Merge remote-tracking branch 'origin/0.9.1'
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..a62eef8
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,56 @@
+---
+Language:        Cpp
+# BasedOnStyle:  LLVM
+AccessModifierOffset: -2
+ConstructorInitializerIndentWidth: 2
+AlignEscapedNewlinesLeft: false
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortBlocksOnASingleLine: false
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: Inline
+AlwaysBreakTemplateDeclarations: true
+AlwaysBreakBeforeMultilineStrings: true
+BreakBeforeBinaryOperators: true
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BinPackParameters: false
+ColumnLimit:     100
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+DerivePointerAlignment: false
+IndentCaseLabels: false
+IndentWrappedFunctionNames: false
+IndentFunctionDeclarationAfterType: false
+MaxEmptyLinesToKeep: 1
+KeepEmptyLinesAtTheStartOfBlocks: true
+NamespaceIndentation: None
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 190
+PenaltyBreakComment: 300
+PenaltyBreakString: 10000
+PenaltyBreakFirstLessLess: 120
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 1200
+PointerAlignment: Left
+SpacesBeforeTrailingComments: 1
+Cpp11BracedListStyle: true
+Standard:        Auto
+IndentWidth:     2
+TabWidth:        4
+UseTab:          Never
+BreakBeforeBraces: Attach
+SpacesInParentheses: false
+SpacesInAngles:  false
+SpaceInEmptyParentheses: false
+SpacesInCStyleCastParentheses: false
+SpacesInContainerLiterals: true
+SpaceBeforeAssignmentOperators: true
+ContinuationIndentWidth: 4
+CommentPragmas:  '^ IWYU pragma:'
+ForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]
+SpaceBeforeParens: ControlStatements
+DisableFormat:   false
+...
+
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..2d2ecd6
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1 @@
+.git/
diff --git a/.editorconfig b/.editorconfig
new file mode 100755
index 0000000..3611762
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,112 @@
+#
+## 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.
+##
+#
+
+# EditorConfig: http://editorconfig.org
+# see doc/coding_standards.md
+
+root = true
+
+[*]
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+# ActionScript
+# [*.as]
+
+# C
+# [*.c]
+
+# C++
+[*.cpp]
+indent_style = space
+indent_size = 2
+
+# C-Sharp
+# [*.cs]
+
+# D
+# [*.d]
+
+# Erlang
+# [*.erl]
+
+# Go-lang
+[*.go]
+indent_style = tab
+indent_size = 8
+
+# C header files
+# [*.h]
+
+# Haskell
+# [*.hs]
+
+# Haxe
+# [*.hx]
+
+# Java
+# [*.java]
+
+# Javascript
+[*.js]
+indent_style = space
+indent_size = 2
+
+# JSON
+[*.json]
+indent_style = space
+indent_size = 2
+
+# Lua
+# [*.lua]
+
+[*.markdown]
+indent_style = space
+trim_trailing_whitespace = false
+
+[*.md]
+indent_style = space
+trim_trailing_whitespace = false
+
+# OCaml
+# [*.ml]
+
+# Delphi Pascal
+# [*.pas]
+
+# PHP
+# [*.php]
+
+# Perl
+# [*.pm]
+
+# Python
+# [*.py]
+
+# Ruby
+# [*.rb]
+
+# Typescript
+# [*.ts]
+
+# XML
+# [*.xml]
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..dde2dba
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,9 @@
+# TODO: Use eslint on js lib and generated code
+
+# Ignore lib/js for now, which uses jshint currently
+lib/js/*
+# Ignore all generated code for now
+**/gen-*
+
+# Don't lint nested node_modules
+**/node_modules
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 0000000..0aae820
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,24 @@
+{
+  "env": {
+    "es6": true,
+    "node": true
+  },
+  "extends": [
+    "eslint:recommended",
+    "plugin:prettier/recommended"
+  ],
+  "parserOptions": {
+    "ecmaVersion": 2017
+  },
+  "rules": {
+    "no-console": "off",
+    "no-var": "error",
+    "prefer-const": "error",
+    "no-constant-condition": [
+      "error",
+      {
+        "checkLoops": false
+      }
+    ]
+  }
+}
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..176a458
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=auto
diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 0000000..12d4afb
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,59 @@
+# Configuration for probot-stale - https://github.com/probot/stale
+
+# Number of days of inactivity before an Issue or Pull Request becomes stale
+daysUntilStale: 60
+
+# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
+# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
+daysUntilClose: 7
+
+# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
+exemptLabels:
+  - Do Not Merge
+  - blocked
+  - pinned
+  - security
+  - "[Status] Maybe Later"
+
+# Set to true to ignore issues in a project (defaults to false)
+exemptProjects: false
+
+# Set to true to ignore issues in a milestone (defaults to false)
+exemptMilestones: false
+
+# Label to use when marking as stale
+staleLabel: wontfix
+
+# Comment to post when marking as stale. Set to `false` to disable
+markComment: >
+  This issue has been automatically marked as stale because it has not had
+  recent activity. It will be closed in 7 days if no further activity occurs.
+  Thank you for your contributions.
+
+# Comment to post when removing the stale label.
+unmarkComment: >
+  This issue is no longer stale.
+  Thank you for your contributions.
+
+# Comment to post when closing a stale Issue or Pull Request.
+closeComment: >
+  This issue has been automatically closed due to inactivity.
+  Thank you for your contributions.
+
+# Limit the number of actions per hour, from 1-30. Default is 30
+limitPerRun: 30
+
+# Limit to only `issues` or `pulls`
+# only: issues
+
+# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
+# pulls:
+#   daysUntilStale: 30
+#   markComment: >
+#     This pull request has been automatically marked as stale because it has not had
+#     recent activity. It will be closed if no further activity occurs. Thank you
+#     for your contributions.
+
+# issues:
+#   exemptLabels:
+#     - confirmed
diff --git a/.gitignore b/.gitignore
index 8b42ed3..b3a5920 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,9 +3,12 @@
 *.lo
 *.o
 *.deps
+*.dirstamp
 *.libs
-gen-*
+*.log
+*.trs
 *.suo
+*.pyc
 *.cache
 *.user
 *.ipch
@@ -16,52 +19,84 @@
 *_ReSharper*
 *.opensdf
 *.swp
-.project
-.pydevproject
+*.hi
+*~
+tags
+
+.*project
+.classpath
+.dub
+.settings
+.checkstyle
+junit*.properties
+.idea
+*.iml
+*.ipr
+*.iws
+gen-*
+Makefile
+Makefile.in
+aclocal.m4
+acinclude.m4
+apache-thrift-test-library
+autom4te.cache
+cmake-*
+dub.selections.json
+libapache-thrift.a
+node_modules
+compile
+test-driver
+erl_crash.dump
+project.lock.json
+
 .sonar
 .DS_Store
+.svn
+.vagrant
+.vscode
+.vs
 
-/Makefile
-/Makefile.in
-/contrib/.vagrant/
 /aclocal/libtool.m4
-/aclocal/ltoptions.m4
-/aclocal/ltsugar.m4
-/aclocal/ltversion.m4
-/aclocal/lt~obsolete.m4
-/aclocal.m4
-/autom4te.cache
+/aclocal/lt*.m4
 /autoscan.log
 /autoscan-*.log
+/cmake_*
+/compiler/cpp/compiler.VC.db
+/compiler/cpp/compiler.VC.VC.opendb
+/compiler/cpp/test/plugin/t_cpp_generator.cc
+/compiler/cpp/src/thrift/plugin/plugin_constants.cpp
+/compiler/cpp/src/thrift/plugin/plugin_constants.h
+/compiler/cpp/src/thrift/plugin/plugin_types.cpp
+/compiler/cpp/src/thrift/plugin/plugin_types.h
+/compiler/cpp/test/*test
+/compiler/cpp/test/thrift-gen-*
+/compiler/cpp/src/thrift/thrift-bootstrap
+/compiler/cpp/src/thrift/plugin/gen.stamp
 /compiler/cpp/Debug
-/compiler/cpp/libparse.a
-/compiler/cpp/Makefile
-/compiler/cpp/Makefile.in
-/compiler/cpp/src/windows/version.h
+/compiler/cpp/Release
+/compiler/cpp/src/thrift/libparse.a
+/compiler/cpp/src/thrift/thriftl.cc
+/compiler/cpp/src/thrift/thrifty.cc
+/compiler/cpp/src/thrift/thrifty.hh
+/compiler/cpp/src/thrift/windows/version.h
 /compiler/cpp/thrift
 /compiler/cpp/thriftl.cc
 /compiler/cpp/thrifty.cc
+/compiler/cpp/lex.yythriftl.cc
 /compiler/cpp/thrifty.h
 /compiler/cpp/thrifty.hh
-/compiler/cpp/version.h
+/compiler/cpp/src/thrift/version.h
 /config.*
 /configure
 /configure.lineno
 /configure.scan
-/contrib/fb303/Makefile
-/contrib/fb303/Makefile.in
-/contrib/fb303/aclocal.m4
-/contrib/fb303/autom4te.cache/
+/contrib/.vagrant/
 /contrib/fb303/config.cache
 /contrib/fb303/config.log
 /contrib/fb303/config.status
 /contrib/fb303/configure
-/contrib/fb303/cpp/Makefile
-/contrib/fb303/cpp/Makefile.in
 /contrib/fb303/cpp/libfb303.a
 /contrib/fb303/java/build/
-/contrib/fb303/py/Makefile
-/contrib/fb303/py/Makefile.in
 /contrib/fb303/py/build/
 /contrib/fb303/py/fb303/FacebookService-remote
 /contrib/fb303/py/fb303/FacebookService.py
@@ -69,36 +104,49 @@
 /contrib/fb303/py/fb303/constants.py
 /contrib/fb303/py/fb303/ttypes.py
 /depcomp
-/if/Makefile
-/if/Makefile.in
 /install-sh
-/lib/Makefile
-/lib/Makefile.in
-/lib/cpp/Makefile
-/lib/cpp/Makefile.in
+/lib/cl/backport-update.zip
+/lib/cl/lib
+/lib/cl/run-tests
+/lib/cl/quicklisp.lisp
+/lib/cl/externals/
+/lib/cl/run-tests
+/lib/cl/quicklisp/
 /lib/cpp/Debug/
 /lib/cpp/Debug-mt/
 /lib/cpp/Release/
 /lib/cpp/Release-mt/
 /lib/cpp/src/thrift/qt/moc_TQTcpServer.cpp
+/lib/cpp/src/thrift/qt/moc__TQTcpServer.cpp
 /lib/cpp/src/thrift/config.h
 /lib/cpp/src/thrift/stamp-h2
-/lib/cpp/test/Makefile
-/lib/cpp/test/Makefile.in
 /lib/cpp/test/Benchmark
 /lib/cpp/test/AllProtocolsTest
+/lib/cpp/test/AnnotationTest
 /lib/cpp/test/DebugProtoTest
+/lib/cpp/test/DenseProtoTest
+/lib/cpp/test/EnumTest
 /lib/cpp/test/JSONProtoTest
 /lib/cpp/test/OptionalRequiredTest
+/lib/cpp/test/SecurityTest
 /lib/cpp/test/SpecializationTest
+/lib/cpp/test/RecursiveTest
 /lib/cpp/test/ReflectionTest
+/lib/cpp/test/RenderedDoubleConstantsTest
 /lib/cpp/test/TFDTransportTest
 /lib/cpp/test/TFileTransportTest
+/lib/cpp/test/TInterruptTest
+/lib/cpp/test/TNonblockingServerTest
+/lib/cpp/test/TNonblockingSSLServerTest
 /lib/cpp/test/TPipedTransportTest
+/lib/cpp/test/TServerIntegrationTest
+/lib/cpp/test/TSocketInterruptTest
 /lib/cpp/test/TransportTest
 /lib/cpp/test/UnitTests
 /lib/cpp/test/ZlibTest
+/lib/cpp/test/OpenSSLManualInitTest
 /lib/cpp/test/concurrency_test
+/lib/cpp/test/link_test
 /lib/cpp/test/processor_test
 /lib/cpp/test/tests.xml
 /lib/cpp/concurrency_test
@@ -110,102 +158,101 @@
 /lib/c_glib/*.gcda
 /lib/c_glib/*.gcno
 /lib/c_glib/*.loT
-/lib/c_glib/Makefile.in
-/lib/c_glib/Makefile
+/lib/c_glib/src/thrift/config.h
+/lib/c_glib/src/thrift/stamp-h3
+/lib/c_glib/test/*.gcno
 /lib/c_glib/test/testwrapper.sh
 /lib/c_glib/test/testwrapper-test*
-/lib/c_glib/test/Makefile
-/lib/c_glib/test/Makefile.in
+/lib/c_glib/test/testapplicationexception
 /lib/c_glib/test/testbinaryprotocol
+/lib/c_glib/test/testcompactprotocol
 /lib/c_glib/test/testbufferedtransport
+/lib/c_glib/test/testcontainertest
 /lib/c_glib/test/testdebugproto
+/lib/c_glib/test/testfdtransport
 /lib/c_glib/test/testframedtransport
 /lib/c_glib/test/testmemorybuffer
 /lib/c_glib/test/testoptionalrequired
+/lib/c_glib/test/testtransportsslsocket
 /lib/c_glib/test/testsimpleserver
 /lib/c_glib/test/teststruct
 /lib/c_glib/test/testthrifttest
 /lib/c_glib/test/testthrifttestclient
 /lib/c_glib/test/testtransportsocket
+/lib/c_glib/test/testserialization
 /lib/c_glib/thriftc.pc
 /lib/c_glib/thrift_c_glib.pc
-/lib/csharp/Makefile
-/lib/csharp/Makefile.in
-/lib/csharp/src/bin/
-/lib/csharp/src/obj/
-/lib/d/libthriftd.a
-/lib/d/Makefile
-/lib/d/Makefile.in
-/lib/d/test/Makefile
-/lib/d/test/Makefile.in
-/lib/delphi/src/*.dcu
-/lib/delphi/test/*.identcache
-/lib/delphi/test/*.local
-/lib/delphi/test/codegen/*.bat
-/lib/delphi/test/skip/*.local
-/lib/delphi/test/skip/*.identcache
-/lib/delphi/test/skip/*.identcache
-/lib/delphi/test/serializer/*.identcache
-/lib/delphi/test/*.dcu
-/lib/delphi/test/*.2007
-/lib/delphi/test/*.dproj
-/lib/delphi/test/*.dproj
-/lib/delphi/test/skip/*.dproj
-/lib/delphi/test/skip/*.dproj
-/lib/delphi/test/serializer/*.dproj
-/lib/delphi/test/serializer/*.local
-/lib/erl/.generated
+/lib/csharp/**/bin/
+/lib/csharp/**/obj/
+/lib/csharp/src/packages
+/lib/d/test/*.pem
+/lib/d/libthriftd*.a
+/lib/d/test/async_test
+/lib/d/test/client_pool_test
+/lib/d/test/serialization_benchmark
+/lib/d/test/stress_test_server
+/lib/d/test/thrift_test_client
+/lib/d/test/thrift_test_server
+/lib/d/test/transport_test
+/lib/d/unittest/
+/lib/dart/coverage
+/lib/dart/**/.packages
+/lib/dart/**/packages
+/lib/dart/**/.pub/
+/lib/dart/**/pubspec.lock
+/lib/delphi/test/skip/*.request
+/lib/delphi/test/skip/*.response
+/lib/delphi/**/*.identcache
+/lib/delphi/**/*.local
+/lib/delphi/**/*.dcu
+/lib/delphi/**/*.2007
+/lib/delphi/**/*.dproj
+/lib/delphi/**/codegen/*.bat
 /lib/erl/.eunit
-/lib/erl/ebin
+/lib/erl/.generated
+/lib/erl/.rebar/
 /lib/erl/deps/
+/lib/erl/ebin
 /lib/erl/src/thrift.app.src
-/lib/erl/test/*.erl
-/lib/erl/test/*.hrl
 /lib/erl/test/*.beam
+/lib/erl/test/*.hrl
+/lib/erl/test/Thrift_omit_without.thrift
+/lib/haxe/test/bin
+/lib/haxe/test/data.tmp
 /lib/hs/dist
-/lib/hs/Makefile
-/lib/hs/Makefile.in
-/lib/go/Makefile
-/lib/go/Makefile.in
-/lib/java/Makefile
-/lib/java/Makefile.in
+/lib/java/.gradle
+/lib/java/android/.gradle
 /lib/java/build
+/lib/java/target
+/lib/js/dist
+/lib/js/doc
 /lib/js/test/build
-/lib/js/test/Makefile
-/lib/js/test/Makefile.in
+/lib/netcore/**/bin
+/lib/netcore/**/obj
+/lib/nodejs/coverage
+/lib/nodejs/node_modules/
 /lib/perl/MANIFEST
-/lib/perl/Makefile
-/lib/perl/Makefile.in
+/lib/perl/MYMETA.json
+/lib/perl/MYMETA.yml
 /lib/perl/Makefile-perl.mk
 /lib/perl/blib
 /lib/perl/pm_to_blib
-/lib/perl/test/Makefile
-/lib/perl/test/Makefile.in
-/lib/py/Makefile
-/lib/py/Makefile.in
 /lib/py/build
 /lib/py/thrift.egg-info/
-/lib/rb/Makefile
-/lib/rb/Makefile.in
+/lib/rb/Gemfile.lock
 /lib/rb/debug_proto_test
 /lib/rb/.config
-/lib/rb/ext/Makefile
 /lib/rb/ext/conftest.dSYM/
 /lib/rb/ext/mkmf.log
 /lib/rb/ext/thrift_native.bundle
 /lib/rb/ext/thrift_native.so
 /lib/rb/test/
 /lib/rb/thrift-*.gem
-/lib/php/Makefile
-/lib/php/Makefile.in
-/lib/php/src/ext/thrift_protocol/Makefile
 /lib/php/src/ext/thrift_protocol/Makefile.*
-/lib/php/src/ext/thrift_protocol/acinclude.m4
-/lib/php/src/ext/thrift_protocol/aclocal.m4
-/lib/php/src/ext/thrift_protocol/autom4te.cache/
 /lib/php/src/ext/thrift_protocol/build/
 /lib/php/src/ext/thrift_protocol/config.*
 /lib/php/src/ext/thrift_protocol/configure
+/lib/php/src/ext/thrift_protocol/configure.ac
 /lib/php/src/ext/thrift_protocol/configure.in
 /lib/php/src/ext/thrift_protocol/install-sh
 /lib/php/src/ext/thrift_protocol/libtool
@@ -218,78 +265,132 @@
 /lib/php/src/ext/thrift_protocol/thrift_protocol.la
 /lib/php/src/ext/thrift_protocol/tmp-php.ini
 /lib/php/src/packages/
-/lib/php/test/Makefile
-/lib/php/test/Makefile.in
-/lib/php/test/phpunit.xml
+/lib/php/test/TEST-*.xml
 /lib/php/test/packages/
+/lib/py/dist/
 /lib/erl/logs/
-/lib/erl/Makefile
-/lib/erl/Makefile.in
-/lib/erl/src/Makefile
-/lib/erl/src/Makefile.in
+/lib/go/pkg
+/lib/go/src
+/lib/go/test/gopath/
+/lib/go/test/ThriftTest.thrift
+/lib/rs/target/
+/lib/rs/Cargo.lock
+/lib/rs/test/Cargo.lock
+/lib/rs/test/target/
+/lib/rs/test/bin/
+/lib/rs/test/src/base_one.rs
+/lib/rs/test/src/base_two.rs
+/lib/rs/test/src/midlayer.rs
+/lib/rs/test/src/recursive.rs
+/lib/rs/test/src/ultimate.rs
+/lib/rs/*.iml
+/lib/rs/**/*.iml
+/lib/swift/.build
 /libtool
 /ltmain.sh
 /missing
+/node_modules/
+/vendor/
+/composer.lock
 /stamp-h1
-/test/Makefile
-/test/Makefile.in
-/test/cpp/Makefile
-/test/cpp/Makefile.in
+/test/features/results.json
+/test/results.json
+/test/c_glib/test_client
+/test/c_glib/test_server
+/test/cl/TestServer
+/test/cl/TestClient
 /test/cpp/StressTest
 /test/cpp/StressTestNonBlocking
 /test/cpp/TestClient
 /test/cpp/TestServer
-/lib/go/test/Makefile
-/lib/go/test/Makefile.in
-/lib/go/test/gopath/
-/lib/go/test/ThriftTest.thrift
-/test/hs/Makefile
-/test/hs/Makefile.in
+/test/csharp/obj
+/test/csharp/bin
+/test/dart/**/.packages
+/test/dart/**/packages
+/test/dart/**/.pub/
+/test/dart/**/pubspec.lock
 /test/log/
 /test/test.log
-/test/nodejs/Makefile
-/test/nodejs/Makefile.in
-/test/perl/Makefile
-/test/perl/Makefile.in
-/test/php/Makefile
-/test/php/Makefile.in
-/test/py/Makefile
-/test/py/Makefile.in
-/test/py.twisted/Makefile
-/test/py.twisted/Makefile.in
+/test/erl/.generated
+/test/erl/.rebar
+/test/erl/ebin
+/test/go/bin/
+/test/go/ThriftTest.thrift
+/test/go/gopath
+/test/go/pkg/
+/test/go/src/code.google.com/
+/test/go/src/common/mock_handler.go
+/test/go/src/github.com/golang/
+/test/go/src/golang.org/
+/test/go/src/gen/
+/test/go/src/thrift
+/test/haxe/bin
+/test/hs/TestClient
+/test/hs/TestServer
+/test/php/php_ext_dir/
 /test/py.twisted/_trial_temp/
-/test/py.twisted/test_suite.pyc
-/test/py.tornado/Makefile
-/test/py.tornado/Makefile.in
-/test/py.tornado/*.pyc
-/test/rb/Makefile
-/test/rb/Makefile.in
-/tutorial/Makefile
-/tutorial/Makefile.in
-/tutorial/cpp/Makefile
-/tutorial/cpp/Makefile.in
+/test/rb/Gemfile.lock
+/test/netcore/**/bin
+/test/netcore/**/obj
+/test/netcore/Thrift
+/test/php/php_ext_dir/
+/test/rs/Cargo.lock
+/test/rs/src/thrift_test.rs
+/test/rs/bin/
+/test/rs/target/
+/test/rs/*.iml
+/test/rs/**/*.iml
+/lib/cl/backport-update.zip
+/lib/cl/lib
+/tutorial/cl/quicklisp.lisp
+/tutorial/cl/externals/
+/tutorial/cl/quicklisp/
+/tutorial/cl/TutorialClient
+/tutorial/cl/TutorialServer
+/tutorial/cl/backport-update.zip
+/tutorial/cl/lib/
+/tutorial/cl/shared-implementation.fasl
+/tutorial/cl/tutorial-implementation.fasl
 /tutorial/cpp/TutorialClient
 /tutorial/cpp/TutorialServer
-/tutorial/go/Makefile
-/tutorial/go/Makefile.in
+/tutorial/c_glib/tutorial_client
+/tutorial/c_glib/tutorial_server
+/tutorial/csharp/CsharpServer/obj
+/tutorial/csharp/CsharpServer/bin
+/tutorial/csharp/CsharpClient/obj
+/tutorial/csharp/CsharpClient/bin
+/tutorial/d/async_client
+/tutorial/d/client
+/tutorial/d/server
+/tutorial/dart/**/.packages
+/tutorial/dart/**/packages
+/tutorial/dart/**/.pub/
+/tutorial/dart/**/pubspec.lock
+/tutorial/delphi/**/*.dsk
+/tutorial/delphi/**/*.local
+/tutorial/delphi/**/*.tvsconfig
+/tutorial/delphi/**/dcu
+/tutorial/delphi/**/*.local
+/tutorial/delphi/**/*.identcache
+/tutorial/go/gopath
 /tutorial/go/go-tutorial
 /tutorial/go/calculator-remote
 /tutorial/go/src/shared
 /tutorial/go/src/tutorial
 /tutorial/go/src/git.apache.org
-/tutorial/java/Makefile
-/tutorial/java/Makefile.in
+/tutorial/go/src/golang.org
+/tutorial/haxe/bin
+/tutorial/hs/dist/
 /tutorial/java/build/
-/tutorial/js/Makefile
-/tutorial/js/Makefile.in
 /tutorial/js/build/
-/tutorial/py.twisted/Makefile
-/tutorial/py.twisted/Makefile.in
-/tutorial/py.tornado/Makefile
-/tutorial/py.tornado/Makefile.in
-/tutorial/py/Makefile
-/tutorial/py/Makefile.in
-/tutorial/rb/Makefile
-/tutorial/rb/Makefile.in
+/tutorial/netcore/**/bin
+/tutorial/netcore/**/obj
+/tutorial/netcore/Thrift
+/tutorial/rs/*.iml
+/tutorial/rs/src/shared.rs
+/tutorial/rs/src/tutorial.rs
+/tutorial/rs/bin
+/tutorial/rs/target
+/tutorial/rs/Cargo.lock
 /ylwrap
 
diff --git a/.rustfmt.toml b/.rustfmt.toml
new file mode 100644
index 0000000..dca5afd
--- /dev/null
+++ b/.rustfmt.toml
@@ -0,0 +1,64 @@
+max_width = 100
+hard_tabs = false
+tab_spaces = 4
+newline_style = "Auto"
+use_small_heuristics = "Default"
+indent_style = "Block"
+wrap_comments = false
+format_doc_comments = false
+comment_width = 80
+normalize_comments = false
+normalize_doc_attributes = false
+license_template_path = ""
+format_strings = false
+format_macro_matchers = false
+format_macro_bodies = true
+empty_item_single_line = true
+struct_lit_single_line = true
+fn_single_line = false
+where_single_line = false
+imports_indent = "Block"
+imports_layout = "Mixed"
+merge_imports = false
+reorder_imports = true
+reorder_modules = true
+reorder_impl_items = false
+type_punctuation_density = "Wide"
+space_before_colon = false
+space_after_colon = true
+spaces_around_ranges = false
+binop_separator = "Front"
+remove_nested_parens = true
+combine_control_expr = true
+overflow_delimited_expr = false
+struct_field_align_threshold = 0
+enum_discrim_align_threshold = 0
+match_arm_blocks = true
+force_multiline_blocks = false
+fn_args_density = "Tall"
+brace_style = "SameLineWhere"
+control_brace_style = "AlwaysSameLine"
+trailing_semicolon = true
+trailing_comma = "Vertical"
+match_block_trailing_comma = false
+blank_lines_upper_bound = 1
+blank_lines_lower_bound = 0
+edition = "2015"
+merge_derives = true
+use_try_shorthand = false
+use_field_init_shorthand = false
+force_explicit_abi = true
+condense_wildcard_suffixes = false
+color = "Auto"
+required_version = "1.0.0"
+unstable_features = false
+disable_all_formatting = false
+skip_children = false
+hide_parse_errors = false
+error_on_line_overflow = false
+error_on_unformatted = false
+report_todo = "Never"
+report_fixme = "Never"
+ignore = []
+emit_mode = "Files"
+make_backup = false
diff --git a/.travis.yml b/.travis.yml
index 68af531..637b5d5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -19,55 +19,155 @@
 
 # build Apache Thrift on Travis CI - https://travis-ci.org/
 
+#
+# Docker Integration
+# see: build/docker/README.md
+# 
+
+sudo: required
+dist: trusty
 language: cpp
 
-# see what we need: http://thrift.apache.org/docs/install/ubuntu
-before_install:
- - export NUM_CPU="`grep processor /proc/cpuinfo | wc -l`"; echo $NUM_CPU
- - sudo apt-get update -qq
- - sudo apt-get upgrade -qq
- - sudo apt-get install -qq libboost-dev libboost-test-dev libboost-program-options-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev 
-# Java
- - sudo apt-get install -qq libcommons-lang3-java ant
-# TODO: fix ruby support
-# Ruby
-# - sudo apt-get install -qq ruby1.9.1-full ruby1.9.1-dev ruby-rspec rake rubygems libdaemons-ruby libgemplugin-ruby mongrel
-# - sudo /usr/bin/gem1.9.1 install bundler
-# - sudo /usr/bin/gem1.9.1 install rack-test
-# Python
- - sudo apt-get install -qq python-all python-all-dev python-all-dbg
-# Perl
- - sudo apt-get install -qq libbit-vector-perl
-# PHP
- - sudo apt-get install -qq php5-dev php5-cli phpunit
-# c_glib
- - sudo apt-get install -qq libglib2.0-dev
-# Erlang
- - sudo apt-get install -qq erlang-base erlang-eunit erlang-dev
-# Csharp
- - sudo apt-get install -qq mono-gmcs mono-devel libmono-system-web2.0-cil nunit nunit-console
-# Haskell
- - sudo apt-get install -qq ghc6 cabal-install libghc6-binary-dev libghc6-network-dev libghc6-http-dev
-# Thrift Compiler for Windows
- - sudo apt-get install -qq mingw32 mingw32-binutils mingw32-runtime
-# node.js
- - sudo apt-get install -qq nodejs npm
- - sudo npm install nodeunit -g || true
-# TODO: move npm install to nodejs Makefile
- - cd lib/nodejs; npm install & cd ../..
-
+services:
+  - docker
 
 install:
-  - sh bootstrap.sh
+  - if [[ `uname` == "Linux" ]]; then build/docker/refresh.sh; fi
 
-script:
-# TODO: fix ruby support
-#  - export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/var/lib/gems/1.9.1/bin
-#  - sh configure RUBY=/usr/bin/ruby1.9.1 RAKE=/usr/bin/rake1.9.1
-# TODO: fix these languages
-  - sh configure --without-ruby --without-haskell --without-perl --without-php  --without-python
-  - make -j$NUM_CPU && make dist
-  - make check -j$NUM_CPU && sh test/test.sh
-# TODO: add these steps
-#  - sh bootstrap.sh ; sh contrib/mingw-cross-compile.sh
-#  - sh bootstrap.sh ; dpkg-buildpackage -tc
+stages:
+  - docker    # docker images
+  - thrift    # thrift build jobs
+
+env:
+  global:
+    - SCRIPT="cmake.sh"
+    - BUILD_ARG=""
+    - BUILD_ENV="-e CC=gcc -e CXX=g++ -e THRIFT_CROSSTEST_CONCURRENCY=4"
+    - DISTRO=ubuntu-bionic
+    - BUILD_LIBS="CPP C_GLIB HASKELL JAVA PYTHON TESTING TUTORIALS"  # only meaningful for CMake builds
+    - TRAVIS_BUILD_STAGE=test
+    # DOCKER_REPO (this works for all builds as a source for docker images - you can override for fork builds in your Travis settings)
+    - DOCKER_REPO="thrift/thrift-build"
+    # DOCKER_USER (provide in your Travis settings if you want to build and update docker images once, instead of on every job)
+    # DOCKER_PASS (same)
+
+jobs:
+  include:
+    # ========================= stage: docker =========================
+    - stage: docker
+      script: true
+      env:
+        - JOB="Docker Build ubuntu-xenial 16.04 LTS"
+        - DISTRO=ubuntu-xenial
+        - TRAVIS_BUILD_STAGE=docker
+    - script: true
+      env:
+        - JOB="Docker Build ubuntu-bionic 18.04 LTS"
+        - DISTRO=ubuntu-bionic
+        - TRAVIS_BUILD_STAGE=docker
+
+    # ========================= stage: thrift =======================
+    # ------------------------- phase: cross ------------------------
+    # apache/thrift official PR builds can exceed 50 minutes per job so combine all cross tests
+    - stage: thrift
+      script: build/docker/run.sh
+      if: repo = apache/thrift
+      env:
+        - JOB="Cross Language Tests"
+        - SCRIPT="cross-test.sh"
+
+    # fork based PR builds cannot exceed 50 minutes per job
+    - stage: thrift
+      script: build/docker/run.sh
+      if: repo != apache/thrift
+      env:
+        - JOB="Cross Language Tests (Binary Protocol)"
+        - SCRIPT="cross-test.sh"
+        - BUILD_ARG="-'(binary)'"
+
+    - stage: thrift
+      script: build/docker/run.sh
+      if: repo != apache/thrift
+      env:
+        - JOB="Cross Language Tests (Header, JSON Protocols)"
+        - SCRIPT="cross-test.sh"
+        - BUILD_ARG="-'(header|json)'"
+
+    - stage: thrift
+      script: build/docker/run.sh
+      if: repo != apache/thrift
+      env:
+        - JOB="Cross Language Tests (Compact and Multiplexed Protocols)"
+        - SCRIPT="cross-test.sh"
+        - BUILD_ARG="-'(compact|multiplexed)'"
+
+    # ------------------------- phase: sca --------------------------
+    # QA jobs for code analytics and metrics
+    - stage: thrift
+      script: build/docker/run.sh
+      env:
+        - JOB="Static Code Analysis"
+        - SCRIPT="sca.sh"
+
+    # C and C++ undefined behavior.
+    # A binary crashes if undefined behavior occurs and produces a stack trace.
+    # python is disabled, see: THRIFT-4360
+    - script: build/docker/run.sh
+      env:
+        - JOB="UBSan"
+        - SCRIPT="ubsan.sh"
+        - BUILD_ARG="--without-python --without-py3"
+
+    # ------------------------- phase: autotools --------------------
+    # TODO: Remove them once migrated to CMake
+    - script: build/docker/run.sh
+      env:
+        - JOB="Autotools (Ubuntu Bionic)"
+        - SCRIPT="autotools.sh"
+
+    - script: build/docker/run.sh
+      env:
+        - JOB="Autotools (Ubuntu Xenial)"
+        - DISTRO=ubuntu-xenial
+        - SCRIPT="autotools.sh"
+
+    # ------------------------- phase: cmake ------------------------
+    - script: build/docker/run.sh
+      env:
+        - JOB="CMake"
+
+    # C++ specific options: compiler plug-in, threading model
+    - script: build/docker/run.sh
+      env:
+        - JOB="C++ (Std Thread) and Plugin"
+        - SCRIPT="cmake.sh"
+        - BUILD_LIBS="CPP TESTING TUTORIALS"
+        - BUILD_ARG="-DWITH_PLUGIN=ON -DWITH_STDTHREADS=ON -DWITH_PYTHON=OFF -DWITH_C_GLIB=OFF -DWITH_JAVA=OFF -DWITH_HASKELL=OFF"
+        - BUILD_ENV="-e CC=clang -e CXX=clang++"
+
+    # ------------------------- phase: dist -------------------------
+    - script: build/docker/run.sh
+      env:
+        - JOB="make dist"
+        - SCRIPT="make-dist.sh"
+
+    - script: build/docker/run.sh
+      env:
+        - JOB="Debian Packages"
+        - SCRIPT="dpkg.sh"
+
+    # ------------------------- phase: coverity ---------------------
+    # We build the coverity scan build once monthly using a travis cron job
+    - if: (env(COVERITY_SCAN_NOTIFICATION_EMAIL) IS present) AND (branch IN (master)) AND (type IN (cron))
+      script: build/docker/run.sh
+      env:
+        - JOB="Coverity Scan"
+        - SCRIPT="covscan.sh"
+     
+
+  ### ------------------------- phase: osx --------------------------
+  # disabled due to the time delays it imposes on build jobs
+  # - os: osx
+  #   osx_image: xcode9
+  #   script: build/docker/scripts/autotools.sh
+
diff --git a/ApacheThrift.nuspec b/ApacheThrift.nuspec
new file mode 100644
index 0000000..54ed2c6
--- /dev/null
+++ b/ApacheThrift.nuspec
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  Instructions for building a nuget package:
+
+  1. Open Thrift.sln in lib\csharp\src and build the release version
+     of the "Thrift" and "Thrift.45" projects.
+  2. Open Thrift.sln in lib\netcore and build the release version of
+     the "Thrift" project.
+  3. nuget setApiKey <your-api-key>
+  3. nuget pack ApacheThrift.nuspec -Symbols -SymbolPackageFormat snupkg
+  4. nuget push ApacheThrift.1.0.0.nupkg -Source https://api.nuget.org/v3/index.json
+  -->
+
+<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
+  <metadata>
+    <id>ApacheThrift</id>
+    <version>1.0.0</version>
+    <title>Apache Thrift 1.0.0</title>
+    <authors>Apache Thrift Developers</authors>
+    <owners>Apache Software Foundation</owners>
+    <license type="expression">Apache-2.0</license>
+    <projectUrl>http://thrift.apache.org/</projectUrl>
+    <requireLicenseAcceptance>true</requireLicenseAcceptance>
+    <summary>Apache Thrift .NET Library</summary>
+    <description>
+      Contains runtime libraries from lib/csharp for net35 and net45 frameworks, 
+      and from lib/netcore for netstandard2.0 framework development.
+    </description>
+    <repository type="GitHub" url="https://github.com/apache/thrift" branch="release/1.0.0" />
+    <tags>Apache Thrift RPC</tags>
+  </metadata>
+  <files>
+    <file src="lib\csharp\src\bin\Release\Thrift.*" target="lib\net35" />
+    <file src="lib\csharp\src\bin\Release\Thrift45.*" target="lib\net45" />
+    <file src="lib\netcore\Thrift\bin\Release\netstandard2.0\*.*" target="lib\netstandard2.0" />
+  </files>
+</package>
\ No newline at end of file
diff --git a/CHANGES b/CHANGES
index 3275de4..244f0da 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,680 +1,2752 @@
-Thrift Changelog
+Apache Thrift Changelog
 
-Version 1.0
-- Coming Soon
+================================================================================
+Thrift 0.12.0
+--------------------------------------------------------------------------------
+## New Languages
+    * Common LISP (cl)
+    * Swift
+    * Typescript (nodets)
 
-Version 0.9.1
+## Deprecated Languages
+    * Cocoa
 
-THRIFT-2137   Ruby                 Ruby test lib fails jenkins build #864
-THRIFT-2136   Build Proces         Vagrant build not compiling java, ruby, php, go libs due to missing dependencies 
-THRIFT-2135   Go                   GO lib leaves behind test files that are auto generated 
-THRIFT-2134   Compiler             mingw-cross-compile script failing with strip errors
-THRIFT-2133   Java                 java TestTBinaryProtocol.java test failing
-THRIFT-2129   PHP                  php ext missing from dist
-THRIFT-2128   Go                   lib GO tests fail with funct ends without a return statement
-THRIFT-2126   C++                  lib/cpp/src/thrift/concurrency/STD* files missing from DIST
-THRIFT-2125   Build Process        debian missing from DIST
-THRIFT-2124   Build Process        .o, .so, .la, .deps, .libs, gen-* files left tutorials, test and lib/cpp when making DIST
-THRIFT-2123                        GO lib missing files in DIST build
-THRIFT-2118                        Certificate error handling still incorrect
-THRIFT-2117   Cocoa                Cocoa TBinaryProtocol strictWrite should be set to true by default
-THRIFT-2112   Go                   Error in Go generator when using typedefs in map keys
-THRIFT-2109                        Secure connections should be supported in Go
-THRIFT-2107   Go                   minor Go generator fixes
-THRIFT-2106                        Fix support for namespaces in GO generator
-THRIFT-2105                        Generated code for default values of collections ignores t_field::T_REQUIRED
-THRIFT-2102                        constants are not referencing to correct type when included from another thrift file
-THRIFT-2100                        typedefs are not correctly referenced when including from other thrift files
-THRIFT-2091                        Unnecessary 'friend' declaration causes warning in TWinsockSingleton
-THRIFT-2090   Go                   Go generator, fix including of other thrift files
-THRIFT-2088   Compiler             Typos in Thrift compiler help text
-THRIFT-2084   Delphi               Delphi: Ability to create entity Thrift-generated instances based on TypeInfo
-THRIFT-2083   Go                   Improve the go lib: buffered Transport, save memory allocation, handle concurrent request
-THRIFT-2082   Build Process        Executing "gmake clean" is broken
-THRIFT-2081                        Specified timeout should be used in TSocket.Open()
-THRIFT-2080   C#                   C# multiplex processor does not catch IOException
-THRIFT-2070                        Improper `HexChar' and 'HexVal' implementation in TJSONProtocol.cs
-THRIFT-2066   Build Process        'make install' does not install two headers required for C++ bindings
-THRIFT-2065   Java                 Not valid constants filename in Java 
-THRIFT-2057   Build Process        Vagrant fails on php tests
-THRIFT-2052   Build Process        Vagrant machine image defaults to only 384MB of RAM
-THRIFT-2051   Build Process        Vagrant fails to build erlang
-THRIFT-2050   Build Process        Vagrant C# lib compile fails with TException missing
-THRIFT-2047                        Thrift.Protocol.TCompactProtocol, intToZigZag data lost (TCompactProtocol.cs)
-THRIFT-2036                        Thrift gem warns about class variable access from top level
-THRIFT-2032   C#                   C# client leaks sockets/handles
-THRIFT-2017   Compiler             Resource Leak in thrift struct under compiler/cpp/src/parse/t_program.h
-THRIFT-2014   C++                  Change C++ lib includes to use <namespace/> style throughout
-THRIFT-2012   Go                   Modernizing Go 
-THRIFT-2003                        Deprecate senum
-THRIFT-2002   Haskell              Haskell: Test use Data.Maybe instead of Maybe
-THRIFT-2001   Website              http://thrift.apache.org/ Example "C++ Server" tab is broken
-THRIFT-1997                        Add accept backlog configuration method to  TServerSocket
-THRIFT-1996   JavaME               JavaME Constants generation is broken / inconsistent with regular Java generation
-THRIFT-1995   Compiler             '.' allowed at end of identifier generates non-compilable code
-THRIFT-1994   Compiler             Deprecate slist
-THRIFT-1993   Delphi               Factory to create instances from known (generated) interface types with Delphi
-THRIFT-1992                        casts in TCompactProtocol.tcc causing "dereferencing type-punned pointer will break strict-
-THRIFT-1988                        When trying to build a debian package it fails as the file NEWS doesn't exist
-THRIFT-1985   Build Process        add a Vagrantfile to build and test Apache Thrift fully reproducable
-THRIFT-1984   Python               namespace collision in python bindings
-THRIFT-1980   Go                   Modernize Go tooling, fix go client libary.
-THRIFT-1978   Ruby                 Ruby: Thrift should allow for the SSL verify mode to be set
-THRIFT-1977   C#                   C# compiler should generate constant files prefixed with thrift file name
-THRIFT-1975                        TBinaryProtocol CheckLength can't be used for a client
-THRIFT-1973   C#                   TCompactProtocol in C# lib does not serialize and deserialize negative int32 and int64 numb
-THRIFT-1972   Java                 Add support for async processors
-THRIFT-1971   Tutorial             [Graphviz] Adds tutorial/general description documentation
-THRIFT-1970                        [Graphviz] Adds option to render exceptions relationships
-THRIFT-1969   C#                   C#: Tests not properly linked from the solution
-THRIFT-1966                        Support different files for SSL certificates and keys
-THRIFT-1965                        Adds Graphviz (graph description language) generator
-THRIFT-1962                        Multiplex processor should send any TApplicationException back to client
-THRIFT-1961   C#                   C# tests should be in lib/csharp/test/...
-THRIFT-1960                        main() declares 22 unused gen bools
-THRIFT-1959   C#                   C#: Add Union TMemoryBuffer support
-THRIFT-1958   C#                   C#: Use static Object.Equals instead of .Equals() calls in equals
-THRIFT-1957   Node.js              NodeJS TFramedTransport and TBufferedTransport read bytes as unsigned
-THRIFT-1956   Java                 Switch to Apache Commons Lang 3
-THRIFT-1955                        Union Type writer generated in C# does not WriteStructBegin
-THRIFT-1952   Build Process        Travis CI
-THRIFT-1951   Java                 libthrift.jar has source files in it
-THRIFT-1949                        WP7 build broken
-THRIFT-1943                        docstrings for enum values are ignored
-THRIFT-1942   PHP                  Binary accelerated cpp extension does not use Thrift namespaces for Exceptions
-THRIFT-1934   Tutorial             Tabs in Example section on main page are not working
-THRIFT-1933                        Delphi generator crashes when a typedef references another typedef from an included file
-THRIFT-1930   C#                   C# generates unsigned byte for Thrift "byte" type
-THRIFT-1929   Website              Update website to use Mirrors for downloads
-THRIFT-1928                        Race may still exist in TFileTransport::flush()
-THRIFT-1924   Delphi               Delphi: Inconsistency in serialization of optional fields 
-THRIFT-1922   C#                   C#: Inconsistency in serialization of optional fields 
-THRIFT-1919                        libthrift depends on httpcore-4.1.3 (directly) and httpcore-4.1.4 (transitively)
-THRIFT-1913                        skipping unknown fields in java unions
-THRIFT-1907                        Compiling namespace and sub-namespace directives for unrecognized generators should only be
-THRIFT-1904                        Incorrect code is generated for typedefs which use included types
-THRIFT-1903   PHP                  PHP namespaces cause binary protocols to not be used
-THRIFT-1902   C++                  C++: Support for Multiplexing Services on any Transport, Protocol and Server
-THRIFT-1901   C#                   C#: Support for Multiplexing Services on any Transport, Protocol and Server
-THRIFT-1899   Celphi               Delphi: Support for Multiplexing Services on any Transport, Protocol and Server
-THRIFT-1897                        Support validation of required fields
-THRIFT-1896   Cocoa                Add TBase protocol for Cocoa
-THRIFT-1895   Delphi               Delphi: reserved variable name "result" not detected properly
-THRIFT-1890   C++                  C++: Make named pipes server work asynchronously 
-THRIFT-1888   Java                 Java Thrift client can't connect to Python Thrift server on same host
-THRIFT-1882                        Use single include
-THRIFT-1881                        TNonblockingServer does not release open connections or threads on shutdown
-THRIFT-1880                        Make named pipes server work asynchronously (overlapped) to allow for clean server stops
-THRIFT-1878                        Add the possibility to send custom headers
-THRIFT-1876                        Use enum names instead of casted integers in assignments
-THRIFT-1874                        timeout for the server-side end of a named pipe
-THRIFT-1873                        Binary protocol factory ignores struct read/write flags
-THRIFT-1872                        issues with TBufferedTransport buffer
-THRIFT-1869   Java                 TThreadPoolServer (java) dies when threadpool is consumed
-THRIFT-1864                        implement event handler for non-blocking server
-THRIFT-1859   C++                  Generated error c++ code with -out and include_prefix param
-THRIFT-1850                        make check hangs on TSocket tests in TransportTest.cpp
-THRIFT-1846                        Restore socket.h header to support builds with Android NDK
-THRIFT-1842                        Memory leak with Pipes
-THRIFT-1838   Compiler             Can't build compiler on OS X because of missing thrifty.h
-THRIFT-1831                        Bug in list deserializer
-THRIFT-1824                        many compile warning, becase Thread.h includes config.h
-THRIFT-1823                        Missing parenthesis breaks "IS_..." macro in generated code
-THRIFT-1822                        PHP unit test does not work
-THRIFT-1816                        Need "require" included thrift files in "xxx_types.js"
-THRIFT-1815                        Code generators line buffer output
-THRIFT-1806                        Python generation always truncates __init__.py files
-THRIFT-1804   Build Proces         Binary+compact protocol single byte error in Ruby library (ARM architecture): caused by dif
-THRIFT-1800                        Documentation text not always escaped correctly when rendered to HTML
-THRIFT-1799                        Option to generate HTML in "standalone mode"
-THRIFT-1794   C#                   C# asyncctp broken
-THRIFT-1793   C#                   C#: Use static read instead of instance read
-THRIFT-1791   Haskell              thrift's namespace directive when generating haskell code
-THRIFT-1788   C#                   C#: Constants static constructor does not compile
-THRIFT-1786   C#                   C# Union Typing
-THRIFT-1785   C#                   C#: Add TMemoryBuffer serializer/deserializer
-THRIFT-1783   C#                   C# doesn't handle required fields correctly
-THRIFT-1782   Javascript           async only defined in silverlight
-THRIFT-1780                        Add option to generate nullable values
-THRIFT-1779                        Missing process_XXXX method in generated TProcessor implementation for all 'oneway' service
-THRIFT-1778                        Configure requires manual intervention due to tar failure
-THRIFT-1777                        TPipeServer is UNSTOPPABLE
-THRIFT-1773   Python               Python library should run on python 2.4
-THRIFT-1769                        unions can't have required fields (C++)
-THRIFT-1768                        unions can't have required fields (Compiler)
-THRIFT-1767                        unions can't have required fields (Delphi)
-THRIFT-1765                        Incorrect error message printed for null or negative keys
-THRIFT-1764                        how to get the context of client when on a rpc call in server side?
-THRIFT-1756   Build Process       'make -j 8' fails with "unterminated #ifdef" error
-THRIFT-1753   C++                  Multiple C++ Windows, OSX, and iOS portability issues
-THRIFT-1749   Python               Python TSSLSocket error handling obscures actual error
-THRIFT-1748                        Guard and RWGuard macros defined in global namespace
-THRIFT-1742   C#                   Optionally implement hashcode and equals in c#
-THRIFT-1740   C++                  Make C++ library build on OS X and iOS
-THRIFT-1739   Node.js              missing license header in node.js files
-THRIFT-1735   Tutorials            integrate tutorial into regular build
-THRIFT-1734   Website              Front webpage is still advertising v0.8 as current release
-THRIFT-1733   Build Process        Fix RPM build issues on RHEL6/OL6 systems
-THRIFT-1729   GLibC                C glib refactor left empty folders in svn
-THRIFT-1728                        Upgradation of httpcomponents
-THRIFT-1720   Ruby                 JRuby times out on successful connection
-THRIFT-1716                        max allowed connections should be PIPE_UNLIMITED_INSTANCES
-THRIFT-1715                        Allow excluding python parts when building contrib/fb303
-THRIFT-1713                        Named and Anonymous Pipe transport (Delphi)
-THRIFT-1699                        Native Union#read has extra read_field_end call
-THRIFT-1695                        allow warning-free compilation in VS 2012 and GNU 4.6
-THRIFT-1681   Lua                  Add Lua Support
-THRIFT-1666   CPP                  htonll usage in TBinaryProtocol.tcc generates warning with MSVC2010
-THRIFT-1660   Python               Python Thrift library can be installed with pip but not easy_install
-THRIFT-1657   Javascript           Chrome browser sending OPTIONS method before POST in xmlHttpRequest
-THRIFT-1648   Node.js              NodeJS clients always receive 0 for 'double' values.
-THRIFT-1637   Node.js              NPM registry does not include version 0.8
-THRIFT-1629   Ruby                 Ruby 1.9 Compatibility during Thrift configure, make, install
-THRIFT-1614                        Thrift build from svn repo sources fails with automake-1.12
-THRIFT-1603                        Thrift IDL allows for multiple exceptions, args or struct member names to be the same
-THRIFT-1600   Go - Compile         Thrift Go Compiler and Library out of date with Go 1 Release.
-THRIFT-1595                        Java test server should follow the documented behavior as of THRIFT-1590
-THRIFT-1594                        Java test clients should have a return codes that reflect whether it succeeds or not. 
-THRIFT-1574                        Apache project branding requirements: DOAP file [PATCH]
-THRIFT-1440                        debian packaging: minor-ish policy problems
-THRIFT-1402                        Generated Y_types.js does not require() X_types.js when an include in the IDL file was used
-THRIFT-1353                        Switch to performance branch, get rid of BinaryParser
-THRIFT-1347   GO                   Unify the exceptions returned in generated Go code
-THRIFT-1264   Cocoa                TSocketClient is queried by run loop after deallocation in Cocoa
-THRIFT-1062   Python               Problems with python tutorials
-THRIFT-991    Haskell              Refactor Haskell code and generator
-THRIFT-990    C++                  Sanify gettimeofday usage codebase-wide
-THRIFT-986    Smalltalk            st: add version Info to the library
-THRIFT-985    PHP                  php: add version Info to the library
-THRIFT-984    OCaml                ocaml: add version Info to the library
-THRIFT-930    Haskell              Ruby and Haskell bindings don't properly support DESTDIR (makes packaging painful)
-THRIFT-864                         default value fails if identifier is a struct
-THRIFT-820                         The readLength attribute of TBinaryProtocol is used as an instance variable and is decremen
-THRIFT-801    Ruby                 Provide an interactive shell (irb) when generating ruby bindings
-THRIFT-791    C++                  Let C++ TSimpleServer be driven by an external main loop
-THRIFT-591                         Make the C++ runtime library be compatible with Windows and Visual Studio
-THRIFT-563                         Support for Multiplexing Services on any Transport, Protocol and Server
-THRIFT-514    Compiler             Add option to configure compiler output directory
-THRIFT-474    Ruby                 Generating Ruby on Rails friendly code
-THRIFT-274    Build Process        Towards a working release/versioning process
+## Breaking Changes (since 0.11.0)
+    * [THRIFT-4529] - Rust enum variants are now camel-cased instead of uppercased to conform to Rust naming conventions
+    * [THRIFT-4448] - Support for golang 1.6 and earlier has been dropped.
+    * [THRIFT-4474] - PHP now uses the PSR-4 loader by default instead of class maps.
+    * [THRIFT-4532] - method signatures changed in the compiler's t_oop_generator.
+    * [THRIFT-4648] - The C (GLib) compiler's handling of namespaces has been improved.
+
+## Known Issues (Blocker or Critical)
+    * [THRIFT-4037] - build: use a single build system for thrift
+    * [THRIFT-4119] - build: bootstrap.sh is missing from source tarball
+    * [THRIFT-3289] - csharp: socket exhaustion in csharp implementation
+    * [THRIFT-3029] - cocoa: Getters for fields defined with uppercase names do not work
+    * [THRIFT-3325] - cocoa: Extended services aren't subclasses in generated Cocoa
+    * [THRIFT-4116] - cocoa: Thrift de-capitalizes the name of IsSet property in Cocoa
+    * [THRIFT-3877] - cpp: the http implementation is not standard; interop with other languages is spotty at best
+    * [THRIFT-4180] - cpp: Impossible to build Thrift C++ library for Android (NDK)
+    * [THRIFT-4384] - cpp: Using multiple async services simultaneously is not thread-safe
+    * [THRIFT-3108] - haskell: Defaulted struct parameters on a service generates invalid Haskell
+    * [THRIFT-3990] - nodejs: Exception swallowed by deserialization function
+    * [THRIFT-4214] - nodejs: map<i64,value> key treated as hex value in JavaScript
+    * [THRIFT-4602] - nodejs: ERROR in ./node_modules/thrift/lib/nodejs/lib/thrift/connection.js Module not found: Error: Can't resolve 'child_process'
+    * [THRIFT-4639] - nodejs: Sequence numbering for multiplexed protocol broken
+    * [THRIFT-1310] - php: sequence and reconnection management issues
+    * [THRIFT-1538] - php: Error during deserialization int64 on 32-bit architecture
+    * [THRIFT-1580] - php: thrift type i64 java to php serialize/deserealize not working
+    * [THRIFT-1950] - php: PHP gets stuck in infinite loop
+    * [THRIFT-2954] - python: sending int or float in a double field breaks the connection
+    * [THRIFT-4080] - python: unix sockets can get stuck forever
+    * [THRIFT-4281] - python: generated code is out of order and causes load issues
+    * [THRIFT-4677] - py3: UnicodeDecideError in Python3
+
+## Build Process
+    * [THRIFT-4067] - Windows thrift compiler distributed on the apache web site has runtime dependencies
+    * [THRIFT-4308] - D language docker images need demios for libevent and openssl fixed to re-enable make cross on dlang
+    * [THRIFT-4579] - Use Ubuntu Bionic (18.04 LTS) for CI builds instead of Artful (17.10)
+    * [THRIFT-4508] - Define CI operating system coverage rules for the project and (hopefully) simplify CI a little more
+    * [THRIFT-4397] - ubuntu install instructions broken on 16.04
+    * [THRIFT-4545] - Appveyor builds are failing due to a haskell / cabal update in chocolatey
+    * [THRIFT-4452] - optimize Dockerfile (only onetime apt-get update)
+    * [THRIFT-4440] - rm `build/docker/ubuntu-trusty/Dockerfile.orig`
+    * [THRIFT-4352] - Ubuntu Artful doesn't appear to be compatible with Thrift and Haxe 3.4.2
+    * [THRIFT-4666] - DLang Client Pool Test fails sporadically
+    * [THRIFT-4676] - CL tutorial build fails sporadically
+    * [THRIFT-4456] - Make haxelib download quiet so it doesn't blow up the build log
+    * [THRIFT-4605] - bootstrap.sh fails if automake=1.16.1
+
+## c_glib
+    * [THRIFT-4648] - The C (GLib) compiler's handling of namespaces has been improved.
+    * [THRIFT-4622] - glibC compilation issue
+    * [THRIFT-4671] - c glib is unable to handle client close unexpectedly
+
+## cl (new language support in 0.12.0)
+    * [THRIFT-82] - Common Lisp support
+
+## csharp
+    * [THRIFT-4558] - reserved Csharp keywords are not escaped in some cases
+    * [THRIFT-4637] - C# async mode generates incorrect code with inherited services
+    * [THRIFT-4672] - IAsyncResult style methods not being supported by certain transports leads to issues in mixed ISync/IAsync use cases
+    * [THRIFT-4539] - Allow TBufferedTransport to be used as base class
+    * [THRIFT-4535] - XML docs; code cleanup (tabs->spaces; String->string)
+    * [THRIFT-4492] - protected ExceptionType type member of TApplicationException cannot be accessed
+    * [THRIFT-4446] - JSONProtocol Base64 Encoding Trims Padding
+    * [THRIFT-4455] - Missing dispose calls in ThreadedServer & ThreadpoolServer
+    * [THRIFT-4609] - keep InnerException wherever appropriate
+    * [THRIFT-4673] - IAsyncResult not supported by layered transports (buffered/framed)
+
+## cpp
+    * [THRIFT-4476] - Typecasting problem on list items
+    * [THRIFT-4465] - TNonblockingServer throwing THRIFT LOGGER: TConnection::workSocket(): THRIFT_EAGAIN (unavailable resources)
+    * [THRIFT-4680] - TBufferTransports.h does not compile under Visual Studio 2017
+    * [THRIFT-4618] - TNonblockingServer crash because of limitation of select()
+    * [THRIFT-4620] - TZlibTransport.cpp doesn't ensure that there is enough space for the zlib flush marker in the buffer.
+    * [THRIFT-4571] - ZeroMQ contrib library needs a refresh
+    * [THRIFT-4559] - TSSLServerSocket incorrectly prints errors
+    * [THRIFT-4578] - Move `TAsyncProtocolProcessor` into main thrift library
+    * [THRIFT-4418] - evhttp_connection_new is deprecated; use evhttp_connection_base_new
+
+## compiler
+    * [THRIFT-4644] - Compiler cannot be compiled on macOS(maybe also on other platforms with clang)
+    * [THRIFT-4531] - Thrift generates wrong Python code for immutable structures with optional members
+    * [THRIFT-4513] - thrift generated code is not stable for constants
+    * [THRIFT-4532] - Avoid updating Thrift compiler generated code if the output has not changed
+    * [THRIFT-4400] - Visual Studio Compiler project should link runtime statically in release builds
+    * [THRIFT-4399] - plugin.thrift t_const_value is not used as a union in C++ code -- fix this
+    * [THRIFT-4496] - Dealing with language keywords in Thrift (e.g. service method names)
+    * [THRIFT-4393] - repeated runs of compiler produce different binary output at plugin interface
+
+## dlang
+    * [THRIFT-4478] - Thrift will not build with dlang 2.078 or later
+    * [THRIFT-4503] - dlang servers logError on normal client disconnection
+    * [THRIFT-4308] - D language docker images need demios for libevent and openssl fixed to re-enable make cross on dlang
+
+## dart
+    * [THRIFT-4646] - Effective Dart and Exceptions
+    * [THRIFT-4439] - Shouldn't download dart.deb directly.
+
+## delphi
+    * [THRIFT-4562] - Calling wrong exception CTOR leads to "call failed: unknown result" instead of the real exception being thrown
+    * [THRIFT-4554] - uncompileable code with member names that are also types under specific conditions
+    * [THRIFT-4422] - Add Async implementation via IFuture
+    * [THRIFT-4485] - Possible invalid ptr AV with overlapped read/write on pipes
+    * [THRIFT-4549] - Thrift exceptions should derive from TException
+    * [THRIFT-4540] - buffered transport broken when trying to re-open a formerly closed transport
+    * [THRIFT-4473] - Move Thrift.Console.pas out of the Library
+    * [THRIFT-4490] - Allow a default service as fallback for multiplex processors connected by old clients
+    * [THRIFT-4454] - Large writes/reads may cause range check errors in debug mode
+    * [THRIFT-4461] - Compiler directive should match Delphi XE4
+    * [THRIFT-4462] - First line in Console duplicated
+    * [THRIFT-4642] - FPU ctrl word settings may cause an unexpected "denormalized" error
+    * [THRIFT-4589] - HTTP client timeouts are a) incomplete and b) not used at all
+    * [THRIFT-4590] - running the test client using HTTP transport leads to "CoInitialize not called"
+
+## erlang
+    * [THRIFT-4497] - Erlang records should use map() for map type
+    * [THRIFT-4495] - Erlang records should allow 'undefined' for non-required fields
+    * [THRIFT-4580] - Fix erlang tutorial unpack on Windows
+    * [THRIFT-4582] - Ubuntu Xenial erlang 18.3 "make check" fails
+
+## golang
+    * [THRIFT-4448] - Support for golang 1.6 and earlier has been dropped.
+    * [THRIFT-4253] - Go generator assigns strings to field in const instead of pointers.
+    * [THRIFT-4573] - Unions Field Count Does Not Consider Binary
+    * [THRIFT-4447] - Golang: Panic on p.c.Call when using deprecated initializers
+    * [THRIFT-4650] - Required field incorrectly marked as set when fieldType does not match
+    * [THRIFT-4486] - Golang: -remote.go client cleanup
+    * [THRIFT-4537] - TSimpleServer can exit Accept loop with lock still acquired
+    * [THRIFT-4516] - Add support for go 1.10
+    * [THRIFT-4421] - golang tests rely on gomock, which has change behaviour, causing tests to fail
+    * [THRIFT-4626] - Communication crash when using binary/compact protocol and zlib transport
+    * [THRIFT-4659] - golang race detected when closing listener socket
+
+## haskell
+    * [THRIFT-4634] - Haskell builds with older cabal cannot reconcile complex version requirements
+
+## java
+    * [THRIFT-4259] - Thrift does not compile due to Ant Maven task errors
+    * [THRIFT-1418] - Compiling Thrift from source: Class org.apache.tools.ant.taskdefs.ConditionTask doesn't support the nested "typefound" element
+    * [THRIFT-4530] - proposal: add nullability annotations to generated Java code
+    * [THRIFT-4614] - Generate missing @Nullable annotations for Java iterator getters
+    * [THRIFT-4555] - Getter of binary field in Java creates unnecessary copy
+    * [THRIFT-3983] - libthrift is deployed on central with pom packaging instead of jar
+    * [THRIFT-4294] - Java Configure Fails for Ant >= 1.10
+    * [THRIFT-4178] - Java libraries missing from package when using cmake
+    * [THRIFT-4120] - pom files are not generated or provided in the build
+    * [THRIFT-1507] - Maven can't download resource from central when behind a proxy and won't use local repository
+    * [THRIFT-4556] - Optional rethrow of unhandled exceptions in java processor
+    * [THRIFT-4337] - Able to set keyStore and trustStore as InputStream in the TSSLTransportFactory.TSSLTransportParameters
+    * [THRIFT-4566] - Pass message of unhandled exception to optional rethrow.
+    * [THRIFT-4506] - Remove assertion in Java SASL code that would be ignored in release builds
+    * [THRIFT-4470] - Include popular IDE file templates to gitignore
+    * [THRIFT-4429] - Make TThreadPoolServer.executorService_ available in inherited classes and refactor methods to be able customization
+    * [THRIFT-3769] - Fix logic of THRIFT-2268
+    * [THRIFT-4494] - Increase Java Socket Buffer Size
+    * [THRIFT-4499] - Remove Magic Number In TFIleTransport
+
+## js
+    * [THRIFT-4406] - JavaScript: Use modern Promise implementations
+    * [THRIFT-4625] - let / const variable decorators for es6 compiler
+    * [THRIFT-4653] - ES6 Classes
+    * [THRIFT-4592] - JS: readI32 performance on large arrays is very poor in Chrome
+    * [THRIFT-4509] - js and nodejs libraries need to be refreshed with current libraries
+    * [THRIFT-4403] - thrift.js: Incorrect usage of 'this' in TWebSocketTransport.__onOpen
+    * [THRIFT-4436] - Deserialization of nested list discards content
+    * [THRIFT-4437] - JS WebSocket client callbacks invoked twice on parallel requests
+    * [THRIFT-4679] - Duplicate declaration of InputBufferUnderrunError in lib/nodejs/lib/thrift/json_protocol.js
+    * [THRIFT-4551] - Add prettier for consistent JS code formatting
+
+## lua
+    * [THRIFT-4591] - lua client uses two write() calls per framed message send
+    * [THRIFT-3863] - Can't "make install" Lua Library
+
+## netcore
+    * [THRIFT-4524] - .NET Core Server doesn't close properly when cancelled
+    * [THRIFT-4434] - Update .NET Core components, add tests for .Net Core library and .Net Core compiler, fix bugs and build process
+    * [THRIFT-4446] - JSONProtocol Base64 Encoding Trims Padding
+
+## node.js
+    * [THRIFT-4225] - Error handling malformed arguments leaks memory, corrupts transport buffers causing next RPC to fail
+    * [THRIFT-3950] - Memory leak while calling oneway method
+    * [THRIFT-3143] - add typescript directory support
+    * [THRIFT-4564] - TBufferedTransport can leave corrupt data in the buffer
+    * [THRIFT-4647] - Node.js Fileserver webroot path
+    * [THRIFT-4489] - Unix domain socket support for NodeJS client
+    * [THRIFT-4443] - node.js json_protocol throws error in skip function
+    * [THRIFT-4604] - NodeJS: Expose Int64 from browser.js for consumption by browser
+    * [THRIFT-4480] - NodeJS warning on binary_protocol writeMessageEnd when seqid = 0
+
+## perl
+    * [THRIFT-4382] - Replace the use of Perl Indirect Object Syntax calls to new()
+    * [THRIFT-4471] - Thrift CPAN release is missing Makefile.PL and the clients are unable to build the module
+    * [THRIFT-4416] - Perl CPAN Packaging Improvements
+
+## php
+    * [THRIFT-4474] - PHP generator use PSR-4 default
+    * [THRIFT-4463] - PHP generated code match PSR-2
+    * [THRIFT-4373] - Extending Thrift class results in "Attempt serialize from non-Thrift object"
+    * [THRIFT-4354] - TSocket block on read
+    * [THRIFT-4423] - migrate php library to psr-4
+    * [THRIFT-4656] - infinite loop in latest PHP library
+    * [THRIFT-4477] - TBufferedTransport must have underlying transport
+    * [THRIFT-4475] - lib/php/test should be checked for PSR-2
+    * [THRIFT-4498] - add phpcs back
+    * [THRIFT-4460] - php library use PSR-2
+    * [THRIFT-4641] - TCurlClient doesn't check for HTTP status code
+    * [THRIFT-4645] - TCurlClient: show actual error message when throwing TTransportException
+    * [THRIFT-4674] - Add stream context support into PHP/THttpClient
+    * [THRIFT-4459] - reduce php library directory depth
+
+## python
+    * [THRIFT-4670] - Twisted, slots, and void method fails with "object has no attribute 'success'"
+    * [THRIFT-4464] - Potentially server-crashing typo in Python TNonblockingServer
+    * [THRIFT-4548] - Supporting TBinaryProtocolAccelerated protocol when using TMultiplexedProcessor in Python
+    * [THRIFT-4577] - Outdated cipher string in python unit test
+    * [THRIFT-4505] - python build on Vagrant Windows boxes fails
+    * [THRIFT-4621] - THeader for Python
+    * [THRIFT-4668] - make socket backlog configurable for python
+    * [THRIFT-4561] - Python: cleanup socket timeout settings
+
+## ruby
+    * [THRIFT-4289] - Thrift RSpec test suite fails with Ruby 2.4.x due to Fixnum deprecation
+    * [THRIFT-4342] - Support ruby rspec 3
+    * [THRIFT-4525] - Add ssl socket option to ruby cross tests
+    * [THRIFT-4450] - Add seek support to TCompactInputProtocol in Rust
+    * [THRIFT-4631] - Codegen Creates Invalid Ruby for Recursive Structs
+    * [THRIFT-4472] - Fix the genspec for ruby so it does not complain about an invalid license
+
+## rust
+    * [THRIFT-4662] - Rust const string calls function at compile time
+    * [THRIFT-4661] - Rust enum name wrong case in generated structs
+    * [THRIFT-4617] - Avoid generating conflicting struct names in Rust code
+    * [THRIFT-4529] - Rust generation should include #![allow(non_snake_case)] or force conform to Rust style guidelines
+    * [THRIFT-4390] - Rust binary protocol and buffered transport cannot handle writes above 4096 bytes
+    * [THRIFT-4419] - Rust framed transport cannot handle writes above 4096 bytes
+    * [THRIFT-4658] - Rust's TBinaryInputProtocol fails when strict is false
+    * [THRIFT-4187] - Dart -> Rust Framed cross tests fail
+    * [THRIFT-4664] - Rust cannot create ReadHalf/WriteHalf to implement custom tranports
+    * [THRIFT-4665] - Keep Rust library up-to-date on crates.io
+
+## swift (new language support in 0.12.0)
+    * [THRIFT-3773] - Swift Library
+
+## test suite
+    * [THRIFT-4515] - Gracefully shutdown cross-test servers to fully test teardown
+    * [THRIFT-4085] - Add .NET Core to the make cross standard test suite
+    * [THRIFT-4358] - Add unix domain sockets in ruby to cross test - code exists
+
+## typescript (new language support in 0.12.0)
+    * [THRIFT-3143] - add typescript directory support
+
+================================================================================
+Thrift 0.11.0
+--------------------------------------------------------------------------------
+## Sub-task
+    * [THRIFT-2733] - Erlang coding standards
+    * [THRIFT-2740] - Perl coding standards
+    * [THRIFT-3610] - Streamline exception handling in Python server handler
+    * [THRIFT-3686] - Java processor should report internal error on uncaught exception
+    * [THRIFT-4049] - Skip() should throw TProtocolException.INVALID_DATA on unknown data types
+    * [THRIFT-4053] - Skip() should throw TProtocolException.INVALID_DATA on unknown data types
+    * [THRIFT-4136] - Align is_binary() method with is_string() to simplify those checks
+    * [THRIFT-4137] - Fix remaining undefined behavior invalid vptr casts in Thrift Compiler
+    * [THRIFT-4138] - Fix remaining undefined behavior invalid vptr casts in C++ library
+    * [THRIFT-4296] - Fix Ubuntu Xenial build environment for the python language
+    * [THRIFT-4298] - Fix Ubuntu Xenial build environment for the go 1.6 language
+    * [THRIFT-4299] - Fix Ubuntu Xenial build environment for the D language
+    * [THRIFT-4300] - Fix make cross in Ubuntu Xenial docker environment, once all language support issues are fixed
+    * [THRIFT-4302] - Fix Ubuntu Xenial make cross testing for lua and php7
+    * [THRIFT-4398] - Update EXTRA_DIST for "make dist"
+
+## Bug
+    * [THRIFT-381] - Fail fast if configure detects C++ problems
+    * [THRIFT-1677] - MinGW support broken
+    * [THRIFT-1805] - Thrift should not swallow ALL exceptions
+    * [THRIFT-2026] - Fix TCompactProtocol 64 bit builds
+    * [THRIFT-2642] - Recursive structs don't work in python
+    * [THRIFT-2889] - stable release 0.9.2, erlang tutorial broken
+    * [THRIFT-2913] - Ruby Server Thrift::ThreadPoolServer should serve inside a thread
+    * [THRIFT-2998] - Node.js: Missing header from http request
+    * [THRIFT-3000] - .NET implementation has trouble with mixed IP modes
+    * [THRIFT-3281] - Travis CI build passed but the log says BUILD FAILED
+    * [THRIFT-3358] - Makefile:1362: *** missing separator. Stop.
+    * [THRIFT-3600] - Make TTwisted server send exception on unexpected handler error
+    * [THRIFT-3602] - Make Tornado server send exception on unexpected handler error
+    * [THRIFT-3657] - D TFileWriterTransport close should use non-priority send
+    * [THRIFT-3700] - Go Map has wrong default value when optional
+    * [THRIFT-3703] - Unions Field Count Does Not Consider Map/Set/List Fields
+    * [THRIFT-3730] - server log error twice
+    * [THRIFT-3778] - go client can not pass method parameter to server of other language if no field_id is given
+    * [THRIFT-3784] - thrift-maven-plugin generates invalid include directories for IDL in dependency JARs
+    * [THRIFT-3801] - Node Thrift client throws exception with multiplexer and responses that are bigger than a single buffer
+    * [THRIFT-3821] - TMemoryBuffer buffer may overflow when resizing
+    * [THRIFT-3832] - Thrift version 0.9.3 example on Windows, Visual Studio, linking errors during compiling
+    * [THRIFT-3847] - thrift/config.h includes a #define for VERSION which will likely conflict with existing user environment or code
+    * [THRIFT-3873] - Fix various build warnings when using Visual Studio
+    * [THRIFT-3891] - TNonblockingServer configured with more than one IO threads does not always return from serve() upon stop()
+    * [THRIFT-3892] - Thrift uses TLS SNI extension provided by OpenSSL library. Older version of OpenSSL(< 0.9.8f) may create problem because they do not support 'SSL_set_tlsext_host_name()'.
+    * [THRIFT-3895] - Build fails using Java 1.8 with Ant < 1.9
+    * [THRIFT-3896] - map<string,string> data with number string key cannot access that deserialized by php extension
+    * [THRIFT-3938] - Python TNonblockingServer does not work with SSL
+    * [THRIFT-3944] - TSSLSocket has dead code in checkHandshake
+    * [THRIFT-3946] - Java 1.5 compatibility broken for binary fields (java5 option)
+    * [THRIFT-3960] - Inherited services in Lua generator are not named correctly
+    * [THRIFT-3962] - Ant build.xml broken on Windows for Java library
+    * [THRIFT-3963] - Thrift.cabal filename does not match module name
+    * [THRIFT-3967] - gobject/gparam.h:166:33: warning: enumerator value for ‘G_PARAM_DEPRECATED’ is not an integer constant expression
+    * [THRIFT-3968] - Deserializing empty string/binary fields
+    * [THRIFT-3974] - Using clang-3.8 and ThreadSanitizer on the concurrency_test claims bad PThread behavior
+    * [THRIFT-3984] - PHP7 extension causes segfault
+    * [THRIFT-4008] - broken ci due to upstream dependency versioning break
+    * [THRIFT-4009] - Use @implementer instead of implements in TTwisted.py
+    * [THRIFT-4010] - Q.fcall messing up with *this* pointer inside called function
+    * [THRIFT-4011] - Sets of Thrift structs generate Go code that can't be serialized to JSON
+    * [THRIFT-4012] - Python Twisted implementation uses implements, not compatible with Py3
+    * [THRIFT-4014] - align C# meta data in AssemblyInfo.cs
+    * [THRIFT-4015] - Fix wrongly spelled "Thirft"s
+    * [THRIFT-4016] - testInsanity() impl does not conform to test spec in ThriftTest.thrift
+    * [THRIFT-4023] - Skip unexpected field types on read/write
+    * [THRIFT-4024] - Skip() should throw on unknown data types
+    * [THRIFT-4026] - TSSLSocket doesn't work with Python < 2.7.9
+    * [THRIFT-4029] - Accelerated protocols do not build from thrift-py 0.10.0 on PyPI
+    * [THRIFT-4031] - Go plugin generates invalid code for lists of typedef'ed built-in types
+    * [THRIFT-4033] - Default build WITH_PLUGIN=ON for all builds results in packaging errors
+    * [THRIFT-4034] - CMake doesn't work to build compiler on MacOS
+    * [THRIFT-4036] - Add .NET Core environment/build support to the docker image
+    * [THRIFT-4038] - socket check: checking an unsigned number against >= 0 never fails
+    * [THRIFT-4042] - ExtractionError when using accelerated thrift in a multiprocess test
+    * [THRIFT-4043] - thrift perl debian package is placing files in the wrong place
+    * [THRIFT-4044] - Build job 17 failing on every pull request; hspec core (haskell) 2.4 issue
+    * [THRIFT-4046] - MinGW with gcc 6.2 does not compile on Windows
+    * [THRIFT-4060] - Thrift printTo ostream overload mechanism breaks down when types are nested
+    * [THRIFT-4062] - Remove debug print from TServiceClient
+    * [THRIFT-4065] - Document Perl ForkingServer signal restriction imposed by THRIFT-3848 and remove unnecessary code
+    * [THRIFT-4068] - A code comment in Java ServerSocket is wrong around accept()
+    * [THRIFT-4073] - enum files are still being generated with unused imports
+    * [THRIFT-4076] - Appveyor builds failing because ant 1.9.8 was removed from apache servers
+    * [THRIFT-4077] - AI_ADDRCONFIG redefined after recent change to PlatformSocket header
+    * [THRIFT-4079] - Generated perl code that returns structures from included thrift files is missing a necessary use clause
+    * [THRIFT-4087] - Spurious exception destroying TThreadedServer because of incorrect join() call
+    * [THRIFT-4102] - TBufferedTransport performance issue since 0.10.0
+    * [THRIFT-4106] - concurrency_test fails randomly
+    * [THRIFT-4108] - c_glib thrift ssl has multiple bugs and deprecated functions
+    * [THRIFT-4109] - Configure Script uses string comparison for versions
+    * [THRIFT-4129] - C++ TNonblockingServer fd leak when failing to dispatch new connections
+    * [THRIFT-4131] - Javascript with WebSocket handles oneway methods wrong
+    * [THRIFT-4134] - Fix remaining undefined behavior invalid vptr casts
+    * [THRIFT-4140] - Use of non-thread-safe function gmtime()
+    * [THRIFT-4141] - Installation of haxe in docker files refers to a redirect link and fails
+    * [THRIFT-4147] - Rust: protocol should accept transports with non-static lifetime
+    * [THRIFT-4148] - [maven-thrift-plugin] compile error while import a thrift in dependency jar file.
+    * [THRIFT-4149] - System.out pollutes log files 
+    * [THRIFT-4154] - PHP close() of a TSocket needs to close any type of socket
+    * [THRIFT-4158] - minor issue in README-MSYS2.md
+    * [THRIFT-4159] - Building tests fails on MSYS2 (MinGW64) due to a (small?) linker error
+    * [THRIFT-4160] - TNonblocking server fix use of closed/freed connections
+    * [THRIFT-4161] - TNonBlocking server using uninitialized event in error paths
+    * [THRIFT-4162] - TNonBlocking handling of TSockets in error state is incorrect after fd is closed
+    * [THRIFT-4164] - Core in TSSLSocket cleanupOpenSSL when destroying a mutex used by openssl
+    * [THRIFT-4165] - C++ build has many warnings under c++03 due to recent changes, cmake needs better platform-independent language level control
+    * [THRIFT-4166] - Recent fix to remove boost::lexical_cast usage broke VS2010
+    * [THRIFT-4167] - Missing compile flag
+    * [THRIFT-4170] - Support lua 5.1 or earlier properly for object length determination
+    * [THRIFT-4172] - node.js tutorial client does not import assert, connection issues are not handled properly
+    * [THRIFT-4177] - Java compiler produces deep copy constructor that could make shallow copy instead
+    * [THRIFT-4184] - Building on Appveyor: invalid escape sequence \L
+    * [THRIFT-4185] - fb303 counter encoding fix
+    * [THRIFT-4189] - Framed/buffered transport Dispose() does not dispose the nested transport
+    * [THRIFT-4193] - Lower the default maxReadBufferBytes for non-blocking servers
+    * [THRIFT-4195] - Compilation to GO produces broken code
+    * [THRIFT-4196] - Cannot generate recursive Rust types
+    * [THRIFT-4204] - typo in compact spec
+    * [THRIFT-4206] - Strings in container fields are not decoded properly with py:dynamic and py:utf8strings
+    * [THRIFT-4208] - C# NamedPipesServer not really working in some scenarios
+    * [THRIFT-4211] - Fix GError glib management under Thrift
+    * [THRIFT-4212] - c_glib flush tries to close SSL even if socket is invalid
+    * [THRIFT-4213] - Travis build fails at curl -sSL https://www.npmjs.com/install.sh | sh
+    * [THRIFT-4215] - Golang TTransportFactory Pattern Squelches Errors
+    * [THRIFT-4216] - Golang Http Clients Do Not Respect User Options
+    * [THRIFT-4218] - Set TCP_NODELAY for PHP client socket
+    * [THRIFT-4219] - Golang HTTP clients created with Nil buffer
+    * [THRIFT-4231] - TJSONProtocol throws unexpected non-Thrift-exception on null strings
+    * [THRIFT-4232] - ./configure does bad ant version check
+    * [THRIFT-4234] - Travis build fails cross language tests with "Unsupported security protocol type"
+    * [THRIFT-4237] - Go TServerSocket Race Conditions
+    * [THRIFT-4240] - Go TSimpleServer does not close properly
+    * [THRIFT-4243] - Go TSimpleServer race on wait in Stop() method
+    * [THRIFT-4245] - Golang TFramedTransport's writeBuffer increases if writes to transport failed
+    * [THRIFT-4246] - Sequence number mismatch on multiplexed clients
+    * [THRIFT-4247] - Compile fails with openssl 1.1
+    * [THRIFT-4248] - Compile fails - strncpy, memcmp, memset not declared in src/thrift/transport/TSSLSocket.cpp
+    * [THRIFT-4251] - Java Epoll Selector Bug
+    * [THRIFT-4257] - Typescript async callbacks do not provide the correct types
+    * [THRIFT-4258] - Boost/std thread wrapping faultiness
+    * [THRIFT-4260] - Go context generation issue. Context is parameter in Interface not in implementation
+    * [THRIFT-4261] - Go context generation issue: breaking change in generated code regarding thrift.TProcessorFunction interface
+    * [THRIFT-4262] - Invalid binding to InterlockedCompareExchange64() with 64-bit targets
+    * [THRIFT-4263] - Fix use after free bug for thrown exceptions
+    * [THRIFT-4266] - Erlang library throws during skipping fields of composite type (maps, lists, structs, sets)
+    * [THRIFT-4268] - Erlang library emits debugging output in transport layer
+    * [THRIFT-4273] - erlang:now/0: Deprecated BIF. 
+    * [THRIFT-4274] - Python feature tests for SSL/TLS failing
+    * [THRIFT-4279] - Wrong path in include directive in generated Thrift sources
+    * [THRIFT-4283] - TNamedPipeServer race condition in interrupt
+    * [THRIFT-4284] - File contains a NBSP: lib/nodejs/lib/thrift/web_server.js
+    * [THRIFT-4290] - C# nullable option generates invalid code for non-required enum field with default value
+    * [THRIFT-4292] - TimerManager::remove() is not implemented
+    * [THRIFT-4307] - Make ssl-open timeout effective in golang client
+    * [THRIFT-4312] - Erlang client cannot connect to Python server: exception error: econnrefused
+    * [THRIFT-4313] - Program code of the Erlang tutorial files contain syntax errors
+    * [THRIFT-4316] - TByteBuffer.java will read too much data if a previous read returns fewer bytes than requested
+    * [THRIFT-4319] - command line switch for "evhttp" incorrectly resolved to anon pipes
+    * [THRIFT-4323] - range check errors or NPE in edge cases
+    * [THRIFT-4324] - field names can conflict with local vars in generated code
+    * [THRIFT-4328] - Travis CI builds are timing out (job 1) and haxe builds are failing since 9/11
+    * [THRIFT-4329] - c_glib Doesn't have a multiplexed processor
+    * [THRIFT-4331] - C++: TSSLSockets bug in handling huge messages, bug in handling polling
+    * [THRIFT-4332] - Binary protocol has memory leaks
+    * [THRIFT-4334] - Perl indentation incorrect when defaulting field attribute to a struct
+    * [THRIFT-4339] - Thrift Framed Transport in Erlang crashes server when client disconnects
+    * [THRIFT-4340] - Erlang fix a crash on client close
+    * [THRIFT-4355] - Javascript indentation incorrect when defaulting field attribute to a struct
+    * [THRIFT-4356] - thrift_protocol call Transport cause Segmentation fault
+    * [THRIFT-4359] - Haxe compiler looks like it is producing incorrect code for map or set key that is binary type
+    * [THRIFT-4362] - Missing size-check can lead to huge memory allocation
+    * [THRIFT-4364] - Website contributing guide erroneously recommends submitting patches in JIRA
+    * [THRIFT-4365] - Perl generated code uses indirect object syntax, which occasionally causes compilation errors.
+    * [THRIFT-4367] - python TProcessor.process is missing "self"
+    * [THRIFT-4370] - Ubuntu Artful cppcheck and flake8 are more stringent and causing SCA build job failures
+    * [THRIFT-4372] - Pipe write operations across a network are limited to 65,535 bytes per write. 
+    * [THRIFT-4374] - cannot load thrift_protocol due to undefined symbol: _ZTVN10__cxxabiv120__si_class_type_infoE
+    * [THRIFT-4375] - TMemory throw bad_alloc due to counter overflow
+    * [THRIFT-4376] - Coverity high impact issue resolution
+    * [THRIFT-4377] - haxe. socket handles leak in TSimpleServer
+    * [THRIFT-4381] - Wrong isset bitfield value after transmission
+    * [THRIFT-4385] - Go remote client -u flag is broken
+    * [THRIFT-4392] - compiler/..../plugin.thrift structs mis-ordered blows up ocaml generator
+    * [THRIFT-4395] - Unable to build in the ubuntu-xenial docker image: clap 2.28 requires Rust 1.20
+    * [THRIFT-4396] - inconsistent (or plain wrong) version numbers in master/trunk 
+
+## Documentation
+    * [THRIFT-4157] - outdated readme about Haxe installation on Linux
+
+## Improvement
+    * [THRIFT-105] - make a thrift_spec for a structures with negative tags
+    * [THRIFT-281] - Cocoa library code needs comments, badly
+    * [THRIFT-775] - performance improvements for Perl
+    * [THRIFT-2221] - Generate c++ code with std::shared_ptr instead of boost::shared_ptr.
+    * [THRIFT-2364] - OCaml: Use Oasis exclusively for build process
+    * [THRIFT-2504] - TMultiplexedProcessor should allow registering default processor called if no service name is present
+    * [THRIFT-3207] - Enable build with OpenSSL 1.1.0 series
+    * [THRIFT-3272] - Perl SSL Authentication Support
+    * [THRIFT-3357] - Generate EnumSet/EnumMap where elements/keys are enums
+    * [THRIFT-3369] - Implement SSL/TLS support on C with c_glib
+    * [THRIFT-3467] - Go Maps for Thrift Sets Should Have Values of Type struct{} 
+    * [THRIFT-3580] - THeader for Haskell
+    * [THRIFT-3627] - Missing basic code style consistency of JavaScript.
+    * [THRIFT-3706] - There's no support for Multiplexed protocol on c_glib library
+    * [THRIFT-3766] - Add getUnderlyingTransport() to TZlibTransport
+    * [THRIFT-3776] - Go code from multiple thrift files with the same namespace
+    * [THRIFT-3823] - Escape documentation while generating non escaped documetation
+    * [THRIFT-3854] - allow users to clear read buffers
+    * [THRIFT-3859] - Unix Domain Socket Support in Objective-C
+    * [THRIFT-3921] - C++ code should print enums as strings
+    * [THRIFT-3926] - There should be an error emitted when http status code is not 200 
+    * [THRIFT-4007] - Micro-optimization of TTransport.py
+    * [THRIFT-4040] - Add real cause of TNonblockingServerSocket error to exception
+    * [THRIFT-4064] - Update node library dependencies
+    * [THRIFT-4069] - All perl packages should have proper namespace, version syntax, and use proper thrift exceptions
+    * [THRIFT-4071] - Consolidate the Travis CI jobs where possible to put less stress on the Apache Foundation's allocation of CI build slaves
+    * [THRIFT-4072] - Add the possibility to send custom headers in TCurlClient
+    * [THRIFT-4075] - Better MinGW support for headers-only boost (without thread library)
+    * [THRIFT-4081] - Provide a MinGW 64-bit Appveyor CI build for better pull request validation
+    * [THRIFT-4084] - Improve SSL security in thrift by adding a make cross client that checks to make sure SSLv3 protocol cannot be negotiated
+    * [THRIFT-4095] - Add multiplexed protocol to Travis CI for make cross
+    * [THRIFT-4099] - Auto-derive Hash for generated Rust structs
+    * [THRIFT-4110] - The debian build files do not produce a "-dbg" package for debug symbols of libthrift0
+    * [THRIFT-4114] - Space after '///' in doc comments
+    * [THRIFT-4126] - Validate objects in php extension
+    * [THRIFT-4130] - Ensure Apache Http connection is released back to pool after use
+    * [THRIFT-4151] - Thrift Mutex Contention Profiling (pthreads) should be disabled by default
+    * [THRIFT-4176] - Implement a threaded and threadpool server type for Rust
+    * [THRIFT-4183] - Named pipe client blocks forever on Open() when there is no server at the other end
+    * [THRIFT-4190] - improve C# TThreadPoolServer defaults
+    * [THRIFT-4197] - Implement transparent gzip compression for HTTP transport
+    * [THRIFT-4198] - Ruby should log Thrift internal errors to global logger
+    * [THRIFT-4203] - thrift server stop gracefully
+    * [THRIFT-4205] - c_glib is not linking against glib + gobject
+    * [THRIFT-4209] - warning CS0414 in T[TLS]ServerSocket.cs
+    * [THRIFT-4210] - include Thrift.45.csproj into CI runs 
+    * [THRIFT-4217] - HttpClient should support gzip and deflate
+    * [THRIFT-4222] - Support Unix Domain Sockets in Golang TServerSocket
+    * [THRIFT-4233] - Make THsHaServer.invoker available (get method only) in inherited classes
+    * [THRIFT-4236] - Support context in go generated code.
+    * [THRIFT-4238] - JSON generator: make annotation-aware
+    * [THRIFT-4269] - Don't append '.' to Erlang namespace if it ends in '_'.
+    * [THRIFT-4270] - Generate Erlang mapping functions for const maps and lists
+    * [THRIFT-4275] - Add support for zope.interface only, apart from twisted support.
+    * [THRIFT-4285] - Pull generated send/recv into library to allow behaviour to be customised
+    * [THRIFT-4287] - Add c++ compiler "no_skeleton" flag option
+    * [THRIFT-4288] - Implement logging levels properly for node.js
+    * [THRIFT-4295] - Refresh the Docker image file suite for Ubuntu, Debian, and CentOS
+    * [THRIFT-4305] - Emit ddoc for generated items
+    * [THRIFT-4306] - Thrift imports not replicated to D service output
+    * [THRIFT-4315] - Add default message for TApplicationException
+    * [THRIFT-4318] - Delphi performance improvements
+    * [THRIFT-4325] - Simplify automake cross compilation by relying on one global THRIFT compiler path
+    * [THRIFT-4327] - Improve TimerManager API to allow removing specific task
+    * [THRIFT-4330] - Allow unused crates in Rust files
+    * [THRIFT-4333] - Erlang tutorial examples are using a different port (9999)
+    * [THRIFT-4343] - Change CI builds to use node.js 8.x LTS once available
+    * [THRIFT-4345] - Create a docker build environment that uses the minimum supported language levels
+    * [THRIFT-4346] - Allow Zlib transport factory to wrap other transports
+    * [THRIFT-4348] - Perl HTTP Client custom HTTP headers
+    * [THRIFT-4350] - Update netcore build for dotnet 2.0 sdk and make cross validation
+    * [THRIFT-4351] - Use Travis CI Build Stages to optimize the CI build
+    * [THRIFT-4353] - cannot read via thrift_protocol at server side
+    * [THRIFT-4378] - add set stopTimeoutUnit method to TThreadPoolServer
+
+## New Feature
+    * [THRIFT-750] - C++ Compiler Virtual Function Option
+    * [THRIFT-2945] - Implement support for Rust language
+    * [THRIFT-3857] - thrift js:node complier support an object as parameter not an instance of struct
+    * [THRIFT-3933] - Port official C# .NET library for Thrift to C# .NET Core libary
+    * [THRIFT-4039] - Update of Apache Thrift .Net Core lib 
+    * [THRIFT-4113] - Provide a buffer transport for reading/writing in memory byte stream
+
+## Question
+    * [THRIFT-2956] - autoconf - possibly undefined macro - AC_PROG_BISON
+    * [THRIFT-4223] - Add support to the isServing() method for the C++ library
+
+## Task
+    * [THRIFT-3622] - Fix deprecated uses of std::auto_ptr
+    * [THRIFT-4028] - Please remove System.out.format from the source code
+    * [THRIFT-4186] - Build and test rust client in Travis
+
+## Test
+    * [THRIFT-4264] - PHP - Support both shared & static linking of sockets library
+
+## Wish
+    * [THRIFT-4344] - Define and maintain the minimum language level for all languages in one place
+
+	
+Thrift 0.10.0
+--------------------------------------------------------------------------------
+## Bug
+    * [THRIFT-1840] - Thrift Generated Code Causes Global Variable Leaks
+    * [THRIFT-1828] - moc_TQTcpServer.cpp was removed from source tree but is in thrift-0.9.0.tar.gz
+    * [THRIFT-1790] - cocoa: Duplicate interface definition error
+    * [THRIFT-1776] - TPipeServer should implement "listen", so that TServerEventHandler preServe will work right
+    * [THRIFT-1351] - Compiler does not care about binary strings
+    * [THRIFT-1229] - Python fastbinary.c can not handle unicode as generated python code
+    * [THRIFT-749] - C++ TBufferedTransports do not flush their buffers on delete
+    * [THRIFT-747] - C++ TSocket->close calls shutdown breaking forked parent process
+    * [THRIFT-732] - server exits abnormally when client calls send_xxx function without calling recv_xxx function
+    * [THRIFT-3942] - TSSLSocket does not honor send and receive timeouts
+    * [THRIFT-3941] - WinXP version of thrift_poll() relies on undefined behavior by passing a destructed variable to select()
+    * [THRIFT-3940] - Visual Studio project file for compiler is broken
+    * [THRIFT-3943] - Coverity Scan identified some high severity defects
+    * [THRIFT-3929] - PHP "nsglobal" Option Results in Syntax Error in Generated Code (Trailing Backslash)
+    * [THRIFT-3936] - Cannot compile 0.10.0 development tip with VS2013 and earlier (snprintf, uint32_t)
+    * [THRIFT-3935] - Incorrect skipping of map and set
+    * [THRIFT-3920] - Ruby: Ensuring that HTTP failures will clear the http transport outbuf var
+    * [THRIFT-3919] - C# TTLSServerSocket does not use clientTimeout
+    * [THRIFT-3917] - Check backports.ssl_match_hostname module version
+    * [THRIFT-3909] - Fix c_glib static lib CMake build
+    * [THRIFT-3904] - Typo in node tutorial leads to wrong transport being used
+    * [THRIFT-3848] - As an implementer of a perl socket server, I do not want to have to remember to ignore SIGCHLD for it to work properly
+    * [THRIFT-3844] - thrift_protocol cannot compile in 7.0.7
+    * [THRIFT-3843] - integer issues with Haxe PHP targets cause ZigZag encoding to fail
+    * [THRIFT-3842] - Dart generates incorrect code for a const struct
+    * [THRIFT-3841] - dart compact protocol incorrectly serializes/deserialized doubles
+    * [THRIFT-3708] - NameError: global name 'TProtocol' is not defined
+    * [THRIFT-3704] - "TConnectedClient died: Could not refill buffer" message shown when using HTTP Server
+    * [THRIFT-3678] - Fix javadoc errors on JDK 8
+    * [THRIFT-3014] - AppVeyor support
+    * [THRIFT-2994] - Node.js TJSONProtocol cannot be used for object serialization.
+    * [THRIFT-2974] - writeToParcel throws NPE for optional enum fields
+    * [THRIFT-2948] - Python TJSONProtocol doesn't handle structs with binary fields containing invalid unicode.
+    * [THRIFT-2845] - ChildService.Plo: No such file or directory
+    * [THRIFT-3276] - Binary data does not decode correctly using the TJSONProtocol when the base64 encoded data is padded.
+    * [THRIFT-3253] - Using latest version of D gives deprecation notices
+    * [THRIFT-2883] - TTwisted.py, during ConnectionLost processing: exceptions.RuntimeError: dictionary changed size during iteration
+    * [THRIFT-2019] - Writing on a disconnected socket on Mac causes SIG PIPE
+    * [THRIFT-2020] - Thrift library has some empty files that haven't really been deleted
+    * [THRIFT-2049] - Go compiler doesn't build on native Windows
+    * [THRIFT-2024] - TServer.cpp warns on 64-bit platforms about truncating an rlim_t into an int
+    * [THRIFT-2023] - gettimeofday implementation on Windows errors when no time zone is passed in.
+    * [THRIFT-2022] - CoB and dense code generation still uses TR1 bind, even though that doesn't work with clang
+    * [THRIFT-2027] - Minor 64-bit and NOMINMAX issues in C++ library
+    * [THRIFT-2156] - TServerSocket::listen() is throwing exceptions with misleading information
+    * [THRIFT-2154] - Missing <operator body
+    * [THRIFT-2148] - TNonblockingMultiFetchClient imports log4j
+    * [THRIFT-2103] - [python] Support for SSL certificates with Subject Alternative Names
+    * [THRIFT-1931] - Sending a frame size of zero to a TNonblockingServer causes an assertion failure
+    * [THRIFT-1751] - definition of increase_max_fds doesn't compile when HAVE_SYS_RESOURCE_H is not defined
+    * [THRIFT-1522] - TServerSocket potential memory leak with addrinfo *res0
+    * [THRIFT-1547] - Problems building against static libevent
+    * [THRIFT-1545] - Generated javascript code uses "for in" for looping over arrays
+    * [THRIFT-1487] - Namespace problem, compile fails on generated code
+    * [THRIFT-1472] - Configuration conflicts with boost platform include header
+    * [THRIFT-6] - Thrift libraries and compiler lack version number
+    * [THRIFT-1680] - make install requires GNU make
+    * [THRIFT-3869] - Dart Tutorial build fails with Error 65 at "pub get"
+    * [THRIFT-3861] - Travis CI builds are timing out - C++TServerIntegrationTest appears to be hanging
+    * [THRIFT-3855] - In the go simple server, if Stop() is called multiple times it hangs
+    * [THRIFT-3885] - PHP: Error when readI64 in TCompactProtocol
+    * [THRIFT-3883] - Go TestAllConnection can fail with port 9090 collision
+    * [THRIFT-3884] - Fix Erlang compact protocol double endianess and boolean list
+    * [THRIFT-3880] - Erlang Compact protocol - boolean values inverted
+    * [THRIFT-3879] - Undefined evaluation order causes incorrect processing in the C++ library JSON protocol
+    * [THRIFT-3851] - Golang thrift continually adds the x/thrift content type 
+    * [THRIFT-3850] - All apache builds are failing when initiated from a github pull request
+    * [THRIFT-3837] - Thift 0.9.3 can't be build with QuickCheck 2.8.2 and unordered-containers 0.2.6
+    * [THRIFT-3831] - build of test/cpp/src/TestClient.cpp fails with newer gcc on platforms with unsigned char due to narrowing conversions
+    * [THRIFT-3827] - php CompactProtocol readI64 function has bug, when value has 32bit ~64bit, Example:value=1461563457000 
+    * [THRIFT-3825] - Javascript test dependency is no longer available
+    * [THRIFT-3814] - Fix contention in TNonblockingServerTest
+    * [THRIFT-3793] - Appveyor builds reference an ant version that is no longer there
+    * [THRIFT-3786] - Node.js TLS emits 'connect' before connection is ready
+    * [THRIFT-3780] - Fix dart int64 usage when compiled to js
+    * [THRIFT-3789] - Node.js lacks ability to destroy connection
+    * [THRIFT-3796] - There's no --dbg for dh_strip, maybe someone has mistaken this for --dbg-package.
+    * [THRIFT-3795] - Generated hashValue method in Swift will overflow
+    * [THRIFT-3790] - Fix Delphi named pipe client to use timeout even when pipe doesn't yet exist
+    * [THRIFT-3787] - Node.js Connection object doesn't handle errors correctly
+    * [THRIFT-3791] - Delphi pipe client may fail even in a non-error condition
+    * [THRIFT-3771] - TBufferedTransport gets in invalid state on read/write errors
+    * [THRIFT-3764] - PHP "make install" does not install TMultiplexedProtocol.php nor TSimpleJSONProtocol.php
+    * [THRIFT-3768] - TThreadedServer may crash if it is destroyed immediately after it returns from serve(); TThreadedServer disconnects clients
+    * [THRIFT-3765] - memory leak in python compact protocol extension
+    * [THRIFT-3758] - TApplicationException::getType and TProtocolException::getType should be const
+    * [THRIFT-3763] - Fix serialization of i64 larger than 2^53 for browserify
+    * [THRIFT-3759] - required fields that are nil are silently ignored on write
+    * [THRIFT-3753] - TServerFramework::stop may fail to interrupt connected clients
+    * [THRIFT-3755] - TDebugProtocol::writeString hits assert in isprint on Windows with debug CRT
+    * [THRIFT-3751] - Compiler allows field ids that are too large for generated code
+    * [THRIFT-3748] - Node.js Deserialization of lists of lists is broken
+    * [THRIFT-3760] - Fix install paths etc of debian packages for py and perl
+    * [THRIFT-3757] - Fix various build warnings on Windows with VS2015 compiler
+    * [THRIFT-3750] - NSCopying copyWithZone: implementation does not check isSet
+    * [THRIFT-3747] - Duplicate node.js build on Travis-CI
+    * [THRIFT-3744] - The precision should be 17 (16 bits need after dot) after dot for double type.
+    * [THRIFT-3741] - haxe test is broken
+    * [THRIFT-3739] - Deprecation warning in codegen/base.d
+    * [THRIFT-3735] - JSON protocol left in incorrect state when an exception is thrown during read or write operations
+    * [THRIFT-3734] - To compare two string as lowercase.
+    * [THRIFT-3743] - Java JSON protocol left in incorrect state when an exception is thrown during read or write operations
+    * [THRIFT-3731] - Perl multiplex test is flaky
+    * [THRIFT-3729] - Restrict rake version
+    * [THRIFT-3727] - Incorrect require paths in Node.js tutorial
+    * [THRIFT-3723] - Fix Lua include path
+    * [THRIFT-3722] - Fix cert path in C++ cross tests for non-Linux platform
+    * [THRIFT-3726] - Fix incorrect conditional in TMultiplexedProcessor.py
+    * [THRIFT-3725] - Skip a flaky cross test entry (d-dart compact framed-ip)
+    * [THRIFT-3724] - Fix incorrect timeval conversion in libevent.d
+    * [THRIFT-3721] - CLONE - why not add unicode strings support to python directly?
+    * [THRIFT-3720] - TTcpSocketStreamImpl.Read() returns 0 if not all requested bytes could be read
+    * [THRIFT-3719] - Dart generator should use lowerCamelCase for service names
+    * [THRIFT-3902] - TSocket.open throws NullPointerException
+    * [THRIFT-3901] - TFramedTransport.open throws NullPointerException
+    * [THRIFT-3893] - Command injection in format_go_output
+    * [THRIFT-3807] - Swift compiler does not escape reserved words
+    * [THRIFT-3798] - THttpClient does not use proxy from http_proxy, https_proxy environment variables
+    * [THRIFT-3809] - wrong/unused BINARY type code
+    * [THRIFT-3806] - Swift generator does not handle self-referring structs
+    * [THRIFT-3805] - Golang server susceptible to memory spike from malformed message
+    * [THRIFT-3797] - Generated Delphi processor shouldn't error out on timed out exceptions
+    * [THRIFT-3813] - Appveyor builds reference an openssl version that is no longer there
+    * [THRIFT-3658] - Missing file in THRIFT-3599
+    * [THRIFT-3649] - Python TSaslClientTransport initializes TTransportException incorrectly
+    * [THRIFT-3650] - incorrect union serialization 
+    * [THRIFT-3713] - lib/d/test/thrift_test_runner.sh is flaky on Jenkins
+    * [THRIFT-3668] - range check error in compact protocol
+    * [THRIFT-3663] - CMake cpp test fails to build on system without zlib
+    * [THRIFT-3712] - TTornadoServer cannot handle IPv6 address
+    * [THRIFT-3710] - Dart generator does not camel case Constants class names
+    * [THRIFT-3697] - Dart generator does not name imports
+    * [THRIFT-3690] - Work around docker image build failures on Travis-CI
+    * [THRIFT-3689] - thrift_reconnecting_client start failed when server is not available
+    * [THRIFT-3695] - Fix D test scripts
+    * [THRIFT-3675] - Union is not serialized correctly by Thrift C Glib
+    * [THRIFT-3673] - API fails with std::exception after a timeout occured in earlier any API call
+    * [THRIFT-3709] - Comment syntax can produce broken code
+    * [THRIFT-3705] - Go map has incorrect types when used with forward-defined types
+    * [THRIFT-3702] - Fix cross tests for Dart compact protocol (3 failing)
+    * [THRIFT-3683] - BadYieldError in thrift py:tornado server
+    * [THRIFT-3682] - Do not reuse refused sockets in test scripts
+    * [THRIFT-3681] - Fix Dart tutorial build
+    * [THRIFT-3680] - Java async processor fails to notify errors to clients
+    * [THRIFT-3714] - Thrift.TProtocolException is not defined in js/src/thrift.js
+    * [THRIFT-3688] - Fix socket bind failure detection of cross test
+    * [THRIFT-3641] - Ruby client should try to connect to every result of getaddrinfo
+    * [THRIFT-3635] - D transport_test is flaky on Jenkins and Travis
+    * [THRIFT-3618] - Python TSSLSocket deprecation message should print caller's location
+    * [THRIFT-3145] - JSON protocol does not handle bool and empty containers correctly
+    * [THRIFT-3158] - TBase<T,F>#deepCopy should return T
+    * [THRIFT-3157] - TBase signature should be TBase<T extends TBase<T,F>, F extends TFieldIdEnum>
+    * [THRIFT-3156] - Node TLS: server executes processing logic two full times
+    * [THRIFT-3154] - tutorial/py.tornado throw EOF exception
+    * [THRIFT-3063] - C++ build -Wunused-parameter warnings on processor_test, TransportTest
+    * [THRIFT-3056] - Add string/collection length limits for Python protocol readers
+    * [THRIFT-3237] - Fix TNamedPipeServer::createNamedPipe memory leak
+    * [THRIFT-3233] - Fix C++ ThreadManager::Impl::removeWorker worker join
+    * [THRIFT-3232] - Cannot deserialize json messages created with fieldNamesAsString 
+    * [THRIFT-3206] - Fix Visual Studio build failure due 'pthread_self': identifier not found
+    * [THRIFT-3200] - JS and nodejs do not encode JSON protocol binary fields as base64
+    * [THRIFT-3199] - Exception field has basic metadata
+    * [THRIFT-3182] - TFramedTransport is in an invalid state after frame size exception
+    * [THRIFT-2536] - new TSocket, uninitialised value reported by valgrind
+    * [THRIFT-2527] - Apache Thrift IDL Compiler code generated for Node.js should be jshint clean
+    * [THRIFT-2519] - "processor" class is not being generated
+    * [THRIFT-2431] - TFileTransportTest fails with "check delta < XXX failed"
+    * [THRIFT-2708] - Erlang library does not support "oneway" message type
+    * [THRIFT-3377] - Deep copy is actually shallow when using typedef members
+    * [THRIFT-3376] - C# and Python JSON protocol double values lose precision
+    * [THRIFT-3373] - Various fixes for cross test servers and clients
+    * [THRIFT-3370] - errno extern variable redefined. Not compiling for Android
+    * [THRIFT-3379] -  Potential out of range panic in Go JSON protocols
+    * [THRIFT-3371] - Abstract namespace Unix domain sockets broken in C++
+    * [THRIFT-3380] - nodejs: 0.9.2 -> 0.9.3 upgrade breaks Protocol and Transport requires
+    * [THRIFT-3367] - Fix bad links to coding_standards.md #634 
+    * [THRIFT-3401] - Nested collections emit Objective-C code that cannot compile
+    * [THRIFT-3403] - JSON String reader doesn't recognize UTF-16 surrogate pairs
+    * [THRIFT-3362] - make check fails for C++ at the SecurityTest
+    * [THRIFT-3395] - Cocoa compiler produces corrupt code when boxing enums inside map.
+    * [THRIFT-3394] - compiler generates uncompilable code
+    * [THRIFT-3388] - hash doesn't work on set/list
+    * [THRIFT-3391] - Wrong bool formatting in test server
+    * [THRIFT-3390] - TTornado server doesn't handle closed connections properly
+    * [THRIFT-3382] - TBase class for C++ Library
+    * [THRIFT-3392] - Java TZlibTransport does not close its wrapper streams upon close()
+    * [THRIFT-3383] - i64 related warnings 
+    * [THRIFT-3386] - misc. warnings with make check
+    * [THRIFT-3385] - warning: format ‘%lu’ expects ‘long unsigned int’, but has type ‘std::basic_string<char>::size_type {aka unsigned int}
+    * [THRIFT-3355] - npm WARN package.json thrift@1.0.0-dev No license field.
+    * [THRIFT-3360] - Improve cross test servers and clients further
+    * [THRIFT-3359] - Binary field incompatibilities
+    * [THRIFT-3354] - Fix word-extraction substr bug in initialism code
+    * [THRIFT-3350] - Python JSON protocol does not encode binary as Base64
+    * [THRIFT-3577] - assertion failed at line 512 of testcontainertest.c
+    * [THRIFT-3576] - Boost test --log_format arg does not accept lowercase
+    * [THRIFT-3575] - Go compiler tries to use unexported library methods when using read_write_private
+    * [THRIFT-3574] - Cocoa generator makes uncompilable imports
+    * [THRIFT-3570] - Remove duplicate instances that are added by upstream
+    * [THRIFT-3571] - Make feature test result browsable
+    * [THRIFT-3569] - c_glib protocols do not check number of bytes read by transport
+    * [THRIFT-3568] - THeader server crashes on readSlow
+    * [THRIFT-3567] - GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed
+    * [THRIFT-3566] - C++/Qt: TQTcpServerTest::test_communicate() is never executed
+    * [THRIFT-3564] - C++/Qt: potential core dump in TQTcpServer in case an exception occurs in TAsyncProcessor::process()
+    * [THRIFT-3558] - typos in c_glib tests
+    * [THRIFT-3559] - Fix awkward extra semi-colons with Cocoa container literals
+    * [THRIFT-3555] - 'configure' script does not honor --with-openssl=<path> for libcrypto for BN_init
+    * [THRIFT-3554] - Constant decls may lead to "Error: internal error: prepare_member_name_mapping() already active for different struct"
+    * [THRIFT-3552] - glib_c Memory Leak
+    * [THRIFT-3551] - Thrift perl library missing package declaration
+    * [THRIFT-3549] - Exceptions are not properly stringified in Perl library
+    * [THRIFT-3546] - NodeJS code should not be namespaced (and is currently not strict-mode compliant)
+    * [THRIFT-3545] - Container type literals do not compile
+    * [THRIFT-3538] - Remove UnboundMethodType in TProtocolDecorator
+    * [THRIFT-3536] - Error 'char' does not contain a definition for 'IsLowSurrogate' for WP7 target
+    * [THRIFT-3534] - Link error when building with Qt5
+    * [THRIFT-3533] - Can not send nil pointer as service method argument
+    * [THRIFT-3507] - THttpClient does not use proxy from http_proxy, https_proxy environment variables
+    * [THRIFT-3502] - C++ TServerSocket passes small buffer to getsockname
+    * [THRIFT-3501] - Forward slash in comment causes compiler error
+    * [THRIFT-3498] - C++ library assumes optional function pthread_attr_setschedpolicy is available
+    * [THRIFT-3497] - Build fails with "invalid use of incomplete type"
+    * [THRIFT-3496] - C++: Cob style client fails when sending a consecutive request
+    * [THRIFT-3493] - libthrift does not compile on windows using visual studio
+    * [THRIFT-3488] - warning: unused variable 'program'
+    * [THRIFT-3489] - warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
+    * [THRIFT-3487] - Full support for newer Delphi versions
+    * [THRIFT-3528] - Fix warnings in thrift.ll
+    * [THRIFT-3527] - -gen py:dynamic,utf8strings ignores utf8strings option
+    * [THRIFT-3526] - Code generated by py:utf8strings does not work for Python3
+    * [THRIFT-3524] - dcc32 warning "W1000 Symbol 'IsLowSurrogate' is deprecated: 'Use TCharHelper'" in Thrift.Protocol.JSON.pas
+    * [THRIFT-3525] - py:dynamic fails to handle binary list/set/map element
+    * [THRIFT-3521] - TSimpleJSONProtocolTest is not deterministic (fails when run on JDK 8)
+    * [THRIFT-3520] - Dart TSocket onError stream should be typed as Object
+    * [THRIFT-3519] - fastbinary does not work with -gen py:utf8strings
+    * [THRIFT-3518] - TConcurrentClientSyncInfo files were missing for Visual Studio
+    * [THRIFT-3512] - c_glib: Build fails due to missing features.h
+    * [THRIFT-3483] - Incorrect empty binary handling introduced by THRIFT-3359
+    * [THRIFT-3479] - Oneway calls should not return exceptions to clients
+    * [THRIFT-3478] - Restore dropped method to THsHaServer.java
+    * [THRIFT-3477] - Parser fails on enum item that starts with 'E' letter and continues with number 
+    * [THRIFT-3476] - Missing include in ./src/thrift/protocol/TJSONProtocol.cpp
+    * [THRIFT-3474] - Docker: thrift-compiler
+    * [THRIFT-3473] - When "optional' is used with a struct member, C++ server seems to not return it correctly
+    * [THRIFT-3468] - Dart TSocketTransport onError handler is too restrictive
+    * [THRIFT-3451] - thrift_protocol PHP extension missing config.m4 file
+    * [THRIFT-3456] - rounding issue in static assert
+    * [THRIFT-3455] - struct write method's return value is incorrect
+    * [THRIFT-3454] - Python Tornado tutorial is broken
+    * [THRIFT-3463] - Java can't be disabled in CMake build
+    * [THRIFT-3450] - NPE when using SSL
+    * [THRIFT-3449] - TBaseAsyncProcessor fb.responseReady() never called for oneway functions
+    * [THRIFT-3471] - Dart generator does not handle uppercase argument names
+    * [THRIFT-3470] - Sporadic timeouts with pipes
+    * [THRIFT-3465] - Go Code With Complex Const Initializer Compilation Depends On Struct Order
+    * [THRIFT-3464] - Fix several defects in c_glib code generator
+    * [THRIFT-3462] - Cocoa generates Incorrect #import header names
+    * [THRIFT-3453] - remove rat_exclude
+    * [THRIFT-3418] - Use of ciphers in ssl.wrap_socket() breaks python 2.6 compatibility
+    * [THRIFT-3417] - "namespace xsd" is not really working
+    * [THRIFT-3413] - Thrift code generation bug in Go when extending service
+    * [THRIFT-3420] - C++: TSSLSockets are not interruptable
+    * [THRIFT-3415] - include unistd.h conditionally
+    * [THRIFT-3414] - #include <pwd.h> in THeaderTransport.h breaks windows build
+    * [THRIFT-3411] - Go generates remotes with wrong package qualifiers when including
+    * [THRIFT-3430] - Go THttpClient does not read HTTP response body to completion when closing
+    * [THRIFT-3423] - First call to thrift_transport:read_exact fails to dispatch correct function
+    * [THRIFT-3422] - Go TServerSocket doesn't close on Interrupt
+    * [THRIFT-3421] - rebar as dependency instead of bundling (was:  rebar fails if PWD contains Unicode)
+    * [THRIFT-3428] - Go test fails when running make check
+    * [THRIFT-3445] - Throwable messages are hidden from JVM stack trace output
+    * [THRIFT-3443] - Thrift include can generate uncompilable code
+    * [THRIFT-3444] - Large 64 bit Integer does not preserve value through Node.js JSONProtocol 
+    * [THRIFT-3436] - misc. cross test issues with UTF-8 path names
+    * [THRIFT-3435] - Put generated Java code for fullcamel tests in a separate package/namespace
+    * [THRIFT-3433] - Doubles aren't interpreted correctly
+    * [THRIFT-3437] - Mingw-w64 build fail
+    * [THRIFT-3434] - Dart generator produces empty name in pubspec.yaml for includes without namespaces
+    * [THRIFT-3408] - JSON generator emits incorrect types
+    * [THRIFT-3406] - Cocoa client should not schedule streams on main runloop
+    * [THRIFT-3404] - JSON String reader doesn't recognize UTF-16 surrogate pair
+    * [THRIFT-3636] - Double precision is not fully preserved in C++ TJSONProtocol
+    * [THRIFT-3632] - c_glib testserialization fails with glib assertion
+    * [THRIFT-3619] - Using Thrift 0.9.3 with googletest on Linux gcc 4.9 / C++11
+    * [THRIFT-3617] - CMake does not build gv/xml generators
+    * [THRIFT-3615] - Fix Python SSL client resource leak on connection failure
+    * [THRIFT-3616] - lib/py/test/test_sslsocket.py is flaky
+    * [THRIFT-3643] - Perl SSL server crushes if a client disconnect without handshake
+    * [THRIFT-3639] - C# Thrift library forces TLS 1.0, thwarting TLS 1.2 usage
+    * [THRIFT-3633] - Travis "C C++ - GCC" build was using clang
+    * [THRIFT-3634] - Fix Python TSocket resource leak on connection failure
+    * [THRIFT-3630] - Debian/Ubuntu install docs need an update
+    * [THRIFT-3629] - Parser sets exitcode on errors, but generator does not
+    * [THRIFT-3608] - lib/cpp/test/SecurityTest is flaky in jenkins Thrift-precommit build.
+    * [THRIFT-3601] - Better conformance to PEP8 for generated code
+    * [THRIFT-3599] - Validate client IP address against cert's SubjectAltName
+    * [THRIFT-3598] - TBufferedTransport doesn't instantiate client connection
+    * [THRIFT-3597] - `make check` hangs in go tests
+    * [THRIFT-3589] - Dart generator uses wrong name in constructor for uppercase arguments with defaults
+    * [THRIFT-3588] - Using TypeScript with --noImplicitAny fails
+    * [THRIFT-3584] - boolean false value cannot be transferred
+    * [THRIFT-3578] - Make THeaderTransport detect TCompact framed and unframed
+    * [THRIFT-3323] - Python library does not handle escaped forward slash ("/") in JSON
+    * [THRIFT-3322] - CMake generated "make check" failes on python_test
+    * [THRIFT-3321] - Thrift can't be added as a subdirectory of another CMake-based project
+    * [THRIFT-3314] - Dots in file names of includes causes dots in javascript variable names
+    * [THRIFT-3307] - Segfault in Ruby serializer
+    * [THRIFT-3309] - Missing TConstant.php in /lib/php/Makefile.am
+    * [THRIFT-3810] - unresolved external symbol public: virtual void __cdecl apache::thrift::server::TServerFramework::serve(void)
+    * [THRIFT-3736] - C++ library build fails if OpenSSL does not surrpot SSLv3
+    * [THRIFT-3878] - Compile error in TSSLSocket.cpp with new OpenSSL [CRYPTO_num_locks]
+    * [THRIFT-3949] - missing make dist entry for compiler/cpp/test
+    * [THRIFT-449] - The wire format of the JSON Protocol may not always be valid JSON if it contains non-UTF8 encoded strings
+    * [THRIFT-162] - Thrift structures are unhashable, preventing them from being used as set elements
+    * [THRIFT-3961] - TConnectedClient does not terminate the connection to the client if an exception while processing the received message occures.
+    * [THRIFT-3881] - Travis CI builds are failing due to docker failures (three retries, and gives up)
+    * [THRIFT-3937] - Cannot compile 0.10.0 development tip with gcc-4.6.x
+    * [THRIFT-3964] - Unsupported mechanism type ????? due to dependency on default OS-dependent charset
+    * [THRIFT-3038] - Use of volatile in cpp library
+    * [THRIFT-3301] - Java generated code uses imports that can lead to class name collisions with IDL defined types
+    * [THRIFT-3348] - PHP TCompactProtocol bool&int64 readvalue bug
+    * [THRIFT-3955] - TThreadedServer Memory Leak
+    * [THRIFT-3829] - Thrift does not install Python Libraries if Twisted is not installed
+    * [THRIFT-3932] - C++ ThreadManager has a rare termination race
+    * [THRIFT-3828] - cmake fails when Boost_INCLUDE_DIRS (and other variables passed to include_directories()) is empty 
+    * [THRIFT-3958] - CMake WITH_MT option for windows static runtime linking does not support the cmake build type RelWithDebInfo
+    * [THRIFT-3957] - TConnectedClient does not disconnect from clients when their timeout is reached.
+    * [THRIFT-3953] - TSSLSocket::close should handle exceptions from waitForEvent because it is called by the destructor.
+    * [THRIFT-3977] - PHP extension creates undefined values when deserializing sets
+    * [THRIFT-3947] - sockaddr type isn't always large enough for the return of getsockname
+    * [THRIFT-2755] - ThreadSanitizer reports data race in ThreadManager::Impl::addWorker
+    * [THRIFT-3948] - errno is not the correct method of getting the error in windows
+    * [THRIFT-4008] - broken ci due to upstream dependency versioning break
+    * [THRIFT-3999] - Fix Debian & Ubuntu package dependencies
+    * [THRIFT-3886] - PHP cross test client returns 0 even when failing
+    * [THRIFT-3997] - building thrift libs does not support new openssl
+
+## Documentation
+    * [THRIFT-3867] - Specify BinaryProtocol and CompactProtocol
+
+## Epic
+    * [THRIFT-3049] - As an iOS developer, I want a generator and library that produces Swift code
+    * [THRIFT-2336] - UTF-8 sent by PHP as JSON is not understood by TJsonProtocol
+
+## Improvement
+    * [THRIFT-1867] - Python client/server should support client-side certificates.
+    * [THRIFT-1313] - c_glib compact support
+    * [THRIFT-1385] - make install doesn't install java library in the setted folder
+    * [THRIFT-1437] - Update RPM spec
+    * [THRIFT-847] - Test Framework harmonization across all languages
+    * [THRIFT-819] - add Enumeration for protocol, transport and server types
+    * [THRIFT-3927] - Emit an error instead of throw an error in the async callback
+    * [THRIFT-3931] - TSimpleServer: If process request encounter UNKNOWN_METHOD, don't close transport.
+    * [THRIFT-3934] - Automatically resolve OpenSSL binary version on Windows CI
+    * [THRIFT-3918] - Run subset of make cross
+    * [THRIFT-3908] - Remove redundant dependencies from Dockerfile
+    * [THRIFT-3907] - Skip Docker image build on CI when unchanged
+    * [THRIFT-3868] - Java struct equals should do identity check before field comparison
+    * [THRIFT-3849] - Port Go serializer and deserializer to dart
+    * [THRIFT-2989] - Complete CMake build for Apache Thrift
+    * [THRIFT-2980] - ThriftMemoryBuffer doesn't have a constructor option to take an existing buffer
+    * [THRIFT-2856] - refactor erlang basic transports and unify interfaces
+    * [THRIFT-2877] - Optimize generated hashCode
+    * [THRIFT-2869] - JSON: run schema validation from tests
+    * [THRIFT-3112] - [Java] AsyncMethodCallback should be typed in generated AsyncIface
+    * [THRIFT-3263] - PHP jsonSerialize() should cast scalar types
+    * [THRIFT-2905] - Cocoa compiler should have option to produce "modern" Objective-C
+    * [THRIFT-2821] - Enable the use of custom HTTP-Header in the Transport
+    * [THRIFT-2093] - added the ability to set compression level in C++ zlib transport
+    * [THRIFT-2089] - Compiler ignores duplicate typenames
+    * [THRIFT-2056] - Moved all #include config.h statements to #include <thrift/config.h>
+    * [THRIFT-2031] - Make SO_KEEPALIVE configurable for C++ lib
+    * [THRIFT-2021] - Improve large binary protocol string performance
+    * [THRIFT-2028] - Cleanup threading headers / libraries
+    * [THRIFT-2014] - Change C++ lib includes to use <namespace/> style throughout
+    * [THRIFT-2312] - travis.yml: build everything
+    * [THRIFT-1915] - Multiplexing Services
+    * [THRIFT-1736] - Visual Studio top level project files within msvc
+    * [THRIFT-1735] - integrate tutorial into regular build
+    * [THRIFT-1533] - Make TTransport should be Closeable
+    * [THRIFT-35] - Move language tests into their appropriate library directory
+    * [THRIFT-1079] - Support i64 in AS3
+    * [THRIFT-1108] - SSL support for the Ruby library 
+    * [THRIFT-3856] - update debian package deependencies
+    * [THRIFT-3833] - haxe http server implementation (by embeding into php web server)
+    * [THRIFT-3839] - Performance issue with big message deserialization using php extension
+    * [THRIFT-3820] - Erlang: Detect OTP >= 18 to use new time correction
+    * [THRIFT-3816] - Reduce docker build duration on Travis-CI
+    * [THRIFT-3815] - Put appveyor dependency versions to one place
+    * [THRIFT-3788] - Compatibility improvements and Win64 support
+    * [THRIFT-3792] - Timeouts for anonymous pipes should be configurable
+    * [THRIFT-3794] - Split Delphi application, protocol and transport exception subtypes into separate exceptions
+    * [THRIFT-3774] - The generated code should have exception_names meta info
+    * [THRIFT-3762] - Fix build warnings for deprecated Thrift "byte" fields
+    * [THRIFT-3756] - Improve requiredness documentation
+    * [THRIFT-3761] - Add debian package for Python3
+    * [THRIFT-3742] - haxe php cli support
+    * [THRIFT-3733] - Socket timeout improvements
+    * [THRIFT-3728] - http transport for thrift-lua
+    * [THRIFT-3905] - Dart compiler does not initialize bool, int, and double properties
+    * [THRIFT-3911] - Loosen Ruby dev dependency version requirements
+    * [THRIFT-3906] - Run C# tests with make check
+    * [THRIFT-3900] - Add Python SSL flags
+    * [THRIFT-3897] - Provide meaningful exception type based on WebExceptionStatus in case of timeout
+    * [THRIFT-3808] - Missing `DOUBLE` in thrift type enumeration
+    * [THRIFT-3803] - Remove "file" attribute from XML generator
+    * [THRIFT-3660] - Add V4 mapped address to test client cert's altname
+    * [THRIFT-3661] - Use https to download meck in erlang test build
+    * [THRIFT-3659] - Check configure result of CMake on CI
+    * [THRIFT-3667] - Add TLS SNI support to clients
+    * [THRIFT-3651] - Make backports.match_hostname and ipaddress optional
+    * [THRIFT-3666] - Build D tutorial as part of Autotools build
+    * [THRIFT-3665] - Add D libevent and OpenSSL to docker images
+    * [THRIFT-3664] - Remove md5.c
+    * [THRIFT-3662] - Add Haskell to debian docker image
+    * [THRIFT-3711] - Add D to cross language test
+    * [THRIFT-3691] - Run flake8 Python style check on Travis-CI
+    * [THRIFT-3692] - (Re)enable Appveyor C++ and Python build
+    * [THRIFT-3677] - Improve CMake Java build
+    * [THRIFT-3679] - Add stdout log to testBinary in Java test server
+    * [THRIFT-3718] - Reduce size of docker image for build environment
+    * [THRIFT-3698] - [Travis-CI] Introduce retry to apt commands
+    * [THRIFT-3127] - switch -recurse to --recurse and reserve -r
+    * [THRIFT-3087] - Pass on errors like "connection closed"
+    * [THRIFT-3240] - Thrift Python client should support subjectAltName and wildcard certs in TSSLSocket
+    * [THRIFT-3213] - make cross should indicate when it skips a known failing test
+    * [THRIFT-3208] - Fix Visual Studio solution build failure due to missing source
+    * [THRIFT-3186] - Add TServerHTTP to Go library
+    * [THRIFT-2342] - Add __FILE__ and __LINE__ to Thrift C++ excpetions
+    * [THRIFT-3372] - Add dart generator to Visual Studio project
+    * [THRIFT-3366] - ThriftTest to implement standard return values 
+    * [THRIFT-3402] - Provide a perl Unix Socket implementation
+    * [THRIFT-3361] - Improve C# library
+    * [THRIFT-3393] - Introduce i8 to provide consistent set of Thrift IDL integer types
+    * [THRIFT-3339] - Support for database/sql
+    * [THRIFT-3565] - C++: T[Async]Processor::getEventHandler() should be declared as const member functions
+    * [THRIFT-3563] - C++/Qt: removed usage of macro QT_PREPEND_NAMESPACE as it isn't consequently used for all references to Qt types.
+    * [THRIFT-3562] - Removed unused TAsyncProcessor::getAsyncServer()
+    * [THRIFT-3561] - C++/Qt: make use of Q_DISABLE_COPY() to get rid of copy ctor and assignment operator
+    * [THRIFT-3556] - c_glib file descriptor transport
+    * [THRIFT-3544] - Make cross test fail when server process died unexpectedly
+    * [THRIFT-3540] - Make python tutorial more in line with PEP8
+    * [THRIFT-3535] - Dart generator argument to produce a file structure usable in parent library
+    * [THRIFT-3505] - Enhance Python TSSLSocket
+    * [THRIFT-3506] - Eliminate old style classes from library code
+    * [THRIFT-3503] - Enable py:utf8string by default
+    * [THRIFT-3499] - Add package_prefix to python generator
+    * [THRIFT-3495] - Minor enhancements and fixes for cross test
+    * [THRIFT-3486] - Java generated `getFieldValue` is incompatible with `setFieldValue` for binary values.
+    * [THRIFT-3484] - Consolidate temporary buffers in Java's TCompactProtocol
+    * [THRIFT-3516] - Add feature test for THeader TBinaryProtocol interop
+    * [THRIFT-3515] - Python 2.6 compatibility and test on CI
+    * [THRIFT-3514] - PHP 7 compatible version of binary protocol
+    * [THRIFT-3469] - Docker: Debian support
+    * [THRIFT-3416] - Retire old "xxx_namespace" declarations from the IDL
+    * [THRIFT-3426] - Align autogen comment in XSD
+    * [THRIFT-3424] - Add CMake android build option
+    * [THRIFT-3439] - Run make cross using Python3 when available
+    * [THRIFT-3440] - Python make check takes too much time
+    * [THRIFT-3441] - Stabilize Travis-CI builds
+    * [THRIFT-3431] - Avoid "schemes" HashMap lookups during struct reads/writes
+    * [THRIFT-3432] - Add a TByteBuffer transport to the Java library
+    * [THRIFT-3438] - Enable py:new_style by default
+    * [THRIFT-3405] - Go THttpClient misuses http.Client objects
+    * [THRIFT-3614] - Improve logging of test_sslsocket.py
+    * [THRIFT-3647] - Fix php extension build warnings
+    * [THRIFT-3642] - Speed up cross test runner
+    * [THRIFT-3637] - Implement compact protocol for dart
+    * [THRIFT-3613] - Port Python C extension to Python 3
+    * [THRIFT-3612] - Add Python C extension for compact protocol
+    * [THRIFT-3611] - Add --regex filter to cross test runner
+    * [THRIFT-3631] - JSON protocol implementation for Lua
+    * [THRIFT-3609] - Remove or replace TestPortFixture.h
+    * [THRIFT-3605] - Have the compiler complain about invalid arguments and options
+    * [THRIFT-3596] - Better conformance to PEP8
+    * [THRIFT-3585] - Compact protocol implementation for Lua
+    * [THRIFT-3582] - Erlang libraries should have service metadata
+    * [THRIFT-3579] - Introduce retry to make cross
+    * [THRIFT-3306] - Java: TBinaryProtocol: Use 1 temp buffer instead of allocating 8
+    * [THRIFT-3910] - Do not invoke pip as part of build process
+    * [THRIFT-1857] - Python 3.X Support
+    * [THRIFT-1944] - Binding to zero port
+    * [THRIFT-3954] - Enable the usage of structs called "Object" in Java
+    * [THRIFT-3981] - Enable analyzer strong mode in Dart library
+    * [THRIFT-3998] - Document ability to add custom tags to thrift structs
+    * [THRIFT-4006] - Add a removeEventListener method on TSocket
+
+## New Feature
+    * [THRIFT-640] - Support deprecation
+    * [THRIFT-948] - SSL socket support for PHP
+    * [THRIFT-764] - add Support for Vala language
+    * [THRIFT-3046] - Allow PSR4 class loading for generated classes (PHP)
+    * [THRIFT-2113] - Erlang SSL Socket Support
+    * [THRIFT-1482] - Unix domain socket support under PHP
+    * [THRIFT-519] - Support collections of types without having to explicitly define it
+    * [THRIFT-468] - Rack Middleware Application for Rails
+    * [THRIFT-1708] - Add event handlers for processor events
+    * [THRIFT-3834] - Erlang namespacing and exception metadata
+    * [THRIFT-2510] - Implement TNonblockingServer's ability to listen on unix domain sockets
+    * [THRIFT-3397] - Implement TProcessorFactory in C# to enable per-client processors
+    * [THRIFT-3523] - XML Generator
+    * [THRIFT-3510] - Add HttpTaskAsyncHandler implementation
+    * [THRIFT-3318] - PHP: SimpleJSONProtocol Implementation
+    * [THRIFT-3299] - Dart language bindings in Thrift
+    * [THRIFT-2835] - Add possibility to distribute generators separately from thrift core, and load them dynamically
+    * [THRIFT-184] - Add OSGi Manifest headers to the libthrift java library to be able to use Thrift in the OSGi runtime
+    * [THRIFT-141] - If a required field is not present on serialization, throw an exception
+    * [THRIFT-1891] - Add Windows ALPC transport which is right counterpart of Unix domain sockets
+
+## Question
+    * [THRIFT-1808] - The Thrift struct should be considered self-contained?
+    * [THRIFT-2895] - Tutorial cpp
+    * [THRIFT-3860] - Elephant-bird application Test fails for Thrift
+    * [THRIFT-3811] - HTTPS Support for C++ applications
+    * [THRIFT-3509] - "make check" error
+
+## Story
+    * [THRIFT-3452] - .travis.yml: Migrating from legacy to container-based infrastructure
+
+## Sub-task
+    * [THRIFT-1811] - ruby tutorial as part of the regular build
+    * [THRIFT-2779] - PHP TJSONProtocol encode unicode into UCS-4LE which can't be parsed by other language bindings
+    * [THRIFT-2110] - Erlang: Support for Multiplexing Services on any Transport, Protocol and Server
+    * [THRIFT-3852] - A Travis-CI job fails with "write error"
+    * [THRIFT-3740] - Fix haxelib.json classpath 
+    * [THRIFT-3653] - incorrect union serialization
+    * [THRIFT-3652] - incorrect serialization of optionals
+    * [THRIFT-3655] - incorrect union serialization
+    * [THRIFT-3654] - incorrect serialization of optionals
+    * [THRIFT-3656] - incorrect serialization of optionals
+    * [THRIFT-3699] - Fix integer limit symbol includes in Python C extension
+    * [THRIFT-3693] - Fix include issue in C++ TSSLSocketInterruptTest on Windows
+    * [THRIFT-3694] - [Windows] Disable tests of a few servers that are not supported
+    * [THRIFT-3696] - Install pip to CentOS Docker images to fix Python builds
+    * [THRIFT-3638] - Fix haxelib.json
+    * [THRIFT-3251] - Add http transport for server to Go lib
+    * [THRIFT-2424] - Recursive Types
+    * [THRIFT-2423] - THeader
+    * [THRIFT-2413] - Python: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol
+    * [THRIFT-2409] - Java: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol
+    * [THRIFT-2412] - D: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol
+    * [THRIFT-2411] - C++: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol
+    * [THRIFT-2410] - JavaMe: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol
+    * [THRIFT-2668] - TestSuite: detailed result on passed tests by feature
+    * [THRIFT-2659] - python Test Server fails when throwing TException
+    * [THRIFT-3398] - Add CMake build  for Haskell library and tests
+    * [THRIFT-3396] - DART: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol
+    * [THRIFT-3364] -   Fix ruby binary field encoding in TJSONProtocol
+    * [THRIFT-3381] - Fix for misc. codegen issues with THRIFT-2905
+    * [THRIFT-3573] - No rule to make target `../../../test/c_glib/src/.deps/testthrifttest-thrift_test_handler.Po'.
+    * [THRIFT-3572] - "Unable to determine the behavior of a signed right shift"
+    * [THRIFT-3542] - Add length limit support to Java test server
+    * [THRIFT-3537] - Remove the (now obsolete) csharp:asyncctp flag 
+    * [THRIFT-3532] - Add configurable string and container read size limit to Python protocols
+    * [THRIFT-3531] - Create cross lang feature test for string and container read length limit
+    * [THRIFT-3482] - Haskell JSON protocol does not encode binary field as Base64
+    * [THRIFT-3425] - Minor fixes + simplification for CentOS Dockerfile
+    * [THRIFT-3442] - Run CMake tests on Appveyor
+    * [THRIFT-3409] - NodeJS binary field issues
+    * [THRIFT-3621] - Fix lib/cpp/test/SecurityTest.cpp to use ephemeral ports
+    * [THRIFT-3628] - Fix lib/cpp/test/TServerIntegrationTest.cpp to use ephemeral ports
+    * [THRIFT-3625] - Kill unused #include "TestPortFixture.h" in lib/cpp/test/TServerTransportTest.cpp.
+    * [THRIFT-3646] - Fix Python extension build warnings
+    * [THRIFT-3626] - Fix lib/cpp/test/TSocketInterruptTest.cpp to use ephemeral ports.
+    * [THRIFT-3624] - Fix lib/cpp/test/TServerSocketTest.cpp to use ephemeral ports
+    * [THRIFT-3623] - Fix Fix cpp/lib/test/TSSLSocketInterruptTest.cpp to use ephemeral ports
+    * [THRIFT-3592] - Add basic test client
+    * [THRIFT-3980] - add TExtendedBinaryProtocol.java
+
+## Task
+    * [THRIFT-1801] - Sync up TApplicationException codes across languages and thrift implementations
+    * [THRIFT-1259] - Automate versioning 
+
+## Test
+    * [THRIFT-3400] - Add Erlang to cross test
+    * [THRIFT-3504] - Fix FastbinaryTest.py
+
+## Wish
+    * [THRIFT-3923] - Maybe remove Aereo from the "Powered by" list
+    * [THRIFT-2149] - Add an option to disable the generation of default operators
 
 
-Version 0.9.0
 
-THRIFT-164    Website              Build web tutorial on Incubator web  site
-THRIFT-304    Python               Building the Python library requires development  headers
-THRIFT-317    Java                 Issues with Java struct  validation
-THRIFT-330    Compiler (General)   Additional method to called when connection is  broken
-THRIFT-336    Csharp               Compact Protocol in  C#
-THRIFT-369    Ruby                 Sets and maps break  equality
-THRIFT-481    Ruby                 Indentation of ruby classes is off by a  few
-THRIFT-491    C++                  Ripping raw pthreads out of TFileTransport and associated test  issues
-THRIFT-541    Cocoa                Cocoa code generator doesn't put keywords before all  arguments.
-THRIFT-556    Ruby                 not correctly referred to top-level modules when a submodule masks the top-level  name
-THRIFT-681    Compiler (General)   The HTML generator does not handle JavaDoc style comments very  well
-THRIFT-956    Python               Python module's version meta-data should be  updated
-THRIFT-973    Cocoa                Cocoa library won't compile using  clang
-THRIFT-982    JavaME               add version Info to the  library
-THRIFT-1023   Ruby                 Thrift encoding (UTF-8) issue with Ruby 1.9.2
-THRIFT-1061   Java, PHP            Read an invalid frame size of 0. Are you using TFramedTransport on the client side?
-THRIFT-1072   Cocoa                Missing - (id) initWithSharedProcessor in TSharedProcessorFactory.h
-THRIFT-1082   Perl                 Thrift::FramedTransport sometimes calls close() on an undefined value
-THRIFT-1090   Website              Document the generation of a file called "Constants.java"
-THRIFT-111    Python               TBase class for dynamic (de)serialization, and __slots__ option for memory  savings
-THRIFT-1128   Build                OS X thrift.h incompatibility with Thrift.h
-THRIFT-1159   CSharp               THttpClient->Flush() issue (connection thru proxy)
-THRIFT-1204   Ruby                 Ruby autogenerated files should require 'thrift' gem
-THRIFT-1224   Ruby                 Cannot insert UTF-8 text
-THRIFT-1235   C++                  How could I use THttpServerTransportFactory withTNonBlockingServer
-THRIFT-1267   JavaScript           Node.js can't throw exceptions.
-THRIFT-1277   JavaScript           Node.js serializes false booleans as null
-THRIFT-1326   C++                  on some platforms, #include <stdint.h> is necessary to be included in Thrift.h
-THRIFT-1327   Ruby                 Fix Spec Suite under Ruby-1.8.7 (works for MRI Ruby-1.9.2)
-THRIFT-1338   Build Process        Do not use an unpatched autoconf 2.65 to generate release tarball
-THRIFT-1340   Cocoa                Add support of ARC to Objective-C
-THRIFT-1343   Erlang               no_auto_import min/2 to avoid compile warning
-THRIFT-1344   Erlang               Using the httpc module directly rather than the deprecated http layer
-THRIFT-1368   Java                 TNonblockingServer usage
-THRIFT-1394   C++                  Treatment of optional fields is not consistent between C++ and Java
-THRIFT-1421   Build Process        Debian Packages can not be built
-THRIFT-1427   PHP                  PHP library uses non-multibyte safe functions with mbstring function overloading
-THRIFT-1429   Java                 The nonblocking servers is supposed to use TransportFactory to read the  data
-THRIFT-1433   C++                  TServerSocket fix for MSVC
-THRIFT-1438   C++                  lib/cpp/src/windows/config.h should read version from configure.ac rather than a  #define
-THRIFT-1441   Delphi               Generate constructor with parameters for exception class for message property auto update
-THRIFT-1443   C++                  define a TProcessor helper class to implement process()
-THRIFT-1444   C++                  FunctionRunner - add syntactic sugar to create shared_ptrs
-THRIFT-1446   Delphi               Compile error with Delphi 2009 in constant  initializer
-THRIFT-1447   Java                 NullpointerException in ProcessFunction.class :in "oneway"  method
-THRIFT-1449   Ruby                 Ruby client does not work on solaris  (?)
-THRIFT-1450   Build                Process  Problems building thrift 0.8.0 for Python and  Ruby
-THRIFT-1451   C++                  FramedTransport: Prevent infinite loop when  writing
-THRIFT-1452   C++                  generate a swap() method for all generated  structs
-THRIFT-1453   C++                  Don't change types of arguments when serializing with thrift php  extension
-THRIFT-1456   C#                   System.Net.HttpWebRequest' does not contain a definition for  'Proxy'
-THRIFT-1460   Python               why not add unicode strings support to python  directly?
-THRIFT-1461   C++                  Recent TNonblockingServer changes broke --enable-boostthreads=yes,  Windows
-THRIFT-1463   Compiler             Decouple Thrift IDL from  generators
-THRIFT-1464   Java                 AbstractNonblockingServer.FrameBuffer TNonblockingTransport changed public to  private
-THRIFT-1465   Java                 Visibility of methods in generated java  code
-THRIFT-1466   C glib               Proper Documentation for Thrift C  Glib
-THRIFT-1467   Delphi               Possible AV with empty strings when using JSON  protocol
-THRIFT-1468   Java                 Memory leak in  TSaslServerTransport
-THRIFT-1469   Java                 Java isset space  optimization
-THRIFT-1473   Delphi               JSON context stack left in an incorrect state when exception thrown during  read/write
-THRIFT-1475   Erlang               Incomplete records generation for  Erlang
-THRIFT-1479   PHP                  Compiled PHP process functions missing  writeMessageEnd()
-THRIFT-1480   Python               remove tabs, adjust whitespace and address PEP8  warnings
-THRIFT-1483   Java                 java compiler does not generate type parameters for services in extended  clauses
-THRIFT-1484   PHP                  Introduce phpunit test  suite
-THRIFT-1485   Delphi               Performance: pass large and/or refcounted arguments as  "const"
-THRIFT-1486   Test Suite           Javascript manual testserver not returning content  types
-THRIFT-1488   Build Process        invalid conversion 'pthread_t {aka _opaque_pthread_t*}' to {aka long long unsigned  int}'
-THRIFT-1490   C++                  Windows-specific header files - fixes &  tweaks
-THRIFT-1491   C++                  Uninitialize processorFactory_ member in  TServer.h
-THRIFT-1492   C glib               enabling c_glib render thrift unusable (even for C++  code)
-THRIFT-1495   Test Suite           PHP TestClient fatals on missing  class
-THRIFT-1496   PHP                  PHP compiler not namespacing  enums
-THRIFT-1498   Java                 Allow TThreadedPoolServer.Args to pass a  ExecutorService
-THRIFT-1500   D                    D programming language  support
-THRIFT-1501   PHP                  PHP old namespaces not generated for  enums
-THRIFT-1502   C++                  TSimpleServer::serve(): Do not print out error message if server was  stopped.
-THRIFT-1504   Cocoa                Cocoa Generator should use local file imports for base Thrift  headers
-THRIFT-1508   C++                  TServerSocket does not allow for the user to specify the IP address to bind  to
-THRIFT-1510   Ruby                 There should be an implementation of the JsonProtocol for  ruby
-THRIFT-1511   Java                 Server with oneway support ( JAVA  )
-THRIFT-1512   C++                  Thrift socket support for Windows  XP
-THRIFT-1515   Python               NameError: global name 'TApplicationException' is not  defined
-THRIFT-1518   C++                  Generated C++ code sends the first optional field in the write() function for a  struct.
-THRIFT-1519   Ruby                 Thirft Build Failure referencing rb_intern2  symbol
-THRIFT-1520   Erlang               Embed version number in erlang .app  file
-THRIFT-1521   PHP                  Two patches for more  Performance
-THRIFT-1523   Java                 clientTimeout not worked as expected in TServerSocket created by  TSSLTransportFactory
-THRIFT-1524   C++                  TNonBlockingServer does not compile in Visual Studio  2010
-THRIFT-1526   Java                 Union TupleSchemeFactory returns  StandardSchemes
-THRIFT-1527   Java                 Gen tupleReadStruct in unions return null when the setfield is  unrecognized
-THRIFT-1529   Java                 TupleProtocol unintentionally includes extra byte in bit vectors with ptional fields is  8
-THRIFT-1532   Erlang               The type specifications in the gen Erlang code should include "undefined" for default  val
-THRIFT-1534   Delphi               Required fields in the Delphi code  generator.
-THRIFT-1535   Java                 Why thrift don't use wrapped class for optional fields  ?
-THRIFT-1537   Delphi               TFramedTransport  issues
-THRIFT-1539   Python               Build and distribute the fb303 python libraries along with  thrift
-THRIFT-1553   Node.js              thrift nodejs service side can't read map structure, key as enum, value as  Object
-THRIFT-1554   Delphi               Inherited service methods are not resolved in derived service  implementations
-THRIFT-1555   Delphi               Delphi version of the tutorial  code
-THRIFT-1567   C++                  Thrift/cpp: Allow alternate classes to be used  for
-THRIFT-1571   Ruby                 Update Ruby HTTP transport for recent Ruby  versions
-THRIFT-1575   C++                  Typo in  server/TThreadPoolServer.h
-THRIFT-1578   C glib               C_GLib generated code does not  compile
-THRIFT-1582   C glib               Bad includes of nested thrift files in  c_glib
-THRIFT-1583   C glib               c_glib leaks  memory
-THRIFT-1591   Ruby                 Enable TCP_NODELAY for ruby  gem
-THRIFT-1593   Erlang               Pass on errors like "connection closed" to the handler  module
-THRIFT-1596   Delphi               Test clients should have a return codes that reflect whether they succeeded or  not
-THRIFT-1597   PHP                  TJSONProtocol.php is missing from  Makefile.am
-THRIFT-1602   PHP                  PHP C Extension is not Compatible with PHP  5.4
-THRIFT-1604   Python               Python exception handeling for changes from PEP  3110
-THRIFT-1606   C++                  Race condition in  BoostThreadFactory.cpp
-THRIFT-1607   Build Process        Incorrect file modes for several source  files
-THRIFT-1610   C#                   IWebProxy not available on WP7  platform
-THRIFT-1611   Delphi               Improved code generation for  typedefs
-THRIFT-1612   C#                   Base64 encoding is  broken
-THRIFT-1613   Java                 Add code back into empty source file  ToStringTest.java
-THRIFT-1615   PHP                  PHP  Namespace
-THRIFT-1621   Delphi               Memory  leaks
-THRIFT-1622   C++                  Incorrect size returned on  read
-THRIFT-1624   Java                 Isset Generated differently on different  platforms
-THRIFT-1627   Build Process        compiler built using compilers.vcxproj cannot be used to build some test .thrift  files
-THRIFT-1631   C++                  Fix C++ server constructor  typos
-THRIFT-1632   Ruby                 data corruption in thrift_native implementation of  MemoryBufferTransport
-THRIFT-1644   Ruby                 Upgrade RSpec to 2.10.x and refactor specs as  needed
-THRIFT-1645   Ruby                 Replace Object#tee with more conventional Object#tap in  specs
-THRIFT-1650   Ruby                 Update clean items and svn:ignore entries for OS X  artifacts
-THRIFT-1652   Java                 TSaslTransport does not log the error when kerberos auth  fails
-THRIFT-1653   Java                 TThreadedSelectorServer leaks CLOSE_WAIT  sockets
-THRIFT-1654   C glib               c_glib thrift_socket_read() returns corrupted  data
-THRIFT-1655   Build Process        Configure still trying to use thrift_generators in  output
-THRIFT-1656   C++                  Set proper headers in THttpServer.cpp so "Cross-Origin Resource Sharing" to fix js client 
-THRIFT-1658   Java                 Java thrift server is not throwing  TApplicationException
-THRIFT-1661   Build Process        Add --with-qt4 configure  option
-THRIFT-1662   Cocoa                "removeObject:" should be "removeObserver:" in [-TSocketServer  dealloc]?
-THRIFT-1663   Java                 Java Thrift server is not throwing  exceptions
-THRIFT-1664   Build Process        Reference to non-existing variable in build  script
-THRIFT-1665   Java                 TBinaryProtocol: exceeded message length raises generic  TException
-THRIFT-1668   Build Process        Compile error in contrib/fb303, thrift/TDispatchProcessor.h: No such file or  directory
-THRIFT-1669   Python               NameError: global name 'TApplicationException' is not  defined
-THRIFT-1670   Delphi               Incompatibilities between different versions of a Thrift  interface
-THRIFT-1671   Cocoa                Cocoa code generator does not put keywords into generated method  calls
-THRIFT-1672   C#                   MonoTouch (and Mono for Android)  compatibility
-THRIFT-1673   Ruby                 Ruby compile flags for extension for multi arch builds (os  x)
-THRIFT-1674   D                    Update Thrift D library to be compatible with  2.060
-THRIFT-1675   Java                 Do we have any plan to support  scala?
-THRIFT-1676   C++                  Allow specifying IP/hostname in  TServer::serve
-THRIFT-1685   Website              Please add "aereo.com" to "Powered by Apache Thrift" list in about  page
-THRIFT-1686   PHP                  php generator uses "and" instead of "&&", and causes compiler errors with Visual  Studio
-THRIFT-1688   Website              Update IDL page  markup
-THRIFT-1689   C++                  don't exit(-1) in  TNonblockingServer
-THRIFT-1691   Delphi               Serializer/deserializer support for  Delphi
-THRIFT-1693   Java                 libthrift has dependency on two different versions of  httpcore
-THRIFT-1694   C#                   Re-Enable serialization for WP7  Silverlight
-THRIFT-1702   Documentation        a thrift  manual
-THRIFT-1707   Ruby                 Adjust server_spec.rb for RSpec 2.11.x and Ruby  1.9.3
-THRIFT-1709   C#                   Warning "Bitwise-or operator used on a sign-extended operand;" cast  error
-THRIFT-1710   Delphi               Minor issues in test case  code
-THRIFT-1714   Ruby                 Explicitly add CWD to Ruby  test_suites.rb
-THRIFT-1718   C++                  Incorrect check in  TFileTransportTest
-THRIFT-1721   Build                Dist broken due to 0.8.0 to 0.9.0  changes
-THRIFT-1722   Csharp               C# WP7 Assembly addition beaks mono  build
-THRIFT-1725   Website              Tutorial web pages for Delphi and  C#
+Thrift 0.9.3
+--------------------------------------------------------------------------------
+## Bug
+    * [THRIFT-2441] - Cannot shutdown TThreadedServer when clients are still connected
+    * [THRIFT-2465] - TBinaryProtocolT breaks if copied/moved
+    * [THRIFT-2474] - thrift.h causes a compile failure
+    * [THRIFT-2540] - Running configure from outside the source directory fails
+    * [THRIFT-2598] - Add check for minimum Go version to configure.ac
+    * [THRIFT-2647] - compiler-hs: don't decapitalize field names, do decapitalize argument bindings
+    * [THRIFT-2773] - Generated Java code for 'oneway' methods is incorrect.
+    * [THRIFT-2789] - TNonblockingServer leaks socket FD's under load
+    * [THRIFT-2682] - TThreadedServer leaks per-thread memory
+    * [THRIFT-2674] - JavaScript: declare Accept: and Content-Type: in request
+    * [THRIFT-3078] - TNonblockingServerSocket's logger is not named after TNonblockingServerSocket
+    * [THRIFT-3077] - C++ TFileTransport ignores return code from ftruncate
+    * [THRIFT-3067] - C++ cppcheck performance related warnings
+    * [THRIFT-3066] - C++ TDenseProtocol assert modifies instead of checks
+    * [THRIFT-3071] - bootstrap.sh on Ubuntu 12.04 (Precise) automake error
+    * [THRIFT-3069] - C++ TServerSocket leaks socket on fcntl get or set flags error
+    * [THRIFT-3079] - TNonblockingServerSocket's logger is not named after TNonblockingServerSocket
+    * [THRIFT-3080] - C++ TNonblockingServer connection leak while accept huge number connections.
+    * [THRIFT-3086] - C++ Valgrind Error Cleanup
+    * [THRIFT-3085] - thrift_reconnecting_client never try to reconnect
+    * [THRIFT-3123] - Missing include in compiler/cpp/src/main.h breaks build in some environments
+    * [THRIFT-3125] - Fix the list of exported headers in automake input
+    * [THRIFT-3126] - PHP JSON serializer converts empty or int-indexed maps to lists
+    * [THRIFT-3132] - Properly format date in Java @Generated annotations
+    * [THRIFT-3137] - Travis build hangs after failure
+    * [THRIFT-3138] - "make check" parallel execution is underministic
+    * [THRIFT-3139] - JS library test is flaky
+    * [THRIFT-3140] - ConcurrentModificationException is thrown by JavaScript test server
+    * [THRIFT-3124] - Some signed/unsigned warnings while building compiler
+    * [THRIFT-3128] - Go generated code produces name collisions between services
+    * [THRIFT-3146] - Graphviz generates function name collisions between services
+    * [THRIFT-3147] - Segfault while receiving data
+    * [THRIFT-3148] - Markdown links to coding_standards are dead
+    * [THRIFT-3090] - cmake build is broken on MacOSX
+    * [THRIFT-3097] - cmake targets unconditionally depend on optional libraries
+    * [THRIFT-3094] - master as of 2015-APR-13 fails -DBOOST_THREADS cmake build
+    * [THRIFT-3099] - cmake build is broken on FreeBSD
+    * [THRIFT-3089] - Assigning default ENUM values results in non-compilable java code if java namespace is not defined
+    * [THRIFT-3093] - mingw compile fixes for c++ library 0.9.2
+    * [THRIFT-3098] - Thrift does not pretty print binary typedefs the way it does binary fields
+    * [THRIFT-3091] - c_glib service method should return result from handler method
+    * [THRIFT-3088] - TThreadPoolServer with Sasl auth may leak CLOSE_WAIT socket
+    * [THRIFT-3109] - Cross test log file cannot be browsed when served in HTTP server
+    * [THRIFT-3113] - m4 C++11 macro issue
+    * [THRIFT-3105] - C++ libthriftnb library on Windows build failure
+    * [THRIFT-3115] - Uncompileable code due to name collision with predefined used types
+    * [THRIFT-3117] - Java TSSLTransportFactory can't load certificates within JAR archive
+    * [THRIFT-3102] - could not make check for Go Library
+    * [THRIFT-3120] - Minor spelling errors and an outdated URL
+    * [THRIFT-3121] - Librt does not exist on OS X
+    * [THRIFT-3152] - Compiler error on Mac OSX (missing #include <cstdlib>)
+    * [THRIFT-3162] - make fails for dmd 2.067
+    * [THRIFT-3164] - Thrift C++ library SSL socket by default allows for unsecure SSLv3 negotiation
+    * [THRIFT-3168] - Fix Maven POM
+    * [THRIFT-3170] - Initialism code in the Go compiler causes chaos
+    * [THRIFT-3169] - Do not export thrift.TestStruct and thrift.TestEnum in thrift Go library 
+    * [THRIFT-3191] - Perl compiler does not add support for unexpected exception handling
+    * [THRIFT-3178] - glib C does not compile
+    * [THRIFT-3189] - Perl ServerSocket should allow a specific interface to be listened to
+    * [THRIFT-3252] - Missing TConcurrentClientSyncInfo.h in cpp Makefile, so doesn't install
+    * [THRIFT-3255] - Thrift generator doesn't exclude 'package' keyword for thrift property names breaking java builds
+    * [THRIFT-3260] - multiple warnings in c_glib tutorial
+    * [THRIFT-3256] - Some D test timings are too aggressive for slow machines
+    * [THRIFT-3257] - warning: extra tokens at end of #endif directive
+    * [THRIFT-3184] - Thrift Go leaves file descriptors open
+    * [THRIFT-3203] - DOAP - please fix "Ocaml" => "OCaml"
+    * [THRIFT-3210] - (uncompileable) code generated for server events while are events not enabled
+    * [THRIFT-3215] - TJSONProtocol '(c++) uses "throw new" to throw exceptions instead of "throw"
+    * [THRIFT-3202] - Allow HSHAServer to configure min and max worker threads separately.
+    * [THRIFT-3205] - TCompactProtocol return a wrong error when the io.EOF happens
+    * [THRIFT-3209] - LGPL mentioned in license file
+    * [THRIFT-3197] - keepAliveTime is hard coded as 60 sec in TThreadPoolServer
+    * [THRIFT-3196] - Misspelling in lua TBinaryProtocol (stirctWrite => strictWrite)
+    * [THRIFT-3198] - Allow construction of TTransportFactory with a specified maxLength
+    * [THRIFT-3192] - Go import paths changed in 1.4, and expired June 1
+    * [THRIFT-3271] - Could not find or load main class configtest_ax_javac_and_java on some non-english systems
+    * [THRIFT-3273] - c_glib: Generated code tries to convert between function and void pointers
+    * [THRIFT-3264] - Fix Erlang 16 namespaced types
+    * [THRIFT-3270] - reusing TNonblockingServer::TConnection cause dirty TSocket
+    * [THRIFT-3267] - c_glib: "Critical" failure during unit tests
+    * [THRIFT-3277] - THttpClient leaks connections if it's used for multiple requests
+    * [THRIFT-3278] - NodeJS: Fix exception stack traces and names
+    * [THRIFT-3279] - Fix a bug in retry_max_delay (NodeJS)
+    * [THRIFT-3280] - Initialize retry variables on construction
+    * [THRIFT-3283] - c_glib: Tutorial server always exits with warning
+    * [THRIFT-3284] - c_glib: Empty service produces unused-variable warning
+    * [THRIFT-1925] - c_glib generated code does not compile
+    * [THRIFT-1849] - after transport->open() opens isOpen returns true and next open() goes thru when it shall not
+    * [THRIFT-1866] - java compiler generates non-compiling code with const's defined in a thrift when name includes non-identifier chars
+    * [THRIFT-1938] - FunctionRunner.h -- uses wrong path for Thread.h when installed
+    * [THRIFT-1844] - Password string not cleared
+    * [THRIFT-2004] - Thrift::Union violates :== method contract and crashes
+    * [THRIFT-2073] - Thrift C++ THttpClient error: cannot refill buffer
+    * [THRIFT-2127] - Autoconf scripting does not properly account for cross-compile
+    * [THRIFT-2180] - Integer types issues in Cocoa lib on ARM64
+    * [THRIFT-2189] - Go needs "isset" to fully support "union" type (and optionals)
+    * [THRIFT-2192] - autotools on Redhat based systems
+    * [THRIFT-2546] - cross language tests fails at 'TestMultiException' when using nodejs server
+    * [THRIFT-2547] - nodejs servers and clients fails to connect with cpp using compact protocol
+    * [THRIFT-2548] - Nodejs servers and clients does not work properly with  -ssl
+    * [THRIFT-1471] - toString() does not print ByteBuffer values when nested in a List
+    * [THRIFT-1201] - getaddrinfo resource leak
+    * [THRIFT-615] - TThreadPoolServer doesn't call task_done after pulling tasks from it's clients queue
+    * [THRIFT-162] - Thrift structures are unhashable, preventing them from being used as set elements
+    * [THRIFT-810] - Crashed client on TSocket::close under loads
+    * [THRIFT-557] - charset problem with file Autogenerated by Thrift
+    * [THRIFT-233] - IDL doesn't support negative hex literals
+    * [THRIFT-1649] - contrib/zeromq does not build in 0.8.0
+    * [THRIFT-1642] - Miscalculation lead to throw unexpected "TTransportException::TIMED_OUT"(or called "EAGAIN (timed out)") exception
+    * [THRIFT-1587] - TSocket::setRecvTimeout error
+    * [THRIFT-1248] - pointer subtraction in TMemoryBuffer relies on undefined behavior
+    * [THRIFT-1774] - Sasl Transport client would hang when trying to connect non-sasl transport server
+    * [THRIFT-1754] - RangeError in buffer handling
+    * [THRIFT-1618] - static structMap in FieldMetaData is not thread safe and can lead to deadlocks
+    * [THRIFT-2335] - thrift incompatibility with py:tornado as server, java as client
+    * [THRIFT-2803] - TCP_DEFER_ACCEPT not supported with domain sockets
+    * [THRIFT-2799] - Build Problem(s): ld: library not found for -l:libboost_unit_test_framework.a
+    * [THRIFT-2801] - C++ test suite compilation warnings
+    * [THRIFT-2802] - C++ tutorial compilation warnings
+    * [THRIFT-2795] - thrift_binary_protocol.c: 'dereferencing type-punned pointer will break strict-aliasing rules'
+    * [THRIFT-2817] - TSimpleJSONProtocol reads beyond end of message
+    * [THRIFT-2826] - html:standalone sometimes ignored
+    * [THRIFT-2829] - Support haxelib installation via github
+    * [THRIFT-2828] - slightly wrong help screen indent
+    * [THRIFT-2831] - Removes dead code in web_server.js introduced in THRIFT-2819
+    * [THRIFT-2823] - All JS-tests are failing when run with grunt test
+    * [THRIFT-2827] - Thrift 0.9.2 fails to compile on Yosemite due to tr1/functional include in ProcessorTest.cpp
+    * [THRIFT-2843] - Automake configure.ac has possible typo related to Java
+    * [THRIFT-2813] - multiple haxe library fixes/improvements
+    * [THRIFT-2825] - Supplying unicode to python Thrift client can cause next request arguments to get overwritten
+    * [THRIFT-2840] - Cabal file points to LICENSE file outside the path of the Haskell project.
+    * [THRIFT-2818] - Trailing commas in array
+    * [THRIFT-2830] - Clean up ant warnings in tutorial dir
+    * [THRIFT-2842] - Erlang thrift client has infinite timeout
+    * [THRIFT-2810] - Do not leave the underlying ServerSocket open if construction of TServerSocket fails
+    * [THRIFT-2812] - Go server adding redundant buffering layer
+    * [THRIFT-2839] - TFramedTransport read bug
+    * [THRIFT-2844] - Nodejs support broken when running under Browserify
+    * [THRIFT-2814] - args/result classes not found when no namespace is set
+    * [THRIFT-2847] - function IfValue() is a duplicate of System.StrUtils.IfThen
+    * [THRIFT-2848] - certain Delphi tests do not build if TypeRegistry is used
+    * [THRIFT-2854] - Go Struct writer and reader looses important error information
+    * [THRIFT-2858] - Enable header field case insensitive match in THttpServer
+    * [THRIFT-2857] - C# generator creates uncompilable code for struct constants
+    * [THRIFT-2860] - Delphi server closes connection on unexpected exceptions
+    * [THRIFT-2868] - Enhance error handling in the Go client 
+    * [THRIFT-2879] - TMemoryBuffer: using lua string in wrong way
+    * [THRIFT-2851] - Remove strange public Peek() from Go transports
+    * [THRIFT-2852] - Better Open/IsOpen/Close behavior for StreamTransport.
+    * [THRIFT-2871] - Missing semicolon in thrift.js
+    * [THRIFT-2872] - ThreadManager deadlock for task expiration
+    * [THRIFT-2881] - Handle errors from Accept() correctly
+    * [THRIFT-2849] - Spell errors reported by codespell tool
+    * [THRIFT-2870] - C++ TJSONProtocol using locale dependent formatting
+    * [THRIFT-2882] - Lua Generator: using string.len funtion to get struct(map,list,set) size
+    * [THRIFT-2864] - JSON generator missing from Visual Studio build project 
+    * [THRIFT-2878] - Go validation support of required fields
+    * [THRIFT-2873] - TPipe and TPipeServer don't compile on Windows with UNICODE enabled
+    * [THRIFT-2888] - import of <limits> is missing in JSON generator
+    * [THRIFT-2900] - Python THttpClient does not reset socket timeout on exception
+    * [THRIFT-2907] - 'ntohll' macro redefined
+    * [THRIFT-2884] - Map does not serialize correctly for JSON protocol in Go library
+    * [THRIFT-2887] - --with-openssl configure flag is ignored
+    * [THRIFT-2894] - PHP json serializer skips maps with int/bool keys
+    * [THRIFT-2904] - json_protocol_test.go fails
+    * [THRIFT-2906] - library not found for -l:libboost_unit_test_framework.a
+    * [THRIFT-2890] - binary data may lose bytes with JSON transport under specific circumstances
+    * [THRIFT-2891] - binary data may cause a failure with JSON transport under specific circumstances
+    * [THRIFT-2901] - Fix for generated TypeScript functions + indentation of JavaScript maps
+    * [THRIFT-2916] - make check fails for D language
+    * [THRIFT-2918] - Race condition in Python TProcessPoolServer test
+    * [THRIFT-2920] - Erlang Thrift test uses wrong IDL file
+    * [THRIFT-2922] - $TRIAL is used with Python tests but not tested accordingly
+    * [THRIFT-2912] - Autotool build for C++ Qt library is invalid
+    * [THRIFT-2914] - explicit dependency to Lua5.2 fails on some systems
+    * [THRIFT-2910] - libevent is not really optional
+    * [THRIFT-2911] - fix c++ version zeromq transport, the old version cannot work
+    * [THRIFT-2915] - Lua generator missing from Visual Studio build project
+    * [THRIFT-2917] - "make clean" breaks test/c_glib
+    * [THRIFT-2919] - Haxe test server timeout too large
+    * [THRIFT-2923] - JavaScript client assumes a message being written
+    * [THRIFT-2924] - TNonblockingServer crashes when user-provided event_base is used
+    * [THRIFT-2925] - CMake build does not work with OpenSSL nor anything installed in non-system location
+    * [THRIFT-2931] - Access to undeclared static property: Thrift\Protocol\TProtocol::$TBINARYPROTOCOLACCELERATED
+    * [THRIFT-2893] - CMake build fails with boost thread or std thread
+    * [THRIFT-2902] - Generated c_glib code does not compile with clang
+    * [THRIFT-2903] - Qt4 library built with CMake does not work
+    * [THRIFT-2942] - CSharp generate invalid code for property named read or write
+    * [THRIFT-2932] - Node.js Thrift connection libraries throw Exceptions into event emitter
+    * [THRIFT-2933] - v0.9.2: doubles encoded in node with compact protocol cannot be decoded by python
+    * [THRIFT-2934] - createServer signature mismatch
+    * [THRIFT-2981] - IDL with no namespace produces unparsable PHP
+    * [THRIFT-2999] - Addition of .gitattributes text auto in THRIFT-2724 causes modified files on checkout
+    * [THRIFT-2949] - typo in compiler/cpp/README.md
+    * [THRIFT-2957] - warning: source file %s is in a subdirectory, but option 'subdir-objects' is disabled
+    * [THRIFT-2953] - TNamedPipeServerTransport is not Stop()able
+    * [THRIFT-2962] - Docker Thrift env for development and testing
+    * [THRIFT-2971] - C++ test and tutorial parallel build is unstable
+    * [THRIFT-2972] - Missing backslash in lib/cpp/test/Makefile.am
+    * [THRIFT-2951] - Fix Erlang name conflict test
+    * [THRIFT-2955] - Using list of typedefs does not compile on Go
+    * [THRIFT-2960] - namespace regression for Ruby
+    * [THRIFT-2959] - nodejs: fix binary unit tests
+    * [THRIFT-2966] - nodejs: Fix bad references to TProtocolException and TProtocolExceptionType
+    * [THRIFT-2970] - grunt-jsdoc fails due to dependency issues
+    * [THRIFT-3001] - C# Equals fails for binary fields (byte[])
+    * [THRIFT-3003] - Missing LICENSE file prevents package from being installed
+    * [THRIFT-3008] - Node.js server does not fully support exception
+    * [THRIFT-3007] - Travis build is broken because of directory conflict
+    * [THRIFT-3009] - TSSLSocket does not use the correct hostname (breaks certificate checks)
+    * [THRIFT-3011] - C# test server testException() not implemented according to specs
+    * [THRIFT-3012] - Timing problems in NamedPipe implementation due to unnecessary open/close
+    * [THRIFT-3019] - Golang generator missing docstring for structs
+    * [THRIFT-3021] - Service remote tool does not import stub package with package prefix
+    * [THRIFT-3026] - TMultiplexedProcessor does not have a constructor
+    * [THRIFT-3028] - Regression caused by THRIFT-2180
+    * [THRIFT-3017] - order of map key/value types incorrect for one CTOR
+    * [THRIFT-3020] - Cannot compile thrift as C++03
+    * [THRIFT-3024] - User-Agent "BattleNet" used in some Thrift library files
+    * [THRIFT-3047] - Uneven calls to indent_up and indent_down in Cocoa generator
+    * [THRIFT-3048] - NodeJS decoding of I64 is inconsistent across protocols
+    * [THRIFT-3043] - go compiler generator uses non C++98 code
+    * [THRIFT-3044] - Docker README.md paths to Dockerfiles are incorrect
+    * [THRIFT-3040] - bower.json wrong "main" path
+    * [THRIFT-3051] - Go Thrift generator creates bad go code
+    * [THRIFT-3057] - Java compiler build is broken
+    * [THRIFT-3061] - C++ TSSLSocket shutdown delay/vulnerability
+    * [THRIFT-3062] - C++ TServerSocket invalid port number (over 999999) causes stack corruption
+    * [THRIFT-3065] - Update libthrift dependencies (slf4j, httpcore, httpclient)
+    * [THRIFT-3244] - TypeScript: fix namespace of included types
+    * [THRIFT-3246] - Reduce the number of trivial warnings in Windows C++ CMake builds
+    * [THRIFT-3224] - Fix TNamedPipeServer unpredictable behavior on accept
+    * [THRIFT-3230] - Python compiler generates wrong code if there is function throwing a typedef of exception with another namespace
+    * [THRIFT-3236] - MaxSkipDepth never checked
+    * [THRIFT-3239] - Limit recursion depth
+    * [THRIFT-3241] - fatal error: runtime: cannot map pages in arena address space
+    * [THRIFT-3242] - OSGi Import-Package directive is missing the Apache HTTP packages
+    * [THRIFT-3234] - Limit recursion depth
+    * [THRIFT-3222] - TypeScript: Generated Enums are quoted
+    * [THRIFT-3229] - unexpected Timeout exception when desired bytes are only partially available
+    * [THRIFT-3231] - CPP: Limit recursion depth to 64
+    * [THRIFT-3235] - Limit recursion depth
+    * [THRIFT-3175] - fastbinary.c python deserialize can cause huge allocations from garbage
+    * [THRIFT-3176] - Union incorrectly implements ==
+    * [THRIFT-3177] - Fails to run rake test
+    * [THRIFT-3180] - lua plugin: framed transport do not work
+    * [THRIFT-3179] - lua plugin cant connect to remote server because function l_socket_create_and_connect always bind socket to localhost
+    * [THRIFT-3248] - TypeScript: additional comma in method signature without parameters
+    * [THRIFT-3302] - Go JSON protocol should encode Thrift byte type as signed integer string
+    * [THRIFT-3297] - c_glib: an abstract base class is not generated
+    * [THRIFT-3294] - TZlibTransport for Java does not write data correctly
+    * [THRIFT-3296] - Go cross test does not conform to spec
+    * [THRIFT-3295] - C# library does not build on Mono 4.0.2.5 or later
+    * [THRIFT-3293] - JavaScript: null values turn into empty structs in constructor
+    * [THRIFT-3310] - lib/erl/README.md has incorrect formatting
+    * [THRIFT-3319] - CSharp tutorial will not build using the *.sln
+    * [THRIFT-3335] - Ruby server does not handle processor exception
+    * [THRIFT-3338] - Stray underscore in generated go when service name starts with "New"
+    * [THRIFT-3324] - Update Go Docs for pulling all packages
+    * [THRIFT-3345] - Clients blocked indefinitely when a java.lang.Error is thrown
+    * [THRIFT-3332] - make dist fails on clean build
+    * [THRIFT-3326] - Tests do not compile under *BSD
+    * [THRIFT-3334] - Markdown notation of protocol spec is malformed
+    * [THRIFT-3331] - warning: ‘etype’ may be used uninitialized in this function
+    * [THRIFT-3349] - Python server does not handle processor exception
+    * [THRIFT-3343] - Fix haskell README
+    * [THRIFT-3340] - Python: enable json tests again
+    * [THRIFT-3311] - Top level README.md has incorrect formmating
+    * [THRIFT-2936] - Minor memory leak in SSL
+    * [THRIFT-3290] - Using from in variable names causes the generated Python code to have errors
+    * [THRIFT-3225] - Fix TPipeServer unpredictable behavior on interrupt()
+    * [THRIFT-3354] - Fix word-extraction substr bug in initialism code
+    * [THRIFT-2006] - TBinaryProtocol message header call name length is not validated and can be used to core the server
+    * [THRIFT-3329] - C++ library unit tests don't compile against the new boost-1.59 unit test framework
+    * [THRIFT-2630] - windows7 64bit pc. ipv4 and ipv6 pc.can't use
+    * [THRIFT-3336] - Thrift generated streaming operators added in 0.9.2 cannot be overridden
+    * [THRIFT-2681] - Core of unwind_cleanup
+    * [THRIFT-3317] - cpp namespace org.apache issue appears in 0.9
+
+## Documentation
+    * [THRIFT-3286] - Apache Ant is a necessary dependency
+
+## Improvement
+    * [THRIFT-227] - Byte[] in collections aren't pretty printed like regular binary fields
+    * [THRIFT-2744] - Vagrantfile for Centos 6.5
+    * [THRIFT-2644] - Haxe support
+    * [THRIFT-2756] - register Media Type @ IANA
+    * [THRIFT-3076] - Compatibility with Haxe 3.2.0
+    * [THRIFT-3081] - C++ Consolidate client processing loops in TServers
+    * [THRIFT-3083] - C++ Consolidate server processing loops in TSimpleServer, TThreadedServer, TThreadPoolServer
+    * [THRIFT-3084] - C++ add concurrent client limit to threaded servers
+    * [THRIFT-3074] -     Add compiler/cpp/lex.yythriftl.cc to gitignore.
+    * [THRIFT-3134] - Remove use of deprecated "phantom.args"
+    * [THRIFT-3133] - Allow "make cross" and "make precross" to run without building all languages
+    * [THRIFT-3142] - Make JavaScript use downloaded libraries
+    * [THRIFT-3141] - Improve logging of JavaScript test
+    * [THRIFT-3144] - Proposal: make String representation of enums in generated go code less verbose
+    * [THRIFT-3130] - Remove the last vestiges of THRIFT_OVERLOAD_IF from THRIFT-1316
+    * [THRIFT-3131] - Consolidate suggested import path for go thrift library to git.apache.org in docs and code
+    * [THRIFT-3092] - Generated Haskell types should derive Generic
+    * [THRIFT-3110] -  Print error log after cross test failures on Travis
+    * [THRIFT-3114] - Using local temp variables to not pollute the global table
+    * [THRIFT-3106] - CMake summary should give more information why a library is set to off
+    * [THRIFT-3119] - Java's TThreadedSelectorServer has indistinguishable log messages in run()
+    * [THRIFT-3122] - Javascript struct constructor should properly initialize struct and container members from plain js arguments
+    * [THRIFT-3151] - Fix links to git-wip* - should be git.apache.org
+    * [THRIFT-3167] - Windows build from source instructions need to be revised
+    * [THRIFT-3155] - move contrib/mingw32-toolchain.cmake to build/cmake/
+    * [THRIFT-3160] - Make generated go enums implement TextMarshaller and TextUnmarshaller interfaces
+    * [THRIFT-3150] - Add an option to thrift go generator to make Read and Write methods private
+    * [THRIFT-3149] - Make ReadFieldN methods in generated Go code private
+    * [THRIFT-3172] - Add tutorial to Thrift web site
+    * [THRIFT-3214] - Add Erlang option for using maps instead of dicts
+    * [THRIFT-3201] - Capture github test artifacts for failed builds
+    * [THRIFT-3266] - c_glib: Multiple compiler warnings building unit tests
+    * [THRIFT-3285] - c_glib: Build library with all warnings enabled, no warnings generated
+    * [THRIFT-1954] - Allow for a separate connection timeout value 
+    * [THRIFT-2098] - Add support for Qt5+
+    * [THRIFT-2199] - Remove Dense protocol (was: move to Contrib)
+    * [THRIFT-406] - C++ Test suite cleanup
+    * [THRIFT-902] - socket and connect timeout in TSocket should be distinguished
+    * [THRIFT-388] - Use a separate wire format for async calls
+    * [THRIFT-727] - support native C++ language specific exception message
+    * [THRIFT-1784] - pep-3110 compliance for exception handling 
+    * [THRIFT-1025] - C++ ServerSocket should inherit from Socket with the necessary Ctor to listen on connections from a specific host
+    * [THRIFT-2269] - Can deploy libthrift-source.jar to maven center repository
+    * [THRIFT-2804] - Pull an interface out of TBaseAsyncProcessor
+    * [THRIFT-2806] - more whitespace fixups
+    * [THRIFT-2811] - Make remote socket address accessible
+    * [THRIFT-2809] - .gitignore update for compiler's visual project
+    * [THRIFT-2846] - Expose ciphers parameter from ssl.wrap_socket()
+    * [THRIFT-2859] - JSON generator: output complete descriptors
+    * [THRIFT-2861] - add buffered transport
+    * [THRIFT-2865] - Test case for Go: SeqId out of sequence
+    * [THRIFT-2866] - Go generator source code is hard to read and maintain
+    * [THRIFT-2880] - Read the network address from the listener if available.
+    * [THRIFT-2875] - Typo in TDenseProtocol.h comment
+    * [THRIFT-2874] - TBinaryProtocol  member variable "string_buf_" is never used.
+    * [THRIFT-2855] - Move contributing.md to the root of the repository
+    * [THRIFT-2862] - Enable RTTI and/or build macros for generated code
+    * [THRIFT-2876] -  Add test for THRIFT-2526 Assignment operators and copy constructors in c++ don't copy the __isset struct
+    * [THRIFT-2897] - Generate -isEqual: and -hash methods
+    * [THRIFT-2909] - Improve travis build
+    * [THRIFT-2921] - Make Erlang impl ready for OTP 18 release (dict/0 and set/0 are deprecated)
+    * [THRIFT-2928] - Rename the erlang test_server module
+    * [THRIFT-2940] - Allow installing Thrift from git as NPM module by providing package.json in top level directory
+    * [THRIFT-2937] - Allow setting a maximum frame size in TFramedTransport
+    * [THRIFT-2976] - nodejs: xhr and websocket support for browserify
+    * [THRIFT-2996] - Test for Haxe 3.1.3 or better 
+    * [THRIFT-2969] - nodejs: DRY up library tests
+    * [THRIFT-2973] - Update Haxe lib readme regarding Haxe 3.1.3
+    * [THRIFT-2952] - Improve handling of Server.Stop() 
+    * [THRIFT-2964] - nodejs: move protocols and transports into separate files
+    * [THRIFT-2963] - nodejs - add test coverage
+    * [THRIFT-3006] - Attach 'omitempty' json tag for optional fields in Go
+    * [THRIFT-3027] - Go compiler does not ensure common initialisms have consistent case
+    * [THRIFT-3030] - TThreadedServer: Property for number of clientThreads
+    * [THRIFT-3023] - Go compiler is a little overly conservative with names of attributes
+    * [THRIFT-3018] - Compact protocol for Delphi
+    * [THRIFT-3025] - Change pure Int constants into @enums (where possible)
+    * [THRIFT-3031] - migrate "shouldStop" flag to TServer
+    * [THRIFT-3022] - Compact protocol for Haxe
+    * [THRIFT-3041] - Generate asynchronous clients for Cocoa
+    * [THRIFT-3053] - Perl SSL Socket Support (Encryption)
+    * [THRIFT-3247] - Generate a C++ thread-safe client
+    * [THRIFT-3217] - Provide a little endian variant of the binary protocol in C++
+    * [THRIFT-3223] - TypeScript: Add initial support for Enum Maps
+    * [THRIFT-3220] - Option to suppress @Generated Annotation entirely
+    * [THRIFT-3300] - Reimplement TZlibTransport in Java using streams
+    * [THRIFT-3288] - c_glib: Build unit tests with all warnings enabled, no warnings generated
+    * [THRIFT-3347] - Improve cross test servers and clients
+    * [THRIFT-3342] - Improve ruby cross test client and server compatibility
+    * [THRIFT-2296] - Add C++ Base class for service
+    * [THRIFT-3337] - Add testBool method to cross tests
+    * [THRIFT-3303] - Disable concurrent cabal jobs on Travis to avoid GHC crash
+    * [THRIFT-2623] - Docker container for Thrift
+    * [THRIFT-3298] - thrift endian converters may conflict with other libraries
+    * [THRIFT-1559] - Provide memory pool for TBinaryProtocol to eliminate memory fragmentation
+    * [THRIFT-424] - Steal ProtocolBuffers' VarInt implementation for C++
+
+## New Feature
+    * [THRIFT-3070] - Add ability to set the LocalCertificateSelectionCallback
+    * [THRIFT-1909] - Java: Add compiler flag to use the "option pattern" for optional fields
+    * [THRIFT-2099] - Stop TThreadPoolServer with alive connections.
+    * [THRIFT-123] - implement TZlibTransport in Java
+    * [THRIFT-2368] - New option: reuse-objects for Java generator
+    * [THRIFT-2836] - Optionally generate C++11 MoveConstructible types
+    * [THRIFT-2824] - Flag to disable html escaping doctext
+    * [THRIFT-2819] - Add WebsSocket client to node.js
+    * [THRIFT-3050] - Client certificate authentication for non-http TLS in C#
+    * [THRIFT-3292] - Implement TZlibTransport in Go
+
+## Question
+    * [THRIFT-2583] - Thrift on xPC target (SpeedGoat)
+    * [THRIFT-2592] - thrift server using c_glib
+    * [THRIFT-2832] - c_glib: Handle string lists correctly
+    * [THRIFT-3136] - thrift installation problem on mac
+    * [THRIFT-3346] - c_glib: Tutorials example crashes saying Calculator.ping implementation returned FALSE but did not set an error
+
+## Sub-task
+    * [THRIFT-2578] - Moving 'make cross' from test.sh to test.py
+    * [THRIFT-2734] - Go coding standards
+    * [THRIFT-2748] - Add Vagrantfile for Centos 6.5
+    * [THRIFT-2753] - Misc. Haxe improvements
+    * [THRIFT-2640] - Compact Protocol in Cocoa
+    * [THRIFT-3262] - warning: overflow in implicit constant conversion in DenseProtoTest.cpp
+    * [THRIFT-3194] - Can't build with go enabled.  gomock SCC path incorrect.
+    * [THRIFT-3275] - c_glib tutorial warnings in generated code
+    * [THRIFT-1125] - Multiplexing support for the Ruby Library
+    * [THRIFT-2807] - PHP Code Style
+    * [THRIFT-2841] - Add comprehensive integration tests for the whole Go stack
+    * [THRIFT-2815] - Haxe: Support for Multiplexing Services on any Transport, Protocol and Server
+    * [THRIFT-2886] - Integrate binary type in standard Thrift cross test
+    * [THRIFT-2946] - Enhance usability of cross test framework
+    * [THRIFT-2967] - Add .editorconfig to root
+    * [THRIFT-3033] - Perl: Support for Multiplexing Services on any Transport, Protocol and Server
+    * [THRIFT-3174] - Initialism code in the Go compiler doesn't check first word
+    * [THRIFT-3193] - Option to supress date value in @Generated annotation
+    * [THRIFT-3305] - Missing dist files for 0.9.3 release candidate
+    * [THRIFT-3341] - Add testBool methods
+    * [THRIFT-3308] - Fix broken test cases for 0.9.3 release candidate
+
+## Task
+    * [THRIFT-2834] - Remove semi-colons from python code generator
+    * [THRIFT-2853] - Adjust comments not applying anymore after THRIFT-2852
+
+## Test
+    * [THRIFT-3211] - Add make cross support for php TCompactProtocol
+
+## Wish
+    * [THRIFT-2838] - TNonblockingServer can bind to port 0 (i.e., get an OS-assigned port) but there is no way to get the port number
 
 
-Version 0.8.0
 
-THRIFT-1330   PHP                  PHP Namespaces no longer generated
-THRIFT-1392   PHP                  Enabling both namespaces and autoloading in generated PHP code won't work.
-THRIFT-386    Python               Make it possible to build the Python library without the extension
-THRIFT-1431   Node.js              Rename 'sys' module to 'util'
-THRIFT-1435   Delphi               make TException.Message property conformant to the usual expectations
-THRIFT-1432   JavaScript           Javascript struct constants declared in the same file as their struct cause an error
-THRIFT-1391   Delphi               Improved Delphi XE test cases
-THRIFT-1387   C++                  Build MSVC libraries with Boost Threads instead of Pthreads
-THRIFT-1426   Build Process        Dist package missing files for release 0.8
-THRIFT-1428   Tutorial             shared.thrft does not include namespace for php, compiler generate incorrect name
-THRIFT-1411   Java                 java generator does not provide type parameter for TBaseProcessor
-THRIFT-1425   Node.js              The Node package is incompatible with latest node (0.6) & npm (1.0.27)
-THRIFT-1401   Delphi               JSON-protocol for Delphi XE Libraries
-THRIFT-1424   Ruby                 Ruby specs fail when run with rake
-THRIFT-1382   Ruby                 Bundle install doesnot work because thrift crashes
-THRIFT-1251   Java                 Generated java code should indicate which fields are required and which are optional
-THRIFT-1361   C++                  Optional replacement of pthread by boost::thread
-THRIFT-1415   Delphi               delphi: add version Info to the library
-THRIFT-1031   C++                  Patch to compile Thrift for vc++ 9.0 and 10.0
-THRIFT-1420   Java                 Nonblocking and HsHa server should close all socket connections when the selector exits
-THRIFT-1419   Java                 AbstractNonBlockingServer does not catch errors when invoking the processor
-THRIFT-1416   Python               Python Unit test is broken on ci
-THRIFT-1409   Delphi               Name conflict check does not work properly for exception object(Delphi).
-THRIFT-1413   Delphi               Generated code does not read MapEnd / ListEnd / SetEnd
-THRIFT-1408   Delphi               Delphi Test Server: Exception test case fails due to naming conflict with e.message
-THRIFT-1407   Python               Typo in Python socket server causes Thrift to fail when we enable a global socket timout
-THRIFT-1405   Delphi               Delphi compiler does not generates container serializer properly.
-THRIFT-1399   Delphi               One of the TServerImpl.Create CTORs lacks implementation
-THRIFT-1406   Delphi               Build error after applying THRIFT-1395
-THRIFT-1404   Delphi               Delphi compiler generates struct reader code with problem.
-THRIFT-1395   Delphi               Patch to prevent warnings for integer types in some cases
-THRIFT-1400   Ruby                 Ruby native extension aborts with __stack_chk_fail in OSX
-THRIFT-1397   Test Suite           CI server fails during build due to unused parameters in delphi generator
-THRIFT-1396   Delphi               Dephi generator has dependacy on boost 1.42 later.
-THRIFT-1390   Build Process        Debian packages build fix for Squeeze (build from the official  0.7.0 tarball)
-THRIFT-1393   PHP                  TTransportException's thrown from THttpClient has extra slashes in the Exception message
-THRIFT-1366   Delphi               Delphi generator, lirbrary and unit test.
-THRIFT-1130   Compiler (General)   Add the ability to specify symbolic default value for optional boolean
-THRIFT-1381   C++                  Thrift C++ libs have incorrectly versioned names
-THRIFT-1384   Javame               Java help menu missing newline near javame flag
-THRIFT-1373   C++                  Fix user-defined exception generation in thrift (python)
-THRIFT-1379   C++                  fix uninitialized enum values in thrift C++ objects
-THRIFT-1377   C++                  abort PHP deserialization on unknown field type
-THRIFT-1376   C++                  Make port specification option in thrift remote
-THRIFT-1375   C++                  fixed a hex char conversion bug in TJSONProtocol
-THRIFT-1370   C glib               Debian packaging should Build-Depend on libglib2.0-dev
-THRIFT-1121   Java                 Java server performance regression in 0.6
-THRIFT-1365   Java                 TupleProtocol#writeBitSet unintentionally writes a variable length byte array
-THRIFT-1359   C++                  --gen-cob cpp:cob_style does not compile anymore
-THRIFT-1355   Ruby                 Running make in lib/rb doesn't build the native extensions
-THRIFT-1354   Ruby                 Add rake task to build just the gem file
-THRIFT-857    Test Suite           tests run by "make install" fail if generators are disabled
-THRIFT-1339   Java                 Extend Tuple Protocol to TUnions
-THRIFT-1331   Ruby                 Ruby library deserializes an empty map to nil
-THRIFT-1350   Go                   Go library code does not build as of r60 (most recent release)
-THRIFT-1227   Erlang               Erlang implementation of thrift JSON protocol
-THRIFT-1335   C++                  Add accept timeout to TServerSocket
-THRIFT-1345   Build Process        Allow building without tests
-THRIFT-1342   Python               Compilation problem on Windows of fastbinary.c
-THRIFT-1341   C++                  TProtocol.h endian detection wrong with boost
-THRIFT-1243   C++                  TAsyncChannel callbacks
-THRIFT-1238   JavaScript           Thrift JS client cannot read map of structures
-THRIFT-1333   C++                  Make RWGuard not copyable
-THRIFT-1334   C++                  Add more info to IllegalStateException
-THRIFT-1332   Java                 TSSLTransportParameters class uses hard coded value keyManagerType: SunX509
-THRIFT-1328   Java                 TBaseHelper.toString(...) appends ByteBuffer data outside of valid buffer range
-THRIFT-1322   OCaml                OCaml lib fail to compile: Thrift.ml line 305, int vs int32 mismatch
-THRIFT-1279   PHP                  type set is handled incorrectly when writing object
-THRIFT-1320   C++                  Consistency of configure generated config.h
-THRIFT-1319   Java                 Mismatch between how a union reads and writes a container
-THRIFT-1316   C++                  thrift: update server classes to accept
-THRIFT-1314   C++                  thrift: add TProcessorFactory
-THRIFT-1315   C++                  thrift: generate server interface factory classes
-THRIFT-1317   C++                  Remove copy constructibility from
-THRIFT-1305   C++                  thrift: make TConnection a private inner class of
-THRIFT-1286   Ruby                 Modernize the Thrift Ruby Library Dev Environment
-THRIFT-1304   C++                  TNonblockingServer: pass in the connection context to
-THRIFT-1302   C++                  thrift: raise an exception if send() times out in
-THRIFT-1301   C++                  thrift: consolidate common code in TNonblockingServer
-THRIFT-1298   Java                 Standard scheme doesn't read or write metadata along with field values
-THRIFT-1257   Java                 thrift's dependency scope on javax.servlet:servlet-api should be 'provided'
-THRIFT-1240   PHP                  TBinarySerializer invalid serialization due to TBufferTransport not flushing 
-THRIFT-1295   C++                  Duplicate include in TSocket.cpp
-THRIFT-1294   C++                  thrift: fix log message typos in TSimpleServer
-THRIFT-1293   C++                  thrift: improve handling of exceptions thrown by
-THRIFT-1292   C++                  thrift: silence log spew from TThreadedServer
-THRIFT-1290   C++                  thrift: TNonblockingServer: clean up state in the
-THRIFT-1289   C++                  thrift: implement TNonblockingServer::stop()
-THRIFT-1288   C++                  Allow typedefed exceptions in throws clauses
-THRIFT-1287   C++                  thrift: start refactoring some of the C++ processor
-THRIFT-1280   C++                  Thrift: Improve Monitor exception-free interfaces
-THRIFT-1281   Compiler (General)   add @generated to the docblock
-THRIFT-1282   Java                 Upgrade httpclient to 4.1.2 (from 4.0.1)
-THRIFT-1284   C++                  thrift: fix processor inheritance
-THRIFT-1283   C++                  thrift: wrap t_cpp_generator::generate_process_function() to 80
-THRIFT-1278   Java                 javadoc warnings - compilation
-THRIFT-1254   JavaME               Code compiled against a regular JRE: Object.clone() override has a different return type
-THRIFT-1271   C++                  thrift: fix missing namespace in generated local
-THRIFT-1274   C++                  thrift: fail compilation if an unexpected token is
-THRIFT-1275   C++                  thrift: always prefix namespaces with " ::"
-THRIFT-1265   C++                  C++ container deserialize
-THRIFT-1167   Java                 Java nonblocking server with more than one thread for select and handling IO
-THRIFT-380    Python               Use setuptools for python build
-THRIFT-1270   C++                  thrift: add --allow-neg-keys argument to allow
-THRIFT-1263   Ruby                 publish ruby client to rubygems
-THRIFT-1205   Java                 port server unduly fragile with arbitrary input
-THRIFT-769    Java                 Pluggable Serializers
-THRIFT-1239   Java                 TupleProtocol- An extremely compact, temporary protocol
+Thrift 0.9.2
+--------------------------------------------------------------------------------
+## Bug
+    * [THRIFT-2793] - Go compiler produces uncompilable code
+    * [THRIFT-1481] - Unix domain sockets in C++ do not support the abstract namespace
+    * [THRIFT-1455] - TBinaryProtocolT<Transport_>::writeString casts from size_t to uint32_t, which is not safe on 64-bit platforms
+    * [THRIFT-1579] - PHP Extention - function thrift_protocol_read_binary not working from TBinarySerializer::deserialize
+    * [THRIFT-1584] - Error: could not SetMinThreads in ThreadPool on single-core machines
+    * [THRIFT-1614] - Thrift build from svn repo sources fails with automake-1.12
+    * [THRIFT-1047] - rb_thrift_memory_buffer_write treats arg as string without check, segfaults if you pass non-string
+    * [THRIFT-1639] - Java/Python: Serialization/Deserialization of double type using CompactProtocol
+    * [THRIFT-1647] - NodeJS BufferedTransport does not work beyond the hello-world example
+    * [THRIFT-2130] - Thrift's D library/test: parts of "make check" code do not compile with recent dmd-2.062 through dmd-2.064alpha
+    * [THRIFT-2140] - Error compiling cpp tutorials
+    * [THRIFT-2139] - MSVC 2012 Error - Cannot compile due to BoostThreadFactory
+    * [THRIFT-2138] - pkgconfig file created with wrong include path
+    * [THRIFT-2160] - Warning in thrift.h when compiling with -Wunused and NDEBUG
+    * [THRIFT-2158] - Compact, JSON, and SimpleJSON protocols are not working correctly
+    * [THRIFT-2167] - nodejs lib throws error if options argument isn't passed
+    * [THRIFT-2288] - Go impl of Thrift JSON protocol wrongly writes/expects true/false for bools
+    * [THRIFT-2147] - Thrift IDL grammar allows for dotted identifier names
+    * [THRIFT-2145] - Rack and Thin are not just development dependencies
+    * [THRIFT-2267] - Should be able to choose socket family in Python TSocket
+    * [THRIFT-2276] - java path in spec file needs updating
+    * [THRIFT-2281] - Generated send/recv code ignores errors returned by the underlying protocol
+    * [THRIFT-2280] - TJSONProtocol.Flush() does not really flush the transport
+    * [THRIFT-2274] - TNonblockingServer and TThreadedSelectorServer do not close their channel selectors on exit and leak file descriptors
+    * [THRIFT-2265] - php library doesn't build
+    * [THRIFT-2232] - IsSet* broken in Go
+    * [THRIFT-2246] - Unset enum value is printed by ToString()
+    * [THRIFT-2240] - thrift.vim (contrib) does not correctly handle 'union'
+    * [THRIFT-2243] - TNonblockingServer in thrift crashes when TFramedTransport opens
+    * [THRIFT-2230] - Cannot Build on RHEL/Centos/Amazon Linux 6.x
+    * [THRIFT-2247] - Go generator doesn't deal well with map keys of type binary
+    * [THRIFT-2253] - Python Tornado TTornadoServer base class change
+    * [THRIFT-2261] - java: error: unmappable character for encoding ASCII
+    * [THRIFT-2259] - C#: unexpected null logDelegate() pointer causes AV in TServer.serve()
+    * [THRIFT-2225] - SSLContext destroy before cleanupOpenSSL
+    * [THRIFT-2224] - TSSLSocket.h and TSSLServerSocket.h should use the platfromsocket too
+    * [THRIFT-2229] - thrift failed to build on OSX 10.9 GM
+    * [THRIFT-2227] - Thrift compiler generates spurious warnings with Xlint
+    * [THRIFT-2219] - Thrift gem fails to build on OS X Mavericks with 1.9.3 rubies
+    * [THRIFT-2226] - TServerSocket - keepAlive wrong initialization order
+    * [THRIFT-2285] - TJsonProtocol implementation for Java doesn't allow a slash (/) to be escaped (\/)
+    * [THRIFT-2216] - Extraneous semicolon in TProtocolUtil.h makes clang mad
+    * [THRIFT-2215] - Generated HTML/Graphviz lists referenced enum identifiers as UNKNOWN.
+    * [THRIFT-2211] - Exception constructor does not contain namespace prefix.
+    * [THRIFT-2210] - lib/java TSimpleJSONProtocol can emit invalid JSON
+    * [THRIFT-2209] - Ruby generator -- please namespace classes
+    * [THRIFT-2202] - Delphi TServerImpl.DefaultLogDelegate may stop the server with I/O-Error 105
+    * [THRIFT-2201] - Ternary operator returns different types (build error for some compilers)
+    * [THRIFT-2200] - nested structs cause generate_fingerprint() to slow down at excessive CPU load
+    * [THRIFT-2197] - fix jar output directory in rpm spec file
+    * [THRIFT-2196] - Fix invalid dependency in Makefile.am
+    * [THRIFT-2194] - Node: Not actually prepending residual data in TFramedTransport.receiver
+    * [THRIFT-2193] - Java code generator emits spurious semicolon when deep copying binary data
+    * [THRIFT-2191] - Fix charp JSONProtocol.ReadJSONDouble (specify InvariantCulture)
+    * [THRIFT-2214] - System header sys/param.h is included inside the Thrift namespace
+    * [THRIFT-2178] - Thrift generator returns error exit code on --version
+    * [THRIFT-2171] - NodeJS implementation has extremely low test coverage
+    * [THRIFT-2183] - gem install fails on zsh
+    * [THRIFT-2182] - segfault in regression tests (GC bug in rb_thrift_memory_buffer_write)
+    * [THRIFT-2181] - oneway calls don't work in NodeJS
+    * [THRIFT-2169] - JavaME Thrift Library causes "java.io.IOException: No Response Entries Available" after using the Thrift client for some time
+    * [THRIFT-2168] - Node.js appears broken (at least, examples don't work as intended)
+    * [THRIFT-2293] - TSSLTransportFactory.createSSLContext() leaves files open
+    * [THRIFT-2279] - TSerializer only returns the first 1024 bytes serialized
+    * [THRIFT-2278] - Buffered transport doesn't support writes > buffer size
+    * [THRIFT-2275] - Fix memory leak in golang compact_protocol.
+    * [THRIFT-2282] - Incorect code generated for some typedefs
+    * [THRIFT-2009] - Go redeclaration error
+    * [THRIFT-1964] - 'Isset' causes problems with C#/.NET serializers
+    * [THRIFT-2026] - Fix TCompactProtocol 64 bit builds
+    * [THRIFT-2108] - Fix TAsyncClientManager timeout race
+    * [THRIFT-2068] - Multiple calls from same connection are not processed in node
+    * [THRIFT-1750] - Make compiler build cleanly under visual studio 10
+    * [THRIFT-1755] - Comment parsing bug
+    * [THRIFT-1771] - "make check" fails on x64 for libboost_unit_test_framework.a
+    * [THRIFT-1841] - NodeJS Thrift incorrectly parses non-UTF8-string types
+    * [THRIFT-1908] - Using php thrift_protocol accelerated transfer causes core dump
+    * [THRIFT-1892] - Socket timeouts are declared in milli-seconds, but are actually set in micro-seconds
+    * [THRIFT-2303] - TBufferredTransport not properly closing underlying transport
+    * [THRIFT-2313] - nodejs server crash after processing the first request when using MultiplexedProcessor/FramedBuffer/BinaryProtocol
+    * [THRIFT-2311] - Go: invalid code generated when exception name is a go keyword
+    * [THRIFT-2308] - node: TJSONProtocol parse error when reading from buffered message
+    * [THRIFT-2316] - ccp: TFileTransportTest
+    * [THRIFT-2352] - msvc failed to compile thrift tests
+    * [THRIFT-2337] - Golang does not report TIMED_OUT exceptions
+    * [THRIFT-2340] - Generated server implementation does not send response type EXCEPTION on the Thrift.TApplicationExceptionType.UNKNOWN_METHOD exception
+    * [THRIFT-2354] - Connection errors can lead to case_clause exceptions
+    * [THRIFT-2339] - Uncaught exception in thrift c# driver
+    * [THRIFT-2356] - c++ thrift client not working with ssl (SSL_connect hangs)
+    * [THRIFT-2331] - Missing call to ReadStructBegin() in TApplicationException.Read()
+    * [THRIFT-2323] - Uncompileable Delphi code generated for typedef'd structs
+    * [THRIFT-2322] - Correctly show the number of times ExecutorService (java) has rejected the client.
+    * [THRIFT-2389] - namespaces handled wrongly in acrionscript 3.0 implementation
+    * [THRIFT-2388] - GoLang - Fix data races in simple_server and server_socket
+    * [THRIFT-2386] - Thrift refuses to link yylex
+    * [THRIFT-2375] - Excessive <br>'s in generated HTML
+    * [THRIFT-2373] - warning CS0414 in THttpClient.cs: private field 'Thrift.Transport.THttpClient.connection' assigned but never used
+    * [THRIFT-2372] - thrift/json_protocol.go:160: function ends without a return statement
+    * [THRIFT-2371] - ruby bundler version fails on ~1.3.1, remove and take latest avail
+    * [THRIFT-2370] - Compiler SEGFAULTs generating HTML documentation for complex strucre
+    * [THRIFT-2384] - Binary map keys produce uncompilable code in go
+    * [THRIFT-2380] - unreachable code (CID 1174546, CID 1174679)
+    * [THRIFT-2378] - service method arguments of binary type lead to uncompileable Go code
+    * [THRIFT-2363] - Issue with character encoding of Success returned from Login using Thrift Proxy and NodeJS
+    * [THRIFT-2359] - TBufferedTransport doesn't clear it's buffer on a failed flush call
+    * [THRIFT-2428] - Python 3 setup.py support
+    * [THRIFT-2367] - Build failure: stdlib and boost both define uint64_t
+    * [THRIFT-2365] - C# decodes too many binary bytes from JSON
+    * [THRIFT-2402] - byte count of FrameBuffer in AWAITING_CLOSE state is not subtracted from readBufferBytesAllocated
+    * [THRIFT-2396] - Build Error on MacOSX
+    * [THRIFT-2395] - thrift Ruby gem requires development dependency 'thin' regardless of environment
+    * [THRIFT-2414] - c_glib fix several bug.
+    * [THRIFT-2420] - Go argument parser for methods without arguments does not skip fields
+    * [THRIFT-2439] - Bug in TProtocolDecorator Class causes parsing errors
+    * [THRIFT-2419] - golang - Fix fmt.Errorf in generated code
+    * [THRIFT-2418] - Go handler function panics on internal error
+    * [THRIFT-2405] - Node.js Multiplexer tests fail (silently)
+    * [THRIFT-2581] - TFDTransport destructor should not throw
+    * [THRIFT-2575] - Thrift includes siginfo_t within apache::thrift::protocol namespace
+    * [THRIFT-2577] - TFileTransport  missuse of closesocket on windows platform
+    * [THRIFT-2576] - Implement Thrift.Protocol.prototype.skip method in JavaScript library
+    * [THRIFT-2588] - Thrift compiler is not buildable in Visual Studio 2010
+    * [THRIFT-2594] - JS Compiler: Single quotes are not being escaped in constants.
+    * [THRIFT-2591] - TFramedTransport does not handle payloads split across packets correctly
+    * [THRIFT-2599] - Uncompileable Delphi code due to naming conflicts with IDL
+    * [THRIFT-2590] - C++ Visual Studio solution doesn't include Multiplexing support
+    * [THRIFT-2595] - Node.js: Fix global leaks and copy-paste errors
+    * [THRIFT-2565] - autoconf fails to find mingw-g++ cross compiler on travis CI
+    * [THRIFT-2555] - excessive "unused field" comments
+    * [THRIFT-2554] - double initialization in generated Read() method
+    * [THRIFT-2551] - OutOfMemoryError "unable to create new native thread" kills serve thread
+    * [THRIFT-2543] - Generated enum type in haskell should be qualified
+    * [THRIFT-2560] - Thrift compiler generator tries to concat ints with strings using +
+    * [THRIFT-2559] - Centos 6.5 unable to "make" with Thrift 0.9.1
+    * [THRIFT-2526] - Assignment operators and copy constructors in c++ don't copy the __isset struct
+    * [THRIFT-2454] - c_glib: There is no gethostbyname_r() in some OS.
+    * [THRIFT-2451] - Do not use pointers for optional fields with defaults. Do not write such fields if its value set to default. Also, do not use pointers for any optional fields mapped to go map or slice. generate Get accessors
+    * [THRIFT-2450] - include HowToContribute in the src repo
+    * [THRIFT-2448] - thrift/test/test.sh has incorrect Node.js test path
+    * [THRIFT-2460] - unopened socket fd must be less than zero.
+    * [THRIFT-2459] - --version should not exit 1
+    * [THRIFT-2468] - Timestamp handling
+    * [THRIFT-2467] - Unable to build contrib/fb303 on OSX 10.9.2
+    * [THRIFT-2466] - Improper error handling for SSL/TLS connections that don't complete a handshake
+    * [THRIFT-2463] - test/py/RunClientServer.py fails sometimes
+    * [THRIFT-2458] - Generated golang server code for "oneway" methods is incorrect
+    * [THRIFT-2456] - THttpClient fails when using async support outside Silverlight
+    * [THRIFT-2524] - Visual Studio project is missing TThreadedServer files
+    * [THRIFT-2523] - Visual Studio project is missing OverlappedSubmissionThread files
+    * [THRIFT-2520] - cpp:cob_style generates incorrect .tcc file
+    * [THRIFT-2508] - Uncompileable C# code due to language keywords in IDL
+    * [THRIFT-2506] - Update TProtocolException error codes to be used consistently throughout the library
+    * [THRIFT-2505] - go: struct should always be a pointer to avoid copying of potentially size-unbounded structs
+    * [THRIFT-2515] - TLS Method error during make
+    * [THRIFT-2503] - C++: Fix name collision when a struct has a member named "val"
+    * [THRIFT-2477] - thrift --help text with misplaced comma
+    * [THRIFT-2492] - test/cpp does not compile on mac
+    * [THRIFT-2500] - sending random data crashes thrift(golang) service
+    * [THRIFT-2475] - c_glib: buffered_transport_write function return always TRUE.
+    * [THRIFT-2495] - JavaScript/Node string constants lack proper escaping
+    * [THRIFT-2491] - unable to import generated ThriftTest service
+    * [THRIFT-2490] - c_glib: if fail to read a exception from server, client may be occurred double free
+    * [THRIFT-2470] - THttpHandler swallows exceptions from processor
+    * [THRIFT-2533] - Boost version in requirements should be updated
+    * [THRIFT-2532] - Java version in installation requirements should be updated
+    * [THRIFT-2529] - TBufferedTransport split  Tcp data bug in nodeJs
+    * [THRIFT-2537] - Path for "go get" does not work (pull request 115)
+    * [THRIFT-2443] - Node fails cross lang tests
+    * [THRIFT-2437] - Author fields in Python setup.py must be strings not lists.
+    * [THRIFT-2435] - Java compiler doesn't like struct member names that are identical to an existing enum or struct type
+    * [THRIFT-2434] - Missing namespace import for php TMultiplexedProcessor implementation
+    * [THRIFT-2432] - Flaky parallel build
+    * [THRIFT-2430] - Crash during TThreadPoolServer shutdown
+    * [THRIFT-667] - Period should not be allowed in identifier names
+    * [THRIFT-1212] - Members capital case conflict
+    * [THRIFT-2584] - Error handler not listened on javascript client
+    * [THRIFT-2294] - Incorrect Makefile generation
+    * [THRIFT-2601] - Fix vagrant to work again for builds again
+    * [THRIFT-2092] - TNonblocking server should release handler as soon as connection closes
+    * [THRIFT-2557] - CS0542 member names cannot be the same as their enclosing type
+    * [THRIFT-2605] - TSocket warning on gcc 4.8.3
+    * [THRIFT-2607] - ThreadManager.cpp warning on clang++ 3.4
+    * [THRIFT-1998] - TCompactProtocol.tcc - one more warning on Visual 2010
+    * [THRIFT-2610] - MSVC warning in TSocket.cpp
+    * [THRIFT-2614] - TNonblockingServer.cpp warnings on MSVC
+    * [THRIFT-2608] - TNonblockingServer.cpp warnings on clang 3.4
+    * [THRIFT-2606] - ThreadManager.h warning in clang++ 3.4
+    * [THRIFT-2609] - TFileTransport.h unused field warning (clang 3.4)
+    * [THRIFT-2416] - Cannot use TCompactProtocol with MSVC
+    * [THRIFT-1803] - Ruby Thrift 0.9.0 tries to encode UUID to UTF8 and crashes
+    * [THRIFT-2385] - Problem with gethostbyname2 during make check
+    * [THRIFT-2262] - thrift server 'MutateRow' operation gives no indication of success / failure
+    * [THRIFT-2048] - Prefer boolean context to nullptr_t conversion
+    * [THRIFT-2528] - Thrift Erlang Library: Multiple thrift applications in one bundle
+    * [THRIFT-1999] - warning on gcc 4.7 while compiling BoostMutex.cpp
+    * [THRIFT-2104] - Structs lose binary data when transferred from server to client in Java
+    * [THRIFT-2184] - undefined method rspec_verify for Thrift::MemoryBufferTransport
+    * [THRIFT-2351] - PHP TCompactProtocol has fails to decode messages
+    * [THRIFT-2016] - Resource Leak in thrift struct under compiler/cpp/src/parse/t_function.h
+    * [THRIFT-2273] - Please delete old releases from mirroring system
+    * [THRIFT-2270] - Faulty library version numbering at build or documentation
+    * [THRIFT-2203] - Tests keeping failing on Jenkins and Travis CI
+    * [THRIFT-2399] - thrift.el: recognize "//"-style comments in emacs thrift-mode
+    * [THRIFT-2582] - "FileTransport error" exception is raised when trying to use Java's TFileTransport
+    * [THRIFT-1682] - Multiple thread calling a Service function unsafely causes message corruption and terminates with Broken Pipe
+    * [THRIFT-2357] - recurse option has no effect when generating php
+    * [THRIFT-2248] - Go generator doesn't deal well with map keys of type binary
+    * [THRIFT-2426] - clarify IP rights and contributions from fbthrift
+    * [THRIFT-2041] - TNonblocking server compilation on windows (ARITHMETIC_RIGHT_SHIFT)
+    * [THRIFT-2400] - thrift.el: recognize "//"-style comments in emacs thrift-mode
+    * [THRIFT-1717] - Fix deb build in jenkins
+    * [THRIFT-2266] - ThreadManager.h:24:10: fatal error: 'tr1/functional' file not found on Mac 10.9 (Mavericks)
+    * [THRIFT-1300] - Test failures with parallel builds (make -j)
+    * [THRIFT-2487] - Tutorial requires two IDL files but only one is linked from the Thrift web site
+    * [THRIFT-2329] - missing release tags within git
+    * [THRIFT-2306] - concurent client calls with nodejs
+    * [THRIFT-2222] - ruby gem cannot be compiled on OS X mavericks
+    * [THRIFT-2381] - code which generated by thrift2/hbase.thrift compile error
+    * [THRIFT-2390] - no close event when connection lost
+    * [THRIFT-2146] - Unable to pass multiple "--gen" options to the thrift compiler
+    * [THRIFT-2438] - Unexpected readFieldEnd call causes JSON Parsing errors
+    * [THRIFT-2498] - Error message "Invalid method name" while trying to call HBase Thrift API
+    * [THRIFT-841] - Build cruft
+    * [THRIFT-2570] - Wrong URL given in http://thrift.apache.org/developers
+    * [THRIFT-2604] - Fix debian packaging
+    * [THRIFT-2618] - Unignore /aclocal files required for build
+    * [THRIFT-2562] - ./configure create MakeFile in lib/d with errors
+    * [THRIFT-2593] - Unable to build thrift on ubuntu-12.04 (Precise)
+    * [THRIFT-2461] - Can't install thrift-0.8.0 on OS X 10.9.2
+    * [THRIFT-2602] - Fix missing dist files
+    * [THRIFT-2620] - Fix python packaging
+    * [THRIFT-2545] - Test CPP fails to build (possibly typo)
+
+## Documentation
+    * [THRIFT-2155] - Adding one liner guide to rename the version.h.in and rename thrifty.cc.h
+    * [THRIFT-1991] - Add exceptions to examples
+    * [THRIFT-2334] - add a tutorial for node JS
+    * [THRIFT-2392] - Actionscript tutorial
+    * [THRIFT-2383] - contrib: sample for connecting Thrift with Rebus
+    * [THRIFT-2382] - contrib: sample for connecting Thrift with STOMP
+
+## Improvement
+    * [THRIFT-1457] - Capacity of TframedTransport write buffer is never reset
+    * [THRIFT-1135] - Node.js tutorial
+    * [THRIFT-1371] - Socket timeouts (SO_RCVTIMEO and SO_SNDTIMEO) not supported on Solaris
+    * [THRIFT-2142] - Minor tweaks to thrift.el for better emacs package compatibility
+    * [THRIFT-2268] - Modify TSaslTransport to ignore TCP health checks from loadbalancers
+    * [THRIFT-2264] - GitHub page incorrectly states that Thrift is still incubating
+    * [THRIFT-2263] - Always generate good hashCode for Java
+    * [THRIFT-2233] - Java compiler should defensively copy its binary inputs
+    * [THRIFT-2239] - Address FindBugs errors
+    * [THRIFT-2249] - Add SMP Build option to thrift.spec (and three config defines)
+    * [THRIFT-2254] - Exceptions generated by Go compiler should implement error interface
+    * [THRIFT-2260] - Thrift imposes unneeded dependency on commons-lang3
+    * [THRIFT-2258] - Add TLS v1.1/1.2 support to TSSLSocket.cpp
+    * [THRIFT-2205] - Node.js Test Server to support test.js JavaScript Browser test and sundry fixes
+    * [THRIFT-2204] - SSL client for the cocoa client
+    * [THRIFT-2172] - Java compiler allocates optionals array for every struct with an optional field
+    * [THRIFT-2185] - use cabal instead of runhaskell in haskell library
+    * [THRIFT-1926] - PHP Constant Generation Refactoring
+    * [THRIFT-2029] - Port C++ tests to Windows
+    * [THRIFT-2054] - TSimpleFileTransport - Java Lib has no straight forward TTransport based file transport
+    * [THRIFT-2040] - "uninitialized variable" warnings on MSVC/windows
+    * [THRIFT-2034] - Give developers' C++ code direct access to socket FDs on server side
+    * [THRIFT-2095] - Use print function for Python 3 compatiblity
+    * [THRIFT-1868] - Make the TPC backlog configurable in the Java servers
+    * [THRIFT-1813] - Add @Generated annotation to generated classes
+    * [THRIFT-1815] - Code generators line buffer output
+    * [THRIFT-2305] - TFramedTransport empty constructor should probably be private
+    * [THRIFT-2304] - Move client assignments from construtor in method
+    * [THRIFT-2309] - Ruby (gem) & PHP RPM subpackages
+    * [THRIFT-2318] - perl: dependency Class::Accessor not checked
+    * [THRIFT-2317] - exclude tutorial from build
+    * [THRIFT-2320] - Program level doctext does not get attached by parser
+    * [THRIFT-2349] - Golang - improve tutorial
+    * [THRIFT-2348] - PHP Generator: add array typehint to functions
+    * [THRIFT-2344] - configure.ac: compiler-only option
+    * [THRIFT-2343] - Golang - Return a single error for all exceptions instead of multiple return values
+    * [THRIFT-2341] - Enable generation of Delphi XMLDoc comments (a.k.a. "Help Insight")
+    * [THRIFT-2355] - Add SSL and Web Socket Support to Node and JavaScript
+    * [THRIFT-2350] - Add async calls to normal JavaScript
+    * [THRIFT-2330] - Generate PHPDoc comments
+    * [THRIFT-2332] - RPMBUILD: run bootstrap (if needed)
+    * [THRIFT-2391] - simple socket transport for actionscript 3.0
+    * [THRIFT-2376] - nodejs: allow Promise style calls for client and server
+    * [THRIFT-2369] - Add ssl support for nodejs implementation
+    * [THRIFT-2401] - Haskell tutorial compiles
+    * [THRIFT-2417] - C# Union classes are not partial
+    * [THRIFT-2415] - Named pipes server performance & message mode
+    * [THRIFT-2404] - emit warning on (typically inefficient) list<byte>
+    * [THRIFT-2398] - Improve Node Server Library
+    * [THRIFT-2397] - Add CORS and CSP support for JavaScript and Node.js libraries
+    * [THRIFT-2407] - use markdown (rename README => README.md)
+    * [THRIFT-2300] - D configure info output should follow same format as other languages
+    * [THRIFT-2579] - Windows CE support
+    * [THRIFT-2574] - Compiler option to generate namespace directories for Ruby
+    * [THRIFT-2571] - Simplify cross compilation using CMake
+    * [THRIFT-2569] - Introduce file to specify third party library locations on Windows
+    * [THRIFT-2568] - Implement own certificate handler
+    * [THRIFT-2552] - eliminate warning from configure.ac
+    * [THRIFT-2549] - Generate json tag for struct members. use go.tag annotation to override the default generated tag.
+    * [THRIFT-2544] - Add support for socket transport for c# library when using Windows Phone projects
+    * [THRIFT-2453] - haskell tutorial: fix up division by 0 example
+    * [THRIFT-2449] - Enhance typedef structure to distinguish between forwards and real typedefs
+    * [THRIFT-2446] - There is no way to handle server stream errors
+    * [THRIFT-2455] - Allow client certificates to be used with THttpClient
+    * [THRIFT-2511] - Node.js needs the compact protocol
+    * [THRIFT-2493] - Node.js lib needs HTTP client
+    * [THRIFT-2502] - Optimize go implementations of binary and compact protocols for speed
+    * [THRIFT-2494] - Add enum toString helper function in c_glib
+    * [THRIFT-2471] - Make cpp.ref annotation language agnostic
+    * [THRIFT-2497] - server and client for test/go, also several fixes and improvements
+    * [THRIFT-2535] - TJSONProtocol when serialized yields TField ids rather than names
+    * [THRIFT-2220] - Add a new struct structv?
+    * [THRIFT-1352] - Thrift server
+    * [THRIFT-989] - Push boost m4 macros upstream
+    * [THRIFT-1349] - Remove unnecessary print outs
+    * [THRIFT-2496] - server and client for test/go, also several fixes and improvements
+    * [THRIFT-1114] - Maven publish shouldn't require passwords hardcoded in settings.xml
+    * [THRIFT-2043] - visual 2010 warnings - unreachable code
+    * [THRIFT-1683] - Implement alternatives to Javascript Client side Transport protocol, just as NPAPI and WebSocket.
+    * [THRIFT-1746] - provide a SPDX file
+    * [THRIFT-1772] - Serialization does not check types of embedded structures.
+    * [THRIFT-2387] - nodejs: external imports should be centralized in index.js
+    * [THRIFT-2037] - More general macro THRIFT_UNUSED_VARIABLE
+
+## New Feature
+    * [THRIFT-1012] - Transport for DataInput DataOutput interface
+    * [THRIFT-2256] - Using c++11/c++0x std library  replace boost library
+    * [THRIFT-2250] - JSON and MemoryBuffer for JavaME
+    * [THRIFT-2114] - Python Service Remote SSL Option
+    * [THRIFT-1719] - SASL client support for Python
+    * [THRIFT-1894] - Thrift multi-threaded async Java Server using Java 7 AsynchronousChannelGroup
+    * [THRIFT-1893] - HTTP/JSON server/client for node js
+    * [THRIFT-2347] - C# TLS Transport based on THRIFT-181
+    * [THRIFT-2377] - Allow addition of custom HTTP Headers to an HTTP Transport
+    * [THRIFT-2408] - Named Pipe Transport Option for C#
+    * [THRIFT-2572] - Add string/collection length limit checks (from C++) to java protocol readers
+    * [THRIFT-2469] - "java:fullcamel" option to automatically camel-case underscored attribute names
+    * [THRIFT-795] - Importing service functions (simulation multiple inheritance)
+    * [THRIFT-2164] - Add a Get/Post Http Server to Node along with examples
+    * [THRIFT-2255] - add Parent Class for generated Struct class
+
+## Question
+    * [THRIFT-2539] - Tsocket.cpp addrinfo ai_flags = AI_ADDRCONFIG
+    * [THRIFT-2440] - how to connect as3 to java by thrift ,
+    * [THRIFT-2379] - Memmory leaking while using multithreading in C++ server.
+    * [THRIFT-2277] - Thrift: installing fb303 error
+    * [THRIFT-2567] - Csharp slow ?
+    * [THRIFT-2573] - thrift 0.9.2 release
+
+## Sub-task
+    * [THRIFT-981] - cocoa: add version Info to the library
+    * [THRIFT-2132] - Go: Support for Multiplexing Services on any Transport, Protocol and Server
+    * [THRIFT-2299] - TJsonProtocol implementation for Ruby does not allow for both possible slash (solidus) encodings
+    * [THRIFT-2298] - TJsonProtocol implementation for C# does not allow for both possible slash (solidus) encodings
+    * [THRIFT-2297] - TJsonProtocol implementation for Delphi does not allow for both possible slash (solidus) encodings
+    * [THRIFT-2271] - JavaScript: Support for Multiplexing Services
+    * [THRIFT-2251] - go test for compact protocol is not running
+    * [THRIFT-2195] - Delphi: Add event handlers for server and processing events
+    * [THRIFT-2176] - TSimpleJSONProtocol.ReadFieldBegin() does not return field type and ID
+    * [THRIFT-2175] - Wrong field type set for binary
+    * [THRIFT-2174] - Deserializing JSON fails in specific cases
+    * [THRIFT-2053] - NodeJS: Support for Multiplexing Services
+    * [THRIFT-1914] - Python: Support for Multiplexing Services on any Transport, Protocol and Server
+    * [THRIFT-1810] - add ruby to test/test.sh
+    * [THRIFT-2310] - PHP: Client-side support for Multiplexing Services
+    * [THRIFT-2346] - C#: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol
+    * [THRIFT-2345] - Delphi: UTF-8 sent by PHP as JSON is not understood by TJsonProtocol
+    * [THRIFT-2338] - First doctext wrongly interpreted as program doctext in some cases
+    * [THRIFT-2325] - SSL test certificates
+    * [THRIFT-2358] - C++: add compact protocol to cross language test suite
+    * [THRIFT-2425] - PHP: Server-side support for Multiplexing Services
+    * [THRIFT-2421] - Tree/Recursive struct support in thrift
+    * [THRIFT-2290] - Update Go tutorial to align with THRIFT-2232
+    * [THRIFT-2558] - CSharp compiler generator tries to concat ints with strings using +
+    * [THRIFT-2507] - Additional LUA TProtocolException error code needed?
+    * [THRIFT-2499] - Compiler: allow annotations without "= value"
+    * [THRIFT-2534] - Cross language test results should recorded to a status.md or status.html file automatically
+    * [THRIFT-66] - Java: Allow multiplexing multiple services over a single TCP connection
+    * [THRIFT-1681] - Add Lua Support
+    * [THRIFT-1727] - Ruby-1.9: data loss: "binary" fields are re-encoded
+    * [THRIFT-1726] - Ruby-1.9: "binary" fields are represented by string whose encoding is "UTF-8"
+    * [THRIFT-988] - perl: add version Info to the library via configure
+    * [THRIFT-334] - Compact Protocol for PHP
+    * [THRIFT-2444] - pull request 88: thrift: clean up enum value assignment
+
+## Task
+    * [THRIFT-2223] - Spam links on wiki
+    * [THRIFT-2566] - Please create a DOAP file for your TLP
+    * [THRIFT-2237] - Update archive to contain all versions
+    * [THRIFT-962] - Tutorial page on our website is really unhelpful
+
+## Test
+    * [THRIFT-2327] - nodejs: nodejs test suite should be bundled with the library
+    * [THRIFT-2445] - THRIFT-2384 (code generation for go maps with binary keys) should be tested
+    * [THRIFT-2501] - C# The test parameters from the TestServer and TestClient are different from the http://thrift.apache.org/test/
+
+## Wish
+    * [THRIFT-2190] - Add the JavaScript thrift.js lib to the Bower registry
+    * [THRIFT-2076] - boost::optional instead of __isset
 
 
-Version 0.7.0
 
-THRIFT-1252   Ruby                 Segfault in Ruby deserializer
-THRIFT-940    Build                'make check' fails if boost is not in the std include and link paths (Christian Lavoie)
-THRIFT-1038   Java                 Generated Java code for structures containing binary fields are not serializable correctly
-THRIFT-1098   PHP                  Undefined properties in TBinaryProtocolFactory		
-THRIFT-1076   Erlang               Erlang Thrift socket server causes java framed client to throw ""out of sequence"" exception"		
-THRIFT-1171   Perl                 Perl write/readDouble assumes little-endian platform		
-THRIFT-151    C                    TSSLServerSocket and TSSLSocket implementation		
-THRIFT-1068   Python               Python SSL Socket Support		
-THRIFT-1011   AS3                  Error generating package imports when using classes from other packages		
-THRIFT-1069   Compiler (General)   Add command line option to prevent thrift from inserting gen-* directories		
-THRIFT-1055   C#                   csharp TServerSocket and TSocket do not disable Nagle via Socket.NoDelay = true like cpp and java do		
-THRIFT-638    PHP                  BufferedTransport + C extensions block until recv timeout is reached on last fread call		
-THRIFT-867    PHP                  PHP accelerator module's output transport is incompatible with TFramedTransport		
-THRIFT-1054                        explicit call to PKG_PROG_PKG_CONFIG is missing and first use of PKG_CHECK_MODULES may not happen
-THRIFT-125    OCaml                OCaml libraries don't compile with 32-bit ocaml		
-THRIFT-1200   JavaScript           JS compiler generates code that clobbers existing namespaces		
-THRIFT-1102   Build                "typo in configure.ac: ""=="" operator in 'test' (instead of""'="")"		
-THRIFT-994    Build                Don't try to invoke phpize if we don't have it		
-THRIFT-864    Compiler (General)   default value fails if identifier is a struct		
-THRIFT-1021   OCaml                Framed transport support for OCaml		
-THRIFT-1032                        make dist fails due to c_glib problem		
-THRIFT-1057   C++                  casts in TBinaryProtocol.tcc causing dereferencing type-punned pointer will break strict-aliasing rules
-THRIFT-1053   Java                 Make remote client's IP address available for all socket related transports		
-THRIFT-1036   C++                  "Auto-generated C++ code fails to compile with ""-Werror -Wextra -Wall"" g++ compiler flags"		
-THRIFT-1063   Tutorial             Fix Erlang Tutorial Files		
-THRIFT-625    Go                   Add support for 'Go'		
-THRIFT-1093   Python               several bugs in python TCompactProtocol		
-THRIFT-1101   Java                 bytebuffer length calculation in TBinaryProtocol writeBinary		
-THRIFT-1094   Python               bug in TCompactProto python readMessageEnd method and updated test cases		
-THRIFT-1100   Python               python TSSLSocket improvements, including certificate validation		
-THRIFT-1104   Build                INSTALLDIRS should be included in configure script		
-THRIFT-1103   Python               TZlibTransport for python, a zlib compressed transport		
-THRIFT-1105   OCaml                OCaml generator does not prefix methods of included structs with their type		
-THRIFT-1107   Python               improvement for compiler-generated python for 'None' object comparisons		
-THRIFT-1109   Java                 Deploy fb303 along side libthrift to maven repo		
-THRIFT-1111   Compiler (General)   The HTML generator does not distinguish between string and binary types		
-THRIFT-1074   Java                 .keystore and .truststore are missing from the 0.6.0 distribution		
-THRIFT-1119   C#                   TJSONProtocol fails to UTF8 decode strings		
-THRIFT-1120   C# - Compiler        proto.WriteListEnd being called in the wrong place		
-THRIFT-1126   Erlang               Extending struct_info for erlang bindings		
-THRIFT-1132   C#                   Deserialization error in TApplicationException C#		
-THRIFT-1131   C#                   C# JSON Protocol is unable to decode escaped characters in string		
-THRIFT-1133   Tutorial             Java and JavaScript tutorial is broken since we have Java maven deployment		
-THRIFT-1140   GlibC                Framed Transport Client using C (Glib) Library hangs when connecting to Ruby Server		
-THRIFT-342    PHP                  PHP: can't have sets of complex types		
-THRIFT-1149   Ruby                 Nonblocking server fails when client connection is reset		
-THRIFT-363    Java                 Maven Deploy		
-THRIFT-1155   Java				   Remove log4j dependency from java client		
-THRIFT-1170   Java                 Thrift Generated Code and Java 5		
-THRIFT-835    AS3                  Bad AS3 syntax in constructors that set default values		
-THRIFT-1174   Build                Publish as3 client implementation via Maven for use by flex-mojos users		
-THRIFT-1178   Java                 Java: TBase signature should be T extends TBase<?,?>		
-THRIFT-1067   PHP                  Tons of bugs in php implementation		
-THRIFT-1182   Ruby                 Native deserializer segfaults on incorrect list element type		
-THRIFT-1190   Java                 readBufferBytesAllocated in TNonblockingServer.java should be AtomicLong to fix FD leakage 
-THRIFT-1183   Ruby                 Pure-ruby CompactProtocol raises ArgumentError when deserializing under Ruby 1.9		
-THRIFT-1192                        Typo: TProtocol.h tests for HAVE_SYS_PARAM_H_		
-THRIFT-1194   Java                 Java lib does not install artifacts to local dir correctly		
-THRIFT-1208   Python               python TCompactProtocol.py writeBool and readBool not follow the compact-proto-spec-2.txt spec 
-THRIFT-1211   Java                 When using THttpClient, non 200 responses leave the connection open		
-THRIFT-627    C++                  should c++ have setters for optional fields?		
-THRIFT-1218   GLibC                c_glib uses wrong name in pkg-config		
-THRIFT-1189   Ruby                 Ruby deserializer speed improvements		
-THRIFT-1225   PHP                  TCompactProtocol for PHP		
-THRIFT-1227   Erlang               Erlang implementation of thrift JSON protocol		
-THRIFT-1228   PHP                  The php accelerator module calls flush incorrectly		
-THRIFT-1234   Python               thrift --help is missing doc on py:utf8strings		
-THRIFT-1237   Java                 Java fb303 missing some methods		
-THRIFT-1248   C++                  pointer subtraction in TMemoryBuffer relies on undefined behavior		
-THRIFT-1253   Java                 Code generated for maps is not compiling		
-THRIFT-1255   Java                 Mismatch of method name between JavaME's lib and generated code (compareTo/compareObjects)
-THRIFT-1238   JavaScript           Thrift JS client cannot read map of structures		
-THRIFT-1213                        Membuffer should provide a way to get back the buffer		
-THRIFT-1117   JavaScript           JavaScript Unit Test does fail due to libthrift*.jar where moved by Maven Deployment		
-THRIFT-1164   JavaScript           Segmentation fault on NULL pointer in t_js_generator::generate_const		
-THRIFT-788    PHP                  thrift_protocol.so: multiget/multiget_slice does not handle more than 17 keys correctly
-THRIFT-1222   C++                  Unhandled exception for TEvhttpServer request		
-THRIFT-1241   PHP                  php namespace generation		
-THRIFT-1236   Erlang               Erlang Reconnecting Thrift Client		
-THRIFT-1151   Erlang               Produce informative runtime error in case of schema and data mismatch on serialization
-THRIFT-1146   Java                 Android Incompatibility: Android < 2.3 java.io.IOException doesn't support for Throwable 
-THRIFT-826    PHP                  PHP TSocket Write Timeout		
-THRIFT-27     Erlang               Generated erlang types don't contain default values for records		
-THRIFT-1153   C++                  HttpClient does not specify the connection close parameter		
-THRIFT-1154   Cocoa                HttpClient does not specify the connection close parameter		
-THRIFT-1081   PHP                  PHP tests broken and somewhat incomplete		
-THRIFT-1078   Test Suite           ThriftTest.thrift generates invalid PHP library		
-THRIFT-447    Java                 Make an abstract base Client class so we can generate less code		
-THRIFT-1181   AS3                  AS3 compiler generates incorrect code for setting default values in constructor		
-THRIFT-997    Java                 Using valueOf for base types in getFieldValue		
-THRIFT-999    PHP                  Add TForkingServer		
-THRIFT-1041   Java                 TDeserializer holds onto a reference of the array it reads after it is done deserializing
-THRIFT-1065   JavaScript           Unexpected exceptions not proper handled on JS		
-THRIFT-993    C++                  Some improvements in C++ stubs for oneway operations		
-THRIFT-1083   Python               Preforking python process pool server		
-THRIFT-1092   Python               generated validate() method has wrong indentation		
-THRIFT-1050   Java                 "Declaring an argument named ""manager"" to a service method produces code that fails compile 
-THRIFT-1106   C++                  C++ code TAsyncProtocolProcessor.h & TAsyncBufferProcessor.h dont have virtual functions 
-THRIFT-1080   Erlang               erlang test's 'make' fails on Mac OSX		
-THRIFT-731    Java                 configure doesn't check for ant >= 1.7		
-THRIFT-1180   AS3                  AS3 compiler generates uncompilable code for binary types.		
-THRIFT-1187   Ruby                 nonblocking_server shutdown race under Ruby 1.9		
-THRIFT-1193   Ruby                 Potential infinite loop in nonblocking_server		
-THRIFT-891    Compiler (General)   Comments are not properly handled in some cases		
-THRIFT-1216   Java                 build Java Library behind a proxy		
-THRIFT-1177   Go                   Update thrift to reflect changes in Go's networking libraries		
-THRIFT-1220   C++                  TProcessor::process never returns false		
-THRIFT-1231   C++                  Remove bogus include		
-THRIFT-1217   C++                  Use evutil_socketpair instead of pipe (Windows port)		
-THRIFT-1215   JavaScript           Undefined property Thirft in lib/js/thrift.js		
-THRIFT-418    Ruby                 Don't do runtime sorting of struct fields		
-THRIFT-1244   C++                  'using' to disambiguate between functions in different bases does not conform to C++ standard
-THRIFT-892    Erlang               Refactor erlang build system with rebar		
-THRIFT-690    Compiler (General)   Update TApplicationException codes		
-THRIFT-1199   Java                 Union structs should have generated methods to test whether a specific field is currently set		
-THRIFT-113    Compiler (General)   to-string methods should omit optional null fields from output		
-THRIFT-1049   Python               Allow for TServerSocket python library to bind to a specific host		
-THRIFT-1152   PHP                  THRIFT-1144 Attributes from private to protected		
-THRIFT-1207   Ruby                 "Support DESTDIR on ""make install"" of ruby libs"		
-THRIFT-1123   C++                  Patch to compile Thrift server and client for vc++ 9.0 and 10.0		
-THRIFT-1031   C++                  Patch to compile Thrift for vc++ 9.0 and 10.0		
-THRIFT-1221   C++                  Remove SimpleCallback.h		
-THRIFT-1233   C++                  Remove unused include in generated C++ code		
-THRIFT-1246   Java                 Improve logging: Change TNonblockingServer internalRead to trace from warn		
-THRIFT-1251   Java                 Generated java code should indicate which fields are required and which are optional
+Thrift 0.9.1
+--------------------------------------------------------------------------------
+## Bug
+    * [THRIFT-1440] - debian packaging: minor-ish policy problems
+    * [THRIFT-1402] - Generated Y_types.js does not require() X_types.js when an include in the IDL file was used
+    * [THRIFT-1551] - 2 thrift file define only struct (no service), one include another, the gen nodejs file didn't have "requires" at the top
+    * [THRIFT-1264] - TSocketClient is queried by run loop after deallocation in Cocoa
+    * [THRIFT-1600] - Thrift Go Compiler and Library out of date with Go 1 Release.
+    * [THRIFT-1603] - Thrift IDL allows for multiple exceptions, args or struct member names to be the same
+    * [THRIFT-1062] - Problems with python tutorials
+    * [THRIFT-864] - default value fails if identifier is a struct
+    * [THRIFT-930] - Ruby and Haskell bindings don't properly support DESTDIR (makes packaging painful)
+    * [THRIFT-820] - The readLength attribute of TBinaryProtocol is used as an instance variable and is decremented on each call of checkReadLength
+    * [THRIFT-1640] - None of the tutorials linked on the website contain content
+    * [THRIFT-1637] - NPM registry does not include version 0.8
+    * [THRIFT-1648] - NodeJS clients always receive 0 for 'double' values.
+    * [THRIFT-1660] - Python Thrift library can be installed with pip but not easy_install
+    * [THRIFT-1657] - Chrome browser sending OPTIONS method before POST in xmlHttpRequest
+    * [THRIFT-2118] - Certificate error handling still incorrect
+    * [THRIFT-2137] - Ruby test lib fails jenkins build #864
+    * [THRIFT-2136] - Vagrant build not compiling java, ruby, php, go libs due to missing dependencies
+    * [THRIFT-2135] - GO lib leaves behind test files that are auto generated
+    * [THRIFT-2134] - mingw-cross-compile script failing with strip errors
+    * [THRIFT-2133] - java TestTBinaryProtocol.java test failing
+    * [THRIFT-2126] - lib/cpp/src/thrift/concurrency/STD* files missing from DIST
+    * [THRIFT-2125] - debian missing from DIST
+    * [THRIFT-2124] - .o, .so, .la, .deps, .libs, gen-* files left tutorials, test and lib/cpp when making DIST
+    * [THRIFT-2123] - GO lib missing files in DIST build
+    * [THRIFT-2121] - Compilation bug for Node.js
+    * [THRIFT-2129] - php ext missing from dist
+    * [THRIFT-2128] - lib GO tests fail with funct ends without a return statement
+    * [THRIFT-2286] - Failed to compile Thrift0.9.1 with boost1.55 by VS2010 if select Debug-mt&x64 mode.
+    * [THRIFT-1973] - TCompactProtocol in C# lib does not serialize and deserialize negative int32 and int64 number correctly
+    * [THRIFT-1992] - casts in TCompactProtocol.tcc causing "dereferencing type-punned pointer will break strict-aliasing rules" warnings from gcc
+    * [THRIFT-1930] - C# generates unsigned byte for Thrift "byte" type
+    * [THRIFT-1929] - Update website to use Mirrors for downloads
+    * [THRIFT-1928] - Race may still exist in TFileTransport::flush()
+    * [THRIFT-1934] - Tabs in Example section on main page are not working
+    * [THRIFT-1933] - Delphi generator crashes when a typedef references another typedef from an included file
+    * [THRIFT-1942] - Binary accelerated cpp extension does not use Thrift namespaces for Exceptions
+    * [THRIFT-1959] - C#: Add Union TMemoryBuffer support
+    * [THRIFT-1958] - C#: Use static Object.Equals instead of .Equals() calls in equals
+    * [THRIFT-1957] - NodeJS TFramedTransport and TBufferedTransport read bytes as unsigned
+    * [THRIFT-1955] - Union Type writer generated in C# does not WriteStructBegin
+    * [THRIFT-1952] - Travis CI
+    * [THRIFT-1949] - WP7 build broken
+    * [THRIFT-1943] - docstrings for enum values are ignored
+    * [THRIFT-2070] - Improper `HexChar' and 'HexVal' implementation in TJSONProtocol.cs
+    * [THRIFT-2017] - Resource Leak in thrift struct under compiler/cpp/src/parse/t_program.h
+    * [THRIFT-2032] - C# client leaks sockets/handles
+    * [THRIFT-1996] - JavaME Constants generation is broken / inconsistent with regular Java generation
+    * [THRIFT-2002] - Haskell: Test use Data.Maybe instead of Maybe
+    * [THRIFT-2051] - Vagrant fails to build erlang
+    * [THRIFT-2050] - Vagrant C# lib compile fails with TException missing
+    * [THRIFT-1978] - Ruby: Thrift should allow for the SSL verify mode to be set
+    * [THRIFT-1984] - namespace collision in python bindings
+    * [THRIFT-1988] - When trying to build a debian package it fails as the file NEWS doesn't exist
+    * [THRIFT-1975] - TBinaryProtocol CheckLength can't be used for a client
+    * [THRIFT-1995] - '.' allowed at end of identifier generates non-compilable code
+    * [THRIFT-2112] - Error in Go generator when using typedefs in map keys
+    * [THRIFT-2088] - Typos in Thrift compiler help text
+    * [THRIFT-2080] - C# multiplex processor does not catch IOException
+    * [THRIFT-2082] - Executing "gmake clean" is broken
+    * [THRIFT-2102] - constants are not referencing to correct type when included from another thrift file
+    * [THRIFT-2100] - typedefs are not correctly referenced when including from other thrift files
+    * [THRIFT-2066] - 'make install' does not install two headers required for C++ bindings
+    * [THRIFT-2065] - Not valid constants filename in Java
+    * [THRIFT-2047] - Thrift.Protocol.TCompactProtocol, intToZigZag data lost (TCompactProtocol.cs)
+    * [THRIFT-2036] - Thrift gem warns about class variable access from top level
+    * [THRIFT-2057] - Vagrant fails on php tests
+    * [THRIFT-2105] - Generated code for default values of collections ignores t_field::T_REQUIRED
+    * [THRIFT-2091] - Unnecessary 'friend' declaration causes warning in TWinsockSingleton
+    * [THRIFT-2090] - Go generator, fix including of other thrift files
+    * [THRIFT-2106] - Fix support for namespaces in GO generator
+    * [THRIFT-1783] - C# doesn't handle required fields correctly
+    * [THRIFT-1782] - async only defined in silverlight
+    * [THRIFT-1779] - Missing process_XXXX method in generated TProcessor implementation for all 'oneway' service functions
+    * [THRIFT-1692] - SO_REUSEADDR allows for socket hijacking on Windows
+    * [THRIFT-1720] - JRuby times out on successful connection
+    * [THRIFT-1713] - Named and Anonymous Pipe transport (Delphi)
+    * [THRIFT-1699] - Native Union#read has extra read_field_end call
+    * [THRIFT-1749] - Python TSSLSocket error handling obscures actual error
+    * [THRIFT-1748] - Guard and RWGuard macros defined in global namespace
+    * [THRIFT-1734] - Front webpage is still advertising v0.8 as current release
+    * [THRIFT-1729] - C glib refactor left empty folders in svn
+    * [THRIFT-1767] - unions can't have required fields (Delphi)
+    * [THRIFT-1765] - Incorrect error message printed for null or negative keys
+    * [THRIFT-1778] - Configure requires manual intervention due to tar failure
+    * [THRIFT-1777] - TPipeServer is UNSTOPPABLE
+    * [THRIFT-1753] - Multiple C++ Windows, OSX, and iOS portability issues
+    * [THRIFT-1756] - 'make -j 8' fails with "unterminated #ifdef" error
+    * [THRIFT-1773] - Python library should run on python 2.4
+    * [THRIFT-1769] - unions can't have required fields (C++)
+    * [THRIFT-1768] - unions can't have required fields (Compiler)
+    * [THRIFT-1666] - htonll usage in TBinaryProtocol.tcc generates warning with MSVC2010
+    * [THRIFT-1919] - libthrift depends on httpcore-4.1.3 (directly) and httpcore-4.1.4 (transitively)
+    * [THRIFT-1864] - implement event handler for non-blocking server
+    * [THRIFT-1859] - Generated error c++ code with -out and include_prefix param
+    * [THRIFT-1869] - TThreadPoolServer (java) dies when threadpool is consumed
+    * [THRIFT-1842] - Memory leak with Pipes
+    * [THRIFT-1838] - Can't build compiler on OS X because of missing thrifty.h
+    * [THRIFT-1846] - Restore socket.h header to support builds with Android NDK
+    * [THRIFT-1850] - make check hangs on TSocket tests in TransportTest.cpp
+    * [THRIFT-1873] - Binary protocol factory ignores struct read/write flags
+    * [THRIFT-1872] - issues with TBufferedTransport buffer
+    * [THRIFT-1904] - Incorrect code is generated for typedefs which use included types
+    * [THRIFT-1903] - PHP namespaces cause binary protocols to not be used
+    * [THRIFT-1895] - Delphi: reserved variable name "result" not detected properly
+    * [THRIFT-1881] - TNonblockingServer does not release open connections or threads on shutdown
+    * [THRIFT-1888] - Java Thrift client can't connect to Python Thrift server on same host
+    * [THRIFT-1831] - Bug in list deserializer
+    * [THRIFT-1824] - many compile warning, becase Thread.h includes config.h
+    * [THRIFT-1823] - Missing parenthesis breaks "IS_..." macro in generated code
+    * [THRIFT-1806] - Python generation always truncates __init__.py files
+    * [THRIFT-1795] - Race condition in TThreadedServerPool java implementation
+    * [THRIFT-1794] - C# asyncctp broken
+    * [THRIFT-1804] - Binary+compact protocol single byte error in Ruby library (ARM architecture): caused by different char signedness
+    * [THRIFT-1800] - Documentation text not always escaped correctly when rendered to HTML
+    * [THRIFT-1788] - C#: Constants static constructor does not compile
+    * [THRIFT-1816] - Need "require" included thrift files in "xxx_types.js"
+    * [THRIFT-1907] - Compiling namespace and sub-namespace directives for unrecognized generators should only be a warning
+    * [THRIFT-1913] - skipping unknown fields in java unions
+    * [THRIFT-2553] - C++ linker error - transport/TSocket
+    * [THRIFT-274] - Towards a working release/versioning process
+
+## Documentation
+    * [THRIFT-1971] - [Graphviz] Adds tutorial/general description documentation
+    * [THRIFT-2001] - http://thrift.apache.org/ Example "C++ Server" tab is broken
+
+## Improvement
+    * [THRIFT-1574] - Apache project branding requirements: DOAP file [PATCH]
+    * [THRIFT-1347] - Unify the exceptions returned in generated Go code
+    * [THRIFT-1353] - Switch to performance branch, get rid of BinaryParser
+    * [THRIFT-1629] - Ruby 1.9 Compatibility during Thrift configure, make, install
+    * [THRIFT-991] - Refactor Haskell code and generator
+    * [THRIFT-990] - Sanify gettimeofday usage codebase-wide
+    * [THRIFT-791] - Let C++ TSimpleServer be driven by an external main loop
+    * [THRIFT-2117] - Cocoa TBinaryProtocol strictWrite should be set to true by default
+    * [THRIFT-2014] - Change C++ lib includes to use <namespace/> style throughout
+    * [THRIFT-1972] - Add support for async processors
+    * [THRIFT-1970] - [Graphviz] Adds option to render exceptions relationships
+    * [THRIFT-1966] - Support different files for SSL certificates and keys
+    * [THRIFT-1965] - Adds Graphviz (graph description language) generator
+    * [THRIFT-1956] - Switch to Apache Commons Lang 3
+    * [THRIFT-1962] - Multiplex processor should send any TApplicationException back to client
+    * [THRIFT-1960] - main() declares 22 unused gen bools
+    * [THRIFT-1951] - libthrift.jar has source files in it
+    * [THRIFT-1997] - Add accept backlog configuration method to  TServerSocket
+    * [THRIFT-2003] - Deprecate senum
+    * [THRIFT-2052] - Vagrant machine image defaults to only 384MB of RAM
+    * [THRIFT-1980] - Modernize Go tooling, fix go client libary.
+    * [THRIFT-1977] - C# compiler should generate constant files prefixed with thrift file name
+    * [THRIFT-1985] - add a Vagrantfile to build and test Apache Thrift fully reproducable
+    * [THRIFT-1994] - Deprecate slist
+    * [THRIFT-1993] - Factory to create instances from known (generated) interface types with Delphi
+    * [THRIFT-2081] - Specified timeout should be used in TSocket.Open()
+    * [THRIFT-2084] - Delphi: Ability to create entity Thrift-generated instances based on TypeInfo
+    * [THRIFT-2083] - Improve the go lib: buffered Transport, save memory allocation, handle concurrent request
+    * [THRIFT-2109] - Secure connections should be supported in Go
+    * [THRIFT-2107] - minor Go generator fixes
+    * [THRIFT-1695] - allow warning-free compilation in VS 2012 and GNU 4.6
+    * [THRIFT-1735] - integrate tutorial into regular build
+    * [THRIFT-1716] - max allowed connections should be PIPE_UNLIMITED_INSTANCES
+    * [THRIFT-1715] - Allow excluding python parts when building contrib/fb303
+    * [THRIFT-1733] - Fix RPM build issues on RHEL6/OL6 systems
+    * [THRIFT-1728] - Upgradation of httpcomponents
+    * [THRIFT-1876] - Use enum names instead of casted integers in assignments
+    * [THRIFT-1874] - timeout for the server-side end of a named pipe
+    * [THRIFT-1897] - Support validation of required fields
+    * [THRIFT-1896] - Add TBase protocol for Cocoa
+    * [THRIFT-1880] - Make named pipes server work asynchronously (overlapped) to allow for clean server stops
+    * [THRIFT-1878] - Add the possibility to send custom headers
+    * [THRIFT-1882] - Use single include
+    * [THRIFT-1793] - C#: Use static read instead of instance read
+    * [THRIFT-1799] - Option to generate HTML in "standalone mode"
+    * [THRIFT-1815] - Code generators line buffer output
+    * [THRIFT-1890] - C++: Make named pipes server work asynchronously
+    * [THRIFT-474] - Generating Ruby on Rails friendly code
+
+## New Feature
+    * [THRIFT-801] - Provide an interactive shell (irb) when generating ruby bindings
+    * [THRIFT-2292] - Android Library Project
+    * [THRIFT-2012] - Modernizing Go
+    * [THRIFT-1969] - C#: Tests not properly linked from the solution
+    * [THRIFT-1785] - C#: Add TMemoryBuffer serializer/deserializer
+    * [THRIFT-1780] - Add option to generate nullable values
+    * [THRIFT-1786] - C# Union Typing
+    * [THRIFT-591] - Make the C++ runtime library be compatible with Windows and Visual Studio
+    * [THRIFT-514] - Add option to configure compiler output directory
+
+## Question
+    * [THRIFT-1764] - how to get the context of client when on a rpc call in server side?
+    * [THRIFT-1791] - thrift's namespace directive when generating haskell code
+
+## Sub-task
+    * [THRIFT-1594] - Java test clients should have a return codes that reflect whether it succeeds or not.
+    * [THRIFT-1595] - Java test server should follow the documented behavior as of THRIFT-1590
+    * [THRIFT-986] - st: add version Info to the library
+    * [THRIFT-985] - php: add version Info to the library
+    * [THRIFT-984] - ocaml: add version Info to the library
+    * [THRIFT-1924] - Delphi: Inconsistency in serialization of optional fields
+    * [THRIFT-1922] - C#: Inconsistency in serialization of optional fields
+    * [THRIFT-1961] - C# tests should be in lib/csharp/test/...
+    * [THRIFT-1822] - PHP unit test does not work
+    * [THRIFT-1902] - C++: Support for Multiplexing Services on any Transport, Protocol and Server
+    * [THRIFT-1901] - C#: Support for Multiplexing Services on any Transport, Protocol and Server
+    * [THRIFT-1899] - Delphi: Support for Multiplexing Services on any Transport, Protocol and Server
+    * [THRIFT-563] - Support for Multiplexing Services on any Transport, Protocol and Server
 
 
-Version 0.6.0
 
-THRIFT-940    Build                'make check' fails if boost is not in the std include and link paths (Christian Lavoie)
-THRIFT-1032   Build                "make dist" fails due to c_glib problem (Michael Lum)
-THRIFT-1002   C glib               CodeStyle: t_c_glib_generator.cc (Anatol Pomozov)
-THRIFT-975    C glib               lib/c_glib/README is missing => breaks make dist (Michael Lum)
-THRIFT-1003   C glib               Polishing c_glib code (Anatol Pomozov)
-THRIFT-582    C glib               C implementation of Thrift (Anatol Pomozov)
-THRIFT-992    C#                   Naming convention in C# constructor is not consistent with other fields causes compile errors (Roger Meier)
-THRIFT-977    C++                  Hex Conversion Bug in C++ TJSONProtocol (Aravind Narayanan)
-THRIFT-922    C++                  Templatized [de]serialization code for C++ (David Reiss)
-THRIFT-923    C++                  Event-driven client and server support for C++ (David Reiss)
-THRIFT-925    C++                  Provide name<->value map for enums in C++ (David Reiss)
-THRIFT-926    C++                  Miscellaneous C++ improvements (David Reiss)
-THRIFT-928    C++                  Make more statistics available in C++ servers (David Reiss)
-THRIFT-929    C++                  Improvements to the C++ test suite (David Reiss)
-THRIFT-868    Compiler (General)   Referencing constant values doesn't work with with typedef types (David Reiss)
-THRIFT-1006   General              Impossible to correctly qualify an enum constant in an external thrift file (Bryan Duxbury)
-THRIFT-932    Haskell              Haskell tests need to be run through 'make check' (and probably 'cabal check') too (Christian Lavoie)
-THRIFT-933    Haskell              Haskell's Thrift.cabal has warnings (Christian Lavoie)
-THRIFT-943    Haskell              Silly readme typo fix. (Christian Lavoie)
-THRIFT-944    Haskell              Support all version-4s of base (Christian Lavoie)
-THRIFT-950    Haskell              Haskell bindings treat 'byte' as unsigned 8-bit int (Data.Word.Word8), java/cpp as signed (byte/int8_t). (Christian Lavoie)
-THRIFT-1009   Java                 TUnion does not correctly deep copy a ByteBuffer (Takashi Yonebayashi)
-THRIFT-1013   Java                 generated java code may have name clashes with thrift library (Peter Schuller)
-THRIFT-1015   Java                 TUnion does not handle ByteBuffer in toString (Takashi Yonebayashi)
-THRIFT-1038   Java                 Generated Java code for structures containing binary fields (or collections thereof) are not serializable (in the Java sense) even though they implement java.io.Serializable (Mathias Herberts)
-THRIFT-106    Java                 TSSLServerSocket (Nirmal Ranganathan)
-THRIFT-377    Java                 TFileTransport port in Java (Joydeep Sen Sarma)
-THRIFT-745    Java                 Make it easier to instantiate servers (Bryan Duxbury)
-THRIFT-862    Java                 Async client issues / improvements (Ning Liang)
-THRIFT-903    Java                 custom ThreadFactory in THsHaServer (Bryan Duxbury)
-THRIFT-939    Java                 optional binary fields throw NPE on default byte[] getters (Bryan Duxbury)
-THRIFT-947    Java                 Provide a helper method to determine the TProtocol used to serialize some data. (Mathias Herberts)
-THRIFT-951    Java                 Add a new isServing() method to TServer (Bryan Duxbury)
-THRIFT-957    Java                 THsHaServer: Change access modifier of the invoker field. (Benjamin Coverston)
-THRIFT-958    Java                 Change accessmodifer on trans_ field in the FrameBuffer class to public. (Benjamin Coverston)
-THRIFT-959    Java                 TSocket seems to do its own buffering inefficiently (Bryan Duxbury)
-THRIFT-970    Java                 Under heavy load, THttpClient may fail with "too many open files" (Mathias Herberts)
-THRIFT-971    Java                 java module can't be compiled without ivy and network connection (Roger Meier)
-THRIFT-807    JavaScript           JavaScript: Initialization of Base Types with 0 instead of null (Roger Meier)
-THRIFT-913    JavaScript           Test Case for Url encoded strings + simple enhancement to lib/js/test/RunTestServer.sh (Roger Meier)
-THRIFT-961    JavaScript           JavaScript TestSuite using ant/ivy and Java's ServerTestBase Handler (Roger Meier)
-THRIFT-1005   Java                 Give unions byte[] signature methods to go along with their ByteBuffer counterparts (Bryan Duxbury)
-THRIFT-1008   Java                 byte[] accessors throw NPE on unset field (Bryan Duxbury)
-THRIFT-517    Java                 TExceptions thrown by server result in cryptic error message on client - Tried to read 4 bytes, but only got 0 bytes (Bryan Duxbury)
-THRIFT-946    Java                 Augment FieldValueMetaData so it differentiates 'string' and 'binary' fields. (Mathias Herberts)
-THRIFT-949    Java                 Modify the TEnum interface so it defines a method similar to findByValue (Mathias Herberts)
-THRIFT-960    Java                 add TestServer, TestNonblockingServer and TestClient again (Roger Meier)
-THRIFT-969    Java                 Java Tutorial broken, move CalculatorHandler to a separate file (Roger Meier)
-THRIFT-71     Misc                 Debian packaging for thrift (Roger Meier)
-THRIFT-1020   OCaml                OCaml compiler generates invalid OCaml (Richard Low)
-THRIFT-347    PHP                  PHP TSocket Timeout Issues (Tyler Hobbs)
-THRIFT-924    PHP                  Fix generated php structure constants (David Reiss)
-THRIFT-927    PHP                  Add option to modify the PHP include path (David Reiss)
-THRIFT-935    PHP                  PHP Extension aborts the build if php-config is not installed (David Reiss)
-THRIFT-941    PHP                  Make PHP C Extension use the defined Protocol writeMessageBegin function (Chris Goffinet)
-THRIFT-955    PHP                  Thrift compiler for Windows uses lowercase names and directories which is inconsistent with compiling on other platforms (Roger Meier)
-THRIFT-979    Ruby                 ruby bindings used to work on jruby (Jeff Hodges)
-THRIFT-581    Test Suite           Add a testsuite for txThrift (Twisted) (Esteve Fernandez)
-THRIFT-1024   Tutorial             Add Python Twisted example to the Tutorial (Roger Meier)
-THRIFT-893    Tutorial             add JavaScript to the tutorial examples (Roger Meier)
+Thrift 0.9
+--------------------------------------------------------------------------------
+## Bug
+    * [THRIFT-1438] - lib/cpp/src/windows/config.h should read version from configure.ac rather than a #define
+    * [THRIFT-1446] - Compile error with Delphi 2009 in constant initializer
+    * [THRIFT-1450] - Problems building thrift 0.8.0 for Python and Ruby
+    * [THRIFT-1449] - Ruby client does not work on solaris (?)
+    * [THRIFT-1447] - NullpointerException in ProcessFunction.class :in "oneway" method
+    * [THRIFT-1433] - TServerSocket fix for MSVC
+    * [THRIFT-1429] - The nonblocking servers is supposed to use TransportFactory to read the data
+    * [THRIFT-1427] - PHP library uses non-multibyte safe functions with mbstring function overloading
+    * [THRIFT-1421] - Debian Packages can not be built
+    * [THRIFT-1394] - Treatment of optional fields is not consistent between C++ and Java
+    * [THRIFT-1511] - Server with oneway support ( JAVA )
+    * [THRIFT-1496] - PHP compiler not namespacing enums
+    * [THRIFT-1495] - PHP TestClient fatals on missing class
+    * [THRIFT-1508] - TServerSocket does not allow for the user to specify the IP address to bind to
+    * [THRIFT-1504] - Cocoa Generator should use local file imports for base Thrift headers
+    * [THRIFT-1512] - Thrift socket support for Windows XP
+    * [THRIFT-1502] - TSimpleServer::serve(): Do not print out error message if server was stopped.
+    * [THRIFT-1501] - PHP old namespaces not generated for enums
+    * [THRIFT-1483] - java compiler does not generate type parameters for services in extended clauses
+    * [THRIFT-1479] - Compiled PHP process functions missing writeMessageEnd()
+    * [THRIFT-1492] - enabling c_glib render thrift unusable (even for C++ code)
+    * [THRIFT-1491] - Uninitialize processorFactory_ member in TServer.h
+    * [THRIFT-1475] - Incomplete records generation for Erlang
+    * [THRIFT-1486] - Javascript manual testserver not returning content types
+    * [THRIFT-1488] - src/concurrency/Thread.h:91:58: error: invalid conversion from 'pthread_t {aka _opaque_pthread_t*}' to 'apache::thrift::concurrency::Thread::id_t {aka long long unsigned int}' [-fpermissive]
+    * [THRIFT-1490] - Windows-specific header files - fixes & tweaks
+    * [THRIFT-1526] - Union TupleSchemeFactory returns StandardSchemes
+    * [THRIFT-1527] - Generated implementation of tupleReadStruct in unions return null when the setfield is unrecognized
+    * [THRIFT-1524] - TNonBlockingServer does not compile in Visual Studio 2010
+    * [THRIFT-1529] - TupleProtocol can unintentionally include an extra byte in bit vectors when number of optional fields is an integral of 8
+    * [THRIFT-1473] - JSON context stack may be left in an incorrect state when an exception is thrown during read or write operations
+    * [THRIFT-1456] - System.Net.HttpWebRequest' does not contain a definition for 'Proxy'
+    * [THRIFT-1468] - Memory leak in TSaslServerTransport
+    * [THRIFT-1461] - Recent TNonblockingServer changes broke --enable-boostthreads=yes, Windows
+    * [THRIFT-1460] - why not add unicode strings support to python directly?
+    * [THRIFT-1464] - AbstractNonblockingServer.FrameBuffer TNonblockingTransport accessor changed from public to private
+    * [THRIFT-1467] - Possible AV with empty strings when using JSON protocol
+    * [THRIFT-1523] - clientTimeout not worked as expected in TServerSocket created by TSSLTransportFactory
+    * [THRIFT-1537] - TFramedTransport issues
+    * [THRIFT-1519] - Thirft Build Failure referencing rb_intern2 symbol
+    * [THRIFT-1518] - Generated C++ code only sends the first optional field in the write() function for a struct.
+    * [THRIFT-1515] - NameError: global name 'TApplicationException' is not defined
+    * [THRIFT-1554] - Inherited service methods are not resolved in derived service implementations
+    * [THRIFT-1553] - thrift nodejs service side can't read map structure, key as enum, value as Object
+    * [THRIFT-1575] - Typo in server/TThreadPoolServer.h
+    * [THRIFT-1327] - Fix Spec Suite under Ruby-1.8.7 (works for MRI Ruby-1.9.2)
+    * [THRIFT-1326] - on some platforms, #include <stdint.h> is necessary to be included in Thrift.h
+    * [THRIFT-1159] - THttpClient->Flush() issue (connection thru proxy)
+    * [THRIFT-1277] - Node.js serializes false booleans as null
+    * [THRIFT-1224] - Cannot insert UTF-8 text
+    * [THRIFT-1267] - Node.js can't throw exceptions.
+    * [THRIFT-1338] - Do not use an unpatched autoconf 2.65 to generate release tarball
+    * [THRIFT-1128] - MAC OS X: thrift.h incompatibility with Thrift.h
+    * [THRIFT-1631] - Fix C++ server constructor typos
+    * [THRIFT-1602] - PHP C Extension is not Compatible with PHP 5.4
+    * [THRIFT-1610] - IWebProxy not available on WP7 platform
+    * [THRIFT-1606] - Race condition in BoostThreadFactory.cpp
+    * [THRIFT-1604] - Python exception handeling for changes from PEP 3110
+    * [THRIFT-1607] - Incorrect file modes for several source files
+    * [THRIFT-1583] - c_glib leaks memory
+    * [THRIFT-1582] - Bad includes of nested thrift files in c_glib
+    * [THRIFT-1578] - C_GLib generated code does not compile
+    * [THRIFT-1597] - TJSONProtocol.php is missing from Makefile.am
+    * [THRIFT-1591] - Enable TCP_NODELAY for ruby gem
+    * [THRIFT-1624] - Isset Generated differently on different platforms
+    * [THRIFT-1622] - Incorrect size returned on read
+    * [THRIFT-1621] - Memory leaks
+    * [THRIFT-1612] - Base64 encoding is broken
+    * [THRIFT-1627] - compiler built using compilers.vcxproj cannot be used to build some test .thrift files
+    * [THRIFT-1571] - Update Ruby HTTP transport for recent Ruby versions
+    * [THRIFT-1023] - Thrift encoding  (UTF-8) issue with Ruby 1.9.2
+    * [THRIFT-1090] - Document the generation of a file called "Constants.java"
+    * [THRIFT-1082] - Thrift::FramedTransport sometimes calls close() on an undefined value
+    * [THRIFT-956] - Python module's version meta-data should be updated
+    * [THRIFT-973] - Cocoa library won't compile using clang
+    * [THRIFT-1632] - ruby: data corruption in thrift_native implementation of MemoryBufferTransport
+    * [THRIFT-1665] - TBinaryProtocol: exceeded message length raises generic TException
+    * [THRIFT-1664] - Reference to non-existing variable in build script
+    * [THRIFT-1663] - Java Thrift server is not throwing exceptions
+    * [THRIFT-1662] - "removeObject:" should be "removeObserver:" in [-TSocketServer dealloc]?
+    * [THRIFT-1643] - Denial of Service attack in TBinaryProtocol.readString
+    * [THRIFT-1674] - Update Thrift D library to be compatible with 2.060
+    * [THRIFT-1673] - Ruby compile flags for extension for multi arch builds (os x)
+    * [THRIFT-1655] - Configure still trying to use thrift_generators in output
+    * [THRIFT-1654] - c_glib thrift_socket_read() returns corrupted data
+    * [THRIFT-1653] - TThreadedSelectorServer leaks CLOSE_WAIT sockets
+    * [THRIFT-1658] - Java thrift server is not throwing TApplicationException
+    * [THRIFT-1656] - Setting proper headers in THttpServer.cpp so that "Cross-Origin Resource Sharing" on js client can work.
+    * [THRIFT-1652] - TSaslTransport does not log the error when kerberos auth fails
+    * [THRIFT-2272] - CLONE - Denial of Service attack in TBinaryProtocol.readString
+    * [THRIFT-2086] - Invalid generated code for Node.JS when using namespaces
+    * [THRIFT-1686] - t_php_generator.cc uses "and" instead of "&&", and causes compiler errors with Visual Studio
+    * [THRIFT-1693] - libthrift has dependency on two different versions of httpcore
+    * [THRIFT-1689] - don't exit(-1) in TNonblockingServer
+    * [THRIFT-1679] - NodeJS: protocol readString() should treat string as utf8, not binary
+    * [THRIFT-1721] - Dist broken due to 0.8.0 to 0.9.0 changes
+    * [THRIFT-1710] - Minor issues in test case code
+    * [THRIFT-1709] - Warning "Bitwise-or operator used on a sign-extended operand; consider casting to a smaller unsigned type first" in TBinaryProtocol.cs at ReadInt64()
+    * [THRIFT-1707] - [ruby] Adjust server_spec.rb for RSpec 2.11.x and Ruby 1.9.3
+    * [THRIFT-1671] - Cocoa code generator does not put keywords into generated method calls
+    * [THRIFT-1670] - Incompatibilities between different versions of a Thrift interface
+    * [THRIFT-1669] - NameError: global name 'TApplicationException' is not defined
+    * [THRIFT-1668] - Compile error in contrib/fb303, thrift/TDispatchProcessor.h: No such file or directory
+    * [THRIFT-1845] - Fix compiler warning caused by implicit string conversion with Xcode 4.6
+    * [THRIFT-304] - Building the Python library requires development headers
+    * [THRIFT-369] - sets and maps break equality
+    * [THRIFT-556] - Ruby compiler does not correctly referred to top-level modules when a submodule masks the top-level name
+    * [THRIFT-481] - indentation of ruby classes is off by a few
+
+## Improvement
+    * [THRIFT-1498] - Allow TThreadedPoolServer.Args to pass a ExecutorService
+    * [THRIFT-1444] - FunctionRunner - add syntactic sugar to create shared_ptrs
+    * [THRIFT-1443] - define a TProcessor helper class to implement process()
+    * [THRIFT-1441] - Generate constructor with parameters for exception class to let it update message property automatically.
+    * [THRIFT-1520] - Embed version number in erlang .app file
+    * [THRIFT-1480] - python: remove tabs, adjust whitespace and address PEP8 warnings
+    * [THRIFT-1485] - Performance: pass large and/or refcounted arguments as "const"
+    * [THRIFT-1484] - Introduce phpunit test suite
+    * [THRIFT-1532] - The type specifications in the generated Erlang code should include "undefined" where it's used as a default value
+    * [THRIFT-1534] - Required fields in the Delphi code generator.
+    * [THRIFT-1469] - Java isset space optimization
+    * [THRIFT-1465] - Visibility of methods in generated java code
+    * [THRIFT-1453] - Don't change types of arguments when serializing with thrift php extension
+    * [THRIFT-1452] - generate a swap() method for all generated structs
+    * [THRIFT-1451] - FramedTransport: Prevent infinite loop when writing
+    * [THRIFT-1521] - Two patches for more Performance
+    * [THRIFT-1555] - Delphi version of the tutorial code
+    * [THRIFT-1535] - Why thrift don't use wrapped class for optional fields ?
+    * [THRIFT-1204] - Ruby autogenerated files should require 'thrift' gem
+    * [THRIFT-1344] - Using the httpc module directly rather than the deprecated http layer
+    * [THRIFT-1343] - no_auto_import min/2 to avoid compile warning
+    * [THRIFT-1340] - Add support of ARC to Objective-C
+    * [THRIFT-1611] - Improved code generation for typedefs
+    * [THRIFT-1593] - Pass on errors like "connection closed" to the handler module
+    * [THRIFT-1615] - PHP Namespace
+    * [THRIFT-1567] - Thrift/cpp: Allow alternate classes to be used for
+    * [THRIFT-1072] - Missing - (id) initWithSharedProcessor in TSharedProcessorFactory.h
+    * [THRIFT-1650] - [ruby] Update clean items and svn:ignore entries for OS X artifacts
+    * [THRIFT-1661] - [PATCH] Add --with-qt4 configure option
+    * [THRIFT-1675] - Do we have any plan to support scala?
+    * [THRIFT-1645] - Replace Object#tee with more conventional Object#tap in specs
+    * [THRIFT-1644] - Upgrade RSpec to 2.10.x and refactor specs as needed
+    * [THRIFT-1672] - MonoTouch (and Mono for Android) compatibility
+    * [THRIFT-1702] - a thrift manual
+    * [THRIFT-1694] - Re-Enable serialization for WP7 Silverlight
+    * [THRIFT-1691] - Serializer/deserializer support for Delphi
+    * [THRIFT-1688] - Update IDL page markup
+    * [THRIFT-1725] - Tutorial web pages for Delphi and C#
+    * [THRIFT-1714] - [ruby] Explicitly add CWD to Ruby test_suites.rb
+    * [THRIFT-317] - Issues with Java struct validation
+    * [THRIFT-164] - Build web tutorial on Incubator web site
+    * [THRIFT-541] - Cocoa code generator doesn't put keywords before all arguments.
+    * [THRIFT-681] - The HTML generator does not handle JavaDoc style comments very well
+
+## New Feature
+    * [THRIFT-1500] - D programming language support
+    * [THRIFT-1510] - There should be an implementation of the JsonProtocol for ruby
+    * [THRIFT-1115] - python TBase class for dynamic (de)serialization, and __slots__ option for memory savings
+    * [THRIFT-1953] - support for asp.net mvc 3
+
+## Question
+    * [THRIFT-1235] - How could I use THttpServerTransportFactory withTNonBlockingServer
+    * [THRIFT-1368] - TNonblockingServer usage
+    * [THRIFT-1061] - Read an invalid frame size of 0. Are you using TFramedTransport on the client side?
+    * [THRIFT-491] - Ripping raw pthreads out of TFileTransport and associated test issues
+
+## Sub-task
+    * [THRIFT-1596] - Delphi: Test clients should have a return codes that reflect whether they succeeded or not
+    * [THRIFT-982] - javame: add version Info to the library
+    * [THRIFT-1722] - C# WP7 Assembly addition beaks mono build
+    * [THRIFT-336] - Compact Protocol in C#
+
+## Test
+    * [THRIFT-1613] - Add code back into empty source file ToStringTest.java
+    * [THRIFT-1718] - Incorrect check in TFileTransportTest
+
+## Wish
+    * [THRIFT-1463] - Decouple Thrift IDL from generators
+    * [THRIFT-1466] - Proper Documentation for Thrift C Glib
+    * [THRIFT-1539] - Build and distribute the fb303 python libraries along with thrift
+    * [THRIFT-1685] - Please add "aereo.com" to "Powered by Apache Thrift" list in about page
+    * [THRIFT-330] - TProcessor - additional method to called when connection is broken
 
 
-Version 0.5.0
 
+Thrift 0.8
+--------------------------------------------------------------------------------
+## Bug
+    * [THRIFT-1436] - pip install thrift fails on Windows with "Unable to find vcvarsall.bat"
+    * [THRIFT-1432] - Javascript struct constants declared in the same file as their struct definition will cause an error
+    * [THRIFT-1428] - shared.thrft does not include namespace for php, so thrift compiler generate incorrect name
+    * [THRIFT-1426] - Dist package missing files for release 0.8
+    * [THRIFT-1425] - The Node package is incompatible with latest node (0.6) & npm (1.0.27)
+    * [THRIFT-1416] - Python Unit test is broken on ci
+    * [THRIFT-1419] - AbstractNonBlockingServer does not catch errors when invoking the processor
+    * [THRIFT-1424] - Ruby specs fail when run with rake
+    * [THRIFT-1420] - Nonblocking and HsHa server should make sure to close all their socket connections when the selector exits
+    * [THRIFT-1413] - Generated code does not read MapEnd / ListEnd / SetEnd
+    * [THRIFT-1409] - Name conflict check does not work properly for exception object(Delphi).
+    * [THRIFT-1408] - Delphi Test Server: Exception test case fails due to naming conflict with e.message
+    * [THRIFT-1407] - Typo in Python socket server causes Thrift to fail when we enable a global socket timout
+    * [THRIFT-1397] - CI server fails during build due to unused parameters in delphi generator
+    * [THRIFT-1404] - Delphi compiler generates struct reader code with problem.
+    * [THRIFT-1400] - Ruby native extension aborts with __stack_chk_fail in OSX
+    * [THRIFT-1399] - One of the TServerImpl.Create CTORs lacks implementation
+    * [THRIFT-1390] - Debian packages build fix for Squeeze (build from the official  0.7.0 tarball)
+    * [THRIFT-1393] - TTransportException's thrown from THttpClient contain superfluous slashes in the Exception message
+    * [THRIFT-1392] - Enabling both namespaces and autoloading in generated PHP code won't work.
+    * [THRIFT-1406] - Build error after applying THRIFT-1395
+    * [THRIFT-1405] - Delphi compiler does not generates container serializer properly.
+    * [THRIFT-1411] - java generator does not provide type parameter for TBaseProcessor
+    * [THRIFT-1473] - JSON context stack may be left in an incorrect state when an exception is thrown during read or write operations
+    * [THRIFT-1331] - Ruby library deserializes an empty map to nil
+    * [THRIFT-1330] - PHP Namespaces no longer generated
+    * [THRIFT-1328] - TBaseHelper.toString(...) appends ByteBuffer data outside of valid buffer range
+    * [THRIFT-1322] - OCaml lib fail to compile: Thrift.ml line 305, int vs int32 mismatch
+    * [THRIFT-1143] - Build doesn't detect correct architecture type on 64bit osx
+    * [THRIFT-1205] - port server unduly fragile with arbitrary input
+    * [THRIFT-1279] - type set is handled incorrectly when writing object
+    * [THRIFT-1298] - Standard scheme doesn't read or write metadata along with field values
+    * [THRIFT-1265] - C++ container deserialize
+    * [THRIFT-1263] - publish ruby client to rubygems
+    * [THRIFT-1384] - Java help menu missing newline near javame flag
+    * [THRIFT-1382] - Bundle install doesnot work because thrift crashes
+    * [THRIFT-1381] - Thrift C++ libs have incorrectly versioned names
+    * [THRIFT-1350] - Go library code does not build as of r60 (most recent release)
+    * [THRIFT-1365] - TupleProtocol#writeBitSet unintentionally writes a variable length byte array
+    * [THRIFT-1359] - --gen-cob cpp:cob_style does not compile anymore
+    * [THRIFT-1319] - Mismatch between how a union reads and writes a container
+    * [THRIFT-1309] - libfb303-0.7.0.jar missing in maven repository
+    * [THRIFT-1238] - Thrift JS client cannot read map of structures
+    * [THRIFT-1254] - Code can't be compiled against a regular JRE: Object.clone() override has a different return type
+    * [THRIFT-1367] - Mac OSX build fails with "no such file to load -- spec/rake/spectask"
+    * [THRIFT-1355] - Running make in lib/rb doesn't build the native extensions
+    * [THRIFT-1370] - Debian packaging should Build-Depend on libglib2.0-dev
+    * [THRIFT-1342] - Compilation problem on Windows of fastbinary.c
+    * [THRIFT-1341] - TProtocol.h endian detection wrong with boost
+    * [THRIFT-1583] - c_glib leaks memory
+    * [THRIFT-1582] - Bad includes of nested thrift files in c_glib
+    * [THRIFT-1578] - C_GLib generated code does not compile
+    * [THRIFT-1027] - 'make -j 16' fails with "unterminated #ifdef" error
+    * [THRIFT-1121] - Java server performance regression in 0.6
+    * [THRIFT-857] - tests run by "make install" fail if generators are disabled
+    * [THRIFT-380] - Use setuptools for python build
+
+## Dependency upgrade
+    * [THRIFT-1257] - thrift's dependency scope on javax.servlet:servlet-api should be 'provided'
+
+## Improvement
+    * [THRIFT-1445] - minor C++ generator variable cleanup
+    * [THRIFT-1435] - make TException.Message property conformant to the usual expectations
+    * [THRIFT-1431] - Rename 'sys' module to 'util'
+    * [THRIFT-1396] - Dephi generator has dependacy on boost 1.42 later.
+    * [THRIFT-1395] - Patch to prevent warnings for integer types in some cases
+    * [THRIFT-1275] -  thrift: always prefix namespaces with " ::"
+    * [THRIFT-1274] -  thrift: fail compilation if an unexpected token is
+    * [THRIFT-1271] -  thrift: fix missing namespace in generated local
+    * [THRIFT-1270] -  thrift: add --allow-neg-keys argument to allow
+    * [THRIFT-1345] - Allow building without tests
+    * [THRIFT-1286] - Modernize the Thrift Ruby Library Dev Environment
+    * [THRIFT-1284] -  thrift: fix processor inheritance
+    * [THRIFT-1283] -  thrift: wrap t_cpp_generator::generate_process_function() to 80
+    * [THRIFT-1282] - Upgrade httpclient to 4.1.2 (from 4.0.1)
+    * [THRIFT-1281] -  add @generated to the docblock
+    * [THRIFT-1280] -  Thrift: Improve Monitor exception-free interfaces
+    * [THRIFT-1278] - javadoc warnings - compilation
+    * [THRIFT-1227] - Erlang implementation of thrift JSON protocol
+    * [THRIFT-1295] - Duplicate include in TSocket.cpp
+    * [THRIFT-1294] -  thrift: fix log message typos in TSimpleServer
+    * [THRIFT-1293] -  thrift: improve handling of exceptions thrown by
+    * [THRIFT-1292] -  thrift: silence log spew from TThreadedServer
+    * [THRIFT-1288] -  Allow typedefed exceptions in throws clauses
+    * [THRIFT-1290] -  thrift: TNonblockingServer: clean up state in the
+    * [THRIFT-1287] -  thrift: start refactoring some of the C++ processor
+    * [THRIFT-1289] -  thrift: implement TNonblockingServer::stop()
+    * [THRIFT-1305] -  thrift: make TConnection a private inner class of
+    * [THRIFT-1304] -  TNonblockingServer: pass in the connection context to
+    * [THRIFT-1302] -  thrift: raise an exception if send() times out in
+    * [THRIFT-1301] -  thrift: consolidate common code in TNonblockingServer
+    * [THRIFT-1377] - abort PHP deserialization on unknown field type
+    * [THRIFT-1379] - fix uninitialized enum values in thrift C++ objects
+    * [THRIFT-1376] - Make port specification option in thrift remote
+    * [THRIFT-1375] - fixed a hex char conversion bug in TJSONProtocol
+    * [THRIFT-1373] - Fix user-defined exception generation in thrift (python)
+    * [THRIFT-1361] - Optional replacement of pthread by boost::thread
+    * [THRIFT-1320] - Consistency of configure generated config.h
+    * [THRIFT-1317] -  Remove copy constructibility from
+    * [THRIFT-1316] -  thrift: update server classes to accept
+    * [THRIFT-1315] -  thrift: generate server interface factory classes
+    * [THRIFT-1314] -  thrift: add TProcessorFactory
+    * [THRIFT-1335] -  Add accept timeout to TServerSocket
+    * [THRIFT-1334] -  Add more info to IllegalStateException
+    * [THRIFT-1333] -  Make RWGuard not copyable
+    * [THRIFT-1332] - TSSLTransportParameters class uses hard coded value keyManagerType: SunX509
+    * [THRIFT-1251] - Generated java code should indicate which fields are required and which are optional
+    * [THRIFT-1387] - Build MSVC libraries with Boost Threads instead of Pthreads
+    * [THRIFT-1339] - Extend Tuple Protocol to TUnions
+    * [THRIFT-1031] - Patch to compile Thrift for vc++ 9.0 and 10.0
+    * [THRIFT-1130] - Add the ability to specify symbolic default value for optional boolean
+    * [THRIFT-1123] - Patch to compile Thrift server and client for vc++ 9.0 and 10.0
+    * [THRIFT-386] - Make it possible to build the Python library without the extension
+
+## New Feature
+    * [THRIFT-1401] - JSON-protocol for Delphi XE Libraries
+    * [THRIFT-1167] - Java nonblocking server with more than one thread for select and handling IO
+    * [THRIFT-1366] - Delphi generator, lirbrary and unit test.
+    * [THRIFT-1354] - Add rake task to build just the gem file
+    * [THRIFT-769] - Pluggable Serializers
+
+## Sub-task
+    * [THRIFT-1415] - delphi: add version Info to the library
+    * [THRIFT-1391] - Improved Delphi XE test cases
+
+
+
+Thrift 0.7
+--------------------------------------------------------------------------------
+## Bug
+    * [THRIFT-1140] - Framed Transport Client using C (Glib) Library hangs when connecting to Ruby Server
+    * [THRIFT-1154] - HttpClient does not specify the connection close parameter
+    * [THRIFT-1153] - HttpClient does not specify the connection close parameter
+    * [THRIFT-1149] - Nonblocking server fails when client connection is reset
+    * [THRIFT-1146] - Android Incompatibility : in Android < 2.3 java.io.IOException doesn't support for Throwable parameter in constructor
+    * [THRIFT-1133] - Java and JavaScript tutorial is broken since we have Java maven deployment
+    * [THRIFT-1132] - Deserialization error in TApplicationException C#
+    * [THRIFT-1131] - C# JSON Protocol is unable to decode escaped characters in string
+    * [THRIFT-1208] - python TCompactProtocol.py writeBool and readBool not follow the compact-proto-spec-2.txt spec for CONTAINER_WRITE, CONTAINER_READ
+    * [THRIFT-1200] - JS compiler generates code that clobbers existing namespaces
+    * [THRIFT-1183] - Pure-ruby CompactProtocol raises ArgumentError when deserializing under Ruby 1.9
+    * [THRIFT-1182] - Native deserializer segfaults on incorrect list element type
+    * [THRIFT-1181] - AS3 compiler generates incorrect code for setting default values in constructor
+    * [THRIFT-1234] - thrift --help is missing doc on py:utf8strings
+    * [THRIFT-1180] - AS3 compiler generates uncompilable code for binary types.
+    * [THRIFT-1194] - Java lib does not install artifacts to local dir correctly
+    * [THRIFT-1193] - Potential infinite loop in nonblocking_server
+    * [THRIFT-1192] - Typo: TProtocol.h tests for HAVE_SYS_PARAM_H_
+    * [THRIFT-1190] - readBufferBytesAllocated in TNonblockingServer.java should be AtomicLong to fix FD leakage and general server malfunction
+    * [THRIFT-1187] - nonblocking_server shutdown race under Ruby 1.9
+    * [THRIFT-1178] - Java: TBase signature should be T extends TBase<?,?>
+    * [THRIFT-1164] - Segmentation fault on NULL pointer in t_js_generator::generate_const
+    * [THRIFT-1171] - Perl write/readDouble assumes little-endian platform
+    * [THRIFT-1222] - Unhandled exception for TEvhttpServer request
+    * [THRIFT-1220] - TProcessor::process never returns false
+    * [THRIFT-1285] - Stable 0.7.0 Windows compiler exe available on the webside is not the good one
+    * [THRIFT-1218] - c_glib uses wrong name in pkg-config
+    * [THRIFT-1215] - Undefined property Thirft in lib/js/thrift.js
+    * [THRIFT-1211] - When using THttpClient, non 200 responses leave the connection open
+    * [THRIFT-1228] - The php accelerator module calls flush incorrectly
+    * [THRIFT-1308] - libfb303-0.7.0.jar missing in maven repository
+    * [THRIFT-1255] - Mismatch of method name between JavaME's lib and generated code (compareTo/compareObjects)
+    * [THRIFT-1253] - Code generated for maps is not compiling
+    * [THRIFT-1252] - Segfault in Ruby deserializer
+    * [THRIFT-1094] - bug in TCompactProto python readMessageEnd method and updated test cases
+    * [THRIFT-1093] - several bugs in python TCompactProtocol
+    * [THRIFT-1092] - generated validate() method has wrong indentation
+    * [THRIFT-1011] - Error generating package imports when using classes from other packages
+    * [THRIFT-1050] - Declaring an argument named "manager" to a service method produces code that fails compile due to name conflicts with protected ivars in TAsyncClient
+    * [THRIFT-1074] - .keystore and .truststore are missing from the 0.6.0 distribution
+    * [THRIFT-1067] - Tons of bugs in php implementation
+    * [THRIFT-1065] - Unexpected exceptions not proper handled on JS
+    * [THRIFT-1076] - Erlang Thrift socket server has a bug that causes java thrift client of framed binary client to throw "out of sequence" exception
+    * [THRIFT-1057] - casts in TBinaryProtocol.tcc causing "dereferencing type-punned pointer will break strict-aliasing rules" warnings from gcc
+    * [THRIFT-1055] - csharp TServerSocket and TSocket do not disable Nagle via Socket.NoDelay = true like cpp and java do
+    * [THRIFT-1054] - explicit call to PKG_PROG_PKG_CONFIG is missing and first use of PKG_CHECK_MODULES may not happen, causes mono detection to fail
+    * [THRIFT-1117] - JavaScript Unit Test does not work anymore because libthrift*.jar where moved by Maven Deployment
+    * [THRIFT-1111] - The HTML generator does not distinguish between string and binary types
+    * [THRIFT-1032] - "make dist" fails due to c_glib problem
+    * [THRIFT-1036] - Auto-generated C++ code fails to compile with "-Werror -Wextra -Wall" g++ compiler flags
+    * [THRIFT-1041] - TDeserializer holds onto a reference of the array it reads after it is done deserializing
+    * [THRIFT-1106] - C++ code TAsyncProtocolProcessor.h & TAsyncBufferProcessor.h dont have virtual functions but no virtual destructor. Causes warnings on -Wall
+    * [THRIFT-1105] - OCaml generator does not prefix methods of included structs with their type
+    * [THRIFT-1104] - INSTALLDIRS should be included in configure script
+    * [THRIFT-1102] - typo in configure.ac: "==" operator in 'test' (instead of"'=")
+    * [THRIFT-1101] - bytebuffer length calculation in TBinaryProtocol writeBinary
+    * [THRIFT-1098] - Undefined properties in TBinaryProtocolFactory
+    * [THRIFT-1081] - PHP tests broken and somewhat incomplete
+    * [THRIFT-1080] - erlang test's 'make' fails on Mac OSX
+    * [THRIFT-1078] - ThriftTest.thrift generates invalid PHP library
+    * [THRIFT-1120] - proto.WriteListEnd being called in the wrong place
+    * [THRIFT-1119] - TJSONProtocol fails to UTF8 decode strings
+    * [THRIFT-867] - PHP accelerator module's output transport is incompatible with TFramedTransport
+    * [THRIFT-826] - PHP TSocket Write Timeout
+    * [THRIFT-835] - Bad AS3 syntax in constructors that set default values
+    * [THRIFT-788] - thrift_protocol.so: multiget/multiget_slice does not handle more than 17 keys correctly
+    * [THRIFT-125] - OCaml libraries don't compile with 32-bit ocaml
+    * [THRIFT-342] - PHP: can't have sets of complex types
+    * [THRIFT-731] - configure doesn't check for ant >= 1.7
+    * [THRIFT-690] - Update TApplicationException codes
+    * [THRIFT-638] - BufferedTransport + C extensions block until recv timeout is reached on last fread call
+
+## Dependency upgrade
+    * [THRIFT-1177] - Update thrift to reflect changes in Go's networking libraries
+
+## Improvement
+    * [THRIFT-1155] - Remove log4j dependency from java client
+    * [THRIFT-1151] - Produce more informative runtime error in case of schema and data mismatch during serialization
+    * [THRIFT-1207] - Support DESTDIR on "make install" of ruby libs
+    * [THRIFT-1199] - Union structs should have generated methods to test whether a specific field is currently set
+    * [THRIFT-1233] - Remove unused include in generated C++ code
+    * [THRIFT-1189] - Ruby deserializer speed improvements
+    * [THRIFT-1170] - Thrift Generated Code and Java 5
+    * [THRIFT-1174] - Publish as3 client implementation via Maven for use by flex-mojos users
+    * [THRIFT-1225] - TCompactProtocol for PHP
+    * [THRIFT-1221] - Remove SimpleCallback.h
+    * [THRIFT-1217] - Use evutil_socketpair instead of pipe (Windows port)
+    * [THRIFT-1216] - build Java Library behind a proxy
+    * [THRIFT-1231] - Remove bogus include
+    * [THRIFT-1213] - Membuffer should provide a way to get back the buffer
+    * [THRIFT-1237] - Java fb303 missing some methods
+    * [THRIFT-1063] - Fix Erlang Tutorial Files
+    * [THRIFT-1053] - Make remote client's IP address available for all socket related transports
+    * [THRIFT-1109] - Deploy fb303 along side libthrift to maven repo
+    * [THRIFT-1107] - improvement for compiler-generated python for 'None' object comparisons
+    * [THRIFT-1069] - Add command line option to prevent thrift from inserting gen-* directories
+    * [THRIFT-1049] - Allow for TServerSocket python library to bind to a specific host
+    * [THRIFT-1126] - Extending struct_info for erlang bindings
+    * [THRIFT-1100] - python TSSLSocket improvements, including certificate validation
+    * [THRIFT-994] - Don't try to invoke phpize if we don't have it
+    * [THRIFT-993] - Some improvements in C++ stubs for oneway operations
+    * [THRIFT-997] - Using valueOf for base types in getFieldValue
+    * [THRIFT-418] - Don't do runtime sorting of struct fields
+    * [THRIFT-151] - TSSLServerSocket and TSSLSocket implementation
+    * [THRIFT-27] - Generated erlang types don't contain default values for records
+    * [THRIFT-113] - to-string methods should omit optional null fields from output
+    * [THRIFT-363] - Maven Deploy
+    * [THRIFT-447] - Make an abstract base Client class so we can generate less code
+    * [THRIFT-627] - should c++ have setters for optional fields?
+
+## New Feature
+    * [THRIFT-1236] - Erlang Reconnecting Thrift Client
+    * [THRIFT-1021] - Framed transport support for OCaml
+    * [THRIFT-1068] - Python SSL Socket Support
+    * [THRIFT-1103] - TZlibTransport for python, a zlib compressed transport
+    * [THRIFT-1083] - Preforking python process pool server
+    * [THRIFT-999] - Add TForkingServer
+
+## Sub-task
+    * [THRIFT-1152] - Attributes from private to protected
+    * [THRIFT-1038] - Generated Java code for structures containing binary fields (or collections thereof) are not serializable (in the Java sense) even though they implement java.io.Serializable
+
+## Task
+    * [THRIFT-892] - Refactor erlang build system with rebar
+
+## Wish
+    * [THRIFT-625] - Add support for 'Go'
+
+
+
+Thrift 0.6.1
+--------------------------------------------------------------------------------
+## Bug
+    * [THRIFT-1133] - Java and JavaScript tutorial is broken since we have Java maven deployment
+    * [THRIFT-1131] - C# JSON Protocol is unable to decode escaped characters in string
+    * [THRIFT-1074] - .keystore and .truststore are missing from the 0.6.0 distribution
+
+## Improvement
+    * [THRIFT-1109] - Deploy fb303 along side libthrift to maven repo
+    * [THRIFT-363] - Maven Deploy
+
+## Question
+    * [THRIFT-1206] - did the THRIFT 0.6.1 merge THRIFT-563 ?
+
+## Sub-task
+    * [THRIFT-1163] - How can i use multi service in one program?
+
+## Task
+    * [THRIFT-1112] - Apply THRIFT-363 to 0.6 branch
+    * [THRIFT-1113] - Apply THRIFT-1074 to 0.6 branch
+
+
+
+Thrift 0.6
+--------------------------------------------------------------------------------
+## Bug
+    * [THRIFT-1020] - OCaml compiler generates invalid OCaml
+    * [THRIFT-1015] - TUnion does not handle ByteBuffer in toString
+    * [THRIFT-1013] - generated java code may have name clashes with thrift library
+    * [THRIFT-1009] - TUnion does not correctly deep copy a ByteBuffer
+    * [THRIFT-1032] - "make dist" fails due to c_glib problem
+    * [THRIFT-868] - Referencing constant values doesn't work with with typedef types
+    * [THRIFT-971] - java module can't be compiled without ivy and network connection
+    * [THRIFT-970] - Under heavy load, THttpClient may fail with "too many open files"
+    * [THRIFT-969] - Java Tutorial broken, move CalculatorHandler to a separate file
+    * [THRIFT-807] - JavaScript: Initialization of Base Types with 0 instead of null
+    * [THRIFT-955] - Thrift compiler for Windows uses lowercase names and directories which is inconsistent with compiling on other platforms
+    * [THRIFT-992] - Naming convention in C# constructor is not consistent with other fields causes compile errors
+    * [THRIFT-1008] - byte[] accessors throw NPE on unset field
+    * [THRIFT-1006] - Impossible to correctly qualify an enum constant in an external thrift file
+    * [THRIFT-950] - Haskell bindings treat 'byte' as unsigned 8-bit int (Data.Word.Word8), java/cpp as signed (byte/int8_t).
+    * [THRIFT-975] - lib/c_glib/README is missing => breaks make dist
+    * [THRIFT-944] - Support all version-4s of base
+    * [THRIFT-939] - optional binary fields throw NPE on default byte[] getters
+    * [THRIFT-935] - PHP Extension aborts the build if php-config is not installed
+    * [THRIFT-933] - Haskell's Thrift.cabal has warnings
+    * [THRIFT-932] - Haskell tests need to be run through 'make check' (and probably 'cabal check') too
+    * [THRIFT-904] - C# TSocket should disable nagle and linger
+    * [THRIFT-941] - Make PHP C Extension use the defined Protocol writeMessageBegin function
+    * [THRIFT-940] - 'make check' fails if boost is not in the std include and link paths
+    * [THRIFT-924] - Fix generated php structure constants
+    * [THRIFT-979] - ruby bindings used to work on jruby
+    * [THRIFT-977] - Hex Conversion Bug in C++ TJSONProtocol
+    * [THRIFT-347] - PHP TSocket Timeout Issues
+    * [THRIFT-517] - TExceptions thrown by server result in cryptic error message on client - Tried to read 4 bytes, but only got 0 bytes
+
+## Improvement
+    * [THRIFT-1024] - Add Python Twisted example to the Tutorial
+    * [THRIFT-958] - Change accessmodifer on trans_ field in the FrameBuffer class to public.
+    * [THRIFT-957] - THsHaServer: Change access modifier of the invoker field.
+    * [THRIFT-1002] - CodeStyle: t_c_glib_generator.cc
+    * [THRIFT-1005] - Give unions byte[] signature methods to go along with their ByteBuffer counterparts
+    * [THRIFT-951] - Add a new isServing() method to TServer
+    * [THRIFT-943] - Silly readme typo fix.
+    * [THRIFT-961] - JavaScript TestSuite using ant/ivy and Java's ServerTestBase Handler
+    * [THRIFT-960] - add TestServer, TestNonblockingServer and TestClient again
+    * [THRIFT-949] - Modify the TEnum interface so it defines a method similar to findByValue
+    * [THRIFT-946] - Augment FieldValueMetaData so it differentiates 'string' and 'binary' fields.
+    * [THRIFT-903] - custom ThreadFactory in THsHaServer
+    * [THRIFT-913] - Test Case for Url encoded strings + simple enhancement to lib/js/test/RunTestServer.sh
+    * [THRIFT-926] - Miscellaneous C++ improvements
+    * [THRIFT-929] - Improvements to the C++ test suite
+    * [THRIFT-893] - add JavaScript to the tutorial examples
+    * [THRIFT-1003] - Polishing c_glib code
+    * [THRIFT-71] - Debian packaging for thrift
+
+## New Feature
+    * [THRIFT-1033] - Node.js language target
+    * [THRIFT-947] - Provide a helper method to determine the TProtocol used to serialize some data.
+    * [THRIFT-928] - Make more statistics available in C++ servers
+    * [THRIFT-922] - Templatized [de]serialization code for C++
+    * [THRIFT-923] - Event-driven client and server support for C++
+    * [THRIFT-925] - Provide name<->value map for enums in C++
+    * [THRIFT-927] - Add option to modify the PHP include path
+    * [THRIFT-377] - TFileTransport port in Java
+    * [THRIFT-106] - TSSLServerSocket
+    * [THRIFT-582] - C implementation of Thrift
+    * [THRIFT-745] - Make it easier to instantiate servers
+
+## Sub-task
+    * [THRIFT-1038] - Generated Java code for structures containing binary fields (or collections thereof) are not serializable (in the Java sense) even though they implement java.io.Serializable
+
+## Task
+    * [THRIFT-862] - Async client issues / improvements
+
+## Test
+    * [THRIFT-581] - Add a testsuite for txThrift (Twisted)
+
+
+
+Thrift 0.5.0 - Incubating
+--------------------------------------------------------------------------------
 THRIFT-505   Build                Make configure give a summary of the enabled components (David Reiss)
 THRIFT-506   Build                Allow Thrift to be built without the C++ library (David Reiss)
 THRIFT-844   Build                Build Requirements state autoconf 2.59+ is required, but 2.60+ is needed (Harlan Lieberman-Berg)
@@ -763,8 +2835,8 @@
 THRIFT-456   Test Suite           Bad IP address string in test/cpp/src/main.cpp (Rush Manbert)
 
 
-Version 0.4.0
-
+Thrift 0.4.0 - Incubating
+--------------------------------------------------------------------------------
 THRIFT-650   Build        Make Check fails on Centos/OSX with 0.2.0 tarball (Anthony Molinaro)
 THRIFT-770   Build        Get 'make dist' to work without first compiling source code (Anthony Molinaro)
 THRIFT-160   C#           Created THttpTransport for the C# library based on WebHttpRequest (Michael Greene)
@@ -812,8 +2884,8 @@
 THRIFT-459   Ruby         Ruby installation always tries to write to /Library/Ruby/site (Matthieu Imbert)
 
 
-Version 0.1.0 RC1 / Unreleased
-
+Thrift 0.1.0 - Incubating (not released)
+--------------------------------------------------------------------------------
 Compatibility Breaking Changes:
   C++:
     * It's quite possible that regenerating code and rebuilding will be
@@ -830,8 +2902,7 @@
   Erlang:
     * Generated code will have to be regenerated, and the new code will
       have to be deployed atomically with the new library code [THRIFT-136]
-  
-  
+
 New Features and Bug Fixes:
   C++:
     * Support for TCompactProtocol [THRIFT-333]
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..9f57a66
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,124 @@
+#
+# 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.
+#
+
+cmake_minimum_required(VERSION 3.1)
+
+# CMake 3.1 supports C++ standards selection with CMAKE_CXX_STANDARD
+# If you need CMake 3.1+ for Ubuntu 14.04, try
+#   https://launchpad.net/~george-edison55/+archive/ubuntu/cmake-3.x
+# If you need CMake 3.1+ for debian "jessie", get it from jessie-backports
+# Otherwise
+#   http://cmake.org
+
+project("Apache Thrift")
+
+set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake")
+
+# TODO: add `git rev-parse --short HEAD`
+# Read the version information from the Autoconf file
+file (STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/configure.ac" CONFIGURE_AC REGEX "AC_INIT\\(.*\\)" )
+
+# The following variable is used in the version.h.in file
+string(REGEX REPLACE "AC_INIT\\(\\[.*\\], \\[([0-9]+\\.[0-9]+\\.[0-9]+(-dev)?)\\]\\)" "\\1" PACKAGE_VERSION ${CONFIGURE_AC})
+message(STATUS "Parsed Thrift package version: ${PACKAGE_VERSION}")
+
+# These are internal to CMake
+string(REGEX REPLACE "([0-9]+\\.[0-9]+\\.[0-9]+)(-dev)?" "\\1" thrift_VERSION ${PACKAGE_VERSION})
+string(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" thrift_VERSION_MAJOR ${thrift_VERSION})
+string(REGEX REPLACE "[0-9]+\\.([0-9])+\\.[0-9]+" "\\1" thrift_VERSION_MINOR ${thrift_VERSION})
+string(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" thrift_VERSION_PATCH ${thrift_VERSION})
+message(STATUS "Parsed Thrift version: ${thrift_VERSION} (${thrift_VERSION_MAJOR}.${thrift_VERSION_MINOR}.${thrift_VERSION_PATCH})")
+
+# Some default settings
+include(DefineCMakeDefaults)
+
+# Build time options are defined here
+include(DefineOptions)
+include(DefineInstallationPaths)
+
+# Based on the options set some platform specifics
+include(DefinePlatformSpecifc)
+
+# Generate the config.h file
+include(ConfigureChecks)
+
+# Package it
+include(CPackConfig)
+
+
+find_package(Threads)
+
+include(CTest)
+if(BUILD_TESTING)
+  message(STATUS "Building with unittests")
+
+  enable_testing()
+  # Define "make check" as alias for "make test"
+  add_custom_target(check COMMAND ctest)
+else ()
+  message(STATUS "Building without tests")
+endif ()
+
+if(BUILD_COMPILER)
+    if(NOT EXISTS ${THRIFT_COMPILER})
+        set(THRIFT_COMPILER $<TARGET_FILE:thrift-compiler>)
+    endif()
+    add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/compiler/cpp)
+elseif(EXISTS ${THRIFT_COMPILER})
+    add_executable(thrift-compiler IMPORTED)
+    set_property(TARGET thrift-compiler PROPERTY IMPORTED_LOCATION ${THRIFT_COMPILER})
+endif()
+
+if(BUILD_CPP)
+    add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/cpp)
+    if(BUILD_TUTORIALS)
+        add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tutorial/cpp)
+    endif()
+    if(BUILD_TESTING)
+        if(WITH_LIBEVENT AND WITH_ZLIB AND WITH_OPENSSL)
+            add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test/cpp)
+        else()
+            message(WARNING "libevent and/or ZLIB and/or OpenSSL not found or disabled; will not build some tests")
+        endif()
+    endif()
+endif()
+
+if(BUILD_C_GLIB)
+    add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/c_glib)
+endif()
+
+if(BUILD_JAVA)
+    add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/java)
+endif()
+
+if(BUILD_PYTHON)
+    add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/py)
+    if(BUILD_TESTING)
+        add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test/py)
+    endif()
+endif()
+
+if(BUILD_HASKELL)
+    add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/hs)
+    if(BUILD_TESTING)
+        add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test/hs)
+    endif()
+endif()
+
+PRINT_CONFIG_SUMMARY()
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..7a1d710
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,116 @@
+# How to Contribute #
+
+Thank you for your interest in contributing to the Apache Thrift project!  Information on why and how to contribute is available on the Apache Software Foundation (ASF) web site. In particular, we recommend the following to become acquainted with Apache Contributions:
+
+ * [Contributors Tech Guide](http://www.apache.org/dev/contributors)
+ * [Get involved!](http://www.apache.org/foundation/getinvolved.html)
+ * [Legal aspects on Submission of Contributions (Patches)](http://www.apache.org/licenses/LICENSE-2.0.html#contributions)
+
+## GitHub pull requests ##
+
+This is the preferred method of submitting changes.  When you submit a pull request through github,
+it activates the continuous integration (CI) build systems at Appveyor and Travis to build your changesxi
+on a variety of Linux and Windows configurations and run all the test suites.  Follow these requirements 
+for a successful pull request:
+
+ 1. All code changes require an [Apache Jira THRIFT Issue](http://issues.apache.org/jira/browse/THRIFT) ticket.
+
+ 1. All pull requests should contain a single commit per issue, or we will ask you to squash it.
+ 1. The pull request title must begin with the Jira THRIFT ticket identifier, for example:
+
+        THRIFT-9999: an example pull request title
+        
+ 1. Commit messages must follow this pattern for code changes (deviations will not be merged):
+        
+        THRIFT-9999: [summary of fix, one line if possible]
+        Client: [language(s) affected, comma separated, use lib/ directory names please]
+
+Instructions:
+
+ 1. Create a fork in your GitHub account of http://github.com/apache/thrift
+ 1. Clone the fork to your development system.
+ 1. Create a branch for your changes (best practice is issue as branch name, e.g. THRIFT-9999).
+ 1. Modify the source to include the improvement/bugfix, and:
+
+    * Remember to provide *tests* for all submitted changes!
+    * Use test-driven development (TDD): add a test that will isolate the bug *before* applying the change that fixes it.
+    * Verify that you follow [Thrift Coding Standards](/docs/coding_standards) (you can run 'make style', which ensures proper format for some languages).
+    * [*optional*] Verify that your change works on other platforms by adding a GitHub service hook to [Travis CI](http://docs.travis-ci.com/user/getting-started/#Step-one%3A-Sign-in) and [AppVeyor](http://www.appveyor.com/docs).  You can use this technique to run the Thrift CI jobs in your account to check your changes before they are made public.  Every GitHub pull request into Thrift will run the full CI build and test suite on your changes.
+
+ 1. Squash your changes to a single commit.  This maintains clean change history.
+ 1. Commit and push changes to your branch (please use issue name and description as commit title, e.g. "THRIFT-9999: make it perfect"), with the affected languages on the next line of the description.
+ 1. Use GitHub to create a pull request going from your branch to apache:master.  Ensure that the Jira ticket number is at the beginning of the title of your pull request, same as the commit title.
+ 1. Wait for other contributors or committers to review your new addition, and for a CI build to complete.
+ 1. Wait for a committer to commit your patch.  You can nudge the committers if necessary by sending a message to the [Apache Thrift mailing list](https://thrift.apache.org/mailing).
+
+## If you want to build the project locally ##
+
+For Windows systems, see our detailed instructions on the [CMake README](/build/cmake/README.md).
+
+For Windows Native C++ builds, see our detailed instructions on the [WinCPP README](/build/wincpp/README.md).
+
+For unix systems, see our detailed instructions on the [Docker README](/build/docker/README.md).
+
+## If you want to review open issues... ##
+
+ 1. Review the [GitHub Pull Request Backlog](https://github.com/apache/thrift/pulls).  Code reviews are open to all.
+ 2. Review the [Jira issue tracker](http://issues.apache.org/jira/browse/THRIFT).  You can search for tickets relating to languages you are interested in or currently using with thrift, for example a Jira search (Issues -> Search For Issues) query of ``project = THRIFT AND component in ("Erlang - Library") and status not in (resolved, closed)`` will locate all the open Erlang Library issues.
+
+## If you discovered a defect... ##
+
+ 1. Check to see if the issue is already in the [Jira issue tracker](http://issues.apache.org/jira/browse/THRIFT).
+ 1. If not, create a ticket describing the change you're proposing in the Jira issue tracker.
+ 1. Contribute your code changes using the GitHub pull request method:
+
+## Contributing via Patch ##
+
+Some changes do not require a build, for example in documentation.  For changes that are not code or build related, you can submit a patch on Jira for review.  To create a patch from changes in your local directory:
+
+    git diff > ../THRIFT-NNNN.patch
+
+then wait for contributors or committers to review your changes, and then for a committer to apply your patch.
+
+## GitHub recipes for Pull Requests ##
+
+Sometimes commmitters may ask you to take actions in your pull requests.  Here are some recipes that will help you accomplish those requests.  These examples assume you are working on Jira issue THRIFT-9999.  You should also be familiar with the [upstream](https://help.github.com/articles/syncing-a-fork/) repository concept.
+
+### Squash your changes ###
+
+If you have not submitted a pull request yet, or if you have not yet rebased your existing pull request, you can squash all your commits down to a single commit.  This makes life easier for the committers.  If your pull request on GitHub has more than one commit, you should do this.
+
+1. Use the command ``git log`` to identify how many commits you made since you began.
+2. Use the command ``git rebase -i HEAD~N`` where N is the number of commits.
+3. Leave "pull" in the first line.
+4. Change all other lines from "pull" to "fixup".
+5. All your changes are now in a single commit.
+
+If you already have a pull request outstanding, you will need to do a "force push" to overwrite it since you changed your commit history:
+
+    git push -u origin THRIFT-9999 --force
+
+A more detailed walkthrough of a squash can be found at [Git Ready](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html).
+
+### Rebase your pull request ###
+
+If your pull request has a conflict with master, it needs to be rebased:
+
+    git checkout THRIFT-9999
+    git rebase upstream master
+      (resolve any conflicts, make sure it builds)
+    git push -u origin THRIFT-9999 --force
+
+### Fix a bad merge ###
+
+If your pull request contains commits that are not yours, then you should use the following technique to fix the bad merge in your branch:
+
+    git checkout master
+    git pull upstream master
+    git checkout -b THRIFT-9999-take-2
+    git cherry-pick ...
+        (pick only your commits from your original pull request in ascending chronological order)
+    squash your changes to a single commit if there is more than one (see above)
+    git push -u origin THRIFT-9999-take-2:THRIFT-9999
+
+This procedure will apply only your commits in order to the current master, then you will squash them to a single commit, and then you force push your local THRIFT-9999-take-2 into remote THRIFT-9999 which represents your pull request, replacing all the commits with the new one.
+
+ 
diff --git a/LANGUAGES.md b/LANGUAGES.md
new file mode 100644
index 0000000..24a3cf5
--- /dev/null
+++ b/LANGUAGES.md
@@ -0,0 +1,355 @@
+# Apache Thrift Language Support #
+
+Last Modified: 2018-12-17
+
+Guidance For: 0.12.0 or later
+
+Thrift supports many programming languages and has an impressive test suite that exercises most of the languages, protocols, and transports that represents a matrix of thousands of possible combinations.  Each language typically has a minimum required version as well as support libraries - some mandatory and some optional.  All of this information is provided below to help you assess whether you can use Apache Thrift with your project.  Obviously this is a complex matrix to maintain and may not be correct in all cases - if you spot an error please inform the developers using the mailing list.
+
+Apache Thrift has a choice of two build systems.  The `autoconf` build system is the most complete build and is used to build all supported languages.  The `cmake` build system has been designated by the project to replace `autoconf` however this transition will take quite some time to complete.
+
+The Language/Library Levels indicate the minimum and maximum versions that are used in the [continuous integration environments](build/docker/README.md) (Appveyor, Travis) for Apache Thrift.  Other language levels may be supported for each language, however tested less thoroughly; check the README file inside each lib directory for additional details.  Note that while a language may contain support for protocols, transports, and servers, the extent to which each is tested as part of the overall build process varies.  The definitive integration test for the project is called the "cross" test which executes a test matrix with clients and servers communicating across languages.
+
+<table style="font-size: 60%; padding: 1px;">
+<thead>
+<tr>
+<th rowspan=2>Language</th>
+<th rowspan=2 align=center>Since</th>
+<th colspan=2 align=center>Build Systems</th>
+<th colspan=2 align=center>Lang/Lib Levels (Tested)</th>
+<th colspan=6 align=center>Low-Level Transports</th>
+<th colspan=3 align=center>Transport Wrappers</th>
+<th colspan=4 align=center>Protocols</th>
+<th colspan=5 align=center>Servers</th>
+<th rowspan=2>Open Issues</th>
+</tr>
+<tr>
+<!-- Build Systems ---------><th>autoconf</th><th>cmake</th>
+<!-- Lang/Lib Levels -------><th>Min</th><th>Max</th>
+<!-- Low-Level Transports --><th><a href="https://en.wikipedia.org/wiki/Unix_domain_socket">Domain</a></th><th>&nbsp;File&nbsp;</th><th>Memory</th><th>&nbsp;Pipe&nbsp;</th><th>Socket</th><th>&nbsp;TLS&nbsp;</th>
+<!-- Transport Wrappers ----><th>Framed</th><th>&nbsp;http&nbsp;</th><th>&nbsp;zlib&nbsp;</th>
+<!-- Protocols -------------><th><a href="doc/specs/thrift-binary-protocol.md">Binary</a></th><th><a href="doc/specs/thrift-compact-protocol.md">Compact</a></th><th>&nbsp;JSON&nbsp;</th><th>Multiplex</th>
+<!-- Servers ---------------><th>Forking</th><th>Nonblocking</th><th>Simple</th><th>Threaded</th><th>ThreadPool</th>
+</tr>
+</thead>
+<tbody>
+<tr align=center>
+<td align=left><a href="lib/as3/README.md">ActionScript</a></td>
+<!-- Since -----------------><td>0.3.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td colspan=2>ActionScript 3</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12313722">ActionScript</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/c_glib/README.md">C (glib)</a></td>
+<!-- Since -----------------><td>0.6.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Language Levels -------><td>2.48.2</td><td>2.56.0</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12313854">C (glib)</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/cpp/README.md">C++</a></td>
+<!-- Since -----------------><td>0.2.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Language Levels -------><td colspan=2>C++98</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12312313">C++</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/csharp/README.md">C#</a></td>
+<!-- Since -----------------><td>0.2.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>.NET&nbsp;3.5 / mono&nbsp;3.2.8.0</td><td>.NET&nbsp;4.6.1 / mono&nbsp;4.6.2.7</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12312362">C# (.NET)</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/cocoa/README.md">Cocoa</a></td>
+<!-- Since -----------------><td>0.2.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td colspan=2>unknown</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12312398">Cocoa</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/cl/README.md">Common Lisp</a></td>
+<!-- Since -----------------><td>0.12.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>SBCL 1.4.5</td><td>SBCL 1.4.15</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT-82">Common Lisp</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/d/README.md">Dlang</a></td>
+<!-- Since -----------------><td>0.9.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>2.075.1</td><td>2.083.2</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12317904">D</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/dart/README.md">Dart</a></td>
+<!-- Since -----------------><td>0.10.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>1.22.1</td><td>1.24.3</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12328006">Dart</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/delphi/README.md">Delphi</a></td>
+<!-- Since -----------------><td>0.8.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>2010</td><td>unknown</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12316601">Delphi</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/netcore/README.md">.NET Core</a></td>
+<!-- Since -----------------><td>0.11.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>2.1.4</td><td>2.2.101</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12331176">.NET Core</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/erl/README.md">Erlang</a></td>
+<!-- Since -----------------><td>0.3.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>18.3</td><td>20.0.4</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12312390">Erlang</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/go/README.md">Go</a></td>
+<!-- Since -----------------><td>0.7.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>1.7.6</td><td>1.11.4</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12314307">Go</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/hs/README.md">Haskell</a></td>
+<!-- Since -----------------><td>0.5.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Language Levels -------><td>7.10.3</td><td>8.0.2</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12312704">Haskell</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/haxe/README.md">Haxe</a></td>
+<!-- Since -----------------><td>0.9.3</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>3.2.1</td><td>3.4.4</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12324347">Haxe</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/java/README.md">Java (SE)</a></td>
+<!-- Since -----------------><td>0.2.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Language Levels -------><td>1.8.0_151</td><td>1.8.0_191</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12312314">Java SE</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/javame/README.md">Java (ME)</a></td>
+<!-- Since -----------------><td>0.5.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td colspan=2>unknown</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12313759">Java ME</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/js/README.md">Javascript</a></td>
+<!-- Since -----------------><td>0.3.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td colspan=2>unknown</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12313418">Javascript</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/lua/README.md">Lua</a></td>
+<!-- Since -----------------><td>0.9.2</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>5.1.5</td><td>5.2.4</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12322659">Lua</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/nodejs/README.md">node.js</a></td>
+<!-- Since -----------------><td>0.6.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>6.x</td><td>8.x</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12314320">node.js</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/nodets/README.md">node.ts</a></td>
+<!-- Since -----------------><td>0.12.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>3.1.6</td><td></td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20resolution%20%3D%20Unresolved%20and%20Component%20in%20(%22TypeScript%20-%20Library%22)%20ORDER%20BY%20priority%20DESC%2C%20updated%20DESC">node.ts</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/ocaml/README.md">OCaml</a></td>
+<!-- Since -----------------><td>0.2.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td colspan=2>4.04.0</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12313660">OCaml</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/perl/README.md">Perl</a></td>
+<!-- Since -----------------><td>0.2.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>5.22.1</td><td>5.26.1</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12312312">Perl</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/php/README.md">PHP</a></td>
+<!-- Since -----------------><td>0.2.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>7.0.22</td><td>7.2.10</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12312431">PHP</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/py/README.md">Python</a></td>
+<!-- Since -----------------><td>0.2.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Language Levels -------><td>2.7.12, 3.5.2</td><td>2.7.15rc1, 3.6.7</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12312315">Python</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/rb/README.md">Ruby</a></td>
+<!-- Since -----------------><td>0.2.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>2.3.1p112</td><td>2.5.1p57</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12312316">Ruby</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/rs/README.md">Rust</a></td>
+<!-- Since -----------------><td>0.11.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td>1.17.0</td><td>1.30.0</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12331420">Rust</a></td>
+</tr>
+<tr align=center>
+<td align=left><a href="lib/st/README.md">Smalltalk</a></td>
+<!-- Since -----------------><td>0.2.0</td>
+<!-- Build Systems ---------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Language Levels -------><td colspan=2>unknown</td>
+<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Transport Wrappers ----><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
+<td align=left><a href="https://issues.apache.org/jira/browse/THRIFT/component/12313861">Smalltalk</a></td>
+</tr>
+</tbody>
+<tfoot>
+<tr>
+<th rowspan=2>Language</th>
+<th rowspan=2 align=center>Since</th>
+<!-- Build Systems ---------><th>autoconf</th><th>cmake</th>
+<!-- Lang/Lib Levels -------><th>Min</th><th>Max</th>
+<!-- Low-Level Transports --><th><a href="https://en.wikipedia.org/wiki/Unix_domain_socket">Domain</a></th></th><th>&nbsp;File&nbsp;</th><th>Memory</th><th>&nbsp;Pipe&nbsp;</th><th>Socket</th><th>&nbsp;TLS&nbsp;</th>
+<!-- Transport Wrappers ----><th>Framed</th><th>&nbsp;http&nbsp;</th><th>&nbsp;zlib&nbsp;</th>
+<!-- Protocols -------------><th><a href="doc/specs/thrift-binary-protocol.md">Binary</a></th><th><a href="doc/specs/thrift-compact-protocol.md">Compact</a></th><th>&nbsp;JSON&nbsp;</th><th>Multiplex</th>
+<!-- Servers ---------------><th>Forking</th><th>Nonblocking</th><th>Simple</th><th>Threaded</th><th>ThreadPool</th>
+<th rowspan=2>Open Issues</th>
+</tr>
+<tr>
+<th colspan=2 align=center>Build Systems</th>
+<th colspan=2 align=center>Lang/Lib Levels (Tested)</th>
+<th colspan=6 align=center>Low-Level Transports</th>
+<th colspan=3 align=center>Transport Wrappers</th>
+<th colspan=4 align=center>Protocols</th>
+<th colspan=5 align=center>Servers</th>
+</tr>
+</tfoot>
+</table>
diff --git a/LICENSE b/LICENSE
index 8db837b..3b6d7d7 100644
--- a/LICENSE
+++ b/LICENSE
@@ -226,36 +226,14 @@
 #   the copyright notice and this notice are preserved.
 
 --------------------------------------------------
-For the compiler/cpp/src/thrift/md5.[ch] components:
+For the lib/nodejs/lib/thrift/json_parse.js:
 
 /*
-  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
+    json_parse.js
+    2015-05-02
+    Public Domain.
+    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
 
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  L. Peter Deutsch
-  ghost@aladdin.com
-
- */
-
----------------------------------------------------
-For the lib/rb/setup.rb: Copyright (c) 2000-2005 Minero Aoki,
-lib/ocaml/OCamlMakefile and lib/ocaml/README-OCamlMakefile components:
-     Copyright (C) 1999 - 2007  Markus Mottl
-
-Licensed under the terms of the GNU Lesser General Public License 2.1
-(see doc/lgpl-2.1.txt for the full terms of this license)
+*/
+(By Douglas Crockford <douglas@crockford.com>)
+--------------------------------------------------
diff --git a/Makefile.am b/Makefile.am
index af25ad3..511452d 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,13 +19,23 @@
 
 ACLOCAL_AMFLAGS = -I ./aclocal
 
-SUBDIRS = compiler/cpp lib tutorial
+if WITH_PLUGIN
+# To enable bootstrap, build order is lib/cpp -> compiler -> others
+SUBDIRS = lib/cpp compiler/cpp lib
+if WITH_TESTS
+SUBDIRS += lib/cpp/test
+endif
+else
+SUBDIRS = compiler/cpp lib
+endif
 
 if WITH_TESTS
 SUBDIRS += test
 endif
 
+if WITH_TUTORIAL
 SUBDIRS += tutorial
+endif
 
 dist-hook:
 	find $(distdir) -type f \( -iname ".DS_Store" -or -iname "._*" -or -iname ".gitignore" \) | xargs rm -rf
@@ -33,15 +43,93 @@
 	find $(distdir) -type d \( -iname ".svn" -or -iname ".git" \) | xargs rm -rf
 
 print-version:
-	@echo $(VERSION)
+	@echo $(PACKAGE_VERSION)
+
+.PHONY: precross cross
+precross-%: all
+	$(MAKE) -C $* precross
+precross: all precross-test precross-lib
+
+empty :=
+space := $(empty) $(empty)
+comma := ,
+
+CROSS_LANGS = @MAYBE_CPP@ @MAYBE_C_GLIB@ @MAYBE_CL@ @MAYBE_D@ @MAYBE_JAVA@ @MAYBE_CSHARP@ @MAYBE_PYTHON@ @MAYBE_PY3@ @MAYBE_RUBY@ @MAYBE_HASKELL@ @MAYBE_PERL@ @MAYBE_PHP@ @MAYBE_GO@ @MAYBE_NODEJS@ @MAYBE_DART@ @MAYBE_ERLANG@ @MAYBE_LUA@ @MAYBE_RS@ @MAYBE_DOTNETCORE@ @MAYBE_NODETS@
+CROSS_LANGS_COMMA_SEPARATED = $(subst $(space),$(comma),$(CROSS_LANGS))
+
+if WITH_PY3
+CROSS_PY=$(PYTHON3)
+else
+CROSS_PY=$(PYTHON)
+endif
+
+if WITH_PYTHON
+crossfeature: precross
+	$(CROSS_PY) test/test.py --retry-count 5 --features .* --skip-known-failures --server $(CROSS_LANGS_COMMA_SEPARATED)
+else
+# feature test needs python build
+crossfeature:
+endif
+
+cross-%: precross crossfeature
+	$(CROSS_PY) test/test.py --retry-count 5 --skip-known-failures --server $(CROSS_LANGS_COMMA_SEPARATED) --client $(CROSS_LANGS_COMMA_SEPARATED) --regex "$*"
+
+cross: cross-.*
+
+TIMES = 1 2 3
+fail: precross
+	$(CROSS_PY) test/test.py || true
+	$(CROSS_PY) test/test.py --update-expected-failures=overwrite
+	$(foreach var,$(TIMES),test/test.py -s || true;test/test.py --update-expected-failures=merge;)
+
+codespell_skip_files = \
+	*.jar \
+	*.class \
+	*.so \
+	*.a \
+	*.la \
+	*.o \
+	*.p12 \
+	*OCamlMakefile \
+	.keystore \
+	.truststore \
+	CHANGES \
+	config.sub \
+	configure \
+	depcomp \
+	libtool.m4 \
+	output.* \
+	rebar \
+	thrift
+
+skipped_files = $(subst $(space),$(comma),$(codespell_skip_files))
+
+style-local:
+	codespell --write-changes --skip=$(skipped_files) --disable-colors
 
 EXTRA_DIST = \
+	.clang-format \
+	.editorconfig \
 	.travis.yml \
+	.rustfmt.toml \
+	.dockerignore \
+	appveyor.yml \
+	bower.json \
+	build \
+	bootstrap.sh \
+	cleanup.sh \
+	CMakeLists.txt \
+	composer.json \
 	contrib \
+	CONTRIBUTING.md \
 	debian \
 	doc \
 	doap.rdf \
+	package.json \
 	sonar-project.properties \
+	LANGUAGES.md \
 	LICENSE \
 	CHANGES \
-	NOTICE
+	NOTICE \
+	README.md \
+	Thrift.podspec
diff --git a/NOTICE b/NOTICE
index c23995a..902dc8d 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,5 +1,5 @@
 Apache Thrift
-Copyright 2006-2010 The Apache Software Foundation.
+Copyright 2006-2017 The Apache Software Foundation.
 
 This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/README b/README
deleted file mode 100644
index b5e2390..0000000
--- a/README
+++ /dev/null
@@ -1,157 +0,0 @@
-Apache Thrift
-
-Last Modified: 2013-June-6
-
-License
-=======
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-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.
-
-Introduction
-============
-
-Thrift is a lightweight, language-independent software stack with an
-associated code generation mechanism for RPC. Thrift provides clean
-abstractions for data transport, data serialization, and application
-level processing. The code generation system takes a simple definition
-language as its input and generates code across programming languages that
-uses the abstracted stack to build interoperable RPC clients and servers.
-
-Thrift is specifically designed to support non-atomic version changes
-across client and server code.
-
-For more details on Thrift's design and implementation, take a gander at
-the Thrift whitepaper included in this distribution or at the README files
-in your particular subdirectory of interest.
-
-Hierarchy
-=========
-
-thrift/
-
-  compiler/
-    Contains the Thrift compiler, implemented in C++.
-
-  lib/
-    Contains the Thrift software library implementation, subdivided by
-    language of implementation.
-
-    cpp/
-    java/
-    php/
-    py/
-    rb/
-
-  test/
-
-    Contains sample Thrift files and test code across the target programming
-    languages.
-
-  tutorial/
-
-    Contains a basic tutorial that will teach you how to develop software
-    using Thrift.
-
-Requirements
-============
-
-See http://wiki.apache.org/thrift/ThriftRequirements for
-an up-to-date list of build requirements.
-
-Resources
-=========
-
-More information about Thrift can be obtained on the Thrift webpage at:
-
-     http://thrift.apache.org
-
-Acknowledgments
-===============
-
-Thrift was inspired by pillar, a lightweight RPC tool written by Adam D'Angelo,
-and also by Google's protocol buffers.
-
-Installation
-============
-
-If you are building from the first time out of the source repository, you will
-need to generate the configure scripts.  (This is not necessary if you
-downloaded a tarball.)  From the top directory, do:
-
-	./bootstrap.sh
-
-Once the configure scripts are generated, thrift can be configured.
-From the top directory, do:
-
-	./configure
-
-You may need to specify the location of the boost files explicitly.
-If you installed boost in /usr/local, you would run configure as follows:
-
-	./configure --with-boost=/usr/local
-
-Note that by default the thrift C++ library is typically built with debugging
-symbols included. If you want to customize these options you should use the
-CXXFLAGS option in configure, as such:
-
-        ./configure CXXFLAGS='-g -O2'
-        ./configure CFLAGS='-g -O2'
-        ./configure CPPFLAGS='-DDEBUG_MY_FEATURE'
-
-Run ./configure --help to see other configuration options
-
-Please be aware that the Python library will ignore the --prefix option
-and just install wherever Python's distutils puts it (usually along
-the lines of /usr/lib/pythonX.Y/site-packages/).  If you need to control
-where the Python modules are installed, set the PY_PREFIX variable.
-(DESTDIR is respected for Python and C++.)
-
-Make thrift:
-
-	make
-
-From the top directory, become superuser and do:
-
-	make install
-
-Note that some language packages must be installed manually using build tools
-better suited to those languages (at the time of this writing, this applies
-to Java, Ruby, PHP).
-
-Look for the README file in the lib/<language>/ folder for more details on the
-installation of each language library package.
-
-Testing
-=======
-
-There are a large number of client library tests that can all be run
-from the top-level directory.
-
-          make -k check
-
-This will make all of the libraries (as necessary), and run through
-the unit tests defined in each of the client libraries. If a single
-language fails, the make check will continue on and provide a synopsis
-at the end.
-
-To run the cross-language test suite, please run:
-
-          sh test/test.sh
-
-This will run a set of tests that use different language clients and
-servers.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d09e6e1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,192 @@
+Apache Thrift
+=============
+
+Introduction
+============
+
+Thrift is a lightweight, language-independent software stack with an
+associated code generation mechanism for point-to-point RPC. Thrift provides 
+clean abstractions for data transport, data serialization, and application
+level processing. The code generation system takes a simple definition
+language as input and generates code across programming languages that
+uses the abstracted stack to build interoperable RPC clients and servers.
+
+![Apache Thrift Layered Architecture](doc/images/thrift-layers.png)
+
+Thrift makes it easy for programs written in different programming
+languages to share data and call remote procedures.  With support 
+for [25 programming languages](LANGUAGES.md), chances are Thrift 
+supports the languages that you currently use.
+
+Thrift is specifically designed to support non-atomic version changes
+across client and server code.
+
+For more details on Thrift's design and implementation, see the Thrift
+whitepaper included in this distribution, or at the README.md file
+in your particular subdirectory of interest.
+
+Status
+======
+
+| Branch | Travis | Appveyor | Coverity Scan | codecov.io | Website |
+| :----- | :----- | :------- | :------------ | :--------- | :------ |
+| [`master`](https://github.com/apache/thrift/tree/master) | [![Build Status](https://travis-ci.org/apache/thrift.svg?branch=master)](https://travis-ci.org/apache/thrift) | [![Build status](https://ci.appveyor.com/api/projects/status/github/apache/thrift?branch=master&svg=true)](https://ci.appveyor.com/project/ApacheSoftwareFoundation/thrift/history) | [![Coverity Scan Build Status](https://scan.coverity.com/projects/1345/badge.svg)](https://scan.coverity.com/projects/thrift) | | [![Website](https://img.shields.io/badge/official-website-brightgreen.svg)](https://thrift.apache.org/) |
+
+Releases
+========
+
+Thrift does not maintain a specific release calendar at this time.  
+
+We strive to release twice yearly.  Download the [current release](http://thrift.apache.org/download).
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+Project Hierarchy
+=================
+
+thrift/
+
+  compiler/
+
+    Contains the Thrift compiler, implemented in C++.
+
+  lib/
+
+    Contains the Thrift software library implementation, subdivided by
+    language of implementation.
+
+    cpp/
+    go/
+    java/
+    php/
+    py/
+    rb/
+    ...
+
+  test/
+
+    Contains sample Thrift files and test code across the target programming
+    languages.
+
+  tutorial/
+
+    Contains a basic tutorial that will teach you how to develop software
+    using Thrift.
+
+Development
+===========
+
+To build the same way Travis CI builds the project you should use docker.
+We have [comprehensive building instructions for docker](build/docker/README.md).
+
+Requirements
+============
+
+See http://thrift.apache.org/docs/install for a list of build requirements (may be stale).  Alternatively see the docker build environments for a list of prerequisites.
+
+Resources
+=========
+
+More information about Thrift can be obtained on the Thrift webpage at:
+
+     http://thrift.apache.org
+
+Acknowledgments
+===============
+
+Thrift was inspired by pillar, a lightweight RPC tool written by Adam D'Angelo,
+and also by Google's protocol buffers.
+
+Installation
+============
+
+If you are building from the first time out of the source repository, you will
+need to generate the configure scripts.  (This is not necessary if you
+downloaded a tarball.)  From the top directory, do:
+
+    ./bootstrap.sh
+
+Once the configure scripts are generated, thrift can be configured.
+From the top directory, do:
+
+    ./configure
+
+You may need to specify the location of the boost files explicitly.
+If you installed boost in /usr/local, you would run configure as follows:
+
+    ./configure --with-boost=/usr/local
+
+Note that by default the thrift C++ library is typically built with debugging
+symbols included. If you want to customize these options you should use the
+CXXFLAGS option in configure, as such:
+
+    ./configure CXXFLAGS='-g -O2'
+    ./configure CFLAGS='-g -O2'
+    ./configure CPPFLAGS='-DDEBUG_MY_FEATURE'
+
+To enable gcov required options -fprofile-arcs -ftest-coverage enable them:
+
+    ./configure  --enable-coverage
+
+Run ./configure --help to see other configuration options
+
+Please be aware that the Python library will ignore the --prefix option
+and just install wherever Python's distutils puts it (usually along
+the lines of /usr/lib/pythonX.Y/site-packages/).  If you need to control
+where the Python modules are installed, set the PY_PREFIX variable.
+(DESTDIR is respected for Python and C++.)
+
+Make thrift:
+
+	make
+
+From the top directory, become superuser and do:
+
+	make install
+
+Note that some language packages must be installed manually using build tools
+better suited to those languages (at the time of this writing, this applies
+to Java, Ruby, PHP).
+
+Look for the README.md file in the lib/<language>/ folder for more details on the
+installation of each language library package.
+
+Testing
+=======
+
+There are a large number of client library tests that can all be run
+from the top-level directory.
+
+          make -k check
+
+This will make all of the libraries (as necessary), and run through
+the unit tests defined in each of the client libraries. If a single
+language fails, the make check will continue on and provide a synopsis
+at the end.
+
+To run the cross-language test suite, please run:
+
+          make cross
+
+This will run a set of tests that use different language clients and
+servers.
+
+
diff --git a/Thrift-swift3.podspec b/Thrift-swift3.podspec
new file mode 100644
index 0000000..126c00b
--- /dev/null
+++ b/Thrift-swift3.podspec
@@ -0,0 +1,16 @@
+Pod::Spec.new do |s|
+  s.name          = "Thrift-swift3"
+  s.version       = "1.0.0"
+  s.summary       = "Apache Thrift is a lightweight, language-independent software stack with an associated code generation mechanism for RPC."
+  s.description   = <<-DESC
+The Apache Thrift scalable cross-language software framework for networked services development combines a software stack with a code generation engine to build services that work efficiently and seamlessly between many programming languages.
+                    DESC
+  s.homepage      = "http://thrift.apache.org"
+  s.license       = { :type => 'Apache License, Version 2.0', :url => 'https://www.apache.org/licenses/LICENSE-2.0' }
+  s.author        = { "Apache Thrift Developers" => "dev@thrift.apache.org" }
+  s.ios.deployment_target = '9.0'
+  s.osx.deployment_target = '10.10'
+  s.requires_arc  = true
+  s.source        = { :git => "https://github.com/apache/thrift.git", :tag => "v1.0.0" }
+  s.source_files  = "lib/swift/Sources/*.swift"
+end
diff --git a/Thrift.podspec b/Thrift.podspec
new file mode 100644
index 0000000..a406eec
--- /dev/null
+++ b/Thrift.podspec
@@ -0,0 +1,18 @@
+Pod::Spec.new do |s|
+  s.name          = "Thrift"
+  s.version       = "1.0.0"
+  s.summary       = "Apache Thrift is a lightweight, language-independent software stack with an associated code generation mechanism for RPC."
+  s.description   = <<-DESC
+The Apache Thrift scalable cross-language software framework for networked services development combines a software stack with a code generation engine to build services that work efficiently and seamlessly between many programming languages.
+                    DESC
+  s.homepage      = "http://thrift.apache.org"
+  s.license       = { :type => 'Apache License, Version 2.0', :url => 'https://www.apache.org/licenses/LICENSE-2.0' }
+  s.author        = { "Apache Thrift Developers" => "dev@thrift.apache.org" }
+  s.requires_arc  = true
+  s.ios.deployment_target = '7.0'
+  s.osx.deployment_target = '10.8'
+  s.ios.framework = 'CFNetwork'
+  s.osx.framework = 'CoreServices'
+  s.source        = { :git => "https://github.com/apache/thrift.git", :tag => "v1.0.0" }
+  s.source_files  = 'lib/cocoa/src/**/*.{h,m,swift}'
+end
diff --git a/aclocal/ac_prog_bison.m4 b/aclocal/ac_prog_bison.m4
new file mode 100644
index 0000000..4d1198b
--- /dev/null
+++ b/aclocal/ac_prog_bison.m4
@@ -0,0 +1,54 @@
+dnl
+dnl Check Bison version
+dnl AC_PROG_BISON([MIN_VERSION=2.4])
+dnl
+dnl Will define BISON_USE_PARSER_H_EXTENSION if Automake is < 1.11
+dnl for use with .h includes.
+dnl
+
+AC_DEFUN([AC_PROG_BISON], [
+if test "x$1" = "x" ; then
+  bison_required_version="2.4"
+else
+  bison_required_version="$1"
+fi
+
+AC_CHECK_PROG(have_prog_bison, [bison], [yes],[no])
+
+AC_DEFINE_UNQUOTED([BISON_VERSION], [0.0], [Bison version if bison is not available])
+
+#Do not use *.h extension for parser header files, use newer *.hh
+bison_use_parser_h_extension=false
+
+if test "$have_prog_bison" = "yes" ; then
+  AC_MSG_CHECKING([for bison version >= $bison_required_version])
+  bison_version=`bison --version | head -n 1 | cut '-d ' -f 4`
+  AC_DEFINE_UNQUOTED([BISON_VERSION], [$bison_version], [Defines bison version])
+  if test "$bison_version" \< "$bison_required_version" ; then
+    BISON=:
+    AC_MSG_RESULT([no])
+    AC_MSG_ERROR([Bison version $bison_required_version or higher must be installed on the system!])
+  else
+    AC_MSG_RESULT([yes])
+    BISON=bison
+    AC_SUBST(BISON)
+
+    #Verify automake version 1.11 headers for yy files are .h, > 1.12 uses .hh
+    automake_version=`automake --version | head -n 1 | cut '-d ' -f 4`
+    AC_DEFINE_UNQUOTED([AUTOMAKE_VERSION], [$automake_version], [Defines automake version])
+
+    if test "$automake_version" \< "1.12" ; then
+      #Use *.h extension for parser header file
+      bison_use_parser_h_extension=true
+      echo "Automake version < 1.12"
+      AC_DEFINE([BISON_USE_PARSER_H_EXTENSION], [1], [Use *.h extension for parser header file])
+    fi
+  fi
+else
+  BISON=:
+  AC_MSG_RESULT([NO])
+fi
+
+AM_CONDITIONAL([BISON_USE_PARSER_H_EXTENSION], [test x$bison_use_parser_h_extension = xtrue])
+AC_SUBST(BISON)
+])
diff --git a/aclocal/ax_boost_base.m4 b/aclocal/ax_boost_base.m4
index 806f98b..d540395 100644
--- a/aclocal/ax_boost_base.m4
+++ b/aclocal/ax_boost_base.m4
@@ -1,17 +1,19 @@
-##### http://autoconf-archive.cryp.to/ax_boost_base.html
+# ===========================================================================
+#      https://www.gnu.org/software/autoconf-archive/ax_boost_base.html
+# ===========================================================================
 #
 # SYNOPSIS
 #
-#   AX_BOOST_BASE([MINIMUM-VERSION])
+#   AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
 #
 # DESCRIPTION
 #
 #   Test for the Boost C++ libraries of a particular version (or newer)
 #
-#   If no path to the installed boost library is given the macro
-#   searchs under /usr, /usr/local, /opt and /opt/local and evaluates
-#   the $BOOST_ROOT environment variable. Further documentation is
-#   available at <http://randspringer.de/boost/index.html>.
+#   If no path to the installed boost library is given the macro searchs
+#   under /usr, /usr/local, /opt and /opt/local and evaluates the
+#   $BOOST_ROOT environment variable. Further documentation is available at
+#   <http://randspringer.de/boost/index.html>.
 #
 #   This macro calls:
 #
@@ -21,187 +23,279 @@
 #
 #     HAVE_BOOST
 #
-# LAST MODIFICATION
+# LICENSE
 #
-#   2007-07-28
-#   Modified for use in Thrift
+#   Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
+#   Copyright (c) 2009 Peter Adolphs
 #
-# COPYLEFT
-#
-#   Copyright (c) 2007 Thomas Porschberg <thomas@randspringer.de>
-#
-#   Copying and distribution of this file, with or without
-#   modification, are permitted in any medium without royalty provided
-#   the copyright notice and this notice are preserved.
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 45
+
+# example boost program (need to pass version)
+m4_define([_AX_BOOST_BASE_PROGRAM],
+          [AC_LANG_PROGRAM([[
+#include <boost/version.hpp>
+]],[[
+(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($1))]));
+]])])
 
 AC_DEFUN([AX_BOOST_BASE],
 [
 AC_ARG_WITH([boost],
-	AS_HELP_STRING([--with-boost@<:@=DIR@:>@], [use boost [default=yes]. Optionally specify the root prefix dir where boost is installed]),
-	[
-    if test "$withval" = "no"; then
-		want_boost="no"
-    elif test "$withval" = "yes"; then
-        want_boost="yes"
-        ac_boost_path=""
-    else
-	    want_boost="yes"
-        ac_boost_path="$withval"
-	fi
+  [AS_HELP_STRING([--with-boost@<:@=ARG@:>@],
+    [use Boost library from a standard location (ARG=yes),
+     from the specified location (ARG=<path>),
+     or disable it (ARG=no)
+     @<:@ARG=yes@:>@ ])],
+    [
+     AS_CASE([$withval],
+       [no],[want_boost="no";_AX_BOOST_BASE_boost_path=""],
+       [yes],[want_boost="yes";_AX_BOOST_BASE_boost_path=""],
+       [want_boost="yes";_AX_BOOST_BASE_boost_path="$withval"])
     ],
     [want_boost="yes"])
 
-if test "x$want_boost" = "xyes"; then
-	boost_lib_version_req=ifelse([$1], ,1.20.0,$1)
-	boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'`
-	boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'`
-	boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
-	boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
-	if test "x$boost_lib_version_req_sub_minor" = "x" ; then
-		boost_lib_version_req_sub_minor="0"
-    	fi
-	WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+  $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor`
-	AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req)
-	succeeded=no
 
-	dnl first we check the system location for boost libraries
-	dnl this location ist chosen if boost libraries are installed with the --layout=system option
-	dnl or if you install boost with RPM
-	if test "$ac_boost_path" != ""; then
-		BOOST_LDFLAGS="-L$ac_boost_path/lib"
-		BOOST_CPPFLAGS="-I$ac_boost_path/include"
-		BOOST_ROOT_PATH="$ac_boost_path"
-	else
-		for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do
-			if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then
-				BOOST_LDFLAGS="-L$ac_boost_path_tmp/lib"
-				BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include"
-				BOOST_ROOT_PATH="$ac_boost_path_tmp"
-				break;
-			fi
-		done
-	fi
+AC_ARG_WITH([boost-libdir],
+  [AS_HELP_STRING([--with-boost-libdir=LIB_DIR],
+    [Force given directory for boost libraries.
+     Note that this will override library path detection,
+     so use this parameter only if default library detection fails
+     and you know exactly where your boost libraries are located.])],
+  [
+   AS_IF([test -d "$withval"],
+         [_AX_BOOST_BASE_boost_lib_path="$withval"],
+    [AC_MSG_ERROR([--with-boost-libdir expected directory name])])
+  ],
+  [_AX_BOOST_BASE_boost_lib_path=""])
 
-	CPPFLAGS_SAVED="$CPPFLAGS"
-	CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
-	export CPPFLAGS
+BOOST_LDFLAGS=""
+BOOST_CPPFLAGS=""
+AS_IF([test "x$want_boost" = "xyes"],
+      [_AX_BOOST_BASE_RUNDETECT([$1],[$2],[$3])])
+AC_SUBST(BOOST_CPPFLAGS)
+AC_SUBST(BOOST_LDFLAGS)
+])
 
-	LDFLAGS_SAVED="$LDFLAGS"
-	LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
-	export LDFLAGS
 
-	export BOOST_ROOT_PATH
+# convert a version string in $2 to numeric and affect to polymorphic var $1
+AC_DEFUN([_AX_BOOST_BASE_TONUMERICVERSION],[
+  AS_IF([test "x$2" = "x"],[_AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0"],[_AX_BOOST_BASE_TONUMERICVERSION_req="$2"])
+  _AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\.[[0-9]]*\)'`
+  _AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\)'`
+  AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_major" = "x"],
+        [AC_MSG_ERROR([You should at least specify libboost major version])])
+  _AX_BOOST_BASE_TONUMERICVERSION_req_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.\([[0-9]]*\)'`
+  AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_minor" = "x"],
+        [_AX_BOOST_BASE_TONUMERICVERSION_req_minor="0"])
+  _AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
+  AS_IF([test "X$_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor" = "X"],
+        [_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor="0"])
+  _AX_BOOST_BASE_TONUMERICVERSION_RET=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req_major \* 100000 \+  $_AX_BOOST_BASE_TONUMERICVERSION_req_minor \* 100 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor`
+  AS_VAR_SET($1,$_AX_BOOST_BASE_TONUMERICVERSION_RET)
+])
 
-	AC_LANG_PUSH(C++)
-     	AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-	@%:@include <boost/version.hpp>
-	]], [[
-	#if BOOST_VERSION >= $WANT_BOOST_VERSION
-	// Everything is okay
-	#else
-	#  error Boost version is too old
-	#endif
-	]])],[
+dnl Run the detection of boost should be run only if $want_boost
+AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
+    _AX_BOOST_BASE_TONUMERICVERSION(WANT_BOOST_VERSION,[$1])
+    succeeded=no
+
+
+    AC_REQUIRE([AC_CANONICAL_HOST])
+    dnl On 64-bit systems check for system libraries in both lib64 and lib.
+    dnl The former is specified by FHS, but e.g. Debian does not adhere to
+    dnl this (as it rises problems for generic multi-arch support).
+    dnl The last entry in the list is chosen by default when no libraries
+    dnl are found, e.g. when only header-only libraries are installed!
+    AS_CASE([${host_cpu}],
+      [x86_64],[libsubdirs="lib64 libx32 lib lib64"],
+      [ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64],[libsubdirs="lib64 lib lib64"],
+      [libsubdirs="lib"]
+    )
+
+    dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give
+    dnl them priority over the other paths since, if libs are found there, they
+    dnl are almost assuredly the ones desired.
+    AS_CASE([${host_cpu}],
+      [i?86],[multiarch_libsubdir="lib/i386-${host_os}"],
+      [multiarch_libsubdir="lib/${host_cpu}-${host_os}"]
+    )
+
+    dnl first we check the system location for boost libraries
+    dnl this location ist chosen if boost libraries are installed with the --layout=system option
+    dnl or if you install boost with RPM
+    AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[
+        AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"])
+         AS_IF([test -d "$_AX_BOOST_BASE_boost_path/include" && test -r "$_AX_BOOST_BASE_boost_path/include"],[
+           AC_MSG_RESULT([yes])
+           BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include"
+           for _AX_BOOST_BASE_boost_path_tmp in $multiarch_libsubdir $libsubdirs; do
+                AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) lib path in "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"])
+                AS_IF([test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ],[
+                        AC_MSG_RESULT([yes])
+                        BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp";
+                        break;
+                ],
+      [AC_MSG_RESULT([no])])
+           done],[
+      AC_MSG_RESULT([no])])
+    ],[
+        if test X"$cross_compiling" = Xyes; then
+            search_libsubdirs=$multiarch_libsubdir
+        else
+            search_libsubdirs="$multiarch_libsubdir $libsubdirs"
+        fi
+        for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local ; do
+            if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then
+                for libsubdir in $search_libsubdirs ; do
+                    if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
+                done
+                BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path_tmp/$libsubdir"
+                BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include"
+                break;
+            fi
+        done
+    ])
+
+    dnl overwrite ld flags if we have required special directory with
+    dnl --with-boost-libdir parameter
+    AS_IF([test "x$_AX_BOOST_BASE_boost_lib_path" != "x"],
+          [BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_lib_path"])
+
+    AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION)])
+    CPPFLAGS_SAVED="$CPPFLAGS"
+    CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+    export CPPFLAGS
+
+    LDFLAGS_SAVED="$LDFLAGS"
+    LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
+    export LDFLAGS
+
+    AC_REQUIRE([AC_PROG_CXX])
+    AC_LANG_PUSH(C++)
+        AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[
         AC_MSG_RESULT(yes)
-	succeeded=yes
-	found_system=yes
-       	],[
-       	])
-	AC_LANG_POP([C++])
+    succeeded=yes
+    found_system=yes
+        ],[
+        ])
+    AC_LANG_POP([C++])
 
 
 
-	dnl if we found no boost with system layout we search for boost libraries
-	dnl built and installed without the --layout=system option or for a staged(not installed) version
-	if test "x$succeeded" != "xyes"; then
-		_version=0
-		if test "$ac_boost_path" != ""; then
-               		BOOST_LDFLAGS="-L$ac_boost_path/lib"
-			if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
-				for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
-					_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
-					V_CHECK=`expr $_version_tmp \> $_version`
-					if test "$V_CHECK" = "1" ; then
-						_version=$_version_tmp
-					fi
-					VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
-					BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
-				done
-			fi
-		else
-			for ac_boost_path in /usr /usr/local /opt /opt/local ; do
-				if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
-					for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
-						_version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
-						V_CHECK=`expr $_version_tmp \> $_version`
-						if test "$V_CHECK" = "1" ; then
-							_version=$_version_tmp
-	               					best_path=$ac_boost_path
-						fi
-					done
-				fi
-			done
-
-			VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
-			BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
-			BOOST_LDFLAGS="-L$best_path/lib"
-			BOOST_ROOT_PATH="$best_path"
-
-	    		if test "x$BOOST_ROOT" != "x"; then
-				if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/lib" && test -r "$BOOST_ROOT/stage/lib"; then
-					version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'`
-					stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
-			        	stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
-					V_CHECK=`expr $stage_version_shorten \>\= $_version`
-				        if test "$V_CHECK" = "1" ; then
-						AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
-						BOOST_CPPFLAGS="-I$BOOST_ROOT"
-						BOOST_LDFLAGS="-L$BOOST_ROOT/stage/lib"
-						BOOST_ROOT_PATH="$BOOST_ROOT"
-					fi
-				fi
-	    		fi
-		fi
-
-		CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
-		export CPPFLAGS
-		LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
-		export LDFLAGS
-		export BOOST_ROOT_PATH
-
-		AC_LANG_PUSH(C++)
-	     	AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-		@%:@include <boost/version.hpp>
-		]], [[
-		#if BOOST_VERSION >= $WANT_BOOST_VERSION
-		// Everything is okay
-		#else
-		#  error Boost version is too old
-		#endif
-		]])],[
-        	AC_MSG_RESULT(yes)
-		succeeded=yes
-		found_system=yes
-       		],[
-	       	])
-		AC_LANG_POP([C++])
-	fi
-
-	if test "$succeeded" != "yes" ; then
-		if test "$_version" = "0" ; then
-			AC_MSG_WARN([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option.  If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
-		else
-			AC_MSG_WARN([Your boost libraries seems to old (version $_version).])
-		fi
-	else
-		AC_SUBST(BOOST_CPPFLAGS)
-		AC_SUBST(BOOST_LDFLAGS)
-		AC_SUBST(BOOST_ROOT_PATH)
-		AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available])
-	fi
-
+    dnl if we found no boost with system layout we search for boost libraries
+    dnl built and installed without the --layout=system option or for a staged(not installed) version
+    if test "x$succeeded" != "xyes" ; then
         CPPFLAGS="$CPPFLAGS_SAVED"
-       	LDFLAGS="$LDFLAGS_SAVED"
-fi
+        LDFLAGS="$LDFLAGS_SAVED"
+        BOOST_CPPFLAGS=
+        if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
+            BOOST_LDFLAGS=
+        fi
+        _version=0
+        if test -n "$_AX_BOOST_BASE_boost_path" ; then
+            if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then
+                for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do
+                    _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
+                    V_CHECK=`expr $_version_tmp \> $_version`
+                    if test "x$V_CHECK" = "x1" ; then
+                        _version=$_version_tmp
+                    fi
+                    VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
+                    BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include/boost-$VERSION_UNDERSCORE"
+                done
+                dnl if nothing found search for layout used in Windows distributions
+                if test -z "$BOOST_CPPFLAGS"; then
+                    if test -d "$_AX_BOOST_BASE_boost_path/boost" && test -r "$_AX_BOOST_BASE_boost_path/boost"; then
+                        BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path"
+                    fi
+                fi
+                dnl if we found something and BOOST_LDFLAGS was unset before
+                dnl (because "$_AX_BOOST_BASE_boost_lib_path" = ""), set it here.
+                if test -n "$BOOST_CPPFLAGS" && test -z "$BOOST_LDFLAGS"; then
+                    for libsubdir in $libsubdirs ; do
+                        if ls "$_AX_BOOST_BASE_boost_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
+                    done
+                    BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$libsubdir"
+                fi
+            fi
+        else
+            if test "x$cross_compiling" != "xyes" ; then
+                for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local ; do
+                    if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then
+                        for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do
+                            _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
+                            V_CHECK=`expr $_version_tmp \> $_version`
+                            if test "x$V_CHECK" = "x1" ; then
+                                _version=$_version_tmp
+                                best_path=$_AX_BOOST_BASE_boost_path
+                            fi
+                        done
+                    fi
+                done
+
+                VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
+                BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
+                if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
+                    for libsubdir in $libsubdirs ; do
+                        if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
+                    done
+                    BOOST_LDFLAGS="-L$best_path/$libsubdir"
+                fi
+            fi
+
+            if test -n "$BOOST_ROOT" ; then
+                for libsubdir in $libsubdirs ; do
+                    if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
+                done
+                if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then
+                    version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'`
+                    stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
+                        stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
+                    V_CHECK=`expr $stage_version_shorten \>\= $_version`
+                    if test "x$V_CHECK" = "x1" && test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
+                        AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
+                        BOOST_CPPFLAGS="-I$BOOST_ROOT"
+                        BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir"
+                    fi
+                fi
+            fi
+        fi
+
+        CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+        export CPPFLAGS
+        LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
+        export LDFLAGS
+
+        AC_LANG_PUSH(C++)
+            AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[
+            AC_MSG_RESULT(yes)
+        succeeded=yes
+        found_system=yes
+            ],[
+            ])
+        AC_LANG_POP([C++])
+    fi
+
+    if test "x$succeeded" != "xyes" ; then
+        if test "x$_version" = "x0" ; then
+            AC_MSG_NOTICE([[We could not detect the boost libraries (version $1 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option.  If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
+        else
+            AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).])
+        fi
+        # execute ACTION-IF-NOT-FOUND (if present):
+        ifelse([$3], , :, [$3])
+    else
+        AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available])
+        # execute ACTION-IF-FOUND (if present):
+        ifelse([$2], , :, [$2])
+    fi
+
+    CPPFLAGS="$CPPFLAGS_SAVED"
+    LDFLAGS="$LDFLAGS_SAVED"
 
 ])
diff --git a/aclocal/ax_check_openssl.m4 b/aclocal/ax_check_openssl.m4
index a87c5a6..28e48cb 100644
--- a/aclocal/ax_check_openssl.m4
+++ b/aclocal/ax_check_openssl.m4
@@ -1,5 +1,5 @@
 # ===========================================================================
-#     http://www.gnu.org/software/autoconf-archive/ax_check_openssl.html
+#     https://www.gnu.org/software/autoconf-archive/ax_check_openssl.html
 # ===========================================================================
 #
 # SYNOPSIS
@@ -32,7 +32,7 @@
 #   and this notice are preserved. This file is offered as-is, without any
 #   warranty.
 
-#serial 8
+#serial 10
 
 AU_ALIAS([CHECK_SSL], [AX_CHECK_OPENSSL])
 AC_DEFUN([AX_CHECK_OPENSSL], [
@@ -51,7 +51,7 @@
         ], [
             # if pkg-config is installed and openssl has installed a .pc file,
             # then use that information and don't search ssldirs
-            AC_PATH_PROG([PKG_CONFIG], [pkg-config])
+            AC_CHECK_TOOL([PKG_CONFIG], [pkg-config])
             if test x"$PKG_CONFIG" != x""; then
                 OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null`
                 if test $? = 0; then
diff --git a/aclocal/ax_compare_version.m4 b/aclocal/ax_compare_version.m4
new file mode 100644
index 0000000..9c8e208
--- /dev/null
+++ b/aclocal/ax_compare_version.m4
@@ -0,0 +1,177 @@
+# ===========================================================================
+#    https://www.gnu.org/software/autoconf-archive/ax_compare_version.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+#
+# DESCRIPTION
+#
+#   This macro compares two version strings. Due to the various number of
+#   minor-version numbers that can exist, and the fact that string
+#   comparisons are not compatible with numeric comparisons, this is not
+#   necessarily trivial to do in a autoconf script. This macro makes doing
+#   these comparisons easy.
+#
+#   The six basic comparisons are available, as well as checking equality
+#   limited to a certain number of minor-version levels.
+#
+#   The operator OP determines what type of comparison to do, and can be one
+#   of:
+#
+#    eq  - equal (test A == B)
+#    ne  - not equal (test A != B)
+#    le  - less than or equal (test A <= B)
+#    ge  - greater than or equal (test A >= B)
+#    lt  - less than (test A < B)
+#    gt  - greater than (test A > B)
+#
+#   Additionally, the eq and ne operator can have a number after it to limit
+#   the test to that number of minor versions.
+#
+#    eq0 - equal up to the length of the shorter version
+#    ne0 - not equal up to the length of the shorter version
+#    eqN - equal up to N sub-version levels
+#    neN - not equal up to N sub-version levels
+#
+#   When the condition is true, shell commands ACTION-IF-TRUE are run,
+#   otherwise shell commands ACTION-IF-FALSE are run. The environment
+#   variable 'ax_compare_version' is always set to either 'true' or 'false'
+#   as well.
+#
+#   Examples:
+#
+#     AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8])
+#     AX_COMPARE_VERSION([3.15],[lt],[3.15.8])
+#
+#   would both be true.
+#
+#     AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8])
+#     AX_COMPARE_VERSION([3.15],[gt],[3.15.8])
+#
+#   would both be false.
+#
+#     AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8])
+#
+#   would be true because it is only comparing two minor versions.
+#
+#     AX_COMPARE_VERSION([3.15.7],[eq0],[3.15])
+#
+#   would be true because it is only comparing the lesser number of minor
+#   versions of the two values.
+#
+#   Note: The characters that separate the version numbers do not matter. An
+#   empty string is the same as version 0. OP is evaluated by autoconf, not
+#   configure, so must be a string, not a variable.
+#
+#   The author would like to acknowledge Guido Draheim whose advice about
+#   the m4_case and m4_ifvaln functions make this macro only include the
+#   portions necessary to perform the specific comparison specified by the
+#   OP argument in the final configure script.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Tim Toolan <toolan@ele.uri.edu>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 12
+
+dnl #########################################################################
+AC_DEFUN([AX_COMPARE_VERSION], [
+  AC_REQUIRE([AC_PROG_AWK])
+
+  # Used to indicate true or false condition
+  ax_compare_version=false
+
+  # Convert the two version strings to be compared into a format that
+  # allows a simple string comparison.  The end result is that a version
+  # string of the form 1.12.5-r617 will be converted to the form
+  # 0001001200050617.  In other words, each number is zero padded to four
+  # digits, and non digits are removed.
+  AS_VAR_PUSHDEF([A],[ax_compare_version_A])
+  A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
+                     -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/[[^0-9]]//g'`
+
+  AS_VAR_PUSHDEF([B],[ax_compare_version_B])
+  B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
+                     -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/[[^0-9]]//g'`
+
+  dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary
+  dnl # then the first line is used to determine if the condition is true.
+  dnl # The sed right after the echo is to remove any indented white space.
+  m4_case(m4_tolower($2),
+  [lt],[
+    ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"`
+  ],
+  [gt],[
+    ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"`
+  ],
+  [le],[
+    ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"`
+  ],
+  [ge],[
+    ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"`
+  ],[
+    dnl Split the operator from the subversion count if present.
+    m4_bmatch(m4_substr($2,2),
+    [0],[
+      # A count of zero means use the length of the shorter version.
+      # Determine the number of characters in A and B.
+      ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'`
+      ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'`
+
+      # Set A to no more than B's length and B to no more than A's length.
+      A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"`
+      B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"`
+    ],
+    [[0-9]+],[
+      # A count greater than zero means use only that many subversions
+      A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
+      B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
+    ],
+    [.+],[
+      AC_WARNING(
+        [illegal OP numeric parameter: $2])
+    ],[])
+
+    # Pad zeros at end of numbers to make same length.
+    ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`"
+    B="$B`echo $A | sed 's/./0/g'`"
+    A="$ax_compare_version_tmp_A"
+
+    # Check for equality or inequality as necessary.
+    m4_case(m4_tolower(m4_substr($2,0,2)),
+    [eq],[
+      test "x$A" = "x$B" && ax_compare_version=true
+    ],
+    [ne],[
+      test "x$A" != "x$B" && ax_compare_version=true
+    ],[
+      AC_WARNING([illegal OP parameter: $2])
+    ])
+  ])
+
+  AS_VAR_POPDEF([A])dnl
+  AS_VAR_POPDEF([B])dnl
+
+  dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE.
+  if test "$ax_compare_version" = "true" ; then
+    m4_ifvaln([$4],[$4],[:])dnl
+    m4_ifvaln([$5],[else $5])dnl
+  fi
+]) dnl AX_COMPARE_VERSION
diff --git a/aclocal/ax_cxx_compile_stdcxx.m4 b/aclocal/ax_cxx_compile_stdcxx.m4
new file mode 100644
index 0000000..9e9eaed
--- /dev/null
+++ b/aclocal/ax_cxx_compile_stdcxx.m4
@@ -0,0 +1,948 @@
+# ===========================================================================
+#  https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the specified
+#   version of the C++ standard.  If necessary, add switches to CXX and
+#   CXXCPP to enable support.  VERSION may be '11' (for the C++11 standard)
+#   or '14' (for the C++14 standard).
+#
+#   The second argument, if specified, indicates whether you insist on an
+#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+#   -std=c++11).  If neither is specified, you get whatever works, with
+#   preference for an extended mode.
+#
+#   The third argument, if specified 'mandatory' or if left unspecified,
+#   indicates that baseline support for the specified C++ standard is
+#   required and that the macro should error out if no mode with that
+#   support is found.  If specified 'optional', then configuration proceeds
+#   regardless, after defining HAVE_CXX${VERSION} if and only if a
+#   supporting mode is found.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+#   Copyright (c) 2015 Paul Norman <penorman@mac.com>
+#   Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+#   Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.  This file is offered as-is, without any
+#   warranty.
+
+#serial 10
+
+dnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
+dnl  (serial version number 13).
+
+AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
+  m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
+        [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
+        [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
+        [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$2], [], [],
+        [$2], [ext], [],
+        [$2], [noext], [],
+        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
+        [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
+  AC_LANG_PUSH([C++])dnl
+  ac_success=no
+
+  m4_if([$2], [noext], [], [dnl
+  if test x$ac_success = xno; then
+    for alternative in ${ax_cxx_compile_alternatives}; do
+      switch="-std=gnu++${alternative}"
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                     $cachevar,
+        [ac_save_CXX="$CXX"
+         CXX="$CXX $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXX="$ac_save_CXX"])
+      if eval test x\$$cachevar = xyes; then
+        CXX="$CXX $switch"
+        if test -n "$CXXCPP" ; then
+          CXXCPP="$CXXCPP $switch"
+        fi
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+
+  m4_if([$2], [ext], [], [dnl
+  if test x$ac_success = xno; then
+    dnl HP's aCC needs +std=c++11 according to:
+    dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
+    dnl Cray's crayCC needs "-h std=c++11"
+    for alternative in ${ax_cxx_compile_alternatives}; do
+      for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
+        cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+        AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                       $cachevar,
+          [ac_save_CXX="$CXX"
+           CXX="$CXX $switch"
+           AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+            [eval $cachevar=yes],
+            [eval $cachevar=no])
+           CXX="$ac_save_CXX"])
+        if eval test x\$$cachevar = xyes; then
+          CXX="$CXX $switch"
+          if test -n "$CXXCPP" ; then
+            CXXCPP="$CXXCPP $switch"
+          fi
+          ac_success=yes
+          break
+        fi
+      done
+      if test x$ac_success = xyes; then
+        break
+      fi
+    done
+  fi])
+  AC_LANG_POP([C++])
+  if test x$ax_cxx_compile_cxx$1_required = xtrue; then
+    if test x$ac_success = xno; then
+      AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
+    fi
+  fi
+  if test x$ac_success = xno; then
+    HAVE_CXX$1=0
+    AC_MSG_NOTICE([No compiler with C++$1 support was found])
+  else
+    HAVE_CXX$1=1
+    AC_DEFINE(HAVE_CXX$1,1,
+              [define if the compiler supports basic C++$1 syntax])
+  fi
+  AC_SUBST(HAVE_CXX$1)
+])
+
+
+dnl  Test body for checking C++11 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+)
+
+
+dnl  Test body for checking C++14 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+)
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
+)
+
+dnl  Tests for new features in C++11
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+]])
+
+
+dnl  Tests for new features in C++14
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
+
+// If the compiler admits that it is not ready for C++14, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201402L
+
+#error "This is not a C++14 compiler"
+
+#else
+
+namespace cxx14
+{
+
+  namespace test_polymorphic_lambdas
+  {
+
+    int
+    test()
+    {
+      const auto lambda = [](auto&&... args){
+        const auto istiny = [](auto x){
+          return (sizeof(x) == 1UL) ? 1 : 0;
+        };
+        const int aretiny[] = { istiny(args)... };
+        return aretiny[0];
+      };
+      return lambda(1, 1L, 1.0f, '1');
+    }
+
+  }
+
+  namespace test_binary_literals
+  {
+
+    constexpr auto ivii = 0b0000000000101010;
+    static_assert(ivii == 42, "wrong value");
+
+  }
+
+  namespace test_generalized_constexpr
+  {
+
+    template < typename CharT >
+    constexpr unsigned long
+    strlen_c(const CharT *const s) noexcept
+    {
+      auto length = 0UL;
+      for (auto p = s; *p; ++p)
+        ++length;
+      return length;
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("x") == 1UL, "");
+    static_assert(strlen_c("test") == 4UL, "");
+    static_assert(strlen_c("another\0test") == 7UL, "");
+
+  }
+
+  namespace test_lambda_init_capture
+  {
+
+    int
+    test()
+    {
+      auto x = 0;
+      const auto lambda1 = [a = x](int b){ return a + b; };
+      const auto lambda2 = [a = lambda1(x)](){ return a; };
+      return lambda2();
+    }
+
+  }
+
+  namespace test_digit_separators
+  {
+
+    constexpr auto ten_million = 100'000'000;
+    static_assert(ten_million == 100000000, "");
+
+  }
+
+  namespace test_return_type_deduction
+  {
+
+    auto f(int& x) { return x; }
+    decltype(auto) g(int& x) { return x; }
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static constexpr auto value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static constexpr auto value = true;
+    };
+
+    int
+    test()
+    {
+      auto x = 0;
+      static_assert(is_same<int, decltype(f(x))>::value, "");
+      static_assert(is_same<int&, decltype(g(x))>::value, "");
+      return x;
+    }
+
+  }
+
+}  // namespace cxx14
+
+#endif  // __cplusplus >= 201402L
+
+]])
+
+
+dnl  Tests for new features in C++17
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
+
+// If the compiler admits that it is not ready for C++17, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201703L
+
+#error "This is not a C++17 compiler"
+
+#else
+
+#include <initializer_list>
+#include <utility>
+#include <type_traits>
+
+namespace cxx17
+{
+
+  namespace test_constexpr_lambdas
+  {
+
+    constexpr int foo = [](){return 42;}();
+
+  }
+
+  namespace test::nested_namespace::definitions
+  {
+
+  }
+
+  namespace test_fold_expression
+  {
+
+    template<typename... Args>
+    int multiply(Args... args)
+    {
+      return (args * ... * 1);
+    }
+
+    template<typename... Args>
+    bool all(Args... args)
+    {
+      return (args && ...);
+    }
+
+  }
+
+  namespace test_extended_static_assert
+  {
+
+    static_assert (true);
+
+  }
+
+  namespace test_auto_brace_init_list
+  {
+
+    auto foo = {5};
+    auto bar {5};
+
+    static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
+    static_assert(std::is_same<int, decltype(bar)>::value);
+  }
+
+  namespace test_typename_in_template_template_parameter
+  {
+
+    template<template<typename> typename X> struct D;
+
+  }
+
+  namespace test_fallthrough_nodiscard_maybe_unused_attributes
+  {
+
+    int f1()
+    {
+      return 42;
+    }
+
+    [[nodiscard]] int f2()
+    {
+      [[maybe_unused]] auto unused = f1();
+
+      switch (f1())
+      {
+      case 17:
+        f1();
+        [[fallthrough]];
+      case 42:
+        f1();
+      }
+      return f1();
+    }
+
+  }
+
+  namespace test_extended_aggregate_initialization
+  {
+
+    struct base1
+    {
+      int b1, b2 = 42;
+    };
+
+    struct base2
+    {
+      base2() {
+        b3 = 42;
+      }
+      int b3;
+    };
+
+    struct derived : base1, base2
+    {
+        int d;
+    };
+
+    derived d1 {{1, 2}, {}, 4};  // full initialization
+    derived d2 {{}, {}, 4};      // value-initialized bases
+
+  }
+
+  namespace test_general_range_based_for_loop
+  {
+
+    struct iter
+    {
+      int i;
+
+      int& operator* ()
+      {
+        return i;
+      }
+
+      const int& operator* () const
+      {
+        return i;
+      }
+
+      iter& operator++()
+      {
+        ++i;
+        return *this;
+      }
+    };
+
+    struct sentinel
+    {
+      int i;
+    };
+
+    bool operator== (const iter& i, const sentinel& s)
+    {
+      return i.i == s.i;
+    }
+
+    bool operator!= (const iter& i, const sentinel& s)
+    {
+      return !(i == s);
+    }
+
+    struct range
+    {
+      iter begin() const
+      {
+        return {0};
+      }
+
+      sentinel end() const
+      {
+        return {5};
+      }
+    };
+
+    void f()
+    {
+      range r {};
+
+      for (auto i : r)
+      {
+        [[maybe_unused]] auto v = i;
+      }
+    }
+
+  }
+
+  namespace test_lambda_capture_asterisk_this_by_value
+  {
+
+    struct t
+    {
+      int i;
+      int foo()
+      {
+        return [*this]()
+        {
+          return i;
+        }();
+      }
+    };
+
+  }
+
+  namespace test_enum_class_construction
+  {
+
+    enum class byte : unsigned char
+    {};
+
+    byte foo {42};
+
+  }
+
+  namespace test_constexpr_if
+  {
+
+    template <bool cond>
+    int f ()
+    {
+      if constexpr(cond)
+      {
+        return 13;
+      }
+      else
+      {
+        return 42;
+      }
+    }
+
+  }
+
+  namespace test_selection_statement_with_initializer
+  {
+
+    int f()
+    {
+      return 13;
+    }
+
+    int f2()
+    {
+      if (auto i = f(); i > 0)
+      {
+        return 3;
+      }
+
+      switch (auto i = f(); i + 4)
+      {
+      case 17:
+        return 2;
+
+      default:
+        return 1;
+      }
+    }
+
+  }
+
+  namespace test_template_argument_deduction_for_class_templates
+  {
+
+    template <typename T1, typename T2>
+    struct pair
+    {
+      pair (T1 p1, T2 p2)
+        : m1 {p1},
+          m2 {p2}
+      {}
+
+      T1 m1;
+      T2 m2;
+    };
+
+    void f()
+    {
+      [[maybe_unused]] auto p = pair{13, 42u};
+    }
+
+  }
+
+  namespace test_non_type_auto_template_parameters
+  {
+
+    template <auto n>
+    struct B
+    {};
+
+    B<5> b1;
+    B<'a'> b2;
+
+  }
+
+  namespace test_structured_bindings
+  {
+
+    int arr[2] = { 1, 2 };
+    std::pair<int, int> pr = { 1, 2 };
+
+    auto f1() -> int(&)[2]
+    {
+      return arr;
+    }
+
+    auto f2() -> std::pair<int, int>&
+    {
+      return pr;
+    }
+
+    struct S
+    {
+      int x1 : 2;
+      volatile double y1;
+    };
+
+    S f3()
+    {
+      return {};
+    }
+
+    auto [ x1, y1 ] = f1();
+    auto& [ xr1, yr1 ] = f1();
+    auto [ x2, y2 ] = f2();
+    auto& [ xr2, yr2 ] = f2();
+    const auto [ x3, y3 ] = f3();
+
+  }
+
+  namespace test_exception_spec_type_system
+  {
+
+    struct Good {};
+    struct Bad {};
+
+    void g1() noexcept;
+    void g2();
+
+    template<typename T>
+    Bad
+    f(T*, T*);
+
+    template<typename T1, typename T2>
+    Good
+    f(T1*, T2*);
+
+    static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
+
+  }
+
+  namespace test_inline_variables
+  {
+
+    template<class T> void f(T)
+    {}
+
+    template<class T> inline T g(T)
+    {
+      return T{};
+    }
+
+    template<> inline void f<>(int)
+    {}
+
+    template<> int g<>(int)
+    {
+      return 5;
+    }
+
+  }
+
+}  // namespace cxx17
+
+#endif  // __cplusplus < 201703L
+
+]])
diff --git a/aclocal/ax_cxx_compile_stdcxx_11.m4 b/aclocal/ax_cxx_compile_stdcxx_11.m4
new file mode 100644
index 0000000..1733fd8
--- /dev/null
+++ b/aclocal/ax_cxx_compile_stdcxx_11.m4
@@ -0,0 +1,39 @@
+# =============================================================================
+#  https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
+# =============================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the C++11
+#   standard; if necessary, add switches to CXX and CXXCPP to enable
+#   support.
+#
+#   This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX
+#   macro with the version set to C++11.  The two optional arguments are
+#   forwarded literally as the second and third argument respectively.
+#   Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for
+#   more information.  If you want to use this macro, you also need to
+#   download the ax_cxx_compile_stdcxx.m4 file.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+#   Copyright (c) 2015 Paul Norman <penorman@mac.com>
+#   Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 18
+
+AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX])
+AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])])
diff --git a/aclocal/ax_javac_and_java.m4 b/aclocal/ax_javac_and_java.m4
index fdb4bf0..0203960 100644
--- a/aclocal/ax_javac_and_java.m4
+++ b/aclocal/ax_javac_and_java.m4
@@ -7,7 +7,7 @@
 dnl java command tested.  Otherwise, a hard-coded list will be used.
 dnl Similarly for "JAVAC".
 dnl
-dnl AX_JAVAC_AND_JAVA does not currenly support testing for a particular
+dnl AX_JAVAC_AND_JAVA does not currently support testing for a particular
 dnl Java version, testing for only one of "java" and "javac", or
 dnl compiling or running user-provided Java code.
 dnl
@@ -57,6 +57,10 @@
             echo "Running \"$JAVAC configtest_ax_javac_and_java.java\"" >&AS_MESSAGE_LOG_FD
             if $JAVAC configtest_ax_javac_and_java.java >&AS_MESSAGE_LOG_FD 2>&1 ; then
 
+              # prevent $JAVA VM issues with UTF-8 path names (THRIFT-3271)
+              oLC_ALL="$LC_ALL"
+              LC_ALL=""
+
               IFS=","
               for JAVA in $JAVA_PROGS ; do
                 IFS="$oIFS"
@@ -69,6 +73,10 @@
 
               done
 
+              # restore LC_ALL
+              LC_ALL="$oLC_ALL"
+              oLC_ALL=""
+
             fi
 
           done
@@ -110,7 +118,7 @@
 AC_DEFUN([AX_CHECK_ANT_VERSION],
          [
           AC_MSG_CHECKING(for ant version > $2)
-          ANT_VALID=`expr $($1 -version 2>/dev/null | sed -n 's/.*version \(@<:@0-9\.@:>@*\).*/\1/p') \>= $2`
+          ANT_VALID=`expr "x$(printf "$2\n$($1 -version 2>/dev/null | sed -n 's/.*version \(@<:@0-9\.@:>@*\).*/\1/p')" | sort -t '.' -k 1,1 -k 2,2 -k 3,3 -g | sed -n 1p)" = "x$2"`
           if test "x$ANT_VALID" = "x1" ; then
             AC_MSG_RESULT(yes)
           else
diff --git a/aclocal/ax_lib_event.m4 b/aclocal/ax_lib_event.m4
index 7d2f98a..d4dcdc9 100644
--- a/aclocal/ax_lib_event.m4
+++ b/aclocal/ax_lib_event.m4
@@ -75,7 +75,7 @@
           AC_LANG_PUSH([C])
           dnl This can be changed to AC_LINK_IFELSE if you are cross-compiling,
           dnl but then the version cannot be checked.
-          AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+          AC_LINK_IFELSE([AC_LANG_PROGRAM([[
           #include <sys/types.h>
           #include <event.h>
           ]], [[
@@ -165,7 +165,7 @@
             if test -n "$ax_libevent_path"; then
               AX_LIB_EVENT_DO_CHECK
             else
-              for ax_libevent_path in "" /usr /usr/local /opt /opt/local /opt/libevent "$LIBEVENT_ROOT" ; do
+              for ax_libevent_path in "" $lt_sysroot/usr $lt_sysroot/usr/local $lt_sysroot/opt $lt_sysroot/opt/local $lt_sysroot/opt/libevent "$LIBEVENT_ROOT" ; do
                 AX_LIB_EVENT_DO_CHECK
                 if test "$success" = "yes"; then
                   break;
diff --git a/aclocal/ax_lib_zlib.m4 b/aclocal/ax_lib_zlib.m4
index 8c10ab4..bdb9e11 100644
--- a/aclocal/ax_lib_zlib.m4
+++ b/aclocal/ax_lib_zlib.m4
@@ -73,7 +73,7 @@
           #   (defined in the library).
           AC_LANG_PUSH([C])
           dnl This can be changed to AC_LINK_IFELSE if you are cross-compiling.
-          AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+          AC_LINK_IFELSE([AC_LANG_PROGRAM([[
           #include <zlib.h>
           #if ZLIB_VERNUM >= 0x$WANT_ZLIB_VERSION
           #else
diff --git a/aclocal/ax_lua.m4 b/aclocal/ax_lua.m4
new file mode 100644
index 0000000..5920167
--- /dev/null
+++ b/aclocal/ax_lua.m4
@@ -0,0 +1,664 @@
+# ===========================================================================
+#          https://www.gnu.org/software/autoconf-archive/ax_lua.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
+#   AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
+#   AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
+#   AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
+#
+# DESCRIPTION
+#
+#   Detect a Lua interpreter, optionally specifying a minimum and maximum
+#   version number. Set up important Lua paths, such as the directories in
+#   which to install scripts and modules (shared libraries).
+#
+#   Also detect Lua headers and libraries. The Lua version contained in the
+#   header is checked to match the Lua interpreter version exactly. When
+#   searching for Lua libraries, the version number is used as a suffix.
+#   This is done with the goal of supporting multiple Lua installs (5.1,
+#   5.2, and 5.3 side-by-side).
+#
+#   A note on compatibility with previous versions: This file has been
+#   mostly rewritten for serial 18. Most developers should be able to use
+#   these macros without needing to modify configure.ac. Care has been taken
+#   to preserve each macro's behavior, but there are some differences:
+#
+#   1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as
+#   AX_PROG_LUA with no arguments.
+#
+#   2) AX_LUA_HEADERS now checks that the version number defined in lua.h
+#   matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore
+#   unnecessary, so it is deprecated and does not expand to anything.
+#
+#   3) The configure flag --with-lua-suffix no longer exists; the user
+#   should instead specify the LUA precious variable on the command line.
+#   See the AX_PROG_LUA description for details.
+#
+#   Please read the macro descriptions below for more information.
+#
+#   This file was inspired by Andrew Dalke's and James Henstridge's
+#   python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4
+#   (serial 17). Basically, this file is a mash-up of those two files. I
+#   like to think it combines the best of the two!
+#
+#   AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua
+#   paths. Adds precious variable LUA, which may contain the path of the Lua
+#   interpreter. If LUA is blank, the user's path is searched for an
+#   suitable interpreter.
+#
+#   If MINIMUM-VERSION is supplied, then only Lua interpreters with a
+#   version number greater or equal to MINIMUM-VERSION will be accepted. If
+#   TOO-BIG-VERSION is also supplied, then only Lua interpreters with a
+#   version number greater or equal to MINIMUM-VERSION and less than
+#   TOO-BIG-VERSION will be accepted.
+#
+#   The Lua version number, LUA_VERSION, is found from the interpreter, and
+#   substituted. LUA_PLATFORM is also found, but not currently supported (no
+#   standard representation).
+#
+#   Finally, the macro finds four paths:
+#
+#     luadir             Directory to install Lua scripts.
+#     pkgluadir          $luadir/$PACKAGE
+#     luaexecdir         Directory to install Lua modules.
+#     pkgluaexecdir      $luaexecdir/$PACKAGE
+#
+#   These paths are found based on $prefix, $exec_prefix, Lua's
+#   package.path, and package.cpath. The first path of package.path
+#   beginning with $prefix is selected as luadir. The first path of
+#   package.cpath beginning with $exec_prefix is used as luaexecdir. This
+#   should work on all reasonable Lua installations. If a path cannot be
+#   determined, a default path is used. Of course, the user can override
+#   these later when invoking make.
+#
+#     luadir             Default: $prefix/share/lua/$LUA_VERSION
+#     luaexecdir         Default: $exec_prefix/lib/lua/$LUA_VERSION
+#
+#   These directories can be used by Automake as install destinations. The
+#   variable name minus 'dir' needs to be used as a prefix to the
+#   appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES.
+#
+#   If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is
+#   performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT-
+#   FOUND is blank, then it will default to printing an error. To prevent
+#   the default behavior, give ':' as an action.
+#
+#   AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be
+#   expanded before this macro. Adds precious variable LUA_INCLUDE, which
+#   may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If
+#   LUA_INCLUDE is blank, then this macro will attempt to find suitable
+#   flags.
+#
+#   LUA_INCLUDE can be used by Automake to compile Lua modules or
+#   executables with embedded interpreters. The *_CPPFLAGS variables should
+#   be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE).
+#
+#   This macro searches for the header lua.h (and others). The search is
+#   performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE.
+#   If the search is unsuccessful, then some common directories are tried.
+#   If the headers are then found, then LUA_INCLUDE is set accordingly.
+#
+#   The paths automatically searched are:
+#
+#     * /usr/include/luaX.Y
+#     * /usr/include/lua/X.Y
+#     * /usr/include/luaXY
+#     * /usr/local/include/luaX.Y
+#     * /usr/local/include/lua-X.Y
+#     * /usr/local/include/lua/X.Y
+#     * /usr/local/include/luaXY
+#
+#   (Where X.Y is the Lua version number, e.g. 5.1.)
+#
+#   The Lua version number found in the headers is always checked to match
+#   the Lua interpreter's version number. Lua headers with mismatched
+#   version numbers are not accepted.
+#
+#   If headers are found, then ACTION-IF-FOUND is performed, otherwise
+#   ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then
+#   it will default to printing an error. To prevent the default behavior,
+#   set the action to ':'.
+#
+#   AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be
+#   expanded before this macro. Adds precious variable LUA_LIB, which may
+#   contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank,
+#   then this macro will attempt to find suitable flags.
+#
+#   LUA_LIB can be used by Automake to link Lua modules or executables with
+#   embedded interpreters. The *_LIBADD and *_LDADD variables should be used
+#   for this purpose, e.g. mymod_LIBADD = $(LUA_LIB).
+#
+#   This macro searches for the Lua library. More technically, it searches
+#   for a library containing the function lua_load. The search is performed
+#   with a combination of LIBS, LIBRARY_PATH, and LUA_LIB.
+#
+#   If the search determines that some linker flags are missing, then those
+#   flags will be added to LUA_LIB.
+#
+#   If libraries are found, then ACTION-IF-FOUND is performed, otherwise
+#   ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then
+#   it will default to printing an error. To prevent the default behavior,
+#   set the action to ':'.
+#
+#   AX_LUA_READLINE: Search for readline headers and libraries. Requires the
+#   AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the
+#   Autoconf Archive.
+#
+#   If a readline compatible library is found, then ACTION-IF-FOUND is
+#   performed, otherwise ACTION-IF-NOT-FOUND is performed.
+#
+# LICENSE
+#
+#   Copyright (c) 2015 Reuben Thomas <rrt@sc3d.org>
+#   Copyright (c) 2014 Tim Perkins <tprk77@gmail.com>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 40
+
+dnl =========================================================================
+dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION],
+dnl             [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl =========================================================================
+AC_DEFUN([AX_PROG_LUA],
+[
+  dnl Check for required tools.
+  AC_REQUIRE([AC_PROG_GREP])
+  AC_REQUIRE([AC_PROG_SED])
+
+  dnl Make LUA a precious variable.
+  AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1])
+
+  dnl Find a Lua interpreter.
+  m4_define_default([_AX_LUA_INTERPRETER_LIST],
+    [lua lua5.3 lua53 lua5.2 lua52 lua5.1 lua51 lua50])
+
+  m4_if([$1], [],
+  [ dnl No version check is needed. Find any Lua interpreter.
+    AS_IF([test "x$LUA" = 'x'],
+      [AC_PATH_PROGS([LUA], [_AX_LUA_INTERPRETER_LIST], [:])])
+    ax_display_LUA='lua'
+
+    AS_IF([test "x$LUA" != 'x:'],
+      [ dnl At least check if this is a Lua interpreter.
+        AC_MSG_CHECKING([if $LUA is a Lua interpreter])
+        _AX_LUA_CHK_IS_INTRP([$LUA],
+          [AC_MSG_RESULT([yes])],
+          [ AC_MSG_RESULT([no])
+            AC_MSG_ERROR([not a Lua interpreter])
+          ])
+      ])
+  ],
+  [ dnl A version check is needed.
+    AS_IF([test "x$LUA" != 'x'],
+    [ dnl Check if this is a Lua interpreter.
+      AC_MSG_CHECKING([if $LUA is a Lua interpreter])
+      _AX_LUA_CHK_IS_INTRP([$LUA],
+        [AC_MSG_RESULT([yes])],
+        [ AC_MSG_RESULT([no])
+          AC_MSG_ERROR([not a Lua interpreter])
+        ])
+      dnl Check the version.
+      m4_if([$2], [],
+        [_ax_check_text="whether $LUA version >= $1"],
+        [_ax_check_text="whether $LUA version >= $1, < $2"])
+      AC_MSG_CHECKING([$_ax_check_text])
+      _AX_LUA_CHK_VER([$LUA], [$1], [$2],
+        [AC_MSG_RESULT([yes])],
+        [ AC_MSG_RESULT([no])
+          AC_MSG_ERROR([version is out of range for specified LUA])])
+      ax_display_LUA=$LUA
+    ],
+    [ dnl Try each interpreter until we find one that satisfies VERSION.
+      m4_if([$2], [],
+        [_ax_check_text="for a Lua interpreter with version >= $1"],
+        [_ax_check_text="for a Lua interpreter with version >= $1, < $2"])
+      AC_CACHE_CHECK([$_ax_check_text],
+        [ax_cv_pathless_LUA],
+        [ for ax_cv_pathless_LUA in _AX_LUA_INTERPRETER_LIST none; do
+            test "x$ax_cv_pathless_LUA" = 'xnone' && break
+            _AX_LUA_CHK_IS_INTRP([$ax_cv_pathless_LUA], [], [continue])
+            _AX_LUA_CHK_VER([$ax_cv_pathless_LUA], [$1], [$2], [break])
+          done
+        ])
+      dnl Set $LUA to the absolute path of $ax_cv_pathless_LUA.
+      AS_IF([test "x$ax_cv_pathless_LUA" = 'xnone'],
+        [LUA=':'],
+        [AC_PATH_PROG([LUA], [$ax_cv_pathless_LUA])])
+      ax_display_LUA=$ax_cv_pathless_LUA
+    ])
+  ])
+
+  AS_IF([test "x$LUA" = 'x:'],
+  [ dnl Run any user-specified action, or abort.
+    m4_default([$4], [AC_MSG_ERROR([cannot find suitable Lua interpreter])])
+  ],
+  [ dnl Query Lua for its version number.
+    AC_CACHE_CHECK([for $ax_display_LUA version],
+      [ax_cv_lua_version],
+      [ dnl Get the interpreter version in X.Y format. This should work for
+        dnl interpreters version 5.0 and beyond.
+        ax_cv_lua_version=[`$LUA -e '
+          -- return a version number in X.Y format
+          local _, _, ver = string.find(_VERSION, "^Lua (%d+%.%d+)")
+          print(ver)'`]
+      ])
+    AS_IF([test "x$ax_cv_lua_version" = 'x'],
+      [AC_MSG_ERROR([invalid Lua version number])])
+    AC_SUBST([LUA_VERSION], [$ax_cv_lua_version])
+    AC_SUBST([LUA_SHORT_VERSION], [`echo "$LUA_VERSION" | $SED 's|\.||'`])
+
+    dnl The following check is not supported:
+    dnl At times (like when building shared libraries) you may want to know
+    dnl which OS platform Lua thinks this is.
+    AC_CACHE_CHECK([for $ax_display_LUA platform],
+      [ax_cv_lua_platform],
+      [ax_cv_lua_platform=[`$LUA -e 'print("unknown")'`]])
+    AC_SUBST([LUA_PLATFORM], [$ax_cv_lua_platform])
+
+    dnl Use the values of $prefix and $exec_prefix for the corresponding
+    dnl values of LUA_PREFIX and LUA_EXEC_PREFIX. These are made distinct
+    dnl variables so they can be overridden if need be. However, the general
+    dnl consensus is that you shouldn't need this ability.
+    AC_SUBST([LUA_PREFIX], ['${prefix}'])
+    AC_SUBST([LUA_EXEC_PREFIX], ['${exec_prefix}'])
+
+    dnl Lua provides no way to query the script directory, and instead
+    dnl provides LUA_PATH. However, we should be able to make a safe educated
+    dnl guess. If the built-in search path contains a directory which is
+    dnl prefixed by $prefix, then we can store scripts there. The first
+    dnl matching path will be used.
+    AC_CACHE_CHECK([for $ax_display_LUA script directory],
+      [ax_cv_lua_luadir],
+      [ AS_IF([test "x$prefix" = 'xNONE'],
+          [ax_lua_prefix=$ac_default_prefix],
+          [ax_lua_prefix=$prefix])
+
+        dnl Initialize to the default path.
+        ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION"
+
+        dnl Try to find a path with the prefix.
+        _AX_LUA_FND_PRFX_PTH([$LUA], [$ax_lua_prefix], [script])
+        AS_IF([test "x$ax_lua_prefixed_path" != 'x'],
+        [ dnl Fix the prefix.
+          _ax_strip_prefix=`echo "$ax_lua_prefix" | $SED 's|.|.|g'`
+          ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \
+            $SED "s|^$_ax_strip_prefix|$LUA_PREFIX|"`
+        ])
+      ])
+    AC_SUBST([luadir], [$ax_cv_lua_luadir])
+    AC_SUBST([pkgluadir], [\${luadir}/$PACKAGE])
+
+    dnl Lua provides no way to query the module directory, and instead
+    dnl provides LUA_PATH. However, we should be able to make a safe educated
+    dnl guess. If the built-in search path contains a directory which is
+    dnl prefixed by $exec_prefix, then we can store modules there. The first
+    dnl matching path will be used.
+    AC_CACHE_CHECK([for $ax_display_LUA module directory],
+      [ax_cv_lua_luaexecdir],
+      [ AS_IF([test "x$exec_prefix" = 'xNONE'],
+          [ax_lua_exec_prefix=$ax_lua_prefix],
+          [ax_lua_exec_prefix=$exec_prefix])
+
+        dnl Initialize to the default path.
+        ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION"
+
+        dnl Try to find a path with the prefix.
+        _AX_LUA_FND_PRFX_PTH([$LUA],
+          [$ax_lua_exec_prefix], [module])
+        AS_IF([test "x$ax_lua_prefixed_path" != 'x'],
+        [ dnl Fix the prefix.
+          _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | $SED 's|.|.|g'`
+          ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \
+            $SED "s|^$_ax_strip_prefix|$LUA_EXEC_PREFIX|"`
+        ])
+      ])
+    AC_SUBST([luaexecdir], [$ax_cv_lua_luaexecdir])
+    AC_SUBST([pkgluaexecdir], [\${luaexecdir}/$PACKAGE])
+
+    dnl Run any user specified action.
+    $3
+  ])
+])
+
+dnl AX_WITH_LUA is now the same thing as AX_PROG_LUA.
+AC_DEFUN([AX_WITH_LUA],
+[
+  AC_MSG_WARN([[$0 is deprecated, please use AX_PROG_LUA instead]])
+  AX_PROG_LUA
+])
+
+
+dnl =========================================================================
+dnl _AX_LUA_CHK_IS_INTRP(PROG, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+dnl =========================================================================
+AC_DEFUN([_AX_LUA_CHK_IS_INTRP],
+[
+  dnl A minimal Lua factorial to prove this is an interpreter. This should work
+  dnl for Lua interpreters version 5.0 and beyond.
+  _ax_lua_factorial=[`$1 2>/dev/null -e '
+    -- a simple factorial
+    function fact (n)
+      if n == 0 then
+        return 1
+      else
+        return n * fact(n-1)
+      end
+    end
+    print("fact(5) is " .. fact(5))'`]
+  AS_IF([test "$_ax_lua_factorial" = 'fact(5) is 120'],
+    [$2], [$3])
+])
+
+
+dnl =========================================================================
+dnl _AX_LUA_CHK_VER(PROG, MINIMUM-VERSION, [TOO-BIG-VERSION],
+dnl                 [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+dnl =========================================================================
+AC_DEFUN([_AX_LUA_CHK_VER],
+[
+  dnl Check that the Lua version is within the bounds. Only the major and minor
+  dnl version numbers are considered. This should work for Lua interpreters
+  dnl version 5.0 and beyond.
+  _ax_lua_good_version=[`$1 -e '
+    -- a script to compare versions
+    function verstr2num(verstr)
+      local _, _, majorver, minorver = string.find(verstr, "^(%d+)%.(%d+)")
+      if majorver and minorver then
+        return tonumber(majorver) * 100 + tonumber(minorver)
+      end
+    end
+    local minver = verstr2num("$2")
+    local _, _, trimver = string.find(_VERSION, "^Lua (.*)")
+    local ver = verstr2num(trimver)
+    local maxver = verstr2num("$3") or 1e9
+    if minver <= ver and ver < maxver then
+      print("yes")
+    else
+      print("no")
+    end'`]
+    AS_IF([test "x$_ax_lua_good_version" = "xyes"],
+      [$4], [$5])
+])
+
+
+dnl =========================================================================
+dnl _AX_LUA_FND_PRFX_PTH(PROG, PREFIX, SCRIPT-OR-MODULE-DIR)
+dnl =========================================================================
+AC_DEFUN([_AX_LUA_FND_PRFX_PTH],
+[
+  dnl Get the script or module directory by querying the Lua interpreter,
+  dnl filtering on the given prefix, and selecting the shallowest path. If no
+  dnl path is found matching the prefix, the result will be an empty string.
+  dnl The third argument determines the type of search, it can be 'script' or
+  dnl 'module'. Supplying 'script' will perform the search with package.path
+  dnl and LUA_PATH, and supplying 'module' will search with package.cpath and
+  dnl LUA_CPATH. This is done for compatibility with Lua 5.0.
+
+  ax_lua_prefixed_path=[`$1 -e '
+    -- get the path based on search type
+    local searchtype = "$3"
+    local paths = ""
+    if searchtype == "script" then
+      paths = (package and package.path) or LUA_PATH
+    elseif searchtype == "module" then
+      paths = (package and package.cpath) or LUA_CPATH
+    end
+    -- search for the prefix
+    local prefix = "'$2'"
+    local minpath = ""
+    local mindepth = 1e9
+    string.gsub(paths, "(@<:@^;@:>@+)",
+      function (path)
+        path = string.gsub(path, "%?.*$", "")
+        path = string.gsub(path, "/@<:@^/@:>@*$", "")
+        if string.find(path, prefix) then
+          local depth = string.len(string.gsub(path, "@<:@^/@:>@", ""))
+          if depth < mindepth then
+            minpath = path
+            mindepth = depth
+          end
+        end
+      end)
+    print(minpath)'`]
+])
+
+
+dnl =========================================================================
+dnl AX_LUA_HEADERS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl =========================================================================
+AC_DEFUN([AX_LUA_HEADERS],
+[
+  dnl Check for LUA_VERSION.
+  AC_MSG_CHECKING([if LUA_VERSION is defined])
+  AS_IF([test "x$LUA_VERSION" != 'x'],
+    [AC_MSG_RESULT([yes])],
+    [ AC_MSG_RESULT([no])
+      AC_MSG_ERROR([cannot check Lua headers without knowing LUA_VERSION])
+    ])
+
+  dnl Make LUA_INCLUDE a precious variable.
+  AC_ARG_VAR([LUA_INCLUDE], [The Lua includes, e.g. -I/usr/include/lua5.1])
+
+  dnl Some default directories to search.
+  LUA_SHORT_VERSION=`echo "$LUA_VERSION" | $SED 's|\.||'`
+  m4_define_default([_AX_LUA_INCLUDE_LIST],
+    [ /usr/include/lua$LUA_VERSION \
+      /usr/include/lua-$LUA_VERSION \
+      /usr/include/lua/$LUA_VERSION \
+      /usr/include/lua$LUA_SHORT_VERSION \
+      /usr/local/include/lua$LUA_VERSION \
+      /usr/local/include/lua-$LUA_VERSION \
+      /usr/local/include/lua/$LUA_VERSION \
+      /usr/local/include/lua$LUA_SHORT_VERSION \
+    ])
+
+  dnl Try to find the headers.
+  _ax_lua_saved_cppflags=$CPPFLAGS
+  CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
+  AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
+  CPPFLAGS=$_ax_lua_saved_cppflags
+
+  dnl Try some other directories if LUA_INCLUDE was not set.
+  AS_IF([test "x$LUA_INCLUDE" = 'x' &&
+         test "x$ac_cv_header_lua_h" != 'xyes'],
+    [ dnl Try some common include paths.
+      for _ax_include_path in _AX_LUA_INCLUDE_LIST; do
+        test ! -d "$_ax_include_path" && continue
+
+        AC_MSG_CHECKING([for Lua headers in])
+        AC_MSG_RESULT([$_ax_include_path])
+
+        AS_UNSET([ac_cv_header_lua_h])
+        AS_UNSET([ac_cv_header_lualib_h])
+        AS_UNSET([ac_cv_header_lauxlib_h])
+        AS_UNSET([ac_cv_header_luaconf_h])
+
+        _ax_lua_saved_cppflags=$CPPFLAGS
+        CPPFLAGS="$CPPFLAGS -I$_ax_include_path"
+        AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
+        CPPFLAGS=$_ax_lua_saved_cppflags
+
+        AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'],
+          [ LUA_INCLUDE="-I$_ax_include_path"
+            break
+          ])
+      done
+    ])
+
+  AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'],
+    [ dnl Make a program to print LUA_VERSION defined in the header.
+      dnl TODO It would be really nice if we could do this without compiling a
+      dnl program, then it would work when cross compiling. But I'm not sure how
+      dnl to do this reliably. For now, assume versions match when cross compiling.
+
+      AS_IF([test "x$cross_compiling" != 'xyes'],
+        [ AC_CACHE_CHECK([for Lua header version],
+            [ax_cv_lua_header_version],
+            [ _ax_lua_saved_cppflags=$CPPFLAGS
+              CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
+              AC_RUN_IFELSE(
+                [ AC_LANG_SOURCE([[
+#include <lua.h>
+#include <stdlib.h>
+#include <stdio.h>
+int main(int argc, char ** argv)
+{
+  if(argc > 1) printf("%s", LUA_VERSION);
+  exit(EXIT_SUCCESS);
+}
+]])
+                ],
+                [ ax_cv_lua_header_version=`./conftest$EXEEXT p | \
+                    $SED -n "s|^Lua \(@<:@0-9@:>@\{1,\}\.@<:@0-9@:>@\{1,\}\).\{0,\}|\1|p"`
+                ],
+                [ax_cv_lua_header_version='unknown'])
+              CPPFLAGS=$_ax_lua_saved_cppflags
+            ])
+
+          dnl Compare this to the previously found LUA_VERSION.
+          AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION])
+          AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"],
+            [ AC_MSG_RESULT([yes])
+              ax_header_version_match='yes'
+            ],
+            [ AC_MSG_RESULT([no])
+              ax_header_version_match='no'
+            ])
+        ],
+        [ AC_MSG_WARN([cross compiling so assuming header version number matches])
+          ax_header_version_match='yes'
+        ])
+    ])
+
+  dnl Was LUA_INCLUDE specified?
+  AS_IF([test "x$ax_header_version_match" != 'xyes' &&
+         test "x$LUA_INCLUDE" != 'x'],
+    [AC_MSG_ERROR([cannot find headers for specified LUA_INCLUDE])])
+
+  dnl Test the final result and run user code.
+  AS_IF([test "x$ax_header_version_match" = 'xyes'], [$1],
+    [m4_default([$2], [AC_MSG_ERROR([cannot find Lua includes])])])
+])
+
+dnl AX_LUA_HEADERS_VERSION no longer exists, use AX_LUA_HEADERS.
+AC_DEFUN([AX_LUA_HEADERS_VERSION],
+[
+  AC_MSG_WARN([[$0 is deprecated, please use AX_LUA_HEADERS instead]])
+])
+
+
+dnl =========================================================================
+dnl AX_LUA_LIBS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl =========================================================================
+AC_DEFUN([AX_LUA_LIBS],
+[
+  dnl TODO Should this macro also check various -L flags?
+
+  dnl Check for LUA_VERSION.
+  AC_MSG_CHECKING([if LUA_VERSION is defined])
+  AS_IF([test "x$LUA_VERSION" != 'x'],
+    [AC_MSG_RESULT([yes])],
+    [ AC_MSG_RESULT([no])
+      AC_MSG_ERROR([cannot check Lua libs without knowing LUA_VERSION])
+    ])
+
+  dnl Make LUA_LIB a precious variable.
+  AC_ARG_VAR([LUA_LIB], [The Lua library, e.g. -llua5.1])
+
+  AS_IF([test "x$LUA_LIB" != 'x'],
+  [ dnl Check that LUA_LIBS works.
+    _ax_lua_saved_libs=$LIBS
+    LIBS="$LIBS $LUA_LIB"
+    AC_SEARCH_LIBS([lua_load], [],
+      [_ax_found_lua_libs='yes'],
+      [_ax_found_lua_libs='no'])
+    LIBS=$_ax_lua_saved_libs
+
+    dnl Check the result.
+    AS_IF([test "x$_ax_found_lua_libs" != 'xyes'],
+      [AC_MSG_ERROR([cannot find libs for specified LUA_LIB])])
+  ],
+  [ dnl First search for extra libs.
+    _ax_lua_extra_libs=''
+
+    _ax_lua_saved_libs=$LIBS
+    LIBS="$LIBS $LUA_LIB"
+    AC_SEARCH_LIBS([exp], [m])
+    AC_SEARCH_LIBS([dlopen], [dl])
+    LIBS=$_ax_lua_saved_libs
+
+    AS_IF([test "x$ac_cv_search_exp" != 'xno' &&
+           test "x$ac_cv_search_exp" != 'xnone required'],
+      [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp"])
+
+    AS_IF([test "x$ac_cv_search_dlopen" != 'xno' &&
+           test "x$ac_cv_search_dlopen" != 'xnone required'],
+      [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen"])
+
+    dnl Try to find the Lua libs.
+    _ax_lua_saved_libs=$LIBS
+    LIBS="$LIBS $LUA_LIB"
+    AC_SEARCH_LIBS([lua_load],
+      [ lua$LUA_VERSION \
+        lua$LUA_SHORT_VERSION \
+        lua-$LUA_VERSION \
+        lua-$LUA_SHORT_VERSION \
+        lua \
+      ],
+      [_ax_found_lua_libs='yes'],
+      [_ax_found_lua_libs='no'],
+      [$_ax_lua_extra_libs])
+    LIBS=$_ax_lua_saved_libs
+
+    AS_IF([test "x$ac_cv_search_lua_load" != 'xno' &&
+           test "x$ac_cv_search_lua_load" != 'xnone required'],
+      [LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs"])
+  ])
+
+  dnl Test the result and run user code.
+  AS_IF([test "x$_ax_found_lua_libs" = 'xyes'], [$1],
+    [m4_default([$2], [AC_MSG_ERROR([cannot find Lua libs])])])
+])
+
+
+dnl =========================================================================
+dnl AX_LUA_READLINE([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl =========================================================================
+AC_DEFUN([AX_LUA_READLINE],
+[
+  AX_LIB_READLINE
+  AS_IF([test "x$ac_cv_header_readline_readline_h" != 'x' &&
+         test "x$ac_cv_header_readline_history_h" != 'x'],
+    [ LUA_LIBS_CFLAGS="-DLUA_USE_READLINE $LUA_LIBS_CFLAGS"
+      $1
+    ],
+    [$2])
+])
diff --git a/aclocal/ax_prog_dotnetcore_version.m4 b/aclocal/ax_prog_dotnetcore_version.m4
new file mode 100644
index 0000000..92c7495
--- /dev/null
+++ b/aclocal/ax_prog_dotnetcore_version.m4
@@ -0,0 +1,61 @@
+# ===============================================================================
+#  https://www.gnu.org/software/autoconf-archive/ax_prog_dotnetcore_version.html
+# ===============================================================================
+#
+# SYNOPSIS
+#
+#   AX_PROG_DOTNETCORE_VERSION([VERSION],[ACTION-IF-TRUE],[ACTION-IF-FALSE])
+#
+# DESCRIPTION
+#
+#   Makes sure that .NET Core supports the version indicated. If true the
+#   shell commands in ACTION-IF-TRUE are executed. If not the shell commands
+#   in ACTION-IF-FALSE are run. The $dotnetcore_version variable will be
+#   filled with the detected version.
+#
+#   This macro uses the $DOTNETCORE variable to perform the check. If
+#   $DOTNETCORE is not set prior to calling this macro, the macro will fail.
+#
+#   Example:
+#
+#     AC_PATH_PROG([DOTNETCORE],[dotnet])
+#     AC_PROG_DOTNETCORE_VERSION([1.0.2],[ ... ],[ ... ])
+#
+#   Searches for .NET Core, then checks if at least version 1.0.2 is
+#   present.
+#
+# LICENSE
+#
+#   Copyright (c) 2016 Jens Geyer <jensg@apache.org>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 2
+
+AC_DEFUN([AX_PROG_DOTNETCORE_VERSION],[
+    AC_REQUIRE([AC_PROG_SED])
+
+    AS_IF([test -n "$DOTNETCORE"],[
+        ax_dotnetcore_version="$1"
+
+        AC_MSG_CHECKING([for .NET Core version])
+        dotnetcore_version=`$DOTNETCORE --version 2>&1 | $SED -e 's/\(@<:@0-9@:>@*\.@<:@0-9@:>@*\.@<:@0-9@:>@*\)\(.*\)/\1/'`
+        AC_MSG_RESULT($dotnetcore_version)
+
+	    AC_SUBST([DOTNETCORE_VERSION],[$dotnetcore_version])
+
+        AX_COMPARE_VERSION([$ax_dotnetcore_version],[le],[$dotnetcore_version],[
+	    :
+            $2
+        ],[
+	    :
+            $3
+        ])
+    ],[
+        AC_MSG_WARN([could not find .NET Core])
+        $3
+    ])
+])
diff --git a/aclocal/ax_prog_haxe_version.m4 b/aclocal/ax_prog_haxe_version.m4
new file mode 100644
index 0000000..fcacc67
--- /dev/null
+++ b/aclocal/ax_prog_haxe_version.m4
@@ -0,0 +1,60 @@
+# ===========================================================================
+#   https://www.gnu.org/software/autoconf-archive/ax_prog_haxe_version.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_PROG_HAXE_VERSION([VERSION],[ACTION-IF-TRUE],[ACTION-IF-FALSE])
+#
+# DESCRIPTION
+#
+#   Makes sure that haxe supports the version indicated. If true the shell
+#   commands in ACTION-IF-TRUE are executed. If not the shell commands in
+#   ACTION-IF-FALSE are run. The $HAXE_VERSION variable will be filled with
+#   the detected version.
+#
+#   This macro uses the $HAXE variable to perform the check. If $HAXE is not
+#   set prior to calling this macro, the macro will fail.
+#
+#   Example:
+#
+#     AC_PATH_PROG([HAXE],[haxe])
+#     AC_PROG_HAXE_VERSION([3.1.3],[ ... ],[ ... ])
+#
+#   Searches for Haxe, then checks if at least version 3.1.3 is present.
+#
+# LICENSE
+#
+#   Copyright (c) 2015 Jens Geyer <jensg@apache.org>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 2
+
+AC_DEFUN([AX_PROG_HAXE_VERSION],[
+    AC_REQUIRE([AC_PROG_SED])
+
+    AS_IF([test -n "$HAXE"],[
+        ax_haxe_version="$1"
+
+        AC_MSG_CHECKING([for haxe version])
+        haxe_version=`$HAXE -version 2>&1 | $SED -e 's/^.* \( @<:@0-9@:>@*\.@<:@0-9@:>@*\.@<:@0-9@:>@*\) .*/\1/'`
+        AC_MSG_RESULT($haxe_version)
+
+	    AC_SUBST([HAXE_VERSION],[$haxe_version])
+
+        AX_COMPARE_VERSION([$ax_haxe_version],[le],[$haxe_version],[
+	    :
+            $2
+        ],[
+	    :
+            $3
+        ])
+    ],[
+        AC_MSG_WARN([could not find Haxe])
+        $3
+    ])
+])
diff --git a/aclocal/ax_prog_perl_modules.m4 b/aclocal/ax_prog_perl_modules.m4
index 11a326c..70b3230 100644
--- a/aclocal/ax_prog_perl_modules.m4
+++ b/aclocal/ax_prog_perl_modules.m4
@@ -1,5 +1,5 @@
 # ===========================================================================
-#   http://www.gnu.org/software/autoconf-archive/ax_prog_perl_modules.html
+#   https://www.gnu.org/software/autoconf-archive/ax_prog_perl_modules.html
 # ===========================================================================
 #
 # SYNOPSIS
@@ -32,7 +32,7 @@
 #   and this notice are preserved. This file is offered as-is, without any
 #   warranty.
 
-#serial 7
+#serial 8
 
 AU_ALIAS([AC_PROG_PERL_MODULES], [AX_PROG_PERL_MODULES])
 AC_DEFUN([AX_PROG_PERL_MODULES],[dnl
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100755
index 0000000..e021479
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,110 @@
+#
+# 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.
+#
+
+# build Apache Thrift on AppVeyor - https://ci.appveyor.com
+
+version: '1.0.0.{build}'
+
+shallow_clone: true
+
+os:
+  - Visual Studio 2017
+
+matrix:
+  allow_failures:
+      - PROFILE: CYGWIN
+  fast_finish: true
+
+environment:
+  matrix:
+   - PROFILE: MSVC2017
+     PLATFORM: x64
+     CONFIGURATION: Release
+     BOOST_VERSION: 1.65.1
+     LIBEVENT_VERSION: 2.1.8
+     PYTHON_VERSION: 3.6
+     QT_VERSION: 5.10
+     ZLIB_VERSION: 1.2.11
+     DISABLED_TESTS: StressTestNonBlocking
+
+   - PROFILE: MSVC2013
+     PLATFORM: x86
+     CONFIGURATION: Release
+     BOOST_VERSION: 1.58.0
+     LIBEVENT_VERSION: 2.0.22
+     PYTHON_VERSION: 3.5
+     QT_VERSION: 5.8
+     ZLIB_VERSION: 1.2.8
+     DISABLED_TESTS: StressTestNonBlocking
+     APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+
+   - PROFILE: MINGW
+     PLATFORM: x64
+     CONFIGURATION: RelWithDebInfo
+     DISABLED_TESTS: StressTestNonBlocking
+
+   - PROFILE: CYGWIN
+     PLATFORM: x86
+     CONFIGURATION: RelWithDebInfo
+     DISABLED_TESTS: (ZlibTest|OpenSSLManualInitTest|TNonblockingServerTest|StressTestNonBlocking)
+
+#  - PROFILE: CYGWIN
+#    PLATFORM: x64
+#    CONFIGURATION: RelWithDebInfo
+#    DISABLED_TESTS: (ZlibTest|OpenSSLManualInitTest|TNonblockingServerTest|StressTestNonBlocking)
+
+install:
+  - cd %APPVEYOR_BUILD_FOLDER%
+  - call build\appveyor\%PROFILE:~0,4%-appveyor-install.bat
+  - refreshenv
+
+build_script:
+  - cd %APPVEYOR_BUILD_FOLDER%
+  - call build\appveyor\%PROFILE:~0,4%-appveyor-build.bat
+
+test_script:
+  - cd %APPVEYOR_BUILD_FOLDER%
+  - call build\appveyor\%PROFILE:~0,4%-appveyor-test.bat
+
+
+# artifact capture disabled as it might increase service cost for little gain:
+#
+# artifacts:
+#  - path: local-thrift-inst
+#    name: cmake installed content
+#    type: zip
+#
+#  - path: local-thrift-build\Testing
+#    name: ctest output
+#    type: zip
+
+# RDP support: use one or the other...
+#
+# enables RDP for each build job so you can inspect the environment at the beginning of the job:
+# init:
+#  - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
+#
+# enables RDP at the end of the build job so you can login and re-run
+# commands to see why something failed...
+#on_finish:
+#  - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
+#
+# also need:
+# environment:
+#   APPVEYOR_RDP_PASSWORD: thr1FT2345$xyzZ
diff --git a/bootstrap.sh b/bootstrap.sh
index 0c2b886..2452eea 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -38,9 +38,24 @@
   exit 1
 fi
 
+format_version () {
+    printf "%03d%03d%03d%03d" $(echo $1 | tr '.' ' ');
+}
+
+# we require automake 1.13 or later
+# check must happen externally due to use of newer macro
+AUTOMAKE_VERSION=`automake --version | grep automake | egrep -o '([0-9]{1,}\.)+[0-9]{1,}'`
+if  [ $(format_version $AUTOMAKE_VERSION) -lt $(format_version 1.13) ]; then
+  echo >&2 "automake version $AUTOMAKE_VERSION is too old (need 1.13 or later)"
+  exit 1
+fi
+
+set -e
 autoscan
 $LIBTOOLIZE --copy --automake
 aclocal -I ./aclocal
 autoheader
+sed '/undef VERSION/d' config.hin > config.hin2
+mv config.hin2 config.hin
 autoconf
 automake --copy --add-missing --foreign
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..853b8cb
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,15 @@
+{
+  "name": "thrift",
+  "version": "1.0.0",
+  "homepage": "https://github.com/apache/thrift.git",
+  "authors": [
+    "Apache Thrift <dev@thrift.apache.org>"
+  ],
+  "description": "Apache Thrift",
+  "main": "lib/js/src/thrift.js",
+  "keywords": [
+    "thrift"
+  ],
+  "license": "Apache v2",
+  "ignore": []
+}
diff --git a/build/appveyor/CYGW-appveyor-build.bat b/build/appveyor/CYGW-appveyor-build.bat
new file mode 100644
index 0000000..c226222
--- /dev/null
+++ b/build/appveyor/CYGW-appveyor-build.bat
@@ -0,0 +1,36 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+CD build\appveyor                           || EXIT /B
+CALL cl_banner_build.bat                    || EXIT /B
+CALL cl_setenv.bat                          || EXIT /B
+
+SET CMAKEARGS=^
+  -G'%GENERATOR%' ^
+  -DCMAKE_BUILD_TYPE=%CONFIGURATION% ^
+  -DCMAKE_INSTALL_PREFIX=%INSTDIR% ^
+  -DCMAKE_CXX_EXTENSIONS=ON ^
+  -DCMAKE_CXX_FLAGS="-D_GNU_SOURCE" ^
+  -DCMAKE_CXX_STANDARD=11 ^
+  -DWITH_PYTHON=OFF ^
+  -DWITH_SHARED_LIB=OFF ^
+  -DWITH_STATIC_LIB=ON ^
+  -DWITH_STDTHREADS=ON
+
+@ECHO ON
+%BASH% -lc "mkdir -p %BUILDDIR% && cd %BUILDDIR% && cmake.exe %SRCDIR% %CMAKEARGS% && cmake --build . --config %CONFIGURATION% --target install" || EXIT /B
+@ECHO OFF
diff --git a/build/appveyor/CYGW-appveyor-install.bat b/build/appveyor/CYGW-appveyor-install.bat
new file mode 100644
index 0000000..77db7d4
--- /dev/null
+++ b/build/appveyor/CYGW-appveyor-install.bat
@@ -0,0 +1,34 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+::
+:: Appveyor install script for CYGWIN
+:: Installs third party packages we need for a cmake build
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+CD build\appveyor                          || EXIT /B
+CALL cl_banner_install.bat                 || EXIT /B
+CALL cl_setenv.bat                         || EXIT /B
+CALL cl_showenv.bat                        || EXIT /B
+
+::
+:: Install apt-cyg for package management
+::
+
+%BASH% -lc "wget rawgit.com/transcode-open/apt-cyg/master/apt-cyg && install apt-cyg /bin && rm -f apt-cyg" || EXIT /B
+%BASH% -lc "apt-cyg update" || EXIT /B
+%BASH% -lc "apt-cyg install bison cmake flex gcc-g++ libboost-devel libevent-devel make openssl-devel zlib-devel"
diff --git a/build/appveyor/CYGW-appveyor-test.bat b/build/appveyor/CYGW-appveyor-test.bat
new file mode 100644
index 0000000..b667f9b
--- /dev/null
+++ b/build/appveyor/CYGW-appveyor-test.bat
@@ -0,0 +1,21 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+CD build\appveyor              || EXIT /B
+CALL cl_banner_test.bat        || EXIT /B
+CALL cl_setenv.bat             || EXIT /B
+
+%BASH% -lc "cd %BUILDDIR% && ctest.exe -C %CONFIGURATION% --timeout 300 -VV -E '%DISABLED_TESTS%'" || EXIT /B
diff --git a/build/appveyor/MING-appveyor-build.bat b/build/appveyor/MING-appveyor-build.bat
new file mode 100644
index 0000000..b37a95a
--- /dev/null
+++ b/build/appveyor/MING-appveyor-build.bat
@@ -0,0 +1,36 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+CD build\appveyor                           || EXIT /B
+CALL cl_banner_build.bat                    || EXIT /B
+CALL cl_setenv.bat                          || EXIT /B
+
+SET CMAKEARGS=^
+  -G'%GENERATOR%' ^
+  -DCMAKE_BUILD_TYPE=%CONFIGURATION% ^
+  -DCMAKE_INSTALL_PREFIX=%INSTDIR% ^
+  -DCMAKE_MAKE_PROGRAM=/mingw%NORM_PLATFORM%/bin/mingw32-make ^
+  -DCMAKE_C_COMPILER=/mingw%NORM_PLATFORM%/bin/gcc.exe ^
+  -DCMAKE_CXX_COMPILER=/mingw%NORM_PLATFORM%/bin/g++.exe ^
+  -DOPENSSL_ROOT_DIR=/mingw%NORM_PLATFORM% ^
+  -DWITH_PYTHON=OFF ^
+  -DWITH_SHARED_LIB=OFF ^
+  -DWITH_STATIC_LIB=ON
+
+@ECHO ON
+%BASH% -lc "mkdir -p %BUILDDIR% && cd %BUILDDIR% && cmake.exe %SRCDIR% %CMAKEARGS% && cmake --build . --config %CONFIGURATION% --target install" || EXIT /B
+@ECHO OFF
diff --git a/build/appveyor/MING-appveyor-install.bat b/build/appveyor/MING-appveyor-install.bat
new file mode 100644
index 0000000..1069b05
--- /dev/null
+++ b/build/appveyor/MING-appveyor-install.bat
@@ -0,0 +1,45 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+::
+:: Appveyor install script for MINGW on MSYS2
+:: Installs third party packages we need for a cmake build
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+CD build\appveyor                          || EXIT /B
+CALL cl_banner_install.bat                 || EXIT /B
+CALL cl_setenv.bat                         || EXIT /B
+CALL cl_showenv.bat                        || EXIT /B
+
+SET PACKAGES=^
+  --needed -S bison flex make ^
+  mingw-w64-%MINGWPLAT%-boost ^
+  mingw-w64-%MINGWPLAT%-cmake ^
+  mingw-w64-%MINGWPLAT%-libevent ^
+  mingw-w64-%MINGWPLAT%-openssl ^
+  mingw-w64-%MINGWPLAT%-toolchain ^
+  mingw-w64-%MINGWPLAT%-zlib
+
+::mingw-w64-%MINGWPLAT%-qt5 : WAY too large (1GB download!) - tested in cygwin builds anyway
+
+:: Remove old packages that no longer exist to avoid an error
+%BASH% -lc "pacman --noconfirm --remove libcatgets catgets || true" || EXIT /B
+
+:: Upgrade things
+%BASH% -lc "pacman --noconfirm -Syu %IGNORE%"                       || EXIT /B
+%BASH% -lc "pacman --noconfirm -Su %IGNORE%"                        || EXIT /B
+%BASH% -lc "pacman --noconfirm %PACKAGES%"                          || EXIT /B
\ No newline at end of file
diff --git a/build/appveyor/MING-appveyor-test.bat b/build/appveyor/MING-appveyor-test.bat
new file mode 100644
index 0000000..499c1ff
--- /dev/null
+++ b/build/appveyor/MING-appveyor-test.bat
@@ -0,0 +1,22 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+CD build\appveyor              || EXIT /B
+CALL cl_banner_test.bat        || EXIT /B
+CALL cl_setenv.bat             || EXIT /B
+
+%BASH% -lc "cd %BUILDDIR% && ctest.exe -C %CONFIGURATION% --timeout 300 -VV -E '%DISABLED_TESTS%'" || EXIT /B
diff --git a/build/appveyor/MSVC-appveyor-build.bat b/build/appveyor/MSVC-appveyor-build.bat
new file mode 100644
index 0000000..a4b92a2
--- /dev/null
+++ b/build/appveyor/MSVC-appveyor-build.bat
@@ -0,0 +1,47 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+CD build\appveyor                           || EXIT /B
+CALL cl_banner_build.bat                    || EXIT /B
+CALL cl_setenv.bat                          || EXIT /B
+MKDIR "%BUILDDIR%"                          || EXIT /B
+CD "%BUILDDIR%"                             || EXIT /B
+
+@ECHO ON
+  cmake "%SRCDIR%" ^
+    -G"%GENERATOR%" ^
+	-DBISON_EXECUTABLE=C:\ProgramData\chocolatey\lib\winflexbison3\tools\win_bison.exe ^
+    -DBOOST_ROOT="%BOOST_ROOT%" ^
+    -DBOOST_LIBRARYDIR="%BOOST_LIBRARYDIR%" ^
+    -DCMAKE_BUILD_TYPE="%CONFIGURATION%" ^
+    -DCMAKE_INSTALL_PREFIX="%INSTDIR%" ^
+	-DFLEX_EXECUTABLE=C:\ProgramData\chocolatey\lib\winflexbison3\tools\win_flex.exe ^
+    -DINTTYPES_ROOT="%WIN3P%\msinttypes" ^
+    -DLIBEVENT_ROOT="%WIN3P%\libevent-%LIBEVENT_VERSION%-stable" ^
+    -DOPENSSL_ROOT_DIR="%OPENSSL_ROOT%" ^
+    -DOPENSSL_USE_STATIC_LIBS=OFF ^
+    -DZLIB_LIBRARY="%WIN3P%\zlib-inst\lib\zlib%ZLIB_LIB_SUFFIX%.lib" ^
+    -DZLIB_ROOT="%WIN3P%\zlib-inst" ^
+    -DWITH_PYTHON=%WITH_PYTHON% ^
+    -DWITH_%THREADMODEL%THREADS=ON ^
+    -DWITH_SHARED_LIB=OFF ^
+    -DWITH_STATIC_LIB=ON                    || EXIT /B
+@ECHO OFF
+
+cmake --build . ^
+  --config "%CONFIGURATION%" ^
+  --target INSTALL                          || EXIT /B
diff --git a/build/appveyor/MSVC-appveyor-install.bat b/build/appveyor/MSVC-appveyor-install.bat
new file mode 100644
index 0000000..f973d29
--- /dev/null
+++ b/build/appveyor/MSVC-appveyor-install.bat
@@ -0,0 +1,59 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+::
+:: Appveyor install script for MSVC
+:: Installs (or builds) third party packages we need
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+CD build\appveyor                         || EXIT /B
+CALL cl_banner_install.bat                || EXIT /B
+CALL cl_setenv.bat                        || EXIT /B
+CALL cl_showenv.bat                       || EXIT /B
+MKDIR "%WIN3P%"                           || EXIT /B
+
+choco feature enable -n allowGlobalConfirmation || EXIT /B
+
+:: Things to install when NOT running in appveyor:
+IF "%APPVEYOR_BUILD_ID%" == "" (
+    cup -y chocolatey                     || EXIT /B
+    cinst -y curl                         || EXIT /B
+    cinst -y 7zip                         || EXIT /B
+    cinst -y python3                      || EXIT /B
+    cinst -y openssl.light                || EXIT /B
+)
+
+cinst -y jdk8                             || EXIT /B
+cinst -y winflexbison3                    || EXIT /B
+
+:: zlib - not available through chocolatey
+CD "%APPVEYOR_SCRIPTS%"                   || EXIT /B
+call build-zlib.bat                       || EXIT /B
+
+:: libevent - not available through chocolatey
+CD "%APPVEYOR_SCRIPTS%"                   || EXIT /B
+call build-libevent.bat                   || EXIT /B
+
+:: python packages (correct path to pip set in cl_setenv.bat)
+pip.exe ^
+    install backports.ssl_match_hostname ^
+            ipaddress ^
+            six ^
+            tornado ^
+            twisted                       || EXIT /B
+
+cinst -y ghc                              || EXIT /B
diff --git a/build/appveyor/MSVC-appveyor-test.bat b/build/appveyor/MSVC-appveyor-test.bat
new file mode 100644
index 0000000..3594579
--- /dev/null
+++ b/build/appveyor/MSVC-appveyor-test.bat
@@ -0,0 +1,32 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+@ECHO ON
+SETLOCAL EnableDelayedExpansion
+CD build\appveyor              || EXIT /B
+CALL cl_banner_test.bat        || EXIT /B
+CALL cl_setenv.bat             || EXIT /B
+CD "%BUILDDIR%"                || EXIT /B
+
+DIR C:\libraries
+DIR C:\libraries\boost_1_59_0
+DIR C:\libraries\boost_1_60_0
+DIR C:\libraries\boost_1_62_0
+DIR C:\libraries\boost_1_63_0
+DIR C:\libraries\boost_1_64_0
+
+:: Add directories to the path to find DLLs of third party libraries so tests run properly!
+SET PATH=%BOOST_LIBRARYDIR:/=\%;%OPENSSL_ROOT%\bin;%WIN3P%\zlib-inst\bin;%PATH%
+
+ctest -C %CONFIGURATION% --timeout 300 -VV -E "(%DISABLED_TESTS%)" || EXIT /B
diff --git a/build/appveyor/MSYS-appveyor-build.bat b/build/appveyor/MSYS-appveyor-build.bat
new file mode 100644
index 0000000..4401729
--- /dev/null
+++ b/build/appveyor/MSYS-appveyor-build.bat
@@ -0,0 +1,48 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+CD build\appveyor                           || EXIT /B
+CALL cl_banner_build.bat                    || EXIT /B
+CALL cl_setenv.bat                          || EXIT /B
+
+SET BASH=C:\msys64\usr\bin\bash
+SET CMAKE=/c/msys64/mingw64/bin/cmake.exe
+
+@ECHO ON
+SET CMAKEARGS=-G\"%GENERATOR%\" ^
+  -DBoost_DEBUG=ON ^
+  -DBoost_NAMESPACE=libboost ^
+  -DBOOST_INCLUDEDIR=%BOOST_INCLUDEDIR% ^
+  -DBOOST_LIBRARYDIR=%BOOST_LIBRARYDIR% ^
+  -DCMAKE_BUILD_TYPE=%CONFIGURATION% ^
+  -DCMAKE_C_COMPILER=gcc.exe ^
+  -DCMAKE_CXX_COMPILER=g++.exe ^
+  -DCMAKE_MAKE_PROGRAM=make.exe ^
+  -DCMAKE_INSTALL_PREFIX=%INSTDIR_MSYS% ^
+  -DLIBEVENT_ROOT=%LIBEVENT_ROOT% ^
+  -DOPENSSL_LIBRARIES=%OPENSSL_LIBRARIES% ^
+  -DOPENSSL_ROOT_DIR=%OPENSSL_ROOT% ^
+  -DOPENSSL_USE_STATIC_LIBS=ON ^
+  -DWITH_BOOST_STATIC=ON ^
+  -DWITH_JAVA=OFF ^
+  -DWITH_LIBEVENT=ON ^
+  -DWITH_PYTHON=%WITH_PYTHON% ^
+  -DWITH_SHARED_LIB=OFF ^
+  -DWITH_STATIC_LIB=ON
+
+%BASH% -lc "mkdir %BUILDDIR_MSYS% && cd %BUILDDIR_MSYS% && %CMAKE% %SRCDIR_MSYS% %CMAKEARGS% && %CMAKE% --build . --config %CONFIGURATION% --target install" || EXIT /B
+@ECHO OFF
diff --git a/build/appveyor/MSYS-appveyor-install.bat b/build/appveyor/MSYS-appveyor-install.bat
new file mode 100644
index 0000000..a818df3
--- /dev/null
+++ b/build/appveyor/MSYS-appveyor-install.bat
@@ -0,0 +1,48 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+::
+:: Appveyor install script for MSYS
+:: Installs (or builds) third party packages we need
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+CD build\appveyor                          || EXIT /B
+CALL cl_banner_install.bat                 || EXIT /B
+CALL cl_setenv.bat                         || EXIT /B
+CALL cl_showenv.bat                        || EXIT /B
+
+:: We're going to keep boost at a version cmake understands
+SET BOOSTPKG=mingw-w64-x86_64-boost-1.64.0-3-any.pkg.tar.xz
+SET IGNORE=--ignore mingw-w64-x86_64-boost
+
+SET PACKAGES=^
+  --needed -S bison flex make ^
+  mingw-w64-x86_64-cmake ^
+  mingw-w64-x86_64-libevent ^
+  mingw-w64-x86_64-openssl ^
+  mingw-w64-x86_64-toolchain ^
+  mingw-w64-x86_64-zlib
+
+%BASH% -lc "pacman --noconfirm -Syu %IGNORE%" || EXIT /B
+%BASH% -lc "pacman --noconfirm -Su %IGNORE%"  || EXIT /B
+%BASH% -lc "pacman --noconfirm %PACKAGES%"    || EXIT /B
+
+:: Install a slightly older boost (1.64.0) as cmake 3.10
+:: does not have built-in dependencies for boost 1.66.0 yet
+:: -- this cuts down on build warning output --
+%BASH% -lc "wget http://repo.msys2.org/mingw/x86_64/%BOOSTPKG% && pacman --noconfirm --needed -U %BOOSTPKG% && rm %BOOSTPKG%" || EXIT /B
+
diff --git a/build/appveyor/MSYS-appveyor-test.bat b/build/appveyor/MSYS-appveyor-test.bat
new file mode 100644
index 0000000..0f37ec5
--- /dev/null
+++ b/build/appveyor/MSYS-appveyor-test.bat
@@ -0,0 +1,26 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+CD build\appveyor              || EXIT /B
+CALL cl_banner_test.bat        || EXIT /B
+CALL cl_setenv.bat             || EXIT /B
+CD "%BUILDDIR%"                || EXIT /B
+
+:: randomly fails on mingw; see Jira THRIFT-4106
+SET DISABLED_TESTS=concurrency_test
+
+%BASH% -lc "cd %BUILDDIR_MSYS% && ctest.exe -C %CONFIGURATION% --timeout 300 -VV -E '(%DISABLED_TESTS%)'" || EXIT /B
diff --git a/build/appveyor/README.md b/build/appveyor/README.md
new file mode 100644
index 0000000..1a2aa30
--- /dev/null
+++ b/build/appveyor/README.md
@@ -0,0 +1,34 @@
+<!---
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Appveyor Build
+
+Appveyor is capable of building MSVC 2010 through 2015 as well as
+having the latest MSYS2/MinGW 64-bit environment.  It has many versions
+of boost and python installed as well.  See what appveyor has
+[installed on build workers](https://www.appveyor.com/docs/installed-software/).
+
+We run a matrix build on Appveyor and build the following combinations:
+
+* MinGW x64 (gcc 6.3.0)
+* MSVC 2010 x86, an older boost, an older python
+* MSVC 2015 x86/x64, the latest boost, the latest python
+* MSYS2 x64 (gcc 6.3.0) - this is a work in progress
+
+The Appveyor script takes the first four letters from the PROFILE specified in
+the environment stanza and runs these scripts in order:
+
+????-appveyor-install.bat will install third party libraries and set up the environment
+????-appveyor-build.bat will build with cmake
+????-appveyor-test.bat will run ctest
diff --git a/build/appveyor/build-libevent.bat b/build/appveyor/build-libevent.bat
new file mode 100644
index 0000000..64b635b
--- /dev/null
+++ b/build/appveyor/build-libevent.bat
@@ -0,0 +1,37 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+SETLOCAL EnableDelayedExpansion
+
+SET URLFILE=libevent-%LIBEVENT_VERSION%-stable.tar.gz
+SET URL=https://github.com/libevent/libevent/releases/download/release-%LIBEVENT_VERSION%-stable/%URLFILE%
+
+:: Download - support running a local build or a build in appveyor
+CD "%WIN3P%"                                     || EXIT /B
+IF "%APPVEYOR_BUILD_ID%" == "" (
+    curl -L -f -o "%URLFILE%" "%URL%"
+) ELSE (
+    appveyor DownloadFile "%URL%"
+)
+7z x "%URLFILE%" -so | 7z x -si -ttar > nul      || EXIT /B
+CD "libevent-%LIBEVENT_VERSION%-stable"          || EXIT /B
+nmake -f Makefile.nmake static_libs              || EXIT /B
+
+:: in libevent 2.0 there is no nmake subdirectory in WIN32-Code, but in 2.1 there is
+mkdir lib                                        || EXIT /B
+move *.lib lib\                                  || EXIT /B
+move WIN32-Code\event2\* include\event2\         || move WIN32-Code\nmake\event2\* include\event2\ || EXIT /B
+move *.h include\                                || EXIT /B
+
+ENDLOCAL
diff --git a/build/appveyor/build-zlib.bat b/build/appveyor/build-zlib.bat
new file mode 100644
index 0000000..9195726
--- /dev/null
+++ b/build/appveyor/build-zlib.bat
@@ -0,0 +1,56 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+SETLOCAL EnableDelayedExpansion
+
+SET PACKAGE=zlib-%ZLIB_VERSION%
+SET BUILDDIR=%WIN3P%\zlib-build
+SET INSTDIR=%WIN3P%\zlib-inst
+SET SRCDIR=%WIN3P%\%PACKAGE%
+SET URLFILE=%PACKAGE%.tar.gz
+
+:: This allows us to tolerate when the current version is archived
+SET URL=http://zlib.net/%URLFILE%
+SET FURL=http://zlib.net/fossils/%URLFILE%
+
+:: Download - support running a local build or a build in appveyor
+CD "%WIN3P%"                                                     || EXIT /B
+IF "%APPVEYOR_BUILD_ID%" == "" (
+    curl -L -f -o "%URLFILE%" "%URL%"
+    IF ERRORLEVEL 1 (
+        curl -L -f -o "%URLFILE%" "%FURL%"
+    )
+) ELSE (
+    appveyor DownloadFile "%URL%"
+    IF ERRORLEVEL 1 (
+        appveyor DownloadFile "%FURL%"                           || EXIT /B
+    )
+)
+7z x "%URLFILE%" -so | 7z x -si -ttar > nul                      || EXIT /B
+
+:: Generate
+MKDIR "%BUILDDIR%"                                               || EXIT /B
+CD "%BUILDDIR%"                                                  || EXIT /B
+cmake "%SRCDIR%" ^
+      -G"NMake Makefiles" ^
+      -DCMAKE_INSTALL_PREFIX="%INSTDIR%" ^
+      -DCMAKE_BUILD_TYPE="%CONFIGURATION%"                       || EXIT /B
+
+:: Build
+nmake /fMakefile install                                         || EXIT /B
+IF "%CONFIGURATION%" == "Debug" (
+    COPY "%BUILDDIR%\zlibd.pdb" "%INSTDIR%\bin\"                 || EXIT /B
+)
+
+ENDLOCAL
diff --git a/build/appveyor/cl_banner_apache_thrift.bat b/build/appveyor/cl_banner_apache_thrift.bat
new file mode 100644
index 0000000..78f2a2a
--- /dev/null
+++ b/build/appveyor/cl_banner_apache_thrift.bat
@@ -0,0 +1,24 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+:: A visual indicator in a large log helps you locate things when scanning
+:: http://www.patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Apache%20Thrift
+
+ECHO/
+ECHO    ___                 __         ________       _ _____
+ECHO   / _ | ___  ___ _____/ /  ___   /_  __/ /  ____(_) _/ /_
+ECHO  / __ |/ _ \/ _ `/ __/ _ \/ -_)   / / / _ \/ __/ / _/ __/
+ECHO /_/ |_/ .__/\_,_/\__/_//_/\__/   /_/ /_//_/_/ /_/_/ \__/
+ECHO      /_/
+ECHO/
diff --git a/build/appveyor/cl_banner_build.bat b/build/appveyor/cl_banner_build.bat
new file mode 100644
index 0000000..60272f3
--- /dev/null
+++ b/build/appveyor/cl_banner_build.bat
@@ -0,0 +1,23 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+:: A visual indicator in a large log helps you locate things when scanning
+:: http://www.patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Build
+
+ECHO/
+ECHO    ___       _ __   __
+ECHO   / _ )__ __(_) /__/ /
+ECHO  / _  / // / / / _  /     @@@ BUILD
+ECHO /____/\_,_/_/_/\_,_/
+ECHO/
diff --git a/build/appveyor/cl_banner_install.bat b/build/appveyor/cl_banner_install.bat
new file mode 100644
index 0000000..fde3da2
--- /dev/null
+++ b/build/appveyor/cl_banner_install.bat
@@ -0,0 +1,23 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+:: A visual indicator in a large log helps you locate things when scanning
+:: http://www.patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Install
+
+ECHO/
+ECHO    ____         __       ____
+ECHO   /  _/__  ___ / /____ _/ / /
+ECHO  _/ // _ \(_-^</ __/ _ \/ / /     @@@ INSTALL
+ECHO /___/_//_/___/\__/\_,_/_/_/
+ECHO/
diff --git a/build/appveyor/cl_banner_test.bat b/build/appveyor/cl_banner_test.bat
new file mode 100644
index 0000000..44e2d10
--- /dev/null
+++ b/build/appveyor/cl_banner_test.bat
@@ -0,0 +1,23 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+:: A visual indicator in a large log helps you locate things when scanning
+:: http://www.patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Test
+
+ECHO/
+ECHO  ______        __
+ECHO /_  __/__ ___ / /_
+ECHO  / / / -_^|_-^</ __/     @@@ TEST
+ECHO /_/  \__/___/\__/
+ECHO/
diff --git a/build/appveyor/cl_setcompiler.bat b/build/appveyor/cl_setcompiler.bat
new file mode 100644
index 0000000..733ffc5
--- /dev/null
+++ b/build/appveyor/cl_setcompiler.bat
@@ -0,0 +1,63 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+::
+:: Detect the compiler edition we're building in.
+:: Set the COMPILER environment variable to one of:
+::   gcc   = MinGW / MSYS2 and gcc toolchain
+::   vc100 = Visual Studio 2010
+::   vc110 = Visual Studio 2012
+::   vc120 = Visual Studio 2013
+::   vc140 = Visual Studio 2015
+::   vc141 = Visual Studio 2017
+::
+:: Honors any existing COMPILER environment variable
+::   setting instead of overwriting it, to allow it
+::   to be forced if needed.
+::
+:: Sets ERRORLEVEL to 0 if COMPILER can be determined,
+::                 to 1 if it cannot.
+::
+
+IF DEFINED COMPILER (
+  ECHO [warn ] using existing environment variable COMPILER
+  EXIT /B 0
+)
+
+IF NOT "%PROFILE:~0,4%" == "MSVC" (
+  SET COMPILER=gcc
+) ELSE (
+  CALL :CHECK 16
+  IF !ERRORLEVEL! == 0 (SET COMPILER=vc100)
+  CALL :CHECK 17
+  IF !ERRORLEVEL! == 0 (SET COMPILER=vc110)
+  CALL :CHECK 18
+  IF !ERRORLEVEL! == 0 (SET COMPILER=vc120)
+  CALL :CHECK 19.0
+  IF !ERRORLEVEL! == 0 (SET COMPILER=vc140)
+  CALL :CHECK 19.1
+  IF !ERRORLEVEL! == 0 (SET COMPILER=vc141)
+)
+
+IF NOT DEFINED COMPILER (
+  ECHO [error] unable to determine the compiler edition
+  EXIT /B 1
+)
+
+ECHO [info ] detected compiler edition    %COMPILER%
+EXIT /B 0
+
+:CHECK
+cl /? 2>&1 | findstr /C:"Version %1%" > nul
+EXIT /B
diff --git a/build/appveyor/cl_setenv.bat b/build/appveyor/cl_setenv.bat
new file mode 100644
index 0000000..c33366d
--- /dev/null
+++ b/build/appveyor/cl_setenv.bat
@@ -0,0 +1,121 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+@ECHO OFF
+
+IF "%PROFILE%" == "MSVC2012" (
+  CALL "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" %PLATFORM%
+) ELSE IF "%PROFILE%" == "MSVC2013" (
+  CALL "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %PLATFORM%
+) ELSE IF "%PROFILE%" == "MSVC2015" (
+  CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %PLATFORM%
+) ELSE IF "%PROFILE%" == "MSVC2017" (
+  CALL :SETUPNEWERMSVC    || EXIT /B
+) ELSE IF "%PROFILE%" == "MINGW" (
+  REM Supported, nothing special to do here.
+) ELSE IF "%PROFILE%" == "CYGWIN" (
+  REM Supported, nothing special to do here.
+) ELSE (
+  ECHO Unsupported PROFILE=%PROFILE% or PLATFORM=%PLATFORM%
+  EXIT /B 1
+)
+
+CALL cl_setcompiler.bat   || EXIT /B
+CALL cl_setgenerator.bat  || EXIT /B
+
+SET APPVEYOR_SCRIPTS=%APPVEYOR_BUILD_FOLDER%\build\appveyor
+SET BUILDDIR=%APPVEYOR_BUILD_FOLDER%\..\build\%PROFILE%\%PLATFORM%
+SET INSTDIR=%APPVEYOR_BUILD_FOLDER%\..\build\%PROFILE%\%PLATFORM%
+SET SRCDIR=%APPVEYOR_BUILD_FOLDER%
+
+:: PLATFORM is x64 or x86
+:: NORM_PLATFORM is 64 or 32
+SET NORM_PLATFORM=%PLATFORM:~-2,2%
+IF "%NORM_PLATFORM%" == "86" (SET NORM_PLATFORM=32)
+
+IF "%PROFILE:~0,4%" == "MSVC" (
+
+  :: FindBoost needs forward slashes so cmake doesn't see something as an escaped character
+  SET BOOST_ROOT=C:/Libraries/boost_%BOOST_VERSION:.=_%
+  SET BOOST_LIBRARYDIR=!BOOST_ROOT!/lib%NORM_PLATFORM%-msvc-%COMPILER:~-3,2%.%COMPILER:~-1,1%
+  SET OPENSSL_ROOT=C:\OpenSSL-Win%NORM_PLATFORM%
+  SET WIN3P=%APPVEYOR_BUILD_FOLDER%\thirdparty
+
+  SET THREADMODEL=STD
+
+  IF "%PYTHON_VERSION%" == "" (
+    SET WITH_PYTHON=OFF
+  ) ELSE (
+    SET WITH_PYTHON=ON
+    IF /i "%PLATFORM%" == "x64" SET PTEXT=-x64
+    SET PATH=C:\Python%PYTHON_VERSION:.=%!PTEXT!\scripts;C:\Python%PYTHON_VERSION:.=%!PTEXT!;!PATH!
+  )
+  IF "%CONFIGURATION%" == "Debug" (SET ZLIB_LIB_SUFFIX=d)
+
+  IF NOT "%QT_VERSION%" == "" (
+    IF /i "%PLATFORM%" == "x64" SET QTEXT=_64
+    SET PATH=C:\Qt\%QT_VERSION%\%PROFILE%!QTEXT!\bin;!PATH!
+  )
+
+) ELSE IF "%PROFILE:~0,4%" == "MING" (
+
+  :: PLATFORM = x86 means MINGWPLAT i686
+  :: PLATFORM = x64 means MINGWPLAT x86_64
+  SET MINGWPLAT=x86_64
+  IF "%PLATFORM%" == "x86" (SET MINGWPLAT=i686)
+
+  SET BASH=C:\msys64\usr\bin\bash.exe
+  !BASH! -lc "sed -i '/export PATH=\/mingw32\/bin/d' ~/.bash_profile && sed -i '/export PATH=\/mingw64\/bin/d' ~/.bash_profile && echo 'export PATH=/mingw%NORM_PLATFORM%/bin:$PATH' >> ~/.bash_profile" || EXIT /B
+
+  SET BUILDDIR=%BUILDDIR:\=/%
+  SET BUILDDIR=/c!BUILDDIR:~2!
+  SET INSTDIR=%INSTDIR:\=/%
+  SET INSTDIR=/c!INSTDIR:~2!
+  SET SRCDIR=%SRCDIR:\=/%
+  SET SRCDIR=/c!SRCDIR:~2!
+
+) ELSE IF "%PROFILE:~0,4%" == "CYGW" (
+
+  SET CYGWINROOT=C:\cygwin
+  IF "%PLATFORM%" == "x64" (SET CYGWINROOT=!CYGWINROOT!64)
+
+  SET BASH=!CYGWINROOT!\bin\bash.exe
+  SET SETUP=!CYGWINROOT!\setup-x86
+  IF "%PLATFORM%" == "x64" (SET SETUP=!SETUP!_64)
+  SET SETUP=!SETUP!.exe
+
+  SET BUILDDIR=%BUILDDIR:\=/%
+  SET BUILDDIR=/cygdrive/c!BUILDDIR:~2!
+  SET INSTDIR=%INSTDIR:\=/%
+  SET INSTDIR_CYG=/cygdrive/c!INSTDIR:~2!
+  SET SRCDIR=%SRCDIR:\=/%
+  SET SRCDIR=/cygdrive/c!SRCDIR:~2!
+
+)
+
+GOTO :EOF
+
+:SETUPNEWERMSVC
+  FOR /F "USEBACKQ TOKENS=*" %%i IN (`call "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -version "[15.0,16.0)" -property installationPath`) DO (
+    IF "%MSVCROOT%" == "" (SET MSVCROOT=%%i)
+  )
+  SET MSVCPLAT=x86
+  IF "%PLATFORM%" == "x64" (SET MSVCPLAT=amd64)
+
+  SET CURRENTDIR=%CD%
+  CALL "!MSVCROOT!\Common7\Tools\VsDevCmd.bat" -arch=!MSVCPLAT! || EXIT /B
+  CD %CURRENTDIR%
+  EXIT /B
+
+:EOF
diff --git a/build/appveyor/cl_setgenerator.bat b/build/appveyor/cl_setgenerator.bat
new file mode 100644
index 0000000..5eb6ff3
--- /dev/null
+++ b/build/appveyor/cl_setgenerator.bat
@@ -0,0 +1,79 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+::
+:: Detect the compiler edition we're building in and then
+:: set the GENERATOR environment variable to one of:
+::
+::  Visual Studio 15 2017 [arch] = Generates Visual Studio 2017 project files.
+::                                 Optional [arch] can be "Win64" or "ARM".
+::  Visual Studio 14 2015 [arch] = Generates Visual Studio 2015 project files.
+::                                 Optional [arch] can be "Win64" or "ARM".
+::  Visual Studio 12 2013 [arch] = Generates Visual Studio 2013 project files.
+::                                 Optional [arch] can be "Win64" or "ARM".
+::  Visual Studio 11 2012 [arch] = Generates Visual Studio 2012 project files.
+::                                 Optional [arch] can be "Win64" or "ARM".
+::  Visual Studio 10 2010 [arch] = Generates Visual Studio 2010 project files.
+::                                 Optional [arch] can be "Win64" or "IA64".
+::  MinGW Makefiles              = Generates makefiles for MinGW
+::  MSYS Makefiles               = Generates makefiles for MSYS
+::  Unix Makefiles               = Generates makefiles for CYGWIN
+::
+:: Honors any existing GENERATOR environment variable
+::   setting instead of overwriting it, to allow it
+::   to be forced if needed.
+::
+:: Sets ERRORLEVEL to 0 if GENERATOR can be determined,
+::                 to 1 if it cannot.
+::
+
+IF DEFINED GENERATOR (
+  ECHO [warn ] using existing environment variable GENERATOR
+  EXIT /B 0
+)
+
+
+IF "%PROFILE:~0,4%" == "MING" (
+  SET GENERATOR=MinGW Makefiles
+
+) ELSE IF "%PROFILE:~0,4%" == "CYGW" (
+  SET GENERATOR=Unix Makefiles
+
+) ELSE IF "%PROFILE:~0,4%" == "MSYS" (
+  SET GENERATOR=MSYS Makefiles
+) ELSE (
+  IF /i "%PLATFORM%" == "x64" SET GENARCH= Win64
+  CALL :CHECK 16
+  IF !ERRORLEVEL! == 0 SET GENERATOR=Visual Studio 10 2010!GENARCH!
+  CALL :CHECK 17
+  IF !ERRORLEVEL! == 0 SET GENERATOR=Visual Studio 11 2012!GENARCH!
+  CALL :CHECK 18
+  IF !ERRORLEVEL! == 0 SET GENERATOR=Visual Studio 12 2013!GENARCH!
+  CALL :CHECK 19.0
+  IF !ERRORLEVEL! == 0 SET GENERATOR=Visual Studio 14 2015!GENARCH!
+  CALL :CHECK 19.1
+  IF !ERRORLEVEL! == 0 SET GENERATOR=Visual Studio 15 2017!GENARCH!
+)
+
+IF NOT DEFINED GENERATOR (
+  ECHO [error] unable to determine the CMake generator to use
+  EXIT /B 1
+)
+
+ECHO [info ] using CMake generator        %GENERATOR%
+EXIT /B 0
+
+:CHECK
+cl /? 2>&1 | findstr /C:"Version %1%" > nul
+EXIT /B
diff --git a/build/appveyor/cl_showenv.bat b/build/appveyor/cl_showenv.bat
new file mode 100644
index 0000000..a70a490
--- /dev/null
+++ b/build/appveyor/cl_showenv.bat
@@ -0,0 +1,63 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+ECHO/
+ECHO ===============================================================================
+IF "%PROFILE:~0,4%" == "MSVC" (
+ECHO Versions
+ECHO -------------------------------------------------------------------------------
+ECHO boost                 = %BOOST_VERSION%
+ECHO libevent              = %LIBEVENT_VERSION%
+ECHO python                = %PYTHON_VERSION%
+ECHO qt                    = %QT_VERSION%
+ECHO zlib                  = %ZLIB_VERSION%
+ECHO/
+)
+ECHO Appveyor Variables
+ECHO -------------------------------------------------------------------------------
+ECHO APPVEYOR_BUILD_FOLDER = %APPVEYOR_BUILD_FOLDER%
+ECHO CONFIGURATION         = %CONFIGURATION%
+ECHO PLATFORM              = %PLATFORM%
+ECHO PROFILE               = %PROFILE%
+ECHO/
+ECHO Our Variables
+ECHO -------------------------------------------------------------------------------
+ECHO APPVEYOR_SCRIPTS      = %APPVEYOR_SCRIPTS%
+ECHO BASH                  = %BASH%
+ECHO BOOST_ROOT            = %BOOST_ROOT%
+ECHO BOOST_INCLUDEDIR      = %BOOST_INCLUDEDIR%
+ECHO BOOST_LIBRARYDIR      = %BOOST_LIBRARYDIR%
+ECHO BUILDDIR              = %BUILDDIR%
+ECHO COMPILER              = %COMPILER%
+ECHO GENERATOR             = %GENERATOR%
+ECHO INSTDIR               = %INSTDIR%
+ECHO JAVA_HOME             = %JAVA_HOME%
+ECHO OPENSSL_ROOT          = %OPENSSL_ROOT%
+ECHO SETUP                 = %SETUP%
+ECHO SRCDIR                = %SRCDIR%
+ECHO WIN3P                 = %WIN3P%
+ECHO WITH_PYTHON           = %WITH_PYTHON%
+ECHO ZLIB_STATIC_SUFFIX    = %ZLIB_STATIC_SUFFIX%
+IF NOT "%PROFILE:~0,4%" == "MSVC" (
+  ECHO/
+  ECHO UNIXy PATH
+  ECHO -------------------------------------------------------------------------------
+  %BASH% -lc "echo $PATH"
+)
+ECHO/
+ECHO Windows PATH
+ECHO -------------------------------------------------------------------------------
+ECHO %PATH%
+ECHO ===============================================================================
+ECHO/
diff --git a/build/appveyor/simulate-appveyor.bat b/build/appveyor/simulate-appveyor.bat
new file mode 100644
index 0000000..8674f40
--- /dev/null
+++ b/build/appveyor/simulate-appveyor.bat
@@ -0,0 +1,35 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::     http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+::
+
+::
+:: Helps build thrift by pretending to be appveyor
+:: Usage:
+::   cd build\appveyor
+::   simulate-appveyor.bat [Debug|Release] [x86|x64] [CYGWIN|MINGW|MSVC201?]
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+SET APPVEYOR_BUILD_FOLDER=%~dp0..\..
+SET CONFIGURATION=%1
+SET PLATFORM=%2
+SET PROFILE=%3
+
+CD %APPVEYOR_BUILD_FOLDER%
+CALL build\appveyor\%PROFILE:~0,4%-appveyor-install.bat || EXIT /B
+CD %APPVEYOR_BUILD_FOLDER%
+CALL build\appveyor\%PROFILE:~0,4%-appveyor-build.bat   || EXIT /B
+CD %APPVEYOR_BUILD_FOLDER%
+CALL build\appveyor\%PROFILE:~0,4%-appveyor-test.bat
diff --git a/build/cmake/CPackConfig.cmake b/build/cmake/CPackConfig.cmake
new file mode 100644
index 0000000..fdc1b4e
--- /dev/null
+++ b/build/cmake/CPackConfig.cmake
@@ -0,0 +1,68 @@
+#
+# 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.
+#
+
+
+#TODO: Should we bundle system libraries for DLLs?
+#include(InstallRequiredSystemLibraries)
+
+# For help take a look at:
+# http://www.cmake.org/Wiki/CMake:CPackConfiguration
+
+### general settings
+set(CPACK_PACKAGE_NAME "thrift")
+set(CPACK_PACKAGE_VERSION "${PACKAGE_VERSION}")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Apache Thrift")
+set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
+set(CPACK_PACKAGE_VENDOR "Apache Software Foundation")
+set(CPACK_PACKAGE_CONTACT "dev@thrift.apache.org")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}")
+set(CPACK_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}")
+
+### versions
+set(CPACK_PACKAGE_VERSION_MAJOR ${thrift_VERSION_MAJOR})
+set(CPACK_PACKAGE_VERSION_MINOR ${thrift_VERSION_MINOR})
+set(CPACK_PACKAGE_VERSION_PATCH ${thrift_VERSION_PATCH})
+
+### source generator
+set(CPACK_SOURCE_GENERATOR "TGZ")
+set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;tags;cscope.*")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
+
+### zip generator
+set(CPACK_GENERATOR "ZIP")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "thrift")
+
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+    set(CPACK_GENERATOR "NSIS")
+    set(CPACK_NSIS_HELP_LINK "http://thrift.apache.org")
+    set(CPACK_NSIS_MENU_LINKS
+        "http://thrift.apache.org" "Apache Thrift - Web Site"
+        "https://issues.apache.org/jira/browse/THRIFT" "Apache Thrift - Issues")
+    set(CPACK_NSIS_CONTACT ${CPACK_PACKAGE_CONTACT})
+    set(CPACK_NSIS_MODIFY_PATH "ON")
+    set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}")
+else()
+    set(CPACK_GENERATOR "DEB" )
+    set(CPACK_DEBIAN_PACKAGE_MAINTAINER ${CPACK_PACKAGE_CONTACT})
+endif()
+
+
+include(CPack)
diff --git a/build/cmake/ConfigureChecks.cmake b/build/cmake/ConfigureChecks.cmake
new file mode 100644
index 0000000..457bfe0
--- /dev/null
+++ b/build/cmake/ConfigureChecks.cmake
@@ -0,0 +1,79 @@
+#
+# 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.
+#
+
+include(CheckFunctionExists)
+include(CheckIncludeFile)
+include(CheckIncludeFiles)
+include(CheckSymbolExists)
+
+if (Inttypes_FOUND)
+  # This allows the inttypes.h and stdint.h checks to succeed on platforms that
+  # do not natively provide there.
+  set (CMAKE_REQUIRED_INCLUDES ${INTTYPES_INCLUDE_DIRS})
+endif ()
+
+check_include_file(arpa/inet.h HAVE_ARPA_INET_H)
+check_include_file(fcntl.h HAVE_FCNTL_H)
+check_include_file(getopt.h HAVE_GETOPT_H)
+check_include_file(inttypes.h HAVE_INTTYPES_H)
+check_include_file(netdb.h HAVE_NETDB_H)
+check_include_file(netinet/in.h HAVE_NETINET_IN_H)
+check_include_file(signal.h HAVE_SIGNAL_H)
+check_include_file(stdint.h HAVE_STDINT_H)
+check_include_file(unistd.h HAVE_UNISTD_H)
+check_include_file(pthread.h HAVE_PTHREAD_H)
+check_include_file(sys/ioctl.h HAVE_SYS_IOCTL_H)
+check_include_file(sys/param.h HAVE_SYS_PARAM_H)
+check_include_file(sys/resource.h HAVE_SYS_RESOURCE_H)
+check_include_file(sys/socket.h HAVE_SYS_SOCKET_H)
+check_include_file(sys/stat.h HAVE_SYS_STAT_H)
+check_include_file(sys/time.h HAVE_SYS_TIME_H)
+check_include_file(sys/un.h HAVE_SYS_UN_H)
+check_include_file(poll.h HAVE_POLL_H)
+check_include_file(sys/poll.h HAVE_SYS_POLL_H)
+check_include_file(sys/select.h HAVE_SYS_SELECT_H)
+check_include_file(sched.h HAVE_SCHED_H)
+check_include_file(string.h HAVE_STRING_H)
+check_include_file(strings.h HAVE_STRINGS_H)
+
+check_function_exists(gethostbyname HAVE_GETHOSTBYNAME)
+check_function_exists(gethostbyname_r HAVE_GETHOSTBYNAME_R)
+check_function_exists(strerror_r HAVE_STRERROR_R)
+check_function_exists(sched_get_priority_max HAVE_SCHED_GET_PRIORITY_MAX)
+check_function_exists(sched_get_priority_min HAVE_SCHED_GET_PRIORITY_MIN)
+
+include(CheckCSourceCompiles)
+include(CheckCXXSourceCompiles)
+
+check_cxx_source_compiles(
+  "
+  #include <string.h>
+  int main(){char b;char *a = strerror_r(0, &b, 0); return(0);}
+  "
+  STRERROR_R_CHAR_P)
+
+
+set(PACKAGE ${PACKAGE_NAME})
+set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
+set(VERSION ${thrift_VERSION})
+
+# generate a config.h file
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/thrift/config.h")
+
+include_directories("${CMAKE_CURRENT_BINARY_DIR}")
diff --git a/build/cmake/DefineCMakeDefaults.cmake b/build/cmake/DefineCMakeDefaults.cmake
new file mode 100644
index 0000000..93255e0
--- /dev/null
+++ b/build/cmake/DefineCMakeDefaults.cmake
@@ -0,0 +1,90 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
+# Always include srcdir and builddir in include path
+# This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY} in
+# about every subdir
+# since cmake 2.4.0
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+# Put the include dirs which are in the source or build tree
+# before all other include dirs, so the headers in the sources
+# are preferred over the already installed ones
+# since cmake 2.4.1
+set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)
+
+# Use colored output
+# since cmake 2.4.0
+set(CMAKE_COLOR_MAKEFILE ON)
+
+# Define the generic version of the libraries here
+set(GENERIC_LIB_VERSION "1.0.0")
+set(GENERIC_LIB_SOVERSION "0")
+
+# Set the default build type to release with debug info
+if (NOT CMAKE_BUILD_TYPE)
+  set(CMAKE_BUILD_TYPE RelWithDebInfo
+    CACHE STRING
+      "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
+  )
+endif (NOT CMAKE_BUILD_TYPE)
+
+# Create the compile command database for clang by default
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+# Put the libraries and binaries that get built into directories at the
+# top of the build tree rather than in hard-to-find leaf
+# directories. This simplifies manual testing and the use of the build
+# tree rather than installed thrift libraries.
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+#
+# "rpath" support.
+# See http://www.itk.org/Wiki/index.php?title=CMake_RPATH_handling
+#
+# On MacOSX, for shared libraries, enable rpath support.
+set(CMAKE_MACOSX_RPATH TRUE)
+#
+# On any OS, for executables, allow linking with shared libraries in non-system
+# locations and running the executables without LD_PRELOAD or similar.
+# This requires the library to be built with rpath support.
+set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+
+#
+# C++ Language Level Defaults - this depends on the compiler capabilities
+#
+if (NOT DEFINED CMAKE_CXX_STANDARD)
+  set(CMAKE_CXX_STANDARD 11) # C++11
+  message(STATUS "Setting C++11 as the default language level.")
+  message(STATUS "To specify a different C++ language level, set CMAKE_CXX_STANDARD")
+endif()
+
+if (CMAKE_CXX_STANDARD EQUAL 98)
+  message(FATAL_ERROR "only C++11 or above C++ standard is supported")
+elseif (CMAKE_CXX_STANDARD EQUAL 11)
+  # should not fallback to C++98
+  set(CMAKE_CXX_STANDARD_REQUIRED ON)
+endif()
+
+if (NOT DEFINED CMAKE_CXX_EXTENSIONS)
+  set(CMAKE_CXX_EXTENSIONS OFF)        # use standards compliant language level for portability
+endif()
diff --git a/build/cmake/DefineInstallationPaths.cmake b/build/cmake/DefineInstallationPaths.cmake
new file mode 100644
index 0000000..122f0f6
--- /dev/null
+++ b/build/cmake/DefineInstallationPaths.cmake
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+
+# Define the default install paths
+set(BIN_INSTALL_DIR "bin" CACHE PATH "The binary install dir (default: bin)")
+set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "The library install dir (default: lib${LIB_SUFFIX})")
+set(INCLUDE_INSTALL_DIR "include" CACHE PATH "The library install dir (default: include)")
+set(CMAKE_INSTALL_DIR "cmake" CACHE PATH "The subdirectory to install cmake config files (default: cmake)")
+set(DOC_INSTALL_DIR "share/doc" CACHE PATH "The subdirectory to install documentation files (default: share/doc)")
diff --git a/build/cmake/DefineOptions.cmake b/build/cmake/DefineOptions.cmake
new file mode 100644
index 0000000..9aff53c
--- /dev/null
+++ b/build/cmake/DefineOptions.cmake
@@ -0,0 +1,204 @@
+#
+# 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.
+#
+
+
+include(CMakeDependentOption)
+
+set(THRIFT_COMPILER "" CACHE FILEPATH "External Thrift compiler to use during build")
+
+# Additional components
+option(BUILD_COMPILER "Build Thrift compiler" ON)
+
+if(BUILD_COMPILER OR EXISTS ${THRIFT_COMPILER})
+    set(HAVE_COMPILER ON)
+endif()
+CMAKE_DEPENDENT_OPTION(BUILD_TESTING "Build with unit tests" ON "HAVE_COMPILER" OFF)
+CMAKE_DEPENDENT_OPTION(BUILD_EXAMPLES "Build examples" ON "HAVE_COMPILER" OFF)
+CMAKE_DEPENDENT_OPTION(BUILD_TUTORIALS "Build Thrift tutorials" ON "HAVE_COMPILER" OFF)
+option(BUILD_LIBRARIES "Build Thrift libraries" ON)
+
+# Libraries to build
+
+# Each language library can be enabled or disabled using the WITH_<LANG> flag.
+# By default CMake checks if the required dependencies for a language are present
+# and enables the library if all are found. This means the default is to build as
+# much as possible but leaving out libraries if their dependencies are not met.
+
+option(WITH_BOOST_STATIC "Build with Boost static link library" OFF)
+set(Boost_USE_STATIC_LIBS ${WITH_BOOST_STATIC})
+if (NOT WITH_BOOST_STATIC)
+    add_definitions(-DBOOST_ALL_DYN_LINK)
+    add_definitions(-DBOOST_TEST_DYN_LINK)
+endif()
+
+# C++
+option(WITH_CPP "Build C++ Thrift library" ON)
+if(WITH_CPP)
+    find_package(Boost 1.53 QUIET)
+    # NOTE: Currently the following options are C++ specific,
+    # but in future other libraries might reuse them.
+    # So they are not dependent on WITH_CPP but setting them without WITH_CPP currently
+    # has no effect.
+    if(ZLIB_LIBRARY)
+        # FindZLIB.cmake does not normalize path so we need to do it ourselves.
+        file(TO_CMAKE_PATH ${ZLIB_LIBRARY} ZLIB_LIBRARY)
+    endif()
+    find_package(ZLIB QUIET)
+    CMAKE_DEPENDENT_OPTION(WITH_ZLIB "Build with ZLIB support" ON
+                           "ZLIB_FOUND" OFF)
+    find_package(Libevent QUIET)
+    CMAKE_DEPENDENT_OPTION(WITH_LIBEVENT "Build with libevent support" ON
+                           "Libevent_FOUND" OFF)
+    find_package(Qt4 QUIET COMPONENTS QtCore QtNetwork)
+    CMAKE_DEPENDENT_OPTION(WITH_QT4 "Build with Qt4 support" ON
+                           "QT4_FOUND" OFF)
+    find_package(Qt5 QUIET COMPONENTS Core Network)
+    CMAKE_DEPENDENT_OPTION(WITH_QT5 "Build with Qt5 support" ON
+                           "Qt5_FOUND" OFF)
+    if(${WITH_QT4} AND ${WITH_QT5} AND ${CMAKE_MAJOR_VERSION} LESS 3)
+      # cmake < 3.0.0 causes conflict when building both Qt4 and Qt5
+      set(WITH_QT4 OFF)
+    endif()
+    find_package(OpenSSL QUIET)
+    CMAKE_DEPENDENT_OPTION(WITH_OPENSSL "Build with OpenSSL support" ON
+                           "OPENSSL_FOUND" OFF)
+    option(WITH_STDTHREADS "Build with C++ std::thread support" ON)
+endif()
+CMAKE_DEPENDENT_OPTION(BUILD_CPP "Build C++ library" ON
+                       "BUILD_LIBRARIES;WITH_CPP;Boost_FOUND" OFF)
+CMAKE_DEPENDENT_OPTION(WITH_PLUGIN "Build compiler plugin support" OFF
+                       "BUILD_COMPILER;BUILD_CPP" OFF)
+
+# C GLib
+option(WITH_C_GLIB "Build C (GLib) Thrift library" ON)
+if(WITH_C_GLIB)
+    find_package(GLIB QUIET COMPONENTS gobject)
+endif()
+CMAKE_DEPENDENT_OPTION(BUILD_C_GLIB "Build C (GLib) library" ON
+                       "BUILD_LIBRARIES;WITH_C_GLIB;GLIB_FOUND" OFF)
+
+if(BUILD_CPP)
+    set(boost_components)
+    if(BUILD_TESTING)
+        list(APPEND boost_components system thread)
+    endif()
+    if(BUILD_TESTING)
+        list(APPEND boost_components unit_test_framework filesystem chrono program_options)
+    endif()
+    if(boost_components)
+        find_package(Boost 1.53 REQUIRED COMPONENTS ${boost_components})
+    endif()
+elseif(BUILD_C_GLIB AND BUILD_TESTING)
+    find_package(Boost 1.53 REQUIRED)
+endif()
+
+# Java
+option(WITH_JAVA "Build Java Thrift library" ON)
+if(ANDROID)
+    find_package(Gradle QUIET)
+    CMAKE_DEPENDENT_OPTION(BUILD_JAVA "Build Java library" ON
+                           "BUILD_LIBRARIES;WITH_JAVA;GRADLE_FOUND" OFF)
+else()
+    find_package(Gradlew QUIET)
+    find_package(Java QUIET)
+    CMAKE_DEPENDENT_OPTION(BUILD_JAVA "Build Java library" ON
+                           "BUILD_LIBRARIES;WITH_JAVA;JAVA_FOUND;GRADLEW_FOUND" OFF)
+endif()
+
+# Python
+option(WITH_PYTHON "Build Python Thrift library" ON)
+find_package(PythonInterp QUIET) # for Python executable
+find_package(PythonLibs QUIET) # for Python.h
+CMAKE_DEPENDENT_OPTION(BUILD_PYTHON "Build Python library" ON
+                       "BUILD_LIBRARIES;WITH_PYTHON;PYTHONLIBS_FOUND" OFF)
+
+# Haskell
+option(WITH_HASKELL "Build Haskell Thrift library" ON)
+find_package(GHC QUIET)
+find_package(Cabal QUIET)
+CMAKE_DEPENDENT_OPTION(BUILD_HASKELL "Build GHC library" ON
+                       "BUILD_LIBRARIES;WITH_HASKELL;GHC_FOUND;CABAL_FOUND" OFF)
+
+# Common library options
+option(WITH_SHARED_LIB "Build shared libraries" ON)
+option(WITH_STATIC_LIB "Build static libraries" ON)
+if (NOT WITH_SHARED_LIB AND NOT WITH_STATIC_LIB)
+    message(FATAL_ERROR "Cannot build with both shared and static outputs disabled!")
+endif()
+
+#NOTE: C++ compiler options are defined in the lib/cpp/CMakeLists.txt
+
+# Visual Studio only options
+if(MSVC)
+option(WITH_MT "Build using MT instead of MD (MSVC only)" OFF)
+endif(MSVC)
+
+macro(MESSAGE_DEP flag summary)
+if(NOT ${flag})
+  message(STATUS "   - ${summary}")
+endif()
+endmacro(MESSAGE_DEP flag summary)
+
+macro(PRINT_CONFIG_SUMMARY)
+message(STATUS "----------------------------------------------------------")
+message(STATUS "Thrift version:                               ${thrift_VERSION} (${thrift_VERSION_MAJOR}.${thrift_VERSION_MINOR}.${thrift_VERSION_PATCH})")
+message(STATUS "Thrift package version:                       ${PACKAGE_VERSION}")
+message(STATUS "Build configuration Summary")
+message(STATUS "  Build Thrift compiler:                      ${BUILD_COMPILER}")
+message(STATUS "  Build compiler plugin support:              ${WITH_PLUGIN}")
+message(STATUS "  Build with unit tests:                      ${BUILD_TESTING}")
+MESSAGE_DEP(HAVE_COMPILER "Disabled because BUILD_THRIFT=OFF and no valid THRIFT_COMPILER is given")
+message(STATUS "  Build examples:                             ${BUILD_EXAMPLES}")
+MESSAGE_DEP(HAVE_COMPILER "Disabled because BUILD_THRIFT=OFF and no valid THRIFT_COMPILER is given")
+message(STATUS "  Build Thrift libraries:                     ${BUILD_LIBRARIES}")
+message(STATUS " Language libraries:")
+message(STATUS "  Build C++ library:                          ${BUILD_CPP}")
+MESSAGE_DEP(WITH_CPP "Disabled by WITH_CPP=OFF")
+MESSAGE_DEP(Boost_FOUND "Boost headers missing")
+message(STATUS "    C++ Language Level:                       ${CXX_LANGUAGE_LEVEL}")
+message(STATUS "  Build C (GLib) library:                     ${BUILD_C_GLIB}")
+MESSAGE_DEP(WITH_C_GLIB "Disabled by WITH_C_GLIB=OFF")
+MESSAGE_DEP(GLIB_FOUND "GLib missing")
+message(STATUS "  Build Java library:                         ${BUILD_JAVA}")
+MESSAGE_DEP(WITH_JAVA "Disabled by WITH_JAVA=OFF")
+if(ANDROID)
+    MESSAGE_DEP(GRADLE_FOUND "Gradle missing")
+else()
+    MESSAGE_DEP(JAVA_FOUND "Java Runtime missing")
+    MESSAGE_DEP(GRADLEW_FOUND "Gradle Wrapper missing")
+endif()
+message(STATUS "  Build Python library:                       ${BUILD_PYTHON}")
+MESSAGE_DEP(WITH_PYTHON "Disabled by WITH_PYTHON=OFF")
+MESSAGE_DEP(PYTHONLIBS_FOUND "Python libraries missing")
+message(STATUS "  Build Haskell library:                      ${BUILD_HASKELL}")
+MESSAGE_DEP(WITH_HASKELL "Disabled by WITH_HASKELL=OFF")
+MESSAGE_DEP(GHC_FOUND "GHC missing")
+MESSAGE_DEP(CABAL_FOUND "Cabal missing")
+message(STATUS " Library features:")
+message(STATUS "  Build shared libraries:                     ${WITH_SHARED_LIB}")
+message(STATUS "  Build static libraries:                     ${WITH_STATIC_LIB}")
+message(STATUS "  Build with Boost static link library:       ${WITH_BOOST_STATIC}")
+message(STATUS "  Build with C++ std::thread support:         ${WITH_STDTHREADS}")
+message(STATUS "  Build with libevent support:                ${WITH_LIBEVENT}")
+message(STATUS "  Build with OpenSSL support:                 ${WITH_OPENSSL}")
+message(STATUS "  Build with Qt4 support:                     ${WITH_QT4}")
+message(STATUS "  Build with Qt5 support:                     ${WITH_QT5}")
+message(STATUS "  Build with ZLIB support:                    ${WITH_ZLIB}")
+message(STATUS "----------------------------------------------------------")
+endmacro(PRINT_CONFIG_SUMMARY)
diff --git a/build/cmake/DefinePlatformSpecifc.cmake b/build/cmake/DefinePlatformSpecifc.cmake
new file mode 100644
index 0000000..3f112b6
--- /dev/null
+++ b/build/cmake/DefinePlatformSpecifc.cmake
@@ -0,0 +1,118 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Uncomment this to show some basic cmake variables about platforms
+# include (NewPlatformDebug)
+
+# Visual Studio specific options
+if(MSVC)
+    #For visual studio the library naming is as following:
+    # Dynamic libraries:
+    #  - thrift.dll  for release library
+    #  - thriftd.dll for debug library
+    #
+    # Static libraries:
+    #  - thriftmd.lib for /MD release build
+    #  - thriftmt.lib for /MT release build
+    #
+    #  - thriftmdd.lib for /MD debug build
+    #  - thriftmtd.lib for /MT debug build
+    #
+    # the same holds for other libraries like libthriftz etc.
+
+    # For Debug build types, append a "d" to the library names.
+    set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Set debug library postfix" FORCE)
+    set(CMAKE_RELEASE_POSTFIX "" CACHE STRING "Set release library postfix" FORCE)
+    set(CMAKE_RELWITHDEBINFO_POSTFIX "" CACHE STRING "Set release library postfix" FORCE)
+
+    # Build using /MT option instead of /MD if the WITH_MT options is set
+    if(WITH_MT)
+        set(CompilerFlags
+                CMAKE_CXX_FLAGS
+                CMAKE_CXX_FLAGS_DEBUG
+                CMAKE_CXX_FLAGS_RELEASE
+                CMAKE_CXX_FLAGS_RELWITHDEBINFO
+                CMAKE_C_FLAGS
+                CMAKE_C_FLAGS_DEBUG
+                CMAKE_C_FLAGS_RELEASE
+                CMAKE_C_FLAGS_RELWITHDEBINFO
+                )
+        foreach(CompilerFlag ${CompilerFlags})
+          string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
+        endforeach()
+        set(STATIC_POSTFIX "mt" CACHE STRING "Set static library postfix" FORCE)
+    else(WITH_MT)
+        set(STATIC_POSTFIX "md" CACHE STRING "Set static library postfix" FORCE)
+    endif(WITH_MT)
+
+    # Disable boost auto linking pragmas - cmake includes the right files
+    add_definitions("-DBOOST_ALL_NO_LIB")
+
+    # Windows build does not know how to make a shared library yet
+    # as there are no __declspec(dllexport) or exports files in the project.
+    if (WITH_SHARED_LIB)
+      message (FATAL_ERROR "Windows build does not support shared library output yet, please set -DWITH_SHARED_LIB=off")
+    endif()
+
+    add_definitions("/MP") # parallel build
+    add_definitions("/W3") # warning level 3
+
+    # VS2010 does not provide inttypes which we need for "PRId64" used in many places
+    find_package(Inttypes)
+    if (Inttypes_FOUND)
+      include_directories(${INTTYPES_INCLUDE_DIRS})
+      # OpenSSL conflicts with the definition of PRId64 unless it is defined first
+      add_definitions("/FIinttypes.h")
+    endif ()
+elseif(UNIX)
+  find_program( MEMORYCHECK_COMMAND valgrind )
+  set( MEMORYCHECK_COMMAND_OPTIONS "--gen-suppressions=all --leak-check=full" )
+  set( MEMORYCHECK_SUPPRESSIONS_FILE "${PROJECT_SOURCE_DIR}/test/valgrind.suppress" )
+endif()
+
+add_definitions("-D__STDC_FORMAT_MACROS")
+add_definitions("-D__STDC_LIMIT_MACROS")
+
+# WITH_*THREADS selects which threading library to use
+if(WITH_STDTHREADS)
+  add_definitions("-DUSE_STD_THREAD=1")
+endif()
+
+# C++ Language Level
+set(CXX_LANGUAGE_LEVEL "C++${CMAKE_CXX_STANDARD}")
+if (CMAKE_CXX_STANDARD_REQUIRED)
+  string(CONCAT CXX_LANGUAGE_LEVEL "${CXX_LANGUAGE_LEVEL} [compiler must support it]")
+else()
+  string(CONCAT CXX_LANGUAGE_LEVEL "${CXX_LANGUAGE_LEVEL} [fallback to earlier if compiler does not support it]")
+endif()
+if (CMAKE_CXX_EXTENSIONS)
+  string(CONCAT CXX_LANGUAGE_LEVEL "${CXX_LANGUAGE_LEVEL} [with compiler-specific extensions]")
+endif()
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-register")
+endif()
+
+# Building WITH_PLUGIN requires boost memory operations, for now, and gcc >= 4.8
+if (WITH_PLUGIN)
+  if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8")
+    message(SEND_ERROR "Thrift compiler plug-in support is not possible with older gcc ( < 4.8 ) compiler")
+  endif()
+endif()
+
diff --git a/build/cmake/FindAnt.cmake b/build/cmake/FindAnt.cmake
new file mode 100644
index 0000000..8b0371d
--- /dev/null
+++ b/build/cmake/FindAnt.cmake
@@ -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.
+#
+
+
+#  ANT_FOUND - system has Ant
+#  Ant_EXECUTABLE - the Ant executable
+#
+# It will search the environment variable ANT_HOME if it is set
+
+include(FindPackageHandleStandardArgs)
+
+find_program(Ant_EXECUTABLE NAMES ant PATHS $ENV{ANT_HOME}/bin)
+find_package_handle_standard_args(Ant DEFAULT_MSG Ant_EXECUTABLE)
+mark_as_advanced(Ant_EXECUTABLE)
diff --git a/build/cmake/FindCabal.cmake b/build/cmake/FindCabal.cmake
new file mode 100644
index 0000000..fed337b
--- /dev/null
+++ b/build/cmake/FindCabal.cmake
@@ -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.
+#
+
+
+#  Cabal_FOUND - system has Cabal
+#  Cabal - the Cabal executable
+#
+# It will search the environment variable CABAL_HOME if it is set
+
+include(FindPackageHandleStandardArgs)
+
+find_program(CABAL NAMES cabal PATHS $ENV{HOME}/.cabal/bin $ENV{CABAL_HOME}/bin)
+find_package_handle_standard_args(CABAL DEFAULT_MSG CABAL)
+mark_as_advanced(CABAL)
diff --git a/build/cmake/FindGHC.cmake b/build/cmake/FindGHC.cmake
new file mode 100644
index 0000000..4873847
--- /dev/null
+++ b/build/cmake/FindGHC.cmake
@@ -0,0 +1,36 @@
+#
+# 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.
+#
+
+
+#  GHC_FOUND - system has GHC
+#  GHC - the GHC executable
+#  RUN_HASKELL_FOUND - system has runhaskell
+#  RUN_HASKELL - the runhaskell executable
+#
+# It will search the environment variable GHC_HOME if it is set
+
+include(FindPackageHandleStandardArgs)
+
+find_program(GHC NAMES ghc PATHS $ENV{GHC_HOME}/bin)
+find_package_handle_standard_args(GHC DEFAULT_MSG GHC)
+mark_as_advanced(GHC)
+
+find_program(RUN_HASKELL NAMES runhaskell PATHS $ENV{GHC_HOME}/bin)
+find_package_handle_standard_args(RUN_HASKELL DEFAULT_MSG RUN_HASKELL)
+mark_as_advanced(RUN_HASKELL)
diff --git a/build/cmake/FindGLIB.cmake b/build/cmake/FindGLIB.cmake
new file mode 100644
index 0000000..acbe433
--- /dev/null
+++ b/build/cmake/FindGLIB.cmake
@@ -0,0 +1,122 @@
+# - Try to find Glib and its components (gio, gobject etc)
+# Once done, this will define
+#
+#  GLIB_FOUND - system has Glib
+#  GLIB_INCLUDE_DIRS - the Glib include directories
+#  GLIB_LIBRARIES - link these to use Glib
+#
+# Optionally, the COMPONENTS keyword can be passed to find_package()
+# and Glib components can be looked for.  Currently, the following
+# components can be used, and they define the following variables if
+# found:
+#
+#  gio:             GLIB_GIO_LIBRARIES
+#  gobject:         GLIB_GOBJECT_LIBRARIES
+#  gmodule:         GLIB_GMODULE_LIBRARIES
+#  gthread:         GLIB_GTHREAD_LIBRARIES
+#
+# Note that the respective _INCLUDE_DIR variables are not set, since
+# all headers are in the same directory as GLIB_INCLUDE_DIRS.
+#
+# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
+# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+find_package(PkgConfig)
+pkg_check_modules(PC_GLIB QUIET glib-2.0)
+
+find_library(GLIB_LIBRARIES
+    NAMES glib-2.0
+    HINTS ${PC_GLIB_LIBDIR}
+          ${PC_GLIB_LIBRARY_DIRS}
+)
+
+# Files in glib's main include path may include glibconfig.h, which,
+# for some odd reason, is normally in $LIBDIR/glib-2.0/include.
+get_filename_component(_GLIB_LIBRARY_DIR ${GLIB_LIBRARIES} PATH)
+find_path(GLIBCONFIG_INCLUDE_DIR
+    NAMES glibconfig.h
+    HINTS ${PC_LIBDIR} ${PC_LIBRARY_DIRS} ${_GLIB_LIBRARY_DIR}
+          ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS}
+    PATH_SUFFIXES glib-2.0/include
+)
+
+find_path(GLIB_INCLUDE_DIR
+    NAMES glib.h
+    HINTS ${PC_GLIB_INCLUDEDIR}
+          ${PC_GLIB_INCLUDE_DIRS}
+    PATH_SUFFIXES glib-2.0
+)
+
+set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIBCONFIG_INCLUDE_DIR})
+
+if(GLIBCONFIG_INCLUDE_DIR)
+    # Version detection
+    file(READ "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h" GLIBCONFIG_H_CONTENTS)
+    string(REGEX MATCH "#define GLIB_MAJOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
+    set(GLIB_VERSION_MAJOR "${CMAKE_MATCH_1}")
+    string(REGEX MATCH "#define GLIB_MINOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
+    set(GLIB_VERSION_MINOR "${CMAKE_MATCH_1}")
+    string(REGEX MATCH "#define GLIB_MICRO_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
+    set(GLIB_VERSION_MICRO "${CMAKE_MATCH_1}")
+    set(GLIB_VERSION "${GLIB_VERSION_MAJOR}.${GLIB_VERSION_MINOR}.${GLIB_VERSION_MICRO}")
+endif()
+
+# Additional Glib components.  We only look for libraries, as not all of them
+# have corresponding headers and all headers are installed alongside the main
+# glib ones.
+foreach (_component ${GLIB_FIND_COMPONENTS})
+    if (${_component} STREQUAL "gio")
+        find_library(GLIB_GIO_LIBRARIES NAMES gio-2.0 HINTS ${_GLIB_LIBRARY_DIR})
+        set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GIO_LIBRARIES)
+    elseif (${_component} STREQUAL "gobject")
+        find_library(GLIB_GOBJECT_LIBRARIES NAMES gobject-2.0 HINTS ${_GLIB_LIBRARY_DIR})
+        set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GOBJECT_LIBRARIES)
+    elseif (${_component} STREQUAL "gmodule")
+        find_library(GLIB_GMODULE_LIBRARIES NAMES gmodule-2.0 HINTS ${_GLIB_LIBRARY_DIR})
+        set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GMODULE_LIBRARIES)
+    elseif (${_component} STREQUAL "gthread")
+        find_library(GLIB_GTHREAD_LIBRARIES NAMES gthread-2.0 HINTS ${_GLIB_LIBRARY_DIR})
+        set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GTHREAD_LIBRARIES)
+    elseif (${_component} STREQUAL "gio-unix")
+        # gio-unix is compiled as part of the gio library, but the include paths
+        # are separate from the shared glib ones. Since this is currently only used
+        # by WebKitGTK+ we don't go to extraordinary measures beyond pkg-config.
+        pkg_check_modules(GIO_UNIX QUIET gio-unix-2.0)
+    endif ()
+endforeach ()
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLIB REQUIRED_VARS GLIB_INCLUDE_DIRS GLIB_LIBRARIES ${ADDITIONAL_REQUIRED_VARS}
+                                       VERSION_VAR   GLIB_VERSION)
+
+mark_as_advanced(
+    GLIBCONFIG_INCLUDE_DIR
+    GLIB_GIO_LIBRARIES
+    GLIB_GIO_UNIX_LIBRARIES
+    GLIB_GMODULE_LIBRARIES
+    GLIB_GOBJECT_LIBRARIES
+    GLIB_GTHREAD_LIBRARIES
+    GLIB_INCLUDE_DIR
+    GLIB_INCLUDE_DIRS
+    GLIB_LIBRARIES
+)
diff --git a/build/cmake/FindGradle.cmake b/build/cmake/FindGradle.cmake
new file mode 100644
index 0000000..8845d69
--- /dev/null
+++ b/build/cmake/FindGradle.cmake
@@ -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.
+#
+
+
+#  GRADLE_FOUND - system has Gradle
+#  GRADLE_EXECUTABLE - the Gradle executable
+#
+# It will search the environment variable ANT_HOME if it is set
+
+include(FindPackageHandleStandardArgs)
+
+find_program(GRADLE_EXECUTABLE NAMES gradle PATHS $ENV{GRADLE_HOME}/bin NO_CMAKE_FIND_ROOT_PATH)
+find_package_handle_standard_args(Gradle DEFAULT_MSG GRADLE_EXECUTABLE)
+mark_as_advanced(GRADLE_EXECUTABLE)
diff --git a/build/cmake/FindGradlew.cmake b/build/cmake/FindGradlew.cmake
new file mode 100644
index 0000000..17bb998
--- /dev/null
+++ b/build/cmake/FindGradlew.cmake
@@ -0,0 +1,36 @@
+#
+# 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.
+#
+
+
+#  GRADLEW_FOUND - system has Gradlew
+#  GRADLEW_EXECUTABLE - the Gradlew executable
+#
+# It will search the location CMAKE_SOURCE_DIR/lib/java
+
+include(FindPackageHandleStandardArgs)
+
+find_program(GRADLEW_EXECUTABLE gradlew PATHS ${CMAKE_SOURCE_DIR}/lib/java NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+find_package_handle_standard_args(Gradlew DEFAULT_MSG GRADLEW_EXECUTABLE)
+mark_as_advanced(GRADLEW_EXECUTABLE)
+
+# Buggy find_program cannot find gradlew.bat when gradlew is at the same path
+# and even buggier ctest will not execute gradlew.bat when gradlew is given.
+if(CMAKE_HOST_WIN32)
+    string(REGEX REPLACE "(.+gradlew)$" "\\1.bat" GRADLEW_EXECUTABLE ${GRADLEW_EXECUTABLE})
+endif(CMAKE_HOST_WIN32)
diff --git a/build/cmake/FindInttypes.cmake b/build/cmake/FindInttypes.cmake
new file mode 100644
index 0000000..e661f78
--- /dev/null
+++ b/build/cmake/FindInttypes.cmake
@@ -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.
+#
+
+# find msinttypes on compilers that don't provide it, for example
+#   VS2010
+
+# Usage: 
+# Provide INTTYPES_ROOT if you need it
+# Result: INTTYPES_INCLUDE_DIRS, where to find inttypes.h
+# Result: Inttypes_FOUND, If false, inttypes.h was not found
+
+find_path(INTTYPES_INCLUDE_DIRS inttypes.h HINTS ${INTTYPES_ROOT})
+if (INTTYPES_INCLUDE_DIRS)
+  set(Inttypes_FOUND TRUE)
+else ()
+  set(Inttypes_FOUND FALSE)
+  if (Inttypes_FIND_REQUIRED)
+    message(FATAL_ERROR "Could NOT find inttypes.h")
+  endif ()
+  message(STATUS "inttypes.h NOT found")
+endif ()
+
+mark_as_advanced(
+  INTTYPES_INCLUDE_DIRS
+)
diff --git a/build/cmake/FindLibevent.cmake b/build/cmake/FindLibevent.cmake
new file mode 100644
index 0000000..ac6a078
--- /dev/null
+++ b/build/cmake/FindLibevent.cmake
@@ -0,0 +1,45 @@
+# find LibEvent
+# an event notification library (http://libevent.org/)
+#
+# Usage: 
+# LIBEVENT_INCLUDE_DIRS, where to find LibEvent headers
+# LIBEVENT_LIBRARIES, LibEvent libraries
+# Libevent_FOUND, If false, do not try to use libevent
+
+set(LIBEVENT_ROOT CACHE PATH "Root directory of libevent installation")
+set(LibEvent_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}" ${LIBEVENT_ROOT})
+foreach(prefix ${LibEvent_EXTRA_PREFIXES})
+  list(APPEND LibEvent_INCLUDE_PATHS "${prefix}/include")
+  list(APPEND LibEvent_LIBRARIES_PATHS "${prefix}/lib")
+endforeach()
+
+# Looking for "event.h" will find the Platform SDK include dir on windows
+# so we also look for a peer header like evhttp.h to get the right path
+find_path(LIBEVENT_INCLUDE_DIRS evhttp.h event.h PATHS ${LibEvent_INCLUDE_PATHS})
+
+# "lib" prefix is needed on Windows in some cases
+# newer versions of libevent use three libraries
+find_library(LIBEVENT_LIBRARIES NAMES event event_core event_extra libevent PATHS ${LibEvent_LIBRARIES_PATHS})
+
+if (LIBEVENT_LIBRARIES AND LIBEVENT_INCLUDE_DIRS)
+  set(Libevent_FOUND TRUE)
+  set(LIBEVENT_LIBRARIES ${LIBEVENT_LIBRARIES})
+else ()
+  set(Libevent_FOUND FALSE)
+endif ()
+
+if (Libevent_FOUND)
+  if (NOT Libevent_FIND_QUIETLY)
+    message(STATUS "Found libevent: ${LIBEVENT_LIBRARIES}")
+  endif ()
+else ()
+  if (LibEvent_FIND_REQUIRED)
+    message(FATAL_ERROR "Could NOT find libevent.")
+  endif ()
+  message(STATUS "libevent NOT found.")
+endif ()
+
+mark_as_advanced(
+    LIBEVENT_LIBRARIES
+    LIBEVENT_INCLUDE_DIRS
+  )
diff --git a/build/cmake/NewPlatformDebug.cmake b/build/cmake/NewPlatformDebug.cmake
new file mode 100644
index 0000000..aa4d302
--- /dev/null
+++ b/build/cmake/NewPlatformDebug.cmake
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+
+#
+# For debugging new platforms, just to see what some environment flags are...
+#
+macro(SHOWFLAG flag)
+  message(STATUS "${flag} = ${${flag}}")
+endmacro(SHOWFLAG)
+
+set(NEWPLATFORMDEBUG ON)
+
+if(NEWPLATFORMDEBUG)
+  SHOWFLAG("APPLE")
+  SHOWFLAG("BORLAND")
+  SHOWFLAG("CMAKE_C_COMPILER_ID")
+  SHOWFLAG("CMAKE_CXX_COMPILER_ID")
+  SHOWFLAG("CMAKE_COMPILER_IS_GNUCC")
+  SHOWFLAG("CMAKE_COMPILER_IS_GNUCXX")
+  SHOWFLAG("CYGWIN")
+  SHOWFLAG("MINGW")
+  SHOWFLAG("MSVC")
+  SHOWFLAG("MSVC_VERSION")
+  SHOWFLAG("MSYS")
+  SHOWFLAG("UNIX")
+  SHOWFLAG("WATCOM")
+  SHOWFLAG("WIN32")
+endif(NEWPLATFORMDEBUG)
diff --git a/build/cmake/README-MSYS2.md b/build/cmake/README-MSYS2.md
new file mode 100644
index 0000000..07cad92
--- /dev/null
+++ b/build/cmake/README-MSYS2.md
@@ -0,0 +1,63 @@
+<!---
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Building thrift on Windows (MinGW64/MSYS2)
+
+Thrift uses cmake to make it easier to build the project on multiple platforms, however to build a fully functional and production ready thrift on Windows requires a number of third party libraries to be obtained.  Once third party libraries are ready, the right combination of options must be passed to cmake in order to generate the correct environment.
+
+> Note: libevent and libevent-devel do not work with this toolchain as they do not properly detect mingw64 and expect some headers to exist that do not, so the non-blocking server is not currently built into this solution.
+
+## MSYS2
+
+Download and fully upgrade msys2 following the instructions at:
+
+    https://msys2.github.io/
+
+Install the necessary toolchain items for C++:
+
+    $ pacman --needed -S bison flex make mingw-w64-x86_64-openssl \
+                mingw-w64-x86_64-boost mingw-w64-x86_64-cmake \
+                mingw-w64-x86_64-toolchain mingw-w64-x86_64-zlib
+
+Update your msys2 bash path to include /mingw64/bin by adding a line to your ~/.bash_profiles using this command:
+
+    echo "export PATH=/mingw64/bin:\$PATH" >> ~/.bash_profile
+
+After that, close your shell and open a new one.
+
+Use cmake to create a MinGW makefile, out of tree (assumes you are in the top level of the thrift source tree):
+
+    mkdir ../thrift-build
+    cd ../thrift-build
+    cmake -G"MinGW Makefiles" -DCMAKE_MAKE_PROGRAM=/mingw64/bin/mingw32-make \
+       -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc.exe \
+       -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++.exe \
+       -DWITH_LIBEVENT=OFF \
+       -DWITH_SHARED_LIB=OFF -DWITH_STATIC_LIB=ON \
+       -DWITH_JAVA=OFF -DWITH_PYTHON=OFF -DWITH_PERL=OFF \
+       ../thrift
+
+Build thrift (inside thrift-build):
+
+    cmake --build .
+
+Run the tests (inside thrift-build):
+
+    ctest
+
+> If you run into issues, check Apache Jira THRIFT-4046 for patches relating to MinGW64/MSYS2 builds.
+
+## Tested With
+
+msys2 64-bit 2016-10-26 distribution
diff --git a/build/cmake/README.md b/build/cmake/README.md
new file mode 100644
index 0000000..e5c128b
--- /dev/null
+++ b/build/cmake/README.md
@@ -0,0 +1,60 @@
+# Apache Thrift - CMake build
+
+## Goal
+Extend Apache Thrift's *make cross* approach to the build system.
+
+Due to growing the field of operating system support, a proper executable
+and library detection mechanism running on as much platforms as possible
+becomes required. The other aspect to simplify the release process and
+package generation process.
+
+As nice side benefit of CMake is the generation of development environment
+specific soultion files. => No solution files within source tree.
+
+
+## Usage
+just do this:
+
+    mkdir cmake-build && cd cmake-build
+    cmake ..
+
+if you use a specific toolchain pass it to cmake, the same for options:
+
+    cmake -DCMAKE_TOOLCHAIN_FILE=../build/cmake/mingw32-toolchain.cmake ..
+    cmake -DCMAKE_C_COMPILER=clang-3.5 -DCMAKE_CXX_COMPILER=clang++-3.5 ..
+    cmake -DTHRIFT_COMPILER_HS=OFF ..
+    cmake -DWITH_ZLIB=ON ..
+
+or on Windows
+
+    cmake -G "Visual Studio 12 2013 Win64" \
+    -DBOOST_ROOT=C:/3rdparty/boost_1_58_0 \
+    -DZLIB_ROOT=C:/3rdparty/zlib128-dll \
+    -DWITH_SHARED_LIB=off ..
+
+and open the development environment you like with the solution or do this:
+
+    make
+    make check
+    make cross
+    make dist
+
+to generate an installer and distribution package do this:
+
+    cpack
+
+## TODO
+* git hash or tag based versioning depending on source state
+* build tutorial
+* build test
+* with/without language lib/<lang>/
+* enable/disable
+* make cross
+* make dist (create an alias to make package_source)
+* make doc
+* cpack (C++ and make dist only ?)
+  * thrift-compiler
+  * libthrift
+  * tutorial
+  * test
+* merge into /README.md
diff --git a/build/cmake/ThriftMacros.cmake b/build/cmake/ThriftMacros.cmake
new file mode 100644
index 0000000..f837f94
--- /dev/null
+++ b/build/cmake/ThriftMacros.cmake
@@ -0,0 +1,105 @@
+#
+# 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.
+#
+
+
+set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Set debug library postfix" FORCE)
+
+
+macro(ADD_LIBRARY_THRIFT name)
+
+if(WITH_SHARED_LIB)
+    add_library(${name} SHARED ${ARGN})
+    set_target_properties(${name} PROPERTIES
+        OUTPUT_NAME ${name}
+        VERSION ${thrift_VERSION}
+        SOVERSION ${thrift_VERSION} )
+    #set_target_properties(${name} PROPERTIES PUBLIC_HEADER "${thriftcpp_HEADERS}")
+    install(TARGETS ${name}
+        RUNTIME DESTINATION "${BIN_INSTALL_DIR}"
+        LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
+        ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
+        PUBLIC_HEADER DESTINATION "${INCLUDE_INSTALL_DIR}")
+endif()
+
+if(WITH_STATIC_LIB)
+    add_library(${name}_static STATIC ${ARGN})
+    set_target_properties(${name}_static PROPERTIES
+        OUTPUT_NAME ${name}${STATIC_POSTFIX}
+        VERSION ${thrift_VERSION}
+        SOVERSION ${thrift_VERSION} )
+    install(TARGETS ${name}_static
+        RUNTIME DESTINATION "${BIN_INSTALL_DIR}"
+        LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
+        ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
+        PUBLIC_HEADER DESTINATION "${INCLUDE_INSTALL_DIR}")
+endif()
+
+endmacro(ADD_LIBRARY_THRIFT)
+
+
+macro(TARGET_INCLUDE_DIRECTORIES_THRIFT name)
+
+if(WITH_SHARED_LIB)
+    target_include_directories(${name} ${ARGN})
+endif()
+
+if(WITH_STATIC_LIB)
+    target_include_directories(${name}_static ${ARGN})
+endif()
+
+endmacro(TARGET_INCLUDE_DIRECTORIES_THRIFT)
+
+
+macro(TARGET_LINK_LIBRARIES_THRIFT name)
+
+if(WITH_SHARED_LIB)
+    target_link_libraries(${name} ${ARGN})
+endif()
+
+if(WITH_STATIC_LIB)
+    target_link_libraries(${name}_static ${ARGN})
+endif()
+
+endmacro(TARGET_LINK_LIBRARIES_THRIFT)
+
+
+macro(LINK_AGAINST_THRIFT_LIBRARY target libname)
+
+if (WITH_SHARED_LIB)
+    target_link_libraries(${target} ${libname})
+elseif (WITH_STATIC_LIB)
+    target_link_libraries(${target} ${libname}_static)
+else()
+    message(FATAL "Not linking with shared or static libraries?")
+endif()
+
+endmacro(LINK_AGAINST_THRIFT_LIBRARY)
+
+
+macro(TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY target libname)
+
+if(WITH_SHARED_LIB)
+    target_link_libraries(${target} ${ARGN} ${libname})
+endif()
+
+if(WITH_STATIC_LIB)
+    target_link_libraries(${target}_static ${ARGN} ${libname}_static)
+endif()
+
+endmacro(TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY)
diff --git a/build/cmake/android-toolchain.cmake b/build/cmake/android-toolchain.cmake
new file mode 100644
index 0000000..15f3d00
--- /dev/null
+++ b/build/cmake/android-toolchain.cmake
@@ -0,0 +1,26 @@
+set(ANDROID_NDK "/opt/android-ndk" CACHE)
+set(ANDROID_PLATFORM "android-15" CACHE)
+set(ANDROID_ARCH "arch-arm" CACHE)
+set(ANDROID_TOOL_ARCH "android-arm" CACHE)
+set(ANDROID_CPU "armeabi-v7a" CACHE)
+set(ANDROID_GCC_VERSION 4.9 CACHE)
+set(HOST_ARCH linux-x86_64 CACHE)
+
+set(CMAKE_SYSTEM_NAME Android)
+set(ANDROID_SYSROOT "${ANDROID_NDK}/platforms/${ANDROID_PLATFORM}/${ANDROID_ARCH}")
+set(ANDROID_TRIPLET arm-linux-androideabi)
+set(ANDROID_STL "${ANDROID_NDK}/sources/cxx-stl/gnu-libstd++/${ANDROID_GCC_VERSION}")
+
+set(_COMPILER_ROOT ${ANDROID_NDK}/prebuilt/${ANDROID_TRIPLET}-${ANDROID_GCC_VERSION}/prebuilt/${HOST_ARCH})
+set(CMAKE_C_COMPILER ${_COMPILER_ROOT}/bin/${ANDROID_TRIPLET}-gcc)
+set(CMAKE_CXCX_COMPILER ${_COMPILER_ROOT}/bin/${ANDROID_TRIPLET}-g++)
+
+include_directories(
+    ${ANDROID_STL}/include
+    ${ANDROID_STL}/libs/${ANDROID_CPU}/include)
+
+set(CMAKE_FIND_ROOT_PATH ${ANDROID_SYSROOT})
+
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/build/cmake/config.h.in b/build/cmake/config.h.in
new file mode 100644
index 0000000..5f0ae46
--- /dev/null
+++ b/build/cmake/config.h.in
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+
+/* config.h generated by CMake from config.h.in */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+
+/* Name of package */
+#cmakedefine PACKAGE "${PACKAGE}"
+
+/* Define to the address where bug reports for this package should be sent. */
+#cmakedefine PACKAGE_BUGREPORT "${PACKAGE_BUGREPORT}"
+
+/* Define to the full name of this package. */
+#cmakedefine PACKAGE_NAME "${PACKAGE_NAME}"
+
+/* Define to the one symbol short name of this package. */
+#cmakedefine PACKAGE_TARNAME "${PACKAGE_TARNAME}"
+
+/* Define to the home page for this package. */
+#cmakedefine PACKAGE_URL "${PACKAGE_URL}"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "${PACKAGE_VERSION}"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "${PACKAGE_STRING}"
+
+/************************** DEFINES *************************/
+
+/* Define if the AI_ADDRCONFIG symbol is unavailable */
+#cmakedefine AI_ADDRCONFIG 0
+
+/* Possible value for SIGNED_RIGHT_SHIFT_IS */
+/* TODO: This is just set to 1 for the moment
+   port the macro aclocal/ax_signed_right_shift.m4 to CMake to make this work */
+#define ARITHMETIC_RIGHT_SHIFT 1
+
+/* Indicates the effect of the right shift operator on negative signed
+   integers */
+/* TODO: This is just set to 1 for the moment */
+#define SIGNED_RIGHT_SHIFT_IS 1
+
+/* Use *.h extension for parser header file */
+/* TODO: This might now be necessary anymore as it is set only for automake < 1.11
+   see: aclocal/ac_prog_bison.m4 */
+#cmakedefine BISON_USE_PARSER_H_EXTENSION 1
+
+/* replaces POSIX pthread by std::thread */
+#cmakedefine USE_STD_THREAD 1
+
+/* Define to 1 if strerror_r returns char *. */
+#cmakedefine STRERROR_R_CHAR_P 1
+
+
+/************************** HEADER FILES *************************/
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#cmakedefine HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#cmakedefine HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#cmakedefine HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#cmakedefine HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#cmakedefine HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#cmakedefine HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#cmakedefine HAVE_PTHREAD_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#cmakedefine HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#cmakedefine HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#cmakedefine HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#cmakedefine HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#cmakedefine HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#cmakedefine HAVE_POLL_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#cmakedefine HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#cmakedefine HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#cmakedefine HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sched.h> header file. */
+#cmakedefine HAVE_SCHED_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/*************************** FUNCTIONS ***************************/
+
+/* Define to 1 if you have the `gethostbyname' function. */
+#cmakedefine HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the `gethostbyname_r' function. */
+#cmakedefine HAVE_GETHOSTBYNAME_R 1
+
+/* Define to 1 if you have the `strerror_r' function. */
+#cmakedefine HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the `sched_get_priority_max' function. */
+#cmakedefine HAVE_SCHED_GET_PRIORITY_MAX 1
+
+/* Define to 1 if you have the `sched_get_priority_min' function. */
+#cmakedefine HAVE_SCHED_GET_PRIORITY_MIN 1
+
+
+/* Define to 1 if strerror_r returns char *. */
+#cmakedefine STRERROR_R_CHAR_P 1
+
+#endif
diff --git a/build/cmake/mingw32-toolchain.cmake b/build/cmake/mingw32-toolchain.cmake
new file mode 100644
index 0000000..864c0eb
--- /dev/null
+++ b/build/cmake/mingw32-toolchain.cmake
@@ -0,0 +1,24 @@
+# CMake mingw32 cross compile toolchain file
+
+# the name of the target operating system
+SET(CMAKE_SYSTEM_NAME Windows)
+
+# which compilers to use for C and C++
+SET(CMAKE_C_COMPILER i586-mingw32msvc-gcc)
+SET(CMAKE_CXX_COMPILER i586-mingw32msvc-g++)
+SET(CMAKE_RC_COMPILER i586-mingw32msvc-windres)
+
+# here is the target environment located
+SET(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc)
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+set(BUILD_SHARED_LIBS OFF)
+SET(CMAKE_EXE_LINKER_FLAGS "-static")
+set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-static-libgcc")
+set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-static-libstdc++")
diff --git a/build/docker/README.md b/build/docker/README.md
new file mode 100644
index 0000000..966d690
--- /dev/null
+++ b/build/docker/README.md
@@ -0,0 +1,198 @@
+# Docker Integration #
+
+Due to the large number of languages supported by Apache Thrift,
+docker containers are used to build and test the project on a
+variety of platforms to provide maximum test coverage.
+
+## Appveyor Integration ##
+
+At this time the Appveyor scripts do not use docker containers.
+Once Microsoft supports Visual Studio Build Tools running inside
+nano containers (instead of Core, which is huge) then we will
+consider using containers for the Windows builds as well.
+
+## Travis CI Integration ##
+
+The Travis CI scripts use the following environment variables and
+logic to determine their behavior:
+
+### Environment Variables ###
+
+| Variable | Default | Usage |
+| -------- | ----- | ------- |
+| `DISTRO` | `ubuntu-bionic` | Set by various build jobs in `.travis.yml` to run builds in different containers.  Not intended to be set externally.|
+| `DOCKER_REPO` | `thrift/thrift-build` | The name of the Docker Hub repository to obtain and store docker images. |
+| `DOCKER_USER` | `<none>` | The Docker Hub account name containing the repository. |
+| `DOCKER_PASS` | `<none>` | The Docker Hub account password to use when pushing new tags. |
+
+For example, the default docker image that is used in builds if no overrides are specified would be: `thrift/thrift-build:ubuntu-bionic`
+
+### Forks ###
+
+If you have forked the Apache Thrift repository and you would like
+to use your own Docker Hub account to store thrift build images,
+you can use the Travis CI web interface to set the `DOCKER_USER`,
+`DOCKER_PASS`, and `DOCKER_REPO` variables in a secure manner.
+Your fork builds will then pull, push, and tag the docker images
+in your account.
+
+### Logic ###
+
+The Travis CI build runs in two phases - first the docker images are rebuilt
+for each of the supported containers if they do not match the Dockerfile that
+was used to build the most recent tag.  If a `DOCKER_PASS` environment
+variable is specified, the docker stage builds will attempt to log into
+Docker Hub and push the resulting tags.
+
+## Supported Containers ##
+
+The Travis CI (continuous integration) builds use the Ubuntu Bionic
+(18.04 LTS) and Xenial (16.04 LTS) images to maximize language level
+coverage.
+
+### Ubuntu ###
+
+* bionic (stable, current)
+* artful (previous stable)
+* xenial (legacy)
+
+## Unsupported Containers ##
+
+These containers may be in various states, and may not build everything.
+They can be found in the `old/` subdirectory.
+
+### CentOS ###
+* 7.3
+  * make check in lib/py may hang in test_sslsocket - root cause unknown
+
+### Debian ###
+
+* jessie
+* stretch
+  * make check in lib/cpp fails due to https://svn.boost.org/trac10/ticket/12507
+
+## Building like Travis CI does, locally ##
+
+We recommend you build locally the same way Travis CI does, so that when you
+submit your pull request you will run into fewer surprises.  To make it a
+little easier, put the following into your `~/.bash_aliases` file:
+
+    # Kill all running containers.
+    alias dockerkillall='docker kill $(docker ps -q)'
+
+    # Delete all stopped containers.
+    alias dockercleanc='printf "\n>>> Deleting stopped containers\n\n" && docker rm $(docker ps -a -q)'
+
+    # Delete all untagged images.
+    alias dockercleani='printf "\n>>> Deleting untagged images\n\n" && docker rmi $(docker images -q -f dangling=true)'
+
+    # Delete all stopped containers and untagged images.
+    alias dockerclean='dockercleanc || true && dockercleani'
+
+    # Build a thrift docker image (run from top level of git repo): argument #1 is image type (ubuntu, centos, etc).
+    function dockerbuild
+    {
+      docker build -t $1 build/docker/$1
+    }
+
+    # Run a thrift docker image: argument #1 is image type (ubuntu, centos, etc).
+    function dockerrun
+    {
+      docker run -v $(pwd):/thrift/src -it $1 /bin/bash
+    }
+
+Then, to pull down the current image being used to build (the same way
+Travis CI does it) - if it is out of date in any way it will build a
+new one for you:
+
+    thrift$ DOCKER_REPO=thrift/thrift-build DISTRO=ubuntu-bionic build/docker/refresh.sh
+
+To run all unit tests (just like Travis CI does):
+
+    thrift$ dockerrun ubuntu-bionic
+    root@8caf56b0ce7b:/thrift/src# build/docker/scripts/autotools.sh
+
+To run the cross tests (just like Travis CI does):
+
+    thrift$ dockerrun ubuntu-bionic
+    root@8caf56b0ce7b:/thrift/src# build/docker/scripts/cross-test.sh
+
+When you are done, you want to clean up occasionally so that docker isn't using lots of extra disk space:
+
+    thrift$ dockerclean
+
+You need to run the docker commands from the root of the local clone of the
+thrift git repository for them to work.
+
+When you are done in the root docker shell you can `exit` to go back to
+your user host shell.  Once the unit tests and cross test passes locally,
+submit the changes, and if desired squash the pull request to one commit
+to make it easier to merge (the committers can squash at commit time now
+that GitHub is the master repository).  Now you are building like Travis CI does!
+
+## Raw Commands for Building with Docker ##
+
+If you do not want to use the same scripts Travis CI does, you can do it manually:
+
+Build the image:
+
+    thrift$ docker build -t thrift build/docker/ubuntu-bionic
+
+Open a command prompt in the image:
+
+    thrift$ docker run -v $(pwd):/thrift/src -it thrift /bin/bash
+
+## Core Tool Versions per Dockerfile ##
+
+Last updated: October 1, 2017
+
+| Tool      | ubuntu-xenial | ubuntu-bionic | Notes |
+| :-------- | :------------ | :------------ | :---- |
+| ant       | 1.9.6         | 1.10.3        |       |
+| autoconf  | 2.69          | 2.69          |       |
+| automake  | 1.15          | 1.15.1        |       |
+| bison     | 3.0.4         | 3.0.4         |       |
+| boost     | 1.58.0        | 1.65.1        |       |
+| cmake     | 3.5.1         | 3.10.2        |       |
+| cppcheck  | 1.72          | 1.82          |       |
+| flex      | 2.6.0         | 2.6.4         |       |
+| libc6     | 2.23          | 2.27          | glibc |
+| libevent  | 2.0.21        | 2.1.8         |       |
+| libstdc++ | 5.4.0         | 7.3.0         |       |
+| make      | 4.1           | 4.1           |       |
+| openssl   | 1.0.2g        | 1.1.0g        |       |
+| qt5       | 5.5.1         | 5.9.5         |       |
+
+## Compiler/Language Versions per Dockerfile ##
+
+| Language  | ubuntu-xenial | ubuntu-bionic | Notes |
+| :-------- | :------------ | :------------ | :---- |
+| as of     | Mar 06, 2018  | Jan 4, 2019   |       |
+| as3       |               |               | Not in CI |
+| C++ gcc   | 5.4.0         | 7.3.0         |       |
+| C++ clang | 3.8           | 6.0           |       |
+| C# (mono) | 4.2.1.0       | 4.6.2.7       |       |
+| c_glib    | 2.48.2        | 2.56.0        |       |
+| cl (sbcl) |               | 1.4.15        |       |
+| cocoa     |               |               | Not in CI |
+| d         | 2.075.1       | 2.083.1       |       |
+| dart      | 1.22.1        | 1.24.3        |       |
+| delphi    |               |               | Not in CI |
+| dotnet    | 2.1.4         | 2.2.101       |       |
+| erlang    | 18.3          | 20.2.2        |       |
+| go        | 1.7.6         | 1.11.4        |       |
+| haskell   | 7.10.3        | 8.0.2         |       |
+| haxe      | 3.2.1         | 3.4.4         | THRIFT-4352: avoid 3.4.2 |
+| java      | 1.8.0_151     | 1.8.0_191     |       |
+| js        |               |               | Unsure how to look for version info? |
+| lua       | 5.2.4         | 5.2.4         | Lua 5.3: see THRIFT-4386 |
+| nodejs    | 6.13.0        | 8.15.0        |       |
+| ocaml     |               | 4.05.0        | THRIFT-4517: ocaml 4.02.3 on xenial appears broken |
+| perl      | 5.22.1        | 5.26.1        |       |
+| php       | 7.0.22        | 7.2.10        |       |
+| python    | 2.7.12        | 2.7.15rc1     |       |
+| python3   | 3.5.2         | 3.6.7         |       |
+| ruby      | 2.3.1p112     | 2.5.1p57      |       |
+| rust      | 1.17.0        | 1.30.0        |       |
+| smalltalk |               |               | Not in CI |
+| swift     |               | 4.2.1         |       |
diff --git a/build/docker/old/Vagrantfile b/build/docker/old/Vagrantfile
new file mode 100644
index 0000000..5eac6e6
--- /dev/null
+++ b/build/docker/old/Vagrantfile
@@ -0,0 +1,59 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Base system bootstrap script
+$bootstrap_script = <<__BOOTSTRAP__
+echo "Provisioning defaults"
+
+sudo apt-get update -y
+sudo apt-get upgrade -y
+
+# Install default packages
+sudo apt-get install -y build-essential curl git
+
+# Install latest Docker version
+sudo curl -sSL https://get.docker.io/gpg | sudo apt-key add -
+sudo echo "deb http://get.docker.io/ubuntu docker main" > /etc/apt/sources.list.d/docker.list
+sudo apt-get update -y
+sudo apt-get install -y linux-image-extra-`uname -r` aufs-tools
+sudo apt-get install -y lxc-docker
+
+echo "Finished provisioning defaults"
+__BOOTSTRAP__
+
+Vagrant.configure("2") do |config|
+  config.vm.box = "trusty64"
+  config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box"
+  config.ssh.forward_agent = true
+
+  config.vm.provider :virtualbox do |vbox|
+    vbox.customize ["modifyvm", :id, "--memory", "1024"]
+    vbox.customize ["modifyvm", :id, "--cpus", "2"]
+  end
+
+  # Setup the default bootstrap script for our ubuntu base box image
+  config.vm.provision "shell", inline: $bootstrap_script
+
+  # Setup the custom docker image from our Ubuntu Dockerfile
+  config.vm.provision "docker" do |d|
+    d.build_image "/vagrant/ubuntu", args: "-t thrift"
+  end
+
+  # Setup the custom docker image from our Centos Dockerfile
+  #config.vm.provision "docker" do |d|
+  #  d.build_image "/vagrant/centos", args: "-t thrift-centos"
+  #end
+
+end
diff --git a/build/docker/old/centos-7.3/Dockerfile b/build/docker/old/centos-7.3/Dockerfile
new file mode 100644
index 0000000..096bbaa
--- /dev/null
+++ b/build/docker/old/centos-7.3/Dockerfile
@@ -0,0 +1,199 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Apache Thrift Docker build environment for CentOS
+#
+# Known missing client libraries:
+#  - dotnet (will update to 2.0.0 separately)
+#  - haxe (not in centos)
+
+FROM centos:7.3.1611
+MAINTAINER Apache Thrift <dev@thrift.apache.org>
+
+RUN yum install -y epel-release
+
+# General dependencies
+RUN yum install -y \
+      autoconf \
+      bison \
+      bison-devel \
+      clang \
+      clang-analyzer \
+      cmake3 \
+      curl \
+      flex \
+      gcc \
+      gcc-c++ \
+      gdb \
+      git \
+      libtool \
+      m4 \
+      make \
+      tar \
+      unzip \
+      valgrind \
+      wget && \
+      ln -s /usr/bin/cmake3 /usr/bin/cmake && \
+      ln -s /usr/bin/cpack3 /usr/bin/cpack && \
+      ln -s /usr/bin/ctest3 /usr/bin/ctest
+
+# C++ dependencies
+RUN yum install -y \
+      boost-devel-static \
+      zlib-devel \
+      openssl-devel \
+      libevent-devel && \
+    cd /usr/lib64 && \
+    ln -s libboost_thread-mt.a libboost_thread.a
+
+# C# Dependencies
+RUN yum install -y \
+      mono-core \
+      mono-devel \
+      mono-web-devel \
+      mono-extras
+
+# D Dependencies
+RUN yum install -y http://downloads.dlang.org/releases/2.x/2.076.0/dmd-2.076.0-0.fedora.x86_64.rpm xdg-utils
+RUN curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \
+    curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \
+    mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
+    mv libevent-master/deimos/* openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+    mv libevent-master/C/* openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \
+    rm -rf libevent-master openssl-master
+
+# Dart
+RUN cd /usr/local && \
+    wget -q https://storage.googleapis.com/dart-archive/channels/stable/release/1.24.2/sdk/dartsdk-linux-x64-release.zip && \
+    unzip -q dartsdk-linux-x64-release.zip && \
+    rm dartsdk-linux-x64-release.zip
+ENV PATH /usr/local/dart-sdk/bin:$PATH
+
+# Erlang Dependencies
+RUN curl -sSL http://packages.erlang-solutions.com/rpm/centos/erlang_solutions.repo -o /etc/yum.repos.d/erlang_solutions.repo && \
+    yum install -y \
+      erlang-kernel \
+      erlang-erts \
+      erlang-stdlib \
+      erlang-eunit \
+      erlang-rebar \
+      erlang-tools
+
+# GLibC Dependencies
+RUN yum install -y glib2-devel
+
+# Go Dependencies
+RUN curl -sSL https://storage.googleapis.com/golang/go1.9.linux-amd64.tar.gz | tar -C /usr/local/ -xz
+ENV PATH /usr/local/go/bin:$PATH
+
+# Haskell Dependencies
+RUN yum -y install haskell-platform
+
+# Haxe Dependencies
+# Not in debian/stretch
+
+# Java Dependencies
+RUN yum install -y \
+      ant \
+      junit \
+      ant-junit \
+      java-1.8.0-openjdk-devel
+
+# Lua Dependencies
+# Lua in epel is too old (5.1.4, need 5.2) so we get the latest
+RUN yum install -y readline-devel && \
+    wget -q http://www.lua.org/ftp/lua-5.3.4.tar.gz && \
+    tar xzf lua-5.3.4.tar.gz && \
+    cd lua-5.3.4 && \
+    sed -i 's/CFLAGS= /CFLAGS= -fPIC /g' src/Makefile && \
+    make linux && \
+    make install && \
+    cd .. && \
+    rm -rf lua-5*
+
+# MinGW Dependencies
+RUN yum install -y \
+      mingw32-binutils \
+      mingw32-crt \
+      mingw32-nsis
+
+# Node.js Dependencies
+# Work around epel issue where they removed http-parser that nodejs depends on!
+RUN yum -y install https://opensource.enda.eu/packages/http-parser-2.7.1-3.el7.x86_64.rpm
+RUN yum install -y \
+      nodejs \
+      npm
+
+# Ocaml Dependencies
+RUN yum install -y \
+      ocaml \
+      ocaml-ocamldoc && \
+    wget -q https://raw.github.com/ocaml/opam/master/shell/opam_installer.sh -O - | sh -s /usr/local/bin && \
+    opam init --yes && \
+    opam install --yes oasis && \
+    echo '. /root/.opam/opam-init/init.sh > /dev/null 2> /dev/null || true' >> ~/.bashrc
+
+# Perl Dependencies
+RUN yum install -y \
+      perl \
+      perl-version \
+      perl-Bit-Vector \
+      perl-Class-Accessor \
+      perl-ExtUtils-MakeMaker \
+      perl-Test-Simple \
+      perl-IO-Socket-SSL \
+      perl-Net-SSLeay \
+      perl-Crypt-SSLeay
+
+# PHP Dependencies
+RUN yum install -y \
+      php \
+      php-devel \
+      php-pear \
+      re2c \
+      php-phpunit-PHPUnit \
+      bzip2
+
+# Python Dependencies
+RUN yum install -y \
+      python \
+      python-devel \
+      python-pip \
+      python-setuptools \
+      python34 \
+      python34-devel \
+      python34-pip \
+      python34-setuptools
+RUN pip2 install --upgrade pip
+RUN pip2 install --upgrade backports.ssl_match_hostname ipaddress setuptools six tornado tornado-testing twisted virtualenv zope-interface
+RUN pip3 install --upgrade pip
+RUN pip3 install --upgrade backports.ssl_match_hostname ipaddress setuptools six tornado tornado-testing twisted virtualenv zope-interface
+
+# Ruby Dependencies
+RUN yum install -y \
+      ruby \
+      ruby-devel \
+      rubygems && \
+    gem install bundler rake
+
+# Rust
+RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.17.0
+ENV PATH /root/.cargo/bin:$PATH
+
+# Clean up
+RUN rm -rf /tmp/* && \
+    yum clean all
+
+ENV THRIFT_ROOT /thrift
+RUN mkdir -p $THRIFT_ROOT/src
+COPY Dockerfile $THRIFT_ROOT/
+WORKDIR $THRIFT_ROOT/src
diff --git a/build/docker/old/debian-jessie/Dockerfile b/build/docker/old/debian-jessie/Dockerfile
new file mode 100644
index 0000000..7bc74fc
--- /dev/null
+++ b/build/docker/old/debian-jessie/Dockerfile
@@ -0,0 +1,204 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Apache Thrift Docker build environment for Debian
+#
+# Known missing client libraries:
+#  - dotnetcore
+#  - rust
+
+FROM buildpack-deps:jessie-scm
+MAINTAINER Apache Thrift <dev@thrift.apache.org>
+
+ENV DEBIAN_FRONTEND noninteractive
+
+# Add apt sources
+# jessie-backports for cmake and some ruby bits
+RUN echo "deb http://ftp.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/jessie-backports.list
+
+# Dart
+RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
+    curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list && \
+    sed -i /etc/apt/sources.list.d/dart_stable.list -e 's/https:/http:/g'
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+`# General dependencies` \
+      bison \
+      build-essential \
+      clang \
+      debhelper \
+      flex \
+      pkg-config && \
+    apt-get -t jessie-backports install -y --no-install-recommends cmake
+
+RUN apt-get install -y --no-install-recommends \
+`# C++ dependencies` \
+      libboost-dev \
+      libboost-filesystem-dev \
+      libboost-program-options-dev \
+      libboost-system-dev \
+      libboost-test-dev \
+      libboost-thread-dev \
+      libevent-dev \
+      libssl-dev \
+      qt5-default \
+      qtbase5-dev \
+      qtbase5-dev-tools
+
+RUN apt-get install -y --no-install-recommends \
+`# Java dependencies` \
+      ant \
+      ant-optional \
+      openjdk-7-jdk \
+      maven
+
+RUN apt-get install -y --no-install-recommends \
+`# Python dependencies` \
+      python-all \
+      python-all-dbg \
+      python-all-dev \
+      python-pip \
+      python-setuptools \
+      python-twisted \
+      python-zope.interface \
+      python3-all \
+      python3-all-dbg \
+      python3-all-dev \
+      python3-setuptools \
+      python3-pip
+
+RUN apt-get install -y --no-install-recommends \
+`# Ruby dependencies` \
+      ruby \
+      ruby-dev \
+`# Perl dependencies` \
+      libbit-vector-perl \
+      libclass-accessor-class-perl \
+      libcrypt-ssleay-perl \
+      libio-socket-ssl-perl \
+      libnet-ssleay-perl
+
+RUN apt-get -t jessie-backports install -y ruby-bundler
+RUN apt-get install -y --no-install-recommends \
+`# Php dependencies` \
+      php5 \
+      php5-dev \
+      php5-cli \
+      php-pear \
+      re2c \
+      phpunit \
+`# GlibC dependencies` \
+      libglib2.0-dev
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+`# Erlang dependencies` \
+      erlang-base \
+      erlang-eunit \
+      erlang-dev \
+      erlang-tools \
+      rebar
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+`# Haskell dependencies` \
+      ghc \
+      cabal-install \
+`# Haxe dependencies` \
+      neko \
+      neko-dev \
+      libneko0
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+`# Node.js dependencies` \
+      nodejs \
+      nodejs-dev \
+      nodejs-legacy \
+      npm
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+`# CSharp dependencies` \
+      libmono-system-web2.0-cil \
+      mono-devel
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+`# D dependencies` \
+      xdg-utils \
+`# Dart dependencies` \
+      dart \
+`# Lua dependencies` \
+      lua5.2 \
+      lua5.2-dev \
+`# MinGW dependencies` \
+      mingw32 \
+      mingw32-binutils \
+`#      mingw32-runtime` \
+      nsis \
+`# Clean up` \
+    && rm -rf /var/cache/apt/* && \
+    rm -rf /var/lib/apt/lists/* && \
+    rm -rf /tmp/* && \
+    rm -rf /var/tmp/*
+
+# Ruby
+RUN gem install bundler --no-ri --no-rdoc
+
+# Python optional dependencies
+RUN pip2 install -U ipaddress backports.ssl_match_hostname tornado
+RUN pip3 install -U backports.ssl_match_hostname tornado
+
+# Go
+RUN curl -sSL https://storage.googleapis.com/golang/go1.4.3.linux-amd64.tar.gz | tar -C /usr/local/ -xz
+ENV PATH /usr/local/go/bin:$PATH
+
+# Haxe
+RUN mkdir -p /usr/lib/haxe && \
+    wget -O - https://github.com/HaxeFoundation/haxe/releases/download/3.2.1/haxe-3.2.1-linux64.tar.gz | \
+    tar -C /usr/lib/haxe --strip-components=1 -xz && \
+    ln -s /usr/lib/haxe/haxe /usr/bin/haxe && \
+    ln -s /usr/lib/haxe/haxelib /usr/bin/haxelib && \
+    mkdir -p /usr/lib/haxe/lib  && \
+    chmod -R 777 /usr/lib/haxe/lib && \
+    haxelib setup /usr/lib/haxe/lib && \
+    haxelib install hxcpp
+
+# D
+RUN curl -sSL http://downloads.dlang.org/releases/2.x/2.070.0/dmd_2.070.0-0_amd64.deb -o /tmp/dmd_2.070.0-0_amd64.deb && \
+    dpkg -i /tmp/dmd_2.070.0-0_amd64.deb && \
+    rm /tmp/dmd_2.070.0-0_amd64.deb && \
+    curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \
+    curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \
+    mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
+    mv libevent-master/deimos/* openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+    mv libevent-master/C/* openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \
+    rm -rf libevent-master openssl-master && \
+    echo 'gcc -Wl,--no-as-needed $*' > /usr/local/bin/gcc-dmd && \
+    chmod 755 /usr/local/bin/gcc-dmd && \
+    echo 'CC=/usr/local/bin/gcc-dmd' >> /etc/dmd.conf
+
+# Dart
+ENV PATH /usr/lib/dart/bin:$PATH
+
+# OCaml
+RUN echo 'deb http://ppa.launchpad.net/avsm/ppa/ubuntu trusty main' > /etc/apt/sources.list.d/avsm-official-ocaml.list && \
+    gpg --keyserver keyserver.ubuntu.com --recv 61707B09 && \
+    gpg --export --armor 61707B09 | apt-key add - && \
+    apt-get update && \
+    apt-get install -y ocaml opam && \
+    opam init && \
+    opam install oasis
+
+# Force utf8 locale to successfully build Haskell tf-random
+ENV LC_ALL C.UTF-8
+
+ENV THRIFT_ROOT /thrift
+RUN mkdir -p $THRIFT_ROOT/src
+COPY Dockerfile $THRIFT_ROOT/
+WORKDIR $THRIFT_ROOT/src
diff --git a/build/docker/old/debian-stretch/Dockerfile b/build/docker/old/debian-stretch/Dockerfile
new file mode 100644
index 0000000..503eecd
--- /dev/null
+++ b/build/docker/old/debian-stretch/Dockerfile
@@ -0,0 +1,231 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Apache Thrift Docker build environment for Debian Stretch
+#
+# Known issues:
+# - d: deimos for libevent and openssl disabled - build errors
+# - dotnetcore, because netcore is for 1.0.0-preview and 2.0.0 is out
+# - rust: cargo not in debian repo - perhaps not needed?
+
+FROM buildpack-deps:stretch-scm
+MAINTAINER Apache Thrift <dev@thrift.apache.org>
+
+ENV DEBIAN_FRONTEND noninteractive
+
+### Add apt repos
+
+RUN apt-get update && apt-get install -y --no-install-recommends apt apt-transport-https curl wget apt-utils
+
+# D
+RUN wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list && \
+    apt-get update && apt-get -y --allow-unauthenticated install --reinstall d-apt-keyring
+
+# Dart
+RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
+    curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list && \
+    sed -i /etc/apt/sources.list.d/dart_stable.list -e 's/https:/http:/g'
+
+# dotnet (core) 2.0.0 - project isn't ready for this yet:
+# RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \
+#     echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > /etc/apt/sources.list.d/dotnetdev.list
+
+# node.js (this step runs apt-get update internally)
+RUN curl -sL https://deb.nodesource.com/setup_8.x | bash
+
+
+### install general dependencies
+RUN apt-get install -y --no-install-recommends \
+`# General dependencies` \
+      bash-completion \
+      bison \
+      build-essential \
+      clang \
+      cmake \
+      debhelper \
+      flex \
+      gdb \
+      ninja-build \
+      pkg-config \
+      valgrind \
+      vim
+
+
+### languages
+
+RUN apt-get install -y --no-install-recommends \
+`# C++ dependencies` \
+      libboost-dev \
+      libboost-filesystem-dev \
+      libboost-program-options-dev \
+      libboost-system-dev \
+      libboost-test-dev \
+      libboost-thread-dev \
+      libevent-dev \
+      libssl-dev \
+      qt5-default \
+      qtbase5-dev \
+      qtbase5-dev-tools
+
+RUN apt-get install -y --no-install-recommends \
+`# csharp (mono) dependencies` \
+      mono-devel
+
+RUN apt-get install -y --no-install-recommends \
+`# D dependencies` \
+      dmd-bin \
+      libevent-dev \
+      libssl-dev \
+      xdg-utils
+# libevent deimos disabled - build errors
+# RUN mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
+#     curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \
+#     mv libevent-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+#     mv libevent-master/C/* /usr/include/dmd/druntime/import/C/ && \
+#     rm -rf libevent-master
+# openssl deimos doesn't work with openssl-1.1.0 - disabling it for now:
+# RUN curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \
+#     mv openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+#     mv openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \
+#     rm -rf openssl-master
+
+RUN apt-get install -y --no-install-recommends \
+`# Dart dependencies` \
+      dart
+ENV PATH /usr/lib/dart/bin:$PATH
+
+# project isn't ready for this quite yet:
+# RUN apt-get install -y --no-install-recommends \
+# `# dotnet core dependencies` \
+#       dotnet-sdk-2.0.0
+
+RUN apt-get install -y --no-install-recommends \
+`# Erlang dependencies` \
+      erlang-base \
+      erlang-eunit \
+      erlang-dev \
+      erlang-tools \
+      rebar
+
+RUN apt-get install -y --no-install-recommends \
+`# GlibC dependencies` \
+      libglib2.0-dev
+
+RUN apt-get install -y --no-install-recommends \
+`# golang (go) dependencies` \
+      golang-go
+
+RUN apt-get install -y --no-install-recommends \
+`# Haskell dependencies` \
+      ghc \
+      cabal-install
+
+RUN apt-get install -y --no-install-recommends \
+`# Haxe dependencies` \
+      haxe \
+      neko \
+      neko-dev
+RUN haxelib setup --always /usr/share/haxe/lib && \
+    haxelib install --always hxcpp
+
+RUN apt-get install -y --no-install-recommends \
+`# Java dependencies` \
+      ant \
+      ant-optional \
+      openjdk-8-jdk \
+      maven
+
+RUN apt-get install -y --no-install-recommends \
+`# Lua dependencies` \
+      lua5.2 \
+      lua5.2-dev
+# https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212
+# same for debian stretch
+# lua5.3 does not install alternatives so stick with 5.2 here
+
+RUN apt-get install -y --no-install-recommends \
+`# Node.js dependencies` \
+      nodejs
+
+RUN apt-get install -y --no-install-recommends \
+`# OCaml dependencies` \
+      ocaml \
+      opam && \
+    opam init --yes && \
+    opam install --yes oasis
+
+RUN apt-get install -y --no-install-recommends \
+`# Perl dependencies` \
+      libbit-vector-perl \
+      libclass-accessor-class-perl \
+      libcrypt-ssleay-perl \
+      libio-socket-ssl-perl \
+      libnet-ssleay-perl
+
+RUN apt-get install -y --no-install-recommends \
+`# Php dependencies` \
+      php7.0 \
+      php7.0-cli \
+      php7.0-dev \
+      php-pear \
+      re2c \
+      phpunit
+
+RUN apt-get install -y --no-install-recommends \
+`# Python dependencies` \
+      python-all \
+      python-all-dbg \
+      python-all-dev \
+      python-backports.ssl-match-hostname \
+      python-ipaddress \
+      python-pip \
+      python-setuptools \
+      python-six \
+      python-tornado \
+      python-twisted \
+      python-wheel \
+      python-zope.interface \
+      python3-all \
+      python3-all-dbg \
+      python3-all-dev \
+      python3-setuptools \
+      python3-six \
+      python3-tornado \
+      python3-twisted \
+      python3-wheel \
+      python3-zope.interface && \
+    pip install --upgrade backports.ssl_match_hostname
+
+RUN apt-get install -y --no-install-recommends \
+`# Ruby dependencies` \
+      ruby \
+      ruby-dev \
+      ruby-bundler
+RUN gem install bundler --no-ri --no-rdoc
+
+RUN apt-get install -y --no-install-recommends \
+`# Rust dependencies` \
+      rustc
+
+# Update anything else left hanging
+RUN apt-get dist-upgrade -y
+
+# Clean up
+RUN rm -rf /var/cache/apt/* && \
+    rm -rf /var/lib/apt/lists/* && \
+    rm -rf /tmp/* && \
+    rm -rf /var/tmp/*
+
+ENV THRIFT_ROOT /thrift
+RUN mkdir -p $THRIFT_ROOT/src
+COPY Dockerfile $THRIFT_ROOT/
+WORKDIR $THRIFT_ROOT/src
diff --git a/build/docker/old/ubuntu-trusty/Dockerfile b/build/docker/old/ubuntu-trusty/Dockerfile
new file mode 100644
index 0000000..a8e4d3b
--- /dev/null
+++ b/build/docker/old/ubuntu-trusty/Dockerfile
@@ -0,0 +1,244 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Apache Thrift Docker build environment for Ubuntu Trusty
+# Using all stock Ubuntu Trusty packaging except for:
+# - d: does not come with Ubuntu so we're installing 2.070.0
+# - dart: does not come with Ubuntu so we're installing 1.20.1
+# - dotnetcore, disabled because netcore is for 1.0.0-preview and 2.0.0 is out
+# - haxe, disabled because the distro comes with 3.0.0 and it cores while installing
+# - node.js, disabled because it is at 0.10.0 in the distro which is too old (need 4+)
+# - ocaml, disabled because it fails to install properly
+#
+
+FROM buildpack-deps:trusty-scm
+MAINTAINER Apache Thrift <dev@thrift.apache.org>
+ENV DEBIAN_FRONTEND noninteractive
+
+### Add apt repos
+
+RUN apt-get update && \
+    apt-get dist-upgrade -y && \
+    apt-get install -y --no-install-recommends \
+      apt \
+      apt-transport-https \
+      apt-utils \
+      curl \
+      dirmngr \
+      software-properties-common \
+      wget
+
+# D
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EBCF975E5BA24D5E && \
+        wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list && \
+        wget -qO - https://dlang.org/d-keyring.gpg | apt-key add -
+
+# Dart
+RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
+        curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \
+          /etc/apt/sources.list.d/dart_stable.list
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+`# General dependencies` \
+      bash-completion \
+      bison \
+      build-essential \
+      clang \
+      cmake \
+      debhelper \
+      flex \
+      gdb \
+      llvm \
+      ninja-build \
+      pkg-config \
+      valgrind \
+      vim
+ENV PATH /usr/lib/llvm-3.8/bin:$PATH
+
+RUN apt-get install -y --no-install-recommends \
+`# C++ dependencies` \
+      libboost-all-dev \
+      libevent-dev \
+      libssl-dev \
+      qt5-default \
+      qtbase5-dev \
+      qtbase5-dev-tools
+
+RUN apt-get install -y --no-install-recommends \
+`# csharp (mono) dependencies` \
+      mono-devel
+
+RUN apt-get install -y --no-install-recommends \
+`# D dependencies` \
+      dmd-bin=2.070.2-0 \
+      libphobos2-dev=2.070.2-0 \
+      dub \
+      dfmt \
+      dscanner \
+      xdg-utils
+RUN mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
+    curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \
+    mv libevent-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+    mv libevent-master/C/* /usr/include/dmd/druntime/import/C/ && \
+    rm -rf libevent-master
+RUN curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \
+    mv openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+    mv openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \
+    rm -rf openssl-master
+
+RUN apt-get install -y --no-install-recommends \
+`# Dart dependencies` \
+      dart=1.20.1-1
+ENV PATH /usr/lib/dart/bin:$PATH
+
+RUN apt-get install -y --no-install-recommends \
+`# Erlang dependencies` \
+      erlang-base \
+      erlang-eunit \
+      erlang-dev \
+      erlang-tools \
+      rebar
+
+RUN apt-get install -y --no-install-recommends \
+`# GlibC dependencies` \
+      libglib2.0-dev
+
+# golang
+ENV GOLANG_VERSION 1.7.6
+ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
+ENV GOLANG_DOWNLOAD_SHA256 ad5808bf42b014c22dd7646458f631385003049ded0bb6af2efc7f1f79fa29ea
+RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \
+      echo "$GOLANG_DOWNLOAD_SHA256  golang.tar.gz" | sha256sum -c - && \
+      tar -C /usr/local -xzf golang.tar.gz && \
+      ln -s /usr/local/go/bin/go /usr/local/bin && \
+      rm golang.tar.gz
+
+RUN apt-get install -y --no-install-recommends \
+`# Haskell dependencies` \
+      ghc \
+      cabal-install
+
+# disabled because it cores while installing
+# RUN apt-get install -y --no-install-recommends \
+# `# Haxe dependencies` \
+#       haxe \
+#       neko \
+#       neko-dev && \
+#     haxelib setup /usr/share/haxe/lib && \
+#     haxelib install hxcpp 3.2.102
+
+RUN apt-get install -y --no-install-recommends \
+`# Java dependencies` \
+      ant \
+      ant-optional \
+      openjdk-7-jdk \
+      maven
+
+RUN apt-get install -y --no-install-recommends \
+`# Lua dependencies` \
+      lua5.1 \
+      lua5.1-dev
+
+# disabled because it is too old
+# RUN apt-get install -y --no-install-recommends \
+# `# Node.js dependencies` \
+#       nodejs \
+#       npm
+
+# disabled because it fails to install properly
+# RUN apt-get install -y --no-install-recommends \
+# `# OCaml dependencies` \
+#       ocaml \
+#       opam && \
+#     opam init --yes && \
+#     opam install --yes oasis
+
+RUN apt-get install -y --no-install-recommends \
+`# Perl dependencies` \
+      libbit-vector-perl \
+      libclass-accessor-class-perl \
+      libcrypt-ssleay-perl \
+      libio-socket-ssl-perl \
+      libnet-ssleay-perl
+
+RUN apt-get install -y --no-install-recommends \
+`# Php dependencies` \
+      php5 \
+      php5-cli \
+      php5-dev \
+      php-pear \
+      re2c && \
+      wget https://getcomposer.org/installer -O - -q | php -- --quiet --install-dir=/usr/local/bin/ --filename=composer
+
+RUN apt-get install -y --no-install-recommends \
+`# Python dependencies` \
+      python-all \
+      python-all-dbg \
+      python-all-dev \
+      python-pip \
+      python-setuptools \
+      python-six \
+      python-twisted \
+      python-wheel \
+      python-zope.interface \
+      python3-all \
+      python3-all-dbg \
+      python3-all-dev \
+      python3-pip \
+      python3-setuptools \
+      python3-six \
+      python3-wheel \
+      python3-zope.interface && \
+    pip install -U ipaddress backports.ssl_match_hostname tornado && \
+    pip3 install -U backports.ssl_match_hostname tornado
+# installing tornado by pip/pip3 instead of debian package
+# if we install the debian package, the build fails in py2
+
+RUN apt-get install -y --no-install-recommends \
+`# Ruby dependencies` \
+      ruby \
+      ruby-dev \
+      ruby-bundler
+RUN gem install bundler --no-ri --no-rdoc
+
+RUN apt-get install -y --no-install-recommends \
+`# Rust dependencies` \
+      cargo \
+      rustc
+
+RUN apt-get install -y --no-install-recommends \
+`# Static Code Analysis dependencies` \
+      cppcheck \
+      sloccount && \
+    pip install flake8
+
+# Install BouncyCastle provider to fix Java builds issues with JDK 7
+# Builds accessing repote repositories fail as seen here: https://github.com/travis-ci/travis-ci/issues/8503
+RUN apt-get install -y --no-install-recommends \
+`# BouncyCastle JCE Provider dependencies` \
+      libbcprov-java && \
+    ln -s /usr/share/java/bcprov.jar /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/ext/bcprov.jar && \
+    awk -F . -v OFS=. 'BEGIN{n=2}/^security\.provider/ {split($3, posAndEquals, "=");$3=n++"="posAndEquals[2];print;next} 1' /etc/java-7-openjdk/security/java.security > /tmp/java.security && \
+  echo "security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider" >> /tmp/java.security && \
+  mv /tmp/java.security /etc/java-7-openjdk/security/java.security
+
+# Clean up
+RUN rm -rf /var/cache/apt/* && \
+    rm -rf /var/lib/apt/lists/* && \
+    rm -rf /tmp/* && \
+    rm -rf /var/tmp/*
+
+ENV THRIFT_ROOT /thrift
+RUN mkdir -p $THRIFT_ROOT/src
+COPY Dockerfile $THRIFT_ROOT/
+WORKDIR $THRIFT_ROOT/src
diff --git a/build/docker/refresh.sh b/build/docker/refresh.sh
new file mode 100755
index 0000000..08cbc91
--- /dev/null
+++ b/build/docker/refresh.sh
@@ -0,0 +1,82 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# The build has two stages: "docker" and "test"
+# The "docker" stage is meant to rebuild the docker images
+#   if needed.  If we cannot push that result however then
+#   there is no reason to do anything.
+# The "test" stage is an actual test job.  Even if the docker
+#   image doesn't match what's in the repo, we still build
+#   the image so the build job can run properly.
+#
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+DOCKER_TAG=$DOCKER_REPO:$DISTRO
+
+function dockerfile_changed {
+  # image may not exist yet, so we have to let it fail silently:
+  docker pull $DOCKER_TAG || true
+  docker run $DOCKER_TAG bash -c 'cd .. && sha512sum Dockerfile' > .Dockerfile.sha512
+  sha512sum -c .Dockerfile.sha512
+}
+
+#
+# If this build has no DOCKER_PASS and it is in the docker stage
+# then there's no reason to do any processing because we cannot
+# push the result if the Dockerfile changed.  
+#
+
+if [[ "$TRAVIS_BUILD_STAGE" == "docker" ]] && [[ -z "$DOCKER_PASS" ]]; then
+  echo Detected docker stage build and no defined DOCKER_PASS, this build job will be skipped.
+  echo Subsequent jobs in the test stage may each rebuild the docker image.
+  exit 0
+fi
+
+
+pushd ${SCRIPT_DIR}/$DISTRO
+if dockerfile_changed; then
+  echo Dockerfile has not changed.  No need to rebuild.
+  exit 0
+else
+  echo Dockerfile has changed.
+fi
+popd
+
+#
+# Dockerfile has changed - rebuild it for the current build job.
+# If it is a "docker" stage build then we want to push it back
+# to the DOCKER_REPO.  If it is a "test" stage build then we do
+# not.  If nobody defined a DOCKER_PASS then it doesn't matter.
+#
+
+echo Rebuilding docker image $DISTRO
+docker build --tag $DOCKER_TAG build/docker/$DISTRO
+
+if [[ "$TRAVIS_BUILD_STAGE" == "docker" ]] && [[ ! -z "$DOCKER_USER" ]] && [[ ! -z "$DOCKER_PASS" ]]; then 
+  echo Pushing docker image $DOCKER_TAG
+  docker login -u $DOCKER_USER -p $DOCKER_PASS
+  docker push $DOCKER_TAG
+else
+  echo Not pushing docker image: either not a docker stage build job, or one of DOCKER_USER or DOCKER_PASS is undefined.
+fi
+
diff --git a/build/docker/run.sh b/build/docker/run.sh
new file mode 100755
index 0000000..1fe19d5
--- /dev/null
+++ b/build/docker/run.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# 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.
+#
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+DOCKER_TAG=$DOCKER_REPO:$DISTRO
+
+printenv | sort
+
+docker run --net=host -e BUILD_LIBS="$BUILD_LIBS" $BUILD_ENV -v $(pwd):/thrift/src \
+	-it $DOCKER_TAG build/docker/scripts/$SCRIPT $BUILD_ARG
+
diff --git a/build/docker/scripts/autotools.sh b/build/docker/scripts/autotools.sh
new file mode 100755
index 0000000..8388f72
--- /dev/null
+++ b/build/docker/scripts/autotools.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+set -ev
+
+./bootstrap.sh
+./configure $*
+make check -j3
diff --git a/build/docker/scripts/cmake.sh b/build/docker/scripts/cmake.sh
new file mode 100755
index 0000000..ccc311e
--- /dev/null
+++ b/build/docker/scripts/cmake.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+set -ev
+
+CMAKE_FLAGS=$*
+MAKEPROG=make
+
+if ninja --version  >/dev/null 2>&1; then
+  MAKEPROG=ninja
+  CMAKE_FLAGS="-GNinja $CMAKE_FLAGS"
+fi
+
+mkdir -p cmake_build && cd cmake_build
+cmake $CMAKE_FLAGS ..
+for LIB in $BUILD_LIBS; do
+  if ! grep "^BUILD_${LIB}:BOOL=ON$" CMakeCache.txt ; then
+    echo "failed to configure $LIB"
+    exit 1
+  fi
+done
+$MAKEPROG -j3
+cpack
+ctest -VV -E "(python_test)"
+# disabled cmake python_test for now since it fails in travis under centos
diff --git a/build/docker/scripts/covscan.sh b/build/docker/scripts/covscan.sh
new file mode 100755
index 0000000..cb3f283
--- /dev/null
+++ b/build/docker/scripts/covscan.sh
@@ -0,0 +1,50 @@
+#
+# Coverity Scan Travis build script
+# To run this interactively, set the environment variables yourself,
+# and run this inside a docker container.
+#
+# Command-Line Arguments
+#
+# --skipdownload   to skip re-downloading the Coverity Scan build package (large)
+#
+# Environment Variables (required)
+#
+# COVERITY_SCAN_NOTIFICATION_EMAIL  - email address to notify
+# COVERITY_SCAN_TOKEN               - the Coverity Scan token (should be secure)
+#
+# Environment Variables (defaulted)
+#
+# COVERITY_SCAN_BUILD_COMMAND       - defaults to "build/docker/scripts/autotools.sh"
+# COVERITY_SCAN_DESCRIPTION         - defaults to TRAVIS_BRANCH or "master" if empty
+# COVERITY_SCAN_PROJECT             - defaults to "thrift"
+
+set -ex
+
+COVERITY_SCAN_BUILD_COMMAND=${COVERITY_SCAN_BUILD_COMMAND:-build/docker/scripts/autotools.sh}
+COVERITY_SCAN_DESCRIPTION=${COVERITY_SCAN_DESCRIPTION:-${TRAVIS_BRANCH:-master}}
+COVERITY_SCAN_PROJECT=${COVERITY_SCAN_PROJECT:-thrift}
+
+# download the coverity scan package
+
+pushd /tmp
+if [[ "$1" != "--skipdownload" ]]; then
+  rm -rf coverity_tool.tgz cov-analysis*
+  wget https://scan.coverity.com/download/linux64 --post-data "token=$COVERITY_SCAN_TOKEN&project=$COVERITY_SCAN_PROJECT" -O coverity_tool.tgz
+  tar xzf coverity_tool.tgz
+fi
+COVBIN=$(echo $(pwd)/cov-analysis*/bin)
+export PATH=$COVBIN:$PATH
+popd
+
+# build the project with coverity scan
+
+rm -rf cov-int/
+cov-build --dir cov-int $COVERITY_SCAN_BUILD_COMMAND
+tar cJf cov-int.tar.xz cov-int/
+curl --form token="$COVERITY_SCAN_TOKEN" \
+     --form email="$COVERITY_SCAN_NOTIFICATION_EMAIL" \
+     --form file=@cov-int.tar.xz \
+     --form version="$(git describe --tags)" \
+     --form description="$COVERITY_SCAN_DESCRIPTION" \
+     https://scan.coverity.com/builds?project="$COVERITY_SCAN_PROJECT"
+
diff --git a/build/docker/scripts/cross-test.sh b/build/docker/scripts/cross-test.sh
new file mode 100755
index 0000000..43581a5
--- /dev/null
+++ b/build/docker/scripts/cross-test.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+set -ev
+
+./bootstrap.sh
+./configure --enable-tutorial=no
+make -j3 precross
+
+set +e
+make cross$1
+
+RET=$?
+if [ $RET -ne 0 ]; then
+  cat test/log/unexpected_failures.log
+fi
+
+exit $RET
diff --git a/build/docker/scripts/dpkg.sh b/build/docker/scripts/dpkg.sh
new file mode 100755
index 0000000..3ba0cd4
--- /dev/null
+++ b/build/docker/scripts/dpkg.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+set -ev
+
+dpkg-buildpackage -tc -us -uc
+ls -al ..
diff --git a/build/docker/scripts/make-dist.sh b/build/docker/scripts/make-dist.sh
new file mode 100755
index 0000000..5a3681e
--- /dev/null
+++ b/build/docker/scripts/make-dist.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+set -ev
+
+./bootstrap.sh
+./configure $*
+make dist
+tar xvf thrift-*.tar.gz
+cd thrift-*
+./build/docker/scripts/cmake.sh
diff --git a/build/docker/scripts/sca.sh b/build/docker/scripts/sca.sh
new file mode 100755
index 0000000..16d5826
--- /dev/null
+++ b/build/docker/scripts/sca.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+set -ev
+
+#
+# Generate thrift files so the static code analysis includes an analysis
+# of the files the thrift compiler spits out.  If running interactively
+# set the NOBUILD environment variable to skip the boot/config/make phase.
+#
+
+if [[ -z "$NOBUILD" ]]; then
+  ./bootstrap.sh
+  ./configure --enable-tutorial=no
+  make -j3 precross
+fi
+
+#
+# C/C++ static code analysis with cppcheck
+# add --error-exitcode=1 to --enable=all as soon as everything is fixed
+#
+# Python code style check with flake8
+#
+# search for TODO etc within source tree
+# some statistics about the code base
+# some info about the build machine
+
+# Compiler cppcheck (All)
+cppcheck --force --quiet --inline-suppr --enable=all -j2 compiler/cpp/src
+
+# C++ cppcheck (All)
+cppcheck --force --quiet --inline-suppr --enable=all -j2 lib/cpp/src lib/cpp/test test/cpp tutorial/cpp
+
+# C Glib cppcheck (All)
+cppcheck --force --quiet --inline-suppr --enable=all -j2 lib/c_glib/src lib/c_glib/test test/c_glib/src tutorial/c_glib
+
+# Silent error checks
+# See THRIFT-4371 : flex generated code triggers "possible null pointer dereference" in yy_init_buffer
+cppcheck --force --quiet --inline-suppr --suppress="*:thrift/thriftl.cc" --error-exitcode=1 -j2 compiler/cpp/src
+cppcheck --force --quiet --inline-suppr --error-exitcode=1 -j2 lib/cpp/src lib/cpp/test test/cpp tutorial/cpp
+cppcheck --force --quiet --inline-suppr --error-exitcode=1 -j2 lib/c_glib/src lib/c_glib/test test/c_glib/src tutorial/c_glib
+
+# Python code style
+flake8 --ignore=W504,E501 lib/py
+flake8 --exclude=tutorial/py/build tutorial/py
+# THRIFT-4371 : generated files are excluded because they haven't been scrubbed yet
+flake8 --ignore=E501 --exclude="*/gen-py*/*",test/py/build test/py
+flake8 test/py.twisted
+flake8 test/py.tornado
+flake8 --ignore=E501 test/test.py
+flake8 --ignore=E501,E722 test/crossrunner
+flake8 test/features
+
+# PHP code style
+composer install --quiet
+./vendor/bin/phpcs
+
+# TODO etc
+echo FIXMEs: `grep -r FIXME * | wc -l`
+echo  HACKs: `grep -r HACK * | wc -l`
+echo  TODOs: `grep -r TODO * | wc -l`
+
+# LoC
+sloccount .
+
+# System Info
+dpkg -l
+uname -a
diff --git a/build/docker/scripts/ubsan.sh b/build/docker/scripts/ubsan.sh
new file mode 100755
index 0000000..650dba0
--- /dev/null
+++ b/build/docker/scripts/ubsan.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+set -e
+
+# Wraps autotools.sh, but each binary crashes if it exhibits undefined behavior. 
+# Set the undefined behavior flags. This crashes on all undefined behavior except for
+# undefined casting, aka "vptr".
+# TODO: fix undefined vptr behavior and turn this option back on.
+
+export CFLAGS="-fsanitize=undefined -fno-sanitize-recover=undefined -O0 -ggdb3 -fno-omit-frame-pointer"
+export CXXFLAGS="${CFLAGS}"
+export LDFLAGS="-lubsan"
+export UBSAN_OPTIONS=print_stacktrace=1
+
+#
+# work around https://svn.boost.org/trac10/ticket/11632 if present
+#
+
+sed -i 's/, stream_t(rdbuf()) /, stream_t(pbase_type::member.get())/g' /usr/include/boost/format/alt_sstream.hpp
+
+# llvm-symbolizer must be on PATH to get a stack trace on error
+
+CLANG_PATH="$(mktemp -d)"
+trap "rm -rf ${CLANG_PATH}" EXIT
+ln -s "$(whereis llvm-symbolizer-4.0  | rev | cut -d ' ' -f 1 | rev)" \
+  "${CLANG_PATH}/llvm-symbolizer"
+export PATH="${CLANG_PATH}:${PATH}"
+llvm-symbolizer -version
+
+build/docker/scripts/autotools.sh $*
diff --git a/build/docker/ubuntu-artful/Dockerfile b/build/docker/ubuntu-artful/Dockerfile
new file mode 100644
index 0000000..abe84d1
--- /dev/null
+++ b/build/docker/ubuntu-artful/Dockerfile
@@ -0,0 +1,270 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Apache Thrift Docker build environment for Ubuntu Artful
+# Using all stock Ubuntu Artful packaging except for:
+# - cpp: stock boost 1.62 in artful has a nasty bug so we use stock boost 1.63
+# - d: dmd does not come with Ubuntu
+# - dart: does not come with Ubuntu. Pinned to last 1.x release
+# - dotnet: does not come with Ubuntu
+# - haxe: version 3.4.2 that comes with Ubuntu cores in our CI build
+# - go: artful comes with 1.9, we want the latest (supported)
+# - nodejs: want v8, artful comes with v6
+#
+
+FROM buildpack-deps:artful-scm
+MAINTAINER Apache Thrift <dev@thrift.apache.org>
+ENV DEBIAN_FRONTEND noninteractive
+
+### Add apt repos
+
+RUN apt-get update && \
+    apt-get dist-upgrade -y && \
+    apt-get install -y --no-install-recommends \
+      apt \
+      apt-transport-https \
+      apt-utils \
+      curl \
+      dirmngr \
+      software-properties-common \
+      wget
+
+# csharp (mono) - if we ever want a later version
+# RUN echo "deb http://download.mono-project.com/repo/debian xenial main" | tee /etc/apt/sources.list.d/mono.list && \
+#     apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A6A19B38D3D831EF
+
+# Dart
+RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
+    curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \
+      /etc/apt/sources.list.d/dart_stable.list
+ENV DART_VERSION 1.24.3-1
+
+# dotnet (netcore)
+RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \
+    echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-artful-prod artful main" > \
+      /etc/apt/sources.list.d/dotnetdev.list
+
+# haxe (https://haxe.org/download/linux/)
+RUN add-apt-repository ppa:haxe/releases -y
+
+# node.js
+RUN curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \
+    echo "deb https://deb.nodesource.com/node_8.x artful main" | tee /etc/apt/sources.list.d/nodesource.list
+
+### install general dependencies
+RUN apt-get update && apt-get install -y --no-install-recommends \
+`# General dependencies` \
+      bash-completion \
+      bison \
+      build-essential \
+      clang \
+      cmake \
+      debhelper \
+      flex \
+      gdb \
+      llvm \
+      ninja-build \
+      pkg-config \
+      valgrind \
+      vim
+ENV PATH /usr/lib/llvm-3.8/bin:$PATH
+
+# boost-1.62 has a terrible bug in boost::test, see https://svn.boost.org/trac10/ticket/12507
+RUN apt-get install -y --no-install-recommends \
+`# C++ dependencies` \
+      libboost1.63-all-dev \
+      libevent-dev \
+      libssl-dev \
+      qt5-default \
+      qtbase5-dev \
+      qtbase5-dev-tools
+
+RUN apt-get install -y --no-install-recommends \
+`# csharp (mono) dependencies` \
+      mono-devel
+
+ENV SBCL_VERSION 1.4.5
+RUN \
+`# Common Lisp (sbcl) dependencies` \
+    curl --version && \
+    curl -O -J -L https://kent.dl.sourceforge.net/project/sbcl/sbcl/${SBCL_VERSION}/sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \
+    tar xjf sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \
+    cd sbcl-${SBCL_VERSION}-x86-64-linux && \
+    ./install.sh && \
+    sbcl --version && \
+    rm -rf sbcl*
+
+ENV D_VERSION     2.080.0
+ENV DMD_DEB       dmd_2.080.0-0_amd64.deb
+RUN \
+`# D dependencies` \
+    wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \
+    dpkg --install ${DMD_DEB} && \
+    rm -f ${DMD_DEB} && \
+    mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
+    curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \
+    mv libevent-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+    mv libevent-master/C/* /usr/include/dmd/druntime/import/C/ && \
+    rm -rf libevent-master && \
+    curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/master.tar.gz| tar xz && \
+    mv openssl-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+    mv openssl-master/C/* /usr/include/dmd/druntime/import/C/ && \
+    rm -rf openssl-master
+
+RUN apt-get install -y --no-install-recommends \
+      `# Dart dependencies` \
+      dart=$DART_VERSION
+ENV PATH /usr/lib/dart/bin:$PATH
+
+RUN apt-get install -y --no-install-recommends \
+`# dotnet core dependencies` \
+      dotnet-sdk-2.1.4
+
+RUN apt-get install -y --no-install-recommends \
+`# Erlang dependencies` \
+      erlang-base \
+      erlang-eunit \
+      erlang-dev \
+      erlang-tools \
+      rebar
+
+RUN apt-get install -y --no-install-recommends \
+`# GlibC dependencies` \
+      libglib2.0-dev
+
+# golang
+ENV GOLANG_VERSION 1.10
+ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
+ENV GOLANG_DOWNLOAD_SHA256 b5a64335f1490277b585832d1f6c7f8c6c11206cba5cd3f771dcb87b98ad1a33
+RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \
+      echo "$GOLANG_DOWNLOAD_SHA256  golang.tar.gz" | sha256sum -c - && \
+            tar -C /usr/local -xzf golang.tar.gz && \
+                  ln -s /usr/local/go/bin/go /usr/local/bin && \
+                        rm golang.tar.gz
+
+RUN apt-get install -y --no-install-recommends \
+`# Haskell dependencies` \
+      ghc \
+      cabal-install
+
+RUN apt-get install -y --no-install-recommends \
+`# Haxe dependencies` \
+      haxe \
+      neko \
+      neko-dev && \
+    haxelib setup --always /usr/share/haxe/lib && \
+    haxelib install --always hxcpp 2>&1 > /dev/null
+
+RUN apt-get install -y --no-install-recommends \
+`# Java dependencies` \
+      ant \
+      ant-optional \
+      openjdk-8-jdk \
+      maven
+
+RUN apt-get install -y --no-install-recommends \
+`# Lua dependencies` \
+      lua5.2 \
+      lua5.2-dev
+# https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212
+# lua5.3 does not install alternatives!
+# need to update our luasocket code, lua doesn't have luaL_openlib any more
+
+RUN apt-get install -y --no-install-recommends \
+`# Node.js dependencies` \
+      nodejs
+
+# Test dependencies for running puppeteer
+RUN apt-get install -y --no-install-recommends \
+`# JS dependencies` \
+      libxss1
+
+RUN apt-get install -y --no-install-recommends \
+`# OCaml dependencies` \
+      ocaml \
+      opam && \
+    opam init --yes && \
+    opam install --yes oasis
+
+RUN apt-get install -y --no-install-recommends \
+`# Perl dependencies` \
+      libbit-vector-perl \
+      libclass-accessor-class-perl \
+      libcrypt-ssleay-perl \
+      libio-socket-ssl-perl \
+      libnet-ssleay-perl
+
+RUN apt-get install -y --no-install-recommends \
+`# Php dependencies` \
+      php \
+      php-cli \
+      php-dev \
+      php-pear \
+      re2c \
+      composer
+
+RUN apt-get install -y --no-install-recommends \
+`# Python dependencies` \
+      python-all \
+      python-all-dbg \
+      python-all-dev \
+      python-ipaddress \
+      python-pip \
+      python-setuptools \
+      python-six \
+      python-tornado \
+      python-twisted \
+      python-wheel \
+      python-zope.interface && \
+   pip install --upgrade backports.ssl_match_hostname
+
+RUN apt-get install -y --no-install-recommends \
+`# Python3 dependencies` \
+      python3-all \
+      python3-all-dbg \
+      python3-all-dev \
+      python3-pip \
+      python3-setuptools \
+      python3-six \
+      python3-tornado \
+      python3-twisted \
+      python3-wheel \
+      python3-zope.interface
+
+RUN apt-get install -y --no-install-recommends \
+`# Ruby dependencies` \
+      ruby \
+      ruby-dev \
+      ruby-bundler
+
+RUN apt-get install -y --no-install-recommends \
+`# Rust dependencies` \
+      cargo \
+      rustc
+
+RUN apt-get install -y --no-install-recommends \
+`# Static Code Analysis dependencies` \
+      cppcheck \
+      sloccount && \
+    pip install flake8
+
+# Clean up
+RUN rm -rf /var/cache/apt/* && \
+    rm -rf /var/lib/apt/lists/* && \
+    rm -rf /tmp/* && \
+    rm -rf /var/tmp/*
+
+ENV THRIFT_ROOT /thrift
+RUN mkdir -p $THRIFT_ROOT/src
+COPY Dockerfile $THRIFT_ROOT/
+WORKDIR $THRIFT_ROOT/src
diff --git a/build/docker/ubuntu-bionic/Dockerfile b/build/docker/ubuntu-bionic/Dockerfile
new file mode 100644
index 0000000..43c99a9
--- /dev/null
+++ b/build/docker/ubuntu-bionic/Dockerfile
@@ -0,0 +1,279 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Apache Thrift Docker build environment for Ubuntu Bionic
+# Using all stock Ubuntu Bionic packaging except for:
+# - cl: want latest
+# - d: dmd does not come with Ubuntu
+# - dart: does not come with Ubuntu. Pinned to last 1.x release
+# - dotnet: does not come with Ubuntu
+# - go: want latest
+# - nodejs: want v8, bionic comes with v6
+#
+
+FROM buildpack-deps:bionic-scm
+MAINTAINER Apache Thrift <dev@thrift.apache.org>
+ENV DEBIAN_FRONTEND noninteractive
+
+### Add apt repos
+
+RUN apt-get update && \
+    apt-get dist-upgrade -y && \
+    apt-get install -y --no-install-recommends \
+      apt \
+      apt-transport-https \
+      apt-utils \
+      curl \
+      dirmngr \
+      software-properties-common \
+      wget
+
+# csharp (mono) - if we ever want a later version
+# RUN echo "deb http://download.mono-project.com/repo/debian xenial main" | tee /etc/apt/sources.list.d/mono.list && \
+#     apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A6A19B38D3D831EF
+
+# Dart
+RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
+    curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \
+      /etc/apt/sources.list.d/dart_stable.list
+ENV DART_VERSION 1.24.3-1
+
+# dotnet (netcore)
+RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \
+    wget -q -O /etc/apt/sources.list.d/microsoft-prod.list https://packages.microsoft.com/config/ubuntu/18.04/prod.list && \
+    chown root:root /etc/apt/trusted.gpg.d/microsoft.gpg && \
+    chown root:root /etc/apt/sources.list.d/microsoft-prod.list
+
+# node.js
+RUN curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \
+    echo "deb https://deb.nodesource.com/node_8.x bionic main" | tee /etc/apt/sources.list.d/nodesource.list
+
+### install general dependencies
+RUN apt-get update && apt-get install -y --no-install-recommends \
+`# General dependencies` \
+      bash-completion \
+      bison \
+      build-essential \
+      clang \
+      cmake \
+      debhelper \
+      flex \
+      gdb \
+      llvm \
+      ninja-build \
+      pkg-config \
+      valgrind \
+      vim
+ENV PATH /usr/lib/llvm-6.0/bin:$PATH
+
+RUN apt-get install -y --no-install-recommends \
+`# C++ dependencies` \
+      libboost-all-dev \
+      libevent-dev \
+      libssl-dev \
+      qt5-default \
+      qtbase5-dev \
+      qtbase5-dev-tools
+
+RUN apt-get install -y --no-install-recommends \
+`# csharp (mono) dependencies` \
+      mono-devel
+
+ENV SBCL_VERSION 1.4.15
+RUN \
+`# Common Lisp (sbcl) dependencies` \
+    curl --version && \
+    curl -o sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 -J -L https://sourceforge.net/projects/sbcl/files/sbcl/${SBCL_VERSION}/sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2/download?use_mirror=managedway# && \
+    tar xjf sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \
+    cd sbcl-${SBCL_VERSION}-x86-64-linux && \
+    ./install.sh && \
+    sbcl --version && \
+    cd .. && \
+    rm -rf sbcl*
+
+ENV D_VERSION     2.083.1
+ENV DMD_DEB       dmd_2.083.1-0_amd64.deb
+RUN \
+`# D dependencies` \
+    wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \
+    dpkg --install ${DMD_DEB} && \
+    rm -f ${DMD_DEB} && \
+    mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
+    git clone -b 'v2.0.2+2.0.16' https://github.com/D-Programming-Deimos/libevent.git deimos-libevent-2.0 && \
+    mv deimos-libevent-2.0/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+    mv deimos-libevent-2.0/C/* /usr/include/dmd/druntime/import/C/ && \
+    rm -rf deimos-libevent-2.0 && \
+    git clone -b 'v2.0.0+1.1.0h' https://github.com/D-Programming-Deimos/openssl.git deimos-openssl-1.1.0h && \
+    mv deimos-openssl-1.1.0h/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+    mv deimos-openssl-1.1.0h/C/* /usr/include/dmd/druntime/import/C/ && \
+    rm -rf deimos-openssl-1.1.0h
+
+RUN apt-get install -y --no-install-recommends \
+      `# Dart dependencies` \
+      dart=$DART_VERSION
+ENV PATH /usr/lib/dart/bin:$PATH
+
+RUN apt-get install -y --no-install-recommends \
+`# dotnet core dependencies` \
+      dotnet-sdk-2.2
+
+RUN apt-get install -y --no-install-recommends \
+`# Erlang dependencies` \
+      erlang-base \
+      erlang-eunit \
+      erlang-dev \
+      erlang-tools \
+      rebar
+
+RUN apt-get install -y --no-install-recommends \
+`# GlibC dependencies` \
+      libglib2.0-dev
+
+# golang
+ENV GOLANG_VERSION 1.11.4
+ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
+ENV GOLANG_DOWNLOAD_SHA256 fb26c30e6a04ad937bbc657a1b5bba92f80096af1e8ee6da6430c045a8db3a5b
+RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \
+      echo "$GOLANG_DOWNLOAD_SHA256  golang.tar.gz" | sha256sum -c - && \
+            tar -C /usr/local -xzf golang.tar.gz && \
+                  ln -s /usr/local/go/bin/go /usr/local/bin && \
+                        rm golang.tar.gz
+
+RUN apt-get install -y --no-install-recommends \
+`# Haskell dependencies` \
+      ghc \
+      cabal-install
+
+RUN apt-get install -y --no-install-recommends \
+`# Haxe dependencies` \
+      haxe \
+      neko \
+      neko-dev && \
+    haxelib setup --always /usr/share/haxe/lib && \
+    haxelib install --always hxcpp 2>&1 > /dev/null
+
+RUN apt-get install -y --no-install-recommends \
+`# Java dependencies` \
+      ant \
+      ant-optional \
+      openjdk-8-jdk \
+      maven && \
+    update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
+
+RUN apt-get install -y --no-install-recommends \
+`# Lua dependencies` \
+      lua5.2 \
+      lua5.2-dev
+# https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212
+# lua5.3 does not install alternatives!
+# need to update our luasocket code, lua doesn't have luaL_openlib any more
+
+RUN apt-get install -y --no-install-recommends \
+`# Node.js dependencies` \
+      nodejs
+
+# Test dependencies for running puppeteer
+RUN apt-get install -y --no-install-recommends \
+`# JS dependencies` \
+      libxss1
+
+RUN apt-get install -y --no-install-recommends \
+`# OCaml dependencies` \
+      ocaml \
+      opam && \
+    opam init --yes && \
+    opam install --yes oasis
+
+RUN apt-get install -y --no-install-recommends \
+`# Perl dependencies` \
+      libbit-vector-perl \
+      libclass-accessor-class-perl \
+      libcrypt-ssleay-perl \
+      libio-socket-ssl-perl \
+      libnet-ssleay-perl
+
+RUN apt-get install -y --no-install-recommends \
+`# Php dependencies` \
+      php \
+      php-cli \
+      php-dev \
+      php-pear \
+      re2c \
+      composer
+
+RUN apt-get install -y --no-install-recommends \
+`# Python dependencies` \
+      python-all \
+      python-all-dbg \
+      python-all-dev \
+      python-ipaddress \
+      python-pip \
+      python-setuptools \
+      python-six \
+      python-tornado \
+      python-twisted \
+      python-wheel \
+      python-zope.interface && \
+   pip install --upgrade backports.ssl_match_hostname
+
+RUN apt-get install -y --no-install-recommends \
+`# Python3 dependencies` \
+      python3-all \
+      python3-all-dbg \
+      python3-all-dev \
+      python3-pip \
+      python3-setuptools \
+      python3-six \
+      python3-tornado \
+      python3-twisted \
+      python3-wheel \
+      python3-zope.interface
+
+RUN apt-get install -y --no-install-recommends \
+`# Ruby dependencies` \
+      ruby \
+      ruby-dev \
+      ruby-bundler
+
+RUN apt-get install -y --no-install-recommends \
+`# Rust dependencies` \
+      cargo \
+      rustc
+
+# Swift on Linux for cross tests
+RUN cd / && \
+    wget --quiet https://swift.org/builds/swift-4.2.1-release/ubuntu1804/swift-4.2.1-RELEASE/swift-4.2.1-RELEASE-ubuntu18.04.tar.gz && \
+    tar xf swift-4.2.1-RELEASE-ubuntu18.04.tar.gz --strip-components=1 && \
+    rm swift-4.2.1-RELEASE-ubuntu18.04.tar.gz && \
+    swift --version
+
+# cppcheck-1.82 has a nasty cpp parser bug, so we're using something newer
+RUN apt-get install -y --no-install-recommends \
+`# Static Code Analysis dependencies` \
+      cppcheck \
+      sloccount && \
+    pip install flake8 && \
+    wget -q "https://launchpad.net/ubuntu/+source/cppcheck/1.83-2/+build/14874703/+files/cppcheck_1.83-2_amd64.deb" && \
+    dpkg -i cppcheck_1.83-2_amd64.deb && \
+    rm cppcheck_1.83-2_amd64.deb
+
+# Clean up
+RUN rm -rf /var/cache/apt/* && \
+    rm -rf /var/lib/apt/lists/* && \
+    rm -rf /tmp/* && \
+    rm -rf /var/tmp/*
+
+ENV THRIFT_ROOT /thrift
+RUN mkdir -p $THRIFT_ROOT/src
+COPY Dockerfile $THRIFT_ROOT/
+WORKDIR $THRIFT_ROOT/src
diff --git a/build/docker/ubuntu-xenial/Dockerfile b/build/docker/ubuntu-xenial/Dockerfile
new file mode 100644
index 0000000..3372b4d
--- /dev/null
+++ b/build/docker/ubuntu-xenial/Dockerfile
@@ -0,0 +1,271 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Apache Thrift Docker build environment for Ubuntu Xenial
+# Using all stock Ubuntu Xenial packaging except for:
+# - d: does not come with Ubuntu so we're installing 2.075.1 for coverage
+# - dart: does not come with Ubuntu so we're installing 1.22.1 for coverage
+# - dotnet: does not come with Ubuntu
+# - go: Xenial comes with 1.6, but we need 1.7 or later
+# - nodejs: Xenial comes with 4.2.6 which exits LTS April 2018, so we're installing 6.x
+# - ocaml: causes stack overflow error, just started March 2018 not sure why
+#
+
+FROM buildpack-deps:xenial-scm
+MAINTAINER Apache Thrift <dev@thrift.apache.org>
+ENV DEBIAN_FRONTEND noninteractive
+
+### Add apt repos
+
+RUN apt-get update && \
+    apt-get dist-upgrade -y && \
+    apt-get install -y --no-install-recommends \
+      apt \
+      apt-transport-https \
+      apt-utils \
+      curl \
+      software-properties-common \
+      wget
+
+# csharp (mono)
+# RUN echo "deb http://download.mono-project.com/repo/debian xenial main" | tee /etc/apt/sources.list.d/mono.list && \
+#     apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A6A19B38D3D831EF
+
+# D
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EBCF975E5BA24D5E && \
+    wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list && \
+    wget -qO - https://dlang.org/d-keyring.gpg | apt-key add -
+
+# Dart
+RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
+    curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \
+      /etc/apt/sources.list.d/dart_stable.list
+ENV DART_VERSION 1.22.1-1
+
+# dotnet (core)
+RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \
+    echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > \
+      /etc/apt/sources.list.d/dotnetdev.list
+
+# node.js
+RUN curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \
+    echo "deb https://deb.nodesource.com/node_6.x xenial main" | tee /etc/apt/sources.list.d/nodesource.list
+
+### install general dependencies
+RUN apt-get update && apt-get install -y --no-install-recommends \
+`# General dependencies` \
+      bash-completion \
+      bison \
+      build-essential \
+      clang \
+      cmake \
+      debhelper \
+      flex \
+      gdb \
+      llvm \
+      ninja-build \
+      pkg-config \
+      valgrind \
+      vim
+ENV PATH /usr/lib/llvm-3.8/bin:$PATH
+
+### languages
+
+RUN apt-get install -y --no-install-recommends \
+`# C++ dependencies` \
+      libboost-dev \
+      libboost-filesystem-dev \
+      libboost-program-options-dev \
+      libboost-system-dev \
+      libboost-test-dev \
+      libboost-thread-dev \
+      libevent-dev \
+      libssl-dev \
+      qt5-default \
+      qtbase5-dev \
+      qtbase5-dev-tools
+
+RUN apt-get install -y --no-install-recommends \
+`# csharp (mono) dependencies` \
+      mono-devel
+
+ENV D_VERSION 2.075.1-0
+RUN apt-get install -y --allow-unauthenticated --no-install-recommends \
+`# D dependencies` \
+      dmd-bin=$D_VERSION \
+      libphobos2-dev=$D_VERSION \
+      dub=1.6.0-0 \
+      dfmt \
+      dscanner \
+      libevent-dev \
+      libssl-dev \
+      xdg-utils
+RUN mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
+    curl -sSL https://github.com/D-Programming-Deimos/libevent/archive/master.tar.gz| tar xz && \
+    mv libevent-master/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+    mv libevent-master/C/* /usr/include/dmd/druntime/import/C/ && \
+    rm -rf libevent-master
+RUN curl -sSL https://github.com/D-Programming-Deimos/openssl/archive/v1.1.6+1.0.1g.tar.gz | tar xz && \
+    mv openssl-1.1.6-1.0.1g/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+    mv openssl-1.1.6-1.0.1g/C/* /usr/include/dmd/druntime/import/C/ && \
+    rm -rf openssl-1.1.6-1.0.1g
+
+RUN apt-get install -y --no-install-recommends \
+`# Dart dependencies` \
+      dart=$DART_VERSION
+ENV PATH /usr/lib/dart/bin:$PATH
+
+RUN apt-get install -y --no-install-recommends \
+`# dotnet core dependencies` \
+      dotnet-sdk-2.1.4
+
+RUN apt-get install -y --no-install-recommends \
+`# Erlang dependencies` \
+      erlang-base \
+      erlang-eunit \
+      erlang-dev \
+      erlang-tools \
+      rebar
+
+RUN apt-get install -y --no-install-recommends \
+`# GlibC dependencies` \
+      libglib2.0-dev
+
+# golang
+ENV GOLANG_VERSION 1.7.6
+ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
+ENV GOLANG_DOWNLOAD_SHA256 ad5808bf42b014c22dd7646458f631385003049ded0bb6af2efc7f1f79fa29ea
+RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \
+      echo "$GOLANG_DOWNLOAD_SHA256  golang.tar.gz" | sha256sum -c - && \
+      tar -C /usr/local -xzf golang.tar.gz && \
+      ln -s /usr/local/go/bin/go /usr/local/bin && \
+      rm golang.tar.gz
+
+# due to a bug in cabal in xenial (cabal-install package) we pull in another:
+RUN apt-get install -y --no-install-recommends \
+`# Haskell dependencies` \
+      ghc && \
+    cd /tmp && \
+    wget -q https://www.haskell.org/cabal/release/cabal-install-1.24.0.2/cabal-install-1.24.0.2-x86_64-unknown-linux.tar.gz && \
+    tar xzf cabal-install-1.24.0.2-x86_64-unknown-linux.tar.gz && \
+    find dist-newstyle/ -type f -name cabal -exec mv {} /usr/bin \; && \
+    rm -rf /tmp/cabal* && \
+    cabal --version
+
+RUN apt-get install -y --no-install-recommends \
+`# Haxe dependencies` \
+      haxe \
+      neko \
+      neko-dev \
+      libneko0 && \
+    haxelib setup --always /usr/share/haxe/lib && \
+    haxelib install --always hxcpp 3.4.64 2>&1 > /dev/null
+# note: hxcpp 3.4.185 (latest) no longer ships static libraries, and caused a build failure
+
+RUN apt-get install -y --no-install-recommends \
+`# Java dependencies` \
+      ant \
+      ant-optional \
+      openjdk-8-jdk \
+      maven
+
+RUN apt-get install -y --no-install-recommends \
+`# Lua dependencies` \
+      lua5.2 \
+      lua5.2-dev
+# https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212
+# lua5.3 does not install alternatives so stick with 5.2 here
+
+RUN apt-get install -y --no-install-recommends \
+`# Node.js dependencies` \
+      nodejs
+
+# Test dependencies for running puppeteer
+RUN apt-get install -y --no-install-recommends \
+`# JS dependencies` \
+      libxss1 \
+      libatk-bridge2.0-0 \
+      libgtk-3-0
+
+# THRIFT-4517: causes stack overflows; version too old; skip ocaml in xenial
+# RUN apt-get install -y --no-install-recommends \
+# `# OCaml dependencies` \
+#       ocaml \
+#       opam && \
+#     opam init --yes && \
+#     opam install --yes oasis
+
+RUN apt-get install -y --no-install-recommends \
+`# Perl dependencies` \
+      libbit-vector-perl \
+      libclass-accessor-class-perl \
+      libcrypt-ssleay-perl \
+      libio-socket-ssl-perl \
+      libnet-ssleay-perl
+
+RUN apt-get install -y --no-install-recommends \
+`# Php dependencies` \
+      php7.0 \
+      php7.0-cli \
+      php7.0-dev \
+      php-pear \
+      re2c \
+      composer
+
+RUN apt-get install -y --no-install-recommends \
+`# Python dependencies` \
+      python-all \
+      python-all-dbg \
+      python-all-dev \
+      python-backports.ssl-match-hostname \
+      python-ipaddress \
+      python-pip \
+      python-setuptools \
+      python-six \
+      python-tornado \
+      python-twisted \
+      python-wheel \
+      python-zope.interface \
+      python3-all \
+      python3-all-dbg \
+      python3-all-dev \
+      python3-setuptools \
+      python3-six \
+      python3-tornado \
+      python3-twisted \
+      python3-wheel \
+      python3-zope.interface && \
+    pip install --upgrade backports.ssl_match_hostname
+
+RUN apt-get install -y --no-install-recommends \
+`# Ruby dependencies` \
+      ruby \
+      ruby-dev \
+      ruby-bundler
+
+RUN apt-get install -y --no-install-recommends \
+`# Rust dependencies` \
+      cargo \
+      rustc
+
+# Clean up
+RUN rm -rf /var/cache/apt/* && \
+    rm -rf /var/lib/apt/lists/* && \
+    rm -rf /tmp/* && \
+    rm -rf /var/tmp/*
+
+ENV DOTNET_CLI_TELEMETRY_OPTOUT 1
+ENV THRIFT_ROOT /thrift
+RUN mkdir -p $THRIFT_ROOT/src
+COPY Dockerfile $THRIFT_ROOT/
+WORKDIR $THRIFT_ROOT/src
diff --git a/build/fixchanges.sh b/build/fixchanges.sh
new file mode 100755
index 0000000..6c57b54
--- /dev/null
+++ b/build/fixchanges.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+#
+# 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.
+#
+
+#
+# fixchanges will take a file as input and look for text matching
+# the pattern [THRIFT-nnnn] (the number of digits is not important)
+# which is not a markdown link, and change it to be a markdown link.
+# The tool writes to stdout so you can redirect it to a temporary
+# file and then compare against the original file before replacing
+# it.
+#
+# This tool was developed after the 0.12.0 release to assist with
+# generation of CHANGES.md content.
+#
+
+while IFS='' read -r line || [[ -n "$line" ]]; do
+    if [[ "$line" =~ ^(.*)\[(THRIFT-[[:digit:]]+)\][^\(](.*)$ ]]; then
+        echo "${BASH_REMATCH[1]}[${BASH_REMATCH[2]}](https://issues.apache.org/jira/browse/${BASH_REMATCH[2]}) ${BASH_REMATCH[3]}"
+    else
+        echo "$line"
+    fi
+done < "$1"
diff --git a/build/veralign.sh b/build/veralign.sh
new file mode 100755
index 0000000..61744b4
--- /dev/null
+++ b/build/veralign.sh
@@ -0,0 +1,313 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# The veralign script sets the appropriate versions in all of
+# the package configuration files for all of the supported
+# languages.  It is used to prepare a release or move master
+# forward to the next anticipated version.
+#
+# USAGE
+# -----------------------------------------------------------
+# usage: veralign.sh <oldVersion> <newVersion>
+#
+# EXAMPLE
+# -----------------------------------------------------------
+# $ ./veralign.sh 0.12.0 1.0.0
+# $ ./veralign.sh 1.0.0 1.1.0
+#
+# IMPORTANT USAGE NOTE
+# -----------------------------------------------------------
+# Define the environment variable DRYRUN to have the script
+# print out all matches to the oldVersion hilighted so that
+# you can verify it will change the right things.
+#
+
+declare -A FILES
+
+# These files require a manual touch:
+FILES[CHANGES.md]=manual
+FILES[debian/changelog]=manual
+FILES[doap.rdf]=manual
+
+# These files can be updated automatically:
+FILES[ApacheThrift.nuspec]=simpleReplace
+FILES[Thrift-swift3.podspec]=simpleReplace
+FILES[Thrift.podspec]=simpleReplace
+FILES[appveyor.yml]=simpleReplace
+FILES[bower.json]=jsonReplace
+FILES[build/cmake/DefineCMakeDefaults.cmake]=simpleReplace
+FILES[configure.ac]=configureReplace
+FILES[contrib/thrift.spec]=simpleReplace
+FILES[lib/cocoa/src/Thrift.h]=simpleReplace
+FILES[lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs]=simpleReplace
+FILES[lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj]=simpleReplace
+FILES[lib/csharp/src/Properties/AssemblyInfo.cs]=simpleReplace
+FILES[lib/csharp/src/Thrift.csproj]=simpleReplace
+FILES[lib/csharp/test/Multiplex/Client/MultiplexClient.csproj]=simpleReplace
+FILES[lib/csharp/test/Multiplex/Client/Properties/AssemblyInfo.cs]=simpleReplace
+FILES[lib/csharp/test/Multiplex/Server/MultiplexServer.csproj]=simpleReplace
+FILES[lib/csharp/test/Multiplex/Server/Properties/AssemblyInfo.cs]=simpleReplace
+FILES[lib/csharp/test/ThriftMVCTest/Properties/AssemblyInfo.cs]=simpleReplace
+FILES[lib/d/src/thrift/base.d]=simpleReplace
+FILES[lib/dart/pubspec.yaml]=pubspecReplace
+FILES[lib/delphi/src/Thrift.pas]=simpleReplace
+FILES[lib/erl/src/thrift.app.src]=simpleReplace
+FILES[lib/haxe/haxelib.json]=simpleReplace
+FILES[lib/hs/thrift.cabal]=simpleReplace
+FILES[lib/java/gradle.properties]=simpleReplace
+FILES[lib/js/package.json]=jsonReplace
+FILES[lib/js/src/thrift.js]=simpleReplace
+FILES[lib/lua/Thrift.lua]=simpleReplace
+FILES[lib/netcore/Thrift/Properties/AssemblyInfo.cs]=simpleReplace
+FILES[lib/netcore/Thrift/Transports/Client/THttpClientTransport.cs]=simpleReplace
+FILES[lib/ocaml/_oasis]=simpleReplace
+FILES[lib/perl/lib/Thrift.pm]=simpleReplace
+FILES[lib/py/setup.py]=simpleReplace
+FILES[lib/rb/thrift.gemspec]=simpleReplace
+FILES[lib/rs/Cargo.toml]=simpleReplace
+FILES[lib/st/package.xml]=simpleReplace
+FILES[package.json]=jsonReplace
+FILES[sonar-project.properties]=simpleReplace
+FILES[test/csharp/Properties/AssemblyInfo.cs]=simpleReplace
+FILES[test/csharp/ThriftTest.csproj]=simpleReplace
+FILES[test/dart/test_client/pubspec.yaml]=pubspecReplace
+FILES[test/erl/src/thrift_test.app.src]=simpleReplace
+FILES[tutorial/csharp/CsharpClient/Properties/AssemblyInfo.cs]=simpleReplace
+FILES[tutorial/csharp/CsharpServer/Properties/AssemblyInfo.cs]=simpleReplace
+FILES[tutorial/dart/client/pubspec.yaml]=pubspecReplace
+FILES[tutorial/dart/console_client/pubspec.yaml]=pubspecReplace
+FILES[tutorial/dart/server/pubspec.yaml]=pubspecReplace
+FILES[tutorial/delphi/DelphiClient/DelphiClient.dproj]=simpleReplace
+FILES[tutorial/delphi/DelphiServer/DelphiServer.dproj]=simpleReplace
+FILES[tutorial/hs/ThriftTutorial.cabal]=simpleReplace
+FILES[tutorial/ocaml/_oasis]=simpleReplace
+
+if [ ! -f "CHANGES" ]; then
+    >&2 echo "error: run veralign.sh while in the thrift root directory"
+    exit 1
+fi
+
+if [ $# -ne 2 ]; then
+    >&2 echo "usage: veralign.sh <oldVersion> <newVersion>"
+    exit 1
+fi
+
+jq --version 1>/dev/null 2>/dev/null
+if [ $? -ne 0 ]; then
+    >&2 echo "error: the 'jq' package is not installed"
+    exit 1
+fi
+
+#
+# validateVersion: check that a version matches the major.minor.patch
+#   format which is the lowest common denominator supported by all
+#   project systems.
+# \param $1 the version
+# \returns 0 if the version is compliant
+#
+function validateVersion
+{
+    local result
+    local valid
+    valid=$(echo "$1" | sed '/^[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+$/!{q22}')
+    result=$?
+    if [ $result -eq 22 ]; then
+        >&2 echo "error: version '$1' does not conform to the required major.minor.patch format"
+        return ${result}
+    fi
+}
+
+OLDVERSION=$1
+NEWVERSION=$2
+validateVersion "${OLDVERSION}" || exit $?
+validateVersion "${NEWVERSION}" || exit $?
+
+#
+# escapeVersion: escape the version for use as a sed search
+# \param $1 the version to escape
+# \output the escaped string
+# \returns 0
+# \example VERSEARCH=$(escapeVersion "[1.0.0]"); echo $VERSEARCH; => "\[1\.0\.0\]"
+#
+function escapeVersion
+{
+    echo "$(echo $1 | sed 's/\./\\./g' | sed 's/\[/\\\[/g' | sed 's/\]/\\\]/g')"
+}
+
+# Set up verbose hilighting if running interactive
+if [ "$(tput colors)" -ne 0 ]; then
+    reverse=$(tput rev)
+    red=$(tput setaf 1)
+    green=$(tput setaf 2)
+    yellow=$(tput setaf 3)
+    normal=$(tput sgr0)
+fi
+
+declare -A MANUAL
+
+#
+# manual: note that update of said file is manual
+# \param $1 filename to do replacements on
+# \returns 0
+#
+function manual
+{
+    MANUAL["$1"]=""
+    return 0
+}
+
+#
+# configureReplace: replace the AC_INIT field in configure.ac
+# \param $1 filename to do replacements on
+# \returns 0 on success
+#
+
+function configureReplace
+{
+    replace "$1" "[thrift], [${OLDVERSION}]" "[thrift], [${NEWVERSION}]"
+}
+
+#
+# jsonReplace: replace a specific version field in a JSON file
+#   must be a top level "version" field in the json structure
+# \param $1 filename to do replacements on
+# \returns 0 on success
+#
+
+function jsonReplace
+{
+    local result
+    local output
+    if [ ! -z "$DRYRUN" ]; then
+        output=$(jq -e ".version" "$1")
+    else
+        output=$(jq -e ".version = \"${NEWVERSION}\"" "$1" > tmp.$$.json && mv tmp.$$.json "$1")
+    fi
+    result=$?
+    if [ $? -ne 0 ]; then
+        printf "%-60s | %5d | ${red}ERROR${normal}: version tag not found" "$1" "$count"
+        echo
+        return 1
+    elif [ ! -z "$DRYRUN" ]; then
+        output=${output%\"}
+        output=${output#\"}
+        printf "%-60s | %5d | MATCHES:   version: \"${reverse}${green}${output}${normal}\"" "$1" 1
+        echo
+        return 0
+    fi
+    printf "%-60s | %5d | ${green}OK${normal}" "$1" 1
+    echo
+    return 0
+}
+
+#
+# pubspecReplace: replace a specific version field in a YAML file
+#   must be a top level "version" field in the yaml structure
+#   did not find a package that preserves comments so this is
+#   somewhat brain-dead, but it gets the job done
+# \param $1 filename to do replacements on
+# \returns 0 on success
+#
+
+function pubspecReplace
+{
+    replace "$1" "version: ${OLDVERSION}" "version: ${NEWVERSION}"
+}
+
+#
+# replace: replace occurrences of one string with another
+#     the file specified must contain the old string at least once
+#     in order to be successful.
+# \param $1 filename to do replacements on
+# \param $2 the "old" string to be replaced
+# \param $3 the "new" striing to replace it with
+# \returns 0 on success
+#
+function replace
+{
+    local result
+    local output
+    local oldString="$2"
+    local newString="$3"
+    local oldRegex=$(escapeVersion "${oldString}")
+    local count=$(grep -Ec "${oldRegex}" "$1")
+    local verbose
+    if [ $count -eq 0 ]; then
+        printf "%-60s | %5d | ${red}NOT FOUND${normal}: ${oldString}" "$1" 0
+        echo
+        return 1
+    elif [ ! -z "$DRYRUN" ]; then
+        printf "%-60s | %5d | MATCHES:" "$1" "$count"
+        echo
+        while read -r line; do
+            echo " > $(echo "$line" | sed "s/${oldRegex}/${reverse}${green}${oldString}${normal}/g")"
+        done < <(grep -E "${oldRegex}" "$1")
+        return 0
+    fi
+    output=$(sed -i "s/${oldRegex}/${newString}/g" "$1")
+    result=$?
+    if [ $result -ne 0 ]; then
+        printf "%-60s | %5d | ${red}ERROR${normal}: %s" "$1" "$count" "$output"
+        echo
+        return 1
+    fi
+    printf "%-60s | %5d | ${green}OK${normal}" "$1" "$count"
+    echo
+    return 0
+}
+
+#
+# simpleReplace: replace occurrences of ${OLDVERSION} with ${NEWVERSION}
+#     the file specified must contain OLDVERSION at least once
+#     in order to be successful.
+# \param $1 filename to do replacements on
+# \param $2 the "old" string to be replaced
+# \param $3 the "new" striing to replace it with
+# \returns 0 on success
+#
+function simpleReplace
+{
+    replace "$1" "${OLDVERSION}" "${NEWVERSION}"
+}
+
+echo ""
+echo "Apache Thrift Version Alignment Tool"
+echo "------------------------------------"
+echo ""
+echo "Previous Version: ${OLDVERSION}"
+echo "     New Version: ${NEWVERSION}"
+echo ""
+echo "-------------------------------------------------------------+-------+----------------------"
+echo "Filename                                                     | Count | Status               "
+echo "-------------------------------------------------------------+-------+----------------------"
+
+for file in $(echo "${!FILES[@]}" | sort); do
+    ${FILES[$file]} $file || exit $?
+done
+
+echo
+echo "Files that must be modified manually:"
+echo
+for manu in $(echo "${!MANUAL[@]}" | sort); do
+    echo " > ${yellow}${manu}${normal}"
+done
+
+exit 0
diff --git a/build/wincpp/README.md b/build/wincpp/README.md
new file mode 100644
index 0000000..a231780
--- /dev/null
+++ b/build/wincpp/README.md
@@ -0,0 +1,219 @@
+<!---
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Building thrift on Windows (Native)
+
+Thrift uses cmake to make it easier to build the project on multiple platforms, however to build a fully functional and production ready thrift on Windows requires a number of third party libraries to be obtained or built.  Once third party libraries are ready, the right combination of options must be passed to cmake in order to generate the correct environment.
+
+## Summary
+
+These instructions will help you build thrift for windows using Visual
+Studio 2010 or later.  The contributed batch files will help you build
+the third party libraries needed for complete thrift functionality as
+well as thrift itself.
+
+These instructions follow a directory layout that looks like the following:
+
+    workspace\
+      build\       - this is where the out-of-tree thrift cmake builds are generated
+      dist\        - this is where the thrift build results end up
+      thirdparty\  - this is where all third party binaries and libraries live
+        build\       - this is where all third party out-of-tree builds are generated
+                       (except for openssl, which only builds in-tree)
+        dist\        - this is where all third party distributions end up
+        src\         - this is where all third party source projects live
+      scripts\     - batch files used to set environment variables for builds
+      thrift\      - this is where the thrift source project lives
+
+Create a "workspace" directory somewhere on your system and then copy the contents of this
+directory to there, then clone or unpack thrift into `workspace\thrift`.
+
+## Third Party Libraries
+
+Batch scripts are provided to build some third party libraries.  You must download them and place them into the directory noted for each.  You can use different versions if you prefer; these instructions were made with the versions listed.  
+
+> TIP: To modify the versions used in the batch scripts, look in scripts\tpversions.bat.
+
+Build them in the order listed to satisfy their dependencies.
+
+### winflexbison
+
+        source: web site
+      location: https://sourceforge.net/projects/winflexbison/files/win_flex_bison-latest.zip/download
+       version: "latest"
+     directory: workspace\thirdparty\dist\winflexbison
+
+This package is required to build the compiler.  This third party package does not need to be built as it is a binary distribution of the "bison" and "flex" tools normally found on Unix boxes.
+
+> TIP: If you are only interested in building the compiler, you can skip the remaining third party libraries.
+
+### zlib
+
+        source: web site
+      location: http://zlib.net/
+       version: 1.2.9
+     directory: workspace\thirdparty\src\zlib-1.2.9
+
+To build, open the appropriate Visual Studio command prompt and then run 
+the build-zlib.bat script in thirdparty\src.
+ 
+### openssl
+
+        source: web site
+      location: https://www.openssl.org/
+       version: 1.1.0c
+     directory: workspace\thirdparty\src\openssl-1.1.0c
+    depends-on: zlib
+
+If you are using openssl-1.1.0 or later, they changed static builds to use Microsoft Static RTL for release builds.  zlib by default uses a dynamic runtime, as does libevent.  Edit the file Configurations/10-main.conf and replace the section contents for "VC-noCE-common" with what appears below to make openssl build with dynamic runtime instead:
+
+    "VC-noCE-common" => {
+        inherit_from     => [ "VC-common" ],
+        template         => 1,
+        cflags           => add(picker(default => "-DUNICODE -D_UNICODE",
+                                       debug   => "/MDd /Od -DDEBUG -D_DEBUG",
+                                       release => "/MD /O2"
+                                      )),
+        bin_cflags       => add(picker(debug   => "/MDd",
+                                       release => "/MD",
+                                      )),
+        bin_lflags       => add("/subsystem:console /opt:ref"),
+        ex_libs          => add(sub {
+            my @ex_libs = ();
+            push @ex_libs, 'ws2_32.lib' unless $disabled{sock};
+            push @ex_libs, 'gdi32.lib advapi32.lib crypt32.lib user32.lib';
+            return join(" ", @ex_libs);
+        }),
+    },
+
+To build, open the appropriate Visual Studio command prompt and then run 
+the build-openssl.bat script in thirdparty\src.
+
+### libevent
+
+        source: git
+      location: https://github.com/nmathewson/Libevent.git
+           use: commit 3821cca1a637f4da4099c9343e7326da00f6981c or later
+          date: Fri Dec 23 16:19:35 2016 +0800 or later
+       version: corresponds to 2.1.7rc + patches
+     directory: workspace\thirdparty\src\libevent-2.1.7rc2
+    depends-on: openssl, zlib
+
+To build, open the appropriate Visual Studio command prompt and then run 
+the build-libevent.bat script in thirdparty\src.
+
+### msinttypes
+
+        source: web site
+      location: https://code.google.com/archive/p/msinttypes/downloads
+       version: 26
+     directory: workspace\thirdparty\dist\msinttypes
+
+> TIP: This is only necessary for Visual Studio 2010, which did not include an <inttypes.h> header.
+
+This third party package does not need to be built as it is a distribution of header files.
+
+### boost
+
+        source: web site
+      location: http://boost.teeks99.com/
+       version: 1_62_0
+     directory: workspace\thirdparty\dist\boost_1_62_0
+
+The pre-built binary versions of boost come in self-unpacking executables.  Run each of the ones you are interested in and point them at the same thirdparty dist directory.
+
+## Building a Production thrift Compiler
+
+### Prerequisites
+
+* CMake-2.8.12.2 or later
+* Visual Studio 2010 or later
+* thrift source placed into workspace\thrift
+* winflexbison placed into workspace\thirdparty\dist
+
+### Instructions
+
+By following these instructions you will end up with a release mode thrift compiler that is suitable for distribution as it has no external dependencies.  
+
+1. Open the appropriate Visual Studio Command Prompt.
+2. `cd workspace`
+3. `build-thrift-compiler.bat`
+
+The batch file uses CMake to generate an out-of-tree build directory in `workspace\build` and then builds the compiler.  The resulting `thrift.exe` program is placed into `workspace\dist` in a path that depends on your compiler version and platform.  For example, if you use a Visual Studio 2010 x64 Command Prompt, the compiler will be placed into `workspace\dist\thrift-compiler-dev\vc100\x64\Release\thrift.exe`
+
+#### Details
+
+This section is for those who are curious about the CMake options used in the build process.
+
+CMake takes the source tree as the first argument and uses the remaining arguments for configuration.  The batch file `build-thrift-compiler` essentially performs the following commands:
+
+    C:\> CD workspace\build
+    C:\workspace\build> "C:\Program Files\CMake\bin\cmake.exe" ..\thrift 
+                          -DBISON_EXECUTABLE=..\thirdparty\dist\winflexbison\win_bison.exe
+                          -DCMAKE_BUILD_TYPE=Release
+                          -DFLEX_EXECUTABLE=..\thirdparty\dist\winflexbison\win_flex.exe
+                          -DWITH_MT=ON
+                          -DWITH_SHARED_LIB=OFF
+                          -G"NMake Makefiles"
+    C:\workspace\build> NMAKE /FMakefile thrift-compiler
+
+WITH_MT controls the dynamic or static runtime library selection.  To build a production compiler, the thrift project recommends using the static runtime library to make the executable portable.  The batch file sets this.
+
+You can build a Visual Studio project file by following the example but substituting a different generator for the "-G" option.  Run `cmake.exe --help` for a list of generators.  Typically, this is one of the following on Windows (omit "Win64" to build 32-bit instead):
+
+* "Visual Studio 10 2010 Win64"
+* "Visual Studio 11 2012 Win64"
+* "Visual Studio 12 2013 Win64"
+* "Visual Studio 14 2015 Win64"
+* "Visual Studio 15 2017 Win64"
+
+For example you can build using a Visual Studio solution file on the command line by doing:
+
+    C:\> CD workspace\build
+    C:\workspace\build> "C:\Program Files\CMake\bin\cmake.exe" ..\thrift 
+                          -DBISON_EXECUTABLE=..\thirdparty\dist\winflexbison\win_bison.exe
+                          -DCMAKE_BUILD_TYPE=Release
+                          -DFLEX_EXECUTABLE=..\thirdparty\dist\winflexbison\win_flex.exe
+                          -DWITH_MT=ON
+                          -DWITH_SHARED_LIB=OFF
+                          -G"Visual Studio 14 2015 Win64"
+    C:\workspace\build> MSBUILD "Apache Thrift.sln" /p:Configuration=Release /p:Platform=x64 /t:thrift-compiler
+
+You can also double-click on the solution file to bring it up in Visual Studio and build or debug interactively from there.
+
+## Building the thrift C++ Run-Time Library
+
+These instructions are similar to the compiler build however there are additional dependencies on third party libraries to build a feature-complete runtime.  The resulting static link library for thrift uses a dynamic Microsoft runtime.
+
+1. Open the desired Visual Studio Command Prompt.
+2. `cd workspace`
+3. `build-thrift.bat`
+
+Thrift depends on boost, libevent, openssl, and zlib in order to build with all server and transport types.  To use later versions of boost like 1.62 you will need a recent version of cmake (at least 3.7).
+
+The build-thrift script has options to build debug or release and to optionally disable any of the generation (cmake), build, or test phases.  By default, the batch file will generate an out-of-tree build directory inside `workspace\build`, then perform a release build, then run the unit tests.  The batch file accepts some option flags to control its behavior:
+
+    :: Flags you can use to change this behavior:
+    ::
+    ::   /DEBUG            - if building, perform a debug build instead
+    ::   /NOGENERATE       - skip cmake generation - useful if you
+    ::                       have already generated a solution and just
+    ::                       want to build
+    ::   /NOBUILD          - skip cmake build - useful if you just
+    ::                       want to generate a solution
+    ::   /NOTEST           - skip ctest execution
+
+For example if you want to generate the cmake environment without building or running tests:
+
+    C:\workspace> build-thrift.bat /NOBUILD /NOTEST
diff --git a/build/wincpp/build-thrift-compiler.bat b/build/wincpp/build-thrift-compiler.bat
new file mode 100644
index 0000000..b6b42a8
--- /dev/null
+++ b/build/wincpp/build-thrift-compiler.bat
@@ -0,0 +1,79 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+:: 
+::     http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+:: 
+
+::
+:: Produces a production thrift compiler suitable for redistribution.
+:: The compiler is linked to runtime statically for maximum portability.
+:: Assumes the thirdparty files for "winflexbison" have been placed
+:: according to the README.md instructions.
+::
+:: Open a Visual Studio Command Prompt of your choosing and then
+:: run this script.  
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+IF NOT DEFINED PACKAGE_NAME    SET PACKAGE_NAME=thrift
+IF NOT DEFINED PACKAGE_VERSION SET PACKAGE_VERSION=dev
+IF NOT DEFINED SOURCE_DIR      SET SOURCEDIR=%~dp0%PACKAGE_NAME%
+IF NOT DEFINED WIN3P_ROOT      SET WIN3P_ROOT=%~dp0thirdparty
+
+:: Set COMPILER to (vc100 - vc140) depending on the current environment
+CALL scripts\cl_setcompiler.bat || EXIT /B
+
+:: Set ARCH to either win32 or x64 depending on the current environment
+CALL scripts\cl_setarch.bat || EXIT /B
+
+:: Set GENERATOR for CMake depending on the current environment
+CALL scripts\cl_setgenerator.bat || EXIT /B
+
+IF NOT DEFINED BUILDTYPE (
+  SET BUILDTYPE=Release
+)
+
+  SET BUILDDIR=%~dp0build\%PACKAGE_NAME%-compiler\%PACKAGE_VERSION%\%COMPILER%\
+  SET OUTDIR=%~dp0dist\%PACKAGE_NAME%-compiler-%PACKAGE_VERSION%\%COMPILER%\%ARCH%\%BUILDTYPE%\
+  SET BOOST_LIBDIR=lib%ARCH:~-2,2%-msvc-%COMPILER:~-3,2%.0
+  IF "%BUILDTYPE%" == "Debug" (SET ZLIB_STATIC_SUFFIX=d)
+
+  ECHO/
+  ECHO =========================================================================
+  ECHO     Configuration: %PACKAGE_NAME% %PACKAGE_VERSION% %COMPILER%:%ARCH%:%BUILDTYPE% "%GENERATOR%"
+IF DEFINED COMPILERONLY (
+  ECHO                    COMPILER ONLY
+)
+  ECHO   Build Directory: %BUILDDIR%
+  ECHO Install Directory: %OUTDIR%
+  ECHO  Source Directory: %SOURCEDIR%
+  ECHO =========================================================================
+  ECHO/
+
+  MKDIR "%BUILDDIR%"
+  CD "%BUILDDIR%" || EXIT /B
+
+  CMAKE.EXE %~dp0thrift ^
+    -G"%GENERATOR%" ^
+    -DBISON_EXECUTABLE=%WIN3P_ROOT%\dist\winflexbison\win_bison.exe ^
+    -DCMAKE_BUILD_TYPE=%BUILDTYPE% ^
+    -DFLEX_EXECUTABLE=%WIN3P_ROOT%\dist\winflexbison\win_flex.exe ^
+    -DWITH_MT=ON ^
+    -DWITH_SHARED_LIB=OFF || EXIT /B
+
+  CD %BUILDDIR%
+
+  CMAKE.EXE --build . --config %BUILDTYPE% --target thrift-compiler || EXIT /B
+  XCOPY /F /Y %BUILDDIR%\bin\%BUILDTYPE%\thrift.exe %OUTDIR%
+
+ENDLOCAL
+EXIT /B
diff --git a/build/wincpp/build-thrift.bat b/build/wincpp/build-thrift.bat
new file mode 100644
index 0000000..b867acf
--- /dev/null
+++ b/build/wincpp/build-thrift.bat
@@ -0,0 +1,163 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+:: 
+::     http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+:: 
+
+::
+:: Generates a Visual Studio solution for thrift and then builds it.
+:: Assumes third party libraries have been built or placed already.
+::
+:: Open a Visual Studio Command Prompt of your choosing and then
+:: run this script.  
+::
+:: Normally the script will run cmake to generate a solution, then
+:: perform a build, then run tests on the complete thrift library
+:: in release mode.
+::
+:: Flags you can use to change this behavior:
+::
+::   /DEBUG            - debug instead of release
+::   /IDE              - launch Visual Studio with a path set
+::                       up correctly to run tests instead of
+::                       performing any other actions, i.e.
+::                       implies setting the next three flags
+::   /NOGENERATE       - skip cmake generation - useful if you
+::                       have already generated a solution and just
+::                       want to build
+::   /NOBUILD          - skip cmake build - useful if you just
+::                       want to generate a solution
+::   /NOTEST           - skip ctest execution
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+:: Sets variables for third party versions used in build
+CALL scripts\tpversions.bat || EXIT /B
+
+IF NOT DEFINED PACKAGE_NAME    SET PACKAGE_NAME=thrift
+IF NOT DEFINED PACKAGE_VERSION SET PACKAGE_VERSION=dev
+IF NOT DEFINED SOURCE_DIR      SET SOURCEDIR=%~dp0%PACKAGE_NAME%
+IF NOT DEFINED WIN3P_ROOT      SET WIN3P_ROOT=%~dp0thirdparty
+
+:: Set COMPILER to (vc100 - vc140) depending on the current environment
+CALL scripts\cl_setcompiler.bat || EXIT /B
+
+:: Set ARCH to either win32 or x64 depending on the current environment
+CALL scripts\cl_setarch.bat || EXIT /B
+
+:: Set GENERATOR for CMake depending on the current environment
+CALL scripts\cl_setgenerator.bat || EXIT /B
+
+:: Defaults
+
+IF NOT DEFINED BUILDTYPE SET BUILDTYPE=Release
+SET OPT_IDE=0
+SET OPT_BUILD=1
+SET OPT_GENERATE=1
+SET OPT_TEST=1
+
+:: Apply Flags
+
+IF /I "%1" == "/DEBUG"        SET BUILDTYPE=Debug
+IF /I "%2" == "/DEBUG"        SET BUILDTYPE=Debug
+IF /I "%3" == "/DEBUG"        SET BUILDTYPE=Debug
+IF /I "%1" == "/IDE"          SET OPT_IDE=1
+IF /I "%2" == "/IDE"          SET OPT_IDE=1
+IF /I "%3" == "/IDE"          SET OPT_IDE=1
+IF /I "%1" == "/NOBUILD"      SET OPT_BUILD=0
+IF /I "%2" == "/NOBUILD"      SET OPT_BUILD=0
+IF /I "%3" == "/NOBUILD"      SET OPT_BUILD=0
+IF /I "%1" == "/NOGENERATE"   SET OPT_GENERATE=0
+IF /I "%2" == "/NOGENERATE"   SET OPT_GENERATE=0
+IF /I "%3" == "/NOGENERATE"   SET OPT_GENERATE=0
+IF /I "%1" == "/NOTEST"       SET OPT_TEST=0
+IF /I "%2" == "/NOTEST"       SET OPT_TEST=0
+IF /I "%3" == "/NOTEST"       SET OPT_TEST=0
+
+IF %OPT_IDE% == 1 (
+  SET OPT_GENERATE=0
+  SET OPT_BUILD=0
+  SET OPT_TEST=0
+)
+
+  SET BUILDDIR=%~dp0build\%PACKAGE_NAME%\%PACKAGE_VERSION%\%COMPILER%\%ARCH%\
+  SET OUTDIR=%~dp0dist\%PACKAGE_NAME%-%PACKAGE_VERSION%\%COMPILER%\%ARCH%\%BUILDTYPE%\
+  SET BOOST_LIBDIR=lib%ARCH:~-2,2%-msvc-%COMPILER:~-3,2%.0
+  IF "%BUILDTYPE%" == "Debug" (SET ZLIB_STATIC_SUFFIX=d)
+
+  ECHO/
+  ECHO =========================================================================
+  ECHO     Configuration: %PACKAGE_NAME% %PACKAGE_VERSION% %COMPILER%:%ARCH%:%BUILDTYPE% "%GENERATOR%"
+IF DEFINED COMPILERONLY (
+  ECHO                    COMPILER ONLY
+)
+  ECHO   Build Directory: %BUILDDIR%
+  ECHO Install Directory: %OUTDIR%
+  ECHO  Source Directory: %SOURCEDIR%
+  ECHO =========================================================================
+  ECHO/
+
+IF %OPT_IDE% == 1 (
+
+  CALL :SETRUNPATH || EXIT /B
+  CALL DEVENV "!BUILDDIR!Apache Thrift.sln" || EXIT /B
+  EXIT /B
+  
+)
+
+  MKDIR "%BUILDDIR%"
+  CD "%BUILDDIR%" || EXIT /B
+
+IF %OPT_GENERATE% == 1 (
+
+  CMAKE.EXE %~dp0thrift ^
+    -G"%GENERATOR%" ^
+    -DBISON_EXECUTABLE=%WIN3P_ROOT%\dist\winflexbison\win_bison.exe ^
+    -DBOOST_ROOT=%WIN3P_ROOT%\dist\boost_%TP_BOOST_VERSION% ^
+    -DBOOST_LIBRARYDIR=%WIN3P_ROOT%\dist\boost_%TP_BOOST_VERSION%\%BOOST_LIBDIR% ^
+    -DCMAKE_INSTALL_PREFIX=%OUTDIR% ^
+    -DCMAKE_BUILD_TYPE=%BUILDTYPE% ^
+    -DFLEX_EXECUTABLE=%WIN3P_ROOT%\dist\winflexbison\win_flex.exe ^
+    -DINTTYPES_ROOT=%WIN3P_ROOT%\dist\msinttypes ^
+    -DLIBEVENT_ROOT=%WIN3P_ROOT%\dist\libevent-%TP_LIBEVENT_VERSION%\%COMPILER%\%ARCH%\%BUILDTYPE% ^
+    -DOPENSSL_ROOT_DIR=%WIN3P_ROOT%\dist\openssl-%TP_OPENSSL_VERSION%\%COMPILER%\%ARCH%\%BUILDTYPE%\dynamic ^
+    -DOPENSSL_USE_STATIC_LIBS=OFF ^
+    -DZLIB_LIBRARY=%WIN3P_ROOT%\dist\zlib-%TP_ZLIB_VERSION%\%COMPILER%\%ARCH%\lib\zlib%ZLIB_LIB_SUFFIX%.lib ^
+    -DZLIB_ROOT=%WIN3P_ROOT%\dist\zlib-%TP_ZLIB_VERSION%\%COMPILER%\%ARCH% ^
+    -DWITH_SHARED_LIB=OFF ^
+    -DWITH_STATIC_LIB=ON || EXIT /B
+
+)
+
+IF %OPT_BUILD% == 1 (
+
+  CD %BUILDDIR%
+  CMAKE.EXE --build . --config %BUILDTYPE% --target INSTALL || EXIT /B
+
+)
+
+IF %OPT_TEST% == 1 (
+
+  CALL :SETRUNPATH || EXIT /B
+  CMAKE.EXE --build . --config %BUILDTYPE% --target RUN_TESTS || EXIT /B
+  
+)
+
+:SETRUNPATH
+  SET PATH=!PATH!;%WIN3P_ROOT%\dist\boost_%TP_BOOST_VERSION%\%BOOST_LIBDIR%
+  SET PATH=!PATH!;%WIN3P_ROOT%\dist\openssl-%TP_OPENSSL_VERSION%\%COMPILER%\%ARCH%\%BUILDTYPE%\dynamic\bin
+  SET PATH=!PATH!;%WIN3P_ROOT%\dist\zlib-%TP_ZLIB_VERSION%\%COMPILER%\%ARCH%\bin
+  EXIT /B
+
+ENDLOCAL
+EXIT /B
diff --git a/build/wincpp/scripts/cl_setarch.bat b/build/wincpp/scripts/cl_setarch.bat
new file mode 100644
index 0000000..9570a1e
--- /dev/null
+++ b/build/wincpp/scripts/cl_setarch.bat
@@ -0,0 +1,47 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+:: 
+::     http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+:: 
+
+::
+:: Detect the architecture we're building for.
+:: Set the ARCH environment variable to one of:
+::   win32
+::   x64
+::
+:: Honors any existing ARCH environment variable
+::   setting instead of overwriting it, to allow it
+::   to be forced if needed.
+::
+:: Sets ERRORLEVEL to 0 if ARCH can be determined,
+::                 to 1 if it cannot.
+::
+
+IF DEFINED ARCH (
+  ECHO [warn ] using existing environment variable ARCH
+  EXIT /B 0
+)
+
+CALL :CHECK x64
+IF %ERRORLEVEL% == 0 (SET ARCH=x64) ELSE (SET ARCH=win32)
+
+IF NOT DEFINED ARCH (
+  ECHO [error] unable to determine the target architecture
+  EXIT /B 1
+)
+
+ECHO [info ] detected target architecture %ARCH%
+EXIT /B 0
+
+:CHECK
+cl /? 2>&1 | findstr /C:" for %1%" > nul
+EXIT /B %ERRORLEVEL%
diff --git a/build/wincpp/scripts/cl_setcompiler.bat b/build/wincpp/scripts/cl_setcompiler.bat
new file mode 100644
index 0000000..8405d76
--- /dev/null
+++ b/build/wincpp/scripts/cl_setcompiler.bat
@@ -0,0 +1,58 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+:: 
+::     http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+:: 
+
+::
+:: Detect the compiler edition we're building in.
+:: Set the COMPILER environment variable to one of:
+::   vc100 = Visual Studio 2010
+::   vc110 = Visual Studio 2012
+::   vc120 = Visual Studio 2013
+::   vc140 = Visual Studio 2015
+::   vc150 = Visual Studio 2017
+::
+:: Honors any existing COMPILER environment variable
+::   setting instead of overwriting it, to allow it
+::   to be forced if needed.
+::
+:: Sets ERRORLEVEL to 0 if COMPILER can be determined,
+::                 to 1 if it cannot.
+::
+
+IF DEFINED COMPILER (
+  ECHO [warn ] using existing environment variable COMPILER
+  EXIT /B 0
+)
+
+CALL :CHECK 16
+IF %ERRORLEVEL% == 0 (IF NOT DEFINED COMPILER SET COMPILER=vc100)
+CALL :CHECK 17
+IF %ERRORLEVEL% == 0 (IF NOT DEFINED COMPILER SET COMPILER=vc110)
+CALL :CHECK 18
+IF %ERRORLEVEL% == 0 (IF NOT DEFINED COMPILER SET COMPILER=vc120)
+CALL :CHECK 19.00
+IF %ERRORLEVEL% == 0 (IF NOT DEFINED COMPILER SET COMPILER=vc140)
+CALL :CHECK 19.10
+IF %ERRORLEVEL% == 0 (IF NOT DEFINED COMPILER SET COMPILER=vc150)
+
+IF NOT DEFINED COMPILER (
+  ECHO [error] unable to determine the compiler edition
+  EXIT /B 1
+)
+
+ECHO [info ] detected compiler edition    %COMPILER%
+EXIT /B 0
+
+:CHECK
+cl /? 2>&1 | findstr /C:"Version %1%." > nul
+EXIT /B %ERRORLEVEL%
diff --git a/build/wincpp/scripts/cl_setgenerator.bat b/build/wincpp/scripts/cl_setgenerator.bat
new file mode 100644
index 0000000..bae2742
--- /dev/null
+++ b/build/wincpp/scripts/cl_setgenerator.bat
@@ -0,0 +1,69 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+:: 
+::     http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+:: 
+
+::
+:: Detect the compiler edition we're building in and then 
+:: set the GENERATOR environment variable to one of:
+::
+::  Visual Studio 15 2017 [arch] = Generates Visual Studio 2017 project files.
+::                                 Optional [arch] can be "Win64" or "ARM".
+::  Visual Studio 14 2015 [arch] = Generates Visual Studio 2015 project files.
+::                                 Optional [arch] can be "Win64" or "ARM".
+::  Visual Studio 12 2013 [arch] = Generates Visual Studio 2013 project files.
+::                                 Optional [arch] can be "Win64" or "ARM".
+::  Visual Studio 11 2012 [arch] = Generates Visual Studio 2012 project files.
+::                                 Optional [arch] can be "Win64" or "ARM".
+::  Visual Studio 10 2010 [arch] = Generates Visual Studio 2010 project files.
+::                                 Optional [arch] can be "Win64" or "IA64".
+::
+:: Honors any existing GENERATOR environment variable
+::   setting instead of overwriting it, to allow it
+::   to be forced if needed.
+::
+:: Sets ERRORLEVEL to 0 if GENERATOR can be determined,
+::                 to 1 if it cannot.
+::
+:: Requires cl_setarch.bat to have been executed or the ARCH environment
+:: variable to be set.
+::
+
+IF "%ARCH%" == "x64" (SET GENARCH= Win64)
+
+IF DEFINED GENERATOR (
+  ECHO [warn ] using existing environment variable GENERATOR
+  EXIT /B 0
+)
+
+CALL :CHECK 16
+IF %ERRORLEVEL% == 0 (IF NOT DEFINED GENERATOR SET GENERATOR=Visual Studio 10 2010%GENARCH%)
+CALL :CHECK 17
+IF %ERRORLEVEL% == 0 (IF NOT DEFINED GENERATOR SET GENERATOR=Visual Studio 11 2012%GENARCH%)
+CALL :CHECK 18
+IF %ERRORLEVEL% == 0 (IF NOT DEFINED GENERATOR SET GENERATOR=Visual Studio 12 2013%GENARCH%)
+CALL :CHECK 19.00
+IF %ERRORLEVEL% == 0 (IF NOT DEFINED GENERATOR SET GENERATOR=Visual Studio 14 2015%GENARCH%)
+CALL :CHECK 19.10
+IF %ERRORLEVEL% == 0 (IF NOT DEFINED GENERATOR SET GENERATOR=Visual Studio 15 2017%GENARCH%)
+
+IF NOT DEFINED GENERATOR (
+  ECHO [error] unable to determine the CMake generator to use
+  EXIT /B 1
+)
+
+ECHO [info ] using CMake generator        %GENERATOR%
+EXIT /B 0
+
+:CHECK
+cl /? 2>&1 | findstr /C:"Version %1%." > nul
+EXIT /B %ERRORLEVEL%
diff --git a/build/wincpp/scripts/tpversions.bat b/build/wincpp/scripts/tpversions.bat
new file mode 100644
index 0000000..d80c868
--- /dev/null
+++ b/build/wincpp/scripts/tpversions.bat
@@ -0,0 +1,24 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+:: 
+::     http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+:: 
+
+::
+:: Set the versions of third party libraries to use.
+::
+
+IF NOT DEFINED TP_BOOST_VERSION    SET TP_BOOST_VERSION=1_62_0
+IF NOT DEFINED TP_LIBEVENT_VERSION SET TP_LIBEVENT_VERSION=2.1.7rc2
+IF NOT DEFINED TP_OPENSSL_VERSION  SET TP_OPENSSL_VERSION=1.1.0c
+IF NOT DEFINED TP_ZLIB_VERSION     SET TP_ZLIB_VERSION=1.2.9
+
+EXIT /B 0
diff --git a/build/wincpp/thirdparty/src/build-libevent.bat b/build/wincpp/thirdparty/src/build-libevent.bat
new file mode 100644
index 0000000..4af505c
--- /dev/null
+++ b/build/wincpp/thirdparty/src/build-libevent.bat
@@ -0,0 +1,86 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+:: 
+::     http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+:: 
+
+::
+:: Build script for libevent on windows
+:: Use libevent master from github which has cmake integration
+:: Uses the environment set up by a Visual Studio Command Prompt shortcut
+:: to target a specific architecture and compiler
+::
+:: Creates a static link library.
+:: Links against OpenSSL and zlib statically.
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+:: Sets variables for third party versions used in build
+CALL ..\..\scripts\tpversions.bat || EXIT /B
+
+:: use "build-libevent.bat /yes" to skip the question part
+IF /I "%1" == "/YES"           SET NOASK=1
+
+:: Set COMPILER to (vc100 - vc140) depending on the current environment
+CALL ..\..\scripts\cl_setcompiler.bat || EXIT /B
+
+:: Set ARCH to either win32 or x64 depending on the current environment
+CALL ..\..\scripts\cl_setarch.bat || EXIT /B
+
+IF NOT DEFINED GENERATOR       SET GENERATOR=NMake Makefiles
+IF NOT DEFINED PACKAGE_NAME    SET PACKAGE_NAME=libevent
+IF NOT DEFINED PACKAGE_VERSION SET PACKAGE_VERSION=%TP_LIBEVENT_VERSION%
+IF NOT DEFINED SOURCEDIR       SET SOURCEDIR=%~dp0%PACKAGE_NAME%-%PACKAGE_VERSION%
+IF NOT DEFINED WIN3P_ROOT      SET WIN3P_ROOT=%~dp0..
+
+FOR %%X IN (
+  Debug 
+  Release
+) DO (
+  SET BUILDTYPE=%%X
+  SET BUILDDIR=%WIN3P_ROOT%\build\%PACKAGE_NAME%\%PACKAGE_VERSION%\%COMPILER%\%ARCH%\!BUILDTYPE!
+  SET OUTDIR=%WIN3P_ROOT%\dist\%PACKAGE_NAME%-%PACKAGE_VERSION%\%COMPILER%\%ARCH%\!BUILDTYPE!
+
+  IF "!BUILDTYPE!" == "Debug" (SET ZLIB_LIB_SUFFIX=d)
+
+  SET CMAKE_DEFS=^
+   -DEVENT__DISABLE_SAMPLES=ON ^
+   -DEVENT__DISABLE_TESTS=ON ^
+   -DOPENSSL_USE_STATIC_LIBS=OFF ^
+   -DOPENSSL_ROOT_DIR=%WIN3P_ROOT%\dist\openssl-%TP_OPENSSL_VERSION%\%COMPILER%\%ARCH%\!BUILDTYPE!\dynamic ^
+   -DZLIB_LIBRARY=%WIN3P_ROOT%\dist\zlib-%TP_ZLIB_VERSION%\%COMPILER%\%ARCH%\lib\zlib!ZLIB_LIB_SUFFIX!.lib ^
+   -DZLIB_ROOT=%WIN3P_ROOT%\dist\zlib-%TP_ZLIB_VERSION%\%COMPILER%\%ARCH%
+
+  ECHO/
+  ECHO =========================================================================
+  ECHO          Building: %PACKAGE_NAME% v%PACKAGE_VERSION% %COMPILER%:%ARCH%:!BUILDTYPE! "%GENERATOR%"
+  ECHO CMake Definitions: !CMAKE_DEFS!
+  ECHO   Build Directory: !BUILDDIR!
+  ECHO Install Directory: !OUTDIR!
+  ECHO  Source Directory: %SOURCEDIR%
+  ECHO =========================================================================
+  ECHO/
+
+  IF NOT DEFINED NOASK (
+    CHOICE /M "Do you want to build this configuration? " /c YN
+    IF !ERRORLEVEL! NEQ 1 (EXIT /B !ERRORLEVEL!)
+  )
+  
+  MKDIR "!BUILDDIR!"
+  CD "!BUILDDIR!" || EXIT /B
+
+  CMAKE.EXE -G"%GENERATOR%" -DCMAKE_INSTALL_PREFIX=!OUTDIR! -DCMAKE_BUILD_TYPE=!BUILDTYPE! !CMAKE_DEFS! "%SOURCEDIR%" || EXIT /B
+  NMAKE /fMakefile install || EXIT /B
+)
+
+ENDLOCAL
diff --git a/build/wincpp/thirdparty/src/build-openssl.bat b/build/wincpp/thirdparty/src/build-openssl.bat
new file mode 100644
index 0000000..cf270f0
--- /dev/null
+++ b/build/wincpp/thirdparty/src/build-openssl.bat
@@ -0,0 +1,106 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+:: 
+::     http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+:: 
+
+::
+:: Build script for openssl on windows
+:: openssl uses an in-tree build so you have to clean between each one
+::
+:: Uses the environment set up by a Visual Studio Command Prompt shortcut
+:: to target a specific architecture and compiler
+::
+:: If you use Lavasoft Ad-Aware, disable it for this build.  It blocks the creation
+:: of any file named "clienthellotest.exe" for whatever reason, which breaks the build.
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+:: Sets variables for third party versions used in build
+CALL ..\..\scripts\tpversions.bat || EXIT /B
+
+:: use "build-openssl.bat /yes" to skip the question part
+IF /I "%1" == "/YES"           SET NOASK=1
+
+IF NOT DEFINED PACKAGE_NAME    SET PACKAGE_NAME=openssl
+IF NOT DEFINED PACKAGE_VERSION SET PACKAGE_VERSION=%TP_OPENSSL_VERSION%
+IF NOT DEFINED SOURCEDIR       SET SOURCEDIR=%~dp0%PACKAGE_NAME%-%PACKAGE_VERSION%
+IF NOT DEFINED WIN3P_ROOT      SET WIN3P_ROOT=%~dp0..
+
+:: Set COMPILER to (vc100 - vc140) depending on the current environment
+CALL ..\..\scripts\cl_setcompiler.bat || EXIT /B
+
+:: Set ARCH to either win32 or x64 depending on the current environment
+CALL ..\..\scripts\cl_setarch.bat || EXIT /B
+
+IF "%ARCH%" == "x64" (
+  SET TODO=debug-VC-WIN64A VC-WIN64A
+) ELSE (
+  SET TODO=debug-VC-WIN32 VC-WIN32
+)
+
+FOR %%X IN ( !TODO! ) DO (
+  SET BUILDTYPE=%%X
+  FOR %%Y IN (
+    nt
+    ntdll
+  ) DO (
+    SET LIBTYPE=%%Y
+
+    IF "!BUILDTYPE:~0,6!" == "debug-" (
+      SET OUTBUILDTYPE=debug
+      SET ZLIBLIBSUFFIX=d
+    ) ELSE (
+      SET OUTBUILDTYPE=release
+      SET ZLIBLIBSUFFIX=
+    )
+
+    IF "!LIBTYPE!" == "ntdll" (
+      SET BUILD_OPTIONS=shared
+      SET OUTLIBTYPE=dynamic
+      SET ZLIBLIB=zlib!ZLIBLIBSUFFIX!
+      SET ZLIBOPT=zlib-dynamic
+    ) ELSE (
+      SET BUILD_OPTIONS=no-shared
+      SET OUTLIBTYPE=static
+      SET ZLIBLIB=zlibstatic!ZLIBLIBSUFFIX!.lib
+      SET ZLIBOPT=zlib
+    )
+
+    SET LIB=%~dp0..\dist\zlib-%TP_ZLIB_VERSION%\!COMPILER!\!ARCH!\lib;!LIB!
+    SET BUILD_OPTIONS=!BUILD_OPTIONS! no-asm no-unit-test !ZLIBOPT! --openssldir=ssl --with-zlib-include=%~dp0..\dist\zlib-%TP_ZLIB_VERSION%\!COMPILER!\!ARCH!\include --with-zlib-lib=!ZLIBLIB!
+    SET OUTDIR=%WIN3P_ROOT%\dist\%PACKAGE_NAME%-%PACKAGE_VERSION%\%COMPILER%\%ARCH%\!OUTBUILDTYPE!\!OUTLIBTYPE!
+
+    ECHO/
+    ECHO =========================================================================
+    ECHO          Building: %PACKAGE_NAME% %PACKAGE_VERSION% %COMPILER%:%ARCH%:!OUTBUILDTYPE!:!OUTLIBTYPE! [!BUILDTYPE!]
+    ECHO Configure Options: !BUILD_OPTIONS!
+    ECHO Install Directory: !OUTDIR!
+    ECHO  Source Directory: %SOURCEDIR%
+    ECHO =========================================================================
+    ECHO/
+
+    IF NOT DEFINED NOASK (
+      CHOICE /M "Do you want to build this configuration? " /c YN
+      IF !ERRORLEVEL! NEQ 1 (EXIT /B !ERRORLEVEL!)
+    )
+
+    CD %SOURCEDIR% || EXIT /B
+    perl Configure !BUILDTYPE! --prefix="!OUTDIR!" !BUILD_OPTIONS! || EXIT /B
+    NMAKE /FMakefile install_sw || EXIT /B
+    NMAKE /FMakefile clean || EXIT /B
+  )
+)
+
+ENDLOCAL
+EXIT /B
diff --git a/build/wincpp/thirdparty/src/build-zlib.bat b/build/wincpp/thirdparty/src/build-zlib.bat
new file mode 100644
index 0000000..2427230
--- /dev/null
+++ b/build/wincpp/thirdparty/src/build-zlib.bat
@@ -0,0 +1,75 @@
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+:: 
+::     http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+:: 
+
+::
+:: Build script for zlib on windows.
+:: Uses the environment set up by a Visual Studio Command Prompt shortcut
+:: to target a specific architecture and compiler.
+::
+
+@ECHO OFF
+SETLOCAL EnableDelayedExpansion
+
+:: Sets variables for third party versions used in build
+CALL ..\..\scripts\tpversions.bat || EXIT /B
+
+:: use "build-zlib.bat /yes" to skip the question part
+IF /I "%1" == "/YES"           SET NOASK=1
+
+IF NOT DEFINED GENERATOR       SET GENERATOR=NMake Makefiles
+IF NOT DEFINED PACKAGE_NAME    SET PACKAGE_NAME=zlib
+IF NOT DEFINED PACKAGE_VERSION SET PACKAGE_VERSION=%TP_ZLIB_VERSION%
+IF NOT DEFINED SOURCE_DIR      SET SOURCEDIR=%~dp0%PACKAGE_NAME%-%PACKAGE_VERSION%
+IF NOT DEFINED WIN3P_ROOT      SET WIN3P_ROOT=%~dp0..
+
+:: Set COMPILER to (vc100 - vc140) depending on the current environment
+CALL ..\..\scripts\cl_setcompiler.bat || EXIT /B
+
+:: Set ARCH to either win32 or x64 depending on the current environment
+CALL ..\..\scripts\cl_setarch.bat || EXIT /B
+
+FOR %%X IN (
+  Debug 
+  Release
+) DO (
+  SET BUILDTYPE=%%X
+  SET BUILDDIR=%WIN3P_ROOT%\build\%PACKAGE_NAME%\%PACKAGE_VERSION%\%COMPILER%\%ARCH%\!BUILDTYPE!
+  SET OUTDIR=%WIN3P_ROOT%\dist\%PACKAGE_NAME%-%PACKAGE_VERSION%\%COMPILER%\%ARCH%
+
+  ECHO/
+  ECHO =========================================================================
+  ECHO          Building: %PACKAGE_NAME% v%PACKAGE_VERSION% %COMPILER%:%ARCH%:!BUILDTYPE! "%GENERATOR%"
+  ECHO   Build Directory: !BUILDDIR!
+  ECHO Install Directory: !OUTDIR!
+  ECHO  Source Directory: %SOURCEDIR%
+  ECHO =========================================================================
+  ECHO/
+
+  IF NOT DEFINED NOASK (
+    CHOICE /M "Do you want to build this configuration? " /c YN
+    IF !ERRORLEVEL! NEQ 1 (EXIT /B !ERRORLEVEL!)
+  )
+
+  MKDIR "!BUILDDIR!"
+  CD "!BUILDDIR!" || EXIT /B
+
+  CMAKE.EXE -G"%GENERATOR%" -DCMAKE_INSTALL_PREFIX=!OUTDIR! -DCMAKE_BUILD_TYPE=!BUILDTYPE! "%SOURCEDIR%" || EXIT /B
+  NMAKE /fMakefile install || EXIT /B
+
+  IF "!BUILDTYPE!" == "Debug" (
+    COPY "!BUILDDIR!\zlibd.pdb" "!OUTDIR!\bin\" || EXIT /B
+  )
+)
+
+ENDLOCAL
diff --git a/compiler/cpp/CMakeLists.txt b/compiler/cpp/CMakeLists.txt
new file mode 100644
index 0000000..0df790e
--- /dev/null
+++ b/compiler/cpp/CMakeLists.txt
@@ -0,0 +1,221 @@
+#
+# 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.
+#
+cmake_minimum_required(VERSION 2.8.12)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/thrift/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/thrift/version.h)
+if(MSVC)
+    # The winflexbison generator outputs some macros that conflict with the Visual Studio 2010 copy of stdint.h
+    # This might be fixed in later versions of Visual Studio, but an easy solution is to include stdint.h first
+    if(HAVE_STDINT_H)
+        add_definitions(-D__STDC_FORMAT_MACROS)
+        add_definitions(-D__STDC_LIMIT_MACROS)
+        add_definitions(/FI"stdint.h")
+    endif(HAVE_STDINT_H)
+endif()
+
+find_package(FLEX REQUIRED)
+find_package(BISON REQUIRED)
+
+# create directory for thrifty and thriftl
+file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/thrift/)
+
+# Create flex and bison files and build the lib parse static library
+BISON_TARGET(thrifty ${CMAKE_CURRENT_SOURCE_DIR}/src/thrift/thrifty.yy ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.cc)
+FLEX_TARGET(thriftl ${CMAKE_CURRENT_SOURCE_DIR}/src/thrift/thriftl.ll ${CMAKE_CURRENT_BINARY_DIR}/thrift/thriftl.cc)
+ADD_FLEX_BISON_DEPENDENCY(thriftl thrifty)
+
+set(parse_SOURCES
+    ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.cc
+    ${CMAKE_CURRENT_BINARY_DIR}/thrift/thriftl.cc
+    ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.hh
+)
+
+add_library(parse STATIC ${parse_SOURCES})
+
+# Create the thrift compiler
+set(compiler_core
+    src/thrift/common.cc
+    src/thrift/generate/t_generator.cc
+    src/thrift/parse/t_typedef.cc
+    src/thrift/parse/parse.cc
+    ${CMAKE_CURRENT_BINARY_DIR}/thrift/version.h
+)
+
+set(thrift-compiler_SOURCES
+    src/thrift/main.cc
+    src/thrift/audit/t_audit.cpp
+)
+
+set(thrift_compiler_LANGS
+)
+
+# This macro adds an option THRIFT_COMPILER_${NAME}
+# that allows enabling or disabling certain languages
+macro(THRIFT_ADD_COMPILER name description initial)
+    string(TOUPPER "THRIFT_COMPILER_${name}" enabler)
+    set(src "src/thrift/generate/t_${name}_generator.cc")
+    option(${enabler} ${description} ${initial})
+    if(${enabler})
+        list(APPEND thrift-compiler_SOURCES ${src})
+        list(APPEND thrift_compiler_LANGS ${name})
+    endif()
+endmacro()
+
+# The following compiler can be enabled or disabled
+THRIFT_ADD_COMPILER(c_glib  "Enable compiler for C with Glib" ON)
+THRIFT_ADD_COMPILER(cpp     "Enable compiler for C++" ON)
+THRIFT_ADD_COMPILER(java    "Enable compiler for Java"   ON)
+THRIFT_ADD_COMPILER(as3     "Enable compiler for ActionScript 3" ON)
+THRIFT_ADD_COMPILER(dart    "Enable compiler for Dart" ON)
+THRIFT_ADD_COMPILER(haxe    "Enable compiler for Haxe" ON)
+THRIFT_ADD_COMPILER(csharp  "Enable compiler for C#" ON)
+THRIFT_ADD_COMPILER(netcore "Enable compiler for .NET Core" ON)
+THRIFT_ADD_COMPILER(py      "Enable compiler for Python 2.0" ON)
+THRIFT_ADD_COMPILER(rb      "Enable compiler for Ruby" ON)
+THRIFT_ADD_COMPILER(perl    "Enable compiler for Perl" ON)
+THRIFT_ADD_COMPILER(php     "Enable compiler for PHP" ON)
+THRIFT_ADD_COMPILER(erl     "Enable compiler for Erlang" ON)
+THRIFT_ADD_COMPILER(cocoa   "Enable compiler for Cocoa Objective-C" ON)
+THRIFT_ADD_COMPILER(swift   "Enable compiler for Cocoa Swift" ON)
+THRIFT_ADD_COMPILER(st      "Enable compiler for Smalltalk" ON)
+THRIFT_ADD_COMPILER(ocaml   "Enable compiler for OCaml" ON)
+THRIFT_ADD_COMPILER(hs      "Enable compiler for Haskell" ON)
+THRIFT_ADD_COMPILER(xsd     "Enable compiler for XSD" ON)
+THRIFT_ADD_COMPILER(html    "Enable compiler for HTML Documentation" ON)
+THRIFT_ADD_COMPILER(js      "Enable compiler for JavaScript" ON)
+THRIFT_ADD_COMPILER(json    "Enable compiler for JSON" ON)
+THRIFT_ADD_COMPILER(javame  "Enable compiler for Java ME" ON)
+THRIFT_ADD_COMPILER(delphi  "Enable compiler for Delphi" ON)
+THRIFT_ADD_COMPILER(go      "Enable compiler for Go" ON)
+THRIFT_ADD_COMPILER(d       "Enable compiler for D" ON)
+THRIFT_ADD_COMPILER(lua     "Enable compiler for Lua" ON)
+THRIFT_ADD_COMPILER(gv      "Enable compiler for GraphViz" ON)
+THRIFT_ADD_COMPILER(rs      "Enable compiler for Rust" ON)
+THRIFT_ADD_COMPILER(xml     "Enable compiler for XML" ON)
+
+# Thrift is looking for include files in the src directory
+# we also add the current binary directory for generated files
+include_directories(${CMAKE_CURRENT_BINARY_DIR} src)
+
+if(NOT DEFINED WITH_PLUGIN OR NOT ${WITH_PLUGIN})
+    list(APPEND thrift-compiler_SOURCES ${compiler_core})
+endif()
+
+add_executable(thrift-compiler ${thrift-compiler_SOURCES})
+
+if(${WITH_PLUGIN})
+    add_executable(thrift-bootstrap ${compiler_core}
+        src/thrift/main.cc
+        src/thrift/audit/t_audit.cpp
+        src/thrift/generate/t_cpp_generator.cc
+    )
+    target_link_libraries(thrift-bootstrap parse)
+
+    set(PLUGIN_GEN_SOURCES
+        ${CMAKE_CURRENT_BINARY_DIR}/thrift/plugin/plugin_types.h
+        ${CMAKE_CURRENT_BINARY_DIR}/thrift/plugin/plugin_types.cpp
+        ${CMAKE_CURRENT_BINARY_DIR}/thrift/plugin/plugin_constants.h
+        ${CMAKE_CURRENT_BINARY_DIR}/thrift/plugin/plugin_constants.cpp
+    )
+
+    file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/thrift/plugin)
+    add_custom_command(OUTPUT ${PLUGIN_GEN_SOURCES}
+        DEPENDS thrift-bootstrap src/thrift/plugin/plugin.thrift
+        COMMAND thrift-bootstrap -gen cpp
+        -out ${CMAKE_CURRENT_BINARY_DIR}/thrift/plugin
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/thrift/plugin/plugin.thrift
+    )
+
+    include_directories(../../lib/cpp/src)
+
+    include(ThriftMacros)
+    ADD_LIBRARY_THRIFT(thriftc
+        ${compiler_core}
+        ${PLUGIN_GEN_SOURCES}
+        src/thrift/logging.cc
+        src/thrift/plugin/plugin_output.cc
+        src/thrift/plugin/plugin.cc
+    )
+    TARGET_INCLUDE_DIRECTORIES_THRIFT(thriftc PUBLIC ${Boost_INCLUDE_DIRS})
+    TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY(thriftc thrift PUBLIC)
+    target_compile_definitions(thrift-compiler PUBLIC THRIFT_ENABLE_PLUGIN)
+    LINK_AGAINST_THRIFT_LIBRARY(thrift-compiler thriftc)
+endif()
+
+set_target_properties(thrift-compiler PROPERTIES RUNTIME_OUTPUT_DIRECTORY bin/)
+set_target_properties(thrift-compiler PROPERTIES OUTPUT_NAME thrift)
+
+target_link_libraries(thrift-compiler parse)
+
+install(TARGETS thrift-compiler DESTINATION bin)
+
+if(${WITH_PLUGIN})
+  # Install the headers
+  install(FILES
+      "src/thrift/common.h"
+      "src/thrift/globals.h"
+      "src/thrift/logging.h"
+      "src/thrift/main.h"
+      "src/thrift/platform.h"
+      "${CMAKE_BINARY_DIR}/compiler/cpp/thrift/version.h"
+      DESTINATION "${INCLUDE_INSTALL_DIR}/thrift")
+  install(FILES
+      "src/thrift/audit/t_audit.h"
+      DESTINATION "${INCLUDE_INSTALL_DIR}/thrift/audit")
+  install(FILES
+      "src/thrift/generate/t_generator.h"
+      "src/thrift/generate/t_generator_registry.h"
+      "src/thrift/generate/t_html_generator.h"
+      "src/thrift/generate/t_oop_generator.h"
+      DESTINATION "${INCLUDE_INSTALL_DIR}/thrift/generate")
+  install(FILES
+      "src/thrift/parse/t_base_type.h"
+      "src/thrift/parse/t_const.h"
+      "src/thrift/parse/t_const_value.h"
+      "src/thrift/parse/t_container.h"
+      "src/thrift/parse/t_doc.h"
+      "src/thrift/parse/t_enum.h"
+      "src/thrift/parse/t_enum_value.h"
+      "src/thrift/parse/t_field.h"
+      "src/thrift/parse/t_function.h"
+      "src/thrift/parse/t_list.h"
+      "src/thrift/parse/t_map.h"
+      "src/thrift/parse/t_program.h"
+      "src/thrift/parse/t_scope.h"
+      "src/thrift/parse/t_service.h"
+      "src/thrift/parse/t_set.h"
+      "src/thrift/parse/t_struct.h"
+      "src/thrift/parse/t_typedef.h"
+      "src/thrift/parse/t_type.h"
+      DESTINATION "${INCLUDE_INSTALL_DIR}/thrift/parse")
+  install(FILES
+      "src/thrift/plugin/plugin.h"
+      "src/thrift/plugin/plugin_output.h"
+      "src/thrift/plugin/type_util.h"
+      DESTINATION "${INCLUDE_INSTALL_DIR}/thrift/plugin")
+if(MSVC)
+  install(FILES
+      "src/thrift/windows/config.h"
+      DESTINATION "${INCLUDE_INSTALL_DIR}/thrift/windows")
+endif()
+endif()
+
+if(BUILD_TESTING)
+    add_subdirectory(test)
+endif()
diff --git a/compiler/cpp/Makefile.am b/compiler/cpp/Makefile.am
index 4c0e71d..0b8ef2e 100644
--- a/compiler/cpp/Makefile.am
+++ b/compiler/cpp/Makefile.am
@@ -21,97 +21,187 @@
 # Please see doc/old-thrift-license.txt in the Thrift distribution for
 # details.
 
-# Override Automake rule that forces .hh extension 
-am__yacc_c2h = sed -e s/cc$$/h/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \
-           -e s/c++$$/h++/ -e s/c$$/h/
+AUTOMAKE_OPTIONS = subdir-objects
 
-AM_YFLAGS = -d
-LIBS =
-BUILT_SOURCES =
+# Note on why we have src/thrift and src/thrift/plugin directories:
+# Since Automake supports only one set of BUILT_SOURCES per file and does not allow
+# SUBDIRS built before BUILT_SOURCES, we end up separate Makefile.am for each source
+# code generation, i.e. lex-yacc and Thrift, to achieve stable parallel make.
+
+SUBDIRS = src src/thrift/plugin .
+if WITH_TESTS
+SUBDIRS += test
+endif
 
 bin_PROGRAMS = thrift
 
-noinst_LIBRARIES = libparse.a
-
 thrift_OBJDIR = obj
 
-thrift_SOURCES = src/main.cc \
-                 src/md5.c \
-                 src/generate/t_generator.cc \
-                 src/generate/t_generator_registry.h \
-                 src/globals.h \
-                 src/main.h \
-                 src/platform.h \
-                 src/md5.h \
-                 src/parse/t_doc.h \
-                 src/parse/t_type.h \
-                 src/parse/t_base_type.h \
-                 src/parse/t_enum.h \
-                 src/parse/t_enum_value.h \
-                 src/parse/t_typedef.h \
-                 src/parse/t_container.h \
-                 src/parse/t_list.h \
-                 src/parse/t_set.h \
-                 src/parse/t_map.h \
-                 src/parse/t_struct.h \
-                 src/parse/t_field.h \
-                 src/parse/t_service.h \
-                 src/parse/t_function.h \
-                 src/parse/t_program.h \
-                 src/parse/t_scope.h \
-                 src/parse/t_const.h \
-                 src/parse/t_const_value.h \
-                 src/parse/parse.cc \
-                 src/generate/t_generator.h \
-                 src/generate/t_oop_generator.h \
-                 src/generate/t_html_generator.h \
-                 src/windows/config.h \
-                 src/windows/version.h
+plugin_gen = src/thrift/plugin/plugin_types.h \
+             src/thrift/plugin/plugin_types.cpp \
+             src/thrift/plugin/plugin_constants.h \
+             src/thrift/plugin/plugin_constants.cpp
+
+compiler_core =  src/thrift/common.h \
+                 src/thrift/common.cc \
+                 src/thrift/generate/t_generator.cc \
+                 src/thrift/generate/t_generator_registry.h \
+                 src/thrift/globals.h \
+                 src/thrift/platform.h \
+                 src/thrift/logging.h \
+                 src/thrift/parse/t_doc.h \
+                 src/thrift/parse/t_type.h \
+                 src/thrift/parse/t_base_type.h \
+                 src/thrift/parse/t_enum.h \
+                 src/thrift/parse/t_enum_value.h \
+                 src/thrift/parse/t_typedef.h \
+                 src/thrift/parse/t_typedef.cc \
+                 src/thrift/parse/t_container.h \
+                 src/thrift/parse/t_list.h \
+                 src/thrift/parse/t_set.h \
+                 src/thrift/parse/t_map.h \
+                 src/thrift/parse/t_struct.h \
+                 src/thrift/parse/t_field.h \
+                 src/thrift/parse/t_service.h \
+                 src/thrift/parse/t_function.h \
+                 src/thrift/parse/t_program.h \
+                 src/thrift/parse/t_scope.h \
+                 src/thrift/parse/t_const.h \
+                 src/thrift/parse/t_const_value.h \
+                 src/thrift/parse/parse.cc \
+                 src/thrift/generate/t_generator.h \
+                 src/thrift/generate/t_oop_generator.h \
+                 src/thrift/generate/t_html_generator.h 
+
+thrift_SOURCES = src/thrift/main.h \
+                 src/thrift/main.cc \
+                 src/thrift/audit/t_audit.cpp \
+                 src/thrift/audit/t_audit.h
 
 # Specific client generator source
-thrift_SOURCES += src/generate/t_c_glib_generator.cc \
-                  src/generate/t_cpp_generator.cc \
-                  src/generate/t_java_generator.cc \
-                  src/generate/t_as3_generator.cc \
-                  src/generate/t_csharp_generator.cc \
-                  src/generate/t_py_generator.cc \
-                  src/generate/t_rb_generator.cc \
-                  src/generate/t_perl_generator.cc \
-                  src/generate/t_php_generator.cc \
-                  src/generate/t_erl_generator.cc \
-                  src/generate/t_cocoa_generator.cc \
-                  src/generate/t_st_generator.cc \
-                  src/generate/t_ocaml_generator.cc \
-                  src/generate/t_hs_generator.cc \
-                  src/generate/t_xsd_generator.cc \
-                  src/generate/t_html_generator.cc \
-                  src/generate/t_js_generator.cc \
-                  src/generate/t_javame_generator.cc \
-                  src/generate/t_delphi_generator.cc \
-                  src/generate/t_go_generator.cc \
-                  src/generate/t_gv_generator.cc \
-                  src/generate/t_d_generator.cc
+thrift_SOURCES += src/thrift/generate/t_c_glib_generator.cc \
+                  src/thrift/generate/t_cpp_generator.cc \
+                  src/thrift/generate/t_java_generator.cc \
+                  src/thrift/generate/t_json_generator.cc \
+                  src/thrift/generate/t_as3_generator.cc \
+                  src/thrift/generate/t_dart_generator.cc \
+                  src/thrift/generate/t_haxe_generator.cc \
+                  src/thrift/generate/t_csharp_generator.cc \
+                  src/thrift/generate/t_netcore_generator.cc \
+                  src/thrift/generate/t_netcore_generator.h \
+                  src/thrift/generate/t_py_generator.cc \
+                  src/thrift/generate/t_rb_generator.cc \
+                  src/thrift/generate/t_perl_generator.cc \
+                  src/thrift/generate/t_php_generator.cc \
+                  src/thrift/generate/t_erl_generator.cc \
+                  src/thrift/generate/t_cocoa_generator.cc \
+                  src/thrift/generate/t_swift_generator.cc \
+                  src/thrift/generate/t_st_generator.cc \
+                  src/thrift/generate/t_ocaml_generator.cc \
+                  src/thrift/generate/t_hs_generator.cc \
+                  src/thrift/generate/t_xsd_generator.cc \
+                  src/thrift/generate/t_xml_generator.cc \
+                  src/thrift/generate/t_html_generator.cc \
+                  src/thrift/generate/t_js_generator.cc \
+                  src/thrift/generate/t_javame_generator.cc \
+                  src/thrift/generate/t_delphi_generator.cc \
+                  src/thrift/generate/t_go_generator.cc \
+                  src/thrift/generate/t_gv_generator.cc \
+                  src/thrift/generate/t_d_generator.cc \
+                  src/thrift/generate/t_lua_generator.cc \
+                  src/thrift/generate/t_rs_generator.cc \
+                  src/thrift/generate/t_cl_generator.cc
 
 thrift_CPPFLAGS = -I$(srcdir)/src
-thrift_CXXFLAGS = -Wall
-thrift_LDADD = @LEXLIB@ libparse.a
+thrift_CXXFLAGS = -Wall -Wextra -pedantic -Werror
+thrift_LDADD = @LEXLIB@ src/thrift/libparse.a
 
-libparse_a_CPPFLAGS = -I$(srcdir)/src
-libparse_a_CXXFLAGS = -Wall -Wno-sign-compare -Wno-unused
+if !WITH_PLUGIN
+thrift_SOURCES += $(compiler_core)
+else
 
-libparse_a_SOURCES = src/thrifty.yy \
-                     src/thriftl.ll
+lib_LTLIBRARIES = libthriftc.la
+
+thrift_CPPFLAGS += -DTHRIFT_ENABLE_PLUGIN=1
+thrift_LDADD += libthriftc.la
+
+nodist_libthriftc_la_SOURCES = $(plugin_gen)
+libthriftc_la_SOURCES = $(compiler_core) \
+                        src/thrift/plugin/type_util.h \
+                        src/thrift/plugin/plugin.h \
+                        src/thrift/plugin/plugin.cc \
+                        src/thrift/plugin/plugin_output.h \
+                        src/thrift/plugin/plugin_output.cc \
+                        src/thrift/plugin/plugin.thrift \
+                        src/thrift/logging.cc
+
+
+libthriftc_la_CPPFLAGS = -I$(srcdir)/src -Isrc -I$(top_builddir)/lib/cpp/src -DTHRIFT_ENABLE_PLUGIN=1
+libthriftc_la_CXXFLAGS = -Wall -Wextra -pedantic
+libthriftc_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la
+
+include_thriftdir = $(includedir)/thrift
+include_thrift_HEADERS = src/thrift/common.h \
+                         src/thrift/globals.h \
+                         src/thrift/logging.h \
+                         src/thrift/main.h \
+                         src/thrift/platform.h \
+                         src/thrift/version.h
+
+include_auditdir = $(include_thriftdir)/windows
+include_audit_HEADERS = src/thrift/audit/t_audit.h
+
+include_generatedir = $(include_thriftdir)/generate
+include_generate_HEADERS = src/thrift/generate/t_generator.h \
+                           src/thrift/generate/t_generator_registry.h \
+                           src/thrift/generate/t_oop_generator.h \
+                           src/thrift/generate/t_html_generator.h 
+
+include_parsedir = $(include_thriftdir)/parse
+include_parse_HEADERS = src/thrift/parse/t_service.h \
+                        src/thrift/parse/t_program.h \
+                        src/thrift/parse/t_field.h \
+                        src/thrift/parse/t_scope.h \
+                        src/thrift/parse/t_typedef.h \
+                        src/thrift/parse/t_set.h \
+                        src/thrift/parse/t_const_value.h \
+                        src/thrift/parse/t_enum_value.h \
+                        src/thrift/parse/t_const.h \
+                        src/thrift/parse/t_list.h \
+                        src/thrift/parse/t_map.h \
+                        src/thrift/parse/t_container.h \
+                        src/thrift/parse/t_base_type.h \
+                        src/thrift/parse/t_enum.h \
+                        src/thrift/parse/t_function.h \
+                        src/thrift/parse/t_type.h \
+                        src/thrift/parse/t_doc.h \
+                        src/thrift/parse/t_struct.h
+
+include_plugindir = $(include_thriftdir)/plugin
+include_plugin_HEADERS = src/thrift/plugin/plugin.h \
+                         src/thrift/plugin/type_util.h \
+                         src/thrift/plugin/plugin_output.h
+
+include_windowsdir = $(include_thriftdir)/windows
+include_windows_HEADERS = src/thrift/windows/config.h
+endif
 
 WINDOWS_DIST = \
              compiler.sln \
              compiler.vcxproj \
-             compiler.vcxproj.filters \
-             README_Windows.txt
+             compiler.vcxproj.filters
 
 EXTRA_DIST = \
+             coding_standards.md \
+             README.md \
+             CMakeLists.txt \
+             test \
              $(WINDOWS_DIST)
 
 clean-local:
-	$(RM) thriftl.cc thrifty.cc thrifty.h thrifty.hh version.h windows/version.h
+	$(RM) version.h $(plugin_gen)
 
-src/main.cc: version.h
+src/thrift/main.cc: src/thrift/version.h
+
+style-local:
+  $(CPPSTYLE_CMD)
diff --git a/compiler/cpp/README.md b/compiler/cpp/README.md
new file mode 100644
index 0000000..32eac9f
--- /dev/null
+++ b/compiler/cpp/README.md
@@ -0,0 +1,175 @@
+# Build Thrift IDL compiler using CMake
+
+<!-- TOC -->
+
+- [Build Thrift IDL compiler using CMake](#build-thrift-idl-compiler-using-cmake)
+    - [Build on Unix-like System](#build-on-unix-like-system)
+        - [Prerequisites](#prerequisites)
+        - [Build using CMake](#build-using-cmake)
+            - [Build with Eclipse IDE](#build-with-eclipse-ide)
+            - [Build with XCode IDE in MacOS](#build-with-xcode-ide-in-macos)
+            - [Usage of other IDEs](#usage-of-other-ides)
+    - [Build on Windows](#build-on-windows)
+        - [Prerequisites](#prerequisites-1)
+        - [Build using Git Bash](#build-using-git-bash)
+        - [Using Visual Studio and Win flex-bison](#using-visual-studio-and-win-flex-bison)
+        - [Cross compile using mingw32 and generate a Windows Installer with CPack](#cross-compile-using-mingw32-and-generate-a-windows-installer-with-cpack)
+- [Other cases](#other-cases)
+    - [Building the Thrift IDL compiler in Windows without CMake](#building-the-thrift-idl-compiler-in-windows-without-cmake)
+- [Unit tests for compiler](#unit-tests-for-compiler)
+    - [Using boost test](#using-boost-test)
+    - [Using Catch C++ test library](#using-catch-c-test-library)
+- [Have a Happy free time and holidays](#have-a-happy-free-time-and-holidays)
+
+<!-- /TOC -->
+
+## Build on Unix-like System
+
+### Prerequisites
+- Install CMake
+- Install flex and bison
+
+### Build using CMake
+
+- Go to **thrift\compiler\cpp**
+- Use the following steps to build using cmake:
+
+```
+mkdir cmake-build && cd cmake-build
+cmake ..
+make
+```
+
+#### Build with Eclipse IDE
+
+- Go to **thrift\compiler\cpp**
+- Use the following steps to build using cmake:
+
+```
+mkdir cmake-ec && cd cmake-ec
+cmake -G "Eclipse CDT4 - Unix Makefiles" ..
+make
+```
+
+Now open the folder cmake-ec using eclipse.
+
+#### Build with XCode IDE in MacOS
+
+- Install/update flex, bison and cmake with brew
+
+```
+brew install cmake
+brew install bison
+```
+
+- Go to **thrift\compiler\cpp**
+- Run commands in command line:
+
+```
+mkdir cmake-build && cd cmake-build
+cmake -G "Xcode" -DWITH_PLUGIN=OFF ..
+cmake --build .
+```
+
+#### Usage of other IDEs
+
+Please check list of supported IDE 
+
+```
+cmake --help
+```
+
+## Build on Windows
+
+### Prerequisites
+- Install CMake - https://cmake.org/download/
+- In case if you want to build without Git Bash - install winflexbison - https://sourceforge.net/projects/winflexbison/
+- In case if you want to build with Visual Studio - install Visual Studio 
+  - Better to use the latest stable Visual Studio Community Edition - https://www.visualstudio.com/vs/whatsnew/ (ensure that you installed workload "Desktop Development with C++" for VS2017) - Microsoft added some support for CMake and improving it in Visual Studio
+
+### Build using Git Bash
+
+Git Bash provides flex and bison
+
+- Go to **thrift\compiler\cpp**
+- Use the following steps to build using cmake:
+
+```
+mkdir cmake-vs && cd cmake-vs
+cmake -DWITH_SHARED_LIB=off ..
+cmake --build .
+```
+
+### Using Visual Studio and Win flex-bison
+
+- Generate a Visual Studio project for version of Visual Studio which you have (**cmake --help** can show list of supportable VS versions):
+- Run commands in command line:
+```
+mkdir cmake-vs
+cd cmake-vs
+cmake -G "Visual Studio 15 2017" -DWITH_PLUGIN=OFF ..
+```
+- Now open the folder cmake-vs using Visual Studio.
+
+### Cross compile using mingw32 and generate a Windows Installer with CPack
+
+```
+mkdir cmake-mingw32 && cd cmake-mingw32
+cmake -DCMAKE_TOOLCHAIN_FILE=../build/cmake/mingw32-toolchain.cmake -DBUILD_COMPILER=ON -DBUILD_LIBRARIES=OFF -DBUILD_TESTING=OFF -DBUILD_EXAMPLES=OFF ..
+cpack
+```
+
+# Other cases
+
+## Building the Thrift IDL compiler in Windows without CMake
+
+If you don't want to use CMake you can use the already available Visual Studio 2010 solution.
+
+The Visual Studio project contains pre-build commands to generate the thriftl.cc, thrifty.cc and thrifty.hh files which are necessary to build the compiler. 
+
+These depend on bison, flex and their dependencies to work properly.
+
+Download flex & bison as described above. 
+
+Place these binaries somewhere in the path and rename win_flex.exe and win_bison.exe to flex.exe and bison.exe respectively.
+
+If this doesn't work on a system, try these manual pre-build steps.
+
+Open compiler.sln and remove the Pre-build commands under the project's: Properties -> Build Events -> Pre-Build Events.
+
+From a command prompt:
+```
+cd thrift/compiler/cpp
+flex -o src\thrift\thriftl.cc src\thrift\thriftl.ll
+```
+In the generated thriftl.cc, comment out #include <unistd.h>
+
+Place a copy of bison.simple in thrift/compiler/cpp
+```
+bison -y -o "src/thrift/thrifty.cc" --defines src/thrift/thrifty.yy
+move src\thrift\thrifty.cc.hh  src\thrift\thrifty.hh
+```
+
+Bison might generate the yacc header file "thrifty.cc.h" with just one h ".h" extension; in this case you'll have to rename to "thrifty.h".
+
+```
+move src\thrift\version.h.in src\thrift\version.h
+```
+
+Download inttypes.h from the interwebs and place it in an include path
+location (e.g. thrift/compiler/cpp/src).
+
+Build the compiler in Visual Studio.
+
+# Unit tests for compiler
+
+## Using boost test
+- pls check **test** folder
+
+## Using Catch C++ test library
+
+Added generic way to cover code by tests for many languages (you just need to make a correct header file for generator for your language - example in **netcore** implementation)
+
+- pls check **tests** folder
+
+# Have a Happy free time and holidays 
\ No newline at end of file
diff --git a/compiler/cpp/README_Windows.txt b/compiler/cpp/README_Windows.txt
deleted file mode 100644
index 438ce04..0000000
--- a/compiler/cpp/README_Windows.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-Building the Thrift IDL compiler in Windows
--------------------------------------------
-
-The Visual Studio project contains pre-build commands to generate the
-thriftl.cc, thrifty.cc and thrifty.hh files which are necessary to build
-the compiler. These depend on bison, flex and their dependencies to
-work properly. If this doesn't work on a system, try these manual
-pre-build steps.
-
-Open compiler.sln and remove the Pre-build commands under the project's
- Properties -> Build Events -> Pre-Build Events.
-
-Download flex & bison from http://jaisantonyk.wordpress.com/2008/03/16/lex-and-yaccbison-in-windows/
-Download bison.simple in addition to bison.exe . This build of bison is easier to use
-than the one on sourceforge which has a myriad of dependencies.
-Place these binaries somewhere in the path.
-
-From a command prompt:
-> cd thrift/compiler/cpp
-> flex -osrc\thriftl.cc src\thriftl.ll
-In the generated thriftl.cc, comment out #include <unistd.h>
-
-Place a copy of bison.simple in thrift/compiler/cpp
-> bison -y -o "src/thrifty.cc" --defines src/thrifty.yy
-> move src\thrifty.cc.hh  src\thrifty.hh
-
-Download inttypes.h from the interwebs and place it in an include path
-location (e.g. thrift/compiler/cpp/src).
-
-Build the compiler in Visual Studio.
diff --git a/compiler/cpp/coding_standards.md b/compiler/cpp/coding_standards.md
new file mode 100644
index 0000000..ea08946
--- /dev/null
+++ b/compiler/cpp/coding_standards.md
@@ -0,0 +1,4 @@
+## Compiler Coding Standards
+
+ * When making small change / bugfix - follow style as seen in nearby code.
+ * When making major refactor and / or adding new feature - follow style for C++ library
\ No newline at end of file
diff --git a/compiler/cpp/compiler.vcxproj b/compiler/cpp/compiler.vcxproj
index 6fe2d9d..0628b54 100644
--- a/compiler/cpp/compiler.vcxproj
+++ b/compiler/cpp/compiler.vcxproj
@@ -19,68 +19,80 @@
     </ProjectConfiguration>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="src\generate\t_generator.h" />
-    <ClInclude Include="src\generate\t_generator_registry.h" />
-    <ClInclude Include="src\generate\t_oop_generator.h" />
-    <ClInclude Include="src\generate\t_html_generator.h" />
-    <ClInclude Include="src\globals.h" />
-    <ClInclude Include="src\main.h" />
-    <ClInclude Include="src\md5.h" />
-    <ClInclude Include="src\parse\t_base_type.h" />
-    <ClInclude Include="src\parse\t_const.h" />
-    <ClInclude Include="src\parse\t_const_value.h" />
-    <ClInclude Include="src\parse\t_container.h" />
-    <ClInclude Include="src\parse\t_doc.h" />
-    <ClInclude Include="src\parse\t_enum.h" />
-    <ClInclude Include="src\parse\t_enum_value.h" />
-    <ClInclude Include="src\parse\t_field.h" />
-    <ClInclude Include="src\parse\t_function.h" />
-    <ClInclude Include="src\parse\t_list.h" />
-    <ClInclude Include="src\parse\t_map.h" />
-    <ClInclude Include="src\parse\t_program.h" />
-    <ClInclude Include="src\parse\t_scope.h" />
-    <ClInclude Include="src\parse\t_service.h" />
-    <ClInclude Include="src\parse\t_set.h" />
-    <ClInclude Include="src\parse\t_struct.h" />
-    <ClInclude Include="src\parse\t_type.h" />
-    <ClInclude Include="src\parse\t_typedef.h" />
-    <ClInclude Include="src\platform.h" />
-    <ClInclude Include="src\thrifty.hh" />
-    <ClInclude Include="src\windows\config.h" />
-    <ClInclude Include="src\windows\version.h" />
+    <ClInclude Include="src\thrift\audit\t_audit.h" />
+    <ClInclude Include="src\thrift\common.h" />
+    <ClInclude Include="src\thrift\generate\t_generator.h" />
+    <ClInclude Include="src\thrift\generate\t_generator_registry.h" />
+    <ClInclude Include="src\thrift\generate\t_oop_generator.h" />
+    <ClInclude Include="src\thrift\generate\t_html_generator.h" />
+    <ClInclude Include="src\thrift\globals.h" />
+    <ClInclude Include="src\thrift\main.h" />
+    <ClInclude Include="src\thrift\parse\t_base_type.h" />
+    <ClInclude Include="src\thrift\parse\t_const.h" />
+    <ClInclude Include="src\thrift\parse\t_const_value.h" />
+    <ClInclude Include="src\thrift\parse\t_container.h" />
+    <ClInclude Include="src\thrift\parse\t_doc.h" />
+    <ClInclude Include="src\thrift\parse\t_enum.h" />
+    <ClInclude Include="src\thrift\parse\t_enum_value.h" />
+    <ClInclude Include="src\thrift\parse\t_field.h" />
+    <ClInclude Include="src\thrift\parse\t_function.h" />
+    <ClInclude Include="src\thrift\parse\t_list.h" />
+    <ClInclude Include="src\thrift\parse\t_map.h" />
+    <ClInclude Include="src\thrift\parse\t_program.h" />
+    <ClInclude Include="src\thrift\parse\t_scope.h" />
+    <ClInclude Include="src\thrift\parse\t_service.h" />
+    <ClInclude Include="src\thrift\parse\t_set.h" />
+    <ClInclude Include="src\thrift\parse\t_struct.h" />
+    <ClInclude Include="src\thrift\parse\t_type.h" />
+    <ClInclude Include="src\thrift\parse\t_typedef.h" />
+    <ClInclude Include="src\thrift\platform.h" />
+    <ClInclude Include="src\thrift\thrifty.hh" />
+    <ClInclude Include="src\thrift\windows\config.h" />
+    <ClInclude Include="src\thrift\version.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="src\generate\t_as3_generator.cc" />
-    <ClCompile Include="src\generate\t_cocoa_generator.cc" />
-    <ClCompile Include="src\generate\t_cpp_generator.cc" />
-    <ClCompile Include="src\generate\t_csharp_generator.cc" />
-    <ClCompile Include="src\generate\t_c_glib_generator.cc" />
-    <ClCompile Include="src\generate\t_d_generator.cc" />
-    <ClCompile Include="src\generate\t_delphi_generator.cc" />
-    <ClCompile Include="src\generate\t_erl_generator.cc" />
-    <ClCompile Include="src\generate\t_generator.cc" />
-    <ClCompile Include="src\generate\t_go_generator.cc" />
-    <ClCompile Include="src\generate\t_hs_generator.cc" />
-    <ClCompile Include="src\generate\t_html_generator.cc" />
-    <ClCompile Include="src\generate\t_javame_generator.cc" />
-    <ClCompile Include="src\generate\t_java_generator.cc" />
-    <ClCompile Include="src\generate\t_js_generator.cc" />
-    <ClCompile Include="src\generate\t_ocaml_generator.cc" />
-    <ClCompile Include="src\generate\t_perl_generator.cc" />
-    <ClCompile Include="src\generate\t_php_generator.cc" />
-    <ClCompile Include="src\generate\t_py_generator.cc" />
-    <ClCompile Include="src\generate\t_rb_generator.cc" />
-    <ClCompile Include="src\generate\t_st_generator.cc" />
-    <ClCompile Include="src\generate\t_xsd_generator.cc" />
-    <ClCompile Include="src\main.cc" />
-    <ClCompile Include="src\md5.c" />
-    <ClCompile Include="src\parse\parse.cc" />
-    <ClCompile Include="src\thriftl.cc" />
-    <ClCompile Include="src\thrifty.cc" />
+    <ClCompile Include="src\thrift\audit\t_audit.cpp" />
+    <ClCompile Include="src\thrift\common.cc" />
+    <ClCompile Include="src\thrift\generate\t_as3_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_cocoa_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_cpp_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_csharp_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_netcore_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_c_glib_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_d_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_dart_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_delphi_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_erl_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_go_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_gv_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_haxe_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_hs_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_html_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_javame_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_java_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_js_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_json_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_lua_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_ocaml_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_perl_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_php_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_py_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_rb_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_rs_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_st_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_swift_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_xml_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_xsd_generator.cc" />
+    <ClCompile Include="src\thrift\main.cc" />
+    <ClCompile Include="src\thrift\parse\parse.cc" />
+    <ClCompile Include="src\thrift\parse\t_typedef.cc" />
+    <ClCompile Include="src\thrift\thriftl.cc" />
+    <ClCompile Include="src\thrift\thrifty.cc" />
   </ItemGroup>
   <ItemGroup>
-    <None Include="src\thriftl.ll" />
-    <None Include="src\thrifty.yy" />
+    <None Include="src\thrift\thriftl.ll" />
+    <None Include="src\thrift\thrifty.yy" />
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{89975A1A-F799-4556-98B8-64E30AB39A90}</ProjectGuid>
@@ -157,7 +169,7 @@
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>WIN32;MINGW;YY_NO_UNISTD_H;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <ForcedIncludeFiles>config.h</ForcedIncludeFiles>
+      <ForcedIncludeFiles>thrift\windows\config.h</ForcedIncludeFiles>
       <CompileAs>CompileAsCpp</CompileAs>
     </ClCompile>
     <Link>
@@ -165,8 +177,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
     </Link>
     <PreBuildEvent>
-      <Command>flex -o "src\\thriftl.cc" src/thriftl.ll
-bison -y -o "src\thrifty.cc" --defines="src/thrifty.hh" src/thrifty.yy</Command>
+      <Command>flex -o "src\\thrift\\thriftl.cc" src/thrift/thriftl.ll &amp;&amp; bison -y -o "src\\thrift\\thrifty.cc" --defines="src\\thrift\\thrifty.hh" src/thrift/thrifty.yy</Command>
     </PreBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -176,7 +187,7 @@
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>WIN32;MINGW;YY_NO_UNISTD_H;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <ForcedIncludeFiles>config.h</ForcedIncludeFiles>
+      <ForcedIncludeFiles>thrift\windows\config.h</ForcedIncludeFiles>
       <CompileAs>CompileAsCpp</CompileAs>
     </ClCompile>
     <Link>
@@ -184,8 +195,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
     </Link>
     <PreBuildEvent>
-      <Command>flex -o "src\thriftl.cc" src/thriftl.ll
-bison -y -o "src\thrifty.cc" --defines="src/thrifty.hh" src/thrifty.yy</Command>
+      <Command>flex -o "src\\thrift\\thriftl.cc" src/thrift/thriftl.ll &amp;&amp; bison -y -o "src\\thrift\\thrifty.cc" --defines="src\\thrift\\thrifty.hh" src/thrift/thrifty.yy</Command>
     </PreBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -197,8 +207,9 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>WIN32;MINGW;YY_NO_UNISTD_H;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <ForcedIncludeFiles>config.h</ForcedIncludeFiles>
+      <ForcedIncludeFiles>thrift\windows\config.h</ForcedIncludeFiles>
       <CompileAs>CompileAsCpp</CompileAs>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
@@ -207,8 +218,7 @@
       <OptimizeReferences>true</OptimizeReferences>
     </Link>
     <PreBuildEvent>
-      <Command>flex -o "src\thriftl.cc" src/thriftl.ll
-bison -y -o "src\thrifty.cc" --defines="src/thrifty.hh" src/thrifty.yy</Command>
+      <Command>flex -o "src\\thrift\\thriftl.cc" src/thrift/thriftl.ll &amp;&amp; bison -y -o "src\\thrift\\thrifty.cc" --defines="src\\thrift\\thrifty.hh" src/thrift/thrifty.yy</Command>
     </PreBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -220,8 +230,9 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>WIN32;MINGW;YY_NO_UNISTD_H;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <ForcedIncludeFiles>config.h</ForcedIncludeFiles>
+      <ForcedIncludeFiles>thrift\windows\config.h</ForcedIncludeFiles>
       <CompileAs>CompileAsCpp</CompileAs>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
@@ -230,8 +241,7 @@
       <OptimizeReferences>true</OptimizeReferences>
     </Link>
     <PreBuildEvent>
-      <Command>flex -o "src\thriftl.cc" src/thriftl.ll
-bison -y -o "src\thrifty.cc" --defines="src/thrifty.hh" src/thrifty.yy</Command>
+      <Command>flex -o "src\\thrift\\thriftl.cc" src/thrift/thriftl.ll &amp;&amp; bison -y -o "src\\thrift\\thrifty.cc" --defines="src\\thrift\\thrifty.hh" src/thrift/thrifty.yy</Command>
     </PreBuildEvent>
   </ItemDefinitionGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
diff --git a/compiler/cpp/compiler.vcxproj.filters b/compiler/cpp/compiler.vcxproj.filters
index 7e2d933..b96865b 100644
--- a/compiler/cpp/compiler.vcxproj.filters
+++ b/compiler/cpp/compiler.vcxproj.filters
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
+    <ClInclude Include="src\audit\t_audit.h" />
     <ClInclude Include="src\generate\t_generator.h">
       <Filter>generate</Filter>
     </ClInclude>
@@ -15,7 +16,6 @@
     </ClInclude>
     <ClInclude Include="src\globals.h" />
     <ClInclude Include="src\main.h" />
-    <ClInclude Include="src\md5.h" />
     <ClInclude Include="src\parse\t_base_type.h">
       <Filter>parse</Filter>
     </ClInclude>
@@ -91,6 +91,7 @@
     </Filter>
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="src\audit\t_audit.cpp"/>
     <ClCompile Include="src\generate\t_as3_generator.cc">
       <Filter>generate</Filter>
     </ClCompile>
@@ -109,6 +110,9 @@
     <ClCompile Include="src\generate\t_d_generator.cc">
       <Filter>generate</Filter>
     </ClCompile>
+    <ClCompile Include="src\generate\t_dart_generator.cc">
+      <Filter>generate</Filter>
+    </ClCompile>
     <ClCompile Include="src\generate\t_delphi_generator.cc">
       <Filter>generate</Filter>
     </ClCompile>
@@ -121,6 +125,12 @@
     <ClCompile Include="src\generate\t_go_generator.cc">
       <Filter>generate</Filter>
     </ClCompile>
+    <ClCompile Include="src\generate\t_gv_generator.cc">
+      <Filter>generate</Filter>
+    </ClCompile>
+    <ClCompile Include="src\generate\t_haxe_generator.cc">
+      <Filter>generate</Filter>
+    </ClCompile>
     <ClCompile Include="src\generate\t_hs_generator.cc">
       <Filter>generate</Filter>
     </ClCompile>
@@ -151,22 +161,39 @@
     <ClCompile Include="src\generate\t_rb_generator.cc">
       <Filter>generate</Filter>
     </ClCompile>
+    <ClCompile Include="src\generate\t_rs_generator.cc">
+      <Filter>generate</Filter>
+    </ClCompile>
     <ClCompile Include="src\generate\t_st_generator.cc">
       <Filter>generate</Filter>
     </ClCompile>
+    <ClCompile Include="src\generate\t_swift_generator.cc">
+      <Filter>generate</Filter>
+    </ClCompile>
     <ClCompile Include="src\generate\t_xsd_generator.cc">
       <Filter>generate</Filter>
     </ClCompile>
+    <ClCompile Include="src\generate\t_xml_generator.cc">
+      <Filter>generate</Filter>
+    </ClCompile>
     <ClCompile Include="src\main.cc" />
-    <ClCompile Include="src\md5.c" />
     <ClCompile Include="src\parse\parse.cc">
       <Filter>parse</Filter>
     </ClCompile>
     <ClCompile Include="src\thriftl.cc" />
     <ClCompile Include="src\thrifty.cc" />
+    <ClCompile Include="src\parse\t_typedef.cc">
+      <Filter>parse</Filter>
+    </ClCompile>
+    <ClCompile Include="src\generate\t_json_generator.cc">
+      <Filter>generate</Filter>
+    </ClCompile>
+    <ClCompile Include="src\generate\t_lua_generator.cc">
+      <Filter>generate</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="src\thriftl.ll" />
     <None Include="src\thrifty.yy" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/compiler/cpp/src/Makefile.am b/compiler/cpp/src/Makefile.am
new file mode 100644
index 0000000..bc2c5cb
--- /dev/null
+++ b/compiler/cpp/src/Makefile.am
@@ -0,0 +1,87 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+# Contains some contributions under the Thrift Software License.
+# Please see doc/old-thrift-license.txt in the Thrift distribution for
+# details.
+
+AUTOMAKE_OPTIONS = subdir-objects
+
+AM_YFLAGS = -d
+
+BUILT_SOURCES = thrift/thrifty.cc
+
+noinst_LIBRARIES = thrift/libparse.a
+
+thrift_libparse_a_CPPFLAGS = -I$(srcdir)
+thrift_libparse_a_CXXFLAGS = -Wall -Wno-sign-compare -Wno-unused
+
+thrift_libparse_a_SOURCES = thrift/thrifty.yy \
+                     thrift/thriftl.ll
+
+clean-local:
+	$(RM) thrift/thriftl.cc thrift/thrifty.cc thrift/thrifty.h thrift/thrifty.hh
+
+if WITH_PLUGIN
+noinst_PROGRAMS = thrift/thrift-bootstrap
+
+thrift_thrift_bootstrap_SOURCES = \
+                 thrift/common.h \
+                 thrift/common.cc \
+                 thrift/audit/t_audit.h \
+                 thrift/audit/t_audit.cpp \
+                 thrift/generate/t_generator.cc \
+                 thrift/generate/t_generator_registry.h \
+                 thrift/globals.h \
+                 thrift/platform.h \
+                 thrift/logging.h \
+                 thrift/parse/t_doc.h \
+                 thrift/parse/t_type.h \
+                 thrift/parse/t_base_type.h \
+                 thrift/parse/t_enum.h \
+                 thrift/parse/t_enum_value.h \
+                 thrift/parse/t_typedef.h \
+                 thrift/parse/t_typedef.cc \
+                 thrift/parse/t_container.h \
+                 thrift/parse/t_list.h \
+                 thrift/parse/t_set.h \
+                 thrift/parse/t_map.h \
+                 thrift/parse/t_struct.h \
+                 thrift/parse/t_field.h \
+                 thrift/parse/t_service.h \
+                 thrift/parse/t_function.h \
+                 thrift/parse/t_program.h \
+                 thrift/parse/t_scope.h \
+                 thrift/parse/t_const.h \
+                 thrift/parse/t_const_value.h \
+                 thrift/parse/parse.cc \
+                 thrift/generate/t_generator.h \
+                 thrift/generate/t_oop_generator.h \
+                 thrift/generate/t_html_generator.h \
+                 thrift/windows/config.h \
+                 thrift/version.h \
+                 thrift/generate/t_cpp_generator.cc \
+                 thrift/main.h \
+                 thrift/main.cc
+
+main.cc: version.h
+
+thrift_thrift_bootstrap_CXXFLAGS = -Wall -Wextra -pedantic
+thrift_thrift_bootstrap_LDADD = @LEXLIB@ thrift/libparse.a
+endif
diff --git a/compiler/cpp/src/generate/t_as3_generator.cc b/compiler/cpp/src/generate/t_as3_generator.cc
deleted file mode 100644
index 5abeba4..0000000
--- a/compiler/cpp/src/generate/t_as3_generator.cc
+++ /dev/null
@@ -1,2704 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <sstream>
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-#include <cctype>
-
-#include <sys/stat.h>
-#include <stdexcept>
-
-#include "platform.h"
-#include "t_oop_generator.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * AS3 code generator.
- *
- */
-class t_as3_generator : public t_oop_generator {
- public:
-  t_as3_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_oop_generator(program)
-  {
-    (void) option_string;
-    std::map<std::string, std::string>::const_iterator iter;
-    
-    iter = parsed_options.find("bindable");
-    bindable_ = (iter != parsed_options.end());
-    
-    out_dir_base_ = "gen-as3";
-  }
-
-  /**
-   * Init and close methods
-   */
-
-  void init_generator();
-  void close_generator();
-
-  void generate_consts(std::vector<t_const*> consts);
-
-  /**
-   * Program-level generation functions
-   */
-
-  void generate_typedef (t_typedef*  ttypedef);
-  void generate_enum    (t_enum*     tenum);
-  void generate_struct  (t_struct*   tstruct);
-  void generate_xception(t_struct*   txception);
-  void generate_service (t_service*  tservice);
-
-  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool in_static, bool defval=false);
-  std::string render_const_value(ofstream& out, std::string name, t_type* type, t_const_value* value);
-
-  /**
-   * Service-level generation functions
-   */
-
-  void generate_as3_struct(t_struct* tstruct, bool is_exception);
-
-  void generate_as3_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool in_class=false, bool is_result=false);
-  //removed -- equality,compare_to
-  void generate_as3_struct_reader(std::ofstream& out, t_struct* tstruct);
-  void generate_as3_validator(std::ofstream& out, t_struct* tstruct);
-  void generate_as3_struct_result_writer(std::ofstream& out, t_struct* tstruct);
-  void generate_as3_struct_writer(std::ofstream& out, t_struct* tstruct);
-  void generate_as3_struct_tostring(std::ofstream& out, t_struct* tstruct, bool bindable);
-  void generate_as3_meta_data_map(std::ofstream& out, t_struct* tstruct);
-  void generate_field_value_meta_data(std::ofstream& out, t_type* type);
-  std::string get_as3_type_string(t_type* type);
-  void generate_reflection_setters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name);
-  void generate_reflection_getters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name);
-  void generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct);
-  void generate_generic_isset_method(std::ofstream& out, t_struct* tstruct);
-  void generate_as3_bean_boilerplate(std::ofstream& out, t_struct* tstruct, bool bindable);
-
-  void generate_function_helpers(t_function* tfunction);
-  std::string get_cap_name(std::string name);
-  std::string generate_isset_check(t_field* field);
-  std::string generate_isset_check(std::string field);
-  void generate_isset_set(ofstream& out, t_field* field);
-  //removed std::string isset_field_id(t_field* field);
-  
-  void generate_service_interface (t_service* tservice);
-  void generate_service_helpers   (t_service* tservice);
-  void generate_service_client    (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,
-                                          std::string prefix="");
-
-  void generate_deserialize_struct       (std::ofstream& out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_deserialize_container    (std::ofstream& out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_deserialize_set_element  (std::ofstream& out,
-                                          t_set*      tset,
-                                          std::string prefix="");
-
-  void generate_deserialize_map_element  (std::ofstream& out,
-                                          t_map*      tmap,
-                                          std::string prefix="");
-
-  void generate_deserialize_list_element (std::ofstream& out,
-                                          t_list*     tlist,
-                                          std::string prefix="");
-
-  void generate_serialize_field          (std::ofstream& out,
-                                          t_field*    tfield,
-                                          std::string prefix="");
-
-  void generate_serialize_struct         (std::ofstream& out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_serialize_container      (std::ofstream& out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_serialize_map_element    (std::ofstream& out,
-                                          t_map*      tmap,
-                                          std::string iter,
-                                          std::string map);
-
-  void generate_serialize_set_element    (std::ofstream& out,
-                                          t_set*      tmap,
-                                          std::string iter);
-
-  void generate_serialize_list_element   (std::ofstream& out,
-                                          t_list*     tlist,
-                                          std::string iter);
-
-  void generate_as3_doc                 (std::ofstream& out,
-                                          t_doc*     tdoc);
-
-  void generate_as3_doc                 (std::ofstream& out,
-                                          t_function* tdoc);
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string as3_package();
-  std::string as3_type_imports();
-  std::string as3_thrift_imports();
-  std::string as3_thrift_gen_imports(t_struct* tstruct, string& imports); 
-  std::string as3_thrift_gen_imports(t_service* tservice); 
-  std::string type_name(t_type* ttype, bool in_container=false, bool in_init=false);
-  std::string base_type_name(t_base_type* tbase, bool in_container=false);
-  std::string declare_field(t_field* tfield, bool init=false);
-  std::string function_signature(t_function* tfunction, std::string prefix="");
-  std::string argument_list(t_struct* tstruct);
-  std::string type_to_enum(t_type* ttype);
-  std::string get_enum_class_name(t_type* type);
-
-  bool type_can_be_null(t_type* ttype) {
-    ttype = get_true_type(ttype);
-
-    return
-      ttype->is_container() ||
-      ttype->is_struct() ||
-      ttype->is_xception() ||
-      ttype->is_string();
-  }
-
-  std::string constant_name(std::string name);
-
- private:
-
-  /**
-   * File streams
-   */
-
-  std::string package_name_;
-  std::ofstream f_service_;
-  std::string package_dir_;
-  
-  bool bindable_;	
-};
-
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * streams.
- *
- * @param tprogram The program to generate
- */
-void t_as3_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-  package_name_ = program_->get_namespace("as3");
-
-  string dir = package_name_;
-  string subdir = get_out_dir();
-  string::size_type loc;
-  while ((loc = dir.find(".")) != string::npos) {
-    subdir = subdir + "/" + dir.substr(0, loc);
-    MKDIR(subdir.c_str());
-    dir = dir.substr(loc+1);
-  }
-  if (dir.size() > 0) {
-    subdir = subdir + "/" + dir;
-    MKDIR(subdir.c_str());
-  }
-
-  package_dir_ = subdir;
-}
-
-/**
- * Packages the generated file
- *
- * @return String of the package, i.e. "package org.apache.thriftdemo;"
- */
-string t_as3_generator::as3_package() {
-  if (!package_name_.empty()) {
-    return string("package ") + package_name_ + " ";
-  }
-  return "";
-}
-
-/**
- * Prints standard as3 imports
- *
- * @return List of imports for As3 types that are used in here
- */
-string t_as3_generator::as3_type_imports() {
-  return
-    string() +
-    "import org.apache.thrift.Set;\n" +
-    "import flash.utils.ByteArray;\n" +
-    "import flash.utils.Dictionary;\n\n";
-}
-
-/**
- * Prints standard as3 imports
- *
- * @return List of imports necessary for thrift
- */
-string t_as3_generator::as3_thrift_imports() {
-  return
-    string() +
-    "import org.apache.thrift.*;\n" +
-    "import org.apache.thrift.meta_data.*;\n" +
-    "import org.apache.thrift.protocol.*;\n\n";
-}
-
-/**
- * Prints imports needed for a given type
- *
- * @return List of imports necessary for a given t_struct
- */
-string t_as3_generator::as3_thrift_gen_imports(t_struct* tstruct, string& imports) {
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  //For each type check if it is from a differnet namespace
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_program* program = (*m_iter)->get_type()->get_program();
-    if (program != NULL && program != program_) {
-      string package = program->get_namespace("as3");
-      if (!package.empty()) {
-        if (imports.find(package + "." + (*m_iter)->get_type()->get_name()) == string::npos) {
-          imports.append("import " + package + "." + (*m_iter)->get_type()->get_name() + ";\n");
-        }
-      }
-    }
-  }
-  return imports;  
-}
-
-
-/**
- * Prints imports needed for a given type
- *
- * @return List of imports necessary for a given t_service
- */
-string t_as3_generator::as3_thrift_gen_imports(t_service* tservice) {
-  string imports;
-  const vector<t_function*>& functions = tservice->get_functions();
-  vector<t_function*>::const_iterator f_iter;
-
-  //For each type check if it is from a differnet namespace
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    t_program* program = (*f_iter)->get_returntype()->get_program();
-    if (program != NULL && program != program_) {
-      string package = program->get_namespace("as3");
-      if (!package.empty()) {
-        if (imports.find(package + "." + (*f_iter)->get_returntype()->get_name()) == string::npos) {
-          imports.append("import " + package + "." + (*f_iter)->get_returntype()->get_name() + ";\n");
-        }
-      }
-    }
-
-    as3_thrift_gen_imports((*f_iter)->get_arglist(), imports);	    
-    as3_thrift_gen_imports((*f_iter)->get_xceptions(), imports);	    
-
-  }
- 
-  return imports;
-
-}
-
-/**
- * Nothing in As3
- */
-void t_as3_generator::close_generator() {}
-
-/**
- * Generates a typedef. This is not done in As3, since it does
- * not support arbitrary name replacements, and it'd be a wacky waste
- * of overhead to make wrapper classes.
- *
- * @param ttypedef The type definition
- */
-void t_as3_generator::generate_typedef(t_typedef* ttypedef) {
-  (void) ttypedef;
-}
-
-/**
- * Enums are a class with a set of static constants.
- *
- * @param tenum The enumeration
- */
-void t_as3_generator::generate_enum(t_enum* tenum) {
-  // Make output file
-  string f_enum_name = package_dir_+"/"+(tenum->get_name())+".as";
-  ofstream f_enum;
-  f_enum.open(f_enum_name.c_str());
-
-  // Comment and package it
-  f_enum <<
-    autogen_comment() <<
-    as3_package() << endl;
-  
-  scope_up(f_enum);
-  // Add as3 imports
-  f_enum << string() +
-  "import org.apache.thrift.Set;" << endl <<
-  "import flash.utils.Dictionary;" << endl;
-  
-  indent(f_enum) <<
-    "public class " << tenum->get_name() << " ";
-  scope_up(f_enum);
-
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    indent(f_enum) <<
-      "public static const " << (*c_iter)->get_name() <<
-      ":int = " << value << ";" << endl;
-  }
-  
-  // Create a static Set with all valid values for this enum
-  f_enum << endl;
-  
-  indent(f_enum) << "public static const VALID_VALUES:Set = new Set(";
-  indent_up();
-  bool firstValue = true;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    // populate set
-    f_enum << (firstValue ? "" : ", ") << (*c_iter)->get_name();
-    firstValue = false;
-  }
-  indent_down();
-  f_enum << ");" << endl;
-
-  indent(f_enum) << "public static const VALUES_TO_NAMES:Dictionary = new Dictionary();" << endl;
-
-  scope_up(f_enum);
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    indent(f_enum) << "VALUES_TO_NAMES[" << (*c_iter)->get_name() << "] = \"" << (*c_iter)->get_name() << "\";" << endl;
-  }
-  f_enum << endl;
-  
-  scope_down(f_enum);
-
-  scope_down(f_enum); // end class
-  
-  scope_down(f_enum); // end package
-  
-  f_enum.close();
-}
-
-/**
- * Generates a class that holds all the constants.
- */
-void t_as3_generator::generate_consts(std::vector<t_const*> consts) {
-  if (consts.empty()) {
-    return;
-  }
-
-  string f_consts_name = package_dir_+ "/" + program_name_ +  "Constants.as";
-  ofstream f_consts;
-  f_consts.open(f_consts_name.c_str());
-
-  // Print header
-  f_consts <<
-    autogen_comment() << as3_package();
-  
-  scope_up(f_consts);
-  f_consts << endl;
-  
-  f_consts << as3_type_imports();
-
- 
-  
-  indent(f_consts) <<
-    "public class " << program_name_ << "Constants {" << endl <<
-    endl;
-  indent_up();
-  vector<t_const*>::iterator c_iter;
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    print_const_value(f_consts,
-                      (*c_iter)->get_name(),
-                      (*c_iter)->get_type(),
-                      (*c_iter)->get_value(),
-                      false);
-  }
-  indent_down();
-  indent(f_consts) <<
-    "}" << endl;
-  scope_down(f_consts);
-  f_consts.close();
-}
-
-void t_as3_generator::print_const_value(std::ofstream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval) {
-  type = get_true_type(type);
-  
-  indent(out);
-  if (!defval) {
-    out <<
-    (in_static ? "var " : "public static const ");
-  }
-  if (type->is_base_type()) {
-    string v2 = render_const_value(out, name, type, value);
-    out << name;
-    if (!defval) {
-      out << ":" << type_name(type);
-    }
-    out << " = " << v2 << ";" << endl << endl;
-  } else if (type->is_enum()) {
-    out << name;
-    if(!defval) {
-      out << ":" << type_name(type);
-    }
-    out << " = " << value->get_integer() << ";" << endl << endl;
-  } else if (type->is_struct() || type->is_xception()) {
-    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;
-    out << name << ":" << type_name(type) << " = new " << type_name(type, false, true) << "();" << endl;
-    if (!in_static) {
-      indent(out) << "{" << endl;
-      indent_up();
-      indent(out) << "new function():void {" << endl;
-      indent_up();
-    }
-    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();
-      }
-      string val = render_const_value(out, name, field_type, v_iter->second);
-      indent(out) << name << ".";
-      out << v_iter->first->get_string() << " = " << val << ";" << endl;
-    }
-    if (!in_static) {
-      indent_down();
-      indent(out) << "}();" << endl;
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    out << endl;
-  } else if (type->is_map()) {
-    out << name;
-    if(!defval){
-      out << ":" << type_name(type);
-    }
-    out << " = new " << type_name(type, false, true) << "();" << endl;
-    if (!in_static) {
-      indent(out) << "{" << endl;
-      indent_up();
-      indent(out) << "new function():void {" << endl;
-      indent_up();
-    }
-    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();
-    map<t_const_value*, t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string key = render_const_value(out, name, ktype, v_iter->first);
-      string val = render_const_value(out, name, vtype, v_iter->second);
-      indent(out) << name << "[" << key << "] = " << val << ";" << endl;
-    }
-    if (!in_static) {
-      indent_down();
-      indent(out) << "}();" << endl;
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    out << endl;
-  } else if (type->is_list() || type->is_set()) {
-    out << name;
-    if(!defval) {
-      out << ":" << type_name(type);
-    }
-    out << " = new " << type_name(type, false, true) << "();" << endl;
-    if (!in_static) {
-      indent(out) << "{" << endl;
-      indent_up();
-      indent(out) << "new function():void {" << endl;
-      indent_up();
-    }
-    t_type* etype;
-    if (type->is_list()) {
-      etype = ((t_list*)type)->get_elem_type();
-    } else {
-      etype = ((t_set*)type)->get_elem_type();
-    }
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string val = render_const_value(out, name, etype, *v_iter);
-      indent(out) << name << "." << (type->is_list() ? "push" : "add") << "(" << val << ");" << endl;
-    }
-    if (!in_static) {
-      indent_down();
-      indent(out) << "}();" << endl;
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    out << endl;
-  } else {
-    throw "compiler error: no const of type " + type->get_name();
-  }
-}
-
-string t_as3_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
-  (void) name;
-  type = get_true_type(type);
-  std::ostringstream render;
-  
-  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:
-          render << '"' << get_escaped_string(value) << '"';
-          break;
-        case t_base_type::TYPE_BOOL:
-          render << ((value->get_integer() > 0) ? "true" : "false");
-          break;
-        case t_base_type::TYPE_BYTE:
-          render << "(byte)" << value->get_integer();
-          break;
-        case t_base_type::TYPE_I16:
-          render << "(short)" << value->get_integer();
-          break;
-        case t_base_type::TYPE_I32:
-          render << value->get_integer();
-          break;
-        case t_base_type::TYPE_I64:
-          render << value->get_integer() << "L";
-          break;
-        case t_base_type::TYPE_DOUBLE:
-          if (value->get_type() == t_const_value::CV_INTEGER) {
-            render << "(double)" << value->get_integer();
-          } else {
-            render << 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()) {
-    render << value->get_integer();
-  } else {
-    string t = tmp("tmp");
-    print_const_value(out, t, type, value, true);
-    render << t;
-  }
-  
-  return render.str();
-}
-
-
-/**
- * Generates a struct definition for a thrift data type. This is a class
- * with data members, read(), write(), and an inner Isset class.
- *
- * @param tstruct The struct definition
- */
-void t_as3_generator::generate_struct(t_struct* tstruct) {
-  generate_as3_struct(tstruct, false);
-}
-
-/**
- * Exceptions are structs, but they inherit from Exception
- *
- * @param tstruct The struct definition
- */
-void t_as3_generator::generate_xception(t_struct* txception) {
-  generate_as3_struct(txception, true);
-}
-
-
-/**
- * As3 struct definition.
- *
- * @param tstruct The struct definition
- */
-void t_as3_generator::generate_as3_struct(t_struct* tstruct,
-                                            bool is_exception) {
-  // Make output file
-  string f_struct_name = package_dir_+"/"+(tstruct->get_name())+".as";
-  ofstream f_struct;
-  f_struct.open(f_struct_name.c_str());
-
-  f_struct <<
-    autogen_comment() <<
-  as3_package();
-  
-  scope_up(f_struct);
-  f_struct << endl;
-  
-  string imports;
-
-  f_struct <<
-    as3_type_imports() <<
-    as3_thrift_imports() << 
-    as3_thrift_gen_imports(tstruct, imports) << endl;
-  
-  if (bindable_ && ! is_exception) {
-    f_struct << "import flash.events.Event;" << endl <<
-    "import flash.events.EventDispatcher;" << endl <<
-    "import mx.events.PropertyChangeEvent;" << endl;
-  }
-  
-  generate_as3_struct_definition(f_struct,
-                                  tstruct,
-                                  is_exception);
-  
-  scope_down(f_struct); // end of package
-  f_struct.close();
-}
-
-/**
- * As3 struct definition. This has various parameters, as it could be
- * generated standalone or inside another class as a helper. If it
- * is a helper than it is a static class.
- *
- * @param tstruct      The struct definition
- * @param is_exception Is this an exception?
- * @param in_class     If inside a class, needs to be static class
- * @param is_result    If this is a result it needs a different writer
- */
-void t_as3_generator::generate_as3_struct_definition(ofstream &out,
-                                                       t_struct* tstruct,
-                                                       bool is_exception,
-                                                       bool in_class,
-                                                       bool is_result) {
-  generate_as3_doc(out, tstruct);
-
-  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
-  bool bindable = ! is_exception && ! in_class && bindable_;
-
-  indent(out) << (in_class ? "" : "public ") << (is_final ? "final " : "") <<
-     "class " << tstruct->get_name() << " ";
-
-  if (is_exception) {
-    out << "extends Error ";
-  }
-  else if (bindable) {
-    out << "extends EventDispatcher ";
-  }
-  out << "implements TBase ";
-
-  scope_up(out);
-
-  indent(out) <<
-    "private static const STRUCT_DESC:TStruct = new TStruct(\"" << tstruct->get_name() << "\");" << endl;
-
-  // Members are public for -as3, private for -as3bean
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    indent(out) <<
-      "private static const " << constant_name((*m_iter)->get_name()) <<
-      "_FIELD_DESC:TField = new TField(\"" << (*m_iter)->get_name() << "\", " <<
-      type_to_enum((*m_iter)->get_type()) << ", " <<
-      (*m_iter)->get_key() << ");" << endl;
-  }
-
-  out << endl;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    generate_as3_doc(out, *m_iter);
-    indent(out) << "private var _" << (*m_iter)->get_name() + ":" + type_name((*m_iter)->get_type()) << ";" << endl;
-
-    indent(out) << "public static const " << upcase_string((*m_iter)->get_name()) << ":int = " << (*m_iter)->get_key() << ";" << endl;
-  }
-  
-  out << endl;
-  
-  // Inner Isset class
-  if (members.size() > 0) {
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-        if (!type_can_be_null((*m_iter)->get_type())){
-          indent(out) <<
-            "private var __isset_" << (*m_iter)->get_name() << ":Boolean = false;" <<  endl;
-        }
-      }
-  }
-  
-  out << endl;
-  
-  generate_as3_meta_data_map(out, tstruct);
-  
-  // Static initializer to populate global class to struct metadata map
-  indent(out) << "{" << endl;
-  indent_up();
-  indent(out) << "FieldMetaData.addStructMetaDataMap(" << type_name(tstruct) << ", metaDataMap);" << endl;
-  indent_down();
-  indent(out) << "}" << endl << endl;
-
-  // Default constructor
-  indent(out) <<
-  "public function " << tstruct->get_name() << "() {" << endl;
-  indent_up();
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    if ((*m_iter)->get_value() != NULL) {
-      indent(out) << "this._" << (*m_iter)->get_name() << " = " << (*m_iter)->get_value()->get_integer() << ";" <<
-      endl;
-    }
-  }
-  indent_down();
-  indent(out) << "}" << endl << endl;
-  
-  generate_as3_bean_boilerplate(out, tstruct, bindable);
-  generate_generic_field_getters_setters(out, tstruct);
-  generate_generic_isset_method(out, tstruct);
-
-  generate_as3_struct_reader(out, tstruct);
-  if (is_result) {
-    generate_as3_struct_result_writer(out, tstruct);
-  } else {
-    generate_as3_struct_writer(out, tstruct);
-  }
-  generate_as3_struct_tostring(out, tstruct, bindable);
-  generate_as3_validator(out, tstruct);
-  scope_down(out);
-  out << endl;
-}
-
-/**
- * Generates a function to read all the fields of the struct.
- *
- * @param tstruct The struct definition
- */
-void t_as3_generator::generate_as3_struct_reader(ofstream& out,
-                                                   t_struct* tstruct) {
-  out <<
-    indent() << "public function read(iprot:TProtocol):void {" << endl;
-  indent_up();
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  // Declare stack tmp variables and read struct header
-  out <<
-    indent() << "var field:TField;" << endl <<
-    indent() << "iprot.readStructBegin();" << endl;
-
-  // Loop over reading in fields
-  indent(out) <<
-    "while (true)" << endl;
-    scope_up(out);
-
-    // Read beginning field marker
-    indent(out) <<
-      "field = iprot.readFieldBegin();" << endl;
-
-    // Check for field STOP marker and break
-    indent(out) <<
-      "if (field.type == TType.STOP) { " << endl;
-    indent_up();
-    indent(out) <<
-      "break;" << endl;
-    indent_down();
-    indent(out) <<
-      "}" << endl;
-
-    // Switch statement on the field we are reading
-    indent(out) <<
-      "switch (field.id)" << endl;
-
-      scope_up(out);
-
-      // Generate deserialization code for known cases
-      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-        indent(out) <<
-          "case " << upcase_string((*f_iter)->get_name()) << ":" << endl;
-        indent_up();
-        indent(out) <<
-          "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
-        indent_up();
-
-        generate_deserialize_field(out, *f_iter, "this.");
-        generate_isset_set(out, *f_iter);
-        indent_down();
-        out <<
-          indent() << "} else { " << endl <<
-          indent() << "  TProtocolUtil.skip(iprot, field.type);" << endl <<
-          indent() << "}" << endl <<
-          indent() << "break;" << endl;
-        indent_down();
-      }
-
-      // In the default case we skip the field
-      out <<
-        indent() << "default:" << endl <<
-        indent() << "  TProtocolUtil.skip(iprot, field.type);" << endl <<
-        indent() << "  break;" << endl;
-
-      scope_down(out);
-
-    // Read field end marker
-    indent(out) <<
-      "iprot.readFieldEnd();" << endl;
-
-    scope_down(out);
-
-    out <<
-      indent() << "iprot.readStructEnd();" << endl << endl;
-    
-    // in non-beans style, check for required fields of primitive type
-    // (which can be checked here but not in the general validate method)
-    out << endl << indent() << "// check for required fields of primitive type, which can't be checked in the validate method" << endl;
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) {
-        out <<
-          indent() << "if (!__isset_" << (*f_iter)->get_name() << ") {" << endl <<
-          indent() << "  throw new TProtocolError(TProtocolError.UNKNOWN, \"Required field '" << (*f_iter)->get_name() << "' was not found in serialized data! Struct: \" + toString());" << endl <<
-          indent() << "}" << endl;
-      }
-    }
-
-    // performs various checks (e.g. check that all required fields are set)
-    indent(out) << "validate();" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-// generates as3 method to perform various checks
-// (e.g. check that all required fields are set)
-void t_as3_generator::generate_as3_validator(ofstream& out,
-                                                   t_struct* tstruct){
-  indent(out) << "public function validate():void {" << endl;
-  indent_up();  
-  
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  
-  out << indent() << "// check for required fields" << endl;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
-      if (type_can_be_null((*f_iter)->get_type())) {
-        indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl;
-        indent(out) << "  throw new TProtocolError(TProtocolError.UNKNOWN, \"Required field '" << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" << endl;
-        indent(out) << "}" << endl;
-      } else {
-        indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name() << "' because it's a primitive and you chose the non-beans generator." << endl;
-      }
-    }
-  }
-  
-  // check that fields of type enum have valid values
-  out << indent() << "// check that fields of type enum have valid values" << endl;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = (*f_iter);
-    t_type* type = field->get_type();
-    // if field is an enum, check that its value is valid
-    if (type->is_enum()){
-      indent(out) << "if (" << generate_isset_check(field) << " && !" << get_enum_class_name(type) << ".VALID_VALUES.contains(" << field->get_name() << ")){" << endl;
-      indent_up();
-      indent(out) << "throw new TProtocolError(TProtocolError.UNKNOWN, \"The field '" << field->get_name() << "' has been assigned the invalid value \" + " << field->get_name() << ");" << endl;
-      indent_down();
-      indent(out) << "}" << endl;
-    } 
-  }  
-  
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-/**
- * Generates a function to write all the fields of the struct
- *
- * @param tstruct The struct definition
- */
-void t_as3_generator::generate_as3_struct_writer(ofstream& out,
-                                                   t_struct* tstruct) {
-  out <<
-    indent() << "public function write(oprot:TProtocol):void {" << endl;
-  indent_up();
-
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  // performs various checks (e.g. check that all required fields are set)
-  indent(out) << "validate();" << endl << endl;
-
-  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    bool null_allowed = type_can_be_null((*f_iter)->get_type());
-    if (null_allowed) {
-      out <<
-        indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
-      indent_up();
-    }
-
-    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl;
-
-    // Write field contents
-    generate_serialize_field(out, *f_iter, "this.");
-
-    // Write field closer
-    indent(out) <<
-      "oprot.writeFieldEnd();" << endl;
-
-    if (null_allowed) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-  }
-  // Write the struct map
-  out <<
-    indent() << "oprot.writeFieldStop();" << endl <<
-    indent() << "oprot.writeStructEnd();" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-/**
- * Generates a function to write all the fields of the struct,
- * which is a function result. These fields are only written
- * if they are set in the Isset array, and only one of them
- * can be set at a time.
- *
- * @param tstruct The struct definition
- */
-void t_as3_generator::generate_as3_struct_result_writer(ofstream& out,
-                                                          t_struct* tstruct) {
-  out <<
-    indent() << "public function write(oprot:TProtocol):void {" << endl;
-  indent_up();
-
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
-
-  bool first = true;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (first) {
-      first = false;
-      out <<
-        endl <<
-        indent() << "if ";
-    } else {
-      out << " else if ";
-    }
-
-    out << "(this." << generate_isset_check(*f_iter) << ") {" << endl;
-
-    indent_up();
-    
-    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl;
-
-    // Write field contents
-    generate_serialize_field(out, *f_iter, "this.");
-
-    // Write field closer
-    indent(out) <<
-      "oprot.writeFieldEnd();" << endl;
-
-    indent_down();
-    indent(out) << "}";
-  }
-  // Write the struct map
-  out <<
-    endl <<
-    indent() << "oprot.writeFieldStop();" << endl <<
-    indent() << "oprot.writeStructEnd();" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-void t_as3_generator::generate_reflection_getters(ostringstream& out, t_type* type, string field_name, string cap_name) {
-  (void) type;
-  (void) cap_name;
-  indent(out) << "case " << upcase_string(field_name) << ":" << endl;
-  indent_up();
-  indent(out) << "return this." << field_name << ";" << endl;
-  indent_down();
-}
-
-void t_as3_generator::generate_reflection_setters(ostringstream& out, t_type* type, string field_name, string cap_name) {
-  (void) type;
-  (void) cap_name;
-  indent(out) << "case " << upcase_string(field_name) << ":" << endl;
-  indent_up();
-  indent(out) << "if (value == null) {" << endl;
-  indent(out) << "  unset" << get_cap_name(field_name) << "();" << endl;
-  indent(out) << "} else {" << endl;
-  indent(out) << "  this." << field_name << " = value;" << endl;
-  indent(out) << "}" << endl;
-  indent(out) << "break;" << endl << endl;
-
-  indent_down();
-}
-
-void t_as3_generator::generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct) {
-
-  std::ostringstream getter_stream;
-  std::ostringstream setter_stream;
-
-  // build up the bodies of both the getter and setter at once
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = *f_iter;
-    t_type* type = get_true_type(field->get_type());
-    std::string field_name = field->get_name();
-    std::string cap_name = get_cap_name(field_name);
-
-    indent_up();
-    generate_reflection_setters(setter_stream, type, field_name, cap_name);
-    generate_reflection_getters(getter_stream, type, field_name, cap_name);
-    indent_down();
-  }
-
-
-  // create the setter
-  indent(out) << "public function setFieldValue(fieldID:int, value:*):void {" << endl;
-  indent_up();
-
-  indent(out) << "switch (fieldID) {" << endl;
-
-  out << setter_stream.str();
-
-  indent(out) << "default:" << endl;
-  indent(out) << "  throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
-
-  indent(out) << "}" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-
-  // create the getter
-  indent(out) << "public function getFieldValue(fieldID:int):* {" << endl;
-  indent_up();
-
-  indent(out) << "switch (fieldID) {" << endl;
-
-  out << getter_stream.str();
-
-  indent(out) << "default:" << endl;
-  indent(out) << "  throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
-
-  indent(out) << "}" << endl;
-
-  indent_down();
-
-  indent(out) << "}" << endl << endl;
-}
-
-// Creates a generic isSet method that takes the field number as argument
-void t_as3_generator::generate_generic_isset_method(std::ofstream& out, t_struct* tstruct){
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  // create the isSet method
-  indent(out) << "// Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise" << endl;
-  indent(out) << "public function isSet(fieldID:int):Boolean {" << endl;
-  indent_up();
-  indent(out) << "switch (fieldID) {" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = *f_iter;
-    indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
-    indent_up();
-    indent(out) << "return " << generate_isset_check(field) << ";" << endl;
-    indent_down();
-  }
-
-  indent(out) << "default:" << endl;
-  indent(out) << "  throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
-
-  indent(out) << "}" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-/**
- * Generates a set of As3 Bean boilerplate functions (setters, getters, etc.)
- * for the given struct.
- *
- * @param tstruct The struct definition
- */
-void t_as3_generator::generate_as3_bean_boilerplate(ofstream& out,
-                                                      t_struct* tstruct, bool bindable) {
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = *f_iter;
-    t_type* type = get_true_type(field->get_type());
-    std::string field_name = field->get_name();
-    std::string cap_name = get_cap_name(field_name);
-        
-    // Simple getter
-    generate_as3_doc(out, field);
-    indent(out) << "public function get " << field_name << "():" <<
-      type_name(type) << " {" << endl;
-    indent_up();
-    indent(out) << "return this._" << field_name << ";" << endl;
-    indent_down();
-    indent(out) << "}" << endl << endl;
-    
-    // Simple setter
-    generate_as3_doc(out, field);
-    std::string propName = tmp("thriftPropertyChange");
-    if (bindable) {
-      indent(out) << "[Bindable(event=\"" << propName << "\")]" << endl;
-    }
-    indent(out) << "public function set " << field_name << "(" << field_name
-      << ":" << type_name(type) << "):void {" << endl;
-    indent_up();
-    indent(out) << "this._" << field_name << " = " << field_name << ";" <<
-    endl;
-    generate_isset_set(out, field);
-    
-    if (bindable) {
-      // We have to use a custom event rather than the default, because if you use the default,
-      // the setter only gets called if the value has changed - this means calling foo.setIntValue(0)
-      // will not cause foo.isIntValueSet() to return true since the value of foo._intValue wasn't changed
-      // so the setter was never called.
-      indent(out) << "dispatchEvent(new Event(\"" << propName << "\"));" << endl;
-      
-      // However, if you just use a custom event, then collections won't be able to detect when elements
-      // in the collections have changed since they listed for PropertyChangeEvents.  So, we dispatch both.
-      indent(out) << "dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE));" << endl;
-    }
-    indent_down();
-    indent(out) << "}" << endl << endl;
-    
-    // Unsetter
-    indent(out) << "public function unset" << cap_name << "():void {" << endl;
-    indent_up();
-    if (type_can_be_null(type)) {
-      indent(out) << "this." << field_name << " = null;" << endl;
-    } else {
-      indent(out) << "this.__isset_" << field_name << " = false;" << endl;
-    }
-    indent_down();
-    indent(out) << "}" << endl << endl;
-    
-    // isSet method
-    indent(out) << "// Returns true if field " << field_name << " is set (has been assigned a value) and false otherwise" << endl;
-    indent(out) << "public function is" << get_cap_name("set") << cap_name << "():Boolean {" << endl;
-    indent_up();
-    if (type_can_be_null(type)) {
-      indent(out) << "return this." << field_name << " != null;" << endl;
-    } else {
-      indent(out) << "return this.__isset_" << field_name << ";" << endl;
-    }
-    indent_down();
-    indent(out) << "}" << endl << endl;
-  }
-}
-
-/**
- * Generates a toString() method for the given struct
- *
- * @param tstruct The struct definition
- */
-void t_as3_generator::generate_as3_struct_tostring(ofstream& out,
-                                                     t_struct* tstruct, bool bindable) {
-  // If it's bindable, it extends EventDispatcher so toString is an override.
-  out << indent() << "public " << (bindable ? "override " : "") << "function toString():String {" << endl;
-  indent_up();
-
-  out <<
-    indent() << "var ret:String = new String(\"" << tstruct->get_name() << "(\");" << endl;
-  out << indent() << "var first:Boolean = true;" << endl << endl;
-
-  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) {
-    bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
-    if(could_be_unset) {
-      indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl;
-      indent_up();
-    }
-
-    t_field* field = (*f_iter);
-
-    if (!first) {
-      indent(out) << "if (!first) ret +=  \", \";" << endl;
-    }
-    indent(out) << "ret += \"" << (*f_iter)->get_name() << ":\";" << endl;
-    bool can_be_null = type_can_be_null(field->get_type());
-    if (can_be_null) {
-      indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl;
-      indent(out) << "  ret += \"null\";" << endl;
-      indent(out) << "} else {" << endl;
-      indent_up();
-    }
-    
-    if (field->get_type()->is_base_type() && ((t_base_type*)(field->get_type()))->is_binary()) {
-      indent(out) << "  ret += \"BINARY\";" << endl;
-    } else if(field->get_type()->is_enum()) {
-      indent(out) << "var " << field->get_name() << "_name:String = " << get_enum_class_name(field->get_type()) << ".VALUES_TO_NAMES[this." << (*f_iter)->get_name() << "];"<< endl;
-      indent(out) << "if (" << field->get_name() << "_name != null) {" << endl;
-      indent(out) << "  ret += " << field->get_name() << "_name;" << endl;
-      indent(out) << "  ret += \" (\";" << endl;
-      indent(out) << "}" << endl;
-      indent(out) << "ret += this." << field->get_name() << ";" << endl;
-      indent(out) << "if (" << field->get_name() << "_name != null) {" << endl;
-      indent(out) << "  ret += \")\";" << endl;
-      indent(out) << "}" << endl;
-    } else {
-      indent(out) << "ret += this." << (*f_iter)->get_name() << ";" << endl;
-    }
-    
-    if (can_be_null) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    indent(out) << "first = false;" << endl;
-
-    if(could_be_unset) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    first = false;
-  }
-  out <<
-    indent() << "ret += \")\";" << endl <<
-    indent() << "return ret;" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl <<
-    endl;
-}
-
-/**
- * Generates a static map with meta data to store information such as fieldID to
- * fieldName mapping
- *
- * @param tstruct The struct definition
- */
-void t_as3_generator::generate_as3_meta_data_map(ofstream& out,
-                                                   t_struct* tstruct) {
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  // Static Map with fieldID -> FieldMetaData mappings
-  indent(out) << "public static const metaDataMap:Dictionary = new Dictionary();" << endl;
-
-  if (fields.size() > 0) {
-    // Populate map
-    scope_up(out);
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      t_field* field = *f_iter;
-      std::string field_name = field->get_name();
-      indent(out) << "metaDataMap[" << upcase_string(field_name) << "] = new FieldMetaData(\"" << field_name << "\", ";
-
-      // Set field requirement type (required, optional, etc.)
-      if (field->get_req() == t_field::T_REQUIRED) {
-        out << "TFieldRequirementType.REQUIRED, ";
-      } else if (field->get_req() == t_field::T_OPTIONAL) {
-        out << "TFieldRequirementType.OPTIONAL, ";
-      } else {
-        out << "TFieldRequirementType.DEFAULT, ";
-      }
-
-      // Create value meta data    
-      generate_field_value_meta_data(out, field->get_type());
-      out  << ");" << endl;
-    }
-    scope_down(out);
-  }
-}
-
-/** 
- * Returns a string with the as3 representation of the given thrift type
- * (e.g. for the type struct it returns "TType.STRUCT")
- */
-std::string t_as3_generator::get_as3_type_string(t_type* type) {
-  if (type->is_list()){
-    return "TType.LIST";
-  } else if (type->is_map()) {
-    return "TType.MAP";
-  } else if (type->is_set()) {
-    return "TType.SET";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "TType.STRUCT";
-  } else if (type->is_enum()) {
-    return "TType.I32";
-  } else if (type->is_typedef()) {
-    return get_as3_type_string(((t_typedef*)type)->get_type());
-  } else if (type->is_base_type()) {
-    switch (((t_base_type*)type)->get_base()) {
-      case t_base_type::TYPE_VOID   : return      "TType.VOID"; break;
-      case t_base_type::TYPE_STRING : return    "TType.STRING"; break;
-      case t_base_type::TYPE_BOOL   : return      "TType.BOOL"; break;
-      case t_base_type::TYPE_BYTE   : return      "TType.BYTE"; break;
-      case t_base_type::TYPE_I16    : return       "TType.I16"; break;
-      case t_base_type::TYPE_I32    : return       "TType.I32"; break;
-      case t_base_type::TYPE_I64    : return       "TType.I64"; break;
-      case t_base_type::TYPE_DOUBLE : return    "TType.DOUBLE"; break;
-      default : throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_as3_generator::get_as3_type_string!"); break; // This should never happen!
-    }
-  } else {
-    throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_as3_generator::get_as3_type_string!"); // This should never happen!
-  }
-}
-
-void t_as3_generator::generate_field_value_meta_data(std::ofstream& out, t_type* type){
-  out << endl;
-  indent_up();
-  indent_up();
-  if (type->is_struct()){
-    indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type);
-  } else if (type->is_container()){
-    if (type->is_list()){
-      indent(out) << "new ListMetaData(TType.LIST, ";
-      t_type* elem_type = ((t_list*)type)->get_elem_type();    
-      generate_field_value_meta_data(out, elem_type);   
-    } else if (type->is_set()){
-      indent(out) << "new SetMetaData(TType.SET, ";
-      t_type* elem_type = ((t_list*)type)->get_elem_type();    
-      generate_field_value_meta_data(out, elem_type); 
-    } else{ // map
-      indent(out) << "new MapMetaData(TType.MAP, ";
-      t_type* key_type = ((t_map*)type)->get_key_type();
-      t_type* val_type = ((t_map*)type)->get_val_type();
-      generate_field_value_meta_data(out, key_type);
-      out << ", ";
-      generate_field_value_meta_data(out, val_type);
-    }
-  } else {
-    indent(out) << "new FieldValueMetaData(" << get_as3_type_string(type);
-  }
-  out << ")";
-  indent_down();
-  indent_down();
-}
-
-
-/**
- * Generates a thrift service. In C++, this comprises an entirely separate
- * header and source file. The header file defines the methods and includes
- * the data types defined in the main header file, and the implementation
- * file contains implementations of the basic printer and default interfaces.
- *
- * @param tservice The service definition
- */
-void t_as3_generator::generate_service(t_service* tservice) {
-  // Make interface file
-  string f_service_name = package_dir_+"/"+service_name_+".as";
-  f_service_.open(f_service_name.c_str());
-
-  f_service_ <<
-    autogen_comment() << as3_package();
-  
-  scope_up(f_service_);
-  
-  f_service_ << endl <<
-    as3_type_imports() <<
-    as3_thrift_imports() <<
-    as3_thrift_gen_imports(tservice) << endl;
-
-  generate_service_interface(tservice);
-
-  scope_down(f_service_);
-  f_service_.close();
-  
-  // Now make the implementation/client file
-  f_service_name = package_dir_+"/"+service_name_+"Impl.as";
-  f_service_.open(f_service_name.c_str());
-  
-  f_service_ <<
-  autogen_comment() << as3_package();
-  
-  scope_up(f_service_);
-  
-  f_service_ << endl <<
-  as3_type_imports() <<
-  as3_thrift_imports() <<
-  as3_thrift_gen_imports(tservice) << endl;
-  
-  generate_service_client(tservice);
-  scope_down(f_service_);
-  
-  f_service_ << as3_type_imports();
-  f_service_ << as3_thrift_imports();
-  f_service_ << as3_thrift_gen_imports(tservice);
-  f_service_ << "import " << package_name_ << ".*;" << endl;
-  
-  generate_service_helpers(tservice);
-  
-  f_service_.close();
-  
-  // Now make the processor/server file
-  f_service_name = package_dir_+"/"+service_name_+"Processor.as";
-  f_service_.open(f_service_name.c_str());
-  
-  f_service_ <<
-  autogen_comment() << as3_package();
-  
-  scope_up(f_service_);
-  
-  f_service_ << endl <<
-  as3_type_imports() <<
-  as3_thrift_imports() <<
-  as3_thrift_gen_imports(tservice) << endl;
-  
-  generate_service_server(tservice);
-  scope_down(f_service_);
-  
-  f_service_ << as3_type_imports();
-  f_service_ << as3_thrift_imports();
-  f_service_ << as3_thrift_gen_imports(tservice) <<endl;
-  f_service_ << "import " << package_name_ << ".*;" << endl;
-  
-  generate_service_helpers(tservice);
-  
-  f_service_.close();
-    
-}
-
-/**
- * Generates a service interface definition.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_as3_generator::generate_service_interface(t_service* tservice) {
-  string extends = "";
-  string extends_iface = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_iface = " extends " + extends;
-  }
-
-  generate_as3_doc(f_service_, tservice);
-  f_service_ << indent() << "public interface " << service_name_ << extends_iface <<
-    " {" << endl << endl;
-  indent_up();
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_as3_doc(f_service_, *f_iter);
-    if (!(*f_iter)->is_oneway()) {
-      if ((*f_iter)->get_returntype()->is_void()) {
-        indent(f_service_) << "//function onError(Error):void;" << endl;
-        indent(f_service_) << "//function onSuccess():void;" << endl;
-      }
-      else {
-        indent(f_service_) << "//function onError(Error):void;" << endl;
-        indent(f_service_) << "//function onSuccess(" << type_name((*f_iter)->get_returntype()) << "):void;" << endl;
-      }
-    }
-    indent(f_service_) << function_signature(*f_iter) << ";" <<
-      endl << endl;
-  }
-  indent_down();
-  f_service_ <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-/**
- * Generates structs for all the service args and return types
- *
- * @param tservice The service
- */
-void t_as3_generator::generate_service_helpers(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    t_struct* ts = (*f_iter)->get_arglist();
-    generate_as3_struct_definition(f_service_, ts, false, true);
-    generate_function_helpers(*f_iter);
-  }
-}
-
-/**
- * Generates a service client definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_as3_generator::generate_service_client(t_service* tservice) {
-  string extends = "";
-  string extends_client = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_client = " extends " + extends + "Impl";
-  }
-
-  indent(f_service_) <<
-    "public class " << service_name_ << "Impl" << extends_client << " implements " << service_name_ << " {" << endl;
-  indent_up();
-
-  indent(f_service_) <<
-    "public function " << service_name_ << "Impl" << "(iprot:TProtocol, oprot:TProtocol=null)" << endl;
-  scope_up(f_service_);
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "iprot_ = iprot;" << endl;
-    f_service_ << indent() << "if (oprot == null) {" << endl;
-    indent_up();
-    f_service_ << indent() << "oprot_ = iprot;" << endl;
-    indent_down();
-    f_service_ << indent() << "} else {" << endl;
-    indent_up();
-    f_service_ << indent() << "oprot_ = oprot;" << endl;
-    indent_down();
-    f_service_ << indent() << "}";
-  } else {
-    f_service_ <<
-      indent() << "super(iprot, oprot);" << endl;
-  }
-  scope_down(f_service_);
-  f_service_ << endl;
-
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "protected var iprot_:TProtocol;"  << endl <<
-      indent() << "protected var oprot_:TProtocol;"  << endl <<
-      endl <<
-      indent() << "protected var seqid_:int;" << endl <<
-      endl;
-
-    indent(f_service_) <<
-      "public function getInputProtocol():TProtocol" << endl;
-    scope_up(f_service_);
-    indent(f_service_) <<
-      "return this.iprot_;" << endl;
-    scope_down(f_service_);
-    f_service_ << endl;
-
-    indent(f_service_) <<
-      "public function getOutputProtocol():TProtocol" << endl;
-    scope_up(f_service_);
-    indent(f_service_) <<
-      "return this.oprot_;" << endl;
-    scope_down(f_service_);
-    f_service_ << 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) {
-    string funname = (*f_iter)->get_name();
-
-    // Open function
-    if (!(*f_iter)->is_oneway()) {
-      if ((*f_iter)->get_returntype()->is_void()) {
-        indent(f_service_) << "//function onError(Error):void;" << endl;
-        indent(f_service_) << "//function onSuccess():void;" << endl;
-      }
-      else {
-        indent(f_service_) << "//function onError(Error):void;" << endl;
-        indent(f_service_) << "//function onSuccess(" << type_name((*f_iter)->get_returntype()) << "):void;" << endl;
-      }
-    }
-    indent(f_service_) <<
-      "public " << function_signature(*f_iter) << endl;
-    scope_up(f_service_);
-
-
-    // Get the struct of function call params
-    t_struct* arg_struct = (*f_iter)->get_arglist();
-    
-    string argsname = (*f_iter)->get_name() + "_args";
-    vector<t_field*>::const_iterator fld_iter;
-    const vector<t_field*>& fields = arg_struct->get_members();
-
-    // Serialize the request
-    f_service_ <<
-      indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", TMessageType.CALL, seqid_));" << endl <<
-      indent() << "var args:" << argsname << " = new " << argsname << "();" << endl;
-
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      f_service_ <<
-        indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl;
-    }
-
-    f_service_ <<
-      indent() << "args.write(oprot_);" << endl <<
-    indent() << "oprot_.writeMessageEnd();" << endl;
-    
-    if ((*f_iter)->is_oneway()) {
-      f_service_ << indent() << "oprot_.getTransport().flush();" << endl;
-    }
-    else {
-      f_service_ << indent() << "oprot_.getTransport().flush(function(error:Error):void {" << endl;
-      indent_up();
-      f_service_ << indent() << "try {" << endl;
-      indent_up();
-      string resultname = (*f_iter)->get_name() + "_result";
-      f_service_ <<
-        indent() << "if (error != null) {" << endl <<
-        indent() << "  if (onError != null) onError(error);" << endl <<
-        indent() << "  return;" << endl <<
-        indent() << "}" << endl <<
-        indent() << "var msg:TMessage = iprot_.readMessageBegin();" << endl <<
-        indent() << "if (msg.type == TMessageType.EXCEPTION) {" << endl <<
-        indent() << "  var x:TApplicationError = TApplicationError.read(iprot_);" << endl <<
-        indent() << "  iprot_.readMessageEnd();" << endl <<
-        indent() << "  if (onError != null) onError(x);" << endl <<
-        indent() << "  return;" << endl <<
-        indent() << "}" << endl <<
-        indent() << "var result :" << resultname << " = new " << resultname << "();" << endl <<
-        indent() << "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() << "if (result." << generate_isset_check("success") << ") {" << endl <<
-          indent() << "  if (onSuccess != null) onSuccess(result.success);" << endl <<
-          indent() << "  return;" << endl <<
-          indent() << "}" << 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." << (*x_iter)->get_name() << " != null) {" << endl <<
-          indent() << "  if (onError != null) onError(result." << (*x_iter)->get_name() << ");" << endl <<
-          indent() << "  return;" << endl <<
-          indent() << "}" << endl;
-      }
-
-      // If you get here it's an exception, unless a void function
-      if ((*f_iter)->get_returntype()->is_void()) {
-        f_service_ <<
-          indent() << "if (onSuccess != null) onSuccess();" << endl <<
-          indent() << "return;" << endl;
-      } else {
-        
-        f_service_ <<
-          indent() << "if (onError != null) onError(new TApplicationError(TApplicationError.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\"));" << endl;
-      }
-      indent_down();
-      f_service_ << indent() << "} catch (e:TError) {" << endl <<
-        indent() << "  if (onError != null) onError(e);" << endl <<
-        indent() << "}" << endl;
-      
-      
-      indent_down();
-      indent(f_service_) <<
-      "});" << endl;
-    }
-    // Close function
-    scope_down(f_service_);
-    f_service_ << endl;
-  }
-
-  indent_down();
-  indent(f_service_) <<
-    "}" << endl;
-}
-
-/**
- * Generates a service server definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_as3_generator::generate_service_server(t_service* tservice) {
-  // Generate the dispatch methods
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  // Extends stuff
-  string extends = "";
-  string extends_processor = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_processor = " extends " + extends + "Processor";
-  }
-
-  // Generate the header portion
-  indent(f_service_) <<
-    "public class " << service_name_ << "Processor" << extends_processor << " implements TProcessor {" << endl;
-  indent_up();
-
-  indent(f_service_) <<
-    "public function " << service_name_ << "Processor(iface:" << service_name_ << ")" << endl;
-  scope_up(f_service_);
-  if (!extends.empty()) {
-    f_service_ <<
-      indent() << "super(iface);" << endl;
-  }
-  f_service_ <<
-    indent() << "iface_ = iface;" << endl;
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_service_ <<
-      indent() << "PROCESS_MAP[\"" << (*f_iter)->get_name() << "\"] = " << (*f_iter)->get_name() << "();" << endl;
-  }
-
-  scope_down(f_service_);
-  f_service_ << endl;
-
-  f_service_ <<
-    indent() << "private var iface_:"  << service_name_ << ";" << endl;
-
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "protected const PROCESS_MAP:Dictionary = new Dictionary();" << endl;
-  }
-
-  f_service_ << endl;
-
-  // Generate the server implementation
-  string override = "";
-  if (tservice->get_extends() != NULL) {
-      override = "override ";
-  }
-  indent(f_service_) << override << "public function process(iprot:TProtocol, oprot:TProtocol):Boolean" << endl;
-  scope_up(f_service_);
-
-  f_service_ <<
-  indent() << "var msg:TMessage = iprot.readMessageBegin();" << endl;
-
-  // TODO(mcslee): validate message, was the seqid etc. legit?
-  // AS- If all method is oneway:
-  // do you have an oprot?
-  // do you you need nullcheck?
-  f_service_ <<
-    indent() << "var fn:Function = PROCESS_MAP[msg.name];" << endl <<
-    indent() << "if (fn == null) {" << endl <<
-    indent() << "  TProtocolUtil.skip(iprot, TType.STRUCT);" << endl <<
-    indent() << "  iprot.readMessageEnd();" << endl <<
-    indent() << "  var x:TApplicationError = new TApplicationError(TApplicationError.UNKNOWN_METHOD, \"Invalid method name: '\"+msg.name+\"'\");" << endl <<
-    indent() << "  oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" << endl <<
-    indent() << "  x.write(oprot);" << endl <<
-    indent() << "  oprot.writeMessageEnd();" << endl <<
-    indent() << "  oprot.getTransport().flush();" << endl <<
-    indent() << "  return true;" << endl <<
-    indent() << "}" << endl <<
-    indent() << "fn.call(this,msg.seqid, iprot, oprot);" << endl;
-
-  f_service_ <<
-    indent() << "return true;" << endl;
-
-  scope_down(f_service_);
-  f_service_ << endl;
-
-  // Generate the process subfunctions
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_process_function(tservice, *f_iter);
-  }
-
-  indent_down();
-  indent(f_service_) <<
-    "}" << endl <<
-    endl;
-}
-
-/**
- * Generates a struct and helpers for a function.
- *
- * @param tfunction The function
- */
-void t_as3_generator::generate_function_helpers(t_function* tfunction) {
-  if (tfunction->is_oneway()) {
-    return;
-  }
-
-  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_as3_struct_definition(f_service_, &result, false, true, true);
-}
-
-/**
- * Generates a process function definition.
- *
- * @param tfunction The function to write a dispatcher for
- */
-void t_as3_generator::generate_process_function(t_service* tservice,
-                                                 t_function* tfunction) {
-  (void) tservice;
-  // Open class
-  indent(f_service_) <<
-  "private function " << tfunction->get_name() << "():Function {" << endl;
-  indent_up();
-
-  // Open function
-  indent(f_service_) <<
-    "return function(seqid:int, iprot:TProtocol, oprot:TProtocol):void"
-    << endl;
-  scope_up(f_service_);
-
-  string argsname = tfunction->get_name() + "_args";
-  string resultname = tfunction->get_name() + "_result";
-
-  f_service_ <<
-    indent() << "var args:"<< argsname << " = new " << argsname << "();" << endl <<
-    indent() << "args.read(iprot);" << endl <<
-    indent() << "iprot.readMessageEnd();" << endl;
-
-  t_struct* xs = tfunction->get_xceptions();
-  const std::vector<t_field*>& xceptions = xs->get_members();
-  vector<t_field*>::const_iterator x_iter;
-
-  // Declare result for non oneway function
-  if (!tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << "var result:" << resultname << " = new " << resultname << "();" << endl;
-  }
-
-  // Try block for a function with exceptions
-  if (xceptions.size() > 0) {
-    f_service_ <<
-      indent() << "try {" << endl;
-    indent_up();
-  }
-
-  // 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_ << indent();
-  if (tfunction->is_oneway()){
-    f_service_ <<
-      "iface_." << 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." << (*f_iter)->get_name();
-    }
-    f_service_ << ");" << endl;
-  } else {
-    f_service_ << "// sorry this operation is not supported yet" << endl;
-    f_service_ << indent() << "throw new Error(\"This is not yet supported\");" << endl;
-  }
-
-  // Set isset on success field
-  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void() && !type_can_be_null(tfunction->get_returntype())) {
-    f_service_ <<
-      indent() << "result.set" << get_cap_name("success") << get_cap_name("isSet") << "(true);" << endl;
-  }
-
-  if (!tfunction->is_oneway() && xceptions.size() > 0) {
-    indent_down();
-    f_service_ << indent() << "}";
-    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      f_service_ << " catch (" << (*x_iter)->get_name() << ":" << type_name((*x_iter)->get_type(), false, false) << ") {" << endl;
-      if (!tfunction->is_oneway()) {
-        indent_up();
-        f_service_ <<
-          indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl;
-        indent_down();
-        f_service_ << indent() << "}";
-      } else {
-        f_service_ << "}";
-      }
-    }
-    f_service_ << " catch (th:Error) {" << endl;
-    indent_up();
-    f_service_ <<
-      indent() << "trace(\"Internal error processing " << tfunction->get_name() << "\", th);" << endl <<
-      indent() << "var x:TApplicationError = new TApplicationError(TApplicationError.INTERNAL_ERROR, \"Internal error processing " << tfunction->get_name() << "\");" << endl <<
-      indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl <<
-      indent() << "x.write(oprot);" << endl <<
-      indent() << "oprot.writeMessageEnd();" << endl <<
-      indent() << "oprot.getTransport().flush();" << endl <<
-      indent() << "return;" << endl;
-    indent_down();
-    f_service_ << indent() << "}" << endl;
-  }
-
-  // Shortcut out here for oneway functions
-  if (tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << "return;" << endl;
-    scope_down(f_service_);
-
-    // Close class
-    indent_down();
-    f_service_ <<
-      indent() << "}" << endl <<
-      endl;
-    return;
-  }
-
-  f_service_ <<
-    indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid));" << endl <<
-    indent() << "result.write(oprot);" << endl <<
-    indent() << "oprot.writeMessageEnd();" << endl <<
-    indent() << "oprot.getTransport().flush();" << endl;
-
-  // Close function
-  scope_down(f_service_);
-  f_service_ << endl;
-
-  // Close class
-  indent_down();
-  f_service_ <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-/**
- * Deserializes a field of any type.
- *
- * @param tfield The field
- * @param prefix The variable name or container for this field
- */
-void t_as3_generator::generate_deserialize_field(ofstream& out,
-                                                  t_field* tfield,
-                                                  string prefix) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  if (type->is_void()) {
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  string name = prefix + tfield->get_name();
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct(out,
-                                (t_struct*)type,
-                                name);
-  } else if (type->is_container()) {
-    generate_deserialize_container(out, type, name);
-  } else if (type->is_base_type() || type->is_enum()) {
-
-    indent(out) <<
-      name << " = 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:
-        if (((t_base_type*)type)->is_binary()) {
-          out << "readBinary();";
-        } else {
-          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 As3 name for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      out << "readI32();";
-    }
-    out <<
-      endl;
-  } else {
-    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
-           tfield->get_name().c_str(), type_name(type).c_str());
-  }
-}
-
-/**
- * Generates an unserializer for a struct, invokes read()
- */
-void t_as3_generator::generate_deserialize_struct(ofstream& out,
-                                                   t_struct* tstruct,
-                                                   string prefix) {
-  out <<
-    indent() << prefix << " = new " << type_name(tstruct) << "();" << endl <<
-    indent() << prefix << ".read(iprot);" << endl;
-}
-
-/**
- * Deserializes a container by reading its size and then iterating
- */
-void t_as3_generator::generate_deserialize_container(ofstream& out,
-                                                      t_type* ttype,
-                                                      string prefix) {
-  scope_up(out);
-
-  string obj;
-
-  if (ttype->is_map()) {
-    obj = tmp("_map");
-  } else if (ttype->is_set()) {
-    obj = tmp("_set");
-  } else if (ttype->is_list()) {
-    obj = tmp("_list");
-  }
-
-  // Declare variables, read header
-  if (ttype->is_map()) {
-    indent(out) << "var " << obj << ":TMap = iprot.readMapBegin();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) << "var " << obj << ":TSet = iprot.readSetBegin();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) << "var " << obj << ":TList = iprot.readListBegin();" << endl;
-  }
-
-  indent(out)
-    << prefix << " = new " << type_name(ttype, false, true)
-    // size the collection correctly
-    << "("
-    << ");" << endl;
-
-  // For loop iterates over elements
-  string i = tmp("_i");
-  indent(out) <<
-    "for (var " << i << ":int = 0; " <<
-    i << " < " << obj << ".size" << "; " <<
-    "++" << i << ")" << endl;
-
-    scope_up(out);
-
-    if (ttype->is_map()) {
-      generate_deserialize_map_element(out, (t_map*)ttype, prefix);
-    } else if (ttype->is_set()) {
-      generate_deserialize_set_element(out, (t_set*)ttype, prefix);
-    } else if (ttype->is_list()) {
-      generate_deserialize_list_element(out, (t_list*)ttype, prefix);
-    }
-
-    scope_down(out);
-
-  // Read container end
-  if (ttype->is_map()) {
-    indent(out) << "iprot.readMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) << "iprot.readSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) << "iprot.readListEnd();" << endl;
-  }
-
-  scope_down(out);
-}
-
-
-/**
- * Generates code to deserialize a map
- */
-void t_as3_generator::generate_deserialize_map_element(ofstream& out,
-                                                        t_map* tmap,
-                                                        string prefix) {
-  string key = tmp("_key");
-  string val = tmp("_val");
-  t_field fkey(tmap->get_key_type(), key);
-  t_field fval(tmap->get_val_type(), val);
-
-  indent(out) <<
-    declare_field(&fkey) << endl;
-  indent(out) <<
-    declare_field(&fval) << endl;
-
-  generate_deserialize_field(out, &fkey);
-  generate_deserialize_field(out, &fval);
-
-  indent(out) <<
-    prefix << "[" << key << "] = " << val << ";" << endl;
-}
-
-/**
- * Deserializes a set element
- */
-void t_as3_generator::generate_deserialize_set_element(ofstream& out,
-                                                        t_set* tset,
-                                                        string prefix) {
-  string elem = tmp("_elem");
-  t_field felem(tset->get_elem_type(), elem);
-
-  indent(out) <<
-    declare_field(&felem) << endl;
-
-  generate_deserialize_field(out, &felem);
-
-  indent(out) <<
-    prefix << ".add(" << elem << ");" << endl;
-}
-
-/**
- * Deserializes a list element
- */
-void t_as3_generator::generate_deserialize_list_element(ofstream& out,
-                                                         t_list* tlist,
-                                                         string prefix) {
-  string elem = tmp("_elem");
-  t_field felem(tlist->get_elem_type(), elem);
-
-  indent(out) <<
-    declare_field(&felem) << endl;
-
-  generate_deserialize_field(out, &felem);
-
-  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_as3_generator::generate_serialize_field(ofstream& out,
-                                                t_field* tfield,
-                                                string prefix) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  // Do nothing for void types
-  if (type->is_void()) {
-    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_serialize_struct(out,
-                              (t_struct*)type,
-                              prefix + tfield->get_name());
-  } else if (type->is_container()) {
-    generate_serialize_container(out,
-                                 type,
-                                 prefix + tfield->get_name());
-  } else if (type->is_base_type() || type->is_enum()) {
-
-    string name = prefix + tfield->get_name();
-    indent(out) <<
-      "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:
-        if (((t_base_type*)type)->is_binary()) {
-          out << "writeBinary(" << name << ");";
-        } else {
-          out << "writeString(" << name << ");";
-        }
-        break;
-      case t_base_type::TYPE_BOOL:
-        out << "writeBool(" << name << ");";
-        break;
-      case t_base_type::TYPE_BYTE:
-        out << "writeByte(" << name << ");";
-        break;
-      case t_base_type::TYPE_I16:
-        out << "writeI16(" << name << ");";
-        break;
-      case t_base_type::TYPE_I32:
-        out << "writeI32(" << name << ");";
-        break;
-      case t_base_type::TYPE_I64:
-        out << "writeI64(" << name << ");";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        out << "writeDouble(" << name << ");";
-        break;
-      default:
-        throw "compiler error: no As3 name for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      out << "writeI32(" << name << ");";
-    }
-    out << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
-           prefix.c_str(),
-           tfield->get_name().c_str(),
-           type_name(type).c_str());
-  }
-}
-
-/**
- * Serializes all the members of a struct.
- *
- * @param tstruct The struct to serialize
- * @param prefix  String prefix to attach to all fields
- */
-void t_as3_generator::generate_serialize_struct(ofstream& out,
-                                                 t_struct* tstruct,
-                                                 string prefix) {
-  (void) tstruct;
-  out <<
-    indent() << prefix << ".write(oprot);" << endl;
-}
-
-/**
- * Serializes a container by writing its size then the elements.
- *
- * @param ttype  The type of container
- * @param prefix String prefix for fields
- */
-void t_as3_generator::generate_serialize_container(ofstream& out,
-                                                    t_type* ttype,
-                                                    string prefix) {
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    string iter = tmp("_key");
-    string counter = tmp("_sizeCounter");
-    indent(out) << "var " << counter << ":int = 0;" << endl;
-    indent(out) << "for (var " << iter << ":* in " << prefix << ") {" << endl;
-    indent(out) << "  " << counter << +"++;" << endl;
-    indent(out) << "}" << endl;
-    
-    indent(out) <<
-      "oprot.writeMapBegin(new TMap(" <<
-      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
-      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
-      counter << "));" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "oprot.writeSetBegin(new TSet(" <<
-      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
-      prefix << ".size));" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "oprot.writeListBegin(new TList(" <<
-      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
-      prefix << ".length));" << endl;
-  }
-
-  string iter = tmp("elem");
-  if (ttype->is_map()) {
-    indent(out) <<
-      "for (var " << iter << ":* in " << prefix << ")";
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "for each (var " << iter << ":* in " << prefix << ".toArray())";
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "for each (var " << iter << ":* in " << prefix << ")";
-  }
-
-    scope_up(out);
-
-    if (ttype->is_map()) {
-      generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
-    } else if (ttype->is_set()) {
-      generate_serialize_set_element(out, (t_set*)ttype, iter);
-    } else if (ttype->is_list()) {
-      generate_serialize_list_element(out, (t_list*)ttype, iter);
-    }
-
-    scope_down(out);
-
-  if (ttype->is_map()) {
-    indent(out) <<
-      "oprot.writeMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "oprot.writeSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "oprot.writeListEnd();" << endl;
-  }
-
-  scope_down(out);
-}
-
-/**
- * Serializes the members of a map.
- */
-void t_as3_generator::generate_serialize_map_element(ofstream& out,
-                                                      t_map* tmap,
-                                                      string iter,
-                                                      string map) {
-  t_field kfield(tmap->get_key_type(), iter);
-  generate_serialize_field(out, &kfield, "");
-  t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
-  generate_serialize_field(out, &vfield, "");
-}
-
-/**
- * Serializes the members of a set.
- */
-void t_as3_generator::generate_serialize_set_element(ofstream& out,
-                                                      t_set* tset,
-                                                      string iter) {
-  t_field efield(tset->get_elem_type(), iter);
-  generate_serialize_field(out, &efield, "");
-}
-
-/**
- * Serializes the members of a list.
- */
-void t_as3_generator::generate_serialize_list_element(ofstream& out,
-                                                       t_list* tlist,
-                                                       string iter) {
-  t_field efield(tlist->get_elem_type(), iter);
-  generate_serialize_field(out, &efield, "");
-}
-
-/**
- * Returns a As3 type name
- *
- * @param ttype The type
- * @param container Is the type going inside a container?
- * @return As3 type name, i.e. HashMap<Key,Value>
- */
-string t_as3_generator::type_name(t_type* ttype, bool in_container, bool in_init) {
-  (void) in_init;
-  // In As3 typedefs are just resolved to their real type
-  ttype = get_true_type(ttype);
-  string prefix;
-
-  if (ttype->is_base_type()) {
-    return base_type_name((t_base_type*)ttype, in_container);
-  } else if (ttype->is_enum()) {
-    return "int";
-  } else if (ttype->is_map()) {
-    return "Dictionary";
-  } else if (ttype->is_set()) {
-    return "Set";
-  } else if (ttype->is_list()) {
-    return "Array";
-  }
-
-  // Check for namespacing
-  t_program* program = ttype->get_program();
-  if (program != NULL && program != program_) {
-    string package = program->get_namespace("as3");
-    if (!package.empty()) {
-      return package + "." + ttype->get_name();
-    }
-  }
-
-  return ttype->get_name();
-}
-
-/**
- * Returns the AS3 type that corresponds to the thrift type.
- *
- * @param tbase The base type
- * @param container Is it going in a As3 container?
- */
-string t_as3_generator::base_type_name(t_base_type* type,
-                                        bool in_container) {
-  (void) in_container;
-  t_base_type::t_base tbase = type->get_base();
-
-  switch (tbase) {
-  case t_base_type::TYPE_VOID:
-    return "void";
-  case t_base_type::TYPE_STRING:
-    if (type->is_binary()) {
-      return "ByteArray";
-    } else {
-      return "String";
-    }
-  case t_base_type::TYPE_BOOL:
-    return "Boolean";
-  case t_base_type::TYPE_BYTE:
-  case t_base_type::TYPE_I16:
-  case t_base_type::TYPE_I32:
-    return "int";
-  case t_base_type::TYPE_I64:
-    throw "i64 is not yet supported in as3";
-  case t_base_type::TYPE_DOUBLE:
-    return "Number";
-  default:
-    throw "compiler error: no C++ name for base type " + t_base_type::t_base_name(tbase);
-  }
-}
-
-/**
- * Declares a field, which may include initialization as necessary.
- *
- * @param ttype The type
- */
-string t_as3_generator::declare_field(t_field* tfield, bool init) {
-  // TODO(mcslee): do we ever need to initialize the field?
-  string result = "var " + tfield->get_name() + ":" + type_name(tfield->get_type());
-  if (init) {
-    t_type* ttype = get_true_type(tfield->get_type());
-    if (ttype->is_base_type() && tfield->get_value() != NULL) {
-      ofstream dummy;
-      result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
-    } else if (ttype->is_base_type()) {
-      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
-      switch (tbase) {
-      case t_base_type::TYPE_VOID:
-        throw "NO T_VOID CONSTRUCT";
-      case t_base_type::TYPE_STRING:
-        result += " = null";
-        break;
-      case t_base_type::TYPE_BOOL:
-        result += " = 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:
-        result += " = 0";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        result += " = (double)0";
-        break;
-    }
-
-    } else if (ttype->is_enum()) {
-      result += " = 0";
-    } else if (ttype->is_container()) {
-      result += " = new " + type_name(ttype, false, true) + "()";
-    } else {
-      result += " = new " + type_name(ttype, false, true) + "()";;
-    }
-  }
-  return result + ";";
-}
-
-/**
- * Renders a function signature of the form 'type name(args)'
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_as3_generator::function_signature(t_function* tfunction,
-                                            string prefix) {
-  std::string arguments = argument_list(tfunction->get_arglist());
-  if (! tfunction->is_oneway()) {
-    if (arguments != "") {
-      arguments += ", ";
-    }
-    arguments += "onError:Function, onSuccess:Function";
-  }
-
-  std::string result = "function " + 
-    prefix + tfunction->get_name() + "(" + arguments + "):void";
-  return result;
-}
-
-/**
- * Renders a comma separated field list, with type names
- */
-string t_as3_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_name((*f_iter)->get_type());
-  }
-  return result;
-}
-
-/**
- * Converts the parse type to a C++ enum string for the given type.
- */
-string t_as3_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 "TType.STRING";
-    case t_base_type::TYPE_BOOL:
-      return "TType.BOOL";
-    case t_base_type::TYPE_BYTE:
-      return "TType.BYTE";
-    case t_base_type::TYPE_I16:
-      return "TType.I16";
-    case t_base_type::TYPE_I32:
-      return "TType.I32";
-    case t_base_type::TYPE_I64:
-      return "TType.I64";
-    case t_base_type::TYPE_DOUBLE:
-      return "TType.DOUBLE";
-    }
-  } else if (type->is_enum()) {
-    return "TType.I32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "TType.STRUCT";
-  } else if (type->is_map()) {
-    return "TType.MAP";
-  } else if (type->is_set()) {
-    return "TType.SET";
-  } else if (type->is_list()) {
-    return "TType.LIST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-/**
- * Applies the correct style to a string based on the value of nocamel_style_
- */
-std::string t_as3_generator::get_cap_name(std::string name){
-  name[0] = toupper(name[0]);
-  return name;
-}
-
-string t_as3_generator::constant_name(string name) {
-  string constant_name;
-
-  bool is_first = true;
-  bool was_previous_char_upper = false;
-  for (string::iterator iter = name.begin(); iter != name.end(); ++iter) {
-    string::value_type character = (*iter);
-
-    bool is_upper = isupper(character);
-
-    if (is_upper && !is_first && !was_previous_char_upper) {
-      constant_name += '_';
-    }
-    constant_name += toupper(character);
-
-    is_first = false;
-    was_previous_char_upper = is_upper;
-  }
-
-  return constant_name;
-}
-
-/**
- * Emits a As3Doc comment if the provided object has a doc in Thrift
- */
-void t_as3_generator::generate_as3_doc(ofstream &out,
-                                         t_doc* tdoc) {
-  if (tdoc->has_doc()) {
-    generate_docstring_comment(out,
-      "/**\n",
-      " * ", tdoc->get_doc(),
-      " */\n");
-  }
-}
-
-/**
- * Emits a As3Doc comment if the provided function object has a doc in Thrift
- */
-void t_as3_generator::generate_as3_doc(ofstream &out,
-                                         t_function* tfunction) {
-  if (tfunction->has_doc()) {
-    stringstream ss;
-    ss << tfunction->get_doc();
-    const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
-    vector<t_field*>::const_iterator p_iter;
-    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
-      t_field* p = *p_iter;
-      ss << "\n@param " << p->get_name();
-      if (p->has_doc()) {
-        ss << " " << p->get_doc();
-      }
-    }
-    generate_docstring_comment(out,
-      "/**\n",
-      " * ", ss.str(),
-      " */\n");
-  }
-}
-
-std::string t_as3_generator::generate_isset_check(t_field* field) {
-  return generate_isset_check(field->get_name());
-}
-
-std::string t_as3_generator::generate_isset_check(std::string field_name) {
-  return "is" + get_cap_name("set") + get_cap_name(field_name) + "()";
-}
-
-void t_as3_generator::generate_isset_set(ofstream& out, t_field* field) {
-  if (!type_can_be_null(field->get_type())) {
-    indent(out) << "this.__isset_" << field->get_name() << " = true;" << endl;
-  }
-}
-
-std::string t_as3_generator::get_enum_class_name(t_type* type) {
-  string package = "";
-  t_program* program = type->get_program();
-  if (program != NULL && program != program_) {
-    package = program->get_namespace("as3") + ".";
-  }
-  return package + type->get_name();
-}
-
-THRIFT_REGISTER_GENERATOR(as3, "AS3",
-"    bindable:          Add [bindable] metadata to all the struct classes.\n"
-)
-
diff --git a/compiler/cpp/src/generate/t_c_glib_generator.cc b/compiler/cpp/src/generate/t_c_glib_generator.cc
deleted file mode 100644
index 373e6a8..0000000
--- a/compiler/cpp/src/generate/t_c_glib_generator.cc
+++ /dev/null
@@ -1,3072 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- * Contains some contributions under the Thrift Software License.
- * Please see doc/old-thrift-license.txt in the Thrift distribution for
- * details.
- */
-
-#include <fstream>
-#include <iostream>
-#include <string>
-#include <vector>
-
-#include <ctype.h>
-
-#include "platform.h"
-#include "t_oop_generator.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/* forward declarations */
-string initial_caps_to_underscores(string name);
-string to_upper_case(string name);
-string to_lower_case(string name);
-
-/**
- * C code generator, using glib for C typing.
- */
-class t_c_glib_generator : public t_oop_generator {
- public:
-
-  /* constructor */
-  t_c_glib_generator(t_program *program,
-                     const map<string, string> &parsed_options,
-                     const string &option_string) : t_oop_generator(program)
-  {
-    (void) parsed_options;
-    (void) option_string;
-    /* set the output directory */
-    this->out_dir_base_ = "gen-c_glib";
-
-    /* set the namespace */
-    this->nspace = program_->get_namespace("c_glib");
-
-    if (this->nspace.empty()) {
-      this->nspace = "";
-      this->nspace_u = "";
-      this->nspace_uc = "";
-      this->nspace_lc = "";
-    } else {
-      /* replace dots with underscores */
-      char *tmp = strdup(this->nspace.c_str());
-      for (unsigned int i = 0; i < strlen(tmp); i++) {
-        if (tmp[i] == '.') {
-          tmp[i] = '_';
-        }
-      }
-      this->nspace = string(tmp, strlen(tmp));
-      free(tmp);
-
-      /* clean up the namespace for C.
-       * An input of 'namespace foo' should result in:
-       *  - nspace = foo       - for thrift objects and typedefs
-       *  - nspace_u = Foo     - for internal GObject prefixes
-       *  - nspace_uc = FOO_   - for macro prefixes
-       *  - nspace_lc = foo_   - for filename and method prefixes
-       * The underscores are there since uc and lc strings are used as file and
-       * variable prefixes.
-       */
-      this->nspace_u = initial_caps_to_underscores(this->nspace);
-      this->nspace_uc = to_upper_case(this->nspace_u) + "_";
-      this->nspace_lc = to_lower_case(this->nspace_u) + "_";
-    }
-  }
-
-  /* initialization and destruction */
-  void init_generator();
-  void close_generator();
-
-  /* generation functions */
-  void generate_typedef(t_typedef *ttypedef);
-  void generate_enum(t_enum *tenum);
-  void generate_consts(vector<t_const *> consts);
-  void generate_struct(t_struct *tstruct);
-  void generate_service(t_service *tservice);
-  void generate_xception(t_struct *tstruct);
-
- private:
-
-  /* file streams */
-  ofstream f_types_;
-  ofstream f_types_impl_;
-  ofstream f_header_;
-  ofstream f_service_;
-
-  /* namespace variables */
-  string nspace;
-  string nspace_u;
-  string nspace_uc;
-  string nspace_lc;
-
-  /* helper functions */
-  bool is_complex_type(t_type *ttype);
-  string type_name(t_type* ttype, bool in_typedef=false, bool is_const=false);
-  string base_type_name(t_base_type *type);
-  string type_to_enum(t_type *type);
-  string constant_value(string name, t_type *type, t_const_value *value);
-  string function_signature(t_function *tfunction);
-  string argument_list(t_struct *tstruct);
-  string xception_list(t_struct *tstruct);
-  string declare_field(t_field *tfield, bool init=false, bool pointer=false, bool constant=false, bool reference=false);
-  void declare_local_variable(ofstream &out, t_type *ttype, string &base_name);
-
-  /* generation functions */
-  void generate_const_initializer(string name, t_type *type, t_const_value *value);
-  void generate_service_client(t_service *tservice);
-  void generate_service_server(t_service *tservice);
-  void generate_object(t_struct *tstruct);
-  void generate_struct_writer(ofstream &out, t_struct *tstruct, string this_name, string this_get="", bool is_function=true);
-  void generate_struct_reader(ofstream &out, t_struct *tstruct, string this_name, string this_get="", bool is_function=true);
-
-  void generate_serialize_field(ofstream &out, t_field *tfield, string prefix, string suffix, int error_ret);
-  void generate_serialize_struct(ofstream &out, t_struct *tstruct, string prefix, int error_ret);
-  void generate_serialize_container(ofstream &out, t_type *ttype, string prefix, int error_ret);
-  void generate_serialize_map_element(ofstream &out, t_map *tmap, string key, string value, int error_ret);
-  void generate_serialize_set_element(ofstream &out, t_set *tset, string element, int error_ret);
-  void generate_serialize_list_element(ofstream &out, t_list *tlist, string list, string index, int error_ret);
-
-  void generate_deserialize_field(ofstream &out, t_field *tfield, string prefix, string suffix, int error_ret, bool allocate=true);
-  void generate_deserialize_struct(ofstream &out, t_struct *tstruct, string prefix, int error_ret, bool allocate=true);
-  void generate_deserialize_container(ofstream &out, t_type *ttype, string prefix, int error_ret);
-  void generate_deserialize_map_element(ofstream &out, t_map *tmap, string prefix, int error_ret);
-  void generate_deserialize_set_element(ofstream &out, t_set *tset, string prefix, int error_ret);
-  void generate_deserialize_list_element(ofstream &out, t_list *tlist, string prefix, string index, int error_ret);
-
-  string generate_new_hash_from_type(t_type * key, t_type * value);
-  string generate_new_array_from_type(t_type * ttype); 
-
-  string generate_free_func_from_type(t_type * ttype);
-  string generate_hash_func_from_type(t_type * ttype);
-  string generate_cmp_func_from_type(t_type * ttype);
-};
-
-/**
- * Prepare for file generation by opening up the necessary file
- * output streams.
- */
-void t_c_glib_generator::init_generator() {
-  /* create output directory */
-  MKDIR(get_out_dir().c_str());
-
-  string program_name_u = initial_caps_to_underscores(program_name_);
-  string program_name_uc = to_upper_case(program_name_u);
-  string program_name_lc = to_lower_case(program_name_u);
-
-  /* create output files */
-  string f_types_name = get_out_dir() + this->nspace_lc
-                        + program_name_lc + "_types.h";
-  f_types_.open(f_types_name.c_str());
-  string f_types_impl_name = get_out_dir() + this->nspace_lc
-                             + program_name_lc + "_types.c";
-  f_types_impl_.open(f_types_impl_name.c_str());
-
-  /* add thrift boilerplate headers */
-  f_types_ << autogen_comment();
-  f_types_impl_ << autogen_comment();
-
-  /* include inclusion guard */
-  f_types_ << 
-    "#ifndef " << this->nspace_uc << program_name_uc << "_TYPES_H" << endl <<
-    "#define " << this->nspace_uc << program_name_uc << "_TYPES_H" << endl <<
-    endl;
-
-  /* include base types */
-  f_types_ <<
-    "/* base includes */" << endl <<
-    "#include <glib-object.h>" << endl <<
-    "#include <thrift/c_glib/thrift_struct.h>" << endl <<
-    "#include <thrift/c_glib/protocol/thrift_protocol.h>" << endl;
-
-  /* include other thrift includes */
-  const vector<t_program *> &includes = program_->get_includes();
-  for (size_t i = 0; i < includes.size(); ++i) {
-    f_types_ <<
-      "/* other thrift includes */" << endl <<
-      "#include \"" << this->nspace_lc << initial_caps_to_underscores(includes[i]->get_name()) <<
-          "_types.h\"" << endl;
-  }
-  f_types_ << endl;
-
-  /* include custom headers */
-  const vector<string> &c_includes = program_->get_c_includes();
-  f_types_ << "/* custom thrift includes */" << endl;
-  for (size_t i = 0; i < c_includes.size(); ++i) {
-    if (c_includes[i][0] == '<') {
-      f_types_ <<
-        "#include " << c_includes[i] << endl;
-    } else {
-      f_types_ <<
-        "#include \"" << c_includes[i] << "\"" << endl;
-    }
-  }
-  f_types_ << endl;
-
-  // include the types file
-  f_types_impl_ <<
-    endl <<
-    "#include \"" << this->nspace_lc << program_name_u << 
-        "_types.h\"" << endl <<
-    "#include <thrift/c_glib/thrift.h>" << endl <<
-    endl;
-
-  f_types_ <<
-    "/* begin types */" << endl << endl;
-}
-
-/**
- *  Finish up generation and close all file streams.
- */
-void t_c_glib_generator::close_generator() {
-  string program_name_uc = to_upper_case 
-    (initial_caps_to_underscores(program_name_));
-
-  /* end the header inclusion guard */
-  f_types_ <<
-    "#endif /* " << this->nspace_uc << program_name_uc << "_TYPES_H */" << endl;
-
-  /* close output file */
-  f_types_.close();
-  f_types_impl_.close();
-}
-
-/**
- * Generates a Thrift typedef in C code.  For example:
- * 
- * Thrift: 
- * typedef map<i32,i32> SomeMap
- * 
- * C: 
- * typedef GHashTable * ThriftSomeMap;
- */
-void t_c_glib_generator::generate_typedef(t_typedef* ttypedef) {
-  f_types_ <<
-    indent() << "typedef " << type_name(ttypedef->get_type(), true) <<
-        " " << this->nspace << ttypedef->get_symbolic() << ";" << endl <<
-    endl;
-} 
-
-/**
- * Generates a C enumeration.  For example:
- *
- * Thrift:
- * enum MyEnum {
- *   ONE = 1,
- *   TWO
- * }
- *
- * C:
- * enum _ThriftMyEnum {
- *   THRIFT_MY_ENUM_ONE = 1,
- *   THRIFT_MY_ENUM_TWO
- * };
- * typedef enum _ThriftMyEnum ThriftMyEnum;
- */
-void t_c_glib_generator::generate_enum(t_enum *tenum) {
-  string name = tenum->get_name();
-  string name_uc = to_upper_case(initial_caps_to_underscores(name));
-
-  f_types_ <<
-    indent() << "enum _" << this->nspace << name << " {" << endl;
-
-  indent_up();
-
-  vector<t_enum_value *> constants = tenum->get_constants();
-  vector<t_enum_value *>::iterator c_iter;
-  bool first = true;
-
-  /* output each of the enumeration elements */
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    if (first) {
-      first = false;
-    } else {
-      f_types_ << "," << endl;
-    }
-
-    f_types_ <<
-      indent() << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name();
-    if ((*c_iter)->has_value()) {
-      f_types_ <<
-        " = " << (*c_iter)->get_value();
-    }
-  }
-
-  indent_down();
-  f_types_ <<
-    endl <<
-    "};" << endl <<
-    "typedef enum _" << this->nspace << name << " " << this->nspace << name << ";" << endl <<
-    endl;
-}
-
-/**
- * Generates Thrift constants in C code.
- */
-void t_c_glib_generator::generate_consts (vector<t_const *> consts) {
-  f_types_ << "/* constants */" << endl;
-  f_types_impl_ << "/* constants */" << endl;
-
-  vector<t_const *>::iterator c_iter;
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    string name = (*c_iter)->get_name();
-    string name_uc = to_upper_case(name);
-    string name_lc = to_lower_case(name);
-    t_type *type = (*c_iter)->get_type();
-    t_const_value *value = (*c_iter)->get_value();
-
-    f_types_ <<
-      indent() << "#define " << this->nspace_uc << name_uc << " " <<
-          constant_value (name_lc, type, value) << endl;
-
-    generate_const_initializer (name_lc, type, value);
-  }
-
-  f_types_ << endl;
-  f_types_impl_ << endl;
-}
-
-/**
- * Generate Thrift structs in C code, as GObjects.  Example:
- *
- * Thrift:
- * struct Bonk
- * {
- *   1: string message,
- *   2: i32 type
- * }
- *
- * C GObject instance header:
- * struct _ThriftBonk
- * {
- *   GObject parent;
- *
- *   gchar * message;
- *   gint32 type;
- * };
- * typedef struct _ThriftBonk ThriftBonk
- * // ... additional GObject boilerplate ...
- */
-void t_c_glib_generator::generate_struct (t_struct *tstruct) {
-  f_types_ << "/* struct " << tstruct->get_name() << " */" << endl;
-  generate_object(tstruct);
-}
-
-/**
- * Generate C code to represent Thrift services.  Creates a new GObject
- * which can be used to access the service.
- */
-void t_c_glib_generator::generate_service (t_service *tservice) {
-  string svcname_u = initial_caps_to_underscores(tservice->get_name());
-  string svcname_uc = this->nspace_uc + to_upper_case(svcname_u);
-  string filename = this->nspace_lc + to_lower_case(svcname_u);
-
-  // make output files
-  string f_header_name = get_out_dir() + filename + ".h";
-  f_header_.open(f_header_name.c_str());
-
-  string program_name_u = initial_caps_to_underscores(program_name_);
-  string program_name_lc = to_lower_case(program_name_u);
-
-  // add header file boilerplate
-  f_header_ <<
-    autogen_comment();
-
-  // add an inclusion guard
-  f_header_ <<
-    "#ifndef " << svcname_uc << "_H" << endl <<
-    "#define " << svcname_uc << "_H" << endl <<
-    endl;
-
-  // add standard includes
-  f_header_ <<
-    "#include \"" << this->nspace_lc << program_name_lc << "_types.h\"" << endl;
-
-  // if we are inheriting from another service, include its header
-  t_service *extends_service = tservice->get_extends();
-  if (extends_service != NULL) {
-    f_header_ <<
-      "#include \"" << this->nspace_lc << to_lower_case(initial_caps_to_underscores(extends_service->get_name())) << ".h\"" << endl;
-  }
-  f_header_ << endl;
-
-  // create the service implementation
-  string f_service_name = get_out_dir() + filename + ".c";
-  f_service_.open(f_service_name.c_str());
-
-  // add the boilerplace header
-  f_service_ <<
-    autogen_comment();
-
-  // include the headers
-  f_service_ <<
-    "#include <string.h>" << endl <<
-    "#include <thrift/c_glib/thrift.h>" << endl <<
-    "#include <thrift/c_glib/thrift_application_exception.h>" << endl <<
-    "#include \"" << filename << ".h\"" << endl <<
-    endl;
-
-  // generate the client objects
-  generate_service_client (tservice);
-
-  // generate the server objects
-  generate_service_server (tservice);
-
-  // end the header inclusion guard
-  f_header_ <<
-    "#endif /* " << svcname_uc << "_H */" << endl;
-
-  // close the files
-  f_service_.close();
-  f_header_.close();
-}
-
-/**
- *
- */
-void t_c_glib_generator::generate_xception (t_struct *tstruct) {
-  string name = tstruct->get_name();
-  string name_u = initial_caps_to_underscores(name);
-  string name_lc = to_lower_case(name_u);
-  string name_uc = to_upper_case(name_u);
-
-  generate_object(tstruct);
-
-  f_types_ << "/* exception */" << endl <<
-    "typedef enum" << endl <<
-    "{" << endl <<
-    "  " << this->nspace_uc << name_uc << "_ERROR_CODE," << endl <<
-    "} " << this->nspace << name << "Error;" << endl <<
-    endl <<
-    "GQuark " << this->nspace_lc << name_lc << "_error_quark (void);" << endl <<
-    "#define " << this->nspace_uc << name_uc << "_ERROR (" <<
-      this->nspace_lc << name_lc << "_error_quark())" << endl <<
-    endl <<
-    endl;
-
-  f_types_impl_ <<
-    "/* define the GError domain for exceptions */" << endl <<
-    "#define " << this->nspace_uc << name_uc << "_ERROR_DOMAIN \"" <<
-        this->nspace_lc << name_lc << "_error_quark\"" << endl <<
-    "GQuark" << endl <<
-    this->nspace_lc << name_lc << "_error_quark (void)" << endl <<
-    "{" << endl <<
-    "  return g_quark_from_static_string (" << this->nspace_uc << name_uc <<
-        "_ERROR_DOMAIN);" << endl <<
-    "}" << endl <<
-    endl;
-}
-
-/********************
- * HELPER FUNCTIONS *
- ********************/
-
-/**
- * Returns true if ttype is not a primitive.
- */
-bool t_c_glib_generator::is_complex_type(t_type *ttype) {
-  ttype = get_true_type (ttype);
-
-  return ttype->is_container()
-         || ttype->is_struct()
-         || ttype->is_xception()
-         || (ttype->is_base_type()
-             && (((t_base_type *) ttype)->get_base()
-                  == t_base_type::TYPE_STRING));
-}
-
-
-/**
- * Maps a Thrift t_type to a C type.
- */
-string t_c_glib_generator::type_name (t_type* ttype, bool in_typedef, bool is_const) {
-  (void) in_typedef;
-  if (ttype->is_base_type()) {
-    string bname = base_type_name ((t_base_type *) ttype);
-
-    if (is_const) {
-      return "const " + bname;
-    } else {
-      return bname;
-    }
-  }
-
-  if (ttype->is_container()) {
-    string cname;
-
-    t_container *tcontainer = (t_container *) ttype;
-    if (tcontainer->has_cpp_name()) {
-      cname = tcontainer->get_cpp_name();
-    } else if (ttype->is_map()) {
-      cname = "GHashTable *";
-    } else if (ttype->is_set()) {
-      // since a set requires unique elements, use a GHashTable, and
-      // populate the keys and values with the same data, using keys for
-      // the actual writes and reads.
-      // TODO: discuss whether or not to implement TSet, THashSet or GHashSet
-      cname = "GHashTable *";
-    } else if (ttype->is_list()) {
-      // TODO: investigate other implementations besides GPtrArray
-      cname = "GPtrArray *";
-      t_type *etype = ((t_list *) ttype)->get_elem_type();
-      if (etype->is_base_type()) {
-        t_base_type::t_base tbase = ((t_base_type *) etype)->get_base();
-        switch (tbase) {
-          case t_base_type::TYPE_VOID:
-            throw "compiler error: cannot determine array type";
-          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:
-            cname = "GArray *";
-            break;
-          case t_base_type::TYPE_STRING:
-            break;
-          default:
-            throw "compiler error: no array info for type";
-        }
-      }
-    }
-
-    if (is_const) {
-      return "const " + cname;
-    } else {
-      return cname;
-    }
-  }
-
-  // check for a namespace
-  string pname = this->nspace + ttype->get_name();
-
-  if (is_complex_type (ttype)) {
-    pname += " *";
-  }
-
-  if (is_const) {
-    return "const " + pname;
-  } else {
-    return pname;
-  }
-}
-
-/**
- * Maps a Thrift primitive to a C primitive.
- */
-string t_c_glib_generator::base_type_name(t_base_type *type) {
-  t_base_type::t_base tbase = type->get_base();
-
-  switch (tbase) {
-    case t_base_type::TYPE_VOID:
-      return "void";
-    case t_base_type::TYPE_STRING:
-      if (type->is_binary()) {
-        return "GByteArray *";
-      } else {
-        return "gchar *";
-      }
-    case t_base_type::TYPE_BOOL:
-      return "gboolean";
-    case t_base_type::TYPE_BYTE:
-      return "gint8";
-    case t_base_type::TYPE_I16:
-      return "gint16";
-    case t_base_type::TYPE_I32:
-      return "gint32";
-    case t_base_type::TYPE_I64:
-      return "gint64";
-    case t_base_type::TYPE_DOUBLE:
-      return "gdouble";
-    default:
-      throw "compiler error: no C base type name for base type "
-            + t_base_type::t_base_name (tbase);
-  }
-}
-
-/**
- * Returns a member of the ThriftType C enumeration in thrift_protocol.h
- * for a Thrift type.
- */
-string t_c_glib_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 "T_STRING";
-      case t_base_type::TYPE_BOOL:
-        return "T_BOOL";
-      case t_base_type::TYPE_BYTE:
-        return "T_BYTE";
-      case t_base_type::TYPE_I16:
-        return "T_I16";
-      case t_base_type::TYPE_I32:
-        return "T_I32";
-      case t_base_type::TYPE_I64:
-        return "T_I64";
-      case t_base_type::TYPE_DOUBLE:
-        return "T_DOUBLE";
-    }
-  } else if (type->is_enum()) {
-    return "T_I32";
-  } else if (type->is_struct()) {
-    return "T_STRUCT";
-  } else if (type->is_xception()) {
-    return "T_STRUCT";
-  } else if (type->is_map()) {
-    return "T_MAP";
-  } else if (type->is_set()) {
-    return "T_SET";
-  } else if (type->is_list()) {
-    return "T_LIST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-
-/**
- * Returns C code that represents a Thrift constant.
- */
-string t_c_glib_generator::constant_value(string name, t_type *type, t_const_value *value) {
-  ostringstream render;
-
-  if (type->is_base_type()) {
-    /* primitives */
-    t_base_type::t_base tbase = ((t_base_type *) type)->get_base();
-    switch (tbase) {
-      case t_base_type::TYPE_STRING:
-        render << "g_strdup (\"" + value->get_string() + "\")";
-        break;
-      case t_base_type::TYPE_BOOL:
-        render << ((value->get_integer() != 0) ? 1 : 0);
-        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:
-        render << value->get_integer();
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        if (value->get_type() == t_const_value::CV_INTEGER) {
-          render << value->get_integer();
-        } else {
-          render << 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()) {
-    render << "(" << type_name (type) << ")" << value->get_integer();
-  } else if (type->is_struct() || type->is_xception() || type->is_list()
-             || type->is_set() || type->is_map()) {
-    render << "(" << this->nspace_lc <<
-      to_lower_case(name) << "_constant())";
-  } else {
-    render << "NULL /* not supported */";
-  }
-
-  return render.str();
-}
-
-/**
- * Renders a function signature of the form 'type name(args)'
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_c_glib_generator::function_signature(t_function* tfunction) {
-  t_type* ttype = tfunction->get_returntype();
-  t_struct* arglist = tfunction->get_arglist();
-  t_struct* xlist = tfunction->get_xceptions();
-  string fname = initial_caps_to_underscores(tfunction->get_name());
-
-  bool has_return = !ttype->is_void();
-  bool has_args = arglist->get_members().size() == 0;
-  bool has_xceptions = xlist->get_members().size() == 0;
-  return
-    "gboolean " + this->nspace_lc + fname + " (" + this->nspace
-    + service_name_ + "If * iface"
-    + (has_return ? ", " + type_name(ttype) + "* _return" : "")
-    + (has_args ? "" : (", " + argument_list (arglist))) 
-    + (has_xceptions ? "" : (", " + xception_list (xlist)))
-    + ", GError ** error)";
-}
-
-/**
- * Renders a field list
- *
- * @param tstruct The struct definition
- * @return Comma sepearated list of all field names in that struct
- */
-string t_c_glib_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 += type_name((*f_iter)->get_type(), false, true) + " " +
-              (*f_iter)->get_name();
-  }
-  return result;
-}
-
-/**
- * Renders mutable exception lists
- *
- * @param tstruct The struct definition
- * @return Comma sepearated list of all field names in that struct
- */
-string t_c_glib_generator::xception_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 += type_name((*f_iter)->get_type(), false, false) + "* " +
-              (*f_iter)->get_name();
-  }
-  return result;
-}
-
-
-/**
- * Declares a field, including any necessary initialization.
- */
-string t_c_glib_generator::declare_field(t_field *tfield,
-                                         bool init,
-                                         bool pointer,
-                                         bool constant,
-                                         bool reference) {
-  string result = "";
-  if (constant) {
-    result += "const ";
-  }
-  result += type_name(tfield->get_type());
-  if (pointer) {
-    result += "*";
-  }
-  if (reference) {
-    result += "*";
-  }
-  result += " " + tfield->get_name();
-  if (init) {
-    t_type* type = get_true_type(tfield->get_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:
-          break;
-        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:
-          result += " = 0";
-          break;
-        case t_base_type::TYPE_DOUBLE:
-          result += " = (gdouble) 0";
-          break;
-        case t_base_type::TYPE_STRING:
-          result += " = NULL";
-          break;
-        default:
-          throw "compiler error: no C intializer for base type "
-                + t_base_type::t_base_name (tbase);
-      }
-    } else if (type->is_enum()) {
-      result += " = (" + type_name (type) + ") 0";
-    } else if (type->is_struct() || type->is_container()) {
-      result += " = NULL";
-    }
-  }
-
-  if (!reference) {
-    result += ";";
-  }
-
-  return result;
-}
-
-/**
- * Generates C code that initializes complex constants.
- */
-void t_c_glib_generator::generate_const_initializer(string name, t_type *type, t_const_value *value) {
-  string name_u = initial_caps_to_underscores(name);
-  string name_lc = to_lower_case(name_u);
-  string type_u = initial_caps_to_underscores(type->get_name());
-  string type_uc = to_upper_case(type_u);
-
-  if (type->is_struct() || type->is_xception()) {
-    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;
-    ostringstream initializers;
-
-    // initialize any constants that may be referenced by this initializer
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      t_type *field_type = NULL;
-      string field_name = "";
-
-      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();
-          field_name = (*f_iter)->get_name();
-        }
-      }
-      if (field_type == NULL) {
-        throw "type error: " + type->get_name() + " has no field "
-              + v_iter->first->get_string();
-      }
-      field_name = tmp (field_name);
-
-      generate_const_initializer (name + "_constant_" + field_name,
-                                  field_type, v_iter->second);
-      initializers <<
-        "    constant->" << v_iter->first->get_string() << " = " <<
-        constant_value (name + "_constant_" + field_name,
-                        field_type, v_iter->second) << ";" << endl <<
-        "    constant->__isset_" << v_iter->first->get_string() <<
-        " = TRUE;" << endl;
-    }
-
-    // implement the initializer
-    f_types_impl_ <<
-      "static " << this->nspace << type->get_name() << " *" << endl <<
-      this->nspace_lc << name_lc << "_constant (void)" << endl <<
-      "{" << endl <<
-      "  static " << this->nspace << type->get_name() <<
-          " *constant = NULL;" << endl <<
-      "  if (constant == NULL)" << endl <<
-      "  {" << endl <<
-      "    constant = g_object_new (" << this->nspace_uc << "TYPE_" <<
-          type_uc << ", NULL);" << endl <<
-      initializers.str() << endl <<
-      "  }" << endl <<
-      "  return constant;" << endl <<
-      "}" << endl <<
-      endl;
-  } else if (type->is_list()) {
-    string list_type = "GPtrArray *";
-    // TODO: This initialization should contain a free function for container
-    string list_initializer = "g_ptr_array_new();";
-    string list_appender = "g_ptr_array_add";
-    bool list_variable = false;
-
-    t_type* etype = ((t_list*)type)->get_elem_type();
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    ostringstream initializers;
-
-    list_initializer = generate_new_array_from_type (etype);
-    if (etype->is_base_type()) {
-      t_base_type::t_base tbase = ((t_base_type *) etype)->get_base();
-      switch (tbase) {
-        case t_base_type::TYPE_VOID:
-          throw "compiler error: cannot determine array type";
-        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:
-          list_type = "GArray *";
-          list_appender = "g_array_append_val";
-          list_variable = true;
-          break;
-        case t_base_type::TYPE_STRING:
-          break;
-        default:
-          throw "compiler error: no array info for type";
-      }
-    }
-
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string fname = tmp (name);
-
-      generate_const_initializer (fname, etype, (*v_iter));
-      if (list_variable) {
-        initializers <<
-          "    " << type_name (etype) << " " << fname << " = " <<
-            constant_value (fname, (t_type *) etype, (*v_iter)) << ";" <<
-                endl <<
-          "    " << list_appender << "(constant, " << fname << ");" << endl;
-      } else {
-        initializers <<
-          "    " << list_appender << "(constant, " <<
-          constant_value (fname, (t_type *) etype, (*v_iter)) << ");" << endl;
-      }
-    }
-
-    f_types_impl_ <<
-      "static " << list_type << endl <<
-      this->nspace_lc << name_lc << "_constant (void)" << endl <<
-      "{" << endl <<
-      "  static " << list_type << " constant = NULL;" << endl <<
-      "  if (constant == NULL)" << endl <<
-      "  {" << endl <<
-      "    constant = " << list_initializer << endl <<
-      initializers.str() << endl <<
-      "  }" << endl <<
-      "  return constant;" << endl <<
-      "}" << endl <<
-    endl;
-  } else if (type->is_set()) {
-    t_type *etype = ((t_set *) type)->get_elem_type();
-    const vector<t_const_value *>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    ostringstream initializers;
-
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string fname = tmp (name);
-      generate_const_initializer (fname, etype, (*v_iter));
-      initializers <<
-        "    " << type_name (etype) << " " << fname << " = " <<
-          constant_value (fname, (t_type *) etype, (*v_iter)) << ";" << endl <<
-        "    g_hash_table_insert (constant, &" << fname << ", &" << fname <<
-        ");" << endl;
-    }
-
-    f_types_impl_ <<
-      "static GHashTable *" << endl <<
-      this->nspace_lc << name_lc << "_constant (void)" << endl <<
-      "{" << endl <<
-      "  static GHashTable *constant = NULL;" << endl <<
-      "  if (constant == NULL)" << endl <<
-      "  {" << endl <<
-      // TODO: This initialization should contain a free function for elements
-      "    constant = g_hash_table_new (NULL, NULL);" << endl <<
-      initializers.str() << endl <<
-      "  }" << endl <<
-      "  return constant;" << endl <<
-      "}" << endl <<
-    endl; 
-  } else if (type->is_map()) {
-    t_type *ktype = ((t_map *) type)->get_key_type();
-    t_type *vtype = ((t_map *) type)->get_val_type();
-    const vector<t_const_value *>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    ostringstream initializers;
-
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string fname = tmp (name);
-      string kname = fname + "key";
-      string vname = fname + "val";
-      generate_const_initializer (kname, ktype, (*v_iter));
-      generate_const_initializer (vname, vtype, (*v_iter));
-
-      initializers <<
-        "    " << type_name (ktype) << " " << kname << " = " <<
-          constant_value (kname, (t_type *) ktype, (*v_iter)) << ";" << endl <<
-        "    " << type_name (vtype) << " " << vname << " = " <<
-          constant_value (vname, (t_type *) vtype, (*v_iter)) << ";" << endl <<
-        "    g_hash_table_insert (constant, &" << fname << ", &" << fname <<
-        ");" << endl;
-    }
-
-    f_types_impl_ <<
-      "static GHashTable *" << endl <<
-      this->nspace_lc << name_lc << "_constant (void)" << endl <<
-      "{" << endl <<
-      "  static GHashTable *constant = NULL;" << endl <<
-      "  if (constant == NULL)" << endl <<
-      "  {" << endl <<
-      // TODO: This initialization should contain a free function for elements
-      "    constant = g_hash_table_new (NULL, NULL);" << endl <<
-      initializers.str() << endl <<
-      "  }" << endl <<
-      "  return constant;" << endl <<
-      "}" << endl <<
-    endl;
-  }
-}
-
-/**
- * Generates C code that represents a Thrift service client.
- */
-void t_c_glib_generator::generate_service_client(t_service *tservice) {
-  /* get some C friendly service names */
-  string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_));
-  string service_name_uc = to_upper_case(service_name_lc);
-
-  // Generate the client interface dummy object in the header.
-  f_header_ <<
-    "/* " << service_name_ << " service interface */" << endl <<
-    "typedef struct _" << this->nspace << service_name_ << "If " <<
-        this->nspace << service_name_ << "If; " <<
-        " /* dummy object */" << endl <<
-    endl;
-
-  // Generate the client interface object in the header.
-  f_header_ <<
-    "struct _" << this->nspace << service_name_ << "IfInterface" << endl <<
-    "{" << endl <<
-    "  GTypeInterface parent;" << endl <<
-  endl;
-
-  /* write out the functions for this interface */
-  indent_up();
-  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) {
-    /* make the function name C friendly */
-    string funname = initial_caps_to_underscores((*f_iter)->get_name());
-    t_type *ttype = (*f_iter)->get_returntype();
-    t_struct *arglist = (*f_iter)->get_arglist();
-    t_struct *xlist = (*f_iter)->get_xceptions();
-    bool has_return = !ttype->is_void();
-    bool has_args = arglist->get_members().size() == 0;
-    bool has_xceptions = xlist->get_members().size() == 0;
-
-    string params = "(" + this->nspace + service_name_ + "If *iface"
-                    + (has_return ? ", " + type_name (ttype) + "* _return" : "")
-                    + (has_args ? "" : (", " + argument_list (arglist)))
-                    + (has_xceptions ? "" : (", " + xception_list (xlist)))
-                    + ", GError **error)";
-                    
-    indent(f_header_) << "gboolean (*" << funname << ") " << params << ";" <<
-                          endl;
-  }
-  indent_down();
-
-  f_header_ <<
-    "};" << endl <<
-    "typedef struct _" << this->nspace << service_name_ << "IfInterface " <<
-        this->nspace << service_name_ << "IfInterface;" << endl <<
-    endl;
-
-  // generate all the interface boilerplate
-  f_header_ <<
-    "GType " << this->nspace_lc << service_name_lc <<
-        "_if_get_type (void);" << endl <<
-    "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_IF " <<
-        "(" << this->nspace_lc << service_name_lc << "_if_get_type())" <<
-        endl <<
-    "#define " << this->nspace_uc << service_name_uc << "_IF(obj) " <<
-        "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " <<
-        this->nspace_uc << "TYPE_" << service_name_uc << "_IF, " <<
-        this->nspace << service_name_ << "If))" << endl <<
-    "#define " << this->nspace_uc << "IS_" << service_name_uc << "_IF(obj) " <<
-        "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " <<
-        this->nspace_uc << "TYPE_" << service_name_uc << "_IF))" << endl <<
-    "#define " << this->nspace_uc << service_name_uc <<
-        "_IF_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), " <<
-        this->nspace_uc << "TYPE_" << service_name_uc << "_IF, " <<
-        this->nspace << service_name_ << "IfInterface))" << endl <<
-    endl;
-
-  // write out all the interface function prototypes
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    /* make the function name C friendly */
-    string funname = initial_caps_to_underscores((*f_iter)->get_name());
-    t_type *ttype = (*f_iter)->get_returntype();
-    t_struct *arglist = (*f_iter)->get_arglist();
-    t_struct *xlist = (*f_iter)->get_xceptions();
-    bool has_return = !ttype->is_void();
-    bool has_args = arglist->get_members().size() == 0;
-    bool has_xceptions = xlist->get_members().size() == 0;
-
-    string params = "(" + this->nspace + service_name_ + "If *iface"
-                    + (has_return ? ", " + type_name (ttype) + "* _return" : "")
-                    + (has_args ? "" : (", " + argument_list (arglist)))
-                    + (has_xceptions ? "" : (", " + xception_list (xlist)))
-                    + ", GError **error)";
-
-    f_header_ << "gboolean " << this->nspace_lc << service_name_lc <<
-                 "_if_" << funname << " " << params << ";" << endl;
-  }
-  f_header_ << endl;
-
-  // Generate the client object instance definition in the header.
-  f_header_ <<
-    "/* " << service_name_ << " service client */" << endl <<
-    "struct _" << this->nspace << service_name_ << "Client" << endl <<
-    "{" << endl <<
-    "  GObject parent;" << endl <<
-    endl <<
-    "  ThriftProtocol *input_protocol;" << endl <<
-    "  ThriftProtocol *output_protocol;" << endl <<
-    "};" << endl <<
-    "typedef struct _" << this->nspace << service_name_ << "Client " <<
-      this->nspace << service_name_ << "Client;" << endl <<
-    endl;
-
-  // Generate the class definition in the header.
-  f_header_ <<
-    "struct _" << this->nspace << service_name_ << "ClientClass" << endl <<
-    "{" << endl <<
-    "  GObjectClass parent;" << endl <<
-    "};" << endl <<
-    "typedef struct _" << this->nspace << service_name_ << "ClientClass " <<
-      this->nspace << service_name_ << "ClientClass;" << endl <<
-    endl;
-
-  // Create all the GObject boilerplate
-  f_header_ <<
-    "GType " << this->nspace_lc << service_name_lc << 
-        "_client_get_type (void);" << endl <<
-    "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT " <<
-        "(" << this->nspace_lc << service_name_lc << "_client_get_type())" <<
-        endl <<
-    "#define " << this->nspace_uc << service_name_uc << "_CLIENT(obj) " <<
-        "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << 
-        this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT, " << 
-        this->nspace << service_name_ << "Client))" << endl <<
-    "#define " << this->nspace_uc << service_name_uc << "_CLIENT_CLASS(c) " << 
-        "(G_TYPE_CHECK_CLASS_CAST ((c), " << 
-        this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT, " << 
-        this->nspace << service_name_ << "ClientClass))" << endl <<
-    "#define " << this->nspace_uc << service_name_uc << "_IS_CLIENT(obj) " <<
-        "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << 
-        this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT))" << endl << 
-    "#define " << this->nspace_uc << service_name_uc <<
-        "_IS_CLIENT_CLASS(c) " << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << 
-        this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT))" << endl <<
-    "#define " << this->nspace_uc << service_name_uc <<
-        "_CLIENT_GET_CLASS(obj) " << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << 
-        this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT, " <<
-        this->nspace << service_name_ << "ClientClass))" << endl << 
-    endl;
-
-  /* write out the function prototypes */
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    /* make the function name C friendly */
-    string funname = to_lower_case(initial_caps_to_underscores((*f_iter)->get_name()));
-
-    t_function service_function ((*f_iter)->get_returntype(),
-                                 service_name_lc + string ("_client_")
-                                 + funname,
-                                 (*f_iter)->get_arglist(),
-                                 (*f_iter)->get_xceptions());
-    indent(f_header_) << function_signature (&service_function) << ";" << endl;
-
-    t_function send_function (g_type_void,
-                              service_name_lc + string ("_client_send_")
-                              + funname,
-                              (*f_iter)->get_arglist());
-    indent(f_header_) << function_signature (&send_function) << ";" << endl;
-
-    // implement recv if not a oneway service
-    if (!(*f_iter)->is_oneway()) {
-      t_struct noargs (program_);
-      t_function recv_function ((*f_iter)->get_returntype(),
-                                service_name_lc + string ("_client_recv_") 
-                                + funname,
-                                &noargs,
-                                (*f_iter)->get_xceptions());
-      indent(f_header_) << function_signature (&recv_function) << ";" << endl;
-    }
-  }
-
-  /* write out the get/set function prototypes */
-  f_header_ << "void " + service_name_lc + "_client_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);" << endl;
-  f_header_ << "void " + service_name_lc + "_client_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);" << endl;
-
-  f_header_ << endl;
-  // end of header code
-
-  // Generate interface method implementations
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    /* make the function name C friendly */
-    string funname = initial_caps_to_underscores((*f_iter)->get_name());
-    t_type *ttype = (*f_iter)->get_returntype();
-    t_struct *arglist = (*f_iter)->get_arglist();
-    t_struct *xlist = (*f_iter)->get_xceptions();
-    bool has_return = !ttype->is_void();
-    bool has_args = arglist->get_members().size() == 0;
-    bool has_xceptions = xlist->get_members().size() == 0;
-
-    string params = "(" + this->nspace + service_name_ + "If *iface"
-                    + (has_return ? ", " + type_name (ttype) + "* _return" : "")
-                    + (has_args ? "" : (", " + argument_list (arglist)))
-                    + (has_xceptions ? "" : (", " + xception_list (xlist)))
-                    + ", GError **error)";
-
-    string params_without_type = string("iface, ")
-                                 + (has_return ? "_return, " : "");
-
-    const vector<t_field *>& fields = arglist->get_members();
-    vector<t_field *>::const_iterator f_iter_field;
-    for (f_iter_field = fields.begin(); f_iter_field != fields.end(); ++f_iter_field) {
-      params_without_type += (*f_iter_field)->get_name(); 
-      params_without_type += ", ";
-    }
-
-    const vector<t_field *>& xceptions = xlist->get_members();
-    vector<t_field *>::const_iterator x_iter;
-    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      params_without_type += (*x_iter)->get_name();
-      params_without_type += ", ";
-    }
-
-    f_service_ <<
-      "gboolean" << endl <<
-      this->nspace_lc << service_name_lc << "_if_" << funname << " " <<
-          params << endl <<
-      "{" << endl << 
-      "  return " << this->nspace_uc << service_name_uc <<
-          "_IF_GET_INTERFACE (iface)->" << funname << " (" <<
-          params_without_type << "error);" << endl <<
-      "}" << endl <<
-      endl;
-  }
-
-  // Generate interface boilerplate
-  f_service_ <<
-    "GType" << endl <<
-    this->nspace_lc << service_name_lc << "_if_get_type (void)" << endl <<
-    "{" << endl <<
-    "  static GType type = 0;" << endl <<
-    "  if (type == 0)" << endl <<
-    "  {" << endl <<
-    "    static const GTypeInfo type_info =" << endl <<
-    "    {" << endl <<
-    "      sizeof (" << this->nspace << service_name_ << "IfInterface)," <<
-        endl <<
-    "      NULL,  /* base_init */" << endl <<
-    "      NULL,  /* base_finalize */" << endl <<
-    "      NULL,  /* class_init */" << endl <<
-    "      NULL,  /* class_finalize */" << endl <<
-    "      NULL,  /* class_data */" << endl <<
-    "      0,     /* instance_size */" << endl <<
-    "      0,     /* n_preallocs */" << endl <<
-    "      NULL,  /* instance_init */" << endl <<
-    "      NULL   /* value_table */" << endl <<
-    "    };" << endl <<
-    "    type = g_type_register_static (G_TYPE_INTERFACE," << endl <<
-    "                                   \"" << this->nspace << service_name_ <<
-        "If\"," << endl <<
-    "                                   &type_info, 0);" << endl <<
-    "  }" << endl <<
-    "  return type;" << endl <<
-    "}" << endl <<
-    endl;
-
-  // Generate client boilerplate
-  f_service_ <<
-    "static void " << endl <<
-    this->nspace_lc << service_name_lc <<
-        "_if_interface_init (" << this->nspace << service_name_ <<
-        "IfInterface *iface);" << endl <<
-    endl <<
-    "G_DEFINE_TYPE_WITH_CODE (" << this->nspace << service_name_ <<
-      "Client, " << this->nspace_lc << service_name_lc << "_client," << endl <<
-      "                       G_TYPE_OBJECT, " << endl <<
-    "                         G_IMPLEMENT_INTERFACE (" <<
-        this->nspace_uc << "TYPE_" << service_name_uc << "_IF," << endl <<
-    "                                                " <<
-        this->nspace_lc << service_name_lc << "_if_interface_init));" << endl <<
-    endl;
-
-  // Generate client properties
-  f_service_ <<
-    "enum _" << this->nspace << service_name_ << "ClientProperties" << endl <<
-    "{" << endl <<
-    "  PROP_0," << endl <<
-    "  PROP_" << this->nspace_uc << service_name_uc <<
-        "_CLIENT_INPUT_PROTOCOL," <<
-        endl <<
-    "  PROP_" << this->nspace_uc << service_name_uc <<
-        "_CLIENT_OUTPUT_PROTOCOL" <<
-        endl <<
-    "};" << endl <<
-  endl;
-
-  // generate property setter
-  f_service_ <<
-    "void" << endl <<
-    this->nspace_lc << service_name_lc << "_client_set_property (" <<
-        "GObject *object, guint property_id, const GValue *value, " <<
-        "GParamSpec *pspec)" << endl <<
-    "{" << endl <<
-    "  " << this->nspace << service_name_ << "Client *client = " <<
-        this->nspace_uc << service_name_uc << "_CLIENT (object);" << endl <<
-    endl <<
-    "  THRIFT_UNUSED_VAR (pspec);" << endl <<
-    endl <<
-    "  switch (property_id)" << endl <<
-    "  {" << endl <<
-    "    case PROP_" << this->nspace_uc << service_name_uc <<
-        "_CLIENT_INPUT_PROTOCOL:" << endl <<
-    "      client->input_protocol = g_value_get_object (value);" << endl <<
-    "      break;" << endl <<
-    "    case PROP_" << this->nspace_uc << service_name_uc <<
-        "_CLIENT_OUTPUT_PROTOCOL:" << endl <<
-    "      client->output_protocol = g_value_get_object (value);" << endl <<
-    "      break;" << endl <<
-    "  }" << endl <<
-    "}" << endl <<
-  endl;
-
-  // generate property getter
-  f_service_ <<
-    "void" << endl <<
-    this->nspace_lc << service_name_lc << "_client_get_property (" <<
-        "GObject *object, guint property_id, GValue *value, " <<
-        "GParamSpec *pspec)" << endl <<
-    "{" << endl <<
-    "  " << this->nspace << service_name_ << "Client *client = " <<
-        this->nspace_uc << service_name_uc << "_CLIENT (object);" << endl <<
-    endl <<
-    "  THRIFT_UNUSED_VAR (pspec);" << endl <<
-    endl <<
-    "  switch (property_id)" << endl <<
-    "  {" << endl <<
-    "    case PROP_" << this->nspace_uc << service_name_uc <<
-        "_CLIENT_INPUT_PROTOCOL:" << endl <<
-    "      g_value_set_object (value, client->input_protocol);" << endl <<
-    "      break;" << endl <<
-    "    case PROP_" << this->nspace_uc << service_name_uc <<
-        "_CLIENT_OUTPUT_PROTOCOL:" << endl <<
-    "      g_value_set_object (value, client->output_protocol);" << endl <<
-    "      break;" << endl <<
-    "  }" << endl <<
-    "}" << endl <<
-  endl;
-
-
-  // Generate client method implementations
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    string name = (*f_iter)->get_name();
-    string funname = initial_caps_to_underscores(name);
-
-    // Get the struct of function call params and exceptions
-    t_struct* arg_struct = (*f_iter)->get_arglist();
-
-    // Function for sending
-    t_function send_function (g_type_void,
-                              service_name_lc + string ("_client_send_")
-                              + funname,
-                              (*f_iter)->get_arglist());
-
-    // Open the send function
-    indent(f_service_) <<
-      function_signature (&send_function) << endl;
-    scope_up(f_service_);
-
-    // Serialize the request
-    f_service_ <<
-      indent() << "gint32 cseqid = 0;" << endl <<
-      indent() << "ThriftProtocol * protocol = " << 
-        this->nspace_uc << service_name_uc << 
-        "_CLIENT (iface)->output_protocol;" << endl <<
-      endl <<
-      indent() << "if (thrift_protocol_write_message_begin (protocol, \"" <<
-        name << "\", T_CALL, cseqid, error) < 0)" << endl <<
-      indent() << "  return FALSE;" << endl <<
-      endl;
-
-    generate_struct_writer (f_service_, arg_struct, "", "", false);
-
-    f_service_ <<
-      indent() <<
-        "if (thrift_protocol_write_message_end (protocol, error) < 0)" <<
-        endl <<
-      indent() <<
-        "  return FALSE;" << endl <<
-      indent() <<
-        "if (!thrift_transport_flush (protocol->transport, error))" << endl <<
-      indent() <<
-        "  return FALSE;" << endl <<
-      indent() <<
-        "if (!thrift_transport_write_end (protocol->transport, error))" <<
-        endl <<
-      indent() <<
-        "  return FALSE;" << endl <<
-      endl <<
-      indent() << 
-        "return TRUE;" << endl;
-
-    scope_down(f_service_);
-    f_service_ << endl;
-
-    // Generate recv function only if not an async function
-    if (!(*f_iter)->is_oneway()) {
-      t_struct noargs (program_);
-      t_function recv_function ((*f_iter)->get_returntype(),
-                                service_name_lc
-                                + string ("_client_recv_") + funname, &noargs,
-                                (*f_iter)->get_xceptions());
-      // Open function
-      indent(f_service_) <<
-        function_signature (&recv_function) << endl;
-      scope_up(f_service_);
-
-      f_service_ << endl <<
-        indent() << "gint32 rseqid;" << endl <<
-        indent() << "gchar * fname;" << endl <<
-        indent() << "ThriftMessageType mtype;" << endl <<
-        indent() << "ThriftProtocol * protocol = " << 
-                      this->nspace_uc << service_name_uc <<
-                      "_CLIENT (iface)->input_protocol;" << endl <<
-        endl <<
-        indent() << "if (thrift_protocol_read_message_begin " << 
-                      "(protocol, &fname, &mtype, &rseqid, error) < 0)" <<
-                      endl <<
-        indent() << "{" << endl <<
-        indent() << "  if (fname) g_free (fname);" << endl <<
-        indent() << "  return FALSE;" << endl <<
-        indent() << "}" << endl <<
-        endl <<
-        indent() << "if (mtype == T_EXCEPTION) {" << endl <<
-        indent() << "  if (fname) g_free (fname);" << endl <<
-        indent() << "  ThriftApplicationException *xception = g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION, NULL);" << endl <<
-
-        indent() << "  thrift_struct_read (THRIFT_STRUCT (xception), protocol, NULL);" << endl <<
-        indent() << "  thrift_protocol_read_message_end (protocol, NULL);" << endl <<
-        indent() << "  thrift_transport_read_end (protocol->transport, NULL);" << endl <<
-        indent() << "  g_set_error (error, THRIFT_APPLICATION_EXCEPTION_ERROR, xception->type, \"application error: %s\", xception->message);" << endl <<
-        indent() << "  g_object_unref (xception);" << endl <<
-        indent() << "  return FALSE;" << endl <<
-        indent() << "} else if (mtype != T_REPLY) {" << endl <<
-        indent() << "  if (fname) g_free (fname);" << endl <<
-        indent() << "  thrift_protocol_skip (protocol, T_STRUCT, NULL);" << endl <<
-        indent() << "  thrift_protocol_read_message_end (protocol, NULL);" << endl <<
-        indent() << "  thrift_transport_read_end (protocol->transport, NULL);" << endl << 
-        indent() << "  g_set_error (error, THRIFT_APPLICATION_EXCEPTION_ERROR, THRIFT_APPLICATION_EXCEPTION_ERROR_INVALID_MESSAGE_TYPE, \"invalid message type %d, expected T_REPLY\", mtype);" << endl <<
-        indent() << "  return FALSE;" << endl <<
-        indent() << "} else if (strncmp (fname, \"" << name << "\", " << name.length() << ") != 0) {" << endl <<
-        indent() << "  thrift_protocol_skip (protocol, T_STRUCT, NULL);" << endl <<
-        indent() << "  thrift_protocol_read_message_end (protocol, error);" << endl <<
-        indent() << "  thrift_transport_read_end (protocol->transport, error);" << endl <<
-        indent() << "  g_set_error (error, THRIFT_APPLICATION_EXCEPTION_ERROR, THRIFT_APPLICATION_EXCEPTION_ERROR_WRONG_METHOD_NAME, \"wrong method name %s, expected " << name << "\", fname);" << endl <<
-        indent() << "  if (fname) g_free (fname);" << endl <<
-        indent() << "  return FALSE;" << endl <<
-        indent() << "}" << endl <<
-        indent() << "if (fname) g_free (fname);" << endl << 
-        endl;
-
-      t_struct* xs = (*f_iter)->get_xceptions();
-      const std::vector<t_field*>& xceptions = xs->get_members();
-      vector<t_field*>::const_iterator x_iter;
-
-      {
-        t_struct result(program_, tservice->get_name() + "_" + 
-                        (*f_iter)->get_name() + "_result");
-        t_field success((*f_iter)->get_returntype(), "*_return", 0);
-        if (!(*f_iter)->get_returntype()->is_void()) {
-          result.append(&success);
-        }
-
-        // add readers for exceptions, dereferencing the pointer.
-        for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) {
-          t_field *xception = new t_field((*x_iter)->get_type(),
-                                          "*" + (*x_iter)->get_name(),
-                                          (*x_iter)->get_key());
-          result.append (xception);
-        }
-
-        generate_struct_reader (f_service_, &result, "", "", false);
-      }
-
-      f_service_ <<
-        indent() << "if (thrift_protocol_read_message_end (protocol, error) < 0)" << endl <<
-        indent() << "  return FALSE;" << endl <<
-        endl <<
-        indent() << "if (!thrift_transport_read_end (protocol->transport, error))" << endl <<
-        indent() << "  return FALSE;" << endl <<
-        endl;
-
-      // copy over any throw exceptions and return failure
-      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) {
-        f_service_ << 
-          indent() << "if (*" << (*x_iter)->get_name() << " != NULL)" << endl <<
-          indent() << "{" << endl <<
-          indent() << "    g_set_error (error, " << this->nspace_uc <<
-              to_upper_case(initial_caps_to_underscores(
-                                 (*x_iter)->get_type()->get_name())) <<
-              "_ERROR, " <<
-              this->nspace_uc <<
-              to_upper_case(initial_caps_to_underscores(
-                                 (*x_iter)->get_type()->get_name())) <<
-              "_ERROR_CODE, \"" << (*x_iter)->get_type()->get_name() << 
-              "\");" << endl <<
-          indent() << "    return FALSE;" << endl <<
-          indent() << "}" << endl;
-      }
-      // Close function
-      indent(f_service_) << "return TRUE;" << endl;
-      scope_down(f_service_);
-      f_service_ << endl;
-    }
-
-    // Open function
-    t_function service_function((*f_iter)->get_returntype(),
-                                 service_name_lc
-                                 + string ("_client_") + funname,
-                                 (*f_iter)->get_arglist(),
-                                 (*f_iter)->get_xceptions());
-    indent(f_service_) <<
-      function_signature (&service_function) << endl;
-    scope_up(f_service_);
-
-    // wrap each function
-    f_service_ <<
-      indent() << "if (!" << this->nspace_lc << service_name_lc <<
-                   "_client_send_" << funname <<
-      " (iface";
-
-    // Declare the function arguments
-    const vector<t_field *> &fields = arg_struct->get_members();
-    vector<t_field *>::const_iterator fld_iter;
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      f_service_ << ", " << (*fld_iter)->get_name();
-    }
-    f_service_ << ", error))" << endl <<
-      indent() << "  return FALSE;" << endl;
-
-    // if not oneway, implement recv
-    if (!(*f_iter)->is_oneway()) {
-      string ret = (*f_iter)->get_returntype()->is_void() ? "" : "_return, ";
-
-      const vector<t_field *>& xceptions =
-          (*f_iter)->get_xceptions()->get_members();
-      vector<t_field *>::const_iterator x_iter;
-      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-        ret += (*x_iter)->get_name();
-        ret += ", ";
-      }
-
-      f_service_ <<
-        indent() << "if (!" << this->nspace_lc << service_name_lc <<
-          "_client_recv_" << funname <<
-          " (iface, " << ret << "error))" << endl <<
-        indent() << "  return FALSE;" << endl;
-    }
-
-    // return TRUE which means all functions were called OK
-    indent(f_service_) << "return TRUE;" << endl;
-    scope_down(f_service_);
-    f_service_ << endl;
-  }
-
-  // create the interface initializer
-  f_service_ <<
-    "static void" << endl <<
-    this->nspace_lc << service_name_lc << "_if_interface_init (" <<
-        this->nspace << service_name_ << "IfInterface *iface)" << endl <<
-    "{" << endl;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    /* make the function name C friendly */
-    string funname = initial_caps_to_underscores((*f_iter)->get_name());
-
-    f_service_ <<
-      "  iface->" << funname << " = " << this->nspace_lc << service_name_lc <<
-        "_client_" << funname << ";" << endl;
-  }
-  f_service_ <<
-    "}" << endl <<
-    endl;
-
-  // create the client instance initializer
-  f_service_ <<
-    "static void" << endl <<
-    this->nspace_lc << service_name_lc << "_client_init (" <<
-        this->nspace << service_name_ << "Client *client)" << endl <<
-    "{" << endl <<
-    "  client->input_protocol = NULL;" << endl <<
-    "  client->output_protocol = NULL;" << endl <<
-    "}" << endl <<
-    endl;
-
-  // create the client class initializer
-  f_service_ <<
-    "static void" << endl <<
-    this->nspace_lc << service_name_lc << "_client_class_init (" <<
-        this->nspace << service_name_ << "ClientClass *cls)" << endl <<
-    "{" << endl <<
-    "  GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl <<
-    "  GParamSpec *param_spec;" << endl <<
-    endl <<
-    "  gobject_class->set_property = " << this->nspace_lc <<
-        service_name_lc << "_client_set_property;" << endl <<
-    "  gobject_class->get_property = " << this->nspace_lc <<
-        service_name_lc << "_client_get_property;" << endl <<
-    endl <<
-    "  param_spec = g_param_spec_object (\"input_protocol\"," << endl <<
-    "                                    \"input protocol (construct)\"," <<
-        endl <<
-    "                                    \"Set the client input protocol\"," <<
-        endl <<
-    "                                    THRIFT_TYPE_PROTOCOL," << endl <<
-    "                                    G_PARAM_READWRITE);" << endl <<
-    "  g_object_class_install_property (gobject_class," << endl <<
-    "                                   PROP_" << this->nspace_uc <<
-        service_name_uc << "_CLIENT_INPUT_PROTOCOL, param_spec);" << endl <<
-    endl <<
-    "  param_spec = g_param_spec_object (\"output_protocol\"," << endl <<
-    "                                    \"output protocol (construct)\"," <<
-        endl <<
-    "                                    \"Set the client output protocol\"," <<
-        endl <<
-    "                                    THRIFT_TYPE_PROTOCOL," << endl <<
-    "                                    G_PARAM_READWRITE);" << endl <<
-    "  g_object_class_install_property (gobject_class," << endl <<
-    "                                   PROP_" << this->nspace_uc <<
-        service_name_uc << "_CLIENT_OUTPUT_PROTOCOL, param_spec);" << endl <<
-    "}" << endl <<
-    endl;
-}
-
-/**
- * Generates C code that represents a Thrift service server.
- */
-void t_c_glib_generator::generate_service_server (t_service *tservice) {
-  (void) tservice;
-  /* get some C friendly service names */
-  string service_name_u = initial_caps_to_underscores(service_name_);
-  string service_name_uc = to_upper_case(service_name_u);
-
-  // write the server object instance definition in the header.
-  // TODO: implement after implement TServer and TProcessor
-}
-
-/**
- * Generates C code to represent a THrift structure as a GObject.
- */
-void t_c_glib_generator::generate_object(t_struct *tstruct) {
-  string name = tstruct->get_name();
-  string name_u = initial_caps_to_underscores(name);
-  string name_uc = to_upper_case(name_u);
-
-  // write the instance definition
-  f_types_ <<
-    "struct _" << this->nspace << name << endl <<
-    "{ " << endl <<
-    "  ThriftStruct parent; " << endl <<
-    endl <<
-    "  /* public */" << endl;
-
-  // for each field, add a member variable
-  vector<t_field *>::const_iterator m_iter;
-  const vector<t_field *> &members = tstruct->get_members();
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type *t = get_true_type ((*m_iter)->get_type());
-    f_types_ <<
-      "  " << type_name (t) << " " << (*m_iter)->get_name() << ";" << endl;
-    if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
-      f_types_ <<
-        "  gboolean __isset_" << (*m_iter)->get_name() << ";" << endl;
-    }
-  }
-
-  // close the structure definition and create a typedef
-  f_types_ <<
-    "};" << endl <<
-    "typedef struct _" << this->nspace << name << " " << 
-        this->nspace << name << ";" << endl <<
-      endl;
-
-  // write the class definition
-  f_types_ <<
-    "struct _" << this->nspace << name << "Class" << endl <<
-    "{" << endl <<
-    "  ThriftStructClass parent;" << endl <<
-    "};" << endl <<
-    "typedef struct _" << this->nspace << name << "Class " << this->nspace << name << "Class;" << endl <<
-    endl;
-
-  // write the standard GObject boilerplate
-  f_types_ <<
-    "GType " << this->nspace_lc << name_u << "_get_type (void);" << endl <<
-    "#define " << this->nspace_uc << "TYPE_" << name_uc << " (" << this->nspace_lc << name_u << "_get_type())" << endl <<
-    "#define " << this->nspace_uc << name_uc << "(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" << name_uc << ", " << this->nspace << name << "))" << endl <<
-    "#define " << this->nspace_uc << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "_TYPE_" << name_uc << ", " << this->nspace << name << "Class))" << endl <<
-    "#define " << this->nspace_uc << "IS_" << name_uc << "(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_" << name_uc << "))" << endl <<
-    "#define " << this->nspace_uc << "IS_" << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << name_uc << "))" << endl <<
-    "#define " << this->nspace_uc << name_uc << "_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_" << name_uc << ", " << this->nspace << name << "Class))" << endl <<
-    endl;
-
-  // start writing the object implementation .c file
-  // generate struct I/O methods
-  string this_get = this->nspace + name + " * this_object = " 
-                    + this->nspace_uc + name_uc + "(object);";
-  generate_struct_reader (f_types_impl_, tstruct, "this_object->", this_get);
-  generate_struct_writer (f_types_impl_, tstruct, "this_object->", this_get);
-
-  // generate the instance init function
-  f_types_impl_ <<
-    "static void " << endl <<
-    this->nspace_lc << name_u << "_instance_init (" << this->nspace << name << " * object)" << endl <<
-    "{" << endl;
-
-  // satisfy compilers with -Wall turned on
-  indent_up();
-  indent(f_types_impl_) << "/* satisfy -Wall */" << endl <<
-               indent() << "THRIFT_UNUSED_VAR (object);" << endl;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* t = get_true_type ((*m_iter)->get_type());
-    if (t->is_base_type()) {
-      // only have init's for base types
-      string dval = " = ";
-      if (t->is_enum()) {
-        dval += "(" + type_name (t) + ")";
-      }
-      t_const_value* cv = (*m_iter)->get_value();
-      if (cv != NULL) {
-        dval += constant_value ("", t, cv);
-      } else {
-        dval += t->is_string() ? "NULL" : "0";
-      }
-      indent(f_types_impl_) << "object->" << (*m_iter)->get_name() << dval << ";" << endl;
-    } else if (t->is_struct()) {
-      string name = (*m_iter)->get_name();
-      string type_name_uc = to_upper_case
-        (initial_caps_to_underscores((*m_iter)->get_type()->get_name()));
-      indent(f_types_impl_) << "object->" << name << " = g_object_new (" << this->nspace_uc << "TYPE_" << type_name_uc << ", NULL);" << endl;
-    } else if (t->is_xception()) {
-      string name = (*m_iter)->get_name();
-      indent(f_types_impl_) << "object->" << name << " = NULL;" << endl;
-    } else if (t->is_container()) {
-      string name = (*m_iter)->get_name();
-      string init_function;
-
-      if (t->is_map()) {
-        t_type *key = ((t_map *) t)->get_key_type();
-        t_type *value = ((t_map *) t)->get_val_type();
-        init_function = generate_new_hash_from_type (key, value);
-      } else if (t->is_set()) {
-        t_type *etype = ((t_set *) t)->get_elem_type();
-        init_function = generate_new_hash_from_type (etype, NULL);
-      } else if (t->is_list()) {
-        t_type *etype = ((t_list *) t)->get_elem_type();
-        init_function = generate_new_array_from_type (etype);
-      }
-
-      indent(f_types_impl_) << "object->" << name << " = " <<
-                                  init_function << endl;
-
-    }
-
-    /* if not required, initialize the __isset variable */
-    if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
-      indent(f_types_impl_) << "object->__isset_" << (*m_iter)->get_name() << " = FALSE;" << endl;
-    }
-  }
-
-  indent_down();
-  f_types_impl_ << "}" << endl <<
-  endl;
-
-  /* create the destructor */
-  f_types_impl_ <<
-    "static void " << endl <<
-    this->nspace_lc << name_u << "_finalize (GObject *object)" << endl <<
-    "{" << endl;
-  indent_up();
-
-  f_types_impl_ <<
-    indent() <<
-    this->nspace << name << " *tobject = " << this->nspace_uc <<
-    name_uc << " (object);" << endl << endl;
-
-  f_types_impl_ <<
-    indent() << "/* satisfy -Wall in case we don't use tobject */" << endl <<
-    indent() << "THRIFT_UNUSED_VAR (tobject);" << endl;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* t = get_true_type ((*m_iter)->get_type());
-    if (t->is_container()) { 
-      string name = (*m_iter)->get_name();
-      if (t->is_map() || t->is_set()) {
-        f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl;
-        f_types_impl_ << indent() << "{" << endl;
-	indent_up();
-	f_types_impl_ <<
-	indent() << "g_hash_table_destroy (tobject->" << name << ");" << endl;
-	f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl;
-	indent_down();
-	f_types_impl_ << indent() << "}" << endl;
-      } else if (t->is_list()) {
-        t_type *etype = ((t_list *) t)->get_elem_type();
-        string destructor_function = "g_ptr_array_free";
-
-        if (etype->is_base_type()) {
-          t_base_type::t_base tbase = ((t_base_type *) etype)->get_base();
-          switch (tbase) {
-            case t_base_type::TYPE_VOID:
-              throw "compiler error: cannot determine array type";
-            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:
-              destructor_function = "g_array_free";
-              break;
-            case t_base_type::TYPE_STRING:
-              break;
-            default:
-              throw "compiler error: no array info for type";
-          }
-        }
-
-        f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl;
-        f_types_impl_ << indent() << "{" << endl;
-        indent_up();
-        f_types_impl_ <<
-          indent() << destructor_function << " (tobject->" << name <<
-                       ", TRUE);" << endl;
-        f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl;
-        indent_down();
-        f_types_impl_ << indent() << "}" << endl;
-      }
-    } else if (t->is_struct() || t->is_xception()) {
-      string name = (*m_iter)->get_name();
-      // TODO: g_clear_object needs glib >= 2.28
-      // f_types_impl_ << indent() << "g_clear_object (&(tobject->" << name << "));" << endl;
-      // does g_object_unref the trick?
-      f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl;
-      f_types_impl_ << indent() << "{" << endl;
-      indent_up();
-      f_types_impl_ <<
-      indent() << "g_object_unref(tobject->" << name << ");" << endl;
-      f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl;
-      indent_down();
-      f_types_impl_ << indent() << "}" << endl;
-    } else if (t->is_string()) {
-      string name = (*m_iter)->get_name();
-      f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl;
-      f_types_impl_ << indent() << "{" << endl;
-      indent_up();
-      f_types_impl_ <<
-      indent() << "g_free (tobject->" << name << ");" << endl;
-      f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl;
-      indent_down();
-      f_types_impl_ << indent() << "}" << endl;
-    }
-  }
-
-  indent_down();
-  f_types_impl_ <<
-    "}" << endl <<
-    endl;
-
-
-  f_types_impl_ <<
-    "static void " << endl <<
-    this->nspace_lc << name_u << "_class_init (ThriftStructClass * cls)" << endl <<
-    "{" << endl;
-  indent_up();
-
-  f_types_impl_ <<   
-    indent() << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl <<
-    endl <<
-    indent() << "gobject_class->finalize = " << this->nspace_lc << name_u << "_finalize;" << endl <<
-    indent() << "cls->read = " << this->nspace_lc << name_u << "_read;" << endl <<
-    indent() << "cls->write = " << this->nspace_lc << name_u << "_write;" << endl;
-
-  indent_down();
-  f_types_impl_ <<
-    "}" << endl <<
-    endl;
-
-
-  f_types_impl_ <<
-    "GType" << endl <<
-    this->nspace_lc << name_u << "_get_type (void)" << endl <<
-    "{" << endl <<
-    "  static GType type = 0;" << endl <<
-    endl <<
-    "  if (type == 0) " << endl <<
-    "  {" << endl <<
-    "    static const GTypeInfo type_info = " << endl <<
-    "    {" << endl <<
-    "      sizeof (" << this->nspace << name << "Class)," << endl <<
-    "      NULL, /* base_init */" << endl <<
-    "      NULL, /* base_finalize */" << endl <<
-    "      (GClassInitFunc) " << this->nspace_lc << name_u << "_class_init," << endl <<
-    "      NULL, /* class_finalize */" << endl <<
-    "      NULL, /* class_data */" << endl <<
-    "      sizeof (" << this->nspace << name << ")," << endl <<
-    "      0, /* n_preallocs */" << endl <<
-    "      (GInstanceInitFunc) " << this->nspace_lc << name_u << "_instance_init," << endl <<
-    "      NULL, /* value_table */" << endl <<
-    "    };" << endl <<
-    endl <<
-    "    type = g_type_register_static (THRIFT_TYPE_STRUCT, " << endl <<
-    "                                   \"" << this->nspace << name << "Type\"," << endl <<
-    "                                   &type_info, 0);" << endl <<
-    "  }" << endl <<
-    endl <<
-    "  return type;" << endl <<
-    "}" << endl <<
-    endl;
-}
-
-/**
- * Generates functions to write Thrift structures to a stream.
- */
-void t_c_glib_generator::generate_struct_writer (ofstream &out,
-                                                 t_struct *tstruct,
-                                                 string this_name,
-                                                 string this_get,
-                                                 bool is_function) {
-  string name = tstruct->get_name();
-  string name_u = initial_caps_to_underscores(name);
-  string name_uc = to_upper_case(name_u);
-
-  const vector<t_field *> &fields = tstruct->get_members();
-  vector <t_field *>::const_iterator f_iter;
-  int error_ret = 0;
-
-  if (is_function) {
-    error_ret = -1;
-    indent(out) <<
-      "static gint32" << endl <<
-      this->nspace_lc << name_u <<
-      "_write (ThriftStruct *object, ThriftProtocol *protocol, GError **error)" << endl;
-  }
-  indent(out) << "{" << endl;
-  indent_up();
-
-  out <<
-    indent() << "gint32 ret;" << endl <<
-    indent() << "gint32 xfer = 0;" << endl <<
-    endl;
-
-  indent(out) << this_get << endl;
-  // satisfy -Wall in the case of an empty struct
-  if (!this_get.empty()) {
-    indent(out) << "THRIFT_UNUSED_VAR (this_object);" << endl;
-  }
-
-  out <<
-    indent() << "if ((ret = thrift_protocol_write_struct_begin (protocol, \"" << name << "\", error)) < 0)" << endl <<
-    indent() << "  return " << error_ret << ";" << endl <<
-    indent() << "xfer += ret;" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
-      indent(out) << "if (this_object->__isset_" << (*f_iter)->get_name() << " == TRUE) {" << endl;
-      indent_up();
-    } 
-
-    out <<
-     indent() << "if ((ret = thrift_protocol_write_field_begin (protocol, " <<
-     "\"" << (*f_iter)->get_name() << "\", " <<
-     type_to_enum ((*f_iter)->get_type()) << ", " <<
-     (*f_iter)->get_key() << ", error)) < 0)" << endl <<
-     indent() << "  return " << error_ret << ";" << endl <<
-     indent() << "xfer += ret;" << endl;
-    generate_serialize_field (out, *f_iter, this_name, "", error_ret);
-    out <<
-      indent() << "if ((ret = thrift_protocol_write_field_end (protocol, error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl;
-
-    if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-  }
-
-  // write the struct map
-  out <<
-    indent() << "if ((ret = thrift_protocol_write_field_stop (protocol, error)) < 0)" << endl <<
-    indent() << "  return " << error_ret << ";" << endl <<
-    indent() << "xfer += ret;" << endl <<
-    indent() << "if ((ret = thrift_protocol_write_struct_end (protocol, error)) < 0)" << endl <<
-    indent() << "  return " << error_ret << ";" << endl <<
-    indent() << "xfer += ret;" << endl <<
-    endl;
-
-  if (is_function) {
-    indent(out) << "return xfer;" << endl;
-  }
-
-  indent_down();
-  indent(out) <<
-    "}" << endl <<
-    endl;
-}
-
-/**
- * Generates code to read Thrift structures from a stream.
- */
-void t_c_glib_generator::generate_struct_reader(ofstream &out,
-                                                t_struct *tstruct,
-                                                string this_name,
-                                                string this_get,
-                                                bool is_function) {
-  string name = tstruct->get_name();
-  string name_u = initial_caps_to_underscores(name);
-  string name_uc = to_upper_case(name_u);
-  int error_ret = 0;
-  const vector<t_field *> &fields = tstruct->get_members();
-  vector <t_field *>::const_iterator f_iter;
-
-  if (is_function) {
-    error_ret = -1;
-    indent(out) <<
-      "/* reads a " << name_u << " object */" << endl <<
-      "static gint32" << endl <<
-      this->nspace_lc << name_u <<
-          "_read (ThriftStruct *object, ThriftProtocol *protocol, GError **error)" << endl;
-  }
-
-  indent(out) << "{" << endl;
-  indent_up();
-
-  // declare stack temp variables
-  out <<
-    indent() << "gint32 ret;" << endl <<
-    indent() << "gint32 xfer = 0;" << endl <<
-    indent() << "gchar *name = NULL;" << endl <<
-    indent() << "ThriftType ftype;" << endl <<
-    indent() << "gint16 fid;" << endl <<
-    indent() << "guint32 len = 0;" << endl <<
-    indent() << "gpointer data = NULL;" << endl <<
-    indent() << this_get << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
-      indent(out) << "gboolean isset_" << (*f_iter)->get_name() << " = FALSE;" << endl;
-    }
-  }
-
-  out << endl;
-
-  // satisfy -Wall in case we don't use some variables
-  out <<
-    indent() << "/* satisfy -Wall in case these aren't used */" << endl <<
-    indent() << "THRIFT_UNUSED_VAR (len);" << endl <<
-    indent() << "THRIFT_UNUSED_VAR (data);" << endl;
-
-  if (!this_get.empty()) {
-    out << indent() << "THRIFT_UNUSED_VAR (this_object);" << endl;
-  }
-  out << endl;
-
-  // read the beginning of the structure marker
-  out <<
-    indent() << "/* read the struct begin marker */" << endl <<
-    indent() << "if ((ret = thrift_protocol_read_struct_begin (protocol, &name, error)) < 0)" << endl <<
-    indent() << "{" << endl <<
-    indent() << "  if (name) g_free (name);" << endl <<
-    indent() << "  return " << error_ret << ";" << endl <<
-    indent() << "}" << endl <<
-    indent() << "xfer += ret;" << endl <<
-    indent() << "if (name) g_free (name);" << endl <<
-    indent() << "name = NULL;" << endl <<
-    endl;
-
-  // read the struct fields
-  out <<
-    indent() << "/* read the struct fields */" << endl <<
-    indent() << "while (1)" << endl;
-  scope_up(out);
-
-  // read beginning field marker
-  out <<
-    indent() << "/* read the beginning of a field */" << endl <<
-    indent() << "if ((ret = thrift_protocol_read_field_begin (protocol, &name, &ftype, &fid, error)) < 0)" << endl <<
-    indent() << "{" << endl <<
-    indent() << "  if (name) g_free (name);" << endl <<
-    indent() << "  return " << error_ret << ";" << endl <<
-    indent() << "}" << endl <<
-    indent() << "xfer += ret;" << endl <<
-    indent() << "if (name) g_free (name);" << endl <<
-    indent() << "name = NULL;" << endl <<
-    endl;
-
-  // check for field STOP marker
-  out <<
-    indent() << "/* break if we get a STOP field */" << endl <<
-    indent() << "if (ftype == T_STOP)" << endl <<
-    indent() << "{" << endl <<
-    indent() << "  break;" << endl <<
-    indent() << "}" << endl <<
-    endl;
-
-  // switch depending on the field type
-  indent(out) <<
-    "switch (fid)" << endl;
-
-  // start switch
-  scope_up(out);
-
-  // generate deserialization code for known types
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    indent(out) <<
-      "case " << (*f_iter)->get_key() << ":" << endl;
-    indent_up();
-    indent(out) <<
-      "if (ftype == " << type_to_enum ((*f_iter)->get_type()) << ")" << endl;
-    indent(out) <<
-      "{" << endl;
-
-
-    indent_up();
-    // generate deserialize field
-    generate_deserialize_field (out, *f_iter, this_name, "", error_ret, false);
-    indent_down();
-
-    out <<
-      indent() << "} else {" << endl <<
-      indent() << "  if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl <<
-      indent() << "    return " << error_ret << ";" << endl <<
-      indent() << "  xfer += ret;" << endl <<
-      indent() << "}" << endl <<
-      indent() << "break;" << endl;
-    indent_down();
-  }
-
-  // create the default case
-  out <<
-    indent() << "default:" << endl <<
-    indent() << "  if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl <<
-    indent() << "    return " << error_ret << ";" << endl <<
-    indent() << "  xfer += ret;" << endl <<
-    indent() << "  break;" << endl;
-
-  // end switch
-  scope_down(out);
-
-  // read field end marker
-  out <<
-    indent() << "if ((ret = thrift_protocol_read_field_end (protocol, error)) < 0)" << endl <<
-    indent() << "  return " << error_ret << ";" << endl <<
-    indent() << "xfer += ret;" << endl;
-
-  // end while loop
-  scope_down(out);
-  out << endl;
-
-  // read the end of the structure
-  out <<
-    indent() << "if ((ret = thrift_protocol_read_struct_end (protocol, error)) < 0)" << endl <<
-    indent() << "  return " << error_ret << ";" << endl <<
-    indent() << "xfer += ret;" << endl <<
-    endl;
-
-  // if a required field is missing, throw an error
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
-      out <<
-        indent() << "if (!isset_" << (*f_iter)->get_name() << ")" << endl <<
-        indent() << "{" << endl <<
-        indent() << "  g_set_error (error, THRIFT_PROTOCOL_ERROR," << endl <<
-        indent() << "               THRIFT_PROTOCOL_ERROR_INVALID_DATA," << endl <<
-        indent() << "               \"missing field\");" << endl <<
-        indent() << "  return -1;" << endl <<
-        indent() << "}" << endl <<
-        endl;
-    }
-  }
-
-  if (is_function) {
-    indent(out) <<
-      "return xfer;" << endl;
-  }
-
-  // end the function/structure
-  indent_down();
-  indent(out) <<
-    "}" << endl <<
-    endl;
-}
-
-void t_c_glib_generator::generate_serialize_field(ofstream &out,
-                                                  t_field *tfield,
-                                                  string prefix,
-                                                  string suffix,
-                                                  int error_ret) {
-  t_type *type = get_true_type (tfield->get_type());
-  string name = prefix + tfield->get_name() + suffix;
-
-  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, error_ret);
-  } else if (type->is_container()) {
-    generate_serialize_container (out, type, name, error_ret);
-  } else if (type->is_base_type() || type->is_enum()) {
-    indent(out) <<
-      "if ((ret = thrift_protocol_write_";
-
-    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_BOOL:
-          out << "bool (protocol, " << name;
-          break;
-        case t_base_type::TYPE_BYTE:
-          out << "byte (protocol, " << name;
-          break;
-        case t_base_type::TYPE_I16:
-          out << "i16 (protocol, " << name;
-          break;
-        case t_base_type::TYPE_I32:
-          out << "i32 (protocol, " << name;
-          break;
-        case t_base_type::TYPE_I64:
-          out << "i64 (protocol, " << name;
-          break;
-        case t_base_type::TYPE_DOUBLE:
-          out << "double (protocol, " << name;
-          break;
-        case t_base_type::TYPE_STRING:
-          if (((t_base_type *) type)->is_binary()) {
-            out << "binary (protocol, ((GByteArray *) " << name <<
-                   ")->data, ((GByteArray *) " << name <<
-                   ")->len";
-          } else {
-            out << "string (protocol, " << name;
-          }
-          break;
-        default:
-          throw "compiler error: no C writer for base type "
-                + t_base_type::t_base_name (tbase) + name;
-      }
-    } else if (type->is_enum()) {
-      out << "i32 (protocol, (gint32) " << name;
-    }
-    out << ", error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl;
-  } else {
-    printf ("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
-            name.c_str(), type_name (type).c_str());
-  }
-}
-
-void t_c_glib_generator::generate_serialize_struct(ofstream &out,
-                                                   t_struct *tstruct,
-                                                   string prefix,
-                                                   int error_ret) {
-  (void) tstruct;
-  out <<
-    indent() << "if ((ret = thrift_struct_write (THRIFT_STRUCT (" << prefix << "), protocol, error)) < 0)" << endl <<
-    indent() << "  return " << error_ret << ";" << endl <<
-    indent() << "xfer += ret;" << endl <<
-    endl;
-}
-
-void t_c_glib_generator::generate_serialize_container(ofstream &out,
-                                                      t_type *ttype,
-                                                      string prefix,
-                                                      int error_ret) {
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    string length = "g_hash_table_size ((GHashTable *) " + prefix + ")";
-    t_type *tkey = ((t_map *) ttype)->get_key_type();
-    t_type *tval = ((t_map *) ttype)->get_val_type();
-    string tkey_name = type_name (tkey);
-    string tval_name = type_name (tval);
-    string tkey_ptr = tkey->is_string() || !tkey->is_base_type() ? "" : "*";
-    string tval_ptr = tval->is_string() || !tval->is_base_type() ? "" : "*";
-
-    /*
-     * Some ugliness here.  To maximize backwards compatibility, we
-     * avoid using GHashTableIter and instead get a GList of all keys,
-     * then copy it into a array on the stack, and free it.
-     * This is because we may exit early before we get a chance to free the
-     * GList.
-     */
-    out <<
-      indent() << "if ((ret = thrift_protocol_write_map_begin (protocol, " <<
-                   type_to_enum (tkey) << ", " << type_to_enum (tval) <<
-                   ", (gint32) " << length << ", error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl <<
-      endl <<
-      indent() << "GList *key_list = NULL, *iter = NULL;" << endl <<
-      indent() << tkey_name << tkey_ptr << " key;" << endl <<
-      indent() << tval_name << tval_ptr << " value;" << endl <<
-      indent() << "g_hash_table_foreach ((GHashTable *) " << prefix << 
-                   ", thrift_hash_table_get_keys, &key_list);" << endl <<
-      indent() << tkey_name << tkey_ptr <<
-                   " keys[g_list_length (key_list)];" << endl <<
-      indent() << "int i=0, key_count = g_list_length (key_list);" << endl <<
-      indent() <<
-        "for (iter = g_list_first (key_list); iter; iter = iter->next)" <<
-        endl <<
-      indent() << "{" << endl <<
-      indent() << "  keys[i++] = (" << tkey_name << tkey_ptr <<
-                   ") iter->data;" << endl <<
-      indent() << "}" << endl <<
-      indent() << "g_list_free (key_list);" << endl <<
-      endl <<
-      indent() << "for (i = 0; i < key_count; ++i)" << endl;
-
-    scope_up(out);
-    out <<
-      indent() << "key = keys[i];" << endl <<
-      indent() << "value = (" << tval_name << tval_ptr <<
-                   ") g_hash_table_lookup (((GHashTable *) " << prefix <<
-                   "), (gpointer) key);" << endl <<
-      endl;
-    generate_serialize_map_element (out, (t_map *) ttype, tkey_ptr + " key",
-                                    tval_ptr + " value", error_ret);
-    scope_down(out);
-
-    out <<
-      indent() << "if ((ret = thrift_protocol_write_map_end (protocol, error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl;
-  } else if (ttype->is_set()) {
-    string length = "g_hash_table_size ((GHashTable *) " + prefix + ")";
-    t_type *telem = ((t_set *) ttype)->get_elem_type();
-    string telem_name = type_name (telem);
-    string telem_ptr = telem->is_string() || !telem->is_base_type() ? "" : "*";
-    out <<
-      indent() << "if ((ret = thrift_protocol_write_set_begin (protocol, " <<
-                   type_to_enum (telem) << ", (gint32) " << length <<
-                   ", error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl <<
-      indent() << "GList *key_list = NULL, *iter = NULL;" << endl <<
-      indent() << telem_name << telem_ptr << " elem;" << endl <<
-      indent() << "gpointer value;" << endl <<
-      indent() << "THRIFT_UNUSED_VAR (value);" << endl <<
-      endl <<
-      indent() << "g_hash_table_foreach ((GHashTable *) " << prefix <<
-                   ", thrift_hash_table_get_keys, &key_list);" << endl <<
-      indent() << telem_name << telem_ptr << " keys[g_list_length (key_list)];" << endl <<
-      indent() << "int i=0, key_count = g_list_length (key_list);" << endl <<
-      indent() << "for (iter = g_list_first (key_list); iter; iter = iter->next)" << endl <<
-      indent() << "{" << endl <<
-      indent() << "  keys[i++] = (" << telem_name << telem_ptr << ") iter->data;" << endl <<
-      indent() << "}" << endl <<
-      indent() << "g_list_free (key_list);" << endl <<
-      endl <<
-      indent() << "for (i=0; i<key_count; ++i)" << endl;
-
-    scope_up(out);
-    out <<
-      indent() << "elem = keys[i];" << endl <<
-      indent() << "value = (gpointer) g_hash_table_lookup (((GHashTable *) " <<
-                   prefix << "), (gpointer) elem);" << endl <<
-      endl;
-    generate_serialize_set_element (out, (t_set *) ttype, telem_ptr + "elem",
-                                    error_ret);
-    scope_down(out);
-
-    out <<
-      indent() << "if ((ret = thrift_protocol_write_set_end (protocol, error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl;
-  } else if (ttype->is_list()) {
-    string length = prefix + "->len";
-    string i = tmp("i");
-    out <<
-      indent() << "if ((ret = thrift_protocol_write_list_begin (protocol, " <<
-                   type_to_enum (((t_list *) ttype)->get_elem_type()) <<
-                   ", (gint32) " << length << ", error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl <<
-      indent() << "guint " << i << ";" << endl <<
-      indent() << "for ("<< i << "=0; " << i << "<" << length << "; " << i <<
-                         "++)" << endl;
-
-    scope_up(out);
-    generate_serialize_list_element (out, (t_list *) ttype, prefix, i, error_ret);
-    scope_down(out);
-
-    out <<
-      indent() << "if ((ret = thrift_protocol_write_list_end (protocol, error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl;
-  }
-
-  scope_down(out);
-}
-
-void t_c_glib_generator::generate_serialize_map_element(ofstream &out,
-                                                        t_map *tmap,
-                                                        string key,
-                                                        string value,
-                                                        int error_ret) {
-  t_field kfield (tmap->get_key_type(), key);
-  generate_serialize_field (out, &kfield, "", "", error_ret);
-
-  t_field vfield (tmap->get_val_type(), value);
-  generate_serialize_field (out, &vfield, "", "", error_ret);
-}
-
-void t_c_glib_generator::generate_serialize_set_element(ofstream &out,
-                                                        t_set *tset,
-                                                        string element,
-                                                        int error_ret) {
-  t_field efield (tset->get_elem_type(), element);
-  generate_serialize_field (out, &efield, "", "", error_ret);
-}
-
-void t_c_glib_generator::generate_serialize_list_element(ofstream &out,
-                                                         t_list *tlist,
-                                                         string list,
-                                                         string index,
-                                                         int error_ret) {
-  t_type *ttype = tlist->get_elem_type();
-
-  // cast to non-const
-  string cast = "";
-  string name = "g_ptr_array_index ((GPtrArray *) " + list + ", "
-                + index + ")";
-
-  if (ttype->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type *) ttype)->get_base(); 
-    switch (tbase) {
-      case t_base_type::TYPE_VOID:
-        throw "compiler error: cannot determine array type";
-        break;
-      case t_base_type::TYPE_BOOL:
-        name = "g_array_index (" + list + ", gboolean, " + index + ")";
-        break;
-      case t_base_type::TYPE_BYTE:
-        name = "g_array_index (" + list + ", gint8, " + index + ")";
-        break;
-      case t_base_type::TYPE_I16:
-        name = "g_array_index (" + list + ", gint16, " + index + ")";
-        break;
-      case t_base_type::TYPE_I32:
-        name = "g_array_index (" + list + ", gint32, " + index + ")";
-        break;
-      case t_base_type::TYPE_I64:
-        name = "g_array_index (" + list + ", gint64, " + index + ")";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        name = "g_array_index (" + list + ", gdouble, " + index + ")";
-        break;
-      case t_base_type::TYPE_STRING:
-        cast = "(gchar*)";
-        break;
-      default:
-        throw "compiler error: no array info for type";
-    }
-  } else if (ttype->is_map() || ttype->is_set()) {
-    cast = "(GHashTable*)";
-  } else if (ttype->is_list()) {
-    t_type *base = ((t_list *)ttype)->get_elem_type();
-    if (base->is_base_type()) {
-      switch (((t_base_type *) base)->get_base()) {
-        case t_base_type::TYPE_VOID:
-          throw "compiler error: cannot determine array type";
-          break;
-        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:
-          cast = "(GArray*)";
-          break;
-        case t_base_type::TYPE_STRING:
-          cast = "(GPtrArray*)";
-          break;
-        default:
-          throw "Compiler error: no array info for type";
-      }
-    } else {
-      cast = "(GPtrArray*)";
-    }
-  }
-
-  t_field efield (ttype, "(" + cast + name + ")");
-  generate_serialize_field (out, &efield, "", "", error_ret);
-}
-
-/* deserializes a field of any type. */
-void t_c_glib_generator::generate_deserialize_field(ofstream &out,
-                                                    t_field *tfield,
-                                                    string prefix,
-                                                    string suffix,
-                                                    int error_ret,
-                                                    bool allocate) {
-  t_type *type = get_true_type (tfield->get_type());
-
-  if (type->is_void()) {
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  string name = prefix + tfield->get_name() + suffix;
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct (out, (t_struct *) type, name, error_ret, allocate);
-  } else if (type->is_container()) {
-    generate_deserialize_container (out, type, name, error_ret);
-  } else if (type->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type *) type)->get_base();
-    if (tbase == t_base_type::TYPE_STRING) {
-      indent(out) << "if (" << name << " != NULL)" << endl <<
-        indent() << "{" << endl;
-      indent_up();
-      indent(out) << "g_free(" << name << ");" << endl <<
-        indent() << name << " = NULL;" << endl;
-      indent_down();
-      indent(out) << "}" << endl <<
-      endl;
-    }
-    indent(out) << "if ((ret = thrift_protocol_read_";
-
-    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:
-        if (((t_base_type *) type)->is_binary()) {
-          out << "binary (protocol, &data, &len";
-        } else {
-          out << "string (protocol, &" << name;
-        }
-        break;
-      case t_base_type::TYPE_BOOL:
-        out << "bool (protocol, &" << name;
-        break;
-      case t_base_type::TYPE_BYTE:
-        out << "byte (protocol, &" << name;
-        break;
-      case t_base_type::TYPE_I16:
-        out << "i16 (protocol, &" << name;
-        break;
-      case t_base_type::TYPE_I32:
-        out << "i32 (protocol, &" << name;
-        break;
-      case t_base_type::TYPE_I64:
-        out << "i64 (protocol, &" << name;
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        out << "double (protocol, &" << name;
-        break;
-      default:
-        throw "compiler error: no C reader for base type "
-          + t_base_type::t_base_name (tbase) + name;
-    }
-    out << ", error)) < 0)" << endl;
-    out << indent() << "  return " << error_ret << ";" << endl <<
-           indent() << "xfer += ret;" << endl;
-
-    // load the byte array with the data
-    if (tbase == t_base_type::TYPE_STRING
-        && ((t_base_type *) type)->is_binary()) {
-      indent(out) << name << " = g_byte_array_new();" << endl;
-      indent(out) << "g_byte_array_append (" << name << ", (guint8 *) data, (guint) len);" << endl;
-      indent(out) << "g_free (data);" << endl;
-    }
-  } else if (type->is_enum()) {
-    string t = tmp ("ecast");
-    out <<
-      indent() << "gint32 " << t << ";" << endl <<
-      indent() << "if ((ret = thrift_protocol_read_i32 (protocol, &" << t << ", error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl <<
-      indent() << name << " = (" << type_name (type) << ")" << t << ";" << endl;
-  } else {
-    printf ("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
-            tfield->get_name().c_str(), type_name (type).c_str());
-  }
-
-  // if the type is not required and this is a thrift struct (no prefix),
-  // set the isset variable.  if the type is required, then set the
-  // local variable indicating the value was set, so that we can do    // validation later.
-  if (tfield->get_req() != t_field::T_REQUIRED && prefix != "") {
-    indent(out) << prefix << "__isset_" << tfield->get_name() << suffix << " = TRUE;" << endl;
-  } else if (tfield->get_req() == t_field::T_REQUIRED && prefix != "") {
-    indent(out) << "isset_" << tfield->get_name() << " = TRUE;" << endl;
-  }
-}
-
-void t_c_glib_generator::generate_deserialize_struct(ofstream &out,
-                                                     t_struct *tstruct,
-                                                     string prefix,
-                                                     int error_ret,
-                                                     bool allocate) {
-  string name_uc = to_upper_case(initial_caps_to_underscores(tstruct->get_name()));
-  if (tstruct->is_xception()) {
-    out <<
-      indent() << "/* This struct is an exception */" << endl;
-    allocate = true;
-  }
-
-  if (allocate) {
-    out <<
-      indent() << "if ( " << prefix << " != NULL)" << endl <<
-      indent() << "{" << endl;
-    indent_up();
-    out <<
-      indent() << "g_object_unref (" << prefix << ");" << endl;
-    indent_down();
-    out <<
-      indent() << "}" << endl <<
-      indent() << prefix << " = g_object_new (" << this->nspace_uc << "TYPE_" << name_uc << ", NULL);" << endl;
-  }
-  out <<
-    indent() << "if ((ret = thrift_struct_read (THRIFT_STRUCT (" << prefix << "), protocol, error)) < 0)" << endl <<
-    indent() << "{" << endl;
-  indent_up();
-  if (allocate) {
-    indent(out) << "g_object_unref (" << prefix << ");" << endl;
-  }
-  out <<
-    indent() << "return " << error_ret << ";" << endl;
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    indent() << "xfer += ret;" << endl;
-}
-
-void t_c_glib_generator::generate_deserialize_container (ofstream &out, t_type *ttype,
-                                               string prefix, int error_ret) {
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    out <<
-      indent() << "guint32 size;" << endl <<
-      indent() << "ThriftType key_type;" << endl <<
-      indent() << "ThriftType value_type;" << endl <<
-      endl <<
-      indent() << "/* read the map begin marker */" << endl <<
-      indent() << "if ((ret = thrift_protocol_read_map_begin (protocol, &key_type, &value_type, &size, error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl <<
-      endl;
-
-    // iterate over map elements
-    out <<
-      indent() << "/* iterate through each of the map's fields */" << endl <<
-      indent() << "guint32 i;" << endl <<
-      indent() << "for (i = 0; i < size; i++)" << endl;
-    scope_up(out);
-    generate_deserialize_map_element (out, (t_map *) ttype, prefix, error_ret);
-    scope_down(out);
-    out << endl;
-  
-    // read map end
-    out <<
-      indent() << "/* read the map end marker */" << endl <<
-      indent() << "if ((ret = thrift_protocol_read_map_end (protocol, error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl;
-  } else if (ttype->is_set()) {
-    out <<
-      indent() << "guint32 size;" << endl <<
-      indent() << "ThriftType element_type;" << endl <<
-      indent() << "if ((ret = thrift_protocol_read_set_begin (protocol, &element_type, &size, error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl <<
-      endl;
-
-    // iterate over the elements
-    out <<
-      indent() << "/* iterate through the set elements */" << endl <<
-      indent() << "guint32 i;" << endl <<
-      indent() << "for (i = 0; i < size; ++i)" << endl;
-
-    scope_up(out);
-    generate_deserialize_set_element (out, (t_set *) ttype, prefix, error_ret);
-    scope_down(out);
-
-    // read set end
-    out <<
-      indent() << "if ((ret = thrift_protocol_read_set_end (protocol, error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl <<
-      endl;
-  } else if (ttype->is_list()) {
-    out <<
-      indent() << "guint32 size;" << endl <<
-      indent() << "ThriftType element_type;" << endl <<
-      indent() << "if ((ret = thrift_protocol_read_list_begin (protocol, &element_type, &size, error)) < 0)" << endl <<
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl <<
-      endl;
-
-    out <<
-      indent() << "/* iterate through list elements */" << endl <<
-      indent() << "guint32 i;" << endl <<
-      indent() << "for (i = 0; i < size; i++)" << endl;
-
-    scope_up(out);
-    generate_deserialize_list_element (out, (t_list *) ttype, prefix, "i",
-                                       error_ret);
-    scope_down(out);
-
-    out <<
-      indent() << "if ((ret = thrift_protocol_read_list_end (protocol, error)) < 0)" << endl << 
-      indent() << "  return " << error_ret << ";" << endl <<
-      indent() << "xfer += ret;" << endl <<
-      endl;
-  }
-
-  scope_down(out);
-}
-
-void t_c_glib_generator::declare_local_variable(ofstream &out, t_type *ttype, string &name) {
-  string tname = type_name (ttype);
-  string ptr = ttype->is_string() || !ttype->is_base_type() ? "" : "*";
-
-  if (ttype->is_map()) {
-    out <<
-    indent() << tname << ptr << " " << name << " = g_hash_table_new (NULL, NULL);" << endl;
-  } else if (ttype->is_enum()) {
-    out <<
-    indent() << tname << ptr << " " << name << ";" << endl;
-  } else {
-    out <<
-    indent() << tname << ptr << " " << name << (ptr != "" ? " = g_new (" + tname + ", 1)" : " = NULL") << ";" << endl;
-  }
-}
-
-
-void t_c_glib_generator::generate_deserialize_map_element(ofstream &out,
-                                                          t_map *tmap,
-                                                          string prefix,
-                                                          int error_ret) {
-  t_type *tkey = tmap->get_key_type();
-  t_type *tval = tmap->get_val_type();
-  string tkey_ptr = tkey->is_string() || !tkey->is_base_type() ? "" : "*";
-  string tval_ptr = tval->is_string() || !tval->is_base_type() ? "" : "*";
-  string keyname = tmp("key");
-  string valname = tmp("val");
-
-  declare_local_variable(out, tkey, keyname);
-  declare_local_variable(out, tval, valname);
-
-  // deserialize the fields of the map element
-  t_field fkey (tkey, tkey_ptr + keyname);
-  generate_deserialize_field (out, &fkey, "", "", error_ret);
-  t_field fval (tval, tval_ptr + valname);
-  generate_deserialize_field (out, &fval, "", "", error_ret);
-
-  indent(out) <<
-    "g_hash_table_insert ((GHashTable *)" << prefix << ", (gpointer) " << keyname << ", (gpointer) " << valname << ");" << endl;
-}
-
-void t_c_glib_generator::generate_deserialize_set_element(ofstream &out,
-                                                          t_set *tset,
-                                                          string prefix,
-                                                          int error_ret) {
-  t_type *telem = tset->get_elem_type();
-  string elem = tmp ("_elem");
-  string telem_ptr = telem->is_string() || !telem->is_base_type() ? "" : "*";
-
-  declare_local_variable(out, telem, elem);
-
-  t_field felem (telem, telem_ptr + elem);
-  generate_deserialize_field (out, &felem, "", "", error_ret);
-
-  indent(out) <<
-    "g_hash_table_insert ((GHashTable *) " << prefix << ", (gpointer) " <<
-                              elem << ", (gpointer) 1);" << endl;
-}
-
-void t_c_glib_generator::generate_deserialize_list_element(ofstream &out,
-                                                           t_list *tlist,
-                                                           string prefix,
-                                                           string index,
-                                                           int error_ret) {
-  (void) index;
-  t_type *ttype = tlist->get_elem_type();
-  string elem = tmp ("_elem");
-  string telem_ptr = ttype->is_string() || !ttype->is_base_type() ? "" : "*";
-
-  declare_local_variable(out, ttype, elem);
-
-  t_field felem (ttype, telem_ptr + elem);
-  generate_deserialize_field (out, &felem, "", "", error_ret);
-
-  indent(out);
-
-  if (ttype->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type *) ttype)->get_base();
-    switch (tbase) {
-      case t_base_type::TYPE_VOID:
-        throw "compiler error: cannot determine array type";
-      case t_base_type::TYPE_STRING:
-        out << "g_ptr_array_add (" << prefix << ", " << elem << ");" << endl;
-        return;
-      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:
-        out << "g_array_append_vals (" << prefix << ", " << elem << ", 1);" << endl;
-        return;
-      default:
-        throw "compiler error: no array info for type";
-    }
-  }
-  out << "g_ptr_array_add (" << prefix << ", " << elem << ");" << endl;
-}
-
-string t_c_glib_generator::generate_free_func_from_type (t_type * ttype) {
-  if (ttype == NULL)
-    return "NULL";
-
-  if (ttype->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type *) ttype)->get_base();
-    switch (tbase) {
-      case t_base_type::TYPE_VOID:
-        throw "compiler error: cannot determine hash type";
-        break;
-      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 "NULL";
-      case t_base_type::TYPE_STRING:
-        return "g_free";
-      default:
-        throw "compiler error: no hash table info for type";
-    }
-  } else if (ttype->is_enum()) {
-    return "NULL";
-  } else if (ttype->is_map() || ttype->is_set()) {
-    return "(GDestroyNotify) g_hash_table_destroy";
-  } else if (ttype->is_struct()) {
-    return "g_object_unref";
-  } else if (ttype->is_list()) {
-    t_type *etype = ((t_list *) ttype)->get_elem_type();
-    if (etype->is_base_type()) {
-      t_base_type::t_base tbase = ((t_base_type *) etype)->get_base();
-      switch (tbase) {
-        case t_base_type::TYPE_VOID:
-          throw "compiler error: cannot determine array type";
-          break;
-        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 "(GDestroyNotify) g_array_unref";
-        case t_base_type::TYPE_STRING:
-          return "(GDestroyNotify) g_ptr_array_unref";
-        default:
-          throw "compiler error: no array info for type";
-      }
-    } else if (etype->is_container() || etype->is_struct()) {
-      return "(GDestroyNotify) g_ptr_array_unref";;
-    } else if (etype->is_enum()) {
-      return "(GDestroyNotify) g_array_unref";
-    }
-    printf("Type not expected inside the array: %s\n", etype->get_name().c_str());
-    throw "Type not expected inside array" ;
-  } else if (ttype->is_typedef()) {
-    return generate_free_func_from_type(((t_typedef *) ttype)->get_type());
-  }
-  printf("Type not expected: %s\n", ttype->get_name().c_str());
-  throw "Type not expected";
-}
-
-string t_c_glib_generator::generate_hash_func_from_type (t_type * ttype) {
-  if (ttype == NULL)
-    return "NULL";
-
-  if (ttype->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type *) ttype)->get_base();
-    switch (tbase) {
-      case t_base_type::TYPE_VOID:
-        throw "compiler error: cannot determine hash type";
-        break;
-      case t_base_type::TYPE_BOOL:
-      case t_base_type::TYPE_BYTE:
-      case t_base_type::TYPE_I16:
-      case t_base_type::TYPE_I32:
-        return "g_int_hash";
-      case t_base_type::TYPE_I64:
-        return "g_int64_hash";
-      case t_base_type::TYPE_DOUBLE:
-        return "g_double_hash";
-      case t_base_type::TYPE_STRING:
-        return "g_str_hash";
-      default:
-        throw "compiler error: no hash table info for type";
-    }
-  } else if (ttype->is_enum()) {
-    return "g_direct_hash";
-  } else if (ttype->is_container() || ttype->is_struct()) {
-    return "g_direct_hash";
-  } else if (ttype->is_typedef()) {
-    return generate_hash_func_from_type(((t_typedef *) ttype)->get_type());
-  }
-  printf("Type not expected: %s\n", ttype->get_name().c_str());
-  throw "Type not expected";
-}
-
-string t_c_glib_generator::generate_cmp_func_from_type (t_type * ttype) {
-  if (ttype == NULL)
-    return "NULL";
-
-  if (ttype->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type *) ttype)->get_base();
-    switch (tbase) {
-      case t_base_type::TYPE_VOID:
-        throw "compiler error: cannot determine hash type";
-        break;
-      case t_base_type::TYPE_BOOL:
-      case t_base_type::TYPE_BYTE:
-      case t_base_type::TYPE_I16:
-      case t_base_type::TYPE_I32:
-        return "g_int_equal";
-      case t_base_type::TYPE_I64:
-        return "g_int64_equal";
-      case t_base_type::TYPE_DOUBLE:
-        return "g_double_equal";
-      case t_base_type::TYPE_STRING:
-        return "g_str_equal";
-      default:
-        throw "compiler error: no hash table info for type";
-    }
-  } else if (ttype->is_enum()) {
-    return "NULL";
-  } else if (ttype->is_container() || ttype->is_struct()) {
-    return "g_direct_equal";
-  } else if (ttype->is_typedef()) {
-    return generate_cmp_func_from_type(((t_typedef *) ttype)->get_type());
-  }
-  printf("Type not expected: %s\n", ttype->get_name().c_str());
-  throw "Type not expected";
-}
-
-string t_c_glib_generator::generate_new_hash_from_type (t_type * key, t_type *value) {
-  string hash_func = generate_hash_func_from_type(key);
-  string cmp_func = generate_cmp_func_from_type(key);
-  string key_free_func = generate_free_func_from_type(key);
-  string value_free_func = generate_free_func_from_type(value);
-
-  return "g_hash_table_new_full (" + hash_func + ", " + cmp_func + ", " +
-                              key_free_func + ", " + value_free_func + ");";
-}
-
-string t_c_glib_generator::generate_new_array_from_type(t_type * ttype) {
-  if (ttype->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type *) ttype)->get_base();
-    switch (tbase) {
-      case t_base_type::TYPE_VOID:
-        throw "compiler error: cannot determine array type";
-        break;
-      case t_base_type::TYPE_BOOL:
-        return "g_array_new (0, 1, sizeof (gboolean));";
-      case t_base_type::TYPE_BYTE:
-        return "g_array_new (0, 1, sizeof (gint8));";
-      case t_base_type::TYPE_I16:
-        return "g_array_new (0, 1, sizeof (gint16));";
-      case t_base_type::TYPE_I32:
-        return "g_array_new (0, 1, sizeof (gint32));";
-      case t_base_type::TYPE_I64:
-        return "g_array_new (0, 1, sizeof (gint64));";
-      case t_base_type::TYPE_DOUBLE:
-        return "g_array_new (0, 1, sizeof (gdouble));";
-      case t_base_type::TYPE_STRING:
-        return "g_ptr_array_new_with_free_func (g_free);";
-      default:
-        throw "compiler error: no array info for type";
-    }
-  } else if (ttype->is_enum()) {
-    return "g_array_new (0, 1, sizeof (gint32));";
-  } else {
-    string free_func = generate_free_func_from_type(ttype);
-    return "g_ptr_array_new_with_free_func (" + free_func + ");";
-  }
-
-  return "g_ptr_array_new();";
-}
-
-
-/***************************************
- * UTILITY FUNCTIONS                   *
- ***************************************/
-
-/**
- * Upper case a string.  Wraps boost's string utility.
- */
-string to_upper_case(string name) {
-  string s (name);
-  std::transform (s.begin(), s.end(), s.begin(), ::toupper);
-  return s;
-//  return boost::to_upper_copy (name);
-}
-
-/**
- * Lower case a string.  Wraps boost's string utility.
- */
-string to_lower_case(string name) {
-  string s (name);
-  std::transform (s.begin(), s.end(), s.begin(), ::tolower);
-  return s;
-//  return boost::to_lower_copy (name);
-}
-
-/**
- * Makes a string friendly to C code standards by lowercasing and adding
- * underscores, with the exception of the first character.  For example:
- *
- * Input: "ZomgCamelCase"
- * Output: "zomg_camel_case"
- */
-string initial_caps_to_underscores(string name) {
-  string ret;
-  const char *tmp = name.c_str();
-  int pos = 0;
-
-  /* the first character isn't underscored if uppercase, just lowercased */
-  ret += tolower (tmp[pos]);
-  pos++;
-  for (unsigned int i = pos; i < name.length(); i++) {
-    char lc = tolower (tmp[i]); 
-    if (lc != tmp[i]) {
-      ret += '_';
-    }
-    ret += lc;
-  }
-
-  return ret;
-}
-
-/* register this generator with the main program */
-THRIFT_REGISTER_GENERATOR(c_glib, "C, using GLib", "")
diff --git a/compiler/cpp/src/generate/t_cocoa_generator.cc b/compiler/cpp/src/generate/t_cocoa_generator.cc
deleted file mode 100644
index b917a14..0000000
--- a/compiler/cpp/src/generate/t_cocoa_generator.cc
+++ /dev/null
@@ -1,2727 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sstream>
-#include "t_oop_generator.h"
-#include "platform.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * Objective-C code generator.
- *
- * mostly copy/pasting/tweaking from mcslee's work.
- */
-class t_cocoa_generator : public t_oop_generator {
- public:
-  t_cocoa_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_oop_generator(program)
-  {
-    (void) option_string;
-    std::map<std::string, std::string>::const_iterator iter;
-    
-    iter = parsed_options.find("log_unexpected");
-    log_unexpected_ = (iter != parsed_options.end());    
-    
-    iter = parsed_options.find("validate_required");
-    validate_required_ = (iter != parsed_options.end());    
-    
-    out_dir_base_ = "gen-cocoa";
-  }
-
-  /**
-   * Init and close methods
-   */
-
-  void init_generator();
-  void close_generator();
-
-  void generate_consts(std::vector<t_const*> consts);
-
-  /**
-   * Program-level generation functions
-   */
-
-  void generate_typedef (t_typedef*  ttypedef);
-  void generate_enum    (t_enum*     tenum);
-  void generate_struct  (t_struct*   tstruct);
-  void generate_xception(t_struct*   txception);
-  void generate_service (t_service*  tservice);
-
-  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool defval=false, bool is_property=false);
-  std::string render_const_value(ofstream& out, t_type* type, t_const_value* value, bool containerize_it=false);
-
-  void generate_cocoa_struct(t_struct* tstruct, bool is_exception);
-  void generate_cocoa_struct_interface(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
-  void generate_cocoa_struct_implementation(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_result=false);
-  void generate_cocoa_struct_initializer_signature(std::ofstream& out,
-                                                   t_struct* tstruct);
-  void generate_cocoa_struct_init_with_coder_method(ofstream &out,
-                                                    t_struct* tstruct,
-                                                    bool is_exception);
-  void generate_cocoa_struct_encode_with_coder_method(ofstream &out,
-                                                    t_struct* tstruct,
-                                                    bool is_exception);
-  void generate_cocoa_struct_field_accessor_declarations(std::ofstream& out,
-                                                         t_struct* tstruct,
-                                                         bool is_exception);
-  void generate_cocoa_struct_field_accessor_implementations(std::ofstream& out,
-                                                            t_struct* tstruct,
-                                                            bool is_exception);
-  void generate_cocoa_struct_reader(std::ofstream& out, t_struct* tstruct);
-  void generate_cocoa_struct_result_writer(std::ofstream& out, t_struct* tstruct);
-  void generate_cocoa_struct_writer(std::ofstream& out, t_struct* tstruct);
-  void generate_cocoa_struct_validator(std::ofstream& out, t_struct* tstruct);
-  void generate_cocoa_struct_description(std::ofstream& out, t_struct* tstruct);
-
-  std::string function_result_helper_struct_type(t_function* tfunction);
-  std::string function_args_helper_struct_type(t_function* tfunction);
-  void generate_function_helpers(t_function* tfunction);
-
-  /**
-   * Service-level generation functions
-   */
-
-  void generate_cocoa_service_protocol (std::ofstream& out, t_service* tservice);
-  void generate_cocoa_service_client_interface (std::ofstream& out, t_service* tservice);
-  void generate_cocoa_service_client_implementation (std::ofstream& out, t_service* tservice);
-  void generate_cocoa_service_server_interface (std::ofstream& out, t_service* tservice);
-  void generate_cocoa_service_server_implementation (std::ofstream& out, t_service* tservice);
-  void generate_cocoa_service_helpers   (t_service* tservice);
-  void generate_service_client    (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,
-                                          std::string fieldName);
-
-  void generate_deserialize_struct       (std::ofstream& out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_deserialize_container    (std::ofstream& out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_deserialize_set_element  (std::ofstream& out,
-                                          t_set*      tset,
-                                          std::string prefix="");
-
-  void generate_deserialize_map_element  (std::ofstream& out,
-                                          t_map*      tmap,
-                                          std::string prefix="");
-
-  void generate_deserialize_list_element (std::ofstream& out,
-                                          t_list*     tlist,
-                                          std::string prefix="");
-
-  void generate_serialize_field          (std::ofstream& out,
-                                          t_field*    tfield,
-                                          std::string prefix="");
-
-  void generate_serialize_struct         (std::ofstream& out,
-                                          t_struct*   tstruct,
-                                          std::string fieldName="");
-
-  void generate_serialize_container      (std::ofstream& out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_serialize_map_element    (std::ofstream& out,
-                                          t_map*      tmap,
-                                          std::string iter,
-                                          std::string map);
-
-  void generate_serialize_set_element    (std::ofstream& out,
-                                          t_set*      tmap,
-                                          std::string iter);
-
-  void generate_serialize_list_element   (std::ofstream& out,
-                                          t_list*     tlist,
-                                          std::string index,
-                                          std::string listName);
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string cocoa_prefix();
-  std::string cocoa_imports();
-  std::string cocoa_thrift_imports();
-  std::string type_name(t_type* ttype, bool class_ref=false);
-  std::string base_type_name(t_base_type* tbase);
-  std::string declare_field(t_field* tfield);
-  std::string declare_property(t_field* tfield);
-  std::string function_signature(t_function* tfunction);
-  std::string argument_list(t_struct* tstruct);
-  std::string type_to_enum(t_type* ttype);
-  std::string format_string_for_type(t_type* type);
-  std::string call_field_setter(t_field* tfield, std::string fieldName);
-  std::string containerize(t_type * ttype, std::string fieldName);
-  std::string decontainerize(t_field * tfield, std::string fieldName);
-
-  bool type_can_be_null(t_type* ttype) {
-    ttype = get_true_type(ttype);
-
-    return
-      ttype->is_container() ||
-      ttype->is_struct() ||
-      ttype->is_xception() ||
-      ttype->is_string();
-  }
-
- private:
-
-  std::string cocoa_prefix_;
-  std::string constants_declarations_;
-
-  /**
-   * File streams
-   */
-
-  std::ofstream f_header_;
-  std::ofstream f_impl_;
-
-  bool log_unexpected_;
-  bool validate_required_;
-};
-
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * streams.
- */
-void t_cocoa_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-  cocoa_prefix_ = program_->get_namespace("cocoa");
-
-  // we have a .h header file...
-  string f_header_name = program_name_+".h";
-  string f_header_fullname = get_out_dir()+f_header_name;
-  f_header_.open(f_header_fullname.c_str());
-
-  f_header_ <<
-    autogen_comment() <<
-    endl;
-
-  f_header_ <<
-    cocoa_imports() <<
-    cocoa_thrift_imports();
-
-  // ...and a .m implementation file
-  string f_impl_name = get_out_dir()+program_name_+".m";
-  f_impl_.open(f_impl_name.c_str());
-
-  f_impl_ <<
-    autogen_comment() <<
-    endl;
-
-  f_impl_ <<
-    cocoa_imports() <<
-    cocoa_thrift_imports() <<
-    "#import \"" << f_header_name << "\"" << endl <<
-    endl;
-
-}
-
-/**
- * Prints standard Cocoa imports
- *
- * @return List of imports for Cocoa libraries
- */
-string t_cocoa_generator::cocoa_imports() {
-  return
-    string() +
-    "#import <Foundation/Foundation.h>\n" +
-    "\n";
-}
-
-/**
- * Prints thrift runtime imports
- *
- * @return List of imports necessary for thrift runtime
- */
-string t_cocoa_generator::cocoa_thrift_imports() {
-  string result = string() +
-    "#import \"TProtocol.h\"\n" +
-    "#import \"TApplicationException.h\"\n" +
-    "#import \"TProtocolException.h\"\n" +
-    "#import \"TProtocolUtil.h\"\n" +
-    "#import \"TProcessor.h\"\n" +
-    "#import \"TObjective-C.h\"\n" +
-    "#import \"TBase.h\"\n" +
-    "\n";
-
-  // Include other Thrift includes
-  const vector<t_program*>& includes = program_->get_includes();
-  for (size_t i = 0; i < includes.size(); ++i) {
-    result += "#import \"" + includes[i]->get_name() + ".h\"" + "\n";
-  }
-  result += "\n";
-
-  return result;
-}
-
-
-/**
- * Finish up generation.
- */
-void t_cocoa_generator::close_generator()
-{
-  // stick our constants declarations at the end of the header file
-  // since they refer to things we are defining.
-  f_header_ << constants_declarations_ << endl;
-}
-
-/**
- * Generates a typedef. This is just a simple 1-liner in objective-c
- *
- * @param ttypedef The type definition
- */
-void t_cocoa_generator::generate_typedef(t_typedef* ttypedef) {
-  f_header_ <<
-    indent() << "typedef " << type_name(ttypedef->get_type()) << " " << cocoa_prefix_ << ttypedef->get_symbolic() << ";" << endl <<
-    endl;
-}
-
-/**
- * Generates code for an enumerated type. In Objective-C, this is
- * essentially the same as the thrift definition itself, using the
- * enum keyword in Objective-C.  For namespace purposes, the name of
- * the enum plus an underscore is prefixed onto each element.
- *
- * @param tenum The enumeration
- */
-void t_cocoa_generator::generate_enum(t_enum* tenum) {
-  f_header_ <<
-    indent() << "enum " << cocoa_prefix_ << tenum->get_name() << " {" << endl;
-  indent_up();
-
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  bool first = true;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    if (first) {
-      first = false;
-    } else {
-      f_header_ <<
-        "," << endl;
-    }
-    f_header_ <<
-      indent() << tenum->get_name() << "_" << (*c_iter)->get_name();
-    f_header_ <<
-      " = " << (*c_iter)->get_value();
-  }
-
-  indent_down();
-  f_header_ <<
-    endl <<
-    "};" << endl <<
-    endl;
-}
-
-/**
- * Generates a class that holds all the constants.  Primitive values
- * could have been placed outside this class, but I just put
- * everything in for consistency.
- */
-void t_cocoa_generator::generate_consts(std::vector<t_const*> consts) {
-  std::ostringstream const_interface;
-  string constants_class_name = cocoa_prefix_ + program_name_ + "Constants";
-
-  const_interface << "@interface " << constants_class_name << " : NSObject ";
-  scope_up(const_interface);
-  scope_down(const_interface);
-
-  // getter method for each constant defined.
-  vector<t_const*>::iterator c_iter;
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    string name = (*c_iter)->get_name();
-    t_type* type = (*c_iter)->get_type();
-    const_interface <<
-      "+ (" << type_name(type) << ") " << name << ";" << endl;
-  }
-
-  const_interface << "@end";
-
-  // this gets spit into the header file in ::close_generator
-  constants_declarations_ = const_interface.str();
-
-  // static variables in the .m hold all constant values
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    string name = (*c_iter)->get_name();
-    t_type* type = (*c_iter)->get_type();
-    f_impl_ <<
-      "static " << type_name(type) << " " << cocoa_prefix_ << name;
-    if (!type->is_container() && !type->is_struct()) {
-      f_impl_ << " = " << render_const_value(f_impl_, type, (*c_iter)->get_value());
-    }
-    f_impl_ << ";" << endl;
-  }
-  f_impl_ << endl;
-
-  f_impl_ << "@implementation " << constants_class_name << endl;
-
-  // initialize complex constants when the class is loaded
-  f_impl_ << "+ (void) initialize ";
-  scope_up(f_impl_);
-
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    if ((*c_iter)->get_type()->is_container() ||
-        (*c_iter)->get_type()->is_struct()) {
-      print_const_value(f_impl_, 
-           cocoa_prefix_+(*c_iter)->get_name(),
-           (*c_iter)->get_type(),
-           (*c_iter)->get_value(),
-           false, false);
-      f_impl_ << ";" << endl;
-    }
-  }
-  scope_down(f_impl_);
-
-  // getter method for each constant
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    string name = (*c_iter)->get_name();
-    t_type* type = (*c_iter)->get_type();
-    f_impl_ <<
-      "+ (" << type_name(type) << ") " << name;
-    scope_up(f_impl_);
-    indent(f_impl_) << "return " << cocoa_prefix_ << name << ";" << endl;
-    scope_down(f_impl_);
-  }
-
-  f_impl_ << "@end" << endl << endl;
-}
-
-
-/**
- * Generates a struct definition for a thrift data type. This is a class
- * with protected data members, read(), write(), and getters and setters.
- *
- * @param tstruct The struct definition
- */
-void t_cocoa_generator::generate_struct(t_struct* tstruct) {
-  generate_cocoa_struct_interface(f_header_, tstruct, false);
-  generate_cocoa_struct_implementation(f_impl_, tstruct, false);
-}
-
-/**
- * Exceptions are structs, but they inherit from NSException
- *
- * @param tstruct The struct definition
- */
-void t_cocoa_generator::generate_xception(t_struct* txception) {
-  generate_cocoa_struct_interface(f_header_, txception, true);
-  generate_cocoa_struct_implementation(f_impl_, txception, true);
-}
-
-
-/**
- * Generate the interface for a struct
- *
- * @param tstruct The struct definition
- */
-void t_cocoa_generator::generate_cocoa_struct_interface(ofstream &out,
-                                                      t_struct* tstruct,
-                                                      bool is_exception) {
-  out << "@interface " << cocoa_prefix_ << tstruct->get_name() << " : ";
-
-  if (is_exception) {
-    out << "NSException ";
-  } else {
-    out << "NSObject ";
-  }
-  out << "<TBase, NSCoding> ";
-
-  scope_up(out);
-
-  // members are protected.  this is redundant, but explicit.
-  //  f_header_ << endl << "@protected:" << endl;
-
-  const vector<t_field*>& members = tstruct->get_members();
-
-  // member varialbes
-  vector<t_field*>::const_iterator m_iter;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    out << indent() << declare_field(*m_iter) << endl;
-  }
-
-  if (members.size() > 0) {
-    out << endl;
-    // isset fields
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      indent(out) <<
-        "BOOL __" << (*m_iter)->get_name() << "_isset;" <<  endl;
-    }
-  }
-
-  scope_down(out);
-  out << endl;
-
-  // properties
-  if (members.size() > 0) {
-    out << "#if TARGET_OS_IPHONE || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)" << endl;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      out << indent() << declare_property(*m_iter) << endl;
-    }
-    out << "#endif" << endl << endl;
-  }
-
-  // default initializer
-  out << indent() << "- (id) init;" << endl;
-
-  // initializer for all fields
-  if (!members.empty()) {
-    generate_cocoa_struct_initializer_signature(out, tstruct);
-    out << ";" << endl;
-  }
-  out << endl;
-
-  // read and write
-  out << "- (void) read: (id <TProtocol>) inProtocol;" << endl;
-  out << "- (void) write: (id <TProtocol>) outProtocol;" << endl;
-  out << endl;
-
-  // validator
-  out << "- (void) validate;" << endl << endl;
-
-  // getters and setters
-  generate_cocoa_struct_field_accessor_declarations(out, tstruct, is_exception);
-
-  out << "@end" << endl << endl;
-}
-
-
-/**
- * Generate signature for initializer of struct with a parameter for
- * each field.
- */
-void t_cocoa_generator::generate_cocoa_struct_initializer_signature(ofstream &out,
-                                                                  t_struct* tstruct) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  indent(out) << "- (id) initWith";
-  for (m_iter = members.begin(); m_iter != members.end(); ) {
-    if (m_iter == members.begin()) {
-      out << capitalize((*m_iter)->get_name());
-    } else {
-      out << (*m_iter)->get_name();
-    }
-    out << ": (" << type_name((*m_iter)->get_type()) << ") " <<
-      (*m_iter)->get_name();
-    ++m_iter;
-    if (m_iter != members.end()) {
-      out << " ";
-    }
-  }
-}
-
-/**
- * Generate getter and setter declarations for all fields, plus an
- * IsSet getter.
- */
-void t_cocoa_generator::generate_cocoa_struct_field_accessor_declarations(ofstream &out,
-                                                                          t_struct* tstruct,
-                                                                          bool is_exception) {
-  (void) is_exception;
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    out << indent() << "#if !__has_feature(objc_arc)" << endl;
-    out << indent() << "- (" << type_name((*m_iter)->get_type()) << ") " << decapitalize((*m_iter)->get_name()) << ";" << endl;
-    out << indent() << "- (void) set" << capitalize((*m_iter)->get_name()) <<
-      ": (" << type_name((*m_iter)->get_type()) << ") " << (*m_iter)->get_name() << ";" << endl;
-    out << indent() << "#endif" << endl;
-    out << indent() << "- (BOOL) " << (*m_iter)->get_name() << "IsSet;" << endl << endl;
-  }
-}
-
-
-/**
- * Generate the initWithCoder method for this struct so it's compatible with
- * the NSCoding protocol
- */
-void t_cocoa_generator::generate_cocoa_struct_init_with_coder_method(ofstream &out,
-                                                                     t_struct* tstruct,
-                                                                     bool is_exception) 
-{
-  indent(out) << "- (id) initWithCoder: (NSCoder *) decoder" << endl;
-  scope_up(out);
-  if (is_exception) {
-    // NSExceptions conform to NSCoding, so we can call super
-    out << indent() << "self = [super initWithCoder: decoder];" << endl;
-  } else {
-    out << indent() << "self = [super init];" << endl;
-  }
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* t = get_true_type((*m_iter)->get_type());
-    out << indent() << "if ([decoder containsValueForKey: @\""<< (*m_iter)->get_name() <<"\"])" << endl;
-    scope_up(out);
-    out << indent() << "__" << (*m_iter)->get_name() << " = ";
-    if (type_can_be_null(t)) 
-    {
-      out << "[[decoder decodeObjectForKey: @\"" << (*m_iter)->get_name() << "\"] retain_stub];" << endl;
-    }
-    else if (t->is_enum()) 
-    {
-      out << "[decoder decodeIntForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
-    }
-    else 
-    {
-      t_base_type::t_base tbase = ((t_base_type *) t)->get_base();
-      switch (tbase)
-      {
-        case t_base_type::TYPE_BOOL:
-          out << "[decoder decodeBoolForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
-          break;
-        case t_base_type::TYPE_BYTE:
-          out << "[decoder decodeIntForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
-          break;
-        case t_base_type::TYPE_I16:
-          out << "[decoder decodeIntForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
-          break;
-        case t_base_type::TYPE_I32:
-          out << "[decoder decodeInt32ForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
-          break;
-        case t_base_type::TYPE_I64:
-          out << "[decoder decodeInt64ForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
-          break;
-        case t_base_type::TYPE_DOUBLE:
-          out << "[decoder decodeDoubleForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
-          break;
-        default:    
-          throw "compiler error: don't know how to decode thrift type: " + t_base_type::t_base_name(tbase);
-      }
-    }
-    out << indent() << "__" << (*m_iter)->get_name() << "_isset = YES;" << endl;
-    scope_down(out);
-  }
-  
-  out << indent() << "return self;" << endl;
-  scope_down(out);
-  out << endl;
-}
-
-
-/**
- * Generate the encodeWithCoder method for this struct so it's compatible with
- * the NSCoding protocol
- */
-void t_cocoa_generator::generate_cocoa_struct_encode_with_coder_method(ofstream &out,
-                                                                       t_struct* tstruct,
-                                                                       bool is_exception) 
-{
-  indent(out) << "- (void) encodeWithCoder: (NSCoder *) encoder" << endl;
-  scope_up(out);
-  if (is_exception) {
-    // NSExceptions conform to NSCoding, so we can call super
-    out << indent() << "[super encodeWithCoder: encoder];" << endl;
-  }
-  
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* t = get_true_type((*m_iter)->get_type());
-    out << indent() << "if (__"<< (*m_iter)->get_name() <<"_isset)" << endl;
-    scope_up(out);
-    //out << indent() << "__" << (*m_iter)->get_name() << " = ";
-    if (type_can_be_null(t)) 
-    {
-      out << indent() << "[encoder encodeObject: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
-    }
-    else if (t->is_enum()) 
-    {
-      out << indent() << "[encoder encodeInt: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
-    }
-    else 
-    {
-      t_base_type::t_base tbase = ((t_base_type *) t)->get_base();
-      switch (tbase)
-      {
-        case t_base_type::TYPE_BOOL:
-          out << indent() << "[encoder encodeBool: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
-          break;
-        case t_base_type::TYPE_BYTE:
-          out << indent() << "[encoder encodeInt: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
-          break;
-        case t_base_type::TYPE_I16:
-          out << indent() << "[encoder encodeInt: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
-          break;
-        case t_base_type::TYPE_I32:
-          out << indent() << "[encoder encodeInt32: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
-          break;
-        case t_base_type::TYPE_I64:
-          out << indent() << "[encoder encodeInt64: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
-          break;
-        case t_base_type::TYPE_DOUBLE:
-          out << indent() << "[encoder encodeDouble: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
-          break;
-        default:    
-          throw "compiler error: don't know how to encode thrift type: " + t_base_type::t_base_name(tbase);
-      }
-    }
-    scope_down(out);
-  }
-  
-  scope_down(out);
-  out << endl;
-}
-
-
-/**
- * Generate struct implementation.
- *
- * @param tstruct      The struct definition
- * @param is_exception Is this an exception?
- * @param is_result    If this is a result it needs a different writer
- */
-void t_cocoa_generator::generate_cocoa_struct_implementation(ofstream &out,
-                                                             t_struct* tstruct,
-                                                             bool is_exception,
-                                                             bool is_result) {
-  indent(out) <<
-    "@implementation " << cocoa_prefix_ << tstruct->get_name() << endl << endl;
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  // exceptions need to call the designated initializer on NSException
-  if (is_exception) {
-    out << indent() << "- (id) init" << endl;
-    scope_up(out);
-    out << indent() << "return [super initWithName: @\"" << tstruct->get_name() <<
-        "\" reason: @\"unknown\" userInfo: nil];" << endl;
-    scope_down(out);
-    out << endl;
-  } else {
-    // struct
-
-    // default initializer
-    // setup instance variables with default values
-    indent(out) << "- (id) init" << endl;
-    scope_up(out);
-    indent(out) << "self = [super init];" << endl;
-    if (members.size() > 0) {
-      out << "#if TARGET_OS_IPHONE || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)" << endl;
-      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-        t_type* t = get_true_type((*m_iter)->get_type());
-        if ((*m_iter)->get_value() != NULL) {
-          print_const_value(out, "self."+(*m_iter)->get_name(), t, (*m_iter)->get_value(), false, true);
-        }
-      }
-      out << "#endif" << endl;
-    }
-    indent(out) << "return self;" << endl;
-    scope_down(out);
-    out << endl;
-  }
-
-  // initializer with all fields as params
-  if (!members.empty()) {
-    generate_cocoa_struct_initializer_signature(out, tstruct);
-    out << endl;
-    scope_up(out);
-    if (is_exception) {
-      out << indent() << "self = [self init];" << endl;
-    } else {
-      out << indent() << "self = [super init];" << endl;
-    }
-
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      t_type* t = get_true_type((*m_iter)->get_type());
-      out << indent() << "__" << (*m_iter)->get_name() << " = ";
-      if (type_can_be_null(t)) {
-        out << "[" << (*m_iter)->get_name() << " retain_stub];" << endl;
-      } else {
-        out << (*m_iter)->get_name() << ";" << endl;
-      }
-      out << indent() << "__" << (*m_iter)->get_name() << "_isset = YES;" << endl;
-    }
-
-    out << indent() << "return self;" << endl;
-    scope_down(out);
-    out << endl;
-  }
-  
-  // initWithCoder for NSCoding
-  generate_cocoa_struct_init_with_coder_method(out, tstruct, is_exception);
-  // encodeWithCoder for NSCoding
-  generate_cocoa_struct_encode_with_coder_method(out, tstruct, is_exception);  
-
-  // dealloc
-  if (!members.empty()) {
-    out << "- (void) dealloc" << endl;
-    scope_up(out);
-
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      t_type* t = get_true_type((*m_iter)->get_type());
-      if (type_can_be_null(t)) {
-        indent(out) << "[__" << (*m_iter)->get_name() << " release_stub];" << endl;
-      }
-    }
-
-    out << indent() << "[super dealloc_stub];" << endl;
-    scope_down(out);
-    out << endl;
-  }
-
-  // the rest of the methods
-  generate_cocoa_struct_field_accessor_implementations(out, tstruct, is_exception);
-  generate_cocoa_struct_reader(out, tstruct);
-  if (is_result) {
-    generate_cocoa_struct_result_writer(out, tstruct);
-  } else {
-    generate_cocoa_struct_writer(out, tstruct);
-  }
-  generate_cocoa_struct_validator(out, tstruct);
-  generate_cocoa_struct_description(out, tstruct);
-
-  out << "@end" << endl << endl;
-}
-
-
-/**
- * Generates a function to read all the fields of the struct.
- *
- * @param tstruct The struct definition
- */
-void t_cocoa_generator::generate_cocoa_struct_reader(ofstream& out,
-                                                     t_struct* tstruct) {
-  out <<
-    "- (void) read: (id <TProtocol>) inProtocol" << endl;
-  scope_up(out);
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  // Declare stack tmp variables
-  indent(out) << "NSString * fieldName;" << endl;
-  indent(out) << "int fieldType;" << endl;
-  indent(out) << "int fieldID;" << endl;
-  out << endl;
-
-  indent(out) << "[inProtocol readStructBeginReturningName: NULL];" << endl;
-
-  // Loop over reading in fields
-  indent(out) <<
-    "while (true)" << endl;
-    scope_up(out);
-
-    // Read beginning field marker
-    indent(out) <<
-      "[inProtocol readFieldBeginReturningName: &fieldName type: &fieldType fieldID: &fieldID];" << endl;
-
-    // Check for field STOP marker and break
-    indent(out) <<
-      "if (fieldType == TType_STOP) { " << endl;
-    indent_up();
-    indent(out) <<
-      "break;" << endl;
-    indent_down();
-    indent(out) <<
-      "}" << endl;
-
-    // Switch statement on the field we are reading
-    indent(out) <<
-      "switch (fieldID)" << endl;
-
-      scope_up(out);
-
-      // Generate deserialization code for known cases
-      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-        indent(out) <<
-          "case " << (*f_iter)->get_key() << ":" << endl;
-        indent_up();
-        indent(out) <<
-          "if (fieldType == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
-        indent_up();
-
-        generate_deserialize_field(out, *f_iter, "fieldValue");
-        indent(out) << call_field_setter(*f_iter, "fieldValue") << endl;
-        // if this is an allocated field, release it since the struct
-        // is now retaining it
-        if (type_can_be_null((*f_iter)->get_type())) {
-          // deserialized strings are autorelease, so don't release them
-          if (!(get_true_type((*f_iter)->get_type())->is_string())) {
-            indent(out) << "[fieldValue release_stub];" << endl;
-          }
-        }
-
-        indent_down();
-        out << indent() << "} else { " << endl;
-        if (log_unexpected_) {
-          out << indent() << "  NSLog(@\"%s: field ID %i has unexpected type %i.  Skipping.\", __PRETTY_FUNCTION__, fieldID, fieldType);" << endl;
-        }
-        out << indent() << "  [TProtocolUtil skipType: fieldType onProtocol: inProtocol];" << endl <<
-          indent() << "}" << endl <<
-          indent() << "break;" << endl;
-        indent_down();
-      }
-
-      // In the default case we skip the field
-      out << indent() << "default:" << endl;
-      if (log_unexpected_) {
-        out << indent() << "  NSLog(@\"%s: unexpected field ID %i with type %i.  Skipping.\", __PRETTY_FUNCTION__, fieldID, fieldType);" << endl;
-      }
-      out << indent() << "  [TProtocolUtil skipType: fieldType onProtocol: inProtocol];" << endl <<
-        indent() << "  break;" << endl;
-
-      scope_down(out);
-
-    // Read field end marker
-    indent(out) <<
-      "[inProtocol readFieldEnd];" << endl;
-
-    scope_down(out);
-
-    out <<
-      indent() << "[inProtocol readStructEnd];" << endl;
-
-    // performs various checks (e.g. check that all required fields are set)
-    if (validate_required_) {
-      out <<
-        indent() << "[self validate];" << endl;
-    }
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-/**
- * Generates a function to write all the fields of the struct
- *
- * @param tstruct The struct definition
- */
-void t_cocoa_generator::generate_cocoa_struct_writer(ofstream& out,
-                                                     t_struct* tstruct) {
-  out <<
-    indent() << "- (void) write: (id <TProtocol>) outProtocol {" << endl;
-  indent_up();
-
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  out <<
-    indent() << "[outProtocol writeStructBeginWithName: @\"" << name << "\"];" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    out <<
-      indent() << "if (__" << (*f_iter)->get_name() << "_isset) {" << endl;
-    indent_up();
-    bool null_allowed = type_can_be_null((*f_iter)->get_type());
-    if (null_allowed) {
-      out <<
-        indent() << "if (__" << (*f_iter)->get_name() << " != nil) {" << endl;
-      indent_up();
-    }
-
-    indent(out) << "[outProtocol writeFieldBeginWithName: @\"" <<
-      (*f_iter)->get_name() << "\" type: " << type_to_enum((*f_iter)->get_type()) <<
-      " fieldID: " << (*f_iter)->get_key() << "];" << endl;
-
-    // Write field contents
-    generate_serialize_field(out, *f_iter, "__"+(*f_iter)->get_name());
-
-    // Write field closer
-    indent(out) <<
-      "[outProtocol writeFieldEnd];" << endl;
-
-    if (null_allowed) {
-      scope_down(out);
-    }
-    scope_down(out);
-  }
-  // Write the struct map
-  out <<
-    indent() << "[outProtocol writeFieldStop];" << endl <<
-    indent() << "[outProtocol writeStructEnd];" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-/**
- * Generates a function to write all the fields of the struct, which
- * is a function result. These fields are only written if they are
- * set, and only one of them can be set at a time.
- *
- * @param tstruct The struct definition
- */
-void t_cocoa_generator::generate_cocoa_struct_result_writer(ofstream& out,
-                                                            t_struct* tstruct) {
-  out <<
-    indent() << "- (void) write: (id <TProtocol>) outProtocol {" << endl;
-  indent_up();
-
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  out <<
-    indent() << "[outProtocol writeStructBeginWithName: @\"" << name << "\"];" << endl;
-
-  bool first = true;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (first) {
-      first = false;
-      out <<
-        endl <<
-        indent() << "if ";
-    } else {
-      out <<
-        " else if ";
-    }
-
-    out <<
-      "(__" << (*f_iter)->get_name() << "_isset) {" << endl;
-    indent_up();
-
-    bool null_allowed = type_can_be_null((*f_iter)->get_type());
-    if (null_allowed) {
-      out <<
-        indent() << "if (__" << (*f_iter)->get_name() << " != nil) {" << endl;
-      indent_up();
-    }
-
-    indent(out) << "[outProtocol writeFieldBeginWithName: @\"" <<
-      (*f_iter)->get_name() << "\" type: " << type_to_enum((*f_iter)->get_type()) <<
-      " fieldID: " << (*f_iter)->get_key() << "];" << endl;
-
-    // Write field contents
-    generate_serialize_field(out, *f_iter, "__"+(*f_iter)->get_name());
-
-    // Write field closer
-    indent(out) <<
-      "[outProtocol writeFieldEnd];" << endl;
-
-    if (null_allowed) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-
-    indent_down();
-    indent(out) << "}";
-  }
-  // Write the struct map
-  out <<
-    endl <<
-    indent() << "[outProtocol writeFieldStop];" << endl <<
-    indent() << "[outProtocol writeStructEnd];" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-/**
- * Generates a function to perform various checks
- * (e.g. check that all required fields are set)
- *
- * @param tstruct The struct definition
- */
-void t_cocoa_generator::generate_cocoa_struct_validator(ofstream& out,
-                                                        t_struct* tstruct) {
-  out <<
-    indent() << "- (void) validate {" << endl;
-  indent_up();
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-    
-  out << indent() << "// check for required fields" << endl;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = (*f_iter);
-    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
-      out <<
-        indent() << "if (!__" << field->get_name() << "_isset) {" << endl <<
-        indent() << "  @throw [TProtocolException exceptionWithName: @\"TProtocolException\"" << endl <<
-        indent() << "                             reason: @\"Required field '" << (*f_iter)->get_name() << "' is not set.\"];" << endl <<
-        indent() << "}" << endl;
-    }
-  }
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-/**
- * Generate property accessor methods for all fields in the struct.
- * getter, setter, isset getter.
- *
- * @param tstruct The struct definition
- */
-void t_cocoa_generator::generate_cocoa_struct_field_accessor_implementations(ofstream& out,
-                                                                             t_struct* tstruct,
-                                                                             bool is_exception) {
-  (void) is_exception;
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = *f_iter;
-    t_type* type = get_true_type(field->get_type());
-    std::string field_name = field->get_name();
-    std::string cap_name = field_name;
-    cap_name[0] = toupper(cap_name[0]);
-
-    // Simple getter
-    indent(out) << "- (" << type_name(type) << ") ";
-    out << field_name << " {" << endl;
-    indent_up();
-    if (!type_can_be_null(type)) {
-      indent(out) << "return __" << field_name << ";" << endl;
-    } else {
-      indent(out) << "return [[__" << field_name << " retain_stub] autorelease_stub];" << endl;
-    }
-    indent_down();
-    indent(out) << "}" << endl << endl;
-
-    // Simple setter
-    indent(out) << "- (void) set" << cap_name << ": (" << type_name(type) <<
-      ") " << field_name << " {" << endl;
-    indent_up();
-    if (!type_can_be_null(type)) {
-      indent(out) << "__" << field_name << " = " << field_name << ";" << endl;
-    } else {
-      indent(out) << "[" << field_name << " retain_stub];" << endl;
-      indent(out) << "[__" << field_name << " release_stub];" << endl;
-      indent(out) << "__" << field_name << " = " << field_name << ";" << endl;
-    }
-    indent(out) << "__" << field_name << "_isset = YES;" << endl;
-    indent_down();
-    indent(out) << "}" << endl << endl;
-
-    // IsSet
-    indent(out) << "- (BOOL) " << field_name << "IsSet {" << endl;
-    indent_up();
-    indent(out) << "return __" << field_name << "_isset;" << endl;
-    indent_down();
-    indent(out) << "}" << endl << endl;
-
-    // Unsetter - do we need this?
-    indent(out) << "- (void) unset" << cap_name << " {" << endl;
-    indent_up();
-    if (type_can_be_null(type)) {
-      indent(out) << "[__" << field_name << " release_stub];" << endl;
-      indent(out) << "__" << field_name << " = nil;" << endl;
-    }
-    indent(out) << "__" << field_name << "_isset = NO;" << endl;
-    indent_down();
-    indent(out) << "}" << endl << endl;
-  }
-}
-
-/**
- * Generates a description method for the given struct
- *
- * @param tstruct The struct definition
- */
-void t_cocoa_generator::generate_cocoa_struct_description(ofstream& out,
-                                                          t_struct* tstruct) {
-  out <<
-    indent() << "- (NSString *) description {" << endl;
-  indent_up();
-
-  out <<
-    indent() << "NSMutableString * ms = [NSMutableString stringWithString: @\"" <<
-    tstruct->get_name() << "(\"];" << endl;
-
-  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;
-      indent(out) << "[ms appendString: @\"" << (*f_iter)->get_name() << ":\"];" << endl;
-    } else {
-      indent(out) << "[ms appendString: @\"," << (*f_iter)->get_name() << ":\"];" << endl;
-    }
-    t_type* ttype = (*f_iter)->get_type();
-    indent(out) << "[ms appendFormat: @\"" << format_string_for_type(ttype) << "\", __" <<
-      (*f_iter)->get_name() << "];" << endl;
-  }
-  out <<
-    indent() << "[ms appendString: @\")\"];" << endl <<
-    indent() << "return [NSString stringWithString: ms];" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl <<
-    endl;
-}
-
-
-/**
- * Generates a thrift service.  In Objective-C this consists of a
- * protocol definition, a client interface and a client implementation.
- *
- * @param tservice The service definition
- */
-void t_cocoa_generator::generate_service(t_service* tservice) {
-  generate_cocoa_service_protocol(f_header_, tservice);
-  generate_cocoa_service_client_interface(f_header_, tservice);
-  generate_cocoa_service_server_interface(f_header_, tservice);
-  generate_cocoa_service_helpers(tservice);
-  generate_cocoa_service_client_implementation(f_impl_, tservice);
-  generate_cocoa_service_server_implementation(f_impl_, tservice);
-}
-
-
-/**
- * Generates structs for all the service return types
- *
- * @param tservice The service
- */
-void t_cocoa_generator::generate_cocoa_service_helpers(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    t_struct* ts = (*f_iter)->get_arglist();
-    generate_cocoa_struct_interface(f_impl_, ts, false);
-    generate_cocoa_struct_implementation(f_impl_, ts, false, false);  
-    generate_function_helpers(*f_iter);
-  }
-}
-
-string t_cocoa_generator::function_result_helper_struct_type(t_function* tfunction) {
-  if (tfunction->is_oneway()) {
-    return capitalize(tfunction->get_name());
-  } else {
-    return capitalize(tfunction->get_name()) + "_result";
-  }
-}
-
-
-string t_cocoa_generator::function_args_helper_struct_type(t_function* tfunction) {
-  return tfunction->get_name() + "_args";
-}
-
-
-/**
- * Generates a struct and helpers for a function.
- *
- * @param tfunction The function
- */
-void t_cocoa_generator::generate_function_helpers(t_function* tfunction) {
-  if (tfunction->is_oneway()) {
-    return;
-  }
-
-  // create a result struct with a success field of the return type,
-  // and a field for each type of exception thrown
-  t_struct result(program_, function_result_helper_struct_type(tfunction));
-  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 the result struct
-  generate_cocoa_struct_interface(f_impl_, &result, false);
-  generate_cocoa_struct_implementation(f_impl_, &result, false, true);  
-}
-
-
-/**
- * Generates a service protocol definition.
- *
- * @param tservice The service to generate a protocol definition for
- */
-void t_cocoa_generator::generate_cocoa_service_protocol(ofstream& out,
-                                                        t_service* tservice) {
-  out << "@protocol " << cocoa_prefix_ << tservice->get_name() << " <NSObject>" << endl;
-
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    out << "- " << function_signature(*f_iter) << ";" <<
-      "  // throws ";
-    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) {
-      out << type_name((*x_iter)->get_type()) + ", ";
-    }
-    out << "TException" << endl;
-  }
-  out << "@end" << endl << endl;
-}
-
-
-/**
- * Generates a service client interface definition.
- *
- * @param tservice The service to generate a client interface definition for
- */
-void t_cocoa_generator::generate_cocoa_service_client_interface(ofstream& out,
-                                                                t_service* tservice) {
-  out << "@interface " << cocoa_prefix_ << tservice->get_name() << "Client : NSObject <" <<
-    cocoa_prefix_ << tservice->get_name() << "> ";
-
-  scope_up(out);
-  out << indent() << "id <TProtocol> inProtocol;" << endl;
-  out << indent() << "id <TProtocol> outProtocol;" << endl;
-  scope_down(out);
-
-  out << "- (id) initWithProtocol: (id <TProtocol>) protocol;" << endl;
-  out << "- (id) initWithInProtocol: (id <TProtocol>) inProtocol outProtocol: (id <TProtocol>) outProtocol;" << endl;
-  out << "@end" << endl << endl;
-}
-
-
-/**
- * Generates a service server interface definition. In other words, the TProcess implementation for the
- * service definition.
- *
- * @param tservice The service to generate a client interface definition for
- */
-void t_cocoa_generator::generate_cocoa_service_server_interface(ofstream& out,
-                                                                t_service* tservice) {
-  out << "@interface " << cocoa_prefix_ << tservice->get_name() << "Processor : NSObject <TProcessor> ";
-  
-  scope_up(out);
-  out << indent() << "id <" << cocoa_prefix_ << tservice->get_name() <<"> mService;" << endl;
-  out << indent() << "NSDictionary * mMethodMap;" << endl;
-  scope_down(out);
-  
-  out << "- (id) initWith" << tservice->get_name() << ": (id <" << cocoa_prefix_ << tservice->get_name() << ">) service;" << endl;
-  out << "- (id<"<<cocoa_prefix_ << tservice->get_name() << ">) service;" << endl;
-
-  out << "@end" << endl << endl;
-}
-
-
-/**
- * Generates a service client implementation.
- *
- * @param tservice The service to generate an implementation for
- */
-void t_cocoa_generator::generate_cocoa_service_client_implementation(ofstream& out,
-                                                                     t_service* tservice) {
-  out << "@implementation " << cocoa_prefix_ << tservice->get_name() << "Client" << endl;
-
-  // initializers
-  out << "- (id) initWithProtocol: (id <TProtocol>) protocol" << endl;
-  scope_up(out);
-  out << indent() << "return [self initWithInProtocol: protocol outProtocol: protocol];" << endl;
-  scope_down(out);
-  out << endl;
-
-  out << "- (id) initWithInProtocol: (id <TProtocol>) anInProtocol outProtocol: (id <TProtocol>) anOutProtocol" << endl;
-  scope_up(out);
-  out << indent() << "self = [super init];" << endl;
-  out << indent() << "inProtocol = [anInProtocol retain_stub];" << endl;
-  out << indent() << "outProtocol = [anOutProtocol retain_stub];" << endl;
-  out << indent() << "return self;" << endl;
-  scope_down(out);
-  out << endl;
-
-  // dealloc
-  out << "- (void) dealloc" << endl;
-  scope_up(out);
-  out << indent() << "[inProtocol release_stub];" << endl;
-  out << indent() << "[outProtocol release_stub];" << endl;
-  out << indent() << "[super dealloc_stub];" << endl;
-  scope_down(out);
-  out << 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) {
-    string funname = (*f_iter)->get_name();
-
-    t_function send_function(g_type_void,
-                             string("send_") + (*f_iter)->get_name(),
-                             (*f_iter)->get_arglist());
-
-    string argsname = (*f_iter)->get_name() + "_args";
-
-    // Open function
-    indent(out) <<
-      "- " << function_signature(&send_function) << endl;
-    scope_up(out);
-
-    // Serialize the request
-    out <<
-      indent() << "[outProtocol writeMessageBeginWithName: @\"" << funname << "\"" <<
-      " type: TMessageType_CALL" <<
-      " sequenceID: 0];" << endl;
-
-    out <<
-      indent() << "[outProtocol writeStructBeginWithName: @\"" << argsname << "\"];" << endl;
-
-    // write out function parameters
-    t_struct* arg_struct = (*f_iter)->get_arglist();
-    const vector<t_field*>& fields = arg_struct->get_members();
-    vector<t_field*>::const_iterator fld_iter;
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      string fieldName = (*fld_iter)->get_name();
-      if (type_can_be_null((*fld_iter)->get_type())) {
-        out << indent() << "if (" << fieldName << " != nil)";
-        scope_up(out);
-      }
-      out <<
-        indent() << "[outProtocol writeFieldBeginWithName: @\"" << fieldName << "\""
-        " type: " << type_to_enum((*fld_iter)->get_type()) <<
-        " fieldID: " << (*fld_iter)->get_key() << "];" << endl;
-
-      generate_serialize_field(out, *fld_iter, fieldName);
-
-      out <<
-        indent() << "[outProtocol writeFieldEnd];" << endl;
-
-      if (type_can_be_null((*fld_iter)->get_type())) {
-        scope_down(out);
-      }
-    }
-
-    out <<
-      indent() << "[outProtocol writeFieldStop];" << endl;
-    out <<
-      indent() << "[outProtocol writeStructEnd];" << endl;
-
-    out <<
-      indent() << "[outProtocol writeMessageEnd];" << endl <<
-      indent() << "[[outProtocol transport] flush];" << endl;
-
-    scope_down(out);
-    out << endl;
-
-    if (!(*f_iter)->is_oneway()) {
-      t_struct noargs(program_);
-      t_function recv_function((*f_iter)->get_returntype(),
-                               string("recv_") + (*f_iter)->get_name(),
-                               &noargs,
-                               (*f_iter)->get_xceptions());
-      // Open function
-      indent(out) <<
-        "- " << function_signature(&recv_function) << endl;
-      scope_up(out);
-
-      // TODO(mcslee): Message validation here, was the seqid etc ok?
-
-      // check for an exception
-      out <<
-        indent() << "int msgType = 0;" << endl <<
-        indent() << "[inProtocol readMessageBeginReturningName: nil type: &msgType sequenceID: NULL];" << endl <<
-        indent() << "if (msgType == TMessageType_EXCEPTION) {" << endl <<
-        indent() << "  TApplicationException * x = [TApplicationException read: inProtocol];" << endl <<
-        indent() << "  [inProtocol readMessageEnd];" << endl <<
-        indent() << "  @throw x;" << endl <<
-        indent() << "}" << endl;
-
-      // FIXME - could optimize here to reduce creation of temporary objects.
-      string resultname = function_result_helper_struct_type(*f_iter);
-      out <<
-        indent() << cocoa_prefix_ << resultname << " * result = [[[" << cocoa_prefix_ <<
-        resultname << " alloc] init] autorelease_stub];" << endl;
-      indent(out) << "[result read: inProtocol];" << endl;
-      indent(out) << "[inProtocol readMessageEnd];" << endl;
-
-      // Careful, only return _result if not a void function
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        out <<
-          indent() << "if ([result successIsSet]) {" << endl <<
-          indent() << "  return [result success];" << endl <<
-          indent() << "}" << 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) {
-        out <<
-          indent() << "if ([result " << (*x_iter)->get_name() << "IsSet]) {" << endl <<
-          indent() << "  @throw [result " << (*x_iter)->get_name() << "];" << endl <<
-          indent() << "}" << endl;
-      }
-
-      // If you get here it's an exception, unless a void function
-      if ((*f_iter)->get_returntype()->is_void()) {
-        indent(out) <<
-          "return;" << endl;
-      } else {
-        out <<
-          indent() << "@throw [TApplicationException exceptionWithType: TApplicationException_MISSING_RESULT" << endl <<
-          indent() << "                                         reason: @\"" << (*f_iter)->get_name() << " failed: unknown result\"];" << endl;
-      }
-
-      // Close function
-      scope_down(out);
-      out << endl;
-    }
-
-    // Open function
-    indent(out) <<
-      "- " << function_signature(*f_iter) << endl;
-    scope_up(out);
-    indent(out) <<
-      "[self send_" << funname;
-
-    // Declare the function arguments
-    bool first = true;
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      string fieldName = (*fld_iter)->get_name();
-      out << " ";
-      if (first) {
-        first = false;
-        out << ": " << fieldName;
-      } else {
-        out << fieldName << ": " << fieldName;
-      }
-    }
-    out << "];" << endl;
-
-    if (!(*f_iter)->is_oneway()) {
-      out << indent();
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        out << "return ";
-      }
-      out <<
-        "[self recv_" << funname << "];" << endl;
-    }
-    scope_down(out);
-    out << endl;
-  }
-
-  indent_down();
-
-  out << "@end" << endl << endl;
-}
-
-
-/**
- * Generates a service server implementation.  In other words the actual TProcessor implementation
- * for the service.
- *
- * @param tservice The service to generate an implementation for
- */
-void t_cocoa_generator::generate_cocoa_service_server_implementation(ofstream& out,
-                                                                     t_service* tservice) {
-  out << "@implementation " << cocoa_prefix_ << tservice->get_name() << "Processor" << endl;
-  indent_up();
-  
-  // initializer
-  out << endl;
-  out << "- (id) initWith" << tservice->get_name() << ": (id <" << cocoa_prefix_ << tservice->get_name() << ">) service" << endl;
-  scope_up(out);
-  out << indent() << "self = [super init];" << endl;
-  out << indent() << "if (!self) {" << endl;
-  out << indent() << "  return nil;" << endl;
-  out << indent() << "}" << endl;
-  out << indent() << "mService = [service retain_stub];" << endl;
-  out << indent() << "mMethodMap = [[NSMutableDictionary dictionary] retain_stub];" << endl;
-  
-  // generate method map for routing incoming calls
-  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) {
-    string funname = (*f_iter)->get_name();
-    scope_up(out);
-    out << indent() << "SEL s = @selector(process_" << funname << "_withSequenceID:inProtocol:outProtocol:);" << endl;
-    out << indent() << "NSMethodSignature * sig = [self methodSignatureForSelector: s];" << endl;
-    out << indent() << "NSInvocation * invocation = [NSInvocation invocationWithMethodSignature: sig];" << endl;
-    out << indent() << "[invocation setSelector: s];" << endl;
-    out << indent() << "[invocation retainArguments];" << endl;
-    out << indent() << "[mMethodMap setValue: invocation forKey: @\"" << funname << "\"];" << endl;
-    scope_down(out);
-  }
-  out << indent() << "return self;" << endl;
-  scope_down(out);
-  
-  // implementation of the 'service' method which returns the service associated with this
-  // processor
-  out << endl;
-  out << indent() << "- (id<"<<cocoa_prefix_ << tservice->get_name() << ">) service" << endl;
-  out << indent() << "{" << endl;
-  out << indent() << "  return [[mService retain_stub] autorelease_stub];" << endl;
-  out << indent() << "}" << endl;
-  
-  // implementation of the TProcess method, which dispatches the incoming call using the method map
-  out << endl;
-  out << indent() << "- (BOOL) processOnInputProtocol: (id <TProtocol>) inProtocol" << endl;
-  out << indent() << "                 outputProtocol: (id <TProtocol>) outProtocol" <<endl;
-  out << indent() << "{" << endl;
-  out << indent() << "  NSString * messageName;" << endl;
-  out << indent() << "  int messageType;" << endl;
-  out << indent() << "  int seqID;" << endl;
-  out << indent() << "  [inProtocol readMessageBeginReturningName: &messageName" << endl;
-  out << indent() << "                                       type: &messageType" << endl;
-  out << indent() << "                                 sequenceID: &seqID];" << endl;
-  out << indent() << "  NSInvocation * invocation = [mMethodMap valueForKey: messageName];" << endl;
-  out << indent() << "  if (invocation == nil) {" << endl;
-  out << indent() << "    [TProtocolUtil skipType: TType_STRUCT onProtocol: inProtocol];" << endl;
-  out << indent() << "    [inProtocol readMessageEnd];" << endl;
-  out << indent() << "    TApplicationException * x = [TApplicationException exceptionWithType: TApplicationException_UNKNOWN_METHOD reason: [NSString stringWithFormat: @\"Invalid method name: '%@'\", messageName]];" << endl;
-  out << indent() << "    [outProtocol writeMessageBeginWithName: messageName" << endl;
-  out << indent() << "                                      type: TMessageType_EXCEPTION" << endl;
-  out << indent() << "                                sequenceID: seqID];" << endl;
-  out << indent() << "    [x write: outProtocol];" << endl;
-  out << indent() << "    [outProtocol writeMessageEnd];" << endl;
-  out << indent() << "    [[outProtocol transport] flush];" << endl;
-  out << indent() << "    return YES;" << endl;
-  out << indent() << "  }" << endl;
-  out << indent() << "  // NSInvocation does not conform to NSCopying protocol" << endl;
-  out << indent() << "  NSInvocation * i = [NSInvocation invocationWithMethodSignature: [invocation methodSignature]];" << endl;
-  out << indent() << "  [i setSelector: [invocation selector]];" << endl;
-  out << indent() << "  [i setArgument: &seqID atIndex: 2];" << endl;
-  out << indent() << "  [i setArgument: &inProtocol atIndex: 3];" << endl;
-  out << indent() << "  [i setArgument: &outProtocol atIndex: 4];" << endl;
-  out << indent() << "  [i setTarget: self];" << endl;
-  out << indent() << "  [i invoke];" << endl;
-  out << indent() << "  return YES;" << endl;
-  out << indent() << "}" << endl;
-  
-  // generate a process_XXXX method for each service function, which reads args, calls the service, and writes results
-  functions = tservice->get_functions();
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    out << endl;
-    string funname = (*f_iter)->get_name();
-    out << indent() << "- (void) process_" << funname << "_withSequenceID: (int32_t) seqID inProtocol: (id<TProtocol>) inProtocol outProtocol: (id<TProtocol>) outProtocol" << endl;
-    scope_up(out);
-    string argstype = cocoa_prefix_ + function_args_helper_struct_type(*f_iter);
-    out << indent() << argstype << " * args = [[" << argstype << " alloc] init];" << endl;
-    out << indent() << "[args read: inProtocol];" << endl;
-    out << indent() << "[inProtocol readMessageEnd];" << endl;
-    
-    // prepare the result if not oneway
-    if (!(*f_iter)->is_oneway()) {
-        string resulttype = cocoa_prefix_ + function_result_helper_struct_type(*f_iter);
-        out << indent() << resulttype << " * result = [[" << resulttype << " alloc] init];" << endl;
-    }
-
-    // make the call to the actual service object
-    out << indent();
-    if (!(*f_iter)->get_returntype()->is_void()) {
-      out << "[result setSuccess: ";
-    }
-    out << "[mService " << funname;
-    // supplying arguments
-    t_struct* arg_struct = (*f_iter)->get_arglist();
-    const vector<t_field*>& fields = arg_struct->get_members();
-    vector<t_field*>::const_iterator fld_iter;
-    bool first = true;
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      string fieldName = (*fld_iter)->get_name();
-      if (first) {
-        first = false;
-        out << ": [args " << fieldName << "]";
-      } else {
-        out << " " << fieldName << ": [args " << fieldName << "]";
-      }
-    }
-    out << "]";
-    if (!(*f_iter)->get_returntype()->is_void()) {
-      out << "]";
-    }
-    out << ";" << endl;
-    
-    // write out the result if not oneway
-    if (!(*f_iter)->is_oneway()) {
-        out << indent() << "[outProtocol writeMessageBeginWithName: @\"" << funname << "\"" << endl;
-        out << indent() << "                                  type: TMessageType_REPLY" << endl;
-        out << indent() << "                            sequenceID: seqID];" << endl;
-        out << indent() << "[result write: outProtocol];" << endl;
-        out << indent() << "[outProtocol writeMessageEnd];" << endl;
-        out << indent() << "[[outProtocol transport] flush];" << endl;
-        out << indent() << "[result release_stub];" << endl;
-    }
-    out << indent() << "[args release_stub];" << endl;
-    
-    scope_down(out);
-  }
-  
-  // dealloc
-  out << endl;
-  out << "- (void) dealloc" << endl;
-  scope_up(out);
-  out << indent() << "[mService release_stub];" << endl;
-  out << indent() << "[mMethodMap release_stub];" << endl;
-  out << indent() << "[super dealloc_stub];" << endl;
-  scope_down(out);
-  out << endl;
-
-  indent_down();
-
-  out << "@end" << endl << endl;
-}
-
-
-/**
- * Deserializes a field of any type.
- *
- * @param tfield The field
- * @param fieldName The variable name for this field
- */
-void t_cocoa_generator::generate_deserialize_field(ofstream& out,
-                                                   t_field* tfield,
-                                                   string fieldName) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  if (type->is_void()) {
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
-      tfield->get_name();
-  }
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct(out,
-                                (t_struct*)type,
-                                fieldName);
-  } else if (type->is_container()) {
-    generate_deserialize_container(out, type, fieldName);
-  } else if (type->is_base_type() || type->is_enum()) {
-    indent(out) <<
-      type_name(type) << " " << fieldName << " = [inProtocol ";
-
-    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: " +
-          tfield->get_name();
-        break;
-      case t_base_type::TYPE_STRING:
-        if (((t_base_type*)type)->is_binary()) {
-          out << "readBinary];";
-        } else {
-          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 Objective-C name for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      out << "readI32];";
-    }
-    out <<
-      endl;
-  } else {
-    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
-           tfield->get_name().c_str(), type_name(type).c_str());
-  }
-}
-
-/**
- * Generates an unserializer for a struct, allocates the struct and invokes read:
- */
-void t_cocoa_generator::generate_deserialize_struct(ofstream& out,
-                                                    t_struct* tstruct,
-                                                    string fieldName) {
-  indent(out) << type_name(tstruct) << fieldName << " = [[" <<
-    type_name(tstruct, true) << " alloc] init];" << endl;
-  indent(out) << "[" << fieldName << " read: inProtocol];" << endl;
-}
-
-/**
- * Deserializes a container by reading its size and then iterating
- */
-void t_cocoa_generator::generate_deserialize_container(ofstream& out,
-                                                       t_type* ttype,
-                                                       string fieldName) {
-  string size = tmp("_size");
-  indent(out) << "int " << size << ";" << endl;
-
-  // Declare variables, read header
-  if (ttype->is_map()) {
-    indent(out)
-      << "[inProtocol readMapBeginReturningKeyType: NULL valueType: NULL size: &" <<
-      size << "];" << endl;
-    indent(out) << "NSMutableDictionary * " << fieldName <<
-      " = [[NSMutableDictionary alloc] initWithCapacity: " << size << "];" << endl;
-  } else if (ttype->is_set()) {
-    indent(out)
-      << "[inProtocol readSetBeginReturningElementType: NULL size: &" << size << "];" << endl;
-    indent(out) << "NSMutableSet * " << fieldName <<
-      " = [[NSMutableSet alloc] initWithCapacity: " << size << "];" << endl;
-  } else if (ttype->is_list()) {
-    indent(out)
-      << "[inProtocol readListBeginReturningElementType: NULL size: &" << size << "];" << endl;
-    indent(out) << "NSMutableArray * " << fieldName <<
-      " = [[NSMutableArray alloc] initWithCapacity: " << size << "];" << endl;
-  }
-  // FIXME - the code above does not verify that the element types of
-  // the containers being read match the element types of the
-  // containers we are reading into.  Does that matter?
-
-  // For loop iterates over elements
-  string i = tmp("_i");
-  indent(out) << "int " << i << ";" << endl <<
-    indent() << "for (" << i << " = 0; " <<
-    i << " < " << size << "; " <<
-    "++" << i << ")" << endl;
-
-    scope_up(out);
-
-    if (ttype->is_map()) {
-      generate_deserialize_map_element(out, (t_map*)ttype, fieldName);
-    } else if (ttype->is_set()) {
-      generate_deserialize_set_element(out, (t_set*)ttype, fieldName);
-    } else if (ttype->is_list()) {
-      generate_deserialize_list_element(out, (t_list*)ttype, fieldName);
-    }
-
-    scope_down(out);
-
-  // Read container end
-  if (ttype->is_map()) {
-    indent(out) << "[inProtocol readMapEnd];" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) << "[inProtocol readSetEnd];" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) << "[inProtocol readListEnd];" << endl;
-  }
-
-}
-
-
-/**
- * Take a variable of a given type and wrap it in code to make it
- * suitable for putting into a container, if necessary.  Basically,
- * wrap scaler primitives in NSNumber objects.
- */
-string t_cocoa_generator::containerize(t_type * ttype,
-                                       string fieldName)
-{
-  // FIXME - optimize here to avoid autorelease pool?
-  ttype = get_true_type(ttype);
-  if (ttype->is_enum()) {
-    return "[NSNumber numberWithInt: " + fieldName + "]";
-  } else if (ttype->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
-    switch (tbase) {
-    case t_base_type::TYPE_VOID:
-      throw "can't containerize void";
-    case t_base_type::TYPE_BOOL:
-      return "[NSNumber numberWithBool: " + fieldName + "]";
-    case t_base_type::TYPE_BYTE:
-      return "[NSNumber numberWithUnsignedChar: " + fieldName + "]";
-    case t_base_type::TYPE_I16:
-      return "[NSNumber numberWithShort: " + fieldName + "]";
-    case t_base_type::TYPE_I32:
-      return "[NSNumber numberWithLong: " + fieldName + "]";
-    case t_base_type::TYPE_I64:
-      return "[NSNumber numberWithLongLong: " + fieldName + "]";
-    case t_base_type::TYPE_DOUBLE:
-      return "[NSNumber numberWithDouble: " + fieldName + "]";
-    default:
-      break;
-    }
-  }
-
-  // do nothing
-  return fieldName;
-}
-
-
-/**
- * Generates code to deserialize a map element
- */
-void t_cocoa_generator::generate_deserialize_map_element(ofstream& out,
-                                                         t_map* tmap,
-                                                         string fieldName) {
-  string key = tmp("_key");
-  string val = tmp("_val");
-  t_type* keyType = tmap->get_key_type();
-  t_type* valType = tmap->get_val_type();
-  t_field fkey(keyType, key);
-  t_field fval(valType, val);
-
-  generate_deserialize_field(out, &fkey, key);
-  generate_deserialize_field(out, &fval, val);
-
-  indent(out) <<
-    "[" << fieldName << " setObject: " << containerize(valType, val) <<
-    " forKey: " << containerize(keyType, key) << "];" << endl;
-
-  if (type_can_be_null(keyType)) {
-    if (!(get_true_type(keyType)->is_string())) {
-      indent(out) << "[" << containerize(keyType, key) << " release_stub];" << endl;
-    }
-  }
-
-  if (type_can_be_null(valType)) {
-    if (!(get_true_type(valType)->is_string())) {
-      indent(out) << "[" << containerize(valType, val) << " release_stub];" << endl;
-    }
-  }
-}
-
-/**
- * Deserializes a set element
- */
-void t_cocoa_generator::generate_deserialize_set_element(ofstream& out,
-                                                         t_set* tset,
-                                                         string fieldName) {
-  string elem = tmp("_elem");
-  t_type* type = tset->get_elem_type();
-  t_field felem(type, elem);
-
-  generate_deserialize_field(out, &felem, elem);
-
-  indent(out) <<
-    "[" << fieldName << " addObject: " << containerize(type, elem) << "];" << endl;
-
-  if (type_can_be_null(type)) {
-    // deserialized strings are autorelease, so don't release them
-    if (!(get_true_type(type)->is_string())) {
-      indent(out) << "[" << containerize(type, elem) << " release_stub];" << endl;
-    }
-  }
-}
-
-/**
- * Deserializes a list element
- */
-void t_cocoa_generator::generate_deserialize_list_element(ofstream& out,
-                                                          t_list* tlist,
-                                                          string fieldName) {
-  string elem = tmp("_elem");
-  t_type* type = tlist->get_elem_type();
-  t_field felem(type, elem);
-
-  generate_deserialize_field(out, &felem, elem);
-
-  indent(out) <<
-    "[" << fieldName << " addObject: " << containerize(type, elem) << "];" << endl;
-
-  if (type_can_be_null(type)) {
-    if (!(get_true_type(type)->is_string())) {
-      indent(out) << "[" << containerize(type, elem) << " release_stub];" << endl;
-    }
-  }
-}
-
-
-/**
- * Serializes a field of any type.
- *
- * @param tfield The field to serialize
- * @param fieldName Name to of the variable holding the field
- */
-void t_cocoa_generator::generate_serialize_field(ofstream& out,
-                                                 t_field* tfield,
-                                                 string fieldName) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  // Do nothing for void types
-  if (type->is_void()) {
-    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
-      tfield->get_name();
-  }
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_serialize_struct(out,
-                              (t_struct*)type,
-                              fieldName);
-  } else if (type->is_container()) {
-    generate_serialize_container(out,
-                                 type,
-                                 fieldName);
-  } else if (type->is_base_type() || type->is_enum()) {
-    indent(out) <<
-      "[outProtocol ";
-
-    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: " + fieldName;
-        break;
-      case t_base_type::TYPE_STRING:
-        if (((t_base_type*)type)->is_binary()) {
-          out << "writeBinary: " << fieldName << "];";
-        } else {
-          out << "writeString: " << fieldName << "];";
-        }
-        break;
-      case t_base_type::TYPE_BOOL:
-        out << "writeBool: " << fieldName << "];";
-        break;
-      case t_base_type::TYPE_BYTE:
-        out << "writeByte: " << fieldName << "];";
-        break;
-      case t_base_type::TYPE_I16:
-        out << "writeI16: " << fieldName << "];";
-        break;
-      case t_base_type::TYPE_I32:
-        out << "writeI32: " << fieldName << "];";
-        break;
-      case t_base_type::TYPE_I64:
-        out << "writeI64: " << fieldName << "];";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        out << "writeDouble: " << fieldName << "];";
-        break;
-      default:
-        throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      out << "writeI32: " << fieldName << "];";
-    }
-    out << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
-           tfield->get_name().c_str(),
-           type_name(type).c_str());
-  }
-}
-
-/**
- * Serialize a struct.
- *
- * @param tstruct The struct to serialize
- * @param fieldName Name of variable holding struct
- */
-void t_cocoa_generator::generate_serialize_struct(ofstream& out,
-                                                  t_struct* tstruct,
-                                                  string fieldName) {
-  (void) tstruct;
-  out <<
-    indent() << "[" << fieldName << " write: outProtocol];" << endl;
-}
-
-/**
- * Serializes a container by writing its size then the elements.
- *
- * @param ttype  The type of container
- * @param fieldName Name of variable holding container
- */
-void t_cocoa_generator::generate_serialize_container(ofstream& out,
-                                                     t_type* ttype,
-                                                     string fieldName) {
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    indent(out) <<
-      "[outProtocol writeMapBeginWithKeyType: " <<
-      type_to_enum(((t_map*)ttype)->get_key_type()) << " valueType: " <<
-      type_to_enum(((t_map*)ttype)->get_val_type()) << " size: [" <<
-      fieldName << " count]];" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "[outProtocol writeSetBeginWithElementType: " <<
-      type_to_enum(((t_set*)ttype)->get_elem_type()) << " size: [" <<
-      fieldName << " count]];" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "[outProtocol writeListBeginWithElementType: " <<
-      type_to_enum(((t_list*)ttype)->get_elem_type()) << " size: [" <<
-      fieldName << " count]];" << endl;
-  }
-
-  string iter = tmp("_iter");
-  string key;
-  if (ttype->is_map()) {
-    key = tmp("key");
-    indent(out) << "NSEnumerator * " << iter << " = [" << fieldName << " keyEnumerator];" << endl;
-    indent(out) << "id " << key << ";" << endl;
-    indent(out) << "while ((" << key << " = [" << iter << " nextObject]))" << endl;
-  } else if (ttype->is_set()) {
-    key = tmp("obj");
-    indent(out) << "NSEnumerator * " << iter << " = [" << fieldName << " objectEnumerator];" << endl;
-    indent(out) << "id " << key << ";" << endl;
-    indent(out) << "while ((" << key << " = [" << iter << " nextObject]))" << endl;
-  } else if (ttype->is_list()) {
-    key = tmp("i");
-    indent(out) << "int " << key << ";" << endl;
-    indent(out) <<
-      "for (" << key << " = 0; " << key << " < [" << fieldName << " count]; " << key << "++)" << endl;
-  }
-
-    scope_up(out);
-
-    if (ttype->is_map()) {
-      generate_serialize_map_element(out, (t_map*)ttype, key, fieldName);
-    } else if (ttype->is_set()) {
-      generate_serialize_set_element(out, (t_set*)ttype, key);
-    } else if (ttype->is_list()) {
-      generate_serialize_list_element(out, (t_list*)ttype, key, fieldName);
-    }
-
-    scope_down(out);
-
-    if (ttype->is_map()) {
-      indent(out) <<
-        "[outProtocol writeMapEnd];" << endl;
-    } else if (ttype->is_set()) {
-      indent(out) <<
-        "[outProtocol writeSetEnd];" << endl;
-    } else if (ttype->is_list()) {
-      indent(out) <<
-        "[outProtocol writeListEnd];" << endl;
-    }
-
-  scope_down(out);
-}
-
-/**
- * Given a field variable name, wrap it in code that converts it to a
- * primitive type, if necessary.
- */
-string t_cocoa_generator::decontainerize(t_field * tfield,
-                                         string fieldName)
-{
-  t_type * ttype = get_true_type(tfield->get_type());
-  if (ttype->is_enum()) {
-    return "[" + fieldName + " intValue]";
-  } else if (ttype->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
-    switch (tbase) {
-    case t_base_type::TYPE_VOID:
-      throw "can't decontainerize void";
-    case t_base_type::TYPE_BOOL:
-      return "[" + fieldName + " boolValue]";
-    case t_base_type::TYPE_BYTE:
-      return "[" + fieldName + " unsignedCharValue]";
-    case t_base_type::TYPE_I16:
-      return "[" + fieldName + " shortValue]";
-    case t_base_type::TYPE_I32:
-      return "[" + fieldName + " longValue]";
-    case t_base_type::TYPE_I64:
-      return "[" + fieldName + " longLongValue]";
-    case t_base_type::TYPE_DOUBLE:
-      return "[" + fieldName + " doubleValue]";
-    default:
-      break;
-    }
-  }
-
-  // do nothing
-  return fieldName;
-}
-
-
-/**
- * Serializes the members of a map.
- */
-void t_cocoa_generator::generate_serialize_map_element(ofstream& out,
-                                                       t_map* tmap,
-                                                       string key,
-                                                       string mapName) {
-  t_field kfield(tmap->get_key_type(), key);
-  generate_serialize_field(out, &kfield, decontainerize(&kfield, key));
-  t_field vfield(tmap->get_val_type(), "[" + mapName + " objectForKey: " + key + "]");
-  generate_serialize_field(out, &vfield, decontainerize(&vfield, vfield.get_name()));
-}
-
-/**
- * Serializes the members of a set.
- */
-void t_cocoa_generator::generate_serialize_set_element(ofstream& out,
-                                                       t_set* tset,
-                                                       string elementName) {
-  t_field efield(tset->get_elem_type(), elementName);
-  generate_serialize_field(out, &efield, decontainerize(&efield, elementName));
-}
-
-/**
- * Serializes the members of a list.
- */
-void t_cocoa_generator::generate_serialize_list_element(ofstream& out,
-                                                        t_list* tlist,
-                                                        string index,
-                                                        string listName) {
-  t_field efield(tlist->get_elem_type(), "[" + listName + " objectAtIndex: " + index + "]");
-  generate_serialize_field(out, &efield, decontainerize(&efield, efield.get_name()));
-}
-
-
-/**
- * Returns an Objective-C name
- *
- * @param ttype The type
- * @param class_ref Do we want a Class reference istead of a type reference?
- * @return Java type name, i.e. HashMap<Key,Value>
- */
-string t_cocoa_generator::type_name(t_type* ttype, bool class_ref) {
-  if (ttype->is_typedef()) {
-    return cocoa_prefix_ + ttype->get_name();
-  }
-
-  string result;
-  if (ttype->is_base_type()) {
-    return base_type_name((t_base_type*)ttype);
-  } else if (ttype->is_enum()) {
-    return "int";
-  } else if (ttype->is_map()) {
-    result = "NSMutableDictionary";
-  } else if (ttype->is_set()) {
-    result = "NSMutableSet";
-  } else if (ttype->is_list()) {
-    result = "NSMutableArray";
-  } else {
-    // Check for prefix
-    t_program* program = ttype->get_program();
-    if (program != NULL) {
-      result = program->get_namespace("cocoa") + ttype->get_name();
-    } else {
-      result = ttype->get_name();
-    }
-  }
-
-  if (!class_ref) {
-    result += " *";
-  }
-  return result;
-}
-
-/**
- * Returns the Objective-C type that corresponds to the thrift type.
- *
- * @param tbase The base type
- */
-string t_cocoa_generator::base_type_name(t_base_type* type) {
-  t_base_type::t_base tbase = type->get_base();
-
-  switch (tbase) {
-  case t_base_type::TYPE_VOID:
-    return "void";
-  case t_base_type::TYPE_STRING:
-    if (type->is_binary()) {
-      return "NSData *";
-    } else {
-      return "NSString *";
-    }
-  case t_base_type::TYPE_BOOL:
-    return "BOOL";
-  case t_base_type::TYPE_BYTE:
-    return "uint8_t";
-  case t_base_type::TYPE_I16:
-    return"int16_t";
-  case t_base_type::TYPE_I32:
-    return "int32_t";
-  case t_base_type::TYPE_I64:
-    return"int64_t";
-  case t_base_type::TYPE_DOUBLE:
-    return "double";
-  default:
-    throw "compiler error: no objective-c name for base type " + t_base_type::t_base_name(tbase);
-  }
-}
-
-/**
- * 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
- */
-void t_cocoa_generator::print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool defval, bool is_property) {
-  type = get_true_type(type);
-
-  indent(out);
-  if (type->is_base_type()) {
-    string v2 = render_const_value(out, type, value);
-    if (defval)
-      out << type_name(type) << " ";
-    out << name << " = " << v2 << ";" << endl << endl;
-  } else if (type->is_enum()) {
-    if (defval)
-      out << type_name(type) << " ";
-    out << name << " = " << render_const_value(out, type, value) << ";" << endl << endl;
-  } else if (type->is_struct() || type->is_xception()) {
-    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;
-    if (defval)
-      out << type_name(type) << " ";
-    if (defval || is_property)
-      out << name << " = [[[" << type_name(type, true) << " alloc] init] autorelease_stub];" << endl;
-    else
-      out << name << " = [[" << type_name(type, true) << " alloc] init];" << endl;
-    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();
-      }
-      string val = render_const_value(out, field_type, v_iter->second);
-      std::string cap_name = capitalize(v_iter->first->get_string());
-      indent(out) << "[" << name << " set" << cap_name << ":" << val << "];" << endl;
-    }
-    out << endl;
-  } 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();
-    map<t_const_value*, t_const_value*>::const_iterator v_iter;
-    if (defval)
-      out << "NSMutableDictionary *";
-    if (defval || is_property)
-      out << name << " = [[[NSMutableDictionary alloc] initWithCapacity:" << val.size() << "] autorelease_stub]; " << endl;
-    else
-      out << name << " = [[NSMutableDictionary alloc] initWithCapacity:" << val.size() << "]; " << endl;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string key = render_const_value(out, ktype, v_iter->first, true);
-      string val = render_const_value(out, vtype, v_iter->second, true);
-      indent(out) << "[" << name << " setObject:" << val << " forKey:" << key << "];" << endl;
-    }
-    out << endl;
-  } else if (type->is_list()) {
-    t_type* etype = ((t_list*)type)->get_elem_type();
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    if (defval)
-      out << "NSMutableArray *";
-    if (defval || is_property)
-      out << name << " = [[[NSMutableArray alloc] initWithCapacity:" << val.size() <<"] autorelease_stub];" << endl;
-    else
-      out << name << " = [[NSMutableArray alloc] initWithCapacity:" << val.size() <<"];" << endl;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string val = render_const_value(out, etype, *v_iter, true);
-      indent(out) << "[" << name << " addObject:" << val << "];" << endl;
-    }
-    out << endl;
-  } else if (type->is_set()) {
-    t_type* etype = ((t_set*)type)->get_elem_type();
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    if (defval)
-      out << "NSMutableSet *";
-    if (defval || is_property)
-      out << name << " = [[[NSMutableSet alloc] initWithCapacity:" << val.size() << "] autorelease_stub];" << endl;
-    else
-      out << name << " = [[NSMutableSet alloc] initWithCapacity:" << val.size() << "];" << endl;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string val = render_const_value(out, etype, *v_iter, true);
-      indent(out) << "[" << name << " addObject:" << val << "];" << endl;
-    }
-    out << endl;
-  } else {
-    throw "compiler error: no const of type " + type->get_name();
-  }
-}
-
-string t_cocoa_generator::render_const_value(ofstream& out, t_type* type, t_const_value* value, bool containerize_it) {
-  type = get_true_type(type);
-  std::ostringstream render;
-
-  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:
-      // We must handle binary constant but the syntax of IDL defines 
-      // nothing about binary constant.
-      //   if ((t_base_type*)type)->is_binary())
-      //      // binary code
-      render << "@\"" << get_escaped_string(value) << '"';
-      break;
-    case t_base_type::TYPE_BOOL:
-      render << ((value->get_integer() > 0) ? "YES" : "NO");
-      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:
-      render << value->get_integer();
-      break;
-    case t_base_type::TYPE_DOUBLE:
-      if (value->get_type() == t_const_value::CV_INTEGER) {
-        render << value->get_integer();
-      } else {
-        render << 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()) {
-    render << value->get_integer();
-  } else {
-    string t = tmp("tmp");
-    print_const_value(out, t, type, value, true, false);
-    render << t;
-  }
-
-  if (containerize_it) {
-    return containerize(type, render.str());
-  }
-  return render.str();
-}
-
-#if 0
-/**
-ORIGINAL
- * Spit out code that evaluates to the specified constant value.
- */
-string t_cocoa_generator::render_const_value(string name,
-                                             t_type* type,
-                                             t_const_value* value,
-                                             bool containerize_it) {
-  type = get_true_type(type);
-  std::ostringstream render;
-
-  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:
-      render << "@\"" << get_escaped_string(value) << '"';
-      break;
-    case t_base_type::TYPE_BOOL:
-      render << ((value->get_integer() > 0) ? "YES" : "NO");
-      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:
-      render << value->get_integer();
-      break;
-    case t_base_type::TYPE_DOUBLE:
-      if (value->get_type() == t_const_value::CV_INTEGER) {
-        render << value->get_integer();
-      } else {
-        render << 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()) {
-    render << value->get_integer();
-  } else if (type->is_struct() || type->is_xception()) {
-    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;
-    if (val.size() > 0)
-      render << "[[" << type_name(type, true) << " alloc] initWith";
-    else
-      render << "[[" << type_name(type, true) << " alloc] init";
-    bool first = true;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      // FIXME The generated code does not match with initWithXXX 
-      //       initializer and causes compile error.
-      //       Try: test/DebugProtoTest.thrift and test/SmallTest.thrift
-      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 (first) {
-        render << capitalize(v_iter->first->get_string());
-        first = false;
-      } else {
-        render << " " << v_iter->first->get_string();
-      }
-      render << ": " << render_const_value(name, field_type, v_iter->second);
-    }
-    render << "]";
-  } else if (type->is_map()) {
-    render << "[[NSDictionary alloc] initWithObjectsAndKeys: ";
-    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();
-    map<t_const_value*, t_const_value*>::const_iterator v_iter;
-    bool first = true;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string key = render_const_value(name, ktype, v_iter->first, true);
-      string val = render_const_value(name, vtype, v_iter->second, true);
-      if (first) {
-        first = false;
-      } else {
-        render << ", ";
-      }
-      render << val << ", " << key;
-    }
-    if (first)
-      render << " nil]";
-    else
-      render << ", nil]";
-  } else if (type->is_list()) {
-    render << "[[NSArray alloc] initWithObjects: ";
-    t_type * etype = ((t_list*)type)->get_elem_type();
-    const vector<t_const_value*>& val = value->get_list();
-    bool first = true;
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      if (first) {
-        first = false;
-      } else {
-        render << ", ";
-      }
-      render << render_const_value(name, etype, *v_iter, true);
-    }
-    if (first)
-      render << " nil]";
-    else
-      render << ", nil]";
-  } else if (type->is_set()) {
-    render << "[[NSSet alloc] initWithObjects: ";
-    t_type * etype = ((t_set*)type)->get_elem_type();
-    const vector<t_const_value*>& val = value->get_list();
-    bool first = true;
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      if (first) {
-        first = false;
-      } else {
-        render << ", ";
-      }
-      render << render_const_value(name, etype, *v_iter, true);
-    }
-    if (first)
-      render << " nil]";
-    else
-      render << ", nil]";
-  } else {
-    throw "don't know how to render constant for type: " + type->get_name();
-  }
-
-  if (containerize_it) {
-    return containerize(type, render.str());
-  }
-
-  return render.str();
-}
-#endif
-
-/**
- * Declares a field.
- *
- * @param ttype The type
- */
-string t_cocoa_generator::declare_field(t_field* tfield) {
-  return type_name(tfield->get_type()) + " __" + tfield->get_name() + ";";
-}
-
-/**
- * Declares an Objective-C 2.0 property.
- *
- * @param tfield The field to declare a property for
- */
-string t_cocoa_generator::declare_property(t_field* tfield) {
-  std::ostringstream render;
-  render << "@property (nonatomic, ";
-
-  if (type_can_be_null(tfield->get_type()))
-    render << "retain, ";
-  
-  render << "getter=" << decapitalize(tfield->get_name()) <<
-    ", setter=set" << capitalize(tfield->get_name()) + ":) " <<
-    type_name(tfield->get_type()) << " " << tfield->get_name() << ";";
-
-  return render.str();
-}
-
-/**
- * Renders a function signature
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_cocoa_generator::function_signature(t_function* tfunction) {
-  t_type* ttype = tfunction->get_returntype();
-  std::string result =
-    "(" + type_name(ttype) + ") " + tfunction->get_name() + argument_list(tfunction->get_arglist());
-  return result;
-}
-
-
-/**
- * Renders a colon separated list of types and names, suitable for an
- * objective-c parameter list
- */
-string t_cocoa_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) {
-    string argPrefix = "";
-    if (first) {
-      first = false;
-    } else {
-      argPrefix = (*f_iter)->get_name();
-      result += " ";
-    }
-    result += argPrefix + ": (" + type_name((*f_iter)->get_type()) + ") " + (*f_iter)->get_name();
-  }
-  return result;
-}
-
-
-/**
- * Converts the parse type to an Objective-C enum string for the given type.
- */
-string t_cocoa_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 "TType_STRING";
-    case t_base_type::TYPE_BOOL:
-      return "TType_BOOL";
-    case t_base_type::TYPE_BYTE:
-      return "TType_BYTE";
-    case t_base_type::TYPE_I16:
-      return "TType_I16";
-    case t_base_type::TYPE_I32:
-      return "TType_I32";
-    case t_base_type::TYPE_I64:
-      return "TType_I64";
-    case t_base_type::TYPE_DOUBLE:
-      return "TType_DOUBLE";
-    }
-  } else if (type->is_enum()) {
-    return "TType_I32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "TType_STRUCT";
-  } else if (type->is_map()) {
-    return "TType_MAP";
-  } else if (type->is_set()) {
-    return "TType_SET";
-  } else if (type->is_list()) {
-    return "TType_LIST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-
-/**
- * Returns a format string specifier for the supplied parse type.
- */
-string t_cocoa_generator::format_string_for_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 "NO T_VOID CONSTRUCT";
-    case t_base_type::TYPE_STRING:
-      return "\\\"%@\\\"";
-    case t_base_type::TYPE_BOOL:
-      return "%i";
-    case t_base_type::TYPE_BYTE:
-      return "%i";
-    case t_base_type::TYPE_I16:
-      return "%hi";
-    case t_base_type::TYPE_I32:
-      return "%i";
-    case t_base_type::TYPE_I64:
-      return "%qi";
-    case t_base_type::TYPE_DOUBLE:
-      return "%f";
-    }
-  } else if (type->is_enum()) {
-    return "%i";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "%@";
-  } else if (type->is_map()) {
-    return "%@";
-  } else if (type->is_set()) {
-    return "%@";
-  } else if (type->is_list()) {
-    return "%@";
-  }
-
-  throw "INVALID TYPE IN format_string_for_type: " + type->get_name();
-}
-
-/**
- * Generate a call to a field's setter.
- *
- * @param tfield Field the setter is being called on
- * @param fieldName Name of variable to pass to setter
- */
-
-string t_cocoa_generator::call_field_setter(t_field* tfield, string fieldName) {
-  return "[self set" + capitalize(tfield->get_name()) + ": " + fieldName + "];";
-}
-
-
-THRIFT_REGISTER_GENERATOR(cocoa, "Cocoa",
-"    log_unexpected:  Log every time an unexpected field ID or type is encountered.\n"
-"    validate_required:\n"
-"                     Throws exception if any required field is not set.\n"
-)
-
diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc
deleted file mode 100644
index 523ce24..0000000
--- a/compiler/cpp/src/generate/t_cpp_generator.cc
+++ /dev/null
@@ -1,4643 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- * Contains some contributions under the Thrift Software License.
- * Please see doc/old-thrift-license.txt in the Thrift distribution for
- * details.
- */
-
-#include <cassert>
-
-#include <fstream>
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include <sys/stat.h>
-
-#include "platform.h"
-#include "t_oop_generator.h"
-
-using std::map;
-using std::ofstream;
-using std::ostream;
-using std::string;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * C++ code generator. This is legitimacy incarnate.
- *
- */
-class t_cpp_generator : public t_oop_generator {
- public:
-  t_cpp_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_oop_generator(program)
-  {
-    (void) option_string;
-    std::map<std::string, std::string>::const_iterator iter;
-
-    iter = parsed_options.find("pure_enums");
-    gen_pure_enums_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("dense");
-    gen_dense_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("include_prefix");
-    use_include_prefix_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("cob_style");
-    gen_cob_style_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("no_client_completion");
-    gen_no_client_completion_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("templates");
-    gen_templates_ = (iter != parsed_options.end());
-
-    gen_templates_only_ =
-      (iter != parsed_options.end() && iter->second == "only");
-
-    out_dir_base_ = "gen-cpp";
-  }
-
-  /**
-   * Init and close methods
-   */
-
-  void init_generator();
-  void close_generator();
-
-  void generate_consts(std::vector<t_const*> consts);
-
-  /**
-   * Program-level generation functions
-   */
-
-  void generate_typedef(t_typedef* ttypedef);
-  void generate_enum(t_enum* tenum);
-  void generate_struct(t_struct* tstruct) {
-    generate_cpp_struct(tstruct, false);
-  }
-  void generate_xception(t_struct* txception) {
-    generate_cpp_struct(txception, true);
-  }
-  void generate_cpp_struct(t_struct* tstruct, bool is_exception);
-
-  void generate_service(t_service* tservice);
-
-  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
-  std::string render_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
-
-  void generate_struct_definition    (std::ofstream& out, t_struct* tstruct,
-                                      bool is_exception=false,
-                                      bool pointers=false,
-                                      bool read=true,
-                                      bool write=true,
-                                      bool swap=false);
-  void generate_struct_fingerprint   (std::ofstream& out, t_struct* tstruct, bool is_definition);
-  void generate_struct_reader        (std::ofstream& out, t_struct* tstruct, bool pointers=false);
-  void generate_struct_writer        (std::ofstream& out, t_struct* tstruct, bool pointers=false);
-  void generate_struct_result_writer (std::ofstream& out, t_struct* tstruct, bool pointers=false);
-  void generate_struct_swap          (std::ofstream& out, t_struct* tstruct);
-
-  /**
-   * Service-level generation functions
-   */
-
-  void generate_service_interface (t_service* tservice, string style);
-  void generate_service_interface_factory (t_service* tservice, string style);
-  void generate_service_null      (t_service* tservice, string style);
-  void generate_service_multiface (t_service* tservice);
-  void generate_service_helpers   (t_service* tservice);
-  void generate_service_client    (t_service* tservice, string style);
-  void generate_service_processor (t_service* tservice, string style);
-  void generate_service_skeleton  (t_service* tservice);
-  void generate_process_function  (t_service* tservice, t_function* tfunction,
-                                   string style, bool specialized=false);
-  void generate_function_helpers  (t_service* tservice, t_function* tfunction);
-  void generate_service_async_skeleton (t_service* tservice);
-
-  /**
-   * Serialization constructs
-   */
-
-  void generate_deserialize_field        (std::ofstream& out,
-                                          t_field*    tfield,
-                                          std::string prefix="",
-                                          std::string suffix="");
-
-  void generate_deserialize_struct       (std::ofstream& out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_deserialize_container    (std::ofstream& out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_deserialize_set_element  (std::ofstream& out,
-                                          t_set*      tset,
-                                          std::string prefix="");
-
-  void generate_deserialize_map_element  (std::ofstream& out,
-                                          t_map*      tmap,
-                                          std::string prefix="");
-
-  void generate_deserialize_list_element (std::ofstream& out,
-                                          t_list*     tlist,
-                                          std::string prefix,
-                                          bool push_back,
-                                          std::string index);
-
-  void generate_serialize_field          (std::ofstream& out,
-                                          t_field*    tfield,
-                                          std::string prefix="",
-                                          std::string suffix="");
-
-  void generate_serialize_struct         (std::ofstream& out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_serialize_container      (std::ofstream& out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_serialize_map_element    (std::ofstream& out,
-                                          t_map*      tmap,
-                                          std::string iter);
-
-  void generate_serialize_set_element    (std::ofstream& out,
-                                          t_set*      tmap,
-                                          std::string iter);
-
-  void generate_serialize_list_element   (std::ofstream& out,
-                                          t_list*     tlist,
-                                          std::string iter);
-
-  void generate_function_call            (ostream& out,
-                                          t_function* tfunction,
-                                          string target,
-                                          string iface,
-                                          string arg_prefix);
-  /*
-   * Helper rendering functions
-   */
-
-  std::string namespace_prefix(std::string ns);
-  std::string namespace_open(std::string ns);
-  std::string namespace_close(std::string ns);
-  std::string type_name(t_type* ttype, bool in_typedef=false, bool arg=false);
-  std::string base_type_name(t_base_type::t_base tbase);
-  std::string declare_field(t_field* tfield, bool init=false, bool pointer=false, bool constant=false, bool reference=false);
-  std::string function_signature(t_function* tfunction, std::string style, std::string prefix="", bool name_params=true);
-  std::string cob_function_signature(t_function* tfunction, std::string prefix="", bool name_params=true);
-  std::string argument_list(t_struct* tstruct, bool name_params=true, bool start_comma=false);
-  std::string type_to_enum(t_type* ttype);
-  std::string local_reflection_name(const char*, t_type* ttype, bool external=false);
-
-  void generate_enum_constant_list(std::ofstream& f,
-                                   const vector<t_enum_value*>& constants,
-                                   const char* prefix,
-                                   const char* suffix,
-                                   bool include_values);
-
-  // These handles checking gen_dense_ and checking for duplicates.
-  void generate_local_reflection(std::ofstream& out, t_type* ttype, bool is_definition);
-  void generate_local_reflection_pointer(std::ofstream& out, t_type* ttype);
-
-  bool is_complex_type(t_type* ttype) {
-    ttype = get_true_type(ttype);
-
-    return
-      ttype->is_container() ||
-      ttype->is_struct() ||
-      ttype->is_xception() ||
-      (ttype->is_base_type() && (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING));
-  }
-
-  void set_use_include_prefix(bool use_include_prefix) {
-    use_include_prefix_ = use_include_prefix;
-  }
-
- private:
-  /**
-   * Returns the include prefix to use for a file generated by program, or the
-   * empty string if no include prefix should be used.
-   */
-  std::string get_include_prefix(const t_program& program) const;
-
-  /**
-   * True if we should generate pure enums for Thrift enums, instead of wrapper classes.
-   */
-  bool gen_pure_enums_;
-
-  /**
-   * True if we should generate local reflection metadata for TDenseProtocol.
-   */
-  bool gen_dense_;
-
-  /**
-   * True if we should generate templatized reader/writer methods.
-   */
-  bool gen_templates_;
-
-  /**
-   * True iff we should generate process function pointers for only templatized
-   * reader/writer methods.
-   */
-  bool gen_templates_only_;
-
-  /**
-   * True iff we should use a path prefix in our #include statements for other
-   * thrift-generated header files.
-   */
-  bool use_include_prefix_;
-
-  /**
-   * True if we should generate "Continuation OBject"-style classes as well.
-   */
-  bool gen_cob_style_;
-
-  /**
-   * True if we should omit calls to completion__() in CobClient class.
-   */
-  bool gen_no_client_completion_;
-
-  /**
-   * Strings for namespace, computed once up front then used directly
-   */
-
-  std::string ns_open_;
-  std::string ns_close_;
-
-  /**
-   * File streams, stored here to avoid passing them as parameters to every
-   * function.
-   */
-
-  std::ofstream f_types_;
-  std::ofstream f_types_impl_;
-  std::ofstream f_types_tcc_;
-  std::ofstream f_header_;
-  std::ofstream f_service_;
-  std::ofstream f_service_tcc_;
-
-  /**
-   * When generating local reflections, make sure we don't generate duplicates.
-   */
-  std::set<std::string> reflected_fingerprints_;
-
-  // The ProcessorGenerator is used to generate parts of the code,
-  // so it needs access to many of our protected members and methods.
-  //
-  // TODO: The code really should be cleaned up so that helper methods for
-  // writing to the output files are separate from the generator classes
-  // themselves.
-  friend class ProcessorGenerator;
-};
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * streams.
- */
-void t_cpp_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-
-  // Make output file
-  string f_types_name = get_out_dir()+program_name_+"_types.h";
-  f_types_.open(f_types_name.c_str());
-
-  string f_types_impl_name = get_out_dir()+program_name_+"_types.cpp";
-  f_types_impl_.open(f_types_impl_name.c_str());
-
-  if (gen_templates_) {
-    // If we don't open the stream, it appears to just discard data,
-    // which is fine.
-    string f_types_tcc_name = get_out_dir()+program_name_+"_types.tcc";
-    f_types_tcc_.open(f_types_tcc_name.c_str());
-  }
-
-  // Print header
-  f_types_ <<
-    autogen_comment();
-  f_types_impl_ <<
-    autogen_comment();
-  f_types_tcc_ <<
-    autogen_comment();
-
-  // Start ifndef
-  f_types_ <<
-    "#ifndef " << program_name_ << "_TYPES_H" << endl <<
-    "#define " << program_name_ << "_TYPES_H" << endl <<
-    endl;
-  f_types_tcc_ <<
-    "#ifndef " << program_name_ << "_TYPES_TCC" << endl <<
-    "#define " << program_name_ << "_TYPES_TCC" << endl <<
-    endl;
-
-  // Include base types
-  f_types_ <<
-    "#include <thrift/Thrift.h>" << endl <<
-    "#include <thrift/TApplicationException.h>" << endl <<
-    "#include <thrift/protocol/TProtocol.h>" << endl <<
-    "#include <thrift/transport/TTransport.h>" << endl <<
-    endl;
-  // Include C++xx compatibility header
-  f_types_ << "#include <thrift/cxxfunctional.h>" << endl;
-
-  // Include other Thrift includes
-  const vector<t_program*>& includes = program_->get_includes();
-  for (size_t i = 0; i < includes.size(); ++i) {
-    f_types_ <<
-      "#include \"" << get_include_prefix(*(includes[i])) <<
-      includes[i]->get_name() << "_types.h\"" << endl;
-
-    // XXX(simpkins): If gen_templates_ is enabled, we currently assume all
-    // included files were also generated with templates enabled.
-    f_types_tcc_ <<
-      "#include \"" << get_include_prefix(*(includes[i])) <<
-      includes[i]->get_name() << "_types.tcc\"" << endl;
-  }
-  f_types_ << endl;
-
-  // Include custom headers
-  const vector<string>& cpp_includes = program_->get_cpp_includes();
-  for (size_t i = 0; i < cpp_includes.size(); ++i) {
-    if (cpp_includes[i][0] == '<') {
-      f_types_ <<
-        "#include " << cpp_includes[i] << endl;
-    } else {
-      f_types_ <<
-        "#include \"" << cpp_includes[i] << "\"" << endl;
-    }
-  }
-  f_types_ <<
-    endl;
-
-  // Include the types file
-  f_types_impl_ <<
-    "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
-    "_types.h\"" << endl <<
-    endl;
-  f_types_tcc_ <<
-    "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
-    "_types.h\"" << endl <<
-    endl;
-
-  // If we are generating local reflection metadata, we need to include
-  // the definition of TypeSpec.
-  if (gen_dense_) {
-    f_types_impl_ <<
-      "#include <thrift/TReflectionLocal.h>" << endl <<
-      endl;
-  }
-
-  // The swap() code needs <algorithm> for std::swap()
-  f_types_impl_ << "#include <algorithm>" << endl << endl;
-
-  // Open namespace
-  ns_open_ = namespace_open(program_->get_namespace("cpp"));
-  ns_close_ = namespace_close(program_->get_namespace("cpp"));
-
-  f_types_ <<
-    ns_open_ << endl <<
-    endl;
-
-  f_types_impl_ <<
-    ns_open_ << endl <<
-    endl;
-
-  f_types_tcc_ <<
-    ns_open_ << endl <<
-    endl;
-}
-
-/**
- * Closes the output files.
- */
-void t_cpp_generator::close_generator() {
-  // Close namespace
-  f_types_ <<
-    ns_close_ << endl <<
-    endl;
-  f_types_impl_ <<
-    ns_close_ << endl;
-  f_types_tcc_ <<
-    ns_close_ << endl <<
-    endl;
-
-  // Include the types.tcc file from the types header file,
-  // so clients don't have to explicitly include the tcc file.
-  // TODO(simpkins): Make this a separate option.
-  if (gen_templates_) {
-    f_types_ <<
-      "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
-      "_types.tcc\"" << endl <<
-      endl;
-  }
-
-  // Close ifndef
-  f_types_ <<
-    "#endif" << endl;
-  f_types_tcc_ <<
-    "#endif" << endl;
-
-  // Close output file
-  f_types_.close();
-  f_types_impl_.close();
-  f_types_tcc_.close();
-}
-
-/**
- * Generates a typedef. This is just a simple 1-liner in C++
- *
- * @param ttypedef The type definition
- */
-void t_cpp_generator::generate_typedef(t_typedef* ttypedef) {
-  f_types_ <<
-    indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " << ttypedef->get_symbolic() << ";" << endl <<
-    endl;
-}
-
-
-void t_cpp_generator::generate_enum_constant_list(std::ofstream& f,
-                                                  const vector<t_enum_value*>& constants,
-                                                  const char* prefix,
-                                                  const char* suffix,
-                                                  bool include_values) {
-  f << " {" << endl;
-  indent_up();
-
-  vector<t_enum_value*>::const_iterator c_iter;
-  bool first = true;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    if (first) {
-      first = false;
-    } else {
-      f << "," << endl;
-    }
-    indent(f)
-      << prefix << (*c_iter)->get_name() << suffix;
-    if (include_values && (*c_iter)->has_value()) {
-      f << " = " << (*c_iter)->get_value();
-    }
-  }
-
-  f << endl;
-  indent_down();
-  indent(f) << "};" << endl;
-}
-
-/**
- * Generates code for an enumerated type. In C++, this is essentially the same
- * as the thrift definition itself, using the enum keyword in C++.
- *
- * @param tenum The enumeration
- */
-void t_cpp_generator::generate_enum(t_enum* tenum) {
-  vector<t_enum_value*> constants = tenum->get_constants();
-
-  std::string enum_name = tenum->get_name();
-  if (!gen_pure_enums_) {
-    enum_name = "type";
-    f_types_ <<
-      indent() << "struct " << tenum->get_name() << " {" << endl;
-    indent_up();
-  }
-  f_types_ <<
-    indent() << "enum " << enum_name;
-
-  generate_enum_constant_list(f_types_, constants, "", "", true);
-
-  if (!gen_pure_enums_) {
-    indent_down();
-    f_types_ << "};" << endl;
-  }
-
-  f_types_ << endl;
-
-  /**
-     Generate a character array of enum names for debugging purposes.
-  */
-  std::string prefix = "";
-  if (!gen_pure_enums_) {
-    prefix = tenum->get_name() + "::";
-  }
-
-  f_types_impl_ <<
-    indent() << "int _k" << tenum->get_name() << "Values[] =";
-  generate_enum_constant_list(f_types_impl_, constants, prefix.c_str(), "", false);
-
-  f_types_impl_ <<
-    indent() << "const char* _k" << tenum->get_name() << "Names[] =";
-  generate_enum_constant_list(f_types_impl_, constants, "\"", "\"", false);
-
-  f_types_ <<
-    indent() << "extern const std::map<int, const char*> _" <<
-    tenum->get_name() << "_VALUES_TO_NAMES;" << endl << endl;
-
-  f_types_impl_ <<
-    indent() << "const std::map<int, const char*> _" << tenum->get_name() <<
-    "_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(" << constants.size() <<
-    ", _k" << tenum->get_name() << "Values" <<
-    ", _k" << tenum->get_name() << "Names), " <<
-    "::apache::thrift::TEnumIterator(-1, NULL, NULL));" << endl << endl;
-
-  generate_local_reflection(f_types_, tenum, false);
-  generate_local_reflection(f_types_impl_, tenum, true);
-}
-
-/**
- * Generates a class that holds all the constants.
- */
-void t_cpp_generator::generate_consts(std::vector<t_const*> consts) {
-  string f_consts_name = get_out_dir()+program_name_+"_constants.h";
-  ofstream f_consts;
-  f_consts.open(f_consts_name.c_str());
-
-  string f_consts_impl_name = get_out_dir()+program_name_+"_constants.cpp";
-  ofstream f_consts_impl;
-  f_consts_impl.open(f_consts_impl_name.c_str());
-
-  // Print header
-  f_consts <<
-    autogen_comment();
-  f_consts_impl <<
-    autogen_comment();
-
-  // Start ifndef
-  f_consts <<
-    "#ifndef " << program_name_ << "_CONSTANTS_H" << endl <<
-    "#define " << program_name_ << "_CONSTANTS_H" << endl <<
-    endl <<
-    "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
-    "_types.h\"" << endl <<
-    endl <<
-    ns_open_ << endl <<
-    endl;
-
-  f_consts_impl <<
-    "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
-    "_constants.h\"" << endl <<
-    endl <<
-    ns_open_ << endl <<
-    endl;
-
-  f_consts <<
-    "class " << program_name_ << "Constants {" << endl <<
-    " public:" << endl <<
-    "  " << program_name_ << "Constants();" << endl <<
-    endl;
-  indent_up();
-  vector<t_const*>::iterator c_iter;
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    string name = (*c_iter)->get_name();
-    t_type* type = (*c_iter)->get_type();
-    f_consts <<
-      indent() << type_name(type) << " " << name << ";" << endl;
-  }
-  indent_down();
-  f_consts <<
-    "};" << endl;
-
-  f_consts_impl <<
-    "const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
-    endl <<
-    program_name_ << "Constants::" << program_name_ << "Constants() {" << endl;
-  indent_up();
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    print_const_value(f_consts_impl,
-                      (*c_iter)->get_name(),
-                      (*c_iter)->get_type(),
-                      (*c_iter)->get_value());
-  }
-  indent_down();
-  indent(f_consts_impl) <<
-    "}" << endl;
-
-  f_consts <<
-    endl <<
-    "extern const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
-    endl <<
-    ns_close_ << endl <<
-    endl <<
-    "#endif" << endl;
-  f_consts.close();
-
-  f_consts_impl <<
-    endl <<
-    ns_close_ << endl <<
-    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
- */
-void t_cpp_generator::print_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
-  type = get_true_type(type);
-  if (type->is_base_type()) {
-    string v2 = render_const_value(out, name, type, value);
-    indent(out) << name << " = " << v2 << ";" << endl <<
-      endl;
-  } else if (type->is_enum()) {
-    indent(out) << name << " = (" << type_name(type) << ")" << value->get_integer() << ";" << endl <<
-      endl;
-  } else if (type->is_struct() || type->is_xception()) {
-    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;
-    bool is_nonrequired_field = false;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      t_type* field_type = NULL;
-      is_nonrequired_field = false;
-      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();
-          is_nonrequired_field = (*f_iter)->get_req() != t_field::T_REQUIRED;
-        }
-      }
-      if (field_type == NULL) {
-        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
-      }
-      string val = render_const_value(out, name, field_type, v_iter->second);
-      indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl;
-      if(is_nonrequired_field) {
-          indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl;
-      }
-    }
-    out << endl;
-  } 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();
-    map<t_const_value*, t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string key = render_const_value(out, name, ktype, v_iter->first);
-      string val = render_const_value(out, name, vtype, v_iter->second);
-      indent(out) << name << ".insert(std::make_pair(" << key << ", " << val << "));" << endl;
-    }
-    out << endl;
-  } else if (type->is_list()) {
-    t_type* etype = ((t_list*)type)->get_elem_type();
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string val = render_const_value(out, name, etype, *v_iter);
-      indent(out) << name << ".push_back(" << val << ");" << endl;
-    }
-    out << endl;
-  } else if (type->is_set()) {
-    t_type* etype = ((t_set*)type)->get_elem_type();
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string val = render_const_value(out, name, etype, *v_iter);
-      indent(out) << name << ".insert(" << val << ");" << endl;
-    }
-    out << endl;
-  } else {
-    throw "INVALID TYPE IN print_const_value: " + type->get_name();
-  }
-}
-
-/**
- *
- */
-string t_cpp_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
-  (void) name;
-  std::ostringstream render;
-
-  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:
-      render << '"' << get_escaped_string(value) << '"';
-      break;
-    case t_base_type::TYPE_BOOL:
-      render << ((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:
-      render << value->get_integer();
-      break;
-    case t_base_type::TYPE_I64:
-      render << value->get_integer() << "LL";
-      break;
-    case t_base_type::TYPE_DOUBLE:
-      if (value->get_type() == t_const_value::CV_INTEGER) {
-        render << value->get_integer();
-      } else {
-        render << 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()) {
-    render << "(" << type_name(type) << ")" << value->get_integer();
-  } else {
-    string t = tmp("tmp");
-    indent(out) << type_name(type) << " " << t << ";" << endl;
-    print_const_value(out, t, type, value);
-    render << t;
-  }
-
-  return render.str();
-}
-
-/**
- * Generates a struct definition for a thrift data type. This is a class
- * with data members and a read/write() function, plus a mirroring isset
- * inner class.
- *
- * @param tstruct The struct definition
- */
-void t_cpp_generator::generate_cpp_struct(t_struct* tstruct, bool is_exception) {
-  generate_struct_definition(f_types_, tstruct, is_exception,
-                             false, true, true, true);
-  generate_struct_fingerprint(f_types_impl_, tstruct, true);
-  generate_local_reflection(f_types_, tstruct, false);
-  generate_local_reflection(f_types_impl_, tstruct, true);
-  generate_local_reflection_pointer(f_types_impl_, tstruct);
-
-  std::ofstream& out = (gen_templates_ ? f_types_tcc_ : f_types_impl_);
-  generate_struct_reader(out, tstruct);
-  generate_struct_writer(out, tstruct);
-  generate_struct_swap(f_types_impl_, tstruct);
-}
-
-/**
- * Writes the struct definition into the header file
- *
- * @param out Output stream
- * @param tstruct The struct
- */
-void t_cpp_generator::generate_struct_definition(ofstream& out,
-                                                 t_struct* tstruct,
-                                                 bool is_exception,
-                                                 bool pointers,
-                                                 bool read,
-                                                 bool write,
-                                                 bool swap) {
-  string extends = "";
-  if (is_exception) {
-    extends = " : public ::apache::thrift::TException";
-  }
-
-  // Get members
-  vector<t_field*>::const_iterator m_iter;
-  const vector<t_field*>& members = tstruct->get_members();
-
-  // Write the isset structure declaration outside the class. This makes
-  // the generated code amenable to processing by SWIG.
-  // We only declare the struct if it gets used in the class.
-
-  // Isset struct has boolean fields, but only for non-required fields.
-  bool has_nonrequired_fields = false;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    if ((*m_iter)->get_req() != t_field::T_REQUIRED)
-      has_nonrequired_fields = true;
-  }
-
-  if (has_nonrequired_fields && (!pointers || read)) {
-
-    out <<
-      indent() << "typedef struct _" << tstruct->get_name() << "__isset {" << endl;
-    indent_up();
-
-    indent(out) <<
-      "_" << tstruct->get_name() << "__isset() ";
-    bool first = true;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if ((*m_iter)->get_req() == t_field::T_REQUIRED) {
-        continue;
-      }
-      string isSet = ((*m_iter)->get_value() != NULL) ? "true" : "false";
-      if (first) {
-        first = false;
-        out <<
-          ": " << (*m_iter)->get_name() << "(" << isSet << ")";
-      } else {
-        out <<
-          ", " << (*m_iter)->get_name() << "(" << isSet << ")";
-      }
-    }
-    out << " {}" << endl;
-
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
-        indent(out) <<
-          "bool " << (*m_iter)->get_name() << ";" << endl;
-        }
-      }
-
-      indent_down();
-      indent(out) <<
-        "} _" << tstruct->get_name() << "__isset;" << endl;
-    }
-
-  out << endl;
-
-  // Open struct def
-  out <<
-    indent() << "class " << tstruct->get_name() << extends << " {" << endl <<
-    indent() << " public:" << endl <<
-    endl;
-  indent_up();
-
-  // Put the fingerprint up top for all to see.
-  generate_struct_fingerprint(out, tstruct, false);
-
-  if (!pointers) {
-    // Default constructor
-    indent(out) <<
-      tstruct->get_name() << "()";
-
-    bool init_ctor = false;
-
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      t_type* t = get_true_type((*m_iter)->get_type());
-      if (t->is_base_type() || t->is_enum()) {
-        string dval;
-        if (t->is_enum()) {
-          dval += "(" + type_name(t) + ")";
-        }
-        dval += t->is_string() ? "" : "0";
-        t_const_value* cv = (*m_iter)->get_value();
-        if (cv != NULL) {
-          dval = render_const_value(out, (*m_iter)->get_name(), t, cv);
-        }
-        if (!init_ctor) {
-          init_ctor = true;
-          out << " : ";
-          out << (*m_iter)->get_name() << "(" << dval << ")";
-        } else {
-          out << ", " << (*m_iter)->get_name() << "(" << dval << ")";
-        }
-      }
-    }
-    out << " {" << endl;
-    indent_up();
-    // TODO(dreiss): When everything else in Thrift is perfect,
-    // do more of these in the initializer list.
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      t_type* t = get_true_type((*m_iter)->get_type());
-
-      if (!t->is_base_type()) {
-        t_const_value* cv = (*m_iter)->get_value();
-        if (cv != NULL) {
-          print_const_value(out, (*m_iter)->get_name(), t, cv);
-        }
-      }
-    }
-    scope_down(out);
-  }
-
-  if (tstruct->annotations_.find("final") == tstruct->annotations_.end()) {
-    out <<
-      endl <<
-      indent() << "virtual ~" << tstruct->get_name() << "() throw() {}" << endl << endl;
-  }
-
-  // Pointer to this structure's reflection local typespec.
-  if (gen_dense_) {
-    indent(out) <<
-      "static ::apache::thrift::reflection::local::TypeSpec* local_reflection;" <<
-      endl << endl;
-  }
-
-  // Declare all fields
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    indent(out) <<
-      declare_field(*m_iter, false, pointers && !(*m_iter)->get_type()->is_xception(), !read) << endl;
-  }
-
-  // Add the __isset data member if we need it, using the definition from above
-  if (has_nonrequired_fields && (!pointers || read)) {
-    out <<
-      endl <<
-      indent() << "_" << tstruct->get_name() << "__isset __isset;" << endl;
-  }
-
-  // Create a setter function for each field
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    if (pointers) {
-      continue;
-    }
-    out <<
-      endl <<
-      indent() << "void __set_" << (*m_iter)->get_name() <<
-        "(" << type_name((*m_iter)->get_type(), false, true);
-    out << " val) {" << endl << indent() <<
-      indent() << (*m_iter)->get_name() << " = val;" << endl;
-
-    // assume all fields are required except optional fields.
-    // for optional fields change __isset.name to true
-    bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
-    if (is_optional) {
-      out <<
-        indent() <<
-        indent() << "__isset." << (*m_iter)->get_name() << " = true;" << endl;
-    }
-    out <<
-      indent()<< "}" << endl;
-  }
-  out << endl;
-
-  if (!pointers) {
-    // Generate an equality testing operator.  Make it inline since the compiler
-    // will do a better job than we would when deciding whether to inline it.
-    out <<
-      indent() << "bool operator == (const " << tstruct->get_name() << " & " <<
-      (members.size() > 0 ? "rhs" : "/* rhs */") << ") const" << endl;
-    scope_up(out);
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      // Most existing Thrift code does not use isset or optional/required,
-      // so we treat "default" fields as required.
-      if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
-        out <<
-          indent() << "if (!(" << (*m_iter)->get_name()
-                   << " == rhs." << (*m_iter)->get_name() << "))" << endl <<
-          indent() << "  return false;" << endl;
-      } else {
-        out <<
-          indent() << "if (__isset." << (*m_iter)->get_name()
-                   << " != rhs.__isset." << (*m_iter)->get_name() << ")" << endl <<
-          indent() << "  return false;" << endl <<
-          indent() << "else if (__isset." << (*m_iter)->get_name() << " && !("
-                   << (*m_iter)->get_name() << " == rhs." << (*m_iter)->get_name()
-                   << "))" << endl <<
-          indent() << "  return false;" << endl;
-      }
-    }
-    indent(out) << "return true;" << endl;
-    scope_down(out);
-    out <<
-      indent() << "bool operator != (const " << tstruct->get_name() << " &rhs) const {" << endl <<
-      indent() << "  return !(*this == rhs);" << endl <<
-      indent() << "}" << endl << endl;
-
-    // Generate the declaration of a less-than operator.  This must be
-    // implemented by the application developer if they wish to use it.  (They
-    // will get a link error if they try to use it without an implementation.)
-    out <<
-      indent() << "bool operator < (const "
-               << tstruct->get_name() << " & ) const;" << endl << endl;
-  }
-
-  if (read) {
-    if (gen_templates_) {
-      out <<
-        indent() << "template <class Protocol_>" << endl <<
-        indent() << "uint32_t read(Protocol_* iprot);" << endl;
-    } else {
-      out <<
-        indent() << "uint32_t read(" <<
-        "::apache::thrift::protocol::TProtocol* iprot);" << endl;
-    }
-  }
-  if (write) {
-    if (gen_templates_) {
-      out <<
-        indent() << "template <class Protocol_>" << endl <<
-        indent() << "uint32_t write(Protocol_* oprot) const;" << endl;
-    } else {
-      out <<
-        indent() << "uint32_t write(" <<
-        "::apache::thrift::protocol::TProtocol* oprot) const;" << endl;
-    }
-  }
-  out << endl;
-
-  indent_down();
-  indent(out) <<
-    "};" << endl <<
-    endl;
-
-  if (swap) {
-    // Generate a namespace-scope swap() function
-    out <<
-      indent() << "void swap(" << tstruct->get_name() << " &a, " <<
-      tstruct->get_name() << " &b);" << endl <<
-      endl;
-  }
-}
-
-/**
- * Writes the fingerprint of a struct to either the header or implementation.
- *
- * @param out Output stream
- * @param tstruct The struct
- */
-void t_cpp_generator::generate_struct_fingerprint(ofstream& out,
-                                                  t_struct* tstruct,
-                                                  bool is_definition) {
-  string stat, nspace, comment;
-  if (is_definition) {
-    stat = "";
-    nspace = tstruct->get_name() + "::";
-    comment = " ";
-  } else {
-    stat = "static ";
-    nspace = "";
-    comment = "; // ";
-  }
-
-  if (tstruct->has_fingerprint()) {
-    out <<
-      indent() << stat << "const char* " << nspace
-        << "ascii_fingerprint" << comment << "= \"" <<
-        tstruct->get_ascii_fingerprint() << "\";" << endl <<
-      indent() << stat << "const uint8_t " << nspace <<
-        "binary_fingerprint[" << t_type::fingerprint_len << "]" << comment << "= {";
-    const char* comma = "";
-    for (int i = 0; i < t_type::fingerprint_len; i++) {
-      out << comma << "0x" << t_struct::byte_to_hex(tstruct->get_binary_fingerprint()[i]);
-      comma = ",";
-    }
-    out << "};" << endl << endl;
-  }
-}
-
-/**
- * Writes the local reflection of a type (either declaration or definition).
- */
-void t_cpp_generator::generate_local_reflection(std::ofstream& out,
-                                                t_type* ttype,
-                                                bool is_definition) {
-  if (!gen_dense_) {
-    return;
-  }
-  ttype = get_true_type(ttype);
-  assert(ttype->has_fingerprint());
-  string key = ttype->get_ascii_fingerprint() + (is_definition ? "-defn" : "-decl");
-  // Note that we have generated this fingerprint.  If we already did, bail out.
-  if (!reflected_fingerprints_.insert(key).second) {
-    return;
-  }
-  // Let each program handle its own structures.
-  if (ttype->get_program() != NULL && ttype->get_program() != program_) {
-    return;
-  }
-
-  // Do dependencies.
-  if (ttype->is_list()) {
-    generate_local_reflection(out, ((t_list*)ttype)->get_elem_type(), is_definition);
-  } else if (ttype->is_set()) {
-    generate_local_reflection(out, ((t_set*)ttype)->get_elem_type(), is_definition);
-  } else if (ttype->is_map()) {
-    generate_local_reflection(out, ((t_map*)ttype)->get_key_type(), is_definition);
-    generate_local_reflection(out, ((t_map*)ttype)->get_val_type(), is_definition);
-  } else if (ttype->is_struct() || ttype->is_xception()) {
-    // Hacky hacky.  For efficiency and convenience, we need a dummy "T_STOP"
-    // type at the end of our typespec array.  Unfortunately, there is no
-    // T_STOP type, so we use the global void type, and special case it when
-    // generating its typespec.
-
-    const vector<t_field*>& members = ((t_struct*)ttype)->get_sorted_members();
-    vector<t_field*>::const_iterator m_iter;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      generate_local_reflection(out, (**m_iter).get_type(), is_definition);
-    }
-    generate_local_reflection(out, g_type_void, is_definition);
-
-    // For definitions of structures, do the arrays of metas and field specs also.
-    if (is_definition) {
-      out <<
-        indent() << "::apache::thrift::reflection::local::FieldMeta" << endl <<
-        indent() << local_reflection_name("metas", ttype) <<"[] = {" << endl;
-      indent_up();
-      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-        indent(out) << "{ " << (*m_iter)->get_key() << ", " <<
-          (((*m_iter)->get_req() == t_field::T_OPTIONAL) ? "true" : "false") <<
-          " }," << endl;
-      }
-      // Zero for the T_STOP marker.
-      indent(out) << "{ 0, false }" << endl << "};" << endl;
-      indent_down();
-
-      out <<
-        indent() << "::apache::thrift::reflection::local::TypeSpec*" << endl <<
-        indent() << local_reflection_name("specs", ttype) <<"[] = {" << endl;
-      indent_up();
-      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-        indent(out) << "&" <<
-          local_reflection_name("typespec", (*m_iter)->get_type(), true) << "," << endl;
-      }
-      indent(out) << "&" <<
-        local_reflection_name("typespec", g_type_void) << "," << endl;
-      indent_down();
-      indent(out) << "};" << endl;
-    }
-  }
-
-  out <<
-    indent() << "// " << ttype->get_fingerprint_material() << endl <<
-    indent() << (is_definition ? "" : "extern ") <<
-      "::apache::thrift::reflection::local::TypeSpec" << endl <<
-      local_reflection_name("typespec", ttype) <<
-      (is_definition ? "(" : ";") << endl;
-
-  if (!is_definition) {
-    out << endl;
-    return;
-  }
-
-  indent_up();
-
-  if (ttype->is_void()) {
-    indent(out) << "::apache::thrift::protocol::T_STOP";
-  } else {
-    indent(out) << type_to_enum(ttype);
-  }
-
-  if (ttype->is_struct()) {
-    out << "," << endl <<
-      indent() << type_name(ttype) << "::binary_fingerprint," << endl <<
-      indent() << local_reflection_name("metas", ttype) << "," << endl <<
-      indent() << local_reflection_name("specs", ttype);
-  } else if (ttype->is_list()) {
-    out << "," << endl <<
-      indent() << "&" << local_reflection_name("typespec", ((t_list*)ttype)->get_elem_type(), true) << "," << endl <<
-      indent() << "NULL";
-  } else if (ttype->is_set()) {
-    out << "," << endl <<
-      indent() << "&" << local_reflection_name("typespec", ((t_set*)ttype)->get_elem_type(), true) << "," << endl <<
-      indent() << "NULL";
-  } else if (ttype->is_map()) {
-    out << "," << endl <<
-      indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_key_type(), true) << "," << endl <<
-      indent() << "&" << local_reflection_name("typespec", ((t_map*)ttype)->get_val_type(), true);
-  }
-
-  out << ");" << endl << endl;
-
-  indent_down();
-}
-
-/**
- * Writes the structure's static pointer to its local reflection typespec
- * into the implementation file.
- */
-void t_cpp_generator::generate_local_reflection_pointer(std::ofstream& out,
-                                                        t_type* ttype) {
-  if (!gen_dense_) {
-    return;
-  }
-  indent(out) <<
-    "::apache::thrift::reflection::local::TypeSpec* " <<
-      ttype->get_name() << "::local_reflection = " << endl <<
-    indent() << "  &" << local_reflection_name("typespec", ttype) << ";" <<
-    endl << endl;
-}
-
-/**
- * Makes a helper function to gen a struct reader.
- *
- * @param out Stream to write to
- * @param tstruct The struct
- */
-void t_cpp_generator::generate_struct_reader(ofstream& out,
-                                             t_struct* tstruct,
-                                             bool pointers) {
-  if (gen_templates_) {
-    out <<
-      indent() << "template <class Protocol_>" << endl <<
-      indent() << "uint32_t " << tstruct->get_name() <<
-      "::read(Protocol_* iprot) {" << endl;
-  } else {
-    indent(out) <<
-      "uint32_t " << tstruct->get_name() <<
-      "::read(::apache::thrift::protocol::TProtocol* iprot) {" << endl;
-  }
-  indent_up();
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  // Declare stack tmp variables
-  out <<
-    endl <<
-    indent() << "uint32_t xfer = 0;" << endl <<
-    indent() << "std::string fname;" << endl <<
-    indent() << "::apache::thrift::protocol::TType ftype;" << endl <<
-    indent() << "int16_t fid;" << endl <<
-    endl <<
-    indent() << "xfer += iprot->readStructBegin(fname);" << endl <<
-    endl <<
-    indent() << "using ::apache::thrift::protocol::TProtocolException;" << endl <<
-    endl;
-
-  // Required variables aren't in __isset, so we need tmp vars to check them.
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if ((*f_iter)->get_req() == t_field::T_REQUIRED)
-      indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
-  }
-  out << endl;
-
-
-  // Loop over reading in fields
-  indent(out) <<
-    "while (true)" << endl;
-    scope_up(out);
-
-    // Read beginning field marker
-    indent(out) <<
-      "xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl;
-
-    // Check for field STOP marker
-    out <<
-      indent() << "if (ftype == ::apache::thrift::protocol::T_STOP) {" << endl <<
-      indent() << "  break;" << endl <<
-      indent() << "}" << endl;
-
-    if(fields.empty()) {
-      out <<
-        indent() << "xfer += iprot->skip(ftype);" << endl;
-    }
-    else {
-      // Switch statement on the field we are reading
-      indent(out) <<
-        "switch (fid)" << endl;
-
-        scope_up(out);
-
-        // Generate deserialization code for known cases
-        for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-          indent(out) <<
-            "case " << (*f_iter)->get_key() << ":" << endl;
-          indent_up();
-          indent(out) <<
-            "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
-          indent_up();
-
-          const char *isset_prefix =
-            ((*f_iter)->get_req() != t_field::T_REQUIRED) ? "this->__isset." : "isset_";
-
-#if 0
-          // This code throws an exception if the same field is encountered twice.
-          // We've decided to leave it out for performance reasons.
-          // TODO(dreiss): Generate this code and "if" it out to make it easier
-          // for people recompiling thrift to include it.
-          out <<
-            indent() << "if (" << isset_prefix << (*f_iter)->get_name() << ")" << endl <<
-            indent() << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
-#endif
-
-          if (pointers && !(*f_iter)->get_type()->is_xception()) {
-            generate_deserialize_field(out, *f_iter, "(*(this->", "))");
-          } else {
-            generate_deserialize_field(out, *f_iter, "this->");
-          }
-          out <<
-            indent() << isset_prefix << (*f_iter)->get_name() << " = true;" << endl;
-          indent_down();
-          out <<
-            indent() << "} else {" << endl <<
-            indent() << "  xfer += iprot->skip(ftype);" << endl <<
-            // TODO(dreiss): Make this an option when thrift structs
-            // have a common base class.
-            // indent() << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl <<
-            indent() << "}" << endl <<
-            indent() << "break;" << endl;
-          indent_down();
-      }
-
-      // In the default case we skip the field
-      out <<
-        indent() << "default:" << endl <<
-        indent() << "  xfer += iprot->skip(ftype);" << endl <<
-        indent() << "  break;" << endl;
-
-      scope_down(out);
-    } //!fields.empty()
-    // Read field end marker
-    indent(out) <<
-      "xfer += iprot->readFieldEnd();" << endl;
-
-    scope_down(out);
-
-  out <<
-    endl <<
-    indent() << "xfer += iprot->readStructEnd();" << endl;
-
-  // Throw if any required fields are missing.
-  // We do this after reading the struct end so that
-  // there might possibly be a chance of continuing.
-  out << endl;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if ((*f_iter)->get_req() == t_field::T_REQUIRED)
-      out <<
-        indent() << "if (!isset_" << (*f_iter)->get_name() << ')' << endl <<
-        indent() << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
-  }
-
-  indent(out) << "return xfer;" << endl;
-
-  indent_down();
-  indent(out) <<
-    "}" << endl << endl;
-}
-
-/**
- * Generates the write function.
- *
- * @param out Stream to write to
- * @param tstruct The struct
- */
-void t_cpp_generator::generate_struct_writer(ofstream& out,
-                                             t_struct* tstruct,
-                                             bool pointers) {
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  if (gen_templates_) {
-    out <<
-      indent() << "template <class Protocol_>" << endl <<
-      indent() << "uint32_t " << tstruct->get_name() <<
-      "::write(Protocol_* oprot) const {" << endl;
-  } else {
-    indent(out) <<
-      "uint32_t " << tstruct->get_name() <<
-      "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl;
-  }
-  indent_up();
-
-  out <<
-    indent() << "uint32_t xfer = 0;" << endl;
-
-  indent(out) <<
-    "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    bool check_if_set = (*f_iter)->get_req() == t_field::T_OPTIONAL ||
-                        (*f_iter)->get_type()->is_xception();
-    if (check_if_set) {
-      out << endl << indent() << "if (this->__isset." << (*f_iter)->get_name() << ") {" << endl;
-      indent_up();
-    } else {
-      out << endl;
-    }
-
-    // Write field header
-    out <<
-      indent() << "xfer += oprot->writeFieldBegin(" <<
-      "\"" << (*f_iter)->get_name() << "\", " <<
-      type_to_enum((*f_iter)->get_type()) << ", " <<
-      (*f_iter)->get_key() << ");" << endl;
-    // Write field contents
-    if (pointers && !(*f_iter)->get_type()->is_xception()) {
-      generate_serialize_field(out, *f_iter, "(*(this->", "))");
-    } else {
-      generate_serialize_field(out, *f_iter, "this->");
-    }
-    // Write field closer
-    indent(out) <<
-      "xfer += oprot->writeFieldEnd();" << endl;
-    if (check_if_set) {
-      indent_down();
-      indent(out) << '}';
-    }
-  }
-
-  out << endl;
-
-  // Write the struct map
-  out <<
-    indent() << "xfer += oprot->writeFieldStop();" << endl <<
-    indent() << "xfer += oprot->writeStructEnd();" << endl <<
-    indent() << "return xfer;" << endl;
-
-  indent_down();
-  indent(out) <<
-    "}" << endl <<
-    endl;
-}
-
-/**
- * Struct writer for result of a function, which can have only one of its
- * fields set and does a conditional if else look up into the __isset field
- * of the struct.
- *
- * @param out Output stream
- * @param tstruct The result struct
- */
-void t_cpp_generator::generate_struct_result_writer(ofstream& out,
-                                                    t_struct* tstruct,
-                                                    bool pointers) {
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  if (gen_templates_) {
-    out <<
-      indent() << "template <class Protocol_>" << endl <<
-      indent() << "uint32_t " << tstruct->get_name() <<
-      "::write(Protocol_* oprot) const {" << endl;
-  } else {
-    indent(out) <<
-      "uint32_t " << tstruct->get_name() <<
-      "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl;
-  }
-  indent_up();
-
-  out <<
-    endl <<
-    indent() << "uint32_t xfer = 0;" << endl <<
-    endl;
-
-  indent(out) <<
-    "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
-
-  bool first = true;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (first) {
-      first = false;
-      out <<
-        endl <<
-        indent() << "if ";
-    } else {
-      out <<
-        " else if ";
-    }
-
-    out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl;
-
-    indent_up();
-
-    // Write field header
-    out <<
-      indent() << "xfer += oprot->writeFieldBegin(" <<
-      "\"" << (*f_iter)->get_name() << "\", " <<
-      type_to_enum((*f_iter)->get_type()) << ", " <<
-      (*f_iter)->get_key() << ");" << endl;
-    // Write field contents
-    if (pointers) {
-      generate_serialize_field(out, *f_iter, "(*(this->", "))");
-    } else {
-      generate_serialize_field(out, *f_iter, "this->");
-    }
-    // Write field closer
-    indent(out) << "xfer += oprot->writeFieldEnd();" << endl;
-
-    indent_down();
-    indent(out) << "}";
-  }
-
-  // Write the struct map
-  out <<
-    endl <<
-    indent() << "xfer += oprot->writeFieldStop();" << endl <<
-    indent() << "xfer += oprot->writeStructEnd();" << endl <<
-    indent() << "return xfer;" << endl;
-
-  indent_down();
-  indent(out) <<
-    "}" << endl <<
-    endl;
-}
-
-/**
- * Generates the swap function.
- *
- * @param out Stream to write to
- * @param tstruct The struct
- */
-void t_cpp_generator::generate_struct_swap(ofstream& out, t_struct* tstruct) {
-  out <<
-    indent() << "void swap(" << tstruct->get_name() << " &a, " <<
-    tstruct->get_name() << " &b) {" << endl;
-  indent_up();
-
-  // Let argument-dependent name lookup find the correct swap() function to
-  // use based on the argument types.  If none is found in the arguments'
-  // namespaces, fall back to ::std::swap().
-  out <<
-    indent() << "using ::std::swap;" << endl;
-
-  bool has_nonrequired_fields = false;
-  const vector<t_field*>& fields = tstruct->get_members();
-  for (vector<t_field*>::const_iterator f_iter = fields.begin();
-       f_iter != fields.end();
-       ++f_iter) {
-    t_field *tfield = *f_iter;
-
-    if (tfield->get_req() != t_field::T_REQUIRED) {
-      has_nonrequired_fields = true;
-    }
-
-    out <<
-      indent() << "swap(a." << tfield->get_name() <<
-      ", b." << tfield->get_name() << ");" << endl;
-  }
-
-  if (has_nonrequired_fields) {
-    out <<
-      indent() << "swap(a.__isset, b.__isset);" << endl;
-  }
-
-  // handle empty structs
-  if (fields.size() == 0) {
-    out <<
-      indent() << "(void) a;" << endl;
-    out <<
-      indent() << "(void) b;" << endl;
-  }
-
-  scope_down(out);
-  out << endl;
-}
-
-/**
- * Generates a thrift service. In C++, this comprises an entirely separate
- * header and source file. The header file defines the methods and includes
- * the data types defined in the main header file, and the implementation
- * file contains implementations of the basic printer and default interfaces.
- *
- * @param tservice The service definition
- */
-void t_cpp_generator::generate_service(t_service* tservice) {
-  string svcname = tservice->get_name();
-
-  // Make output files
-  string f_header_name = get_out_dir()+svcname+".h";
-  f_header_.open(f_header_name.c_str());
-
-  // Print header file includes
-  f_header_ <<
-    autogen_comment();
-  f_header_ <<
-    "#ifndef " << svcname << "_H" << endl <<
-    "#define " << svcname << "_H" << endl <<
-    endl;
-  if (gen_cob_style_) {
-    f_header_ <<
-      "#include <thrift/transport/TBufferTransports.h>" << endl << // TMemoryBuffer
-      "#include <thrift/cxxfunctional.h>" << endl <<
-      "namespace apache { namespace thrift { namespace async {" << endl <<
-      "class TAsyncChannel;" << endl <<
-      "}}}" << endl;
-  }
-  f_header_ <<
-    "#include <thrift/TDispatchProcessor.h>" << endl;
-  if (gen_cob_style_) {
-    f_header_ <<
-      "#include <thrift/async/TAsyncDispatchProcessor.h>" << endl;
-  }
-  f_header_ <<
-    "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
-    "_types.h\"" << endl;
-
-  t_service* extends_service = tservice->get_extends();
-  if (extends_service != NULL) {
-    f_header_ <<
-      "#include \"" << get_include_prefix(*(extends_service->get_program())) <<
-      extends_service->get_name() << ".h\"" << endl;
-  }
-
-  f_header_ <<
-    endl <<
-    ns_open_ << endl <<
-    endl;
-
-  // Service implementation file includes
-  string f_service_name = get_out_dir()+svcname+".cpp";
-  f_service_.open(f_service_name.c_str());
-  f_service_ <<
-    autogen_comment();
-  f_service_ <<
-    "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl;
-  if (gen_cob_style_) {
-    f_service_ <<
-      "#include \"thrift/async/TAsyncChannel.h\"" << endl;
-  }
-  if (gen_templates_) {
-    f_service_ <<
-      "#include \"" << get_include_prefix(*get_program()) << svcname <<
-      ".tcc\"" << endl;
-
-    string f_service_tcc_name = get_out_dir()+svcname+".tcc";
-    f_service_tcc_.open(f_service_tcc_name.c_str());
-    f_service_tcc_ <<
-      autogen_comment();
-    f_service_tcc_ <<
-      "#include \"" << get_include_prefix(*get_program()) << svcname <<
-      ".h\"" << endl;
-
-    f_service_tcc_ <<
-      "#ifndef " << svcname << "_TCC" << endl <<
-      "#define " << svcname << "_TCC" << endl <<
-      endl;
-
-    if (gen_cob_style_) {
-      f_service_tcc_ <<
-        "#include \"thrift/async/TAsyncChannel.h\"" << endl;
-    }
-  }
-
-  f_service_ <<
-    endl << ns_open_ << endl << endl;
-  f_service_tcc_ <<
-    endl << ns_open_ << endl << endl;
-
-  // Generate all the components
-  generate_service_interface(tservice, "");
-  generate_service_interface_factory(tservice, "");
-  generate_service_null(tservice, "");
-  generate_service_helpers(tservice);
-  generate_service_client(tservice, "");
-  generate_service_processor(tservice, "");
-  generate_service_multiface(tservice);
-  generate_service_skeleton(tservice);
-
-  // Generate all the cob components
-  if (gen_cob_style_) {
-    generate_service_interface(tservice, "CobCl");
-    generate_service_interface(tservice, "CobSv");
-    generate_service_interface_factory(tservice, "CobSv");
-    generate_service_null(tservice, "CobSv");
-    generate_service_client(tservice, "Cob");
-    generate_service_processor(tservice, "Cob");
-    generate_service_async_skeleton(tservice);
-  }
-
-  // Close the namespace
-  f_service_ <<
-    ns_close_ << endl <<
-    endl;
-  f_service_tcc_ <<
-    ns_close_ << endl <<
-    endl;
-  f_header_ <<
-    ns_close_ << endl <<
-    endl;
-
-  // TODO(simpkins): Make this a separate option
-  if (gen_templates_) {
-    f_header_ <<
-      "#include \"" << get_include_prefix(*get_program()) << svcname <<
-      ".tcc\"" << endl <<
-      "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
-      "_types.tcc\"" << endl <<
-      endl;
-  }
-
-  f_header_ <<
-    "#endif" << endl;
-  f_service_tcc_ <<
-    "#endif" << endl;
-
-  // Close the files
-  f_service_tcc_.close();
-  f_service_.close();
-  f_header_.close();
-}
-
-/**
- * Generates helper functions for a service. Basically, this generates types
- * for all the arguments and results to functions.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_cpp_generator::generate_service_helpers(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_);
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    t_struct* ts = (*f_iter)->get_arglist();
-    string name_orig = ts->get_name();
-
-    // TODO(dreiss): Why is this stuff not in generate_function_helpers?
-    ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_args");
-    generate_struct_definition(f_header_, ts, false);
-    generate_struct_reader(out, ts);
-    generate_struct_writer(out, ts);
-    ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs");
-    generate_struct_definition(f_header_, ts, false, true, false, true);
-    generate_struct_writer(out, ts, true);
-    ts->set_name(name_orig);
-
-    generate_function_helpers(tservice, *f_iter);
-  }
-}
-
-/**
- * Generates a service interface definition.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_cpp_generator::generate_service_interface(t_service* tservice, string style) {
-
-  string service_if_name = service_name_ + style + "If";
-  if (style == "CobCl") {
-    // Forward declare the client.
-    string client_name = service_name_ + "CobClient";
-    if (gen_templates_) {
-      client_name += "T";
-      service_if_name += "T";
-      indent(f_header_) <<
-        "template <class Protocol_>" << endl;
-    }
-    indent(f_header_) << "class " << client_name << ";" <<
-      endl << endl;
-  }
-
-  string extends = "";
-  if (tservice->get_extends() != NULL) {
-    extends = " : virtual public " + type_name(tservice->get_extends()) +
-      style + "If";
-    if (style == "CobCl" && gen_templates_) {
-      // TODO(simpkins): If gen_templates_ is enabled, we currently assume all
-      // parent services were also generated with templates enabled.
-      extends += "T<Protocol_>";
-    }
-  }
-
-  if (style == "CobCl" && gen_templates_) {
-    f_header_ << "template <class Protocol_>" << endl;
-  }
-  f_header_ <<
-    "class " << service_if_name << extends << " {" << endl <<
-    " public:" << endl;
-  indent_up();
-  f_header_ <<
-    indent() << "virtual ~" << service_if_name << "() {}" << endl;
-
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_header_ <<
-      indent() << "virtual " << function_signature(*f_iter, style) << " = 0;" << endl;
-  }
-  indent_down();
-  f_header_ <<
-    "};" << endl << endl;
-
-  if (style == "CobCl" && gen_templates_) {
-    // generate a backwards-compatible typedef for clients that do not
-    // know about the new template-style code
-    f_header_ <<
-      "typedef " << service_if_name <<
-      "< ::apache::thrift::protocol::TProtocol> " <<
-      service_name_ << style << "If;" <<
-      endl << endl;
-  }
-}
-
-/**
- * Generates a service interface factory.
- *
- * @param tservice The service to generate an interface factory for.
- */
-void t_cpp_generator::generate_service_interface_factory(t_service* tservice,
-                                                         string style) {
-  string service_if_name = service_name_ + style + "If";
-
-  // Figure out the name of the upper-most parent class.
-  // Getting everything to work out properly with inheritance is annoying.
-  // Here's what we're doing for now:
-  //
-  // - All handlers implement getHandler(), but subclasses use covariant return
-  //   types to return their specific service interface class type.  We have to
-  //   use raw pointers because of this; shared_ptr<> can't be used for
-  //   covariant return types.
-  //
-  // - Since we're not using shared_ptr<>, we also provide a releaseHandler()
-  //   function that must be called to release a pointer to a handler obtained
-  //   via getHandler().
-  //
-  //   releaseHandler() always accepts a pointer to the upper-most parent class
-  //   type.  This is necessary since the parent versions of releaseHandler()
-  //   may accept any of the parent types, not just the most specific subclass
-  //   type.  Implementations can use dynamic_cast to cast the pointer to the
-  //   subclass type if desired.
-  t_service* base_service = tservice;
-  while (base_service->get_extends() != NULL) {
-    base_service = base_service->get_extends();
-  }
-  string base_if_name = type_name(base_service) + style + "If";
-
-  // Generate the abstract factory class
-  string factory_name = service_if_name + "Factory";
-  string extends;
-  if (tservice->get_extends() != NULL) {
-    extends = " : virtual public " + type_name(tservice->get_extends()) +
-      style + "IfFactory";
-  }
-
-  f_header_ <<
-    "class " << factory_name << extends << " {" << endl <<
-    " public:" << endl;
-  indent_up();
-  f_header_ <<
-    indent() << "typedef " << service_if_name << " Handler;" << endl <<
-    endl <<
-    indent() << "virtual ~" << factory_name << "() {}" << endl <<
-    endl <<
-    indent() << "virtual " << service_if_name << "* getHandler(" <<
-      "const ::apache::thrift::TConnectionInfo& connInfo) = 0;" <<
-    endl <<
-    indent() << "virtual void releaseHandler(" << base_if_name <<
-    "* /* handler */) = 0;" << endl;
-
-  indent_down();
-  f_header_ <<
-    "};" << endl << endl;
-
-  // Generate the singleton factory class
-  string singleton_factory_name = service_if_name + "SingletonFactory";
-  f_header_ <<
-    "class " << singleton_factory_name <<
-    " : virtual public " << factory_name << " {" << endl <<
-    " public:" << endl;
-  indent_up();
-  f_header_ <<
-    indent() << singleton_factory_name << "(const boost::shared_ptr<" <<
-    service_if_name << ">& iface) : iface_(iface) {}" << endl <<
-    indent() << "virtual ~" << singleton_factory_name << "() {}" << endl <<
-    endl <<
-    indent() << "virtual " << service_if_name << "* getHandler(" <<
-      "const ::apache::thrift::TConnectionInfo&) {" << endl <<
-    indent() << "  return iface_.get();" << endl <<
-    indent() << "}" << endl <<
-    indent() << "virtual void releaseHandler(" << base_if_name <<
-    "* /* handler */) {}" << endl;
-
-  f_header_ <<
-    endl <<
-    " protected:" << endl <<
-    indent() << "boost::shared_ptr<" << service_if_name << "> iface_;" << endl;
-
-  indent_down();
-  f_header_ <<
-    "};" << endl << endl;
-}
-
-/**
- * Generates a null implementation of the service.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_cpp_generator::generate_service_null(t_service* tservice, string style) {
-  string extends = "";
-  if (tservice->get_extends() != NULL) {
-    extends = " , virtual public " + type_name(tservice->get_extends()) + style + "Null";
-  }
-  f_header_ <<
-    "class " << service_name_ << style << "Null : virtual public " << service_name_ << style << "If" << extends << " {" << endl <<
-    " public:" << endl;
-  indent_up();
-  f_header_ <<
-    indent() << "virtual ~" << service_name_ << style << "Null() {}" << endl;
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_header_ <<
-      indent() << function_signature(*f_iter, style, "", false) << " {" << endl;
-    indent_up();
-
-    t_type* returntype = (*f_iter)->get_returntype();
-    t_field returnfield(returntype, "_return");
-
-    if (style == "") {
-      if (returntype->is_void() || is_complex_type(returntype)) {
-        f_header_ << indent() << "return;" << endl;
-      } else {
-        f_header_ <<
-          indent() << declare_field(&returnfield, true) << endl <<
-          indent() << "return _return;" << endl;
-      }
-    } else if (style == "CobSv") {
-      if (returntype->is_void()) {
-        f_header_ << indent() << "return cob();" << endl;
-    } else {
-      t_field returnfield(returntype, "_return");
-      f_header_ <<
-        indent() << declare_field(&returnfield, true) << endl <<
-        indent() << "return cob(_return);" << endl;
-    }
-
-    } else {
-      throw "UNKNOWN STYLE";
-    }
-
-    indent_down();
-    f_header_ <<
-      indent() << "}" << endl;
-  }
-  indent_down();
-  f_header_ <<
-    "};" << endl << endl;
-}
-
-void t_cpp_generator::generate_function_call(ostream& out, t_function* tfunction, string target, string iface, string arg_prefix) {
-  bool first = true;
-  t_type* ret_type = get_true_type(tfunction->get_returntype());
-  out << indent();
-  if (!tfunction->is_oneway() && !ret_type->is_void()) {
-    if (is_complex_type(ret_type)) {
-      first = false;
-      out << iface << "->" << tfunction->get_name() << "(" << target;
-    } else {
-      out << target << " = " << iface << "->" << tfunction->get_name() << "(";
-    }
-  } else {
-    out << iface << "->" << tfunction->get_name() << "(";
-  }
-  const std::vector<t_field*>& fields = tfunction->get_arglist()->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (first) {
-      first = false;
-    } else {
-      out << ", ";
-    }
-    out << arg_prefix << (*f_iter)->get_name();
-  }
-  out << ");" << endl;
-}
-
-void t_cpp_generator::generate_service_async_skeleton(t_service* tservice) {
-  string svcname = tservice->get_name();
-
-  // Service implementation file includes
-  string f_skeleton_name = get_out_dir()+svcname+"_async_server.skeleton.cpp";
-
-  string ns = namespace_prefix(tservice->get_program()->get_namespace("cpp"));
-
-  ofstream f_skeleton;
-  f_skeleton.open(f_skeleton_name.c_str());
-  f_skeleton <<
-    "// This autogenerated skeleton file illustrates one way to adapt a synchronous" << endl <<
-    "// interface into an asynchronous interface. You should copy it to another" << endl <<
-    "// filename to avoid overwriting it and rewrite as asynchronous any functions" << endl <<
-    "// that would otherwise introduce unwanted latency." << endl <<
-    endl <<
-    "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl <<
-    "#include <thrift/protocol/TBinaryProtocol.h>" << endl <<
-    endl <<
-    "using namespace ::apache::thrift;" << endl <<
-    "using namespace ::apache::thrift::protocol;" << endl <<
-    "using namespace ::apache::thrift::transport;" << endl <<
-    "using namespace ::apache::thrift::async;" << endl <<
-    endl <<
-    "using boost::shared_ptr;" << endl <<
-    endl;
-
-  // the following code would not compile:
-  // using namespace ;
-  // using namespace ::;
-  if ( (!ns.empty()) && (ns.compare(" ::") != 0)) {
-    f_skeleton <<
-      "using namespace " << string(ns, 0, ns.size()-2) << ";" << endl <<
-      endl;
-  }
-
-  f_skeleton <<
-    "class " << svcname << "AsyncHandler : " <<
-    "public " << svcname << "CobSvIf {" << endl <<
-    " public:" << endl;
-  indent_up();
-  f_skeleton <<
-    indent() << svcname << "AsyncHandler() {" << endl <<
-    indent() << "  syncHandler_ = std::auto_ptr<" << svcname <<
-                "Handler>(new " << svcname << "Handler);" << endl <<
-    indent() << "  // Your initialization goes here" << endl <<
-    indent() << "}" << endl;
-  f_skeleton <<
-    indent() << "virtual ~" << service_name_ << "AsyncHandler();" << endl;
-
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_skeleton <<
-      endl <<
-      indent() << function_signature(*f_iter, "CobSv", "", true) << " {" << endl;
-    indent_up();
-
-    t_type* returntype = (*f_iter)->get_returntype();
-    t_field returnfield(returntype, "_return");
-
-    string target = returntype->is_void() ? "" : "_return";
-    if (!returntype->is_void()) {
-      f_skeleton <<
-        indent() << declare_field(&returnfield, true) << endl;
-    }
-    generate_function_call(f_skeleton, *f_iter, target, "syncHandler_", "");
-    f_skeleton << indent() << "return cob(" << target << ");" << endl;
-
-    scope_down(f_skeleton);
-  }
-  f_skeleton << endl <<
-    " protected:" << endl <<
-    indent() << "std::auto_ptr<" << svcname << "Handler> syncHandler_;" << endl;
-  indent_down();
-  f_skeleton <<
-    "};" << endl << endl;
-}
-
-/**
- * Generates a multiface, which is a single server that just takes a set
- * of objects implementing the interface and calls them all, returning the
- * value of the last one to be called.
- *
- * @param tservice The service to generate a multiserver for.
- */
-void t_cpp_generator::generate_service_multiface(t_service* tservice) {
-  // Generate the dispatch methods
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  string extends = "";
-  string extends_multiface = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_multiface = ", public " + extends + "Multiface";
-  }
-
-  string list_type = string("std::vector<boost::shared_ptr<") + service_name_ + "If> >";
-
-  // Generate the header portion
-  f_header_ <<
-    "class " << service_name_ << "Multiface : " <<
-    "virtual public " << service_name_ << "If" <<
-    extends_multiface << " {" << endl <<
-    " public:" << endl;
-  indent_up();
-  f_header_ <<
-    indent() << service_name_ << "Multiface(" << list_type << "& ifaces) : ifaces_(ifaces) {" << endl;
-  if (!extends.empty()) {
-    f_header_ <<
-      indent() << "  std::vector<boost::shared_ptr<" + service_name_ + "If> >::iterator iter;" << endl <<
-      indent() << "  for (iter = ifaces.begin(); iter != ifaces.end(); ++iter) {" << endl <<
-      indent() << "    " << extends << "Multiface::add(*iter);" << endl <<
-      indent() << "  }" << endl;
-  }
-  f_header_ <<
-    indent() << "}" << endl <<
-    indent() << "virtual ~" << service_name_ << "Multiface() {}" << endl;
-  indent_down();
-
-  // Protected data members
-  f_header_ <<
-    " protected:" << endl;
-  indent_up();
-  f_header_ <<
-    indent() << list_type << " ifaces_;" << endl <<
-    indent() << service_name_ << "Multiface() {}" << endl <<
-    indent() << "void add(boost::shared_ptr<" << service_name_ << "If> iface) {" << endl;
-  if (!extends.empty()) {
-    f_header_ <<
-      indent() << "  " << extends << "Multiface::add(iface);" << endl;
-  }
-  f_header_ <<
-    indent() << "  ifaces_.push_back(iface);" << endl <<
-    indent() << "}" << endl;
-  indent_down();
-
-  f_header_ <<
-    indent() << " public:" << endl;
-  indent_up();
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    t_struct* arglist = (*f_iter)->get_arglist();
-    const vector<t_field*>& args = arglist->get_members();
-    vector<t_field*>::const_iterator a_iter;
-
-    string call = string("ifaces_[i]->") + (*f_iter)->get_name() + "(";
-    bool first = true;
-    if (is_complex_type((*f_iter)->get_returntype())) {
-      call += "_return";
-      first = false;
-    }
-    for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
-      if (first) {
-        first = false;
-      } else {
-        call += ", ";
-      }
-      call += (*a_iter)->get_name();
-    }
-    call += ")";
-
-    f_header_ <<
-      indent() << function_signature(*f_iter, "") << " {" << endl;
-    indent_up();
-    f_header_ <<
-      indent() << "size_t sz = ifaces_.size();" << endl <<
-      indent() << "size_t i = 0;" << endl <<
-      indent() << "for (; i < (sz - 1); ++i) {" << endl;
-    indent_up();
-    f_header_ <<
-      indent() << call << ";" << endl;
-    indent_down();
-    f_header_ <<
-      indent() << "}" << endl;
-
-    if (!(*f_iter)->get_returntype()->is_void()) {
-      if (is_complex_type((*f_iter)->get_returntype())) {
-        f_header_ <<
-          indent() << call << ";" << endl <<
-          indent() << "return;" << endl;
-      } else {
-        f_header_ <<
-          indent() << "return " << call << ";" << endl;
-      }
-    } else {
-      f_header_ <<
-        indent() << call << ";" << endl;
-    }
-
-    indent_down();
-    f_header_ <<
-      indent() << "}" << endl <<
-      endl;
-  }
-
-  indent_down();
-  f_header_ <<
-    indent() << "};" << endl <<
-    endl;
-}
-
-/**
- * Generates a service client definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_cpp_generator::generate_service_client(t_service* tservice, string style) {
-  string ifstyle;
-  if (style == "Cob") {
-    ifstyle = "CobCl";
-  }
-
-  std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_);
-  string template_header, template_suffix, short_suffix, protocol_type, _this;
-  string const prot_factory_type =
-    "::apache::thrift::protocol::TProtocolFactory";
-  if (gen_templates_) {
-    template_header = "template <class Protocol_>\n";
-    short_suffix = "T";
-    template_suffix = "T<Protocol_>";
-    protocol_type = "Protocol_";
-    _this = "this->";
-  } else {
-    protocol_type = "::apache::thrift::protocol::TProtocol";
-  }
-  string prot_ptr = "boost::shared_ptr< " + protocol_type + ">";
-  string client_suffix = "Client" + template_suffix;
-  string if_suffix = "If";
-  if (style == "Cob") {
-    if_suffix += template_suffix;
-  }
-
-  string extends = "";
-  string extends_client = "";
-  if (tservice->get_extends() != NULL) {
-    // TODO(simpkins): If gen_templates_ is enabled, we currently assume all
-    // parent services were also generated with templates enabled.
-    extends = type_name(tservice->get_extends());
-    extends_client = ", public " + extends + style + client_suffix;
-  }
-
-  // Generate the header portion
-  f_header_ <<
-    template_header <<
-    "class " << service_name_ << style << "Client" << short_suffix << " : " <<
-    "virtual public " << service_name_ << ifstyle << if_suffix <<
-    extends_client << " {" << endl <<
-    " public:" << endl;
-
-  indent_up();
-  if (style != "Cob") {
-    f_header_ <<
-      indent() << service_name_ << style << "Client" << short_suffix <<
-      "(" << prot_ptr << " prot) :" <<
-      endl;
-    if (extends.empty()) {
-      f_header_ <<
-        indent() << "  piprot_(prot)," << endl <<
-        indent() << "  poprot_(prot) {" << endl <<
-        indent() << "  iprot_ = prot.get();" << endl <<
-        indent() << "  oprot_ = prot.get();" << endl <<
-        indent() << "}" << endl;
-    } else {
-      f_header_ <<
-        indent() << "  " << extends << style << client_suffix <<
-        "(prot, prot) {}" << endl;
-    }
-
-    f_header_ <<
-      indent() << service_name_ << style << "Client" << short_suffix <<
-      "(" << prot_ptr << " iprot, " << prot_ptr << " oprot) :" << endl;
-    if (extends.empty()) {
-      f_header_ <<
-        indent() << "  piprot_(iprot)," << endl <<
-        indent() << "  poprot_(oprot) {" << endl <<
-        indent() << "  iprot_ = iprot.get();" << endl <<
-        indent() << "  oprot_ = oprot.get();" << endl <<
-        indent() << "}" << endl;
-    } else {
-      f_header_ <<
-        indent() << "  " << extends << style << client_suffix <<
-        "(iprot, oprot) {}" << endl;
-    }
-
-    // Generate getters for the protocols.
-    // Note that these are not currently templated for simplicity.
-    // TODO(simpkins): should they be templated?
-    f_header_ <<
-      indent() << "boost::shared_ptr< ::apache::thrift::protocol::TProtocol> getInputProtocol() {" << endl <<
-      indent() << "  return " << _this << "piprot_;" << endl <<
-      indent() << "}" << endl;
-
-    f_header_ <<
-      indent() << "boost::shared_ptr< ::apache::thrift::protocol::TProtocol> getOutputProtocol() {" << endl <<
-      indent() << "  return " << _this << "poprot_;" << endl <<
-      indent() << "}" << endl;
-
-  } else /* if (style == "Cob") */ {
-    f_header_ <<
-      indent() << service_name_ << style << "Client" << short_suffix << "(" <<
-      "boost::shared_ptr< ::apache::thrift::async::TAsyncChannel> channel, " <<
-      "::apache::thrift::protocol::TProtocolFactory* protocolFactory) :" <<
-      endl;
-    if (extends.empty()) {
-      f_header_ <<
-        indent() << "  channel_(channel)," << endl <<
-        indent() << "  itrans_(new ::apache::thrift::transport::TMemoryBuffer())," << endl <<
-        indent() << "  otrans_(new ::apache::thrift::transport::TMemoryBuffer())," << endl;
-      if (gen_templates_) {
-        // TProtocolFactory classes return generic TProtocol pointers.
-        // We have to dynamic cast to the Protocol_ type we are expecting.
-        f_header_ <<
-          indent() << "  piprot_(boost::dynamic_pointer_cast<Protocol_>(" <<
-          "protocolFactory->getProtocol(itrans_)))," << endl <<
-          indent() << "  poprot_(boost::dynamic_pointer_cast<Protocol_>(" <<
-          "protocolFactory->getProtocol(otrans_))) {" << endl;
-        // Throw a TException if either dynamic cast failed.
-        f_header_ <<
-          indent() << "  if (!piprot_ || !poprot_) {" << endl <<
-          indent() << "    throw ::apache::thrift::TException(\"" <<
-          "TProtocolFactory returned unexpected protocol type in " <<
-          service_name_ << style << "Client" << short_suffix <<
-          " constructor\");" << endl <<
-          indent() << "  }" << endl;
-      } else {
-        f_header_ <<
-          indent() << "  piprot_(protocolFactory->getProtocol(itrans_))," <<
-          endl <<
-          indent() << "  poprot_(protocolFactory->getProtocol(otrans_)) {" <<
-          endl;
-      }
-      f_header_ <<
-        indent() << "  iprot_ = piprot_.get();" << endl <<
-        indent() << "  oprot_ = poprot_.get();" << endl <<
-        indent() << "}" << endl;
-    } else {
-      f_header_ <<
-        indent() << "  " << extends << style << client_suffix <<
-        "(channel, protocolFactory) {}" << endl;
-    }
-  }
-
-  if (style == "Cob") {
-    f_header_ <<
-      indent() << "boost::shared_ptr< ::apache::thrift::async::TAsyncChannel> getChannel() {" << endl <<
-      indent() << "  return " << _this << "channel_;" << endl <<
-      indent() << "}" << endl;
-    if (!gen_no_client_completion_) {
-      f_header_ <<
-        indent() << "virtual void completed__(bool /* success */) {}" << endl;
-    }
-  }
-
-  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) {
-    indent(f_header_) << function_signature(*f_iter, ifstyle) << ";" << endl;
-    // TODO(dreiss): Use private inheritance to avoid generating thise in cob-style.
-    t_function send_function(g_type_void,
-        string("send_") + (*f_iter)->get_name(),
-        (*f_iter)->get_arglist());
-    indent(f_header_) << function_signature(&send_function, "") << ";" << endl;
-    if (!(*f_iter)->is_oneway()) {
-      t_struct noargs(program_);
-      t_function recv_function((*f_iter)->get_returntype(),
-          string("recv_") + (*f_iter)->get_name(),
-          &noargs);
-      indent(f_header_) << function_signature(&recv_function, "") << ";" << endl;
-    }
-  }
-  indent_down();
-
-  if (extends.empty()) {
-    f_header_ <<
-      " protected:" << endl;
-    indent_up();
-
-    if (style == "Cob") {
-      f_header_ <<
-        indent() << "boost::shared_ptr< ::apache::thrift::async::TAsyncChannel> channel_;"  << endl <<
-        indent() << "boost::shared_ptr< ::apache::thrift::transport::TMemoryBuffer> itrans_;"  << endl <<
-        indent() << "boost::shared_ptr< ::apache::thrift::transport::TMemoryBuffer> otrans_;"  << endl;
-    }
-    f_header_ <<
-      indent() << prot_ptr << " piprot_;"  << endl <<
-      indent() << prot_ptr << " poprot_;"  << endl <<
-      indent() << protocol_type << "* iprot_;"  << endl <<
-      indent() << protocol_type << "* oprot_;"  << endl;
-
-    indent_down();
-  }
-
-  f_header_ <<
-    "};" << endl <<
-    endl;
-
-  if (gen_templates_) {
-    // Output a backwards compatibility typedef using
-    // TProtocol as the template parameter.
-    f_header_ <<
-      "typedef " << service_name_ << style <<
-      "ClientT< ::apache::thrift::protocol::TProtocol> " <<
-      service_name_ << style << "Client;" << endl <<
-      endl;
-  }
-
-  string scope = service_name_ + style + client_suffix + "::";
-
-  // Generate client method implementations
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    string funname = (*f_iter)->get_name();
-
-    // Open function
-    if (gen_templates_) {
-      indent(out) << template_header;
-    }
-    indent(out) <<
-      function_signature(*f_iter, ifstyle, scope) << endl;
-    scope_up(out);
-    indent(out) <<
-      "send_" << funname << "(";
-
-    // Get the struct of function call params
-    t_struct* arg_struct = (*f_iter)->get_arglist();
-
-    // Declare the function arguments
-    const vector<t_field*>& fields = arg_struct->get_members();
-    vector<t_field*>::const_iterator fld_iter;
-    bool first = true;
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      if (first) {
-        first = false;
-      } else {
-        out << ", ";
-      }
-      out << (*fld_iter)->get_name();
-    }
-    out << ");" << endl;
-
-    if (style != "Cob") {
-      if (!(*f_iter)->is_oneway()) {
-        out << indent();
-        if (!(*f_iter)->get_returntype()->is_void()) {
-          if (is_complex_type((*f_iter)->get_returntype())) {
-            out << "recv_" << funname << "(_return);" << endl;
-          } else {
-            out << "return recv_" << funname << "();" << endl;
-          }
-        } else {
-          out <<
-            "recv_" << funname << "();" << endl;
-        }
-      }
-    } else {
-      if (!(*f_iter)->is_oneway()) {
-        out <<
-          indent() << _this << "channel_->sendAndRecvMessage(" <<
-          "tcxx::bind(cob, this), " << _this << "otrans_.get(), " <<
-          _this << "itrans_.get());" << endl;
-      } else {
-        out <<
-        indent() << _this << "channel_->sendMessage(" <<
-          "tcxx::bind(cob, this), " << _this << "otrans_.get());" << endl;
-      }
-    }
-    scope_down(out);
-    out << endl;
-
-    //if (style != "Cob") // TODO(dreiss): Libify the client and don't generate this for cob-style
-    if (true) {
-      // Function for sending
-      t_function send_function(g_type_void,
-                               string("send_") + (*f_iter)->get_name(),
-                               (*f_iter)->get_arglist());
-
-      // Open the send function
-      if (gen_templates_) {
-        indent(out) << template_header;
-      }
-      indent(out) <<
-        function_signature(&send_function, "", scope) << endl;
-      scope_up(out);
-
-      // Function arguments and results
-      string argsname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs";
-      string resultname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_presult";
-
-      // Serialize the request
-      out <<
-        indent() << "int32_t cseqid = 0;" << endl <<
-        indent() << _this << "oprot_->writeMessageBegin(\"" <<
-        (*f_iter)->get_name() <<
-        "\", ::apache::thrift::protocol::T_CALL, cseqid);" << endl <<
-        endl <<
-        indent() << argsname << " args;" << endl;
-
-      for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-        out <<
-          indent() << "args." << (*fld_iter)->get_name() << " = &" << (*fld_iter)->get_name() << ";" << endl;
-      }
-
-      out <<
-        indent() << "args.write(" << _this << "oprot_);" << endl <<
-        endl <<
-        indent() << _this << "oprot_->writeMessageEnd();" << endl <<
-        indent() << _this << "oprot_->getTransport()->writeEnd();" << endl <<
-        indent() << _this << "oprot_->getTransport()->flush();" << endl;
-
-      scope_down(out);
-      out << endl;
-
-      // Generate recv function only if not an oneway function
-      if (!(*f_iter)->is_oneway()) {
-        t_struct noargs(program_);
-        t_function recv_function((*f_iter)->get_returntype(),
-                                 string("recv_") + (*f_iter)->get_name(),
-                                 &noargs);
-        // Open the recv function
-        if (gen_templates_) {
-          indent(out) << template_header;
-        }
-        indent(out) <<
-          function_signature(&recv_function, "", scope) << endl;
-        scope_up(out);
-
-        out <<
-          endl <<
-          indent() << "int32_t rseqid = 0;" << endl <<
-          indent() << "std::string fname;" << endl <<
-          indent() << "::apache::thrift::protocol::TMessageType mtype;" << endl;
-        if (style == "Cob" && !gen_no_client_completion_) {
-          out <<
-            indent() << "bool completed = false;" << endl << endl <<
-            indent() << "try {";
-          indent_up();
-        }
-        out << endl <<
-          indent() << _this << "iprot_->readMessageBegin(fname, mtype, rseqid);" << endl <<
-          indent() << "if (mtype == ::apache::thrift::protocol::T_EXCEPTION) {" << endl <<
-          indent() << "  ::apache::thrift::TApplicationException x;" << endl <<
-          indent() << "  x.read(" << _this << "iprot_);" << endl <<
-          indent() << "  " << _this << "iprot_->readMessageEnd();" << endl <<
-          indent() << "  " << _this << "iprot_->getTransport()->readEnd();" <<
-          endl;
-        if (style == "Cob" && !gen_no_client_completion_) {
-          out <<
-            indent() << "  completed = true;" << endl <<
-            indent() << "  completed__(true);" << endl;
-        }
-        out <<
-          indent() << "  throw x;" << endl <<
-          indent() << "}" << endl <<
-          indent() << "if (mtype != ::apache::thrift::protocol::T_REPLY) {" << endl <<
-          indent() << "  " << _this << "iprot_->skip(" <<
-          "::apache::thrift::protocol::T_STRUCT);" << endl <<
-          indent() << "  " << _this << "iprot_->readMessageEnd();" << endl <<
-          indent() << "  " << _this << "iprot_->getTransport()->readEnd();" <<
-          endl;
-        if (style == "Cob" && !gen_no_client_completion_) {
-          out <<
-            indent() << "  completed = true;" << endl <<
-            indent() << "  completed__(false);" << endl;
-        }
-        out <<
-          indent() << "}" << endl <<
-          indent() << "if (fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl <<
-          indent() << "  " << _this << "iprot_->skip(" <<
-          "::apache::thrift::protocol::T_STRUCT);" << endl <<
-          indent() << "  " << _this << "iprot_->readMessageEnd();" << endl <<
-          indent() << "  " << _this << "iprot_->getTransport()->readEnd();" <<
-          endl;
-        if (style == "Cob" && !gen_no_client_completion_) {
-          out <<
-            indent() << "  completed = true;" << endl <<
-            indent() << "  completed__(false);" << endl;
-        }
-        out <<
-          indent() << "}" << endl;
-
-        if (!(*f_iter)->get_returntype()->is_void() &&
-            !is_complex_type((*f_iter)->get_returntype())) {
-          t_field returnfield((*f_iter)->get_returntype(), "_return");
-          out <<
-            indent() << declare_field(&returnfield) << endl;
-        }
-
-        out <<
-          indent() << resultname << " result;" << endl;
-
-        if (!(*f_iter)->get_returntype()->is_void()) {
-          out <<
-            indent() << "result.success = &_return;" << endl;
-        }
-
-        out <<
-          indent() << "result.read(" << _this << "iprot_);" << endl <<
-          indent() << _this << "iprot_->readMessageEnd();" << endl <<
-          indent() << _this << "iprot_->getTransport()->readEnd();" << endl <<
-          endl;
-
-        // Careful, only look for _result if not a void function
-        if (!(*f_iter)->get_returntype()->is_void()) {
-          if (is_complex_type((*f_iter)->get_returntype())) {
-            out <<
-              indent() << "if (result.__isset.success) {" << endl <<
-              indent() << "  // _return pointer has now been filled" << endl;
-            if (style == "Cob" && !gen_no_client_completion_) {
-              out <<
-                indent() << "  completed = true;" << endl <<
-                indent() << "  completed__(true);" << endl;
-            }
-            out <<
-              indent() << "  return;" << endl <<
-              indent() << "}" << endl;
-          } else {
-            out <<
-              indent() << "if (result.__isset.success) {" << endl;
-            if (style == "Cob" && !gen_no_client_completion_) {
-              out <<
-                indent() << "  completed = true;" << endl <<
-                indent() << "  completed__(true);" << endl;
-            }
-            out <<
-              indent() << "  return _return;" << endl <<
-              indent() << "}" << 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) {
-          out <<
-            indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl;
-          if (style == "Cob" && !gen_no_client_completion_) {
-            out <<
-              indent() << "  completed = true;" << endl <<
-              indent() << "  completed__(true);" << endl;
-          }
-          out  <<
-            indent() << "  throw result." << (*x_iter)->get_name() << ";" << endl <<
-            indent() << "}" << endl;
-        }
-
-        // We only get here if we are a void function
-        if ((*f_iter)->get_returntype()->is_void()) {
-          if (style == "Cob" && !gen_no_client_completion_) {
-            out <<
-              indent() << "completed = true;" << endl <<
-              indent() << "completed__(true);" << endl;
-          }
-          indent(out) <<
-            "return;" << endl;
-        } else {
-          if (style == "Cob" && !gen_no_client_completion_) {
-            out <<
-              indent() << "completed = true;" << endl <<
-              indent() << "completed__(true);" << endl;
-          }
-          out <<
-            indent() << "throw ::apache::thrift::TApplicationException(::apache::thrift::TApplicationException::MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
-        }
-        if (style == "Cob" && !gen_no_client_completion_) {
-          indent_down();
-          out <<
-            indent() << "} catch (...) {" << endl <<
-            indent() << "  if (!completed) {" << endl <<
-            indent() << "    completed__(false);" << endl <<
-            indent() << "  }" << endl <<
-            indent() << "  throw;" << endl <<
-            indent() << "}" << endl;
-        }
-        // Close function
-        scope_down(out);
-        out << endl;
-      }
-    }
-  }
-}
-
-class ProcessorGenerator {
- public:
-  ProcessorGenerator(t_cpp_generator* generator, t_service* service,
-                     const string& style);
-
-  void run() {
-    generate_class_definition();
-
-    // Generate the dispatchCall() function
-    generate_dispatch_call(false);
-    if (generator_->gen_templates_) {
-      generate_dispatch_call(true);
-    }
-
-    // Generate all of the process subfunctions
-    generate_process_functions();
-
-    generate_factory();
-  }
-
-  void generate_class_definition();
-  void generate_dispatch_call(bool template_protocol);
-  void generate_process_functions();
-  void generate_factory();
-
- protected:
-  std::string type_name(t_type* ttype, bool in_typedef=false, bool arg=false) {
-    return generator_->type_name(ttype, in_typedef, arg);
-  }
-
-  std::string indent() {
-    return generator_->indent();
-  }
-  std::ostream& indent(std::ostream &os) {
-    return generator_->indent(os);
-  }
-
-  void indent_up() {
-    generator_->indent_up();
-  }
-  void indent_down() {
-    generator_->indent_down();
-  }
-
-  t_cpp_generator* generator_;
-  t_service* service_;
-  std::ofstream& f_header_;
-  std::ofstream& f_out_;
-  string service_name_;
-  string style_;
-  string pstyle_;
-  string class_name_;
-  string if_name_;
-  string factory_class_name_;
-  string finish_cob_;
-  string finish_cob_decl_;
-  string ret_type_;
-  string call_context_;
-  string cob_arg_;
-  string call_context_arg_;
-  string call_context_decl_;
-  string template_header_;
-  string template_suffix_;
-  string typename_str_;
-  string class_suffix_;
-  string extends_;
-};
-
-ProcessorGenerator::ProcessorGenerator(t_cpp_generator* generator,
-                                       t_service* service,
-                                       const string& style)
-  : generator_(generator),
-    service_(service),
-    f_header_(generator->f_header_),
-    f_out_(generator->gen_templates_ ?
-           generator->f_service_tcc_ : generator->f_service_),
-    service_name_(generator->service_name_),
-    style_(style) {
-  if (style_ == "Cob") {
-    pstyle_ = "Async";
-    class_name_ = service_name_ + pstyle_ + "Processor";
-    if_name_ = service_name_ + "CobSvIf";
-
-    finish_cob_ = "tcxx::function<void(bool ok)> cob, ";
-    finish_cob_decl_ = "tcxx::function<void(bool ok)>, ";
-    cob_arg_ = "cob, ";
-    ret_type_ = "void ";
-  } else {
-    class_name_ = service_name_ + "Processor";
-    if_name_ = service_name_ + "If";
-
-    ret_type_ = "bool ";
-    // TODO(edhall) callContext should eventually be added to TAsyncProcessor
-    call_context_ = ", void* callContext";
-    call_context_arg_ = ", callContext";
-    call_context_decl_ = ", void*";
-  }
-
-  factory_class_name_ = class_name_ + "Factory";
-
-  if (generator->gen_templates_) {
-    template_header_ = "template <class Protocol_>\n";
-    template_suffix_ = "<Protocol_>";
-    typename_str_ = "typename ";
-    class_name_ += "T";
-    factory_class_name_ += "T";
-  }
-
-  if (service_->get_extends() != NULL) {
-    extends_ = type_name(service_->get_extends()) + pstyle_ + "Processor";
-    if (generator_->gen_templates_) {
-      // TODO(simpkins): If gen_templates_ is enabled, we currently assume all
-      // parent services were also generated with templates enabled.
-      extends_ += "T<Protocol_>";
-    }
-  }
-}
-
-void ProcessorGenerator::generate_class_definition() {
-  // Generate the dispatch methods
-  vector<t_function*> functions = service_->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  string parent_class;
-  if (service_->get_extends() != NULL) {
-    parent_class = extends_;
-  } else {
-    if (style_ == "Cob") {
-      parent_class = "::apache::thrift::async::TAsyncDispatchProcessor";
-    } else {
-      parent_class = "::apache::thrift::TDispatchProcessor";
-    }
-
-    if (generator_->gen_templates_) {
-      parent_class += "T<Protocol_>";
-    }
-  }
-
-  // Generate the header portion
-  f_header_ <<
-    template_header_ <<
-    "class " << class_name_ << " : public " << parent_class << " {" << endl;
-
-  // Protected data members
-  f_header_ <<
-    " protected:" << endl;
-  indent_up();
-  f_header_ <<
-    indent() << "boost::shared_ptr<" << if_name_ << "> iface_;" << endl;
-  f_header_ <<
-    indent() << "virtual " << ret_type_ << "dispatchCall(" << finish_cob_ <<
-      "::apache::thrift::protocol::TProtocol* iprot, " <<
-      "::apache::thrift::protocol::TProtocol* oprot, " <<
-      "const std::string& fname, int32_t seqid" << call_context_ << ");" <<
-      endl;
-  if (generator_->gen_templates_) {
-    f_header_ <<
-      indent() << "virtual " << ret_type_ << "dispatchCallTemplated(" <<
-        finish_cob_ << "Protocol_* iprot, Protocol_* oprot, " <<
-        "const std::string& fname, int32_t seqid" << call_context_ << ");" <<
-        endl;
-  }
-  indent_down();
-
-  // Process function declarations
-  f_header_ <<
-    " private:" << endl;
-  indent_up();
-
-  // Declare processMap_
-  f_header_ <<
-    indent() << "typedef  void (" << class_name_ << "::*" <<
-      "ProcessFunction)(" << finish_cob_decl_ << "int32_t, " <<
-      "::apache::thrift::protocol::TProtocol*, " <<
-      "::apache::thrift::protocol::TProtocol*" << call_context_decl_ << ");" <<
-      endl;
-  if (generator_->gen_templates_) {
-    f_header_ <<
-      indent() << "typedef void (" << class_name_ << "::*" <<
-        "SpecializedProcessFunction)(" << finish_cob_decl_ << "int32_t, " <<
-        "Protocol_*, Protocol_*" << call_context_decl_ << ");" <<
-        endl <<
-      indent() << "struct ProcessFunctions {" << endl <<
-      indent() << "  ProcessFunction generic;" << endl <<
-      indent() << "  SpecializedProcessFunction specialized;" << endl <<
-      indent() << "  ProcessFunctions(ProcessFunction g, " <<
-        "SpecializedProcessFunction s) :" << endl <<
-      indent() << "    generic(g)," << endl <<
-      indent() << "    specialized(s) {}" << endl <<
-      indent() << "  ProcessFunctions() : generic(NULL), specialized(NULL) " <<
-        "{}" << endl <<
-      indent() << "};" << endl <<
-      indent() << "typedef std::map<std::string, ProcessFunctions> " <<
-        "ProcessMap;" << endl;
-  } else {
-    f_header_ <<
-      indent() << "typedef std::map<std::string, ProcessFunction> " <<
-        "ProcessMap;" << endl;
-  }
-  f_header_ <<
-    indent() << "ProcessMap processMap_;" << endl;
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    indent(f_header_) <<
-      "void process_" << (*f_iter)->get_name() << "(" << finish_cob_ << "int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot" << call_context_ << ");" << endl;
-    if (generator_->gen_templates_) {
-      indent(f_header_) <<
-        "void process_" << (*f_iter)->get_name() << "(" << finish_cob_ <<
-        "int32_t seqid, Protocol_* iprot, Protocol_* oprot" <<
-        call_context_ << ");" << endl;
-    }
-    if (style_ == "Cob") {
-      // XXX Factor this out, even if it is a pain.
-      string ret_arg = ((*f_iter)->get_returntype()->is_void()
-                        ? ""
-                        : ", const " + type_name((*f_iter)->get_returntype()) + "& _return");
-      f_header_ <<
-        indent() << "void return_" << (*f_iter)->get_name() <<
-        "(tcxx::function<void(bool ok)> cob, int32_t seqid, " <<
-        "::apache::thrift::protocol::TProtocol* oprot, " <<
-        "void* ctx" << ret_arg << ");" << endl;
-      if (generator_->gen_templates_) {
-        f_header_ <<
-          indent() << "void return_" << (*f_iter)->get_name() <<
-          "(tcxx::function<void(bool ok)> cob, int32_t seqid, " <<
-          "Protocol_* oprot, void* ctx" << ret_arg << ");" << endl;
-      }
-      // XXX Don't declare throw if it doesn't exist
-      f_header_ <<
-        indent() << "void throw_" << (*f_iter)->get_name() <<
-        "(tcxx::function<void(bool ok)> cob, int32_t seqid, " <<
-        "::apache::thrift::protocol::TProtocol* oprot, void* ctx, " <<
-        "::apache::thrift::TDelayedException* _throw);" << endl;
-      if (generator_->gen_templates_) {
-        f_header_ <<
-          indent() << "void throw_" << (*f_iter)->get_name() <<
-          "(tcxx::function<void(bool ok)> cob, int32_t seqid, " <<
-          "Protocol_* oprot, void* ctx, " <<
-          "::apache::thrift::TDelayedException* _throw);" << endl;
-      }
-    }
-  }
-
-  f_header_ <<
-    " public:" << endl <<
-    indent() << class_name_ <<
-    "(boost::shared_ptr<" << if_name_ << "> iface) :" << endl;
-  if (!extends_.empty()) {
-    f_header_ <<
-      indent() << "  " << extends_ << "(iface)," << endl;
-  }
-  f_header_ <<
-    indent() << "  iface_(iface) {" << endl;
-  indent_up();
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_header_ <<
-      indent() << "processMap_[\"" << (*f_iter)->get_name() << "\"] = ";
-    if (generator_->gen_templates_) {
-      f_header_ << "ProcessFunctions(" << endl;
-      if (generator_->gen_templates_only_) {
-        indent(f_header_) << "  NULL," << endl;
-      } else {
-        indent(f_header_) << "  &" << class_name_ << "::process_" <<
-          (*f_iter)->get_name() << "," << endl;
-      }
-      indent(f_header_) << "  &" << class_name_ << "::process_" <<
-        (*f_iter)->get_name() << ")";
-    } else {
-      f_header_ << "&" << class_name_ << "::process_" << (*f_iter)->get_name();
-    }
-    f_header_ <<
-      ";" << endl;
-  }
-
-  indent_down();
-  f_header_ <<
-    indent() << "}" << endl <<
-    endl <<
-    indent() << "virtual ~" << class_name_ << "() {}" << endl;
-  indent_down();
-  f_header_ <<
-    "};" << endl << endl;
-
-  if (generator_->gen_templates_) {
-    // Generate a backwards compatible typedef, for callers who don't know
-    // about the new template-style code.
-    //
-    // We can't use TProtocol as the template parameter, since ProcessorT
-    // provides overloaded versions of most methods, one of which accepts
-    // TProtocol pointers, and one which accepts Protocol_ pointers.  This
-    // results in a compile error if instantiated with Protocol_ == TProtocol.
-    // Therefore, we define TDummyProtocol solely so we can use it as the
-    // template parameter here.
-    f_header_ <<
-      "typedef " << class_name_ <<
-      "< ::apache::thrift::protocol::TDummyProtocol > " <<
-      service_name_ << pstyle_ << "Processor;" << endl << endl;
-  }
-}
-
-void ProcessorGenerator::generate_dispatch_call(bool template_protocol) {
-  string protocol = "::apache::thrift::protocol::TProtocol";
-  string function_suffix;
-  if (template_protocol) {
-    protocol = "Protocol_";
-    // We call the generic version dispatchCall(), and the specialized
-    // version dispatchCallTemplated().  We can't call them both
-    // dispatchCall(), since this will cause the compiler to issue a warning if
-    // a service that doesn't use templates inherits from a service that does
-    // use templates: the compiler complains that the subclass only implements
-    // the generic version of dispatchCall(), and hides the templated version.
-    // Using different names for the two functions prevents this.
-    function_suffix = "Templated";
-  }
-
-  f_out_ <<
-    template_header_ <<
-    ret_type_ << class_name_ <<
-    template_suffix_ << "::dispatchCall" << function_suffix << "(" <<
-    finish_cob_ << protocol << "* iprot, " << protocol << "* oprot, " <<
-    "const std::string& fname, int32_t seqid" << call_context_ << ") {" <<
-    endl;
-  indent_up();
-
-  // HOT: member function pointer map
-  f_out_ <<
-    indent() << typename_str_ << "ProcessMap::iterator pfn;" << endl <<
-    indent() << "pfn = processMap_.find(fname);" << endl <<
-    indent() << "if (pfn == processMap_.end()) {" << endl;
-  if (extends_.empty()) {
-    f_out_ <<
-      indent() << "  iprot->skip(::apache::thrift::protocol::T_STRUCT);" << endl <<
-      indent() << "  iprot->readMessageEnd();" << endl <<
-      indent() << "  iprot->getTransport()->readEnd();" << endl <<
-      indent() << "  ::apache::thrift::TApplicationException x(::apache::thrift::TApplicationException::UNKNOWN_METHOD, \"Invalid method name: '\"+fname+\"'\");" << endl <<
-      indent() << "  oprot->writeMessageBegin(fname, ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
-      indent() << "  x.write(oprot);" << endl <<
-      indent() << "  oprot->writeMessageEnd();" << endl <<
-      indent() << "  oprot->getTransport()->writeEnd();" << endl <<
-      indent() << "  oprot->getTransport()->flush();" << endl <<
-      indent() << (style_ == "Cob" ? "  return cob(true);" : "  return true;") << endl;
-  } else {
-    f_out_ <<
-      indent() << "  return "
-               << extends_ << "::dispatchCall("
-               << (style_ == "Cob" ? "cob, " : "")
-               << "iprot, oprot, fname, seqid" << call_context_arg_ << ");" << endl;
-  }
-  f_out_ <<
-    indent() << "}" << endl;
-  if (template_protocol) {
-    f_out_ <<
-      indent() << "(this->*(pfn->second.specialized))";
-  } else {
-    if (generator_->gen_templates_only_) {
-      // TODO: This is a null pointer, so nothing good will come from calling
-      // it.  Throw an exception instead.
-      f_out_ <<
-        indent() << "(this->*(pfn->second.generic))";
-    } else if (generator_->gen_templates_) {
-      f_out_ <<
-        indent() << "(this->*(pfn->second.generic))";
-    } else {
-      f_out_ <<
-        indent() << "(this->*(pfn->second))";
-    }
-  }
-  f_out_ << "(" << cob_arg_ << "seqid, iprot, oprot" <<
-    call_context_arg_ << ");" << endl;
-
-  // TODO(dreiss): return pfn ret?
-  if (style_ == "Cob") {
-    f_out_ <<
-      indent() << "return;" << endl;
-  } else {
-    f_out_ <<
-      indent() << "return true;" << endl;
-  }
-
-  indent_down();
-  f_out_ <<
-    "}" << endl <<
-    endl;
-}
-
-void ProcessorGenerator::generate_process_functions() {
-  vector<t_function*> functions = service_->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    if (generator_->gen_templates_) {
-      generator_->generate_process_function(service_, *f_iter, style_, false);
-      generator_->generate_process_function(service_, *f_iter, style_, true);
-    } else {
-      generator_->generate_process_function(service_, *f_iter, style_, false);
-    }
-  }
-}
-
-void ProcessorGenerator::generate_factory() {
-  string if_factory_name = if_name_ + "Factory";
-
-  // Generate the factory class definition
-  f_header_ <<
-    template_header_ <<
-    "class " << factory_class_name_ <<
-      " : public ::apache::thrift::" <<
-        (style_ == "Cob" ? "async::TAsyncProcessorFactory" :  "TProcessorFactory") <<
-        " {" << endl <<
-    " public:" << endl;
-  indent_up();
-
-  f_header_ <<
-    indent() << factory_class_name_ << "(const ::boost::shared_ptr< " <<
-      if_factory_name << " >& handlerFactory) :" << endl <<
-    indent() << "    handlerFactory_(handlerFactory) {}" << endl <<
-    endl <<
-    indent() << "::boost::shared_ptr< ::apache::thrift::" <<
-      (style_ == "Cob" ? "async::TAsyncProcessor" :  "TProcessor") << " > " <<
-      "getProcessor(const ::apache::thrift::TConnectionInfo& connInfo);" <<
-      endl;
-
-  f_header_ <<
-    endl <<
-    " protected:" << endl <<
-    indent() << "::boost::shared_ptr< " << if_factory_name <<
-      " > handlerFactory_;" << endl;
-
-  indent_down();
-  f_header_ <<
-    "};" << endl << endl;
-
-  // If we are generating templates, output a typedef for the plain
-  // factory name.
-  if (generator_->gen_templates_) {
-    f_header_ <<
-      "typedef " << factory_class_name_ <<
-      "< ::apache::thrift::protocol::TDummyProtocol > " <<
-      service_name_ << pstyle_ << "ProcessorFactory;" << endl << endl;
-  }
-
-  // Generate the getProcessor() method
-  f_out_ <<
-    template_header_ <<
-    indent() << "::boost::shared_ptr< ::apache::thrift::" <<
-      (style_ == "Cob" ? "async::TAsyncProcessor" :  "TProcessor") << " > " <<
-      factory_class_name_ << template_suffix_ << "::getProcessor(" <<
-      "const ::apache::thrift::TConnectionInfo& connInfo) {" << endl;
-  indent_up();
-
-  f_out_ <<
-    indent() << "::apache::thrift::ReleaseHandler< " << if_factory_name <<
-      " > cleanup(handlerFactory_);" << endl <<
-    indent() << "::boost::shared_ptr< " << if_name_ << " > handler(" <<
-      "handlerFactory_->getHandler(connInfo), cleanup);" << endl <<
-    indent() << "::boost::shared_ptr< ::apache::thrift::" <<
-      (style_ == "Cob" ? "async::TAsyncProcessor" :  "TProcessor") << " > " <<
-      "processor(new " << class_name_ << template_suffix_ <<
-      "(handler));" << endl <<
-    indent() << "return processor;" << endl;
-
-  indent_down();
-  f_out_ <<
-    indent() << "}" << endl;
-}
-
-/**
- * Generates a service processor definition.
- *
- * @param tservice The service to generate a processor for.
- */
-void t_cpp_generator::generate_service_processor(t_service* tservice,
-                                                 string style) {
-  ProcessorGenerator generator(this, tservice, style);
-  generator.run();
-}
-
-/**
- * Generates a struct and helpers for a function.
- *
- * @param tfunction The function
- */
-void t_cpp_generator::generate_function_helpers(t_service* tservice,
-                                                t_function* tfunction) {
-  if (tfunction->is_oneway()) {
-    return;
-  }
-
-  std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_);
-
-  t_struct result(program_, tservice->get_name() + "_" + 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_struct_definition(f_header_, &result, false);
-  generate_struct_reader(out, &result);
-  generate_struct_result_writer(out, &result);
-
-  result.set_name(tservice->get_name() + "_" + tfunction->get_name() + "_presult");
-  generate_struct_definition(f_header_, &result, false, true, true, gen_cob_style_);
-  generate_struct_reader(out, &result, true);
-  if (gen_cob_style_) {
-    generate_struct_writer(out, &result, true);
-  }
-
-}
-
-/**
- * Generates a process function definition.
- *
- * @param tfunction The function to write a dispatcher for
- */
-void t_cpp_generator::generate_process_function(t_service* tservice,
-                                                t_function* tfunction,
-                                                string style,
-                                                bool specialized) {
-  t_struct* arg_struct = tfunction->get_arglist();
-  const std::vector<t_field*>& fields = arg_struct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  t_struct* xs = tfunction->get_xceptions();
-  const std::vector<t_field*>& xceptions = xs->get_members();
-  vector<t_field*>::const_iterator x_iter;
-  string service_func_name = "\"" + tservice->get_name() + "." +
-    tfunction->get_name() + "\"";
-
-  std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_);
-
-  string prot_type =
-    (specialized ? "Protocol_" : "::apache::thrift::protocol::TProtocol");
-  string class_suffix;
-  if (gen_templates_) {
-    class_suffix = "T<Protocol_>";
-  }
-
-  // I tried to do this as one function.  I really did.  But it was too hard.
-  if (style != "Cob") {
-    // Open function
-    if (gen_templates_) {
-      out <<
-        indent() << "template <class Protocol_>" << endl;
-    }
-    const bool unnamed_oprot_seqid = tfunction->is_oneway() &&
-      !(gen_templates_ && !specialized);
-    out <<
-      "void " << tservice->get_name() << "Processor" << class_suffix << "::" <<
-      "process_" << tfunction->get_name() << "(" <<
-      "int32_t" << (unnamed_oprot_seqid ? ", " : " seqid, ") <<
-      prot_type << "* iprot, " <<
-      prot_type << "*" << (unnamed_oprot_seqid ? ", " : " oprot, ") <<
-      "void* callContext)" << endl;
-    scope_up(out);
-
-    string argsname = tservice->get_name() + "_" + tfunction->get_name() +
-      "_args";
-    string resultname = tservice->get_name() + "_" + tfunction->get_name() +
-      "_result";
-
-    if (tfunction->is_oneway() && !unnamed_oprot_seqid) {
-      out <<
-        indent() << "(void) seqid;" << endl <<
-        indent() << "(void) oprot;" << endl;
-    }
-
-    out <<
-      indent() << "void* ctx = NULL;" << endl <<
-      indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-      indent() << "  ctx = this->eventHandler_->getContext(" <<
-        service_func_name << ", callContext);" << endl <<
-      indent() << "}" << endl <<
-      indent() << "::apache::thrift::TProcessorContextFreer freer(" <<
-        "this->eventHandler_.get(), ctx, " << service_func_name << ");" <<
-        endl << endl <<
-      indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-      indent() << "  this->eventHandler_->preRead(ctx, " <<
-        service_func_name << ");" << endl <<
-      indent() << "}" << endl << endl <<
-      indent() << argsname << " args;" << endl <<
-      indent() << "args.read(iprot);" << endl <<
-      indent() << "iprot->readMessageEnd();" << endl <<
-      indent() << "uint32_t bytes = iprot->getTransport()->readEnd();" <<
-        endl << endl <<
-      indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-      indent() << "  this->eventHandler_->postRead(ctx, " <<
-        service_func_name << ", bytes);" << endl <<
-      indent() << "}" << endl <<
-      endl;
-
-    // Declare result
-    if (!tfunction->is_oneway()) {
-      out <<
-        indent() << resultname << " result;" << endl;
-    }
-
-    // Try block for functions with exceptions
-    out <<
-      indent() << "try {" << endl;
-    indent_up();
-
-    // Generate the function call
-    bool first = true;
-    out << indent();
-    if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
-      if (is_complex_type(tfunction->get_returntype())) {
-        first = false;
-        out << "iface_->" << tfunction->get_name() << "(result.success";
-      } else {
-        out << "result.success = iface_->" << tfunction->get_name() << "(";
-      }
-    } else {
-      out <<
-        "iface_->" << tfunction->get_name() << "(";
-    }
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      if (first) {
-        first = false;
-      } else {
-        out << ", ";
-      }
-      out << "args." << (*f_iter)->get_name();
-    }
-    out << ");" << endl;
-
-    // Set isset on success field
-    if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
-      out <<
-        indent() << "result.__isset.success = true;" << endl;
-    }
-
-    indent_down();
-    out << indent() << "}";
-
-    if (!tfunction->is_oneway()) {
-      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-        out << " catch (" << type_name((*x_iter)->get_type()) << " &" <<
-          (*x_iter)->get_name() << ") {" << endl;
-        if (!tfunction->is_oneway()) {
-          indent_up();
-          out <<
-            indent() << "result." << (*x_iter)->get_name() << " = " <<
-              (*x_iter)->get_name() << ";" << endl <<
-            indent() << "result.__isset." << (*x_iter)->get_name() <<
-              " = true;" << endl;
-          indent_down();
-          out << indent() << "}";
-        } else {
-          out << "}";
-        }
-      }
-    }
-
-    out << " catch (const std::exception& e) {" << endl;
-
-    indent_up();
-    out <<
-      indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-      indent() << "  this->eventHandler_->handlerError(ctx, " <<
-        service_func_name << ");" << endl <<
-      indent() << "}" << endl;
-
-    if (!tfunction->is_oneway()) {
-      out <<
-        endl <<
-        indent() << "::apache::thrift::TApplicationException x(e.what());" <<
-          endl <<
-        indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() <<
-          "\", ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
-        indent() << "x.write(oprot);" << endl <<
-        indent() << "oprot->writeMessageEnd();" << endl <<
-        indent() << "oprot->getTransport()->writeEnd();" << endl <<
-        indent() << "oprot->getTransport()->flush();" << endl;
-    }
-    out << indent() << "return;" << endl;
-    indent_down();
-    out << indent() << "}" << endl << endl;
-
-    // Shortcut out here for oneway functions
-    if (tfunction->is_oneway()) {
-      out <<
-        indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-        indent() << "  this->eventHandler_->asyncComplete(ctx, " <<
-          service_func_name << ");" << endl <<
-        indent() << "}" << endl << endl <<
-        indent() << "return;" << endl;
-      indent_down();
-      out << "}" << endl <<
-        endl;
-      return;
-    }
-
-    // Serialize the result into a struct
-    out <<
-      indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-      indent() << "  this->eventHandler_->preWrite(ctx, " <<
-        service_func_name << ");" << endl <<
-      indent() << "}" << endl << endl <<
-      indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() <<
-        "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl <<
-      indent() << "result.write(oprot);" << endl <<
-      indent() << "oprot->writeMessageEnd();" << endl <<
-      indent() << "bytes = oprot->getTransport()->writeEnd();" << endl <<
-      indent() << "oprot->getTransport()->flush();" << endl << endl <<
-      indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-      indent() << "  this->eventHandler_->postWrite(ctx, " <<
-        service_func_name << ", bytes);" << endl <<
-      indent() << "}" << endl;
-
-    // Close function
-    scope_down(out);
-    out << endl;
-  }
-
-  // Cob style.
-  else {
-    // Processor entry point.
-    // TODO(edhall) update for callContext when TEventServer is ready
-    if (gen_templates_) {
-      out <<
-        indent() << "template <class Protocol_>" << endl;
-    }
-    out <<
-      "void " << tservice->get_name() << "AsyncProcessor" << class_suffix <<
-      "::process_" << tfunction->get_name() <<
-      "(tcxx::function<void(bool ok)> cob, int32_t seqid, " <<
-      prot_type << "* iprot, " << prot_type << "* oprot)" << endl;
-    scope_up(out);
-
-    // TODO(simpkins): we could try to consoldate this
-    // with the non-cob code above
-    if (gen_templates_ && !specialized) {
-      // If these are instances of Protocol_, instead of any old TProtocol,
-      // use the specialized process function instead.
-      out <<
-        indent() << "Protocol_* _iprot = dynamic_cast<Protocol_*>(iprot);" <<
-        endl <<
-        indent() << "Protocol_* _oprot = dynamic_cast<Protocol_*>(oprot);" <<
-        endl <<
-        indent() << "if (_iprot && _oprot) {" << endl <<
-        indent() << "  return process_" << tfunction->get_name() <<
-        "(cob, seqid, _iprot, _oprot);" << endl <<
-        indent() << "}" << endl <<
-        indent() << "T_GENERIC_PROTOCOL(this, iprot, _iprot);" << endl <<
-        indent() << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" << endl << endl;
-    }
-
-    if (tfunction->is_oneway()) {
-      out <<
-        indent() << "(void) seqid;" << endl <<
-        indent() << "(void) oprot;" << endl;
-    }
-
-    out <<
-      indent() << tservice->get_name() + "_" + tfunction->get_name() <<
-        "_args args;" << endl <<
-      indent() << "void* ctx = NULL;" << endl <<
-      indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-      indent() << "  ctx = this->eventHandler_->getContext(" <<
-        service_func_name << ", NULL);" << endl <<
-      indent() << "}" << endl <<
-      indent() << "::apache::thrift::TProcessorContextFreer freer(" <<
-        "this->eventHandler_.get(), ctx, " << service_func_name << ");" <<
-        endl << endl <<
-      indent() << "try {" << endl;
-    indent_up();
-    out <<
-      indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-      indent() << "  this->eventHandler_->preRead(ctx, " <<
-        service_func_name << ");" << endl <<
-      indent() << "}" << endl <<
-      indent() << "args.read(iprot);" << endl <<
-      indent() << "iprot->readMessageEnd();" << endl <<
-      indent() << "uint32_t bytes = iprot->getTransport()->readEnd();" <<
-        endl <<
-      indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-      indent() << "  this->eventHandler_->postRead(ctx, " <<
-        service_func_name << ", bytes);" << endl <<
-      indent() << "}" << endl;
-    scope_down(out);
-
-    // TODO(dreiss): Handle TExceptions?  Expose to server?
-    out <<
-      indent() << "catch (const std::exception& exn) {" << endl <<
-      indent() << "  if (this->eventHandler_.get() != NULL) {" << endl <<
-      indent() << "    this->eventHandler_->handlerError(ctx, " <<
-        service_func_name << ");" << endl <<
-      indent() << "  }" << endl <<
-      indent() << "  return cob(false);" << endl <<
-      indent() << "}" << endl;
-
-    if (tfunction->is_oneway()) {
-      out <<
-        indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-        indent() << "  this->eventHandler_->asyncComplete(ctx, " <<
-          service_func_name << ");" << endl <<
-        indent() << "}" << endl;
-    }
-    // TODO(dreiss): Figure out a strategy for exceptions in async handlers.
-    out <<
-      indent() << "freer.unregister();" << endl;
-    if (tfunction->is_oneway()) {
-      // No return.  Just hand off our cob.
-      // TODO(dreiss): Call the cob immediately?
-      out <<
-        indent() << "iface_->" << tfunction->get_name() << "(" <<
-        "tcxx::bind(cob, true)" << endl;
-      indent_up(); indent_up();
-    } else {
-      string ret_arg, ret_placeholder;
-      if (!tfunction->get_returntype()->is_void()) {
-        ret_arg = ", const " + type_name(tfunction->get_returntype()) +
-          "& _return";
-        ret_placeholder = ", tcxx::placeholders::_1";
-      }
-
-      // When gen_templates_ is true, the return_ and throw_ functions are
-      // overloaded.  We have to declare pointers to them so that the compiler
-      // can resolve the correct overloaded version.
-      out <<
-        indent() << "void (" << tservice->get_name() << "AsyncProcessor" <<
-        class_suffix << "::*return_fn)(tcxx::function<void(bool ok)> " <<
-        "cob, int32_t seqid, " << prot_type << "* oprot, void* ctx" <<
-        ret_arg << ") =" << endl;
-      out <<
-        indent() << "  &" << tservice->get_name() << "AsyncProcessor" <<
-        class_suffix << "::return_" << tfunction->get_name() << ";" << endl;
-      if (!xceptions.empty()) {
-        out <<
-          indent() << "void (" << tservice->get_name() << "AsyncProcessor" <<
-          class_suffix << "::*throw_fn)(tcxx::function<void(bool ok)> " <<
-          "cob, int32_t seqid, " << prot_type << "* oprot, void* ctx, " <<
-          "::apache::thrift::TDelayedException* _throw) =" << endl;
-        out <<
-          indent() << "  &" << tservice->get_name() << "AsyncProcessor" <<
-          class_suffix << "::throw_" << tfunction->get_name() << ";" << endl;
-      }
-
-      out <<
-        indent() << "iface_->" << tfunction->get_name() << "(" << endl;
-      indent_up(); indent_up();
-      out <<
-        indent() << "tcxx::bind(return_fn, this, cob, seqid, oprot, ctx" <<
-        ret_placeholder << ")";
-      if (!xceptions.empty()) {
-        out
-          << ',' << endl <<
-          indent() << "tcxx::bind(throw_fn, this, cob, seqid, oprot, " <<
-          "ctx, tcxx::placeholders::_1)";
-      }
-    }
-
-    // XXX Whitespace cleanup.
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      out
-                 << ',' << endl <<
-        indent() << "args." << (*f_iter)->get_name();
-    }
-    out << ");" << endl;
-    indent_down(); indent_down();
-    scope_down(out);
-    out << endl;
-
-    // Normal return.
-    if (!tfunction->is_oneway()) {
-      string ret_arg_decl, ret_arg_name;
-      if (!tfunction->get_returntype()->is_void()) {
-        ret_arg_decl = ", const " + type_name(tfunction->get_returntype()) +
-          "& _return";
-        ret_arg_name = ", _return";
-      }
-      if (gen_templates_) {
-        out <<
-          indent() << "template <class Protocol_>" << endl;
-      }
-      out <<
-        "void " << tservice->get_name() << "AsyncProcessor" << class_suffix <<
-        "::return_" << tfunction->get_name() <<
-        "(tcxx::function<void(bool ok)> cob, int32_t seqid, " <<
-        prot_type << "* oprot, void* ctx" << ret_arg_decl << ')' << endl;
-      scope_up(out);
-
-      if (gen_templates_ && !specialized) {
-        // If oprot is a Protocol_ instance,
-        // use the specialized return function instead.
-        out <<
-          indent() << "Protocol_* _oprot = dynamic_cast<Protocol_*>(oprot);" <<
-          endl <<
-          indent() << "if (_oprot) {" << endl <<
-          indent() << "  return return_" << tfunction->get_name() <<
-          "(cob, seqid, _oprot, ctx" << ret_arg_name << ");" << endl <<
-          indent() << "}" << endl <<
-          indent() << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" <<
-          endl << endl;
-      }
-
-      out <<
-        indent() << tservice->get_name() << "_" << tfunction->get_name() <<
-          "_presult result;" << endl;
-      if (!tfunction->get_returntype()->is_void()) {
-        // The const_cast here is unfortunate, but it would be a pain to avoid,
-        // and we only do a write with this struct, which is const-safe.
-        out <<
-          indent() << "result.success = const_cast<" <<
-            type_name(tfunction->get_returntype()) << "*>(&_return);" <<
-            endl <<
-          indent() << "result.__isset.success = true;" << endl;
-      }
-      // Serialize the result into a struct
-      out <<
-        endl <<
-        indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-        indent() << "  ctx = this->eventHandler_->getContext(" <<
-          service_func_name << ", NULL);" << endl <<
-        indent() << "}" << endl <<
-        indent() << "::apache::thrift::TProcessorContextFreer freer(" <<
-          "this->eventHandler_.get(), ctx, " << service_func_name <<
-          ");" << endl << endl <<
-        indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-        indent() << "  this->eventHandler_->preWrite(ctx, " <<
-          service_func_name << ");" << endl <<
-        indent() << "}" << endl << endl <<
-        indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() <<
-          "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl <<
-        indent() << "result.write(oprot);" << endl <<
-        indent() << "oprot->writeMessageEnd();" << endl <<
-        indent() << "uint32_t bytes = oprot->getTransport()->writeEnd();" <<
-          endl <<
-        indent() << "oprot->getTransport()->flush();" << endl <<
-        indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-        indent() << "  this->eventHandler_->postWrite(ctx, " <<
-          service_func_name << ", bytes);" << endl <<
-        indent() << "}" << endl <<
-        indent() << "return cob(true);" << endl;
-      scope_down(out);
-      out << endl;
-    }
-
-    // Exception return.
-    if (!tfunction->is_oneway() && !xceptions.empty()) {
-      if (gen_templates_) {
-        out <<
-          indent() << "template <class Protocol_>" << endl;
-      }
-      out <<
-        "void " << tservice->get_name() << "AsyncProcessor" << class_suffix <<
-        "::throw_" << tfunction->get_name() <<
-        "(tcxx::function<void(bool ok)> cob, int32_t seqid, " <<
-        prot_type << "* oprot, void* ctx, " <<
-        "::apache::thrift::TDelayedException* _throw)" << endl;
-      scope_up(out);
-
-      if (gen_templates_ && !specialized) {
-        // If oprot is a Protocol_ instance,
-        // use the specialized throw function instead.
-        out <<
-          indent() << "Protocol_* _oprot = dynamic_cast<Protocol_*>(oprot);" <<
-          endl <<
-          indent() << "if (_oprot) {" << endl <<
-          indent() << "  return throw_" << tfunction->get_name() <<
-          "(cob, seqid, _oprot, ctx, _throw);" << endl <<
-          indent() << "}" << endl <<
-          indent() << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" <<
-          endl << endl;
-      }
-
-      // Get the event handler context
-      out <<
-        endl <<
-        indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-        indent() << "  ctx = this->eventHandler_->getContext(" <<
-          service_func_name << ", NULL);" << endl <<
-        indent() << "}" << endl <<
-        indent() << "::apache::thrift::TProcessorContextFreer freer(" <<
-          "this->eventHandler_.get(), ctx, " << service_func_name << ");" <<
-          endl << endl;
-
-      // Throw the TDelayedException, and catch the result
-      out <<
-        indent() << tservice->get_name() << "_" << tfunction->get_name() <<
-          "_result result;" << endl << endl <<
-        indent() << "try {" << endl;
-      indent_up();
-      out <<
-        indent() << "_throw->throw_it();" << endl <<
-        indent() << "return cob(false);" << endl;  // Is this possible?  TBD.
-      indent_down();
-      out <<
-        indent() << '}';
-      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-        out << "  catch (" << type_name((*x_iter)->get_type()) << " &" <<
-          (*x_iter)->get_name() << ") {" << endl;
-        indent_up();
-        out <<
-          indent() << "result." << (*x_iter)->get_name() << " = " <<
-            (*x_iter)->get_name() << ";" << endl <<
-          indent() << "result.__isset." << (*x_iter)->get_name() <<
-            " = true;" << endl;
-        scope_down(out);
-      }
-
-      // Handle the case where an undeclared exception is thrown
-      out << " catch (std::exception& e) {" << endl;
-      indent_up();
-      out <<
-        indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-        indent() << "  this->eventHandler_->handlerError(ctx, " <<
-          service_func_name << ");" << endl <<
-        indent() << "}" << endl <<
-        endl <<
-        indent() << "::apache::thrift::TApplicationException x(e.what());" <<
-          endl <<
-        indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() <<
-          "\", ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
-        indent() << "x.write(oprot);" << endl <<
-        indent() << "oprot->writeMessageEnd();" << endl <<
-        indent() << "oprot->getTransport()->writeEnd();" << endl <<
-        indent() << "oprot->getTransport()->flush();" << endl <<
-        // We pass true to the cob here, since we did successfully write a
-        // response, even though it is an exception response.
-        // It looks like the argument is currently ignored, anyway.
-        indent() << "return cob(true);" << endl;
-      scope_down(out);
-
-      // Serialize the result into a struct
-      out <<
-        indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-        indent() << "  this->eventHandler_->preWrite(ctx, " <<
-          service_func_name << ");" << endl <<
-        indent() << "}" << endl << endl <<
-        indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() <<
-          "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl <<
-        indent() << "result.write(oprot);" << endl <<
-        indent() << "oprot->writeMessageEnd();" << endl <<
-        indent() << "uint32_t bytes = oprot->getTransport()->writeEnd();" <<
-          endl <<
-        indent() << "oprot->getTransport()->flush();" << endl <<
-        indent() << "if (this->eventHandler_.get() != NULL) {" << endl <<
-        indent() << "  this->eventHandler_->postWrite(ctx, " <<
-          service_func_name << ", bytes);" << endl <<
-        indent() << "}" << endl <<
-        indent() << "return cob(true);" << endl;
-      scope_down(out);
-      out << endl;
-    } // for each function
-  } // cob style
-}
-
-/**
- * Generates a skeleton file of a server
- *
- * @param tservice The service to generate a server for.
- */
-void t_cpp_generator::generate_service_skeleton(t_service* tservice) {
-  string svcname = tservice->get_name();
-
-  // Service implementation file includes
-  string f_skeleton_name = get_out_dir()+svcname+"_server.skeleton.cpp";
-
-  string ns = namespace_prefix(tservice->get_program()->get_namespace("cpp"));
-
-  ofstream f_skeleton;
-  f_skeleton.open(f_skeleton_name.c_str());
-  f_skeleton <<
-    "// This autogenerated skeleton file illustrates how to build a server." << endl <<
-    "// You should copy it to another filename to avoid overwriting it." << endl <<
-    endl <<
-    "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl <<
-    "#include <thrift/protocol/TBinaryProtocol.h>" << endl <<
-    "#include <thrift/server/TSimpleServer.h>" << endl <<
-    "#include <thrift/transport/TServerSocket.h>" << endl <<
-    "#include <thrift/transport/TBufferTransports.h>" << endl <<
-    endl <<
-    "using namespace ::apache::thrift;" << endl <<
-    "using namespace ::apache::thrift::protocol;" << endl <<
-    "using namespace ::apache::thrift::transport;" << endl <<
-    "using namespace ::apache::thrift::server;" << endl <<
-    endl <<
-    "using boost::shared_ptr;" << endl <<
-    endl;
-
-  // the following code would not compile:
-  // using namespace ;
-  // using namespace ::;
-  if ( (!ns.empty()) && (ns.compare(" ::") != 0)) {
-    f_skeleton <<
-      "using namespace " << string(ns, 0, ns.size()-2) << ";" << endl <<
-      endl;
-  }
-
-  f_skeleton <<
-    "class " << svcname << "Handler : virtual public " << svcname << "If {" << endl <<
-    " public:" << endl;
-  indent_up();
-  f_skeleton <<
-    indent() << svcname << "Handler() {" << endl <<
-    indent() << "  // Your initialization goes here" << endl <<
-    indent() << "}" << endl <<
-    endl;
-
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_skeleton <<
-      indent() << function_signature(*f_iter, "") << " {" << endl <<
-      indent() << "  // Your implementation goes here" << endl <<
-      indent() << "  printf(\"" << (*f_iter)->get_name() << "\\n\");" << endl <<
-      indent() << "}" << endl <<
-      endl;
-  }
-
-  indent_down();
-  f_skeleton <<
-    "};" << endl <<
-    endl;
-
-  f_skeleton <<
-    indent() << "int main(int argc, char **argv) {" << endl;
-  indent_up();
-  f_skeleton <<
-    indent() << "int port = 9090;" << endl <<
-    indent() << "shared_ptr<" << svcname << "Handler> handler(new " << svcname << "Handler());" << endl <<
-    indent() << "shared_ptr<TProcessor> processor(new " << svcname << "Processor(handler));" << endl <<
-    indent() << "shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));" << endl <<
-    indent() << "shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());" << endl <<
-    indent() << "shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());" << endl <<
-    endl <<
-    indent() << "TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);" << endl <<
-    indent() << "server.serve();" << endl <<
-    indent() << "return 0;" << endl;
-  indent_down();
-  f_skeleton <<
-    "}" << endl <<
-    endl;
-
-  // Close the files
-  f_skeleton.close();
-}
-
-/**
- * Deserializes a field of any type.
- */
-void t_cpp_generator::generate_deserialize_field(ofstream& out,
-                                                 t_field* tfield,
-                                                 string prefix,
-                                                 string suffix) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  if (type->is_void()) {
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  string name = prefix + tfield->get_name() + suffix;
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct(out, (t_struct*)type, name);
-  } else if (type->is_container()) {
-    generate_deserialize_container(out, type, name);
-  } else if (type->is_base_type()) {
-    indent(out) <<
-      "xfer += iprot->";
-    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:
-      if (((t_base_type*)type)->is_binary()) {
-        out << "readBinary(" << name << ");";
-      }
-      else {
-        out << "readString(" << name << ");";
-      }
-      break;
-    case t_base_type::TYPE_BOOL:
-      out << "readBool(" << name << ");";
-      break;
-    case t_base_type::TYPE_BYTE:
-      out << "readByte(" << name << ");";
-      break;
-    case t_base_type::TYPE_I16:
-      out << "readI16(" << name << ");";
-      break;
-    case t_base_type::TYPE_I32:
-      out << "readI32(" << name << ");";
-      break;
-    case t_base_type::TYPE_I64:
-      out << "readI64(" << name << ");";
-      break;
-    case t_base_type::TYPE_DOUBLE:
-      out << "readDouble(" << name << ");";
-      break;
-    default:
-      throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + name;
-    }
-    out <<
-      endl;
-  } else if (type->is_enum()) {
-    string t = tmp("ecast");
-    out <<
-      indent() << "int32_t " << t << ";" << endl <<
-      indent() << "xfer += iprot->readI32(" << t << ");" << endl <<
-      indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
-           tfield->get_name().c_str(), type_name(type).c_str());
-  }
-}
-
-/**
- * Generates an unserializer for a variable. This makes two key assumptions,
- * first that there is a const char* variable named data that points to the
- * buffer for deserialization, and that there is a variable protocol which
- * is a reference to a TProtocol serialization object.
- */
-void t_cpp_generator::generate_deserialize_struct(ofstream& out,
-                                                  t_struct* tstruct,
-                                                  string prefix) {
-  (void) tstruct;
-  indent(out) <<
-    "xfer += " << prefix << ".read(iprot);" << endl;
-}
-
-void t_cpp_generator::generate_deserialize_container(ofstream& out,
-                                                     t_type* ttype,
-                                                     string prefix) {
-  scope_up(out);
-
-  string size = tmp("_size");
-  string ktype = tmp("_ktype");
-  string vtype = tmp("_vtype");
-  string etype = tmp("_etype");
-
-  t_container* tcontainer = (t_container*)ttype;
-  bool use_push = tcontainer->has_cpp_name();
-
-  indent(out) <<
-    prefix << ".clear();" << endl <<
-    indent() << "uint32_t " << size << ";" << endl;
-
-  // Declare variables, read header
-  if (ttype->is_map()) {
-    out <<
-      indent() << "::apache::thrift::protocol::TType " << ktype << ";" << endl <<
-      indent() << "::apache::thrift::protocol::TType " << vtype << ";" << endl <<
-      indent() << "xfer += iprot->readMapBegin(" <<
-                   ktype << ", " << vtype << ", " << size << ");" << endl;
-  } else if (ttype->is_set()) {
-    out <<
-      indent() << "::apache::thrift::protocol::TType " << etype << ";" << endl <<
-      indent() << "xfer += iprot->readSetBegin(" <<
-                   etype << ", " << size << ");" << endl;
-  } else if (ttype->is_list()) {
-    out <<
-      indent() << "::apache::thrift::protocol::TType " << etype << ";" << endl <<
-      indent() << "xfer += iprot->readListBegin(" <<
-      etype << ", " << size << ");" << endl;
-    if (!use_push) {
-      indent(out) << prefix << ".resize(" << size << ");" << endl;
-    }
-  }
-
-
-  // For loop iterates over elements
-  string i = tmp("_i");
-  out <<
-    indent() << "uint32_t " << i << ";" << endl <<
-    indent() << "for (" << i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl;
-
-    scope_up(out);
-
-    if (ttype->is_map()) {
-      generate_deserialize_map_element(out, (t_map*)ttype, prefix);
-    } else if (ttype->is_set()) {
-      generate_deserialize_set_element(out, (t_set*)ttype, prefix);
-    } else if (ttype->is_list()) {
-      generate_deserialize_list_element(out, (t_list*)ttype, prefix, use_push, i);
-    }
-
-    scope_down(out);
-
-  // Read container end
-  if (ttype->is_map()) {
-    indent(out) << "xfer += iprot->readMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) << "xfer += iprot->readSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) << "xfer += iprot->readListEnd();" << endl;
-  }
-
-  scope_down(out);
-}
-
-
-/**
- * Generates code to deserialize a map
- */
-void t_cpp_generator::generate_deserialize_map_element(ofstream& out,
-                                                       t_map* tmap,
-                                                       string prefix) {
-  string key = tmp("_key");
-  string val = tmp("_val");
-  t_field fkey(tmap->get_key_type(), key);
-  t_field fval(tmap->get_val_type(), val);
-
-  out <<
-    indent() << declare_field(&fkey) << endl;
-
-  generate_deserialize_field(out, &fkey);
-  indent(out) <<
-    declare_field(&fval, false, false, false, true) << " = " <<
-    prefix << "[" << key << "];" << endl;
-
-  generate_deserialize_field(out, &fval);
-}
-
-void t_cpp_generator::generate_deserialize_set_element(ofstream& out,
-                                                       t_set* tset,
-                                                       string prefix) {
-  string elem = tmp("_elem");
-  t_field felem(tset->get_elem_type(), elem);
-
-  indent(out) <<
-    declare_field(&felem) << endl;
-
-  generate_deserialize_field(out, &felem);
-
-  indent(out) <<
-    prefix << ".insert(" << elem << ");" << endl;
-}
-
-void t_cpp_generator::generate_deserialize_list_element(ofstream& out,
-                                                        t_list* tlist,
-                                                        string prefix,
-                                                        bool use_push,
-                                                        string index) {
-  if (use_push) {
-    string elem = tmp("_elem");
-    t_field felem(tlist->get_elem_type(), elem);
-    indent(out) << declare_field(&felem) << endl;
-    generate_deserialize_field(out, &felem);
-    indent(out) << prefix << ".push_back(" << elem << ");" << endl;
-  } else {
-    t_field felem(tlist->get_elem_type(), prefix + "[" + index + "]");
-    generate_deserialize_field(out, &felem);
-  }
-}
-
-
-/**
- * Serializes a field of any type.
- *
- * @param tfield The field to serialize
- * @param prefix Name to prepend to field name
- */
-void t_cpp_generator::generate_serialize_field(ofstream& out,
-                                               t_field* tfield,
-                                               string prefix,
-                                               string suffix) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  string name = prefix + tfield->get_name() + suffix;
-
-  // 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);
-  } else if (type->is_container()) {
-    generate_serialize_container(out, type, name);
-  } else if (type->is_base_type() || type->is_enum()) {
-
-    indent(out) <<
-      "xfer += 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:
-        if (((t_base_type*)type)->is_binary()) {
-          out << "writeBinary(" << name << ");";
-        }
-        else {
-          out << "writeString(" << name << ");";
-        }
-        break;
-      case t_base_type::TYPE_BOOL:
-        out << "writeBool(" << name << ");";
-        break;
-      case t_base_type::TYPE_BYTE:
-        out << "writeByte(" << name << ");";
-        break;
-      case t_base_type::TYPE_I16:
-        out << "writeI16(" << name << ");";
-        break;
-      case t_base_type::TYPE_I32:
-        out << "writeI32(" << name << ");";
-        break;
-      case t_base_type::TYPE_I64:
-        out << "writeI64(" << name << ");";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        out << "writeDouble(" << name << ");";
-        break;
-      default:
-        throw "compiler error: no C++ writer for base type " + t_base_type::t_base_name(tbase) + name;
-      }
-    } else if (type->is_enum()) {
-      out << "writeI32((int32_t)" << name << ");";
-    }
-    out << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
-           name.c_str(),
-           type_name(type).c_str());
-  }
-}
-
-/**
- * Serializes all the members of a struct.
- *
- * @param tstruct The struct to serialize
- * @param prefix  String prefix to attach to all fields
- */
-void t_cpp_generator::generate_serialize_struct(ofstream& out,
-                                                t_struct* tstruct,
-                                                string prefix) {
-  (void) tstruct;
-  indent(out) <<
-    "xfer += " << prefix << ".write(oprot);" << endl;
-}
-
-void t_cpp_generator::generate_serialize_container(ofstream& out,
-                                                   t_type* ttype,
-                                                   string prefix) {
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    indent(out) <<
-      "xfer += oprot->writeMapBegin(" <<
-      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
-      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
-      "static_cast<uint32_t>(" << prefix << ".size()));" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "xfer += oprot->writeSetBegin(" <<
-      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
-      "static_cast<uint32_t>(" << prefix << ".size()));" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "xfer += oprot->writeListBegin(" <<
-      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
-      "static_cast<uint32_t>(" << prefix << ".size()));" << endl;
-  }
-
-  string iter = tmp("_iter");
-  out <<
-    indent() << type_name(ttype) << "::const_iterator " << iter << ";" << endl <<
-    indent() << "for (" << iter << " = " << prefix  << ".begin(); " << iter << " != " << prefix << ".end(); ++" << iter << ")" << endl;
-  scope_up(out);
-    if (ttype->is_map()) {
-      generate_serialize_map_element(out, (t_map*)ttype, iter);
-    } else if (ttype->is_set()) {
-      generate_serialize_set_element(out, (t_set*)ttype, iter);
-    } else if (ttype->is_list()) {
-      generate_serialize_list_element(out, (t_list*)ttype, iter);
-    }
-  scope_down(out);
-
-  if (ttype->is_map()) {
-    indent(out) <<
-      "xfer += oprot->writeMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "xfer += oprot->writeSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "xfer += oprot->writeListEnd();" << endl;
-  }
-
-  scope_down(out);
-}
-
-/**
- * Serializes the members of a map.
- *
- */
-void t_cpp_generator::generate_serialize_map_element(ofstream& out,
-                                                     t_map* tmap,
-                                                     string iter) {
-  t_field kfield(tmap->get_key_type(), iter + "->first");
-  generate_serialize_field(out, &kfield, "");
-
-  t_field vfield(tmap->get_val_type(), iter + "->second");
-  generate_serialize_field(out, &vfield, "");
-}
-
-/**
- * Serializes the members of a set.
- */
-void t_cpp_generator::generate_serialize_set_element(ofstream& out,
-                                                     t_set* tset,
-                                                     string iter) {
-  t_field efield(tset->get_elem_type(), "(*" + iter + ")");
-  generate_serialize_field(out, &efield, "");
-}
-
-/**
- * Serializes the members of a list.
- */
-void t_cpp_generator::generate_serialize_list_element(ofstream& out,
-                                                      t_list* tlist,
-                                                      string iter) {
-  t_field efield(tlist->get_elem_type(), "(*" + iter + ")");
-  generate_serialize_field(out, &efield, "");
-}
-
-/**
- * Makes a :: prefix for a namespace
- *
- * @param ns The namespace, w/ periods in it
- * @return Namespaces
- */
-string t_cpp_generator::namespace_prefix(string ns) {
-  // Always start with "::", to avoid possible name collisions with
-  // other names in one of the current namespaces.
-  //
-  // We also need a leading space, in case the name is used inside of a
-  // template parameter.  "MyTemplate<::foo::Bar>" is not valid C++,
-  // since "<:" is an alternative token for "[".
-  string result = " ::";
-
-  if (ns.size() == 0) {
-    return result;
-  }
-  string::size_type loc;
-  while ((loc = ns.find(".")) != string::npos) {
-    result += ns.substr(0, loc);
-    result += "::";
-    ns = ns.substr(loc+1);
-  }
-  if (ns.size() > 0) {
-    result += ns + "::";
-  }
-  return result;
-}
-
-/**
- * Opens namespace.
- *
- * @param ns The namespace, w/ periods in it
- * @return Namespaces
- */
-string t_cpp_generator::namespace_open(string ns) {
-  if (ns.size() == 0) {
-    return "";
-  }
-  string result = "";
-  string separator = "";
-  string::size_type loc;
-  while ((loc = ns.find(".")) != string::npos) {
-    result += separator;
-    result += "namespace ";
-    result += ns.substr(0, loc);
-    result += " {";
-    separator = " ";
-    ns = ns.substr(loc+1);
-  }
-  if (ns.size() > 0) {
-    result += separator + "namespace " + ns + " {";
-  }
-  return result;
-}
-
-/**
- * Closes namespace.
- *
- * @param ns The namespace, w/ periods in it
- * @return Namespaces
- */
-string t_cpp_generator::namespace_close(string ns) {
-  if (ns.size() == 0) {
-    return "";
-  }
-  string result = "}";
-  string::size_type loc;
-  while ((loc = ns.find(".")) != string::npos) {
-    result += "}";
-    ns = ns.substr(loc+1);
-  }
-  result += " // namespace";
-  return result;
-}
-
-/**
- * Returns a C++ type name
- *
- * @param ttype The type
- * @return String of the type name, i.e. std::set<type>
- */
-string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) {
-  if (ttype->is_base_type()) {
-    string bname = base_type_name(((t_base_type*)ttype)->get_base());
-    std::map<string, string>::iterator it = ttype->annotations_.find("cpp.type");
-    if (it != ttype->annotations_.end()) {
-      bname = it->second;
-    }
-
-    if (!arg) {
-      return bname;
-    }
-
-    if (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING) {
-      return "const " + bname + "&";
-    } else {
-      return "const " + bname;
-    }
-  }
-
-  // Check for a custom overloaded C++ name
-  if (ttype->is_container()) {
-    string cname;
-
-    t_container* tcontainer = (t_container*) ttype;
-    if (tcontainer->has_cpp_name()) {
-      cname = tcontainer->get_cpp_name();
-    } else if (ttype->is_map()) {
-      t_map* tmap = (t_map*) ttype;
-      cname = "std::map<" +
-        type_name(tmap->get_key_type(), in_typedef) + ", " +
-        type_name(tmap->get_val_type(), in_typedef) + "> ";
-    } else if (ttype->is_set()) {
-      t_set* tset = (t_set*) ttype;
-      cname = "std::set<" + type_name(tset->get_elem_type(), in_typedef) + "> ";
-    } else if (ttype->is_list()) {
-      t_list* tlist = (t_list*) ttype;
-      cname = "std::vector<" + type_name(tlist->get_elem_type(), in_typedef) + "> ";
-    }
-
-    if (arg) {
-      return "const " + cname + "&";
-    } else {
-      return cname;
-    }
-  }
-
-  string class_prefix;
-  if (in_typedef && (ttype->is_struct() || ttype->is_xception())) {
-    class_prefix = "class ";
-  }
-
-  // Check if it needs to be namespaced
-  string pname;
-  t_program* program = ttype->get_program();
-  if (program != NULL && program != program_) {
-    pname =
-      class_prefix +
-      namespace_prefix(program->get_namespace("cpp")) +
-      ttype->get_name();
-  } else {
-    pname = class_prefix + ttype->get_name();
-  }
-
-  if (ttype->is_enum() && !gen_pure_enums_) {
-    pname += "::type";
-  }
-
-  if (arg) {
-    if (is_complex_type(ttype)) {
-      return "const " + pname + "&";
-    } else {
-      return "const " + pname;
-    }
-  } else {
-    return pname;
-  }
-}
-
-/**
- * Returns the C++ type that corresponds to the thrift type.
- *
- * @param tbase The base type
- * @return Explicit C++ type, i.e. "int32_t"
- */
-string t_cpp_generator::base_type_name(t_base_type::t_base tbase) {
-  switch (tbase) {
-  case t_base_type::TYPE_VOID:
-    return "void";
-  case t_base_type::TYPE_STRING:
-    return "std::string";
-  case t_base_type::TYPE_BOOL:
-    return "bool";
-  case t_base_type::TYPE_BYTE:
-    return "int8_t";
-  case t_base_type::TYPE_I16:
-    return "int16_t";
-  case t_base_type::TYPE_I32:
-    return "int32_t";
-  case t_base_type::TYPE_I64:
-    return "int64_t";
-  case t_base_type::TYPE_DOUBLE:
-    return "double";
-  default:
-    throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);
-  }
-}
-
-/**
- * Declares a field, which may include initialization as necessary.
- *
- * @param ttype The type
- * @return Field declaration, i.e. int x = 0;
- */
-string t_cpp_generator::declare_field(t_field* tfield, bool init, bool pointer, bool constant, bool reference) {
-  // TODO(mcslee): do we ever need to initialize the field?
-  string result = "";
-  if (constant) {
-    result += "const ";
-  }
-  result += type_name(tfield->get_type());
-  if (pointer) {
-    result += "*";
-  }
-  if (reference) {
-    result += "&";
-  }
-  result += " " + tfield->get_name();
-  if (init) {
-    t_type* type = get_true_type(tfield->get_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:
-      case t_base_type::TYPE_STRING:
-        break;
-      case t_base_type::TYPE_BOOL:
-        result += " = 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:
-        result += " = 0";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        result += " = (double)0";
-        break;
-      default:
-        throw "compiler error: no C++ initializer for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      result += " = (" + type_name(type) + ")0";
-    }
-  }
-  if (!reference) {
-    result += ";";
-  }
-  return result;
-}
-
-/**
- * Renders a function signature of the form 'type name(args)'
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_cpp_generator::function_signature(t_function* tfunction,
-                                           string style,
-                                           string prefix,
-                                           bool name_params) {
-  t_type* ttype = tfunction->get_returntype();
-  t_struct* arglist = tfunction->get_arglist();
-  bool has_xceptions = !tfunction->get_xceptions()->get_members().empty();
-
-  if (style == "") {
-    if (is_complex_type(ttype)) {
-      return
-        "void " + prefix + tfunction->get_name() +
-        "(" + type_name(ttype) + (name_params ? "& _return" : "& /* _return */") +
-        argument_list(arglist, name_params, true) + ")";
-    } else {
-      return
-        type_name(ttype) + " " + prefix + tfunction->get_name() +
-        "(" + argument_list(arglist, name_params) + ")";
-    }
-  } else if (style.substr(0,3) == "Cob") {
-    string cob_type;
-    string exn_cob;
-    if (style == "CobCl") {
-      cob_type = "(" + service_name_ + "CobClient";
-      if (gen_templates_) {
-        cob_type += "T<Protocol_>";
-      }
-      cob_type += "* client)";
-    } else if (style =="CobSv") {
-      cob_type = (ttype->is_void()
-                  ? "()"
-                  : ("(" + type_name(ttype) + " const& _return)"));
-      if (has_xceptions) {
-        exn_cob = ", tcxx::function<void(::apache::thrift::TDelayedException* _throw)> /* exn_cob */";
-      }
-    } else {
-      throw "UNKNOWN STYLE";
-    }
-
-    return
-      "void " + prefix + tfunction->get_name() +
-      "(tcxx::function<void" + cob_type + "> cob" + exn_cob +
-      argument_list(arglist, name_params, true) + ")";
-  } else {
-    throw "UNKNOWN STYLE";
-  }
-}
-
-/**
- * Renders a field list
- *
- * @param tstruct The struct definition
- * @return Comma sepearated list of all field names in that struct
- */
-string t_cpp_generator::argument_list(t_struct* tstruct, bool name_params, bool start_comma) {
-  string result = "";
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  bool first = !start_comma;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (first) {
-      first = false;
-    } else {
-      result += ", ";
-    }
-    result += type_name((*f_iter)->get_type(), false, true) + " " +
-      (name_params ? (*f_iter)->get_name() : "/* " + (*f_iter)->get_name() + " */");
-  }
-  return result;
-}
-
-/**
- * Converts the parse type to a C++ enum string for the given type.
- *
- * @param type Thrift Type
- * @return String of C++ code to definition of that type constant
- */
-string t_cpp_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 "::apache::thrift::protocol::T_STRING";
-    case t_base_type::TYPE_BOOL:
-      return "::apache::thrift::protocol::T_BOOL";
-    case t_base_type::TYPE_BYTE:
-      return "::apache::thrift::protocol::T_BYTE";
-    case t_base_type::TYPE_I16:
-      return "::apache::thrift::protocol::T_I16";
-    case t_base_type::TYPE_I32:
-      return "::apache::thrift::protocol::T_I32";
-    case t_base_type::TYPE_I64:
-      return "::apache::thrift::protocol::T_I64";
-    case t_base_type::TYPE_DOUBLE:
-      return "::apache::thrift::protocol::T_DOUBLE";
-    }
-  } else if (type->is_enum()) {
-    return "::apache::thrift::protocol::T_I32";
-  } else if (type->is_struct()) {
-    return "::apache::thrift::protocol::T_STRUCT";
-  } else if (type->is_xception()) {
-    return "::apache::thrift::protocol::T_STRUCT";
-  } else if (type->is_map()) {
-    return "::apache::thrift::protocol::T_MAP";
-  } else if (type->is_set()) {
-    return "::apache::thrift::protocol::T_SET";
-  } else if (type->is_list()) {
-    return "::apache::thrift::protocol::T_LIST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-/**
- * Returns the symbol name of the local reflection of a type.
- */
-string t_cpp_generator::local_reflection_name(const char* prefix, t_type* ttype, bool external) {
-  ttype = get_true_type(ttype);
-
-  // We have to use the program name as part of the identifier because
-  // if two thrift "programs" are compiled into one actual program
-  // you would get a symbol collision if they both defined list<i32>.
-  // trlo = Thrift Reflection LOcal.
-  string prog;
-  string name;
-  string nspace;
-
-  // TODO(dreiss): Would it be better to pregenerate the base types
-  //               and put them in Thrift.{h,cpp} ?
-
-  if (ttype->is_base_type()) {
-    prog = program_->get_name();
-    name = ttype->get_ascii_fingerprint();
-  } else if (ttype->is_enum()) {
-    assert(ttype->get_program() != NULL);
-    prog = ttype->get_program()->get_name();
-    name = ttype->get_ascii_fingerprint();
-  } else if (ttype->is_container()) {
-    prog = program_->get_name();
-    name = ttype->get_ascii_fingerprint();
-  } else {
-    assert(ttype->is_struct() || ttype->is_xception());
-    assert(ttype->get_program() != NULL);
-    prog = ttype->get_program()->get_name();
-    name = ttype->get_ascii_fingerprint();
-  }
-
-  if (external &&
-      ttype->get_program() != NULL &&
-      ttype->get_program() != program_) {
-    nspace = namespace_prefix(ttype->get_program()->get_namespace("cpp"));
-  }
-
-  return nspace + "trlo_" + prefix + "_" + prog + "_" + name;
-}
-
-string t_cpp_generator::get_include_prefix(const t_program& program) const {
-  string include_prefix = program.get_include_prefix();
-  if (!use_include_prefix_ ||
-      (include_prefix.size() > 0 && include_prefix[0] == '/')) {
-    // if flag is turned off or this is absolute path, return empty prefix
-    return "";
-  }
-
-  string::size_type last_slash = string::npos;
-  if ((last_slash = include_prefix.rfind("/")) != string::npos) {
-    return include_prefix.substr(0, last_slash) +
-      (get_program()->is_out_path_absolute() ? "/" : "/" + out_dir_base_ + "/");
-
-  }
-
-  return "";
-}
-
-
-THRIFT_REGISTER_GENERATOR(cpp, "C++",
-"    cob_style:       Generate \"Continuation OBject\"-style classes.\n"
-"    no_client_completion:\n"
-"                     Omit calls to completion__() in CobClient class.\n"
-"    templates:       Generate templatized reader/writer methods.\n"
-"    pure_enums:      Generate pure enums instead of wrapper classes.\n"
-"    dense:           Generate type specifications for the dense protocol.\n"
-"    include_prefix:  Use full include paths in generated files.\n"
-)
-
diff --git a/compiler/cpp/src/generate/t_csharp_generator.cc b/compiler/cpp/src/generate/t_csharp_generator.cc
deleted file mode 100644
index 3f432da..0000000
--- a/compiler/cpp/src/generate/t_csharp_generator.cc
+++ /dev/null
@@ -1,2567 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- * Contains some contributions under the Thrift Software License.
- * Please see doc/old-thrift-license.txt in the Thrift distribution for
- * details.
- */
-
-#include <cassert>
-
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sstream>
-
-#include "platform.h"
-#include "t_oop_generator.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-class t_csharp_generator : public t_oop_generator
-{
-  public:
-    t_csharp_generator(
-        t_program* program,
-        const std::map<std::string, std::string>& parsed_options,
-        const std::string& option_string)
-      : t_oop_generator(program)
-    {
-      (void) option_string;
-
-      std::map<std::string, std::string>::const_iterator iter;
-
-      iter = parsed_options.find("async");
-      async_ = (iter != parsed_options.end());
-      iter = parsed_options.find("asyncctp");
-      async_ctp_ = (iter != parsed_options.end());
-      if (async_ && async_ctp_) {
-        throw "argument error: Cannot specify both async and asyncctp; they are incompatible.";
-      }
-
-      iter = parsed_options.find("nullable");
-      nullable_ = (iter != parsed_options.end());
-
-      iter = parsed_options.find("hashcode");
-      hashcode_ = (iter != parsed_options.end());
-
-      iter = parsed_options.find("union");
-      union_ = (iter != parsed_options.end());
-
-      iter = parsed_options.find("serial");
-      serialize_ = (iter != parsed_options.end());
-      if (serialize_) {
-	wcf_namespace_ = iter->second;  // since there can be only one namespace
-      }
-      
-      iter = parsed_options.find("wcf");
-      wcf_ = (iter != parsed_options.end());
-      if (wcf_) {
-	wcf_namespace_ = iter->second;
-      }
-
-      out_dir_base_ = "gen-csharp";
-    }
-    void init_generator();
-    void close_generator();
-
-    void generate_consts(std::vector<t_const*> consts);
-
-    void generate_typedef (t_typedef* ttypedef);
-    void generate_enum (t_enum* tenum);
-    void generate_struct (t_struct* tstruct);
-    void generate_union (t_struct* tunion);
-    void generate_xception (t_struct* txception);
-    void generate_service (t_service* tservice);
-    void generate_property(ofstream& out, t_field* tfield, bool isPublic, bool generateIsset);
-    void generate_csharp_property(ofstream& out, t_field* tfield, bool isPublic, bool includeIsset=true, std::string fieldPrefix = "");
-    bool print_const_value (std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool in_static, bool defval=false, bool needtype=false);
-    std::string render_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
-    void print_const_constructor(std::ofstream& out, std::vector<t_const*> consts);
-    void print_const_def_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
-
-    void generate_csharp_struct(t_struct* tstruct, bool is_exception);
-    void generate_csharp_union(t_struct* tunion);
-    void generate_csharp_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool in_class=false, bool is_result=false);
-    void generate_csharp_union_definition(std::ofstream& out, t_struct* tunion);
-    void generate_csharp_union_class(std::ofstream& out, t_struct* tunion, t_field* tfield);
-    void generate_csharp_wcffault(std::ofstream& out, t_struct* tstruct);
-    void generate_csharp_struct_reader(std::ofstream& out, t_struct* tstruct);
-    void generate_csharp_struct_result_writer(std::ofstream& out, t_struct* tstruct);
-    void generate_csharp_struct_writer(std::ofstream& out, t_struct* tstruct);
-    void generate_csharp_struct_tostring(std::ofstream& out, t_struct* tstruct);
-    void generate_csharp_struct_equals(std::ofstream& out, t_struct* tstruct);
-    void generate_csharp_struct_hashcode(std::ofstream& out, t_struct* tstruct);
-    void generate_csharp_union_reader(std::ofstream& out, t_struct* tunion);
-
-    void generate_function_helpers(t_function* tfunction);
-    void generate_service_interface (t_service* tservice);
-    void generate_service_helpers (t_service* tservice);
-    void generate_service_client (t_service* tservice);
-    void generate_service_server (t_service* tservice);
-    void generate_process_function (t_service* tservice, t_function* function);
-
-    void generate_deserialize_field (std::ofstream& out, t_field* tfield, std::string prefix="", bool is_propertyless=false);
-    void generate_deserialize_struct (std::ofstream& out, t_struct* tstruct, std::string prefix="");
-    void generate_deserialize_container (std::ofstream& out, t_type* ttype, std::string prefix="");
-    void generate_deserialize_set_element (std::ofstream& out, t_set* tset, std::string prefix="");
-    void generate_deserialize_map_element (std::ofstream& out, t_map* tmap, std::string prefix="");
-    void generate_deserialize_list_element (std::ofstream& out, t_list* list, std::string prefix="");
-    void generate_serialize_field (std::ofstream& out, t_field* tfield, std::string prefix="", bool is_element=false, bool is_propertyless=false);
-    void generate_serialize_struct (std::ofstream& out, t_struct* tstruct, std::string prefix="");
-    void generate_serialize_container (std::ofstream& out, t_type* ttype, std::string prefix="");
-    void generate_serialize_map_element (std::ofstream& out, t_map* tmap, std::string iter, std::string map);
-    void generate_serialize_set_element (std::ofstream& out, t_set* tmap, std::string iter);
-    void generate_serialize_list_element (std::ofstream& out, t_list* tlist, std::string iter);
-
-    void generate_csharp_doc (std::ofstream& out, t_field*    field);
-    void generate_csharp_doc (std::ofstream& out, t_doc*      tdoc);
-    void generate_csharp_doc (std::ofstream& out, t_function* tdoc);
-    void generate_csharp_docstring_comment (std::ofstream &out, string contents);
-
-    void start_csharp_namespace (std::ofstream& out);
-    void end_csharp_namespace (std::ofstream& out);
-
-    std::string csharp_type_usings();
-    std::string csharp_thrift_usings();
-
-    std::string type_name(t_type* ttype, bool in_countainer=false, bool in_init=false, bool in_param=false, bool is_required=false);
-    std::string base_type_name(t_base_type* tbase, bool in_container=false, bool in_param=false, bool is_required=false);
-    std::string declare_field(t_field* tfield, bool init=false, std::string prefix="");
-    std::string function_signature_async_begin(t_function* tfunction, std::string prefix = "");
-    std::string function_signature_async_end(t_function* tfunction, std::string prefix = "");
-    std::string function_signature_async(t_function* tfunction, std::string prefix = "");
-    std::string function_signature(t_function* tfunction, std::string prefix="");
-    std::string argument_list(t_struct* tstruct);
-    std::string type_to_enum(t_type* ttype);
-    std::string prop_name(t_field* tfield);
-    std::string get_enum_class_name(t_type* type);
-    
-    std::string make_valid_csharp_identifier( std::string const & fromName);
-
-    bool field_has_default(t_field* tfield) {
-      return tfield->get_value() != NULL;
-    }
-
-    bool field_is_required(t_field* tfield) {
-      return tfield->get_req() == t_field::T_REQUIRED;
-    }
-
-    bool type_can_be_null(t_type* ttype) {
-      while (ttype->is_typedef()) {
-        ttype = ((t_typedef*)ttype)->get_type();
-      }
-
-      return ttype->is_container() ||
-        ttype->is_struct() ||
-        ttype->is_xception() ||
-        ttype->is_string();
-    }
-
-  private:
-    std::string namespace_name_;
-    std::ofstream f_service_;
-    std::string namespace_dir_;
-    bool async_;
-    bool async_ctp_;
-    bool nullable_;
-    bool union_;
-    bool hashcode_;
-    bool serialize_;
-    bool wcf_;
-    std::string wcf_namespace_;
-};
-
-
-void t_csharp_generator::init_generator() {
-  MKDIR(get_out_dir().c_str());
-  namespace_name_ = program_->get_namespace("csharp");
-
-  string dir = namespace_name_;
-  string subdir = get_out_dir().c_str();
-  string::size_type loc;
-
-  while ((loc = dir.find(".")) != string::npos) {
-    subdir = subdir + "/" + dir.substr(0, loc);
-    MKDIR(subdir.c_str());
-    dir = dir.substr(loc + 1);
-  }
-  if (dir.size() > 0) {
-    subdir = subdir + "/" + dir;
-    MKDIR(subdir.c_str());
-  }
-
-  namespace_dir_ = subdir;
-}
-
-void t_csharp_generator::start_csharp_namespace(ofstream& out) {
-  if (!namespace_name_.empty()) {
-    out <<
-      "namespace " << namespace_name_ << "\n";
-    scope_up(out);
-  }
-}
-
-void t_csharp_generator::end_csharp_namespace(ofstream& out) {
-  if (!namespace_name_.empty()) {
-    scope_down(out);
-  }
-}
-
-string t_csharp_generator::csharp_type_usings() {
-  return string() +
-    "using System;\n" +
-    "using System.Collections;\n" +
-    "using System.Collections.Generic;\n" +
-    "using System.Text;\n" +
-    "using System.IO;\n" +
-    ((async_||async_ctp_) ? "using System.Threading.Tasks;\n" : "") +
-    "using Thrift;\n" +
-    "using Thrift.Collections;\n" +
-    (wcf_ ? "//using System.ServiceModel;\n" : "") +
-    "using System.Runtime.Serialization;\n";
-}
-
-string t_csharp_generator::csharp_thrift_usings() {
-  return string() +
-    "using Thrift.Protocol;\n" +
-    "using Thrift.Transport;\n";
-}
-
-void t_csharp_generator::close_generator() { }
-void t_csharp_generator::generate_typedef(t_typedef* ttypedef) {
-  (void) ttypedef;
-}
-
-void t_csharp_generator::generate_enum(t_enum* tenum) {
-  string f_enum_name = namespace_dir_+"/" + (tenum->get_name())+".cs";
-  ofstream f_enum;
-  f_enum.open(f_enum_name.c_str());
-
-  f_enum <<
-    autogen_comment() << endl;
-
-  start_csharp_namespace(f_enum);
-
-  generate_csharp_doc(f_enum, tenum);
-
-  indent(f_enum) <<
-    "public enum " << tenum->get_name() << "\n";
-  scope_up(f_enum);
-
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-	generate_csharp_doc(f_enum, *c_iter);
-
-    int value = (*c_iter)->get_value();
-    indent(f_enum) << (*c_iter)->get_name() << " = " << value << "," << endl;
-  }
-
-  scope_down(f_enum);
-
-  end_csharp_namespace(f_enum);
-
-  f_enum.close();
-}
-
-void t_csharp_generator::generate_consts(std::vector<t_const*> consts) {
-  if (consts.empty()){
-    return;
-  }
-  string f_consts_name = namespace_dir_ + '/' + program_name_ +  ".Constants.cs";
-  ofstream f_consts;
-  f_consts.open(f_consts_name.c_str());
-
-  f_consts <<
-    autogen_comment() <<
-    csharp_type_usings() << endl;
-
-  start_csharp_namespace(f_consts);
-
-  indent(f_consts) <<
-    "public static class " << make_valid_csharp_identifier(program_name_) << "Constants" << endl;
-  scope_up(f_consts);
-
-  vector<t_const*>::iterator c_iter;
-  bool need_static_constructor = false;
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    generate_csharp_doc(f_consts, (*c_iter));
-    if (print_const_value(f_consts, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value(), false)) {
-      need_static_constructor = true;
-    }
-  }
-
-  if (need_static_constructor) {
-    print_const_constructor(f_consts, consts);
-  }
-
-  scope_down(f_consts);
-  end_csharp_namespace(f_consts);
-  f_consts.close();
-}
-
-void t_csharp_generator::print_const_def_value(std::ofstream& out, string name, t_type* type, t_const_value* value)
-{
-  if (type->is_struct() || type->is_xception()) {
-    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_field* field = NULL;
-      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
-          field = (*f_iter);
-        }
-      }
-      if (field == NULL) {
-        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
-      }
-      t_type* field_type = field->get_type();
-      string val = render_const_value(out, name, field_type, v_iter->second);
-      indent(out) << name << "." << prop_name(field) << " = " << val << ";" << endl;
-    }
-  } 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();
-    map<t_const_value*, t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string key = render_const_value(out, name, ktype, v_iter->first);
-      string val = render_const_value(out, name, vtype, v_iter->second);
-      indent(out) << name << "[" << key << "]" << " = " << val << ";" << endl;
-    }
-  } else if (type->is_list() || type->is_set()) {
-    t_type* etype;
-    if (type->is_list()) {
-      etype = ((t_list*)type)->get_elem_type();
-    } else {
-      etype = ((t_set*)type)->get_elem_type();
-    }
-
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string val = render_const_value(out, name, etype, *v_iter);
-      indent(out) << name << ".Add(" << val << ");" << endl;
-    }
-  }
-}
-
-void t_csharp_generator::print_const_constructor(std::ofstream& out, std::vector<t_const*> consts) {
-  indent(out) << "static " << make_valid_csharp_identifier(program_name_).c_str() << "Constants()" << endl;
-  scope_up(out);
-  vector<t_const*>::iterator c_iter;
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    string name = (*c_iter)->get_name();
-    t_type* type = (*c_iter)->get_type();
-    t_const_value* value = (*c_iter)->get_value();
-
-    print_const_def_value(out, name, type, value);
-  }
-  scope_down(out);
-}
-
-
-//it seems like all that methods that call this are using in_static to be the opposite of what it would imply
-bool t_csharp_generator::print_const_value(std::ofstream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval, bool needtype) {
-  indent(out);
-  bool need_static_construction = !in_static;
-  while (type->is_typedef()) {
-    type = ((t_typedef*)type)->get_type();
-  }
-
-  if (!defval || needtype) {
-    out <<
-      (in_static ? "" : "public static ") <<
-      type_name(type) << " ";
-  }
-  if (type->is_base_type()) {
-    string v2 = render_const_value(out, name, type, value);
-    out << name << " = " << v2 << ";" << endl;
-    need_static_construction = false;
-  } else if (type->is_enum()) {
-    out << name << " = " << type_name(type, false, true) << "." << value->get_identifier_name() << ";" << endl;
-    need_static_construction = false;
-  } else if (type->is_struct() || type->is_xception()) {
-    out << name << " = new " << type_name(type) << "();" << endl;
-  } else if (type->is_map()) {
-    out << name << " = new " << type_name(type, true, true) << "();" << endl;
-  } else if (type->is_list() || type->is_set()) {
-    out << name << " = new " << type_name(type) << "();" << endl;
-  }
-
-  if (defval && !type->is_base_type() && !type->is_enum()) {
-    print_const_def_value(out, name, type, value);
-  }
-
-  return need_static_construction;
-}
-
-std::string t_csharp_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
-  (void) name;
-  std::ostringstream render;
-
-  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:
-        render << '"' << get_escaped_string(value) << '"';
-        break;
-      case t_base_type::TYPE_BOOL:
-        render << ((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:
-        render << value->get_integer();
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        if (value->get_type() == t_const_value::CV_INTEGER) {
-          render << value->get_integer();
-        } else {
-          render << value->get_double();
-        }
-        break;
-      default:
-        throw "compiler error: no const of base type " + tbase;
-    }
-  } else if (type->is_enum()) {
-    render << type->get_name() << "." << value->get_identifier_name();
-  } else {
-    string t = tmp("tmp");
-    print_const_value(out, t, type, value, true, true, true);
-    render << t;
-  }
-
-  return render.str();
-}
-
-void t_csharp_generator::generate_struct(t_struct* tstruct) {
-  if (union_ && tstruct->is_union()) {
-    generate_csharp_union(tstruct);
-  } else {
-    generate_csharp_struct(tstruct, false);
-  }
-}
-
-void t_csharp_generator::generate_xception(t_struct* txception) {
-  generate_csharp_struct(txception, true);
-}
-
-void t_csharp_generator::generate_csharp_struct(t_struct* tstruct, bool is_exception) {
-  string f_struct_name = namespace_dir_ + "/" + (tstruct->get_name()) + ".cs";
-  ofstream f_struct;
-
-  f_struct.open(f_struct_name.c_str());
-
-  f_struct <<
-    autogen_comment() <<
-    csharp_type_usings() <<
-    csharp_thrift_usings() << endl;
-
-  generate_csharp_struct_definition(f_struct, tstruct, is_exception);
-
-  f_struct.close();
-}
-
-void t_csharp_generator::generate_csharp_struct_definition(ofstream &out, t_struct* tstruct, bool is_exception, bool in_class, bool is_result) {
-
-  if (!in_class) {
-    start_csharp_namespace(out);
-  }
-
-  out << endl;
-
-  generate_csharp_doc(out, tstruct);
-
-  indent(out) << "#if !SILVERLIGHT" << endl;
-  indent(out) << "[Serializable]" << endl; 
-  indent(out) << "#endif" << endl;
-  if ((serialize_||wcf_) &&!is_exception) {
-    indent(out) << "[DataContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl; // do not make exception classes directly WCF serializable, we provide a seperate "fault" for that
-  }
-  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
- 
-  indent(out) << "public " << (is_final ? "sealed " : "") << "partial class " << tstruct->get_name() << " : ";
-
-  if (is_exception) {
-    out << "TException, ";
-  }
-  out << "TBase";
-
-  out << endl;
-
-  scope_up(out);
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  //make private members with public Properties
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    // if the field is requied, then we use auto-properties
-    if (!field_is_required((*m_iter)) && (!nullable_ || field_has_default((*m_iter)))) {
-      indent(out) << "private " << declare_field(*m_iter, false, "_") << endl;
-    }
-  }
-  out << endl;
-
-  bool has_non_required_fields = false;
-  bool has_non_required_default_value_fields = false;
-  bool has_required_fields = false;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    generate_csharp_doc(out, *m_iter);
-    generate_property(out, *m_iter, true, true);
-    bool is_required = field_is_required((*m_iter));
-    bool has_default = field_has_default((*m_iter));
-    if (is_required) {
-      has_required_fields = true;
-    } else {
-      if (has_default) {
-        has_non_required_default_value_fields = true;
-      }
-      has_non_required_fields = true;
-    }
-  }
-
-  bool generate_isset =
-    (nullable_ && has_non_required_default_value_fields)
-    || (!nullable_ && has_non_required_fields);
-  if (generate_isset) {
-    out <<
-      endl <<
-      indent() << "public Isset __isset;" << endl <<
-      indent() << "#if !SILVERLIGHT" << endl <<
-      indent() << "[Serializable]" << endl <<
-      indent() << "#endif" << endl;
-    if ((serialize_||wcf_)) {
-      indent(out) << "[DataContract]" << endl;
-    }
-    
-    indent(out) << "public struct Isset {" << endl;
-    indent_up();
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      bool is_required = field_is_required((*m_iter));
-      bool has_default = field_has_default((*m_iter));
-      // if it is required, don't need Isset for that variable
-      // if it is not required, if it has a default value, we need to generate Isset
-      // if we are not nullable, then we generate Isset
-      if (!is_required && (!nullable_ || has_default)) {
-	indent(out) << "public bool " << (*m_iter)->get_name() << ";" << endl;
-      }
-    }
-
-    indent_down();
-    indent(out) << "}" << endl << endl;
-  }
-  
-  // We always want a default, no argument constructor for Reading
-  indent(out) << "public " << tstruct->get_name() << "() {" << endl;
-  indent_up();
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* t = (*m_iter)->get_type();
-    while (t->is_typedef()) {
-      t = ((t_typedef*)t)->get_type();
-    }
-    if ((*m_iter)->get_value() != NULL) {
-      if (field_is_required((*m_iter))) {
-        print_const_value(out, "this." + prop_name(*m_iter), t, (*m_iter)->get_value(), true, true);
-      } else {
-        print_const_value(out, "this._" + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true);
-        // Optionals with defaults are marked set
-        indent(out) << "this.__isset." << (*m_iter)->get_name() << " = true;" << endl;
-      }
-    }
-  }
-  indent_down();
-  indent(out) << "}" << endl << endl;
-  
-  if (has_required_fields) {
-    indent(out) << "public " << tstruct->get_name() << "(";
-    bool first = true;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if (field_is_required((*m_iter))) {
-        if (first) {
-          first = false;
-        } else {
-          out << ", ";
-        }
-        out << type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name();
-      }
-    }
-    out << ") : this() {" << endl;
-    indent_up();
-
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if (field_is_required((*m_iter))) {
-        indent(out) << "this." << prop_name((*m_iter)) << " = " << (*m_iter)->get_name() << ";" << endl;
-      }
-    }
-
-    indent_down();
-    indent(out) << "}" << endl << endl;
-  }
-  
-  generate_csharp_struct_reader(out, tstruct);
-  if (is_result) {
-    generate_csharp_struct_result_writer(out, tstruct);
-  } else {
-    generate_csharp_struct_writer(out, tstruct);
-  }
-  if (hashcode_) {
-    generate_csharp_struct_equals(out, tstruct);
-    generate_csharp_struct_hashcode(out, tstruct);
-  }
-  generate_csharp_struct_tostring(out, tstruct);
-  scope_down(out);
-  out << endl;
-
-  // generate a corresponding WCF fault to wrap the exception
-  if((serialize_||wcf_) && is_exception) {
-    generate_csharp_wcffault(out, tstruct);
-  }
-
-  if (!in_class) {
-    end_csharp_namespace(out);
-  }
-}
-
-void t_csharp_generator::generate_csharp_wcffault(ofstream& out, t_struct* tstruct) {
-  out << endl;
-  indent(out) << "#if !SILVERLIGHT" << endl;
-  indent(out) << "[Serializable]" << endl;
-  indent(out) << "#endif" << endl;
-  indent(out) << "[DataContract]" << endl;
-  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
-
-  indent(out) << "public " << (is_final ? "sealed " : "") << "partial class " << tstruct->get_name() << "Fault" << endl;
-
-  scope_up(out);
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  // make private members with public Properties
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    indent(out) <<
-    "private " << declare_field(*m_iter, false, "_") << endl;
-  }
-  out << endl;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    generate_property(out, *m_iter, true, false);
-  }
-
-  scope_down(out);
-  out << endl;
-}
-
-void t_csharp_generator::generate_csharp_struct_reader(ofstream& out, t_struct* tstruct) {
-  indent(out) <<
-    "public void Read (TProtocol iprot)" << endl;
-  scope_up(out);
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  // Required variables aren't in __isset, so we need tmp vars to check them
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (field_is_required((*f_iter))) {
-      indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
-    }
-  }
-
-  indent(out) <<
-    "TField field;" << endl <<
-    indent() << "iprot.ReadStructBegin();" << endl;
-
-  indent(out) <<
-    "while (true)" << endl;
-  scope_up(out);
-
-  indent(out) <<
-    "field = iprot.ReadFieldBegin();" << endl;
-
-  indent(out) <<
-    "if (field.Type == TType.Stop) { " << endl;
-  indent_up();
-  indent(out) <<
-    "break;" << endl;
-  indent_down();
-  indent(out) <<
-    "}" << endl;
-
-  indent(out) <<
-    "switch (field.ID)" << endl;
-
-  scope_up(out);
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    bool is_required = field_is_required((*f_iter));
-    indent(out) <<
-      "case " << (*f_iter)->get_key() << ":" << endl;
-    indent_up();
-    indent(out) <<
-      "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
-    indent_up();
-
-    generate_deserialize_field(out, *f_iter);
-    if (is_required) {
-      indent(out) << "isset_" << (*f_iter)->get_name() << " = true;" << endl;
-    }
-    
-    indent_down();
-    out <<
-      indent() << "} else { " << endl <<
-      indent() << "  TProtocolUtil.Skip(iprot, field.Type);" << endl <<
-      indent() << "}" << endl <<
-      indent() << "break;" << endl;
-    indent_down();
-  }
-
-  indent(out) <<
-    "default: " << endl;
-  indent_up();
-  indent(out) << "TProtocolUtil.Skip(iprot, field.Type);" << endl;
-  indent(out) << "break;" << endl;
-  indent_down();
-
-  scope_down(out);
-
-  indent(out) <<
-    "iprot.ReadFieldEnd();" << endl;
-
-  scope_down(out);
-
-  indent(out) <<
-    "iprot.ReadStructEnd();" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (field_is_required((*f_iter))) {
-      indent(out) << "if (!isset_" << (*f_iter)->get_name() << ")" << endl;
-      indent_up();
-      indent(out) << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl;
-      indent_down();
-    }
-  }
-
-  indent_down();
-
-  indent(out) << "}" << endl << endl;
-
-}
-
-void t_csharp_generator::generate_csharp_struct_writer(ofstream& out, t_struct* tstruct) {
-  out <<
-    indent() << "public void Write(TProtocol oprot) {" << endl;
-  indent_up();
-
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  indent(out) <<
-    "TStruct struc = new TStruct(\"" << name << "\");" << endl;
-  indent(out) <<
-    "oprot.WriteStructBegin(struc);" << endl;
-
-  if (fields.size() > 0) {
-    indent(out) << "TField field = new TField();" << endl;
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      bool is_required = field_is_required((*f_iter));
-      bool has_default = field_has_default((*f_iter));
-      if (nullable_ && !has_default && !is_required) {
-	indent(out) << "if (" << prop_name((*f_iter)) << " != null) {" << endl;
-	indent_up();
-      } else if (!is_required) {
-	bool null_allowed = type_can_be_null((*f_iter)->get_type());
-	if (null_allowed) {
-	  indent(out) <<
-	    "if (" << prop_name((*f_iter)) << " != null && __isset." << (*f_iter)->get_name() << ") {" << endl;
-	  indent_up();
-	} else {
-	  indent(out) <<
-	    "if (__isset." << (*f_iter)->get_name() << ") {" << endl;
-	  indent_up();
-	}
-      }
-      indent(out) << "field.Name = \"" << (*f_iter)->get_name() << "\";" << endl;
-      indent(out) << "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl;
-      indent(out) << "field.ID = " << (*f_iter)->get_key() << ";" << endl;
-      indent(out) << "oprot.WriteFieldBegin(field);" << endl;
-
-      generate_serialize_field(out, *f_iter);
-
-      indent(out) << "oprot.WriteFieldEnd();" << endl;
-      if (!is_required) {
-	indent_down();
-	indent(out) << "}" << endl;
-      }
-    }
-  }
-
-  indent(out) << "oprot.WriteFieldStop();" << endl;
-  indent(out) << "oprot.WriteStructEnd();" << endl;
-
-  indent_down();
-
-  indent(out) << "}" << endl << endl;
-}
-
-void t_csharp_generator::generate_csharp_struct_result_writer(ofstream& out, t_struct* tstruct) {
-  indent(out) <<
-    "public void Write(TProtocol oprot) {" << endl;
-  indent_up();
-
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  indent(out) <<
-    "TStruct struc = new TStruct(\"" << name << "\");" << endl;
-  indent(out) <<
-    "oprot.WriteStructBegin(struc);" << endl;
-
-  if (fields.size() > 0) {
-    indent(out) << "TField field = new TField();" << endl;
-    bool first = true;
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      if (first) {
-        first = false;
-        out << endl << indent() << "if ";
-      } else {
-        out << " else if ";
-      }
-      
-      if (nullable_) {
-	out << "(this." << prop_name((*f_iter)) << " != null) {" << endl;
-      } else {
-	out <<
-	  "(this.__isset." << (*f_iter)->get_name() << ") {" << endl;
-      }
-      indent_up();
-
-      bool null_allowed = !nullable_ && type_can_be_null((*f_iter)->get_type());
-      if (null_allowed) {
-        indent(out) <<
-          "if (" << prop_name(*f_iter) << " != null) {" << endl;
-        indent_up();
-      }
-
-      indent(out) <<
-        "field.Name = \"" << prop_name(*f_iter) << "\";" << endl;
-      indent(out) <<
-        "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl;
-      indent(out) <<
-        "field.ID = " << (*f_iter)->get_key() << ";" << endl;
-      indent(out) <<
-        "oprot.WriteFieldBegin(field);" << endl;
-
-      generate_serialize_field(out, *f_iter);
-
-      indent(out) <<
-        "oprot.WriteFieldEnd();" << endl;
-
-      if (null_allowed) {
-	indent_down();
-	indent(out) << "}" << endl;
-      }
-
-      indent_down();
-      indent(out) << "}";
-    }
-  }
-
-  out <<
-    endl <<
-    indent() << "oprot.WriteFieldStop();" << endl <<
-    indent() << "oprot.WriteStructEnd();" << endl;
-
-  indent_down();
-
-  indent(out) <<
-    "}" << endl << endl;
-}
-
-void t_csharp_generator::generate_csharp_struct_tostring(ofstream& out, t_struct* tstruct) {
-  indent(out) <<
-    "public override string ToString() {" << endl;
-  indent_up();
-
-  indent(out) <<
-    "StringBuilder sb = new StringBuilder(\"" << tstruct->get_name() << "(\");" << endl;
-
-  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;
-      indent(out) <<
-        "sb.Append(\"" << prop_name((*f_iter)) << ": \");" << endl;
-    } else {
-      indent(out) <<
-        "sb.Append(\"," << prop_name((*f_iter)) << ": \");" << endl;
-    }
-    t_type* ttype = (*f_iter)->get_type();
-    if (ttype->is_xception() || ttype->is_struct()) {
-      indent(out) <<
-        "sb.Append(" << prop_name((*f_iter)) << "== null ? \"<null>\" : "<< prop_name((*f_iter))  << ".ToString());" << endl;
-    } else {
-      indent(out) <<
-        "sb.Append(" << prop_name((*f_iter))  << ");" << endl;
-    }
-  }
-
-  indent(out) <<
-    "sb.Append(\")\");" << endl;
-  indent(out) <<
-    "return sb.ToString();" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-
-void t_csharp_generator::generate_csharp_union(t_struct* tunion) {
-  string f_union_name = namespace_dir_ + "/" + (tunion->get_name()) + ".cs";
-  ofstream f_union;
-
-  f_union.open(f_union_name.c_str());
-
-  f_union <<
-    autogen_comment() <<
-    csharp_type_usings() <<
-    csharp_thrift_usings() << endl;
-
-  generate_csharp_union_definition(f_union, tunion);
-
-  f_union.close();
-}
-
-void t_csharp_generator::generate_csharp_union_definition(std::ofstream& out, t_struct* tunion) {
-  // Let's define the class first
-  start_csharp_namespace(out);
-
-  indent(out) << "public abstract class " << tunion->get_name() << " : TAbstractBase {" << endl;
-
-  indent_up();
-
-  indent(out) << "public abstract void Write(TProtocol protocol);" << endl;
-  indent(out) << "public readonly bool Isset;" << endl;
-  indent(out) << "public abstract object Data { get; }" << endl;
-
-  indent(out) << "protected " << tunion->get_name() << "(bool isset) {" << endl;
-  indent_up();
-  indent(out) << "Isset = isset;" << endl;
-  indent_down();
-  indent(out) << "}" << endl << endl;
-
-  indent(out) << "public class ___undefined : " << tunion->get_name() << " {" << endl;
-  indent_up();
-
-  indent(out) << "public override object Data { get { return null; } }" << endl;
-
-  indent(out) << "public ___undefined() : base(false) {}" << endl << endl;
-
-  indent(out) << "public override void Write(TProtocol protocol) {" << endl;
-  indent_up();
-  indent(out) << "throw new TProtocolException( TProtocolException.INVALID_DATA, \"Cannot persist an union type which is not set.\");" << endl;
-  indent_down();
-  indent(out) << "}" << endl << endl;
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-
-  const vector<t_field*>& fields = tunion->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    generate_csharp_union_class(out, tunion, (*f_iter));
-  }
-
-  generate_csharp_union_reader(out, tunion);
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-
-  end_csharp_namespace(out);
-}
-
-void t_csharp_generator::generate_csharp_union_class(std::ofstream& out, t_struct* tunion, t_field* tfield) {
-  indent(out) << "public class " << tfield->get_name() << " : " << tunion->get_name() << " {" << endl;
-  indent_up();
-  indent(out) << "private " << type_name(tfield->get_type()) << " _data;" << endl;
-  indent(out) << "public override object Data { get { return _data; } }" << endl;
-  indent(out) << "public " << tfield->get_name() << "(" << type_name(tfield->get_type()) << " data) : base(true) {" << endl;
-  indent_up();
-  indent(out) << "this._data = data;" << endl;
-  indent_down();
-  indent(out) << "}" << endl;
-  indent(out) << "public override void Write(TProtocol oprot) {" << endl;
-  indent_up();
-  indent(out) << "TStruct struc = new TStruct(\"" << tunion->get_name() << "\");" << endl;
-  indent(out) << "oprot.WriteStructBegin(struc);" << endl;
-
-  indent(out) << "TField field = new TField();" << endl;
-  indent(out) << "field.Name = \"" << tfield->get_name() << "\";" << endl;
-  indent(out) << "field.Type = " << type_to_enum(tfield->get_type()) << ";" << endl;
-  indent(out) << "field.ID = " << tfield->get_key() << ";" << endl;
-  indent(out) << "oprot.WriteFieldBegin(field);" << endl;
-  
-  generate_serialize_field(out, tfield, "_data", true, true);
-
-  indent(out) << "oprot.WriteFieldEnd();" << endl;
-  indent(out) << "oprot.WriteFieldStop();" << endl;
-  indent(out) << "oprot.WriteStructEnd();" << endl;
-  indent_down();
-  indent(out) << "}" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-
-void t_csharp_generator::generate_csharp_struct_equals(ofstream& out, t_struct* tstruct) {
-  indent(out) << "public override bool Equals(object that) {" << endl;
-  indent_up();
-  
-  indent(out) << "var other = that as " << type_name(tstruct) << ";" << endl;
-  indent(out) << "if (other == null) return false;" << endl;
-  indent(out) << "if (ReferenceEquals(this, other)) return true;" << endl;
-  
-  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;
-      indent(out) << "return ";
-      indent_up();
-    } else {
-      out << endl;
-      indent(out) << "&& ";
-    }
-    if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) {
-      out << "((__isset." << (*f_iter)->get_name() << " == other.__isset." << (*f_iter)->get_name() << ") && ((!__isset." << (*f_iter)->get_name() << ") || (";
-    }
-    t_type* ttype = (*f_iter)->get_type();
-    if (ttype->is_container()) {
-      out << "TCollections.Equals(";
-    } else {
-      out << "System.Object.Equals(";
-    }
-    out << prop_name((*f_iter)) << ", other." << prop_name((*f_iter)) << ")";
-    if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) {
-      out << ")))";
-    }
-  }
-  if (first) {
-    indent(out) << "return true;" << endl;
-  } else {
-    out << ";" << endl;
-    indent_down();
-  }
-  
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-void t_csharp_generator::generate_csharp_struct_hashcode(ofstream& out, t_struct* tstruct) {
-  indent(out) << "public override int GetHashCode() {" << endl;
-  indent_up();
-  
-  indent(out) << "int hashcode = 0;" << endl;
-  indent(out) << "unchecked {" << endl;
-  indent_up();
-  
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_type* ttype = (*f_iter)->get_type();
-    indent(out) << "hashcode = (hashcode * 397) ^ ";
-    if (field_is_required((*f_iter))) {
-    out << "(";
-    } else if ( nullable_) {
-      out << "(" << prop_name((*f_iter)) << " == null ? 0 : ";
-    }else {
-      out << "(!__isset." << (*f_iter)->get_name() << " ? 0 : ";
-    }
-    if (ttype->is_container()) {
-    	out << "(TCollections.GetHashCode("
-    		<< prop_name((*f_iter))
-    		<< "))";
-    } else {
-		out << "("
-			<< prop_name((*f_iter))
-			<< ".GetHashCode())";
-    }
-    out << ");" << endl;
-  }
-  
-  indent_down();
-  indent(out) << "}" << endl;
-  indent(out) << "return hashcode;" << endl;
-  
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-void t_csharp_generator::generate_service(t_service* tservice) {
-  string f_service_name = namespace_dir_ + "/" + service_name_ + ".cs";
-  f_service_.open(f_service_name.c_str());
-
-  f_service_ <<
-    autogen_comment() <<
-    csharp_type_usings() <<
-    csharp_thrift_usings() << endl;
-
-  start_csharp_namespace(f_service_);
-
-  indent(f_service_) <<
-    "public partial class " << service_name_ << " {" << endl;
-  indent_up();
-
-  generate_service_interface(tservice);
-  generate_service_client(tservice);
-  generate_service_server(tservice);
-  generate_service_helpers(tservice);
-
-  indent_down();
-
-  indent(f_service_) <<
-    "}" << endl;
-  end_csharp_namespace(f_service_);
-  f_service_.close();
-}
-
-void t_csharp_generator::generate_service_interface(t_service* tservice) {
-  string extends = "";
-  string extends_iface = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_iface = " : " + extends + ".Iface";
-  }
-
-  generate_csharp_doc(f_service_, tservice);
-
-  if (wcf_) {
-	  indent(f_service_) <<
-		"[ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
-  }
-  indent(f_service_) <<
-    "public interface Iface" << extends_iface << " {" << endl;
-
-  indent_up();
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
-  {
-	generate_csharp_doc(f_service_, *f_iter);
-
-	// if we're using WCF, add the corresponding attributes
-	if (wcf_) {
-		indent(f_service_) <<
-			"[OperationContract]" << endl;
-
-		const std::vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
-		vector<t_field*>::const_iterator x_iter;
-		for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-		  indent(f_service_) << "[FaultContract(typeof(" + type_name((*x_iter)->get_type(), false, false) + "Fault))]" << endl;
-		}
-	}
-
-    indent(f_service_) <<
-      function_signature(*f_iter) << ";" << endl;
-    if(!async_) {
-      indent(f_service_) << "#if SILVERLIGHT" << endl;
-    }
-    indent(f_service_) <<
-      function_signature_async_begin(*f_iter, "Begin_") << ";" << endl;
-    indent(f_service_) <<
-      function_signature_async_end(*f_iter, "End_") << ";" << endl;  
-    if(async_||async_ctp_) {
-      indent(f_service_) <<
-        function_signature_async(*f_iter) << ";" << endl;
-    }
-    if (!async_) {
-      indent(f_service_) << "#endif" << endl;
-    }
-  }
-  indent_down();
-  f_service_ <<
-    indent() << "}" << endl << endl;
-}
-
-void t_csharp_generator::generate_service_helpers(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    t_struct* ts = (*f_iter)->get_arglist();
-    generate_csharp_struct_definition(f_service_, ts, false, true);
-    generate_function_helpers(*f_iter);
-  }
-}
-
-void t_csharp_generator::generate_service_client(t_service* tservice) {
-  string extends = "";
-  string extends_client = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_client = extends + ".Client, ";
-  } else {
-    extends_client = "IDisposable, ";
-  }
-
-  generate_csharp_doc(f_service_, tservice);
-
-  indent(f_service_) <<
-    "public class Client : " << extends_client << "Iface {" << endl;
-  indent_up();
-  indent(f_service_) <<
-    "public Client(TProtocol prot) : this(prot, prot)" << endl;
-  scope_up(f_service_);
-  scope_down(f_service_);
-  f_service_ << endl;
-
-  indent(f_service_) <<
-    "public Client(TProtocol iprot, TProtocol oprot)";
-  if (!extends.empty()) {
-    f_service_ << " : base(iprot, oprot)";
-  }
-  f_service_ << endl;
-
-  scope_up(f_service_);
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "iprot_ = iprot;" << endl <<
-      indent() << "oprot_ = oprot;" << endl;
-  }
-  scope_down(f_service_);
-
-  f_service_ << endl;
-
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "protected TProtocol iprot_;" << endl <<
-      indent() << "protected TProtocol oprot_;" << endl <<
-      indent() << "protected int seqid_;" << endl << endl;
-
-    f_service_ << indent() << "public TProtocol InputProtocol" << endl;
-    scope_up(f_service_);
-    indent(f_service_) << "get { return iprot_; }" << endl;
-    scope_down(f_service_);
-
-    f_service_ << indent() << "public TProtocol OutputProtocol" << endl;
-    scope_up(f_service_);
-    indent(f_service_) << "get { return oprot_; }" << endl;
-    scope_down(f_service_);
-    f_service_ << endl << endl;
-    
-    indent(f_service_) << "#region \" IDisposable Support \"" << endl;
-    indent(f_service_) << "private bool _IsDisposed;" << endl << endl;
-    indent(f_service_) << "// IDisposable" << endl;
-    indent(f_service_) << "public void Dispose()" << endl;
-    scope_up(f_service_);
-    indent(f_service_) << "Dispose(true);" << endl;
-    scope_down(f_service_);
-    indent(f_service_) << endl << endl;
-    indent(f_service_) << "protected virtual void Dispose(bool disposing)" << endl;
-    scope_up(f_service_);
-    indent(f_service_) << "if (!_IsDisposed)" << endl;
-    scope_up(f_service_);
-    indent(f_service_) << "if (disposing)" << endl;
-    scope_up(f_service_);
-    indent(f_service_) << "if (iprot_ != null)" << endl;
-    scope_up(f_service_);
-    indent(f_service_) << "((IDisposable)iprot_).Dispose();" << endl;
-    scope_down(f_service_);
-    indent(f_service_) << "if (oprot_ != null)" << endl;
-    scope_up(f_service_);
-    indent(f_service_) << "((IDisposable)oprot_).Dispose();" << endl;
-    scope_down(f_service_);
-    scope_down(f_service_);
-    scope_down(f_service_);
-    indent(f_service_) << "_IsDisposed = true;" << endl;
-    scope_down(f_service_);
-    indent(f_service_) << "#endregion" << endl;
-    f_service_ << endl << endl;
-  }
-
-  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) {
-    string funname = (*f_iter)->get_name();
-
-    indent(f_service_) << endl;
-    
-    if (!async_) {
-      indent(f_service_) << "#if SILVERLIGHT" << endl;
-    }
-    // Begin_
-    indent(f_service_) <<
-      "public " << function_signature_async_begin(*f_iter, "Begin_") << endl;
-    scope_up(f_service_);
-    indent(f_service_) <<
-      "return " << "send_" << funname << "(callback, state";
-
-    t_struct* arg_struct = (*f_iter)->get_arglist();
-
-    const vector<t_field*>& fields = arg_struct->get_members();
-    vector<t_field*>::const_iterator fld_iter;
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      f_service_ << ", ";
-      f_service_ << (*fld_iter)->get_name();
-    }
-    f_service_ << ");" << endl;
-    scope_down(f_service_);
-    f_service_ << endl;
-	
-    // End
-    indent(f_service_) <<
-      "public " << function_signature_async_end(*f_iter, "End_") << endl;
-    scope_up(f_service_);
-    indent(f_service_) <<
-      "oprot_.Transport.EndFlush(asyncResult);" << endl;
-    if (!(*f_iter)->is_oneway()) {
-      f_service_ << indent();
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_ << "return ";
-      }
-      f_service_ <<
-        "recv_" << funname << "();" << endl;
-    }
-    scope_down(f_service_);
-    f_service_ << endl;
-
-    // async
-    bool first;
-    if( async_||async_ctp_) {
-      indent(f_service_) <<
-	"public async " << function_signature_async(*f_iter, "") << endl;
-      scope_up(f_service_);
-      
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        indent(f_service_) <<
-          type_name( (*f_iter)->get_returntype()) << " retval;" << endl;
-        indent(f_service_) <<
-          "retval = ";
-      } else {
-        indent(f_service_);
-      }
-      if (async_) {
-	f_service_ << "await Task.Run(() =>" << endl;
-      } else {
-	f_service_ << "await TaskEx.Run(() =>" << endl;
-      }
-      scope_up(f_service_);
-      indent(f_service_);
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_ <<
-          "return ";
-      }
-      f_service_ << 
-        funname << "(";
-	  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_down();
-      indent(f_service_) << 
-        "});" << endl;
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        indent(f_service_) << 
-          "return retval;"  << endl;
-      }
-	  scope_down(f_service_);
-      f_service_ << endl;
-    }
-    
-    if (!async_) {
-      indent(f_service_) << "#endif" << endl << endl;
-    }
-
-    // "Normal" Synchronous invoke
-    generate_csharp_doc(f_service_, *f_iter);
-    indent(f_service_) <<
-      "public " << function_signature(*f_iter) << endl;
-    scope_up(f_service_);
-
-    if (!async_) {
-      indent(f_service_) << "#if !SILVERLIGHT" << endl;
-      indent(f_service_) <<
-        "send_" << funname << "(";
-
-      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;
-
-      if (!(*f_iter)->is_oneway()) {
-        f_service_ << indent();
-        if (!(*f_iter)->get_returntype()->is_void()) {
-          f_service_ << "return ";
-        }
-        f_service_ <<
-          "recv_" << funname << "();" << endl;
-      }
-      f_service_ << endl;
-
-      indent(f_service_) << "#else" << endl;
-    }
-
-    // Silverlight synchronous invoke
-    indent(f_service_) << "var asyncResult = Begin_" << funname << "(null, null";
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      f_service_ << ", " << (*fld_iter)->get_name();
-    }
-    f_service_ << ");" << endl;
-
-    if (!(*f_iter)->is_oneway()) {
-      f_service_ << indent();
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_ << "return ";
-      }
-      f_service_ <<
-        "End_" << funname << "(asyncResult);" << endl;
-    }
-    f_service_ << endl;
-
-    if (!async_) {
-      indent(f_service_) << "#endif" << endl;
-    }
-    scope_down(f_service_);
-
-    // Send
-    t_function send_function(g_type_void,
-        string("send_") + (*f_iter)->get_name(),
-        (*f_iter)->get_arglist());
-
-    string argsname = (*f_iter)->get_name() + "_args";
-
-    if (!async_) {
-      indent(f_service_) << "#if SILVERLIGHT" << endl;
-    }
-    indent(f_service_) << "public " << function_signature_async_begin(&send_function) << endl;
-    if (!async_) {
-      indent(f_service_) << "#else" << endl;
-      indent(f_service_) << "public " << function_signature(&send_function) << endl;
-      indent(f_service_) << "#endif" << endl;
-    }
-    scope_up(f_service_);
-
-    f_service_ <<
-      indent() << "oprot_.WriteMessageBegin(new TMessage(\"" << funname << "\", TMessageType.Call, seqid_));" << endl <<
-      indent() << argsname << " args = new " << argsname << "();" << endl;
-
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      f_service_ <<
-        indent() << "args." << prop_name(*fld_iter) << " = " << (*fld_iter)->get_name() << ";" << endl;
-    }
-
-    f_service_ <<
-      indent() << "args.Write(oprot_);" << endl <<
-      indent() << "oprot_.WriteMessageEnd();" << endl;;
-    
-    if (!async_) {
-      indent(f_service_) << "#if SILVERLIGHT" << endl;
-    }
-    indent(f_service_) << "return oprot_.Transport.BeginFlush(callback, state);" << endl;
-    if (!async_) {
-      indent(f_service_) << "#else" << endl;
-      indent(f_service_) << "oprot_.Transport.Flush();" << endl;
-      indent(f_service_) << "#endif" << endl;
-    }
-
-    scope_down(f_service_);
-    f_service_ << endl;
-
-    if (!(*f_iter)->is_oneway()) {
-      string resultname = (*f_iter)->get_name() + "_result";
-
-      t_struct noargs(program_);
-      t_function recv_function((*f_iter)->get_returntype(),
-          string("recv_") + (*f_iter)->get_name(),
-          &noargs,
-          (*f_iter)->get_xceptions());
-      indent(f_service_) <<
-        "public " << function_signature(&recv_function) << endl;
-      scope_up(f_service_);
-
-      f_service_ <<
-        indent() << "TMessage msg = iprot_.ReadMessageBegin();" << endl <<
-        indent() << "if (msg.Type == TMessageType.Exception) {" << endl;
-      indent_up();
-      f_service_ <<
-        indent() << "TApplicationException x = TApplicationException.Read(iprot_);" << endl <<
-        indent() << "iprot_.ReadMessageEnd();" << endl <<
-        indent() << "throw x;" << endl;
-      indent_down();
-      f_service_ <<
-        indent() << "}" << endl <<
-        indent() << resultname << " result = new " << resultname << "();" << endl <<
-        indent() << "result.Read(iprot_);" << endl <<
-        indent() << "iprot_.ReadMessageEnd();" << endl;
-
-      if (!(*f_iter)->get_returntype()->is_void()) {
-	if (nullable_) {
-	  if (type_can_be_null((*f_iter)->get_returntype())) {
-	    f_service_ <<
-	      indent() << "if (result.Success != null) {" << endl <<
-	      indent() << "  return result.Success;" << endl <<
-	      indent() << "}" << endl;
-	  } else {
-	    f_service_ <<
-	      indent() << "if (result.Success.HasValue) {" << endl <<
-	      indent() << "  return result.Success.Value;" << endl <<
-	      indent() << "}" << endl;
-	  }
-	} else {
-	  f_service_ <<
-	    indent() << "if (result.__isset.success) {" << endl <<
-	    indent() << "  return result.Success;" << endl <<
-	    indent() << "}" << 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) {
-	if (nullable_) {
-	  f_service_ <<
-	    indent() << "if (result." << prop_name(*x_iter) << " != null) {" << endl <<
-	    indent() << "  throw result." << prop_name(*x_iter) << ";" << endl <<
-	    indent() << "}" << endl;
-	} else {
-	  f_service_ <<
-	    indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
-	    indent() << "  throw result." << prop_name(*x_iter) << ";" << endl <<
-	    indent() << "}" << endl;
-	}
-      }
-
-      if ((*f_iter)->get_returntype()->is_void()) {
-        indent(f_service_) <<
-          "return;" << endl;
-      } else {
-        f_service_ <<
-          indent() << "throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
-      }
-
-      scope_down(f_service_);
-      f_service_ << endl;
-    }
-  }
-
-  indent_down();
-  indent(f_service_) <<
-    "}" << endl;
-}
-
-void t_csharp_generator::generate_service_server(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  string extends = "";
-  string extends_processor = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_processor = extends + ".Processor, ";
-  }
-
-  indent(f_service_) <<
-    "public class Processor : " << extends_processor << "TProcessor {" << endl;
-  indent_up();
-
-  indent(f_service_) <<
-    "public Processor(Iface iface)" ;
-  if (!extends.empty()) {
-    f_service_ << " : base(iface)";
-  }
-  f_service_ << endl;
-  scope_up(f_service_);
-  f_service_ <<
-    indent() << "iface_ = iface;" << endl;
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_service_ <<
-      indent() << "processMap_[\"" << (*f_iter)->get_name() << "\"] = " << (*f_iter)->get_name() << "_Process;" << endl;
-  }
-
-  scope_down(f_service_);
-  f_service_ << endl;
-
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "protected delegate void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);" << endl;
-  }
-
-  f_service_ <<
-    indent() << "private Iface iface_;" << endl;
-
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new Dictionary<string, ProcessFunction>();" << endl;
-  }
-
-  f_service_ << endl;
-
-  if (extends.empty()) {
-    indent(f_service_) <<
-      "public bool Process(TProtocol iprot, TProtocol oprot)" << endl;
-  }
-  else
-  {
-    indent(f_service_) <<
-      "public new bool Process(TProtocol iprot, TProtocol oprot)" << endl;
-  }
-  scope_up(f_service_);
-
-  f_service_ <<  indent() << "try" << endl;
-  scope_up(f_service_);
-
-  f_service_ <<
-    indent() << "TMessage msg = iprot.ReadMessageBegin();" << endl;
-
-  f_service_ <<
-    indent() << "ProcessFunction fn;" << endl <<
-    indent() << "processMap_.TryGetValue(msg.Name, out fn);" << endl <<
-    indent() << "if (fn == null) {" << endl <<
-    indent() << "  TProtocolUtil.Skip(iprot, TType.Struct);" << endl <<
-    indent() << "  iprot.ReadMessageEnd();" << endl <<
-    indent() << "  TApplicationException x = new TApplicationException (TApplicationException.ExceptionType.UnknownMethod, \"Invalid method name: '\" + msg.Name + \"'\");" << endl <<
-    indent() << "  oprot.WriteMessageBegin(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID));" << endl <<
-    indent() << "  x.Write(oprot);" << endl <<
-    indent() << "  oprot.WriteMessageEnd();" << endl <<
-    indent() << "  oprot.Transport.Flush();" << endl <<
-    indent() << "  return true;" << endl <<
-    indent() << "}" << endl <<
-    indent() << "fn(msg.SeqID, iprot, oprot);" << endl;
-
-  scope_down(f_service_);
-
-  f_service_ <<
-    indent() << "catch (IOException)" << endl;
-  scope_up(f_service_);
-  f_service_ <<
-    indent() << "return false;" << endl;
-  scope_down(f_service_);
-
-  f_service_ <<
-    indent() << "return true;" << endl;
-
-  scope_down(f_service_);
-  f_service_ << endl;
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
-  {
-    generate_process_function(tservice, *f_iter);
-  }
-
-  indent_down();
-  indent(f_service_) <<
-    "}" << endl << endl;
-}
-
-void t_csharp_generator::generate_function_helpers(t_function* tfunction) {
-  if (tfunction->is_oneway()) {
-    return;
-  }
-
-  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_csharp_struct_definition(f_service_, &result, false, true, true);
-}
-
-void t_csharp_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
-  (void) tservice;
-  indent(f_service_) <<
-    "public void " << tfunction->get_name() << "_Process(int seqid, TProtocol iprot, TProtocol oprot)" << endl;
-  scope_up(f_service_);
-
-  string argsname = tfunction->get_name() + "_args";
-  string resultname = tfunction->get_name() + "_result";
-
-  f_service_ <<
-    indent() << argsname << " args = new " << argsname << "();" << endl <<
-    indent() << "args.Read(iprot);" << endl <<
-    indent() << "iprot.ReadMessageEnd();" << endl;
-
-  t_struct* xs = tfunction->get_xceptions();
-  const std::vector<t_field*>& xceptions = xs->get_members();
-  vector<t_field*>::const_iterator x_iter;
-
-  if (!tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << resultname << " result = new " << resultname << "();" << endl;
-  }
-
-  if (xceptions.size() > 0) {
-    f_service_ <<
-      indent() << "try {" << endl;
-    indent_up();
-  }
-
-  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_ << indent();
-  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
-    f_service_ << "result.Success = ";
-  }
-  f_service_ <<
-    "iface_." << 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." << prop_name(*f_iter);
-    if (nullable_ && !type_can_be_null((*f_iter)->get_type())) {
-      f_service_ << ".Value";
-    }
-  }
-  f_service_ << ");" << endl;
-
-  if (!tfunction->is_oneway() && xceptions.size() > 0) {
-    indent_down();
-    f_service_ << indent() << "}";
-    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " " << (*x_iter)->get_name() << ") {" << endl;
-      if (!tfunction->is_oneway()) {
-        indent_up();
-        f_service_ <<
-          indent() << "result." << prop_name(*x_iter) << " = " << (*x_iter)->get_name() << ";" << endl;
-        indent_down();
-        f_service_ << indent() << "}";
-      } else {
-        f_service_ << "}";
-      }
-    }
-    f_service_ << endl;
-  }
-
-  if (tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << "return;" << endl;
-    scope_down(f_service_);
-
-    return;
-  }
-
-  f_service_ <<
-    indent() << "oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.Reply, seqid)); " << endl <<
-    indent() << "result.Write(oprot);" << endl <<
-    indent() << "oprot.WriteMessageEnd();" << endl <<
-    indent() << "oprot.Transport.Flush();" << endl;
-
-  scope_down(f_service_);
-
-  f_service_ << endl;
-}
-
-void t_csharp_generator::generate_csharp_union_reader(std::ofstream& out, t_struct* tunion) {
-  // Thanks to THRIFT-1768, we don't need to check for required fields in the union
-  const vector<t_field*>& fields = tunion->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  indent(out) << "public static " << tunion->get_name() << " Read(TProtocol iprot)" << endl;
-  scope_up(out);
-  indent(out) << tunion->get_name() << " retval;" << endl;
-  indent(out) << "iprot.ReadStructBegin();" << endl;
-  indent(out) << "TField field = iprot.ReadFieldBegin();" << endl;
-  // we cannot have the first field be a stop -- we must have a single field defined
-  indent(out) << "if (field.Type == TType.Stop)" << endl;
-  scope_up(out);
-  indent(out) << "iprot.ReadFieldEnd();" << endl;
-  indent(out) << "retval = new ___undefined();" << endl;
-  scope_down(out);
-  indent(out) << "else" << endl;
-  scope_up(out);
-  indent(out) << "switch (field.ID)" << endl;
-  scope_up(out);
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    indent(out) <<
-      "case " << (*f_iter)->get_key() << ":" << endl;
-    indent_up();
-    indent(out) << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
-    indent_up();
-
-    indent(out) << type_name((*f_iter)->get_type()) << " temp;" << endl;
-    generate_deserialize_field(out, (*f_iter), "temp", true);
-    indent(out) << "retval = new " << (*f_iter)->get_name() << "(temp);" << endl;
-    
-    indent_down();
-    out <<
-      indent() << "} else { " << endl <<
-      indent() << "  TProtocolUtil.Skip(iprot, field.Type);" << endl <<
-      indent() << "  retval = new ___undefined();" << endl <<
-      indent() << "}" << endl <<
-      indent() << "break;" << endl;
-    indent_down();
-  }
-
-  indent(out) <<
-    "default: " << endl;
-  indent_up();
-  indent(out) << "TProtocolUtil.Skip(iprot, field.Type);" << endl <<
-    indent() << "retval = new ___undefined();" << endl;
-  indent(out) << "break;" << endl;
-  indent_down();
-
-  scope_down(out);
-
-  indent(out) << "iprot.ReadFieldEnd();" << endl;
-
-  indent(out) << "if (iprot.ReadFieldBegin().Type != TType.Stop)" << endl;
-  scope_up(out);
-  indent(out) << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl;
-  scope_down(out);
-
-  // end of else for TStop
-  scope_down(out);
-
-  indent(out) <<
-    "iprot.ReadStructEnd();" << endl;
-
-  indent(out) << "return retval;" << endl;
-
-  indent_down();
-
-  indent(out) << "}" << endl << endl;
-}
-
-void t_csharp_generator::generate_deserialize_field(ofstream& out, t_field* tfield, string prefix, bool is_propertyless) {
-  t_type* type = tfield->get_type();
-  while(type->is_typedef()) {
-    type = ((t_typedef*)type)->get_type();
-  }
-
-  if (type->is_void()) {
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
-  }
-
-  string name = prefix + (is_propertyless ? "" : prop_name(tfield));
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct(out, (t_struct*)type, name);
-  } else if (type->is_container()) {
-    generate_deserialize_container(out, type, name);
-  } else if (type->is_base_type() || type->is_enum()) {
-    indent(out) <<
-      name << " = ";
-
-    if (type->is_enum())
-    {
-      out << "(" << type_name(type, false, true) << ")";
-    }
-
-    out << "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:
-          if (((t_base_type*)type)->is_binary()) {
-             out << "ReadBinary();";
-          } else {
-            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 C# name for base type " + tbase;
-      }
-    } else if (type->is_enum()) {
-      out << "ReadI32();";
-    }
-    out << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type_name(type).c_str());
-  }
-}
-
-void t_csharp_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, string prefix) {
-  if (union_ && tstruct->is_union()) {
-    out << indent() << prefix << " = " << type_name(tstruct) << ".Read(iprot);" << endl;
-  } else {
-    out <<
-      indent() << prefix << " = new " << type_name(tstruct) << "();" << endl <<
-      indent() << prefix << ".Read(iprot);" << endl;
-  }
-}
-
-void t_csharp_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) {
-  scope_up(out);
-
-  string obj;
-
-  if (ttype->is_map()) {
-    obj = tmp("_map");
-  } else if (ttype->is_set()) {
-    obj = tmp("_set");
-  } else if (ttype->is_list()) {
-    obj = tmp("_list");
-  }
-
-  indent(out) <<
-    prefix << " = new " << type_name(ttype, false, true) << "();" <<endl;
-  if (ttype->is_map()) {
-    out <<
-      indent() << "TMap " << obj << " = iprot.ReadMapBegin();" << endl;
-  } else if (ttype->is_set()) {
-    out <<
-      indent() << "TSet " << obj << " = iprot.ReadSetBegin();" << endl;
-  } else if (ttype->is_list()) {
-    out <<
-      indent() << "TList " << obj << " = iprot.ReadListBegin();" << endl;
-  }
-
-  string i = tmp("_i");
-  indent(out) <<
-    "for( int " << i << " = 0; " << i << " < " << obj << ".Count" << "; " << "++" << i << ")" << endl;
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
-  } else if (ttype->is_set()) {
-    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
-  } else if (ttype->is_list()) {
-    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
-  }
-
-  scope_down(out);
-
-  if (ttype->is_map()) {
-    indent(out) << "iprot.ReadMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) << "iprot.ReadSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) << "iprot.ReadListEnd();" << endl;
-  }
-
-  scope_down(out);
-}
-
-void t_csharp_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, string prefix) {
-  string key = tmp("_key");
-  string val = tmp("_val");
-
-  t_field fkey(tmap->get_key_type(), key);
-  t_field fval(tmap->get_val_type(), val);
-
-  indent(out) <<
-    declare_field(&fkey) << endl;
-  indent(out) <<
-    declare_field(&fval) << endl;
-
-  generate_deserialize_field(out, &fkey);
-  generate_deserialize_field(out, &fval);
-
-  indent(out) <<
-    prefix << "[" << key << "] = " << val << ";" << endl;
-}
-
-void t_csharp_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) {
-  string elem = tmp("_elem");
-  t_field felem(tset->get_elem_type(), elem);
-
-  indent(out) <<
-    declare_field(&felem, true) << endl;
-
-  generate_deserialize_field(out, &felem);
-
-  indent(out) <<
-    prefix << ".Add(" << elem << ");" << endl;
-}
-
-void t_csharp_generator::generate_deserialize_list_element(ofstream& out, t_list* tlist, string prefix) {
-  string elem = tmp("_elem");
-  t_field felem(tlist->get_elem_type(), elem);
-
-  indent(out) <<
-    declare_field(&felem, true) << endl;
-
-  generate_deserialize_field(out, &felem);
-
-  indent(out) <<
-    prefix << ".Add(" << elem << ");" << endl;
-}
-
- void t_csharp_generator::generate_serialize_field(ofstream& out, t_field* tfield, string prefix, bool is_element, bool is_propertyless) {
-  t_type* type = tfield->get_type();
-  while (type->is_typedef()) {
-    type = ((t_typedef*)type)->get_type();
-  }
-
-  string name = prefix + (is_propertyless ? "" : prop_name(tfield));
-  
-  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);
-  } else if (type->is_container()) {
-    generate_serialize_container(out, type, name);
-  } else if (type->is_base_type() || type->is_enum()) {
-    indent(out) <<
-      "oprot.";
-    
-    string nullable_name = nullable_ && !is_element && !field_is_required(tfield)
-      ? name + ".Value"
-      : name;
-
-    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:
-          if (((t_base_type*)type)->is_binary()) {
-            out << "WriteBinary(";
-          } else {
-            out << "WriteString(";
-          }
-          out << name << ");";
-          break;
-        case t_base_type::TYPE_BOOL:
-          out << "WriteBool(" << nullable_name << ");";
-          break;
-        case t_base_type::TYPE_BYTE:
-          out << "WriteByte(" << nullable_name << ");";
-          break;
-        case t_base_type::TYPE_I16:
-          out << "WriteI16(" << nullable_name << ");";
-          break;
-        case t_base_type::TYPE_I32:
-          out << "WriteI32(" << nullable_name << ");";
-          break;
-        case t_base_type::TYPE_I64:
-          out << "WriteI64(" << nullable_name << ");";
-          break;
-        case t_base_type::TYPE_DOUBLE:
-          out << "WriteDouble(" << nullable_name << ");";
-          break;
-        default:
-          throw "compiler error: no C# name for base type " + tbase;
-      }
-    } else if (type->is_enum()) {
-      out << "WriteI32((int)" << nullable_name << ");";
-    }
-    out << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n",
-        prefix.c_str(),
-        tfield->get_name().c_str(),
-        type_name(type).c_str());
-  }
-}
-
-void t_csharp_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) {
-  (void) tstruct;
-  out <<
-    indent() << prefix << ".Write(oprot);" << endl;
-}
-
-void t_csharp_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) {
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    indent(out) <<
-      "oprot.WriteMapBegin(new TMap(" <<
-      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
-      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
-      prefix << ".Count));" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "oprot.WriteSetBegin(new TSet(" <<
-      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
-      prefix << ".Count));" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "oprot.WriteListBegin(new TList(" <<
-      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
-      prefix << ".Count));" << endl;
-  }
-
-  string iter = tmp("_iter");
-  if (ttype->is_map()) {
-    indent(out) <<
-      "foreach (" <<
-      type_name(((t_map*)ttype)->get_key_type()) << " " << iter <<
-      " in " <<
-      prefix << ".Keys)";
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "foreach (" <<
-      type_name(((t_set*)ttype)->get_elem_type()) << " " << iter <<
-      " in " <<
-      prefix << ")";
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "foreach (" <<
-      type_name(((t_list*)ttype)->get_elem_type()) << " " << iter <<
-      " in " <<
-      prefix << ")";
-  }
-
-  out << endl;
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
-  } else if (ttype->is_set()) {
-    generate_serialize_set_element(out, (t_set*)ttype, iter);
-  } else if (ttype->is_list()) {
-    generate_serialize_list_element(out, (t_list*)ttype, iter);
-  }
-
-  scope_down(out);
-
-  if (ttype->is_map()) {
-    indent(out) << "oprot.WriteMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) << "oprot.WriteSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) << "oprot.WriteListEnd();" << endl;
-  }
-
-  scope_down(out);
-}
-
-void t_csharp_generator::generate_serialize_map_element(ofstream& out, t_map* tmap, string iter, string map) {
-  t_field kfield(tmap->get_key_type(), iter);
-  generate_serialize_field(out, &kfield, "", true);
-  t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
-  generate_serialize_field(out, &vfield, "", true);
-}
-
-void t_csharp_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string iter) {
-  t_field efield(tset->get_elem_type(), iter);
-  generate_serialize_field(out, &efield, "", true);
-}
-
-void t_csharp_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string iter) {
-  t_field efield(tlist->get_elem_type(), iter);
-  generate_serialize_field(out, &efield, "", true);
-}
-
-void t_csharp_generator::generate_property(ofstream& out, t_field* tfield, bool isPublic, bool generateIsset) {
-    generate_csharp_property(out, tfield, isPublic, generateIsset, "_");
-}
-void t_csharp_generator::generate_csharp_property(ofstream& out, t_field* tfield, bool isPublic, bool generateIsset, std::string fieldPrefix) {
-    if((serialize_||wcf_) && isPublic) {
-      indent(out) << "[DataMember]" << endl;
-    }
-    bool has_default = field_has_default(tfield);
-    bool is_required = field_is_required(tfield);
-    if ((nullable_ && !has_default) || (is_required)) {
-      indent(out) << (isPublic ? "public " : "private ") << type_name(tfield->get_type(), false, false, true, is_required)
-                  << " " << prop_name(tfield) << " { get; set; }" << endl;
-    } else {
-      indent(out) << (isPublic ? "public " : "private ") << type_name(tfield->get_type(), false, false, true)
-		  << " " << prop_name(tfield) << endl;
-      scope_up(out);
-      indent(out) << "get" << endl;
-      scope_up(out);
-      bool use_nullable = false;
-      if (nullable_) {
-	t_type* ttype = tfield->get_type();
-	while (ttype->is_typedef()) {
-	  ttype = ((t_typedef*)ttype)->get_type();
-	}
-	if (ttype->is_base_type()) {
-	  use_nullable = ((t_base_type*)ttype)->get_base() != t_base_type::TYPE_STRING;
-	}
-      }
-      indent(out) << "return " << fieldPrefix + tfield->get_name() << ";" << endl;
-      scope_down(out);
-      indent(out) << "set" << endl;
-      scope_up(out);
-      if (use_nullable) {
-	if (generateIsset) {
-	  indent(out) << "__isset." << tfield->get_name() << " = value.HasValue;" << endl;
-	}
-	indent(out) << "if (value.HasValue) this." << fieldPrefix + tfield->get_name() << " = value.Value;" << endl;
-      } else {
-	if (generateIsset) {
-	  indent(out) << "__isset." << tfield->get_name() << " = true;" << endl;
-	}
-	indent(out) << "this." << fieldPrefix + tfield->get_name() << " = value;" << endl;
-      }
-      scope_down(out);
-      scope_down(out);
-    }
-    out << endl;
-}
-
-std::string t_csharp_generator::make_valid_csharp_identifier( std::string const & fromName) {
-    std::string str = fromName;
-    if( str.empty()) {
-        return str;
-    }
-
-    // tests rely on this
-    assert( ('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
-    
-    // if the first letter is a number, we add an additional underscore in front of it
-    char c = str.at(0);
-    if( ('0' <= c) && (c <= '9')) {
-        str = "_" + str;
-    }
-
-    // following chars: letter, number or underscore
-    for( size_t i = 0;  i < str.size();  ++i) {
-        c = str.at(i);        
-        if( (('A' > c) || (c > 'Z')) && 
-            (('a' > c) || (c > 'z')) && 
-            (('0' > c) || (c > '9')) && 
-            ('_' != c) ) {
-            str.replace( i, 1, "_");
-        }
-    }
-
-    return str;
-}
-
-std::string t_csharp_generator::prop_name(t_field* tfield) {
-    string name (tfield->get_name());
-    name[0] = toupper(name[0]);
-    return name;
-}
-
-string t_csharp_generator::type_name(t_type* ttype, bool in_container, bool in_init, bool in_param, bool is_required) {
-  (void) in_init;
-  while (ttype->is_typedef()) {
-    ttype = ((t_typedef*)ttype)->get_type();
-  }
-
-  if (ttype->is_base_type()) {
-    return base_type_name((t_base_type*)ttype, in_container, in_param, is_required);
-  } else if (ttype->is_map()) {
-    t_map *tmap = (t_map*) ttype;
-    return "Dictionary<" + type_name(tmap->get_key_type(), true) +
-      ", " + type_name(tmap->get_val_type(), true) + ">";
-  } else if (ttype->is_set()) {
-    t_set* tset = (t_set*) ttype;
-    return "THashSet<" + type_name(tset->get_elem_type(), true) + ">";
-  } else if (ttype->is_list()) {
-    t_list* tlist = (t_list*) ttype;
-    return "List<" + type_name(tlist->get_elem_type(), true) + ">";
-  }
-
-  t_program* program = ttype->get_program();
-  string postfix = (!is_required && nullable_ && in_param && ttype->is_enum()) ? "?" : "";
-  if (program != NULL && program != program_) {
-    string ns = program->get_namespace("csharp");
-    if (!ns.empty()) {
-      return ns + "." + ttype->get_name() + postfix;
-    }
-  }
-
-  return ttype->get_name() + postfix;
-}
-
-string t_csharp_generator::base_type_name(t_base_type* tbase, bool in_container, bool in_param, bool is_required) {
-  (void) in_container;
-  string postfix = (!is_required && nullable_ && in_param) ? "?" : "";
-  switch (tbase->get_base()) {
-    case t_base_type::TYPE_VOID:
-      return "void";
-    case t_base_type::TYPE_STRING:
-      if (tbase->is_binary()) {
-        return "byte[]";
-      } else {
-        return "string";
-      }
-    case t_base_type::TYPE_BOOL:
-      return "bool" + postfix;
-    case t_base_type::TYPE_BYTE:
-      return "sbyte" + postfix;
-    case t_base_type::TYPE_I16:
-      return "short" + postfix;
-    case t_base_type::TYPE_I32:
-      return "int" + postfix;
-    case t_base_type::TYPE_I64:
-      return "long" + postfix;
-    case t_base_type::TYPE_DOUBLE:
-      return "double" + postfix;
-    default:
-      throw "compiler error: no C# name for base type " + tbase->get_base();
-  }
-}
-
-string t_csharp_generator::declare_field(t_field* tfield, bool init, std::string prefix) {
-  string result = type_name(tfield->get_type()) + " " + prefix + tfield->get_name();
-  if (init) {
-    t_type* ttype = tfield->get_type();
-    while (ttype->is_typedef()) {
-      ttype = ((t_typedef*)ttype)->get_type();
-    }
-    if (ttype->is_base_type() && field_has_default(tfield)) {
-      ofstream dummy;
-      result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
-    } else if (ttype->is_base_type()) {
-      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
-      switch (tbase) {
-        case t_base_type::TYPE_VOID:
-          throw "NO T_VOID CONSTRUCT";
-        case t_base_type::TYPE_STRING:
-          result += " = null";
-          break; 
-        case t_base_type::TYPE_BOOL:
-          result += " = 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:
-          result += " = 0";
-          break;
-        case t_base_type::TYPE_DOUBLE:
-          result += " = (double)0";
-          break;
-      }
-    } else if (ttype->is_enum()) {
-      result += " = (" + type_name(ttype, false, true) + ")0";
-    } else if (ttype->is_container()) {
-      result += " = new " + type_name(ttype, false, true) + "()";
-    } else {
-      result += " = new " + type_name(ttype, false, true) + "()";
-    }
-  }
-  return result + ";";
-}
-
-string t_csharp_generator::function_signature(t_function* tfunction, string prefix) {
-  t_type* ttype = tfunction->get_returntype();
-  return type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")";
-}
-
-string t_csharp_generator::function_signature_async_begin(t_function* tfunction, string prefix) {
-  string comma = (tfunction->get_arglist()->get_members().size() > 0 ? ", " : "");
-  return "IAsyncResult " + prefix + tfunction->get_name() + "(AsyncCallback callback, object state" + comma + argument_list(tfunction->get_arglist()) + ")";
-}
-
-string t_csharp_generator::function_signature_async_end(t_function* tfunction, string prefix) {
-  t_type* ttype = tfunction->get_returntype();
-  return type_name(ttype) + " " + prefix + tfunction->get_name() + "(IAsyncResult asyncResult)";
-}
-
-string t_csharp_generator::function_signature_async(t_function* tfunction, string prefix) {
-  t_type* ttype = tfunction->get_returntype();
-  string task = "Task";
-  if( ! ttype->is_void())
-    task += "<" + type_name(ttype) + ">";
-  return task + " " + prefix + tfunction->get_name() + "Async(" + argument_list(tfunction->get_arglist()) + ")";
-}
-
-
-string t_csharp_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 += type_name((*f_iter)->get_type()) + " " + (*f_iter)->get_name();
-  }
-  return result;
-}
-
-string t_csharp_generator::type_to_enum(t_type* type) {
-  while (type->is_typedef()) {
-    type = ((t_typedef*)type)->get_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 "TType.String";
-      case t_base_type::TYPE_BOOL:
-        return "TType.Bool";
-      case t_base_type::TYPE_BYTE:
-        return "TType.Byte";
-      case t_base_type::TYPE_I16:
-        return "TType.I16";
-      case t_base_type::TYPE_I32:
-        return "TType.I32";
-      case t_base_type::TYPE_I64:
-        return "TType.I64";
-      case t_base_type::TYPE_DOUBLE:
-        return "TType.Double";
-    }
-  } else if (type->is_enum()) {
-    return "TType.I32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "TType.Struct";
-  } else if (type->is_map()) {
-    return "TType.Map";
-  } else if (type->is_set()) {
-    return "TType.Set";
-  } else if (type->is_list()) {
-    return "TType.List";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-void t_csharp_generator::generate_csharp_docstring_comment(ofstream &out, string contents) {
-  generate_docstring_comment(out,
-                             "/// <summary>\n",
-                             "/// ", contents,
-                             "/// </summary>\n");
-
-
-}
-
-void t_csharp_generator::generate_csharp_doc(ofstream &out, t_field* field) {
-  if (field->get_type()->is_enum()) {
-    string combined_message = field->get_doc() + "\n<seealso cref=\"" + get_enum_class_name(field->get_type()) + "\"/>";
-    generate_csharp_docstring_comment(out, combined_message);
-  } else {
-    generate_csharp_doc(out, (t_doc*)field);
-  }
-}
-
-void t_csharp_generator::generate_csharp_doc(ofstream &out, t_doc* tdoc) {
-  if (tdoc->has_doc()) {
-    generate_csharp_docstring_comment(out, tdoc->get_doc());
-  }
-}
-
-void t_csharp_generator::generate_csharp_doc(ofstream &out, t_function* tfunction) {
-  if (tfunction->has_doc()) {
-	stringstream ps;
-    const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
-    vector<t_field*>::const_iterator p_iter;
-    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
-      t_field* p = *p_iter;
-      ps << "\n<param name=\"" << p->get_name() << "\">";
-      if (p->has_doc()) {
-		std::string str = p->get_doc();
-		str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); // remove the newlines that appear from the parser
-		ps << str;
-      }
-	  ps << "</param>";
-    }
-    generate_docstring_comment(out,
-                               "",
-                               "/// ",
-							   "<summary>\n" + tfunction->get_doc() + "</summary>" + ps.str(),
-                               "");
-  }
-}
-
-std::string t_csharp_generator::get_enum_class_name(t_type* type) {
-  string package = "";
-  t_program* program = type->get_program();
-  if (program != NULL && program != program_) {
-    package = program->get_namespace("csharp") + ".";
-  }
-  return package + type->get_name();
-}
-
-THRIFT_REGISTER_GENERATOR(csharp, "C#",
-"    async:           Adds Async support using Task.Run.\n"
-"    asyncctp:        Adds Async CTP support using TaskEx.Run.\n"
-"    wcf:             Adds bindings for WCF to generated classes.\n"
-"    serial:          Add serialization support to generated classes.\n"
-"    nullable:        Use nullable types for properties.\n"
-"    hashcode:        Generate a hashcode and equals implementation for classes.\n"
-"    union:           Use new union typing, which includes a static read function for union types.\n"
-)
-
diff --git a/compiler/cpp/src/generate/t_d_generator.cc b/compiler/cpp/src/generate/t_d_generator.cc
deleted file mode 100644
index 58dbb9a..0000000
--- a/compiler/cpp/src/generate/t_d_generator.cc
+++ /dev/null
@@ -1,780 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- * Contains some contributions under the Thrift Software License.
- * Please see doc/old-thrift-license.txt in the Thrift distribution for
- * details.
- */
-
-#include <cassert>
-
-#include <fstream>
-#include <iostream>
-#include <set>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include <sys/stat.h>
-
-#include "platform.h"
-#include "t_oop_generator.h"
-
-using std::map;
-using std::ofstream;
-using std::ostream;
-using std::ostringstream;
-using std::set;
-using std::string;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * D code generator.
- *
- * generate_*() functions are called by the base class to emit code for the
- * given entity, print_*() functions write a piece of code to the passed
- * stream, and render_*() return a string containing the D representation of
- * the passed entity.
- */
-class t_d_generator : public t_oop_generator {
- public:
-  t_d_generator(
-      t_program* program,
-      const std::map<string, string>& parsed_options,
-      const string& option_string)
-    : t_oop_generator(program)
-  {
-    (void) parsed_options;
-    (void) option_string;
-    out_dir_base_ = "gen-d";
-  }
-
- protected:
-  virtual void init_generator() {
-    // Make output directory
-    MKDIR(get_out_dir().c_str());
-
-    string dir = program_->get_namespace("d");
-    string subdir = get_out_dir();
-    string::size_type loc;
-    while ((loc = dir.find(".")) != string::npos) {
-      subdir = subdir + "/" + dir.substr(0, loc);
-      MKDIR(subdir.c_str());
-      dir = dir.substr(loc+1);
-    }
-    if (!dir.empty()) {
-      subdir = subdir + "/" + dir;
-      MKDIR(subdir.c_str());
-    }
-
-    package_dir_ = subdir + "/";
-
-    // Make output file
-    string f_types_name = package_dir_ + program_name_ + "_types.d";
-    f_types_.open(f_types_name.c_str());
-
-    // Print header
-    f_types_ <<
-      autogen_comment() <<
-      "module " << render_package(*program_) << program_name_ << "_types;" << endl <<
-      endl;
-
-    print_default_imports(f_types_);
-
-    // Include type modules from other imported programs.
-    const vector<t_program*>& includes = program_->get_includes();
-    for (size_t i = 0; i < includes.size(); ++i) {
-      f_types_ <<
-        "import " << render_package(*(includes[i])) <<
-        includes[i]->get_name() << "_types;" << endl;
-    }
-    if (!includes.empty()) f_types_ << endl;
-  }
-
-  virtual void close_generator() {
-    // Close output file
-    f_types_.close();
-  }
-
-  virtual void generate_consts(std::vector<t_const*> consts) {
-    if (!consts.empty()) {
-      string f_consts_name = package_dir_+program_name_+"_constants.d";
-      ofstream f_consts;
-      f_consts.open(f_consts_name.c_str());
-
-      f_consts <<
-        autogen_comment() <<
-        "module " << render_package(*program_) << program_name_ << "_constants;" << endl
-        << endl;
-
-      print_default_imports(f_consts);
-
-      f_consts <<
-        "import " << render_package(*get_program()) << program_name_ << "_types;" << endl <<
-        endl;
-
-      vector<t_const*>::iterator c_iter;
-      for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-        string name = (*c_iter)->get_name();
-        t_type* type = (*c_iter)->get_type();
-        indent(f_consts) << "immutable(" << render_type_name(type) << ") " <<
-          name << ";" << endl;
-      }
-
-      f_consts <<
-        endl <<
-        "static this() {" << endl;
-      indent_up();
-
-      bool first = true;
-      for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-        if (first) {
-          first = false;
-        } else {
-          f_consts << endl;
-        }
-        t_type* type = (*c_iter)->get_type();
-        indent(f_consts) << (*c_iter)->get_name() << " = ";
-        if (!is_immutable_type(type)) {
-          f_consts << "cast(immutable(" << render_type_name(type) << ")) ";
-        }
-        f_consts <<
-          render_const_value(type, (*c_iter)->get_value()) << ";" << endl;
-      }
-      indent_down();
-      indent(f_consts) <<
-        "}" << endl;
-    }
-  }
-
-  virtual void generate_typedef(t_typedef* ttypedef) {
-    f_types_ <<
-      indent() << "alias " << render_type_name(ttypedef->get_type()) << " " <<
-      ttypedef->get_symbolic() << ";" << endl << endl;
-  }
-
-  virtual void generate_enum(t_enum* tenum) {
-    vector<t_enum_value*> constants = tenum->get_constants();
-
-    string enum_name = tenum->get_name();
-    f_types_ <<
-      indent() << "enum " << enum_name << " {" << endl;
-
-    indent_up();
-
-    vector<t_enum_value*>::const_iterator c_iter;
-    bool first = true;
-    for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-      if (first) {
-        first = false;
-      } else {
-        f_types_ << "," << endl;
-      }
-      indent(f_types_) << (*c_iter)->get_name();
-      if ((*c_iter)->has_value()) {
-        f_types_ << " = " << (*c_iter)->get_value();
-      }
-    }
-
-    f_types_ << endl;
-    indent_down();
-    indent(f_types_) << "}" << endl;
-
-    f_types_ << endl;
-  }
-
-  virtual void generate_struct(t_struct* tstruct) {
-    print_struct_definition(f_types_, tstruct, false);
-  }
-
-  virtual void generate_xception(t_struct* txception) {
-    print_struct_definition(f_types_, txception, true);
-  }
-
-  virtual void generate_service(t_service* tservice) {
-    string svc_name = tservice->get_name();
-
-    // Service implementation file includes
-    string f_servicename = package_dir_ + svc_name + ".d";
-    std::ofstream f_service;
-    f_service.open(f_servicename.c_str());
-    f_service <<
-      autogen_comment() <<
-      "module " << render_package(*program_) << svc_name << ";" << endl <<
-      endl;
-
-    print_default_imports(f_service);
-
-    f_service << "import " << render_package(*get_program()) << program_name_ <<
-      "_types;" << endl;
-
-    t_service* extends_service = tservice->get_extends();
-    if (extends_service != NULL) {
-      f_service <<
-        "import " << render_package(*(extends_service->get_program())) <<
-        extends_service->get_name() << ";" << endl;
-    }
-
-    f_service << endl;
-
-    string extends = "";
-    if (tservice->get_extends() != NULL) {
-      extends = " : " + render_type_name(tservice->get_extends());
-    }
-
-    f_service <<
-      indent() << "interface " << svc_name << extends << " {" << endl;
-    indent_up();
-
-    // Collect all the exception types service methods can throw so we can
-    // emit the necessary aliases later.
-    set<t_type*> exception_types;
-
-    // Print the method signatures.
-    vector<t_function*> functions = tservice->get_functions();
-    vector<t_function*>::iterator fn_iter;
-    for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) {
-      f_service << indent();
-      print_function_signature(f_service, *fn_iter);
-      f_service << ";" << endl;
-
-      const vector<t_field*>& exceptions = (*fn_iter)->get_xceptions()->get_members();
-      vector<t_field*>::const_iterator ex_iter;
-      for (ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter) {
-        exception_types.insert((*ex_iter)->get_type());
-      }
-    }
-
-    // Alias the exception types into the current scope.
-    if (!exception_types.empty()) f_service << endl;
-    set<t_type*>::const_iterator et_iter;
-    for (et_iter = exception_types.begin(); et_iter != exception_types.end(); ++et_iter) {
-      indent(f_service) << "alias " << render_package(*(*et_iter)->get_program()) <<
-        (*et_iter)->get_program()->get_name() << "_types" << "." <<
-        (*et_iter)->get_name() << " " << (*et_iter)->get_name() << ";" << endl;
-    }
-
-    // Write the method metadata.
-    ostringstream meta;
-    indent_up();
-    bool first = true;
-    for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) {
-      if ((*fn_iter)->get_arglist()->get_members().empty() &&
-        (*fn_iter)->get_xceptions()->get_members().empty() &&
-        !(*fn_iter)->is_oneway()) {
-        continue;
-      }
-
-      if (first) {
-        first = false;
-      } else {
-        meta << ",";
-      }
-
-      meta << endl <<
-        indent() << "TMethodMeta(`" << (*fn_iter)->get_name() << "`, " << endl;
-      indent_up();
-      indent(meta) << "[";
-
-      bool first = true;
-      const vector<t_field*> &params = (*fn_iter)->get_arglist()->get_members();
-      vector<t_field*>::const_iterator p_iter;
-      for (p_iter = params.begin(); p_iter != params.end(); ++p_iter) {
-        if (first) {
-          first = false;
-        } else {
-          meta << ", ";
-        }
-
-        meta << "TParamMeta(`" << (*p_iter)->get_name() << "`, " << (*p_iter)->get_key();
-
-        t_const_value* cv = (*p_iter)->get_value();
-        if (cv != NULL) {
-          meta << ", q{" << render_const_value((*p_iter)->get_type(), cv) << "}";
-        }
-        meta << ")";
-      }
-
-      meta << "]";
-
-      if (!(*fn_iter)->get_xceptions()->get_members().empty() ||
-        (*fn_iter)->is_oneway()) {
-        meta << "," << endl <<
-          indent() << "[";
-
-        bool first = true;
-        const vector<t_field*>& exceptions =
-          (*fn_iter)->get_xceptions()->get_members();
-        vector<t_field*>::const_iterator ex_iter;
-        for (ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter) {
-          if (first) {
-            first = false;
-          } else {
-            meta << ", ";
-          }
-
-          meta << "TExceptionMeta(`" << (*ex_iter)->get_name() <<
-            "`, " << (*ex_iter)->get_key() << ", `" <<
-            (*ex_iter)->get_type()->get_name() << "`)";
-        }
-
-        meta << "]";
-      }
-
-      if ((*fn_iter)->is_oneway()) {
-        meta << "," << endl <<
-          indent() << "TMethodType.ONEWAY";
-      }
-
-      indent_down();
-      meta << endl <<
-        indent() << ")";
-    }
-    indent_down();
-
-    string meta_str(meta.str());
-    if (!meta_str.empty()) {
-      f_service << endl <<
-        indent() << "enum methodMeta = [" << meta_str << endl <<
-        indent() << "];" << endl;
-    }
-
-    indent_down();
-    indent(f_service) << "}" << endl;
-
-
-    // Server skeleton generation.
-    string f_skeletonname = package_dir_ + svc_name + "_server.skeleton.d";
-    std::ofstream f_skeleton;
-    f_skeleton.open(f_skeletonname.c_str());
-    print_server_skeleton(f_skeleton, tservice);
-    f_skeleton.close();
-  }
-
- private:
-    /**
-     * Writes a server skeleton for the passed service to out.
-     */
-    void print_server_skeleton(ostream &out, t_service* tservice) {
-      string svc_name = tservice->get_name();
-
-      out <<
-        "/*" << endl <<
-        " * This auto-generated skeleton file illustrates how to build a server. If you" << endl <<
-        " * intend to customize it, you should edit a copy with another file name to " << endl <<
-        " * avoid overwriting it when running the generator again." << endl <<
-        " */" << endl <<
-        "module " << render_package(*tservice->get_program()) << svc_name << "_server;" << endl <<
-        endl <<
-        "import std.stdio;" << endl <<
-        "import thrift.codegen.processor;" << endl <<
-        "import thrift.protocol.binary;" << endl <<
-        "import thrift.server.simple;" << endl <<
-        "import thrift.server.transport.socket;" << endl <<
-        "import thrift.transport.buffered;" << endl <<
-        "import thrift.util.hashset;" << endl <<
-        endl <<
-        "import " << render_package(*tservice->get_program()) << svc_name << ";" << endl <<
-        "import " << render_package(*get_program()) << program_name_ << "_types;" << endl <<
-        endl <<
-        endl <<
-        "class " << svc_name << "Handler : " << svc_name << " {" << endl;
-
-      indent_up();
-      out <<
-        indent() << "this() {" << endl <<
-        indent() << "  // Your initialization goes here." << endl <<
-        indent() << "}" << endl <<
-        endl;
-
-      vector<t_function*> functions = tservice->get_functions();
-      vector<t_function*>::iterator f_iter;
-      for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-        out << indent();
-        print_function_signature(out, *f_iter);
-        out << " {" << endl;
-
-        indent_up();
-
-        out <<
-          indent() << "// Your implementation goes here." << endl <<
-          indent() << "writeln(\"" << (*f_iter)->get_name() << " called\");" << endl;
-
-        t_base_type* rt = (t_base_type*)(*f_iter)->get_returntype();
-        if (rt->get_base() != t_base_type::TYPE_VOID) {
-          indent(out) << "return typeof(return).init;" << endl;
-        }
-
-        indent_down();
-
-        out <<
-          indent() << "}" << endl <<
-          endl;
-      }
-
-      indent_down();
-      out <<
-        "}" << endl <<
-        endl;
-
-      out <<
-        indent() << "void main() {" << endl;
-      indent_up();
-      out <<
-        indent() << "auto protocolFactory = new TBinaryProtocolFactory!();" << endl <<
-        indent() << "auto processor = new TServiceProcessor!" << svc_name << "(new " << svc_name << "Handler);" << endl <<
-        indent() << "auto serverTransport = new TServerSocket(9090);" << endl <<
-        indent() << "auto transportFactory = new TBufferedTransportFactory;" << endl <<
-
-        indent() << "auto server = new TSimpleServer(" << endl <<
-        indent() << "  processor, serverTransport, transportFactory, protocolFactory);" << endl <<
-        indent() << "server.serve();" << endl;
-      indent_down();
-      out <<
-        "}" << endl;
-    }
-
-  /**
-   * Writes the definition of a struct or an exception type to out.
-   */
-  void print_struct_definition(ostream& out, t_struct* tstruct, bool is_exception) {
-    const vector<t_field*>& members = tstruct->get_members();
-
-    if (is_exception) {
-      indent(out) << "class " << tstruct->get_name() << " : TException {" << endl;
-    } else {
-      indent(out) << "struct " << tstruct->get_name() << " {" << endl;
-    }
-    indent_up();
-
-    // Declare all fields.
-    vector<t_field*>::const_iterator m_iter;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      indent(out) << render_type_name((*m_iter)->get_type()) << " " <<
-        (*m_iter)->get_name() << ";" << endl;
-    }
-
-    if (!members.empty()) indent(out) << endl;
-    indent(out) << "mixin TStructHelpers!(";
-
-    if (!members.empty()) {
-      // If there are any fields, construct the TFieldMeta array to pass to
-      // TStructHelpers. We can't just pass an empty array if not because []
-      // doesn't pass the TFieldMeta[] constraint.
-      out << "[";
-      indent_up();
-
-      bool first = true;
-      vector<t_field*>::const_iterator m_iter;
-      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-        if (first) {
-          first = false;
-        } else {
-          out << ",";
-        }
-        out << endl;
-
-        indent(out) << "TFieldMeta(`" << (*m_iter)->get_name() << "`, " <<
-          (*m_iter)->get_key();
-
-        t_const_value* cv = (*m_iter)->get_value();
-        t_field::e_req req = (*m_iter)->get_req();
-        out << ", " << render_req(req);
-        if (cv != NULL) {
-          out << ", q{" << render_const_value((*m_iter)->get_type(), cv) << "}";
-        }
-        out << ")";
-      }
-
-      indent_down();
-      out << endl << indent() << "]";
-    }
-
-    out << ");" << endl;
-
-    indent_down();
-    indent(out) <<
-      "}" << endl <<
-      endl;
-  }
-
-  /**
-   * Prints the D function signature (including return type) for the given
-   * method.
-   */
-  void print_function_signature(ostream& out, t_function* fn) {
-    out << render_type_name(fn->get_returntype()) <<
-      " " << fn->get_name() << "(";
-
-    const vector<t_field*>& fields = fn->get_arglist()->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 {
-        out << ", ";
-      }
-      out << render_type_name((*f_iter)->get_type(), true) << " " <<
-          (*f_iter)->get_name();
-    }
-
-    out << ")";
-  }
-
-  /**
-   * Returns the D representation of value. The result is guaranteed to be a
-   * single expression; for complex types, immediately called delegate
-   * literals are used to achieve this.
-   */
-  string render_const_value(t_type* type, t_const_value* value) {
-    // Resolve any typedefs.
-    type = get_true_type(type);
-
-    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:
-        out << "cast(" << render_type_name(type) << ")" << value->get_integer();
-        break;
-      case t_base_type::TYPE_I32:
-        out << value->get_integer();
-        break;
-      case t_base_type::TYPE_I64:
-        out << value->get_integer() << "L";
-        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()) {
-      out << "cast(" << render_type_name(type) << ")" << value->get_integer();
-    } else {
-      out << "{" << endl;
-      indent_up();
-
-      indent(out) << render_type_name(type) << " v;" << endl;
-      if (type->is_struct() || type->is_xception()) {
-        indent(out) << "v = " << (type->is_xception() ? "new " : "") <<
-          render_type_name(type) << "();" << endl;
-
-        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();
-          }
-          string val = render_const_value(field_type, v_iter->second);
-          indent(out) << "v.set!`" << v_iter->first->get_string() <<
-            "`(" << val << ");" << endl;
-        }
-      } 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();
-        map<t_const_value*, t_const_value*>::const_iterator v_iter;
-        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-          string key = render_const_value(ktype, v_iter->first);
-          string val = render_const_value(vtype, v_iter->second);
-          indent(out) << "v[";
-          if (!is_immutable_type(ktype)) {
-            out << "cast(immutable(" << render_type_name(ktype) << "))";
-          }
-          out << key << "] = " << val << ";" << endl;
-        }
-      } else if (type->is_list()) {
-        t_type* etype = ((t_list*)type)->get_elem_type();
-        const vector<t_const_value*>& val = value->get_list();
-        vector<t_const_value*>::const_iterator v_iter;
-        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-          string val = render_const_value(etype, *v_iter);
-          indent(out) << "v ~= " << val << ";" << endl;
-        }
-      } else if (type->is_set()) {
-        t_type* etype = ((t_set*)type)->get_elem_type();
-        const vector<t_const_value*>& val = value->get_list();
-        vector<t_const_value*>::const_iterator v_iter;
-        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-          string val = render_const_value(etype, *v_iter);
-          indent(out) << "v ~= " << val << ";" << endl;
-        }
-      } else {
-        throw "Compiler error: Invalid type in render_const_value: " +
-          type->get_name();
-      }
-      indent(out) << "return v;" << endl;
-
-      indent_down();
-      indent(out) << "}()";
-    }
-
-    return out.str();
-  }
-
-  /**
-   * Returns the D package to which modules for program are written (with a
-   * trailing dot, if not empty).
-   */
-  string render_package(const t_program& program) const {
-    string package = program.get_namespace("d");
-    if (package.size() == 0) return "";
-    return package + ".";
-  }
-
-  /**
-   * Returns the name of the D repesentation of ttype.
-   *
-   * If isArg is true, a const reference to the type will be returned for
-   * structs.
-   */
-  string render_type_name(const t_type* ttype, bool isArg = false) const {
-    if (ttype->is_base_type()) {
-      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
-      switch (tbase) {
-      case t_base_type::TYPE_VOID:
-        return "void";
-      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 "short";
-      case t_base_type::TYPE_I32:
-        return "int";
-      case t_base_type::TYPE_I64:
-        return "long";
-      case t_base_type::TYPE_DOUBLE:
-        return "double";
-      default:
-        throw "Compiler error: No D type name for base type " +
-          t_base_type::t_base_name(tbase);
-      }
-    }
-
-    if (ttype->is_container()) {
-      t_container* tcontainer = (t_container*) ttype;
-      if (tcontainer->has_cpp_name()) {
-        return tcontainer->get_cpp_name();
-      } else if (ttype->is_map()) {
-        t_map* tmap = (t_map*) ttype;
-        t_type* ktype = tmap->get_key_type();
-
-        string name = render_type_name(tmap->get_val_type()) + "[";
-        if (!is_immutable_type(ktype)) {
-          name += "immutable(";
-        }
-        name += render_type_name(ktype);
-        if (!is_immutable_type(ktype)) {
-          name += ")";
-        }
-        name += "]";
-        return name;
-      } else if (ttype->is_set()) {
-        t_set* tset = (t_set*) ttype;
-        return "HashSet!(" + render_type_name(tset->get_elem_type()) + ")";
-      } else if (ttype->is_list()) {
-        t_list* tlist = (t_list*) ttype;
-        return render_type_name(tlist->get_elem_type()) + "[]";
-      }
-    }
-
-    if (ttype->is_struct() && isArg) {
-      return "ref const(" + ttype->get_name() + ")";
-    } else {
-      return ttype->get_name();
-    }
-  }
-
-  /**
-   * Returns the D TReq enum member corresponding to req.
-   */
-  string render_req(t_field::e_req req) const {
-    switch (req) {
-    case t_field::T_OPT_IN_REQ_OUT:
-      return "TReq.OPT_IN_REQ_OUT";
-    case t_field::T_OPTIONAL:
-      return "TReq.OPTIONAL";
-    case t_field::T_REQUIRED:
-      return "TReq.REQUIRED";
-    default:
-      throw "Compiler error: Invalid requirement level: " + req;
-    }
-  }
-
-  /**
-   * Writes the default list of imports (which are written to every generated
-   * module) to f.
-   */
-  void print_default_imports(ostream& out) {
-    indent(out) <<
-      "import thrift.base;" << endl <<
-      "import thrift.codegen.base;" << endl <<
-      "import thrift.util.hashset;" << endl <<
-      endl;
-  }
-
-  /**
-   * Returns whether type is »intrinsically immutable«, in the sense that
-   * a value of that type is implicitly castable to immutable(type), and it is
-   * allowed for AA keys without an immutable() qualifier.
-   */
-  bool is_immutable_type(t_type* type) const {
-    t_type* ttype = get_true_type(type);
-    return ttype->is_base_type() || ttype->is_enum();
-  }
-
-  /*
-   * File streams, stored here to avoid passing them as parameters to every
-   * function.
-   */
-  ofstream f_types_;
-  ofstream f_header_;
-
-  string package_dir_;
-};
-
-THRIFT_REGISTER_GENERATOR(d, "D", "")
-
diff --git a/compiler/cpp/src/generate/t_delphi_generator.cc b/compiler/cpp/src/generate/t_delphi_generator.cc
deleted file mode 100644
index 547031d..0000000
--- a/compiler/cpp/src/generate/t_delphi_generator.cc
+++ /dev/null
@@ -1,3129 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- * Contains some contributions under the Thrift Software License.
- * Please see doc/old-thrift-license.txt in the Thrift distribution for
- * details.
- */
-
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-#include <list>
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sstream>
-#include <cctype>
-
-#include "platform.h"
-#include "t_oop_generator.h"
-
-using std::map;
-using std::ofstream;
-using std::ostream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-class t_delphi_generator : public t_oop_generator
-{
-  public:
-    t_delphi_generator(
-        t_program* program,
-        const std::map<std::string, std::string>& parsed_options,
-        const std::string& option_string)
-      : t_oop_generator(program)
-    {
-      (void) option_string;
-
-      std::map<std::string, std::string>::const_iterator iter;
-
-      iter = parsed_options.find("ansistr_binary");
-      ansistr_binary_ = (iter != parsed_options.end());
-      iter = parsed_options.find("register_types");
-	  register_types_ = (iter != parsed_options.end());
-
-      out_dir_base_ = "gen-delphi";
-      escape_.clear();
-      escape_['\''] = "''";
-    }
-
-
-    void init_generator();
-    void close_generator();
-
-    void generate_consts(std::vector<t_const*> consts);
-
-    void generate_typedef (t_typedef* ttypedef);
-    void generate_enum (t_enum* tenum);
-    void generate_struct (t_struct* tstruct);
-    void generate_xception (t_struct* txception);
-    void generate_service (t_service* tservice);
-    void generate_property(ostream& out, t_field* tfield, bool isPublic,  bool is_xception);
-    void generate_property_writer_(ostream& out, t_field* tfield, bool isPublic);
-
-    void generate_delphi_property(ostream& out, bool struct_is_exception, t_field* tfield, bool isPublic, std::string fieldPrefix = "");
-    void generate_delphi_isset_reader_definition(ostream& out, t_field* tfield, bool is_xception);
-    void generate_delphi_property_reader_definition(ostream& out, t_field* tfield, bool is_xception_class);
-    void generate_delphi_property_writer_definition(ostream& out, t_field* tfield, bool is_xception_class);
-    void generate_delphi_property_reader_impl(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception_class);
-    void generate_delphi_property_writer_impl(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception_class, bool is_union, bool is_xception_factory, std::string xception_factroy_name);
-    void generate_delphi_clear_union_value(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception_class, bool is_union, bool is_xception_factory, std::string xception_factroy_name);
-    void generate_delphi_isset_reader_impl(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception);
-    void generate_delphi_struct_writer_impl(ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception);
-    void generate_delphi_struct_result_writer_impl(ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception);
-
-    void generate_delphi_struct_tostring_impl(ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_x_factory);
-
-    void add_delphi_uses_list( string unitname);
-
-    void generate_delphi_struct_reader_impl(ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception);
-    void generate_delphi_create_exception_impl(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception);
-
-    void print_const_prop(std::ostream& out, string name, t_type* type, t_const_value* value);
-    void print_private_field(std::ostream& out, string name, t_type* type, t_const_value* value);
-    void print_const_value ( std::ostream& vars, std::ostream& out, std::string name, t_type* type, t_const_value* value);
-    void initialize_field(std::ostream& vars, std::ostream& out, std::string name, t_type* type, t_const_value* value);
-    void finalize_field(std::ostream& out, std::string name, t_type* type, t_const_value* value, std::string cls_nm = "");
-    std::string render_const_value( std::ostream& local_vars, std::ostream& out, std::string name, t_type* type, t_const_value* value);
-    void print_const_def_value( std::ostream& vars, std::ostream& out, std::string name, t_type* type, t_const_value* value, std::string cls_nm = "");
-
-    void generate_delphi_struct(t_struct* tstruct, bool is_exception);
-    void generate_delphi_struct_impl( ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result = false, bool is_x_factory = false);
-	void print_delphi_struct_type_factory_func(  ostream& out, t_struct* tstruct);
-	void generate_delphi_struct_type_factory(  ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result = false, bool is_x_factory = false);
-	void generate_delphi_struct_type_factory_registration(  ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result = false, bool is_x_factory = false);
-    void generate_delphi_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception=false, bool in_class=false, bool is_result=false, bool is_x_factory = false);
-    void generate_delphi_struct_reader(std::ostream& out, t_struct* tstruct);
-    void generate_delphi_struct_result_writer(std::ostream& out, t_struct* tstruct);
-    void generate_delphi_struct_writer(std::ostream& out, t_struct* tstruct);
-    void generate_delphi_struct_tostring(std::ostream& out, t_struct* tstruct);
-
-    void generate_function_helpers(t_function* tfunction);
-    void generate_service_interface (t_service* tservice);
-    void generate_service_helpers (t_service* tservice);
-    void generate_service_client (t_service* tservice);
-    void generate_service_server (t_service* tservice);
-    void generate_process_function (t_service* tservice, t_function* function);
-
-    void generate_deserialize_field (std::ostream& out, bool is_xception, t_field* tfield, std::string prefix, std::ostream& local_vars);
-    void generate_deserialize_struct (std::ostream& out, t_struct* tstruct, std::string name, std::string prefix);
-    void generate_deserialize_container(ostream& out, bool is_xception, t_type* ttype, string name, std::ostream& local_vars);
-
-    void generate_deserialize_set_element (std::ostream& out, bool is_xception, t_set* tset, std::string prefix, std::ostream& local_vars);
-    void generate_deserialize_map_element (std::ostream& out, bool is_xception, t_map* tmap, std::string prefix, std::ostream& local_vars);
-    void generate_deserialize_list_element (std::ostream& out, bool is_xception, t_list* list, std::string prefix, std::ostream& local_vars);
-
-    void generate_serialize_field (std::ostream& out, bool is_xception, t_field* tfield, std::string prefix, std::ostream& local_vars);
-    void generate_serialize_struct (std::ostream& out, t_struct* tstruct, std::string prefix, std::ostream& local_vars);
-    void generate_serialize_container (std::ostream& out, bool is_xception, t_type* ttype, std::string prefix, std::ostream& local_vars);
-    void generate_serialize_map_element (std::ostream& out, bool is_xception, t_map* tmap, std::string iter, std::string map, std::ostream& local_vars);
-    void generate_serialize_set_element (std::ostream& out, bool is_xception, t_set* tmap, std::string iter, std::ostream& local_vars);
-    void generate_serialize_list_element (std::ostream& out, bool is_xception, t_list* tlist, std::string iter, std::ostream& local_vars);
-
-    void delphi_type_usings(std::ostream& out);
-    std::string delphi_thrift_usings();
-
-    std::string type_name( t_type* ttype, bool b_cls=false, bool b_no_postfix=false, bool b_exception_factory=false, bool b_full_exception_factory = false);
-    std::string normalize_clsnm(std::string name, std::string prefix, bool b_no_check_keyword = false);
-    std::string input_arg_prefix( t_type* ttype);
-  
-    std::string base_type_name(t_base_type* tbase);
-    std::string declare_field(t_field* tfield, bool init=false, std::string prefix="", bool is_xception_class = false);
-    std::string function_signature(t_function* tfunction, std::string full_cls="", bool is_xception = false);  
-    std::string argument_list(t_struct* tstruct);
-    std::string constructor_argument_list(t_struct* tstruct, std::string current_indent);
-    std::string type_to_enum(t_type* ttype);
-    std::string prop_name(t_field* tfield, bool is_xception = false);
-    std::string prop_name(std::string name, bool is_xception = false);
-    std::string constructor_param_name(string name);
-
-    void write_enum(std::string line);
-    void write_forward_decr(std::string line);
-    void write_const(std::string line);
-    void write_struct(std::string line);
-    void write_service(std::string line);
-
-    virtual std::string autogen_comment() {
-      return
-        std::string("(**\n") +
-        " * Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" +
-        " *\n" +
-        " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
-        " *)\n";
-    }
-
-    bool type_can_be_null(t_type* ttype) {
-      while (ttype->is_typedef()) {
-        ttype = ((t_typedef*)ttype)->get_type();
-      }
-
-      return ttype->is_container() ||
-        ttype->is_struct() ||
-        ttype->is_xception();
-    }
-
-  private:
-    std::string namespace_name_;
-    std::ostringstream s_forward_decr;
-    std::ostringstream s_enum;
-    std::ostringstream s_const;
-    std::ostringstream s_struct;
-    std::ostringstream s_service;
-    std::ostringstream s_const_impl;
-    std::ostringstream s_struct_impl;
-    std::ostringstream s_service_impl;
-	std::ostringstream s_type_factory_registration;
-	std::ostringstream s_type_factory_funcs;
-    bool has_enum;
-    bool has_const;
-    std::string namespace_dir_;
-    std::map<std::string, int> delphi_keywords;
-    std::map<std::string, int> delphi_reserved_method;
-    std::map<std::string, int> delphi_reserved_method_exception;
-    std::map<std::string, int> types_known;
-    std::list<t_typedef*> typedefs_pending;
-    std::vector<std::string> uses_list;
-    void create_keywords();
-    bool find_keyword( std::map<std::string, int>& keyword_map, std::string name);
-    std::string normalize_name( std::string name, bool b_method = false, bool b_exception_method = false);
-    std::string empty_value(t_type* type);
-    bool is_fully_defined_type( t_type* ttype);
-    void add_defined_type( t_type* ttype);
-    void init_known_types_list();
-    bool is_void( t_type* type );
-    int indent_impl_;
-    bool ansistr_binary_;
-	bool register_types_;
-    void indent_up_impl(){
-      ++indent_impl_;
-    };
-    void indent_down_impl() {
-      --indent_impl_;
-    };
-    std::string indent_impl() {
-      std::string ind = "";
-      int i;
-      for (i = 0; i < indent_impl_; ++i) {
-        ind += "  ";
-      }
-      return ind;
-    };
-    std::ostream& indent_impl(std::ostream &os) {
-      return os << indent_impl();
-    };
-};
-
-bool t_delphi_generator::find_keyword( std::map<std::string, int>& keyword_map, std::string name) {
-  int len = name.length();
-
-  if ( len <= 0 ) {
-    return false;
-  }
-
-  int nlast = name.find_last_of('_');
-
-  if ( nlast >= 1) {
-    if (nlast == (len - 1)) {
-      string new_name( name, 0, nlast);
-      return find_keyword( keyword_map, new_name);
-    }
-  }
-  return (keyword_map[name] == 1);
-}
-
-std::string t_delphi_generator::normalize_name( std::string name, bool b_method, bool b_exception_method) {
-  string tmp( name );
-  std::transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast<int (*)(int)>(std::tolower));
-
-  bool b_found = false;
-
-  if ( find_keyword( delphi_keywords, tmp) ) {
-    b_found = true;
-  } else if ( b_method && find_keyword( delphi_reserved_method, tmp)) {
-    b_found = true;
-  } else if ( b_exception_method && find_keyword( delphi_reserved_method_exception, tmp)) {
-    b_found = true;
-  }
-
-  if (b_found) {
-    return name + "_";
-  } else {
-    return name;
-  }
-}
-
-void t_delphi_generator::create_keywords() {
-  delphi_keywords["and"] = 1;
-  delphi_keywords["end"] = 1;
-  delphi_keywords["interface"] = 1;
-  delphi_keywords["raise"] = 1;
-  delphi_keywords["uses"] = 1;
-  delphi_keywords["array"] = 1;
-  delphi_keywords["except"] = 1;
-  delphi_keywords["is"] = 1;
-  delphi_keywords["record"] = 1;
-  delphi_keywords["var"] = 1;
-  delphi_keywords["as"] = 1;
-  delphi_keywords["exports"] = 1;
-  delphi_keywords["label"] = 1;
-  delphi_keywords["repeat"] = 1;
-  delphi_keywords["while"] = 1;
-  delphi_keywords["asm"] = 1;
-  delphi_keywords["file"] = 1;
-  delphi_keywords["library"] = 1;
-  delphi_keywords["resourcestring"] = 1;
-  delphi_keywords["with"] = 1;
-  delphi_keywords["begin"] = 1;
-  delphi_keywords["finalization"] = 1;
-  delphi_keywords["mod"] = 1;
-  delphi_keywords["set"] = 1;
-  delphi_keywords["xor"] = 1;
-  delphi_keywords["case"] = 1;
-  delphi_keywords["finally"] = 1;
-  delphi_keywords["nil"] = 1;
-  delphi_keywords["shl"] = 1;
-  delphi_keywords["class"] = 1;
-  delphi_keywords["for"] = 1;
-  delphi_keywords["not"] = 1;
-  delphi_keywords["shr"] = 1;
-  delphi_keywords["const"] = 1;
-  delphi_keywords["function"] = 1;
-  delphi_keywords["object"] = 1;
-  delphi_keywords["string"] = 1;
-  delphi_keywords["constructor"] = 1;
-  delphi_keywords["goto"] = 1;
-  delphi_keywords["of"] = 1;
-  delphi_keywords["then"] = 1;
-  delphi_keywords["destructor"] = 1;
-  delphi_keywords["if"] = 1;
-  delphi_keywords["or"] = 1;
-  delphi_keywords["threadvar"] = 1;
-  delphi_keywords["dispinterface"] = 1;
-  delphi_keywords["implementation"] = 1;
-  delphi_keywords["out"] = 1;
-  delphi_keywords["to"] = 1;
-  delphi_keywords["div"] = 1;
-  delphi_keywords["in"] = 1;
-  delphi_keywords["packed"] = 1;
-  delphi_keywords["try"] = 1;
-  delphi_keywords["do"] = 1;
-  delphi_keywords["inherited"] = 1;
-  delphi_keywords["procedure"] = 1;
-  delphi_keywords["type"] = 1;
-  delphi_keywords["downto"] = 1;
-  delphi_keywords["initialization"] = 1;
-  delphi_keywords["program"] = 1;
-  delphi_keywords["unit"] = 1;
-  delphi_keywords["else"] = 1;
-  delphi_keywords["inline"] = 1;
-  delphi_keywords["property"] = 1;
-  delphi_keywords["until"] = 1;
-  delphi_keywords["private"] = 1;
-  delphi_keywords["protected"] = 1;
-  delphi_keywords["public"] = 1;
-  delphi_keywords["published"] = 1;
-  delphi_keywords["automated"] = 1;
-  delphi_keywords["at"] = 1;
-  delphi_keywords["on"] = 1;
-  delphi_keywords["result"] = 1;
-
-  delphi_reserved_method["create"] = 1;
-  delphi_reserved_method["free"] = 1;
-  delphi_reserved_method["initinstance"] = 1;
-  delphi_reserved_method["cleanupinstance"] = 1;
-  delphi_reserved_method["classtype"] = 1;
-  delphi_reserved_method["classname"] = 1;
-  delphi_reserved_method["classnameis"] = 1;
-  delphi_reserved_method["classparent"] = 1;
-  delphi_reserved_method["classinfo"] = 1;
-  delphi_reserved_method["instancesize"] = 1;
-  delphi_reserved_method["inheritsfrom"] = 1;
-  delphi_reserved_method["methodaddress"] = 1;
-  delphi_reserved_method["methodaddress"] = 1;
-  delphi_reserved_method["methodname"] = 1;
-  delphi_reserved_method["fieldaddress"] = 1;
-  delphi_reserved_method["fieldaddress"] = 1;
-  delphi_reserved_method["getinterface"] = 1;
-  delphi_reserved_method["getinterfaceentry"] = 1;
-  delphi_reserved_method["getinterfacetable"] = 1;
-  delphi_reserved_method["unitname"] = 1;
-  delphi_reserved_method["equals"] = 1;
-  delphi_reserved_method["gethashcode"] = 1;
-  delphi_reserved_method["tostring"] = 1;
-  delphi_reserved_method["safecallexception"] = 1;
-  delphi_reserved_method["afterconstruction"] = 1;
-  delphi_reserved_method["beforedestruction"] = 1;
-  delphi_reserved_method["dispatch"] = 1;
-  delphi_reserved_method["defaulthandler"] = 1;
-  delphi_reserved_method["newinstance"] = 1;
-  delphi_reserved_method["freeinstance"] = 1;
-  delphi_reserved_method["destroy"] = 1;
-  delphi_reserved_method["read"] = 1;
-  delphi_reserved_method["write"] = 1;
-
-  delphi_reserved_method_exception["setinnerexception"] = 1;
-  delphi_reserved_method_exception["setstackinfo"] = 1;
-  delphi_reserved_method_exception["getstacktrace"] = 1;
-  delphi_reserved_method_exception["raisingexception"] = 1;
-  delphi_reserved_method_exception["createfmt"] = 1;
-  delphi_reserved_method_exception["createres"] = 1;
-  delphi_reserved_method_exception["createresfmt"] = 1;
-  delphi_reserved_method_exception["createhelp"] = 1;
-  delphi_reserved_method_exception["createfmthelp"] = 1;
-  delphi_reserved_method_exception["createreshelp"] = 1;
-  delphi_reserved_method_exception["createresfmthelp"] = 1;
-  delphi_reserved_method_exception["getbaseexception"] = 1;
-  delphi_reserved_method_exception["baseexception"] = 1;
-  delphi_reserved_method_exception["helpcontext"] = 1;
-  delphi_reserved_method_exception["innerexception"] = 1;
-  delphi_reserved_method_exception["message"] = 1;
-  delphi_reserved_method_exception["stacktrace"] = 1;
-  delphi_reserved_method_exception["stackinfo"] = 1;
-  delphi_reserved_method_exception["getexceptionstackinfoproc"] = 1;
-  delphi_reserved_method_exception["getstackinfostringproc"] = 1;
-  delphi_reserved_method_exception["cleanupstackinfoproc"] = 1;
-  delphi_reserved_method_exception["raiseouterexception"] = 1;
-  delphi_reserved_method_exception["throwouterexception"] = 1;
-}
-
-void t_delphi_generator::add_delphi_uses_list( string unitname){
-  vector<std::string>::const_iterator s_iter;
-  bool found = false;
-  for (s_iter = uses_list.begin(); s_iter != uses_list.end(); ++s_iter) {
-    if ((*s_iter) == unitname ) {
-      found = true;
-      break;
-    }
-  }
-  if (! found) {
-    uses_list.push_back( unitname );
-  }
-}
-
-void t_delphi_generator::init_generator() {
-  indent_impl_ = 0;
-  namespace_name_ = program_->get_namespace("delphi");
-  has_enum = false;
-  has_const = false;
-  create_keywords();
-  add_delphi_uses_list("Classes");
-  add_delphi_uses_list("SysUtils");
-  add_delphi_uses_list("Generics.Collections");
-  add_delphi_uses_list("Thrift");
-  add_delphi_uses_list("Thrift.Utils");
-  add_delphi_uses_list("Thrift.Collections");
-  add_delphi_uses_list("Thrift.Protocol");
-  add_delphi_uses_list("Thrift.Transport");
-
-  if (register_types_)
-  {
-	  add_delphi_uses_list("Thrift.TypeRegistry");
-  }
-
-  init_known_types_list();
-  
-  string unitname, nsname;
-  const vector<t_program*>& includes = program_->get_includes();
-  for (size_t i = 0; i < includes.size(); ++i) {
-    unitname = includes[i]->get_name();
-    nsname = includes[i]->get_namespace("delphi");
-    if ( "" != nsname) {
-      unitname = nsname;
-    }
-    add_delphi_uses_list(unitname);
-  }
-
-
-  MKDIR(get_out_dir().c_str());
-}
-
-void t_delphi_generator::close_generator() { 
-  std::string unitname = program_name_;
-  if( "" != namespace_name_) {
-    unitname = namespace_name_;
-  }
-
-  for ( int i = 0; i < (int)unitname.size(); i++) {
-    if ( unitname[i] == ' ' ) {
-      unitname.replace( i, 1, "_" );
-    }
-  }
-
-  std::string f_name = get_out_dir() + "/" + unitname + ".pas";
-  std::ofstream f_all;
-
-  f_all.open( f_name.c_str() );
-
-  f_all << autogen_comment() << endl;
-  f_all << "unit " << unitname << ";" << endl << endl;
-  f_all << "interface" << endl << endl;
-  f_all  << "uses"  << endl;
-
-  indent_up();
-
-  vector<std::string>::const_iterator s_iter;
-  for (s_iter = uses_list.begin(); s_iter != uses_list.end(); ++s_iter) {
-    if (s_iter != uses_list.begin()) {
-      f_all << ",";
-      f_all << endl;
-    }
-    indent(f_all) << *s_iter;
-  }
-
-  f_all << ";" << endl << endl;
-
-  indent_down();
-
-  string tmp_unit( unitname );
-  for ( int i = 0; i < (int)tmp_unit.size(); i++) {
-    if ( tmp_unit[i] == '.' ) {
-      tmp_unit.replace( i, 1, "_" );
-    }
-  }
-
-  f_all  << "const"  << endl;
-  indent_up();
-  indent(f_all)  << "c" << tmp_unit << "_Option_AnsiStr_Binary = " << ( ansistr_binary_ ? "True" : "False") << ";" << endl;
-  indent_down();
-
-  f_all  << "type"  << endl;
-  f_all  << s_forward_decr.str();
-  if (has_enum) {
-    indent(f_all) << endl;
-    indent(f_all) << "{$SCOPEDENUMS ON}" << endl << endl;
-    f_all  << s_enum.str();
-    indent(f_all) << "{$SCOPEDENUMS OFF}" << endl << endl;
-  }
-  f_all  << s_struct.str();
-  f_all  << s_service.str();
-  f_all  << s_const.str();
-  f_all  << "implementation"  << endl << endl;
-  f_all  << s_struct_impl.str();
-  f_all  << s_service_impl.str();
-  f_all  << s_const_impl.str();
-  
-  
-  if (register_types_)
-  {
-	  f_all  << endl;
-	  f_all  << "// Type factory methods and registration" << endl;
-	  f_all  << s_type_factory_funcs.str();
-	  f_all << "procedure RegisterTypeFactories;" << endl;
-	  f_all << "begin" << endl;
-	  f_all << s_type_factory_registration.str();	  
-	  f_all << "end;" << endl;
-  }
-  f_all  << endl;
-
-  f_all  << "initialization" << endl;
-  if ( has_const ) {    
-	f_all  << "{$IF CompilerVersion < 21.0}" << endl;
-    f_all  << "  TConstants_Initialize;" << endl;
-	f_all  << "{$IFEND}" << endl;
-  }
-  if (register_types_) {
-	  f_all << "  RegisterTypeFactories;" << endl;
-  }
-  f_all  << endl;
-
-  f_all  << "finalization" << endl;
-  if ( has_const ) {    
-	f_all  << "{$IF CompilerVersion < 21.0}" << endl;
-    f_all  << "  TConstants_Finalize;" << endl;
-	f_all  << "{$IFEND}" << endl;
-  }
-  f_all  << endl << endl;
-  
-  f_all  << "end." << endl;
-  f_all.close();
-  
-  if( ! typedefs_pending.empty()) {
-    pwarning(0, "%d typedefs with unresolved type references left:\n", typedefs_pending.size());
-    for( std::list<t_typedef*>::iterator iter = typedefs_pending.begin();  typedefs_pending.end() != iter;  ++iter) {
-      pwarning(0, "- %s\n", (*iter)->get_symbolic().c_str());
-    }
-  }
-}
-
-void t_delphi_generator::delphi_type_usings( ostream& out) {
-  indent_up();
-  indent(out) << "Classes, SysUtils, Generics.Collections, Thrift.Collections, Thrift.Protocol," << endl;
-  indent(out) << "Thrift.Transport;" << endl << endl;
-  indent_down();
-}
-
-void t_delphi_generator::generate_typedef(t_typedef* ttypedef) {
-  t_type* type = ttypedef->get_type();
-
-  // write now or save for later?  
-  if( ! is_fully_defined_type( type)) {
-    pverbose("typedef %s: unresolved dependencies found\n", type_name(ttypedef).c_str());
-    typedefs_pending.push_back( ttypedef); 
-    return;
-  }
-  
-  indent_up();
-  indent(s_struct) << 
-    type_name(ttypedef) << " = ";
-
-  bool container = type->is_list() || type->is_map() || type->is_set();
-
-  // commented out: the benefit is not big enough to risk breaking existing code
-  //if( ! container)
-  //  s_struct << "type ";  //the "type A = type B" syntax leads to E2574 with generics
-
-  s_struct << type_name(ttypedef->get_type(), ! container) << ";" << endl <<
-    endl;
-  indent_down();
-  
-  add_defined_type( ttypedef);
-}
-
-bool t_delphi_generator::is_fully_defined_type( t_type* ttype) {
-  if( (NULL != ttype->get_program()) && (ttype->get_program() != program_)) {
-    t_scope* scope = ttype->get_program()->scope();
-    if( NULL != scope->get_type( ttype->get_name())) {
-      //printf("type %s found in included scope %s\n", ttype->get_name().c_str(), ttype->get_program()->get_name().c_str());
-      return true;
-    }
-  }
-
-  if (ttype->is_typedef()) {
-    return (1 == types_known[ type_name(ttype)]);
-  }
-  
-  if (ttype->is_base_type()) {
-    return (1 == types_known[ base_type_name((t_base_type*)ttype)]);
-  } else if (ttype->is_enum()) {
-    return true;  // enums are written first, before all other types
-  } else if (ttype->is_map()) {
-    t_map *tmap = (t_map*) ttype;
-    return is_fully_defined_type( tmap->get_key_type()) &&
-           is_fully_defined_type( tmap->get_val_type());
-  } else if (ttype->is_set()) {
-    t_set* tset = (t_set*) ttype;
-    return is_fully_defined_type( tset->get_elem_type());
-  } else if (ttype->is_list()) {
-    t_list* tlist = (t_list*) ttype;
-    return is_fully_defined_type( tlist->get_elem_type());
-  }
-
-  return (1 == types_known[ type_name(ttype)]);
-}
-
-void t_delphi_generator::add_defined_type( t_type* ttype) {
-  // mark as known type
-  types_known[ type_name(ttype)] = 1;
-  
-  // check all pending typedefs
-  std::list<t_typedef*>::iterator  iter;
-  bool more = true;
-  while( more && (! typedefs_pending.empty()))
-  {
-    more = false;
-    
-    for( iter = typedefs_pending.begin(); typedefs_pending.end() != iter; ++iter)
-    {
-      t_typedef* ttypedef = (*iter);
-      if( is_fully_defined_type( ttypedef->get_type()))
-      {      
-        pverbose("typedef %s: all pending references are now resolved\n", type_name(ttypedef).c_str());
-        typedefs_pending.erase( iter);
-        generate_typedef( ttypedef);
-        more = true;
-        break;
-      }
-    }
-  }
-}
-
-void t_delphi_generator::init_known_types_list() {
-  // known base types
-  types_known[ type_name( g_type_string)] = 1;
-  types_known[ type_name( g_type_binary)] = 1;
-  types_known[ type_name( g_type_bool)] = 1;
-  types_known[ type_name( g_type_byte)] = 1;
-  types_known[ type_name( g_type_i16)] = 1;
-  types_known[ type_name( g_type_i32)] = 1;
-  types_known[ type_name( g_type_i64)] = 1;
-  types_known[ type_name( g_type_double)] = 1;
-}
-
-void t_delphi_generator::generate_enum(t_enum* tenum) {
-  has_enum = true;
-  indent_up();
-  indent(s_enum) <<
-    type_name(tenum,true,true) << " = " <<  "("  << endl;
-  indent_up();
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    if (c_iter != constants.begin()) {
-      s_enum << ",";
-      s_enum << endl;
-    }
-    indent(s_enum) << normalize_name((*c_iter)->get_name()) << " = " << value;
-  }
-  s_enum << endl;
-  indent_down();
-  indent(s_enum) << ");" << endl << endl;
-  indent_down();
-}
-
-void t_delphi_generator::generate_consts(std::vector<t_const*> consts) {
-  if (consts.empty()){
-    return;
-  }
-
-  has_const = true;
-
-  indent_up();
-  indent(s_const) <<
-    "TConstants = class" << endl;
-  indent(s_const) << "private" << endl;
-  indent_up();
-  vector<t_const*>::iterator c_iter;
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    print_private_field(s_const, normalize_name((*c_iter)->get_name()),
-      (*c_iter)->get_type(), (*c_iter)->get_value());
-  }
-  indent_down();
-  indent(s_const) << "public" << endl;
-  indent_up();
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    print_const_prop(s_const, normalize_name((*c_iter)->get_name()), 
-      (*c_iter)->get_type(), (*c_iter)->get_value());
-  }
-  indent(s_const) << "{$IF CompilerVersion >= 21.0}" << endl;
-  indent(s_const) << "class constructor Create;" << endl;
-  indent(s_const) << "class destructor Destroy;" << endl;
-  indent(s_const) << "{$IFEND}" << endl;
-  indent_down();
-  indent(s_const) << "end;" << endl << endl;
-  indent_down();
-
-  std::ostringstream  vars, code;
-
-  indent_up_impl();
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    initialize_field(vars, code, "F" + prop_name( (*c_iter)->get_name()),
-      (*c_iter)->get_type(), (*c_iter)->get_value());
-  }
-  indent_down_impl();
-
-  indent_impl(s_const_impl) << "{$IF CompilerVersion >= 21.0}" << endl;
-  indent_impl(s_const_impl) << "class constructor TConstants.Create;" << endl;
-
-  if ( ! vars.str().empty() ) {
-    indent_impl(s_const_impl) << "var" << endl;
-    s_const_impl << vars.str();
-  }
-  indent_impl(s_const_impl) << "begin" << endl;
-  if ( ! code.str().empty() ) {
-    s_const_impl << code.str();
-  }
-  indent_impl(s_const_impl) << "end;" << endl << endl;
-  indent_impl(s_const_impl) << "class destructor TConstants.Destroy;" << endl;
-  indent_impl(s_const_impl) << "begin" << endl;
-  indent_up_impl();
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    finalize_field(s_const_impl, normalize_name( (*c_iter)->get_name()),
-      (*c_iter)->get_type(), (*c_iter)->get_value());
-  }
-  indent_impl(s_const_impl) << "inherited;" << endl;
-  indent_down_impl();
-  indent_impl(s_const_impl) << "end;" << endl;
-  indent_impl(s_const_impl) << "{$ELSE}" << endl;
-
-  vars.str("");
-  code.str("");
-
-  indent_up_impl();
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    initialize_field( vars, code, "TConstants.F" + prop_name( (*c_iter)->get_name()),
-      (*c_iter)->get_type(), (*c_iter)->get_value());
-  }
-  indent_down_impl();
-
-  indent_impl(s_const_impl) << "procedure TConstants_Initialize;" << endl;
-  if ( ! vars.str().empty() ) {
-    indent_impl(s_const_impl) << "var" << endl;
-    s_const_impl << vars.str();
-  }
-  indent_impl(s_const_impl) << "begin" << endl;
-  if ( ! code.str().empty() ) {
-    s_const_impl << code.str();
-  }
-  indent_impl(s_const_impl) << "end;" << endl << endl;
-
-  indent_impl(s_const_impl) << "procedure TConstants_Finalize;" << endl;
-  indent_impl(s_const_impl) << "begin" << endl;
-  indent_up_impl();
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    finalize_field(s_const_impl, normalize_name( (*c_iter)->get_name()),
-      (*c_iter)->get_type(), (*c_iter)->get_value(), "TConstants" );
-  }
-  indent_down_impl();
-  indent_impl(s_const_impl) << "end;" << endl;
-  indent_impl(s_const_impl) << "{$IFEND}" << endl << endl;
-}
-
-void t_delphi_generator::print_const_def_value(std::ostream& vars, std::ostream& out, string name, t_type* type, t_const_value* value, string cls_nm)
-{
-
-  string cls_prefix;
-
-  if (cls_nm == "") {
-    cls_prefix = "";
-  } else {
-    cls_prefix = cls_nm + ".";
-  }
-
-  if (type->is_struct() || type->is_xception()) {
-    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();
-      }
-      string val = render_const_value( vars, out, name, field_type, v_iter->second);
-      indent_impl(out) << cls_prefix << normalize_name(name) << "." << prop_name( v_iter->first->get_string(), type->is_xception()) << " := " << val << ";" << endl;
-    }
-  } 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();
-    map<t_const_value*, t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string key = render_const_value( vars, out, name, ktype, v_iter->first);
-      string val = render_const_value( vars, out, name, vtype, v_iter->second);
-      indent_impl(out) << cls_prefix << normalize_name(name) << "[" << key << "]" << " := " << val << ";" << endl;
-    }
-  } else if (type->is_list() || type->is_set()) {
-    t_type* etype;
-    if (type->is_list()) {
-      etype = ((t_list*)type)->get_elem_type();
-    } else {
-      etype = ((t_set*)type)->get_elem_type();
-    }
-
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string val = render_const_value( vars, out, name, etype, *v_iter);
-      indent_impl(out) << cls_prefix << normalize_name(name) << ".Add(" << val << ");" << endl;
-    }
-  }
-}
-
-void t_delphi_generator::print_private_field(std::ostream& out, string name, t_type* type, t_const_value* value) {
-  (void) value;
-  indent(out) << "class var F" << name << ": " << type_name(type) << ";" << endl;
-}
-
-void t_delphi_generator::print_const_prop(std::ostream& out, string name, t_type* type, t_const_value* value) {
-  (void) value;
-  indent(out) << "class property " << name << ": " << type_name(type) << " read F" << name << ";" << endl;
-}
-
-void t_delphi_generator::print_const_value( std::ostream& vars, std::ostream& out, string name, t_type* type, t_const_value* value) {
-  t_type* truetype = type;
-  while (truetype->is_typedef()) {
-    truetype = ((t_typedef*)truetype)->get_type();
-  }
-
-  if (truetype->is_base_type()) {
-    string v2 = render_const_value( vars, out, name, type, value);
-    indent_impl(out) << name << " := " << v2 << ";" << endl;
-  } else if (truetype->is_enum()) {
-    indent_impl(out) << name << " := " << type_name(type) << "." << value->get_identifier_name() << ";" << endl;
-  } else {
-    string typname;
-    typname = type_name( type, true, false, type->is_xception(), type->is_xception());
-    indent_impl(out) << name << " := " << typname << ".Create;" << endl;
-    print_const_def_value( vars, out, name, type, value);
-  }
-}
-
-void t_delphi_generator::initialize_field(std::ostream& vars, std::ostream& out, string name, t_type* type, t_const_value* value) {
-  print_const_value( vars, out, name, type, value );
-}
-
-void t_delphi_generator::finalize_field(std::ostream& out, string name, t_type* type, t_const_value* value , string cls_nm) {
-  (void) out;
-  (void) name;
-  (void) type;
-  (void) value;
-  (void) cls_nm;
-}
-
-string t_delphi_generator::render_const_value(ostream& vars, ostream& out, string name, t_type* type, t_const_value* value) {
-  (void) name;
-
-  t_type* truetype = type;
-  while (truetype->is_typedef()) {
-    truetype = ((t_typedef*)truetype)->get_type();
-  }
-
-  std::ostringstream render;
-
-  if (truetype->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type*)truetype)->get_base();
-    switch (tbase) {
-      case t_base_type::TYPE_STRING:
-        render << "'" << get_escaped_string(value) << "'";
-        break;
-      case t_base_type::TYPE_BOOL:
-        render << ((value->get_integer() > 0) ? "True" : "False");
-        break;
-      case t_base_type::TYPE_BYTE:
-        render << "ShortInt( " << value->get_integer() << ")";
-        break;
-      case t_base_type::TYPE_I16:
-        render << "SmallInt( " << value->get_integer() << ")";
-        break;
-      case t_base_type::TYPE_I32:
-        render << "LongInt( " << value->get_integer() << ")";
-        break;
-      case t_base_type::TYPE_I64:
-        render << "Int64( " << value->get_integer() << ")";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        if (value->get_type() == t_const_value::CV_INTEGER) {
-          render << value->get_integer();
-        } else {
-          render << value->get_double();
-        }
-        break;
-      default:
-          render << "";
-    }
-  } else if (truetype->is_enum()) {
-    render << type_name( type, false) << "." << value->get_identifier_name();
-  } else {
-    string t = tmp("tmp");
-    vars <<  "  " << t << " : " << type_name(type) << ";" << endl;
-    print_const_value( vars, out, t, type, value);
-    render << t;
-  }
-
-  return render.str();
-}
-
-void t_delphi_generator::generate_struct(t_struct* tstruct) {
-  generate_delphi_struct(tstruct, false);
-}
-
-void t_delphi_generator::generate_xception(t_struct* txception) {
-  generate_delphi_struct(txception, true);
-}
-
-void t_delphi_generator::generate_delphi_struct(t_struct* tstruct, bool is_exception) {
-  indent_up();
-  generate_delphi_struct_definition(s_struct, tstruct, is_exception);
-  indent_down();
-  
-  add_defined_type( tstruct);
-
-  generate_delphi_struct_impl(s_struct_impl, "", tstruct, is_exception);
-  if (register_types_) {
-	generate_delphi_struct_type_factory(s_type_factory_funcs, "", tstruct, is_exception);
-	generate_delphi_struct_type_factory_registration(s_type_factory_registration, "", tstruct, is_exception);
-  }
-}
-
-void t_delphi_generator::generate_delphi_struct_impl( ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result, bool is_x_factory) {
-
-  if (is_exception &&  (! is_x_factory)) {
-    generate_delphi_struct_impl( out,  cls_prefix, tstruct, is_exception, is_result, true);
-  }
-
-  string cls_nm;
-
-  string exception_factory_name;
-
-  if (is_exception) {
-    exception_factory_name = normalize_clsnm( tstruct->get_name(), "", true ) + "Factory";
-  }
-
-  if (is_exception) {
-    cls_nm = type_name(tstruct,true,(! is_x_factory),is_x_factory,true);
-  }
-  else {
-    cls_nm = type_name(tstruct,true,false);
-  }
-
-  std::ostringstream vars, code;
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  indent_up_impl();
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* t = (*m_iter)->get_type();
-    while (t->is_typedef()) {
-      t = ((t_typedef*)t)->get_type();
-    }
-    if ((*m_iter)->get_value() != NULL) {
-      initialize_field( vars, code, "F" + prop_name( (*m_iter)->get_name(), is_exception), t, (*m_iter)->get_value());
-      if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
-        indent_impl(code) << "F__isset_" << prop_name((*m_iter), is_exception) << " := True;" << endl;
-      }
-    }
-  }
-  indent_down_impl();
-
-  indent_impl(out) << "constructor " << cls_prefix << cls_nm <<  "." << "Create;" << endl;
-
-  if ( ! vars.str().empty()) {
-    out << "var" << endl;
-    out << vars.str();
-  }
-
-  indent_impl(out) << "begin" << endl;
-  indent_up_impl();
-  if (is_exception && (! is_x_factory)) {
-    indent_impl(out) << "inherited Create('');" << endl;
-    indent_impl(out) << "F" << exception_factory_name << " := T" << exception_factory_name << "Impl.Create;" << endl;
-  } else {
-    indent_impl(out) << "inherited;" << endl;
-  }
-
-  if ( ! code.str().empty()) {
-    out << code.str();
-  }
-
-  indent_down_impl();
-  indent_impl(out) << "end;" << endl << endl;
-
-  if ((members.size() > 0) && is_exception && (!is_x_factory)) {
-    indent_impl(out) << "constructor " << cls_prefix << cls_nm <<  "." << "Create(" << constructor_argument_list( tstruct, indent_impl()) << ");" << endl;
-    indent_impl(out) << "begin" << endl;
-    indent_up_impl();
-    indent_impl(out) << "Create;" << endl;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      string propname = prop_name((*m_iter)->get_name(), is_exception);
-      string param_name = constructor_param_name( (*m_iter)->get_name());
-      indent_impl(out) << propname << " := " << param_name << ";" << endl;
-    }
-    indent_impl(out) << "UpdateMessageProperty;" << endl;
-    indent_down_impl();
-    indent_impl(out) << "end;" << endl << endl;
-  }
-
-  indent_impl(out) << "destructor "  << cls_prefix << cls_nm <<  "." << "Destroy;" << endl;
-  indent_impl(out) << "begin" << endl;
-  indent_up_impl();
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* t = (*m_iter)->get_type();
-    while (t->is_typedef()) {
-      t = ((t_typedef*)t)->get_type();
-    }
-    finalize_field( out, prop_name(*m_iter, is_exception), t, (*m_iter)->get_value());
-  }
-
-  indent_impl(out) << "inherited;" << endl;
-  indent_down_impl();
-  indent_impl(out) << "end;" << endl << endl;
-
-  if ( tstruct->is_union() ) {
-    indent_impl(out) << "procedure "  << cls_prefix << cls_nm <<  "." << "ClearUnionValues;" << endl;
-    indent_impl(out) << "begin" << endl;
-    indent_up_impl();
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      t_type* t = (*m_iter)->get_type();
-      while (t->is_typedef()) {
-        t = ((t_typedef*)t)->get_type();
-      }
-
-      generate_delphi_clear_union_value( out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception, tstruct->is_union(), is_x_factory, exception_factory_name);
-    }
-    indent_down_impl();
-    indent_impl(out) << "end;" << endl << endl;
-  }
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* t = (*m_iter)->get_type();
-    while (t->is_typedef()) {
-      t = ((t_typedef*)t)->get_type();
-    }
-    generate_delphi_property_reader_impl( out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception);
-    generate_delphi_property_writer_impl( out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception, tstruct->is_union(), is_x_factory, exception_factory_name);
-    if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
-      generate_delphi_isset_reader_impl( out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception);
-    }
-  }
-
-  if ((! is_exception) || is_x_factory) {
-    generate_delphi_struct_reader_impl( out, cls_prefix, tstruct, is_exception);
-    if ( is_result ) {
-      generate_delphi_struct_result_writer_impl( out, cls_prefix, tstruct, is_exception);
-    } else {
-      generate_delphi_struct_writer_impl( out, cls_prefix, tstruct, is_exception);
-    }
-  }
-  generate_delphi_struct_tostring_impl( out, cls_prefix, tstruct, is_exception, is_x_factory);
-
-  if (is_exception && is_x_factory) {
-    generate_delphi_create_exception_impl( out, cls_prefix, tstruct, is_exception);
-  }
-}
-
-void t_delphi_generator::print_delphi_struct_type_factory_func(  ostream& out, t_struct* tstruct) {
-	string struct_intf_name = type_name(tstruct);
-	out << "Create_";
-	out << struct_intf_name;
-	out << "_Impl";
-}
-
-
-void t_delphi_generator::generate_delphi_struct_type_factory( ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result, bool is_x_factory) {
-	
-	if (is_exception)
-		return;
-	if (is_result)
-		return;
-	if (is_x_factory)
-		return;
-
-	string struct_intf_name = type_name(tstruct);
-	string cls_nm = type_name(tstruct,true,false);
-
-	out << "function ";
-	print_delphi_struct_type_factory_func(out, tstruct);
-	out << ": ";
-	out << struct_intf_name;
-	out << ";" << endl;
-	out << "begin" << endl;
-	indent_up();
-	indent(out) << "Result := " << cls_nm << ".Create;" << endl;
-	indent_down();
-	out << "end;" << endl << endl;
-}
-
-void t_delphi_generator::generate_delphi_struct_type_factory_registration( ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result, bool is_x_factory) {
-	if (is_exception)
-		return;
-	if (is_result)
-		return;
-	if (is_x_factory)
-		return;
-
-	string struct_intf_name = type_name(tstruct);
-
-	indent(out) << "  TypeRegistry.RegisterTypeFactory<" << struct_intf_name << ">(";
-	print_delphi_struct_type_factory_func(out, tstruct);
-	out << ");";
-	out << endl;
-}
-
-void t_delphi_generator::generate_delphi_struct_definition(ostream &out, t_struct* tstruct, bool is_exception, bool in_class, bool is_result, bool is_x_factory) {
-  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
-  string struct_intf_name;
-  string struct_name;
-  string isset_name; 
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  string exception_factory_name = normalize_clsnm( tstruct->get_name(), "", true ) + "Factory";
-
-  if (is_exception) {
-    struct_intf_name = type_name(tstruct,false,false,true);
-  }
-  else {
-    struct_intf_name = type_name(tstruct);
-  }
-
-
-  if (is_exception) {
-    struct_name = type_name(tstruct, true, (! is_x_factory), is_x_factory);
-  }
-  else {
-    struct_name = type_name(tstruct,true);
-  }
-
-  if ((! is_exception) || is_x_factory) {
-
-    indent(out) << struct_intf_name << " = interface(IBase)" << endl;
-    indent_up();
-
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      generate_delphi_property_reader_definition( out, *m_iter, is_exception);
-      generate_delphi_property_writer_definition( out, *m_iter, is_exception);
-    }
-
-    if (is_x_factory) {
-      out << endl;
-      indent(out) << "// Create Exception Object" << endl;
-      indent(out) << "function CreateException: " << type_name(tstruct,true,true) << ";" << endl;
-    }
-
-    if (members.size() > 0) {
-      out << endl;
-      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-        generate_property(out, *m_iter, true, is_exception);
-      }
-    }
-
-    if (members.size() > 0) {
-      out << endl;
-      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-        if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
-          generate_delphi_isset_reader_definition( out, *m_iter, is_exception);
-        }
-      }
-    }
-
-    if (members.size() > 0) {
-      out << endl;
-      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-        if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
-          isset_name = "__isset_" + prop_name(*m_iter, is_exception);
-          indent(out) << "property " << isset_name << ": Boolean read Get" << isset_name << ";" << endl;
-        }
-      }
-    }
-
-    indent_down();
-    indent(out) << "end;" << endl << endl;
-  }
-
-  indent(out) << struct_name << " = ";
-  if (is_final) {
-    out << "sealed ";
-  }
-  out << "class(";
-  if ( is_exception && (! is_x_factory)) {
-    out << "TException";
-  } else {
-    out << "TInterfacedObject, IBase, " << struct_intf_name;
-  }
-  out << ")" << endl;
-
-  if (is_exception && (! is_x_factory)) {
-    indent(out) << "public" << endl;
-    indent_up();
-    indent(out) << "type" << endl;
-    indent_up();
-    generate_delphi_struct_definition( out, tstruct, is_exception, in_class, is_result, true);
-    indent_down();
-    indent_down();
-  }
-
-  indent(out) << "private" << endl;
-  indent_up();
-
-  if (is_exception && (! is_x_factory)) {
-    indent(out) << "F" << exception_factory_name << " :" << struct_intf_name << ";" << endl << endl;
-  }
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    indent(out) << declare_field(*m_iter, false, "F", is_exception) << endl;
-  }
-
-  if (members.size() > 0) {
-    indent(out) << endl;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
-        isset_name = "F__isset_" + prop_name(*m_iter, is_exception);
-        indent(out) << isset_name << ": Boolean;" << endl;
-      }
-    }
-  }
-
-  indent(out) << endl;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    generate_delphi_property_reader_definition( out, *m_iter, is_exception);
-    generate_delphi_property_writer_definition( out, *m_iter, is_exception);
-  }
-
-  if (tstruct->is_union()) {
-    out << endl;
-    indent(out) << "// Clear values(for union's property setter)" << endl;
-    indent(out) << "procedure ClearUnionValues;" << endl;
-  }
-
-  if (members.size() > 0) {
-    out << endl;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
-        isset_name = "__isset_" + prop_name(*m_iter, is_exception);
-        indent(out) << "function Get" << isset_name << ": Boolean;" << endl;
-      }
-    }
-  }
-
-  indent_down();
-
-  indent(out) << "public" << endl;
-  indent_up();
-
-  if ((members.size() > 0) && is_exception && (! is_x_factory)) {
-    indent(out) << "constructor Create; overload;" << endl;
-    indent(out) << "constructor Create(" << constructor_argument_list( tstruct, indent()) << "); overload;" << endl;
-  } else {
-    indent(out) << "constructor Create;" << endl;
-  }
-
-  indent(out) << "destructor Destroy; override;" << endl;
-
-  out  << endl;
-  indent(out) << "function ToString: string; override;" << endl;
-
-  if (is_exception && (! is_x_factory)) {
-    out  << endl;
-    indent(out) << "// Exception Factory" << endl;
-    indent(out) << "property " << exception_factory_name << ": " << struct_intf_name << " read F" << exception_factory_name << " write F" << exception_factory_name << ";" << endl;
-  }
-
-  if ((! is_exception) || is_x_factory) {
-    out  << endl;
-    indent(out) << "// IBase" << endl;
-    indent(out) << "procedure Read( const iprot: IProtocol);" << endl;
-    indent(out) << "procedure Write( const oprot: IProtocol);" << endl;
-  }
-
-  if (is_exception && is_x_factory) {
-    out  << endl;
-    indent(out) << "// Create Exception Object" << endl;
-    indent(out) << "function CreateException: " << type_name(tstruct,true,true) << ";" << endl;
-  }
-
-  if (members.size() > 0) {
-    out << endl;
-    indent(out) << "// Properties" << endl;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      generate_property(out, *m_iter, true, is_exception);
-    }
-  }
-
-  if (members.size() > 0) {
-    out << endl;
-    indent(out) << "// isset" << endl;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
-        isset_name = "__isset_" + prop_name(*m_iter, is_exception);
-        indent(out) << "property " << isset_name << ": Boolean read Get" << isset_name << ";" << endl;
-      }
-    }
-  }
-
-  indent_down();
-  indent(out) << "end;" << endl << endl;
-}
-
-void t_delphi_generator::generate_service(t_service* tservice) {
-  indent_up();
-  indent(s_service) << normalize_clsnm(service_name_, "T") << " = class" << endl;
-  indent(s_service) << "public" << endl;
-  indent_up();
-  indent(s_service) << "type" << endl;
-  generate_service_interface(tservice);
-  generate_service_client(tservice);
-  generate_service_server(tservice);
-  generate_service_helpers(tservice);
-  indent_down();
-  indent_down();
-  indent(s_service) << "end;" << endl;
-  indent(s_service) << endl;
-  indent_down();
-}
-
-void t_delphi_generator::generate_service_interface(t_service* tservice) {
-  string extends = "";
-  string extends_iface = "";
-
-  indent_up();
-
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends(), true, true);
-    extends_iface = extends + ".Iface";
-    indent(s_service) <<
-      "Iface = interface(" << extends_iface << ")" << endl;
-  } else {
-    indent(s_service) <<
-      "Iface = interface" << endl;
-  }
-
-  indent_up();
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
-  {
-    indent(s_service) <<
-      function_signature(*f_iter) << endl;
-  }
-  indent_down();
-  indent(s_service) << "end;" << endl << endl;
-
-  indent_down();
-}
-
-void t_delphi_generator::generate_service_helpers(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    t_struct* ts = (*f_iter)->get_arglist();
-    generate_delphi_struct_definition(s_service, ts, false, true);
-    generate_delphi_struct_impl(s_service_impl, normalize_clsnm( service_name_, "T") + ".", ts, false);
-    generate_function_helpers(*f_iter);
-  }
-}
-
-void t_delphi_generator::generate_service_client(t_service* tservice) {
-  indent_up();
-  string extends = "";
-  string extends_client = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_client = extends + ".Client, ";
-  }
-
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends(), true, true);
-    extends_client = extends + ".TClient";
-    indent(s_service) <<
-      "TClient = class(" << extends_client << ", Iface)" << endl;
-  } else {
-    indent(s_service) <<
-      "TClient = class( TInterfacedObject, Iface)" << endl;
-  }
-
-  indent(s_service) << "public" << endl;
-  indent_up();
-
-  indent(s_service) << "constructor Create( prot: IProtocol); overload;" << endl;
-
-  indent_impl(s_service_impl) <<  "constructor " << normalize_clsnm( service_name_, "T") << ".TClient.Create( prot: IProtocol);" << endl;
-  indent_impl(s_service_impl) <<  "begin" << endl;
-  indent_up_impl();
-  indent_impl(s_service_impl) << "Create( prot, prot );" << endl;    
-  indent_down_impl();
-  indent_impl(s_service_impl) <<  "end;" << endl << endl;
-
-  indent(s_service) << "constructor Create( const iprot: IProtocol; const oprot: IProtocol); overload;" << endl;
-
-  indent_impl(s_service_impl) <<  
-    "constructor " << normalize_clsnm( service_name_, "T") << 
-    ".TClient.Create( const iprot: IProtocol; const oprot: IProtocol);" << endl;
-  indent_impl(s_service_impl) <<  "begin" << endl;
-  indent_up_impl();
-  indent_impl(s_service_impl) << "iprot_ := iprot;" << endl;    
-  indent_impl(s_service_impl) << "oprot_ := oprot;" << endl;    
-  indent_down_impl();
-  indent_impl(s_service_impl) <<  "end;" << endl << endl;
-
-  indent_down();
-
-  if (extends.empty()) {
-    indent(s_service) << "protected" << endl;
-    indent_up();
-    indent(s_service) << "iprot_: IProtocol;" << endl;
-    indent(s_service) << "oprot_: IProtocol;" << endl;
-    indent(s_service) << "seqid_: Integer;" << endl;
-    indent_down();
-
-    indent(s_service) << "public" << endl;
-    indent_up();
-    indent(s_service) << "property InputProtocol: IProtocol read iprot_;" << endl;
-    indent(s_service) << "property OutputProtocol: IProtocol read oprot_;" << endl;
-    indent_down();
-  }
-
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::const_iterator f_iter;
-
-  indent(s_service) << "protected" << endl;
-  indent_up();
-  indent(s_service) << "// Iface" << endl;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    string funname = (*f_iter)->get_name();
-    indent(s_service) << function_signature(*f_iter) << endl;
-  }
-  indent_down();
-
-  indent(s_service) << "public" << endl;
-  indent_up();
-
-  string full_cls = normalize_clsnm(service_name_,"T") + ".TClient";
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    string funname = (*f_iter)->get_name();
-
-    indent_impl(s_service_impl) << function_signature(*f_iter, full_cls) << endl;
-    indent_impl(s_service_impl) << "begin" << endl;
-    indent_up_impl();
-    indent_impl(s_service_impl) << "send_" << funname << "(";
-
-    t_struct* arg_struct = (*f_iter)->get_arglist();
-
-    const vector<t_field*>& fields = arg_struct->get_members();
-    vector<t_field*>::const_iterator fld_iter;
-    bool first = true;
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      if (first) {
-        first = false;
-      } else {
-        s_service_impl << ", ";
-      }
-      s_service_impl << normalize_name( (*fld_iter)->get_name());
-    }
-    s_service_impl << ");" << endl;
-
-    if (!(*f_iter)->is_oneway()) {
-      s_service_impl << indent_impl();
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        s_service_impl << "Result := ";
-      }
-      s_service_impl <<
-        "recv_" << funname << "();" << endl;
-    }
-
-    indent_down_impl();
-    indent_impl(s_service_impl) << "end;" << endl << endl;
-
-    t_function send_function(g_type_void,
-        string("send_") + (*f_iter)->get_name(),
-        (*f_iter)->get_arglist());
-
-    string argsname =  (*f_iter)->get_name() + "_args";
-    string args_clsnm = normalize_clsnm( argsname, "T");
-    string args_intfnm= normalize_clsnm( argsname, "I");
-
-    indent(s_service) << function_signature(&send_function) << endl;
-    indent_impl(s_service_impl) << function_signature(&send_function, full_cls) << endl;
-    indent_impl(s_service_impl) << "var" << endl;
-    indent_up_impl();
-    indent_impl(s_service_impl) << "args : " << args_intfnm << ";" << endl;
-    indent_impl(s_service_impl) << "msg : IMessage;" << endl;
-    indent_down_impl();
-    indent_impl(s_service_impl) << "begin" << endl;
-    indent_up_impl();
-
-    indent_impl(s_service_impl) <<
-      "seqid_ := seqid_ + 1;" << endl;
-    indent_impl(s_service_impl) <<
-      "msg := TMessageImpl.Create('" << funname << "', TMessageType.Call, seqid_);" << endl;
-
-    indent_impl(s_service_impl) <<
-      "oprot_.WriteMessageBegin( msg );" << endl;
-    indent_impl(s_service_impl) <<
-      "args := " << args_clsnm << "Impl.Create();" << endl;
-
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      indent_impl(s_service_impl) <<
-        "args." << prop_name(*fld_iter) << " := " << normalize_name( (*fld_iter)->get_name()) << ";" << endl;
-    }
-    indent_impl(s_service_impl) << "args.Write(oprot_);" << endl;
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      indent_impl(s_service_impl) <<
-        "args." << prop_name(*fld_iter) << " := " << empty_value((*fld_iter)->get_type()) << ";" << endl;
-    }
-
-    indent_impl(s_service_impl) << "oprot_.WriteMessageEnd();" << endl;
-    indent_impl(s_service_impl) << "oprot_.Transport.Flush();" << endl;
-
-    indent_down_impl();
-    indent_impl(s_service_impl) << "end;" << endl << endl;
-
-    if (!(*f_iter)->is_oneway()) {
-      string org_resultname = (*f_iter)->get_name() + "_result" ;
-      string result_clsnm = normalize_clsnm( org_resultname, "T");
-      string result_intfnm = normalize_clsnm( org_resultname, "I");
-
-      t_struct noargs(program_);
-      t_function recv_function((*f_iter)->get_returntype(),
-          string("recv_") + (*f_iter)->get_name(),
-          &noargs,
-          (*f_iter)->get_xceptions());
-
-      t_struct *xs = (*f_iter)->get_xceptions();
-      const std::vector<t_field*>& xceptions = xs->get_members();
-
-      indent(s_service) << function_signature(&recv_function) << endl;
-      indent_impl(s_service_impl) << function_signature(&recv_function, full_cls) << endl;
-      indent_impl(s_service_impl) << "var" << endl;
-      indent_up_impl();
-      indent_impl(s_service_impl) << "msg : IMessage;" << endl;
-      if ( xceptions.size() > 0) {
-        indent_impl(s_service_impl) << "ex : Exception;" << endl;
-      }
-      indent_impl(s_service_impl) << "x : TApplicationException;" << endl;
-      indent_impl(s_service_impl) << "ret : " << result_intfnm << ";" << endl;
-
-      indent_down_impl();
-      indent_impl(s_service_impl) << "begin" << endl;
-      indent_up_impl();
-      indent_impl(s_service_impl) << "msg := iprot_.ReadMessageBegin();" << endl;
-      indent_impl(s_service_impl) << "if (msg.Type_ = TMessageType.Exception) then" << endl;
-      indent_impl(s_service_impl) << "begin" << endl;
-      indent_up_impl();
-      indent_impl(s_service_impl) << "x := TApplicationException.Read(iprot_);" << endl;
-      indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << endl;
-      indent_impl(s_service_impl) << "raise x;" << endl;
-      indent_down_impl();
-      indent_impl(s_service_impl) << "end;" << endl;
-
-      indent_impl(s_service_impl) << "ret := " << result_clsnm << "Impl.Create();" << endl;
-      indent_impl(s_service_impl) << "ret.Read(iprot_);" << endl;
-      indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << endl;
-
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        indent_impl(s_service_impl) << "if (ret.__isset_success) then" << endl;
-        indent_impl(s_service_impl) << "begin" << endl;
-        indent_up_impl();
-        indent_impl(s_service_impl) << "Result := ret.Success;" << endl;
-        t_type *type = (*f_iter)->get_returntype();
-        if (type->is_struct() || type->is_xception() || type->is_map() || type->is_list() || type->is_set()) {
-          indent_impl(s_service_impl) << "ret.Success := nil;" << endl;
-        }
-        indent_impl(s_service_impl) << "Exit;" << endl;
-        indent_down_impl();
-        indent_impl(s_service_impl) << "end;" << endl;
-      }
-
-      vector<t_field*>::const_iterator x_iter;
-      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-        indent_impl(s_service_impl) << "if (ret.__isset_" << prop_name(*x_iter) << ") then" << endl;
-        indent_impl(s_service_impl) << "begin" << endl;
-        indent_up_impl();
-        indent_impl(s_service_impl) << "ex := ret." << prop_name(*x_iter) << ".CreateException;" << endl;
-        indent_impl(s_service_impl) << "raise ex;" << endl;
-        indent_down_impl();
-        indent_impl(s_service_impl) << "end;" << endl;
-      }
-
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        indent_impl(s_service_impl) << 
-          "raise TApplicationException.Create(TApplicationException.TExceptionType.MissingResult, '" << (*f_iter)->get_name() << " failed: unknown result');" << endl;
-      }
-
-      indent_down_impl();
-      indent_impl(s_service_impl) << "end;" << endl << endl;
-    }
-  }
-
-  indent_down();
-  indent(s_service) << "end;" << endl << endl;
-}
-
-void t_delphi_generator::generate_service_server(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  string extends = "";
-  string extends_processor = "";
-
-  string full_cls = normalize_clsnm( service_name_, "T") + ".TProcessorImpl";
-
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends(), true, true);
-    extends_processor = extends + ".TProcessorImpl";
-    indent(s_service) <<
-      "TProcessorImpl = class(" << extends_processor << ", IProcessor)" << endl;
-  } else {
-    indent(s_service) <<
-      "TProcessorImpl = class( TInterfacedObject, IProcessor)" << endl;
-  }
-
-  indent(s_service) << "public" << endl;
-  indent_up();
-  indent(s_service) << "constructor Create( iface_: Iface );" << endl;
-  indent(s_service) << "destructor Destroy; override;" << endl;
-  indent_down();
-
-  indent_impl(s_service_impl) << "constructor " << full_cls << ".Create( iface_: Iface );" << endl;
-  indent_impl(s_service_impl) << "begin" << endl;
-  indent_up_impl();
-  if (tservice->get_extends() != NULL)
-  {
-    indent_impl(s_service_impl) << "inherited Create( iface_);" << endl;
-  } else {
-    indent_impl(s_service_impl) << "inherited Create;" << endl;
-  }
-  indent_impl(s_service_impl) << "Self.iface_ := iface_;" << endl;
-  if (tservice->get_extends() != NULL)
-  {
-    indent_impl(s_service_impl) << "ASSERT( processMap_ <> nil);  // inherited" << endl;
-  } else {
-    indent_impl(s_service_impl) << "processMap_ := TThriftDictionaryImpl<string, TProcessFunction>.Create;" << endl;
-  }
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    indent_impl(s_service_impl) << 
-      "processMap_.AddOrSetValue( '" << (*f_iter)->get_name() << "', " << (*f_iter)->get_name() << "_Process);" << endl;
-  }
-  indent_down_impl();
-  indent_impl(s_service_impl) << "end;" << endl << endl;
-
-  indent_impl(s_service_impl) << "destructor " << full_cls << ".Destroy;" << endl;
-  indent_impl(s_service_impl) << "begin" << endl;
-  indent_up_impl();
-  indent_impl(s_service_impl) << "inherited;" << endl;
-  indent_down_impl();
-  indent_impl(s_service_impl) << "end;" << endl << endl;
-
-  indent(s_service) << "private" << endl;
-  indent_up();
-  indent(s_service) << "iface_: Iface;" << endl;
-  indent_down();
-
-  if (tservice->get_extends() == NULL)
-  {
-    indent(s_service) << "protected" << endl;
-    indent_up();
-    indent(s_service) << "type" << endl;
-    indent_up();
-    indent(s_service) << "TProcessFunction = reference to procedure( seqid: Integer; const iprot: IProtocol; const oprot: IProtocol);" << endl;
-    indent_down();
-    indent_down();
-    indent(s_service) << "protected" << endl;
-    indent_up();
-    indent(s_service) << "processMap_: IThriftDictionary<string, TProcessFunction>;" << endl;
-    indent_down();
-  }
-
-  indent(s_service) << "public" << endl;
-  indent_up();
-  if (extends.empty()) {
-    indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol): Boolean;" << endl;
-  } else {
-    indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol): Boolean; reintroduce;" << endl;
-  }
-
-  indent_impl(s_service_impl) << "function " << full_cls << ".Process( const iprot: IProtocol; const oprot: IProtocol): Boolean;" << endl;;
-  indent_impl(s_service_impl) << "var" << endl;
-  indent_up_impl();
-  indent_impl(s_service_impl) << "msg : IMessage;" << endl;
-  indent_impl(s_service_impl) << "fn : TProcessFunction;" << endl;
-  indent_impl(s_service_impl) << "x : TApplicationException;" << endl;
-  indent_down_impl();
-  indent_impl(s_service_impl) << "begin" << endl;
-  indent_up_impl();
-  indent_impl(s_service_impl) << "try" << endl;
-  indent_up_impl();
-  indent_impl(s_service_impl) << "msg := iprot.ReadMessageBegin();" << endl;
-  indent_impl(s_service_impl) << "fn := nil;" << endl;
-  indent_impl(s_service_impl) << "if not processMap_.TryGetValue(msg.Name, fn)" << endl;
-  indent_impl(s_service_impl) << "or not Assigned(fn) then" << endl;
-  indent_impl(s_service_impl) << "begin" << endl;
-  indent_up_impl();
-  indent_impl(s_service_impl) << "TProtocolUtil.Skip(iprot, TType.Struct);" << endl;
-  indent_impl(s_service_impl) << "iprot.ReadMessageEnd();" << endl;
-  indent_impl(s_service_impl) << "x := TApplicationException.Create(TApplicationException.TExceptionType.UnknownMethod, 'Invalid method name: ''' + msg.Name + '''');" << endl;
-  indent_impl(s_service_impl) << "msg := TMessageImpl.Create(msg.Name, TMessageType.Exception, msg.SeqID);" << endl;
-  indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg);" << endl;
-  indent_impl(s_service_impl) << "x.Write(oprot);" << endl;
-  indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl;
-  indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl;
-  indent_impl(s_service_impl) << "Result := True;" << endl;
-  indent_impl(s_service_impl) << "Exit;" << endl;
-  indent_down_impl();
-  indent_impl(s_service_impl) << "end;" << endl;
-  indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot);" << endl;
-  indent_down_impl();
-  indent_impl(s_service_impl) << "except" << endl;
-  indent_up_impl();
-  indent_impl(s_service_impl) << "Result := False;" << endl;
-  indent_impl(s_service_impl) << "Exit;" << endl;
-  indent_down_impl();
-  indent_impl(s_service_impl) << "end;" << endl;
-  indent_impl(s_service_impl) << "Result := True;" << endl;
-  indent_down_impl();
-  indent_impl(s_service_impl) << "end;" << endl << endl;
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
-  {
-    generate_process_function(tservice, *f_iter);
-  }
-
-  indent_down();
-  indent(s_service) << "end;" << endl << endl;
-
-}
-
-void t_delphi_generator::generate_function_helpers(t_function* tfunction) {
-  if (tfunction->is_oneway()) {
-    return;
-  }
-
-  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_delphi_struct_definition(s_service, &result, false, true, true);
-  generate_delphi_struct_impl(s_service_impl, normalize_clsnm( service_name_, "T") + ".", &result, false);
-}
-
-void t_delphi_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
-  (void) tservice;
-  string funcname = tfunction->get_name();
-  string full_cls = normalize_clsnm( service_name_, "T") + ".TProcessorImpl";
-
-  string org_argsname  = funcname + "_args";
-  string args_clsnm = normalize_clsnm(org_argsname, "T");
-  string args_intfnm = normalize_clsnm(org_argsname, "I");
-
-  string org_resultname = funcname + "_result";
-  string result_clsnm = normalize_clsnm(org_resultname, "T");
-  string result_intfnm = normalize_clsnm(org_resultname, "I");
-
-  indent(s_service) <<
-    "procedure " << funcname << "_Process( seqid: Integer; const iprot: IProtocol; const oprot: IProtocol);" << endl;
-
-  if (tfunction->is_oneway()) {
-    indent_impl(s_service_impl) << "// one way processor" << endl;
-  } else {
-    indent_impl(s_service_impl) << "// both way processor" << endl;
-  }
-
-  indent_impl(s_service_impl) <<
-    "procedure " << full_cls << "." << funcname << "_Process( seqid: Integer; const iprot: IProtocol; const oprot: IProtocol);" << endl;
-  indent_impl(s_service_impl) << "var" << endl;
-  indent_up_impl();
-  indent_impl(s_service_impl) << "args: " << args_intfnm << ";" << endl;
-  if (!tfunction->is_oneway()) {
-    indent_impl(s_service_impl) << "msg: IMessage;" << endl;
-    indent_impl(s_service_impl) << "ret: " << result_intfnm << ";" << endl;
-  }
-
-  indent_down_impl();
-  indent_impl(s_service_impl) << "begin" << endl;
-  indent_up_impl();
-  indent_impl(s_service_impl) << "args := " << args_clsnm << "Impl.Create;" << endl;
-  indent_impl(s_service_impl) << "args.Read(iprot);" << endl;
-  indent_impl(s_service_impl) << "iprot.ReadMessageEnd();" << endl;
-
-  t_struct* xs = tfunction->get_xceptions();
-  const std::vector<t_field*>& xceptions = xs->get_members();
-  vector<t_field*>::const_iterator x_iter;
-
-  if (!tfunction->is_oneway()) {
-    indent_impl(s_service_impl) << "ret := " << result_clsnm << "Impl.Create;" << endl;
-  }
-
-  if (!tfunction->is_oneway() && xceptions.size() > 0) {
-    indent_impl(s_service_impl) << "try" << endl;
-    indent_up_impl();
-  }
-
-  t_struct* arg_struct = tfunction->get_arglist();
-  const std::vector<t_field*>& fields = arg_struct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  s_service_impl << indent_impl();
-  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
-    s_service_impl << "ret.Success := ";
-  }
-  s_service_impl <<  "iface_." << normalize_name( tfunction->get_name(), true) << "(";
-  bool first = true;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (first) {
-      first = false;
-    } else {
-      s_service_impl << ", ";
-    }
-    s_service_impl << "args." << prop_name(*f_iter);
-  }
-  s_service_impl << ");" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    indent_impl(s_service_impl) <<
-      "args." << prop_name(*f_iter) << " := " << empty_value((*f_iter)->get_type()) << ";" << endl;
-  }
-
-  if (!tfunction->is_oneway() && xceptions.size() > 0) {
-    indent_down_impl();
-    indent_impl(s_service_impl) << "except" << endl;
-    indent_up_impl();
-    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      indent_impl(s_service_impl) << "on E: " << type_name((*x_iter)->get_type(),true,true) << " do" << endl;
-      indent_impl(s_service_impl) << "begin" << endl;
-      indent_up_impl();
-      if (!tfunction->is_oneway()) {
-        string factory_name = normalize_clsnm((*x_iter)->get_type()->get_name(),"",true) + "Factory";
-        indent_impl(s_service_impl) << 
-          "ret." << prop_name(*x_iter) << " := E." << factory_name << ";" << endl;
-      }
-      indent_down_impl();
-      indent_impl(s_service_impl) << "end;" << endl;
-    }
-    indent_down_impl();
-    indent_impl(s_service_impl) << "end;" << endl;
-  }
-
-  if (! tfunction->is_oneway()) {
-    indent_impl(s_service_impl) << "msg := TMessageImpl.Create('" << tfunction->get_name() << "', TMessageType.Reply, seqid); " << endl;
-    indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg); " << endl;
-    indent_impl(s_service_impl) << "ret.Write(oprot);" << endl;
-    indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl;
-    indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl;
-  }
-
-  indent_down_impl();
-  indent_impl(s_service_impl) << "end;" << endl << endl;
-}
-
-void t_delphi_generator::generate_deserialize_field(ostream& out, bool is_xception, t_field* tfield, string prefix, ostream& local_vars) {
-  t_type* type = tfield->get_type();
-  while(type->is_typedef()) {
-    type = ((t_typedef*)type)->get_type();
-  }
-
-  if (type->is_void()) {
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
-  }
-
-  string name = prefix + prop_name(tfield,is_xception);
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct(out, (t_struct*)type, name, "");
-  } else if (type->is_container()) {
-    generate_deserialize_container(out, is_xception, type, name, local_vars);
-  } else if (type->is_base_type() || type->is_enum()) {
-    indent_impl(out) <<
-      name << " := ";
-
-    if (type->is_enum())
-    {
-      out << type_name(type, false) << "(";
-    }
-
-    out << "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:
-          if (((t_base_type*)type)->is_binary()) {
-             if (ansistr_binary_) {
-               out << "ReadAnsiString();";
-             } else {
-               out << "ReadBinary();";
-             }
-          } else {
-            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 C# name for base type " + tbase;
-      }
-    } else if (type->is_enum()) {
-      out << "ReadI32()";
-      out << ");";
-    }
-    out << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type_name(type).c_str());
-  }
-}
-
-void t_delphi_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string name, string prefix) {
-  string typ_name;
-
-  if (tstruct->is_xception()) {
-    typ_name = type_name(tstruct,true,false,true,true);
-  } else {
-    typ_name = type_name(tstruct,true,false);
-  }
-
-  indent_impl(out) << prefix << name << " := " << typ_name << ".Create;" << endl;
-  indent_impl(out) << prefix << name << ".Read(iprot);" << endl;
-}
-
-void t_delphi_generator::generate_deserialize_container(ostream& out, bool is_xception, t_type* ttype, string name, std::ostream& local_vars) {
-
-  string obj;
-  string counter;
-  string local_var;
-
-  if (ttype->is_map()) {
-    obj = tmp("_map");
-  } else if (ttype->is_set()) {
-    obj = tmp("_set");
-  } else if (ttype->is_list()) {
-    obj = tmp("_list");
-  }
-
-  if (ttype->is_map()) {
-    local_var = obj + ": IMap;";
-  } else if (ttype->is_set()) {
-    local_var = obj + ": ISet;";
-  } else if (ttype->is_list()) {
-    local_var = obj + ": IList;";
-  }
-  local_vars << "  " << local_var << endl;
-  counter = tmp("_i");
-  local_var = counter + ": Integer;";
-  local_vars << "  " << local_var << endl;
-
-  indent_impl(out) << name << " := " << type_name(ttype, true) << ".Create;" << endl;
-
-  if (ttype->is_map()) {
-    indent_impl(out) << obj << " := iprot.ReadMapBegin();" << endl;
-  } else if (ttype->is_set()) {
-    indent_impl(out) << obj << " := iprot.ReadSetBegin();" << endl;
-  } else if (ttype->is_list()) {
-    indent_impl(out) << obj << " := iprot.ReadListBegin();" << endl;
-  }
-
-  indent_impl(out) << 
-    "for " << counter << " := 0 to " << obj << ".Count - 1 do" << endl;
-  indent_impl(out) <<  "begin" << endl;
-  indent_up_impl();
-  if (ttype->is_map()) {
-    generate_deserialize_map_element(out, is_xception, (t_map*)ttype, name, local_vars);
-  } else if (ttype->is_set()) {
-    generate_deserialize_set_element(out, is_xception, (t_set*)ttype, name, local_vars);
-  } else if (ttype->is_list()) {
-    generate_deserialize_list_element(out, is_xception, (t_list*)ttype, name, local_vars);
-  }
-  indent_down_impl();
-  indent_impl(out) << "end;" << endl;
-
-  if (ttype->is_map()) {
-    indent_impl(out) << "iprot.ReadMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent_impl(out) << "iprot.ReadSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent_impl(out) << "iprot.ReadListEnd();" << endl;
-  }
-}
-
-void t_delphi_generator::generate_deserialize_map_element(ostream& out, bool is_xception, t_map* tmap, string prefix, ostream& local_vars) {
-
-  string key = tmp("_key");
-  string val = tmp("_val");
-  string local_var;
-
-  t_field fkey(tmap->get_key_type(), key);
-  t_field fval(tmap->get_val_type(), val);
-
-  local_vars << "  " << declare_field(&fkey) << endl;
-  local_vars << "  " << declare_field(&fval) << endl;
-
-  generate_deserialize_field(out, is_xception, &fkey, "", local_vars);
-  generate_deserialize_field(out, is_xception, &fval, "", local_vars);
-
-  indent_impl(out) <<
-    prefix << ".AddOrSetValue( " << key << ", " << val << ");" << endl;
-
-}
-
-void t_delphi_generator::generate_deserialize_set_element(ostream& out, bool is_xception, t_set* tset, string prefix, ostream& local_vars) {
-  string elem = tmp("_elem");
-  t_field felem(tset->get_elem_type(), elem);
-  local_vars << "  " << declare_field(&felem) << endl;
-  generate_deserialize_field(out, is_xception, &felem, "", local_vars);
-  indent_impl(out) <<
-    prefix << ".Add(" << elem << ");" << endl;
-}
-
-void t_delphi_generator::generate_deserialize_list_element(ostream& out, bool is_xception, t_list* tlist, string prefix, ostream& local_vars) {
-  string elem = tmp("_elem");
-  t_field felem(tlist->get_elem_type(), elem);
-  local_vars << "  " << declare_field(&felem) << endl;
-  generate_deserialize_field(out, is_xception, &felem, "", local_vars);
-  indent_impl(out) <<
-    prefix << ".Add(" << elem << ");" << endl;
-}
-
-void t_delphi_generator::generate_serialize_field(ostream& out, bool is_xception, t_field* tfield, string prefix, ostream& local_vars) {
-  (void) local_vars;
-
-  t_type* type = tfield->get_type();
-  while (type->is_typedef()) {
-    type = ((t_typedef*)type)->get_type();
-  }
-
-  string name = prefix + prop_name(tfield, is_xception);
-  
-  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, local_vars);
-  } else if (type->is_container()) {
-    generate_serialize_container(out, is_xception, type, name, local_vars);
-  } else if (type->is_base_type() || type->is_enum()) {
-    
-    indent_impl(out) <<
-      "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:
-          if (((t_base_type*)type)->is_binary()) {
-            if (ansistr_binary_) {
-              out << "WriteAnsiString(";
-            } else {
-              out << "WriteBinary(";
-            }
-          } else {
-            out << "WriteString(";
-          }
-          out << name << ");";
-          break;
-        case t_base_type::TYPE_BOOL:
-          out << "WriteBool(" << name << ");";
-          break;
-        case t_base_type::TYPE_BYTE:
-          out << "WriteByte(" << name << ");";
-          break;
-        case t_base_type::TYPE_I16:
-          out << "WriteI16(" << name << ");";
-          break;
-        case t_base_type::TYPE_I32:
-          out << "WriteI32(" << name << ");";
-          break;
-        case t_base_type::TYPE_I64:
-          out << "WriteI64(" << name << ");";
-          break;
-        case t_base_type::TYPE_DOUBLE:
-          out << "WriteDouble(" << name << ");";
-          break;
-        default:
-          throw "compiler error: no Delphi name for base type " + tbase;
-      }
-    } else if (type->is_enum()) {
-      out << "WriteI32(Integer(" << name << "));";
-    }
-    out << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n",
-        prefix.c_str(),
-        tfield->get_name().c_str(),
-        type_name(type).c_str());
-  }
-}
-
-void t_delphi_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix, ostream& local_vars) {
-  (void) local_vars;
-  (void) tstruct;
-  out <<
-    indent_impl() << prefix << ".Write(oprot);" << endl;
-}
-
-void t_delphi_generator::generate_serialize_container(ostream& out, bool is_xception, t_type* ttype, string prefix, ostream& local_vars) {
-  string obj;
-  if (ttype->is_map()) {
-    obj = tmp("map");
-    local_vars << "  " << obj << " : IMap;" << endl;
-    indent_impl(out) << obj << " := TMapImpl.Create( " <<
-      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
-      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
-      prefix << ".Count);" << endl;
-    indent_impl(out) << "oprot.WriteMapBegin( " << obj << ");" << endl;
-  } else if (ttype->is_set()) {
-    obj = tmp("set_");
-    local_vars << "  " << obj << " : ISet;" << endl;
-    indent_impl(out) << obj << " := TSetImpl.Create("  << 
-      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
-      prefix << ".Count);" << endl;
-    indent_impl(out) <<
-      "oprot.WriteSetBegin( " << obj << ");" << endl;
-  } else if (ttype->is_list()) {
-    obj = tmp("list_");
-    local_vars << "  " << obj << " : IList;" << endl;
-    indent_impl(out) << obj << " := TListImpl.Create("  << 
-      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
-      prefix << ".Count);" << endl;
-    indent_impl(out) <<
-      "oprot.WriteListBegin( " << obj << ");" << endl;
-  }
-
-  string iter = tmp("_iter");
-  if (ttype->is_map()) {
-    local_vars << "  " << iter << ": " << type_name(((t_map*)ttype)->get_key_type()) << ";" << endl;
-    indent_impl(out) << "for " << iter << " in " << prefix << ".Keys do" << endl;
-    indent_impl(out) << "begin" << endl;
-    indent_up_impl();
-  } else if (ttype->is_set()) {
-    local_vars << "  " << iter << ": " << type_name(((t_set*)ttype)->get_elem_type()) << ";" << endl;
-    indent_impl(out) << "for " << iter << " in " << prefix << " do" << endl;
-    indent_impl(out) << "begin" << endl;
-    indent_up_impl();
-  } else if (ttype->is_list()) {
-    local_vars << "  " << iter << ": " << type_name(((t_list*)ttype)->get_elem_type()) << ";" << endl;
-    indent_impl(out) << "for " << iter << " in " << prefix << " do" << endl;
-    indent_impl(out) << "begin" << endl;
-    indent_up_impl();
-  }
-
-  if (ttype->is_map()) {
-    generate_serialize_map_element(out, is_xception, (t_map*)ttype, iter, prefix, local_vars);
-  } else if (ttype->is_set()) {
-    generate_serialize_set_element(out, is_xception, (t_set*)ttype, iter, local_vars);
-  } else if (ttype->is_list()) {
-    generate_serialize_list_element(out, is_xception, (t_list*)ttype, iter, local_vars);
-  }
-
-  indent_down_impl();
-  indent_impl(out) << "end;" << endl;
-
-  if (ttype->is_map()) {
-    indent_impl(out) << "oprot.WriteMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent_impl(out) << "oprot.WriteSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent_impl(out) << "oprot.WriteListEnd();" << endl;
-  }
-}
-
-void t_delphi_generator::generate_serialize_map_element(ostream& out, bool is_xception, t_map* tmap, string iter, string map, ostream& local_vars) {
-  t_field kfield(tmap->get_key_type(), iter);
-  generate_serialize_field(out, is_xception, &kfield, "", local_vars);
-  t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
-  generate_serialize_field(out, is_xception, &vfield, "", local_vars);
-}
-
-void t_delphi_generator::generate_serialize_set_element(ostream& out, bool is_xception, t_set* tset, string iter, ostream& local_vars) {
-  t_field efield(tset->get_elem_type(), iter);
-  generate_serialize_field(out, is_xception, &efield, "", local_vars);
-}
-
-void t_delphi_generator::generate_serialize_list_element(ostream& out, bool is_xception, t_list* tlist, string iter, ostream& local_vars) {
-  t_field efield(tlist->get_elem_type(), iter);
-  generate_serialize_field(out, is_xception, &efield, "", local_vars);
-}
-
-void t_delphi_generator::generate_property(ostream& out, t_field* tfield, bool isPublic, bool is_xception) {
-  generate_delphi_property(out, is_xception, tfield, isPublic, "Get");
-}
-
-void t_delphi_generator::generate_delphi_property(ostream& out, bool struct_is_xception, t_field* tfield, bool isPublic, std::string fieldPrefix) {
-  (void) isPublic;
-
-  t_type* ftype = tfield->get_type();
-  bool is_xception = ftype->is_xception();
-  indent(out) << "property " << prop_name(tfield, struct_is_xception) << ": " << type_name(ftype, false, true, is_xception, true) << " read " << fieldPrefix + prop_name(tfield, struct_is_xception)
-    << " write Set" << prop_name(tfield, struct_is_xception) << ";" << endl;
-}
-
-std::string t_delphi_generator::prop_name(t_field* tfield, bool is_xception) {
-  return  prop_name(tfield->get_name(), is_xception);
-}
-
-std::string t_delphi_generator::prop_name(string name, bool is_xception) {
-  string ret = name;
-  ret[0] = toupper(ret[0]);
-  return normalize_name( ret, true, is_xception);
-}
-
-std::string t_delphi_generator::constructor_param_name(string name) {
-  string ret = name;
-  ret[0] = toupper(ret[0]);
-  ret = "A" + ret;
-  return normalize_name( ret, false, false);
-}
-
-string t_delphi_generator::normalize_clsnm(string clsnm, string prefix, bool b_no_check_keyword) {
-  if (clsnm.size() > 0) {
-    clsnm[0] = toupper(clsnm[0]);
-  }
-  if (b_no_check_keyword) {
-    return prefix + clsnm;
-  } else {
-    return normalize_name( prefix + clsnm);
-  }
-}
-
-string t_delphi_generator::type_name( t_type* ttype, bool b_cls, bool b_no_postfix, bool b_exception_factory, bool b_full_exception_factory) {
-  
-  if (ttype->is_typedef()) {
-    return normalize_name( "T"+((t_typedef*)ttype)->get_symbolic());
-  }
-  
-  string typ_nm;
-
-  string s_factory;
-
-  if (ttype->is_base_type()) {
-    return base_type_name((t_base_type*)ttype);
-  } else if (ttype->is_enum()) {
-    b_cls = true;
-    b_no_postfix = true;
-  } else if (ttype->is_map()) {
-    t_map *tmap = (t_map*) ttype;
-    if (b_cls) {
-      typ_nm = "TThriftDictionaryImpl";
-    } else {
-      typ_nm = "IThriftDictionary";
-    }
-    return typ_nm + "<" + type_name(tmap->get_key_type()) +
-      ", " + type_name(tmap->get_val_type()) + ">";
-  } else if (ttype->is_set()) {
-    t_set* tset = (t_set*) ttype;
-    if (b_cls) {
-      typ_nm = "THashSetImpl";
-    } else {
-      typ_nm = "IHashSet";
-    }
-    return typ_nm + "<" + type_name(tset->get_elem_type()) + ">";
-  } else if (ttype->is_list()) {
-    t_list* tlist = (t_list*) ttype;
-    if (b_cls) {
-      typ_nm = "TThriftListImpl";
-    } else {
-      typ_nm = "IThriftList";
-    }
-    return typ_nm + "<" + type_name(tlist->get_elem_type()) + ">";
-  }
-
-  string type_prefix;
-
-  if (b_cls) {
-    type_prefix = "T";
-  } else {
-    type_prefix = "I";
-  }
-
-  string nm = normalize_clsnm( ttype->get_name(), type_prefix);
-
-  if (b_exception_factory) {
-    nm = nm + "Factory";
-  }
-
-  if (b_cls) {
-    if (! b_no_postfix) {
-      nm = nm + "Impl";
-    }
-  }
-
-  if ( b_exception_factory && b_full_exception_factory) {
-    return type_name( ttype, true, true, false, false ) + "." + nm;
-  }
-
-  return nm;
-}
-
-// returns "const " for some argument types
-string t_delphi_generator::input_arg_prefix( t_type* ttype) {
-
-  // base types
-  if (ttype->is_base_type()) {
-    switch (((t_base_type*)ttype)->get_base()) {
-  
-      // these should be const'ed for optimal performamce
-      case t_base_type::TYPE_STRING:  // refcounted pointer
-      case t_base_type::TYPE_I64:   // larger than 32 bit
-      case t_base_type::TYPE_DOUBLE:   // larger than 32 bit
-        return "const ";
-  
-      // all others don't need to be
-      case t_base_type::TYPE_BYTE:
-      case t_base_type::TYPE_I16:
-      case t_base_type::TYPE_I32:
-      case t_base_type::TYPE_BOOL:
-      case t_base_type::TYPE_VOID:
-        return "";
-      
-      // we better always report any unknown types
-      default:
-        throw "compiler error: no input_arg_prefix() for base type " + (((t_base_type*)ttype)->get_base());
-    }
-  
-  // enums
-  } else if (ttype->is_enum()) {
-    return "";   // usually <= 32 bit
-  
-  // containers
-  } else if (ttype->is_map()) {
-    return "const ";  // refcounted pointer
-
-  } else if (ttype->is_set()) {
-    return "const ";  // refcounted pointer
-
-  } else if (ttype->is_list()) {
-    return "const ";  // refcounted pointer
-
-  }
-  
-  // any other type, either TSomething or ISomething
-  return "const ";  // possibly refcounted pointer
-}
-
-string t_delphi_generator::base_type_name(t_base_type* tbase) {
-  switch (tbase->get_base()) {
-    case t_base_type::TYPE_VOID:
-      // no "void" in Delphi language
-      return "";
-    case t_base_type::TYPE_STRING:
-      if (tbase->is_binary()) {
-        if ( ansistr_binary_) {
-          return "AnsiString";
-        } else {
-          return "TBytes";
-        }
-      } else {
-        return "string";
-      }
-    case t_base_type::TYPE_BOOL:
-      return "Boolean";
-    case t_base_type::TYPE_BYTE:
-      return "ShortInt";
-    case t_base_type::TYPE_I16:
-      return "SmallInt";
-    case t_base_type::TYPE_I32:
-      return "Integer";
-    case t_base_type::TYPE_I64:
-      return "Int64";
-    case t_base_type::TYPE_DOUBLE:
-      return "Double";
-    default:
-      throw "compiler error: no Delphi name for base type " + tbase->get_base();
-  }
-}
-
-string t_delphi_generator::declare_field(t_field* tfield, bool init, std::string prefix, bool is_xception_class) {
-  (void) init;
-
-  t_type * ftype = tfield->get_type();
-  bool is_xception = ftype->is_xception();
-
-  string result = prefix + prop_name(tfield, is_xception_class) + ": " + type_name(ftype,false,true,is_xception,true) + ";";
-  return result;
-}
-
-string t_delphi_generator::function_signature(t_function* tfunction, std::string full_cls, bool is_xception) {
-  t_type* ttype = tfunction->get_returntype();
-  string prefix;
-  if (full_cls == "") {
-    prefix = "";
-  } else {
-    prefix = full_cls + ".";
-  }
-  if (is_void(ttype)) {
-    return "procedure " + prefix + normalize_name(tfunction->get_name(), true, is_xception)  + "(" + argument_list(tfunction->get_arglist()) + ");";
-  } else {
-    return "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception)  + "(" + argument_list(tfunction->get_arglist()) + "): " + type_name(ttype, false, true, is_xception, true) + ";";
-  }
-}
-
-string t_delphi_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;
-  t_type* tt;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (first) {
-      first = false;
-    } else {
-      result += "; ";
-    }
-
-    tt = (*f_iter)->get_type();
-  result += input_arg_prefix(tt);  // const?
-  result += normalize_name((*f_iter)->get_name()) + ": " + type_name( tt, false, true, tt->is_xception(), true);
-  }
-  return result;
-}
-
-string t_delphi_generator::constructor_argument_list(t_struct* tstruct, string current_indent) {
-  ostringstream result;
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  bool first = true;
-  t_type* tt;
-  string line = "";
-  string newline_indent = current_indent + "  ";
-
-  bool firstline = true;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (first) {
-      first = false;
-    } else {
-      line += ";";
-    }
-
-    if (line.size() > 80) {
-      if ( firstline ) {
-        result << endl << newline_indent;
-        firstline = false;
-      }
-      result << line << endl;
-      line = newline_indent;
-    } else if ( line.size() > 0) {
-      line += " ";
-    }
-
-    tt = (*f_iter)->get_type();
-    line += input_arg_prefix(tt);  // const?
-    line += constructor_param_name((*f_iter)->get_name()) + ": " + type_name( tt, false, true, tt->is_xception(), true);
-  }
-
-  if ( line.size() > 0) {
-    result << line;
-  }
-
-  string result_str;
-
-  if (firstline) {
-    result_str = " " + result.str();
-  } else {
-    result_str = result.str();
-  }
-
-  return result_str;
-}
-
-string t_delphi_generator::type_to_enum(t_type* type) {
-  while (type->is_typedef()) {
-    type = ((t_typedef*)type)->get_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 "TType.String_";
-      case t_base_type::TYPE_BOOL:
-        return "TType.Bool_";
-      case t_base_type::TYPE_BYTE:
-        return "TType.Byte_";
-      case t_base_type::TYPE_I16:
-        return "TType.I16";
-      case t_base_type::TYPE_I32:
-        return "TType.I32";
-      case t_base_type::TYPE_I64:
-        return "TType.I64";
-      case t_base_type::TYPE_DOUBLE:
-        return "TType.Double_";
-    }
-  } else if (type->is_enum()) {
-    return "TType.I32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "TType.Struct";
-  } else if (type->is_map()) {
-    return "TType.Map";
-  } else if (type->is_set()) {
-    return "TType.Set_";
-  } else if (type->is_list()) {
-    return "TType.List";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-string t_delphi_generator::empty_value(t_type* type) {
-  while (type->is_typedef()) {
-    type = ((t_typedef*)type)->get_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:
-        return "0";
-      case t_base_type::TYPE_STRING:
-        if (((t_base_type*)type)->is_binary()) {
-          if (ansistr_binary_) {
-            return "''";
-          } else {
-            return "nil";
-          }
-        } else {
-          return "''";
-        }
-      case t_base_type::TYPE_BOOL:
-        return "False";
-      case t_base_type::TYPE_BYTE:
-      case t_base_type::TYPE_I16:
-      case t_base_type::TYPE_I32:
-      case t_base_type::TYPE_I64:
-        return "0";
-      case t_base_type::TYPE_DOUBLE:
-        return "0.0";
-    }
-  } else if (type->is_enum()) {
-    return "T" + type->get_name() + "(0)";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "nil";
-  } else if (type->is_map()) {
-    return "nil";
-  } else if (type->is_set()) {
-    return "nil";
-  } else if (type->is_list()) {
-    return "nil";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-void t_delphi_generator::generate_delphi_property_writer_definition(ostream& out, t_field* tfield, bool is_xception_class) {
-  t_type * ftype = tfield->get_type();
-  bool is_xception = ftype->is_xception();
-
-  indent(out) << "procedure Set" << prop_name(tfield, is_xception_class) << "( const Value: " << type_name(ftype,false,true,is_xception,true) << ");" << endl;
-}
-
-void t_delphi_generator::generate_delphi_property_reader_definition(ostream& out, t_field* tfield, bool is_xception_class) {
-  t_type * ftype = tfield->get_type();
-  bool is_xception = ftype->is_xception();
-
-  indent(out) << "function Get" << prop_name(tfield, is_xception_class) << ": " << type_name(ftype,false,true,is_xception,true) << ";" << endl;
-}
-
-void t_delphi_generator::generate_delphi_isset_reader_definition(ostream& out, t_field* tfield, bool is_xception) {
-  indent(out) << "function Get__isset_" << prop_name( tfield, is_xception) << ": Boolean;" << endl;
-}
-
-void t_delphi_generator::generate_delphi_clear_union_value(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception_class, bool is_union, bool is_xception_factory, std::string xception_factroy_name) {
-  (void) type;
-
-  t_type * ftype = tfield->get_type();
-  bool is_xception = ftype->is_xception();
-
-  indent_impl(out) << "if F__isset_" << prop_name(tfield, is_xception_class) << " then begin" << endl;
-  indent_up_impl();
-  indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := False;" << endl;
-  indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := " << "Default( " << type_name(ftype,false,true,is_xception,true) << ");" << endl;
-  indent_down_impl();
-  indent_impl(out) << "end;" << endl;
-}
-
-void t_delphi_generator::generate_delphi_property_writer_impl(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception_class, bool is_union, bool is_xception_factory, std::string xception_factroy_name) {
-  (void) type;
-
-  t_type * ftype = tfield->get_type();
-  bool is_xception = ftype->is_xception();
-
-  indent_impl(out) << "procedure " << cls_prefix << name << "." << "Set" << prop_name(tfield, is_xception_class) << "( const Value: " << type_name(ftype,false,true,is_xception,true) << ");" << endl;
-  indent_impl(out) << "begin" << endl;
-  indent_up_impl();
-  if ( is_union ) {
-    indent_impl(out) << "ClearUnionValues;" << endl;
-  }
-  if (tfield->get_req() != t_field::T_REQUIRED) {
-    indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := True;" << endl;
-  }
-  indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := Value;" << endl;
-
-  if (is_xception_class && (! is_xception_factory) ) {
-    indent_impl(out) << "F" << xception_factroy_name << "." << prop_name(tfield, is_xception_class) << " := Value;" << endl;
-  }
-
-  indent_down_impl();
-  indent_impl(out) << "end;" << endl << endl;
-}
-
-void t_delphi_generator::generate_delphi_property_reader_impl(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception_class) {
-  (void) type;
-
-  t_type * ftype = tfield->get_type();
-  bool is_xception = ftype->is_xception();
-
-  indent_impl(out) << "function " << cls_prefix << name << "." << "Get" << prop_name( tfield, is_xception_class) << ": " << type_name(ftype,false,true,is_xception,true) << ";" << endl;
-  indent_impl(out) << "begin" << endl;
-  indent_up_impl();
-  indent_impl(out) << "Result := " << fieldPrefix << prop_name(tfield, is_xception_class) << ";" << endl;
-  indent_down_impl();
-  indent_impl(out) << "end;" << endl << endl;
-}
-
-void t_delphi_generator::generate_delphi_isset_reader_impl(ostream& out, std::string cls_prefix, std::string name, t_type* type, t_field* tfield, std::string fieldPrefix, bool is_xception) {
-  (void) type;
-
-  string isset_name = "__isset_" + prop_name( tfield, is_xception);
-  indent_impl(out) << "function " << cls_prefix << name << "." << "Get" << isset_name << ": Boolean;" << endl;
-  indent_impl(out) << "begin" << endl;
-  indent_up_impl();
-  indent_impl(out) << "Result := " << fieldPrefix << isset_name << ";" << endl;
-  indent_down_impl();
-  indent_impl(out) << "end;" << endl << endl;
-}
-
-void t_delphi_generator::generate_delphi_create_exception_impl(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception) {
-  (void) cls_prefix;
-
-  string exception_cls_nm = type_name(tstruct,true,true);
-  string cls_nm = type_name(tstruct,true,false,is_exception,is_exception);
-
-  indent_impl(out) << "function " << cls_nm << ".CreateException: " << exception_cls_nm << ";" << endl;
-
-  indent_impl(out) << "begin" << endl;
-  indent_up_impl();
-
-
-  indent_impl(out) << "Result := " << exception_cls_nm << ".Create;" << endl;
-  string factory_name = normalize_clsnm(tstruct->get_name(),"",true) + "Factory";
-  indent_impl(out) << "Result." << factory_name << " := Self;" << endl;
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  string propname;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    propname = prop_name(*f_iter, is_exception);
-    if ((*f_iter)->get_req() != t_field::T_REQUIRED) {
-      indent_impl(out) << "if __isset_" << propname << " then" << endl;
-      indent_impl(out) << "begin" << endl;
-      indent_up_impl();
-    }
-    indent_impl(out) << "Result." << propname <<  " := " << propname << ";" << endl;
-    if ((*f_iter)->get_req() != t_field::T_REQUIRED) {
-      indent_down_impl();
-      indent_impl(out) << "end;" << endl;
-    }
-  }
-
-  indent_impl(out) << "Result.UpdateMessageProperty;" << endl;
- 
-  indent_down_impl();
-  indent_impl(out) << "end;" << endl << endl;
-}
-
-void t_delphi_generator::generate_delphi_struct_reader_impl(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception) {
-
-  ostringstream local_vars;
-  ostringstream code_block;
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-
-  indent_impl(code_block) << "begin" << endl;
-  indent_up_impl();
-
-  // local bools for required fields
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
-      indent_impl(local_vars) << 
-        "_req_isset_" << prop_name(*f_iter, is_exception) << " : Boolean;" << endl;
-      indent_impl(code_block) << 
-        "_req_isset_" << prop_name(*f_iter, is_exception) << " := FALSE;" << endl;
-    }
-  }
-  
-  indent_impl(code_block) << "struc := iprot.ReadStructBegin;" << endl;
-
-  indent_impl(code_block) << "try" << endl;
-  indent_up_impl();
-
-  indent_impl(code_block) << "while (true) do" << endl;
-  indent_impl(code_block) << "begin" << endl;
-  indent_up_impl();
-
-  indent_impl(code_block) << "field_ := iprot.ReadFieldBegin();" << endl;
-
-  indent_impl(code_block) << "if (field_.Type_ = TType.Stop) then" << endl;
-  indent_impl(code_block) << "begin" << endl;
-  indent_up_impl();
-  indent_impl(code_block) << "Break;" << endl;
-  indent_down_impl();
-  indent_impl(code_block) << "end;" << endl;
-
-
-  bool first = true;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-
-    if (first) {
-      indent_impl(code_block) << "case field_.ID of" << endl;
-      indent_up_impl();
-    }
-
-    first = false;
-    if (f_iter != fields.begin()) {
-      code_block << ";" << endl;
-    }
-    indent_impl(code_block) << (*f_iter)->get_key() << ": begin" << endl;
-    indent_up_impl();
-    indent_impl(code_block) << "if (field_.Type_ = " << type_to_enum((*f_iter)->get_type()) << ") then" << endl;
-    indent_impl(code_block) << "begin" << endl;
-    indent_up_impl();
-
-    generate_deserialize_field(code_block, is_exception,  *f_iter, "", local_vars);
-
-    // required field?
-    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
-      indent_impl(code_block) << 
-        "_req_isset_" << prop_name(*f_iter, is_exception) << " := TRUE;" << endl;
-    }
-
-    indent_down_impl();
-
-    indent_impl(code_block) << "end else" << endl;
-    indent_impl(code_block) << "begin" << endl;
-    indent_up_impl();
-    indent_impl(code_block) << "TProtocolUtil.Skip(iprot, field_.Type_);" << endl;
-    indent_down_impl();
-    indent_impl(code_block) << "end;" << endl;
-    indent_down_impl();
-    indent_impl(code_block) << "end";
-
-  }
-
-  if (! first) {
-    code_block << endl;
-    indent_impl(code_block) << "else begin" << endl;
-    indent_up_impl();
-  }
-
-  indent_impl(code_block) << "TProtocolUtil.Skip(iprot, field_.Type_);" << endl;
-
-  if (! first) {
-    indent_down_impl();
-    indent_impl(code_block) << "end;" << endl;
-    indent_down_impl();
-    indent_impl(code_block) << "end;" << endl;
-  }
-
-  indent_impl(code_block) << "iprot.ReadFieldEnd;" << endl;
-
-  indent_down_impl();
-
-  indent_impl(code_block) << "end;" << endl;
-  indent_down_impl();
-
-  indent_impl(code_block) << "finally" << endl;
-  indent_up_impl();
-  indent_impl(code_block) << "iprot.ReadStructEnd;" << endl;
-  indent_down_impl();
-  indent_impl(code_block) << "end;" << endl;
-
-  // all required fields have been read?  
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
-      indent_impl(code_block) << 
-        "if not _req_isset_" << prop_name(*f_iter, is_exception) << endl;
-      indent_impl(code_block) << 
-        "then raise TProtocolException.Create( TProtocolException.INVALID_DATA, '" << 
-        prop_name(*f_iter, is_exception) << "');" << endl;
-    }
-  }
-  
-  indent_down_impl();
-  indent_impl(code_block) << "end;" << endl << endl;
-
-  string cls_nm;
-
-  cls_nm = type_name(tstruct,true,false,is_exception,is_exception);
-
-  indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Read( const iprot: IProtocol);" << endl;
-  indent_impl(out) << "var" << endl;
-  indent_up_impl();
-  indent_impl(out) << "field_ : IField;" << endl;
-  indent_impl(out) << "struc : IStruct;" << endl;
-  indent_down_impl();
-  out << local_vars.str() << endl;
-  out << code_block.str();
-}
-
-void t_delphi_generator::generate_delphi_struct_result_writer_impl(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception) {
-
-  ostringstream local_vars;
-  ostringstream code_block;
-
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-
-  indent_impl(code_block) << "begin" << endl;
-  indent_up_impl();
-
-  indent_impl(code_block) << "struc := TStructImpl.Create('" << name << "');" << endl;
-
-  indent_impl(code_block) << "oprot.WriteStructBegin(struc);" << endl;
-
-  if (fields.size() > 0) {
-    indent_impl(code_block) << "field_ := TFieldImpl.Create;" << endl;
-    bool first = true;
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      if (! first) {
-        indent_impl(code_block) << "end else" << endl;
-      }
-
-      indent_impl(code_block) << "if (__isset_" << prop_name(*f_iter,is_exception) << ") then" << endl;
-      indent_impl(code_block) << "begin" << endl;
-      indent_up_impl();
-      indent_impl(code_block) <<
-        "field_.Name := '" << (*f_iter)->get_name() << "';" << endl;
-      indent_impl(code_block) <<
-        "field_.Type_  := " << type_to_enum((*f_iter)->get_type()) << ";" << endl;
-      indent_impl(code_block) <<
-        "field_.ID := " << (*f_iter)->get_key() << ";" << endl;
-      indent_impl(code_block) <<
-        "oprot.WriteFieldBegin(field_);" << endl;
-      generate_serialize_field(code_block, is_exception, *f_iter, "", local_vars);
-      indent_impl(code_block) << "oprot.WriteFieldEnd();" << endl;
-      indent_down_impl();
-    }
-
-    if (! first) {
-        indent_impl(code_block) << "end;" << endl;
-    }
-
-  }
-
-
-  indent_impl(code_block) << "oprot.WriteFieldStop();" << endl;
-  indent_impl(code_block) << "oprot.WriteStructEnd();" << endl;
-
-  indent_down_impl();
-  indent_impl(code_block) << "end;" << endl << endl;
-
-  string cls_nm;
-
-  cls_nm = type_name(tstruct,true,false,is_exception,is_exception);
-
-  indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Write( const oprot: IProtocol);" << endl;
-  indent_impl(out) << "var" << endl;
-  indent_up_impl();
-  indent_impl(out) << "struc : IStruct;" << endl;
-
-  if (fields.size() > 0) {
-    indent_impl(out) << "field_ : IField;" << endl;
-  }
-
-  out << local_vars.str();
-  indent_down_impl();
-  out << code_block.str();
-
-}
-
-void t_delphi_generator::generate_delphi_struct_writer_impl(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception) {
-
-  ostringstream local_vars;
-  ostringstream code_block;
-
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-
-  indent_impl(code_block) << "begin" << endl;
-  indent_up_impl();
-
-  indent_impl(code_block) << "struc := TStructImpl.Create('" << name << "');" << endl;
-
-  indent_impl(code_block) << "oprot.WriteStructBegin(struc);" << endl;
-
-  if (fields.size() > 0) {
-    indent_impl(code_block) << "field_ := TFieldImpl.Create;" << endl;
-  }
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    bool null_allowed = type_can_be_null((*f_iter)->get_type());
-    bool is_optional  = ((*f_iter)->get_req() != t_field::T_REQUIRED);
-    if (null_allowed) {
-      indent_impl(code_block) <<
-        "if (" << prop_name((*f_iter), is_exception) << " <> nil)";
-      if (is_optional) {
-        code_block << 
-          " and __isset_" << prop_name(*f_iter,is_exception);
-      }
-      code_block << 
-        " then" << endl;
-      indent_impl(code_block) << "begin" << endl;
-      indent_up_impl();
-    } else {
-      if (is_optional) {
-        indent_impl(code_block) << "if (__isset_" << prop_name(*f_iter,is_exception) << ") then" << endl;
-        indent_impl(code_block) << "begin" << endl;
-        indent_up_impl();
-      } else {
-        indent_impl(code_block) << "// required field" << endl;
-      }
-    }
-    indent_impl(code_block) <<
-      "field_.Name := '" << (*f_iter)->get_name() << "';" << endl;
-    indent_impl(code_block) <<
-      "field_.Type_  := " << type_to_enum((*f_iter)->get_type()) << ";" << endl;
-    indent_impl(code_block) <<
-      "field_.ID := " << (*f_iter)->get_key() << ";" << endl;
-    indent_impl(code_block) <<
-      "oprot.WriteFieldBegin(field_);" << endl;
-    generate_serialize_field(code_block, is_exception, *f_iter, "", local_vars);
-    indent_impl(code_block) << "oprot.WriteFieldEnd();" << endl;
-    if (null_allowed || is_optional) {
-      indent_down_impl();
-      indent_impl(code_block) << "end;" << endl;
-    }
-  }
-
-  indent_impl(code_block) << "oprot.WriteFieldStop();" << endl;
-  indent_impl(code_block) << "oprot.WriteStructEnd();" << endl;
-
-  indent_down_impl();
-  indent_impl(code_block) << "end;" << endl << endl;
-
-  string cls_nm;
-
-  cls_nm = type_name(tstruct,true,false,is_exception,is_exception);
-
-  indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Write( const oprot: IProtocol);" << endl;
-  indent_impl(out) << "var" << endl;
-  indent_up_impl();
-  indent_impl(out) << "struc : IStruct;" << endl;
-  if (fields.size() > 0) {
-    indent_impl(out) << "field_ : IField;" << endl;
-  }
-  out << local_vars.str();
-  indent_down_impl();
-  out << code_block.str();
-
-}
-
-void t_delphi_generator::generate_delphi_struct_tostring_impl(ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception, bool is_x_factory) {
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  string cls_nm;
-
-  if (is_exception) {
-    cls_nm = type_name(tstruct,true,(! is_x_factory),is_x_factory,true);
-  } else {
-    cls_nm = type_name(tstruct,true,false);
-  }
-
-  string tmp_sb = "sb";
-
-  indent_impl(out) << "function " << cls_prefix << cls_nm << ".ToString: string;" << endl;
-  indent_impl(out) << "var" << endl;
-  indent_up_impl();
-  indent_impl(out) << tmp_sb << " : TThriftStringBuilder;" << endl;
-  indent_down_impl();
-  indent_impl(out) << "begin" << endl;
-  indent_up_impl();
-
-  indent_impl(out) << tmp_sb << " := TThriftStringBuilder.Create('(');" << endl;
-  indent_impl(out) << "try" << endl;
-  indent_up_impl();
-
-  bool first = true;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (first) {
-      first = false;
-      indent_impl(out) <<
-        tmp_sb << ".Append('" << prop_name((*f_iter), is_exception) << ": ');" << endl;
-    } else {
-      indent_impl(out) <<
-        tmp_sb << ".Append('," << prop_name((*f_iter), is_exception) << ": ');" << endl;
-    }
-    t_type* ttype = (*f_iter)->get_type();
-    if (ttype->is_xception() || ttype->is_struct()) {
-      indent_impl(out) <<
-        "if (" << prop_name((*f_iter), is_exception) << " = nil) then " << tmp_sb <<  ".Append('<null>') else " << tmp_sb <<  ".Append("<< prop_name((*f_iter), is_exception)  << ".ToString());" << endl;
-    } else if (ttype->is_enum()) {
-      indent_impl(out) <<
-        tmp_sb << ".Append(Integer(" << prop_name((*f_iter), is_exception) << "));" << endl;
-    } else {
-      indent_impl(out) <<
-        tmp_sb << ".Append(" << prop_name((*f_iter), is_exception)  << ");" << endl;
-    }
-  }
-
-  indent_impl(out) <<
-    tmp_sb << ".Append(')');" << endl;
-  indent_impl(out) <<
-    "Result := " << tmp_sb <<  ".ToString;" << endl;
-
-  indent_down_impl();
-  indent_impl(out) << "finally" << endl;
-  indent_up_impl();
-  indent_impl(out) << tmp_sb << ".Free;" << endl;
-  indent_down_impl();
-  indent_impl(out) << "end;" << endl;
-
-  indent_down_impl();
-  indent_impl(out) << "end;" << endl << endl;
-}
-
-bool t_delphi_generator::is_void( t_type* type ) {
-  while (type->is_typedef()) {
-    type = ((t_typedef*)type)->get_type();
-  }
-
-  if (type->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
-    if (tbase == t_base_type::TYPE_VOID) {
-      return true;
-    }
-  }
-  return false;
-}
-
-THRIFT_REGISTER_GENERATOR(delphi, "delphi", 
-"    ansistr_binary:  Use AnsiString for binary datatype (default is TBytes).\n" 
-"    register_types:  Enable TypeRegistry, allows for creation of struct, union\n" 
-"                     and container instances by interface or TypeInfo()\n");
-
diff --git a/compiler/cpp/src/generate/t_erl_generator.cc b/compiler/cpp/src/generate/t_erl_generator.cc
deleted file mode 100644
index ae1a122..0000000
--- a/compiler/cpp/src/generate/t_erl_generator.cc
+++ /dev/null
@@ -1,1026 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sstream>
-#include "t_generator.h"
-#include "platform.h"
-#include "version.h"
-
-using std::map;
-using std::ofstream;
-using std::ostream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const std::string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * Erlang code generator.
- *
- */
-class t_erl_generator : public t_generator {
- public:
-  t_erl_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_generator(program)
-  {
-    (void) parsed_options;
-    (void) option_string;
-    program_name_[0] = tolower(program_name_[0]);
-    service_name_[0] = tolower(service_name_[0]);
-    out_dir_base_ = "gen-erl";
-  }
-
-  /**
-   * 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);
-  void generate_member_type(std::ostream & out, t_type* type);
-  void generate_member_value(std::ostream & out, t_type* type, t_const_value* value);
-
-  std::string render_member_type(t_field * field);
-  std::string render_member_value(t_field * field);
-  std::string render_member_requiredness(t_field * field);
-
-//  std::string render_default_value(t_type* type);
-  std::string render_default_value(t_field * field);
-  std::string render_const_value(t_type* type, t_const_value* value);
-  std::string render_type_term(t_type* ttype, bool expand_structs, bool extended_info = false);
-
-  /**
-   * Struct generation code
-   */
-
-  void generate_erl_struct(t_struct* tstruct, bool is_exception);
-  void generate_erl_struct_definition(std::ostream& out, t_struct* tstruct);
-  void generate_erl_struct_member(std::ostream& out, t_field * tmember);
-  void generate_erl_struct_info(std::ostream& out, t_struct* tstruct);
-  void generate_erl_extended_struct_info(std::ostream& out, t_struct* tstruct);
-  void generate_erl_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_function_info     (t_service* tservice, t_function* tfunction);
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string erl_autogen_comment();
-  std::string erl_imports();
-  std::string render_includes();
-  std::string type_name(t_type* ttype);
-
-  std::string function_signature(t_function* tfunction, std::string prefix="");
-
-
-  std::string argument_list(t_struct* tstruct);
-  std::string type_to_enum(t_type* ttype);
-  std::string type_module(t_type* ttype);
-
-  std::string capitalize(std::string in) {
-    in[0] = toupper(in[0]);
-    return in;
-  }
-
-  std::string uncapitalize(std::string in) {
-    in[0] = tolower(in[0]);
-    return in;
-  }
-
-  static std::string comment(string in);
-
- private:
-
-  bool has_default_value(t_field *);
-
-  /**
-   * add function to export list
-   */
-
-  void export_function(t_function* tfunction, std::string prefix="");
-  void export_string(std::string name, int num);
-
-  void export_types_function(t_function* tfunction, std::string prefix="");
-  void export_types_string(std::string name, int num);
-
-  /**
-   * write out headers and footers for hrl files
-   */
-
-  void hrl_header(std::ostream& out, std::string name);
-  void hrl_footer(std::ostream& out, std::string name);
-
-  /**
-   * stuff to spit out at the top of generated files
-   */
-
-  bool export_lines_first_;
-  std::ostringstream export_lines_;
-
-  bool export_types_lines_first_;
-  std::ostringstream export_types_lines_;
-
-  /**
-   * File streams
-   */
-
-  std::ostringstream f_info_;
-  std::ostringstream f_info_ext_;
-
-  std::ofstream f_types_file_;
-  std::ofstream f_types_hrl_file_;
-
-  std::ofstream f_consts_;
-  std::ostringstream f_service_;
-  std::ofstream f_service_file_;
-  std::ofstream f_service_hrl_;
-
-};
-
-
-/**
- * UI for file generation by opening up the necessary file output
- * streams.
- *
- * @param tprogram The program to generate
- */
-void t_erl_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-
-  // setup export lines
-  export_lines_first_ = true;
-  export_types_lines_first_ = true;
-
-  // types files
-  string f_types_name = get_out_dir()+program_name_+"_types.erl";
-  string f_types_hrl_name = get_out_dir()+program_name_+"_types.hrl";
-
-  f_types_file_.open(f_types_name.c_str());
-  f_types_hrl_file_.open(f_types_hrl_name.c_str());
-
-  hrl_header(f_types_hrl_file_, program_name_ + "_types");
-
-  f_types_file_ <<
-    erl_autogen_comment() << endl <<
-    "-module(" << program_name_ << "_types)." << endl <<
-    erl_imports() << endl;
-
-  f_types_file_ <<
-    "-include(\"" << program_name_ << "_types.hrl\")." << endl <<
-    endl;
-
-  f_types_hrl_file_ << render_includes() << endl;
-
-  // consts file
-  string f_consts_name = get_out_dir()+program_name_+"_constants.hrl";
-  f_consts_.open(f_consts_name.c_str());
-
-  f_consts_ <<
-    erl_autogen_comment() << endl <<
-    erl_imports() << endl <<
-    "-include(\"" << program_name_ << "_types.hrl\")." << endl <<
-    endl;
-}
-
-/**
- * Boilerplate at beginning and end of header files
- */
-void t_erl_generator::hrl_header(ostream& out, string name) {
-  out << "-ifndef(_" << name << "_included)." << endl <<
-    "-define(_" << name << "_included, yeah)." << endl;
-}
-
-void t_erl_generator::hrl_footer(ostream& out, string name) {
-  (void) name;
-  out << "-endif." << endl;
-}
-
-/**
- * Renders all the imports necessary for including another Thrift program
- */
-string t_erl_generator::render_includes() {
-  const vector<t_program*>& includes = program_->get_includes();
-  string result = "";
-  for (size_t i = 0; i < includes.size(); ++i) {
-    result += "-include(\"" + uncapitalize(includes[i]->get_name()) + "_types.hrl\").\n";
-  }
-  if (includes.size() > 0) {
-    result += "\n";
-  }
-  return result;
-}
-
-/**
- * Autogen'd comment
- */
-string t_erl_generator::erl_autogen_comment() {
-  return
-    std::string("%%\n") +
-    "%% Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" +
-    "%%\n" +
-    "%% DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
-    "%%\n";
-}
-
-/**
- * Comment out text
- */
-
-string t_erl_generator::comment(string in)
-{
-  size_t pos = 0;
-  in.insert(pos, "%% ");
-  while ( (pos = in.find_first_of('\n', pos)) != string::npos )
-  {
-    in.insert(++pos, "%% ");
-  }
-  return in;
-}
-
-/**
- * Prints standard thrift imports
- */
-string t_erl_generator::erl_imports() {
-  return "";
-}
-
-/**
- * Closes the type files
- */
-void t_erl_generator::close_generator() {
-
-  export_types_string("struct_info", 1);
-  export_types_string("struct_info_ext", 1);
-  f_types_file_ << "-export([" << export_types_lines_.str() << "])." << endl << endl;
-
-  f_types_file_ << f_info_.str();
-  f_types_file_ << "struct_info('i am a dummy struct') -> undefined." << endl << endl;
-
-  f_types_file_ << f_info_ext_.str();
-  f_types_file_ << "struct_info_ext('i am a dummy struct') -> undefined." << endl << endl;
-
-  hrl_footer(f_types_hrl_file_, string("BOGUS"));
-
-  f_types_file_.close();
-  f_types_hrl_file_.close();
-  f_consts_.close();
-}
-
-/**
- * Generates a typedef. no op
- *
- * @param ttypedef The type definition
- */
-void t_erl_generator::generate_typedef(t_typedef* ttypedef) {
-  (void) ttypedef;
-}
-
-/**
- * Generates code for an enumerated type. Done using a class to scope
- * the values.
- *
- * @param tenum The enumeration
- */
-void t_erl_generator::generate_enum(t_enum* tenum) {
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    string name = capitalize((*c_iter)->get_name());
-    indent(f_types_hrl_file_) <<
-      "-define(" << program_name_ << "_" << tenum->get_name() << "_" << name << ", " << value << ")."<< endl;
-  }
-
-  f_types_hrl_file_ << endl;
-}
-
-/**
- * Generate a constant value
- */
-void t_erl_generator::generate_const(t_const* tconst) {
-  t_type* type = tconst->get_type();
-  string name = capitalize(tconst->get_name());
-  t_const_value* value = tconst->get_value();
-
-  f_consts_ << "-define(" << program_name_ << "_" << name << ", " << render_const_value(type, value) << ")." << endl << 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_erl_generator::render_const_value(t_type* type, t_const_value* value) {
-  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 << "#" << uncapitalize(type->get_name()) << "{";
-    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;
-
-    bool first = true;
-    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 (first) {
-        first = false;
-      } else {
-        out << ",";
-      }
-      out << v_iter->first->get_string();
-      out << " = ";
-      out << render_const_value(field_type, v_iter->second);
-    }
-    indent_down();
-    indent(out) << "}";
-
-  } else if (type->is_map()) {
-    t_type* ktype = ((t_map*)type)->get_key_type();
-    t_type* vtype = ((t_map*)type)->get_val_type();
-
-    out << "dict:from_list([";
-    map<t_const_value*, t_const_value*>::const_iterator i, end = value->get_map().end();
-    for (i = value->get_map().begin(); i != end;) {
-      out << "{"
-          << render_const_value(ktype, i->first)  << ","
-          << render_const_value(vtype, i->second) << "}";
-      if ( ++i != end ) {
-        out << ",";
-      }
-    }
-    out << "])";
-  } else if (type->is_set()) {
-    t_type* etype = ((t_set*)type)->get_elem_type();
-    out << "sets:from_list([";
-    vector<t_const_value*>::const_iterator i, end = value->get_list().end();
-    for( i = value->get_list().begin(); i != end; ) {
-      out << render_const_value(etype, *i) ;
-      if ( ++i != end ) {
-        out << ",";
-      }
-    }
-    out << "])";
-  } else if (type->is_list()) {
-    t_type* etype;
-    etype = ((t_list*)type)->get_elem_type();
-    out << "[";
-
-    bool first = true;
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      if (first) {
-        first=false;
-      } else {
-        out << ",";
-      }
-      out << render_const_value(etype, *v_iter);
-    }
-    out << "]";
-  } else {
-    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
-  }
-  return out.str();
-}
-
-
-string t_erl_generator::render_default_value(t_field* field) {
-  t_type *type = field->get_type();
-  if (type->is_struct() || type->is_xception()) {
-    return "#" + uncapitalize(type->get_name()) + "{}";
-  } else if (type->is_map()) {
-    return "dict:new()";
-  } else if (type->is_set()) {
-    return "sets:new()";
-  } else if (type->is_list()) {
-    return "[]";
-  } else {
-    return "undefined";
-  }
-}
-
-string t_erl_generator::render_member_type(t_field * field) {
-  t_type * type = get_true_type(field->get_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_STRING:
-      return "string() | binary()";
-    case t_base_type::TYPE_BOOL:
-      return "boolean()";
-    case t_base_type::TYPE_BYTE:
-    case t_base_type::TYPE_I16:
-    case t_base_type::TYPE_I32:
-    case t_base_type::TYPE_I64:
-      return "integer()";
-    case t_base_type::TYPE_DOUBLE:
-      return "float()";
-    default:
-      throw "compiler error: unsupported base type " + t_base_type::t_base_name(tbase);
-    }
-  } else if (type->is_enum()) {
-    return "integer()";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "#" + uncapitalize(type->get_name()) + "{}";
-  } else if (type->is_map()) {
-    return "dict()";
-  } else if (type->is_set()) {
-    return "set()";
-  } else if (type->is_list()) {
-    return "list()";
-  } else {
-    throw "compiler error: unsupported type " + type->get_name();
-  }
-}
-
-string t_erl_generator::render_member_requiredness(t_field * field) {
-    switch(field->get_req()) {
-        case t_field::T_REQUIRED:       return "required";
-        case t_field::T_OPTIONAL:       return "optional";
-        default:                        return "undefined";
-    }
-}
-
-/**
- * Generates a struct
- */
-void t_erl_generator::generate_struct(t_struct* tstruct) {
-  generate_erl_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_erl_generator::generate_xception(t_struct* txception) {
-  generate_erl_struct(txception, true);
-}
-
-/**
- * Generates a struct
- */
-void t_erl_generator::generate_erl_struct(t_struct* tstruct, bool is_exception) {
-  (void) is_exception;
-  generate_erl_struct_definition(f_types_hrl_file_, tstruct);
-  generate_erl_struct_info(f_info_, tstruct);
-  generate_erl_extended_struct_info(f_info_ext_, tstruct);
-}
-
-/**
- * Generates a struct definition for a thrift data type.
- *
- * @param tstruct The struct definition
- */
-void t_erl_generator::generate_erl_struct_definition(ostream& out, t_struct* tstruct)
-{
-  indent(out) << "%% struct " << type_name(tstruct) << endl << endl;
-
-  std::stringstream buf;
-  buf << indent() << "-record(" << type_name(tstruct) << ", {";
-  string field_indent(buf.str().size(), ' ');
-
-  const vector<t_field*>& members = tstruct->get_members();
-  for (vector<t_field*>::const_iterator m_iter = members.begin(); m_iter != members.end();) {
-    generate_erl_struct_member(buf, *m_iter);
-    if ( ++m_iter != members.end() ) {
-      buf << "," << endl << field_indent;
-    }
-  }
-  buf << "}).";
-
-  out << buf.str() << endl << endl;
-}
-
-/**
- * Generates the record field definition
- */
-
-void t_erl_generator::generate_erl_struct_member(ostream & out, t_field * tmember)
-{
-  out << uncapitalize(tmember->get_name());
-  if (has_default_value(tmember))
-    out << " = "  << render_member_value(tmember);
-  out << " :: " << render_member_type(tmember);
-}
-
-bool t_erl_generator::has_default_value(t_field * field) {
-  t_type *type = field->get_type();
-  if (!field->get_value()) {
-    if ( field->get_req() == t_field::T_REQUIRED) {
-      if (type->is_struct() || type->is_xception() || type->is_map() ||
-          type->is_set() || type->is_list()) {
-        return true;
-      } else {
-        return false;
-      }
-    } else {
-      return false;
-    }
-  } else {
-    return true;
-  }
-}
-
-string t_erl_generator::render_member_value(t_field * field) {
-  if (!field->get_value()) {
-    return render_default_value(field);
-  } else {
-    return render_const_value(field->get_type(), field->get_value());
-  }
-}
-
-
-
-/**
- * Generates the read method for a struct
- */
-void t_erl_generator::generate_erl_struct_info(ostream& out, t_struct* tstruct) {
-  indent(out) << "struct_info('" << type_name(tstruct) << "') ->" << endl;
-  indent_up();
-  out << indent() << render_type_term(tstruct, true) << ";" << endl;
-  indent_down();
-  out << endl;
-}
-
-void t_erl_generator::generate_erl_extended_struct_info(ostream& out, t_struct* tstruct) {
-  indent(out) << "struct_info_ext('" << type_name(tstruct) << "') ->" << endl;
-  indent_up();
-  out << indent() << render_type_term(tstruct, true, true) << ";" << endl;
-  indent_down();
-  out << endl;
-}
-
-/**
- * Generates a thrift service.
- *
- * @param tservice The service definition
- */
-void t_erl_generator::generate_service(t_service* tservice) {
-  // somehow this point is reached before the constructor and it's not downcased yet
-  // ...awesome
-  service_name_[0] = tolower(service_name_[0]);
-
-  string f_service_hrl_name = get_out_dir()+service_name_+"_thrift.hrl";
-  string f_service_name = get_out_dir()+service_name_+"_thrift.erl";
-  f_service_file_.open(f_service_name.c_str());
-  f_service_hrl_.open(f_service_hrl_name.c_str());
-
-  // Reset service text aggregating stream streams
-  f_service_.str("");
-  export_lines_.str("");
-  export_lines_first_ = true;
-
-  hrl_header(f_service_hrl_, service_name_);
-
-  if (tservice->get_extends() != NULL) {
-    f_service_hrl_ << "-include(\"" <<
-      uncapitalize(tservice->get_extends()->get_name()) << "_thrift.hrl\"). % inherit " << endl;
-  }
-
-  f_service_hrl_ <<
-    "-include(\"" << program_name_ << "_types.hrl\")." << endl <<
-    endl;
-
-  // Generate the three main parts of the service (well, two for now in PHP)
-  generate_service_helpers(tservice); // cpiro: New Erlang Order
-
-  generate_service_interface(tservice);
-
-  // indent_down();
-
-  f_service_file_ <<
-    erl_autogen_comment() << endl <<
-    "-module(" << service_name_ << "_thrift)." << endl <<
-    "-behaviour(thrift_service)." << endl << endl <<
-    erl_imports() << endl;
-
-  f_service_file_ << "-include(\"" << uncapitalize(tservice->get_name()) << "_thrift.hrl\")." << endl << endl;
-
-  f_service_file_ << "-export([" << export_lines_.str() << "])." << endl << endl;
-
-  f_service_file_ << f_service_.str();
-
-  hrl_footer(f_service_hrl_, f_service_name);
-
-  // Close service file
-  f_service_file_.close();
-  f_service_hrl_.close();
-}
-
-/**
- * Generates helper functions for a service.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_erl_generator::generate_service_helpers(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  //  indent(f_service_) <<
-  //  "% HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
-
-  export_string("struct_info", 1);
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_erl_function_helpers(*f_iter);
-  }
-  f_service_    << "struct_info('i am a dummy struct') -> undefined." << endl;
-}
-
-/**
- * Generates a struct and helpers for a function.
- *
- * @param tfunction The function
- */
-void t_erl_generator::generate_erl_function_helpers(t_function* tfunction) {
-  (void) tfunction;
-}
-
-/**
- * Generates a service interface definition.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_erl_generator::generate_service_interface(t_service* tservice) {
-
-  export_string("function_info", 2);
-
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  f_service_ << "%%% interface" << endl;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_service_ <<
-      indent() << "% " << function_signature(*f_iter) << endl;
-
-    generate_function_info(tservice, *f_iter);
-  }
-
-  // Inheritance - pass unknown functions to base class
-  if (tservice->get_extends() != NULL) {
-      indent(f_service_) << "function_info(Function, InfoType) ->" << endl;
-      indent_up();
-      indent(f_service_) << uncapitalize(tservice->get_extends()->get_name())
-                         << "_thrift:function_info(Function, InfoType)." << endl;
-      indent_down();
-  } else {
-      // Use a special return code for nonexistent functions
-      indent(f_service_) << "function_info(_Func, _Info) -> no_function." << endl;
-  }
-
-  indent(f_service_) << endl;
-}
-
-
-/**
- * Generates a function_info(FunctionName, params_type) and
- * function_info(FunctionName, reply_type)
- */
-void t_erl_generator::generate_function_info(t_service* tservice,
-                                                t_function* tfunction) {
-  (void) tservice;
-  string name_atom = "'" + tfunction->get_name() + "'";
-
-
-
-  t_struct* xs = tfunction->get_xceptions();
-  t_struct* arg_struct = tfunction->get_arglist();
-
-  // function_info(Function, params_type):
-  indent(f_service_) <<
-    "function_info(" << name_atom << ", params_type) ->" << endl;
-  indent_up();
-
-  indent(f_service_) << render_type_term(arg_struct, true) << ";" << endl;
-
-  indent_down();
-
-  // function_info(Function, reply_type):
-  indent(f_service_) <<
-    "function_info(" << name_atom << ", reply_type) ->" << endl;
-  indent_up();
-
-  if (!tfunction->get_returntype()->is_void())
-    indent(f_service_) <<
-        render_type_term(tfunction->get_returntype(), false) << ";" << endl;
-  else if (tfunction->is_oneway())
-    indent(f_service_) << "oneway_void;" << endl;
-  else
-    indent(f_service_) << "{struct, []}" << ";" << endl;
-  indent_down();
-
-  // function_info(Function, exceptions):
-  indent(f_service_) <<
-    "function_info(" << name_atom << ", exceptions) ->" << endl;
-  indent_up();
-  indent(f_service_) << render_type_term(xs, true) << ";" << endl;
-  indent_down();
-}
-
-/**
- * Renders a function signature of the form 'type name(args)'
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_erl_generator::function_signature(t_function* tfunction,
-                                           string prefix) {
-  return
-    prefix + tfunction->get_name() +
-    "(This" +  capitalize(argument_list(tfunction->get_arglist())) + ")";
-}
-
-/**
- * Add a function to the exports list
- */
-void t_erl_generator::export_string(string name, int num) {
-  if (export_lines_first_) {
-    export_lines_first_ = false;
-  } else {
-    export_lines_ << ", ";
-  }
-  export_lines_ << name << "/" << num;
-}
-
-void t_erl_generator::export_types_function(t_function* tfunction,
-                                               string prefix) {
-
-  export_types_string(prefix + tfunction->get_name(),
-                      1 // This
-                      + ((tfunction->get_arglist())->get_members()).size()
-                      );
-}
-
-void t_erl_generator::export_types_string(string name, int num) {
-  if (export_types_lines_first_) {
-    export_types_lines_first_ = false;
-  } else {
-    export_types_lines_ << ", ";
-  }
-  export_types_lines_ << name << "/" << num;
-}
-
-void t_erl_generator::export_function(t_function* tfunction,
-                                      string prefix) {
-
-  export_string(prefix + tfunction->get_name(),
-                1 // This
-                + ((tfunction->get_arglist())->get_members()).size()
-                );
-}
-
-
-/**
- * Renders a field list
- */
-string t_erl_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;
-      result += ", "; // initial comma to compensate for initial This
-    } else {
-      result += ", ";
-    }
-    result += capitalize((*f_iter)->get_name());
-  }
-  return result;
-}
-
-string t_erl_generator::type_name(t_type* ttype) {
-  string prefix = "";
-  string name = ttype->get_name();
-
-  if (ttype->is_struct() || ttype->is_xception() || ttype->is_service()) {
-    name = uncapitalize(ttype->get_name());
-  }
-
-  return prefix + name;
-}
-
-/**
- * Converts the parse type to a Erlang "type" (macro for int constants)
- */
-string t_erl_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 "?tType_STRING";
-    case t_base_type::TYPE_BOOL:
-      return "?tType_BOOL";
-    case t_base_type::TYPE_BYTE:
-      return "?tType_BYTE";
-    case t_base_type::TYPE_I16:
-      return "?tType_I16";
-    case t_base_type::TYPE_I32:
-      return "?tType_I32";
-    case t_base_type::TYPE_I64:
-      return "?tType_I64";
-    case t_base_type::TYPE_DOUBLE:
-      return "?tType_DOUBLE";
-    }
-  } else if (type->is_enum()) {
-    return "?tType_I32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "?tType_STRUCT";
-  } else if (type->is_map()) {
-    return "?tType_MAP";
-  } else if (type->is_set()) {
-    return "?tType_SET";
-  } else if (type->is_list()) {
-    return "?tType_LIST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-
-/**
- * Generate an Erlang term which represents a thrift type
- */
-std::string t_erl_generator::render_type_term(t_type* type, bool expand_structs, bool extended_info) {
-    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 "string";
-    case t_base_type::TYPE_BOOL:
-      return "bool";
-    case t_base_type::TYPE_BYTE:
-      return "byte";
-    case t_base_type::TYPE_I16:
-      return "i16";
-    case t_base_type::TYPE_I32:
-      return "i32";
-    case t_base_type::TYPE_I64:
-      return "i64";
-    case t_base_type::TYPE_DOUBLE:
-      return "double";
-    }
-  } else if (type->is_enum()) {
-    return "i32";
-  } else if (type->is_struct() || type->is_xception()) {
-    if (expand_structs) {
-
-      std::stringstream buf;
-      buf << "{struct, [";
-      string field_indent(buf.str().size(), ' ');
-
-      t_struct::members_type const& fields = static_cast<t_struct*>(type)->get_members();
-      t_struct::members_type::const_iterator i, end = fields.end();
-      for( i = fields.begin(); i != end; )
-      {
-        t_struct::members_type::value_type member = *i;
-        int32_t key  = member->get_key();
-        string  type = render_type_term(member->get_type(), false, false); // recursive call
-
-        if ( !extended_info ) {
-          // Convert to format: {struct, [{Fid, Type}|...]}
-          buf << "{" << key << ", "  << type << "}";
-        } else {
-          // Convert to format: {struct, [{Fid, Req, Type, Name, Def}|...]}
-          string  name         = uncapitalize(member->get_name());
-          string  value        = render_member_value(member);
-          string  requiredness = render_member_requiredness(member);
-          buf << "{" << key << ", "  << requiredness << ", "  << type << ", '" << name << "'"<< ", "  << value << "}";
-        }
-
-        if ( ++i != end ) {
-          buf << "," << endl << field_indent;
-        }
-      }
-
-      buf << "]}" << endl;
-      return buf.str();
-    } else {
-      return "{struct, {'" + type_module(type) + "', '" + type_name(type) + "'}}";
-    }
-  } else if (type->is_map()) {
-    // {map, KeyType, ValType}
-    t_type *key_type = ((t_map*)type)->get_key_type();
-    t_type *val_type = ((t_map*)type)->get_val_type();
-
-    return "{map, " + render_type_term(key_type, false) + ", " +
-      render_type_term(val_type, false) + "}";
-
-  } else if (type->is_set()) {
-    t_type *elem_type = ((t_set*)type)->get_elem_type();
-
-    return "{set, " + render_type_term(elem_type, false) + "}";
-
-  } else if (type->is_list()) {
-    t_type *elem_type = ((t_list*)type)->get_elem_type();
-
-    return "{list, " + render_type_term(elem_type, false) + "}";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-std::string t_erl_generator::type_module(t_type* ttype) {
-  return uncapitalize(ttype->get_program()->get_name()) + "_types";
-}
-
-THRIFT_REGISTER_GENERATOR(erl, "Erlang", "")
-
diff --git a/compiler/cpp/src/generate/t_generator.cc b/compiler/cpp/src/generate/t_generator.cc
deleted file mode 100644
index 67a3e78..0000000
--- a/compiler/cpp/src/generate/t_generator.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include "t_generator.h"
-using namespace std;
-
-/**
- * Top level program generation function. Calls the generator subclass methods
- * for preparing file streams etc. then iterates over all the parts of the
- * program to perform the correct actions.
- *
- * @param program The thrift program to compile into C++ source
- */
-void t_generator::generate_program() {
-  // Initialize the generator
-  init_generator();
-
-  // Generate enums
-  vector<t_enum*> enums = program_->get_enums();
-  vector<t_enum*>::iterator en_iter;
-  for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
-    generate_enum(*en_iter);
-  }
-
-  // Generate typedefs
-  vector<t_typedef*> typedefs = program_->get_typedefs();
-  vector<t_typedef*>::iterator td_iter;
-  for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
-    generate_typedef(*td_iter);
-  }
-
-  // Generate structs, exceptions, and unions in declared order
-  vector<t_struct*> objects = program_->get_objects();
-  vector<t_struct*>::iterator o_iter;
-  for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
-    if ((*o_iter)->is_xception()) {
-      generate_xception(*o_iter);
-    } else {
-      generate_struct(*o_iter);
-    }
-  }
-
-  // Generate constants
-  vector<t_const*> consts = program_->get_consts();
-  generate_consts(consts);
-
-  // Generate services
-  vector<t_service*> services = program_->get_services();
-  vector<t_service*>::iterator sv_iter;
-  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
-    service_name_ = get_service_name(*sv_iter);
-    generate_service(*sv_iter);
-  }
-
-  // Close the generator
-  close_generator();
-}
-
-string t_generator::escape_string(const string &in) const {
-  string result = "";
-  for (string::const_iterator it = in.begin(); it < in.end(); it++) {
-    std::map<char, std::string>::const_iterator res = escape_.find(*it);
-    if (res != escape_.end()) {
-      result.append(res->second);
-    } else {
-      result.push_back(*it);
-    }
-  }
-  return result;
-}
-
-void t_generator::generate_consts(vector<t_const*> consts) {
-  vector<t_const*>::iterator c_iter;
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    generate_const(*c_iter);
-  }
-}
-
-void t_generator::generate_docstring_comment(ofstream& out,
-                                             const string& comment_start,
-                                             const string& line_prefix,
-                                             const string& contents,
-                                             const string& comment_end) {
-  if (comment_start != "") indent(out) << comment_start;
-  stringstream docs(contents, ios_base::in);
-  while (!docs.eof()) {
-    char line[1024];
-    docs.getline(line, 1024);
-
-    // Just prnt a newline when the line & prefix are empty.
-    if (strlen(line) == 0 && line_prefix == "" && !docs.eof()) {
-        out << std::endl;
-    } else if (strlen(line) > 0 || !docs.eof()) {  // skip the empty last line
-      indent(out) << line_prefix << line << std::endl;
-    }
-  }
-  if (comment_end != "") indent(out) << comment_end;
-}
-
-
-void t_generator_registry::register_generator(t_generator_factory* factory) {
-  gen_map_t& the_map = get_generator_map();
-  if (the_map.find(factory->get_short_name()) != the_map.end()) {
-    failure("Duplicate generators for language \"%s\"!\n", factory->get_short_name().c_str());
-  }
-  the_map[factory->get_short_name()] = factory;
-}
-
-t_generator* t_generator_registry::get_generator(t_program* program,
-                                                 const string& options) {
-  string::size_type colon = options.find(':');
-  string language = options.substr(0, colon);
-
-  map<string, string> parsed_options;
-  if (colon != string::npos) {
-    string::size_type pos = colon+1;
-    while (pos != string::npos && pos < options.size()) {
-      string::size_type next_pos = options.find(',', pos);
-      string option = options.substr(pos, next_pos-pos);
-      pos = ((next_pos == string::npos) ? next_pos : next_pos+1);
-
-      string::size_type separator = option.find('=');
-      string key, value;
-      if (separator == string::npos) {
-        key = option;
-        value = "";
-      } else {
-        key = option.substr(0, separator);
-        value = option.substr(separator+1);
-      }
-
-      parsed_options[key] = value;
-    }
-  }
-
-  gen_map_t& the_map = get_generator_map();
-  gen_map_t::iterator iter = the_map.find(language);
-
-  if (iter == the_map.end()) {
-    return NULL;
-  }
-
-  return iter->second->get_generator(program, parsed_options, options);
-}
-
-t_generator_registry::gen_map_t& t_generator_registry::get_generator_map() {
-  // http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12
-  static gen_map_t* the_map = new gen_map_t();
-  return *the_map;
-}
-
-t_generator_factory::t_generator_factory(
-    const std::string& short_name,
-    const std::string& long_name,
-    const std::string& documentation)
-  : short_name_(short_name)
-  , long_name_(long_name)
-  , documentation_(documentation)
-{
-  t_generator_registry::register_generator(this);
-}
diff --git a/compiler/cpp/src/generate/t_generator.h b/compiler/cpp/src/generate/t_generator.h
deleted file mode 100644
index 25b532b..0000000
--- a/compiler/cpp/src/generate/t_generator.h
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_GENERATOR_H
-#define T_GENERATOR_H
-
-#include <string>
-#include <iostream>
-#include <fstream>
-#include <sstream>
-#include "parse/t_program.h"
-#include "globals.h"
-#include "t_generator_registry.h"
-
-/**
- * Base class for a thrift code generator. This class defines the basic
- * routines for code generation and contains the top level method that
- * dispatches code generation across various components.
- *
- */
-class t_generator {
- public:
-  t_generator(t_program* program) {
-    tmp_ = 0;
-    indent_ = 0;
-    program_ = program;
-    program_name_ = get_program_name(program);
-    escape_['\n'] = "\\n";
-    escape_['\r'] = "\\r";
-    escape_['\t'] = "\\t";
-    escape_['"']  = "\\\"";
-    escape_['\\'] = "\\\\";
-  }
-
-  virtual ~t_generator() {}
-
-  /**
-   * Framework generator method that iterates over all the parts of a program
-   * and performs general actions. This is implemented by the base class and
-   * should not normally be overwritten in the subclasses.
-   */
-  virtual void generate_program();
-
-  const t_program* get_program() const { return program_; }
-
-  void generate_docstring_comment(std::ofstream& out,
-                                  const std::string& comment_start,
-                                  const std::string& line_prefix,
-                                  const std::string& contents,
-                                  const std::string& comment_end);
-
-  /**
-   * check whether sub-namespace declaraction is used by generator.
-   * e.g. allow
-   * namespace py.twisted bar
-   * to specify namespace to use when -gen py:twisted is specified.
-   * Will be called with subnamespace, i.e. is_valid_namespace("twisted")
-   * will be called for the above example.
-   */
-  static bool is_valid_namespace(const std::string& sub_namespace) {
-    (void) sub_namespace;
-    return false;
-  }
-
-  /**
-   * Escape string to use one in generated sources.
-   */
-  virtual std::string escape_string(const std::string &in) const;
-
-  std::string get_escaped_string(t_const_value* constval) {
-    return escape_string(constval->get_string());
-  }
-
- protected:
-
-  /**
-   * Optional methods that may be imlemented by subclasses to take necessary
-   * steps at the beginning or end of code generation.
-   */
-
-  virtual void init_generator() {}
-  virtual void close_generator() {}
-
-  virtual void generate_consts(std::vector<t_const*> consts);
-
-  /**
-   * Pure virtual methods implemented by the generator subclasses.
-   */
-
-  virtual void generate_typedef  (t_typedef*  ttypedef)  = 0;
-  virtual void generate_enum     (t_enum*     tenum)     = 0;
-  virtual void generate_const    (t_const*    tconst) {
-    (void) tconst;
-  }
-  virtual void generate_struct   (t_struct*   tstruct)   = 0;
-  virtual void generate_service  (t_service*  tservice)  = 0;
-  virtual void generate_xception (t_struct*   txception) {
-    // By default exceptions are the same as structs
-    generate_struct(txception);
-  }
-
-  /**
-   * Method to get the program name, may be overridden
-   */
-  virtual std::string get_program_name(t_program* tprogram) {
-    return tprogram->get_name();
-  }
-
-  /**
-   * Method to get the service name, may be overridden
-   */
-  virtual std::string get_service_name(t_service* tservice) {
-    return tservice->get_name();
-  }
-
-  /**
-   * Get the current output directory
-   */
-  virtual std::string get_out_dir() const {
-    if (program_->is_out_path_absolute()) {
-      return program_->get_out_path() + "/";
-    }
-
-    return program_->get_out_path() + out_dir_base_ + "/";
-  }
-
-  /**
-   * Creates a unique temporary variable name, which is just "name" with a
-   * number appended to it (i.e. name35)
-   */
-  std::string tmp(std::string name) {
-    std::ostringstream out;
-    out << name << tmp_++;
-    return out.str();
-  }
-
-  /**
-   * Indentation level modifiers
-   */
-
-  void indent_up(){
-    ++indent_;
-  }
-
-  void indent_down() {
-    --indent_;
-  }
-
-  /**
-   * Indentation print function
-   */
-  std::string indent() {
-    std::string ind = "";
-    int i;
-    for (i = 0; i < indent_; ++i) {
-      ind += "  ";
-    }
-    return ind;
-  }
-
-  /**
-   * Indentation utility wrapper
-   */
-  std::ostream& indent(std::ostream &os) {
-    return os << indent();
-  }
-
-  /**
-   * Capitalization helpers
-   */
-  std::string capitalize(std::string in) {
-    in[0] = toupper(in[0]);
-    return in;
-  }
-  std::string decapitalize(std::string in) {
-    in[0] = tolower(in[0]);
-    return in;
-  }
-  std::string lowercase(std::string in) {
-    for (size_t i = 0; i < in.size(); ++i) {
-      in[i] = tolower(in[i]);
-    }
-    return in;
-  }
-  /**
-   * Transforms a camel case string to an equivalent one separated by underscores
-   * e.g. aMultiWord -> a_multi_word
-   *      someName   -> some_name
-   *      CamelCase  -> camel_case
-   *      name       -> name
-   *      Name       -> name
-   */
-  std::string underscore(std::string in) {
-    in[0] = tolower(in[0]);
-    for (size_t i = 1; i < in.size(); ++i) {
-      if (isupper(in[i])) {
-        in[i] = tolower(in[i]);
-        in.insert(i, "_");
-      }
-    }
-    return in;
-  }
-  /**
-    * Transforms a string with words separated by underscores to a camel case equivalent
-    * e.g. a_multi_word -> aMultiWord
-    *      some_name    ->  someName
-    *      name         ->  name
-    */
-  std::string camelcase(std::string in) {
-    std::ostringstream out;
-    bool underscore = false;
-
-    for (size_t i = 0; i < in.size(); i++) {
-      if (in[i] == '_') {
-        underscore = true;
-        continue;
-      }
-      if (underscore) {
-        out << (char) toupper(in[i]);
-        underscore = false;
-        continue;
-      }
-      out << in[i];
-    }
-
-    return out.str();
-  }
-
- public:
-  /**
-   * Get the true type behind a series of typedefs.
-   */
-  static t_type* get_true_type(t_type* type) {
-    return type->get_true_type();
-  }
-
- protected:
-  /**
-   * The program being generated
-   */
-  t_program* program_;
-
-  /**
-   * Quick accessor for formatted program name that is currently being
-   * generated.
-   */
-  std::string program_name_;
-
-  /**
-   * Quick accessor for formatted service name that is currently being
-   * generated.
-   */
-  std::string service_name_;
-
-  /**
-   * Output type-specifc directory name ("gen-*")
-   */
-  std::string out_dir_base_;
-
-  /**
-   * Map of characters to escape in string literals.
-   */
-  std::map<char, std::string> escape_;
-
- private:
-  /**
-   * Current code indentation level
-   */
-  int indent_;
-
-  /**
-   * Temporary variable counter, for making unique variable names
-   */
-  int tmp_;
-};
-
-#endif
diff --git a/compiler/cpp/src/generate/t_generator_registry.h b/compiler/cpp/src/generate/t_generator_registry.h
deleted file mode 100644
index 0010e94..0000000
--- a/compiler/cpp/src/generate/t_generator_registry.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_GENERATOR_REGISTRY_H
-#define T_GENERATOR_REGISTRY_H
-
-class t_generator;
-
-/**
- * A factory for producing generator classes of a particular language.
- *
- * This class is also responsible for:
- *  - Registering itself with the generator registry.
- *  - Providing documentation for the generators it produces.
- */
-class t_generator_factory {
- public:
-  t_generator_factory(const std::string& short_name,
-                      const std::string& long_name,
-                      const std::string& documentation);
-
-  virtual ~t_generator_factory() {}
-
-  virtual t_generator* get_generator(
-      // The program to generate.
-      t_program* program,
-      // Note: parsed_options will not exist beyond the call to get_generator.
-      const std::map<std::string, std::string>& parsed_options,
-      // Note: option_string might not exist beyond the call to get_generator.
-      const std::string& option_string)
-    = 0;
-
-  virtual bool is_valid_namespace(const std::string& sub_namespace) = 0;
-
-  std::string get_short_name() { return short_name_; }
-  std::string get_long_name() { return long_name_; }
-  std::string get_documentation() { return documentation_; }
-
- private:
-  std::string short_name_;
-  std::string long_name_;
-  std::string documentation_;
-};
-
-template <typename generator>
-class t_generator_factory_impl : public t_generator_factory {
- public:
-  t_generator_factory_impl(const std::string& short_name,
-                           const std::string& long_name,
-                           const std::string& documentation)
-    : t_generator_factory(short_name, long_name, documentation)
-  {}
-
-  virtual t_generator* get_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string) {
-    return new generator(program, parsed_options, option_string);
-  }
-
-  virtual bool is_valid_namespace(const std::string& sub_namespace) {
-    return generator::is_valid_namespace(sub_namespace);
-  }
-};
-
-class t_generator_registry {
- public:
-  static void register_generator(t_generator_factory* factory);
-
-  static t_generator* get_generator(t_program* program,
-                                    const std::string& options);
-
-  typedef std::map<std::string, t_generator_factory*> gen_map_t;
-  static gen_map_t& get_generator_map();
-
- private:
-  t_generator_registry();
-  t_generator_registry(const t_generator_registry&);
-};
-
-#define THRIFT_REGISTER_GENERATOR(language, long_name, doc)        \
-  class t_##language##_generator_factory_impl                      \
-    : public t_generator_factory_impl<t_##language##_generator>    \
-  {                                                                \
-   public:                                                         \
-    t_##language##_generator_factory_impl()                        \
-      : t_generator_factory_impl<t_##language##_generator>(        \
-          #language, long_name, doc)                               \
-    {}                                                             \
-  };                                                               \
-  static t_##language##_generator_factory_impl _registerer;
-
-#endif
diff --git a/compiler/cpp/src/generate/t_go_generator.cc b/compiler/cpp/src/generate/t_go_generator.cc
deleted file mode 100644
index eecc836..0000000
--- a/compiler/cpp/src/generate/t_go_generator.cc
+++ /dev/null
@@ -1,3344 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*
- * This file is programmatically sanitized for style:
- * astyle --style=1tbs -f -p -H -j -U t_go_generator.cc
- *
- * The output of astyle should not be taken unquestioningly, but it is a good
- * guide for ensuring uniformity and readability.
- */
-
-#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"
-#include "version.h"
-
-using namespace std;
-
-/**
- * A helper for automatically formatting the emitted Go code from the Thrift
- * IDL per the Go style guide.
- *
- * Returns:
- *  - true, if the formatting process succeeded.
- *  - false, if the formatting process failed, which means the basic output was
- *           still generated.
- */
-bool format_go_output(const string &file_path);
-
-const string default_thrift_import = "git.apache.org/thrift.git/lib/go/thrift";
-
-/**
- * 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";
-        gen_thrift_import_ = default_thrift_import;
-
-        iter = parsed_options.find("package_prefix");
-
-        if (iter != parsed_options.end()) {
-            gen_package_prefix_ = (iter->second);
-        }
-
-        iter = parsed_options.find("thrift_import");
-
-        if (iter != parsed_options.end()) {
-            gen_thrift_import_ = (iter->second);
-        }
-    }
-
-    /**
-     * 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_isset_helpers(std::ofstream& out, t_struct* tstruct, const string& tstruct_name, 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 = "",
-                                    bool inclass = false,
-                                    bool coerceData = false);
-
-    void generate_deserialize_struct(std::ofstream &out,
-                                     t_struct*   tstruct,
-                                     bool        declare,
-                                     std::string prefix = "");
-
-    void generate_deserialize_container(std::ofstream &out,
-                                        t_type*     ttype,
-                                        bool        declare,
-                                        std::string prefix = "");
-
-    void generate_deserialize_set_element(std::ofstream &out,
-                                          t_set*      tset,
-                                          bool        declare,
-                                          std::string prefix = "");
-
-    void generate_deserialize_map_element(std::ofstream &out,
-                                          t_map*      tmap,
-                                          bool        declare,
-                                          std::string prefix = "");
-
-    void generate_deserialize_list_element(std::ofstream &out,
-                                           t_list*     tlist,
-                                           bool        declare,
-                                           std::string prefix = "");
-
-    void generate_serialize_field(std::ofstream &out,
-                                  t_field*    tfield,
-                                  std::string prefix = "");
-
-    void generate_serialize_struct(std::ofstream &out,
-                                   t_struct*   tstruct,
-                                   std::string prefix = "");
-
-    void generate_serialize_container(std::ofstream &out,
-                                      t_type*     ttype,
-                                      std::string prefix = "");
-
-    void generate_serialize_map_element(std::ofstream &out,
-                                        t_map*      tmap,
-                                        std::string kiter,
-                                        std::string viter);
-
-    void generate_serialize_set_element(std::ofstream &out,
-                                        t_set*      tmap,
-                                        std::string iter);
-
-    void generate_serialize_list_element(std::ofstream &out,
-                                         t_list*     tlist,
-                                         std::string iter);
-
-    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_begin();
-    std::string go_imports_end();
-    std::string render_includes();
-    std::string render_import_protection();
-    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 addError = 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_go_key_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:
-
-    std::string gen_package_prefix_;
-    std::string gen_thrift_import_;
-
-    /**
-     * File streams
-     */
-
-    std::ofstream f_types_;
-    std::string f_types_name_;
-    std::ofstream f_consts_;
-    std::string f_consts_name_;
-    std::stringstream f_const_values_;
-    std::ofstream f_service_;
-
-    std::string package_name_;
-    std::string package_dir_;
-
-    static std::string publicize(const std::string& value);
-    static std::string new_prefix(const std::string& value);
-    static std::string privatize(const std::string& value);
-    static std::string variable_name_to_go_name(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), prefix;
-
-    string::size_type dot_pos = value.rfind('.');
-    if (dot_pos != string::npos) {
-      prefix = value.substr(0, dot_pos + 1) + prefix;
-      value2 = value.substr(dot_pos + 1);
-    }
-
-    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] == '_' && islower(value2[i + 1])) {
-            value2.replace(i, 2, 1, toupper(value2[i + 1]));
-        }
-    }
-
-    return prefix + value2;
-}
-
-std::string t_go_generator::new_prefix(const std::string& value)
-{
-    if (value.size() <= 0) {
-        return value;
-    }
-
-    string::size_type dot_pos = value.rfind('.');
-    if (dot_pos != string::npos) {
-      return value.substr(0, dot_pos + 1) + "New" + publicize(value.substr(dot_pos + 1));
-    }
-    return "New" + publicize(value);
-}
-
-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;
-}
-
-std::string t_go_generator::variable_name_to_go_name(const std::string& value)
-{
-    if (value.size() <= 0) {
-        return value;
-    }
-
-    std::string value2(value);
-    std::transform(value2.begin(), value2.end(), value2.begin(), ::tolower);
-
-    switch (value[0]) {
-    case 'b':
-    case 'B':
-        if (value2 != "break") {
-            return value;
-        }
-
-        break;
-
-    case 'c':
-    case 'C':
-        if (value2 != "case" && value2 != "chan" && value2 != "const" && value2 != "continue") {
-            return value;
-        }
-
-        break;
-
-    case 'd':
-    case 'D':
-        if (value2 != "default" && value2 != "defer") {
-            return value;
-        }
-
-        break;
-
-    case 'e':
-    case 'E':
-        if (value2 != "else" && value2 != "error") {
-            return value;
-        }
-
-        break;
-
-    case 'f':
-    case 'F':
-        if (value2 != "fallthrough" && value2 != "for" && value2 != "func") {
-            return value;
-        }
-
-        break;
-
-    case 'g':
-    case 'G':
-        if (value2 != "go" && value2 != "goto") {
-            return value;
-        }
-
-        break;
-
-    case 'i':
-    case 'I':
-        if (value2 != "if" && value2 != "import" && value2 != "interface") {
-            return value;
-        }
-
-        break;
-
-    case 'm':
-    case 'M':
-        if (value2 != "map") {
-            return value;
-        }
-
-        break;
-
-    case 'p':
-    case 'P':
-        if (value2 != "package") {
-            return value;
-        }
-
-        break;
-
-    case 'r':
-    case 'R':
-        if (value2 != "range" && value2 != "return") {
-            return value;
-        }
-
-        break;
-
-    case 's':
-    case 'S':
-        if (value2 != "select" && value2 != "struct" && value2 != "switch") {
-            return value;
-        }
-
-        break;
-
-    case 't':
-    case 'T':
-        if (value2 != "type") {
-            return value;
-        }
-
-        break;
-
-    case 'v':
-    case 'V':
-        if (value2 != "var") {
-            return value;
-        }
-
-        break;
-
-    default:
-        return value;
-    }
-
-    return value2 + "_a1";
-}
-
-
-/**
- * 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 files
-    f_types_name_ = package_dir_ + "/" + "ttypes.go";
-    f_types_.open(f_types_name_.c_str());
-
-    f_consts_name_ = package_dir_ + "/" + "constants.go";
-    f_consts_.open(f_consts_name_.c_str());
-
-    vector<t_service*> services = program_->get_services();
-    vector<t_service*>::iterator sv_iter;
-
-    for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
-        string service_dir = package_dir_ + "/" + underscore((*sv_iter)->get_name()) + "-remote";
-        MKDIR(service_dir.c_str());
-    }
-
-    // Print header
-    f_types_ <<
-             go_autogen_comment() <<
-             go_package() <<
-             render_includes() <<
-             render_import_protection();
-
-    f_consts_ <<
-              go_autogen_comment() <<
-              go_package() <<
-              render_includes();
-
-    f_const_values_ << endl << "func init() {" << 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 = "";
-    string unused_prot = "";
-
-    for (size_t i = 0; i < includes.size(); ++i) {
-        string go_module = get_real_go_module(includes[i]);
-        size_t found = 0;
-        for (size_t j = 0; j < go_module.size(); j++) {
-            // Import statement uses slashes ('/') in namespace
-            if (go_module[j] == '.') {
-                go_module[j] = '/';
-                found = j + 1;
-            }
-        }
-
-        result += "\t\"" + gen_package_prefix_ + go_module + "\"\n";
-        unused_prot += "var _ = " + go_module.substr(found) + ".GoUnusedProtection__\n";
-    }
-
-    if (includes.size() > 0) {
-        result += "\n";
-    }
-
-    return go_imports_begin() + result + go_imports_end() + unused_prot;
-}
-
-string t_go_generator::render_import_protection() {
-  return string("var GoUnusedProtection__ int;\n\n");
-}
-
-/**
- * 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
-        std::string() +
-        "// Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\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";
-}
-
-/**
- * Render the beginning of the import statement
- */
-string t_go_generator::go_imports_begin()
-{
-    return
-        string("import (\n"
-               "\t\"fmt\"\n"
-               "\t\"math\"\n"
-               "\t\"" + gen_thrift_import_ + "\"\n");
-}
-
-/**
- * End the import statement, include undscore-assignments
- *
- * These "_ =" prevent the go compiler complaining about used imports.
- * This will have to do in lieu of more intelligent import statement construction
- */
-string t_go_generator::go_imports_end()
-{
-    return
-        string(
-            ")\n\n"
-            "// (needed to ensure safety because of naive import list construction.)\n"
-            "var _ = math.MinInt32\n"
-            "var _ = thrift.ZERO\n"
-            "var _ = fmt.Printf\n\n");
-}
-
-/**
- * Closes the type files
- */
-void t_go_generator::close_generator()
-{
-    f_const_values_ << "}" << endl << endl;
-    f_consts_ << f_const_values_.str();
-
-    // Close types and constants files
-    f_consts_.close();
-    f_types_.close();
-    format_go_output(f_types_name_);
-    format_go_output(f_consts_name_);
-}
-
-/**
- * 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 << " int64" << endl <<
-             "const (" << endl;
-    to_string_mapping <<
-                      indent() << "func (p " << tenum_name << ") String() string {" << endl <<
-                      indent() << "  switch p {" << endl;
-    from_string_mapping <<
-                        indent() << "func " << tenum_name << "FromString(s string) (" << tenum_name << ", error) {" << 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() << "  " << tenum_name << "_" << iter_name << ' ' << tenum_name << " = " << value << endl;
-        // Dictionaries to/from string names of enums
-        to_string_mapping <<
-                          indent() << "  case " << tenum_name << "_" << iter_name << ": return \"" << tenum_name << "_" << iter_std_name << "\"" << endl;
-
-        if (iter_std_name != escape_string(iter_name)) {
-            from_string_mapping <<
-                                indent() << "  case \"" << tenum_name << "_" << iter_std_name << "\", \"" << escape_string(iter_name) << "\": return " <<
-                                tenum_name << "_" << iter_name << ", nil " << endl;
-        } else {
-            from_string_mapping <<
-                                indent() << "  case \"" << tenum_name << "_" << iter_std_name << "\": return " <<
-                                tenum_name << "_" << iter_name << ", nil "  << endl;
-        }
-    }
-
-    to_string_mapping <<
-                      indent() << "  }" << endl <<
-                      indent() << "  return \"<UNSET>\"" << endl <<
-                      indent() << "}" << endl;
-    from_string_mapping <<
-                        indent() << "  }" << endl <<
-                        indent() << "  return " << tenum_name << "(math.MinInt32 - 1)," <<
-                        " fmt.Errorf(\"not a valid " << tenum_name << " string\")" << endl <<
-                        indent() << "}" << endl;
-
-    f_types_ << ")" << endl << endl
-             << to_string_mapping.str() << endl
-             << from_string_mapping.str() << 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_consts_) << "const " << name << " = " << render_const_value(type, value, name) << endl;
-    } else {
-        f_const_values_ <<
-                        indent() << name << " = " << render_const_value(type, value, name) << endl << endl;
-
-        f_consts_ <<
-                  indent() << "var " << name << " " << type_to_go_type(type) << 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:
-            if (((t_base_type*)type)->is_binary()) {
-                out << "[]byte(\"" << get_escaped_string(value) << "\")";
-            } else {
-                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 <<
-            "&" << publicize(type_name(type)) << "{";
-        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 << endl <<
-                    indent() << publicize(v_iter->first->get_string()) << ": " << render_const_value(field_type, v_iter->second, name) << ",";
-            } else {
-                string k(tmp("k"));
-                string v(tmp("v"));
-                out << endl <<
-                    indent() << v << " := " << render_const_value(field_type, v_iter->second, v) << endl <<
-                    indent() << name << "." << publicize(v_iter->first->get_string()) << " = " << v;
-            }
-        }
-
-        out << "}";
-
-        indent_down();
-    } 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 <<
-            "map[" << type_to_go_type(ktype) << "]" << type_to_go_type(vtype) << "{" << 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) {
-            out <<
-                indent() << render_const_value(ktype, v_iter->first, name) << ": " <<
-                render_const_value(vtype, v_iter->second, name) << "," << endl;
-        }
-
-        indent_down();
-        out <<
-            indent() << "}";
-    } else if (type->is_list()) {
-        t_type* etype = ((t_list*)type)->get_elem_type();
-        const vector<t_const_value*>& val = value->get_list();
-        out <<
-            "[]" << type_to_go_type(etype) << "{" << endl;
-        indent_up();
-        vector<t_const_value*>::const_iterator v_iter;
-
-        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-            out <<
-                indent() << render_const_value(etype, *v_iter, name) << ", ";
-        }
-
-        indent_down();
-        out <<
-            indent() << "}";
-    } else if (type->is_set()) {
-        t_type* etype = ((t_set*)type)->get_elem_type();
-        const vector<t_const_value*>& val = value->get_list();
-        out <<
-            "map[" << type_to_go_key_type(etype) << "]bool{" << endl;
-        indent_up();
-        vector<t_const_value*>::const_iterator v_iter;
-
-        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-            out <<
-                indent() << render_const_value(etype, *v_iter, name) << ": true," << endl;
-
-        }
-
-        indent_down();
-        out <<
-            indent() << "}";
-    } 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;
-
-    std::string tstruct_name(publicize(tstruct->get_name()));
-    out <<
-        indent() << "type " << tstruct_name << " struct {" << 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) << "// unused field # " << sorted_keys_pos << endl;
-                }
-            }
-
-            t_type* fieldType = (*m_iter)->get_type();
-            string goType(type_to_go_type(fieldType));
-
-            indent(out) << publicize(variable_name_to_go_name((*m_iter)->get_name())) << " "
-                        << goType << " `thrift:\""
-                        << escape_string((*m_iter)->get_name())
-                        << "," << sorted_keys_pos;
-
-            if ((*m_iter)->get_req() == t_field::T_REQUIRED) {
-                out << ",required";
-            }
-
-            out << "\"`" << 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_go_type((*m_iter)->get_type()) << endl;
-        }
-    }
-
-    indent_down();
-    out <<
-        indent() << "}" << endl << endl <<
-        indent() << "func New" << tstruct_name << "() *" << tstruct_name << " {" << endl <<
-        indent() << "  return &" << tstruct_name << "{";
-
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-        // Initialize fields
-        const string base_field_name = (*m_iter)->get_name();
-        const string escaped_field_name = escape_string(base_field_name);
-        const string go_safe_name = variable_name_to_go_name(escaped_field_name);
-        const string publicized_name = publicize(go_safe_name);
-        const t_type* type = get_true_type((*m_iter)->get_type());
-        const bool has_default_value = (*m_iter)->get_value() != NULL;
-        const bool type_is_enum = type->is_enum();
-
-        if (has_default_value) {
-            out << endl << indent() << publicized_name << ": " << render_field_default_value(*m_iter, base_field_name) << "," << endl;
-        } else if (type_is_enum) {
-            out << endl << indent() << publicized_name << ": math.MinInt32 - 1, // unset sentinal value" << endl;
-        }
-    }
-
-    out << "}" << endl;
-    out << "}" << endl << endl;
-    generate_isset_helpers(out, tstruct, tstruct_name, is_result);
-    generate_go_struct_reader(out, tstruct, tstruct_name, is_result);
-    generate_go_struct_writer(out, tstruct, tstruct_name, is_result);
-
-    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;
-
-}
-
-/**
- * Generates the IsSet helper methods for a struct
- */
-void t_go_generator::generate_isset_helpers(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;
-    const string escaped_tstruct_name(escape_string(tstruct->get_name()));
-
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-        t_type* type = get_true_type((*f_iter)->get_type());
-
-        if ((*f_iter)->get_req() == t_field::T_OPTIONAL || type->is_enum()) {
-            const string field_name(publicize(variable_name_to_go_name(escape_string((*f_iter)->get_name()))));
-            t_const_value* field_default_value = (*f_iter)->get_value();
-            out <<
-                indent() << "func (p *" << tstruct_name << ") IsSet" << field_name << "() bool {" << endl;
-            indent_up();
-            string s_check_value;
-            int64_t i_check_value;
-            double d_check_value;
-
-            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:
-                    if (((t_base_type*)type)->is_binary()) {
-                        // ignore default value for binary
-                        out <<
-                            indent() << "return p." << field_name << " != nil" << endl;
-                    } else {
-                        s_check_value = (field_default_value == NULL) ? "\"\"" : render_const_value(type, field_default_value, tstruct_name);
-                        out <<
-                            indent() << "return p." << field_name << " != " << s_check_value << endl;
-                    }
-
-                    break;
-
-                case t_base_type::TYPE_BOOL:
-                    s_check_value = (field_default_value != NULL && field_default_value->get_integer() > 0) ? "true" : "false";
-                    out <<
-                        indent() << "return p." << field_name << " != " << s_check_value << endl;
-                    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:
-                    i_check_value = (field_default_value == NULL) ? 0 : field_default_value->get_integer();
-                    out <<
-                        indent() << "return p." << field_name << " != " << i_check_value << endl;
-                    break;
-
-                case t_base_type::TYPE_DOUBLE:
-                    d_check_value = (field_default_value == NULL) ? 0.0 : field_default_value->get_double();
-                    out <<
-                        indent() << "return p." << field_name << " != " << d_check_value << endl;
-                    break;
-
-                default:
-                    throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
-                }
-            } else if (type->is_enum()) {
-                out << indent() << "return int64(p." << field_name << ") != "
-                    << "math.MinInt32 - 1" << endl;
-            } else if (type->is_struct() || type->is_xception()) {
-                out <<
-                    indent() << "return p." << field_name << " != nil" << endl;
-            } else if (type->is_list() || type->is_set()) {
-                if (field_default_value != NULL && field_default_value->get_list().size() > 0) {
-                    out <<
-                        indent() << "return p." << field_name << " != nil" << endl;
-                } else {
-                    out <<
-                        indent() << "return p." << field_name << " != nil && len(p." << field_name << ") > 0" << endl;
-                }
-            } else if (type->is_map()) {
-                if (field_default_value != NULL && field_default_value->get_map().size() > 0) {
-                    out <<
-                        indent() << "return p." << field_name << " != nil" << endl;
-                } else {
-                    out <<
-                        indent() << "return p." << field_name << " != nil && len(p." << field_name << ") > 0" << endl;
-                }
-            } else {
-                throw "CANNOT GENERATE ISSET HELPERS FOR TYPE: " + type->get_name();
-            }
-
-            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) error {" << endl;
-    indent_up();
-    out <<
-        indent() << "if _, err := iprot.ReadStructBegin(); err != nil {" << endl <<
-        indent() << "  return fmt.Errorf(\"%T read error\", p)" << endl <<
-        indent() << "}" << endl;
-    // Loop over reading in fields
-    indent(out) << "for {" << endl;
-    indent_up();
-    // Read beginning field marker
-    out <<
-        indent() << "_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()" << endl <<
-        indent() << "if err != nil {" << endl <<
-        indent() << "  return fmt.Errorf(\"%T field %d read error: %s\", p, fieldId, 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;
-    string thriftFieldTypeId;
-    // 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) << "switch fieldId {" << endl;
-        }
-
-        // if negative id, ensure we generate a valid method name
-        string field_method_prefix("readField");
-
-        if (field_id < 0) {
-            field_method_prefix += "_";
-            field_id *= -1;
-        }
-
-        indent_up();
-        out << "case " << field_id << ":" << endl;
-        thriftFieldTypeId = type_to_enum((*f_iter)->get_type());
-
-        if (thriftFieldTypeId == "thrift.BINARY") {
-            thriftFieldTypeId = "thrift.STRING";
-        }
-
-        out <<
-            indent() << "if err := p." << field_method_prefix << field_id << "(iprot); err != nil {" << endl <<
-            indent() << "  return err" << endl <<
-            indent() << "}" << endl;
-        indent_down();
-    }
-
-    // In the default case we skip the field
-    if (!first) {
-        out <<
-            indent() << "default:" << endl <<
-            indent() << "  if err := iprot.Skip(fieldTypeId); err != nil {" << endl <<
-            indent() << "    return err" << endl <<
-            indent() << "  }" << endl <<
-            indent() << "}" << endl;
-    }
-
-    // Read field end marker
-    out <<
-        indent() << "if err := iprot.ReadFieldEnd(); err != nil {" << endl <<
-        indent() << "  return err" << endl <<
-        indent() << "}" << endl;
-    indent_down();
-    out <<
-        indent() << "}" << endl <<
-        indent() << "if err := iprot.ReadStructEnd(); err != nil {" << endl <<
-        indent() << "  return fmt.Errorf(\"%T read struct end error: %s\", p, err)" << endl <<
-        indent() << "}" << endl <<
-        indent() << "return nil" << 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()));
-        string field_method_prefix("readField");
-        int32_t field_id = (*f_iter)->get_key();
-
-        if (field_id < 0) {
-            field_method_prefix += "_";
-            field_id *= -1;
-        }
-
-        out <<
-            indent() << "func (p *" << tstruct_name << ")  " << field_method_prefix << field_id << "(iprot thrift.TProtocol) error {" << endl;
-        indent_up();
-        generate_deserialize_field(out, *f_iter, false, "p.");
-        indent_down();
-        out <<
-            indent() << "  return nil" << 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) error {" << endl;
-    indent_up();
-    out <<
-        indent() << "if err := oprot.WriteStructBegin(\"" << name << "\"); err != nil {" << endl <<
-        indent() << "  return fmt.Errorf(\"%T write struct begin error: %s\", p, err) }" << endl;
-
-    string field_name;
-    string escape_field_name;
-    //t_const_value* field_default_value;
-    t_field::e_req field_required;
-    bool field_can_be_nil = false;
-    int32_t field_id = -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) {
-            string field_method_prefix("writeField");
-            field_name = (*fr_iter)->get_name();
-            field_id = (*fr_iter)->get_key();
-
-            if (field_id < 0) {
-                field_method_prefix += "_";
-                field_id *= -1;
-            }
-
-            if (can_be_nil((*fr_iter)->get_type()) && field_id != 0) {
-                out <<
-                    indent() << "case p." << publicize(variable_name_to_go_name(field_name)) << " != nil:" << endl <<
-                    indent() << "  if err := p." << field_method_prefix << field_id << "(oprot); err != nil { return err }" << endl;
-            } else {
-                out <<
-                    indent() << "default:" << endl <<
-                    indent() << "  if err := p." << field_method_prefix << field_id << "(oprot); err != nil { return err }" << endl;
-            }
-        }
-
-        out <<
-            indent() << "}" << endl;
-    } else {
-        for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-            string field_method_prefix("writeField");
-            field_name = (*f_iter)->get_name();
-            escape_field_name = escape_string(field_name);
-            field_id = (*f_iter)->get_key();
-
-            if (field_id < 0) {
-                field_method_prefix += "_";
-                field_id *= -1;
-            }
-
-            out <<
-                indent() << "if err := p." << field_method_prefix << field_id << "(oprot); err != nil { return err }" << endl;
-
-        }
-    }
-
-    // Write the struct map
-    out <<
-        indent() << "if err := oprot.WriteFieldStop(); err != nil {" << endl <<
-        indent() << "  return fmt.Errorf(\"%T write field stop error: %s\", err) }" << endl <<
-        indent() << "if err := oprot.WriteStructEnd(); err != nil {" << endl <<
-        indent() << "  return fmt.Errorf(\"%T write struct stop error: %s\", err) }" << endl <<
-        indent() << "return nil" << endl;
-    indent_down();
-    out <<
-        indent() << "}" << endl << endl;
-
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-        string field_method_prefix("writeField");
-        field_id = (*f_iter)->get_key();
-        field_name = (*f_iter)->get_name();
-        escape_field_name = escape_string(field_name);
-        //field_default_value = (*f_iter)->get_value();
-        field_required = (*f_iter)->get_req();
-        field_can_be_nil = can_be_nil((*f_iter)->get_type());
-
-        if (field_id < 0) {
-            field_method_prefix += "_";
-            field_id *= -1;
-        }
-
-        out <<
-            indent() << "func (p *" << tstruct_name << ") " << field_method_prefix << field_id << "(oprot thrift.TProtocol) (err error) {" << endl;
-        indent_up();
-
-        // Write field header
-        if (field_can_be_nil) {
-            out <<
-                indent() << "if p." << publicize(variable_name_to_go_name(field_name)) << " != nil {" << endl;
-            indent_up();
-        }
-
-        if (field_required == t_field::T_OPTIONAL || (*f_iter)->get_type()->is_enum()) {
-            out <<
-                indent() << "if p.IsSet" << publicize(variable_name_to_go_name(field_name)) << "() {" << endl;
-            indent_up();
-        }
-
-        out <<
-            indent() << "if err := oprot.WriteFieldBegin(\"" <<
-            escape_field_name << "\", " <<
-            type_to_enum((*f_iter)->get_type()) << ", " <<
-            field_id << "); err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"%T write field begin error " << field_id << ":" << escape_field_name << ": %s\", p, err); }" << endl;
-
-        // Write field contents
-        generate_serialize_field(out, *f_iter, "p.");
-
-
-        // Write field closer
-        out <<
-            indent() << "if err := oprot.WriteFieldEnd(); err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"%T write field end error " << field_id << ":" << escape_field_name << ": %s\", p, err); }" << endl;
-
-        if (field_required == t_field::T_OPTIONAL || (*f_iter)->get_type()->is_enum()) {
-            indent_down();
-            out <<
-                indent() << "}" << endl;
-        }
-
-        if (field_can_be_nil) {
-            indent_down();
-            out <<
-                indent() << "}" << endl;
-        }
-
-        indent_down();
-        out <<
-            indent() << "  return err" << 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_ + "/" + underscore(service_name_) + ".go";
-    f_service_.open(f_service_name.c_str());
-    f_service_ <<
-               go_autogen_comment() <<
-               go_package() <<
-               render_includes();
-
-    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();
-    format_go_output(f_service_name);
-}
-
-/**
- * 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 = 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) + publicize(extends.substr(index + 1)) + "\n";
-        } else {
-            extends_if = "\n" + indent() + 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_field = "";
-    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;
-        }
-    }
-
-    extends_field = extends_client.substr(extends_client.find(".") + 1);
-
-    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_field << ": " << 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_field << ": " << 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() << "if 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_ << variable_name_to_go_name((*fld_iter)->get_name());
-        }
-
-        f_service_ << "); 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 error) {" << endl;
-        indent_up();
-        std::string argsname = publicize((*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(variable_name_to_go_name((*fld_iter)->get_name())) << " = " << variable_name_to_go_name((*fld_iter)->get_name()) << endl;
-        }
-
-        // Write to the stream
-        f_service_ <<
-                   indent() << "err = " << args << ".Write(oprot)" << endl <<
-                   indent() << "oprot.WriteMessageEnd()" << endl <<
-                   indent() << "oprot.Flush()" << endl <<
-                   indent() << "return" << endl;
-        indent_down();
-        f_service_ <<
-                   indent() << "}" << endl << endl;
-
-        if (true) { //!(*f_iter)->is_oneway() || true) {}
-            std::string resultname = publicize((*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 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.NewTApplicationException(thrift.UNKNOWN_APPLICATION_EXCEPTION, \"Unknown Exception\")" << endl <<
-                       indent() << "  var " << error2 << " error" << 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();
-    t_service* parent = tservice->get_extends();
-
-    // collect inherited functions
-    while (parent != NULL) {
-        vector<t_function*> p_functions = parent->get_functions();
-        functions.insert(functions.end(), p_functions.begin(), p_functions.end());
-        parent = parent->get_extends();
-    }
-
-    vector<t_function*>::iterator f_iter;
-    string f_remote_name = package_dir_ + "/" + underscore(service_name_) + "-remote/" + underscore(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() << "        \"math\"" << endl <<
-             indent() << "        \"net\"" << endl <<
-             indent() << "        \"net/url\"" << endl <<
-             indent() << "        \"os\"" << endl <<
-             indent() << "        \"strconv\"" << endl <<
-             indent() << "        \"strings\"" << endl <<
-             indent() << "        \"" + gen_thrift_import_ + "\"" << endl <<
-             indent() << "        \"" << service_module << "\"" << endl <<
-             indent() << ")" << endl <<
-             indent() << endl <<
-             indent() << "func Usage() {" << endl <<
-             indent() << "  fmt.Fprintln(os.Stderr, \"Usage of \", os.Args[0], \" [-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:\")" << endl <<
-             indent() << "  flag.PrintDefaults()" << endl <<
-             indent() << "  fmt.Fprintln(os.Stderr, \"\\nFunctions:\")" << endl;
-
-    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-        f_remote <<
-                 "  fmt.Fprintln(os.Stderr, \"  " << (*f_iter)->get_returntype()->get_name() << " " << (*f_iter)->get_name() << "(";
-        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();
-        bool first = true;
-
-        for (int i = 0; i < num_args; ++i) {
-            if (first) {
-                first = false;
-            } else {
-                f_remote << ", ";
-            }
-
-            f_remote <<
-                     args[i]->get_type()->get_name() << " " << args[i]->get_name();
-        }
-
-        f_remote << ")\")" << endl;
-    }
-
-    f_remote <<
-             indent() << "  fmt.Fprintln(os.Stderr)" << 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 parsedUrl url.URL" << endl <<
-             indent() << "var trans thrift.TTransport" << endl <<
-             indent() << "_ = math.MinInt32 // will become unneeded eventually" << endl <<
-             indent() << "_ = strconv.Atoi" << 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.Parse()" << endl <<
-             indent() << endl <<
-             indent() << "if len(urlString) > 0 {" << endl <<
-             indent() << "  parsedUrl, err := url.Parse(urlString)" << endl <<
-             indent() << "  if err != nil {" << endl <<
-             indent() << "    fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << endl <<
-             indent() << "    flag.Usage()" << endl <<
-             indent() << "  }" << endl <<
-             indent() << "  host = parsedUrl.Host" << endl <<
-             indent() << "  useHttp = len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == \"http\"" << endl <<
-             indent() << "} else if useHttp {" << endl <<
-             indent() << "  _, err := url.Parse(fmt.Sprint(\"http://\", host, \":\", port))" << endl <<
-             indent() << "  if err != nil {" << endl <<
-             indent() << "    fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << endl <<
-             indent() << "    flag.Usage()" << endl <<
-             indent() << "  }" << endl <<
-             indent() << "}" << endl <<
-             indent() << endl <<
-             indent() << "cmd := flag.Arg(0)" << endl <<
-             indent() << "var err error" << endl <<
-             indent() << "if useHttp {" << endl <<
-             indent() << "  trans, err = thrift.NewTHttpClient(parsedUrl.String())" << endl <<
-             indent() << "} else {" << endl <<
-             indent() << "  portStr := fmt.Sprint(port)" << endl <<
-             indent() << "  if strings.Contains(host, \":\") {" << endl <<
-             indent() << "         host, portStr, err = net.SplitHostPort(host)" << endl <<
-             indent() << "         if err != nil {" << endl <<
-             indent() << "                 fmt.Fprintln(os.Stderr, \"error with host:\", err)" << endl <<
-             indent() << "                 os.Exit(1)" << endl <<
-             indent() << "         }" << endl <<
-             indent() << "  }" << endl <<
-             indent() << "  trans, err = thrift.NewTSocket(net.JoinHostPort(host, portStr))" << endl <<
-             indent() << "  if err != nil {" << endl <<
-             indent() << "    fmt.Fprintln(os.Stderr, \"error resolving address:\", err)" << endl <<
-             indent() << "    os.Exit(1)" << endl <<
-             indent() << "  }" << endl <<
-             indent() << "  if framed {" << endl <<
-             indent() << "    trans = thrift.NewTFramedTransport(trans)" << endl <<
-             indent() << "  }" << endl <<
-             indent() << "}" << endl <<
-             indent() << "if err != nil {" << endl <<
-             indent() << "  fmt.Fprintln(os.Stderr, \"Error creating transport\", err)" << 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.Fprintln(os.Stderr, \"Invalid protocol specified: \", protocol)" << 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.Fprintln(os.Stderr, \"Error opening socket to \", host, \":\", port, \" \", err)" << 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.Fprintln(os.Stderr, \"" << escape_string(pubName) << " requires " << num_args << " args\")" << 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.ParseInt(flag.Arg(" << flagArg << "), 10, 64))" << 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.ParseFloat(flag.Arg(" << flagArg << "), 64))" << 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.Fprintln(os.Stderr, \"Invalid function \", cmd)" << endl <<
-             indent() << "}" << endl;
-    indent_down();
-    f_remote <<
-             indent() << "}" << endl;
-    // Close service file
-    f_remote.close();
-    format_go_output(f_remote_name);
-#ifndef _MSC_VER
-    // 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
-         );
-#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() << "  processorMap map[string]thrift.TProcessorFunction" << endl <<
-                   indent() << "  handler " << serviceName << 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, ok bool) {" << endl <<
-                   indent() << "  processor, ok = p.processorMap[key]" << endl <<
-                   indent() << "  return processor, ok" << 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 " << 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 false, err }" << endl <<
-                   indent() << "  if processor, ok := p.GetProcessorFunction(name); ok {" << endl <<
-                   indent() << "    return processor.Process(seqId, iprot, oprot)" << endl <<
-                   indent() << "  }" << 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.Flush()" << endl <<
-                   indent() << "  return false, " << x << endl <<
-                   indent() << "" << endl <<
-                   indent() << "}" << endl << endl;
-    } else {
-        f_service_ <<
-                   indent() << "type " << serviceName << "Processor struct {" << endl <<
-                   indent() << "  *" << extends_processor << endl <<
-                   indent() << "}" << endl << endl <<
-                   indent() << "func New" << serviceName << "Processor(handler " << serviceName << ") *" << serviceName << "Processor {" << endl <<
-                   indent() << "  " << self << " := &" << serviceName << "Processor{" << 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;
-    }
-
-    // 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 " << 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.Error())" << endl <<
-               indent() << "  oprot.WriteMessageBegin(\"" << escape_string(tfunction->get_name()) << "\", thrift.EXCEPTION, seqId)" << endl <<
-               indent() << "  x.Write(oprot)" << endl <<
-               indent() << "  oprot.WriteMessageEnd()" << endl <<
-               indent() << "  oprot.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(variable_name_to_go_name((*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(variable_name_to_go_name((*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.Error())" << endl <<
-               indent() << "  oprot.WriteMessageBegin(\"" << escape_string(tfunction->get_name()) << "\", thrift.EXCEPTION, seqId)" << endl <<
-               indent() << "  x.Write(oprot)" << endl <<
-               indent() << "  oprot.WriteMessageEnd()" << endl <<
-               indent() << "  oprot.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.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 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.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 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.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,
-        bool inclass,
-        bool coerceData)
-{
-    t_type* orig_type = tfield->get_type();
-    t_type* type = get_true_type(orig_type);
-    string name(prefix + publicize(variable_name_to_go_name(tfield->get_name())));
-
-    if (type->is_void()) {
-        throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + name;
-    }
-
-    if (type->is_struct() || type->is_xception()) {
-        generate_deserialize_struct(out,
-                                    (t_struct*)type,
-                                    declare,
-                                    name);
-    } else if (type->is_container()) {
-        generate_deserialize_container(out, type, declare, name);
-    } else if (type->is_base_type() || type->is_enum()) {
-
-        if (declare) {
-            out << "var " << tfield->get_name() << " " << type_to_go_type(tfield->get_type()) << endl;
-        }
-
-        indent(out) <<
-                    "if v, err := 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:
-                if (((t_base_type*)type)->is_binary()) {
-                    out << "ReadBinary()";
-                } else {
-                    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()";
-        }
-
-        out << "; err != nil {" << endl <<
-            indent() << "return fmt.Errorf(\"error reading field " <<
-            tfield->get_key()  << ": %s\")" << endl;
-
-        out << "} else {" << endl;
-        string wrap;
-
-        if (type->is_enum() || orig_type->is_typedef()) {
-            wrap = publicize(type_name(orig_type));
-        } else if (((t_base_type*)type)->get_base() == t_base_type::TYPE_BYTE) {
-            wrap = "int8";
-        }
-
-        if (wrap == "") {
-            indent(out) << name << " = v" << endl;
-        } else {
-            indent(out) << name << " = " << wrap << "(v)" << endl;
-        }
-
-        out << "}" << 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 eq(" := ");
-
-    if (!declare) {
-        eq = " = ";
-    }
-
-    out <<
-        indent() << prefix << eq << new_prefix(type_name(tstruct)) << "()" << endl <<
-        indent() << "if err := " << prefix << ".Read(iprot); err != nil {" << endl <<
-        indent() << "  return fmt.Errorf(\"%T error reading struct: %s\", " << prefix << ")" << endl <<
-        indent() << "}" << endl;
-}
-
-/**
- * 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 eq(" = ");
-
-    if (declare) {
-        eq = " := ";
-    }
-
-    // Declare variables, read header
-    if (ttype->is_map()) {
-        t_map* t = (t_map*)ttype;
-        out <<
-            indent() << "_, _, size, err := iprot.ReadMapBegin()" << endl <<
-            indent() << "if err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"error reading map begin: %s\")" << endl <<
-            indent() << "}" << endl <<
-            indent() << prefix << eq << "make(map[" << type_to_go_type(t->get_key_type()) << "]" <<  type_to_go_type(t->get_val_type()) << ", size)" << endl;
-    } else if (ttype->is_set()) {
-        t_set* t = (t_set*)ttype;
-        out <<
-            indent() << "_, size, err := iprot.ReadSetBegin()" << endl <<
-            indent() << "if err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"error reading set being: %s\")" << endl <<
-            indent() << "}" << endl <<
-            indent() << prefix << eq << "make(map[" << type_to_go_type(t->get_elem_type()) << "]bool, size)" << endl;
-    } else if (ttype->is_list()) {
-        t_list* t = (t_list*)ttype;
-        out <<
-            indent() << "_, size, err := iprot.ReadListBegin()" << endl <<
-            indent() << "if err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"error reading list being: %s\")" << endl <<
-            indent() << "}" << endl <<
-            indent() << prefix << eq << "make(" << type_to_go_type(t) << ", 0, size)" << endl;
-    } else {
-        throw "INVALID TYPE IN generate_deserialize_container '" + ttype->get_name() + "' for prefix '" + prefix + "'";
-    }
-
-    // For loop iterates over elements
-    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() << "if err := iprot.ReadMapEnd(); err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"error reading map end: %s\")" << endl <<
-            indent() << "}" << endl;
-    } else if (ttype->is_set()) {
-        out <<
-            indent() << "if err := iprot.ReadSetEnd(); err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"error reading set end: %s\")" << endl <<
-            indent() << "}" << endl;
-    } else if (ttype->is_list()) {
-        out <<
-            indent() << "if err := iprot.ReadListEnd(); err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"error reading list end: %s\")" << endl <<
-            indent() << "}" << 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 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 << "[" << 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 elem = tmp("_elem");
-    t_field felem(tset->get_elem_type(), elem);
-    generate_deserialize_field(out, &felem, true, "");
-    indent(out) <<
-                prefix << "[" << elem << "] = true" << endl;
-}
-
-/**
- * Write a list element
- */
-void t_go_generator::generate_deserialize_list_element(ofstream &out,
-        t_list* tlist,
-        bool   declare,
-        string prefix)
-{
-    string elem = tmp("_elem");
-    t_field felem(tlist->get_elem_type(), elem);
-    generate_deserialize_field(out, &felem, true, "");
-    indent(out) <<
-                prefix << " = append(" << prefix << ", " << 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)
-{
-    t_type* type = get_true_type(tfield->get_type());
-    string name(prefix + publicize(variable_name_to_go_name(tfield->get_name())));
-
-    // Do nothing for void types
-    if (type->is_void()) {
-        throw "compiler error: cannot generate serialize for void type: " + name;
-    }
-
-    if (type->is_struct() || type->is_xception()) {
-        generate_serialize_struct(out,
-                                  (t_struct*)type,
-                                  name);
-    } else if (type->is_container()) {
-        generate_serialize_container(out,
-                                     type,
-                                     name);
-    } else if (type->is_base_type() || type->is_enum()) {
-        indent(out) <<
-                    "if 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:
-                if (((t_base_type*)type)->is_binary()) {
-                    out << "WriteBinary(" << name << ")";
-                } else {
-                    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 Go name for base type " + t_base_type::t_base_name(tbase);
-            }
-        } else if (type->is_enum()) {
-            out << "WriteI32(int32(" << name << "))";
-        }
-
-        out << "; err != nil {" << endl
-            << indent() << "return fmt.Errorf(\"%T." << escape_string(tfield->get_name())
-            << " (" << tfield->get_key() << ") field write error: %s\", p) }" << endl;
-    } else {
-        throw "compiler error: Invalid type in generate_serialize_field '" + type->get_name() + "' for field '" + 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)
-{
-    out <<
-        indent() << "if err := " << prefix << ".Write(oprot); err != nil {" << endl <<
-        indent() << "  return fmt.Errorf(\"%T error writing struct: %s\", " << prefix << ")" << endl <<
-        indent() << "}" << endl;
-}
-
-void t_go_generator::generate_serialize_container(ofstream &out,
-        t_type* ttype,
-        string prefix)
-{
-    if (ttype->is_map()) {
-        out <<
-            indent() << "if err := oprot.WriteMapBegin(" <<
-            type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
-            type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
-            "len(" << prefix << ")); err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"error writing map begin: %s\")" << endl <<
-            indent() << "}" << endl;
-    } else if (ttype->is_set()) {
-        out <<
-            indent() << "if err := oprot.WriteSetBegin(" <<
-            type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
-            "len(" << prefix << ")); err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"error writing set begin: %s\")" << endl <<
-            indent() << "}" << endl;
-    } else if (ttype->is_list()) {
-        out <<
-            indent() << "if err := oprot.WriteListBegin(" <<
-            type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
-            "len(" << prefix << ")); err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"error writing list begin: %s\")" << endl <<
-            indent() << "}" << endl;
-    } else {
-        throw "compiler error: Invalid type in generate_serialize_container '" + ttype->get_name() + "' for prefix '" + prefix + "'";
-    }
-
-    if (ttype->is_map()) {
-        t_map* tmap = (t_map*)ttype;
-        out <<
-            indent() << "for k,v := range " << prefix << " {" << endl;
-        indent_up();
-        generate_serialize_map_element(out, tmap, "k", "v");
-        indent_down();
-        indent(out) << "}" << endl;
-    } else if (ttype->is_set()) {
-        t_set* tset = (t_set*)ttype;
-        out <<
-            indent() << "for v, _ := range " << prefix << " {" << endl;
-        indent_up();
-        generate_serialize_set_element(out, tset, "v");
-        indent_down();
-        indent(out) << "}" << endl;
-    } else if (ttype->is_list()) {
-        t_list* tlist = (t_list*)ttype;
-        out <<
-            indent() << "for _, v := range " << prefix << " {" << endl;
-
-        indent_up();
-        generate_serialize_list_element(out, tlist, "v");
-        indent_down();
-        indent(out) << "}" << endl;
-    }
-
-    if (ttype->is_map()) {
-        out <<
-            indent() << "if err := oprot.WriteMapEnd(); err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"error writing map end: %s\")" << endl <<
-            indent() << "}" << endl;
-    } else if (ttype->is_set()) {
-        out <<
-            indent() << "if err := oprot.WriteSetEnd(); err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"error writing set end: %s\")" << endl <<
-            indent() << "}" << endl;
-    } else if (ttype->is_list()) {
-        out <<
-            indent() << "if err := oprot.WriteListEnd(); err != nil {" << endl <<
-            indent() << "  return fmt.Errorf(\"error writing list end: %s\")" << endl <<
-            indent() << "}" << endl;
-    }
-}
-
-/**
- * Serializes the members of a map.
- *
- */
-void t_go_generator::generate_serialize_map_element(ofstream &out,
-        t_map* tmap,
-        string kiter,
-        string viter)
-{
-    t_field kfield(tmap->get_key_type(), "");
-    generate_serialize_field(out, &kfield, kiter);
-    t_field vfield(tmap->get_val_type(), "");
-    generate_serialize_field(out, &vfield, viter);
-}
-
-/**
- * Serializes the members of a set.
- */
-void t_go_generator::generate_serialize_set_element(ofstream &out,
-        t_set* tset,
-        string prefix)
-{
-    t_field efield(tset->get_elem_type(), "");
-    generate_serialize_field(out, &efield, prefix);
-}
-
-/**
- * Serializes the members of a list.
- */
-void t_go_generator::generate_serialize_list_element(ofstream &out,
-        t_list* tlist,
-        string prefix)
-{
-    t_field efield(tlist->get_elem_type(), "");
-    generate_serialize_field(out, &efield, prefix);
-}
-
-/**
- * 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(variable_name_to_go_name(p->get_name()));
-
-            if (p->has_doc()) {
-                ss << ": " << p->get_doc();
-            } else {
-                ss << endl;
-            }
-        }
-    }
-
-    if (has_doc) {
-        generate_docstring_comment(out,
-                                   "",
-                                   "// ", ss.str(),
-                                   "");
-    }
-}
-
-/**
- * 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,
-                                   "",
-                                   "//", tdoc->get_doc(),
-                                   "");
-    }
-}
-
-/**
- * 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 addError)
-{
-    // 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);
-
-    if (!ret->is_void()) {
-        signature += "r " + type_to_go_type(ret);
-
-        if (addError || errs.size() == 0) {
-            signature += ", ";
-        }
-    }
-
-    if (errs.size() > 0) {
-        signature += errs;
-
-        if (addError) {
-            signature += ", ";
-        }
-    }
-
-    if (addError) {
-        signature += "err 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 += variable_name_to_go_name((*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 (program != NULL && program != program_) {
-        string module(get_real_go_module(program));
-        // for namespaced includes, only keep part after dot.
-        size_t dot = module.rfind('.');
-        if (dot != string::npos) {
-            module = module.substr(dot + 1);
-        }
-        return module + "." + 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:
-            if (((t_base_type*)type)->is_binary()) {
-                return "thrift.BINARY";
-            }
-
-            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 map type, will throw an exception if it will
- * not produce a valid go map type.
- */
-string t_go_generator::type_to_go_key_type(t_type* type)
-{
-    t_type* resolved_type = type;
-
-    while (resolved_type->is_typedef()) {
-        resolved_type = ((t_typedef*)resolved_type)->get_type();
-    }
-
-    if (resolved_type->is_map() || resolved_type->is_list() || resolved_type->is_set()) {
-        throw "Cannot produce a valid type for a Go map key: "  + type_to_go_type(type) + " - aborting.";
-    }
-
-    return type_to_go_type(type);
-}
-
-/**
- * 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:
-            if (((t_base_type*)type)->is_binary()) {
-                return "[]byte";
-            }
-
-            return "string";
-
-        case t_base_type::TYPE_BOOL:
-            return "bool";
-
-        case t_base_type::TYPE_BYTE:
-            return "int8";
-
-        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_name(type));
-    } else if (type->is_struct() || type->is_xception()) {
-        return string("*") + publicize(type_name(type));
-    } else if (type->is_map()) {
-        t_map* t = (t_map*)type;
-        string keyType = type_to_go_key_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()) {
-        t_set* t = (t_set*)type;
-        string elemType = type_to_go_key_type(t->get_elem_type());
-        return string("map[") + elemType + string("]bool");
-    } else if (type->is_list()) {
-        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(type_name(type));
-    }
-
-    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_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;
-
-        case t_base_type::TYPE_STRING:
-            return (((t_base_type*)type)->is_binary());
-        }
-    } 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();
-}
-
-bool format_go_output(const string &file_path)
-{
-    const string command = "gofmt -w " + file_path;
-
-    if (system(command.c_str()) == 0) {
-        return true;
-    }
-
-    fprintf(stderr, "WARNING - Running '%s' failed.\n", command.c_str());
-    return false;
-}
-
-
-THRIFT_REGISTER_GENERATOR(go, "Go",
-                          "    package_prefix= Package prefix for generated files.\n" \
-                          "    thrift_import=  Override thrift package import path (default:" + default_thrift_import + ")\n")
diff --git a/compiler/cpp/src/generate/t_gv_generator.cc b/compiler/cpp/src/generate/t_gv_generator.cc
deleted file mode 100644
index ff6bca1..0000000
--- a/compiler/cpp/src/generate/t_gv_generator.cc
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-#include <map>
-#include <list>
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sstream>
-#include "t_generator.h"
-#include "platform.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::pair;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * Graphviz code generator
- */
-class t_gv_generator : public t_generator {
-  public:
-    t_gv_generator(
-        t_program* program,
-        const std::map<std::string, std::string>& parsed_options,
-        const std::string& option_string)
-      : t_generator(program)
-    {
-      (void) parsed_options;
-      (void) option_string;
-      out_dir_base_ = "gen-gv";
-
-      std::map<std::string, std::string>::const_iterator iter;
-      iter = parsed_options.find("exceptions");
-      exception_arrows = (iter != parsed_options.end());
-    }
-
-    /**
-     * Init and end of generator
-     */
-    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_service (t_service*  tservice);
-
-  protected:
-    /**
-     * Helpers
-     */
-    void print_type(t_type* ttype, string struct_field_ref);
-    void print_const_value(t_const_value* tvalue);
-
-  private:
-    std::ofstream f_out_;
-    std::list<string> edges;
-    bool exception_arrows;
-};
-
-/**
- * Init generator:
- * - Adds some escaping for the Graphviz domain.
- * - Create output directory and open file for writting.
- * - Write the file header.
- */
-void t_gv_generator::init_generator() {
-  escape_['{']  = "\\{";
-  escape_['}']  = "\\}";
-
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-  string fname = get_out_dir() + program_->get_name() + ".gv";
-  f_out_.open(fname.c_str());
-  f_out_ << "digraph \""  << escape_string(program_name_) << "\" {" << endl;
-  f_out_ << "node [style=filled, shape=record];" << endl;
-  f_out_ << "edge [arrowsize=0.5];" << endl;
-  f_out_ << "rankdir=LR" << endl;
-}
-
-/**
- * Closes generator:
- * - Print accumulated nodes connections.
- * - Print footnote.
- * - Closes file.
- */
-void t_gv_generator::close_generator() {
-  // Print edges
-  std::list<string>::iterator iter = edges.begin();
-  for ( ; iter != edges.end(); iter++) {
-    f_out_ << (*iter) << endl;
-  }
-
-  // Print graph end } and close file
-f_out_ << "}" << endl;
-f_out_.close();
-}
-
-void t_gv_generator::generate_typedef (t_typedef* ttypedef) {
-  string name = ttypedef->get_name();
-  f_out_ << "node [fillcolor=azure];" << endl;
-  f_out_ << name << " [label=\"";
-
-  f_out_ << escape_string(name);
-  f_out_ << " :: ";
-  print_type(ttypedef->get_type(), name);
-
-  f_out_ << "\"];" << endl;
-}
-
-void t_gv_generator::generate_enum (t_enum* tenum) {
-  string name = tenum->get_name();
-  f_out_ << "node [fillcolor=white];" << endl;
-  f_out_ << name << " [label=\"enum " << escape_string(name);
-
-  vector<t_enum_value*> values = tenum->get_constants();
-  vector<t_enum_value*>::iterator val_iter;
-  for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) {
-    f_out_ << '|' << (*val_iter)->get_name();
-    f_out_ << " = ";
-    f_out_ << (*val_iter)->get_value();
-  }
-
-  f_out_ << "\"];" << endl;
-}
-
-void t_gv_generator::generate_const (t_const* tconst) {
-  string name = tconst->get_name();
-
-  f_out_ << "node [fillcolor=aliceblue];" << endl;
-  f_out_ << "const_" << name << " [label=\"";
-
-  f_out_ << escape_string(name);
-  f_out_ << " = ";
-  print_const_value(tconst->get_value());
-  f_out_ << " :: ";
-  print_type(tconst->get_type(), "const_" + name);
-
-  f_out_ << "\"];" << endl;
-}
-
-void t_gv_generator::generate_struct  (t_struct*   tstruct) {
-  string name = tstruct->get_name();
-
-  if (tstruct->is_xception()) {
-    f_out_ << "node [fillcolor=lightpink];" << endl;
-    f_out_ << name << " [label=\"";
-    f_out_ << "exception " << escape_string(name);
-  } else if (tstruct->is_union()) {
-    f_out_ << "node [fillcolor=lightcyan];" << endl;
-    f_out_ << name << " [label=\"";
-    f_out_ << "union " << escape_string(name);
-  } else {
-    f_out_ << "node [fillcolor=beige];" << endl;
-    f_out_ << name << " [label=\"";
-    f_out_ << "struct " << escape_string(name);
-  }
-
-  vector<t_field*> members = tstruct->get_members();
-  vector<t_field*>::iterator mem_iter = members.begin();
-  for ( ; mem_iter != members.end(); mem_iter++) {
-    string field_name = (*mem_iter)->get_name();
-
-    // print port (anchor reference)
-    f_out_ << "|<field_" << field_name << '>';
-
-    // field name :: field type
-    f_out_ << (*mem_iter)->get_name();
-    f_out_ << " :: ";
-    print_type((*mem_iter)->get_type(),
-        name + ":field_" + field_name);
-  }
-
-  f_out_ << "\"];" << endl;
-}
-
-void t_gv_generator::print_type(t_type* ttype, string struct_field_ref) {
-  if (ttype->is_container()) {
-    if (ttype->is_list()) {
-      f_out_ << "list\\<";
-      print_type(((t_list*)ttype)->get_elem_type(), struct_field_ref);
-      f_out_ << "\\>";
-    } else if (ttype->is_set()) {
-      f_out_ << "set\\<";
-      print_type(((t_set*)ttype)->get_elem_type(), struct_field_ref);
-      f_out_ << "\\>";
-    } else if (ttype->is_map()) {
-      f_out_ << "map\\<";
-      print_type(((t_map*)ttype)->get_key_type(), struct_field_ref);
-      f_out_ << ", ";
-      print_type(((t_map*)ttype)->get_val_type(), struct_field_ref);
-      f_out_ << "\\>";
-    }
-  } else if (ttype->is_base_type()) {
-    f_out_ << (((t_base_type*)ttype)->is_binary() ? "binary" : ttype->get_name());
-  } else {
-    f_out_ << ttype->get_name();
-    edges.push_back(struct_field_ref + " -> " + ttype->get_name());
-  }
-}
-
-/**
- * Prints out an string representation of the provided constant value
- */
-void t_gv_generator::print_const_value(t_const_value* tvalue) {
-  bool first = true;
-  switch (tvalue->get_type()) {
-    case t_const_value::CV_INTEGER:
-      f_out_ << tvalue->get_integer();
-      break;
-    case t_const_value::CV_DOUBLE:
-      f_out_ << tvalue->get_double();
-      break;
-    case t_const_value::CV_STRING:
-      f_out_ << "\\\"" <<  get_escaped_string(tvalue) << "\\\"";
-      break;
-    case t_const_value::CV_MAP:
-      {
-        f_out_ << "\\{ ";
-        map<t_const_value*, t_const_value*> map_elems = tvalue->get_map();
-        map<t_const_value*, t_const_value*>::iterator map_iter;
-        for (map_iter = map_elems.begin(); map_iter != map_elems.end(); map_iter++) {
-          if (!first) {
-            f_out_ << ", ";
-          }
-          first = false;
-          print_const_value(map_iter->first);
-          f_out_ << " = ";
-          print_const_value(map_iter->second);
-        }
-        f_out_ << " \\}";
-      }
-      break;
-    case t_const_value::CV_LIST:
-      {
-        f_out_ << "\\{ ";
-        vector<t_const_value*> list_elems = tvalue->get_list();;
-        vector<t_const_value*>::iterator list_iter;
-        for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) {
-          if (!first) {
-            f_out_ << ", ";
-          }
-          first = false;
-          print_const_value(*list_iter);
-        }
-        f_out_ << " \\}";
-      }
-      break;
-    default:
-      f_out_ << "UNKNOWN";
-      break;
-  }
-}
-
-void t_gv_generator::generate_service (t_service*  tservice) {
-  string service_name = get_service_name(tservice);
-  f_out_ << "subgraph cluster_" << service_name << " {" << endl;
-  f_out_ << "node [fillcolor=bisque];" << endl;
-  f_out_ << "style=dashed;" << endl;
-  f_out_ << "label = \"" << escape_string(service_name) << " service\";" << endl;
-
-  // TODO: service extends
-
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator fn_iter = functions.begin();
-  for ( ; fn_iter != functions.end(); fn_iter++) {
-    string fn_name = (*fn_iter)->get_name();
-
-    f_out_ << "function_" << fn_name;
-    f_out_ << "[label=\"<return_type>function " << escape_string(fn_name);
-    f_out_ << " :: ";
-    print_type((*fn_iter)->get_returntype(), "function_" + fn_name + ":return_type");
-
-    vector<t_field*> args = (*fn_iter)->get_arglist()->get_members();
-    vector<t_field*>::iterator arg_iter = args.begin();
-    for ( ; arg_iter != args.end(); arg_iter++) {
-      f_out_ << "|<param_" << (*arg_iter)->get_name() << ">";
-      f_out_ << (*arg_iter)->get_name();
-      if ((*arg_iter)->get_value() != NULL) {
-        f_out_ << " = ";
-        print_const_value((*arg_iter)->get_value());
-      }
-      f_out_ << " :: ";
-      print_type((*arg_iter)->get_type(),
-          "function_" + fn_name + ":param_" + (*arg_iter)->get_name());
-
-    }
-    // end of node
-    f_out_ << "\"];" << endl;
-
-    // Exception edges
-    if (exception_arrows) {
-      vector<t_field*> excepts = (*fn_iter)->get_xceptions()->get_members();
-      vector<t_field*>::iterator ex_iter = excepts.begin();
-      for ( ; ex_iter != excepts.end(); ex_iter++) {
-        edges.push_back("function_" + fn_name + " -> " +
-            (*ex_iter)->get_type()->get_name() + " [color=red]");
-      }
-    }
-  }
-
-  f_out_ << " }" << endl;
-}
-
-THRIFT_REGISTER_GENERATOR(gv, "Graphviz",
-    "    exceptions:      Whether to draw arrows from functions to exception.\n"
-    )
-
diff --git a/compiler/cpp/src/generate/t_hs_generator.cc b/compiler/cpp/src/generate/t_hs_generator.cc
deleted file mode 100644
index bbfaba5..0000000
--- a/compiler/cpp/src/generate/t_hs_generator.cc
+++ /dev/null
@@ -1,1510 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sstream>
-
-#include "t_oop_generator.h"
-#include "platform.h"
-#include "version.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * Haskell code generator.
- *
- */
-class t_hs_generator : public t_oop_generator {
- public:
-  t_hs_generator(t_program* program,
-                 const map<string, string>& parsed_options,
-                 const string& option_string)
-    : t_oop_generator(program)
-  {
-    (void) parsed_options;
-    (void) option_string;
-    out_dir_base_ = "gen-hs";
-  }
-
-  /**
-   * 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);
-
-  string render_const_value(t_type* type, t_const_value* value);
-
-  /**
-   * Struct generation code
-   */
-
-  void generate_hs_struct            (t_struct* tstruct,
-                                      bool is_exception);
-
-  void generate_hs_struct_definition (ofstream &out,
-                                      t_struct* tstruct,
-                                      bool is_xception = false,
-                                      bool helper = false);
-
-  void generate_hs_struct_reader     (ofstream& out,
-                                      t_struct* tstruct);
-
-  void generate_hs_struct_writer     (ofstream& out,
-                                      t_struct* tstruct);
-
-  void generate_hs_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_server    (t_service* tservice);
-  void generate_process_function  (t_service* tservice,
-                                   t_function* tfunction);
-
-  /**
-   * Serialization constructs
-   */
-
-  void generate_deserialize_field        (ofstream &out,
-                                          t_field* tfield,
-                                          string prefix);
-
-  void generate_deserialize_struct       (ofstream &out,
-                                          t_struct* tstruct);
-
-  void generate_deserialize_container    (ofstream &out,
-                                          t_type* ttype);
-
-  void generate_deserialize_set_element  (ofstream &out,
-                                          t_set* tset);
-
-
-  void generate_deserialize_list_element (ofstream &out,
-                                          t_list* tlist,
-                                          string prefix = "");
-
-  void generate_deserialize_type          (ofstream &out,
-                                           t_type* type);
-
-  void generate_serialize_field          (ofstream &out,
-                                          t_field* tfield,
-                                          string name = "");
-
-  void generate_serialize_struct         (ofstream &out,
-                                          t_struct* tstruct,
-                                          string prefix = "");
-
-  void generate_serialize_container      (ofstream &out,
-                                          t_type* ttype,
-                                          string prefix = "");
-
-  void generate_serialize_map_element    (ofstream &out,
-                                          t_map* tmap,
-                                          string kiter,
-                                          string viter);
-
-  void generate_serialize_set_element    (ofstream &out,
-                                          t_set* tmap,
-                                          string iter);
-
-  void generate_serialize_list_element   (ofstream &out,
-                                          t_list* tlist,
-                                          string iter);
-
-  /**
-   * Helper rendering functions
-   */
-
-  string hs_autogen_comment();
-  string hs_language_pragma();
-  string hs_imports();
-
-  string type_name(t_type* ttype,
-                   string function_prefix = "");
-
-  string function_type(t_function* tfunc,
-                       bool options = false,
-                       bool io = false,
-                       bool method = false);
-
-  string type_to_enum(t_type* ttype);
-
-  string render_hs_type(t_type* type,
-                        bool needs_parens);
-
- private:
-  ofstream f_types_;
-  ofstream f_consts_;
-  ofstream f_service_;
-  ofstream f_iface_;
-  ofstream f_client_;
-};
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * streams.
- *
- * @param tprogram The program to generate
- */
-void t_hs_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-
-  // Make output file
-  string pname = capitalize(program_name_);
-  string f_types_name = get_out_dir() + pname + "_Types.hs";
-  f_types_.open(f_types_name.c_str());
-
-  string f_consts_name = get_out_dir() + pname + "_Consts.hs";
-  f_consts_.open(f_consts_name.c_str());
-
-  // Print header
-  f_types_ << hs_language_pragma() << endl;
-  f_types_ << hs_autogen_comment() << endl;
-  f_types_ << "module " << pname << "_Types where" << endl;
-  f_types_ << hs_imports() << endl;
-
-  f_consts_ << hs_language_pragma() << endl;
-  f_consts_ << hs_autogen_comment() << endl;
-  f_consts_ << "module " << pname << "_Consts where" << endl;
-  f_consts_ << hs_imports() << endl;
-  f_consts_ << "import " << pname << "_Types" << endl;
-}
-
-string t_hs_generator::hs_language_pragma() {
-  return string("{-# LANGUAGE DeriveDataTypeable #-}\n"
-                "{-# LANGUAGE OverloadedStrings #-}\n"
-                "{-# OPTIONS_GHC -fno-warn-missing-fields #-}\n"
-                "{-# OPTIONS_GHC -fno-warn-missing-signatures #-}\n"
-                "{-# OPTIONS_GHC -fno-warn-name-shadowing #-}\n"
-                "{-# OPTIONS_GHC -fno-warn-unused-imports #-}\n"
-                "{-# OPTIONS_GHC -fno-warn-unused-matches #-}\n");
-}
-
-/**
- * Autogen'd comment
- */
-string t_hs_generator::hs_autogen_comment() {
-  return string("-----------------------------------------------------------------\n") +
-                "-- Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")                      --\n" +
-                "--                                                             --\n" +
-                "-- DO NOT EDIT UNLESS YOU ARE SURE YOU KNOW WHAT YOU ARE DOING --\n" +
-                "-----------------------------------------------------------------\n";
-}
-
-/**
- * Prints standard thrift imports
- */
-string t_hs_generator::hs_imports() {
-  const vector<t_program*>& includes = program_->get_includes();
-  string result = string(
-      "import Prelude ( Bool(..), Enum, Double, String, Maybe(..),\n"
-      "                 Eq, Show, Ord,\n"
-      "                 return, length, IO, fromIntegral, fromEnum, toEnum,\n"
-      "                 (.), (&&), (||), (==), (++), ($), (-) )\n"
-      "\n"
-      "import Control.Exception\n"
-      "import Data.ByteString.Lazy\n"
-      "import Data.Hashable\n"
-      "import Data.Int\n"
-      "import Data.Text.Lazy ( Text )\n"
-      "import qualified Data.Text.Lazy as TL\n"
-      "import Data.Typeable ( Typeable )\n"
-      "import qualified Data.HashMap.Strict as Map\n"
-      "import qualified Data.HashSet as Set\n"
-      "import qualified Data.Vector as Vector\n"
-      "\n"
-      "import Thrift\n"
-      "import Thrift.Types ()\n"
-      "\n");
-
-  for (size_t i = 0; i < includes.size(); ++i)
-    result += "import qualified " + capitalize(includes[i]->get_name()) + "_Types\n";
-
-  if (includes.size() > 0)
-    result += "\n";
-
-  return result;
-}
-
-/**
- * Closes the type files
- */
-void t_hs_generator::close_generator() {
-  // Close types file
-  f_types_.close();
-  f_consts_.close();
-}
-
-/**
- * Generates a typedef. Ez.
- *
- * @param ttypedef The type definition
- */
-void t_hs_generator::generate_typedef(t_typedef* ttypedef) {
-  string tname = capitalize(ttypedef->get_symbolic());
-  string tdef = render_hs_type(ttypedef->get_type(), false);
-  indent(f_types_) << "type " << tname << " = " << tdef << endl;
-  f_types_ << endl;
-}
-
-/**
- * Generates code for an enumerated type.
- * the values.
- *
- * @param tenum The enumeration
- */
-void t_hs_generator::generate_enum(t_enum* tenum) {
-  indent(f_types_) << "data " << capitalize(tenum->get_name()) << " = ";
-  indent_up();
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-
-  bool first = true;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    string name = capitalize((*c_iter)->get_name());
-    f_types_ << (first ? "" : "|");
-    f_types_ << name;
-    first = false;
-  }
-  indent(f_types_) << "deriving (Show,Eq, Typeable, Ord)" << endl;
-  indent_down();
-
-  string ename = capitalize(tenum->get_name());
-
-  indent(f_types_) << "instance Enum " << ename << " where" << endl;
-  indent_up();
-  indent(f_types_) << "fromEnum t = case t of" << endl;
-  indent_up();
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    string name = capitalize((*c_iter)->get_name());
-    indent(f_types_) << name << " -> " << value << endl;
-  }
-  indent_down();
-  indent(f_types_) << "toEnum t = case t of" << endl;
-  indent_up();
-  for(c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    string name = capitalize((*c_iter)->get_name());
-    indent(f_types_) << value << " -> " << name << endl;
-  }
-  indent(f_types_) << "_ -> throw ThriftException" << endl;
-  indent_down();
-  indent_down();
-
-  indent(f_types_) << "instance Hashable " << ename << " where" << endl;
-  indent_up();
-  indent(f_types_) << "hashWithSalt salt = hashWithSalt salt . fromEnum" << endl;
-  indent_down();
-}
-
-/**
- * Generate a constant value
- */
-void t_hs_generator::generate_const(t_const* tconst) {
-  t_type* type = tconst->get_type();
-  string name = decapitalize(tconst->get_name());
-
-  t_const_value* value = tconst->get_value();
-
-  indent(f_consts_) << name << " :: " << render_hs_type(type, false) << endl;
-  indent(f_consts_) << name << " = " << render_const_value(type, value) << endl;
-  f_consts_ << 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_hs_generator::render_const_value(t_type* type, t_const_value* value) {
-  type = get_true_type(type);
-  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:
-      out << "(" << value->get_integer() << " :: Int8)";
-      break;
-
-    case t_base_type::TYPE_I16:
-      out << "(" << value->get_integer() << " :: Int16)";
-      break;
-
-    case t_base_type::TYPE_I32:
-      out << "(" << value->get_integer() << " :: Int32)";
-      break;
-
-    case t_base_type::TYPE_I64:
-      out << "(" << value->get_integer() << " :: Int64)";
-      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()) {
-    t_enum* tenum = (t_enum*)type;
-    vector<t_enum_value*> constants = tenum->get_constants();
-    vector<t_enum_value*>::iterator c_iter;
-    for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-      int val = (*c_iter)->get_value();
-      if (val == value->get_integer()) {
-        indent(out) << capitalize((*c_iter)->get_name());
-        break;
-      }
-    }
-
-  } else if (type->is_struct() || type->is_xception()) {
-    string cname = type_name(type);
-    indent(out) << cname << "{";
-
-    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;
-
-    bool first = true;
-    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();
-
-      string fname = v_iter->first->get_string();
-      string const_value = render_const_value(field_type, v_iter->second);
-
-      out << (first ? "" : ",");
-      out << "f_" << cname << "_" << fname << " = Just (" << const_value << ")";
-      first = false;
-    }
-
-    indent(out) << "}";
-
-  } 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();
-    map<t_const_value*, t_const_value*>::const_iterator v_iter;
-
-    out << "(Map.fromList [";
-
-    bool first = true;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string key = render_const_value(ktype, v_iter->first);
-      string val = render_const_value(vtype, v_iter->second);
-      out << (first ? "" : ",");
-      out << "(" << key << "," << val << ")";
-      first = false;
-    }
-    out << "])";
-
-  } else if (type->is_list() || type->is_set()) {
-    t_type* etype = type->is_list()
-        ? ((t_list*) type)->get_elem_type()
-        : ((t_set*) type)->get_elem_type();
-
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-
-    if (type->is_set())
-      out << "(Set.fromList [";
-    else
-      out << "(Vector.fromList ";
-
-    bool first = true;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      out << (first ? "" : ",");
-      out << render_const_value(etype, *v_iter);
-      first = false;
-    }
-
-    out << "])";
-
-  } else {
-    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
-  }
-
-  return out.str();
-}
-
-/**
- * Generates a "struct"
- */
-void t_hs_generator::generate_struct(t_struct* tstruct) {
-  generate_hs_struct(tstruct, false);
-}
-
-/**
- * Generates a struct definition for a thrift exception. Basically the same
- * as a struct, but also has an exception declaration.
- *
- * @param txception The struct definition
- */
-void t_hs_generator::generate_xception(t_struct* txception) {
-  generate_hs_struct(txception, true);
-}
-
-/**
- * Generates a Haskell struct
- */
-void t_hs_generator::generate_hs_struct(t_struct* tstruct,
-                                        bool is_exception) {
-  generate_hs_struct_definition(f_types_,tstruct, is_exception,false);
-}
-
-/**
- * Generates a struct definition for a thrift data type.
- *
- * @param tstruct The struct definition
- */
-void t_hs_generator::generate_hs_struct_definition(ofstream& out,
-                                                   t_struct* tstruct,
-                                                   bool is_exception,
-                                                   bool helper) {
-  (void) helper;
-  string tname = type_name(tstruct);
-  string name = tstruct->get_name();
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  indent(out) << "data " << tname << " = " << tname;
-  if (members.size() > 0) {
-    out << "{";
-
-    bool first = true;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      string mname = (*m_iter)->get_name();
-      out << (first ? "" : ",");
-      out << "f_" << tname << "_" << mname << " :: Maybe " << render_hs_type((*m_iter)->get_type(), true);
-      first = false;
-    }
-    out << "}";
-  }
-
-  out << " deriving (Show,Eq,Typeable)" << endl;
-
-  if (is_exception)
-    out << "instance Exception " << tname << endl;
-
-  indent(out) << "instance Hashable " << tname << " where" << endl;
-  indent_up();
-  indent(out) << "hashWithSalt salt record = salt";
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    string mname = (*m_iter)->get_name();
-    indent(out) << " `hashWithSalt` " << "f_" << tname << "_" << mname << " record";
-  }
-  indent(out) << endl;
-  indent_down();
-
-  generate_hs_struct_writer(out, tstruct);
-  generate_hs_struct_reader(out, tstruct);
-}
-
-/**
- * Generates the read method for a struct
- */
-void t_hs_generator::generate_hs_struct_reader(ofstream& out, t_struct* tstruct) {
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  string sname = type_name(tstruct);
-  string str = tmp("_str");
-  string t = tmp("_t");
-  string id = tmp("_id");
-
-  indent(out) << "read_" << sname << "_fields iprot record = do" << endl;
-  indent_up();
-
-  // Read beginning field marker
-  indent(out) << "(_," << t << "," << id << ") <- readFieldBegin iprot" << endl;
-
-  // Check for field STOP marker and break
-  indent(out) << "if " << t << " == T_STOP then return record else" << endl;
-
-  indent_up();
-  indent(out) << "case " << id << " of " << endl;
-  indent_up();
-
-  // Generate deserialization code for known cases
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    int32_t key = (*f_iter)->get_key();
-    string etype = type_to_enum((*f_iter)->get_type());
-    indent(out) << key << " -> " << "if " << t << " == " << etype << " then do" << endl;
-
-    indent_up();
-    indent(out) << "s <- ";
-    generate_deserialize_field(out, *f_iter,str);
-    out << endl;
-
-    string fname = decapitalize((*f_iter)->get_name());
-    indent(out) << "read_" << sname << "_fields iprot record{f_" << sname << "_" << fname << "=Just s}" << endl;
-
-    indent(out) << "else do" << endl;
-
-    indent_up();
-    indent(out) << "skip iprot " << t << endl;
-
-    indent(out) << "read_" << sname << "_fields iprot record" << endl;
-
-    indent_down();
-    indent_down();
-  }
-
-  // In the default case we skip the field
-  indent(out) << "_ -> do" << endl;
-  indent_up();
-  indent(out) << "skip iprot " << t << endl;
-  indent(out) << "readFieldEnd iprot" << endl;
-  indent(out) << "read_" << sname << "_fields iprot record" << endl;
-  indent_down();
-  indent_down();
-  indent_down();
-  indent_down();
-
-  // read
-  indent(out) << "read_" << sname << " iprot = do" << endl;
-  indent_up();
-  indent(out) << "_ <- readStructBegin iprot" << endl;
-  indent(out) << "record <- read_" << sname << "_fields iprot (" << sname << "{";
-
-  bool first = true;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    out << (first ? "" : ",");
-    out << "f_" << sname << "_" << decapitalize((*f_iter)->get_name()) << "=Nothing";
-    first = false;
-  }
-
-  out << "})" << endl;
-  indent(out) << "readStructEnd iprot" << endl;
-  indent(out) << "return record" << endl;
-  indent_down();
-}
-
-void t_hs_generator::generate_hs_struct_writer(ofstream& out,
-                                               t_struct* tstruct) {
-  string name = type_name(tstruct);
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-  string str = tmp("_str");
-  string f = tmp("_f");
-
-  indent(out) << "write_" << name << " oprot record = do" << endl;
-  indent_up();
-  indent(out) << "writeStructBegin oprot \"" << name << "\"" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    // Write field header
-    string mname = (*f_iter)->get_name();
-    indent(out) << "case f_" << name << "_" << mname << " record of {Nothing -> return (); Just _v -> do" << endl;
-
-    indent_up();
-    indent(out) << "writeFieldBegin oprot (\"" << (*f_iter)->get_name() << "\","
-                << type_to_enum((*f_iter)->get_type()) << ","
-                << (*f_iter)->get_key() << ")" << endl;
-
-    // Write field contents
-    indent(out);
-    generate_serialize_field(out, *f_iter, "_v");
-    out << endl;
-
-    // Write field closer
-    indent(out) << "writeFieldEnd oprot}" << endl;
-    indent_down();
-  }
-
-  // Write the struct map
-  indent(out) << "writeFieldStop oprot" << endl;
-  indent(out) << "writeStructEnd oprot" << endl;
-
-  indent_down();
-}
-
-/**
- * Generates a thrift service.
- *
- * @param tservice The service definition
- */
-void t_hs_generator::generate_service(t_service* tservice) {
-  string f_service_name = get_out_dir() + capitalize(service_name_) + ".hs";
-  f_service_.open(f_service_name.c_str());
-
-  f_service_ << hs_language_pragma() << endl;
-  f_service_ << hs_autogen_comment() << endl;
-  f_service_ << "module " << capitalize(service_name_) << " where" << endl;
-  f_service_ << hs_imports() << endl;
-
-  if (tservice->get_extends()) {
-    f_service_ << "import qualified " << capitalize(tservice->get_extends()->get_name()) << endl;
-  }
-
-  f_service_ << "import " << capitalize(program_name_) << "_Types" << endl;
-  f_service_ << "import qualified " << capitalize(service_name_) << "_Iface as Iface" << endl;
-
-  // Generate the three main parts of the service
-  generate_service_helpers(tservice);
-  generate_service_interface(tservice);
-  generate_service_client(tservice);
-  generate_service_server(tservice);
-
-  // Close service file
-  f_service_.close();
-}
-
-/**
- * Generates helper functions for a service.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_hs_generator::generate_service_helpers(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  indent(f_service_) << "-- HELPER FUNCTIONS AND STRUCTURES --" << endl;
-  indent(f_service_) << endl;
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    t_struct* ts = (*f_iter)->get_arglist();
-    generate_hs_struct_definition(f_service_,ts, false);
-    generate_hs_function_helpers(*f_iter);
-  }
-}
-
-/**
- * Generates a struct and helpers for a function.
- *
- * @param tfunction The function
- */
-void t_hs_generator::generate_hs_function_helpers(t_function* tfunction) {
-  t_struct result(program_, decapitalize(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_hs_struct_definition(f_service_,&result, false);
-}
-
-/**
- * Generates a service interface definition.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_hs_generator::generate_service_interface(t_service* tservice) {
-  string f_iface_name = get_out_dir() + capitalize(service_name_) + "_Iface.hs";
-  f_iface_.open(f_iface_name.c_str());
-
-  f_iface_ << hs_language_pragma() << endl;
-  f_iface_ << hs_autogen_comment() << endl;
-
-  f_iface_ << "module " << capitalize(service_name_) << "_Iface where" << endl;
-
-  f_iface_ << hs_imports() << endl;
-  f_iface_ << "import " << capitalize(program_name_) << "_Types" << endl;
-  f_iface_ << endl;
-
-  string sname = capitalize(service_name_);
-  if (tservice->get_extends() != NULL) {
-    string extends = type_name(tservice->get_extends());
-
-    indent(f_iface_) << "import " << extends << "_Iface" << endl;
-    indent(f_iface_) << "class " << extends << "_Iface a => " << sname << "_Iface a where" << endl;
-
-  } else {
-    indent(f_iface_) << "class " << sname << "_Iface a where" << endl;
-  }
-
-  indent_up();
-
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    string ft = function_type(*f_iter, true, true, true);
-    indent(f_iface_) << decapitalize((*f_iter)->get_name()) << " :: a -> " << ft  << endl;
-  }
-
-  indent_down();
-  f_iface_.close();
-}
-
-/**
- * Generates a service client definition. Note that in Haskell, the client doesn't implement iface. This is because
- * The client does not (and should not have to) deal with arguments being Nothing.
- *
- * @param tservice The service to generate a server for.
- */
-void t_hs_generator::generate_service_client(t_service* tservice) {
-  string f_client_name = get_out_dir() + capitalize(service_name_) + "_Client.hs";
-  f_client_.open(f_client_name.c_str());
-  f_client_ << hs_language_pragma() << endl;
-  f_client_ << hs_autogen_comment() << endl;
-
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::const_iterator f_iter;
-
-  string extends = "";
-  string exports = "";
-
-  bool first = true;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    exports += (first ? "" : ",");
-    string funname = (*f_iter)->get_name();
-    exports += decapitalize(funname);
-    first = false;
-  }
-
-  string sname = capitalize(service_name_);
-  indent(f_client_) << "module " << sname << "_Client(" << exports << ") where" << endl;
-
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    indent(f_client_) << "import " << extends << "_Client" << endl;
-  }
-
-  indent(f_client_) << "import Data.IORef" << endl;
-  indent(f_client_) << hs_imports() << endl;
-  indent(f_client_) << "import " << capitalize(program_name_) << "_Types" << endl;
-  indent(f_client_) << "import " << capitalize(service_name_) << endl;
-
-  // DATS RITE A GLOBAL VAR
-  indent(f_client_) << "seqid = newIORef 0" << endl;
-
-  // Generate client method implementations
-  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 = (*f_iter)->get_name();
-
-    string fargs = "";
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter)
-      fargs += " arg_" + decapitalize((*fld_iter)->get_name());
-
-    // Open function
-    indent(f_client_) << decapitalize(funname) << " (ip,op)" <<  fargs << " = do" << endl;
-    indent_up();
-    indent(f_client_) <<  "send_" << funname << " op" << fargs;
-
-    f_client_ << endl;
-
-    if (!(*f_iter)->is_oneway())
-      indent(f_client_) << "recv_" << funname << " ip" << endl;
-
-    indent_down();
-
-    indent(f_client_) << "send_" << funname << " op" << fargs << " = do" << endl;
-    indent_up();
-
-    indent(f_client_) << "seq <- seqid" << endl;
-    indent(f_client_) << "seqn <- readIORef seq" << endl;
-    string argsname = capitalize((*f_iter)->get_name() + "_args");
-
-    // Serialize the request header
-    string fname = (*f_iter)->get_name();
-    indent(f_client_) << "writeMessageBegin op (\"" << fname << "\", M_CALL, seqn)" << endl;
-    indent(f_client_) << "write_" << argsname << " op (" << argsname << "{";
-
-    bool first = true;
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      string fieldname = (*fld_iter)->get_name();
-      f_client_ << (first ? "" : ",");
-      f_client_ << "f_" << argsname << "_" << fieldname << "=Just arg_" << fieldname;
-      first = false;
-    }
-    f_client_ << "})" << endl;
-
-    // Write to the stream
-    indent(f_client_) << "writeMessageEnd op" << endl;
-    indent(f_client_) << "tFlush (getTransport op)" << endl;
-    indent_down();
-
-    if (!(*f_iter)->is_oneway()) {
-      string resultname = capitalize((*f_iter)->get_name() + "_result");
-      t_struct noargs(program_);
-
-      string funname = string("recv_") + (*f_iter)->get_name();
-      t_function recv_function((*f_iter)->get_returntype(), funname, &noargs);
-
-      // Open function
-      indent(f_client_) << funname << " ip = do" << endl;
-      indent_up();
-
-      // TODO(mcslee): Validate message reply here, seq ids etc.
-      indent(f_client_) << "(fname, mtype, rseqid) <- readMessageBegin ip" << endl;
-      indent(f_client_) << "if mtype == M_EXCEPTION then do" << endl;
-      indent(f_client_) << "  x <- readAppExn ip" << endl;
-      indent(f_client_) << "  readMessageEnd ip" << endl;
-      indent(f_client_) << "  throw x" << endl;
-      indent(f_client_) << "  else return ()" << endl;
-
-      t_struct* xs = (*f_iter)->get_xceptions();
-      const vector<t_field*>& xceptions = xs->get_members();
-
-      indent(f_client_) << "res <- read_" << resultname << " ip" << endl;
-      indent(f_client_) << "readMessageEnd ip" << endl;
-
-      // Careful, only return _result if not a void function
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        indent(f_client_) << "case f_" << resultname << "_success res of" << endl;
-        indent_up();
-
-        indent(f_client_) << "Just v -> return v" << endl;
-        indent(f_client_) << "Nothing -> do" << endl;
-        indent_up();
-      }
-
-      vector<t_field*>::const_iterator x_iter;
-      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-        string xname = (*x_iter)->get_name();
-        indent(f_client_) << "case f_" << resultname << "_" << xname << " res of" << endl;
-        indent_up();
-
-        indent(f_client_) << "Nothing -> return ()" << endl;
-        indent(f_client_) << "Just _v -> throw _v" << endl;
-        indent_down();
-      }
-
-      // Careful, only return _result if not a void function
-      if ((*f_iter)->get_returntype()->is_void()) {
-        indent(f_client_) << "return ()" << endl;
-
-      } else {
-        string tname = (*f_iter)->get_name();
-        indent(f_client_) << "throw (AppExn AE_MISSING_RESULT \"" << tname << " failed: unknown result\")" << endl;
-        indent_down();
-        indent_down();
-      }
-
-      // Close function
-      indent_down();
-    }
-  }
-
-  f_client_.close();
-}
-
-/**
- * Generates a service server definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_hs_generator::generate_service_server(t_service* tservice) {
-  // Generate the dispatch methods
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  // Generate the process subfunctions
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
-    generate_process_function(tservice, *f_iter);
-
-  indent(f_service_) << "proc_ handler (iprot,oprot) (name,typ,seqid) = case name of" << endl;
-  indent_up();
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    string fname = (*f_iter)->get_name();
-    indent(f_service_) << "\"" << fname << "\" -> process_" << decapitalize(fname) << " (seqid,iprot,oprot,handler)" << endl;
-  }
-
-  indent(f_service_) << "_ -> ";
-  if (tservice->get_extends() != NULL) {
-    f_service_ << type_name(tservice->get_extends()) << ".proc_ handler (iprot,oprot) (name,typ,seqid)" << endl;
-
-  } else {
-    f_service_ << "do" << endl;
-    indent_up();
-    indent(f_service_) << "skip iprot T_STRUCT" << endl;
-    indent(f_service_) << "readMessageEnd iprot" << endl;
-    indent(f_service_) << "writeMessageBegin oprot (name,M_EXCEPTION,seqid)" << endl;
-    indent(f_service_) << "writeAppExn oprot (AppExn AE_UNKNOWN_METHOD (\"Unknown function \" ++ TL.unpack name))" << endl;
-    indent(f_service_) << "writeMessageEnd oprot" << endl;
-    indent(f_service_) << "tFlush (getTransport oprot)" << endl;
-    indent_down();
-  }
-
-  indent_down();
-
-  // Generate the server implementation
-  indent(f_service_) << "process handler (iprot, oprot) = do" << endl;
-  indent_up();
-
-  indent(f_service_) << "(name, typ, seqid) <- readMessageBegin iprot" << endl;
-  indent(f_service_) << "proc_ handler (iprot,oprot) (name,typ,seqid)" << endl;
-  indent(f_service_) << "return True" << endl;
-  indent_down();
-}
-
-/**
- * Generates a process function definition.
- *
- * @param tfunction The function to write a dispatcher for
- */
-void t_hs_generator::generate_process_function(t_service* tservice,
-                                               t_function* tfunction) {
-  (void) tservice;
-  // Open function
-  string funname = decapitalize(tfunction->get_name());
-  indent(f_service_) << "process_" << funname << " (seqid, iprot, oprot, handler) = do" << endl;
-  indent_up();
-
-  string argsname = capitalize(tfunction->get_name()) + "_args";
-  string resultname = capitalize(tfunction->get_name()) + "_result";
-
-  // Generate the function call
-  t_struct* arg_struct = tfunction->get_arglist();
-  const vector<t_field*>& fields = arg_struct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  indent(f_service_) << "args <- read_" << argsname << " iprot" << endl;
-  indent(f_service_) << "readMessageEnd iprot" << endl;
-
-  t_struct* xs = tfunction->get_xceptions();
-  const vector<t_field*>& xceptions = xs->get_members();
-  vector<t_field*>::const_iterator x_iter;
-
-  size_t n = xceptions.size();
-  if (!tfunction->is_oneway()) {
-    if (!tfunction->get_returntype()->is_void())
-      n++;
-
-    indent(f_service_) << "rs <- return (" << resultname;
-
-    for(size_t i = 0; i < n; i++)
-      f_service_ << " Nothing";
-
-    f_service_ << ")" << endl;
-  }
-
-  indent(f_service_) << "res <- ";
-  // Try block for a function with exceptions
-  if (xceptions.size() > 0) {
-    for(size_t i = 0; i < xceptions.size(); i++) {
-      f_service_ << "(Control.Exception.catch" << endl;
-      indent_up();
-      indent(f_service_);
-    }
-  }
-
-  f_service_ << "(do" << endl;
-  indent_up();
-  indent(f_service_);
-
-  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void())
-    f_service_ << "res <- ";
-
-  f_service_ << "Iface." << decapitalize(tfunction->get_name()) << " handler";
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
-    f_service_ <<  " (f_" << argsname <<  "_" << (*f_iter)->get_name() << " args)";
-
-  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
-    f_service_ << endl;
-    indent(f_service_) << "return rs{f_" << resultname << "_success= Just res}";
-
-  } else if (!tfunction->is_oneway()) {
-    f_service_ << endl;
-    indent(f_service_) << "return rs";
-  }
-
-  f_service_ << ")" << endl;
-  indent_down();
-
-  if (xceptions.size() > 0 && !tfunction->is_oneway()) {
-    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      indent(f_service_) << "(\\e  -> " << endl;
-      indent_up();
-
-      if (!tfunction->is_oneway()) {
-        indent(f_service_) << "return rs{f_" << resultname << "_" << (*x_iter)->get_name() << " =Just e}";
-
-      } else {
-        indent(f_service_) << "return ()";
-      }
-
-      f_service_ << "))" << endl;
-      indent_down();
-      indent_down();
-    }
-  }
-
-  // Shortcut out here for oneway functions
-  if (tfunction->is_oneway()) {
-    indent(f_service_) << "return ()" << endl;
-    indent_down();
-    return;
-  }
-
-  indent(f_service_ ) << "writeMessageBegin oprot (\"" << tfunction->get_name() << "\", M_REPLY, seqid);" << endl;
-  indent(f_service_ ) << "write_" << resultname << " oprot res" << endl;
-  indent(f_service_ ) << "writeMessageEnd oprot" << endl;
-  indent(f_service_ ) << "tFlush (getTransport oprot)" << endl;
-
-  // Close function
-  indent_down();
-}
-
-/**
- * Deserializes a field of any type.
- */
-void t_hs_generator::generate_deserialize_field(ofstream &out,
-                                                t_field* tfield,
-                                                string prefix) {
-  (void) prefix;
-  t_type* type = tfield->get_type();
-  generate_deserialize_type(out,type);
-}
-
-/**
- * Deserializes a field of any type.
- */
-void t_hs_generator::generate_deserialize_type(ofstream &out,
-                                               t_type* type) {
-  type = get_true_type(type);
-
-  if (type->is_void())
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE";
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct(out, (t_struct*)type);
-
-  } else if (type->is_container()) {
-    generate_deserialize_container(out, type);
-
-  } else 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";
-      break;
-    case t_base_type::TYPE_STRING:
-      out << (((t_base_type*)type)->is_binary() ? "readBinary" : "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 PHP name for base type " + t_base_type::t_base_name(tbase);
-    }
-    out << " iprot";
-
-  } else if (type->is_enum()) {
-    string ename = capitalize(type->get_name());
-    out << "(do {i <- readI32 iprot; return $ toEnum $ fromIntegral i})";
-
-  } else {
-    printf("DO NOT KNOW HOW TO DESERIALIZE TYPE '%s'\n",
-           type->get_name().c_str());
-  }
-}
-
-
-/**
- * Generates an unserializer for a struct, calling read()
- */
-void t_hs_generator::generate_deserialize_struct(ofstream &out,
-                                                 t_struct* tstruct) {
-  string name = capitalize(tstruct->get_name());
-  out << "(read_" << name << " iprot)";
-}
-
-/**
- * Serialize a container by writing out the header followed by
- * data and then a footer.
- */
-void t_hs_generator::generate_deserialize_container(ofstream &out,
-                                                    t_type* ttype) {
-  string size = tmp("_size");
-  string ktype = tmp("_ktype");
-  string vtype = tmp("_vtype");
-  string etype = tmp("_etype");
-  string con = tmp("_con");
-
-  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);
-
-  // Declare variables, read header
-  if (ttype->is_map()) {
-    out << "(let {f 0 = return []; f n = do {k <- ";
-    generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
-
-    out << "; v <- ";
-    generate_deserialize_type(out,((t_map*)ttype)->get_val_type());
-
-    out << ";r <- f (n-1); return $ (k,v):r}} in do {(" << ktype << "," << vtype << "," << size << ") <- readMapBegin iprot; l <- f " << size << "; return $ Map.fromList l})";
-
-  } else if (ttype->is_set()) {
-    out << "(let {f 0 = return []; f n = do {v <- ";
-    generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
-    out << ";r <- f (n-1); return $ v:r}} in do {(" << etype << "," << size << ") <- readSetBegin iprot; l <- f " << size << "; return $ Set.fromList l})";
-
-  } else if (ttype->is_list()) {
-    out << "(let f n = Vector.replicateM (fromIntegral n) (";
-    generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
-    out << ") in do {(" << etype << "," << size << ") <- readListBegin iprot; f " << size << "})";
-  }
-}
-
-/**
- * Serializes a field of any type.
- *
- * @param tfield The field to serialize
- * @param prefix Name to prepend to field name
- */
-void t_hs_generator::generate_serialize_field(ofstream &out,
-                                              t_field* tfield,
-                                              string name) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  // Do nothing for void types
-  if (type->is_void())
-    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + tfield->get_name();
-
-  if (name.length() == 0)
-    name = decapitalize(tfield->get_name());
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_serialize_struct(out, (t_struct*)type, name);
-
-  } else if (type->is_container()) {
-    generate_serialize_container(out, type, name);
-
-  } else if (type->is_base_type() || type->is_enum()) {
-    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 << (((t_base_type*)type)->is_binary() ? "writeBinary" : "writeString") << " oprot " << name;
-        break;
-
-      case t_base_type::TYPE_BOOL:
-        out << "writeBool oprot " << name;
-       break;
-
-      case t_base_type::TYPE_BYTE:
-        out << "writeByte oprot " << name;
-        break;
-
-      case t_base_type::TYPE_I16:
-        out << "writeI16 oprot " << name;
-        break;
-
-      case t_base_type::TYPE_I32:
-        out << "writeI32 oprot " << name;
-        break;
-
-      case t_base_type::TYPE_I64:
-        out << "writeI64 oprot " << name;
-        break;
-
-      case t_base_type::TYPE_DOUBLE:
-        out << "writeDouble oprot " << name;
-        break;
-
-      default:
-        throw "compiler error: no hs name for base type " + t_base_type::t_base_name(tbase);
-      }
-
-    } else if (type->is_enum()) {
-      string ename = capitalize(type->get_name());
-      out << "writeI32 oprot (fromIntegral $ fromEnum " << name << ")";
-    }
-
-  } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
-           tfield->get_name().c_str(),
-           type->get_name().c_str());
-  }
-}
-
-/**
- * Serializes all the members of a struct.
- *
- * @param tstruct The struct to serialize
- * @param prefix  String prefix to attach to all fields
- */
-void t_hs_generator::generate_serialize_struct(ofstream &out,
-                                               t_struct* tstruct,
-                                               string prefix) {
-  out << type_name(tstruct, "write_") << " oprot " << prefix;
-}
-
-void t_hs_generator::generate_serialize_container(ofstream &out,
-                                                  t_type* ttype,
-                                                  string prefix) {
-  if (ttype->is_map()) {
-    string k = tmp("_kiter");
-    string v = tmp("_viter");
-    out << "(let {f [] = return (); f ((" << k << "," << v << "):t) = do {";
-    generate_serialize_map_element(out, (t_map*)ttype, k, v);
-    out << ";f t}} in do {writeMapBegin oprot (" << type_to_enum(((t_map*)ttype)->get_key_type()) << "," << type_to_enum(((t_map*)ttype)->get_val_type()) << ",fromIntegral $ Map.size " << prefix << "); f (Map.toList " << prefix << ");writeMapEnd oprot})";
-
-  } else if (ttype->is_set()) {
-    string v = tmp("_viter");
-    out << "(let {f [] = return (); f (" << v << ":t) = do {";
-    generate_serialize_set_element(out, (t_set*)ttype, v);
-    out << ";f t}} in do {writeSetBegin oprot (" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ",fromIntegral $ Set.size " << prefix << "); f (Set.toList " << prefix << ");writeSetEnd oprot})";
-
-  } else if (ttype->is_list()) {
-    string v = tmp("_viter");
-    out << "(let f = Vector.mapM_ (\\" << v << " -> ";
-    generate_serialize_list_element(out, (t_list*)ttype, v);
-    out << ") in do {writeListBegin oprot (" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ",fromIntegral $ Vector.length " << prefix << "); f " << prefix << ";writeListEnd oprot})";
-  }
-
-}
-
-/**
- * Serializes the members of a map.
- *
- */
-void t_hs_generator::generate_serialize_map_element(ofstream &out,
-                                                    t_map* tmap,
-                                                    string kiter,
-                                                    string viter) {
-  t_field kfield(tmap->get_key_type(), kiter);
-  out << "do {";
-  generate_serialize_field(out, &kfield);
-  out << ";";
-
-  t_field vfield(tmap->get_val_type(), viter);
-  generate_serialize_field(out, &vfield);
-  out << "}";
-}
-
-/**
- * Serializes the members of a set.
- */
-void t_hs_generator::generate_serialize_set_element(ofstream &out,
-                                                    t_set* tset,
-                                                    string iter) {
-  t_field efield(tset->get_elem_type(), iter);
-  generate_serialize_field(out, &efield);
-}
-
-/**
- * Serializes the members of a list.
- */
-void t_hs_generator::generate_serialize_list_element(ofstream &out,
-                                                     t_list* tlist,
-                                                     string iter) {
-  t_field efield(tlist->get_elem_type(), iter);
-  generate_serialize_field(out, &efield);
-}
-
-string t_hs_generator::function_type(t_function* tfunc, bool options, bool io, bool method) {
-  string result = "";
-
-  const vector<t_field*>& fields = tfunc->get_arglist()->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (options) result += "Maybe ";
-    result += render_hs_type((*f_iter)->get_type(), options);
-    result += " -> ";
-  }
-
-  if (fields.empty() && !method)
-    result += "() -> ";
-
-  if (io)
-    result += "IO ";
-
-  result += render_hs_type(tfunc->get_returntype(), io);
-  return result;
-}
-
-
-string t_hs_generator::type_name(t_type* ttype, string function_prefix) {
-  string prefix = "";
-  t_program* program = ttype->get_program();
-
-  if (program != NULL && program != program_)
-    if (!ttype->is_service())
-      prefix = capitalize(program->get_name()) + "_Types.";
-
-  return prefix + function_prefix + capitalize(ttype->get_name());
-}
-
-/**
- * Converts the parse type to a Protocol.t_type enum
- */
-string t_hs_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:   return "T_VOID";
-    case t_base_type::TYPE_STRING: return "T_STRING";
-    case t_base_type::TYPE_BOOL:   return "T_BOOL";
-    case t_base_type::TYPE_BYTE:   return "T_BYTE";
-    case t_base_type::TYPE_I16:    return "T_I16";
-    case t_base_type::TYPE_I32:    return "T_I32";
-    case t_base_type::TYPE_I64:    return "T_I64";
-    case t_base_type::TYPE_DOUBLE: return "T_DOUBLE";
-    }
-
-  } else if (type->is_enum()) {
-    return "T_I32";
-
-  } else if (type->is_struct() || type->is_xception()) {
-    return "T_STRUCT";
-
-  } else if (type->is_map()) {
-    return "T_MAP";
-
-  } else if (type->is_set()) {
-    return "T_SET";
-
-  } else if (type->is_list()) {
-    return "T_LIST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-/**
- * Converts the parse type to an haskell type
- */
-string t_hs_generator::render_hs_type(t_type* type, bool needs_parens) {
-  type = get_true_type(type);
-  string type_repr;
-
-  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:   return "()";
-    case t_base_type::TYPE_STRING: return (((t_base_type*)type)->is_binary() ? "ByteString" : "Text");
-    case t_base_type::TYPE_BOOL:   return "Bool";
-    case t_base_type::TYPE_BYTE:   return "Int8";
-    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 "Double";
-    }
-
-  } else if (type->is_enum()) {
-    return capitalize(((t_enum*)type)->get_name());
-
-  } else if (type->is_struct() || type->is_xception()) {
-    return type_name((t_struct*)type);
-
-  } else if (type->is_map()) {
-    t_type* ktype = ((t_map*)type)->get_key_type();
-    t_type* vtype = ((t_map*)type)->get_val_type();
-    type_repr = "Map.HashMap " + render_hs_type(ktype, true) + " " + render_hs_type(vtype, true);
-
-  } else if (type->is_set()) {
-    t_type* etype = ((t_set*)type)->get_elem_type();
-    type_repr = "Set.HashSet " + render_hs_type(etype, true) ;
-
-  } else if (type->is_list()) {
-    t_type* etype = ((t_list*)type)->get_elem_type();
-    type_repr = "Vector.Vector " + render_hs_type(etype, true);
-
-  } else {
-    throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-  }
-
-  return needs_parens ? "(" + type_repr + ")" : type_repr;
-}
-
-THRIFT_REGISTER_GENERATOR(hs, "Haskell", "")
diff --git a/compiler/cpp/src/generate/t_html_generator.cc b/compiler/cpp/src/generate/t_html_generator.cc
deleted file mode 100644
index 0d0115d..0000000
--- a/compiler/cpp/src/generate/t_html_generator.cc
+++ /dev/null
@@ -1,889 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-#include <map>
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sstream>
-#include "t_generator.h"
-#include "t_html_generator.h"
-#include "platform.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::pair;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-enum input_type { INPUT_UNKNOWN, INPUT_UTF8, INPUT_PLAIN };
-
-/**
- * HTML code generator
- *
- * mostly copy/pasting/tweaking from mcslee's work.
- */
-class t_html_generator : public t_generator {
- public:
-  t_html_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_generator(program)
-  {
-    (void) parsed_options;
-    (void) option_string;  
-    out_dir_base_ = "gen-html";
-    input_type_ = INPUT_UNKNOWN;
-    
-    std::map<std::string, std::string>::const_iterator iter;
-    iter = parsed_options.find("standalone");
-    standalone_ = (iter != parsed_options.end());
-    
-    escape_.clear();
-    escape_['&']  = "&amp;";
-    escape_['<']  = "&lt;";
-    escape_['>']  = "&gt;";
-    escape_['"']  = "&quot;";
-    escape_['\''] = "&apos;";
-  }
-
-  void generate_program();
-  void generate_program_toc();
-  void generate_program_toc_row(t_program* tprog);
-  void generate_program_toc_rows(t_program* tprog,
-         std::vector<t_program*>& finished);
-  void generate_index();
-  std::string escape_html(std::string const & str);
-  void generate_css();
-  void generate_css_content(std::ofstream & f_target);
-  void generate_style_tag();
-  std::string make_file_link( std::string name);
-  bool is_utf8_sequence(std::string const & str, size_t firstpos);
-  void detect_input_encoding(std::string const & str, size_t firstpos);
-  
-  /**
-   * 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_service (t_service*  tservice);
-  void generate_xception(t_struct*   txception);
-
-  void print_doc        (t_doc* tdoc);
-  int  print_type       (t_type* ttype);
-  void print_const_value(t_const_value* tvalue);
-  void print_fn_args_doc(t_function* tfunction);
-
- private:
-  std::ofstream f_out_;
-  std::string  current_file_;
-  input_type input_type_;
- 
-  bool standalone_; 
-};
-
-
-/**
- * Emits the Table of Contents links at the top of the module's page
- */
-void t_html_generator::generate_program_toc() {
-  f_out_ << "<table class=\"table-bordered table-striped table-condensed\"><thead><th>Module</th><th>Services</th>"
-   << "<th>Data types</th><th>Constants</th></thead>" << endl;
-  generate_program_toc_row(program_);
-  f_out_ << "</table>" << endl;
-}
-
-
-/**
- * Recurses through from the provided program and generates a ToC row
- * for each discovered program exactly once by maintaining the list of
- * completed rows in 'finished'
- */
-void t_html_generator::generate_program_toc_rows(t_program* tprog,
-         std::vector<t_program*>& finished) {
-  for (vector<t_program*>::iterator iter = finished.begin();
-       iter != finished.end(); iter++) {
-    if (tprog->get_path() == (*iter)->get_path()) {
-      return;
-    }
-  }
-  finished.push_back(tprog);
-  generate_program_toc_row(tprog);
-  vector<t_program*> includes = tprog->get_includes();
-  for (vector<t_program*>::iterator iter = includes.begin();
-       iter != includes.end(); iter++) {
-    generate_program_toc_rows(*iter, finished);
-  }
-}
-
-/**
- * Emits the Table of Contents links at the top of the module's page
- */
-void t_html_generator::generate_program_toc_row(t_program* tprog) {
-  string fname = tprog->get_name() + ".html";
-  f_out_ << "<tr>" << endl << "<td>" << tprog->get_name() << "</td><td>";
-  if (!tprog->get_services().empty()) {
-    vector<t_service*> services = tprog->get_services();
-    vector<t_service*>::iterator sv_iter;
-    for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
-      string name = get_service_name(*sv_iter);
-      f_out_ << "<a href=\"" << make_file_link(fname) << "#Svc_" << name << "\">" << name
-        << "</a><br/>" << endl;
-      f_out_ << "<ul>" << endl;
-      map<string,string> fn_html;
-      vector<t_function*> functions = (*sv_iter)->get_functions();
-      vector<t_function*>::iterator fn_iter;
-      for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) {
-        string fn_name = (*fn_iter)->get_name();
-        string html = "<li><a href=\"" + make_file_link(fname) + "#Fn_" + name + "_" +
-          fn_name + "\">" + fn_name + "</a></li>";
-        fn_html.insert(pair<string,string>(fn_name, html));
-      }
-      for (map<string,string>::iterator html_iter = fn_html.begin();
-        html_iter != fn_html.end(); html_iter++) {
-        f_out_ << html_iter->second << endl;
-      }
-      f_out_ << "</ul>" << endl;
-    }
-  }
-  f_out_ << "</td>" << endl << "<td>";
-  map<string,string> data_types;
-  if (!tprog->get_enums().empty()) {
-    vector<t_enum*> enums = tprog->get_enums();
-    vector<t_enum*>::iterator en_iter;
-    for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
-      string name = (*en_iter)->get_name();
-      // f_out_ << "<a href=\"" << make_file_link(fname) << "#Enum_" << name << "\">" << name
-      // <<  "</a><br/>" << endl;
-      string html = "<a href=\"" + make_file_link(fname) + "#Enum_" + name + "\">" + name +
-        "</a>";
-      data_types.insert(pair<string,string>(name, html));
-    }
-  }
-  if (!tprog->get_typedefs().empty()) {
-    vector<t_typedef*> typedefs = tprog->get_typedefs();
-    vector<t_typedef*>::iterator td_iter;
-    for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
-      string name = (*td_iter)->get_symbolic();
-      // f_out_ << "<a href=\"" << make_file_link(fname) << "#Typedef_" << name << "\">" << name
-      // << "</a><br/>" << endl;
-      string html = "<a href=\"" + make_file_link(fname) + "#Typedef_" + name + "\">" + name +
-        "</a>";
-      data_types.insert(pair<string,string>(name, html));
-    }
-  }
-  if (!tprog->get_objects().empty()) {
-    vector<t_struct*> objects = tprog->get_objects();
-    vector<t_struct*>::iterator o_iter;
-    for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
-      string name = (*o_iter)->get_name();
-      //f_out_ << "<a href=\"" << make_file_link(fname) << "#Struct_" << name << "\">" << name
-      //<< "</a><br/>" << endl;
-      string html = "<a href=\"" + make_file_link(fname) + "#Struct_" + name + "\">" + name +
-        "</a>";
-      data_types.insert(pair<string,string>(name, html));
-    }
-  }
-  for (map<string,string>::iterator dt_iter = data_types.begin();
-       dt_iter != data_types.end(); dt_iter++) {
-    f_out_ << dt_iter->second << "<br/>" << endl;
-  }
-  f_out_ << "</td>" << endl << "<td>";
-  if (!tprog->get_consts().empty()) {
-    map<string,string> const_html;
-    vector<t_const*> consts = tprog->get_consts();
-    vector<t_const*>::iterator con_iter;
-    for (con_iter = consts.begin(); con_iter != consts.end(); ++con_iter) {
-      string name = (*con_iter)->get_name();
-      string html ="<code><a href=\"" + make_file_link(fname) + "#Const_" + name +
-        "\">" + name + "</a></code>";
-      const_html.insert(pair<string,string>(name, html));
-    }
-    for (map<string,string>::iterator con_iter = const_html.begin();
-   con_iter != const_html.end(); con_iter++) {
-      f_out_ << con_iter->second << "<br/>" << endl;
-    }
-  }
-  f_out_ << "</code></td>" << endl << "</tr>";
-}
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * stream.
- */
-void t_html_generator::generate_program() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-  current_file_ =  program_->get_name() + ".html";
-  string fname = get_out_dir() + current_file_;
-  f_out_.open(fname.c_str());
-  f_out_ << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"" << endl;
-  f_out_ << "    \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" << endl;
-  f_out_ << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl;
-  f_out_ << "<head>" << endl;
-  f_out_ << "<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" />" << endl;
-  generate_style_tag();
-  f_out_ << "<title>Thrift module: " << program_->get_name()
-   << "</title></head><body>" << endl
-   << "<div class=\"container-fluid\">" << endl
-   << "<h1>Thrift module: "
-   << program_->get_name() << "</h1>" << endl;
-
-  print_doc(program_);
-
-  generate_program_toc();
-
-  if (!program_->get_consts().empty()) {
-    f_out_ << "<hr/><h2 id=\"Constants\">Constants</h2>" << endl;
-    vector<t_const*> consts = program_->get_consts();
-    f_out_ << "<table class=\"table-bordered table-striped table-condensed\">";
-    f_out_ << "<thead><th>Constant</th><th>Type</th><th>Value</th></thead>" << endl;
-    generate_consts(consts);
-    f_out_ << "</table>";
-  }
-
-  if (!program_->get_enums().empty()) {
-    f_out_ << "<hr/><h2 id=\"Enumerations\">Enumerations</h2>" << endl;
-    // Generate enums
-    vector<t_enum*> enums = program_->get_enums();
-    vector<t_enum*>::iterator en_iter;
-    for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
-      generate_enum(*en_iter);
-    }
-  }
-
-  if (!program_->get_typedefs().empty()) {
-    f_out_ << "<hr/><h2 id=\"Typedefs\">Type declarations</h2>" << endl;
-    // Generate typedefs
-    vector<t_typedef*> typedefs = program_->get_typedefs();
-    vector<t_typedef*>::iterator td_iter;
-    for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
-      generate_typedef(*td_iter);
-    }
-  }
-
-  if (!program_->get_objects().empty()) {
-    f_out_ << "<hr/><h2 id=\"Structs\">Data structures</h2>" << endl;
-    // Generate structs and exceptions in declared order
-    vector<t_struct*> objects = program_->get_objects();
-    vector<t_struct*>::iterator o_iter;
-    for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
-      if ((*o_iter)->is_xception()) {
-        generate_xception(*o_iter);
-      } else {
-        generate_struct(*o_iter);
-      }
-    }
-  }
-
-  if (!program_->get_services().empty()) {
-    f_out_ << "<hr/><h2 id=\"Services\">Services</h2>" << endl;
-    // Generate services
-    vector<t_service*> services = program_->get_services();
-    vector<t_service*>::iterator sv_iter;
-    for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
-      service_name_ = get_service_name(*sv_iter);
-      generate_service(*sv_iter);
-    }
-  }
-
-  f_out_ << "</div></body></html>" << endl;
-  f_out_.close();
-  
-  generate_index();
-  generate_css();
-}
-
-
-/**
- * Emits the index.html file for the recursive set of Thrift programs
- */
-void t_html_generator::generate_index() {
-  current_file_ = "index.html";
-  string index_fname = get_out_dir() + current_file_;
-  f_out_.open(index_fname.c_str());
-  f_out_ << "<html><head>" << endl;
-  generate_style_tag();
-  f_out_ << "<title>All Thrift declarations</title></head><body>"
-   << endl << "<div class=\"container-fluid\">"
-   << endl << "<h1>All Thrift declarations</h1>" << endl;
-  f_out_ << "<table class=\"table-bordered table-striped table-condensed\"><thead><th>Module</th><th>Services</th><th>Data types</th>"
-   << "<th>Constants</th></thead>" << endl;
-  vector<t_program*> programs;
-  generate_program_toc_rows(program_, programs);
-  f_out_ << "</table>" << endl;
-  f_out_ << "</div></body></html>" << endl;
-  f_out_.close();
-}
-
-void t_html_generator::generate_css() {
-  if( ! standalone_) {
-    current_file_ = "style.css";
-    string css_fname = get_out_dir() + current_file_;
-    f_out_.open(css_fname.c_str());
-    generate_css_content( f_out_);
-    f_out_.close();
-  }
-}
-
-
-void t_html_generator::generate_css_content(std::ofstream & f_target) {
-  f_target << BOOTSTRAP_CSS() << endl;
-  f_target << "/* Auto-generated CSS for generated Thrift docs */" << endl;
-  f_target << "h3, h4 { margin-bottom: 6px; }" << endl;
-  f_target << "div.definition { border: 1px solid #CCC; margin-bottom: 10px; padding: 10px; }" << endl;
-  f_target << "div.extends { margin: -0.5em 0 1em 5em }" << endl;
-  f_target << "td { vertical-align: top; }" << endl;
-  f_target << "table { empty-cells: show; }" << endl;
-  f_target << "code { line-height: 20px; }" << endl;
-  f_target << ".table-bordered th, .table-bordered td { border-bottom: 1px solid #DDDDDD; }" << endl;
-}
-
-/**
- * Generates the CSS tag. 
- * Depending on "standalone", either a CSS file link (default), or the entire CSS is embedded inline.
- */
-void t_html_generator::generate_style_tag() {
-  if( ! standalone_) {
-    f_out_ << "<link href=\"style.css\" rel=\"stylesheet\" type=\"text/css\"/>" << endl;
-  } else {
-    f_out_ << "<style type=\"text/css\"/><!--" << endl;
-    generate_css_content( f_out_);
-    f_out_ << "--></style>" << endl;
-  } 
-}
-
-/**
- * Returns the target file for a <a href> link 
- * The returned string is empty, whenever filename refers to the current file.
- */
-std::string t_html_generator::make_file_link( std::string filename) {
-  return (current_file_.compare(filename) != 0)  ?  filename  :  "";
-}
-
-/**
- * If the provided documentable object has documentation attached, this
- * will emit it to the output stream in HTML format.
- */
-void t_html_generator::print_doc(t_doc* tdoc) {
-  if (tdoc->has_doc()) {
-    string doc = tdoc->get_doc();
-    size_t index;
-    while ((index = doc.find_first_of("\r\n")) != string::npos) {
-      if (index == 0) {
-        f_out_ << "<p/>" << endl;
-      } else {
-        f_out_ << escape_html( doc.substr(0, index)) << endl;
-      }
-      if (index + 1 < doc.size() && doc.at(index) != doc.at(index + 1) &&
-         (doc.at(index + 1) == '\r' || doc.at(index + 1) == '\n')) {
-        index++;
-      }
-      doc = doc.substr(index + 1);
-    }
-    f_out_ << escape_html(doc) << "<br/>";
-  }
-}
-
-bool t_html_generator::is_utf8_sequence(std::string const & str, size_t firstpos) {
-  // leading char determines the length of the sequence
-  unsigned char c = str.at(firstpos);
-  int count = 0;
-  if(        (c & 0xE0) == 0xC0) {
-    count = 1;
-  } else if( (c & 0xF0) == 0xE0) {
-    count = 2;
-  } else if( (c & 0xF8) == 0xF0) {
-    count = 3;
-  } else if( (c & 0xFC) == 0xF8) {
-    count = 4;
-  } else if( (c & 0xFE) == 0xFC) {
-    count = 5;
-  } else {
-    //pdebug("UTF-8 test: char '%c' (%d) is not a valid UTF-8 leading byte", c, int(c));
-    return false;  // no UTF-8
-  }
-
-  // following chars
-  size_t pos = firstpos + 1;
-  while( (pos < str.length()) && (0 < count))
-  {
-    c = str.at(pos);
-    if( (c & 0xC0) !=  0x80) {
-      //pdebug("UTF-8 test: char '%c' (%d) is not a valid UTF-8 following byte", c, int(c));
-      return false;  // no UTF-8
-    }    
-    --count;
-    ++pos;
-  }
-  
-  // true if the sequence is complete
-  return (0 == count);
-}
-
-void t_html_generator::detect_input_encoding(std::string const & str, size_t firstpos) {
-  if( is_utf8_sequence(str,firstpos))
-  {
-    pdebug( "Input seems to be already UTF-8 encoded");
-    input_type_ = INPUT_UTF8;
-    return;
-  }
-
-  // fallback 
-  pwarning( 1, "Input is not UTF-8, treating as plain ANSI");
-  input_type_ = INPUT_PLAIN;
-}
-
-std::string t_html_generator::escape_html(std::string const & str) {
-
-  // the generated HTML header says it is UTF-8 encoded
-  // if UTF-8 input has been detected before, we don't need to change anything
-  if( input_type_ == INPUT_UTF8) {
-    return str;
-  }
-  
-  // convert unsafe chars to their &#<num>; equivalent
-  std::ostringstream result;
-  unsigned char c = '?';
-  unsigned int ic = 0;
-  size_t lastpos;
-  size_t firstpos = 0;
-  while( firstpos < str.length()) {
-
-    // look for non-ASCII char  
-    lastpos = firstpos;    
-    while( lastpos < str.length()) {
-      c = str.at(lastpos);
-      ic = c;
-      if( (32 > ic) || (127 < ic)) {
-        break;
-      }
-      ++lastpos;
-    }
-    
-    // copy what we got so far    
-    if( lastpos > firstpos) {
-      result << str.substr( firstpos, lastpos-firstpos);
-      firstpos = lastpos;
-    }
-
-    // some control code?
-    if( (0 <= ic) && (31 >= ic))
-    {
-      switch( c)
-      {
-        case '\r' :  
-        case '\n' :  
-          result << "<br/>";  
-          break;
-        case '\t' :
-          result << " ";  
-          break;
-      }
-      ++firstpos;
-      continue;        
-    }
-    
-    // reached the end?
-    if( firstpos >= str.length()) {
-      break;
-    }
-
-    // try to detect input encoding
-    if( input_type_ == INPUT_UNKNOWN) {
-      detect_input_encoding(str,firstpos);
-      if( input_type_ == INPUT_UTF8) {
-        lastpos = str.length();
-        result << str.substr( firstpos, lastpos-firstpos);
-        break;
-      }
-    }
-    
-    // convert the character to something useful based on the detected encoding
-    switch( input_type_) {
-      case INPUT_PLAIN: 
-        result << "&#" << ic << ";";  
-        ++firstpos;
-        break;
-      default:
-        throw "Unexpected or unrecognized input encoding";
-    }
-  }
-  
-  return result.str();
-}
-
-/**
- * Prints out the provided type in HTML
- */
-int t_html_generator::print_type(t_type* ttype) {
-  int len = 0;
-  f_out_ << "<code>";
-  if (ttype->is_container()) {
-    if (ttype->is_list()) {
-      f_out_ << "list&lt;";
-      len = 6 + print_type(((t_list*)ttype)->get_elem_type());
-      f_out_ << "&gt;";
-    } else if (ttype->is_set()) {
-      f_out_ << "set&lt;";
-      len = 5 + print_type(((t_set*)ttype)->get_elem_type());
-      f_out_ << "&gt;";
-    } else if (ttype->is_map()) {
-      f_out_ << "map&lt;";
-      len = 5 + print_type(((t_map*)ttype)->get_key_type());
-      f_out_ << ", ";
-      len += print_type(((t_map*)ttype)->get_val_type());
-      f_out_ << "&gt;";
-    }
-  } else if (ttype->is_base_type()) {
-    f_out_ << (((t_base_type*)ttype)->is_binary() ? "binary" : ttype->get_name());
-    len = ttype->get_name().size();
-  } else {
-    string prog_name = ttype->get_program()->get_name();
-    string type_name = ttype->get_name();
-    f_out_ << "<a href=\"" << prog_name << ".html#";
-    if (ttype->is_typedef()) {
-      f_out_ << "Typedef_";
-    } else if (ttype->is_struct() || ttype->is_xception()) {
-      f_out_ << "Struct_";
-    } else if (ttype->is_enum()) {
-      f_out_ << "Enum_";
-    } else if (ttype->is_service()) {
-      f_out_ << "Svc_";
-    }
-    f_out_ << type_name << "\">";
-    len = type_name.size();
-    if (ttype->get_program() != program_) {
-      f_out_ << prog_name << ".";
-      len += prog_name.size() + 1;
-    }
-    f_out_ << type_name << "</a>";
-  }
-  f_out_ << "</code>";
-  return len;
-}
-
-/**
- * Prints out an HTML representation of the provided constant value
- */
-void t_html_generator::print_const_value(t_const_value* tvalue) {
-  bool first = true;
-  switch (tvalue->get_type()) {
-  case t_const_value::CV_INTEGER:
-    f_out_ << tvalue->get_integer();
-    break;
-  case t_const_value::CV_DOUBLE:
-    f_out_ << tvalue->get_double();
-    break;
-  case t_const_value::CV_STRING:
-    f_out_ << '"' << escape_html( get_escaped_string(tvalue)) << '"';
-    break;
-  case t_const_value::CV_MAP:
-    {
-      f_out_ << "{ ";
-      map<t_const_value*, t_const_value*> map_elems = tvalue->get_map();
-      map<t_const_value*, t_const_value*>::iterator map_iter;
-      for (map_iter = map_elems.begin(); map_iter != map_elems.end(); map_iter++) {
-        if (!first) {
-          f_out_ << ", ";
-        }
-        first = false;
-        print_const_value(map_iter->first);
-        f_out_ << " = ";
-        print_const_value(map_iter->second);
-      }
-      f_out_ << " }";
-    }
-    break;
-  case t_const_value::CV_LIST:
-    {
-      f_out_ << "{ ";
-      vector<t_const_value*> list_elems = tvalue->get_list();;
-      vector<t_const_value*>::iterator list_iter;
-      for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) {
-        if (!first) {
-          f_out_ << ", ";
-        }
-        first = false;
-        print_const_value(*list_iter);
-      }
-      f_out_ << " }";
-    }
-    break;
-  default:
-    f_out_ << "UNKNOWN";
-    break;
-  }
-}
-
-/**
- * Prints out documentation for arguments/exceptions of a function, if any documentation has been supplied.
- */
-void t_html_generator::print_fn_args_doc(t_function* tfunction) {
-  bool has_docs = false;
-  vector<t_field*> args = tfunction->get_arglist()->get_members();
-  vector<t_field*>::iterator arg_iter = args.begin();
-  if (arg_iter != args.end()) {
-    for ( ; arg_iter != args.end(); arg_iter++) {
-      if ((*arg_iter)->has_doc() && !(*arg_iter)->get_doc().empty())
-        has_docs = true;
-    }
-    if (has_docs) {
-      arg_iter = args.begin();
-      f_out_ << "<br/><h4 id=\"Parameters_" << service_name_ << "_" << tfunction->get_name()
-        << "\">Parameters</h4>" << endl;
-      f_out_ << "<table class=\"table-bordered table-striped table-condensed\">";
-      f_out_ << "<thead><th>Name</th><th>Description</th></thead>";
-      for ( ; arg_iter != args.end(); arg_iter++) {
-        f_out_ << "<tr><td>" << (*arg_iter)->get_name();
-        f_out_ << "</td><td>";
-        f_out_ << escape_html( (*arg_iter)->get_doc());
-        f_out_ << "</td></tr>" << endl;
-      }
-      f_out_ << "</table>";
-    }
-  }
-
-  has_docs = false;
-  vector<t_field*> excepts = tfunction->get_xceptions()->get_members();
-  vector<t_field*>::iterator ex_iter = excepts.begin();
-  if (ex_iter != excepts.end()) {
-    for ( ; ex_iter != excepts.end(); ex_iter++) {
-      if ((*ex_iter)->has_doc() && !(*ex_iter)->get_doc().empty())
-        has_docs = true;
-    }
-    if (has_docs) {
-      ex_iter = excepts.begin();
-      f_out_ << "<br/><h4 id=\"Exceptions_" << service_name_ << "_" << tfunction->get_name()
-        << "\">Exceptions</h4>" << endl;
-      f_out_ << "<table class=\"table-bordered table-striped table-condensed\">";
-      f_out_ << "<thead><th>Type</th><th>Description</th></thead>";
-      for ( ; ex_iter != excepts.end(); ex_iter++) {
-        f_out_ << "<tr><td>" << (*ex_iter)->get_type()->get_name();
-        f_out_ << "</td><td>";
-        f_out_ << escape_html( (*ex_iter)->get_doc());
-        f_out_ << "</td></tr>" << endl;
-      }
-      f_out_ << "</table>";
-    }
-  }
-}
-
-/**
- * Generates a typedef.
- *
- * @param ttypedef The type definition
- */
-void t_html_generator::generate_typedef(t_typedef* ttypedef) {
-  string name = ttypedef->get_name();
-  f_out_ << "<div class=\"definition\">";
-  f_out_ << "<h3 id=\"Typedef_" << name << "\">Typedef: " << name
-   << "</h3>" << endl;
-  f_out_ << "<p><strong>Base type:</strong>&nbsp;";
-  print_type(ttypedef->get_type());
-  f_out_ << "</p>" << endl;
-  print_doc(ttypedef);
-  f_out_ << "</div>" << endl;
-}
-
-/**
- * Generates code for an enumerated type.
- *
- * @param tenum The enumeration
- */
-void t_html_generator::generate_enum(t_enum* tenum) {
-  string name = tenum->get_name();
-  f_out_ << "<div class=\"definition\">";
-  f_out_ << "<h3 id=\"Enum_" << name << "\">Enumeration: " << name
-   << "</h3>" << endl;
-  print_doc(tenum);
-  vector<t_enum_value*> values = tenum->get_constants();
-  vector<t_enum_value*>::iterator val_iter;
-  f_out_ << "<br/><table class=\"table-bordered table-striped table-condensed\">" << endl;
-  for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) {
-    f_out_ << "<tr><td><code>";
-    f_out_ << (*val_iter)->get_name();
-    f_out_ << "</code></td><td><code>";
-    f_out_ << (*val_iter)->get_value();
-    f_out_ << "</code></td><td>" << endl;
-    print_doc((*val_iter));
-    f_out_ << "</td></tr>" << endl;
-  }
-  f_out_ << "</table></div>" << endl;
-}
-
-/**
- * Generates a constant value
- */
-void t_html_generator::generate_const(t_const* tconst) {
-  string name = tconst->get_name();
-  f_out_ << "<tr id=\"Const_" << name << "\"><td><code>" << name
-   << "</code></td><td>";
-  print_type(tconst->get_type());
-  f_out_ << "</td><td><code>";
-  print_const_value(tconst->get_value());
-  f_out_ << "</code></td></tr>";
-  if (tconst->has_doc()) {
-    f_out_ << "<tr><td colspan=\"3\"><blockquote>";
-    print_doc(tconst);
-    f_out_ << "</blockquote></td></tr>";
-  }
-}
-
-/**
- * Generates a struct definition for a thrift data type.
- *
- * @param tstruct The struct definition
- */
-void t_html_generator::generate_struct(t_struct* tstruct) {
-  string name = tstruct->get_name();
-  f_out_ << "<div class=\"definition\">";
-  f_out_ << "<h3 id=\"Struct_" << name << "\">";
-  if (tstruct->is_xception()) {
-    f_out_ << "Exception: ";
-  } else if (tstruct->is_union()) {
-    f_out_ << "Union: ";
-  } else {
-    f_out_ << "Struct: ";
-  }
-  f_out_ << name << "</h3>" << endl;
-  vector<t_field*> members = tstruct->get_members();
-  vector<t_field*>::iterator mem_iter = members.begin();
-  f_out_ << "<table class=\"table-bordered table-striped table-condensed\">";
-  f_out_ << "<thead><th>Key</th><th>Field</th><th>Type</th><th>Description</th><th>Requiredness</th><th>Default value</th></thead>"
-    << endl;
-  for ( ; mem_iter != members.end(); mem_iter++) {
-    f_out_ << "<tr><td>" << (*mem_iter)->get_key() << "</td><td>";
-    f_out_ << (*mem_iter)->get_name();
-    f_out_ << "</td><td>";
-    print_type((*mem_iter)->get_type());
-    f_out_ << "</td><td>";
-    f_out_ << escape_html( (*mem_iter)->get_doc());
-    f_out_ << "</td><td>";
-    if ((*mem_iter)->get_req() == t_field::T_OPTIONAL) {
-      f_out_ << "optional";
-    } else if ((*mem_iter)->get_req() == t_field::T_REQUIRED) {
-      f_out_ << "required";
-    } else {
-      f_out_ << "default";
-    }
-    f_out_ << "</td><td>";
-    t_const_value* default_val = (*mem_iter)->get_value();
-    if (default_val != NULL) {
-      print_const_value(default_val);
-    }
-    f_out_ << "</td></tr>" << endl;
-  }
-  f_out_ << "</table><br/>";
-  print_doc(tstruct);
-  f_out_ << "</div>";
-}
-
-/**
- * Exceptions are special structs
- *
- * @param tstruct The struct definition
- */
-void t_html_generator::generate_xception(t_struct* txception) {
-  generate_struct(txception);
-}
-
-/**
- * Generates the HTML block for a Thrift service.
- *
- * @param tservice The service definition
- */
-void t_html_generator::generate_service(t_service* tservice) {
-  f_out_ << "<h3 id=\"Svc_" << service_name_ << "\">Service: "
-    << service_name_ << "</h3>" << endl;
-
-  if (tservice->get_extends()) {
-    f_out_ << "<div class=\"extends\"><em>extends</em> ";
-    print_type(tservice->get_extends());
-    f_out_ << "</div>\n";
-  }
-  print_doc(tservice);
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator fn_iter = functions.begin();
-  for ( ; fn_iter != functions.end(); fn_iter++) {
-    string fn_name = (*fn_iter)->get_name();
-    f_out_ << "<div class=\"definition\">";
-    f_out_ << "<h4 id=\"Fn_" << service_name_ << "_" << fn_name
-      << "\">Function: " << service_name_ << "." << fn_name
-      << "</h4>" << endl;
-    f_out_ << "<pre>";
-    int offset = print_type((*fn_iter)->get_returntype());
-    bool first = true;
-    f_out_ << " " << fn_name << "(";
-    offset += fn_name.size() + 2;
-    vector<t_field*> args = (*fn_iter)->get_arglist()->get_members();
-    vector<t_field*>::iterator arg_iter = args.begin();
-    for ( ; arg_iter != args.end(); arg_iter++) {
-      if (!first) {
-        f_out_ << "," << endl;
-        for (int i = 0; i < offset; ++i) {
-          f_out_ << " ";
-        }
-      }
-      first = false;
-      print_type((*arg_iter)->get_type());
-      f_out_ << " " << (*arg_iter)->get_name();
-      if ((*arg_iter)->get_value() != NULL) {
-        f_out_ << " = ";
-        print_const_value((*arg_iter)->get_value());
-      }
-    }
-    f_out_ << ")" << endl;
-    first = true;
-    vector<t_field*> excepts = (*fn_iter)->get_xceptions()->get_members();
-    vector<t_field*>::iterator ex_iter = excepts.begin();
-    if (ex_iter != excepts.end()) {
-      f_out_ << "    throws ";
-      for ( ; ex_iter != excepts.end(); ex_iter++) {
-        if (!first) {
-          f_out_ << ", ";
-        }
-        first = false;
-        print_type((*ex_iter)->get_type());
-      }
-      f_out_ << endl;
-    }
-    f_out_ << "</pre>";
-    print_doc(*fn_iter);
-    print_fn_args_doc(*fn_iter);
-    f_out_ << "</div>";
-  }
-}
-
-THRIFT_REGISTER_GENERATOR(html, "HTML",
-"    standalone:      Self-contained mode, includes all CSS in the HTML files.\n"
-"                     Generates no style.css file, but HTML files will be larger.\n"
-)
diff --git a/compiler/cpp/src/generate/t_html_generator.h b/compiler/cpp/src/generate/t_html_generator.h
deleted file mode 100644
index e40edd3..0000000
--- a/compiler/cpp/src/generate/t_html_generator.h
+++ /dev/null
@@ -1,176 +0,0 @@
-#define BOOTSTRAP_CSS() "/*!\n"\
-" * Bootstrap v2.0.3\n"\
-" *\n"\
-" * Copyright 2012 Twitter, Inc\n"\
-" * Licensed under the Apache License v2.0\n"\
-" * http://www.apache.org/licenses/LICENSE-2.0\n"\
-" *\n"\
-" * Designed and built with all the love in the world @twitter by @mdo and @fat.\n"\
-" */\n"\
-".clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:\"\";}\n"\
-".clearfix:after{clear:both;}\n"\
-".hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;}\n"\
-".input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;}\n"\
-"article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}\n"\
-"audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}\n"\
-"audio:not([controls]){display:none;}\n"\
-"html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}\n"\
-"a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}\n"\
-"a:hover,a:active{outline:0;}\n"\
-"sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}\n"\
-"sup{top:-0.5em;}\n"\
-"sub{bottom:-0.25em;}\n"\
-"img{max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;}\n"\
-"button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}\n"\
-"button,input{*overflow:visible;line-height:normal;}\n"\
-"button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}\n"\
-"button,input[type=\"button\"],input[type=\"reset\"],input[type=\"submit\"]{cursor:pointer;-webkit-appearance:button;}\n"\
-"input[type=\"search\"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield;}\n"\
-"input[type=\"search\"]::-webkit-search-decoration,input[type=\"search\"]::-webkit-search-cancel-button{-webkit-appearance:none;}\n"\
-"textarea{overflow:auto;vertical-align:top;}\n"\
-"body{margin:0;font-family:\"Helvetica Neue\",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;}\n"\
-"a{color:#0088cc;text-decoration:none;}\n"\
-"a:hover{color:#005580;text-decoration:underline;}\n"\
-".row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:\"\";}\n"\
-".row:after{clear:both;}\n"\
-"[class*=\"span\"]{float:left;margin-left:20px;}\n"\
-".container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}\n"\
-".span12{width:940px;}\n"\
-".span11{width:860px;}\n"\
-".span10{width:780px;}\n"\
-".span9{width:700px;}\n"\
-".span8{width:620px;}\n"\
-".span7{width:540px;}\n"\
-".span6{width:460px;}\n"\
-".span5{width:380px;}\n"\
-".span4{width:300px;}\n"\
-".span3{width:220px;}\n"\
-".span2{width:140px;}\n"\
-".span1{width:60px;}\n"\
-".offset12{margin-left:980px;}\n"\
-".offset11{margin-left:900px;}\n"\
-".offset10{margin-left:820px;}\n"\
-".offset9{margin-left:740px;}\n"\
-".offset8{margin-left:660px;}\n"\
-".offset7{margin-left:580px;}\n"\
-".offset6{margin-left:500px;}\n"\
-".offset5{margin-left:420px;}\n"\
-".offset4{margin-left:340px;}\n"\
-".offset3{margin-left:260px;}\n"\
-".offset2{margin-left:180px;}\n"\
-".offset1{margin-left:100px;}\n"\
-".row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:\"\";}\n"\
-".row-fluid:after{clear:both;}\n"\
-".row-fluid [class*=\"span\"]{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574%;*margin-left:2.0744680846382977%;}\n"\
-".row-fluid [class*=\"span\"]:first-child{margin-left:0;}\n"\
-".row-fluid .span12{width:99.99999998999999%;*width:99.94680850063828%;}\n"\
-".row-fluid .span11{width:91.489361693%;*width:91.4361702036383%;}\n"\
-".row-fluid .span10{width:82.97872339599999%;*width:82.92553190663828%;}\n"\
-".row-fluid .span9{width:74.468085099%;*width:74.4148936096383%;}\n"\
-".row-fluid .span8{width:65.95744680199999%;*width:65.90425531263828%;}\n"\
-".row-fluid .span7{width:57.446808505%;*width:57.3936170156383%;}\n"\
-".row-fluid .span6{width:48.93617020799999%;*width:48.88297871863829%;}\n"\
-".row-fluid .span5{width:40.425531911%;*width:40.3723404216383%;}\n"\
-".row-fluid .span4{width:31.914893614%;*width:31.8617021246383%;}\n"\
-".row-fluid .span3{width:23.404255317%;*width:23.3510638276383%;}\n"\
-".row-fluid .span2{width:14.89361702%;*width:14.8404255306383%;}\n"\
-".row-fluid .span1{width:6.382978723%;*width:6.329787233638298%;}\n"\
-".container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{display:table;content:\"\";}\n"\
-".container:after{clear:both;}\n"\
-".container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:\"\";}\n"\
-".container-fluid:after{clear:both;}\n"\
-"p{margin:0 0 9px;font-family:\"Helvetica Neue\",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p small{font-size:11px;color:#999999;}\n"\
-".lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;}\n"\
-"h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;}\n"\
-"h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;}\n"\
-"h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;}\n"\
-"h3{font-size:18px;line-height:27px;}h3 small{font-size:14px;}\n"\
-"h4,h5,h6{line-height:18px;}\n"\
-"h4{font-size:14px;}h4 small{font-size:12px;}\n"\
-"h5{font-size:12px;}\n"\
-"h6{font-size:11px;color:#999999;text-transform:uppercase;}\n"\
-".page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;}\n"\
-".page-header h1{line-height:1;}\n"\
-"ul,ol{padding:0;margin:0 0 9px 25px;}\n"\
-"ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}\n"\
-"ul{list-style:disc;}\n"\
-"ol{list-style:decimal;}\n"\
-"li{line-height:18px;}\n"\
-"ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}\n"\
-"dl{margin-bottom:18px;}\n"\
-"dt,dd{line-height:18px;}\n"\
-"dt{font-weight:bold;line-height:17px;}\n"\
-"dd{margin-left:9px;}\n"\
-".dl-horizontal dt{float:left;width:120px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}\n"\
-".dl-horizontal dd{margin-left:130px;}\n"\
-"hr{margin:18px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}\n"\
-"strong{font-weight:bold;}\n"\
-"em{font-style:italic;}\n"\
-".muted{color:#999999;}\n"\
-"abbr[title]{cursor:help;border-bottom:1px dotted #ddd;}\n"\
-"abbr.initialism{font-size:90%;text-transform:uppercase;}\n"\
-"blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;}\n"\
-"blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\\2014 \\00A0';}\n"\
-"blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;}\n"\
-"q:before,q:after,blockquote:before,blockquote:after{content:\"\";}\n"\
-"address{display:block;margin-bottom:18px;font-style:normal;line-height:18px;}\n"\
-"small{font-size:100%;}\n"\
-"cite{font-style:normal;}\n"\
-"code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,Consolas,\"Courier New\",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}\n"\
-"code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;}\n"\
-"pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12.025px;line-height:18px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}pre.prettyprint{margin-bottom:18px;}\n"\
-"pre code{padding:0;color:inherit;background-color:transparent;border:0;}\n"\
-".pre-scrollable{max-height:340px;overflow-y:scroll;}\n"\
-".label,.badge{font-size:10.998px;font-weight:bold;line-height:14px;color:#ffffff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;}\n"\
-".label{padding:1px 4px 2px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}\n"\
-".badge{padding:1px 9px 2px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;}\n"\
-"a.label:hover,a.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;}\n"\
-".label-important,.badge-important{background-color:#b94a48;}\n"\
-".label-important[href],.badge-important[href]{background-color:#953b39;}\n"\
-".label-warning,.badge-warning{background-color:#f89406;}\n"\
-".label-warning[href],.badge-warning[href]{background-color:#c67605;}\n"\
-".label-success,.badge-success{background-color:#468847;}\n"\
-".label-success[href],.badge-success[href]{background-color:#356635;}\n"\
-".label-info,.badge-info{background-color:#3a87ad;}\n"\
-".label-info[href],.badge-info[href]{background-color:#2d6987;}\n"\
-".label-inverse,.badge-inverse{background-color:#333333;}\n"\
-".label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;}\n"\
-"table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;}\n"\
-".table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;}\n"\
-".table th{font-weight:bold;}\n"\
-".table thead th{vertical-align:bottom;}\n"\
-".table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;}\n"\
-".table tbody+tbody{border-top:2px solid #dddddd;}\n"\
-".table-condensed th,.table-condensed td{padding:4px 5px;}\n"\
-".table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapsed;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;}\n"\
-".table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;}\n"\
-".table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px;}\n"\
-".table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px;}\n"\
-".table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;}\n"\
-".table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;}\n"\
-".table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;}\n"\
-".table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5;}\n"\
-"table .span1{float:none;width:44px;margin-left:0;}\n"\
-"table .span2{float:none;width:124px;margin-left:0;}\n"\
-"table .span3{float:none;width:204px;margin-left:0;}\n"\
-"table .span4{float:none;width:284px;margin-left:0;}\n"\
-"table .span5{float:none;width:364px;margin-left:0;}\n"\
-"table .span6{float:none;width:444px;margin-left:0;}\n"\
-"table .span7{float:none;width:524px;margin-left:0;}\n"\
-"table .span8{float:none;width:604px;margin-left:0;}\n"\
-"table .span9{float:none;width:684px;margin-left:0;}\n"\
-"table .span10{float:none;width:764px;margin-left:0;}\n"\
-"table .span11{float:none;width:844px;margin-left:0;}\n"\
-"table .span12{float:none;width:924px;margin-left:0;}\n"\
-"table .span13{float:none;width:1004px;margin-left:0;}\n"\
-"table .span14{float:none;width:1084px;margin-left:0;}\n"\
-"table .span15{float:none;width:1164px;margin-left:0;}\n"\
-"table .span16{float:none;width:1244px;margin-left:0;}\n"\
-"table .span17{float:none;width:1324px;margin-left:0;}\n"\
-"table .span18{float:none;width:1404px;margin-left:0;}\n"\
-"table .span19{float:none;width:1484px;margin-left:0;}\n"\
-"table .span20{float:none;width:1564px;margin-left:0;}\n"\
-"table .span21{float:none;width:1644px;margin-left:0;}\n"\
-"table .span22{float:none;width:1724px;margin-left:0;}\n"\
-"table .span23{float:none;width:1804px;margin-left:0;}\n"\
-"table .span24{float:none;width:1884px;margin-left:0;}"
diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc
deleted file mode 100644
index e443dc0..0000000
--- a/compiler/cpp/src/generate/t_java_generator.cc
+++ /dev/null
@@ -1,4532 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <cassert>
-
-#include <sstream>
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-#include <cctype>
-
-#include <sys/stat.h>
-#include <stdexcept>
-
-#include "platform.h"
-#include "t_oop_generator.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * Java code generator.
- *
- */
-class t_java_generator : public t_oop_generator {
-public:
-  t_java_generator(
-                   t_program* program,
-                   const std::map<std::string, std::string>& parsed_options,
-                   const std::string& option_string)
-  : t_oop_generator(program)
-  {
-    (void) option_string;
-    std::map<std::string, std::string>::const_iterator iter;
-
-    iter = parsed_options.find("beans");
-    bean_style_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("private-members");
-    private_members_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("nocamel");
-    nocamel_style_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("hashcode");
-    gen_hash_code_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("android_legacy");
-    android_legacy_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("sorted_containers");
-    sorted_containers_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("java5");
-    java5_ = (iter != parsed_options.end());
-    if (java5_) {
-      android_legacy_ = true;
-    }
-
-    out_dir_base_ = (bean_style_ ? "gen-javabean" : "gen-java");
-  }
-
-  /**
-   * Init and close methods
-   */
-
-  void init_generator();
-  void close_generator();
-
-  void generate_consts(std::vector<t_const*> consts);
-
-  /**
-   * Program-level generation functions
-   */
-
-  void generate_typedef (t_typedef*  ttypedef);
-  void generate_enum    (t_enum*     tenum);
-  void generate_struct  (t_struct*   tstruct);
-  void generate_union   (t_struct*   tunion);
-  void generate_xception(t_struct*   txception);
-  void generate_service (t_service*  tservice);
-
-  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool in_static, bool defval=false);
-  std::string render_const_value(std::ofstream& out, t_type* type, t_const_value* value);
-
-  /**
-   * Service-level generation functions
-   */
-
-  void generate_java_struct(t_struct* tstruct, bool is_exception);
-
-  void generate_java_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool in_class=false, bool is_result=false);
-  void generate_java_struct_equality(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_compare_to(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_reader(std::ofstream& out, t_struct* tstruct);
-  void generate_java_validator(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_result_writer(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_writer(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_tostring(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_clear(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_write_object(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_read_object(std::ofstream& out, t_struct* tstruct);
-  void generate_java_meta_data_map(std::ofstream& out, t_struct* tstruct);
-  void generate_field_value_meta_data(std::ofstream& out, t_type* type);
-  std::string get_java_type_string(t_type* type);
-  void generate_java_struct_field_by_id(ofstream& out, t_struct* tstruct);
-  void generate_reflection_setters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name);
-  void generate_reflection_getters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name);
-  void generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct);
-  void generate_generic_isset_method(std::ofstream& out, t_struct* tstruct);
-  void generate_java_bean_boilerplate(std::ofstream& out, t_struct* tstruct);
-
-  void generate_function_helpers(t_function* tfunction);
-  std::string get_cap_name(std::string name);
-  std::string generate_isset_check(t_field* field);
-  std::string generate_isset_check(std::string field);
-  void generate_isset_set(ofstream& out, t_field* field, std::string prefix);
-  std::string isset_field_id(t_field* field);
-
-  void generate_service_interface (t_service* tservice);
-  void generate_service_async_interface(t_service* tservice);
-  void generate_service_helpers   (t_service* tservice);
-  void generate_service_client    (t_service* tservice);
-  void generate_service_async_client(t_service* tservice);
-  void generate_service_server    (t_service* tservice);
-  void generate_service_async_server    (t_service* tservice);
-  void generate_process_function  (t_service* tservice, t_function* tfunction);
-  void generate_process_async_function  (t_service* tservice, t_function* tfunction);
-
-
-  void generate_java_union(t_struct* tstruct);
-  void generate_union_constructor(ofstream& out, t_struct* tstruct);
-  void generate_union_getters_and_setters(ofstream& out, t_struct* tstruct);
-  void generate_union_is_set_methods(ofstream& out, t_struct* tstruct);
-  void generate_union_abstract_methods(ofstream& out, t_struct* tstruct);
-  void generate_check_type(ofstream& out, t_struct* tstruct);
-  void generate_standard_scheme_read_value(ofstream& out, t_struct* tstruct);
-  void generate_standard_scheme_write_value(ofstream& out, t_struct* tstruct);
-  void generate_tuple_scheme_read_value(ofstream& out, t_struct* tstruct);
-  void generate_tuple_scheme_write_value(ofstream& out, t_struct* tstruct);
-  void generate_get_field_desc(ofstream& out, t_struct* tstruct);
-  void generate_get_struct_desc(ofstream& out, t_struct* tstruct);
-  void generate_get_field_name(ofstream& out, t_struct* tstruct);
-
-  void generate_union_comparisons(ofstream& out, t_struct* tstruct);
-  void generate_union_hashcode(ofstream& out, t_struct* tstruct);
-
-  void generate_scheme_map(ofstream& out, t_struct* tstruct);
-  void generate_standard_writer(ofstream& out, t_struct* tstruct, bool is_result);
-  void generate_standard_reader(ofstream& out, t_struct* tstruct);
-  void generate_java_struct_standard_scheme(ofstream& out, t_struct* tstruct, bool is_result);
-
-  void generate_java_struct_tuple_scheme(ofstream& out, t_struct* tstruct);
-  void generate_java_struct_tuple_reader(ofstream& out, t_struct* tstruct);
-  void generate_java_struct_tuple_writer(ofstream& out, t_struct* tstruct);
-
-  /**
-   * Serialization constructs
-   */
-
-  void generate_deserialize_field        (std::ofstream& out,
-                                          t_field*    tfield,
-                                          std::string prefix="",
-                                          bool has_metadata = true);
-
-  void generate_deserialize_struct       (std::ofstream& out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_deserialize_container    (std::ofstream& out,
-                                          t_type*     ttype,
-                                          std::string prefix="",
-                                          bool has_metadata = true);
-
-  void generate_deserialize_set_element  (std::ofstream& out,
-                                          t_set*      tset,
-                                          std::string prefix="",
-                                          bool has_metadata = true);
-
-  void generate_deserialize_map_element  (std::ofstream& out,
-                                          t_map*      tmap,
-                                          std::string prefix="",
-                                          bool has_metadata = true);
-
-  void generate_deserialize_list_element (std::ofstream& out,
-                                          t_list*     tlist,
-                                          std::string prefix="",
-                                          bool has_metadata = true);
-
-  void generate_serialize_field          (std::ofstream& out,
-                                          t_field*    tfield,
-                                          std::string prefix="",
-                                          bool has_metadata = true);
-
-  void generate_serialize_struct         (std::ofstream& out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_serialize_container      (std::ofstream& out,
-                                          t_type*     ttype,
-                                          std::string prefix="",
-                                          bool has_metadata = true);
-
-  void generate_serialize_map_element    (std::ofstream& out,
-                                          t_map*      tmap,
-                                          std::string iter,
-                                          std::string map,
-                                          bool has_metadata = true);
-
-  void generate_serialize_set_element    (std::ofstream& out,
-                                          t_set*      tmap,
-                                          std::string iter,
-                                          bool has_metadata = true);
-
-  void generate_serialize_list_element   (std::ofstream& out,
-                                          t_list*     tlist,
-                                          std::string iter,
-                                          bool has_metadata = true);
-
-  void generate_java_doc                 (std::ofstream& out,
-                                          t_field*    field);
-
-  void generate_java_doc                 (std::ofstream& out,
-                                          t_doc*      tdoc);
-
-  void generate_java_doc                 (std::ofstream& out,
-                                          t_function* tdoc);
-
-  void generate_java_docstring_comment   (std::ofstream &out,
-                                          string contents);
-
-  void generate_deep_copy_container(std::ofstream& out, std::string source_name_p1, std::string source_name_p2, std::string result_name, t_type* type);
-  void generate_deep_copy_non_container(std::ofstream& out, std::string source_name, std::string dest_name, t_type* type);
-
-  enum isset_type { ISSET_NONE, ISSET_PRIMITIVE, ISSET_BITSET };
-  isset_type needs_isset(t_struct* tstruct, std::string *outPrimitiveType = NULL);
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string java_package();
-  std::string java_type_imports();
-  std::string type_name(t_type* ttype, bool in_container=false, bool in_init=false, bool skip_generic=false);
-  std::string base_type_name(t_base_type* tbase, bool in_container=false);
-  std::string declare_field(t_field* tfield, bool init=false, bool comment=false);
-  std::string function_signature(t_function* tfunction, std::string prefix="");
-  std::string function_signature_async(t_function* tfunction, bool use_base_method = false, std::string prefix="");
-  std::string argument_list(t_struct* tstruct, bool include_types = true);
-  std::string async_function_call_arglist(t_function* tfunc, bool use_base_method = true, bool include_types = true);
-  std::string async_argument_list(t_function* tfunct, t_struct* tstruct, t_type* ttype, bool include_types=false);
-  std::string type_to_enum(t_type* ttype);
-  std::string get_enum_class_name(t_type* type);
-  void generate_struct_desc(ofstream& out, t_struct* tstruct);
-  void generate_field_descs(ofstream& out, t_struct* tstruct);
-  void generate_field_name_constants(ofstream& out, t_struct* tstruct);
-
-  std::string make_valid_java_filename( std::string const & fromName);
-  std::string make_valid_java_identifier( std::string const & fromName);
-  
-  bool type_can_be_null(t_type* ttype) {
-    ttype = get_true_type(ttype);
-
-    return
-      ttype->is_container() ||
-      ttype->is_struct() ||
-      ttype->is_xception() ||
-      ttype->is_string() ||
-      ttype->is_enum();
-  }
-
-  std::string constant_name(std::string name);
-
- private:
-
-  /**
-   * File streams
-   */
-
-  std::string package_name_;
-  std::ofstream f_service_;
-  std::string package_dir_;
-
-  bool bean_style_;
-  bool private_members_;
-  bool nocamel_style_;
-  bool gen_hash_code_;
-  bool android_legacy_;
-  bool java5_;
-  bool sorted_containers_;
-};
-
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * streams.
- *
- * @param tprogram The program to generate
- */
-void t_java_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-  package_name_ = program_->get_namespace("java");
-
-  string dir = package_name_;
-  string subdir = get_out_dir();
-  string::size_type loc;
-  while ((loc = dir.find(".")) != string::npos) {
-    subdir = subdir + "/" + dir.substr(0, loc);
-    MKDIR(subdir.c_str());
-    dir = dir.substr(loc+1);
-  }
-  if (dir.size() > 0) {
-    subdir = subdir + "/" + dir;
-    MKDIR(subdir.c_str());
-  }
-
-  package_dir_ = subdir;
-}
-
-/**
- * Packages the generated file
- *
- * @return String of the package, i.e. "package org.apache.thriftdemo;"
- */
-string t_java_generator::java_package() {
-  if (!package_name_.empty()) {
-    return string("package ") + package_name_ + ";\n\n";
-  }
-  return "";
-}
-
-/**
- * Prints standard java imports
- *
- * @return List of imports for Java types that are used in here
- */
-string t_java_generator::java_type_imports() {
-  string hash_builder;
-  string tree_set_and_map;
-  if (gen_hash_code_) {
-    hash_builder = "import org.apache.commons.lang3.builder.HashCodeBuilder;\n";
-  }
-  if (sorted_containers_) {
-    tree_set_and_map = string() + 
-      "import java.util.TreeSet;\n" +
-      "import java.util.TreeMap;\n";
-  }
-
-  return
-    string() +
-    hash_builder +
-    "import org.apache.thrift.scheme.IScheme;\n" +
-    "import org.apache.thrift.scheme.SchemeFactory;\n" +
-    "import org.apache.thrift.scheme.StandardScheme;\n\n" +
-    "import org.apache.thrift.scheme.TupleScheme;\n" +
-    "import org.apache.thrift.protocol.TTupleProtocol;\n" +
-    "import org.apache.thrift.protocol.TProtocolException;\n" +
-    "import org.apache.thrift.EncodingUtils;\n" +
-    "import org.apache.thrift.TException;\n" +
-    "import org.apache.thrift.async.AsyncMethodCallback;\n"+
-    "import org.apache.thrift.server.AbstractNonblockingServer.*;\n"+
-    "import java.util.List;\n" +
-    "import java.util.ArrayList;\n" +
-    "import java.util.Map;\n" +
-    "import java.util.HashMap;\n" +
-    "import java.util.EnumMap;\n" +
-    "import java.util.Set;\n" +
-    "import java.util.HashSet;\n" +
-    "import java.util.EnumSet;\n" +
-    tree_set_and_map + 
-    "import java.util.Collections;\n" +
-    "import java.util.BitSet;\n" +
-    "import java.nio.ByteBuffer;\n"
-    "import java.util.Arrays;\n" +
-    "import org.slf4j.Logger;\n" +
-    "import org.slf4j.LoggerFactory;\n\n";
-}
-
-/**
- * Nothing in Java
- */
-void t_java_generator::close_generator() {}
-
-/**
- * Generates a typedef. This is not done in Java, since it does
- * not support arbitrary name replacements, and it'd be a wacky waste
- * of overhead to make wrapper classes.
- *
- * @param ttypedef The type definition
- */
-void t_java_generator::generate_typedef(t_typedef* ttypedef) {
-  (void) ttypedef;
-}
-
-/**
- * Enums are a class with a set of static constants.
- *
- * @param tenum The enumeration
- */
-void t_java_generator::generate_enum(t_enum* tenum) {
-  // Make output file
-  string f_enum_name = package_dir_+"/"+make_valid_java_filename(tenum->get_name())+".java";
-  ofstream f_enum;
-  f_enum.open(f_enum_name.c_str());
-
-  // Comment and package it
-  f_enum <<
-    autogen_comment() <<
-    java_package() << endl;
-
-  // Add java imports
-  f_enum << string() +
-    "import java.util.Map;\n" + 
-    "import java.util.HashMap;\n" +
-    "import org.apache.thrift.TEnum;" << endl << endl;
-
-  generate_java_doc(f_enum, tenum);
-  indent(f_enum) <<
-    "public enum " << tenum->get_name() << " implements org.apache.thrift.TEnum ";
-  scope_up(f_enum);
-
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  bool first = true;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-
-    if (first) {
-      first = false;
-    } else {
-      f_enum << "," << endl;
-    }
-
-    generate_java_doc(f_enum, *c_iter);
-    indent(f_enum) << (*c_iter)->get_name() << "(" << value << ")";
-  }
-  f_enum << ";" << endl << endl;
-
-  // Field for thriftCode
-  indent(f_enum) << "private final int value;" << endl << endl;
-
-  indent(f_enum) << "private " << tenum->get_name() << "(int value) {" << endl;
-  indent(f_enum) << "  this.value = value;" <<endl;
-  indent(f_enum) << "}" << endl << endl;
-
-  indent(f_enum) << "/**" << endl;
-  indent(f_enum) << " * Get the integer value of this enum value, as defined in the Thrift IDL." << endl;
-  indent(f_enum) << " */" << endl;
-  indent(f_enum) << "public int getValue() {" << endl;
-  indent(f_enum) << "  return value;" <<endl;
-  indent(f_enum) << "}" << endl << endl;
-
-  indent(f_enum) << "/**" << endl;
-  indent(f_enum) << " * Find a the enum type by its integer value, as defined in the Thrift IDL." << endl;
-  indent(f_enum) << " * @return null if the value is not found." << endl;
-  indent(f_enum) << " */" << endl;
-  indent(f_enum) << "public static "+ tenum->get_name() + " findByValue(int value) { " << endl;
-
-  indent_up();
-
-  indent(f_enum) << "switch (value) {" << endl;
-  indent_up();
-
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    indent(f_enum) << "case " << value << ":" << endl;
-    indent(f_enum) << "  return " << (*c_iter)->get_name() << ";" << endl;
-  }
-
-  indent(f_enum) << "default:" << endl;
-  indent(f_enum) << "  return null;" << endl;  
-
-  indent_down();
-
-  indent(f_enum) << "}" << endl;
-
-  indent_down();
-
-  indent(f_enum) << "}" << endl;
-
-  scope_down(f_enum);
-
-  f_enum.close();
-}
-
-/**
- * Generates a class that holds all the constants.
- */
-void t_java_generator::generate_consts(std::vector<t_const*> consts) {
-  if (consts.empty()) {
-    return;
-  }
-
-  string f_consts_name = package_dir_+ '/' + make_valid_java_filename(program_name_) + "Constants.java";
-  ofstream f_consts;
-  f_consts.open(f_consts_name.c_str());
-
-  // Print header
-  f_consts <<
-    autogen_comment() <<
-    java_package() <<
-    java_type_imports();
-
-  f_consts <<
-    "public class " << make_valid_java_identifier(program_name_) << "Constants {" << endl <<
-    endl;
-  indent_up();
-  vector<t_const*>::iterator c_iter;
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    generate_java_doc(f_consts, (*c_iter));
-    print_const_value(f_consts,
-                      (*c_iter)->get_name(),
-                      (*c_iter)->get_type(),
-                      (*c_iter)->get_value(),
-                      false);
-  }
-  indent_down();
-  indent(f_consts) << "}" << endl;
-  f_consts.close();
-}
-
-
-/**
- * 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
- */
-void t_java_generator::print_const_value(std::ofstream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval) {
-  type = get_true_type(type);
-
-  indent(out);
-  if (!defval) {
-    out <<
-      (in_static ? "" : "public static final ") <<
-      type_name(type) << " ";
-  }
-  if (type->is_base_type()) {
-    string v2 = render_const_value(out, type, value);
-    out << name << " = " << v2 << ";" << endl << endl;
-  } else if (type->is_enum()) {
-    out << name << " = " << render_const_value(out, type, value) << ";" << endl << endl;
-  } else if (type->is_struct() || type->is_xception()) {
-    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;
-    out << name << " = new " << type_name(type, false, true) << "();" << endl;
-    if (!in_static) {
-      indent(out) << "static {" << endl;
-      indent_up();
-    }
-    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();
-      }
-      string val = render_const_value(out, field_type, v_iter->second);
-      indent(out) << name << ".";
-      std::string cap_name = get_cap_name(v_iter->first->get_string());
-      out << "set" << cap_name << "(" << val << ");" << endl;
-    }
-    if (!in_static) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    out << endl;
-  } else if (type->is_map()) {
-    out << name << " = new " << type_name(type, false, true) << "();" << endl;
-    if (!in_static) {
-      indent(out) << "static {" << endl;
-      indent_up();
-    }
-    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();
-    map<t_const_value*, t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string key = render_const_value(out, ktype, v_iter->first);
-      string val = render_const_value(out, vtype, v_iter->second);
-      indent(out) << name << ".put(" << key << ", " << val << ");" << endl;
-    }
-    if (!in_static) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    out << endl;
-  } else if (type->is_list() || type->is_set()) {
-    out << name << " = new " << type_name(type, false, true) << "();" << endl;
-    if (!in_static) {
-      indent(out) << "static {" << endl;
-      indent_up();
-    }
-    t_type* etype;
-    if (type->is_list()) {
-      etype = ((t_list*)type)->get_elem_type();
-    } else {
-      etype = ((t_set*)type)->get_elem_type();
-    }
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string val = render_const_value(out, etype, *v_iter);
-      indent(out) << name << ".add(" << val << ");" << endl;
-    }
-    if (!in_static) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    out << endl;
-  } else {
-    throw "compiler error: no const of type " + type->get_name();
-  }
-}
-
-string t_java_generator::render_const_value(ofstream& out, t_type* type, t_const_value* value) {
-  type = get_true_type(type);
-  std::ostringstream render;
-
-  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:
-        render << '"' << get_escaped_string(value) << '"';
-        break;
-      case t_base_type::TYPE_BOOL:
-        render << ((value->get_integer() > 0) ? "true" : "false");
-        break;
-      case t_base_type::TYPE_BYTE:
-        render << "(byte)" << value->get_integer();
-        break;
-      case t_base_type::TYPE_I16:
-        render << "(short)" << value->get_integer();
-        break;
-      case t_base_type::TYPE_I32:
-        render << value->get_integer();
-        break;
-      case t_base_type::TYPE_I64:
-        render << value->get_integer() << "L";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        if (value->get_type() == t_const_value::CV_INTEGER) {
-          render << "(double)" << value->get_integer();
-        } else {
-          render << 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()) {
-    render << type->get_program()->get_namespace("java") << "." << value->get_identifier_with_parent();
-  } else {
-    string t = tmp("tmp");
-    print_const_value(out, t, type, value, true);
-    render << t;
-  }
-
-  return render.str();
-}
-
-/**
- * Generates a struct definition for a thrift data type. This will be a org.apache.thrift.TBase 
- * implementor.
- *
- * @param tstruct The struct definition
- */
-void t_java_generator::generate_struct(t_struct* tstruct) {
-  if (tstruct->is_union()) {
-    generate_java_union(tstruct);
-  } else {
-    generate_java_struct(tstruct, false);
-  }
-}
-
-/**
- * Exceptions are structs, but they inherit from Exception
- *
- * @param tstruct The struct definition
- */
-void t_java_generator::generate_xception(t_struct* txception) {
-  generate_java_struct(txception, true);
-}
-
-
-/**
- * Java struct definition.
- *
- * @param tstruct The struct definition
- */
-void t_java_generator::generate_java_struct(t_struct* tstruct,
-                                            bool is_exception) {
-  // Make output file
-  string f_struct_name = package_dir_+"/"+make_valid_java_filename(tstruct->get_name())+".java";
-  ofstream f_struct;
-  f_struct.open(f_struct_name.c_str());
-
-  f_struct <<
-    autogen_comment() <<
-    java_package() <<
-    java_type_imports();
-
-  generate_java_struct_definition(f_struct,
-                                  tstruct,
-                                  is_exception);
-  f_struct.close();
-}
-
-/**
- * Java union definition.
- *
- * @param tstruct The struct definition
- */
-void t_java_generator::generate_java_union(t_struct* tstruct) {
-  // Make output file
-  string f_struct_name = package_dir_+"/"+make_valid_java_filename(tstruct->get_name())+".java";
-  ofstream f_struct;
-  f_struct.open(f_struct_name.c_str());
-
-  f_struct <<
-    autogen_comment() <<
-    java_package() <<
-    java_type_imports();
-
-  generate_java_doc(f_struct, tstruct);
-
-  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
-
-  indent(f_struct) <<
-    "public " << (is_final ? "final " : "") << "class " << tstruct->get_name()
-    << " extends org.apache.thrift.TUnion<" << tstruct->get_name() << ", " << tstruct->get_name() << "._Fields> ";
-
-  scope_up(f_struct);
-
-  generate_struct_desc(f_struct, tstruct);
-  generate_field_descs(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_field_name_constants(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_java_meta_data_map(f_struct, tstruct);
-
-  generate_union_constructor(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_union_abstract_methods(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_java_struct_field_by_id(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_union_getters_and_setters(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_union_is_set_methods(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_union_comparisons(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_union_hashcode(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_java_struct_write_object(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_java_struct_read_object(f_struct, tstruct);
-
-  f_struct << endl;
-
-  scope_down(f_struct);
-
-  f_struct.close();
-}
-
-void t_java_generator::generate_union_constructor(ofstream& out, t_struct* tstruct) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  indent(out) << "public " << type_name(tstruct) << "() {" << endl;
-  indent_up();
-  bool default_value = false;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* type = get_true_type((*m_iter)->get_type());
-    if ((*m_iter)->get_value() != NULL) {
-      indent(out) << "super(_Fields." << constant_name((*m_iter)->get_name()) << ", " << render_const_value(out, type, (*m_iter)->get_value()) << ");" << endl;
-      default_value = true;
-      break;
-    }
-  }
-  if (default_value == false) {
-    indent(out) << "super();" << endl;
-  }
-  indent_down();
-  indent(out) << "}" << endl << endl;
-
-  indent(out) << "public " << type_name(tstruct) << "(_Fields setField, Object value) {" << endl;
-  indent(out) << "  super(setField, value);" << endl;
-  indent(out) << "}" << endl << endl;
-
-  indent(out) << "public " << type_name(tstruct) << "(" << type_name(tstruct) << " other) {" << endl;
-  indent(out) << "  super(other);" << endl;
-  indent(out) << "}" << endl;
-
-  indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl;
-  indent(out) << "  return new " << tstruct->get_name() << "(this);" << endl;
-  indent(out) << "}" << endl << endl;
-
-  // generate "constructors" for each field
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* type = (*m_iter)->get_type();
-    indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() << "(" << type_name(type) << " value) {" << endl;
-    indent(out) << "  " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" << endl;
-    indent(out) << "  x.set" << get_cap_name((*m_iter)->get_name()) << "(value);" << endl;
-    indent(out) << "  return x;" << endl;
-    indent(out) << "}" << endl << endl;
-
-    if (type->is_base_type() && ((t_base_type*)type)->is_binary()) {
-      indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() << "(byte[] value) {" << endl;
-      indent(out) << "  " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" << endl;
-      indent(out) << "  x.set" << get_cap_name((*m_iter)->get_name()) << "(ByteBuffer.wrap(value));" << endl;
-      indent(out) << "  return x;" << endl;
-      indent(out) << "}" << endl << endl;
-    }
-  }
-}
-
-void t_java_generator::generate_union_getters_and_setters(ofstream& out, t_struct* tstruct) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  bool first = true;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    if (first) {
-      first = false;
-    } else {
-      out << endl;
-    }
-
-    t_field* field = (*m_iter);
-    t_type* type = field->get_type();
-    std::string cap_name = get_cap_name(field->get_name());
-
-    generate_java_doc(out, field);
-    if (type->is_base_type() && ((t_base_type*)type)->is_binary()) {
-      indent(out) << "public byte[] get" << cap_name << "() {" << endl;
-      indent(out) << "  set" << cap_name << "(org.apache.thrift.TBaseHelper.rightSize(buffer" << get_cap_name("for") << cap_name << "()));" << endl;
-      indent(out) << "  ByteBuffer b = buffer" << get_cap_name("for") << cap_name << "();" << endl;
-      indent(out) << "  return b == null ? null : b.array();" << endl;
-      indent(out) << "}" << endl;
-
-      out << endl;
-
-      indent(out) << "public ByteBuffer buffer" << get_cap_name("for") << get_cap_name(field->get_name()) << "() {" << endl;
-      indent(out) << "  if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {" << endl;
-      indent(out) << "    return (ByteBuffer)getFieldValue();" << endl;
-      indent(out) << "  } else {" << endl;
-      indent(out) << "    throw new RuntimeException(\"Cannot get field '" << field->get_name()
-        << "' because union is currently set to \" + getFieldDesc(getSetField()).name);" << endl;
-      indent(out) << "  }" << endl;
-      indent(out) << "}" << endl;
-    } else {
-      indent(out) << "public " << type_name(field->get_type()) << " get" << get_cap_name(field->get_name()) << "() {" << endl;
-      indent(out) << "  if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {" << endl;
-      indent(out) << "    return (" << type_name(field->get_type(), true) << ")getFieldValue();" << endl;
-      indent(out) << "  } else {" << endl;
-      indent(out) << "    throw new RuntimeException(\"Cannot get field '" << field->get_name() 
-        << "' because union is currently set to \" + getFieldDesc(getSetField()).name);" << endl;
-      indent(out) << "  }" << endl;
-      indent(out) << "}" << endl;
-    }
-
-    out << endl;
-
-    generate_java_doc(out, field);
-    if (type->is_base_type() && ((t_base_type*)type)->is_binary()) {
-      indent(out) << "public void set" << get_cap_name(field->get_name()) << "(byte[] value) {" << endl;
-      indent(out) << "  set" << get_cap_name(field->get_name()) << "(ByteBuffer.wrap(value));" << endl;
-      indent(out) << "}" << endl;
-
-      out << endl;
-    }
-    indent(out) << "public void set" << get_cap_name(field->get_name()) << "(" << type_name(field->get_type()) << " value) {" << endl;
-    if (type_can_be_null(field->get_type())) {
-      indent(out) << "  if (value == null) throw new NullPointerException();" << endl;
-    }
-    indent(out) << "  setField_ = _Fields." << constant_name(field->get_name()) << ";" << endl;
-    indent(out) << "  value_ = value;" << endl;
-    indent(out) << "}" << endl;
-  }
-}
-
-void t_java_generator::generate_union_is_set_methods(ofstream& out, t_struct* tstruct) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  bool first = true;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    if (first) {
-      first = false;
-    } else {
-      out << endl;
-    }
-
-    std::string field_name = (*m_iter)->get_name();
-
-    indent(out) << "public boolean is" << get_cap_name("set") << get_cap_name(field_name) << "() {" << endl;
-    indent_up();
-    indent(out) << "return setField_ == _Fields." << constant_name(field_name) << ";" << endl;
-    indent_down();
-    indent(out) << "}" << endl << endl;
-  }
-}
-
-void t_java_generator::generate_union_abstract_methods(ofstream& out, t_struct* tstruct) {
-  generate_check_type(out, tstruct);
-  out << endl;
-  generate_standard_scheme_read_value(out, tstruct);
-  out << endl;
-  generate_standard_scheme_write_value(out, tstruct);
-  out << endl;
-  generate_tuple_scheme_read_value(out, tstruct);
-  out << endl;
-  generate_tuple_scheme_write_value(out, tstruct);
-  out << endl;
-  generate_get_field_desc(out, tstruct);
-  out << endl;
-  generate_get_struct_desc(out, tstruct);
-  out << endl;
-  indent(out) << "@Override" << endl;
-  indent(out) << "protected _Fields enumForId(short id) {" << endl;
-  indent(out) << "  return _Fields.findByThriftIdOrThrow(id);" << endl;
-  indent(out) << "}" << endl;
-}
-
-void t_java_generator::generate_check_type(ofstream& out, t_struct* tstruct) {
-  indent(out) << "@Override" << endl;
-  indent(out) << "protected void checkType(_Fields setField, Object value) throws ClassCastException {" << endl;
-  indent_up();
-
-  indent(out) << "switch (setField) {" << endl;
-  indent_up();
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = (*m_iter);
-
-    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
-    indent(out) << "  if (value instanceof " << type_name(field->get_type(), true, false, true) << ") {" << endl;
-    indent(out) << "    break;" << endl;
-    indent(out) << "  }" << endl;
-    indent(out) << "  throw new ClassCastException(\"Was expecting value of type " 
-      << type_name(field->get_type(), true, false) << " for field '" << field->get_name() 
-      << "', but got \" + value.getClass().getSimpleName());" << endl;
-    // do the real check here
-  }
-
-  indent(out) << "default:" << endl;
-  indent(out) << "  throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-}
-
-void t_java_generator::generate_standard_scheme_read_value(ofstream& out, t_struct* tstruct) {
-  indent(out) << "@Override" << endl;
-  indent(out) << "protected Object standardSchemeReadValue(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TField field) throws org.apache.thrift.TException {" << endl;
-
-  indent_up();
-
-  indent(out) << "_Fields setField = _Fields.findByThriftId(field.id);" << endl;
-  indent(out) << "if (setField != null) {" << endl;
-  indent_up();
-  indent(out) << "switch (setField) {" << endl;
-  indent_up();
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = (*m_iter);
-
-    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
-    indent_up();
-    indent(out) << "if (field.type == " << constant_name(field->get_name()) << "_FIELD_DESC.type) {" << endl;
-    indent_up();
-    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";" << endl;
-    generate_deserialize_field(out, field, "");
-    indent(out) << "return " << field->get_name() << ";" << endl;
-    indent_down();
-    indent(out) << "} else {" << endl;
-    indent(out) << "  org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);" << endl;
-    indent(out) << "  return null;" << endl;
-    indent(out) << "}" << endl;
-    indent_down();
-  }
-
-  indent(out) << "default:" << endl;
-  indent(out) << "  throw new IllegalStateException(\"setField wasn't null, but didn't match any of the case statements!\");" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-
-  indent_down();
-  indent(out) << "} else {" << endl;
-  indent_up();  
-  indent(out) << "org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);" << endl;
-  indent(out) << "return null;" << endl;
-  indent_down();
-  indent(out) << "}" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-}
-
-void t_java_generator::generate_standard_scheme_write_value(ofstream& out, t_struct* tstruct) {
-  indent(out) << "@Override" << endl;
-  indent(out) << "protected void standardSchemeWriteValue(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {" << endl;
-
-  indent_up();
-
-  indent(out) << "switch (setField_) {" << endl;
-  indent_up();
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = (*m_iter);
-
-    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
-    indent_up();
-    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() 
-      << " = (" <<  type_name(field->get_type(), true, false) << ")value_;" << endl;
-    generate_serialize_field(out, field, "");
-    indent(out) << "return;" << endl;
-    indent_down();
-  }
-
-  indent(out) << "default:" << endl;
-  indent(out) << "  throw new IllegalStateException(\"Cannot write union with unknown field \" + setField_);" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-
-  indent_down();
-
-  indent(out) << "}" << endl;
-}
-
-void t_java_generator::generate_tuple_scheme_read_value(ofstream& out, t_struct* tstruct) {
-  indent(out) << "@Override" << endl;
-  indent(out) << "protected Object tupleSchemeReadValue(org.apache.thrift.protocol.TProtocol iprot, short fieldID) throws org.apache.thrift.TException {" << endl;
-  
-  indent_up();
-  
-  indent(out) << "_Fields setField = _Fields.findByThriftId(fieldID);" << endl;
-  indent(out) << "if (setField != null) {" << endl;
-  indent_up();
-  indent(out) << "switch (setField) {" << endl;
-  indent_up();
-  
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = (*m_iter);
-    
-    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
-    indent_up();
-    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";" << endl;
-    generate_deserialize_field(out, field, "");
-    indent(out) << "return " << field->get_name() << ";" << endl;
-    indent_down();
-  }
-  
-  indent(out) << "default:" << endl;
-  indent(out) << "  throw new IllegalStateException(\"setField wasn't null, but didn't match any of the case statements!\");" << endl;
-  
-  indent_down();
-  indent(out) << "}" << endl;
-  
-  indent_down();
-  indent(out) << "} else {" << endl;
-  indent_up();
-  indent(out) << "throw new TProtocolException(\"Couldn't find a field with field id \" + fieldID);" << endl;
-  indent_down();
-  indent(out) << "}" << endl;
-  indent_down();
-  indent(out) << "}" << endl;
-}
-
-void t_java_generator::generate_tuple_scheme_write_value(ofstream& out, t_struct* tstruct) {
-  indent(out) << "@Override" << endl;
-  indent(out) << "protected void tupleSchemeWriteValue(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {" << endl;
-  
-  indent_up();
-  
-  indent(out) << "switch (setField_) {" << endl;
-  indent_up();
-  
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = (*m_iter);
-    
-    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
-    indent_up();
-    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() 
-    << " = (" <<  type_name(field->get_type(), true, false) << ")value_;" << endl;
-    generate_serialize_field(out, field, "");
-    indent(out) << "return;" << endl;
-    indent_down();
-  }
-  
-  indent(out) << "default:" << endl;
-  indent(out) << "  throw new IllegalStateException(\"Cannot write union with unknown field \" + setField_);" << endl;
-  
-  indent_down();
-  indent(out) << "}" << endl;
-  
-  indent_down();
-  
-  indent(out) << "}" << endl;
-}
-
-void t_java_generator::generate_get_field_desc(ofstream& out, t_struct* tstruct) {
-  indent(out) << "@Override" << endl;
-  indent(out) << "protected org.apache.thrift.protocol.TField getFieldDesc(_Fields setField) {" << endl;
-  indent_up();
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  indent(out) << "switch (setField) {" << endl;
-  indent_up();
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = (*m_iter);
-    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
-    indent(out) << "  return " << constant_name(field->get_name()) << "_FIELD_DESC;" << endl;
-  }
-
-  indent(out) << "default:" << endl;
-  indent(out) << "  throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-}
-
-void t_java_generator::generate_get_struct_desc(ofstream& out, t_struct* tstruct) {
-  (void) tstruct;
-  indent(out) << "@Override" << endl;
-  indent(out) << "protected org.apache.thrift.protocol.TStruct getStructDesc() {" << endl;
-  indent(out) << "  return STRUCT_DESC;" << endl;
-  indent(out) << "}" << endl;
-}
-
-void t_java_generator::generate_union_comparisons(ofstream& out, t_struct* tstruct) {
-  // equality
-  indent(out) << "public boolean equals(Object other) {" << endl;
-  indent(out) << "  if (other instanceof " << tstruct->get_name() << ") {" << endl;
-  indent(out) << "    return equals((" << tstruct->get_name() << ")other);" << endl;
-  indent(out) << "  } else {" << endl;
-  indent(out) << "    return false;" << endl;
-  indent(out) << "  }" << endl;
-  indent(out) << "}" << endl;
-
-  out << endl;
-
-  indent(out) << "public boolean equals(" << tstruct->get_name() << " other) {" << endl;
-  indent(out) << "  return other != null && getSetField() == other.getSetField() && getFieldValue().equals(other.getFieldValue());" << endl;
-  indent(out) << "}" << endl;
-  out << endl;
-
-  indent(out) << "@Override" << endl;
-  indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl;
-  indent(out) << "  int lastComparison = org.apache.thrift.TBaseHelper.compareTo(getSetField(), other.getSetField());" << endl;
-  indent(out) << "  if (lastComparison == 0) {" << endl;
-  indent(out) << "    return org.apache.thrift.TBaseHelper.compareTo(getFieldValue(), other.getFieldValue());" << endl;
-  indent(out) << "  }" << endl;
-  indent(out) << "  return lastComparison;" << endl;
-  indent(out) << "}" << endl;
-  out << endl;
-}
-
-void t_java_generator::generate_union_hashcode(ofstream& out, t_struct* tstruct) {
-  (void) tstruct;
-  if (gen_hash_code_) {
-    indent(out) << "@Override" << endl;
-    indent(out) << "public int hashCode() {" << endl;
-    indent(out) << "  HashCodeBuilder hcb = new HashCodeBuilder();" << endl;
-    indent(out) << "  hcb.append(this.getClass().getName());" << endl;
-    indent(out) << "  org.apache.thrift.TFieldIdEnum setField = getSetField();" << endl;
-    indent(out) << "  if (setField != null) {" << endl;
-    indent(out) << "    hcb.append(setField.getThriftFieldId());" << endl;
-    indent(out) << "    Object value = getFieldValue();" << endl;
-    indent(out) << "    if (value instanceof org.apache.thrift.TEnum) {" << endl;
-    indent(out) << "      hcb.append(((org.apache.thrift.TEnum)getFieldValue()).getValue());" << endl;
-    indent(out) << "    } else {" << endl;
-    indent(out) << "      hcb.append(value);" << endl;
-    indent(out) << "    }" << endl;
-    indent(out) << "  }" << endl;
-    indent(out) << "  return hcb.toHashCode();" << endl;
-    indent(out) << "}";
-  } else {
-    indent(out) << "/**" << endl;
-    indent(out) << " * If you'd like this to perform more respectably, use the hashcode generator option." << endl;
-    indent(out) << " */" << endl;
-    indent(out) << "@Override" << endl;
-    indent(out) << "public int hashCode() {" << endl;
-    indent(out) << "  return 0;" << endl;
-    indent(out) << "}" << endl;
-  }
-}
-
-/**
- * Java struct definition. This has various parameters, as it could be
- * generated standalone or inside another class as a helper. If it
- * is a helper than it is a static class.
- *
- * @param tstruct      The struct definition
- * @param is_exception Is this an exception?
- * @param in_class     If inside a class, needs to be static class
- * @param is_result    If this is a result it needs a different writer
- */
-void t_java_generator::generate_java_struct_definition(ofstream &out,
-                                                       t_struct* tstruct,
-                                                       bool is_exception,
-                                                       bool in_class,
-                                                       bool is_result) {
-  generate_java_doc(out, tstruct);
-
-  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
-
-  indent(out) <<
-    "public " << (is_final ? "final " : "") <<
-    (in_class ? "static " : "") << "class " << tstruct->get_name() << " ";
-
-  if (is_exception) {
-    out << "extends TException ";
-  }
-  out << "implements org.apache.thrift.TBase<" << tstruct->get_name() << ", " << tstruct->get_name() << "._Fields>, java.io.Serializable, Cloneable, Comparable<" << tstruct->get_name() << ">";
-
-  out << " ";
-
-  scope_up(out);
-
-  generate_struct_desc(out, tstruct);
-
-  // Members are public for -java, private for -javabean
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  out << endl;
-
-  generate_field_descs(out, tstruct);
-
-  out << endl;
-
-  generate_scheme_map(out, tstruct);
-
-  out << endl;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    if (bean_style_ || private_members_) {
-      indent(out) << "private ";
-    } else {
-      generate_java_doc(out, *m_iter);
-      indent(out) << "public ";
-    }
-    out << declare_field(*m_iter, false, true) << endl;
-  }
-
-  out << endl;
-
-  generate_field_name_constants(out, tstruct);
-
-  // isset data
-  if (members.size() > 0) {
-    out << endl;
-
-    indent(out) << "// isset id assignments" << endl;
-
-    int i = 0;
-    int optionals = 0;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if ((*m_iter)->get_req() == t_field::T_OPTIONAL) {
-        optionals++;
-      }
-      if (!type_can_be_null((*m_iter)->get_type())) {
-        indent(out) << "private static final int " << isset_field_id(*m_iter)
-          << " = " << i << ";" <<  endl;
-        i++;
-      }
-    }
-
-    std::string primitiveType;
-    switch(needs_isset(tstruct, &primitiveType)) {
-    case ISSET_NONE:
-      break;
-    case ISSET_PRIMITIVE:
-      indent(out) << "private " << primitiveType << " __isset_bitfield = 0;" << endl;
-      break;
-    case ISSET_BITSET:
-      indent(out) << "private BitSet __isset_bit_vector = new BitSet(" << i << ");" << endl;
-      break;
-    }
-
-    if (optionals > 0) {
-      std::string output_string = "private _Fields optionals[] = {";
-      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-        if ((*m_iter)->get_req() == t_field::T_OPTIONAL) {
-          output_string = output_string + "_Fields." + constant_name((*m_iter)->get_name()) + ",";
-        }
-      }
-      indent(out) << output_string.substr(0, output_string.length() - 1) <<  "};" << endl;
-    }
-  }
-
-  generate_java_meta_data_map(out, tstruct);
-
-  bool all_optional_members = true;
-
-  // Default constructor
-  indent(out) <<
-    "public " << tstruct->get_name() << "() {" << endl;
-  indent_up();
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* t = get_true_type((*m_iter)->get_type());
-    if ((*m_iter)->get_value() != NULL) {
-      print_const_value(out, "this." + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true);
-    }
-    if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
-      all_optional_members = false;
-    }
-  }
-  indent_down();
-  indent(out) << "}" << endl << endl;
-
-  if (!members.empty() && !all_optional_members) {
-    // Full constructor for all fields
-    indent(out) <<
-      "public " << tstruct->get_name() << "(" << endl;
-    indent_up();
-    bool first = true;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
-        if (!first) {
-          out << "," << endl;
-        }
-        first = false;
-        indent(out) << type_name((*m_iter)->get_type()) << " " <<
-          (*m_iter)->get_name();
-      }
-    }
-    out << ")" << endl;
-    indent_down();
-    indent(out) << "{" << endl;
-    indent_up();
-    indent(out) << "this();" << endl;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
-        indent(out) << "this." << (*m_iter)->get_name() << " = " <<
-          (*m_iter)->get_name() << ";" << endl;
-        generate_isset_set(out, (*m_iter), "");
-      }
-    }
-
-    indent_down();
-    indent(out) << "}" << endl << endl;
-  }
-
-  // copy constructor
-  indent(out) << "/**" << endl;
-  indent(out) << " * Performs a deep copy on <i>other</i>." << endl;
-  indent(out) << " */" << endl;
-  indent(out) << "public " << tstruct->get_name() << "(" << tstruct->get_name() << " other) {" << endl;
-  indent_up();
-
-  switch(needs_isset(tstruct)) {
-  case ISSET_NONE:
-    break;
-  case ISSET_PRIMITIVE:
-    indent(out) << "__isset_bitfield = other.__isset_bitfield;" << endl;
-    break;
-  case ISSET_BITSET:
-    indent(out) << "__isset_bit_vector.clear();" << endl;
-    indent(out) << "__isset_bit_vector.or(other.__isset_bit_vector);" << endl;    
-    break;
-  }
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = (*m_iter);
-    std::string field_name = field->get_name();
-    t_type* type = field->get_type();
-    bool can_be_null = type_can_be_null(type);
-
-    if (can_be_null) {
-      indent(out) << "if (other." << generate_isset_check(field) << ") {" << endl;
-      indent_up();
-    }
-
-    if (type->is_container()) {
-      generate_deep_copy_container(out, "other", field_name, "__this__" + field_name, type);
-      indent(out) << "this." << field_name << " = __this__" << field_name << ";" << endl;
-    } else {
-      indent(out) << "this." << field_name << " = ";
-      generate_deep_copy_non_container(out, "other." + field_name, field_name, type);
-      out << ";" << endl;
-    }
-
-    if (can_be_null) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-  }
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-
-  // clone method, so that you can deep copy an object when you don't know its class.
-  indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl;
-  indent(out) << "  return new " << tstruct->get_name() << "(this);" << endl;
-  indent(out) << "}" << endl << endl;
-
-  generate_java_struct_clear(out, tstruct);
-
-  generate_java_bean_boilerplate(out, tstruct);
-  generate_generic_field_getters_setters(out, tstruct);
-  generate_generic_isset_method(out, tstruct);
-
-  generate_java_struct_equality(out, tstruct);
-  generate_java_struct_compare_to(out, tstruct);
-  generate_java_struct_field_by_id(out, tstruct);
-
-  generate_java_struct_reader(out, tstruct);
-  if (is_result) {
-    generate_java_struct_result_writer(out, tstruct);
-  } else {
-    generate_java_struct_writer(out, tstruct);
-  }
-  generate_java_struct_tostring(out, tstruct);
-  generate_java_validator(out, tstruct);
-
-  generate_java_struct_write_object(out, tstruct);
-  generate_java_struct_read_object(out, tstruct);
-
-  generate_java_struct_standard_scheme(out, tstruct, is_result);
-  generate_java_struct_tuple_scheme(out, tstruct);
-
-  scope_down(out);
-  out << endl;
-}
-
-/**
- * Generates equals methods and a hashCode method for a structure.
- *
- * @param tstruct The struct definition
- */
-void t_java_generator::generate_java_struct_equality(ofstream& out,
-                                                     t_struct* tstruct) {
-  out << indent() << "@Override" << endl <<
-    indent() << "public boolean equals(Object that) {" << endl;
-  indent_up();
-  out <<
-    indent() << "if (that == null)" << endl <<
-    indent() << "  return false;" << endl <<
-    indent() << "if (that instanceof " << tstruct->get_name() << ")" << endl <<
-    indent() << "  return this.equals((" << tstruct->get_name() << ")that);" << endl <<
-    indent() << "return false;" << endl;
-  scope_down(out);
-  out << endl;
-
-  out <<
-    indent() << "public boolean equals(" << tstruct->get_name() << " that) {" << endl;
-  indent_up();
-  out <<
-    indent() << "if (that == null)" << endl <<
-    indent() << "  return false;" << endl;
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    out << endl;
-
-    t_type* t = get_true_type((*m_iter)->get_type());
-    // Most existing Thrift code does not use isset or optional/required,
-    // so we treat "default" fields as required.
-    bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
-    bool can_be_null = type_can_be_null(t);
-    string name = (*m_iter)->get_name();
-
-    string this_present = "true";
-    string that_present = "true";
-    string unequal;
-
-    if (is_optional || can_be_null) {
-      this_present += " && this." + generate_isset_check(*m_iter);
-      that_present += " && that." + generate_isset_check(*m_iter);
-    }
-
-    out <<
-      indent() << "boolean this_present_" << name << " = "
-      << this_present << ";" << endl <<
-      indent() << "boolean that_present_" << name << " = "
-      << that_present << ";" << endl <<
-      indent() << "if (" << "this_present_" << name
-      << " || that_present_" << name << ") {" << endl;
-    indent_up();
-    out <<
-      indent() << "if (!(" << "this_present_" << name
-      << " && that_present_" << name << "))" << endl <<
-      indent() << "  return false;" << endl;
-
-    if (t->is_base_type() && ((t_base_type*)t)->is_binary()) {
-      unequal = "!this." + name + ".equals(that." + name + ")";
-    } else if (can_be_null) {
-      unequal = "!this." + name + ".equals(that." + name + ")";
-    } else {
-      unequal = "this." + name + " != that." + name;
-    }
-
-    out <<
-      indent() << "if (" << unequal << ")" << endl <<
-      indent() << "  return false;" << endl;
-
-    scope_down(out);
-  }
-  out << endl;
-  indent(out) << "return true;" << endl;
-  scope_down(out);
-  out << endl;
-
-  out << indent() << "@Override" << endl <<
-    indent() << "public int hashCode() {" << endl;
-  indent_up();
-  if (gen_hash_code_) {
-    indent(out) << "HashCodeBuilder builder = new HashCodeBuilder();" << endl;
-
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      out << endl;
-
-      t_type* t = get_true_type((*m_iter)->get_type());
-      bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
-      bool can_be_null = type_can_be_null(t);
-      string name = (*m_iter)->get_name();
-
-      string present = "true";
-
-      if (is_optional || can_be_null) {
-        present += " && (" + generate_isset_check(*m_iter) + ")";
-      }
-
-      indent(out) << "boolean present_" << name << " = " << present << ";" << endl;
-      indent(out) << "builder.append(present_" << name << ");" << endl;
-      indent(out) << "if (present_" << name << ")" << endl;
-      if (t->is_enum()) {
-        indent(out) << "  builder.append(" << name << ".getValue());" << endl;
-      } else {
-        indent(out) << "  builder.append(" << name << ");" << endl;
-      }
-    }
-
-    out << endl;
-    indent(out) << "return builder.toHashCode();" << endl;
-  } else {
-    indent(out) << "return 0;" << endl;
-  }
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-void t_java_generator::generate_java_struct_compare_to(ofstream& out, t_struct* tstruct) {
-  indent(out) << "@Override" << endl;
-  indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl;
-  indent_up();
-
-  indent(out) << "if (!getClass().equals(other.getClass())) {" << endl;
-  indent(out) << "  return getClass().getName().compareTo(other.getClass().getName());" << endl;
-  indent(out) << "}" << endl;
-  out << endl;
-
-  indent(out) << "int lastComparison = 0;" << endl;
-  out << endl;
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = *m_iter;
-    indent(out) << "lastComparison = Boolean.valueOf(" << generate_isset_check(field) << ").compareTo(other." << generate_isset_check(field) << ");" << endl;
-    indent(out) << "if (lastComparison != 0) {" << endl;
-    indent(out) << "  return lastComparison;" << endl;
-    indent(out) << "}" << endl;
-
-    indent(out) << "if (" << generate_isset_check(field) << ") {" << endl;
-    indent(out) << "  lastComparison = org.apache.thrift.TBaseHelper.compareTo(this." << field->get_name() << ", other." << field->get_name() << ");" << endl;
-    indent(out) << "  if (lastComparison != 0) {" << endl;
-    indent(out) << "    return lastComparison;" << endl;
-    indent(out) << "  }" << endl;
-    indent(out) << "}" << endl;
-  }
-
-  indent(out) << "return 0;" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-/**
- * Generates a function to read all the fields of the struct.
- *
- * @param tstruct The struct definition
- */
-void t_java_generator::generate_java_struct_reader(ofstream& out,
-                                                   t_struct* tstruct) {
-  (void) tstruct;
-  indent(out) << "public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {" << endl;
-  indent_up();
-  indent(out) << "schemes.get(iprot.getScheme()).getScheme().read(iprot, this);" << endl; 
-  indent_down();
-  indent(out) << "}" << endl <<
-  endl;	
-}
-
-// generates java method to perform various checks
-// (e.g. check that all required fields are set)
-void t_java_generator::generate_java_validator(ofstream& out,
-                                               t_struct* tstruct){
-  indent(out) << "public void validate() throws org.apache.thrift.TException {" << endl;
-  indent_up();
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  out << indent() << "// check for required fields" << endl;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
-      if (bean_style_) {
-        out <<
-          indent() << "if (!" << generate_isset_check(*f_iter) << ") {" << endl <<
-          indent() << "  throw new org.apache.thrift.protocol.TProtocolException(\"Required field '" << (*f_iter)->get_name() << "' is unset! Struct:\" + toString());" << endl <<
-          indent() << "}" << endl << endl;
-      } else{
-        if (type_can_be_null((*f_iter)->get_type())) {
-          indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl;
-          indent(out) << "  throw new org.apache.thrift.protocol.TProtocolException(\"Required field '" << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" << endl;
-          indent(out) << "}" << endl;
-        } else {
-          indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name() << "' because it's a primitive and you chose the non-beans generator." << endl;
-        }
-      }
-    }
-  }
-
-  out << indent() << "// check for sub-struct validity" << endl;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_type* type = (*f_iter)->get_type();
-    if (type->is_struct() && ! ((t_struct*)type)->is_union()) {
-      out << indent() << "if (" << (*f_iter)->get_name() << " != null) {" << endl;
-      out << indent() << "  " << (*f_iter)->get_name() << ".validate();" << endl;
-      out << indent() << "}" << endl;
-    }
-  }
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-/**
- * Generates a function to write all the fields of the struct
- *
- * @param tstruct The struct definition
- */
-void t_java_generator::generate_java_struct_writer(ofstream& out,
-                                                   t_struct* tstruct) {
-  (void) tstruct;
-  indent(out) << "public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {" << endl;
-  indent_up();
-  indent(out) << "schemes.get(oprot.getScheme()).getScheme().write(oprot, this);" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl << endl;	
-}
-
-/**
- * Generates a function to write all the fields of the struct,
- * which is a function result. These fields are only written
- * if they are set in the Isset array, and only one of them
- * can be set at a time.
- *
- * @param tstruct The struct definition
- */
-void t_java_generator::generate_java_struct_result_writer(ofstream& out,
-                                                          t_struct* tstruct) {
-  (void) tstruct;
-  indent(out) << "public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {" << endl;
-  indent_up();
-  indent(out) << "schemes.get(oprot.getScheme()).getScheme().write(oprot, this);" << endl;
-  
-  indent_down();
-  indent(out) << "  }" << endl << endl;	
-}
-
-void t_java_generator::generate_java_struct_field_by_id(ofstream& out, t_struct* tstruct) {
-  (void) tstruct;
-  indent(out) << "public _Fields fieldForId(int fieldId) {" << endl;
-  indent(out) << "  return _Fields.findByThriftId(fieldId);" << endl;
-  indent(out) << "}" << endl << endl;
-}
-
-void t_java_generator::generate_reflection_getters(ostringstream& out, t_type* type, string field_name, string cap_name) {
-  indent(out) << "case " << constant_name(field_name) << ":" << endl;
-  indent_up();
-
-  if (type->is_base_type() && !type->is_string()) {
-    t_base_type* base_type = (t_base_type*)type;
-
-    indent(out) << "return " << type_name(type, true, false) << ".valueOf(" << (base_type->is_bool() ? "is" : "get") << cap_name << "());" << endl << endl;
-  } else {
-    indent(out) << "return get" << cap_name << "();" << endl << endl;
-  }
-
-  indent_down();
-}
-
-void t_java_generator::generate_reflection_setters(ostringstream& out, t_type* type, string field_name, string cap_name) {
-  indent(out) << "case " << constant_name(field_name) << ":" << endl;
-  indent_up();
-  indent(out) << "if (value == null) {" << endl;
-  indent(out) << "  unset" << get_cap_name(field_name) << "();" << endl;
-  indent(out) << "} else {" << endl;
-  indent(out) << "  set" << cap_name << "((" << type_name(type, true, false) << ")value);" << endl;
-  indent(out) << "}" << endl;
-  indent(out) << "break;" << endl << endl;
-
-  indent_down();
-}
-
-void t_java_generator::generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct) {
-  std::ostringstream getter_stream;
-  std::ostringstream setter_stream;
-
-  // build up the bodies of both the getter and setter at once
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = *f_iter;
-    t_type* type = get_true_type(field->get_type());
-    std::string field_name = field->get_name();
-    std::string cap_name = get_cap_name(field_name);
-
-    indent_up();
-    generate_reflection_setters(setter_stream, type, field_name, cap_name);
-    generate_reflection_getters(getter_stream, type, field_name, cap_name);
-    indent_down();
-  }
-
-
-  // create the setter
-
-  indent(out) << "public void setFieldValue(_Fields field, Object value) {" << endl;
-  indent(out) << "  switch (field) {" << endl;
-  out << setter_stream.str();
-  indent(out) << "  }" << endl;
-  indent(out) << "}" << endl << endl;
-
-  // create the getter
-  indent(out) << "public Object getFieldValue(_Fields field) {" << endl;
-  indent_up();
-  indent(out) << "switch (field) {" << endl;
-  out << getter_stream.str();
-  indent(out) << "}" << endl;
-  indent(out) << "throw new IllegalStateException();" << endl;
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-// Creates a generic isSet method that takes the field number as argument
-void t_java_generator::generate_generic_isset_method(std::ofstream& out, t_struct* tstruct){
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  // create the isSet method
-  indent(out) << "/** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */" << endl;
-  indent(out) << "public boolean isSet(_Fields field) {" << endl;
-  indent_up();
-  indent(out) << "if (field == null) {" << endl;
-  indent(out) << "  throw new IllegalArgumentException();" << endl;
-  indent(out) << "}" << endl << endl;
-
-  indent(out) << "switch (field) {" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = *f_iter;
-    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
-    indent_up();
-    indent(out) << "return " << generate_isset_check(field) << ";" << endl;
-    indent_down();
-  }
-
-  indent(out) << "}" << endl;
-  indent(out) << "throw new IllegalStateException();" << endl;
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-/**
- * Generates a set of Java Bean boilerplate functions (setters, getters, etc.)
- * for the given struct.
- *
- * @param tstruct The struct definition
- */
-void t_java_generator::generate_java_bean_boilerplate(ofstream& out,
-                                                      t_struct* tstruct) {
-  isset_type issetType = needs_isset(tstruct);
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = *f_iter;
-    t_type* type = get_true_type(field->get_type());
-    std::string field_name = field->get_name();
-    std::string cap_name = get_cap_name(field_name);
-
-    if (type->is_container()) {
-      // Method to return the size of the collection
-      indent(out) << "public int get" << cap_name;
-      out << get_cap_name("size() {") << endl;
-
-      indent_up();
-      indent(out) << "return (this." << field_name << " == null) ? 0 : " <<
-        "this." << field_name << ".size();" << endl;
-      indent_down();
-      indent(out) << "}" << endl << endl;
-    }
-
-    if (type->is_set() || type->is_list()) {
-      t_type* element_type;
-      if (type->is_set()) {
-        element_type = ((t_set*)type)->get_elem_type();
-      } else {
-        element_type = ((t_list*)type)->get_elem_type();
-      }
-
-      // Iterator getter for sets and lists
-      indent(out) << "public java.util.Iterator<" <<
-        type_name(element_type, true, false) <<  "> get" << cap_name;
-      out << get_cap_name("iterator() {") << endl;
-
-      indent_up();
-      indent(out) << "return (this." << field_name << " == null) ? null : " <<
-        "this." << field_name << ".iterator();" << endl;
-      indent_down();
-      indent(out) << "}" << endl << endl;
-
-      // Add to set or list, create if the set/list is null
-      indent(out);
-      out << "public void add" << get_cap_name("to");
-      out << cap_name << "(" << type_name(element_type) << " elem) {" << endl;
-
-      indent_up();
-      indent(out) << "if (this." << field_name << " == null) {" << endl;
-      indent_up();
-      indent(out) << "this." << field_name << " = new " << type_name(type, false, true) <<
-        "();" << endl;
-      indent_down();
-      indent(out) << "}" << endl;
-      indent(out) << "this." << field_name << ".add(elem);" << endl;
-      indent_down();
-      indent(out) << "}" << endl << endl;
-    } else if (type->is_map()) {
-      // Put to map
-      t_type* key_type = ((t_map*)type)->get_key_type();
-      t_type* val_type = ((t_map*)type)->get_val_type();
-
-      indent(out);
-      out << "public void put" << get_cap_name("to");
-      out << cap_name << "(" << type_name(key_type) << " key, "
-        << type_name(val_type) << " val) {" << endl;
-
-      indent_up();
-      indent(out) << "if (this." << field_name << " == null) {" << endl;
-      indent_up();
-      indent(out) << "this." << field_name << " = new " <<
-        type_name(type, false, true) << "();" << endl;
-      indent_down();
-      indent(out) << "}" << endl;
-      indent(out) << "this." << field_name << ".put(key, val);" << endl;
-      indent_down();
-      indent(out) << "}" << endl << endl;
-    }
-
-    // Simple getter
-    generate_java_doc(out, field);
-    if (type->is_base_type() && ((t_base_type*)type)->is_binary()) {
-      indent(out) << "public byte[] get" << cap_name << "() {" << endl;
-      indent(out) << "  set" << cap_name << "(org.apache.thrift.TBaseHelper.rightSize(" << field_name << "));" << endl;
-      indent(out) << "  return " << field_name << " == null ? null : " << field_name << ".array();" << endl;
-      indent(out) << "}" << endl << endl;
-
-      indent(out) << "public ByteBuffer buffer" << get_cap_name("for") << cap_name << "() {" << endl;
-      indent(out) << "  return " << field_name << ";" << endl;
-      indent(out) << "}" << endl << endl;
-    } else {
-      indent(out) << "public " << type_name(type);
-      if (type->is_base_type() &&
-          ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) {
-        out << " is";
-      } else {
-        out << " get";
-      }
-      out << cap_name << "() {" << endl;
-      indent_up();
-      indent(out) << "return this." << field_name << ";" << endl;
-      indent_down();
-      indent(out) << "}" << endl << endl;
-    }
-
-    // Simple setter
-    generate_java_doc(out, field);
-    if (type->is_base_type() && ((t_base_type*)type)->is_binary()) {
-      indent(out) << "public ";
-      if (bean_style_) {
-        out << "void";
-      } else {
-        out << type_name(tstruct);
-      }
-      out << " set" << cap_name << "(byte[] " << field_name << ") {" << endl;
-      indent(out) << "  set" << cap_name << "(" << field_name << " == null ? (ByteBuffer)null : ByteBuffer.wrap(" << field_name << "));" << endl;
-      if (!bean_style_) {
-        indent(out) << "  return this;" << endl;
-      }
-      indent(out) << "}" << endl << endl;
-    }
-    indent(out) << "public ";
-    if (bean_style_) {
-      out << "void";
-    } else {
-      out << type_name(tstruct);
-    }
-    out << " set" << cap_name << "(" << type_name(type) << " " << field_name << ") {" << endl;
-    indent_up();
-    indent(out) << "this." << field_name << " = " << field_name << ";" << endl;
-    generate_isset_set(out, field, "");
-    if (!bean_style_) {
-      indent(out) << "return this;" << endl;
-    }
-
-    indent_down();
-    indent(out) << "}" << endl << endl;
-
-    // Unsetter
-    indent(out) << "public void unset" << cap_name << "() {" << endl;
-    indent_up();
-    if (type_can_be_null(type)) {
-      indent(out) << "this." << field_name << " = null;" << endl;
-    } else if(issetType == ISSET_PRIMITIVE) {
-      indent(out) << "__isset_bitfield = EncodingUtils.clearBit(__isset_bitfield, " << isset_field_id(field) << ");" << endl;
-    } else {
-      indent(out) << "__isset_bit_vector.clear(" << isset_field_id(field) << ");" << endl;
-    }
-    indent_down();
-    indent(out) << "}" << endl << endl;
-
-    // isSet method
-    indent(out) << "/** Returns true if field " << field_name << " is set (has been assigned a value) and false otherwise */" << endl;
-    indent(out) << "public boolean is" << get_cap_name("set") << cap_name << "() {" << endl;
-    indent_up();
-    if (type_can_be_null(type)) {
-      indent(out) << "return this." << field_name << " != null;" << endl;
-    } else if(issetType == ISSET_PRIMITIVE) {
-      indent(out) << "return EncodingUtils.testBit(__isset_bitfield, " << isset_field_id(field) << ");" << endl;
-    } else {
-      indent(out) << "return __isset_bit_vector.get(" << isset_field_id(field) << ");" << endl;
-    }
-    indent_down();
-    indent(out) << "}" << endl << endl;
-
-    indent(out) << "public void set" << cap_name << get_cap_name("isSet") << "(boolean value) {" << endl;
-    indent_up();
-    if (type_can_be_null(type)) {
-      indent(out) << "if (!value) {" << endl;
-      indent(out) << "  this." << field_name << " = null;" << endl;
-      indent(out) << "}" << endl;
-    } else if(issetType == ISSET_PRIMITIVE) {
-      indent(out) << "__isset_bitfield = EncodingUtils.setBit(__isset_bitfield, " << isset_field_id(field) << ", value);" << endl;
-    } else {
-      indent(out) << "__isset_bit_vector.set(" << isset_field_id(field) << ", value);" << endl;
-    }
-    indent_down();
-    indent(out) << "}" << endl << endl; 
-  }
-}
-
-/**
- * Generates a toString() method for the given struct
- *
- * @param tstruct The struct definition
- */
-void t_java_generator::generate_java_struct_tostring(ofstream& out,
-                                                     t_struct* tstruct) {
-  out << indent() << "@Override" << endl <<
-    indent() << "public String toString() {" << endl;
-  indent_up();
-
-  out <<
-    indent() << "StringBuilder sb = new StringBuilder(\"" << tstruct->get_name() << "(\");" << endl;
-  out << indent() << "boolean first = true;" << endl << endl;
-
-  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) {
-    bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
-    if(could_be_unset) {
-      indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl;
-      indent_up();
-    }
-
-    t_field* field = (*f_iter);
-
-    if (!first) {
-      indent(out) << "if (!first) sb.append(\", \");" << endl;
-    }
-    indent(out) << "sb.append(\"" << (*f_iter)->get_name() << ":\");" << endl;
-    bool can_be_null = type_can_be_null(field->get_type());
-    if (can_be_null) {
-      indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl;
-      indent(out) << "  sb.append(\"null\");" << endl;
-      indent(out) << "} else {" << endl;
-      indent_up();
-    }
-
-    if (field->get_type()->is_base_type() && ((t_base_type*)(field->get_type()))->is_binary()) {
-      indent(out) << "org.apache.thrift.TBaseHelper.toString(this." << field->get_name() << ", sb);" << endl;
-    } else {
-      indent(out) << "sb.append(this." << (*f_iter)->get_name() << ");" << endl;
-    }
-
-    if (can_be_null) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    indent(out) << "first = false;" << endl;
-
-    if(could_be_unset) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    first = false;
-  }
-  out <<
-    indent() << "sb.append(\")\");" << endl <<
-    indent() << "return sb.toString();" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-/**
- * Generates a static map with meta data to store information such as fieldID to
- * fieldName mapping
- *
- * @param tstruct The struct definition
- */
-void t_java_generator::generate_java_meta_data_map(ofstream& out,
-                                                   t_struct* tstruct) {
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  // Static Map with fieldID -> org.apache.thrift.meta_data.FieldMetaData mappings
-  indent(out) << "public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;" << endl;
-  indent(out) << "static {" << endl;
-  indent_up();
-
-  indent(out) << "Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);" << endl;
-
-  // Populate map
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = *f_iter;
-    std::string field_name = field->get_name();
-    indent(out) << "tmpMap.put(_Fields." << constant_name(field_name) << ", new org.apache.thrift.meta_data.FieldMetaData(\"" << field_name << "\", ";
-
-    // Set field requirement type (required, optional, etc.)
-    if (field->get_req() == t_field::T_REQUIRED) {
-      out << "org.apache.thrift.TFieldRequirementType.REQUIRED, ";
-    } else if (field->get_req() == t_field::T_OPTIONAL) {
-      out << "org.apache.thrift.TFieldRequirementType.OPTIONAL, ";
-    } else {
-      out << "org.apache.thrift.TFieldRequirementType.DEFAULT, ";
-    }
-
-    // Create value meta data
-    generate_field_value_meta_data(out, field->get_type());
-    out  << "));" << endl;
-  }
-
-  indent(out) << "metaDataMap = Collections.unmodifiableMap(tmpMap);" << endl;
-
-  indent(out) << "org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(" << type_name(tstruct) << ".class, metaDataMap);" << endl;
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-/** 
- * Returns a string with the java representation of the given thrift type
- * (e.g. for the type struct it returns "org.apache.thrift.protocol.TType.STRUCT")
- */
-std::string t_java_generator::get_java_type_string(t_type* type) {
-  if (type->is_list()){
-    return "org.apache.thrift.protocol.TType.LIST";
-  } else if (type->is_map()) {
-    return "org.apache.thrift.protocol.TType.MAP";
-  } else if (type->is_set()) {
-    return "org.apache.thrift.protocol.TType.SET";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "org.apache.thrift.protocol.TType.STRUCT";
-  } else if (type->is_enum()) {
-    return "org.apache.thrift.protocol.TType.ENUM";
-  } else if (type->is_typedef()) {
-    return get_java_type_string(((t_typedef*)type)->get_type());
-  } else if (type->is_base_type()) {
-    switch (((t_base_type*)type)->get_base()) {
-      case t_base_type::TYPE_VOID   : return      "org.apache.thrift.protocol.TType.VOID"; break;
-      case t_base_type::TYPE_STRING : return    "org.apache.thrift.protocol.TType.STRING"; break;
-      case t_base_type::TYPE_BOOL   : return      "org.apache.thrift.protocol.TType.BOOL"; break;
-      case t_base_type::TYPE_BYTE   : return      "org.apache.thrift.protocol.TType.BYTE"; break;
-      case t_base_type::TYPE_I16    : return       "org.apache.thrift.protocol.TType.I16"; break;
-      case t_base_type::TYPE_I32    : return       "org.apache.thrift.protocol.TType.I32"; break;
-      case t_base_type::TYPE_I64    : return       "org.apache.thrift.protocol.TType.I64"; break;
-      case t_base_type::TYPE_DOUBLE : return    "org.apache.thrift.protocol.TType.DOUBLE"; break;
-      default : throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_java_generator::get_java_type_string!"); break; // This should never happen!
-    }
-  } else {
-    throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_java_generator::get_java_type_string!"); // This should never happen!
-  }
-}
-
-void t_java_generator::generate_field_value_meta_data(std::ofstream& out, t_type* type){
-  out << endl;
-  indent_up();
-  indent_up();
-  if (type->is_struct()){
-    indent(out) << "new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, " << type_name(type) << ".class";
-  } else if (type->is_container()){
-    if (type->is_list()){
-      indent(out) << "new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, ";
-      t_type* elem_type = ((t_list*)type)->get_elem_type();    
-      generate_field_value_meta_data(out, elem_type);   
-    } else if (type->is_set()){
-      indent(out) << "new org.apache.thrift.meta_data.SetMetaData(org.apache.thrift.protocol.TType.SET, ";
-      t_type* elem_type = ((t_list*)type)->get_elem_type();    
-      generate_field_value_meta_data(out, elem_type); 
-    } else{ // map
-      indent(out) << "new org.apache.thrift.meta_data.MapMetaData(org.apache.thrift.protocol.TType.MAP, ";
-      t_type* key_type = ((t_map*)type)->get_key_type();
-      t_type* val_type = ((t_map*)type)->get_val_type();
-      generate_field_value_meta_data(out, key_type);
-      out << ", ";
-      generate_field_value_meta_data(out, val_type);
-    }
-  } else if (type->is_enum()) {
-    indent(out) << "new org.apache.thrift.meta_data.EnumMetaData(org.apache.thrift.protocol.TType.ENUM, " << type_name(type) << ".class";
-  } else {
-    indent(out) << "new org.apache.thrift.meta_data.FieldValueMetaData(" << get_java_type_string(type);
-    if (type->is_typedef()) {
-      indent(out) << ", \"" << ((t_typedef*)type)->get_symbolic() << "\"";
-    } else if (((t_base_type*)type)->is_binary()) {
-      indent(out) << ", true";
-    }
-  }
-  out << ")";
-  indent_down();
-  indent_down();
-}
-
-
-/**
- * Generates a thrift service. In C++, this comprises an entirely separate
- * header and source file. The header file defines the methods and includes
- * the data types defined in the main header file, and the implementation
- * file contains implementations of the basic printer and default interfaces.
- *
- * @param tservice The service definition
- */
-void t_java_generator::generate_service(t_service* tservice) {
-  // Make output file
-  string f_service_name = package_dir_+"/"+make_valid_java_filename(service_name_)+".java";
-  f_service_.open(f_service_name.c_str());
-
-  f_service_ <<
-    autogen_comment() <<
-    java_package() <<
-    java_type_imports();
-
-  f_service_ << "public class " << service_name_ << " {" << endl << endl;
-  indent_up();
-
-  // Generate the three main parts of the service
-  generate_service_interface(tservice);
-  generate_service_async_interface(tservice);
-  generate_service_client(tservice);
-  generate_service_async_client(tservice);
-  generate_service_server(tservice);
-  generate_service_async_server(tservice);
-  generate_service_helpers(tservice);
-
-  indent_down();
-  f_service_ <<
-    "}" << endl;
-  f_service_.close();
-}
-
-/**
- * Generates a service interface definition.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_java_generator::generate_service_interface(t_service* tservice) {
-  string extends = "";
-  string extends_iface = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_iface = " extends " + extends + ".Iface";
-  }
-
-  generate_java_doc(f_service_, tservice);
-  f_service_ << indent() << "public interface Iface" << extends_iface <<
-    " {" << endl << endl;
-  indent_up();
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_java_doc(f_service_, *f_iter);
-    indent(f_service_) << "public " << function_signature(*f_iter) << ";" << endl << endl;
-  }
-  indent_down();
-  f_service_ << indent() << "}" << endl << endl;
-}
-
-void t_java_generator::generate_service_async_interface(t_service* tservice) {
-  string extends = "";
-  string extends_iface = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_iface = " extends " + extends + " .AsyncIface";
-  }
-
-  f_service_ << indent() << "public interface AsyncIface" << extends_iface << " {" << endl << endl;
-  indent_up();
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    indent(f_service_) << "public " << function_signature_async(*f_iter, true) << " throws org.apache.thrift.TException;" << endl << endl;
-  }
-  indent_down();
-  f_service_ << indent() << "}" << endl << endl;
-}
-
-
-/**
- * Generates structs for all the service args and return types
- *
- * @param tservice The service
- */
-void t_java_generator::generate_service_helpers(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    t_struct* ts = (*f_iter)->get_arglist();
-    generate_java_struct_definition(f_service_, ts, false, true);
-    generate_function_helpers(*f_iter);
-  }
-}
-
-/**
- * Generates a service client definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_java_generator::generate_service_client(t_service* tservice) {
-  string extends = "";
-  string extends_client = "";
-  if (tservice->get_extends() == NULL) {
-    extends_client = "org.apache.thrift.TServiceClient";
-  } else {
-    extends = type_name(tservice->get_extends());
-    extends_client = extends + ".Client";
-  }
-
-  indent(f_service_) <<
-    "public static class Client extends " << extends_client << " implements Iface {" << endl;
-  indent_up();
-
-  indent(f_service_) << "public static class Factory implements org.apache.thrift.TServiceClientFactory<Client> {" << endl;
-  indent_up();
-  indent(f_service_) << "public Factory() {}" << endl;
-  indent(f_service_) << "public Client getClient(org.apache.thrift.protocol.TProtocol prot) {" << endl;
-  indent_up();
-  indent(f_service_) << "return new Client(prot);" << endl;
-  indent_down();
-  indent(f_service_) << "}" << endl;
-  indent(f_service_) << "public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {" << endl;
-  indent_up();
-  indent(f_service_) << "return new Client(iprot, oprot);" << endl;
-  indent_down();
-  indent(f_service_) << "}" << endl;
-  indent_down();
-  indent(f_service_) << "}" << endl << endl;
-
-  indent(f_service_) << "public Client(org.apache.thrift.protocol.TProtocol prot)" << endl;
-  scope_up(f_service_);
-  indent(f_service_) << "super(prot, prot);" << endl;
-  scope_down(f_service_);
-  f_service_ << endl;
-
-  indent(f_service_) <<
-    "public Client(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {" << endl;
-  indent(f_service_) << "  super(iprot, oprot);" << endl;
-  indent(f_service_) << "}" << 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) {
-    string funname = (*f_iter)->get_name();
-
-    // Open function
-    indent(f_service_) << "public " << function_signature(*f_iter) << endl;
-    scope_up(f_service_);
-    indent(f_service_) << "send_" << funname << "(";
-
-    // Get the struct of function call params
-    t_struct* arg_struct = (*f_iter)->get_arglist();
-
-    // Declare the function arguments
-    const vector<t_field*>& fields = arg_struct->get_members();
-    vector<t_field*>::const_iterator fld_iter;
-    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;
-
-    if (!(*f_iter)->is_oneway()) {
-      f_service_ << indent();
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_ << "return ";
-      }
-      f_service_ <<
-        "recv_" << funname << "();" << endl;
-    }
-    scope_down(f_service_);
-    f_service_ << endl;
-
-    t_function send_function(g_type_void,
-                             string("send_") + (*f_iter)->get_name(),
-                             (*f_iter)->get_arglist());
-
-    string argsname = (*f_iter)->get_name() + "_args";
-
-    // Open function
-    indent(f_service_) <<
-      "public " << function_signature(&send_function) << endl;
-    scope_up(f_service_);
-
-    // Serialize the request
-    indent(f_service_) << argsname << " args = new " << argsname << "();" << endl;
-
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      indent(f_service_) << "args.set" << get_cap_name((*fld_iter)->get_name()) << "(" << (*fld_iter)->get_name() << ");" << endl;
-    }
-
-    indent(f_service_) << "sendBase(\"" << funname << "\", args);" << endl;
-
-    scope_down(f_service_);
-    f_service_ << endl;
-
-    if (!(*f_iter)->is_oneway()) {
-      string resultname = (*f_iter)->get_name() + "_result";
-
-      t_struct noargs(program_);
-      t_function recv_function((*f_iter)->get_returntype(),
-                               string("recv_") + (*f_iter)->get_name(),
-                               &noargs,
-                               (*f_iter)->get_xceptions());
-      // Open function
-      indent(f_service_) <<
-        "public " << function_signature(&recv_function) << endl;
-      scope_up(f_service_);
-
-      f_service_ <<
-        indent() << resultname << " result = new " << resultname << "();" << endl <<
-        indent() << "receiveBase(result, \"" << funname << "\");" << endl;
-
-      // Careful, only return _result if not a void function
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_ <<
-          indent() << "if (result." << generate_isset_check("success") << ") {" << endl <<
-          indent() << "  return result.success;" << endl <<
-          indent() << "}" << 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." << (*x_iter)->get_name() << " != null) {" << endl <<
-          indent() << "  throw result." << (*x_iter)->get_name() << ";" << endl <<
-          indent() << "}" << endl;
-      }
-
-      // If you get here it's an exception, unless a void function
-      if ((*f_iter)->get_returntype()->is_void()) {
-        indent(f_service_) << "return;" << endl;
-      } else {
-        f_service_ <<
-          indent() << "throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
-      }
-
-      // Close function
-      scope_down(f_service_);
-      f_service_ << endl;
-    }
-  }
-
-  indent_down();
-  indent(f_service_) << "}" << endl;
-}
-
-void t_java_generator::generate_service_async_client(t_service* tservice) {
-  string extends = "org.apache.thrift.async.TAsyncClient";
-  string extends_client = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends()) + ".AsyncClient";
-  }
-
-  indent(f_service_) <<
-    "public static class AsyncClient extends " << extends << " implements AsyncIface {" << endl;
-  indent_up();
-
-  // Factory method
-  indent(f_service_) << "public static class Factory implements org.apache.thrift.async.TAsyncClientFactory<AsyncClient> {" << endl;
-  indent(f_service_) << "  private org.apache.thrift.async.TAsyncClientManager clientManager;" << endl;
-  indent(f_service_) << "  private org.apache.thrift.protocol.TProtocolFactory protocolFactory;" << endl;
-  indent(f_service_) << "  public Factory(org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.protocol.TProtocolFactory protocolFactory) {" << endl;
-  indent(f_service_) << "    this.clientManager = clientManager;" << endl; 
-  indent(f_service_) << "    this.protocolFactory = protocolFactory;" << endl;
-  indent(f_service_) << "  }" << endl;
-  indent(f_service_) << "  public AsyncClient getAsyncClient(org.apache.thrift.transport.TNonblockingTransport transport) {" << endl;
-  indent(f_service_) << "    return new AsyncClient(protocolFactory, clientManager, transport);" << endl;
-  indent(f_service_) << "  }" << endl;
-  indent(f_service_) << "}" << endl << endl;
-
-  indent(f_service_) << "public AsyncClient(org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.transport.TNonblockingTransport transport) {" << endl;
-  indent(f_service_) << "  super(protocolFactory, clientManager, transport);" << endl;
-  indent(f_service_) << "}" << 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) {
-    string funname = (*f_iter)->get_name();
-    t_type* ret_type = (*f_iter)->get_returntype();
-    t_struct* arg_struct = (*f_iter)->get_arglist();
-    string funclassname = funname + "_call";
-    const vector<t_field*>& fields = arg_struct->get_members();
-    const std::vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
-    vector<t_field*>::const_iterator fld_iter;
-    string args_name = (*f_iter)->get_name() + "_args";
-    string result_name = (*f_iter)->get_name() + "_result";
-
-    // Main method body   
-    indent(f_service_) << "public " << function_signature_async(*f_iter, false) << " throws org.apache.thrift.TException {" << endl;
-    indent(f_service_) << "  checkReady();" << endl;
-    indent(f_service_) << "  " << funclassname << " method_call = new " + funclassname + "(" << async_argument_list(*f_iter, arg_struct, ret_type) << ", this, ___protocolFactory, ___transport);" << endl;
-    indent(f_service_) << "  this.___currentMethod = method_call;" << endl;
-    indent(f_service_) << "  ___manager.call(method_call);" << endl;
-    indent(f_service_) << "}" << endl;
-
-    f_service_ << endl;
-
-    // TAsyncMethod object for this function call
-    indent(f_service_) << "public static class " + funclassname + " extends org.apache.thrift.async.TAsyncMethodCall {" << endl;
-    indent_up();
-
-    // Member variables
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      indent(f_service_) << "private " + type_name((*fld_iter)->get_type()) + " " + (*fld_iter)->get_name() + ";" << endl;
-    }
-
-    // NOTE since we use a new Client instance to deserialize, let's keep seqid to 0 for now
-    // indent(f_service_) << "private int seqid;" << endl << endl;
-
-    // Constructor
-    indent(f_service_) << "public " + funclassname + "(" + async_argument_list(*f_iter, arg_struct, ret_type, true) << ", org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {" << endl;
-    indent(f_service_) << "  super(client, protocolFactory, transport, resultHandler, " << ((*f_iter)->is_oneway() ? "true" : "false") << ");" << endl;
-
-    // Assign member variables
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      indent(f_service_) << "  this." + (*fld_iter)->get_name() + " = " + (*fld_iter)->get_name() + ";" << endl;
-    }
-
-    indent(f_service_) << "}" << endl << endl;
-
-    indent(f_service_) << "public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {" << endl;
-    indent_up();
-
-    // Serialize request
-    // NOTE we are leaving seqid as 0, for now (see above)
-    f_service_ << 
-      indent() << "prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage(\"" << funname << "\", org.apache.thrift.protocol.TMessageType.CALL, 0));" << endl <<
-      indent() << args_name << " args = new " << args_name << "();" << endl;
-
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      f_service_ << indent() << "args.set" << get_cap_name((*fld_iter)->get_name()) << "(" << (*fld_iter)->get_name() << ");" << endl;
-    }
-
-    f_service_ << 
-      indent() << "args.write(prot);" << endl <<
-      indent() << "prot.writeMessageEnd();" << endl;
-
-    indent_down();
-    indent(f_service_) << "}" << endl << endl;
-
-    // Return method  
-    indent(f_service_) << "public " + type_name(ret_type) + " getResult() throws ";
-    vector<t_field*>::const_iterator x_iter;
-    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      f_service_ << type_name((*x_iter)->get_type(), false, false) + ", ";
-    }
-    f_service_ << "org.apache.thrift.TException {" << endl;
-
-    indent_up();
-    f_service_ <<
-      indent() << "if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {" << endl <<
-      indent() << "  throw new IllegalStateException(\"Method call not finished!\");" << endl <<
-      indent() << "}" << endl <<
-      indent() << "org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());" << endl <<
-      indent() << "org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);" << endl;
-    if (!(*f_iter)->is_oneway()) {
-      indent(f_service_);
-      if (!ret_type->is_void()) {
-        f_service_ << "return "; 
-      }
-      f_service_ << "(new Client(prot)).recv_" + funname + "();" << endl;
-    }
-
-    // Close function
-    indent_down();
-    indent(f_service_) << "}" << endl;
-
-    // Close class
-    indent_down();
-    indent(f_service_) << "}" << endl << endl;
-  }
-
-  // Close AsyncClient
-  scope_down(f_service_);
-  f_service_ << endl;
-}
-
-/**
- * Generates a service server definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_java_generator::generate_service_server(t_service* tservice) {
-  // Generate the dispatch methods
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  // Extends stuff
-  string extends = "";
-  string extends_processor = "";
-  if (tservice->get_extends() == NULL) {
-    extends_processor = "org.apache.thrift.TBaseProcessor<I>";
-  } else {
-    extends = type_name(tservice->get_extends());
-    extends_processor = extends + ".Processor<I>";
-  }
-
-  // Generate the header portion
-  indent(f_service_) <<
-    "public static class Processor<I extends Iface> extends " << extends_processor << " implements org.apache.thrift.TProcessor {" << endl;
-  indent_up();
-
-  indent(f_service_) << "private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class.getName());" << endl;
-
-  indent(f_service_) << "public Processor(I iface) {" << endl;
-  indent(f_service_) << "  super(iface, getProcessMap(new HashMap<String, org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>>()));" << endl;
-  indent(f_service_) << "}" << endl << endl;
-
-  indent(f_service_) << "protected Processor(I iface, Map<String,  org.apache.thrift.ProcessFunction<I, ? extends  org.apache.thrift.TBase>> processMap) {" << endl;
-  indent(f_service_) << "  super(iface, getProcessMap(processMap));" << endl;
-  indent(f_service_) << "}" << endl << endl;
-
-  indent(f_service_) << "private static <I extends Iface> Map<String,  org.apache.thrift.ProcessFunction<I, ? extends  org.apache.thrift.TBase>> getProcessMap(Map<String,  org.apache.thrift.ProcessFunction<I, ? extends  org.apache.thrift.TBase>> processMap) {" << endl;
-  indent_up();
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    indent(f_service_) << "processMap.put(\"" << (*f_iter)->get_name() << "\", new " << (*f_iter)->get_name() << "());" << endl;
-  }
-  indent(f_service_) << "return processMap;" << endl;
-  indent_down();
-  indent(f_service_) << "}" << endl << endl;
-
-  // Generate the process subfunctions
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_process_function(tservice, *f_iter);
-  }
-
-  indent_down();
-  indent(f_service_) << "}" << endl << endl;
-}
-
-/**
- * Generates a service server definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_java_generator::generate_service_async_server(t_service* tservice) {
-  // Generate the dispatch methods
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  // Extends stuff
-  string extends = "";
-  string extends_processor = "";
-  if (tservice->get_extends() == NULL) {
-    extends_processor = "org.apache.thrift.TBaseAsyncProcessor<I>";
-  } else {
-    extends = type_name(tservice->get_extends());
-    extends_processor = extends + ".AsyncProcessor<I>";
-  }
-
-  // Generate the header portion
-  indent(f_service_) <<
-    "public static class AsyncProcessor<I extends AsyncIface> extends " << extends_processor << " {" << endl;
-  indent_up();
-
-  indent(f_service_) << "private static final Logger LOGGER = LoggerFactory.getLogger(AsyncProcessor.class.getName());" << endl;
-
-  indent(f_service_) << "public AsyncProcessor(I iface) {" << endl;
-  indent(f_service_) << "  super(iface, getProcessMap(new HashMap<String, org.apache.thrift.AsyncProcessFunction<I, ? extends org.apache.thrift.TBase, ?>>()));" << endl;
-  indent(f_service_) << "}" << endl << endl;
-
-  indent(f_service_) << "protected AsyncProcessor(I iface, Map<String,  org.apache.thrift.AsyncProcessFunction<I, ? extends  org.apache.thrift.TBase, ?>> processMap) {" << endl;
-  indent(f_service_) << "  super(iface, getProcessMap(processMap));" << endl;
-  indent(f_service_) << "}" << endl << endl;
-
-
-  indent(f_service_) << "private static <I extends AsyncIface> Map<String,  org.apache.thrift.AsyncProcessFunction<I, ? extends  org.apache.thrift.TBase,?>> getProcessMap(Map<String,  org.apache.thrift.AsyncProcessFunction<I, ? extends  org.apache.thrift.TBase, ?>> processMap) {" << endl;
-  indent_up();
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    indent(f_service_) << "processMap.put(\"" << (*f_iter)->get_name() << "\", new " << (*f_iter)->get_name() << "());" << endl;
-  }
-  indent(f_service_) << "return processMap;" << endl;
-  indent_down();
-  indent(f_service_) << "}" << endl << endl;
-
-  // Generate the process subfunctions
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_process_async_function(tservice, *f_iter);
-  }
-
-  indent_down();
-  indent(f_service_) << "}" << endl << endl;
-}
-
-
-/**
- * Generates a struct and helpers for a function.
- *
- * @param tfunction The function
- */
-void t_java_generator::generate_function_helpers(t_function* tfunction) {
-  if (tfunction->is_oneway()) {
-    return;
-  }
-
-  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_java_struct_definition(f_service_, &result, false, true, true);
-}
-
-
-
-/**
- * Generates a process function definition.
- *
- * @param tfunction The function to write a dispatcher for
- */
-void t_java_generator::generate_process_async_function(t_service* tservice,
-                                                 t_function* tfunction) {
-  string argsname = tfunction->get_name() + "_args";
-
-  string resultname = tfunction->get_name() + "_result";
-    if (tfunction->is_oneway()) {
-      resultname = "org.apache.thrift.TBase";
-    }
-
-  string resulttype = type_name(tfunction->get_returntype(),true);
-
-
-  (void) tservice;
-  // Open class
-  indent(f_service_) <<
-    "public static class " << tfunction->get_name() << "<I extends AsyncIface> extends org.apache.thrift.AsyncProcessFunction<I, " << argsname << ", "<<resulttype<<"> {" << endl;
-  indent_up();
-
-  indent(f_service_) << "public " << tfunction->get_name() << "() {" << endl;
-  indent(f_service_) << "  super(\"" << tfunction->get_name() << "\");" << endl;
-  indent(f_service_) << "}" << endl << endl;
-
-  indent(f_service_) << "public " << argsname << " getEmptyArgsInstance() {" << endl;
-  indent(f_service_) << "  return new " << argsname << "();" << endl;
-  indent(f_service_) << "}" << endl << endl;
-
-  indent(f_service_) << "public AsyncMethodCallback<"<<resulttype<<"> getResultHandler(final AsyncFrameBuffer fb, final int seqid) {" << endl;
-  indent_up();
-  indent(f_service_) << "final org.apache.thrift.AsyncProcessFunction fcall = this;"<<endl;
-  indent(f_service_) << "return new AsyncMethodCallback<"<<resulttype<<">() { " << endl;
-  indent_up();
-  indent(f_service_) <<	"public void onComplete(" << resulttype <<" o) {" << endl;
-
-  indent_up();
-  if (!tfunction->is_oneway()) {
-    indent(f_service_) <<resultname<<" result = new "<<resultname<<"();"<<endl;
-
-    if (!tfunction->get_returntype()->is_void()) {
-  	  indent(f_service_) << "result.success = o;"<<endl;
-      // Set isset on success field
-  	  if (!type_can_be_null(tfunction->get_returntype())) {
-  	    indent(f_service_) << "result.set" << get_cap_name("success") << get_cap_name("isSet") << "(true);" << endl;
-  	  }
-    }
-
-    indent(f_service_) << "try {"<<endl;
-    indent(f_service_) << "  fcall.sendResponse(fb,result, org.apache.thrift.protocol.TMessageType.REPLY,seqid);"<<endl;
-    indent(f_service_) << "  return;"<<endl;
-    indent(f_service_) << "} catch (Exception e) {"<<endl;
-    indent(f_service_) << "  LOGGER.error(\"Exception writing to internal frame buffer\", e);"<<endl;
-    indent(f_service_) << "}"<<endl;
-    indent(f_service_) << "fb.close();"<<endl;
-  }
-  indent_down();
-  indent(f_service_) << "}" <<endl;
-
-  indent(f_service_) << "public void onError(Exception e) {"<<endl;
-  indent_up();
-
-
-
-  if (!tfunction->is_oneway()) {
-	 indent(f_service_) <<"byte msgType = org.apache.thrift.protocol.TMessageType.REPLY;"<<endl;
-	 indent(f_service_) <<"org.apache.thrift.TBase msg;"<<endl;
-     indent(f_service_) <<resultname<<" result = new "<<resultname<<"();"<<endl;
-
-     t_struct* xs = tfunction->get_xceptions();
-     const std::vector<t_field*>& xceptions = xs->get_members();
-     vector<t_field*>::const_iterator x_iter;
-     bool first = true;
-     if (xceptions.size() > 0) {
-    	 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-    		 first ? first = false : indent(f_service_) << "else ";
-    		 indent(f_service_) << "if (e instanceof " << type_name((*x_iter)->get_type(), false, false)<<") {" << endl;
-    		 indent(f_service_) << indent() << "result." << (*x_iter)->get_name() << " = (" << type_name((*x_iter)->get_type(), false, false) << ") e;" << endl;
-    	  	 indent(f_service_) << indent() << "result.set" << get_cap_name((*x_iter)->get_name()) << get_cap_name("isSet") << "(true);" << endl;
-    		 indent(f_service_) << indent() << "msg = result;"<<endl;
-
-    	  	 indent(f_service_) << "}"<<endl;
-    	 }
-    	 indent(f_service_) << " else "<<endl;
-     }
-
-     indent(f_service_) << "{"<<endl;
-     indent_up();
-     indent(f_service_) << "msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;"<<endl;
-     indent(f_service_) << "msg = (org.apache.thrift.TBase)new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.INTERNAL_ERROR, e.getMessage());"<<endl;
-     indent_down();
-     indent(f_service_) << "}"<<endl;
-
-
-     indent(f_service_) << "try {"<<endl;
-     indent(f_service_) << "  fcall.sendResponse(fb,msg,msgType,seqid);"<<endl;
-     indent(f_service_) << "  return;"<<endl;
-     indent(f_service_) << "} catch (Exception ex) {"<<endl;
-     indent(f_service_) << "  LOGGER.error(\"Exception writing to internal frame buffer\", ex);"<<endl;
-     indent(f_service_) << "}"<<endl;
-     indent(f_service_) << "fb.close();"<<endl;
-  }
-  indent_down();
-  indent(f_service_) << "}" <<endl;
-  indent_down();
-  indent(f_service_) << "};" <<endl;
-  indent_down();
-  indent(f_service_) << "}" << endl << endl;
-
-  indent(f_service_) << "protected boolean isOneway() {" << endl;
-  indent(f_service_) << "  return " << ((tfunction->is_oneway())?"true":"false") << ";" << endl;
-  indent(f_service_) << "}" << endl << endl;
-
-  indent(f_service_) << "public void start(I iface, " << argsname << " args, org.apache.thrift.async.AsyncMethodCallback<"<<resulttype<<"> resultHandler) throws TException {" << endl;
-  indent_up();
-
-  // 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_ << indent();
-
-  f_service_ << "iface." << 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." << (*f_iter)->get_name();
-  }
-  if (!first)
-	  f_service_ << ",";
-  f_service_ << "resultHandler";
-  f_service_ << ");" << endl;
-
-
-  indent_down();
-  indent(f_service_) << "}";
-
-  // Close function
-  f_service_ << endl;
-
-  // Close class
-  indent_down();
-  f_service_ << indent() << "}" << endl << endl;
-}
-
-/**
- * Generates a process function definition.
- *
- * @param tfunction The function to write a dispatcher for
- */
-void t_java_generator::generate_process_function(t_service* tservice,
-                                                 t_function* tfunction) {
-  string argsname = tfunction->get_name() + "_args";
-  string resultname = tfunction->get_name() + "_result";
-  if (tfunction->is_oneway()) {
-    resultname = "org.apache.thrift.TBase";
-  }
-
-  (void) tservice;
-  // Open class
-  indent(f_service_) <<
-    "public static class " << tfunction->get_name() << "<I extends Iface> extends org.apache.thrift.ProcessFunction<I, " << argsname << "> {" << endl;
-  indent_up();
-
-  indent(f_service_) << "public " << tfunction->get_name() << "() {" << endl;
-  indent(f_service_) << "  super(\"" << tfunction->get_name() << "\");" << endl;
-  indent(f_service_) << "}" << endl << endl;
-
-  indent(f_service_) << "public " << argsname << " getEmptyArgsInstance() {" << endl;
-  indent(f_service_) << "  return new " << argsname << "();" << endl;
-  indent(f_service_) << "}" << endl << endl;
-
-  indent(f_service_) << "protected boolean isOneway() {" << endl;
-  indent(f_service_) << "  return " << ((tfunction->is_oneway())?"true":"false") << ";" << endl;
-  indent(f_service_) << "}" << endl << endl;
-
-  indent(f_service_) << "public " << resultname << " getResult(I iface, " << argsname << " args) throws org.apache.thrift.TException {" << endl;
-  indent_up();
-  if (!tfunction->is_oneway()) {
-    indent(f_service_) << resultname << " result = new " << resultname << "();" << endl;
-  }
-
-  t_struct* xs = tfunction->get_xceptions();
-  const std::vector<t_field*>& xceptions = xs->get_members();
-  vector<t_field*>::const_iterator x_iter;
-
-  // Try block for a function with exceptions
-  if (xceptions.size() > 0) {
-    f_service_ << indent() << "try {" << endl;
-    indent_up();
-  }
-
-  // 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_ << indent();
-
-  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
-    f_service_ << "result.success = ";
-  }
-  f_service_ << "iface." << 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." << (*f_iter)->get_name();
-  }
-  f_service_ << ");" << endl;
-
-  // Set isset on success field
-  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void() && !type_can_be_null(tfunction->get_returntype())) {
-    indent(f_service_) << "result.set" << get_cap_name("success") << get_cap_name("isSet") << "(true);" << endl;
-  }
-
-  if (!tfunction->is_oneway() && xceptions.size() > 0) {
-    indent_down();
-    f_service_ << indent() << "}";
-    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " " << (*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();
-        f_service_ << indent() << "}";
-      } else {
-        f_service_ << "}";
-      }
-    }
-    f_service_ << endl;
-  }
-
-  if (tfunction->is_oneway()) {
-    indent(f_service_) << "return null;" << endl;
-  } else {
-    indent(f_service_) << "return result;" << endl;
-  }
-  indent_down();
-  indent(f_service_) << "}";
-
-  // Close function
-  f_service_ << endl;
-
-  // Close class
-  indent_down();
-  f_service_ << indent() << "}" << endl << endl;
-}
-
-
-/**
- * Deserializes a field of any type.
- *
- * @param tfield The field
- * @param prefix The variable name or container for this field
- */
-void t_java_generator::generate_deserialize_field(ofstream& out,
-                                                  t_field* tfield,
-                                                  string prefix, bool has_metadata) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  if (type->is_void()) {
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
-  }
-
-  string name = prefix + tfield->get_name();
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct(out,
-                                (t_struct*)type,
-                                name);
-  } else if (type->is_container()) {
-    generate_deserialize_container(out, type, name, has_metadata);
-  } else if (type->is_base_type()) {
-    indent(out) << name << " = iprot.";
-
-
-    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:
-        if (((t_base_type*)type)->is_binary()) {
-          out << "readBinary();";
-        } else {
-          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 Java name for base type " + t_base_type::t_base_name(tbase);
-    }
-    out << endl;
-  } else if (type->is_enum()) {
-    indent(out) << name << " = " << type_name(tfield->get_type(), true, false) + ".findByValue(iprot.readI32());" << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
-           tfield->get_name().c_str(), type_name(type).c_str());
-  }
-}
-
-/**
- * Generates an unserializer for a struct, invokes read()
- */
-void t_java_generator::generate_deserialize_struct(ofstream& out,
-                                                   t_struct* tstruct,
-                                                   string prefix) {
-  out <<
-    indent() << prefix << " = new " << type_name(tstruct) << "();" << endl <<
-    indent() << prefix << ".read(iprot);" << endl;
-}
-
-/**
- * Deserializes a container by reading its size and then iterating
- */
-void t_java_generator::generate_deserialize_container(ofstream& out,
-                                                      t_type* ttype,
-                                                      string prefix, bool has_metadata) {
-
-  scope_up(out);
-
-  string obj;
-
-  if (ttype->is_map()) {
-    obj = tmp("_map");
-  } else if (ttype->is_set()) {
-    obj = tmp("_set");
-  } else if (ttype->is_list()) {
-    obj = tmp("_list");
-  }
-
-  if (has_metadata) {
-    // Declare variables, read header
-    if (ttype->is_map()) {
-      indent(out) << "org.apache.thrift.protocol.TMap " << obj << " = iprot.readMapBegin();" << endl;
-    } else if (ttype->is_set()) {
-      indent(out) << "org.apache.thrift.protocol.TSet " << obj << " = iprot.readSetBegin();" << endl;
-    } else if (ttype->is_list()) {
-      indent(out) << "org.apache.thrift.protocol.TList " << obj << " = iprot.readListBegin();" << endl;
-    }
-  } else {
-    // Declare variables, read header
-    if (ttype->is_map()) {
-      indent(out) << "org.apache.thrift.protocol.TMap " << obj << " = new org.apache.thrift.protocol.TMap(" << 
-      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << "iprot.readI32());" << endl;
-    } else if (ttype->is_set()) {
-      indent(out) << "org.apache.thrift.protocol.TSet " << obj << " = new org.apache.thrift.protocol.TSet(" << 
-      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", iprot.readI32());" << endl;
-    } else if (ttype->is_list()) {
-      indent(out) << "org.apache.thrift.protocol.TList " << obj << " = new org.apache.thrift.protocol.TList(" << 
-      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", iprot.readI32());" << endl;
-    }
-  }
-
-  indent(out) << prefix << " = new " << type_name(ttype, false, true);
-  // size the collection correctly
-  if (sorted_containers_ && (ttype->is_map() || ttype->is_set())) {
-    // TreeSet and TreeMap don't have any constructor which takes a capactity as an argument
-    out << "();" << endl;
-  } else {
-    out << "("
-      << (ttype->is_list() ? "" : "2*" )
-      << obj << ".size"
-      << ");" << endl;
-  }
-
-  // For loop iterates over elements
-  string i = tmp("_i");
-  indent(out) <<
-    "for (int " << i << " = 0; " <<
-    i << " < " << obj << ".size" << "; " <<
-    "++" << i << ")" << endl;
-
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    generate_deserialize_map_element(out, (t_map*)ttype, prefix, has_metadata);
-  } else if (ttype->is_set()) {
-    generate_deserialize_set_element(out, (t_set*)ttype, prefix, has_metadata);
-  } else if (ttype->is_list()) {
-    generate_deserialize_list_element(out, (t_list*)ttype, prefix, has_metadata);
-  }
-
-  scope_down(out);
-
-  if (has_metadata) {
-    // Read container end
-    if (ttype->is_map()) {
-      indent(out) << "iprot.readMapEnd();" << endl;
-    } else if (ttype->is_set()) {
-      indent(out) << "iprot.readSetEnd();" << endl;
-    } else if (ttype->is_list()) {
-      indent(out) << "iprot.readListEnd();" << endl;
-    }
-  }
-  scope_down(out);
-}
-
-
-/**
- * Generates code to deserialize a map
- */
-void t_java_generator::generate_deserialize_map_element(ofstream& out,
-                                                        t_map* tmap,
-                                                        string prefix, bool has_metadata) {
-  string key = tmp("_key");
-  string val = tmp("_val");
-  t_field fkey(tmap->get_key_type(), key);
-  t_field fval(tmap->get_val_type(), val);
-
-  indent(out) << declare_field(&fkey) << endl;
-  indent(out) << declare_field(&fval) << endl;
-
-  generate_deserialize_field(out, &fkey, "", has_metadata);
-  generate_deserialize_field(out, &fval, "", has_metadata);
-
-  indent(out) << prefix << ".put(" << key << ", " << val << ");" << endl;
-}
-
-/**
- * Deserializes a set element
- */
-void t_java_generator::generate_deserialize_set_element(ofstream& out,
-                                                        t_set* tset,
-                                                        string prefix, bool has_metadata) {
-  string elem = tmp("_elem");
-  t_field felem(tset->get_elem_type(), elem);
-
-  indent(out) << declare_field(&felem) << endl;
-
-  generate_deserialize_field(out, &felem, "", has_metadata);
-
-  indent(out) << prefix << ".add(" << elem << ");" << endl;
-}
-
-/**
- * Deserializes a list element
- */
-void t_java_generator::generate_deserialize_list_element(ofstream& out,
-                                                         t_list* tlist,
-                                                         string prefix, bool has_metadata) {
-  string elem = tmp("_elem");
-  t_field felem(tlist->get_elem_type(), elem);
-
-  indent(out) << declare_field(&felem) << endl;
-
-  generate_deserialize_field(out, &felem, "", has_metadata);
-
-  indent(out) << prefix << ".add(" << elem << ");" << endl;
-}
-
-/**
- * Serializes a field of any type.
- *
- * @param tfield The field to serialize
- * @param prefix Name to prepend to field name
- */
-void t_java_generator::generate_serialize_field(ofstream& out,
-                                                t_field* tfield,
-                                                string prefix, bool has_metadata) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  // Do nothing for void types
-  if (type->is_void()) {
-    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
-  }
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_serialize_struct(out,
-                              (t_struct*)type,
-                              prefix + tfield->get_name());
-  } else if (type->is_container()) {
-    generate_serialize_container(out,
-                                 type,
-                                 prefix + tfield->get_name(), has_metadata);
-  } else if (type->is_enum()){
-    indent(out) << "oprot.writeI32(" << prefix + tfield->get_name() << ".getValue());" << endl;
-  } else if (type->is_base_type()) {
-    string name = prefix + tfield->get_name();
-    indent(out) << "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:
-          if (((t_base_type*)type)->is_binary()) {
-            out << "writeBinary(" << name << ");";
-          } else {
-            out << "writeString(" << name << ");";
-          }
-          break;
-        case t_base_type::TYPE_BOOL:
-          out << "writeBool(" << name << ");";
-          break;
-        case t_base_type::TYPE_BYTE:
-          out << "writeByte(" << name << ");";
-          break;
-        case t_base_type::TYPE_I16:
-          out << "writeI16(" << name << ");";
-          break;
-        case t_base_type::TYPE_I32:
-          out << "writeI32(" << name << ");";
-          break;
-        case t_base_type::TYPE_I64:
-          out << "writeI64(" << name << ");";
-          break;
-        case t_base_type::TYPE_DOUBLE:
-          out << "writeDouble(" << name << ");";
-          break;
-        default:
-          throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      out << "writeI32(struct." << name << ");";
-    }
-    out << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
-           prefix.c_str(),
-           tfield->get_name().c_str(),
-           type_name(type).c_str());
-  }
-}
-
-/**
- * Serializes all the members of a struct.
- *
- * @param tstruct The struct to serialize
- * @param prefix  String prefix to attach to all fields
- */
-void t_java_generator::generate_serialize_struct(ofstream& out,
-                                                 t_struct* tstruct,
-                                                 string prefix) {
-  (void) tstruct;
-  out << indent() << prefix << ".write(oprot);" << endl;
-}
-
-/**
- * Serializes a container by writing its size then the elements.
- *
- * @param ttype  The type of container
- * @param prefix String prefix for fields
- */
-void t_java_generator::generate_serialize_container(ofstream& out,
-                                                    t_type* ttype,
-                                                    string prefix, bool has_metadata) {
-  scope_up(out);
-
-  if (has_metadata) {
-    if (ttype->is_map()) {
-      indent(out) <<
-        "oprot.writeMapBegin(new org.apache.thrift.protocol.TMap(" <<
-        type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
-        type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
-        prefix << ".size()));" << endl;
-    } else if (ttype->is_set()) {
-      indent(out) <<
-        "oprot.writeSetBegin(new org.apache.thrift.protocol.TSet(" <<
-        type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
-        prefix << ".size()));" << endl;
-    } else if (ttype->is_list()) {
-      indent(out) <<
-        "oprot.writeListBegin(new org.apache.thrift.protocol.TList(" <<
-        type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
-        prefix << ".size()));" << endl;
-    }
-  } else {
-    indent(out) << "oprot.writeI32(" << prefix << ".size());" << endl;
-  }
-
-  string iter = tmp("_iter");
-  if (ttype->is_map()) {
-    indent(out) <<
-      "for (Map.Entry<" <<
-      type_name(((t_map*)ttype)->get_key_type(), true, false) << ", " <<
-      type_name(((t_map*)ttype)->get_val_type(), true, false) << "> " << iter <<
-      " : " <<
-      prefix << ".entrySet())";
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "for (" <<
-      type_name(((t_set*)ttype)->get_elem_type()) << " " << iter <<
-      " : " <<
-      prefix << ")";
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "for (" <<
-      type_name(((t_list*)ttype)->get_elem_type()) << " " << iter <<
-      " : " <<
-      prefix << ")";
-  }
-
-  out << endl;
-  scope_up(out);
-  if (ttype->is_map()) {
-    generate_serialize_map_element(out, (t_map*)ttype, iter, prefix, has_metadata);
-  } else if (ttype->is_set()) {
-    generate_serialize_set_element(out, (t_set*)ttype, iter, has_metadata);
-  } else if (ttype->is_list()) {
-    generate_serialize_list_element(out, (t_list*)ttype, iter, has_metadata);
-  }
-  scope_down(out);
-
-  if (has_metadata) {
-    if (ttype->is_map()) {
-      indent(out) << "oprot.writeMapEnd();" << endl;
-    } else if (ttype->is_set()) {
-      indent(out) << "oprot.writeSetEnd();" << endl;
-    } else if (ttype->is_list()) {
-      indent(out) << "oprot.writeListEnd();" << endl;
-    }
-  }
-
-  scope_down(out);
-}
-
-/**
- * Serializes the members of a map.
- */
-void t_java_generator::generate_serialize_map_element(ofstream& out,
-                                                      t_map* tmap,
-                                                      string iter,
-                                                      string map, bool has_metadata) {
-  (void) map;
-  t_field kfield(tmap->get_key_type(), iter + ".getKey()");
-  generate_serialize_field(out, &kfield, "", has_metadata);
-  t_field vfield(tmap->get_val_type(), iter + ".getValue()");
-  generate_serialize_field(out, &vfield, "", has_metadata);
-}
-
-/**
- * Serializes the members of a set.
- */
-void t_java_generator::generate_serialize_set_element(ofstream& out,
-                                                      t_set* tset,
-                                                      string iter,
-                                                      bool has_metadata) {
-  t_field efield(tset->get_elem_type(), iter);
-  generate_serialize_field(out, &efield, "", has_metadata);
-}
-
-/**
- * Serializes the members of a list.
- */
-void t_java_generator::generate_serialize_list_element(ofstream& out,
-                                                       t_list* tlist,
-                                                       string iter,
-                                                       bool has_metadata) {
-  t_field efield(tlist->get_elem_type(), iter);
-  generate_serialize_field(out, &efield, "", has_metadata);
-}
-
-/**
- * Returns a Java type name
- *
- * @param ttype The type
- * @param container Is the type going inside a container?
- * @return Java type name, i.e. HashMap<Key,Value>
- */
-string t_java_generator::type_name(t_type* ttype, bool in_container, bool in_init, bool skip_generic) {
-  // In Java typedefs are just resolved to their real type
-  ttype = get_true_type(ttype);
-  string prefix;
-
-  if (ttype->is_base_type()) {
-    return base_type_name((t_base_type*)ttype, in_container);
-  } else if (ttype->is_map()) {
-    t_map* tmap = (t_map*) ttype;
-    if (in_init) {
-      if (sorted_containers_) {
-        prefix = "TreeMap";
-      } else {
-        prefix = "HashMap";
-      }
-    } else {
-      prefix = "Map";
-    }
-    return prefix + (skip_generic ? "" : "<" +
-                     type_name(tmap->get_key_type(), true) + "," +
-                     type_name(tmap->get_val_type(), true) + ">");
-  } else if (ttype->is_set()) {
-    t_set* tset = (t_set*) ttype;
-    if (in_init) {
-      if (sorted_containers_) {
-        prefix = "TreeSet";
-      } else { 
-        prefix = "HashSet";
-      }
-    } else {
-      prefix = "Set";
-    }
-    return prefix + (skip_generic ? "" : "<" + type_name(tset->get_elem_type(), true) + ">");
-  } else if (ttype->is_list()) {
-    t_list* tlist = (t_list*) ttype;
-    if (in_init) {
-      prefix = "ArrayList";
-    } else {
-      prefix = "List";
-    }
-    return prefix + (skip_generic ? "" : "<" + type_name(tlist->get_elem_type(), true) + ">");
-  }
-
-  // Check for namespacing
-  t_program* program = ttype->get_program();
-  if (program != NULL && program != program_) {
-    string package = program->get_namespace("java");
-    if (!package.empty()) {
-      return package + "." + ttype->get_name();
-    }
-  }
-
-  return ttype->get_name();
-}
-
-/**
- * Returns the Java type that corresponds to the thrift type.
- *
- * @param tbase The base type
- * @param container Is it going in a Java container?
- */
-string t_java_generator::base_type_name(t_base_type* type,
-                                        bool in_container) {
-  t_base_type::t_base tbase = type->get_base();
-
-  switch (tbase) {
-    case t_base_type::TYPE_VOID:
-      return (in_container ? "Void" : "void");
-    case t_base_type::TYPE_STRING:
-      if (type->is_binary()) {
-        return "ByteBuffer";
-      } else {
-        return "String";
-      }
-    case t_base_type::TYPE_BOOL:
-      return (in_container ? "Boolean" : "boolean");
-    case t_base_type::TYPE_BYTE:
-      return (in_container ? "Byte" : "byte");
-    case t_base_type::TYPE_I16:
-      return (in_container ? "Short" : "short");
-    case t_base_type::TYPE_I32:
-      return (in_container ? "Integer" : "int");
-    case t_base_type::TYPE_I64:
-      return (in_container ? "Long" : "long");
-    case t_base_type::TYPE_DOUBLE:
-      return (in_container ? "Double" : "double");
-    default:
-      throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
-  }
-}
-
-/**
- * Declares a field, which may include initialization as necessary.
- *
- * @param tfield The field
- * @param init Whether to initialize the field
- */
-string t_java_generator::declare_field(t_field* tfield, bool init, bool comment) {
-  // TODO(mcslee): do we ever need to initialize the field?
-  string result = type_name(tfield->get_type()) + " " + tfield->get_name();
-  if (init) {
-    t_type* ttype = get_true_type(tfield->get_type());
-    if (ttype->is_base_type() && tfield->get_value() != NULL) {
-      ofstream dummy;
-      result += " = " + render_const_value(dummy, ttype, tfield->get_value());
-    } else if (ttype->is_base_type()) {
-      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
-      switch (tbase) {
-        case t_base_type::TYPE_VOID:
-          throw "NO T_VOID CONSTRUCT";
-        case t_base_type::TYPE_STRING:
-          result += " = null";
-          break;
-        case t_base_type::TYPE_BOOL:
-          result += " = 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:
-          result += " = 0";
-          break;
-        case t_base_type::TYPE_DOUBLE:
-          result += " = (double)0";
-          break;
-      }
-    } else if (ttype->is_enum()) {
-      result += " = 0";
-    } else if (ttype->is_container()) {
-      result += " = new " + type_name(ttype, false, true) + "()";
-    } else {
-      result += " = new " + type_name(ttype, false, true) + "()";;
-    }
-  }
-  result += ";";
-  if (comment) {
-    result += " // ";
-    if (tfield->get_req() == t_field::T_OPTIONAL) {
-      result += "optional";
-    } else {
-      result += "required";
-    }
-  }
-  return result;
-}
-
-/**
- * Renders a function signature of the form 'type name(args)'
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_java_generator::function_signature(t_function* tfunction,
-                                            string prefix) {
-  t_type* ttype = tfunction->get_returntype();
-  std::string result =
-    type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ") throws ";
-  t_struct* xs = tfunction->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) {
-    result += type_name((*x_iter)->get_type(), false, false) + ", ";
-  }
-  result += "org.apache.thrift.TException";
-  return result;
-}
-
-/**
- * Renders a function signature of the form 'void name(args, resultHandler)'
- *
- * @params tfunction Function definition
- * @return String of rendered function definition
- */
-string t_java_generator::function_signature_async(t_function* tfunction, bool use_base_method, string prefix) {
-  std::string arglist = async_function_call_arglist(tfunction, use_base_method, true);
-
-  std::string ret_type = "";
-  if (use_base_method) {
-    ret_type += "AsyncClient.";
-  }
-  ret_type += tfunction->get_name() + "_call";
-
-  std::string result = prefix + "void " + tfunction->get_name() + "(" + arglist + ")";
-  return result;
-}
-
-string t_java_generator::async_function_call_arglist(t_function* tfunc, bool use_base_method, bool include_types) {
-  std::string arglist = "";
-  if (tfunc->get_arglist()->get_members().size() > 0) {
-    arglist = argument_list(tfunc->get_arglist(), include_types) + ", ";
-  }
-
-  if (include_types) {
-    arglist += "org.apache.thrift.async.AsyncMethodCallback ";
-  }
-  arglist += "resultHandler";
-
-  return arglist;
-}
-
-/**
- * Renders a comma separated field list, with type names
- */
-string t_java_generator::argument_list(t_struct* tstruct, bool include_types) {
-  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 += ", ";
-    }
-    if (include_types) {
-      result += type_name((*f_iter)->get_type()) + " ";
-    }
-    result += (*f_iter)->get_name();
-  }
-  return result;
-}
-
-string t_java_generator::async_argument_list(t_function* tfunct, t_struct* tstruct, t_type* ttype, bool include_types) {
-  (void) ttype;
-  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 += ", ";
-    }
-    if (include_types) {
-      result += type_name((*f_iter)->get_type()) + " ";
-    }
-    result += (*f_iter)->get_name();
-  }
-  if (!first) {
-    result += ", ";
-  }
-  if (include_types) {
-    result += "org.apache.thrift.async.AsyncMethodCallback ";
-  }
-  result += "resultHandler";
-  return result;
-}
-
-/**
- * Converts the parse type to a Java enum string for the given type.
- */
-string t_java_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 "org.apache.thrift.protocol.TType.STRING";
-      case t_base_type::TYPE_BOOL:
-        return "org.apache.thrift.protocol.TType.BOOL";
-      case t_base_type::TYPE_BYTE:
-        return "org.apache.thrift.protocol.TType.BYTE";
-      case t_base_type::TYPE_I16:
-        return "org.apache.thrift.protocol.TType.I16";
-      case t_base_type::TYPE_I32:
-        return "org.apache.thrift.protocol.TType.I32";
-      case t_base_type::TYPE_I64:
-        return "org.apache.thrift.protocol.TType.I64";
-      case t_base_type::TYPE_DOUBLE:
-        return "org.apache.thrift.protocol.TType.DOUBLE";
-    }
-  } else if (type->is_enum()) {
-    return "org.apache.thrift.protocol.TType.I32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "org.apache.thrift.protocol.TType.STRUCT";
-  } else if (type->is_map()) {
-    return "org.apache.thrift.protocol.TType.MAP";
-  } else if (type->is_set()) {
-    return "org.apache.thrift.protocol.TType.SET";
-  } else if (type->is_list()) {
-    return "org.apache.thrift.protocol.TType.LIST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-/**
- * Takes a name and produes a valid Java source file name from it
- *
- * @param fromName The name which shall become a valid Java source file name
- * @return The produced identifier
- */
-std::string t_java_generator::make_valid_java_filename( std::string const & fromName) {
-    // if any further rules apply to source file names in Java, modify as necessary
-    return make_valid_java_identifier(fromName);
-}
-
-/**
- * Takes a name and produes a valid Java identifier from it
- *
- * @param fromName The name which shall become a valid Java identifier
- * @return The produced identifier
- */
-std::string t_java_generator::make_valid_java_identifier( std::string const & fromName) {
-    std::string str = fromName;
-    if( str.empty()) {
-        return str;
-    }
-
-    // tests rely on this
-    assert( ('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
-    
-    // if the first letter is a number, we add an additional underscore in front of it
-    char c = str.at(0);
-    if( ('0' <= c) && (c <= '9')) {
-        str = "_" + str;
-    }
-
-    // following chars: letter, number or underscore
-    for( size_t i = 0;  i < str.size();  ++i) {
-        c = str.at(i);        
-        if( (('A' > c) || (c > 'Z')) && 
-            (('a' > c) || (c > 'z')) && 
-            (('0' > c) || (c > '9')) && 
-            ('_' != c) ) {
-            str.replace( i, 1, "_");
-        }
-    }
-
-    return str;
-}
-
-
-/**
- * Applies the correct style to a string based on the value of nocamel_style_
- */
-std::string t_java_generator::get_cap_name(std::string name){
-  if (nocamel_style_) {
-    return "_" + name;
-  } else {
-    name[0] = toupper(name[0]);
-    return name;
-  }
-}
-
-string t_java_generator::constant_name(string name) {
-  string constant_name;
-
-  bool is_first = true;
-  bool was_previous_char_upper = false;
-  for (string::iterator iter = name.begin(); iter != name.end(); ++iter) {
-    string::value_type character = (*iter);
-
-    bool is_upper = isupper(character);
-
-    if (is_upper && !is_first && !was_previous_char_upper) {
-      constant_name += '_';
-    }
-    constant_name += toupper(character);
-
-    is_first = false;
-    was_previous_char_upper = is_upper;
-  }
-
-  return constant_name;
-}
-
-void t_java_generator::generate_java_docstring_comment(ofstream &out, string contents) {
-  generate_docstring_comment(out,
-                             "/**\n",
-                             " * ", contents,
-                             " */\n");
-}
-
-void t_java_generator::generate_java_doc(ofstream &out,
-                                         t_field* field) {
-  if (field->get_type()->is_enum()) {
-    string combined_message = field->get_doc() + "\n@see " + get_enum_class_name(field->get_type());
-    generate_java_docstring_comment(out, combined_message);
-  } else {
-    generate_java_doc(out, (t_doc*)field);
-  }
-}
-
-/**
- * Emits a JavaDoc comment if the provided object has a doc in Thrift
- */
-void t_java_generator::generate_java_doc(ofstream &out,
-                                         t_doc* tdoc) {
-  if (tdoc->has_doc()) {
-    generate_java_docstring_comment(out, tdoc->get_doc());
-  }
-}
-
-/**
- * Emits a JavaDoc comment if the provided function object has a doc in Thrift
- */
-void t_java_generator::generate_java_doc(ofstream &out,
-                                         t_function* tfunction) {
-  if (tfunction->has_doc()) {
-    stringstream ss;
-    ss << tfunction->get_doc();
-    const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
-    vector<t_field*>::const_iterator p_iter;
-    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
-      t_field* p = *p_iter;
-      ss << "\n@param " << p->get_name();
-      if (p->has_doc()) {
-        ss << " " << p->get_doc();
-      }
-    }
-    generate_docstring_comment(out,
-                               "/**\n",
-                               " * ", ss.str(),
-                               " */\n");
-  }
-}
-
-void t_java_generator::generate_deep_copy_container(ofstream &out, std::string source_name_p1, std::string source_name_p2,
-                                                    std::string result_name, t_type* type) {
-
-  t_container* container = (t_container*)type;
-  std::string source_name;
-  if (source_name_p2 == "")
-    source_name = source_name_p1;
-  else
-    source_name = source_name_p1 + "." + source_name_p2;
-  
-  bool copy_construct_container;
-  if (container->is_map()) {
-    t_map *tmap = (t_map *)container;
-    copy_construct_container = tmap->get_key_type()->is_base_type() && tmap->get_val_type()->is_base_type();
-  } else {
-    t_type* elem_type = container->is_list() ? ((t_list *) container)->get_elem_type() :
-                                               ((t_set *) container)->get_elem_type();
-    copy_construct_container = elem_type->is_base_type();
-  }
-
-  if (copy_construct_container) {
-    // deep copy of base types can be done much more efficiently than iterating over all the elements manually
-    indent(out) << type_name(type, true, false) << " " << result_name << " = new " << type_name(container, false, true) << "(" << source_name << ");" << endl;
-    return;
-  }
-
-  std::string capacity;
-  if (!(sorted_containers_ && (container->is_map() || container->is_set()))) {
-    // unsorted containers accept a capacity value
-    capacity = source_name + ".size()";
-  }
-  indent(out) << type_name(type, true, false) << " " << result_name << " = new " << type_name(container, false, true) << "(" << capacity << ");" << endl;
-
-  std::string iterator_element_name = source_name_p1 + "_element";
-  std::string result_element_name = result_name + "_copy";
-
-  if(container->is_map()) {
-    t_type* key_type = ((t_map*)container)->get_key_type();
-    t_type* val_type = ((t_map*)container)->get_val_type();
-
-    indent(out) <<
-      "for (Map.Entry<" << type_name(key_type, true, false) << ", " << type_name(val_type, true, false) << "> " << iterator_element_name << " : " << source_name << ".entrySet()) {" << endl;
-    indent_up();
-
-    out << endl;
-
-    indent(out) << type_name(key_type, true, false) << " " << iterator_element_name << "_key = " << iterator_element_name << ".getKey();" << endl;
-    indent(out) << type_name(val_type, true, false) << " " << iterator_element_name << "_value = " << iterator_element_name << ".getValue();" << endl;
-
-    out << endl;
-
-    if (key_type->is_container()) {
-      generate_deep_copy_container(out, iterator_element_name + "_key", "", result_element_name + "_key", key_type);
-    } else {
-      indent(out) << type_name(key_type, true, false) << " " << result_element_name << "_key = ";
-      generate_deep_copy_non_container(out, iterator_element_name + "_key", result_element_name + "_key", key_type);
-      out << ";" << endl;
-    }
-
-    out << endl;
-
-    if (val_type->is_container()) {
-      generate_deep_copy_container(out, iterator_element_name + "_value", "", result_element_name + "_value", val_type);
-    } else {
-      indent(out) << type_name(val_type, true, false) << " " << result_element_name << "_value = ";
-      generate_deep_copy_non_container(out, iterator_element_name + "_value", result_element_name + "_value", val_type);
-      out << ";" << endl;
-    }
-
-    out << endl;
-
-    indent(out) << result_name << ".put(" << result_element_name << "_key, " << result_element_name << "_value);" << endl;
-
-    indent_down();
-    indent(out) << "}" << endl;
-
-  } else {
-    t_type* elem_type;
-
-    if (container->is_set()) {
-      elem_type = ((t_set*)container)->get_elem_type();
-    } else {
-      elem_type = ((t_list*)container)->get_elem_type();
-    }
-
-    indent(out)
-      << "for (" << type_name(elem_type, true, false) << " " << iterator_element_name << " : " << source_name << ") {" << endl;
-
-    indent_up();
-
-    if (elem_type->is_container()) {
-      // recursive deep copy
-      generate_deep_copy_container(out, iterator_element_name, "", result_element_name, elem_type);
-      indent(out) << result_name << ".add(" << result_element_name << ");" << endl;
-    } else {
-      // iterative copy
-      if(((t_base_type*)elem_type)->is_binary()){
-        indent(out) << "ByteBuffer temp_binary_element = ";
-        generate_deep_copy_non_container(out, iterator_element_name, "temp_binary_element", elem_type);
-        out << ";" << endl;
-        indent(out) << result_name << ".add(temp_binary_element);" << endl;
-      } else{
-        indent(out) << result_name << ".add(";
-        generate_deep_copy_non_container(out, iterator_element_name, result_name, elem_type);
-        out << ");" << endl;
-      }
-    }
-
-    indent_down();
-
-    indent(out) << "}" << endl;
-
-  }
-}
-
-void t_java_generator::generate_deep_copy_non_container(ofstream& out, std::string source_name, std::string dest_name, t_type* type) {
-  (void) dest_name;
-  if (type->is_base_type() || type->is_enum() || type->is_typedef()) {
-    if (((t_base_type*)type)->is_binary()) {
-      out << "org.apache.thrift.TBaseHelper.copyBinary(" << source_name << ");" << endl;
-    } else {
-      // everything else can be copied directly
-      out << source_name;
-    }
-  } else {
-    out << "new " << type_name(type, true, true) << "(" << source_name << ")";
-  }
-}
-
-std::string t_java_generator::generate_isset_check(t_field* field) {
-  return generate_isset_check(field->get_name());
-}
-
-std::string t_java_generator::isset_field_id(t_field* field) {
-  return "__" + upcase_string(field->get_name() + "_isset_id");
-}
-
-std::string t_java_generator::generate_isset_check(std::string field_name) {
-  return "is" + get_cap_name("set") + get_cap_name(field_name) + "()";
-}
-
-void t_java_generator::generate_isset_set(ofstream& out, t_field* field, string prefix) {
-  if (!type_can_be_null(field->get_type())) {
-    indent(out) << prefix << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet") << "(true);" << endl;
-  }
-}
-
-std::string t_java_generator::get_enum_class_name(t_type* type) {
-  string package = "";
-  t_program* program = type->get_program();
-  if (program != NULL && program != program_) {
-    package = program->get_namespace("java") + ".";
-  }
-  return package + type->get_name();
-}
-
-void t_java_generator::generate_struct_desc(ofstream& out, t_struct* tstruct) {
-  indent(out) <<
-  "private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct(\"" << tstruct->get_name() << "\");" << endl;
-}
-
-void t_java_generator::generate_field_descs(ofstream& out, t_struct* tstruct) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    indent(out) <<
-      "private static final org.apache.thrift.protocol.TField " << constant_name((*m_iter)->get_name()) <<
-      "_FIELD_DESC = new org.apache.thrift.protocol.TField(\"" << (*m_iter)->get_name() << "\", " <<
-      type_to_enum((*m_iter)->get_type()) << ", " <<
-      "(short)" << (*m_iter)->get_key() << ");" << endl;
-  }
-}
-
-void t_java_generator::generate_scheme_map(ofstream& out, t_struct* tstruct) {
-  indent(out) << "private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();" << endl;
-  indent(out) << "static {" << endl;
-  indent(out) << "  schemes.put(StandardScheme.class, new " << tstruct->get_name() << "StandardSchemeFactory());" << endl;  
-  indent(out) << "  schemes.put(TupleScheme.class, new " << tstruct->get_name() << "TupleSchemeFactory());" << endl;  
-  indent(out) << "}" << endl;
-}
-
-void t_java_generator::generate_field_name_constants(ofstream& out, t_struct* tstruct) {
-  indent(out) << "/** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */" << endl;
-  indent(out) << "public enum _Fields implements org.apache.thrift.TFieldIdEnum {" << endl;
-
-  indent_up();
-  bool first = true;
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    if (!first) {
-      out << "," << endl;
-    }
-    first = false;
-    generate_java_doc(out, *m_iter);
-    indent(out) << constant_name((*m_iter)->get_name()) << "((short)" << (*m_iter)->get_key() << ", \"" << (*m_iter)->get_name() << "\")";
-  }
-
-  out << ";" << endl << endl;
-
-  indent(out) << "private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();" << endl;
-  out << endl;
-
-  indent(out) << "static {" << endl;
-  indent(out) << "  for (_Fields field : EnumSet.allOf(_Fields.class)) {" << endl;
-  indent(out) << "    byName.put(field.getFieldName(), field);" << endl;
-  indent(out) << "  }" << endl;
-  indent(out) << "}" << endl << endl;
-
-  indent(out) << "/**" << endl;
-  indent(out) << " * Find the _Fields constant that matches fieldId, or null if its not found." << endl;
-  indent(out) << " */" << endl;
-  indent(out) << "public static _Fields findByThriftId(int fieldId) {" << endl;
-  indent_up();
-  indent(out) << "switch(fieldId) {" << endl;
-  indent_up();
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    indent(out) << "case " << (*m_iter)->get_key() << ": // " << constant_name((*m_iter)->get_name()) << endl;
-    indent(out) << "  return " << constant_name((*m_iter)->get_name()) << ";" << endl;
-  }
-
-  indent(out) << "default:" << endl;
-  indent(out) << "  return null;" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-
-  indent(out) << "/**" << endl;
-  indent(out) << " * Find the _Fields constant that matches fieldId, throwing an exception" << endl;
-  indent(out) << " * if it is not found." << endl;
-  indent(out) << " */" << endl;
-  indent(out) << "public static _Fields findByThriftIdOrThrow(int fieldId) {" << endl;
-  indent(out) << "  _Fields fields = findByThriftId(fieldId);" << endl;
-  indent(out) << "  if (fields == null) throw new IllegalArgumentException(\"Field \" + fieldId + \" doesn't exist!\");" << endl;
-  indent(out) << "  return fields;" << endl;
-  indent(out) << "}" << endl << endl;
-
-  indent(out) << "/**" << endl;
-  indent(out) << " * Find the _Fields constant that matches name, or null if its not found." << endl;
-  indent(out) << " */" << endl;
-  indent(out) << "public static _Fields findByName(String name) {" << endl;
-  indent(out) << "  return byName.get(name);" << endl;
-  indent(out) << "}" << endl << endl;
-
-  indent(out) << "private final short _thriftId;" << endl;
-  indent(out) << "private final String _fieldName;" << endl << endl;
-
-  indent(out) << "_Fields(short thriftId, String fieldName) {" << endl;
-  indent(out) << "  _thriftId = thriftId;" << endl;
-  indent(out) << "  _fieldName = fieldName;" << endl;
-  indent(out) << "}" << endl << endl;
-
-  indent(out) << "public short getThriftFieldId() {" << endl;
-  indent(out) << "  return _thriftId;" << endl;
-  indent(out) << "}" << endl << endl;
-
-  indent(out) << "public String getFieldName() {" << endl;
-  indent(out) << "  return _fieldName;" << endl;
-  indent(out) << "}" << endl;
-
-  indent_down();
-
-  indent(out) << "}" << endl;
-}
-
-t_java_generator::isset_type t_java_generator::needs_isset(t_struct* tstruct, std::string *outPrimitiveType) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  int count = 0;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    if (!type_can_be_null(get_true_type((*m_iter)->get_type()))) {
-      count++;
-    }
-  }
-  if(count == 0) {
-    return ISSET_NONE;
-  } else if(count <= 64) {
-    if(outPrimitiveType != NULL) {
-      if(count <= 8)
-        *outPrimitiveType = "byte";
-      else if(count <= 16)
-        *outPrimitiveType = "short";
-      else if(count <= 32)
-        *outPrimitiveType = "int";
-      else if(count <= 64)
-        *outPrimitiveType = "long";
-    }
-    return ISSET_PRIMITIVE;
-  } else {
-    return ISSET_BITSET;
-  }
-}
-
-void t_java_generator::generate_java_struct_clear(std::ofstream& out, t_struct* tstruct) {
-  if (!java5_) {
-    indent(out) << "@Override" << endl;
-  }
-  indent(out) << "public void clear() {" << endl;
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  indent_up();
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = *m_iter;
-    t_type* t = get_true_type(field->get_type());
-
-    if (field->get_value() != NULL) {
-      print_const_value(out, "this." + field->get_name(), t, field->get_value(), true, true);
-      continue;
-    }
-
-    if (type_can_be_null(t)) {
-      indent(out) << "this." << field->get_name() << " = null;" << endl;
-      continue;
-    }
-
-    // must be a base type
-    // means it also needs to be explicitly unset
-    indent(out) << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet") << "(false);" << endl;
-    t_base_type* base_type = (t_base_type*) t;
-
-    switch (base_type->get_base()) {
-      case t_base_type::TYPE_BYTE:
-      case t_base_type::TYPE_I16:
-      case t_base_type::TYPE_I32:
-      case t_base_type::TYPE_I64:
-        indent(out) << "this." << field->get_name() << " = 0;" << endl;
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        indent(out) << "this." << field->get_name() << " = 0.0;" << endl;
-        break;
-      case t_base_type::TYPE_BOOL:
-        indent(out) << "this." << field->get_name() << " = false;" << endl;
-        break;
-      default:
-        throw "unsupported type: " + base_type->get_name() + " for field " + field->get_name();
-    }
-  }
-  indent_down();
-
-  indent(out) << "}" << endl << endl;
-}
-
-// generates java method to serialize (in the Java sense) the object
-void t_java_generator::generate_java_struct_write_object(ofstream& out, t_struct* tstruct) {
-  (void) tstruct;
-  indent(out) << "private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {" << endl;
-  indent(out) << "  try {" << endl;
-  indent(out) << "    write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));" << endl;
-  indent(out) << "  } catch (org.apache.thrift.TException te) {" << endl;
-  indent(out) << "    throw new java.io.IOException(te" << (android_legacy_? ".getMessage()" : "") << ");" << endl;
-  indent(out) << "  }" << endl;
-  indent(out) << "}" << endl << endl;
-}
-
-// generates java method to serialize (in the Java sense) the object
-void t_java_generator::generate_java_struct_read_object(ofstream& out, t_struct* tstruct) {
-  indent(out) << "private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {" << endl;
-  indent(out) << "  try {" << endl;
-  if (!tstruct->is_union()) {
-    switch(needs_isset(tstruct)) {
-      case ISSET_NONE:
-        break;
-      case ISSET_PRIMITIVE:
-        indent(out) << "    // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor." << endl;
-        indent(out) << "    __isset_bitfield = 0;" << endl;
-        break;
-      case ISSET_BITSET:
-        indent(out) << "    // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor." << endl;
-        indent(out) << "    __isset_bit_vector = new BitSet(1);" << endl;
-        break;
-    }
-  }
-  indent(out) << "    read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));" << endl;
-  indent(out) << "  } catch (org.apache.thrift.TException te) {" << endl;
-  indent(out) << "    throw new java.io.IOException(te" << (android_legacy_? ".getMessage()" : "") << ");" << endl;
-  indent(out) << "  }" << endl;
-  indent(out) << "}" << endl << endl;
-}
-
-void t_java_generator::generate_standard_reader(ofstream& out, t_struct* tstruct) {
-  out <<
-    indent() << "public void read(org.apache.thrift.protocol.TProtocol iprot, " <<  tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl;
-  indent_up();
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  // Declare stack tmp variables and read struct header
-  out <<
-    indent() << "org.apache.thrift.protocol.TField schemeField;" << endl <<
-    indent() << "iprot.readStructBegin();" << endl;
-
-  // Loop over reading in fields
-  indent(out) << "while (true)" << endl;
-  scope_up(out);
-
-  // Read beginning field marker
-  indent(out) << "schemeField = iprot.readFieldBegin();" << endl;
-
-  // Check for field STOP marker and break
-  indent(out) << "if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { " << endl;
-  indent_up();
-  indent(out) << "break;" << endl;
-  indent_down();
-  indent(out) << "}" << endl;
-
-  // Switch statement on the field we are reading
-  indent(out) << "switch (schemeField.id) {" << endl;
-
-  indent_up();
-
-  // Generate deserialization code for known cases
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    indent(out) <<
-      "case " << (*f_iter)->get_key() << ": // " << constant_name((*f_iter)->get_name()) << endl;
-    indent_up();
-    indent(out) <<
-      "if (schemeField.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
-    indent_up();
-
-    generate_deserialize_field(out, *f_iter, "struct.", true);
-    indent(out) << "struct." << "set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet") << "(true);" << endl;
-    indent_down();
-    out <<
-      indent() << "} else { " << endl <<
-      indent() << "  org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);" << endl <<
-      indent() << "}" << endl <<
-      indent() << "break;" << endl;
-    indent_down();
-  }
-
-  indent(out) << "default:" << endl;
-  indent(out) << "  org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-
-  // Read field end marker
-  indent(out) << "iprot.readFieldEnd();" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-
-  out <<
-    indent() << "iprot.readStructEnd();" << endl;
-
-  // in non-beans style, check for required fields of primitive type
-  // (which can be checked here but not in the general validate method)
-  if (!bean_style_){
-    out << endl << indent() << "// check for required fields of primitive type, which can't be checked in the validate method" << endl;
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) {
-        out <<
-        indent() << "if (!struct."  << generate_isset_check(*f_iter) << ") {" << endl <<
-        indent() << "  throw new org.apache.thrift.protocol.TProtocolException(\"Required field '" << (*f_iter)->get_name() << "' was not found in serialized data! Struct: \" + toString());" << endl <<
-        indent() << "}" << endl;
-      }
-    }
-  }
-
-  // performs various checks (e.g. check that all required fields are set)
-  indent(out) << "struct.validate();" << endl;
-
-  indent_down();
-  out << indent() << "}" << endl;	
-}
-
-void t_java_generator::generate_standard_writer(ofstream& out, t_struct* tstruct, bool is_result) {
-  indent_up();
-  out <<
-    indent() << "public void write(org.apache.thrift.protocol.TProtocol oprot, " << 
-    tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl;
-  indent_up();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  // performs various checks (e.g. check that all required fields are set)
-  indent(out) << "struct.validate();" << endl << endl;
-
-  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    bool null_allowed = type_can_be_null((*f_iter)->get_type());
-    if (null_allowed) {
-      out <<
-      indent() << "if (struct." << (*f_iter)->get_name() << " != null) {" << endl;
-      indent_up();
-    }
-    bool optional = ((*f_iter)->get_req() == t_field::T_OPTIONAL) || (is_result && !null_allowed);
-    if (optional) {
-      indent(out) << "if (" << "struct." << generate_isset_check((*f_iter)) << ") {" << endl;
-      indent_up();
-    }
-
-    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl;
-
-    // Write field contents
-    generate_serialize_field(out, *f_iter, "struct.", true);
-
-    // Write field closer
-    indent(out) << "oprot.writeFieldEnd();" << endl;
-
-    if (optional) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    if (null_allowed) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-  }
-  // Write the struct map
-  out << 
-    indent() << "oprot.writeFieldStop();" << endl <<
-    indent() << "oprot.writeStructEnd();" << endl;
-
-  indent_down();
-  out << indent() << "}" << endl << endl;
-  indent_down();
-}
-
-void t_java_generator::generate_java_struct_standard_scheme(ofstream& out, t_struct* tstruct, bool is_result){
-  indent(out) << "private static class " << tstruct->get_name() << "StandardSchemeFactory implements SchemeFactory {" << endl;
-  indent_up();
-  indent(out) << "public " << tstruct->get_name() << "StandardScheme getScheme() {" << endl;
-  indent_up();
-  indent(out) << "return new " << tstruct->get_name() << "StandardScheme();" << endl;
-  indent_down();
-  indent(out) << "}" << endl;
-  indent_down();
-  indent(out) << "}" << endl << endl;
-
-  out << indent() << "private static class " << tstruct->get_name() << "StandardScheme extends StandardScheme<" << tstruct->get_name() << "> {" << endl << endl;
-  indent_up();
-  generate_standard_reader(out, tstruct);
-  indent_down();
-  out << endl;
-  generate_standard_writer(out, tstruct, is_result);
-
-  out <<
-  indent() << "}" << endl <<
-  endl;
-}
-
-void t_java_generator::generate_java_struct_tuple_reader(ofstream& out, t_struct* tstruct) {
-  indent(out) << "@Override" << endl;
-  indent(out) << "public void read(org.apache.thrift.protocol.TProtocol prot, " << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl;
-  indent_up();
-  indent(out) << "TTupleProtocol iprot = (TTupleProtocol) prot;" << endl;
-  int optional_count = 0;
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if ((*f_iter)->get_req() == t_field::T_OPTIONAL || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
-      optional_count++;
-    }
-    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
-      generate_deserialize_field(out, (*f_iter), "struct.", false);
-      indent(out) << "struct.set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet") << "(true);" << endl;
-    }
-  }
-  if (optional_count > 0) {
-    indent(out) << "BitSet incoming = iprot.readBitSet(" << optional_count << ");" << endl;
-    int i = 0;
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      if ((*f_iter)->get_req() == t_field::T_OPTIONAL || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
-        indent(out) << "if (incoming.get(" << i << ")) {" << endl;
-        indent_up();
-        generate_deserialize_field(out, (*f_iter), "struct.", false);
-        indent(out) << "struct.set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet") << "(true);" << endl;
-        indent_down();
-        indent(out) << "}" << endl;
-        i++;
-      }
-    }
-  }
-  indent_down();
-  indent(out) << "}" << endl;  
-}
-
-void t_java_generator::generate_java_struct_tuple_writer(ofstream& out, t_struct* tstruct) {
-  indent(out) << "@Override" << endl;
-  indent(out) << "public void write(org.apache.thrift.protocol.TProtocol prot, " << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl;
-  indent_up();
-  indent(out) << "TTupleProtocol oprot = (TTupleProtocol) prot;" << endl;
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  bool has_optional = false;
-  int optional_count = 0;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if ((*f_iter)->get_req() == t_field::T_OPTIONAL || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
-      optional_count++;
-      has_optional = true;
-    }
-    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
-      generate_serialize_field(out, (*f_iter), "struct.", false);
-    }
-  }
-  if (has_optional) {
-    indent(out) << "BitSet optionals = new BitSet();" << endl;
-    int i = 0;
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      if ((*f_iter)->get_req() == t_field::T_OPTIONAL || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
-        indent(out) << "if (struct." << generate_isset_check((*f_iter)) << ") {" << endl;
-        indent_up();
-        indent(out) << "optionals.set(" << i << ");" << endl;
-        indent_down();
-        indent(out) << "}" << endl;
-        i++;
-      }
-    }
-
-    indent(out) << "oprot.writeBitSet(optionals, " << optional_count << ");" << endl;
-    int j = 0;
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      if ((*f_iter)->get_req() == t_field::T_OPTIONAL || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
-        indent(out) << "if (struct." << generate_isset_check(*f_iter) << ") {" << endl;
-        indent_up();
-        generate_serialize_field(out, (*f_iter), "struct.", false);
-        indent_down();
-        indent(out) << "}" << endl;
-        j++;
-      }
-    }
-  }
-  indent_down();
-  indent(out) << "}" << endl;
-}
-
-void t_java_generator::generate_java_struct_tuple_scheme(ofstream& out, t_struct* tstruct){
-  indent(out) << "private static class " << tstruct->get_name() << "TupleSchemeFactory implements SchemeFactory {" << endl;
-  indent_up();
-  indent(out) << "public " << tstruct->get_name() << "TupleScheme getScheme() {" << endl;
-  indent_up();
-  indent(out) << "return new " << tstruct->get_name() << "TupleScheme();" << endl;
-  indent_down();
-  indent(out) << "}" << endl;
-  indent_down();
-  indent(out) << "}" << endl << endl;
-  out << indent() << "private static class " << tstruct->get_name() << "TupleScheme extends TupleScheme<" << tstruct->get_name() << "> {" << endl << endl;
-  indent_up();
-  generate_java_struct_tuple_writer(out, tstruct);
-  out << endl;
-  generate_java_struct_tuple_reader(out, tstruct);
-  indent_down();
-  out << indent() << "}" << endl << endl;
-}
-
-THRIFT_REGISTER_GENERATOR(java, "Java",
-"    beans:           Members will be private, and setter methods will return void.\n"
-"    private-members: Members will be private, but setter methods will return 'this' like usual.\n"
-"    nocamel:         Do not use CamelCase field accessors with beans.\n"
-"    hashcode:        Generate quality hashCode methods.\n"
-"    android_legacy:  Do not use java.io.IOException(throwable) (available for Android 2.3 and above).\n"
-"    java5:           Generate Java 1.5 compliant code (includes android_legacy flag).\n"
-"    sorted_containers:\n"
-"                     Use TreeSet/TreeMap instead of HashSet/HashMap as a implementation of set/map.\n"
-)
-
diff --git a/compiler/cpp/src/generate/t_javame_generator.cc b/compiler/cpp/src/generate/t_javame_generator.cc
deleted file mode 100644
index a2a31a5..0000000
--- a/compiler/cpp/src/generate/t_javame_generator.cc
+++ /dev/null
@@ -1,3393 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <sstream>
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-#include <cctype>
-
-#include <sys/stat.h>
-#include <stdexcept>
-
-#include "platform.h"
-#include "t_oop_generator.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * Java code generator.
- *
- */
-class t_javame_generator : public t_oop_generator {
- public:
-  t_javame_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_oop_generator(program)
-  {
-    (void) parsed_options;
-    (void) option_string;
-    std::map<std::string, std::string>::const_iterator iter;
-    out_dir_base_ = "gen-javame";
-  }
-
-  /**
-   * Init and close methods
-   */
-
-  void init_generator();
-  void close_generator();
-
-  void generate_consts(std::vector<t_const*> consts);
-
-  /**
-   * Program-level generation functions
-   */
-
-  void generate_typedef (t_typedef*  ttypedef);
-  void generate_enum    (t_enum*     tenum);
-  void generate_struct  (t_struct*   tstruct);
-  void generate_union   (t_struct*   tunion);
-  void generate_xception(t_struct*   txception);
-  void generate_service (t_service*  tservice);
-
-  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool in_static, bool defval=false);
-  std::string render_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
-
-  /**
-   * Service-level generation functions
-   */
-
-  void generate_java_struct(t_struct* tstruct, bool is_exception);
-
-  void generate_java_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool in_class=false, bool is_result=false);
-  void generate_java_struct_equality(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_compare_to(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_reader(std::ofstream& out, t_struct* tstruct);
-  void generate_java_validator(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_result_writer(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_writer(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_tostring(std::ofstream& out, t_struct* tstruct);
-  void generate_java_struct_clear(std::ofstream& out, t_struct* tstruct);
-  void generate_field_value_meta_data(std::ofstream& out, t_type* type);
-  std::string get_java_type_string(t_type* type);
-  void generate_reflection_setters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name);
-  void generate_reflection_getters(std::ostringstream& out, t_type* type, std::string field_name, std::string cap_name);
-  void generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct);
-  void generate_java_bean_boilerplate(std::ofstream& out, t_struct* tstruct);
-
-  void generate_function_helpers(t_function* tfunction);
-  std::string get_cap_name(std::string name);
-  std::string generate_isset_check(t_field* field);
-  std::string generate_isset_check(std::string field);
-  void generate_isset_set(ofstream& out, t_field* field);
-  std::string isset_field_id(t_field* field);
-
-  void generate_primitive_service_interface (t_service* tservice);
-  void generate_service_interface (t_service* tservice);
-  void generate_service_helpers   (t_service* tservice);
-  void generate_service_client    (t_service* tservice);
-  void generate_service_server    (t_service* tservice);
-  void generate_process_function  (t_service* tservice, t_function* tfunction);
-
-  void generate_java_union(t_struct* tstruct);
-  void generate_union_constructor(ofstream& out, t_struct* tstruct);
-  void generate_union_getters_and_setters(ofstream& out, t_struct* tstruct);
-  void generate_union_abstract_methods(ofstream& out, t_struct* tstruct);
-  void generate_check_type(ofstream& out, t_struct* tstruct);
-  void generate_read_value(ofstream& out, t_struct* tstruct);
-  void generate_write_value(ofstream& out, t_struct* tstruct);
-  void generate_get_field_desc(ofstream& out, t_struct* tstruct);
-  void generate_get_struct_desc(ofstream& out, t_struct* tstruct);
-  void generate_get_field_name(ofstream& out, t_struct* tstruct);
-
-  void generate_union_comparisons(ofstream& out, t_struct* tstruct);
-  void generate_union_hashcode(ofstream& out, t_struct* tstruct);
-
-  /**
-   * Serialization constructs
-   */
-
-  void generate_deserialize_field        (std::ofstream& out,
-                                          t_field*    tfield,
-                                          std::string prefix="");
-
-  void generate_deserialize_struct       (std::ofstream& out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_deserialize_container    (std::ofstream& out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_deserialize_set_element  (std::ofstream& out,
-                                          t_set*      tset,
-                                          std::string prefix="");
-
-  void generate_deserialize_map_element  (std::ofstream& out,
-                                          t_map*      tmap,
-                                          std::string prefix="");
-
-  void generate_deserialize_list_element (std::ofstream& out,
-                                          t_list*     tlist,
-                                          std::string prefix="");
-
-  void generate_serialize_field          (std::ofstream& out,
-                                          t_field*    tfield,
-                                          std::string prefix="");
-
-  void generate_serialize_struct         (std::ofstream& out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_serialize_container      (std::ofstream& out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_serialize_map_element    (std::ofstream& out,
-                                          t_map*      tmap,
-                                          std::string iter,
-                                          std::string map);
-
-  void generate_serialize_set_element    (std::ofstream& out,
-                                          t_set*      tmap,
-                                          std::string iter);
-
-  void generate_serialize_list_element   (std::ofstream& out,
-                                          t_list*     tlist,
-                                          std::string iter);
-
-  void generate_java_doc                 (std::ofstream& out,
-                                          t_field*    field);
-
-  void generate_java_doc                 (std::ofstream& out,
-                                          t_doc*      tdoc);
-
-  void generate_java_doc                 (std::ofstream& out,
-                                          t_function* tdoc);
-
-  void generate_java_docstring_comment   (std::ofstream &out,
-                                          string contents);
-
-  void generate_deep_copy_container(std::ofstream& out, std::string source_name_p1, std::string source_name_p2, std::string result_name, t_type* type);
-  void generate_deep_copy_non_container(std::ofstream& out, std::string source_name, std::string dest_name, t_type* type);
-
-  bool has_bit_vector(t_struct* tstruct);
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string java_package();
-  std::string java_type_imports();
-  std::string java_thrift_imports();
-  std::string type_name(t_type* ttype, bool in_container=false, bool in_init=false, bool skip_generic=false);
-  std::string base_type_name(t_base_type* tbase, bool in_container=false);
-  std::string declare_field(t_field* tfield, bool init=false);
-  std::string function_signature(t_function* tfunction, std::string prefix="");
-  std::string argument_list(t_struct* tstruct, bool include_types = true);
-  std::string type_to_enum(t_type* ttype);
-  std::string get_enum_class_name(t_type* type);
-  void generate_struct_desc(ofstream& out, t_struct* tstruct);
-  void generate_field_descs(ofstream& out, t_struct* tstruct);
-  std::string box_type(t_type* type, string value);
-
-  bool type_can_be_null(t_type* ttype) {
-    ttype = get_true_type(ttype);
-
-    return
-      ttype->is_container() ||
-      ttype->is_struct() ||
-      ttype->is_xception() ||
-      ttype->is_string() ||
-      ttype->is_enum();
-  }
-
-  std::string constant_name(std::string name);
-
- private:
-
-  /**
-   * File streams
-   */
-
-  std::string package_name_;
-  std::ofstream f_service_;
-  std::string package_dir_;
-
-};
-
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * streams.
- *
- * @param tprogram The program to generate
- */
-void t_javame_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-  package_name_ = program_->get_namespace("java");
-
-  string dir = package_name_;
-  string subdir = get_out_dir();
-  string::size_type loc;
-  while ((loc = dir.find(".")) != string::npos) {
-    subdir = subdir + "/" + dir.substr(0, loc);
-    MKDIR(subdir.c_str());
-    dir = dir.substr(loc+1);
-  }
-  if (dir.size() > 0) {
-    subdir = subdir + "/" + dir;
-    MKDIR(subdir.c_str());
-  }
-
-  package_dir_ = subdir;
-}
-
-/**
- * Packages the generated file
- *
- * @return String of the package, i.e. "package org.apache.thriftdemo;"
- */
-string t_javame_generator::java_package() {
-  if (!package_name_.empty()) {
-    return string("package ") + package_name_ + ";\n\n";
-  }
-  return "";
-}
-
-/**
- * Prints standard java imports
- *
- * @return List of imports for Java types that are used in here
- */
-string t_javame_generator::java_type_imports() {
-  return
-    string() +
-    "import java.util.Hashtable;\n" +
-    "import java.util.Vector;\n" +
-    "import java.util.Enumeration;\n\n";
-}
-
-/**
- * Prints standard java imports
- *
- * @return List of imports necessary for thrift
- */
-string t_javame_generator::java_thrift_imports() {
-  return
-    string() +
-    "import org.apache.thrift.*;\n" +
-    "import org.apache.thrift.meta_data.*;\n" +
-    "import org.apache.thrift.transport.*;\n" +
-    "import org.apache.thrift.protocol.*;\n\n";
-}
-
-/**
- * Nothing in Java
- */
-void t_javame_generator::close_generator() {}
-
-/**
- * Generates a typedef. This is not done in Java, since it does
- * not support arbitrary name replacements, and it'd be a wacky waste
- * of overhead to make wrapper classes.
- *
- * @param ttypedef The type definition
- */
-void t_javame_generator::generate_typedef(t_typedef* ttypedef) {
-  (void) ttypedef;
-}
-
-/**
- * Enums are a class with a set of static constants.
- *
- * @param tenum The enumeration
- */
-void t_javame_generator::generate_enum(t_enum* tenum) {
-  // Make output file
-  string f_enum_name = package_dir_+"/"+(tenum->get_name())+".java";
-  ofstream f_enum;
-  f_enum.open(f_enum_name.c_str());
-
-  // Comment and package it
-  f_enum <<
-    autogen_comment() <<
-    java_package();
-
-  generate_java_doc(f_enum, tenum);
-  indent(f_enum) <<
-    "public class " << tenum->get_name() << " implements org.apache.thrift.TEnum ";
-  scope_up(f_enum);
-  f_enum << endl;
-
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    generate_java_doc(f_enum, *c_iter);
-    indent(f_enum) << "public static final " << tenum->get_name() <<
-      " " << (*c_iter)->get_name() << " = new " << tenum->get_name() <<
-      "(" << value << ");" << endl;
-  }
-  f_enum << endl;
-
-  // Field for thriftCode
-  indent(f_enum) << "private final int value;" << endl << endl;
-
-  indent(f_enum) << "private " << tenum->get_name() << "(int value) {" << endl;
-  indent(f_enum) << "  this.value = value;" <<endl;
-  indent(f_enum) << "}" << endl << endl;
-
-  indent(f_enum) << "/**" << endl;
-  indent(f_enum) << " * Get the integer value of this enum value, as defined in the Thrift IDL." << endl;
-  indent(f_enum) << " */" << endl;
-  indent(f_enum) << "public int getValue() {" << endl;
-  indent(f_enum) << "  return value;" <<endl;
-  indent(f_enum) << "}" << endl << endl;
-
-  indent(f_enum) << "/**" << endl;
-  indent(f_enum) << " * Find a the enum type by its integer value, as defined in the Thrift IDL." << endl;
-  indent(f_enum) << " * @return null if the value is not found." << endl;
-  indent(f_enum) << " */" << endl;
-  indent(f_enum) << "public static "+ tenum->get_name() + " findByValue(int value) { " << endl;
-
-  indent_up();
-
-  indent(f_enum) << "switch (value) {" << endl;
-  indent_up();
-
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    indent(f_enum) << "case " << value << ":" << endl;
-    indent(f_enum) << "  return " << (*c_iter)->get_name() << ";" << endl;
-  }
-  
-  indent(f_enum) << "default:" << endl;
-  indent(f_enum) << "  return null;" << endl;  
-
-  indent_down();
-
-  indent(f_enum) << "}" << endl;
-  
-  indent_down();
-
-  indent(f_enum) << "}" << endl;
-
-  scope_down(f_enum);
-
-  f_enum.close();
-}
-
-/**
- * Generates a class that holds all the constants.
- */
-void t_javame_generator::generate_consts(std::vector<t_const*> consts) {
-  if (consts.empty()) {
-    return;
-  }
-
-  string f_consts_name = package_dir_+ "/" + program_name_ +  "Constants.java";
-  ofstream f_consts;
-  f_consts.open(f_consts_name.c_str());
-
-  // Print header
-  f_consts <<
-    autogen_comment() <<
-    java_package() <<
-    java_type_imports();
-
-  f_consts <<
-    "public class " << program_name_ << "Constants {" << endl <<
-    endl;
-  indent_up();
-  vector<t_const*>::iterator c_iter;
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    print_const_value(f_consts,
-                      (*c_iter)->get_name(),
-                      (*c_iter)->get_type(),
-                      (*c_iter)->get_value(),
-                      false);
-  }
-  indent_down();
-  indent(f_consts) <<
-    "}" << endl;
-  f_consts.close();
-}
-
-
-/**
- * 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
- */
-void t_javame_generator::print_const_value(std::ofstream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval) {
-  type = get_true_type(type);
-
-  indent(out);
-  if (!defval) {
-    out <<
-      (in_static ? "" : "public static final ") <<
-      type_name(type) << " ";
-  }
-  if (type->is_base_type()) {
-    string v2 = render_const_value(out, name, type, value);
-    out << name << " = " << v2 << ";" << endl << endl;
-  } else if (type->is_enum()) {
-    out << name << " = " << render_const_value(out, name, type, value) << ";" << endl << endl;
-  } else if (type->is_struct() || type->is_xception()) {
-    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;
-    out << name << " = new " << type_name(type, false, true) << "();" << endl;
-    if (!in_static) {
-      indent(out) << "static {" << endl;
-      indent_up();
-    }
-    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();
-      }
-      string val = render_const_value(out, name, field_type, v_iter->second);
-      indent(out) << name << ".";
-      std::string cap_name = get_cap_name(v_iter->first->get_string());
-      out << "set" << cap_name << "(" << val << ");" << endl;
-    }
-    if (!in_static) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    out << endl;
-  } else if (type->is_map()) {
-    out << name << " = new " << type_name(type, false, true) << "();" << endl;
-    if (!in_static) {
-      indent(out) << "static {" << endl;
-      indent_up();
-    }
-    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();
-    map<t_const_value*, t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string key = render_const_value(out, name, ktype, v_iter->first);
-      string val = render_const_value(out, name, vtype, v_iter->second);
-      indent(out) << name << ".put(" << box_type(ktype, key) << ", " <<
-	box_type(vtype, val) << ");" << endl;
-    }
-    if (!in_static) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    out << endl;
-  } else if (type->is_list() || type->is_set()) {
-    out << name << " = new " << type_name(type, false, true) << "();" << endl;
-    if (!in_static) {
-      indent(out) << "static {" << endl;
-      indent_up();
-    }
-    t_type* etype;
-    if (type->is_list()) {
-      etype = ((t_list*)type)->get_elem_type();
-    } else {
-      etype = ((t_set*)type)->get_elem_type();
-    }
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string val = render_const_value(out, name, etype, *v_iter);
-      if (type->is_list()) {
-	indent(out) << name << ".addElement(" << box_type(etype, val) << ");" << endl;
-      } else {
-	indent(out) << name << ".put(" <<
-	  box_type(etype, val) << ", " <<
-	  box_type(etype, val) << ");" << endl;
-      }
-    }
-    if (!in_static) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    out << endl;
-  } else {
-    throw "compiler error: no const of type " + type->get_name();
-  }
-}
-
-string t_javame_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
-  (void) name;
-  type = get_true_type(type);
-  std::ostringstream render;
-
-  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:
-      render << '"' << get_escaped_string(value) << '"';
-      break;
-    case t_base_type::TYPE_BOOL:
-      render << ((value->get_integer() > 0) ? "true" : "false");
-      break;
-    case t_base_type::TYPE_BYTE:
-      render << "(byte)" << value->get_integer();
-      break;
-    case t_base_type::TYPE_I16:
-      render << "(short)" << value->get_integer();
-      break;
-    case t_base_type::TYPE_I32:
-      render << value->get_integer();
-      break;
-    case t_base_type::TYPE_I64:
-      render << value->get_integer() << "L";
-      break;
-    case t_base_type::TYPE_DOUBLE:
-      if (value->get_type() == t_const_value::CV_INTEGER) {
-        render << "(double)" << value->get_integer();
-      } else {
-        render << 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()) {
-    render << type_name(type, false, false) << "." << value->get_identifier();
-  } else {
-    string t = tmp("tmp");
-    print_const_value(out, t, type, value, true);
-    render << t;
-  }
-
-  return render.str();
-}
-
-string t_javame_generator::box_type(t_type* type, string value) {
-  if (type->is_base_type()) {
-    switch (((t_base_type*)type)->get_base()) {
-    case t_base_type::TYPE_BOOL:
-      return "new Boolean(" + value + ")";
-    case t_base_type::TYPE_BYTE:
-      return "new Byte(" + value + ")";
-    case t_base_type::TYPE_I16:
-      return "new Short(" + value + ")";
-    case t_base_type::TYPE_I32:
-      return "new Integer(" + value + ")";
-    case t_base_type::TYPE_I64:
-      return "new Long(" + value + ")";
-    case t_base_type::TYPE_DOUBLE:
-      return "new Double(" + value + ")";
-    default:
-      break;
-    }
-  }
-  return value;
-}
-
-/**
- * Generates a struct definition for a thrift data type. This will be a TBase 
- * implementor.
- *
- * @param tstruct The struct definition
- */
-void t_javame_generator::generate_struct(t_struct* tstruct) {
-  if (tstruct->is_union()) {
-    generate_java_union(tstruct);
-  } else {
-    generate_java_struct(tstruct, false);
-  }
-}
-
-/**
- * Exceptions are structs, but they inherit from Exception
- *
- * @param tstruct The struct definition
- */
-void t_javame_generator::generate_xception(t_struct* txception) {
-  generate_java_struct(txception, true);
-}
-
-
-/**
- * Java struct definition.
- *
- * @param tstruct The struct definition
- */
-void t_javame_generator::generate_java_struct(t_struct* tstruct,
-                                            bool is_exception) {
-  // Make output file
-  string f_struct_name = package_dir_+"/"+(tstruct->get_name())+".java";
-  ofstream f_struct;
-  f_struct.open(f_struct_name.c_str());
-
-  f_struct <<
-    autogen_comment() <<
-    java_package() <<
-    java_type_imports() <<
-    java_thrift_imports();
-
-  generate_java_struct_definition(f_struct,
-                                  tstruct,
-                                  is_exception);
-  f_struct.close();
-}
-
-/**
- * Java union definition.
- *
- * @param tstruct The struct definition
- */
-void t_javame_generator::generate_java_union(t_struct* tstruct) {
-  // Make output file
-  string f_struct_name = package_dir_+"/"+(tstruct->get_name())+".java";
-  ofstream f_struct;
-  f_struct.open(f_struct_name.c_str());
-
-  f_struct <<
-    autogen_comment() <<
-    java_package() <<
-    java_type_imports() <<
-    java_thrift_imports();
-
-  generate_java_doc(f_struct, tstruct);
-
-  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
-
-  indent(f_struct) <<
-    "public " << (is_final ? "final " : "") << "class " << tstruct->get_name()
-	      << " extends TUnion ";
-
-  scope_up(f_struct);
-
-  generate_struct_desc(f_struct, tstruct);
-  generate_field_descs(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_union_constructor(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_union_abstract_methods(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_union_getters_and_setters(f_struct, tstruct);
-  
-  f_struct << endl;
-
-  generate_union_comparisons(f_struct, tstruct);
-
-  f_struct << endl;
-
-  generate_union_hashcode(f_struct, tstruct);
-
-  f_struct << endl;
-
-  scope_down(f_struct);
-
-  f_struct.close();
-}
-
-void t_javame_generator::generate_union_constructor(ofstream& out, t_struct* tstruct) {
-  indent(out) << "public " << type_name(tstruct) << "() {" << endl;
-  indent(out) << "  super();" << endl;
-  indent(out) << "}" << endl << endl;
-
-  indent(out) << "public " << type_name(tstruct) << "(_Fields setField, Object value) {" << endl;
-  indent(out) << "  super(setField, value);" << endl;
-  indent(out) << "}" << endl << endl;
-
-  indent(out) << "public " << type_name(tstruct) << "(" << type_name(tstruct) << " other) {" << endl;
-  indent(out) << "  super(other);" << endl;
-  indent(out) << "}" << endl;
-
-  indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl;
-  indent(out) << "  return new " << tstruct->get_name() << "(this);" << endl;
-  indent(out) << "}" << endl << endl;
-
-  // generate "constructors" for each field
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() << "(" << type_name((*m_iter)->get_type()) << " value) {" << endl;
-    indent(out) << "  " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" << endl;
-    indent(out) << "  x.set" << get_cap_name((*m_iter)->get_name()) << "(value);" << endl;
-    indent(out) << "  return x;" << endl;
-    indent(out) << "}" << endl << endl; 
-  }
-}
-
-void t_javame_generator::generate_union_getters_and_setters(ofstream& out, t_struct* tstruct) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  
-  bool first = true;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    if (first) {
-      first = false;
-    } else {
-      out << endl;
-    }
-
-    t_field* field = (*m_iter);
-
-    generate_java_doc(out, field);
-    indent(out) << "public " << type_name(field->get_type()) << " get" << get_cap_name(field->get_name()) << "() {" << endl;
-    indent(out) << "  if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {" << endl;
-    indent(out) << "    return (" << type_name(field->get_type(), true) << ")getFieldValue();" << endl;
-    indent(out) << "  } else {" << endl;
-    indent(out) << "    throw new RuntimeException(\"Cannot get field '" << field->get_name() 
-      << "' because union is currently set to \" + getFieldDesc(getSetField()).name);" << endl;
-    indent(out) << "  }" << endl;
-    indent(out) << "}" << endl;
-    
-    out << endl;
-
-    generate_java_doc(out, field);
-    indent(out) << "public void set" << get_cap_name(field->get_name()) << "(" << type_name(field->get_type()) << " value) {" << endl;
-    if (type_can_be_null(field->get_type())) {
-      indent(out) << "  if (value == null) throw new NullPointerException();" << endl;
-    }
-    indent(out) << "  setField_ = _Fields." << constant_name(field->get_name()) << ";" << endl;
-    indent(out) << "  value_ = value;" << endl;
-    indent(out) << "}" << endl;
-  }
-}
-
-void t_javame_generator::generate_union_abstract_methods(ofstream& out, t_struct* tstruct) {
-  generate_check_type(out, tstruct);
-  out << endl;
-  generate_read_value(out, tstruct);
-  out << endl;
-  generate_write_value(out, tstruct);
-  out << endl;
-  generate_get_field_desc(out, tstruct);
-  out << endl;
-  generate_get_struct_desc(out, tstruct);
-  out << endl;
-}
-
-void t_javame_generator::generate_check_type(ofstream& out, t_struct* tstruct) {
-  indent(out) << "protected void checkType(_Fields setField, Object value) throws ClassCastException {" << endl;
-  indent_up();
-
-  indent(out) << "switch (setField) {" << endl;
-  indent_up();
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = (*m_iter);
-    
-    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
-    indent(out) << "  if (value instanceof " << type_name(field->get_type(), true, false, true) << ") {" << endl;
-    indent(out) << "    break;" << endl;
-    indent(out) << "  }" << endl;
-    indent(out) << "  throw new ClassCastException(\"Was expecting value of type " 
-      << type_name(field->get_type(), true, false) << " for field '" << field->get_name() 
-      << "', but got \" + value.getClass().getSimpleName());" << endl;
-    // do the real check here
-  }
-  
-  indent(out) << "default:" << endl;
-  indent(out) << "  throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-  
-  indent_down();
-  indent(out) << "}" << endl;
-}
-
-void t_javame_generator::generate_read_value(ofstream& out, t_struct* tstruct) {
-  indent(out) << "protected Object readValue(TProtocol iprot, TField field) throws TException {" << endl;
-
-  indent_up();
-
-  indent(out) << "_Fields setField = _Fields.findByThriftId(field.id);" << endl;
-  indent(out) << "if (setField != null) {" << endl;
-  indent_up();
-  indent(out) << "switch (setField) {" << endl;
-  indent_up();
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = (*m_iter);
-    
-    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
-    indent_up();
-    indent(out) << "if (field.type == " << constant_name(field->get_name()) << "_FIELD_DESC.type) {" << endl;
-    indent_up();
-    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";" << endl;
-    generate_deserialize_field(out, field, "");
-    indent(out) << "return " << field->get_name() << ";" << endl;
-    indent_down();
-    indent(out) << "} else {" << endl;
-    indent(out) << "  TProtocolUtil.skip(iprot, field.type);" << endl;
-    indent(out) << "  return null;" << endl;
-    indent(out) << "}" << endl;
-    indent_down();
-  }
-
-  indent(out) << "default:" << endl;
-  indent(out) << "  throw new IllegalStateException(\"setField wasn't null, but didn't match any of the case statements!\");" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-
-  indent_down();
-  indent(out) << "} else {" << endl;
-  indent_up();
-  indent(out) << "TProtocolUtil.skip(iprot, field.type);" << endl;
-  indent(out) << "return null;" << endl;
-  indent_down();
-  indent(out) << "}" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-}
-
-void t_javame_generator::generate_write_value(ofstream& out, t_struct* tstruct) {
-  indent(out) << "protected void writeValue(TProtocol oprot) throws TException {" << endl;
-
-  indent_up();
-
-  indent(out) << "switch (setField_) {" << endl;
-  indent_up();
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = (*m_iter);
-    
-    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
-    indent_up();
-    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() 
-      << " = (" <<  type_name(field->get_type(), true, false) << ")value_;" << endl;
-    generate_serialize_field(out, field, "");
-    indent(out) << "return;" << endl;
-    indent_down();
-  }
-  
-  indent(out) << "default:" << endl;
-  indent(out) << "  throw new IllegalStateException(\"Cannot write union with unknown field \" + setField_);" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-
-  indent_down();
-
-
-
-  indent(out) << "}" << endl;
-}
-
-void t_javame_generator::generate_get_field_desc(ofstream& out, t_struct* tstruct) {
-  indent(out) << "protected TField getFieldDesc(_Fields setField) {" << endl;
-  indent_up();
-  
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  indent(out) << "switch (setField) {" << endl;
-  indent_up();
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = (*m_iter);
-    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
-    indent(out) << "  return " << constant_name(field->get_name()) << "_FIELD_DESC;" << endl;
-  }
-
-  indent(out) << "default:" << endl;
-  indent(out) << "  throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl;
-}
-
-void t_javame_generator::generate_get_struct_desc(ofstream& out, t_struct* tstruct) {
-  (void) tstruct;
-  indent(out) << "protected TStruct getStructDesc() {" << endl;
-  indent(out) << "  return STRUCT_DESC;" << endl;
-  indent(out) << "}" << endl;
-}
-
-void t_javame_generator::generate_union_comparisons(ofstream& out, t_struct* tstruct) {
-  // equality
-  indent(out) << "public boolean equals(Object other) {" << endl;
-  indent(out) << "  if (other instanceof " << tstruct->get_name() << ") {" << endl;
-  indent(out) << "    return equals((" << tstruct->get_name() << ")other);" << endl;
-  indent(out) << "  } else {" << endl;
-  indent(out) << "    return false;" << endl;
-  indent(out) << "  }" << endl;
-  indent(out) << "}" << endl;
-
-  out << endl;
-
-  indent(out) << "public boolean equals(" << tstruct->get_name() << " other) {" << endl;
-  indent(out) << "  return other != null && getSetField() == other.getSetField() && getFieldValue().equals(other.getFieldValue());" << endl;
-  indent(out) << "}" << endl;
-  out << endl;
-
-  indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl;
-  indent(out) << "  int lastComparison = TBaseHelper.compareTo(getSetField(), other.getSetField());" << endl;
-  indent(out) << "  if (lastComparison == 0) {" << endl;
-  indent(out) << "    return TBaseHelper.compareTo(getFieldValue(), other.getFieldValue());" << endl;
-  indent(out) << "  }" << endl;
-  indent(out) << "  return lastComparison;" << endl;
-  indent(out) << "}" << endl;
-  out << endl;
-}
-
-void t_javame_generator::generate_union_hashcode(ofstream& out, t_struct* tstruct) {
-  (void) tstruct;
-  indent(out) << "/**" << endl;
-  indent(out) << " * If you'd like this to perform more respectably, use the hashcode generator option." << endl;
-  indent(out) << " */" << endl;
-  indent(out) << "public int hashCode() {" << endl;
-  indent(out) << "  return 0;" << endl;
-  indent(out) << "}" << endl;
-}
-
-/**
- * Java struct definition. This has various parameters, as it could be
- * generated standalone or inside another class as a helper. If it
- * is a helper than it is a static class.
- *
- * @param tstruct      The struct definition
- * @param is_exception Is this an exception?
- * @param in_class     If inside a class, needs to be static class
- * @param is_result    If this is a result it needs a different writer
- */
-void t_javame_generator::generate_java_struct_definition(ofstream &out,
-                                                       t_struct* tstruct,
-                                                       bool is_exception,
-                                                       bool in_class,
-                                                       bool is_result) {
-  generate_java_doc(out, tstruct);
-
-  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
-
-  indent(out) <<
-    "public " << (is_final ? "final " : "") <<
-     (in_class ? "static " : "") << "class " << tstruct->get_name() << " ";
-
-  if (is_exception) {
-    out << "extends Exception ";
-  }
-  out << "implements TBase ";
-
-  scope_up(out);
-
-  generate_struct_desc(out, tstruct);
-
-  // Members are public for -java, private for -javabean
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  out << endl;
-
-  generate_field_descs(out, tstruct);
-
-  out << endl;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    indent(out) << "private ";
-    out << declare_field(*m_iter, false) << endl;
-  }
-
-  // isset data
-  if (members.size() > 0) {
-    out << endl;
-
-    indent(out) << "// isset id assignments" << endl;
-
-    int i = 0;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if (!type_can_be_null((*m_iter)->get_type())) {
-        indent(out) << "private static final int " << isset_field_id(*m_iter)
-          << " = " << i << ";" <<  endl;
-        i++;
-      }
-    }
-
-    if (i > 0) {
-      indent(out) << "private boolean[] __isset_vector = new boolean[" << i << "];" << endl;
-    }
-
-    out << endl;
-  }
-
-  bool all_optional_members = true;
-
-  // Default constructor
-  indent(out) <<
-    "public " << tstruct->get_name() << "() {" << endl;
-  indent_up();
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* t = get_true_type((*m_iter)->get_type());
-    if ((*m_iter)->get_value() != NULL) {
-      print_const_value(out, "this." + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true);
-    }
-    if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
-      all_optional_members = false;
-    }
-  }
-  indent_down();
-  indent(out) << "}" << endl << endl;
-
-  if (!members.empty() && !all_optional_members) {
-    // Full constructor for all fields
-    indent(out) <<
-      "public " << tstruct->get_name() << "(" << endl;
-    indent_up();
-    bool first = true;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
-        if (!first) {
-          out << "," << endl;
-        }
-        first = false;
-        indent(out) << type_name((*m_iter)->get_type()) << " " <<
-          (*m_iter)->get_name();
-      }
-    }
-    out << ")" << endl;
-    indent_down();
-    indent(out) << "{" << endl;
-    indent_up();
-    indent(out) << "this();" << endl;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
-        indent(out) << "this." << (*m_iter)->get_name() << " = " <<
-          (*m_iter)->get_name() << ";" << endl;
-        generate_isset_set(out, (*m_iter));
-      }
-    }
-    indent_down();
-    indent(out) << "}" << endl << endl;
-  }
-
-  // copy constructor
-  indent(out) << "/**" << endl;
-  indent(out) << " * Performs a deep copy on <i>other</i>." << endl;
-  indent(out) << " */" << endl;
-  indent(out) << "public " << tstruct->get_name() << "(" << tstruct->get_name() << " other) {" << endl;
-  indent_up();
-
-  if (has_bit_vector(tstruct)) {
-    indent(out) << "System.arraycopy(other.__isset_vector, 0, __isset_vector, 0, other.__isset_vector.length);" << endl;
-  }
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = (*m_iter);
-    std::string field_name = field->get_name();
-    t_type* type = field->get_type();
-    bool can_be_null = type_can_be_null(type);
-
-    if (can_be_null) {
-      indent(out) << "if (other." << generate_isset_check(field) << ") {" << endl;
-      indent_up();
-    }
-
-    if (type->is_container()) {
-      generate_deep_copy_container(out, "other", field_name, "__this__" + field_name, type);
-      indent(out) << "this." << field_name << " = __this__" << field_name << ";" << endl;
-    } else {
-      indent(out) << "this." << field_name << " = ";
-      generate_deep_copy_non_container(out, "other." + field_name, field_name, type);
-      out << ";" << endl;
-    }
-
-    if (can_be_null) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-  }
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-
-  // clone method, so that you can deep copy an object when you don't know its class.
-  indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl;
-  indent(out) << "  return new " << tstruct->get_name() << "(this);" << endl;
-  indent(out) << "}" << endl << endl;
-
-  generate_java_struct_clear(out, tstruct);
-
-  generate_java_bean_boilerplate(out, tstruct);
-  generate_generic_field_getters_setters(out, tstruct);
-
-  generate_java_struct_equality(out, tstruct);
-  generate_java_struct_compare_to(out, tstruct);
-
-  generate_java_struct_reader(out, tstruct);
-  if (is_result) {
-    generate_java_struct_result_writer(out, tstruct);
-  } else {
-    generate_java_struct_writer(out, tstruct);
-  }
-  generate_java_struct_tostring(out, tstruct);
-  generate_java_validator(out, tstruct);
-  scope_down(out);
-  out << endl;
-}
-
-/**
- * Generates equals methods and a hashCode method for a structure.
- *
- * @param tstruct The struct definition
- */
-void t_javame_generator::generate_java_struct_equality(ofstream& out,
-                                                     t_struct* tstruct) {
-  out << indent() << "public boolean equals(Object that) {" << endl;
-  indent_up();
-  out <<
-    indent() << "if (that == null)" << endl <<
-    indent() << "  return false;" << endl <<
-    indent() << "if (that instanceof " << tstruct->get_name() << ")" << endl <<
-    indent() << "  return this.equals((" << tstruct->get_name() << ")that);" << endl <<
-    indent() << "return false;" << endl;
-  scope_down(out);
-  out << endl;
-
-  out <<
-    indent() << "public boolean equals(" << tstruct->get_name() << " that) {" << endl;
-  indent_up();
-  out <<
-    indent() << "if (that == null)" << endl <<
-    indent() << "  return false;" << endl;
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    out << endl;
-
-    t_type* t = get_true_type((*m_iter)->get_type());
-    // Most existing Thrift code does not use isset or optional/required,
-    // so we treat "default" fields as required.
-    bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
-    bool can_be_null = type_can_be_null(t);
-    string name = (*m_iter)->get_name();
-
-    string this_present = "true";
-    string that_present = "true";
-    string unequal;
-
-    if (is_optional || can_be_null) {
-      this_present += " && this." + generate_isset_check(*m_iter);
-      that_present += " && that." + generate_isset_check(*m_iter);
-    }
-
-    out <<
-      indent() << "boolean this_present_" << name << " = "
-               << this_present << ";" << endl <<
-      indent() << "boolean that_present_" << name << " = "
-               << that_present << ";" << endl <<
-      indent() << "if (" << "this_present_" << name
-               << " || that_present_" << name << ") {" << endl;
-    indent_up();
-    out <<
-      indent() << "if (!(" << "this_present_" << name
-               << " && that_present_" << name << "))" << endl <<
-      indent() << "  return false;" << endl;
-
-    if (t->is_base_type() && ((t_base_type*)t)->is_binary()) {
-      unequal = "TBaseHelper.compareTo(this." + name + ", that." +
-	name + ") != 0";
-    } else if (can_be_null) {
-      unequal = "!this." + name + ".equals(that." + name + ")";
-    } else {
-      unequal = "this." + name + " != that." + name;
-    }
-
-    out <<
-      indent() << "if (" << unequal << ")" << endl <<
-      indent() << "  return false;" << endl;
-
-    scope_down(out);
-  }
-  out << endl;
-  indent(out) << "return true;" << endl;
-  scope_down(out);
-  out << endl;
-
-  out << indent() << "public int hashCode() {" << endl;
-  indent_up();
-  indent(out) << "return 0;" << endl;
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-void t_javame_generator::generate_java_struct_compare_to(ofstream& out, t_struct* tstruct) {
-  indent(out) << "public int compareTo(Object otherObject) {" << endl;
-  //  indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl;
-  indent_up();
-
-  indent(out) << "if (!getClass().equals(otherObject.getClass())) {" << endl;
-  indent(out) << "  return getClass().getName().compareTo(otherObject.getClass().getName());" << endl;
-  indent(out) << "}" << endl;
-  out << endl;
-  indent(out) << type_name(tstruct) << " other = (" << type_name(tstruct) << ")otherObject;";
-
-  indent(out) << "int lastComparison = 0;" << endl;
-  out << endl;
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = *m_iter;
-    indent(out) << "lastComparison = TBaseHelper.compareTo(" << generate_isset_check(field) << ", other." << generate_isset_check(field) << ");" << endl;
-    indent(out) << "if (lastComparison != 0) {" << endl;
-    indent(out) << "  return lastComparison;" << endl;
-    indent(out) << "}" << endl;
-
-    indent(out) << "if (" << generate_isset_check(field) << ") {" << endl;
-    if (field->get_type()->is_struct() || field->get_type()->is_xception()) {
-      indent(out) << "  lastComparison = this." << field->get_name() << ".compareTo(other." << field->get_name() << ");" << endl;
-    } else {
-      indent(out) << "  lastComparison = TBaseHelper.compareTo(this." << field->get_name() << ", other." << field->get_name() << ");" << endl;
-    }
-
-    indent(out) << "  if (lastComparison != 0) {" << endl;
-    indent(out) << "    return lastComparison;" << endl;
-    indent(out) << "  }" << endl;
-    indent(out) << "}" << endl;
-  }
-
-  indent(out) << "return 0;" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-/**
- * Generates a function to read all the fields of the struct.
- *
- * @param tstruct The struct definition
- */
-void t_javame_generator::generate_java_struct_reader(ofstream& out,
-                                                   t_struct* tstruct) {
-  out <<
-    indent() << "public void read(TProtocol iprot) throws TException {" << endl;
-  indent_up();
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  // Declare stack tmp variables and read struct header
-  out <<
-    indent() << "TField field;" << endl <<
-    indent() << "iprot.readStructBegin();" << endl;
-
-  // Loop over reading in fields
-  indent(out) <<
-    "while (true)" << endl;
-    scope_up(out);
-
-    // Read beginning field marker
-    indent(out) <<
-      "field = iprot.readFieldBegin();" << endl;
-
-    // Check for field STOP marker and break
-    indent(out) <<
-      "if (field.type == TType.STOP) { " << endl;
-    indent_up();
-    indent(out) <<
-      "break;" << endl;
-    indent_down();
-    indent(out) <<
-      "}" << endl;
-
-    // Switch statement on the field we are reading
-    indent(out) << "switch (field.id) {" << endl;
-
-    indent_up();
-
-    // Generate deserialization code for known cases
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      indent(out) <<
-        "case " << (*f_iter)->get_key() << ": // " << constant_name((*f_iter)->get_name()) << endl;
-      indent_up();
-      indent(out) <<
-        "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
-      indent_up();
-
-      generate_deserialize_field(out, *f_iter, "this.");
-      generate_isset_set(out, *f_iter);
-      indent_down();
-      out <<
-        indent() << "} else { " << endl <<
-        indent() << "  TProtocolUtil.skip(iprot, field.type);" << endl <<
-        indent() << "}" << endl <<
-        indent() << "break;" << endl;
-      indent_down();
-    }
-
-    indent(out) << "default:" << endl;
-    indent(out) << "  TProtocolUtil.skip(iprot, field.type);" << endl;
-
-    indent_down();
-    indent(out) << "}" << endl;
-
-    // Read field end marker
-    indent(out) <<
-      "iprot.readFieldEnd();" << endl;
-
-    indent_down();
-    indent(out) << "}" << endl;
-
-    out <<
-      indent() << "iprot.readStructEnd();" << endl;
-
-    // performs various checks (e.g. check that all required fields are set)
-    indent(out) << "validate();" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-// generates java method to perform various checks
-// (e.g. check that all required fields are set)
-void t_javame_generator::generate_java_validator(ofstream& out,
-                                                   t_struct* tstruct){
-  indent(out) << "public void validate() throws TException {" << endl;
-  indent_up();
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  out << indent() << "// check for required fields" << endl;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
-      out <<
-        indent() << "if (!" << generate_isset_check(*f_iter) << ") {" << endl <<
-        indent() << "  throw new TProtocolException(\"Required field '" << (*f_iter)->get_name() << "' is unset! Struct:\" + toString());" << endl <<
-        indent() << "}" << endl << endl;
-    }
-  }
-
-  indent_down();
-  indent(out) << "}" << endl << endl;
-}
-
-/**
- * Generates a function to write all the fields of the struct
- *
- * @param tstruct The struct definition
- */
-void t_javame_generator::generate_java_struct_writer(ofstream& out,
-                                                   t_struct* tstruct) {
-  out <<
-    indent() << "public void write(TProtocol oprot) throws TException {" << endl;
-  indent_up();
-
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  // performs various checks (e.g. check that all required fields are set)
-  indent(out) << "validate();" << endl << endl;
-
-  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    bool null_allowed = type_can_be_null((*f_iter)->get_type());
-    if (null_allowed) {
-      out <<
-        indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
-      indent_up();
-    }
-    bool optional = (*f_iter)->get_req() == t_field::T_OPTIONAL;
-    if (optional) {
-      indent(out) << "if (" << generate_isset_check((*f_iter)) << ") {" << endl;
-      indent_up();
-    }
-
-    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl;
-
-    // Write field contents
-    generate_serialize_field(out, *f_iter, "this.");
-
-    // Write field closer
-    indent(out) <<
-      "oprot.writeFieldEnd();" << endl;
-
-    if (optional) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    if (null_allowed) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-  }
-  // Write the struct map
-  out <<
-    indent() << "oprot.writeFieldStop();" << endl <<
-    indent() << "oprot.writeStructEnd();" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-/**
- * Generates a function to write all the fields of the struct,
- * which is a function result. These fields are only written
- * if they are set in the Isset array, and only one of them
- * can be set at a time.
- *
- * @param tstruct The struct definition
- */
-void t_javame_generator::generate_java_struct_result_writer(ofstream& out,
-                                                          t_struct* tstruct) {
-  out <<
-    indent() << "public void write(TProtocol oprot) throws TException {" << endl;
-  indent_up();
-
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
-
-  bool first = true;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (first) {
-      first = false;
-      out <<
-        endl <<
-        indent() << "if ";
-    } else {
-      out << " else if ";
-    }
-
-    out << "(this." << generate_isset_check(*f_iter) << ") {" << endl;
-
-    indent_up();
-    
-    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) << "_FIELD_DESC);" << endl;
-
-    // Write field contents
-    generate_serialize_field(out, *f_iter, "this.");
-
-    // Write field closer
-    indent(out) <<
-      "oprot.writeFieldEnd();" << endl;
-
-    indent_down();
-    indent(out) << "}";
-  }
-  // Write the struct map
-  out <<
-    endl <<
-    indent() << "oprot.writeFieldStop();" << endl <<
-    indent() << "oprot.writeStructEnd();" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-void t_javame_generator::generate_reflection_getters(ostringstream& out, t_type* type, string field_name, string cap_name) {
-  indent(out) << "case " << constant_name(field_name) << ":" << endl;
-  indent_up();
-
-  if (type->is_base_type() && !type->is_string()) {
-    t_base_type* base_type = (t_base_type*)type;
-
-    indent(out) << "return new " << type_name(type, true, false) << "(" << (base_type->is_bool() ? "is" : "get") << cap_name << "());" << endl << endl;
-  } else {
-    indent(out) << "return get" << cap_name << "();" << endl << endl;
-  }
-
-  indent_down();
-}
-
-void t_javame_generator::generate_reflection_setters(ostringstream& out, t_type* type, string field_name, string cap_name) {
-  indent(out) << "case " << constant_name(field_name) << ":" << endl;
-  indent_up();
-  indent(out) << "if (value == null) {" << endl;
-  indent(out) << "  unset" << get_cap_name(field_name) << "();" << endl;
-  indent(out) << "} else {" << endl;
-  indent(out) << "  set" << cap_name << "((" << type_name(type, true, false) << ")value);" << endl;
-  indent(out) << "}" << endl;
-  indent(out) << "break;" << endl << endl;
-
-  indent_down();
-}
-
-void t_javame_generator::generate_generic_field_getters_setters(std::ofstream& out, t_struct* tstruct) {
-  (void) out;
-  std::ostringstream getter_stream;
-  std::ostringstream setter_stream;
-
-  // build up the bodies of both the getter and setter at once
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = *f_iter;
-    t_type* type = get_true_type(field->get_type());
-    std::string field_name = field->get_name();
-    std::string cap_name = get_cap_name(field_name);
-
-    indent_up();
-    generate_reflection_setters(setter_stream, type, field_name, cap_name);
-    generate_reflection_getters(getter_stream, type, field_name, cap_name);
-    indent_down();
-  }
-
-}
-
-/**
- * Generates a set of Java Bean boilerplate functions (setters, getters, etc.)
- * for the given struct.
- *
- * @param tstruct The struct definition
- */
-void t_javame_generator::generate_java_bean_boilerplate(ofstream& out,
-                                                      t_struct* tstruct) {
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = *f_iter;
-    t_type* type = get_true_type(field->get_type());
-    std::string field_name = field->get_name();
-    std::string cap_name = get_cap_name(field_name);
-
-    if (type->is_container()) {
-      // Method to return the size of the collection
-      indent(out) << "public int get" << cap_name;
-      out << get_cap_name("size() {") << endl;
-
-      indent_up();
-      indent(out) << "return (this." << field_name << " == null) ? 0 : " <<
-        "this." << field_name << ".size();" << endl;
-      indent_down();
-      indent(out) << "}" << endl << endl;
-    }
-
-    if (type->is_set() || type->is_list()) {
-
-      t_type* element_type;
-      if (type->is_set()) {
-        element_type = ((t_set*)type)->get_elem_type();
-      } else {
-        element_type = ((t_list*)type)->get_elem_type();
-      }
-
-      // Iterator getter for sets and lists
-      indent(out) << "public Enumeration get" << cap_name;
-      out << get_cap_name("Enumeration() {") << endl;
-
-      indent_up();
-      indent(out) << "return (this." << field_name << " == null) ? null : " <<
-        "this." << field_name << ".elements();" << endl;
-      indent_down();
-      indent(out) << "}" << endl << endl;
-
-      // Add to set or list, create if the set/list is null
-      indent(out);
-      out << "public void add" << get_cap_name("to");
-      out << cap_name << "(" << type_name(element_type) << " elem) {" << endl;
-
-      indent_up();
-      indent(out) << "if (this." << field_name << " == null) {" << endl;
-      indent_up();
-      indent(out) << "this." << field_name << " = new " << type_name(type, false, true) <<
-        "();" << endl;
-      indent_down();
-      indent(out) << "}" << endl;
-      if (type->is_set()) {
-	indent(out) << "this." << field_name << ".put(" <<
-	  box_type(element_type, "elem") << ", " <<
-	  box_type(element_type, "elem") << ");" << endl;
-      } else {
-	indent(out) << "this." << field_name << ".addElement(" <<
-	  box_type(element_type, "elem") << ");" << endl;
-      }
-      indent_down();
-      indent(out) << "}" << endl << endl;
-
-    } else if (type->is_map()) {
-      // Put to map
-      t_type* key_type = ((t_map*)type)->get_key_type();
-      t_type* val_type = ((t_map*)type)->get_val_type();
-
-      indent(out);
-      out << "public void putTo"
-	  << cap_name << "(" << type_name(key_type, true) << " key, "
-	  << type_name(val_type, true) << " val) {" << endl;
-
-      indent_up();
-      indent(out) << "if (this." << field_name << " == null) {" << endl;
-      indent_up();
-      indent(out) << "this." << field_name << " = new " <<
-        type_name(type, false, true) << "();" << endl;
-      indent_down();
-      indent(out) << "}" << endl;
-      indent(out) << "this." << field_name << ".put(key, val);" << endl;
-      indent_down();
-      indent(out) << "}" << endl << endl;
-    }
-
-    // Simple getter
-    generate_java_doc(out, field);
-    indent(out) << "public " << type_name(type);
-    if (type->is_base_type() &&
-        ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) {
-      out << " is";
-    } else {
-      out << " get";
-    }
-    out << cap_name << "() {" << endl;
-    indent_up();
-    indent(out) << "return this." << field_name << ";" << endl;
-    indent_down();
-    indent(out) << "}" << endl << endl;
-
-    // Simple setter
-    generate_java_doc(out, field);
-    indent(out) << "public ";
-    out << "void";
-    out << " set" << cap_name << "(" << type_name(type) << " " << field_name << ") {" << endl;
-    indent_up();
-    indent(out) << "this." << field_name << " = " << field_name << ";" <<
-      endl;
-    generate_isset_set(out, field);
-
-    indent_down();
-    indent(out) << "}" << endl << endl;
-
-    // Unsetter
-    indent(out) << "public void unset" << cap_name << "() {" << endl;
-    indent_up();
-    if (type_can_be_null(type)) {
-      indent(out) << "this." << field_name << " = null;" << endl;
-    } else {
-      indent(out) << "__isset_vector[" << isset_field_id(field) << "] = false;" << endl;
-    }
-    indent_down();
-    indent(out) << "}" << endl << endl;
-
-    // isSet method
-    indent(out) << "/** Returns true if field " << field_name << " is set (has been assigned a value) and false otherwise */" << endl;
-    indent(out) << "public boolean is" << get_cap_name("set") << cap_name << "() {" << endl;
-    indent_up();
-    if (type_can_be_null(type)) {
-      indent(out) << "return this." << field_name << " != null;" << endl;
-    } else {
-      indent(out) << "return __isset_vector[" << isset_field_id(field) << "];" << endl;
-    }
-    indent_down();
-    indent(out) << "}" << endl << endl;
-
-    indent(out) << "public void set" << cap_name << get_cap_name("isSet") << "(boolean value) {" << endl;
-    indent_up();
-    if (type_can_be_null(type)) {
-      indent(out) << "if (!value) {" << endl;
-      indent(out) << "  this." << field_name << " = null;" << endl;
-      indent(out) << "}" << endl;
-    } else {
-      indent(out) << "__isset_vector[" << isset_field_id(field) << "] = value;" << endl;
-    }
-    indent_down();
-    indent(out) << "}" << endl << endl; 
-  }
-}
-
-/**
- * Generates a toString() method for the given struct
- *
- * @param tstruct The struct definition
- */
-void t_javame_generator::generate_java_struct_tostring(ofstream& out,
-                                                     t_struct* tstruct) {
-  out << indent() << "public String toString() {" << endl;
-  indent_up();
-
-  out <<
-    indent() << "StringBuffer sb = new StringBuffer(\"" << tstruct->get_name() << "(\");" << endl;
-  out << indent() << "boolean first = true;" << endl << endl;
-
-  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) {
-    bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
-    if(could_be_unset) {
-      indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl;
-      indent_up();
-    }
-
-    t_field* field = (*f_iter);
-
-    if (!first) {
-      indent(out) << "if (!first) sb.append(\", \");" << endl;
-    }
-    indent(out) << "sb.append(\"" << (*f_iter)->get_name() << ":\");" << endl;
-    bool can_be_null = type_can_be_null(field->get_type());
-    if (can_be_null) {
-      indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl;
-      indent(out) << "  sb.append(\"null\");" << endl;
-      indent(out) << "} else {" << endl;
-      indent_up();
-    }
-    
-    if (field->get_type()->is_base_type() && ((t_base_type*)(field->get_type()))->is_binary()) {
-      indent(out) << "TBaseHelper.toString(this." << field->get_name() << ", sb);" << endl;
-    } else {
-      indent(out) << "sb.append(this." << (*f_iter)->get_name() << ");" << endl;
-    }
-    
-    if (can_be_null) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    indent(out) << "first = false;" << endl;
-
-    if(could_be_unset) {
-      indent_down();
-      indent(out) << "}" << endl;
-    }
-    first = false;
-  }
-  out <<
-    indent() << "sb.append(\")\");" << endl <<
-    indent() << "return sb.toString();" << endl;
-
-  indent_down();
-  indent(out) << "}" << endl <<
-    endl;
-}
-
-/** 
- * Returns a string with the java representation of the given thrift type
- * (e.g. for the type struct it returns "TType.STRUCT")
- */
-std::string t_javame_generator::get_java_type_string(t_type* type) {
-  if (type->is_list()){
-    return "TType.LIST";
-  } else if (type->is_map()) {
-    return "TType.MAP";
-  } else if (type->is_set()) {
-    return "TType.SET";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "TType.STRUCT";
-  } else if (type->is_enum()) {
-    return "TType.ENUM";
-  } else if (type->is_typedef()) {
-    return get_java_type_string(((t_typedef*)type)->get_type());
-  } else if (type->is_base_type()) {
-    switch (((t_base_type*)type)->get_base()) {
-      case t_base_type::TYPE_VOID   : return      "TType.VOID"; break;
-      case t_base_type::TYPE_STRING : return    "TType.STRING"; break;
-      case t_base_type::TYPE_BOOL   : return      "TType.BOOL"; break;
-      case t_base_type::TYPE_BYTE   : return      "TType.BYTE"; break;
-      case t_base_type::TYPE_I16    : return       "TType.I16"; break;
-      case t_base_type::TYPE_I32    : return       "TType.I32"; break;
-      case t_base_type::TYPE_I64    : return       "TType.I64"; break;
-      case t_base_type::TYPE_DOUBLE : return    "TType.DOUBLE"; break;
-      default : throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_javame_generator::get_java_type_string!"); break; // This should never happen!
-    }
-  } else {
-    throw std::runtime_error("Unknown thrift type \"" + type->get_name() + "\" passed to t_javame_generator::get_java_type_string!"); // This should never happen!
-  }
-}
-
-void t_javame_generator::generate_field_value_meta_data(std::ofstream& out, t_type* type){
-  out << endl;
-  indent_up();
-  indent_up();
-  if (type->is_struct()){
-    indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type) << ".class";
-  } else if (type->is_container()){
-    if (type->is_list()){
-      indent(out) << "new ListMetaData(TType.LIST, ";
-      t_type* elem_type = ((t_list*)type)->get_elem_type();    
-      generate_field_value_meta_data(out, elem_type);   
-    } else if (type->is_set()){
-      indent(out) << "new SetMetaData(TType.SET, ";
-      t_type* elem_type = ((t_list*)type)->get_elem_type();    
-      generate_field_value_meta_data(out, elem_type); 
-    } else{ // map
-      indent(out) << "new MapMetaData(TType.MAP, ";
-      t_type* key_type = ((t_map*)type)->get_key_type();
-      t_type* val_type = ((t_map*)type)->get_val_type();
-      generate_field_value_meta_data(out, key_type);
-      out << ", ";
-      generate_field_value_meta_data(out, val_type);
-    }
-  } else if (type->is_enum()) {
-    indent(out) << "new EnumMetaData(TType.ENUM, " << type_name(type) << ".class";
-  } else {
-    indent(out) << "new FieldValueMetaData(" << get_java_type_string(type);
-    if (type->is_typedef()) {
-      indent(out) << ", \"" << ((t_typedef*)type)->get_symbolic() << "\"";
-    }
-  }
-  out << ")";
-  indent_down();
-  indent_down();
-}
-
-
-/**
- * Generates a thrift service. In C++, this comprises an entirely separate
- * header and source file. The header file defines the methods and includes
- * the data types defined in the main header file, and the implementation
- * file contains implementations of the basic printer and default interfaces.
- *
- * @param tservice The service definition
- */
-void t_javame_generator::generate_service(t_service* tservice) {
-  // Make output file
-  string f_service_name = package_dir_+"/"+service_name_+".java";
-  f_service_.open(f_service_name.c_str());
-
-  f_service_ <<
-    autogen_comment() <<
-    java_package() <<
-    java_type_imports() <<
-    java_thrift_imports();
-
-  f_service_ <<
-    "public class " << service_name_ << " {" << endl <<
-    endl;
-  indent_up();
-
-  // Generate the three main parts of the service
-  generate_service_interface(tservice);
-  generate_service_client(tservice);
-  generate_service_server(tservice);
-  generate_service_helpers(tservice);
-
-  indent_down();
-  f_service_ <<
-    "}" << endl;
-  f_service_.close();
-}
-
-/**
- * Generates a service interface definition.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_javame_generator::generate_primitive_service_interface(t_service* tservice) {
-  f_service_ << indent() << "public interface Iface extends " <<
-    service_name_ << "Iface { }" << endl << endl;
-
-  string f_interface_name = package_dir_ + "/" + service_name_ + "Iface.java";
-  std::ofstream f_iface;
-  f_iface.open(f_interface_name.c_str());
-
-  string extends_iface = "";
-  if (tservice->get_extends() != NULL) {
-    extends_iface = " extends " + type_name(tservice->get_extends()) + "Iface";
-  }
-  
-  f_iface <<
-    autogen_comment() <<
-    java_package() <<
-    java_type_imports() <<
-    java_thrift_imports();
-  generate_java_doc(f_iface, tservice);
-  f_iface <<
-    "public interface " << service_name_ << "Iface" << extends_iface << " {" << endl << endl;
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_java_doc(f_iface, *f_iter);
-    f_iface << "  public " << function_signature(*f_iter) << ";" << endl << endl;
-  }
-  f_iface << "}" << endl << endl;
-}
-
-/**
- * Generates a service interface definition.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_javame_generator::generate_service_interface(t_service* tservice) {
-  string extends = "";
-  string extends_iface = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_iface = " extends " + extends + ".Iface";
-  }
-
-  generate_java_doc(f_service_, tservice);
-  f_service_ << indent() << "public interface Iface" << extends_iface <<
-    " {" << endl << endl;
-  indent_up();
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_java_doc(f_service_, *f_iter);
-    indent(f_service_) << "public " << function_signature(*f_iter) << ";" << endl << endl;
-  }
-  indent_down();
-  f_service_ << indent() << "}" << endl << endl;
-}
-
-/**
- * Generates structs for all the service args and return types
- *
- * @param tservice The service
- */
-void t_javame_generator::generate_service_helpers(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    t_struct* ts = (*f_iter)->get_arglist();
-    generate_java_struct_definition(f_service_, ts, false, true);
-    generate_function_helpers(*f_iter);
-  }
-}
-
-/**
- * Generates a service client definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_javame_generator::generate_service_client(t_service* tservice) {
-  string extends = "";
-  string extends_client = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_client = " extends " + extends + ".Client";
-  }
-
-  indent(f_service_) <<
-    "public static class Client" << extends_client << " implements TServiceClient, Iface {" << endl;
-  indent_up();
-
-  indent(f_service_) <<
-    "public Client(TProtocol prot)" << endl;
-  scope_up(f_service_);
-  indent(f_service_) <<
-    "this(prot, prot);" << endl;
-  scope_down(f_service_);
-  f_service_ << endl;
-
-  indent(f_service_) <<
-    "public Client(TProtocol iprot, TProtocol oprot)" << endl;
-  scope_up(f_service_);
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "iprot_ = iprot;" << endl <<
-      indent() << "oprot_ = oprot;" << endl;
-  } else {
-    f_service_ <<
-      indent() << "super(iprot, oprot);" << endl;
-  }
-  scope_down(f_service_);
-  f_service_ << endl;
-
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "protected TProtocol iprot_;"  << endl <<
-      indent() << "protected TProtocol oprot_;"  << endl <<
-      endl <<
-      indent() << "protected int seqid_;" << endl <<
-      endl;
-
-    indent(f_service_) <<
-      "public TProtocol getInputProtocol()" << endl;
-    scope_up(f_service_);
-    indent(f_service_) <<
-      "return this.iprot_;" << endl;
-    scope_down(f_service_);
-    f_service_ << endl;
-
-    indent(f_service_) <<
-      "public TProtocol getOutputProtocol()" << endl;
-    scope_up(f_service_);
-    indent(f_service_) <<
-      "return this.oprot_;" << endl;
-    scope_down(f_service_);
-    f_service_ << 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) {
-    string funname = (*f_iter)->get_name();
-
-    // Open function
-    indent(f_service_) <<
-      "public " << function_signature(*f_iter) << endl;
-    scope_up(f_service_);
-    indent(f_service_) <<
-      "send_" << funname << "(";
-
-    // Get the struct of function call params
-    t_struct* arg_struct = (*f_iter)->get_arglist();
-
-    // Declare the function arguments
-    const vector<t_field*>& fields = arg_struct->get_members();
-    vector<t_field*>::const_iterator fld_iter;
-    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;
-
-    if (!(*f_iter)->is_oneway()) {
-      f_service_ << indent();
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_ << "return ";
-      }
-      f_service_ <<
-        "recv_" << funname << "();" << endl;
-    }
-    scope_down(f_service_);
-    f_service_ << endl;
-
-    t_function send_function(g_type_void,
-                             string("send_") + (*f_iter)->get_name(),
-                             (*f_iter)->get_arglist());
-
-    string argsname = (*f_iter)->get_name() + "_args";
-
-    // Open function
-    indent(f_service_) <<
-      "public " << function_signature(&send_function) << endl;
-    scope_up(f_service_);
-
-    // Serialize the request
-    f_service_ <<
-      indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", TMessageType.CALL, ++seqid_));" << endl <<
-      indent() << argsname << " args = new " << argsname << "();" << endl;
-
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      f_service_ <<
-        indent() << "args.set" << get_cap_name((*fld_iter)->get_name()) << "(" << (*fld_iter)->get_name() << ");" << endl;
-    }
-
-    f_service_ <<
-      indent() << "args.write(oprot_);" << endl <<
-      indent() << "oprot_.writeMessageEnd();" << endl <<
-      indent() << "oprot_.getTransport().flush();" << endl;
-
-    scope_down(f_service_);
-    f_service_ << endl;
-
-    if (!(*f_iter)->is_oneway()) {
-      string resultname = (*f_iter)->get_name() + "_result";
-
-      t_struct noargs(program_);
-      t_function recv_function((*f_iter)->get_returntype(),
-                               string("recv_") + (*f_iter)->get_name(),
-                               &noargs,
-                               (*f_iter)->get_xceptions());
-      // Open function
-      indent(f_service_) <<
-        "public " << function_signature(&recv_function) << endl;
-      scope_up(f_service_);
-
-      f_service_ <<
-        indent() << "TMessage msg = iprot_.readMessageBegin();" << endl <<
-        indent() << "if (msg.type == TMessageType.EXCEPTION) {" << endl <<
-        indent() << "  TApplicationException x = TApplicationException.read(iprot_);" << endl <<
-        indent() << "  iprot_.readMessageEnd();" << endl <<
-        indent() << "  throw x;" << endl <<
-        indent() << "}" << endl <<
-        indent() << "if (msg.seqid != seqid_) {" << endl <<
-        indent() << "  throw new TApplicationException(TApplicationException.BAD_SEQUENCE_ID, \"" << (*f_iter)->get_name() << " failed: out of sequence response\");" << endl <<
-        indent() << "}" << endl <<
-        indent() << resultname << " result = new " << resultname << "();" << endl <<
-        indent() << "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() << "if (result." << generate_isset_check("success") << ") {" << endl <<
-          indent() << "  return result.success;" << endl <<
-          indent() << "}" << 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." << (*x_iter)->get_name() << " != null) {" << endl <<
-          indent() << "  throw result." << (*x_iter)->get_name() << ";" << endl <<
-          indent() << "}" << endl;
-      }
-
-      // If you get here it's an exception, unless a void function
-      if ((*f_iter)->get_returntype()->is_void()) {
-        indent(f_service_) <<
-          "return;" << endl;
-      } else {
-        f_service_ <<
-          indent() << "throw new TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
-      }
-
-      // Close function
-      scope_down(f_service_);
-      f_service_ << endl;
-    }
-  }
-
-  indent_down();
-  indent(f_service_) <<
-    "}" << endl;
-}
-
-/**
- * Generates a service server definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_javame_generator::generate_service_server(t_service* tservice) {
-  // Generate the dispatch methods
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  // Extends stuff
-  string extends = "";
-  string extends_processor = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_processor = " extends " + extends + ".Processor";
-  }
-
-  // Generate the header portion
-  indent(f_service_) <<
-    "public static class Processor" << extends_processor << " implements TProcessor {" << endl;
-  indent_up();
-
-  indent(f_service_) <<
-    "public Processor(Iface iface)" << endl;
-  scope_up(f_service_);
-  if (!extends.empty()) {
-    f_service_ <<
-      indent() << "super(iface);" << endl;
-  }
-  f_service_ <<
-    indent() << "iface_ = iface;" << endl;
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_service_ <<
-      indent() << "processMap_.put(\"" << (*f_iter)->get_name() << "\", new " << (*f_iter)->get_name() << "());" << endl;
-  }
-
-  scope_down(f_service_);
-  f_service_ << endl;
-
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "protected static interface ProcessFunction {" << endl <<
-      indent() << "  public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException;" << endl <<
-      indent() << "}" << endl <<
-      endl;
-  }
-
-  f_service_ <<
-    indent() << "private Iface iface_;" << endl;
-
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "protected final Hashtable processMap_ = new Hashtable();" << endl;
-  }
-
-  f_service_ << endl;
-
-  // Generate the server implementation
-  indent(f_service_) <<
-    "public boolean process(TProtocol iprot, TProtocol oprot) throws TException" << endl;
-  scope_up(f_service_);
-
-  f_service_ <<
-    indent() << "TMessage msg = iprot.readMessageBegin();" << endl;
-
-  // TODO(mcslee): validate message, was the seqid etc. legit?
-
-  f_service_ <<
-    indent() << "ProcessFunction fn = (ProcessFunction)processMap_.get(msg.name);" << endl <<
-    indent() << "if (fn == null) {" << endl <<
-    indent() << "  TProtocolUtil.skip(iprot, TType.STRUCT);" << endl <<
-    indent() << "  iprot.readMessageEnd();" << endl <<
-    indent() << "  TApplicationException x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, \"Invalid method name: '\"+msg.name+\"'\");" << endl <<
-    indent() << "  oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" << endl <<
-    indent() << "  x.write(oprot);" << endl <<
-    indent() << "  oprot.writeMessageEnd();" << endl <<
-    indent() << "  oprot.getTransport().flush();" << endl <<
-    indent() << "  return true;" << endl <<
-    indent() << "}" << endl <<
-    indent() << "fn.process(msg.seqid, iprot, oprot);" << endl;
-
-  f_service_ <<
-    indent() << "return true;" << endl;
-
-  scope_down(f_service_);
-  f_service_ << endl;
-
-  // Generate the process subfunctions
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_process_function(tservice, *f_iter);
-  }
-
-  indent_down();
-  indent(f_service_) <<
-    "}" << endl <<
-    endl;
-}
-
-/**
- * Generates a struct and helpers for a function.
- *
- * @param tfunction The function
- */
-void t_javame_generator::generate_function_helpers(t_function* tfunction) {
-  if (tfunction->is_oneway()) {
-    return;
-  }
-
-  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_java_struct_definition(f_service_, &result, false, true, true);
-}
-
-/**
- * Generates a process function definition.
- *
- * @param tfunction The function to write a dispatcher for
- */
-void t_javame_generator::generate_process_function(t_service* tservice,
-                                                 t_function* tfunction) {
-  (void) tservice;
-  // Open class
-  indent(f_service_) <<
-    "private class " << tfunction->get_name() << " implements ProcessFunction {" << endl;
-  indent_up();
-
-  // Open function
-  indent(f_service_) <<
-    "public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException" << endl;
-  scope_up(f_service_);
-
-  string argsname = tfunction->get_name() + "_args";
-  string resultname = tfunction->get_name() + "_result";
-
-  f_service_ <<
-    indent() << argsname << " args = new " << argsname << "();" << endl <<
-    indent() << "try {" << endl;
-  indent_up();
-  f_service_ <<
-    indent() << "args.read(iprot);" << endl;
-  indent_down();
-  f_service_ << 
-    indent() << "} catch (TProtocolException e) {" << endl;
-  indent_up();
-  f_service_ <<
-    indent() << "iprot.readMessageEnd();" << endl <<
-    indent() << "TApplicationException x = new TApplicationException(TApplicationException.PROTOCOL_ERROR, e.getMessage());" << endl <<
-    indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl <<
-    indent() << "x.write(oprot);" << endl <<
-    indent() << "oprot.writeMessageEnd();" << endl <<
-    indent() << "oprot.getTransport().flush();" << endl <<
-    indent() << "return;" << endl;
-  indent_down();
-  f_service_ << indent() << "}" << endl;
-  f_service_ <<
-    indent() << "iprot.readMessageEnd();" << endl;
-
-  t_struct* xs = tfunction->get_xceptions();
-  const std::vector<t_field*>& xceptions = xs->get_members();
-  vector<t_field*>::const_iterator x_iter;
-
-  // Declare result for non oneway function
-  if (!tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << resultname << " result = new " << resultname << "();" << endl;
-  }
-
-  // Try block for a function with exceptions
-  if (xceptions.size() > 0) {
-    f_service_ <<
-      indent() << "try {" << endl;
-    indent_up();
-  }
-
-  // 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_ << indent();
-  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
-    f_service_ << "result.success = ";
-  }
-  f_service_ <<
-    "iface_." << 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." << (*f_iter)->get_name();
-  }
-  f_service_ << ");" << endl;
-
-  // Set isset on success field
-  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void() && !type_can_be_null(tfunction->get_returntype())) {
-    f_service_ <<
-      indent() << "result.set" << get_cap_name("success") << get_cap_name("isSet") << "(true);" << endl;
-  }
-
-  if (!tfunction->is_oneway() && xceptions.size() > 0) {
-    indent_down();
-    f_service_ << indent() << "}";
-    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " " << (*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();
-        f_service_ << indent() << "}";
-      } else {
-        f_service_ << "}";
-      }
-    }
-    f_service_ << " catch (Throwable th) {" << endl;
-    indent_up();
-    f_service_ <<
-      indent() << "TApplicationException x = new TApplicationException(TApplicationException.INTERNAL_ERROR, \"Internal error processing " << tfunction->get_name() << "\");" << endl <<
-      indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl <<
-      indent() << "x.write(oprot);" << endl <<
-      indent() << "oprot.writeMessageEnd();" << endl <<
-      indent() << "oprot.getTransport().flush();" << endl <<
-      indent() << "return;" << endl;
-    indent_down();
-    f_service_ << indent() << "}" << endl;
-  }
-
-  // Shortcut out here for oneway functions
-  if (tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << "return;" << endl;
-    scope_down(f_service_);
-
-    // Close class
-    indent_down();
-    f_service_ <<
-      indent() << "}" << endl <<
-      endl;
-    return;
-  }
-
-  f_service_ <<
-    indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid));" << endl <<
-    indent() << "result.write(oprot);" << endl <<
-    indent() << "oprot.writeMessageEnd();" << endl <<
-    indent() << "oprot.getTransport().flush();" << endl;
-
-  // Close function
-  scope_down(f_service_);
-  f_service_ << endl;
-
-  // Close class
-  indent_down();
-  f_service_ <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-/**
- * Deserializes a field of any type.
- *
- * @param tfield The field
- * @param prefix The variable name or container for this field
- */
-void t_javame_generator::generate_deserialize_field(ofstream& out,
-                                                  t_field* tfield,
-                                                  string prefix) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  if (type->is_void()) {
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  string name = prefix + tfield->get_name();
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct(out,
-                                (t_struct*)type,
-                                name);
-  } else if (type->is_container()) {
-    generate_deserialize_container(out, type, name);
-  } else if (type->is_base_type()) {
-    indent(out) << name << " = iprot.";
-
-    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:
-        if (!((t_base_type*)type)->is_binary()) {
-          out << "readString();";
-        } else {
-          out << "readBinary();";
-        }
-        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 Java name for base type " + t_base_type::t_base_name(tbase);
-    }
-    out << endl;
-  } else if (type->is_enum()) {
-    indent(out) << name << " = " << type_name(tfield->get_type(), true, false) + ".findByValue(iprot.readI32());" << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
-           tfield->get_name().c_str(), type_name(type).c_str());
-  }
-}
-
-/**
- * Generates an unserializer for a struct, invokes read()
- */
-void t_javame_generator::generate_deserialize_struct(ofstream& out,
-                                                   t_struct* tstruct,
-                                                   string prefix) {
-  out <<
-    indent() << prefix << " = new " << type_name(tstruct) << "();" << endl <<
-    indent() << prefix << ".read(iprot);" << endl;
-}
-
-/**
- * Deserializes a container by reading its size and then iterating
- */
-void t_javame_generator::generate_deserialize_container(ofstream& out,
-                                                      t_type* ttype,
-                                                      string prefix) {
-  scope_up(out);
-
-  string obj;
-
-  if (ttype->is_map()) {
-    obj = tmp("_map");
-  } else if (ttype->is_set()) {
-    obj = tmp("_set");
-  } else if (ttype->is_list()) {
-    obj = tmp("_list");
-  }
-
-  // Declare variables, read header
-  if (ttype->is_map()) {
-    indent(out) << "TMap " << obj << " = iprot.readMapBegin();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) << "TSet " << obj << " = iprot.readSetBegin();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) << "TList " << obj << " = iprot.readListBegin();" << endl;
-  }
-
-  indent(out)
-    << prefix << " = new " << type_name(ttype, false, true)
-    // size the collection correctly
-    << "("
-    << (ttype->is_list() ? "" : "2*" )
-    << obj << ".size"
-    << ");" << endl;
-
-  // For loop iterates over elements
-  string i = tmp("_i");
-  indent(out) <<
-    "for (int " << i << " = 0; " <<
-    i << " < " << obj << ".size" << "; " <<
-    "++" << i << ")" << endl;
-
-    scope_up(out);
-
-    if (ttype->is_map()) {
-      generate_deserialize_map_element(out, (t_map*)ttype, prefix);
-    } else if (ttype->is_set()) {
-      generate_deserialize_set_element(out, (t_set*)ttype, prefix);
-    } else if (ttype->is_list()) {
-      generate_deserialize_list_element(out, (t_list*)ttype, prefix);
-    }
-
-    scope_down(out);
-
-  // Read container end
-  if (ttype->is_map()) {
-    indent(out) << "iprot.readMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) << "iprot.readSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) << "iprot.readListEnd();" << endl;
-  }
-
-  scope_down(out);
-}
-
-
-/**
- * Generates code to deserialize a map
- */
-void t_javame_generator::generate_deserialize_map_element(ofstream& out,
-                                                        t_map* tmap,
-                                                        string prefix) {
-  string key = tmp("_key");
-  string val = tmp("_val");
-  t_field fkey(tmap->get_key_type(), key);
-  t_field fval(tmap->get_val_type(), val);
-
-  indent(out) <<
-    declare_field(&fkey) << endl;
-  indent(out) <<
-    declare_field(&fval) << endl;
-
-  generate_deserialize_field(out, &fkey);
-  generate_deserialize_field(out, &fval);
-
-  indent(out) <<
-    prefix << ".put(" <<
-    box_type(tmap->get_key_type(), key) << ", " <<
-    box_type(tmap->get_val_type(), val) << ");" << endl;
-}
-
-/**
- * Deserializes a set element
- */
-void t_javame_generator::generate_deserialize_set_element(ofstream& out,
-                                                        t_set* tset,
-                                                        string prefix) {
-  string elem = tmp("_elem");
-  t_field felem(tset->get_elem_type(), elem);
-
-  indent(out) <<
-    declare_field(&felem) << endl;
-
-  generate_deserialize_field(out, &felem);
-
-  indent(out) <<
-    prefix << ".put(" <<
-    box_type(tset->get_elem_type(), elem) << ", " <<
-    box_type(tset->get_elem_type(), elem) << ");" << endl;
-}
-
-/**
- * Deserializes a list element
- */
-void t_javame_generator::generate_deserialize_list_element(ofstream& out,
-                                                         t_list* tlist,
-                                                         string prefix) {
-  string elem = tmp("_elem");
-  t_field felem(tlist->get_elem_type(), elem);
-
-  indent(out) <<
-    declare_field(&felem) << endl;
-
-  generate_deserialize_field(out, &felem);
-
-  indent(out) <<
-    prefix << ".addElement(" <<
-    box_type(tlist->get_elem_type(), elem) << ");" << endl;
-}
-
-
-/**
- * Serializes a field of any type.
- *
- * @param tfield The field to serialize
- * @param prefix Name to prepend to field name
- */
-void t_javame_generator::generate_serialize_field(ofstream& out,
-                                                t_field* tfield,
-                                                string prefix) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  // Do nothing for void types
-  if (type->is_void()) {
-    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_serialize_struct(out,
-                              (t_struct*)type,
-                              prefix + tfield->get_name());
-  } else if (type->is_container()) {
-    generate_serialize_container(out,
-                                 type,
-                                 prefix + tfield->get_name());
-  } else if (type->is_enum()){
-    indent(out) << "oprot.writeI32(" << prefix + tfield->get_name() << ".getValue());" << endl;
-  } else if (type->is_base_type()) {
-    string name = prefix + tfield->get_name();
-    indent(out) <<
-      "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:
-        if (((t_base_type*)type)->is_binary()) {
-          out << "writeBinary(" << name << ");";
-        } else {
-          out << "writeString(" << name << ");";
-        }
-        break;
-      case t_base_type::TYPE_BOOL:
-        out << "writeBool(" << name << ");";
-        break;
-      case t_base_type::TYPE_BYTE:
-        out << "writeByte(" << name << ");";
-        break;
-      case t_base_type::TYPE_I16:
-        out << "writeI16(" << name << ");";
-        break;
-      case t_base_type::TYPE_I32:
-        out << "writeI32(" << name << ");";
-        break;
-      case t_base_type::TYPE_I64:
-        out << "writeI64(" << name << ");";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        out << "writeDouble(" << name << ");";
-        break;
-      default:
-        throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      out << "writeI32(" << name << ");";
-    }
-    out << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
-           prefix.c_str(),
-           tfield->get_name().c_str(),
-           type_name(type).c_str());
-  }
-}
-
-/**
- * Serializes all the members of a struct.
- *
- * @param tstruct The struct to serialize
- * @param prefix  String prefix to attach to all fields
- */
-void t_javame_generator::generate_serialize_struct(ofstream& out,
-                                                 t_struct* tstruct,
-                                                 string prefix) {
-  (void) tstruct;
-  out <<
-    indent() << prefix << ".write(oprot);" << endl;
-}
-
-/**
- * Serializes a container by writing its size then the elements.
- *
- * @param ttype  The type of container
- * @param prefix String prefix for fields
- */
-void t_javame_generator::generate_serialize_container(ofstream& out,
-                                                    t_type* ttype,
-                                                    string prefix) {
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    indent(out) <<
-      "oprot.writeMapBegin(new TMap(" <<
-      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
-      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
-      prefix << ".size()));" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "oprot.writeSetBegin(new TSet(" <<
-      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
-      prefix << ".size()));" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "oprot.writeListBegin(new TList(" <<
-      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
-      prefix << ".size()));" << endl;
-  }
-
-  string iter = tmp("_iter");
-  if (ttype->is_map()) {
-    string enumer = iter + "_enum";
-    string key_type = type_name(((t_map*)ttype)->get_key_type(), true, false);
-    indent(out) <<
-      "for (Enumeration " << enumer << " = " << prefix << ".keys(); " << enumer << ".hasMoreElements(); ) ";
-    scope_up(out);
-    indent(out)
-      << key_type << " " << iter << " = (" << key_type << ")" << enumer << ".nextElement();" << endl;
-  } else if (ttype->is_set()) {
-    string enumer = iter + "_enum";
-    string ele_type = type_name(((t_list*)ttype)->get_elem_type(), true);
-    indent(out) <<
-      "for (Enumeration " << enumer << " = " << prefix << ".keys(); " << enumer << ".hasMoreElements(); ) ";
-    scope_up(out);
-    indent(out)
-      << ele_type << " " << iter << " = ("
-      << ele_type << ")" << enumer << ".nextElement();" << endl;
-  } else if (ttype->is_list()) {
-    string enumer = iter + "_enum";
-    indent(out) <<
-      "for (Enumeration " << enumer << " = " << prefix << ".elements(); " << enumer << ".hasMoreElements(); ) ";
-    scope_up(out);
-    string ele_type = type_name(((t_list*)ttype)->get_elem_type(), true);
-    indent(out)
-      << ele_type << " " << iter << " = ("
-      << ele_type << ")" << enumer << ".nextElement();" << endl;
-  }
-
-  if (ttype->is_map()) {
-    generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
-  } else if (ttype->is_set()) {
-    generate_serialize_set_element(out, (t_set*)ttype, iter);
-  } else if (ttype->is_list()) {
-    generate_serialize_list_element(out, (t_list*)ttype, iter);
-  }
-  scope_down(out);
-
-  if (ttype->is_map()) {
-    indent(out) <<
-      "oprot.writeMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "oprot.writeSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "oprot.writeListEnd();" << endl;
-  }
-
-  scope_down(out);
-}
-
-/**
- * Serializes the members of a map.
- */
-void t_javame_generator::generate_serialize_map_element(ofstream& out,
-                                                      t_map* tmap,
-                                                      string iter,
-                                                      string map) {
-  t_field kfield(tmap->get_key_type(), iter);
-  generate_serialize_field(out, &kfield, "");
-  string val_type = type_name(tmap->get_val_type(), true, false);
-  t_field vfield(tmap->get_val_type(), "((" + val_type + ")" + map + ".get(" + iter + "))");
-  generate_serialize_field(out, &vfield, "");
-}
-
-/**
- * Serializes the members of a set.
- */
-void t_javame_generator::generate_serialize_set_element(ofstream& out,
-                                                      t_set* tset,
-                                                      string iter) {
-  t_field efield(tset->get_elem_type(), iter);
-  generate_serialize_field(out, &efield, "");
-}
-
-/**
- * Serializes the members of a list.
- */
-void t_javame_generator::generate_serialize_list_element(ofstream& out,
-                                                       t_list* tlist,
-                                                       string iter) {
-  t_field efield(tlist->get_elem_type(), iter);
-  generate_serialize_field(out, &efield, "");
-}
-
-/**
- * Returns a Java type name
- *
- * @param ttype The type
- * @param container Is the type going inside a container?
- * @return Java type name, i.e. Vector
- */
-string t_javame_generator::type_name(t_type* ttype, bool in_container, bool in_init, bool skip_generic) {
-  (void) in_init;
-  (void) skip_generic;
-  // In Java typedefs are just resolved to their real type
-  ttype = get_true_type(ttype);
-  string prefix;
-
-  if (ttype->is_base_type()) {
-    return base_type_name((t_base_type*)ttype, in_container);
-  } else if (ttype->is_map()) {
-    return "Hashtable";
-  } else if (ttype->is_set()) {
-    return "Hashtable";
-  } else if (ttype->is_list()) {
-    return "Vector";
-  }
-
-  // Check for namespacing
-  t_program* program = ttype->get_program();
-  if (program != NULL && program != program_) {
-    string package = program->get_namespace("java");
-    if (!package.empty()) {
-      return package + "." + ttype->get_name();
-    }
-  }
-
-  return ttype->get_name();
-}
-
-/**
- * Returns the C++ type that corresponds to the thrift type.
- *
- * @param tbase The base type
- * @param container Is it going in a Java container?
- */
-string t_javame_generator::base_type_name(t_base_type* type,
-                                        bool in_container) {
-  t_base_type::t_base tbase = type->get_base();
-
-  switch (tbase) {
-  case t_base_type::TYPE_VOID:
-    return "void";
-  case t_base_type::TYPE_STRING:
-    if (!type->is_binary()) {
-      return "String";
-    } else {
-      return "byte[]";
-    }
-  case t_base_type::TYPE_BOOL:
-    return (in_container ? "Boolean" : "boolean");
-  case t_base_type::TYPE_BYTE:
-    return (in_container ? "Byte" : "byte");
-  case t_base_type::TYPE_I16:
-    return (in_container ? "Short" : "short");
-  case t_base_type::TYPE_I32:
-    return (in_container ? "Integer" : "int");
-  case t_base_type::TYPE_I64:
-    return (in_container ? "Long" : "long");
-  case t_base_type::TYPE_DOUBLE:
-    return (in_container ? "Double" : "double");
-  default:
-    throw "compiler error: no C++ name for base type " + t_base_type::t_base_name(tbase);
-  }
-}
-
-/**
- * Declares a field, which may include initialization as necessary.
- *
- * @param ttype The type
- */
-string t_javame_generator::declare_field(t_field* tfield, bool init) {
-  // TODO(mcslee): do we ever need to initialize the field?
-  string result = type_name(tfield->get_type()) + " " + tfield->get_name();
-  if (init) {
-    t_type* ttype = get_true_type(tfield->get_type());
-    if (ttype->is_base_type() && tfield->get_value() != NULL) {
-      ofstream dummy;
-      result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
-    } else if (ttype->is_base_type()) {
-      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
-      switch (tbase) {
-      case t_base_type::TYPE_VOID:
-        throw "NO T_VOID CONSTRUCT";
-      case t_base_type::TYPE_STRING:
-        result += " = null";
-        break;
-      case t_base_type::TYPE_BOOL:
-        result += " = 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:
-        result += " = 0";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        result += " = (double)0";
-        break;
-    }
-
-    } else if (ttype->is_enum()) {
-      result += " = 0";
-    } else if (ttype->is_container()) {
-      result += " = new " + type_name(ttype, false, true) + "()";
-    } else {
-      result += " = new " + type_name(ttype, false, true) + "()";;
-    }
-  }
-  return result + ";";
-}
-
-/**
- * Renders a function signature of the form 'type name(args)'
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_javame_generator::function_signature(t_function* tfunction,
-                                            string prefix) {
-  t_type* ttype = tfunction->get_returntype();
-  std::string result =
-    type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ") throws ";
-  t_struct* xs = tfunction->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) {
-    result += type_name((*x_iter)->get_type(), false, false) + ", ";
-  }
-  result += "TException";
-  return result;
-}
-
-/**
- * Renders a comma separated field list, with type names
- */
-string t_javame_generator::argument_list(t_struct* tstruct, bool include_types) {
-  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 += ", ";
-    }
-    if (include_types) {
-      result += type_name((*f_iter)->get_type()) + " ";
-    }
-    result += (*f_iter)->get_name();
-  }
-  return result;
-}
-
-/**
- * Converts the parse type to a C++ enum string for the given type.
- */
-string t_javame_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 "TType.STRING";
-    case t_base_type::TYPE_BOOL:
-      return "TType.BOOL";
-    case t_base_type::TYPE_BYTE:
-      return "TType.BYTE";
-    case t_base_type::TYPE_I16:
-      return "TType.I16";
-    case t_base_type::TYPE_I32:
-      return "TType.I32";
-    case t_base_type::TYPE_I64:
-      return "TType.I64";
-    case t_base_type::TYPE_DOUBLE:
-      return "TType.DOUBLE";
-    }
-  } else if (type->is_enum()) {
-    return "TType.I32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "TType.STRUCT";
-  } else if (type->is_map()) {
-    return "TType.MAP";
-  } else if (type->is_set()) {
-    return "TType.SET";
-  } else if (type->is_list()) {
-    return "TType.LIST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-/**
- * Applies the correct style to a string based on the value of nocamel_style_
- */
-std::string t_javame_generator::get_cap_name(std::string name){
-  name[0] = toupper(name[0]);
-  return name;
-}
-
-string t_javame_generator::constant_name(string name) {
-  string constant_name;
-
-  bool is_first = true;
-  bool was_previous_char_upper = false;
-  for (string::iterator iter = name.begin(); iter != name.end(); ++iter) {
-    string::value_type character = (*iter);
-
-    bool is_upper = isupper(character);
-
-    if (is_upper && !is_first && !was_previous_char_upper) {
-      constant_name += '_';
-    }
-    constant_name += toupper(character);
-
-    is_first = false;
-    was_previous_char_upper = is_upper;
-  }
-
-  return constant_name;
-}
-
-void t_javame_generator::generate_java_docstring_comment(ofstream &out, string contents) {
-  generate_docstring_comment(out,
-    "/**\n",
-    " * ", contents,
-    " */\n");
-}
-
-void t_javame_generator::generate_java_doc(ofstream &out,
-                                         t_field* field) {
-  if (field->get_type()->is_enum()) {
-    string combined_message = field->get_doc() + "\n@see " + get_enum_class_name(field->get_type());
-    generate_java_docstring_comment(out, combined_message);
-  } else {
-    generate_java_doc(out, (t_doc*)field);
-  }
-}
-
-/**
- * Emits a JavaDoc comment if the provided object has a doc in Thrift
- */
-void t_javame_generator::generate_java_doc(ofstream &out,
-                                         t_doc* tdoc) {
-  if (tdoc->has_doc()) {
-    generate_java_docstring_comment(out, tdoc->get_doc());
-  }
-}
-
-/**
- * Emits a JavaDoc comment if the provided function object has a doc in Thrift
- */
-void t_javame_generator::generate_java_doc(ofstream &out,
-                                         t_function* tfunction) {
-  if (tfunction->has_doc()) {
-    stringstream ss;
-    ss << tfunction->get_doc();
-    const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
-    vector<t_field*>::const_iterator p_iter;
-    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
-      t_field* p = *p_iter;
-      ss << "\n@param " << p->get_name();
-      if (p->has_doc()) {
-        ss << " " << p->get_doc();
-      }
-    }
-    generate_docstring_comment(out,
-      "/**\n",
-      " * ", ss.str(),
-      " */\n");
-  }
-}
-
-void t_javame_generator::generate_deep_copy_container(ofstream &out, std::string source_name_p1, std::string source_name_p2,
-                                                    std::string result_name, t_type* type) {
-
-  t_container* container = (t_container*)type;
-  std::string source_name;
-  if (source_name_p2 == "")
-      source_name = source_name_p1;
-  else
-      source_name = source_name_p1 + "." + source_name_p2;
-
-  indent(out) << type_name(type, true, false) << " " << result_name << " = new " << type_name(container, false, true) << "();" << endl;
-
-  std::string iterator_element_name = source_name_p1 + "_element";
-  std::string enumeration_name = source_name_p1 + "_enum";
-  std::string result_element_name = result_name + "_copy";
-
-  if(container->is_map()) {
-    t_type* key_type = ((t_map*)container)->get_key_type();
-    t_type* val_type = ((t_map*)container)->get_val_type();
-
-    indent(out) <<
-      "for (Enumeration " << enumeration_name << " = " << source_name << ".keys(); " << enumeration_name << ".hasMoreElements(); ) {" << endl;
-    indent_up();
-
-    out << endl;
-
-    indent(out) << type_name(key_type, true, false) << " " << iterator_element_name << "_key = (" << type_name(key_type, true, false) << ")" << enumeration_name << ".nextElement();" << endl;
-    indent(out) << type_name(val_type, true, false) << " " << iterator_element_name << "_value = ("
-		<< type_name(val_type, true, false) << ")" << source_name << ".get(" << iterator_element_name << "_key);" << endl;
-
-    out << endl;
-
-    if (key_type->is_container()) {
-      generate_deep_copy_container(out, iterator_element_name + "_key", "", result_element_name + "_key", key_type);
-    } else {
-      indent(out) << type_name(key_type, true, false) << " " << result_element_name << "_key = ";
-      generate_deep_copy_non_container(out, iterator_element_name + "_key", result_element_name + "_key", key_type);
-      out << ";" << endl;
-    }
-
-    out << endl;
-
-    if (val_type->is_container()) {
-      generate_deep_copy_container(out, iterator_element_name + "_value", "", result_element_name + "_value", val_type);
-    } else {
-      indent(out) << type_name(val_type, true, false) << " " << result_element_name << "_value = ";
-      generate_deep_copy_non_container(out, iterator_element_name + "_value", result_element_name + "_value", val_type);
-      out << ";" << endl;
-    }
-
-    out << endl;
-
-    indent(out) << result_name << ".put(" << result_element_name << "_key, " << result_element_name << "_value);" << endl;
-
-    indent_down();
-    indent(out) << "}" << endl;
-
-  } else {
-    t_type* elem_type;
-
-    if (container->is_set()) {
-      elem_type = ((t_set*)container)->get_elem_type();
-    } else {
-      elem_type = ((t_list*)container)->get_elem_type();
-    }
-
-    indent(out)
-      << "for (Enumeration " << enumeration_name << " = " << source_name << ".elements(); " 
-      << enumeration_name << ".hasMoreElements(); ) {" << endl;
-    indent_up();
-    indent(out)
-      << type_name(elem_type, true, false) << " " << iterator_element_name << " = ("
-      << type_name(elem_type, true, false) << ")" << enumeration_name << ".nextElement();" << endl;
-    if (elem_type->is_container()) {
-      // recursive deep copy
-      generate_deep_copy_container(out, iterator_element_name, "", result_element_name, elem_type);
-      if (elem_type->is_list()) {
-	indent(out) << result_name << ".addElement(" << result_element_name << ");" << endl;
-      } else {
-	indent(out) << result_name << ".put(" << result_element_name << ", " << result_element_name << ");" << endl;
-      }
-    } else {
-      // iterative copy
-      if(((t_base_type*)elem_type)->is_binary()){
-        indent(out) << type_name(elem_type, true, false) << " temp_binary_element = ";
-        generate_deep_copy_non_container(out, iterator_element_name, "temp_binary_element", elem_type);
-        out << ";" << endl;
-	if (elem_type->is_list()) {
-	  indent(out) << result_name << ".addElement(temp_binary_element);" << endl;
-	} else {
-	  indent(out) << result_name << ".put(temp_binary_element, temp_binary_element);" << endl;
-	}
-      } else{
-        indent(out) << result_name << ".addElement(";
-        generate_deep_copy_non_container(out, iterator_element_name, result_name, elem_type);
-        out << ");" << endl;
-      }
-    }
-
-    indent_down();
-
-    indent(out) << "}" << endl;
-
-  }
-}
-
-void t_javame_generator::generate_deep_copy_non_container(ofstream& out, std::string source_name, std::string dest_name, t_type* type) {
-  if (type->is_base_type() || type->is_enum() || type->is_typedef()) {
-    // binary fields need to be copied with System.arraycopy
-    if (((t_base_type*)type)->is_binary()){
-      out << "new byte[" << source_name << ".length];" << endl;
-      indent(out) << "System.arraycopy(" << source_name << ", 0, " << dest_name << ", 0, " << source_name << ".length)";
-    }
-    // everything else can be copied directly
-    else
-      out << source_name;
-  } else {
-    out << "new " << type_name(type, true, true) << "(" << source_name << ")";
-  }
-}
-
-std::string t_javame_generator::generate_isset_check(t_field* field) {
-  return generate_isset_check(field->get_name());
-}
-
-std::string t_javame_generator::isset_field_id(t_field* field) {
-  return "__" + upcase_string(field->get_name() + "_isset_id");
-}
-
-std::string t_javame_generator::generate_isset_check(std::string field_name) {
-  return "is" + get_cap_name("set") + get_cap_name(field_name) + "()";
-}
-
-void t_javame_generator::generate_isset_set(ofstream& out, t_field* field) {
-  if (!type_can_be_null(field->get_type())) {
-    indent(out) << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet") << "(true);" << endl;
-  }
-}
-
-std::string t_javame_generator::get_enum_class_name(t_type* type) {
-  string package = "";
-  t_program* program = type->get_program();
-  if (program != NULL && program != program_) {
-    package = program->get_namespace("java") + ".";
-  }
-  return package + type->get_name();
-}
-
-void t_javame_generator::generate_struct_desc(ofstream& out, t_struct* tstruct) {
-  indent(out) <<
-    "private static final TStruct STRUCT_DESC = new TStruct(\"" << tstruct->get_name() << "\");" << endl;
-}
-
-void t_javame_generator::generate_field_descs(ofstream& out, t_struct* tstruct) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    indent(out) <<
-      "private static final TField " << constant_name((*m_iter)->get_name()) <<
-      "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", " <<
-      type_to_enum((*m_iter)->get_type()) << ", " <<
-      "(short)" << (*m_iter)->get_key() << ");" << endl;
-  }
-}
-
-bool t_javame_generator::has_bit_vector(t_struct* tstruct) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    if (!type_can_be_null(get_true_type((*m_iter)->get_type()))) {
-      return true;
-    }
-  }
-  return false;
-}
-
-void t_javame_generator::generate_java_struct_clear(std::ofstream& out, t_struct* tstruct) {
-  indent(out) << "public void clear() {" << endl;
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  indent_up();
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* t = get_true_type((*m_iter)->get_type());
-    if ((*m_iter)->get_value() != NULL) {
-      print_const_value(out, "this." + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true);
-    } else {
-      if (type_can_be_null(t)) {
-        indent(out) << "this." << (*m_iter)->get_name() << " = null;" << endl;
-      } else {
-        // must be a base type
-        // means it also needs to be explicitly unset
-        indent(out) << "set" << get_cap_name((*m_iter)->get_name()) << get_cap_name("isSet") << "(false);" << endl;
-        switch (((t_base_type*)t)->get_base()) {
-          case t_base_type::TYPE_BYTE:
-          case t_base_type::TYPE_I16:
-          case t_base_type::TYPE_I32:
-          case t_base_type::TYPE_I64:
-            indent(out) << "this." << (*m_iter)->get_name() << " = 0;" << endl;
-            break;
-          case t_base_type::TYPE_DOUBLE:
-            indent(out) << "this." << (*m_iter)->get_name() << " = 0.0;" << endl;
-            break;
-          case t_base_type::TYPE_BOOL:
-            indent(out) << "this." << (*m_iter)->get_name() << " = false;" << endl;
-            break;
-          default:  // prevent gcc compiler warning
-            break;
-        }
-      }
-    }
-  }
-  indent_down();
-
-  indent(out) << "}" << endl << endl;
-}
-
-THRIFT_REGISTER_GENERATOR(javame, "Java ME", "")
-
diff --git a/compiler/cpp/src/generate/t_js_generator.cc b/compiler/cpp/src/generate/t_js_generator.cc
deleted file mode 100644
index e27f5de..0000000
--- a/compiler/cpp/src/generate/t_js_generator.cc
+++ /dev/null
@@ -1,1807 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <map>
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-#include <list>
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sstream>
-#include "platform.h"
-#include "version.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-#include "t_oop_generator.h"
-
-/**
- * JS code generator.
- */
-class t_js_generator : public t_oop_generator {
- public:
-  t_js_generator(t_program* program,
-                const std::map<std::string, std::string>& parsed_options,
-                const std::string& option_string) :
-     t_oop_generator(program) {
-     (void) option_string;
-     
-     std::map<std::string, std::string>::const_iterator iter;
-     
-     iter = parsed_options.find("node");
-     gen_node_ = (iter != parsed_options.end());
-     
-     iter = parsed_options.find("jquery");
-     gen_jquery_ = (iter != parsed_options.end());
-
-     if (gen_node_) {
-       out_dir_base_ = "gen-nodejs";
-     } else {
-       out_dir_base_ = "gen-js";
-     }
-  }
-
-  /**
-   * 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_recv_throw(std::string var);
-  std::string render_recv_return(std::string var);
-
-  std::string render_const_value(t_type* type, t_const_value* value);
-
-
-  /**
-   * Structs!
-   */
-  void generate_js_struct(t_struct* tstruct, bool is_exception);
-  void generate_js_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_exported=true);
-  void generate_js_struct_reader(std::ofstream& out, t_struct* tstruct);
-  void generate_js_struct_writer(std::ofstream& out, t_struct* tstruct);
-  void generate_js_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_rest      (t_service* tservice);
-  void generate_service_client    (t_service* tservice);
-  void generate_service_processor (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,
-                                          std::string prefix="",
-                                          bool inclass=false);
-
-  void generate_deserialize_struct       (std::ofstream &out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_deserialize_container    (std::ofstream &out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_deserialize_set_element  (std::ofstream &out,
-                                          t_set*      tset,
-                                          std::string prefix="");
-
-  void generate_deserialize_map_element  (std::ofstream &out,
-                                          t_map*      tmap,
-                                          std::string prefix="");
-
-  void generate_deserialize_list_element (std::ofstream &out,
-                                          t_list*     tlist,
-                                          std::string prefix="");
-
-  void generate_serialize_field          (std::ofstream &out,
-                                          t_field*    tfield,
-                                          std::string prefix="");
-
-  void generate_serialize_struct         (std::ofstream &out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_serialize_container      (std::ofstream &out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_serialize_map_element    (std::ofstream &out,
-                                          t_map*      tmap,
-                                          std::string kiter,
-                                          std::string viter);
-
-  void generate_serialize_set_element    (std::ofstream &out,
-                                          t_set*      tmap,
-                                          std::string iter);
-
-  void generate_serialize_list_element   (std::ofstream &out,
-                                          t_list*     tlist,
-                                          std::string iter);
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string js_includes();
-  std::string render_includes();
-  std::string declare_field(t_field* tfield, bool init=false, bool obj=false);
-  std::string function_signature(t_function* tfunction, std::string prefix="", bool include_callback=false);
-  std::string argument_list(t_struct* tstruct, bool include_callback=false);
-  std::string type_to_enum(t_type* ttype);
-
-  std::string autogen_comment() {
-    return
-      std::string("//\n") +
-      "// Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" +
-      "//\n" +
-      "// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
-      "//\n";
-  }
-
-  std::vector<std::string> js_namespace_pieces(t_program* p) {
-      std::string ns = p->get_namespace("js");
-
-      std::string::size_type   loc;
-      std::vector<std::string> pieces;
-
-      if (ns.size() > 0) {
-          while ((loc = ns.find(".")) != std::string::npos) {
-              pieces.push_back(ns.substr(0, loc));
-              ns = ns.substr(loc+1);
-          }
-      }
-
-      if (ns.size() > 0) {
-          pieces.push_back(ns);
-      }
-
-      return pieces;
-  }
-
-  std::string js_type_namespace(t_program* p) {
-    if (gen_node_) {
-      if (p != NULL && p != program_) {
-        return p->get_name() + "_ttypes.";
-      }
-      return "ttypes.";
-    }
-    return js_namespace(p);
-  }
-
-  std::string js_export_namespace(t_program* p) {
-    if (gen_node_) {
-      return "exports.";
-    }
-    return js_namespace(p);
-  }
-
-  std::string js_namespace(t_program* p) {
-      std::string ns = p->get_namespace("js");
-      if (ns.size() > 0) {
-          ns += ".";
-      }
-
-
-      return ns;
-  }
-
- private:
-
-  /**
-   * True iff we should generate NodeJS-friendly RPC services.
-   */
-  bool gen_node_;
-
-  /**
-   * True if we should generate services that use jQuery ajax (async/sync).
-   */
-  bool gen_jquery_;
-
-  /**
-   * File streams
-   */
-  std::ofstream f_types_;
-  std::ofstream f_service_;
-};
-
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * streams.
- *
- * @param tprogram The program to generate
- */
-void t_js_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-
-  string outdir = get_out_dir();
-
-  // Make output file
-  string f_types_name = outdir+program_->get_name()+"_types.js";
-  f_types_.open(f_types_name.c_str());
-
-  // Print header
-  f_types_ <<
-    autogen_comment() <<
-    js_includes() << endl <<
-    render_includes() << endl;
-
-  if (gen_node_) {
-    f_types_ << "var ttypes = module.exports = {};" << endl;
-  }
-
-  string pns;
-
-  //setup the namespace
-  // TODO should the namespace just be in the directory structure for node?
-  vector<string> ns_pieces = js_namespace_pieces( program_ );
-  if( ns_pieces.size() > 0){
-    for(size_t i = 0; i < ns_pieces.size(); ++i) {
-      pns += ((i == 0) ? "" : ".") + ns_pieces[i];
-      f_types_ << "if (typeof " << pns << " === 'undefined') {" << endl;
-        f_types_ << "  " << pns << " = {};" << endl;
-        f_types_ << "}" << endl;
-    }
-  }
-
-}
-
-/**
- * Prints standard js imports
- */
-string t_js_generator::js_includes() {
-  if (gen_node_) {
-    return string("var Thrift = require('thrift').Thrift;");
-  }
-  string inc;
-
-  return inc;
-}
-
-/**
- * Renders all the imports necessary for including another Thrift program
- */
-string t_js_generator::render_includes() {
-  if (gen_node_) {
-    const vector<t_program*>& includes = program_->get_includes();
-    string result = "";
-    for (size_t i = 0; i < includes.size(); ++i) {
-      result += "var " + includes[i]->get_name() + "_ttypes = require('./" + includes[i]->get_name() + "_types')\n";
-    }
-    if (includes.size() > 0) {
-      result += "\n";
-    }
-    return result;
-  }
-  string inc;
-
-  return inc;
-}
-
-/**
- * Close up (or down) some filez.
- */
-void t_js_generator::close_generator() {
-  // Close types file
-
-  f_types_.close();
-}
-
-/**
- * Generates a typedef. This is not done in JS, types are all implicit.
- *
- * @param ttypedef The type definition
- */
-void t_js_generator::generate_typedef(t_typedef* ttypedef) {
-  (void) ttypedef;
-}
-
-/**
- * Generates code for an enumerated type. Since define is expensive to lookup
- * in JS, we use a global array for this.
- *
- * @param tenum The enumeration
- */
-void t_js_generator::generate_enum(t_enum* tenum) {
-  f_types_ << js_type_namespace(tenum->get_program())<<tenum->get_name()<<" = {"<<endl;
-
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    f_types_ << "'" << (*c_iter)->get_name() << "' : " << value;
-    if (c_iter != constants.end()-1) {
-        f_types_ << ",";
-    }
-    f_types_ << endl;
-  }
-
-  f_types_ << "};"<<endl;
-}
-
-/**
- * Generate a constant value
- */
-void t_js_generator::generate_const(t_const* tconst) {
-  t_type* type = tconst->get_type();
-  string name = tconst->get_name();
-  t_const_value* value = tconst->get_value();
-
-  f_types_ << js_type_namespace(program_)  << name << " = ";
-  f_types_ << render_const_value(type, value) << ";" << 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_js_generator::render_const_value(t_type* type, t_const_value* value) {
-  std::ostringstream out;
-
-  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_STRING:
-      out << "'" << value->get_string() << "'";
-      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()) {
-    out << value->get_integer();
-  } else if (type->is_struct() || type->is_xception()) {
-    out << "new " << js_type_namespace(type->get_program()) << type->get_name() << "({" << 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 (v_iter != val.begin())
-        out << ",";
-      out << render_const_value(g_type_string, v_iter->first);
-      out << " : ";
-      out << render_const_value(field_type, v_iter->second);
-    }
-
-    out << "})";
-  } else if (type->is_map()) {
-    t_type* ktype = ((t_map*)type)->get_key_type();
-
-    t_type* vtype = ((t_map*)type)->get_val_type();
-    out << "{";
-
-    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) {
-        if (v_iter != val.begin())
-          out << "," << endl;
-
-        out << render_const_value(ktype, v_iter->first);
-
-        out << " : ";
-        out << render_const_value(vtype, v_iter->second);
-    }
-
-    out << endl << "}";
-  } else if (type->is_list() || type->is_set()) {
-    t_type* etype;
-    if (type->is_list()) {
-      etype = ((t_list*)type)->get_elem_type();
-    } else {
-      etype = ((t_set*)type)->get_elem_type();
-    }
-    out << "[";
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      if (v_iter != val.begin())
-        out << ",";
-      out << render_const_value(etype, *v_iter);
-    }
-    out << "]";
-  }
-  return out.str();
-}
-
-/**
- * Make a struct
- */
-void t_js_generator::generate_struct(t_struct* tstruct) {
-  generate_js_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_js_generator::generate_xception(t_struct* txception) {
-  generate_js_struct(txception, true);
-}
-
-/**
- * Structs can be normal or exceptions.
- */
-void t_js_generator::generate_js_struct(t_struct* tstruct,
-                                            bool is_exception) {
-  generate_js_struct_definition(f_types_, tstruct, is_exception);
-}
-
-/**
- * Generates a struct definition for a thrift data type. This is nothing in JS
- * where the objects are all just associative arrays (unless of course we
- * decide to start using objects for them...)
- *
- * @param tstruct The struct definition
- */
-void t_js_generator::generate_js_struct_definition(ofstream& out,
-                                                       t_struct* tstruct,
-                                                       bool is_exception,
-                                                       bool is_exported) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  indent_up();
-
-  if (gen_node_) {
-    if (is_exported) {
-      out << js_namespace(tstruct->get_program()) << tstruct->get_name() << " = " <<
-        "module.exports." << tstruct->get_name() << " = function(args) {\n";
-    } else {
-      out << js_namespace(tstruct->get_program()) << tstruct->get_name() << " = function(args) {\n";
-    }
-  } else {
-    out << js_namespace(tstruct->get_program()) << tstruct->get_name() <<" = function(args) {\n";
-  }
-
-  if (gen_node_ && is_exception) {
-      out << indent() << "Thrift.TException.call(this, \"" <<
-          js_namespace(tstruct->get_program()) << tstruct->get_name() << "\")" << endl;
-      out << indent() << "this.name = \"" <<
-          js_namespace(tstruct->get_program()) << tstruct->get_name() << "\"" << endl;
-  }
-
-  //members with arguments
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    string dval = declare_field(*m_iter,false,true);
-    t_type* t = get_true_type((*m_iter)->get_type());
-    if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) {
-        dval = render_const_value((*m_iter)-> get_type(), (*m_iter)->get_value());
-        out << indent() << "this." << (*m_iter)->get_name() << " = " << dval << ";" << endl;
-    } else {
-        out << indent() <<  dval << ";" << endl;
-    }
-
-  }
-
-  // Generate constructor from array
-  if (members.size() > 0) {
-
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      t_type* t = get_true_type((*m_iter)->get_type());
-      if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) {
-        indent(out) << "this." << (*m_iter)->get_name() << " = " << render_const_value(t, (*m_iter)->get_value())  << ";" << endl;
-      }
-    }
-
-    // Early returns for exceptions
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-       t_type* t = get_true_type((*m_iter)->get_type());
-       if (t->is_xception()) {
-                       out << indent() <<  "if (args instanceof " << js_type_namespace(t->get_program()) << t->get_name() << ") {" << endl
-                               << indent() << indent() << "this." << (*m_iter)->get_name() << " = args;" << endl
-                               << indent() << indent() << "return;" << endl
-                               << indent() << "}" << endl;
-       }
-    }
-
-    out << indent() <<  "if (args) {" << endl;
-
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-        out << indent() << indent() << "if (args." << (*m_iter)->get_name() << " !== undefined) {" << endl
-            << indent() << indent() << indent() << "this." << (*m_iter)->get_name() << " = args." << (*m_iter)->get_name()  << ";" << endl
-            << indent() << indent() << "}" << endl;
-    }
-
-    out << indent() <<  "}" << endl;
-
-  }
-
-  indent_down();
-  out << "};\n";
-
-  if (is_exception) {
-    out << "Thrift.inherits(" <<
-        js_namespace(tstruct->get_program()) <<
-        tstruct->get_name() << ", Thrift.TException);" << endl;
-	out << js_namespace(tstruct->get_program())<<tstruct->get_name() <<".prototype.name = '" << tstruct->get_name() << "';" << endl;
-  } else {
-    //init prototype
-    out << js_namespace(tstruct->get_program())<<tstruct->get_name() <<".prototype = {};\n";
-  }
-
-
-  generate_js_struct_reader(out, tstruct);
-  generate_js_struct_writer(out, tstruct);
-
-}
-
-/**
- * Generates the read() method for a struct
- */
-void t_js_generator::generate_js_struct_reader(ofstream& out,
-                                                   t_struct* tstruct) {
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  out <<  js_namespace(tstruct->get_program())<<tstruct->get_name() << ".prototype.read = function(input) {"<<endl;
-
-  indent_up();
-
-  indent(out) << "input.readStructBegin();" << endl;
-
-
-  // Loop over reading in fields
-  indent(out) << "while (true)" << endl;
-
-  scope_up(out);
-
-  indent(out) << "var ret = input.readFieldBegin();" << endl;
-  indent(out) << "var fname = ret.fname;" << endl;
-  indent(out) << "var ftype = ret.ftype;" << endl;
-  indent(out) << "var fid = ret.fid;"   << endl;
-
-
-  // Check for field STOP marker and break
-  indent(out) << "if (ftype == Thrift.Type.STOP) {" << endl;
-  indent_up();
-  indent(out) << "break;" << endl;
-  indent_down();
-  indent(out) << "}" << endl;
-  if (!fields.empty()) {
-    // Switch statement on the field we are reading
-    indent(out) << "switch (fid)" << endl;
-
-    scope_up(out);
-
-    // Generate deserialization code for known cases
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-
-      indent(out) << "case " << (*f_iter)->get_key() << ":" << endl;
-      indent(out) << "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
-
-      indent_up();
-      generate_deserialize_field(out, *f_iter, "this.");
-      indent_down();
-
-      indent(out) << "} else {" << endl;
-
-      indent(out) <<  "  input.skip(ftype);" << endl;
-
-      out <<
-        indent() << "}" << endl <<
-        indent() << "break;" << endl;
-
-    }
-    if (fields.size() == 1) {
-      // pseudo case to make jslint happy
-      indent(out) <<  "case 0:" << endl;
-      indent(out) <<  "  input.skip(ftype);" << endl;
-      indent(out) <<  "  break;" << endl;
-    }
-    // In the default case we skip the field
-    indent(out) <<  "default:" << endl;
-    indent(out) <<  "  input.skip(ftype);" << endl;
-
-    scope_down(out);
-  } else {
-    indent(out) << "input.skip(ftype);" << endl;
-  }
-
-  indent(out) << "input.readFieldEnd();" << endl;
-
-  scope_down(out);
-
-  indent(out) << "input.readStructEnd();" << endl;
-
-  indent(out) << "return;" << endl;
-
-  indent_down();
-  out << indent() << "};" << endl << endl;
-}
-
-/**
- * Generates the write() method for a struct
- */
-void t_js_generator::generate_js_struct_writer(ofstream& out,
-                                                   t_struct* tstruct) {
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  out << js_namespace(tstruct->get_program())<< tstruct->get_name() << ".prototype.write = function(output) {"<<endl;
-
-  indent_up();
-
-  indent(out) << "output.writeStructBegin('" << name << "');" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    out << indent() << "if (this." << (*f_iter)->get_name() <<  " !== null && this." << (*f_iter)->get_name() << " !== undefined) {" << endl;
-    indent_up();
-
-    indent(out) <<
-      "output.writeFieldBegin(" <<
-      "'" << (*f_iter)->get_name() << "', " <<
-      type_to_enum((*f_iter)->get_type()) << ", " <<
-      (*f_iter)->get_key() << ");" << endl;
-
-
-    // Write field contents
-    generate_serialize_field(out, *f_iter, "this.");
-
-    indent(out) <<
-        "output.writeFieldEnd();" << endl;
-
-    indent_down();
-    indent(out) << "}" << endl;
-  }
-
-
-  out <<
-    indent() << "output.writeFieldStop();" << endl <<
-    indent() << "output.writeStructEnd();" << endl;
-
-  out <<indent() << "return;" << endl;
-
-  indent_down();
-  out <<
-    indent() << "};" << endl <<
-    endl;
-}
-
-/**
- * Generates a thrift service.
- *
- * @param tservice The service definition
- */
-void t_js_generator::generate_service(t_service* tservice) {
-    string f_service_name = get_out_dir()+service_name_+".js";
-    f_service_.open(f_service_name.c_str());
-
-    f_service_ <<
-      autogen_comment() <<
-      js_includes() << endl <<
-      render_includes() << endl;
-
-    if (gen_node_) {
-      if (tservice->get_extends() != NULL) {
-        f_service_ <<
-          "var " << tservice->get_extends()->get_name() <<
-          " = require('./" << tservice->get_extends()->get_name() << "')" << endl <<
-          "var " << tservice->get_extends()->get_name() << "Client = " <<
-          tservice->get_extends()->get_name() << ".Client" << endl <<
-          "var " << tservice->get_extends()->get_name() << "Processor = " <<
-          tservice->get_extends()->get_name() << ".Processor" << endl;
-      }
-
-      f_service_ <<
-        "var ttypes = require('./" + program_->get_name() + "_types');" << endl;
-    }
-
-    generate_service_helpers(tservice);
-    generate_service_interface(tservice);
-    generate_service_client(tservice);
-
-    if (gen_node_) {
-      generate_service_processor(tservice);
-    }
-
-    f_service_.close();
-}
-
-/**
- * Generates a service server definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_js_generator::generate_service_processor(t_service* tservice) {
-    vector<t_function*> functions = tservice->get_functions();
-    vector<t_function*>::iterator f_iter;
-
-    f_service_ <<
-        js_namespace(tservice->get_program()) << service_name_ << "Processor = " <<
-        "exports.Processor = function(handler) ";
-
-    scope_up(f_service_);
-
-    f_service_ << indent() << "this._handler = handler" << endl;
-
-    scope_down(f_service_);
-
-    if (tservice->get_extends() != NULL) {
-        indent(f_service_) << "Thrift.inherits(" <<
-            js_namespace(tservice->get_program()) <<
-            service_name_ << "Processor, " <<
-            tservice->get_extends()->get_name() << "Processor)" << endl;
-    }
-
-    // Generate the server implementation
-    indent(f_service_) <<
-        js_namespace(tservice->get_program()) << service_name_ << "Processor.prototype.process = function(input, output) ";
-
-    scope_up(f_service_);
-
-    f_service_ << indent() << "var r = input.readMessageBegin();" << endl
-               << indent() << "if (this['process_' + r.fname]) {" << endl
-               << indent() << "  return this['process_' + r.fname].call(this, r.rseqid, input, output);" << endl
-               << indent() << "} else {" << endl
-               << indent() << "  input.skip(Thrift.Type.STRUCT);" << endl
-               << indent() << "  input.readMessageEnd();" << endl
-               << indent() << "  var x = new Thrift.TApplicationException(Thrift.TApplicationExceptionType.UNKNOWN_METHOD, 'Unknown function ' + r.fname);" << endl
-               << indent() << "  output.writeMessageBegin(r.fname, Thrift.MessageType.Exception, r.rseqid);" << endl
-               << indent() << "  x.write(output);" << endl
-               << indent() << "  output.writeMessageEnd();" << endl
-               << indent() << "  output.flush();" << endl
-               << indent() << "}" << endl;
-
-    scope_down(f_service_);
-    f_service_ << endl;
-
-    // Generate the process subfunctions
-    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-        generate_process_function(tservice, *f_iter);
-    }
-}
-
-/**
- * Generates a process function definition.
- *
- * @param tfunction The function to write a dispatcher for
- */
-void t_js_generator::generate_process_function(t_service* tservice,
-                                                 t_function* tfunction) {
-    indent(f_service_) <<
-        js_namespace(tservice->get_program()) << service_name_ << "Processor.prototype.process_" + tfunction->get_name() + " = function(seqid, input, output) ";
-
-    scope_up(f_service_);
-
-    string argsname =  js_namespace(program_)+ service_name_ + "_" + tfunction->get_name() + "_args";
-    string resultname =  js_namespace(program_)+ service_name_ + "_" + tfunction->get_name() + "_result";
-
-    f_service_ <<
-        indent() << "var args = new " << argsname << "();" << endl <<
-        indent() << "args.read(input);" << endl <<
-        indent() << "input.readMessageEnd();" << endl;
-
-    // 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_ <<
-      indent() << "this._handler." << 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." << (*f_iter)->get_name();
-    }
-
-    // Shortcut out here for oneway functions
-    if (tfunction->is_oneway()) {
-      f_service_ << ")" << endl;
-      scope_down(f_service_);
-      f_service_ << endl;
-      return;
-    }
-
-    if (!first) {
-        f_service_ << ", ";
-    }
-    f_service_ << "function (err, result) {" << endl;
-    indent_up();
-
-    f_service_ <<
-      indent() << "var result = new " << resultname << "((err != null ? err : {success: result}));" << endl <<
-      indent() << "output.writeMessageBegin(\"" << tfunction->get_name() <<
-        "\", Thrift.MessageType.REPLY, seqid);" << endl <<
-      indent() << "result.write(output);" << endl <<
-      indent() << "output.writeMessageEnd();" << endl <<
-      indent() << "output.flush();" << endl;
-
-    indent_down();
-    indent(f_service_) << "})" << endl;
-
-    scope_down(f_service_);
-    f_service_ << endl;
-}
-
-/**
- * Generates helper functions for a service.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_js_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();
-        string name = ts->get_name();
-        ts->set_name(service_name_ + "_" + name);
-        generate_js_struct_definition(f_service_, ts, false, false);
-        generate_js_function_helpers(*f_iter);
-        ts->set_name(name);
-    }
-}
-
-/**
- * Generates a struct and helpers for a function.
- *
- * @param tfunction The function
- */
-void t_js_generator::generate_js_function_helpers(t_function* tfunction) {
-    t_struct result(program_, service_name_ + "_" + 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_js_struct_definition(f_service_, &result, false, false);
-}
-
-/**
- * Generates a service interface definition.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_js_generator::generate_service_interface(t_service* tservice) {
-  (void) tservice;
-}
-
-/**
- * Generates a REST interface
- */
-void t_js_generator::generate_service_rest(t_service* tservice) {
-  (void) tservice;
-}
-
-/**
- * Generates a service client definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_js_generator::generate_service_client(t_service* tservice) {
-  string extends = "";
-
-  if (gen_node_) {
-    f_service_ <<
-        js_namespace(tservice->get_program()) << service_name_ << "Client = " << 
-        "exports.Client = function(output, pClass) {"<<endl;
-  } else {
-    f_service_ <<
-        js_namespace(tservice->get_program()) << service_name_ << "Client = function(input, output) {"<<endl;
-  }
-
-  indent_up();
-
-
-  if (gen_node_) {
-    f_service_ <<
-      indent() << "  this.output = output;" << endl <<
-      indent() << "  this.pClass = pClass;" << endl <<
-      indent() << "  this.seqid = 0;" << endl <<
-      indent() << "  this._reqs = {};" << endl;
-  } else {
-    f_service_ <<
-      indent() << "  this.input = input;" << endl <<
-      indent() << "  this.output = (!output) ? input : output;" << endl <<
-      indent() << "  this.seqid = 0;" << endl;
-  }
-
-
-  indent_down();
-
-  f_service_ <<
-      indent() << "};" << endl;
-
-
-  if (tservice->get_extends() != NULL) {
-    indent(f_service_) << "Thrift.inherits(" <<
-        js_namespace(tservice->get_program()) <<
-        service_name_ << "Client, " <<
-        tservice->get_extends()->get_name() << "Client)" << endl;
-  } else {
-      //init prototype
-      indent(f_service_) <<  js_namespace(tservice->get_program())<<service_name_ << "Client.prototype = {};"<<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 = (*f_iter)->get_name();
-    string arglist = argument_list(arg_struct);
-
-    // Open function
-    f_service_ <<  js_namespace(tservice->get_program())<<service_name_<<"Client.prototype." <<
-      function_signature(*f_iter, "", gen_node_ || gen_jquery_) << " {" << endl;
-
-    indent_up();
-
-    if (gen_node_) {
-      f_service_ <<
-        indent() << "this.seqid += 1;" << endl <<
-        indent() << "this._reqs[this.seqid] = callback;" << endl;
-    } else if (gen_jquery_) {
-      f_service_ <<
-        indent() << "if (callback === undefined) {" << endl;
-        indent_up();
-    }
-
-    f_service_ << indent() <<
-      "this.send_" << funname << "(" << arglist << ");" << endl;
-
-    if (!gen_node_ && !(*f_iter)->is_oneway()) {
-      f_service_ << indent();
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_ << "return ";
-      }
-      f_service_ <<
-        "this.recv_" << funname << "();" << endl;
-    }
-
-    if (gen_jquery_) {
-      indent_down();
-      f_service_ << indent() << "} else {" << endl;
-      indent_up();
-        f_service_ << indent() << "var postData = this.send_" << funname <<
-           "(" << arglist << (arglist.empty() ? "" : ", ") << "true);" << endl;
-        f_service_ << indent() << "return this.output.getTransport()" << endl;
-        indent_up();
-          f_service_ << indent() << ".jqRequest(this, postData, arguments, this.recv_" << funname << ");" << endl;
-        indent_down();
-      indent_down();
-      f_service_ << indent() << "}" << endl;
-    }
-
-    indent_down();
-
-    f_service_ << "};" << endl << endl;
-
-
-    // Send function
-    f_service_ <<  js_namespace(tservice->get_program())<<service_name_ <<
-        "Client.prototype.send_" << function_signature(*f_iter, "", gen_jquery_) << " {" <<endl;
-
-    indent_up();
-
-    std::string outputVar;
-    if (gen_node_) {
-      f_service_ <<
-        indent() << "var output = new this.pClass(this.output);" << endl;
-      outputVar = "output";
-    } else {
-      outputVar = "this.output";
-    }
-
-    std::string argsname =  js_namespace(program_)+ service_name_ + "_" + (*f_iter)->get_name() + "_args";
-
-    // Serialize the request header
-    f_service_ <<
-      indent() << outputVar << ".writeMessageBegin('" << (*f_iter)->get_name() << "', Thrift.MessageType.CALL, this.seqid);" << endl;
-
-    f_service_ <<
-      indent() << "var args = new " << argsname << "();" << endl; 
-
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      f_service_ <<
-        indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl;
-    }
-
-    // Write to the stream
-    f_service_ <<
-      indent() << "args.write(" << outputVar << ");" << endl <<
-      indent() << outputVar << ".writeMessageEnd();" << endl;
-
-    if (gen_node_) {
-      f_service_ << indent() << "return this.output.flush();" << endl;
-    } else {
-      if (gen_jquery_) {
-        f_service_ << indent() << "return this.output.getTransport().flush(callback);" << endl;
-      } else {
-        f_service_ << indent() << "return this.output.getTransport().flush();" << endl;
-      }
-    }
-
-
-    indent_down();
-
-    f_service_ << "};" << endl;
-
-
-    if (!(*f_iter)->is_oneway()) {
-      std::string resultname = js_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_result";
-
-      if (gen_node_) {
-        // Open function
-        f_service_ <<
-            endl <<  js_namespace(tservice->get_program())<<service_name_ <<
-            "Client.prototype.recv_" << (*f_iter)->get_name() << " = function(input,mtype,rseqid) {" << endl;
-      } else {
-        t_struct noargs(program_);
-
-        t_function recv_function((*f_iter)->get_returntype(),
-                                 string("recv_") + (*f_iter)->get_name(),
-                                 &noargs);
-        // Open function
-        f_service_ <<
-            endl <<  js_namespace(tservice->get_program())<<service_name_ <<
-            "Client.prototype." << function_signature(&recv_function) << " {" << endl;
-      }
-
-      indent_up();
-
-      std::string inputVar;
-      if (gen_node_) {
-        inputVar = "input";
-      } else {
-        inputVar = "this.input";
-      }
-
-      if (gen_node_) {
-        f_service_ <<
-          indent() << "var callback = this._reqs[rseqid] || function() {};" << endl <<
-          indent() << "delete this._reqs[rseqid];" << endl;
-      } else {
-        f_service_ <<
-          indent() << "var ret = this.input.readMessageBegin();" << endl <<
-          indent() << "var fname = ret.fname;" << endl <<
-          indent() << "var mtype = ret.mtype;" << endl <<
-          indent() << "var rseqid = ret.rseqid;" <<endl;
-      }
-
-      f_service_ <<
-          indent() << "if (mtype == Thrift.MessageType.EXCEPTION) {" << endl <<
-          indent() << "  var x = new Thrift.TApplicationException();" << endl <<
-          indent() << "  x.read(" << inputVar << ");" << endl <<
-          indent() << "  " << inputVar << ".readMessageEnd();" << endl <<
-          indent() << "  " << render_recv_throw("x") << endl <<
-          indent() << "}" << endl;
-
-
-      f_service_ <<
-        indent() << "var result = new " << resultname << "();" << endl <<
-        indent() << "result.read(" << inputVar << ");" << endl;
-
-
-      f_service_ <<
-        indent() << inputVar << ".readMessageEnd();" << endl <<
-        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 (null !== result." << (*x_iter)->get_name() << ") {" << endl <<
-          indent() << "  " << render_recv_throw("result." + (*x_iter)->get_name()) << endl <<
-          indent() << "}" << endl;
-      }
-
-      // Careful, only return result if not a void function
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_ <<
-          indent() << "if (null !== result.success) {" << endl <<
-          indent() << "  " << render_recv_return("result.success") << endl <<
-          indent() << "}" << endl;
-        f_service_ <<
-          indent() << render_recv_throw("'" + (*f_iter)->get_name() + " failed: unknown result'") << endl;
-      } else {
-          if (gen_node_) {
-            indent(f_service_) << "callback(null)" << endl;
-          } else {
-            indent(f_service_) << "return;" << endl;
-          }
-      }
-
-      // Close function
-      indent_down();
-      f_service_ << "};"<<endl;
-
-    }
-  }
-
-}
-
-std::string t_js_generator::render_recv_throw(std::string var) {
-  if (gen_node_) {
-    return "return callback(" + var + ");";
-  } else {
-    return "throw " + var + ";";
-  }
-}
-
-std::string t_js_generator::render_recv_return(std::string var) {
-  if (gen_node_) {
-    return "return callback(null, " + var + ");";
-  } else {
-    return "return " + var + ";";
-  }
-}
-
-/**
- * Deserializes a field of any type.
- */
-void t_js_generator::generate_deserialize_field(ofstream &out,
-                                                  t_field* tfield,
-                                                  string prefix,
-                                                  bool inclass) {
-  (void) inclass;
-  t_type* type = get_true_type(tfield->get_type());
-
-  if (type->is_void()) {
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  string name = prefix+tfield->get_name();
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct(out,
-                                (t_struct*)type,
-                                 name);
-  } else if (type->is_container()) {
-    generate_deserialize_container(out, type, name);
-  } else if (type->is_base_type() || type->is_enum()) {
-    indent(out) << name << " = input.";
-
-    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 JS name for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      out << "readI32()";
-    }
-
-    if (!gen_node_) {
-        out << ".value";
-    }
-
-    out << ";" << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
-           tfield->get_name().c_str(), type->get_name().c_str());
-  }
-}
-
-/**
- * Generates an unserializer for a variable. This makes two key assumptions,
- * first that there is a const char* variable named data that points to the
- * buffer for deserialization, and that there is a variable protocol which
- * is a reference to a TProtocol serialization object.
- */
-void t_js_generator::generate_deserialize_struct(ofstream &out,
-                                                   t_struct* tstruct,
-                                                   string prefix) {
-    out <<
-        indent() << prefix << " = new " <<  js_type_namespace(tstruct->get_program())<<tstruct->get_name() << "();" << endl <<
-        indent() << prefix << ".read(input);" << endl;
-
-}
-
-void t_js_generator::generate_deserialize_container(ofstream &out,
-                                                      t_type* ttype,
-                                                      string prefix) {
-  string size = tmp("_size");
-  string ktype = tmp("_ktype");
-  string vtype = tmp("_vtype");
-  string etype = tmp("_etype");
-  string rtmp3 = tmp("_rtmp3");
-
-  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);
-
-  out << indent() << "var " << size << " = 0;" << endl;
-  out << indent() << "var " << rtmp3 << ";" << endl;
-
-
-  // Declare variables, read header
-  if (ttype->is_map()) {
-      out <<
-          indent() << prefix << " = {};" << endl <<
-          indent() << "var " << ktype << " = 0;" << endl <<
-          indent() << "var " << vtype << " = 0;" << endl;
-
-      out << indent() << rtmp3 << " = input.readMapBegin();" << endl;
-      out << indent() << ktype << " = " << rtmp3 << ".ktype;" << endl;
-      out << indent() << vtype << " = " << rtmp3 << ".vtype;" << endl;
-      out << indent() << size  << " = " << rtmp3 << ".size;" << endl;
-
-
-  } else if (ttype->is_set()) {
-
-    out <<
-        indent() << prefix << " = [];" << endl <<
-        indent() << "var " << etype << " = 0;" << endl <<
-        indent() << rtmp3 << " = input.readSetBegin();" << endl <<
-        indent() << etype << " = " << rtmp3 << ".etype;"<<endl<<
-        indent() << size << " = " << rtmp3 << ".size;"<<endl;
-
-  } else if (ttype->is_list()) {
-
-    out <<
-        indent() << prefix << " = [];" << endl <<
-        indent() << "var " << etype << " = 0;" << endl <<
-        indent() << rtmp3 << " = input.readListBegin();" << endl <<
-        indent() << etype << " = " << rtmp3 << ".etype;"<<endl<<
-        indent() << size << " = " << rtmp3 << ".size;"<<endl;
-  }
-
-  // For loop iterates over elements
-  string i = tmp("_i");
-  indent(out) <<
-    "for (var " <<
-    i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl;
-
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    if (!gen_node_) {
-      out <<
-      indent() << "if (" << i << " > 0 ) {" << endl <<
-      indent() << "  if (input.rstack.length > input.rpos[input.rpos.length -1] + 1) {" << endl <<
-      indent() << "    input.rstack.pop();" << endl <<
-      indent() << "  }" << endl <<
-      indent() << "}" << endl;
-    }
-
-    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
-  } else if (ttype->is_set()) {
-    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
-  } else if (ttype->is_list()) {
-    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
-  }
-
-  scope_down(out);
-
-
-  // Read container end
-  if (ttype->is_map()) {
-    indent(out) << "input.readMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) << "input.readSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) << "input.readListEnd();" << endl;
-  }
-}
-
-
-/**
- * Generates code to deserialize a map
- */
-void t_js_generator::generate_deserialize_map_element(ofstream &out,
-                                                        t_map* tmap,
-                                                        string prefix) {
-  string key = tmp("key");
-  string val = tmp("val");
-  t_field fkey(tmap->get_key_type(), key);
-  t_field fval(tmap->get_val_type(), val);
-
-  indent(out) <<
-    declare_field(&fkey, false, false) << ";" << endl;
-  indent(out) <<
-    declare_field(&fval, false, false) << ";" << endl;
-
-  generate_deserialize_field(out, &fkey);
-  generate_deserialize_field(out, &fval);
-
-  indent(out) <<
-      prefix << "[" << key << "] = " << val << ";" << endl;
-}
-
-void t_js_generator::generate_deserialize_set_element(ofstream &out,
-                                                        t_set* tset,
-                                                        string prefix) {
-  string elem = tmp("elem");
-  t_field felem(tset->get_elem_type(), elem);
-
-  indent(out) <<
-    "var " << elem << " = null;" << endl;
-
-  generate_deserialize_field(out, &felem);
-
-  indent(out) <<
-      prefix << ".push(" << elem << ");" << endl;
-}
-
-void t_js_generator::generate_deserialize_list_element(ofstream &out,
-                                                         t_list* tlist,
-                                                         string prefix) {
-  string elem = tmp("elem");
-  t_field felem(tlist->get_elem_type(), elem);
-
-  indent(out) <<
-    "var " << elem << " = null;" << endl;
-
-  generate_deserialize_field(out, &felem);
-
-  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_js_generator::generate_serialize_field(ofstream &out,
-                                                t_field* tfield,
-                                                string prefix) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  // Do nothing for void types
-  if (type->is_void()) {
-    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_serialize_struct(out,
-                              (t_struct*)type,
-                               prefix +tfield->get_name() );
-  } else if (type->is_container()) {
-    generate_serialize_container(out,
-                                 type,
-                                 prefix + tfield->get_name());
-  } else if (type->is_base_type() || type->is_enum()) {
-
-    string name = tfield->get_name();
-
-    //Hack for when prefix is defined (always a hash ref)
-    if(!prefix.empty())
-      name = prefix + tfield->get_name();
-
-    indent(out) << "output.";
-
-    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(" << name << ")";
-        break;
-      case t_base_type::TYPE_BOOL:
-        out << "writeBool(" << name << ")";
-        break;
-      case t_base_type::TYPE_BYTE:
-        out << "writeByte(" << name << ")";
-        break;
-      case t_base_type::TYPE_I16:
-        out << "writeI16(" << name << ")";
-        break;
-      case t_base_type::TYPE_I32:
-        out << "writeI32(" << name << ")";
-        break;
-      case t_base_type::TYPE_I64:
-        out << "writeI64(" << name << ")";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        out << "writeDouble(" << name << ")";
-        break;
-      default:
-        throw "compiler error: no JS name for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      out << "writeI32(" << name << ")";
-    }
-    out << ";" << endl;
-
-  } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
-           prefix.c_str(),
-           tfield->get_name().c_str(),
-           type->get_name().c_str());
-  }
-}
-
-/**
- * Serializes all the members of a struct.
- *
- * @param tstruct The struct to serialize
- * @param prefix  String prefix to attach to all fields
- */
-void t_js_generator::generate_serialize_struct(ofstream &out,
-                                                 t_struct* tstruct,
-                                                 string prefix) {
-  (void) tstruct;
-  indent(out) << prefix << ".write(output);" << endl;
-}
-
-/**
- * Writes out a container
- */
-void t_js_generator::generate_serialize_container(ofstream &out,
-                                                    t_type* ttype,
-                                                    string prefix) {
-  if (ttype->is_map()) {
-    indent(out) <<
-        "output.writeMapBegin(" <<
-        type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
-        type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
-        "Thrift.objectLength(" << prefix << "));" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "output.writeSetBegin(" <<
-      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
-        prefix << ".length);" << endl;
-
-  } else if (ttype->is_list()) {
-
-    indent(out) <<
-        "output.writeListBegin(" <<
-        type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
-        prefix << ".length);" << endl;
-
-  }
-
-  if (ttype->is_map()) {
-    string kiter = tmp("kiter");
-    string viter = tmp("viter");
-    indent(out) << "for (var "<<kiter<<" in "<<prefix<<")" << endl;
-    scope_up(out);
-    indent(out) << "if ("<<prefix<<".hasOwnProperty("<<kiter<<"))" <<endl;
-    scope_up(out);
-    indent(out) << "var "<<viter<<" = "<<prefix<<"["<<kiter<<"];"<<endl;
-    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
-    scope_down(out);
-    scope_down(out);
-
-
-  } else if (ttype->is_set()) {
-    string iter = tmp("iter");
-    indent(out) <<
-      "for (var "<<iter<<" in " << prefix << ")" << endl;
-    scope_up(out);
-    indent(out) << "if ("<<prefix<<".hasOwnProperty("<<iter<<"))" <<endl;
-    scope_up(out);
-    indent(out) << iter << " = " << prefix << "[" << iter << "];"<< endl;
-    generate_serialize_set_element(out, (t_set*)ttype, iter);
-    scope_down(out);
-    scope_down(out);
-
-
-  } else if (ttype->is_list()) {
-    string iter = tmp("iter");
-    indent(out) <<
-        "for (var "<<iter<<" in "<< prefix << ")" << endl;
-    scope_up(out);
-    indent(out) << "if ("<<prefix<<".hasOwnProperty("<<iter<<"))" <<endl;
-    scope_up(out);
-    indent(out) << iter << " = " << prefix << "[" << iter << "];"<< endl;
-    generate_serialize_list_element(out, (t_list*)ttype, iter);
-    scope_down(out);
-    scope_down(out);
-  }
-
-  if (ttype->is_map()) {
-    indent(out) <<
-      "output.writeMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "output.writeSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "output.writeListEnd();" << endl;
-  }
-}
-
-/**
- * Serializes the members of a map.
- *
- */
-void t_js_generator::generate_serialize_map_element(ofstream &out,
-                                                      t_map* tmap,
-                                                      string kiter,
-                                                      string viter) {
-  t_field kfield(tmap->get_key_type(), kiter);
-  generate_serialize_field(out, &kfield);
-
-  t_field vfield(tmap->get_val_type(), viter);
-  generate_serialize_field(out, &vfield);
-}
-
-/**
- * Serializes the members of a set.
- */
-void t_js_generator::generate_serialize_set_element(ofstream &out,
-                                                      t_set* tset,
-                                                      string iter) {
-  t_field efield(tset->get_elem_type(), iter);
-  generate_serialize_field(out, &efield);
-}
-
-/**
- * Serializes the members of a list.
- */
-void t_js_generator::generate_serialize_list_element(ofstream &out,
-                                                       t_list* tlist,
-                                                       string iter) {
-  t_field efield(tlist->get_elem_type(), iter);
-  generate_serialize_field(out, &efield);
-}
-
-/**
- * Declares a field, which may include initialization as necessary.
- *
- * @param ttype The type
- */
-string t_js_generator::declare_field(t_field* tfield, bool init, bool obj) {
-  string result = "this." + tfield->get_name();
-
-  if(!obj){
-      result = "var " + tfield->get_name();
-  }
-
-  if (init) {
-    t_type* type = get_true_type(tfield->get_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:
-        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:
-        result += " = null";
-        break;
-      default:
-        throw "compiler error: no JS initializer for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      result += " = null";
-    } else if (type->is_map()){
-      result += " = null";
-    } else if (type->is_container()) {
-      result += " = null";
-    } else if (type->is_struct() || type->is_xception()) {
-      if (obj) {
-          result += " = new " +js_type_namespace(type->get_program()) + type->get_name() + "()";
-      } else {
-        result += " = null";
-      }
-    }
-  } else {
-    result += " = null";
-  }
-  return result;
-}
-
-/**
- * Renders a function signature of the form 'type name(args)'
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_js_generator::function_signature(t_function* tfunction,
-                                            string prefix,
-                                            bool include_callback) {
-
-  string str;
-
-  str  = prefix + tfunction->get_name() + " = function(";
-
-  str += argument_list(tfunction->get_arglist(), include_callback);
-
-  str += ")";
-  return str;
-}
-
-/**
- * Renders a field list
- */
-string t_js_generator::argument_list(t_struct* tstruct,
-                                       bool include_callback) {
-  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();
-  }
-
-  if (include_callback) {
-    if (!fields.empty()) {
-      result += ", ";
-    }
-    result += "callback";
-  }
-
-  return result;
-}
-
-/**
- * Converts the parse type to a C++ enum string for the given type.
- */
-string t_js_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.Type.STRING";
-    case t_base_type::TYPE_BOOL:
-      return "Thrift.Type.BOOL";
-    case t_base_type::TYPE_BYTE:
-      return "Thrift.Type.BYTE";
-    case t_base_type::TYPE_I16:
-      return "Thrift.Type.I16";
-    case t_base_type::TYPE_I32:
-      return "Thrift.Type.I32";
-    case t_base_type::TYPE_I64:
-      return "Thrift.Type.I64";
-    case t_base_type::TYPE_DOUBLE:
-      return "Thrift.Type.DOUBLE";
-    }
-  } else if (type->is_enum()) {
-    return "Thrift.Type.I32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "Thrift.Type.STRUCT";
-  } else if (type->is_map()) {
-    return "Thrift.Type.MAP";
-  } else if (type->is_set()) {
-    return "Thrift.Type.SET";
-  } else if (type->is_list()) {
-    return "Thrift.Type.LIST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-
-THRIFT_REGISTER_GENERATOR(js, "Javascript",
-"    jquery:          Generate jQuery compatible code.\n"
-"    node:            Generate node.js compatible code.\n")
-
diff --git a/compiler/cpp/src/generate/t_ocaml_generator.cc b/compiler/cpp/src/generate/t_ocaml_generator.cc
deleted file mode 100644
index 8ee870f..0000000
--- a/compiler/cpp/src/generate/t_ocaml_generator.cc
+++ /dev/null
@@ -1,1897 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sstream>
-#include "t_oop_generator.h"
-#include "platform.h"
-#include "version.h"
-
-using std::ios;
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * OCaml code generator.
- *
- */
-class t_ocaml_generator : public t_oop_generator {
- public:
-  t_ocaml_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_oop_generator(program)
-  {
-    (void) parsed_options;
-    (void) option_string;
-    out_dir_base_ = "gen-ocaml";
-  }
-
-  /**
-   * Init and close methods
-   */
-
-  void init_generator();
-  void close_generator();
-
-  /**
-   * Program-level generation functions
-   */
-  void generate_program  ();
-  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);
-  bool struct_member_persistent(t_field *tmember);
-  bool struct_member_omitable(t_field *tmember);
-  bool struct_member_default_cheaply_comparable(t_field *tmember);
-  std::string struct_member_copy_of(t_type *type, string what);
-
-  /**
-   * Struct generation code
-   */
-
-  void generate_ocaml_struct(t_struct* tstruct, bool is_exception);
-  void generate_ocaml_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
-  void generate_ocaml_struct_member(std::ofstream& out, string tname, t_field* tmember);
-  void generate_ocaml_struct_sig(std::ofstream& out, t_struct* tstruct, bool is_exception);
-  void generate_ocaml_struct_reader(std::ofstream& out, t_struct* tstruct);
-  void generate_ocaml_struct_writer(std::ofstream& out, t_struct* tstruct);
-  void generate_ocaml_function_helpers(t_function* tfunction);
-  void generate_ocaml_method_copy(std::ofstream& out, const vector<t_field *>& members);
-  void generate_ocaml_member_copy(std::ofstream& out, t_field *member);
-
-  /**
-   * 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_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,
-                                          std::string prefix);
-
-  void generate_deserialize_struct       (std::ofstream &out,
-                                          t_struct*   tstruct);
-
-  void generate_deserialize_container    (std::ofstream &out,
-                                          t_type*     ttype);
-
-  void generate_deserialize_set_element  (std::ofstream &out,
-                                          t_set*      tset);
-
-
-  void generate_deserialize_list_element (std::ofstream &out,
-                                          t_list*     tlist,
-                                          std::string prefix="");
-  void generate_deserialize_type          (std::ofstream &out,
-                                           t_type* type);
-
-  void generate_serialize_field          (std::ofstream &out,
-                                          t_field*    tfield,
-                                          std::string name= "");
-
-  void generate_serialize_struct         (std::ofstream &out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_serialize_container      (std::ofstream &out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_serialize_map_element    (std::ofstream &out,
-                                          t_map*      tmap,
-                                          std::string kiter,
-                                          std::string viter);
-
-  void generate_serialize_set_element    (std::ofstream &out,
-                                          t_set*      tmap,
-                                          std::string iter);
-
-  void generate_serialize_list_element   (std::ofstream &out,
-                                          t_list*     tlist,
-                                          std::string iter);
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string ocaml_autogen_comment();
-  std::string ocaml_imports();
-  std::string type_name(t_type* ttype);
-  std::string function_signature(t_function* tfunction, std::string prefix="");
-  std::string function_type(t_function* tfunc, bool method=false, bool options = false);
-  std::string argument_list(t_struct* tstruct);
-  std::string type_to_enum(t_type* ttype);
-  std::string render_ocaml_type(t_type* type);
-
-
- private:
-
-  /**
-   * File streams
-   */
-
-  std::ofstream f_types_;
-  std::ofstream f_consts_;
-  std::ofstream f_service_;
-
-  std::ofstream f_types_i_;
-  std::ofstream f_service_i_;
-
-};
-
-
-/*
- * This is necessary because we want typedefs to appear later,
- * after all the types have been declared.
- */
-void t_ocaml_generator::generate_program() {
-  // Initialize the generator
-  init_generator();
-
-  // Generate enums
-  vector<t_enum*> enums = program_->get_enums();
-  vector<t_enum*>::iterator en_iter;
-  for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
-    generate_enum(*en_iter);
-  }
-
-  // Generate structs
-  vector<t_struct*> structs = program_->get_structs();
-  vector<t_struct*>::iterator st_iter;
-  for (st_iter = structs.begin(); st_iter != structs.end(); ++st_iter) {
-    generate_struct(*st_iter);
-  }
-
-  // Generate xceptions
-  vector<t_struct*> xceptions = program_->get_xceptions();
-  vector<t_struct*>::iterator x_iter;
-  for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-    generate_xception(*x_iter);
-  }
-
-  // Generate typedefs
-  vector<t_typedef*> typedefs = program_->get_typedefs();
-  vector<t_typedef*>::iterator td_iter;
-  for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
-    generate_typedef(*td_iter);
-  }
-
-  // Generate services
-  vector<t_service*> services = program_->get_services();
-  vector<t_service*>::iterator sv_iter;
-  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
-    service_name_ = get_service_name(*sv_iter);
-    generate_service(*sv_iter);
-  }
-
-  // Generate constants
-  vector<t_const*> consts = program_->get_consts();
-  generate_consts(consts);
-
-  // Close the generator
-  close_generator();
-}
-
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * streams.
- *
- * @param tprogram The program to generate
- */
-void t_ocaml_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-
-  // Make output file
-  string f_types_name = get_out_dir()+program_name_+"_types.ml";
-  f_types_.open(f_types_name.c_str());
-  string f_types_i_name = get_out_dir()+program_name_+"_types.mli";
-  f_types_i_.open(f_types_i_name.c_str());
-
-  string f_consts_name = get_out_dir()+program_name_+"_consts.ml";
-  f_consts_.open(f_consts_name.c_str());
-
-  // Print header
-  f_types_ <<
-    ocaml_autogen_comment() << endl <<
-    ocaml_imports() << endl;
-  f_types_i_ <<
-    ocaml_autogen_comment() << endl <<
-    ocaml_imports() << endl;
-  f_consts_ <<
-    ocaml_autogen_comment() << endl <<
-    ocaml_imports() << endl <<
-    "open " << capitalize(program_name_)<<"_types"<< endl;
-}
-
-
-/**
- * Autogen'd comment
- */
-string t_ocaml_generator::ocaml_autogen_comment() {
-  return
-    std::string("(*\n") +
-    " Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" +
-    "\n" +
-    " DO NOT EDIT UNLESS YOU ARE SURE YOU KNOW WHAT YOU ARE DOING\n" +
-    "*)\n";
-}
-
-/**
- * Prints standard thrift imports
- */
-string t_ocaml_generator::ocaml_imports() {
-  return "open Thrift";
-}
-
-/**
- * Closes the type files
- */
-void t_ocaml_generator::close_generator() {
-  // Close types file
-  f_types_.close();
-}
-
-/**
- * Generates a typedef. Ez.
- *
- * @param ttypedef The type definition
- */
-void t_ocaml_generator::generate_typedef(t_typedef* ttypedef) {
-  f_types_ <<
-    indent() << "type "<< decapitalize(ttypedef->get_symbolic()) << " = " << render_ocaml_type(ttypedef->get_type()) << endl << endl;
-  f_types_i_ <<
-    indent() << "type "<< decapitalize(ttypedef->get_symbolic()) << " = " << render_ocaml_type(ttypedef->get_type()) << endl << endl;
-}
-
-/**
- * Generates code for an enumerated type.
- * the values.
- *
- * @param tenum The enumeration
- */
-void t_ocaml_generator::generate_enum(t_enum* tenum) {
-  indent(f_types_) << "module " << capitalize(tenum->get_name()) << " = " << endl << "struct" << endl;
-  indent(f_types_i_) << "module " << capitalize(tenum->get_name()) << " : " << endl << "sig" << endl;
-  indent_up();
-  indent(f_types_) << "type t = " << endl;
-  indent(f_types_i_) << "type t = " << endl;
-  indent_up();
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    string name = capitalize((*c_iter)->get_name());
-    indent(f_types_) << "| " << name << endl;
-    indent(f_types_i_) << "| " << name << endl;
-  }
-  indent_down();
-
-  indent(f_types_) << "let to_i = function" << endl;
-  indent(f_types_i_) << "val to_i : t -> Int32.t" << endl;
-  indent_up();
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    string name = capitalize((*c_iter)->get_name());
-    indent(f_types_) << "| " << name << " -> " << value << "l" << endl;
-  }
-  indent_down();
-
-  indent(f_types_) << "let of_i = function" << endl;
-  indent(f_types_i_) << "val of_i : Int32.t -> t" << endl;
-  indent_up();
-  for(c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    string name = capitalize((*c_iter)->get_name());
-    indent(f_types_) << "| " << value << "l -> " << name << endl;
-  }
-  indent(f_types_) << "| _ -> raise Thrift_error" << endl;
-  indent_down();
-  indent_down();
-  indent(f_types_) << "end" << endl;
-  indent(f_types_i_) << "end" << endl;
-}
-
-/**
- * Generate a constant value
- */
-void t_ocaml_generator::generate_const(t_const* tconst) {
-  t_type* type = tconst->get_type();
-  string name = decapitalize(tconst->get_name());
-  t_const_value* value = tconst->get_value();
-
-  indent(f_consts_) << "let " << name << " = " << render_const_value(type, value) << endl << 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_ocaml_generator::render_const_value(t_type* type, t_const_value* value) {
-  type = get_true_type(type);
-  std::ostringstream out;
-  // OCaml requires all floating point numbers contain a decimal point
-  out.setf(ios::showpoint);
-  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:
-      out << value->get_integer();
-      break;
-    case t_base_type::TYPE_I32:
-      out << value->get_integer() << "l";
-      break;
-    case t_base_type::TYPE_I64:
-      out << value->get_integer() << "L";
-      break;
-    case t_base_type::TYPE_DOUBLE:
-      if (value->get_type() == t_const_value::CV_INTEGER) {
-        out << value->get_integer() << ".0";
-      } 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()) {
-    t_enum* tenum = (t_enum*)type;
-    vector<t_enum_value*> constants = tenum->get_constants();
-    vector<t_enum_value*>::iterator c_iter;
-    for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-      int val = (*c_iter)->get_value();
-      if (val == value->get_integer()) {
-        indent(out) << capitalize(tenum->get_name()) << "." << capitalize((*c_iter)->get_name());
-        break;
-      }
-    }
-  } else if (type->is_struct() || type->is_xception()) {
-    string cname = type_name(type);
-    string ct = tmp("_c");
-    out << endl;
-    indent_up();
-    indent(out) << "(let " << ct << " = new " << cname << " in" << 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();
-      }
-      string fname = v_iter->first->get_string();
-      out << indent();
-      out << ct <<"#set_" << fname << " ";
-      out << render_const_value(field_type, v_iter->second);
-      out << ";" << endl;
-    }
-    indent(out) << ct << ")";
-    indent_down();
-    indent_down();
-  } 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();
-    map<t_const_value*, t_const_value*>::const_iterator v_iter;
-    string hm = tmp("_hm");
-    out << endl;
-    indent_up();
-    indent(out) << "(let " << hm << " = Hashtbl.create " << val.size() << " in" << endl;
-    indent_up();
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string key = render_const_value(ktype, v_iter->first);
-      string val = render_const_value(vtype, v_iter->second);
-      indent(out) << "Hashtbl.add " << hm << " " << key << " " << val << ";" << endl;
-    }
-    indent(out) << hm << ")";
-    indent_down();
-    indent_down();
-  } else if (type->is_list()) {
-    t_type* etype;
-    etype = ((t_list*)type)->get_elem_type();
-    out << "[" << endl;
-    indent_up();
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      out << indent();
-      out << render_const_value(etype, *v_iter);
-      out << ";" << endl;
-    }
-    indent_down();
-    indent(out) << "]";
-  } else if (type->is_set()) {
-    t_type* etype = ((t_set*)type)->get_elem_type();
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    string hm = tmp("_hm");
-    indent(out) << "(let " << hm << " = Hashtbl.create " << val.size() << " in" << endl;
-    indent_up();
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      string val = render_const_value(etype, *v_iter);
-      indent(out) << "Hashtbl.add " << hm << " " << val << " true;" << endl;
-    }
-    indent(out) << hm << ")" << endl;
-    indent_down();
-    out << endl;
-  } else {
-    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
-  }
-  return out.str();
-}
-
-/**
- * Generates a "struct"
- */
-void t_ocaml_generator::generate_struct(t_struct* tstruct) {
-  generate_ocaml_struct(tstruct, false);
-}
-
-/**
- * Generates a struct definition for a thrift exception. Basically the same
- * as a struct, but also has an exception declaration.
- *
- * @param txception The struct definition
- */
-void t_ocaml_generator::generate_xception(t_struct* txception) {
-  generate_ocaml_struct(txception, true);
-}
-
-/**
- * Generates an OCaml struct
- */
-void t_ocaml_generator::generate_ocaml_struct(t_struct* tstruct,
-                                              bool is_exception) {
-  generate_ocaml_struct_definition(f_types_, tstruct, is_exception);
-  generate_ocaml_struct_sig(f_types_i_,tstruct,is_exception);
-}
-
-void t_ocaml_generator::generate_ocaml_method_copy(ofstream& out,
-                                                   const vector<t_field *>& members) {
-    vector<t_field*>::const_iterator m_iter;
-
-    /* Create a copy of the current object */
-    indent(out) << "method copy =" << endl;
-    indent_up(); indent_up();
-    indent(out) << "let _new = Oo.copy self in" << endl;
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
-        generate_ocaml_member_copy(out, *m_iter);
-
-    indent_down();
-    indent(out) << "_new" << endl;
-    indent_down();
-}
-
-string t_ocaml_generator::struct_member_copy_of(t_type *type, string what) {
-    if (type->is_struct() || type->is_xception()) {
-        return what + string ("#copy");
-    } if (type->is_map()) {
-        string copy_of_k = struct_member_copy_of(((t_map *)type)->get_key_type(), "k");
-        string copy_of_v = struct_member_copy_of(((t_map *)type)->get_val_type(), "v");
-
-        if(copy_of_k == "k" && copy_of_v == "v") {
-                return string ("(Hashtbl.copy ") + what + string(")");
-        } else {
-                return string ("((fun oh -> let nh = Hashtbl.create (Hashtbl.length oh) in Hashtbl.iter (fun k v -> Hashtbl.add nh ")
-                    + copy_of_k + string(" ") + copy_of_v
-                    + string(") oh; nh) ")
-                    + what + ")";
-        }
-    } if (type->is_set()) {
-        string copy_of = struct_member_copy_of(((t_set *)type)->get_elem_type(), "k");
-
-        if(copy_of == "k") {
-                return string ("(Hashtbl.copy ") + what + string(")");
-        } else {
-                return string ("((fun oh -> let nh = Hashtbl.create (Hashtbl.length oh) in Hashtbl.iter (fun k v -> Hashtbl.add nh ")
-                    + copy_of + string(" true")
-                    + string(") oh; nh) ")
-                    + what + ")";
-        }
-    } if (type->is_list()) {
-        string copy_of = struct_member_copy_of(((t_list *)type)->get_elem_type(), "x");
-        if(copy_of != "x") {
-            return string("(List.map (fun x -> ")
-                + copy_of + string (") ")
-                + what + string(")");
-        } else {
-            return what;
-        }
-    }
-    return what;
-}
-
-void t_ocaml_generator::generate_ocaml_member_copy(ofstream& out,
-                                                   t_field *tmember) {
-    string mname = decapitalize(tmember->get_name());
-    t_type* type = get_true_type(tmember->get_type());
-
-    string grab_field = string("self#grab_") + mname;
-    string copy_of = struct_member_copy_of(type, grab_field);
-    if(copy_of != grab_field) {
-        indent(out);
-        if(!struct_member_persistent(tmember)) {
-                out << "if _" << mname << " <> None then" << endl;
-                indent(out) << "  ";
-        }
-        out << "_new#set_" << mname << " " << copy_of << ";" << endl;
-    }
-}
-
-/**
- * Generates a struct definition for a thrift data type.
- *
- * @param tstruct The struct definition
- */
-void t_ocaml_generator::generate_ocaml_struct_definition(ofstream& out,
-                                                         t_struct* tstruct,
-                                                         bool is_exception) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  string tname = type_name(tstruct);
-  indent(out) << "class " << tname << " =" << endl;
-  indent(out) << "object (self)" << endl;
-
-  indent_up();
-
-  if (members.size() > 0) {
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      generate_ocaml_struct_member(out, tname, (*m_iter));
-      out << endl;
-    }
-  }
-  generate_ocaml_method_copy(out, members);
-  generate_ocaml_struct_writer(out, tstruct);
-  indent_down();
-  indent(out) << "end" << endl;
-
-  if(is_exception){
-    indent(out) << "exception " << capitalize(tname) <<" of " << tname << endl;
-  }
-
-  generate_ocaml_struct_reader(out, tstruct);
-}
-
-/**
- * Generates a structure member for a thrift data type.
- *
- * @param tname Name of the parent structure for the member
- * @param tmember Member definition
- */
-void t_ocaml_generator::generate_ocaml_struct_member(ofstream& out,
-                                                     string tname,
-                                                     t_field* tmember) {
-  string x = tmp("_x");
-  string mname = decapitalize(tmember->get_name());
-
-  indent(out) << "val mutable _" << mname << " : " << render_ocaml_type(tmember->get_type());
-  t_const_value *val = tmember->get_value();
-  if(val) {
-    if(struct_member_persistent(tmember))
-        out << " = " << render_const_value(tmember->get_type(), tmember->get_value()) << endl;
-    else
-        out << " option = Some " << render_const_value(tmember->get_type(), tmember->get_value()) << endl;
-  } else {
-    // assert(!struct_member_persistent(tmember))
-    out << " option = None" << endl;
-  }
-
-  if(struct_member_persistent(tmember)) {
-        indent(out) << "method get_" << mname << " = Some _" << mname << endl;
-        indent(out) << "method grab_" << mname << " = _" << mname << endl;
-        indent(out) << "method set_" << mname << " " << x << " = _" << mname << " <- " << x << endl;
-  } else {
-        indent(out) << "method get_" << mname << " = _" << mname << endl;
-        indent(out) << "method grab_" << mname << " = match _"<<mname<<" with None->raise (Field_empty \""<<tname<<"."<<mname<<"\") | Some " << x <<" -> " << x << endl;
-        indent(out) << "method set_" << mname << " " << x << " = _" << mname << " <- Some " << x << endl;
-        indent(out) << "method unset_" << mname << " = _" << mname << " <- None" << endl;
-  }
-
-  indent(out) << "method reset_" << mname << " = _" << mname << " <- ";
-  if(val) {
-    if(struct_member_persistent(tmember))
-        out << render_const_value(tmember->get_type(), tmember->get_value()) << endl;
-    else
-        out << "Some " << render_const_value(tmember->get_type(), tmember->get_value()) << endl;
-  } else {
-    out << "None" << endl;
-  }
-
-
-}
-
-/**
- * Check whether a member of the structure can not have undefined value
- *
- * @param tmember Member definition
- */
-bool t_ocaml_generator::struct_member_persistent(t_field *tmember) {
-  t_const_value *val = tmember->get_value();
-  return (val ? true : false);
-}
-
-/**
- * Check whether a member of the structure can be skipped during encoding
- *
- * @param tmember Member definition
- */
-bool t_ocaml_generator::struct_member_omitable(t_field *tmember) {
-  return (tmember->get_req() != t_field::T_REQUIRED);
-}
-
-/**
- * Figure out whether a member of the structure has
- * a cheaply comparable default value.
- *
- * @param tmember Member definition
- */
-bool t_ocaml_generator::struct_member_default_cheaply_comparable(t_field *tmember) {
-  t_type* type = get_true_type(tmember->get_type());
-  t_const_value *val = tmember->get_value();
-  if(!val) {
-    return false;
-  } else if(type->is_base_type()) {
-    // Base types are generally cheaply compared for structural equivalence.
-    switch(((t_base_type*)type)->get_base()) {
-    case t_base_type::TYPE_DOUBLE:
-        if(val->get_double() == 0.0)
-                return true;
-        else
-                return false;
-    default:
-        return true;
-    }
-  } else if(type->is_list()) {
-    // Empty lists are cheaply compared for structural equivalence.
-    // Is empty list?
-    if(val->get_list().size() == 0)
-        return true;
-    else
-        return false;
-  } else {
-    return false;
-  }
-}
-
-/**
- * Generates a struct definition for a thrift data type.
- *
- * @param tstruct The struct definition
- */
-void t_ocaml_generator::generate_ocaml_struct_sig(ofstream& out,
-                                                  t_struct* tstruct,
-                                                  bool is_exception) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  string tname = type_name(tstruct);
-  indent(out) << "class " << tname << " :" << endl;
-  indent(out) << "object ('a)" << endl;
-
-  indent_up();
-
-  string x = tmp("_x");
-  if (members.size() > 0) {
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      string mname = decapitalize((*m_iter)->get_name());
-      string type = render_ocaml_type((*m_iter)->get_type());
-      indent(out) << "method get_" << mname << " : " << type << " option" << endl;
-      indent(out) << "method grab_" << mname << " : " << type << endl;
-      indent(out) << "method set_" << mname << " : " << type << " -> unit" << endl;
-      if(!struct_member_persistent(*m_iter))
-        indent(out) << "method unset_" << mname << " : unit" << endl;
-      indent(out) << "method reset_" << mname << " : unit" << endl;
-    }
-  }
-  indent(out) << "method copy : 'a" << endl;
-  indent(out) << "method write : Protocol.t -> unit" << endl;
-  indent_down();
-  indent(out) << "end" << endl;
-
-  if(is_exception){
-    indent(out) << "exception " << capitalize(tname) <<" of " << tname << endl;
-  }
-
-  indent(out) << "val read_" << tname << " : Protocol.t -> " << tname << endl;
-}
-
-/**
- * Generates the read method for a struct
- */
-void t_ocaml_generator::generate_ocaml_struct_reader(ofstream& out, t_struct* tstruct) {
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  string sname = type_name(tstruct);
-  string str = tmp("_str");
-  string t = tmp("_t");
-  string id = tmp("_id");
-  indent(out) <<
-    "let rec read_" << sname << " (iprot : Protocol.t) =" << endl;
-  indent_up();
-  indent(out) << "let " << str << " = new " << sname << " in" << endl;
-  indent_up();
-  indent(out) <<
-    "ignore(iprot#readStructBegin);" << endl;
-
-  // Loop over reading in fields
-  indent(out) <<
-    "(try while true do" << endl;
-  indent_up();
-  indent_up();
-
-  // Read beginning field marker
-  indent(out) <<
-    "let (_," << t <<","<<id<<") = iprot#readFieldBegin in" << endl;
-
-  // Check for field STOP marker and break
-  indent(out) <<
-    "if " << t <<" = Protocol.T_STOP then" << endl;
-  indent_up();
-  indent(out) <<
-      "raise Break" << endl;
-    indent_down();
-    indent(out) << "else ();" << endl;
-
-    indent(out) << "(match " << id<<" with " << endl;
-    indent_up();
-    // Generate deserialization code for known cases
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      indent(out) << "| " << (*f_iter)->get_key() << " -> (";
-      out << "if " << t <<" = " << type_to_enum((*f_iter)->get_type()) << " then" << endl;
-      indent_up();
-      indent_up();
-      generate_deserialize_field(out, *f_iter,str);
-      indent_down();
-      out <<
-        indent() << "else" << endl <<
-        indent() << "  iprot#skip "<< t << ")" << endl;
-      indent_down();
-    }
-
-    // In the default case we skip the field
-    out <<
-      indent() << "| _ -> " << "iprot#skip "<<t<<");" << endl;
-    indent_down();
-    // Read field end marker
-    indent(out) << "iprot#readFieldEnd;" << endl;
-    indent_down();
-    indent(out) << "done; ()" << endl;
-    indent_down();
-    indent(out) << "with Break -> ());" << endl;
-
-    indent(out) <<
-      "iprot#readStructEnd;" << endl;
-
-    indent(out) << str << endl << endl;
-    indent_down();
-    indent_down();
-}
-
-void t_ocaml_generator::generate_ocaml_struct_writer(ofstream& out,
-                                               t_struct* tstruct) {
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-  string str = tmp("_str");
-  string f = tmp("_f");
-
-  indent(out) <<
-    "method write (oprot : Protocol.t) =" << endl;
-  indent_up();
-  indent(out) <<
-    "oprot#writeStructBegin \""<<name<<"\";" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field *tmember = (*f_iter);
-    string mname = "_"+decapitalize(tmember->get_name());
-    string _v;
-
-    if(struct_member_persistent(tmember)) {
-
-      if(struct_member_omitable(tmember)
-        && struct_member_default_cheaply_comparable(tmember)) {
-        _v = "_v";
-        // Avoid redundant encoding of members having default values.
-        indent(out) << "(match " << mname << " with "
-            << render_const_value(tmember->get_type(), tmember->get_value())
-            << " -> () | " << _v << " -> " << endl;
-      } else {
-        _v = mname;
-        indent(out) << "(" << endl;
-      }
-
-    } else {
-
-      indent(out) << "(match " << mname << " with ";
-
-      if(struct_member_omitable(tmember)) {
-        out << "None -> ()";
-
-        if(struct_member_default_cheaply_comparable(tmember)) {
-          // Avoid redundant encoding of members having default values.
-          out << " | Some "
-              << render_const_value(tmember->get_type(), tmember->get_value())
-              << " -> ()";
-        }
-        out << " | Some _v -> " << endl;
-      } else {
-        out << endl;
-        indent(out) << "| None -> raise (Field_empty \""
-                    << type_name(tstruct) << "." << mname << "\")" << endl;
-        indent(out) << "| Some _v -> " << endl;
-      }
-
-      _v = "_v";
-    }
-    indent_up();
-    // Write field header
-    indent(out) << "oprot#writeFieldBegin(\""<< tmember->get_name()<<"\","
-                << type_to_enum(tmember->get_type()) << ","
-                << tmember->get_key()<<");" << endl;
-
-    // Write field contents
-    generate_serialize_field(out, tmember, _v);
-
-    // Write field closer
-    indent(out) << "oprot#writeFieldEnd" << endl;
-
-    indent_down();
-    indent(out) << ");" << endl;
-  }
-
-  // Write the struct map
-  out <<
-    indent() << "oprot#writeFieldStop;" << endl <<
-    indent() << "oprot#writeStructEnd" << endl;
-
-  indent_down();
-}
-
-/**
- * Generates a thrift service.
- *
- * @param tservice The service definition
- */
-void t_ocaml_generator::generate_service(t_service* tservice) {
-  string f_service_name = get_out_dir()+capitalize(service_name_)+".ml";
-  f_service_.open(f_service_name.c_str());
-  string f_service_i_name = get_out_dir()+capitalize(service_name_)+".mli";
-  f_service_i_.open(f_service_i_name.c_str());
-
-  f_service_ <<
-    ocaml_autogen_comment() << endl <<
-    ocaml_imports() << endl;
-  f_service_i_ <<
-    ocaml_autogen_comment() << endl <<
-    ocaml_imports() << endl;
-
-  /* if (tservice->get_extends() != NULL) {
-    f_service_ <<
-      "open " << capitalize(tservice->get_extends()->get_name()) << endl;
-    f_service_i_ <<
-      "open " << capitalize(tservice->get_extends()->get_name()) << endl;
-  }
-  */
-  f_service_ <<
-     "open " << capitalize(program_name_) << "_types" << endl <<
-    endl;
-
-  f_service_i_ <<
-     "open " << capitalize(program_name_) << "_types" << endl <<
-    endl;
-
-  // Generate the three main parts of the service
-  generate_service_helpers(tservice);
-  generate_service_interface(tservice);
-  generate_service_client(tservice);
-  generate_service_server(tservice);
-
-
-  // Close service file
-  f_service_.close();
-  f_service_i_.close();
-}
-
-/**
- * Generates helper functions for a service.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_ocaml_generator::generate_service_helpers(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  indent(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_ocaml_struct_definition(f_service_, ts, false);
-    generate_ocaml_function_helpers(*f_iter);
-  }
-}
-
-/**
- * Generates a struct and helpers for a function.
- *
- * @param tfunction The function
- */
-void t_ocaml_generator::generate_ocaml_function_helpers(t_function* tfunction) {
-  t_struct result(program_, decapitalize(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_ocaml_struct_definition(f_service_, &result, false);
-}
-
-/**
- * Generates a service interface definition.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_ocaml_generator::generate_service_interface(t_service* tservice) {
-  f_service_ <<
-    indent() << "class virtual iface =" << endl << "object (self)" << endl;
-  f_service_i_ <<
-    indent() << "class virtual iface :" << endl << "object" << endl;
-
-  indent_up();
-
-  if (tservice->get_extends() != NULL) {
-    string extends = type_name(tservice->get_extends());
-    indent(f_service_) << "inherit " << extends << ".iface" << endl;
-    indent(f_service_i_) << "inherit " << extends << ".iface" << endl;
-  }
-
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    string ft = function_type(*f_iter,true,true);
-    f_service_ <<
-      indent() << "method virtual " << decapitalize((*f_iter)->get_name()) << " : " << ft  << endl;
-    f_service_i_ <<
-      indent() << "method virtual " << decapitalize((*f_iter)->get_name()) << " : " << ft << endl;
-  }
-  indent_down();
-  indent(f_service_) << "end" << endl << endl;
-  indent(f_service_i_) << "end" << endl << endl;
-}
-
-/**
- * Generates a service client definition. Note that in OCaml, the client doesn't implement iface. This is because
- * The client does not (and should not have to) deal with arguments being None.
- *
- * @param tservice The service to generate a server for.
- */
-void t_ocaml_generator::generate_service_client(t_service* tservice) {
-  string extends = "";
-  indent(f_service_) <<
-    "class client (iprot : Protocol.t) (oprot : Protocol.t) =" << endl << "object (self)" << endl;
-  indent(f_service_i_) <<
-    "class client : Protocol.t -> Protocol.t -> " << endl << "object" << endl;
-  indent_up();
-
-
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    indent(f_service_) << "inherit " << extends << ".client iprot oprot as super" << endl;
-    indent(f_service_i_) << "inherit " << extends << ".client" << endl;
-  }
-  indent(f_service_) << "val mutable seqid = 0" << 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 = (*f_iter)->get_name();
-
-    // Open function
-    indent(f_service_) <<
-      "method " << function_signature(*f_iter) << " = " << endl;
-    indent(f_service_i_) <<
-      "method " << decapitalize((*f_iter)->get_name()) << " : " << function_type(*f_iter,true,false) << endl;
-    indent_up();
-    indent(f_service_) <<
-      "self#send_" << funname;
-
-
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      f_service_ << " " << decapitalize((*fld_iter)->get_name());
-    }
-    f_service_ << ";" << endl;
-
-    if (!(*f_iter)->is_oneway()) {
-      f_service_ << indent();
-      f_service_ <<
-        "self#recv_" << funname << endl;
-    }
-    indent_down();
-
-    indent(f_service_) <<
-      "method private send_" << function_signature(*f_iter) << " = " << endl;
-    indent_up();
-
-    std::string argsname = decapitalize((*f_iter)->get_name() + "_args");
-
-    // Serialize the request header
-    f_service_ <<
-      indent() << "oprot#writeMessageBegin (\"" << (*f_iter)->get_name() << "\", Protocol.CALL, seqid);" << endl;
-
-    f_service_ <<
-      indent() << "let args = new " << argsname << " in" << endl;
-    indent_up();
-
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      f_service_ <<
-        indent() << "args#set_" << (*fld_iter)->get_name() << " " << (*fld_iter)->get_name() << ";" << endl;
-    }
-
-    // Write to the stream
-    f_service_ <<
-      indent() << "args#write oprot;" << endl <<
-      indent() << "oprot#writeMessageEnd;" << endl <<
-      indent() << "oprot#getTransport#flush" << endl;
-
-    indent_down();
-    indent_down();
-
-    if (!(*f_iter)->is_oneway()) {
-      std::string resultname = decapitalize((*f_iter)->get_name() + "_result");
-      t_struct noargs(program_);
-
-      t_function recv_function((*f_iter)->get_returntype(),
-                               string("recv_") + (*f_iter)->get_name(),
-                               &noargs);
-      // Open function
-      f_service_ <<
-        indent() << "method private " << function_signature(&recv_function) << " =" << endl;
-      indent_up();
-
-      // TODO(mcslee): Validate message reply here, seq ids etc.
-
-      f_service_ <<
-        indent() << "let (fname, mtype, rseqid) = iprot#readMessageBegin in" << endl;
-      indent_up();
-      f_service_ <<
-        indent() << "(if mtype = Protocol.EXCEPTION then" << endl <<
-        indent() << "  let x = Application_Exn.read iprot in" << endl;
-      indent_up();
-      f_service_ <<
-        indent() << "  (iprot#readMessageEnd;" <<
-        indent() << "   raise (Application_Exn.E x))" << endl;
-      indent_down();
-      f_service_ <<
-        indent() << "else ());" << endl;
-      string res = "_";
-
-      t_struct* xs = (*f_iter)->get_xceptions();
-      const std::vector<t_field*>& xceptions = xs->get_members();
-
-      if (!(*f_iter)->get_returntype()->is_void() || xceptions.size() > 0) {
-        res = "result";
-      }
-      f_service_ <<
-        indent() << "let "<<res<<" = read_" << resultname << " iprot in" << endl;
-      indent_up();
-      f_service_ <<
-        indent() << "iprot#readMessageEnd;" << endl;
-
-      // Careful, only return _result if not a void function
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_ <<
-          indent() << "match result#get_success with Some v -> v | None -> (" << endl;
-        indent_up();
-      }
-
-
-      vector<t_field*>::const_iterator x_iter;
-      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-        f_service_ <<
-          indent() << "(match result#get_" << (*x_iter)->get_name() << " with None -> () | Some _v ->" << endl;
-        indent(f_service_) << "  raise (" << capitalize(type_name((*x_iter)->get_type())) << " _v));" << endl;
-      }
-
-      // Careful, only return _result if not a void function
-      if ((*f_iter)->get_returntype()->is_void()) {
-        indent(f_service_) <<
-          "()" << endl;
-      } else {
-        f_service_ <<
-          indent() << "raise (Application_Exn.E (Application_Exn.create Application_Exn.MISSING_RESULT \"" << (*f_iter)->get_name() << " failed: unknown result\")))" << endl;
-        indent_down();
-      }
-
-      // Close function
-      indent_down();
-      indent_down();
-      indent_down();
-    }
-  }
-
-  indent_down();
-  indent(f_service_) << "end" << endl << endl;
-  indent(f_service_i_) << "end" << endl << endl;
-}
-
-/**
- * Generates a service server definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_ocaml_generator::generate_service_server(t_service* tservice) {
-  // Generate the dispatch methods
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-
-  // Generate the header portion
-  indent(f_service_) <<
-    "class processor (handler : iface) =" << endl << indent() << "object (self)" << endl;
-  indent(f_service_i_) <<
-    "class processor : iface ->" << endl << indent() << "object" << endl;
-  indent_up();
-
-  f_service_ <<
-     indent() << "inherit Processor.t" << endl <<
-    endl;
-  f_service_i_ <<
-     indent() << "inherit Processor.t" << endl <<
-    endl;
-  string extends = "";
-
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    indent(f_service_) << "inherit " + extends + ".processor (handler :> " + extends + ".iface)" << endl;
-    indent(f_service_i_) << "inherit " + extends + ".processor" << endl;
-  }
-
-  if (extends.empty()) {
-    indent(f_service_) << "val processMap = Hashtbl.create " << functions.size() << endl;
-  }
-  indent(f_service_i_) << "val processMap : (string, int * Protocol.t * Protocol.t -> unit) Hashtbl.t" << endl;
-
-  // Generate the server implementation
-  indent(f_service_) <<
-    "method process iprot oprot =" << endl;
-  indent(f_service_i_) <<
-    "method process : Protocol.t -> Protocol.t -> bool" << endl;
-  indent_up();
-
-  f_service_ <<
-    indent() << "let (name, typ, seqid)  = iprot#readMessageBegin in" << endl;
-  indent_up();
-  // TODO(mcslee): validate message
-
-  // HOT: dictionary function lookup
-  f_service_ <<
-    indent() << "if Hashtbl.mem processMap name then" << endl <<
-    indent() << "  (Hashtbl.find processMap name) (seqid, iprot, oprot)" << endl <<
-    indent() << "else (" << endl <<
-    indent() << "  iprot#skip(Protocol.T_STRUCT);" << endl <<
-    indent() << "  iprot#readMessageEnd;" << endl <<
-    indent() << "  let x = Application_Exn.create Application_Exn.UNKNOWN_METHOD (\"Unknown function \"^name) in" << endl <<
-    indent() << "    oprot#writeMessageBegin(name, Protocol.EXCEPTION, seqid);" << endl <<
-    indent() << "    x#write oprot;" << endl <<
-    indent() << "    oprot#writeMessageEnd;" << endl <<
-    indent() << "    oprot#getTransport#flush" << endl <<
-    indent() << ");" << endl;
-
-  // Read end of args field, the T_STOP, and the struct close
-  f_service_ <<
-    indent() << "true" << endl;
-  indent_down();
-  indent_down();
-  // Generate the process subfunctions
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_process_function(tservice, *f_iter);
-  }
-
-  indent(f_service_) << "initializer" << endl;
-  indent_up();
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_service_ <<
-      indent() << "Hashtbl.add processMap \"" << (*f_iter)->get_name() << "\" self#process_" << (*f_iter)->get_name() << ";" << endl;
-  }
-  indent_down();
-
-  indent_down();
-  indent(f_service_) << "end" << endl << endl;
-  indent(f_service_i_) << "end" << endl << endl;
-}
-
-/**
- * Generates a process function definition.
- *
- * @param tfunction The function to write a dispatcher for
- */
-void t_ocaml_generator::generate_process_function(t_service* tservice,
-                                               t_function* tfunction) {
-  (void) tservice;
-  // Open function
-  indent(f_service_) <<
-    "method private process_" << tfunction->get_name() <<
-    " (seqid, iprot, oprot) =" << endl;
-  indent_up();
-
-  string argsname = decapitalize(tfunction->get_name()) + "_args";
-  string resultname = decapitalize(tfunction->get_name()) + "_result";
-
-  // 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;
-
-  string args = "args";
-  if(fields.size() == 0){
-    args="_";
-  }
-
-  f_service_ <<
-    indent() << "let "<<args<<" = read_" << argsname << " iprot in" << endl;
-  indent_up();
-  f_service_ <<
-    indent() << "iprot#readMessageEnd;" << endl;
-
-  t_struct* xs = tfunction->get_xceptions();
-  const std::vector<t_field*>& xceptions = xs->get_members();
-  vector<t_field*>::const_iterator x_iter;
-
-  // Declare result for non oneway function
-  if (!tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << "let result = new " << resultname << " in" << endl;
-    indent_up();
-  }
-
-  // Try block for a function with exceptions
-  if (xceptions.size() > 0) {
-    f_service_ <<
-      indent() << "(try" << endl;
-    indent_up();
-  }
-
-
-
-
-  f_service_ << indent();
-  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
-    f_service_ << "result#set_success ";
-  }
-  f_service_ <<
-    "(handler#" << tfunction->get_name();
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    f_service_ <<  " args#get_" << (*f_iter)->get_name();
-  }
-  f_service_ << ");" << endl;
-
-
-  if (xceptions.size() > 0) {
-    indent_down();
-    indent(f_service_) << "with" <<endl;
-    indent_up();
-    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      f_service_ <<
-        indent() << "| " << capitalize(type_name((*x_iter)->get_type())) << " " << (*x_iter)->get_name() << " -> " << endl;
-      indent_up();
-      indent_up();
-      if(!tfunction->is_oneway()){
-           f_service_ <<
-             indent() << "result#set_" << (*x_iter)->get_name() << " " << (*x_iter)->get_name() << endl;
-      } else {
-        indent(f_service_) << "()";
-      }
-      indent_down();
-      indent_down();
-    }
-    indent_down();
-    f_service_ << indent() << ");" << endl;
-  }
-
-
-
-  // Shortcut out here for oneway functions
-  if (tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << "()" << endl;
-    indent_down();
-    indent_down();
-    return;
-  }
-
-  f_service_ <<
-    indent() << "oprot#writeMessageBegin (\"" << tfunction->get_name() << "\", Protocol.REPLY, seqid);" << endl <<
-    indent() << "result#write oprot;" << endl <<
-    indent() << "oprot#writeMessageEnd;" << endl <<
-    indent() << "oprot#getTransport#flush" << endl;
-
-  // Close function
-  indent_down();
-  indent_down();
-  indent_down();
-}
-
-/**
- * Deserializes a field of any type.
- */
-void t_ocaml_generator::generate_deserialize_field(ofstream &out,
-                                                   t_field* tfield,
-                                                   string prefix){
-  t_type* type = tfield->get_type();
-
-
-  string name = decapitalize(tfield->get_name());
-  indent(out) << prefix << "#set_"<<name << " ";
-  generate_deserialize_type(out,type);
-  out << endl;
-}
-
-
-/**
- * Deserializes a field of any type.
- */
-void t_ocaml_generator::generate_deserialize_type(ofstream &out,
-                                                   t_type* type){
-  type = get_true_type(type);
-
-  if (type->is_void()) {
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE";
-  }
-
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct(out,
-                                (t_struct*)type);
-  } else if (type->is_container()) {
-    generate_deserialize_container(out, type);
-  } else if (type->is_base_type()) {
-    out << "iprot#";
-    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";
-      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 PHP name for base type " + t_base_type::t_base_name(tbase);
-    }
-  } else if (type->is_enum()) {
-    string ename = capitalize(type->get_name());
-    out << "(" <<ename << ".of_i iprot#readI32)";
-  } else {
-    printf("DO NOT KNOW HOW TO DESERIALIZE TYPE '%s'\n",
-           type->get_name().c_str());
-  }
-}
-
-
-/**
- * Generates an unserializer for a struct, calling read()
- */
-void t_ocaml_generator::generate_deserialize_struct(ofstream &out,
-                                                  t_struct* tstruct) {
-  string prefix = "";
-  t_program* program = tstruct->get_program();
-  if (program != NULL && program != program_) {
-     prefix = capitalize(program->get_name()) + "_types.";
-  }
-  string name = decapitalize(tstruct->get_name());
-  out << "(" << prefix << "read_" << name << " iprot)";
-
-}
-
-/**
- * Serialize a container by writing out the header followed by
- * data and then a footer.
- */
-void t_ocaml_generator::generate_deserialize_container(ofstream &out,
-                                                    t_type* ttype) {
-  string size = tmp("_size");
-  string ktype = tmp("_ktype");
-  string vtype = tmp("_vtype");
-  string etype = tmp("_etype");
-  string con = tmp("_con");
-
-  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);
-
-  out << endl;
-  indent_up();
-  // Declare variables, read header
-  if (ttype->is_map()) {
-    indent(out) << "(let ("<<ktype<<","<<vtype<<","<<size<<") = iprot#readMapBegin in" << endl;
-    indent(out) << "let "<<con<<" = Hashtbl.create "<<size<<" in" << endl;
-    indent_up();
-    indent(out) << "for i = 1 to "<<size<<" do" <<endl;
-    indent_up();
-    indent(out) << "let _k = ";
-    generate_deserialize_type(out,((t_map*)ttype)->get_key_type());
-    out << " in" << endl;
-    indent(out) << "let _v = ";
-    generate_deserialize_type(out,((t_map*)ttype)->get_val_type());
-    out << " in" << endl;
-    indent_up();
-    indent(out) << "Hashtbl.add "<<con<< " _k _v" << endl;
-    indent_down();
-    indent_down();
-    indent(out) << "done; iprot#readMapEnd; "<<con<<")";
-    indent_down();
-  } else if (ttype->is_set()) {
-    indent(out) << "(let ("<<etype<<","<<size<<") = iprot#readSetBegin in" << endl;
-    indent(out) << "let "<<con<<" = Hashtbl.create "<<size<<" in" << endl;
-    indent_up();
-    indent(out) << "for i = 1 to "<<size<<" do" <<endl;
-    indent_up();
-    indent(out) << "Hashtbl.add "<<con<<" ";
-    generate_deserialize_type(out,((t_set*)ttype)->get_elem_type());
-    out << " true" << endl;
-    indent_down();
-    indent(out) << "done; iprot#readSetEnd; "<<con<<")";
-    indent_down();
-  } else if (ttype->is_list()) {
-    indent(out) << "(let ("<<etype<<","<<size<<") = iprot#readListBegin in" << endl;
-    indent_up();
-    indent(out) << "let "<<con<<" = (Array.to_list (Array.init "<<size<<" (fun _ -> ";
-    generate_deserialize_type(out,((t_list*)ttype)->get_elem_type());
-    out << "))) in" << endl;
-    indent_up();
-    indent(out) << "iprot#readListEnd; "<<con<<")";
-    indent_down();
-    indent_down();
-  }
-  indent_down();
-}
-
-
-
-/**
- * Serializes a field of any type.
- *
- * @param tfield The field to serialize
- * @param prefix Name to prepend to field name
- */
-void t_ocaml_generator::generate_serialize_field(ofstream &out,
-                                                 t_field* tfield,
-                                                 string name) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  // Do nothing for void types
-  if (type->is_void()) {
-    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
-      tfield->get_name();
-  }
-
-  if(name.length() == 0){
-    name = decapitalize(tfield->get_name());
-  }
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_serialize_struct(out,
-                              (t_struct*)type,
-                              name);
-  } else if (type->is_container()) {
-    generate_serialize_container(out,
-                                 type,
-                                 name);
-  } else if (type->is_base_type() || type->is_enum()) {
-
-
-    indent(out) <<
-      "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(" << name << ")";
-        break;
-      case t_base_type::TYPE_BOOL:
-        out << "writeBool(" << name << ")";
-       break;
-      case t_base_type::TYPE_BYTE:
-        out << "writeByte(" << name << ")";
-        break;
-      case t_base_type::TYPE_I16:
-        out << "writeI16(" << name << ")";
-        break;
-      case t_base_type::TYPE_I32:
-        out << "writeI32(" << name << ")";
-        break;
-      case t_base_type::TYPE_I64:
-        out << "writeI64(" << name << ")";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        out << "writeDouble(" << name << ")";
-        break;
-      default:
-        throw "compiler error: no ocaml name for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      string ename = capitalize(type->get_name());
-      out << "writeI32("<<ename<<".to_i " << name << ")";
-    }
-
-  } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
-           tfield->get_name().c_str(),
-           type->get_name().c_str());
-  }
-  out << ";" << endl;
-}
-
-/**
- * Serializes all the members of a struct.
- *
- * @param tstruct The struct to serialize
- * @param prefix  String prefix to attach to all fields
- */
-void t_ocaml_generator::generate_serialize_struct(ofstream &out,
-                                               t_struct* tstruct,
-                                               string prefix) {
-  (void) tstruct;
-  indent(out) << prefix << "#write(oprot)";
-}
-
-void t_ocaml_generator::generate_serialize_container(ofstream &out,
-                                                  t_type* ttype,
-                                                  string prefix) {
-  if (ttype->is_map()) {
-    indent(out) << "oprot#writeMapBegin("<< type_to_enum(((t_map*)ttype)->get_key_type()) << ",";
-    out << type_to_enum(((t_map*)ttype)->get_val_type()) << ",";
-    out << "Hashtbl.length " << prefix << ");" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "oprot#writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ",";
-    out << "Hashtbl.length " << prefix << ");" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "oprot#writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type()) << ",";
-    out << "List.length " << prefix << ");" << endl;
-  }
-
-  if (ttype->is_map()) {
-    string kiter = tmp("_kiter");
-    string viter = tmp("_viter");
-    indent(out) << "Hashtbl.iter (fun "<<kiter<<" -> fun " << viter << " -> " << endl;
-    indent_up();
-    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
-    indent_down();
-    indent(out) << ") " << prefix << ";" << endl;
-  } else if (ttype->is_set()) {
-    string iter = tmp("_iter");
-    indent(out) << "Hashtbl.iter (fun "<<iter<<" -> fun _ -> ";
-    indent_up();
-    generate_serialize_set_element(out, (t_set*)ttype, iter);
-    indent_down();
-    indent(out) << ") " << prefix << ";" << endl;
-  } else if (ttype->is_list()) {
-    string iter = tmp("_iter");
-    indent(out) << "List.iter (fun "<<iter<<" -> ";
-    indent_up();
-    generate_serialize_list_element(out, (t_list*)ttype, iter);
-    indent_down();
-    indent(out) << ") " << prefix << ";" <<  endl;
-  }
-
-  if (ttype->is_map()) {
-    indent(out) <<
-      "oprot#writeMapEnd";
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "oprot#writeSetEnd";
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "oprot#writeListEnd";
-  }
-}
-
-/**
- * Serializes the members of a map.
- *
- */
-void t_ocaml_generator::generate_serialize_map_element(ofstream &out,
-                                                     t_map* tmap,
-                                                     string kiter,
-                                                     string viter) {
-  t_field kfield(tmap->get_key_type(), kiter);
-  generate_serialize_field(out, &kfield);
-
-  t_field vfield(tmap->get_val_type(), viter);
-  generate_serialize_field(out, &vfield);
-}
-
-/**
- * Serializes the members of a set.
- */
-void t_ocaml_generator::generate_serialize_set_element(ofstream &out,
-                                                     t_set* tset,
-                                                     string iter) {
-  t_field efield(tset->get_elem_type(), iter);
-  generate_serialize_field(out, &efield);
-}
-
-/**
- * Serializes the members of a list.
- */
-void t_ocaml_generator::generate_serialize_list_element(ofstream &out,
-                                                      t_list* tlist,
-                                                      string iter) {
-  t_field efield(tlist->get_elem_type(), iter);
-  generate_serialize_field(out, &efield);
-}
-
-
-
-/**
- * Renders a function signature of the form 'name args'
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_ocaml_generator::function_signature(t_function* tfunction,
-                                           string prefix) {
-  return
-    prefix + decapitalize(tfunction->get_name()) +
-    " " +  argument_list(tfunction->get_arglist());
-}
-
-string t_ocaml_generator::function_type(t_function* tfunc, bool method, bool options){
-  string result="";
-
-  const vector<t_field*>& fields = tfunc->get_arglist()->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    result += render_ocaml_type((*f_iter)->get_type());
-    if(options)
-      result += " option";
-    result += " -> ";
-  }
-  if(fields.empty() && !method){
-    result += "unit -> ";
-  }
-  result += render_ocaml_type(tfunc->get_returntype());
-  return result;
-}
-
-/**
- * Renders a field list
- */
-string t_ocaml_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();
-  }
-  return result;
-}
-
-string t_ocaml_generator::type_name(t_type* ttype) {
-  string prefix = "";
-  t_program* program = ttype->get_program();
-  if (program != NULL && program != program_) {
-    if (!ttype->is_service()) {
-      prefix = capitalize(program->get_name()) + "_types.";
-    }
-  }
-
-  string name = ttype->get_name();
-  if(ttype->is_service()){
-    name = capitalize(name);
-  } else {
-    name = decapitalize(name);
-  }
-  return prefix + name;
-}
-
-/**
- * Converts the parse type to a Protocol.t_type enum
- */
-string t_ocaml_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:
-      return "Protocol.T_VOID";
-    case t_base_type::TYPE_STRING:
-      return "Protocol.T_STRING";
-    case t_base_type::TYPE_BOOL:
-      return "Protocol.T_BOOL";
-    case t_base_type::TYPE_BYTE:
-      return "Protocol.T_BYTE";
-    case t_base_type::TYPE_I16:
-      return "Protocol.T_I16";
-    case t_base_type::TYPE_I32:
-      return "Protocol.T_I32";
-    case t_base_type::TYPE_I64:
-      return "Protocol.T_I64";
-    case t_base_type::TYPE_DOUBLE:
-      return "Protocol.T_DOUBLE";
-    }
-  } else if (type->is_enum()) {
-    return "Protocol.T_I32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "Protocol.T_STRUCT";
-  } else if (type->is_map()) {
-    return "Protocol.T_MAP";
-  } else if (type->is_set()) {
-    return "Protocol.T_SET";
-  } else if (type->is_list()) {
-    return "Protocol.T_LIST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-/**
- * Converts the parse type to an ocaml type
- */
-string t_ocaml_generator::render_ocaml_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:
-      return "unit";
-    case t_base_type::TYPE_STRING:
-      return "string";
-    case t_base_type::TYPE_BOOL:
-      return "bool";
-    case t_base_type::TYPE_BYTE:
-      return "int";
-    case t_base_type::TYPE_I16:
-      return "int";
-    case t_base_type::TYPE_I32:
-      return "Int32.t";
-    case t_base_type::TYPE_I64:
-      return "Int64.t";
-    case t_base_type::TYPE_DOUBLE:
-      return "float";
-    }
-  } else if (type->is_enum()) {
-    return capitalize(((t_enum*)type)->get_name())+".t";
-  } else if (type->is_struct() || type->is_xception()) {
-    return type_name((t_struct*)type);
-  } else if (type->is_map()) {
-    t_type* ktype = ((t_map*)type)->get_key_type();
-    t_type* vtype = ((t_map*)type)->get_val_type();
-    return "("+render_ocaml_type(ktype)+","+render_ocaml_type(vtype)+") Hashtbl.t";
-  } else if (type->is_set()) {
-    t_type* etype = ((t_set*)type)->get_elem_type();
-    return "("+render_ocaml_type(etype)+",bool) Hashtbl.t";
-  } else if (type->is_list()) {
-    t_type* etype = ((t_list*)type)->get_elem_type();
-    return render_ocaml_type(etype)+" list";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-
-THRIFT_REGISTER_GENERATOR(ocaml, "OCaml", "")
-
diff --git a/compiler/cpp/src/generate/t_oop_generator.h b/compiler/cpp/src/generate/t_oop_generator.h
deleted file mode 100644
index 20b73b2..0000000
--- a/compiler/cpp/src/generate/t_oop_generator.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_OOP_GENERATOR_H
-#define T_OOP_GENERATOR_H
-
-#include <string>
-#include <iostream>
-
-#include "globals.h"
-#include "t_generator.h"
-#include "version.h"
-
-#include <algorithm>
-
-/**
- * Class with utility methods shared across common object oriented languages.
- * Specifically, most of this stuff is for C++/Java.
- *
- */
-class t_oop_generator : public t_generator {
- public:
-  t_oop_generator(t_program* program) :
-    t_generator(program) {}
-
-  /**
-   * Scoping, using curly braces!
-   */
-
-  void scope_up(std::ostream& out) {
-    indent(out) << "{" << std::endl;
-    indent_up();
-  }
-
-  void scope_down(std::ostream& out) {
-    indent_down();
-    indent(out) << "}" << std::endl;
-  }
-
-  std::string upcase_string(std::string original) {
-    std::transform(original.begin(), original.end(), original.begin(), (int(*)(int)) toupper);
-    return original;
-  }
-
-  /**
-   * Generates a comment about this code being autogenerated, using C++ style
-   * comments, which are also fair game in Java / PHP, yay!
-   *
-   * @return C-style comment mentioning that this file is autogenerated.
-   */
-  virtual std::string autogen_comment() {
-    return
-      std::string("/**\n") +
-      " * Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" +
-      " *\n" +
-      " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
-      " *  @generated\n" +
-      " */\n";
-  }
-};
-
-#endif
-
diff --git a/compiler/cpp/src/generate/t_perl_generator.cc b/compiler/cpp/src/generate/t_perl_generator.cc
deleted file mode 100644
index a40f85b..0000000
--- a/compiler/cpp/src/generate/t_perl_generator.cc
+++ /dev/null
@@ -1,1821 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-#include <list>
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sstream>
-#include "t_oop_generator.h"
-#include "platform.h"
-#include "version.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * PERL code generator.
- *
- */
-class t_perl_generator : public t_oop_generator {
- public:
-  t_perl_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_oop_generator(program)
-  {
-    (void) parsed_options;
-    (void) option_string;
-    out_dir_base_ = "gen-perl";
-    escape_['$'] = "\\$";
-    escape_['@'] = "\\@";
-  }
-
-  /**
-   * 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);
-
-  /**
-   * Structs!
-   */
-
-  void generate_perl_struct(t_struct* tstruct, bool is_exception);
-  void generate_perl_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
-  void generate_perl_struct_reader(std::ofstream& out, t_struct* tstruct);
-  void generate_perl_struct_writer(std::ofstream& out, t_struct* tstruct);
-  void generate_perl_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_rest      (t_service* tservice);
-  void generate_service_client    (t_service* tservice);
-  void generate_service_processor (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,
-                                          std::string prefix="",
-                                          bool inclass=false);
-
-  void generate_deserialize_struct       (std::ofstream &out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_deserialize_container    (std::ofstream &out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_deserialize_set_element  (std::ofstream &out,
-                                          t_set*      tset,
-                                          std::string prefix="");
-
-  void generate_deserialize_map_element  (std::ofstream &out,
-                                          t_map*      tmap,
-                                          std::string prefix="");
-
-  void generate_deserialize_list_element (std::ofstream &out,
-                                          t_list*     tlist,
-                                          std::string prefix="");
-
-  void generate_serialize_field          (std::ofstream &out,
-                                          t_field*    tfield,
-                                          std::string prefix="");
-
-  void generate_serialize_struct         (std::ofstream &out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_serialize_container      (std::ofstream &out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_serialize_map_element    (std::ofstream &out,
-                                          t_map*      tmap,
-                                          std::string kiter,
-                                          std::string viter);
-
-  void generate_serialize_set_element    (std::ofstream &out,
-                                          t_set*      tmap,
-                                          std::string iter);
-
-  void generate_serialize_list_element   (std::ofstream &out,
-                                          t_list*     tlist,
-                                          std::string iter);
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string perl_includes();
-  std::string declare_field(t_field* tfield, bool init=false, bool obj=false);
-  std::string function_signature(t_function* tfunction, std::string prefix="");
-  std::string argument_list(t_struct* tstruct);
-  std::string type_to_enum(t_type* ttype);
-
-  std::string autogen_comment() {
-    return
-      std::string("#\n") +
-      "# Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" +
-      "#\n" +
-      "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
-      "#\n";
-  }
-
-  void perl_namespace_dirs(t_program* p, std::list<std::string>& dirs) {
-    std::string ns = p->get_namespace("perl");
-    std::string::size_type loc;
-
-    if (ns.size() > 0) {
-      while ((loc = ns.find(".")) != std::string::npos) {
-        dirs.push_back(ns.substr(0, loc));
-        ns = ns.substr(loc+1);
-      }
-    }
-
-    if (ns.size() > 0) {
-      dirs.push_back(ns);
-    }
-  }
-
-  std::string perl_namespace(t_program* p) {
-    std::string ns = p->get_namespace("perl");
-    std::string result = "";
-    std::string::size_type loc;
-
-    if (ns.size() > 0) {
-      while ((loc = ns.find(".")) != std::string::npos) {
-        result += ns.substr(0, loc);
-        result += "::";
-        ns = ns.substr(loc+1);
-      }
-
-      if (ns.size() > 0) {
-        result += ns + "::";
-      }
-    }
-
-    return result;
-  }
-
-  std::string get_namespace_out_dir() {
-    std::string outdir = get_out_dir();
-    std::list<std::string> dirs;
-    perl_namespace_dirs(program_, dirs);
-    std::list<std::string>::iterator it;
-    for (it = dirs.begin(); it != dirs.end(); it++) {
-      outdir += *it + "/";
-    }
-    return outdir;
-  }
-
- private:
-
-  /**
-   * File streams
-   */
-  std::ofstream f_types_;
-  std::ofstream f_consts_;
-  std::ofstream f_helpers_;
-  std::ofstream f_service_;
-
-};
-
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * streams.
- *
- * @param tprogram The program to generate
- */
-void t_perl_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-
-  string outdir = get_out_dir();
-  std::list<std::string> dirs;
-  perl_namespace_dirs(program_, dirs);
-  std::list<std::string>::iterator it;
-  for (it = dirs.begin(); it != dirs.end(); it++) {
-      outdir += *it + "/";
-      MKDIR(outdir.c_str());
-  }
-
-  // Make output file
-  string f_types_name = outdir+"Types.pm";
-  f_types_.open(f_types_name.c_str());
-  string f_consts_name = outdir+"Constants.pm";
-  f_consts_.open(f_consts_name.c_str());
-
-  // Print header
-  f_types_ <<
-    autogen_comment() <<
-    perl_includes();
-
-  // Print header
-  f_consts_ <<
-    autogen_comment() <<
-    "package "<< perl_namespace(program_) <<"Constants;"<<endl<<
-    perl_includes() <<
-    endl;
-}
-
-/**
- * Prints standard java imports
- */
-string t_perl_generator::perl_includes() {
-  string inc;
-
-  inc  = "require 5.6.0;\n";
-  inc += "use strict;\n";
-  inc += "use warnings;\n";
-  inc += "use Thrift;\n\n";
-
-  return inc;
-}
-
-/**
- * Close up (or down) some filez.
- */
-void t_perl_generator::close_generator() {
-  // Close types file
-  f_types_ << "1;" << endl;
-  f_types_.close();
-
-  f_consts_ << "1;" << endl;
-  f_consts_.close();
-}
-
-/**
- * Generates a typedef. This is not done in PERL, types are all implicit.
- *
- * @param ttypedef The type definition
- */
-void t_perl_generator::generate_typedef(t_typedef* ttypedef) {
-  (void) ttypedef;
-}
-
-/**
- * Generates code for an enumerated type. Since define is expensive to lookup
- * in PERL, we use a global array for this.
- *
- * @param tenum The enumeration
- */
-void t_perl_generator::generate_enum(t_enum* tenum) {
-  f_types_ << "package " << perl_namespace(program_) <<tenum->get_name()<<";"<<endl;
-
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    f_types_ << "use constant "<< (*c_iter)->get_name() << " => " << value << ";" << endl;
-  }
-}
-
-/**
- * Generate a constant value
- */
-void t_perl_generator::generate_const(t_const* tconst) {
-  t_type* type = tconst->get_type();
-  string name = tconst->get_name();
-  t_const_value* value = tconst->get_value();
-
-  f_consts_ << "use constant " << name << " => ";
-  f_consts_ << render_const_value(type, value);
-  f_consts_ << ";" << endl << 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_perl_generator::render_const_value(t_type* type, t_const_value* value) {
-  std::ostringstream out;
-
-  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_STRING:
-      out << '"' << get_escaped_string(value) << '"';
-      break;
-    case t_base_type::TYPE_BOOL:
-      out << (value->get_integer() > 0 ? "1" : "0");
-      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()) {
-    out << value->get_integer();
-  } else if (type->is_struct() || type->is_xception()) {
-    out << "new " << perl_namespace(type->get_program()) << type->get_name() << "({" << 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();
-      }
-      out << render_const_value(g_type_string, v_iter->first);
-      out << " => ";
-      out << render_const_value(field_type, v_iter->second);
-      out << ",";
-      out << endl;
-    }
-
-    out << "})";
-  } else if (type->is_map()) {
-    t_type* ktype = ((t_map*)type)->get_key_type();
-    t_type* vtype = ((t_map*)type)->get_val_type();
-    out << "{" << endl;
-
-    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) {
-      out << render_const_value(ktype, v_iter->first);
-      out << " => ";
-      out << render_const_value(vtype, v_iter->second);
-      out << "," << endl;
-    }
-
-    out << "}";
-  } else if (type->is_list() || type->is_set()) {
-    t_type* etype;
-    if (type->is_list()) {
-      etype = ((t_list*)type)->get_elem_type();
-    } else {
-      etype = ((t_set*)type)->get_elem_type();
-    }
-    out << "[" << endl;
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-
-      out << render_const_value(etype, *v_iter);
-      if (type->is_set()) {
-        out << " => 1";
-      }
-      out << "," << endl;
-    }
-    out << "]";
-  }
-  return out.str();
-}
-
-/**
- * Make a struct
- */
-void t_perl_generator::generate_struct(t_struct* tstruct) {
-  generate_perl_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_perl_generator::generate_xception(t_struct* txception) {
-  generate_perl_struct(txception, true);
-}
-
-/**
- * Structs can be normal or exceptions.
- */
-void t_perl_generator::generate_perl_struct(t_struct* tstruct,
-                                            bool is_exception) {
-  generate_perl_struct_definition(f_types_, tstruct, is_exception);
-}
-
-/**
- * Generates a struct definition for a thrift data type. This is nothing in PERL
- * where the objects are all just associative arrays (unless of course we
- * decide to start using objects for them...)
- *
- * @param tstruct The struct definition
- */
-void t_perl_generator::generate_perl_struct_definition(ofstream& out,
-                                                       t_struct* tstruct,
-                                                       bool is_exception) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  out <<
-      "package " << perl_namespace(tstruct->get_program()) << tstruct->get_name() <<";\n";
-  if (is_exception) {
-    out << "use base qw(Thrift::TException);\n";
-  }
-
-  //Create simple acessor methods
-  out << "use base qw(Class::Accessor);\n";
-
-  if (members.size() > 0) {
-      out << perl_namespace(tstruct->get_program()) << tstruct->get_name() <<"->mk_accessors( qw( ";
-      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-          t_type* t = get_true_type((*m_iter)->get_type());
-          if (!t->is_xception()) {
-              out << (*m_iter)->get_name() << " ";
-          }
-      }
-
-      out << ") );\n";
-  }
-
-  out << endl;
-
-  // new()
-  indent_up();
-  out <<
-    "sub new {" << endl <<
-    indent() << "my $classname = shift;" << endl <<
-    indent() << "my $self      = {};" << endl <<
-    indent() << "my $vals      = shift || {};" << endl;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    string dval = "undef";
-    t_type* t = get_true_type((*m_iter)->get_type());
-    if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) {
-      dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value());
-    }
-    out <<
-      indent() << "$self->{" << (*m_iter)->get_name() << "} = " << dval << ";" << endl;
-  }
-
-  // Generate constructor from array
-  if (members.size() > 0) {
-
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      t_type* t = get_true_type((*m_iter)->get_type());
-      if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) {
-        indent(out) << "$self->{" << (*m_iter)->get_name() << "} = " << render_const_value(t, (*m_iter)->get_value()) << ";" << endl;
-      }
-    }
-
-    out << indent() << "if (UNIVERSAL::isa($vals,'HASH')) {" << endl;
-    indent_up();
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      out <<
-        indent() << "if (defined $vals->{" << (*m_iter)->get_name() << "}) {" << endl <<
-        indent() << "  $self->{" << (*m_iter)->get_name() << "} = $vals->{" << (*m_iter)->get_name() << "};" << endl <<
-        indent() << "}" << endl;
-    }
-    indent_down();
-    out <<
-      indent() << "}" << endl;
-
-  }
-
-  out << indent() << "return bless ($self, $classname);" << endl;
-  indent_down();
-  out << "}\n\n";
-
-  out <<
-    "sub getName {" << endl <<
-    indent() << "  return '" << tstruct->get_name() << "';" << endl <<
-    indent() << "}" << endl <<
-    endl;
-
-  generate_perl_struct_reader(out, tstruct);
-  generate_perl_struct_writer(out, tstruct);
-
-}
-
-/**
- * Generates the read() method for a struct
- */
-void t_perl_generator::generate_perl_struct_reader(ofstream& out,
-                                                   t_struct* tstruct) {
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  out << "sub read {" <<endl;
-
-  indent_up();
-
-  out <<
-    indent() << "my ($self, $input) = @_;" << endl <<
-    indent() << "my $xfer  = 0;" << endl <<
-    indent() << "my $fname;"     << endl <<
-    indent() << "my $ftype = 0;" << endl <<
-    indent() << "my $fid   = 0;" << endl;
-
-  indent(out) << "$xfer += $input->readStructBegin(\\$fname);" << endl;
-
-
-  // Loop over reading in fields
-  indent(out) << "while (1) " << endl;
-
-  scope_up(out);
-
-  indent(out) << "$xfer += $input->readFieldBegin(\\$fname, \\$ftype, \\$fid);" << endl;
-
-  // Check for field STOP marker and break
-  indent(out) << "if ($ftype == TType::STOP) {" << endl;
-  indent_up();
-  indent(out) << "last;" << endl;
-  indent_down();
-  indent(out) << "}" << endl;
-
-  // Switch statement on the field we are reading
-  indent(out) << "SWITCH: for($fid)" << endl;
-
-  scope_up(out);
-
-  // Generate deserialization code for known cases
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-
-    indent(out) << "/^" << (*f_iter)->get_key() << "$/ && do{";
-    indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
-
-    indent_up();
-    generate_deserialize_field(out, *f_iter, "self->");
-    indent_down();
-
-    indent(out) << "} else {" << endl;
-
-    indent(out) <<  "  $xfer += $input->skip($ftype);" << endl;
-
-    out <<
-      indent() << "}" << endl <<
-      indent() << "last; };" << endl;
-
-  }
-  // In the default case we skip the field
-
-  indent(out) <<  "  $xfer += $input->skip($ftype);" << endl;
-
-  scope_down(out);
-
-  indent(out) << "$xfer += $input->readFieldEnd();" << endl;
-
-  scope_down(out);
-
-  indent(out) << "$xfer += $input->readStructEnd();" << endl;
-
-  indent(out) << "return $xfer;" << endl;
-
-  indent_down();
-  out << indent() << "}" << endl << endl;
-}
-
-/**
- * Generates the write() method for a struct
- */
-void t_perl_generator::generate_perl_struct_writer(ofstream& out,
-                                                   t_struct* tstruct) {
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  out << "sub write {" << endl;
-
-  indent_up();
-  indent(out) << "my ($self, $output) = @_;" << endl;
-  indent(out) << "my $xfer   = 0;" << endl;
-
-  indent(out) << "$xfer += $output->writeStructBegin('" << name << "');" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    out << indent() << "if (defined $self->{" << (*f_iter)->get_name() << "}) {" << endl;
-    indent_up();
-
-    indent(out) <<
-      "$xfer += $output->writeFieldBegin(" <<
-      "'" << (*f_iter)->get_name() << "', " <<
-      type_to_enum((*f_iter)->get_type()) << ", " <<
-      (*f_iter)->get_key() << ");" << endl;
-
-
-    // Write field contents
-    generate_serialize_field(out, *f_iter, "self->");
-
-    indent(out) <<
-        "$xfer += $output->writeFieldEnd();" << endl;
-
-    indent_down();
-    indent(out) << "}" << endl;
-  }
-
-
-  out <<
-    indent() << "$xfer += $output->writeFieldStop();" << endl <<
-    indent() << "$xfer += $output->writeStructEnd();" << endl;
-
-  out <<indent() << "return $xfer;" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-/**
- * Generates a thrift service.
- *
- * @param tservice The service definition
- */
-void t_perl_generator::generate_service(t_service* tservice) {
-  string f_service_name = get_namespace_out_dir()+service_name_+".pm";
-  f_service_.open(f_service_name.c_str());
-
-  f_service_ <<
-    ///      "package "<<service_name_<<";"<<endl<<
-    autogen_comment() <<
-    perl_includes();
-
-  f_service_ <<
-    "use " << perl_namespace(tservice->get_program()) << "Types;" << endl;
-
-  t_service* extends_s = tservice->get_extends();
-  if (extends_s != NULL) {
-    f_service_ <<
-      "use " << perl_namespace(extends_s->get_program()) << extends_s->get_name() << ";" << endl;
-  }
-
-  f_service_ <<
-    endl;
-
-  // Generate the three main parts of the service (well, two for now in PERL)
-  generate_service_helpers(tservice);
-  generate_service_interface(tservice);
-  generate_service_rest(tservice);
-  generate_service_client(tservice);
-  generate_service_processor(tservice);
-
-  // Close service file
-  f_service_ << "1;" << endl;
-  f_service_.close();
-}
-
-/**
- * Generates a service server definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_perl_generator::generate_service_processor(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 = "";
-  t_service* extends_s = tservice->get_extends();
-  if (extends_s != NULL) {
-    extends = perl_namespace(extends_s->get_program()) + extends_s->get_name();
-    extends_processor = "use base qw(" + extends + "Processor);";
-  }
-
-  indent_up();
-
-  // Generate the header portion
-  f_service_ <<
-    "package " << perl_namespace(program_) << service_name_ << "Processor;" << endl << endl <<
-    "use strict;" << endl <<
-    extends_processor << endl << endl;
-
-
-  if (extends.empty()) {
-    f_service_ << "sub new {" << endl;
-
-    indent_up();
-
-    f_service_ <<
-      indent() << "my ($classname, $handler) = @_;"<< endl <<
-      indent() << "my $self      = {};"   << endl;
-
-    f_service_ <<
-      indent() << "$self->{handler} = $handler;" << endl;
-
-    f_service_ <<
-      indent() << "return bless ($self, $classname);"<<endl;
-
-    indent_down();
-
-    f_service_ <<
-      "}" << endl << endl;
-  }
-
-  // Generate the server implementation
-  f_service_ << "sub process {" << endl;
-  indent_up();
-
-  f_service_ <<
-    indent() << "my ($self, $input, $output) = @_;" << endl;
-
-  f_service_ <<
-    indent() << "my $rseqid = 0;" << endl <<
-    indent() << "my $fname  = undef;" << endl <<
-    indent() << "my $mtype  = 0;" << endl << endl;
-
-  f_service_ <<
-    indent() << "$input->readMessageBegin(\\$fname, \\$mtype, \\$rseqid);" << endl;
-
-  // HOT: check for method implementation
-  f_service_ <<
-    indent() << "my $methodname = 'process_'.$fname;" << endl <<
-    indent() << "if (!$self->can($methodname)) {" << endl;
-  indent_up();
-
-  f_service_ <<
-    indent() << "$input->skip(TType::STRUCT);" << endl <<
-    indent() << "$input->readMessageEnd();" << endl <<
-    indent() << "my $x = new TApplicationException('Function '.$fname.' not implemented.', TApplicationException::UNKNOWN_METHOD);" << endl <<
-    indent() << "$output->writeMessageBegin($fname, TMessageType::EXCEPTION, $rseqid);" << endl <<
-    indent() << "$x->write($output);" << endl <<
-    indent() << "$output->writeMessageEnd();" << endl <<
-    indent() << "$output->getTransport()->flush();" << endl <<
-    indent() << "return;" << endl;
-
-  indent_down();
-  f_service_ <<
-    indent() << "}" << endl <<
-    indent() << "$self->$methodname($rseqid, $input, $output);" << endl <<
-    indent() << "return 1;" << endl;
-
-  indent_down();
-
-  f_service_ <<
-    "}" << endl <<endl;
-
-  // Generate the process subfunctions
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_process_function(tservice, *f_iter);
-  }
-}
-
-/**
- * Generates a process function definition.
- *
- * @param tfunction The function to write a dispatcher for
- */
-void t_perl_generator::generate_process_function(t_service* tservice,
-                                                 t_function* tfunction) {
-  // Open function
-  f_service_ <<
-    "sub process_" << tfunction->get_name() << " {"<<endl;
-
-  indent_up();
-
-  f_service_ <<
-    indent() << "my ($self, $seqid, $input, $output) = @_;" << endl;
-
-  string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_args";
-  string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_result";
-
-  f_service_ <<
-    indent() << "my $args = new " << argsname << "();" << endl <<
-    indent() << "$args->read($input);" << endl;
-
-  f_service_ <<
-    indent() << "$input->readMessageEnd();" << endl;
-
-  t_struct* xs = tfunction->get_xceptions();
-  const std::vector<t_field*>& xceptions = xs->get_members();
-  vector<t_field*>::const_iterator x_iter;
-
-  // Declare result for non oneway function
-  if (!tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << "my $result = new " << resultname << "();" << endl;
-  }
-
-  // Try block for a function with exceptions
-  if (xceptions.size() > 0) {
-    f_service_ <<
-      indent() << "eval {" << endl;
-    indent_up();
-  }
-
-  // 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_ << indent();
-  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
-    f_service_ << "$result->{success} = ";
-  }
-  f_service_ <<
-    "$self->{handler}->" << 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->" << (*f_iter)->get_name();
-  }
-  f_service_ << ");" << endl;
-
-  if (!tfunction->is_oneway() && xceptions.size() > 0) {
-    indent_down();
-    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      f_service_ <<
-        indent() << "}; if( UNIVERSAL::isa($@,'" <<
-          perl_namespace((*x_iter)->get_type()->get_program()) <<
-          (*x_iter)->get_type()->get_name() <<
-          "') ){ " << endl;
-
-      if (!tfunction->is_oneway()) {
-        indent_up();
-        f_service_ <<
-          indent() << "$result->{" << (*x_iter)->get_name() << "} = $@;" << endl;
-        indent_down();
-        f_service_ << indent();
-      }
-    }
-    f_service_ << "}" << endl;
-  }
-
-  // Shortcut out here for oneway functions
-  if (tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << "return;" << endl;
-    indent_down();
-    f_service_ <<
-      "}" << endl;
-    return;
-  }
-  // Serialize the request header
-  f_service_ <<
-    indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', TMessageType::REPLY, $seqid);" << endl <<
-    indent() << "$result->write($output);" << endl <<
-    indent() << "$output->writeMessageEnd();" << endl <<
-    indent() << "$output->getTransport()->flush();" << endl;
-
-  // Close function
-  indent_down();
-  f_service_ <<
-    "}" << endl << endl;
-}
-
-/**
- * Generates helper functions for a service.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_perl_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();
-    string name = ts->get_name();
-    ts->set_name(service_name_ + "_" + name);
-    generate_perl_struct_definition(f_service_, ts, false);
-    generate_perl_function_helpers(*f_iter);
-    ts->set_name(name);
-  }
-}
-
-/**
- * Generates a struct and helpers for a function.
- *
- * @param tfunction The function
- */
-void t_perl_generator::generate_perl_function_helpers(t_function* tfunction) {
-  t_struct result(program_, service_name_ + "_" + 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_perl_struct_definition(f_service_, &result, false);
-}
-
-/**
- * Generates a service interface definition.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_perl_generator::generate_service_interface(t_service* tservice) {
-  string extends_if = "";
-  t_service* extends_s = tservice->get_extends();
-  if (extends_s != NULL) {
-    extends_if = "use base qw(" + perl_namespace(extends_s->get_program()) + extends_s->get_name() + "If);";
-  }
-
-  f_service_ <<
-    "package " << perl_namespace(program_) << service_name_ << "If;" << endl << endl <<
-    "use strict;" << endl <<
-    extends_if << endl << endl;
-
-
-  indent_up();
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_service_ <<
-      "sub " << function_signature(*f_iter) <<endl<< "  die 'implement interface';\n}" << endl << endl;
-  }
-  indent_down();
-
-}
-
-/**
- * Generates a REST interface
- */
-void t_perl_generator::generate_service_rest(t_service* tservice) {
-  string extends = "";
-  string extends_if = "";
-  t_service* extends_s = tservice->get_extends();
-  if (extends_s != NULL) {
-    extends    =  extends_s->get_name();
-    extends_if = "use base qw(" + perl_namespace(extends_s->get_program()) + extends_s->get_name() + "Rest);";
-  }
-  f_service_ <<
-    "package " << perl_namespace(program_) << service_name_ << "Rest;" << endl << endl <<
-    "use strict;" << endl <<
-    extends_if << endl << endl;
-
-
-  if (extends.empty()) {
-    f_service_ << "sub new {" << endl;
-
-    indent_up();
-
-    f_service_ <<
-      indent() << "my ($classname, $impl) = @_;" << endl <<
-      indent() << "my $self     ={ impl => $impl };" << endl << endl <<
-      indent() << "return bless($self,$classname);" << endl;
-
-
-    indent_down();
-
-    f_service_  <<
-      "}" << endl << endl;
-  }
-
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_service_ <<
-      "sub " << (*f_iter)->get_name() <<
-      "{"    <<endl;
-
-    indent_up();
-
-    f_service_ <<
-      indent() << "my ($self, $request) = @_;" << endl << endl;
-
-
-    const vector<t_field*>& args = (*f_iter)->get_arglist()->get_members();
-    vector<t_field*>::const_iterator a_iter;
-    for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
-      t_type* atype = get_true_type((*a_iter)->get_type());
-      string req = "$request->{'" + (*a_iter)->get_name() + "'}";
-      f_service_ <<
-        indent() << "my $" << (*a_iter)->get_name() << " = (" << req << ") ? " << req << " : undef;" << endl;
-      if (atype->is_string() &&
-          ((t_base_type*)atype)->is_string_list()) {
-        f_service_ <<
-          indent() << "my @" << (*a_iter)->get_name() << " = split(/,/, $" << (*a_iter)->get_name() << ");" << endl <<
-          indent()     << "$"<<(*a_iter)->get_name() <<" = \\@"<<(*a_iter)->get_name()<<endl;
-      }
-    }
-    f_service_ <<
-      indent() << "return $self->{impl}->" << (*f_iter)->get_name() << "(" << argument_list((*f_iter)->get_arglist()) << ");" << endl;
-    indent_down();
-    indent(f_service_) << "}" << endl <<endl;
-  }
-
-}
-
-/**
- * Generates a service client definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_perl_generator::generate_service_client(t_service* tservice) {
-  string extends = "";
-  string extends_client = "";
-  t_service* extends_s = tservice->get_extends();
-  if (extends_s != NULL) {
-    extends = perl_namespace(extends_s->get_program()) + extends_s->get_name();
-    extends_client = "use base qw(" + extends + "Client);";
-  }
-
-  f_service_ <<
-      "package " << perl_namespace(program_) << service_name_ << "Client;" << endl << endl <<
-      extends_client << endl <<
-      "use base qw(" << perl_namespace(program_) << service_name_ << "If);" << endl;
-
-  // Constructor function
-  f_service_ << "sub new {"<<endl;
-
-  indent_up();
-
-  f_service_ <<
-    indent() << "my ($classname, $input, $output) = @_;" << endl <<
-    indent() << "my $self      = {};"   <<endl;
-
-  if (!extends.empty()) {
-    f_service_ <<
-      indent() << "$self = $classname->SUPER::new($input, $output);" << endl;
-  } else {
-    f_service_ <<
-      indent() << "$self->{input}  = $input;" << endl <<
-      indent() << "$self->{output} = defined $output ? $output : $input;" << endl <<
-      indent() << "$self->{seqid}  = 0;" << endl;
-  }
-
-  f_service_ <<
-    indent() << "return bless($self,$classname);"<<endl;
-
-  indent_down();
-
-  f_service_ <<
-    "}" << 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 = (*f_iter)->get_name();
-
-    // Open function
-    f_service_ << "sub " << function_signature(*f_iter) << endl;
-
-    indent_up();
-
-    indent(f_service_) << indent() <<
-      "$self->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;
-
-    if (!(*f_iter)->is_oneway()) {
-      f_service_ << indent();
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_ << "return ";
-      }
-      f_service_ <<
-        "$self->recv_" << funname << "();" << endl;
-    }
-
-    indent_down();
-
-    f_service_ << "}" << endl << endl;
-
-    f_service_ <<
-      "sub send_" << function_signature(*f_iter) << endl;
-
-    indent_up();
-
-    std::string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_args";
-
-    // Serialize the request header
-    f_service_ <<
-      indent() << "$self->{output}->writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType::CALL, $self->{seqid});" << endl;
-
-    f_service_ <<
-      indent() << "my $args = new " << argsname << "();" << endl;
-
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      f_service_ <<
-        indent() << "$args->{" << (*fld_iter)->get_name() << "} = $" << (*fld_iter)->get_name() << ";" << endl;
-    }
-
-    // Write to the stream
-    f_service_ <<
-      indent() << "$args->write($self->{output});" << endl <<
-      indent() << "$self->{output}->writeMessageEnd();" << endl <<
-      indent() << "$self->{output}->getTransport()->flush();" << endl;
-
-
-    indent_down();
-
-    f_service_ << "}" << endl;
-
-
-    if (!(*f_iter)->is_oneway()) {
-      std::string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_result";
-      t_struct noargs(program_);
-
-      t_function recv_function((*f_iter)->get_returntype(),
-                               string("recv_") + (*f_iter)->get_name(),
-                               &noargs);
-      // Open function
-      f_service_ <<
-        endl <<
-        "sub " << function_signature(&recv_function) << endl;
-
-      indent_up();
-
-      f_service_ <<
-        indent() << "my $rseqid = 0;" << endl <<
-        indent() << "my $fname;" << endl <<
-        indent() << "my $mtype = 0;" << endl <<
-        endl;
-
-      f_service_ <<
-        indent() << "$self->{input}->readMessageBegin(\\$fname, \\$mtype, \\$rseqid);" << endl <<
-        indent() << "if ($mtype == TMessageType::EXCEPTION) {" << endl <<
-        indent() << "  my $x = new TApplicationException();" << endl <<
-        indent() << "  $x->read($self->{input});" << endl <<
-        indent() << "  $self->{input}->readMessageEnd();" << endl <<
-        indent() << "  die $x;" << endl <<
-        indent() << "}" << endl;
-
-
-      f_service_ <<
-        indent() << "my $result = new " << resultname << "();" << endl <<
-        indent() << "$result->read($self->{input});" << endl;
-
-
-      f_service_ <<
-        indent() << "$self->{input}->readMessageEnd();" << endl <<
-        endl;
-
-
-      // Careful, only return result if not a void function
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_ <<
-          indent() << "if (defined $result->{success} ) {" << endl <<
-          indent() << "  return $result->{success};" << endl <<
-          indent() << "}" << 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 (defined $result->{" << (*x_iter)->get_name() << "}) {" << endl <<
-          indent() << "  die $result->{" << (*x_iter)->get_name() << "};" << endl <<
-          indent() << "}" << endl;
-      }
-
-      // Careful, only return _result if not a void function
-      if ((*f_iter)->get_returntype()->is_void()) {
-        indent(f_service_) <<
-          "return;" << endl;
-      } else {
-        f_service_ <<
-          indent() << "die \"" << (*f_iter)->get_name() << " failed: unknown result\";" << endl;
-      }
-
-      // Close function
-      indent_down();
-      f_service_ << "}"<<endl;
-
-    }
-  }
-
-}
-
-/**
- * Deserializes a field of any type.
- */
-void t_perl_generator::generate_deserialize_field(ofstream &out,
-                                                  t_field* tfield,
-                                                  string prefix,
-                                                  bool inclass) {
-  (void) inclass;
-  t_type* type = get_true_type(tfield->get_type());
-
-  if (type->is_void()) {
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  string name = tfield->get_name();
-
-  //Hack for when prefix is defined (always a hash ref)
-  if (!prefix.empty()) {
-    name = prefix + "{" + tfield->get_name() + "}";
-  }
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct(out,
-                                (t_struct*)type,
-                                 name);
-  } else if (type->is_container()) {
-    generate_deserialize_container(out, type, name);
-  } else if (type->is_base_type() || type->is_enum()) {
-    indent(out) <<
-      "$xfer += $input->";
-
-    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(\\$" << name << ");";
-        break;
-      case t_base_type::TYPE_BOOL:
-        out << "readBool(\\$" << name << ");";
-        break;
-      case t_base_type::TYPE_BYTE:
-        out << "readByte(\\$" << name << ");";
-        break;
-      case t_base_type::TYPE_I16:
-        out << "readI16(\\$" << name << ");";
-        break;
-      case t_base_type::TYPE_I32:
-        out << "readI32(\\$" << name << ");";
-        break;
-      case t_base_type::TYPE_I64:
-        out << "readI64(\\$" << name << ");";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        out << "readDouble(\\$" << name << ");";
-        break;
-      default:
-        throw "compiler error: no PERL name for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      out << "readI32(\\$" << name << ");";
-    }
-    out << endl;
-
-  } else {
-    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
-           tfield->get_name().c_str(), type->get_name().c_str());
-  }
-}
-
-/**
- * Generates an unserializer for a variable. This makes two key assumptions,
- * first that there is a const char* variable named data that points to the
- * buffer for deserialization, and that there is a variable protocol which
- * is a reference to a TProtocol serialization object.
- */
-void t_perl_generator::generate_deserialize_struct(ofstream &out,
-                                                   t_struct* tstruct,
-                                                   string prefix) {
-  out <<
-    indent() << "$" << prefix << " = new " << perl_namespace(tstruct->get_program()) << tstruct->get_name() << "();" << endl <<
-    indent() << "$xfer += $" << prefix << "->read($input);" << endl;
-}
-
-void t_perl_generator::generate_deserialize_container(ofstream &out,
-                                                      t_type* ttype,
-                                                      string prefix) {
-  scope_up(out);
-
-  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);
-
-  out <<
-    indent() << "my $" << size << " = 0;" << endl;
-
-  // Declare variables, read header
-  if (ttype->is_map()) {
-    out <<
-      indent() << "$" << prefix << " = {};" << endl <<
-      indent() << "my $" << ktype << " = 0;" << endl <<
-      indent() << "my $" << vtype << " = 0;" << endl;
-
-    out <<
-      indent() << "$xfer += $input->readMapBegin(" <<
-      "\\$" << ktype << ", \\$" << vtype << ", \\$" << size << ");" << endl;
-
-  } else if (ttype->is_set()) {
-
-    out <<
-      indent() << "$" << prefix << " = {};" << endl <<
-      indent() << "my $" << etype << " = 0;" << endl <<
-      indent() << "$xfer += $input->readSetBegin(" <<
-      "\\$" << etype << ", \\$" << size << ");" << endl;
-
-  } else if (ttype->is_list()) {
-
-    out <<
-      indent() << "$" << prefix << " = [];" << endl <<
-      indent() << "my $" << etype << " = 0;" << endl <<
-      indent() << "$xfer += $input->readListBegin(" <<
-      "\\$" << etype << ", \\$" << size << ");" << endl;
-
-  }
-
-  // For loop iterates over elements
-  string i = tmp("_i");
-  indent(out) <<
-    "for (my $" <<
-    i << " = 0; $" << i << " < $" << size << "; ++$" << i << ")" << endl;
-
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
-  } else if (ttype->is_set()) {
-    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
-  } else if (ttype->is_list()) {
-    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
-  }
-
-  scope_down(out);
-
-
-  // Read container end
-  if (ttype->is_map()) {
-    indent(out) << "$xfer += $input->readMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) << "$xfer += $input->readSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) << "$xfer += $input->readListEnd();" << endl;
-  }
-
-  scope_down(out);
-}
-
-
-/**
- * Generates code to deserialize a map
- */
-void t_perl_generator::generate_deserialize_map_element(ofstream &out,
-                                                        t_map* tmap,
-                                                        string prefix) {
-  string key = tmp("key");
-  string val = tmp("val");
-  t_field fkey(tmap->get_key_type(), key);
-  t_field fval(tmap->get_val_type(), val);
-
-  indent(out) <<
-    declare_field(&fkey, true, true) << endl;
-  indent(out) <<
-    declare_field(&fval, true, true) << endl;
-
-  generate_deserialize_field(out, &fkey);
-  generate_deserialize_field(out, &fval);
-
-  indent(out) <<
-    "$" << prefix << "->{$" << key << "} = $" << val << ";" << endl;
-}
-
-void t_perl_generator::generate_deserialize_set_element(ofstream &out,
-                                                        t_set* tset,
-                                                        string prefix) {
-  string elem = tmp("elem");
-  t_field felem(tset->get_elem_type(), elem);
-
-  indent(out) <<
-    "my $" << elem << " = undef;" << endl;
-
-  generate_deserialize_field(out, &felem);
-
-  indent(out) <<
-    "$" << prefix << "->{$" << elem << "} = 1;" << endl;
-}
-
-void t_perl_generator::generate_deserialize_list_element(ofstream &out,
-                                                         t_list* tlist,
-                                                         string prefix) {
-  string elem = tmp("elem");
-  t_field felem(tlist->get_elem_type(), elem);
-
-  indent(out) <<
-    "my $" << elem << " = undef;" << endl;
-
-  generate_deserialize_field(out, &felem);
-
-  indent(out) <<
-    "push(@{$" << prefix << "},$" << elem << ");" << endl;
-}
-
-
-/**
- * Serializes a field of any type.
- *
- * @param tfield The field to serialize
- * @param prefix Name to prepend to field name
- */
-void t_perl_generator::generate_serialize_field(ofstream &out,
-                                                t_field* tfield,
-                                                string prefix) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  // Do nothing for void types
-  if (type->is_void()) {
-    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_serialize_struct(out,
-                              (t_struct*)type,
-                               prefix + "{"+tfield->get_name()+"}" );
-  } else if (type->is_container()) {
-    generate_serialize_container(out,
-                                 type,
-                                 prefix + "{" + tfield->get_name()+"}");
-  } else if (type->is_base_type() || type->is_enum()) {
-
-    string name = tfield->get_name();
-
-    //Hack for when prefix is defined (always a hash ref)
-    if(!prefix.empty())
-      name = prefix + "{" + tfield->get_name() + "}";
-
-    indent(out) <<
-      "$xfer += $output->";
-
-    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($" << name << ");";
-        break;
-      case t_base_type::TYPE_BOOL:
-        out << "writeBool($" << name << ");";
-        break;
-      case t_base_type::TYPE_BYTE:
-        out << "writeByte($" << name << ");";
-        break;
-      case t_base_type::TYPE_I16:
-        out << "writeI16($" << name << ");";
-        break;
-      case t_base_type::TYPE_I32:
-        out << "writeI32($" << name << ");";
-        break;
-      case t_base_type::TYPE_I64:
-        out << "writeI64($" << name << ");";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        out << "writeDouble($" << name << ");";
-        break;
-      default:
-        throw "compiler error: no PERL name for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      out << "writeI32($" << name << ");";
-    }
-    out << endl;
-
-  } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
-           prefix.c_str(),
-           tfield->get_name().c_str(),
-           type->get_name().c_str());
-  }
-}
-
-/**
- * Serializes all the members of a struct.
- *
- * @param tstruct The struct to serialize
- * @param prefix  String prefix to attach to all fields
- */
-void t_perl_generator::generate_serialize_struct(ofstream &out,
-                                                 t_struct* tstruct,
-                                                 string prefix) {
-  (void) tstruct;
-  indent(out) <<
-      "$xfer += $" << prefix << "->write($output);" << endl;
-}
-
-/**
- * Writes out a container
- */
-void t_perl_generator::generate_serialize_container(ofstream &out,
-                                                    t_type* ttype,
-                                                    string prefix) {
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    indent(out) <<
-      "$xfer += $output->writeMapBegin(" <<
-      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
-      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
-      "scalar(keys %{$" << prefix << "}));" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "$xfer += $output->writeSetBegin(" <<
-      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
-      "scalar(@{$" << prefix << "}));" << endl;
-
-  } else if (ttype->is_list()) {
-
-    indent(out) <<
-      "$xfer += $output->writeListBegin(" <<
-      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
-      "scalar(@{$" << prefix << "}));" << endl;
-
-  }
-
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    string kiter = tmp("kiter");
-    string viter = tmp("viter");
-    indent(out) <<
-      "while( my ($"<<kiter<<",$"<<viter<<") = each %{$" << prefix << "}) " << endl;
-
-    scope_up(out);
-    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
-    scope_down(out);
-
-  } else if (ttype->is_set()) {
-    string iter = tmp("iter");
-    indent(out) <<
-      "foreach my $"<<iter<<" (@{$" << prefix << "})" << endl;
-    scope_up(out);
-    generate_serialize_set_element(out, (t_set*)ttype, iter);
-    scope_down(out);
-
-
-  } else if (ttype->is_list()) {
-    string iter = tmp("iter");
-    indent(out) <<
-      "foreach my $"<<iter<<" (@{$" << prefix << "}) " << endl;
-    scope_up(out);
-    generate_serialize_list_element(out, (t_list*)ttype, iter);
-    scope_down(out);
-  }
-
-  scope_down(out);
-
-  if (ttype->is_map()) {
-    indent(out) <<
-      "$xfer += $output->writeMapEnd();" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "$xfer += $output->writeSetEnd();" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "$xfer += $output->writeListEnd();" << endl;
-  }
-
-  scope_down(out);
-}
-
-/**
- * Serializes the members of a map.
- *
- */
-void t_perl_generator::generate_serialize_map_element(ofstream &out,
-                                                      t_map* tmap,
-                                                      string kiter,
-                                                      string viter) {
-  t_field kfield(tmap->get_key_type(), kiter);
-  generate_serialize_field(out, &kfield);
-
-  t_field vfield(tmap->get_val_type(), viter);
-  generate_serialize_field(out, &vfield);
-}
-
-/**
- * Serializes the members of a set.
- */
-void t_perl_generator::generate_serialize_set_element(ofstream &out,
-                                                      t_set* tset,
-                                                      string iter) {
-  t_field efield(tset->get_elem_type(), iter);
-  generate_serialize_field(out, &efield);
-}
-
-/**
- * Serializes the members of a list.
- */
-void t_perl_generator::generate_serialize_list_element(ofstream &out,
-                                                       t_list* tlist,
-                                                       string iter) {
-  t_field efield(tlist->get_elem_type(), iter);
-  generate_serialize_field(out, &efield);
-}
-
-/**
- * Declares a field, which may include initialization as necessary.
- *
- * @param ttype The type
- */
-string t_perl_generator::declare_field(t_field* tfield, bool init, bool obj) {
-  string result = "my $" + tfield->get_name();
-  if (init) {
-    t_type* type = get_true_type(tfield->get_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:
-        break;
-      case t_base_type::TYPE_STRING:
-        result += " = ''";
-        break;
-      case t_base_type::TYPE_BOOL:
-        result += " = 0";
-        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:
-        result += " = 0";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        result += " = 0.0";
-        break;
-      default:
-        throw "compiler error: no PERL initializer for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      result += " = 0";
-    } else if (type->is_container()) {
-      result += " = []";
-    } else if (type->is_struct() || type->is_xception()) {
-      if (obj) {
-        result += " = new " + perl_namespace(type->get_program()) + type->get_name() + "()";
-      } else {
-        result += " = undef";
-      }
-    }
-  }
-  return result + ";";
-}
-
-/**
- * Renders a function signature of the form 'type name(args)'
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_perl_generator::function_signature(t_function* tfunction,
-                                            string prefix) {
-
-  string str;
-
-  str  = prefix + tfunction->get_name() + "{\n";
-  str += "  my $self = shift;\n";
-
-  //Need to create perl function arg inputs
-  const vector<t_field*> &fields = tfunction->get_arglist()->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    str += "  my $" + (*f_iter)->get_name() + " = shift;\n";
-  }
-
-  return str;
-}
-
-/**
- * Renders a field list
- */
-string t_perl_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();
-  }
-  return result;
-}
-
-/**
- * Converts the parse type to a C++ enum string for the given type.
- */
-string t_perl_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 "TType::STRING";
-    case t_base_type::TYPE_BOOL:
-      return "TType::BOOL";
-    case t_base_type::TYPE_BYTE:
-      return "TType::BYTE";
-    case t_base_type::TYPE_I16:
-      return "TType::I16";
-    case t_base_type::TYPE_I32:
-      return "TType::I32";
-    case t_base_type::TYPE_I64:
-      return "TType::I64";
-    case t_base_type::TYPE_DOUBLE:
-      return "TType::DOUBLE";
-    }
-  } else if (type->is_enum()) {
-    return "TType::I32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "TType::STRUCT";
-  } else if (type->is_map()) {
-    return "TType::MAP";
-  } else if (type->is_set()) {
-    return "TType::SET";
-  } else if (type->is_list()) {
-    return "TType::LIST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-THRIFT_REGISTER_GENERATOR(perl, "Perl", "")
-
diff --git a/compiler/cpp/src/generate/t_php_generator.cc b/compiler/cpp/src/generate/t_php_generator.cc
deleted file mode 100644
index 833caef..0000000
--- a/compiler/cpp/src/generate/t_php_generator.cc
+++ /dev/null
@@ -1,2372 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sstream>
-#include "t_oop_generator.h"
-#include "platform.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-#define NSGLOBAL  (nsglobal_.size() ? nsglobal_ : "")
-#define NSGLOBAL_A ("\\" + NSGLOBAL )
-#define NSGLOBAL_B ( NSGLOBAL + "\\")
-#define NSGLOBAL_AB ("\\" + NSGLOBAL + "\\")
-
-
-/**
- * PHP code generator.
- *
- */
-class t_php_generator : public t_oop_generator {
- public:
-  t_php_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_oop_generator(program)
-  {
-    (void) option_string;
-    std::map<std::string, std::string>::const_iterator iter;
-
-    iter = parsed_options.find("inlined");
-    binary_inline_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("rest");
-    rest_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("server");
-    phps_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("oop");
-    oop_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("nsglobal");
-    if(iter != parsed_options.end()) {
-      nsglobal_ = iter->second;
-    }
-    else {
-      nsglobal_ = ""; // by default global namespace is empty
-    }
-
-    if (oop_ && binary_inline_) {
-      throw "oop and inlined are mutually exclusive.";
-    }
-
-    out_dir_base_ = (binary_inline_ ? "gen-phpi" : "gen-php");
-    escape_['$'] = "\\$";
-  }
-
-  static bool is_valid_namespace(const std::string& sub_namespace);
-
-  /**
-   * 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);
-
-  /**
-   * Structs!
-   */
-
-  void generate_php_struct(t_struct* tstruct, bool is_exception);
-  void generate_php_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
-  void generate_php_struct_reader(std::ofstream& out, t_struct* tstruct);
-  void generate_php_struct_writer(std::ofstream& out, t_struct* tstruct);
-  void generate_php_function_helpers(t_function* tfunction);
-
-  void generate_php_type_spec(std::ofstream &out, t_type* t);
-  void generate_php_struct_spec(std::ofstream &out, t_struct* tstruct);
-
-  /**
-   * Service-level generation functions
-   */
-
-  void generate_service_helpers   (t_service* tservice);
-  void generate_service_interface (t_service* tservice);
-  void generate_service_rest      (t_service* tservice);
-  void generate_service_client    (t_service* tservice);
-  void generate_service_processor (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,
-                                          std::string prefix="",
-                                          bool inclass=false);
-
-  void generate_deserialize_struct       (std::ofstream &out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_deserialize_container    (std::ofstream &out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_deserialize_set_element  (std::ofstream &out,
-                                          t_set*      tset,
-                                          std::string prefix="");
-
-  void generate_deserialize_map_element  (std::ofstream &out,
-                                          t_map*      tmap,
-                                          std::string prefix="");
-
-  void generate_deserialize_list_element (std::ofstream &out,
-                                          t_list*     tlist,
-                                          std::string prefix="");
-
-  void generate_serialize_field          (std::ofstream &out,
-                                          t_field*    tfield,
-                                          std::string prefix="");
-
-  void generate_serialize_struct         (std::ofstream &out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_serialize_container      (std::ofstream &out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_serialize_map_element    (std::ofstream &out,
-                                          t_map*      tmap,
-                                          std::string kiter,
-                                          std::string viter);
-
-  void generate_serialize_set_element    (std::ofstream &out,
-                                          t_set*      tmap,
-                                          std::string iter);
-
-  void generate_serialize_list_element   (std::ofstream &out,
-                                          t_list*     tlist,
-                                          std::string iter);
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string php_includes();
-  std::string declare_field(t_field* tfield, bool init=false, bool obj=false);
-  std::string function_signature(t_function* tfunction, std::string prefix="");
-  std::string argument_list(t_struct* tstruct, bool addStructSignature = true);
-  std::string type_to_cast(t_type* ttype);
-  std::string type_to_enum(t_type* ttype);
-
-  std::string php_namespace_base(const t_program* p) {
-    std::string ns = p->get_namespace("php");
-    const char * delimiter = "\\";
-    size_t position = ns.find('.');
-    while (position != string::npos) {
-      ns.replace(position, 1, delimiter);
-      position = ns.find('.', position + 1);
-    }
-    return ns;
-  }
-
-  //general use namespace prefixing: \my\namespace\ or my_namespace_
-  string php_namespace(const t_program* p) {
-    string ns = php_namespace_base(p);
-    return (nsglobal_.size() ? NSGLOBAL_AB : NSGLOBAL_B) + (ns.size() ? (ns + "\\") : "");
-  }
-
-  //setting the namespace of a file: my\namespace
-  string php_namespace_suffix(const t_program* p) {
-    string ns = php_namespace_base(p);
-
-    return (nsglobal_.size() ? NSGLOBAL_B : NSGLOBAL) + ns;
-  }
-
-  //add a directory to allready existing namespace
-  string php_namespace_directory(string directory, bool end = true) {
-    if(end) {
-      return ";";
-    } else {
-      return "";
-    }
-  }
-
-  //writing an autload identifier into globa;ls: my\namespace\ or my_namespace_
-  string php_namespace_autoload(const t_program* p) {
-    std::string ns = php_namespace_base(p);
-    return (nsglobal_.size() ? NSGLOBAL_B : NSGLOBAL) + (ns.size() ? (ns + "\\") : "");
-  }
-
-  //declaring a type: typename or my_namespace_typename
-  string php_namespace_declaration(t_type* t) {
-    return t->get_name();
-  }
-
-  std::string php_path(t_program* p) {
-    std::string ns = p->get_namespace("php.path");
-    if (ns.empty()) {
-      return p->get_name();
-    }
-
-    // Transform the java-style namespace into a path.
-    for (std::string::iterator it = ns.begin(); it != ns.end(); ++it) {
-      if (*it == '.') {
-        *it = '/';
-      }
-    }
-
-    return ns + '/';
-  }
-
-  /**
-   * Transform class_method into ClassMethod
-   *
-   * @param str
-   * @return stirng
-   */
-  string classify(string str)
-  {
-    string classe = "";
-
-    vector<string> x = split(str, '_');
-
-    for (size_t i = 0; i < x.size(); ++i) {
-      classe = classe + capitalize(x[i]);
-    }
-
-    return classe;
-  }
-
-  /**
-   * Split method
-   * @param s
-   * @param delim
-   * @param elems
-   * @return
-   */
-  vector<string> &split(const string &s, char delim, vector<string> &elems) {
-    stringstream ss(s);
-    string item;
-
-    while(getline(ss, item, delim)) {
-      elems.push_back(item);
-    }
-
-    return elems;
-  }
-
-  vector<string> split(const string &s, char delim) {
-    vector<string> elems;
-
-    return split(s, delim, elems);
-  }
-
-  /**
-   * Capitalize method
-   * @param str
-   * @return
-   */
-  string capitalize(string str)
-  {
-    string::iterator it(str.begin());
-
-    if (it != str.end())
-        str[0] = toupper((unsigned char)str[0]);
-
-//    while(++it != str.end())
-//    {
-//      *it = tolower((unsigned char)*it);
-//    }
-    return str;
-  }
-
- private:
-
-  /**
-   * File streams
-   */
-  std::ofstream f_types_;
-  std::ofstream f_helpers_;
-  std::ofstream f_service_;
-
-  std::string package_dir_;
-  /**
-   * Generate protocol-independent template? Or Binary inline code?
-   */
-  bool binary_inline_;
-
-  /**
-   * Generate a REST handler class
-   */
-  bool rest_;
-
-  /**
-   * Generate stubs for a PHP server
-   */
-  bool phps_;
-
-  /**
-   * Whether to use OOP base class TBase
-   */
-  bool oop_;
-
-  /**
-   * Global namespace for PHP 5.3
-   */
-  std::string nsglobal_;
-};
-
-
-bool t_php_generator::is_valid_namespace(const std::string& sub_namespace) {
-  return sub_namespace == "path";
-}
-
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * streams.
- *
- * @param tprogram The program to generate
- */
-void t_php_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-
-  // Create Real directory Namespaces
-  vector<string> NSx = split(php_namespace_suffix(get_program()), '\\');
-  package_dir_ = get_out_dir();
-
-  for (size_t i = 0; i < NSx.size(); ++i) {
-	package_dir_ = package_dir_ + "/" + NSx[i] + "/";
-	MKDIR(package_dir_.c_str());
-  }
-
-  // Make output file
-  string f_types_name = package_dir_+"Types.php";
-  f_types_.open(f_types_name.c_str());
-
-  // Print header
-  f_types_ <<
-    "<?php" << endl;
-    f_types_ << "namespace " << php_namespace_suffix(get_program()) << ";" << endl << endl;
-  f_types_ << autogen_comment() << php_includes();
-
-  f_types_ << endl;
-}
-
-/**
- * Prints standard php includes
- */
-string t_php_generator::php_includes() {
-  string TBase = "use Thrift\\Base\\TBase;\n";
-  string TType = "use Thrift\\Type\\TType;\n";
-  string TMessageType = "use Thrift\\Type\\TMessageType;\n";
-  string TException = "use Thrift\\Exception\\TException;\n";
-  string TProtocolException = "use Thrift\\Exception\\TProtocolException;\n";
-  string TProtocol = "use Thrift\\Protocol\\TProtocol;\n";
-  string TBinaryProtocolAccelerated = "use Thrift\\Protocol\\TBinaryProtocolAccelerated;\n";
-  string TApplicationException = "use Thrift\\Exception\\TApplicationException;\n\n";
-
-  return TBase + TType + TMessageType + TException + TProtocolException + TProtocol + TBinaryProtocolAccelerated + TApplicationException;
-}
-
-/**
- * Close up (or down) some filez.
- */
-void t_php_generator::close_generator() {
-  // Close types file
-    f_types_ << endl;
-  f_types_.close();
-}
-
-/**
- * Generates a typedef. This is not done in PHP, types are all implicit.
- *
- * @param ttypedef The type definition
- */
-void t_php_generator::generate_typedef(t_typedef* ttypedef) {
-  (void) ttypedef;
-}
-
-/**
- * Generates code for an enumerated type. Since define is expensive to lookup
- * in PHP, we use a global array for this.
- *
- * @param tenum The enumeration
- */
-void t_php_generator::generate_enum(t_enum* tenum) {
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-
-  // We're also doing it this way to see how it performs. It's more legible
-  // code but you can't do things like an 'extract' on it, which is a bit of
-  // a downer.
-  f_types_ <<
-    "final class " << tenum->get_name() << " {" << endl;
-  indent_up();
-
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    indent(f_types_) <<
-      "const " << (*c_iter)->get_name() << " = " << value << ";" << endl;
-  }
-
-  indent(f_types_) <<
-    "static public $__names = array(" << endl;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    indent(f_types_) <<
-      "  " << value << " => '" << (*c_iter)->get_name() << "'," << endl;
-  }
-  indent(f_types_) <<
-    ");" << endl;
-
-  indent_down();
-  f_types_ << "}" << endl << endl;
-}
-
-/**
- * Generate a constant value
- */
-void t_php_generator::generate_const(t_const* tconst) {
-  t_type* type = tconst->get_type();
-  string name = tconst->get_name();
-  t_const_value* value = tconst->get_value();
-
-  f_types_ << "$GLOBALS['" << program_name_ << "_CONSTANTS']['" << name << "'] = ";
-  f_types_ << render_const_value(type, value);
-  f_types_ << ";" << endl << 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_php_generator::render_const_value(t_type* type, t_const_value* value) {
-  std::ostringstream out;
-  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_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 " << php_namespace(type->get_program()) << type->get_name() << "(array(" << 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();
-      }
-      out << indent();
-      out << render_const_value(g_type_string, v_iter->first);
-      out << " => ";
-      out << render_const_value(field_type, v_iter->second);
-      out << "," << endl;
-    }
-    indent_down();
-    indent(out) << "))";
-  } else if (type->is_map()) {
-    t_type* ktype = ((t_map*)type)->get_key_type();
-    t_type* vtype = ((t_map*)type)->get_val_type();
-    out << "array(" << endl;
-    indent_up();
-    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) {
-      out << indent();
-      out << render_const_value(ktype, v_iter->first);
-      out << " => ";
-      out << render_const_value(vtype, v_iter->second);
-      out << "," << endl;
-    }
-    indent_down();
-    indent(out) << ")";
-  } else if (type->is_list() || type->is_set()) {
-    t_type* etype;
-    if (type->is_list()) {
-      etype = ((t_list*)type)->get_elem_type();
-    } else {
-      etype = ((t_set*)type)->get_elem_type();
-    }
-    out << "array(" << endl;
-    indent_up();
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      out << indent();
-      out << render_const_value(etype, *v_iter);
-      if (type->is_set()) {
-        out << " => true";
-      }
-      out << "," << endl;
-    }
-    indent_down();
-    indent(out) << ")";
-  }
-  return out.str();
-}
-
-/**
- * Make a struct
- */
-void t_php_generator::generate_struct(t_struct* tstruct) {
-  generate_php_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_php_generator::generate_xception(t_struct* txception) {
-  generate_php_struct(txception, true);
-}
-
-/**
- * Structs can be normal or exceptions.
- */
-void t_php_generator::generate_php_struct(t_struct* tstruct,
-                                          bool is_exception) {
-  generate_php_struct_definition(f_types_, tstruct, is_exception);
-}
-
-void t_php_generator::generate_php_type_spec(ofstream& out,
-                                             t_type* t) {
-  t = get_true_type(t);
-  indent(out) << "'type' => " << type_to_enum(t) << "," << endl;
-
-  if (t->is_base_type() || t->is_enum()) {
-    // Noop, type is all we need
-  } else if (t->is_struct() || t->is_xception()) {
-    indent(out) << "'class' => '" << php_namespace(t->get_program()) << t->get_name() <<"'," << endl;
-  } else if (t->is_map()) {
-    t_type* ktype = get_true_type(((t_map*)t)->get_key_type());
-    t_type* vtype = get_true_type(((t_map*)t)->get_val_type());
-    indent(out) << "'ktype' => " << type_to_enum(ktype) << "," << endl;
-    indent(out) << "'vtype' => " << type_to_enum(vtype) << "," << endl;
-    indent(out) << "'key' => array(" << endl;
-    indent_up();
-    generate_php_type_spec(out, ktype);
-    indent_down();
-    indent(out) << ")," << endl;
-    indent(out) << "'val' => array(" << endl;
-    indent_up();
-    generate_php_type_spec(out, vtype);
-    indent(out) << ")," << endl;
-    indent_down();
-  } else if (t->is_list() || t->is_set()) {
-    t_type* etype;
-    if (t->is_list()) {
-      etype = get_true_type(((t_list*)t)->get_elem_type());
-    } else {
-      etype = get_true_type(((t_set*)t)->get_elem_type());
-    }
-    indent(out) << "'etype' => " << type_to_enum(etype) <<"," << endl;
-    indent(out) << "'elem' => array(" << endl;
-    indent_up();
-    generate_php_type_spec(out, etype);
-    indent(out) << ")," << endl;
-    indent_down();
-  } else {
-    throw "compiler error: no type for php struct spec field";
-  }
-
-}
-
-/**
- * Generates the struct specification structure, which fully qualifies enough
- * type information to generalize serialization routines.
- */
-void t_php_generator::generate_php_struct_spec(ofstream& out,
-                                               t_struct* tstruct) {
-  indent(out) << "if (!isset(self::$_TSPEC)) {" << endl;
-  indent_up();
-
-  indent(out) << "self::$_TSPEC = array(" << endl;
-  indent_up();
-
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_type* t = get_true_type((*m_iter)->get_type());
-    indent(out) << (*m_iter)->get_key() << " => array(" << endl;
-    indent_up();
-    out <<
-      indent() << "'var' => '" << (*m_iter)->get_name() << "'," << endl;
-    generate_php_type_spec(out, t);
-    indent(out) << ")," << endl;
-    indent_down();
-  }
-
-  indent_down();
-  indent(out) << "  );" << endl;
-  indent_down();
-  indent(out) << "}" << endl;
-}
-
-/**
- * Generates a struct definition for a thrift data type. This is nothing in PHP
- * where the objects are all just associative arrays (unless of course we
- * decide to start using objects for them...)
- *
- * @param tstruct The struct definition
- */
-void t_php_generator::generate_php_struct_definition(ofstream& out,
-                                                     t_struct* tstruct,
-                                                     bool is_exception) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  out <<
-    "class " << php_namespace_declaration(tstruct);
-  if (is_exception) {
-    out << " extends " << "TException";
-  } else if (oop_) {
-    out << " extends " << "TBase";
-  }
-  out <<
-    " {" << endl;
-  indent_up();
-
-  indent(out) << "static $_TSPEC;" << endl << endl;
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    string dval = "null";
-    t_type* t = get_true_type((*m_iter)->get_type());
-    if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) {
-      dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value());
-    }
-    indent(out) <<
-      "public $" << (*m_iter)->get_name() << " = " << dval << ";" << endl;
-  }
-
-  out << endl;
-
-  // Generate constructor from array
-  string param = (members.size() > 0) ? "$vals=null" : "";
-  out <<
-    indent() << "public function __construct(" << param << ") {" << endl;
-  indent_up();
-
-  generate_php_struct_spec(out, tstruct);
-
-  if (members.size() > 0) {
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      t_type* t = get_true_type((*m_iter)->get_type());
-      if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) {
-        indent(out) << "$this->" << (*m_iter)->get_name() << " = " << render_const_value(t, (*m_iter)->get_value()) << ";" << endl;
-      }
-    }
-    out <<
-      indent() << "if (is_array($vals)) {" << endl;
-    indent_up();
-    if (oop_) {
-      out << indent() << "parent::__construct(self::$_TSPEC, $vals);" << endl;
-    } else {
-      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-        out <<
-          indent() << "if (isset($vals['" << (*m_iter)->get_name() << "'])) {" << endl <<
-          indent() << "  $this->" << (*m_iter)->get_name() << " = $vals['" << (*m_iter)->get_name() << "'];" << endl <<
-          indent() << "}" << endl;
-      }
-    }
-    indent_down();
-    out <<
-      indent() << "}" << endl;
-  }
-  scope_down(out);
-  out << endl;
-
-  out <<
-    indent() << "public function getName() {" << endl <<
-    indent() << "  return '" << tstruct->get_name() << "';" << endl <<
-    indent() << "}" << endl <<
-    endl;
-
-  generate_php_struct_reader(out, tstruct);
-  generate_php_struct_writer(out, tstruct);
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-/**
- * Generates the read() method for a struct
- */
-void t_php_generator::generate_php_struct_reader(ofstream& out,
-                                                 t_struct* tstruct) {
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  indent(out) <<
-    "public function read($input)" << endl;
-  scope_up(out);
-
-  if (oop_) {
-    indent(out) << "return $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);" << endl;
-    scope_down(out);
-    return;
-  }
-
-  out <<
-    indent() << "$xfer = 0;" << endl <<
-    indent() << "$fname = null;" << endl <<
-    indent() << "$ftype = 0;" << endl <<
-    indent() << "$fid = 0;" << endl;
-
-  // Declare stack tmp variables
-  if (!binary_inline_) {
-    indent(out) <<
-      "$xfer += $input->readStructBegin($fname);" << endl;
-  }
-
-  // Loop over reading in fields
-  indent(out) <<
-    "while (true)" << endl;
-
-    scope_up(out);
-
-    // Read beginning field marker
-    if (binary_inline_) {
-      t_field fftype(g_type_byte, "ftype");
-      t_field ffid(g_type_i16, "fid");
-      generate_deserialize_field(out, &fftype);
-      out <<
-        indent() << "if ($ftype == " << "TType::STOP) {" << endl <<
-        indent() << "  break;" << endl <<
-        indent() << "}" << endl;
-      generate_deserialize_field(out, &ffid);
-    } else {
-      indent(out) <<
-        "$xfer += $input->readFieldBegin($fname, $ftype, $fid);" << endl;
-      // Check for field STOP marker and break
-      indent(out) <<
-        "if ($ftype == " << "TType::STOP) {" << endl;
-      indent_up();
-      indent(out) <<
-        "break;" << endl;
-      indent_down();
-      indent(out) <<
-        "}" << endl;
-    }
-
-    // Switch statement on the field we are reading
-    indent(out) <<
-      "switch ($fid)" << endl;
-
-      scope_up(out);
-
-      // Generate deserialization code for known cases
-      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-        indent(out) <<
-          "case " << (*f_iter)->get_key() << ":" << endl;
-        indent_up();
-        indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
-        indent_up();
-        generate_deserialize_field(out, *f_iter, "this->");
-        indent_down();
-        out <<
-          indent() << "} else {" << endl;
-        if (binary_inline_) {
-          indent(out) <<  "  $xfer += " << "TProtocol::skipBinary($input, $ftype);" << endl;
-        } else {
-          indent(out) <<  "  $xfer += $input->skip($ftype);" << endl;
-        }
-        out <<
-          indent() << "}" << endl <<
-          indent() << "break;" << endl;
-        indent_down();
-      }
-
-      // In the default case we skip the field
-      indent(out) <<  "default:" << endl;
-      if (binary_inline_) {
-        indent(out) <<  "  $xfer += " << "TProtocol::skipBinary($input, $ftype);" << endl;
-      } else {
-        indent(out) <<  "  $xfer += $input->skip($ftype);" << endl;
-      }
-      indent(out) <<  "  break;" << endl;
-
-      scope_down(out);
-
-    if (!binary_inline_) {
-      // Read field end marker
-      indent(out) <<
-        "$xfer += $input->readFieldEnd();" << endl;
-    }
-
-    scope_down(out);
-
-  if (!binary_inline_) {
-    indent(out) <<
-      "$xfer += $input->readStructEnd();" << endl;
-  }
-
-  indent(out) <<
-    "return $xfer;" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-/**
- * Generates the write() method for a struct
- */
-void t_php_generator::generate_php_struct_writer(ofstream& out,
-                                                 t_struct* tstruct) {
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  if (binary_inline_) {
-    indent(out) <<
-      "public function write(&$output) {" << endl;
-  } else {
-    indent(out) <<
-      "public function write($output) {" << endl;
-  }
-  indent_up();
-
-  if (oop_) {
-    indent(out) << "return $this->_write('" << tstruct->get_name() << "', self::$_TSPEC, $output);" << endl;
-    scope_down(out);
-    return;
-  }
-
-  indent(out) <<
-    "$xfer = 0;" << endl;
-
-  if (!binary_inline_) {
-    indent(out) <<
-      "$xfer += $output->writeStructBegin('" << name << "');" << endl;
-  }
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    out <<
-      indent() << "if ($this->" << (*f_iter)->get_name() << " !== null) {" << endl;
-    indent_up();
-
-    t_type* type = get_true_type((*f_iter)->get_type());
-    string expect;
-    if (type->is_container()) {
-      expect = "array";
-    } else if (type->is_struct()) {
-      expect = "object";
-    }
-    if (!expect.empty()) {
-      out <<
-        indent() << "if (!is_" << expect << "($this->" << (*f_iter)->get_name() << ")) {" << endl;
-      indent_up();
-      out <<
-        indent() << "throw new " << "TProtocolException('Bad type in structure.', " << "TProtocolException::INVALID_DATA);" << endl;
-      scope_down(out);
-    }
-
-    // Write field header
-    if (binary_inline_) {
-      out <<
-        indent() << "$output .= pack('c', " << type_to_enum((*f_iter)->get_type()) << ");" << endl <<
-        indent() << "$output .= pack('n', " << (*f_iter)->get_key() << ");" << endl;
-    } else {
-      indent(out) <<
-        "$xfer += $output->writeFieldBegin(" <<
-        "'" << (*f_iter)->get_name() << "', " <<
-        type_to_enum((*f_iter)->get_type()) << ", " <<
-        (*f_iter)->get_key() << ");" << endl;
-    }
-
-    // Write field contents
-    generate_serialize_field(out, *f_iter, "this->");
-
-    // Write field closer
-    if (!binary_inline_) {
-      indent(out) <<
-        "$xfer += $output->writeFieldEnd();" << endl;
-    }
-
-    indent_down();
-    indent(out) <<
-      "}" << endl;
-  }
-
-  if (binary_inline_) {
-    out <<
-      indent() << "$output .= pack('c', " << "TType::STOP);" << endl;
-  } else {
-    out <<
-      indent() << "$xfer += $output->writeFieldStop();" << endl <<
-      indent() << "$xfer += $output->writeStructEnd();" << endl;
-  }
-
-  out <<
-    indent() << "return $xfer;" << endl;
-
-  indent_down();
-  out <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-/**
- * Generates a thrift service.
- *
- * @param tservice The service definition
- */
-void t_php_generator::generate_service(t_service* tservice) {
-  string f_service_name = package_dir_+service_name_+".php";
-  f_service_.open(f_service_name.c_str());
-
-  f_service_ << "<?php" << endl;
-  f_service_ << "namespace " << php_namespace_suffix(tservice->get_program()) << ";" << endl;
-  f_service_ << autogen_comment() <<
-    php_includes();
-
-  f_service_ <<
-    endl;
-
-  // Generate the three main parts of the service (well, two for now in PHP)
-  generate_service_interface(tservice);
-  if (rest_) {
-    generate_service_rest(tservice);
-  }
-  generate_service_client(tservice);
-  generate_service_helpers(tservice);
-  if (phps_) {
-    generate_service_processor(tservice);
-  }
-
-  // Close service file
-  f_service_ << endl;
-  f_service_.close();
-}
-
-/**
- * Generates a service server definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_php_generator::generate_service_processor(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 = "";
-  if (tservice->get_extends() != NULL) {
-    extends = tservice->get_extends()->get_name();
-    extends_processor = " extends " + php_namespace(tservice->get_extends()->get_program()) + extends + "Processor";
-  }
-
-  // Generate the header portion
-  f_service_ <<
-    "class " << service_name_ << "Processor" << extends_processor << " {" << endl;
-  indent_up();
-
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "protected $handler_ = null;" << endl;
-  }
-
-  f_service_ <<
-    indent() << "public function __construct($handler) {" << endl;
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "  $this->handler_ = $handler;" << endl;
-  } else {
-    f_service_ <<
-      indent() << "  parent::__construct($handler);" << endl;
-  }
-  f_service_ <<
-    indent() << "}" << endl <<
-    endl;
-
-  // Generate the server implementation
-  indent(f_service_) <<
-    "public function process($input, $output) {" << endl;
-  indent_up();
-
-  f_service_ <<
-    indent() << "$rseqid = 0;" << endl <<
-    indent() << "$fname = null;" << endl <<
-    indent() << "$mtype = 0;" << endl <<
-    endl;
-
-  if (binary_inline_) {
-    t_field ffname(g_type_string, "fname");
-    t_field fmtype(g_type_byte, "mtype");
-    t_field fseqid(g_type_i32, "rseqid");
-    generate_deserialize_field(f_service_, &ffname, "", true);
-    generate_deserialize_field(f_service_, &fmtype, "", true);
-    generate_deserialize_field(f_service_, &fseqid, "", true);
-  } else {
-    f_service_ <<
-      indent() << "$input->readMessageBegin($fname, $mtype, $rseqid);" << endl;
-  }
-
-  // HOT: check for method implementation
-  f_service_ <<
-    indent() << "$methodname = 'process_'.$fname;" << endl <<
-    indent() << "if (!method_exists($this, $methodname)) {" << endl;
-  if (binary_inline_) {
-    f_service_ <<
-      indent() << "  throw new \\Exception('Function '.$fname.' not implemented.');" << endl;
-  } else {
-    f_service_ <<
-      indent() << "  $input->skip(" << "TType::STRUCT);" << endl <<
-      indent() << "  $input->readMessageEnd();" << endl <<
-      indent() << "  $x = new " << "TApplicationException('Function '.$fname.' not implemented.', " << "TApplicationException::UNKNOWN_METHOD);" << endl <<
-      indent() << "  $output->writeMessageBegin($fname, " << "TMessageType::EXCEPTION, $rseqid);" << endl <<
-      indent() << "  $x->write($output);" << endl <<
-      indent() << "  $output->writeMessageEnd();" << endl <<
-      indent() << "  $output->getTransport()->flush();" << endl <<
-      indent() << "  return;" << endl;
-  }
-  f_service_ <<
-    indent() << "}" << endl <<
-    indent() << "$this->$methodname($rseqid, $input, $output);" << endl <<
-    indent() << "return true;" << endl;
-  indent_down();
-  f_service_ <<
-    indent() << "}" << endl <<
-    endl;
-
-  // Generate the process subfunctions
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_process_function(tservice, *f_iter);
-  }
-
-  indent_down();
-  f_service_ << "}" << endl;
-}
-
-/**
- * Generates a process function definition.
- *
- * @param tfunction The function to write a dispatcher for
- */
-void t_php_generator::generate_process_function(t_service* tservice,
-                                                t_function* tfunction) {
-  // Open function
-  indent(f_service_) <<
-    "protected function process_" << tfunction->get_name() <<
-    "($seqid, $input, $output) {" << endl;
-  indent_up();
-
-  string argsname = php_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_args";
-  string resultname = php_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_result";
-
-  f_service_ <<
-    indent() << "$args = new " << argsname << "();" << endl <<
-    indent() << "$args->read($input);" << endl;
-  if (!binary_inline_) {
-    f_service_ <<
-      indent() << "$input->readMessageEnd();" << endl;
-  }
-
-  t_struct* xs = tfunction->get_xceptions();
-  const std::vector<t_field*>& xceptions = xs->get_members();
-  vector<t_field*>::const_iterator x_iter;
-
-  // Declare result for non oneway function
-  if (!tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << "$result = new " << resultname << "();" << endl;
-  }
-
-  // Try block for a function with exceptions
-  if (xceptions.size() > 0) {
-    f_service_ <<
-      indent() << "try {" << endl;
-    indent_up();
-  }
-
-  // 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_ << indent();
-  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
-    f_service_ << "$result->success = ";
-  }
-  f_service_ <<
-    "$this->handler_->" << 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->" << (*f_iter)->get_name();
-  }
-  f_service_ << ");" << endl;
-
-  if (!tfunction->is_oneway() && xceptions.size() > 0) {
-    indent_down();
-    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      f_service_ <<
-        indent() << "} catch (" << php_namespace(get_true_type((*x_iter)->get_type())->get_program()) << (*x_iter)->get_type()->get_name() << " $" << (*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();
-        f_service_ << indent();
-      }
-    }
-    f_service_ << "}" << endl;
-  }
-
-  // Shortcut out here for oneway functions
-  if (tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << "return;" << endl;
-    indent_down();
-    f_service_ <<
-      indent() << "}" << endl;
-    return;
-  }
-
-  f_service_ <<
-    indent() << "$bin_accel = ($output instanceof " << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');" << endl;
-
-  f_service_ <<
-    indent() << "if ($bin_accel)" << endl;
-  scope_up(f_service_);
-
-  f_service_ <<
-    indent() << "thrift_protocol_write_binary($output, '" << tfunction->get_name() << "', " << "TMessageType::REPLY, $result, $seqid, $output->isStrictWrite());" << endl;
-
-  scope_down(f_service_);
-  f_service_ <<
-    indent() << "else" << endl;
-  scope_up(f_service_);
-
-  // Serialize the request header
-  if (binary_inline_) {
-    f_service_ <<
-      indent() << "$buff = pack('N', (0x80010000 | " << "TMessageType::REPLY)); " << endl <<
-      indent() << "$buff .= pack('N', strlen('" << tfunction->get_name() << "'));" << endl <<
-      indent() << "$buff .= '" << tfunction->get_name() << "';" << endl <<
-      indent() << "$buff .= pack('N', $seqid);" << endl <<
-      indent() << "$result->write($buff);" << endl <<
-      indent() << "$output->write($buff);" << endl <<
-      indent() << "$output->flush();" << endl;
-  } else {
-    f_service_ <<
-      indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', " << "TMessageType::REPLY, $seqid);" << endl <<
-      indent() << "$result->write($output);" << endl <<
-      indent() << "$output->writeMessageEnd();" << endl <<
-      indent() << "$output->getTransport()->flush();" << endl;
-  }
-
-  scope_down(f_service_);
-
-  // Close function
-  indent_down();
-  f_service_ <<
-    indent() << "}" << endl;
-}
-
-/**
- * Generates helper functions for a service.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_php_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();
-    string name = ts->get_name();
-    ts->set_name(service_name_ + "_" + name);
-    generate_php_struct_definition(f_service_, ts, false);
-    generate_php_function_helpers(*f_iter);
-    ts->set_name(name);
-  }
-}
-
-/**
- * Generates a struct and helpers for a function.
- *
- * @param tfunction The function
- */
-void t_php_generator::generate_php_function_helpers(t_function* tfunction) {
-  if (!tfunction->is_oneway()) {
-    t_struct result(program_, service_name_ + "_" + 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_php_struct_definition(f_service_, &result, false);
-  }
-}
-
-/**
- * Generates a service interface definition.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_php_generator::generate_service_interface(t_service* tservice) {
-  string extends = "";
-  string extends_if = "";
-  if (tservice->get_extends() != NULL) {
-    extends = " extends " + php_namespace(tservice->get_extends()->get_program()) + tservice->get_extends()->get_name();
-    extends_if = " extends " + php_namespace(tservice->get_extends()->get_program()) + tservice->get_extends()->get_name() + "If";
-  }
-  f_service_ <<
-    "interface " << php_namespace_declaration(tservice) << "If" << extends_if << " {" << endl;
-  indent_up();
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    indent(f_service_) <<
-      "public function " << function_signature(*f_iter) << ";" << endl;
-  }
-  indent_down();
-  f_service_ <<
-    "}" << endl << endl;
-}
-
-/**
- * Generates a REST interface
- */
-void t_php_generator::generate_service_rest(t_service* tservice) {
-  string extends = "";
-  string extends_if = "";
-  if (tservice->get_extends() != NULL) {
-    extends = " extends " + php_namespace(tservice->get_extends()->get_program()) + tservice->get_extends()->get_name();
-    extends_if = " extends " + php_namespace(tservice->get_extends()->get_program()) + tservice->get_extends()->get_name() + "Rest";
-  }
-  f_service_ <<
-    "class " << service_name_ << "Rest" << extends_if << " {" << endl;
-  indent_up();
-
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "protected $impl_;" << endl <<
-      endl;
-  }
-
-  f_service_ <<
-    indent() << "public function __construct($impl) {" << endl <<
-    indent() << "  $this->impl_ = $impl;" << endl <<
-    indent() << "}" << endl <<
-    endl;
-
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    indent(f_service_) <<
-      "public function " << (*f_iter)->get_name() << "($request) {" << endl;
-    indent_up();
-    const vector<t_field*>& args = (*f_iter)->get_arglist()->get_members();
-    vector<t_field*>::const_iterator a_iter;
-    for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
-      t_type* atype = get_true_type((*a_iter)->get_type());
-      string cast = type_to_cast(atype);
-      string req = "$request['" + (*a_iter)->get_name() + "']";
-      if (atype->is_bool()) {
-        f_service_ <<
-          indent() << "$" << (*a_iter)->get_name() << " = " << cast << "(!empty(" << req << ") && (" << req << " !== 'false'));" << endl;
-      } else {
-        f_service_ <<
-          indent() << "$" << (*a_iter)->get_name() << " = isset(" << req << ") ? " << cast << req << " : null;" << endl;
-      }
-      if (atype->is_string() &&
-          ((t_base_type*)atype)->is_string_list()) {
-        f_service_ <<
-          indent() << "$" << (*a_iter)->get_name() << " = explode(',', $" << (*a_iter)->get_name() << ");" << endl;
-      } else if (atype->is_map() || atype->is_list()) {
-        f_service_ <<
-          indent() << "$" << (*a_iter)->get_name() << " = json_decode($" << (*a_iter)->get_name() << ", true);" << endl;
-      } else if (atype->is_set()) {
-        f_service_ <<
-          indent() << "$" << (*a_iter)->get_name() << " = array_fill_keys(json_decode($" << (*a_iter)->get_name() << ", true), 1);" << endl;
-      } else if (atype->is_struct() || atype->is_xception()) {
-        f_service_ <<
-          indent() << "if ($" << (*a_iter)->get_name() << " !== null) {" << endl <<
-          indent() << "  $" << (*a_iter)->get_name() << " = new " << php_namespace(atype->get_program()) << atype->get_name() << "(json_decode($" << (*a_iter)->get_name() << ", true));" << endl <<
-          indent() << "}" << endl;
-      }
-    }
-    f_service_ <<
-      indent() << "return $this->impl_->" << (*f_iter)->get_name() << "(" << argument_list((*f_iter)->get_arglist(), false) << ");" << endl;
-    indent_down();
-    indent(f_service_) <<
-      "}" << endl <<
-      endl;
-  }
-  indent_down();
-  f_service_ <<
-    "}" << endl << endl;
-}
-
-/**
- * Generates a service client definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_php_generator::generate_service_client(t_service* tservice) {
-  string extends = "";
-  string extends_client = "";
-  if (tservice->get_extends() != NULL) {
-    extends = tservice->get_extends()->get_name();
-    extends_client = " extends " + php_namespace(tservice->get_extends()->get_program()) + extends + "Client";
-  }
-
-  f_service_ <<
-    "class " << php_namespace_declaration(tservice) << "Client" << extends_client << " implements " <<  php_namespace(tservice->get_program()) << service_name_ << "If {" << endl;
-  indent_up();
-
-  // Private members
-  if (extends.empty()) {
-    f_service_ <<
-      indent() << "protected $input_ = null;" << endl <<
-      indent() << "protected $output_ = null;" << endl <<
-      endl;
-    f_service_ <<
-      indent() << "protected $seqid_ = 0;" << endl <<
-      endl;
-  }
-
-  // Constructor function
-  f_service_ <<
-    indent() << "public function __construct($input, $output=null) {" << endl;
-  if (!extends.empty()) {
-    f_service_ <<
-      indent() << "  parent::__construct($input, $output);" << endl;
-  } else {
-    f_service_ <<
-      indent() << "  $this->input_ = $input;" << endl <<
-      indent() << "  $this->output_ = $output ? $output : $input;" << endl;
-  }
-  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 = (*f_iter)->get_name();
-
-    // Open function
-    indent(f_service_) <<
-      "public function " << function_signature(*f_iter) << endl;
-    scope_up(f_service_);
-      indent(f_service_) <<
-        "$this->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;
-
-      if (!(*f_iter)->is_oneway()) {
-        f_service_ << indent();
-        if (!(*f_iter)->get_returntype()->is_void()) {
-          f_service_ << "return ";
-        }
-        f_service_ <<
-          "$this->recv_" << funname << "();" << endl;
-      }
-    scope_down(f_service_);
-    f_service_ << endl;
-
-    indent(f_service_) <<
-      "public function send_" << function_signature(*f_iter) << endl;
-    scope_up(f_service_);
-
-      std::string argsname = php_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_args";
-
-      f_service_ <<
-        indent() << "$args = new " << argsname << "();" << endl;
-
-      for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-        f_service_ <<
-          indent() << "$args->" << (*fld_iter)->get_name() << " = $" << (*fld_iter)->get_name() << ";" << endl;
-      }
-
-      f_service_ <<
-        indent() << "$bin_accel = ($this->output_ instanceof " << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');" << endl;
-
-      f_service_ <<
-        indent() << "if ($bin_accel)" << endl;
-      scope_up(f_service_);
-
-      f_service_ <<
-        indent() << "thrift_protocol_write_binary($this->output_, '" << (*f_iter)->get_name() << "', " << "TMessageType::CALL, $args, $this->seqid_, $this->output_->isStrictWrite());" << endl;
-
-      scope_down(f_service_);
-      f_service_ <<
-        indent() << "else" << endl;
-      scope_up(f_service_);
-
-      // Serialize the request header
-      if (binary_inline_) {
-        f_service_ <<
-          indent() << "$buff = pack('N', (0x80010000 | " << "TMessageType::CALL));" << endl <<
-          indent() << "$buff .= pack('N', strlen('" << funname << "'));" << endl <<
-          indent() << "$buff .= '" << funname << "';" << endl <<
-          indent() << "$buff .= pack('N', $this->seqid_);" << endl;
-      } else {
-        f_service_ <<
-          indent() << "$this->output_->writeMessageBegin('" << (*f_iter)->get_name() << "', " << "TMessageType::CALL, $this->seqid_);" << endl;
-      }
-
-      // Write to the stream
-      if (binary_inline_) {
-        f_service_ <<
-          indent() << "$args->write($buff);" << endl <<
-          indent() << "$this->output_->write($buff);" << endl <<
-          indent() << "$this->output_->flush();" << endl;
-      } else {
-        f_service_ <<
-          indent() << "$args->write($this->output_);" << endl <<
-          indent() << "$this->output_->writeMessageEnd();" << endl <<
-          indent() << "$this->output_->getTransport()->flush();" << endl;
-      }
-
-    scope_down(f_service_);
-
-    scope_down(f_service_);
-
-
-    if (!(*f_iter)->is_oneway()) {
-      std::string resultname = php_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_result";
-      t_struct noargs(program_);
-
-      t_function recv_function((*f_iter)->get_returntype(),
-                               string("recv_") + (*f_iter)->get_name(),
-                               &noargs);
-      // Open function
-      f_service_ <<
-        endl <<
-        indent() << "public function " << function_signature(&recv_function) << endl;
-      scope_up(f_service_);
-
-      f_service_ <<
-        indent() << "$bin_accel = ($this->input_ instanceof " << "TBinaryProtocolAccelerated)"
-                 << " && function_exists('thrift_protocol_read_binary');" << endl;
-
-      f_service_ <<
-        indent() << "if ($bin_accel) $result = thrift_protocol_read_binary($this->input_, '" << resultname << "', $this->input_->isStrictRead());" << endl;
-      f_service_ <<
-        indent() << "else" << endl;
-      scope_up(f_service_);
-
-      f_service_ <<
-        indent() << "$rseqid = 0;" << endl <<
-        indent() << "$fname = null;" << endl <<
-        indent() << "$mtype = 0;" << endl <<
-        endl;
-
-      if (binary_inline_) {
-        t_field ffname(g_type_string, "fname");
-        t_field fseqid(g_type_i32, "rseqid");
-        f_service_ <<
-          indent() << "$ver = unpack('N', $this->input_->readAll(4));" << endl <<
-          indent() << "$ver = $ver[1];" << endl <<
-          indent() << "$mtype = $ver & 0xff;" << endl <<
-          indent() << "$ver = $ver & 0xffff0000;" << endl <<
-          indent() << "if ($ver != 0x80010000) throw new " << "TProtocolException('Bad version identifier: '.$ver, " << "TProtocolException::BAD_VERSION);" << endl;
-        generate_deserialize_field(f_service_, &ffname, "", true);
-        generate_deserialize_field(f_service_, &fseqid, "", true);
-      } else {
-        f_service_ <<
-          indent() << "$this->input_->readMessageBegin($fname, $mtype, $rseqid);" << endl <<
-          indent() << "if ($mtype == " << "TMessageType::EXCEPTION) {" << endl <<
-          indent() << "  $x = new " << "TApplicationException();" << endl <<
-          indent() << "  $x->read($this->input_);" << endl <<
-          indent() << "  $this->input_->readMessageEnd();" << endl <<
-          indent() << "  throw $x;" << endl <<
-          indent() << "}" << endl;
-      }
-
-      f_service_ <<
-        indent() << "$result = new " << resultname << "();" << endl <<
-        indent() << "$result->read($this->input_);" << endl;
-
-      if (!binary_inline_) {
-        f_service_ <<
-          indent() << "$this->input_->readMessageEnd();" << endl;
-      }
-
-      scope_down(f_service_);
-
-      // Careful, only return result if not a void function
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_ <<
-          indent() << "if ($result->success !== null) {" << endl <<
-          indent() << "  return $result->success;" << endl <<
-          indent() << "}" << 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->" << (*x_iter)->get_name() << " !== null) {" << endl <<
-          indent() << "  throw $result->" << (*x_iter)->get_name() << ";" << endl <<
-          indent() << "}" << endl;
-      }
-
-      // Careful, only return _result if not a void function
-      if ((*f_iter)->get_returntype()->is_void()) {
-        indent(f_service_) <<
-          "return;" << endl;
-      } else {
-        f_service_ <<
-          indent() << "throw new \\Exception(\"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
-      }
-
-    // Close function
-    scope_down(f_service_);
-    f_service_ << endl;
-
-    }
-  }
-
-  indent_down();
-  f_service_ <<
-    "}" << endl << endl;
-}
-
-/**
- * Deserializes a field of any type.
- */
-void t_php_generator::generate_deserialize_field(ofstream &out,
-                                                 t_field* tfield,
-                                                 string prefix,
-                                                 bool inclass) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  if (type->is_void()) {
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  string name = prefix + tfield->get_name();
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct(out,
-                                (t_struct*)type,
-                                 name);
-  } else {
-
-    if (type->is_container()) {
-      generate_deserialize_container(out, type, name);
-    } else if (type->is_base_type() || type->is_enum()) {
-
-      if (binary_inline_) {
-        std::string itrans = (inclass ? "$this->input_" : "$input");
-
-        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 <<
-              indent() << "$len = unpack('N', " << itrans << "->readAll(4));" << endl <<
-              indent() << "$len = $len[1];" << endl <<
-              indent() << "if ($len > 0x7fffffff) {" << endl <<
-              indent() << "  $len = 0 - (($len - 1) ^ 0xffffffff);" << endl <<
-              indent() << "}" << endl <<
-              indent() << "$" << name << " = " << itrans << "->readAll($len);" << endl;
-            break;
-          case t_base_type::TYPE_BOOL:
-            out <<
-              indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl <<
-              indent() << "$" << name << " = (bool)$" << name << "[1];" << endl;
-            break;
-          case t_base_type::TYPE_BYTE:
-            out <<
-              indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl <<
-              indent() << "$" << name << " = $" << name << "[1];" << endl;
-            break;
-          case t_base_type::TYPE_I16:
-            out <<
-              indent() << "$val = unpack('n', " << itrans << "->readAll(2));" << endl <<
-              indent() << "$val = $val[1];" << endl <<
-              indent() << "if ($val > 0x7fff) {" << endl <<
-              indent() << "  $val = 0 - (($val - 1) ^ 0xffff);" << endl <<
-              indent() << "}" << endl <<
-              indent() << "$" << name << " = $val;" << endl;
-            break;
-          case t_base_type::TYPE_I32:
-            out <<
-              indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl <<
-              indent() << "$val = $val[1];" << endl <<
-              indent() << "if ($val > 0x7fffffff) {" << endl <<
-              indent() << "  $val = 0 - (($val - 1) ^ 0xffffffff);" << endl <<
-              indent() << "}" << endl <<
-              indent() << "$" << name << " = $val;" << endl;
-            break;
-          case t_base_type::TYPE_I64:
-            out <<
-              indent() << "$arr = unpack('N2', " << itrans << "->readAll(8));" << endl <<
-              indent() << "if ($arr[1] & 0x80000000) {" << endl <<
-              indent() << "  $arr[1] = $arr[1] ^ 0xFFFFFFFF;" << endl <<
-              indent() << "  $arr[2] = $arr[2] ^ 0xFFFFFFFF;" << endl <<
-              indent() << "  $" << name << " = 0 - $arr[1]*4294967296 - $arr[2] - 1;" << endl <<
-              indent() << "} else {" << endl <<
-              indent() << "  $" << name << " = $arr[1]*4294967296 + $arr[2];" << endl <<
-              indent() << "}" << endl;
-            break;
-          case t_base_type::TYPE_DOUBLE:
-            out <<
-              indent() << "$arr = unpack('d', strrev(" << itrans << "->readAll(8)));" << endl <<
-              indent() << "$" << name << " = $arr[1];" << endl;
-            break;
-          default:
-            throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase) + tfield->get_name();
-          }
-        } else if (type->is_enum()) {
-            out <<
-              indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl <<
-              indent() << "$val = $val[1];" << endl <<
-              indent() << "if ($val > 0x7fffffff) {" << endl <<
-              indent() << "  $val = 0 - (($val - 1) ^ 0xffffffff);" << endl <<
-              indent() << "}" << endl <<
-              indent() << "$" << name << " = $val;" << endl;
-        }
-      } else {
-
-        indent(out) <<
-          "$xfer += $input->";
-
-        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($" << name << ");";
-            break;
-          case t_base_type::TYPE_BOOL:
-            out << "readBool($" << name << ");";
-            break;
-          case t_base_type::TYPE_BYTE:
-            out << "readByte($" << name << ");";
-            break;
-          case t_base_type::TYPE_I16:
-            out << "readI16($" << name << ");";
-            break;
-          case t_base_type::TYPE_I32:
-            out << "readI32($" << name << ");";
-            break;
-          case t_base_type::TYPE_I64:
-            out << "readI64($" << name << ");";
-            break;
-          case t_base_type::TYPE_DOUBLE:
-            out << "readDouble($" << 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 << "readI32($" << name << ");";
-        }
-        out << endl;
-      }
-    } else {
-      printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
-             tfield->get_name().c_str(), type->get_name().c_str());
-    }
-  }
-}
-
-/**
- * Generates an unserializer for a variable. This makes two key assumptions,
- * first that there is a const char* variable named data that points to the
- * buffer for deserialization, and that there is a variable protocol which
- * is a reference to a TProtocol serialization object.
- */
-void t_php_generator::generate_deserialize_struct(ofstream &out,
-                                                  t_struct* tstruct,
-                                                  string prefix) {
-  out <<
-    indent() << "$" << prefix << " = new " << php_namespace(tstruct->get_program()) << tstruct->get_name() << "();" << endl <<
-    indent() << "$xfer += $" << prefix << "->read($input);" << endl;
-}
-
-void t_php_generator::generate_deserialize_container(ofstream &out,
-                                                     t_type* ttype,
-                                                     string prefix) {
-  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);
-
-  out <<
-    indent() << "$" << prefix << " = array();" << endl <<
-    indent() << "$" << size << " = 0;" << endl;
-
-  // Declare variables, read header
-  if (ttype->is_map()) {
-    out <<
-      indent() << "$" << ktype << " = 0;" << endl <<
-      indent() << "$" << vtype << " = 0;" << endl;
-    if (binary_inline_) {
-      generate_deserialize_field(out, &fktype);
-      generate_deserialize_field(out, &fvtype);
-      generate_deserialize_field(out, &fsize);
-    } else {
-      out <<
-        indent() << "$xfer += $input->readMapBegin(" <<
-        "$" << ktype << ", $" << vtype << ", $" << size << ");" << endl;
-    }
-  } else if (ttype->is_set()) {
-    if (binary_inline_) {
-      generate_deserialize_field(out, &fetype);
-      generate_deserialize_field(out, &fsize);
-    } else {
-      out <<
-        indent() << "$" << etype << " = 0;" << endl <<
-        indent() << "$xfer += $input->readSetBegin(" <<
-        "$" << etype << ", $" << size << ");" << endl;
-    }
-  } else if (ttype->is_list()) {
-    if (binary_inline_) {
-      generate_deserialize_field(out, &fetype);
-      generate_deserialize_field(out, &fsize);
-    } else {
-      out <<
-        indent() << "$" << etype << " = 0;" << endl <<
-        indent() << "$xfer += $input->readListBegin(" <<
-        "$" << etype << ", $" << size << ");" << endl;
-    }
-  }
-
-  // For loop iterates over elements
-  string i = tmp("_i");
-  indent(out) <<
-    "for ($" <<
-    i << " = 0; $" << i << " < $" << size << "; ++$" << i << ")" << endl;
-
-    scope_up(out);
-
-    if (ttype->is_map()) {
-      generate_deserialize_map_element(out, (t_map*)ttype, prefix);
-    } else if (ttype->is_set()) {
-      generate_deserialize_set_element(out, (t_set*)ttype, prefix);
-    } else if (ttype->is_list()) {
-      generate_deserialize_list_element(out, (t_list*)ttype, prefix);
-    }
-
-    scope_down(out);
-
-  if (!binary_inline_) {
-    // Read container end
-    if (ttype->is_map()) {
-      indent(out) << "$xfer += $input->readMapEnd();" << endl;
-    } else if (ttype->is_set()) {
-      indent(out) << "$xfer += $input->readSetEnd();" << endl;
-    } else if (ttype->is_list()) {
-      indent(out) << "$xfer += $input->readListEnd();" << endl;
-    }
-  }
-}
-
-
-/**
- * Generates code to deserialize a map
- */
-void t_php_generator::generate_deserialize_map_element(ofstream &out,
-                                                       t_map* tmap,
-                                                       string prefix) {
-  string key = tmp("key");
-  string val = tmp("val");
-  t_field fkey(tmap->get_key_type(), key);
-  t_field fval(tmap->get_val_type(), val);
-
-  indent(out) <<
-    declare_field(&fkey, true, true) << endl;
-  indent(out) <<
-    declare_field(&fval, true, true) << endl;
-
-  generate_deserialize_field(out, &fkey);
-  generate_deserialize_field(out, &fval);
-
-  indent(out) <<
-    "$" << prefix << "[$" << key << "] = $" << val << ";" << endl;
-}
-
-void t_php_generator::generate_deserialize_set_element(ofstream &out,
-                                                       t_set* tset,
-                                                       string prefix) {
-  string elem = tmp("elem");
-  t_field felem(tset->get_elem_type(), elem);
-
-  indent(out) <<
-    "$" << elem << " = null;" << endl;
-
-  generate_deserialize_field(out, &felem);
-
-  indent(out) << "if (is_scalar($" << elem << ")) {" << endl;
-  indent(out) << "  $" << prefix << "[$" << elem << "] = true;" << endl;
-  indent(out) << "} else {" << endl;
-  indent(out) << "  $" << prefix << " []= $" << elem << ";" << endl;
-  indent(out) << "}" << endl;
-}
-
-void t_php_generator::generate_deserialize_list_element(ofstream &out,
-                                                        t_list* tlist,
-                                                        string prefix) {
-  string elem = tmp("elem");
-  t_field felem(tlist->get_elem_type(), elem);
-
-  indent(out) <<
-    "$" << elem << " = null;" << endl;
-
-  generate_deserialize_field(out, &felem);
-
-  indent(out) <<
-    "$" << prefix << " []= $" << elem << ";" << endl;
-}
-
-
-/**
- * Serializes a field of any type.
- *
- * @param tfield The field to serialize
- * @param prefix Name to prepend to field name
- */
-void t_php_generator::generate_serialize_field(ofstream &out,
-                                               t_field* tfield,
-                                               string prefix) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  // Do nothing for void types
-  if (type->is_void()) {
-    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_serialize_struct(out,
-                              (t_struct*)type,
-                              prefix + tfield->get_name());
-  } else if (type->is_container()) {
-    generate_serialize_container(out,
-                                 type,
-                                 prefix + tfield->get_name());
-  } else if (type->is_base_type() || type->is_enum()) {
-
-    string name = prefix + tfield->get_name();
-
-    if (binary_inline_) {
-      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 <<
-            indent() << "$output .= pack('N', strlen($" << name << "));" << endl <<
-            indent() << "$output .= $" << name << ";" << endl;
-          break;
-        case t_base_type::TYPE_BOOL:
-          out <<
-            indent() << "$output .= pack('c', $" << name << " ? 1 : 0);" << endl;
-          break;
-        case t_base_type::TYPE_BYTE:
-          out <<
-            indent() << "$output .= pack('c', $" << name << ");" << endl;
-          break;
-        case t_base_type::TYPE_I16:
-          out <<
-            indent() << "$output .= pack('n', $" << name << ");" << endl;
-          break;
-        case t_base_type::TYPE_I32:
-          out <<
-            indent() << "$output .= pack('N', $" << name << ");" << endl;
-          break;
-        case t_base_type::TYPE_I64:
-          out <<
-            indent() << "$output .= pack('N2', $" << name << " >> 32, $" << name << " & 0xFFFFFFFF);" << endl;
-          break;
-        case t_base_type::TYPE_DOUBLE:
-          out <<
-            indent() << "$output .= strrev(pack('d', $" << name << "));" << endl;
-          break;
-        default:
-          throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
-        }
-      } else if (type->is_enum()) {
-        out <<
-          indent() << "$output .= pack('N', $" << name << ");" << endl;
-      }
-    } else {
-
-      indent(out) <<
-        "$xfer += $output->";
-
-      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($" << name << ");";
-          break;
-        case t_base_type::TYPE_BOOL:
-          out << "writeBool($" << name << ");";
-          break;
-        case t_base_type::TYPE_BYTE:
-          out << "writeByte($" << name << ");";
-          break;
-        case t_base_type::TYPE_I16:
-          out << "writeI16($" << name << ");";
-          break;
-        case t_base_type::TYPE_I32:
-          out << "writeI32($" << name << ");";
-          break;
-        case t_base_type::TYPE_I64:
-          out << "writeI64($" << name << ");";
-          break;
-        case t_base_type::TYPE_DOUBLE:
-          out << "writeDouble($" << 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($" << name << ");";
-      }
-      out << endl;
-    }
-  } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
-           prefix.c_str(),
-           tfield->get_name().c_str(),
-           type->get_name().c_str());
-  }
-}
-
-/**
- * Serializes all the members of a struct.
- *
- * @param tstruct The struct to serialize
- * @param prefix  String prefix to attach to all fields
- */
-void t_php_generator::generate_serialize_struct(ofstream &out,
-                                                t_struct* tstruct,
-                                                string prefix) {
-  (void) tstruct;
-  indent(out) <<
-    "$xfer += $" << prefix << "->write($output);" << endl;
-}
-
-/**
- * Writes out a container
- */
-void t_php_generator::generate_serialize_container(ofstream &out,
-                                                   t_type* ttype,
-                                                   string prefix) {
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    if (binary_inline_) {
-      out <<
-        indent() << "$output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_key_type()) << ");" << endl <<
-        indent() << "$output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_val_type()) << ");" << endl <<
-        indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
-    } else {
-      indent(out) <<
-        "$output->writeMapBegin(" <<
-        type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
-        type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
-        "count($" << prefix << "));" << endl;
-    }
-  } else if (ttype->is_set()) {
-    if (binary_inline_) {
-      out <<
-        indent() << "$output .= pack('c', " << type_to_enum(((t_set*)ttype)->get_elem_type()) << ");" << endl <<
-        indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
-
-    } else {
-      indent(out) <<
-        "$output->writeSetBegin(" <<
-        type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
-        "count($" << prefix << "));" << endl;
-    }
-  } else if (ttype->is_list()) {
-    if (binary_inline_) {
-      out <<
-        indent() << "$output .= pack('c', " << type_to_enum(((t_list*)ttype)->get_elem_type()) << ");" << endl <<
-        indent() << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
-
-    } else {
-      indent(out) <<
-        "$output->writeListBegin(" <<
-        type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
-        "count($" << prefix << "));" << endl;
-    }
-  }
-
-  scope_up(out);
-
-  if (ttype->is_map()) {
-    string kiter = tmp("kiter");
-    string viter = tmp("viter");
-    indent(out) <<
-      "foreach ($" << prefix << " as " <<
-      "$" << kiter << " => $" << viter << ")" << endl;
-    scope_up(out);
-    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
-    scope_down(out);
-  } else if (ttype->is_set()) {
-    string iter = tmp("iter");
-    string iter_val = tmp("iter");
-    indent(out) <<
-      "foreach ($" << prefix << " as $" << iter << " => $" << iter_val << ")" << endl;
-    scope_up(out);
-    indent(out) << "if (is_scalar($" << iter_val << ")) {" << endl;
-    generate_serialize_set_element(out, (t_set*)ttype, iter);
-    indent(out) << "} else {" << endl;
-    generate_serialize_set_element(out, (t_set*)ttype, iter_val);
-    indent(out) << "}" << endl;
-    scope_down(out);
-  } else if (ttype->is_list()) {
-    string iter = tmp("iter");
-    indent(out) <<
-      "foreach ($" << prefix << " as $" << iter << ")" << endl;
-    scope_up(out);
-    generate_serialize_list_element(out, (t_list*)ttype, iter);
-    scope_down(out);
-  }
-
-  scope_down(out);
-
-  if (!binary_inline_) {
-    if (ttype->is_map()) {
-      indent(out) <<
-        "$output->writeMapEnd();" << endl;
-    } else if (ttype->is_set()) {
-      indent(out) <<
-        "$output->writeSetEnd();" << endl;
-    } else if (ttype->is_list()) {
-      indent(out) <<
-        "$output->writeListEnd();" << endl;
-    }
-  }
-
-  scope_down(out);
-}
-
-/**
- * Serializes the members of a map.
- *
- */
-void t_php_generator::generate_serialize_map_element(ofstream &out,
-                                                     t_map* tmap,
-                                                     string kiter,
-                                                     string viter) {
-  t_field kfield(tmap->get_key_type(), kiter);
-  generate_serialize_field(out, &kfield, "");
-
-  t_field vfield(tmap->get_val_type(), viter);
-  generate_serialize_field(out, &vfield, "");
-}
-
-/**
- * Serializes the members of a set.
- */
-void t_php_generator::generate_serialize_set_element(ofstream &out,
-                                                     t_set* tset,
-                                                     string iter) {
-  t_field efield(tset->get_elem_type(), iter);
-  generate_serialize_field(out, &efield, "");
-}
-
-/**
- * Serializes the members of a list.
- */
-void t_php_generator::generate_serialize_list_element(ofstream &out,
-                                                      t_list* tlist,
-                                                      string iter) {
-  t_field efield(tlist->get_elem_type(), iter);
-  generate_serialize_field(out, &efield, "");
-}
-
-/**
- * Declares a field, which may include initialization as necessary.
- *
- * @param ttype The type
- */
-string t_php_generator::declare_field(t_field* tfield, bool init, bool obj) {
-  string result = "$" + tfield->get_name();
-  if (init) {
-    t_type* type = get_true_type(tfield->get_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:
-        break;
-      case t_base_type::TYPE_STRING:
-        result += " = ''";
-        break;
-      case t_base_type::TYPE_BOOL:
-        result += " = 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:
-        result += " = 0";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        result += " = 0.0";
-        break;
-      default:
-        throw "compiler error: no PHP initializer for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      result += " = 0";
-    } else if (type->is_container()) {
-      result += " = array()";
-    } else if (type->is_struct() || type->is_xception()) {
-      if (obj) {
-        result += " = new " + php_namespace(type->get_program()) + type->get_name() + "()";
-      } else {
-        result += " = null";
-      }
-    }
-  }
-  return result + ";";
-}
-
-/**
- * Renders a function signature of the form 'type name(args)'
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_php_generator::function_signature(t_function* tfunction,
-                                           string prefix) {
-  return
-    prefix + tfunction->get_name() +
-    "(" + argument_list(tfunction->get_arglist()) + ")";
-}
-
-/**
- * Renders a field list
- */
-string t_php_generator::argument_list(t_struct* tstruct, bool addStructSignature) {
-  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 += ", ";
-    }
-
-    t_type* type = (*f_iter)->get_type();
-
-    //Set type name
-    if(addStructSignature && type->is_struct())
-    {
-      string className = php_namespace(type->get_program()) + php_namespace_directory("Definition", false) + classify(type->get_name());
-
-      result += className + " ";
-    }
-
-    result += "$" + (*f_iter)->get_name();
-  }
-  return result;
-}
-
-/**
- * Gets a typecast string for a particular type.
- */
-string t_php_generator::type_to_cast(t_type* type) {
-  if (type->is_base_type()) {
-    t_base_type* btype = (t_base_type*)type;
-    switch (btype->get_base()) {
-    case t_base_type::TYPE_BOOL:
-      return "(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:
-      return "(int)";
-    case t_base_type::TYPE_DOUBLE:
-      return "(double)";
-    case t_base_type::TYPE_STRING:
-      return "(string)";
-    default:
-      return "";
-    }
-  } else if (type->is_enum()) {
-    return "(int)";
-  }
-  return "";
-}
-
-/**
- * Converts the parse type to a C++ enum string for the given type.
- */
-string t_php_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 "TType::STRING";
-    case t_base_type::TYPE_BOOL:
-      return "TType::BOOL";
-    case t_base_type::TYPE_BYTE:
-      return "TType::BYTE";
-    case t_base_type::TYPE_I16:
-      return "TType::I16";
-    case t_base_type::TYPE_I32:
-      return "TType::I32";
-    case t_base_type::TYPE_I64:
-      return "TType::I64";
-    case t_base_type::TYPE_DOUBLE:
-      return "TType::DOUBLE";
-    }
-  } else if (type->is_enum()) {
-    return "TType::I32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "TType::STRUCT";
-  } else if (type->is_map()) {
-    return "TType::MAP";
-  } else if (type->is_set()) {
-    return "TType::SET";
-  } else if (type->is_list()) {
-    return "TType::LST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-THRIFT_REGISTER_GENERATOR(php, "PHP",
-"    inlined:         Generate PHP inlined files\n"
-"    server:          Generate PHP server stubs\n"
-"    oop:             Generate PHP with object oriented subclasses\n"
-"    rest:            Generate PHP REST processors\n"
-)
-
diff --git a/compiler/cpp/src/generate/t_py_generator.cc b/compiler/cpp/src/generate/t_py_generator.cc
deleted file mode 100644
index 4a540f2..0000000
--- a/compiler/cpp/src/generate/t_py_generator.cc
+++ /dev/null
@@ -1,2777 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#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"
-#include "version.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * Python code generator.
- *
- */
-class t_py_generator : public t_generator {
- public:
-  t_py_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_generator(program)
-  {
-    (void) option_string;
-    std::map<std::string, std::string>::const_iterator iter;
-
-    iter = parsed_options.find("new_style");
-    gen_newstyle_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("slots");
-    gen_slots_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("dynamic");
-    gen_dynamic_ = (iter != parsed_options.end());
-
-    if (gen_dynamic_) {
-      gen_newstyle_ = 0; // dynamic is newstyle
-      gen_dynbaseclass_ = "TBase";
-      gen_dynbaseclass_exc_ = "TExceptionBase";
-      import_dynbase_ = "from thrift.protocol.TBase import TBase, TExceptionBase\n";
-    }
-
-    iter = parsed_options.find("dynbase");
-    if (iter != parsed_options.end()) {
-      gen_dynbase_ = true;
-      gen_dynbaseclass_ = (iter->second);
-    }
-
-    iter = parsed_options.find("dynexc");
-    if (iter != parsed_options.end()) {
-      gen_dynbaseclass_exc_ = (iter->second);
-    }
-
-    iter = parsed_options.find("dynimport");
-    if (iter != parsed_options.end()) {
-      gen_dynbase_ = true;
-      import_dynbase_ = (iter->second);
-    }
-
-    iter = parsed_options.find("twisted");
-    gen_twisted_ = (iter != parsed_options.end());
-
-    iter = parsed_options.find("tornado");
-    gen_tornado_ = (iter != parsed_options.end());
-
-    if (gen_twisted_ && gen_tornado_) {
-      throw "at most one of 'twisted' and 'tornado' are allowed";
-    }
-
-    iter = parsed_options.find("utf8strings");
-    gen_utf8strings_ = (iter != parsed_options.end());
-
-    copy_options_ = option_string;
-
-    if (gen_twisted_) {
-      out_dir_base_ = "gen-py.twisted";
-    } else if (gen_tornado_) {
-      out_dir_base_ = "gen-py.tornado";
-    } else {
-      out_dir_base_ = "gen-py";
-    }
-  }
-
-  /**
-   * 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);
-
-  /**
-   * Struct generation code
-   */
-
-  void generate_py_struct(t_struct* tstruct, bool is_exception);
-  void generate_py_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_result=false);
-  void generate_py_struct_reader(std::ofstream& out, t_struct* tstruct);
-  void generate_py_struct_writer(std::ofstream& out, t_struct* tstruct);
-  void generate_py_struct_required_validator(std::ofstream& out, t_struct* tstruct);
-  void generate_py_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,
-                                          std::string prefix="",
-                                          bool inclass=false);
-
-  void generate_deserialize_struct       (std::ofstream &out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_deserialize_container    (std::ofstream &out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_deserialize_set_element  (std::ofstream &out,
-                                          t_set*      tset,
-                                          std::string prefix="");
-
-  void generate_deserialize_map_element  (std::ofstream &out,
-                                          t_map*      tmap,
-                                          std::string prefix="");
-
-  void generate_deserialize_list_element (std::ofstream &out,
-                                          t_list*     tlist,
-                                          std::string prefix="");
-
-  void generate_serialize_field          (std::ofstream &out,
-                                          t_field*    tfield,
-                                          std::string prefix="");
-
-  void generate_serialize_struct         (std::ofstream &out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_serialize_container      (std::ofstream &out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_serialize_map_element    (std::ofstream &out,
-                                          t_map*      tmap,
-                                          std::string kiter,
-                                          std::string viter);
-
-  void generate_serialize_set_element    (std::ofstream &out,
-                                          t_set*      tmap,
-                                          std::string iter);
-
-  void generate_serialize_list_element   (std::ofstream &out,
-                                          t_list*     tlist,
-                                          std::string iter);
-
-  void generate_python_docstring         (std::ofstream& out,
-                                          t_struct* tstruct);
-
-  void generate_python_docstring         (std::ofstream& out,
-                                          t_function* tfunction);
-
-  void generate_python_docstring         (std::ofstream& out,
-                                          t_doc*    tdoc,
-                                          t_struct* tstruct,
-                                          const char* subheader);
-
-  void generate_python_docstring         (std::ofstream& out,
-                                          t_doc* tdoc);
-
-  /**
-   * a type for specifying to function_signature what type of Tornado callback
-   * parameter to add
-   */
-
-  enum tornado_callback_t {
-    NONE = 0,
-    MANDATORY_FOR_ONEWAY_ELSE_NONE = 1,
-    OPTIONAL_FOR_ONEWAY_ELSE_MANDATORY = 2,
-  };
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string py_autogen_comment();
-  std::string py_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);
-  std::string type_name(t_type* ttype);
-  std::string function_signature(t_function* tfunction,
-                                 bool interface=false,
-                                 tornado_callback_t callback=NONE);
-  std::string argument_list(t_struct* tstruct,
-                            std::vector<std::string> *pre=NULL,
-                            std::vector<std::string> *post=NULL);
-  std::string type_to_enum(t_type* ttype);
-  std::string type_to_spec_args(t_type* ttype);
-
-  static bool is_valid_namespace(const std::string& sub_namespace) {
-    return sub_namespace == "twisted";
-  }
-
-  static std::string get_real_py_module(const t_program* program, bool gen_twisted) {
-    if(gen_twisted) {
-      std::string twisted_module = program->get_namespace("py.twisted");
-      if(!twisted_module.empty()){
-        return twisted_module;
-      }
-    }
-
-    std::string real_module = program->get_namespace("py");
-    if (real_module.empty()) {
-      return program->get_name();
-    }
-    return real_module;
-  }
-
- private:
-
-  /**
-   * True if we should generate new-style classes.
-   */
-  bool gen_newstyle_;
-
-   /**
-   * True if we should generate dynamic style classes.
-   */
-  bool gen_dynamic_;
-
-  bool gen_dynbase_;
-  std::string gen_dynbaseclass_;
-  std::string gen_dynbaseclass_exc_;
-
-  std::string import_dynbase_;
-
-  bool gen_slots_;
-
-  std::string copy_options_;
-
-  /**
-   * True if we should generate Twisted-friendly RPC services.
-   */
-  bool gen_twisted_;
-
-  /**
-   * True if we should generate code for use with Tornado
-   */
-  bool gen_tornado_;
-
-  /**
-   * True if strings should be encoded using utf-8.
-   */
-  bool gen_utf8strings_;
-
-  /**
-   * File streams
-   */
-
-  std::ofstream f_types_;
-  std::ofstream f_consts_;
-  std::ofstream f_service_;
-
-  std::string package_dir_;
-  std::string module_;
-
-};
-
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * streams.
- *
- * @param tprogram The program to generate
- */
-void t_py_generator::init_generator() {
-  // Make output directory
-  string module = get_real_py_module(program_, gen_twisted_);
-  package_dir_ = get_out_dir();
-  module_ = module;
-  while (true) {
-    // TODO: Do better error checking here.
-    MKDIR(package_dir_.c_str());
-    std::ofstream init_py((package_dir_+"/__init__.py").c_str(), std::ios_base::app);
-    init_py.close();
-    if (module.empty()) {
-      break;
-    }
-    string::size_type pos = module.find('.');
-    if (pos == string::npos) {
-      package_dir_ += "/";
-      package_dir_ += module;
-      module.clear();
-    } else {
-      package_dir_ += "/";
-      package_dir_ += module.substr(0, pos);
-      module.erase(0, pos+1);
-    }
-  }
-
-  // Make output file
-  string f_types_name = package_dir_+"/"+"ttypes.py";
-  f_types_.open(f_types_name.c_str());
-
-  string f_consts_name = package_dir_+"/"+"constants.py";
-  f_consts_.open(f_consts_name.c_str());
-
-  string f_init_name = package_dir_+"/__init__.py";
-  ofstream f_init;
-  f_init.open(f_init_name.c_str());
-  f_init  <<
-    "__all__ = ['ttypes', 'constants'";
-  vector<t_service*> services = program_->get_services();
-  vector<t_service*>::iterator sv_iter;
-  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
-    f_init << ", '" << (*sv_iter)->get_name() << "'";
-  }
-  f_init << "]" << endl;
-  f_init.close();
-
-  // Print header
-  f_types_ <<
-    py_autogen_comment() << endl <<
-    py_imports() << endl <<
-    render_includes() << endl <<
-    render_fastbinary_includes() <<
-    endl << endl;
-
-  f_consts_ <<
-    py_autogen_comment() << endl <<
-    py_imports() << endl <<
-    "from ttypes import *" << endl <<
-    endl;
-}
-
-/**
- * Renders all the imports necessary for including another Thrift program
- */
-string t_py_generator::render_includes() {
-  const vector<t_program*>& includes = program_->get_includes();
-  string result = "";
-  for (size_t i = 0; i < includes.size(); ++i) {
-    result += "import " + get_real_py_module(includes[i], gen_twisted_) + ".ttypes\n";
-  }
-  if (includes.size() > 0) {
-    result += "\n";
-  }
-  return result;
-}
-
-/**
- * Renders all the imports necessary to use the accelerated TBinaryProtocol
- */
-string t_py_generator::render_fastbinary_includes() {
-  string hdr = "";
-  if (gen_dynamic_) {
-    hdr += std::string(import_dynbase_);
-  } else {
-    hdr +=
-      "from thrift.transport import TTransport\n"
-      "from thrift.protocol import TBinaryProtocol, TProtocol\n"
-      "try:\n"
-      "  from thrift.protocol import fastbinary\n"
-      "except:\n"
-      "  fastbinary = None\n";
-  }
-  return hdr;
-}
-
-/**
- * Autogen'd comment
- */
-string t_py_generator::py_autogen_comment() {
-  return
-    std::string("#\n") +
-    "# Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" +
-    "#\n" +
-    "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
-    "#\n" +
-    "#  options string: " + copy_options_  + "\n" +
-    "#\n";
-}
-
-/**
- * Prints standard thrift imports
- */
-string t_py_generator::py_imports() {
-  return
-    string("from thrift.Thrift import TType, TMessageType, TException, TApplicationException");
-}
-
-/**
- * Closes the type files
- */
-void t_py_generator::close_generator() {
-  // Close types file
-  f_types_.close();
-  f_consts_.close();
-}
-
-/**
- * Generates a typedef. This is not done in Python, types are all implicit.
- *
- * @param ttypedef The type definition
- */
-void t_py_generator::generate_typedef(t_typedef* ttypedef) {
-  (void) ttypedef;
-}
-
-/**
- * Generates code for an enumerated type. Done using a class to scope
- * the values.
- *
- * @param tenum The enumeration
- */
-void t_py_generator::generate_enum(t_enum* tenum) {
-  std::ostringstream to_string_mapping, from_string_mapping;
-
-  f_types_ <<
-    "class " << tenum->get_name() <<
-    (gen_newstyle_ ? "(object)" : "") <<
-    (gen_dynamic_ ? "(" + gen_dynbaseclass_ + ")" : "") <<
-    ":" << endl;
-  indent_up();
-  generate_python_docstring(f_types_, tenum);
-
-  to_string_mapping << indent() << "_VALUES_TO_NAMES = {" << endl;
-  from_string_mapping << indent() << "_NAMES_TO_VALUES = {" << endl;
-
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    indent(f_types_) << (*c_iter)->get_name() << " = " << value << endl;
-
-    // Dictionaries to/from string names of enums
-    to_string_mapping <<
-      indent() << indent() << value << ": \"" <<
-      escape_string((*c_iter)->get_name()) << "\"," << endl;
-    from_string_mapping <<
-      indent() << indent() << '"' << escape_string((*c_iter)->get_name()) <<
-      "\": " << value << ',' << endl;
-  }
-  to_string_mapping << indent() << "}" << endl;
-  from_string_mapping << indent() << "}" << endl;
-
-  indent_down();
-  f_types_ << endl;
-  f_types_ << to_string_mapping.str() << endl << from_string_mapping.str() << endl;
-}
-
-/**
- * Generate a constant value
- */
-void t_py_generator::generate_const(t_const* tconst) {
-  t_type* type = tconst->get_type();
-  string name = tconst->get_name();
-  t_const_value* value = tconst->get_value();
-
-  indent(f_consts_) << name << " = " << render_const_value(type, value);
-  f_consts_ << 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_py_generator::render_const_value(t_type* type, t_const_value* value) {
-  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 << type_name(type) << "(**{" << 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();
-      }
-      out << indent();
-      out << render_const_value(g_type_string, v_iter->first);
-      out << " : ";
-      out << render_const_value(field_type, v_iter->second);
-      out << "," << endl;
-    }
-    indent_down();
-    indent(out) << "})";
-  } else if (type->is_map()) {
-    t_type* ktype = ((t_map*)type)->get_key_type();
-    t_type* vtype = ((t_map*)type)->get_val_type();
-    out << "{" << endl;
-    indent_up();
-    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) {
-      out << indent();
-      out << render_const_value(ktype, v_iter->first);
-      out << " : ";
-      out << render_const_value(vtype, v_iter->second);
-      out << "," << endl;
-    }
-    indent_down();
-    indent(out) << "}";
-  } else if (type->is_list() || type->is_set()) {
-    t_type* etype;
-    if (type->is_list()) {
-      etype = ((t_list*)type)->get_elem_type();
-    } else {
-      etype = ((t_set*)type)->get_elem_type();
-    }
-    if (type->is_set()) {
-      out << "set(";
-    }
-    out << "[" << endl;
-    indent_up();
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      out << indent();
-      out << render_const_value(etype, *v_iter);
-      out << "," << endl;
-    }
-    indent_down();
-    indent(out) << "]";
-    if (type->is_set()) {
-      out << ")";
-    }
-  } else {
-    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
-  }
-
-  return out.str();
-}
-
-/**
- * Generates a python struct
- */
-void t_py_generator::generate_struct(t_struct* tstruct) {
-  generate_py_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_py_generator::generate_xception(t_struct* txception) {
-  generate_py_struct(txception, true);
-}
-
-/**
- * Generates a python struct
- */
-void t_py_generator::generate_py_struct(t_struct* tstruct,
-                                        bool is_exception) {
-  generate_py_struct_definition(f_types_, tstruct, is_exception);
-}
-
-/**
- * Generates a struct definition for a thrift data type.
- *
- * @param tstruct The struct definition
- */
-void t_py_generator::generate_py_struct_definition(ofstream& out,
-                                                   t_struct* tstruct,
-                                                   bool is_exception,
-                                                   bool is_result) {
-  (void) 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;
-
-  out << std::endl <<
-    "class " << tstruct->get_name();
-  if (is_exception) {
-    if (gen_dynamic_) {
-      out << "(" << gen_dynbaseclass_exc_ << ")";
-    } else {
-      out << "(TException)";
-    }
-  } else {
-    if (gen_newstyle_) {
-      out << "(object)";
-    } else if (gen_dynamic_) {
-      out << "(" << gen_dynbaseclass_ << ")";
-    }
-  }
-  out << ":" << endl;
-  indent_up();
-  generate_python_docstring(out, tstruct);
-
-  out << 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 -> None | (tag, type_enum, name, spec_args, default)
-     tag -> integer
-     type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ...
-     name -> string_literal
-     default -> None  # Handled by __init__
-     spec_args -> None  # 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.
-  */
-
-  if (gen_slots_) {
-    indent(out) << "__slots__ = [ " << endl;
-    indent_up();
-    for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) {
-      indent(out) <<  "'" << (*m_iter)->get_name()  << "'," << endl;
-    }
-    indent_down();
-    indent(out) << " ]" << endl << endl;
-
-  }
-
-  // TODO(dreiss): Look into generating an empty tuple instead of None
-  // for structures with no members.
-  // TODO(dreiss): Test encoding of structs where some inner structs
-  // don't have thrift_spec.
-  if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) {
-    indent(out) << "thrift_spec = (" << endl;
-    indent_up();
-
-    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++) {
-        indent(out) << "None, # " << sorted_keys_pos << endl;
-      }
-
-      indent(out) << "(" << (*m_iter)->get_key() << ", "
-            << type_to_enum((*m_iter)->get_type()) << ", "
-            << "'" << (*m_iter)->get_name() << "'" << ", "
-            << type_to_spec_args((*m_iter)->get_type()) << ", "
-            << render_field_default_value(*m_iter) << ", "
-            << "),"
-            << " # " << sorted_keys_pos
-            << endl;
-
-      sorted_keys_pos ++;
-    }
-
-    indent_down();
-    indent(out) << ")" << endl << endl;
-  } else {
-    indent(out) << "thrift_spec = None" << endl;
-  }
-
-
-  if (members.size() > 0) {
-    out <<
-      indent() << "def __init__(self,";
-
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      // This fills in default values, as opposed to nulls
-      out << " " << declare_argument(*m_iter) << ",";
-    }
-
-    out << "):" << endl;
-
-    indent_up();
-
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      // Initialize fields
-      t_type* type = (*m_iter)->get_type();
-      if (!type->is_base_type() && !type->is_enum() && (*m_iter)->get_value() != NULL) {
-        indent(out) <<
-          "if " << (*m_iter)->get_name() << " is " << "self.thrift_spec[" <<
-            (*m_iter)->get_key() << "][4]:" << endl;
-        indent(out) << "  " << (*m_iter)->get_name() << " = " <<
-          render_field_default_value(*m_iter) << endl;
-      }
-      indent(out) <<
-        "self." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << endl;
-    }
-
-    indent_down();
-
-    out << endl;
-  }
-
-  if (!gen_dynamic_) {
-    generate_py_struct_reader(out, tstruct);
-    generate_py_struct_writer(out, tstruct);
-  }
-
-  // For exceptions only, generate a __str__ method. This is
-  // because when raised exceptions are printed to the console, __repr__
-  // isn't used. See python bug #5882
-  if (is_exception) {
-    out <<
-      indent() << "def __str__(self):" << endl <<
-      indent() << "  return repr(self)" << endl <<
-      endl;
-  }
-
-  if (!gen_slots_) {
-    // Printing utilities so that on the command line thrift
-    // structs look pretty like dictionaries
-    out <<
-      indent() << "def __repr__(self):" << endl <<
-      indent() << "  L = ['%s=%r' % (key, value)" << endl <<
-      indent() << "    for key, value in self.__dict__.iteritems()]" << endl <<
-      indent() << "  return '%s(%s)' % (self.__class__.__name__, ', '.join(L))" << endl <<
-      endl;
-
-    // Equality and inequality methods that compare by value
-    out <<
-      indent() << "def __eq__(self, other):" << endl;
-    indent_up();
-    out <<
-      indent() << "return isinstance(other, self.__class__) and "
-                  "self.__dict__ == other.__dict__" << endl;
-    indent_down();
-    out << endl;
-
-    out <<
-      indent() << "def __ne__(self, other):" << endl;
-    indent_up();
-
-    out <<
-      indent() << "return not (self == other)" << endl;
-    indent_down();
-  } else if (!gen_dynamic_) {
-    // no base class available to implement __eq__ and __repr__ and __ne__ for us
-    // so we must provide one that uses __slots__
-    out <<
-      indent() << "def __repr__(self):" << endl <<
-      indent() << "  L = ['%s=%r' % (key, getattr(self, key))" << endl <<
-      indent() << "    for key in self.__slots__]" << endl <<
-      indent() << "  return '%s(%s)' % (self.__class__.__name__, ', '.join(L))" << endl <<
-      endl;
-
-    // Equality method that compares each attribute by value and type, walking __slots__
-    out <<
-      indent() << "def __eq__(self, other):" << endl <<
-      indent() << "  if not isinstance(other, self.__class__):" << endl <<
-      indent() << "    return False" << endl <<
-      indent() << "  for attr in self.__slots__:" << endl <<
-      indent() << "    my_val = getattr(self, attr)" << endl <<
-      indent() << "    other_val = getattr(other, attr)" << endl <<
-      indent() << "    if my_val != other_val:" << endl <<
-      indent() << "      return False" << endl <<
-      indent() << "  return True" << endl <<
-      endl;
-
-    out <<
-      indent() << "def __ne__(self, other):" << endl <<
-      indent() << "  return not (self == other)" << endl <<
-      endl;
-  }
-  indent_down();
-}
-
-/**
- * Generates the read method for a struct
- */
-void t_py_generator::generate_py_struct_reader(ofstream& out,
-                                                t_struct* tstruct) {
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  indent(out) <<
-    "def read(self, iprot):" << endl;
-  indent_up();
-
-  indent(out) <<
-    "if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated "
-    "and isinstance(iprot.trans, TTransport.CReadableTransport) "
-    "and self.thrift_spec is not None "
-    "and fastbinary is not None:" << endl;
-  indent_up();
-
-  indent(out) <<
-    "fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))" << endl;
-  indent(out) <<
-    "return" << endl;
-  indent_down();
-
-  indent(out) <<
-    "iprot.readStructBegin()" << endl;
-
-  // Loop over reading in fields
-  indent(out) <<
-    "while True:" << endl;
-    indent_up();
-
-    // Read beginning field marker
-    indent(out) <<
-      "(fname, ftype, fid) = iprot.readFieldBegin()" << endl;
-
-    // Check for field STOP marker and break
-    indent(out) <<
-      "if ftype == TType.STOP:" << endl;
-    indent_up();
-    indent(out) <<
-      "break" << endl;
-    indent_down();
-
-    // Switch statement on the field we are reading
-    bool first = true;
-
-    // Generate deserialization code for known cases
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      if (first) {
-        first = false;
-        out <<
-          indent() << "if ";
-      } else {
-        out <<
-          indent() << "elif ";
-      }
-      out << "fid == " << (*f_iter)->get_key() << ":" << endl;
-      indent_up();
-      indent(out) << "if ftype == " << type_to_enum((*f_iter)->get_type()) << ":" << endl;
-      indent_up();
-      generate_deserialize_field(out, *f_iter, "self.");
-      indent_down();
-      out <<
-        indent() << "else:" << endl <<
-        indent() << "  iprot.skip(ftype)" << endl;
-      indent_down();
-    }
-
-    // In the default case we skip the field
-    out <<
-      indent() <<  "else:" << endl <<
-      indent() <<  "  iprot.skip(ftype)" << endl;
-
-    // Read field end marker
-    indent(out) <<
-      "iprot.readFieldEnd()" << endl;
-
-    indent_down();
-
-    indent(out) <<
-      "iprot.readStructEnd()" << endl;
-
-    indent_down();
-  out << endl;
-}
-
-void t_py_generator::generate_py_struct_writer(ofstream& out,
-                                               t_struct* tstruct) {
-  string name = tstruct->get_name();
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  indent(out) <<
-    "def write(self, oprot):" << endl;
-  indent_up();
-
-  indent(out) <<
-    "if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated "
-    "and self.thrift_spec is not None "
-    "and fastbinary is not None:" << endl;
-  indent_up();
-
-  indent(out) <<
-    "oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))" << endl;
-  indent(out) <<
-    "return" << endl;
-  indent_down();
-
-  indent(out) <<
-    "oprot.writeStructBegin('" << name << "')" << endl;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    // Write field header
-    indent(out) <<
-      "if self." << (*f_iter)->get_name() << " is not None:" << endl;
-    indent_up();
-    indent(out) <<
-      "oprot.writeFieldBegin(" <<
-      "'" << (*f_iter)->get_name() << "', " <<
-      type_to_enum((*f_iter)->get_type()) << ", " <<
-      (*f_iter)->get_key() << ")" << endl;
-
-    // Write field contents
-    generate_serialize_field(out, *f_iter, "self.");
-
-    // Write field closer
-    indent(out) <<
-      "oprot.writeFieldEnd()" << endl;
-
-    indent_down();
-  }
-
-  // Write the struct map
-  out <<
-    indent() << "oprot.writeFieldStop()" << endl <<
-    indent() << "oprot.writeStructEnd()" << endl;
-
-  out << endl;
-
-  indent_down();
-  generate_py_struct_required_validator(out, tstruct);
-  out <<
-    endl;
-}
-
-void t_py_generator::generate_py_struct_required_validator(ofstream& out,
-                                               t_struct* tstruct) {
-  indent(out) << "def validate(self):" << endl;
-  indent_up();
-
-  const vector<t_field*>& fields = tstruct->get_members();
-
-  if (fields.size() > 0) {
-    vector<t_field*>::const_iterator f_iter;
-
-    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-      t_field* field = (*f_iter);
-      if (field->get_req() == t_field::T_REQUIRED) {
-        indent(out) << "if self." << field->get_name() << " is None:" << endl;
-        indent(out) << "  raise TProtocol.TProtocolException(message='Required field " <<
-          field->get_name() << " is unset!')" << endl;
-      }
-    }
-  }
-
-  indent(out) << "return" << endl << endl;
-  indent_down();
-}
-
-/**
- * Generates a thrift service.
- *
- * @param tservice The service definition
- */
-void t_py_generator::generate_service(t_service* tservice) {
-  string f_service_name = package_dir_+"/"+service_name_+".py";
-  f_service_.open(f_service_name.c_str());
-
-  f_service_ <<
-    py_autogen_comment() << endl <<
-    py_imports() << endl;
-
-  if (tservice->get_extends() != NULL) {
-    f_service_ <<
-      "import " << get_real_py_module(tservice->get_extends()->get_program(), gen_twisted_) <<
-      "." << tservice->get_extends()->get_name() << endl;
-  }
-
-  f_service_ <<
-    "from ttypes import *" << endl <<
-    "from thrift.Thrift import TProcessor" << endl <<
-    render_fastbinary_includes() << endl;
-
-  if (gen_twisted_) {
-    f_service_ <<
-      "from zope.interface import Interface, implements" << endl <<
-      "from twisted.internet import defer" << endl <<
-      "from thrift.transport import TTwisted" << endl;
-  } else if (gen_tornado_) {
-    f_service_ << "from tornado import gen" << endl;
-    f_service_ << "from tornado import stack_context" << endl;
-  }
-
-  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_.close();
-}
-
-/**
- * Generates helper functions for a service.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_py_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;
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    t_struct* ts = (*f_iter)->get_arglist();
-    generate_py_struct_definition(f_service_, ts, false);
-    generate_py_function_helpers(*f_iter);
-  }
-}
-
-/**
- * Generates a struct and helpers for a function.
- *
- * @param tfunction The function
- */
-void t_py_generator::generate_py_function_helpers(t_function* tfunction) {
-  if (!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_py_struct_definition(f_service_, &result, false, true);
-  }
-}
-
-/**
- * Generates a service interface definition.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_py_generator::generate_service_interface(t_service* tservice) {
-  string extends = "";
-  string extends_if = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_if = "(" + extends + ".Iface)";
-  } else {
-    if (gen_twisted_) {
-      extends_if = "(Interface)";
-    } else if (gen_newstyle_ || gen_dynamic_ || gen_tornado_) {
-      extends_if = "(object)";
-    }
-  }
-
-  f_service_ <<
-    "class Iface" << extends_if << ":" << endl;
-  indent_up();
-  generate_python_docstring(f_service_, tservice);
-  vector<t_function*> functions = tservice->get_functions();
-  if (functions.empty()) {
-    f_service_ <<
-      indent() << "pass" << endl;
-  } else {
-    vector<t_function*>::iterator f_iter;
-    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-      f_service_ <<
-        indent() << "def " << function_signature(*f_iter, true, OPTIONAL_FOR_ONEWAY_ELSE_MANDATORY) << ":" << endl;
-      indent_up();
-      generate_python_docstring(f_service_, (*f_iter));
-      f_service_ <<
-        indent() << "pass" << endl << endl;
-      indent_down();
-    }
-  }
-
-  indent_down();
-  f_service_ <<
-    endl;
-}
-
-/**
- * Generates a service client definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_py_generator::generate_service_client(t_service* tservice) {
-  string extends = "";
-  string extends_client = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    if (gen_twisted_) {
-      extends_client = "(" + extends + ".Client)";
-    } else {
-      extends_client = extends + ".Client, ";
-    }
-  } else {
-    if (gen_twisted_ && (gen_newstyle_ || gen_dynamic_)) {
-      extends_client = "(object)";
-    }
-  }
-
-  if (gen_twisted_) {
-    f_service_ <<
-      "class Client" << extends_client << ":" << endl <<
-      "  implements(Iface)" << endl << endl;
-  } else {
-    f_service_ <<
-      "class Client(" << extends_client << "Iface):" << endl;
-  }
-  indent_up();
-  generate_python_docstring(f_service_, tservice);
-
-  // Constructor function
-  if (gen_twisted_) {
-    f_service_ <<
-      indent() << "def __init__(self, transport, oprot_factory):" << endl;
-  } else if (gen_tornado_) {
-    f_service_ <<
-      indent() << "def __init__(self, transport, iprot_factory, oprot_factory=None):" << endl;
-  } else {
-    f_service_ <<
-      indent() << "def __init__(self, iprot, oprot=None):" << endl;
-  }
-  if (extends.empty()) {
-    if (gen_twisted_) {
-      f_service_ <<
-        indent() << "  self._transport = transport" << endl <<
-        indent() << "  self._oprot_factory = oprot_factory" << endl <<
-        indent() << "  self._seqid = 0" << endl <<
-        indent() << "  self._reqs = {}" << endl <<
-        endl;
-    } else if (gen_tornado_) {
-      f_service_ <<
-        indent() << "  self._transport = transport" << endl <<
-        indent() << "  self._iprot_factory = iprot_factory" << endl <<
-        indent() << "  self._oprot_factory = (oprot_factory if oprot_factory is not None" << endl <<
-        indent() << "                         else iprot_factory)" << endl <<
-        indent() << "  self._seqid = 0" << endl <<
-        indent() << "  self._reqs = {}" << endl <<
-        endl;
-    } else {
-      f_service_ <<
-        indent() << "  self._iprot = self._oprot = iprot" << endl <<
-        indent() << "  if oprot is not None:" << endl <<
-        indent() << "    self._oprot = oprot" << endl <<
-        indent() << "  self._seqid = 0" << endl <<
-        endl;
-    }
-  } else {
-    if (gen_twisted_) {
-      f_service_ <<
-        indent() << "  " << extends << ".Client.__init__(self, transport, oprot_factory)" << endl <<
-        endl;
-    } else if (gen_tornado_) {
-      f_service_ <<
-        indent() << "  " << extends << ".Client.__init__(self, transport, iprot_factory, oprot_factory)" << endl <<
-        endl;
-    } else {
-      f_service_ <<
-        indent() << "  " << extends << ".Client.__init__(self, iprot, oprot)" << endl <<
-        endl;
-    }
-  }
-
-  if (gen_tornado_ && extends.empty()) {
-    f_service_ <<
-      indent() << "@gen.engine" << endl <<
-      indent() << "def recv_dispatch(self):" << endl <<
-      indent() << "  \"\"\"read a response from the wire. schedule exactly one per send that" << endl <<
-      indent() << "  expects a response, but it doesn't matter which callee gets which" << endl <<
-      indent() << "  response; they're dispatched here properly\"\"\"" << endl <<
-      endl <<
-      indent() << "  # wait for a frame header" << endl <<
-      indent() << "  frame = yield gen.Task(self._transport.readFrame)" << endl <<
-      indent() << "  tr = TTransport.TMemoryBuffer(frame)" << endl <<
-      indent() << "  iprot = self._iprot_factory.getProtocol(tr)" << endl <<
-      indent() << "  (fname, mtype, rseqid) = iprot.readMessageBegin()" << endl <<
-      indent() << "  method = getattr(self, 'recv_' + fname)" << endl <<
-      indent() << "  method(iprot, mtype, rseqid)" << 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 = (*f_iter)->get_name();
-
-    // Open function
-    indent(f_service_) <<
-      "def " << function_signature(*f_iter, false, OPTIONAL_FOR_ONEWAY_ELSE_MANDATORY) << ":" << endl;
-    indent_up();
-    generate_python_docstring(f_service_, (*f_iter));
-    if (gen_twisted_) {
-      indent(f_service_) << "self._seqid += 1" << endl;
-      if (!(*f_iter)->is_oneway()) {
-        indent(f_service_) <<
-          "d = self._reqs[self._seqid] = defer.Deferred()" << endl;
-      }
-    } else if (gen_tornado_) {
-      indent(f_service_) << "self._seqid += 1" << endl;
-      if (!(*f_iter)->is_oneway()) {
-        indent(f_service_) <<
-          "self._reqs[self._seqid] = callback" << endl;
-      }
-    }
-
-    indent(f_service_) <<
-      "self.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();
-    }
-
-    if (gen_tornado_ && (*f_iter)->is_oneway()) {
-      if (first) {
-        first = false;
-      } else {
-        f_service_ << ", ";
-      }
-      f_service_ << "callback";
-    }
-
-    f_service_ << ")" << endl;
-
-    if (!(*f_iter)->is_oneway()) {
-      f_service_ << indent();
-      if (gen_twisted_) {
-        f_service_ << "return d" << endl;
-      } else if (gen_tornado_) {
-        f_service_ << "self.recv_dispatch()" << endl;
-      } else {
-        if (!(*f_iter)->get_returntype()->is_void()) {
-          f_service_ << "return ";
-        }
-        f_service_ <<
-          "self.recv_" << funname << "()" << endl;
-      }
-    } else {
-      if (gen_twisted_) {
-        f_service_ <<
-          indent() << "return defer.succeed(None)" << endl;
-      }
-    }
-    indent_down();
-    f_service_ << endl;
-
-    indent(f_service_) <<
-      "def send_" << function_signature(*f_iter, false, MANDATORY_FOR_ONEWAY_ELSE_NONE) << ":" << endl;
-
-    indent_up();
-
-    std::string argsname = (*f_iter)->get_name() + "_args";
-
-    // Serialize the request header
-    if (gen_twisted_ || gen_tornado_) {
-      f_service_ <<
-        indent() << "oprot = self._oprot_factory.getProtocol(self._transport)" << endl <<
-        indent() <<
-          "oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType.CALL, self._seqid)"
-        << endl;
-    } else {
-      f_service_ <<
-        indent() << "self._oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType.CALL, self._seqid)" << endl;
-    }
-
-    f_service_ <<
-      indent() << "args = " << argsname << "()" << endl;
-
-    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-      f_service_ <<
-        indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << endl;
-    }
-
-    // Write to the stream
-    if (gen_twisted_) {
-      f_service_ <<
-        indent() << "args.write(oprot)" << endl <<
-        indent() << "oprot.writeMessageEnd()" << endl <<
-        indent() << "oprot.trans.flush()" << endl;
-    } else if (gen_tornado_) {
-      f_service_ <<
-        indent() << "args.write(oprot)" << endl <<
-        indent() << "oprot.writeMessageEnd()" << endl;
-      if ((*f_iter)->is_oneway()) {
-        // send_* carry the callback so you can block on the write's flush
-        // (rather than on receipt of the response)
-        f_service_ <<
-          indent() << "oprot.trans.flush(callback=callback)" << endl;
-      } else {
-        f_service_ <<
-          indent() << "oprot.trans.flush()" << endl;
-      }
-    } else {
-      f_service_ <<
-        indent() << "args.write(self._oprot)" << endl <<
-        indent() << "self._oprot.writeMessageEnd()" << endl <<
-        indent() << "self._oprot.trans.flush()" << endl;
-    }
-
-    indent_down();
-
-    if (!(*f_iter)->is_oneway()) {
-      std::string resultname = (*f_iter)->get_name() + "_result";
-      // Open function
-      f_service_ <<
-        endl;
-      if (gen_twisted_ || gen_tornado_) {
-        f_service_ <<
-          indent() << "def recv_" << (*f_iter)->get_name() <<
-              "(self, iprot, mtype, rseqid):" << endl;
-      } else {
-        t_struct noargs(program_);
-        t_function recv_function((*f_iter)->get_returntype(),
-                               string("recv_") + (*f_iter)->get_name(),
-                               &noargs);
-        f_service_ <<
-          indent() << "def " << function_signature(&recv_function) << ":" << endl;
-      }
-      indent_up();
-
-      // TODO(mcslee): Validate message reply here, seq ids etc.
-
-      if (gen_twisted_) {
-        f_service_ <<
-          indent() << "d = self._reqs.pop(rseqid)" << endl;
-      } else if (gen_tornado_) {
-        f_service_ <<
-          indent() << "callback = self._reqs.pop(rseqid)" << endl;
-      } else {
-        f_service_ <<
-          indent() << "(fname, mtype, rseqid) = self._iprot.readMessageBegin()" << endl;
-      }
-
-      f_service_ <<
-        indent() << "if mtype == TMessageType.EXCEPTION:" << endl <<
-        indent() << "  x = TApplicationException()" << endl;
-
-      if (gen_twisted_) {
-        f_service_ <<
-          indent() << "  x.read(iprot)" << endl <<
-          indent() << "  iprot.readMessageEnd()" << endl <<
-          indent() << "  return d.errback(x)" << endl <<
-          indent() << "result = " << resultname << "()" << endl <<
-          indent() << "result.read(iprot)" << endl <<
-          indent() << "iprot.readMessageEnd()" << endl;
-      } else if (gen_tornado_) {
-        f_service_ <<
-          indent() << "  x.read(iprot)" << endl <<
-          indent() << "  iprot.readMessageEnd()" << endl <<
-          indent() << "  callback(x)" << endl <<
-          indent() << "  return" << endl <<
-          indent() << "result = " << resultname << "()" << endl <<
-          indent() << "result.read(iprot)" << endl <<
-          indent() << "iprot.readMessageEnd()" << endl;
-      } else {
-        f_service_ <<
-          indent() << "  x.read(self._iprot)" << endl <<
-          indent() << "  self._iprot.readMessageEnd()" << endl <<
-          indent() << "  raise x" << endl <<
-          indent() << "result = " << resultname << "()" << endl <<
-          indent() << "result.read(self._iprot)" << endl <<
-          indent() << "self._iprot.readMessageEnd()" << endl;
-      }
-
-      // Careful, only return _result if not a void function
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_ <<
-          indent() << "if result.success is not None:" << endl;
-          if (gen_twisted_) {
-            f_service_ <<
-              indent() << "  return d.callback(result.success)" << endl;
-          } else if (gen_tornado_) {
-            f_service_ <<
-              indent() << "  callback(result.success)" << endl <<
-              indent() << "  return" << endl;
-          } else {
-            f_service_ <<
-              indent() << "  return 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." << (*x_iter)->get_name() << " is not None:" << endl;
-          if (gen_twisted_) {
-            f_service_ <<
-              indent() << "  return d.errback(result." << (*x_iter)->get_name() << ")" << endl;
-
-          } else if (gen_tornado_) {
-            f_service_ <<
-              indent() << "  callback(result." << (*x_iter)->get_name() << ")" << endl <<
-              indent() << "  return" << endl;
-          } else {
-            f_service_ <<
-              indent() << "  raise result." << (*x_iter)->get_name() << "" << endl;
-          }
-      }
-
-      // Careful, only return _result if not a void function
-      if ((*f_iter)->get_returntype()->is_void()) {
-        if (gen_twisted_) {
-          f_service_ <<
-            indent() << "return d.callback(None)" << endl;
-        } else if (gen_tornado_) {
-          f_service_ <<
-            indent() << "callback(None)" << endl <<
-            indent() << "return" << endl;
-        } else {
-          f_service_ <<
-            indent() << "return" << endl;
-        }
-      } else {
-        if (gen_twisted_) {
-          f_service_ <<
-            indent() << "return d.errback(TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\"))" << endl;
-        } else if (gen_tornado_) {
-          f_service_ <<
-            indent() << "callback(TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\"))" << endl <<
-            indent() << "return" << endl;
-        } else {
-          f_service_ <<
-            indent() << "raise TApplicationException(TApplicationException.MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
-        }
-      }
-
-      // Close function
-      indent_down();
-      f_service_ << 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_py_generator::generate_service_remote(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  //Get all function from parents
-  t_service* parent = tservice->get_extends();
-  while(parent != NULL) {
-    vector<t_function*> p_functions = parent->get_functions();
-    functions.insert(functions.end(), p_functions.begin(), p_functions.end());
-    parent = parent->get_extends();
-  }
-  vector<t_function*>::iterator f_iter;
-
-  string f_remote_name = package_dir_+"/"+service_name_+"-remote";
-  ofstream f_remote;
-  f_remote.open(f_remote_name.c_str());
-
-  f_remote <<
-    "#!/usr/bin/env python" << endl <<
-    py_autogen_comment() << endl <<
-    "import sys" << endl <<
-    "import pprint" << endl <<
-    "from urlparse import urlparse" << endl <<
-    "from thrift.transport import TTransport" << endl <<
-    "from thrift.transport import TSocket" << endl <<
-    "from thrift.transport import THttpClient" << endl <<
-    "from thrift.protocol import TBinaryProtocol" << endl <<
-    endl;
-
-  f_remote <<
-    "from " << module_ << " import " << service_name_ << endl <<
-    "from " << module_ << ".ttypes import *" << endl <<
-    endl;
-
-  f_remote <<
-    "if len(sys.argv) <= 1 or sys.argv[1] == '--help':" << endl <<
-    "  print ''" << endl <<
-    "  print 'Usage: ' + sys.argv[0] + ' [-h host[:port]] [-u url] [-f[ramed]] function [arg1 [arg2...]]'" << endl <<
-    "  print ''" << endl <<
-    "  print 'Functions:'" << endl;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_remote <<
-      "  print '  " << (*f_iter)->get_returntype()->get_name() << " " << (*f_iter)->get_name() << "(";
-    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();
-    bool first = true;
-    for (int i = 0; i < num_args; ++i) {
-      if (first) {
-        first = false;
-      } else {
-        f_remote << ", ";
-      }
-      f_remote <<
-        args[i]->get_type()->get_name() << " " << args[i]->get_name();
-    }
-    f_remote << ")'" << endl;
-  }
-  f_remote <<
-    "  print ''" << endl <<
-    "  sys.exit(0)" << endl <<
-    endl;
-
-  f_remote <<
-    "pp = pprint.PrettyPrinter(indent = 2)" << endl <<
-    "host = 'localhost'" << endl <<
-    "port = 9090" << endl <<
-    "uri = ''" << endl <<
-    "framed = False" << endl <<
-    "http = False" << endl <<
-    "argi = 1" << endl <<
-    endl <<
-    "if sys.argv[argi] == '-h':" << endl <<
-    "  parts = sys.argv[argi+1].split(':')" << endl <<
-    "  host = parts[0]" << endl <<
-    "  if len(parts) > 1:" << endl <<
-    "    port = int(parts[1])" << endl <<
-    "  argi += 2" << endl <<
-    endl <<
-    "if sys.argv[argi] == '-u':" << endl <<
-    "  url = urlparse(sys.argv[argi+1])" << endl <<
-    "  parts = url[1].split(':')" << endl <<
-    "  host = parts[0]" << endl <<
-    "  if len(parts) > 1:" << endl <<
-    "    port = int(parts[1])" << endl <<
-    "  else:" << endl <<
-    "    port = 80" << endl <<
-    "  uri = url[2]" << endl <<
-    "  if url[4]:" << endl <<
-    "    uri += '?%s' % url[4]" << endl <<
-    "  http = True" << endl <<
-    "  argi += 2" << endl <<
-    endl <<
-    "if sys.argv[argi] == '-f' or sys.argv[argi] == '-framed':" << endl <<
-    "  framed = True" << endl <<
-    "  argi += 1" << endl <<
-    endl <<
-    "cmd = sys.argv[argi]" << endl <<
-    "args = sys.argv[argi+1:]" << endl <<
-    endl <<
-    "if http:" << endl <<
-    "  transport = THttpClient.THttpClient(host, port, uri)" << endl <<
-    "else:" << endl <<
-    "  socket = TSocket.TSocket(host, port)" << endl <<
-    "  if framed:" << endl <<
-    "    transport = TTransport.TFramedTransport(socket)" << endl <<
-    "  else:" << endl <<
-    "    transport = TTransport.TBufferedTransport(socket)" << endl <<
-    "protocol = TBinaryProtocol.TBinaryProtocol(transport)" << endl <<
-    "client = " << service_name_ << ".Client(protocol)" << endl <<
-    "transport.open()" << endl <<
-    endl;
-
-  // Generate the dispatch methods
-  bool first = true;
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    if (first) {
-      first = false;
-    } else {
-      f_remote << "el";
-    }
-
-    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();
-
-    f_remote <<
-      "if cmd == '" << (*f_iter)->get_name() << "':" << endl <<
-      "  if len(args) != " << num_args << ":" << endl <<
-      "    print '" << (*f_iter)->get_name() << " requires " << num_args << " args'" << endl <<
-      "    sys.exit(1)" << endl <<
-      "  pp.pprint(client." << (*f_iter)->get_name() << "(";
-    for (int i = 0; i < num_args; ++i) {
-      if (args[i]->get_type()->is_string()) {
-        f_remote << "args[" << i << "],";
-      } else {
-        f_remote << "eval(args[" << i << "]),";
-      }
-    }
-    f_remote << "))" << endl;
-
-    f_remote << endl;
-  }
-
-  if (functions.size() > 0) {
-    f_remote << "else:" << endl;
-    f_remote << "  print 'Unrecognized method %s' % cmd" << endl;
-    f_remote << "  sys.exit(1)" << endl;
-    f_remote << endl;
-  }
-
-  f_remote << "transport.close()" << endl;
-
-  // Close service file
-  f_remote.close();
-
-#ifndef _MSC_VER
-
-  // 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
-  );
-
-#endif // _MSC_VER
-}
-
-/**
- * Generates a service server definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_py_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 = "";
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_processor = extends + ".Processor, ";
-  }
-
-  // Generate the header portion
-  if (gen_twisted_) {
-    f_service_ <<
-      "class Processor(" << extends_processor << "TProcessor):" << endl <<
-      "  implements(Iface)" << endl << endl;
-  } else {
-    f_service_ <<
-      "class Processor(" << extends_processor << "Iface, TProcessor):" << endl;
-  }
-
-  indent_up();
-
-  indent(f_service_) <<
-    "def __init__(self, handler):" << endl;
-  indent_up();
-  if (extends.empty()) {
-    if (gen_twisted_) {
-      f_service_ <<
-        indent() << "self._handler = Iface(handler)" << endl;
-    } else {
-      f_service_ <<
-        indent() << "self._handler = handler" << endl;
-    }
-
-    f_service_ <<
-      indent() << "self._processMap = {}" << endl;
-  } else {
-    if (gen_twisted_) {
-      f_service_ <<
-        indent() << extends << ".Processor.__init__(self, Iface(handler))" << endl;
-    } else {
-      f_service_ <<
-        indent() << extends << ".Processor.__init__(self, handler)" << endl;
-    }
-  }
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    f_service_ <<
-      indent() << "self._processMap[\"" << (*f_iter)->get_name() << "\"] = Processor.process_" << (*f_iter)->get_name() << endl;
-  }
-  indent_down();
-  f_service_ << endl;
-
-  // Generate the server implementation
-  if (gen_tornado_) {
-    f_service_ <<
-      indent() << "@gen.engine" << endl <<
-      indent() << "def process(self, transport, iprot_factory, oprot, callback):" << endl;
-    indent_up();
-    f_service_ <<
-      indent() << "# wait for a frame header" << endl <<
-      indent() << "frame = yield gen.Task(transport.readFrame)" << endl <<
-      indent() << "tr = TTransport.TMemoryBuffer(frame)" << endl <<
-      indent() << "iprot = iprot_factory.getProtocol(tr)" << endl <<
-      endl;
-  } else {
-    f_service_ <<
-      indent() << "def process(self, iprot, oprot):" << endl;
-    indent_up();
-  }
-
-  f_service_ <<
-    indent() << "(name, type, seqid) = iprot.readMessageBegin()" << endl;
-
-  // TODO(mcslee): validate message
-
-  // HOT: dictionary function lookup
-  f_service_ <<
-    indent() << "if name not in self._processMap:" << endl <<
-    indent() << "  iprot.skip(TType.STRUCT)" << endl <<
-    indent() << "  iprot.readMessageEnd()" << endl <<
-    indent() << "  x = TApplicationException(TApplicationException.UNKNOWN_METHOD, 'Unknown function %s' % (name))" << endl <<
-    indent() << "  oprot.writeMessageBegin(name, TMessageType.EXCEPTION, seqid)" << endl <<
-    indent() << "  x.write(oprot)" << endl <<
-    indent() << "  oprot.writeMessageEnd()" << endl <<
-    indent() << "  oprot.trans.flush()" << endl;
-
-  if (gen_twisted_) {
-    f_service_ <<
-      indent() << "  return defer.succeed(None)" << endl;
-  } else if (gen_tornado_) {
-    // nothing
-  } else {
-    f_service_ <<
-      indent() << "  return" << endl;
-  }
-
-  f_service_ <<
-    indent() << "else:" << endl;
-
-  if (gen_twisted_) {
-    f_service_ <<
-      indent() << "  return self._processMap[name](self, seqid, iprot, oprot)" << endl;
-  } else if (gen_tornado_) {
-    f_service_ <<
-      indent() << "  yield gen.Task(self._processMap[name], self, seqid, iprot, oprot)" << endl <<
-      indent() << "callback()" << endl;
-  } else {
-    f_service_ <<
-      indent() << "  self._processMap[name](self, seqid, iprot, oprot)" << endl;
-
-    // Read end of args field, the T_STOP, and the struct close
-    f_service_ <<
-      indent() << "return True" << endl;
-  }
-
-  indent_down();
-  f_service_ << endl;
-
-  // Generate the process subfunctions
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    generate_process_function(tservice, *f_iter);
-  }
-
-  indent_down();
-  f_service_ << endl;
-}
-
-/**
- * Generates a process function definition.
- *
- * @param tfunction The function to write a dispatcher for
- */
-void t_py_generator::generate_process_function(t_service* tservice,
-                                               t_function* tfunction) {
-  (void) tservice;
-  // Open function
-  if (gen_tornado_) {
-    f_service_ <<
-      indent() << "@gen.engine" << endl <<
-      indent() << "def process_" << tfunction->get_name() <<
-                  "(self, seqid, iprot, oprot, callback):" << endl;
-  } else {
-    f_service_ <<
-      indent() << "def process_" << tfunction->get_name() <<
-                  "(self, seqid, iprot, oprot):" << endl;
-  }
-
-  indent_up();
-
-  string argsname = tfunction->get_name() + "_args";
-  string resultname = tfunction->get_name() + "_result";
-
-  f_service_ <<
-    indent() << "args = " << argsname << "()" << endl <<
-    indent() << "args.read(iprot)" << endl <<
-    indent() << "iprot.readMessageEnd()" << endl;
-
-  t_struct* xs = tfunction->get_xceptions();
-  const std::vector<t_field*>& xceptions = xs->get_members();
-  vector<t_field*>::const_iterator x_iter;
-
-  // Declare result for non oneway function
-  if (!tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << "result = " << resultname << "()" << endl;
-  }
-
-  if (gen_twisted_) {
-    // 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_ <<
-      indent() << "d = defer.maybeDeferred(self._handler." <<
-        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." << (*f_iter)->get_name();
-    }
-    f_service_ << ")" << endl;
-
-    // Shortcut out here for oneway functions
-    if (tfunction->is_oneway()) {
-      f_service_ <<
-        indent() << "return d" << endl;
-      indent_down();
-      f_service_ << endl;
-      return;
-    }
-
-    f_service_ <<
-      indent() <<
-        "d.addCallback(self.write_results_success_" <<
-          tfunction->get_name() << ", result, seqid, oprot)" << endl;
-
-    if (xceptions.size() > 0) {
-      f_service_ <<
-        indent() <<
-          "d.addErrback(self.write_results_exception_" <<
-            tfunction->get_name() << ", result, seqid, oprot)" << endl;
-    }
-
-    f_service_ <<
-      indent() << "return d" << endl;
-
-    indent_down();
-    f_service_ << endl;
-
-    indent(f_service_) <<
-        "def write_results_success_" << tfunction->get_name() <<
-        "(self, success, result, seqid, oprot):" << endl;
-    indent_up();
-    f_service_ <<
-      indent() << "result.success = success" << endl <<
-      indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() <<
-        "\", TMessageType.REPLY, seqid)" << endl <<
-      indent() << "result.write(oprot)" << endl <<
-      indent() << "oprot.writeMessageEnd()" << endl <<
-      indent() << "oprot.trans.flush()" << endl;
-    indent_down();
-    f_service_ << endl;
-
-    // Try block for a function with exceptions
-    if (!tfunction->is_oneway() && xceptions.size() > 0) {
-      indent(f_service_) <<
-        "def write_results_exception_" << tfunction->get_name() <<
-        "(self, error, result, seqid, oprot):" << endl;
-      indent_up();
-      f_service_ <<
-        indent() << "try:" << endl;
-
-      // Kinda absurd
-      f_service_ <<
-        indent() << "  error.raiseException()" << endl;
-      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() << "oprot.writeMessageBegin(\"" << tfunction->get_name() <<
-          "\", TMessageType.REPLY, seqid)" << endl <<
-        indent() << "result.write(oprot)" << endl <<
-        indent() << "oprot.writeMessageEnd()" << endl <<
-        indent() << "oprot.trans.flush()" << endl;
-      indent_down();
-      f_service_ << endl;
-    }
-
-  } else if (gen_tornado_) {
-    if (!tfunction->is_oneway() && xceptions.size() > 0) {
-      f_service_ <<
-        endl <<
-        indent() << "def handle_exception(xtype, value, traceback):" << endl;
-
-      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-        f_service_ <<
-          indent() << "  if xtype == " << type_name((*x_iter)->get_type()) << ":" << endl;
-        if (!tfunction->is_oneway()) {
-          f_service_ <<
-            indent() << "    result." << (*x_iter)->get_name() << " = value" << endl;
-        }
-        f_service_ <<
-          indent() << "    return True" << endl;
-      }
-
-      f_service_ <<
-        endl <<
-        indent() << "with stack_context.ExceptionStackContext(handle_exception):" << endl;
-      indent_up();
-    }
-
-    // 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_ << indent();
-    if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
-      f_service_ << "result.success = ";
-    }
-    f_service_ <<
-      "yield gen.Task(self._handler." << 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." << (*f_iter)->get_name();
-    }
-    f_service_ << ")" << endl;
-
-    if (xceptions.size() > 0) {
-      f_service_ << endl;
-    }
-
-    if (!tfunction->is_oneway() && xceptions.size() > 0) {
-      indent_down();
-    }
-
-    // Shortcut out here for oneway functions
-    if (tfunction->is_oneway()) {
-      f_service_ <<
-        indent() << "callback()" << endl;
-      indent_down();
-      f_service_ << endl;
-      return;
-    }
-
-    f_service_ <<
-      indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid)" << endl <<
-      indent() << "result.write(oprot)" << endl <<
-      indent() << "oprot.writeMessageEnd()" << endl <<
-      indent() << "oprot.trans.flush()" << endl <<
-      indent() << "callback()" << endl;
-
-    // Close function
-    indent_down();
-    f_service_ << endl;
-
-  } else {  // py
-    // Try block for a function with exceptions
-    if (xceptions.size() > 0) {
-      f_service_ <<
-        indent() << "try:" << endl;
-      indent_up();
-    }
-
-    // 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_ << indent();
-    if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
-      f_service_ << "result.success = ";
-    }
-    f_service_ <<
-      "self._handler." << 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." << (*f_iter)->get_name();
-    }
-    f_service_ << ")" << endl;
-
-    if (!tfunction->is_oneway() && xceptions.size() > 0) {
-      indent_down();
-      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;
-        }
-      }
-    }
-
-    // Shortcut out here for oneway functions
-    if (tfunction->is_oneway()) {
-      f_service_ <<
-        indent() << "return" << endl;
-      indent_down();
-      f_service_ << endl;
-      return;
-    }
-
-    f_service_ <<
-      indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid)" << endl <<
-      indent() << "result.write(oprot)" << endl <<
-      indent() << "oprot.writeMessageEnd()" << endl <<
-      indent() << "oprot.trans.flush()" << endl;
-
-    // Close function
-    indent_down();
-    f_service_ << endl;
-  }
-}
-
-/**
- * Deserializes a field of any type.
- */
-void t_py_generator::generate_deserialize_field(ofstream &out,
-                                                t_field* tfield,
-                                                string prefix,
-                                                bool inclass) {
-  (void) inclass;
-  t_type* type = get_true_type(tfield->get_type());
-
-  if (type->is_void()) {
-    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  string name = prefix + tfield->get_name();
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_deserialize_struct(out,
-                                (t_struct*)type,
-                                 name);
-  } else if (type->is_container()) {
-    generate_deserialize_container(out, type, name);
-  } else if (type->is_base_type() || type->is_enum()) {
-    indent(out) <<
-      name << " = 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:
-        if (((t_base_type*)type)->is_binary() || !gen_utf8strings_) {
-          out << "readString();";
-        } else {
-          out << "readString().decode('utf-8')";
-        }
-        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 PHP name for base type " + t_base_type::t_base_name(tbase);
-      }
-    } else if (type->is_enum()) {
-      out << "readI32();";
-    }
-    out << endl;
-
-  } else {
-    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
-           tfield->get_name().c_str(), type->get_name().c_str());
-  }
-}
-
-/**
- * Generates an unserializer for a struct, calling read()
- */
-void t_py_generator::generate_deserialize_struct(ofstream &out,
-                                                  t_struct* tstruct,
-                                                  string prefix) {
-  out <<
-    indent() << prefix << " = " << type_name(tstruct) << "()" << endl <<
-    indent() << prefix << ".read(iprot)" << endl;
-}
-
-/**
- * Serialize a container by writing out the header followed by
- * data and then a footer.
- */
-void t_py_generator::generate_deserialize_container(ofstream &out,
-                                                    t_type* ttype,
-                                                    string prefix) {
-  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);
-
-  // Declare variables, read header
-  if (ttype->is_map()) {
-    out <<
-      indent() << prefix << " = {}" << endl <<
-      indent() << "(" << ktype << ", " << vtype << ", " << size << " ) = iprot.readMapBegin()" << endl;
-  } else if (ttype->is_set()) {
-    out <<
-      indent() << prefix << " = set()" << endl <<
-      indent() << "(" << etype << ", " << size << ") = iprot.readSetBegin()" << endl;
-  } else if (ttype->is_list()) {
-    out <<
-      indent() << prefix << " = []" << endl <<
-      indent() << "(" << etype << ", " << size << ") = iprot.readListBegin()" << endl;
-  }
-
-  // For loop iterates over elements
-  string i = tmp("_i");
-  indent(out) <<
-    "for " << i << " in xrange(" << size << "):" << endl;
-
-    indent_up();
-
-    if (ttype->is_map()) {
-      generate_deserialize_map_element(out, (t_map*)ttype, prefix);
-    } else if (ttype->is_set()) {
-      generate_deserialize_set_element(out, (t_set*)ttype, prefix);
-    } else if (ttype->is_list()) {
-      generate_deserialize_list_element(out, (t_list*)ttype, prefix);
-    }
-
-    indent_down();
-
-  // Read container end
-  if (ttype->is_map()) {
-    indent(out) << "iprot.readMapEnd()" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) << "iprot.readSetEnd()" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) << "iprot.readListEnd()" << endl;
-  }
-}
-
-
-/**
- * Generates code to deserialize a map
- */
-void t_py_generator::generate_deserialize_map_element(ofstream &out,
-                                                       t_map* tmap,
-                                                       string prefix) {
-  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);
-  generate_deserialize_field(out, &fval);
-
-  indent(out) <<
-    prefix << "[" << key << "] = " << val << endl;
-}
-
-/**
- * Write a set element
- */
-void t_py_generator::generate_deserialize_set_element(ofstream &out,
-                                                       t_set* tset,
-                                                       string prefix) {
-  string elem = tmp("_elem");
-  t_field felem(tset->get_elem_type(), elem);
-
-  generate_deserialize_field(out, &felem);
-
-  indent(out) <<
-    prefix << ".add(" << elem << ")" << endl;
-}
-
-/**
- * Write a list element
- */
-void t_py_generator::generate_deserialize_list_element(ofstream &out,
-                                                        t_list* tlist,
-                                                        string prefix) {
-  string elem = tmp("_elem");
-  t_field felem(tlist->get_elem_type(), elem);
-
-  generate_deserialize_field(out, &felem);
-
-  indent(out) <<
-    prefix << ".append(" << elem << ")" << endl;
-}
-
-
-/**
- * Serializes a field of any type.
- *
- * @param tfield The field to serialize
- * @param prefix Name to prepend to field name
- */
-void t_py_generator::generate_serialize_field(ofstream &out,
-                                               t_field* tfield,
-                                               string prefix) {
-  t_type* type = get_true_type(tfield->get_type());
-
-  // Do nothing for void types
-  if (type->is_void()) {
-    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
-      prefix + tfield->get_name();
-  }
-
-  if (type->is_struct() || type->is_xception()) {
-    generate_serialize_struct(out,
-                              (t_struct*)type,
-                              prefix + tfield->get_name());
-  } else if (type->is_container()) {
-    generate_serialize_container(out,
-                                 type,
-                                 prefix + tfield->get_name());
-  } else if (type->is_base_type() || type->is_enum()) {
-
-    string name = prefix + tfield->get_name();
-
-    indent(out) <<
-      "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:
-        if (((t_base_type*)type)->is_binary() || !gen_utf8strings_) {
-          out << "writeString(" << name << ")";
-        } else {
-          out << "writeString(" << name << ".encode('utf-8'))";
-        }
-        break;
-      case t_base_type::TYPE_BOOL:
-        out << "writeBool(" << name << ")";
-        break;
-      case t_base_type::TYPE_BYTE:
-        out << "writeByte(" << name << ")";
-        break;
-      case t_base_type::TYPE_I16:
-        out << "writeI16(" << name << ")";
-        break;
-      case t_base_type::TYPE_I32:
-        out << "writeI32(" << name << ")";
-        break;
-      case t_base_type::TYPE_I64:
-        out << "writeI64(" << name << ")";
-        break;
-      case t_base_type::TYPE_DOUBLE:
-        out << "writeDouble(" << 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(" << name << ")";
-    }
-    out << endl;
-  } else {
-    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
-           prefix.c_str(),
-           tfield->get_name().c_str(),
-           type->get_name().c_str());
-  }
-}
-
-/**
- * Serializes all the members of a struct.
- *
- * @param tstruct The struct to serialize
- * @param prefix  String prefix to attach to all fields
- */
-void t_py_generator::generate_serialize_struct(ofstream &out,
-                                               t_struct* tstruct,
-                                               string prefix) {
-  (void) tstruct;
-  indent(out) <<
-    prefix << ".write(oprot)" << endl;
-}
-
-void t_py_generator::generate_serialize_container(ofstream &out,
-                                                  t_type* ttype,
-                                                  string prefix) {
-  if (ttype->is_map()) {
-    indent(out) <<
-      "oprot.writeMapBegin(" <<
-      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
-      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
-      "len(" << prefix << "))" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "oprot.writeSetBegin(" <<
-      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
-      "len(" << prefix << "))" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "oprot.writeListBegin(" <<
-      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
-      "len(" << prefix << "))" << endl;
-  }
-
-  if (ttype->is_map()) {
-    string kiter = tmp("kiter");
-    string viter = tmp("viter");
-    indent(out) <<
-      "for " << kiter << "," << viter << " in " << prefix << ".items():" << endl;
-    indent_up();
-    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
-    indent_down();
-  } else if (ttype->is_set()) {
-    string iter = tmp("iter");
-    indent(out) <<
-      "for " << iter << " in " << prefix << ":" << endl;
-    indent_up();
-    generate_serialize_set_element(out, (t_set*)ttype, iter);
-    indent_down();
-  } else if (ttype->is_list()) {
-    string iter = tmp("iter");
-    indent(out) <<
-      "for " << iter << " in " << prefix << ":" << endl;
-    indent_up();
-    generate_serialize_list_element(out, (t_list*)ttype, iter);
-    indent_down();
-  }
-
-  if (ttype->is_map()) {
-    indent(out) <<
-      "oprot.writeMapEnd()" << endl;
-  } else if (ttype->is_set()) {
-    indent(out) <<
-      "oprot.writeSetEnd()" << endl;
-  } else if (ttype->is_list()) {
-    indent(out) <<
-      "oprot.writeListEnd()" << endl;
-  }
-}
-
-/**
- * Serializes the members of a map.
- *
- */
-void t_py_generator::generate_serialize_map_element(ofstream &out,
-                                                     t_map* tmap,
-                                                     string kiter,
-                                                     string viter) {
-  t_field kfield(tmap->get_key_type(), kiter);
-  generate_serialize_field(out, &kfield, "");
-
-  t_field vfield(tmap->get_val_type(), viter);
-  generate_serialize_field(out, &vfield, "");
-}
-
-/**
- * Serializes the members of a set.
- */
-void t_py_generator::generate_serialize_set_element(ofstream &out,
-                                                     t_set* tset,
-                                                     string iter) {
-  t_field efield(tset->get_elem_type(), iter);
-  generate_serialize_field(out, &efield, "");
-}
-
-/**
- * Serializes the members of a list.
- */
-void t_py_generator::generate_serialize_list_element(ofstream &out,
-                                                      t_list* tlist,
-                                                      string iter) {
-  t_field efield(tlist->get_elem_type(), iter);
-  generate_serialize_field(out, &efield, "");
-}
-
-/**
- * Generates the docstring for a given struct.
- */
-void t_py_generator::generate_python_docstring(ofstream& out,
-                                               t_struct* tstruct) {
-  generate_python_docstring(out, tstruct, tstruct, "Attributes");
-}
-
-/**
- * Generates the docstring for a given function.
- */
-void t_py_generator::generate_python_docstring(ofstream& out,
-                                               t_function* tfunction) {
-  generate_python_docstring(out, tfunction, tfunction->get_arglist(), "Parameters");
-}
-
-/**
- * Generates the docstring for a struct or function.
- */
-void t_py_generator::generate_python_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 << " - " << 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_py_generator::generate_python_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_py_generator::declare_argument(t_field* tfield) {
-  std::ostringstream result;
-  result << tfield->get_name() << "=";
-  if (tfield->get_value() != NULL) {
-    result << "thrift_spec[" <<
-      tfield->get_key() << "][4]";
-  } else {
-    result << "None";
-  }
-  return result.str();
-}
-
-/**
- * Renders a field default value, returns None otherwise.
- *
- * @param tfield The field
- */
-string t_py_generator::render_field_default_value(t_field* tfield) {
-  t_type* type = get_true_type(tfield->get_type());
-  if (tfield->get_value() != NULL) {
-    return render_const_value(type, tfield->get_value());
-  } else {
-    return "None";
-  }
-}
-
-/**
- * Renders a function signature of the form 'type name(args)'
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_py_generator::function_signature(t_function* tfunction,
-                                          bool interface,
-                                          tornado_callback_t callback) {
-  vector<string> pre;
-  vector<string> post;
-  string signature = tfunction->get_name() + "(";
-
-  if (!(gen_twisted_ && interface)) {
-    pre.push_back("self");
-  }
-
-  if (gen_tornado_) {
-    if (callback == NONE) {
-    } else if (callback == MANDATORY_FOR_ONEWAY_ELSE_NONE) {
-      if (tfunction->is_oneway()) {
-        // Tornado send_* carry the callback so you can block on the write's flush
-        // (rather than on receipt of the response)
-        post.push_back("callback");
-      }
-    } else if (callback == OPTIONAL_FOR_ONEWAY_ELSE_MANDATORY) {
-      if (tfunction->is_oneway()) {
-        post.push_back("callback=None");
-      } else {
-        post.push_back("callback");
-      }
-    }
-  }
-  signature += argument_list(tfunction->get_arglist(), &pre, &post) + ")";
-  return signature;
-}
-
-/**
- * Renders a field list
- */
-string t_py_generator::argument_list(t_struct* tstruct, vector<string> *pre, vector<string> *post) {
-  string result = "";
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-  vector<string>::const_iterator s_iter;
-  bool first = true;
-  if (pre) {
-    for (s_iter = pre->begin(); s_iter != pre->end(); ++s_iter) {
-      if (first) {
-        first = false;
-      } else {
-        result += ", ";
-      }
-      result += *s_iter;
-    }
-  }
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (first) {
-      first = false;
-    } else {
-      result += ", ";
-    }
-    result += (*f_iter)->get_name();
-  }
-  if (post) {
-    for (s_iter = post->begin(); s_iter != post->end(); ++s_iter) {
-      if (first) {
-        first = false;
-      } else {
-        result += ", ";
-      }
-      result += *s_iter;
-    }
-  }
-  return result;
-}
-
-string t_py_generator::type_name(t_type* ttype) {
-  t_program* program = ttype->get_program();
-  if (ttype->is_service()) {
-    return get_real_py_module(program, gen_twisted_) + "." + ttype->get_name();
-  }
-  if (program != NULL && program != program_) {
-    return get_real_py_module(program, gen_twisted_) + ".ttypes." + ttype->get_name();
-  }
-  return ttype->get_name();
-}
-
-/**
- * Converts the parse type to a Python tyoe
- */
-string t_py_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 "TType.STRING";
-    case t_base_type::TYPE_BOOL:
-      return "TType.BOOL";
-    case t_base_type::TYPE_BYTE:
-      return "TType.BYTE";
-    case t_base_type::TYPE_I16:
-      return "TType.I16";
-    case t_base_type::TYPE_I32:
-      return "TType.I32";
-    case t_base_type::TYPE_I64:
-      return "TType.I64";
-    case t_base_type::TYPE_DOUBLE:
-      return "TType.DOUBLE";
-    }
-  } else if (type->is_enum()) {
-    return "TType.I32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "TType.STRUCT";
-  } else if (type->is_map()) {
-    return "TType.MAP";
-  } else if (type->is_set()) {
-    return "TType.SET";
-  } else if (type->is_list()) {
-    return "TType.LIST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-/** See the comment inside generate_py_struct_definition for what this is. */
-string t_py_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 "None";
-  } 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(py, "Python",
-"    new_style:       Generate new-style classes.\n" \
-"    twisted:         Generate Twisted-friendly RPC services.\n" \
-"    tornado:         Generate code for use with Tornado.\n" \
-"    utf8strings:     Encode/decode strings using utf8 in the generated code.\n" \
-"    slots:           Generate code using slots for instance members.\n" \
-"    dynamic:         Generate dynamic code, less code generated but slower.\n" \
-"    dynbase=CLS      Derive generated classes from class CLS instead of TBase.\n" \
-"    dynexc=CLS       Derive generated exceptions from CLS instead of TExceptionBase.\n" \
-"    dynimport='from foo.bar import CLS'\n" \
-"                     Add an import line to generated code to find the dynbase class.\n")
diff --git a/compiler/cpp/src/generate/t_rb_generator.cc b/compiler/cpp/src/generate/t_rb_generator.cc
deleted file mode 100644
index 082f316..0000000
--- a/compiler/cpp/src/generate/t_rb_generator.cc
+++ /dev/null
@@ -1,1226 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- * Contains some contributions under the Thrift Software License.
- * Please see doc/old-thrift-license.txt in the Thrift distribution for
- * details.
- */
-
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-#include <algorithm>
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sstream>
-
-#include "t_oop_generator.h"
-#include "platform.h"
-#include "version.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * A subclass of std::ofstream that includes indenting functionality.
- */
-class t_rb_ofstream : public std::ofstream {
-  private:
-    int indent_;
-
-  public:
-    t_rb_ofstream() : std::ofstream(), indent_(0) { }
-    explicit t_rb_ofstream(const char* filename, ios_base::openmode mode = ios_base::out, int indent = 0) :
-      std::ofstream(filename, mode), indent_(indent) { }
-
-  t_rb_ofstream& indent() {
-    for (int i = 0; i < indent_; ++i) { *this << "  "; }
-    return *this;
-  }
-
-  void indent_up() { indent_++; }
-  void indent_down() { indent_--; }
-};
-
-/**
- * Ruby code generator.
- *
- */
-class t_rb_generator : public t_oop_generator {
- public:
-  t_rb_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_oop_generator(program)
-  {
-    (void) option_string;
-    out_dir_base_ = "gen-rb";
-
-    require_rubygems_ = (parsed_options.find("rubygems") != parsed_options.end());
-  }
-
-  /**
-   * 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_union        (t_struct*   tunion);
-  void generate_xception    (t_struct*   txception);
-  void generate_service     (t_service*  tservice);
-
-  t_rb_ofstream& render_const_value(t_rb_ofstream& out, t_type* type, t_const_value* value);
-
-  /**
-   * Struct generation code
-   */
-
-  void generate_rb_struct(t_rb_ofstream& out, t_struct* tstruct, bool is_exception);
-  void generate_rb_struct_required_validator(t_rb_ofstream& out, t_struct* tstruct);
-  void generate_rb_union(t_rb_ofstream& out, t_struct* tstruct, bool is_exception);
-  void generate_rb_union_validator(t_rb_ofstream& out, t_struct* tstruct);
-  void generate_rb_function_helpers(t_function* tfunction);
-  void generate_rb_simple_constructor(t_rb_ofstream& out, t_struct* tstruct);
-  void generate_rb_simple_exception_constructor(t_rb_ofstream& out, t_struct* tstruct);
-  void generate_field_constants (t_rb_ofstream& out, t_struct* tstruct);
-  void generate_field_constructors (t_rb_ofstream& out, t_struct* tstruct);
-  void generate_field_defns (t_rb_ofstream& out, t_struct* tstruct);
-  void generate_field_data  (t_rb_ofstream& out, t_type* field_type, const std::string& field_name, t_const_value* field_value, bool optional);
-
-  /**
-   * 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_server    (t_service* tservice);
-  void generate_process_function  (t_service* tservice, t_function* tfunction);
-
-  /**
-   * Serialization constructs
-   */
-
-  void generate_deserialize_field        (t_rb_ofstream &out,
-                                          t_field*    tfield,
-                                          std::string prefix="",
-                                          bool inclass=false);
-
-  void generate_deserialize_struct       (t_rb_ofstream &out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_deserialize_container    (t_rb_ofstream &out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_deserialize_set_element  (t_rb_ofstream &out,
-                                          t_set*      tset,
-                                          std::string prefix="");
-
-  void generate_deserialize_map_element  (t_rb_ofstream &out,
-                                          t_map*      tmap,
-                                          std::string prefix="");
-
-  void generate_deserialize_list_element (t_rb_ofstream &out,
-                                          t_list*     tlist,
-                                          std::string prefix="");
-
-  void generate_serialize_field          (t_rb_ofstream &out,
-                                          t_field*    tfield,
-                                          std::string prefix="");
-
-  void generate_serialize_struct         (t_rb_ofstream &out,
-                                          t_struct*   tstruct,
-                                          std::string prefix="");
-
-  void generate_serialize_container      (t_rb_ofstream &out,
-                                          t_type*     ttype,
-                                          std::string prefix="");
-
-  void generate_serialize_map_element    (t_rb_ofstream &out,
-                                          t_map*      tmap,
-                                          std::string kiter,
-                                          std::string viter);
-
-  void generate_serialize_set_element    (t_rb_ofstream &out,
-                                          t_set*      tmap,
-                                          std::string iter);
-
-  void generate_serialize_list_element   (t_rb_ofstream &out,
-                                          t_list*     tlist,
-                                          std::string iter);
-
-  void generate_rdoc                     (t_rb_ofstream& out, 
-                                          t_doc* tdoc);
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string rb_autogen_comment();
-  std::string render_require_thrift();
-  std::string render_includes();
-  std::string declare_field(t_field* tfield);
-  std::string type_name(t_type* ttype);
-  std::string full_type_name(t_type* ttype);
-  std::string function_signature(t_function* tfunction, std::string prefix="");
-  std::string argument_list(t_struct* tstruct);
-  std::string type_to_enum(t_type* ttype);
-
-
-
-  std::vector<std::string> ruby_modules(t_program* p) {
-    std::string ns = p->get_namespace("rb");
-    std::vector<std::string> modules;
-    if (ns.empty()) {
-      return modules;
-    }
-
-    std::string::iterator pos = ns.begin();
-    while (true) {
-      std::string::iterator delim = std::find(pos, ns.end(), '.');
-      modules.push_back(capitalize(std::string(pos, delim)));
-      pos = delim;
-      if (pos == ns.end()) {
-        break;
-      }
-      ++pos;
-    }
-
-    return modules;
-  }
-
-  void begin_namespace(t_rb_ofstream&, std::vector<std::string>);
-  void end_namespace(t_rb_ofstream&, std::vector<std::string>);
-
- private:
-
-  /**
-   * File streams
-   */
-
-  t_rb_ofstream f_types_;
-  t_rb_ofstream f_consts_;
-  t_rb_ofstream f_service_;
-
-  /** If true, add a "require 'rubygems'" line to the top of each gen-rb file. */
-  bool require_rubygems_;
-};
-
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * streams.
- *
- * @param tprogram The program to generate
- */
-void t_rb_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-
-  // Make output file
-  string f_types_name = get_out_dir()+underscore(program_name_)+"_types.rb";
-  f_types_.open(f_types_name.c_str());
-
-  string f_consts_name = get_out_dir()+underscore(program_name_)+"_constants.rb";
-  f_consts_.open(f_consts_name.c_str());
-
-  // Print header
-  f_types_ <<
-    rb_autogen_comment() << endl << render_require_thrift() <<
-    render_includes() << endl;
-    begin_namespace(f_types_, ruby_modules(program_));
-
-  f_consts_ <<
-    rb_autogen_comment() << endl << render_require_thrift() <<
-    "require '" << underscore(program_name_) << "_types'" << endl <<
-    endl;
-    begin_namespace(f_consts_, ruby_modules(program_));
-
-}
-
-/**
- * Renders the require of thrift itself, and possibly of the rubygems dependency.
- */
-string t_rb_generator::render_require_thrift() {
-  if (require_rubygems_) {
-    return "require 'rubygems'\nrequire 'thrift'\n";
-  } else {
-    return "require 'thrift'\n";
-  }
-}
-
-/**
- * Renders all the imports necessary for including another Thrift program
- */
-string t_rb_generator::render_includes() {
-  const vector<t_program*>& includes = program_->get_includes();
-  string result = "";
-  for (size_t i = 0; i < includes.size(); ++i) {
-    result += "require '" + underscore(includes[i]->get_name()) + "_types'\n";
-  }
-  if (includes.size() > 0) {
-    result += "\n";
-  }
-  return result;
-}
-
-/**
- * Autogen'd comment
- */
-string t_rb_generator::rb_autogen_comment() {
-  return
-    std::string("#\n") +
-    "# Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" +
-    "#\n" +
-    "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
-    "#\n";
-}
-
-/**
- * Closes the type files
- */
-void t_rb_generator::close_generator() {
-  // Close types file
-  end_namespace(f_types_, ruby_modules(program_));
-  end_namespace(f_consts_, ruby_modules(program_));
-  f_types_.close();
-  f_consts_.close();
-}
-
-/**
- * Generates a typedef. This is not done in Ruby, types are all implicit.
- *
- * @param ttypedef The type definition
- */
-void t_rb_generator::generate_typedef(t_typedef* ttypedef) {
-  (void) ttypedef;
-}
-
-/**
- * Generates code for an enumerated type. Done using a class to scope
- * the values.
- *
- * @param tenum The enumeration
- */
-void t_rb_generator::generate_enum(t_enum* tenum) {
-  f_types_.indent() <<
-    "module " << capitalize(tenum->get_name()) << endl;
-  f_types_.indent_up();
-
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-
-    // Ruby class constants have to be capitalized... omg i am so on the fence
-    // about languages strictly enforcing capitalization why can't we just all
-    // agree and play nice.
-    string name = capitalize((*c_iter)->get_name());
-
-    generate_rdoc(f_types_, *c_iter);
-    f_types_.indent() << name << " = " << value << endl;
-  }
-  
-  // Create a hash mapping values back to their names (as strings) since ruby has no native enum type
-  f_types_.indent() << "VALUE_MAP = {";
-  bool first = true;
-  for(c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    // Populate the hash
-    int value = (*c_iter)->get_value();
-    first ? first = false : f_types_ << ", ";
-    f_types_ << value << " => \"" << capitalize((*c_iter)->get_name()) << "\"";
-  }
-  f_types_ << "}" << endl;
-  
-  // Create a set with valid values for this enum
-  f_types_.indent() << "VALID_VALUES = Set.new([";
-  first = true;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    // Populate the set
-    first ? first = false : f_types_ << ", ";
-    f_types_ << capitalize((*c_iter)->get_name());
-  }
-  f_types_ << "]).freeze" << endl;
-
-  f_types_.indent_down();
-  f_types_.indent() <<
-    "end" << endl << endl;
-}
-
-/**
- * Generate a constant value
- */
-void t_rb_generator::generate_const(t_const* tconst) {
-  t_type* type = tconst->get_type();
-  string name = tconst->get_name();
-  t_const_value* value = tconst->get_value();
-
-  name[0] = toupper(name[0]);
-
-  f_consts_.indent() << name << " = ";
-  render_const_value(f_consts_, type, value) << endl << 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
- */
-t_rb_ofstream& t_rb_generator::render_const_value(t_rb_ofstream& out, t_type* type, t_const_value* value) {
-  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_STRING:
-      out << "%q\"" << 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()) {
-    out.indent() << value->get_integer();
-  } else if (type->is_struct() || type->is_xception()) {
-    out << full_type_name(type) << ".new({" << endl;
-    out.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();
-      }
-      out.indent();
-      render_const_value(out, g_type_string, v_iter->first) << " => ";
-      render_const_value(out, field_type, v_iter->second) << "," << endl;
-    }
-    out.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();
-    out << "{" << endl;
-    out.indent_up();
-    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) {
-      out.indent();
-      render_const_value(out, ktype, v_iter->first) << " => ";
-      render_const_value(out, vtype, v_iter->second) << "," << endl;
-    }
-    out.indent_down();
-    out.indent() << "}";
-  } else if (type->is_list() || type->is_set()) {
-    t_type* etype;
-    if (type->is_list()) {
-      etype = ((t_list*)type)->get_elem_type();
-    } else {
-      etype = ((t_set*)type)->get_elem_type();
-    }
-    if (type->is_set()) {
-      out << "Set.new([" << endl;
-    } else {
-      out << "[" << endl;
-    }
-    out.indent_up();
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      out.indent();
-      render_const_value(out, etype, *v_iter) << "," << endl;
-    }
-    out.indent_down();
-    if (type->is_set()) {
-      out.indent() << "])";
-    } else {
-      out.indent() << "]";
-    }
-  } else {
-    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
-  }
-  return out;
-}
-
-/**
- * Generates a ruby struct
- */
-void t_rb_generator::generate_struct(t_struct* tstruct) {
-  if (tstruct->is_union()) {
-    generate_rb_union(f_types_, tstruct, false);
-  } else {
-    generate_rb_struct(f_types_, 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_rb_generator::generate_xception(t_struct* txception) {
-  generate_rb_struct(f_types_, txception, true);
-}
-
-/**
- * Generates a ruby struct
- */
-void t_rb_generator::generate_rb_struct(t_rb_ofstream& out, t_struct* tstruct, bool is_exception = false) {
-  generate_rdoc(out, tstruct);
-  out.indent() << "class " << type_name(tstruct);
-  if (is_exception) {
-    out << " < ::Thrift::Exception";
-  }
-  out << endl;
-
-  out.indent_up();
-  out.indent() << "include ::Thrift::Struct, ::Thrift::Struct_Union" << endl;
-
-  if (is_exception) {
-    generate_rb_simple_exception_constructor(out, tstruct);
-  }
-
-  generate_field_constants(out, tstruct);
-  generate_field_defns(out, tstruct);
-  generate_rb_struct_required_validator(out, tstruct);
-
-  out.indent() << "::Thrift::Struct.generate_accessors self" << endl;
-
-  out.indent_down();
-  out.indent() << "end" << endl << endl;
-}
-
-
-/**
- * Generates a ruby union
- */
-void t_rb_generator::generate_rb_union(t_rb_ofstream& out, t_struct* tstruct, bool is_exception = false) {
-  (void) is_exception;
-  generate_rdoc(out, tstruct);
-  out.indent() << "class " << type_name(tstruct) << " < ::Thrift::Union" << endl;
-
-  out.indent_up();
-  out.indent() << "include ::Thrift::Struct_Union" << endl;
-
-  generate_field_constructors(out, tstruct);
-
-  generate_field_constants(out, tstruct);
-  generate_field_defns(out, tstruct);
-  generate_rb_union_validator(out, tstruct);
-
-  out.indent() << "::Thrift::Union.generate_accessors self" << endl;
-
-  out.indent_down();
-  out.indent() << "end" << endl << endl;
-}
-
-void t_rb_generator::generate_field_constructors(t_rb_ofstream& out, t_struct* tstruct) {
-
-  out.indent() << "class << self" << endl;
-  out.indent_up();
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (f_iter != fields.begin()) {
-      out << endl;
-    }
-    std::string field_name = (*f_iter)->get_name();
-
-    out.indent() << "def " << field_name << "(val)" << endl;
-    out.indent() << "  " << tstruct->get_name() << ".new(:" << field_name << ", val)" << endl;
-    out.indent() << "end" << endl;
-  }
-  
-  out.indent_down();
-  out.indent() << "end" << endl;
-
-  out << endl;
-}
-
-void t_rb_generator::generate_rb_simple_exception_constructor(t_rb_ofstream& out, t_struct* tstruct) {
-  const vector<t_field*>& members = tstruct->get_members();
-
-  if (members.size() == 1) {
-    vector<t_field*>::const_iterator m_iter = members.begin();
-
-    if ((*m_iter)->get_type()->is_string()) {
-      string name = (*m_iter)->get_name();
-
-      out.indent() << "def initialize(message=nil)" << endl;
-      out.indent_up();
-      out.indent() << "super()" << endl;
-      out.indent() << "self." << name << " = message" << endl;
-      out.indent_down();
-      out.indent() << "end" << endl << endl;
-
-      if (name != "message") {
-        out.indent() << "def message; " << name << " end" << endl << endl;
-      }
-    }
-  }
-}
-
-void t_rb_generator::generate_field_constants(t_rb_ofstream& out, t_struct* tstruct) {
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    std::string field_name = (*f_iter)->get_name();
-    std::string cap_field_name = upcase_string(field_name);
-    
-    out.indent() << cap_field_name << " = " << (*f_iter)->get_key() << endl;
-  }
-  out << endl;
-}
-
-void t_rb_generator::generate_field_defns(t_rb_ofstream& out, t_struct* tstruct) {
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  out.indent() << "FIELDS = {" << endl;
-  out.indent_up();
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    if (f_iter != fields.begin()) {
-      out << "," << endl;
-    }
-
-    // generate the field docstrings within the FIELDS constant. no real better place...
-    generate_rdoc(out, *f_iter);
-
-    out.indent() << upcase_string((*f_iter)->get_name()) << " => ";
-
-    generate_field_data(out, (*f_iter)->get_type(), (*f_iter)->get_name(), (*f_iter)->get_value(), 
-      (*f_iter)->get_req() == t_field::T_OPTIONAL);
-  }
-  out.indent_down();
-  out << endl;
-  out.indent() << "}" << endl << endl;
-  
-  out.indent() << "def struct_fields; FIELDS; end" << endl << endl;
-  
-}
-
-void t_rb_generator::generate_field_data(t_rb_ofstream& out, t_type* field_type,
-    const std::string& field_name = "", t_const_value* field_value = NULL, bool optional = false) {
-  field_type = get_true_type(field_type);
-
-  // Begin this field's defn
-  out << "{:type => " << type_to_enum(field_type);
-
-  if (!field_name.empty()) {
-    out << ", :name => '" << field_name << "'";
-  }
-
-  if (field_value != NULL) {
-    out << ", :default => ";
-    render_const_value(out, field_type, field_value);
-  }
-
-  if (!field_type->is_base_type()) {
-    if (field_type->is_struct() || field_type->is_xception()) {
-      out << ", :class => " << full_type_name((t_struct*)field_type);
-    } else if (field_type->is_list()) {
-      out << ", :element => ";
-      generate_field_data(out, ((t_list*)field_type)->get_elem_type());
-    } else if (field_type->is_map()) {
-      out << ", :key => ";
-      generate_field_data(out, ((t_map*)field_type)->get_key_type());
-      out << ", :value => ";
-      generate_field_data(out, ((t_map*)field_type)->get_val_type());
-    } else if (field_type->is_set()) {
-      out << ", :element => ";
-      generate_field_data(out, ((t_set*)field_type)->get_elem_type());
-    }
-  } else {
-    if (((t_base_type*)field_type)->is_binary()) {
-      out << ", :binary => true";
-    }
-  }
-  
-  if(optional) {
-    out << ", :optional => true";
-  }
-
-  if (field_type->is_enum()) {
-    out << ", :enum_class => " << full_type_name(field_type);
-  }
-
-  // End of this field's defn
-  out << "}";
-}
-
-void t_rb_generator::begin_namespace(t_rb_ofstream& out, vector<std::string> modules) {
-  for (vector<std::string>::iterator m_iter = modules.begin(); m_iter != modules.end(); ++m_iter) {
-    out.indent() << "module " << *m_iter << endl;
-    out.indent_up();
-  }
-}
-
-void t_rb_generator::end_namespace(t_rb_ofstream& out, vector<std::string> modules) {
-  for (vector<std::string>::reverse_iterator m_iter = modules.rbegin(); m_iter != modules.rend(); ++m_iter) {
-    out.indent_down();
-    out.indent() << "end" << endl;
-  }
-}
-
-
-/**
- * Generates a thrift service.
- *
- * @param tservice The service definition
- */
-void t_rb_generator::generate_service(t_service* tservice) {
-  string f_service_name = get_out_dir()+underscore(service_name_)+".rb";
-  f_service_.open(f_service_name.c_str());
-
-  f_service_ <<
-    rb_autogen_comment() << endl << render_require_thrift();
-
-  if (tservice->get_extends() != NULL) {
-    f_service_ <<
-      "require '" << underscore(tservice->get_extends()->get_name()) << "'" << endl;
-  }
-
-  f_service_ <<
-    "require '" << underscore(program_name_) << "_types'" << endl <<
-    endl;
-
-  begin_namespace(f_service_, ruby_modules(tservice->get_program()));
-
-  f_service_.indent() << "module " << capitalize(tservice->get_name()) << endl;
-  f_service_.indent_up();
-
-  // Generate the three main parts of the service (well, two for now in PHP)
-  generate_service_client(tservice);
-  generate_service_server(tservice);
-  generate_service_helpers(tservice);
-
-  f_service_.indent_down();
-  f_service_.indent() << "end" << endl << endl;
-
-  end_namespace(f_service_, ruby_modules(tservice->get_program()));
-
-  // Close service file
-  f_service_.close();
-}
-
-/**
- * Generates helper functions for a service.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_rb_generator::generate_service_helpers(t_service* tservice) {
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  f_service_.indent() << "# 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_rb_struct(f_service_, ts);
-    generate_rb_function_helpers(*f_iter);
-  }
-}
-
-/**
- * Generates a struct and helpers for a function.
- *
- * @param tfunction The function
- */
-void t_rb_generator::generate_rb_function_helpers(t_function* tfunction) {
-  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_rb_struct(f_service_, &result);
-}
-
-/**
- * Generates a service client definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_rb_generator::generate_service_client(t_service* tservice) {
-  string extends = "";
-  string extends_client = "";
-  if (tservice->get_extends() != NULL) {
-    extends = full_type_name(tservice->get_extends());
-    extends_client = " < " + extends + "::Client ";
-  }
-
-  f_service_.indent() << "class Client" << extends_client << endl;
-  f_service_.indent_up();
-
-  f_service_.indent() << "include ::Thrift::Client" << 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 = (*f_iter)->get_name();
-
-    // Open function
-    f_service_.indent() << "def " << function_signature(*f_iter) << endl;
-    f_service_.indent_up();
-      f_service_.indent() <<
-        "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;
-
-      if (!(*f_iter)->is_oneway()) {
-        f_service_.indent();
-        if (!(*f_iter)->get_returntype()->is_void()) {
-          f_service_ << "return ";
-        }
-        f_service_ <<
-          "recv_" << funname << "()" << endl;
-      }
-    f_service_.indent_down();
-    f_service_.indent() << "end" << endl;
-    f_service_ << endl;
-
-    f_service_.indent() <<
-      "def send_" << function_signature(*f_iter) << endl;
-    f_service_.indent_up();
-
-      std::string argsname = capitalize((*f_iter)->get_name() + "_args");
-
-      f_service_.indent() << "send_message('" << funname << "', " << argsname;
-
-      for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-        f_service_ << ", :" << (*fld_iter)->get_name() << " => " << (*fld_iter)->get_name();
-      }
-
-      f_service_ << ")" << endl;
-
-    f_service_.indent_down();
-    f_service_.indent() << "end" << endl;
-
-    if (!(*f_iter)->is_oneway()) {
-      std::string resultname = capitalize((*f_iter)->get_name() + "_result");
-      t_struct noargs(program_);
-
-      t_function recv_function((*f_iter)->get_returntype(),
-                               string("recv_") + (*f_iter)->get_name(),
-                               &noargs);
-      // Open function
-      f_service_ << endl;
-      f_service_.indent() << "def " << function_signature(&recv_function) << endl;
-      f_service_.indent_up();
-
-      // TODO(mcslee): Validate message reply here, seq ids etc.
-
-      f_service_.indent() << "result = receive_message(" << resultname << ")" << endl;
-
-      // Careful, only return _result if not a void function
-      if (!(*f_iter)->get_returntype()->is_void()) {
-        f_service_.indent() << "return result.success unless result.success.nil?" << 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() <<
-          "raise result." << (*x_iter)->get_name() <<
-            " unless result." << (*x_iter)->get_name() << ".nil?" << endl;
-      }
-
-      // Careful, only return _result if not a void function
-      if ((*f_iter)->get_returntype()->is_void()) {
-        f_service_.indent() <<
-          "return" << endl;
-      } else {
-        f_service_.indent() <<
-          "raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, '" <<
-          (*f_iter)->get_name() << " failed: unknown result')" << endl;
-      }
-
-      // Close function
-      f_service_.indent_down();
-      f_service_.indent() << "end" << endl << endl;
-    }
-  }
-
-  f_service_.indent_down();
-  f_service_.indent() << "end" << endl << endl;
-}
-
-/**
- * Generates a service server definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_rb_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 = "";
-  if (tservice->get_extends() != NULL) {
-    extends = full_type_name(tservice->get_extends());
-    extends_processor = " < " + extends + "::Processor ";
-  }
-
-  // Generate the header portion
-  f_service_.indent() <<
-    "class Processor" << extends_processor << endl;
-  f_service_.indent_up();
-
-  f_service_.indent() << "include ::Thrift::Processor" << 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_.indent_down();
-  f_service_.indent() << "end" << endl << endl;
-}
-
-/**
- * Generates a process function definition.
- *
- * @param tfunction The function to write a dispatcher for
- */
-void t_rb_generator::generate_process_function(t_service* tservice,
-                                               t_function* tfunction) {
-  (void) tservice;
-  // Open function
-  f_service_.indent() <<
-    "def process_" << tfunction->get_name() <<
-    "(seqid, iprot, oprot)" << endl;
-  f_service_.indent_up();
-
-  string argsname = capitalize(tfunction->get_name()) + "_args";
-  string resultname = capitalize(tfunction->get_name()) + "_result";
-
-  f_service_.indent() << "args = read_args(iprot, " << argsname << ")" << endl;
-
-  t_struct* xs = tfunction->get_xceptions();
-  const std::vector<t_field*>& xceptions = xs->get_members();
-  vector<t_field*>::const_iterator x_iter;
-
-  // Declare result for non oneway function
-  if (!tfunction->is_oneway()) {
-    f_service_.indent() << "result = " << resultname << ".new()" << endl;
-  }
-
-  // Try block for a function with exceptions
-  if (xceptions.size() > 0) {
-    f_service_.indent() << "begin" << endl;
-    f_service_.indent_up();
-  }
-
-  // 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_.indent();
-  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
-    f_service_ << "result.success = ";
-  }
-  f_service_ <<
-    "@handler." << 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." << (*f_iter)->get_name();
-  }
-  f_service_ << ")" << endl;
-
-  if (!tfunction->is_oneway() && xceptions.size() > 0) {
-    f_service_.indent_down();
-    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      f_service_.indent() << "rescue " << full_type_name((*x_iter)->get_type()) << " => " <<
-        (*x_iter)->get_name() << endl;
-      if (!tfunction->is_oneway()) {
-        f_service_.indent_up();
-        f_service_.indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << endl;
-        f_service_.indent_down();
-      }
-    }
-    f_service_.indent() << "end" << endl;
-  }
-
-  // Shortcut out here for oneway functions
-  if (tfunction->is_oneway()) {
-    f_service_.indent() << "return" << endl;
-    f_service_.indent_down();
-    f_service_.indent() << "end" << endl << endl;
-    return;
-  }
-
-  f_service_.indent() << "write_result(result, oprot, '" << tfunction->get_name() << "', seqid)" << endl;
-
-  // Close function
-  f_service_.indent_down();
-  f_service_.indent() << "end" << endl << endl;
-}
-
-/**
- * Renders a function signature of the form 'type name(args)'
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_rb_generator::function_signature(t_function* tfunction,
-                                           string prefix) {
-  // TODO(mcslee): Nitpicky, no ',' if argument_list is empty
-  return
-    prefix + tfunction->get_name() +
-    "(" +  argument_list(tfunction->get_arglist()) + ")";
-}
-
-/**
- * Renders a field list
- */
-string t_rb_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();
-  }
-  return result;
-}
-
-string t_rb_generator::type_name(t_type* ttype) {
-  string prefix = "";
-
-  string name = ttype->get_name();
-  if (ttype->is_struct() || ttype->is_xception() || ttype->is_enum()) {
-    name = capitalize(ttype->get_name());
-  }
-
-  return prefix + name;
-}
-
-string t_rb_generator::full_type_name(t_type* ttype) {
-  string prefix = "::";
-  vector<std::string> modules = ruby_modules(ttype->get_program());
-  for (vector<std::string>::iterator m_iter = modules.begin();
-       m_iter != modules.end(); ++m_iter) {
-    prefix += *m_iter + "::";
-  }
-  return prefix + type_name(ttype);
-}
-
-/**
- * Converts the parse type to a Ruby tyoe
- */
-string t_rb_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::Types::STRING";
-    case t_base_type::TYPE_BOOL:
-      return "::Thrift::Types::BOOL";
-    case t_base_type::TYPE_BYTE:
-      return "::Thrift::Types::BYTE";
-    case t_base_type::TYPE_I16:
-      return "::Thrift::Types::I16";
-    case t_base_type::TYPE_I32:
-      return "::Thrift::Types::I32";
-    case t_base_type::TYPE_I64:
-      return "::Thrift::Types::I64";
-    case t_base_type::TYPE_DOUBLE:
-      return "::Thrift::Types::DOUBLE";
-    }
-  } else if (type->is_enum()) {
-    return "::Thrift::Types::I32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "::Thrift::Types::STRUCT";
-  } else if (type->is_map()) {
-    return "::Thrift::Types::MAP";
-  } else if (type->is_set()) {
-    return "::Thrift::Types::SET";
-  } else if (type->is_list()) {
-    return "::Thrift::Types::LIST";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-
-void t_rb_generator::generate_rdoc(t_rb_ofstream& out, t_doc* tdoc) {
-  if (tdoc->has_doc()) {
-    out.indent();
-    generate_docstring_comment(out,
-      "", "# ", tdoc->get_doc(), "");
-  }
-}
-
-void t_rb_generator::generate_rb_struct_required_validator(t_rb_ofstream& out, 
-                                                           t_struct* tstruct) {
-  out.indent() << "def validate" << endl;
-  out.indent_up();
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = (*f_iter);
-    if (field->get_req() == t_field::T_REQUIRED) {
-      out.indent() <<
-        "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field " <<
-        field->get_name() << " is unset!')";
-      if (field->get_type()->is_bool()) {
-        out << " if @" << field->get_name() << ".nil?";
-      } else {
-        out << " unless @" << field->get_name();
-      }
-      out << endl;
-    }
-  }
-
-  // if field is an enum, check that its value is valid
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    t_field* field = (*f_iter);
-
-    if (field->get_type()->is_enum()){      
-      out.indent() << "unless @" << field->get_name() << ".nil? || " <<
-        full_type_name(field->get_type()) << "::VALID_VALUES.include?(@" <<
-        field->get_name() << ")" << endl;
-      out.indent_up();
-      out.indent() <<
-        "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field " <<
-        field->get_name() << "!')" << endl;  
-      out.indent_down();
-      out.indent() << "end" << endl;
-    }
-  }
-
-  out.indent_down();
-  out.indent() << "end" << endl << endl;
-}
-
-void t_rb_generator::generate_rb_union_validator(t_rb_ofstream& out, 
-                                                 t_struct* tstruct) {
-  out.indent() << "def validate" << endl;
-  out.indent_up();
-
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  out.indent() <<
-    "raise(StandardError, 'Union fields are not set.') if get_set_field.nil? || get_value.nil?" << endl;
-
-  // if field is an enum, check that its value is valid
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    const t_field* field = (*f_iter);
-
-    if (field->get_type()->is_enum()){      
-      out.indent() << "if get_set_field == :" << field->get_name() << endl;
-      out.indent() <<
-        "  raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field " <<
-        field->get_name() << "!') unless " << full_type_name(field->get_type()) <<
-        "::VALID_VALUES.include?(get_value)" << endl;  
-      out.indent() << "end" << endl;
-    }
-  }
-
-  out.indent_down();
-  out.indent() << "end" << endl << endl;
-}
-
-THRIFT_REGISTER_GENERATOR(rb, "Ruby",
-"    rubygems:        Add a \"require 'rubygems'\" line to the top of each generated file.\n")
diff --git a/compiler/cpp/src/generate/t_st_generator.cc b/compiler/cpp/src/generate/t_st_generator.cc
deleted file mode 100644
index 32ffd88..0000000
--- a/compiler/cpp/src/generate/t_st_generator.cc
+++ /dev/null
@@ -1,1067 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- * Contains some contributions under the Thrift Software License.
- * Please see doc/old-thrift-license.txt in the Thrift distribution for
- * details.
- */
-
-#include <string>
-#include <fstream>
-#include <iostream>
-#include <vector>
-
-#include <stdlib.h>
-#include <time.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sstream>
-
-#include "platform.h"
-#include "t_oop_generator.h"
-#include "version.h"
-
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * Smalltalk code generator.
- *
- */
-class t_st_generator : public t_oop_generator {
- public:
-  t_st_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_oop_generator(program)
-  {
-    (void) parsed_options;
-    (void) option_string;
-    out_dir_base_ = "gen-st";
-  }
-
-  /**
-   * 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);
-  void generate_class_side_definition ();
-  void generate_force_consts ();
-
-
-  std::string render_const_value(t_type* type, t_const_value* value);
-
-  /**
-   * Struct generation code
-   */
-
-  void generate_st_struct (std::ofstream& out, t_struct* tstruct, bool is_exception);
-  void generate_accessors   (std::ofstream& out, t_struct* tstruct);
-
-  /**
-   * Service-level generation functions
-   */
-
-  void generate_service_client    (t_service* tservice);
-
-  void generate_send_method (t_function* tfunction);
-  void generate_recv_method (t_function* tfunction);
-
-  std::string map_reader (t_map *tmap);
-  std::string list_reader (t_list *tlist);
-  std::string set_reader (t_set *tset);
-  std::string struct_reader (t_struct *tstruct, std::string clsName);
-
-  std::string map_writer (t_map *tmap, std::string name);
-  std::string list_writer (t_list *tlist, std::string name);
-  std::string set_writer (t_set *tset, std::string name);
-  std::string struct_writer (t_struct *tstruct, std::string fname);
-
-  std::string write_val (t_type *t, std::string fname);
-  std::string read_val (t_type *t);
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string st_autogen_comment();
-
-  void st_class_def(std::ofstream &out, std::string name);
-  void st_method(std::ofstream &out, std::string cls, std::string name);
-  void st_method(std::ofstream &out, std::string cls, std::string name, std::string category);
-  void st_close_method(std::ofstream &out);
-  void st_class_method(std::ofstream &out, std::string cls, std::string name);
-  void st_class_method(std::ofstream &out, std::string cls, std::string name, std::string category);
-  void st_setter(std::ofstream &out, std::string cls, std::string name, std::string type);
-  void st_getter(std::ofstream &out, std::string cls, std::string name);
-  void st_accessors(std::ofstream &out, std::string cls, std::string name, std::string type);
-
-  std::string class_name();
-  static bool is_valid_namespace(const std::string& sub_namespace);
-  std::string client_class_name();
-  std::string prefix(std::string name);
-  std::string declare_field(t_field* tfield);
-  std::string type_name(t_type* ttype);
-
-  std::string function_signature(t_function* tfunction);
-  std::string argument_list(t_struct* tstruct);
-  std::string function_types_comment(t_function* fn);
-
-  std::string type_to_enum(t_type* ttype);
-  std::string a_type(t_type* type);
-  bool is_vowel(char c);
-  std::string temp_name();
-  std::string generated_category();
-
- private:
-
-  /**
-   * File streams
-   */
-  int temporary_var;
-  std::ofstream f_;
-
-};
-
-
-/**
- * Prepares for file generation by opening up the necessary file output
- * streams.
- *
- * @param tprogram The program to generate
- */
-void t_st_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-
-  temporary_var = 0;
-
-  // Make output file
-  string f_name = get_out_dir()+"/"+program_name_+".st";
-  f_.open(f_name.c_str());
-
-  // Print header
-  f_ << st_autogen_comment() << endl;
-
-  st_class_def(f_, program_name_);
-  generate_class_side_definition();
-
-  //Generate enums
-  vector<t_enum*> enums = program_->get_enums();
-  vector<t_enum*>::iterator en_iter;
-  for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
-    generate_enum(*en_iter);
-  }
-}
-
-string t_st_generator::class_name() {
-  return capitalize(program_name_);
-}
-
-bool t_st_generator::is_valid_namespace(const std::string& sub_namespace) {
-  return sub_namespace == "prefix" || sub_namespace == "category";
-}
-
-string t_st_generator::prefix(string class_name) {
-  string prefix = program_->get_namespace("smalltalk.prefix");
-  string name = capitalize(class_name);
-  name = prefix.empty() ? name : (prefix + name);
-  return name;
-}
-
-string t_st_generator::client_class_name() {
-  return capitalize(service_name_) + "Client";
-}
-
-/**
- * Autogen'd comment
- */
-string t_st_generator::st_autogen_comment() {
-  return
-    std::string("'") +
-    "Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" +
-    "\n" +
-    "DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
-    "'!\n";
-}
-
-void t_st_generator::generate_force_consts() {
-  f_ << prefix(class_name()) << " enums keysAndValuesDo: [:k :v | " <<
-    prefix(class_name()) << " enums at: k put: v value].!" << endl;
-
-  f_ << prefix(class_name()) << " constants keysAndValuesDo: [:k :v | " <<
-    prefix(class_name()) << " constants at: k put: v value].!" << endl;
-
-}
-
-void t_st_generator::close_generator() {
-  generate_force_consts();
-  f_.close();
-}
-
-string t_st_generator::generated_category() {
-  string cat = program_->get_namespace("smalltalk.category");
-  // For compatibility with the Thrift grammar, the category must
-  // be punctuated by dots.  Replaces them with dashes here.
-  for (string::iterator iter = cat.begin(); iter != cat.end(); ++iter) {
-    if (*iter == '.') {
-      *iter = '-';
-    }
-  }
-  return cat.size() ? cat : "Generated-" + class_name();
-}
-
-/**
- * Generates a typedef. This is not done in Smalltalk, types are all implicit.
- *
- * @param ttypedef The type definition
- */
-void t_st_generator::generate_typedef(t_typedef* ttypedef) {
-  (void) ttypedef;
-}
-
-void t_st_generator::st_class_def(std::ofstream &out, string name) {
-  out << "Object subclass: #" << prefix(name) << endl;
-  indent_up();
-  out << indent() << "instanceVariableNames: ''" << endl <<
-    indent() << "classVariableNames: ''" << endl <<
-    indent() << "poolDictionaries: ''" << endl <<
-    indent() << "category: '" << generated_category() << "'!" << endl << endl;
-}
-
-void t_st_generator::st_method(std::ofstream &out, string cls, string name) {
-  st_method(out, cls, name, "as yet uncategorized");
-}
-
-void t_st_generator::st_class_method(std::ofstream &out, string cls, string name) {
-  st_method(out, cls + " class", name);
-}
-
-void t_st_generator::st_class_method(std::ofstream &out, string cls, string name, string category) {
-  st_method(out, cls, name, category);
-}
-
-void t_st_generator::st_method(std::ofstream &out, string cls, string name, string category) {
-  char timestr[50];
-  time_t rawtime;
-  struct tm *tinfo;
-
-  time(&rawtime);
-  tinfo = localtime(&rawtime);
-  strftime(timestr, 50, "%m/%d/%Y %H:%M", tinfo);
-
-  out << "!" << prefix(cls) <<
-    " methodsFor: '"+category+"' stamp: 'thrift " << timestr << "'!\n" <<
-    name << endl;
-
-  indent_up();
-  out << indent();
-}
-
-void t_st_generator::st_close_method(std::ofstream &out) {
-  out << "! !" << endl << endl;
-  indent_down();
-}
-
-void t_st_generator::st_setter(std::ofstream &out, string cls, string name, string type = "anObject") {
-  st_method(out, cls, name + ": " + type);
-  out << name << " := " + type;
-  st_close_method(out);
-}
-
-void t_st_generator::st_getter(std::ofstream &out, string cls, string name) {
-  st_method(out, cls, name + "");
-  out << "^ " << name;
-  st_close_method(out);
-}
-
-void t_st_generator::st_accessors(std::ofstream &out, string cls, string name, string type = "anObject") {
-  st_setter(out, cls, name, type);
-  st_getter(out, cls, name);
-}
-
-void t_st_generator::generate_class_side_definition() {
-  f_ << prefix(class_name()) << " class" << endl <<
-    "\tinstanceVariableNames: 'constants enums'!" << endl << endl;
-
-  st_accessors(f_, class_name() + " class", "enums");
-  st_accessors(f_, class_name() + " class", "constants");
-
-  f_ << prefix(class_name()) << " enums: Dictionary new!" << endl;
-  f_ << prefix(class_name()) << " constants: Dictionary new!" << endl;
-
-  f_ << endl;
-}
-
-/**
- * Generates code for an enumerated type. Done using a class to scope
- * the values.
- *
- * @param tenum The enumeration
- */
-void t_st_generator::generate_enum(t_enum* tenum) {
-  string cls_name = program_name_ + capitalize(tenum->get_name());
-
-  f_ << prefix(class_name()) << " enums at: '" << tenum->get_name() << "' put: [" <<
-    "(Dictionary new " << endl;
-
-  vector<t_enum_value*> constants = tenum->get_constants();
-  vector<t_enum_value*>::iterator c_iter;
-  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
-    int value = (*c_iter)->get_value();
-    f_ << "\tat: '" << (*c_iter)->get_name() << "' put: " << value << ";" << endl;
-  }
-
-  f_ << "\tyourself)]!" << endl << endl;
-}
-
-/**
- * Generate a constant value
- */
-void t_st_generator::generate_const(t_const* tconst) {
-  t_type* type = tconst->get_type();
-  string name = tconst->get_name();
-  t_const_value* value = tconst->get_value();
-
-  f_ << prefix(class_name()) << " constants at: '" << name << "' put: [" <<
-    render_const_value(type, value) << "]!" << endl << 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_st_generator::render_const_value(t_type* type, t_const_value* value) {
-  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 << "(" << capitalize(type->get_name()) << " new " << 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();
-      }
-
-      out << indent() << v_iter->first->get_string() << ": " <<
-        render_const_value(field_type, v_iter->second) << ";" << endl;
-    }
-    out << indent() << "yourself)";
-
-    indent_down();
-  } else if (type->is_map()) {
-    t_type* ktype = ((t_map*)type)->get_key_type();
-    t_type* vtype = ((t_map*)type)->get_val_type();
-    out << "(Dictionary new" << endl;
-    indent_up();
-    indent_up();
-    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) {
-      out << indent() << indent();
-      out << "at: " << render_const_value(ktype, v_iter->first);
-      out << " put: ";
-      out << render_const_value(vtype, v_iter->second);
-      out << ";" << endl;
-    }
-    out << indent() << indent() << "yourself)";
-    indent_down();
-    indent_down();
-  } else if (type->is_list() || type->is_set()) {
-    t_type* etype;
-    if (type->is_list()) {
-      etype = ((t_list*)type)->get_elem_type();
-    } else {
-      etype = ((t_set*)type)->get_elem_type();
-    }
-    if (type->is_set()) {
-      out << "(Set new" << endl;
-    } else {
-      out << "(OrderedCollection new" << endl;
-    }
-    indent_up();
-    indent_up();
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      out << indent() << indent();
-      out << "add: " << render_const_value(etype, *v_iter);
-      out << ";" << endl;
-    }
-    out << indent() << indent() << "yourself)";
-    indent_down();
-    indent_down();
-  } else {
-    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
-  }
-  return out.str();
-}
-
-/**
- * Generates a Smalltalk struct
- */
-void t_st_generator::generate_struct(t_struct* tstruct) {
-  generate_st_struct(f_, 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_st_generator::generate_xception(t_struct* txception) {
-  generate_st_struct(f_, txception, true);
-}
-
-/**
- * Generates a smalltalk class to represent a struct
- */
-void t_st_generator::generate_st_struct(std::ofstream& out, t_struct* tstruct, bool is_exception = false) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
-  if (is_exception)
-    out << "Error";
-  else
-    out << "Object";
-
-  out << " subclass: #" << prefix(type_name(tstruct)) << endl <<
-    "\tinstanceVariableNames: '";
-
-  if (members.size() > 0) {
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      if (m_iter != members.begin()) out << " ";
-      out << camelcase((*m_iter)->get_name());
-    }
-  }
-
-  out << "'\n" <<
-    "\tclassVariableNames: ''\n" <<
-    "\tpoolDictionaries: ''\n" <<
-    "\tcategory: '" << generated_category() << "'!\n\n";
-
-  generate_accessors(out, tstruct);
-}
-
-bool t_st_generator::is_vowel(char c) {
-  switch(tolower(c)) {
-    case 'a': case 'e': case 'i': case 'o': case 'u':
-    return true;
-  }
-  return false;
-}
-
-string t_st_generator::a_type(t_type* type) {
-  string prefix;
-
-  if (is_vowel(type_name(type)[0]))
-    prefix = "an";
-  else
-    prefix = "a";
-
-  return prefix + capitalize(type_name(type));
-}
-
-void t_st_generator::generate_accessors(std::ofstream& out, t_struct* tstruct) {
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  string type;
-  string prefix;
-
-  if (members.size() > 0) {
-    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      st_accessors(out,
-                   capitalize(type_name(tstruct)),
-                   camelcase((*m_iter)->get_name()),
-                   a_type((*m_iter)->get_type()));
-    }
-    out << endl;
-  }
-}
-
-/**
- * Generates a thrift service.
- *
- * @param tservice The service definition
- */
-void t_st_generator::generate_service(t_service* tservice) {
-  generate_service_client(tservice);
-  // generate_service_server(tservice);
-}
-
-string t_st_generator::temp_name() {
-  std::ostringstream out;
-  out << "temp" << temporary_var++;
-  return out.str();
-}
-
-string t_st_generator::map_writer(t_map *tmap, string fname) {
-  std::ostringstream out;
-  string key = temp_name();
-  string val = temp_name();
-
-  out << "[oprot writeMapBegin: (TMap new keyType: " << type_to_enum(tmap->get_key_type()) <<
-    "; valueType: " << type_to_enum(tmap->get_val_type()) << "; size: " << fname << " size)." << endl;
-  indent_up();
-
-  out << indent() << fname << " keysAndValuesDo: [:" << key << " :" << val << " |" << endl;
-  indent_up();
-
-  out << indent() << write_val(tmap->get_key_type(), key) << "." << endl <<
-    indent() << write_val(tmap->get_val_type(), val);
-  indent_down();
-
-  out << "]." << endl <<
-    indent() << "oprot writeMapEnd] value";
-  indent_down();
-
-  return out.str();
-}
-
-string t_st_generator::map_reader(t_map *tmap) {
-  std::ostringstream out;
-  string desc = temp_name();
-  string val = temp_name();
-
-  out << "[|" << desc << " " << val << "| " << endl;
-  indent_up();
-
-  out << indent() << desc << " := iprot readMapBegin." << endl <<
-    indent() << val << " := Dictionary new." << endl <<
-    indent() << desc << " size timesRepeat: [" << endl;
-
-  indent_up();
-  out << indent() << val << " at: " << read_val(tmap->get_key_type()) <<
-    " put: " << read_val(tmap->get_val_type());
-  indent_down();
-
-  out << "]." << endl <<
-    indent() << "iprot readMapEnd." << endl <<
-  indent() << val << "] value";
-  indent_down();
-
-  return out.str();
-}
-
-string t_st_generator::list_writer(t_list *tlist, string fname) {
-  std::ostringstream out;
-  string val = temp_name();
-
-  out << "[oprot writeListBegin: (TList new elemType: " <<
-    type_to_enum(tlist->get_elem_type()) << "; size: " << fname << " size)." << endl;
-  indent_up();
-
-  out << indent() << fname << " do: [:" << val << "|" << endl;
-  indent_up();
-
-  out << indent() << write_val(tlist->get_elem_type(), val) << endl;
-  indent_down();
-
-  out << "]." << endl <<
-    indent() << "oprot writeListEnd] value";
-  indent_down();
-
-  return out.str();
-}
-
-string t_st_generator::list_reader(t_list *tlist) {
-  std::ostringstream out;
-  string desc = temp_name();
-  string val = temp_name();
-
-  out << "[|" << desc << " " << val << "| " << desc << " := iprot readListBegin." << endl;
-  indent_up();
-
-  out << indent() << val << " := OrderedCollection new." << endl <<
-    indent() << desc << " size timesRepeat: [" << endl;
-
-  indent_up();
-  out << indent() << val << " add: " << read_val(tlist->get_elem_type());
-  indent_down();
-
-  out << "]." << endl <<
-    indent() << "iprot readListEnd." << endl <<
-  indent() << val << "] value";
-  indent_down();
-
-  return out.str();
-}
-
-string t_st_generator::set_writer(t_set *tset, string fname) {
-  std::ostringstream out;
-  string val = temp_name();
-
-  out << "[oprot writeSetBegin: (TSet new elemType: " << type_to_enum(tset->get_elem_type()) <<
-    "; size: " << fname << " size)." << endl;
-  indent_up();
-
-  out << indent() << fname << " do: [:" << val << "|" << endl;
-  indent_up();
-
-  out << indent() << write_val(tset->get_elem_type(), val) << endl;
-  indent_down();
-
-  out << "]." << endl <<
-    indent() << "oprot writeSetEnd] value";
-  indent_down();
-
-  return out.str();
-}
-
-string t_st_generator::set_reader(t_set *tset) {
-  std::ostringstream out;
-  string desc = temp_name();
-  string val = temp_name();
-
-  out << "[|" << desc << " " << val << "| " << desc << " := iprot readSetBegin." << endl;
-  indent_up();
-
-  out << indent() << val << " := Set new." << endl <<
-    indent() << desc << " size timesRepeat: [" << endl;
-
-  indent_up();
-  out << indent() << val << " add: " << read_val(tset->get_elem_type());
-  indent_down();
-
-  out << "]." << endl <<
-    indent() << "iprot readSetEnd." << endl <<
-  indent() << val << "] value";
-  indent_down();
-
-  return out.str();
-}
-
-string t_st_generator::struct_writer(t_struct *tstruct, string sname) {
-  std::ostringstream out;
-  const vector<t_field*>& fields = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator fld_iter;
-
-  out << "[oprot writeStructBegin: " <<
-    "(TStruct new name: '" + tstruct->get_name() +"')." << endl;
-  indent_up();
-
-  for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-    bool optional = (*fld_iter)->get_req() == t_field::T_OPTIONAL;
-    string fname = camelcase((*fld_iter)->get_name());
-    string accessor = sname + " " + camelcase(fname);
-
-    if (optional) {
-      out << indent() << accessor << " ifNotNil: [" << endl;
-      indent_up();
-    }
-
-    out << indent() << "oprot writeFieldBegin: (TField new name: '" << fname <<
-      "'; type: " << type_to_enum((*fld_iter)->get_type()) <<
-      "; id: " << (*fld_iter)->get_key() << ")." << endl;
-
-    out << indent() << write_val((*fld_iter)->get_type(), accessor) << "." << endl <<
-      indent() << "oprot writeFieldEnd";
-
-    if (optional) {
-      out << "]";
-      indent_down();
-    }
-
-    out << "." << endl;
-  }
-
-  out << indent() << "oprot writeFieldStop; writeStructEnd] value";
-  indent_down();
-
-  return out.str();
-}
-
-string t_st_generator::struct_reader(t_struct *tstruct, string clsName = "") {
-  std::ostringstream out;
-  const vector<t_field*>& fields = tstruct->get_members();
-  vector<t_field*>::const_iterator fld_iter;
-  string val = temp_name();
-  string desc = temp_name();
-  string found = temp_name();
-
-  if (clsName.size() == 0) {
-    clsName = tstruct->get_name();
-  }
-
-  out << "[|" << desc << " " << val << "|" << endl;
-  indent_up();
-
-  //This is nasty, but without it we'll break things by prefixing TResult.
-  string name = ((capitalize(clsName) == "TResult") ? capitalize(clsName) : prefix(clsName));
-  out << indent() << val << " := " << name << " new." << endl;
-
-  out << indent() << "iprot readStructBegin." << endl <<
-    indent() << "[" << desc << " := iprot readFieldBegin." << endl <<
-    indent() << desc << " type = TType stop] whileFalse: [|" << found << "|" << endl;
-  indent_up();
-
-  for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-    out << indent() << desc << " id = " << (*fld_iter)->get_key() <<
-      " ifTrue: [" << endl;
-    indent_up();
-
-    out << indent() << found << " := true." << endl <<
-      indent() << val << " " << camelcase((*fld_iter)->get_name()) << ": " <<
-      read_val((*fld_iter)->get_type());
-    indent_down();
-
-    out << "]." << endl;
-  }
-
-  out << indent() << found << " ifNil: [iprot skip: " << desc << " type]]." << endl;
-  indent_down();
-
-  out << indent() << "oprot readStructEnd." << endl <<
-    indent() << val << "] value";
-  indent_down();
-
-  return out.str();
-}
-
-string t_st_generator::write_val(t_type *t, string fname) {
-  t = get_true_type(t);
-
-  if (t->is_base_type()) {
-    t_base_type::t_base tbase = ((t_base_type*) t)->get_base();
-    switch(tbase) {
-    case t_base_type::TYPE_DOUBLE:
-      return "iprot writeDouble: " + fname + " asFloat";
-      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:
-      return "iprot write" + capitalize(type_name(t)) + ": " + fname + " asInteger";
-    default:
-      return "iprot write" + capitalize(type_name(t)) + ": " + fname;
-    }
-  } else if (t->is_map()) {
-    return map_writer((t_map*) t, fname);
-  } else if (t->is_struct() || t->is_xception()) {
-    return struct_writer((t_struct*) t, fname);
-  } else if (t->is_list()) {
-    return list_writer((t_list*) t, fname);
-  } else if (t->is_set()) {
-    return set_writer((t_set*) t, fname);
-  } else if (t->is_enum()) {
-    return "iprot writeI32: " + fname;
-  } else {
-    throw "Sorry, I don't know how to write this: " + type_name(t);
-  }
-}
-
-string t_st_generator::read_val(t_type *t) {
-  t = get_true_type(t);
-
-  if (t->is_base_type()) {
-    return "iprot read" + capitalize(type_name(t));
-  } else if (t->is_map()) {
-    return map_reader((t_map*) t);
-  } else if (t->is_struct() || t->is_xception()) {
-    return struct_reader((t_struct*) t);
-  } else if (t->is_list()) {
-    return list_reader((t_list*) t);
-  } else if (t->is_set()) {
-    return set_reader((t_set*) t);
-  } else if (t->is_enum()) {
-    return "iprot readI32";
-  } else {
-    throw "Sorry, I don't know how to read this: " + type_name(t);
-  }
-}
-
-void t_st_generator::generate_send_method(t_function* function) {
-  string funname = function->get_name();
-  string signature = function_signature(function);
-  t_struct* arg_struct = function->get_arglist();
-  const vector<t_field*>& fields = arg_struct->get_members();
-  vector<t_field*>::const_iterator fld_iter;
-
-  st_method(f_, client_class_name(), "send" + capitalize(signature));
-  f_ << "oprot writeMessageBegin:" << endl;
-  indent_up();
-
-  f_ << indent() << "(TCallMessage new" << endl;
-  indent_up();
-
-  f_ << indent() << "name: '" << funname << "'; " << endl <<
-    indent() << "seqid: self nextSeqid)." << endl;
-  indent_down();
-  indent_down();
-
-  f_ << indent() << "oprot writeStructBegin: " <<
-    "(TStruct new name: '" + capitalize(camelcase(funname)) + "_args')." << endl;
-
-  for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
-    string fname = camelcase((*fld_iter)->get_name());
-
-    f_ << indent() << "oprot writeFieldBegin: (TField new name: '" << fname <<
-      "'; type: " << type_to_enum((*fld_iter)->get_type()) <<
-      "; id: " << (*fld_iter)->get_key() << ")." << endl;
-
-    f_ << indent() << write_val((*fld_iter)->get_type(), fname) << "." << endl <<
-      indent() << "oprot writeFieldEnd." << endl;
-  }
-
-  f_ << indent() << "oprot writeFieldStop; writeStructEnd; writeMessageEnd." << endl;
-  f_ << indent() << "oprot transport flush";
-
-  st_close_method(f_);
-}
-
-// We only support receiving TResult structures (so this won't work on the server side)
-void t_st_generator::generate_recv_method(t_function* function) {
-  string funname = camelcase(function->get_name());
-  string signature = function_signature(function);
-
-  t_struct result(program_, "TResult");
-  t_field success(function->get_returntype(), "success", 0);
-  result.append(&success);
-
-  t_struct* xs = function->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) {
-    // duplicate the field, but call it "exception"... we don't need a dynamic name
-    t_field *exception = new t_field((*f_iter)->get_type(), "exception", (*f_iter)->get_key());
-    result.append(exception);
-  }
-
-  st_method(f_, client_class_name(), "recv" + capitalize(funname));
-  f_ << "| f msg res | " << endl <<
-    indent() << "msg := oprot readMessageBegin." << endl <<
-    indent() << "self validateRemoteMessage: msg." << endl <<
-    indent() << "res := " << struct_reader(&result) << "." << endl <<
-    indent() << "oprot readMessageEnd." << endl <<
-    indent() << "oprot transport flush." << endl <<
-    indent() << "res exception ifNotNil: [res exception signal]." << endl <<
-    indent() << "^ res";
-  st_close_method(f_);
-}
-
-string t_st_generator::function_types_comment(t_function* fn) {
-  std::ostringstream out;
-  const vector<t_field*>& fields = fn->get_arglist()->get_members();
-  vector<t_field*>::const_iterator f_iter;
-
-  out << "\"";
-
-  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
-    out << camelcase((*f_iter)->get_name()) << ": " << type_name((*f_iter)->get_type());
-    if ((f_iter + 1) != fields.end()) {
-      out << ", ";
-    }
-  }
-
-  out << "\"";
-
-  return out.str();
-}
-
-/**
- * Generates a service client definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_st_generator::generate_service_client(t_service* tservice) {
-  string extends = "";
-  string extends_client = "TClient";
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-
-  if (tservice->get_extends() != NULL) {
-    extends = type_name(tservice->get_extends());
-    extends_client = extends + "Client";
-  }
-
-  f_ << extends_client << " subclass: #" << prefix(client_class_name()) << endl <<
-    "\tinstanceVariableNames: ''\n" <<
-    "\tclassVariableNames: ''\n" <<
-    "\tpoolDictionaries: ''\n" <<
-    "\tcategory: '" << generated_category() << "'!\n\n";
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    string funname = camelcase((*f_iter)->get_name());
-    string signature = function_signature(*f_iter);
-
-    st_method(f_, client_class_name(), signature);
-    f_ << function_types_comment(*f_iter) << endl <<
-      indent() << "self send" << capitalize(signature) << "." << endl;
-
-    if (!(*f_iter)->is_oneway()) {
-      f_ << indent() << "^ self recv" << capitalize(funname) << " success " << endl;
-    }
-
-    st_close_method(f_);
-
-    generate_send_method(*f_iter);
-    if (!(*f_iter)->is_oneway()) {
-      generate_recv_method(*f_iter);
-    }
-  }
-}
-
-/**
- * Renders a function signature of the form 'type name(args)'
- *
- * @param tfunction Function definition
- * @return String of rendered function definition
- */
-string t_st_generator::function_signature(t_function* tfunction) {
-  return camelcase(tfunction->get_name()) + capitalize(argument_list(tfunction->get_arglist()));
-}
-
-/**
- * Renders a field list
- */
-string t_st_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 += " ";
-    }
-    string name = camelcase((*f_iter)->get_name());
-    result += name + ": " + name;
-  }
-  return result;
-}
-
-string t_st_generator::type_name(t_type* ttype) {
-  string prefix = "";
-  t_program* program = ttype->get_program();
-  if (program != NULL && program != program_) {
-    if (!ttype->is_service()) {
-      prefix = program->get_name() + "_types.";
-    }
-  }
-
-  string name = ttype->get_name();
-  if (ttype->is_struct() || ttype->is_xception()) {
-    name = capitalize(ttype->get_name());
-  }
-
-  return prefix + name;
-}
-
-/* Convert t_type to Smalltalk type code */
-string t_st_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 "TType string";
-    case t_base_type::TYPE_BOOL:
-      return "TType bool";
-    case t_base_type::TYPE_BYTE:
-      return "TType byte";
-    case t_base_type::TYPE_I16:
-      return "TType i16";
-    case t_base_type::TYPE_I32:
-      return "TType i32";
-    case t_base_type::TYPE_I64:
-      return "TType i64";
-    case t_base_type::TYPE_DOUBLE:
-      return "TType double";
-    }
-  } else if (type->is_enum()) {
-    return "TType i32";
-  } else if (type->is_struct() || type->is_xception()) {
-    return "TType struct";
-  } else if (type->is_map()) {
-    return "TType map";
-  } else if (type->is_set()) {
-    return "TType set";
-  } else if (type->is_list()) {
-    return "TType list";
-  }
-
-  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
-}
-
-
-THRIFT_REGISTER_GENERATOR(st, "Smalltalk", "")
-
diff --git a/compiler/cpp/src/generate/t_xsd_generator.cc b/compiler/cpp/src/generate/t_xsd_generator.cc
deleted file mode 100644
index ef00e51..0000000
--- a/compiler/cpp/src/generate/t_xsd_generator.cc
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <fstream>
-#include <iostream>
-#include <sstream>
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sstream>
-#include "t_generator.h"
-#include "platform.h"
-
-using std::map;
-using std::ofstream;
-using std::ostream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
-
-static const string endl = "\n";  // avoid ostream << std::endl flushes
-
-/**
- * XSD generator, creates an XSD for the base types etc.
- *
- */
-class t_xsd_generator : public t_generator {
- public:
-  t_xsd_generator(
-      t_program* program,
-      const std::map<std::string, std::string>& parsed_options,
-      const std::string& option_string)
-    : t_generator(program)
-  {
-    (void) parsed_options;
-    (void) option_string;
-    out_dir_base_ = "gen-xsd";
-  }
-
-  virtual ~t_xsd_generator() {}
-
-  /**
-   * 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) tenum;
-  }
-
-  void generate_service(t_service* tservice);
-  void generate_struct(t_struct* tstruct);
-
- private:
-
-  void generate_element(std::ostream& out, std::string name, t_type* ttype, t_struct* attrs=NULL, bool optional=false, bool nillable=false, bool list_element=false);
-
-  std::string ns(std::string in, std::string ns) {
-    return ns + ":" + in;
-  }
-
-  std::string xsd(std::string in) {
-    return ns(in, "xsd");
-  }
-
-  std::string type_name(t_type* ttype);
-  std::string base_type_name(t_base_type::t_base tbase);
-
-  /**
-   * Output xsd/php file
-   */
-  std::ofstream f_xsd_;
-  std::ofstream f_php_;
-
-  /**
-   * Output string stream
-   */
-  std::ostringstream s_xsd_types_;
-
-};
-
-
-void t_xsd_generator::init_generator() {
-  // Make output directory
-  MKDIR(get_out_dir().c_str());
-
-  // Make output file
-  string f_php_name = get_out_dir()+program_->get_name()+"_xsd.php";
-  f_php_.open(f_php_name.c_str());
-
-  f_php_ <<
-    "<?php" << endl;
-
-}
-
-void t_xsd_generator::close_generator() {
-  f_php_ << "?>" << endl;
-  f_php_.close();
-}
-
-void t_xsd_generator::generate_typedef(t_typedef* ttypedef) {
-  indent(s_xsd_types_) <<
-    "<xsd:simpleType name=\"" << ttypedef->get_name() << "\">" << endl;
-  indent_up();
-  if (ttypedef->get_type()->is_string() && ((t_base_type*)ttypedef->get_type())->is_string_enum()) {
-    indent(s_xsd_types_) <<
-      "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\">" << endl;
-    indent_up();
-    const vector<string>& values = ((t_base_type*)ttypedef->get_type())->get_string_enum_vals();
-    vector<string>::const_iterator v_iter;
-    for (v_iter = values.begin(); v_iter != values.end(); ++v_iter) {
-      indent(s_xsd_types_) <<
-        "<xsd:enumeration value=\"" << (*v_iter) << "\" />" << endl;
-    }
-    indent_down();
-    indent(s_xsd_types_) <<
-      "</xsd:restriction>" << endl;
-  } else {
-    indent(s_xsd_types_) <<
-      "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\" />" << endl;
-  }
-  indent_down();
-  indent(s_xsd_types_) <<
-    "</xsd:simpleType>" << endl << endl;
-}
-
-void t_xsd_generator::generate_struct(t_struct* tstruct) {
-  vector<t_field*>::const_iterator m_iter;
-  const vector<t_field*>& members = tstruct->get_members();
-  bool xsd_all = tstruct->get_xsd_all();
-
-  indent(s_xsd_types_) << "<xsd:complexType name=\"" << tstruct->get_name() << "\">" << endl;
-  indent_up();
-  if (xsd_all) {
-    indent(s_xsd_types_) << "<xsd:all>" << endl;
-  } else {
-    indent(s_xsd_types_) << "<xsd:sequence>" << endl;
-  }
-  indent_up();
-
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    generate_element(s_xsd_types_, (*m_iter)->get_name(), (*m_iter)->get_type(), (*m_iter)->get_xsd_attrs(), (*m_iter)->get_xsd_optional() || xsd_all, (*m_iter)->get_xsd_nillable());
-  }
-
-  indent_down();
-  if (xsd_all) {
-    indent(s_xsd_types_) << "</xsd:all>" << endl;
-  } else {
-    indent(s_xsd_types_) << "</xsd:sequence>" << endl;
-  }
-  indent_down();
-  indent(s_xsd_types_) <<
-    "</xsd:complexType>" << endl <<
-    endl;
-}
-
-void t_xsd_generator::generate_element(ostream& out,
-                                       string name,
-                                       t_type* ttype,
-                                       t_struct* attrs,
-                                       bool optional,
-                                       bool nillable,
-                                       bool list_element) {
-  string sminOccurs = (optional || list_element) ? " minOccurs=\"0\"" : "";
-  string smaxOccurs = list_element ? " maxOccurs=\"unbounded\"" : "";
-  string soptional = sminOccurs + smaxOccurs;
-  string snillable = nillable ? " nillable=\"true\"" : "";
-
-  if (ttype->is_void() || ttype->is_list()) {
-    indent(out) <<
-      "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
-    indent_up();
-    if (attrs == NULL && ttype->is_void()) {
-      indent(out) <<
-        "<xsd:complexType />" << endl;
-    } else {
-      indent(out) <<
-        "<xsd:complexType>" << endl;
-      indent_up();
-      if (ttype->is_list()) {
-        indent(out) << "<xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">" << endl;
-        indent_up();
-        string subname;
-        t_type* subtype = ((t_list*)ttype)->get_elem_type();
-        if (subtype->is_base_type() || subtype->is_container()) {
-          subname = name + "_elt";
-        } else {
-          subname = type_name(subtype);
-        }
-        f_php_ << "$GLOBALS['" << program_->get_name() << "_xsd_elt_" << name << "'] = '" << subname << "';" << endl;
-        generate_element(out, subname, subtype, NULL, false, false, true);
-        indent_down();
-        indent(out) << "</xsd:sequence>" << endl;
-        indent(out) << "<xsd:attribute name=\"list\" type=\"xsd:boolean\" />" << endl;
-      }
-      if (attrs != NULL) {
-        const vector<t_field*>& members = attrs->get_members();
-        vector<t_field*>::const_iterator a_iter;
-        for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
-          indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << endl;
-        }
-      }
-      indent_down();
-      indent(out) <<
-        "</xsd:complexType>" << endl;
-    }
-    indent_down();
-    indent(out) <<
-      "</xsd:element>" << endl;
-  } else {
-    if (attrs == NULL) {
-      indent(out) <<
-        "<xsd:element name=\"" << name << "\"" << " type=\"" << type_name(ttype) << "\"" << soptional << snillable << " />" << endl;
-    } else {
-      // Wow, all this work for a SIMPLE TYPE with attributes?!?!?!
-      indent(out) << "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
-      indent_up();
-      indent(out) << "<xsd:complexType>" << endl;
-      indent_up();
-      indent(out) << "<xsd:complexContent>" << endl;
-      indent_up();
-      indent(out) << "<xsd:extension base=\"" << type_name(ttype) << "\">" << endl;
-      indent_up();
-      const vector<t_field*>& members = attrs->get_members();
-      vector<t_field*>::const_iterator a_iter;
-      for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
-        indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\"" << type_name((*a_iter)->get_type()) << "\" />" << endl;
-      }
-      indent_down();
-      indent(out) << "</xsd:extension>" << endl;
-      indent_down();
-      indent(out) << "</xsd:complexContent>" << endl;
-      indent_down();
-      indent(out) << "</xsd:complexType>" << endl;
-      indent_down();
-      indent(out) << "</xsd:element>" << endl;
-    }
-  }
-}
-
-void t_xsd_generator::generate_service(t_service* tservice) {
-  // Make output file
-  string f_xsd_name = get_out_dir()+tservice->get_name()+".xsd";
-  f_xsd_.open(f_xsd_name.c_str());
-
-  string ns = program_->get_namespace("xsd");
-  if (ns.size() > 0) {
-    ns = " targetNamespace=\"" + ns + "\" xmlns=\"" + ns + "\" " +
-      "elementFormDefault=\"qualified\"";
-  }
-
-  // Print the XSD header
-  f_xsd_ <<
-    "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" << endl <<
-    "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" << ns << ">" << endl <<
-    endl <<
-    "<!-- Yo yo yo, this XSD woz be generated by Thrift. -->" << endl <<
-    endl;
-
-  // Print out the type definitions
-  indent(f_xsd_) << s_xsd_types_.str();
-
-  // Keep a list of all the possible exceptions that might get thrown
-  map<string, t_struct*> all_xceptions;
-
-  // List the elements that you might actually get
-  vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter;
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    string elemname = (*f_iter)->get_name() + "_response";
-    t_type* returntype = (*f_iter)->get_returntype();
-    generate_element(f_xsd_, elemname, returntype);
-    f_xsd_ << 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) {
-      all_xceptions[(*x_iter)->get_name()] = (t_struct*)((*x_iter)->get_type());
-    }
-  }
-
-  map<string, t_struct*>::iterator ax_iter;
-  for (ax_iter = all_xceptions.begin(); ax_iter != all_xceptions.end(); ++ax_iter) {
-    generate_element(f_xsd_, ax_iter->first, ax_iter->second);
-  }
-
-  // Close the XSD document
-  f_xsd_ << endl << "</xsd:schema>" << endl;
-  f_xsd_.close();
-}
-
-string t_xsd_generator::type_name(t_type* ttype) {
-  if (ttype->is_typedef()) {
-    return ttype->get_name();
-  }
-
-  if (ttype->is_base_type()) {
-    return xsd(base_type_name(((t_base_type*)ttype)->get_base()));
-  }
-
-  if (ttype->is_enum()) {
-    return xsd("int");
-  }
-
-  if (ttype->is_struct() || ttype->is_xception()) {
-    return ttype->get_name();
-  }
-
-  return "container";
-}
-
-/**
- * Returns the XSD type that corresponds to the thrift type.
- *
- * @param tbase The base type
- * @return Explicit XSD type, i.e. xsd:string
- */
-string t_xsd_generator::base_type_name(t_base_type::t_base tbase) {
-  switch (tbase) {
-  case t_base_type::TYPE_VOID:
-    return "void";
-  case t_base_type::TYPE_STRING:
-    return "string";
-  case t_base_type::TYPE_BOOL:
-    return "boolean";
-  case t_base_type::TYPE_BYTE:
-    return "byte";
-  case t_base_type::TYPE_I16:
-    return "short";
-  case t_base_type::TYPE_I32:
-    return "int";
-  case t_base_type::TYPE_I64:
-    return "long";
-  case t_base_type::TYPE_DOUBLE:
-    return "decimal";
-  default:
-    throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);
-  }
-}
-
-THRIFT_REGISTER_GENERATOR(xsd, "XSD", "")
-
diff --git a/compiler/cpp/src/globals.h b/compiler/cpp/src/globals.h
deleted file mode 100644
index 2b1865b..0000000
--- a/compiler/cpp/src/globals.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_GLOBALS_H
-#define T_GLOBALS_H
-
-#include <set>
-#include <queue>
-#include <stack>
-#include <vector>
-#include <string>
-
-/**
- * This module contains all the global variables (slap on the wrist) that are
- * shared throughout the program. The reason for this is to facilitate simple
- * interaction between the parser and the rest of the program. Before calling
- * yyparse(), the main.cc program will make necessary adjustments to these
- * global variables such that the parser does the right thing and puts entries
- * into the right containers, etc.
- *
- */
-
-/**
- * Hooray for forward declaration of types!
- */
-
-class t_program;
-class t_scope;
-class t_type;
-
-/**
- * Parsing mode, two passes up in this gin rummy!
- */
-
-enum PARSE_MODE {
-  INCLUDES = 1,
-  PROGRAM = 2
-};
-
-/**
- * Strictness level
- */
-extern int g_strict;
-
-/**
- * The master program parse tree. This is accessed from within the parser code
- * to build up the program elements.
- */
-extern t_program* g_program;
-
-/**
- * Global types for the parser to be able to reference
- */
-
-extern t_type* g_type_void;
-extern t_type* g_type_string;
-extern t_type* g_type_binary;
-extern t_type* g_type_slist;
-extern t_type* g_type_bool;
-extern t_type* g_type_byte;
-extern t_type* g_type_i16;
-extern t_type* g_type_i32;
-extern t_type* g_type_i64;
-extern t_type* g_type_double;
-
-/**
- * The scope that we are currently parsing into
- */
-extern t_scope* g_scope;
-
-/**
- * The parent scope to also load symbols into
- */
-extern t_scope* g_parent_scope;
-
-/**
- * The prefix for the parent scope entries
- */
-extern std::string g_parent_prefix;
-
-/**
- * The parsing pass that we are on. We do different things on each pass.
- */
-extern PARSE_MODE g_parse_mode;
-
-/**
- * Global time string, used in formatting error messages etc.
- */
-extern char* g_time_str;
-
-/**
- * The last parsed doctext comment.
- */
-extern char* g_doctext;
-
-/**
- * The location of the last parsed doctext comment.
- */
-extern int g_doctext_lineno;
-
-/**
- * Whether or not negative field keys are accepted.
- *
- * When a field does not have a user-specified key, thrift automatically
- * assigns a negative value.  However, this is fragile since changes to the
- * file may unintentionally change the key numbering, resulting in a new
- * protocol that is not backwards compatible.
- *
- * When g_allow_neg_field_keys is enabled, users can explicitly specify
- * negative keys.  This way they can write a .thrift file with explicitly
- * specified keys that is still backwards compatible with older .thrift files
- * that did not specify key values.
- */
-extern int g_allow_neg_field_keys;
-
-/**
- * Whether or not 64-bit constants will generate a warning.
- *
- * Some languages don't support 64-bit constants, but many do, so we can
- * suppress this warning for projects that don't use any non-64-bit-safe
- * languages.
- */
-extern int g_allow_64bit_consts;
-
-#endif
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
deleted file mode 100755
index da45ae7..0000000
--- a/compiler/cpp/src/main.cc
+++ /dev/null
@@ -1,1134 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * thrift - a lightweight cross-language rpc/serialization tool
- *
- * This file contains the main compiler engine for Thrift, which invokes the
- * scanner/parser to build the thrift object tree. The interface generation
- * code for each language lives in a file by the language name under the
- * generate/ folder, and all parse structures live in parse/
- *
- */
-
-#include <cassert>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <time.h>
-#include <string>
-#include <algorithm>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <limits.h>
-
-#ifdef MINGW
-# include <windows.h> /* for GetFullPathName */
-#endif
-
-// Careful: must include globals first for extern definitions
-#include "globals.h"
-
-#include "main.h"
-#include "parse/t_program.h"
-#include "parse/t_scope.h"
-#include "generate/t_generator.h"
-
-#include "version.h"
-
-using namespace std;
-
-/**
- * Global program tree
- */
-t_program* g_program;
-
-/**
- * Global types
- */
-
-t_type* g_type_void;
-t_type* g_type_string;
-t_type* g_type_binary;
-t_type* g_type_slist;
-t_type* g_type_bool;
-t_type* g_type_byte;
-t_type* g_type_i16;
-t_type* g_type_i32;
-t_type* g_type_i64;
-t_type* g_type_double;
-
-/**
- * Global scope
- */
-t_scope* g_scope;
-
-/**
- * Parent scope to also parse types
- */
-t_scope* g_parent_scope;
-
-/**
- * Prefix for putting types in parent scope
- */
-string g_parent_prefix;
-
-/**
- * Parsing pass
- */
-PARSE_MODE g_parse_mode;
-
-/**
- * Current directory of file being parsed
- */
-string g_curdir;
-
-/**
- * Current file being parsed
- */
-string g_curpath;
-
-/**
- * Search path for inclusions
- */
-vector<string> g_incl_searchpath;
-
-/**
- * Global debug state
- */
-int g_debug = 0;
-
-/**
- * Strictness level
- */
-int g_strict = 127;
-
-/**
- * Warning level
- */
-int g_warn = 1;
-
-/**
- * Verbose output
- */
-int g_verbose = 0;
-
-/**
- * Global time string
- */
-char* g_time_str;
-
-/**
- * The last parsed doctext comment.
- */
-char* g_doctext;
-
-/**
- * The location of the last parsed doctext comment.
- */
-int g_doctext_lineno;
-
-/**
- * Whether or not negative field keys are accepted.
- */
-int g_allow_neg_field_keys;
-
-/**
- * Whether or not 64-bit constants will generate a warning.
- */
-int g_allow_64bit_consts = 0;
-
-/**
- * Flags to control code generation
- */
-bool gen_recurse = false;
-
-/**
- * MinGW doesn't have realpath, so use fallback implementation in that case,
- * otherwise this just calls through to realpath
- */
-char *saferealpath(const char *path, char *resolved_path) {
-#ifdef MINGW
-  char buf[MAX_PATH];
-  char* basename;
-  DWORD len = GetFullPathName(path, MAX_PATH, buf, &basename);
-  if (len == 0 || len > MAX_PATH - 1){
-    strcpy(resolved_path, path);
-  } else {
-    strcpy(resolved_path, buf);
-  }
-
-  // Replace backslashes with forward slashes so the
-  // rest of the code behaves correctly.
-  size_t resolved_len = strlen(resolved_path);
-  for (size_t i = 0; i < resolved_len; i++) {
-    if (resolved_path[i] == '\\') {
-      resolved_path[i] = '/';
-    }
-  }
-  return resolved_path;
-#else
-  return realpath(path, resolved_path);
-#endif
-}
-
-bool check_is_directory(const char *dir_name) {
-#ifdef MINGW
-  DWORD attributes = ::GetFileAttributesA(dir_name);
-  if(attributes == INVALID_FILE_ATTRIBUTES) {
-    fprintf(stderr, "Output directory %s is unusable: GetLastError() = %ld\n", dir_name, GetLastError());
-    return false;
-  }
-  if((attributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) {
-    fprintf(stderr, "Output directory %s exists but is not a directory\n", dir_name);
-    return false;
-  }
-  return true;
-#else
-  struct stat sb;
-  if (stat(dir_name, &sb) < 0) {
-    fprintf(stderr, "Output directory %s is unusable: %s\n", dir_name, strerror(errno));
-    return false;
-  }
-  if (! S_ISDIR(sb.st_mode)) {
-    fprintf(stderr, "Output directory %s exists but is not a directory\n", dir_name);
-    return false;
-  }
-  return true;
-#endif
-}
-
-/**
- * Report an error to the user. This is called yyerror for historical
- * reasons (lex and yacc expect the error reporting routine to be called
- * this). Call this function to report any errors to the user.
- * yyerror takes printf style arguments.
- *
- * @param fmt C format string followed by additional arguments
- */
-void yyerror(const char* fmt, ...) {
-  va_list args;
-  fprintf(stderr,
-          "[ERROR:%s:%d] (last token was '%s')\n",
-          g_curpath.c_str(),
-          yylineno,
-          yytext);
-
-  va_start(args, fmt);
-  vfprintf(stderr, fmt, args);
-  va_end(args);
-
-  fprintf(stderr, "\n");
-}
-
-/**
- * Prints a debug message from the parser.
- *
- * @param fmt C format string followed by additional arguments
- */
-void pdebug(const char* fmt, ...) {
-  if (g_debug == 0) {
-    return;
-  }
-  va_list args;
-  printf("[PARSE:%d] ", yylineno);
-  va_start(args, fmt);
-  vprintf(fmt, args);
-  va_end(args);
-  printf("\n");
-}
-
-/**
- * Prints a verbose output mode message
- *
- * @param fmt C format string followed by additional arguments
- */
-void pverbose(const char* fmt, ...) {
-  if (g_verbose == 0) {
-    return;
-  }
-  va_list args;
-  va_start(args, fmt);
-  vprintf(fmt, args);
-  va_end(args);
-}
-
-/**
- * Prints a warning message
- *
- * @param fmt C format string followed by additional arguments
- */
-void pwarning(int level, const char* fmt, ...) {
-  if (g_warn < level) {
-    return;
-  }
-  va_list args;
-  printf("[WARNING:%s:%d] ", g_curpath.c_str(), yylineno);
-  va_start(args, fmt);
-  vprintf(fmt, args);
-  va_end(args);
-  printf("\n");
-}
-
-/**
- * Prints a failure message and exits
- *
- * @param fmt C format string followed by additional arguments
- */
-void failure(const char* fmt, ...) {
-  va_list args;
-  fprintf(stderr, "[FAILURE:%s:%d] ", g_curpath.c_str(), yylineno);
-  va_start(args, fmt);
-  vfprintf(stderr, fmt, args);
-  va_end(args);
-  printf("\n");
-  exit(1);
-}
-
-/**
- * Converts a string filename into a thrift program name
- */
-string program_name(string filename) {
-  string::size_type slash = filename.rfind("/");
-  if (slash != string::npos) {
-    filename = filename.substr(slash+1);
-  }
-  string::size_type dot = filename.rfind(".");
-  if (dot != string::npos) {
-    filename = filename.substr(0, dot);
-  }
-  return filename;
-}
-
-/**
- * Gets the directory path of a filename
- */
-string directory_name(string filename) {
-  string::size_type slash = filename.rfind("/");
-  // No slash, just use the current directory
-  if (slash == string::npos) {
-    return ".";
-  }
-  return filename.substr(0, slash);
-}
-
-/**
- * Finds the appropriate file path for the given filename
- */
-string include_file(string filename) {
-  // Absolute path? Just try that
-  if (filename[0] == '/') {
-    // Realpath!
-    char rp[PATH_MAX];
-    if (saferealpath(filename.c_str(), rp) == NULL) {
-      pwarning(0, "Cannot open include file %s\n", filename.c_str());
-      return std::string();
-    }
-
-    // Stat this file
-    struct stat finfo;
-    if (stat(rp, &finfo) == 0) {
-      return rp;
-    }
-  } else { // relative path, start searching
-    // new search path with current dir global
-    vector<string> sp = g_incl_searchpath;
-    sp.insert(sp.begin(), g_curdir);
-
-    // iterate through paths
-    vector<string>::iterator it;
-    for (it = sp.begin(); it != sp.end(); it++) {
-      string sfilename = *(it) + "/" + filename;
-
-      // Realpath!
-      char rp[PATH_MAX];
-      if (saferealpath(sfilename.c_str(), rp) == NULL) {
-        continue;
-      }
-
-      // Stat this files
-      struct stat finfo;
-      if (stat(rp, &finfo) == 0) {
-        return rp;
-      }
-    }
-  }
-
-  // Uh oh
-  pwarning(0, "Could not find include file %s\n", filename.c_str());
-  return std::string();
-}
-
-/**
- * Clears any previously stored doctext string.
- * Also prints a warning if we are discarding information.
- */
-void clear_doctext() {
-  if (g_doctext != NULL) {
-    pwarning(2, "Uncaptured doctext at on line %d.", g_doctext_lineno);
-  }
-  free(g_doctext);
-  g_doctext = NULL;
-}
-
-/**
- * Cleans up text commonly found in doxygen-like comments
- *
- * Warning: if you mix tabs and spaces in a non-uniform way,
- * you will get what you deserve.
- */
-char* clean_up_doctext(char* doctext) {
-  // Convert to C++ string, and remove Windows's carriage returns.
-  string docstring = doctext;
-  docstring.erase(
-      remove(docstring.begin(), docstring.end(), '\r'),
-      docstring.end());
-
-  // Separate into lines.
-  vector<string> lines;
-  string::size_type pos = string::npos;
-  string::size_type last;
-  while (true) {
-    last = (pos == string::npos) ? 0 : pos+1;
-    pos = docstring.find('\n', last);
-    if (pos == string::npos) {
-      // First bit of cleaning.  If the last line is only whitespace, drop it.
-      string::size_type nonwhite = docstring.find_first_not_of(" \t", last);
-      if (nonwhite != string::npos) {
-        lines.push_back(docstring.substr(last));
-      }
-      break;
-    }
-    lines.push_back(docstring.substr(last, pos-last));
-  }
-
-  // A very profound docstring.
-  if (lines.empty()) {
-    return NULL;
-  }
-
-  // Clear leading whitespace from the first line.
-  pos = lines.front().find_first_not_of(" \t");
-  lines.front().erase(0, pos);
-
-  // If every nonblank line after the first has the same number of spaces/tabs,
-  // then a star, remove them.
-  bool have_prefix = true;
-  bool found_prefix = false;
-  string::size_type prefix_len = 0;
-  vector<string>::iterator l_iter;
-  for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
-    if (l_iter->empty()) {
-      continue;
-    }
-
-    pos = l_iter->find_first_not_of(" \t");
-    if (!found_prefix) {
-      if (pos != string::npos) {
-        if (l_iter->at(pos) == '*') {
-          found_prefix = true;
-          prefix_len = pos;
-        } else {
-          have_prefix = false;
-          break;
-        }
-      } else {
-        // Whitespace-only line.  Truncate it.
-        l_iter->clear();
-      }
-    } else if (l_iter->size() > pos
-        && l_iter->at(pos) == '*'
-        && pos == prefix_len) {
-      // Business as usual.
-    } else if (pos == string::npos) {
-      // Whitespace-only line.  Let's truncate it for them.
-      l_iter->clear();
-    } else {
-      // The pattern has been broken.
-      have_prefix = false;
-      break;
-    }
-  }
-
-  // If our prefix survived, delete it from every line.
-  if (have_prefix) {
-    // Get the star too.
-    prefix_len++;
-    for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
-      l_iter->erase(0, prefix_len);
-    }
-  }
-
-  // Now delete the minimum amount of leading whitespace from each line.
-  prefix_len = string::npos;
-  for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
-    if (l_iter->empty()) {
-      continue;
-    }
-    pos = l_iter->find_first_not_of(" \t");
-    if (pos != string::npos
-        && (prefix_len == string::npos || pos < prefix_len)) {
-      prefix_len = pos;
-    }
-  }
-
-  // If our prefix survived, delete it from every line.
-  if (prefix_len != string::npos) {
-    for (l_iter = lines.begin()+1; l_iter != lines.end(); ++l_iter) {
-      l_iter->erase(0, prefix_len);
-    }
-  }
-
-  // Remove trailing whitespace from every line.
-  for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) {
-    pos = l_iter->find_last_not_of(" \t");
-    if (pos != string::npos && pos != l_iter->length()-1) {
-      l_iter->erase(pos+1);
-    }
-  }
-
-  // If the first line is empty, remove it.
-  // Don't do this earlier because a lot of steps skip the first line.
-  if (lines.front().empty()) {
-    lines.erase(lines.begin());
-  }
-
-  // Now rejoin the lines and copy them back into doctext.
-  docstring.clear();
-  for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) {
-    docstring += *l_iter;
-    docstring += '\n';
-  }
-
-  assert(docstring.length() <= strlen(doctext));
-  strcpy(doctext, docstring.c_str());
-  return doctext;
-}
-
-/** Set to true to debug docstring parsing */
-static bool dump_docs = false;
-
-/**
- * Dumps docstrings to stdout
- * Only works for top-level definitions and the whole program doc
- * (i.e., not enum constants, struct fields, or functions.
- */
-void dump_docstrings(t_program* program) {
-  string progdoc = program->get_doc();
-  if (!progdoc.empty()) {
-    printf("Whole program doc:\n%s\n", progdoc.c_str());
-  }
-  const vector<t_typedef*>& typedefs = program->get_typedefs();
-  vector<t_typedef*>::const_iterator t_iter;
-  for (t_iter = typedefs.begin(); t_iter != typedefs.end(); ++t_iter) {
-    t_typedef* td = *t_iter;
-    if (td->has_doc()) {
-      printf("typedef %s:\n%s\n", td->get_name().c_str(), td->get_doc().c_str());
-    }
-  }
-  const vector<t_enum*>& enums = program->get_enums();
-  vector<t_enum*>::const_iterator e_iter;
-  for (e_iter = enums.begin(); e_iter != enums.end(); ++e_iter) {
-    t_enum* en = *e_iter;
-    if (en->has_doc()) {
-      printf("enum %s:\n%s\n", en->get_name().c_str(), en->get_doc().c_str());
-    }
-  }
-  const vector<t_const*>& consts = program->get_consts();
-  vector<t_const*>::const_iterator c_iter;
-  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    t_const* co = *c_iter;
-    if (co->has_doc()) {
-      printf("const %s:\n%s\n", co->get_name().c_str(), co->get_doc().c_str());
-    }
-  }
-  const vector<t_struct*>& structs = program->get_structs();
-  vector<t_struct*>::const_iterator s_iter;
-  for (s_iter = structs.begin(); s_iter != structs.end(); ++s_iter) {
-    t_struct* st = *s_iter;
-    if (st->has_doc()) {
-      printf("struct %s:\n%s\n", st->get_name().c_str(), st->get_doc().c_str());
-    }
-  }
-  const vector<t_struct*>& xceptions = program->get_xceptions();
-  vector<t_struct*>::const_iterator x_iter;
-  for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-    t_struct* xn = *x_iter;
-    if (xn->has_doc()) {
-      printf("xception %s:\n%s\n", xn->get_name().c_str(), xn->get_doc().c_str());
-    }
-  }
-  const vector<t_service*>& services = program->get_services();
-  vector<t_service*>::const_iterator v_iter;
-  for (v_iter = services.begin(); v_iter != services.end(); ++v_iter) {
-    t_service* sv = *v_iter;
-    if (sv->has_doc()) {
-      printf("service %s:\n%s\n", sv->get_name().c_str(), sv->get_doc().c_str());
-    }
-  }
-}
-
-/**
- * Call generate_fingerprint for every structure and enum.
- */
-void generate_all_fingerprints(t_program* program) {
-  const vector<t_struct*>& structs = program->get_structs();
-  vector<t_struct*>::const_iterator s_iter;
-  for (s_iter = structs.begin(); s_iter != structs.end(); ++s_iter) {
-    t_struct* st = *s_iter;
-    st->generate_fingerprint();
-  }
-
-  const vector<t_struct*>& xceptions = program->get_xceptions();
-  vector<t_struct*>::const_iterator x_iter;
-  for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-    t_struct* st = *x_iter;
-    st->generate_fingerprint();
-  }
-
-  const vector<t_enum*>& enums = program->get_enums();
-  vector<t_enum*>::const_iterator e_iter;
-  for (e_iter = enums.begin(); e_iter != enums.end(); ++e_iter) {
-    t_enum* e = *e_iter;
-    e->generate_fingerprint();
-  }
-
-  g_type_void->generate_fingerprint();
-
-  // If you want to generate fingerprints for implicit structures, start here.
-  /*
-  const vector<t_service*>& services = program->get_services();
-  vector<t_service*>::const_iterator v_iter;
-  for (v_iter = services.begin(); v_iter != services.end(); ++v_iter) {
-    t_service* sv = *v_iter;
-  }
-  */
-}
-
-/**
- * Prints the version number
- */
-void version() {
-  printf("Thrift version %s\n", THRIFT_VERSION);
-}
-
-/**
- * Display the usage message and then exit with an error code.
- */
-void usage() {
-  fprintf(stderr, "Usage: thrift [options] file\n\n");
-  fprintf(stderr, "Use thrift -help for a list of options\n");
-  exit(1);
-}
-
-/**
- * Diplays the help message and then exits with an error code.
- */
-void help() {
-  fprintf(stderr, "Usage: thrift [options] file\n");
-  fprintf(stderr, "Options:\n");
-  fprintf(stderr, "  -version    Print the compiler version\n");
-  fprintf(stderr, "  -o dir      Set the output directory for gen-* packages\n");
-  fprintf(stderr, "               (default: current directory)\n");
-  fprintf(stderr, "  -out dir    Set the ouput location for generated files.\n");
-  fprintf(stderr,"               (no gen-* folder will be created)\n");
-  fprintf(stderr, "  -I dir      Add a directory to the list of directories\n");
-  fprintf(stderr, "                searched for include directives\n");
-  fprintf(stderr, "  -nowarn     Suppress all compiler warnings (BAD!)\n");
-  fprintf(stderr, "  -strict     Strict compiler warnings on\n");
-  fprintf(stderr, "  -v[erbose]  Verbose mode\n");
-  fprintf(stderr, "  -r[ecurse]  Also generate included files\n");
-  fprintf(stderr, "  -debug      Parse debug trace to stdout\n");
-  fprintf(stderr, "  --allow-neg-keys  Allow negative field keys (Used to "
-          "preserve protocol\n");
-  fprintf(stderr, "                compatibility with older .thrift files)\n");
-  fprintf(stderr, "  --allow-64bit-consts  Do not print warnings about using 64-bit constants\n");
-  fprintf(stderr, "  --gen STR   Generate code with a dynamically-registered generator.\n");
-  fprintf(stderr, "                STR has the form language[:key1=val1[,key2,[key3=val3]]].\n");
-  fprintf(stderr, "                Keys and values are options passed to the generator.\n");
-  fprintf(stderr, "                Many options will not require values.\n");
-  fprintf(stderr, "\n");
-  fprintf(stderr, "Available generators (and options):\n");
-
-  t_generator_registry::gen_map_t gen_map = t_generator_registry::get_generator_map();
-  t_generator_registry::gen_map_t::iterator iter;
-  for (iter = gen_map.begin(); iter != gen_map.end(); ++iter) {
-    fprintf(stderr, "  %s (%s):\n",
-        iter->second->get_short_name().c_str(),
-        iter->second->get_long_name().c_str());
-    fprintf(stderr, "%s", iter->second->get_documentation().c_str());
-  }
-  exit(1);
-}
-
-/**
- * You know, when I started working on Thrift I really thought it wasn't going
- * to become a programming language because it was just a generator and it
- * wouldn't need runtime type information and all that jazz. But then we
- * decided to add constants, and all of a sudden that means runtime type
- * validation and inference, except the "runtime" is the code generator
- * runtime.
- */
-void validate_const_rec(std::string name, t_type* type, t_const_value* value) {
-  if (type->is_void()) {
-    throw "type error: cannot declare a void const: " + name;
-  }
-
-  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:
-      if (value->get_type() != t_const_value::CV_STRING) {
-        throw "type error: const \"" + name + "\" was declared as string";
-      }
-      break;
-    case t_base_type::TYPE_BOOL:
-      if (value->get_type() != t_const_value::CV_INTEGER) {
-        throw "type error: const \"" + name + "\" was declared as bool";
-      }
-      break;
-    case t_base_type::TYPE_BYTE:
-      if (value->get_type() != t_const_value::CV_INTEGER) {
-        throw "type error: const \"" + name + "\" was declared as byte";
-      }
-      break;
-    case t_base_type::TYPE_I16:
-      if (value->get_type() != t_const_value::CV_INTEGER) {
-        throw "type error: const \"" + name + "\" was declared as i16";
-      }
-      break;
-    case t_base_type::TYPE_I32:
-      if (value->get_type() != t_const_value::CV_INTEGER) {
-        throw "type error: const \"" + name + "\" was declared as i32";
-      }
-      break;
-    case t_base_type::TYPE_I64:
-      if (value->get_type() != t_const_value::CV_INTEGER) {
-        throw "type error: const \"" + name + "\" was declared as i64";
-      }
-      break;
-    case t_base_type::TYPE_DOUBLE:
-      if (value->get_type() != t_const_value::CV_INTEGER &&
-          value->get_type() != t_const_value::CV_DOUBLE) {
-        throw "type error: const \"" + name + "\" was declared as double";
-      }
-      break;
-    default:
-      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase) + name;
-    }
-  } else if (type->is_enum()) {
-    if (value->get_type() != t_const_value::CV_IDENTIFIER) {
-      throw "type error: const \"" + name + "\" was declared as enum";
-    }
-
-    // see if there's a dot in the identifier
-    std::string name_portion = value->get_identifier_name();
-
-    const vector<t_enum_value*>& enum_values = ((t_enum*)type)->get_constants();
-    vector<t_enum_value*>::const_iterator c_iter;
-    bool found = false;
-
-    for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) {
-      if ((*c_iter)->get_name() == name_portion) {
-        found = true;
-        break;
-      }
-    }
-    if (!found) {
-      throw "type error: const " + name + " was declared as type " 
-        + type->get_name() + " which is an enum, but " 
-        + value->get_identifier() + " is not a valid value for that enum";
-    }
-  } else if (type->is_struct() || type->is_xception()) {
-    if (value->get_type() != t_const_value::CV_MAP) {
-      throw "type error: const \"" + name + "\" was declared as struct/xception";
-    }
-    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) {
-      if (v_iter->first->get_type() != t_const_value::CV_STRING) {
-        throw "type error: " + name + " struct key must be string";
-      }
-      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();
-      }
-
-      validate_const_rec(name + "." + v_iter->first->get_string(), field_type, v_iter->second);
-    }
-  } else if (type->is_map()) {
-    t_type* k_type = ((t_map*)type)->get_key_type();
-    t_type* v_type = ((t_map*)type)->get_val_type();
-    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) {
-      validate_const_rec(name + "<key>", k_type, v_iter->first);
-      validate_const_rec(name + "<val>", v_type, v_iter->second);
-    }
-  } else if (type->is_list() || type->is_set()) {
-    t_type* e_type;
-    if (type->is_list()) {
-      e_type = ((t_list*)type)->get_elem_type();
-    } else {
-      e_type = ((t_set*)type)->get_elem_type();
-    }
-    const vector<t_const_value*>& val = value->get_list();
-    vector<t_const_value*>::const_iterator v_iter;
-    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      validate_const_rec(name + "<elem>", e_type, *v_iter);
-    }
-  }
-}
-
-/**
- * Check the type of the parsed const information against its declared type
- */
-void validate_const_type(t_const* c) {
-  validate_const_rec(c->get_name(), c->get_type(), c->get_value());
-}
-
-/**
- * Check the type of a default value assigned to a field.
- */
-void validate_field_value(t_field* field, t_const_value* cv) {
-  validate_const_rec(field->get_name(), field->get_type(), cv);
-}
-
-/**
- * Check that all the elements of a throws block are actually exceptions.
- */
-bool validate_throws(t_struct* throws) {
-  const vector<t_field*>& members = throws->get_members();
-  vector<t_field*>::const_iterator m_iter;
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    if (!t_generator::get_true_type((*m_iter)->get_type())->is_xception()) {
-      return false;
-    }
-  }
-  return true;
-}
-
-/**
- * Parses a program
- */
-void parse(t_program* program, t_program* parent_program) {
-  // Get scope file path
-  string path = program->get_path();
-
-  // Set current dir global, which is used in the include_file function
-  g_curdir = directory_name(path);
-  g_curpath = path;
-
-  // Open the file
-  yyin = fopen(path.c_str(), "r");
-  if (yyin == 0) {
-    failure("Could not open input file: \"%s\"", path.c_str());
-  }
-
-  // Create new scope and scan for includes
-  pverbose("Scanning %s for includes\n", path.c_str());
-  g_parse_mode = INCLUDES;
-  g_program = program;
-  g_scope = program->scope();
-  try {
-    yylineno = 1;
-    if (yyparse() != 0) {
-      failure("Parser error during include pass.");
-    }
-  } catch (string x) {
-    failure(x.c_str());
-  }
-  fclose(yyin);
-
-  // Recursively parse all the include programs
-  vector<t_program*>& includes = program->get_includes();
-  vector<t_program*>::iterator iter;
-  for (iter = includes.begin(); iter != includes.end(); ++iter) {
-    parse(*iter, program);
-  }
-
-  // Parse the program file
-  g_parse_mode = PROGRAM;
-  g_program = program;
-  g_scope = program->scope();
-  g_parent_scope = (parent_program != NULL) ? parent_program->scope() : NULL;
-  g_parent_prefix = program->get_name() + ".";
-  g_curpath = path;
-  yyin = fopen(path.c_str(), "r");
-  if (yyin == 0) {
-    failure("Could not open input file: \"%s\"", path.c_str());
-  }
-  pverbose("Parsing %s for types\n", path.c_str());
-  yylineno = 1;
-  try {
-    if (yyparse() != 0) {
-      failure("Parser error during types pass.");
-    }
-  } catch (string x) {
-    failure(x.c_str());
-  }
-  fclose(yyin);
-}
-
-/**
- * Generate code
- */
-void generate(t_program* program, const vector<string>& generator_strings) {
-  // Oooohh, recursive code generation, hot!!
-  if (gen_recurse) {
-    const vector<t_program*>& includes = program->get_includes();
-    for (size_t i = 0; i < includes.size(); ++i) {
-      // Propogate output path from parent to child programs
-      includes[i]->set_out_path(program->get_out_path(), program->is_out_path_absolute());
-
-      generate(includes[i], generator_strings);
-    }
-  }
-
-  // Generate code!
-  try {
-    pverbose("Program: %s\n", program->get_path().c_str());
-
-    // Compute fingerprints.
-    generate_all_fingerprints(program);
-
-    if (dump_docs) {
-      dump_docstrings(program);
-    }
-
-    vector<string>::const_iterator iter;
-    for (iter = generator_strings.begin(); iter != generator_strings.end(); ++iter) {
-      t_generator* generator = t_generator_registry::get_generator(program, *iter);
-
-      if (generator == NULL) {
-        pwarning(1, "Unable to get a generator for \"%s\".\n", iter->c_str());
-      } else {
-        pverbose("Generating \"%s\"\n", iter->c_str());
-        generator->generate_program();
-        delete generator;
-      }
-    }
-
-  } catch (string s) {
-    printf("Error: %s\n", s.c_str());
-  } catch (const char* exc) {
-    printf("Error: %s\n", exc);
-  }
-
-}
-
-/**
- * Parse it up.. then spit it back out, in pretty much every language. Alright
- * not that many languages, but the cool ones that we care about.
- */
-int main(int argc, char** argv) {
-  int i;
-  std::string out_path;
-  bool out_path_is_absolute = false;
-
-  // Setup time string
-  time_t now = time(NULL);
-  g_time_str = ctime(&now);
-
-  // Check for necessary arguments, you gotta have at least a filename and
-  // an output language flag
-  if (argc < 2) {
-    usage();
-  }
-
-  vector<string> generator_strings;
-
-  // Set the current path to a dummy value to make warning messages clearer.
-  g_curpath = "arguments";
-
-  // Hacky parameter handling... I didn't feel like using a library sorry!
-  for (i = 1; i < argc-1; i++) {
-    char* arg;
-
-    arg = strtok(argv[i], " ");
-    while (arg != NULL) {
-      // Treat double dashes as single dashes
-      if (arg[0] == '-' && arg[1] == '-') {
-        ++arg;
-      }
-
-      if (strcmp(arg, "-help") == 0) {
-        help();
-      } else if (strcmp(arg, "-version") == 0) {
-        version();
-        exit(1);
-      } else if (strcmp(arg, "-debug") == 0) {
-        g_debug = 1;
-      } else if (strcmp(arg, "-nowarn") == 0) {
-        g_warn = 0;
-      } else if (strcmp(arg, "-strict") == 0) {
-        g_strict = 255;
-        g_warn = 2;
-      } else if (strcmp(arg, "-v") == 0 || strcmp(arg, "-verbose") == 0 ) {
-        g_verbose = 1;
-      } else if (strcmp(arg, "-r") == 0 || strcmp(arg, "-recurse") == 0 ) {
-        gen_recurse = true;
-      } else if (strcmp(arg, "-allow-neg-keys") == 0) {
-        g_allow_neg_field_keys = true;
-      } else if (strcmp(arg, "-allow-64bit-consts") == 0) {
-        g_allow_64bit_consts = true;
-      } else if (strcmp(arg, "-gen") == 0) {
-        arg = argv[++i];
-        if (arg == NULL) {
-          fprintf(stderr, "Missing generator specification\n");
-          usage();
-        }
-        generator_strings.push_back(arg);
-      } else if (strcmp(arg, "-I") == 0) {
-        // An argument of "-I\ asdf" is invalid and has unknown results
-        arg = argv[++i];
-
-        if (arg == NULL) {
-          fprintf(stderr, "Missing Include directory\n");
-          usage();
-        }
-        g_incl_searchpath.push_back(arg);
-      } else if ((strcmp(arg, "-o") == 0) || (strcmp(arg, "-out") == 0)) {
-        out_path_is_absolute = (strcmp(arg, "-out") == 0) ? true : false;
-        arg = argv[++i];
-        if (arg == NULL) {
-          fprintf(stderr, "-o: missing output directory\n");
-          usage();
-        }
-        out_path = arg;
-
-#ifdef MINGW
-        //strip out trailing \ on Windows
-        int last = out_path.length()-1;
-        if (out_path[last] == '\\')
-        {
-          out_path.erase(last);
-        }
-#endif
-        if (!check_is_directory(out_path.c_str()))
-          return -1;
-      } else {
-        fprintf(stderr, "Unrecognized option: %s\n", arg);
-        usage();
-      }
-
-      // Tokenize more
-      arg = strtok(NULL, " ");
-    }
-  }
-
-  // display help
-  if ((strcmp(argv[argc-1], "-help") == 0) || (strcmp(argv[argc-1], "--help") == 0)) {
-    help();
-  }
-
-  // if you're asking for version, you have a right not to pass a file
-  if ((strcmp(argv[argc-1], "-version") == 0) || (strcmp(argv[argc-1], "--version") == 0)) {
-    version();
-    exit(1);
-  }
-
-  // You gotta generate something!
-  if (generator_strings.empty()) {
-    fprintf(stderr, "No output language(s) specified\n");
-    usage();
-  }
-
-  // Real-pathify it
-  char rp[PATH_MAX];
-  if (argv[i] == NULL) {
-    fprintf(stderr, "Missing file name\n");
-    usage();
-  }
-  if (saferealpath(argv[i], rp) == NULL) {
-    failure("Could not open input file with realpath: %s", argv[i]);
-  }
-  string input_file(rp);
-
-  // Instance of the global parse tree
-  t_program* program = new t_program(input_file);
-  if (out_path.size()) {
-    program->set_out_path(out_path, out_path_is_absolute);
-  }
-
-  // Compute the cpp include prefix.
-  // infer this from the filename passed in
-  string input_filename = argv[i];
-  string include_prefix;
-
-  string::size_type last_slash = string::npos;
-  if ((last_slash = input_filename.rfind("/")) != string::npos) {
-    include_prefix = input_filename.substr(0, last_slash);
-  }
-
-  program->set_include_prefix(include_prefix);
-
-  // Initialize global types
-  g_type_void   = new t_base_type("void",   t_base_type::TYPE_VOID);
-  g_type_string = new t_base_type("string", t_base_type::TYPE_STRING);
-  g_type_binary = new t_base_type("string", t_base_type::TYPE_STRING);
-  ((t_base_type*)g_type_binary)->set_binary(true);
-  g_type_slist  = new t_base_type("string", t_base_type::TYPE_STRING);
-  ((t_base_type*)g_type_slist)->set_string_list(true);
-  g_type_bool   = new t_base_type("bool",   t_base_type::TYPE_BOOL);
-  g_type_byte   = new t_base_type("byte",   t_base_type::TYPE_BYTE);
-  g_type_i16    = new t_base_type("i16",    t_base_type::TYPE_I16);
-  g_type_i32    = new t_base_type("i32",    t_base_type::TYPE_I32);
-  g_type_i64    = new t_base_type("i64",    t_base_type::TYPE_I64);
-  g_type_double = new t_base_type("double", t_base_type::TYPE_DOUBLE);
-
-  // Parse it!
-  parse(program, NULL);
-
-  // The current path is not really relevant when we are doing generation.
-  // Reset the variable to make warning messages clearer.
-  g_curpath = "generation";
-  // Reset yylineno for the heck of it.  Use 1 instead of 0 because
-  // That is what shows up during argument parsing.
-  yylineno = 1;
-
-  // Generate it!
-  generate(program, generator_strings);
-
-  // Clean up. Who am I kidding... this program probably orphans heap memory
-  // all over the place, but who cares because it is about to exit and it is
-  // all referenced and used by this wacky parse tree up until now anyways.
-
-  delete program;
-  delete g_type_void;
-  delete g_type_string;
-  delete g_type_bool;
-  delete g_type_byte;
-  delete g_type_i16;
-  delete g_type_i32;
-  delete g_type_i64;
-  delete g_type_double;
-
-  // Finished
-  return 0;
-}
diff --git a/compiler/cpp/src/main.h b/compiler/cpp/src/main.h
deleted file mode 100644
index cb6d27a..0000000
--- a/compiler/cpp/src/main.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_MAIN_H
-#define T_MAIN_H
-
-#include <string>
-#include "parse/t_const.h"
-#include "parse/t_field.h"
-
-/**
- * Defined in the flex library
- */
-
-int yylex(void);
-
-int yyparse(void);
-
-/**
- * Expected to be defined by Flex/Bison
- */
-void yyerror(const char* fmt, ...);
-
-/**
- * Parse debugging output, used to print helpful info
- */
-void pdebug(const char* fmt, ...);
-
-/**
- * Parser warning
- */
-void pwarning(int level, const char* fmt, ...);
-
-/**
- * Print verbose output message
- */
-void pverbose(const char* fmt, ...);
-
-/**
- * Failure!
- */
-void failure(const char* fmt, ...);
-
-/**
- * Check constant types
- */
-void validate_const_type(t_const* c);
-
-/**
- * Check constant types
- */
-void validate_field_value(t_field* field, t_const_value* cv);
-
-/**
- * Check members of a throws block
- */
-bool validate_throws(t_struct* throws);
-
-/**
- * Converts a string filename into a thrift program name
- */
-std::string program_name(std::string filename);
-
-/**
- * Gets the directory path of a filename
- */
-std::string directory_name(std::string filename);
-
-/**
- * Get the absolute path for an include file
- */
-std::string include_file(std::string filename);
-
-/**
- * Clears any previously stored doctext string.
- */
-void clear_doctext();
-
-/**
- * Cleans up text commonly found in doxygen-like comments
- */
-char* clean_up_doctext(char* doctext);
-
-/**
- * Flex utilities
- */
-
-extern int   yylineno;
-extern char  yytext[];
-extern FILE* yyin;
-
-#endif
diff --git a/compiler/cpp/src/md5.c b/compiler/cpp/src/md5.c
deleted file mode 100644
index c35d96c..0000000
--- a/compiler/cpp/src/md5.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
-  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  L. Peter Deutsch
-  ghost@aladdin.com
-
- */
-/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
-/*
-  Independent implementation of MD5 (RFC 1321).
-
-  This code implements the MD5 Algorithm defined in RFC 1321, whose
-  text is available at
-	http://www.ietf.org/rfc/rfc1321.txt
-  The code is derived from the text of the RFC, including the test suite
-  (section A.5) but excluding the rest of Appendix A.  It does not include
-  any code or documentation that is identified in the RFC as being
-  copyrighted.
-
-  The original and principal author of md5.c is L. Peter Deutsch
-  <ghost@aladdin.com>.  Other authors are noted in the change history
-  that follows (in reverse chronological order):
-
-  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
-	either statically or dynamically; added missing #include <string.h>
-	in library.
-  2002-03-11 lpd Corrected argument list for main(), and added int return
-	type, in test program and T value program.
-  2002-02-21 lpd Added missing #include <stdio.h> in test program.
-  2000-07-03 lpd Patched to eliminate warnings about "constant is
-	unsigned in ANSI C, signed in traditional"; made test program
-	self-checking.
-  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
-  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
-  1999-05-03 lpd Original version.
- */
-
-#include "md5.h"
-#include <string.h>
-
-#undef BYTE_ORDER	/* 1 = big-endian, -1 = little-endian, 0 = unknown */
-#ifdef ARCH_IS_BIG_ENDIAN
-#  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
-#else
-#  define BYTE_ORDER 0
-#endif
-
-#define T_MASK ((md5_word_t)~0)
-#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
-#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
-#define T3    0x242070db
-#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
-#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
-#define T6    0x4787c62a
-#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
-#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
-#define T9    0x698098d8
-#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
-#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
-#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
-#define T13    0x6b901122
-#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
-#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
-#define T16    0x49b40821
-#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
-#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
-#define T19    0x265e5a51
-#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
-#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
-#define T22    0x02441453
-#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
-#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
-#define T25    0x21e1cde6
-#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
-#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
-#define T28    0x455a14ed
-#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
-#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
-#define T31    0x676f02d9
-#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
-#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
-#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
-#define T35    0x6d9d6122
-#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
-#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
-#define T38    0x4bdecfa9
-#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
-#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
-#define T41    0x289b7ec6
-#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
-#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
-#define T44    0x04881d05
-#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
-#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
-#define T47    0x1fa27cf8
-#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
-#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
-#define T50    0x432aff97
-#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
-#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
-#define T53    0x655b59c3
-#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
-#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
-#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
-#define T57    0x6fa87e4f
-#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
-#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
-#define T60    0x4e0811a1
-#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
-#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
-#define T63    0x2ad7d2bb
-#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
-
-
-static void
-md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
-{
-    md5_word_t
-	a = pms->abcd[0], b = pms->abcd[1],
-	c = pms->abcd[2], d = pms->abcd[3];
-    md5_word_t t;
-#if BYTE_ORDER > 0
-    /* Define storage only for big-endian CPUs. */
-    md5_word_t X[16];
-#else
-    /* Define storage for little-endian or both types of CPUs. */
-    md5_word_t xbuf[16];
-    const md5_word_t *X;
-#endif
-
-    {
-#if BYTE_ORDER == 0
-	/*
-	 * Determine dynamically whether this is a big-endian or
-	 * little-endian machine, since we can use a more efficient
-	 * algorithm on the latter.
-	 */
-	static const int w = 1;
-
-	if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
-#endif
-#if BYTE_ORDER <= 0		/* little-endian */
-	{
-	    /*
-	     * On little-endian machines, we can process properly aligned
-	     * data without copying it.
-	     */
-	    if (!((data - (const md5_byte_t *)0) & 3)) {
-		/* data are properly aligned */
-		X = (const md5_word_t *)data;
-	    } else {
-		/* not aligned */
-		memcpy(xbuf, data, 64);
-		X = xbuf;
-	    }
-	}
-#endif
-#if BYTE_ORDER == 0
-	else			/* dynamic big-endian */
-#endif
-#if BYTE_ORDER >= 0		/* big-endian */
-	{
-	    /*
-	     * On big-endian machines, we must arrange the bytes in the
-	     * right order.
-	     */
-	    const md5_byte_t *xp = data;
-	    int i;
-
-#  if BYTE_ORDER == 0
-	    X = xbuf;		/* (dynamic only) */
-#  else
-#    define xbuf X		/* (static only) */
-#  endif
-	    for (i = 0; i < 16; ++i, xp += 4)
-		xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
-	}
-#endif
-    }
-
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
-
-    /* Round 1. */
-    /* Let [abcd k s i] denote the operation
-       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
-#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
-#define SET(a, b, c, d, k, s, Ti)\
-  t = a + F(b,c,d) + X[k] + Ti;\
-  a = ROTATE_LEFT(t, s) + b
-    /* Do the following 16 operations. */
-    SET(a, b, c, d,  0,  7,  T1);
-    SET(d, a, b, c,  1, 12,  T2);
-    SET(c, d, a, b,  2, 17,  T3);
-    SET(b, c, d, a,  3, 22,  T4);
-    SET(a, b, c, d,  4,  7,  T5);
-    SET(d, a, b, c,  5, 12,  T6);
-    SET(c, d, a, b,  6, 17,  T7);
-    SET(b, c, d, a,  7, 22,  T8);
-    SET(a, b, c, d,  8,  7,  T9);
-    SET(d, a, b, c,  9, 12, T10);
-    SET(c, d, a, b, 10, 17, T11);
-    SET(b, c, d, a, 11, 22, T12);
-    SET(a, b, c, d, 12,  7, T13);
-    SET(d, a, b, c, 13, 12, T14);
-    SET(c, d, a, b, 14, 17, T15);
-    SET(b, c, d, a, 15, 22, T16);
-#undef SET
-
-     /* Round 2. */
-     /* Let [abcd k s i] denote the operation
-          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
-#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
-#define SET(a, b, c, d, k, s, Ti)\
-  t = a + G(b,c,d) + X[k] + Ti;\
-  a = ROTATE_LEFT(t, s) + b
-     /* Do the following 16 operations. */
-    SET(a, b, c, d,  1,  5, T17);
-    SET(d, a, b, c,  6,  9, T18);
-    SET(c, d, a, b, 11, 14, T19);
-    SET(b, c, d, a,  0, 20, T20);
-    SET(a, b, c, d,  5,  5, T21);
-    SET(d, a, b, c, 10,  9, T22);
-    SET(c, d, a, b, 15, 14, T23);
-    SET(b, c, d, a,  4, 20, T24);
-    SET(a, b, c, d,  9,  5, T25);
-    SET(d, a, b, c, 14,  9, T26);
-    SET(c, d, a, b,  3, 14, T27);
-    SET(b, c, d, a,  8, 20, T28);
-    SET(a, b, c, d, 13,  5, T29);
-    SET(d, a, b, c,  2,  9, T30);
-    SET(c, d, a, b,  7, 14, T31);
-    SET(b, c, d, a, 12, 20, T32);
-#undef SET
-
-     /* Round 3. */
-     /* Let [abcd k s t] denote the operation
-          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define SET(a, b, c, d, k, s, Ti)\
-  t = a + H(b,c,d) + X[k] + Ti;\
-  a = ROTATE_LEFT(t, s) + b
-     /* Do the following 16 operations. */
-    SET(a, b, c, d,  5,  4, T33);
-    SET(d, a, b, c,  8, 11, T34);
-    SET(c, d, a, b, 11, 16, T35);
-    SET(b, c, d, a, 14, 23, T36);
-    SET(a, b, c, d,  1,  4, T37);
-    SET(d, a, b, c,  4, 11, T38);
-    SET(c, d, a, b,  7, 16, T39);
-    SET(b, c, d, a, 10, 23, T40);
-    SET(a, b, c, d, 13,  4, T41);
-    SET(d, a, b, c,  0, 11, T42);
-    SET(c, d, a, b,  3, 16, T43);
-    SET(b, c, d, a,  6, 23, T44);
-    SET(a, b, c, d,  9,  4, T45);
-    SET(d, a, b, c, 12, 11, T46);
-    SET(c, d, a, b, 15, 16, T47);
-    SET(b, c, d, a,  2, 23, T48);
-#undef SET
-
-     /* Round 4. */
-     /* Let [abcd k s t] denote the operation
-          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
-#define I(x, y, z) ((y) ^ ((x) | ~(z)))
-#define SET(a, b, c, d, k, s, Ti)\
-  t = a + I(b,c,d) + X[k] + Ti;\
-  a = ROTATE_LEFT(t, s) + b
-     /* Do the following 16 operations. */
-    SET(a, b, c, d,  0,  6, T49);
-    SET(d, a, b, c,  7, 10, T50);
-    SET(c, d, a, b, 14, 15, T51);
-    SET(b, c, d, a,  5, 21, T52);
-    SET(a, b, c, d, 12,  6, T53);
-    SET(d, a, b, c,  3, 10, T54);
-    SET(c, d, a, b, 10, 15, T55);
-    SET(b, c, d, a,  1, 21, T56);
-    SET(a, b, c, d,  8,  6, T57);
-    SET(d, a, b, c, 15, 10, T58);
-    SET(c, d, a, b,  6, 15, T59);
-    SET(b, c, d, a, 13, 21, T60);
-    SET(a, b, c, d,  4,  6, T61);
-    SET(d, a, b, c, 11, 10, T62);
-    SET(c, d, a, b,  2, 15, T63);
-    SET(b, c, d, a,  9, 21, T64);
-#undef SET
-
-     /* Then perform the following additions. (That is increment each
-        of the four registers by the value it had before this block
-        was started.) */
-    pms->abcd[0] += a;
-    pms->abcd[1] += b;
-    pms->abcd[2] += c;
-    pms->abcd[3] += d;
-}
-
-void
-md5_init(md5_state_t *pms)
-{
-    pms->count[0] = pms->count[1] = 0;
-    pms->abcd[0] = 0x67452301;
-    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
-    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
-    pms->abcd[3] = 0x10325476;
-}
-
-void
-md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
-{
-    const md5_byte_t *p = data;
-    int left = nbytes;
-    int offset = (pms->count[0] >> 3) & 63;
-    md5_word_t nbits = (md5_word_t)(nbytes << 3);
-
-    if (nbytes <= 0)
-	return;
-
-    /* Update the message length. */
-    pms->count[1] += nbytes >> 29;
-    pms->count[0] += nbits;
-    if (pms->count[0] < nbits)
-	pms->count[1]++;
-
-    /* Process an initial partial block. */
-    if (offset) {
-	int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
-
-	memcpy(pms->buf + offset, p, copy);
-	if (offset + copy < 64)
-	    return;
-	p += copy;
-	left -= copy;
-	md5_process(pms, pms->buf);
-    }
-
-    /* Process full blocks. */
-    for (; left >= 64; p += 64, left -= 64)
-	md5_process(pms, p);
-
-    /* Process a final partial block. */
-    if (left)
-	memcpy(pms->buf, p, left);
-}
-
-void
-md5_finish(md5_state_t *pms, md5_byte_t digest[16])
-{
-    static const md5_byte_t pad[64] = {
-	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-    };
-    md5_byte_t data[8];
-    int i;
-
-    /* Save the length before padding. */
-    for (i = 0; i < 8; ++i)
-	data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
-    /* Pad to 56 bytes mod 64. */
-    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
-    /* Append the length. */
-    md5_append(pms, data, 8);
-    for (i = 0; i < 16; ++i)
-	digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
-}
diff --git a/compiler/cpp/src/md5.h b/compiler/cpp/src/md5.h
deleted file mode 100644
index 698c995..0000000
--- a/compiler/cpp/src/md5.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
-  Copyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  L. Peter Deutsch
-  ghost@aladdin.com
-
- */
-/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
-/*
-  Independent implementation of MD5 (RFC 1321).
-
-  This code implements the MD5 Algorithm defined in RFC 1321, whose
-  text is available at
-	http://www.ietf.org/rfc/rfc1321.txt
-  The code is derived from the text of the RFC, including the test suite
-  (section A.5) but excluding the rest of Appendix A.  It does not include
-  any code or documentation that is identified in the RFC as being
-  copyrighted.
-
-  The original and principal author of md5.h is L. Peter Deutsch
-  <ghost@aladdin.com>.  Other authors are noted in the change history
-  that follows (in reverse chronological order):
-
-  2002-04-13 lpd Removed support for non-ANSI compilers; removed
-	references to Ghostscript; clarified derivation from RFC 1321;
-	now handles byte order either statically or dynamically.
-  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
-  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
-	added conditionalization for C++ compilation from Martin
-	Purschke <purschke@bnl.gov>.
-  1999-05-03 lpd Original version.
- */
-
-#ifndef md5_INCLUDED
-#  define md5_INCLUDED
-
-/*
- * This package supports both compile-time and run-time determination of CPU
- * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
- * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
- * defined as non-zero, the code will be compiled to run only on big-endian
- * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
- * run on either big- or little-endian CPUs, but will run slightly less
- * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
- */
-
-typedef unsigned char md5_byte_t; /* 8-bit byte */
-typedef unsigned int md5_word_t; /* 32-bit word */
-
-/* Define the state of the MD5 Algorithm. */
-typedef struct md5_state_s {
-    md5_word_t count[2];	/* message length in bits, lsw first */
-    md5_word_t abcd[4];		/* digest buffer */
-    md5_byte_t buf[64];		/* accumulate block */
-} md5_state_t;
-
-#ifdef __cplusplus
-extern "C" 
-{
-#endif
-
-/* Initialize the algorithm. */
-void md5_init(md5_state_t *pms);
-
-/* Append a string to the message. */
-void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
-
-/* Finish the message and return the digest. */
-void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
-
-#ifdef __cplusplus
-}  /* end extern "C" */
-#endif
-
-#endif /* md5_INCLUDED */
diff --git a/compiler/cpp/src/parse/parse.cc b/compiler/cpp/src/parse/parse.cc
deleted file mode 100644
index a655652..0000000
--- a/compiler/cpp/src/parse/parse.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "t_type.h"
-#include "t_typedef.h"
-
-#include "md5.h"
-
-void t_type::generate_fingerprint() {
-  std::string material = get_fingerprint_material();
-  md5_state_t ctx;
-  md5_init(&ctx);
-  md5_append(&ctx, (md5_byte_t*)(material.data()), (int)material.size());
-  md5_finish(&ctx, (md5_byte_t*)fingerprint_);
-}
-
-t_type* t_type::get_true_type() {
-  t_type* type = this;
-  while (type->is_typedef()) {
-    type = ((t_typedef*)type)->get_type();
-  }
-  return type;
-}
diff --git a/compiler/cpp/src/parse/t_base_type.h b/compiler/cpp/src/parse/t_base_type.h
deleted file mode 100644
index d76772b..0000000
--- a/compiler/cpp/src/parse/t_base_type.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_BASE_TYPE_H
-#define T_BASE_TYPE_H
-
-#include <cstdlib>
-#include "t_type.h"
-
-/**
- * A thrift base type, which must be one of the defined enumerated types inside
- * this definition.
- *
- */
-class t_base_type : public t_type {
- public:
-  /**
-   * Enumeration of thrift base types
-   */
-  enum t_base {
-    TYPE_VOID,
-    TYPE_STRING,
-    TYPE_BOOL,
-    TYPE_BYTE,
-    TYPE_I16,
-    TYPE_I32,
-    TYPE_I64,
-    TYPE_DOUBLE
-  };
-
-  t_base_type(std::string name, t_base base) :
-    t_type(name),
-    base_(base),
-    string_list_(false),
-    binary_(false),
-    string_enum_(false){}
-
-  t_base get_base() const {
-    return base_;
-  }
-
-  bool is_void() const {
-    return base_ == TYPE_VOID;
-  }
-
-  bool is_string() const {
-    return base_ == TYPE_STRING;
-  }
-
-  bool is_bool() const {
-    return base_ == TYPE_BOOL;
-  }
-
-  void set_string_list(bool val) {
-    string_list_ = val;
-  }
-
-  bool is_string_list() const {
-    return (base_ == TYPE_STRING) && string_list_;
-  }
-
-  void set_binary(bool val) {
-    binary_ = val;
-  }
-
-  bool is_binary() const {
-    return (base_ == TYPE_STRING) && binary_;
-  }
-
-  void set_string_enum(bool val) {
-    string_enum_ = val;
-  }
-
-  bool is_string_enum() const {
-    return base_ == TYPE_STRING && string_enum_;
-  }
-
-  void add_string_enum_val(std::string val) {
-    string_enum_vals_.push_back(val);
-  }
-
-  const std::vector<std::string>& get_string_enum_vals() const {
-    return string_enum_vals_;
-  }
-
-  bool is_base_type() const {
-    return true;
-  }
-
-  virtual std::string get_fingerprint_material() const {
-    std::string rv = t_base_name(base_);
-    if (rv == "(unknown)") {
-      throw "BUG: Can't get fingerprint material for this base type.";
-    }
-    return rv;
-  }
-
-  static std::string t_base_name(t_base tbase) {
-    switch (tbase) {
-      case TYPE_VOID   : return      "void"; break;
-      case TYPE_STRING : return    "string"; break;
-      case TYPE_BOOL   : return      "bool"; break;
-      case TYPE_BYTE   : return      "byte"; break;
-      case TYPE_I16    : return       "i16"; break;
-      case TYPE_I32    : return       "i32"; break;
-      case TYPE_I64    : return       "i64"; break;
-      case TYPE_DOUBLE : return    "double"; break;
-      default          : return "(unknown)"; break;
-    }
-  }
-
- private:
-  t_base base_;
-
-  bool string_list_;
-  bool binary_;
-  bool string_enum_;
-  std::vector<std::string> string_enum_vals_;
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_const.h b/compiler/cpp/src/parse/t_const.h
deleted file mode 100644
index 7fd81bd..0000000
--- a/compiler/cpp/src/parse/t_const.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_CONST_H
-#define T_CONST_H
-
-#include "t_type.h"
-#include "t_const_value.h"
-
-/**
- * A const is a constant value defined across languages that has a type and
- * a value. The trick here is that the declared type might not match the type
- * of the value object, since that is not determined until after parsing the
- * whole thing out.
- *
- */
-class t_const : public t_doc {
- public:
-  t_const(t_type* type, std::string name, t_const_value* value) :
-    type_(type),
-    name_(name),
-    value_(value) {}
-
-  t_type* get_type() const {
-    return type_;
-  }
-
-  std::string get_name() const {
-    return name_;
-  }
-
-  t_const_value* get_value() const {
-    return value_;
-  }
-
- private:
-  t_type* type_;
-  std::string name_;
-  t_const_value* value_;
-};
-
-#endif
-
diff --git a/compiler/cpp/src/parse/t_const_value.h b/compiler/cpp/src/parse/t_const_value.h
deleted file mode 100644
index ff422ae..0000000
--- a/compiler/cpp/src/parse/t_const_value.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_CONST_VALUE_H
-#define T_CONST_VALUE_H
-
-#include "t_enum.h"
-#include <stdint.h>
-#include <map>
-#include <vector>
-#include <string>
-
-/**
- * A const value is something parsed that could be a map, set, list, struct
- * or whatever.
- *
- */
-class t_const_value {
- public:
-
-  enum t_const_value_type {
-    CV_INTEGER,
-    CV_DOUBLE,
-    CV_STRING,
-    CV_MAP,
-    CV_LIST,
-    CV_IDENTIFIER
-  };
-
-  t_const_value() {}
-
-  t_const_value(int64_t val) {
-    set_integer(val);
-  }
-
-  t_const_value(std::string val) {
-    set_string(val);
-  }
-
-  void set_string(std::string val) {
-    valType_ = CV_STRING;
-    stringVal_ = val;
-  }
-
-  std::string get_string() const {
-    return stringVal_;
-  }
-
-  void set_integer(int64_t val) {
-    valType_ = CV_INTEGER;
-    intVal_ = val;
-  }
-
-  int64_t get_integer() const {
-    if (valType_ == CV_IDENTIFIER) {
-      if (enum_ == NULL) {
-        throw "have identifier \"" + get_identifier() + "\", but unset enum on line!";
-      }
-      std::string identifier = get_identifier();
-      std::string::size_type dot = identifier.rfind('.');
-      if (dot != std::string::npos) {
-        identifier = identifier.substr(dot+1);
-      }
-      t_enum_value* val = enum_->get_constant_by_name(identifier);
-      if (val == NULL) {
-        throw
-          "Unable to find enum value \"" + identifier +
-          "\" in enum \"" + enum_->get_name() + "\"";
-      }
-      return val->get_value();
-    } else {
-      return intVal_;
-    }
-  }
-
-  void set_double(double val) {
-    valType_ = CV_DOUBLE;
-    doubleVal_ = val;
-  }
-
-  double get_double() const {
-    return doubleVal_;
-  }
-
-  void set_map() {
-    valType_ = CV_MAP;
-  }
-
-  void add_map(t_const_value* key, t_const_value* val) {
-    mapVal_[key] = val;
-  }
-
-  const std::map<t_const_value*, t_const_value*>& get_map() const {
-    return mapVal_;
-  }
-
-  void set_list() {
-    valType_ = CV_LIST;
-  }
-
-  void add_list(t_const_value* val) {
-    listVal_.push_back(val);
-  }
-
-  const std::vector<t_const_value*>& get_list() const {
-    return listVal_;
-  }
-
-  void set_identifier(std::string val) {
-    valType_ = CV_IDENTIFIER;
-    identifierVal_ = val;
-  }
-
-  std::string get_identifier() const {
-    return identifierVal_;
-  }
-
-  std::string get_identifier_name() const {
-    std::string ret = get_identifier();
-    size_t s = ret.find('.');
-    if (s == std::string::npos) {
-      throw "error: identifier " + ret + " is unqualified!";
-    }
-    ret = ret.substr(s+1);
-    s = ret.find('.');
-    if (s != std::string::npos) {
-      ret = ret.substr(s+1);
-    }
-    return ret;
-  }
-
-  std::string get_identifier_with_parent() const {
-    std::string ret = get_identifier();
-    size_t s = ret.find('.');
-    if (s == std::string::npos) {
-      throw "error: identifier " + ret + " is unqualified!";
-    }
-    size_t s2 = ret.find('.', s+1);
-    if (s2 != std::string::npos) {
-      ret = ret.substr(s+1);
-    }
-    return ret;
-  }
-
-  void set_enum(t_enum* tenum) {
-    enum_ = tenum;
-  }
-
-  t_const_value_type get_type() const {
-    return valType_;
-  }
-
- private:
-  std::map<t_const_value*, t_const_value*> mapVal_;
-  std::vector<t_const_value*> listVal_;
-  std::string stringVal_;
-  int64_t intVal_;
-  double doubleVal_;
-  std::string identifierVal_;
-  t_enum* enum_;
-
-  t_const_value_type valType_;
-
-};
-
-#endif
-
diff --git a/compiler/cpp/src/parse/t_container.h b/compiler/cpp/src/parse/t_container.h
deleted file mode 100644
index 6753493..0000000
--- a/compiler/cpp/src/parse/t_container.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_CONTAINER_H
-#define T_CONTAINER_H
-
-#include "t_type.h"
-
-class t_container : public t_type {
- public:
-  t_container() :
-    cpp_name_(),
-    has_cpp_name_(false) {}
-
-  virtual ~t_container() {}
-
-  void set_cpp_name(std::string cpp_name) {
-    cpp_name_ = cpp_name;
-    has_cpp_name_ = true;
-  }
-
-  bool has_cpp_name() {
-    return has_cpp_name_;
-  }
-
-  std::string get_cpp_name() {
-    return cpp_name_;
-  }
-
-  bool is_container() const {
-    return true;
-  }
-
- private:
-  std::string cpp_name_;
-  bool has_cpp_name_;
-
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_doc.h b/compiler/cpp/src/parse/t_doc.h
deleted file mode 100644
index e52068c..0000000
--- a/compiler/cpp/src/parse/t_doc.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_DOC_H
-#define T_DOC_H
-
-/**
- * Documentation stubs
- *
- */
-class t_doc {
-
- public:
-  t_doc() : has_doc_(false) {}
-
-  void set_doc(const std::string& doc) {
-    doc_ = doc;
-    has_doc_ = true;
-  }
-
-  const std::string& get_doc() const {
-    return doc_;
-  }
-
-  bool has_doc() {
-    return has_doc_;
-  }
-
- private:
-  std::string doc_;
-  bool has_doc_;
-
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_enum.h b/compiler/cpp/src/parse/t_enum.h
deleted file mode 100644
index 45d1606..0000000
--- a/compiler/cpp/src/parse/t_enum.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_ENUM_H
-#define T_ENUM_H
-
-#include "t_enum_value.h"
-#include <vector>
-
-/**
- * An enumerated type. A list of constant objects with a name for the type.
- *
- */
-class t_enum : public t_type {
- public:
-  t_enum(t_program* program) :
-    t_type(program) {}
-
-  void set_name(const std::string& name) {
-    name_ = name;
-  }
-
-  void append(t_enum_value* constant) {
-    constants_.push_back(constant);
-  }
-
-  const std::vector<t_enum_value*>& get_constants() {
-    return constants_;
-  }
-
-  t_enum_value* get_constant_by_name(const std::string name) {
-    const std::vector<t_enum_value*>& enum_values = get_constants();
-    std::vector<t_enum_value*>::const_iterator c_iter;
-    for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) {
-      if ((*c_iter)->get_name() == name) {
-        return *c_iter;
-      }
-    }
-    return NULL;
-  }
-
-  t_enum_value* get_constant_by_value(int64_t value) {
-    const std::vector<t_enum_value*>& enum_values = get_constants();
-    std::vector<t_enum_value*>::const_iterator c_iter;
-    for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) {
-      if ((*c_iter)->get_value() == value) {
-        return *c_iter;
-      }
-    }
-    return NULL;
-  }
-
-  bool is_enum() const {
-    return true;
-  }
-
-  virtual std::string get_fingerprint_material() const {
-    return "enum";
-  }
-
-  void resolve_values() {
-    const std::vector<t_enum_value*>& enum_values = get_constants();
-    std::vector<t_enum_value*>::const_iterator c_iter;
-    int lastValue = -1;
-    for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) {
-      if (! (*c_iter)->has_value()) {
-        (*c_iter)->set_value(++lastValue);
-      } else {
-        lastValue = (*c_iter)->get_value();
-      }
-    }
-  }
-
- private:
-  std::vector<t_enum_value*> constants_;
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_enum_value.h b/compiler/cpp/src/parse/t_enum_value.h
deleted file mode 100644
index 3a4a90a..0000000
--- a/compiler/cpp/src/parse/t_enum_value.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_ENUM_VALUE_H
-#define T_ENUM_VALUE_H
-
-#include <string>
-#include "t_doc.h"
-
-/**
- * A constant. These are used inside of enum definitions. Constants are just
- * symbol identifiers that may or may not have an explicit value associated
- * with them.
- *
- */
-class t_enum_value : public t_doc {
- public:
-  t_enum_value(std::string name) :
-    name_(name),
-    has_value_(false),
-    value_(0) {}
-
-  t_enum_value(std::string name, int value) :
-    name_(name),
-    has_value_(true),
-    value_(value) {}
-
-  ~t_enum_value() {}
-
-  const std::string& get_name() {
-    return name_;
-  }
-
-  bool has_value() {
-    return has_value_;
-  }
-
-  int get_value() {
-    return value_;
-  }
-
-  void set_value(int val) {
-    has_value_ = true;
-    value_ = val;
-  }
-
-  std::map<std::string, std::string> annotations_;
-
- private:
-  std::string name_;
-  bool has_value_;
-  int value_;
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_field.h b/compiler/cpp/src/parse/t_field.h
deleted file mode 100644
index ac10d57..0000000
--- a/compiler/cpp/src/parse/t_field.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_FIELD_H
-#define T_FIELD_H
-
-#include <string>
-#include <sstream>
-
-#include "t_doc.h"
-
-// Forward declare for xsd_attrs
-class t_struct;
-
-/**
- * Class to represent a field in a thrift structure. A field has a data type,
- * a symbolic name, and a numeric identifier.
- *
- */
-class t_field : public t_doc {
- public:
-  t_field(t_type* type, std::string name) :
-    type_(type),
-    name_(name),
-    key_(0),
-    value_(NULL),
-    xsd_optional_(false),
-    xsd_nillable_(false),
-    xsd_attrs_(NULL) {}
-
-  t_field(t_type* type, std::string name, int32_t key) :
-    type_(type),
-    name_(name),
-    key_(key),
-    req_(T_OPT_IN_REQ_OUT),
-    value_(NULL),
-    xsd_optional_(false),
-    xsd_nillable_(false),
-    xsd_attrs_(NULL) {}
-
-  ~t_field() {}
-
-  t_type* get_type() const {
-    return type_;
-  }
-
-  const std::string& get_name() const {
-    return name_;
-  }
-
-  int32_t get_key() const {
-    return key_;
-  }
-
-  enum e_req {
-    T_REQUIRED,
-    T_OPTIONAL,
-    T_OPT_IN_REQ_OUT
-  };
-
-  void set_req(e_req req) {
-    req_ = req;
-  }
-
-  e_req get_req() const {
-    return req_;
-  }
-
-  void set_value(t_const_value* value) {
-    value_ = value;
-  }
-
-  t_const_value* get_value() {
-    return value_;
-  }
-
-  void set_xsd_optional(bool xsd_optional) {
-    xsd_optional_ = xsd_optional;
-  }
-
-  bool get_xsd_optional() const {
-    return xsd_optional_;
-  }
-
-  void set_xsd_nillable(bool xsd_nillable) {
-    xsd_nillable_ = xsd_nillable;
-  }
-
-  bool get_xsd_nillable() const {
-    return xsd_nillable_;
-  }
-
-  void set_xsd_attrs(t_struct* xsd_attrs) {
-    xsd_attrs_ = xsd_attrs;
-  }
-
-  t_struct* get_xsd_attrs() {
-    return xsd_attrs_;
-  }
-
-  // This is not the same function as t_type::get_fingerprint_material,
-  // but it does the same thing.
-  std::string get_fingerprint_material() const {
-    std::ostringstream keystm;
-    keystm << key_;
-    return keystm.str() + ":" +
-      ((req_ == T_OPTIONAL) ? "opt-" : "") +
-      type_->get_fingerprint_material();
-  }
-
-  /**
-   * Comparator to sort fields in ascending order by key.
-   * Make this a functor instead of a function to help GCC inline it.
-   * The arguments are (const) references to const pointers to const t_fields.
-   */
-  struct key_compare {
-    bool operator()(t_field const * const & a, t_field const * const & b) {
-      return a->get_key() < b->get_key();
-    }
-  };
-
-  std::map<std::string, std::string> annotations_;
-
- private:
-  t_type* type_;
-  std::string name_;
-  int32_t key_;
-  e_req req_;
-  t_const_value* value_;
-
-  bool xsd_optional_;
-  bool xsd_nillable_;
-  t_struct* xsd_attrs_;
-
-};
-
-/**
- * A simple struct for the parser to use to store a field ID, and whether or
- * not it was specified by the user or automatically chosen.
- */
-struct t_field_id {
-  int64_t value;
-  bool auto_assigned;
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_function.h b/compiler/cpp/src/parse/t_function.h
deleted file mode 100644
index ae8c2f6..0000000
--- a/compiler/cpp/src/parse/t_function.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_FUNCTION_H
-#define T_FUNCTION_H
-
-#include <string>
-#include "t_type.h"
-#include "t_struct.h"
-#include "t_doc.h"
-
-/**
- * Representation of a function. Key parts are return type, function name,
- * optional modifiers, and an argument list, which is implemented as a thrift
- * struct.
- *
- */
-class t_function : public t_doc {
- public:
-  t_function(t_type* returntype,
-             std::string name,
-             t_struct* arglist,
-             bool oneway=false) :
-    returntype_(returntype),
-    name_(name),
-    arglist_(arglist),
-    oneway_(oneway) {
-    xceptions_ = new t_struct(NULL);
-    if (oneway_ && (! returntype_->is_void())) {
-      pwarning(1, "Oneway methods should return void.\n");
-    }
-  }
-
-  t_function(t_type* returntype,
-             std::string name,
-             t_struct* arglist,
-             t_struct* xceptions,
-             bool oneway=false) :
-    returntype_(returntype),
-    name_(name),
-    arglist_(arglist),
-    xceptions_(xceptions),
-    oneway_(oneway)
-  {
-    if (oneway_ && !xceptions_->get_members().empty()) {
-      throw std::string("Oneway methods can't throw exceptions.");
-    }
-    if (oneway_ && (! returntype_->is_void())) {
-      pwarning(1, "Oneway methods should return void.\n");
-    }
-  }
-
-  ~t_function() {}
-
-  t_type* get_returntype() const {
-    return returntype_;
-  }
-
-  const std::string& get_name() const {
-    return name_;
-  }
-
-  t_struct* get_arglist() const {
-    return arglist_;
-  }
-
-  t_struct* get_xceptions() const {
-    return xceptions_;
-  }
-
-  bool is_oneway() const {
-    return oneway_;
-  }
-
-  std::map<std::string, std::string> annotations_;
-
- private:
-  t_type* returntype_;
-  std::string name_;
-  t_struct* arglist_;
-  t_struct* xceptions_;
-  bool oneway_;
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_list.h b/compiler/cpp/src/parse/t_list.h
deleted file mode 100644
index 21a9625..0000000
--- a/compiler/cpp/src/parse/t_list.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_LIST_H
-#define T_LIST_H
-
-#include "t_container.h"
-
-/**
- * A list is a lightweight container type that just wraps another data type.
- *
- */
-class t_list : public t_container {
- public:
-  t_list(t_type* elem_type) :
-    elem_type_(elem_type) {}
-
-  t_type* get_elem_type() const {
-    return elem_type_;
-  }
-
-  bool is_list() const {
-    return true;
-  }
-
-  virtual std::string get_fingerprint_material() const {
-    return "list<" + elem_type_->get_fingerprint_material() + ">";
-  }
-
-  virtual void generate_fingerprint() {
-    t_type::generate_fingerprint();
-    elem_type_->generate_fingerprint();
-  }
-
- private:
-  t_type* elem_type_;
-};
-
-#endif
-
diff --git a/compiler/cpp/src/parse/t_map.h b/compiler/cpp/src/parse/t_map.h
deleted file mode 100644
index c4e358f..0000000
--- a/compiler/cpp/src/parse/t_map.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_MAP_H
-#define T_MAP_H
-
-#include "t_container.h"
-
-/**
- * A map is a lightweight container type that just wraps another two data
- * types.
- *
- */
-class t_map : public t_container {
- public:
-  t_map(t_type* key_type, t_type* val_type) :
-    key_type_(key_type),
-    val_type_(val_type) {}
-
-  t_type* get_key_type() const {
-    return key_type_;
-  }
-
-  t_type* get_val_type() const {
-    return val_type_;
-  }
-
-  bool is_map() const {
-    return true;
-  }
-
-  virtual std::string get_fingerprint_material() const {
-    return "map<" + key_type_->get_fingerprint_material() +
-      "," + val_type_->get_fingerprint_material() + ">";
-  }
-
-  virtual void generate_fingerprint() {
-    t_type::generate_fingerprint();
-    key_type_->generate_fingerprint();
-    val_type_->generate_fingerprint();
-  }
-
- private:
-  t_type* key_type_;
-  t_type* val_type_;
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h
deleted file mode 100644
index 96a8a5c..0000000
--- a/compiler/cpp/src/parse/t_program.h
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_PROGRAM_H
-#define T_PROGRAM_H
-
-#include <map>
-#include <string>
-#include <vector>
-
-// For program_name()
-#include "main.h"
-
-#include "t_doc.h"
-#include "t_scope.h"
-#include "t_base_type.h"
-#include "t_typedef.h"
-#include "t_enum.h"
-#include "t_const.h"
-#include "t_struct.h"
-#include "t_service.h"
-#include "t_list.h"
-#include "t_map.h"
-#include "t_set.h"
-#include "generate/t_generator_registry.h"
-//#include "t_doc.h"
-
-/**
- * Top level class representing an entire thrift program. A program consists
- * fundamentally of the following:
- *
- *   Typedefs
- *   Enumerations
- *   Constants
- *   Structs
- *   Exceptions
- *   Services
- *
- * The program module also contains the definitions of the base types.
- *
- */
-class t_program : public t_doc {
- public:
-  t_program(std::string path, std::string name) :
-    path_(path),
-    name_(name),
-    out_path_("./"),
-    out_path_is_absolute_(false) {
-    scope_ = new t_scope();
-  }
-
-  t_program(std::string path) :
-    path_(path),
-    out_path_("./"),
-    out_path_is_absolute_(false) {
-    name_ = program_name(path);
-    scope_ = new t_scope();
-  }
-
-  ~t_program()
-  {
-   if(scope_)
-   {
-     delete scope_; 
-     scope_ = NULL; 
-   }
-  } 
-
-  // Path accessor
-  const std::string& get_path() const { return path_; }
-
-  // Output path accessor
-  const std::string& get_out_path() const { return out_path_; }
-
-  // Create gen-* dir accessor
-  const bool is_out_path_absolute() const { return out_path_is_absolute_; }
-
-  // Name accessor
-  const std::string& get_name() const { return name_; }
-
-  // Namespace
-  const std::string& get_namespace() const { return namespace_; }
-
-  // Include prefix accessor
-  const std::string& get_include_prefix() const { return include_prefix_; }
-
-  // Accessors for program elements
-  const std::vector<t_typedef*>& get_typedefs()  const { return typedefs_;  }
-  const std::vector<t_enum*>&    get_enums()     const { return enums_;     }
-  const std::vector<t_const*>&   get_consts()    const { return consts_;    }
-  const std::vector<t_struct*>&  get_structs()   const { return structs_;   }
-  const std::vector<t_struct*>&  get_xceptions() const { return xceptions_; }
-  const std::vector<t_struct*>&  get_objects()   const { return objects_;   }
-  const std::vector<t_service*>& get_services()  const { return services_;  }
-
-  // Program elements
-  void add_typedef  (t_typedef* td) { typedefs_.push_back(td);  }
-  void add_enum     (t_enum*    te) { enums_.push_back(te);     }
-  void add_const    (t_const*   tc) { consts_.push_back(tc);    }
-  void add_struct   (t_struct*  ts) { objects_.push_back(ts);
-                                      structs_.push_back(ts);   }
-  void add_xception (t_struct*  tx) { objects_.push_back(tx);
-                                      xceptions_.push_back(tx); }
-  void add_service  (t_service* ts) { services_.push_back(ts);  }
-
-  // Programs to include
-  const std::vector<t_program*>& get_includes() const { return includes_; }
-
-  void set_out_path(std::string out_path, bool out_path_is_absolute) {
-    out_path_ = out_path;
-    out_path_is_absolute_ = out_path_is_absolute;
-    // Ensure that it ends with a trailing '/' (or '\' for windows machines)
-    char c = out_path_.at(out_path_.size() - 1);
-    if (!(c == '/' || c == '\\')) {
-      out_path_.push_back('/');
-    }
-  }
-
-  // Typename collision detection
-  /**
-   * Search for typename collisions
-   * @param t    the type to test for collisions
-   * @return     true if a certain collision was found, otherwise false
-   */
-  bool is_unique_typename(t_type * t) {
-    int occurances = program_typename_count(this, t);
-    for (std::vector<t_program*>::iterator it = includes_.begin();
-         it != includes_.end(); ++it) {
-      occurances += program_typename_count(*it, t);
-    }
-    return 0 == occurances;
-  }
-
-  /**
-   * Search all type collections for duplicate typenames
-   * @param prog the program to search
-   * @param t    the type to test for collisions
-   * @return     the number of certain typename collisions
-   */
-  int program_typename_count(t_program * prog, t_type * t) {
-    int occurances = 0;
-    occurances += collection_typename_count(prog, prog->typedefs_, t);
-    occurances += collection_typename_count(prog, prog->enums_, t);
-    occurances += collection_typename_count(prog, prog->objects_, t);
-    occurances += collection_typename_count(prog, prog->services_, t);
-    return occurances;
-  }
-
-  /**
-   * Search a type collection for duplicate typenames
-   * @param prog            the program to search
-   * @param type_collection the type collection to search
-   * @param t               the type to test for collisions
-   * @return                the number of certain typename collisions
-   */
-  template <class T>
-  int collection_typename_count(t_program * prog, T type_collection, t_type * t) {
-    int occurances = 0;
-    for (typename T::iterator it = type_collection.begin(); it != type_collection.end(); ++it)
-      if (t != *it && 0 == t->get_name().compare((*it)->get_name()) && is_common_namespace(prog, t))
-        ++occurances;
-    return occurances;
-  }
-
-  /**
-   * Determine whether identical typenames will collide based on namespaces.
-   *
-   * Because we do not know which languages the user will generate code for,
-   * collisions within programs (IDL files) having namespace declarations can be
-   * difficult to determine. Only guaranteed collisions return true (cause an error).
-   * Possible collisions involving explicit namespace declarations produce a warning.
-   * Other possible collisions go unreported.
-   * @param prog the program containing the preexisting typename
-   * @param t    the type containing the typename match
-   * @return     true if a collision within namespaces is found, otherwise false
-   */
-  bool is_common_namespace(t_program * prog, t_type * t) {
-    //Case 1: Typenames are in the same program [collision]
-    if (prog == t->get_program()) {
-      pwarning(1, "Duplicate typename %s found in %s",
-               t->get_name().c_str(), t->get_program()->get_name().c_str());
-      return true;
-    }
-
-    //Case 2: Both programs have identical namespace scope/name declarations [collision]
-    bool match = true;
-    for (std::map<std::string, std::string>::iterator it = prog->namespaces_.begin();
-         it != prog->namespaces_.end(); ++it) {
-      if (0 == it->second.compare(t->get_program()->get_namespace(it->first))) {
-        pwarning(1, "Duplicate typename %s found in %s,%s,%s and %s,%s,%s [file,scope,ns]",
-                 t->get_name().c_str(),
-                 t->get_program()->get_name().c_str(), it->first.c_str(), it->second.c_str(),
-                 prog->get_name().c_str(), it->first.c_str(), it->second.c_str());
-      } else {
-        match = false;
-      }
-    }
-    for (std::map<std::string, std::string>::iterator it = t->get_program()->namespaces_.begin();
-         it != t->get_program()->namespaces_.end(); ++it) {
-      if (0 == it->second.compare(prog->get_namespace(it->first))) {
-        pwarning(1, "Duplicate typename %s found in %s,%s,%s and %s,%s,%s [file,scope,ns]",
-                 t->get_name().c_str(),
-                 t->get_program()->get_name().c_str(), it->first.c_str(), it->second.c_str(),
-                 prog->get_name().c_str(), it->first.c_str(), it->second.c_str());
-      } else {
-        match = false;
-      }
-    }
-    if (0 == prog->namespaces_.size() && 0 == t->get_program()->namespaces_.size()) {
-      pwarning(1, "Duplicate typename %s found in %s and %s",
-        t->get_name().c_str(), t->get_program()->get_name().c_str(),  prog->get_name().c_str());
-    }
-    return match;
-  }
-
-  // Scoping and namespacing
-  void set_namespace(std::string name) {
-    namespace_ = name;
-  }
-
-  // Scope accessor
-  t_scope* scope() {
-    return scope_;
-  }
-
-  // Includes
-
-  void add_include(std::string path, std::string include_site) {
-    t_program* program = new t_program(path);
-
-    // include prefix for this program is the site at which it was included
-    // (minus the filename)
-    std::string include_prefix;
-    std::string::size_type last_slash = std::string::npos;
-    if ((last_slash = include_site.rfind("/")) != std::string::npos) {
-      include_prefix = include_site.substr(0, last_slash);
-    }
-
-    program->set_include_prefix(include_prefix);
-    includes_.push_back(program);
-  }
-
-  std::vector<t_program*>& get_includes() {
-    return includes_;
-  }
-
-  void set_include_prefix(std::string include_prefix) {
-    include_prefix_ = include_prefix;
-
-    // this is intended to be a directory; add a trailing slash if necessary
-    int len = include_prefix_.size();
-    if (len > 0 && include_prefix_[len - 1] != '/') {
-      include_prefix_ += '/';
-    }
-  }
-
-  // Language neutral namespace / packaging
-  void set_namespace(std::string language, std::string name_space) {
-    if (language != "*") {
-      size_t sub_index = language.find('.');
-      std::string base_language = language.substr(0, sub_index);
-      std::string sub_namespace;
-
-      if(base_language == "smalltalk") {
-        pwarning(1, "Namespace 'smalltalk' is deprecated. Use 'st' instead");
-        base_language = "st";
-      }
-
-      t_generator_registry::gen_map_t my_copy = t_generator_registry::get_generator_map();
-
-      t_generator_registry::gen_map_t::iterator it;
-      it=my_copy.find(base_language);
-
-      if (it == my_copy.end()) {
-        std::string warning = "No generator named '" + base_language + "' could be found!";
-        pwarning(1, warning.c_str());
-      } else {
-        if (sub_index != std::string::npos) {
-          std::string sub_namespace = language.substr(sub_index+1);
-          if ( ! it->second->is_valid_namespace(sub_namespace)) {
-            std::string warning = base_language + " generator does not accept '" + sub_namespace + "' as sub-namespace!";
-            pwarning(1, warning.c_str());
-          }
-        }
-      }
-    }
-
-    namespaces_[language] = name_space;
-  }
-
-  std::string get_namespace(std::string language) const {
-    std::map<std::string, std::string>::const_iterator iter;
-    if ((iter = namespaces_.find(language)) != namespaces_.end() ||
-        (iter = namespaces_.find("*"     )) != namespaces_.end()) {
-      return iter->second;
-    }
-    return std::string();
-  }
-
-  // Language specific namespace / packaging
-
-  void add_cpp_include(std::string path) {
-    cpp_includes_.push_back(path);
-  }
-
-  const std::vector<std::string>& get_cpp_includes() {
-    return cpp_includes_;
-  }
-
-  void add_c_include(std::string path) {
-    c_includes_.push_back(path);
-  }
-
-  const std::vector<std::string>& get_c_includes() {
-    return c_includes_;
-  }
-
- private:
-
-  // File path
-  std::string path_;
-
-  // Name
-  std::string name_;
-
-  // Output directory
-  std::string out_path_;
-
-  // Output directory is absolute location for generated source (no gen-*)
-  bool out_path_is_absolute_;
-
-  // Namespace
-  std::string namespace_;
-
-  // Included programs
-  std::vector<t_program*> includes_;
-
-  // Include prefix for this program, if any
-  std::string include_prefix_;
-
-  // Identifier lookup scope
-  t_scope* scope_;
-
-  // Components to generate code for
-  std::vector<t_typedef*> typedefs_;
-  std::vector<t_enum*>    enums_;
-  std::vector<t_const*>   consts_;
-  std::vector<t_struct*>  objects_;
-  std::vector<t_struct*>  structs_;
-  std::vector<t_struct*>  xceptions_;
-  std::vector<t_service*> services_;
-
-  // Dynamic namespaces
-  std::map<std::string, std::string> namespaces_;
-
-  // C++ extra includes
-  std::vector<std::string> cpp_includes_;
-
-  // C extra includes
-  std::vector<std::string> c_includes_;
-
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_scope.h b/compiler/cpp/src/parse/t_scope.h
deleted file mode 100644
index 4617bf8..0000000
--- a/compiler/cpp/src/parse/t_scope.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_SCOPE_H
-#define T_SCOPE_H
-
-#include <map>
-#include <string>
-#include <sstream>
-
-#include "t_type.h"
-#include "t_service.h"
-#include "t_const.h"
-#include "t_const_value.h"
-#include "t_base_type.h"
-#include "t_map.h"
-#include "t_list.h"
-
-/**
- * This represents a variable scope used for looking up predefined types and
- * services. Typically, a scope is associated with a t_program. Scopes are not
- * used to determine code generation, but rather to resolve identifiers at
- * parse time.
- *
- */
-class t_scope {
- public:
-  t_scope() {}
-
-  void add_type(std::string name, t_type* type) {
-    types_[name] = type;
-  }
-
-  t_type* get_type(std::string name) {
-    return types_[name];
-  }
-
-  void add_service(std::string name, t_service* service) {
-    services_[name] = service;
-  }
-
-  t_service* get_service(std::string name) {
-    return services_[name];
-  }
-
-  void add_constant(std::string name, t_const* constant) {
-    if (constants_.find(name) != constants_.end()) {
-      throw "Enum " + name + " is already defined!";
-    } else {
-      constants_[name] = constant;
-    }
-		   
-  }
-
-  t_const* get_constant(std::string name) {
-    return constants_[name];
-  }
-
-  void print() {
-    std::map<std::string, t_type*>::iterator iter;
-    for (iter = types_.begin(); iter != types_.end(); ++iter) {
-      printf("%s => %s\n",
-             iter->first.c_str(),
-             iter->second->get_name().c_str());
-    }
-  }
-
-  void resolve_const_value(t_const_value* const_val, t_type* ttype) {
-    if (ttype->is_map()) {
-      const std::map<t_const_value*, t_const_value*>& map = const_val->get_map();
-      std::map<t_const_value*, t_const_value*>::const_iterator v_iter;
-      for (v_iter = map.begin(); v_iter != map.end(); ++v_iter) {
-        resolve_const_value(v_iter->first, ((t_map*)ttype)->get_key_type());
-        resolve_const_value(v_iter->second, ((t_map*)ttype)->get_val_type());
-      }
-    } else if (ttype->is_list() || ttype->is_set()) {
-      const std::vector<t_const_value*>& val = const_val->get_list();
-      std::vector<t_const_value*>::const_iterator v_iter;
-      for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-        resolve_const_value((*v_iter), ((t_list*)ttype)->get_elem_type());
-      }
-    } else if (ttype->is_struct()) {
-      t_struct* tstruct = (t_struct*)ttype;
-      const std::map<t_const_value*, t_const_value*>& map = const_val->get_map();
-      std::map<t_const_value*, t_const_value*>::const_iterator v_iter;
-      for (v_iter = map.begin(); v_iter != map.end(); ++v_iter) {
-        t_field* field = tstruct->get_field_by_name(v_iter->first->get_string());
-        if (field == NULL) {
-          throw "No field named \"" + v_iter->first->get_string() + "\" was found in struct of type \"" + tstruct->get_name() + "\"";
-        }
-        resolve_const_value(v_iter->second, field->get_type());
-      }
-    } else if (const_val->get_type() == t_const_value::CV_IDENTIFIER) {
-      if (ttype->is_enum()) {
-        const_val->set_enum((t_enum*)ttype);
-      } else {
-        t_const* constant = get_constant(const_val->get_identifier());
-        if (constant == NULL) {
-          throw "No enum value or constant found named \"" + const_val->get_identifier() + "\"!";
-        }
-
-        // Resolve typedefs to the underlying type
-        t_type* const_type = constant->get_type()->get_true_type();
-
-        if (const_type->is_base_type()) {
-          switch (((t_base_type*)const_type)->get_base()) {
-            case t_base_type::TYPE_I16:
-            case t_base_type::TYPE_I32:
-            case t_base_type::TYPE_I64:
-            case t_base_type::TYPE_BOOL:
-            case t_base_type::TYPE_BYTE:
-              const_val->set_integer(constant->get_value()->get_integer());
-              break;
-            case t_base_type::TYPE_STRING:
-              const_val->set_string(constant->get_value()->get_string());
-              break;
-            case t_base_type::TYPE_DOUBLE:
-              const_val->set_double(constant->get_value()->get_double());
-              break;
-            case t_base_type::TYPE_VOID:
-              throw "Constants cannot be of type VOID";
-          }
-        } else if (const_type->is_map()) {
-          const std::map<t_const_value*, t_const_value*>& map = constant->get_value()->get_map();
-          std::map<t_const_value*, t_const_value*>::const_iterator v_iter;
-
-          const_val->set_map();
-          for (v_iter = map.begin(); v_iter != map.end(); ++v_iter) {
-            const_val->add_map(v_iter->first, v_iter->second);
-          }
-        } else if (const_type->is_list()) {
-          const std::vector<t_const_value*>& val = constant->get_value()->get_list();
-          std::vector<t_const_value*>::const_iterator v_iter;
-
-          const_val->set_list();
-          for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-            const_val->add_list(*v_iter);
-          }
-        }
-      }
-    } else if (ttype->is_enum()) {
-      // enum constant with non-identifier value. set the enum and find the
-      // value's name.
-      t_enum* tenum = (t_enum*)ttype;
-      t_enum_value* enum_value = tenum->get_constant_by_value(const_val->get_integer());
-      if (enum_value == NULL) {
-        std::ostringstream valstm;
-        valstm << const_val->get_integer();
-        throw "Couldn't find a named value in enum " + tenum->get_name() + " for value " + valstm.str();
-      }
-      const_val->set_identifier(tenum->get_name() + "." + enum_value->get_name());
-      const_val->set_enum(tenum);
-    }
-  }
-
- private:
-
-  // Map of names to types
-  std::map<std::string, t_type*> types_;
-
-  // Map of names to constants
-  std::map<std::string, t_const*> constants_;
-
-  // Map of names to services
-  std::map<std::string, t_service*> services_;
-
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_service.h b/compiler/cpp/src/parse/t_service.h
deleted file mode 100644
index 31e6924..0000000
--- a/compiler/cpp/src/parse/t_service.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_SERVICE_H
-#define T_SERVICE_H
-
-#include "t_function.h"
-#include <vector>
-
-class t_program;
-
-/**
- * A service consists of a set of functions.
- *
- */
-class t_service : public t_type {
- public:
-  t_service(t_program* program) :
-    t_type(program),
-    extends_(NULL) {}
-
-  bool is_service() const {
-    return true;
-  }
-
-  void set_extends(t_service* extends) {
-    extends_ = extends;
-  }
-
-  void add_function(t_function* func) {
-    std::vector<t_function*>::const_iterator iter;
-    for (iter = functions_.begin(); iter != functions_.end(); iter++) {
-      if (func->get_name() == (*iter)->get_name()) {
-        throw "Function " + func->get_name() + " is already defined";
-      }
-    }
-    functions_.push_back(func);
-  }
-
-  const std::vector<t_function*>& get_functions() const {
-    return functions_;
-  }
-
-  t_service* get_extends() {
-    return extends_;
-  }
-
-  virtual std::string get_fingerprint_material() const {
-    // Services should never be used in fingerprints.
-    throw "BUG: Can't get fingerprint material for service.";
-  }
-
- private:
-  std::vector<t_function*> functions_;
-  t_service* extends_;
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_set.h b/compiler/cpp/src/parse/t_set.h
deleted file mode 100644
index d198357..0000000
--- a/compiler/cpp/src/parse/t_set.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_SET_H
-#define T_SET_H
-
-#include "t_container.h"
-
-/**
- * A set is a lightweight container type that just wraps another data type.
- *
- */
-class t_set : public t_container {
- public:
-  t_set(t_type* elem_type) :
-    elem_type_(elem_type) {}
-
-  t_type* get_elem_type() const {
-    return elem_type_;
-  }
-
-  bool is_set() const {
-    return true;
-  }
-
-  virtual std::string get_fingerprint_material() const {
-    return "set<" + elem_type_->get_fingerprint_material() + ">";
-  }
-
-  virtual void generate_fingerprint() {
-    t_type::generate_fingerprint();
-    elem_type_->generate_fingerprint();
-  }
-
- private:
-  t_type* elem_type_;
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_struct.h b/compiler/cpp/src/parse/t_struct.h
deleted file mode 100644
index 1d03542..0000000
--- a/compiler/cpp/src/parse/t_struct.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_STRUCT_H
-#define T_STRUCT_H
-
-#include <algorithm>
-#include <vector>
-#include <utility>
-#include <string>
-
-#include "t_type.h"
-#include "t_field.h"
-
-// Forward declare that puppy
-class t_program;
-
-/**
- * A struct is a container for a set of member fields that has a name. Structs
- * are also used to implement exception types.
- *
- */
-class t_struct : public t_type {
- public:
-  typedef std::vector<t_field*> members_type;
-
-  t_struct(t_program* program) :
-    t_type(program),
-    is_xception_(false),
-    is_union_(false),
-    members_validated(false),
-    members_with_value(0),
-    xsd_all_(false) {}
-
-  t_struct(t_program* program, const std::string& name) :
-    t_type(program, name),
-    is_xception_(false),
-    is_union_(false),
-    members_validated(false),
-    members_with_value(0),
-    xsd_all_(false) {}
-
-  void set_name(const std::string& name) {
-    name_ = name;
-    validate_union_members();
-  }
-
-  void set_xception(bool is_xception) {
-    is_xception_ = is_xception;
-  }
-
-  void validate_union_member( t_field * field) {
-    if( is_union_ && (! name_.empty())) {
-
-      // unions can't have required fields
-      if( field->get_req() == t_field::T_REQUIRED) {
-        pwarning(  1, "Required field %s of union %s set to optional.\n", field->get_name().c_str(), name_.c_str());
-        field->set_req( t_field::T_OPTIONAL);
-      }
-
-      // unions may have up to one member defaulted, but not more
-      if( field->get_value() != NULL) {
-        if( 1 < ++members_with_value) {
-          throw "Error: Field "+field->get_name()+" provides another default value for union "+name_;
-        }
-      }
-    }
-    
-  }
-
-  void validate_union_members() {
-    if( is_union_ && (! name_.empty()) && (!members_validated)) {
-      members_type::const_iterator m_iter;
-      for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) {
-        validate_union_member( *m_iter);
-      }
-      members_validated = true;          
-    }
-  }
-
-  void set_union(bool is_union) {
-    is_union_ = is_union;
-    validate_union_members();
-  }
-
-  void set_xsd_all(bool xsd_all) {
-    xsd_all_ = xsd_all;
-  }
-
-  bool get_xsd_all() const {
-    return xsd_all_;
-  }
-
-  bool append(t_field* elem) {
-    typedef members_type::iterator iter_type;
-    std::pair<iter_type, iter_type> bounds = std::equal_range(
-            members_in_id_order_.begin(), members_in_id_order_.end(), elem, t_field::key_compare()
-        );
-    if (bounds.first != bounds.second) {
-      return false;
-    }
-    // returns false when there is a conflict of field names
-    if (get_field_by_name(elem->get_name()) != NULL) {
-      return false; 
-    }
-    members_.push_back(elem);
-    members_in_id_order_.insert(bounds.second, elem);
-    validate_union_member( elem);
-    return true;
-  }
-
-  const members_type& get_members() {
-    return members_;
-  }
-
-  const members_type& get_sorted_members() {
-    return members_in_id_order_;
-  }
-
-  bool is_struct() const {
-    return !is_xception_;
-  }
-
-  bool is_xception() const {
-    return is_xception_;
-  }
-  
-  bool is_union() const {
-    return is_union_;
-  }
-
-  virtual std::string get_fingerprint_material() const {
-    std::string rv = "{";
-    members_type::const_iterator m_iter;
-    for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) {
-      rv += (*m_iter)->get_fingerprint_material();
-      rv += ";";
-    }
-    rv += "}";
-    return rv;
-  }
-
-  virtual void generate_fingerprint() {
-    t_type::generate_fingerprint();
-    members_type::const_iterator m_iter;
-    for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) {
-      (*m_iter)->get_type()->generate_fingerprint();
-    }
-  }
-
-  t_field* get_field_by_name(std::string field_name) {
-    members_type::const_iterator m_iter;
-    for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) {
-      if ((*m_iter)->get_name() == field_name) {
-        return *m_iter;
-      }
-    }
-    return NULL;
-  }
-
- private:
-
-  members_type members_;
-  members_type members_in_id_order_;
-  bool is_xception_;
-  bool is_union_;
-  bool members_validated;
-  int  members_with_value;
-
-  bool xsd_all_;
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_type.h b/compiler/cpp/src/parse/t_type.h
deleted file mode 100644
index f024279..0000000
--- a/compiler/cpp/src/parse/t_type.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_TYPE_H
-#define T_TYPE_H
-
-#include <string>
-#include <map>
-#include <cstring>
-#include <stdint.h>
-#include "t_doc.h"
-
-class t_program;
-
-/**
- * Generic representation of a thrift type. These objects are used by the
- * parser module to build up a tree of object that are all explicitly typed.
- * The generic t_type class exports a variety of useful methods that are
- * used by the code generator to branch based upon different handling for the
- * various types.
- *
- */
-class t_type : public t_doc {
- public:
-  virtual ~t_type() {}
-
-  virtual void set_name(const std::string& name) {
-    name_ = name;
-  }
-
-  virtual const std::string& get_name() const {
-    return name_;
-  }
-
-  virtual bool is_void()      const { return false; }
-  virtual bool is_base_type() const { return false; }
-  virtual bool is_string()    const { return false; }
-  virtual bool is_bool()      const { return false; }
-  virtual bool is_typedef()   const { return false; }
-  virtual bool is_enum()      const { return false; }
-  virtual bool is_struct()    const { return false; }
-  virtual bool is_xception()  const { return false; }
-  virtual bool is_container() const { return false; }
-  virtual bool is_list()      const { return false; }
-  virtual bool is_set()       const { return false; }
-  virtual bool is_map()       const { return false; }
-  virtual bool is_service()   const { return false; }
-
-  t_program* get_program() {
-    return program_;
-  }
-
-  t_type* get_true_type();
-
-  // Return a string that uniquely identifies this type
-  // from any other thrift type in the world, as far as
-  // TDenseProtocol is concerned.
-  // We don't cache this, which is a little sloppy,
-  // but the compiler is so fast that it doesn't really matter.
-  virtual std::string get_fingerprint_material() const = 0;
-
-  // Fingerprint should change whenever (and only when)
-  // the encoding via TDenseProtocol changes.
-  static const int fingerprint_len = 16;
-
-  // Call this before trying get_*_fingerprint().
-  virtual void generate_fingerprint();
-
-  bool has_fingerprint() const {
-    for (int i = 0; i < fingerprint_len; i++) {
-      if (fingerprint_[i] != 0) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  const uint8_t* get_binary_fingerprint() const {
-    return fingerprint_;
-  }
-
-  std::string get_ascii_fingerprint() const {
-    std::string rv;
-    const uint8_t* fp = get_binary_fingerprint();
-    for (int i = 0; i < fingerprint_len; i++) {
-      rv += byte_to_hex(fp[i]);
-    }
-    return rv;
-  }
-
-  // This function will break (maybe badly) unless 0 <= num <= 16.
-  static char nybble_to_xdigit(int num) {
-    if (num < 10) {
-      return '0' + num;
-    } else {
-      return 'A' + num - 10;
-    }
-  }
-
-  static std::string byte_to_hex(uint8_t byte) {
-    std::string rv;
-    rv += nybble_to_xdigit(byte >> 4);
-    rv += nybble_to_xdigit(byte & 0x0f);
-    return rv;
-  }
-
-  std::map<std::string, std::string> annotations_;
-
- protected:
-  t_type() :
-    program_(NULL)
-  {
-    memset(fingerprint_, 0, sizeof(fingerprint_));
-  }
-
-  t_type(t_program* program) :
-    program_(program)
-  {
-    memset(fingerprint_, 0, sizeof(fingerprint_));
-  }
-
-  t_type(t_program* program, std::string name) :
-    program_(program),
-    name_(name)
-  {
-    memset(fingerprint_, 0, sizeof(fingerprint_));
-  }
-
-  t_type(std::string name) :
-    program_(NULL),
-    name_(name)
-  {
-    memset(fingerprint_, 0, sizeof(fingerprint_));
-  }
-
-  t_program* program_;
-  std::string name_;
-
-  uint8_t fingerprint_[fingerprint_len];
-};
-
-
-/**
- * Placeholder struct for returning the key and value of an annotation
- * during parsing.
- */
-struct t_annotation {
-  std::string key;
-  std::string val;
-};
-
-#endif
diff --git a/compiler/cpp/src/parse/t_typedef.h b/compiler/cpp/src/parse/t_typedef.h
deleted file mode 100644
index 4c77d97..0000000
--- a/compiler/cpp/src/parse/t_typedef.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef T_TYPEDEF_H
-#define T_TYPEDEF_H
-
-#include <string>
-#include "t_type.h"
-
-/**
- * A typedef is a mapping from a symbolic name to another type. In dymanically
- * typed languages (i.e. php/python) the code generator can actually usually
- * ignore typedefs and just use the underlying type directly, though in C++
- * the symbolic naming can be quite useful for code clarity.
- *
- */
-class t_typedef : public t_type {
- public:
-  t_typedef(t_program* program, t_type* type, std::string symbolic) :
-    t_type(program, symbolic),
-    type_(type),
-    symbolic_(symbolic) {}
-
-  ~t_typedef() {}
-
-  t_type* get_type() const {
-    return type_;
-  }
-
-  const std::string& get_symbolic() const {
-    return symbolic_;
-  }
-
-  bool is_typedef() const {
-    return true;
-  }
-
-  virtual std::string get_fingerprint_material() const {
-    return type_->get_fingerprint_material();
-  }
-
-  virtual void generate_fingerprint() {
-    t_type::generate_fingerprint();
-    if (!type_->has_fingerprint()) {
-      type_->generate_fingerprint();
-    }
-  }
-
- private:
-  t_type* type_;
-  std::string symbolic_;
-};
-
-#endif
diff --git a/compiler/cpp/src/platform.h b/compiler/cpp/src/platform.h
deleted file mode 100644
index 04f04c7..0000000
--- a/compiler/cpp/src/platform.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * define for mkdir,since the method signature
- * is different for the non-POSIX MinGW
- */
-
-#ifdef MINGW
-#include <direct.h>
-#include <io.h>
-#else
-#include <sys/types.h>
-#include <sys/stat.h>
-#endif
-
-#if defined MINGW
-#define MKDIR(x) mkdir(x)
-#else
-#define MKDIR(x) mkdir(x, S_IRWXU | S_IRWXG | S_IRWXO)
-#endif
diff --git a/compiler/cpp/src/thrift/audit/t_audit.cpp b/compiler/cpp/src/thrift/audit/t_audit.cpp
new file mode 100644
index 0000000..ef39d60
--- /dev/null
+++ b/compiler/cpp/src/thrift/audit/t_audit.cpp
@@ -0,0 +1,464 @@
+
+#include <cassert>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string>
+#include <algorithm>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+
+// Careful: must include globals first for extern definitions
+#include "thrift/globals.h"
+
+#include "thrift/parse/t_program.h"
+#include "thrift/parse/t_scope.h"
+#include "thrift/parse/t_const.h"
+#include "thrift/parse/t_field.h"
+
+#include "thrift/version.h"
+
+#include "thrift/audit/t_audit.h"
+
+extern int g_warn;
+extern std::string g_curpath;
+extern bool g_return_failure;
+
+void thrift_audit_warning(int level, const char* fmt, ...) {
+   if (g_warn < level) {
+      return;
+   }
+   va_list args;
+   printf("[Thrift Audit Warning:%s] ", g_curpath.c_str());
+   va_start(args, fmt);
+   vprintf(fmt, args);
+   va_end(args);
+   printf("\n");
+}
+
+void thrift_audit_failure(const char* fmt, ...) {
+  va_list args;
+  fprintf(stderr, "[Thrift Audit Failure:%s] ", g_curpath.c_str());
+  va_start(args, fmt);
+  vfprintf(stderr, fmt, args);
+  va_end(args);
+  fprintf(stderr, "\n");
+  g_return_failure = true;
+}
+
+void compare_namespace(t_program* newProgram, t_program* oldProgram)
+{
+   const std::map<std::string, std::string>& newNamespaceMap = newProgram->get_all_namespaces();
+   const std::map<std::string, std::string>& oldNamespaceMap = oldProgram->get_all_namespaces();
+
+   for(std::map<std::string, std::string>::const_iterator oldNamespaceMapIt = oldNamespaceMap.begin();
+         oldNamespaceMapIt != oldNamespaceMap.end();
+         oldNamespaceMapIt++)
+   {
+      std::map<std::string, std::string>::const_iterator newNamespaceMapIt = newNamespaceMap.find(oldNamespaceMapIt->first);
+      if(newNamespaceMapIt == newNamespaceMap.end())
+      {
+         thrift_audit_warning(1, "Language %s not found in new thrift file\n", (oldNamespaceMapIt->first).c_str());
+      }
+      else if((newNamespaceMapIt->second) != oldNamespaceMapIt->second)
+      {
+         thrift_audit_warning(1, "Namespace %s changed in new thrift file\n", (oldNamespaceMapIt->second).c_str());
+      }
+   }
+}
+
+void compare_enum_values(t_enum* newEnum,t_enum* oldEnum)
+{
+   const std::vector<t_enum_value*>& oldEnumValues = oldEnum->get_constants();
+   for(std::vector<t_enum_value*>::const_iterator oldEnumValuesIt = oldEnumValues.begin();
+         oldEnumValuesIt != oldEnumValues.end();
+         oldEnumValuesIt++)
+   {
+      int enumValue = (*oldEnumValuesIt)->get_value();
+      t_enum_value* newEnumValue = newEnum->get_constant_by_value(enumValue);
+      if(newEnumValue != NULL)
+      {
+         std::string enumName = (*oldEnumValuesIt)->get_name();
+         if(enumName != newEnumValue->get_name())
+         {
+            thrift_audit_warning(1, "Name of the value %d changed in enum %s\n", enumValue, oldEnum->get_name().c_str());
+         }
+      }
+      else
+      {
+         thrift_audit_failure("Enum value %d missing in %s\n", enumValue, oldEnum->get_name().c_str());
+      }
+
+   }
+}
+
+void compare_enums(const std::vector<t_enum*>& newEnumList, const std::vector<t_enum*>& oldEnumList)
+{
+   std::map<std::string,t_enum*> newEnumMap;
+   std::vector<t_enum*>::const_iterator newEnumIt;
+   for(newEnumIt = newEnumList.begin(); newEnumIt != newEnumList.end(); newEnumIt++)
+   {
+      newEnumMap[(*newEnumIt)->get_name()] = *newEnumIt;
+   }
+   std::vector<t_enum*>::const_iterator oldEnumIt;
+   for(oldEnumIt = oldEnumList.begin(); oldEnumIt != oldEnumList.end(); oldEnumIt++)
+   {
+      std::map<std::string,t_enum*>::iterator newEnumMapIt;
+      newEnumMapIt = newEnumMap.find((*oldEnumIt)->get_name());
+
+      if(newEnumMapIt == newEnumMap.end())
+      {
+         thrift_audit_warning(1, "Enum %s not found in new thrift file\n",(*oldEnumIt)->get_name().c_str());
+      }
+      else
+      {
+         compare_enum_values(newEnumMapIt->second, *oldEnumIt);
+      }
+   }
+}
+
+//This function returns 'true' if the two arguements are of same types.
+//Returns false if they are of different type
+bool compare_type(t_type* newType, t_type* oldType)
+{
+   //Comparing names of two types will work when the newType and oldType are basic types or structs or enums.
+   //However, when they are containers, get_name() returns empty for which we have to compare the type of
+   //their elements as well.
+   if((newType->get_name()).empty() && (oldType->get_name()).empty())
+   {
+
+      if(newType->is_list() && oldType->is_list())
+      {
+         t_type* newElementType = ((t_list*)newType)->get_elem_type();
+         t_type* oldElementType = ((t_list*)oldType)->get_elem_type();
+         return compare_type(newElementType, oldElementType);
+      }
+      else if(newType->is_map() && oldType->is_map())
+      {
+         t_type* newKeyType = ((t_map*)newType)->get_key_type();
+         t_type* oldKeyType = ((t_map*)oldType)->get_key_type();
+
+         t_type* newValType = ((t_map*)newType)->get_val_type();
+         t_type* oldValType = ((t_map*)oldType)->get_val_type();
+
+         return (compare_type(newKeyType, oldKeyType) && compare_type(newValType, oldValType));
+      }
+      else if(newType->is_set() && oldType->is_set())
+      {
+         t_type* newElementType = ((t_set*)newType)->get_elem_type();
+         t_type* oldElementType = ((t_set*)oldType)->get_elem_type();
+         return compare_type(newElementType, oldElementType);
+      }
+      else
+      {
+         return false;
+      }
+   }
+   else if(newType->get_name() == oldType->get_name())
+   {
+      return true;
+   }
+   else
+   {
+      return false;
+   }
+}
+
+bool compare_pair(std::pair<t_const_value*, t_const_value*> newMapPair, std::pair<t_const_value*, t_const_value*> oldMapPair)
+{
+   return compare_defaults(newMapPair.first, oldMapPair.first) && compare_defaults(newMapPair.second, oldMapPair.second);
+}
+
+// This function returns 'true' if the default values are same. Returns false if they are different.
+bool compare_defaults(t_const_value* newStructDefault, t_const_value* oldStructDefault)
+{
+   if(newStructDefault == NULL && oldStructDefault == NULL) return true;
+   else if(newStructDefault == NULL && oldStructDefault != NULL) return false;
+   else if (newStructDefault != NULL && oldStructDefault == NULL) return false;
+
+   if(newStructDefault->get_type() != oldStructDefault->get_type())
+   {
+      return false;
+   }
+
+   switch(newStructDefault->get_type())
+   {
+      case t_const_value::CV_INTEGER:
+         return (newStructDefault->get_integer() == oldStructDefault->get_integer());
+      case t_const_value::CV_DOUBLE:
+         return (newStructDefault->get_double() == oldStructDefault->get_double());
+      case t_const_value::CV_STRING:
+         return (newStructDefault->get_string() == oldStructDefault->get_string());
+      case t_const_value::CV_LIST:
+         {
+            const std::vector<t_const_value*>& oldDefaultList = oldStructDefault->get_list();
+            const std::vector<t_const_value*>& newDefaultList = newStructDefault->get_list();
+            bool defaultValuesCompare = (oldDefaultList.size() == newDefaultList.size());
+
+            return defaultValuesCompare && std::equal(newDefaultList.begin(), newDefaultList.end(), oldDefaultList.begin(), compare_defaults);
+         }
+      case t_const_value::CV_MAP:
+         {
+            const std::map<t_const_value*, t_const_value*, t_const_value::value_compare> newMap = newStructDefault->get_map();
+            const std::map<t_const_value*, t_const_value*, t_const_value::value_compare> oldMap = oldStructDefault->get_map();
+
+            bool defaultValuesCompare = (oldMap.size() == newMap.size());
+
+            return defaultValuesCompare && std::equal(newMap.begin(), newMap.end(), oldMap.begin(), compare_pair);
+         }
+      case t_const_value::CV_IDENTIFIER:
+         return (newStructDefault->get_identifier() == oldStructDefault->get_identifier());
+      default:
+         return false;
+   }
+
+}
+
+void compare_struct_field(t_field* newField, t_field* oldField, std::string oldStructName)
+{
+   t_type* newFieldType = newField->get_type();
+   t_type* oldFieldType = oldField->get_type();
+   if(!compare_type(newFieldType, oldFieldType))
+   {
+      thrift_audit_failure("Struct Field Type Changed for Id = %d in %s \n", newField->get_key(), oldStructName.c_str());
+   }
+
+   // A Struct member can be optional if it is mentioned explicitly, or if it is assigned with default values.
+   bool newStructFieldOptional = (newField->get_req() != t_field::T_REQUIRED);
+   bool oldStructFieldOptional = (oldField->get_req() != t_field::T_REQUIRED);
+
+   if(newStructFieldOptional != oldStructFieldOptional)
+   {
+      thrift_audit_failure("Struct Field Requiredness Changed for Id = %d in %s \n", newField->get_key(), oldStructName.c_str());
+   }
+   if(newStructFieldOptional || oldStructFieldOptional)
+   {
+      if(!compare_defaults(newField->get_value(), oldField->get_value()))
+      {
+         thrift_audit_warning(1, "Default value changed for Id = %d in %s \n", newField->get_key(), oldStructName.c_str());
+      }
+   }
+
+   std::string fieldName = newField->get_name();
+   if(fieldName != oldField->get_name())
+   {
+      thrift_audit_warning(1, "Struct field name changed for Id = %d in %s\n", newField->get_key(), oldStructName.c_str());
+   }
+
+}
+
+void compare_single_struct(t_struct* newStruct, t_struct* oldStruct, const std::string& oldStructName = std::string())
+{
+   std::string structName = oldStructName.empty() ? oldStruct->get_name() : oldStructName;
+   const std::vector<t_field*>& oldStructMembersInIdOrder = oldStruct->get_sorted_members();
+   const std::vector<t_field*>& newStructMembersInIdOrder = newStruct->get_sorted_members();
+   std::vector<t_field*>::const_iterator oldStructMemberIt = oldStructMembersInIdOrder.begin();
+   std::vector<t_field*>::const_iterator newStructMemberIt = newStructMembersInIdOrder.begin();
+
+   // Since we have the struct members in their ID order, comparing their IDs can be done by traversing the two member
+   // lists together.
+   while(!(oldStructMemberIt == oldStructMembersInIdOrder.end() && newStructMemberIt == newStructMembersInIdOrder.end()))
+   {
+      if(newStructMemberIt == newStructMembersInIdOrder.end() && oldStructMemberIt != oldStructMembersInIdOrder.end())
+      {
+         // A field ID has been removed from the end.
+         thrift_audit_failure("Struct Field removed for Id = %d in %s \n", (*oldStructMemberIt)->get_key(), structName.c_str());
+         oldStructMemberIt++;
+      }
+      else if(newStructMemberIt != newStructMembersInIdOrder.end() && oldStructMemberIt == oldStructMembersInIdOrder.end())
+      {
+         //New field ID has been added to the end.
+         if((*newStructMemberIt)->get_req() == t_field::T_REQUIRED)
+         {
+            thrift_audit_failure("Required Struct Field Added for Id = %d in %s \n", (*newStructMemberIt)->get_key(), structName.c_str());
+         }
+         newStructMemberIt++;
+      }
+      else if((*newStructMemberIt)->get_key() == (*oldStructMemberIt)->get_key())
+      {
+         //Field ID found in both structs. Compare field types, default values.
+         compare_struct_field(*newStructMemberIt, *oldStructMemberIt, structName);
+
+         newStructMemberIt++;
+         oldStructMemberIt++;
+      }
+      else if((*newStructMemberIt)->get_key() < (*oldStructMemberIt)->get_key())
+      {
+         //New Field Id is inserted in between
+         //Adding fields to struct is fine, but adding them in the middle is suspicious. Error!!
+         thrift_audit_failure("Struct field is added in the middle with Id = %d in %s\n",  (*newStructMemberIt)->get_key(),  structName.c_str());
+         newStructMemberIt++;
+      }
+      else if((*newStructMemberIt)->get_key() > (*oldStructMemberIt)->get_key())
+      {
+         //A field is deleted in newStruct.
+         thrift_audit_failure("Struct Field removed for Id = %d in %s \n",  (*oldStructMemberIt)->get_key(), structName.c_str());
+         oldStructMemberIt++;
+      }
+
+   }
+}
+
+void compare_structs(const std::vector<t_struct*>& newStructList, const std::vector<t_struct*>& oldStructList)
+{
+   std::map<std::string,t_struct*> newStructMap;
+   std::vector<t_struct*>::const_iterator newStructListIt;
+   for(newStructListIt = newStructList.begin(); newStructListIt != newStructList.end(); newStructListIt++)
+   {
+      newStructMap[(*newStructListIt)->get_name()] = *newStructListIt;
+   }
+
+   std::vector<t_struct*>::const_iterator oldStructListIt;
+   for(oldStructListIt = oldStructList.begin(); oldStructListIt != oldStructList.end(); oldStructListIt++)
+   {
+      std::map<std::string, t_struct*>::iterator newStructMapIt;
+      newStructMapIt = newStructMap.find((*oldStructListIt)->get_name());
+      if(newStructMapIt == newStructMap.end())
+      {
+         thrift_audit_failure("Struct %s not found in new thrift file\n", (*oldStructListIt)->get_name().c_str());
+      }
+      else
+      {
+         compare_single_struct(newStructMapIt->second, *oldStructListIt);
+      }
+   }
+
+}
+
+void compare_single_function(t_function* newFunction, t_function* oldFunction)
+{
+   t_type* newFunctionReturnType = newFunction->get_returntype();
+
+   if(newFunction->is_oneway() != oldFunction->is_oneway())
+   {
+      thrift_audit_failure("Oneway attribute changed for function %s\n",oldFunction->get_name().c_str());
+   }
+   if(!compare_type(newFunctionReturnType, oldFunction->get_returntype()))
+   {
+      thrift_audit_failure("Return type changed for function %s\n",oldFunction->get_name().c_str());
+   }
+
+   //Compare function arguments.
+   compare_single_struct(newFunction->get_arglist(), oldFunction->get_arglist());
+   std::string exceptionName = oldFunction->get_name();
+   exceptionName += "_exception";
+   compare_single_struct(newFunction->get_xceptions(), oldFunction->get_xceptions(), exceptionName);
+}
+
+void compare_functions(const std::vector<t_function*>& newFunctionList, const std::vector<t_function*>& oldFunctionList)
+{
+   std::map<std::string, t_function*> newFunctionMap;
+   std::map<std::string, t_function*>::iterator newFunctionMapIt;
+   for(std::vector<t_function*>::const_iterator newFunctionIt = newFunctionList.begin();
+         newFunctionIt != newFunctionList.end();
+         newFunctionIt++)
+   {
+      newFunctionMap[(*newFunctionIt)->get_name()] = *newFunctionIt;
+   }
+
+   for(std::vector<t_function*>::const_iterator oldFunctionIt = oldFunctionList.begin();
+         oldFunctionIt != oldFunctionList.end();
+         oldFunctionIt++)
+   {
+      newFunctionMapIt = newFunctionMap.find((*oldFunctionIt)->get_name());
+      if(newFunctionMapIt == newFunctionMap.end())
+      {
+         thrift_audit_failure("New Thrift File has missing function %s\n",(*oldFunctionIt)->get_name().c_str());
+         continue;
+      }
+      else
+      {
+         //Function is found in both thrift files. Compare return type and argument list
+         compare_single_function(newFunctionMapIt->second, *oldFunctionIt);
+      }
+   }
+
+}
+
+void compare_services(const std::vector<t_service*>& newServices, const std::vector<t_service*>& oldServices)
+{
+   std::vector<t_service*>::const_iterator oldServiceIt;
+
+   std::map<std::string, t_service*> newServiceMap;
+   for(std::vector<t_service*>::const_iterator newServiceIt = newServices.begin();
+         newServiceIt != newServices.end();
+         newServiceIt++)
+   {
+      newServiceMap[(*newServiceIt)->get_name()] = *newServiceIt;
+   }
+
+
+   for(oldServiceIt = oldServices.begin(); oldServiceIt != oldServices.end(); oldServiceIt++)
+   {
+      const std::string oldServiceName = (*oldServiceIt)->get_name();
+      std::map<std::string, t_service*>::iterator newServiceMapIt = newServiceMap.find(oldServiceName);
+
+      if(newServiceMapIt == newServiceMap.end())
+      {
+         thrift_audit_failure("New Thrift file is missing a service %s\n", oldServiceName.c_str());
+      }
+      else
+      {
+         t_service* oldServiceExtends = (*oldServiceIt)->get_extends();
+         t_service* newServiceExtends = (newServiceMapIt->second)->get_extends();
+
+         if(oldServiceExtends == NULL)
+         {
+            // It is fine to add extends. So if service in older thrift did not have any extends, we are fine.
+            // DO Nothing
+         }
+         else if(oldServiceExtends != NULL && newServiceExtends == NULL)
+         {
+            thrift_audit_failure("Change in Service inheritance for %s\n", oldServiceName.c_str());
+         }
+         else
+         {
+            std::string oldExtendsName = oldServiceExtends->get_name();
+            std::string newExtendsName = newServiceExtends->get_name();
+
+            if( newExtendsName != oldExtendsName)
+            {
+               thrift_audit_failure("Change in Service inheritance for %s\n", oldServiceName.c_str());
+            }
+         }
+
+         compare_functions((newServiceMapIt->second)->get_functions(), (*oldServiceIt)->get_functions());
+      }
+
+   }
+
+}
+
+void compare_consts(const std::vector<t_const*>& newConst, const std::vector<t_const*>& oldConst)
+{
+   std::vector<t_const*>::const_iterator newConstIt;
+   std::vector<t_const*>::const_iterator oldConstIt;
+
+   std::map<std::string, t_const*> newConstMap;
+
+   for(newConstIt = newConst.begin(); newConstIt != newConst.end(); newConstIt++)
+   {
+      newConstMap[(*newConstIt)->get_name()] = *newConstIt;
+   }
+
+   std::map<std::string, t_const*>::const_iterator newConstMapIt;
+   for(oldConstIt = oldConst.begin(); oldConstIt != oldConst.end(); oldConstIt++)
+   {
+      newConstMapIt = newConstMap.find((*oldConstIt)->get_name());
+      if(newConstMapIt == newConstMap.end())
+      {
+         thrift_audit_warning(1, "Constants Missing %s \n", ((*oldConstIt)->get_name()).c_str());
+      }
+      else if(!compare_type((newConstMapIt->second)->get_type(), (*oldConstIt)->get_type()))
+      {
+         thrift_audit_warning(1, "Constant %s is of different type \n", ((*oldConstIt)->get_name()).c_str());
+      }
+      else if(!compare_defaults((newConstMapIt->second)->get_value(), (*oldConstIt)->get_value()))
+      {
+         thrift_audit_warning(1, "Constant %s has different value\n", ((*oldConstIt)->get_name()).c_str());
+      }
+   }
+}
diff --git a/compiler/cpp/src/thrift/audit/t_audit.h b/compiler/cpp/src/thrift/audit/t_audit.h
new file mode 100644
index 0000000..be79e31
--- /dev/null
+++ b/compiler/cpp/src/thrift/audit/t_audit.h
@@ -0,0 +1,14 @@
+#ifndef T_AUDIT_H
+#define T_AUDIT_H
+
+void compare_namespace(t_program* newProgram, t_program* oldProgram);
+void compare_enums(const std::vector<t_enum*>& newEnumList,
+                   const std::vector<t_enum*>& oldEnumList);
+bool compare_defaults(t_const_value* newStructDefault, t_const_value* oldStructDefault);
+void compare_structs(const std::vector<t_struct*>& newStructList,
+                     const std::vector<t_struct*>& oldStructList);
+void compare_services(const std::vector<t_service*>& newServices,
+                      const std::vector<t_service*>& oldServices);
+void compare_consts(const std::vector<t_const*>& newConst, const std::vector<t_const*>& oldConst);
+
+#endif
diff --git a/compiler/cpp/src/thrift/common.cc b/compiler/cpp/src/thrift/common.cc
new file mode 100644
index 0000000..3a2b9d3
--- /dev/null
+++ b/compiler/cpp/src/thrift/common.cc
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "thrift/common.h"
+#include "thrift/parse/t_base_type.h"
+
+t_type* g_type_void;
+t_type* g_type_string;
+t_type* g_type_binary;
+t_type* g_type_slist;
+t_type* g_type_bool;
+t_type* g_type_i8;
+t_type* g_type_i16;
+t_type* g_type_i32;
+t_type* g_type_i64;
+t_type* g_type_double;
+
+void initGlobals() {
+  g_type_void = new t_base_type("void", t_base_type::TYPE_VOID);
+  g_type_string = new t_base_type("string", t_base_type::TYPE_STRING);
+  g_type_binary = new t_base_type("string", t_base_type::TYPE_STRING);
+  ((t_base_type*)g_type_binary)->set_binary(true);
+  g_type_slist = new t_base_type("string", t_base_type::TYPE_STRING);
+  ((t_base_type*)g_type_slist)->set_string_list(true);
+  g_type_bool = new t_base_type("bool", t_base_type::TYPE_BOOL);
+  g_type_i8 = new t_base_type("i8", t_base_type::TYPE_I8);
+  g_type_i16 = new t_base_type("i16", t_base_type::TYPE_I16);
+  g_type_i32 = new t_base_type("i32", t_base_type::TYPE_I32);
+  g_type_i64 = new t_base_type("i64", t_base_type::TYPE_I64);
+  g_type_double = new t_base_type("double", t_base_type::TYPE_DOUBLE);
+}
+
+void clearGlobals() {
+  delete g_type_void;
+  delete g_type_string;
+  delete g_type_bool;
+  delete g_type_i8;
+  delete g_type_i16;
+  delete g_type_i32;
+  delete g_type_i64;
+  delete g_type_double;
+}
+
+/**
+ * Those are not really needed for plugins but causes link errors without
+ */
+
+/**
+ * The location of the last parsed doctext comment.
+ */
+int g_doctext_lineno;
+int g_program_doctext_lineno = 0;
+PROGDOCTEXT_STATUS g_program_doctext_status = INVALID;
diff --git a/compiler/cpp/src/thrift/common.h b/compiler/cpp/src/thrift/common.h
new file mode 100644
index 0000000..6948846
--- /dev/null
+++ b/compiler/cpp/src/thrift/common.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef T_COMMON_H
+#define T_COMMON_H
+
+#include "thrift/parse/t_type.h"
+
+/**
+ * Global types for the parser to be able to reference
+ */
+
+extern t_type* g_type_void;
+extern t_type* g_type_string;
+extern t_type* g_type_binary;
+extern t_type* g_type_slist;
+extern t_type* g_type_bool;
+extern t_type* g_type_i8;
+extern t_type* g_type_i16;
+extern t_type* g_type_i32;
+extern t_type* g_type_i64;
+extern t_type* g_type_double;
+
+void initGlobals();
+void clearGlobals();
+
+#endif
diff --git a/compiler/cpp/src/thrift/generate/t_as3_generator.cc b/compiler/cpp/src/thrift/generate/t_as3_generator.cc
new file mode 100644
index 0000000..41724fe
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_as3_generator.cc
@@ -0,0 +1,2594 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <cctype>
+
+#include <sys/stat.h>
+#include <stdexcept>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * AS3 code generator.
+ *
+ */
+class t_as3_generator : public t_oop_generator {
+public:
+  t_as3_generator(t_program* program,
+                  const std::map<std::string, std::string>& parsed_options,
+                  const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    bindable_ = false;
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("bindable") == 0) {
+        bindable_ = true;
+      } else {
+        throw "unknown option as3:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-as3";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  void generate_consts(std::vector<t_const*> consts);
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_struct(t_struct* tstruct);
+  void generate_xception(t_struct* txception);
+  void generate_service(t_service* tservice);
+
+  void print_const_value(std::ostream& out,
+                         std::string name,
+                         t_type* type,
+                         t_const_value* value,
+                         bool in_static,
+                         bool defval = false);
+  std::string render_const_value(ostream& out,
+                                 std::string name,
+                                 t_type* type,
+                                 t_const_value* value);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_as3_struct(t_struct* tstruct, bool is_exception);
+
+  void generate_as3_struct_definition(std::ostream& out,
+                                      t_struct* tstruct,
+                                      bool is_xception = false,
+                                      bool in_class = false,
+                                      bool is_result = false);
+  // removed -- equality,compare_to
+  void generate_as3_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_as3_validator(std::ostream& out, t_struct* tstruct);
+  void generate_as3_struct_result_writer(std::ostream& out, t_struct* tstruct);
+  void generate_as3_struct_writer(std::ostream& out, t_struct* tstruct);
+  void generate_as3_struct_tostring(std::ostream& out, t_struct* tstruct, bool bindable);
+  void generate_as3_meta_data_map(std::ostream& out, t_struct* tstruct);
+  void generate_field_value_meta_data(std::ostream& out, t_type* type);
+  std::string get_as3_type_string(t_type* type);
+  void generate_reflection_setters(std::ostringstream& out,
+                                   t_type* type,
+                                   std::string field_name,
+                                   std::string cap_name);
+  void generate_reflection_getters(std::ostringstream& out,
+                                   t_type* type,
+                                   std::string field_name,
+                                   std::string cap_name);
+  void generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct);
+  void generate_generic_isset_method(std::ostream& out, t_struct* tstruct);
+  void generate_as3_bean_boilerplate(std::ostream& out, t_struct* tstruct, bool bindable);
+
+  void generate_function_helpers(t_function* tfunction);
+  std::string get_cap_name(std::string name);
+  std::string generate_isset_check(t_field* field);
+  std::string generate_isset_check(std::string field);
+  void generate_isset_set(ostream& out, t_field* field);
+  // removed std::string isset_field_id(t_field* field);
+
+  void generate_service_interface(t_service* tservice);
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_client(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::ostream& out, t_field* tfield, std::string prefix = "");
+
+  void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+
+  void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         std::string prefix = "");
+
+  void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
+
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string iter,
+                                      std::string map);
+
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  void generate_as3_doc(std::ostream& out, t_doc* tdoc);
+
+  void generate_as3_doc(std::ostream& out, t_function* tdoc);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string as3_package();
+  std::string as3_type_imports();
+  std::string as3_thrift_imports();
+  std::string as3_thrift_gen_imports(t_struct* tstruct, string& imports);
+  std::string as3_thrift_gen_imports(t_service* tservice);
+  std::string type_name(t_type* ttype, bool in_container = false, bool in_init = false);
+  std::string base_type_name(t_base_type* tbase, bool in_container = false);
+  std::string declare_field(t_field* tfield, bool init = false);
+  std::string function_signature(t_function* tfunction, std::string prefix = "");
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string get_enum_class_name(t_type* type);
+
+  bool type_can_be_null(t_type* ttype) {
+    ttype = get_true_type(ttype);
+
+    return ttype->is_container() || ttype->is_struct() || ttype->is_xception()
+           || ttype->is_string();
+  }
+
+  std::string constant_name(std::string name);
+
+private:
+  /**
+   * File streams
+   */
+
+  std::string package_name_;
+  ofstream_with_content_based_conditional_update f_service_;
+  std::string package_dir_;
+
+  bool bindable_;
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_as3_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+  package_name_ = program_->get_namespace("as3");
+
+  string dir = package_name_;
+  string subdir = get_out_dir();
+  string::size_type loc;
+  while ((loc = dir.find(".")) != string::npos) {
+    subdir = subdir + "/" + dir.substr(0, loc);
+    MKDIR(subdir.c_str());
+    dir = dir.substr(loc + 1);
+  }
+  if (dir.size() > 0) {
+    subdir = subdir + "/" + dir;
+    MKDIR(subdir.c_str());
+  }
+
+  package_dir_ = subdir;
+}
+
+/**
+ * Packages the generated file
+ *
+ * @return String of the package, i.e. "package org.apache.thriftdemo;"
+ */
+string t_as3_generator::as3_package() {
+  if (!package_name_.empty()) {
+    return string("package ") + package_name_ + " ";
+  }
+  return "package ";
+}
+
+/**
+ * Prints standard as3 imports
+ *
+ * @return List of imports for As3 types that are used in here
+ */
+string t_as3_generator::as3_type_imports() {
+  return string() + "import org.apache.thrift.Set;\n" + "import flash.utils.ByteArray;\n"
+         + "import flash.utils.Dictionary;\n\n";
+}
+
+/**
+ * Prints standard as3 imports
+ *
+ * @return List of imports necessary for thrift
+ */
+string t_as3_generator::as3_thrift_imports() {
+  return string() + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n"
+         + "import org.apache.thrift.protocol.*;\n\n";
+}
+
+/**
+ * Prints imports needed for a given type
+ *
+ * @return List of imports necessary for a given t_struct
+ */
+string t_as3_generator::as3_thrift_gen_imports(t_struct* tstruct, string& imports) {
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  // For each type check if it is from a differnet namespace
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_program* program = (*m_iter)->get_type()->get_program();
+    if (program != NULL && program != program_) {
+      string package = program->get_namespace("as3");
+      if (!package.empty()) {
+        if (imports.find(package + "." + (*m_iter)->get_type()->get_name()) == string::npos) {
+          imports.append("import " + package + "." + (*m_iter)->get_type()->get_name() + ";\n");
+        }
+      }
+    }
+  }
+  return imports;
+}
+
+/**
+ * Prints imports needed for a given type
+ *
+ * @return List of imports necessary for a given t_service
+ */
+string t_as3_generator::as3_thrift_gen_imports(t_service* tservice) {
+  string imports;
+  const vector<t_function*>& functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+
+  // For each type check if it is from a differnet namespace
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_program* program = (*f_iter)->get_returntype()->get_program();
+    if (program != NULL && program != program_) {
+      string package = program->get_namespace("as3");
+      if (!package.empty()) {
+        if (imports.find(package + "." + (*f_iter)->get_returntype()->get_name()) == string::npos) {
+          imports.append("import " + package + "." + (*f_iter)->get_returntype()->get_name()
+                         + ";\n");
+        }
+      }
+    }
+
+    as3_thrift_gen_imports((*f_iter)->get_arglist(), imports);
+    as3_thrift_gen_imports((*f_iter)->get_xceptions(), imports);
+  }
+
+  return imports;
+}
+
+/**
+ * Nothing in As3
+ */
+void t_as3_generator::close_generator() {
+}
+
+/**
+ * Generates a typedef. This is not done in As3, since it does
+ * not support arbitrary name replacements, and it'd be a wacky waste
+ * of overhead to make wrapper classes.
+ *
+ * @param ttypedef The type definition
+ */
+void t_as3_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+/**
+ * Enums are a class with a set of static constants.
+ *
+ * @param tenum The enumeration
+ */
+void t_as3_generator::generate_enum(t_enum* tenum) {
+  // Make output file
+  string f_enum_name = package_dir_ + "/" + (tenum->get_name()) + ".as";
+  ofstream_with_content_based_conditional_update f_enum;
+  f_enum.open(f_enum_name);
+
+  // Comment and package it
+  f_enum << autogen_comment() << as3_package() << endl;
+
+  scope_up(f_enum);
+  // Add as3 imports
+  f_enum << string() + "import org.apache.thrift.Set;" << endl << "import flash.utils.Dictionary;"
+         << endl;
+
+  indent(f_enum) << "public class " << tenum->get_name() << " ";
+  scope_up(f_enum);
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    indent(f_enum) << "public static const " << (*c_iter)->get_name() << ":int = " << value << ";"
+                   << endl;
+  }
+
+  // Create a static Set with all valid values for this enum
+  f_enum << endl;
+
+  indent(f_enum) << "public static const VALID_VALUES:Set = new Set(";
+  indent_up();
+  bool firstValue = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    // populate set
+    f_enum << (firstValue ? "" : ", ") << (*c_iter)->get_name();
+    firstValue = false;
+  }
+  indent_down();
+  f_enum << ");" << endl;
+
+  indent(f_enum) << "public static const VALUES_TO_NAMES:Dictionary = new Dictionary();" << endl;
+
+  scope_up(f_enum);
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    indent(f_enum) << "VALUES_TO_NAMES[" << (*c_iter)->get_name() << "] = \""
+                   << (*c_iter)->get_name() << "\";" << endl;
+  }
+  f_enum << endl;
+
+  scope_down(f_enum);
+
+  scope_down(f_enum); // end class
+
+  scope_down(f_enum); // end package
+
+  f_enum.close();
+}
+
+/**
+ * Generates a class that holds all the constants.
+ */
+void t_as3_generator::generate_consts(std::vector<t_const*> consts) {
+  if (consts.empty()) {
+    return;
+  }
+
+  string f_consts_name = package_dir_ + "/" + program_name_ + "Constants.as";
+  ofstream_with_content_based_conditional_update f_consts;
+  f_consts.open(f_consts_name);
+
+  // Print header
+  f_consts << autogen_comment() << as3_package();
+
+  scope_up(f_consts);
+  f_consts << endl;
+
+  f_consts << as3_type_imports();
+
+  indent(f_consts) << "public class " << program_name_ << "Constants {" << endl << endl;
+  indent_up();
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    print_const_value(f_consts,
+                      (*c_iter)->get_name(),
+                      (*c_iter)->get_type(),
+                      (*c_iter)->get_value(),
+                      false);
+  }
+  indent_down();
+  indent(f_consts) << "}" << endl;
+  scope_down(f_consts);
+  f_consts.close();
+}
+
+void t_as3_generator::print_const_value(std::ostream& out,
+                                        string name,
+                                        t_type* type,
+                                        t_const_value* value,
+                                        bool in_static,
+                                        bool defval) {
+  type = get_true_type(type);
+
+  indent(out);
+  if (!defval) {
+    out << (in_static ? "var " : "public static const ");
+  }
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, name, type, value);
+    out << name;
+    if (!defval) {
+      out << ":" << type_name(type);
+    }
+    out << " = " << v2 << ";" << endl << endl;
+  } else if (type->is_enum()) {
+    out << name;
+    if (!defval) {
+      out << ":" << type_name(type);
+    }
+    out << " = " << value->get_integer() << ";" << endl << endl;
+  } else if (type->is_struct() || type->is_xception()) {
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    out << name << ":" << type_name(type) << " = new " << type_name(type, false, true) << "();"
+        << endl;
+    if (!in_static) {
+      indent(out) << "{" << endl;
+      indent_up();
+      indent(out) << "new function():void {" << endl;
+      indent_up();
+    }
+    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();
+      }
+      string val = render_const_value(out, name, field_type, v_iter->second);
+      indent(out) << name << ".";
+      out << v_iter->first->get_string() << " = " << val << ";" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}();" << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else if (type->is_map()) {
+    out << name;
+    if (!defval) {
+      out << ":" << type_name(type);
+    }
+    out << " = new " << type_name(type, false, true) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "{" << endl;
+      indent_up();
+      indent(out) << "new function():void {" << endl;
+      indent_up();
+    }
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, name, ktype, v_iter->first);
+      string val = render_const_value(out, name, vtype, v_iter->second);
+      indent(out) << name << "[" << key << "] = " << val << ";" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}();" << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else if (type->is_list() || type->is_set()) {
+    out << name;
+    if (!defval) {
+      out << ":" << type_name(type);
+    }
+    out << " = new " << type_name(type, false, true) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "{" << endl;
+      indent_up();
+      indent(out) << "new function():void {" << endl;
+      indent_up();
+    }
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(out, name, etype, *v_iter);
+      indent(out) << name << "." << (type->is_list() ? "push" : "add") << "(" << val << ");"
+                  << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}();" << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else {
+    throw "compiler error: no const of type " + type->get_name();
+  }
+}
+
+string t_as3_generator::render_const_value(ostream& out,
+                                           string name,
+                                           t_type* type,
+                                           t_const_value* value) {
+  (void)name;
+  type = get_true_type(type);
+  std::ostringstream render;
+
+  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:
+      render << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "true" : "false");
+      break;
+    case t_base_type::TYPE_I8:
+      render << "(byte)" << value->get_integer();
+      break;
+    case t_base_type::TYPE_I16:
+      render << "(short)" << value->get_integer();
+      break;
+    case t_base_type::TYPE_I32:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_I64:
+      render << value->get_integer() << "L";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << "(double)" << value->get_integer();
+      } else {
+        render << 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()) {
+    render << value->get_integer();
+  } else {
+    string t = tmp("tmp");
+    print_const_value(out, t, type, value, true);
+    render << t;
+  }
+
+  return render.str();
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This is a class
+ * with data members, read(), write(), and an inner Isset class.
+ *
+ * @param tstruct The struct definition
+ */
+void t_as3_generator::generate_struct(t_struct* tstruct) {
+  generate_as3_struct(tstruct, false);
+}
+
+/**
+ * Exceptions are structs, but they inherit from Exception
+ *
+ * @param tstruct The struct definition
+ */
+void t_as3_generator::generate_xception(t_struct* txception) {
+  generate_as3_struct(txception, true);
+}
+
+/**
+ * As3 struct definition.
+ *
+ * @param tstruct The struct definition
+ */
+void t_as3_generator::generate_as3_struct(t_struct* tstruct, bool is_exception) {
+  // Make output file
+  string f_struct_name = package_dir_ + "/" + (tstruct->get_name()) + ".as";
+  ofstream_with_content_based_conditional_update f_struct;
+  f_struct.open(f_struct_name.c_str());
+
+  f_struct << autogen_comment() << as3_package();
+
+  scope_up(f_struct);
+  f_struct << endl;
+
+  string imports;
+
+  f_struct << as3_type_imports() << as3_thrift_imports() << as3_thrift_gen_imports(tstruct, imports)
+           << endl;
+
+  if (bindable_ && !is_exception) {
+    f_struct << "import flash.events.Event;" << endl << "import flash.events.EventDispatcher;"
+             << endl << "import mx.events.PropertyChangeEvent;" << endl;
+  }
+
+  generate_as3_struct_definition(f_struct, tstruct, is_exception);
+
+  scope_down(f_struct); // end of package
+  f_struct.close();
+}
+
+/**
+ * As3 struct definition. This has various parameters, as it could be
+ * generated standalone or inside another class as a helper. If it
+ * is a helper than it is a static class.
+ *
+ * @param tstruct      The struct definition
+ * @param is_exception Is this an exception?
+ * @param in_class     If inside a class, needs to be static class
+ * @param is_result    If this is a result it needs a different writer
+ */
+void t_as3_generator::generate_as3_struct_definition(ostream& out,
+                                                     t_struct* tstruct,
+                                                     bool is_exception,
+                                                     bool in_class,
+                                                     bool is_result) {
+  generate_as3_doc(out, tstruct);
+
+  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+  bool bindable = !is_exception && !in_class && bindable_;
+
+  indent(out) << (in_class ? "" : "public ") << (is_final ? "final " : "") << "class "
+              << tstruct->get_name() << " ";
+
+  if (is_exception) {
+    out << "extends Error ";
+  } else if (bindable) {
+    out << "extends EventDispatcher ";
+  }
+  out << "implements TBase ";
+
+  scope_up(out);
+
+  indent(out) << "private static const STRUCT_DESC:TStruct = new TStruct(\"" << tstruct->get_name()
+              << "\");" << endl;
+
+  // Members are public for -as3, private for -as3bean
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) << "private static const " << constant_name((*m_iter)->get_name())
+                << "_FIELD_DESC:TField = new TField(\"" << (*m_iter)->get_name() << "\", "
+                << type_to_enum((*m_iter)->get_type()) << ", " << (*m_iter)->get_key() << ");"
+                << endl;
+  }
+
+  out << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    generate_as3_doc(out, *m_iter);
+    indent(out) << "private var _" << (*m_iter)->get_name() + ":" + type_name((*m_iter)->get_type())
+                << ";" << endl;
+
+    indent(out) << "public static const " << upcase_string((*m_iter)->get_name())
+                << ":int = " << (*m_iter)->get_key() << ";" << endl;
+  }
+
+  out << endl;
+
+  // Inner Isset class
+  if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (!type_can_be_null((*m_iter)->get_type())) {
+        indent(out) << "private var __isset_" << (*m_iter)->get_name() << ":Boolean = false;"
+                    << endl;
+      }
+    }
+  }
+
+  out << endl;
+
+  generate_as3_meta_data_map(out, tstruct);
+
+  // Static initializer to populate global class to struct metadata map
+  indent(out) << "{" << endl;
+  indent_up();
+  indent(out) << "FieldMetaData.addStructMetaDataMap(" << type_name(tstruct) << ", metaDataMap);"
+              << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  // Default constructor
+  indent(out) << "public function " << tstruct->get_name() << "() {" << endl;
+  indent_up();
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if ((*m_iter)->get_value() != NULL) {
+      indent(out) << "this._" << (*m_iter)->get_name() << " = "
+                  << (*m_iter)->get_value()->get_integer() << ";" << endl;
+    }
+  }
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  generate_as3_bean_boilerplate(out, tstruct, bindable);
+  generate_generic_field_getters_setters(out, tstruct);
+  generate_generic_isset_method(out, tstruct);
+
+  generate_as3_struct_reader(out, tstruct);
+  if (is_result) {
+    generate_as3_struct_result_writer(out, tstruct);
+  } else {
+    generate_as3_struct_writer(out, tstruct);
+  }
+  generate_as3_struct_tostring(out, tstruct, bindable);
+  generate_as3_validator(out, tstruct);
+  scope_down(out);
+  out << endl;
+}
+
+/**
+ * Generates a function to read all the fields of the struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_as3_generator::generate_as3_struct_reader(ostream& out, t_struct* tstruct) {
+  out << indent() << "public function read(iprot:TProtocol):void {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Declare stack tmp variables and read struct header
+  out << indent() << "var field:TField;" << endl << indent() << "iprot.readStructBegin();" << endl;
+
+  // Loop over reading in fields
+  indent(out) << "while (true)" << endl;
+  scope_up(out);
+
+  // Read beginning field marker
+  indent(out) << "field = iprot.readFieldBegin();" << endl;
+
+  // Check for field STOP marker and break
+  indent(out) << "if (field.type == TType.STOP) { " << endl;
+  indent_up();
+  indent(out) << "break;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+
+  // Switch statement on the field we are reading
+  indent(out) << "switch (field.id)" << endl;
+
+  scope_up(out);
+
+  // Generate deserialization code for known cases
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) << "case " << upcase_string((*f_iter)->get_name()) << ":" << endl;
+    indent_up();
+    indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+    indent_up();
+
+    generate_deserialize_field(out, *f_iter, "this.");
+    generate_isset_set(out, *f_iter);
+    indent_down();
+    out << indent() << "} else { " << endl << indent() << "  TProtocolUtil.skip(iprot, field.type);"
+        << endl << indent() << "}" << endl << indent() << "break;" << endl;
+    indent_down();
+  }
+
+  // In the default case we skip the field
+  out << indent() << "default:" << endl << indent() << "  TProtocolUtil.skip(iprot, field.type);"
+      << endl << indent() << "  break;" << endl;
+
+  scope_down(out);
+
+  // Read field end marker
+  indent(out) << "iprot.readFieldEnd();" << endl;
+
+  scope_down(out);
+
+  out << indent() << "iprot.readStructEnd();" << endl << endl;
+
+  // in non-beans style, check for required fields of primitive type
+  // (which can be checked here but not in the general validate method)
+  out << endl << indent() << "// check for required fields of primitive type, which can't be "
+                             "checked in the validate method" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) {
+      out << indent() << "if (!__isset_" << (*f_iter)->get_name() << ") {" << endl << indent()
+          << "  throw new TProtocolError(TProtocolError.UNKNOWN, \"Required field '"
+          << (*f_iter)->get_name()
+          << "' was not found in serialized data! Struct: \" + toString());" << endl << indent()
+          << "}" << endl;
+    }
+  }
+
+  // performs various checks (e.g. check that all required fields are set)
+  indent(out) << "validate();" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+// generates as3 method to perform various checks
+// (e.g. check that all required fields are set)
+void t_as3_generator::generate_as3_validator(ostream& out, t_struct* tstruct) {
+  indent(out) << "public function validate():void {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out << indent() << "// check for required fields" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      if (type_can_be_null((*f_iter)->get_type())) {
+        indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl;
+        indent(out) << "  throw new TProtocolError(TProtocolError.UNKNOWN, \"Required field '"
+                    << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());"
+                    << endl;
+        indent(out) << "}" << endl;
+      } else {
+        indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name()
+                    << "' because it's a primitive and you chose the non-beans generator." << endl;
+      }
+    }
+  }
+
+  // check that fields of type enum have valid values
+  out << indent() << "// check that fields of type enum have valid values" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = (*f_iter);
+    t_type* type = field->get_type();
+    // if field is an enum, check that its value is valid
+    if (type->is_enum()) {
+      indent(out) << "if (" << generate_isset_check(field) << " && !" << get_enum_class_name(type)
+                  << ".VALID_VALUES.contains(" << field->get_name() << ")){" << endl;
+      indent_up();
+      indent(out) << "throw new TProtocolError(TProtocolError.UNKNOWN, \"The field '"
+                  << field->get_name() << "' has been assigned the invalid value \" + "
+                  << field->get_name() << ");" << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_as3_generator::generate_as3_struct_writer(ostream& out, t_struct* tstruct) {
+  out << indent() << "public function write(oprot:TProtocol):void {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // performs various checks (e.g. check that all required fields are set)
+  indent(out) << "validate();" << endl << endl;
+
+  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
+    if (could_be_unset) {
+      indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl;
+      indent_up();
+    }
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    if (null_allowed) {
+      out << indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
+      indent_up();
+    }
+
+    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name())
+                << "_FIELD_DESC);" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "this.");
+
+    // Write field closer
+    indent(out) << "oprot.writeFieldEnd();" << endl;
+
+    if (null_allowed) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    if (could_be_unset) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+  // Write the struct map
+  out << indent() << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();"
+      << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct,
+ * which is a function result. These fields are only written
+ * if they are set in the Isset array, and only one of them
+ * can be set at a time.
+ *
+ * @param tstruct The struct definition
+ */
+void t_as3_generator::generate_as3_struct_result_writer(ostream& out, t_struct* tstruct) {
+  out << indent() << "public function write(oprot:TProtocol):void {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
+
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      out << endl << indent() << "if ";
+    } else {
+      out << " else if ";
+    }
+
+    out << "(this." << generate_isset_check(*f_iter) << ") {" << endl;
+
+    indent_up();
+
+    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name())
+                << "_FIELD_DESC);" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "this.");
+
+    // Write field closer
+    indent(out) << "oprot.writeFieldEnd();" << endl;
+
+    indent_down();
+    indent(out) << "}";
+  }
+  // Write the struct map
+  out << endl << indent() << "oprot.writeFieldStop();" << endl << indent()
+      << "oprot.writeStructEnd();" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+void t_as3_generator::generate_reflection_getters(ostringstream& out,
+                                                  t_type* type,
+                                                  string field_name,
+                                                  string cap_name) {
+  (void)type;
+  (void)cap_name;
+  indent(out) << "case " << upcase_string(field_name) << ":" << endl;
+  indent_up();
+  indent(out) << "return this." << field_name << ";" << endl;
+  indent_down();
+}
+
+void t_as3_generator::generate_reflection_setters(ostringstream& out,
+                                                  t_type* type,
+                                                  string field_name,
+                                                  string cap_name) {
+  (void)type;
+  (void)cap_name;
+  indent(out) << "case " << upcase_string(field_name) << ":" << endl;
+  indent_up();
+  indent(out) << "if (value == null) {" << endl;
+  indent(out) << "  unset" << get_cap_name(field_name) << "();" << endl;
+  indent(out) << "} else {" << endl;
+  indent(out) << "  this." << field_name << " = value;" << endl;
+  indent(out) << "}" << endl;
+  indent(out) << "break;" << endl << endl;
+
+  indent_down();
+}
+
+void t_as3_generator::generate_generic_field_getters_setters(std::ostream& out,
+                                                             t_struct* tstruct) {
+
+  std::ostringstream getter_stream;
+  std::ostringstream setter_stream;
+
+  // build up the bodies of both the getter and setter at once
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    t_type* type = get_true_type(field->get_type());
+    std::string field_name = field->get_name();
+    std::string cap_name = get_cap_name(field_name);
+
+    indent_up();
+    generate_reflection_setters(setter_stream, type, field_name, cap_name);
+    generate_reflection_getters(getter_stream, type, field_name, cap_name);
+    indent_down();
+  }
+
+  // create the setter
+  indent(out) << "public function setFieldValue(fieldID:int, value:*):void {" << endl;
+  indent_up();
+
+  indent(out) << "switch (fieldID) {" << endl;
+
+  out << setter_stream.str();
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  // create the getter
+  indent(out) << "public function getFieldValue(fieldID:int):* {" << endl;
+  indent_up();
+
+  indent(out) << "switch (fieldID) {" << endl;
+
+  out << getter_stream.str();
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+
+  indent(out) << "}" << endl;
+
+  indent_down();
+
+  indent(out) << "}" << endl << endl;
+}
+
+// Creates a generic isSet method that takes the field number as argument
+void t_as3_generator::generate_generic_isset_method(std::ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // create the isSet method
+  indent(out) << "// Returns true if field corresponding to fieldID is set (has been assigned a "
+                 "value) and false otherwise" << endl;
+  indent(out) << "public function isSet(fieldID:int):Boolean {" << endl;
+  indent_up();
+  indent(out) << "switch (fieldID) {" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
+    indent_up();
+    indent(out) << "return " << generate_isset_check(field) << ";" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a set of As3 Bean boilerplate functions (setters, getters, etc.)
+ * for the given struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_as3_generator::generate_as3_bean_boilerplate(ostream& out,
+                                                    t_struct* tstruct,
+                                                    bool bindable) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    t_type* type = get_true_type(field->get_type());
+    std::string field_name = field->get_name();
+    std::string cap_name = get_cap_name(field_name);
+
+    // Simple getter
+    generate_as3_doc(out, field);
+    indent(out) << "public function get " << field_name << "():" << type_name(type) << " {" << endl;
+    indent_up();
+    indent(out) << "return this._" << field_name << ";" << endl;
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // Simple setter
+    generate_as3_doc(out, field);
+    std::string propName = tmp("thriftPropertyChange");
+    if (bindable) {
+      indent(out) << "[Bindable(event=\"" << propName << "\")]" << endl;
+    }
+    indent(out) << "public function set " << field_name << "(" << field_name << ":"
+                << type_name(type) << "):void {" << endl;
+    indent_up();
+    indent(out) << "this._" << field_name << " = " << field_name << ";" << endl;
+    generate_isset_set(out, field);
+
+    if (bindable) {
+      // We have to use a custom event rather than the default, because if you use the default,
+      // the setter only gets called if the value has changed - this means calling
+      // foo.setIntValue(0)
+      // will not cause foo.isIntValueSet() to return true since the value of foo._intValue wasn't
+      // changed
+      // so the setter was never called.
+      indent(out) << "dispatchEvent(new Event(\"" << propName << "\"));" << endl;
+
+      // However, if you just use a custom event, then collections won't be able to detect when
+      // elements
+      // in the collections have changed since they listed for PropertyChangeEvents.  So, we
+      // dispatch both.
+      indent(out) << "dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE));"
+                  << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // Unsetter
+    indent(out) << "public function unset" << cap_name << "():void {" << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "this." << field_name << " = null;" << endl;
+    } else {
+      indent(out) << "this.__isset_" << field_name << " = false;" << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // isSet method
+    indent(out) << "// Returns true if field " << field_name
+                << " is set (has been assigned a value) and false otherwise" << endl;
+    indent(out) << "public function is" << get_cap_name("set") << cap_name << "():Boolean {"
+                << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "return this." << field_name << " != null;" << endl;
+    } else {
+      indent(out) << "return this.__isset_" << field_name << ";" << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+}
+
+/**
+ * Generates a toString() method for the given struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_as3_generator::generate_as3_struct_tostring(ostream& out,
+                                                   t_struct* tstruct,
+                                                   bool bindable) {
+  // If it's bindable, it extends EventDispatcher so toString is an override.
+  out << indent() << "public " << (bindable ? "override " : "") << "function toString():String {"
+      << endl;
+  indent_up();
+
+  out << indent() << "var ret:String = new String(\"" << tstruct->get_name() << "(\");" << endl;
+  out << indent() << "var first:Boolean = true;" << endl << endl;
+
+  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) {
+    bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
+    if (could_be_unset) {
+      indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl;
+      indent_up();
+    }
+
+    t_field* field = (*f_iter);
+
+    if (!first) {
+      indent(out) << "if (!first) ret +=  \", \";" << endl;
+    }
+    indent(out) << "ret += \"" << (*f_iter)->get_name() << ":\";" << endl;
+    bool can_be_null = type_can_be_null(field->get_type());
+    if (can_be_null) {
+      indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl;
+      indent(out) << "  ret += \"null\";" << endl;
+      indent(out) << "} else {" << endl;
+      indent_up();
+    }
+
+    if (field->get_type()->is_binary()) {
+      indent(out) << "  ret += \"BINARY\";" << endl;
+    } else if (field->get_type()->is_enum()) {
+      indent(out) << "var " << field->get_name()
+                  << "_name:String = " << get_enum_class_name(field->get_type())
+                  << ".VALUES_TO_NAMES[this." << (*f_iter)->get_name() << "];" << endl;
+      indent(out) << "if (" << field->get_name() << "_name != null) {" << endl;
+      indent(out) << "  ret += " << field->get_name() << "_name;" << endl;
+      indent(out) << "  ret += \" (\";" << endl;
+      indent(out) << "}" << endl;
+      indent(out) << "ret += this." << field->get_name() << ";" << endl;
+      indent(out) << "if (" << field->get_name() << "_name != null) {" << endl;
+      indent(out) << "  ret += \")\";" << endl;
+      indent(out) << "}" << endl;
+    } else {
+      indent(out) << "ret += this." << (*f_iter)->get_name() << ";" << endl;
+    }
+
+    if (can_be_null) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    indent(out) << "first = false;" << endl;
+
+    if (could_be_unset) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    first = false;
+  }
+  out << indent() << "ret += \")\";" << endl << indent() << "return ret;" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a static map with meta data to store information such as fieldID to
+ * fieldName mapping
+ *
+ * @param tstruct The struct definition
+ */
+void t_as3_generator::generate_as3_meta_data_map(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Static Map with fieldID -> FieldMetaData mappings
+  indent(out) << "public static const metaDataMap:Dictionary = new Dictionary();" << endl;
+
+  if (fields.size() > 0) {
+    // Populate map
+    scope_up(out);
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      t_field* field = *f_iter;
+      std::string field_name = field->get_name();
+      indent(out) << "metaDataMap[" << upcase_string(field_name) << "] = new FieldMetaData(\""
+                  << field_name << "\", ";
+
+      // Set field requirement type (required, optional, etc.)
+      if (field->get_req() == t_field::T_REQUIRED) {
+        out << "TFieldRequirementType.REQUIRED, ";
+      } else if (field->get_req() == t_field::T_OPTIONAL) {
+        out << "TFieldRequirementType.OPTIONAL, ";
+      } else {
+        out << "TFieldRequirementType.DEFAULT, ";
+      }
+
+      // Create value meta data
+      generate_field_value_meta_data(out, field->get_type());
+      out << ");" << endl;
+    }
+    scope_down(out);
+  }
+}
+
+/**
+ * Returns a string with the as3 representation of the given thrift type
+ * (e.g. for the type struct it returns "TType.STRUCT")
+ */
+std::string t_as3_generator::get_as3_type_string(t_type* type) {
+  if (type->is_list()) {
+    return "TType.LIST";
+  } else if (type->is_map()) {
+    return "TType.MAP";
+  } else if (type->is_set()) {
+    return "TType.SET";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.STRUCT";
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_typedef()) {
+    return get_as3_type_string(((t_typedef*)type)->get_type());
+  } else if (type->is_base_type()) {
+    switch (((t_base_type*)type)->get_base()) {
+    case t_base_type::TYPE_VOID:
+      return "TType.VOID";
+      break;
+    case t_base_type::TYPE_STRING:
+      return "TType.STRING";
+      break;
+    case t_base_type::TYPE_BOOL:
+      return "TType.BOOL";
+      break;
+    case t_base_type::TYPE_I8:
+      return "TType.BYTE";
+      break;
+    case t_base_type::TYPE_I16:
+      return "TType.I16";
+      break;
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+      break;
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      return "TType.DOUBLE";
+      break;
+    default:
+      throw std::runtime_error("Unknown thrift type \"" + type->get_name()
+                               + "\" passed to t_as3_generator::get_as3_type_string!");
+      break; // This should never happen!
+    }
+  } else {
+    throw std::runtime_error(
+        "Unknown thrift type \"" + type->get_name()
+        + "\" passed to t_as3_generator::get_as3_type_string!"); // This should never happen!
+  }
+}
+
+void t_as3_generator::generate_field_value_meta_data(std::ostream& out, t_type* type) {
+  out << endl;
+  indent_up();
+  indent_up();
+  if (type->is_struct() || type->is_xception()) {
+    indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type);
+  } else if (type->is_container()) {
+    if (type->is_list()) {
+      indent(out) << "new ListMetaData(TType.LIST, ";
+      t_type* elem_type = ((t_list*)type)->get_elem_type();
+      generate_field_value_meta_data(out, elem_type);
+    } else if (type->is_set()) {
+      indent(out) << "new SetMetaData(TType.SET, ";
+      t_type* elem_type = ((t_list*)type)->get_elem_type();
+      generate_field_value_meta_data(out, elem_type);
+    } else { // map
+      indent(out) << "new MapMetaData(TType.MAP, ";
+      t_type* key_type = ((t_map*)type)->get_key_type();
+      t_type* val_type = ((t_map*)type)->get_val_type();
+      generate_field_value_meta_data(out, key_type);
+      out << ", ";
+      generate_field_value_meta_data(out, val_type);
+    }
+  } else {
+    indent(out) << "new FieldValueMetaData(" << get_as3_type_string(type);
+  }
+  out << ")";
+  indent_down();
+  indent_down();
+}
+
+/**
+ * Generates a thrift service. In C++, this comprises an entirely separate
+ * header and source file. The header file defines the methods and includes
+ * the data types defined in the main header file, and the implementation
+ * file contains implementations of the basic printer and default interfaces.
+ *
+ * @param tservice The service definition
+ */
+void t_as3_generator::generate_service(t_service* tservice) {
+  // Make interface file
+  string f_service_name = package_dir_ + "/" + service_name_ + ".as";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << autogen_comment() << as3_package();
+
+  scope_up(f_service_);
+
+  f_service_ << endl << as3_type_imports() << as3_thrift_imports()
+             << as3_thrift_gen_imports(tservice);
+
+  if (tservice->get_extends() != NULL) {
+    t_type* parent = tservice->get_extends();
+    string parent_namespace = parent->get_program()->get_namespace("as3");
+    if (!parent_namespace.empty() && parent_namespace != package_name_) {
+      f_service_ << "import " << type_name(parent) << ";" << endl;
+    }
+  }
+
+  f_service_ << endl;
+
+  generate_service_interface(tservice);
+
+  scope_down(f_service_);
+  f_service_.close();
+
+  // Now make the implementation/client file
+  f_service_name = package_dir_ + "/" + service_name_ + "Impl.as";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << autogen_comment() << as3_package();
+
+  scope_up(f_service_);
+
+  f_service_ << endl << as3_type_imports() << as3_thrift_imports()
+             << as3_thrift_gen_imports(tservice);
+
+  if (tservice->get_extends() != NULL) {
+    t_type* parent = tservice->get_extends();
+    string parent_namespace = parent->get_program()->get_namespace("as3");
+    if (!parent_namespace.empty() && parent_namespace != package_name_) {
+      f_service_ << "import " << type_name(parent) << "Impl;" << endl;
+    }
+  }
+
+  f_service_ << endl;
+
+  generate_service_client(tservice);
+  scope_down(f_service_);
+
+  f_service_ << as3_type_imports();
+  f_service_ << as3_thrift_imports();
+  f_service_ << as3_thrift_gen_imports(tservice);
+  if (!package_name_.empty()) {
+    f_service_ << "import " << package_name_ << ".*;" << endl;
+  }
+
+  generate_service_helpers(tservice);
+
+  f_service_.close();
+
+  // Now make the processor/server file
+  f_service_name = package_dir_ + "/" + service_name_ + "Processor.as";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << autogen_comment() << as3_package();
+
+  scope_up(f_service_);
+
+  f_service_ << endl << as3_type_imports() << as3_thrift_imports()
+             << as3_thrift_gen_imports(tservice) << endl;
+
+  generate_service_server(tservice);
+  scope_down(f_service_);
+
+  f_service_ << as3_type_imports();
+  f_service_ << as3_thrift_imports();
+  f_service_ << as3_thrift_gen_imports(tservice) << endl;
+  if (!package_name_.empty()) {
+    f_service_ << "import " << package_name_ << ".*;" << endl;
+  }
+
+  generate_service_helpers(tservice);
+
+  f_service_.close();
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_as3_generator::generate_service_interface(t_service* tservice) {
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends_iface = " extends " + tservice->get_extends()->get_name();
+  }
+
+  generate_as3_doc(f_service_, tservice);
+  f_service_ << indent() << "public interface " << service_name_ << extends_iface << " {" << endl
+             << endl;
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_as3_doc(f_service_, *f_iter);
+    if (!(*f_iter)->is_oneway()) {
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) << "//function onError(Error):void;" << endl;
+        indent(f_service_) << "//function onSuccess():void;" << endl;
+      } else {
+        indent(f_service_) << "//function onError(Error):void;" << endl;
+        indent(f_service_) << "//function onSuccess(" << type_name((*f_iter)->get_returntype())
+                           << "):void;" << endl;
+      }
+    }
+    indent(f_service_) << function_signature(*f_iter) << ";" << endl << endl;
+  }
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates structs for all the service args and return types
+ *
+ * @param tservice The service
+ */
+void t_as3_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_as3_struct_definition(f_service_, ts, false, true);
+    generate_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_as3_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = tservice->get_extends()->get_name();
+    extends_client = " extends " + extends + "Impl";
+  }
+
+  indent(f_service_) << "public class " << service_name_ << "Impl" << extends_client
+                     << " implements " << service_name_ << " {" << endl;
+  indent_up();
+
+  indent(f_service_) << "public function " << service_name_ << "Impl"
+                     << "(iprot:TProtocol, oprot:TProtocol=null)" << endl;
+  scope_up(f_service_);
+  if (extends.empty()) {
+    f_service_ << indent() << "iprot_ = iprot;" << endl;
+    f_service_ << indent() << "if (oprot == null) {" << endl;
+    indent_up();
+    f_service_ << indent() << "oprot_ = iprot;" << endl;
+    indent_down();
+    f_service_ << indent() << "} else {" << endl;
+    indent_up();
+    f_service_ << indent() << "oprot_ = oprot;" << endl;
+    indent_down();
+    f_service_ << indent() << "}";
+  } else {
+    f_service_ << indent() << "super(iprot, oprot);" << endl;
+  }
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_ << indent() << "protected var iprot_:TProtocol;" << endl << indent()
+               << "protected var oprot_:TProtocol;" << endl << endl << indent()
+               << "protected var seqid_:int;" << endl << endl;
+
+    indent(f_service_) << "public function getInputProtocol():TProtocol" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "return this.iprot_;" << endl;
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    indent(f_service_) << "public function getOutputProtocol():TProtocol" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "return this.oprot_;" << endl;
+    scope_down(f_service_);
+    f_service_ << 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) {
+    string funname = (*f_iter)->get_name();
+
+    // Open function
+    if (!(*f_iter)->is_oneway()) {
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) << "//function onError(Error):void;" << endl;
+        indent(f_service_) << "//function onSuccess():void;" << endl;
+      } else {
+        indent(f_service_) << "//function onError(Error):void;" << endl;
+        indent(f_service_) << "//function onSuccess(" << type_name((*f_iter)->get_returntype())
+                           << "):void;" << endl;
+      }
+    }
+    indent(f_service_) << "public " << function_signature(*f_iter) << endl;
+    scope_up(f_service_);
+
+    // Get the struct of function call params
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+
+    string argsname = (*f_iter)->get_name() + "_args";
+    vector<t_field*>::const_iterator fld_iter;
+    const vector<t_field*>& fields = arg_struct->get_members();
+
+    // Serialize the request
+    f_service_ << indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", "
+               << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL")
+               << ", seqid_));" << endl << indent() << "var args:" << argsname << " = new "
+               << argsname << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << indent() << "args." << (*fld_iter)->get_name() << " = "
+                 << (*fld_iter)->get_name() << ";" << endl;
+    }
+
+    f_service_ << indent() << "args.write(oprot_);" << endl << indent()
+               << "oprot_.writeMessageEnd();" << endl;
+
+    if ((*f_iter)->is_oneway()) {
+      f_service_ << indent() << "oprot_.getTransport().flush();" << endl;
+    } else {
+      f_service_ << indent() << "oprot_.getTransport().flush(function(error:Error):void {" << endl;
+      indent_up();
+      f_service_ << indent() << "try {" << endl;
+      indent_up();
+      string resultname = (*f_iter)->get_name() + "_result";
+      f_service_ << indent() << "if (error != null) {" << endl << indent()
+                 << "  if (onError != null) onError(error);" << endl << indent() << "  return;"
+                 << endl << indent() << "}" << endl << indent()
+                 << "var msg:TMessage = iprot_.readMessageBegin();" << endl << indent()
+                 << "if (msg.type == TMessageType.EXCEPTION) {" << endl << indent()
+                 << "  var x:TApplicationError = TApplicationError.read(iprot_);" << endl
+                 << indent() << "  iprot_.readMessageEnd();" << endl << indent()
+                 << "  if (onError != null) onError(x);" << endl << indent() << "  return;" << endl
+                 << indent() << "}" << endl << indent() << "var result :" << resultname << " = new "
+                 << resultname << "();" << endl << indent() << "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() << "if (result." << generate_isset_check("success") << ") {" << endl
+                   << indent() << "  if (onSuccess != null) onSuccess(result.success);" << endl
+                   << indent() << "  return;" << endl << indent() << "}" << 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." << (*x_iter)->get_name() << " != null) {" << endl
+                   << indent() << "  if (onError != null) onError(result." << (*x_iter)->get_name()
+                   << ");" << endl << indent() << "  return;" << endl << indent() << "}" << endl;
+      }
+
+      // If you get here it's an exception, unless a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        f_service_ << indent() << "if (onSuccess != null) onSuccess();" << endl << indent()
+                   << "return;" << endl;
+      } else {
+
+        f_service_ << indent() << "if (onError != null) onError(new "
+                                  "TApplicationError(TApplicationError.MISSING_RESULT, \""
+                   << (*f_iter)->get_name() << " failed: unknown result\"));" << endl;
+      }
+      indent_down();
+      f_service_ << indent() << "} catch (e:TError) {" << endl << indent()
+                 << "  if (onError != null) onError(e);" << endl << indent() << "}" << endl;
+
+      indent_down();
+      indent(f_service_) << "});" << endl;
+    }
+    // Close function
+    scope_down(f_service_);
+    f_service_ << endl;
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl;
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_as3_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  // Extends stuff
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_processor = " extends " + extends + "Processor";
+  }
+
+  // Generate the header portion
+  indent(f_service_) << "public class " << service_name_ << "Processor" << extends_processor
+                     << " implements TProcessor {" << endl;
+  indent_up();
+
+  indent(f_service_) << "public function " << service_name_ << "Processor(iface:" << service_name_
+                     << ")" << endl;
+  scope_up(f_service_);
+  if (!extends.empty()) {
+    f_service_ << indent() << "super(iface);" << endl;
+  }
+  f_service_ << indent() << "iface_ = iface;" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << indent() << "PROCESS_MAP[\"" << (*f_iter)->get_name()
+               << "\"] = " << (*f_iter)->get_name() << "();" << endl;
+  }
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  f_service_ << indent() << "private var iface_:" << service_name_ << ";" << endl;
+
+  if (extends.empty()) {
+    f_service_ << indent() << "protected const PROCESS_MAP:Dictionary = new Dictionary();" << endl;
+  }
+
+  f_service_ << endl;
+
+  // Generate the server implementation
+  string override = "";
+  if (tservice->get_extends() != NULL) {
+    override = "override ";
+  }
+  indent(f_service_) << override
+                     << "public function process(iprot:TProtocol, oprot:TProtocol):Boolean" << endl;
+  scope_up(f_service_);
+
+  f_service_ << indent() << "var msg:TMessage = iprot.readMessageBegin();" << endl;
+
+  // TODO(mcslee): validate message, was the seqid etc. legit?
+  // AS- If all method is oneway:
+  // do you have an oprot?
+  // do you you need nullcheck?
+  f_service_
+      << indent() << "var fn:Function = PROCESS_MAP[msg.name];" << endl << indent()
+      << "if (fn == null) {" << endl << indent() << "  TProtocolUtil.skip(iprot, TType.STRUCT);"
+      << endl << indent() << "  iprot.readMessageEnd();" << endl << indent()
+      << "  var x:TApplicationError = new TApplicationError(TApplicationError.UNKNOWN_METHOD, "
+         "\"Invalid method name: '\"+msg.name+\"'\");" << endl << indent()
+      << "  oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));"
+      << endl << indent() << "  x.write(oprot);" << endl << indent() << "  oprot.writeMessageEnd();"
+      << endl << indent() << "  oprot.getTransport().flush();" << endl << indent()
+      << "  return true;" << endl << indent() << "}" << endl << indent()
+      << "fn.call(this,msg.seqid, iprot, oprot);" << endl;
+
+  f_service_ << indent() << "return true;" << endl;
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl << endl;
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_as3_generator::generate_function_helpers(t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return;
+  }
+
+  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_as3_struct_definition(f_service_, &result, false, true, true);
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_as3_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+  // Open class
+  indent(f_service_) << "private function " << tfunction->get_name() << "():Function {" << endl;
+  indent_up();
+
+  // Open function
+  indent(f_service_) << "return function(seqid:int, iprot:TProtocol, oprot:TProtocol):void" << endl;
+  scope_up(f_service_);
+
+  string argsname = tfunction->get_name() + "_args";
+  string resultname = tfunction->get_name() + "_result";
+
+  f_service_ << indent() << "var args:" << argsname << " = new " << argsname << "();" << endl
+             << indent() << "args.read(iprot);" << endl << indent() << "iprot.readMessageEnd();"
+             << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << "var result:" << resultname << " = new " << resultname << "();"
+               << endl;
+  }
+
+  // Try block for a function with exceptions
+  if (xceptions.size() > 0) {
+    f_service_ << indent() << "try {" << endl;
+    indent_up();
+  }
+
+  // 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_ << indent();
+  if (tfunction->is_oneway()) {
+    f_service_ << "iface_." << 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." << (*f_iter)->get_name();
+    }
+    f_service_ << ");" << endl;
+  } else {
+    f_service_ << "// sorry this operation is not supported yet" << endl;
+    f_service_ << indent() << "throw new Error(\"This is not yet supported\");" << endl;
+  }
+
+  // Set isset on success field
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()
+      && !type_can_be_null(tfunction->get_returntype())) {
+    f_service_ << indent() << "result.set" << get_cap_name("success") << get_cap_name("isSet")
+               << "(true);" << endl;
+  }
+
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    indent_down();
+    f_service_ << indent() << "}";
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << " catch (" << (*x_iter)->get_name() << ":"
+                 << type_name((*x_iter)->get_type(), false, false) << ") {" << endl;
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        f_service_ << indent() << "result." << (*x_iter)->get_name() << " = "
+                   << (*x_iter)->get_name() << ";" << endl;
+        indent_down();
+        f_service_ << indent() << "}";
+      } else {
+        f_service_ << "}";
+      }
+    }
+    f_service_ << " catch (th:Error) {" << endl;
+    indent_up();
+    f_service_ << indent() << "trace(\"Internal error processing " << tfunction->get_name()
+               << "\", th);" << endl << indent()
+               << "var x:TApplicationError = new "
+                  "TApplicationError(TApplicationError.INTERNAL_ERROR, \"Internal error processing "
+               << tfunction->get_name() << "\");" << endl << indent()
+               << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name()
+               << "\", TMessageType.EXCEPTION, seqid));" << endl << indent() << "x.write(oprot);"
+               << endl << indent() << "oprot.writeMessageEnd();" << endl << indent()
+               << "oprot.getTransport().flush();" << endl << indent() << "return;" << endl;
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+  }
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    f_service_ << indent() << "return;" << endl;
+    scope_down(f_service_);
+
+    // Close class
+    indent_down();
+    f_service_ << indent() << "}" << endl << endl;
+    return;
+  }
+
+  f_service_ << indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name()
+             << "\", TMessageType.REPLY, seqid));" << endl << indent() << "result.write(oprot);"
+             << endl << indent() << "oprot.writeMessageEnd();" << endl << indent()
+             << "oprot.getTransport().flush();" << endl;
+
+  // Close function
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Close class
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+/**
+ * Deserializes a field of any type.
+ *
+ * @param tfield The field
+ * @param prefix The variable name or container for this field
+ */
+void t_as3_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name();
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    indent(out) << name << " = 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:
+        if (type->is_binary()) {
+          out << "readBinary();";
+        } else {
+          out << "readString();";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "readBool();";
+        break;
+      case t_base_type::TYPE_I8:
+        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 As3 name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "readI32();";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a struct, invokes read()
+ */
+void t_as3_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl << indent()
+      << prefix << ".read(iprot);" << endl;
+}
+
+/**
+ * Deserializes a container by reading its size and then iterating
+ */
+void t_as3_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  string obj;
+
+  if (ttype->is_map()) {
+    obj = tmp("_map");
+  } else if (ttype->is_set()) {
+    obj = tmp("_set");
+  } else if (ttype->is_list()) {
+    obj = tmp("_list");
+  }
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    indent(out) << "var " << obj << ":TMap = iprot.readMapBegin();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "var " << obj << ":TSet = iprot.readSetBegin();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "var " << obj << ":TList = iprot.readListBegin();" << endl;
+  }
+
+  indent(out) << prefix << " = new " << type_name(ttype, false, true)
+              // size the collection correctly
+              << "("
+              << ");" << endl;
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) << "for (var " << i << ":int = 0; " << i << " < " << obj << ".size"
+              << "; "
+              << "++" << i << ")" << endl;
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  scope_down(out);
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "iprot.readMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "iprot.readSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "iprot.readListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_as3_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) << declare_field(&fkey) << endl;
+  indent(out) << declare_field(&fval) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) << prefix << "[" << key << "] = " << val << ";" << endl;
+}
+
+/**
+ * Deserializes a set element
+ */
+void t_as3_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".add(" << elem << ");" << endl;
+}
+
+/**
+ * Deserializes a list element
+ */
+void t_as3_generator::generate_deserialize_list_element(ostream& out,
+                                                        t_list* tlist,
+                                                        string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  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_as3_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name());
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, prefix + tfield->get_name());
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    string name = prefix + tfield->get_name();
+    indent(out) << "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:
+        if (type->is_binary()) {
+          out << "writeBinary(" << name << ");";
+        } else {
+          out << "writeString(" << name << ");";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ");";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "writeByte(" << name << ");";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16(" << name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32(" << name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64(" << name << ");";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble(" << name << ");";
+        break;
+      default:
+        throw "compiler error: no As3 name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32(" << name << ");";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_as3_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  (void)tstruct;
+  out << indent() << prefix << ".write(oprot);" << endl;
+}
+
+/**
+ * Serializes a container by writing its size then the elements.
+ *
+ * @param ttype  The type of container
+ * @param prefix String prefix for fields
+ */
+void t_as3_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    string iter = tmp("_key");
+    string counter = tmp("_sizeCounter");
+    indent(out) << "var " << counter << ":int = 0;" << endl;
+    indent(out) << "for (var " << iter << ":* in " << prefix << ") {" << endl;
+    indent(out) << "  " << counter << +"++;" << endl;
+    indent(out) << "}" << endl;
+
+    indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type())
+                << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << counter << "));"
+                << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type())
+                << ", " << prefix << ".size));" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.writeListBegin(new TList("
+                << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".length));"
+                << endl;
+  }
+
+  string iter = tmp("elem");
+  if (ttype->is_map()) {
+    indent(out) << "for (var " << iter << ":* in " << prefix << ")";
+  } else if (ttype->is_set()) {
+    indent(out) << "for each (var " << iter << ":* in " << prefix << ".toArray())";
+  } else if (ttype->is_list()) {
+    indent(out) << "for each (var " << iter << ":* in " << prefix << ")";
+  }
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
+  } else if (ttype->is_set()) {
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+  } else if (ttype->is_list()) {
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+  }
+
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "oprot.writeMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.writeSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.writeListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ */
+void t_as3_generator::generate_serialize_map_element(ostream& out,
+                                                     t_map* tmap,
+                                                     string iter,
+                                                     string map) {
+  t_field kfield(tmap->get_key_type(), iter);
+  generate_serialize_field(out, &kfield, "");
+  t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
+  generate_serialize_field(out, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_as3_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_as3_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Returns a As3 type name
+ *
+ * @param ttype The type
+ * @param container Is the type going inside a container?
+ * @return As3 type name, i.e. HashMap<Key,Value>
+ */
+string t_as3_generator::type_name(t_type* ttype, bool in_container, bool in_init) {
+  (void)in_init;
+  // In As3 typedefs are just resolved to their real type
+  ttype = get_true_type(ttype);
+  string prefix;
+
+  if (ttype->is_base_type()) {
+    return base_type_name((t_base_type*)ttype, in_container);
+  } else if (ttype->is_enum()) {
+    return "int";
+  } else if (ttype->is_map()) {
+    return "Dictionary";
+  } else if (ttype->is_set()) {
+    return "Set";
+  } else if (ttype->is_list()) {
+    return "Array";
+  }
+
+  // Check for namespacing
+  t_program* program = ttype->get_program();
+  if (program != NULL && program != program_) {
+    string package = program->get_namespace("as3");
+    if (!package.empty()) {
+      return package + "." + ttype->get_name();
+    }
+  }
+
+  return ttype->get_name();
+}
+
+/**
+ * Returns the AS3 type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ * @param container Is it going in a As3 container?
+ */
+string t_as3_generator::base_type_name(t_base_type* type, bool in_container) {
+  (void)in_container;
+  t_base_type::t_base tbase = type->get_base();
+
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    if (type->is_binary()) {
+      return "ByteArray";
+    } else {
+      return "String";
+    }
+  case t_base_type::TYPE_BOOL:
+    return "Boolean";
+  case t_base_type::TYPE_I8:
+  case t_base_type::TYPE_I16:
+  case t_base_type::TYPE_I32:
+    return "int";
+  case t_base_type::TYPE_I64:
+    throw "i64 is not yet supported in as3";
+  case t_base_type::TYPE_DOUBLE:
+    return "Number";
+  default:
+    throw "compiler error: no As3 name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_as3_generator::declare_field(t_field* tfield, bool init) {
+  // TODO(mcslee): do we ever need to initialize the field?
+  string result = "var " + tfield->get_name() + ":" + type_name(tfield->get_type());
+  if (init) {
+    t_type* ttype = get_true_type(tfield->get_type());
+    if (ttype->is_base_type() && tfield->get_value() != NULL) {
+      std::ofstream dummy;
+      result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
+    } else if (ttype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "NO T_VOID CONSTRUCT";
+      case t_base_type::TYPE_STRING:
+        result += " = null";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = false";
+        break;
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = (double)0";
+        break;
+      }
+
+    } else if (ttype->is_enum()) {
+      result += " = 0";
+    } else if (ttype->is_container()) {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    } else {
+      result += " = new " + type_name(ttype, false, true) + "()";
+      ;
+    }
+  }
+  return result + ";";
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_as3_generator::function_signature(t_function* tfunction, string prefix) {
+  std::string arguments = argument_list(tfunction->get_arglist());
+  if (!tfunction->is_oneway()) {
+    if (arguments != "") {
+      arguments += ", ";
+    }
+    arguments += "onError:Function, onSuccess:Function";
+  }
+
+  std::string result = "function " + prefix + tfunction->get_name() + "(" + arguments + "):void";
+  return result;
+}
+
+/**
+ * Renders a comma separated field list, with type names
+ */
+string t_as3_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_name((*f_iter)->get_type());
+  }
+  return result;
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ */
+string t_as3_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 "TType.STRING";
+    case t_base_type::TYPE_BOOL:
+      return "TType.BOOL";
+    case t_base_type::TYPE_I8:
+      return "TType.BYTE";
+    case t_base_type::TYPE_I16:
+      return "TType.I16";
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "TType.DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.STRUCT";
+  } else if (type->is_map()) {
+    return "TType.MAP";
+  } else if (type->is_set()) {
+    return "TType.SET";
+  } else if (type->is_list()) {
+    return "TType.LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Applies the correct style to a string based on the value of nocamel_style_
+ */
+std::string t_as3_generator::get_cap_name(std::string name) {
+  name[0] = toupper(name[0]);
+  return name;
+}
+
+string t_as3_generator::constant_name(string name) {
+  string constant_name;
+
+  bool is_first = true;
+  bool was_previous_char_upper = false;
+  for (string::iterator iter = name.begin(); iter != name.end(); ++iter) {
+    string::value_type character = (*iter);
+
+    bool is_upper = isupper(character);
+
+    if (is_upper && !is_first && !was_previous_char_upper) {
+      constant_name += '_';
+    }
+    constant_name += toupper(character);
+
+    is_first = false;
+    was_previous_char_upper = is_upper;
+  }
+
+  return constant_name;
+}
+
+/**
+ * Emits a As3Doc comment if the provided object has a doc in Thrift
+ */
+void t_as3_generator::generate_as3_doc(ostream& out, t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    generate_docstring_comment(out, "/**\n", " * ", tdoc->get_doc(), " */\n");
+  }
+}
+
+/**
+ * Emits a As3Doc comment if the provided function object has a doc in Thrift
+ */
+void t_as3_generator::generate_as3_doc(ostream& out, t_function* tfunction) {
+  if (tfunction->has_doc()) {
+    stringstream ss;
+    ss << tfunction->get_doc();
+    const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+    vector<t_field*>::const_iterator p_iter;
+    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
+      t_field* p = *p_iter;
+      ss << "\n@param " << p->get_name();
+      if (p->has_doc()) {
+        ss << " " << p->get_doc();
+      }
+    }
+    generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n");
+  }
+}
+
+std::string t_as3_generator::generate_isset_check(t_field* field) {
+  return generate_isset_check(field->get_name());
+}
+
+std::string t_as3_generator::generate_isset_check(std::string field_name) {
+  return "is" + get_cap_name("set") + get_cap_name(field_name) + "()";
+}
+
+void t_as3_generator::generate_isset_set(ostream& out, t_field* field) {
+  if (!type_can_be_null(field->get_type())) {
+    indent(out) << "this.__isset_" << field->get_name() << " = true;" << endl;
+  }
+}
+
+std::string t_as3_generator::get_enum_class_name(t_type* type) {
+  string package = "";
+  t_program* program = type->get_program();
+  if (program != NULL && program != program_) {
+    package = program->get_namespace("as3") + ".";
+  }
+  return package + type->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(
+    as3,
+    "AS3",
+    "    bindable:        Add [bindable] metadata to all the struct classes.\n")
diff --git a/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc b/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc
new file mode 100644
index 0000000..be3bad1
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc
@@ -0,0 +1,4587 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+#include <fstream>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include <ctype.h>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/* forward declarations */
+string initial_caps_to_underscores(string name);
+string underscores_to_initial_caps(string name);
+string to_upper_case(string name);
+string to_lower_case(string name);
+
+/**
+ * C code generator, using glib for C typing.
+ */
+class t_c_glib_generator : public t_oop_generator {
+public:
+  /* constructor */
+  t_c_glib_generator(t_program* program,
+                     const map<string, string>& parsed_options,
+                     const string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    /* set the output directory */
+    this->out_dir_base_ = "gen-c_glib";
+
+    /* no options yet */
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      throw "unknown option c_glib:" + iter->first;
+    }
+
+    /* set the namespace */
+    this->nspace = program_->get_namespace("c_glib");
+
+    if (this->nspace.empty()) {
+      this->nspace = "";
+      this->nspace_u = "";
+      this->nspace_uc = "";
+      this->nspace_lc = "";
+    } else {
+      /* replace dots with underscores */
+      char* tmp = strdup(this->nspace.c_str());
+      for (unsigned int i = 0; i < strlen(tmp); i++) {
+        if (tmp[i] == '.') {
+          tmp[i] = '_';
+        }
+      }
+      this->nspace = string(tmp, strlen(tmp));
+      free(tmp);
+
+      /* clean up the namespace for C.
+       * An input of 'namespace foo' should result in:
+       *  - nspace = foo       - for thrift objects and typedefs
+       *  - nspace_u = Foo     - for internal GObject prefixes
+       *  - nspace_uc = FOO_   - for macro prefixes
+       *  - nspace_lc = foo_   - for filename and method prefixes
+       * The underscores are there since uc and lc strings are used as file and
+       * variable prefixes.
+       */
+      this->nspace_u = initial_caps_to_underscores(this->nspace);
+      this->nspace_uc = to_upper_case(this->nspace_u) + "_";
+      this->nspace_lc = to_lower_case(this->nspace_u) + "_";
+    }
+  }
+
+  /* initialization and destruction */
+  void init_generator();
+  void close_generator();
+
+  /* generation functions */
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_consts(vector<t_const*> consts);
+  void generate_struct(t_struct* tstruct);
+  void generate_service(t_service* tservice);
+  void generate_xception(t_struct* tstruct);
+
+private:
+  /* file streams */
+  ofstream_with_content_based_conditional_update f_types_;
+  ofstream_with_content_based_conditional_update f_types_impl_;
+  ofstream_with_content_based_conditional_update f_header_;
+  ofstream_with_content_based_conditional_update f_service_;
+
+  /* namespace variables */
+  string nspace;
+  string nspace_u;
+  string nspace_uc;
+  string nspace_lc;
+
+  /* helper functions */
+  bool is_complex_type(t_type* ttype);
+  bool is_numeric(t_type* ttype);
+  string type_name(t_type* ttype, bool in_typedef = false, bool is_const = false);
+  string property_type_name(t_type* ttype, bool in_typedef = false, bool is_const = false);
+  string base_type_name(t_type* type);
+  string type_to_enum(t_type* type);
+  string constant_literal(t_type* type, t_const_value* value);
+  string constant_value(string name, t_type* type, t_const_value* value);
+  string constant_value_with_storage(string name, t_type* type, t_const_value* value);
+  string function_signature(t_function* tfunction);
+  string argument_list(t_struct* tstruct);
+  string xception_list(t_struct* tstruct);
+  string declare_field(t_field* tfield,
+                       bool init = false,
+                       bool pointer = false,
+                       bool constant = false,
+                       bool reference = false);
+  void declare_local_variable(ostream& out, t_type* ttype, string& base_name, bool for_hash_table);
+  void declore_local_variable_for_write(ostream& out, t_type* ttype, string& base_name);
+
+  /* generation functions */
+  void generate_const_initializer(string name,
+                                  t_type* type,
+                                  t_const_value* value,
+                                  bool top_level = false);
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_client(t_service* tservice);
+  void generate_service_handler(t_service* tservice);
+  void generate_service_processor(t_service* tservice);
+  void generate_service_server(t_service* tservice);
+  void generate_object(t_struct* tstruct);
+  void generate_struct_writer(ostream& out,
+                              t_struct* tstruct,
+                              string this_name,
+                              string this_get = "",
+                              bool is_function = true);
+  void generate_struct_reader(ostream& out,
+                              t_struct* tstruct,
+                              string this_name,
+                              string this_get = "",
+                              bool is_function = true);
+
+  void generate_serialize_field(ostream& out,
+                                t_field* tfield,
+                                string prefix,
+                                string suffix,
+                                int error_ret);
+  void generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix, int error_ret);
+  void generate_serialize_container(ostream& out, t_type* ttype, string prefix, int error_ret);
+  void generate_serialize_map_element(ostream& out,
+                                      t_map* tmap,
+                                      string key,
+                                      string value,
+                                      int error_ret);
+  void generate_serialize_set_element(ostream& out, t_set* tset, string element, int error_ret);
+  void generate_serialize_list_element(ostream& out,
+                                       t_list* tlist,
+                                       string list,
+                                       string index,
+                                       int error_ret);
+
+  void generate_deserialize_field(ostream& out,
+                                  t_field* tfield,
+                                  string prefix,
+                                  string suffix,
+                                  int error_ret,
+                                  bool allocate = true);
+  void generate_deserialize_struct(ostream& out,
+                                   t_struct* tstruct,
+                                   string prefix,
+                                   int error_ret,
+                                   bool allocate = true);
+  void generate_deserialize_container(ostream& out, t_type* ttype, string prefix, int error_ret);
+  void generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix, int error_ret);
+  void generate_deserialize_set_element(ostream& out, t_set* tset, string prefix, int error_ret);
+  void generate_deserialize_list_element(ostream& out,
+                                         t_list* tlist,
+                                         string prefix,
+                                         string index,
+                                         int error_ret);
+
+  string generate_new_hash_from_type(t_type* key, t_type* value);
+  string generate_new_array_from_type(t_type* ttype);
+
+  string generate_free_func_from_type(t_type* ttype);
+  string generate_hash_func_from_type(t_type* ttype);
+  string generate_cmp_func_from_type(t_type* ttype);
+};
+
+/**
+ * Prepare for file generation by opening up the necessary file
+ * output streams.
+ */
+void t_c_glib_generator::init_generator() {
+  /* create output directory */
+  MKDIR(get_out_dir().c_str());
+
+  string program_name_u = initial_caps_to_underscores(program_name_);
+  string program_name_uc = to_upper_case(program_name_u);
+  string program_name_lc = to_lower_case(program_name_u);
+
+  /* create output files */
+  string f_types_name = get_out_dir() + this->nspace_lc + program_name_lc + "_types.h";
+  f_types_.open(f_types_name.c_str());
+  string f_types_impl_name = get_out_dir() + this->nspace_lc + program_name_lc + "_types.c";
+  f_types_impl_.open(f_types_impl_name.c_str());
+
+  /* add thrift boilerplate headers */
+  f_types_ << autogen_comment();
+  f_types_impl_ << autogen_comment();
+
+  /* include inclusion guard */
+  f_types_ << "#ifndef " << this->nspace_uc << program_name_uc << "_TYPES_H" << endl << "#define "
+           << this->nspace_uc << program_name_uc << "_TYPES_H" << endl << endl;
+
+  /* include base types */
+  f_types_ << "/* base includes */" << endl << "#include <glib-object.h>" << endl
+           << "#include <thrift/c_glib/thrift_struct.h>" << endl
+           << "#include <thrift/c_glib/protocol/thrift_protocol.h>" << endl;
+
+  /* include other thrift includes */
+  const vector<t_program*>& includes = program_->get_includes();
+  if (!includes.empty()) {
+    f_types_ << "/* other thrift includes */" << endl;
+
+    for (vector<t_program*>::const_iterator iter = includes.begin();
+         iter != includes.end();
+         ++iter) {
+      const std::string& include_nspace = (*iter)->get_namespace("c_glib");
+      std::string include_nspace_prefix =
+        include_nspace.empty() ? "" : initial_caps_to_underscores(include_nspace) + "_";
+
+      f_types_ << "#include \"" << include_nspace_prefix
+               << initial_caps_to_underscores((*iter)->get_name()) << "_types.h\"" << endl;
+    }
+    f_types_ << endl;
+  }
+
+  /* include custom headers */
+  const vector<string>& c_includes = program_->get_c_includes();
+  f_types_ << "/* custom thrift includes */" << endl;
+  for (size_t i = 0; i < c_includes.size(); ++i) {
+    if (c_includes[i][0] == '<') {
+      f_types_ << "#include " << c_includes[i] << endl;
+    } else {
+      f_types_ << "#include \"" << c_includes[i] << "\"" << endl;
+    }
+  }
+  f_types_ << endl;
+
+  /* include math.h (for "INFINITY") in the implementation file, in case we
+     encounter a struct with a member of type double */
+  f_types_impl_ << endl << "#include <math.h>" << endl;
+
+  // include the types file
+  f_types_impl_ << endl << "#include \"" << this->nspace_lc << program_name_u << "_types.h\""
+                << endl << "#include <thrift/c_glib/thrift.h>" << endl << endl;
+
+  f_types_ << "/* begin types */" << endl << endl;
+}
+
+/**
+ *  Finish up generation and close all file streams.
+ */
+void t_c_glib_generator::close_generator() {
+  string program_name_uc = to_upper_case(initial_caps_to_underscores(program_name_));
+
+  /* end the header inclusion guard */
+  f_types_ << "#endif /* " << this->nspace_uc << program_name_uc << "_TYPES_H */" << endl;
+
+  /* close output file */
+  f_types_.close();
+  f_types_impl_.close();
+}
+
+/**
+ * Generates a Thrift typedef in C code.  For example:
+ *
+ * Thrift:
+ * typedef map<i32,i32> SomeMap
+ *
+ * C:
+ * typedef GHashTable * ThriftSomeMap;
+ */
+void t_c_glib_generator::generate_typedef(t_typedef* ttypedef) {
+  f_types_ << indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " << this->nspace
+           << ttypedef->get_symbolic() << ";" << endl << endl;
+}
+
+/**
+ * Generates a C enumeration.  For example:
+ *
+ * Thrift:
+ * enum MyEnum {
+ *   ONE = 1,
+ *   TWO
+ * }
+ *
+ * C:
+ * enum _ThriftMyEnum {
+ *   THRIFT_MY_ENUM_ONE = 1,
+ *   THRIFT_MY_ENUM_TWO
+ * };
+ * typedef enum _ThriftMyEnum ThriftMyEnum;
+ */
+void t_c_glib_generator::generate_enum(t_enum* tenum) {
+  string name = tenum->get_name();
+  string name_uc = to_upper_case(initial_caps_to_underscores(name));
+
+  f_types_ << indent() << "enum _" << this->nspace << name << " {" << endl;
+
+  indent_up();
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  bool first = true;
+
+  /* output each of the enumeration elements */
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_types_ << "," << endl;
+    }
+
+    f_types_ << indent() << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name();
+    f_types_ << " = " << (*c_iter)->get_value();
+  }
+
+  indent_down();
+  f_types_ << endl << "};" << endl << "typedef enum _" << this->nspace << name << " "
+           << this->nspace << name << ";" << endl << endl;
+
+  f_types_ << "/* return the name of the constant */" << endl;
+  f_types_ << "const char *" << endl;
+  f_types_ << "toString_" << name << "(int value); " << endl << endl;
+  ;
+  f_types_impl_ << "/* return the name of the constant */" << endl;
+  f_types_impl_ << "const char *" << endl;
+  f_types_impl_ << "toString_" << name << "(int value) " << endl;
+  f_types_impl_ << "{" << endl;
+  f_types_impl_ << "  static __thread char buf[16] = {0};" << endl;
+  f_types_impl_ << "  switch(value) {" << endl;
+  std::set<int> done;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    // Skipping duplicate value
+    if (done.find(value) == done.end()) {
+      done.insert(value);
+      f_types_impl_ << "  case " << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name()
+                    << ":"
+                    << "return \"" << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name()
+                    << "\";" << endl;
+    }
+  }
+  f_types_impl_ << "  default: g_snprintf(buf, 16, \"%d\", value); return buf;" << endl;
+  f_types_impl_ << "  }" << endl;
+  f_types_impl_ << "}" << endl << endl;
+}
+
+/**
+ * Generates Thrift constants in C code.
+ */
+void t_c_glib_generator::generate_consts(vector<t_const*> consts) {
+  f_types_ << "/* constants */" << endl;
+  f_types_impl_ << "/* constants */" << endl;
+
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    string name = (*c_iter)->get_name();
+    string name_uc = to_upper_case(name);
+    string name_lc = to_lower_case(name);
+    t_type* type = (*c_iter)->get_type();
+    t_const_value* value = (*c_iter)->get_value();
+
+    if (is_complex_type(type)) {
+      f_types_ << type_name(type) << indent() << this->nspace_lc << name_lc
+               << "_constant();" << endl;
+    }
+
+    f_types_ << indent() << "#define " << this->nspace_uc << name_uc << " "
+             << constant_value(name_lc, type, value) << endl;
+
+    generate_const_initializer(name_lc, type, value, true);
+  }
+
+  f_types_ << endl;
+  f_types_impl_ << endl;
+}
+
+/**
+ * Generate Thrift structs in C code, as GObjects.  Example:
+ *
+ * Thrift:
+ * struct Bonk
+ * {
+ *   1: string message,
+ *   2: i32 type
+ * }
+ *
+ * C GObject instance header:
+ * struct _ThriftBonk
+ * {
+ *   GObject parent;
+ *
+ *   gchar * message;
+ *   gint32 type;
+ * };
+ * typedef struct _ThriftBonk ThriftBonk
+ * // ... additional GObject boilerplate ...
+ */
+void t_c_glib_generator::generate_struct(t_struct* tstruct) {
+  f_types_ << "/* struct " << tstruct->get_name() << " */" << endl;
+  generate_object(tstruct);
+}
+
+/**
+ * Generate C code to represent Thrift services.  Creates a new GObject
+ * which can be used to access the service.
+ */
+void t_c_glib_generator::generate_service(t_service* tservice) {
+  string svcname_u = initial_caps_to_underscores(tservice->get_name());
+  string svcname_uc = this->nspace_uc + to_upper_case(svcname_u);
+  string filename = this->nspace_lc + to_lower_case(svcname_u);
+
+  // make output files
+  string f_header_name = get_out_dir() + filename + ".h";
+  f_header_.open(f_header_name.c_str());
+
+  string program_name_u = initial_caps_to_underscores(program_name_);
+  string program_name_lc = to_lower_case(program_name_u);
+
+  // add header file boilerplate
+  f_header_ << autogen_comment();
+
+  // add an inclusion guard
+  f_header_ << "#ifndef " << svcname_uc << "_H" << endl << "#define " << svcname_uc << "_H" << endl
+            << endl;
+
+  // add standard includes
+  f_header_ << "#include <thrift/c_glib/processor/thrift_dispatch_processor.h>" << endl << endl;
+  f_header_ << "#include \"" << this->nspace_lc << program_name_lc << "_types.h\"" << endl;
+
+  // if we are inheriting from another service, include its header
+  t_service* extends_service = tservice->get_extends();
+  if (extends_service != NULL) {
+    f_header_ << "#include \"" << this->nspace_lc
+              << to_lower_case(initial_caps_to_underscores(extends_service->get_name())) << ".h\""
+              << endl;
+  }
+  f_header_ << endl;
+
+  // create the service implementation
+  string f_service_name = get_out_dir() + filename + ".c";
+  f_service_.open(f_service_name.c_str());
+
+  // add the boilerplace header
+  f_service_ << autogen_comment();
+
+  // include the headers
+  f_service_ << "#include <string.h>" << endl << "#include <thrift/c_glib/thrift.h>" << endl
+             << "#include <thrift/c_glib/thrift_application_exception.h>" << endl << "#include \""
+             << filename << ".h\"" << endl << endl;
+
+  // generate the service-helper classes
+  generate_service_helpers(tservice);
+
+  // generate the client objects
+  generate_service_client(tservice);
+
+  // generate the server objects
+  generate_service_server(tservice);
+
+  // end the header inclusion guard
+  f_header_ << "#endif /* " << svcname_uc << "_H */" << endl;
+
+  // close the files
+  f_service_.close();
+  f_header_.close();
+}
+
+/**
+ *
+ */
+void t_c_glib_generator::generate_xception(t_struct* tstruct) {
+  string name = tstruct->get_name();
+  string name_u = initial_caps_to_underscores(name);
+  string name_lc = to_lower_case(name_u);
+  string name_uc = to_upper_case(name_u);
+
+  generate_object(tstruct);
+
+  f_types_ << "/* exception */" << endl
+           << "typedef enum" << endl
+           << "{" << endl;
+  indent_up();
+  f_types_ << indent() << this->nspace_uc << name_uc << "_ERROR_CODE" << endl;
+  indent_down();
+  f_types_ << "} " << this->nspace << name << "Error;" << endl
+           << endl
+           << "GQuark " << this->nspace_lc << name_lc
+           << "_error_quark (void);" << endl
+           << "#define " << this->nspace_uc << name_uc << "_ERROR ("
+           << this->nspace_lc << name_lc << "_error_quark())" << endl
+           << endl
+           << endl;
+
+  f_types_impl_ << "/* define the GError domain for exceptions */" << endl << "#define "
+                << this->nspace_uc << name_uc << "_ERROR_DOMAIN \"" << this->nspace_lc << name_lc
+                << "_error_quark\"" << endl << "GQuark" << endl << this->nspace_lc << name_lc
+                << "_error_quark (void)" << endl << "{" << endl
+                << "  return g_quark_from_static_string (" << this->nspace_uc << name_uc
+                << "_ERROR_DOMAIN);" << endl << "}" << endl << endl;
+}
+
+/********************
+ * HELPER FUNCTIONS *
+ ********************/
+
+/**
+ * Returns true if ttype is not a primitive.
+ */
+bool t_c_glib_generator::is_complex_type(t_type* ttype) {
+  ttype = get_true_type(ttype);
+
+  return ttype->is_container() || ttype->is_struct() || ttype->is_xception();
+}
+
+bool t_c_glib_generator::is_numeric(t_type* ttype) {
+  return ttype->is_enum() || (ttype->is_base_type() && !ttype->is_string());
+}
+
+/**
+ * Maps a Thrift t_type to a C type.
+ */
+string t_c_glib_generator::type_name(t_type* ttype, bool in_typedef, bool is_const) {
+  if (ttype->is_base_type()) {
+    string bname = base_type_name(ttype);
+
+    if (is_const) {
+      return "const " + bname;
+    } else {
+      return bname;
+    }
+  }
+
+  if (ttype->is_container()) {
+    string cname;
+
+    t_container* tcontainer = (t_container*)ttype;
+    if (tcontainer->has_cpp_name()) {
+      cname = tcontainer->get_cpp_name();
+    } else if (ttype->is_map()) {
+      cname = "GHashTable";
+    } else if (ttype->is_set()) {
+      // since a set requires unique elements, use a GHashTable, and
+      // populate the keys and values with the same data, using keys for
+      // the actual writes and reads.
+      // TODO: discuss whether or not to implement TSet, THashSet or GHashSet
+      cname = "GHashTable";
+    } else if (ttype->is_list()) {
+      t_type* etype = get_true_type(((t_list*)ttype)->get_elem_type());
+      if (etype->is_void()) {
+        throw std::runtime_error("compiler error: list element type cannot be void");
+      }
+      // TODO: investigate other implementations besides GPtrArray
+      cname = is_numeric(etype) ? "GArray" : "GPtrArray";
+    }
+
+    /* Omit the dereference operator if we are aliasing this type within a
+       typedef, to allow the type to be used more naturally in client code;
+       otherwise, include it */
+    if (!in_typedef) {
+      cname += " *";
+    }
+
+    if (is_const) {
+      return "const " + cname;
+    } else {
+      return cname;
+    }
+  }
+
+  // check for a namespace
+  t_program* tprogram = ttype->get_program();
+  string pname = (tprogram ? tprogram->get_namespace("c_glib") : "") + ttype->get_name();
+
+  if (is_complex_type(ttype)) {
+    pname += " *";
+  }
+
+  if (is_const) {
+    return "const " + pname;
+  } else {
+    return pname;
+  }
+}
+
+/**
+ * Maps a Thrift primitive to the type needed to hold its value when used as an
+ * object property.
+ *
+ * This method is needed because all integer properties of width less than 64
+ * bits map to the same type, gint, as opposed to their width-specific type
+ * (gint8, gint16 or gint32).
+ */
+string t_c_glib_generator::property_type_name(t_type* ttype, bool in_typedef, bool is_const) {
+  string result;
+
+  if (ttype->is_base_type()) {
+    switch (((t_base_type*)ttype)->get_base()) {
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+      if (is_const) {
+        result = "const gint";
+      } else {
+        result = "gint";
+      }
+      break;
+
+    default:
+      result = type_name(ttype, in_typedef, is_const);
+    }
+  } else {
+    result = type_name(ttype, in_typedef, is_const);
+  }
+
+  return result;
+}
+
+/**
+ * Maps a Thrift primitive to a C primitive.
+ */
+string t_c_glib_generator::base_type_name(t_type* type) {
+  if (type->is_enum()) {
+    return type_name(type);
+  }
+  if (!type->is_base_type()) {
+    throw std::invalid_argument("Only base types are suppported.");
+  }
+  t_base_type* base_type = reinterpret_cast<t_base_type*>(type);
+  t_base_type::t_base tbase = base_type->get_base();
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    if (base_type->is_binary()) {
+      return "GByteArray *";
+    } else {
+      return "gchar *";
+    }
+  case t_base_type::TYPE_BOOL:
+    return "gboolean";
+  case t_base_type::TYPE_I8:
+    return "gint8";
+  case t_base_type::TYPE_I16:
+    return "gint16";
+  case t_base_type::TYPE_I32:
+    return "gint32";
+  case t_base_type::TYPE_I64:
+    return "gint64";
+  case t_base_type::TYPE_DOUBLE:
+    return "gdouble";
+  default:
+    throw std::logic_error("compiler error: no C base type name for base type "
+                           + t_base_type::t_base_name(tbase));
+  }
+}
+
+/**
+ * Returns a member of the ThriftType C enumeration in thrift_protocol.h
+ * for a Thrift type.
+ */
+string t_c_glib_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 "T_STRING";
+    case t_base_type::TYPE_BOOL:
+      return "T_BOOL";
+    case t_base_type::TYPE_I8:
+      return "T_BYTE";
+    case t_base_type::TYPE_I16:
+      return "T_I16";
+    case t_base_type::TYPE_I32:
+      return "T_I32";
+    case t_base_type::TYPE_I64:
+      return "T_I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "T_DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "T_I32";
+  } else if (type->is_struct()) {
+    return "T_STRUCT";
+  } else if (type->is_xception()) {
+    return "T_STRUCT";
+  } else if (type->is_map()) {
+    return "T_MAP";
+  } else if (type->is_set()) {
+    return "T_SET";
+  } else if (type->is_list()) {
+    return "T_LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Returns a Thrift constant formatted as a literal for inclusion in C code.
+ */
+string t_c_glib_generator::constant_literal(t_type* type, t_const_value* value) {
+  ostringstream render;
+
+  if (type->is_base_type()) {
+    /* primitives */
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      render << "\"" + value->get_string() + "\"";
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() != 0) ? "TRUE" : "FALSE");
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      render << value->get_double();
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else {
+    t_const_value::t_const_value_type value_type = value->get_type();
+
+    switch (value_type) {
+    case t_const_value::CV_IDENTIFIER:
+      render << value->get_integer();
+      break;
+    case t_const_value::CV_LIST:
+      render << "{ ";
+      {
+        t_type* elem_type = ((t_list*)type)->get_elem_type();
+        const vector<t_const_value*>& list = value->get_list();
+        vector<t_const_value*>::const_iterator list_iter;
+
+        if (list.size() > 0) {
+          list_iter = list.begin();
+          render << constant_literal(elem_type, *list_iter);
+
+          while (++list_iter != list.end()) {
+            render << ", " << constant_literal(elem_type, *list_iter);
+          }
+        }
+      }
+      render << " }";
+      break;
+    case t_const_value::CV_MAP:
+    default:
+      render << "NULL /* not supported */";
+    }
+  }
+
+  return render.str();
+}
+
+/**
+ * Returns C code that represents a Thrift constant.
+ */
+string t_c_glib_generator::constant_value(string name, t_type* type, t_const_value* value) {
+  ostringstream render;
+
+  if (type->is_base_type()) {
+    /* primitives */
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      render << "g_strdup (\"" + value->get_string() + "\")";
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() != 0) ? 1 : 0);
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_I64:
+      render << "G_GINT64_CONSTANT (" << value->get_integer() << ")";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << value->get_integer();
+      } else {
+        render << 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()) {
+    render << "(" << type_name(type) << ")" << value->get_integer();
+  } else if (is_complex_type(type)) {
+    render << "(" << this->nspace_lc << to_lower_case(name) << "_constant())";
+  } else {
+    render << "NULL /* not supported */";
+  }
+
+  return render.str();
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_c_glib_generator::function_signature(t_function* tfunction) {
+  t_type* ttype = tfunction->get_returntype();
+  t_struct* arglist = tfunction->get_arglist();
+  t_struct* xlist = tfunction->get_xceptions();
+  string fname = initial_caps_to_underscores(tfunction->get_name());
+
+  bool has_return = !ttype->is_void();
+  bool has_args = arglist->get_members().size() == 0;
+  bool has_xceptions = xlist->get_members().size() == 0;
+  return "gboolean " + this->nspace_lc + fname + " (" + this->nspace + service_name_ + "If * iface"
+         + (has_return ? ", " + type_name(ttype) + "* _return" : "")
+         + (has_args ? "" : (", " + argument_list(arglist)))
+         + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError ** error)";
+}
+
+/**
+ * Renders a field list
+ *
+ * @param tstruct The struct definition
+ * @return Comma sepearated list of all field names in that struct
+ */
+string t_c_glib_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 += type_name((*f_iter)->get_type(), false, true) + " " + (*f_iter)->get_name();
+  }
+  return result;
+}
+
+/**
+ * Renders mutable exception lists
+ *
+ * @param tstruct The struct definition
+ * @return Comma sepearated list of all field names in that struct
+ */
+string t_c_glib_generator::xception_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 += type_name((*f_iter)->get_type(), false, false) + "* " + (*f_iter)->get_name();
+  }
+  return result;
+}
+
+/**
+ * Declares a field, including any necessary initialization.
+ */
+string t_c_glib_generator::declare_field(t_field* tfield,
+                                         bool init,
+                                         bool pointer,
+                                         bool constant,
+                                         bool reference) {
+  string result = "";
+  if (constant) {
+    result += "const ";
+  }
+  result += type_name(tfield->get_type());
+  if (pointer) {
+    result += "*";
+  }
+  if (reference) {
+    result += "*";
+  }
+  result += " " + tfield->get_name();
+  if (init) {
+    t_type* type = get_true_type(tfield->get_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:
+        break;
+      case t_base_type::TYPE_BOOL:
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = (gdouble) 0";
+        break;
+      case t_base_type::TYPE_STRING:
+        result += " = NULL";
+        break;
+      default:
+        throw "compiler error: no C intializer for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      result += " = (" + type_name(type) + ") 0";
+    } else if (type->is_struct() || type->is_container()) {
+      result += " = NULL";
+    }
+  }
+
+  if (!reference) {
+    result += ";";
+  }
+
+  return result;
+}
+
+string t_c_glib_generator::constant_value_with_storage(string fname,
+                                                       t_type* etype,
+                                                       t_const_value* value) {
+  ostringstream render;
+  if (is_numeric(etype)) {
+    render << "    " << type_name(etype) << " *" << fname << " = "
+           << "g_new (" << base_type_name(etype) << ", 1);" << endl
+           << "    *" << fname << " = " << constant_value(fname, (t_type*)etype, value) << ";"
+           << endl;
+  } else {
+    render << "    " << type_name(etype) << " " << fname << " = "
+           << constant_value(fname, (t_type*)etype, value) << ";" << endl;
+  }
+  return render.str();
+}
+
+/**
+ * Generates C code that initializes complex constants.
+ */
+void t_c_glib_generator::generate_const_initializer(string name,
+                                                    t_type* type,
+                                                    t_const_value* value,
+                                                    bool top_level) {
+  string name_u = initial_caps_to_underscores(name);
+  string name_lc = to_lower_case(name_u);
+  string type_u = initial_caps_to_underscores(type->get_name());
+  string type_uc = to_upper_case(type_u);
+  string maybe_static = top_level ? "" : "static ";
+
+  if (type->is_struct() || type->is_xception()) {
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    ostringstream initializers;
+
+    // initialize any constants that may be referenced by this initializer
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_type* field_type = NULL;
+      string field_name = "";
+
+      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();
+          field_name = (*f_iter)->get_name();
+          break;
+        }
+      }
+      if (field_type == NULL) {
+        throw "type error: " + type->get_name() + " has no field "
+          + v_iter->first->get_string();
+      }
+      field_name = tmp(field_name);
+
+      generate_const_initializer(name + "_constant_" + field_name,
+                                 field_type,
+                                 v_iter->second);
+      initializers << "    constant->" << v_iter->first->get_string() << " = "
+                   << constant_value(name + "_constant_" + field_name,
+                                     field_type,
+                                     v_iter->second) << ";" << endl
+                   << "    constant->__isset_" << v_iter->first->get_string()
+                   << " = TRUE;" << endl;
+    }
+
+    // implement the initializer
+    f_types_impl_ << maybe_static << this->nspace << type->get_name() << " *"
+                  << endl
+                  << this->nspace_lc << name_lc << "_constant (void)" << endl;
+    scope_up(f_types_impl_);
+    f_types_impl_ << indent() << "static " << this->nspace << type->get_name()
+                  << " *constant = NULL;" << endl
+                  << indent() << "if (constant == NULL)" << endl;
+    scope_up(f_types_impl_);
+    f_types_impl_ << indent() << "constant = g_object_new (" << this->nspace_uc
+                  << "TYPE_" << type_uc << ", NULL);" << endl
+                  << initializers.str();
+    scope_down(f_types_impl_);
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_type* field_type = NULL;
+      string field_name = "";
+
+      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();
+          field_name = (*f_iter)->get_name();
+          break;
+        }
+      }
+      if (field_type == NULL) {
+        throw "type error: " + type->get_name() + " has no field "
+          + v_iter->first->get_string();
+      }
+      field_name = tmp(field_name);
+    }
+
+    f_types_impl_ << indent() << "return constant;" << endl;
+    scope_down(f_types_impl_);
+    f_types_impl_ << endl;
+  } else if (type->is_list()) {
+    string list_type = "GPtrArray *";
+    string free_func
+        = generate_free_func_from_type(reinterpret_cast<t_list*>(type)->get_elem_type());
+    string list_initializer = "g_ptr_array_new_with_free_func (" + free_func + ");";
+    string list_appender = "g_ptr_array_add";
+    bool list_variable = false;
+
+    t_type* etype = ((t_list*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    ostringstream initializers;
+    ostringstream appenders;
+
+    list_initializer = generate_new_array_from_type(etype);
+    if (etype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)etype)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "compiler error: cannot determine array type";
+      case t_base_type::TYPE_BOOL:
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+      case t_base_type::TYPE_DOUBLE:
+        list_type = "GArray *";
+        list_appender = "g_array_append_val";
+        list_variable = true;
+        break;
+      case t_base_type::TYPE_STRING:
+        break;
+      default:
+        throw "compiler error: no array info for type";
+      }
+    } else if (etype->is_enum()) {
+      list_type = "GArray *";
+      list_appender = "g_array_append_val";
+      list_variable = true;
+    }
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string fname = tmp(name);
+
+      generate_const_initializer(fname, etype, (*v_iter));
+      if (list_variable) {
+        initializers << "    " << type_name(etype) << " " << fname << " = "
+                     << constant_value(fname, (t_type*)etype, (*v_iter)) << ";"
+                     << endl;
+        appenders << "    " << list_appender << "(constant, " << fname << ");"
+                  << endl;
+      } else {
+        appenders << "    " << list_appender << "(constant, "
+                  << constant_value(fname, (t_type*)etype, (*v_iter)) << ");"
+                  << endl;
+      }
+    }
+
+    f_types_impl_ << maybe_static << list_type << endl
+                  << this->nspace_lc << name_lc << "_constant (void)" << endl;
+    scope_up(f_types_impl_);
+    f_types_impl_ << indent() << "static " << list_type << " constant = NULL;"
+                  << endl
+                  << indent() << "if (constant == NULL)" << endl;
+    scope_up(f_types_impl_);
+    if (!initializers.str().empty()) {
+      f_types_impl_ << initializers.str()
+                    << endl;
+    }
+    f_types_impl_ << indent() << "constant = " << list_initializer << endl
+                  << appenders.str();
+    scope_down(f_types_impl_);
+    f_types_impl_ << indent() << "return constant;" << endl;
+    scope_down(f_types_impl_);
+    f_types_impl_ << endl;
+  } else if (type->is_set()) {
+    t_type* etype = ((t_set*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    ostringstream initializers;
+    ostringstream appenders;
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string fname = tmp(name);
+      string ptr = is_numeric(etype) ? "*" : "";
+      generate_const_initializer(fname, etype, (*v_iter));
+      initializers << constant_value_with_storage(fname, (t_type*)etype, *v_iter);
+      appenders << "    g_hash_table_insert (constant, " << fname << ", 0);" << endl;
+    }
+
+    f_types_impl_ << maybe_static << "GHashTable *" << endl
+                  << this->nspace_lc << name_lc << "_constant (void)" << endl;
+    scope_up(f_types_impl_);
+    f_types_impl_ << indent() << "static GHashTable *constant = NULL;" << endl
+                  << indent() << "if (constant == NULL)" << endl;
+    scope_up(f_types_impl_);
+    f_types_impl_ << initializers.str() << endl
+                  << indent() << "constant = " << generate_new_hash_from_type(etype, NULL) << endl
+                  << appenders.str();
+    scope_down(f_types_impl_);
+    f_types_impl_ << indent() << "return constant;" << endl;
+    scope_down(f_types_impl_);
+    f_types_impl_ << endl;
+  } 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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    ostringstream initializers;
+    ostringstream appenders;
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string fname = tmp(name);
+      string kname = fname + "key";
+      string vname = fname + "val";
+      generate_const_initializer(kname, ktype, v_iter->first);
+      generate_const_initializer(vname, vtype, v_iter->second);
+
+      initializers << constant_value_with_storage(kname, (t_type*)ktype, v_iter->first);
+      initializers << constant_value_with_storage(vname, (t_type*)vtype, v_iter->second);
+      appenders << "    g_hash_table_insert (constant, " << kname << ", " << vname << ");" << endl;
+    }
+
+    f_types_impl_ << maybe_static << "GHashTable *" << endl
+                  << this->nspace_lc << name_lc << "_constant (void)" << endl;
+    scope_up(f_types_impl_);
+    f_types_impl_ << indent() << "static GHashTable *constant = NULL;" << endl
+                  << indent() << "if (constant == NULL)" << endl;
+    scope_up(f_types_impl_);
+    f_types_impl_ << initializers.str() << endl
+                  << indent() << "constant = " << generate_new_hash_from_type(ktype, vtype) << endl
+                  << appenders.str();
+    scope_down(f_types_impl_);
+    f_types_impl_ << indent() << "return constant;" << endl;
+    scope_down(f_types_impl_);
+    f_types_impl_ << endl;
+  }
+}
+
+/**
+ * Generates helper classes for a service, consisting of a ThriftStruct subclass
+ * for the arguments to and the result from each method.
+ *
+ * @param tservice The service for which to generate helper classes
+ */
+void t_c_glib_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator function_iter;
+
+  // Iterate through the service's methods
+  for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
+    string function_name = (*function_iter)->get_name();
+    t_struct* arg_list = (*function_iter)->get_arglist();
+    string arg_list_name_orig = arg_list->get_name();
+
+    // Generate the arguments class
+    arg_list->set_name(tservice->get_name() + underscores_to_initial_caps(function_name) + "Args");
+    generate_struct(arg_list);
+
+    arg_list->set_name(arg_list_name_orig);
+
+    // Generate the result class
+    if (!(*function_iter)->is_oneway()) {
+      t_struct result(program_,
+                      tservice->get_name() + underscores_to_initial_caps(function_name) + "Result");
+      t_field success((*function_iter)->get_returntype(), "success", 0);
+      success.set_req(t_field::T_OPTIONAL);
+      if (!(*function_iter)->get_returntype()->is_void()) {
+        result.append(&success);
+      }
+
+      t_struct* xs = (*function_iter)->get_xceptions();
+      const vector<t_field*>& fields = xs->get_members();
+      vector<t_field*>::const_iterator field_iter;
+      for (field_iter = fields.begin(); field_iter != fields.end(); ++field_iter) {
+        (*field_iter)->set_req(t_field::T_OPTIONAL);
+        result.append(*field_iter);
+      }
+
+      generate_struct(&result);
+    }
+  }
+}
+
+/**
+ * Generates C code that represents a Thrift service client.
+ */
+void t_c_glib_generator::generate_service_client(t_service* tservice) {
+  /* get some C friendly service names */
+  string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_));
+  string service_name_uc = to_upper_case(service_name_lc);
+
+  string parent_service_name;
+  string parent_service_name_lc;
+  string parent_service_name_uc;
+
+  string parent_class_name = "GObject";
+  string parent_type_name = "G_TYPE_OBJECT";
+
+  // The service this service extends, or NULL if it extends no
+  // service
+  t_service* extends_service = tservice->get_extends();
+  if (extends_service) {
+    // The name of the parent service
+    parent_service_name = extends_service->get_name();
+    parent_service_name_lc = to_lower_case(initial_caps_to_underscores(parent_service_name));
+    parent_service_name_uc = to_upper_case(parent_service_name_lc);
+
+    // The names of the client class' parent class and type
+    parent_class_name = this->nspace + parent_service_name + "Client";
+    parent_type_name = this->nspace_uc + "TYPE_" + parent_service_name_uc + "_CLIENT";
+  }
+
+  // The base service (the topmost in the "extends" hierarchy), on
+  // whose client class the "input_protocol" and "output_protocol"
+  // properties are defined
+  t_service* base_service = tservice;
+  while (base_service->get_extends()) {
+    base_service = base_service->get_extends();
+  }
+
+  string base_service_name = base_service->get_name();
+  string base_service_name_lc = to_lower_case(initial_caps_to_underscores(base_service_name));
+  string base_service_name_uc = to_upper_case(base_service_name_lc);
+
+  // Generate the client interface dummy object in the header.
+  f_header_ << "/* " << service_name_ << " service interface */" << endl << "typedef struct _"
+            << this->nspace << service_name_ << "If " << this->nspace << service_name_ << "If; "
+            << " /* dummy object */" << endl << endl;
+
+  // Generate the client interface object in the header.
+  f_header_ << "struct _" << this->nspace << service_name_ << "IfInterface" << endl << "{" << endl
+            << "  GTypeInterface parent;" << endl << endl;
+
+  /* write out the functions for this interface */
+  indent_up();
+  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) {
+    /* make the function name C friendly */
+    string funname = initial_caps_to_underscores((*f_iter)->get_name());
+    t_type* ttype = (*f_iter)->get_returntype();
+    t_struct* arglist = (*f_iter)->get_arglist();
+    t_struct* xlist = (*f_iter)->get_xceptions();
+    bool has_return = !ttype->is_void();
+    bool has_args = arglist->get_members().size() == 0;
+    bool has_xceptions = xlist->get_members().size() == 0;
+
+    string params = "(" + this->nspace + service_name_ + "If *iface"
+                    + (has_return ? ", " + type_name(ttype) + "* _return" : "")
+                    + (has_args ? "" : (", " + argument_list(arglist)))
+                    + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError **error)";
+
+    indent(f_header_) << "gboolean (*" << funname << ") " << params << ";" << endl;
+  }
+  indent_down();
+
+  f_header_ << "};" << endl << "typedef struct _" << this->nspace << service_name_ << "IfInterface "
+            << this->nspace << service_name_ << "IfInterface;" << endl << endl;
+
+  // generate all the interface boilerplate
+  f_header_ << "GType " << this->nspace_lc << service_name_lc << "_if_get_type (void);" << endl
+            << "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_IF "
+            << "(" << this->nspace_lc << service_name_lc << "_if_get_type())" << endl << "#define "
+            << this->nspace_uc << service_name_uc << "_IF(obj) "
+            << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_"
+            << service_name_uc << "_IF, " << this->nspace << service_name_ << "If))" << endl
+            << "#define " << this->nspace_uc << "IS_" << service_name_uc << "_IF(obj) "
+            << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_"
+            << service_name_uc << "_IF))" << endl << "#define " << this->nspace_uc
+            << service_name_uc << "_IF_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), "
+            << this->nspace_uc << "TYPE_" << service_name_uc << "_IF, " << this->nspace
+            << service_name_ << "IfInterface))" << endl << endl;
+
+  // write out all the interface function prototypes
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    /* make the function name C friendly */
+    string funname = initial_caps_to_underscores((*f_iter)->get_name());
+    t_type* ttype = (*f_iter)->get_returntype();
+    t_struct* arglist = (*f_iter)->get_arglist();
+    t_struct* xlist = (*f_iter)->get_xceptions();
+    bool has_return = !ttype->is_void();
+    bool has_args = arglist->get_members().size() == 0;
+    bool has_xceptions = xlist->get_members().size() == 0;
+
+    string params = "(" + this->nspace + service_name_ + "If *iface"
+                    + (has_return ? ", " + type_name(ttype) + "* _return" : "")
+                    + (has_args ? "" : (", " + argument_list(arglist)))
+                    + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError **error)";
+
+    f_header_ << "gboolean " << this->nspace_lc << service_name_lc << "_if_" << funname << " "
+              << params << ";" << endl;
+  }
+  f_header_ << endl;
+
+  // Generate the client object instance definition in the header.
+  f_header_ << "/* " << service_name_ << " service client */" << endl << "struct _" << this->nspace
+            << service_name_ << "Client" << endl << "{" << endl << "  " << parent_class_name
+            << " parent;" << endl;
+  if (!extends_service) {
+    // Define "input_protocol" and "output_protocol" properties only
+    // for base services; child service-client classes will inherit
+    // these
+    f_header_ << endl << "  ThriftProtocol *input_protocol;" << endl
+              << "  ThriftProtocol *output_protocol;" << endl;
+  }
+  f_header_ << "};" << endl << "typedef struct _" << this->nspace << service_name_ << "Client "
+            << this->nspace << service_name_ << "Client;" << endl << endl;
+
+  // Generate the class definition in the header.
+  f_header_ << "struct _" << this->nspace << service_name_ << "ClientClass" << endl << "{" << endl
+            << "  " << parent_class_name << "Class parent;" << endl << "};" << endl
+            << "typedef struct _" << this->nspace << service_name_ << "ClientClass " << this->nspace
+            << service_name_ << "ClientClass;" << endl << endl;
+
+  // Create all the GObject boilerplate
+  f_header_ << "GType " << this->nspace_lc << service_name_lc << "_client_get_type (void);" << endl
+            << "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT "
+            << "(" << this->nspace_lc << service_name_lc << "_client_get_type())" << endl
+            << "#define " << this->nspace_uc << service_name_uc << "_CLIENT(obj) "
+            << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_"
+            << service_name_uc << "_CLIENT, " << this->nspace << service_name_ << "Client))" << endl
+            << "#define " << this->nspace_uc << service_name_uc << "_CLIENT_CLASS(c) "
+            << "(G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_" << service_name_uc
+            << "_CLIENT, " << this->nspace << service_name_ << "ClientClass))" << endl << "#define "
+            << this->nspace_uc << service_name_uc << "_IS_CLIENT(obj) "
+            << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_"
+            << service_name_uc << "_CLIENT))" << endl << "#define " << this->nspace_uc
+            << service_name_uc << "_IS_CLIENT_CLASS(c) "
+            << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << service_name_uc
+            << "_CLIENT))" << endl << "#define " << this->nspace_uc << service_name_uc
+            << "_CLIENT_GET_CLASS(obj) "
+            << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_"
+            << service_name_uc << "_CLIENT, " << this->nspace << service_name_ << "ClientClass))"
+            << endl << endl;
+
+  /* write out the function prototypes */
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    /* make the function name C friendly */
+    string funname = to_lower_case(initial_caps_to_underscores((*f_iter)->get_name()));
+
+    t_function service_function((*f_iter)->get_returntype(),
+                                service_name_lc + string("_client_") + funname,
+                                (*f_iter)->get_arglist(),
+                                (*f_iter)->get_xceptions());
+    indent(f_header_) << function_signature(&service_function) << ";" << endl;
+
+    t_function send_function(g_type_void,
+                             service_name_lc + string("_client_send_") + funname,
+                             (*f_iter)->get_arglist());
+    indent(f_header_) << function_signature(&send_function) << ";" << endl;
+
+    // implement recv if not a oneway service
+    if (!(*f_iter)->is_oneway()) {
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+                               service_name_lc + string("_client_recv_") + funname,
+                               &noargs,
+                               (*f_iter)->get_xceptions());
+      indent(f_header_) << function_signature(&recv_function) << ";" << endl;
+    }
+  }
+
+  /* write out the get/set function prototypes */
+  f_header_ << "void " + service_name_lc + "_client_set_property (GObject *object, guint "
+                                           "property_id, const GValue *value, GParamSpec *pspec);"
+            << endl;
+  f_header_ << "void " + service_name_lc + "_client_get_property (GObject *object, guint "
+                                           "property_id, GValue *value, GParamSpec *pspec);"
+            << endl;
+
+  f_header_ << endl;
+  // end of header code
+
+  // Generate interface method implementations
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    /* make the function name C friendly */
+    string funname = initial_caps_to_underscores((*f_iter)->get_name());
+    t_type* ttype = (*f_iter)->get_returntype();
+    t_struct* arglist = (*f_iter)->get_arglist();
+    t_struct* xlist = (*f_iter)->get_xceptions();
+    bool has_return = !ttype->is_void();
+    bool has_args = arglist->get_members().size() == 0;
+    bool has_xceptions = xlist->get_members().size() == 0;
+
+    string params = "(" + this->nspace + service_name_ + "If *iface"
+                    + (has_return ? ", " + type_name(ttype) + "* _return" : "")
+                    + (has_args ? "" : (", " + argument_list(arglist)))
+                    + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError **error)";
+
+    string params_without_type = string("iface, ") + (has_return ? "_return, " : "");
+
+    const vector<t_field*>& fields = arglist->get_members();
+    vector<t_field*>::const_iterator f_iter_field;
+    for (f_iter_field = fields.begin(); f_iter_field != fields.end(); ++f_iter_field) {
+      params_without_type += (*f_iter_field)->get_name();
+      params_without_type += ", ";
+    }
+
+    const vector<t_field*>& xceptions = xlist->get_members();
+    vector<t_field*>::const_iterator x_iter;
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      params_without_type += (*x_iter)->get_name();
+      params_without_type += ", ";
+    }
+
+    f_service_ << "gboolean" << endl << this->nspace_lc << service_name_lc << "_if_" << funname
+               << " " << params << endl << "{" << endl << "  return " << this->nspace_uc
+               << service_name_uc << "_IF_GET_INTERFACE (iface)->" << funname << " ("
+               << params_without_type << "error);" << endl << "}" << endl << endl;
+  }
+
+  // Generate interface boilerplate
+  f_service_ << "GType" << endl << this->nspace_lc << service_name_lc << "_if_get_type (void)"
+             << endl << "{" << endl << "  static GType type = 0;" << endl << "  if (type == 0)"
+             << endl << "  {" << endl << "    static const GTypeInfo type_info =" << endl << "    {"
+             << endl << "      sizeof (" << this->nspace << service_name_ << "IfInterface)," << endl
+             << "      NULL,  /* base_init */" << endl << "      NULL,  /* base_finalize */" << endl
+             << "      NULL,  /* class_init */" << endl << "      NULL,  /* class_finalize */"
+             << endl << "      NULL,  /* class_data */" << endl
+             << "      0,     /* instance_size */" << endl << "      0,     /* n_preallocs */"
+             << endl << "      NULL,  /* instance_init */" << endl
+             << "      NULL   /* value_table */" << endl << "    };" << endl
+             << "    type = g_type_register_static (G_TYPE_INTERFACE," << endl
+             << "                                   \"" << this->nspace << service_name_ << "If\","
+             << endl << "                                   &type_info, 0);" << endl << "  }"
+             << endl << "  return type;" << endl << "}" << endl << endl;
+
+  // Generate client boilerplate
+  f_service_ << "static void " << endl << this->nspace_lc << service_name_lc
+             << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface);"
+             << endl << endl << "G_DEFINE_TYPE_WITH_CODE (" << this->nspace << service_name_
+             << "Client, " << this->nspace_lc << service_name_lc << "_client," << endl
+             << "                         " << parent_type_name << ", " << endl
+             << "                         G_IMPLEMENT_INTERFACE (" << this->nspace_uc << "TYPE_"
+             << service_name_uc << "_IF," << endl
+             << "                                                " << this->nspace_lc
+             << service_name_lc << "_if_interface_init))" << endl << endl;
+
+  // Generate property-related code only for base services---child
+  // service-client classes have only properties inherited from their
+  // parent class
+  if (!extends_service) {
+    // Generate client properties
+    f_service_ << "enum _" << this->nspace << service_name_ << "ClientProperties" << endl << "{"
+               << endl << "  PROP_0," << endl << "  PROP_" << this->nspace_uc << service_name_uc
+               << "_CLIENT_INPUT_PROTOCOL," << endl << "  PROP_" << this->nspace_uc
+               << service_name_uc << "_CLIENT_OUTPUT_PROTOCOL" << endl << "};" << endl << endl;
+
+    // generate property setter
+    f_service_ << "void" << endl << this->nspace_lc << service_name_lc << "_client_set_property ("
+               << "GObject *object, guint property_id, const GValue *value, "
+               << "GParamSpec *pspec)" << endl << "{" << endl << "  " << this->nspace
+               << service_name_ << "Client *client = " << this->nspace_uc << service_name_uc
+               << "_CLIENT (object);" << endl << endl << "  THRIFT_UNUSED_VAR (pspec);" << endl
+               << endl << "  switch (property_id)" << endl << "  {" << endl << "    case PROP_"
+               << this->nspace_uc << service_name_uc << "_CLIENT_INPUT_PROTOCOL:" << endl
+               << "      client->input_protocol = g_value_get_object (value);" << endl
+               << "      break;" << endl << "    case PROP_" << this->nspace_uc << service_name_uc
+               << "_CLIENT_OUTPUT_PROTOCOL:" << endl
+               << "      client->output_protocol = g_value_get_object (value);" << endl
+               << "      break;" << endl << "  }" << endl << "}" << endl << endl;
+
+    // generate property getter
+    f_service_ << "void" << endl << this->nspace_lc << service_name_lc << "_client_get_property ("
+               << "GObject *object, guint property_id, GValue *value, "
+               << "GParamSpec *pspec)" << endl << "{" << endl << "  " << this->nspace
+               << service_name_ << "Client *client = " << this->nspace_uc << service_name_uc
+               << "_CLIENT (object);" << endl << endl << "  THRIFT_UNUSED_VAR (pspec);" << endl
+               << endl << "  switch (property_id)" << endl << "  {" << endl << "    case PROP_"
+               << this->nspace_uc << service_name_uc << "_CLIENT_INPUT_PROTOCOL:" << endl
+               << "      g_value_set_object (value, client->input_protocol);" << endl
+               << "      break;" << endl << "    case PROP_" << this->nspace_uc << service_name_uc
+               << "_CLIENT_OUTPUT_PROTOCOL:" << endl
+               << "      g_value_set_object (value, client->output_protocol);" << endl
+               << "      break;" << endl << "  }" << endl << "}" << endl << endl;
+  }
+
+  // Generate client method implementations
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string name = (*f_iter)->get_name();
+    string funname = initial_caps_to_underscores(name);
+
+    // Get the struct of function call params and exceptions
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+
+    // Function for sending
+    t_function send_function(g_type_void,
+                             service_name_lc + string("_client_send_") + funname,
+                             (*f_iter)->get_arglist());
+
+    // Open the send function
+    indent(f_service_) << function_signature(&send_function) << endl;
+    scope_up(f_service_);
+
+    string reqType = (*f_iter)->is_oneway() ? "T_ONEWAY" : "T_CALL";
+
+    // Serialize the request
+    f_service_ << indent() << "gint32 cseqid = 0;" << endl << indent()
+               << "ThriftProtocol * protocol = " << this->nspace_uc << base_service_name_uc
+               << "_CLIENT (iface)->output_protocol;" << endl << endl << indent()
+               << "if (thrift_protocol_write_message_begin (protocol, \"" << name << "\", "
+               << reqType << ", cseqid, error) < 0)" << endl << indent() << "  return FALSE;"
+               << endl << endl;
+
+    generate_struct_writer(f_service_, arg_struct, "", "", false);
+
+    f_service_ << indent() << "if (thrift_protocol_write_message_end (protocol, error) < 0)" << endl
+               << indent() << "  return FALSE;" << endl << indent()
+               << "if (!thrift_transport_flush (protocol->transport, error))" << endl << indent()
+               << "  return FALSE;" << endl << indent()
+               << "if (!thrift_transport_write_end (protocol->transport, error))" << endl
+               << indent() << "  return FALSE;" << endl << endl << indent() << "return TRUE;"
+               << endl;
+
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    // Generate recv function only if not an async function
+    if (!(*f_iter)->is_oneway()) {
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+                               service_name_lc + string("_client_recv_") + funname,
+                               &noargs,
+                               (*f_iter)->get_xceptions());
+      // Open function
+      indent(f_service_) << function_signature(&recv_function) << endl;
+      scope_up(f_service_);
+
+      f_service_ << indent() << "gint32 rseqid;" << endl
+                 << indent() << "gchar * fname = NULL;" << endl
+                 << indent() << "ThriftMessageType mtype;" << endl
+                 << indent() << "ThriftProtocol * protocol = "
+                 << this->nspace_uc << base_service_name_uc
+                 << "_CLIENT (iface)->input_protocol;" << endl
+                 << indent() << "ThriftApplicationException *xception;" << endl
+                 << endl
+                 << indent() << "if (thrift_protocol_read_message_begin "
+                    "(protocol, &fname, &mtype, &rseqid, error) < 0) {" << endl;
+      indent_up();
+      f_service_ << indent() << "if (fname) g_free (fname);" << endl
+                 << indent() << "return FALSE;" << endl;
+      indent_down();
+      f_service_ << indent() << "}" << endl
+                 << endl
+                 << indent() << "if (mtype == T_EXCEPTION) {" << endl;
+      indent_up();
+      f_service_ << indent() << "if (fname) g_free (fname);" << endl
+                 << indent() << "xception = g_object_new "
+                    "(THRIFT_TYPE_APPLICATION_EXCEPTION, NULL);" << endl
+                 << indent() << "thrift_struct_read (THRIFT_STRUCT (xception), "
+                    "protocol, NULL);" << endl
+                 << indent() << "thrift_protocol_read_message_end "
+                    "(protocol, NULL);" << endl
+                 << indent() << "thrift_transport_read_end "
+                    "(protocol->transport, NULL);" << endl
+                 << indent() << "g_set_error (error, "
+                    "THRIFT_APPLICATION_EXCEPTION_ERROR,xception->type, "
+                    "\"application error: %s\", xception->message);" << endl
+                 << indent() << "g_object_unref (xception);" << endl
+                 << indent() << "return FALSE;" << endl;
+      indent_down();
+      f_service_ << indent() << "} else if (mtype != T_REPLY) {" << endl;
+      indent_up();
+      f_service_ << indent() << "if (fname) g_free (fname);" << endl
+                 << indent() << "thrift_protocol_skip (protocol, T_STRUCT, "
+                    "NULL);" << endl
+                 << indent() << "thrift_protocol_read_message_end (protocol, "
+                    "NULL);" << endl
+                 << indent() << "thrift_transport_read_end ("
+                    "protocol->transport, NULL);" << endl
+                 << indent() << "g_set_error (error, "
+                    "THRIFT_APPLICATION_EXCEPTION_ERROR, "
+                    "THRIFT_APPLICATION_EXCEPTION_ERROR_INVALID_MESSAGE_TYPE, "
+                    "\"invalid message type %d, expected T_REPLY\", mtype);"
+                 << endl
+                 << indent() << "return FALSE;" << endl;
+      indent_down();
+      f_service_ << indent() << "} else if (strncmp (fname, \"" << name
+                 << "\", " << name.length() << ") != 0) {" << endl;
+      indent_up();
+      f_service_ << indent() << "thrift_protocol_skip (protocol, T_STRUCT, "
+                    "NULL);" << endl
+                 << indent() << "thrift_protocol_read_message_end (protocol,"
+                    "error);" << endl
+                 << indent() << "thrift_transport_read_end ("
+                    "protocol->transport, error);" << endl
+                 << indent() << "g_set_error (error, "
+                    "THRIFT_APPLICATION_EXCEPTION_ERROR, "
+                    "THRIFT_APPLICATION_EXCEPTION_ERROR_WRONG_METHOD_NAME, "
+                    "\"wrong method name %s, expected " << name
+                    << "\", fname);" << endl
+                 << indent() << "if (fname) g_free (fname);" << endl
+                 << indent() << "return FALSE;" << endl;
+      indent_down();
+      f_service_ << indent() << "}" << endl
+                 << indent() << "if (fname) g_free (fname);" << endl
+                 << endl;
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+
+      {
+        t_struct result(program_, tservice->get_name() + "_" + (*f_iter)->get_name() + "_result");
+        t_field success((*f_iter)->get_returntype(), "*_return", 0);
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          result.append(&success);
+        }
+
+        // add readers for exceptions, dereferencing the pointer.
+        for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) {
+          t_field* xception = new t_field((*x_iter)->get_type(),
+                                          "*" + (*x_iter)->get_name(),
+                                          (*x_iter)->get_key());
+          result.append(xception);
+        }
+
+        generate_struct_reader(f_service_, &result, "", "", false);
+      }
+
+      f_service_ << indent() << "if (thrift_protocol_read_message_end (protocol, error) < 0)"
+                 << endl << indent() << "  return FALSE;" << endl << endl << indent()
+                 << "if (!thrift_transport_read_end (protocol->transport, error))" << endl
+                 << indent() << "  return FALSE;" << endl << endl;
+
+      // copy over any throw exceptions and return failure
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) {
+        f_service_ << indent() << "if (*" << (*x_iter)->get_name() << " != NULL)" << endl
+                   << indent() << "{" << endl << indent() << "    g_set_error (error, "
+                   << this->nspace_uc
+                   << to_upper_case(initial_caps_to_underscores((*x_iter)->get_type()->get_name()))
+                   << "_ERROR, " << this->nspace_uc
+                   << to_upper_case(initial_caps_to_underscores((*x_iter)->get_type()->get_name()))
+                   << "_ERROR_CODE, \"" << (*x_iter)->get_type()->get_name() << "\");" << endl
+                   << indent() << "    return FALSE;" << endl << indent() << "}" << endl;
+      }
+      // Close function
+      indent(f_service_) << "return TRUE;" << endl;
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
+
+    // Open function
+    t_function service_function((*f_iter)->get_returntype(),
+                                service_name_lc + string("_client_") + funname,
+                                (*f_iter)->get_arglist(),
+                                (*f_iter)->get_xceptions());
+    indent(f_service_) << function_signature(&service_function) << endl;
+    scope_up(f_service_);
+
+    // wrap each function
+    f_service_ << indent() << "if (!" << this->nspace_lc << service_name_lc << "_client_send_"
+               << funname << " (iface";
+
+    // Declare the function arguments
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << ", " << (*fld_iter)->get_name();
+    }
+    f_service_ << ", error))" << endl << indent() << "  return FALSE;" << endl;
+
+    // if not oneway, implement recv
+    if (!(*f_iter)->is_oneway()) {
+      string ret = (*f_iter)->get_returntype()->is_void() ? "" : "_return, ";
+
+      const vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        ret += (*x_iter)->get_name();
+        ret += ", ";
+      }
+
+      f_service_ << indent() << "if (!" << this->nspace_lc << service_name_lc << "_client_recv_"
+                 << funname << " (iface, " << ret << "error))" << endl << indent()
+                 << "  return FALSE;" << endl;
+    }
+
+    // return TRUE which means all functions were called OK
+    indent(f_service_) << "return TRUE;" << endl;
+    scope_down(f_service_);
+    f_service_ << endl;
+  }
+
+  // create the interface initializer
+  f_service_ << "static void" << endl
+             << this->nspace_lc << service_name_lc << "_if_interface_init ("
+             << this->nspace << service_name_ << "IfInterface *iface)" << endl;
+  scope_up(f_service_);
+  if (functions.size() > 0) {
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      /* make the function name C friendly */
+      string funname = initial_caps_to_underscores((*f_iter)->get_name());
+
+      f_service_ << indent() << "iface->" << funname << " = " << this->nspace_lc
+                 << service_name_lc << "_client_" << funname << ";" << endl;
+    }
+  }
+  else {
+    f_service_ << indent() << "THRIFT_UNUSED_VAR (iface);" << endl;
+  }
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // create the client instance initializer
+  f_service_ << "static void" << endl
+             << this->nspace_lc << service_name_lc << "_client_init ("
+             << this->nspace << service_name_ << "Client *client)" << endl;
+  scope_up(f_service_);
+  if (!extends_service) {
+    f_service_ << indent() << "client->input_protocol = NULL;" << endl
+               << indent() << "client->output_protocol = NULL;" << endl;
+  }
+  else {
+    f_service_ << indent() << "THRIFT_UNUSED_VAR (client);" << endl;
+  }
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // create the client class initializer
+  f_service_ << "static void" << endl << this->nspace_lc << service_name_lc
+             << "_client_class_init (" << this->nspace << service_name_ << "ClientClass *cls)"
+             << endl << "{" << endl;
+  if (!extends_service) {
+    f_service_ << "  GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl
+               << "  GParamSpec *param_spec;" << endl << endl
+               << "  gobject_class->set_property = " << this->nspace_lc << service_name_lc
+               << "_client_set_property;" << endl
+               << "  gobject_class->get_property = " << this->nspace_lc << service_name_lc
+               << "_client_get_property;" << endl << endl
+               << "  param_spec = g_param_spec_object (\"input_protocol\"," << endl
+               << "                                    \"input protocol (construct)\"," << endl
+               << "                                    \"Set the client input protocol\"," << endl
+               << "                                    THRIFT_TYPE_PROTOCOL," << endl
+               << "                                    G_PARAM_READWRITE);" << endl
+               << "  g_object_class_install_property (gobject_class," << endl
+               << "                                   PROP_" << this->nspace_uc << service_name_uc
+               << "_CLIENT_INPUT_PROTOCOL, param_spec);" << endl << endl
+               << "  param_spec = g_param_spec_object (\"output_protocol\"," << endl
+               << "                                    \"output protocol (construct)\"," << endl
+               << "                                    \"Set the client output protocol\"," << endl
+               << "                                    THRIFT_TYPE_PROTOCOL," << endl
+               << "                                    G_PARAM_READWRITE);" << endl
+               << "  g_object_class_install_property (gobject_class," << endl
+               << "                                   PROP_" << this->nspace_uc << service_name_uc
+               << "_CLIENT_OUTPUT_PROTOCOL, param_spec);" << endl;
+  }
+  else {
+    f_service_ << "  THRIFT_UNUSED_VAR (cls);" << endl;
+  }
+  f_service_ << "}" << endl << endl;
+}
+
+/**
+ * Generates C code that represents a Thrift service handler.
+ *
+ * @param tservice The service for which to generate a handler.
+ */
+void t_c_glib_generator::generate_service_handler(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator function_iter;
+
+  string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_));
+  string service_name_uc = to_upper_case(service_name_lc);
+
+  string service_handler_name = service_name_ + "Handler";
+
+  string class_name = this->nspace + service_handler_name;
+  string class_name_lc = this->nspace_lc + initial_caps_to_underscores(service_handler_name);
+  string class_name_uc = to_upper_case(class_name_lc);
+
+  string parent_class_name;
+  string parent_type_name;
+
+  string args_indent;
+
+  // The service this service extends, or NULL if it extends no service
+  t_service* extends_service = tservice->get_extends();
+
+  // Determine the name of our parent service (if any) and the handler class'
+  // parent class name and type
+  if (extends_service) {
+    string parent_service_name = extends_service->get_name();
+    string parent_service_name_lc = to_lower_case(initial_caps_to_underscores(parent_service_name));
+    string parent_service_name_uc = to_upper_case(parent_service_name_lc);
+
+    parent_class_name = this->nspace + parent_service_name + "Handler";
+    parent_type_name = this->nspace_uc + "TYPE_" + parent_service_name_uc + "_HANDLER";
+  } else {
+    parent_class_name = "GObject";
+    parent_type_name = "G_TYPE_OBJECT";
+  }
+
+  // Generate the handler class' definition in the header file
+
+  // Generate the handler instance definition
+  f_header_ << "/* " << service_name_ << " handler (abstract base class) */" << endl << "struct _"
+            << class_name << endl << "{" << endl;
+  indent_up();
+  f_header_ << indent() << parent_class_name << " parent;" << endl;
+  indent_down();
+  f_header_ << "};" << endl << "typedef struct _" << class_name << " " << class_name << ";" << endl
+            << endl;
+
+  // Generate the handler class definition, including its class members
+  // (methods)
+  f_header_ << "struct _" << class_name << "Class" << endl << "{" << endl;
+  indent_up();
+  f_header_ << indent() << parent_class_name << "Class parent;" << endl << endl;
+
+  for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
+    string method_name = initial_caps_to_underscores((*function_iter)->get_name());
+    t_type* return_type = (*function_iter)->get_returntype();
+    t_struct* arg_list = (*function_iter)->get_arglist();
+    t_struct* x_list = (*function_iter)->get_xceptions();
+    bool has_return = !return_type->is_void();
+    bool has_args = arg_list->get_members().size() == 0;
+    bool has_xceptions = x_list->get_members().size() == 0;
+
+    string params = "(" + this->nspace + service_name_ + "If *iface"
+                    + (has_return ? ", " + type_name(return_type) + "* _return" : "")
+                    + (has_args ? "" : (", " + argument_list(arg_list)))
+                    + (has_xceptions ? "" : (", " + xception_list(x_list))) + ", GError **error)";
+
+    indent(f_header_) << "gboolean (*" << method_name << ") " << params << ";" << endl;
+  }
+  indent_down();
+
+  f_header_ << "};" << endl << "typedef struct _" << class_name << "Class " << class_name
+            << "Class;" << endl << endl;
+
+  // Generate the remaining header boilerplate
+  f_header_ << "GType " << class_name_lc << "_get_type (void);" << endl << "#define "
+            << this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER "
+            << "(" << class_name_lc << "_get_type())" << endl << "#define " << class_name_uc
+            << "(obj) "
+            << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_"
+            << service_name_uc << "_HANDLER, " << class_name << "))" << endl << "#define "
+            << this->nspace_uc << "IS_" << service_name_uc << "_HANDLER(obj) "
+            << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_"
+            << service_name_uc << "_HANDLER))" << endl << "#define " << class_name_uc
+            << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_"
+            << service_name_uc << "_HANDLER, " << class_name << "Class))" << endl << "#define "
+            << this->nspace_uc << "IS_" << service_name_uc << "_HANDLER_CLASS(c) "
+            << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << service_name_uc
+            << "_HANDLER))" << endl << "#define " << this->nspace_uc << service_name_uc
+            << "_HANDLER_GET_CLASS(obj) "
+            << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_"
+            << service_name_uc << "_HANDLER, " << class_name << "Class))" << endl << endl;
+
+  // Generate the handler class' method definitions
+  for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
+    string method_name = initial_caps_to_underscores((*function_iter)->get_name());
+    t_type* return_type = (*function_iter)->get_returntype();
+    t_struct* arg_list = (*function_iter)->get_arglist();
+    t_struct* x_list = (*function_iter)->get_xceptions();
+    bool has_return = !return_type->is_void();
+    bool has_args = arg_list->get_members().size() == 0;
+    bool has_xceptions = x_list->get_members().size() == 0;
+
+    string params = "(" + this->nspace + service_name_ + "If *iface"
+                    + (has_return ? ", " + type_name(return_type) + "* _return" : "")
+                    + (has_args ? "" : (", " + argument_list(arg_list)))
+                    + (has_xceptions ? "" : (", " + xception_list(x_list))) + ", GError **error)";
+
+    f_header_ << "gboolean " << class_name_lc << "_" << method_name << " " << params << ";" << endl;
+  }
+  f_header_ << endl;
+
+  // Generate the handler's implementation in the implementation file
+
+  // Generate the implementation boilerplate
+  f_service_ << "static void" << endl << class_name_lc << "_" << service_name_lc
+             << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface);"
+             << endl << endl;
+
+  args_indent = string(25, ' ');
+  f_service_ << "G_DEFINE_TYPE_WITH_CODE (" << class_name << ", " << endl << args_indent
+             << class_name_lc << "," << endl << args_indent << parent_type_name << "," << endl
+             << args_indent << "G_IMPLEMENT_INTERFACE (" << this->nspace_uc << "TYPE_"
+             << service_name_uc << "_IF," << endl;
+  args_indent += string(23, ' ');
+  f_service_ << args_indent << class_name_lc << "_" << service_name_lc << "_if_interface_init))"
+             << endl << endl;
+
+  // Generate the handler method implementations
+  for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
+    string function_name = (*function_iter)->get_name();
+    string method_name = initial_caps_to_underscores(function_name);
+    t_type* return_type = (*function_iter)->get_returntype();
+    t_struct* arg_list = (*function_iter)->get_arglist();
+    t_struct* x_list = (*function_iter)->get_xceptions();
+
+    const vector<t_field*>& args = arg_list->get_members();
+    const vector<t_field*>& xceptions = x_list->get_members();
+
+    vector<t_field*>::const_iterator field_iter;
+
+    t_function implementing_function(return_type,
+                                     service_name_lc + "_handler_" + method_name,
+                                     arg_list,
+                                     x_list,
+                                     (*function_iter)->is_oneway());
+
+    indent(f_service_) << function_signature(&implementing_function) << endl;
+    scope_up(f_service_);
+    f_service_ << indent() << "g_return_val_if_fail (" << this->nspace_uc << "IS_"
+               << service_name_uc << "_HANDLER (iface), FALSE);" << endl << endl << indent()
+               << "return " << class_name_uc << "_GET_CLASS (iface)"
+               << "->" << method_name << " (iface, ";
+
+    if (!return_type->is_void()) {
+      f_service_ << "_return, ";
+    }
+    for (field_iter = args.begin(); field_iter != args.end(); ++field_iter) {
+      f_service_ << (*field_iter)->get_name() << ", ";
+    }
+    for (field_iter = xceptions.begin(); field_iter != xceptions.end(); ++field_iter) {
+      f_service_ << (*field_iter)->get_name() << ", ";
+    }
+    f_service_ << "error);" << endl;
+    scope_down(f_service_);
+    f_service_ << endl;
+  }
+
+  // Generate the handler interface initializer
+  f_service_ << "static void" << endl << class_name_lc << "_" << service_name_lc
+             << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface)"
+             << endl;
+  scope_up(f_service_);
+  if (functions.size() > 0) {
+    for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
+      string method_name = initial_caps_to_underscores((*function_iter)->get_name());
+
+      f_service_ << indent() << "iface->" << method_name << " = " << class_name_lc << "_"
+                 << method_name << ";" << endl;
+    }
+  }
+  else {
+    f_service_ << "THRIFT_UNUSED_VAR (iface);" << endl;
+  }
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generate the handler instance initializer
+  f_service_ << "static void" << endl << class_name_lc << "_init (" << class_name << " *self)"
+             << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << "THRIFT_UNUSED_VAR (self);" << endl;
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generate the handler class initializer
+  f_service_ << "static void" << endl
+             << class_name_lc << "_class_init (" << class_name << "Class *cls)"
+             << endl;
+  scope_up(f_service_);
+  if (functions.size() > 0) {
+    for (function_iter = functions.begin();
+         function_iter != functions.end();
+         ++function_iter) {
+      string function_name = (*function_iter)->get_name();
+      string method_name = initial_caps_to_underscores(function_name);
+
+      // All methods are pure virtual and must be implemented by subclasses
+      f_service_ << indent() << "cls->" << method_name << " = NULL;" << endl;
+    }
+  }
+  else {
+    f_service_ << indent() << "THRIFT_UNUSED_VAR (cls);" << endl;
+  }
+  scope_down(f_service_);
+  f_service_ << endl;
+}
+
+/**
+ * Generates C code that represents a Thrift service processor.
+ *
+ * @param tservice The service for which to generate a processor
+ */
+void t_c_glib_generator::generate_service_processor(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator function_iter;
+
+  string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_));
+  string service_name_uc = to_upper_case(service_name_lc);
+
+  string service_processor_name = service_name_ + "Processor";
+
+  string class_name = this->nspace + service_processor_name;
+  string class_name_lc = this->nspace_lc + initial_caps_to_underscores(service_processor_name);
+  string class_name_uc = to_upper_case(class_name_lc);
+
+  string parent_class_name;
+  string parent_type_name;
+
+  string handler_class_name = this->nspace + service_name_ + "Handler";
+  string handler_class_name_lc = initial_caps_to_underscores(handler_class_name);
+
+  string process_function_type_name = class_name + "ProcessFunction";
+  string process_function_def_type_name =
+    class_name_lc + "_process_function_def";
+
+  string function_name;
+  string args_indent;
+
+  // The service this service extends, or NULL if it extends no service
+  t_service* extends_service = tservice->get_extends();
+
+  // Determine the name of our parent service (if any) and the
+  // processor class' parent class name and type
+  if (extends_service) {
+    string parent_service_name = extends_service->get_name();
+    string parent_service_name_lc = to_lower_case(initial_caps_to_underscores(parent_service_name));
+    string parent_service_name_uc = to_upper_case(parent_service_name_lc);
+
+    parent_class_name = this->nspace + parent_service_name + "Processor";
+    parent_type_name = this->nspace_uc + "TYPE_" + parent_service_name_uc + "_PROCESSOR";
+  } else {
+    parent_class_name = "ThriftDispatchProcessor";
+    parent_type_name = "THRIFT_TYPE_DISPATCH_PROCESSOR";
+  }
+
+  // Generate the processor class' definition in the header file
+
+  // Generate the processor instance definition
+  f_header_ << "/* " << service_name_ << " processor */" << endl << "struct _" << class_name << endl
+            << "{" << endl;
+  indent_up();
+  f_header_ << indent() << parent_class_name << " parent;" << endl << endl << indent()
+            << "/* protected */" << endl << indent()
+            << this->nspace + service_name_ + "Handler *handler;" << endl << indent()
+            << "GHashTable *process_map;" << endl;
+  indent_down();
+  f_header_ << "};" << endl << "typedef struct _" << class_name << " " << class_name << ";" << endl
+            << endl;
+
+  // Generate the processor class definition
+  f_header_ << "struct _" << class_name << "Class" << endl << "{" << endl;
+  indent_up();
+  f_header_ << indent() << parent_class_name << "Class parent;" << endl << endl << indent()
+            << "/* protected */" << endl << indent()
+            << "gboolean (*dispatch_call) (ThriftDispatchProcessor *processor," << endl;
+  args_indent = indent() + string(27, ' ');
+  f_header_ << args_indent << "ThriftProtocol *in," << endl << args_indent << "ThriftProtocol *out,"
+            << endl << args_indent << "gchar *fname," << endl << args_indent << "gint32 seqid,"
+            << endl << args_indent << "GError **error);" << endl;
+  indent_down();
+  f_header_ << "};" << endl << "typedef struct _" << class_name << "Class " << class_name
+            << "Class;" << endl << endl;
+
+  // Generate the remaining header boilerplate
+  f_header_ << "GType " << class_name_lc << "_get_type (void);" << endl << "#define "
+            << this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR "
+            << "(" << class_name_lc << "_get_type())" << endl << "#define " << class_name_uc
+            << "(obj) "
+            << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_"
+            << service_name_uc << "_PROCESSOR, " << class_name << "))" << endl << "#define "
+            << this->nspace_uc << "IS_" << service_name_uc << "_PROCESSOR(obj) "
+            << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_"
+            << service_name_uc << "_PROCESSOR))" << endl << "#define " << class_name_uc
+            << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_"
+            << service_name_uc << "_PROCESSOR, " << class_name << "Class))" << endl << "#define "
+            << this->nspace_uc << "IS_" << service_name_uc << "_PROCESSOR_CLASS(c) "
+            << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << service_name_uc
+            << "_PROCESSOR))" << endl << "#define " << this->nspace_uc << service_name_uc
+            << "_PROCESSOR_GET_CLASS(obj) "
+            << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_"
+            << service_name_uc << "_PROCESSOR, " << class_name << "Class))" << endl << endl;
+
+  // Generate the processor's implementation in the implementation file
+
+  // Generate the processor's properties enum
+  f_service_ << "enum _" << class_name << "Properties" << endl << "{" << endl;
+  indent_up();
+  f_service_ << indent() << "PROP_" << class_name_uc << "_0," << endl << indent() << "PROP_"
+             << class_name_uc << "_HANDLER" << endl;
+  indent_down();
+  f_service_ << "};" << endl << endl;
+
+  // Generate the implementation boilerplate
+  args_indent = string(15, ' ');
+  f_service_ << "G_DEFINE_TYPE (" << class_name << "," << endl << args_indent << class_name_lc
+             << "," << endl << args_indent << parent_type_name << ")" << endl << endl;
+
+  // Generate the processor's processing-function type
+  args_indent = string(process_function_type_name.length() + 23, ' ');
+  f_service_ << "typedef gboolean (* " << process_function_type_name << ") ("
+             << class_name << " *, " << endl
+             << args_indent << "gint32," << endl
+             << args_indent << "ThriftProtocol *," << endl
+             << args_indent << "ThriftProtocol *," << endl
+             << args_indent << "GError **);" << endl
+             << endl;
+
+  // Generate the processor's processing-function-definition type
+  f_service_ << "typedef struct" << endl
+             << "{" << endl;
+  indent_up();
+  f_service_ << indent() << "gchar *name;" << endl
+             << indent() << process_function_type_name << " function;" << endl;
+  indent_down();
+  f_service_ << "} " << process_function_def_type_name << ";" << endl
+             << endl;
+
+  // Generate forward declarations of the processor's processing functions so we
+  // can refer to them in the processing-function-definition struct below and
+  // keep all of the processor's declarations in one place
+  for (function_iter = functions.begin();
+       function_iter != functions.end();
+       ++function_iter) {
+    function_name = class_name_lc + "_process_"
+      + initial_caps_to_underscores((*function_iter)->get_name());
+
+    args_indent = string(function_name.length() + 2, ' ');
+    f_service_ << "static gboolean" << endl
+               << function_name << " ("
+               << class_name << " *," << endl
+               << args_indent << "gint32," << endl
+               << args_indent << "ThriftProtocol *," << endl
+               << args_indent << "ThriftProtocol *," << endl
+               << args_indent << "GError **);" << endl;
+  }
+  f_service_ << endl;
+
+  // Generate the processor's processing-function definitions, if the service
+  // defines any methods
+  if (functions.size() > 0) {
+    f_service_ << indent() << "static " << process_function_def_type_name
+               << endl
+               << indent() << class_name_lc << "_process_function_defs["
+               << functions.size() << "] = {" << endl;
+    indent_up();
+    for (function_iter = functions.begin();
+         function_iter != functions.end();
+         ++function_iter) {
+      string service_function_name = (*function_iter)->get_name();
+      string process_function_name = class_name_lc + "_process_"
+        + initial_caps_to_underscores(service_function_name);
+
+      f_service_ << indent() << "{" << endl;
+      indent_up();
+      f_service_ << indent() << "\"" << service_function_name << "\"," << endl
+                 << indent() << process_function_name << endl;
+      indent_down();
+      f_service_ << indent() << "}"
+                 << (function_iter == --functions.end() ? "" : ",") << endl;
+    }
+    indent_down();
+    f_service_ << indent() << "};" << endl
+               << endl;
+  }
+
+  // Generate the processor's processing functions
+  for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
+    string service_function_name = (*function_iter)->get_name();
+    string service_function_name_ic = underscores_to_initial_caps(service_function_name);
+    string service_function_name_lc = initial_caps_to_underscores(service_function_name);
+    string service_function_name_uc = to_upper_case(service_function_name_lc);
+
+    t_type* return_type = (*function_iter)->get_returntype();
+    bool has_return_value = !return_type->is_void();
+
+    t_struct* arg_list = (*function_iter)->get_arglist();
+    const vector<t_field*>& args = arg_list->get_members();
+    vector<t_field*>::const_iterator arg_iter;
+
+    const vector<t_field*>& xceptions = (*function_iter)->get_xceptions()->get_members();
+    vector<t_field*>::const_iterator xception_iter;
+
+    string args_class_name = this->nspace + service_name_ + service_function_name_ic + "Args";
+    string args_class_type = this->nspace_uc + "TYPE_" + service_name_uc + "_"
+                             + service_function_name_uc + "_ARGS";
+
+    string result_class_name = this->nspace + service_name_ + service_function_name_ic + "Result";
+    string result_class_type = this->nspace_uc + "TYPE_" + service_name_uc + "_"
+                               + service_function_name_uc + "_RESULT";
+
+    string handler_function_name = handler_class_name_lc + "_" + service_function_name_lc;
+
+    function_name = class_name_lc + "_process_"
+                    + initial_caps_to_underscores(service_function_name);
+
+    args_indent = string(function_name.length() + 2, ' ');
+    f_service_ << "static gboolean" << endl << function_name << " (" << class_name << " *self,"
+               << endl << args_indent << "gint32 sequence_id," << endl << args_indent
+               << "ThriftProtocol *input_protocol," << endl << args_indent
+               << "ThriftProtocol *output_protocol," << endl << args_indent << "GError **error)"
+               << endl;
+    scope_up(f_service_);
+    f_service_ << indent() << "gboolean result = TRUE;" << endl
+               << indent() << "ThriftTransport * transport;" << endl
+               << indent() << "ThriftApplicationException *xception;" << endl
+               << indent() << args_class_name + " * args =" << endl;
+    indent_up();
+    f_service_ << indent() << "g_object_new (" << args_class_type << ", NULL);" << endl << endl;
+    indent_down();
+    if ((*function_iter)->is_oneway()) {
+      f_service_ << indent() << "THRIFT_UNUSED_VAR (sequence_id);" << endl << indent()
+                 << "THRIFT_UNUSED_VAR (output_protocol);" << endl << endl;
+    }
+    f_service_ << indent() << "g_object_get (input_protocol, \"transport\", "
+               << "&transport, NULL);" << endl << endl;
+
+    // Read the method's arguments from the caller
+    f_service_ << indent() << "if ((thrift_struct_read (THRIFT_STRUCT (args), "
+               << "input_protocol, error) != -1) &&" << endl << indent()
+               << "    (thrift_protocol_read_message_end (input_protocol, "
+               << "error) != -1) &&" << endl << indent()
+               << "    (thrift_transport_read_end (transport, error) != FALSE))" << endl;
+    scope_up(f_service_);
+
+    for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) {
+      f_service_ << indent() << property_type_name((*arg_iter)->get_type()) << " "
+                 << (*arg_iter)->get_name() << ";" << endl;
+    }
+    for (xception_iter = xceptions.begin(); xception_iter != xceptions.end(); ++xception_iter) {
+      f_service_ << indent() << type_name((*xception_iter)->get_type()) << " "
+                 << initial_caps_to_underscores((*xception_iter)->get_name()) << " = NULL;" << endl;
+    }
+    if (has_return_value) {
+      f_service_ << indent() << property_type_name(return_type) << " return_value;" << endl;
+    }
+    if (!(*function_iter)->is_oneway()) {
+      f_service_ << indent() << result_class_name << " * result_struct;" << endl;
+    }
+    f_service_ << endl;
+
+    if (args.size() > 0) {
+      f_service_ << indent() << "g_object_get (args," << endl;
+      args_indent = indent() + string(14, ' ');
+      for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) {
+        string arg_name = (*arg_iter)->get_name();
+
+        f_service_ << args_indent << "\"" << arg_name << "\", &" << arg_name << "," << endl;
+      }
+      f_service_ << args_indent << "NULL);" << endl << endl;
+    }
+
+    if (!(*function_iter)->is_oneway()) {
+      f_service_ << indent() << "g_object_unref (transport);" << endl << indent()
+                 << "g_object_get (output_protocol, \"transport\", "
+                 << "&transport, NULL);" << endl << endl << indent()
+                 << "result_struct = g_object_new (" << result_class_type << ", NULL);" << endl;
+      if (has_return_value) {
+        f_service_ << indent() << "g_object_get (result_struct, "
+                                  "\"success\", &return_value, NULL);" << endl;
+      }
+      f_service_ << endl;
+    }
+
+    // Pass the arguments to the corresponding method in the handler
+    f_service_ << indent() << "if (" << handler_function_name << " (" << this->nspace_uc
+               << service_name_uc << "_IF (self->handler)," << endl;
+    args_indent = indent() + string(handler_function_name.length() + 6, ' ');
+    if (has_return_value) {
+      string return_type_name = type_name(return_type);
+
+      f_service_ << args_indent;
+
+      // Cast return_value if it was declared as a type other than the return
+      // value's actual type---this is true for integer values 32 bits or fewer
+      // in width, for which GLib requires a plain gint type be used when
+      // storing or retrieving as an object property
+      if (return_type_name != property_type_name(return_type)) {
+        if (return_type_name[return_type_name.length() - 1] != '*') {
+          return_type_name += ' ';
+        }
+        return_type_name += '*';
+
+        f_service_ << "(" << return_type_name << ")";
+      }
+
+      f_service_ << "&return_value," << endl;
+    }
+    for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) {
+      f_service_ << args_indent << (*arg_iter)->get_name() << "," << endl;
+    }
+    for (xception_iter = xceptions.begin(); xception_iter != xceptions.end(); ++xception_iter) {
+      f_service_ << args_indent << "&" << initial_caps_to_underscores((*xception_iter)->get_name())
+                 << "," << endl;
+    }
+    f_service_ << args_indent << "error) == TRUE)" << endl;
+    scope_up(f_service_);
+
+    // The handler reported success; return the result, if any, to the caller
+    if (!(*function_iter)->is_oneway()) {
+      if (has_return_value) {
+        f_service_ << indent() << "g_object_set (result_struct, \"success\", ";
+        if (type_name(return_type) != property_type_name(return_type)) {
+          // Roundtrip cast to fix the position of sign bit.
+          f_service_ << "(" << property_type_name(return_type) << ")"
+                     << "(" << type_name(return_type) << ")";
+        }
+        f_service_ << "return_value, "
+                   << "NULL);" << endl;
+
+        // Deallocate (or unref) return_value
+        return_type = get_true_type(return_type);
+        if (return_type->is_base_type()) {
+          t_base_type* base_type = ((t_base_type*)return_type);
+
+          if (base_type->get_base() == t_base_type::TYPE_STRING) {
+            f_service_ << indent() << "if (return_value != NULL)" << endl;
+            indent_up();
+            if (base_type->is_binary()) {
+              f_service_ << indent() << "g_byte_array_unref (return_value);" << endl;
+            } else {
+              f_service_ << indent() << "g_free (return_value);" << endl;
+            }
+            indent_down();
+          }
+        } else if (return_type->is_container()) {
+          f_service_ << indent() << "if (return_value != NULL)" << endl;
+          indent_up();
+
+          if (return_type->is_list()) {
+            t_type* elem_type = ((t_list*)return_type)->get_elem_type();
+
+            f_service_ << indent();
+            if (is_numeric(elem_type)) {
+              f_service_ << "g_array_unref";
+            } else {
+              f_service_ << "g_ptr_array_unref";
+            }
+            f_service_ << " (return_value);" << endl;
+          } else if (return_type->is_map() || return_type->is_set()) {
+            f_service_ << indent() << "g_hash_table_unref (return_value);" << endl;
+          }
+
+          indent_down();
+        } else if (return_type->is_struct()) {
+          f_service_ << indent() << "if (return_value != NULL)" << endl;
+          indent_up();
+          f_service_ << indent() << "g_object_unref (return_value);" << endl;
+          indent_down();
+        }
+
+        f_service_ << endl;
+      }
+      f_service_ << indent() << "result =" << endl;
+      indent_up();
+      f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl;
+      args_indent = indent() + string(39, ' ');
+      f_service_ << args_indent << "\"" << service_function_name << "\"," << endl << args_indent
+                 << "T_REPLY," << endl << args_indent << "sequence_id," << endl << args_indent
+                 << "error) != -1) &&" << endl << indent()
+                 << " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << endl;
+      args_indent = indent() + string(23, ' ');
+      f_service_ << args_indent << "output_protocol," << endl << args_indent << "error) != -1));"
+                 << endl;
+      indent_down();
+    }
+    scope_down(f_service_);
+    f_service_ << indent() << "else" << endl;
+    scope_up(f_service_);
+
+    // The handler reported failure; check to see if an application-defined
+    // exception was raised and if so, return it to the caller
+    f_service_ << indent();
+    if (xceptions.size() > 0) {
+      for (xception_iter = xceptions.begin(); xception_iter != xceptions.end(); ++xception_iter) {
+        f_service_ << "if (" << initial_caps_to_underscores((*xception_iter)->get_name())
+                   << " != NULL)" << endl;
+        scope_up(f_service_);
+        f_service_ << indent() << "g_object_set (result_struct," << endl;
+        args_indent = indent() + string(14, ' ');
+        f_service_ << args_indent << "\"" << (*xception_iter)->get_name() << "\", "
+                   << (*xception_iter)->get_name() << "," << endl << args_indent << "NULL);" << endl
+                   << endl;
+        f_service_ << indent() << "result =" << endl;
+        indent_up();
+        f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl;
+        args_indent = indent() + string(39, ' ');
+        f_service_ << args_indent << "\"" << service_function_name << "\"," << endl << args_indent
+                   << "T_REPLY," << endl << args_indent << "sequence_id," << endl << args_indent
+                   << "error) != -1) &&" << endl << indent()
+                   << " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << endl;
+        args_indent = indent() + string(23, ' ');
+        f_service_ << args_indent << "output_protocol," << endl << args_indent << "error) != -1));"
+                   << endl;
+        indent_down();
+        scope_down(f_service_);
+        f_service_ << indent() << "else" << endl;
+      }
+
+      scope_up(f_service_);
+      f_service_ << indent();
+    }
+
+    // If the handler reported failure but raised no application-defined
+    // exception, return a Thrift application exception with the information
+    // returned via GLib's own error-reporting mechanism
+    f_service_ << "if (*error == NULL)" << endl;
+    indent_up();
+    f_service_ << indent() << "g_warning (\"" << service_name_ << "."
+               << (*function_iter)->get_name() << " implementation returned FALSE \"" << endl
+               << indent() << string(11, ' ') << "\"but did not set an error\");" << endl << endl;
+    indent_down();
+    f_service_ << indent() << "xception =" << endl;
+    indent_up();
+    f_service_ << indent() << "g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION," << endl;
+    args_indent = indent() + string(14, ' ');
+    f_service_ << args_indent << "\"type\",    *error != NULL ? (*error)->code :" << endl
+               << args_indent << string(11, ' ') << "THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN,"
+               << endl << args_indent << "\"message\", *error != NULL ? (*error)->message : NULL,"
+               << endl << args_indent << "NULL);" << endl;
+    indent_down();
+    f_service_ << indent() << "g_clear_error (error);" << endl << endl << indent()
+               << "result =" << endl;
+    indent_up();
+    f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl;
+    args_indent = indent() + string(39, ' ');
+    f_service_ << args_indent << "\"" << service_function_name << "\"," << endl << args_indent
+               << "T_EXCEPTION," << endl << args_indent << "sequence_id," << endl << args_indent
+               << "error) != -1) &&" << endl << indent()
+               << " (thrift_struct_write (THRIFT_STRUCT (xception)," << endl;
+    args_indent = indent() + string(23, ' ');
+    f_service_ << args_indent << "output_protocol," << endl << args_indent << "error) != -1));"
+               << endl;
+    indent_down();
+    f_service_ << endl << indent() << "g_object_unref (xception);" << endl;
+
+    if (xceptions.size() > 0) {
+      scope_down(f_service_);
+    }
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    // Dellocate or unref retrieved argument values as necessary
+    for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) {
+      string arg_name = (*arg_iter)->get_name();
+      t_type* arg_type = get_true_type((*arg_iter)->get_type());
+
+      if (arg_type->is_base_type()) {
+        t_base_type* base_type = ((t_base_type*)arg_type);
+
+        if (base_type->get_base() == t_base_type::TYPE_STRING) {
+          f_service_ << indent() << "if (" << arg_name << " != NULL)" << endl;
+          indent_up();
+          if (base_type->is_binary()) {
+            f_service_ << indent() << "g_byte_array_unref (" << arg_name << ");" << endl;
+          } else {
+            f_service_ << indent() << "g_free (" << arg_name << ");" << endl;
+          }
+          indent_down();
+        }
+      } else if (arg_type->is_container()) {
+        f_service_ << indent() << "if (" << arg_name << " != NULL)" << endl;
+        indent_up();
+
+        if (arg_type->is_list()) {
+          t_type* elem_type = ((t_list*)arg_type)->get_elem_type();
+
+          f_service_ << indent();
+          if (is_numeric(elem_type)) {
+            f_service_ << "g_array_unref";
+          } else {
+            f_service_ << "g_ptr_array_unref";
+          }
+          f_service_ << " (" << arg_name << ");" << endl;
+        } else if (arg_type->is_map() || arg_type->is_set()) {
+          f_service_ << indent() << "g_hash_table_unref (" << arg_name << ");" << endl;
+        }
+
+        indent_down();
+      } else if (arg_type->is_struct()) {
+        f_service_ << indent() << "if (" << arg_name << " != NULL)" << endl;
+        indent_up();
+        f_service_ << indent() << "g_object_unref (" << arg_name << ");" << endl;
+        indent_down();
+      }
+    }
+
+    if (!(*function_iter)->is_oneway()) {
+      f_service_ << indent() << "g_object_unref (result_struct);" << endl << endl << indent()
+                 << "if (result == TRUE)" << endl;
+      indent_up();
+      f_service_ << indent() << "result =" << endl;
+      indent_up();
+      f_service_ << indent() << "((thrift_protocol_write_message_end "
+                 << "(output_protocol, error) != -1) &&" << endl << indent()
+                 << " (thrift_transport_write_end (transport, error) "
+                 << "!= FALSE) &&" << endl << indent()
+                 << " (thrift_transport_flush (transport, error) "
+                 << "!= FALSE));" << endl;
+      indent_down();
+      indent_down();
+    }
+    scope_down(f_service_);
+    f_service_ << indent() << "else" << endl;
+    indent_up();
+    f_service_ << indent() << "result = FALSE;" << endl;
+    indent_down();
+
+    f_service_ << endl << indent() << "g_object_unref (transport);" << endl << indent()
+               << "g_object_unref (args);" << endl << endl << indent() << "return result;" << endl;
+    scope_down(f_service_);
+
+    f_service_ << endl;
+  }
+
+  // Generate the processor's dispatch_call implementation
+  function_name = class_name_lc + "_dispatch_call";
+  args_indent = indent() + string(function_name.length() + 2, ' ');
+  f_service_ << "static gboolean" << endl << function_name
+             << " (ThriftDispatchProcessor *dispatch_processor," << endl << args_indent
+             << "ThriftProtocol *input_protocol," << endl << args_indent
+             << "ThriftProtocol *output_protocol," << endl << args_indent << "gchar *method_name,"
+             << endl << args_indent << "gint32 sequence_id," << endl << args_indent
+             << "GError **error)" << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << class_name_lc << "_process_function_def *"
+             << "process_function_def;" << endl;
+  f_service_ << indent() << "gboolean dispatch_result = FALSE;" << endl << endl << indent()
+             << class_name << " *self = " << class_name_uc << " (dispatch_processor);" << endl;
+  f_service_ << indent() << parent_class_name << "Class "
+                                                 "*parent_class =" << endl;
+  indent_up();
+  f_service_ << indent() << "g_type_class_peek_parent (" << class_name_uc << "_GET_CLASS (self));"
+             << endl;
+  indent_down();
+  f_service_ << endl
+             << indent() << "process_function_def = "
+             << "g_hash_table_lookup (self->process_map, method_name);" << endl
+             << indent() << "if (process_function_def != NULL)" << endl;
+  scope_up(f_service_);
+  args_indent = indent() + string(53, ' ');
+  f_service_ << indent() << "g_free (method_name);" << endl
+             << indent() << "dispatch_result = "
+             << "(*process_function_def->function) (self," << endl
+             << args_indent << "sequence_id," << endl
+             << args_indent << "input_protocol," << endl
+             << args_indent << "output_protocol," << endl
+             << args_indent << "error);" << endl;
+  scope_down(f_service_);
+  f_service_ << indent() << "else" << endl;
+  scope_up(f_service_);
+
+  // Method name not recognized; chain up to our parent processor---note the
+  // top-most implementation of this method, in ThriftDispatchProcessor itself,
+  // will return an application exception to the caller if no class in the
+  // hierarchy recognizes the method name
+  f_service_ << indent() << "dispatch_result = parent_class->dispatch_call "
+                            "(dispatch_processor," << endl;
+  args_indent = indent() + string(47, ' ');
+  f_service_ << args_indent << "input_protocol," << endl << args_indent << "output_protocol,"
+             << endl << args_indent << "method_name," << endl << args_indent << "sequence_id,"
+             << endl << args_indent << "error);" << endl;
+  scope_down(f_service_);
+  f_service_ << endl << indent() << "return dispatch_result;" << endl;
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generate the processor's property setter
+  function_name = class_name_lc + "_set_property";
+  args_indent = string(function_name.length() + 2, ' ');
+  f_service_ << "static void" << endl << function_name << " (GObject *object," << endl
+             << args_indent << "guint property_id," << endl << args_indent << "const GValue *value,"
+             << endl << args_indent << "GParamSpec *pspec)" << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl
+             << endl << indent() << "switch (property_id)" << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << "case PROP_" << class_name_uc << "_HANDLER:" << endl;
+  indent_up();
+  f_service_ << indent() << "if (self->handler != NULL)" << endl;
+  indent_up();
+  f_service_ << indent() << "g_object_unref (self->handler);" << endl;
+  indent_down();
+  f_service_ << indent() << "self->handler = g_value_get_object (value);" << endl << indent()
+             << "g_object_ref (self->handler);" << endl;
+  if (extends_service) {
+    // Chain up to set the handler in every superclass as well
+    f_service_ << endl << indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)->"
+               << endl;
+    indent_up();
+    f_service_ << indent() << "set_property (object, property_id, value, pspec);" << endl;
+    indent_down();
+  }
+  f_service_ << indent() << "break;" << endl;
+  indent_down();
+  f_service_ << indent() << "default:" << endl;
+  indent_up();
+  f_service_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
+             << endl << indent() << "break;" << endl;
+  indent_down();
+  scope_down(f_service_);
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generate processor's property getter
+  function_name = class_name_lc + "_get_property";
+  args_indent = string(function_name.length() + 2, ' ');
+  f_service_ << "static void" << endl << function_name << " (GObject *object," << endl
+             << args_indent << "guint property_id," << endl << args_indent << "GValue *value,"
+             << endl << args_indent << "GParamSpec *pspec)" << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl
+             << endl << indent() << "switch (property_id)" << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << "case PROP_" << class_name_uc << "_HANDLER:" << endl;
+  indent_up();
+  f_service_ << indent() << "g_value_set_object (value, self->handler);" << endl << indent()
+             << "break;" << endl;
+  indent_down();
+  f_service_ << indent() << "default:" << endl;
+  indent_up();
+  f_service_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
+             << endl << indent() << "break;" << endl;
+  indent_down();
+  scope_down(f_service_);
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generator the processor's dispose function
+  f_service_ << "static void" << endl << class_name_lc << "_dispose (GObject *gobject)" << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << class_name << " *self = " << class_name_uc << " (gobject);" << endl
+             << endl << indent() << "if (self->handler != NULL)" << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << "g_object_unref (self->handler);" << endl << indent()
+             << "self->handler = NULL;" << endl;
+  scope_down(f_service_);
+  f_service_ << endl << indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)"
+                                                                           "->dispose (gobject);"
+             << endl;
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generate processor finalize function
+  f_service_ << "static void" << endl << class_name_lc << "_finalize (GObject *gobject)" << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << this->nspace << service_name_ << "Processor *self = " << this->nspace_uc
+             << service_name_uc << "_PROCESSOR (gobject);" << endl << endl << indent()
+             << "thrift_safe_hash_table_destroy (self->process_map);" << endl << endl << indent()
+             << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)"
+                                                       "->finalize (gobject);" << endl;
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generate processor instance initializer
+  f_service_ << "static void" << endl << class_name_lc << "_init (" << class_name << " *self)"
+             << endl;
+  scope_up(f_service_);
+  if (functions.size() > 0) {
+    f_service_ << indent() << "guint index;" << endl
+               << endl;
+  }
+  f_service_ << indent() << "self->handler = NULL;" << endl << indent()
+             << "self->process_map = "
+                "g_hash_table_new (g_str_hash, g_str_equal);" << endl;
+  if (functions.size() > 0) {
+    args_indent = string(21, ' ');
+    f_service_ << endl
+               << indent() << "for (index = 0; index < "
+               << functions.size() << "; index += 1)" << endl;
+    indent_up();
+    f_service_ << indent() << "g_hash_table_insert (self->process_map," << endl
+               << indent() << args_indent
+               << class_name_lc << "_process_function_defs[index].name," << endl
+               << indent() << args_indent
+               << "&" << class_name_lc << "_process_function_defs[index]" << ");"
+               << endl;
+    indent_down();
+  }
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generate processor class initializer
+  f_service_ << "static void" << endl << class_name_lc << "_class_init (" << class_name
+             << "Class *cls)" << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl
+             << indent() << "ThriftDispatchProcessorClass *dispatch_processor_class =" << endl;
+  indent_up();
+  f_service_ << indent() << "THRIFT_DISPATCH_PROCESSOR_CLASS (cls);" << endl;
+  indent_down();
+  f_service_ << indent() << "GParamSpec *param_spec;" << endl << endl << indent()
+             << "gobject_class->dispose = " << class_name_lc << "_dispose;" << endl << indent()
+             << "gobject_class->finalize = " << class_name_lc << "_finalize;" << endl << indent()
+             << "gobject_class->set_property = " << class_name_lc << "_set_property;" << endl
+             << indent() << "gobject_class->get_property = " << class_name_lc << "_get_property;"
+             << endl << endl << indent()
+             << "dispatch_processor_class->dispatch_call = " << class_name_lc << "_dispatch_call;"
+             << endl << indent() << "cls->dispatch_call = " << class_name_lc << "_dispatch_call;"
+             << endl << endl << indent() << "param_spec = g_param_spec_object (\"handler\","
+             << endl;
+  args_indent = indent() + string(34, ' ');
+  f_service_ << args_indent << "\"Service handler implementation\"," << endl << args_indent
+             << "\"The service handler implementation \"" << endl << args_indent
+             << "\"to which method calls are dispatched.\"," << endl << args_indent
+             << this->nspace_uc + "TYPE_" + service_name_uc + "_HANDLER," << endl << args_indent
+             << "G_PARAM_READWRITE);" << endl;
+  f_service_ << indent() << "g_object_class_install_property (gobject_class," << endl;
+  args_indent = indent() + string(33, ' ');
+  f_service_ << args_indent << "PROP_" << class_name_uc << "_HANDLER," << endl << args_indent
+             << "param_spec);" << endl;
+  scope_down(f_service_);
+}
+
+/**
+ * Generates C code that represents a Thrift service server.
+ */
+void t_c_glib_generator::generate_service_server(t_service* tservice) {
+  (void)tservice;
+  // Generate the service's handler class
+  generate_service_handler(tservice);
+
+  // Generate the service's processor class
+  generate_service_processor(tservice);
+}
+
+/**
+ * Generates C code to represent a THrift structure as a GObject.
+ */
+void t_c_glib_generator::generate_object(t_struct* tstruct) {
+  string name = tstruct->get_name();
+  string name_u = initial_caps_to_underscores(name);
+  string name_uc = to_upper_case(name_u);
+
+  string class_name = this->nspace + name;
+  string class_name_lc = this->nspace_lc + initial_caps_to_underscores(name);
+  string class_name_uc = to_upper_case(class_name_lc);
+
+  string function_name;
+  string args_indent;
+
+  // write the instance definition
+  f_types_ << "struct _" << this->nspace << name << endl << "{ " << endl
+           << "  ThriftStruct parent; " << endl << endl << "  /* public */" << endl;
+
+  // for each field, add a member variable
+  vector<t_field*>::const_iterator m_iter;
+  const vector<t_field*>& members = tstruct->get_members();
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    f_types_ << "  " << type_name(t) << " " << (*m_iter)->get_name() << ";" << endl;
+    if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
+      f_types_ << "  gboolean __isset_" << (*m_iter)->get_name() << ";" << endl;
+    }
+  }
+
+  // close the structure definition and create a typedef
+  f_types_ << "};" << endl << "typedef struct _" << this->nspace << name << " " << this->nspace
+           << name << ";" << endl << endl;
+
+  // write the class definition
+  f_types_ << "struct _" << this->nspace << name << "Class" << endl << "{" << endl
+           << "  ThriftStructClass parent;" << endl << "};" << endl << "typedef struct _"
+           << this->nspace << name << "Class " << this->nspace << name << "Class;" << endl << endl;
+
+  // write the standard GObject boilerplate
+  f_types_ << "GType " << this->nspace_lc << name_u << "_get_type (void);" << endl << "#define "
+           << this->nspace_uc << "TYPE_" << name_uc << " (" << this->nspace_lc << name_u
+           << "_get_type())" << endl << "#define " << this->nspace_uc << name_uc
+           << "(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" << name_uc
+           << ", " << this->nspace << name << "))" << endl << "#define " << this->nspace_uc
+           << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "_TYPE_"
+           << name_uc << ", " << this->nspace << name << "Class))" << endl << "#define "
+           << this->nspace_uc << "IS_" << name_uc << "(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), "
+           << this->nspace_uc << "TYPE_" << name_uc << "))" << endl << "#define " << this->nspace_uc
+           << "IS_" << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc
+           << "TYPE_" << name_uc << "))" << endl << "#define " << this->nspace_uc << name_uc
+           << "_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_"
+           << name_uc << ", " << this->nspace << name << "Class))" << endl << endl;
+
+  // start writing the object implementation .c file
+
+  // generate properties enum
+  if (members.size() > 0) {
+    f_types_impl_ << "enum _" << class_name << "Properties" << endl << "{" << endl;
+    indent_up();
+    f_types_impl_ << indent() << "PROP_" << class_name_uc << "_0";
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      string member_name_uc
+          = to_upper_case(to_lower_case(initial_caps_to_underscores((*m_iter)->get_name())));
+
+      f_types_impl_ << "," << endl << indent() << "PROP_" << class_name_uc << "_" << member_name_uc;
+    }
+    f_types_impl_ << endl;
+    indent_down();
+    f_types_impl_ << "};" << endl << endl;
+  }
+
+  // generate struct I/O methods
+  string this_get = this->nspace + name + " * this_object = " + this->nspace_uc + name_uc
+                    + "(object);";
+  generate_struct_reader(f_types_impl_, tstruct, "this_object->", this_get);
+  generate_struct_writer(f_types_impl_, tstruct, "this_object->", this_get);
+
+  // generate property setter and getter
+  if (members.size() > 0) {
+    // generate property setter
+    function_name = class_name_lc + "_set_property";
+    args_indent = string(function_name.length() + 2, ' ');
+    f_types_impl_ << "static void" << endl << function_name << " (GObject *object," << endl
+                  << args_indent << "guint property_id," << endl << args_indent
+                  << "const GValue *value," << endl << args_indent << "GParamSpec *pspec)" << endl;
+    scope_up(f_types_impl_);
+    f_types_impl_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl
+                  << endl << indent() << "switch (property_id)" << endl;
+    scope_up(f_types_impl_);
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_field* member = (*m_iter);
+      string member_name = member->get_name();
+      string member_name_uc
+          = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name)));
+      t_type* member_type = get_true_type(member->get_type());
+
+      string property_identifier = "PROP_" + class_name_uc + "_" + member_name_uc;
+
+      f_types_impl_ << indent() << "case " << property_identifier + ":" << endl;
+      indent_up();
+
+      if (member_type->is_base_type()) {
+        t_base_type* base_type = ((t_base_type*)member_type);
+        string assign_function_name;
+
+        if (base_type->get_base() == t_base_type::TYPE_STRING) {
+          string release_function_name;
+
+          f_types_impl_ << indent() << "if (self->" << member_name << " != NULL)" << endl;
+          indent_up();
+
+          if (base_type->is_binary()) {
+            release_function_name = "g_byte_array_unref";
+            assign_function_name = "g_value_dup_boxed";
+          } else {
+            release_function_name = "g_free";
+            assign_function_name = "g_value_dup_string";
+          }
+
+          f_types_impl_ << indent() << release_function_name << " (self->" << member_name << ");"
+                        << endl;
+          indent_down();
+        } else {
+          switch (base_type->get_base()) {
+          case t_base_type::TYPE_BOOL:
+            assign_function_name = "g_value_get_boolean";
+            break;
+
+          case t_base_type::TYPE_I8:
+          case t_base_type::TYPE_I16:
+          case t_base_type::TYPE_I32:
+            assign_function_name = "g_value_get_int";
+            break;
+
+          case t_base_type::TYPE_I64:
+            assign_function_name = "g_value_get_int64";
+            break;
+
+          case t_base_type::TYPE_DOUBLE:
+            assign_function_name = "g_value_get_double";
+            break;
+
+          default:
+            throw "compiler error: "
+                  "unrecognized base type \"" + base_type->get_name() + "\" "
+                                                                        "for struct member \""
+                + member_name + "\"";
+            break;
+          }
+        }
+
+        f_types_impl_ << indent() << "self->" << member_name << " = " << assign_function_name
+                      << " (value);" << endl;
+      } else if (member_type->is_enum()) {
+        f_types_impl_ << indent() << "self->" << member_name << " = g_value_get_int (value);"
+                      << endl;
+      } else if (member_type->is_container()) {
+        string release_function_name;
+        string assign_function_name;
+
+        if (member_type->is_list()) {
+          t_type* elem_type = ((t_list*)member_type)->get_elem_type();
+
+          // Lists of base types other than strings are represented as GArrays;
+          // all others as GPtrArrays
+          if (is_numeric(elem_type)) {
+            release_function_name = "g_array_unref";
+          } else {
+            release_function_name = "g_ptr_array_unref";
+          }
+
+          assign_function_name = "g_value_dup_boxed";
+        } else if (member_type->is_set() || member_type->is_map()) {
+          release_function_name = "g_hash_table_unref";
+          assign_function_name = "g_value_dup_boxed";
+        }
+
+        f_types_impl_ << indent() << "if (self->" << member_name << " != NULL)" << endl;
+        indent_up();
+        f_types_impl_ << indent() << release_function_name << " (self->" << member_name << ");"
+                      << endl;
+        indent_down();
+        f_types_impl_ << indent() << "self->" << member_name << " = " << assign_function_name
+                      << " (value);" << endl;
+      } else if (member_type->is_struct() || member_type->is_xception()) {
+        f_types_impl_ << indent() << "if (self->" << member_name << " != NULL)" << endl;
+        indent_up();
+        f_types_impl_ << indent() << "g_object_unref (self->" << member_name << ");" << endl;
+        indent_down();
+        f_types_impl_ << indent() << "self->" << member_name << " = g_value_dup_object (value);"
+                      << endl;
+      }
+
+      if (member->get_req() != t_field::T_REQUIRED) {
+        f_types_impl_ << indent() << "self->__isset_" << member_name << " = TRUE;" << endl;
+      }
+
+      f_types_impl_ << indent() << "break;" << endl << endl;
+      indent_down();
+    }
+    f_types_impl_ << indent() << "default:" << endl;
+    indent_up();
+    f_types_impl_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
+                  << endl << indent() << "break;" << endl;
+    indent_down();
+    scope_down(f_types_impl_);
+    scope_down(f_types_impl_);
+    f_types_impl_ << endl;
+
+    // generate property getter
+    function_name = class_name_lc + "_get_property";
+    args_indent = string(function_name.length() + 2, ' ');
+    f_types_impl_ << "static void" << endl << function_name << " (GObject *object," << endl
+                  << args_indent << "guint property_id," << endl << args_indent << "GValue *value,"
+                  << endl << args_indent << "GParamSpec *pspec)" << endl;
+    scope_up(f_types_impl_);
+    f_types_impl_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl
+                  << endl << indent() << "switch (property_id)" << endl;
+    scope_up(f_types_impl_);
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_field* member = (*m_iter);
+      string member_name = (*m_iter)->get_name();
+      string member_name_uc
+          = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name)));
+      t_type* member_type = get_true_type(member->get_type());
+
+      string property_identifier = "PROP_" + class_name_uc + "_" + member_name_uc;
+
+      string setter_function_name;
+
+      if (member_type->is_base_type()) {
+        t_base_type* base_type = ((t_base_type*)member_type);
+
+        switch (base_type->get_base()) {
+        case t_base_type::TYPE_BOOL:
+          setter_function_name = "g_value_set_boolean";
+          break;
+
+        case t_base_type::TYPE_I8:
+        case t_base_type::TYPE_I16:
+        case t_base_type::TYPE_I32:
+          setter_function_name = "g_value_set_int";
+          break;
+
+        case t_base_type::TYPE_I64:
+          setter_function_name = "g_value_set_int64";
+          break;
+
+        case t_base_type::TYPE_DOUBLE:
+          setter_function_name = "g_value_set_double";
+          break;
+
+        case t_base_type::TYPE_STRING:
+          if (base_type->is_binary()) {
+            setter_function_name = "g_value_set_boxed";
+          } else {
+            setter_function_name = "g_value_set_string";
+          }
+          break;
+
+        default:
+          throw "compiler error: "
+                "unrecognized base type \"" + base_type->get_name() + "\" "
+                                                                      "for struct member \""
+              + member_name + "\"";
+          break;
+        }
+      } else if (member_type->is_enum()) {
+        setter_function_name = "g_value_set_int";
+      } else if (member_type->is_struct() || member_type->is_xception()) {
+        setter_function_name = "g_value_set_object";
+      } else if (member_type->is_container()) {
+        setter_function_name = "g_value_set_boxed";
+      } else {
+        throw "compiler error: "
+              "unrecognized type for struct member \"" + member_name + "\"";
+      }
+
+      f_types_impl_ << indent() << "case " << property_identifier + ":" << endl;
+      indent_up();
+      f_types_impl_ << indent() << setter_function_name << " (value, self->" << member_name << ");"
+                    << endl << indent() << "break;" << endl << endl;
+      indent_down();
+    }
+    f_types_impl_ << indent() << "default:" << endl;
+    indent_up();
+    f_types_impl_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
+                  << endl << indent() << "break;" << endl;
+    indent_down();
+    scope_down(f_types_impl_);
+    scope_down(f_types_impl_);
+    f_types_impl_ << endl;
+  }
+
+  // generate the instance init function
+
+  f_types_impl_ << "static void " << endl << this->nspace_lc << name_u << "_instance_init ("
+                << this->nspace << name << " * object)" << endl << "{" << endl;
+  indent_up();
+
+  // generate default-value structures for container-type members
+  bool constant_declaration_output = false;
+  bool string_list_constant_output = false;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* member = *m_iter;
+    t_const_value* member_value = member->get_value();
+
+    if (member_value != NULL) {
+      string member_name = member->get_name();
+      t_type* member_type = get_true_type(member->get_type());
+
+      if (member_type->is_list()) {
+        const vector<t_const_value*>& list = member_value->get_list();
+        t_type* elem_type = ((t_list*)member_type)->get_elem_type();
+
+        // Generate an array with the list literal
+        indent(f_types_impl_) << "static " << type_name(elem_type, false, true) << " __default_"
+                              << member_name << "[" << list.size() << "] = " << endl;
+        indent_up();
+        f_types_impl_ << indent() << constant_literal(member_type, member_value) << ";" << endl;
+        indent_down();
+
+        constant_declaration_output = true;
+
+        // If we are generating values for a pointer array (i.e. a list of
+        // strings), set a flag so we know to also declare an index variable to
+        // use in pre-populating the array
+        if (elem_type->is_string()) {
+          string_list_constant_output = true;
+        }
+      }
+
+      // TODO: Handle container types other than list
+    }
+  }
+  if (constant_declaration_output) {
+    if (string_list_constant_output) {
+      indent(f_types_impl_) << "unsigned int list_index;" << endl;
+    }
+
+    f_types_impl_ << endl;
+  }
+
+  // satisfy compilers with -Wall turned on
+  indent(f_types_impl_) << "/* satisfy -Wall */" << endl << indent()
+                        << "THRIFT_UNUSED_VAR (object);" << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* member_type = (*m_iter)->get_type();
+    t_type* t = get_true_type(member_type);
+    if (t->is_base_type()) {
+      string dval = " = ";
+      if (t->is_enum()) {
+        dval += "(" + type_name(t) + ")";
+      }
+      t_const_value* cv = (*m_iter)->get_value();
+      if (cv != NULL) {
+        dval += constant_value("", t, cv);
+      } else {
+        dval += t->is_string() ? "NULL" : "0";
+      }
+      indent(f_types_impl_) << "object->" << (*m_iter)->get_name() << dval << ";" << endl;
+    } else if (t->is_struct()) {
+      string name = (*m_iter)->get_name();
+      t_program* type_program = member_type->get_program();
+      string type_nspace = type_program ? type_program->get_namespace("c_glib") : "";
+      string type_nspace_prefix =
+        type_nspace.empty() ? "" : initial_caps_to_underscores(type_nspace) + "_";
+      string type_name_uc = to_upper_case(initial_caps_to_underscores(member_type->get_name()));
+      indent(f_types_impl_) << "object->" << name << " = g_object_new ("
+                            << to_upper_case(type_nspace_prefix) << "TYPE_" << type_name_uc
+                            << ", NULL);" << endl;
+    } else if (t->is_xception()) {
+      string name = (*m_iter)->get_name();
+      indent(f_types_impl_) << "object->" << name << " = NULL;" << endl;
+    } else if (t->is_container()) {
+      string name = (*m_iter)->get_name();
+      string init_function;
+      t_type* etype = NULL;
+
+      if (t->is_map()) {
+        t_type* key = ((t_map*)t)->get_key_type();
+        t_type* value = ((t_map*)t)->get_val_type();
+        init_function = generate_new_hash_from_type(key, value);
+      } else if (t->is_set()) {
+        etype = ((t_set*)t)->get_elem_type();
+        init_function = generate_new_hash_from_type(etype, NULL);
+      } else if (t->is_list()) {
+        etype = ((t_list*)t)->get_elem_type();
+        init_function = generate_new_array_from_type(etype);
+      }
+
+      indent(f_types_impl_) << "object->" << name << " = " << init_function << endl;
+
+      // Pre-populate the container with the specified default values, if any
+      if ((*m_iter)->get_value()) {
+        t_const_value* member_value = (*m_iter)->get_value();
+
+        if (t->is_list()) {
+          const vector<t_const_value*>& list = member_value->get_list();
+
+          if (is_numeric(etype)) {
+            indent(f_types_impl_) <<
+              "g_array_append_vals (object->" << name << ", &__default_" <<
+              name << ", " << list.size() << ");" << endl;
+          }
+          else {
+            indent(f_types_impl_) <<
+              "for (list_index = 0; list_index < " << list.size() << "; " <<
+              "list_index += 1)" << endl;
+            indent_up();
+            indent(f_types_impl_) <<
+              "g_ptr_array_add (object->" << name << "," << endl <<
+              indent() << string(17, ' ') << "g_strdup (__default_" <<
+              name << "[list_index]));" << endl;
+            indent_down();
+          }
+        }
+
+        // TODO: Handle container types other than list
+      }
+    }
+
+    /* if not required, initialize the __isset variable */
+    if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
+      indent(f_types_impl_) << "object->__isset_" << (*m_iter)->get_name() << " = FALSE;" << endl;
+    }
+  }
+
+  indent_down();
+  f_types_impl_ << "}" << endl << endl;
+
+  /* create the destructor */
+  f_types_impl_ << "static void " << endl << this->nspace_lc << name_u
+                << "_finalize (GObject *object)" << endl << "{" << endl;
+  indent_up();
+
+  f_types_impl_ << indent() << this->nspace << name << " *tobject = " << this->nspace_uc << name_uc
+                << " (object);" << endl << endl;
+
+  f_types_impl_ << indent() << "/* satisfy -Wall in case we don't use tobject */" << endl
+                << indent() << "THRIFT_UNUSED_VAR (tobject);" << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    if (t->is_container()) {
+      string name = (*m_iter)->get_name();
+      if (t->is_map() || t->is_set()) {
+        f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl;
+        f_types_impl_ << indent() << "{" << endl;
+        indent_up();
+        f_types_impl_ << indent() << "g_hash_table_destroy (tobject->" << name << ");" << endl;
+        f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl;
+        indent_down();
+        f_types_impl_ << indent() << "}" << endl;
+      } else if (t->is_list()) {
+        t_type* etype = ((t_list*)t)->get_elem_type();
+        string destructor_function = "g_ptr_array_unref";
+
+        if (etype->is_base_type()) {
+          t_base_type::t_base tbase = ((t_base_type*)etype)->get_base();
+          switch (tbase) {
+          case t_base_type::TYPE_VOID:
+            throw "compiler error: cannot determine array type";
+          case t_base_type::TYPE_BOOL:
+          case t_base_type::TYPE_I8:
+          case t_base_type::TYPE_I16:
+          case t_base_type::TYPE_I32:
+          case t_base_type::TYPE_I64:
+          case t_base_type::TYPE_DOUBLE:
+            destructor_function = "g_array_unref";
+            break;
+          case t_base_type::TYPE_STRING:
+            break;
+          default:
+            throw "compiler error: no array info for type";
+          }
+        } else if (etype->is_enum()) {
+          destructor_function = "g_array_unref";
+        }
+
+        f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl;
+        f_types_impl_ << indent() << "{" << endl;
+        indent_up();
+        f_types_impl_ << indent() << destructor_function << " (tobject->" << name << ");" << endl;
+        f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl;
+        indent_down();
+        f_types_impl_ << indent() << "}" << endl;
+      }
+    } else if (t->is_struct() || t->is_xception()) {
+      string name = (*m_iter)->get_name();
+      // TODO: g_clear_object needs glib >= 2.28
+      // f_types_impl_ << indent() << "g_clear_object (&(tobject->" << name << "));" << endl;
+      // does g_object_unref the trick?
+      f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl;
+      f_types_impl_ << indent() << "{" << endl;
+      indent_up();
+      f_types_impl_ << indent() << "g_object_unref(tobject->" << name << ");" << endl;
+      f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl;
+      indent_down();
+      f_types_impl_ << indent() << "}" << endl;
+    } else if (t->is_string()) {
+      string name = (*m_iter)->get_name();
+      f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl;
+      f_types_impl_ << indent() << "{" << endl;
+      indent_up();
+      f_types_impl_ << indent() << generate_free_func_from_type(t) << "(tobject->" << name << ");"
+                    << endl;
+      f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl;
+      indent_down();
+      f_types_impl_ << indent() << "}" << endl;
+    }
+  }
+
+  indent_down();
+  f_types_impl_ << "}" << endl << endl;
+
+  // generate the class init function
+
+  f_types_impl_ << "static void" << endl << class_name_lc << "_class_init (" << class_name
+                << "Class * cls)" << endl;
+  scope_up(f_types_impl_);
+
+  f_types_impl_ << indent() << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl
+                << indent() << "ThriftStructClass *struct_class = "
+                << "THRIFT_STRUCT_CLASS (cls);" << endl << endl << indent()
+                << "struct_class->read = " << class_name_lc << "_read;" << endl << indent()
+                << "struct_class->write = " << class_name_lc << "_write;" << endl << endl
+                << indent() << "gobject_class->finalize = " << class_name_lc << "_finalize;"
+                << endl;
+  if (members.size() > 0) {
+    f_types_impl_ << indent() << "gobject_class->get_property = " << class_name_lc
+                  << "_get_property;" << endl << indent()
+                  << "gobject_class->set_property = " << class_name_lc << "_set_property;" << endl;
+
+    // install a property for each member
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_field* member = (*m_iter);
+      string member_name = member->get_name();
+      string member_name_uc
+          = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name)));
+      t_type* member_type = get_true_type(member->get_type());
+      t_const_value* member_value = member->get_value();
+
+      string property_identifier = "PROP_" + class_name_uc + "_" + member_name_uc;
+
+      f_types_impl_ << endl << indent() << "g_object_class_install_property" << endl;
+      indent_up();
+      args_indent = indent() + ' ';
+      f_types_impl_ << indent() << "(gobject_class," << endl << args_indent << property_identifier
+                    << "," << endl << args_indent;
+
+      if (member_type->is_base_type()) {
+        t_base_type::t_base base_type = ((t_base_type*)member_type)->get_base();
+
+        if (base_type == t_base_type::TYPE_STRING) {
+          if (((t_base_type*)member_type)->is_binary()) {
+            args_indent += string(20, ' ');
+            f_types_impl_ << "g_param_spec_boxed (\"" << member_name << "\"," << endl << args_indent
+                          << "NULL," << endl << args_indent << "NULL," << endl << args_indent
+                          << "G_TYPE_BYTE_ARRAY," << endl << args_indent << "G_PARAM_READWRITE));"
+                          << endl;
+          } else {
+            args_indent += string(21, ' ');
+            f_types_impl_ << "g_param_spec_string (\"" << member_name << "\"," << endl
+                          << args_indent << "NULL," << endl << args_indent << "NULL," << endl
+                          << args_indent
+                          << ((member_value != NULL) ? "\"" + member_value->get_string() + "\""
+                                                     : "NULL") << "," << endl << args_indent
+                          << "G_PARAM_READWRITE));" << endl;
+          }
+        } else if (base_type == t_base_type::TYPE_BOOL) {
+          args_indent += string(22, ' ');
+          f_types_impl_ << "g_param_spec_boolean (\"" << member_name << "\"," << endl << args_indent
+                        << "NULL," << endl << args_indent << "NULL," << endl << args_indent
+                        << (((member_value != NULL) && (member_value->get_integer() != 0))
+                                ? "TRUE"
+                                : "FALSE") << "," << endl << args_indent << "G_PARAM_READWRITE));"
+                        << endl;
+        } else if ((base_type == t_base_type::TYPE_I8) || (base_type == t_base_type::TYPE_I16)
+                   || (base_type == t_base_type::TYPE_I32) || (base_type == t_base_type::TYPE_I64)
+                   || (base_type == t_base_type::TYPE_DOUBLE)) {
+          string param_spec_function_name = "g_param_spec_int";
+          string min_value;
+          string max_value;
+          ostringstream default_value;
+
+          switch (base_type) {
+          case t_base_type::TYPE_I8:
+            min_value = "G_MININT8";
+            max_value = "G_MAXINT8";
+            break;
+
+          case t_base_type::TYPE_I16:
+            min_value = "G_MININT16";
+            max_value = "G_MAXINT16";
+            break;
+
+          case t_base_type::TYPE_I32:
+            min_value = "G_MININT32";
+            max_value = "G_MAXINT32";
+            break;
+
+          case t_base_type::TYPE_I64:
+            param_spec_function_name = "g_param_spec_int64";
+            min_value = "G_MININT64";
+            max_value = "G_MAXINT64";
+            break;
+
+          case t_base_type::TYPE_DOUBLE:
+            param_spec_function_name = "g_param_spec_double";
+            min_value = "-INFINITY";
+            max_value = "INFINITY";
+            break;
+
+          default:
+            throw "compiler error: "
+                  "unrecognized base type \"" + member_type->get_name() + "\" "
+                                                                          "for struct member \""
+                + member_name + "\"";
+            break;
+          }
+
+          if (member_value != NULL) {
+            default_value << (base_type == t_base_type::TYPE_DOUBLE ? member_value->get_double()
+                                                                    : member_value->get_integer());
+          } else {
+            default_value << "0";
+          }
+
+          args_indent += string(param_spec_function_name.length() + 2, ' ');
+          f_types_impl_ << param_spec_function_name << " (\"" << member_name << "\"," << endl
+                        << args_indent << "NULL," << endl << args_indent << "NULL," << endl
+                        << args_indent << min_value << "," << endl << args_indent << max_value
+                        << "," << endl << args_indent << default_value.str() << "," << endl
+                        << args_indent << "G_PARAM_READWRITE));" << endl;
+        }
+
+        indent_down();
+      } else if (member_type->is_enum()) {
+        t_enum_value* enum_min_value = ((t_enum*)member_type)->get_min_value();
+        t_enum_value* enum_max_value = ((t_enum*)member_type)->get_max_value();
+        int min_value = (enum_min_value != NULL) ? enum_min_value->get_value() : 0;
+        int max_value = (enum_max_value != NULL) ? enum_max_value->get_value() : 0;
+
+        args_indent += string(18, ' ');
+        f_types_impl_ << "g_param_spec_int (\"" << member_name << "\"," << endl << args_indent
+                      << "NULL," << endl << args_indent << "NULL," << endl << args_indent
+                      << min_value << "," << endl << args_indent << max_value << "," << endl
+                      << args_indent << min_value << "," << endl << args_indent
+                      << "G_PARAM_READWRITE));" << endl;
+        indent_down();
+      } else if (member_type->is_struct() || member_type->is_xception()) {
+        t_program* type_program = member_type->get_program();
+        string type_nspace = type_program ? type_program->get_namespace("c_glib") : "";
+        string type_nspace_prefix =
+          type_nspace.empty() ? "" : initial_caps_to_underscores(type_nspace) + "_";
+
+        string param_type = to_upper_case(type_nspace_prefix) + "TYPE_"
+                            + to_upper_case(initial_caps_to_underscores(member_type->get_name()));
+
+        args_indent += string(20, ' ');
+        f_types_impl_ << "g_param_spec_object (\"" << member_name << "\"," << endl << args_indent
+                      << "NULL," << endl << args_indent << "NULL," << endl << args_indent
+                      << param_type << "," << endl << args_indent << "G_PARAM_READWRITE));" << endl;
+        indent_down();
+      } else if (member_type->is_list()) {
+        t_type* elem_type = ((t_list*)member_type)->get_elem_type();
+        string param_type;
+
+        if (elem_type->is_base_type() && !elem_type->is_string()) {
+          param_type = "G_TYPE_ARRAY";
+        } else {
+          param_type = "G_TYPE_PTR_ARRAY";
+        }
+
+        args_indent += string(20, ' ');
+        f_types_impl_ << "g_param_spec_boxed (\"" << member_name << "\"," << endl << args_indent
+                      << "NULL," << endl << args_indent << "NULL," << endl << args_indent
+                      << param_type << "," << endl << args_indent << "G_PARAM_READWRITE));" << endl;
+        indent_down();
+      } else if (member_type->is_set() || member_type->is_map()) {
+        args_indent += string(20, ' ');
+        f_types_impl_ << "g_param_spec_boxed (\"" << member_name << "\"," << endl << args_indent
+                      << "NULL," << endl << args_indent << "NULL," << endl << args_indent
+                      << "G_TYPE_HASH_TABLE," << endl << args_indent << "G_PARAM_READWRITE));"
+                      << endl;
+        indent_down();
+      }
+    }
+  }
+  scope_down(f_types_impl_);
+  f_types_impl_ << endl;
+
+  f_types_impl_ << "GType" << endl << this->nspace_lc << name_u << "_get_type (void)" << endl << "{"
+                << endl << "  static GType type = 0;" << endl << endl << "  if (type == 0) " << endl
+                << "  {" << endl << "    static const GTypeInfo type_info = " << endl << "    {"
+                << endl << "      sizeof (" << this->nspace << name << "Class)," << endl
+                << "      NULL, /* base_init */" << endl << "      NULL, /* base_finalize */"
+                << endl << "      (GClassInitFunc) " << this->nspace_lc << name_u << "_class_init,"
+                << endl << "      NULL, /* class_finalize */" << endl
+                << "      NULL, /* class_data */" << endl << "      sizeof (" << this->nspace
+                << name << ")," << endl << "      0, /* n_preallocs */" << endl
+                << "      (GInstanceInitFunc) " << this->nspace_lc << name_u << "_instance_init,"
+                << endl << "      NULL, /* value_table */" << endl << "    };" << endl << endl
+                << "    type = g_type_register_static (THRIFT_TYPE_STRUCT, " << endl
+                << "                                   \"" << this->nspace << name << "Type\","
+                << endl << "                                   &type_info, 0);" << endl << "  }"
+                << endl << endl << "  return type;" << endl << "}" << endl << endl;
+}
+
+/**
+ * Generates functions to write Thrift structures to a stream.
+ */
+void t_c_glib_generator::generate_struct_writer(ostream& out,
+                                                t_struct* tstruct,
+                                                string this_name,
+                                                string this_get,
+                                                bool is_function) {
+  string name = tstruct->get_name();
+  string name_u = initial_caps_to_underscores(name);
+  string name_uc = to_upper_case(name_u);
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  int error_ret = 0;
+
+  if (is_function) {
+    error_ret = -1;
+    indent(out) << "static gint32" << endl << this->nspace_lc << name_u
+                << "_write (ThriftStruct *object, ThriftProtocol *protocol, GError **error)"
+                << endl;
+  }
+  indent(out) << "{" << endl;
+  indent_up();
+
+  out << indent() << "gint32 ret;" << endl << indent() << "gint32 xfer = 0;" << endl << endl;
+
+  indent(out) << this_get << endl;
+  // satisfy -Wall in the case of an empty struct
+  if (!this_get.empty()) {
+    indent(out) << "THRIFT_UNUSED_VAR (this_object);" << endl;
+  }
+
+  out << indent() << "if ((ret = thrift_protocol_write_struct_begin (protocol, \"" << name
+      << "\", error)) < 0)" << endl << indent() << "  return " << error_ret << ";" << endl
+      << indent() << "xfer += ret;" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
+      indent(out) << "if (this_object->__isset_" << (*f_iter)->get_name() << " == TRUE) {" << endl;
+      indent_up();
+    }
+
+    out << indent() << "if ((ret = thrift_protocol_write_field_begin (protocol, "
+        << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", "
+        << (*f_iter)->get_key() << ", error)) < 0)" << endl << indent() << "  return " << error_ret
+        << ";" << endl << indent() << "xfer += ret;" << endl;
+    generate_serialize_field(out, *f_iter, this_name, "", error_ret);
+    out << indent() << "if ((ret = thrift_protocol_write_field_end (protocol, error)) < 0)" << endl
+        << indent() << "  return " << error_ret << ";" << endl << indent() << "xfer += ret;"
+        << endl;
+
+    if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+
+  // write the struct map
+  out << indent() << "if ((ret = thrift_protocol_write_field_stop (protocol, error)) < 0)" << endl
+      << indent() << "  return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl
+      << indent() << "if ((ret = thrift_protocol_write_struct_end (protocol, error)) < 0)" << endl
+      << indent() << "  return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl
+      << endl;
+
+  if (is_function) {
+    indent(out) << "return xfer;" << endl;
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates code to read Thrift structures from a stream.
+ */
+void t_c_glib_generator::generate_struct_reader(ostream& out,
+                                                t_struct* tstruct,
+                                                string this_name,
+                                                string this_get,
+                                                bool is_function) {
+  string name = tstruct->get_name();
+  string name_u = initial_caps_to_underscores(name);
+  string name_uc = to_upper_case(name_u);
+  int error_ret = 0;
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  if (is_function) {
+    error_ret = -1;
+    indent(out) << "/* reads a " << name_u << " object */" << endl << "static gint32" << endl
+                << this->nspace_lc << name_u
+                << "_read (ThriftStruct *object, ThriftProtocol *protocol, GError **error)" << endl;
+  }
+
+  indent(out) << "{" << endl;
+  indent_up();
+
+  // declare stack temp variables
+  out << indent() << "gint32 ret;" << endl << indent() << "gint32 xfer = 0;" << endl << indent()
+      << "gchar *name = NULL;" << endl << indent() << "ThriftType ftype;" << endl << indent()
+      << "gint16 fid;" << endl << indent() << "guint32 len = 0;" << endl << indent()
+      << "gpointer data = NULL;" << endl << indent() << this_get << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      indent(out) << "gboolean isset_" << (*f_iter)->get_name() << " = FALSE;" << endl;
+    }
+  }
+
+  out << endl;
+
+  // satisfy -Wall in case we don't use some variables
+  out << indent() << "/* satisfy -Wall in case these aren't used */" << endl << indent()
+      << "THRIFT_UNUSED_VAR (len);" << endl << indent() << "THRIFT_UNUSED_VAR (data);" << endl;
+
+  if (!this_get.empty()) {
+    out << indent() << "THRIFT_UNUSED_VAR (this_object);" << endl;
+  }
+  out << endl;
+
+  // read the beginning of the structure marker
+  out << indent() << "/* read the struct begin marker */" << endl << indent()
+      << "if ((ret = thrift_protocol_read_struct_begin (protocol, &name, error)) < 0)" << endl
+      << indent() << "{" << endl << indent() << "  if (name) g_free (name);" << endl << indent()
+      << "  return " << error_ret << ";" << endl << indent() << "}" << endl << indent()
+      << "xfer += ret;" << endl << indent() << "if (name) g_free (name);" << endl << indent()
+      << "name = NULL;" << endl << endl;
+
+  // read the struct fields
+  out << indent() << "/* read the struct fields */" << endl << indent() << "while (1)" << endl;
+  scope_up(out);
+
+  // read beginning field marker
+  out << indent() << "/* read the beginning of a field */" << endl << indent()
+      << "if ((ret = thrift_protocol_read_field_begin (protocol, &name, &ftype, &fid, error)) < 0)"
+      << endl << indent() << "{" << endl << indent() << "  if (name) g_free (name);" << endl
+      << indent() << "  return " << error_ret << ";" << endl << indent() << "}" << endl << indent()
+      << "xfer += ret;" << endl << indent() << "if (name) g_free (name);" << endl << indent()
+      << "name = NULL;" << endl << endl;
+
+  // check for field STOP marker
+  out << indent() << "/* break if we get a STOP field */" << endl << indent()
+      << "if (ftype == T_STOP)" << endl << indent() << "{" << endl << indent() << "  break;" << endl
+      << indent() << "}" << endl << endl;
+
+  // switch depending on the field type
+  indent(out) << "switch (fid)" << endl;
+
+  // start switch
+  scope_up(out);
+
+  // generate deserialization code for known types
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) << "case " << (*f_iter)->get_key() << ":" << endl;
+    indent_up();
+    indent(out) << "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ")" << endl;
+    indent(out) << "{" << endl;
+
+    indent_up();
+    // generate deserialize field
+    generate_deserialize_field(out, *f_iter, this_name, "", error_ret, false);
+    indent_down();
+
+    out << indent() << "} else {" << endl << indent()
+        << "  if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl << indent()
+        << "    return " << error_ret << ";" << endl << indent() << "  xfer += ret;" << endl
+        << indent() << "}" << endl << indent() << "break;" << endl;
+    indent_down();
+  }
+
+  // create the default case
+  out << indent() << "default:" << endl << indent()
+      << "  if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl << indent()
+      << "    return " << error_ret << ";" << endl << indent() << "  xfer += ret;" << endl
+      << indent() << "  break;" << endl;
+
+  // end switch
+  scope_down(out);
+
+  // read field end marker
+  out << indent() << "if ((ret = thrift_protocol_read_field_end (protocol, error)) < 0)" << endl
+      << indent() << "  return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl;
+
+  // end while loop
+  scope_down(out);
+  out << endl;
+
+  // read the end of the structure
+  out << indent() << "if ((ret = thrift_protocol_read_struct_end (protocol, error)) < 0)" << endl
+      << indent() << "  return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl
+      << endl;
+
+  // if a required field is missing, throw an error
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      out << indent() << "if (!isset_" << (*f_iter)->get_name() << ")" << endl << indent() << "{"
+          << endl << indent() << "  g_set_error (error, THRIFT_PROTOCOL_ERROR," << endl << indent()
+          << "               THRIFT_PROTOCOL_ERROR_INVALID_DATA," << endl << indent()
+          << "               \"missing field\");" << endl << indent() << "  return -1;" << endl
+          << indent() << "}" << endl << endl;
+    }
+  }
+
+  if (is_function) {
+    indent(out) << "return xfer;" << endl;
+  }
+
+  // end the function/structure
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+void t_c_glib_generator::generate_serialize_field(ostream& out,
+                                                  t_field* tfield,
+                                                  string prefix,
+                                                  string suffix,
+                                                  int error_ret) {
+  t_type* type = get_true_type(tfield->get_type());
+  string name = prefix + tfield->get_name() + suffix;
+
+  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, error_ret);
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, name, error_ret);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) << "if ((ret = thrift_protocol_write_";
+
+    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_BOOL:
+        out << "bool (protocol, " << name;
+        break;
+      case t_base_type::TYPE_I8:
+        out << "byte (protocol, " << name;
+        break;
+      case t_base_type::TYPE_I16:
+        out << "i16 (protocol, " << name;
+        break;
+      case t_base_type::TYPE_I32:
+        out << "i32 (protocol, " << name;
+        break;
+      case t_base_type::TYPE_I64:
+        out << "i64 (protocol, " << name;
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "double (protocol, " << name;
+        break;
+      case t_base_type::TYPE_STRING:
+        if (type->is_binary()) {
+          out << "binary (protocol, " << name << " ? ((GByteArray *) " << name << ")->data : NULL, "
+              << name << " ? ((GByteArray *) " << name << ")->len : 0";
+        } else {
+          out << "string (protocol, " << name;
+        }
+        break;
+      default:
+        throw "compiler error: no C writer for base type " + t_base_type::t_base_name(tbase) + name;
+      }
+    } else {
+      out << "i32 (protocol, (gint32) " << name;
+    }
+    out << ", error)) < 0)" << endl
+        << indent() << "  return " << error_ret << ";" << endl
+        << indent() << "xfer += ret;" << endl << endl;
+  } else {
+    throw std::logic_error("DO NOT KNOW HOW TO SERIALIZE FIELD '" + name + "' TYPE '"
+                           + type_name(type));
+  }
+}
+
+void t_c_glib_generator::generate_serialize_struct(ostream& out,
+                                                   t_struct* tstruct,
+                                                   string prefix,
+                                                   int error_ret) {
+  (void)tstruct;
+  out << indent() << "if ((ret = thrift_struct_write (THRIFT_STRUCT (" << prefix
+      << "), protocol, error)) < 0)" << endl << indent() << "  return " << error_ret << ";" << endl
+      << indent() << "xfer += ret;" << endl << endl;
+}
+
+void t_c_glib_generator::generate_serialize_container(ostream& out,
+                                                      t_type* ttype,
+                                                      string prefix,
+                                                      int error_ret) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    t_type* tkey = ((t_map*)ttype)->get_key_type();
+    t_type* tval = ((t_map*)ttype)->get_val_type();
+    string tkey_name = type_name(tkey);
+    string tval_name = type_name(tval);
+    string tkey_ptr;
+    string tval_ptr;
+    string keyname = tmp("key");
+    string valname = tmp("val");
+
+    declore_local_variable_for_write(out, tkey, keyname);
+    declore_local_variable_for_write(out, tval, valname);
+
+    /* If either the key or value type is a typedef, find its underlying type so
+       we can correctly determine how to generate a pointer to it */
+    tkey = get_true_type(tkey);
+    tval = get_true_type(tval);
+
+    tkey_ptr = tkey->is_string() || !tkey->is_base_type() ? "" : "*";
+    tval_ptr = tval->is_string() || !tval->is_base_type() ? "" : "*";
+
+    /*
+     * Some ugliness here.  To maximize backwards compatibility, we
+     * avoid using GHashTableIter and instead get a GList of all keys,
+     * then copy it into a array on the stack, and free it.
+     * This is because we may exit early before we get a chance to free the
+     * GList.
+     */
+    out << indent() << "GList *key_list = NULL, *iter = NULL;" << endl
+        << indent() << tkey_name << tkey_ptr << "* keys;" << endl
+        << indent() << "int i = 0, key_count;" << endl
+        << endl
+        << indent() << "if ((ret = thrift_protocol_write_map_begin (protocol, "
+        << type_to_enum(tkey) << ", " << type_to_enum(tval) << ", " << prefix << " ? "
+        << "(gint32) g_hash_table_size ((GHashTable *) " << prefix << ") : 0"
+        << ", error)) < 0)" << endl;
+    indent_up();
+    out << indent() << "return " << error_ret << ";" << endl;
+    indent_down();
+    out << indent() << "xfer += ret;" << endl
+        << indent() << "if (" << prefix << ")" << endl
+        << indent() << "  g_hash_table_foreach ((GHashTable *) " << prefix
+        << ", thrift_hash_table_get_keys, &key_list);" << endl
+        << indent() << "key_count = g_list_length (key_list);" << endl
+        << indent() << "keys = g_newa (" << tkey_name << tkey_ptr
+        << ", key_count);" << endl
+        << indent() << "for (iter = g_list_first (key_list); iter; "
+           "iter = iter->next)" << endl;
+    indent_up();
+    out << indent() << "keys[i++] = (" << tkey_name << tkey_ptr
+        << ") iter->data;" << endl;
+    indent_down();
+    out << indent() << "g_list_free (key_list);" << endl
+        << endl
+        << indent() << "for (i = 0; i < key_count; ++i)" << endl;
+    scope_up(out);
+    out << indent() << keyname << " = keys[i];" << endl
+        << indent() << valname << " = (" << tval_name << tval_ptr
+        << ") g_hash_table_lookup (((GHashTable *) " << prefix
+        << "), (gpointer) " << keyname << ");" << endl
+        << endl;
+    generate_serialize_map_element(out,
+                                   (t_map*)ttype,
+                                   tkey_ptr + " " + keyname,
+                                   tval_ptr + " " + valname,
+                                   error_ret);
+    scope_down(out);
+    out << indent() << "if ((ret = thrift_protocol_write_map_end (protocol, "
+           "error)) < 0)" << endl;
+    indent_up();
+    out << indent() << "return " << error_ret << ";" << endl;
+    indent_down();
+    out << indent() << "xfer += ret;" << endl;
+  } else if (ttype->is_set()) {
+    t_type* telem = ((t_set*)ttype)->get_elem_type();
+    string telem_name = type_name(telem);
+    string telem_ptr = telem->is_string() || !telem->is_base_type() ? "" : "*";
+    out << indent() << "GList *key_list = NULL, *iter = NULL;" << endl
+        << indent() << telem_name << telem_ptr << "* keys;" << endl
+        << indent() << "int i = 0, key_count;" << endl
+        << indent() << telem_name << telem_ptr << " elem;" << endl
+        << indent() << "gpointer value;" << endl
+        << indent() << "THRIFT_UNUSED_VAR (value);" << endl
+        << endl
+        << indent() << "if ((ret = thrift_protocol_write_set_begin (protocol, "
+        << type_to_enum(telem) << ", " << prefix << " ? "
+        << "(gint32) g_hash_table_size ((GHashTable *) " << prefix << ") : 0"
+        << ", error)) < 0)" << endl;
+    indent_up();
+    out << indent() << "return " << error_ret << ";" << endl;
+    indent_down();
+    out << indent() << "xfer += ret;" << endl
+        << indent() << "if (" << prefix << ")" << endl
+        << indent() << "  g_hash_table_foreach ((GHashTable *) " << prefix
+        << ", thrift_hash_table_get_keys, &key_list);" << endl
+        << indent() << "key_count = g_list_length (key_list);" << endl
+        << indent() << "keys = g_newa (" << telem_name << telem_ptr
+        << ", key_count);" << endl
+        << indent() << "for (iter = g_list_first (key_list); iter; "
+           "iter = iter->next)" << endl;
+    indent_up();
+    out << indent() << "keys[i++] = (" << telem_name << telem_ptr
+        << ") iter->data;" << endl;
+    indent_down();
+    out << indent() << "g_list_free (key_list);" << endl
+        << endl
+        << indent() << "for (i = 0; i < key_count; ++i)" << endl;
+    scope_up(out);
+    out << indent() << "elem = keys[i];" << endl
+        << indent() << "value = (gpointer) g_hash_table_lookup "
+           "(((GHashTable *) " << prefix << "), (gpointer) elem);" << endl
+        << endl;
+    generate_serialize_set_element(out,
+                                   (t_set*)ttype,
+                                   telem_ptr + "elem",
+                                   error_ret);
+    scope_down(out);
+    out << indent() << "if ((ret = thrift_protocol_write_set_end (protocol, "
+           "error)) < 0)" << endl;
+    indent_up();
+    out << indent() << "return " << error_ret << ";" << endl;
+    indent_down();
+    out << indent() << "xfer += ret;" << endl;
+  } else if (ttype->is_list()) {
+    string length = "(" + prefix + " ? " + prefix + "->len : 0)";
+    string i = tmp("i");
+    out << indent() << "guint " << i << ";" << endl
+        << endl
+        << indent() << "if ((ret = thrift_protocol_write_list_begin (protocol, "
+        << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", (gint32) "
+        << length << ", error)) < 0)" << endl;
+    indent_up();
+    out << indent() << "return " << error_ret << ";" << endl;
+    indent_down();
+    out << indent() << "xfer += ret;" << endl
+        << indent() << "for (" << i << " = 0; " << i << " < " << length << "; "
+        << i << "++)" << endl;
+    scope_up(out);
+    generate_serialize_list_element(out, (t_list*)ttype, prefix, i, error_ret);
+    scope_down(out);
+    out << indent() << "if ((ret = thrift_protocol_write_list_end (protocol, "
+           "error)) < 0)" << endl;
+    indent_up();
+    out << indent() << "return " << error_ret << ";" << endl;
+    indent_down();
+    out << indent() << "xfer += ret;" << endl;
+  }
+
+  scope_down(out);
+}
+
+void t_c_glib_generator::generate_serialize_map_element(ostream& out,
+                                                        t_map* tmap,
+                                                        string key,
+                                                        string value,
+                                                        int error_ret) {
+  t_field kfield(tmap->get_key_type(), key);
+  generate_serialize_field(out, &kfield, "", "", error_ret);
+
+  t_field vfield(tmap->get_val_type(), value);
+  generate_serialize_field(out, &vfield, "", "", error_ret);
+}
+
+void t_c_glib_generator::generate_serialize_set_element(ostream& out,
+                                                        t_set* tset,
+                                                        string element,
+                                                        int error_ret) {
+  t_field efield(tset->get_elem_type(), element);
+  generate_serialize_field(out, &efield, "", "", error_ret);
+}
+
+void t_c_glib_generator::generate_serialize_list_element(ostream& out,
+                                                         t_list* tlist,
+                                                         string list,
+                                                         string index,
+                                                         int error_ret) {
+  t_type* ttype = get_true_type(tlist->get_elem_type());
+
+  // cast to non-const
+  string cast = "";
+  string name = "g_ptr_array_index ((GPtrArray *) " + list + ", " + index + ")";
+
+  if (ttype->is_void()) {
+    throw std::runtime_error("compiler error: list element type cannot be void");
+  } else if (is_numeric(ttype)) {
+    name = "g_array_index (" + list + ", " + base_type_name(ttype) + ", " + index + ")";
+  } else if (ttype->is_string()) {
+    cast = "(gchar*)";
+  } else if (ttype->is_map() || ttype->is_set()) {
+    cast = "(GHashTable*)";
+  } else if (ttype->is_list()) {
+    t_type* etype = ((t_list*)ttype)->get_elem_type();
+    if (etype->is_void()) {
+      throw std::runtime_error("compiler error: list element type cannot be void");
+    }
+    cast = is_numeric(etype) ? "(GArray*)" : "(GPtrArray*)";
+  }
+
+  t_field efield(ttype, "(" + cast + name + ")");
+  generate_serialize_field(out, &efield, "", "", error_ret);
+}
+
+/* deserializes a field of any type. */
+void t_c_glib_generator::generate_deserialize_field(ostream& out,
+                                                    t_field* tfield,
+                                                    string prefix,
+                                                    string suffix,
+                                                    int error_ret,
+                                                    bool allocate) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw std::runtime_error("CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix
+                             + tfield->get_name());
+  }
+
+  string name = prefix + tfield->get_name() + suffix;
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name, error_ret, allocate);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name, error_ret);
+  } else if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    if (tbase == t_base_type::TYPE_STRING) {
+      indent(out) << "if (" << name << " != NULL)" << endl << indent() << "{" << endl;
+      indent_up();
+      indent(out) << "g_free(" << name << ");" << endl << indent() << name << " = NULL;" << endl;
+      indent_down();
+      indent(out) << "}" << endl << endl;
+    }
+    indent(out) << "if ((ret = thrift_protocol_read_";
+
+    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:
+      if (type->is_binary()) {
+        out << "binary (protocol, &data, &len";
+      } else {
+        out << "string (protocol, &" << name;
+      }
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << "bool (protocol, &" << name;
+      break;
+    case t_base_type::TYPE_I8:
+      out << "byte (protocol, &" << name;
+      break;
+    case t_base_type::TYPE_I16:
+      out << "i16 (protocol, &" << name;
+      break;
+    case t_base_type::TYPE_I32:
+      out << "i32 (protocol, &" << name;
+      break;
+    case t_base_type::TYPE_I64:
+      out << "i64 (protocol, &" << name;
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      out << "double (protocol, &" << name;
+      break;
+    default:
+      throw "compiler error: no C reader for base type " + t_base_type::t_base_name(tbase) + name;
+    }
+    out << ", error)) < 0)" << endl;
+    out << indent() << "  return " << error_ret << ";" << endl << indent() << "xfer += ret;"
+        << endl;
+
+    // load the byte array with the data
+    if (tbase == t_base_type::TYPE_STRING && type->is_binary()) {
+      indent(out) << name << " = g_byte_array_new();" << endl;
+      indent(out) << "g_byte_array_append (" << name << ", (guint8 *) data, (guint) len);" << endl;
+      indent(out) << "g_free (data);" << endl;
+    }
+  } else if (type->is_enum()) {
+    string t = tmp("ecast");
+    out << indent() << "gint32 " << t << ";" << endl << indent()
+        << "if ((ret = thrift_protocol_read_i32 (protocol, &" << t << ", error)) < 0)" << endl
+        << indent() << "  return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl
+        << indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl;
+  } else {
+    throw std::logic_error("DO NOT KNOW HOW TO SERIALIZE FIELD '" + tfield->get_name() + "' TYPE '"
+                           + type_name(type));
+  }
+
+  // if the type is not required and this is a thrift struct (no prefix),
+  // set the isset variable.  if the type is required, then set the
+  // local variable indicating the value was set, so that we can do    // validation later.
+  if (prefix != "" && tfield->get_req() != t_field::T_REQUIRED) {
+    indent(out) << prefix << "__isset_" << tfield->get_name() << suffix << " = TRUE;" << endl;
+  } else if (prefix != "" && tfield->get_req() == t_field::T_REQUIRED) {
+    indent(out) << "isset_" << tfield->get_name() << " = TRUE;" << endl;
+  }
+}
+
+void t_c_glib_generator::generate_deserialize_struct(ostream& out,
+                                                     t_struct* tstruct,
+                                                     string prefix,
+                                                     int error_ret,
+                                                     bool allocate) {
+  string name_uc = to_upper_case(initial_caps_to_underscores(tstruct->get_name()));
+  if (tstruct->is_xception()) {
+    out << indent() << "/* This struct is an exception */" << endl;
+    allocate = true;
+  }
+
+  if (allocate) {
+    out << indent() << "if ( " << prefix << " != NULL)" << endl << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "g_object_unref (" << prefix << ");" << endl;
+    indent_down();
+    out << indent() << "}" << endl << indent() << prefix << " = g_object_new (" << this->nspace_uc
+        << "TYPE_" << name_uc << ", NULL);" << endl;
+  }
+  out << indent() << "if ((ret = thrift_struct_read (THRIFT_STRUCT (" << prefix
+      << "), protocol, error)) < 0)" << endl << indent() << "{" << endl;
+  indent_up();
+  if (allocate) {
+    indent(out) << "g_object_unref (" << prefix << ");" << endl;
+    if (tstruct->is_xception()) {
+      indent(out) << prefix << " = NULL;" << endl;
+    }
+  }
+  out << indent() << "return " << error_ret << ";" << endl;
+  indent_down();
+  out << indent() << "}" << endl << indent() << "xfer += ret;" << endl;
+}
+
+void t_c_glib_generator::generate_deserialize_container(ostream& out,
+                                                        t_type* ttype,
+                                                        string prefix,
+                                                        int error_ret) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    out << indent() << "guint32 size;" << endl
+        << indent() << "guint32 i;" << endl
+        << indent() << "ThriftType key_type;" << endl
+        << indent() << "ThriftType value_type;" << endl
+        << endl
+        << indent() << "/* read the map begin marker */" << endl
+        << indent() << "if ((ret = thrift_protocol_read_map_begin (protocol, "
+           "&key_type, &value_type, &size, error)) < 0)" << endl;
+    indent_up();
+    out << indent() << "return " << error_ret << ";" << endl;
+    indent_down();
+    out << indent() << "xfer += ret;" << endl
+        << endl;
+
+    // iterate over map elements
+    out << indent() << "/* iterate through each of the map's fields */" << endl
+        << indent() << "for (i = 0; i < size; i++)" << endl;
+    scope_up(out);
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix, error_ret);
+    scope_down(out);
+    out << endl;
+
+    // read map end
+    out << indent() << "/* read the map end marker */" << endl
+        << indent() << "if ((ret = thrift_protocol_read_map_end (protocol, "
+           "error)) < 0)" << endl;
+    indent_up();
+    out << indent() << "return " << error_ret << ";" << endl;
+    indent_down();
+    out << indent() << "xfer += ret;" << endl;
+  } else if (ttype->is_set()) {
+    out << indent() << "guint32 size;" << endl
+        << indent() << "guint32 i;" << endl
+        << indent() << "ThriftType element_type;" << endl
+        << endl
+        << indent() << "if ((ret = thrift_protocol_read_set_begin (protocol, "
+           "&element_type, &size, error)) < 0)" << endl;
+    indent_up();
+    out << indent() << "return " << error_ret << ";" << endl;
+    indent_down();
+    out << indent() << "xfer += ret;" << endl
+        << endl;
+
+    // iterate over the elements
+    out << indent() << "/* iterate through the set elements */" << endl
+        << indent() << "for (i = 0; i < size; ++i)" << endl;
+    scope_up(out);
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix, error_ret);
+    scope_down(out);
+
+    // read set end
+    out << indent() << "if ((ret = thrift_protocol_read_set_end (protocol, "
+           "error)) < 0)" << endl;
+    indent_up();
+    out << indent() << "return " << error_ret << ";" << endl;
+    indent_down();
+    out << indent() << "xfer += ret;" << endl
+        << endl;
+  } else if (ttype->is_list()) {
+    out << indent() << "guint32 size;" << endl
+        << indent() << "guint32 i;" << endl
+        << indent() << "ThriftType element_type;" << endl
+        << endl
+        << indent() << "if ((ret = thrift_protocol_read_list_begin (protocol, "
+           "&element_type,&size, error)) < 0)" << endl;
+    indent_up();
+    out << indent() << "return " << error_ret << ";" << endl;
+    indent_down();
+    out << indent() << "xfer += ret;" << endl
+        << endl;
+
+    // iterate over the elements
+    out << indent() << "/* iterate through list elements */" << endl
+        << indent() << "for (i = 0; i < size; i++)" << endl;
+    scope_up(out);
+    generate_deserialize_list_element(out,
+                                      (t_list*)ttype,
+                                      prefix,
+                                      "i",
+                                      error_ret);
+    scope_down(out);
+
+    // read list end
+    out << indent() << "if ((ret = thrift_protocol_read_list_end (protocol, "
+           "error)) < 0)" << endl;
+    indent_up();
+    out << indent() << "return " << error_ret << ";" << endl;
+    indent_down();
+    out << indent() << "xfer += ret;" << endl;
+  }
+
+  scope_down(out);
+}
+
+void t_c_glib_generator::declare_local_variable(ostream& out, t_type* ttype, string& name, bool for_hash_table) {
+  string tname = type_name(ttype);
+
+  /* If the given type is a typedef, find its underlying type so we
+     can correctly determine how to generate a pointer to it */
+  ttype = get_true_type(ttype);
+  string ptr = !is_numeric(ttype) ? "" : "*";
+
+  if (ttype->is_map()) {
+    t_map* tmap = (t_map*)ttype;
+    out << indent() << tname << ptr << " " << name << " = "
+        << generate_new_hash_from_type(tmap->get_key_type(), tmap->get_val_type()) << endl;
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*)ttype;
+    out << indent() << tname << ptr << " " << name << " = "
+        << generate_new_array_from_type(tlist->get_elem_type()) << endl;
+  } else if (for_hash_table && ttype->is_enum()) {
+    out << indent() << tname << " " << name << ";" << endl;
+  } else {
+    out << indent() << tname << ptr << " " << name
+        << (ptr != "" ? " = g_new (" + tname + ", 1)" : " = NULL") << ";" << endl;
+  }
+}
+
+void t_c_glib_generator::declore_local_variable_for_write(ostream& out,
+                                                          t_type* ttype,
+                                                          string& name) {
+  string tname = type_name(ttype);
+  ttype = get_true_type(ttype);
+  string ptr = ttype->is_string() || !ttype->is_base_type() ? " " : "* ";
+  string init_val = ttype->is_enum() ? "" : " = NULL";
+  out << indent() << tname << ptr << name << init_val << ";" << endl;
+}
+
+void t_c_glib_generator::generate_deserialize_map_element(ostream& out,
+                                                          t_map* tmap,
+                                                          string prefix,
+                                                          int error_ret) {
+  t_type* tkey = tmap->get_key_type();
+  t_type* tval = tmap->get_val_type();
+  string keyname = tmp("key");
+  string valname = tmp("val");
+
+  declare_local_variable(out, tkey, keyname, true);
+  declare_local_variable(out, tval, valname, true);
+
+  /* If either the key or value type is a typedef, find its underlying
+     type so we can correctly determine how to generate a pointer to
+     it */
+  tkey = get_true_type(tkey);
+  tval = get_true_type(tval);
+
+  string tkey_ptr = tkey->is_string() || !tkey->is_base_type() ? "" : "*";
+  string tval_ptr = tval->is_string() || !tval->is_base_type() ? "" : "*";
+
+  // deserialize the fields of the map element
+  t_field fkey(tkey, tkey_ptr + keyname);
+  generate_deserialize_field(out, &fkey, "", "", error_ret);
+  t_field fval(tval, tval_ptr + valname);
+  generate_deserialize_field(out, &fval, "", "", error_ret);
+
+  indent(out) << "if (" << prefix << " && " << keyname << ")" << endl;
+  indent_up();
+  indent(out) << "g_hash_table_insert ((GHashTable *)" << prefix << ", (gpointer) " << keyname
+              << ", (gpointer) " << valname << ");" << endl;
+  indent_down();
+}
+
+void t_c_glib_generator::generate_deserialize_set_element(ostream& out,
+                                                          t_set* tset,
+                                                          string prefix,
+                                                          int error_ret) {
+  t_type* telem = tset->get_elem_type();
+  string elem = tmp("_elem");
+  string telem_ptr = telem->is_string() || !telem->is_base_type() ? "" : "*";
+
+  declare_local_variable(out, telem, elem, true);
+
+  t_field felem(telem, telem_ptr + elem);
+  generate_deserialize_field(out, &felem, "", "", error_ret);
+
+  indent(out) << "if (" << prefix << " && " << elem << ")" << endl;
+  indent_up();
+  indent(out) << "g_hash_table_insert ((GHashTable *) " << prefix << ", (gpointer) " << elem
+              << ", (gpointer) " << elem << ");" << endl;
+  indent_down();
+}
+
+void t_c_glib_generator::generate_deserialize_list_element(ostream& out,
+                                                           t_list* tlist,
+                                                           string prefix,
+                                                           string index,
+                                                           int error_ret) {
+  (void)index;
+  t_type* ttype = get_true_type(tlist->get_elem_type());
+  string elem = tmp("_elem");
+  string telem_ptr = !is_numeric(ttype) ? "" : "*";
+
+  declare_local_variable(out, ttype, elem, false);
+
+  t_field felem(ttype, telem_ptr + elem);
+  generate_deserialize_field(out, &felem, "", "", error_ret);
+
+  if (ttype->is_void()) {
+    throw std::runtime_error("compiler error: list element type cannot be void");
+  } else if (is_numeric(ttype)) {
+    indent(out) << "g_array_append_vals (" << prefix << ", " << elem << ", 1);" << endl;
+  } else {
+    indent(out) << "g_ptr_array_add (" << prefix << ", " << elem << ");" << endl;
+  }
+}
+
+string t_c_glib_generator::generate_free_func_from_type(t_type* ttype) {
+  if (ttype == NULL)
+    return "NULL";
+
+  if (ttype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "compiler error: cannot determine hash type";
+      break;
+    case t_base_type::TYPE_BOOL:
+    case t_base_type::TYPE_I8:
+    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 "g_free";
+    case t_base_type::TYPE_STRING:
+      if (((t_base_type*)ttype)->is_binary()) {
+        return "thrift_string_free";
+      }
+      return "g_free";
+    default:
+      throw "compiler error: no hash table info for type";
+    }
+  } else if (ttype->is_enum()) {
+    return "NULL";
+  } else if (ttype->is_map() || ttype->is_set()) {
+    return "(GDestroyNotify) thrift_safe_hash_table_destroy";
+  } else if (ttype->is_struct()) {
+    return "g_object_unref";
+  } else if (ttype->is_list()) {
+    t_type* etype = ((t_list*)ttype)->get_elem_type();
+    if (etype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)etype)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "compiler error: cannot determine array type";
+        break;
+      case t_base_type::TYPE_BOOL:
+      case t_base_type::TYPE_I8:
+      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 "(GDestroyNotify) g_array_unref";
+      case t_base_type::TYPE_STRING:
+        return "(GDestroyNotify) g_ptr_array_unref";
+      default:
+        throw "compiler error: no array info for type";
+      }
+    } else if (etype->is_container() || etype->is_struct()) {
+      return "(GDestroyNotify) g_ptr_array_unref";
+      ;
+    } else if (etype->is_enum()) {
+      return "(GDestroyNotify) g_array_unref";
+    }
+    printf("Type not expected inside the array: %s\n", etype->get_name().c_str());
+    throw "Type not expected inside array";
+  } else if (ttype->is_typedef()) {
+    return generate_free_func_from_type(((t_typedef*)ttype)->get_type());
+  }
+  printf("Type not expected: %s\n", ttype->get_name().c_str());
+  throw "Type not expected";
+}
+
+string t_c_glib_generator::generate_hash_func_from_type(t_type* ttype) {
+  if (ttype == NULL)
+    return "NULL";
+
+  if (ttype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "compiler error: cannot determine hash type";
+      break;
+    case t_base_type::TYPE_BOOL:
+      return "thrift_boolean_hash";
+    case t_base_type::TYPE_I8:
+      return "thrift_int8_hash";
+    case t_base_type::TYPE_I16:
+      return "thrift_int16_hash";
+    case t_base_type::TYPE_I32:
+      return "g_int_hash";
+    case t_base_type::TYPE_I64:
+      return "g_int64_hash";
+    case t_base_type::TYPE_DOUBLE:
+      return "g_double_hash";
+    case t_base_type::TYPE_STRING:
+      return "g_str_hash";
+    default:
+      throw "compiler error: no hash table info for type";
+    }
+  } else if (ttype->is_enum()) {
+    return "g_direct_hash";
+  } else if (ttype->is_container() || ttype->is_struct()) {
+    return "g_direct_hash";
+  } else if (ttype->is_typedef()) {
+    return generate_hash_func_from_type(((t_typedef*)ttype)->get_type());
+  }
+  printf("Type not expected: %s\n", ttype->get_name().c_str());
+  throw "Type not expected";
+}
+
+string t_c_glib_generator::generate_cmp_func_from_type(t_type* ttype) {
+  if (ttype == NULL)
+    return "NULL";
+
+  if (ttype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "compiler error: cannot determine hash type";
+      break;
+    case t_base_type::TYPE_BOOL:
+      return "thrift_boolean_equal";
+    case t_base_type::TYPE_I8:
+      return "thrift_int8_equal";
+    case t_base_type::TYPE_I16:
+      return "thrift_int16_equal";
+    case t_base_type::TYPE_I32:
+      return "g_int_equal";
+    case t_base_type::TYPE_I64:
+      return "g_int64_equal";
+    case t_base_type::TYPE_DOUBLE:
+      return "g_double_equal";
+    case t_base_type::TYPE_STRING:
+      return "g_str_equal";
+    default:
+      throw "compiler error: no hash table info for type";
+    }
+  } else if (ttype->is_enum()) {
+    return "g_direct_equal";
+  } else if (ttype->is_container() || ttype->is_struct()) {
+    return "g_direct_equal";
+  } else if (ttype->is_typedef()) {
+    return generate_cmp_func_from_type(((t_typedef*)ttype)->get_type());
+  }
+  printf("Type not expected: %s\n", ttype->get_name().c_str());
+  throw "Type not expected";
+}
+
+string t_c_glib_generator::generate_new_hash_from_type(t_type* key, t_type* value) {
+  string hash_func = generate_hash_func_from_type(key);
+  string cmp_func = generate_cmp_func_from_type(key);
+  string key_free_func = generate_free_func_from_type(key);
+  string value_free_func = generate_free_func_from_type(value);
+
+  return "g_hash_table_new_full (" + hash_func + ", " + cmp_func + ", " + key_free_func + ", "
+         + value_free_func + ");";
+}
+
+string t_c_glib_generator::generate_new_array_from_type(t_type* ttype) {
+  if (ttype->is_void()) {
+    throw std::runtime_error("compiler error: cannot determine array type");
+  } else if (is_numeric(ttype)) {
+    return "g_array_new (0, 1, sizeof (" + base_type_name(ttype) + "));";
+  } else {
+    string free_func = generate_free_func_from_type(ttype);
+    return "g_ptr_array_new_with_free_func (" + free_func + ");";
+  }
+}
+
+/***************************************
+ * UTILITY FUNCTIONS                   *
+ ***************************************/
+
+/**
+ * Upper case a string.  Wraps boost's string utility.
+ */
+string to_upper_case(string name) {
+  string s(name);
+  std::transform(s.begin(), s.end(), s.begin(), ::toupper);
+  return s;
+  //  return boost::to_upper_copy (name);
+}
+
+/**
+ * Lower case a string.  Wraps boost's string utility.
+ */
+string to_lower_case(string name) {
+  string s(name);
+  std::transform(s.begin(), s.end(), s.begin(), ::tolower);
+  return s;
+  //  return boost::to_lower_copy (name);
+}
+
+/**
+ * Makes a string friendly to C code standards by lowercasing and adding
+ * underscores, with the exception of the first character.  For example:
+ *
+ * Input: "ZomgCamelCase"
+ * Output: "zomg_camel_case"
+ */
+string initial_caps_to_underscores(string name) {
+  string ret;
+  const char* tmp = name.c_str();
+  int pos = 0;
+
+  /* the first character isn't underscored if uppercase, just lowercased */
+  ret += tolower(tmp[pos]);
+  pos++;
+  for (unsigned int i = pos; i < name.length(); i++) {
+    char lc = tolower(tmp[i]);
+    if (lc != tmp[i]) {
+      ret += '_';
+    }
+    ret += lc;
+  }
+
+  return ret;
+}
+
+/**
+ * Performs the reverse operation of initial_caps_to_underscores: The first
+ * character of the string is made uppercase, along with each character that
+ * follows an underscore (which is removed). Useful for converting Thrift
+ * service-method names into GObject-style class names.
+ *
+ * Input: "zomg_camel_case"
+ * Output: "ZomgCamelCase"
+ */
+string underscores_to_initial_caps(string name) {
+  string ret;
+  const char* tmp = name.c_str();
+  bool uppercase_next = true;
+
+  for (unsigned int i = 0; i < name.length(); i++) {
+    char c = tmp[i];
+    if (c == '_') {
+      uppercase_next = true;
+    } else {
+      if (uppercase_next) {
+        ret += toupper(c);
+        uppercase_next = false;
+      } else {
+        ret += c;
+      }
+    }
+  }
+
+  return ret;
+}
+
+/* register this generator with the main program */
+THRIFT_REGISTER_GENERATOR(c_glib, "C, using GLib", "")
diff --git a/compiler/cpp/src/thrift/generate/t_cl_generator.cc b/compiler/cpp/src/thrift/generate/t_cl_generator.cc
new file mode 100644
index 0000000..628d0d8
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_cl_generator.cc
@@ -0,0 +1,558 @@
+/*
+ * Copyright (c) 2008- Patrick Collison <patrick@collison.ie>
+ * Copyright (c) 2006- Facebook
+ *
+ * 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.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <boost/tokenizer.hpp>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+#include <string>
+#include <algorithm>
+
+#include "thrift/platform.h"
+#include "t_oop_generator.h"
+using namespace std;
+
+
+/**
+ * Common Lisp code generator.
+ *
+ * @author Patrick Collison <patrick@collison.ie>
+ */
+class t_cl_generator : public t_oop_generator {
+ public:
+  t_cl_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_oop_generator(program)
+  {
+    no_asd = false;
+    system_prefix = "thrift-gen-";
+
+    std::map<std::string, std::string>::const_iterator iter;
+
+    for(iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if(iter->first.compare("no_asd") == 0) {
+        no_asd = true;
+      } else if (iter->first.compare("sys_pref") == 0) {
+	system_prefix = iter->second;
+      } else {
+        throw "unknown option cl:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-cl";
+    copy_options_ = option_string;
+  }
+
+  void init_generator();
+  void close_generator();
+
+  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);
+  void generate_cl_struct (std::ostream& out, t_struct* tstruct, bool is_exception);
+  void generate_cl_struct_internal (std::ostream& out, t_struct* tstruct, bool is_exception);
+  void generate_exception_sig(std::ostream& out, t_function* f);
+  std::string render_const_value(t_type* type, t_const_value* value);
+
+  std::string cl_autogen_comment();
+  void asdf_def(std::ostream &out);
+  void package_def(std::ostream &out);
+  void package_in(std::ostream &out);
+  std::string generated_package();
+  std::string prefix(std::string name);
+  std::string package_of(t_program* program);
+  std::string package();
+  std::string render_includes();
+
+  std::string type_name(t_type* ttype);
+  std::string typespec (t_type *t);
+  std::string function_signature(t_function* tfunction);
+  std::string argument_list(t_struct* tstruct);
+
+  std::string cl_docstring(std::string raw);
+
+ private:
+
+  int temporary_var;
+  /**
+   * Isolate the variable definitions, as they can require structure definitions
+   */
+  ofstream_with_content_based_conditional_update f_asd_;
+  ofstream_with_content_based_conditional_update f_types_;
+  ofstream_with_content_based_conditional_update f_vars_;
+
+  std::string copy_options_;
+
+  bool no_asd;
+  std::string system_prefix;
+};
+
+
+void t_cl_generator::init_generator() {
+  MKDIR(get_out_dir().c_str());
+  string program_dir = get_out_dir() + "/" + program_name_;
+  MKDIR(program_dir.c_str());
+
+  temporary_var = 0;
+
+  string f_types_name = program_dir + "/" + program_name_ + "-types.lisp";
+  string f_vars_name = program_dir + "/" + program_name_ + "-vars.lisp";
+
+  f_types_.open(f_types_name.c_str());
+  f_types_ << cl_autogen_comment() << endl;
+  f_vars_.open(f_vars_name.c_str());
+  f_vars_ << cl_autogen_comment() << endl;
+
+  package_def(f_types_);
+  package_in(f_types_);
+  package_in(f_vars_);
+
+  if (!no_asd) {
+    string f_asd_name = program_dir + "/" + system_prefix + program_name_ + ".asd";
+    f_asd_.open(f_asd_name.c_str());
+    f_asd_ << cl_autogen_comment() << endl;
+    asdf_def(f_asd_);
+  }
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program
+ */
+string t_cl_generator::render_includes() {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = "";
+  result += ":depends-on (:thrift";
+  for (size_t i = 0; i < includes.size(); ++i) {
+    result += " :" + system_prefix + underscore(includes[i]->get_name());
+  }
+  result += ")\n";
+  return result;
+}
+
+string t_cl_generator::package_of(t_program* program) {
+  string prefix = program->get_namespace("cl");
+  return prefix.empty() ? "thrift-generated" : prefix;
+}
+
+string t_cl_generator::package() {
+  return package_of(program_);
+}
+
+string t_cl_generator::prefix(string symbol) {
+  return "\"" + symbol + "\"";
+}
+
+string t_cl_generator::cl_autogen_comment() {
+  return
+    std::string(";;; ") + "Autogenerated by Thrift\n" +
+    ";;; DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
+    ";;; options string: " + copy_options_ + "\n";
+}
+
+string t_cl_generator::cl_docstring(string raw) {
+  replace(raw.begin(), raw.end(), '"', '\'');
+  return raw;
+}
+
+
+void t_cl_generator::close_generator() {
+  f_asd_.close();
+  f_types_.close();
+  f_vars_.close();
+}
+
+string t_cl_generator::generated_package() {
+  return program_->get_namespace("cpp");
+}
+
+void t_cl_generator::asdf_def(std::ostream &out) {
+  out << "(asdf:defsystem #:" << system_prefix << program_name_ << endl;
+  indent_up();
+  out << indent() << render_includes()
+      << indent() << ":serial t" << endl
+      << indent() << ":components ("
+      << "(:file \"" << program_name_ << "-types\") "
+      << "(:file \"" << program_name_ << "-vars\")))" << endl;
+  indent_down();
+}
+
+/***
+ * Generate a package definition. Add use references equivalent to the idl file's include statements.
+ */
+void t_cl_generator::package_def(std::ostream &out) {
+  const vector<t_program*>& includes = program_->get_includes();
+
+  out << "(thrift:def-package :" << package();
+  if ( includes.size() > 0 ) {
+    out << " :use (";
+    for (size_t i = 0; i < includes.size(); ++i) {
+      out << " :" << includes[i]->get_name();
+    }
+    out << ")";
+  }
+  out << ")" << endl << endl;
+}
+
+void t_cl_generator::package_in(std::ostream &out) {
+  out << "(cl:in-package :" << package() << ")" << endl << endl;
+}
+
+/**
+ * Generates a typedef. This is not done in Common Lisp, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_cl_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+void t_cl_generator::generate_enum(t_enum* tenum) {
+  f_types_ << "(thrift:def-enum " << prefix(tenum->get_name()) << endl;
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  int value = -1;
+
+  indent_up();
+  f_types_ << indent() << "(";
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    value = (*c_iter)->get_value();
+
+    if(c_iter != constants.begin()) f_types_ << endl << indent() << " ";
+
+    f_types_ << "(\"" << (*c_iter)->get_name() << "\" . " << value << ")";
+  }
+  indent_down();
+  f_types_ << "))" << endl << endl;
+}
+
+/**
+ * Generate a constant value
+ */
+void t_cl_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  f_vars_ << "(thrift:def-constant " << prefix(name) << " " << render_const_value(type, value) << ")"
+          << endl << 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_cl_generator::render_const_value(t_type* type, t_const_value* value) {
+  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 << "\"" << value->get_string() << "\"";
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "t" : "nil");
+      break;
+    case t_base_type::TYPE_I8:
+    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 << (type->is_struct() ? "(make-instance '" : "(make-exception '") <<
+           lowercase(type->get_name()) << " " << 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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::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();
+      }
+
+      out << indent() << ":" << v_iter->first->get_string() << " " <<
+        render_const_value(field_type, v_iter->second) << endl;
+    }
+    out << indent() << ")";
+
+    indent_down();
+  } else if (type->is_map()) {
+    // emit an hash form with both keys and values to be evaluated
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    out << "(thrift:map ";
+    indent_up();
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << endl << indent()
+          << "(cl:cons " << render_const_value(ktype, v_iter->first) << " "
+          << render_const_value(vtype, v_iter->second) << ")";
+    }
+    indent_down();
+    out << indent() << ")";
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    if (type->is_set()) {
+      out << "(thrift:set" << endl;
+    } else {
+      out << "(thrift:list" << endl;
+    }
+    indent_up();
+    indent_up();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent() << render_const_value(etype, *v_iter) << endl;
+    }
+    out << indent() << ")";
+    indent_down();
+    indent_down();
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+  return out.str();
+}
+
+void t_cl_generator::generate_struct(t_struct* tstruct) {
+  generate_cl_struct(f_types_, tstruct, false);
+}
+
+void t_cl_generator::generate_xception(t_struct* txception) {
+  generate_cl_struct(f_types_, txception, true);
+}
+
+void t_cl_generator::generate_cl_struct_internal(std::ostream& out, t_struct* tstruct, bool is_exception) {
+  (void)is_exception;
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  out << "(";
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_const_value* value = (*m_iter)->get_value();
+    t_type* type = (*m_iter)->get_type();
+
+    if (m_iter != members.begin()) {
+      out << endl << indent() << " ";
+    }
+    out << "(" << prefix((*m_iter)->get_name()) << " " <<
+        ( (NULL != value) ? render_const_value(type, value) : "nil" ) <<
+        " :id " << (*m_iter)->get_key();
+    if ( type->is_base_type() && "string" == typespec(type) )
+      if ( ((t_base_type*)type)->is_binary() )
+        out << " :type binary";
+      else
+        out << " :type string";
+    else
+      out << " :type " << typespec(type);
+    if ( (*m_iter)->get_req() == t_field::T_OPTIONAL ) {
+      out << " :optional t";
+    }
+    if ( (*m_iter)->has_doc()) {
+      out << " :documentation \"" << cl_docstring((*m_iter)->get_doc()) << "\"";
+    }
+    out <<")";
+  }
+
+  out << ")";
+}
+
+void t_cl_generator::generate_cl_struct(std::ostream& out, t_struct* tstruct, bool is_exception = false) {
+  std::string name = type_name(tstruct);
+  out << (is_exception ? "(thrift:def-exception " : "(thrift:def-struct ") <<
+      prefix(name) << endl;
+  indent_up();
+  if ( tstruct->has_doc() ) {
+    out << indent() ;
+    out << "\"" << cl_docstring(tstruct->get_doc()) << "\"" << endl;
+  }
+  out << indent() ;
+  generate_cl_struct_internal(out, tstruct, is_exception);
+  indent_down();
+  out << ")" << endl << endl;
+}
+
+void t_cl_generator::generate_exception_sig(std::ostream& out, t_function* f) {
+  generate_cl_struct_internal(out, f->get_xceptions(), true);
+}
+
+void t_cl_generator::generate_service(t_service* tservice) {
+  string extends_client;
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  if (tservice->get_extends() != NULL) {
+    extends_client = type_name(tservice->get_extends());
+  }
+
+  extends_client = extends_client.empty() ? "nil" : prefix(extends_client);
+
+  f_types_ << "(thrift:def-service " << prefix(service_name_) << " "
+           << extends_client;
+
+  indent_up();
+
+  if ( tservice->has_doc()) {
+      f_types_ << endl << indent()
+               << "(:documentation \"" << cl_docstring(tservice->get_doc()) << "\")";
+    }
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_function* function = *f_iter;
+    string fname = function->get_name();
+    string signature = function_signature(function);
+    t_struct* exceptions = function->get_xceptions();
+    const vector<t_field*>& xmembers = exceptions->get_members();
+
+    f_types_ << endl << indent() << "(:method " << prefix(fname);
+    f_types_ << " (" << signature << " "  << typespec((*f_iter)->get_returntype()) << ")";
+    if (xmembers.size() > 0) {
+      f_types_ << endl << indent() << " :exceptions " ;
+      generate_exception_sig(f_types_, function);
+    }
+    if ( (*f_iter)->is_oneway() ) {
+      f_types_ << endl << indent() << " :oneway t";
+    }
+    if ( (*f_iter)->has_doc() ) {
+      f_types_ << endl << indent() << " :documentation \""
+               << cl_docstring((*f_iter)->get_doc()) << "\"";
+  }
+    f_types_ << ")";
+  }
+
+  f_types_ << ")" << endl << endl;
+
+  indent_down();
+}
+
+string t_cl_generator::typespec(t_type *t) {
+  t = get_true_type(t);
+
+  if (t -> is_binary()){
+    return "binary";
+  } else if (t->is_base_type()) {
+    return type_name(t);
+  } else if (t->is_map()) {
+    t_map *m = (t_map*) t;
+    return "(thrift:map " + typespec(m->get_key_type()) + " " +
+      typespec(m->get_val_type()) + ")";
+  } else if (t->is_struct() || t->is_xception()) {
+    return "(struct " + prefix(type_name(t)) + ")";
+  } else if (t->is_list()) {
+    return "(thrift:list " + typespec(((t_list*) t)->get_elem_type()) + ")";
+  } else if (t->is_set()) {
+    return "(thrift:set " + typespec(((t_set*) t)->get_elem_type()) + ")";
+  } else if (t->is_enum()) {
+    return "(enum \"" + ((t_enum*) t)->get_name() + "\")";
+  } else {
+    throw "Sorry, I don't know how to generate this: " + type_name(t);
+  }
+}
+
+string t_cl_generator::function_signature(t_function* tfunction) {
+  return argument_list(tfunction->get_arglist());
+}
+
+string t_cl_generator::argument_list(t_struct* tstruct) {
+  stringstream res;
+  res << "(";
+
+  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 {
+      res << " ";
+    }
+    res << "(" + prefix((*f_iter)->get_name()) << " " <<
+      typespec((*f_iter)->get_type()) << " " <<
+      (*f_iter)->get_key() <<  ")";
+
+
+  }
+  res << ")";
+  return res.str();
+}
+
+string t_cl_generator::type_name(t_type* ttype) {
+  string prefix = "";
+  t_program* program = ttype->get_program();
+
+  if (program != NULL && program != program_)
+    prefix = package_of(program) == package() ? "" : package_of(program) + ":";
+
+  string name = ttype->get_name();
+
+  if (ttype->is_struct() || ttype->is_xception())
+    name = lowercase(ttype->get_name());
+
+  return prefix + name;
+}
+
+THRIFT_REGISTER_GENERATOR(
+    cl,
+    "Common Lisp",
+    "    no_asd:          Do not define ASDF systems for each generated Thrift program.\n"
+    "    sys_pref=        The prefix to give ASDF system names. Default: thrift-gen-\n")
diff --git a/compiler/cpp/src/thrift/generate/t_cocoa_generator.cc b/compiler/cpp/src/thrift/generate/t_cocoa_generator.cc
new file mode 100644
index 0000000..ac644f5
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_cocoa_generator.cc
@@ -0,0 +1,3309 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ofstream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * Objective-C code generator.
+ *
+ * mostly copy/pasting/tweaking from mcslee's work.
+ */
+class t_cocoa_generator : public t_oop_generator {
+public:
+  t_cocoa_generator(t_program* program,
+                    const std::map<std::string, std::string>& parsed_options,
+                    const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    log_unexpected_ = false;
+    validate_required_ = false;
+    async_clients_ = false;
+    promise_kit_ = false;
+    debug_descriptions_ = false;
+    pods_ = false;
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("log_unexpected") == 0) {
+        log_unexpected_ = true;
+      } else if( iter->first.compare("validate_required") == 0) {
+        validate_required_ = true;
+      } else if( iter->first.compare("async_clients") == 0) {
+        async_clients_ = true;
+      } else if( iter->first.compare("promise_kit") == 0) {
+        promise_kit_ = true;
+      } else if( iter->first.compare("debug_descriptions") == 0) {
+        debug_descriptions_ = true;
+      } else if( iter->first.compare("pods") == 0) {
+        pods_ = true;
+      } else {
+        throw "unknown option cocoa:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-cocoa";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  void generate_consts(std::vector<t_const*> consts);
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_struct(t_struct* tstruct);
+  void generate_xception(t_struct* txception);
+  void generate_service(t_service* tservice);
+
+  void print_const_value(ostream& out,
+                         string name,
+                         t_type* type,
+                         t_const_value* value,
+                         bool defval = false);
+  std::string render_const_value(ostream& out,
+                                 t_type* type,
+                                 t_const_value* value,
+                                 bool box_it = false);
+
+  void generate_cocoa_struct(t_struct* tstruct, bool is_exception);
+  void generate_cocoa_struct_interface(std::ostream& out,
+                                       t_struct* tstruct,
+                                       bool is_xception = false);
+  void generate_cocoa_struct_implementation(std::ostream& out,
+                                            t_struct* tstruct,
+                                            bool is_xception = false,
+                                            bool is_result = false);
+  void generate_cocoa_struct_initializer_signature(std::ostream& out, t_struct* tstruct);
+  void generate_cocoa_struct_init_with_coder_method(ostream& out,
+                                                    t_struct* tstruct,
+                                                    bool is_exception);
+  void generate_cocoa_struct_encode_with_coder_method(ostream& out,
+                                                      t_struct* tstruct,
+                                                      bool is_exception);
+  void generate_cocoa_struct_copy_method(ostream& out,
+                                         t_struct* tstruct,
+                                         bool is_exception);
+  void generate_cocoa_struct_hash_method(ostream& out, t_struct* tstruct);
+  void generate_cocoa_struct_is_equal_method(ostream& out,
+                                             t_struct* tstruct,
+                                             bool is_exception);
+  void generate_cocoa_struct_field_accessor_implementations(std::ostream& out,
+                                                            t_struct* tstruct,
+                                                            bool is_exception);
+  void generate_cocoa_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_cocoa_struct_result_writer(std::ostream& out, t_struct* tstruct);
+  void generate_cocoa_struct_writer(std::ostream& out, t_struct* tstruct);
+  void generate_cocoa_struct_validator(std::ostream& out, t_struct* tstruct);
+  void generate_cocoa_struct_description(std::ostream& out, t_struct* tstruct);
+
+  std::string function_result_helper_struct_type(t_service *tservice, t_function* tfunction);
+  std::string function_args_helper_struct_type(t_service* tservice, t_function* tfunction);
+  void generate_function_helpers(t_service *tservice, t_function* tfunction);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_cocoa_service_protocol(std::ostream& out, t_service* tservice);
+  void generate_cocoa_service_async_protocol(std::ostream& out, t_service* tservice);
+
+  void generate_cocoa_service_client_interface(std::ostream& out, t_service* tservice);
+  void generate_cocoa_service_client_async_interface(std::ostream& out, t_service* tservice);
+
+  void generate_cocoa_service_client_send_function_implementation(ostream& out,
+                                                                  t_service* tservice,
+                                                                  t_function* tfunction,
+                                                                  bool needs_protocol);
+  void generate_cocoa_service_client_send_function_invocation(ostream& out, t_function* tfunction);
+  void generate_cocoa_service_client_send_async_function_invocation(ostream& out,
+                                                                    t_function* tfunction,
+                                                                    string failureBlockName);
+  void generate_cocoa_service_client_recv_function_implementation(ostream& out,
+                                                                  t_service* tservice,
+                                                                  t_function* tfunction,
+                                                                  bool needs_protocol);
+  void generate_cocoa_service_client_implementation(std::ostream& out, t_service* tservice);
+  void generate_cocoa_service_client_async_implementation(std::ostream& out, t_service* tservice);
+
+  void generate_cocoa_service_server_interface(std::ostream& out, t_service* tservice);
+  void generate_cocoa_service_server_implementation(std::ostream& out, t_service* tservice);
+  void generate_cocoa_service_helpers(t_service* tservice);
+  void generate_service_client(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::ostream& out, t_field* tfield, std::string fieldName);
+
+  void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+
+  void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         std::string prefix = "");
+
+  void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
+
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string fieldName = "");
+
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string iter,
+                                      std::string map);
+
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ostream& out,
+                                       t_list* tlist,
+                                       std::string index,
+                                       std::string listName);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string cocoa_prefix();
+  std::string cocoa_imports();
+  std::string cocoa_thrift_imports();
+  std::string type_name(t_type* ttype, bool class_ref = false, bool needs_mutable = false);
+  std::string element_type_name(t_type* ttype);
+  std::string base_type_name(t_base_type* tbase);
+  std::string declare_property(t_field* tfield);
+  std::string declare_property_isset(t_field* tfield);
+  std::string declare_property_unset(t_field* tfield);
+  std::string invalid_return_statement(t_function* tfunction);
+  std::string function_signature(t_function* tfunction, bool include_error);
+  std::string async_function_signature(t_function* tfunction, bool include_error);
+  std::string promise_function_signature(t_function* tfunction);
+  std::string argument_list(t_struct* tstruct, string protocol_name, bool include_error);
+  std::string type_to_enum(t_type* ttype);
+  std::string format_string_for_type(t_type* type);
+  std::string format_cast_for_type(t_type* type);
+  std::string call_field_setter(t_field* tfield, std::string fieldName);
+  std::string box(t_type *ttype, std::string field_name);
+  std::string unbox(t_type* ttype, std::string field_name);
+  std::string getter_name(string field_name);
+  std::string setter_name(string field_name);
+
+  bool type_can_be_copy(t_type* ttype) {
+    ttype = get_true_type(ttype);
+    
+    return ttype->is_string();
+  }
+  
+  bool type_can_be_null(t_type* ttype) {
+    ttype = get_true_type(ttype);
+
+    return ttype->is_container() || ttype->is_struct() || ttype->is_xception()
+           || ttype->is_string();
+  }
+
+private:
+  std::string cocoa_prefix_;
+  std::string constants_declarations_;
+  int error_constant_;
+
+  /**
+   * File streams
+   */
+
+  ofstream_with_content_based_conditional_update f_header_;
+  ofstream_with_content_based_conditional_update f_impl_;
+
+  bool log_unexpected_;
+  bool validate_required_;
+  bool async_clients_;
+  bool promise_kit_;
+  bool debug_descriptions_;
+  bool pods_;
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ */
+void t_cocoa_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+  cocoa_prefix_ = program_->get_namespace("cocoa");
+
+  // we have a .h header file...
+  string f_header_name = cocoa_prefix_ + capitalize(program_name_) + ".h";
+  string f_header_fullname = get_out_dir() + f_header_name;
+  f_header_.open(f_header_fullname.c_str());
+
+  f_header_ << autogen_comment() << endl;
+
+  f_header_ << cocoa_imports() << cocoa_thrift_imports();
+
+  // ...and a .m implementation file
+  string f_impl_name = cocoa_prefix_ + capitalize(program_name_) + ".m";
+  string f_impl_fullname = get_out_dir() + f_impl_name;
+  f_impl_.open(f_impl_fullname.c_str());
+
+  f_impl_ << autogen_comment() << endl;
+
+  f_impl_ << cocoa_imports() << cocoa_thrift_imports() << "#import \"" << f_header_name << "\""
+          << endl << endl;
+
+  error_constant_ = 60000;
+}
+
+/**
+ * Prints standard Cocoa imports
+ *
+ * @return List of imports for Cocoa libraries
+ */
+string t_cocoa_generator::cocoa_imports() {
+  return string() + "#import <Foundation/Foundation.h>\n" + "\n";
+}
+
+/**
+ * Prints thrift runtime imports
+ *
+ * @return List of imports necessary for thrift runtime
+ */
+string t_cocoa_generator::cocoa_thrift_imports() {
+
+  vector<string> includes_list;
+  includes_list.push_back("TProtocol.h");
+  includes_list.push_back("TProtocolFactory.h");
+  includes_list.push_back("TApplicationError.h");
+  includes_list.push_back("TProtocolError.h");
+  includes_list.push_back("TProtocolUtil.h");
+  includes_list.push_back("TProcessor.h");
+  includes_list.push_back("TBase.h");
+  includes_list.push_back("TAsyncTransport.h");
+  includes_list.push_back("TBaseClient.h");
+
+  std::ostringstream includes;
+
+  vector<string>::const_iterator i_iter;
+  for (i_iter=includes_list.begin(); i_iter!=includes_list.end(); ++i_iter) {
+    includes << "#import ";
+    if (pods_) {
+      includes << "<Thrift/" << *i_iter << ">";
+    } else {
+      includes << "\"" << *i_iter << "\"";
+    }
+    includes << endl;
+  }
+
+  includes << endl;
+
+  if (promise_kit_) {
+    includes << "#import ";
+    if (pods_) {
+      includes << "<PromiseKit/PromiseKit.h>";
+    } else {
+      includes << "\"PromiseKit.h\"";
+    }
+    includes << endl;
+  }
+
+  // Include other Thrift includes
+  const vector<t_program*>& other_includes = program_->get_includes();
+  for (size_t i = 0; i < other_includes.size(); ++i) {
+    includes << "#import \""
+             << other_includes[i]->get_namespace("cocoa")
+             << capitalize(other_includes[i]->get_name())
+             << ".h\"" << endl;
+  }
+
+  includes << endl;
+
+  return includes.str();
+}
+
+/**
+ * Finish up generation.
+ */
+void t_cocoa_generator::close_generator() {
+  // stick our constants declarations at the end of the header file
+  // since they refer to things we are defining.
+  f_header_ << constants_declarations_ << endl;
+}
+
+/**
+ * Generates a typedef. This is just a simple 1-liner in objective-c
+ *
+ * @param ttypedef The type definition
+ */
+void t_cocoa_generator::generate_typedef(t_typedef* ttypedef) {
+  if (ttypedef->get_type()->is_map()) {
+    t_map *map = (t_map *)ttypedef->get_type();
+    if (map->get_key_type()->is_struct()) {
+      f_header_ << indent() << "@class " << type_name(map->get_key_type(), true) << ";" << endl;
+    }
+    if (map->get_val_type()->is_struct()) {
+      f_header_ << indent() << "@class " << type_name(map->get_val_type(), true) << ";" << endl;
+    }
+  }
+  else if (ttypedef->get_type()->is_set()) {
+    t_set *set = (t_set *)ttypedef->get_type();
+    if (set->get_elem_type()->is_struct()) {
+      f_header_ << indent() << "@class " << type_name(set->get_elem_type(), true) << ";" << endl;
+    }
+  }
+  else if (ttypedef->get_type()->is_list()) {
+    t_list *list = (t_list *)ttypedef->get_type();
+    if (list->get_elem_type()->is_struct()) {
+      f_header_ << indent() << "@class " << type_name(list->get_elem_type(), true) << ";" << endl;
+    }
+  }
+  f_header_ << indent() << "typedef " << type_name(ttypedef->get_type()) << " " << cocoa_prefix_
+            << ttypedef->get_symbolic() << ";" << endl << endl;
+  if (ttypedef->get_type()->is_container()) {
+    f_header_ << indent() << "typedef " << type_name(ttypedef->get_type(), false, true) << " " << cocoa_prefix_
+              << "Mutable" << ttypedef->get_symbolic() << ";" << endl << endl;
+  }
+}
+
+/**
+ * Generates code for an enumerated type. In Objective-C, this is
+ * essentially the same as the thrift definition itself, instead using
+ * NS_ENUM keyword in Objective-C.  For namespace purposes, the name of
+ * the enum is prefixed to each element in keeping with Cocoa & Swift
+ * standards.
+ *
+ * @param tenum The enumeration
+ */
+void t_cocoa_generator::generate_enum(t_enum* tenum) {
+  f_header_ << indent() << "typedef NS_ENUM(SInt32, " << cocoa_prefix_ << tenum->get_name() << ") {" << endl;
+  indent_up();
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  bool first = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_header_ << "," << endl;
+    }
+    f_header_ << indent() << cocoa_prefix_ << tenum->get_name() << (*c_iter)->get_name();
+    f_header_ << " = " << (*c_iter)->get_value();
+  }
+
+  indent_down();
+  f_header_ << endl << "};" << endl << endl;
+}
+
+/**
+ * Generates a class that holds all the constants.
+ */
+void t_cocoa_generator::generate_consts(std::vector<t_const*> consts) {
+  std::ostringstream const_interface;
+
+  const_interface << "FOUNDATION_EXPORT NSString *" << cocoa_prefix_ << capitalize(program_name_) << "ErrorDomain;" << endl
+                  << endl;
+
+
+  bool needs_class = false;
+
+  // Public constants for base types & strings
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    t_type* type = (*c_iter)->get_type()->get_true_type();
+    if (!type->is_container() && !type->is_struct()) {
+      const_interface << "FOUNDATION_EXPORT " << type_name(type) << " "
+                      << cocoa_prefix_ << capitalize((*c_iter)->get_name()) << ";" << endl;
+    }
+    else {
+      needs_class = true;
+    }
+  }
+
+
+  string constants_class_name = cocoa_prefix_ + capitalize(program_name_) + "Constants";
+
+  if (needs_class) {
+
+    const_interface << endl;
+
+    const_interface << "@interface " << constants_class_name << " : NSObject ";
+    scope_up(const_interface);
+    scope_down(const_interface);
+
+    // getter method for each constant defined.
+    for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+      string name = (*c_iter)->get_name();
+      t_type* type = (*c_iter)->get_type()->get_true_type();
+      if (type->is_container() || type->is_struct()) {
+        t_type* type = (*c_iter)->get_type();
+        const_interface << endl << "+ (" << type_name(type) << ") " << name << ";" << endl;
+      }
+    }
+
+    const_interface << endl << "@end";
+  }
+
+  // this gets spit into the header file in ::close_generator
+  constants_declarations_ = const_interface.str();
+
+  f_impl_ << "NSString *" << cocoa_prefix_ << capitalize(program_name_) << "ErrorDomain = "
+          << "@\"" << cocoa_prefix_ << capitalize(program_name_) << "ErrorDomain\";" << endl << endl;
+
+  // variables in the .m hold all simple constant values
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    string name = (*c_iter)->get_name();
+    t_type* type = (*c_iter)->get_type();
+    f_impl_ << type_name(type) << " " << cocoa_prefix_ << name;
+    t_type* ttype = type->get_true_type();
+    if (!ttype->is_container() && !ttype->is_struct()) {
+      f_impl_ << " = " << render_const_value(f_impl_, type, (*c_iter)->get_value());
+    }
+    f_impl_ << ";" << endl;
+  }
+  f_impl_ << endl;
+
+  if (needs_class) {
+
+    f_impl_ << "@implementation " << constants_class_name << endl << endl;
+
+    // initialize complex constants when the class is loaded
+    f_impl_ << "+ (void) initialize ";
+    scope_up(f_impl_);
+
+    for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+      t_type* ttype = (*c_iter)->get_type()->get_true_type();
+      if (ttype->is_container() || ttype->is_struct()) {
+        f_impl_ << endl;
+        print_const_value(f_impl_,
+                          cocoa_prefix_ + (*c_iter)->get_name(),
+                          (*c_iter)->get_type(),
+                          (*c_iter)->get_value(),
+                          false);
+        f_impl_ << ";" << endl;
+      }
+    }
+    scope_down(f_impl_);
+
+    // getter method for each constant
+    for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+      string name = (*c_iter)->get_name();
+      t_type* type = (*c_iter)->get_type()->get_true_type();
+      if (type->is_container() || type->is_struct()) {
+        f_impl_ << endl << "+ (" << type_name(type) << ") " << name << " ";
+        scope_up(f_impl_);
+        indent(f_impl_) << "return " << cocoa_prefix_ << name << ";" << endl;
+        scope_down(f_impl_);
+      }
+    }
+
+    f_impl_ << "@end" << endl << endl;
+  }
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This is a class
+ * with protected data members, read(), write(), and getters and setters.
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_struct(t_struct* tstruct) {
+  generate_cocoa_struct_interface(f_header_, tstruct, false);
+  generate_cocoa_struct_implementation(f_impl_, tstruct, false);
+}
+
+/**
+ * Exceptions are structs, but they inherit from NSException
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_xception(t_struct* txception) {
+  generate_cocoa_struct_interface(f_header_, txception, true);
+  generate_cocoa_struct_implementation(f_impl_, txception, true);
+}
+
+/**
+ * Generate the interface for a struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_cocoa_struct_interface(ostream& out,
+                                                        t_struct* tstruct,
+                                                        bool is_exception) {
+
+  if (is_exception) {
+    out << "enum {" << endl
+        << "  " << cocoa_prefix_ << capitalize(program_name_) << "Error" << tstruct->get_name() <<  " = -" << error_constant_++ << endl
+        << "};" << endl
+        << endl;
+  }
+
+  out << "@interface " << cocoa_prefix_ << tstruct->get_name() << " : ";
+
+  if (is_exception) {
+    out << "NSError ";
+  } else {
+    out << "NSObject ";
+  }
+  out << "<TBase, NSCoding, NSCopying> " << endl;
+
+  out << endl;
+
+  // properties
+  const vector<t_field*>& members = tstruct->get_members();
+  if (members.size() > 0) {
+    vector<t_field*>::const_iterator m_iter;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      out << indent() << declare_property(*m_iter) << endl;
+      out << indent() << declare_property_isset(*m_iter) << endl;
+      out << indent() << declare_property_unset(*m_iter) << endl;
+      out << endl;
+    }
+  }
+
+  out << endl;
+
+  // initializer for all fields
+  if (!members.empty()) {
+    generate_cocoa_struct_initializer_signature(out, tstruct);
+    out << ";" << endl;
+  }
+  out << endl;
+
+  out << "@end" << endl << endl;
+}
+
+/**
+ * Generate signature for initializer of struct with a parameter for
+ * each field.
+ */
+void t_cocoa_generator::generate_cocoa_struct_initializer_signature(ostream& out,
+                                                                    t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  indent(out) << "- (instancetype) initWith";
+  for (m_iter = members.begin(); m_iter != members.end();) {
+    if (m_iter == members.begin()) {
+      out << capitalize((*m_iter)->get_name());
+    } else {
+      out << (*m_iter)->get_name();
+    }
+    out << ": (" << type_name((*m_iter)->get_type()) << ") " << (*m_iter)->get_name();
+    ++m_iter;
+    if (m_iter != members.end()) {
+      out << " ";
+    }
+  }
+}
+
+/**
+ * Generate the initWithCoder method for this struct so it's compatible with
+ * the NSCoding protocol
+ */
+void t_cocoa_generator::generate_cocoa_struct_init_with_coder_method(ostream& out,
+                                                                     t_struct* tstruct,
+                                                                     bool is_exception) {
+
+  indent(out) << "- (instancetype) initWithCoder: (NSCoder *) decoder" << endl;
+  scope_up(out);
+
+  if (is_exception) {
+    // NSExceptions conform to NSCoding, so we can call super
+    indent(out) << "self = [super initWithCoder: decoder];" << endl;
+  } else {
+    indent(out) << "self = [super init];" << endl;
+  }
+
+  indent(out) << "if (self) ";
+  scope_up(out);
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    out << indent() << "if ([decoder containsValueForKey: @\"" << (*m_iter)->get_name() << "\"])"
+        << endl;
+    scope_up(out);
+    out << indent() << "_" << (*m_iter)->get_name() << " = ";
+    if (type_can_be_null(t)) {
+      out << "[decoder decodeObjectForKey: @\"" << (*m_iter)->get_name() << "\"];"
+          << endl;
+    } else if (t->is_enum()) {
+      out << "[decoder decodeIntForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
+    } else {
+      t_base_type::t_base tbase = ((t_base_type*)t)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_BOOL:
+        out << "[decoder decodeBoolForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
+        break;
+      case t_base_type::TYPE_I8:
+        out << "[decoder decodeIntForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
+        break;
+      case t_base_type::TYPE_I16:
+        out << "[decoder decodeIntForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
+        break;
+      case t_base_type::TYPE_I32:
+        out << "[decoder decodeInt32ForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
+        break;
+      case t_base_type::TYPE_I64:
+        out << "[decoder decodeInt64ForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "[decoder decodeDoubleForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
+        break;
+      default:
+        throw "compiler error: don't know how to decode thrift type: "
+            + t_base_type::t_base_name(tbase);
+      }
+    }
+    out << indent() << "_" << (*m_iter)->get_name() << "IsSet = YES;" << endl;
+    scope_down(out);
+  }
+
+  scope_down(out);
+
+  out << indent() << "return self;" << endl;
+  scope_down(out);
+  out << endl;
+}
+
+/**
+ * Generate the encodeWithCoder method for this struct so it's compatible with
+ * the NSCoding protocol
+ */
+void t_cocoa_generator::generate_cocoa_struct_encode_with_coder_method(ostream& out,
+                                                                       t_struct* tstruct,
+                                                                       bool is_exception) {
+
+  indent(out) << "- (void) encodeWithCoder: (NSCoder *) encoder" << endl;
+  scope_up(out);
+
+  if (is_exception) {
+    // NSExceptions conform to NSCoding, so we can call super
+    out << indent() << "[super encodeWithCoder: encoder];" << endl;
+  }
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    out << indent() << "if (_" << (*m_iter)->get_name() << "IsSet)" << endl;
+    scope_up(out);
+    if (type_can_be_null(t)) {
+      out << indent() << "[encoder encodeObject: _" << (*m_iter)->get_name() << " forKey: @\""
+          << (*m_iter)->get_name() << "\"];" << endl;
+    } else if (t->is_enum()) {
+      out << indent() << "[encoder encodeInt: _" << (*m_iter)->get_name() << " forKey: @\""
+          << (*m_iter)->get_name() << "\"];" << endl;
+    } else {
+      t_base_type::t_base tbase = ((t_base_type*)t)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_BOOL:
+        out << indent() << "[encoder encodeBool: _" << (*m_iter)->get_name() << " forKey: @\""
+            << (*m_iter)->get_name() << "\"];" << endl;
+        break;
+      case t_base_type::TYPE_I8:
+        out << indent() << "[encoder encodeInt: _" << (*m_iter)->get_name() << " forKey: @\""
+            << (*m_iter)->get_name() << "\"];" << endl;
+        break;
+      case t_base_type::TYPE_I16:
+        out << indent() << "[encoder encodeInt: _" << (*m_iter)->get_name() << " forKey: @\""
+            << (*m_iter)->get_name() << "\"];" << endl;
+        break;
+      case t_base_type::TYPE_I32:
+        out << indent() << "[encoder encodeInt32: _" << (*m_iter)->get_name() << " forKey: @\""
+            << (*m_iter)->get_name() << "\"];" << endl;
+        break;
+      case t_base_type::TYPE_I64:
+        out << indent() << "[encoder encodeInt64: _" << (*m_iter)->get_name() << " forKey: @\""
+            << (*m_iter)->get_name() << "\"];" << endl;
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << indent() << "[encoder encodeDouble: _" << (*m_iter)->get_name() << " forKey: @\""
+            << (*m_iter)->get_name() << "\"];" << endl;
+        break;
+      default:
+        throw "compiler error: don't know how to encode thrift type: "
+            + t_base_type::t_base_name(tbase);
+      }
+    }
+    scope_down(out);
+  }
+
+  scope_down(out);
+  out << endl;
+}
+
+/**
+ * Generate the copy method for this struct
+ */
+void t_cocoa_generator::generate_cocoa_struct_copy_method(ostream& out, t_struct* tstruct, bool is_exception) {
+  out << indent() << "- (instancetype) copyWithZone:(NSZone *)zone" << endl;
+  scope_up(out);
+
+  if (is_exception) {
+    out << indent() << type_name(tstruct) << " val = [" << cocoa_prefix_ << tstruct->get_name() << " errorWithDomain: self.domain code: self.code userInfo: self.userInfo];" << endl;
+  } else {
+    out << indent() << type_name(tstruct) << " val = [" << cocoa_prefix_ << tstruct->get_name() << " new];" << endl;
+  }
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    out << indent() << "if (_" << (*m_iter)->get_name() << "IsSet)" << endl;
+    scope_up(out);
+    if (type_can_be_null(t)) {
+      out << indent() << "val." << (*m_iter)->get_name() << " = [self." << (*m_iter)->get_name() << " copy];";
+    } else {
+      out << indent() << "val." << (*m_iter)->get_name() << " = self." << (*m_iter)->get_name() << ";";
+    }
+    out << endl;
+    scope_down(out);
+  }
+
+  out << indent() << "return val;" << endl;
+
+  scope_down(out);
+  out << endl;
+}
+
+/**
+ * Generate the hash method for this struct
+ */
+void t_cocoa_generator::generate_cocoa_struct_hash_method(ostream& out, t_struct* tstruct) {
+  indent(out) << "- (NSUInteger) hash" << endl;
+  scope_up(out);
+  out << indent() << "NSUInteger hash = 17;" << endl;
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    out << indent() << "hash = (hash * 31) ^ _" << (*m_iter)->get_name()
+        << "IsSet ? 2654435761 : 0;" << endl;
+    out << indent() << "if (_" << (*m_iter)->get_name() << "IsSet)" << endl;
+    scope_up(out);
+    if (type_can_be_null(t)) {
+      out << indent() << "hash = (hash * 31) ^ [_" << (*m_iter)->get_name() << " hash];" << endl;
+    } else {
+      out << indent() << "hash = (hash * 31) ^ [@(_" << (*m_iter)->get_name() << ") hash];"
+          << endl;
+    }
+    scope_down(out);
+  }
+
+  out << indent() << "return hash;" << endl;
+  scope_down(out);
+  out << endl;
+}
+
+/**
+ * Generate the isEqual method for this struct
+ */
+void t_cocoa_generator::generate_cocoa_struct_is_equal_method(ostream& out, t_struct* tstruct, bool is_exception) {
+  indent(out) << "- (BOOL) isEqual: (id) anObject" << endl;
+  scope_up(out);
+
+  indent(out) << "if (self == anObject) {" << endl;
+  indent_up();
+  indent(out) << "return YES;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+
+  string class_name = cocoa_prefix_ + tstruct->get_name();
+
+  if (is_exception) {
+    indent(out) << "if (![super isEqual:anObject]) {" << endl;
+    indent_up();
+    indent(out) << "return NO;" << endl;
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+  else {
+    indent(out) << "if (![anObject isKindOfClass:[" << class_name << " class]]) {" << endl;
+    indent_up();
+    indent(out) << "return NO;" << endl;
+    indent_down();
+    indent(out) << "}" << endl;
+  }
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  if (!members.empty()) {
+    indent(out) << class_name << " *other = (" << class_name << " *)anObject;" << endl;
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+      string name = (*m_iter)->get_name();
+      if (type_can_be_null(t)) {
+        out << indent() << "if ((_" << name << "IsSet != other->_" << name << "IsSet) ||" << endl
+            << indent() << "    "
+            << "(_" << name << "IsSet && "
+            << "((_" << name << " || other->_" << name << ") && "
+            << "![_" << name << " isEqual:other->_" << name << "]))) {" << endl;
+      } else {
+        out << indent() << "if ((_" << name << "IsSet != other->_" << name << "IsSet) ||" << endl
+            << indent() << "    "
+            << "(_" << name << "IsSet && "
+            << "(_" << name << " != other->_" << name << "))) {" << endl;
+      }
+      indent_up();
+      indent(out) << "return NO;" << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+
+  out << indent() << "return YES;" << endl;
+  scope_down(out);
+  out << endl;
+}
+
+/**
+ * Generate struct implementation.
+ *
+ * @param tstruct      The struct definition
+ * @param is_exception Is this an exception?
+ * @param is_result    If this is a result it needs a different writer
+ */
+void t_cocoa_generator::generate_cocoa_struct_implementation(ostream& out,
+                                                             t_struct* tstruct,
+                                                             bool is_exception,
+                                                             bool is_result) {
+  indent(out) << "@implementation " << cocoa_prefix_ << tstruct->get_name() << endl << endl;
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  // exceptions need to call the designated initializer on NSException
+  if (is_exception) {
+    out << indent() << "- (instancetype) init" << endl;
+    scope_up(out);
+    out << indent() << "return [super initWithDomain: " << cocoa_prefix_ << capitalize(program_name_) << "ErrorDomain" << endl
+        << indent() << "                        code: " << cocoa_prefix_ << capitalize(program_name_) << "Error" << tstruct->get_name() << endl
+        << indent() << "                    userInfo: nil];" << endl;
+    scope_down(out);
+    out << endl;
+  } else {
+    // struct
+
+    // default initializer
+    // setup instance variables with default values
+    indent(out) << "- (instancetype) init" << endl;
+    scope_up(out);
+    indent(out) << "self = [super init];" << endl;
+    indent(out) << "if (self)";
+    scope_up(out);
+    if (members.size() > 0) {
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        t_type* t = get_true_type((*m_iter)->get_type());
+        if ((*m_iter)->get_value() != NULL) {
+          print_const_value(out,
+                            "self." + (*m_iter)->get_name(),
+                            t,
+                            (*m_iter)->get_value(),
+                            false);
+        }
+      }
+    }
+    scope_down(out);
+    indent(out) << "return self;" << endl;
+    scope_down(out);
+    out << endl;
+  }
+
+  // initializer with all fields as params
+  if (!members.empty()) {
+    generate_cocoa_struct_initializer_signature(out, tstruct);
+    out << endl;
+    scope_up(out);
+    if (is_exception) {
+      out << indent() << "self = [self init];" << endl;
+    } else {
+      out << indent() << "self = [super init];" << endl;
+    }
+
+    indent(out) << "if (self)";
+    scope_up(out);
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      out << indent() << "_" << (*m_iter)->get_name() << " = ";
+      if (get_true_type((*m_iter)->get_type())->is_container()) {
+        out << "[" << (*m_iter)->get_name() << " mutableCopy];" << endl;
+      } else {
+        out << (*m_iter)->get_name() << ";" << endl;
+      }
+      out << indent() << "_" << (*m_iter)->get_name() << "IsSet = YES;" << endl;
+    }
+    scope_down(out);
+
+    out << indent() << "return self;" << endl;
+    scope_down(out);
+    out << endl;
+  }
+
+  // initWithCoder for NSCoding
+  generate_cocoa_struct_init_with_coder_method(out, tstruct, is_exception);
+  // encodeWithCoder for NSCoding
+  generate_cocoa_struct_encode_with_coder_method(out, tstruct, is_exception);
+  // hash and isEqual for NSObject
+  generate_cocoa_struct_hash_method(out, tstruct);
+  generate_cocoa_struct_is_equal_method(out, tstruct, is_exception);
+  // copy for NSObject
+  generate_cocoa_struct_copy_method(out, tstruct, is_exception);
+
+  // the rest of the methods
+  generate_cocoa_struct_field_accessor_implementations(out, tstruct, is_exception);
+  generate_cocoa_struct_reader(out, tstruct);
+  if (is_result) {
+    generate_cocoa_struct_result_writer(out, tstruct);
+  } else {
+    generate_cocoa_struct_writer(out, tstruct);
+  }
+  generate_cocoa_struct_validator(out, tstruct);
+  generate_cocoa_struct_description(out, tstruct);
+
+  out << "@end" << endl << endl;
+}
+
+/**
+ * Generates a function to read all the fields of the struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_cocoa_struct_reader(ostream& out, t_struct* tstruct) {
+  out << "- (BOOL) read: (id <TProtocol>) inProtocol error: (NSError *__autoreleasing *)__thriftError" << endl;
+  scope_up(out);
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Declare stack tmp variables
+  indent(out) << "NSString * fieldName;" << endl;
+  indent(out) << "SInt32 fieldType;" << endl;
+  indent(out) << "SInt32 fieldID;" << endl;
+  out << endl;
+
+  indent(out) << "if (![inProtocol readStructBeginReturningName: NULL error: __thriftError]) return NO;" << endl;
+
+  // Loop over reading in fields
+  indent(out) << "while (true)" << endl;
+  scope_up(out);
+
+  // Read beginning field marker
+  indent(out)
+      << "if (![inProtocol readFieldBeginReturningName: &fieldName type: &fieldType fieldID: &fieldID error: __thriftError]) return NO;"
+      << endl;
+
+  // Check for field STOP marker and break
+  indent(out) << "if (fieldType == TTypeSTOP) { " << endl;
+  indent_up();
+  indent(out) << "break;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+
+  // Switch statement on the field we are reading
+  indent(out) << "switch (fieldID)" << endl;
+
+  scope_up(out);
+
+  // Generate deserialization code for known cases
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) << "case " << (*f_iter)->get_key() << ":" << endl;
+    indent_up();
+    indent(out) << "if (fieldType == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+    indent_up();
+
+    generate_deserialize_field(out, *f_iter, "fieldValue");
+    indent(out) << call_field_setter(*f_iter, "fieldValue") << endl;
+
+    indent_down();
+    out << indent() << "} else { " << endl;
+    if (log_unexpected_) {
+      out << indent() << "  NSLog(@\"%s: field ID %i has unexpected type %i.  Skipping.\", "
+                         "__PRETTY_FUNCTION__, (int)fieldID, (int)fieldType);" << endl;
+    }
+
+    out << indent() << "  if (![TProtocolUtil skipType: fieldType onProtocol: inProtocol error: __thriftError]) return NO;" << endl;
+    out << indent() << "}" << endl << indent() << "break;" << endl;
+    indent_down();
+  }
+
+  // In the default case we skip the field
+  out << indent() << "default:" << endl;
+  if (log_unexpected_) {
+    out << indent() << "  NSLog(@\"%s: unexpected field ID %i with type %i.  Skipping.\", "
+                       "__PRETTY_FUNCTION__, (int)fieldID, (int)fieldType);" << endl;
+  }
+
+  out << indent() << "  if (![TProtocolUtil skipType: fieldType onProtocol: inProtocol error: __thriftError]) return NO;" << endl;
+
+  out << indent() << "  break;" << endl;
+
+  scope_down(out);
+
+  // Read field end marker
+  indent(out) << "if (![inProtocol readFieldEnd: __thriftError]) return NO;" << endl;
+
+  scope_down(out);
+
+  out << indent() << "if (![inProtocol readStructEnd: __thriftError]) return NO;" << endl;
+
+  // performs various checks (e.g. check that all required fields are set)
+  if (validate_required_) {
+    out << indent() << "if (![self validate: __thriftError]) return NO;" << endl;
+  }
+
+  indent(out) << "return YES;" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_cocoa_struct_writer(ostream& out, t_struct* tstruct) {
+  out << indent() << "- (BOOL) write: (id <TProtocol>) outProtocol error: (NSError *__autoreleasing *)__thriftError {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out << indent() << "if (![outProtocol writeStructBeginWithName: @\"" << name << "\" error: __thriftError]) return NO;" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    out << indent() << "if (_" << (*f_iter)->get_name() << "IsSet) {" << endl;
+    indent_up();
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    if (null_allowed) {
+      out << indent() << "if (_" << (*f_iter)->get_name() << " != nil) {" << endl;
+      indent_up();
+    }
+
+    indent(out) << "if (![outProtocol writeFieldBeginWithName: @\"" << (*f_iter)->get_name()
+                << "\" type: " << type_to_enum((*f_iter)->get_type())
+                << " fieldID: " << (*f_iter)->get_key() << " error: __thriftError]) return NO;" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "_" + (*f_iter)->get_name());
+
+    // Write field closer
+    indent(out) << "if (![outProtocol writeFieldEnd: __thriftError]) return NO;" << endl;
+
+    if (null_allowed) {
+      scope_down(out);
+    }
+    scope_down(out);
+  }
+  // Write the struct map
+  out << indent() << "if (![outProtocol writeFieldStop: __thriftError]) return NO;" << endl
+      << indent() << "if (![outProtocol writeStructEnd: __thriftError]) return NO;" << endl;
+
+  indent(out) << "return YES;" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct, which
+ * is a function result. These fields are only written if they are
+ * set, and only one of them can be set at a time.
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_cocoa_struct_result_writer(ostream& out, t_struct* tstruct) {
+  out << indent() << "- (BOOL) write: (id <TProtocol>) outProtocol error: (NSError *__autoreleasing *)__thriftError {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out << indent() << "if (![outProtocol writeStructBeginWithName: @\"" << name << "\" error: __thriftError]) return NO;" << endl;
+
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      out << endl << indent() << "if ";
+    } else {
+      out << " else if ";
+    }
+
+    out << "(_" << (*f_iter)->get_name() << "IsSet) {" << endl;
+    indent_up();
+
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    if (null_allowed) {
+      out << indent() << "if (_" << (*f_iter)->get_name() << " != nil) {" << endl;
+      indent_up();
+    }
+
+    indent(out) << "if (![outProtocol writeFieldBeginWithName: @\"" << (*f_iter)->get_name()
+                << "\" type: " << type_to_enum((*f_iter)->get_type())
+                << " fieldID: " << (*f_iter)->get_key() << " error: __thriftError]) return NO;" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "_" + (*f_iter)->get_name());
+
+    // Write field closer
+    indent(out) << "if (![outProtocol writeFieldEnd: __thriftError]) return NO;" << endl;
+
+    if (null_allowed) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+
+    indent_down();
+    indent(out) << "}";
+  }
+  // Write the struct map
+  out << endl << indent() << "if (![outProtocol writeFieldStop: __thriftError]) return NO;"
+      << endl << indent() << "if (![outProtocol writeStructEnd: __thriftError]) return NO;"
+      << endl;
+
+  indent(out) << "return YES;" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to perform various checks
+ * (e.g. check that all required fields are set)
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_cocoa_struct_validator(ostream& out, t_struct* tstruct) {
+  out << indent() << "- (BOOL) validate: (NSError *__autoreleasing *)__thriftError {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out << indent() << "// check for required fields" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = (*f_iter);
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      out << indent() << "if (!_" << field->get_name() << "IsSet) ";
+      scope_up(out);
+      indent(out) << "if (__thriftError) ";
+      scope_up(out);
+      out << indent() << "*__thriftError = [NSError errorWithDomain: TProtocolErrorDomain" << endl
+          << indent() << "                                     code: TProtocolErrorUnknown" << endl
+          << indent() << "                                 userInfo: @{TProtocolErrorExtendedErrorKey: @(TProtocolExtendedErrorMissingRequiredField)," << endl
+          << indent() << "                                             TProtocolErrorFieldNameKey: @\"" << (*f_iter)->get_name() << "\"}];" << endl;
+      scope_down(out);
+      scope_down(out);
+    }
+  }
+  indent(out) << "return YES;" << endl;
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generate property accessor methods for all fields in the struct.
+ * getter, setter, isset getter.
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_cocoa_struct_field_accessor_implementations(ostream& out,
+                                                                             t_struct* tstruct,
+                                                                             bool is_exception) {
+  (void)is_exception;
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    t_type* type = get_true_type(field->get_type());
+    std::string field_name = field->get_name();
+    std::string cap_name = field_name;
+    cap_name[0] = toupper(cap_name[0]);
+
+    // Simple setter
+    indent(out) << "- (void) set" << cap_name << ": (" << type_name(type, false, true) << ") " << field_name
+                << " {" << endl;
+    indent_up();
+    indent(out) << "_" << field_name << " = " << field_name << ";" << endl;
+    indent(out) << "_" << field_name << "IsSet = YES;" << endl;
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // Unsetter - do we need this?
+    indent(out) << "- (void) unset" << cap_name << " {" << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "_" << field_name << " = nil;" << endl;
+    }
+    indent(out) << "_" << field_name << "IsSet = NO;" << endl;
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+}
+
+/**
+ * Generates a description method for the given struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_cocoa_generator::generate_cocoa_struct_description(ostream& out, t_struct* tstruct) {
+
+  // Allow use of debugDescription so the app can add description via a cateogory/extension
+  if (debug_descriptions_) {
+    out << indent() << "- (NSString *) debugDescription {" << endl;
+  }
+  else {
+    out << indent() << "- (NSString *) description {" << endl;
+  }
+  indent_up();
+
+  out << indent() << "NSMutableString * ms = [NSMutableString stringWithString: @\""
+      << cocoa_prefix_ << tstruct->get_name() << "(\"];" << endl;
+
+  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;
+      indent(out) << "[ms appendString: @\"" << (*f_iter)->get_name() << ":\"];" << endl;
+    } else {
+      indent(out) << "[ms appendString: @\"," << (*f_iter)->get_name() << ":\"];" << endl;
+    }
+    t_type* ttype = (*f_iter)->get_type();
+    indent(out) << "[ms appendFormat: @\"" << format_string_for_type(ttype) << "\", "
+                << format_cast_for_type(ttype) << "_" << (*f_iter)->get_name() << "];" << endl;
+  }
+  out << indent() << "[ms appendString: @\")\"];" << endl << indent()
+      << "return [NSString stringWithString: ms];" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a thrift service.  In Objective-C this consists of a
+ * protocol definition, a client interface and a client implementation.
+ *
+ * @param tservice The service definition
+ */
+void t_cocoa_generator::generate_service(t_service* tservice) {
+  generate_cocoa_service_protocol(f_header_, tservice);
+  generate_cocoa_service_client_interface(f_header_, tservice);
+  generate_cocoa_service_server_interface(f_header_, tservice);
+  generate_cocoa_service_helpers(tservice);
+  generate_cocoa_service_client_implementation(f_impl_, tservice);
+  generate_cocoa_service_server_implementation(f_impl_, tservice);
+  if (async_clients_) {
+    generate_cocoa_service_async_protocol(f_header_, tservice);
+    generate_cocoa_service_client_async_interface(f_header_, tservice);
+    generate_cocoa_service_client_async_implementation(f_impl_, tservice);
+  }
+}
+
+/**
+ * Generates structs for all the service return types
+ *
+ * @param tservice The service
+ */
+void t_cocoa_generator::generate_cocoa_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+
+    t_struct* ts = (*f_iter)->get_arglist();
+
+    string qname = function_args_helper_struct_type(tservice, *f_iter);
+
+    t_struct qname_ts = t_struct(ts->get_program(), qname);
+
+    const vector<t_field*>& members = ts->get_members();
+    vector<t_field*>::const_iterator m_iter;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      qname_ts.append(*m_iter);
+    }
+
+    generate_cocoa_struct_interface(f_impl_, &qname_ts, false);
+    generate_cocoa_struct_implementation(f_impl_, &qname_ts, false, false);
+    generate_function_helpers(tservice, *f_iter);
+  }
+}
+
+string t_cocoa_generator::function_result_helper_struct_type(t_service *tservice, t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return tservice->get_name() + "_" + tfunction->get_name();
+  } else {
+    return tservice->get_name() + "_" + tfunction->get_name() + "_result";
+  }
+}
+
+string t_cocoa_generator::function_args_helper_struct_type(t_service *tservice, t_function* tfunction) {
+  return tservice->get_name() + "_" + tfunction->get_name() + "_args";
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_cocoa_generator::generate_function_helpers(t_service *tservice, t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return;
+  }
+
+  // create a result struct with a success field of the return type,
+  // and a field for each type of exception thrown
+  t_struct result(program_, function_result_helper_struct_type(tservice, tfunction));
+  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 the result struct
+  generate_cocoa_struct_interface(f_impl_, &result, false);
+  generate_cocoa_struct_implementation(f_impl_, &result, false, true);
+}
+
+/**
+ * Generates a service protocol definition.
+ *
+ * @param tservice The service to generate a protocol definition for
+ */
+void t_cocoa_generator::generate_cocoa_service_protocol(ostream& out, t_service* tservice) {
+  out << "@protocol " << cocoa_prefix_ << tservice->get_name() << " <NSObject>" << endl;
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    out << "- " << function_signature(*f_iter, true) << ";"
+        << "  // throws ";
+    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) {
+      out << type_name((*x_iter)->get_type()) + ", ";
+    }
+    out << "TException" << endl;
+  }
+  out << "@end" << endl << endl;
+}
+
+/**
+ * Generates an asynchronous service protocol definition.
+ *
+ * @param tservice The service to generate a protocol definition for
+ */
+void t_cocoa_generator::generate_cocoa_service_async_protocol(ostream& out, t_service* tservice) {
+  out << "@protocol " << cocoa_prefix_ << tservice->get_name() << "Async"
+      << " <NSObject>" << endl;
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    out << "- " << async_function_signature(*f_iter, false) << ";" << endl;
+    if (promise_kit_) {
+      out << "- " << promise_function_signature(*f_iter) << ";" << endl;
+    }
+  }
+  out << "@end" << endl << endl;
+}
+
+/**
+ * Generates a service client interface definition.
+ *
+ * @param tservice The service to generate a client interface definition for
+ */
+void t_cocoa_generator::generate_cocoa_service_client_interface(ostream& out,
+                                                                t_service* tservice) {
+  out << "@interface " << cocoa_prefix_ << tservice->get_name() << "Client : TBaseClient <"
+      << cocoa_prefix_ << tservice->get_name() << "> " << endl;
+
+  out << "- (id) initWithProtocol: (id <TProtocol>) protocol;" << endl;
+  out << "- (id) initWithInProtocol: (id <TProtocol>) inProtocol outProtocol: (id <TProtocol>) "
+         "outProtocol;" << endl;
+  out << "@end" << endl << endl;
+}
+
+/**
+ * Generates a service client interface definition.
+ *
+ * @param tservice The service to generate a client interface definition for
+ */
+void t_cocoa_generator::generate_cocoa_service_client_async_interface(ostream& out,
+                                                                      t_service* tservice) {
+  out << "@interface " << cocoa_prefix_ << tservice->get_name() << "ClientAsync : TBaseClient <"
+      << cocoa_prefix_ << tservice->get_name() << "Async> " << endl
+      << endl;
+
+  out << "- (id) initWithProtocolFactory: (id <TProtocolFactory>) protocolFactory "
+      << "transportFactory: (id <TAsyncTransportFactory>) transportFactory;" << endl;
+  out << "@end" << endl << endl;
+}
+
+/**
+ * Generates a service server interface definition. In other words, the TProcess implementation for
+ *the
+ * service definition.
+ *
+ * @param tservice The service to generate a client interface definition for
+ */
+void t_cocoa_generator::generate_cocoa_service_server_interface(ostream& out,
+                                                                t_service* tservice) {
+  out << "@interface " << cocoa_prefix_ << tservice->get_name()
+      << "Processor : NSObject <TProcessor> " << endl;
+
+  out << "- (id) initWith" << tservice->get_name() << ": (id <" << cocoa_prefix_
+      << tservice->get_name() << ">) service;" << endl;
+  out << "- (id<" << cocoa_prefix_ << tservice->get_name() << ">) service;" << endl;
+
+  out << "@end" << endl << endl;
+}
+
+void t_cocoa_generator::generate_cocoa_service_client_send_function_implementation(
+    ostream& out,
+    t_service *tservice,
+    t_function* tfunction,
+    bool needs_protocol) {
+  string funname = tfunction->get_name();
+
+  t_function send_function(g_type_bool,
+                           string("send_") + tfunction->get_name(),
+                           tfunction->get_arglist());
+
+  string argsname = function_args_helper_struct_type(tservice, tfunction);
+
+  // Open function
+  indent(out) << "- (BOOL) send_" << tfunction->get_name() << argument_list(tfunction->get_arglist(), needs_protocol ? "outProtocol" : "", true) << endl;
+  scope_up(out);
+
+  // Serialize the request
+  out << indent() << "if (![outProtocol writeMessageBeginWithName: @\"" << funname << "\""
+      << (tfunction->is_oneway() ? " type: TMessageTypeONEWAY" : " type: TMessageTypeCALL")
+      << " sequenceID: 0 error: __thriftError]) return NO;" << endl;
+
+  out << indent() << "if (![outProtocol writeStructBeginWithName: @\"" << argsname
+                  << "\" error: __thriftError]) return NO;" << endl;
+
+  // write out function parameters
+  t_struct* arg_struct = tfunction->get_arglist();
+  const vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator fld_iter;
+  for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+    string fieldName = (*fld_iter)->get_name();
+    if (type_can_be_null((*fld_iter)->get_type())) {
+      out << indent() << "if (" << fieldName << " != nil)";
+      scope_up(out);
+    }
+    out << indent() << "if (![outProtocol writeFieldBeginWithName: @\"" << fieldName
+        << "\""
+           " type: " << type_to_enum((*fld_iter)->get_type())
+        << " fieldID: " << (*fld_iter)->get_key() << " error: __thriftError]) return NO;" << endl;
+
+    generate_serialize_field(out, *fld_iter, fieldName);
+
+    out << indent() << "if (![outProtocol writeFieldEnd: __thriftError]) return NO;" << endl;
+
+    if (type_can_be_null((*fld_iter)->get_type())) {
+      indent_down();
+      out << indent() << "}" << endl;
+    }
+  }
+
+  out << indent() << "if (![outProtocol writeFieldStop: __thriftError]) return NO;" << endl;
+  out << indent() << "if (![outProtocol writeStructEnd: __thriftError]) return NO;" << endl;
+  out << indent() << "if (![outProtocol writeMessageEnd: __thriftError]) return NO;" << endl;
+  out << indent() << "return YES;" << endl;
+  scope_down(out);
+  out << endl;
+}
+
+void t_cocoa_generator::generate_cocoa_service_client_recv_function_implementation(
+    ostream& out,
+    t_service* tservice,
+    t_function* tfunction,
+    bool needs_protocol) {
+
+
+  // Open function
+  indent(out) << "- (BOOL) recv_" << tfunction->get_name();
+  if (!tfunction->get_returntype()->is_void()) {
+    out << ": (" << type_name(tfunction->get_returntype(), false, true) << " *) result ";
+    if (needs_protocol) {
+      out << "protocol";
+    } else {
+      out << "error";
+    }
+  }
+  if (needs_protocol) {
+    out << ": (id<TProtocol>) inProtocol error";
+  }
+  out << ": (NSError *__autoreleasing *)__thriftError" << endl;
+  scope_up(out);
+
+  // TODO(mcslee): Message validation here, was the seqid etc ok?
+
+  // check for an exception
+  out << indent() << "NSError *incomingException = [self checkIncomingMessageException: inProtocol];" << endl
+      << indent() << "if (incomingException)";
+  scope_up(out);
+  out << indent() << "if (__thriftError)";
+  scope_up(out);
+  out << indent() << "*__thriftError = incomingException;" << endl;
+  scope_down(out);
+  out << indent() << "return NO;" << endl;
+  scope_down(out);
+
+  // FIXME - could optimize here to reduce creation of temporary objects.
+  string resultname = function_result_helper_struct_type(tservice, tfunction);
+  out << indent() << cocoa_prefix_ << resultname << " * resulter = [" << cocoa_prefix_ << resultname << " new];" << endl;
+  indent(out) << "if (![resulter read: inProtocol error: __thriftError]) return NO;" << endl;
+  indent(out) << "if (![inProtocol readMessageEnd: __thriftError]) return NO;" << endl;
+
+  // Careful, only return _result if not a void function
+  if (!tfunction->get_returntype()->is_void()) {
+    out << indent() << "if (resulter.successIsSet)";
+    scope_up(out);
+    out << indent() << "*result = resulter.success;" << endl;
+    out << indent() << "return YES;" << endl;
+    scope_down(out);
+  }
+
+  t_struct* xs = tfunction->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) {
+    out << indent() << "if (resulter." << (*x_iter)->get_name() << "IsSet)";
+    scope_up(out);
+    out << indent() << "if (__thriftError)";
+    scope_up(out);
+    out << indent() << "*__thriftError = [resulter " << (*x_iter)->get_name() << "];" << endl;
+    scope_down(out);
+    out << indent() << "return NO;" << endl;
+    scope_down(out);
+  }
+
+  // If you get here it's an exception, unless a void function
+  if (tfunction->get_returntype()->is_void()) {
+    indent(out) << "return YES;" << endl;
+  } else {
+    out << indent() << "if (__thriftError)";
+    scope_up(out);
+    out << indent() << "*__thriftError = [NSError errorWithDomain: TApplicationErrorDomain" << endl
+        << indent() << "                                     code: TApplicationErrorMissingResult" << endl
+        << indent() << "                                 userInfo: @{TApplicationErrorMethodKey: @\""
+        << tfunction->get_name() << "\"}];" << endl;
+    scope_down(out);
+    out << indent() << "return NO;" << endl;
+  }
+
+  // Close function
+  scope_down(out);
+  out << endl;
+}
+
+/**
+ * Generates an invocation of a given 'send_' function.
+ *
+ * @param tfunction The service to generate an implementation for
+ */
+void t_cocoa_generator::generate_cocoa_service_client_send_function_invocation(
+                                                                               ostream& out,
+                                                                               t_function* tfunction) {
+
+  t_struct* arg_struct = tfunction->get_arglist();
+  const vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator fld_iter;
+  out << indent() << "if (![self send_" << tfunction->get_name();
+  bool first = true;
+  for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+    string fieldName = (*fld_iter)->get_name();
+    out << " ";
+    if (first) {
+      first = false;
+      out << ": " << fieldName;
+    } else {
+      out << fieldName << ": " << fieldName;
+    }
+  }
+  if (!fields.empty()) {
+    out << " error";
+  }
+  out << ": __thriftError]) " << invalid_return_statement(tfunction) << endl;
+}
+
+/**
+ * Generates an invocation of a given 'send_' function.
+ *
+ * @param tfunction The service to generate an implementation for
+ */
+void t_cocoa_generator::generate_cocoa_service_client_send_async_function_invocation(
+                                                                                     ostream& out,
+                                                                                     t_function* tfunction,
+                                                                                     string failureBlockName) {
+
+  t_struct* arg_struct = tfunction->get_arglist();
+  const vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator fld_iter;
+  out << indent() << "if (![self send_" << tfunction->get_name();
+  bool first = true;
+  for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+    string fieldName = (*fld_iter)->get_name();
+    out << " ";
+    if (first) {
+      first = false;
+      out << ": " << fieldName;
+    } else {
+      out << fieldName << ": " << fieldName;
+    }
+  }
+  if (!fields.empty()) {
+    out << " protocol";
+  }
+  out << ": protocol error: &thriftError]) ";
+  scope_up(out);
+  out << indent() << failureBlockName << "(thriftError);" << endl
+      << indent() << "return;" << endl;
+  scope_down(out);
+}
+
+/**
+ * Generates a service client implementation.
+ *
+ * @param tservice The service to generate an implementation for
+ */
+void t_cocoa_generator::generate_cocoa_service_client_implementation(ostream& out,
+                                                                     t_service* tservice) {
+
+  string name = cocoa_prefix_ + tservice->get_name() + "Client";
+
+  out << "@interface " << name << " () ";
+  scope_up(out);
+  out << endl;
+  out << indent() << "id<TProtocol> inProtocol;" << endl;
+  out << indent() << "id<TProtocol> outProtocol;" << endl;
+  out << endl;
+  scope_down(out);
+  out << endl;
+  out << "@end" << endl << endl;
+
+  out << "@implementation " << name << endl;
+
+  // initializers
+  out << "- (id) initWithProtocol: (id <TProtocol>) protocol" << endl;
+  scope_up(out);
+  out << indent() << "return [self initWithInProtocol: protocol outProtocol: protocol];" << endl;
+  scope_down(out);
+  out << endl;
+
+  out << "- (id) initWithInProtocol: (id <TProtocol>) anInProtocol outProtocol: (id <TProtocol>) "
+         "anOutProtocol" << endl;
+  scope_up(out);
+  out << indent() << "self = [super init];" << endl;
+  out << indent() << "if (self) ";
+  scope_up(out);
+  out << indent() << "inProtocol = anInProtocol;" << endl;
+  out << indent() << "outProtocol = anOutProtocol;" << endl;
+  scope_down(out);
+  out << indent() << "return self;" << endl;
+  scope_down(out);
+  out << 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) {
+
+    generate_cocoa_service_client_send_function_implementation(out, tservice, *f_iter, false);
+
+    if (!(*f_iter)->is_oneway()) {
+      generate_cocoa_service_client_recv_function_implementation(out, tservice, *f_iter, false);
+    }
+
+    // Open function
+    indent(out) << "- " << function_signature(*f_iter, true) << endl;
+    scope_up(out);
+    generate_cocoa_service_client_send_function_invocation(out, *f_iter);
+
+    out << indent() << "if (![[outProtocol transport] flush: __thriftError]) " << invalid_return_statement(*f_iter) << endl;
+    if (!(*f_iter)->is_oneway()) {
+      if ((*f_iter)->get_returntype()->is_void()) {
+        out << indent() << "if (![self recv_" << (*f_iter)->get_name() << ": __thriftError]) return NO;" << endl;
+        out << indent() << "return YES;" << endl;
+      } else {
+        out << indent() << type_name((*f_iter)->get_returntype(), false, true) << " __result;" << endl
+            << indent() << "if (![self recv_" << (*f_iter)->get_name() << ": &__result error: __thriftError]) "
+            << invalid_return_statement(*f_iter) << endl;
+        if (type_can_be_null((*f_iter)->get_returntype())) {
+          out << indent() << "return __result;" << endl;
+        } else {
+          out << indent() << "return @(__result);" << endl;
+        }
+      }
+    }
+    else {
+      out << indent() << "return YES;" << endl;
+    }
+    scope_down(out);
+    out << endl;
+  }
+
+  out << "@end" << endl << endl;
+}
+
+/**
+ * Generates a service client implementation for its asynchronous interface.
+ *
+ * @param tservice The service to generate an implementation for
+ */
+void t_cocoa_generator::generate_cocoa_service_client_async_implementation(ostream& out,
+                                                                           t_service* tservice) {
+
+  string name = cocoa_prefix_ + tservice->get_name() + "ClientAsync";
+
+  out << "@interface " << name << " () ";
+  scope_up(out);
+  out << endl;
+  out << indent() << "id<TProtocolFactory> protocolFactory;" << endl;
+  out << indent() << "id<TAsyncTransportFactory> transportFactory;" << endl;
+  out << endl;
+  scope_down(out);
+  out << endl;
+  out << "@end" << endl << endl;
+
+
+  out << "@implementation " << name << endl
+      << endl << "- (id) initWithProtocolFactory: (id <TProtocolFactory>) aProtocolFactory "
+                 "transportFactory: (id <TAsyncTransportFactory>) aTransportFactory;" << endl;
+
+  scope_up(out);
+  out << indent() << "self = [super init];" << endl;
+  out << indent() << "if (self) {" << endl;
+  out << indent() << "  protocolFactory = aProtocolFactory;" << endl;
+  out << indent() << "  transportFactory = aTransportFactory;" << endl;
+  out << indent() << "}" << endl;
+  out << indent() << "return self;" << endl;
+  scope_down(out);
+  out << 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) {
+
+    generate_cocoa_service_client_send_function_implementation(out, tservice, *f_iter, true);
+
+    if (!(*f_iter)->is_oneway()) {
+      generate_cocoa_service_client_recv_function_implementation(out, tservice, *f_iter, true);
+    }
+
+    // Open function
+    indent(out) << "- " << async_function_signature(*f_iter, false) << endl;
+    scope_up(out);
+
+    out << indent() << "NSError *thriftError;" << endl
+        << indent() << "id<TAsyncTransport> transport = [transportFactory newTransport];" << endl
+        << indent() << "id<TProtocol> protocol = [protocolFactory newProtocolOnTransport:transport];" << endl
+        << endl;
+
+    generate_cocoa_service_client_send_async_function_invocation(out, *f_iter, "failureBlock");
+
+    out << indent() << "[transport flushWithCompletion:^{" << endl;
+    indent_up();
+
+    if (!(*f_iter)->is_oneway()) {
+      out << indent() << "NSError *thriftError;" << endl;
+
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        out << indent() << type_name((*f_iter)->get_returntype()) << " result;" << endl;
+      }
+      out << indent() << "if (![self recv_" << (*f_iter)->get_name();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        out << ": &result protocol";
+      }
+      out << ": protocol error: &thriftError]) ";
+      scope_up(out);
+      out << indent() << "failureBlock(thriftError);" << endl
+          << indent() << "return;" << endl;
+      scope_down(out);
+    }
+
+    out << indent() << "responseBlock(";
+    if (!(*f_iter)->is_oneway() && !(*f_iter)->get_returntype()->is_void()) {
+      out << "result";
+    }
+    out << ");" << endl;
+
+    indent_down();
+
+    out << indent() << "} failure:failureBlock];" << endl;
+
+    scope_down(out);
+
+    out << endl;
+
+    // Promise function
+    if (promise_kit_) {
+
+      indent(out) << "- " << promise_function_signature(*f_iter) << endl;
+      scope_up(out);
+
+      out << indent() << "return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolver) {" << endl;
+      indent_up();
+
+      out << indent() << "NSError *thriftError;" << endl
+          << indent() << "id<TAsyncTransport> transport = [transportFactory newTransport];" << endl
+          << indent() << "id<TProtocol> protocol = [protocolFactory newProtocolOnTransport:transport];" << endl
+          << endl;
+
+      generate_cocoa_service_client_send_async_function_invocation(out, *f_iter, "resolver");
+
+      out << indent() << "[transport flushWithCompletion:^{" << endl;
+      indent_up();
+
+      if (!(*f_iter)->is_oneway()) {
+        out << indent() << "NSError *thriftError;" << endl;
+
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          out << indent() << type_name((*f_iter)->get_returntype()) << " result;" << endl;
+        }
+        out << indent() << "if (![self recv_" << (*f_iter)->get_name();
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          out << ": &result protocol";
+        }
+        out << ": protocol error: &thriftError]) ";
+        scope_up(out);
+        out << indent() << "resolver(thriftError);" << endl
+            << indent() << "return;" << endl;
+        scope_down(out);
+      }
+
+      out << indent() << "resolver(";
+      if ((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void()) {
+        out << "@YES";
+      } else if (type_can_be_null((*f_iter)->get_returntype())) {
+        out << "result";
+      } else {
+        out << "@(result)";
+      }
+      out << ");" << endl;
+
+      indent_down();
+
+      out << indent() << "} failure:^(NSError *error) {" << endl;
+      indent_up();
+      out << indent() << "resolver(error);" << endl;
+      indent_down();
+      out << indent() << "}];" << endl;
+
+      indent_down();
+      out << indent() << "}];" << endl;
+
+      scope_down(out);
+
+      out << endl;
+
+    }
+
+  }
+
+  out << "@end" << endl << endl;
+}
+
+/**
+ * Generates a service server implementation.  In other words the actual TProcessor implementation
+ * for the service.
+ *
+ * @param tservice The service to generate an implementation for
+ */
+void t_cocoa_generator::generate_cocoa_service_server_implementation(ostream& out,
+                                                                     t_service* tservice) {
+
+  string name = cocoa_prefix_ + tservice->get_name() + "Processor";
+
+  out << "@interface " << name << " () ";
+
+  scope_up(out);
+  out << indent() << "id <" << cocoa_prefix_ << tservice->get_name() << "> service;" << endl;
+  out << indent() << "NSDictionary * methodMap;" << endl;
+  scope_down(out);
+
+  out << "@end" << endl << endl;
+
+  out << "@implementation " << name << endl;
+
+  // initializer
+  out << endl;
+  out << "- (id) initWith" << tservice->get_name() << ": (id <" << cocoa_prefix_ << tservice->get_name() << ">) aService" << endl;
+  scope_up(out);
+  out << indent() << "self = [super init];" << endl;
+  out << indent() << "if (self) ";
+  scope_up(out);
+  out << indent() << "service = aService;" << endl;
+  out << indent() << "methodMap = [NSMutableDictionary dictionary];" << endl;
+
+  // generate method map for routing incoming calls
+  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) {
+    string funname = (*f_iter)->get_name();
+    scope_up(out);
+    out << indent() << "SEL s = @selector(process_" << funname << "_withSequenceID:inProtocol:outProtocol:error:);" << endl;
+    out << indent() << "NSMethodSignature * sig = [self methodSignatureForSelector: s];" << endl;
+    out << indent() << "NSInvocation * invocation = [NSInvocation invocationWithMethodSignature: sig];" << endl;
+    out << indent() << "[invocation setSelector: s];" << endl;
+    out << indent() << "[invocation retainArguments];" << endl;
+    out << indent() << "[methodMap setValue: invocation forKey: @\"" << funname << "\"];" << endl;
+    scope_down(out);
+  }
+  scope_down(out);
+  out << indent() << "return self;" << endl;
+  scope_down(out);
+
+  // implementation of the 'service' method which returns the service associated with this
+  // processor
+  out << endl;
+  out << indent() << "- (id<" << cocoa_prefix_ << tservice->get_name() << ">) service" << endl;
+  out << indent() << "{" << endl;
+  out << indent() << "  return service;" << endl;
+  out << indent() << "}" << endl;
+
+  // implementation of the TProcess method, which dispatches the incoming call using the method map
+  out << endl;
+  out << indent() << "- (BOOL) processOnInputProtocol: (id <TProtocol>) inProtocol" << endl;
+  out << indent() << "                 outputProtocol: (id <TProtocol>) outProtocol" << endl;
+  out << indent() << "                          error: (NSError *__autoreleasing *)__thriftError" << endl;
+  out << indent() << "{" << endl;
+  out << indent() << "  NSString * messageName;" << endl;
+  out << indent() << "  SInt32 messageType;" << endl;
+  out << indent() << "  SInt32 seqID;" << endl;
+  out << indent() << "  if (![inProtocol readMessageBeginReturningName: &messageName" << endl;
+  out << indent() << "                                       type: &messageType" << endl;
+  out << indent() << "                                 sequenceID: &seqID" << endl;
+  out << indent() << "                                      error: __thriftError]) return NO;" << endl;
+  out << indent() << "  NSInvocation * invocation = [methodMap valueForKey: messageName];" << endl;
+  out << indent() << "  if (invocation == nil) {" << endl;
+  out << indent() << "    if (![TProtocolUtil skipType: TTypeSTRUCT onProtocol: inProtocol error: __thriftError]) return NO;" << endl;
+  out << indent() << "    if (![inProtocol readMessageEnd: __thriftError]) return NO;" << endl;
+  out << indent() << "    NSError * x = [NSError errorWithDomain: TApplicationErrorDomain" << endl;
+  out << indent() << "                                      code: TApplicationErrorUnknownMethod" << endl;
+  out << indent() << "                                  userInfo: @{TApplicationErrorMethodKey: messageName}];" << endl;
+  out << indent() << "    if (![outProtocol writeMessageBeginWithName: messageName" << endl;
+  out << indent() << "                                           type: TMessageTypeEXCEPTION" << endl;
+  out << indent() << "                                     sequenceID: seqID" << endl;
+  out << indent() << "                                          error: __thriftError]) return NO;" << endl;
+  out << indent() << "    if (![x write: outProtocol error: __thriftError]) return NO;" << endl;
+  out << indent() << "    if (![outProtocol writeMessageEnd: __thriftError]) return NO;" << endl;
+  out << indent() << "    if (![[outProtocol transport] flush: __thriftError]) return NO;" << endl;
+  out << indent() << "    return YES;" << endl;
+  out << indent() << "  }" << endl;
+  out << indent() << "  // NSInvocation does not conform to NSCopying protocol" << endl;
+  out << indent() << "  NSInvocation * i = [NSInvocation invocationWithMethodSignature: "
+                     "[invocation methodSignature]];" << endl;
+  out << indent() << "  [i setSelector: [invocation selector]];" << endl;
+  out << indent() << "  [i setArgument: &seqID atIndex: 2];" << endl;
+  out << indent() << "  [i setArgument: &inProtocol atIndex: 3];" << endl;
+  out << indent() << "  [i setArgument: &outProtocol atIndex: 4];" << endl;
+  out << indent() << "  [i setArgument: &__thriftError atIndex: 5];" << endl;
+  out << indent() << "  [i setTarget: self];" << endl;
+  out << indent() << "  [i invoke];" << endl;
+  out << indent() << "  return YES;" << endl;
+  out << indent() << "}" << endl;
+
+  // generate a process_XXXX method for each service function, which reads args, calls the service,
+  // and writes results
+  functions = tservice->get_functions();
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    out << endl;
+    string funname = (*f_iter)->get_name();
+    out << indent() << "- (BOOL) process_" << funname
+        << "_withSequenceID: (SInt32) seqID inProtocol: (id<TProtocol>) inProtocol outProtocol: "
+           "(id<TProtocol>) outProtocol error:(NSError *__autoreleasing *)__thriftError" << endl;
+    scope_up(out);
+    string argstype = cocoa_prefix_ + function_args_helper_struct_type(tservice, *f_iter);
+    out << indent() << argstype << " * args = [" << argstype << " new];" << endl;
+    out << indent() << "if (![args read: inProtocol error: __thriftError]) return NO;" << endl;
+    out << indent() << "if (![inProtocol readMessageEnd: __thriftError]) return NO;" << endl;
+
+    // prepare the result if not oneway
+    if (!(*f_iter)->is_oneway()) {
+      string resulttype = cocoa_prefix_ + function_result_helper_struct_type(tservice, *f_iter);
+      out << indent() << resulttype << " * result = [" << resulttype << " new];" << endl;
+    }
+
+    // make the call to the actual service object
+    out << indent();
+    if ((*f_iter)->get_returntype()->is_void()) {
+      out << "BOOL";
+    } else if (type_can_be_null((*f_iter)->get_returntype())) {
+      out << type_name((*f_iter)->get_returntype(), false, true);
+    } else {
+      out << "NSNumber *";
+    }
+    out << " serviceResult = ";
+    if ((*f_iter)->get_returntype()->get_true_type()->is_container()) {
+      out << "(" << type_name((*f_iter)->get_returntype(), false, true) << ")";
+    }
+    out << "[service " << funname;
+    // supplying arguments
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      string fieldName = (*fld_iter)->get_name();
+      if (first) {
+        first = false;
+        out << ": [args " << fieldName << "]";
+      } else {
+        out << " " << fieldName << ": [args " << fieldName << "]";
+      }
+    }
+    if (!fields.empty()) {
+      out << " error";
+    }
+    out << ": __thriftError];" << endl;
+    out << indent() << "if (!serviceResult) return NO;" << endl;
+    if (!(*f_iter)->get_returntype()->is_void()) {
+      out << indent() << "[result setSuccess: " << unbox((*f_iter)->get_returntype(), "serviceResult") << "];" << endl;
+    }
+
+    // write out the result if not oneway
+    if (!(*f_iter)->is_oneway()) {
+      out << indent() << "if (![outProtocol writeMessageBeginWithName: @\"" << funname << "\"" << endl;
+      out << indent() << "                                       type: TMessageTypeREPLY" << endl;
+      out << indent() << "                                 sequenceID: seqID" << endl;
+      out << indent() << "                                      error: __thriftError]) return NO;" << endl;
+      out << indent() << "if (![result write: outProtocol error: __thriftError]) return NO;" << endl;
+      out << indent() << "if (![outProtocol writeMessageEnd: __thriftError]) return NO;" << endl;
+      out << indent() << "if (![[outProtocol transport] flush: __thriftError]) return NO;" << endl;
+    }
+    out << indent() << "return YES;" << endl;
+
+    scope_down(out);
+  }
+
+  out << "@end" << endl << endl;
+}
+
+/**
+ * Deserializes a field of any type.
+ *
+ * @param tfield The field
+ * @param fieldName The variable name for this field
+ */
+void t_cocoa_generator::generate_deserialize_field(ostream& out,
+                                                   t_field* tfield,
+                                                   string fieldName) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, fieldName);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, fieldName);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) << type_name(type) << " " << fieldName << ";" << endl;
+    indent(out) << "if (![inProtocol ";
+
+    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: " + tfield->get_name();
+        break;
+      case t_base_type::TYPE_STRING:
+        if (type->is_binary()) {
+          out << "readBinary:&" << fieldName << " error: __thriftError]";
+        } else {
+          out << "readString:&" << fieldName << " error: __thriftError]";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "readBool:&" << fieldName << " error: __thriftError]";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "readByte:(UInt8 *)&" << fieldName << " error: __thriftError]";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "readI16:&" << fieldName << " error: __thriftError]";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "readI32:&" << fieldName << " error: __thriftError]";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "readI64:&" << fieldName << " error: __thriftError]";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "readDouble:&" << fieldName << " error: __thriftError]";
+        break;
+      default:
+        throw "compiler error: no Objective-C name for base type "
+            + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "readI32:&" << fieldName << " error: __thriftError]";
+    }
+    out << ") return NO;" << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a struct, allocates the struct and invokes read:
+ */
+void t_cocoa_generator::generate_deserialize_struct(ostream& out,
+                                                    t_struct* tstruct,
+                                                    string fieldName) {
+  indent(out) << type_name(tstruct) << fieldName << " = [[" << type_name(tstruct, true)
+              << " alloc] init];" << endl;
+  indent(out) << "if (![" << fieldName << " read: inProtocol error: __thriftError]) return NO;" << endl;
+}
+
+/**
+ * Deserializes a container by reading its size and then iterating
+ */
+void t_cocoa_generator::generate_deserialize_container(ostream& out,
+                                                       t_type* ttype,
+                                                       string fieldName) {
+  string size = tmp("_size");
+  indent(out) << "SInt32 " << size << ";" << endl;
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    indent(out) << "if (![inProtocol readMapBeginReturningKeyType: NULL valueType: NULL size: &" << size << " error: __thriftError]) return NO;" << endl;
+    indent(out) << "NSMutableDictionary * " << fieldName
+                << " = [[NSMutableDictionary alloc] initWithCapacity: " << size << "];" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "if (![inProtocol readSetBeginReturningElementType: NULL size: &" << size << " error: __thriftError]) return NO;"
+                << endl;
+    indent(out) << "NSMutableSet * " << fieldName
+                << " = [[NSMutableSet alloc] initWithCapacity: " << size << "];" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "if (![inProtocol readListBeginReturningElementType: NULL size: &" << size << " error: __thriftError]) return NO;"
+                << endl;
+    indent(out) << "NSMutableArray * " << fieldName
+                << " = [[NSMutableArray alloc] initWithCapacity: " << size << "];" << endl;
+  }
+  // FIXME - the code above does not verify that the element types of
+  // the containers being read match the element types of the
+  // containers we are reading into.  Does that matter?
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) << "int " << i << ";" << endl << indent() << "for (" << i << " = 0; " << i << " < "
+              << size << "; "
+              << "++" << i << ")" << endl;
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, fieldName);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, fieldName);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, fieldName);
+  }
+
+  scope_down(out);
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "if (![inProtocol readMapEnd: __thriftError]) return NO;" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "if (![inProtocol readSetEnd: __thriftError]) return NO;" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "if (![inProtocol readListEnd: __thriftError]) return NO;" << endl;
+  }
+}
+
+/**
+ * Take a variable of a given type and wrap it in code to make it
+ * suitable for putting into a container, if necessary.  Basically,
+ * wrap scaler primitives in NSNumber objects.
+ */
+string t_cocoa_generator::box(t_type* ttype, string field_name) {
+
+  ttype = get_true_type(ttype);
+  if (ttype->is_enum()) {
+    return "@(" + field_name + ")";
+  } else if (ttype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+    switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "can't box void";
+      case t_base_type::TYPE_BOOL:
+      case t_base_type::TYPE_I8:
+      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 "@(" + field_name + ")";
+      default:
+        break;
+    }
+  }
+
+  // do nothing
+  return field_name;
+}
+
+/**
+ * Extracts the actual value from a boxed value
+ */
+string t_cocoa_generator::unbox(t_type* ttype, string field_name) {
+  ttype = get_true_type(ttype);
+  if (ttype->is_enum()) {
+    return "[" + field_name + " intValue]";
+  } else if (ttype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+    switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "can't unbox void";
+      case t_base_type::TYPE_BOOL:
+        return "[" + field_name + " boolValue]";
+      case t_base_type::TYPE_I8:
+        return "((SInt8)[" + field_name + " charValue])";
+      case t_base_type::TYPE_I16:
+        return "((SInt16)[" + field_name + " shortValue])";
+      case t_base_type::TYPE_I32:
+        return "((SInt32)[" + field_name + " longValue])";
+      case t_base_type::TYPE_I64:
+        return "((SInt64)[" + field_name + " longLongValue])";
+      case t_base_type::TYPE_DOUBLE:
+        return "[" + field_name + " doubleValue]";
+      default:
+        break;
+    }
+  }
+
+  // do nothing
+  return field_name;
+}
+
+/**
+ * Generates code to deserialize a map element
+ */
+void t_cocoa_generator::generate_deserialize_map_element(ostream& out,
+                                                         t_map* tmap,
+                                                         string fieldName) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_type* keyType = tmap->get_key_type();
+  t_type* valType = tmap->get_val_type();
+  t_field fkey(keyType, key);
+  t_field fval(valType, val);
+
+  generate_deserialize_field(out, &fkey, key);
+  generate_deserialize_field(out, &fval, val);
+
+  indent(out) << "[" << fieldName << " setObject: " << box(valType, val)
+              << " forKey: " << box(keyType, key) << "];" << endl;
+}
+
+/**
+ * Deserializes a set element
+ */
+void t_cocoa_generator::generate_deserialize_set_element(ostream& out,
+                                                         t_set* tset,
+                                                         string fieldName) {
+  string elem = tmp("_elem");
+  t_type* type = tset->get_elem_type();
+  t_field felem(type, elem);
+
+  generate_deserialize_field(out, &felem, elem);
+
+  indent(out) << "[" << fieldName << " addObject: " << box(type, elem) << "];" << endl;
+}
+
+/**
+ * Deserializes a list element
+ */
+void t_cocoa_generator::generate_deserialize_list_element(ostream& out,
+                                                          t_list* tlist,
+                                                          string fieldName) {
+  string elem = tmp("_elem");
+  t_type* type = tlist->get_elem_type();
+  t_field felem(type, elem);
+
+  generate_deserialize_field(out, &felem, elem);
+
+  indent(out) << "[" << fieldName << " addObject: " << box(type, elem) << "];" << endl;
+}
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param fieldName Name to of the variable holding the field
+ */
+void t_cocoa_generator::generate_serialize_field(ostream& out, t_field* tfield, string fieldName) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, fieldName);
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, fieldName);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) << "if (![outProtocol ";
+
+    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: " + fieldName;
+        break;
+      case t_base_type::TYPE_STRING:
+        if (type->is_binary()) {
+          out << "writeBinary: " << fieldName << " error: __thriftError]";
+        } else {
+          out << "writeString: " << fieldName << " error: __thriftError]";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool: " << fieldName << " error: __thriftError]";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "writeByte: (UInt8)" << fieldName << " error: __thriftError]";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16: " << fieldName << " error: __thriftError]";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32: " << fieldName << " error: __thriftError]";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64: " << fieldName << " error: __thriftError]";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble: " << fieldName << " error: __thriftError]";
+        break;
+      default:
+        throw "compiler error: no Objective-C name for base type "
+            + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32: " << fieldName << " error: __thriftError]";
+    }
+    out << ") return NO;" << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Serialize a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param fieldName Name of variable holding struct
+ */
+void t_cocoa_generator::generate_serialize_struct(ostream& out,
+                                                  t_struct* tstruct,
+                                                  string fieldName) {
+  (void)tstruct;
+  out << indent() << "if (![" << fieldName << " write: outProtocol error: __thriftError]) return NO;" << endl;
+}
+
+/**
+ * Serializes a container by writing its size then the elements.
+ *
+ * @param ttype  The type of container
+ * @param fieldName Name of variable holding container
+ */
+void t_cocoa_generator::generate_serialize_container(ostream& out,
+                                                     t_type* ttype,
+                                                     string fieldName) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "if (![outProtocol writeMapBeginWithKeyType: "
+                << type_to_enum(((t_map*)ttype)->get_key_type())
+                << " valueType: " << type_to_enum(((t_map*)ttype)->get_val_type()) << " size: (SInt32)["
+                << fieldName << " count] error: __thriftError]) return NO;" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "if (![outProtocol writeSetBeginWithElementType: "
+                << type_to_enum(((t_set*)ttype)->get_elem_type()) << " size: (SInt32)[" << fieldName
+                << " count] error: __thriftError]) return NO;" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "if (![outProtocol writeListBeginWithElementType: "
+                << type_to_enum(((t_list*)ttype)->get_elem_type()) << " size: (SInt32)[" << fieldName
+                << " count] error: __thriftError]) return NO;" << endl;
+  }
+
+  string iter = tmp("_iter");
+  string key;
+  if (ttype->is_map()) {
+    key = tmp("key");
+    indent(out) << "NSEnumerator * " << iter << " = [" << fieldName << " keyEnumerator];" << endl;
+    indent(out) << "id " << key << ";" << endl;
+    indent(out) << "while ((" << key << " = [" << iter << " nextObject]))" << endl;
+  } else if (ttype->is_set()) {
+    key = tmp("obj");
+    indent(out) << "NSEnumerator * " << iter << " = [" << fieldName << " objectEnumerator];"
+                << endl;
+    indent(out) << "id " << key << ";" << endl;
+    indent(out) << "while ((" << key << " = [" << iter << " nextObject]))" << endl;
+  } else if (ttype->is_list()) {
+    key = tmp("idx");
+    indent(out) << "int " << key << ";" << endl;
+    indent(out) << "for (" << key << " = 0; " << key << " < [" << fieldName << " count]; " << key
+                << "++)" << endl;
+  }
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_serialize_map_element(out, (t_map*)ttype, key, fieldName);
+  } else if (ttype->is_set()) {
+    generate_serialize_set_element(out, (t_set*)ttype, key);
+  } else if (ttype->is_list()) {
+    generate_serialize_list_element(out, (t_list*)ttype, key, fieldName);
+  }
+
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "if (![outProtocol writeMapEnd: __thriftError]) return NO;" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "if (![outProtocol writeSetEnd: __thriftError]) return NO;" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "if (![outProtocol writeListEnd: __thriftError]) return NO;" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ */
+void t_cocoa_generator::generate_serialize_map_element(ostream& out,
+                                                       t_map* tmap,
+                                                       string key,
+                                                       string mapName) {
+  t_field kfield(tmap->get_key_type(), key);
+  generate_serialize_field(out, &kfield, unbox(kfield.get_type(), key));
+  t_field vfield(tmap->get_val_type(), "[" + mapName + " objectForKey: " + key + "]");
+  generate_serialize_field(out, &vfield, unbox(vfield.get_type(), vfield.get_name()));
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_cocoa_generator::generate_serialize_set_element(ostream& out,
+                                                       t_set* tset,
+                                                       string elementName) {
+  t_field efield(tset->get_elem_type(), elementName);
+  generate_serialize_field(out, &efield, unbox(efield.get_type(), elementName));
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_cocoa_generator::generate_serialize_list_element(ostream& out,
+                                                        t_list* tlist,
+                                                        string index,
+                                                        string listName) {
+  t_field efield(tlist->get_elem_type(), "[" + listName + " objectAtIndex: " + index + "]");
+  generate_serialize_field(out, &efield, unbox(efield.get_type(), efield.get_name()));
+}
+
+/**
+ * Returns an Objective-C name
+ *
+ * @param ttype The type
+ * @param class_ref Do we want a Class reference istead of a type reference?
+ * @return Objective-C type name, i.e. NSDictionary<Key,Value> *
+ */
+string t_cocoa_generator::type_name(t_type* ttype, bool class_ref, bool needs_mutable) {
+  if (ttype->is_typedef()) {
+    string name = (needs_mutable && ttype->get_true_type()->is_container()) ? "Mutable" + ttype->get_name() : ttype->get_name();
+    t_program* program = ttype->get_program();
+    return program ? (program->get_namespace("cocoa") + name) : name;
+  }
+
+  string result;
+  if (ttype->is_base_type()) {
+    return base_type_name((t_base_type*)ttype);
+  } else if (ttype->is_enum()) {
+    return cocoa_prefix_ + ttype->get_name();
+  } else if (ttype->is_map()) {
+    t_map *map = (t_map *)ttype;
+    result = needs_mutable ? "NSMutableDictionary" : "NSDictionary";
+    result += "<" + element_type_name(map->get_key_type()) + ", " + element_type_name(map->get_val_type()) + ">";
+  } else if (ttype->is_set()) {
+    t_set *set = (t_set *)ttype;
+    result = needs_mutable ? "NSMutableSet" : "NSSet";
+    result += "<" + element_type_name(set->get_elem_type()) + ">";
+  } else if (ttype->is_list()) {
+    t_list *list = (t_list *)ttype;
+    result = needs_mutable ? "NSMutableArray" : "NSArray";
+    result += "<" + element_type_name(list->get_elem_type()) + ">";
+  } else {
+    // Check for prefix
+    t_program* program = ttype->get_program();
+    if (program != NULL) {
+      result = program->get_namespace("cocoa") + ttype->get_name();
+    } else {
+      result = ttype->get_name();
+    }
+  }
+
+  if (!class_ref) {
+    result += " *";
+  }
+  return result;
+}
+
+/**
+ * Returns an Objective-C type name for container types
+ *
+ * @param ttype the type
+ */
+string t_cocoa_generator::element_type_name(t_type* etype) {
+
+  t_type* ttype = etype->get_true_type();
+
+  if (etype->is_typedef() && type_can_be_null(ttype)) {
+    return type_name(etype);
+  }
+
+  string result;
+  if (ttype->is_base_type()) {
+    t_base_type* tbase = (t_base_type*)ttype;
+    switch (tbase->get_base()) {
+    case t_base_type::TYPE_STRING:
+      if (tbase->is_binary()) {
+        result = "NSData *";
+      }
+      else {
+        result = "NSString *";
+      }
+      break;
+    default:
+      result = "NSNumber *";
+      break;
+    }
+  } else if (ttype->is_enum()) {
+      result = "NSNumber *";
+  } else if (ttype->is_map()) {
+    t_map *map = (t_map *)ttype;
+    result = "NSDictionary<" + element_type_name(map->get_key_type()) + ", " + element_type_name(map->get_val_type()) + "> *";
+  } else if (ttype->is_set()) {
+    t_set *set = (t_set *)ttype;
+    result = "NSSet<" + element_type_name(set->get_elem_type()) + "> *";
+  } else if (ttype->is_list()) {
+    t_list *list = (t_list *)ttype;
+    result = "NSArray<" + element_type_name(list->get_elem_type()) + "> *";
+  } else if (ttype->is_struct() || ttype->is_xception()) {
+    result = cocoa_prefix_ + ttype->get_name() + " *";
+  }
+
+  return result;
+}
+
+/**
+ * Returns the Objective-C type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ */
+string t_cocoa_generator::base_type_name(t_base_type* type) {
+  t_base_type::t_base tbase = type->get_base();
+
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    if (type->is_binary()) {
+      return "NSData *";
+    } else {
+      return "NSString *";
+    }
+  case t_base_type::TYPE_BOOL:
+    return "BOOL";
+  case t_base_type::TYPE_I8:
+    return "SInt8";
+  case t_base_type::TYPE_I16:
+    return "SInt16";
+  case t_base_type::TYPE_I32:
+    return "SInt32";
+  case t_base_type::TYPE_I64:
+    return "SInt64";
+  case t_base_type::TYPE_DOUBLE:
+    return "double";
+  default:
+    throw "compiler error: no Objective-C name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+/**
+ * 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
+ */
+void t_cocoa_generator::print_const_value(ostream& out,
+                                          string name,
+                                          t_type* type,
+                                          t_const_value* value,
+                                          bool defval) {
+  type = get_true_type(type);
+
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, type, value);
+    indent(out);
+    if (defval)
+      out << type_name(type) << " ";
+    out << name << " = " << v2 << ";" << endl << endl;
+  } else if (type->is_enum()) {
+    indent(out);
+    if (defval)
+      out << type_name(type) << " ";
+    out << name << " = " << render_const_value(out, type, value) << ";" << endl << endl;
+  } else if (type->is_struct() || type->is_xception()) {
+    indent(out);
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    if (defval)
+      out << type_name(type) << " ";
+    out << name << " = [" << type_name(type, true) << " new];"
+        << endl;
+    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();
+      }
+      string val = render_const_value(out, field_type, v_iter->second);
+      std::string cap_name = capitalize(v_iter->first->get_string());
+      indent(out) << "[" << name << " set" << cap_name << ":" << val << "];" << endl;
+    }
+  } else if (type->is_map()) {
+    ostringstream mapout;
+    indent(mapout);
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    if (defval)
+      mapout << type_name(type) << " ";
+    mapout << name << " = @{";
+    for (v_iter = val.begin(); v_iter != val.end();) {
+      mapout << render_const_value(out, ktype, v_iter->first, true) << ": "
+          << render_const_value(out, vtype, v_iter->second, true);
+      if (++v_iter != val.end()) {
+        mapout << ", ";
+      }
+    }
+    mapout << "}";
+    out << mapout.str();
+  } else if (type->is_list()) {
+    ostringstream listout;
+    indent(listout);
+    t_type* etype = ((t_list*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    if (defval)
+      listout << type_name(type) << " ";
+    listout << name << " = @[";
+    for (v_iter = val.begin(); v_iter != val.end();) {
+      listout << render_const_value(out, etype, *v_iter, true);
+      if (++v_iter != val.end()) {
+        listout << ", ";
+      }
+    }
+    listout << "]";
+    out << listout.str();
+  } else if (type->is_set()) {
+    ostringstream setout;
+    indent(setout);
+    t_type* etype = ((t_set*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    if (defval)
+      setout << type_name(type) << " ";
+    setout << name << " = [NSSet setWithArray:@[";
+    for (v_iter = val.begin(); v_iter != val.end();) {
+      setout << render_const_value(out, etype, *v_iter, true);
+      if (++v_iter != val.end()) {
+        setout << ", ";
+      }
+    }
+    setout << "]]";
+    out << setout.str();
+  } else {
+    throw "compiler error: no const of type " + type->get_name();
+  }
+}
+
+string t_cocoa_generator::render_const_value(ostream& out,
+                                             t_type* type,
+                                             t_const_value* value,
+                                             bool box_it) {
+  type = get_true_type(type);
+  std::ostringstream render;
+
+  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:
+      // We must handle binary constant but the syntax of IDL defines
+      // nothing about binary constant.
+      //   if type->is_binary())
+      //      // binary code
+      render << "@\"" << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "YES" : "NO");
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << value->get_integer();
+      } else {
+        render << 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()) {
+    render << value->get_integer();
+  } else {
+    string t = tmp("tmp");
+    print_const_value(out, t, type, value, true);
+    out << ";" << endl;
+    render << t;
+  }
+
+  if (box_it) {
+    return box(type, render.str());
+  }
+  return render.str();
+}
+
+#if 0
+/**
+ORIGINAL
+ * Spit out code that evaluates to the specified constant value.
+ */
+string t_cocoa_generator::render_const_value(string name,
+                                             t_type* type,
+                                             t_const_value* value,
+                                             bool box_it) {
+  type = get_true_type(type);
+  std::ostringstream render;
+
+  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:
+      render << "@\"" << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "YES" : "NO");
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << value->get_integer();
+      } else {
+        render << 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()) {
+    render << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    if (val.size() > 0)
+      render << "[[" << type_name(type, true) << " alloc] initWith";
+    else
+      render << "[[" << type_name(type, true) << " alloc] init";
+    bool first = true;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      // FIXME The generated code does not match with initWithXXX
+      //       initializer and causes compile error.
+      //       Try: test/DebugProtoTest.thrift and test/SmallTest.thrift
+      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 (first) {
+        render << capitalize(v_iter->first->get_string());
+        first = false;
+      } else {
+        render << " " << v_iter->first->get_string();
+      }
+      render << ": " << render_const_value(name, field_type, v_iter->second);
+    }
+    render << "]";
+  } else if (type->is_map()) {
+    render << "[[NSDictionary alloc] initWithObjectsAndKeys: ";
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    bool first = true;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(name, ktype, v_iter->first, true);
+      string val = render_const_value(name, vtype, v_iter->second, true);
+      if (first) {
+        first = false;
+      } else {
+        render << ", ";
+      }
+      render << val << ", " << key;
+    }
+    if (first)
+      render << " nil]";
+    else
+      render << ", nil]";
+  } else if (type->is_list()) {
+    render << "[[NSArray alloc] initWithObjects: ";
+    t_type * etype = ((t_list*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    bool first = true;
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      if (first) {
+        first = false;
+      } else {
+        render << ", ";
+      }
+      render << render_const_value(name, etype, *v_iter, true);
+    }
+    if (first)
+      render << " nil]";
+    else
+      render << ", nil]";
+  } else if (type->is_set()) {
+    render << "[[NSSet alloc] initWithObjects: ";
+    t_type * etype = ((t_set*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    bool first = true;
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      if (first) {
+        first = false;
+      } else {
+        render << ", ";
+      }
+      render << render_const_value(name, etype, *v_iter, true);
+    }
+    if (first)
+      render << " nil]";
+    else
+      render << ", nil]";
+  } else {
+    throw "don't know how to render constant for type: " + type->get_name();
+  }
+
+  if (box_it) {
+    return box(type, render.str());
+  }
+
+  return render.str();
+}
+#endif
+
+/**
+ * Declares an Objective-C 2.0 property.
+ *
+ * @param tfield The field to declare a property for
+ */
+string t_cocoa_generator::declare_property(t_field* tfield) {
+  std::ostringstream render;
+  render << "@property (";
+
+  if (type_can_be_copy(tfield->get_type())) {
+    render << "copy, ";
+  } else if (type_can_be_null(tfield->get_type())) {
+    render << "strong, ";
+  } else {
+    render << "assign, ";
+  }
+
+  render << "nonatomic) " << type_name(tfield->get_type(), false, true) << " "
+  << tfield->get_name() << ";";
+
+  // Check if the property name is an Objective-C return +1 count signal
+  if ((tfield->get_name().length() >= 3 && tfield->get_name().substr(0,3) == "new") ||
+      (tfield->get_name().length() >= 6 && tfield->get_name().substr(0,6) == "create") ||
+      (tfield->get_name().length() >= 5 && tfield->get_name().substr(0,5) == "alloc")) {
+    // Let Objective-C know not to return +1 for object pointers
+    if (type_can_be_null(tfield->get_type())) {
+      render << endl;
+      render << "- (" + type_name(tfield->get_type()) + ") " + decapitalize(tfield->get_name()) + " __attribute__((objc_method_family(none)));";
+    }
+  }
+
+  return render.str();
+}
+
+/**
+ * Declares an Objective-C 2.0 property.
+ *
+ * @param tfield The field to declare a property for
+ */
+string t_cocoa_generator::declare_property_isset(t_field* tfield) {
+  return "@property (assign, nonatomic) BOOL " + decapitalize(tfield->get_name()) + "IsSet;";
+}
+
+/**
+ * Declares property unset method.
+ *
+ * @param tfield The field to declare a property for
+ */
+string t_cocoa_generator::declare_property_unset(t_field* tfield) {
+  return "- (void) unset" + capitalize(tfield->get_name()) + ";";
+}
+
+/**
+ * Renders the early out return statement
+ *
+ * @param tfunction Function definition
+ * @return String of rendered invalid return statment
+ */
+string t_cocoa_generator::invalid_return_statement(t_function *tfunction) {
+  if ((tfunction->get_returntype()->is_void())) {
+    return "return NO;";
+  }
+  return "return nil;";
+}
+
+/**
+ * Renders a function signature
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_cocoa_generator::function_signature(t_function* tfunction, bool include_error) {
+  t_type* ttype = tfunction->get_returntype();
+  string result;
+  if (ttype->is_void()) {
+    result = "(BOOL)";
+  }
+  else if (type_can_be_null(ttype)) {
+    result = "(" + type_name(ttype) + ")";
+  }
+  else {
+    result = "(NSNumber *)";
+  }
+  result += " " + tfunction->get_name() + argument_list(tfunction->get_arglist(), "", include_error);
+  return result;
+}
+
+/**
+ * Renders a function signature that returns asynchronously instead of
+ * literally returning.
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_cocoa_generator::async_function_signature(t_function* tfunction, bool include_error) {
+  t_type* ttype = tfunction->get_returntype();
+  t_struct* targlist = tfunction->get_arglist();
+  string response_param = "void (^)(" + ((ttype->is_void()) ? "" : type_name(ttype)) + ")";
+  std::string result = "(void) " + tfunction->get_name() + argument_list(tfunction->get_arglist(), "", include_error)
+  + (targlist->get_members().size() ? " response" : "") + ": ("
+  + response_param + ") responseBlock "
+  + "failure : (TAsyncFailureBlock) failureBlock";
+  return result;
+}
+
+/**
+ * Renders a function signature that returns a promise instead of
+ * literally returning.
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_cocoa_generator::promise_function_signature(t_function* tfunction) {
+  return "(AnyPromise *) " + tfunction->get_name() + argument_list(tfunction->get_arglist(), "", false);
+}
+
+/**
+ * Renders a colon separated list of types and names, suitable for an
+ * objective-c parameter list
+ */
+string t_cocoa_generator::argument_list(t_struct* tstruct, string protocol_name, bool include_error) {
+  string result = "";
+  bool include_protocol = !protocol_name.empty();
+
+  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) {
+    string argPrefix = "";
+    if (first) {
+      first = false;
+    } else {
+      argPrefix = (*f_iter)->get_name();
+      result += " ";
+    }
+    result += argPrefix + ": (" + type_name((*f_iter)->get_type()) + ") " + (*f_iter)->get_name();
+  }
+  if (include_protocol) {
+    if (!first) {
+      result += " protocol";
+    }
+    result += ": (id<TProtocol>) " + protocol_name;
+    first = false;
+  }
+  if (include_error) {
+    if (!first) {
+      result += " error";
+    }
+    result += ": (NSError *__autoreleasing *)__thriftError";
+    first = false;
+  }
+  return result;
+}
+
+/**
+ * Converts the parse type to an Objective-C enum string for the given type.
+ */
+string t_cocoa_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 "TTypeSTRING";
+    case t_base_type::TYPE_BOOL:
+      return "TTypeBOOL";
+    case t_base_type::TYPE_I8:
+      return "TTypeBYTE";
+    case t_base_type::TYPE_I16:
+      return "TTypeI16";
+    case t_base_type::TYPE_I32:
+      return "TTypeI32";
+    case t_base_type::TYPE_I64:
+      return "TTypeI64";
+    case t_base_type::TYPE_DOUBLE:
+      return "TTypeDOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "TTypeI32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TTypeSTRUCT";
+  } else if (type->is_map()) {
+    return "TTypeMAP";
+  } else if (type->is_set()) {
+    return "TTypeSET";
+  } else if (type->is_list()) {
+    return "TTypeLIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Returns a format string specifier for the supplied parse type.
+ */
+string t_cocoa_generator::format_string_for_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 "NO T_VOID CONSTRUCT";
+    case t_base_type::TYPE_STRING:
+      return "\\\"%@\\\"";
+    case t_base_type::TYPE_BOOL:
+      return "%i";
+    case t_base_type::TYPE_I8:
+      return "%i";
+    case t_base_type::TYPE_I16:
+      return "%hi";
+    case t_base_type::TYPE_I32:
+      return "%i";
+    case t_base_type::TYPE_I64:
+      return "%qi";
+    case t_base_type::TYPE_DOUBLE:
+      return "%f";
+    }
+  } else if (type->is_enum()) {
+    return "%i";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "%@";
+  } else if (type->is_map()) {
+    return "%@";
+  } else if (type->is_set()) {
+    return "%@";
+  } else if (type->is_list()) {
+    return "%@";
+  }
+
+  throw "INVALID TYPE IN format_string_for_type: " + type->get_name();
+}
+
+/**
+ * Returns a format cast for the supplied parse type.
+ */
+string t_cocoa_generator::format_cast_for_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 "NO T_VOID CONSTRUCT";
+    case t_base_type::TYPE_STRING:
+      return ""; // "\\\"%@\\\"";
+    case t_base_type::TYPE_BOOL:
+      return ""; // "%i";
+    case t_base_type::TYPE_I8:
+      return ""; // "%i";
+    case t_base_type::TYPE_I16:
+      return ""; // "%hi";
+    case t_base_type::TYPE_I32:
+      return "(int)"; // "%i";
+    case t_base_type::TYPE_I64:
+      return ""; // "%qi";
+    case t_base_type::TYPE_DOUBLE:
+      return ""; // "%f";
+    }
+  } else if (type->is_enum()) {
+    return "(int)"; // "%i";
+  } else if (type->is_struct() || type->is_xception()) {
+    return ""; // "%@";
+  } else if (type->is_map()) {
+    return ""; // "%@";
+  } else if (type->is_set()) {
+    return ""; // "%@";
+  } else if (type->is_list()) {
+    return ""; // "%@";
+  }
+
+  throw "INVALID TYPE IN format_cast_for_type: " + type->get_name();
+}
+
+/**
+ * Generate a call to a field's setter.
+ *
+ * @param tfield Field the setter is being called on
+ * @param fieldName Name of variable to pass to setter
+ */
+
+string t_cocoa_generator::call_field_setter(t_field* tfield, string fieldName) {
+  return "self." + tfield->get_name() + " = " + fieldName + ";";
+}
+
+THRIFT_REGISTER_GENERATOR(
+    cocoa,
+    "Cocoa",
+    "    log_unexpected:  Log every time an unexpected field ID or type is encountered.\n"
+    "    debug_descriptions:\n"
+    "                     Allow use of debugDescription so the app can add description via a cateogory/extension\n"
+    "    validate_required:\n"
+    "                     Throws exception if any required field is not set.\n"
+    "    async_clients:   Generate clients which invoke asynchronously via block syntax.\n"
+    "    pods:            Generate imports in Cocopods framework format.\n"
+    "    promise_kit:     Generate clients which invoke asynchronously via promises.\n")
diff --git a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
new file mode 100644
index 0000000..cf30363
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
@@ -0,0 +1,4491 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+#include <cassert>
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <limits>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <sys/stat.h>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ofstream;
+using std::ostream;
+using std::string;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * C++ code generator. This is legitimacy incarnate.
+ *
+ */
+class t_cpp_generator : public t_oop_generator {
+public:
+  t_cpp_generator(t_program* program,
+                  const std::map<std::string, std::string>& parsed_options,
+                  const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+
+    gen_pure_enums_ = false;
+    use_include_prefix_ = false;
+    gen_cob_style_ = false;
+    gen_no_client_completion_ = false;
+    gen_no_default_operators_ = false;
+    gen_templates_ = false;
+    gen_templates_only_ = false;
+    gen_moveable_ = false;
+    gen_no_ostream_operators_ = false;
+    gen_no_skeleton_ = false;
+
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("pure_enums") == 0) {
+        gen_pure_enums_ = true;
+      } else if( iter->first.compare("include_prefix") == 0) {
+        use_include_prefix_ = true;
+      } else if( iter->first.compare("cob_style") == 0) {
+        gen_cob_style_ = true;
+      } else if( iter->first.compare("no_client_completion") == 0) {
+        gen_no_client_completion_ = true;
+      } else if( iter->first.compare("no_default_operators") == 0) {
+        gen_no_default_operators_ = true;
+      } else if( iter->first.compare("templates") == 0) {
+        gen_templates_ = true;
+        gen_templates_only_ = (iter->second == "only");
+      } else if( iter->first.compare("moveable_types") == 0) {
+        gen_moveable_ = true;
+      } else if ( iter->first.compare("no_ostream_operators") == 0) {
+        gen_no_ostream_operators_ = true;
+      } else if ( iter->first.compare("no_skeleton") == 0) {
+        gen_no_skeleton_ = true;
+      } else {
+        throw "unknown option cpp:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-cpp";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  void generate_consts(std::vector<t_const*> consts);
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_enum_ostream_operator_decl(std::ostream& out, t_enum* tenum);
+  void generate_enum_ostream_operator(std::ostream& out, t_enum* tenum);
+  void generate_forward_declaration(t_struct* tstruct);
+  void generate_struct(t_struct* tstruct) { generate_cpp_struct(tstruct, false); }
+  void generate_xception(t_struct* txception) { generate_cpp_struct(txception, true); }
+  void generate_cpp_struct(t_struct* tstruct, bool is_exception);
+
+  void generate_service(t_service* tservice);
+
+  void print_const_value(std::ostream& out, std::string name, t_type* type, t_const_value* value);
+  std::string render_const_value(std::ostream& out,
+                                 std::string name,
+                                 t_type* type,
+                                 t_const_value* value);
+
+  void generate_struct_declaration(std::ostream& out,
+                                   t_struct* tstruct,
+                                   bool is_exception = false,
+                                   bool pointers = false,
+                                   bool read = true,
+                                   bool write = true,
+                                   bool swap = false,
+                                   bool is_user_struct = false);
+  void generate_struct_definition(std::ostream& out,
+                                  std::ostream& force_cpp_out,
+                                  t_struct* tstruct,
+                                  bool setters = true,
+                                  bool is_user_struct = false);
+  void generate_copy_constructor(std::ostream& out, t_struct* tstruct, bool is_exception);
+  void generate_move_constructor(std::ostream& out, t_struct* tstruct, bool is_exception);
+  void generate_constructor_helper(std::ostream& out,
+                                   t_struct* tstruct,
+                                   bool is_excpetion,
+                                   bool is_move);
+  void generate_assignment_operator(std::ostream& out, t_struct* tstruct);
+  void generate_move_assignment_operator(std::ostream& out, t_struct* tstruct);
+  void generate_assignment_helper(std::ostream& out, t_struct* tstruct, bool is_move);
+  void generate_struct_reader(std::ostream& out, t_struct* tstruct, bool pointers = false);
+  void generate_struct_writer(std::ostream& out, t_struct* tstruct, bool pointers = false);
+  void generate_struct_result_writer(std::ostream& out, t_struct* tstruct, bool pointers = false);
+  void generate_struct_swap(std::ostream& out, t_struct* tstruct);
+  void generate_struct_print_method(std::ostream& out, t_struct* tstruct);
+  void generate_exception_what_method(std::ostream& out, t_struct* tstruct);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_service_interface(t_service* tservice, string style);
+  void generate_service_interface_factory(t_service* tservice, string style);
+  void generate_service_null(t_service* tservice, string style);
+  void generate_service_multiface(t_service* tservice);
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_client(t_service* tservice, string style);
+  void generate_service_processor(t_service* tservice, string style);
+  void generate_service_skeleton(t_service* tservice);
+  void generate_process_function(t_service* tservice,
+                                 t_function* tfunction,
+                                 string style,
+                                 bool specialized = false);
+  void generate_function_helpers(t_service* tservice, t_function* tfunction);
+  void generate_service_async_skeleton(t_service* tservice);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field(std::ostream& out,
+                                  t_field* tfield,
+                                  std::string prefix = "",
+                                  std::string suffix = "");
+
+  void generate_deserialize_struct(std::ostream& out,
+                                   t_struct* tstruct,
+                                   std::string prefix = "",
+                                   bool pointer = false);
+
+  void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+
+  void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         std::string prefix,
+                                         bool push_back,
+                                         std::string index);
+
+  void generate_serialize_field(std::ostream& out,
+                                t_field* tfield,
+                                std::string prefix = "",
+                                std::string suffix = "");
+
+  void generate_serialize_struct(std::ostream& out,
+                                 t_struct* tstruct,
+                                 std::string prefix = "",
+                                 bool pointer = false);
+
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_serialize_map_element(std::ostream& out, t_map* tmap, std::string iter);
+
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  void generate_function_call(ostream& out,
+                              t_function* tfunction,
+                              string target,
+                              string iface,
+                              string arg_prefix);
+  /*
+   * Helper rendering functions
+   */
+
+  std::string namespace_prefix(std::string ns);
+  std::string namespace_open(std::string ns);
+  std::string namespace_close(std::string ns);
+  std::string type_name(t_type* ttype, bool in_typedef = false, bool arg = false);
+  std::string base_type_name(t_base_type::t_base tbase);
+  std::string declare_field(t_field* tfield,
+                            bool init = false,
+                            bool pointer = false,
+                            bool constant = false,
+                            bool reference = false);
+  std::string function_signature(t_function* tfunction,
+                                 std::string style,
+                                 std::string prefix = "",
+                                 bool name_params = true);
+  std::string cob_function_signature(t_function* tfunction,
+                                     std::string prefix = "",
+                                     bool name_params = true);
+  std::string argument_list(t_struct* tstruct, bool name_params = true, bool start_comma = false);
+  std::string type_to_enum(t_type* ttype);
+
+  void generate_enum_constant_list(std::ostream& f,
+                                   const vector<t_enum_value*>& constants,
+                                   const char* prefix,
+                                   const char* suffix,
+                                   bool include_values);
+
+  void generate_struct_ostream_operator_decl(std::ostream& f, t_struct* tstruct);
+  void generate_struct_ostream_operator(std::ostream& f, t_struct* tstruct);
+  void generate_struct_print_method_decl(std::ostream& f, t_struct* tstruct);
+  void generate_exception_what_method_decl(std::ostream& f,
+                                           t_struct* tstruct,
+                                           bool external = false);
+
+  bool is_reference(t_field* tfield) { return tfield->get_reference(); }
+
+  bool is_complex_type(t_type* ttype) {
+    ttype = get_true_type(ttype);
+
+    return ttype->is_container() || ttype->is_struct() || ttype->is_xception()
+           || (ttype->is_base_type()
+               && (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING));
+  }
+
+  void set_use_include_prefix(bool use_include_prefix) { use_include_prefix_ = use_include_prefix; }
+
+  /**
+   * The compiler option "no_thrift_ostream_impl" can be used to prevent
+   * the compiler from emitting implementations for operator <<.  In this
+   * case the consuming application must provide any needed to build.
+   *
+   * To disable this on a per structure bases, one can alternatively set
+   * the annotation "cpp.customostream" to prevent thrift from emitting an
+   * operator << (std::ostream&).
+   *
+   * See AnnotationTest for validation of this annotation feature.
+   */
+  bool has_custom_ostream(t_type* ttype) const {
+    return (gen_no_ostream_operators_) ||
+           (ttype->annotations_.find("cpp.customostream") != ttype->annotations_.end());
+  }
+
+private:
+  /**
+   * Returns the include prefix to use for a file generated by program, or the
+   * empty string if no include prefix should be used.
+   */
+  std::string get_include_prefix(const t_program& program) const;
+
+  /**
+   * True if we should generate pure enums for Thrift enums, instead of wrapper classes.
+   */
+  bool gen_pure_enums_;
+
+  /**
+   * True if we should generate templatized reader/writer methods.
+   */
+  bool gen_templates_;
+
+  /**
+   * True iff we should generate process function pointers for only templatized
+   * reader/writer methods.
+   */
+  bool gen_templates_only_;
+
+  /**
+   * True if we should generate move constructors & assignment operators.
+   */
+  bool gen_moveable_;
+
+  /**
+   * True if we should generate ostream definitions
+   */
+  bool gen_no_ostream_operators_;
+
+  /**
+   * True iff we should use a path prefix in our #include statements for other
+   * thrift-generated header files.
+   */
+  bool use_include_prefix_;
+
+  /**
+   * True if we should generate "Continuation OBject"-style classes as well.
+   */
+  bool gen_cob_style_;
+
+  /**
+   * True if we should omit calls to completion__() in CobClient class.
+   */
+  bool gen_no_client_completion_;
+
+  /**
+   * True if we should omit generating the default opeartors ==, != and <.
+   */
+  bool gen_no_default_operators_;
+
+   /**
+   * True if we should generate skeleton.
+   */
+  bool gen_no_skeleton_;
+
+  /**
+   * Strings for namespace, computed once up front then used directly
+   */
+
+  std::string ns_open_;
+  std::string ns_close_;
+
+  /**
+   * File streams, stored here to avoid passing them as parameters to every
+   * function.
+   */
+
+  ofstream_with_content_based_conditional_update f_types_;
+  ofstream_with_content_based_conditional_update f_types_impl_;
+  ofstream_with_content_based_conditional_update f_types_tcc_;
+  ofstream_with_content_based_conditional_update f_header_;
+  ofstream_with_content_based_conditional_update f_service_;
+  ofstream_with_content_based_conditional_update f_service_tcc_;
+
+  // The ProcessorGenerator is used to generate parts of the code,
+  // so it needs access to many of our protected members and methods.
+  //
+  // TODO: The code really should be cleaned up so that helper methods for
+  // writing to the output files are separate from the generator classes
+  // themselves.
+  friend class ProcessorGenerator;
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ */
+void t_cpp_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  // Make output file
+  string f_types_name = get_out_dir() + program_name_ + "_types.h";
+  f_types_.open(f_types_name);
+
+  string f_types_impl_name = get_out_dir() + program_name_ + "_types.cpp";
+  f_types_impl_.open(f_types_impl_name.c_str());
+
+  if (gen_templates_) {
+    // If we don't open the stream, it appears to just discard data,
+    // which is fine.
+    string f_types_tcc_name = get_out_dir() + program_name_ + "_types.tcc";
+    f_types_tcc_.open(f_types_tcc_name.c_str());
+  }
+
+  // Print header
+  f_types_ << autogen_comment();
+  f_types_impl_ << autogen_comment();
+  f_types_tcc_ << autogen_comment();
+
+  // Start ifndef
+  f_types_ << "#ifndef " << program_name_ << "_TYPES_H" << endl << "#define " << program_name_
+           << "_TYPES_H" << endl << endl;
+  f_types_tcc_ << "#ifndef " << program_name_ << "_TYPES_TCC" << endl << "#define " << program_name_
+               << "_TYPES_TCC" << endl << endl;
+
+  // Include base types
+  f_types_ << "#include <iosfwd>" << endl
+           << endl
+           << "#include <thrift/Thrift.h>" << endl
+           << "#include <thrift/TApplicationException.h>" << endl
+           << "#include <thrift/TBase.h>" << endl
+           << "#include <thrift/protocol/TProtocol.h>" << endl
+           << "#include <thrift/transport/TTransport.h>" << endl
+           << endl;
+  // Include C++xx compatibility header
+  f_types_ << "#include <functional>" << endl;
+  f_types_ << "#include <memory>" << endl;
+
+  // Include other Thrift includes
+  const vector<t_program*>& includes = program_->get_includes();
+  for (size_t i = 0; i < includes.size(); ++i) {
+    f_types_ << "#include \"" << get_include_prefix(*(includes[i])) << includes[i]->get_name()
+             << "_types.h\"" << endl;
+
+    // XXX(simpkins): If gen_templates_ is enabled, we currently assume all
+    // included files were also generated with templates enabled.
+    f_types_tcc_ << "#include \"" << get_include_prefix(*(includes[i])) << includes[i]->get_name()
+                 << "_types.tcc\"" << endl;
+  }
+  f_types_ << endl;
+
+  // Include custom headers
+  const vector<string>& cpp_includes = program_->get_cpp_includes();
+  for (size_t i = 0; i < cpp_includes.size(); ++i) {
+    if (cpp_includes[i][0] == '<') {
+      f_types_ << "#include " << cpp_includes[i] << endl;
+    } else {
+      f_types_ << "#include \"" << cpp_includes[i] << "\"" << endl;
+    }
+  }
+  f_types_ << endl;
+
+  // Include the types file
+  f_types_impl_ << "#include \"" << get_include_prefix(*get_program()) << program_name_
+                << "_types.h\"" << endl << endl;
+  f_types_tcc_ << "#include \"" << get_include_prefix(*get_program()) << program_name_
+               << "_types.h\"" << endl << endl;
+
+  // The swap() code needs <algorithm> for std::swap()
+  f_types_impl_ << "#include <algorithm>" << endl;
+  // for operator<<
+  f_types_impl_ << "#include <ostream>" << endl << endl;
+  f_types_impl_ << "#include <thrift/TToString.h>" << endl << endl;
+
+  // Open namespace
+  ns_open_ = namespace_open(program_->get_namespace("cpp"));
+  ns_close_ = namespace_close(program_->get_namespace("cpp"));
+
+  f_types_ << ns_open_ << endl << endl;
+
+  f_types_impl_ << ns_open_ << endl << endl;
+
+  f_types_tcc_ << ns_open_ << endl << endl;
+}
+
+/**
+ * Closes the output files.
+ */
+void t_cpp_generator::close_generator() {
+  // Close namespace
+  f_types_ << ns_close_ << endl << endl;
+  f_types_impl_ << ns_close_ << endl;
+  f_types_tcc_ << ns_close_ << endl << endl;
+
+  // Include the types.tcc file from the types header file,
+  // so clients don't have to explicitly include the tcc file.
+  // TODO(simpkins): Make this a separate option.
+  if (gen_templates_) {
+    f_types_ << "#include \"" << get_include_prefix(*get_program()) << program_name_
+             << "_types.tcc\"" << endl << endl;
+  }
+
+  // Close ifndef
+  f_types_ << "#endif" << endl;
+  f_types_tcc_ << "#endif" << endl;
+
+  // Close output file
+  f_types_.close();
+  f_types_impl_.close();
+  f_types_tcc_.close();
+}
+
+/**
+ * Generates a typedef. This is just a simple 1-liner in C++
+ *
+ * @param ttypedef The type definition
+ */
+void t_cpp_generator::generate_typedef(t_typedef* ttypedef) {
+  f_types_ << indent() << "typedef " << type_name(ttypedef->get_type(), true) << " "
+           << ttypedef->get_symbolic() << ";" << endl << endl;
+}
+
+void t_cpp_generator::generate_enum_constant_list(std::ostream& f,
+                                                  const vector<t_enum_value*>& constants,
+                                                  const char* prefix,
+                                                  const char* suffix,
+                                                  bool include_values) {
+  f << " {" << endl;
+  indent_up();
+
+  vector<t_enum_value*>::const_iterator c_iter;
+  bool first = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f << "," << endl;
+    }
+    indent(f) << prefix << (*c_iter)->get_name() << suffix;
+    if (include_values) {
+      f << " = " << (*c_iter)->get_value();
+    }
+  }
+
+  f << endl;
+  indent_down();
+  indent(f) << "};" << endl;
+}
+
+/**
+ * Generates code for an enumerated type. In C++, this is essentially the same
+ * as the thrift definition itself, using the enum keyword in C++.
+ *
+ * @param tenum The enumeration
+ */
+void t_cpp_generator::generate_enum(t_enum* tenum) {
+  vector<t_enum_value*> constants = tenum->get_constants();
+
+  std::string enum_name = tenum->get_name();
+  if (!gen_pure_enums_) {
+    enum_name = "type";
+    f_types_ << indent() << "struct " << tenum->get_name() << " {" << endl;
+    indent_up();
+  }
+  f_types_ << indent() << "enum " << enum_name;
+
+  generate_enum_constant_list(f_types_, constants, "", "", true);
+
+  if (!gen_pure_enums_) {
+    indent_down();
+    f_types_ << "};" << endl;
+  }
+
+  f_types_ << endl;
+
+  /**
+     Generate a character array of enum names for debugging purposes.
+  */
+  std::string prefix = "";
+  if (!gen_pure_enums_) {
+    prefix = tenum->get_name() + "::";
+  }
+
+  f_types_impl_ << indent() << "int _k" << tenum->get_name() << "Values[] =";
+  generate_enum_constant_list(f_types_impl_, constants, prefix.c_str(), "", false);
+
+  f_types_impl_ << indent() << "const char* _k" << tenum->get_name() << "Names[] =";
+  generate_enum_constant_list(f_types_impl_, constants, "\"", "\"", false);
+
+  f_types_ << indent() << "extern const std::map<int, const char*> _" << tenum->get_name()
+           << "_VALUES_TO_NAMES;" << endl << endl;
+
+  f_types_impl_ << indent() << "const std::map<int, const char*> _" << tenum->get_name()
+                << "_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(" << constants.size() << ", _k"
+                << tenum->get_name() << "Values"
+                << ", _k" << tenum->get_name() << "Names), "
+                << "::apache::thrift::TEnumIterator(-1, NULL, NULL));" << endl << endl;
+
+  generate_enum_ostream_operator_decl(f_types_, tenum);
+  generate_enum_ostream_operator(f_types_impl_, tenum);
+}
+
+void t_cpp_generator::generate_enum_ostream_operator_decl(std::ostream& out, t_enum* tenum) {
+
+  out << "std::ostream& operator<<(std::ostream& out, const ";
+  if (gen_pure_enums_) {
+    out << tenum->get_name();
+  } else {
+    out << tenum->get_name() << "::type&";
+  }
+  out << " val);" << endl;
+  out << endl;
+}
+
+void t_cpp_generator::generate_enum_ostream_operator(std::ostream& out, t_enum* tenum) {
+
+  // If we've been told the consuming application will provide an ostream
+  // operator definition then we only make a declaration:
+
+  if (!has_custom_ostream(tenum)) {
+    out << "std::ostream& operator<<(std::ostream& out, const ";
+    if (gen_pure_enums_) {
+      out << tenum->get_name();
+    } else {
+      out << tenum->get_name() << "::type&";
+    }
+    out << " val) ";
+    scope_up(out);
+
+    out << indent() << "std::map<int, const char*>::const_iterator it = _"
+             << tenum->get_name() << "_VALUES_TO_NAMES.find(val);" << endl;
+    out << indent() << "if (it != _" << tenum->get_name() << "_VALUES_TO_NAMES.end()) {" << endl;
+    indent_up();
+    out << indent() << "out << it->second;" << endl;
+    indent_down();
+    out << indent() << "} else {" << endl;
+    indent_up();
+    out << indent() << "out << static_cast<int>(val);" << endl;
+    indent_down();
+    out << indent() << "}" << endl;
+
+    out << indent() << "return out;" << endl;
+    scope_down(out);
+    out << endl;
+  }
+}
+
+/**
+ * Generates a class that holds all the constants.
+ */
+void t_cpp_generator::generate_consts(std::vector<t_const*> consts) {
+  string f_consts_name = get_out_dir() + program_name_ + "_constants.h";
+  ofstream_with_content_based_conditional_update f_consts;
+  f_consts.open(f_consts_name);
+
+  string f_consts_impl_name = get_out_dir() + program_name_ + "_constants.cpp";
+  ofstream_with_content_based_conditional_update f_consts_impl;
+  f_consts_impl.open(f_consts_impl_name);
+
+  // Print header
+  f_consts << autogen_comment();
+  f_consts_impl << autogen_comment();
+
+  // Start ifndef
+  f_consts << "#ifndef " << program_name_ << "_CONSTANTS_H" << endl << "#define " << program_name_
+           << "_CONSTANTS_H" << endl << endl << "#include \"" << get_include_prefix(*get_program())
+           << program_name_ << "_types.h\"" << endl << endl << ns_open_ << endl << endl;
+
+  f_consts_impl << "#include \"" << get_include_prefix(*get_program()) << program_name_
+                << "_constants.h\"" << endl << endl << ns_open_ << endl << endl;
+
+  f_consts << "class " << program_name_ << "Constants {" << endl << " public:" << endl << "  "
+           << program_name_ << "Constants();" << endl << endl;
+  indent_up();
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    string name = (*c_iter)->get_name();
+    t_type* type = (*c_iter)->get_type();
+    f_consts << indent() << type_name(type) << " " << name << ";" << endl;
+  }
+  indent_down();
+  f_consts << "};" << endl;
+
+  f_consts_impl << "const " << program_name_ << "Constants g_" << program_name_ << "_constants;"
+                << endl << endl << program_name_ << "Constants::" << program_name_
+                << "Constants() {" << endl;
+  indent_up();
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    print_const_value(f_consts_impl,
+                      (*c_iter)->get_name(),
+                      (*c_iter)->get_type(),
+                      (*c_iter)->get_value());
+  }
+  indent_down();
+  indent(f_consts_impl) << "}" << endl;
+
+  f_consts << endl << "extern const " << program_name_ << "Constants g_" << program_name_
+           << "_constants;" << endl << endl << ns_close_ << endl << endl << "#endif" << endl;
+  f_consts.close();
+
+  f_consts_impl << endl << ns_close_ << endl << endl;
+  f_consts_impl.close();
+}
+
+/**
+ * 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
+ */
+void t_cpp_generator::print_const_value(ostream& out,
+                                        string name,
+                                        t_type* type,
+                                        t_const_value* value) {
+  type = get_true_type(type);
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, name, type, value);
+    indent(out) << name << " = " << v2 << ";" << endl << endl;
+  } else if (type->is_enum()) {
+    indent(out) << name << " = (" << type_name(type) << ")" << value->get_integer() << ";" << endl
+                << endl;
+  } else if (type->is_struct() || type->is_xception()) {
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    bool is_nonrequired_field = false;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_type* field_type = NULL;
+      is_nonrequired_field = false;
+      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();
+          is_nonrequired_field = (*f_iter)->get_req() != t_field::T_REQUIRED;
+        }
+      }
+      if (field_type == NULL) {
+        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+      }
+      string val = render_const_value(out, name, field_type, v_iter->second);
+      indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl;
+      if (is_nonrequired_field) {
+        indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl;
+      }
+    }
+    out << endl;
+  } 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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, name, ktype, v_iter->first);
+      string val = render_const_value(out, name, vtype, v_iter->second);
+      indent(out) << name << ".insert(std::make_pair(" << key << ", " << val << "));" << endl;
+    }
+    out << endl;
+  } else if (type->is_list()) {
+    t_type* etype = ((t_list*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(out, name, etype, *v_iter);
+      indent(out) << name << ".push_back(" << val << ");" << endl;
+    }
+    out << endl;
+  } else if (type->is_set()) {
+    t_type* etype = ((t_set*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(out, name, etype, *v_iter);
+      indent(out) << name << ".insert(" << val << ");" << endl;
+    }
+    out << endl;
+  } else {
+    throw "INVALID TYPE IN print_const_value: " + type->get_name();
+  }
+}
+
+/**
+ *
+ */
+string t_cpp_generator::render_const_value(ostream& out,
+                                           string name,
+                                           t_type* type,
+                                           t_const_value* value) {
+  (void)name;
+  std::ostringstream render;
+
+  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:
+      render << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "true" : "false");
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_I64:
+      render << value->get_integer() << "LL";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << "static_cast<double>(" << value->get_integer() << ")";
+      } else {
+        render << emit_double_as_string(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()) {
+    render << "(" << type_name(type) << ")" << value->get_integer();
+  } else {
+    string t = tmp("tmp");
+    indent(out) << type_name(type) << " " << t << ";" << endl;
+    print_const_value(out, t, type, value);
+    render << t;
+  }
+
+  return render.str();
+}
+
+void t_cpp_generator::generate_forward_declaration(t_struct* tstruct) {
+  // Forward declare struct def
+  f_types_ << indent() << "class " << tstruct->get_name() << ";" << endl << endl;
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This is a class
+ * with data members and a read/write() function, plus a mirroring isset
+ * inner class.
+ *
+ * @param tstruct The struct definition
+ */
+void t_cpp_generator::generate_cpp_struct(t_struct* tstruct, bool is_exception) {
+  generate_struct_declaration(f_types_, tstruct, is_exception, false, true, true, true, true);
+  generate_struct_definition(f_types_impl_, f_types_impl_, tstruct, true, true);
+
+  std::ostream& out = (gen_templates_ ? f_types_tcc_ : f_types_impl_);
+  generate_struct_reader(out, tstruct);
+  generate_struct_writer(out, tstruct);
+  generate_struct_swap(f_types_impl_, tstruct);
+  generate_copy_constructor(f_types_impl_, tstruct, is_exception);
+  if (gen_moveable_) {
+    generate_move_constructor(f_types_impl_, tstruct, is_exception);
+  }
+  generate_assignment_operator(f_types_impl_, tstruct);
+  if (gen_moveable_) {
+    generate_move_assignment_operator(f_types_impl_, tstruct);
+  }
+
+  if (!has_custom_ostream(tstruct)) {
+    generate_struct_print_method(f_types_impl_, tstruct);
+  }
+
+  if (is_exception) {
+    generate_exception_what_method(f_types_impl_, tstruct);
+  }
+}
+
+void t_cpp_generator::generate_copy_constructor(ostream& out,
+                                                t_struct* tstruct,
+                                                bool is_exception) {
+  generate_constructor_helper(out, tstruct, is_exception, /*is_move=*/false);
+}
+
+void t_cpp_generator::generate_move_constructor(ostream& out,
+                                                t_struct* tstruct,
+                                                bool is_exception) {
+  generate_constructor_helper(out, tstruct, is_exception, /*is_move=*/true);
+}
+
+namespace {
+// Helper to convert a variable to rvalue, if move is enabled
+std::string maybeMove(std::string const& other, bool move) {
+  if (move) {
+    return "std::move(" + other + ")";
+  }
+  return other;
+}
+}
+
+void t_cpp_generator::generate_constructor_helper(ostream& out,
+                                                  t_struct* tstruct,
+                                                  bool is_exception,
+                                                  bool is_move) {
+
+  std::string tmp_name = tmp("other");
+
+  indent(out) << tstruct->get_name() << "::" << tstruct->get_name();
+
+  if (is_move) {
+    out << "( " << tstruct->get_name() << "&& ";
+  } else {
+    out << "(const " << tstruct->get_name() << "& ";
+  }
+  out << tmp_name << ") ";
+  if (is_exception)
+    out << ": TException() ";
+  out << "{" << endl;
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+
+  // eliminate compiler unused warning
+  if (members.empty())
+    indent(out) << "(void) " << tmp_name << ";" << endl;
+
+  vector<t_field*>::const_iterator f_iter;
+  bool has_nonrequired_fields = false;
+  for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) {
+    if ((*f_iter)->get_req() != t_field::T_REQUIRED)
+      has_nonrequired_fields = true;
+    indent(out) << (*f_iter)->get_name() << " = "
+                << maybeMove(tmp_name + "." + (*f_iter)->get_name(), is_move) << ";" << endl;
+  }
+
+  if (has_nonrequired_fields) {
+    indent(out) << "__isset = " << maybeMove(tmp_name + ".__isset", is_move) << ";" << endl;
+  }
+
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_cpp_generator::generate_assignment_operator(ostream& out, t_struct* tstruct) {
+  generate_assignment_helper(out, tstruct, /*is_move=*/false);
+}
+
+void t_cpp_generator::generate_move_assignment_operator(ostream& out, t_struct* tstruct) {
+  generate_assignment_helper(out, tstruct, /*is_move=*/true);
+}
+
+void t_cpp_generator::generate_assignment_helper(ostream& out, t_struct* tstruct, bool is_move) {
+  std::string tmp_name = tmp("other");
+
+  indent(out) << tstruct->get_name() << "& " << tstruct->get_name() << "::operator=(";
+
+  if (is_move) {
+    out << tstruct->get_name() << "&& ";
+  } else {
+    out << "const " << tstruct->get_name() << "& ";
+  }
+  out << tmp_name << ") {" << endl;
+
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+
+  // eliminate compiler unused warning
+  if (members.empty())
+    indent(out) << "(void) " << tmp_name << ";" << endl;
+
+  vector<t_field*>::const_iterator f_iter;
+  bool has_nonrequired_fields = false;
+  for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) {
+    if ((*f_iter)->get_req() != t_field::T_REQUIRED)
+      has_nonrequired_fields = true;
+    indent(out) << (*f_iter)->get_name() << " = "
+                << maybeMove(tmp_name + "." + (*f_iter)->get_name(), is_move) << ";" << endl;
+  }
+  if (has_nonrequired_fields) {
+    indent(out) << "__isset = " << maybeMove(tmp_name + ".__isset", is_move) << ";" << endl;
+  }
+
+  indent(out) << "return *this;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+/**
+ * Writes the struct declaration into the header file
+ *
+ * @param out Output stream
+ * @param tstruct The struct
+ */
+void t_cpp_generator::generate_struct_declaration(ostream& out,
+                                                  t_struct* tstruct,
+                                                  bool is_exception,
+                                                  bool pointers,
+                                                  bool read,
+                                                  bool write,
+                                                  bool swap,
+                                                  bool is_user_struct) {
+  string extends = "";
+  if (is_exception) {
+    extends = " : public ::apache::thrift::TException";
+  } else {
+    if (is_user_struct && !gen_templates_) {
+      extends = " : public virtual ::apache::thrift::TBase";
+    }
+  }
+
+  // Get members
+  vector<t_field*>::const_iterator m_iter;
+  const vector<t_field*>& members = tstruct->get_members();
+
+  // Write the isset structure declaration outside the class. This makes
+  // the generated code amenable to processing by SWIG.
+  // We only declare the struct if it gets used in the class.
+
+  // Isset struct has boolean fields, but only for non-required fields.
+  bool has_nonrequired_fields = false;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if ((*m_iter)->get_req() != t_field::T_REQUIRED)
+      has_nonrequired_fields = true;
+  }
+
+  if (has_nonrequired_fields && (!pointers || read)) {
+
+    out << indent() << "typedef struct _" << tstruct->get_name() << "__isset {" << endl;
+    indent_up();
+
+    indent(out) << "_" << tstruct->get_name() << "__isset() ";
+    bool first = true;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if ((*m_iter)->get_req() == t_field::T_REQUIRED) {
+        continue;
+      }
+      string isSet = ((*m_iter)->get_value() != NULL) ? "true" : "false";
+      if (first) {
+        first = false;
+        out << ": " << (*m_iter)->get_name() << "(" << isSet << ")";
+      } else {
+        out << ", " << (*m_iter)->get_name() << "(" << isSet << ")";
+      }
+    }
+    out << " {}" << endl;
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
+        indent(out) << "bool " << (*m_iter)->get_name() << " :1;" << endl;
+      }
+    }
+
+    indent_down();
+    indent(out) << "} _" << tstruct->get_name() << "__isset;" << endl;
+  }
+
+  out << endl;
+
+  // Open struct def
+  out << indent() << "class " << tstruct->get_name() << extends << " {" << endl << indent()
+      << " public:" << endl << endl;
+  indent_up();
+
+  if (!pointers) {
+    // Copy constructor
+    indent(out) << tstruct->get_name() << "(const " << tstruct->get_name() << "&);" << endl;
+
+    // Move constructor
+    if (gen_moveable_) {
+      indent(out) << tstruct->get_name() << "(" << tstruct->get_name() << "&&);" << endl;
+    }
+
+    // Assignment Operator
+    indent(out) << tstruct->get_name() << "& operator=(const " << tstruct->get_name() << "&);"
+                << endl;
+
+    // Move assignment operator
+    if (gen_moveable_) {
+      indent(out) << tstruct->get_name() << "& operator=(" << tstruct->get_name() << "&&);" << endl;
+    }
+
+    // Default constructor
+    indent(out) << tstruct->get_name() << "()";
+
+    bool init_ctor = false;
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+      if (t->is_base_type() || t->is_enum() || is_reference(*m_iter)) {
+        string dval;
+        if (t->is_enum()) {
+          dval += "(" + type_name(t) + ")";
+        }
+        dval += (t->is_string() || is_reference(*m_iter)) ? "" : "0";
+        t_const_value* cv = (*m_iter)->get_value();
+        if (cv != NULL) {
+          dval = render_const_value(out, (*m_iter)->get_name(), t, cv);
+        }
+        if (!init_ctor) {
+          init_ctor = true;
+          out << " : ";
+          out << (*m_iter)->get_name() << "(" << dval << ")";
+        } else {
+          out << ", " << (*m_iter)->get_name() << "(" << dval << ")";
+        }
+      }
+    }
+    out << " {" << endl;
+    indent_up();
+    // TODO(dreiss): When everything else in Thrift is perfect,
+    // do more of these in the initializer list.
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+
+      if (!t->is_base_type()) {
+        t_const_value* cv = (*m_iter)->get_value();
+        if (cv != NULL) {
+          print_const_value(out, (*m_iter)->get_name(), t, cv);
+        }
+      }
+    }
+    scope_down(out);
+  }
+
+  if (tstruct->annotations_.find("final") == tstruct->annotations_.end()) {
+    out << endl << indent() << "virtual ~" << tstruct->get_name() << "() noexcept;" << endl;
+  }
+
+  // Declare all fields
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) << declare_field(*m_iter,
+                                 false,
+                                 (pointers && !(*m_iter)->get_type()->is_xception()),
+                                 !read) << endl;
+  }
+
+  // Add the __isset data member if we need it, using the definition from above
+  if (has_nonrequired_fields && (!pointers || read)) {
+    out << endl << indent() << "_" << tstruct->get_name() << "__isset __isset;" << endl;
+  }
+
+  // Create a setter function for each field
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if (pointers) {
+      continue;
+    }
+    if (is_reference((*m_iter))) {
+      out << endl << indent() << "void __set_" << (*m_iter)->get_name() << "(::std::shared_ptr<"
+          << type_name((*m_iter)->get_type(), false, false) << ">";
+      out << " val);" << endl;
+    } else {
+      out << endl << indent() << "void __set_" << (*m_iter)->get_name() << "("
+          << type_name((*m_iter)->get_type(), false, true);
+      out << " val);" << endl;
+    }
+  }
+  out << endl;
+
+  if (!pointers) {
+    // Should we generate default operators?
+    if (!gen_no_default_operators_) {
+      // Generate an equality testing operator.  Make it inline since the compiler
+      // will do a better job than we would when deciding whether to inline it.
+      out << indent() << "bool operator == (const " << tstruct->get_name() << " & "
+          << (members.size() > 0 ? "rhs" : "/* rhs */") << ") const" << endl;
+      scope_up(out);
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        // Most existing Thrift code does not use isset or optional/required,
+        // so we treat "default" fields as required.
+        if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
+          out << indent() << "if (!(" << (*m_iter)->get_name() << " == rhs."
+              << (*m_iter)->get_name() << "))" << endl << indent() << "  return false;" << endl;
+        } else {
+          out << indent() << "if (__isset." << (*m_iter)->get_name() << " != rhs.__isset."
+              << (*m_iter)->get_name() << ")" << endl << indent() << "  return false;" << endl
+              << indent() << "else if (__isset." << (*m_iter)->get_name() << " && !("
+              << (*m_iter)->get_name() << " == rhs." << (*m_iter)->get_name() << "))" << endl
+              << indent() << "  return false;" << endl;
+        }
+      }
+      indent(out) << "return true;" << endl;
+      scope_down(out);
+      out << indent() << "bool operator != (const " << tstruct->get_name() << " &rhs) const {"
+          << endl << indent() << "  return !(*this == rhs);" << endl << indent() << "}" << endl
+          << endl;
+
+      // Generate the declaration of a less-than operator.  This must be
+      // implemented by the application developer if they wish to use it.  (They
+      // will get a link error if they try to use it without an implementation.)
+      out << indent() << "bool operator < (const " << tstruct->get_name() << " & ) const;" << endl
+          << endl;
+    }
+  }
+
+  if (read) {
+    if (gen_templates_) {
+      out << indent() << "template <class Protocol_>" << endl << indent()
+          << "uint32_t read(Protocol_* iprot);" << endl;
+    } else {
+      out << indent() << "uint32_t read("
+          << "::apache::thrift::protocol::TProtocol* iprot);" << endl;
+    }
+  }
+  if (write) {
+    if (gen_templates_) {
+      out << indent() << "template <class Protocol_>" << endl << indent()
+          << "uint32_t write(Protocol_* oprot) const;" << endl;
+    } else {
+      out << indent() << "uint32_t write("
+          << "::apache::thrift::protocol::TProtocol* oprot) const;" << endl;
+    }
+  }
+  out << endl;
+
+  if (is_user_struct && !has_custom_ostream(tstruct)) {
+    out << indent() << "virtual ";
+    generate_struct_print_method_decl(out, NULL);
+    out << ";" << endl;
+  }
+
+  // std::exception::what()
+  if (is_exception) {
+    out << indent() << "mutable std::string thriftTExceptionMessageHolder_;" << endl;
+    out << indent();
+    generate_exception_what_method_decl(out, tstruct, false);
+    out << ";" << endl;
+  }
+
+  indent_down();
+  indent(out) << "};" << endl << endl;
+
+  if (swap) {
+    // Generate a namespace-scope swap() function
+    out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name()
+        << " &b);" << endl << endl;
+  }
+
+  if (is_user_struct) {
+    generate_struct_ostream_operator_decl(out, tstruct);
+  }
+}
+
+void t_cpp_generator::generate_struct_definition(ostream& out,
+                                                 ostream& force_cpp_out,
+                                                 t_struct* tstruct,
+                                                 bool setters,
+                                                 bool is_user_struct) {
+  // Get members
+  vector<t_field*>::const_iterator m_iter;
+  const vector<t_field*>& members = tstruct->get_members();
+
+  // Destructor
+  if (tstruct->annotations_.find("final") == tstruct->annotations_.end()) {
+    force_cpp_out << endl << indent() << tstruct->get_name() << "::~" << tstruct->get_name()
+                  << "() noexcept {" << endl;
+    indent_up();
+
+    indent_down();
+    force_cpp_out << indent() << "}" << endl << endl;
+  }
+
+  // Create a setter function for each field
+  if (setters) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (is_reference((*m_iter))) {
+        std::string type = type_name((*m_iter)->get_type());
+        out << endl << indent() << "void " << tstruct->get_name() << "::__set_"
+            << (*m_iter)->get_name() << "(::std::shared_ptr<"
+            << type_name((*m_iter)->get_type(), false, false) << ">";
+        out << " val) {" << endl;
+      } else {
+        out << endl << indent() << "void " << tstruct->get_name() << "::__set_"
+            << (*m_iter)->get_name() << "(" << type_name((*m_iter)->get_type(), false, true);
+        out << " val) {" << endl;
+      }
+      indent_up();
+      out << indent() << "this->" << (*m_iter)->get_name() << " = val;" << endl;
+      indent_down();
+
+      // assume all fields are required except optional fields.
+      // for optional fields change __isset.name to true
+      bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
+      if (is_optional) {
+        out << indent() << indent() << "__isset." << (*m_iter)->get_name() << " = true;" << endl;
+      }
+      out << indent() << "}" << endl;
+    }
+  }
+  if (is_user_struct) {
+    generate_struct_ostream_operator(out, tstruct);
+  }
+  out << endl;
+}
+
+/**
+ * Makes a helper function to gen a struct reader.
+ *
+ * @param out Stream to write to
+ * @param tstruct The struct
+ */
+void t_cpp_generator::generate_struct_reader(ostream& out, t_struct* tstruct, bool pointers) {
+  if (gen_templates_) {
+    out << indent() << "template <class Protocol_>" << endl << indent() << "uint32_t "
+        << tstruct->get_name() << "::read(Protocol_* iprot) {" << endl;
+  } else {
+    indent(out) << "uint32_t " << tstruct->get_name()
+                << "::read(::apache::thrift::protocol::TProtocol* iprot) {" << endl;
+  }
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Declare stack tmp variables
+  out << endl
+      << indent() << "::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot);" << endl
+      << indent() << "uint32_t xfer = 0;" << endl
+      << indent() << "std::string fname;" << endl
+      << indent() << "::apache::thrift::protocol::TType ftype;" << endl
+      << indent() << "int16_t fid;" << endl
+      << endl
+      << indent() << "xfer += iprot->readStructBegin(fname);" << endl
+      << endl
+      << indent() << "using ::apache::thrift::protocol::TProtocolException;" << endl
+      << endl;
+
+  // Required variables aren't in __isset, so we need tmp vars to check them.
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED)
+      indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
+  }
+  out << endl;
+
+  // Loop over reading in fields
+  indent(out) << "while (true)" << endl;
+  scope_up(out);
+
+  // Read beginning field marker
+  indent(out) << "xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl;
+
+  // Check for field STOP marker
+  out << indent() << "if (ftype == ::apache::thrift::protocol::T_STOP) {" << endl << indent()
+      << "  break;" << endl << indent() << "}" << endl;
+
+  if (fields.empty()) {
+    out << indent() << "xfer += iprot->skip(ftype);" << endl;
+  } else {
+    // Switch statement on the field we are reading
+    indent(out) << "switch (fid)" << endl;
+
+    scope_up(out);
+
+    // Generate deserialization code for known cases
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      indent(out) << "case " << (*f_iter)->get_key() << ":" << endl;
+      indent_up();
+      indent(out) << "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+      indent_up();
+
+      const char* isset_prefix = ((*f_iter)->get_req() != t_field::T_REQUIRED) ? "this->__isset."
+                                                                               : "isset_";
+
+#if 0
+          // This code throws an exception if the same field is encountered twice.
+          // We've decided to leave it out for performance reasons.
+          // TODO(dreiss): Generate this code and "if" it out to make it easier
+          // for people recompiling thrift to include it.
+          out <<
+            indent() << "if (" << isset_prefix << (*f_iter)->get_name() << ")" << endl <<
+            indent() << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
+#endif
+
+      if (pointers && !(*f_iter)->get_type()->is_xception()) {
+        generate_deserialize_field(out, *f_iter, "(*(this->", "))");
+      } else {
+        generate_deserialize_field(out, *f_iter, "this->");
+      }
+      out << indent() << isset_prefix << (*f_iter)->get_name() << " = true;" << endl;
+      indent_down();
+      out << indent() << "} else {" << endl << indent() << "  xfer += iprot->skip(ftype);" << endl
+          <<
+          // TODO(dreiss): Make this an option when thrift structs
+          // have a common base class.
+          // indent() << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl <<
+          indent() << "}" << endl << indent() << "break;" << endl;
+      indent_down();
+    }
+
+    // In the default case we skip the field
+    out << indent() << "default:" << endl << indent() << "  xfer += iprot->skip(ftype);" << endl
+        << indent() << "  break;" << endl;
+
+    scope_down(out);
+  } //!fields.empty()
+  // Read field end marker
+  indent(out) << "xfer += iprot->readFieldEnd();" << endl;
+
+  scope_down(out);
+
+  out << endl << indent() << "xfer += iprot->readStructEnd();" << endl;
+
+  // Throw if any required fields are missing.
+  // We do this after reading the struct end so that
+  // there might possibly be a chance of continuing.
+  out << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED)
+      out << indent() << "if (!isset_" << (*f_iter)->get_name() << ')' << endl << indent()
+          << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
+  }
+
+  indent(out) << "return xfer;" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates the write function.
+ *
+ * @param out Stream to write to
+ * @param tstruct The struct
+ */
+void t_cpp_generator::generate_struct_writer(ostream& out, t_struct* tstruct, bool pointers) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  if (gen_templates_) {
+    out << indent() << "template <class Protocol_>" << endl << indent() << "uint32_t "
+        << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl;
+  } else {
+    indent(out) << "uint32_t " << tstruct->get_name()
+                << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl;
+  }
+  indent_up();
+
+  out << indent() << "uint32_t xfer = 0;" << endl;
+
+  indent(out) << "::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot);" << endl;
+  indent(out) << "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    bool check_if_set = (*f_iter)->get_req() == t_field::T_OPTIONAL
+                        || (*f_iter)->get_type()->is_xception();
+    if (check_if_set) {
+      out << endl << indent() << "if (this->__isset." << (*f_iter)->get_name() << ") {" << endl;
+      indent_up();
+    } else {
+      out << endl;
+    }
+
+    // Write field header
+    out << indent() << "xfer += oprot->writeFieldBegin("
+        << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", "
+        << (*f_iter)->get_key() << ");" << endl;
+    // Write field contents
+    if (pointers && !(*f_iter)->get_type()->is_xception()) {
+      generate_serialize_field(out, *f_iter, "(*(this->", "))");
+    } else {
+      generate_serialize_field(out, *f_iter, "this->");
+    }
+    // Write field closer
+    indent(out) << "xfer += oprot->writeFieldEnd();" << endl;
+    if (check_if_set) {
+      indent_down();
+      indent(out) << '}';
+    }
+  }
+
+  out << endl;
+
+  // Write the struct map
+  out << indent() << "xfer += oprot->writeFieldStop();" << endl << indent()
+      << "xfer += oprot->writeStructEnd();" << endl << indent()
+      << "return xfer;" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Struct writer for result of a function, which can have only one of its
+ * fields set and does a conditional if else look up into the __isset field
+ * of the struct.
+ *
+ * @param out Output stream
+ * @param tstruct The result struct
+ */
+void t_cpp_generator::generate_struct_result_writer(ostream& out,
+                                                    t_struct* tstruct,
+                                                    bool pointers) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  if (gen_templates_) {
+    out << indent() << "template <class Protocol_>" << endl << indent() << "uint32_t "
+        << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl;
+  } else {
+    indent(out) << "uint32_t " << tstruct->get_name()
+                << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl;
+  }
+  indent_up();
+
+  out << endl << indent() << "uint32_t xfer = 0;" << endl << endl;
+
+  indent(out) << "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
+
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      out << endl << indent() << "if ";
+    } else {
+      out << " else if ";
+    }
+
+    out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl;
+
+    indent_up();
+
+    // Write field header
+    out << indent() << "xfer += oprot->writeFieldBegin("
+        << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", "
+        << (*f_iter)->get_key() << ");" << endl;
+    // Write field contents
+    if (pointers) {
+      generate_serialize_field(out, *f_iter, "(*(this->", "))");
+    } else {
+      generate_serialize_field(out, *f_iter, "this->");
+    }
+    // Write field closer
+    indent(out) << "xfer += oprot->writeFieldEnd();" << endl;
+
+    indent_down();
+    indent(out) << "}";
+  }
+
+  // Write the struct map
+  out << endl << indent() << "xfer += oprot->writeFieldStop();" << endl << indent()
+      << "xfer += oprot->writeStructEnd();" << endl << indent() << "return xfer;" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates the swap function.
+ *
+ * @param out Stream to write to
+ * @param tstruct The struct
+ */
+void t_cpp_generator::generate_struct_swap(ostream& out, t_struct* tstruct) {
+  out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name()
+      << " &b) {" << endl;
+  indent_up();
+
+  // Let argument-dependent name lookup find the correct swap() function to
+  // use based on the argument types.  If none is found in the arguments'
+  // namespaces, fall back to ::std::swap().
+  out << indent() << "using ::std::swap;" << endl;
+
+  bool has_nonrequired_fields = false;
+  const vector<t_field*>& fields = tstruct->get_members();
+  for (vector<t_field*>::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* tfield = *f_iter;
+
+    if (tfield->get_req() != t_field::T_REQUIRED) {
+      has_nonrequired_fields = true;
+    }
+
+    out << indent() << "swap(a." << tfield->get_name() << ", b." << tfield->get_name() << ");"
+        << endl;
+  }
+
+  if (has_nonrequired_fields) {
+    out << indent() << "swap(a.__isset, b.__isset);" << endl;
+  }
+
+  // handle empty structs
+  if (fields.size() == 0) {
+    out << indent() << "(void) a;" << endl;
+    out << indent() << "(void) b;" << endl;
+  }
+
+  scope_down(out);
+  out << endl;
+}
+
+void t_cpp_generator::generate_struct_ostream_operator_decl(std::ostream& out, t_struct* tstruct) {
+  out << "std::ostream& operator<<(std::ostream& out, const "
+      << tstruct->get_name()
+      << "& obj);" << endl;
+  out << endl;
+}
+
+void t_cpp_generator::generate_struct_ostream_operator(std::ostream& out, t_struct* tstruct) {
+  if (!has_custom_ostream(tstruct)) {
+    // thrift defines this behavior
+    out << "std::ostream& operator<<(std::ostream& out, const "
+        << tstruct->get_name()
+        << "& obj)" << endl;
+    scope_up(out);
+    out << indent() << "obj.printTo(out);" << endl
+        << indent() << "return out;" << endl;
+    scope_down(out);
+    out << endl;
+  }
+}
+
+void t_cpp_generator::generate_struct_print_method_decl(std::ostream& out, t_struct* tstruct) {
+  out << "void ";
+  if (tstruct) {
+    out << tstruct->get_name() << "::";
+  }
+  out << "printTo(std::ostream& out) const";
+}
+
+void t_cpp_generator::generate_exception_what_method_decl(std::ostream& out,
+                                                          t_struct* tstruct,
+                                                          bool external) {
+  out << "const char* ";
+  if (external) {
+    out << tstruct->get_name() << "::";
+  }
+  out << "what() const noexcept";
+}
+
+namespace struct_ostream_operator_generator {
+void generate_required_field_value(std::ostream& out, const t_field* field) {
+  out << " << to_string(" << field->get_name() << ")";
+}
+
+void generate_optional_field_value(std::ostream& out, const t_field* field) {
+  out << "; (__isset." << field->get_name() << " ? (out";
+  generate_required_field_value(out, field);
+  out << ") : (out << \"<null>\"))";
+}
+
+void generate_field_value(std::ostream& out, const t_field* field) {
+  if (field->get_req() == t_field::T_OPTIONAL)
+    generate_optional_field_value(out, field);
+  else
+    generate_required_field_value(out, field);
+}
+
+void generate_field_name(std::ostream& out, const t_field* field) {
+  out << "\"" << field->get_name() << "=\"";
+}
+
+void generate_field(std::ostream& out, const t_field* field) {
+  generate_field_name(out, field);
+  generate_field_value(out, field);
+}
+
+void generate_fields(std::ostream& out,
+                     const vector<t_field*>& fields,
+                     const std::string& indent) {
+  const vector<t_field*>::const_iterator beg = fields.begin();
+  const vector<t_field*>::const_iterator end = fields.end();
+
+  for (vector<t_field*>::const_iterator it = beg; it != end; ++it) {
+    out << indent << "out << ";
+
+    if (it != beg) {
+      out << "\", \" << ";
+    }
+
+    generate_field(out, *it);
+    out << ";" << endl;
+  }
+}
+}
+
+/**
+ * Generates operator<<
+ */
+void t_cpp_generator::generate_struct_print_method(std::ostream& out, t_struct* tstruct) {
+  out << indent();
+  generate_struct_print_method_decl(out, tstruct);
+  out << " {" << endl;
+
+  indent_up();
+
+  out << indent() << "using ::apache::thrift::to_string;" << endl;
+  out << indent() << "out << \"" << tstruct->get_name() << "(\";" << endl;
+  struct_ostream_operator_generator::generate_fields(out, tstruct->get_members(), indent());
+  out << indent() << "out << \")\";" << endl;
+
+  indent_down();
+  out << "}" << endl << endl;
+}
+
+/**
+ * Generates what() method for exceptions
+ */
+void t_cpp_generator::generate_exception_what_method(std::ostream& out, t_struct* tstruct) {
+  out << indent();
+  generate_exception_what_method_decl(out, tstruct, true);
+  out << " {" << endl;
+
+  indent_up();
+  out << indent() << "try {" << endl;
+
+  indent_up();
+  out << indent() << "std::stringstream ss;" << endl;
+  out << indent() << "ss << \"TException - service has thrown: \" << *this;" << endl;
+  out << indent() << "this->thriftTExceptionMessageHolder_ = ss.str();" << endl;
+  out << indent() << "return this->thriftTExceptionMessageHolder_.c_str();" << endl;
+  indent_down();
+
+  out << indent() << "} catch (const std::exception&) {" << endl;
+
+  indent_up();
+  out << indent() << "return \"TException - service has thrown: " << tstruct->get_name() << "\";"
+      << endl;
+  indent_down();
+
+  out << indent() << "}" << endl;
+
+  indent_down();
+  out << "}" << endl << endl;
+}
+
+/**
+ * Generates a thrift service. In C++, this comprises an entirely separate
+ * header and source file. The header file defines the methods and includes
+ * the data types defined in the main header file, and the implementation
+ * file contains implementations of the basic printer and default interfaces.
+ *
+ * @param tservice The service definition
+ */
+void t_cpp_generator::generate_service(t_service* tservice) {
+  string svcname = tservice->get_name();
+
+  // Make output files
+  string f_header_name = get_out_dir() + svcname + ".h";
+  f_header_.open(f_header_name.c_str());
+
+  // Print header file includes
+  f_header_ << autogen_comment();
+  f_header_ << "#ifndef " << svcname << "_H" << endl << "#define " << svcname << "_H" << endl
+            << endl;
+  if (gen_cob_style_) {
+    f_header_ << "#include <thrift/transport/TBufferTransports.h>" << endl // TMemoryBuffer
+              << "#include <functional>" << endl 
+              << "#include <memory>" << endl
+              << "namespace apache { namespace thrift { namespace async {" << endl
+              << "class TAsyncChannel;" << endl << "}}}" << endl;
+  }
+  f_header_ << "#include <thrift/TDispatchProcessor.h>" << endl;
+  if (gen_cob_style_) {
+    f_header_ << "#include <thrift/async/TAsyncDispatchProcessor.h>" << endl;
+  }
+  f_header_ << "#include <thrift/async/TConcurrentClientSyncInfo.h>" << endl;
+  f_header_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ << "_types.h\""
+            << endl;
+
+  t_service* extends_service = tservice->get_extends();
+  if (extends_service != NULL) {
+    f_header_ << "#include \"" << get_include_prefix(*(extends_service->get_program()))
+              << extends_service->get_name() << ".h\"" << endl;
+  }
+
+  f_header_ << endl << ns_open_ << endl << endl;
+
+  f_header_ << "#ifdef _MSC_VER\n"
+               "  #pragma warning( push )\n"
+               "  #pragma warning (disable : 4250 ) //inheriting methods via dominance \n"
+               "#endif\n\n";
+
+  // Service implementation file includes
+  string f_service_name = get_out_dir() + svcname + ".cpp";
+  f_service_.open(f_service_name.c_str());
+  f_service_ << autogen_comment();
+  f_service_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl;
+  if (gen_cob_style_) {
+    f_service_ << "#include \"thrift/async/TAsyncChannel.h\"" << endl;
+  }
+  if (gen_templates_) {
+    f_service_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".tcc\""
+               << endl;
+
+    string f_service_tcc_name = get_out_dir() + svcname + ".tcc";
+    f_service_tcc_.open(f_service_tcc_name.c_str());
+    f_service_tcc_ << autogen_comment();
+    f_service_tcc_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\""
+                   << endl;
+
+    f_service_tcc_ << "#ifndef " << svcname << "_TCC" << endl << "#define " << svcname << "_TCC"
+                   << endl << endl;
+
+    if (gen_cob_style_) {
+      f_service_tcc_ << "#include \"thrift/async/TAsyncChannel.h\"" << endl;
+    }
+  }
+
+  f_service_ << endl << ns_open_ << endl << endl;
+  f_service_tcc_ << endl << ns_open_ << endl << endl;
+
+  // Generate all the components
+  generate_service_interface(tservice, "");
+  generate_service_interface_factory(tservice, "");
+  generate_service_null(tservice, "");
+  generate_service_helpers(tservice);
+  generate_service_client(tservice, "");
+  generate_service_processor(tservice, "");
+  generate_service_multiface(tservice);
+  generate_service_client(tservice, "Concurrent");
+
+  // Generate skeleton
+  if (!gen_no_skeleton_) {
+      generate_service_skeleton(tservice);
+  }
+
+  // Generate all the cob components
+  if (gen_cob_style_) {
+    generate_service_interface(tservice, "CobCl");
+    generate_service_interface(tservice, "CobSv");
+    generate_service_interface_factory(tservice, "CobSv");
+    generate_service_null(tservice, "CobSv");
+    generate_service_client(tservice, "Cob");
+    generate_service_processor(tservice, "Cob");
+
+    if (!gen_no_skeleton_) {
+      generate_service_async_skeleton(tservice);
+    }
+
+  }
+
+  f_header_ << "#ifdef _MSC_VER\n"
+               "  #pragma warning( pop )\n"
+               "#endif\n\n";
+
+  // Close the namespace
+  f_service_ << ns_close_ << endl << endl;
+  f_service_tcc_ << ns_close_ << endl << endl;
+  f_header_ << ns_close_ << endl << endl;
+
+  // TODO(simpkins): Make this a separate option
+  if (gen_templates_) {
+    f_header_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".tcc\"" << endl
+              << "#include \"" << get_include_prefix(*get_program()) << program_name_
+              << "_types.tcc\"" << endl << endl;
+  }
+
+  f_header_ << "#endif" << endl;
+  f_service_tcc_ << "#endif" << endl;
+
+  // Close the files
+  f_service_tcc_.close();
+  f_service_.close();
+  f_header_.close();
+}
+
+/**
+ * Generates helper functions for a service. Basically, this generates types
+ * for all the arguments and results to functions.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_cpp_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  std::ostream& out = (gen_templates_ ? f_service_tcc_ : f_service_);
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    string name_orig = ts->get_name();
+
+    // TODO(dreiss): Why is this stuff not in generate_function_helpers?
+    ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_args");
+    generate_struct_declaration(f_header_, ts, false);
+    generate_struct_definition(out, f_service_, ts, false);
+    generate_struct_reader(out, ts);
+    generate_struct_writer(out, ts);
+    ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs");
+    generate_struct_declaration(f_header_, ts, false, true, false, true);
+    generate_struct_definition(out, f_service_, ts, false);
+    generate_struct_writer(out, ts, true);
+    ts->set_name(name_orig);
+
+    generate_function_helpers(tservice, *f_iter);
+  }
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_cpp_generator::generate_service_interface(t_service* tservice, string style) {
+
+  string service_if_name = service_name_ + style + "If";
+  if (style == "CobCl") {
+    // Forward declare the client.
+    string client_name = service_name_ + "CobClient";
+    if (gen_templates_) {
+      client_name += "T";
+      service_if_name += "T";
+      indent(f_header_) << "template <class Protocol_>" << endl;
+    }
+    indent(f_header_) << "class " << client_name << ";" << endl << endl;
+  }
+
+  string extends = "";
+  if (tservice->get_extends() != NULL) {
+    extends = " : virtual public " + type_name(tservice->get_extends()) + style + "If";
+    if (style == "CobCl" && gen_templates_) {
+      // TODO(simpkins): If gen_templates_ is enabled, we currently assume all
+      // parent services were also generated with templates enabled.
+      extends += "T<Protocol_>";
+    }
+  }
+
+  if (style == "CobCl" && gen_templates_) {
+    f_header_ << "template <class Protocol_>" << endl;
+  }
+  f_header_ << "class " << service_if_name << extends << " {" << endl << " public:" << endl;
+  indent_up();
+  f_header_ << indent() << "virtual ~" << service_if_name << "() {}" << endl;
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    if ((*f_iter)->has_doc())
+      f_header_ << endl;
+    generate_java_doc(f_header_, *f_iter);
+    f_header_ << indent() << "virtual " << function_signature(*f_iter, style) << " = 0;" << endl;
+  }
+  indent_down();
+  f_header_ << "};" << endl << endl;
+
+  if (style == "CobCl" && gen_templates_) {
+    // generate a backwards-compatible typedef for clients that do not
+    // know about the new template-style code
+    f_header_ << "typedef " << service_if_name << "< ::apache::thrift::protocol::TProtocol> "
+              << service_name_ << style << "If;" << endl << endl;
+  }
+}
+
+/**
+ * Generates a service interface factory.
+ *
+ * @param tservice The service to generate an interface factory for.
+ */
+void t_cpp_generator::generate_service_interface_factory(t_service* tservice, string style) {
+  string service_if_name = service_name_ + style + "If";
+
+  // Figure out the name of the upper-most parent class.
+  // Getting everything to work out properly with inheritance is annoying.
+  // Here's what we're doing for now:
+  //
+  // - All handlers implement getHandler(), but subclasses use covariant return
+  //   types to return their specific service interface class type.  We have to
+  //   use raw pointers because of this; shared_ptr<> can't be used for
+  //   covariant return types.
+  //
+  // - Since we're not using shared_ptr<>, we also provide a releaseHandler()
+  //   function that must be called to release a pointer to a handler obtained
+  //   via getHandler().
+  //
+  //   releaseHandler() always accepts a pointer to the upper-most parent class
+  //   type.  This is necessary since the parent versions of releaseHandler()
+  //   may accept any of the parent types, not just the most specific subclass
+  //   type.  Implementations can use dynamic_cast to cast the pointer to the
+  //   subclass type if desired.
+  t_service* base_service = tservice;
+  while (base_service->get_extends() != NULL) {
+    base_service = base_service->get_extends();
+  }
+  string base_if_name = type_name(base_service) + style + "If";
+
+  // Generate the abstract factory class
+  string factory_name = service_if_name + "Factory";
+  string extends;
+  if (tservice->get_extends() != NULL) {
+    extends = " : virtual public " + type_name(tservice->get_extends()) + style + "IfFactory";
+  }
+
+  f_header_ << "class " << factory_name << extends << " {" << endl << " public:" << endl;
+  indent_up();
+  f_header_ << indent() << "typedef " << service_if_name << " Handler;" << endl << endl << indent()
+            << "virtual ~" << factory_name << "() {}" << endl << endl << indent() << "virtual "
+            << service_if_name << "* getHandler("
+            << "const ::apache::thrift::TConnectionInfo& connInfo) = 0;" << endl << indent()
+            << "virtual void releaseHandler(" << base_if_name << "* /* handler */) = 0;" << endl;
+
+  indent_down();
+  f_header_ << "};" << endl << endl;
+
+  // Generate the singleton factory class
+  string singleton_factory_name = service_if_name + "SingletonFactory";
+  f_header_ << "class " << singleton_factory_name << " : virtual public " << factory_name << " {"
+            << endl << " public:" << endl;
+  indent_up();
+  f_header_ << indent() << singleton_factory_name << "(const ::std::shared_ptr<" << service_if_name
+            << ">& iface) : iface_(iface) {}" << endl << indent() << "virtual ~"
+            << singleton_factory_name << "() {}" << endl << endl << indent() << "virtual "
+            << service_if_name << "* getHandler("
+            << "const ::apache::thrift::TConnectionInfo&) {" << endl << indent()
+            << "  return iface_.get();" << endl << indent() << "}" << endl << indent()
+            << "virtual void releaseHandler(" << base_if_name << "* /* handler */) {}" << endl;
+
+  f_header_ << endl << " protected:" << endl << indent() << "::std::shared_ptr<" << service_if_name
+            << "> iface_;" << endl;
+
+  indent_down();
+  f_header_ << "};" << endl << endl;
+}
+
+/**
+ * Generates a null implementation of the service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_cpp_generator::generate_service_null(t_service* tservice, string style) {
+  string extends = "";
+  if (tservice->get_extends() != NULL) {
+    extends = " , virtual public " + type_name(tservice->get_extends()) + style + "Null";
+  }
+  f_header_ << "class " << service_name_ << style << "Null : virtual public " << service_name_
+            << style << "If" << extends << " {" << endl << " public:" << endl;
+  indent_up();
+  f_header_ << indent() << "virtual ~" << service_name_ << style << "Null() {}" << endl;
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_header_ << indent() << function_signature(*f_iter, style, "", false) << " {" << endl;
+    indent_up();
+
+    t_type* returntype = (*f_iter)->get_returntype();
+    t_field returnfield(returntype, "_return");
+
+    if (style == "") {
+      if (returntype->is_void() || is_complex_type(returntype)) {
+        f_header_ << indent() << "return;" << endl;
+      } else {
+        f_header_ << indent() << declare_field(&returnfield, true) << endl << indent()
+                  << "return _return;" << endl;
+      }
+    } else if (style == "CobSv") {
+      if (returntype->is_void()) {
+        f_header_ << indent() << "return cob();" << endl;
+      } else {
+        t_field returnfield(returntype, "_return");
+        f_header_ << indent() << declare_field(&returnfield, true) << endl << indent()
+                  << "return cob(_return);" << endl;
+      }
+
+    } else {
+      throw "UNKNOWN STYLE";
+    }
+
+    indent_down();
+    f_header_ << indent() << "}" << endl;
+  }
+  indent_down();
+  f_header_ << "};" << endl << endl;
+}
+
+void t_cpp_generator::generate_function_call(ostream& out,
+                                             t_function* tfunction,
+                                             string target,
+                                             string iface,
+                                             string arg_prefix) {
+  bool first = true;
+  t_type* ret_type = get_true_type(tfunction->get_returntype());
+  out << indent();
+  if (!tfunction->is_oneway() && !ret_type->is_void()) {
+    if (is_complex_type(ret_type)) {
+      first = false;
+      out << iface << "->" << tfunction->get_name() << "(" << target;
+    } else {
+      out << target << " = " << iface << "->" << tfunction->get_name() << "(";
+    }
+  } else {
+    out << iface << "->" << tfunction->get_name() << "(";
+  }
+  const std::vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      out << ", ";
+    }
+    out << arg_prefix << (*f_iter)->get_name();
+  }
+  out << ");" << endl;
+}
+
+void t_cpp_generator::generate_service_async_skeleton(t_service* tservice) {
+  string svcname = tservice->get_name();
+
+  // Service implementation file includes
+  string f_skeleton_name = get_out_dir() + svcname + "_async_server.skeleton.cpp";
+
+  string ns = namespace_prefix(tservice->get_program()->get_namespace("cpp"));
+
+  ofstream_with_content_based_conditional_update f_skeleton;
+  f_skeleton.open(f_skeleton_name.c_str());
+  f_skeleton << "// This autogenerated skeleton file illustrates one way to adapt a synchronous"
+             << endl << "// interface into an asynchronous interface. You should copy it to another"
+             << endl
+             << "// filename to avoid overwriting it and rewrite as asynchronous any functions"
+             << endl << "// that would otherwise introduce unwanted latency." << endl << endl
+             << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl
+             << "#include <thrift/protocol/TBinaryProtocol.h>" << endl << endl
+             << "using namespace ::apache::thrift;" << endl
+             << "using namespace ::apache::thrift::protocol;" << endl
+             << "using namespace ::apache::thrift::transport;" << endl
+             << "using namespace ::apache::thrift::async;" << endl << endl;
+
+  // the following code would not compile:
+  // using namespace ;
+  // using namespace ::;
+  if ((!ns.empty()) && (ns.compare(" ::") != 0)) {
+    f_skeleton << "using namespace " << string(ns, 0, ns.size() - 2) << ";" << endl << endl;
+  }
+
+  f_skeleton << "class " << svcname << "AsyncHandler : "
+             << "public " << svcname << "CobSvIf {" << endl << " public:" << endl;
+  indent_up();
+  f_skeleton << indent() << svcname << "AsyncHandler() {" << endl << indent()
+             << "  syncHandler_ = std::auto_ptr<" << svcname << "Handler>(new " << svcname
+             << "Handler);" << endl << indent() << "  // Your initialization goes here" << endl
+             << indent() << "}" << endl;
+  f_skeleton << indent() << "virtual ~" << service_name_ << "AsyncHandler();" << endl;
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_skeleton << endl << indent() << function_signature(*f_iter, "CobSv", "", true) << " {"
+               << endl;
+    indent_up();
+
+    t_type* returntype = (*f_iter)->get_returntype();
+    t_field returnfield(returntype, "_return");
+
+    string target = returntype->is_void() ? "" : "_return";
+    if (!returntype->is_void()) {
+      f_skeleton << indent() << declare_field(&returnfield, true) << endl;
+    }
+    generate_function_call(f_skeleton, *f_iter, target, "syncHandler_", "");
+    f_skeleton << indent() << "return cob(" << target << ");" << endl;
+
+    scope_down(f_skeleton);
+  }
+  f_skeleton << endl << " protected:" << endl << indent() << "std::auto_ptr<" << svcname
+             << "Handler> syncHandler_;" << endl;
+  indent_down();
+  f_skeleton << "};" << endl << endl;
+}
+
+/**
+ * Generates a multiface, which is a single server that just takes a set
+ * of objects implementing the interface and calls them all, returning the
+ * value of the last one to be called.
+ *
+ * @param tservice The service to generate a multiserver for.
+ */
+void t_cpp_generator::generate_service_multiface(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_multiface = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_multiface = ", public " + extends + "Multiface";
+  }
+
+  string list_type = string("std::vector<std::shared_ptr<") + service_name_ + "If> >";
+
+  // Generate the header portion
+  f_header_ << "class " << service_name_ << "Multiface : "
+            << "virtual public " << service_name_ << "If" << extends_multiface << " {" << endl
+            << " public:" << endl;
+  indent_up();
+  f_header_ << indent() << service_name_ << "Multiface(" << list_type
+            << "& ifaces) : ifaces_(ifaces) {" << endl;
+  if (!extends.empty()) {
+    f_header_ << indent()
+              << "  std::vector<std::shared_ptr<" + service_name_ + "If> >::iterator iter;"
+              << endl << indent() << "  for (iter = ifaces.begin(); iter != ifaces.end(); ++iter) {"
+              << endl << indent() << "    " << extends << "Multiface::add(*iter);" << endl
+              << indent() << "  }" << endl;
+  }
+  f_header_ << indent() << "}" << endl << indent() << "virtual ~" << service_name_
+            << "Multiface() {}" << endl;
+  indent_down();
+
+  // Protected data members
+  f_header_ << " protected:" << endl;
+  indent_up();
+  f_header_ << indent() << list_type << " ifaces_;" << endl << indent() << service_name_
+            << "Multiface() {}" << endl << indent() << "void add(::std::shared_ptr<"
+            << service_name_ << "If> iface) {" << endl;
+  if (!extends.empty()) {
+    f_header_ << indent() << "  " << extends << "Multiface::add(iface);" << endl;
+  }
+  f_header_ << indent() << "  ifaces_.push_back(iface);" << endl << indent() << "}" << endl;
+  indent_down();
+
+  f_header_ << indent() << " public:" << endl;
+  indent_up();
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* arglist = (*f_iter)->get_arglist();
+    const vector<t_field*>& args = arglist->get_members();
+    vector<t_field*>::const_iterator a_iter;
+
+    string call = string("ifaces_[i]->") + (*f_iter)->get_name() + "(";
+    bool first = true;
+    if (is_complex_type((*f_iter)->get_returntype())) {
+      call += "_return";
+      first = false;
+    }
+    for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
+      if (first) {
+        first = false;
+      } else {
+        call += ", ";
+      }
+      call += (*a_iter)->get_name();
+    }
+    call += ")";
+
+    f_header_ << indent() << function_signature(*f_iter, "") << " {" << endl;
+    indent_up();
+    f_header_ << indent() << "size_t sz = ifaces_.size();" << endl << indent() << "size_t i = 0;"
+              << endl << indent() << "for (; i < (sz - 1); ++i) {" << endl;
+    indent_up();
+    f_header_ << indent() << call << ";" << endl;
+    indent_down();
+    f_header_ << indent() << "}" << endl;
+
+    if (!(*f_iter)->get_returntype()->is_void()) {
+      if (is_complex_type((*f_iter)->get_returntype())) {
+        f_header_ << indent() << call << ";" << endl << indent() << "return;" << endl;
+      } else {
+        f_header_ << indent() << "return " << call << ";" << endl;
+      }
+    } else {
+      f_header_ << indent() << call << ";" << endl;
+    }
+
+    indent_down();
+    f_header_ << indent() << "}" << endl << endl;
+  }
+
+  indent_down();
+  f_header_ << indent() << "};" << endl << endl;
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_cpp_generator::generate_service_client(t_service* tservice, string style) {
+  string ifstyle;
+  if (style == "Cob") {
+    ifstyle = "CobCl";
+  }
+
+  std::ostream& out = (gen_templates_ ? f_service_tcc_ : f_service_);
+  string template_header, template_suffix, short_suffix, protocol_type, _this;
+  string const prot_factory_type = "::apache::thrift::protocol::TProtocolFactory";
+  if (gen_templates_) {
+    template_header = "template <class Protocol_>\n";
+    short_suffix = "T";
+    template_suffix = "T<Protocol_>";
+    protocol_type = "Protocol_";
+    _this = "this->";
+  } else {
+    protocol_type = "::apache::thrift::protocol::TProtocol";
+  }
+  string prot_ptr = "std::shared_ptr< " + protocol_type + ">";
+  string client_suffix = "Client" + template_suffix;
+  string if_suffix = "If";
+  if (style == "Cob") {
+    if_suffix += template_suffix;
+  }
+
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    // TODO(simpkins): If gen_templates_ is enabled, we currently assume all
+    // parent services were also generated with templates enabled.
+    extends = type_name(tservice->get_extends());
+    extends_client = ", public " + extends + style + client_suffix;
+  }
+
+  // Generate the header portion
+  if (style == "Concurrent") {
+    f_header_ << "// The \'concurrent\' client is a thread safe client that correctly handles\n"
+                 "// out of order responses.  It is slower than the regular client, so should\n"
+                 "// only be used when you need to share a connection among multiple threads\n";
+  }
+  f_header_ << template_header << "class " << service_name_ << style << "Client" << short_suffix
+            << " : "
+            << "virtual public " << service_name_ << ifstyle << if_suffix << extends_client << " {"
+            << endl << " public:" << endl;
+
+  indent_up();
+  if (style != "Cob") {
+    f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" << prot_ptr
+              << " prot) ";
+
+    if (extends.empty()) {
+      f_header_ << "{" << endl;
+      f_header_ << indent() << "  setProtocol" << short_suffix << "(prot);" << endl << indent()
+                << "}" << endl;
+    } else {
+      f_header_ << ":" << endl;
+      f_header_ << indent() << "  " << extends << style << client_suffix << "(prot, prot) {}"
+                << endl;
+    }
+
+    f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" << prot_ptr
+              << " iprot, " << prot_ptr << " oprot) ";
+    if (extends.empty()) {
+      f_header_ << "{" << endl;
+      f_header_ << indent() << "  setProtocol" << short_suffix << "(iprot,oprot);" << endl
+                << indent() << "}" << endl;
+    } else {
+      f_header_ << ":" << indent() << "  " << extends << style << client_suffix
+                << "(iprot, oprot) {}" << endl;
+    }
+
+    // create the setProtocol methods
+    if (extends.empty()) {
+      f_header_ << " private:" << endl;
+      // 1: one parameter
+      f_header_ << indent() << "void setProtocol" << short_suffix << "(" << prot_ptr << " prot) {"
+                << endl;
+      f_header_ << indent() << "setProtocol" << short_suffix << "(prot,prot);" << endl;
+      f_header_ << indent() << "}" << endl;
+      // 2: two parameter
+      f_header_ << indent() << "void setProtocol" << short_suffix << "(" << prot_ptr << " iprot, "
+                << prot_ptr << " oprot) {" << endl;
+
+      f_header_ << indent() << "  piprot_=iprot;" << endl << indent() << "  poprot_=oprot;" << endl
+                << indent() << "  iprot_ = iprot.get();" << endl << indent()
+                << "  oprot_ = oprot.get();" << endl;
+
+      f_header_ << indent() << "}" << endl;
+      f_header_ << " public:" << endl;
+    }
+
+    // Generate getters for the protocols.
+    // Note that these are not currently templated for simplicity.
+    // TODO(simpkins): should they be templated?
+    f_header_ << indent()
+              << "std::shared_ptr< ::apache::thrift::protocol::TProtocol> getInputProtocol() {"
+              << endl << indent() << "  return " << _this << "piprot_;" << endl << indent() << "}"
+              << endl;
+
+    f_header_ << indent()
+              << "std::shared_ptr< ::apache::thrift::protocol::TProtocol> getOutputProtocol() {"
+              << endl << indent() << "  return " << _this << "poprot_;" << endl << indent() << "}"
+              << endl;
+
+  } else /* if (style == "Cob") */ {
+    f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "("
+              << "std::shared_ptr< ::apache::thrift::async::TAsyncChannel> channel, "
+              << "::apache::thrift::protocol::TProtocolFactory* protocolFactory) :" << endl;
+    if (extends.empty()) {
+      f_header_ << indent() << "  channel_(channel)," << endl << indent()
+                << "  itrans_(new ::apache::thrift::transport::TMemoryBuffer())," << endl
+                << indent() << "  otrans_(new ::apache::thrift::transport::TMemoryBuffer()),"
+                << endl;
+      if (gen_templates_) {
+        // TProtocolFactory classes return generic TProtocol pointers.
+        // We have to dynamic cast to the Protocol_ type we are expecting.
+        f_header_ << indent() << "  piprot_(::std::dynamic_pointer_cast<Protocol_>("
+                  << "protocolFactory->getProtocol(itrans_)))," << endl << indent()
+                  << "  poprot_(::std::dynamic_pointer_cast<Protocol_>("
+                  << "protocolFactory->getProtocol(otrans_))) {" << endl;
+        // Throw a TException if either dynamic cast failed.
+        f_header_ << indent() << "  if (!piprot_ || !poprot_) {" << endl << indent()
+                  << "    throw ::apache::thrift::TException(\""
+                  << "TProtocolFactory returned unexpected protocol type in " << service_name_
+                  << style << "Client" << short_suffix << " constructor\");" << endl << indent()
+                  << "  }" << endl;
+      } else {
+        f_header_ << indent() << "  piprot_(protocolFactory->getProtocol(itrans_))," << endl
+                  << indent() << "  poprot_(protocolFactory->getProtocol(otrans_)) {" << endl;
+      }
+      f_header_ << indent() << "  iprot_ = piprot_.get();" << endl << indent()
+                << "  oprot_ = poprot_.get();" << endl << indent() << "}" << endl;
+    } else {
+      f_header_ << indent() << "  " << extends << style << client_suffix
+                << "(channel, protocolFactory) {}" << endl;
+    }
+  }
+
+  if (style == "Cob") {
+    f_header_ << indent()
+              << "::std::shared_ptr< ::apache::thrift::async::TAsyncChannel> getChannel() {" << endl
+              << indent() << "  return " << _this << "channel_;" << endl << indent() << "}" << endl;
+    if (!gen_no_client_completion_) {
+      f_header_ << indent() << "virtual void completed__(bool /* success */) {}" << endl;
+    }
+  }
+
+  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) {
+    indent(f_header_) << function_signature(*f_iter, ifstyle) << ";" << endl;
+    // TODO(dreiss): Use private inheritance to avoid generating thise in cob-style.
+    if (style == "Concurrent" && !(*f_iter)->is_oneway()) {
+      // concurrent clients need to move the seqid from the send function to the
+      // recv function.  Oneway methods don't have a recv function, so we don't need to
+      // move the seqid for them.  Attempting to do so would result in a seqid leak.
+      t_function send_function(g_type_i32, /*returning seqid*/
+                               string("send_") + (*f_iter)->get_name(),
+                               (*f_iter)->get_arglist());
+      indent(f_header_) << function_signature(&send_function, "") << ";" << endl;
+    } else {
+      t_function send_function(g_type_void,
+                               string("send_") + (*f_iter)->get_name(),
+                               (*f_iter)->get_arglist());
+      indent(f_header_) << function_signature(&send_function, "") << ";" << endl;
+    }
+    if (!(*f_iter)->is_oneway()) {
+      if (style == "Concurrent") {
+        t_field seqIdArg(g_type_i32, "seqid");
+        t_struct seqIdArgStruct(program_);
+        seqIdArgStruct.append(&seqIdArg);
+        t_function recv_function((*f_iter)->get_returntype(),
+                                 string("recv_") + (*f_iter)->get_name(),
+                                 &seqIdArgStruct);
+        indent(f_header_) << function_signature(&recv_function, "") << ";" << endl;
+      } else {
+        t_struct noargs(program_);
+        t_function recv_function((*f_iter)->get_returntype(),
+                                 string("recv_") + (*f_iter)->get_name(),
+                                 &noargs);
+        indent(f_header_) << function_signature(&recv_function, "") << ";" << endl;
+      }
+    }
+  }
+  indent_down();
+
+  if (extends.empty()) {
+    f_header_ << " protected:" << endl;
+    indent_up();
+
+    if (style == "Cob") {
+      f_header_ << indent()
+                << "::std::shared_ptr< ::apache::thrift::async::TAsyncChannel> channel_;" << endl
+                << indent()
+                << "::std::shared_ptr< ::apache::thrift::transport::TMemoryBuffer> itrans_;" << endl
+                << indent()
+                << "::std::shared_ptr< ::apache::thrift::transport::TMemoryBuffer> otrans_;"
+                << endl;
+    }
+    f_header_ <<
+      indent() << prot_ptr << " piprot_;" << endl <<
+      indent() << prot_ptr << " poprot_;" << endl <<
+      indent() << protocol_type << "* iprot_;" << endl <<
+      indent() << protocol_type << "* oprot_;" << endl;
+
+    if (style == "Concurrent") {
+      f_header_ <<
+        indent() << "::apache::thrift::async::TConcurrentClientSyncInfo sync_;"<<endl;
+    }
+    indent_down();
+  }
+
+  f_header_ << "};" << endl << endl;
+
+  if (gen_templates_) {
+    // Output a backwards compatibility typedef using
+    // TProtocol as the template parameter.
+    f_header_ << "typedef " << service_name_ << style
+              << "ClientT< ::apache::thrift::protocol::TProtocol> " << service_name_ << style
+              << "Client;" << endl << endl;
+  }
+
+  string scope = service_name_ + style + client_suffix + "::";
+
+  // Generate client method implementations
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string seqIdCapture;
+    string seqIdUse;
+    string seqIdCommaUse;
+    if (style == "Concurrent" && !(*f_iter)->is_oneway()) {
+      seqIdCapture = "int32_t seqid = ";
+      seqIdUse = "seqid";
+      seqIdCommaUse = ", seqid";
+    }
+
+    string funname = (*f_iter)->get_name();
+
+    // Open function
+    if (gen_templates_) {
+      indent(out) << template_header;
+    }
+    indent(out) << function_signature(*f_iter, ifstyle, scope) << endl;
+    scope_up(out);
+    indent(out) << seqIdCapture << "send_" << funname << "(";
+
+    // Get the struct of function call params
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+
+    // Declare the function arguments
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        out << ", ";
+      }
+      out << (*fld_iter)->get_name();
+    }
+    out << ");" << endl;
+
+    if (style != "Cob") {
+      if (!(*f_iter)->is_oneway()) {
+        out << indent();
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          if (is_complex_type((*f_iter)->get_returntype())) {
+            out << "recv_" << funname << "(_return" << seqIdCommaUse << ");" << endl;
+          } else {
+            out << "return recv_" << funname << "(" << seqIdUse << ");" << endl;
+          }
+        } else {
+          out << "recv_" << funname << "(" << seqIdUse << ");" << endl;
+        }
+      }
+    } else {
+      if (!(*f_iter)->is_oneway()) {
+        out << indent() << _this << "channel_->sendAndRecvMessage("
+            << "::std::bind(cob, this), " << _this << "otrans_.get(), " << _this << "itrans_.get());"
+            << endl;
+      } else {
+        out << indent() << _this << "channel_->sendMessage("
+            << "::std::bind(cob, this), " << _this << "otrans_.get());" << endl;
+      }
+    }
+    scope_down(out);
+    out << endl;
+
+    // if (style != "Cob") // TODO(dreiss): Libify the client and don't generate this for cob-style
+    if (true) {
+      t_type* send_func_return_type = g_type_void;
+      if (style == "Concurrent" && !(*f_iter)->is_oneway()) {
+        send_func_return_type = g_type_i32;
+      }
+      // Function for sending
+      t_function send_function(send_func_return_type,
+                               string("send_") + (*f_iter)->get_name(),
+                               (*f_iter)->get_arglist());
+
+      // Open the send function
+      if (gen_templates_) {
+        indent(out) << template_header;
+      }
+      indent(out) << function_signature(&send_function, "", scope) << endl;
+      scope_up(out);
+
+      // Function arguments and results
+      string argsname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs";
+      string resultname = tservice->get_name() + "_" + (*f_iter)->get_name() + "_presult";
+
+      string cseqidVal = "0";
+      if (style == "Concurrent") {
+        if (!(*f_iter)->is_oneway()) {
+          cseqidVal = "this->sync_.generateSeqId()";
+        }
+      }
+      // Serialize the request
+      out <<
+        indent() << "int32_t cseqid = " << cseqidVal << ";" << endl;
+      if(style == "Concurrent") {
+        out <<
+          indent() << "::apache::thrift::async::TConcurrentSendSentry sentry(&this->sync_);" << endl;
+      }
+      if (style == "Cob") {
+        out <<
+          indent() << _this << "otrans_->resetBuffer();" << endl;
+      }
+      out <<
+        indent() << _this << "oprot_->writeMessageBegin(\"" <<
+        (*f_iter)->get_name() <<
+        "\", ::apache::thrift::protocol::" << ((*f_iter)->is_oneway() ? "T_ONEWAY" : "T_CALL") <<
+        ", cseqid);" << endl << endl <<
+        indent() << argsname << " args;" << endl;
+
+      for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+        out << indent() << "args." << (*fld_iter)->get_name() << " = &" << (*fld_iter)->get_name()
+            << ";" << endl;
+      }
+
+      out << indent() << "args.write(" << _this << "oprot_);" << endl << endl << indent() << _this
+          << "oprot_->writeMessageEnd();" << endl << indent() << _this
+          << "oprot_->getTransport()->writeEnd();" << endl << indent() << _this
+          << "oprot_->getTransport()->flush();" << endl;
+
+      if (style == "Concurrent") {
+        out << endl << indent() << "sentry.commit();" << endl;
+
+        if (!(*f_iter)->is_oneway()) {
+          out << indent() << "return cseqid;" << endl;
+        }
+      }
+      scope_down(out);
+      out << endl;
+
+      // Generate recv function only if not an oneway function
+      if (!(*f_iter)->is_oneway()) {
+        t_struct noargs(program_);
+
+        t_field seqIdArg(g_type_i32, "seqid");
+        t_struct seqIdArgStruct(program_);
+        seqIdArgStruct.append(&seqIdArg);
+
+        t_struct* recv_function_args = &noargs;
+        if (style == "Concurrent") {
+          recv_function_args = &seqIdArgStruct;
+        }
+
+        t_function recv_function((*f_iter)->get_returntype(),
+                                 string("recv_") + (*f_iter)->get_name(),
+                                 recv_function_args);
+        // Open the recv function
+        if (gen_templates_) {
+          indent(out) << template_header;
+        }
+        indent(out) << function_signature(&recv_function, "", scope) << endl;
+        scope_up(out);
+
+        out << endl <<
+          indent() << "int32_t rseqid = 0;" << endl <<
+          indent() << "std::string fname;" << endl <<
+          indent() << "::apache::thrift::protocol::TMessageType mtype;" << endl;
+        if(style == "Concurrent") {
+          out <<
+            endl <<
+            indent() << "// the read mutex gets dropped and reacquired as part of waitForWork()" << endl <<
+            indent() << "// The destructor of this sentry wakes up other clients" << endl <<
+            indent() << "::apache::thrift::async::TConcurrentRecvSentry sentry(&this->sync_, seqid);" << endl;
+        }
+        if (style == "Cob" && !gen_no_client_completion_) {
+          out << indent() << "bool completed = false;" << endl << endl << indent() << "try {";
+          indent_up();
+        }
+        out << endl;
+        if (style == "Concurrent") {
+          out <<
+            indent() << "while(true) {" << endl <<
+            indent() << "  if(!this->sync_.getPending(fname, mtype, rseqid)) {" << endl;
+          indent_up();
+          indent_up();
+        }
+        out <<
+          indent() << _this << "iprot_->readMessageBegin(fname, mtype, rseqid);" << endl;
+        if (style == "Concurrent") {
+          scope_down(out);
+          out << indent() << "if(seqid == rseqid) {" << endl;
+          indent_up();
+        }
+        out <<
+          indent() << "if (mtype == ::apache::thrift::protocol::T_EXCEPTION) {" << endl <<
+          indent() << "  ::apache::thrift::TApplicationException x;" << endl <<
+          indent() << "  x.read(" << _this << "iprot_);" << endl <<
+          indent() << "  " << _this << "iprot_->readMessageEnd();" << endl <<
+          indent() << "  " << _this << "iprot_->getTransport()->readEnd();" << endl;
+        if (style == "Cob" && !gen_no_client_completion_) {
+          out << indent() << "  completed = true;" << endl << indent() << "  completed__(true);"
+              << endl;
+        }
+        if (style == "Concurrent") {
+          out << indent() << "  sentry.commit();" << endl;
+        }
+        out <<
+          indent() << "  throw x;" << endl <<
+          indent() << "}" << endl <<
+          indent() << "if (mtype != ::apache::thrift::protocol::T_REPLY) {" << endl <<
+          indent() << "  " << _this << "iprot_->skip(" << "::apache::thrift::protocol::T_STRUCT);" << endl <<
+          indent() << "  " << _this << "iprot_->readMessageEnd();" << endl <<
+          indent() << "  " << _this << "iprot_->getTransport()->readEnd();" << endl;
+        if (style == "Cob" && !gen_no_client_completion_) {
+          out << indent() << "  completed = true;" << endl << indent() << "  completed__(false);"
+              << endl;
+        }
+        out <<
+          indent() << "}" << endl <<
+          indent() << "if (fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl <<
+          indent() << "  " << _this << "iprot_->skip(" << "::apache::thrift::protocol::T_STRUCT);" << endl <<
+          indent() << "  " << _this << "iprot_->readMessageEnd();" << endl <<
+          indent() << "  " << _this << "iprot_->getTransport()->readEnd();" << endl;
+        if (style == "Cob" && !gen_no_client_completion_) {
+          out << indent() << "  completed = true;" << endl << indent() << "  completed__(false);"
+              << endl;
+        }
+        if (style == "Concurrent") {
+          out << endl <<
+            indent() << "  // in a bad state, don't commit" << endl <<
+            indent() << "  using ::apache::thrift::protocol::TProtocolException;" << endl <<
+            indent() << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
+        }
+        out << indent() << "}" << endl;
+
+        if (!(*f_iter)->get_returntype()->is_void()
+            && !is_complex_type((*f_iter)->get_returntype())) {
+          t_field returnfield((*f_iter)->get_returntype(), "_return");
+          out << indent() << declare_field(&returnfield) << endl;
+        }
+
+        out << indent() << resultname << " result;" << endl;
+
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          out << indent() << "result.success = &_return;" << endl;
+        }
+
+        out << indent() << "result.read(" << _this << "iprot_);" << endl << indent() << _this
+            << "iprot_->readMessageEnd();" << endl << indent() << _this
+            << "iprot_->getTransport()->readEnd();" << endl << endl;
+
+        // Careful, only look for _result if not a void function
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          if (is_complex_type((*f_iter)->get_returntype())) {
+            out <<
+              indent() << "if (result.__isset.success) {" << endl;
+            out <<
+              indent() << "  // _return pointer has now been filled" << endl;
+            if (style == "Cob" && !gen_no_client_completion_) {
+              out << indent() << "  completed = true;" << endl << indent() << "  completed__(true);"
+                  << endl;
+            }
+            if (style == "Concurrent") {
+              out << indent() << "  sentry.commit();" << endl;
+            }
+            out <<
+              indent() << "  return;" << endl <<
+              indent() << "}" << endl;
+          } else {
+            out << indent() << "if (result.__isset.success) {" << endl;
+            if (style == "Cob" && !gen_no_client_completion_) {
+              out << indent() << "  completed = true;" << endl << indent() << "  completed__(true);"
+                  << endl;
+            }
+            if (style == "Concurrent") {
+              out << indent() << "  sentry.commit();" << endl;
+            }
+            out << indent() << "  return _return;" << endl << indent() << "}" << 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) {
+          out << indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl;
+          if (style == "Cob" && !gen_no_client_completion_) {
+            out << indent() << "  completed = true;" << endl << indent() << "  completed__(true);"
+                << endl;
+          }
+          if (style == "Concurrent") {
+            out << indent() << "  sentry.commit();" << endl;
+          }
+          out << indent() << "  throw result." << (*x_iter)->get_name() << ";" << endl << indent()
+              << "}" << endl;
+        }
+
+        // We only get here if we are a void function
+        if ((*f_iter)->get_returntype()->is_void()) {
+          if (style == "Cob" && !gen_no_client_completion_) {
+            out << indent() << "completed = true;" << endl << indent() << "completed__(true);"
+                << endl;
+          }
+          if (style == "Concurrent") {
+            out << indent() << "sentry.commit();" << endl;
+          }
+          indent(out) << "return;" << endl;
+        } else {
+          if (style == "Cob" && !gen_no_client_completion_) {
+            out << indent() << "completed = true;" << endl << indent() << "completed__(true);"
+                << endl;
+          }
+          if (style == "Concurrent") {
+            out << indent() << "// in a bad state, don't commit" << endl;
+          }
+          out << indent() << "throw "
+                             "::apache::thrift::TApplicationException(::apache::thrift::"
+                             "TApplicationException::MISSING_RESULT, \"" << (*f_iter)->get_name()
+              << " failed: unknown result\");" << endl;
+        }
+        if (style == "Concurrent") {
+          indent_down();
+          indent_down();
+          out <<
+            indent() << "  }" << endl <<
+            indent() << "  // seqid != rseqid" << endl <<
+            indent() << "  this->sync_.updatePending(fname, mtype, rseqid);" << endl <<
+            endl <<
+            indent() << "  // this will temporarily unlock the readMutex, and let other clients get work done" << endl <<
+            indent() << "  this->sync_.waitForWork(seqid);" << endl <<
+            indent() << "} // end while(true)" << endl;
+        }
+        if (style == "Cob" && !gen_no_client_completion_) {
+          indent_down();
+          out << indent() << "} catch (...) {" << endl << indent() << "  if (!completed) {" << endl
+              << indent() << "    completed__(false);" << endl << indent() << "  }" << endl
+              << indent() << "  throw;" << endl << indent() << "}" << endl;
+        }
+        // Close function
+        scope_down(out);
+        out << endl;
+      }
+    }
+  }
+}
+
+class ProcessorGenerator {
+public:
+  ProcessorGenerator(t_cpp_generator* generator, t_service* service, const string& style);
+
+  void run() {
+    generate_class_definition();
+
+    // Generate the dispatchCall() function
+    generate_dispatch_call(false);
+    if (generator_->gen_templates_) {
+      generate_dispatch_call(true);
+    }
+
+    // Generate all of the process subfunctions
+    generate_process_functions();
+
+    generate_factory();
+  }
+
+  void generate_class_definition();
+  void generate_dispatch_call(bool template_protocol);
+  void generate_process_functions();
+  void generate_factory();
+
+protected:
+  std::string type_name(t_type* ttype, bool in_typedef = false, bool arg = false) {
+    return generator_->type_name(ttype, in_typedef, arg);
+  }
+
+  std::string indent() { return generator_->indent(); }
+  std::ostream& indent(std::ostream& os) { return generator_->indent(os); }
+
+  void indent_up() { generator_->indent_up(); }
+  void indent_down() { generator_->indent_down(); }
+
+  t_cpp_generator* generator_;
+  t_service* service_;
+  std::ostream& f_header_;
+  std::ostream& f_out_;
+  string service_name_;
+  string style_;
+  string pstyle_;
+  string class_name_;
+  string if_name_;
+  string factory_class_name_;
+  string finish_cob_;
+  string finish_cob_decl_;
+  string ret_type_;
+  string call_context_;
+  string cob_arg_;
+  string call_context_arg_;
+  string call_context_decl_;
+  string template_header_;
+  string template_suffix_;
+  string typename_str_;
+  string class_suffix_;
+  string extends_;
+};
+
+ProcessorGenerator::ProcessorGenerator(t_cpp_generator* generator,
+                                       t_service* service,
+                                       const string& style)
+  : generator_(generator),
+    service_(service),
+    f_header_(generator->f_header_),
+    f_out_(generator->gen_templates_ ? generator->f_service_tcc_ : generator->f_service_),
+    service_name_(generator->service_name_),
+    style_(style) {
+  if (style_ == "Cob") {
+    pstyle_ = "Async";
+    class_name_ = service_name_ + pstyle_ + "Processor";
+    if_name_ = service_name_ + "CobSvIf";
+
+    finish_cob_ = "::std::function<void(bool ok)> cob, ";
+    finish_cob_decl_ = "::std::function<void(bool ok)>, ";
+    cob_arg_ = "cob, ";
+    ret_type_ = "void ";
+  } else {
+    class_name_ = service_name_ + "Processor";
+    if_name_ = service_name_ + "If";
+
+    ret_type_ = "bool ";
+    // TODO(edhall) callContext should eventually be added to TAsyncProcessor
+    call_context_ = ", void* callContext";
+    call_context_arg_ = ", callContext";
+    call_context_decl_ = ", void*";
+  }
+
+  factory_class_name_ = class_name_ + "Factory";
+
+  if (generator->gen_templates_) {
+    template_header_ = "template <class Protocol_>\n";
+    template_suffix_ = "<Protocol_>";
+    typename_str_ = "typename ";
+    class_name_ += "T";
+    factory_class_name_ += "T";
+  }
+
+  if (service_->get_extends() != NULL) {
+    extends_ = type_name(service_->get_extends()) + pstyle_ + "Processor";
+    if (generator_->gen_templates_) {
+      // TODO(simpkins): If gen_templates_ is enabled, we currently assume all
+      // parent services were also generated with templates enabled.
+      extends_ += "T<Protocol_>";
+    }
+  }
+}
+
+void ProcessorGenerator::generate_class_definition() {
+  // Generate the dispatch methods
+  vector<t_function*> functions = service_->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string parent_class;
+  if (service_->get_extends() != NULL) {
+    parent_class = extends_;
+  } else {
+    if (style_ == "Cob") {
+      parent_class = "::apache::thrift::async::TAsyncDispatchProcessor";
+    } else {
+      parent_class = "::apache::thrift::TDispatchProcessor";
+    }
+
+    if (generator_->gen_templates_) {
+      parent_class += "T<Protocol_>";
+    }
+  }
+
+  // Generate the header portion
+  f_header_ << template_header_ << "class " << class_name_ << " : public " << parent_class << " {"
+            << endl;
+
+  // Protected data members
+  f_header_ << " protected:" << endl;
+  indent_up();
+  f_header_ << indent() << "::std::shared_ptr<" << if_name_ << "> iface_;" << endl;
+  f_header_ << indent() << "virtual " << ret_type_ << "dispatchCall(" << finish_cob_
+            << "::apache::thrift::protocol::TProtocol* iprot, "
+            << "::apache::thrift::protocol::TProtocol* oprot, "
+            << "const std::string& fname, int32_t seqid" << call_context_ << ");" << endl;
+  if (generator_->gen_templates_) {
+    f_header_ << indent() << "virtual " << ret_type_ << "dispatchCallTemplated(" << finish_cob_
+              << "Protocol_* iprot, Protocol_* oprot, "
+              << "const std::string& fname, int32_t seqid" << call_context_ << ");" << endl;
+  }
+  indent_down();
+
+  // Process function declarations
+  f_header_ << " private:" << endl;
+  indent_up();
+
+  // Declare processMap_
+  f_header_ << indent() << "typedef  void (" << class_name_ << "::*"
+            << "ProcessFunction)(" << finish_cob_decl_ << "int32_t, "
+            << "::apache::thrift::protocol::TProtocol*, "
+            << "::apache::thrift::protocol::TProtocol*" << call_context_decl_ << ");" << endl;
+  if (generator_->gen_templates_) {
+    f_header_ << indent() << "typedef void (" << class_name_ << "::*"
+              << "SpecializedProcessFunction)(" << finish_cob_decl_ << "int32_t, "
+              << "Protocol_*, Protocol_*" << call_context_decl_ << ");" << endl << indent()
+              << "struct ProcessFunctions {" << endl << indent() << "  ProcessFunction generic;"
+              << endl << indent() << "  SpecializedProcessFunction specialized;" << endl << indent()
+              << "  ProcessFunctions(ProcessFunction g, "
+              << "SpecializedProcessFunction s) :" << endl << indent() << "    generic(g)," << endl
+              << indent() << "    specialized(s) {}" << endl << indent()
+              << "  ProcessFunctions() : generic(NULL), specialized(NULL) "
+              << "{}" << endl << indent() << "};" << endl << indent()
+              << "typedef std::map<std::string, ProcessFunctions> "
+              << "ProcessMap;" << endl;
+  } else {
+    f_header_ << indent() << "typedef std::map<std::string, ProcessFunction> "
+              << "ProcessMap;" << endl;
+  }
+  f_header_ << indent() << "ProcessMap processMap_;" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    indent(f_header_) << "void process_" << (*f_iter)->get_name() << "(" << finish_cob_
+                      << "int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, "
+                         "::apache::thrift::protocol::TProtocol* oprot" << call_context_ << ");"
+                      << endl;
+    if (generator_->gen_templates_) {
+      indent(f_header_) << "void process_" << (*f_iter)->get_name() << "(" << finish_cob_
+                        << "int32_t seqid, Protocol_* iprot, Protocol_* oprot" << call_context_
+                        << ");" << endl;
+    }
+    if (style_ == "Cob") {
+      // XXX Factor this out, even if it is a pain.
+      string ret_arg = ((*f_iter)->get_returntype()->is_void()
+                            ? ""
+                            : ", const " + type_name((*f_iter)->get_returntype()) + "& _return");
+      f_header_ << indent() << "void return_" << (*f_iter)->get_name()
+                << "(::std::function<void(bool ok)> cob, int32_t seqid, "
+                << "::apache::thrift::protocol::TProtocol* oprot, "
+                << "void* ctx" << ret_arg << ");" << endl;
+      if (generator_->gen_templates_) {
+        f_header_ << indent() << "void return_" << (*f_iter)->get_name()
+                  << "(::std::function<void(bool ok)> cob, int32_t seqid, "
+                  << "Protocol_* oprot, void* ctx" << ret_arg << ");" << endl;
+      }
+      // XXX Don't declare throw if it doesn't exist
+      f_header_ << indent() << "void throw_" << (*f_iter)->get_name()
+                << "(::std::function<void(bool ok)> cob, int32_t seqid, "
+                << "::apache::thrift::protocol::TProtocol* oprot, void* ctx, "
+                << "::apache::thrift::TDelayedException* _throw);" << endl;
+      if (generator_->gen_templates_) {
+        f_header_ << indent() << "void throw_" << (*f_iter)->get_name()
+                  << "(::std::function<void(bool ok)> cob, int32_t seqid, "
+                  << "Protocol_* oprot, void* ctx, "
+                  << "::apache::thrift::TDelayedException* _throw);" << endl;
+      }
+    }
+  }
+
+  f_header_ << " public:" << endl << indent() << class_name_ << "(::std::shared_ptr<" << if_name_
+            << "> iface) :" << endl;
+  if (!extends_.empty()) {
+    f_header_ << indent() << "  " << extends_ << "(iface)," << endl;
+  }
+  f_header_ << indent() << "  iface_(iface) {" << endl;
+  indent_up();
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_header_ << indent() << "processMap_[\"" << (*f_iter)->get_name() << "\"] = ";
+    if (generator_->gen_templates_) {
+      f_header_ << "ProcessFunctions(" << endl;
+      if (generator_->gen_templates_only_) {
+        indent(f_header_) << "  NULL," << endl;
+      } else {
+        indent(f_header_) << "  &" << class_name_ << "::process_" << (*f_iter)->get_name() << ","
+                          << endl;
+      }
+      indent(f_header_) << "  &" << class_name_ << "::process_" << (*f_iter)->get_name() << ")";
+    } else {
+      f_header_ << "&" << class_name_ << "::process_" << (*f_iter)->get_name();
+    }
+    f_header_ << ";" << endl;
+  }
+
+  indent_down();
+  f_header_ << indent() << "}" << endl << endl << indent() << "virtual ~" << class_name_ << "() {}"
+            << endl;
+  indent_down();
+  f_header_ << "};" << endl << endl;
+
+  if (generator_->gen_templates_) {
+    // Generate a backwards compatible typedef, for callers who don't know
+    // about the new template-style code.
+    //
+    // We can't use TProtocol as the template parameter, since ProcessorT
+    // provides overloaded versions of most methods, one of which accepts
+    // TProtocol pointers, and one which accepts Protocol_ pointers.  This
+    // results in a compile error if instantiated with Protocol_ == TProtocol.
+    // Therefore, we define TDummyProtocol solely so we can use it as the
+    // template parameter here.
+    f_header_ << "typedef " << class_name_ << "< ::apache::thrift::protocol::TDummyProtocol > "
+              << service_name_ << pstyle_ << "Processor;" << endl << endl;
+  }
+}
+
+void ProcessorGenerator::generate_dispatch_call(bool template_protocol) {
+  string protocol = "::apache::thrift::protocol::TProtocol";
+  string function_suffix;
+  if (template_protocol) {
+    protocol = "Protocol_";
+    // We call the generic version dispatchCall(), and the specialized
+    // version dispatchCallTemplated().  We can't call them both
+    // dispatchCall(), since this will cause the compiler to issue a warning if
+    // a service that doesn't use templates inherits from a service that does
+    // use templates: the compiler complains that the subclass only implements
+    // the generic version of dispatchCall(), and hides the templated version.
+    // Using different names for the two functions prevents this.
+    function_suffix = "Templated";
+  }
+
+  f_out_ << template_header_ << ret_type_ << class_name_ << template_suffix_ << "::dispatchCall"
+         << function_suffix << "(" << finish_cob_ << protocol << "* iprot, " << protocol
+         << "* oprot, "
+         << "const std::string& fname, int32_t seqid" << call_context_ << ") {" << endl;
+  indent_up();
+
+  // HOT: member function pointer map
+  f_out_ << indent() << typename_str_ << "ProcessMap::iterator pfn;" << endl << indent()
+         << "pfn = processMap_.find(fname);" << endl << indent()
+         << "if (pfn == processMap_.end()) {" << endl;
+  if (extends_.empty()) {
+    f_out_ << indent() << "  iprot->skip(::apache::thrift::protocol::T_STRUCT);" << endl << indent()
+           << "  iprot->readMessageEnd();" << endl << indent()
+           << "  iprot->getTransport()->readEnd();" << endl << indent()
+           << "  ::apache::thrift::TApplicationException "
+              "x(::apache::thrift::TApplicationException::UNKNOWN_METHOD, \"Invalid method name: "
+              "'\"+fname+\"'\");" << endl << indent()
+           << "  oprot->writeMessageBegin(fname, ::apache::thrift::protocol::T_EXCEPTION, seqid);"
+           << endl << indent() << "  x.write(oprot);" << endl << indent()
+           << "  oprot->writeMessageEnd();" << endl << indent()
+           << "  oprot->getTransport()->writeEnd();" << endl << indent()
+           << "  oprot->getTransport()->flush();" << endl << indent()
+           << (style_ == "Cob" ? "  return cob(true);" : "  return true;") << endl;
+  } else {
+    f_out_ << indent() << "  return " << extends_ << "::dispatchCall("
+           << (style_ == "Cob" ? "cob, " : "") << "iprot, oprot, fname, seqid" << call_context_arg_
+           << ");" << endl;
+  }
+  f_out_ << indent() << "}" << endl;
+  if (template_protocol) {
+    f_out_ << indent() << "(this->*(pfn->second.specialized))";
+  } else {
+    if (generator_->gen_templates_only_) {
+      // TODO: This is a null pointer, so nothing good will come from calling
+      // it.  Throw an exception instead.
+      f_out_ << indent() << "(this->*(pfn->second.generic))";
+    } else if (generator_->gen_templates_) {
+      f_out_ << indent() << "(this->*(pfn->second.generic))";
+    } else {
+      f_out_ << indent() << "(this->*(pfn->second))";
+    }
+  }
+  f_out_ << "(" << cob_arg_ << "seqid, iprot, oprot" << call_context_arg_ << ");" << endl;
+
+  // TODO(dreiss): return pfn ret?
+  if (style_ == "Cob") {
+    f_out_ << indent() << "return;" << endl;
+  } else {
+    f_out_ << indent() << "return true;" << endl;
+  }
+
+  indent_down();
+  f_out_ << "}" << endl << endl;
+}
+
+void ProcessorGenerator::generate_process_functions() {
+  vector<t_function*> functions = service_->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    if (generator_->gen_templates_) {
+      generator_->generate_process_function(service_, *f_iter, style_, false);
+      generator_->generate_process_function(service_, *f_iter, style_, true);
+    } else {
+      generator_->generate_process_function(service_, *f_iter, style_, false);
+    }
+  }
+}
+
+void ProcessorGenerator::generate_factory() {
+  string if_factory_name = if_name_ + "Factory";
+
+  // Generate the factory class definition
+  f_header_ << template_header_ << "class " << factory_class_name_ << " : public ::apache::thrift::"
+            << (style_ == "Cob" ? "async::TAsyncProcessorFactory" : "TProcessorFactory") << " {"
+            << endl << " public:" << endl;
+  indent_up();
+
+  f_header_ << indent() << factory_class_name_ << "(const ::std::shared_ptr< " << if_factory_name
+            << " >& handlerFactory) :" << endl << indent()
+            << "    handlerFactory_(handlerFactory) {}" << endl << endl << indent()
+            << "::std::shared_ptr< ::apache::thrift::"
+            << (style_ == "Cob" ? "async::TAsyncProcessor" : "TProcessor") << " > "
+            << "getProcessor(const ::apache::thrift::TConnectionInfo& connInfo);" << endl;
+
+  f_header_ << endl << " protected:" << endl << indent() << "::std::shared_ptr< "
+            << if_factory_name << " > handlerFactory_;" << endl;
+
+  indent_down();
+  f_header_ << "};" << endl << endl;
+
+  // If we are generating templates, output a typedef for the plain
+  // factory name.
+  if (generator_->gen_templates_) {
+    f_header_ << "typedef " << factory_class_name_
+              << "< ::apache::thrift::protocol::TDummyProtocol > " << service_name_ << pstyle_
+              << "ProcessorFactory;" << endl << endl;
+  }
+
+  // Generate the getProcessor() method
+  f_out_ << template_header_ << indent() << "::std::shared_ptr< ::apache::thrift::"
+         << (style_ == "Cob" ? "async::TAsyncProcessor" : "TProcessor") << " > "
+         << factory_class_name_ << template_suffix_ << "::getProcessor("
+         << "const ::apache::thrift::TConnectionInfo& connInfo) {" << endl;
+  indent_up();
+
+  f_out_ << indent() << "::apache::thrift::ReleaseHandler< " << if_factory_name
+         << " > cleanup(handlerFactory_);" << endl << indent() << "::std::shared_ptr< "
+         << if_name_ << " > handler("
+         << "handlerFactory_->getHandler(connInfo), cleanup);" << endl << indent()
+         << "::std::shared_ptr< ::apache::thrift::"
+         << (style_ == "Cob" ? "async::TAsyncProcessor" : "TProcessor") << " > "
+         << "processor(new " << class_name_ << template_suffix_ << "(handler));" << endl << indent()
+         << "return processor;" << endl;
+
+  indent_down();
+  f_out_ << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates a service processor definition.
+ *
+ * @param tservice The service to generate a processor for.
+ */
+void t_cpp_generator::generate_service_processor(t_service* tservice, string style) {
+  ProcessorGenerator generator(this, tservice, style);
+  generator.run();
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_cpp_generator::generate_function_helpers(t_service* tservice, t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return;
+  }
+
+  std::ostream& out = (gen_templates_ ? f_service_tcc_ : f_service_);
+
+  t_struct result(program_, tservice->get_name() + "_" + 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_struct_declaration(f_header_, &result, false);
+  generate_struct_definition(out, f_service_, &result, false);
+  generate_struct_reader(out, &result);
+  generate_struct_result_writer(out, &result);
+
+  result.set_name(tservice->get_name() + "_" + tfunction->get_name() + "_presult");
+  generate_struct_declaration(f_header_, &result, false, true, true, gen_cob_style_);
+  generate_struct_definition(out, f_service_, &result, false);
+  generate_struct_reader(out, &result, true);
+  if (gen_cob_style_) {
+    generate_struct_writer(out, &result, true);
+  }
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_cpp_generator::generate_process_function(t_service* tservice,
+                                                t_function* tfunction,
+                                                string style,
+                                                bool specialized) {
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+  string service_func_name = "\"" + tservice->get_name() + "." + tfunction->get_name() + "\"";
+
+  std::ostream& out = (gen_templates_ ? f_service_tcc_ : f_service_);
+
+  string prot_type = (specialized ? "Protocol_" : "::apache::thrift::protocol::TProtocol");
+  string class_suffix;
+  if (gen_templates_) {
+    class_suffix = "T<Protocol_>";
+  }
+
+  // I tried to do this as one function.  I really did.  But it was too hard.
+  if (style != "Cob") {
+    // Open function
+    if (gen_templates_) {
+      out << indent() << "template <class Protocol_>" << endl;
+    }
+    const bool unnamed_oprot_seqid = tfunction->is_oneway() && !(gen_templates_ && !specialized);
+    out << "void " << tservice->get_name() << "Processor" << class_suffix << "::"
+        << "process_" << tfunction->get_name() << "("
+        << "int32_t" << (unnamed_oprot_seqid ? ", " : " seqid, ") << prot_type << "* iprot, "
+        << prot_type << "*" << (unnamed_oprot_seqid ? ", " : " oprot, ") << "void* callContext)"
+        << endl;
+    scope_up(out);
+
+    string argsname = tservice->get_name() + "_" + tfunction->get_name() + "_args";
+    string resultname = tservice->get_name() + "_" + tfunction->get_name() + "_result";
+
+    if (tfunction->is_oneway() && !unnamed_oprot_seqid) {
+      out << indent() << "(void) seqid;" << endl << indent() << "(void) oprot;" << endl;
+    }
+
+    out << indent() << "void* ctx = NULL;" << endl << indent()
+        << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+        << "  ctx = this->eventHandler_->getContext(" << service_func_name << ", callContext);"
+        << endl << indent() << "}" << endl << indent()
+        << "::apache::thrift::TProcessorContextFreer freer("
+        << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl
+        << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+        << "  this->eventHandler_->preRead(ctx, " << service_func_name << ");" << endl << indent()
+        << "}" << endl << endl << indent() << argsname << " args;" << endl << indent()
+        << "args.read(iprot);" << endl << indent() << "iprot->readMessageEnd();" << endl << indent()
+        << "uint32_t bytes = iprot->getTransport()->readEnd();" << endl << endl << indent()
+        << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+        << "  this->eventHandler_->postRead(ctx, " << service_func_name << ", bytes);" << endl
+        << indent() << "}" << endl << endl;
+
+    // Declare result
+    if (!tfunction->is_oneway()) {
+      out << indent() << resultname << " result;" << endl;
+    }
+
+    // Try block for functions with exceptions
+    out << indent() << "try {" << endl;
+    indent_up();
+
+    // Generate the function call
+    bool first = true;
+    out << indent();
+    if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+      if (is_complex_type(tfunction->get_returntype())) {
+        first = false;
+        out << "iface_->" << tfunction->get_name() << "(result.success";
+      } else {
+        out << "result.success = iface_->" << tfunction->get_name() << "(";
+      }
+    } else {
+      out << "iface_->" << tfunction->get_name() << "(";
+    }
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      if (first) {
+        first = false;
+      } else {
+        out << ", ";
+      }
+      out << "args." << (*f_iter)->get_name();
+    }
+    out << ");" << endl;
+
+    // Set isset on success field
+    if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+      out << indent() << "result.__isset.success = true;" << endl;
+    }
+
+    indent_down();
+    out << indent() << "}";
+
+    if (!tfunction->is_oneway()) {
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        out << " catch (" << type_name((*x_iter)->get_type()) << " &" << (*x_iter)->get_name()
+            << ") {" << endl;
+        if (!tfunction->is_oneway()) {
+          indent_up();
+          out << indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name()
+              << ";" << endl << indent() << "result.__isset." << (*x_iter)->get_name() << " = true;"
+              << endl;
+          indent_down();
+          out << indent() << "}";
+        } else {
+          out << "}";
+        }
+      }
+    }
+
+    if (!tfunction->is_oneway()) {
+      out << " catch (const std::exception& e) {" << endl;
+    } else {
+      out << " catch (const std::exception&) {" << endl;
+    }
+
+    indent_up();
+    out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+        << "  this->eventHandler_->handlerError(ctx, " << service_func_name << ");" << endl
+        << indent() << "}" << endl;
+
+    if (!tfunction->is_oneway()) {
+      out << endl << indent() << "::apache::thrift::TApplicationException x(e.what());" << endl
+          << indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name()
+          << "\", ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl << indent()
+          << "x.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl
+          << indent() << "oprot->getTransport()->writeEnd();" << endl << indent()
+          << "oprot->getTransport()->flush();" << endl;
+    }
+    out << indent() << "return;" << endl;
+    indent_down();
+    out << indent() << "}" << endl << endl;
+
+    // Shortcut out here for oneway functions
+    if (tfunction->is_oneway()) {
+      out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+          << "  this->eventHandler_->asyncComplete(ctx, " << service_func_name << ");" << endl
+          << indent() << "}" << endl << endl << indent() << "return;" << endl;
+      indent_down();
+      out << "}" << endl << endl;
+      return;
+    }
+
+    // Serialize the result into a struct
+    out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+        << "  this->eventHandler_->preWrite(ctx, " << service_func_name << ");" << endl << indent()
+        << "}" << endl << endl << indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name()
+        << "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl << indent()
+        << "result.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl
+        << indent() << "bytes = oprot->getTransport()->writeEnd();" << endl << indent()
+        << "oprot->getTransport()->flush();" << endl << endl << indent()
+        << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+        << "  this->eventHandler_->postWrite(ctx, " << service_func_name << ", bytes);" << endl
+        << indent() << "}" << endl;
+
+    // Close function
+    scope_down(out);
+    out << endl;
+  }
+
+  // Cob style.
+  else {
+    // Processor entry point.
+    // TODO(edhall) update for callContext when TEventServer is ready
+    if (gen_templates_) {
+      out << indent() << "template <class Protocol_>" << endl;
+    }
+    out << "void " << tservice->get_name() << "AsyncProcessor" << class_suffix << "::process_"
+        << tfunction->get_name() << "(::std::function<void(bool ok)> cob, int32_t seqid, "
+        << prot_type << "* iprot, " << prot_type << "* oprot)" << endl;
+    scope_up(out);
+
+    // TODO(simpkins): we could try to consoldate this
+    // with the non-cob code above
+    if (gen_templates_ && !specialized) {
+      // If these are instances of Protocol_, instead of any old TProtocol,
+      // use the specialized process function instead.
+      out << indent() << "Protocol_* _iprot = dynamic_cast<Protocol_*>(iprot);" << endl << indent()
+          << "Protocol_* _oprot = dynamic_cast<Protocol_*>(oprot);" << endl << indent()
+          << "if (_iprot && _oprot) {" << endl << indent() << "  return process_"
+          << tfunction->get_name() << "(cob, seqid, _iprot, _oprot);" << endl << indent() << "}"
+          << endl << indent() << "T_GENERIC_PROTOCOL(this, iprot, _iprot);" << endl << indent()
+          << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" << endl << endl;
+    }
+
+    if (tfunction->is_oneway()) {
+      out << indent() << "(void) seqid;" << endl << indent() << "(void) oprot;" << endl;
+    }
+
+    out << indent() << tservice->get_name() + "_" + tfunction->get_name() << "_args args;" << endl
+        << indent() << "void* ctx = NULL;" << endl << indent()
+        << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+        << "  ctx = this->eventHandler_->getContext(" << service_func_name << ", NULL);" << endl
+        << indent() << "}" << endl << indent() << "::apache::thrift::TProcessorContextFreer freer("
+        << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl
+        << indent() << "try {" << endl;
+    indent_up();
+    out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+        << "  this->eventHandler_->preRead(ctx, " << service_func_name << ");" << endl << indent()
+        << "}" << endl << indent() << "args.read(iprot);" << endl << indent()
+        << "iprot->readMessageEnd();" << endl << indent()
+        << "uint32_t bytes = iprot->getTransport()->readEnd();" << endl << indent()
+        << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+        << "  this->eventHandler_->postRead(ctx, " << service_func_name << ", bytes);" << endl
+        << indent() << "}" << endl;
+    scope_down(out);
+
+    // TODO(dreiss): Handle TExceptions?  Expose to server?
+    out << indent() << "catch (const std::exception&) {" << endl << indent()
+        << "  if (this->eventHandler_.get() != NULL) {" << endl << indent()
+        << "    this->eventHandler_->handlerError(ctx, " << service_func_name << ");" << endl
+        << indent() << "  }" << endl << indent() << "  return cob(false);" << endl << indent()
+        << "}" << endl;
+
+    if (tfunction->is_oneway()) {
+      out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+          << "  this->eventHandler_->asyncComplete(ctx, " << service_func_name << ");" << endl
+          << indent() << "}" << endl;
+    }
+    // TODO(dreiss): Figure out a strategy for exceptions in async handlers.
+    out << indent() << "freer.unregister();" << endl;
+    if (tfunction->is_oneway()) {
+      // No return.  Just hand off our cob.
+      // TODO(dreiss): Call the cob immediately?
+      out << indent() << "iface_->" << tfunction->get_name() << "("
+          << "::std::bind(cob, true)" << endl;
+      indent_up();
+      indent_up();
+    } else {
+      string ret_arg, ret_placeholder;
+      if (!tfunction->get_returntype()->is_void()) {
+        ret_arg = ", const " + type_name(tfunction->get_returntype()) + "& _return";
+        ret_placeholder = ", ::std::placeholders::_1";
+      }
+
+      // When gen_templates_ is true, the return_ and throw_ functions are
+      // overloaded.  We have to declare pointers to them so that the compiler
+      // can resolve the correct overloaded version.
+      out << indent() << "void (" << tservice->get_name() << "AsyncProcessor" << class_suffix
+          << "::*return_fn)(::std::function<void(bool ok)> "
+          << "cob, int32_t seqid, " << prot_type << "* oprot, void* ctx" << ret_arg
+          << ") =" << endl;
+      out << indent() << "  &" << tservice->get_name() << "AsyncProcessor" << class_suffix
+          << "::return_" << tfunction->get_name() << ";" << endl;
+      if (!xceptions.empty()) {
+        out << indent() << "void (" << tservice->get_name() << "AsyncProcessor" << class_suffix
+            << "::*throw_fn)(::std::function<void(bool ok)> "
+            << "cob, int32_t seqid, " << prot_type << "* oprot, void* ctx, "
+            << "::apache::thrift::TDelayedException* _throw) =" << endl;
+        out << indent() << "  &" << tservice->get_name() << "AsyncProcessor" << class_suffix
+            << "::throw_" << tfunction->get_name() << ";" << endl;
+      }
+
+      out << indent() << "iface_->" << tfunction->get_name() << "(" << endl;
+      indent_up();
+      indent_up();
+      out << indent() << "::std::bind(return_fn, this, cob, seqid, oprot, ctx" << ret_placeholder
+          << ")";
+      if (!xceptions.empty()) {
+        out << ',' << endl << indent() << "::std::bind(throw_fn, this, cob, seqid, oprot, "
+            << "ctx, ::std::placeholders::_1)";
+      }
+    }
+
+    // XXX Whitespace cleanup.
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      out << ',' << endl << indent() << "args." << (*f_iter)->get_name();
+    }
+    out << ");" << endl;
+    indent_down();
+    indent_down();
+    scope_down(out);
+    out << endl;
+
+    // Normal return.
+    if (!tfunction->is_oneway()) {
+      string ret_arg_decl, ret_arg_name;
+      if (!tfunction->get_returntype()->is_void()) {
+        ret_arg_decl = ", const " + type_name(tfunction->get_returntype()) + "& _return";
+        ret_arg_name = ", _return";
+      }
+      if (gen_templates_) {
+        out << indent() << "template <class Protocol_>" << endl;
+      }
+      out << "void " << tservice->get_name() << "AsyncProcessor" << class_suffix << "::return_"
+          << tfunction->get_name() << "(::std::function<void(bool ok)> cob, int32_t seqid, "
+          << prot_type << "* oprot, void* ctx" << ret_arg_decl << ')' << endl;
+      scope_up(out);
+
+      if (gen_templates_ && !specialized) {
+        // If oprot is a Protocol_ instance,
+        // use the specialized return function instead.
+        out << indent() << "Protocol_* _oprot = dynamic_cast<Protocol_*>(oprot);" << endl
+            << indent() << "if (_oprot) {" << endl << indent() << "  return return_"
+            << tfunction->get_name() << "(cob, seqid, _oprot, ctx" << ret_arg_name << ");" << endl
+            << indent() << "}" << endl << indent() << "T_GENERIC_PROTOCOL(this, oprot, _oprot);"
+            << endl << endl;
+      }
+
+      out << indent() << tservice->get_name() << "_" << tfunction->get_name() << "_presult result;"
+          << endl;
+      if (!tfunction->get_returntype()->is_void()) {
+        // The const_cast here is unfortunate, but it would be a pain to avoid,
+        // and we only do a write with this struct, which is const-safe.
+        out << indent() << "result.success = const_cast<" << type_name(tfunction->get_returntype())
+            << "*>(&_return);" << endl << indent() << "result.__isset.success = true;" << endl;
+      }
+      // Serialize the result into a struct
+      out << endl << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+          << "  ctx = this->eventHandler_->getContext(" << service_func_name << ", NULL);" << endl
+          << indent() << "}" << endl << indent()
+          << "::apache::thrift::TProcessorContextFreer freer("
+          << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl
+          << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+          << "  this->eventHandler_->preWrite(ctx, " << service_func_name << ");" << endl
+          << indent() << "}" << endl << endl << indent() << "oprot->writeMessageBegin(\""
+          << tfunction->get_name() << "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl
+          << indent() << "result.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();"
+          << endl << indent() << "uint32_t bytes = oprot->getTransport()->writeEnd();" << endl
+          << indent() << "oprot->getTransport()->flush();" << endl << indent()
+          << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+          << "  this->eventHandler_->postWrite(ctx, " << service_func_name << ", bytes);" << endl
+          << indent() << "}" << endl << indent() << "return cob(true);" << endl;
+      scope_down(out);
+      out << endl;
+    }
+
+    // Exception return.
+    if (!tfunction->is_oneway() && !xceptions.empty()) {
+      if (gen_templates_) {
+        out << indent() << "template <class Protocol_>" << endl;
+      }
+      out << "void " << tservice->get_name() << "AsyncProcessor" << class_suffix << "::throw_"
+          << tfunction->get_name() << "(::std::function<void(bool ok)> cob, int32_t seqid, "
+          << prot_type << "* oprot, void* ctx, "
+          << "::apache::thrift::TDelayedException* _throw)" << endl;
+      scope_up(out);
+
+      if (gen_templates_ && !specialized) {
+        // If oprot is a Protocol_ instance,
+        // use the specialized throw function instead.
+        out << indent() << "Protocol_* _oprot = dynamic_cast<Protocol_*>(oprot);" << endl
+            << indent() << "if (_oprot) {" << endl << indent() << "  return throw_"
+            << tfunction->get_name() << "(cob, seqid, _oprot, ctx, _throw);" << endl << indent()
+            << "}" << endl << indent() << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" << endl
+            << endl;
+      }
+
+      // Get the event handler context
+      out << endl << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+          << "  ctx = this->eventHandler_->getContext(" << service_func_name << ", NULL);" << endl
+          << indent() << "}" << endl << indent()
+          << "::apache::thrift::TProcessorContextFreer freer("
+          << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl;
+
+      // Throw the TDelayedException, and catch the result
+      out << indent() << tservice->get_name() << "_" << tfunction->get_name() << "_result result;"
+          << endl << endl << indent() << "try {" << endl;
+      indent_up();
+      out << indent() << "_throw->throw_it();" << endl << indent() << "return cob(false);"
+          << endl; // Is this possible?  TBD.
+      indent_down();
+      out << indent() << '}';
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        out << "  catch (" << type_name((*x_iter)->get_type()) << " &" << (*x_iter)->get_name()
+            << ") {" << endl;
+        indent_up();
+        out << indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name()
+            << ";" << endl << indent() << "result.__isset." << (*x_iter)->get_name() << " = true;"
+            << endl;
+        scope_down(out);
+      }
+
+      // Handle the case where an undeclared exception is thrown
+      out << " catch (std::exception& e) {" << endl;
+      indent_up();
+      out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+          << "  this->eventHandler_->handlerError(ctx, " << service_func_name << ");" << endl
+          << indent() << "}" << endl << endl << indent()
+          << "::apache::thrift::TApplicationException x(e.what());" << endl << indent()
+          << "oprot->writeMessageBegin(\"" << tfunction->get_name()
+          << "\", ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl << indent()
+          << "x.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();" << endl
+          << indent() << "oprot->getTransport()->writeEnd();" << endl << indent()
+          << "oprot->getTransport()->flush();" << endl <<
+          // We pass true to the cob here, since we did successfully write a
+          // response, even though it is an exception response.
+          // It looks like the argument is currently ignored, anyway.
+          indent() << "return cob(true);" << endl;
+      scope_down(out);
+
+      // Serialize the result into a struct
+      out << indent() << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+          << "  this->eventHandler_->preWrite(ctx, " << service_func_name << ");" << endl
+          << indent() << "}" << endl << endl << indent() << "oprot->writeMessageBegin(\""
+          << tfunction->get_name() << "\", ::apache::thrift::protocol::T_REPLY, seqid);" << endl
+          << indent() << "result.write(oprot);" << endl << indent() << "oprot->writeMessageEnd();"
+          << endl << indent() << "uint32_t bytes = oprot->getTransport()->writeEnd();" << endl
+          << indent() << "oprot->getTransport()->flush();" << endl << indent()
+          << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+          << "  this->eventHandler_->postWrite(ctx, " << service_func_name << ", bytes);" << endl
+          << indent() << "}" << endl << indent() << "return cob(true);" << endl;
+      scope_down(out);
+      out << endl;
+    } // for each function
+  }   // cob style
+}
+
+/**
+ * Generates a skeleton file of a server
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_cpp_generator::generate_service_skeleton(t_service* tservice) {
+  string svcname = tservice->get_name();
+
+  // Service implementation file includes
+  string f_skeleton_name = get_out_dir() + svcname + "_server.skeleton.cpp";
+
+  string ns = namespace_prefix(tservice->get_program()->get_namespace("cpp"));
+
+  ofstream_with_content_based_conditional_update f_skeleton;
+  f_skeleton.open(f_skeleton_name.c_str());
+  f_skeleton << "// This autogenerated skeleton file illustrates how to build a server." << endl
+             << "// You should copy it to another filename to avoid overwriting it." << endl << endl
+             << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl
+             << "#include <thrift/protocol/TBinaryProtocol.h>" << endl
+             << "#include <thrift/server/TSimpleServer.h>" << endl
+             << "#include <thrift/transport/TServerSocket.h>" << endl
+             << "#include <thrift/transport/TBufferTransports.h>" << endl << endl
+             << "using namespace ::apache::thrift;" << endl
+             << "using namespace ::apache::thrift::protocol;" << endl
+             << "using namespace ::apache::thrift::transport;" << endl
+             << "using namespace ::apache::thrift::server;" << endl << endl;
+
+  // the following code would not compile:
+  // using namespace ;
+  // using namespace ::;
+  if ((!ns.empty()) && (ns.compare(" ::") != 0)) {
+    f_skeleton << "using namespace " << string(ns, 0, ns.size() - 2) << ";" << endl << endl;
+  }
+
+  f_skeleton << "class " << svcname << "Handler : virtual public " << svcname << "If {" << endl
+             << " public:" << endl;
+  indent_up();
+  f_skeleton << indent() << svcname << "Handler() {" << endl << indent()
+             << "  // Your initialization goes here" << endl << indent() << "}" << endl << endl;
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_java_doc(f_skeleton, *f_iter);
+    f_skeleton << indent() << function_signature(*f_iter, "") << " {" << endl << indent()
+               << "  // Your implementation goes here" << endl << indent() << "  printf(\""
+               << (*f_iter)->get_name() << "\\n\");" << endl << indent() << "}" << endl << endl;
+  }
+
+  indent_down();
+  f_skeleton << "};" << endl << endl;
+
+  f_skeleton << indent() << "int main(int argc, char **argv) {" << endl;
+  indent_up();
+  f_skeleton
+      << indent() << "int port = 9090;" << endl << indent() << "::std::shared_ptr<" << svcname
+      << "Handler> handler(new " << svcname << "Handler());" << endl << indent()
+      << "::std::shared_ptr<TProcessor> processor(new " << svcname << "Processor(handler));" << endl
+      << indent() << "::std::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));"
+      << endl << indent()
+      << "::std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());" << endl
+      << indent() << "::std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());"
+      << endl << endl << indent()
+      << "TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);"
+      << endl << indent() << "server.serve();" << endl << indent() << "return 0;" << endl;
+  indent_down();
+  f_skeleton << "}" << endl << endl;
+
+  // Close the files
+  f_skeleton.close();
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_cpp_generator::generate_deserialize_field(ostream& out,
+                                                 t_field* tfield,
+                                                 string prefix,
+                                                 string suffix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name() + suffix;
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name, is_reference(tfield));
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type()) {
+    indent(out) << "xfer += iprot->";
+    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:
+      if (type->is_binary()) {
+        out << "readBinary(" << name << ");";
+      } else {
+        out << "readString(" << name << ");";
+      }
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << "readBool(" << name << ");";
+      break;
+    case t_base_type::TYPE_I8:
+      out << "readByte(" << name << ");";
+      break;
+    case t_base_type::TYPE_I16:
+      out << "readI16(" << name << ");";
+      break;
+    case t_base_type::TYPE_I32:
+      out << "readI32(" << name << ");";
+      break;
+    case t_base_type::TYPE_I64:
+      out << "readI64(" << name << ");";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      out << "readDouble(" << name << ");";
+      break;
+    default:
+      throw "compiler error: no C++ reader for base type " + t_base_type::t_base_name(tbase) + name;
+    }
+    out << endl;
+  } else if (type->is_enum()) {
+    string t = tmp("ecast");
+    out << indent() << "int32_t " << t << ";" << endl << indent() << "xfer += iprot->readI32(" << t
+        << ");" << endl << indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a variable. This makes two key assumptions,
+ * first that there is a const char* variable named data that points to the
+ * buffer for deserialization, and that there is a variable protocol which
+ * is a reference to a TProtocol serialization object.
+ */
+void t_cpp_generator::generate_deserialize_struct(ostream& out,
+                                                  t_struct* tstruct,
+                                                  string prefix,
+                                                  bool pointer) {
+  if (pointer) {
+    indent(out) << "if (!" << prefix << ") { " << endl;
+    indent(out) << "  " << prefix << " = ::std::shared_ptr<" << type_name(tstruct) << ">(new "
+                << type_name(tstruct) << ");" << endl;
+    indent(out) << "}" << endl;
+    indent(out) << "xfer += " << prefix << "->read(iprot);" << endl;
+    indent(out) << "bool wasSet = false;" << endl;
+    const vector<t_field*>& members = tstruct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    for (f_iter = members.begin(); f_iter != members.end(); ++f_iter) {
+
+      indent(out) << "if (" << prefix << "->__isset." << (*f_iter)->get_name()
+                  << ") { wasSet = true; }" << endl;
+    }
+    indent(out) << "if (!wasSet) { " << prefix << ".reset(); }" << endl;
+  } else {
+    indent(out) << "xfer += " << prefix << ".read(iprot);" << endl;
+  }
+}
+
+void t_cpp_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  string size = tmp("_size");
+  string ktype = tmp("_ktype");
+  string vtype = tmp("_vtype");
+  string etype = tmp("_etype");
+
+  t_container* tcontainer = (t_container*)ttype;
+  bool use_push = tcontainer->has_cpp_name();
+
+  indent(out) << prefix << ".clear();" << endl << indent() << "uint32_t " << size << ";" << endl;
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    out << indent() << "::apache::thrift::protocol::TType " << ktype << ";" << endl << indent()
+        << "::apache::thrift::protocol::TType " << vtype << ";" << endl << indent()
+        << "xfer += iprot->readMapBegin(" << ktype << ", " << vtype << ", " << size << ");" << endl;
+  } else if (ttype->is_set()) {
+    out << indent() << "::apache::thrift::protocol::TType " << etype << ";" << endl << indent()
+        << "xfer += iprot->readSetBegin(" << etype << ", " << size << ");" << endl;
+  } else if (ttype->is_list()) {
+    out << indent() << "::apache::thrift::protocol::TType " << etype << ";" << endl << indent()
+        << "xfer += iprot->readListBegin(" << etype << ", " << size << ");" << endl;
+    if (!use_push) {
+      indent(out) << prefix << ".resize(" << size << ");" << endl;
+    }
+  }
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  out << indent() << "uint32_t " << i << ";" << endl << indent() << "for (" << i << " = 0; " << i
+      << " < " << size << "; ++" << i << ")" << endl;
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix, use_push, i);
+  }
+
+  scope_down(out);
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "xfer += iprot->readMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "xfer += iprot->readSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "xfer += iprot->readListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_cpp_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  out << indent() << declare_field(&fkey) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  indent(out) << declare_field(&fval, false, false, false, true) << " = " << prefix << "[" << key
+              << "];" << endl;
+
+  generate_deserialize_field(out, &fval);
+}
+
+void t_cpp_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".insert(" << elem << ");" << endl;
+}
+
+void t_cpp_generator::generate_deserialize_list_element(ostream& out,
+                                                        t_list* tlist,
+                                                        string prefix,
+                                                        bool use_push,
+                                                        string index) {
+  if (use_push) {
+    string elem = tmp("_elem");
+    t_field felem(tlist->get_elem_type(), elem);
+    indent(out) << declare_field(&felem) << endl;
+    generate_deserialize_field(out, &felem);
+    indent(out) << prefix << ".push_back(" << elem << ");" << endl;
+  } else {
+    t_field felem(tlist->get_elem_type(), prefix + "[" + index + "]");
+    generate_deserialize_field(out, &felem);
+  }
+}
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_cpp_generator::generate_serialize_field(ostream& out,
+                                               t_field* tfield,
+                                               string prefix,
+                                               string suffix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  string name = prefix + tfield->get_name() + suffix;
+
+  // 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, is_reference(tfield));
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    indent(out) << "xfer += 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:
+        if (type->is_binary()) {
+          out << "writeBinary(" << name << ");";
+        } else {
+          out << "writeString(" << name << ");";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ");";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "writeByte(" << name << ");";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16(" << name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32(" << name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64(" << name << ");";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble(" << name << ");";
+        break;
+      default:
+        throw "compiler error: no C++ writer for base type " + t_base_type::t_base_name(tbase)
+            + name;
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32((int32_t)" << name << ");";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
+           name.c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_cpp_generator::generate_serialize_struct(ostream& out,
+                                                t_struct* tstruct,
+                                                string prefix,
+                                                bool pointer) {
+  if (pointer) {
+    indent(out) << "if (" << prefix << ") {" << endl;
+    indent(out) << "  xfer += " << prefix << "->write(oprot); " << endl;
+    indent(out) << "} else {"
+                << "oprot->writeStructBegin(\"" << tstruct->get_name() << "\"); " << endl;
+    indent(out) << "  oprot->writeStructEnd();" << endl;
+    indent(out) << "  oprot->writeFieldStop();" << endl;
+    indent(out) << "}" << endl;
+  } else {
+    indent(out) << "xfer += " << prefix << ".write(oprot);" << endl;
+  }
+}
+
+void t_cpp_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "xfer += oprot->writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type())
+                << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", "
+                << "static_cast<uint32_t>(" << prefix << ".size()));" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "xfer += oprot->writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type())
+                << ", "
+                << "static_cast<uint32_t>(" << prefix << ".size()));" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "xfer += oprot->writeListBegin("
+                << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", "
+                << "static_cast<uint32_t>(" << prefix << ".size()));" << endl;
+  }
+
+  string iter = tmp("_iter");
+  out << indent() << type_name(ttype) << "::const_iterator " << iter << ";" << endl << indent()
+      << "for (" << iter << " = " << prefix << ".begin(); " << iter << " != " << prefix
+      << ".end(); ++" << iter << ")" << endl;
+  scope_up(out);
+  if (ttype->is_map()) {
+    generate_serialize_map_element(out, (t_map*)ttype, iter);
+  } else if (ttype->is_set()) {
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+  } else if (ttype->is_list()) {
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+  }
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "xfer += oprot->writeMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "xfer += oprot->writeSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "xfer += oprot->writeListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_cpp_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string iter) {
+  t_field kfield(tmap->get_key_type(), iter + "->first");
+  generate_serialize_field(out, &kfield, "");
+
+  t_field vfield(tmap->get_val_type(), iter + "->second");
+  generate_serialize_field(out, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_cpp_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), "(*" + iter + ")");
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_cpp_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) {
+  t_field efield(tlist->get_elem_type(), "(*" + iter + ")");
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Makes a :: prefix for a namespace
+ *
+ * @param ns The namespace, w/ periods in it
+ * @return Namespaces
+ */
+string t_cpp_generator::namespace_prefix(string ns) {
+  // Always start with "::", to avoid possible name collisions with
+  // other names in one of the current namespaces.
+  //
+  // We also need a leading space, in case the name is used inside of a
+  // template parameter.  "MyTemplate<::foo::Bar>" is not valid C++,
+  // since "<:" is an alternative token for "[".
+  string result = " ::";
+
+  if (ns.size() == 0) {
+    return result;
+  }
+  string::size_type loc;
+  while ((loc = ns.find(".")) != string::npos) {
+    result += ns.substr(0, loc);
+    result += "::";
+    ns = ns.substr(loc + 1);
+  }
+  if (ns.size() > 0) {
+    result += ns + "::";
+  }
+  return result;
+}
+
+/**
+ * Opens namespace.
+ *
+ * @param ns The namespace, w/ periods in it
+ * @return Namespaces
+ */
+string t_cpp_generator::namespace_open(string ns) {
+  if (ns.size() == 0) {
+    return "";
+  }
+  string result = "";
+  string separator = "";
+  string::size_type loc;
+  while ((loc = ns.find(".")) != string::npos) {
+    result += separator;
+    result += "namespace ";
+    result += ns.substr(0, loc);
+    result += " {";
+    separator = " ";
+    ns = ns.substr(loc + 1);
+  }
+  if (ns.size() > 0) {
+    result += separator + "namespace " + ns + " {";
+  }
+  return result;
+}
+
+/**
+ * Closes namespace.
+ *
+ * @param ns The namespace, w/ periods in it
+ * @return Namespaces
+ */
+string t_cpp_generator::namespace_close(string ns) {
+  if (ns.size() == 0) {
+    return "";
+  }
+  string result = "}";
+  string::size_type loc;
+  while ((loc = ns.find(".")) != string::npos) {
+    result += "}";
+    ns = ns.substr(loc + 1);
+  }
+  result += " // namespace";
+  return result;
+}
+
+/**
+ * Returns a C++ type name
+ *
+ * @param ttype The type
+ * @return String of the type name, i.e. std::set<type>
+ */
+string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) {
+  if (ttype->is_base_type()) {
+    string bname = base_type_name(((t_base_type*)ttype)->get_base());
+    std::map<string, string>::iterator it = ttype->annotations_.find("cpp.type");
+    if (it != ttype->annotations_.end()) {
+      bname = it->second;
+    }
+
+    if (!arg) {
+      return bname;
+    }
+
+    if (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING) {
+      return "const " + bname + "&";
+    } else {
+      return "const " + bname;
+    }
+  }
+
+  // Check for a custom overloaded C++ name
+  if (ttype->is_container()) {
+    string cname;
+
+    t_container* tcontainer = (t_container*)ttype;
+    if (tcontainer->has_cpp_name()) {
+      cname = tcontainer->get_cpp_name();
+    } else if (ttype->is_map()) {
+      t_map* tmap = (t_map*)ttype;
+      cname = "std::map<" + type_name(tmap->get_key_type(), in_typedef) + ", "
+              + type_name(tmap->get_val_type(), in_typedef) + "> ";
+    } else if (ttype->is_set()) {
+      t_set* tset = (t_set*)ttype;
+      cname = "std::set<" + type_name(tset->get_elem_type(), in_typedef) + "> ";
+    } else if (ttype->is_list()) {
+      t_list* tlist = (t_list*)ttype;
+      cname = "std::vector<" + type_name(tlist->get_elem_type(), in_typedef) + "> ";
+    }
+
+    if (arg) {
+      return "const " + cname + "&";
+    } else {
+      return cname;
+    }
+  }
+
+  string class_prefix;
+  if (in_typedef && (ttype->is_struct() || ttype->is_xception())) {
+    class_prefix = "class ";
+  }
+
+  // Check if it needs to be namespaced
+  string pname;
+  t_program* program = ttype->get_program();
+  if (program != NULL && program != program_) {
+    pname = class_prefix + namespace_prefix(program->get_namespace("cpp")) + ttype->get_name();
+  } else {
+    pname = class_prefix + ttype->get_name();
+  }
+
+  if (ttype->is_enum() && !gen_pure_enums_) {
+    pname += "::type";
+  }
+
+  if (arg) {
+    if (is_complex_type(ttype)) {
+      return "const " + pname + "&";
+    } else {
+      return "const " + pname;
+    }
+  } else {
+    return pname;
+  }
+}
+
+/**
+ * Returns the C++ type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ * @return Explicit C++ type, i.e. "int32_t"
+ */
+string t_cpp_generator::base_type_name(t_base_type::t_base tbase) {
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    return "std::string";
+  case t_base_type::TYPE_BOOL:
+    return "bool";
+  case t_base_type::TYPE_I8:
+    return "int8_t";
+  case t_base_type::TYPE_I16:
+    return "int16_t";
+  case t_base_type::TYPE_I32:
+    return "int32_t";
+  case t_base_type::TYPE_I64:
+    return "int64_t";
+  case t_base_type::TYPE_DOUBLE:
+    return "double";
+  default:
+    throw "compiler error: no C++ base type name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ * @return Field declaration, i.e. int x = 0;
+ */
+string t_cpp_generator::declare_field(t_field* tfield,
+                                      bool init,
+                                      bool pointer,
+                                      bool constant,
+                                      bool reference) {
+  // TODO(mcslee): do we ever need to initialize the field?
+  string result = "";
+  if (constant) {
+    result += "const ";
+  }
+  result += type_name(tfield->get_type());
+  if (is_reference(tfield)) {
+    result = "::std::shared_ptr<" + result + ">";
+  }
+  if (pointer) {
+    result += "*";
+  }
+  if (reference) {
+    result += "&";
+  }
+  result += " " + tfield->get_name();
+  if (init) {
+    t_type* type = get_true_type(tfield->get_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:
+      case t_base_type::TYPE_STRING:
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = false";
+        break;
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = (double)0";
+        break;
+      default:
+        throw "compiler error: no C++ initializer for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      result += " = (" + type_name(type) + ")0";
+    }
+  }
+  if (!reference) {
+    result += ";";
+  }
+  return result;
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_cpp_generator::function_signature(t_function* tfunction,
+                                           string style,
+                                           string prefix,
+                                           bool name_params) {
+  t_type* ttype = tfunction->get_returntype();
+  t_struct* arglist = tfunction->get_arglist();
+  bool has_xceptions = !tfunction->get_xceptions()->get_members().empty();
+
+  if (style == "") {
+    if (is_complex_type(ttype)) {
+      return "void " + prefix + tfunction->get_name() + "(" + type_name(ttype)
+             + (name_params ? "& _return" : "& /* _return */")
+             + argument_list(arglist, name_params, true) + ")";
+    } else {
+      return type_name(ttype) + " " + prefix + tfunction->get_name() + "("
+             + argument_list(arglist, name_params) + ")";
+    }
+  } else if (style.substr(0, 3) == "Cob") {
+    string cob_type;
+    string exn_cob;
+    if (style == "CobCl") {
+      cob_type = "(" + service_name_ + "CobClient";
+      if (gen_templates_) {
+        cob_type += "T<Protocol_>";
+      }
+      cob_type += "* client)";
+    } else if (style == "CobSv") {
+      cob_type = (ttype->is_void() ? "()" : ("(" + type_name(ttype) + " const& _return)"));
+      if (has_xceptions) {
+        exn_cob
+            = ", ::std::function<void(::apache::thrift::TDelayedException* _throw)> /* exn_cob */";
+      }
+    } else {
+      throw "UNKNOWN STYLE";
+    }
+
+    return "void " + prefix + tfunction->get_name() + "(::std::function<void" + cob_type + "> cob"
+           + exn_cob + argument_list(arglist, name_params, true) + ")";
+  } else {
+    throw "UNKNOWN STYLE";
+  }
+}
+
+/**
+ * Renders a field list
+ *
+ * @param tstruct The struct definition
+ * @return Comma sepearated list of all field names in that struct
+ */
+string t_cpp_generator::argument_list(t_struct* tstruct, bool name_params, bool start_comma) {
+  string result = "";
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  bool first = !start_comma;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      result += ", ";
+    }
+    result += type_name((*f_iter)->get_type(), false, true) + " "
+              + (name_params ? (*f_iter)->get_name() : "/* " + (*f_iter)->get_name() + " */");
+  }
+  return result;
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ *
+ * @param type Thrift Type
+ * @return String of C++ code to definition of that type constant
+ */
+string t_cpp_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 "::apache::thrift::protocol::T_STRING";
+    case t_base_type::TYPE_BOOL:
+      return "::apache::thrift::protocol::T_BOOL";
+    case t_base_type::TYPE_I8:
+      return "::apache::thrift::protocol::T_BYTE";
+    case t_base_type::TYPE_I16:
+      return "::apache::thrift::protocol::T_I16";
+    case t_base_type::TYPE_I32:
+      return "::apache::thrift::protocol::T_I32";
+    case t_base_type::TYPE_I64:
+      return "::apache::thrift::protocol::T_I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "::apache::thrift::protocol::T_DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "::apache::thrift::protocol::T_I32";
+  } else if (type->is_struct()) {
+    return "::apache::thrift::protocol::T_STRUCT";
+  } else if (type->is_xception()) {
+    return "::apache::thrift::protocol::T_STRUCT";
+  } else if (type->is_map()) {
+    return "::apache::thrift::protocol::T_MAP";
+  } else if (type->is_set()) {
+    return "::apache::thrift::protocol::T_SET";
+  } else if (type->is_list()) {
+    return "::apache::thrift::protocol::T_LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+string t_cpp_generator::get_include_prefix(const t_program& program) const {
+  string include_prefix = program.get_include_prefix();
+  if (!use_include_prefix_ || (include_prefix.size() > 0 && include_prefix[0] == '/')) {
+    // if flag is turned off or this is absolute path, return empty prefix
+    return "";
+  }
+
+  string::size_type last_slash = string::npos;
+  if ((last_slash = include_prefix.rfind("/")) != string::npos) {
+    return include_prefix.substr(0, last_slash)
+           + (get_program()->is_out_path_absolute() ? "/" : "/" + out_dir_base_ + "/");
+  }
+
+  return "";
+}
+
+THRIFT_REGISTER_GENERATOR(
+    cpp,
+    "C++",
+    "    cob_style:       Generate \"Continuation OBject\"-style classes.\n"
+    "    no_client_completion:\n"
+    "                     Omit calls to completion__() in CobClient class.\n"
+    "    no_default_operators:\n"
+    "                     Omits generation of default operators ==, != and <\n"
+    "    templates:       Generate templatized reader/writer methods.\n"
+    "    pure_enums:      Generate pure enums instead of wrapper classes.\n"
+    "    include_prefix:  Use full include paths in generated files.\n"
+    "    moveable_types:  Generate move constructors and assignment operators.\n"
+    "    no_ostream_operators:\n"
+    "                     Omit generation of ostream definitions.\n"
+    "    no_skeleton:     Omits generation of skeleton.\n")
diff --git a/compiler/cpp/src/thrift/generate/t_csharp_generator.cc b/compiler/cpp/src/thrift/generate/t_csharp_generator.cc
new file mode 100644
index 0000000..9d1e29e
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_csharp_generator.cc
@@ -0,0 +1,3245 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+#include <cassert>
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <cctype>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+struct member_mapping_scope {
+  void* scope_member;
+  std::map<std::string, std::string> mapping_table;
+};
+
+class t_csharp_generator : public t_oop_generator {
+public:
+  t_csharp_generator(t_program* program,
+                     const std::map<std::string, std::string>& parsed_options,
+                     const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+
+    std::map<std::string, std::string>::const_iterator iter;
+
+    async_ = false;
+    nullable_ = false;
+    hashcode_ = false;
+    union_ = false;
+    serialize_ = false;
+    wcf_ = false;
+    wcf_namespace_.clear();
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("async") == 0) {
+        async_ = true;
+      } else if( iter->first.compare("nullable") == 0) {
+        nullable_ = true;
+      } else if( iter->first.compare("hashcode") == 0) {
+        hashcode_ = true;
+      } else if( iter->first.compare("union") == 0) {
+        union_ = true;
+      } else if( iter->first.compare("serial") == 0) {
+        serialize_ = true;
+        wcf_namespace_ = iter->second; // since there can be only one namespace
+      } else if( iter->first.compare("wcf") == 0) {
+        wcf_ = true;
+        wcf_namespace_ = iter->second;
+      } else {
+        throw "unknown option csharp:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-csharp";
+  }
+  void init_generator();
+  void close_generator();
+
+  void generate_consts(std::vector<t_const*> consts);
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_struct(t_struct* tstruct);
+  void generate_union(t_struct* tunion);
+  void generate_xception(t_struct* txception);
+  void generate_service(t_service* tservice);
+  void generate_property(ostream& out, t_field* tfield, bool isPublic, bool generateIsset);
+  void generate_csharp_property(ostream& out,
+                                t_field* tfield,
+                                bool isPublic,
+                                bool includeIsset = true,
+                                std::string fieldPrefix = "");
+  bool print_const_value(std::ostream& out,
+                         std::string name,
+                         t_type* type,
+                         t_const_value* value,
+                         bool in_static,
+                         bool defval = false,
+                         bool needtype = false);
+  std::string render_const_value(std::ostream& out,
+                                 std::string name,
+                                 t_type* type,
+                                 t_const_value* value);
+  void print_const_constructor(std::ostream& out, std::vector<t_const*> consts);
+  void print_const_def_value(std::ostream& out,
+                             std::string name,
+                             t_type* type,
+                             t_const_value* value);
+
+  void generate_csharp_struct(t_struct* tstruct, bool is_exception);
+  void generate_csharp_union(t_struct* tunion);
+  void generate_csharp_struct_definition(std::ostream& out,
+                                         t_struct* tstruct,
+                                         bool is_xception = false,
+                                         bool in_class = false,
+                                         bool is_result = false);
+  void generate_csharp_union_definition(std::ostream& out, t_struct* tunion);
+  void generate_csharp_union_class(std::ostream& out, t_struct* tunion, t_field* tfield);
+  void generate_csharp_wcffault(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_struct_result_writer(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_struct_writer(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_struct_tostring(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_struct_equals(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_struct_hashcode(std::ostream& out, t_struct* tstruct);
+  void generate_csharp_union_reader(std::ostream& out, t_struct* tunion);
+
+  void generate_function_helpers(t_function* tfunction);
+  void generate_service_interface(t_service* tservice);
+  void generate_separate_service_interfaces(t_service* tservice);
+  void generate_sync_service_interface(t_service* tservice);
+  void generate_async_service_interface(t_service* tservice);
+  void generate_combined_service_interface(t_service* tservice);
+  void generate_silverlight_async_methods(t_service* tservice);
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_client(t_service* tservice);
+  void generate_service_server(t_service* tservice);
+  void generate_service_server_sync(t_service* tservice);
+  void generate_service_server_async(t_service* tservice);
+  void generate_process_function(t_service* tservice, t_function* function);
+  void generate_process_function_async(t_service* tservice, t_function* function);
+
+  void generate_deserialize_field(std::ostream& out,
+                                  t_field* tfield,
+                                  std::string prefix = "",
+                                  bool is_propertyless = false);
+  void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+  void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+  void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+  void generate_deserialize_list_element(std::ostream& out, t_list* list, std::string prefix = "");
+  void generate_serialize_field(std::ostream& out,
+                                t_field* tfield,
+                                std::string prefix = "",
+                                bool is_element = false,
+                                bool is_propertyless = false);
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string iter,
+                                      std::string map);
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  void generate_csharp_doc(std::ostream& out, t_field* field);
+  void generate_csharp_doc(std::ostream& out, t_doc* tdoc);
+  void generate_csharp_doc(std::ostream& out, t_function* tdoc);
+  void generate_csharp_docstring_comment(std::ostream& out, string contents);
+
+  void start_csharp_namespace(std::ostream& out);
+  void end_csharp_namespace(std::ostream& out);
+
+  std::string csharp_type_usings();
+  std::string csharp_thrift_usings();
+
+  std::string type_name(t_type* ttype,
+                        bool in_countainer = false,
+                        bool in_init = false,
+                        bool in_param = false,
+                        bool is_required = false);
+  std::string base_type_name(t_base_type* tbase,
+                             bool in_container = false,
+                             bool in_param = false,
+                             bool is_required = false);
+  std::string declare_field(t_field* tfield, bool init = false, std::string prefix = "");
+  std::string function_signature_async_begin(t_function* tfunction, std::string prefix = "");
+  std::string function_signature_async_end(t_function* tfunction, std::string prefix = "");
+  std::string function_signature_async(t_function* tfunction, std::string prefix = "");
+  std::string function_signature(t_function* tfunction, std::string prefix = "");
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string prop_name(t_field* tfield, bool suppress_mapping = false);
+  std::string get_enum_class_name(t_type* type);
+
+  bool field_has_default(t_field* tfield) { return tfield->get_value() != NULL; }
+
+  bool field_is_required(t_field* tfield) { return tfield->get_req() == t_field::T_REQUIRED; }
+
+  bool type_can_be_null(t_type* ttype) {
+    while (ttype->is_typedef()) {
+      ttype = ((t_typedef*)ttype)->get_type();
+    }
+
+    return ttype->is_container() || ttype->is_struct() || ttype->is_xception()
+           || ttype->is_string();
+  }
+
+private:
+  std::string namespace_name_;
+  ofstream_with_content_based_conditional_update f_service_;
+  std::string namespace_dir_;
+  bool async_;
+  bool nullable_;
+  bool union_;
+  bool hashcode_;
+  bool serialize_;
+  bool wcf_;
+  std::string wcf_namespace_;
+
+  std::map<std::string, int> csharp_keywords;
+  std::vector<member_mapping_scope>  member_mapping_scopes;
+
+  void init_keywords();
+  std::string normalize_name(std::string name);
+  std::string make_valid_csharp_identifier(std::string const& fromName);
+  void prepare_member_name_mapping(t_struct* tstruct);
+  void prepare_member_name_mapping(void* scope,
+                                   const vector<t_field*>& members,
+                                   const string& structname);
+  void cleanup_member_name_mapping(void* scope);
+  string get_mapped_member_name(string oldname);
+};
+
+void t_csharp_generator::init_generator() {
+  MKDIR(get_out_dir().c_str());
+  namespace_name_ = program_->get_namespace("csharp");
+
+  string dir = namespace_name_;
+  string subdir = get_out_dir().c_str();
+  string::size_type loc;
+
+  while ((loc = dir.find(".")) != string::npos) {
+    subdir = subdir + "/" + dir.substr(0, loc);
+    MKDIR(subdir.c_str());
+    dir = dir.substr(loc + 1);
+  }
+  if (dir.size() > 0) {
+    subdir = subdir + "/" + dir;
+    MKDIR(subdir.c_str());
+  }
+
+  namespace_dir_ = subdir;
+  init_keywords();
+
+  while( ! member_mapping_scopes.empty()) {
+    cleanup_member_name_mapping( member_mapping_scopes.back().scope_member);
+  }
+
+  pverbose("C# options:\n");
+  pverbose("- async ...... %s\n", (async_ ? "ON" : "off"));
+  pverbose("- nullable ... %s\n", (nullable_ ? "ON" : "off"));
+  pverbose("- union ...... %s\n", (union_ ? "ON" : "off"));
+  pverbose("- hashcode ... %s\n", (hashcode_ ? "ON" : "off"));
+  pverbose("- serialize .. %s\n", (serialize_ ? "ON" : "off"));
+  pverbose("- wcf ........ %s\n", (wcf_ ? "ON" : "off"));
+}
+
+std::string t_csharp_generator::normalize_name(std::string name) {
+  string tmp(name);
+  std::transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast<int (*)(int)>(std::tolower));
+
+  // un-conflict keywords by prefixing with "@"
+  if (csharp_keywords.find(tmp) != csharp_keywords.end()) {
+    return "@" + name;
+  }
+
+  // no changes necessary
+  return name;
+}
+
+void t_csharp_generator::init_keywords() {
+  csharp_keywords.clear();
+
+  // C# keywords
+  csharp_keywords["abstract"] = 1;
+  csharp_keywords["as"] = 1;
+  csharp_keywords["base"] = 1;
+  csharp_keywords["bool"] = 1;
+  csharp_keywords["break"] = 1;
+  csharp_keywords["byte"] = 1;
+  csharp_keywords["case"] = 1;
+  csharp_keywords["catch"] = 1;
+  csharp_keywords["char"] = 1;
+  csharp_keywords["checked"] = 1;
+  csharp_keywords["class"] = 1;
+  csharp_keywords["const"] = 1;
+  csharp_keywords["continue"] = 1;
+  csharp_keywords["decimal"] = 1;
+  csharp_keywords["default"] = 1;
+  csharp_keywords["delegate"] = 1;
+  csharp_keywords["do"] = 1;
+  csharp_keywords["double"] = 1;
+  csharp_keywords["else"] = 1;
+  csharp_keywords["enum"] = 1;
+  csharp_keywords["event"] = 1;
+  csharp_keywords["explicit"] = 1;
+  csharp_keywords["extern"] = 1;
+  csharp_keywords["false"] = 1;
+  csharp_keywords["finally"] = 1;
+  csharp_keywords["fixed"] = 1;
+  csharp_keywords["float"] = 1;
+  csharp_keywords["for"] = 1;
+  csharp_keywords["foreach"] = 1;
+  csharp_keywords["goto"] = 1;
+  csharp_keywords["if"] = 1;
+  csharp_keywords["implicit"] = 1;
+  csharp_keywords["in"] = 1;
+  csharp_keywords["int"] = 1;
+  csharp_keywords["interface"] = 1;
+  csharp_keywords["internal"] = 1;
+  csharp_keywords["is"] = 1;
+  csharp_keywords["lock"] = 1;
+  csharp_keywords["long"] = 1;
+  csharp_keywords["namespace"] = 1;
+  csharp_keywords["new"] = 1;
+  csharp_keywords["null"] = 1;
+  csharp_keywords["object"] = 1;
+  csharp_keywords["operator"] = 1;
+  csharp_keywords["out"] = 1;
+  csharp_keywords["override"] = 1;
+  csharp_keywords["params"] = 1;
+  csharp_keywords["private"] = 1;
+  csharp_keywords["protected"] = 1;
+  csharp_keywords["public"] = 1;
+  csharp_keywords["readonly"] = 1;
+  csharp_keywords["ref"] = 1;
+  csharp_keywords["return"] = 1;
+  csharp_keywords["sbyte"] = 1;
+  csharp_keywords["sealed"] = 1;
+  csharp_keywords["short"] = 1;
+  csharp_keywords["sizeof"] = 1;
+  csharp_keywords["stackalloc"] = 1;
+  csharp_keywords["static"] = 1;
+  csharp_keywords["string"] = 1;
+  csharp_keywords["struct"] = 1;
+  csharp_keywords["switch"] = 1;
+  csharp_keywords["this"] = 1;
+  csharp_keywords["throw"] = 1;
+  csharp_keywords["true"] = 1;
+  csharp_keywords["try"] = 1;
+  csharp_keywords["typeof"] = 1;
+  csharp_keywords["uint"] = 1;
+  csharp_keywords["ulong"] = 1;
+  csharp_keywords["unchecked"] = 1;
+  csharp_keywords["unsafe"] = 1;
+  csharp_keywords["ushort"] = 1;
+  csharp_keywords["using"] = 1;
+  csharp_keywords["virtual"] = 1;
+  csharp_keywords["void"] = 1;
+  csharp_keywords["volatile"] = 1;
+  csharp_keywords["while"] = 1;
+
+  // C# contextual keywords
+  csharp_keywords["add"] = 1;
+  csharp_keywords["alias"] = 1;
+  csharp_keywords["ascending"] = 1;
+  csharp_keywords["async"] = 1;
+  csharp_keywords["await"] = 1;
+  csharp_keywords["descending"] = 1;
+  csharp_keywords["dynamic"] = 1;
+  csharp_keywords["from"] = 1;
+  csharp_keywords["get"] = 1;
+  csharp_keywords["global"] = 1;
+  csharp_keywords["group"] = 1;
+  csharp_keywords["into"] = 1;
+  csharp_keywords["join"] = 1;
+  csharp_keywords["let"] = 1;
+  csharp_keywords["orderby"] = 1;
+  csharp_keywords["partial"] = 1;
+  csharp_keywords["remove"] = 1;
+  csharp_keywords["select"] = 1;
+  csharp_keywords["set"] = 1;
+  csharp_keywords["value"] = 1;
+  csharp_keywords["var"] = 1;
+  csharp_keywords["where"] = 1;
+  csharp_keywords["yield"] = 1;
+}
+
+void t_csharp_generator::start_csharp_namespace(ostream& out) {
+  if (!namespace_name_.empty()) {
+    out << "namespace " << namespace_name_ << "\n";
+    scope_up(out);
+  }
+}
+
+void t_csharp_generator::end_csharp_namespace(ostream& out) {
+  if (!namespace_name_.empty()) {
+    scope_down(out);
+  }
+}
+
+string t_csharp_generator::csharp_type_usings() {
+  return string() + "using System;\n" + "using System.Collections;\n"
+         + "using System.Collections.Generic;\n" + "using System.Text;\n" + "using System.IO;\n"
+         + ((async_) ? "using System.Threading.Tasks;\n" : "") + "using Thrift;\n"
+         + "using Thrift.Collections;\n" + ((serialize_ || wcf_) ? "#if !SILVERLIGHT\n" : "")
+         + ((serialize_ || wcf_) ? "using System.Xml.Serialization;\n" : "")
+         + ((serialize_ || wcf_) ? "#endif\n" : "")
+         + "using System.Runtime.Serialization;\n";
+}
+
+string t_csharp_generator::csharp_thrift_usings() {
+  return string() + "using Thrift.Protocol;\n" + "using Thrift.Transport;\n";
+}
+
+void t_csharp_generator::close_generator() {
+}
+void t_csharp_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+void t_csharp_generator::generate_enum(t_enum* tenum) {
+  string f_enum_name = namespace_dir_ + "/" + (tenum->get_name()) + ".cs";
+  ofstream_with_content_based_conditional_update f_enum;
+  f_enum.open(f_enum_name.c_str());
+
+  f_enum << autogen_comment() << endl;
+
+  start_csharp_namespace(f_enum);
+
+  generate_csharp_doc(f_enum, tenum);
+
+  indent(f_enum) << "public enum " << tenum->get_name() << "\n";
+  scope_up(f_enum);
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    generate_csharp_doc(f_enum, *c_iter);
+
+    int value = (*c_iter)->get_value();
+    indent(f_enum) << (*c_iter)->get_name() << " = " << value << "," << endl;
+  }
+
+  scope_down(f_enum);
+
+  end_csharp_namespace(f_enum);
+
+  f_enum.close();
+}
+
+void t_csharp_generator::generate_consts(std::vector<t_const*> consts) {
+  if (consts.empty()) {
+    return;
+  }
+  string f_consts_name = namespace_dir_ + '/' + program_name_ + ".Constants.cs";
+  ofstream_with_content_based_conditional_update f_consts;
+  f_consts.open(f_consts_name.c_str());
+
+  f_consts << autogen_comment() << csharp_type_usings() << endl;
+
+  start_csharp_namespace(f_consts);
+
+  indent(f_consts) << "public static class " << make_valid_csharp_identifier(program_name_)
+                   << "Constants" << endl;
+  scope_up(f_consts);
+
+  vector<t_const*>::iterator c_iter;
+  bool need_static_constructor = false;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    generate_csharp_doc(f_consts, (*c_iter));
+    if (print_const_value(f_consts,
+                          (*c_iter)->get_name(),
+                          (*c_iter)->get_type(),
+                          (*c_iter)->get_value(),
+                          false)) {
+      need_static_constructor = true;
+    }
+  }
+
+  if (need_static_constructor) {
+    print_const_constructor(f_consts, consts);
+  }
+
+  scope_down(f_consts);
+  end_csharp_namespace(f_consts);
+  f_consts.close();
+}
+
+void t_csharp_generator::print_const_def_value(std::ostream& out,
+                                               string name,
+                                               t_type* type,
+                                               t_const_value* value) {
+  if (type->is_struct() || type->is_xception()) {
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    prepare_member_name_mapping((t_struct*)type);
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_field* field = NULL;
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+          field = (*f_iter);
+        }
+      }
+      if (field == NULL) {
+        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+      }
+      t_type* field_type = field->get_type();
+      string val = render_const_value(out, name, field_type, v_iter->second);
+      indent(out) << name << "." << prop_name(field) << " = " << val << ";" << endl;
+    }
+    cleanup_member_name_mapping((t_struct*)type);
+  } 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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, name, ktype, v_iter->first);
+      string val = render_const_value(out, name, vtype, v_iter->second);
+      indent(out) << name << "[" << key << "]"
+                  << " = " << val << ";" << endl;
+    }
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(out, name, etype, *v_iter);
+      indent(out) << name << ".Add(" << val << ");" << endl;
+    }
+  }
+}
+
+void t_csharp_generator::print_const_constructor(std::ostream& out, std::vector<t_const*> consts) {
+  indent(out) << "static " << make_valid_csharp_identifier(program_name_).c_str() << "Constants()"
+              << endl;
+  scope_up(out);
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    string name = (*c_iter)->get_name();
+    t_type* type = (*c_iter)->get_type();
+    t_const_value* value = (*c_iter)->get_value();
+
+    print_const_def_value(out, name, type, value);
+  }
+  scope_down(out);
+}
+
+// it seems like all that methods that call this are using in_static to be the opposite of what it
+// would imply
+bool t_csharp_generator::print_const_value(std::ostream& out,
+                                           string name,
+                                           t_type* type,
+                                           t_const_value* value,
+                                           bool in_static,
+                                           bool defval,
+                                           bool needtype) {
+  indent(out);
+  bool need_static_construction = !in_static;
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  if (!defval || needtype) {
+    out << (in_static ? "" : type->is_base_type() ? "public const " : "public static ")
+        << type_name(type) << " ";
+  }
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, name, type, value);
+    out << name << " = " << v2 << ";" << endl;
+    need_static_construction = false;
+  } else if (type->is_enum()) {
+    out << name << " = " << type_name(type, false, true) << "." << value->get_identifier_name()
+        << ";" << endl;
+    need_static_construction = false;
+  } else if (type->is_struct() || type->is_xception()) {
+    out << name << " = new " << type_name(type) << "();" << endl;
+  } else if (type->is_map()) {
+    out << name << " = new " << type_name(type, true, true) << "();" << endl;
+  } else if (type->is_list() || type->is_set()) {
+    out << name << " = new " << type_name(type) << "();" << endl;
+  }
+
+  if (defval && !type->is_base_type() && !type->is_enum()) {
+    print_const_def_value(out, name, type, value);
+  }
+
+  return need_static_construction;
+}
+
+std::string t_csharp_generator::render_const_value(ostream& out,
+                                                   string name,
+                                                   t_type* type,
+                                                   t_const_value* value) {
+  (void)name;
+  std::ostringstream render;
+
+  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:
+      render << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "true" : "false");
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << value->get_integer();
+      } else {
+        render << 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()) {
+    render << type->get_name() << "." << value->get_identifier_name();
+  } else {
+    string t = tmp("tmp");
+    print_const_value(out, t, type, value, true, true, true);
+    render << t;
+  }
+
+  return render.str();
+}
+
+void t_csharp_generator::generate_struct(t_struct* tstruct) {
+  if (union_ && tstruct->is_union()) {
+    generate_csharp_union(tstruct);
+  } else {
+    generate_csharp_struct(tstruct, false);
+  }
+}
+
+void t_csharp_generator::generate_xception(t_struct* txception) {
+  generate_csharp_struct(txception, true);
+}
+
+void t_csharp_generator::generate_csharp_struct(t_struct* tstruct, bool is_exception) {
+  string f_struct_name = namespace_dir_ + "/" + (tstruct->get_name()) + ".cs";
+  ofstream_with_content_based_conditional_update f_struct;
+
+  f_struct.open(f_struct_name.c_str());
+
+  f_struct << autogen_comment() << csharp_type_usings() << csharp_thrift_usings() << endl;
+
+  generate_csharp_struct_definition(f_struct, tstruct, is_exception);
+
+  f_struct.close();
+}
+
+void t_csharp_generator::generate_csharp_struct_definition(ostream& out,
+                                                           t_struct* tstruct,
+                                                           bool is_exception,
+                                                           bool in_class,
+                                                           bool is_result) {
+
+  if (!in_class) {
+    start_csharp_namespace(out);
+  }
+
+  out << endl;
+
+  generate_csharp_doc(out, tstruct);
+  prepare_member_name_mapping(tstruct);
+
+  indent(out) << "#if !SILVERLIGHT" << endl;
+  indent(out) << "[Serializable]" << endl;
+  indent(out) << "#endif" << endl;
+  if ((serialize_ || wcf_) && !is_exception) {
+    indent(out) << "[DataContract(Namespace=\"" << wcf_namespace_ << "\")]"
+                << endl; // do not make exception classes directly WCF serializable, we provide a
+                         // separate "fault" for that
+  }
+  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+
+  indent(out) << "public " << (is_final ? "sealed " : "") << "partial class "
+              << normalize_name(tstruct->get_name()) << " : ";
+
+  if (is_exception) {
+    out << "TException, ";
+  }
+  out << "TBase";
+
+  out << endl;
+
+  scope_up(out);
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  // make private members with public Properties
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    // if the field is requied, then we use auto-properties
+    if (!field_is_required((*m_iter)) && (!nullable_ || field_has_default((*m_iter)))) {
+      indent(out) << "private " << declare_field(*m_iter, false, "_") << endl;
+    }
+  }
+  out << endl;
+
+  bool has_non_required_fields = false;
+  bool has_non_required_default_value_fields = false;
+  bool has_required_fields = false;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    generate_csharp_doc(out, *m_iter);
+    generate_property(out, *m_iter, true, true);
+    bool is_required = field_is_required((*m_iter));
+    bool has_default = field_has_default((*m_iter));
+    if (is_required) {
+      has_required_fields = true;
+    } else {
+      if (has_default) {
+        has_non_required_default_value_fields = true;
+      }
+      has_non_required_fields = true;
+    }
+  }
+
+  bool generate_isset = (nullable_ && has_non_required_default_value_fields)
+                        || (!nullable_ && has_non_required_fields);
+  if (generate_isset) {
+    out << endl;
+    if (serialize_ || wcf_) {
+      out << indent() << "[XmlIgnore] // XmlSerializer" << endl << indent()
+          << "[DataMember(Order = 1)]  // XmlObjectSerializer, DataContractJsonSerializer, etc."
+          << endl;
+    }
+    out << indent() << "public Isset __isset;" << endl << indent() << "#if !SILVERLIGHT" << endl
+        << indent() << "[Serializable]" << endl << indent() << "#endif" << endl;
+    if (serialize_ || wcf_) {
+      indent(out) << "[DataContract]" << endl;
+    }
+    indent(out) << "public struct Isset {" << endl;
+    indent_up();
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      bool is_required = field_is_required((*m_iter));
+      bool has_default = field_has_default((*m_iter));
+      // if it is required, don't need Isset for that variable
+      // if it is not required, if it has a default value, we need to generate Isset
+      // if we are not nullable, then we generate Isset
+      if (!is_required && (!nullable_ || has_default)) {
+        if (serialize_ || wcf_) {
+          indent(out) << "[DataMember]" << endl;
+        }
+        indent(out) << "public bool " << normalize_name((*m_iter)->get_name()) << ";" << endl;
+      }
+    }
+
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    if (generate_isset && (serialize_ || wcf_)) {
+      indent(out) << "#region XmlSerializer support" << endl << endl;
+
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        bool is_required = field_is_required((*m_iter));
+        bool has_default = field_has_default((*m_iter));
+        // if it is required, don't need Isset for that variable
+        // if it is not required, if it has a default value, we need to generate Isset
+        // if we are not nullable, then we generate Isset
+        if (!is_required && (!nullable_ || has_default)) {
+          indent(out) << "public bool ShouldSerialize" << prop_name((*m_iter)) << "()" << endl;
+          indent(out) << "{" << endl;
+          indent_up();
+          indent(out) << "return __isset." << normalize_name((*m_iter)->get_name()) << ";" << endl;
+          indent_down();
+          indent(out) << "}" << endl << endl;
+        }
+      }
+
+      indent(out) << "#endregion XmlSerializer support" << endl << endl;
+    }
+  }
+
+  // We always want a default, no argument constructor for Reading
+  indent(out) << "public " << normalize_name(tstruct->get_name()) << "() {" << endl;
+  indent_up();
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = (*m_iter)->get_type();
+    while (t->is_typedef()) {
+      t = ((t_typedef*)t)->get_type();
+    }
+    if ((*m_iter)->get_value() != NULL) {
+      if (field_is_required((*m_iter))) {
+        print_const_value(out, "this." + prop_name(*m_iter), t, (*m_iter)->get_value(), true, true);
+      } else {
+        print_const_value(out,
+                          "this._" + (*m_iter)->get_name(),
+                          t,
+                          (*m_iter)->get_value(),
+                          true,
+                          true);
+        // Optionals with defaults are marked set
+        indent(out) << "this.__isset." << normalize_name((*m_iter)->get_name()) << " = true;"
+                    << endl;
+      }
+    }
+  }
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  if (has_required_fields) {
+    indent(out) << "public " << tstruct->get_name() << "(";
+    bool first = true;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (field_is_required((*m_iter))) {
+        if (first) {
+          first = false;
+        } else {
+          out << ", ";
+        }
+        out << type_name((*m_iter)->get_type()) << " " << normalize_name((*m_iter)->get_name());
+      }
+    }
+    out << ") : this() {" << endl;
+    indent_up();
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (field_is_required((*m_iter))) {
+        indent(out) << "this." << prop_name((*m_iter)) << " = " << normalize_name((*m_iter)->get_name()) << ";"
+                    << endl;
+      }
+    }
+
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+
+  generate_csharp_struct_reader(out, tstruct);
+  if (is_result) {
+    generate_csharp_struct_result_writer(out, tstruct);
+  } else {
+    generate_csharp_struct_writer(out, tstruct);
+  }
+  if (hashcode_) {
+    generate_csharp_struct_equals(out, tstruct);
+    generate_csharp_struct_hashcode(out, tstruct);
+  }
+  generate_csharp_struct_tostring(out, tstruct);
+  scope_down(out);
+  out << endl;
+
+  // generate a corresponding WCF fault to wrap the exception
+  if ((serialize_ || wcf_) && is_exception) {
+    generate_csharp_wcffault(out, tstruct);
+  }
+
+  cleanup_member_name_mapping(tstruct);
+  if (!in_class) {
+    end_csharp_namespace(out);
+  }
+}
+
+void t_csharp_generator::generate_csharp_wcffault(ostream& out, t_struct* tstruct) {
+  out << endl;
+  indent(out) << "#if !SILVERLIGHT" << endl;
+  indent(out) << "[Serializable]" << endl;
+  indent(out) << "#endif" << endl;
+  indent(out) << "[DataContract]" << endl;
+  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+
+  indent(out) << "public " << (is_final ? "sealed " : "") << "partial class " << tstruct->get_name()
+              << "Fault" << endl;
+
+  scope_up(out);
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  // make private members with public Properties
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    // if the field is requied, then we use auto-properties
+    if (!field_is_required((*m_iter)) && (!nullable_ || field_has_default((*m_iter)))) {
+      indent(out) << "private " << declare_field(*m_iter, false, "_") << endl;
+    }
+  }
+  out << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    generate_property(out, *m_iter, true, false);
+  }
+
+  scope_down(out);
+  out << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_reader(ostream& out, t_struct* tstruct) {
+  indent(out) << "public void Read (TProtocol iprot)" << endl;
+  scope_up(out);
+
+  out << indent() << "iprot.IncrementRecursionDepth();" << endl;
+  out << indent() << "try" << endl;
+  scope_up(out);
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Required variables aren't in __isset, so we need tmp vars to check them
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (field_is_required((*f_iter))) {
+      indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
+    }
+  }
+
+  indent(out) << "TField field;" << endl << indent() << "iprot.ReadStructBegin();" << endl;
+
+  indent(out) << "while (true)" << endl;
+  scope_up(out);
+
+  indent(out) << "field = iprot.ReadFieldBegin();" << endl;
+
+  indent(out) << "if (field.Type == TType.Stop) { " << endl;
+  indent_up();
+  indent(out) << "break;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent(out) << "switch (field.ID)" << endl;
+
+  scope_up(out);
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    bool is_required = field_is_required((*f_iter));
+    indent(out) << "case " << (*f_iter)->get_key() << ":" << endl;
+    indent_up();
+    indent(out) << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+    indent_up();
+
+    generate_deserialize_field(out, *f_iter);
+    if (is_required) {
+      indent(out) << "isset_" << (*f_iter)->get_name() << " = true;" << endl;
+    }
+
+    indent_down();
+    out << indent() << "} else { " << endl << indent() << "  TProtocolUtil.Skip(iprot, field.Type);"
+        << endl << indent() << "}" << endl << indent() << "break;" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default: " << endl;
+  indent_up();
+  indent(out) << "TProtocolUtil.Skip(iprot, field.Type);" << endl;
+  indent(out) << "break;" << endl;
+  indent_down();
+
+  scope_down(out);
+
+  indent(out) << "iprot.ReadFieldEnd();" << endl;
+
+  scope_down(out);
+
+  indent(out) << "iprot.ReadStructEnd();" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (field_is_required((*f_iter))) {
+      indent(out) << "if (!isset_" << (*f_iter)->get_name() << ")" << endl;
+      indent_up();
+      out << indent()
+          << "throw new TProtocolException(TProtocolException.INVALID_DATA, "
+          << "\"required field " << prop_name((*f_iter)) << " not set\");"
+          << endl;
+      indent_down();
+    }
+  }
+
+  scope_down(out);
+  out << indent() << "finally" << endl;
+  scope_up(out);
+  out << indent() << "iprot.DecrementRecursionDepth();" << endl;
+  scope_down(out);
+
+  indent_down();
+
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_writer(ostream& out, t_struct* tstruct) {
+  out << indent() << "public void Write(TProtocol oprot) {" << endl;
+  indent_up();
+
+  out << indent() << "oprot.IncrementRecursionDepth();" << endl;
+  out << indent() << "try" << endl;
+  scope_up(out);
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "TStruct struc = new TStruct(\"" << name << "\");" << endl;
+  indent(out) << "oprot.WriteStructBegin(struc);" << endl;
+
+  if (fields.size() > 0) {
+    indent(out) << "TField field = new TField();" << endl;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      bool is_required = field_is_required((*f_iter));
+      bool has_default = field_has_default((*f_iter));
+      bool null_allowed = type_can_be_null((*f_iter)->get_type());
+
+      if (is_required)
+      {
+        if (null_allowed) {
+          indent(out) << "if (" << prop_name((*f_iter)) << " == null)" << endl;
+          indent_up();
+          out << indent()
+              << "throw new TProtocolException(TProtocolException.INVALID_DATA, "
+              << "\"required field " << prop_name((*f_iter)) << " not set\");"
+              << endl;
+          indent_down();
+        }
+      }
+      else
+      {
+        if (nullable_ && !has_default) {
+            indent(out) << "if (" << prop_name((*f_iter)) << " != null) {" << endl;
+        }
+        else if (null_allowed) {
+          out << indent()
+              << "if (" << prop_name((*f_iter)) << " != null && __isset."
+              << normalize_name((*f_iter)->get_name()) << ") {"
+              << endl;
+        }
+        else {
+           indent(out) << "if (__isset." << normalize_name((*f_iter)->get_name()) << ") {" << endl;
+        }
+        indent_up();
+      }
+      indent(out) << "field.Name = \"" << (*f_iter)->get_name() << "\";" << endl;
+      indent(out) << "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl;
+      indent(out) << "field.ID = " << (*f_iter)->get_key() << ";" << endl;
+      indent(out) << "oprot.WriteFieldBegin(field);" << endl;
+
+      generate_serialize_field(out, *f_iter);
+
+      indent(out) << "oprot.WriteFieldEnd();" << endl;
+      if (!is_required) {
+        indent_down();
+        indent(out) << "}" << endl;
+      }
+    }
+  }
+
+  indent(out) << "oprot.WriteFieldStop();" << endl;
+  indent(out) << "oprot.WriteStructEnd();" << endl;
+
+  scope_down(out);
+  out << indent() << "finally" << endl;
+  scope_up(out);
+  out << indent() << "oprot.DecrementRecursionDepth();" << endl;
+  scope_down(out);
+
+  indent_down();
+
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_result_writer(ostream& out, t_struct* tstruct) {
+  indent(out) << "public void Write(TProtocol oprot) {" << endl;
+  indent_up();
+
+  out << indent() << "oprot.IncrementRecursionDepth();" << endl;
+  out << indent() << "try" << endl;
+  scope_up(out);
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "TStruct struc = new TStruct(\"" << name << "\");" << endl;
+  indent(out) << "oprot.WriteStructBegin(struc);" << endl;
+
+  if (fields.size() > 0) {
+    indent(out) << "TField field = new TField();" << endl;
+    bool first = true;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      if (first) {
+        first = false;
+        out << endl << indent() << "if ";
+      } else {
+        out << " else if ";
+      }
+
+      if (nullable_) {
+        out << "(this." << prop_name((*f_iter)) << " != null) {" << endl;
+      } else {
+        out << "(this.__isset." << normalize_name((*f_iter)->get_name()) << ") {" << endl;
+      }
+      indent_up();
+
+      bool null_allowed = !nullable_ && type_can_be_null((*f_iter)->get_type());
+      if (null_allowed) {
+        indent(out) << "if (" << prop_name(*f_iter) << " != null) {" << endl;
+        indent_up();
+      }
+
+      indent(out) << "field.Name = \"" << prop_name(*f_iter) << "\";" << endl;
+      indent(out) << "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl;
+      indent(out) << "field.ID = " << (*f_iter)->get_key() << ";" << endl;
+      indent(out) << "oprot.WriteFieldBegin(field);" << endl;
+
+      generate_serialize_field(out, *f_iter);
+
+      indent(out) << "oprot.WriteFieldEnd();" << endl;
+
+      if (null_allowed) {
+        indent_down();
+        indent(out) << "}" << endl;
+      }
+
+      indent_down();
+      indent(out) << "}";
+    }
+  }
+
+  out << endl << indent() << "oprot.WriteFieldStop();" << endl << indent()
+      << "oprot.WriteStructEnd();" << endl;
+
+  scope_down(out);
+  out << indent() << "finally" << endl;
+  scope_up(out);
+  out << indent() << "oprot.DecrementRecursionDepth();" << endl;
+  scope_down(out);
+
+  indent_down();
+
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_tostring(ostream& out, t_struct* tstruct) {
+  indent(out) << "public override string ToString() {" << endl;
+  indent_up();
+
+  indent(out) << "StringBuilder __sb = new StringBuilder(\"" << tstruct->get_name() << "(\");"
+              << endl;
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  bool useFirstFlag = false;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (!field_is_required((*f_iter))) {
+      indent(out) << "bool __first = true;" << endl;
+      useFirstFlag = true;
+    }
+    break;
+  }
+
+  bool had_required = false; // set to true after first required field has been processed
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    bool is_required = field_is_required((*f_iter));
+    bool has_default = field_has_default((*f_iter));
+    if (nullable_ && !has_default && !is_required) {
+      indent(out) << "if (" << prop_name((*f_iter)) << " != null) {" << endl;
+      indent_up();
+    } else if (!is_required) {
+      bool null_allowed = type_can_be_null((*f_iter)->get_type());
+      if (null_allowed) {
+        indent(out) << "if (" << prop_name((*f_iter)) << " != null && __isset."
+                    << normalize_name((*f_iter)->get_name()) << ") {" << endl;
+        indent_up();
+      } else {
+        indent(out) << "if (__isset." << normalize_name((*f_iter)->get_name()) << ") {" << endl;
+        indent_up();
+      }
+    }
+
+    if (useFirstFlag && (!had_required)) {
+      indent(out) << "if(!__first) { __sb.Append(\", \"); }" << endl;
+      if (!is_required) {
+        indent(out) << "__first = false;" << endl;
+      }
+      indent(out) << "__sb.Append(\"" << prop_name((*f_iter)) << ": \");" << endl;
+    } else {
+      indent(out) << "__sb.Append(\", " << prop_name((*f_iter)) << ": \");" << endl;
+    }
+
+    t_type* ttype = (*f_iter)->get_type();
+    if (ttype->is_xception() || ttype->is_struct()) {
+      indent(out) << "__sb.Append(" << prop_name((*f_iter))
+                  << "== null ? \"<null>\" : " << prop_name((*f_iter)) << ".ToString());" << endl;
+    } else {
+      indent(out) << "__sb.Append(" << prop_name((*f_iter)) << ");" << endl;
+    }
+
+    if (!is_required) {
+      indent_down();
+      indent(out) << "}" << endl;
+    } else {
+      had_required = true; // now __first must be false, so we don't need to check it anymore
+    }
+  }
+
+  indent(out) << "__sb.Append(\")\");" << endl;
+  indent(out) << "return __sb.ToString();" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_union(t_struct* tunion) {
+  string f_union_name = namespace_dir_ + "/" + (tunion->get_name()) + ".cs";
+  ofstream_with_content_based_conditional_update f_union;
+
+  f_union.open(f_union_name.c_str());
+
+  f_union << autogen_comment() << csharp_type_usings() << csharp_thrift_usings() << endl;
+
+  generate_csharp_union_definition(f_union, tunion);
+
+  f_union.close();
+}
+
+void t_csharp_generator::generate_csharp_union_definition(std::ostream& out, t_struct* tunion) {
+  // Let's define the class first
+  start_csharp_namespace(out);
+
+  indent(out) << "public abstract partial class " << tunion->get_name() << " : TAbstractBase {"
+              << endl;
+
+  indent_up();
+
+  indent(out) << "public abstract void Write(TProtocol protocol);" << endl;
+  indent(out) << "public readonly bool Isset;" << endl;
+  indent(out) << "public abstract object Data { get; }" << endl;
+
+  indent(out) << "protected " << tunion->get_name() << "(bool isset) {" << endl;
+  indent_up();
+  indent(out) << "Isset = isset;" << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  indent(out) << "public class ___undefined : " << tunion->get_name() << " {" << endl;
+  indent_up();
+
+  indent(out) << "public override object Data { get { return null; } }" << endl;
+
+  indent(out) << "public ___undefined() : base(false) {}" << endl << endl;
+
+  indent(out) << "public override void Write(TProtocol protocol) {" << endl;
+  indent_up();
+  indent(out) << "throw new TProtocolException( TProtocolException.INVALID_DATA, \"Cannot persist "
+                 "an union type which is not set.\");" << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  const vector<t_field*>& fields = tunion->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    generate_csharp_union_class(out, tunion, (*f_iter));
+  }
+
+  generate_csharp_union_reader(out, tunion);
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  end_csharp_namespace(out);
+}
+
+void t_csharp_generator::generate_csharp_union_class(std::ostream& out,
+                                                     t_struct* tunion,
+                                                     t_field* tfield) {
+  indent(out) << "public class " << tfield->get_name() << " : " << tunion->get_name() << " {"
+              << endl;
+  indent_up();
+  indent(out) << "private " << type_name(tfield->get_type()) << " _data;" << endl;
+  indent(out) << "public override object Data { get { return _data; } }" << endl;
+  indent(out) << "public " << tfield->get_name() << "(" << type_name(tfield->get_type())
+              << " data) : base(true) {" << endl;
+  indent_up();
+  indent(out) << "this._data = data;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+  indent(out) << "public override void Write(TProtocol oprot) {" << endl;
+  indent_up();
+
+  out << indent() << "oprot.IncrementRecursionDepth();" << endl;
+  out << indent() << "try" << endl;
+  scope_up(out);
+
+  indent(out) << "TStruct struc = new TStruct(\"" << tunion->get_name() << "\");" << endl;
+  indent(out) << "oprot.WriteStructBegin(struc);" << endl;
+
+  indent(out) << "TField field = new TField();" << endl;
+  indent(out) << "field.Name = \"" << tfield->get_name() << "\";" << endl;
+  indent(out) << "field.Type = " << type_to_enum(tfield->get_type()) << ";" << endl;
+  indent(out) << "field.ID = " << tfield->get_key() << ";" << endl;
+  indent(out) << "oprot.WriteFieldBegin(field);" << endl;
+
+  generate_serialize_field(out, tfield, "_data", true, true);
+
+  indent(out) << "oprot.WriteFieldEnd();" << endl;
+  indent(out) << "oprot.WriteFieldStop();" << endl;
+  indent(out) << "oprot.WriteStructEnd();" << endl;
+  indent_down();
+
+  scope_down(out);
+  out << indent() << "finally" << endl;
+  scope_up(out);
+  out << indent() << "oprot.DecrementRecursionDepth();" << endl;
+  scope_down(out);
+
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_equals(ostream& out, t_struct* tstruct) {
+  indent(out) << "public override bool Equals(object that) {" << endl;
+  indent_up();
+
+  indent(out) << "var other = that as " << type_name(tstruct) << ";" << endl;
+  indent(out) << "if (other == null) return false;" << endl;
+  indent(out) << "if (ReferenceEquals(this, other)) return true;" << endl;
+
+  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;
+      indent(out) << "return ";
+      indent_up();
+    } else {
+      out << endl;
+      indent(out) << "&& ";
+    }
+    if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) {
+      out << "((__isset." << normalize_name((*f_iter)->get_name()) << " == other.__isset."
+          << normalize_name((*f_iter)->get_name()) << ") && ((!__isset."
+          << normalize_name((*f_iter)->get_name()) << ") || (";
+    }
+    t_type* ttype = (*f_iter)->get_type();
+    if (ttype->is_container() || ttype->is_binary()) {
+      out << "TCollections.Equals(";
+    } else {
+      out << "System.Object.Equals(";
+    }
+    out << prop_name((*f_iter)) << ", other." << prop_name((*f_iter)) << ")";
+    if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter)))) {
+      out << ")))";
+    }
+  }
+  if (first) {
+    indent(out) << "return true;" << endl;
+  } else {
+    out << ";" << endl;
+    indent_down();
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_csharp_struct_hashcode(ostream& out, t_struct* tstruct) {
+  indent(out) << "public override int GetHashCode() {" << endl;
+  indent_up();
+
+  indent(out) << "int hashcode = 0;" << endl;
+  indent(out) << "unchecked {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_type* ttype = (*f_iter)->get_type();
+    indent(out) << "hashcode = (hashcode * 397) ^ ";
+    if (field_is_required((*f_iter))) {
+      out << "(";
+    } else if (nullable_) {
+      out << "(" << prop_name((*f_iter)) << " == null ? 0 : ";
+    } else {
+      out << "(!__isset." << normalize_name((*f_iter)->get_name()) << " ? 0 : ";
+    }
+    if (ttype->is_container()) {
+      out << "(TCollections.GetHashCode(" << prop_name((*f_iter)) << "))";
+    } else {
+      out << "(" << prop_name((*f_iter)) << ".GetHashCode())";
+    }
+    out << ");" << endl;
+  }
+
+  indent_down();
+  indent(out) << "}" << endl;
+  indent(out) << "return hashcode;" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_service(t_service* tservice) {
+  string f_service_name = namespace_dir_ + "/" + service_name_ + ".cs";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << autogen_comment() << csharp_type_usings() << csharp_thrift_usings() << endl;
+
+  start_csharp_namespace(f_service_);
+
+  indent(f_service_) << "public partial class " << normalize_name(service_name_) << " {" << endl;
+  indent_up();
+
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+
+  indent_down();
+
+  indent(f_service_) << "}" << endl;
+  end_csharp_namespace(f_service_);
+  f_service_.close();
+}
+
+void t_csharp_generator::generate_service_interface(t_service* tservice) {
+  generate_separate_service_interfaces(tservice);
+}
+
+void t_csharp_generator::generate_separate_service_interfaces(t_service* tservice) {
+  generate_sync_service_interface(tservice);
+
+  if (async_) {
+    generate_async_service_interface(tservice);
+  }
+
+  generate_combined_service_interface(tservice);
+}
+
+void t_csharp_generator::generate_sync_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_iface = " : " + extends + ".ISync";
+  }
+
+  generate_csharp_doc(f_service_, tservice);
+
+  if (wcf_) {
+    indent(f_service_) << "[System.ServiceModel.ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
+  }
+  indent(f_service_) << "public interface ISync" << extends_iface << " {" << endl;
+
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_csharp_doc(f_service_, *f_iter);
+
+    // if we're using WCF, add the corresponding attributes
+    if (wcf_) {
+      indent(f_service_) << "[System.ServiceModel.OperationContract]" << endl;
+
+      const std::vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        indent(f_service_) << "[System.ServiceModel.FaultContract(typeof("
+          + type_name((*x_iter)->get_type(), false, false) + "Fault))]" << endl;
+      }
+    }
+
+    indent(f_service_) << function_signature(*f_iter) << ";" << endl;
+  }
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_async_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_iface = " : " + extends + ".IAsync";
+  }
+
+  generate_csharp_doc(f_service_, tservice);
+
+  if (wcf_) {
+    indent(f_service_) << "[System.ServiceModel.ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
+  }
+  indent(f_service_) << "public interface IAsync" << extends_iface << " {" << endl;
+
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_csharp_doc(f_service_, *f_iter);
+
+    // if we're using WCF, add the corresponding attributes
+    if (wcf_) {
+      indent(f_service_) << "[System.ServiceModel.OperationContract]" << endl;
+
+      const std::vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        indent(f_service_) << "[System.ServiceModel.FaultContract(typeof("
+          + type_name((*x_iter)->get_type(), false, false) + "Fault))]" << endl;
+      }
+    }
+
+    indent(f_service_) << function_signature_async(*f_iter) << ";" << endl;
+  }
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_combined_service_interface(t_service* tservice) {
+  string extends_iface = " : ISync";
+
+  if (async_) {
+    extends_iface += ", IAsync";
+  }
+
+  generate_csharp_doc(f_service_, tservice);
+
+  if (wcf_) {
+    indent(f_service_) << "[System.ServiceModel.ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
+  }
+
+  indent(f_service_) << "public interface Iface" << extends_iface << " {" << endl;
+
+  indent_up();
+
+  // We need to generate extra old style async methods for silverlight. Since
+  // this isn't something you'd want to implement server-side, just put them into
+  // the main Iface interface.
+  generate_silverlight_async_methods(tservice);
+
+  indent_down();
+
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_silverlight_async_methods(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_csharp_doc(f_service_, *f_iter);
+
+    // For backwards compatibility, include the Begin_, End_ methods if we're generating
+    // with the async flag. I'm not sure this is necessary, so someone with more knowledge
+    // can maybe remove these checks if they know it's safe.
+    if (!async_) {
+      indent(f_service_) << "#if SILVERLIGHT" << endl;
+    }
+
+    indent(f_service_) << function_signature_async_begin(*f_iter, "Begin_") << ";" << endl;
+    indent(f_service_) << function_signature_async_end(*f_iter, "End_") << ";" << endl;
+
+    if (!async_) {
+      indent(f_service_) << "#endif" << endl;
+    }
+  }
+}
+
+void t_csharp_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_csharp_struct_definition(f_service_, ts, false, true);
+    generate_function_helpers(*f_iter);
+  }
+}
+
+void t_csharp_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_client = extends + ".Client, ";
+  } else {
+    extends_client = "IDisposable, ";
+  }
+
+  generate_csharp_doc(f_service_, tservice);
+
+  indent(f_service_) << "public class Client : " << extends_client << "Iface {" << endl;
+  indent_up();
+  indent(f_service_) << "public Client(TProtocol prot) : this(prot, prot)" << endl;
+  scope_up(f_service_);
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  indent(f_service_) << "public Client(TProtocol iprot, TProtocol oprot)";
+  if (!extends.empty()) {
+    f_service_ << " : base(iprot, oprot)";
+  }
+  f_service_ << endl;
+
+  scope_up(f_service_);
+  if (extends.empty()) {
+    f_service_ << indent() << "iprot_ = iprot;" << endl << indent() << "oprot_ = oprot;" << endl;
+  }
+  scope_down(f_service_);
+
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_ << indent() << "protected TProtocol iprot_;" << endl << indent()
+               << "protected TProtocol oprot_;" << endl << indent() << "protected int seqid_;"
+               << endl << endl;
+
+    f_service_ << indent() << "public TProtocol InputProtocol" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "get { return iprot_; }" << endl;
+    scope_down(f_service_);
+
+    f_service_ << indent() << "public TProtocol OutputProtocol" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "get { return oprot_; }" << endl;
+    scope_down(f_service_);
+    f_service_ << endl << endl;
+
+    indent(f_service_) << "#region \" IDisposable Support \"" << endl;
+    indent(f_service_) << "private bool _IsDisposed;" << endl << endl;
+    indent(f_service_) << "// IDisposable" << endl;
+    indent(f_service_) << "public void Dispose()" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "Dispose(true);" << endl;
+    scope_down(f_service_);
+    indent(f_service_) << endl << endl;
+    indent(f_service_) << "protected virtual void Dispose(bool disposing)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "if (!_IsDisposed)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "if (disposing)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "if (iprot_ != null)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "((IDisposable)iprot_).Dispose();" << endl;
+    scope_down(f_service_);
+    indent(f_service_) << "if (oprot_ != null)" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "((IDisposable)oprot_).Dispose();" << endl;
+    scope_down(f_service_);
+    scope_down(f_service_);
+    scope_down(f_service_);
+    indent(f_service_) << "_IsDisposed = true;" << endl;
+    scope_down(f_service_);
+    indent(f_service_) << "#endregion" << endl;
+    f_service_ << endl << endl;
+  }
+
+  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) {
+    string funname = (*f_iter)->get_name();
+
+    indent(f_service_) << endl;
+
+    if (!async_) {
+      indent(f_service_) << "#if SILVERLIGHT" << endl;
+      indent(f_service_) << endl;
+    }
+    // Begin_
+    indent(f_service_) << "public " << function_signature_async_begin(*f_iter, "Begin_") << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "return "
+                       << "send_" << funname << "(callback, state";
+
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    prepare_member_name_mapping(arg_struct);
+
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << ", ";
+      f_service_ << normalize_name((*fld_iter)->get_name());
+    }
+    f_service_ << ");" << endl;
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    // End
+    indent(f_service_) << "public " << function_signature_async_end(*f_iter, "End_") << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "oprot_.Transport.EndFlush(asyncResult);" << endl;
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "return ";
+      }
+      f_service_ << "recv_" << funname << "();" << endl;
+    }
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    // async
+    bool first;
+    if (async_) {
+      indent(f_service_) << "public async " << function_signature_async(*f_iter, "") << endl;
+      scope_up(f_service_);
+
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) << type_name((*f_iter)->get_returntype()) << " retval;" << endl;
+        indent(f_service_) << "retval = ";
+      } else {
+        indent(f_service_);
+      }
+      f_service_ << "await Task.Run(() =>" << endl;
+      scope_up(f_service_);
+      indent(f_service_);
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "return ";
+      }
+      f_service_ << funname << "(";
+      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_down();
+      indent(f_service_) << "});" << endl;
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) << "return retval;" << endl;
+      }
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
+
+    if (!async_) {
+      indent(f_service_) << "#endif" << endl << endl;
+    }
+
+    generate_csharp_doc(f_service_, *f_iter);
+    indent(f_service_) << "public " << function_signature(*f_iter) << endl;
+    scope_up(f_service_);
+
+    // silverlight invoke
+    if (!async_) {
+      indent(f_service_) << "#if SILVERLIGHT" << endl;
+
+      indent(f_service_) << "var asyncResult = Begin_" << funname << "(null, null";
+      for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+        f_service_ << ", " << normalize_name((*fld_iter)->get_name());
+      }
+      f_service_ << ");" << endl;
+      
+      if (!(*f_iter)->is_oneway()) {
+        f_service_ << indent();
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          f_service_ << "return ";
+        }
+        f_service_ << "End_" << funname << "(asyncResult);" << endl;
+      }
+      f_service_ << endl;
+
+      indent(f_service_) << "#else" << endl;
+    }
+
+    // synchronous invoke
+    indent(f_service_) << "send_" << funname << "(";
+  
+    first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      f_service_ << normalize_name((*fld_iter)->get_name());
+    }
+    f_service_ << ");" << endl;
+  
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "return ";
+      }
+      f_service_ << "recv_" << funname << "();" << endl;
+    }
+    f_service_ << endl;
+
+    if (!async_) {
+      indent(f_service_) << "#endif" << endl;
+    }
+    scope_down(f_service_);
+
+    // Send
+    t_function send_function(g_type_void,
+                             string("send_") + (*f_iter)->get_name(),
+                             (*f_iter)->get_arglist());
+
+    string argsname = (*f_iter)->get_name() + "_args";
+
+    if (!async_) {
+      indent(f_service_) << "#if SILVERLIGHT" << endl;
+    }
+
+    indent(f_service_) << "public " << function_signature_async_begin(&send_function) << endl;
+    scope_up(f_service_);
+
+    f_service_ << indent() << "oprot_.WriteMessageBegin(new TMessage(\"" << funname << "\", "
+               << ((*f_iter)->is_oneway() ? "TMessageType.Oneway" : "TMessageType.Call")
+               << ", seqid_));" << endl << indent() << argsname << " args = new " << argsname
+               << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << indent() << "args." << prop_name(*fld_iter) << " = "
+                 << normalize_name((*fld_iter)->get_name()) << ";" << endl;
+    }
+
+    f_service_ << indent() << "args.Write(oprot_);" << endl << indent()
+               << "oprot_.WriteMessageEnd();" << endl;
+    indent(f_service_) << "return oprot_.Transport.BeginFlush(callback, state);" << endl;
+      
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    if (!async_) {
+      indent(f_service_) << "#else" << endl;
+      f_service_ << endl;
+    }
+
+    indent(f_service_) << "public " << function_signature(&send_function) << endl;
+    scope_up(f_service_);
+
+    f_service_ << indent() << "oprot_.WriteMessageBegin(new TMessage(\"" << funname << "\", "
+               << ((*f_iter)->is_oneway() ? "TMessageType.Oneway" : "TMessageType.Call")
+               << ", seqid_));" << endl << indent() << argsname << " args = new " << argsname
+               << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << indent() << "args." << prop_name(*fld_iter) << " = "
+                 << normalize_name((*fld_iter)->get_name()) << ";" << endl;
+    }
+
+    f_service_ << indent() << "args.Write(oprot_);" << endl << indent()
+               << "oprot_.WriteMessageEnd();" << endl;
+
+    indent(f_service_) << "oprot_.Transport.Flush();" << endl;
+    cleanup_member_name_mapping(arg_struct);
+    scope_down(f_service_);
+
+    if (!async_) {
+      indent(f_service_) << "#endif" << endl;
+    }
+
+    f_service_ << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      string resultname = (*f_iter)->get_name() + "_result";
+
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs,
+                               (*f_iter)->get_xceptions());
+      indent(f_service_) << "public " << function_signature(&recv_function) << endl;
+      scope_up(f_service_);
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      prepare_member_name_mapping(xs, xs->get_members(), resultname);
+
+      f_service_ << indent() << "TMessage msg = iprot_.ReadMessageBegin();" << endl << indent()
+                 << "if (msg.Type == TMessageType.Exception) {" << endl;
+      indent_up();
+      f_service_ << indent() << "TApplicationException x = TApplicationException.Read(iprot_);"
+                 << endl << indent() << "iprot_.ReadMessageEnd();" << endl << indent() << "throw x;"
+                 << endl;
+      indent_down();
+      f_service_ << indent() << "}" << endl << indent() << resultname << " result = new "
+                 << resultname << "();" << endl << indent() << "result.Read(iprot_);" << endl
+                 << indent() << "iprot_.ReadMessageEnd();" << endl;
+
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        if (nullable_) {
+          if (type_can_be_null((*f_iter)->get_returntype())) {
+            f_service_ << indent() << "if (result.Success != null) {" << endl << indent()
+                       << "  return result.Success;" << endl << indent() << "}" << endl;
+          } else {
+            f_service_ << indent() << "if (result.Success.HasValue) {" << endl << indent()
+                       << "  return result.Success.Value;" << endl << indent() << "}" << endl;
+          }
+        } else {
+          f_service_ << indent() << "if (result.__isset.success) {" << endl << indent()
+                     << "  return result.Success;" << endl << indent() << "}" << endl;
+        }
+      }
+
+      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) {
+        if (nullable_) {
+          f_service_ << indent() << "if (result." << prop_name(*x_iter) << " != null) {" << endl
+                     << indent() << "  throw result." << prop_name(*x_iter) << ";" << endl
+                     << indent() << "}" << endl;
+        } else {
+          f_service_ << indent() << "if (result.__isset." << normalize_name((*x_iter)->get_name())
+                     << ") {" << endl << indent() << "  throw result." << prop_name(*x_iter) << ";"
+                     << endl << indent() << "}" << endl;
+        }
+      }
+
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) << "return;" << endl;
+      } else {
+        f_service_ << indent()
+                   << "throw new "
+                      "TApplicationException(TApplicationException.ExceptionType.MissingResult, \""
+                   << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
+      }
+
+      cleanup_member_name_mapping((*f_iter)->get_xceptions());
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl;
+}
+
+void t_csharp_generator::generate_service_server(t_service* tservice) {
+  if (async_) {
+    generate_service_server_async(tservice);
+    generate_service_server_sync(tservice);
+  }
+  else {
+    generate_service_server_sync(tservice);
+  }
+}
+
+void t_csharp_generator::generate_service_server_sync(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_processor = extends + ".Processor, ";
+  }
+
+  indent(f_service_) << "public class Processor : " << extends_processor << "TProcessor {" << endl;
+  indent_up();
+
+  indent(f_service_) << "public Processor(ISync iface)";
+
+  if (!extends.empty()) {
+    f_service_ << " : base(iface)";
+  }
+  f_service_ << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << "iface_ = iface;" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << indent() << "processMap_[\"" << (*f_iter)->get_name()
+      << "\"] = " << (*f_iter)->get_name() << "_Process;" << endl;
+  }
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_
+      << indent()
+      << "protected delegate void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);"
+      << endl;
+  }
+
+  f_service_ << indent() << "private ISync iface_;" << endl;
+
+  if (extends.empty()) {
+    f_service_ << indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new "
+      "Dictionary<string, ProcessFunction>();" << endl;
+  }
+
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    indent(f_service_) << "public bool Process(TProtocol iprot, TProtocol oprot)" << endl;
+  }
+  else {
+    indent(f_service_) << "public new bool Process(TProtocol iprot, TProtocol oprot)" << endl;
+  }
+  scope_up(f_service_);
+
+  f_service_ << indent() << "try" << endl;
+  scope_up(f_service_);
+
+  f_service_ << indent() << "TMessage msg = iprot.ReadMessageBegin();" << endl;
+
+  f_service_
+    << indent() << "ProcessFunction fn;" << endl << indent()
+    << "processMap_.TryGetValue(msg.Name, out fn);" << endl << indent() << "if (fn == null) {"
+    << endl << indent() << "  TProtocolUtil.Skip(iprot, TType.Struct);" << endl << indent()
+    << "  iprot.ReadMessageEnd();" << endl << indent()
+    << "  TApplicationException x = new TApplicationException "
+    "(TApplicationException.ExceptionType.UnknownMethod, \"Invalid method name: '\" + "
+    "msg.Name + \"'\");" << endl << indent()
+    << "  oprot.WriteMessageBegin(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID));"
+    << endl << indent() << "  x.Write(oprot);" << endl << indent() << "  oprot.WriteMessageEnd();"
+    << endl << indent() << "  oprot.Transport.Flush();" << endl << indent() << "  return true;"
+    << endl << indent() << "}" << endl << indent() << "fn(msg.SeqID, iprot, oprot);" << endl;
+
+  scope_down(f_service_);
+
+  f_service_ << indent() << "catch (IOException)" << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << "return false;" << endl;
+  scope_down(f_service_);
+
+  f_service_ << indent() << "return true;" << endl;
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_service_server_async(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_processor = extends + ".AsyncProcessor, ";
+  }
+
+  indent(f_service_) << "public class AsyncProcessor : " << extends_processor << "TAsyncProcessor {" << endl;
+  indent_up();
+
+  indent(f_service_) << "public AsyncProcessor(IAsync iface)";
+  if (!extends.empty()) {
+    f_service_ << " : base(iface)";
+  }
+  f_service_ << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << "iface_ = iface;" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << indent() << "processMap_[\"" << (*f_iter)->get_name()
+      << "\"] = " << (*f_iter)->get_name() << "_ProcessAsync;" << endl;
+  }
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_
+      << indent()
+      << "protected delegate Task ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);"
+      << endl;
+  }
+
+  f_service_ << indent() << "private IAsync iface_;" << endl;
+
+  if (extends.empty()) {
+    f_service_ << indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new "
+      "Dictionary<string, ProcessFunction>();" << endl;
+  }
+
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    indent(f_service_) << "public async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl;
+  }
+  else {
+    indent(f_service_) << "public new async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl;
+  }
+  scope_up(f_service_);
+
+  f_service_ << indent() << "try" << endl;
+  scope_up(f_service_);
+
+  f_service_ << indent() << "TMessage msg = iprot.ReadMessageBegin();" << endl;
+
+  f_service_
+    << indent() << "ProcessFunction fn;" << endl << indent()
+    << "processMap_.TryGetValue(msg.Name, out fn);" << endl << indent() << "if (fn == null) {"
+    << endl << indent() << "  TProtocolUtil.Skip(iprot, TType.Struct);" << endl << indent()
+    << "  iprot.ReadMessageEnd();" << endl << indent()
+    << "  TApplicationException x = new TApplicationException "
+    "(TApplicationException.ExceptionType.UnknownMethod, \"Invalid method name: '\" + "
+    "msg.Name + \"'\");" << endl << indent()
+    << "  oprot.WriteMessageBegin(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID));"
+    << endl << indent() << "  x.Write(oprot);" << endl << indent() << "  oprot.WriteMessageEnd();"
+    << endl << indent() << "  oprot.Transport.Flush();" << endl << indent() << "  return true;"
+    << endl << indent() << "}" << endl << indent() << "await fn(msg.SeqID, iprot, oprot);" << endl;
+
+  scope_down(f_service_);
+
+  f_service_ << indent() << "catch (IOException)" << endl;
+  scope_up(f_service_);
+  f_service_ << indent() << "return false;" << endl;
+  scope_down(f_service_);
+
+  f_service_ << indent() << "return true;" << endl;
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function_async(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_function_helpers(t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return;
+  }
+
+  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_csharp_struct_definition(f_service_, &result, false, true, true);
+}
+
+void t_csharp_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+  indent(f_service_) << "public void " << tfunction->get_name()
+                     << "_Process(int seqid, TProtocol iprot, TProtocol oprot)" << endl;
+  scope_up(f_service_);
+
+  string argsname = tfunction->get_name() + "_args";
+  string resultname = tfunction->get_name() + "_result";
+
+  f_service_ << indent() << argsname << " args = new " << argsname << "();" << endl
+             << indent() << "args.Read(iprot);" << endl
+             << indent() << "iprot.ReadMessageEnd();" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl;
+  }
+
+  f_service_ << indent() << "try" << endl
+             << indent() << "{" << endl;
+  indent_up();
+
+  if (xceptions.size() > 0) {
+    f_service_ << indent() << "try" << endl
+               << indent() << "{" << endl;
+    indent_up();
+  }
+
+  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_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "result.Success = ";
+  }
+  f_service_ << "iface_." << normalize_name(tfunction->get_name()) << "(";
+  bool first = true;
+  prepare_member_name_mapping(arg_struct);
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_service_ << ", ";
+    }
+    f_service_ << "args." << prop_name(*f_iter);
+    if (nullable_ && !type_can_be_null((*f_iter)->get_type())) {
+      f_service_ << ".Value";
+    }
+  }
+  cleanup_member_name_mapping(arg_struct);
+  f_service_ << ");" << endl;
+
+  prepare_member_name_mapping(xs, xs->get_members(), resultname);
+  if (xceptions.size() > 0) {
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << indent() << "catch (" << type_name((*x_iter)->get_type(), false, false) << " "
+                 << (*x_iter)->get_name() << ")" << endl
+                 << indent() << "{" << endl;
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        f_service_ << indent() << "result." << prop_name(*x_iter) << " = " << (*x_iter)->get_name()
+                   << ";" << endl;
+        indent_down();
+      }
+      f_service_ << indent() << "}" << endl;
+    }
+  }
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << "oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name()
+               << "\", TMessageType.Reply, seqid)); " << endl;
+    f_service_ << indent() << "result.Write(oprot);" << endl;
+  }
+  indent_down();
+
+  cleanup_member_name_mapping(xs);
+
+  f_service_ << indent() << "}" << endl
+             << indent() << "catch (TTransportException)" << endl
+             << indent() << "{" << endl
+             << indent() << "  throw;" << endl
+             << indent() << "}" << endl
+             << indent() << "catch (Exception ex)" << endl
+             << indent() << "{" << endl
+             << indent() << "  Console.Error.WriteLine(\"Error occurred in processor:\");" << endl
+             << indent() << "  Console.Error.WriteLine(ex.ToString());" << endl;
+
+  if (tfunction->is_oneway()) {
+    f_service_ << indent() << "}" << endl;
+  } else {
+    f_service_ << indent() << "  TApplicationException x = new TApplicationException" << indent()
+               << "(TApplicationException.ExceptionType.InternalError,\" Internal error.\");"
+               << endl
+               << indent() << "  oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name()
+               << "\", TMessageType.Exception, seqid));" << endl
+               << indent() << "  x.Write(oprot);" << endl
+               << indent() << "}" << endl;
+    f_service_ << indent() << "oprot.WriteMessageEnd();" << endl
+               << indent() << "oprot.Transport.Flush();" << endl;
+  }
+
+  scope_down(f_service_);
+
+  f_service_ << endl;
+}
+
+void t_csharp_generator::generate_process_function_async(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+  indent(f_service_) << "public async Task " << tfunction->get_name()
+    << "_ProcessAsync(int seqid, TProtocol iprot, TProtocol oprot)" << endl;
+  scope_up(f_service_);
+
+  string argsname = tfunction->get_name() + "_args";
+  string resultname = tfunction->get_name() + "_result";
+
+  f_service_ << indent() << argsname << " args = new " << argsname << "();" << endl
+    << indent() << "args.Read(iprot);" << endl
+    << indent() << "iprot.ReadMessageEnd();" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl;
+  }
+
+  f_service_ << indent() << "try" << endl
+    << indent() << "{" << endl;
+  indent_up();
+
+  if (xceptions.size() > 0) {
+    f_service_ << indent() << "try" << endl
+      << indent() << "{" << endl;
+    indent_up();
+  }
+
+  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_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "result.Success = ";
+  }
+  f_service_ << "await iface_." << normalize_name(tfunction->get_name()) << "Async(";
+  bool first = true;
+  prepare_member_name_mapping(arg_struct);
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    }
+    else {
+      f_service_ << ", ";
+    }
+    f_service_ << "args." << prop_name(*f_iter);
+    if (nullable_ && !type_can_be_null((*f_iter)->get_type())) {
+      f_service_ << ".Value";
+    }
+  }
+  cleanup_member_name_mapping(arg_struct);
+  f_service_ << ");" << endl;
+
+  prepare_member_name_mapping(xs, xs->get_members(), resultname);
+  if (xceptions.size() > 0) {
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << indent() << "catch (" << type_name((*x_iter)->get_type(), false, false) << " "
+        << (*x_iter)->get_name() << ")" << endl
+        << indent() << "{" << endl;
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        f_service_ << indent() << "result." << prop_name(*x_iter) << " = " << (*x_iter)->get_name()
+          << ";" << endl;
+        indent_down();
+      }
+      f_service_ << indent() << "}" << endl;
+    }
+  }
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << "oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name()
+      << "\", TMessageType.Reply, seqid)); " << endl;
+    f_service_ << indent() << "result.Write(oprot);" << endl;
+  }
+  indent_down();
+
+  cleanup_member_name_mapping(xs);
+
+  f_service_ << indent() << "}" << endl
+    << indent() << "catch (TTransportException)" << endl
+    << indent() << "{" << endl
+    << indent() << "  throw;" << endl
+    << indent() << "}" << endl
+    << indent() << "catch (Exception ex)" << endl
+    << indent() << "{" << endl
+    << indent() << "  Console.Error.WriteLine(\"Error occurred in processor:\");" << endl
+    << indent() << "  Console.Error.WriteLine(ex.ToString());" << endl;
+
+  if (tfunction->is_oneway()) {
+    f_service_ << indent() << "}" << endl;
+  }
+  else {
+    f_service_ << indent() << "  TApplicationException x = new TApplicationException" << indent()
+      << "(TApplicationException.ExceptionType.InternalError,\" Internal error.\");"
+      << endl
+      << indent() << "  oprot.WriteMessageBegin(new TMessage(\"" << tfunction->get_name()
+      << "\", TMessageType.Exception, seqid));" << endl
+      << indent() << "  x.Write(oprot);" << endl
+      << indent() << "}" << endl;
+    f_service_ << indent() << "oprot.WriteMessageEnd();" << endl
+      << indent() << "oprot.Transport.Flush();" << endl;
+  }
+
+  scope_down(f_service_);
+
+  f_service_ << endl;
+}
+
+void t_csharp_generator::generate_csharp_union_reader(std::ostream& out, t_struct* tunion) {
+  // Thanks to THRIFT-1768, we don't need to check for required fields in the union
+  const vector<t_field*>& fields = tunion->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "public static " << tunion->get_name() << " Read(TProtocol iprot)" << endl;
+  scope_up(out);
+
+  out << indent() << "iprot.IncrementRecursionDepth();" << endl;
+  out << indent() << "try" << endl;
+  scope_up(out);
+
+  indent(out) << tunion->get_name() << " retval;" << endl;
+  indent(out) << "iprot.ReadStructBegin();" << endl;
+  indent(out) << "TField field = iprot.ReadFieldBegin();" << endl;
+  // we cannot have the first field be a stop -- we must have a single field defined
+  indent(out) << "if (field.Type == TType.Stop)" << endl;
+  scope_up(out);
+  indent(out) << "iprot.ReadFieldEnd();" << endl;
+  indent(out) << "retval = new ___undefined();" << endl;
+  scope_down(out);
+  indent(out) << "else" << endl;
+  scope_up(out);
+  indent(out) << "switch (field.ID)" << endl;
+  scope_up(out);
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) << "case " << (*f_iter)->get_key() << ":" << endl;
+    indent_up();
+    indent(out) << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+    indent_up();
+
+    indent(out) << type_name((*f_iter)->get_type()) << " temp;" << endl;
+    generate_deserialize_field(out, (*f_iter), "temp", true);
+    indent(out) << "retval = new " << (*f_iter)->get_name() << "(temp);" << endl;
+
+    indent_down();
+    out << indent() << "} else { " << endl << indent() << "  TProtocolUtil.Skip(iprot, field.Type);"
+        << endl << indent() << "  retval = new ___undefined();" << endl << indent() << "}" << endl
+        << indent() << "break;" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default: " << endl;
+  indent_up();
+  indent(out) << "TProtocolUtil.Skip(iprot, field.Type);" << endl << indent()
+              << "retval = new ___undefined();" << endl;
+  indent(out) << "break;" << endl;
+  indent_down();
+
+  scope_down(out);
+
+  indent(out) << "iprot.ReadFieldEnd();" << endl;
+
+  indent(out) << "if (iprot.ReadFieldBegin().Type != TType.Stop)" << endl;
+  scope_up(out);
+  indent(out) << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl;
+  scope_down(out);
+
+  // end of else for TStop
+  scope_down(out);
+  indent(out) << "iprot.ReadStructEnd();" << endl;
+  indent(out) << "return retval;" << endl;
+  indent_down();
+
+  scope_down(out);
+  out << indent() << "finally" << endl;
+  scope_up(out);
+  out << indent() << "iprot.DecrementRecursionDepth();" << endl;
+  scope_down(out);
+
+  indent(out) << "}" << endl << endl;
+}
+
+void t_csharp_generator::generate_deserialize_field(ostream& out,
+                                                    t_field* tfield,
+                                                    string prefix,
+                                                    bool is_propertyless) {
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = prefix + (is_propertyless ? "" : prop_name(tfield));
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) << name << " = ";
+
+    if (type->is_enum()) {
+      out << "(" << type_name(type, false, true) << ")";
+    }
+
+    out << "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:
+        if (type->is_binary()) {
+          out << "ReadBinary();";
+        } else {
+          out << "ReadString();";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "ReadBool();";
+        break;
+      case t_base_type::TYPE_I8:
+        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 C# name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "ReadI32();";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+void t_csharp_generator::generate_deserialize_struct(ostream& out,
+                                                     t_struct* tstruct,
+                                                     string prefix) {
+  if (union_ && tstruct->is_union()) {
+    out << indent() << prefix << " = " << type_name(tstruct) << ".Read(iprot);" << endl;
+  } else {
+    out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl << indent()
+        << prefix << ".Read(iprot);" << endl;
+  }
+}
+
+void t_csharp_generator::generate_deserialize_container(ostream& out,
+                                                        t_type* ttype,
+                                                        string prefix) {
+  scope_up(out);
+
+  string obj;
+
+  if (ttype->is_map()) {
+    obj = tmp("_map");
+  } else if (ttype->is_set()) {
+    obj = tmp("_set");
+  } else if (ttype->is_list()) {
+    obj = tmp("_list");
+  }
+
+  indent(out) << prefix << " = new " << type_name(ttype, false, true) << "();" << endl;
+  if (ttype->is_map()) {
+    out << indent() << "TMap " << obj << " = iprot.ReadMapBegin();" << endl;
+  } else if (ttype->is_set()) {
+    out << indent() << "TSet " << obj << " = iprot.ReadSetBegin();" << endl;
+  } else if (ttype->is_list()) {
+    out << indent() << "TList " << obj << " = iprot.ReadListBegin();" << endl;
+  }
+
+  string i = tmp("_i");
+  indent(out) << "for( int " << i << " = 0; " << i << " < " << obj << ".Count"
+              << "; "
+              << "++" << i << ")" << endl;
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "iprot.ReadMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "iprot.ReadSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "iprot.ReadListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+void t_csharp_generator::generate_deserialize_map_element(ostream& out,
+                                                          t_map* tmap,
+                                                          string prefix) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) << declare_field(&fkey) << endl;
+  indent(out) << declare_field(&fval) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) << prefix << "[" << key << "] = " << val << ";" << endl;
+}
+
+void t_csharp_generator::generate_deserialize_set_element(ostream& out,
+                                                          t_set* tset,
+                                                          string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_csharp_generator::generate_deserialize_list_element(ostream& out,
+                                                           t_list* tlist,
+                                                           string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_csharp_generator::generate_serialize_field(ostream& out,
+                                                  t_field* tfield,
+                                                  string prefix,
+                                                  bool is_element,
+                                                  bool is_propertyless) {
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  string name = prefix + (is_propertyless ? "" : prop_name(tfield));
+
+  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);
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) << "oprot.";
+
+    string nullable_name = nullable_ && !is_element && !field_is_required(tfield) ? name + ".Value"
+                                                                                  : name;
+
+    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:
+        if (type->is_binary()) {
+          out << "WriteBinary(";
+        } else {
+          out << "WriteString(";
+        }
+        out << name << ");";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "WriteBool(" << nullable_name << ");";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "WriteByte(" << nullable_name << ");";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "WriteI16(" << nullable_name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "WriteI32(" << nullable_name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "WriteI64(" << nullable_name << ");";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "WriteDouble(" << nullable_name << ");";
+        break;
+      default:
+        throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "WriteI32((int)" << nullable_name << ");";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+void t_csharp_generator::generate_serialize_struct(ostream& out,
+                                                   t_struct* tstruct,
+                                                   string prefix) {
+  (void)tstruct;
+  out << indent() << prefix << ".Write(oprot);" << endl;
+}
+
+void t_csharp_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "oprot.WriteMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type())
+                << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix
+                << ".Count));" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.WriteSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type())
+                << ", " << prefix << ".Count));" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.WriteListBegin(new TList("
+                << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".Count));"
+                << endl;
+  }
+
+  string iter = tmp("_iter");
+  if (ttype->is_map()) {
+    indent(out) << "foreach (" << type_name(((t_map*)ttype)->get_key_type()) << " " << iter
+                << " in " << prefix << ".Keys)";
+  } else if (ttype->is_set()) {
+    indent(out) << "foreach (" << type_name(((t_set*)ttype)->get_elem_type()) << " " << iter
+                << " in " << prefix << ")";
+  } else if (ttype->is_list()) {
+    indent(out) << "foreach (" << type_name(((t_list*)ttype)->get_elem_type()) << " " << iter
+                << " in " << prefix << ")";
+  }
+
+  out << endl;
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
+  } else if (ttype->is_set()) {
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+  } else if (ttype->is_list()) {
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+  }
+
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "oprot.WriteMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.WriteSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.WriteListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+void t_csharp_generator::generate_serialize_map_element(ostream& out,
+                                                        t_map* tmap,
+                                                        string iter,
+                                                        string map) {
+  t_field kfield(tmap->get_key_type(), iter);
+  generate_serialize_field(out, &kfield, "", true);
+  t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
+  generate_serialize_field(out, &vfield, "", true);
+}
+
+void t_csharp_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "", true);
+}
+
+void t_csharp_generator::generate_serialize_list_element(ostream& out,
+                                                         t_list* tlist,
+                                                         string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "", true);
+}
+
+void t_csharp_generator::generate_property(ostream& out,
+                                           t_field* tfield,
+                                           bool isPublic,
+                                           bool generateIsset) {
+  generate_csharp_property(out, tfield, isPublic, generateIsset, "_");
+}
+void t_csharp_generator::generate_csharp_property(ostream& out,
+                                                  t_field* tfield,
+                                                  bool isPublic,
+                                                  bool generateIsset,
+                                                  std::string fieldPrefix) {
+  if ((serialize_ || wcf_) && isPublic) {
+    indent(out) << "[DataMember(Order = 0)]" << endl;
+  }
+  bool has_default = field_has_default(tfield);
+  bool is_required = field_is_required(tfield);
+  if ((nullable_ && !has_default) || (is_required)) {
+    indent(out) << (isPublic ? "public " : "private ")
+                << type_name(tfield->get_type(), false, false, true, is_required) << " "
+                << prop_name(tfield) << " { get; set; }" << endl;
+  } else {
+    indent(out) << (isPublic ? "public " : "private ")
+                << type_name(tfield->get_type(), false, false, true) << " " << prop_name(tfield)
+                << endl;
+    scope_up(out);
+    indent(out) << "get" << endl;
+    scope_up(out);
+    bool use_nullable = false;
+    if (nullable_) {
+      t_type* ttype = tfield->get_type();
+      while (ttype->is_typedef()) {
+        ttype = ((t_typedef*)ttype)->get_type();
+      }
+      if (ttype->is_base_type()) {
+        use_nullable = ((t_base_type*)ttype)->get_base() != t_base_type::TYPE_STRING;
+      } else if (ttype->is_enum()) {
+        use_nullable = true;
+      }
+    }
+    indent(out) << "return " << fieldPrefix + tfield->get_name() << ";" << endl;
+    scope_down(out);
+    indent(out) << "set" << endl;
+    scope_up(out);
+    if (use_nullable) {
+      if (generateIsset) {
+        indent(out) << "__isset." << normalize_name(tfield->get_name()) << " = value.HasValue;"
+                    << endl;
+      }
+      indent(out) << "if (value.HasValue) this." << fieldPrefix + tfield->get_name()
+                  << " = value.Value;" << endl;
+    } else {
+      if (generateIsset) {
+        indent(out) << "__isset." << normalize_name(tfield->get_name()) << " = true;" << endl;
+      }
+      indent(out) << "this." << fieldPrefix + tfield->get_name() << " = value;" << endl;
+    }
+    scope_down(out);
+    scope_down(out);
+  }
+  out << endl;
+}
+
+std::string t_csharp_generator::make_valid_csharp_identifier(std::string const& fromName) {
+  std::string str = fromName;
+  if (str.empty()) {
+    return str;
+  }
+
+  // tests rely on this
+  assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
+
+  // if the first letter is a number, we add an additional underscore in front of it
+  char c = str.at(0);
+  if (('0' <= c) && (c <= '9')) {
+    str = "_" + str;
+  }
+
+  // following chars: letter, number or underscore
+  for (size_t i = 0; i < str.size(); ++i) {
+    c = str.at(i);
+    if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9'))
+        && ('_' != c)) {
+      str.replace(i, 1, "_");
+    }
+  }
+
+  return str;
+}
+
+void t_csharp_generator::cleanup_member_name_mapping(void* scope) {
+  if( member_mapping_scopes.empty()) {
+    throw "internal error: cleanup_member_name_mapping() no scope active";
+  }
+
+  member_mapping_scope& active = member_mapping_scopes.back();
+  if (active.scope_member != scope) {
+    throw "internal error: cleanup_member_name_mapping() called for wrong struct";
+  }
+
+  member_mapping_scopes.pop_back();
+}
+
+string t_csharp_generator::get_mapped_member_name(string name) {
+  if( ! member_mapping_scopes.empty()) {
+    member_mapping_scope& active = member_mapping_scopes.back();
+    map<string, string>::iterator iter = active.mapping_table.find(name);
+    if (active.mapping_table.end() != iter) {
+      return iter->second;
+    }
+  }
+
+  pverbose("no mapping for member %s\n", name.c_str());
+  return name;
+}
+
+void t_csharp_generator::prepare_member_name_mapping(t_struct* tstruct) {
+  prepare_member_name_mapping(tstruct, tstruct->get_members(), tstruct->get_name());
+}
+
+void t_csharp_generator::prepare_member_name_mapping(void* scope,
+                                                     const vector<t_field*>& members,
+                                                     const string& structname) {
+  // begin new scope
+  member_mapping_scope dummy;
+  dummy.scope_member = 0;
+  member_mapping_scopes.push_back(dummy);
+  member_mapping_scope& active = member_mapping_scopes.back();
+  active.scope_member = scope;
+
+  // current C# generator policy:
+  // - prop names are always rendered with an Uppercase first letter
+  // - struct names are used as given
+  std::set<std::string> used_member_names;
+  vector<t_field*>::const_iterator iter;
+
+  // prevent name conflicts with struct (CS0542 error)
+  used_member_names.insert(structname);
+
+  // prevent name conflicts with known methods (THRIFT-2942)
+  used_member_names.insert("Read");
+  used_member_names.insert("Write");
+
+  for (iter = members.begin(); iter != members.end(); ++iter) {
+    string oldname = (*iter)->get_name();
+    string newname = prop_name(*iter, true);
+    while (true) {
+
+      // new name conflicts with another member
+      if (used_member_names.find(newname) != used_member_names.end()) {
+        pverbose("struct %s: member %s conflicts with another member\n",
+                 structname.c_str(),
+                 newname.c_str());
+        newname += '_';
+        continue;
+      }
+
+      // add always, this helps us to detect edge cases like
+      // different spellings ("foo" and "Foo") within the same struct
+      pverbose("struct %s: member mapping %s => %s\n",
+               structname.c_str(),
+               oldname.c_str(),
+               newname.c_str());
+      active.mapping_table[oldname] = newname;
+      used_member_names.insert(newname);
+      break;
+    }
+  }
+}
+
+std::string t_csharp_generator::prop_name(t_field* tfield, bool suppress_mapping) {
+  string name(tfield->get_name());
+  if (suppress_mapping) {
+    name[0] = toupper(name[0]);
+  } else {
+    name = get_mapped_member_name(name);
+  }
+  return name;
+}
+
+string t_csharp_generator::type_name(t_type* ttype,
+                                     bool in_container,
+                                     bool in_init,
+                                     bool in_param,
+                                     bool is_required) {
+  (void)in_init;
+  while (ttype->is_typedef()) {
+    ttype = ((t_typedef*)ttype)->get_type();
+  }
+
+  if (ttype->is_base_type()) {
+    return base_type_name((t_base_type*)ttype, in_container, in_param, is_required);
+  } else if (ttype->is_map()) {
+    t_map* tmap = (t_map*)ttype;
+    return "Dictionary<" + type_name(tmap->get_key_type(), true) + ", "
+           + type_name(tmap->get_val_type(), true) + ">";
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*)ttype;
+    return "THashSet<" + type_name(tset->get_elem_type(), true) + ">";
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*)ttype;
+    return "List<" + type_name(tlist->get_elem_type(), true) + ">";
+  }
+
+  t_program* program = ttype->get_program();
+  string postfix = (!is_required && nullable_ && in_param && ttype->is_enum()) ? "?" : "";
+  if (program != NULL && program != program_) {
+    string ns = program->get_namespace("csharp");
+    if (!ns.empty()) {
+      return ns + "." + normalize_name(ttype->get_name()) + postfix;
+    }
+  }
+
+  return normalize_name(ttype->get_name()) + postfix;
+}
+
+string t_csharp_generator::base_type_name(t_base_type* tbase,
+                                          bool in_container,
+                                          bool in_param,
+                                          bool is_required) {
+  (void)in_container;
+  string postfix = (!is_required && nullable_ && in_param) ? "?" : "";
+  switch (tbase->get_base()) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    if (tbase->is_binary()) {
+      return "byte[]";
+    } else {
+      return "string";
+    }
+  case t_base_type::TYPE_BOOL:
+    return "bool" + postfix;
+  case t_base_type::TYPE_I8:
+    return "sbyte" + postfix;
+  case t_base_type::TYPE_I16:
+    return "short" + postfix;
+  case t_base_type::TYPE_I32:
+    return "int" + postfix;
+  case t_base_type::TYPE_I64:
+    return "long" + postfix;
+  case t_base_type::TYPE_DOUBLE:
+    return "double" + postfix;
+  default:
+    throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase->get_base());
+  }
+}
+
+string t_csharp_generator::declare_field(t_field* tfield, bool init, std::string prefix) {
+  string result = type_name(tfield->get_type()) + " " + prefix + tfield->get_name();
+  if (init) {
+    t_type* ttype = tfield->get_type();
+    while (ttype->is_typedef()) {
+      ttype = ((t_typedef*)ttype)->get_type();
+    }
+    if (ttype->is_base_type() && field_has_default(tfield)) {
+      std::ofstream dummy;
+      result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
+    } else if (ttype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "NO T_VOID CONSTRUCT";
+      case t_base_type::TYPE_STRING:
+        result += " = null";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = false";
+        break;
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = (double)0";
+        break;
+      }
+    } else if (ttype->is_enum()) {
+      result += " = (" + type_name(ttype, false, true) + ")0";
+    } else if (ttype->is_container()) {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    } else {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    }
+  }
+  return result + ";";
+}
+
+string t_csharp_generator::function_signature(t_function* tfunction, string prefix) {
+  t_type* ttype = tfunction->get_returntype();
+  return type_name(ttype) + " " + normalize_name(prefix + tfunction->get_name()) + "("
+         + argument_list(tfunction->get_arglist()) + ")";
+}
+
+string t_csharp_generator::function_signature_async_begin(t_function* tfunction, string prefix) {
+  string comma = (tfunction->get_arglist()->get_members().size() > 0 ? ", " : "");
+  return "IAsyncResult " + normalize_name(prefix + tfunction->get_name())
+         + "(AsyncCallback callback, object state" + comma + argument_list(tfunction->get_arglist())
+         + ")";
+}
+
+string t_csharp_generator::function_signature_async_end(t_function* tfunction, string prefix) {
+  t_type* ttype = tfunction->get_returntype();
+  return type_name(ttype) + " " + normalize_name(prefix + tfunction->get_name())
+         + "(IAsyncResult asyncResult)";
+}
+
+string t_csharp_generator::function_signature_async(t_function* tfunction, string prefix) {
+  t_type* ttype = tfunction->get_returntype();
+  string task = "Task";
+  if (!ttype->is_void())
+    task += "<" + type_name(ttype) + ">";
+  return task + " " + normalize_name(prefix + tfunction->get_name()) + "Async("
+         + argument_list(tfunction->get_arglist()) + ")";
+}
+
+string t_csharp_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 += type_name((*f_iter)->get_type()) + " " + normalize_name((*f_iter)->get_name());
+  }
+  return result;
+}
+
+string t_csharp_generator::type_to_enum(t_type* type) {
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_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 "TType.String";
+    case t_base_type::TYPE_BOOL:
+      return "TType.Bool";
+    case t_base_type::TYPE_I8:
+      return "TType.Byte";
+    case t_base_type::TYPE_I16:
+      return "TType.I16";
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "TType.Double";
+    }
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.Struct";
+  } else if (type->is_map()) {
+    return "TType.Map";
+  } else if (type->is_set()) {
+    return "TType.Set";
+  } else if (type->is_list()) {
+    return "TType.List";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+void t_csharp_generator::generate_csharp_docstring_comment(ostream& out, string contents) {
+  generate_docstring_comment(out, "/// <summary>\n", "/// ", contents, "/// </summary>\n");
+}
+
+void t_csharp_generator::generate_csharp_doc(ostream& out, t_field* field) {
+  if (field->get_type()->is_enum()) {
+    string combined_message = field->get_doc() + "\n<seealso cref=\""
+                              + get_enum_class_name(field->get_type()) + "\"/>";
+    generate_csharp_docstring_comment(out, combined_message);
+  } else {
+    generate_csharp_doc(out, (t_doc*)field);
+  }
+}
+
+void t_csharp_generator::generate_csharp_doc(ostream& out, t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    generate_csharp_docstring_comment(out, tdoc->get_doc());
+  }
+}
+
+void t_csharp_generator::generate_csharp_doc(ostream& out, t_function* tfunction) {
+  if (tfunction->has_doc()) {
+    stringstream ps;
+    const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+    vector<t_field*>::const_iterator p_iter;
+    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
+      t_field* p = *p_iter;
+      ps << "\n<param name=\"" << p->get_name() << "\">";
+      if (p->has_doc()) {
+        std::string str = p->get_doc();
+        str.erase(std::remove(str.begin(), str.end(), '\n'),
+                  str.end()); // remove the newlines that appear from the parser
+        ps << str;
+      }
+      ps << "</param>";
+    }
+    generate_docstring_comment(out,
+                               "",
+                               "/// ",
+                               "<summary>\n" + tfunction->get_doc() + "</summary>" + ps.str(),
+                               "");
+  }
+}
+
+std::string t_csharp_generator::get_enum_class_name(t_type* type) {
+  string package = "";
+  t_program* program = type->get_program();
+  if (program != NULL && program != program_) {
+    package = program->get_namespace("csharp") + ".";
+  }
+  return package + type->get_name();
+}
+
+
+THRIFT_REGISTER_GENERATOR(
+    csharp,
+    "C#",
+    "    async:           Adds Async support using Task.Run.\n"
+    "    wcf:             Adds bindings for WCF to generated classes.\n"
+    "    serial:          Add serialization support to generated classes.\n"
+    "    nullable:        Use nullable types for properties.\n"
+    "    hashcode:        Generate a hashcode and equals implementation for classes.\n"
+    "    union:           Use new union typing, which includes a static read function for union "
+    "types.\n")
diff --git a/compiler/cpp/src/thrift/generate/t_d_generator.cc b/compiler/cpp/src/thrift/generate/t_d_generator.cc
new file mode 100644
index 0000000..df56cfc
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_d_generator.cc
@@ -0,0 +1,742 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+#include <cassert>
+
+#include <fstream>
+#include <iostream>
+#include <set>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <sys/stat.h>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ofstream;
+using std::ostream;
+using std::ostringstream;
+using std::set;
+using std::string;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * D code generator.
+ *
+ * generate_*() functions are called by the base class to emit code for the
+ * given entity, print_*() functions write a piece of code to the passed
+ * stream, and render_*() return a string containing the D representation of
+ * the passed entity.
+ */
+class t_d_generator : public t_oop_generator {
+public:
+  t_d_generator(t_program* program,
+                const std::map<string, string>& parsed_options,
+                const string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    /* no options yet */
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      throw "unknown option d:" + iter->first;
+    }
+
+    out_dir_base_ = "gen-d";
+  }
+
+protected:
+  virtual void init_generator() {
+    // Make output directory
+    MKDIR(get_out_dir().c_str());
+
+    string dir = program_->get_namespace("d");
+    string subdir = get_out_dir();
+    string::size_type loc;
+    while ((loc = dir.find(".")) != string::npos) {
+      subdir = subdir + "/" + dir.substr(0, loc);
+      MKDIR(subdir.c_str());
+      dir = dir.substr(loc + 1);
+    }
+    if (!dir.empty()) {
+      subdir = subdir + "/" + dir;
+      MKDIR(subdir.c_str());
+    }
+
+    package_dir_ = subdir + "/";
+
+    // Make output file
+    string f_types_name = package_dir_ + program_name_ + "_types.d";
+    f_types_.open(f_types_name.c_str());
+
+    // Print header
+    f_types_ << autogen_comment() << "module " << render_package(*program_) << program_name_
+             << "_types;" << endl << endl;
+
+    print_default_imports(f_types_);
+
+    // Include type modules from other imported programs.
+    const vector<t_program*>& includes = program_->get_includes();
+    for (size_t i = 0; i < includes.size(); ++i) {
+      f_types_ << "public import " << render_package(*(includes[i])) << includes[i]->get_name()
+               << "_types;" << endl;
+    }
+    if (!includes.empty())
+      f_types_ << endl;
+  }
+
+  virtual void close_generator() {
+    // Close output file
+    f_types_.close();
+  }
+
+  virtual void generate_consts(std::vector<t_const*> consts) {
+    if (!consts.empty()) {
+      string f_consts_name = package_dir_ + program_name_ + "_constants.d";
+      ofstream_with_content_based_conditional_update f_consts;
+      f_consts.open(f_consts_name.c_str());
+
+      f_consts << autogen_comment() << "module " << render_package(*program_) << program_name_
+               << "_constants;" << endl << endl;
+
+      print_default_imports(f_consts);
+
+      f_consts << "import " << render_package(*get_program()) << program_name_ << "_types;" << endl
+               << endl;
+
+      vector<t_const*>::iterator c_iter;
+      for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+        this->emit_doc(*c_iter, f_consts);
+        string name = (*c_iter)->get_name();
+        t_type* type = (*c_iter)->get_type();
+        indent(f_consts) << "immutable(" << render_type_name(type) << ") " << name << ";" << endl;
+      }
+
+      f_consts << endl << "static this() {" << endl;
+      indent_up();
+
+      bool first = true;
+      for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+        if (first) {
+          first = false;
+        } else {
+          f_consts << endl;
+        }
+        t_type* type = (*c_iter)->get_type();
+        indent(f_consts) << (*c_iter)->get_name() << " = ";
+        if (!is_immutable_type(type)) {
+          f_consts << "cast(immutable(" << render_type_name(type) << ")) ";
+        }
+        f_consts << render_const_value(type, (*c_iter)->get_value()) << ";" << endl;
+      }
+      indent_down();
+      indent(f_consts) << "}" << endl;
+    }
+  }
+
+  virtual void generate_typedef(t_typedef* ttypedef) {
+    this->emit_doc(ttypedef, f_types_);
+    f_types_ << indent() << "alias " << render_type_name(ttypedef->get_type()) << " "
+             << ttypedef->get_symbolic() << ";" << endl << endl;
+  }
+
+  virtual void generate_enum(t_enum* tenum) {
+    vector<t_enum_value*> constants = tenum->get_constants();
+
+    this->emit_doc(tenum, f_types_);
+    string enum_name = tenum->get_name();
+    f_types_ << indent() << "enum " << enum_name << " {" << endl;
+
+    indent_up();
+
+    vector<t_enum_value*>::const_iterator c_iter;
+    for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+      this->emit_doc(*c_iter, f_types_);
+      indent(f_types_) << (*c_iter)->get_name();
+      f_types_ << " = " << (*c_iter)->get_value() << ",";
+    }
+
+    f_types_ << endl;
+    indent_down();
+    indent(f_types_) << "}" << endl;
+
+    f_types_ << endl;
+  }
+
+  virtual void generate_struct(t_struct* tstruct) {
+    print_struct_definition(f_types_, tstruct, false);
+  }
+
+  virtual void generate_xception(t_struct* txception) {
+    print_struct_definition(f_types_, txception, true);
+  }
+
+  virtual void generate_service(t_service* tservice) {
+    string svc_name = tservice->get_name();
+
+    // Service implementation file includes
+    string f_servicename = package_dir_ + svc_name + ".d";
+    ofstream_with_content_based_conditional_update f_service;
+    f_service.open(f_servicename.c_str());
+    f_service << autogen_comment() << "module " << render_package(*program_) << svc_name << ";"
+              << endl << endl;
+
+    print_default_imports(f_service);
+
+    f_service << "import " << render_package(*get_program()) << program_name_ << "_types;" << endl;
+
+    t_service* extends_service = tservice->get_extends();
+    if (extends_service != NULL) {
+      f_service << "import " << render_package(*(extends_service->get_program()))
+                << extends_service->get_name() << ";" << endl;
+    }
+
+    f_service << endl;
+
+    string extends = "";
+    if (tservice->get_extends() != NULL) {
+      extends = " : " + render_type_name(tservice->get_extends());
+    }
+
+    this->emit_doc(tservice, f_service);
+    f_service << indent() << "interface " << svc_name << extends << " {" << endl;
+    indent_up();
+
+    // Collect all the exception types service methods can throw so we can
+    // emit the necessary aliases later.
+    set<t_type*> exception_types;
+
+    // Print the method signatures.
+    vector<t_function*> functions = tservice->get_functions();
+    vector<t_function*>::iterator fn_iter;
+    for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) {
+      this->emit_doc(*fn_iter, f_service);
+      f_service << indent();
+      print_function_signature(f_service, *fn_iter);
+      f_service << ";" << endl;
+
+      const vector<t_field*>& exceptions = (*fn_iter)->get_xceptions()->get_members();
+      vector<t_field*>::const_iterator ex_iter;
+      for (ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter) {
+        exception_types.insert((*ex_iter)->get_type());
+      }
+    }
+
+    // Alias the exception types into the current scope.
+    if (!exception_types.empty())
+      f_service << endl;
+    set<t_type*>::const_iterator et_iter;
+    for (et_iter = exception_types.begin(); et_iter != exception_types.end(); ++et_iter) {
+      indent(f_service) << "alias " << render_package(*(*et_iter)->get_program())
+                        << (*et_iter)->get_program()->get_name() << "_types"
+                        << "." << (*et_iter)->get_name() << " " << (*et_iter)->get_name() << ";"
+                        << endl;
+    }
+
+    // Write the method metadata.
+    ostringstream meta;
+    indent_up();
+    bool first = true;
+    for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) {
+      if ((*fn_iter)->get_arglist()->get_members().empty()
+          && (*fn_iter)->get_xceptions()->get_members().empty() && !(*fn_iter)->is_oneway()) {
+        continue;
+      }
+
+      if (first) {
+        first = false;
+      } else {
+        meta << ",";
+      }
+
+      meta << endl << indent() << "TMethodMeta(`" << (*fn_iter)->get_name() << "`, " << endl;
+      indent_up();
+      indent(meta) << "[";
+
+      bool first = true;
+      const vector<t_field*>& params = (*fn_iter)->get_arglist()->get_members();
+      vector<t_field*>::const_iterator p_iter;
+      for (p_iter = params.begin(); p_iter != params.end(); ++p_iter) {
+        if (first) {
+          first = false;
+        } else {
+          meta << ", ";
+        }
+
+        meta << "TParamMeta(`" << (*p_iter)->get_name() << "`, " << (*p_iter)->get_key();
+
+        t_const_value* cv = (*p_iter)->get_value();
+        if (cv != NULL) {
+          meta << ", q{" << render_const_value((*p_iter)->get_type(), cv) << "}";
+        }
+        meta << ")";
+      }
+
+      meta << "]";
+
+      if (!(*fn_iter)->get_xceptions()->get_members().empty() || (*fn_iter)->is_oneway()) {
+        meta << "," << endl << indent() << "[";
+
+        bool first = true;
+        const vector<t_field*>& exceptions = (*fn_iter)->get_xceptions()->get_members();
+        vector<t_field*>::const_iterator ex_iter;
+        for (ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter) {
+          if (first) {
+            first = false;
+          } else {
+            meta << ", ";
+          }
+
+          meta << "TExceptionMeta(`" << (*ex_iter)->get_name() << "`, " << (*ex_iter)->get_key()
+               << ", `" << (*ex_iter)->get_type()->get_name() << "`)";
+        }
+
+        meta << "]";
+      }
+
+      if ((*fn_iter)->is_oneway()) {
+        meta << "," << endl << indent() << "TMethodType.ONEWAY";
+      }
+
+      indent_down();
+      meta << endl << indent() << ")";
+    }
+    indent_down();
+
+    string meta_str(meta.str());
+    if (!meta_str.empty()) {
+      f_service << endl << indent() << "enum methodMeta = [" << meta_str << endl << indent() << "];"
+                << endl;
+    }
+
+    indent_down();
+    indent(f_service) << "}" << endl;
+
+    // Server skeleton generation.
+    string f_skeletonname = package_dir_ + svc_name + "_server.skeleton.d";
+    ofstream_with_content_based_conditional_update f_skeleton;
+    f_skeleton.open(f_skeletonname.c_str());
+    print_server_skeleton(f_skeleton, tservice);
+    f_skeleton.close();
+  }
+
+  void emit_doc(t_doc *doc, std::ostream& out) {
+    if (!doc->has_doc()) {
+      return;
+    }
+    indent(out) << "/**" << std::endl;
+    indent_up();
+    // No endl -- comments reliably have a newline at the end.
+    // This is true even for stuff like:
+    //     /** method infos */ void foo(/** huh?*/ 1: i64 stuff)
+    indent(out) << doc->get_doc();
+    indent_down();
+    indent(out) << "*/" << std::endl;
+  }
+
+private:
+  /**
+   * Writes a server skeleton for the passed service to out.
+   */
+  void print_server_skeleton(ostream& out, t_service* tservice) {
+    string svc_name = tservice->get_name();
+
+    out << "/*" << endl
+        << " * This auto-generated skeleton file illustrates how to build a server. If you" << endl
+        << " * intend to customize it, you should edit a copy with another file name to " << endl
+        << " * avoid overwriting it when running the generator again." << endl << " */" << endl
+        << "module " << render_package(*tservice->get_program()) << svc_name << "_server;" << endl
+        << endl << "import std.stdio;" << endl << "import thrift.codegen.processor;" << endl
+        << "import thrift.protocol.binary;" << endl << "import thrift.server.simple;" << endl
+        << "import thrift.server.transport.socket;" << endl << "import thrift.transport.buffered;"
+        << endl << "import thrift.util.hashset;" << endl << endl << "import "
+        << render_package(*tservice->get_program()) << svc_name << ";" << endl << "import "
+        << render_package(*get_program()) << program_name_ << "_types;" << endl << endl << endl
+        << "class " << svc_name << "Handler : " << svc_name << " {" << endl;
+
+    indent_up();
+    out << indent() << "this() {" << endl << indent() << "  // Your initialization goes here."
+        << endl << indent() << "}" << endl << endl;
+
+    vector<t_function*> functions = tservice->get_functions();
+    vector<t_function*>::iterator f_iter;
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      out << indent();
+      print_function_signature(out, *f_iter);
+      out << " {" << endl;
+
+      indent_up();
+
+      out << indent() << "// Your implementation goes here." << endl << indent() << "writeln(\""
+          << (*f_iter)->get_name() << " called\");" << endl;
+
+	  t_type* rt = (*f_iter)->get_returntype();
+	  if (!rt->is_void()) {
+        indent(out) << "return typeof(return).init;" << endl;
+      }
+
+      indent_down();
+
+      out << indent() << "}" << endl << endl;
+    }
+
+    indent_down();
+    out << "}" << endl << endl;
+
+    out << indent() << "void main() {" << endl;
+    indent_up();
+    out << indent() << "auto protocolFactory = new TBinaryProtocolFactory!();" << endl << indent()
+        << "auto processor = new TServiceProcessor!" << svc_name << "(new " << svc_name
+        << "Handler);" << endl << indent() << "auto serverTransport = new TServerSocket(9090);"
+        << endl << indent() << "auto transportFactory = new TBufferedTransportFactory;" << endl
+        << indent() << "auto server = new TSimpleServer(" << endl << indent()
+        << "  processor, serverTransport, transportFactory, protocolFactory);" << endl << indent()
+        << "server.serve();" << endl;
+    indent_down();
+    out << "}" << endl;
+  }
+
+  /**
+   * Writes the definition of a struct or an exception type to out.
+   */
+  void print_struct_definition(ostream& out, t_struct* tstruct, bool is_exception) {
+    const vector<t_field*>& members = tstruct->get_members();
+
+    if (is_exception) {
+      indent(out) << "class " << tstruct->get_name() << " : TException {" << endl;
+    } else {
+      indent(out) << "struct " << tstruct->get_name() << " {" << endl;
+    }
+    indent_up();
+
+    // Declare all fields.
+    vector<t_field*>::const_iterator m_iter;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      indent(out) << render_type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name() << ";"
+                  << endl;
+    }
+
+    if (!members.empty())
+      indent(out) << endl;
+    indent(out) << "mixin TStructHelpers!(";
+
+    if (!members.empty()) {
+      // If there are any fields, construct the TFieldMeta array to pass to
+      // TStructHelpers. We can't just pass an empty array if not because []
+      // doesn't pass the TFieldMeta[] constraint.
+      out << "[";
+      indent_up();
+
+      bool first = true;
+      vector<t_field*>::const_iterator m_iter;
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        if (first) {
+          first = false;
+        } else {
+          out << ",";
+        }
+        out << endl;
+
+        indent(out) << "TFieldMeta(`" << (*m_iter)->get_name() << "`, " << (*m_iter)->get_key();
+
+        t_const_value* cv = (*m_iter)->get_value();
+        t_field::e_req req = (*m_iter)->get_req();
+        out << ", " << render_req(req);
+        if (cv != NULL) {
+          out << ", q{" << render_const_value((*m_iter)->get_type(), cv) << "}";
+        }
+        out << ")";
+      }
+
+      indent_down();
+      out << endl << indent() << "]";
+    }
+
+    out << ");" << endl;
+
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+
+  /**
+   * Prints the D function signature (including return type) for the given
+   * method.
+   */
+  void print_function_signature(ostream& out, t_function* fn) {
+    out << render_type_name(fn->get_returntype()) << " " << fn->get_name() << "(";
+
+    const vector<t_field*>& fields = fn->get_arglist()->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 {
+        out << ", ";
+      }
+      out << render_type_name((*f_iter)->get_type(), true) << " " << (*f_iter)->get_name();
+    }
+
+    out << ")";
+  }
+
+  /**
+   * Returns the D representation of value. The result is guaranteed to be a
+   * single expression; for complex types, immediately called delegate
+   * literals are used to achieve this.
+   */
+  string render_const_value(t_type* type, t_const_value* value) {
+    // Resolve any typedefs.
+    type = get_true_type(type);
+
+    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_I8:
+      case t_base_type::TYPE_I16:
+        out << "cast(" << render_type_name(type) << ")" << value->get_integer();
+        break;
+      case t_base_type::TYPE_I32:
+        out << value->get_integer();
+        break;
+      case t_base_type::TYPE_I64:
+        out << value->get_integer() << "L";
+        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()) {
+      out << "cast(" << render_type_name(type) << ")" << value->get_integer();
+    } else {
+      out << "{" << endl;
+      indent_up();
+
+      indent(out) << render_type_name(type) << " v;" << endl;
+      if (type->is_struct() || type->is_xception()) {
+        indent(out) << "v = " << (type->is_xception() ? "new " : "") << render_type_name(type)
+                    << "();" << endl;
+
+        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*, t_const_value::value_compare>& val = value->get_map();
+        map<t_const_value*, t_const_value*, t_const_value::value_compare>::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();
+          }
+          string val = render_const_value(field_type, v_iter->second);
+          indent(out) << "v.set!`" << v_iter->first->get_string() << "`(" << val << ");" << endl;
+        }
+      } 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*, t_const_value::value_compare>& val = value->get_map();
+        map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+          string key = render_const_value(ktype, v_iter->first);
+          string val = render_const_value(vtype, v_iter->second);
+          indent(out) << "v[";
+          if (!is_immutable_type(ktype)) {
+            out << "cast(immutable(" << render_type_name(ktype) << "))";
+          }
+          out << key << "] = " << val << ";" << endl;
+        }
+      } else if (type->is_list()) {
+        t_type* etype = ((t_list*)type)->get_elem_type();
+        const vector<t_const_value*>& val = value->get_list();
+        vector<t_const_value*>::const_iterator v_iter;
+        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+          string val = render_const_value(etype, *v_iter);
+          indent(out) << "v ~= " << val << ";" << endl;
+        }
+      } else if (type->is_set()) {
+        t_type* etype = ((t_set*)type)->get_elem_type();
+        const vector<t_const_value*>& val = value->get_list();
+        vector<t_const_value*>::const_iterator v_iter;
+        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+          string val = render_const_value(etype, *v_iter);
+          indent(out) << "v ~= " << val << ";" << endl;
+        }
+      } else {
+        throw "Compiler error: Invalid type in render_const_value: " + type->get_name();
+      }
+      indent(out) << "return v;" << endl;
+
+      indent_down();
+      indent(out) << "}()";
+    }
+
+    return out.str();
+  }
+
+  /**
+   * Returns the D package to which modules for program are written (with a
+   * trailing dot, if not empty).
+   */
+  string render_package(const t_program& program) const {
+    string package = program.get_namespace("d");
+    if (package.size() == 0)
+      return "";
+    return package + ".";
+  }
+
+  /**
+   * Returns the name of the D repesentation of ttype.
+   *
+   * If isArg is true, a const reference to the type will be returned for
+   * structs.
+   */
+  string render_type_name(const t_type* ttype, bool isArg = false) const {
+    if (ttype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        return "void";
+      case t_base_type::TYPE_STRING:
+        return "string";
+      case t_base_type::TYPE_BOOL:
+        return "bool";
+      case t_base_type::TYPE_I8:
+        return "byte";
+      case t_base_type::TYPE_I16:
+        return "short";
+      case t_base_type::TYPE_I32:
+        return "int";
+      case t_base_type::TYPE_I64:
+        return "long";
+      case t_base_type::TYPE_DOUBLE:
+        return "double";
+      default:
+        throw "Compiler error: No D type name for base type " + t_base_type::t_base_name(tbase);
+      }
+    }
+
+    if (ttype->is_container()) {
+      t_container* tcontainer = (t_container*)ttype;
+      if (tcontainer->has_cpp_name()) {
+        return tcontainer->get_cpp_name();
+      } else if (ttype->is_map()) {
+        t_map* tmap = (t_map*)ttype;
+        t_type* ktype = tmap->get_key_type();
+
+        string name = render_type_name(tmap->get_val_type()) + "[";
+        if (!is_immutable_type(ktype)) {
+          name += "immutable(";
+        }
+        name += render_type_name(ktype);
+        if (!is_immutable_type(ktype)) {
+          name += ")";
+        }
+        name += "]";
+        return name;
+      } else if (ttype->is_set()) {
+        t_set* tset = (t_set*)ttype;
+        return "HashSet!(" + render_type_name(tset->get_elem_type()) + ")";
+      } else if (ttype->is_list()) {
+        t_list* tlist = (t_list*)ttype;
+        return render_type_name(tlist->get_elem_type()) + "[]";
+      }
+    }
+
+    if (ttype->is_struct() && isArg) {
+      return "ref const(" + ttype->get_name() + ")";
+    } else {
+      return ttype->get_name();
+    }
+  }
+
+  /**
+   * Returns the D TReq enum member corresponding to req.
+   */
+  string render_req(t_field::e_req req) const {
+    switch (req) {
+    case t_field::T_OPT_IN_REQ_OUT:
+      return "TReq.OPT_IN_REQ_OUT";
+    case t_field::T_OPTIONAL:
+      return "TReq.OPTIONAL";
+    case t_field::T_REQUIRED:
+      return "TReq.REQUIRED";
+    default: {
+      std::stringstream ss;
+      ss << "Compiler error: Invalid requirement level " << req;
+      throw ss.str();
+    }
+    }
+  }
+
+  /**
+   * Writes the default list of imports (which are written to every generated
+   * module) to f.
+   */
+  void print_default_imports(ostream& out) {
+    indent(out) << "import thrift.base;" << endl << "import thrift.codegen.base;" << endl
+                << "import thrift.util.hashset;" << endl << endl;
+  }
+
+  /**
+   * Returns whether type is »intrinsically immutable«, in the sense that
+   * a value of that type is implicitly castable to immutable(type), and it is
+   * allowed for AA keys without an immutable() qualifier.
+   */
+  bool is_immutable_type(t_type* type) const {
+    t_type* ttype = get_true_type(type);
+    return ttype->is_base_type() || ttype->is_enum();
+  }
+
+  /*
+   * File streams, stored here to avoid passing them as parameters to every
+   * function.
+   */
+  ofstream_with_content_based_conditional_update f_types_;
+  ofstream_with_content_based_conditional_update f_header_;
+
+  string package_dir_;
+};
+
+THRIFT_REGISTER_GENERATOR(d, "D", "")
diff --git a/compiler/cpp/src/thrift/generate/t_dart_generator.cc b/compiler/cpp/src/thrift/generate/t_dart_generator.cc
new file mode 100644
index 0000000..414c333
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_dart_generator.cc
@@ -0,0 +1,2516 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <cctype>
+
+#include <sys/stat.h>
+#include <stdexcept>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+static const string endl2 = "\n\n";
+
+/**
+ * Use the current Thrift version for static libraries.  When releasing, update
+ * the version in these files.
+ * - lib/dart/pubspec.yaml
+ * - test/dart/test_client/pubspec.yaml
+ * - tutorial/dart/client/pubspec.yaml
+ * - tutorial/dart/console_client/pubspec.yaml
+ * - tutorial/dart/server/pubspec.yaml
+ * See https://thrift.apache.org/docs/committers/HowToVersion
+ */
+static const string dart_thrift_version = THRIFT_VERSION;
+
+/* forward declarations */
+string initial_caps_to_underscores(string name);
+
+/**
+ * Dart code generator
+ *
+ */
+class t_dart_generator : public t_oop_generator {
+public:
+  t_dart_generator(t_program* program,
+                  const std::map<std::string, std::string>& parsed_options,
+                  const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    library_name_ = "";
+    library_prefix_ = "";
+    package_prefix_ = "";
+    pubspec_lib_ = "";
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("library_name") == 0) {
+        library_name_ = (iter->second);
+      } else if( iter->first.compare("library_prefix") == 0) {
+        library_prefix_ = (iter->second) + ".";
+        package_prefix_ = replace_all(library_prefix_, ".", "/");
+      } else if( iter->first.compare("pubspec_lib") == 0) {
+        pubspec_lib_ = (iter->second);
+      } else {
+        throw "unknown option dart:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-dart";
+  }
+
+  void scope_up(std::ostream& out, std::string prefix=" ") {
+    out << prefix << "{" << endl;
+    indent_up();
+  }
+
+  void scope_down(std::ostream& out, std::string postfix=endl) {
+    indent_down();
+    indent(out) << "}" << postfix;
+  }
+
+  string replace_all(string contents, string search, string repl) {
+    string str(contents);
+
+    size_t slen = search.length();
+    size_t rlen = repl.length();
+    size_t incr = (rlen > 0) ? rlen : 1;
+
+    if (slen > 0) {
+      size_t found = str.find(search);
+      while ((found != string::npos) && (found < str.length())) {
+        str.replace(found, slen, repl);
+        found = str.find(search, found + incr);
+      }
+    }
+
+    return str;
+  }
+
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  void export_class_to_library(string file_name, string class_name);
+
+  void generate_dart_library();
+  void generate_dart_pubspec();
+
+  void generate_consts(std::vector<t_const*> consts);
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_struct(t_struct* tstruct);
+  void generate_xception(t_struct* txception);
+  void generate_service(t_service* tservice);
+
+  void print_const_value(std::ostream& out,
+                         std::string name,
+                         t_type* type,
+                         t_const_value* value,
+                         bool in_static,
+                         bool defval = false);
+  std::string render_const_value(ostream& out,
+                                 std::string name,
+                                 t_type* type,
+                                 t_const_value* value);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_dart_struct(t_struct* tstruct, bool is_exception);
+
+  void generate_dart_struct_definition(std::ostream& out,
+                                       t_struct* tstruct,
+                                       bool is_xception = false,
+                                       bool is_result = false,
+                                       string export_file_name = "");
+  void generate_dart_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_dart_validator(std::ostream& out, t_struct* tstruct);
+  void generate_dart_struct_result_writer(std::ostream& out, t_struct* tstruct);
+  void generate_dart_struct_writer(std::ostream& out, t_struct* tstruct);
+  void generate_dart_struct_tostring(std::ostream& out, t_struct* tstruct);
+  std::string get_dart_type_string(t_type* type);
+  void generate_generic_field_getters(std::ostream& out, t_struct* tstruct);
+  void generate_generic_field_setters(std::ostream& out, t_struct* tstruct);
+  void generate_generic_isset_method(std::ostream& out, t_struct* tstruct);
+  void generate_dart_bean_boilerplate(std::ostream& out, t_struct* tstruct);
+
+  void generate_function_helpers(t_function* tfunction);
+  std::string init_value(t_field* tfield);
+  std::string get_cap_name(std::string name);
+  std::string get_member_name(std::string name);
+  std::string get_args_class_name(std::string name);
+  std::string get_result_class_name(std::string name);
+  std::string get_file_name(std::string name);
+  std::string get_constants_class_name(std::string name);
+  std::string generate_isset_check(t_field* field);
+  std::string generate_isset_check(std::string field);
+  void generate_isset_set(ostream& out, t_field* field);
+
+  void generate_service_interface(t_service* tservice);
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_client(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::ostream& out, t_field* tfield, std::string prefix = "");
+
+  void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+
+  void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         std::string prefix = "");
+
+  void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
+
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string iter,
+                                      std::string map);
+
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  void generate_dart_doc(std::ostream& out, t_doc* tdoc);
+
+  void generate_dart_doc(std::ostream& out, t_function* tdoc);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string find_library_name(t_program* program);
+  std::string dart_library(string file_name);
+  std::string service_imports();
+  std::string dart_thrift_imports();
+  std::string type_name(t_type* ttype);
+  std::string base_type_name(t_base_type* tbase);
+  std::string declare_field(t_field* tfield, bool init = false);
+  std::string function_signature(t_function* tfunction);
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string get_ttype_class_name(t_type* ttype);
+
+  bool type_can_be_null(t_type* ttype) {
+    ttype = get_true_type(ttype);
+
+    return ttype->is_container() || ttype->is_struct() || ttype->is_xception()
+           || ttype->is_string();
+  }
+
+  vector<std::string> split(const string& s, char delim) {
+    vector<std::string> elems;
+    stringstream ss(s);
+    string item;
+    while (getline(ss, item, delim)) {
+      elems.push_back(item);
+    }
+    return elems;
+  }
+
+  std::string constant_name(std::string name);
+
+private:
+  ofstream_with_content_based_conditional_update f_service_;
+
+  std::string library_name_;
+  std::string library_prefix_;
+  std::string package_prefix_;
+  std::string pubspec_lib_;
+
+  std::string base_dir_;
+  std::string src_dir_;
+  std::string library_exports_;
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_dart_generator::init_generator() {
+  MKDIR(get_out_dir().c_str());
+
+  if (library_name_.empty()) {
+    library_name_ = find_library_name(program_);
+  }
+
+  string subdir = get_out_dir() + "/" + library_name_;
+  MKDIR(subdir.c_str());
+  base_dir_ = subdir;
+
+  if (library_prefix_.empty()) {
+    subdir += "/lib";
+    MKDIR(subdir.c_str());
+    subdir += "/src";
+    MKDIR(subdir.c_str());
+    src_dir_ = subdir;
+  } else {
+    src_dir_ = base_dir_;
+  }
+}
+
+string t_dart_generator::find_library_name(t_program* program) {
+  string name = program->get_namespace("dart");
+  if (name.empty()) {
+    name = program->get_name();
+  }
+  name = replace_all(name, ".", "_");
+  name = replace_all(name, "-", "_");
+  return name;
+}
+
+/**
+ * The Dart library
+ *
+ * @return String of the library, e.g. "library myservice;"
+ */
+string t_dart_generator::dart_library(string file_name) {
+  string out = "library " + library_prefix_ + library_name_;
+  if (!file_name.empty()) {
+    if (library_prefix_.empty()) {
+      out += ".src." + file_name;
+    } else {
+      out += "." + file_name;
+    }
+  }
+  return out + ";\n";
+}
+
+/**
+ * Prints imports for services
+ *
+ * @return List of imports for services
+ */
+string t_dart_generator::service_imports() {
+  return "import 'dart:async';" + endl;
+}
+
+/**
+ * Prints standard dart imports
+ *
+ * @return List of imports necessary for thrift
+ */
+string t_dart_generator::dart_thrift_imports() {
+  string imports = "import 'dart:typed_data' show Uint8List;" + endl +
+                   "import 'package:thrift/thrift.dart';" + endl;
+
+  // add import for this library
+  if (package_prefix_.empty()) {
+    imports += "import 'package:" + library_name_ + "/" + library_name_ + ".dart';" + endl;
+  } else {
+    imports += "import 'package:" + package_prefix_ + library_name_ + ".dart';" + endl;
+  }
+
+  // add imports for included thrift files
+  const vector<t_program*>& includes = program_->get_includes();
+  for (size_t i = 0; i < includes.size(); ++i) {
+    string include_name = find_library_name(includes[i]);
+    string named_import = "t_" + include_name;
+    if (package_prefix_.empty()) {
+      imports += "import 'package:" + include_name + "/" + include_name + ".dart' as " + named_import + ";" + endl;
+    } else {
+      imports += "import 'package:" + package_prefix_ + include_name + ".dart' as " + named_import + ";" + endl;
+    }
+  }
+
+  return imports;
+}
+
+/**
+ * Not used
+ */
+void t_dart_generator::close_generator() {
+  generate_dart_library();
+
+  if (library_prefix_.empty()) {
+    generate_dart_pubspec();
+  }
+}
+
+void t_dart_generator::generate_dart_library() {
+  string f_library_name;
+  if (library_prefix_.empty()) {
+    f_library_name = base_dir_ + "/lib/" + library_name_ + ".dart";
+  } else {
+    f_library_name = get_out_dir() + "/" + library_name_ + ".dart";
+  }
+
+  ofstream_with_content_based_conditional_update f_library;
+  f_library.open(f_library_name.c_str());
+
+  f_library << autogen_comment() << endl;
+  f_library << "library " << library_prefix_ << library_name_ << ";" << endl2;
+  f_library << library_exports_;
+
+  f_library.close();
+}
+
+void t_dart_generator::export_class_to_library(string file_name, string class_name) {
+  string subdir;
+  if (library_prefix_.empty()) {
+    subdir = "src";
+  } else {
+    subdir = library_name_;
+  }
+  library_exports_ += "export '" + subdir + "/" + file_name + ".dart' show " + class_name + ";" + endl;
+}
+
+void t_dart_generator::generate_dart_pubspec() {
+  string f_pubspec_name = base_dir_ + "/pubspec.yaml";
+  ofstream_with_content_based_conditional_update f_pubspec;
+  f_pubspec.open(f_pubspec_name.c_str());
+
+  indent(f_pubspec) << "name: " << library_name_ << endl;
+  indent(f_pubspec) << "version: 0.0.1" << endl;
+  indent(f_pubspec) << "description: Autogenerated by Thrift Compiler" << endl;
+  f_pubspec << endl;
+
+  indent(f_pubspec) << "environment:" << endl;
+  indent_up();
+  indent(f_pubspec) << "sdk: ^1.12.0" << endl;
+  indent_down();
+  f_pubspec << endl;
+
+  indent(f_pubspec) << "dependencies:" << endl;
+  indent_up();
+
+  if (pubspec_lib_.empty()) {
+    // default to relative path within working directory, which works for tests
+    indent(f_pubspec) << "thrift:  # ^" << dart_thrift_version << endl;
+    indent_up();
+    indent(f_pubspec) << "path: ../../../../lib/dart" << endl;
+    indent_down();
+  } else {
+    const vector<std::string> lines = split(pubspec_lib_, '|');
+    for (size_t line_index = 0; line_index < lines.size(); line_index++) {
+      indent(f_pubspec) << lines[line_index] << endl;
+    }
+  }
+
+  // add included thrift files as dependencies
+  const vector<t_program*>& includes = program_->get_includes();
+  for (size_t i = 0; i < includes.size(); ++i) {
+    string include_name = find_library_name(includes[i]);
+    indent(f_pubspec) << include_name << ":" << endl;
+    indent_up();
+    indent(f_pubspec) << "path: ../" << include_name << endl;
+    indent_down();
+  }
+
+  indent_down();
+  f_pubspec << endl;
+
+  f_pubspec.close();
+}
+
+/**
+ * Not used
+ *
+ * @param ttypedef The type definition
+ */
+void t_dart_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+/**
+ * Enums are a class with a set of static constants.
+ *
+ * @param tenum The enumeration
+ */
+void t_dart_generator::generate_enum(t_enum* tenum) {
+  // Make output file
+  string file_name = get_file_name(tenum->get_name());
+
+  string f_enum_name = src_dir_ + "/" + file_name + ".dart";
+  ofstream_with_content_based_conditional_update f_enum;
+  f_enum.open(f_enum_name.c_str());
+
+  // Comment and add library
+  f_enum << autogen_comment() << dart_library(file_name) << endl;
+
+  string class_name = tenum->get_name();
+  export_class_to_library(file_name, class_name);
+  f_enum << "class " << class_name;
+  scope_up(f_enum);
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    indent(f_enum) << "static const int " << (*c_iter)->get_name() << " = " << value << ";"
+                   << endl;
+  }
+
+  // Create a static Set with all valid values for this enum
+  f_enum << endl;
+
+  indent(f_enum) << "static final Set<int> VALID_VALUES = new Set.from([" << endl;
+  indent_up();
+  bool firstValue = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    // populate set
+    indent(f_enum) << (firstValue ? "" : ", ");
+    f_enum << (*c_iter)->get_name() << endl;
+    firstValue = false;
+  }
+  indent_down();
+  indent(f_enum) << "]);" << endl;
+
+  indent(f_enum) << "static final Map<int, String> VALUES_TO_NAMES = {" << endl;
+  indent_up();
+  firstValue = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    indent(f_enum) << (firstValue ? "" : ", ");
+    f_enum  << (*c_iter)->get_name() << ": '" << (*c_iter)->get_name() << "'" << endl;
+    firstValue = false;
+  }
+  indent_down();
+  indent(f_enum) << "};" << endl;
+
+  scope_down(f_enum); // end class
+
+  f_enum.close();
+}
+
+/**
+ * Generates a class that holds all the constants.
+ */
+void t_dart_generator::generate_consts(std::vector<t_const*> consts) {
+  if (consts.empty()) {
+    return;
+  }
+
+  string class_name = get_constants_class_name(program_name_);
+  string file_name = get_file_name(class_name);
+
+  string f_consts_name = src_dir_ + "/" + file_name + ".dart";
+  ofstream_with_content_based_conditional_update f_consts;
+  f_consts.open(f_consts_name.c_str());
+
+  // Print header
+  f_consts << autogen_comment() << dart_library(file_name) << endl;
+  f_consts << dart_thrift_imports() << endl;
+
+  export_class_to_library(file_name, class_name);
+  indent(f_consts) << "class " << class_name;
+  scope_up(f_consts);
+
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    print_const_value(f_consts,
+                      (*c_iter)->get_name(),
+                      (*c_iter)->get_type(),
+                      (*c_iter)->get_value(),
+                      false);
+    f_consts << endl;
+  }
+
+  scope_down(f_consts);
+
+  f_consts.close();
+}
+
+void t_dart_generator::print_const_value(std::ostream& out,
+                                        string name,
+                                        t_type* type,
+                                        t_const_value* value,
+                                        bool in_static,
+                                        bool defval) {
+  type = get_true_type(type);
+
+  indent(out);
+  if (!defval) {
+    out << (in_static ? "var " : "static final ");
+  }
+  if (type->is_base_type()) {
+    if (!defval) {
+      out << type_name(type) << " ";
+    }
+    string v2 = render_const_value(out, name, type, value);
+    out << name;
+    out << " = " << v2 << ";" << endl << endl;
+  } else if (type->is_enum()) {
+    if (!defval) {
+      out << type_name(type) << " ";
+    }
+    out << name;
+    out << " = " << value->get_integer() << ";" << endl << endl;
+  } else if (type->is_struct() || type->is_xception()) {
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    out << type_name(type) << " " << name << " = new " << type_name(type) << "()";
+    indent_up();
+    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();
+      }
+      string val = render_const_value(out, name, field_type, v_iter->second);
+      out << endl;
+      indent(out) << ".." << v_iter->first->get_string() << " = " << val;
+    }
+    indent_down();
+    out << ";" << endl;
+  } else if (type->is_map()) {
+    if (!defval) {
+      out << type_name(type) << " ";
+    }
+    out << name << " =";
+    scope_up(out);
+
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, name, ktype, v_iter->first);
+      string val = render_const_value(out, name, vtype, v_iter->second);
+      indent(out) << key << ": " << val << "," << endl;
+    }
+    scope_down(out, ";" + endl);
+
+    out << endl;
+  } else if (type->is_list() || type->is_set()) {
+    if (!defval) {
+      out << type_name(type) << " ";
+    }
+    out << name << " = ";
+    t_type* etype;
+    if (type->is_list()) {
+      out << "[" << endl;
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      out << "new " << type_name(type) << ".from([" << endl;
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+
+    indent_up();
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(out, name, etype, *v_iter);
+      indent(out) << val << "," << endl;
+    }
+    indent_down();
+
+    if (type->is_list()) {
+      indent(out) << "];" << endl;
+    } else {
+      indent(out) << "]);" << endl;
+    }
+
+  } else {
+    throw "compiler error: no const of type " + type->get_name();
+  }
+}
+
+string t_dart_generator::render_const_value(ostream& out,
+                                           string name,
+                                           t_type* type,
+                                           t_const_value* value) {
+  (void)name;
+  type = get_true_type(type);
+  std::ostringstream render;
+
+  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:
+      render << "'" << get_escaped_string(value) << "'";
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "true" : "false");
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << value->get_integer();
+      } else {
+        render << 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()) {
+    render << value->get_integer();
+  } else {
+    string t = tmp("tmp");
+    print_const_value(out, t, type, value, true);
+    out << endl;
+    render << t;
+  }
+
+  return render.str();
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This is a class
+ * with data members, read(), write(), and an inner Isset class.
+ *
+ * @param tstruct The struct definition
+ */
+void t_dart_generator::generate_struct(t_struct* tstruct) {
+  generate_dart_struct(tstruct, false);
+}
+
+/**
+ * Exceptions are structs, but they inherit from Exception
+ *
+ * @param tstruct The struct definition
+ */
+void t_dart_generator::generate_xception(t_struct* txception) {
+  generate_dart_struct(txception, true);
+}
+
+/**
+ * Dart struct definition.
+ *
+ * @param tstruct The struct definition
+ */
+void t_dart_generator::generate_dart_struct(t_struct* tstruct, bool is_exception) {
+  string file_name = get_file_name(tstruct->get_name());
+  string f_struct_name = src_dir_ + "/" + file_name + ".dart";
+  ofstream_with_content_based_conditional_update f_struct;
+  f_struct.open(f_struct_name.c_str());
+
+  f_struct << autogen_comment() << dart_library(file_name) << endl;
+
+  string imports;
+
+  f_struct << dart_thrift_imports() << endl;
+
+  generate_dart_struct_definition(f_struct, tstruct, is_exception, false, file_name);
+
+  f_struct.close();
+}
+
+/**
+ * Dart struct definition. This has various parameters, as it could be
+ * generated standalone or inside another class as a helper. If it
+ * is a helper than it is a static class.
+ *
+ * @param tstruct      The struct definition
+ * @param is_exception Is this an exception?
+ * @param in_class     If inside a class, needs to be static class
+ * @param is_result    If this is a result it needs a different writer
+ */
+void t_dart_generator::generate_dart_struct_definition(ostream& out,
+                                                       t_struct* tstruct,
+                                                       bool is_exception,
+                                                       bool is_result,
+                                                       string export_file_name) {
+  generate_dart_doc(out, tstruct);
+
+  string class_name = tstruct->get_name();
+  if (!export_file_name.empty()) {
+    export_class_to_library(export_file_name, class_name);
+  }
+  indent(out) << "class " << class_name << " ";
+
+  out << "implements TBase";
+  if (is_exception) {
+    out << ", Exception ";
+  }
+  scope_up(out);
+
+  indent(out) << "static final TStruct _STRUCT_DESC = new TStruct(\"" << class_name
+              << "\");" << endl;
+
+  // Members are public for -dart, private for -dartbean
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) << "static final TField _" << constant_name((*m_iter)->get_name())
+                << "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", "
+                << type_to_enum((*m_iter)->get_type()) << ", " << (*m_iter)->get_key() << ");"
+                << endl;
+  }
+
+  out << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    generate_dart_doc(out, *m_iter);
+    indent(out) << type_name((*m_iter)->get_type()) + " _"
+                << get_member_name((*m_iter)->get_name()) << init_value(*m_iter) << ";" << endl;
+
+    indent(out) << "static const int " << upcase_string((*m_iter)->get_name())
+                << " = " << (*m_iter)->get_key() << ";" << endl;
+  }
+
+  out << endl;
+
+  // Inner Isset class
+  if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (!type_can_be_null((*m_iter)->get_type())) {
+        string field_name = get_member_name((*m_iter)->get_name());
+        indent(out) << "bool __isset_" << field_name << " = false;" << endl;
+      }
+    }
+  }
+
+  out << endl;
+
+  // Default constructor
+  indent(out) << tstruct->get_name() << "()";
+  scope_up(out);
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    if ((*m_iter)->get_value() != NULL) {
+      print_const_value(out,
+                        "this." + get_member_name((*m_iter)->get_name()),
+                        t,
+                        (*m_iter)->get_value(),
+                        true,
+                        true);
+    }
+  }
+  scope_down(out);
+  out << endl;
+
+  generate_dart_bean_boilerplate(out, tstruct);
+  generate_generic_field_getters(out, tstruct);
+  generate_generic_field_setters(out, tstruct);
+  generate_generic_isset_method(out, tstruct);
+
+  generate_dart_struct_reader(out, tstruct);
+  if (is_result) {
+    generate_dart_struct_result_writer(out, tstruct);
+  } else {
+    generate_dart_struct_writer(out, tstruct);
+  }
+  generate_dart_struct_tostring(out, tstruct);
+  generate_dart_validator(out, tstruct);
+  scope_down(out);
+  out << endl;
+}
+
+/**
+ * Generates a function to read all the fields of the struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_dart_generator::generate_dart_struct_reader(ostream& out, t_struct* tstruct) {
+  indent(out) << "read(TProtocol iprot)";
+  scope_up(out);
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Declare stack tmp variables and read struct header
+  indent(out) << "TField field;" << endl;
+  indent(out) << "iprot.readStructBegin();" << endl;
+
+  // Loop over reading in fields
+  indent(out) << "while (true)";
+  scope_up(out);
+
+  // Read beginning field marker
+  indent(out) << "field = iprot.readFieldBegin();" << endl;
+
+  // Check for field STOP marker and break
+  indent(out) << "if (field.type == TType.STOP)";
+  scope_up(out);
+  indent(out) << "break;" << endl;
+  scope_down(out);
+
+  // Switch statement on the field we are reading
+  indent(out) << "switch (field.id)";
+  scope_up(out);
+
+  // Generate deserialization code for known cases
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) << "case " << upcase_string((*f_iter)->get_name()) << ":" << endl;
+    indent_up();
+
+    indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ")";
+    scope_up(out);
+
+    generate_deserialize_field(out, *f_iter, "this.");
+    generate_isset_set(out, *f_iter);
+
+    scope_down(out, " else");
+    scope_up(out);
+    indent(out) << "TProtocolUtil.skip(iprot, field.type);" << endl;
+    scope_down(out);
+
+    indent(out) << "break;" << endl;
+    indent_down();
+  }
+
+  // In the default case we skip the field
+  indent(out) << "default:" << endl;
+  indent_up();
+  indent(out) << "TProtocolUtil.skip(iprot, field.type);" << endl;
+  indent(out) << "break;" << endl;
+  indent_down();
+
+  scope_down(out);
+
+  // Read field end marker
+  indent(out) << "iprot.readFieldEnd();" << endl;
+
+  scope_down(out);
+
+  indent(out) << "iprot.readStructEnd();" << endl2;
+
+  // in non-beans style, check for required fields of primitive type
+  // (which can be checked here but not in the general validate method)
+  indent(out) << "// check for required fields of primitive type, which can't be "
+                 "checked in the validate method" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) {
+      string field_name = get_member_name((*f_iter)->get_name());
+      indent(out) << "if (!__isset_" << field_name << ")";
+      scope_up(out);
+      indent(out) << "  throw new TProtocolError(TProtocolErrorType.UNKNOWN, \"Required field '"
+          << field_name
+          << "' was not found in serialized data! Struct: \" + toString());" << endl;
+      scope_down(out, endl2);
+    }
+  }
+
+  // performs various checks (e.g. check that all required fields are set)
+  indent(out) << "validate();" << endl;
+
+  scope_down(out, endl2);
+}
+
+// generates dart method to perform various checks
+// (e.g. check that all required fields are set)
+void t_dart_generator::generate_dart_validator(ostream& out, t_struct* tstruct) {
+  indent(out) << "validate()";
+  scope_up(out);
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "// check for required fields" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      string field_name = get_member_name((*f_iter)->get_name());
+      if (type_can_be_null((*f_iter)->get_type())) {
+        indent(out) << "if (" << field_name << " == null)";
+        scope_up(out);
+        indent(out) << "throw new TProtocolError(TProtocolErrorType.UNKNOWN, \"Required field '"
+                    << field_name << "' was not present! Struct: \" + toString());"
+                    << endl;
+        scope_down(out);
+      } else {
+        indent(out) << "// alas, we cannot check '" << field_name
+                    << "' because it's a primitive and you chose the non-beans generator." << endl;
+      }
+    }
+  }
+
+  // check that fields of type enum have valid values
+  indent(out) << "// check that fields of type enum have valid values" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = (*f_iter);
+    t_type* type = field->get_type();
+    // if field is an enum, check that its value is valid
+    if (type->is_enum()) {
+      string field_name = get_member_name(field->get_name());
+      indent(out) << "if (" << generate_isset_check(field) << " && !" << get_ttype_class_name(type)
+                  << ".VALID_VALUES.contains(" << field_name << "))";
+      scope_up(out);
+      indent(out) << "throw new TProtocolError(TProtocolErrorType.UNKNOWN, \"The field '"
+                  << field_name << "' has been assigned the invalid value "
+                  << "$" << field_name << "\");" << endl;
+      scope_down(out);
+    }
+  }
+
+  scope_down(out, endl2);
+}
+
+/**
+ * Generates a function to write all the fields of the struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_dart_generator::generate_dart_struct_writer(ostream& out, t_struct* tstruct) {
+  out << indent() << "write(TProtocol oprot)";
+  scope_up(out);
+
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // performs various checks (e.g. check that all required fields are set)
+  indent(out) << "validate();" << endl2;
+
+  indent(out) << "oprot.writeStructBegin(_STRUCT_DESC);" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    string field_name = get_member_name((*f_iter)->get_name());
+    bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
+    if (could_be_unset) {
+      indent(out) << "if (" << generate_isset_check(*f_iter) << ")";
+      scope_up(out);
+    }
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    if (null_allowed) {
+      indent(out) << "if (this." << field_name << " != null)";
+      scope_up(out);
+    }
+
+    indent(out) << "oprot.writeFieldBegin(_" << constant_name((*f_iter)->get_name())
+                << "_FIELD_DESC);" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "this.");
+
+    // Write field closer
+    indent(out) << "oprot.writeFieldEnd();" << endl;
+
+    if (null_allowed) {
+      scope_down(out);
+    }
+    if (could_be_unset) {
+      scope_down(out);
+    }
+  }
+  // Write the struct map
+  indent(out) << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();"
+      << endl;
+
+  scope_down(out, endl2);
+}
+
+/**
+ * Generates a function to write all the fields of the struct,
+ * which is a function result. These fields are only written
+ * if they are set in the Isset array, and only one of them
+ * can be set at a time.
+ *
+ * @param tstruct The struct definition
+ */
+void t_dart_generator::generate_dart_struct_result_writer(ostream& out, t_struct* tstruct) {
+  indent(out) << "write(TProtocol oprot)";
+  scope_up(out);
+
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "oprot.writeStructBegin(_STRUCT_DESC);" << endl2;
+
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      indent(out) << "if ";
+    } else {
+      out << " else if ";
+    }
+
+    out << "(this." << generate_isset_check(*f_iter) << ")";
+    scope_up(out);
+
+    indent(out) << "oprot.writeFieldBegin(_" << constant_name((*f_iter)->get_name())
+                << "_FIELD_DESC);" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "this.");
+
+    // Write field closer
+    indent(out) << "oprot.writeFieldEnd();" << endl;
+
+    scope_down(out, "");
+  }
+  out << endl;
+
+  // Write the struct map
+  indent(out) << "oprot.writeFieldStop();" << endl << indent()
+      << "oprot.writeStructEnd();" << endl;
+
+  scope_down(out, endl2);
+}
+
+void t_dart_generator::generate_generic_field_getters(std::ostream& out,
+                                                      t_struct* tstruct) {
+  // create the getter
+  indent(out) << "getFieldValue(int fieldID)";
+  scope_up(out);
+
+  indent(out) << "switch (fieldID)";
+  scope_up(out);
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    std::string field_name = get_member_name(field->get_name());
+
+    indent(out) << "case " << upcase_string(field_name) << ":" << endl;
+    indent_up();
+    indent(out) << "return this." << field_name << ";" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default:" << endl;
+  indent_up();
+  indent(out) << "throw new ArgumentError(\"Field $fieldID doesn't exist!\");" << endl;
+  indent_down();
+
+  scope_down(out);  // switch
+  scope_down(out, endl2);  // method
+}
+
+void t_dart_generator::generate_generic_field_setters(std::ostream& out,
+                                                      t_struct* tstruct) {
+
+  // create the setter
+  indent(out) << "setFieldValue(int fieldID, Object value)";
+  scope_up(out);
+
+  indent(out) << "switch (fieldID)";
+  scope_up(out);
+
+  // build up the bodies of both the getter and setter at once
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    std::string field_name = get_member_name(field->get_name());
+
+    indent(out) << "case " << upcase_string(field_name) << ":" << endl;
+    indent_up();
+
+    indent(out) << "if (value == null)";
+    scope_up(out);
+    indent(out) << "unset" << get_cap_name(field_name) << "();" << endl;
+
+    scope_down(out, " else");
+    scope_up(out);
+    indent(out) << "this." << field_name << " = value;" << endl;
+    scope_down(out);
+
+    indent(out) << "break;" << endl;
+
+    indent_down();
+    out << endl;
+  }
+
+  indent(out) << "default:" << endl;
+  indent_up();
+  indent(out) << "throw new ArgumentError(\"Field $fieldID doesn't exist!\");" << endl;
+  indent_down();
+
+  scope_down(out);  // switch
+  scope_down(out, endl2);  // method
+}
+
+// Creates a generic isSet method that takes the field number as argument
+void t_dart_generator::generate_generic_isset_method(std::ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // create the isSet method
+  indent(out) << "// Returns true if field corresponding to fieldID is set (has been assigned a "
+                 "value) and false otherwise" << endl;
+  indent(out) << "bool isSet(int fieldID)";
+  scope_up(out);
+
+  indent(out) << "switch (fieldID)";
+  scope_up(out);
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
+    indent_up();
+    indent(out) << "return " << generate_isset_check(field) << ";" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default:" << endl;
+  indent_up();
+  indent(out) << "throw new ArgumentError(\"Field $fieldID doesn't exist!\");" << endl;
+  indent_down();
+
+  scope_down(out);  // switch
+  scope_down(out, endl2);  // method
+}
+
+/**
+ * Generates a set of Dart Bean boilerplate functions (setters, getters, etc.)
+ * for the given struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_dart_generator::generate_dart_bean_boilerplate(ostream& out,
+                                                    t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    t_type* type = get_true_type(field->get_type());
+    std::string field_name = get_member_name(field->get_name());
+    std::string cap_name = get_cap_name(field_name);
+
+    indent(out) << "// " << field_name << endl;
+
+    // Simple getter
+    generate_dart_doc(out, field);
+    indent(out) << type_name(type) << " get " << field_name << " => this._" << field_name << ";" << endl2;
+
+    // Simple setter
+    generate_dart_doc(out, field);
+    indent(out) << "set " << field_name << "(" << type_name(type) << " " << field_name << ")";
+    scope_up(out);
+    indent(out) << "this._" << field_name << " = " << field_name << ";" << endl;
+    generate_isset_set(out, field);
+    scope_down(out, endl2);
+
+    // isSet method
+    indent(out) << "bool is" << get_cap_name("set") << cap_name << "()";
+    if (type_can_be_null(type)) {
+      out << " => this." << field_name << " != null;" << endl2;
+    } else {
+      out << " => this.__isset_" << field_name << ";" << endl2;
+    }
+
+    // Unsetter
+    indent(out) << "unset" << cap_name << "()";
+    scope_up(out);
+    if (type_can_be_null(type)) {
+      indent(out) << "this." << field_name << " = null;" << endl;
+    } else {
+      indent(out) << "this.__isset_" << field_name << " = false;" << endl;
+    }
+    scope_down(out, endl2);
+  }
+}
+
+/**
+ * Generates a toString() method for the given struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_dart_generator::generate_dart_struct_tostring(ostream& out,
+                                                   t_struct* tstruct) {
+  indent(out) << "String toString()";
+  scope_up(out);
+
+  indent(out) << "StringBuffer ret = new StringBuffer(\""
+              << tstruct->get_name() << "(\");" << endl2;
+
+  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) {
+    bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
+    if (could_be_unset) {
+      indent(out) << "if (" << generate_isset_check(*f_iter) << ")";
+      scope_up(out);
+    }
+
+    t_field* field = (*f_iter);
+    std::string field_name = get_member_name(field->get_name());
+
+    if (!first) {
+      indent(out) << "ret.write(\", \");" << endl;
+    }
+    indent(out) << "ret.write(\"" << field_name << ":\");" << endl;
+    bool can_be_null = type_can_be_null(field->get_type());
+    if (can_be_null) {
+      indent(out) << "if (this." << field_name << " == null)";
+      scope_up(out);
+      indent(out) << "ret.write(\"null\");" << endl;
+      scope_down(out, " else");
+      scope_up(out);
+    }
+
+    if (field->get_type()->is_binary()) {
+      indent(out) << "ret.write(\"BINARY\");" << endl;
+    } else if (field->get_type()->is_enum()) {
+      indent(out) << "String " << field_name << "_name = "
+                  << get_ttype_class_name(field->get_type())
+                  << ".VALUES_TO_NAMES[this." << field_name << "];" << endl;
+      indent(out) << "if (" << field_name << "_name != null)";
+      scope_up(out);
+      indent(out) << "ret.write(" << field_name << "_name);" << endl;
+      indent(out) << "ret.write(\" (\");" << endl;
+      scope_down(out);
+      indent(out) << "ret.write(this." << field_name << ");" << endl;
+      indent(out) << "if (" << field_name << "_name != null)";
+      scope_up(out);
+      indent(out) << "ret.write(\")\");" << endl;
+      scope_down(out);
+    } else {
+      indent(out) << "ret.write(this." << field_name << ");" << endl;
+    }
+
+    if (can_be_null) {
+      scope_down(out);
+    }
+    if (could_be_unset) {
+      scope_down(out);
+    }
+
+    out << endl;
+    first = false;
+  }
+
+  indent(out) << "ret.write(\")\");" << endl2;
+
+  indent(out) << "return ret.toString();" << endl;
+
+  scope_down(out, endl2);
+}
+
+/**
+ * Returns a string with the dart representation of the given thrift type
+ * (e.g. for the type struct it returns "TType.STRUCT")
+ */
+std::string t_dart_generator::get_dart_type_string(t_type* type) {
+  if (type->is_list()) {
+    return "TType.LIST";
+  } else if (type->is_map()) {
+    return "TType.MAP";
+  } else if (type->is_set()) {
+    return "TType.SET";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.STRUCT";
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_typedef()) {
+    return get_dart_type_string(((t_typedef*)type)->get_type());
+  } else if (type->is_base_type()) {
+    switch (((t_base_type*)type)->get_base()) {
+    case t_base_type::TYPE_VOID:
+      return "TType.VOID";
+      break;
+    case t_base_type::TYPE_STRING:
+      return "TType.STRING";
+      break;
+    case t_base_type::TYPE_BOOL:
+      return "TType.BOOL";
+      break;
+    case t_base_type::TYPE_I8:
+      return "TType.BYTE";
+      break;
+    case t_base_type::TYPE_I16:
+      return "TType.I16";
+      break;
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+      break;
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      return "TType.DOUBLE";
+      break;
+    default:
+      throw std::runtime_error("Unknown thrift type \"" + type->get_name()
+                               + "\" passed to t_dart_generator::get_dart_type_string!");
+      break; // This should never happen!
+    }
+  } else {
+    throw std::runtime_error(
+        "Unknown thrift type \"" + type->get_name()
+        + "\" passed to t_dart_generator::get_dart_type_string!"); // This should never happen!
+  }
+}
+
+void t_dart_generator::generate_service(t_service* tservice) {
+  string file_name = get_file_name(service_name_);
+  string f_service_name = src_dir_ + "/" + file_name + ".dart";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << autogen_comment() << dart_library(file_name) << endl;
+  f_service_ << service_imports() << dart_thrift_imports() << endl;
+  f_service_ << endl;
+
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+
+  f_service_.close();
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_dart_generator::generate_service_interface(t_service* tservice) {
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends_iface = " extends " + get_ttype_class_name(tservice->get_extends());
+  }
+
+  generate_dart_doc(f_service_, tservice);
+
+  string class_name = service_name_;
+  export_class_to_library(get_file_name(service_name_), class_name);
+  indent(f_service_) << "abstract class " << class_name << extends_iface;
+  scope_up(f_service_);
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << endl;
+    generate_dart_doc(f_service_, *f_iter);
+    indent(f_service_) << function_signature(*f_iter) << ";" << endl;
+  }
+
+  scope_down(f_service_, endl2);
+}
+
+/**
+ * Generates structs for all the service args and return types
+ *
+ * @param tservice The service
+ */
+void t_dart_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_dart_struct_definition(f_service_, ts, false, false);
+    generate_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_dart_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = get_ttype_class_name(tservice->get_extends());
+    extends_client = " extends " + extends + "Client";
+  }
+
+  string class_name = service_name_ + "Client";
+  export_class_to_library(get_file_name(service_name_), class_name);
+  indent(f_service_) << "class " << class_name << extends_client
+                     << " implements " << service_name_;
+  scope_up(f_service_);
+  f_service_ << endl;
+
+  indent(f_service_) << class_name << "(TProtocol iprot, [TProtocol oprot = null])";
+
+  if (!extends.empty()) {
+    indent_up();
+    f_service_ << endl;
+    indent(f_service_) << ": super(iprot, oprot);" << endl;
+    indent_down();
+  } else {
+    scope_up(f_service_);
+    indent(f_service_) << "_iprot = iprot;" << endl;
+    indent(f_service_) << "_oprot = (oprot == null) ? iprot : oprot;" << endl;
+    scope_down(f_service_);
+  }
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    indent(f_service_) << "TProtocol _iprot;" << endl2;
+    indent(f_service_) << "TProtocol get iprot => _iprot;" << endl2;
+    indent(f_service_) << "TProtocol _oprot;" << endl2;
+    indent(f_service_) << "TProtocol get oprot => _oprot;" << endl2;
+    indent(f_service_) << "int _seqid = 0;" << endl2;
+    indent(f_service_) << "int get seqid => _seqid;" << endl2;
+    indent(f_service_) << "int nextSeqid() => ++_seqid;" << endl2;
+  }
+
+  // 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) {
+    // Open function
+    indent(f_service_) << function_signature(*f_iter) << " async";
+    scope_up(f_service_);
+
+    // Get the struct of function call params
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+
+    string argsname = get_args_class_name((*f_iter)->get_name());
+    vector<t_field*>::const_iterator fld_iter;
+    const vector<t_field*>& fields = arg_struct->get_members();
+
+    // Serialize the request
+    indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << (*f_iter)->get_name() << "\", "
+               << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL")
+               << ", nextSeqid()));" << endl;
+    indent(f_service_) << argsname << " args = new " << argsname << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      string arg_field_name = get_member_name((*fld_iter)->get_name());
+      indent(f_service_) << "args." << arg_field_name << " = "
+                 << arg_field_name << ";" << endl;
+    }
+
+    indent(f_service_) << "args.write(oprot);" << endl;
+    indent(f_service_) << "oprot.writeMessageEnd();" << endl2;
+
+    indent(f_service_) << "await oprot.transport.flush();" << endl2;
+
+    if (!(*f_iter)->is_oneway()) {
+      indent(f_service_) << "TMessage msg = iprot.readMessageBegin();" << endl;
+      indent(f_service_) << "if (msg.type == TMessageType.EXCEPTION)";
+      scope_up(f_service_);
+      indent(f_service_) << "TApplicationError error = TApplicationError.read(iprot);" << endl;
+      indent(f_service_) << "iprot.readMessageEnd();" << endl;
+      indent(f_service_) << "throw error;" << endl;
+      scope_down(f_service_, endl2);
+
+      string result_class = get_result_class_name((*f_iter)->get_name());
+      indent(f_service_) << result_class << " result = new " << result_class << "();" << endl;
+      indent(f_service_) << "result.read(iprot);" << endl;
+      indent(f_service_) << "iprot.readMessageEnd();" << endl;
+
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) << "if (result." << generate_isset_check("success") << ")";
+        scope_up(f_service_);
+        indent(f_service_) << "return result.success;" << endl;
+        scope_down(f_service_, endl2);
+      }
+
+      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) {
+        string result_field_name = get_member_name((*x_iter)->get_name());
+        indent(f_service_) << "if (result." << result_field_name << " != null)";
+        scope_up(f_service_);
+        indent(f_service_) << "throw result." << result_field_name << ";" << endl;
+        scope_down(f_service_);
+      }
+
+      // If you get here it's an exception, unless a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) << "return;" << endl;
+      } else {
+        indent(f_service_) << "throw new TApplicationError(TApplicationErrorType.MISSING_RESULT, \""
+                   << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
+      }
+    }
+
+    scope_down(f_service_, endl2);
+  }
+
+  scope_down(f_service_, endl2);
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_dart_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  // typedef
+  indent(f_service_) << "typedef void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);" << endl2;
+
+  // Extends stuff
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = get_ttype_class_name(tservice->get_extends());
+    extends_processor = " extends " + extends + "Processor";
+  }
+
+  // Generate the header portion
+  string class_name =  service_name_ + "Processor";
+  export_class_to_library(get_file_name(service_name_), class_name);
+  indent(f_service_) << "class " << class_name << extends_processor << " implements TProcessor";
+  scope_up(f_service_);
+
+  indent(f_service_) << class_name << "(" << service_name_ << " iface)";
+  if (!extends.empty()) {
+    indent_up();
+    f_service_ << endl;
+    indent(f_service_) << ": super(iface)";
+    indent_down();
+  }
+  scope_up(f_service_);
+
+  if (extends.empty()) {
+    indent(f_service_) << "iface_ = iface;" << endl;
+  }
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    indent(f_service_) << "PROCESS_MAP[\"" << (*f_iter)->get_name()
+               << "\"] = " << get_member_name((*f_iter)->get_name()) << ";" << endl;
+  }
+  scope_down(f_service_, endl2);
+
+  indent(f_service_) << service_name_ << " iface_;" << endl;
+
+  if (extends.empty()) {
+    indent(f_service_) << "final Map<String, ProcessFunction> PROCESS_MAP = {};" << endl;
+  }
+
+  f_service_ << endl;
+
+  // Generate the server implementation
+  indent(f_service_) << "bool process(TProtocol iprot, TProtocol oprot)";
+  scope_up(f_service_);
+  indent(f_service_) << "TMessage msg = iprot.readMessageBegin();" << endl;
+  indent(f_service_) << "ProcessFunction fn = PROCESS_MAP[msg.name];" << endl;
+  indent(f_service_) << "if (fn == null)";
+  scope_up(f_service_);
+  indent(f_service_) << "TProtocolUtil.skip(iprot, TType.STRUCT);" << endl;
+  indent(f_service_) << "iprot.readMessageEnd();" << endl;
+  indent(f_service_) << "TApplicationError x = new TApplicationError(TApplicationErrorType.UNKNOWN_METHOD, "
+         "\"Invalid method name: '\"+msg.name+\"'\");" << endl;
+  indent(f_service_) << "oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" << endl;
+  indent(f_service_) << "x.write(oprot);" << endl;
+  indent(f_service_) << "oprot.writeMessageEnd();" << endl;
+  indent(f_service_) << "oprot.transport.flush();" << endl;
+  indent(f_service_) << "return true;" << endl;
+  scope_down(f_service_);
+  indent(f_service_) << "fn(msg.seqid, iprot, oprot);" << endl;
+  indent(f_service_) << "return true;" << endl;
+  scope_down(f_service_, endl2); // process function
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  scope_down(f_service_, endl2); // class
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_dart_generator::generate_function_helpers(t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return;
+  }
+
+  t_struct result(program_, get_result_class_name(tfunction->get_name()));
+  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_dart_struct_definition(f_service_, &result, false, true);
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_dart_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+
+  bool await_result = (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void());
+
+  indent(f_service_) << get_member_name(tfunction->get_name()) << "(int seqid, TProtocol iprot, TProtocol oprot)";
+  if (await_result) {
+    f_service_ << " async";
+  }
+  scope_up(f_service_);
+
+  string argsname = get_args_class_name(tfunction->get_name());
+  string resultname = get_result_class_name(tfunction->get_name());
+
+  indent(f_service_) << argsname << " args = new " << argsname << "();" << endl;
+  indent(f_service_) << "args.read(iprot);" << endl;
+  indent(f_service_) << "iprot.readMessageEnd();" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  if (!tfunction->is_oneway()) {
+    indent(f_service_) << resultname << " result = new " << resultname << "();" << endl;
+  }
+
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    indent(f_service_) << "try";
+    scope_up(f_service_);
+  }
+
+  // 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_ << indent();
+  if (await_result) {
+    f_service_ << "result.success = await ";
+  }
+  f_service_ << "iface_." << get_member_name(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." << get_member_name((*f_iter)->get_name());
+  }
+  f_service_ << ");" << endl;
+
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      string result_field_name = get_member_name((*x_iter)->get_name());
+      scope_down(f_service_, "");
+      f_service_ << " on " << type_name((*x_iter)->get_type())
+              << " catch(" << result_field_name << ")";
+      scope_up(f_service_);
+      if (!tfunction->is_oneway()) {
+        indent(f_service_) << "result." << result_field_name << " = "
+                   << result_field_name << ";" << endl;
+      }
+    }
+    scope_down(f_service_, " ");
+    f_service_ << "catch (th)";
+    scope_up(f_service_);
+    indent(f_service_) << "// Internal error" << endl;
+    indent(f_service_) << "TApplicationError x = new "
+               "TApplicationError(TApplicationErrorType.INTERNAL_ERROR, \"Internal error processing "
+               << tfunction->get_name() << "\");" << endl;
+    indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name()
+               << "\", TMessageType.EXCEPTION, seqid));" << endl;
+    indent(f_service_) << "x.write(oprot);" << endl;
+    indent(f_service_) << "oprot.writeMessageEnd();" << endl;
+    indent(f_service_) << "oprot.transport.flush();" << endl;
+    indent(f_service_) << "return;" << endl;
+    scope_down(f_service_);
+  }
+
+  if (tfunction->is_oneway()) {
+    indent(f_service_) << "return;" << endl;
+  } else {
+    indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name()
+               << "\", TMessageType.REPLY, seqid));" << endl;
+    indent(f_service_) << "result.write(oprot);" << endl;
+    indent(f_service_) << "oprot.writeMessageEnd();" << endl;
+    indent(f_service_) << "oprot.transport.flush();" << endl;
+  }
+
+  scope_down(f_service_, endl2);
+}
+
+/**
+ * Deserializes a field of any type.
+ *
+ * @param tfield The field
+ * @param prefix The variable name or container for this field
+ */
+void t_dart_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+  string field_name = get_member_name(tfield->get_name());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + field_name;
+  }
+
+  string name = prefix + field_name;
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    indent(out) << name << " = 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:
+        if (type->is_binary()) {
+          out << "readBinary();";
+        } else {
+          out << "readString();";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "readBool();";
+        break;
+      case t_base_type::TYPE_I8:
+        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 Dart name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "readI32();";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           field_name.c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a struct, invokes read()
+ */
+void t_dart_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  indent(out) << prefix << " = new " << type_name(tstruct) << "();" << endl;
+  indent(out) << prefix << ".read(iprot);" << endl;
+}
+
+/**
+ * Deserializes a container by reading its size and then iterating
+ */
+void t_dart_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) {
+  indent(out);
+  scope_up(out, "");
+
+  string obj;
+
+  if (ttype->is_map()) {
+    obj = tmp("_map");
+  } else if (ttype->is_set()) {
+    obj = tmp("_set");
+  } else if (ttype->is_list()) {
+    obj = tmp("_list");
+  }
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    indent(out) << "TMap " << obj << " = iprot.readMapBegin();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "TSet " << obj << " = iprot.readSetBegin();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "TList " << obj << " = iprot.readListBegin();" << endl;
+  }
+
+  indent(out) << prefix << " = new " << type_name(ttype) << "();" << endl;
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".length"
+              << "; "
+              << "++" << i << ")";
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  scope_down(out);
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "iprot.readMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "iprot.readSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "iprot.readListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_dart_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) << declare_field(&fkey) << endl;
+  indent(out) << declare_field(&fval) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) << prefix << "[" << key << "] = " << val << ";" << endl;
+}
+
+/**
+ * Deserializes a set element
+ */
+void t_dart_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".add(" << elem << ");" << endl;
+}
+
+/**
+ * Deserializes a list element
+ */
+void t_dart_generator::generate_deserialize_list_element(ostream& out,
+                                                        t_list* tlist,
+                                                        string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".add(" << elem << ");" << endl;
+}
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_dart_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+  string field_name = get_member_name(tfield->get_name());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + field_name;
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, prefix + field_name);
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, prefix + field_name);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    string name = prefix + field_name;
+    indent(out) << "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:
+        if (type->is_binary()) {
+          out << "writeBinary(" << name << ");";
+        } else {
+          out << "writeString(" << name << ");";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ");";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "writeByte(" << name << ");";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16(" << name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32(" << name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64(" << name << ");";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble(" << name << ");";
+        break;
+      default:
+        throw "compiler error: no Dart name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32(" << name << ");";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           field_name.c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_dart_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  (void)tstruct;
+  indent(out) << prefix << ".write(oprot);" << endl;
+}
+
+/**
+ * Serializes a container by writing its size then the elements.
+ *
+ * @param ttype  The type of container
+ * @param prefix String prefix for fields
+ */
+void t_dart_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  indent(out);
+  scope_up(out, "");
+
+  if (ttype->is_map()) {
+    string iter = tmp("_key");
+    indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type())
+                << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix << ".length));"
+                << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type())
+                << ", " << prefix << ".length));" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.writeListBegin(new TList("
+                << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".length));"
+                << endl;
+  }
+
+  string iter = tmp("elem");
+  if (ttype->is_map()) {
+    indent(out) << "for (var " << iter << " in " << prefix << ".keys)";
+  } else if (ttype->is_set() || ttype->is_list()) {
+    indent(out) << "for (var " << iter << " in " << prefix << ")";
+  }
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
+  } else if (ttype->is_set()) {
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+  } else if (ttype->is_list()) {
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+  }
+
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "oprot.writeMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.writeSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.writeListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ */
+void t_dart_generator::generate_serialize_map_element(ostream& out,
+                                                     t_map* tmap,
+                                                     string iter,
+                                                     string map) {
+  t_field kfield(tmap->get_key_type(), iter);
+  generate_serialize_field(out, &kfield, "");
+  t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
+  generate_serialize_field(out, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_dart_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_dart_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Returns a Dart type name
+ *
+ * @param ttype The type
+ * @return Dart type name, i.e. Map<Key, Value>
+ */
+string t_dart_generator::type_name(t_type* ttype) {
+  ttype = get_true_type(ttype);
+
+  if (ttype->is_base_type()) {
+    return base_type_name((t_base_type*)ttype);
+  } else if (ttype->is_enum()) {
+    return "int";
+  } else if (ttype->is_map()) {
+    t_map* tmap = (t_map*)ttype;
+    return "Map<" + type_name(tmap->get_key_type()) + ", "
+                  + type_name(tmap->get_val_type()) + ">";
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*)ttype;
+    return "Set<" + type_name(tset->get_elem_type()) + ">";
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*)ttype;
+    return "List<" + type_name(tlist->get_elem_type()) + ">";
+  }
+
+  return get_ttype_class_name(ttype);
+}
+
+/**
+ * Returns the Dart type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ */
+string t_dart_generator::base_type_name(t_base_type* type) {
+  t_base_type::t_base tbase = type->get_base();
+
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    if (type->is_binary()) {
+      return "Uint8List";
+    } else {
+      return "String";
+    }
+  case t_base_type::TYPE_BOOL:
+    return "bool";
+  case t_base_type::TYPE_I8:
+  case t_base_type::TYPE_I16:
+  case t_base_type::TYPE_I32:
+  case t_base_type::TYPE_I64:
+    return "int";
+  case t_base_type::TYPE_DOUBLE:
+    return "double";
+  default:
+    throw "compiler error: no Dart name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_dart_generator::declare_field(t_field* tfield, bool init) {
+  string field_name = get_member_name(tfield->get_name());
+  string result = type_name(tfield->get_type()) + " " + field_name;
+  if (init) {
+    t_type* ttype = get_true_type(tfield->get_type());
+    if (ttype->is_base_type() && tfield->get_value() != NULL) {
+      std:: ofstream dummy;
+      result += " = " + render_const_value(dummy, field_name, ttype, tfield->get_value());
+    } else if (ttype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "NO T_VOID CONSTRUCT";
+      case t_base_type::TYPE_STRING:
+        result += " = null";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = false";
+        break;
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = 0.0";
+        break;
+      }
+
+    } else if (ttype->is_enum()) {
+      result += " = 0";
+    } else if (ttype->is_container()) {
+      result += " = new " + type_name(ttype) + "()";
+    } else {
+      result += " = new " + type_name(ttype) + "()";
+      ;
+    }
+  }
+  return result + ";";
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_dart_generator::function_signature(t_function* tfunction) {
+  std::string arguments = argument_list(tfunction->get_arglist());
+
+  std::string returntype;
+  if (tfunction->get_returntype()->is_void()) {
+    returntype = "Future";
+  } else {
+    returntype = "Future<" + type_name(tfunction->get_returntype()) + ">";
+  }
+
+  std::string result = returntype + " " + get_member_name(tfunction->get_name()) +
+                       "(" + arguments + ")";
+  return result;
+}
+
+/**
+ * Renders a comma separated field list, with type names
+ */
+string t_dart_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 += ", ";
+    }
+    string field_name = get_member_name((*f_iter)->get_name());
+    result += type_name((*f_iter)->get_type()) + " " + field_name;
+  }
+  return result;
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ */
+string t_dart_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 "TType.STRING";
+    case t_base_type::TYPE_BOOL:
+      return "TType.BOOL";
+    case t_base_type::TYPE_I8:
+      return "TType.BYTE";
+    case t_base_type::TYPE_I16:
+      return "TType.I16";
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "TType.DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.STRUCT";
+  } else if (type->is_map()) {
+    return "TType.MAP";
+  } else if (type->is_set()) {
+    return "TType.SET";
+  } else if (type->is_list()) {
+    return "TType.LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+std::string t_dart_generator::init_value(t_field* field) {
+  // Do not initialize optional fields
+  if (field->get_req() == t_field::T_OPTIONAL) {
+    return "";
+  }
+
+  t_type* ttype = field->get_type();
+
+  // Get the actual type for a typedef
+  if (ttype->is_typedef()) {
+    ttype = ((t_typedef*)ttype)->get_type();
+  }
+
+  // Only consider base types for default initialization
+  if (!ttype->is_base_type()) {
+    return "";
+  }
+  t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+
+  // Initialize bools, ints, and doubles with sane defaults
+  string result;
+  switch (tbase) {
+  case t_base_type::TYPE_BOOL:
+    result = " = false";
+    break;
+  case t_base_type::TYPE_I8:
+  case t_base_type::TYPE_I16:
+  case t_base_type::TYPE_I32:
+  case t_base_type::TYPE_I64:
+    result = " = 0";
+    break;
+  case t_base_type::TYPE_DOUBLE:
+    result = " = 0.0";
+    break;
+  case t_base_type::TYPE_VOID:
+  case t_base_type::TYPE_STRING:
+    result = "";
+    break;
+  }
+
+  return result;
+}
+
+std::string t_dart_generator::get_cap_name(std::string name) {
+  name[0] = toupper(name[0]);
+  return name;
+}
+
+std::string t_dart_generator::get_member_name(std::string name) {
+  name[0] = tolower(name[0]);
+  return name;
+}
+
+std::string t_dart_generator::get_args_class_name(std::string name) {
+  return name + "_args";
+}
+
+std::string t_dart_generator::get_result_class_name(std::string name) {
+  return name + "_result";
+}
+
+std::string t_dart_generator::get_file_name(std::string name) {
+  // e.g. change APIForFileIO to api_for_file_io
+
+  string ret;
+  const char* tmp = name.c_str();
+  bool is_prev_lc = true;
+  bool is_current_lc = tmp[0] == tolower(tmp[0]);
+  bool is_next_lc = false;
+
+  for (unsigned int i = 0; i < name.length(); i++) {
+    char lc = tolower(tmp[i]);
+
+    if (i == name.length() - 1) {
+      is_next_lc = false;
+    } else {
+      is_next_lc = (tmp[i+1] == tolower(tmp[i+1]));
+    }
+
+    if (i != 0 && !is_current_lc && (is_prev_lc || is_next_lc)) {
+      ret += "_";
+    }
+    ret += lc;
+
+    is_prev_lc = is_current_lc;
+    is_current_lc = is_next_lc;
+  }
+
+  return ret;
+}
+
+std::string t_dart_generator::get_constants_class_name(std::string name) {
+  // e.g. change my_great_model to MyGreatModelConstants
+  string ret;
+  const char* tmp = name.c_str();
+  bool is_prev_underscore = true;
+
+  for (unsigned int i = 0; i < name.length(); i++) {
+    if (tmp[i] == '_') {
+      is_prev_underscore = true;
+    } else {
+      if (is_prev_underscore) {
+        ret += toupper(tmp[i]);
+      } else {
+        ret += tmp[i];
+      }
+
+      is_prev_underscore = false;
+    }
+  }
+
+  return ret + "Constants";
+}
+
+string t_dart_generator::constant_name(string name) {
+  string constant_name;
+
+  bool is_first = true;
+  bool was_previous_char_upper = false;
+  for (string::iterator iter = name.begin(); iter != name.end(); ++iter) {
+    string::value_type character = (*iter);
+
+    bool is_upper = isupper(character);
+
+    if (is_upper && !is_first && !was_previous_char_upper) {
+      constant_name += '_';
+    }
+    constant_name += toupper(character);
+
+    is_first = false;
+    was_previous_char_upper = is_upper;
+  }
+
+  return constant_name;
+}
+
+/**
+ * Emits a doc comment if the provided object has a doc in Thrift
+ */
+void t_dart_generator::generate_dart_doc(ostream& out, t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    generate_docstring_comment(out, "", "/// ", tdoc->get_doc(), "");
+  }
+}
+
+/**
+ * Emits a doc comment if the provided function object has a doc in Thrift
+ */
+void t_dart_generator::generate_dart_doc(ostream& out, t_function* tfunction) {
+  if (tfunction->has_doc()) {
+    stringstream ss;
+    ss << tfunction->get_doc();
+    const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+    vector<t_field*>::const_iterator p_iter;
+    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
+      t_field* p = *p_iter;
+      string field_name = get_member_name(p->get_name());
+      ss << "\n@param " << field_name;
+      if (p->has_doc()) {
+        ss << " " << p->get_doc();
+      }
+    }
+    generate_docstring_comment(out, "", "/// ", ss.str(), "");
+  }
+}
+
+std::string t_dart_generator::generate_isset_check(t_field* field) {
+  string field_name = get_member_name(field->get_name());
+  return generate_isset_check(field_name);
+}
+
+std::string t_dart_generator::generate_isset_check(std::string field_name) {
+  return "is" + get_cap_name("set") + get_cap_name(field_name) + "()";
+}
+
+void t_dart_generator::generate_isset_set(ostream& out, t_field* field) {
+  if (!type_can_be_null(field->get_type())) {
+    string field_name = get_member_name(field->get_name());
+    indent(out) << "this.__isset_" << field_name << " = true;" << endl;
+  }
+}
+
+std::string t_dart_generator::get_ttype_class_name(t_type* ttype) {
+  if (program_ == ttype->get_program()) {
+    return ttype->get_name();
+  } else {
+    string named_import = "t_" + find_library_name(ttype->get_program());
+    return named_import + "." + ttype->get_name();
+  }
+}
+
+THRIFT_REGISTER_GENERATOR(
+    dart,
+    "Dart",
+    "    library_name:    Optional override for library name.\n"
+    "    library_prefix:  Generate code that can be used within an existing library.\n"
+    "                     Use a dot-separated string, e.g. \"my_parent_lib.src.gen\"\n"
+    "    pubspec_lib:     Optional override for thrift lib dependency in pubspec.yaml,\n"
+    "                     e.g. \"thrift: 0.x.x\".  Use a pipe delimiter to separate lines,\n"
+    "                     e.g. \"thrift:|  git:|    url: git@foo.com\"\n"
+)
diff --git a/compiler/cpp/src/thrift/generate/t_delphi_generator.cc b/compiler/cpp/src/thrift/generate/t_delphi_generator.cc
new file mode 100644
index 0000000..8bd77e8
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_delphi_generator.cc
@@ -0,0 +1,4011 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+#include <cassert>
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <list>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include <cctype>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ofstream;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+class t_delphi_generator : public t_oop_generator {
+public:
+  t_delphi_generator(t_program* program,
+                     const std::map<std::string, std::string>& parsed_options,
+                     const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    indent_impl_ = 0;
+    has_forward = false;
+    has_enum = false;
+    has_const = false;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    ansistr_binary_ = false;
+    register_types_ = false;
+    constprefix_ = false;
+    events_ = false;
+    xmldoc_ = false;
+    async_ = false;
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("ansistr_binary") == 0) {
+        ansistr_binary_ = true;
+      } else if( iter->first.compare("register_types") == 0) {
+        register_types_ = true;
+      } else if( iter->first.compare("constprefix") == 0) {
+        constprefix_ = true;
+      } else if( iter->first.compare("events") == 0) {
+        events_ = true;
+      } else if( iter->first.compare("xmldoc") == 0) {
+        xmldoc_ = true;
+      } else if( iter->first.compare("async") == 0) {
+        async_ = true;
+      } else {
+        throw "unknown option delphi:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-delphi";
+    escape_.clear();
+    escape_['\''] = "''";
+  }
+
+  void init_generator();
+  void close_generator();
+
+  void generate_consts(std::vector<t_const*> consts);
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_forward_declaration(t_struct* tstruct);
+  void generate_struct(t_struct* tstruct);
+  void generate_xception(t_struct* txception);
+  void generate_service(t_service* tservice);
+  void generate_property(ostream& out, t_field* tfield, bool isPublic, bool is_xception);
+  void generate_property_writer_(ostream& out, t_field* tfield, bool isPublic);
+
+  void generate_delphi_property(ostream& out,
+                                bool struct_is_exception,
+                                t_field* tfield,
+                                bool isPublic,
+                                std::string fieldPrefix = "");
+  void generate_delphi_isset_reader_definition(ostream& out, t_field* tfield, bool is_xception);
+  void generate_delphi_property_reader_definition(ostream& out,
+                                                  t_field* tfield,
+                                                  bool is_xception_class);
+  void generate_delphi_property_writer_definition(ostream& out,
+                                                  t_field* tfield,
+                                                  bool is_xception_class);
+  void generate_delphi_property_reader_impl(ostream& out,
+                                            std::string cls_prefix,
+                                            std::string name,
+                                            t_type* type,
+                                            t_field* tfield,
+                                            std::string fieldPrefix,
+                                            bool is_xception_class);
+  void generate_delphi_property_writer_impl(ostream& out,
+                                            std::string cls_prefix,
+                                            std::string name,
+                                            t_type* type,
+                                            t_field* tfield,
+                                            std::string fieldPrefix,
+                                            bool is_xception_class,
+                                            bool is_union,
+                                            bool is_xception_factory,
+                                            std::string xception_factory_name);
+  void generate_delphi_clear_union_value(ostream& out,
+                                         std::string cls_prefix,
+                                         std::string name,
+                                         t_type* type,
+                                         t_field* tfield,
+                                         std::string fieldPrefix,
+                                         bool is_xception_class,
+                                         bool is_union,
+                                         bool is_xception_factory,
+                                         std::string xception_factory_name);
+  void generate_delphi_isset_reader_impl(ostream& out,
+                                         std::string cls_prefix,
+                                         std::string name,
+                                         t_type* type,
+                                         t_field* tfield,
+                                         std::string fieldPrefix,
+                                         bool is_xception);
+  void generate_delphi_struct_writer_impl(ostream& out,
+                                          std::string cls_prefix,
+                                          t_struct* tstruct,
+                                          bool is_exception);
+  void generate_delphi_struct_result_writer_impl(ostream& out,
+                                                 std::string cls_prefix,
+                                                 t_struct* tstruct,
+                                                 bool is_exception);
+
+  void generate_delphi_struct_tostring_impl(ostream& out,
+                                            std::string cls_prefix,
+                                            t_struct* tstruct,
+                                            bool is_exception,
+                                            bool is_x_factory);
+
+  void add_delphi_uses_list(string unitname);
+
+  void generate_delphi_struct_reader_impl(ostream& out,
+                                          std::string cls_prefix,
+                                          t_struct* tstruct,
+                                          bool is_exception);
+  void generate_delphi_create_exception_impl(ostream& out,
+                                             string cls_prefix,
+                                             t_struct* tstruct,
+                                             bool is_exception);
+
+  bool const_needs_var(t_type* type);
+  void print_const_prop(std::ostream& out, string name, t_type* type, t_const_value* value);
+  void print_private_field(std::ostream& out, string name, t_type* type, t_const_value* value);
+  void print_const_value(std::ostream& vars,
+                         std::ostream& out,
+                         std::string name,
+                         t_type* type,
+                         t_const_value* value);
+  void initialize_field(std::ostream& vars,
+                        std::ostream& out,
+                        std::string name,
+                        t_type* type,
+                        t_const_value* value);
+  void finalize_field(std::ostream& out,
+                      std::string name,
+                      t_type* type,
+                      t_const_value* value,
+                      std::string cls_nm = "");
+  std::string render_const_value(std::ostream& local_vars,
+                                 std::ostream& out,
+                                 std::string name,
+                                 t_type* type,
+                                 t_const_value* value);
+  void print_const_def_value(std::ostream& vars,
+                             std::ostream& out,
+                             std::string name,
+                             t_type* type,
+                             t_const_value* value,
+                             std::string cls_nm = "");
+  std::string make_constants_classname();
+
+  void generate_delphi_struct(t_struct* tstruct, bool is_exception);
+  void generate_delphi_struct_impl(ostream& out,
+                                   std::string cls_prefix,
+                                   t_struct* tstruct,
+                                   bool is_exception,
+                                   bool is_result = false,
+                                   bool is_x_factory = false);
+  void print_delphi_struct_type_factory_func(ostream& out, t_struct* tstruct);
+  void generate_delphi_struct_type_factory(ostream& out,
+                                           std::string cls_prefix,
+                                           t_struct* tstruct,
+                                           bool is_exception,
+                                           bool is_result = false,
+                                           bool is_x_factory = false);
+  void generate_delphi_struct_type_factory_registration(ostream& out,
+                                                        std::string cls_prefix,
+                                                        t_struct* tstruct,
+                                                        bool is_exception,
+                                                        bool is_result = false,
+                                                        bool is_x_factory = false);
+  void generate_delphi_struct_definition(std::ostream& out,
+                                         t_struct* tstruct,
+                                         bool is_xception = false,
+                                         bool in_class = false,
+                                         bool is_result = false,
+                                         bool is_x_factory = false);
+  void generate_delphi_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_delphi_struct_result_writer(std::ostream& out, t_struct* tstruct);
+  void generate_delphi_struct_writer(std::ostream& out, t_struct* tstruct);
+  void generate_delphi_struct_tostring(std::ostream& out, t_struct* tstruct);
+
+  void generate_function_helpers(t_function* tfunction);
+  void generate_service_interface(t_service* tservice);
+  void generate_service_interface(t_service* tservice, bool for_async);
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_client(t_service* tservice);
+  void generate_service_server(t_service* tservice);
+  void generate_process_function(t_service* tservice, t_function* function);
+
+  void generate_deserialize_field(std::ostream& out,
+                                  bool is_xception,
+                                  t_field* tfield,
+                                  std::string prefix,
+                                  std::ostream& local_vars);
+  void generate_deserialize_struct(std::ostream& out,
+                                   t_struct* tstruct,
+                                   std::string name,
+                                   std::string prefix);
+  void generate_deserialize_container(ostream& out,
+                                      bool is_xception,
+                                      t_type* ttype,
+                                      string name,
+                                      std::ostream& local_vars);
+
+  void generate_deserialize_set_element(std::ostream& out,
+                                        bool is_xception,
+                                        t_set* tset,
+                                        std::string prefix,
+                                        std::ostream& local_vars);
+  void generate_deserialize_map_element(std::ostream& out,
+                                        bool is_xception,
+                                        t_map* tmap,
+                                        std::string prefix,
+                                        std::ostream& local_vars);
+  void generate_deserialize_list_element(std::ostream& out,
+                                         bool is_xception,
+                                         t_list* list,
+                                         std::string prefix,
+                                         std::ostream& local_vars);
+
+  void generate_serialize_field(std::ostream& out,
+                                bool is_xception,
+                                t_field* tfield,
+                                std::string prefix,
+                                std::ostream& local_vars);
+  void generate_serialize_struct(std::ostream& out,
+                                 t_struct* tstruct,
+                                 std::string prefix,
+                                 std::ostream& local_vars);
+  void generate_serialize_container(std::ostream& out,
+                                    bool is_xception,
+                                    t_type* ttype,
+                                    std::string prefix,
+                                    std::ostream& local_vars);
+  void generate_serialize_map_element(std::ostream& out,
+                                      bool is_xception,
+                                      t_map* tmap,
+                                      std::string iter,
+                                      std::string map,
+                                      std::ostream& local_vars);
+  void generate_serialize_set_element(std::ostream& out,
+                                      bool is_xception,
+                                      t_set* tmap,
+                                      std::string iter,
+                                      std::ostream& local_vars);
+  void generate_serialize_list_element(std::ostream& out,
+                                       bool is_xception,
+                                       t_list* tlist,
+                                       std::string iter,
+                                       std::ostream& local_vars);
+
+  void delphi_type_usings(std::ostream& out);
+  std::string delphi_thrift_usings();
+
+  std::string type_name(t_type* ttype,
+                        bool b_cls = false,
+                        bool b_no_postfix = false,
+                        bool b_exception_factory = false,
+                        bool b_full_exception_factory = false);
+  std::string normalize_clsnm(std::string name,
+                              std::string prefix,
+                              bool b_no_check_keyword = false);
+  std::string make_valid_delphi_identifier(std::string const& fromName);
+  std::string input_arg_prefix(t_type* ttype);
+
+  std::string base_type_name(t_base_type* tbase);
+  std::string declare_field(t_field* tfield,
+                            bool init = false,
+                            std::string prefix = "",
+                            bool is_xception_class = false);
+  std::string function_signature(t_function* tfunction,
+                                 bool for_async,
+                                 std::string full_cls = "",
+                                 bool is_xception = false);
+  std::string argument_list(t_struct* tstruct);
+  std::string constructor_argument_list(t_struct* tstruct, std::string current_indent);
+  std::string type_to_enum(t_type* ttype);
+  std::string prop_name(t_field* tfield, bool is_xception = false);
+  std::string prop_name(std::string name, bool is_xception = false);
+  std::string constructor_param_name(string name);
+
+  void write_enum(std::string line);
+  void write_forward_decr(std::string line);
+  void write_const(std::string line);
+  void write_struct(std::string line);
+  void write_service(std::string line);
+
+  virtual std::string autogen_comment() {
+    return std::string("(**\n") + " * Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
+           + " *\n" + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n"
+           + " *)\n";
+  }
+
+  string replace_all(string contents, string search, string replace);
+  string xml_encode(string contents);
+  string xmldoc_encode(string contents);
+  string xmlattrib_encode(string contents);
+  void generate_delphi_doc(std::ostream& out, t_field* field);
+  void generate_delphi_doc(std::ostream& out, t_doc* tdoc);
+  void generate_delphi_doc(std::ostream& out, t_function* tdoc);
+  void generate_delphi_docstring_comment(std::ostream& out, string contents);
+
+  bool type_can_be_null(t_type* ttype) {
+    while (ttype->is_typedef()) {
+      ttype = ((t_typedef*)ttype)->get_type();
+    }
+
+    return ttype->is_container() || ttype->is_struct() || ttype->is_xception();
+  }
+
+private:
+  std::string namespace_name_;
+  std::ostringstream s_forward_decr;
+  std::ostringstream s_enum;
+  std::ostringstream s_const;
+  std::ostringstream s_struct;
+  std::ostringstream s_service;
+  std::ostringstream s_const_impl;
+  std::ostringstream s_struct_impl;
+  std::ostringstream s_service_impl;
+  std::ostringstream s_type_factory_registration;
+  std::ostringstream s_type_factory_funcs;
+  bool has_forward;
+  bool has_enum;
+  bool has_const;
+  std::string namespace_dir_;
+  std::map<std::string, int> delphi_keywords;
+  std::map<std::string, int> delphi_reserved_method;
+  std::map<std::string, int> delphi_reserved_method_exception;
+  std::map<std::string, int> types_known;
+  std::list<t_typedef*> typedefs_pending;
+  std::vector<std::string> uses_list;
+  void create_keywords();
+  bool find_keyword(std::map<std::string, int>& keyword_map, std::string name);
+  std::string normalize_name(std::string name,
+                             bool b_method = false,
+                             bool b_exception_method = false);
+  std::string empty_value(t_type* type);
+  bool is_fully_defined_type(t_type* ttype);
+  void add_defined_type(t_type* ttype);
+  void init_known_types_list();
+  bool is_void(t_type* type);
+  int indent_impl_;
+  bool ansistr_binary_;
+  bool register_types_;
+  bool constprefix_;
+  bool events_;
+  bool xmldoc_;
+  bool async_;
+  void indent_up_impl() { ++indent_impl_; };
+  void indent_down_impl() { --indent_impl_; };
+  std::string indent_impl() {
+    std::string ind = "";
+    int i;
+    for (i = 0; i < indent_impl_; ++i) {
+      ind += "  ";
+    }
+    return ind;
+  };
+  std::ostream& indent_impl(std::ostream& os) { return os << indent_impl(); };
+};
+
+string t_delphi_generator::replace_all(string contents, string search, string repl) {
+  string str(contents);
+
+  size_t slen = search.length();
+  size_t rlen = repl.length();
+  size_t incr = (rlen > 0) ? rlen : 1;
+
+  if (slen > 0) {
+    size_t found = str.find(search);
+    while ((found != string::npos) && (found < str.length())) {
+      str.replace(found, slen, repl);
+      found = str.find(search, found + incr);
+    }
+  }
+
+  return str;
+}
+
+// XML encoding
+string t_delphi_generator::xml_encode(string contents) {
+  string str(contents);
+
+  // escape the escape
+  str = replace_all(str, "&", "&amp;");
+
+  // other standard XML entities
+  str = replace_all(str, "<", "&lt;");
+  str = replace_all(str, ">", "&gt;");
+
+  return str;
+}
+
+// XML attribute encoding
+string t_delphi_generator::xmlattrib_encode(string contents) {
+  string str(xml_encode(contents));
+
+  // our attribs are enclosed in "
+  str = replace_all(str, "\"", "\\\"");
+
+  return str;
+}
+
+// XML encoding for doc comments
+string t_delphi_generator::xmldoc_encode(string contents) {
+  string str(xml_encode(contents));
+
+  // XMLDoc specific: convert linebreaks into <para>graphs</para>
+  str = replace_all(str, "\r\n", "\r");
+  str = replace_all(str, "\n", "\r");
+  str = replace_all(str, "\r", "</para>\n<para>");
+
+  return str;
+}
+
+void t_delphi_generator::generate_delphi_docstring_comment(ostream& out, string contents) {
+  if (xmldoc_) {
+    generate_docstring_comment(out,
+                               "{$REGION 'XMLDoc'}/// <summary>\n",
+                               "/// ",
+                               "<para>" + contents + "</para>",
+                               "/// </summary>\n{$ENDREGION}\n");
+  }
+}
+
+void t_delphi_generator::generate_delphi_doc(ostream& out, t_field* field) {
+  if (xmldoc_) {
+    if (field->get_type()->is_enum()) {
+      string combined_message = xmldoc_encode(field->get_doc()) + "\n<seealso cref=\""
+                                + xmldoc_encode(type_name(field->get_type())) + "\"/>";
+      generate_delphi_docstring_comment(out, combined_message);
+    } else {
+      generate_delphi_doc(out, (t_doc*)field);
+    }
+  }
+}
+
+void t_delphi_generator::generate_delphi_doc(ostream& out, t_doc* tdoc) {
+  if (tdoc->has_doc() && xmldoc_) {
+    generate_delphi_docstring_comment(out, xmldoc_encode(tdoc->get_doc()));
+  }
+}
+
+void t_delphi_generator::generate_delphi_doc(ostream& out, t_function* tfunction) {
+  if (tfunction->has_doc() && xmldoc_) {
+    stringstream ps;
+    const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+    vector<t_field*>::const_iterator p_iter;
+    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
+      t_field* p = *p_iter;
+      ps << "\n<param name=\"" << xmlattrib_encode(p->get_name()) << "\">";
+      if (p->has_doc()) {
+        std::string str = p->get_doc();
+        str.erase(std::remove(str.begin(), str.end(), '\n'),
+                  str.end()); // remove the newlines that appear from the parser
+        ps << xmldoc_encode(str);
+      }
+      ps << "</param>";
+    }
+    generate_docstring_comment(out,
+                               "{$REGION 'XMLDoc'}",
+                               "/// ",
+                               "<summary><para>" + xmldoc_encode(tfunction->get_doc())
+                               + "</para></summary>" + ps.str(),
+                               "{$ENDREGION}\n");
+  }
+}
+
+bool t_delphi_generator::find_keyword(std::map<std::string, int>& keyword_map, std::string name) {
+  std::string::size_type len = name.length();
+
+  if (len <= 0) {
+    return false;
+  }
+
+  std::string::size_type nlast = name.find_last_of('_');
+
+  if (nlast >= 1) {
+    if (nlast == (len - 1)) {
+      string new_name(name, 0, nlast);
+      return find_keyword(keyword_map, new_name);
+    }
+  }
+  return (keyword_map[name] == 1);
+}
+
+std::string t_delphi_generator::normalize_name(std::string name,
+                                               bool b_method,
+                                               bool b_exception_method) {
+  string tmp(name);
+  std::transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast<int (*)(int)>(std::tolower));
+
+  bool b_found = false;
+
+  if (find_keyword(delphi_keywords, tmp)) {
+    b_found = true;
+  } else if (b_method && find_keyword(delphi_reserved_method, tmp)) {
+    b_found = true;
+  } else if (b_exception_method && find_keyword(delphi_reserved_method_exception, tmp)) {
+    b_found = true;
+  }
+
+  if (b_found) {
+    return name + "_";
+  } else {
+    return name;
+  }
+}
+
+void t_delphi_generator::create_keywords() {
+  delphi_keywords["and"] = 1;
+  delphi_keywords["end"] = 1;
+  delphi_keywords["interface"] = 1;
+  delphi_keywords["raise"] = 1;
+  delphi_keywords["uses"] = 1;
+  delphi_keywords["array"] = 1;
+  delphi_keywords["except"] = 1;
+  delphi_keywords["is"] = 1;
+  delphi_keywords["record"] = 1;
+  delphi_keywords["var"] = 1;
+  delphi_keywords["as"] = 1;
+  delphi_keywords["exports"] = 1;
+  delphi_keywords["label"] = 1;
+  delphi_keywords["repeat"] = 1;
+  delphi_keywords["while"] = 1;
+  delphi_keywords["asm"] = 1;
+  delphi_keywords["file"] = 1;
+  delphi_keywords["library"] = 1;
+  delphi_keywords["resourcestring"] = 1;
+  delphi_keywords["with"] = 1;
+  delphi_keywords["begin"] = 1;
+  delphi_keywords["finalization"] = 1;
+  delphi_keywords["mod"] = 1;
+  delphi_keywords["set"] = 1;
+  delphi_keywords["xor"] = 1;
+  delphi_keywords["case"] = 1;
+  delphi_keywords["finally"] = 1;
+  delphi_keywords["nil"] = 1;
+  delphi_keywords["shl"] = 1;
+  delphi_keywords["class"] = 1;
+  delphi_keywords["for"] = 1;
+  delphi_keywords["not"] = 1;
+  delphi_keywords["shr"] = 1;
+  delphi_keywords["const"] = 1;
+  delphi_keywords["function"] = 1;
+  delphi_keywords["object"] = 1;
+  delphi_keywords["string"] = 1;
+  delphi_keywords["constructor"] = 1;
+  delphi_keywords["goto"] = 1;
+  delphi_keywords["of"] = 1;
+  delphi_keywords["then"] = 1;
+  delphi_keywords["destructor"] = 1;
+  delphi_keywords["if"] = 1;
+  delphi_keywords["or"] = 1;
+  delphi_keywords["threadvar"] = 1;
+  delphi_keywords["dispinterface"] = 1;
+  delphi_keywords["implementation"] = 1;
+  delphi_keywords["out"] = 1;
+  delphi_keywords["to"] = 1;
+  delphi_keywords["div"] = 1;
+  delphi_keywords["in"] = 1;
+  delphi_keywords["packed"] = 1;
+  delphi_keywords["try"] = 1;
+  delphi_keywords["do"] = 1;
+  delphi_keywords["inherited"] = 1;
+  delphi_keywords["procedure"] = 1;
+  delphi_keywords["type"] = 1;
+  delphi_keywords["downto"] = 1;
+  delphi_keywords["initialization"] = 1;
+  delphi_keywords["program"] = 1;
+  delphi_keywords["unit"] = 1;
+  delphi_keywords["else"] = 1;
+  delphi_keywords["inline"] = 1;
+  delphi_keywords["property"] = 1;
+  delphi_keywords["until"] = 1;
+  delphi_keywords["private"] = 1;
+  delphi_keywords["protected"] = 1;
+  delphi_keywords["public"] = 1;
+  delphi_keywords["published"] = 1;
+  delphi_keywords["automated"] = 1;
+  delphi_keywords["at"] = 1;
+  delphi_keywords["on"] = 1;
+
+  // reserved/predefined variables and types (lowercase!)
+  delphi_keywords["result"] = 1;
+  delphi_keywords["system"] = 1;
+  delphi_keywords["sysutils"] = 1;
+  delphi_keywords["thrift"] = 1;
+  delphi_keywords["tbytes"] = 1;
+  delphi_keywords["tobject"] = 1;
+  delphi_keywords["tclass"] = 1;
+  delphi_keywords["tinterfacedobject"] = 1;
+  delphi_keywords["ansistring"] = 1;
+  delphi_keywords["string"] = 1;
+  delphi_keywords["boolean"] = 1;
+  delphi_keywords["shortint"] = 1;
+  delphi_keywords["smallint"] = 1;
+  delphi_keywords["integer"] = 1;
+  delphi_keywords["int64"] = 1;
+  delphi_keywords["double"] = 1;
+
+  delphi_reserved_method["create"] = 1;
+  delphi_reserved_method["free"] = 1;
+  delphi_reserved_method["initinstance"] = 1;
+  delphi_reserved_method["cleanupinstance"] = 1;
+  delphi_reserved_method["classtype"] = 1;
+  delphi_reserved_method["classname"] = 1;
+  delphi_reserved_method["classnameis"] = 1;
+  delphi_reserved_method["classparent"] = 1;
+  delphi_reserved_method["classinfo"] = 1;
+  delphi_reserved_method["instancesize"] = 1;
+  delphi_reserved_method["inheritsfrom"] = 1;
+  delphi_reserved_method["methodaddress"] = 1;
+  delphi_reserved_method["methodaddress"] = 1;
+  delphi_reserved_method["methodname"] = 1;
+  delphi_reserved_method["fieldaddress"] = 1;
+  delphi_reserved_method["fieldaddress"] = 1;
+  delphi_reserved_method["getinterface"] = 1;
+  delphi_reserved_method["getinterfaceentry"] = 1;
+  delphi_reserved_method["getinterfacetable"] = 1;
+  delphi_reserved_method["unitname"] = 1;
+  delphi_reserved_method["equals"] = 1;
+  delphi_reserved_method["gethashcode"] = 1;
+  delphi_reserved_method["tostring"] = 1;
+  delphi_reserved_method["safecallexception"] = 1;
+  delphi_reserved_method["afterconstruction"] = 1;
+  delphi_reserved_method["beforedestruction"] = 1;
+  delphi_reserved_method["dispatch"] = 1;
+  delphi_reserved_method["defaulthandler"] = 1;
+  delphi_reserved_method["newinstance"] = 1;
+  delphi_reserved_method["freeinstance"] = 1;
+  delphi_reserved_method["destroy"] = 1;
+  delphi_reserved_method["read"] = 1;
+  delphi_reserved_method["write"] = 1;
+
+  delphi_reserved_method_exception["setinnerexception"] = 1;
+  delphi_reserved_method_exception["setstackinfo"] = 1;
+  delphi_reserved_method_exception["getstacktrace"] = 1;
+  delphi_reserved_method_exception["raisingexception"] = 1;
+  delphi_reserved_method_exception["createfmt"] = 1;
+  delphi_reserved_method_exception["createres"] = 1;
+  delphi_reserved_method_exception["createresfmt"] = 1;
+  delphi_reserved_method_exception["createhelp"] = 1;
+  delphi_reserved_method_exception["createfmthelp"] = 1;
+  delphi_reserved_method_exception["createreshelp"] = 1;
+  delphi_reserved_method_exception["createresfmthelp"] = 1;
+  delphi_reserved_method_exception["getbaseexception"] = 1;
+  delphi_reserved_method_exception["baseexception"] = 1;
+  delphi_reserved_method_exception["helpcontext"] = 1;
+  delphi_reserved_method_exception["innerexception"] = 1;
+  delphi_reserved_method_exception["message"] = 1;
+  delphi_reserved_method_exception["stacktrace"] = 1;
+  delphi_reserved_method_exception["stackinfo"] = 1;
+  delphi_reserved_method_exception["getexceptionstackinfoproc"] = 1;
+  delphi_reserved_method_exception["getstackinfostringproc"] = 1;
+  delphi_reserved_method_exception["cleanupstackinfoproc"] = 1;
+  delphi_reserved_method_exception["raiseouterexception"] = 1;
+  delphi_reserved_method_exception["throwouterexception"] = 1;
+}
+
+void t_delphi_generator::add_delphi_uses_list(string unitname) {
+  vector<std::string>::const_iterator s_iter;
+  bool found = false;
+  for (s_iter = uses_list.begin(); s_iter != uses_list.end(); ++s_iter) {
+    if ((*s_iter) == unitname) {
+      found = true;
+      break;
+    }
+  }
+  if (!found) {
+    uses_list.push_back(unitname);
+  }
+}
+
+void t_delphi_generator::init_generator() {
+  indent_impl_ = 0;
+  namespace_name_ = program_->get_namespace("delphi");
+  has_forward = false;
+  has_enum = false;
+  has_const = false;
+  create_keywords();
+
+  add_delphi_uses_list("Classes");
+  add_delphi_uses_list("SysUtils");
+  add_delphi_uses_list("Generics.Collections");
+  if(async_) {
+    add_delphi_uses_list("System.Threading");
+  }
+
+  add_delphi_uses_list("Thrift");
+  add_delphi_uses_list("Thrift.Utils");
+  add_delphi_uses_list("Thrift.Collections");
+  add_delphi_uses_list("Thrift.Protocol");
+  add_delphi_uses_list("Thrift.Transport");
+  if (register_types_) {
+    add_delphi_uses_list("Thrift.TypeRegistry");
+  }
+
+  init_known_types_list();
+
+  string unitname, nsname;
+  const vector<t_program*>& includes = program_->get_includes();
+  for (size_t i = 0; i < includes.size(); ++i) {
+    unitname = includes[i]->get_name();
+    nsname = includes[i]->get_namespace("delphi");
+    if ("" != nsname) {
+      unitname = normalize_name(nsname);
+    }
+    add_delphi_uses_list(unitname);
+  }
+
+  MKDIR(get_out_dir().c_str());
+}
+
+void t_delphi_generator::close_generator() {
+  std::string unitname = program_name_;
+  if ("" != namespace_name_) {
+    unitname = namespace_name_;
+  }
+
+  for (int i = 0; i < (int)unitname.size(); i++) {
+    if (unitname[i] == ' ') {
+      unitname.replace(i, 1, "_");
+    }
+  }
+
+  unitname = normalize_name(unitname);
+  
+  std::string f_name = get_out_dir() + "/" + unitname + ".pas";
+  ofstream_with_content_based_conditional_update f_all;
+
+  f_all.open(f_name.c_str());
+
+  f_all << autogen_comment() << endl;
+  generate_delphi_doc(f_all, program_);
+  f_all << "unit " << unitname << ";" << endl << endl;
+  f_all << "interface" << endl << endl;
+  f_all << "uses" << endl;
+
+  indent_up();
+
+  vector<std::string>::const_iterator s_iter;
+  for (s_iter = uses_list.begin(); s_iter != uses_list.end(); ++s_iter) {
+    if (s_iter != uses_list.begin()) {
+      f_all << ",";
+      f_all << endl;
+    }
+    indent(f_all) << *s_iter;
+  }
+
+  f_all << ";" << endl << endl;
+
+  indent_down();
+
+  string tmp_unit(unitname);
+  for (int i = 0; i < (int)tmp_unit.size(); i++) {
+    if (tmp_unit[i] == '.') {
+      tmp_unit.replace(i, 1, "_");
+    }
+  }
+
+  f_all << "const" << endl;
+  indent_up();
+  indent(f_all) << "c" << tmp_unit
+                << "_Option_AnsiStr_Binary = " << (ansistr_binary_ ? "True" : "False") << ";"
+                << endl;
+  indent(f_all) << "c" << tmp_unit
+                << "_Option_Register_Types = " << (register_types_ ? "True" : "False") << ";"
+                << endl;
+  indent(f_all) << "c" << tmp_unit
+                << "_Option_ConstPrefix    = " << (constprefix_ ? "True" : "False") << ";" << endl;
+  indent(f_all) << "c" << tmp_unit << "_Option_Events         = " << (events_ ? "True" : "False")
+                << ";" << endl;
+  indent(f_all) << "c" << tmp_unit << "_Option_XmlDoc         = " << (xmldoc_ ? "True" : "False")
+                << ";" << endl;
+  indent_down();
+
+  f_all << endl;
+  f_all << "type" << endl;
+  if (has_forward) {
+    f_all << s_forward_decr.str() << endl;
+  }
+  if (has_enum) {
+    indent(f_all) << endl;
+    indent(f_all) << "{$SCOPEDENUMS ON}" << endl << endl;
+    f_all << s_enum.str();
+    indent(f_all) << "{$SCOPEDENUMS OFF}" << endl << endl;
+  }
+  f_all << s_struct.str();
+  f_all << s_service.str();
+  f_all << s_const.str();
+  f_all << "implementation" << endl << endl;
+  f_all << s_struct_impl.str();
+  f_all << s_service_impl.str();
+  f_all << s_const_impl.str();
+
+  if (register_types_) {
+    f_all << endl;
+    f_all << "// Type factory methods and registration" << endl;
+    f_all << s_type_factory_funcs.str();
+    f_all << "procedure RegisterTypeFactories;" << endl;
+    f_all << "begin" << endl;
+    f_all << s_type_factory_registration.str();
+    f_all << "end;" << endl;
+  }
+  f_all << endl;
+
+  string constants_class = make_constants_classname();
+
+  f_all << "initialization" << endl;
+  if (has_const) {
+    f_all << "{$IF CompilerVersion < 21.0}  // D2010" << endl;
+    f_all << "  " << constants_class.c_str() << "_Initialize;" << endl;
+    f_all << "{$IFEND}" << endl;
+  }
+  if (register_types_) {
+    f_all << "  RegisterTypeFactories;" << endl;
+  }
+  f_all << endl;
+
+  f_all << "finalization" << endl;
+  if (has_const) {
+    f_all << "{$IF CompilerVersion < 21.0}  // D2010" << endl;
+    f_all << "  " << constants_class.c_str() << "_Finalize;" << endl;
+    f_all << "{$IFEND}" << endl;
+  }
+  f_all << endl << endl;
+
+  f_all << "end." << endl;
+  f_all.close();
+
+  if (!typedefs_pending.empty()) {
+    pwarning(0, "%d typedefs with unresolved type references left:\n", typedefs_pending.size());
+    for (std::list<t_typedef*>::iterator iter = typedefs_pending.begin();
+         typedefs_pending.end() != iter;
+         ++iter) {
+      pwarning(0, "- %s\n", (*iter)->get_symbolic().c_str());
+    }
+  }
+}
+
+void t_delphi_generator::delphi_type_usings(ostream& out) {
+  indent_up();
+  indent(out) << "Classes, SysUtils, Generics.Collections, Thrift.Collections, Thrift.Protocol,"
+              << endl;
+  indent(out) << "Thrift.Transport;" << endl << endl;
+  indent_down();
+}
+
+void t_delphi_generator::generate_forward_declaration(t_struct* tstruct) {
+  // Forward declare struct def
+  has_forward = true;
+  pverbose("forward declaration of %s\n", type_name(tstruct).c_str());
+
+  string what = tstruct->is_xception() ? "class" : "interface";
+
+  indent_up();
+  indent(s_forward_decr) << type_name(tstruct, tstruct->is_xception(), true) << " = " << what << ";"
+                         << endl;
+  indent_down();
+
+  add_defined_type(tstruct);
+}
+
+void t_delphi_generator::generate_typedef(t_typedef* ttypedef) {
+  t_type* type = ttypedef->get_type();
+
+  // write now or save for later?
+  if (!is_fully_defined_type(type)) {
+    pverbose("typedef %s: unresolved dependencies found\n", type_name(ttypedef).c_str());
+    typedefs_pending.push_back(ttypedef);
+    return;
+  }
+
+  indent_up();
+  generate_delphi_doc(s_struct, ttypedef);
+  indent(s_struct) << type_name(ttypedef) << " = ";
+
+  // commented out: the benefit is not big enough to risk breaking existing code
+  // bool container = type->is_list() || type->is_map() || type->is_set();
+  // if( ! container)
+  //  s_struct << "type ";  //the "type A = type B" syntax leads to E2574 with generics
+
+  s_struct << type_name(ttypedef->get_type()) << ";" << endl << endl;
+  indent_down();
+
+  add_defined_type(ttypedef);
+}
+
+bool t_delphi_generator::is_fully_defined_type(t_type* ttype) {
+  if ((NULL != ttype->get_program()) && (ttype->get_program() != program_)) {
+    t_scope* scope = ttype->get_program()->scope();
+    if (NULL != scope->get_type(ttype->get_name())) {
+      // printf("type %s found in included scope %s\n", ttype->get_name().c_str(),
+      // ttype->get_program()->get_name().c_str());
+      return true;
+    }
+  }
+
+  if (ttype->is_typedef()) {
+    return (1 == types_known[type_name(ttype)]);
+  }
+
+  if (ttype->is_base_type()) {
+    return (1 == types_known[base_type_name((t_base_type*)ttype)]);
+  } else if (ttype->is_enum()) {
+    return true; // enums are written first, before all other types
+  } else if (ttype->is_map()) {
+    t_map* tmap = (t_map*)ttype;
+    return is_fully_defined_type(tmap->get_key_type())
+           && is_fully_defined_type(tmap->get_val_type());
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*)ttype;
+    return is_fully_defined_type(tset->get_elem_type());
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*)ttype;
+    return is_fully_defined_type(tlist->get_elem_type());
+  }
+
+  return (1 == types_known[type_name(ttype)]);
+}
+
+void t_delphi_generator::add_defined_type(t_type* ttype) {
+  // mark as known type
+  types_known[type_name(ttype)] = 1;
+
+  // check all pending typedefs
+  std::list<t_typedef*>::iterator iter;
+  bool more = true;
+  while (more && (!typedefs_pending.empty())) {
+    more = false;
+
+    for (iter = typedefs_pending.begin(); typedefs_pending.end() != iter; ++iter) {
+      t_typedef* ttypedef = (*iter);
+      if (is_fully_defined_type(ttypedef->get_type())) {
+        pverbose("typedef %s: all pending references are now resolved\n",
+                 type_name(ttypedef).c_str());
+        typedefs_pending.erase(iter);
+        generate_typedef(ttypedef);
+        more = true;
+        break;
+      }
+    }
+  }
+}
+
+void t_delphi_generator::init_known_types_list() {
+  // known base types
+  types_known[type_name(g_type_string)] = 1;
+  types_known[type_name(g_type_binary)] = 1;
+  types_known[type_name(g_type_bool)] = 1;
+  types_known[type_name(g_type_i8)] = 1;
+  types_known[type_name(g_type_i16)] = 1;
+  types_known[type_name(g_type_i32)] = 1;
+  types_known[type_name(g_type_i64)] = 1;
+  types_known[type_name(g_type_double)] = 1;
+}
+
+void t_delphi_generator::generate_enum(t_enum* tenum) {
+  has_enum = true;
+  indent_up();
+  generate_delphi_doc(s_enum, tenum);
+  indent(s_enum) << type_name(tenum, true, true) << " = "
+                 << "(" << endl;
+  indent_up();
+  vector<t_enum_value*> constants = tenum->get_constants();
+  if (constants.empty()) {
+    indent(s_enum) << "dummy = 0  // empty enums are not allowed";
+  } else {
+    vector<t_enum_value*>::iterator c_iter;
+    for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+      int value = (*c_iter)->get_value();
+      if (c_iter != constants.begin()) {
+        s_enum << ",";
+        s_enum << endl;
+      }
+      generate_delphi_doc(s_enum, *c_iter);
+      indent(s_enum) << normalize_name((*c_iter)->get_name()) << " = " << value;
+    }
+  }
+  s_enum << endl;
+  indent_down();
+  indent(s_enum) << ");" << endl << endl;
+  indent_down();
+}
+
+std::string t_delphi_generator::make_valid_delphi_identifier(std::string const& fromName) {
+  std::string str = fromName;
+  if (str.empty()) {
+    return str;
+  }
+
+  // tests rely on this
+  assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
+
+  // if the first letter is a number, we add an additional underscore in front of it
+  char c = str.at(0);
+  if (('0' <= c) && (c <= '9')) {
+    str = "_" + str;
+  }
+
+  // following chars: letter, number or underscore
+  for (size_t i = 0; i < str.size(); ++i) {
+    c = str.at(i);
+    if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9'))
+        && ('_' != c)) {
+      str.replace(i, 1, "_");
+    }
+  }
+
+  return str;
+}
+
+std::string t_delphi_generator::make_constants_classname() {
+  if (constprefix_) {
+    return make_valid_delphi_identifier("T" + program_name_ + "Constants");
+  } else {
+    return "TConstants"; // compatibility
+  }
+}
+
+void t_delphi_generator::generate_consts(std::vector<t_const*> consts) {
+  if (consts.empty()) {
+    return;
+  }
+
+  has_const = true;
+  string constants_class = make_constants_classname();
+
+  indent_up();
+  indent(s_const) << constants_class.c_str() << " = class" << endl;
+  indent(s_const) << "private" << endl;
+  indent_up();
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    if (const_needs_var((*c_iter)->get_type())) {
+      print_private_field(s_const,
+                          normalize_name((*c_iter)->get_name()),
+                          (*c_iter)->get_type(),
+                          (*c_iter)->get_value());
+    }
+  }
+  indent_down();
+  indent(s_const) << "public" << endl;
+  indent_up();
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    generate_delphi_doc(s_const, *c_iter);
+    print_const_prop(s_const,
+                     normalize_name((*c_iter)->get_name()),
+                     (*c_iter)->get_type(),
+                     (*c_iter)->get_value());
+  }
+  indent(s_const) << "{$IF CompilerVersion >= 21.0}" << endl;
+  indent(s_const) << "class constructor Create;" << endl;
+  indent(s_const) << "class destructor Destroy;" << endl;
+  indent(s_const) << "{$IFEND}" << endl;
+  indent_down();
+  indent(s_const) << "end;" << endl << endl;
+  indent_down();
+
+  std::ostringstream vars, code;
+
+  indent_up_impl();
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    initialize_field(vars,
+                     code,
+                     "F" + prop_name((*c_iter)->get_name()),
+                     (*c_iter)->get_type(),
+                     (*c_iter)->get_value());
+  }
+  indent_down_impl();
+
+  indent_impl(s_const_impl) << "{$IF CompilerVersion >= 21.0}" << endl;
+  indent_impl(s_const_impl) << "class constructor " << constants_class.c_str() << ".Create;"
+                            << endl;
+
+  if (!vars.str().empty()) {
+    indent_impl(s_const_impl) << "var" << endl;
+    s_const_impl << vars.str();
+  }
+  indent_impl(s_const_impl) << "begin" << endl;
+  if (!code.str().empty()) {
+    s_const_impl << code.str();
+  }
+  indent_impl(s_const_impl) << "end;" << endl << endl;
+  indent_impl(s_const_impl) << "class destructor " << constants_class.c_str() << ".Destroy;"
+                            << endl;
+  indent_impl(s_const_impl) << "begin" << endl;
+  indent_up_impl();
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    if (const_needs_var((*c_iter)->get_type())) {
+      finalize_field(s_const_impl,
+                     normalize_name((*c_iter)->get_name()),
+                     (*c_iter)->get_type(),
+                     (*c_iter)->get_value());
+    }
+  }
+  indent_impl(s_const_impl) << "inherited;" << endl;
+  indent_down_impl();
+  indent_impl(s_const_impl) << "end;" << endl;
+  indent_impl(s_const_impl) << "{$ELSE}" << endl;
+
+  vars.str("");
+  code.str("");
+
+  indent_up_impl();
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    if (const_needs_var((*c_iter)->get_type())) {
+      initialize_field(vars,
+                       code,
+                       constants_class + ".F" + prop_name((*c_iter)->get_name()),
+                       (*c_iter)->get_type(),
+                       (*c_iter)->get_value());
+    }
+  }
+  indent_down_impl();
+
+  indent_impl(s_const_impl) << "procedure " << constants_class.c_str() << "_Initialize;" << endl;
+  if (!vars.str().empty()) {
+    indent_impl(s_const_impl) << "var" << endl;
+    s_const_impl << vars.str();
+  }
+  indent_impl(s_const_impl) << "begin" << endl;
+  if (!code.str().empty()) {
+    s_const_impl << code.str();
+  }
+  indent_impl(s_const_impl) << "end;" << endl << endl;
+
+  indent_impl(s_const_impl) << "procedure " << constants_class.c_str() << "_Finalize;" << endl;
+  indent_impl(s_const_impl) << "begin" << endl;
+  indent_up_impl();
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    finalize_field(s_const_impl,
+                   normalize_name((*c_iter)->get_name()),
+                   (*c_iter)->get_type(),
+                   (*c_iter)->get_value(),
+                   constants_class);
+  }
+  indent_down_impl();
+  indent_impl(s_const_impl) << "end;" << endl;
+  indent_impl(s_const_impl) << "{$IFEND}" << endl << endl;
+}
+
+void t_delphi_generator::print_const_def_value(std::ostream& vars,
+                                               std::ostream& out,
+                                               string name,
+                                               t_type* type,
+                                               t_const_value* value,
+                                               string cls_nm) {
+
+  string cls_prefix;
+
+  if (cls_nm == "") {
+    cls_prefix = "";
+  } else {
+    cls_prefix = cls_nm + ".";
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::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();
+      }
+      string val = render_const_value(vars, out, name, field_type, v_iter->second);
+      indent_impl(out) << cls_prefix << normalize_name(name) << "."
+                       << prop_name(v_iter->first->get_string(), type->is_xception())
+                       << " := " << val << ";" << endl;
+    }
+  } 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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(vars, out, name, ktype, v_iter->first);
+      string val = render_const_value(vars, out, name, vtype, v_iter->second);
+      indent_impl(out) << cls_prefix << normalize_name(name) << "[" << key << "]"
+                       << " := " << val << ";" << endl;
+    }
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(vars, out, name, etype, *v_iter);
+      indent_impl(out) << cls_prefix << normalize_name(name) << ".Add(" << val << ");" << endl;
+    }
+  }
+}
+
+void t_delphi_generator::print_private_field(std::ostream& out,
+                                             string name,
+                                             t_type* type,
+                                             t_const_value* value) {
+  (void)value;
+  indent(out) << "class var F" << name << ": " << type_name(type) << ";" << endl;
+}
+
+bool t_delphi_generator::const_needs_var(t_type* type) {
+  t_type* truetype = type;
+  while (truetype->is_typedef()) {
+    truetype = ((t_typedef*)truetype)->get_type();
+  }
+  return (!truetype->is_base_type());
+}
+
+void t_delphi_generator::print_const_prop(std::ostream& out,
+                                          string name,
+                                          t_type* type,
+                                          t_const_value* value) {
+  (void)value;
+  if (const_needs_var(type)) {
+    indent(out) << "class property " << name << ": " << type_name(type) << " read F" << name << ";"
+                << endl;
+  } else {
+    std::ostringstream vars; // dummy
+    string v2 = render_const_value(vars, out, name, type, value);
+    indent(out) << "const " << name << " = " << v2 << ";" << endl;
+  }
+}
+
+void t_delphi_generator::print_const_value(std::ostream& vars,
+                                           std::ostream& out,
+                                           string name,
+                                           t_type* type,
+                                           t_const_value* value) {
+  t_type* truetype = type;
+  while (truetype->is_typedef()) {
+    truetype = ((t_typedef*)truetype)->get_type();
+  }
+
+  if (truetype->is_base_type()) {
+    // already done
+    // string v2 = render_const_value( vars, out, name, type, value);
+    // indent_impl(out) << name << " := " << v2 << ";" << endl;
+  } else if (truetype->is_enum()) {
+    indent_impl(out) << name << " := " << type_name(type) << "." << value->get_identifier_name()
+                     << ";" << endl;
+  } else {
+    string typname;
+    typname = type_name(truetype, true, false, type->is_xception(), type->is_xception());
+    indent_impl(out) << name << " := " << typname << ".Create;" << endl;
+    print_const_def_value(vars, out, name, truetype, value);
+  }
+}
+
+void t_delphi_generator::initialize_field(std::ostream& vars,
+                                          std::ostream& out,
+                                          string name,
+                                          t_type* type,
+                                          t_const_value* value) {
+  print_const_value(vars, out, name, type, value);
+}
+
+void t_delphi_generator::finalize_field(std::ostream& out,
+                                        string name,
+                                        t_type* type,
+                                        t_const_value* value,
+                                        string cls_nm) {
+  (void)out;
+  (void)name;
+  (void)type;
+  (void)value;
+  (void)cls_nm;
+}
+
+string t_delphi_generator::render_const_value(ostream& vars,
+                                              ostream& out,
+                                              string name,
+                                              t_type* type,
+                                              t_const_value* value) {
+  (void)name;
+
+  t_type* truetype = type;
+  while (truetype->is_typedef()) {
+    truetype = ((t_typedef*)truetype)->get_type();
+  }
+
+  std::ostringstream render;
+
+  if (truetype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)truetype)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      render << "'" << get_escaped_string(value) << "'";
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "True" : "False");
+      break;
+    case t_base_type::TYPE_I8:
+      render << "ShortInt( " << value->get_integer() << ")";
+      break;
+    case t_base_type::TYPE_I16:
+      render << "SmallInt( " << value->get_integer() << ")";
+      break;
+    case t_base_type::TYPE_I32:
+      render << "LongInt( " << value->get_integer() << ")";
+      break;
+    case t_base_type::TYPE_I64:
+      render << "Int64( " << value->get_integer() << ")";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << value->get_integer() << ".0"; // make it a double constant by adding ".0"
+      } else {
+        render << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (truetype->is_enum()) {
+    render << type_name(type, false) << "." << value->get_identifier_name();
+  } else {
+    string t = tmp("tmp");
+    vars << "  " << t << " : " << type_name(type) << ";" << endl;
+    print_const_value(vars, out, t, type, value);
+    render << t;
+  }
+
+  return render.str();
+}
+
+void t_delphi_generator::generate_struct(t_struct* tstruct) {
+  generate_delphi_struct(tstruct, false);
+}
+
+void t_delphi_generator::generate_xception(t_struct* txception) {
+  generate_delphi_struct(txception, true);
+}
+
+void t_delphi_generator::generate_delphi_struct(t_struct* tstruct, bool is_exception) {
+  indent_up();
+  generate_delphi_struct_definition(s_struct, tstruct, is_exception);
+  indent_down();
+
+  add_defined_type(tstruct);
+
+  generate_delphi_struct_impl(s_struct_impl, "", tstruct, is_exception);
+  if (register_types_) {
+    generate_delphi_struct_type_factory(s_type_factory_funcs, "", tstruct, is_exception);
+    generate_delphi_struct_type_factory_registration(s_type_factory_registration,
+                                                     "",
+                                                     tstruct,
+                                                     is_exception);
+  }
+}
+
+void t_delphi_generator::generate_delphi_struct_impl(ostream& out,
+                                                     string cls_prefix,
+                                                     t_struct* tstruct,
+                                                     bool is_exception,
+                                                     bool is_result,
+                                                     bool is_x_factory) {
+
+  if (is_exception && (!is_x_factory)) {
+    generate_delphi_struct_impl(out, cls_prefix, tstruct, is_exception, is_result, true);
+  }
+
+  string cls_nm;
+
+  string exception_factory_name;
+
+  if (is_exception) {
+    exception_factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory";
+  }
+
+  if (is_exception) {
+    cls_nm = type_name(tstruct, true, (!is_x_factory), is_x_factory, true);
+  } else {
+    cls_nm = type_name(tstruct, true, false);
+  }
+
+  std::ostringstream vars, code;
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  indent_up_impl();
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = (*m_iter)->get_type();
+    while (t->is_typedef()) {
+      t = ((t_typedef*)t)->get_type();
+    }
+    if ((*m_iter)->get_value() != NULL) {
+      initialize_field(vars,
+                       code,
+                       "F" + prop_name((*m_iter)->get_name(), is_exception),
+                       t,
+                       (*m_iter)->get_value());
+      if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
+        indent_impl(code) << "F__isset_" << prop_name((*m_iter), is_exception) << " := True;"
+                          << endl;
+      }
+    }
+  }
+  indent_down_impl();
+
+  indent_impl(out) << "constructor " << cls_prefix << cls_nm << "."
+                   << "Create;" << endl;
+
+  if (!vars.str().empty()) {
+    out << "var" << endl;
+    out << vars.str();
+  }
+
+  indent_impl(out) << "begin" << endl;
+  indent_up_impl();
+  if (is_exception && (!is_x_factory)) {
+    indent_impl(out) << "inherited Create('');" << endl;
+  } else {
+    indent_impl(out) << "inherited;" << endl;
+  }
+
+  if (!code.str().empty()) {
+    out << code.str();
+  }
+
+  indent_down_impl();
+  indent_impl(out) << "end;" << endl << endl;
+
+  if ((members.size() > 0) && is_exception && (!is_x_factory)) {
+    indent_impl(out) << "constructor " << cls_prefix << cls_nm << "."
+                     << "Create(" << constructor_argument_list(tstruct, indent_impl()) << ");"
+                     << endl;
+    indent_impl(out) << "begin" << endl;
+    indent_up_impl();
+    indent_impl(out) << "Create;" << endl;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      string propname = prop_name((*m_iter)->get_name(), is_exception);
+      string param_name = constructor_param_name((*m_iter)->get_name());
+      indent_impl(out) << propname << " := " << param_name << ";" << endl;
+    }
+    indent_impl(out) << "UpdateMessageProperty;" << endl;
+    indent_down_impl();
+    indent_impl(out) << "end;" << endl << endl;
+  }
+
+  indent_impl(out) << "destructor " << cls_prefix << cls_nm << "."
+                   << "Destroy;" << endl;
+  indent_impl(out) << "begin" << endl;
+  indent_up_impl();
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = (*m_iter)->get_type();
+    while (t->is_typedef()) {
+      t = ((t_typedef*)t)->get_type();
+    }
+    finalize_field(out, prop_name(*m_iter, is_exception), t, (*m_iter)->get_value());
+  }
+
+  indent_impl(out) << "inherited;" << endl;
+  indent_down_impl();
+  indent_impl(out) << "end;" << endl << endl;
+
+  if (is_exception && (!is_x_factory)) {
+    indent_impl(out) << "function " << cls_prefix << cls_nm << "." << exception_factory_name
+                     << ": I" << exception_factory_name << ";" << endl;
+    indent_impl(out) << "begin" << endl;
+    indent_up_impl();
+    indent_impl(out) << "if F" << exception_factory_name << " = nil" << endl;
+    indent_impl(out) << "then F" << exception_factory_name << " := T" << exception_factory_name << "Impl.Create;" << endl;
+    indent_impl(out) << endl;
+    indent_impl(out) << "result := F" << exception_factory_name << ";" << endl;
+    indent_down_impl();
+    indent_impl(out) << "end;" << endl << endl;
+  }
+
+  if (tstruct->is_union()) {
+    indent_impl(out) << "procedure " << cls_prefix << cls_nm << "."
+                     << "ClearUnionValues;" << endl;
+    indent_impl(out) << "begin" << endl;
+    indent_up_impl();
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = (*m_iter)->get_type();
+      while (t->is_typedef()) {
+        t = ((t_typedef*)t)->get_type();
+      }
+
+      generate_delphi_clear_union_value(out,
+                                        cls_prefix,
+                                        cls_nm,
+                                        t,
+                                        *m_iter,
+                                        "F",
+                                        is_exception,
+                                        tstruct->is_union(),
+                                        is_x_factory,
+                                        exception_factory_name);
+    }
+    indent_down_impl();
+    indent_impl(out) << "end;" << endl << endl;
+  }
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = (*m_iter)->get_type();
+    while (t->is_typedef()) {
+      t = ((t_typedef*)t)->get_type();
+    }
+    generate_delphi_property_reader_impl(out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception);
+    generate_delphi_property_writer_impl(out,
+                                         cls_prefix,
+                                         cls_nm,
+                                         t,
+                                         *m_iter,
+                                         "F",
+                                         is_exception,
+                                         tstruct->is_union(),
+                                         is_x_factory,
+                                         exception_factory_name);
+    if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
+      generate_delphi_isset_reader_impl(out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception);
+    }
+  }
+
+  if ((!is_exception) || is_x_factory) {
+    generate_delphi_struct_reader_impl(out, cls_prefix, tstruct, is_exception);
+    if (is_result) {
+      generate_delphi_struct_result_writer_impl(out, cls_prefix, tstruct, is_exception);
+    } else {
+      generate_delphi_struct_writer_impl(out, cls_prefix, tstruct, is_exception);
+    }
+  }
+  generate_delphi_struct_tostring_impl(out, cls_prefix, tstruct, is_exception, is_x_factory);
+
+  if (is_exception && is_x_factory) {
+    generate_delphi_create_exception_impl(out, cls_prefix, tstruct, is_exception);
+  }
+}
+
+void t_delphi_generator::print_delphi_struct_type_factory_func(ostream& out, t_struct* tstruct) {
+  string struct_intf_name = type_name(tstruct);
+  out << "Create_";
+  out << struct_intf_name;
+  out << "_Impl";
+}
+
+void t_delphi_generator::generate_delphi_struct_type_factory(ostream& out,
+                                                             string cls_prefix,
+                                                             t_struct* tstruct,
+                                                             bool is_exception,
+                                                             bool is_result,
+                                                             bool is_x_factory) {
+  (void)cls_prefix;
+  if (is_exception)
+    return;
+  if (is_result)
+    return;
+  if (is_x_factory)
+    return;
+
+  string struct_intf_name = type_name(tstruct);
+  string cls_nm = type_name(tstruct, true, false);
+
+  out << "function ";
+  print_delphi_struct_type_factory_func(out, tstruct);
+  out << ": ";
+  out << struct_intf_name;
+  out << ";" << endl;
+  out << "begin" << endl;
+  indent_up();
+  indent(out) << "Result := " << cls_nm << ".Create;" << endl;
+  indent_down();
+  out << "end;" << endl << endl;
+}
+
+void t_delphi_generator::generate_delphi_struct_type_factory_registration(ostream& out,
+                                                                          string cls_prefix,
+                                                                          t_struct* tstruct,
+                                                                          bool is_exception,
+                                                                          bool is_result,
+                                                                          bool is_x_factory) {
+  (void)cls_prefix;
+  if (is_exception)
+    return;
+  if (is_result)
+    return;
+  if (is_x_factory)
+    return;
+
+  string struct_intf_name = type_name(tstruct);
+
+  indent(out) << "  TypeRegistry.RegisterTypeFactory<" << struct_intf_name << ">(";
+  print_delphi_struct_type_factory_func(out, tstruct);
+  out << ");";
+  out << endl;
+}
+
+void t_delphi_generator::generate_delphi_struct_definition(ostream& out,
+                                                           t_struct* tstruct,
+                                                           bool is_exception,
+                                                           bool in_class,
+                                                           bool is_result,
+                                                           bool is_x_factory) {
+  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+  string struct_intf_name;
+  string struct_name;
+  string isset_name;
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  string exception_factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory";
+
+  if (is_exception) {
+    struct_intf_name = type_name(tstruct, false, false, true);
+  } else {
+    struct_intf_name = type_name(tstruct);
+  }
+
+  if (is_exception) {
+    struct_name = type_name(tstruct, true, (!is_x_factory), is_x_factory);
+  } else {
+    struct_name = type_name(tstruct, true);
+  }
+
+  if ((!is_exception) || is_x_factory) {
+
+    generate_delphi_doc(out, tstruct);
+    indent(out) << struct_intf_name << " = interface(IBase)" << endl;
+    indent_up();
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      generate_delphi_property_reader_definition(out, *m_iter, is_exception);
+      generate_delphi_property_writer_definition(out, *m_iter, is_exception);
+    }
+
+    if (is_x_factory) {
+      out << endl;
+      indent(out) << "// Create Exception Object" << endl;
+      indent(out) << "function CreateException: " << type_name(tstruct, true, true) << ";" << endl;
+    }
+
+    if (members.size() > 0) {
+      out << endl;
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        generate_property(out, *m_iter, true, is_exception);
+      }
+    }
+
+    if (members.size() > 0) {
+      out << endl;
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
+          generate_delphi_isset_reader_definition(out, *m_iter, is_exception);
+        }
+      }
+    }
+
+    if (members.size() > 0) {
+      out << endl;
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
+          isset_name = "__isset_" + prop_name(*m_iter, is_exception);
+          indent(out) << "property " << isset_name << ": System.Boolean read Get" << isset_name << ";"
+                      << endl;
+        }
+      }
+    }
+
+    indent_down();
+    indent(out) << "end;" << endl << endl;
+  }
+
+  generate_delphi_doc(out, tstruct);
+  indent(out) << struct_name << " = ";
+  if (is_final) {
+    out << "sealed ";
+  }
+  out << "class(";
+  if (is_exception && (!is_x_factory)) {
+    out << "TException";
+  } else {
+    out << "TInterfacedObject, IBase, " << struct_intf_name;
+  }
+  out << ")" << endl;
+
+  if (is_exception && (!is_x_factory)) {
+    indent(out) << "public" << endl;
+    indent_up();
+    indent(out) << "type" << endl;
+    indent_up();
+    generate_delphi_struct_definition(out, tstruct, is_exception, in_class, is_result, true);
+    indent_down();
+    indent_down();
+  }
+
+  indent(out) << "private" << endl;
+  indent_up();
+
+  if (is_exception && (!is_x_factory)) {
+    indent(out) << "F" << exception_factory_name << " :" << struct_intf_name << ";" << endl << endl;
+  }
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) << declare_field(*m_iter, false, "F", is_exception) << endl;
+  }
+
+  if (members.size() > 0) {
+    indent(out) << endl;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
+        isset_name = "F__isset_" + prop_name(*m_iter, is_exception);
+        indent(out) << isset_name << ": System.Boolean;" << endl;
+      }
+    }
+  }
+
+  indent(out) << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    generate_delphi_property_reader_definition(out, *m_iter, is_exception);
+    generate_delphi_property_writer_definition(out, *m_iter, is_exception);
+  }
+
+  if (tstruct->is_union()) {
+    out << endl;
+    indent(out) << "// Clear values(for union's property setter)" << endl;
+    indent(out) << "procedure ClearUnionValues;" << endl;
+  }
+
+  if (members.size() > 0) {
+    out << endl;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
+        isset_name = "__isset_" + prop_name(*m_iter, is_exception);
+        indent(out) << "function Get" << isset_name << ": System.Boolean;" << endl;
+      }
+    }
+  }
+
+  indent_down();
+
+  indent(out) << "public" << endl;
+  indent_up();
+
+  if ((members.size() > 0) && is_exception && (!is_x_factory)) {
+    indent(out) << "constructor Create; overload;" << endl;
+    indent(out) << "constructor Create(" << constructor_argument_list(tstruct, indent())
+                << "); overload;" << endl;
+  } else {
+    indent(out) << "constructor Create;" << endl;
+  }
+
+  indent(out) << "destructor Destroy; override;" << endl;
+
+  out << endl;
+  indent(out) << "function ToString: string; override;" << endl;
+
+  if (is_exception && (!is_x_factory)) {
+    out << endl;
+    indent(out) << "// Exception Factory" << endl;
+    indent(out) << "function " << exception_factory_name << ": " << struct_intf_name << ";" << endl;
+  }
+
+  if ((!is_exception) || is_x_factory) {
+    out << endl;
+    indent(out) << "// IBase" << endl;
+    indent(out) << "procedure Read( const iprot: IProtocol);" << endl;
+    indent(out) << "procedure Write( const oprot: IProtocol);" << endl;
+  }
+
+  if (is_exception && is_x_factory) {
+    out << endl;
+    indent(out) << "// Create Exception Object" << endl;
+    indent(out) << "function CreateException: " << type_name(tstruct, true, true) << ";" << endl;
+  }
+
+  if (members.size() > 0) {
+    out << endl;
+    indent(out) << "// Properties" << endl;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      generate_property(out, *m_iter, true, is_exception);
+    }
+  }
+
+  if (members.size() > 0) {
+    out << endl;
+    indent(out) << "// isset" << endl;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
+        isset_name = "__isset_" + prop_name(*m_iter, is_exception);
+        indent(out) << "property " << isset_name << ": System.Boolean read Get" << isset_name << ";"
+                    << endl;
+      }
+    }
+  }
+
+  indent_down();
+  indent(out) << "end;" << endl << endl;
+}
+
+void t_delphi_generator::generate_service(t_service* tservice) {
+  indent_up();
+  generate_delphi_doc(s_service, tservice);
+  indent(s_service) << normalize_clsnm(service_name_, "T") << " = class" << endl;
+  indent(s_service) << "public" << endl;
+  indent_up();
+  indent(s_service) << "type" << endl;
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+  indent_down();
+  indent_down();
+  indent(s_service) << "end;" << endl;
+  indent(s_service) << endl;
+  indent_down();
+}
+
+void t_delphi_generator::generate_service_interface(t_service* tservice) {
+  generate_service_interface(tservice,false);
+  if(async_) {
+    generate_service_interface(tservice,true);
+  }
+}
+
+
+void t_delphi_generator::generate_service_interface(t_service* tservice, bool for_async) {
+  string extends = "";
+  string extends_iface = "";
+  string iface_name = for_async ? "IAsync" : "Iface";
+
+  indent_up();
+
+  generate_delphi_doc(s_service, tservice);
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends(), true, true);
+    extends_iface = extends + "." + iface_name;
+    generate_delphi_doc(s_service, tservice);
+    indent(s_service) << iface_name << " = interface(" << extends_iface << ")" << endl;
+  } else {
+    indent(s_service) << iface_name << " = interface" << endl;
+  }
+
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_delphi_doc(s_service, *f_iter);
+    indent(s_service) << function_signature(*f_iter, for_async) << endl;
+  }
+  indent_down();
+  indent(s_service) << "end;" << endl << endl;
+
+  indent_down();
+}
+
+void t_delphi_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_delphi_struct_definition(s_service, ts, false, true);
+    generate_delphi_struct_impl(s_service_impl,
+                                normalize_clsnm(service_name_, "T") + ".",
+                                ts,
+                                false);
+    generate_function_helpers(*f_iter);
+  }
+}
+
+void t_delphi_generator::generate_service_client(t_service* tservice) {
+  indent_up();
+  string extends = "";
+  string extends_client = "TInterfacedObject";
+  string implements = async_ ? "Iface, IAsync" : "Iface";
+
+  generate_delphi_doc(s_service, tservice);
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends(), true, true);
+    extends_client = extends + ".TClient";
+  }
+  indent(s_service) << "TClient = class( " << extends_client << ", " << implements << ")" << endl;
+
+  indent(s_service) << "public" << endl;
+  indent_up();
+
+  indent(s_service) << "constructor Create( prot: IProtocol); overload;" << endl;
+
+  indent_impl(s_service_impl) << "constructor " << normalize_clsnm(service_name_, "T")
+                              << ".TClient.Create( prot: IProtocol);" << endl;
+  indent_impl(s_service_impl) << "begin" << endl;
+  indent_up_impl();
+  indent_impl(s_service_impl) << "Create( prot, prot );" << endl;
+  indent_down_impl();
+  indent_impl(s_service_impl) << "end;" << endl << endl;
+
+  indent(s_service)
+      << "constructor Create( const iprot: IProtocol; const oprot: IProtocol); overload;" << endl;
+
+  indent_impl(s_service_impl) << "constructor " << normalize_clsnm(service_name_, "T")
+                              << ".TClient.Create( const iprot: IProtocol; const oprot: IProtocol);"
+                              << endl;
+  indent_impl(s_service_impl) << "begin" << endl;
+  indent_up_impl();
+  indent_impl(s_service_impl) << "inherited Create;" << endl;
+  indent_impl(s_service_impl) << "iprot_ := iprot;" << endl;
+  indent_impl(s_service_impl) << "oprot_ := oprot;" << endl;
+  indent_down_impl();
+  indent_impl(s_service_impl) << "end;" << endl << endl;
+
+  indent_down();
+
+  if (extends.empty()) {
+    indent(s_service) << "protected" << endl;
+    indent_up();
+    indent(s_service) << "iprot_: IProtocol;" << endl;
+    indent(s_service) << "oprot_: IProtocol;" << endl;
+    indent(s_service) << "seqid_: System.Integer;" << endl;
+    indent_down();
+
+    indent(s_service) << "public" << endl;
+    indent_up();
+    indent(s_service) << "property InputProtocol: IProtocol read iprot_;" << endl;
+    indent(s_service) << "property OutputProtocol: IProtocol read oprot_;" << endl;
+    indent_down();
+  }
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+
+  indent(s_service) << "protected" << endl;
+  indent_up();
+
+  indent(s_service) << "// Iface" << endl;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string funname = (*f_iter)->get_name();
+    generate_delphi_doc(s_service, *f_iter);
+    indent(s_service) << function_signature(*f_iter, false) << endl;
+  }
+
+  if( async_) {
+    indent(s_service) << endl;
+    indent(s_service) << "// IAsync" << endl;
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      string funname = (*f_iter)->get_name();
+      generate_delphi_doc(s_service, *f_iter);
+      indent(s_service) << function_signature(*f_iter, true) << endl;
+    }
+  }
+
+  indent_down();
+
+  indent(s_service) << "public" << endl;
+  indent_up();
+
+  string full_cls = normalize_clsnm(service_name_, "T") + ".TClient";
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string funname = (*f_iter)->get_name();
+
+    vector<t_field*>::const_iterator fld_iter;
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const vector<t_field*>& fields = arg_struct->get_members();
+
+    // one for sync only, two for async+sync
+    int mode = async_ ? 1 : 0;
+    while( mode >= 0) {
+      bool for_async = (mode != 0);
+      mode--;
+
+      indent_impl(s_service_impl) << function_signature(*f_iter, for_async, full_cls) << endl;
+      indent_impl(s_service_impl) << "begin" << endl;
+      indent_up_impl();
+
+      t_type* ttype = (*f_iter)->get_returntype();
+      if( for_async) {
+        if (is_void(ttype)) {
+           // Delphi forces us to specify a type with IFuture<T>, so we use Integer=0 for void methods
+          indent_impl(s_service_impl) << "result := TTask.Future<System.Integer>(function: System.Integer" << endl;
+        } else {
+          string rettype = type_name(ttype, false, true, false, true);
+          indent_impl(s_service_impl) << "result := TTask.Future<" << rettype << ">(function: " << rettype << endl;
+        }
+        indent_impl(s_service_impl) << "begin" << endl;
+        indent_up_impl();
+      }
+
+      indent_impl(s_service_impl) << "send_" << funname << "(";
+
+      bool first = true;
+      for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+        if (first) {
+          first = false;
+        } else {
+          s_service_impl << ", ";
+        }
+        s_service_impl << normalize_name((*fld_iter)->get_name());
+      }
+      s_service_impl << ");" << endl;
+
+      if (!(*f_iter)->is_oneway()) {
+        s_service_impl << indent_impl();
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          s_service_impl << "Result := ";
+        }
+        s_service_impl << "recv_" << funname << "();" << endl;
+      }
+
+      if( for_async) {
+        if (is_void(ttype)) {
+          indent_impl(s_service_impl) << "Result := 0;" << endl;  // no IFuture<void> in Delphi
+        }
+        indent_down_impl();
+        indent_impl(s_service_impl) << "end);" << endl;
+      }
+
+      indent_down_impl();
+      indent_impl(s_service_impl) << "end;" << endl << endl;
+    }
+
+    t_function send_function(g_type_void,
+                             string("send_") + (*f_iter)->get_name(),
+                             (*f_iter)->get_arglist());
+
+    string argsname = (*f_iter)->get_name() + "_args";
+    string args_clsnm = normalize_clsnm(argsname, "T");
+    string args_intfnm = normalize_clsnm(argsname, "I");
+
+    string argsvar = tmp("_args");
+    string msgvar = tmp("_msg");
+
+    indent(s_service) << function_signature(&send_function, false) << endl;
+    indent_impl(s_service_impl) << function_signature(&send_function, false, full_cls) << endl;
+    indent_impl(s_service_impl) << "var" << endl;
+    indent_up_impl();
+    indent_impl(s_service_impl) << argsvar << " : " << args_intfnm << ";" << endl;
+    indent_impl(s_service_impl) << msgvar << " : Thrift.Protocol.TThriftMessage;" << endl;
+    indent_down_impl();
+    indent_impl(s_service_impl) << "begin" << endl;
+    indent_up_impl();
+
+    indent_impl(s_service_impl) << "seqid_ := seqid_ + 1;" << endl;
+    indent_impl(s_service_impl) << "Thrift.Protocol.Init( " << msgvar << ", '" << funname
+                                << "', " << ((*f_iter)->is_oneway() ? "TMessageType.Oneway"
+                                                                    : "TMessageType.Call")
+                                << ", seqid_);" << endl;
+
+    indent_impl(s_service_impl) << "oprot_.WriteMessageBegin( " << msgvar << " );" << endl;
+    indent_impl(s_service_impl) << argsvar << " := " << args_clsnm << "Impl.Create();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      indent_impl(s_service_impl) << argsvar << "." << prop_name(*fld_iter)
+                                  << " := " << normalize_name((*fld_iter)->get_name()) << ";"
+                                  << endl;
+    }
+    indent_impl(s_service_impl) << argsvar << ".Write(oprot_);" << endl;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      indent_impl(s_service_impl) << argsvar << "." << prop_name(*fld_iter)
+                                  << " := " << empty_value((*fld_iter)->get_type()) << ";" << endl;
+    }
+
+    indent_impl(s_service_impl) << "oprot_.WriteMessageEnd();" << endl;
+    indent_impl(s_service_impl) << "oprot_.Transport.Flush();" << endl;
+
+    indent_down_impl();
+    indent_impl(s_service_impl) << "end;" << endl << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      string org_resultname = (*f_iter)->get_name() + "_result";
+      string result_clsnm = normalize_clsnm(org_resultname, "T");
+      string result_intfnm = normalize_clsnm(org_resultname, "I");
+
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs,
+                               (*f_iter)->get_xceptions());
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+
+      string exceptvar = tmp("_ex");
+      string appexvar = tmp("_ax");
+      string retvar = tmp("_ret");
+
+      indent(s_service) << function_signature(&recv_function, false) << endl;
+      indent_impl(s_service_impl) << function_signature(&recv_function, false, full_cls) << endl;
+      indent_impl(s_service_impl) << "var" << endl;
+      indent_up_impl();
+      indent_impl(s_service_impl) << msgvar << " : Thrift.Protocol.TThriftMessage;" << endl;
+      if (xceptions.size() > 0) {
+        indent_impl(s_service_impl) << exceptvar << " : Exception;" << endl;
+      }
+      indent_impl(s_service_impl) << appexvar << " : TApplicationException;" << endl;
+      indent_impl(s_service_impl) << retvar << " : " << result_intfnm << ";" << endl;
+
+      indent_down_impl();
+      indent_impl(s_service_impl) << "begin" << endl;
+      indent_up_impl();
+      indent_impl(s_service_impl) << msgvar << " := iprot_.ReadMessageBegin();" << endl;
+      indent_impl(s_service_impl) << "if (" << msgvar << ".Type_ = TMessageType.Exception) then"
+                                  << endl;
+      indent_impl(s_service_impl) << "begin" << endl;
+      indent_up_impl();
+      indent_impl(s_service_impl) << appexvar << " := TApplicationException.Read(iprot_);" << endl;
+      indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << endl;
+      indent_impl(s_service_impl) << "raise " << appexvar << ";" << endl;
+      indent_down_impl();
+      indent_impl(s_service_impl) << "end;" << endl;
+
+      indent_impl(s_service_impl) << retvar << " := " << result_clsnm << "Impl.Create();" << endl;
+      indent_impl(s_service_impl) << retvar << ".Read(iprot_);" << endl;
+      indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << endl;
+
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        indent_impl(s_service_impl) << "if (" << retvar << ".__isset_success) then" << endl;
+        indent_impl(s_service_impl) << "begin" << endl;
+        indent_up_impl();
+        indent_impl(s_service_impl) << "Result := " << retvar << ".Success;" << endl;
+        t_type* type = (*f_iter)->get_returntype();
+        if (type->is_struct() || type->is_xception() || type->is_map() || type->is_list()
+            || type->is_set()) {
+          indent_impl(s_service_impl) << retvar << ".Success := nil;" << endl;
+        }
+        indent_impl(s_service_impl) << "Exit;" << endl;
+        indent_down_impl();
+        indent_impl(s_service_impl) << "end;" << endl;
+      }
+
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        indent_impl(s_service_impl) << "if (" << retvar << ".__isset_" << prop_name(*x_iter)
+                                    << ") then" << endl;
+        indent_impl(s_service_impl) << "begin" << endl;
+        indent_up_impl();
+        indent_impl(s_service_impl) << exceptvar << " := " << retvar << "." << prop_name(*x_iter)
+                                    << ".CreateException;" << endl;
+        indent_impl(s_service_impl) << "raise " << exceptvar << ";" << endl;
+        indent_down_impl();
+        indent_impl(s_service_impl) << "end;" << endl;
+      }
+
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        indent_impl(s_service_impl)
+            << "raise TApplicationExceptionMissingResult.Create('"
+            << (*f_iter)->get_name() << " failed: unknown result');" << endl;
+      }
+
+      indent_down_impl();
+      indent_impl(s_service_impl) << "end;" << endl << endl;
+    }
+  }
+
+  indent_down();
+  indent(s_service) << "end;" << endl << endl;
+}
+
+void t_delphi_generator::generate_service_server(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_processor = "";
+
+  string full_cls = normalize_clsnm(service_name_, "T") + ".TProcessorImpl";
+
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends(), true, true);
+    extends_processor = extends + ".TProcessorImpl";
+    indent(s_service) << "TProcessorImpl = class(" << extends_processor << ", IProcessor)" << endl;
+  } else {
+    indent(s_service) << "TProcessorImpl = class( TInterfacedObject, IProcessor)" << endl;
+  }
+
+  indent(s_service) << "public" << endl;
+  indent_up();
+  indent(s_service) << "constructor Create( iface_: Iface );" << endl;
+  indent(s_service) << "destructor Destroy; override;" << endl;
+  indent_down();
+
+  indent_impl(s_service_impl) << "constructor " << full_cls << ".Create( iface_: Iface );" << endl;
+  indent_impl(s_service_impl) << "begin" << endl;
+  indent_up_impl();
+  if (tservice->get_extends() != NULL) {
+    indent_impl(s_service_impl) << "inherited Create( iface_);" << endl;
+  } else {
+    indent_impl(s_service_impl) << "inherited Create;" << endl;
+  }
+  indent_impl(s_service_impl) << "Self.iface_ := iface_;" << endl;
+  if (tservice->get_extends() != NULL) {
+    indent_impl(s_service_impl) << "ASSERT( processMap_ <> nil);  // inherited" << endl;
+  } else {
+    indent_impl(s_service_impl)
+        << "processMap_ := TThriftDictionaryImpl<string, TProcessFunction>.Create;" << endl;
+  }
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    indent_impl(s_service_impl) << "processMap_.AddOrSetValue( '" << (*f_iter)->get_name() << "', "
+                                << (*f_iter)->get_name() << "_Process);" << endl;
+  }
+  indent_down_impl();
+  indent_impl(s_service_impl) << "end;" << endl << endl;
+
+  indent_impl(s_service_impl) << "destructor " << full_cls << ".Destroy;" << endl;
+  indent_impl(s_service_impl) << "begin" << endl;
+  indent_up_impl();
+  indent_impl(s_service_impl) << "inherited;" << endl;
+  indent_down_impl();
+  indent_impl(s_service_impl) << "end;" << endl << endl;
+
+  indent(s_service) << "private" << endl;
+  indent_up();
+  indent(s_service) << "iface_: Iface;" << endl;
+  indent_down();
+
+  if (tservice->get_extends() == NULL) {
+    indent(s_service) << "protected" << endl;
+    indent_up();
+    indent(s_service) << "type" << endl;
+    indent_up();
+    indent(s_service) << "TProcessFunction = reference to procedure( seqid: System.Integer; const iprot: "
+                         "IProtocol; const oprot: IProtocol"
+                      << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl;
+    indent_down();
+    indent_down();
+    indent(s_service) << "protected" << endl;
+    indent_up();
+    indent(s_service) << "processMap_: IThriftDictionary<string, TProcessFunction>;" << endl;
+    indent_down();
+  }
+
+  indent(s_service) << "public" << endl;
+  indent_up();
+  if (extends.empty()) {
+    indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol; const "
+                         "events : IProcessorEvents): System.Boolean;" << endl;
+  } else {
+    indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol; const "
+                         "events : IProcessorEvents): System.Boolean; reintroduce;" << endl;
+  }
+
+  indent_impl(s_service_impl) << "function " << full_cls << ".Process( const iprot: IProtocol; "
+                                                            "const oprot: IProtocol; const events "
+                                                            ": IProcessorEvents): System.Boolean;" << endl;
+  ;
+  indent_impl(s_service_impl) << "var" << endl;
+  indent_up_impl();
+  indent_impl(s_service_impl) << "msg : Thrift.Protocol.TThriftMessage;" << endl;
+  indent_impl(s_service_impl) << "fn : TProcessFunction;" << endl;
+  indent_impl(s_service_impl) << "x : TApplicationException;" << endl;
+  if (events_) {
+    indent_impl(s_service_impl) << "context : IRequestEvents;" << endl;
+  }
+  indent_down_impl();
+  indent_impl(s_service_impl) << "begin" << endl;
+  indent_up_impl();
+  indent_impl(s_service_impl) << "try" << endl;
+  indent_up_impl();
+  indent_impl(s_service_impl) << "msg := iprot.ReadMessageBegin();" << endl;
+  indent_impl(s_service_impl) << "fn := nil;" << endl;
+  indent_impl(s_service_impl) << "if not processMap_.TryGetValue(msg.Name, fn)" << endl;
+  indent_impl(s_service_impl) << "or not Assigned(fn) then" << endl;
+  indent_impl(s_service_impl) << "begin" << endl;
+  indent_up_impl();
+  indent_impl(s_service_impl) << "TProtocolUtil.Skip(iprot, TType.Struct);" << endl;
+  indent_impl(s_service_impl) << "iprot.ReadMessageEnd();" << endl;
+  indent_impl(s_service_impl) << "x := "
+                                 "TApplicationExceptionUnknownMethod.Create("
+                                 "'Invalid method name: ''' + msg.Name + '''');" << endl;
+  indent_impl(s_service_impl)
+      << "Thrift.Protocol.Init( msg, msg.Name, TMessageType.Exception, msg.SeqID);"
+      << endl;
+  indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg);" << endl;
+  indent_impl(s_service_impl) << "x.Write(oprot);" << endl;
+  indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl;
+  indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl;
+  indent_impl(s_service_impl) << "Result := True;" << endl;
+  indent_impl(s_service_impl) << "Exit;" << endl;
+  indent_down_impl();
+  indent_impl(s_service_impl) << "end;" << endl;
+  if (events_) {
+    indent_impl(s_service_impl) << "if events <> nil" << endl;
+    indent_impl(s_service_impl) << "then context := events.CreateRequestContext(msg.Name)" << endl;
+    indent_impl(s_service_impl) << "else context := nil;" << endl;
+    indent_impl(s_service_impl) << "try" << endl;
+    indent_up_impl();
+    indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot, context);" << endl;
+    indent_down_impl();
+    indent_impl(s_service_impl) << "finally" << endl;
+    indent_up_impl();
+    indent_impl(s_service_impl) << "if context <> nil then begin" << endl;
+    indent_up_impl();
+    indent_impl(s_service_impl) << "context.CleanupContext;" << endl;
+    indent_impl(s_service_impl) << "context := nil;" << endl;
+    indent_down_impl();
+    indent_impl(s_service_impl) << "end;" << endl;
+    indent_down_impl();
+    indent_impl(s_service_impl) << "end;" << endl;
+  } else {
+    indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot);" << endl;
+  }
+  indent_down_impl();
+  indent_impl(s_service_impl) << "except" << endl;
+  indent_up_impl();
+  indent_impl(s_service_impl) << "on TTransportExceptionTimedOut do begin" << endl;
+  indent_up_impl();
+  indent_impl(s_service_impl) << "Result := True;" << endl;
+  indent_impl(s_service_impl) << "Exit;" << endl;
+  indent_down_impl();
+  indent_impl(s_service_impl) << "end;" << endl;
+  indent_impl(s_service_impl) << "else begin" << endl;
+  indent_up_impl();
+  indent_impl(s_service_impl) << "Result := False;" << endl;
+  indent_impl(s_service_impl) << "Exit;" << endl;
+  indent_down_impl();
+  indent_impl(s_service_impl) << "end;" << endl;
+  indent_down_impl();
+  indent_impl(s_service_impl) << "end;" << endl;
+  indent_impl(s_service_impl) << "Result := True;" << endl;
+  indent_down_impl();
+  indent_impl(s_service_impl) << "end;" << endl << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(s_service) << "end;" << endl << endl;
+}
+
+void t_delphi_generator::generate_function_helpers(t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return;
+  }
+
+  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_delphi_struct_definition(s_service, &result, false, true, true);
+  generate_delphi_struct_impl(s_service_impl,
+                              normalize_clsnm(service_name_, "T") + ".",
+                              &result,
+                              false);
+}
+
+void t_delphi_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+  string funcname = tfunction->get_name();
+  string full_cls = normalize_clsnm(service_name_, "T") + ".TProcessorImpl";
+
+  string org_argsname = funcname + "_args";
+  string args_clsnm = normalize_clsnm(org_argsname, "T");
+  string args_intfnm = normalize_clsnm(org_argsname, "I");
+
+  string org_resultname = funcname + "_result";
+  string result_clsnm = normalize_clsnm(org_resultname, "T");
+  string result_intfnm = normalize_clsnm(org_resultname, "I");
+
+  indent(s_service) << "procedure " << funcname
+                    << "_Process( seqid: System.Integer; const iprot: IProtocol; const oprot: IProtocol"
+                    << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl;
+
+  if (tfunction->is_oneway()) {
+    indent_impl(s_service_impl) << "// one way processor" << endl;
+  } else {
+    indent_impl(s_service_impl) << "// both way processor" << endl;
+  }
+
+  indent_impl(s_service_impl)
+      << "procedure " << full_cls << "." << funcname
+      << "_Process( seqid: System.Integer; const iprot: IProtocol; const oprot: IProtocol"
+      << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl;
+  indent_impl(s_service_impl) << "var" << endl;
+  indent_up_impl();
+  indent_impl(s_service_impl) << "args: " << args_intfnm << ";" << endl;
+  if (!tfunction->is_oneway()) {
+    indent_impl(s_service_impl) << "msg: Thrift.Protocol.TThriftMessage;" << endl;
+    indent_impl(s_service_impl) << "ret: " << result_intfnm << ";" << endl;
+    indent_impl(s_service_impl) << "appx : TApplicationException;" << endl;
+  }
+
+  indent_down_impl();
+  indent_impl(s_service_impl) << "begin" << endl;
+  indent_up_impl();
+
+  if (events_) {
+    indent_impl(s_service_impl) << "if events <> nil then events.PreRead;" << endl;
+  }
+  indent_impl(s_service_impl) << "args := " << args_clsnm << "Impl.Create;" << endl;
+  indent_impl(s_service_impl) << "args.Read(iprot);" << endl;
+  indent_impl(s_service_impl) << "iprot.ReadMessageEnd();" << endl;
+  if (events_) {
+    indent_impl(s_service_impl) << "if events <> nil then events.PostRead;" << endl;
+  }
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  if (!tfunction->is_oneway()) {
+    indent_impl(s_service_impl) << "ret := " << result_clsnm << "Impl.Create;" << endl;
+  }
+
+  indent_impl(s_service_impl) << "try" << endl;
+  indent_up_impl();
+
+  t_struct* arg_struct = tfunction->get_arglist();
+  const std::vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  s_service_impl << indent_impl();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    s_service_impl << "ret.Success := ";
+  }
+  s_service_impl << "iface_." << normalize_name(tfunction->get_name(), true) << "(";
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      s_service_impl << ", ";
+    }
+    s_service_impl << "args." << prop_name(*f_iter);
+  }
+  s_service_impl << ");" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent_impl(s_service_impl) << "args." << prop_name(*f_iter)
+                                << " := " << empty_value((*f_iter)->get_type()) << ";" << endl;
+  }
+
+  indent_down_impl();
+  indent_impl(s_service_impl) << "except" << endl;
+  indent_up_impl();
+
+  for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+    indent_impl(s_service_impl) << "on E: " << type_name((*x_iter)->get_type(), true, true)
+                                << " do begin" << endl;
+    indent_up_impl();
+    if (!tfunction->is_oneway()) {
+      string factory_name = normalize_clsnm((*x_iter)->get_type()->get_name(), "", true)
+                            + "Factory";
+      indent_impl(s_service_impl) << "ret." << prop_name(*x_iter) << " := E." << factory_name << ";"
+                                  << endl;
+    }
+    indent_down_impl();
+    indent_impl(s_service_impl) << "end;" << endl;
+  }
+
+  indent_impl(s_service_impl) << "on E: Exception do begin" << endl;
+  indent_up_impl();
+  if(events_) {
+    indent_impl(s_service_impl) << "if events <> nil then events.UnhandledError(E);" << endl;
+  }
+  if (!tfunction->is_oneway()) {
+    indent_impl(s_service_impl) << "appx := TApplicationExceptionInternalError.Create(E.Message);"
+                                << endl;
+    indent_impl(s_service_impl) << "try" << endl;
+    indent_up_impl();
+    if(events_) {
+      indent_impl(s_service_impl) << "if events <> nil then events.PreWrite;" << endl;
+    }
+    indent_impl(s_service_impl) << "Thrift.Protocol.Init( msg, '"
+                                << tfunction->get_name() << "', TMessageType.Exception, seqid);"
+                                << endl;
+    indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg);" << endl;
+    indent_impl(s_service_impl) << "appx.Write(oprot);" << endl;
+    indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl;
+    indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl;
+    if(events_) {
+      indent_impl(s_service_impl) << "if events <> nil then events.PostWrite;" << endl;
+    }
+    indent_impl(s_service_impl) << "Exit;" << endl;
+    indent_down_impl();
+    indent_impl(s_service_impl) << "finally" << endl;
+    indent_up_impl();
+    indent_impl(s_service_impl) << "appx.Free;" << endl;
+    indent_down_impl();
+    indent_impl(s_service_impl) << "end;" << endl;
+  }
+  indent_down_impl();
+  indent_impl(s_service_impl) << "end;" << endl;
+
+  indent_down_impl();
+  indent_impl(s_service_impl) << "end;" << endl;
+
+  if (!tfunction->is_oneway()) {
+    if (events_) {
+      indent_impl(s_service_impl) << "if events <> nil then events.PreWrite;" << endl;
+    }
+    indent_impl(s_service_impl) << "Thrift.Protocol.Init( msg, '"
+                                << tfunction->get_name() << "', TMessageType.Reply, seqid); "
+                                << endl;
+    indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg); " << endl;
+    indent_impl(s_service_impl) << "ret.Write(oprot);" << endl;
+    indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl;
+    indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl;
+    if (events_) {
+      indent_impl(s_service_impl) << "if events <> nil then events.PostWrite;" << endl;
+    }
+  } else if (events_) {
+    indent_impl(s_service_impl) << "if events <> nil then events.OnewayComplete;" << endl;
+  }
+
+  indent_down_impl();
+  indent_impl(s_service_impl) << "end;" << endl << endl;
+}
+
+void t_delphi_generator::generate_deserialize_field(ostream& out,
+                                                    bool is_xception,
+                                                    t_field* tfield,
+                                                    string prefix,
+                                                    ostream& local_vars) {
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = prefix + prop_name(tfield, is_xception);
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name, "");
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, is_xception, type, name, local_vars);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent_impl(out) << name << " := ";
+
+    if (type->is_enum()) {
+      out << type_name(type, false) << "(";
+    }
+
+    out << "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:
+        if (type->is_binary()) {
+          if (ansistr_binary_) {
+            out << "ReadAnsiString();";
+          } else {
+            out << "ReadBinary();";
+          }
+        } else {
+          out << "ReadString();";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "ReadBool();";
+        break;
+      case t_base_type::TYPE_I8:
+        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 Delphi name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "ReadI32()";
+      out << ");";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+void t_delphi_generator::generate_deserialize_struct(ostream& out,
+                                                     t_struct* tstruct,
+                                                     string name,
+                                                     string prefix) {
+  string typ_name;
+
+  if (tstruct->is_xception()) {
+    typ_name = type_name(tstruct, true, false, true, true);
+  } else {
+    typ_name = type_name(tstruct, true, false);
+  }
+
+  indent_impl(out) << prefix << name << " := " << typ_name << ".Create;" << endl;
+  indent_impl(out) << prefix << name << ".Read(iprot);" << endl;
+}
+
+void t_delphi_generator::generate_deserialize_container(ostream& out,
+                                                        bool is_xception,
+                                                        t_type* ttype,
+                                                        string name,
+                                                        std::ostream& local_vars) {
+
+  string obj;
+  string counter;
+  string local_var;
+
+  if (ttype->is_map()) {
+    obj = tmp("_map");
+  } else if (ttype->is_set()) {
+    obj = tmp("_set");
+  } else if (ttype->is_list()) {
+    obj = tmp("_list");
+  }
+
+  if (ttype->is_map()) {
+    local_var = obj + ": TThriftMap;";
+  } else if (ttype->is_set()) {
+    local_var = obj + ": TThriftSet;";
+  } else if (ttype->is_list()) {
+    local_var = obj + ": TThriftList;";
+  }
+  local_vars << "  " << local_var << endl;
+  counter = tmp("_i");
+  local_var = counter + ": System.Integer;";
+  local_vars << "  " << local_var << endl;
+
+  indent_impl(out) << name << " := " << type_name(ttype, true) << ".Create;" << endl;
+
+  if (ttype->is_map()) {
+    indent_impl(out) << obj << " := iprot.ReadMapBegin();" << endl;
+  } else if (ttype->is_set()) {
+    indent_impl(out) << obj << " := iprot.ReadSetBegin();" << endl;
+  } else if (ttype->is_list()) {
+    indent_impl(out) << obj << " := iprot.ReadListBegin();" << endl;
+  }
+
+  indent_impl(out) << "for " << counter << " := 0 to " << obj << ".Count - 1 do" << endl;
+  indent_impl(out) << "begin" << endl;
+  indent_up_impl();
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, is_xception, (t_map*)ttype, name, local_vars);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, is_xception, (t_set*)ttype, name, local_vars);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, is_xception, (t_list*)ttype, name, local_vars);
+  }
+  indent_down_impl();
+  indent_impl(out) << "end;" << endl;
+
+  if (ttype->is_map()) {
+    indent_impl(out) << "iprot.ReadMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent_impl(out) << "iprot.ReadSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent_impl(out) << "iprot.ReadListEnd();" << endl;
+  }
+}
+
+void t_delphi_generator::generate_deserialize_map_element(ostream& out,
+                                                          bool is_xception,
+                                                          t_map* tmap,
+                                                          string prefix,
+                                                          ostream& local_vars) {
+
+  string key = tmp("_key");
+  string val = tmp("_val");
+  string local_var;
+
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  local_vars << "  " << declare_field(&fkey) << endl;
+  local_vars << "  " << declare_field(&fval) << endl;
+
+  generate_deserialize_field(out, is_xception, &fkey, "", local_vars);
+  generate_deserialize_field(out, is_xception, &fval, "", local_vars);
+
+  indent_impl(out) << prefix << ".AddOrSetValue( " << key << ", " << val << ");" << endl;
+}
+
+void t_delphi_generator::generate_deserialize_set_element(ostream& out,
+                                                          bool is_xception,
+                                                          t_set* tset,
+                                                          string prefix,
+                                                          ostream& local_vars) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+  local_vars << "  " << declare_field(&felem) << endl;
+  generate_deserialize_field(out, is_xception, &felem, "", local_vars);
+  indent_impl(out) << prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_delphi_generator::generate_deserialize_list_element(ostream& out,
+                                                           bool is_xception,
+                                                           t_list* tlist,
+                                                           string prefix,
+                                                           ostream& local_vars) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+  local_vars << "  " << declare_field(&felem) << endl;
+  generate_deserialize_field(out, is_xception, &felem, "", local_vars);
+  indent_impl(out) << prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_delphi_generator::generate_serialize_field(ostream& out,
+                                                  bool is_xception,
+                                                  t_field* tfield,
+                                                  string prefix,
+                                                  ostream& local_vars) {
+  (void)local_vars;
+
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  string name = prefix + prop_name(tfield, is_xception);
+
+  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, local_vars);
+  } else if (type->is_container()) {
+    generate_serialize_container(out, is_xception, type, name, local_vars);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    indent_impl(out) << "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:
+        if (type->is_binary()) {
+          if (ansistr_binary_) {
+            out << "WriteAnsiString(";
+          } else {
+            out << "WriteBinary(";
+          }
+        } else {
+          out << "WriteString(";
+        }
+        out << name << ");";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "WriteBool(" << name << ");";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "WriteByte(" << name << ");";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "WriteI16(" << name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "WriteI32(" << name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "WriteI64(" << name << ");";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "WriteDouble(" << name << ");";
+        break;
+      default:
+        throw "compiler error: no Delphi name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "WriteI32(System.Integer(" << name << "));";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+void t_delphi_generator::generate_serialize_struct(ostream& out,
+                                                   t_struct* tstruct,
+                                                   string prefix,
+                                                   ostream& local_vars) {
+  (void)local_vars;
+  (void)tstruct;
+  out << indent_impl() << prefix << ".Write(oprot);" << endl;
+}
+
+void t_delphi_generator::generate_serialize_container(ostream& out,
+                                                      bool is_xception,
+                                                      t_type* ttype,
+                                                      string prefix,
+                                                      ostream& local_vars) {
+  string obj;
+  if (ttype->is_map()) {
+    obj = tmp("map");
+    local_vars << "  " << obj << " : TThriftMap;" << endl;
+    indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", "
+                     << type_to_enum(((t_map*)ttype)->get_key_type()) << ", "
+                     << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix
+                     << ".Count);" << endl;
+    indent_impl(out) << "oprot.WriteMapBegin( " << obj << ");" << endl;
+  } else if (ttype->is_set()) {
+    obj = tmp("set_");
+    local_vars << "  " << obj << " : TThriftSet;" << endl;
+    indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", "
+                     << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix
+                     << ".Count);" << endl;
+    indent_impl(out) << "oprot.WriteSetBegin( " << obj << ");" << endl;
+  } else if (ttype->is_list()) {
+    obj = tmp("list_");
+    local_vars << "  " << obj << " : TThriftList;" << endl;
+    indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", "
+                     << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix
+                     << ".Count);" << endl;
+    indent_impl(out) << "oprot.WriteListBegin( " << obj << ");" << endl;
+  }
+
+  string iter = tmp("_iter");
+  if (ttype->is_map()) {
+    local_vars << "  " << iter << ": " << type_name(((t_map*)ttype)->get_key_type()) << ";" << endl;
+    indent_impl(out) << "for " << iter << " in " << prefix << ".Keys do" << endl;
+    indent_impl(out) << "begin" << endl;
+    indent_up_impl();
+  } else if (ttype->is_set()) {
+    local_vars << "  " << iter << ": " << type_name(((t_set*)ttype)->get_elem_type()) << ";"
+               << endl;
+    indent_impl(out) << "for " << iter << " in " << prefix << " do" << endl;
+    indent_impl(out) << "begin" << endl;
+    indent_up_impl();
+  } else if (ttype->is_list()) {
+    local_vars << "  " << iter << ": " << type_name(((t_list*)ttype)->get_elem_type()) << ";"
+               << endl;
+    indent_impl(out) << "for " << iter << " in " << prefix << " do" << endl;
+    indent_impl(out) << "begin" << endl;
+    indent_up_impl();
+  }
+
+  if (ttype->is_map()) {
+    generate_serialize_map_element(out, is_xception, (t_map*)ttype, iter, prefix, local_vars);
+  } else if (ttype->is_set()) {
+    generate_serialize_set_element(out, is_xception, (t_set*)ttype, iter, local_vars);
+  } else if (ttype->is_list()) {
+    generate_serialize_list_element(out, is_xception, (t_list*)ttype, iter, local_vars);
+  }
+
+  indent_down_impl();
+  indent_impl(out) << "end;" << endl;
+
+  if (ttype->is_map()) {
+    indent_impl(out) << "oprot.WriteMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent_impl(out) << "oprot.WriteSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent_impl(out) << "oprot.WriteListEnd();" << endl;
+  }
+}
+
+void t_delphi_generator::generate_serialize_map_element(ostream& out,
+                                                        bool is_xception,
+                                                        t_map* tmap,
+                                                        string iter,
+                                                        string map,
+                                                        ostream& local_vars) {
+  t_field kfield(tmap->get_key_type(), iter);
+  generate_serialize_field(out, is_xception, &kfield, "", local_vars);
+  t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
+  generate_serialize_field(out, is_xception, &vfield, "", local_vars);
+}
+
+void t_delphi_generator::generate_serialize_set_element(ostream& out,
+                                                        bool is_xception,
+                                                        t_set* tset,
+                                                        string iter,
+                                                        ostream& local_vars) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, is_xception, &efield, "", local_vars);
+}
+
+void t_delphi_generator::generate_serialize_list_element(ostream& out,
+                                                         bool is_xception,
+                                                         t_list* tlist,
+                                                         string iter,
+                                                         ostream& local_vars) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, is_xception, &efield, "", local_vars);
+}
+
+void t_delphi_generator::generate_property(ostream& out,
+                                           t_field* tfield,
+                                           bool isPublic,
+                                           bool is_xception) {
+  generate_delphi_property(out, is_xception, tfield, isPublic, "Get");
+}
+
+void t_delphi_generator::generate_delphi_property(ostream& out,
+                                                  bool struct_is_xception,
+                                                  t_field* tfield,
+                                                  bool isPublic,
+                                                  std::string fieldPrefix) {
+  (void)isPublic;
+
+  t_type* ftype = tfield->get_type();
+  bool is_xception = ftype->is_xception();
+  generate_delphi_doc(out, tfield);
+  indent(out) << "property " << prop_name(tfield, struct_is_xception) << ": "
+              << type_name(ftype, false, true, is_xception, true) << " read "
+              << fieldPrefix + prop_name(tfield, struct_is_xception) << " write Set"
+              << prop_name(tfield, struct_is_xception) << ";" << endl;
+}
+
+std::string t_delphi_generator::prop_name(t_field* tfield, bool is_xception) {
+  return prop_name(tfield->get_name(), is_xception);
+}
+
+std::string t_delphi_generator::prop_name(string name, bool is_xception) {
+  string ret = name;
+  ret[0] = toupper(ret[0]);
+  return normalize_name(ret, true, is_xception);
+}
+
+std::string t_delphi_generator::constructor_param_name(string name) {
+  string ret = name;
+  ret[0] = toupper(ret[0]);
+  ret = "A" + ret;
+  return normalize_name(ret, false, false);
+}
+
+string t_delphi_generator::normalize_clsnm(string clsnm, string prefix, bool b_no_check_keyword) {
+  if (clsnm.size() > 0) {
+    clsnm[0] = toupper(clsnm[0]);
+  }
+  if (b_no_check_keyword) {
+    return prefix + clsnm;
+  } else {
+    return normalize_name(prefix + clsnm);
+  }
+}
+
+string t_delphi_generator::type_name(t_type* ttype,
+                                     bool b_cls,
+                                     bool b_no_postfix,
+                                     bool b_exception_factory,
+                                     bool b_full_exception_factory) {
+
+  if (ttype->is_typedef()) {
+    t_typedef* tdef = (t_typedef*)ttype;
+    if (tdef->is_forward_typedef()) { // forward types according to THRIFT-2421
+      if (tdef->get_type() != NULL) {
+        return type_name(tdef->get_type(),
+                         b_cls,
+                         b_no_postfix,
+                         b_exception_factory,
+                         b_full_exception_factory);
+      } else {
+        throw "unresolved forward declaration: " + tdef->get_symbolic();
+      }
+    } else {
+      return normalize_name("T" + tdef->get_symbolic());
+    }
+  }
+
+  string typ_nm;
+
+  string s_factory;
+
+  if (ttype->is_base_type()) {
+    return base_type_name((t_base_type*)ttype);
+  } else if (ttype->is_enum()) {
+    b_cls = true;
+    b_no_postfix = true;
+  } else if (ttype->is_map()) {
+    t_map* tmap = (t_map*)ttype;
+    if (b_cls) {
+      typ_nm = "TThriftDictionaryImpl";
+    } else {
+      typ_nm = "IThriftDictionary";
+    }
+    return typ_nm + "<" + type_name(tmap->get_key_type()) + ", " + type_name(tmap->get_val_type())
+           + ">";
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*)ttype;
+    if (b_cls) {
+      typ_nm = "THashSetImpl";
+    } else {
+      typ_nm = "IHashSet";
+    }
+    return typ_nm + "<" + type_name(tset->get_elem_type()) + ">";
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*)ttype;
+    if (b_cls) {
+      typ_nm = "TThriftListImpl";
+    } else {
+      typ_nm = "IThriftList";
+    }
+    return typ_nm + "<" + type_name(tlist->get_elem_type()) + ">";
+  }
+
+  string type_prefix;
+
+  if (b_cls) {
+    type_prefix = "T";
+  } else {
+    type_prefix = "I";
+  }
+
+  string nm = normalize_clsnm(ttype->get_name(), type_prefix);
+
+  if (b_exception_factory) {
+    nm = nm + "Factory";
+  }
+
+  if (b_cls) {
+    if (!b_no_postfix) {
+      nm = nm + "Impl";
+    }
+  }
+
+  if (b_exception_factory && b_full_exception_factory) {
+    return type_name(ttype, true, true, false, false) + "." + nm;
+  }
+
+  return nm;
+}
+
+// returns "const " for some argument types
+string t_delphi_generator::input_arg_prefix(t_type* ttype) {
+
+  // base types
+  if (ttype->is_base_type()) {
+    switch (((t_base_type*)ttype)->get_base()) {
+
+    // these should be const'ed for optimal performamce
+    case t_base_type::TYPE_STRING: // refcounted pointer
+    case t_base_type::TYPE_I64:    // larger than 32 bit
+    case t_base_type::TYPE_DOUBLE: // larger than 32 bit
+      return "const ";
+
+    // all others don't need to be
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_BOOL:
+    case t_base_type::TYPE_VOID:
+      return "";
+
+    // we better always report any unknown types
+    default:
+      throw "compiler error: no input_arg_prefix() for base type "
+          + t_base_type::t_base_name(((t_base_type*)ttype)->get_base());
+    }
+
+    // enums
+  } else if (ttype->is_enum()) {
+    return ""; // usually <= 32 bit
+
+    // containers
+  } else if (ttype->is_map()) {
+    return "const "; // refcounted pointer
+
+  } else if (ttype->is_set()) {
+    return "const "; // refcounted pointer
+
+  } else if (ttype->is_list()) {
+    return "const "; // refcounted pointer
+  }
+
+  // any other type, either TSomething or ISomething
+  return "const "; // possibly refcounted pointer
+}
+
+string t_delphi_generator::base_type_name(t_base_type* tbase) {
+  switch (tbase->get_base()) {
+  case t_base_type::TYPE_VOID:
+    // no "void" in Delphi language
+    return "";
+  case t_base_type::TYPE_STRING:
+    if (tbase->is_binary()) {
+      if (ansistr_binary_) {
+        return "System.AnsiString";
+      } else {
+        return "SysUtils.TBytes";
+      }
+    } else {
+      return "System.string";
+    }
+  case t_base_type::TYPE_BOOL:
+    return "System.Boolean";
+  case t_base_type::TYPE_I8:
+    return "System.ShortInt";
+  case t_base_type::TYPE_I16:
+    return "System.SmallInt";
+  case t_base_type::TYPE_I32:
+    return "System.Integer";
+  case t_base_type::TYPE_I64:
+    return "System.Int64";
+  case t_base_type::TYPE_DOUBLE:
+    return "System.Double";
+  default:
+    throw "compiler error: no Delphi name for base type "
+        + t_base_type::t_base_name(tbase->get_base());
+  }
+}
+
+string t_delphi_generator::declare_field(t_field* tfield,
+                                         bool init,
+                                         std::string prefix,
+                                         bool is_xception_class) {
+  (void)init;
+
+  t_type* ftype = tfield->get_type();
+  bool is_xception = ftype->is_xception();
+
+  string result = prefix + prop_name(tfield, is_xception_class) + ": "
+                  + type_name(ftype, false, true, is_xception, true) + ";";
+  return result;
+}
+
+string t_delphi_generator::function_signature(t_function* tfunction,
+                                              bool for_async,
+                                              std::string full_cls,
+                                              bool is_xception) {
+  t_type* ttype = tfunction->get_returntype();
+  string prefix;
+  if (full_cls == "") {
+    prefix = "";
+  } else {
+    prefix = full_cls + ".";
+  }
+
+  if( for_async) {
+    if (is_void(ttype)) {
+      return "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "Async("
+             + argument_list(tfunction->get_arglist()) + "): IFuture<Integer>;";  // no IFuture<void> in Delphi
+    } else {
+      return "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "Async("
+             + argument_list(tfunction->get_arglist()) + "): IFuture<"
+             + type_name(ttype, false, true, is_xception, true) + ">;";
+    }
+  } else {
+    if (is_void(ttype)) {
+      return "procedure " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "("
+             + argument_list(tfunction->get_arglist()) + ");";
+    } else {
+      return "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "("
+             + argument_list(tfunction->get_arglist()) + "): "
+             + type_name(ttype, false, true, is_xception, true) + ";";
+    }
+  }
+}
+
+string t_delphi_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;
+  t_type* tt;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      result += "; ";
+    }
+
+    tt = (*f_iter)->get_type();
+    result += input_arg_prefix(tt); // const?
+    result += normalize_name((*f_iter)->get_name()) + ": "
+              + type_name(tt, false, true, tt->is_xception(), true);
+  }
+  return result;
+}
+
+string t_delphi_generator::constructor_argument_list(t_struct* tstruct, string current_indent) {
+  ostringstream result;
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  bool first = true;
+  t_type* tt;
+  string line = "";
+  string newline_indent = current_indent + "  ";
+
+  bool firstline = true;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      line += ";";
+    }
+
+    if (line.size() > 80) {
+      if (firstline) {
+        result << endl << newline_indent;
+        firstline = false;
+      }
+      result << line << endl;
+      line = newline_indent;
+    } else if (line.size() > 0) {
+      line += " ";
+    }
+
+    tt = (*f_iter)->get_type();
+    line += input_arg_prefix(tt); // const?
+    line += constructor_param_name((*f_iter)->get_name()) + ": "
+            + type_name(tt, false, true, tt->is_xception(), true);
+  }
+
+  if (line.size() > 0) {
+    result << line;
+  }
+
+  string result_str;
+
+  if (firstline) {
+    result_str = " " + result.str();
+  } else {
+    result_str = result.str();
+  }
+
+  return result_str;
+}
+
+string t_delphi_generator::type_to_enum(t_type* type) {
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_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 "TType.String_";
+    case t_base_type::TYPE_BOOL:
+      return "TType.Bool_";
+    case t_base_type::TYPE_I8:
+      return "TType.Byte_";
+    case t_base_type::TYPE_I16:
+      return "TType.I16";
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "TType.Double_";
+    }
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.Struct";
+  } else if (type->is_map()) {
+    return "TType.Map";
+  } else if (type->is_set()) {
+    return "TType.Set_";
+  } else if (type->is_list()) {
+    return "TType.List";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+string t_delphi_generator::empty_value(t_type* type) {
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_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:
+      return "0";
+    case t_base_type::TYPE_STRING:
+      if (type->is_binary()) {
+        if (ansistr_binary_) {
+          return "''";
+        } else {
+          return "nil";
+        }
+      } else {
+        return "''";
+      }
+    case t_base_type::TYPE_BOOL:
+      return "False";
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      return "0";
+    case t_base_type::TYPE_DOUBLE:
+      return "0.0";
+    }
+  } else if (type->is_enum()) {
+    return "T" + type->get_name() + "(0)";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "nil";
+  } else if (type->is_map()) {
+    return "nil";
+  } else if (type->is_set()) {
+    return "nil";
+  } else if (type->is_list()) {
+    return "nil";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+void t_delphi_generator::generate_delphi_property_writer_definition(ostream& out,
+                                                                    t_field* tfield,
+                                                                    bool is_xception_class) {
+  t_type* ftype = tfield->get_type();
+  bool is_xception = ftype->is_xception();
+
+  indent(out) << "procedure Set" << prop_name(tfield, is_xception_class)
+              << "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");"
+              << endl;
+}
+
+void t_delphi_generator::generate_delphi_property_reader_definition(ostream& out,
+                                                                    t_field* tfield,
+                                                                    bool is_xception_class) {
+  t_type* ftype = tfield->get_type();
+  bool is_xception = ftype->is_xception();
+
+  indent(out) << "function Get" << prop_name(tfield, is_xception_class) << ": "
+              << type_name(ftype, false, true, is_xception, true) << ";" << endl;
+}
+
+void t_delphi_generator::generate_delphi_isset_reader_definition(ostream& out,
+                                                                 t_field* tfield,
+                                                                 bool is_xception) {
+  indent(out) << "function Get__isset_" << prop_name(tfield, is_xception) << ": System.Boolean;" << endl;
+}
+
+void t_delphi_generator::generate_delphi_clear_union_value(ostream& out,
+                                                           std::string cls_prefix,
+                                                           std::string name,
+                                                           t_type* type,
+                                                           t_field* tfield,
+                                                           std::string fieldPrefix,
+                                                           bool is_xception_class,
+                                                           bool is_union,
+                                                           bool is_xception_factory,
+                                                           std::string xception_factory_name) {
+  (void)cls_prefix;
+  (void)name;
+  (void)type;
+  (void)is_union;
+  (void)is_xception_factory;
+  (void)xception_factory_name;
+
+  t_type* ftype = tfield->get_type();
+  bool is_xception = ftype->is_xception();
+
+  indent_impl(out) << "if F__isset_" << prop_name(tfield, is_xception_class) << " then begin"
+                   << endl;
+  indent_up_impl();
+  indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := False;" << endl;
+  indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := "
+                   << "Default( " << type_name(ftype, false, true, is_xception, true) << ");"
+                   << endl;
+  indent_down_impl();
+  indent_impl(out) << "end;" << endl;
+}
+
+void t_delphi_generator::generate_delphi_property_writer_impl(ostream& out,
+                                                              std::string cls_prefix,
+                                                              std::string name,
+                                                              t_type* type,
+                                                              t_field* tfield,
+                                                              std::string fieldPrefix,
+                                                              bool is_xception_class,
+                                                              bool is_union,
+                                                              bool is_xception_factory,
+                                                              std::string xception_factory_name) {
+  (void)type;
+
+  t_type* ftype = tfield->get_type();
+  bool is_xception = ftype->is_xception();
+
+  indent_impl(out) << "procedure " << cls_prefix << name << "."
+                   << "Set" << prop_name(tfield, is_xception_class)
+                   << "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");"
+                   << endl;
+  indent_impl(out) << "begin" << endl;
+  indent_up_impl();
+  if (is_union) {
+    indent_impl(out) << "ClearUnionValues;" << endl;
+  }
+  if (tfield->get_req() != t_field::T_REQUIRED) {
+    indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := True;" << endl;
+  }
+  indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := Value;" << endl;
+
+  if (is_xception_class && (!is_xception_factory)) {
+    indent_impl(out) << xception_factory_name << "." << prop_name(tfield, is_xception_class)
+                     << " := Value;" << endl;
+  }
+
+  indent_down_impl();
+  indent_impl(out) << "end;" << endl << endl;
+}
+
+void t_delphi_generator::generate_delphi_property_reader_impl(ostream& out,
+                                                              std::string cls_prefix,
+                                                              std::string name,
+                                                              t_type* type,
+                                                              t_field* tfield,
+                                                              std::string fieldPrefix,
+                                                              bool is_xception_class) {
+  (void)type;
+
+  t_type* ftype = tfield->get_type();
+  bool is_xception = ftype->is_xception();
+
+  indent_impl(out) << "function " << cls_prefix << name << "."
+                   << "Get" << prop_name(tfield, is_xception_class) << ": "
+                   << type_name(ftype, false, true, is_xception, true) << ";" << endl;
+  indent_impl(out) << "begin" << endl;
+  indent_up_impl();
+  indent_impl(out) << "Result := " << fieldPrefix << prop_name(tfield, is_xception_class) << ";"
+                   << endl;
+  indent_down_impl();
+  indent_impl(out) << "end;" << endl << endl;
+}
+
+void t_delphi_generator::generate_delphi_isset_reader_impl(ostream& out,
+                                                           std::string cls_prefix,
+                                                           std::string name,
+                                                           t_type* type,
+                                                           t_field* tfield,
+                                                           std::string fieldPrefix,
+                                                           bool is_xception) {
+  (void)type;
+
+  string isset_name = "__isset_" + prop_name(tfield, is_xception);
+  indent_impl(out) << "function " << cls_prefix << name << "."
+                   << "Get" << isset_name << ": System.Boolean;" << endl;
+  indent_impl(out) << "begin" << endl;
+  indent_up_impl();
+  indent_impl(out) << "Result := " << fieldPrefix << isset_name << ";" << endl;
+  indent_down_impl();
+  indent_impl(out) << "end;" << endl << endl;
+}
+
+void t_delphi_generator::generate_delphi_create_exception_impl(ostream& out,
+                                                               string cls_prefix,
+                                                               t_struct* tstruct,
+                                                               bool is_exception) {
+  (void)cls_prefix;
+
+  string exception_cls_nm = type_name(tstruct, true, true);
+  string cls_nm = type_name(tstruct, true, false, is_exception, is_exception);
+
+  indent_impl(out) << "function " << cls_nm << ".CreateException: " << exception_cls_nm << ";"
+                   << endl;
+
+  indent_impl(out) << "begin" << endl;
+  indent_up_impl();
+
+  indent_impl(out) << "Result := " << exception_cls_nm << ".Create;" << endl;
+  string factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory";
+  indent_impl(out) << "Result.F" << factory_name << " := Self;" << endl;
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  string propname;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    propname = prop_name(*f_iter, is_exception);
+    if ((*f_iter)->get_req() != t_field::T_REQUIRED) {
+      indent_impl(out) << "if __isset_" << propname << " then begin" << endl;
+      indent_up_impl();
+    }
+    indent_impl(out) << "Result." << propname << " := " << propname << ";" << endl;
+    if ((*f_iter)->get_req() != t_field::T_REQUIRED) {
+      indent_down_impl();
+      indent_impl(out) << "end;" << endl;
+    }
+  }
+
+  indent_impl(out) << "Result.UpdateMessageProperty;" << endl;
+
+  indent_down_impl();
+  indent_impl(out) << "end;" << endl << endl;
+}
+
+void t_delphi_generator::generate_delphi_struct_reader_impl(ostream& out,
+                                                            string cls_prefix,
+                                                            t_struct* tstruct,
+                                                            bool is_exception) {
+
+  ostringstream local_vars;
+  ostringstream code_block;
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent_impl(code_block) << "begin" << endl;
+  indent_up_impl();
+
+  indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl;
+  indent_impl(code_block) << "tracker := iprot.NextRecursionLevel;" << endl;
+
+  // local bools for required fields
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      indent_impl(local_vars) << "_req_isset_" << prop_name(*f_iter, is_exception) << " : System.Boolean;"
+                              << endl;
+      indent_impl(code_block) << "_req_isset_" << prop_name(*f_iter, is_exception) << " := FALSE;"
+                              << endl;
+    }
+  }
+
+  indent_impl(code_block) << "struc := iprot.ReadStructBegin;" << endl;
+
+  indent_impl(code_block) << "try" << endl;
+  indent_up_impl();
+
+  indent_impl(code_block) << "while (true) do" << endl;
+  indent_impl(code_block) << "begin" << endl;
+  indent_up_impl();
+
+  indent_impl(code_block) << "field_ := iprot.ReadFieldBegin();" << endl;
+
+  indent_impl(code_block) << "if (field_.Type_ = TType.Stop) then" << endl;
+  indent_impl(code_block) << "begin" << endl;
+  indent_up_impl();
+  indent_impl(code_block) << "Break;" << endl;
+  indent_down_impl();
+  indent_impl(code_block) << "end;" << endl;
+
+  bool first = true;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+
+    if (first) {
+      indent_impl(code_block) << "case field_.ID of" << endl;
+      indent_up_impl();
+    }
+
+    first = false;
+    if (f_iter != fields.begin()) {
+      code_block << ";" << endl;
+    }
+    indent_impl(code_block) << (*f_iter)->get_key() << ": begin" << endl;
+    indent_up_impl();
+    indent_impl(code_block) << "if (field_.Type_ = " << type_to_enum((*f_iter)->get_type())
+                            << ") then begin" << endl;
+    indent_up_impl();
+
+    generate_deserialize_field(code_block, is_exception, *f_iter, "Self.", local_vars);
+
+    // required field?
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      indent_impl(code_block) << "_req_isset_" << prop_name(*f_iter, is_exception) << " := TRUE;"
+                              << endl;
+    }
+
+    indent_down_impl();
+
+    indent_impl(code_block) << "end else begin" << endl;
+    indent_up_impl();
+    indent_impl(code_block) << "TProtocolUtil.Skip(iprot, field_.Type_);" << endl;
+    indent_down_impl();
+    indent_impl(code_block) << "end;" << endl;
+    indent_down_impl();
+    indent_impl(code_block) << "end";
+  }
+
+  if (!first) {
+    code_block << endl;
+    indent_impl(code_block) << "else begin" << endl;
+    indent_up_impl();
+  }
+
+  indent_impl(code_block) << "TProtocolUtil.Skip(iprot, field_.Type_);" << endl;
+
+  if (!first) {
+    indent_down_impl();
+    indent_impl(code_block) << "end;" << endl;
+    indent_down_impl();
+    indent_impl(code_block) << "end;" << endl;
+  }
+
+  indent_impl(code_block) << "iprot.ReadFieldEnd;" << endl;
+
+  indent_down_impl();
+
+  indent_impl(code_block) << "end;" << endl;
+  indent_down_impl();
+
+  indent_impl(code_block) << "finally" << endl;
+  indent_up_impl();
+  indent_impl(code_block) << "iprot.ReadStructEnd;" << endl;
+  indent_down_impl();
+  indent_impl(code_block) << "end;" << endl;
+
+  // all required fields have been read?
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      indent_impl(code_block) << "if not _req_isset_" << prop_name(*f_iter, is_exception) << endl;
+      indent_impl(code_block)
+          << "then raise TProtocolExceptionInvalidData.Create("
+          << "'required field " << prop_name(*f_iter, is_exception) << " not set');"
+          << endl;
+    }
+  }
+
+  indent_down_impl();
+  indent_impl(code_block) << "end;" << endl << endl;
+
+  string cls_nm;
+
+  cls_nm = type_name(tstruct, true, false, is_exception, is_exception);
+
+  indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Read( const iprot: IProtocol);"
+                   << endl;
+  indent_impl(out) << "var" << endl;
+  indent_up_impl();
+  indent_impl(out) << "field_ : TThriftField;" << endl;
+  indent_impl(out) << "struc : TThriftStruct;" << endl;
+  indent_down_impl();
+  out << local_vars.str() << endl;
+  out << code_block.str();
+}
+
+void t_delphi_generator::generate_delphi_struct_result_writer_impl(ostream& out,
+                                                                   string cls_prefix,
+                                                                   t_struct* tstruct,
+                                                                   bool is_exception) {
+
+  ostringstream local_vars;
+  ostringstream code_block;
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent_impl(code_block) << "begin" << endl;
+  indent_up_impl();
+
+  indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl;
+  indent_impl(code_block) << "tracker := oprot.NextRecursionLevel;" << endl;
+
+  indent_impl(code_block) << "Thrift.Protocol.Init( struc, '" << name << "');" << endl;
+  indent_impl(code_block) << "oprot.WriteStructBegin(struc);" << endl;
+
+  if (fields.size() > 0) {
+    indent_impl(code_block) << "Thrift.Protocol.Init( field_);" << endl;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      indent_impl(code_block) << "if (__isset_" << prop_name(*f_iter, is_exception) << ") then"
+                              << endl;
+      indent_impl(code_block) << "begin" << endl;
+      indent_up_impl();
+      indent_impl(code_block) << "field_.Name := '" << (*f_iter)->get_name() << "';" << endl;
+      indent_impl(code_block) << "field_.Type_  := " << type_to_enum((*f_iter)->get_type()) << ";"
+                              << endl;
+      indent_impl(code_block) << "field_.ID := " << (*f_iter)->get_key() << ";" << endl;
+      indent_impl(code_block) << "oprot.WriteFieldBegin(field_);" << endl;
+      generate_serialize_field(code_block, is_exception, *f_iter, "Self.", local_vars);
+      indent_impl(code_block) << "oprot.WriteFieldEnd();" << endl;
+      indent_down_impl();
+    }
+  }
+
+  indent_impl(code_block) << "oprot.WriteFieldStop();" << endl;
+  indent_impl(code_block) << "oprot.WriteStructEnd();" << endl;
+
+  indent_down_impl();
+  indent_impl(code_block) << "end;" << endl << endl;
+
+  string cls_nm;
+
+  cls_nm = type_name(tstruct, true, false, is_exception, is_exception);
+
+  indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Write( const oprot: IProtocol);"
+                   << endl;
+  indent_impl(out) << "var" << endl;
+  indent_up_impl();
+  indent_impl(out) << "struc : TThriftStruct;" << endl;
+
+  if (fields.size() > 0) {
+    indent_impl(out) << "field_ : TThriftField;" << endl;
+  }
+
+  out << local_vars.str();
+  indent_down_impl();
+  out << code_block.str();
+}
+
+void t_delphi_generator::generate_delphi_struct_writer_impl(ostream& out,
+                                                            string cls_prefix,
+                                                            t_struct* tstruct,
+                                                            bool is_exception) {
+
+  ostringstream local_vars;
+  ostringstream code_block;
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent_impl(code_block) << "begin" << endl;
+  indent_up_impl();
+
+  indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl;
+  indent_impl(code_block) << "tracker := oprot.NextRecursionLevel;" << endl;
+
+  indent_impl(code_block) << "Thrift.Protocol.Init( struc, '" << name << "');" << endl;
+  indent_impl(code_block) << "oprot.WriteStructBegin(struc);" << endl;
+
+  if (fields.size() > 0) {
+    indent_impl(code_block) << "Thrift.Protocol.Init( field_);" << endl;
+  }
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    string fieldname = prop_name((*f_iter), is_exception);
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    bool is_required = ((*f_iter)->get_req() == t_field::T_REQUIRED);
+    bool has_isset = (!is_required);
+    if (is_required && null_allowed) {
+      null_allowed = false;
+      indent_impl(code_block) << "if (Self." << fieldname << " = nil)" << endl;
+      indent_impl(code_block) << "then raise TProtocolExceptionInvalidData.Create("
+                              << "'required field " << fieldname << " not set');"
+                              << endl;
+    }
+    if (null_allowed) {
+      indent_impl(code_block) << "if (Self." << fieldname << " <> nil)";
+      if (has_isset) {
+        code_block << " and __isset_" << fieldname;
+      }
+      code_block << " then begin" << endl;
+      indent_up_impl();
+    } else {
+      if (has_isset) {
+        indent_impl(code_block) << "if (__isset_" << fieldname << ") then begin" << endl;
+        indent_up_impl();
+      }
+    }
+    indent_impl(code_block) << "field_.Name := '" << (*f_iter)->get_name() << "';" << endl;
+    indent_impl(code_block) << "field_.Type_  := " << type_to_enum((*f_iter)->get_type()) << ";"
+                            << endl;
+    indent_impl(code_block) << "field_.ID := " << (*f_iter)->get_key() << ";" << endl;
+    indent_impl(code_block) << "oprot.WriteFieldBegin(field_);" << endl;
+    generate_serialize_field(code_block, is_exception, *f_iter, "Self.", local_vars);
+    indent_impl(code_block) << "oprot.WriteFieldEnd();" << endl;
+    if (null_allowed || has_isset) {
+      indent_down_impl();
+      indent_impl(code_block) << "end;" << endl;
+    }
+  }
+
+  indent_impl(code_block) << "oprot.WriteFieldStop();" << endl;
+  indent_impl(code_block) << "oprot.WriteStructEnd();" << endl;
+
+  indent_down_impl();
+  indent_impl(code_block) << "end;" << endl << endl;
+
+  string cls_nm;
+
+  cls_nm = type_name(tstruct, true, false, is_exception, is_exception);
+
+  indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Write( const oprot: IProtocol);"
+                   << endl;
+  indent_impl(out) << "var" << endl;
+  indent_up_impl();
+  indent_impl(out) << "struc : TThriftStruct;" << endl;
+  if (fields.size() > 0) {
+    indent_impl(out) << "field_ : TThriftField;" << endl;
+  }
+  out << local_vars.str();
+  indent_down_impl();
+  out << code_block.str();
+}
+
+void t_delphi_generator::generate_delphi_struct_tostring_impl(ostream& out,
+                                                              string cls_prefix,
+                                                              t_struct* tstruct,
+                                                              bool is_exception,
+                                                              bool is_x_factory) {
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  string cls_nm;
+
+  if (is_exception) {
+    cls_nm = type_name(tstruct, true, (!is_x_factory), is_x_factory, true);
+  } else {
+    cls_nm = type_name(tstruct, true, false);
+  }
+
+  string tmp_sb = tmp("_sb");
+  string tmp_first = tmp("_first");
+  bool useFirstFlag = false;
+
+  indent_impl(out) << "function " << cls_prefix << cls_nm << ".ToString: string;" << endl;
+  indent_impl(out) << "var" << endl;
+  indent_up_impl();
+  indent_impl(out) << tmp_sb << " : TThriftStringBuilder;" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    bool is_optional = ((*f_iter)->get_req() != t_field::T_REQUIRED);
+    if (is_optional) {
+      indent_impl(out) << tmp_first << " : System.Boolean;" << endl;
+      useFirstFlag = true;
+    }
+    break;
+  }
+  indent_down_impl();
+  indent_impl(out) << "begin" << endl;
+  indent_up_impl();
+
+  indent_impl(out) << tmp_sb << " := TThriftStringBuilder.Create('(');" << endl;
+  indent_impl(out) << "try" << endl;
+  indent_up_impl();
+
+  if (useFirstFlag) {
+    indent_impl(out) << tmp_first << " := TRUE;" << endl;
+  }
+
+  bool had_required = false; // set to true after first required field has been processed
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    bool is_optional = ((*f_iter)->get_req() != t_field::T_REQUIRED);
+    if (null_allowed) {
+      indent_impl(out) << "if (Self." << prop_name((*f_iter), is_exception) << " <> nil)";
+      if (is_optional) {
+        out << " and __isset_" << prop_name(*f_iter, is_exception);
+      }
+      out << " then begin" << endl;
+      indent_up_impl();
+    } else {
+      if (is_optional) {
+        indent_impl(out) << "if (__isset_" << prop_name(*f_iter, is_exception) << ") then begin"
+                         << endl;
+        indent_up_impl();
+      }
+    }
+
+    if (useFirstFlag && (!had_required)) {
+      indent_impl(out) << "if not " << tmp_first << " then " << tmp_sb << ".Append(',');" << endl;
+      if (is_optional) {
+        indent_impl(out) << tmp_first << " := FALSE;" << endl;
+      }
+      indent_impl(out) << tmp_sb << ".Append('" << prop_name((*f_iter), is_exception) << ": ');"
+                       << endl;
+    } else {
+      indent_impl(out) << tmp_sb << ".Append(', " << prop_name((*f_iter), is_exception) << ": ');"
+                       << endl;
+    }
+
+    t_type* ttype = (*f_iter)->get_type();
+    while (ttype->is_typedef()) {
+      ttype = ((t_typedef*)ttype)->get_type();
+    }
+
+    if (ttype->is_xception() || ttype->is_struct()) {
+      indent_impl(out) << "if (Self." << prop_name((*f_iter), is_exception) << " = nil) then " << tmp_sb
+                       << ".Append('<null>') else " << tmp_sb << ".Append( Self."
+                       << prop_name((*f_iter), is_exception) << ".ToString());" << endl;
+    } else if (ttype->is_enum()) {
+      indent_impl(out) << tmp_sb << ".Append(System.Integer( Self." << prop_name((*f_iter), is_exception)
+                       << "));" << endl;
+    } else {
+      indent_impl(out) << tmp_sb << ".Append( Self." << prop_name((*f_iter), is_exception) << ");"
+                       << endl;
+    }
+
+    if (null_allowed || is_optional) {
+      indent_down_impl();
+      indent_impl(out) << "end;" << endl;
+    }
+
+    if (!is_optional) {
+      had_required = true; // now __first must be false, so we don't need to check it anymore
+    }
+  }
+
+  indent_impl(out) << tmp_sb << ".Append(')');" << endl;
+  indent_impl(out) << "Result := " << tmp_sb << ".ToString;" << endl;
+  if (useFirstFlag) {
+    indent_impl(out) << "if " << tmp_first << " then {prevent warning};" << endl;
+  }
+
+  indent_down_impl();
+  indent_impl(out) << "finally" << endl;
+  indent_up_impl();
+  indent_impl(out) << tmp_sb << ".Free;" << endl;
+  indent_down_impl();
+  indent_impl(out) << "end;" << endl;
+
+  indent_down_impl();
+  indent_impl(out) << "end;" << endl << endl;
+}
+
+bool t_delphi_generator::is_void(t_type* type) {
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    if (tbase == t_base_type::TYPE_VOID) {
+      return true;
+    }
+  }
+  return false;
+}
+
+THRIFT_REGISTER_GENERATOR(
+    delphi,
+    "delphi",
+    "    ansistr_binary:  Use AnsiString for binary datatype (default is TBytes).\n"
+    "    register_types:  Enable TypeRegistry, allows for creation of struct, union\n"
+    "                     and container instances by interface or TypeInfo()\n"
+    "    constprefix:     Name TConstants classes after IDL to reduce ambiguities\n"
+    "    events:          Enable and use processing events in the generated code.\n"
+    "    xmldoc:          Enable XMLDoc comments for Help Insight etc.\n"
+    "    async:           Generate IAsync interface to use Parallel Programming Library (XE7+ only).\n")
diff --git a/compiler/cpp/src/thrift/generate/t_erl_generator.cc b/compiler/cpp/src/thrift/generate/t_erl_generator.cc
new file mode 100644
index 0000000..12d91a7
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_erl_generator.cc
@@ -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.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+#include "thrift/platform.h"
+#include "thrift/version.h"
+#include "thrift/generate/t_generator.h"
+
+using std::map;
+using std::ofstream;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const std::string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * Erlang code generator.
+ *
+ */
+class t_erl_generator : public t_generator {
+public:
+  t_erl_generator(t_program* program,
+                  const std::map<std::string, std::string>& parsed_options,
+                  const std::string& option_string)
+    : t_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    legacy_names_ = false;
+    maps_ = false;
+    otp16_ = false;
+    export_lines_first_ = true;
+    export_types_lines_first_ = true;
+
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("legacynames") == 0) {
+        legacy_names_ = true;
+      } else if( iter->first.compare("maps") == 0) {
+        maps_ = true;
+      } else if( iter->first.compare("otp16") == 0) {
+        otp16_ = true;
+      } else {
+        throw "unknown option erl:" + iter->first;
+      }
+    }
+
+    if (maps_ && otp16_) {
+      throw "argument error: Cannot specify both maps and otp16; maps are not available for Erlang/OTP R16 or older";
+    }
+
+    out_dir_base_ = "gen-erl";
+  }
+
+  /**
+   * 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);
+  void generate_member_type(std::ostream& out, t_type* type);
+  void generate_member_value(std::ostream& out, t_type* type, t_const_value* value);
+
+  std::string render_member_type(t_field* field);
+  std::string render_member_value(t_field* field);
+  std::string render_member_requiredness(t_field* field);
+
+  //  std::string render_default_value(t_type* type);
+  std::string render_default_value(t_field* field);
+  std::string render_const_value(t_type* type, t_const_value* value);
+  std::string render_type_term(t_type* ttype, bool expand_structs, bool extended_info = false);
+
+  /**
+   * Struct generation code
+   */
+
+  void generate_erl_struct(t_struct* tstruct, bool is_exception);
+  void generate_erl_struct_definition(std::ostream& out, t_struct* tstruct);
+  void generate_erl_struct_member(std::ostream& out, t_field* tmember);
+  void generate_erl_struct_info(std::ostream& out, t_struct* tstruct);
+  void generate_erl_extended_struct_info(std::ostream& out, t_struct* tstruct);
+  void generate_erl_function_helpers(t_function* tfunction);
+  void generate_type_metadata(std::string function_name, vector<string> names);
+  void generate_enum_info(t_enum* tenum);
+  void generate_enum_metadata();
+  void generate_const_function(t_const* tconst, ostringstream& exports, ostringstream& functions);
+  void generate_const_functions();
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_metadata(t_service* tservice);
+  void generate_service_interface(t_service* tservice);
+  void generate_function_info(t_service* tservice, t_function* tfunction);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string erl_autogen_comment();
+  std::string erl_imports();
+  std::string render_includes();
+  std::string type_name(t_type* ttype);
+  std::string render_const_list_values(t_type* type, t_const_value* value);
+
+  std::string function_signature(t_function* tfunction, std::string prefix = "");
+
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string type_module(t_type* ttype);
+
+  std::string make_safe_for_module_name(std::string in) {
+    if (legacy_names_) {
+      return decapitalize(in);
+    } else {
+      return underscore(in);
+    }
+  }
+
+  std::string atomify(std::string in) {
+    if (legacy_names_) {
+      return "'" + decapitalize(in) + "'";
+    } else {
+      return "'" + in + "'";
+    }
+  }
+
+  std::string constify(std::string in) {
+    if (legacy_names_) {
+      return capitalize(in);
+    } else {
+      return uppercase(in);
+    }
+  }
+
+  static std::string comment(string in);
+
+private:
+  bool has_default_value(t_field*);
+
+  /* if true retain pre 0.9.2 naming scheme for functions, atoms and consts */
+  bool legacy_names_;
+
+  /* if true use maps instead of dicts in generated code */
+  bool maps_;
+
+  /* if true use non-namespaced dict and set instead of dict:dict and sets:set */
+  bool otp16_;
+
+  /**
+   * add function to export list
+   */
+
+  void export_function(t_function* tfunction, std::string prefix = "");
+  void export_string(std::string name, int num);
+
+  void export_types_string(std::string name, int num);
+
+  /**
+   * write out headers and footers for hrl files
+   */
+
+  void hrl_header(std::ostream& out, std::string name);
+  void hrl_footer(std::ostream& out, std::string name);
+
+  /**
+   * stuff to spit out at the top of generated files
+   */
+
+  bool export_lines_first_;
+  std::ostringstream export_lines_;
+
+  bool export_types_lines_first_;
+  std::ostringstream export_types_lines_;
+
+  /**
+   * File streams
+   */
+
+  std::ostringstream f_info_;
+  std::ostringstream f_info_ext_;
+
+  ofstream_with_content_based_conditional_update f_types_file_;
+  ofstream_with_content_based_conditional_update f_types_hrl_file_;
+
+  ofstream_with_content_based_conditional_update f_consts_file_;
+  ofstream_with_content_based_conditional_update f_consts_hrl_file_;
+
+  std::ostringstream f_service_;
+  ofstream_with_content_based_conditional_update f_service_file_;
+  ofstream_with_content_based_conditional_update f_service_hrl_;
+
+  /**
+   * Metadata containers
+   */
+  std::vector<std::string> v_struct_names_;
+  std::vector<std::string> v_enum_names_;
+  std::vector<std::string> v_exception_names_;
+  std::vector<t_enum*> v_enums_;
+  std::vector<t_const*> v_consts_;
+};
+
+/**
+ * UI for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_erl_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  // setup export lines
+  export_lines_first_ = true;
+  export_types_lines_first_ = true;
+
+  string program_module_name = make_safe_for_module_name(program_name_);
+
+  // types files
+  string f_types_name = get_out_dir() + program_module_name + "_types.erl";
+  string f_types_hrl_name = get_out_dir() + program_module_name + "_types.hrl";
+
+  f_types_file_.open(f_types_name.c_str());
+  f_types_hrl_file_.open(f_types_hrl_name.c_str());
+
+  hrl_header(f_types_hrl_file_, program_module_name + "_types");
+
+  f_types_file_ << erl_autogen_comment() << endl
+                << "-module(" << program_module_name << "_types)." << endl
+                << erl_imports() << endl;
+
+  f_types_file_ << "-include(\"" << program_module_name << "_types.hrl\")." << endl
+                  << endl;
+
+  f_types_hrl_file_ << render_includes() << endl;
+
+  // consts files
+  string f_consts_name = get_out_dir() + program_module_name + "_constants.erl";
+  string f_consts_hrl_name = get_out_dir() + program_module_name + "_constants.hrl";
+
+  f_consts_file_.open(f_consts_name.c_str());
+  f_consts_hrl_file_.open(f_consts_hrl_name.c_str());
+
+  f_consts_file_ << erl_autogen_comment() << endl
+                 << "-module(" << program_module_name << "_constants)." << endl
+                 << erl_imports() << endl
+                 << "-include(\"" << program_module_name << "_types.hrl\")." << endl
+                 << endl;
+
+  f_consts_hrl_file_ << erl_autogen_comment() << endl << erl_imports() << endl
+                     << "-include(\"" << program_module_name << "_types.hrl\")." << endl << endl;
+}
+
+/**
+ * Boilerplate at beginning and end of header files
+ */
+void t_erl_generator::hrl_header(ostream& out, string name) {
+  out << "-ifndef(_" << name << "_included)." << endl << "-define(_" << name << "_included, yeah)."
+      << endl;
+}
+
+void t_erl_generator::hrl_footer(ostream& out, string name) {
+  (void)name;
+  out << "-endif." << endl;
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program
+ */
+string t_erl_generator::render_includes() {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = "";
+  for (size_t i = 0; i < includes.size(); ++i) {
+    result += "-include(\"" + make_safe_for_module_name(includes[i]->get_name())
+              + "_types.hrl\").\n";
+  }
+  if (includes.size() > 0) {
+    result += "\n";
+  }
+  return result;
+}
+
+/**
+ * Autogen'd comment
+ */
+string t_erl_generator::erl_autogen_comment() {
+  return std::string("%%\n") + "%% Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
+         + "%%\n" + "%% DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n"
+         + "%%\n";
+}
+
+/**
+ * Comment out text
+ */
+
+string t_erl_generator::comment(string in) {
+  size_t pos = 0;
+  in.insert(pos, "%% ");
+  while ((pos = in.find_first_of('\n', pos)) != string::npos) {
+    in.insert(++pos, "%% ");
+  }
+  return in;
+}
+
+/**
+ * Prints standard thrift imports
+ */
+string t_erl_generator::erl_imports() {
+  return "";
+}
+
+/**
+ * Closes the type files
+ */
+void t_erl_generator::close_generator() {
+
+  export_types_string("struct_info", 1);
+  export_types_string("struct_info_ext", 1);
+  export_types_string("enum_info", 1);
+  export_types_string("enum_names", 0);
+  export_types_string("struct_names", 0);
+  export_types_string("exception_names", 0);
+
+  f_types_file_ << "-export([" << export_types_lines_.str() << "])." << endl << endl;
+
+  f_types_file_ << f_info_.str();
+  f_types_file_ << "struct_info(_) -> erlang:error(function_clause)." << endl << endl;
+
+  f_types_file_ << f_info_ext_.str();
+  f_types_file_ << "struct_info_ext(_) -> erlang:error(function_clause)." << endl << endl;
+
+  generate_const_functions();
+
+  generate_type_metadata("struct_names", v_struct_names_);
+  generate_enum_metadata();
+  generate_type_metadata("enum_names", v_enum_names_);
+  generate_type_metadata("exception_names", v_exception_names_);
+
+  hrl_footer(f_types_hrl_file_, string("BOGUS"));
+
+  f_types_file_.close();
+  f_types_hrl_file_.close();
+  f_consts_file_.close();
+  f_consts_hrl_file_.close();
+}
+
+const std::string emit_double_as_string(const double value) {
+  std::stringstream double_output_stream;
+  // sets the maximum precision: http://en.cppreference.com/w/cpp/io/manip/setprecision
+  // sets the output format to fixed: http://en.cppreference.com/w/cpp/io/manip/fixed (not in scientific notation)
+  double_output_stream << std::setprecision(std::numeric_limits<double>::digits10 + 1);
+
+  #ifdef _MSC_VER
+      // strtod is broken in MSVC compilers older than 2015, so std::fixed fails to format a double literal.
+      // more details: https://blogs.msdn.microsoft.com/vcblog/2014/06/18/
+      //               c-runtime-crt-features-fixes-and-breaking-changes-in-visual-studio-14-ctp1/
+      //               and
+      //               http://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/
+      #if _MSC_VER >= MSC_2015_VER
+          double_output_stream << std::fixed;
+      #else
+          // note that if this function is called from the erlang generator and the MSVC compiler is older than 2015,
+          // the double literal must be output in the scientific format. There can be some cases where the
+          // mantissa of the output does not have fractionals, which is illegal in Erlang.
+          // example => 10000000000000000.0 being output as 1e+16
+          double_output_stream << std::scientific;
+      #endif
+  #else
+      double_output_stream << std::fixed;
+  #endif
+
+  double_output_stream << value;
+
+  return double_output_stream.str();
+}
+
+void t_erl_generator::generate_type_metadata(std::string function_name, vector<string> names) {
+  size_t num_structs = names.size();
+
+  indent(f_types_file_) << function_name << "() ->\n";
+  indent_up();
+  indent(f_types_file_) << "[";
+
+
+  for(size_t i=0; i < num_structs; i++) {
+    f_types_file_ << names.at(i);
+
+    if (i < num_structs - 1) {
+      f_types_file_ << ", ";
+    }
+  }
+
+  f_types_file_ << "].\n\n";
+  indent_down();
+}
+
+/**
+ * Generates a typedef. no op
+ *
+ * @param ttypedef The type definition
+ */
+void t_erl_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+
+void t_erl_generator::generate_const_function(t_const* tconst, ostringstream& exports, ostringstream& functions) {
+  t_type* type = get_true_type(tconst->get_type());
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    string const_fun_name = lowercase(name);
+
+    // Emit const function export.
+    if (exports.tellp() > 0) { exports << ", "; }
+    exports << const_fun_name << "/1, " << const_fun_name << "/2";
+
+    // Emit const function definition.
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator i, end = value->get_map().end();
+    // The one-argument form throws an error if the key does not exist in the map.
+    for (i = value->get_map().begin(); i != end;) {
+      functions << const_fun_name << "(" << render_const_value(ktype, i->first) << ") -> "
+                << render_const_value(vtype, i->second);
+      ++i;
+      functions << (i != end ? ";\n" : ".\n\n");
+    }
+
+    // The two-argument form returns a default value if the key does not exist in the map.
+    for (i = value->get_map().begin(); i != end; ++i) {
+      functions << const_fun_name << "(" << render_const_value(ktype, i->first) << ", _) -> "
+                << render_const_value(vtype, i->second) << ";\n";
+    }
+    functions << const_fun_name << "(_, Default) -> Default.\n\n";
+  } else if (type->is_list()) {
+    string const_fun_name = lowercase(name);
+
+    if (exports.tellp() > 0) { exports << ", "; }
+    exports << const_fun_name << "/1, " << const_fun_name << "/2";
+
+    size_t list_size = value->get_list().size();
+    string rendered_list = render_const_list_values(type, value);
+    functions << const_fun_name << "(N) when N >= 1, N =< " << list_size << " ->\n"
+              << indent_str() << "element(N, {" << rendered_list << "}).\n";
+    functions << const_fun_name << "(N, _) when N >= 1, N =< " << list_size << " ->\n"
+              << indent_str() << "element(N, {" << rendered_list << "});\n"
+              << const_fun_name << "(_, Default) -> Default.\n\n";
+    indent_down();
+  }
+}
+
+void t_erl_generator::generate_const_functions() {
+  ostringstream exports;
+  ostringstream functions;
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = v_consts_.begin(); c_iter != v_consts_.end(); ++c_iter) {
+    generate_const_function(*c_iter, exports, functions);
+  }
+  if (exports.tellp() > 0) {
+    f_consts_file_ << "-export([" << exports.str() << "]).\n\n"
+                   << functions.str();
+  }
+}
+
+
+/**
+ * Generates code for an enumerated type. Done using a class to scope
+ * the values.
+ *
+ * @param tenum The enumeration
+ */
+void t_erl_generator::generate_enum(t_enum* tenum) {
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+
+  v_enums_.push_back(tenum);
+  v_enum_names_.push_back(atomify(tenum->get_name()));
+
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    string name = (*c_iter)->get_name();
+    indent(f_types_hrl_file_) << "-define(" << constify(make_safe_for_module_name(program_name_))
+                              << "_" << constify(tenum->get_name()) << "_" << constify(name) << ", "
+                              << value << ")." << endl;
+  }
+
+  f_types_hrl_file_ << endl;
+}
+
+void t_erl_generator::generate_enum_info(t_enum* tenum){
+  vector<t_enum_value*> constants = tenum->get_constants();
+  size_t num_constants = constants.size();
+
+  indent(f_types_file_) << "enum_info(" << atomify(tenum->get_name()) << ") ->\n";
+  indent_up();
+  indent(f_types_file_) << "[\n";
+
+  for(size_t i=0; i < num_constants; i++) {
+    indent_up();
+    t_enum_value* value = constants.at(i);
+    indent(f_types_file_) << "{" << atomify(value->get_name()) << ", " << value->get_value() << "}";
+
+    if (i < num_constants - 1) {
+      f_types_file_ << ",\n";
+    }
+    indent_down();
+  }
+  f_types_file_ << "\n";
+  indent(f_types_file_) << "];\n\n";
+  indent_down();
+}
+
+void t_erl_generator::generate_enum_metadata() {
+  size_t enum_count = v_enums_.size();
+
+  for(size_t i=0; i < enum_count; i++) {
+    t_enum* tenum = v_enums_.at(i);
+    generate_enum_info(tenum);
+  }
+
+  indent(f_types_file_) << "enum_info(_) -> erlang:error(function_clause).\n\n";
+}
+
+/**
+ * Generate a constant value
+ */
+void t_erl_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  // Save the tconst so that function can be emitted in generate_const_functions().
+  v_consts_.push_back(tconst);
+
+  f_consts_hrl_file_ << "-define(" << constify(make_safe_for_module_name(program_name_)) << "_"
+                     << constify(name) << ", " << render_const_value(type, value) << ")." << endl << 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_erl_generator::render_const_value(t_type* type, t_const_value* value) {
+  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_I8:
+    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 << "float(" << value->get_integer() << ")";
+      } else {
+        out << emit_double_as_string(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 << "#" << type_name(type) << "{";
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+
+    bool first = true;
+    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 (first) {
+        first = false;
+      } else {
+        out << ",";
+      }
+      out << v_iter->first->get_string();
+      out << " = ";
+      out << render_const_value(field_type, v_iter->second);
+    }
+    indent_down();
+    indent(out) << "}";
+
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+
+    if (maps_) {
+      out << "maps:from_list([";
+    } else {
+      out << "dict:from_list([";
+    }
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator i, end = value->get_map().end();
+    for (i = value->get_map().begin(); i != end;) {
+      out << "{" << render_const_value(ktype, i->first) << ","
+          << render_const_value(vtype, i->second) << "}";
+      if (++i != end) {
+        out << ",";
+      }
+    }
+    out << "])";
+  } else if (type->is_set()) {
+    t_type* etype = ((t_set*)type)->get_elem_type();
+    out << "sets:from_list([";
+    vector<t_const_value*>::const_iterator i, end = value->get_list().end();
+    for (i = value->get_list().begin(); i != end;) {
+      out << render_const_value(etype, *i);
+      if (++i != end) {
+        out << ",";
+      }
+    }
+    out << "])";
+  } else if (type->is_list()) {
+    out << "[" << render_const_list_values(type, value) << "]";
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+  return out.str();
+}
+
+string t_erl_generator::render_const_list_values(t_type* type, t_const_value* value) {
+  std::ostringstream out;
+  t_type* etype = ((t_list*)type)->get_elem_type();
+
+  bool first = true;
+  const vector<t_const_value*>& val = value->get_list();
+  vector<t_const_value*>::const_iterator v_iter;
+  for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+    if (first) {
+      first = false;
+    } else {
+      out << ",";
+    }
+    out << render_const_value(etype, *v_iter);
+  }
+  return out.str();
+}
+
+
+string t_erl_generator::render_default_value(t_field* field) {
+  t_type* type = field->get_type();
+  if (type->is_struct() || type->is_xception()) {
+    return "#" + type_name(type) + "{}";
+  } else if (type->is_map()) {
+    if (maps_) {
+      return "#{}";
+    } else {
+      return "dict:new()";
+    }
+  } else if (type->is_set()) {
+    return "sets:new()";
+  } else if (type->is_list()) {
+    return "[]";
+  } else {
+    return "undefined";
+  }
+}
+
+string t_erl_generator::render_member_type(t_field* field) {
+  t_type* type = get_true_type(field->get_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_STRING:
+      return "string() | binary()";
+    case t_base_type::TYPE_BOOL:
+      return "boolean()";
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      return "integer()";
+    case t_base_type::TYPE_DOUBLE:
+      return "float()";
+    default:
+      throw "compiler error: unsupported base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    return "integer()";
+  } else if (type->is_struct() || type->is_xception()) {
+    return type_name(type) + "()";
+  } else if (type->is_map()) {
+    if (maps_) {
+      return "map()";
+    } else if (otp16_) {
+      return "dict()";
+    } else {
+      return "dict:dict()";
+    }
+  } else if (type->is_set()) {
+    if (otp16_) {
+      return "set()";
+    } else {
+      return "sets:set()";
+    }
+  } else if (type->is_list()) {
+    return "list()";
+  } else {
+    throw "compiler error: unsupported type " + type->get_name();
+  }
+}
+
+string t_erl_generator::render_member_requiredness(t_field* field) {
+  switch (field->get_req()) {
+  case t_field::T_REQUIRED:
+    return "required";
+  case t_field::T_OPTIONAL:
+    return "optional";
+  default:
+    return "undefined";
+  }
+}
+
+/**
+ * Generates a struct
+ */
+void t_erl_generator::generate_struct(t_struct* tstruct) {
+  v_struct_names_.push_back(type_name(tstruct));
+  generate_erl_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_erl_generator::generate_xception(t_struct* txception) {
+  v_exception_names_.push_back(type_name(txception));
+  generate_erl_struct(txception, true);
+}
+
+/**
+ * Generates a struct
+ */
+void t_erl_generator::generate_erl_struct(t_struct* tstruct, bool is_exception) {
+  (void)is_exception;
+  generate_erl_struct_definition(f_types_hrl_file_, tstruct);
+  generate_erl_struct_info(f_info_, tstruct);
+  generate_erl_extended_struct_info(f_info_ext_, tstruct);
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_erl_generator::generate_erl_struct_definition(ostream& out, t_struct* tstruct) {
+  indent(out) << "%% struct " << type_name(tstruct) << endl << endl;
+
+  std::stringstream buf;
+  buf << indent() << "-record(" << type_name(tstruct) << ", {";
+  string field_indent(buf.str().size(), ' ');
+
+  const vector<t_field*>& members = tstruct->get_members();
+  for (vector<t_field*>::const_iterator m_iter = members.begin(); m_iter != members.end();) {
+    generate_erl_struct_member(buf, *m_iter);
+    if (++m_iter != members.end()) {
+      buf << "," << endl << field_indent;
+    }
+  }
+  buf << "}).";
+
+  out << buf.str() << endl;
+  out << "-type " + type_name(tstruct) << "() :: #" + type_name(tstruct) + "{}." << endl << endl;
+}
+
+/**
+ * Generates the record field definition
+ */
+
+void t_erl_generator::generate_erl_struct_member(ostream& out, t_field* tmember) {
+  out << atomify(tmember->get_name());
+  if (has_default_value(tmember))
+    out << " = " << render_member_value(tmember);
+  out << " :: " << render_member_type(tmember);
+  if (tmember->get_req() != t_field::T_REQUIRED)
+    out << " | 'undefined'";
+}
+
+bool t_erl_generator::has_default_value(t_field* field) {
+  t_type* type = field->get_type();
+  if (!field->get_value()) {
+    if (field->get_req() == t_field::T_REQUIRED) {
+      if (type->is_struct() || type->is_xception() || type->is_map() || type->is_set()
+          || type->is_list()) {
+        return true;
+      } else {
+        return false;
+      }
+    } else {
+      return false;
+    }
+  } else {
+    return true;
+  }
+}
+
+string t_erl_generator::render_member_value(t_field* field) {
+  if (!field->get_value()) {
+    return render_default_value(field);
+  } else {
+    return render_const_value(field->get_type(), field->get_value());
+  }
+}
+
+/**
+ * Generates the read method for a struct
+ */
+void t_erl_generator::generate_erl_struct_info(ostream& out, t_struct* tstruct) {
+  indent(out) << "struct_info(" << type_name(tstruct) << ") ->" << endl;
+  indent_up();
+  out << indent() << render_type_term(tstruct, true) << ";" << endl;
+  indent_down();
+  out << endl;
+}
+
+void t_erl_generator::generate_erl_extended_struct_info(ostream& out, t_struct* tstruct) {
+  indent(out) << "struct_info_ext(" << type_name(tstruct) << ") ->" << endl;
+  indent_up();
+  out << indent() << render_type_term(tstruct, true, true) << ";" << endl;
+  indent_down();
+  out << endl;
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_erl_generator::generate_service(t_service* tservice) {
+  service_name_ = make_safe_for_module_name(service_name_);
+
+  string f_service_hrl_name = get_out_dir() + service_name_ + "_thrift.hrl";
+  string f_service_name = get_out_dir() + service_name_ + "_thrift.erl";
+  f_service_file_.open(f_service_name.c_str());
+  f_service_hrl_.open(f_service_hrl_name.c_str());
+
+  // Reset service text aggregating stream streams
+  f_service_.str("");
+  export_lines_.str("");
+  export_lines_first_ = true;
+
+  hrl_header(f_service_hrl_, service_name_);
+
+  if (tservice->get_extends() != NULL) {
+    f_service_hrl_ << "-include(\""
+                   << make_safe_for_module_name(tservice->get_extends()->get_name())
+                   << "_thrift.hrl\"). % inherit " << endl;
+  }
+
+  f_service_hrl_ << "-include(\"" << make_safe_for_module_name(program_name_) << "_types.hrl\")."
+                 << endl << endl;
+
+  // Generate the three main parts of the service (well, two for now in PHP)
+  generate_service_helpers(tservice); // cpiro: New Erlang Order
+
+  generate_service_interface(tservice);
+
+  generate_service_metadata(tservice);
+
+  // indent_down();
+
+  f_service_file_ << erl_autogen_comment() << endl << "-module(" << service_name_ << "_thrift)."
+                  << endl << "-behaviour(thrift_service)." << endl << endl << erl_imports() << endl;
+
+  f_service_file_ << "-include(\"" << make_safe_for_module_name(tservice->get_name())
+                  << "_thrift.hrl\")." << endl << endl;
+
+  f_service_file_ << "-export([" << export_lines_.str() << "])." << endl << endl;
+
+  f_service_file_ << f_service_.str();
+
+  hrl_footer(f_service_hrl_, f_service_name);
+
+  // Close service file
+  f_service_file_.close();
+  f_service_hrl_.close();
+}
+
+void t_erl_generator::generate_service_metadata(t_service* tservice) {
+  export_string("function_names", 0);
+  vector<t_function*> functions = tservice->get_functions();
+  size_t num_functions = functions.size();
+
+  indent(f_service_) << "function_names() -> " << endl;
+  indent_up();
+  indent(f_service_) << "[";
+
+  for (size_t i=0; i < num_functions; i++) {
+    t_function* current = functions.at(i);
+    f_service_ << atomify(current->get_name());
+    if (i < num_functions - 1) {
+      f_service_ << ", ";
+    }
+  }
+
+  f_service_ << "].\n\n";
+  indent_down();
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_erl_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  //  indent(f_service_) <<
+  //  "% HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
+
+  export_string("struct_info", 1);
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_erl_function_helpers(*f_iter);
+  }
+  f_service_ << "struct_info(_) -> erlang:error(function_clause)." << endl;
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_erl_generator::generate_erl_function_helpers(t_function* tfunction) {
+  (void)tfunction;
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_erl_generator::generate_service_interface(t_service* tservice) {
+
+  export_string("function_info", 2);
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  f_service_ << "%%% interface" << endl;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << indent() << "% " << function_signature(*f_iter) << endl;
+
+    generate_function_info(tservice, *f_iter);
+  }
+
+  // Inheritance - pass unknown functions to base class
+  if (tservice->get_extends() != NULL) {
+    indent(f_service_) << "function_info(Function, InfoType) ->" << endl;
+    indent_up();
+    indent(f_service_) << make_safe_for_module_name(tservice->get_extends()->get_name())
+                       << "_thrift:function_info(Function, InfoType)." << endl;
+    indent_down();
+  } else {
+    // return function_clause error for non-existent functions
+    indent(f_service_) << "function_info(_Func, _Info) -> erlang:error(function_clause)." << endl;
+  }
+
+  indent(f_service_) << endl;
+}
+
+/**
+ * Generates a function_info(FunctionName, params_type) and
+ * function_info(FunctionName, reply_type)
+ */
+void t_erl_generator::generate_function_info(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+  string name_atom = atomify(tfunction->get_name());
+
+  t_struct* xs = tfunction->get_xceptions();
+  t_struct* arg_struct = tfunction->get_arglist();
+
+  // function_info(Function, params_type):
+  indent(f_service_) << "function_info(" << name_atom << ", params_type) ->" << endl;
+  indent_up();
+
+  indent(f_service_) << render_type_term(arg_struct, true) << ";" << endl;
+
+  indent_down();
+
+  // function_info(Function, reply_type):
+  indent(f_service_) << "function_info(" << name_atom << ", reply_type) ->" << endl;
+  indent_up();
+
+  if (!tfunction->get_returntype()->is_void())
+    indent(f_service_) << render_type_term(tfunction->get_returntype(), false) << ";" << endl;
+  else if (tfunction->is_oneway())
+    indent(f_service_) << "oneway_void;" << endl;
+  else
+    indent(f_service_) << "{struct, []}"
+                       << ";" << endl;
+  indent_down();
+
+  // function_info(Function, exceptions):
+  indent(f_service_) << "function_info(" << name_atom << ", exceptions) ->" << endl;
+  indent_up();
+  indent(f_service_) << render_type_term(xs, true) << ";" << endl;
+  indent_down();
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_erl_generator::function_signature(t_function* tfunction, string prefix) {
+  return prefix + tfunction->get_name() + "(This"
+         + capitalize(argument_list(tfunction->get_arglist())) + ")";
+}
+
+/**
+ * Add a function to the exports list
+ */
+void t_erl_generator::export_string(string name, int num) {
+  if (export_lines_first_) {
+    export_lines_first_ = false;
+  } else {
+    export_lines_ << ", ";
+  }
+  export_lines_ << name << "/" << num;
+}
+
+void t_erl_generator::export_types_string(string name, int num) {
+  if (export_types_lines_first_) {
+    export_types_lines_first_ = false;
+  } else {
+    export_types_lines_ << ", ";
+  }
+  export_types_lines_ << name << "/" << num;
+}
+
+void t_erl_generator::export_function(t_function* tfunction, string prefix) {
+  t_struct::members_type::size_type num = tfunction->get_arglist()->get_members().size();
+  if (num > static_cast<t_struct::members_type::size_type>(std::numeric_limits<int>().max())) {
+    throw "integer overflow in t_erl_generator::export_function, name " + tfunction->get_name();
+  }
+  export_string(prefix + tfunction->get_name(),
+                1 // This
+                + static_cast<int>(num));
+}
+
+/**
+ * Renders a field list
+ */
+string t_erl_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;
+      result += ", "; // initial comma to compensate for initial This
+    } else {
+      result += ", ";
+    }
+    result += capitalize((*f_iter)->get_name());
+  }
+  return result;
+}
+
+string t_erl_generator::type_name(t_type* ttype) {
+  string prefix = ttype->get_program()->get_namespace("erl");
+  size_t prefix_length = prefix.length();
+  if (prefix_length > 0 && prefix[prefix_length - 1] != '_') {
+    prefix += '.';
+  }
+
+  string name = ttype->get_name();
+
+  return atomify(prefix + name);
+}
+
+/**
+ * Converts the parse type to a Erlang "type" (macro for int constants)
+ */
+string t_erl_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 "?tType_STRING";
+    case t_base_type::TYPE_BOOL:
+      return "?tType_BOOL";
+    case t_base_type::TYPE_I8:
+      return "?tType_I8";
+    case t_base_type::TYPE_I16:
+      return "?tType_I16";
+    case t_base_type::TYPE_I32:
+      return "?tType_I32";
+    case t_base_type::TYPE_I64:
+      return "?tType_I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "?tType_DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "?tType_I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "?tType_STRUCT";
+  } else if (type->is_map()) {
+    return "?tType_MAP";
+  } else if (type->is_set()) {
+    return "?tType_SET";
+  } else if (type->is_list()) {
+    return "?tType_LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Generate an Erlang term which represents a thrift type
+ */
+std::string t_erl_generator::render_type_term(t_type* type,
+                                              bool expand_structs,
+                                              bool extended_info) {
+  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 "string";
+    case t_base_type::TYPE_BOOL:
+      return "bool";
+    case t_base_type::TYPE_I8:
+      return "byte";
+    case t_base_type::TYPE_I16:
+      return "i16";
+    case t_base_type::TYPE_I32:
+      return "i32";
+    case t_base_type::TYPE_I64:
+      return "i64";
+    case t_base_type::TYPE_DOUBLE:
+      return "double";
+    }
+  } else if (type->is_enum()) {
+    return "i32";
+  } else if (type->is_struct() || type->is_xception()) {
+    if (expand_structs) {
+
+      std::stringstream buf;
+      buf << "{struct, [";
+      string field_indent(buf.str().size(), ' ');
+
+      t_struct::members_type const& fields = static_cast<t_struct*>(type)->get_members();
+      t_struct::members_type::const_iterator i, end = fields.end();
+      for (i = fields.begin(); i != end;) {
+        t_struct::members_type::value_type member = *i;
+        int32_t key = member->get_key();
+        string type = render_type_term(member->get_type(), false, false); // recursive call
+
+        if (!extended_info) {
+          // Convert to format: {struct, [{Fid, Type}|...]}
+          buf << "{" << key << ", " << type << "}";
+        } else {
+          // Convert to format: {struct, [{Fid, Req, Type, Name, Def}|...]}
+          string name = member->get_name();
+          string value = render_member_value(member);
+          string requiredness = render_member_requiredness(member);
+          buf << "{" << key << ", " << requiredness << ", " << type << ", " << atomify(name) << ", "
+              << value << "}";
+        }
+
+        if (++i != end) {
+          buf << "," << endl << field_indent;
+        }
+      }
+
+      buf << "]}" << endl;
+      return buf.str();
+    } else {
+      return "{struct, {" + atomify(type_module(type)) + ", " + type_name(type) + "}}";
+    }
+  } else if (type->is_map()) {
+    // {map, KeyType, ValType}
+    t_type* key_type = ((t_map*)type)->get_key_type();
+    t_type* val_type = ((t_map*)type)->get_val_type();
+
+    return "{map, " + render_type_term(key_type, false) + ", " + render_type_term(val_type, false)
+           + "}";
+
+  } else if (type->is_set()) {
+    t_type* elem_type = ((t_set*)type)->get_elem_type();
+
+    return "{set, " + render_type_term(elem_type, false) + "}";
+
+  } else if (type->is_list()) {
+    t_type* elem_type = ((t_list*)type)->get_elem_type();
+
+    return "{list, " + render_type_term(elem_type, false) + "}";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+std::string t_erl_generator::type_module(t_type* ttype) {
+  return make_safe_for_module_name(ttype->get_program()->get_name()) + "_types";
+}
+
+THRIFT_REGISTER_GENERATOR(
+    erl,
+    "Erlang",
+    "    legacynames: Output files retain naming conventions of Thrift 0.9.1 and earlier.\n"
+    "    maps:        Generate maps instead of dicts.\n"
+    "    otp16:       Generate non-namespaced dict and set instead of dict:dict and sets:set.\n")
diff --git a/compiler/cpp/src/thrift/generate/t_generator.cc b/compiler/cpp/src/thrift/generate/t_generator.cc
new file mode 100644
index 0000000..ca3f5dd
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_generator.cc
@@ -0,0 +1,262 @@
+/*
+ * 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.
+ */
+
+#include "thrift/generate/t_generator.h"
+using namespace std;
+
+/**
+ * Top level program generation function. Calls the generator subclass methods
+ * for preparing file streams etc. then iterates over all the parts of the
+ * program to perform the correct actions.
+ *
+ * @param program The thrift program to compile into C++ source
+ */
+void t_generator::generate_program() {
+  // Initialize the generator
+  init_generator();
+
+  // Generate enums
+  vector<t_enum*> enums = program_->get_enums();
+  vector<t_enum*>::iterator en_iter;
+  for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+    generate_enum(*en_iter);
+  }
+
+  // Generate typedefs
+  vector<t_typedef*> typedefs = program_->get_typedefs();
+  vector<t_typedef*>::iterator td_iter;
+  for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
+    generate_typedef(*td_iter);
+  }
+
+  // Generate structs, exceptions, and unions in declared order
+  vector<t_struct*> objects = program_->get_objects();
+
+  vector<t_struct*>::iterator o_iter;
+  for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
+    generate_forward_declaration(*o_iter);
+  }
+  for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
+    if ((*o_iter)->is_xception()) {
+      generate_xception(*o_iter);
+    } else {
+      generate_struct(*o_iter);
+    }
+  }
+
+  // Generate constants
+  vector<t_const*> consts = program_->get_consts();
+  generate_consts(consts);
+
+  // Generate services
+  vector<t_service*> services = program_->get_services();
+  vector<t_service*>::iterator sv_iter;
+  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    service_name_ = get_service_name(*sv_iter);
+    generate_service(*sv_iter);
+  }
+
+  // Close the generator
+  close_generator();
+}
+
+std::set<std::string> t_generator::lang_keywords() const {
+  std::string keywords[] = { "BEGIN", "END", "__CLASS__", "__DIR__", "__FILE__", "__FUNCTION__",
+      "__LINE__", "__METHOD__", "__NAMESPACE__", "abstract", "alias", "and", "args", "as",
+      "assert", "begin", "break", "case", "catch", "class", "clone", "continue", "declare",
+      "def", "default", "del", "delete", "do", "dynamic", "elif", "else", "elseif", "elsif",
+      "end", "enddeclare", "endfor", "endforeach", "endif", "endswitch", "endwhile", "ensure",
+      "except", "exec", "finally", "float", "for", "foreach", "from", "function", "global",
+      "goto", "if", "implements", "import", "in", "inline", "instanceof", "interface", "is",
+      "lambda", "module", "native", "new", "next", "nil", "not", "or", "package", "pass",
+      "public", "print", "private", "protected", "raise", "redo", "rescue", "retry", "register",
+      "return", "self", "sizeof", "static", "super", "switch", "synchronized", "then", "this",
+      "throw", "transient", "try", "undef", "unless", "unsigned", "until", "use", "var",
+      "virtual", "volatile", "when", "while", "with", "xor", "yield" };
+  return std::set<std::string>(keywords, keywords + sizeof(keywords)/sizeof(keywords[0]) );
+}
+
+void t_generator::validate_input() const {
+  validate(program_->get_enums());
+  validate(program_->get_typedefs());
+  validate(program_->get_objects());
+  validate(program_->get_consts());
+  validate(program_->get_services());
+}
+
+template <typename T>
+void t_generator::validate(const vector<T>& list) const{
+  typename vector<T>::const_iterator it;
+  for(it=list.begin(); it != list.end(); ++it) {
+      validate(*it);
+  }
+}
+
+void t_generator::validate(t_function const* f) const {
+  validate_id(f->get_name());
+  validate(f->get_arglist());
+  validate(f->get_xceptions());
+}
+
+void t_generator::validate(t_service const* s) const {
+  validate_id(s->get_name());
+  validate(s->get_functions());
+}
+
+void t_generator::validate(t_enum const* en) const {
+  validate_id(en->get_name());
+  validate(en->get_constants());
+}
+void t_generator::validate(t_struct const* s) const {
+  validate_id(s->get_name());
+  validate(s->get_members());
+}
+
+void t_generator::validate(t_enum_value const* en_val) const {
+  validate_id(en_val->get_name());
+}
+void t_generator::validate(t_typedef const* td) const {
+  validate_id(td->get_name());
+}
+void t_generator::validate(t_const const* c) const {
+  validate_id(c->get_name());
+}
+void t_generator::validate(t_field const* f) const {
+  validate_id(f->get_name());
+}
+
+void t_generator::validate_id(const string& id) const {
+  if (keywords_.find(id) != keywords_.end()) {
+    failure("Cannot use reserved language keyword: \"%s\"", id.c_str());
+  }
+}
+
+string t_generator::escape_string(const string& in) const {
+  string result = "";
+  for (string::const_iterator it = in.begin(); it < in.end(); it++) {
+    std::map<char, std::string>::const_iterator res = escape_.find(*it);
+    if (res != escape_.end()) {
+      result.append(res->second);
+    } else {
+      result.push_back(*it);
+    }
+  }
+  return result;
+}
+
+void t_generator::generate_consts(vector<t_const*> consts) {
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    generate_const(*c_iter);
+  }
+}
+
+void t_generator::generate_docstring_comment(ostream& out,
+                                             const string& comment_start,
+                                             const string& line_prefix,
+                                             const string& contents,
+                                             const string& comment_end) {
+  if (!comment_start.empty())
+    indent(out) << comment_start;
+  stringstream docs(contents, ios_base::in);
+  while (!(docs.eof() || docs.fail())) {
+    char line[1024];
+    docs.getline(line, 1024);
+
+    if (strlen(line) > 0) {
+      indent(out) << line_prefix << line << std::endl;
+    } else if (line_prefix.empty()){
+      out << std::endl;
+    } else if(!docs.eof()) {
+      indent(out) << line_prefix << std::endl;
+    }
+  }
+  if (!comment_end.empty())
+    indent(out) << comment_end;
+}
+
+void t_generator_registry::register_generator(t_generator_factory* factory) {
+  gen_map_t& the_map = get_generator_map();
+  if (the_map.find(factory->get_short_name()) != the_map.end()) {
+    failure("Duplicate generators for language \"%s\"!\n", factory->get_short_name().c_str());
+  }
+  the_map[factory->get_short_name()] = factory;
+}
+
+void t_generator::parse_options(const string& options,
+                                string& language,
+                                map<string, string>& parsed_options) {
+  string::size_type colon = options.find(':');
+  language = options.substr(0, colon);
+
+  if (colon != string::npos) {
+    string::size_type pos = colon + 1;
+    while (pos != string::npos && pos < options.size()) {
+      string::size_type next_pos = options.find(',', pos);
+      string option = options.substr(pos, next_pos - pos);
+      pos = ((next_pos == string::npos) ? next_pos : next_pos + 1);
+
+      string::size_type separator = option.find('=');
+      string key, value;
+      if (separator == string::npos) {
+        key = option;
+        value = "";
+      } else {
+        key = option.substr(0, separator);
+        value = option.substr(separator + 1);
+      }
+
+      parsed_options[key] = value;
+    }
+  }
+}
+
+t_generator* t_generator_registry::get_generator(t_program* program,
+                                                 const string& language,
+                                                 const map<string, string>& parsed_options,
+                                                 const std::string& options) {
+  gen_map_t& the_map = get_generator_map();
+  gen_map_t::iterator iter = the_map.find(language);
+
+  if (iter == the_map.end()) {
+    return NULL;
+  }
+
+  return iter->second->get_generator(program, parsed_options, options);
+}
+
+t_generator* t_generator_registry::get_generator(t_program* program, const string& options) {
+  string language;
+  map<string, string> parsed_options;
+  t_generator::parse_options(options, language, parsed_options);
+  return get_generator(program, language, parsed_options, options);
+}
+
+t_generator_registry::gen_map_t& t_generator_registry::get_generator_map() {
+  // http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12
+  static gen_map_t* the_map = new gen_map_t();
+  return *the_map;
+}
+
+t_generator_factory::t_generator_factory(const std::string& short_name,
+                                         const std::string& long_name,
+                                         const std::string& documentation)
+  : short_name_(short_name), long_name_(long_name), documentation_(documentation) {
+  t_generator_registry::register_generator(this);
+}
diff --git a/compiler/cpp/src/thrift/generate/t_generator.h b/compiler/cpp/src/thrift/generate/t_generator.h
new file mode 100644
index 0000000..cb9d076
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_generator.h
@@ -0,0 +1,452 @@
+/*
+ * 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.
+ */
+
+#ifndef T_GENERATOR_H
+#define T_GENERATOR_H
+#define MSC_2015_VER 1900
+
+#include <cstring>
+#include <string>
+#include <iomanip>
+#include <iostream>
+#include <fstream>
+#include <limits>
+#include <sstream>
+#include "thrift/common.h"
+#include "thrift/logging.h"
+#include "thrift/version.h"
+#include "thrift/generate/t_generator_registry.h"
+#include "thrift/parse/t_program.h"
+
+/**
+ * Base class for a thrift code generator. This class defines the basic
+ * routines for code generation and contains the top level method that
+ * dispatches code generation across various components.
+ *
+ */
+class t_generator {
+public:
+  t_generator(t_program* program)
+    : keywords_(lang_keywords()){
+    tmp_ = 0;
+    indent_ = 0;
+    program_ = program;
+    program_name_ = get_program_name(program);
+    escape_['\n'] = "\\n";
+    escape_['\r'] = "\\r";
+    escape_['\t'] = "\\t";
+    escape_['"'] = "\\\"";
+    escape_['\\'] = "\\\\";
+  }
+
+  virtual ~t_generator() {}
+
+  /**
+   * Framework generator method that iterates over all the parts of a program
+   * and performs general actions. This is implemented by the base class and
+   * should not normally be overwritten in the subclasses.
+   */
+  virtual void generate_program();
+
+  const t_program* get_program() const { return program_; }
+
+  void generate_docstring_comment(std::ostream& out,
+                                  const std::string& comment_start,
+                                  const std::string& line_prefix,
+                                  const std::string& contents,
+                                  const std::string& comment_end);
+
+  static void parse_options(const std::string& options, std::string& language,
+                     std::map<std::string, std::string>& parsed_options);
+
+  /**
+   * check whether sub-namespace declaraction is used by generator.
+   * e.g. allow
+   * namespace py.twisted bar
+   * to specify namespace to use when -gen py:twisted is specified.
+   * Will be called with subnamespace, i.e. is_valid_namespace("twisted")
+   * will be called for the above example.
+   */
+  static bool is_valid_namespace(const std::string& sub_namespace) {
+    (void)sub_namespace;
+    return false;
+  }
+
+  /**
+   * Escape string to use one in generated sources.
+   */
+  virtual std::string escape_string(const std::string& in) const;
+
+  std::string get_escaped_string(t_const_value* constval) {
+    return escape_string(constval->get_string());
+  }
+
+  /**
+   * Check if all identifiers are valid for the target language
+   */
+  virtual void validate_input() const;
+
+protected:
+  virtual std::set<std::string> lang_keywords() const;
+
+  /**
+   * A list of reserved words that cannot be used as identifiers.
+   */
+  const std::set<std::string> keywords_;
+
+  virtual void validate_id(const std::string& id) const;
+
+  virtual void validate(t_enum const* en) const;
+  virtual void validate(t_enum_value const* en_val) const;
+  virtual void validate(t_typedef const* td) const;
+  virtual void validate(t_const const* c) const;
+  virtual void validate(t_service const* s) const;
+  virtual void validate(t_struct const* c) const;
+  virtual void validate(t_field const* f) const;
+  virtual void validate(t_function const* f) const;
+
+  template <typename T>
+  void validate(const std::vector<T>& list) const;
+
+  /**
+   * Optional methods that may be implemented by subclasses to take necessary
+   * steps at the beginning or end of code generation.
+   */
+
+  virtual void init_generator() {}
+  virtual void close_generator() {}
+
+  virtual void generate_consts(std::vector<t_const*> consts);
+
+  /**
+   * Pure virtual methods implemented by the generator subclasses.
+   */
+
+  virtual void generate_typedef(t_typedef* ttypedef) = 0;
+  virtual void generate_enum(t_enum* tenum) = 0;
+  virtual void generate_const(t_const* tconst) { (void)tconst; }
+  virtual void generate_struct(t_struct* tstruct) = 0;
+  virtual void generate_service(t_service* tservice) = 0;
+  virtual void generate_forward_declaration(t_struct*) {}
+  virtual void generate_xception(t_struct* txception) {
+    // By default exceptions are the same as structs
+    generate_struct(txception);
+  }
+
+  /**
+   * Method to get the program name, may be overridden
+   */
+  virtual std::string get_program_name(t_program* tprogram) { return tprogram->get_name(); }
+
+  /**
+   * Method to get the service name, may be overridden
+   */
+  virtual std::string get_service_name(t_service* tservice) { return tservice->get_name(); }
+
+  /**
+   * Get the current output directory
+   */
+  virtual std::string get_out_dir() const {
+    if (program_->is_out_path_absolute()) {
+      return program_->get_out_path() + "/";
+    }
+
+    return program_->get_out_path() + out_dir_base_ + "/";
+  }
+
+  /**
+   * Creates a unique temporary variable name, which is just "name" with a
+   * number appended to it (i.e. name35)
+   */
+  std::string tmp(std::string name) {
+    std::ostringstream out;
+    out << name << tmp_++;
+    return out.str();
+  }
+
+  /**
+   * Generates a comment about this code being autogenerated, using C++ style
+   * comments, which are also fair game in Java / PHP, yay!
+   *
+   * @return C-style comment mentioning that this file is autogenerated.
+   */
+  virtual std::string autogen_comment() {
+    return std::string("/**\n") + " * " + autogen_summary() + "\n" + " *\n"
+           + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n"
+           + " *  @generated\n" + " */\n";
+  }
+
+  virtual std::string autogen_summary() {
+    return std::string("Autogenerated by Thrift Compiler (") + THRIFT_VERSION + ")";
+  }
+
+  /**
+   * Indentation level modifiers
+   */
+
+  void indent_up() { ++indent_; }
+
+  void indent_down() { --indent_; }
+
+  /**
+  * Indentation validation helper
+  */
+  int indent_count() { return indent_; }
+
+  void indent_validate( int expected, const char * func_name) {
+    if (indent_ != expected) { 
+      pverbose("Wrong indent count in %s: difference = %i \n", func_name, (expected - indent_));
+    }
+  }
+
+  /**
+   * Indentation print function
+   */
+  std::string indent() {
+    std::string ind = "";
+    int i;
+    for (i = 0; i < indent_; ++i) {
+      ind += indent_str();
+    }
+    return ind;
+  }
+
+  /**
+   * Indentation utility wrapper
+   */
+  std::ostream& indent(std::ostream& os) { return os << indent(); }
+
+  /**
+   * Capitalization helpers
+   */
+  std::string capitalize(std::string in) {
+    in[0] = toupper(in[0]);
+    return in;
+  }
+  std::string decapitalize(std::string in) {
+    in[0] = tolower(in[0]);
+    return in;
+  }
+  static std::string lowercase(std::string in) {
+    for (size_t i = 0; i < in.size(); ++i) {
+      in[i] = tolower(in[i]);
+    }
+    return in;
+  }
+  static std::string uppercase(std::string in) {
+    for (size_t i = 0; i < in.size(); ++i) {
+      in[i] = toupper(in[i]);
+    }
+    return in;
+  }
+
+  /**
+   * Transforms a camel case string to an equivalent one separated by underscores
+   * e.g. aMultiWord -> a_multi_word
+   *      someName   -> some_name
+   *      CamelCase  -> camel_case
+   *      name       -> name
+   *      Name       -> name
+   */
+  std::string underscore(std::string in) {
+    in[0] = tolower(in[0]);
+    for (size_t i = 1; i < in.size(); ++i) {
+      if (isupper(in[i])) {
+        in[i] = tolower(in[i]);
+        in.insert(i, "_");
+      }
+    }
+    return in;
+  }
+
+  /**
+    * Transforms a string with words separated by underscores to a camel case equivalent
+    * e.g. a_multi_word -> aMultiWord
+    *      some_name    ->  someName
+    *      name         ->  name
+    */
+  std::string camelcase(std::string in) {
+    std::ostringstream out;
+    bool underscore = false;
+
+    for (size_t i = 0; i < in.size(); i++) {
+      if (in[i] == '_') {
+        underscore = true;
+        continue;
+      }
+      if (underscore) {
+        out << (char)toupper(in[i]);
+        underscore = false;
+        continue;
+      }
+      out << in[i];
+    }
+
+    return out.str();
+  }
+
+  const std::string emit_double_as_string(const double value) {
+      std::stringstream double_output_stream;
+      // sets the maximum precision: http://en.cppreference.com/w/cpp/io/manip/setprecision
+      // sets the output format to fixed: http://en.cppreference.com/w/cpp/io/manip/fixed (not in scientific notation)
+      double_output_stream << std::setprecision(std::numeric_limits<double>::digits10 + 1);
+
+      #ifdef _MSC_VER
+          // strtod is broken in MSVC compilers older than 2015, so std::fixed fails to format a double literal.
+          // more details: https://blogs.msdn.microsoft.com/vcblog/2014/06/18/
+          //               c-runtime-crt-features-fixes-and-breaking-changes-in-visual-studio-14-ctp1/
+          //               and
+          //               http://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/
+          #if _MSC_VER >= MSC_2015_VER
+              double_output_stream << std::fixed;
+          #endif
+      #else
+          double_output_stream << std::fixed;
+      #endif
+
+      double_output_stream << value;
+
+      return double_output_stream.str();
+  }
+
+public:
+  /**
+   * Get the true type behind a series of typedefs.
+   */
+  static const t_type* get_true_type(const t_type* type) { return type->get_true_type(); }
+  static t_type* get_true_type(t_type* type) { return type->get_true_type(); }
+
+protected:
+  /**
+   * The program being generated
+   */
+  t_program* program_;
+
+  /**
+   * Quick accessor for formatted program name that is currently being
+   * generated.
+   */
+  std::string program_name_;
+
+  /**
+   * Quick accessor for formatted service name that is currently being
+   * generated.
+   */
+  std::string service_name_;
+
+  /**
+   * Output type-specifc directory name ("gen-*")
+   */
+  std::string out_dir_base_;
+
+  /**
+   * Map of characters to escape in string literals.
+   */
+  std::map<char, std::string> escape_;
+
+  virtual std::string indent_str() const {
+    return "  ";
+  }
+
+private:
+  /**
+   * Current code indentation level
+   */
+  int indent_;
+
+  /**
+   * Temporary variable counter, for making unique variable names
+   */
+  int tmp_;
+};
+
+template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
+class template_ofstream_with_content_based_conditional_update : public std::ostringstream {
+public:
+  template_ofstream_with_content_based_conditional_update(): contents_written(false) {}
+
+  template_ofstream_with_content_based_conditional_update(std::string const& output_file_path_)
+  : output_file_path(output_file_path_), contents_written(false) {}
+
+  ~template_ofstream_with_content_based_conditional_update() {
+    if (!contents_written) {
+      close();
+    }
+  }
+
+  void open(std::string const& output_file_path_) {
+    output_file_path = output_file_path_;
+    clear_buf();
+    contents_written = false;
+  }
+
+  void close() {
+    if (contents_written || output_file_path == "")
+      return;
+
+    if (!is_readable(output_file_path)) {
+      dump();
+      return;
+    }
+
+    std::ifstream old_file;
+    old_file.exceptions(old_file.exceptions() | std::ifstream::badbit | std::ifstream::failbit);
+    old_file.open(output_file_path.c_str(), std::ios::in);
+
+    if (old_file) {
+      std::string const old_file_contents(static_cast<std::ostringstream const&>(std::ostringstream() << old_file.rdbuf()).str());
+      old_file.close();
+
+      if (old_file_contents != str()) {
+        dump();
+      }
+    }
+  }
+
+protected:
+  void dump() {
+    std::ofstream out_file;
+    out_file.exceptions(out_file.exceptions() | std::ofstream::badbit | std::ofstream::failbit);
+    try {
+      out_file.open(output_file_path.c_str(), std::ios::out);
+    }
+    catch (const std::ios_base::failure& e) {
+      ::failure("failed to write the output to the file '%s', details: '%s'", output_file_path.c_str(), e.what());
+    }
+    out_file << str();
+    out_file.close();
+    clear_buf();
+    contents_written = true;
+  }
+
+  void clear_buf() {
+    str(std::string());
+  }
+
+  static bool is_readable(std::string const& file_name) {
+    return static_cast<bool>(std::ifstream(file_name.c_str()));
+  }
+
+private:
+  std::string output_file_path;
+  bool contents_written;
+};
+typedef template_ofstream_with_content_based_conditional_update<char> ofstream_with_content_based_conditional_update;
+
+#endif
diff --git a/compiler/cpp/src/thrift/generate/t_generator_registry.h b/compiler/cpp/src/thrift/generate/t_generator_registry.h
new file mode 100644
index 0000000..1f02167
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_generator_registry.h
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+#ifndef T_GENERATOR_REGISTRY_H
+#define T_GENERATOR_REGISTRY_H
+
+class t_generator;
+
+/**
+ * A factory for producing generator classes of a particular language.
+ *
+ * This class is also responsible for:
+ *  - Registering itself with the generator registry.
+ *  - Providing documentation for the generators it produces.
+ */
+class t_generator_factory {
+public:
+  t_generator_factory(const std::string& short_name,
+                      const std::string& long_name,
+                      const std::string& documentation);
+
+  virtual ~t_generator_factory() {}
+
+  virtual t_generator* get_generator(
+      // The program to generate.
+      t_program* program,
+      // Note: parsed_options will not exist beyond the call to get_generator.
+      const std::map<std::string, std::string>& parsed_options,
+      // Note: option_string might not exist beyond the call to get_generator.
+      const std::string& option_string) = 0;
+
+  virtual bool is_valid_namespace(const std::string& sub_namespace) = 0;
+
+  std::string get_short_name() { return short_name_; }
+  std::string get_long_name() { return long_name_; }
+  std::string get_documentation() { return documentation_; }
+
+private:
+  std::string short_name_;
+  std::string long_name_;
+  std::string documentation_;
+};
+
+template <typename generator>
+class t_generator_factory_impl : public t_generator_factory {
+public:
+  t_generator_factory_impl(const std::string& short_name,
+                           const std::string& long_name,
+                           const std::string& documentation)
+    : t_generator_factory(short_name, long_name, documentation) {}
+
+  virtual t_generator* get_generator(t_program* program,
+                                     const std::map<std::string, std::string>& parsed_options,
+                                     const std::string& option_string) {
+    return new generator(program, parsed_options, option_string);
+  }
+
+  virtual bool is_valid_namespace(const std::string& sub_namespace) {
+    return generator::is_valid_namespace(sub_namespace);
+  }
+};
+
+class t_generator_registry {
+public:
+  static void register_generator(t_generator_factory* factory);
+
+  static t_generator* get_generator(t_program* program, const std::string& options);
+  static t_generator* get_generator(t_program* program,
+                                    const std::string& laugnage,
+                                    const std::map<std::string, std::string>& parsed_options,
+                                    const std::string& options);
+
+  typedef std::map<std::string, t_generator_factory*> gen_map_t;
+  static gen_map_t& get_generator_map();
+
+private:
+  t_generator_registry();
+  t_generator_registry(const t_generator_registry&);
+};
+
+#define THRIFT_REGISTER_GENERATOR(language, long_name, doc)                                        \
+  class t_##language##_generator_factory_impl                                                      \
+      : public t_generator_factory_impl<t_##language##_generator> {                                \
+  public:                                                                                          \
+    t_##language##_generator_factory_impl()                                                        \
+      : t_generator_factory_impl<t_##language##_generator>(#language, long_name, doc) {}           \
+  };                                                                                               \
+  static t_##language##_generator_factory_impl _registerer;
+
+#endif
diff --git a/compiler/cpp/src/thrift/generate/t_go_generator.cc b/compiler/cpp/src/thrift/generate/t_go_generator.cc
new file mode 100644
index 0000000..ec16b87
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_go_generator.cc
@@ -0,0 +1,3713 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * This file is programmatically sanitized for style:
+ * astyle --style=1tbs -f -p -H -j -U t_go_generator.cc
+ *
+ * The output of astyle should not be taken unquestioningly, but it is a good
+ * guide for ensuring uniformity and readability.
+ */
+
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <string>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+#include <algorithm>
+#include <clocale>
+#include "thrift/platform.h"
+#include "thrift/version.h"
+#include "thrift/generate/t_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * A helper for automatically formatting the emitted Go code from the Thrift
+ * IDL per the Go style guide.
+ *
+ * Returns:
+ *  - true, if the formatting process succeeded.
+ *  - false, if the formatting process failed, which means the basic output was
+ *           still generated.
+ */
+bool format_go_output(const string& file_path);
+
+const string DEFAULT_THRIFT_IMPORT = "github.com/apache/thrift/lib/go/thrift";
+static std::string package_flag;
+
+/**
+ * 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) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+
+    gen_thrift_import_ = DEFAULT_THRIFT_IMPORT;
+    gen_package_prefix_ = "";
+    package_flag = "";
+    read_write_private_ = false;
+    ignore_initialisms_ = false;
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("package_prefix") == 0) {
+        gen_package_prefix_ = (iter->second);
+      } else if( iter->first.compare("thrift_import") == 0) {
+        gen_thrift_import_ = (iter->second);
+      } else if( iter->first.compare("package") == 0) {
+        package_flag = (iter->second);
+      } else if( iter->first.compare("read_write_private") == 0) {
+        read_write_private_ = true;
+      } else if( iter->first.compare("ignore_initialisms") == 0) {
+        ignore_initialisms_ =  true;
+      } else {
+        throw "unknown option go:" + iter->first;
+      }
+    }
+
+    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, bool opt = false);
+
+  /**
+   * Struct generation code
+   */
+
+  void generate_go_struct(t_struct* tstruct, bool is_exception);
+  void generate_go_struct_definition(std::ostream& out,
+                                     t_struct* tstruct,
+                                     bool is_xception = false,
+                                     bool is_result = false,
+                                     bool is_args = false);
+  void generate_go_struct_initializer(std::ostream& out,
+                                      t_struct* tstruct,
+                                      bool is_args_or_result = false);
+  void generate_isset_helpers(std::ostream& out,
+                              t_struct* tstruct,
+                              const string& tstruct_name,
+                              bool is_result = false);
+  void generate_countsetfields_helper(std::ostream& out,
+                                      t_struct* tstruct,
+                                      const string& tstruct_name,
+                                      bool is_result = false);
+  void generate_go_struct_reader(std::ostream& out,
+                                 t_struct* tstruct,
+                                 const string& tstruct_name,
+                                 bool is_result = false);
+  void generate_go_struct_writer(std::ostream& out,
+                                 t_struct* tstruct,
+                                 const string& tstruct_name,
+                                 bool is_result = false,
+                                 bool uses_countsetfields = false);
+  void generate_go_function_helpers(t_function* tfunction);
+  void get_publicized_name_and_def_value(t_field* tfield,
+                                         string* OUT_pub_name,
+                                         t_const_value** OUT_def_value) const;
+
+  /**
+   * 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::ostream& out,
+                                  t_field* tfield,
+                                  bool declare,
+                                  std::string prefix = "",
+                                  bool inclass = false,
+                                  bool coerceData = false,
+                                  bool inkey = false,
+                                  bool in_container = false);
+
+  void generate_deserialize_struct(std::ostream& out,
+                                   t_struct* tstruct,
+                                   bool is_pointer_field,
+                                   bool declare,
+                                   std::string prefix = "");
+
+  void generate_deserialize_container(std::ostream& out,
+                                      t_type* ttype,
+                                      bool pointer_field,
+                                      bool declare,
+                                      std::string prefix = "");
+
+  void generate_deserialize_set_element(std::ostream& out,
+                                        t_set* tset,
+                                        bool declare,
+                                        std::string prefix = "");
+
+  void generate_deserialize_map_element(std::ostream& out,
+                                        t_map* tmap,
+                                        bool declare,
+                                        std::string prefix = "");
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         bool declare,
+                                         std::string prefix = "");
+
+  void generate_serialize_field(std::ostream& out,
+                                t_field* tfield,
+                                std::string prefix = "",
+                                bool inkey = false);
+
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(std::ostream& out,
+                                    t_type* ttype,
+                                    bool pointer_field,
+                                    std::string prefix = "");
+
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string kiter,
+                                      std::string viter);
+
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  void generate_go_docstring(std::ostream& out, t_struct* tstruct);
+
+  void generate_go_docstring(std::ostream& out, t_function* tfunction);
+
+  void generate_go_docstring(std::ostream& out,
+                             t_doc* tdoc,
+                             t_struct* tstruct,
+                             const char* subheader);
+
+  void generate_go_docstring(std::ostream& out, t_doc* tdoc);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string go_autogen_comment();
+  std::string go_package();
+  std::string go_imports_begin(bool consts);
+  std::string go_imports_end();
+  std::string render_includes(bool consts);
+  std::string render_included_programs(string& unused_protection);
+  std::string render_import_protection();
+  std::string render_fastbinary_includes();
+  std::string declare_argument(t_field* tfield);
+  std::string render_field_initial_value(t_field* tfield, const string& name, bool optional_field);
+  std::string type_name(t_type* ttype);
+  std::string module_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 addError = 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_go_type_with_opt(t_type* ttype,
+                                       bool optional_field);
+  std::string type_to_go_key_type(t_type* ttype);
+  std::string type_to_spec_args(t_type* ttype);
+
+  static std::string get_real_go_module(const t_program* program) {
+
+    if (!package_flag.empty()) {
+      return package_flag;
+    }
+    std::string real_module = program->get_namespace("go");
+    if (!real_module.empty()) {
+      return real_module;
+    }
+
+    return lowercase(program->get_name());
+  }
+
+private:
+  std::string gen_package_prefix_;
+  std::string gen_thrift_import_;
+  bool read_write_private_;
+  bool ignore_initialisms_;
+
+  /**
+   * File streams
+   */
+
+  ofstream_with_content_based_conditional_update f_types_;
+  std::string f_types_name_;
+  ofstream_with_content_based_conditional_update f_consts_;
+  std::string f_consts_name_;
+  std::stringstream f_const_values_;
+
+  std::string package_name_;
+  std::string package_dir_;
+  std::string read_method_name_;
+  std::string write_method_name_;
+
+  std::set<std::string> commonInitialisms;
+
+  std::string camelcase(const std::string& value) const;
+  void fix_common_initialism(std::string& value, int i) const;
+  std::string publicize(const std::string& value, bool is_args_or_result = false) const;
+  std::string privatize(const std::string& value) const;
+  std::string new_prefix(const std::string& value) const;
+  static std::string variable_name_to_go_name(const std::string& value);
+  static bool is_pointer_field(t_field* tfield, bool in_container = false);
+  static bool omit_initialization(t_field* tfield);
+};
+
+// returns true if field initialization can be omitted since it has corresponding go type zero value
+// or default value is not set
+bool t_go_generator::omit_initialization(t_field* tfield) {
+  t_const_value* value = tfield->get_value();
+  if (!value) {
+    return true;
+  }
+  t_type* type = tfield->get_type()->get_true_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:
+      if (type->is_binary()) {
+        //[]byte are always inline
+        return false;
+      }
+      // strings are pointers if has no default
+      return value->get_string().empty();
+
+    case t_base_type::TYPE_BOOL:
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      return value->get_integer() == 0;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        return value->get_integer() == 0;
+      } else {
+        return value->get_double() == 0.;
+      }
+    }
+  }
+  return false;
+}
+
+// Returns true if the type need a reference if used as optional without default
+static bool type_need_reference(t_type* type) {
+  type = type->get_true_type();
+  if (type->is_map() || type->is_set() || type->is_list() || type->is_struct()
+      || type->is_xception() || type->is_binary()) {
+    return false;
+  }
+  return true;
+}
+
+// returns false if field could not use comparison to default value as !IsSet*
+bool t_go_generator::is_pointer_field(t_field* tfield, bool in_container_value) {
+  (void)in_container_value;
+  if (tfield->annotations_.count("cpp.ref") != 0) {
+    return true;
+  }
+  t_type* type = tfield->get_type()->get_true_type();
+  // Structs in containers are pointers
+  if (type->is_struct() || type->is_xception()) {
+    return true;
+  }
+  if (!(tfield->get_req() == t_field::T_OPTIONAL)) {
+    return false;
+  }
+  bool has_default = tfield->get_value();
+  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:
+      if (type->is_binary()) {
+        //[]byte are always inline
+        return false;
+      }
+      // strings are pointers if has no default
+      return !has_default;
+
+    case t_base_type::TYPE_BOOL:
+    case t_base_type::TYPE_I8:
+    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 !has_default;
+    }
+  } else if (type->is_enum()) {
+    return !has_default;
+  } else if (type->is_struct() || type->is_xception()) {
+    return true;
+  } else if (type->is_map()) {
+    return has_default;
+  } else if (type->is_set()) {
+    return has_default;
+  } else if (type->is_list()) {
+    return has_default;
+  } else if (type->is_typedef()) {
+    return has_default;
+  }
+
+  throw "INVALID TYPE IN type_to_go_type: " + type->get_name();
+}
+
+std::string t_go_generator::camelcase(const std::string& value) const {
+  std::string value2(value);
+  std::setlocale(LC_ALL, "C"); // set locale to classic
+
+  // Fix common initialism in first word
+  fix_common_initialism(value2, 0);
+
+  // as long as we are changing things, let's change _ followed by lowercase to
+  // capital and fix common initialisms
+  for (std::string::size_type i = 1; i < value2.size() - 1; ++i) {
+    if (value2[i] == '_') {
+      if (islower(value2[i + 1])) {
+        value2.replace(i, 2, 1, toupper(value2[i + 1]));
+      }
+
+      if (i > static_cast<std::string::size_type>(std::numeric_limits<int>().max())) {
+        throw "integer overflow in t_go_generator::camelcase, value = " + value;
+      }
+      fix_common_initialism(value2, static_cast<int>(i));
+    }
+  }
+
+  return value2;
+}
+
+// Checks to see if the word starting at i in value contains a common initialism
+// and if so replaces it with the upper case version of the word.
+void t_go_generator::fix_common_initialism(std::string& value, int i) const {
+  if (!ignore_initialisms_) {
+    size_t wordLen = value.find('_', i);
+    if (wordLen != std::string::npos) {
+      wordLen -= i;
+    }
+    std::string word = value.substr(i, wordLen);
+    std::transform(word.begin(), word.end(), word.begin(), ::toupper);
+    if (commonInitialisms.find(word) != commonInitialisms.end()) {
+      value.replace(i, word.length(), word);
+    }
+  }
+}
+
+std::string t_go_generator::publicize(const std::string& value, bool is_args_or_result) const {
+  if (value.size() <= 0) {
+    return value;
+  }
+
+  std::string value2(value), prefix;
+
+  string::size_type dot_pos = value.rfind('.');
+  if (dot_pos != string::npos) {
+    prefix = value.substr(0, dot_pos + 1) + prefix;
+    value2 = value.substr(dot_pos + 1);
+  }
+
+  if (!isupper(value2[0])) {
+    value2[0] = toupper(value2[0]);
+  }
+
+  value2 = camelcase(value2);
+
+  // final length before further checks, the string may become longer
+  size_t len_before = value2.length();
+
+  // IDL identifiers may start with "New" which interferes with the CTOR pattern
+  // Adding an extra underscore to all those identifiers solves this
+  if ((len_before >= 3) && (value2.substr(0, 3) == "New")) {
+    value2 += '_';
+  }
+
+  // IDL identifiers may end with "Args"/"Result" which interferes with the implicit service
+  // function structs
+  // Adding another extra underscore to all those identifiers solves this
+  // Suppress this check for the actual helper struct names
+  if (!is_args_or_result) {
+    bool ends_with_args = (len_before >= 4) && (value2.substr(len_before - 4, 4) == "Args");
+    bool ends_with_rslt = (len_before >= 6) && (value2.substr(len_before - 6, 6) == "Result");
+    if (ends_with_args || ends_with_rslt) {
+      value2 += '_';
+    }
+  }
+
+  // Avoid naming collisions with other services
+  if (is_args_or_result) {
+    prefix += publicize(service_name_);
+  }
+
+  return prefix + value2;
+}
+
+std::string t_go_generator::new_prefix(const std::string& value) const {
+  if (value.size() <= 0) {
+    return value;
+  }
+
+  string::size_type dot_pos = value.rfind('.');
+  if (dot_pos != string::npos) {
+    return value.substr(0, dot_pos + 1) + "New" + publicize(value.substr(dot_pos + 1));
+  }
+  return "New" + publicize(value);
+}
+
+std::string t_go_generator::privatize(const std::string& value) const {
+  if (value.size() <= 0) {
+    return value;
+  }
+
+  std::string value2(value);
+
+  if (!islower(value2[0])) {
+    value2[0] = tolower(value2[0]);
+  }
+
+  value2 = camelcase(value2);
+
+  return value2;
+}
+
+std::string t_go_generator::variable_name_to_go_name(const std::string& value) {
+  if (value.size() <= 0) {
+    return value;
+  }
+
+  std::string value2(value);
+  std::transform(value2.begin(), value2.end(), value2.begin(), ::tolower);
+
+  switch (value[0]) {
+  case 'b':
+  case 'B':
+    if (value2 != "break") {
+      return value;
+    }
+
+    break;
+
+  case 'c':
+  case 'C':
+    if (value2 != "case" && value2 != "chan" && value2 != "const" && value2 != "continue") {
+      return value;
+    }
+
+    break;
+
+  case 'd':
+  case 'D':
+    if (value2 != "default" && value2 != "defer") {
+      return value;
+    }
+
+    break;
+
+  case 'e':
+  case 'E':
+    if (value2 != "else" && value2 != "error") {
+      return value;
+    }
+
+    break;
+
+  case 'f':
+  case 'F':
+    if (value2 != "fallthrough" && value2 != "for" && value2 != "func") {
+      return value;
+    }
+
+    break;
+
+  case 'g':
+  case 'G':
+    if (value2 != "go" && value2 != "goto") {
+      return value;
+    }
+
+    break;
+
+  case 'i':
+  case 'I':
+    if (value2 != "if" && value2 != "import" && value2 != "interface") {
+      return value;
+    }
+
+    break;
+
+  case 'm':
+  case 'M':
+    if (value2 != "map") {
+      return value;
+    }
+
+    break;
+
+  case 'p':
+  case 'P':
+    if (value2 != "package") {
+      return value;
+    }
+
+    break;
+
+  case 'r':
+  case 'R':
+    if (value2 != "range" && value2 != "return") {
+      return value;
+    }
+
+    break;
+
+  case 's':
+  case 'S':
+    if (value2 != "select" && value2 != "struct" && value2 != "switch") {
+      return value;
+    }
+
+    break;
+
+  case 't':
+  case 'T':
+    if (value2 != "type") {
+      return value;
+    }
+
+    break;
+
+  case 'v':
+  case 'V':
+    if (value2 != "var") {
+      return value;
+    }
+
+    break;
+
+  default:
+    return value;
+  }
+
+  return value2 + "_a1";
+}
+
+/**
+ * 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();
+
+  // This set is taken from https://github.com/golang/lint/blob/master/lint.go#L692
+  commonInitialisms.insert("API");
+  commonInitialisms.insert("ASCII");
+  commonInitialisms.insert("CPU");
+  commonInitialisms.insert("CSS");
+  commonInitialisms.insert("DNS");
+  commonInitialisms.insert("EOF");
+  commonInitialisms.insert("GUID");
+  commonInitialisms.insert("HTML");
+  commonInitialisms.insert("HTTP");
+  commonInitialisms.insert("HTTPS");
+  commonInitialisms.insert("ID");
+  commonInitialisms.insert("IP");
+  commonInitialisms.insert("JSON");
+  commonInitialisms.insert("LHS");
+  commonInitialisms.insert("QPS");
+  commonInitialisms.insert("RAM");
+  commonInitialisms.insert("RHS");
+  commonInitialisms.insert("RPC");
+  commonInitialisms.insert("SLA");
+  commonInitialisms.insert("SMTP");
+  commonInitialisms.insert("SSH");
+  commonInitialisms.insert("TCP");
+  commonInitialisms.insert("TLS");
+  commonInitialisms.insert("TTL");
+  commonInitialisms.insert("UDP");
+  commonInitialisms.insert("UI");
+  commonInitialisms.insert("UID");
+  commonInitialisms.insert("UUID");
+  commonInitialisms.insert("URI");
+  commonInitialisms.insert("URL");
+  commonInitialisms.insert("UTF8");
+  commonInitialisms.insert("VM");
+  commonInitialisms.insert("XML");
+  commonInitialisms.insert("XSRF");
+  commonInitialisms.insert("XSS");
+
+  // names of read and write methods
+  if (read_write_private_) {
+    read_method_name_ = "read";
+    write_method_name_ = "write";
+  } else {
+    read_method_name_ = "Read";
+    write_method_name_ = "Write";
+  }
+
+  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 files
+  f_types_name_ = package_dir_ + "/" + program_name_ + ".go";
+  f_types_.open(f_types_name_.c_str());
+
+  f_consts_name_ = package_dir_ + "/" + program_name_ + "-consts.go";
+  f_consts_.open(f_consts_name_.c_str());
+
+  // Print header
+  f_types_ << go_autogen_comment() << go_package() << render_includes(false);
+
+  f_consts_ << go_autogen_comment() << go_package() << render_includes(true);
+
+  f_const_values_ << endl << "func init() {" << endl;
+
+  // Create file for the GoUnusedProtection__ variable
+  string f_unused_prot_name_ = package_dir_ + "/" + "GoUnusedProtection__.go";
+  ofstream_with_content_based_conditional_update f_unused_prot_;
+  f_unused_prot_.open(f_unused_prot_name_.c_str());
+  f_unused_prot_ << go_autogen_comment() << go_package() << render_import_protection();
+  f_unused_prot_.close();
+}
+
+
+string t_go_generator::render_included_programs(string& unused_protection) {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = "";
+
+  unused_protection = "";
+
+  string local_namespace = program_->get_namespace("go");
+  for (size_t i = 0; i < includes.size(); ++i) {
+    if (!local_namespace.empty() && local_namespace == includes[i]->get_namespace("go")) {
+      continue;
+    }
+
+    string go_module = get_real_go_module(includes[i]);
+    size_t found = 0;
+    for (size_t j = 0; j < go_module.size(); j++) {
+      // Import statement uses slashes ('/') in namespace
+      if (go_module[j] == '.') {
+        go_module[j] = '/';
+        found = j + 1;
+      }
+    }
+
+    result += "\t\"" + gen_package_prefix_ + go_module + "\"\n";
+    unused_protection += "var _ = " + go_module.substr(found) + ".GoUnusedProtection__\n";
+  }
+
+  return result;
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program.
+ * If consts include the additional imports.
+ */
+string t_go_generator::render_includes(bool consts) {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = "";
+  string unused_prot = "";
+
+  string local_namespace = program_->get_namespace("go");
+  for (size_t i = 0; i < includes.size(); ++i) {
+    if (!local_namespace.empty() && local_namespace == includes[i]->get_namespace("go")) {
+      continue;
+    }
+
+    string go_module = get_real_go_module(includes[i]);
+    size_t found = 0;
+    for (size_t j = 0; j < go_module.size(); j++) {
+      // Import statement uses slashes ('/') in namespace
+      if (go_module[j] == '.') {
+        go_module[j] = '/';
+        found = j + 1;
+      }
+    }
+
+    result += "\t\"" + gen_package_prefix_ + go_module + "\"\n";
+    unused_prot += "var _ = " + go_module.substr(found) + ".GoUnusedProtection__\n";
+  }
+
+  if (includes.size() > 0) {
+    result += "\n";
+  }
+
+  return go_imports_begin(consts) + result + go_imports_end() + unused_prot;
+}
+
+string t_go_generator::render_import_protection() {
+  return string("var GoUnusedProtection__ int;\n\n");
+}
+
+/**
+ * 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
+        std::string() +
+        "// Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\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";
+}
+
+/**
+ * Render the beginning of the import statement.
+ * If consts include the additional imports.
+ */
+string t_go_generator::go_imports_begin(bool consts) {
+  string extra;
+
+  // If not writing constants, and there are enums, need extra imports.
+  if (!consts && get_program()->get_enums().size() > 0) {
+    extra +=
+      "\t\"database/sql/driver\"\n"
+      "\t\"errors\"\n";
+  }
+  return string(
+      "import (\n"
+      "\t\"bytes\"\n"
+      "\t\"context\"\n"
+      "\t\"reflect\"\n"
+      + extra +
+      "\t\"fmt\"\n"
+      "\t\"" + gen_thrift_import_ + "\"\n");
+}
+
+/**
+ * End the import statement, include undscore-assignments
+ *
+ * These "_ =" prevent the go compiler complaining about unused imports.
+ * This will have to do in lieu of more intelligent import statement construction
+ */
+string t_go_generator::go_imports_end() {
+  return string(
+      ")\n\n"
+      "// (needed to ensure safety because of naive import list construction.)\n"
+      "var _ = thrift.ZERO\n"
+      "var _ = fmt.Printf\n"
+      "var _ = context.Background\n"
+      "var _ = reflect.DeepEqual\n"
+      "var _ = bytes.Equal\n\n");
+}
+
+/**
+ * Closes the type files
+ */
+void t_go_generator::close_generator() {
+  f_const_values_ << "}" << endl << endl;
+  f_consts_ << f_const_values_.str();
+
+  // Close types and constants files
+  f_consts_.close();
+  f_types_.close();
+  format_go_output(f_types_name_);
+  format_go_output(f_consts_name_);
+}
+
+/**
+ * Generates a typedef.
+ *
+ * @param ttypedef The type definition
+ */
+void t_go_generator::generate_typedef(t_typedef* ttypedef) {
+  generate_go_docstring(f_types_, ttypedef);
+  string new_type_name(publicize(ttypedef->get_symbolic()));
+  string base_type(type_to_go_type(ttypedef->get_type()));
+
+  if (base_type == new_type_name) {
+    return;
+  }
+
+  f_types_ << "type " << new_type_name << " " << base_type << endl << endl;
+  // Generate a convenience function that converts an instance of a type
+  // (which may be a constant) into a pointer to an instance of a type.
+  f_types_ << "func " << new_type_name << "Ptr(v " << new_type_name << ") *" << new_type_name
+           << " { return &v }" << 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 << " int64" << endl << "const (" << endl;
+
+  to_string_mapping << indent() << "func (p " << tenum_name << ") String() string {" << endl;
+  to_string_mapping << indent() << "  switch p {" << endl;
+
+  from_string_mapping << indent() << "func " << tenum_name << "FromString(s string) (" << tenum_name
+                      << ", error) {" << endl;
+  from_string_mapping << 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) {
+    value = (*c_iter)->get_value();
+
+    string iter_std_name(escape_string((*c_iter)->get_name()));
+    string iter_name((*c_iter)->get_name());
+    f_types_ << indent() << "  " << tenum_name << "_" << iter_name << ' ' << tenum_name << " = "
+             << value << endl;
+    // Dictionaries to/from string names of enums
+    to_string_mapping << indent() << "  case " << tenum_name << "_" << 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 " << tenum_name << "_"
+                          << iter_name << ", nil " << endl;
+    } else {
+      from_string_mapping << indent() << "  case \"" << iter_std_name << "\": return " << tenum_name
+                          << "_" << iter_name << ", nil " << endl;
+    }
+  }
+
+  to_string_mapping << indent() << "  }" << endl;
+  to_string_mapping << indent() << "  return \"<UNSET>\"" << endl;
+  to_string_mapping << indent() << "}" << endl;
+  from_string_mapping << indent() << "  }" << endl;
+  from_string_mapping << indent() << "  return " << tenum_name << "(0),"
+                      << " fmt.Errorf(\"not a valid " << tenum_name << " string\")" << endl;
+  from_string_mapping << indent() << "}" << endl;
+
+  f_types_ << ")" << endl << endl << to_string_mapping.str() << endl << from_string_mapping.str()
+           << endl << endl;
+
+  // Generate a convenience function that converts an instance of an enum
+  // (which may be a constant) into a pointer to an instance of that enum
+  // type.
+  f_types_ << "func " << tenum_name << "Ptr(v " << tenum_name << ") *" << tenum_name
+           << " { return &v }" << endl << endl;
+
+  // Generate MarshalText
+  f_types_ << "func (p " << tenum_name << ") MarshalText() ([]byte, error) {" << endl;
+  f_types_ << "return []byte(p.String()), nil" << endl;
+  f_types_ << "}" << endl << endl;
+
+  // Generate UnmarshalText
+  f_types_ << "func (p *" << tenum_name << ") UnmarshalText(text []byte) error {" << endl;
+  f_types_ << "q, err := " << tenum_name << "FromString(string(text))" << endl;
+  f_types_ << "if (err != nil) {" << endl << "return err" << endl << "}" << endl;
+  f_types_ << "*p = q" << endl;
+  f_types_ << "return nil" << endl;
+  f_types_ << "}" << endl << endl;
+
+  // Generate Scan for sql.Scanner interface
+  f_types_ << "func (p *" << tenum_name << ") Scan(value interface{}) error {" <<endl;
+  f_types_ << "v, ok := value.(int64)" <<endl;
+  f_types_ << "if !ok {" <<endl;
+  f_types_ << "return errors.New(\"Scan value is not int64\")" <<endl;
+  f_types_ << "}" <<endl;
+  f_types_ << "*p = " << tenum_name << "(v)" << endl;
+  f_types_ << "return nil" << endl;
+  f_types_ << "}" << endl << endl;
+
+  // Generate Value for driver.Valuer interface
+  f_types_ << "func (p * " << tenum_name << ") Value() (driver.Value, error) {" <<endl;
+  f_types_ << "  if p == nil {" << endl;
+  f_types_ << "    return nil, nil" << endl;
+  f_types_ << "  }" << endl;
+  f_types_ << "return int64(*p), nil" << endl;
+  f_types_ << "}" << 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_consts_) << "const " << name << " = " << render_const_value(type, value, name) << endl;
+  } else {
+    f_const_values_ << indent() << name << " = " << render_const_value(type, value, name) << endl
+                    << endl;
+
+    f_consts_ << indent() << "var " << name << " " << type_to_go_type(type) << 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, bool opt) {
+  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();
+
+    if (opt) {
+      out << "&(&struct{x ";
+      switch (tbase) {
+        case t_base_type::TYPE_BOOL:
+          out << "bool}{";
+          out << (value->get_integer() > 0 ? "true" : "false");
+          break;
+
+        case t_base_type::TYPE_I8:
+          out << "int8}{";
+          out << value->get_integer();
+          break;
+        case t_base_type::TYPE_I16:
+          out << "int16}{";
+          out << value->get_integer();
+          break;
+        case t_base_type::TYPE_I32:
+          out << "int32}{";
+          out << value->get_integer();
+          break;
+        case t_base_type::TYPE_I64:
+          out << "int64}{";
+          out << value->get_integer();
+          break;
+
+        case t_base_type::TYPE_DOUBLE:
+          out << "float64}{";
+          if (value->get_type() == t_const_value::CV_INTEGER) {
+            out << value->get_integer();
+          } else {
+            out << value->get_double();
+          }
+          break;
+
+        case t_base_type::TYPE_STRING:
+          out << "string}{";
+          out << '"' + get_escaped_string(value) + '"';
+          break;
+
+        default:
+          throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+      }
+      out << "}).x";
+    } else {
+      switch (tbase) {
+        case t_base_type::TYPE_STRING:
+          if (type->is_binary()) {
+            out << "[]byte(\"" << get_escaped_string(value) << "\")";
+          } else {
+            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_I8:
+        case t_base_type::TYPE_I16:
+        case t_base_type::TYPE_I32:
+        case t_base_type::TYPE_I64:
+          if (opt) {
+            out << "&(&struct{x int}{";
+          }
+          out << value->get_integer();
+          if (opt) {
+            out << "}).x";
+          }
+          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 << "&" << publicize(type_name(type)) << "{";
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_type* field_type = NULL;
+      bool is_optional = false;
+      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();
+          is_optional = is_pointer_field(*f_iter);
+        }
+      }
+
+      if (field_type == NULL) {
+        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+      }
+      out << endl << indent() << publicize(v_iter->first->get_string()) << ": "
+          << render_const_value(field_type, v_iter->second, name, is_optional) << "," << endl;
+    }
+
+    indent_down();
+    out << "}";
+
+  } 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*, t_const_value::value_compare>& val = value->get_map();
+    out << "map[" << type_to_go_type(ktype) << "]" << type_to_go_type(vtype) << "{" << endl;
+    indent_up();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent() << render_const_value(ktype, v_iter->first, name) << ": "
+          << render_const_value(vtype, v_iter->second, name) << "," << endl;
+    }
+
+    indent_down();
+    out << indent() << "}";
+  } else if (type->is_list()) {
+    t_type* etype = ((t_list*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    out << "[]" << type_to_go_type(etype) << "{" << endl;
+    indent_up();
+    vector<t_const_value*>::const_iterator v_iter;
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent() << render_const_value(etype, *v_iter, name) << ", ";
+    }
+
+    indent_down();
+    out << indent() << "}";
+  } else if (type->is_set()) {
+    t_type* etype = ((t_set*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    out << "[]" << type_to_go_key_type(etype) << "{" << endl;
+    indent_up();
+    vector<t_const_value*>::const_iterator v_iter;
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent() << render_const_value(etype, *v_iter, name) << ", ";
+    }
+
+    indent_down();
+    out << indent() << "}";
+  } 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);
+}
+
+void t_go_generator::get_publicized_name_and_def_value(t_field* tfield,
+                                                       string* OUT_pub_name,
+                                                       t_const_value** OUT_def_value) const {
+  const string base_field_name = tfield->get_name();
+  const string escaped_field_name = escape_string(base_field_name);
+  *OUT_pub_name = publicize(escaped_field_name);
+  *OUT_def_value = tfield->get_value();
+}
+
+void t_go_generator::generate_go_struct_initializer(ostream& out,
+                                                    t_struct* tstruct,
+                                                    bool is_args_or_result) {
+  out << publicize(type_name(tstruct), is_args_or_result) << "{";
+  const vector<t_field*>& members = tstruct->get_members();
+  for (vector<t_field*>::const_iterator m_iter = members.begin(); m_iter != members.end();
+       ++m_iter) {
+    bool pointer_field = is_pointer_field(*m_iter);
+    string publicized_name;
+    t_const_value* def_value;
+    get_publicized_name_and_def_value(*m_iter, &publicized_name, &def_value);
+    if (!pointer_field && def_value != NULL && !omit_initialization(*m_iter)) {
+      out << endl << indent() << publicized_name << ": "
+          << render_field_initial_value(*m_iter, (*m_iter)->get_name(), pointer_field) << ","
+          << endl;
+    }
+  }
+
+  out << "}" << endl;
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_go_generator::generate_go_struct_definition(ostream& out,
+                                                   t_struct* tstruct,
+                                                   bool is_exception,
+                                                   bool is_result,
+                                                   bool is_args) {
+  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;
+
+  std::string tstruct_name(publicize(tstruct->get_name(), is_args || is_result));
+  generate_go_docstring(out, tstruct);
+  out << indent() << "type " << tstruct_name << " struct {" << 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();
+
+  int num_setable = 0;
+  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) {
+      // Set field to optional if field is union, this is so we can get a
+      // pointer to the field.
+      if (tstruct->is_union())
+        (*m_iter)->set_req(t_field::T_OPTIONAL);
+      if (sorted_keys_pos != (*m_iter)->get_key()) {
+        int first_unused = (std::max)(1, sorted_keys_pos++);
+        while (sorted_keys_pos != (*m_iter)->get_key()) {
+          ++sorted_keys_pos;
+        }
+        int last_unused = sorted_keys_pos - 1;
+        if (first_unused < last_unused) {
+          indent(out) << "// unused fields # " << first_unused << " to " << last_unused << endl;
+        } else if (first_unused == last_unused) {
+          indent(out) << "// unused field # " << first_unused << endl;
+        }
+      }
+
+      t_type* fieldType = (*m_iter)->get_type();
+      string goType = type_to_go_type_with_opt(fieldType, is_pointer_field(*m_iter));
+      string gotag = "db:\"" + escape_string((*m_iter)->get_name())  + "\" ";
+      if ((*m_iter)->get_req() == t_field::T_OPTIONAL) {
+        gotag += "json:\"" + escape_string((*m_iter)->get_name()) + ",omitempty\"";
+      } else {
+        gotag += "json:\"" + escape_string((*m_iter)->get_name()) + "\"";
+      }
+
+      // Check for user override of db and json tags using "go.tag"
+      std::map<string, string>::iterator it = (*m_iter)->annotations_.find("go.tag");
+      if (it != (*m_iter)->annotations_.end()) {
+        gotag = it->second;
+      }
+      indent(out) << publicize((*m_iter)->get_name()) << " " << goType << " `thrift:\""
+                  << escape_string((*m_iter)->get_name()) << "," << sorted_keys_pos;
+      if ((*m_iter)->get_req() == t_field::T_REQUIRED) {
+        out << ",required";
+      }
+
+      out << "\" " << gotag << "`" << 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_go_type((*m_iter)->get_type()) << endl;
+    }
+  }
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+  out << indent() << "func New" << tstruct_name << "() *" << tstruct_name << " {" << endl;
+  out << indent() << "  return &";
+  generate_go_struct_initializer(out, tstruct, is_result || is_args);
+  out << indent() << "}" << endl << endl;
+  // Default values for optional fields
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    string publicized_name;
+    t_const_value* def_value;
+    get_publicized_name_and_def_value(*m_iter, &publicized_name, &def_value);
+    t_type* fieldType = (*m_iter)->get_type();
+    string goType = type_to_go_type_with_opt(fieldType, false);
+    string def_var_name = tstruct_name + "_" + publicized_name + "_DEFAULT";
+    if ((*m_iter)->get_req() == t_field::T_OPTIONAL || is_pointer_field(*m_iter)) {
+      out << indent() << "var " << def_var_name << " " << goType;
+      if (def_value != NULL) {
+        out << " = " << render_const_value(fieldType, def_value, (*m_iter)->get_name());
+      }
+      out << endl;
+    }
+
+    // num_setable is used for deciding if Count* methods will be generated for union fields.
+    // This applies to all nullable fields including slices (used for set, list and binary) and maps, not just pointers.
+    t_type* type = fieldType->get_true_type();
+    if (is_pointer_field(*m_iter)|| type->is_map() || type->is_set() || type->is_list() || type->is_binary()) {
+      num_setable += 1;
+    }
+
+    if (is_pointer_field(*m_iter)) {
+      string goOptType = type_to_go_type_with_opt(fieldType, true);
+      string maybepointer = goOptType != goType ? "*" : "";
+      out << indent() << "func (p *" << tstruct_name << ") Get" << publicized_name << "() "
+          << goType << " {" << endl;
+      out << indent() << "  if !p.IsSet" << publicized_name << "() {" << endl;
+      out << indent() << "    return " << def_var_name << endl;
+      out << indent() << "  }" << endl;
+      out << indent() << "return " << maybepointer << "p." << publicized_name << endl;
+      out << indent() << "}" << endl;
+    } else {
+      out << endl;
+      out << indent() << "func (p *" << tstruct_name << ") Get" << publicized_name << "() "
+          << goType << " {" << endl;
+      out << indent() << "  return p." << publicized_name << endl;
+      out << indent() << "}" << endl;
+    }
+  }
+
+  if (tstruct->is_union() && num_setable > 0) {
+    generate_countsetfields_helper(out, tstruct, tstruct_name, is_result);
+  }
+
+  generate_isset_helpers(out, tstruct, tstruct_name, is_result);
+  generate_go_struct_reader(out, tstruct, tstruct_name, is_result);
+  generate_go_struct_writer(out, tstruct, tstruct_name, is_result, num_setable > 0);
+
+  out << indent() << "func (p *" << tstruct_name << ") String() string {" << endl;
+  out << indent() << "  if p == nil {" << endl;
+  out << indent() << "    return \"<nil>\"" << endl;
+  out << indent() << "  }" << endl;
+  out << indent() << "  return fmt.Sprintf(\"" << escape_string(tstruct_name) << "(%+v)\", *p)"
+      << endl;
+  out << indent() << "}" << endl << endl;
+
+  if (is_exception) {
+    out << indent() << "func (p *" << tstruct_name << ") Error() string {" << endl;
+    out << indent() << "  return p.String()" << endl;
+    out << indent() << "}" << endl << endl;
+  }
+}
+
+/**
+ * Generates the IsSet helper methods for a struct
+ */
+void t_go_generator::generate_isset_helpers(ostream& out,
+                                            t_struct* tstruct,
+                                            const string& tstruct_name,
+                                            bool is_result) {
+  (void)is_result;
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  const string escaped_tstruct_name(escape_string(tstruct->get_name()));
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    const string field_name(publicize(escape_string((*f_iter)->get_name())));
+    if ((*f_iter)->get_req() == t_field::T_OPTIONAL || is_pointer_field(*f_iter)) {
+      out << indent() << "func (p *" << tstruct_name << ") IsSet" << field_name << "() bool {"
+          << endl;
+      indent_up();
+      t_type* ttype = (*f_iter)->get_type()->get_true_type();
+      bool is_byteslice = ttype->is_binary();
+      bool compare_to_nil_only = ttype->is_set() || ttype->is_list() || ttype->is_map()
+                                 || (is_byteslice && !(*f_iter)->get_value());
+      if (is_pointer_field(*f_iter) || compare_to_nil_only) {
+        out << indent() << "return p." << field_name << " != nil" << endl;
+      } else {
+        string def_var_name = tstruct_name + "_" + field_name + "_DEFAULT";
+        if (is_byteslice) {
+          out << indent() << "return !bytes.Equal(p." << field_name << ", " << def_var_name << ")"
+              << endl;
+        } else {
+          out << indent() << "return p." << field_name << " != " << def_var_name << endl;
+        }
+      }
+      indent_down();
+      out << indent() << "}" << endl << endl;
+    }
+  }
+}
+
+/**
+ * Generates the CountSetFields helper method for a struct
+ */
+void t_go_generator::generate_countsetfields_helper(ostream& out,
+                                                    t_struct* tstruct,
+                                                    const string& tstruct_name,
+                                                    bool is_result) {
+  (void)is_result;
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  const string escaped_tstruct_name(escape_string(tstruct->get_name()));
+
+  out << indent() << "func (p *" << tstruct_name << ") CountSetFields" << tstruct_name << "() int {"
+      << endl;
+  indent_up();
+  out << indent() << "count := 0" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED)
+      continue;
+
+    t_type* type = (*f_iter)->get_type()->get_true_type();
+
+    if (!(is_pointer_field(*f_iter) || type->is_map() || type->is_set() || type->is_list() || type->is_binary()))
+      continue;
+
+    const string field_name(publicize(escape_string((*f_iter)->get_name())));
+
+    out << indent() << "if (p.IsSet" << field_name << "()) {" << endl;
+    indent_up();
+    out << indent() << "count++" << endl;
+    indent_down();
+    out << indent() << "}" << endl;
+  }
+
+  out << indent() << "return count" << endl << endl;
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates the read method for a struct
+ */
+void t_go_generator::generate_go_struct_reader(ostream& out,
+                                               t_struct* tstruct,
+                                               const string& tstruct_name,
+                                               bool is_result) {
+  (void)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_method_name_ << "(iprot thrift.TProtocol) error {"
+      << endl;
+  indent_up();
+  out << indent() << "if _, err := iprot.ReadStructBegin(); err != nil {" << endl;
+  out << indent() << "  return thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)"
+      << endl;
+  out << indent() << "}" << endl << endl;
+
+  // Required variables does not have IsSet functions, so we need tmp vars to check them.
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      const string field_name(publicize(escape_string((*f_iter)->get_name())));
+      indent(out) << "var isset" << field_name << " bool = false;" << endl;
+    }
+  }
+  out << endl;
+
+  // Loop over reading in fields
+  indent(out) << "for {" << endl;
+  indent_up();
+  // Read beginning field marker
+  out << indent() << "_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()" << endl;
+  out << indent() << "if err != nil {" << endl;
+  out << indent() << "  return thrift.PrependError(fmt.Sprintf("
+                     "\"%T field %d read error: \", p, fieldId), err)" << endl;
+  out << indent() << "}" << endl;
+  // Check for field STOP marker and break
+  out << indent() << "if fieldTypeId == thrift.STOP { break; }" << endl;
+
+  string thriftFieldTypeId;
+  // Generate deserialization code for known cases
+  int32_t field_id = -1;
+
+  // Switch statement on the field we are reading, false if no fields present
+  bool have_switch = !fields.empty();
+  if (have_switch) {
+    indent(out) << "switch fieldId {" << endl;
+  }
+
+  // All the fields we know
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    field_id = (*f_iter)->get_key();
+
+    // if negative id, ensure we generate a valid method name
+    string field_method_prefix("ReadField");
+    int32_t field_method_suffix = field_id;
+
+    if (field_method_suffix < 0) {
+      field_method_prefix += "_";
+      field_method_suffix *= -1;
+    }
+
+    out << indent() << "case " << field_id << ":" << endl;
+    indent_up();
+    thriftFieldTypeId = type_to_enum((*f_iter)->get_type());
+
+    if (thriftFieldTypeId == "thrift.BINARY") {
+      thriftFieldTypeId = "thrift.STRING";
+    }
+
+    out << indent() << "if fieldTypeId == " << thriftFieldTypeId << " {" << endl;
+    out << indent() << "  if err := p." << field_method_prefix << field_method_suffix << "(iprot); err != nil {"
+        << endl;
+    out << indent() << "    return err" << endl;
+    out << indent() << "  }" << endl;
+
+    // Mark required field as read
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      const string field_name(publicize(escape_string((*f_iter)->get_name())));
+      out << indent() << "  isset" << field_name << " = true" << endl;
+    }
+
+    out << indent() << "} else {" << endl;
+    out << indent() << "  if err := iprot.Skip(fieldTypeId); err != nil {" << endl;
+    out << indent() << "    return err" << endl;
+    out << indent() << "  }" << endl;
+    out << indent() << "}" << endl;
+
+
+    indent_down();
+  }
+
+  // Begin switch default case
+  if (have_switch) {
+    out << indent() << "default:" << endl;
+    indent_up();
+  }
+
+  // Skip unknown fields in either case
+  out << indent() << "if err := iprot.Skip(fieldTypeId); err != nil {" << endl;
+  out << indent() << "  return err" << endl;
+  out << indent() << "}" << endl;
+
+  // End switch default case
+  if (have_switch) {
+    indent_down();
+    out << indent() << "}" << endl;
+  }
+
+  // Read field end marker
+  out << indent() << "if err := iprot.ReadFieldEnd(); err != nil {" << endl;
+  out << indent() << "  return err" << endl;
+  out << indent() << "}" << endl;
+  indent_down();
+  out << indent() << "}" << endl;
+  out << indent() << "if err := iprot.ReadStructEnd(); err != nil {" << endl;
+  out << indent() << "  return thrift.PrependError(fmt.Sprintf("
+                     "\"%T read struct end error: \", p), err)" << endl;
+  out << indent() << "}" << endl;
+
+  // Return error if any required fields are missing.
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      const string field_name(publicize(escape_string((*f_iter)->get_name())));
+      out << indent() << "if !isset" << field_name << "{" << endl;
+      out << indent() << "  return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, "
+                         "fmt.Errorf(\"Required field " << field_name << " is not set\"));" << endl;
+      out << indent() << "}" << endl;
+    }
+  }
+
+  out << indent() << "return nil" << 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()));
+    string field_method_prefix("ReadField");
+    int32_t field_id = (*f_iter)->get_key();
+    int32_t field_method_suffix = field_id;
+
+    if (field_method_suffix < 0) {
+      field_method_prefix += "_";
+      field_method_suffix *= -1;
+    }
+
+    out << indent() << "func (p *" << tstruct_name << ")  " << field_method_prefix << field_method_suffix
+        << "(iprot thrift.TProtocol) error {" << endl;
+    indent_up();
+    generate_deserialize_field(out, *f_iter, false, "p.");
+    indent_down();
+    out << indent() << "  return nil" << endl;
+    out << indent() << "}" << endl << endl;
+  }
+}
+
+void t_go_generator::generate_go_struct_writer(ostream& out,
+                                               t_struct* tstruct,
+                                               const string& tstruct_name,
+                                               bool is_result,
+                                               bool uses_countsetfields) {
+  (void)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_method_name_ << "(oprot thrift.TProtocol) error {" << endl;
+  indent_up();
+  if (tstruct->is_union() && uses_countsetfields) {
+    std::string tstruct_name(publicize(tstruct->get_name()));
+    out << indent() << "if c := p.CountSetFields" << tstruct_name << "(); c != 1 {" << endl
+        << indent()
+        << "  return fmt.Errorf(\"%T write union: exactly one field must be set (%d set).\", p, c)"
+        << endl << indent() << "}" << endl;
+  }
+  out << indent() << "if err := oprot.WriteStructBegin(\"" << name << "\"); err != nil {" << endl;
+  out << indent() << "  return thrift.PrependError(fmt.Sprintf("
+                     "\"%T write struct begin error: \", p), err) }" << endl;
+
+  string field_name;
+  string escape_field_name;
+  // t_const_value* field_default_value;
+  t_field::e_req field_required;
+  int32_t field_id = -1;
+
+  out << indent() << "if p != nil {" << endl;
+  indent_up();
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    string field_method_prefix("writeField");
+    field_name = (*f_iter)->get_name();
+    escape_field_name = escape_string(field_name);
+    field_id = (*f_iter)->get_key();
+    int32_t field_method_suffix = field_id;
+
+    if (field_method_suffix < 0) {
+      field_method_prefix += "_";
+      field_method_suffix *= -1;
+    }
+
+    out << indent() << "if err := p." << field_method_prefix << field_method_suffix
+        << "(oprot); err != nil { return err }" << endl;
+  }
+
+  indent_down();
+  out << indent() << "}" << endl;
+
+  // Write the struct map
+  out << indent() << "if err := oprot.WriteFieldStop(); err != nil {" << endl;
+  out << indent() << "  return thrift.PrependError(\"write field stop error: \", err) }" << endl;
+  out << indent() << "if err := oprot.WriteStructEnd(); err != nil {" << endl;
+  out << indent() << "  return thrift.PrependError(\"write struct stop error: \", err) }" << endl;
+  out << indent() << "return nil" << endl;
+  indent_down();
+  out << indent() << "}" << endl << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    string field_method_prefix("writeField");
+    field_id = (*f_iter)->get_key();
+    field_name = (*f_iter)->get_name();
+    escape_field_name = escape_string(field_name);
+    // field_default_value = (*f_iter)->get_value();
+    field_required = (*f_iter)->get_req();
+    int32_t field_method_suffix = field_id;
+
+    if (field_method_suffix < 0) {
+      field_method_prefix += "_";
+      field_method_suffix *= -1;
+    }
+
+    out << indent() << "func (p *" << tstruct_name << ") " << field_method_prefix << field_method_suffix
+        << "(oprot thrift.TProtocol) (err error) {" << endl;
+    indent_up();
+
+    if (field_required == t_field::T_OPTIONAL) {
+      out << indent() << "if p.IsSet" << publicize(field_name) << "() {" << endl;
+      indent_up();
+    }
+
+    out << indent() << "if err := oprot.WriteFieldBegin(\"" << escape_field_name << "\", "
+        << type_to_enum((*f_iter)->get_type()) << ", " << field_id << "); err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(fmt.Sprintf(\"%T write field begin error "
+        << field_id << ":" << escape_field_name << ": \", p), err) }" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "p.");
+
+    // Write field closer
+    out << indent() << "if err := oprot.WriteFieldEnd(); err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(fmt.Sprintf(\"%T write field end error "
+        << field_id << ":" << escape_field_name << ": \", p), err) }" << endl;
+
+    if (field_required == t_field::T_OPTIONAL) {
+      indent_down();
+      out << indent() << "}" << endl;
+    }
+
+    indent_down();
+    out << indent() << "  return err" << endl;
+    out << indent() << "}" << endl << endl;
+  }
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_go_generator::generate_service(t_service* tservice) {
+  string test_suffix("_test");
+  string filename = lowercase(service_name_);
+  string f_service_name;
+
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+  generate_service_remote(tservice);
+  f_types_ << endl;
+}
+
+/**
+ * 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_types_ << "// 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_types_, ts, false, false, true);
+    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 (!tfunction->is_oneway()) {
+    t_struct result(program_, tfunction->get_name() + "_result");
+    t_field success(tfunction->get_returntype(), "success", 0);
+    success.set_req(t_field::T_OPTIONAL);
+
+    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) {
+      t_field* f = *f_iter;
+      f->set_req(t_field::T_OPTIONAL);
+      result.append(f);
+    }
+
+    generate_go_struct_definition(f_types_, &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 = 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)
+                   + publicize(extends.substr(index + 1)) + "\n";
+    } else {
+      extends_if = "\n" + indent() + publicize(extends) + "\n";
+    }
+  }
+
+  f_types_ << indent() << "type " << interfaceName << " interface {" << extends_if;
+  indent_up();
+  generate_go_docstring(f_types_, tservice);
+  vector<t_function*> functions = tservice->get_functions();
+
+  if (!functions.empty()) {
+    f_types_ << endl;
+    vector<t_function*>::iterator f_iter;
+
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      generate_go_docstring(f_types_, (*f_iter));
+      f_types_ << indent() << function_signature_if(*f_iter, "", true) << endl;
+    }
+  }
+
+  indent_down();
+  f_types_ << 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_field = "";
+  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;
+    }
+  }
+
+  extends_field = extends_client.substr(extends_client.find(".") + 1);
+
+  generate_go_docstring(f_types_, tservice);
+  f_types_ << indent() << "type " << serviceName << "Client struct {" << endl;
+  indent_up();
+
+  if (!extends_client.empty()) {
+    f_types_ << indent() << "*" << extends_client << endl;
+  } else {
+    f_types_ << indent() << "c thrift.TClient" << endl;
+  }
+
+  indent_down();
+  f_types_ << indent() << "}" << endl << endl;
+
+  // Legacy constructor function
+  f_types_ << indent() << "func New" << serviceName
+             << "ClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *" << serviceName
+             << "Client {" << endl;
+  indent_up();
+  f_types_ << indent() << "return &" << serviceName << "Client";
+
+  if (!extends.empty()) {
+    f_types_ << "{" << extends_field << ": " << extends_client_new << "Factory(t, f)}";
+  } else {
+    indent_up();
+    f_types_ << "{" << endl;
+    f_types_ << indent() << "c: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t))," << endl;
+    indent_down();
+    f_types_ << indent() << "}" << endl;
+  }
+
+  indent_down();
+  f_types_ << indent() << "}" << endl << endl;
+  // Legacy constructor function with custom input & output protocols
+  f_types_
+      << indent() << "func New" << serviceName
+      << "ClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *"
+      << serviceName << "Client {" << endl;
+  indent_up();
+  f_types_ << indent() << "return &" << serviceName << "Client";
+
+  if (!extends.empty()) {
+    f_types_ << "{" << extends_field << ": " << extends_client_new << "Protocol(t, iprot, oprot)}"
+               << endl;
+  } else {
+    indent_up();
+    f_types_ << "{" << endl;
+    f_types_ << indent() << "c: thrift.NewTStandardClient(iprot, oprot)," << endl;
+    indent_down();
+    f_types_ << indent() << "}" << endl;
+  }
+
+  indent_down();
+  f_types_ << indent() << "}" << endl << endl;
+
+  // Constructor function
+  f_types_ << indent() << "func New" << serviceName
+    << "Client(c thrift.TClient) *" << serviceName << "Client {" << endl;
+  indent_up();
+  f_types_ << indent() << "return &" << serviceName << "Client{" << endl;
+
+  indent_up();
+  if (!extends.empty()) {
+    f_types_ << indent() << extends_field << ": " << extends_client_new << "(c)," << endl;
+  } else {
+    f_types_ << indent() << "c: c," << endl;
+  }
+  indent_down();
+  f_types_ << indent() << "}" << endl;
+
+  indent_down();
+  f_types_ << indent() << "}" << endl << endl;
+
+  if (extends.empty()) {
+    f_types_ << indent() << "func (p *" << serviceName << "Client) Client_() thrift.TClient {" << endl;
+    indent_up();
+    f_types_ << indent() << "return p.c" << endl;
+    indent_down();
+    f_types_ << indent() << "}" << 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_types_, (*f_iter));
+    f_types_ << indent() << "func (p *" << serviceName << "Client) "
+               << function_signature_if(*f_iter, "", true) << " {" << endl;
+    indent_up();
+
+    std::string method = (*f_iter)->get_name();
+    std::string argsType = publicize(method + "_args", true);
+    std::string argsName = tmp("_args");
+    f_types_ << indent() << "var " << argsName << " " << argsType << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_types_ << indent() << argsName << "." << publicize((*fld_iter)->get_name())
+               << " = " << variable_name_to_go_name((*fld_iter)->get_name()) << endl;
+    }
+
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultName = tmp("_result");
+      std::string resultType = publicize(method + "_result", true);
+      f_types_ << indent() << "var " << resultName << " " << resultType << endl;
+      f_types_ << indent() << "if err = p.Client_().Call(ctx, \""
+        << method << "\", &" << argsName << ", &" << resultName << "); err != nil {" << endl;
+
+      indent_up();
+      f_types_ << indent() << "return" << endl;
+      indent_down();
+      f_types_ << indent() << "}" << endl;
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+
+      if (!xceptions.empty()) {
+        f_types_ << indent() << "switch {" << endl;
+
+        for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+          const std::string pubname = publicize((*x_iter)->get_name());
+          const std::string field = resultName + "." + pubname;
+
+          f_types_ << indent() << "case " << field << "!= nil:" << endl;
+          indent_up();
+
+          if (!(*f_iter)->get_returntype()->is_void()) {
+            f_types_ << indent() << "return r, " << field << endl;
+          } else {
+            f_types_ << indent() << "return "<< field << endl;
+          }
+
+          indent_down();
+        }
+
+        f_types_ << indent() << "}" << endl << endl;
+      }
+
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_types_ << indent() << "return " << resultName << ".GetSuccess(), nil" << endl;
+      } else {
+        f_types_ << indent() << "return nil" << endl;
+      }
+    } else {
+      // TODO: would be nice to not to duplicate the call generation
+      f_types_ << indent() << "if err := p.Client_().Call(ctx, \""
+      << method << "\", &"<< argsName << ", nil); err != nil {" << endl;
+
+      indent_up();
+      f_types_ << indent() << "return err" << endl;
+      indent_down();
+      f_types_ << indent() << "}" << endl;
+      f_types_ << indent() << "return nil" << endl;
+    }
+
+    indent_down();
+    f_types_ << "}" << endl << 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();
+  t_service* parent = tservice->get_extends();
+
+  // collect inherited functions
+  while (parent != NULL) {
+    vector<t_function*> p_functions = parent->get_functions();
+    functions.insert(functions.end(), p_functions.begin(), p_functions.end());
+    parent = parent->get_extends();
+  }
+
+  // This file is not useful if there are no functions; don't generate it
+  if (functions.size() == 0) {
+    return;
+  }
+
+  string f_remote_dir = package_dir_ + "/" + underscore(service_name_) + "-remote";
+  MKDIR(f_remote_dir.c_str());
+
+  vector<t_function*>::iterator f_iter;
+  string f_remote_name = f_remote_dir + "/"
+                         + underscore(service_name_) + "-remote.go";
+  ofstream_with_content_based_conditional_update 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, '/');
+  }
+  if (!gen_package_prefix_.empty()) {
+    service_module = gen_package_prefix_ + service_module;
+  }
+
+  string unused_protection;
+
+  string ctxPackage = "context";
+
+  f_remote << go_autogen_comment();
+  f_remote << indent() << "package main" << endl << endl;
+  f_remote << indent() << "import (" << endl;
+  f_remote << indent() << "        \"" << ctxPackage << "\"" << endl;
+  f_remote << indent() << "        \"flag\"" << endl;
+  f_remote << indent() << "        \"fmt\"" << endl;
+  f_remote << indent() << "        \"math\"" << endl;
+  f_remote << indent() << "        \"net\"" << endl;
+  f_remote << indent() << "        \"net/url\"" << endl;
+  f_remote << indent() << "        \"os\"" << endl;
+  f_remote << indent() << "        \"strconv\"" << endl;
+  f_remote << indent() << "        \"strings\"" << endl;
+  f_remote << indent() << "        \"" + gen_thrift_import_ + "\"" << endl;
+  f_remote << indent() << render_included_programs(unused_protection);
+  f_remote << indent() << "        \"" << service_module << "\"" << endl;
+  f_remote << indent() << ")" << endl;
+  f_remote << indent() << endl;
+  f_remote << indent() << unused_protection; // filled in render_included_programs()
+  f_remote << indent() << endl;
+  f_remote << indent() << "func Usage() {" << endl;
+  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Usage of \", os.Args[0], \" "
+                          "[-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:\")"
+           << endl;
+  f_remote << indent() << "  flag.PrintDefaults()" << endl;
+  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"\\nFunctions:\")" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_remote << "  fmt.Fprintln(os.Stderr, \"  " << (*f_iter)->get_returntype()->get_name() << " "
+             << (*f_iter)->get_name() << "(";
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const std::vector<t_field*>& args = arg_struct->get_members();
+    std::vector<t_field*>::size_type num_args = args.size();
+    bool first = true;
+
+    for (std::vector<t_field*>::size_type i = 0; i < num_args; ++i) {
+      if (first) {
+        first = false;
+      } else {
+        f_remote << ", ";
+      }
+
+      f_remote << args[i]->get_type()->get_name() << " " << args[i]->get_name();
+    }
+
+    f_remote << ")\")" << endl;
+  }
+
+  f_remote << indent() << "  fmt.Fprintln(os.Stderr)" << endl;
+  f_remote << indent() << "  os.Exit(0)" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << endl;
+
+  f_remote << indent() << "type httpHeaders map[string]string" << endl;
+  f_remote << indent() << endl;
+  f_remote << indent() << "func (h httpHeaders) String() string {" << endl;
+  f_remote << indent() << "  var m map[string]string = h" << endl;
+  f_remote << indent() << "  return fmt.Sprintf(\"%s\", m)" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << endl;
+  f_remote << indent() << "func (h httpHeaders) Set(value string) error {" << endl;
+  f_remote << indent() << "  parts := strings.Split(value, \": \")" << endl;
+  f_remote << indent() << "  if len(parts) != 2 {" << endl;
+  f_remote << indent() << "    return fmt.Errorf(\"header should be of format 'Key: Value'\")" << endl;
+  f_remote << indent() << "  }" << endl;
+  f_remote << indent() << "  h[parts[0]] = parts[1]" << endl;
+  f_remote << indent() << "  return nil" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << endl;
+
+  f_remote << indent() << "func main() {" << endl;
+  indent_up();
+  f_remote << indent() << "flag.Usage = Usage" << endl;
+  f_remote << indent() << "var host string" << endl;
+  f_remote << indent() << "var port int" << endl;
+  f_remote << indent() << "var protocol string" << endl;
+  f_remote << indent() << "var urlString string" << endl;
+  f_remote << indent() << "var framed bool" << endl;
+  f_remote << indent() << "var useHttp bool" << endl;
+  f_remote << indent() << "headers := make(httpHeaders)" << endl;
+  f_remote << indent() << "var parsedUrl *url.URL" << endl;
+  f_remote << indent() << "var trans thrift.TTransport" << endl;
+  f_remote << indent() << "_ = strconv.Atoi" << endl;
+  f_remote << indent() << "_ = math.Abs" << endl;
+  f_remote << indent() << "flag.Usage = Usage" << endl;
+  f_remote << indent() << "flag.StringVar(&host, \"h\", \"localhost\", \"Specify host and port\")"
+           << endl;
+  f_remote << indent() << "flag.IntVar(&port, \"p\", 9090, \"Specify port\")" << endl;
+  f_remote << indent() << "flag.StringVar(&protocol, \"P\", \"binary\", \""
+                          "Specify the protocol (binary, compact, simplejson, json)\")" << endl;
+  f_remote << indent() << "flag.StringVar(&urlString, \"u\", \"\", \"Specify the url\")" << endl;
+  f_remote << indent() << "flag.BoolVar(&framed, \"framed\", false, \"Use framed transport\")"
+           << endl;
+  f_remote << indent() << "flag.BoolVar(&useHttp, \"http\", false, \"Use http\")" << endl;
+  f_remote << indent() << "flag.Var(headers, \"H\", \"Headers to set on the http(s) request (e.g. -H \\\"Key: Value\\\")\")" << endl;
+  f_remote << indent() << "flag.Parse()" << endl;
+  f_remote << indent() << endl;
+  f_remote << indent() << "if len(urlString) > 0 {" << endl;
+  f_remote << indent() << "  var err error" << endl;
+  f_remote << indent() << "  parsedUrl, err = url.Parse(urlString)" << endl;
+  f_remote << indent() << "  if err != nil {" << endl;
+  f_remote << indent() << "    fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << endl;
+  f_remote << indent() << "    flag.Usage()" << endl;
+  f_remote << indent() << "  }" << endl;
+  f_remote << indent() << "  host = parsedUrl.Host" << endl;
+  f_remote << indent() << "  useHttp = len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == \"http\" || parsedUrl.Scheme == \"https\""
+           << endl;
+  f_remote << indent() << "} else if useHttp {" << endl;
+  f_remote << indent() << "  _, err := url.Parse(fmt.Sprint(\"http://\", host, \":\", port))"
+           << endl;
+  f_remote << indent() << "  if err != nil {" << endl;
+  f_remote << indent() << "    fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << endl;
+  f_remote << indent() << "    flag.Usage()" << endl;
+  f_remote << indent() << "  }" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << endl;
+  f_remote << indent() << "cmd := flag.Arg(0)" << endl;
+  f_remote << indent() << "var err error" << endl;
+  f_remote << indent() << "if useHttp {" << endl;
+  f_remote << indent() << "  trans, err = thrift.NewTHttpClient(parsedUrl.String())" << endl;
+  f_remote << indent() << "  if len(headers) > 0 {" << endl;
+  f_remote << indent() << "    httptrans := trans.(*thrift.THttpClient)" << endl;
+  f_remote << indent() << "    for key, value := range headers {" << endl;
+  f_remote << indent() << "      httptrans.SetHeader(key, value)" << endl;
+  f_remote << indent() << "    }" << endl;
+  f_remote << indent() << "  }" << endl;
+  f_remote << indent() << "} else {" << endl;
+  f_remote << indent() << "  portStr := fmt.Sprint(port)" << endl;
+  f_remote << indent() << "  if strings.Contains(host, \":\") {" << endl;
+  f_remote << indent() << "         host, portStr, err = net.SplitHostPort(host)" << endl;
+  f_remote << indent() << "         if err != nil {" << endl;
+  f_remote << indent() << "                 fmt.Fprintln(os.Stderr, \"error with host:\", err)"
+           << endl;
+  f_remote << indent() << "                 os.Exit(1)" << endl;
+  f_remote << indent() << "         }" << endl;
+  f_remote << indent() << "  }" << endl;
+  f_remote << indent() << "  trans, err = thrift.NewTSocket(net.JoinHostPort(host, portStr))"
+           << endl;
+  f_remote << indent() << "  if err != nil {" << endl;
+  f_remote << indent() << "    fmt.Fprintln(os.Stderr, \"error resolving address:\", err)" << endl;
+  f_remote << indent() << "    os.Exit(1)" << endl;
+  f_remote << indent() << "  }" << endl;
+  f_remote << indent() << "  if framed {" << endl;
+  f_remote << indent() << "    trans = thrift.NewTFramedTransport(trans)" << endl;
+  f_remote << indent() << "  }" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << "if err != nil {" << endl;
+  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Error creating transport\", err)" << endl;
+  f_remote << indent() << "  os.Exit(1)" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << "defer trans.Close()" << endl;
+  f_remote << indent() << "var protocolFactory thrift.TProtocolFactory" << endl;
+  f_remote << indent() << "switch protocol {" << endl;
+  f_remote << indent() << "case \"compact\":" << endl;
+  f_remote << indent() << "  protocolFactory = thrift.NewTCompactProtocolFactory()" << endl;
+  f_remote << indent() << "  break" << endl;
+  f_remote << indent() << "case \"simplejson\":" << endl;
+  f_remote << indent() << "  protocolFactory = thrift.NewTSimpleJSONProtocolFactory()" << endl;
+  f_remote << indent() << "  break" << endl;
+  f_remote << indent() << "case \"json\":" << endl;
+  f_remote << indent() << "  protocolFactory = thrift.NewTJSONProtocolFactory()" << endl;
+  f_remote << indent() << "  break" << endl;
+  f_remote << indent() << "case \"binary\", \"\":" << endl;
+  f_remote << indent() << "  protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()" << endl;
+  f_remote << indent() << "  break" << endl;
+  f_remote << indent() << "default:" << endl;
+  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Invalid protocol specified: \", protocol)"
+           << endl;
+  f_remote << indent() << "  Usage()" << endl;
+  f_remote << indent() << "  os.Exit(1)" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << "iprot := protocolFactory.GetProtocol(trans)" << endl;
+  f_remote << indent() << "oprot := protocolFactory.GetProtocol(trans)" << endl;
+  f_remote << indent() << "client := " << package_name_ << ".New" << publicize(service_name_)
+           << "Client(thrift.NewTStandardClient(iprot, oprot))" << endl;
+  f_remote << indent() << "if err := trans.Open(); err != nil {" << endl;
+  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Error opening socket to \", "
+                          "host, \":\", port, \" \", err)" << endl;
+  f_remote << indent() << "  os.Exit(1)" << endl;
+  f_remote << indent() << "}" << endl;
+  f_remote << indent() << endl;
+  f_remote << 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();
+    std::vector<t_field*>::size_type num_args = args.size();
+    string funcName((*f_iter)->get_name());
+    string pubName(publicize(funcName));
+    string argumentsName(publicize(funcName + "_args", true));
+    f_remote << indent() << "case \"" << escape_string(funcName) << "\":" << endl;
+    indent_up();
+    f_remote << indent() << "if flag.NArg() - 1 != " << num_args << " {" << endl;
+    f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"" << escape_string(pubName) << " requires "
+             << num_args << " args\")" << endl;
+    f_remote << indent() << "  flag.Usage()" << endl;
+    f_remote << indent() << "}" << endl;
+
+    for (std::vector<t_field*>::size_type i = 0; i < num_args; ++i) {
+      std::vector<t_field*>::size_type 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;
+        f_remote << indent() << "if err != nil {" << endl;
+        f_remote << indent() << "  Usage()" << endl;
+        f_remote << indent() << " return" << endl;
+        f_remote << indent() << "}" << endl;
+        f_remote << 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:
+          if (the_type2->is_binary()) {
+            f_remote << indent() << "argvalue" << i << " := []byte(flag.Arg(" << flagArg << "))"
+                     << endl;
+          } else {
+            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_I8:
+          f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg("
+                   << flagArg << ")))" << endl;
+          f_remote << indent() << "if " << err << " != nil {" << endl;
+          f_remote << indent() << "  Usage()" << endl;
+          f_remote << indent() << "  return" << endl;
+          f_remote << indent() << "}" << endl;
+          f_remote << indent() << "argvalue" << i << " := int8(tmp" << i << ")" << endl;
+          break;
+
+        case t_base_type::TYPE_I16:
+          f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg("
+                   << flagArg << ")))" << endl;
+          f_remote << indent() << "if " << err << " != nil {" << endl;
+          f_remote << indent() << "  Usage()" << endl;
+          f_remote << indent() << "  return" << endl;
+          f_remote << indent() << "}" << endl;
+          f_remote << indent() << "argvalue" << i << " := int16(tmp" << i << ")" << endl;
+          break;
+
+        case t_base_type::TYPE_I32:
+          f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg("
+                   << flagArg << ")))" << endl;
+          f_remote << indent() << "if " << err << " != nil {" << endl;
+          f_remote << indent() << "  Usage()" << endl;
+          f_remote << indent() << "  return" << endl;
+          f_remote << indent() << "}" << endl;
+          f_remote << indent() << "argvalue" << i << " := int32(tmp" << i << ")" << endl;
+          break;
+
+        case t_base_type::TYPE_I64:
+          f_remote << indent() << "argvalue" << i << ", " << err
+                   << " := (strconv.ParseInt(flag.Arg(" << flagArg << "), 10, 64))" << endl;
+          f_remote << indent() << "if " << err << " != nil {" << endl;
+          f_remote << indent() << "  Usage()" << endl;
+          f_remote << indent() << "  return" << endl;
+          f_remote << indent() << "}" << endl;
+          break;
+
+        case t_base_type::TYPE_DOUBLE:
+          f_remote << indent() << "argvalue" << i << ", " << err
+                   << " := (strconv.ParseFloat(flag.Arg(" << flagArg << "), 64))" << endl;
+          f_remote << indent() << "if " << err << " != nil {" << endl;
+          f_remote << indent() << "  Usage()" << endl;
+          f_remote << indent() << "  return" << endl;
+          f_remote << 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()));
+        std::string tstruct_module( module_name(the_type));
+        if(tstruct_module.empty()) {
+          tstruct_module = package_name_;
+        }
+
+        f_remote << indent() << arg << " := flag.Arg(" << flagArg << ")" << endl;
+        f_remote << indent() << mbTrans << " := thrift.NewTMemoryBufferLen(len(" << arg << "))"
+                 << endl;
+        f_remote << indent() << "defer " << mbTrans << ".Close()" << endl;
+        f_remote << indent() << "_, " << err1 << " := " << mbTrans << ".WriteString(" << arg << ")"
+                 << endl;
+        f_remote << indent() << "if " << err1 << " != nil {" << endl;
+        f_remote << indent() << "  Usage()" << endl;
+        f_remote << indent() << "  return" << endl;
+        f_remote << indent() << "}" << endl;
+        f_remote << indent() << factory << " := thrift.NewTJSONProtocolFactory()" << endl;
+        f_remote << indent() << jsProt << " := " << factory << ".GetProtocol(" << mbTrans << ")"
+                 << endl;
+        f_remote << indent() << "argvalue" << i << " := " << tstruct_module << ".New" << tstruct_name
+                 << "()" << endl;
+        f_remote << indent() << err2 << " := argvalue" << i << "." << read_method_name_ <<  "(" << jsProt << ")" << endl;
+        f_remote << indent() << "if " << err2 << " != nil {" << endl;
+        f_remote << indent() << "  Usage()" << endl;
+        f_remote << indent() << "  return" << endl;
+        f_remote << 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;
+        f_remote << indent() << mbTrans << " := thrift.NewTMemoryBufferLen(len(" << arg << "))"
+                 << endl;
+        f_remote << indent() << "defer " << mbTrans << ".Close()" << endl;
+        f_remote << indent() << "_, " << err1 << " := " << mbTrans << ".WriteString(" << arg << ")"
+                 << endl;
+        f_remote << indent() << "if " << err1 << " != nil { " << endl;
+        f_remote << indent() << "  Usage()" << endl;
+        f_remote << indent() << "  return" << endl;
+        f_remote << indent() << "}" << endl;
+        f_remote << indent() << factory << " := thrift.NewTJSONProtocolFactory()" << endl;
+        f_remote << indent() << jsProt << " := " << factory << ".GetProtocol(" << mbTrans << ")"
+                 << endl;
+        f_remote << indent() << "containerStruct" << i << " := " << package_name_ << ".New"
+                 << argumentsName << "()" << endl;
+        f_remote << indent() << err2 << " := containerStruct" << i << ".ReadField" << (i + 1) << "("
+                 << jsProt << ")" << endl;
+        f_remote << indent() << "if " << err2 << " != nil {" << endl;
+        f_remote << indent() << "  Usage()" << endl;
+        f_remote << indent() << "  return" << endl;
+        f_remote << indent() << "}" << endl;
+        f_remote << indent() << "argvalue" << i << " := containerStruct" << i << "." << argName
+                 << endl;
+      } else {
+        throw("Invalid argument type in generate_service_remote");
+      }
+
+      if (the_type->is_typedef()) {
+        std::string typedef_module( module_name(the_type));
+        if(typedef_module.empty()) {
+          typedef_module = package_name_;
+        }
+        f_remote << indent() << "value" << i << " := " << typedef_module << "."
+                 << 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;
+
+    f_remote << "context.Background()";
+    for (std::vector<t_field*>::size_type i = 0; i < num_args; ++i) {
+      if (argFirst) {
+        argFirst = false;
+        f_remote << ", ";
+      } 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_I8:
+        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;
+    f_remote << indent() << "fmt.Print(\"\\n\")" << endl;
+    f_remote << indent() << "break" << endl;
+    indent_down();
+  }
+
+  f_remote << indent() << "case \"\":" << endl;
+  f_remote << indent() << "  Usage()" << endl;
+  f_remote << indent() << "  break" << endl;
+  f_remote << indent() << "default:" << endl;
+  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Invalid function \", cmd)" << endl;
+  f_remote << indent() << "}" << endl;
+  indent_down();
+  f_remote << indent() << "}" << endl;
+  // Close service file
+  f_remote.close();
+  format_go_output(f_remote_name);
+#ifndef _MSC_VER
+  // Make file executable, love that bitwise OR action
+  chmod(f_remote_name.c_str(),
+        S_IRUSR | S_IWUSR | S_IXUSR
+#ifndef _WIN32
+        | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
+#endif
+        );
+#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(tservice->get_name()));
+  // Generate the header portion
+  string self(tmp("self"));
+
+  if (extends_processor.empty()) {
+    f_types_ << indent() << "type " << serviceName << "Processor struct {" << endl;
+    f_types_ << indent() << "  processorMap map[string]thrift.TProcessorFunction" << endl;
+    f_types_ << indent() << "  handler " << serviceName << endl;
+    f_types_ << indent() << "}" << endl << endl;
+    f_types_ << indent() << "func (p *" << serviceName
+               << "Processor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {"
+               << endl;
+    f_types_ << indent() << "  p.processorMap[key] = processor" << endl;
+    f_types_ << indent() << "}" << endl << endl;
+    f_types_ << indent() << "func (p *" << serviceName
+               << "Processor) GetProcessorFunction(key string) "
+                  "(processor thrift.TProcessorFunction, ok bool) {" << endl;
+    f_types_ << indent() << "  processor, ok = p.processorMap[key]" << endl;
+    f_types_ << indent() << "  return processor, ok" << endl;
+    f_types_ << indent() << "}" << endl << endl;
+    f_types_ << indent() << "func (p *" << serviceName
+               << "Processor) ProcessorMap() map[string]thrift.TProcessorFunction {" << endl;
+    f_types_ << indent() << "  return p.processorMap" << endl;
+    f_types_ << indent() << "}" << endl << endl;
+    f_types_ << indent() << "func New" << serviceName << "Processor(handler " << serviceName
+               << ") *" << serviceName << "Processor {" << endl << endl;
+    f_types_
+        << 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_types_ << indent() << "  " << self << ".processorMap[\"" << escapedFuncName << "\"] = &"
+                 << pServiceName << "Processor" << publicize((*f_iter)->get_name())
+                 << "{handler:handler}" << endl;
+    }
+
+    string x(tmp("x"));
+    f_types_ << indent() << "return " << self << endl;
+    f_types_ << indent() << "}" << endl << endl;
+    f_types_ << indent() << "func (p *" << serviceName
+               << "Processor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err "
+                  "thrift.TException) {" << endl;
+    f_types_ << indent() << "  name, _, seqId, err := iprot.ReadMessageBegin()" << endl;
+    f_types_ << indent() << "  if err != nil { return false, err }" << endl;
+    f_types_ << indent() << "  if processor, ok := p.GetProcessorFunction(name); ok {" << endl;
+    f_types_ << indent() << "    return processor.Process(ctx, seqId, iprot, oprot)" << endl;
+    f_types_ << indent() << "  }" << endl;
+    f_types_ << indent() << "  iprot.Skip(thrift.STRUCT)" << endl;
+    f_types_ << indent() << "  iprot.ReadMessageEnd()" << endl;
+    f_types_ << indent() << "  " << x
+               << " := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, \"Unknown function "
+                  "\" + name)" << endl;
+    f_types_ << indent() << "  oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId)" << endl;
+    f_types_ << indent() << "  " << x << ".Write(oprot)" << endl;
+    f_types_ << indent() << "  oprot.WriteMessageEnd()" << endl;
+    f_types_ << indent() << "  oprot.Flush(ctx)" << endl;
+    f_types_ << indent() << "  return false, " << x << endl;
+    f_types_ << indent() << "" << endl;
+    f_types_ << indent() << "}" << endl << endl;
+  } else {
+    f_types_ << indent() << "type " << serviceName << "Processor struct {" << endl;
+    f_types_ << indent() << "  *" << extends_processor << endl;
+    f_types_ << indent() << "}" << endl << endl;
+    f_types_ << indent() << "func New" << serviceName << "Processor(handler " << serviceName
+               << ") *" << serviceName << "Processor {" << endl;
+    f_types_ << indent() << "  " << self << " := &" << serviceName << "Processor{"
+               << 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_types_ << indent() << "  " << self << ".AddToProcessorMap(\"" << escapedFuncName
+                 << "\", &" << pServiceName << "Processor" << publicize((*f_iter)->get_name())
+                 << "{handler:handler})" << endl;
+    }
+
+    f_types_ << indent() << "  return " << self << endl;
+    f_types_ << 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_types_ << 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", true);
+  string resultname = publicize(tfunction->get_name() + "_result", true);
+
+  // t_struct* xs = tfunction->get_xceptions();
+  // const std::vector<t_field*>& xceptions = xs->get_members();
+  f_types_ << indent() << "type " << processorName << " struct {" << endl;
+  f_types_ << indent() << "  handler " << publicize(tservice->get_name()) << endl;
+  f_types_ << indent() << "}" << endl << endl;
+  f_types_ << indent() << "func (p *" << processorName
+             << ") Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err "
+                "thrift.TException) {" << endl;
+  indent_up();
+  f_types_ << indent() << "args := " << argsname << "{}" << endl;
+  f_types_ << indent() << "if err = args." << read_method_name_ <<  "(iprot); err != nil {" << endl;
+  f_types_ << indent() << "  iprot.ReadMessageEnd()" << endl;
+  if (!tfunction->is_oneway()) {
+    f_types_ << indent()
+               << "  x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error())"
+               << endl;
+    f_types_ << indent() << "  oprot.WriteMessageBegin(\"" << escape_string(tfunction->get_name())
+               << "\", thrift.EXCEPTION, seqId)" << endl;
+    f_types_ << indent() << "  x.Write(oprot)" << endl;
+    f_types_ << indent() << "  oprot.WriteMessageEnd()" << endl;
+    f_types_ << indent() << "  oprot.Flush(ctx)" << endl;
+  }
+  f_types_ << indent() << "  return false, err" << endl;
+  f_types_ << indent() << "}" << endl << endl;
+  f_types_ << indent() << "iprot.ReadMessageEnd()" << endl;
+
+  if (!tfunction->is_oneway()) {
+    f_types_ << indent() << "result := " << resultname << "{}" << endl;
+  }
+  bool need_reference = type_need_reference(tfunction->get_returntype());
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_types_ << "var retval " << type_to_go_type(tfunction->get_returntype()) << endl;
+  }
+
+  f_types_ << indent() << "var err2 error" << endl;
+  f_types_ << indent() << "if ";
+
+  if (!tfunction->is_oneway()) {
+    if (!tfunction->get_returntype()->is_void()) {
+      f_types_ << "retval, ";
+    }
+  }
+
+  // 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_types_ << "err2 = p.handler." << publicize(tfunction->get_name()) << "(";
+  bool first = true;
+
+  f_types_ << "ctx";
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      f_types_ << ", ";
+    } else {
+      f_types_ << ", ";
+    }
+
+    f_types_ << "args." << publicize((*f_iter)->get_name());
+  }
+
+  f_types_ << "); err2 != nil {" << endl;
+
+  t_struct* exceptions = tfunction->get_xceptions();
+  const vector<t_field*>& x_fields = exceptions->get_members();
+  if (!x_fields.empty()) {
+    f_types_ << indent() << "switch v := err2.(type) {" << endl;
+
+    vector<t_field*>::const_iterator xf_iter;
+
+    for (xf_iter = x_fields.begin(); xf_iter != x_fields.end(); ++xf_iter) {
+      f_types_ << indent() << "  case " << type_to_go_type(((*xf_iter)->get_type())) << ":"
+                 << endl;
+      f_types_ << indent() << "result." << publicize((*xf_iter)->get_name()) << " = v" << endl;
+    }
+
+    f_types_ << indent() << "  default:" << endl;
+  }
+
+  if (!tfunction->is_oneway()) {
+    f_types_ << indent() << "  x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "
+                              "\"Internal error processing " << escape_string(tfunction->get_name())
+               << ": \" + err2.Error())" << endl;
+    f_types_ << indent() << "  oprot.WriteMessageBegin(\"" << escape_string(tfunction->get_name())
+               << "\", thrift.EXCEPTION, seqId)" << endl;
+    f_types_ << indent() << "  x.Write(oprot)" << endl;
+    f_types_ << indent() << "  oprot.WriteMessageEnd()" << endl;
+    f_types_ << indent() << "  oprot.Flush(ctx)" << endl;
+  }
+
+  f_types_ << indent() << "  return true, err2" << endl;
+
+  if (!x_fields.empty()) {
+    f_types_ << indent() << "}" << endl;
+  }
+
+  f_types_ << indent() << "}"; // closes err2 != nil
+
+  if (!tfunction->is_oneway()) {
+    if (!tfunction->get_returntype()->is_void()) {
+      f_types_ << " else {" << endl; // make sure we set Success retval only on success
+      indent_up();
+      f_types_ << indent() << "result.Success = ";
+      if (need_reference) {
+        f_types_ << "&";
+      }
+      f_types_ << "retval" << endl;
+      indent_down();
+      f_types_ << "}" << endl;
+    } else {
+      f_types_ << endl;
+    }
+    f_types_ << indent() << "if err2 = oprot.WriteMessageBegin(\""
+               << escape_string(tfunction->get_name()) << "\", thrift.REPLY, seqId); err2 != nil {"
+               << endl;
+    f_types_ << indent() << "  err = err2" << endl;
+    f_types_ << indent() << "}" << endl;
+    f_types_ << indent() << "if err2 = result." << write_method_name_ << "(oprot); err == nil && err2 != nil {" << endl;
+    f_types_ << indent() << "  err = err2" << endl;
+    f_types_ << indent() << "}" << endl;
+    f_types_ << indent() << "if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil {"
+               << endl;
+    f_types_ << indent() << "  err = err2" << endl;
+    f_types_ << indent() << "}" << endl;
+    f_types_ << indent() << "if err2 = oprot.Flush(ctx); err == nil && err2 != nil {" << endl;
+    f_types_ << indent() << "  err = err2" << endl;
+    f_types_ << indent() << "}" << endl;
+    f_types_ << indent() << "if err != nil {" << endl;
+    f_types_ << indent() << "  return" << endl;
+    f_types_ << indent() << "}" << endl;
+    f_types_ << indent() << "return true, err" << endl;
+  } else {
+    f_types_ << endl;
+    f_types_ << indent() << "return true, nil" << endl;
+  }
+  indent_down();
+  f_types_ << indent() << "}" << endl << endl;
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_go_generator::generate_deserialize_field(ostream& out,
+                                                t_field* tfield,
+                                                bool declare,
+                                                string prefix,
+                                                bool inclass,
+                                                bool coerceData,
+                                                bool inkey,
+                                                bool in_container_value) {
+  (void)inclass;
+  (void)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;
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out,
+                                (t_struct*)type,
+                                is_pointer_field(tfield, in_container_value),
+                                declare,
+                                name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, orig_type, is_pointer_field(tfield), declare, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    if (declare) {
+      string type_name = inkey ? type_to_go_key_type(tfield->get_type())
+                               : type_to_go_type(tfield->get_type());
+
+      out << "var " << tfield->get_name() << " " << type_name << endl;
+    }
+
+    indent(out) << "if v, err := 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:
+        if (type->is_binary() && !inkey) {
+          out << "ReadBinary()";
+        } else {
+          out << "ReadString()";
+        }
+
+        break;
+
+      case t_base_type::TYPE_BOOL:
+        out << "ReadBool()";
+        break;
+
+      case t_base_type::TYPE_I8:
+        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()";
+    }
+
+    out << "; err != nil {" << endl;
+    out << indent() << "return thrift.PrependError(\"error reading field " << tfield->get_key()
+        << ": \", err)" << endl;
+
+    out << "} else {" << endl;
+    string wrap;
+
+    if (type->is_enum() || orig_type->is_typedef()) {
+      wrap = publicize(type_name(orig_type));
+    } else if (((t_base_type*)type)->get_base() == t_base_type::TYPE_I8) {
+      wrap = "int8";
+    }
+
+    string maybe_address = (is_pointer_field(tfield) ? "&" : "");
+    if (wrap == "") {
+      indent(out) << name << " = " << maybe_address << "v" << endl;
+    } else {
+      indent(out) << "temp := " << wrap << "(v)" << endl;
+      indent(out) << name << " = " << maybe_address << "temp" << endl;
+    }
+
+    out << "}" << 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(ostream& out,
+                                                 t_struct* tstruct,
+                                                 bool pointer_field,
+                                                 bool declare,
+                                                 string prefix) {
+  string eq(declare ? " := " : " = ");
+
+  out << indent() << prefix << eq << (pointer_field ? "&" : "");
+  generate_go_struct_initializer(out, tstruct);
+  out << indent() << "if err := " << prefix << "." << read_method_name_ <<  "(iprot); err != nil {" << endl;
+  out << indent() << "  return thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", "
+      << prefix << "), err)" << endl;
+  out << indent() << "}" << endl;
+}
+
+/**
+ * Serialize a container by writing out the header followed by
+ * data and then a footer.
+ */
+void t_go_generator::generate_deserialize_container(ostream& out,
+                                                    t_type* orig_type,
+                                                    bool pointer_field,
+                                                    bool declare,
+                                                    string prefix) {
+  t_type* ttype = get_true_type(orig_type);
+  string eq(" = ");
+
+  if (declare) {
+    eq = " := ";
+  }
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    out << indent() << "_, _, size, err := iprot.ReadMapBegin()" << endl;
+    out << indent() << "if err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(\"error reading map begin: \", err)" << endl;
+    out << indent() << "}" << endl;
+    out << indent() << "tMap := make(" << type_to_go_type(orig_type) << ", size)" << endl;
+    out << indent() << prefix << eq << " " << (pointer_field ? "&" : "") << "tMap" << endl;
+  } else if (ttype->is_set()) {
+    out << indent() << "_, size, err := iprot.ReadSetBegin()" << endl;
+    out << indent() << "if err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(\"error reading set begin: \", err)" << endl;
+    out << indent() << "}" << endl;
+    out << indent() << "tSet := make(" << type_to_go_type(orig_type) << ", 0, size)" << endl;
+    out << indent() << prefix << eq << " " << (pointer_field ? "&" : "") << "tSet" << endl;
+  } else if (ttype->is_list()) {
+    out << indent() << "_, size, err := iprot.ReadListBegin()" << endl;
+    out << indent() << "if err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(\"error reading list begin: \", err)" << endl;
+    out << indent() << "}" << endl;
+    out << indent() << "tSlice := make(" << type_to_go_type(orig_type) << ", 0, size)" << endl;
+    out << indent() << prefix << eq << " " << (pointer_field ? "&" : "") << "tSlice" << endl;
+  } else {
+    throw "INVALID TYPE IN generate_deserialize_container '" + ttype->get_name() + "' for prefix '"
+        + prefix + "'";
+  }
+
+  // For loop iterates over elements
+  out << indent() << "for i := 0; i < size; i ++ {" << endl;
+  indent_up();
+
+  if (pointer_field) {
+    prefix = "(*" + prefix + ")";
+  }
+  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() << "if err := iprot.ReadMapEnd(); err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(\"error reading map end: \", err)" << endl;
+    out << indent() << "}" << endl;
+  } else if (ttype->is_set()) {
+    out << indent() << "if err := iprot.ReadSetEnd(); err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(\"error reading set end: \", err)" << endl;
+    out << indent() << "}" << endl;
+  } else if (ttype->is_list()) {
+    out << indent() << "if err := iprot.ReadListEnd(); err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(\"error reading list end: \", err)" << endl;
+    out << indent() << "}" << endl;
+  }
+}
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_go_generator::generate_deserialize_map_element(ostream& out,
+                                                      t_map* tmap,
+                                                      bool declare,
+                                                      string prefix) {
+  (void)declare;
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+  fkey.set_req(t_field::T_OPT_IN_REQ_OUT);
+  fval.set_req(t_field::T_OPT_IN_REQ_OUT);
+  generate_deserialize_field(out, &fkey, true, "", false, false, true);
+  generate_deserialize_field(out, &fval, true, "", false, false, false, true);
+  indent(out) << prefix << "[" << key << "] = " << val << endl;
+}
+
+/**
+ * Write a set element
+ */
+void t_go_generator::generate_deserialize_set_element(ostream& out,
+                                                      t_set* tset,
+                                                      bool declare,
+                                                      string prefix) {
+  (void)declare;
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+  felem.set_req(t_field::T_OPT_IN_REQ_OUT);
+  generate_deserialize_field(out, &felem, true, "", false, false, false, true);
+  indent(out) << prefix << " = append(" << prefix << ", " << elem << ")" << endl;
+}
+
+/**
+ * Write a list element
+ */
+void t_go_generator::generate_deserialize_list_element(ostream& out,
+                                                       t_list* tlist,
+                                                       bool declare,
+                                                       string prefix) {
+  (void)declare;
+  string elem = tmp("_elem");
+  t_field felem(((t_list*)tlist)->get_elem_type(), elem);
+  felem.set_req(t_field::T_OPT_IN_REQ_OUT);
+  generate_deserialize_field(out, &felem, true, "", false, false, false, true);
+  indent(out) << prefix << " = append(" << prefix << ", " << 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(ostream& out,
+                                              t_field* tfield,
+                                              string prefix,
+                                              bool inkey) {
+  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 "compiler error: cannot generate serialize for void type: " + name;
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, is_pointer_field(tfield), name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) << "if err := oprot.";
+
+    if (is_pointer_field(tfield)) {
+      name = "*" + name;
+    }
+
+    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:
+        if (type->is_binary() && !inkey) {
+          out << "WriteBinary(" << name << ")";
+        } else {
+          out << "WriteString(string(" << name << "))";
+        }
+
+        break;
+
+      case t_base_type::TYPE_BOOL:
+        out << "WriteBool(bool(" << name << "))";
+        break;
+
+      case t_base_type::TYPE_I8:
+        out << "WriteByte(int8(" << 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 Go name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "WriteI32(int32(" << name << "))";
+    }
+
+    out << "; err != nil {" << endl;
+    out << indent() << "return thrift.PrependError(fmt.Sprintf(\"%T."
+        << escape_string(tfield->get_name()) << " (" << tfield->get_key()
+        << ") field write error: \", p), err) }" << endl;
+  } else {
+    throw "compiler error: Invalid type in generate_serialize_field '" + type->get_name()
+        + "' for field '" + 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(ostream& out, t_struct* tstruct, string prefix) {
+  (void)tstruct;
+  out << indent() << "if err := " << prefix << "." << write_method_name_ << "(oprot); err != nil {" << endl;
+  out << indent() << "  return thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", "
+      << prefix << "), err)" << endl;
+  out << indent() << "}" << endl;
+}
+
+void t_go_generator::generate_serialize_container(ostream& out,
+                                                  t_type* ttype,
+                                                  bool pointer_field,
+                                                  string prefix) {
+  if (pointer_field) {
+    prefix = "*" + prefix;
+  }
+  if (ttype->is_map()) {
+    out << indent() << "if err := oprot.WriteMapBegin("
+        << type_to_enum(((t_map*)ttype)->get_key_type()) << ", "
+        << type_to_enum(((t_map*)ttype)->get_val_type()) << ", "
+        << "len(" << prefix << ")); err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(\"error writing map begin: \", err)" << endl;
+    out << indent() << "}" << endl;
+  } else if (ttype->is_set()) {
+    out << indent() << "if err := oprot.WriteSetBegin("
+        << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", "
+        << "len(" << prefix << ")); err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(\"error writing set begin: \", err)" << endl;
+    out << indent() << "}" << endl;
+  } else if (ttype->is_list()) {
+    out << indent() << "if err := oprot.WriteListBegin("
+        << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", "
+        << "len(" << prefix << ")); err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(\"error writing list begin: \", err)" << endl;
+    out << indent() << "}" << endl;
+  } else {
+    throw "compiler error: Invalid type in generate_serialize_container '" + ttype->get_name()
+        + "' for prefix '" + prefix + "'";
+  }
+
+  if (ttype->is_map()) {
+    t_map* tmap = (t_map*)ttype;
+    out << indent() << "for k, v := range " << prefix << " {" << endl;
+    indent_up();
+    generate_serialize_map_element(out, tmap, "k", "v");
+    indent_down();
+    indent(out) << "}" << endl;
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*)ttype;
+    out << indent() << "for i := 0; i<len(" << prefix << "); i++ {" << endl;
+    out << indent() << "  for j := i+1; j<len(" << prefix << "); j++ {" << endl;
+    out << indent() << "    if reflect.DeepEqual(" << prefix << "[i]," << prefix << "[j]) { " << endl;
+    out << indent() << "      return thrift.PrependError(\"\", fmt.Errorf(\"%T error writing set field: slice is not unique\", " << prefix << "[i]))" << endl;
+    out << indent() << "    }" << endl;
+    out << indent() << "  }" << endl;
+    out << indent() << "}" << endl;
+    out << indent() << "for _, v := range " << prefix << " {" << endl;
+    indent_up();
+    generate_serialize_set_element(out, tset, "v");
+    indent_down();
+    indent(out) << "}" << endl;
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*)ttype;
+    out << indent() << "for _, v := range " << prefix << " {" << endl;
+
+    indent_up();
+    generate_serialize_list_element(out, tlist, "v");
+    indent_down();
+    indent(out) << "}" << endl;
+  }
+
+  if (ttype->is_map()) {
+    out << indent() << "if err := oprot.WriteMapEnd(); err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(\"error writing map end: \", err)" << endl;
+    out << indent() << "}" << endl;
+  } else if (ttype->is_set()) {
+    out << indent() << "if err := oprot.WriteSetEnd(); err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(\"error writing set end: \", err)" << endl;
+    out << indent() << "}" << endl;
+  } else if (ttype->is_list()) {
+    out << indent() << "if err := oprot.WriteListEnd(); err != nil {" << endl;
+    out << indent() << "  return thrift.PrependError(\"error writing list end: \", err)" << endl;
+    out << indent() << "}" << endl;
+  }
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_go_generator::generate_serialize_map_element(ostream& out,
+                                                    t_map* tmap,
+                                                    string kiter,
+                                                    string viter) {
+  t_field kfield(tmap->get_key_type(), "");
+  t_field vfield(tmap->get_val_type(), "");
+  kfield.set_req(t_field::T_OPT_IN_REQ_OUT);
+  vfield.set_req(t_field::T_OPT_IN_REQ_OUT);
+  generate_serialize_field(out, &kfield, kiter, true);
+  generate_serialize_field(out, &vfield, viter);
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_go_generator::generate_serialize_set_element(ostream& out, t_set* tset, string prefix) {
+  t_field efield(tset->get_elem_type(), "");
+  efield.set_req(t_field::T_OPT_IN_REQ_OUT);
+  generate_serialize_field(out, &efield, prefix);
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_go_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string prefix) {
+  t_field efield(tlist->get_elem_type(), "");
+  efield.set_req(t_field::T_OPT_IN_REQ_OUT);
+  generate_serialize_field(out, &efield, prefix);
+}
+
+/**
+ * Generates the docstring for a given struct.
+ */
+void t_go_generator::generate_go_docstring(ostream& 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(ostream& 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(ostream& 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, "", "// ", ss.str(), "");
+  }
+}
+
+/**
+ * Generates the docstring for a generic object.
+ */
+void t_go_generator::generate_go_docstring(ostream& out, t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    generate_docstring_comment(out, "", "//", tdoc->get_doc(), "");
+  }
+}
+
+/**
+ * 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 struct field initial value.
+ *
+ * @param tfield The field, which must have `tfield->get_value() != NULL`
+ */
+string t_go_generator::render_field_initial_value(t_field* tfield,
+                                                  const string& name,
+                                                  bool optional_field) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (optional_field) {
+    // The caller will make a second pass for optional fields,
+    // assigning the result of render_const_value to "*field_name". It
+    // is maddening that Go syntax does not allow for a type-agnostic
+    // way to initialize a pointer to a const value, but so it goes.
+    // The alternative would be to write type specific functions that
+    // convert from const values to pointer types, but given the lack
+    // of overloading it would be messy.
+    return "new(" + type_to_go_type(tfield->get_type()) + ")";
+  } else {
+    return render_const_value(type, tfield->get_value(), name);
+  }
+}
+
+/**
+ * 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 addError) {
+  string signature = publicize(prefix + tfunction->get_name()) + "(";
+  signature += "ctx context.Context";
+  if (!tfunction->get_arglist()->get_members().empty()) {
+    signature += ", " + argument_list(tfunction->get_arglist());
+  }
+  signature += ") (";
+
+  t_type* ret = tfunction->get_returntype();
+  t_struct* exceptions = tfunction->get_xceptions();
+  string errs = argument_list(exceptions);
+
+  if (!ret->is_void()) {
+    signature += "r " + type_to_go_type(ret);
+
+    if (addError || errs.size() == 0) {
+      signature += ", ";
+    }
+  }
+
+  if (addError) {
+    signature += "err 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 += variable_name_to_go_name((*f_iter)->get_name()) + " "
+              + type_to_go_type((*f_iter)->get_type());
+  }
+
+  return result;
+}
+
+string t_go_generator::type_name(t_type* ttype) {
+  string module( module_name(ttype));
+  if( ! module.empty()) {
+    return module + "." + ttype->get_name();
+  }
+
+  return ttype->get_name();
+}
+
+string t_go_generator::module_name(t_type* ttype) {
+  t_program* program = ttype->get_program();
+
+  if (program != NULL && program != program_) {
+    if (program->get_namespace("go").empty() ||
+        program_->get_namespace("go").empty() ||
+        program->get_namespace("go") != program_->get_namespace("go")) {
+      string module(get_real_go_module(program));
+      // for namespaced includes, only keep part after dot.
+      size_t dot = module.rfind('.');
+      if (dot != string::npos) {
+        module = module.substr(dot + 1);
+      }
+      return module;
+    }
+  }
+
+  return "";
+}
+
+/**
+ * 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:
+      /* this is wrong, binary is still a string type internally
+      if (type->is_binary()) {
+          return "thrift.BINARY";
+      }
+      */
+      return "thrift.STRING";
+
+    case t_base_type::TYPE_BOOL:
+      return "thrift.BOOL";
+
+    case t_base_type::TYPE_I8:
+      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 map type, will throw an exception if it will
+ * not produce a valid go map type.
+ */
+string t_go_generator::type_to_go_key_type(t_type* type) {
+  t_type* resolved_type = type;
+
+  while (resolved_type->is_typedef()) {
+    resolved_type = ((t_typedef*)resolved_type)->get_type()->get_true_type();
+  }
+
+  if (resolved_type->is_map() || resolved_type->is_list() || resolved_type->is_set()) {
+    throw "Cannot produce a valid type for a Go map key: " + type_to_go_type(type) + " - aborting.";
+  }
+
+  if (resolved_type->is_binary())
+    return "string";
+
+  return type_to_go_type(type);
+}
+
+/**
+ * Converts the parse type to a go type
+ */
+string t_go_generator::type_to_go_type(t_type* type) {
+  return type_to_go_type_with_opt(type, false);
+}
+
+/**
+ * Converts the parse type to a go type, taking into account whether the field
+ * associated with the type is T_OPTIONAL.
+ */
+string t_go_generator::type_to_go_type_with_opt(t_type* type,
+                                                bool optional_field) {
+  string maybe_pointer(optional_field ? "*" : "");
+
+  if (type->is_typedef() && ((t_typedef*)type)->is_forward_typedef()) {
+    type = ((t_typedef*)type)->get_true_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:
+      if (type->is_binary()) {
+        return maybe_pointer + "[]byte";
+      }
+
+      return maybe_pointer + "string";
+
+    case t_base_type::TYPE_BOOL:
+      return maybe_pointer + "bool";
+
+    case t_base_type::TYPE_I8:
+      return maybe_pointer + "int8";
+
+    case t_base_type::TYPE_I16:
+      return maybe_pointer + "int16";
+
+    case t_base_type::TYPE_I32:
+      return maybe_pointer + "int32";
+
+    case t_base_type::TYPE_I64:
+      return maybe_pointer + "int64";
+
+    case t_base_type::TYPE_DOUBLE:
+      return maybe_pointer + "float64";
+    }
+  } else if (type->is_enum()) {
+    return maybe_pointer + publicize(type_name(type));
+  } else if (type->is_struct() || type->is_xception()) {
+    return "*" + publicize(type_name(type));
+  } else if (type->is_map()) {
+    t_map* t = (t_map*)type;
+    string keyType = type_to_go_key_type(t->get_key_type());
+    string valueType = type_to_go_type(t->get_val_type());
+    return maybe_pointer + string("map[") + keyType + "]" + valueType;
+  } else if (type->is_set()) {
+    t_set* t = (t_set*)type;
+    string elemType = type_to_go_type(t->get_elem_type());
+    return maybe_pointer + string("[]") + elemType;
+  } else if (type->is_list()) {
+    t_list* t = (t_list*)type;
+    string elemType = type_to_go_type(t->get_elem_type());
+    return maybe_pointer + string("[]") + elemType;
+  } else if (type->is_typedef()) {
+    return maybe_pointer + publicize(type_name(type));
+  }
+
+  throw "INVALID TYPE IN type_to_go_type: " + 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();
+}
+
+bool format_go_output(const string& file_path) {
+
+  // formatting via gofmt deactivated due to THRIFT-3893
+  // Please look at the ticket and make sure you fully understand all the implications
+  // before submitting a patch that enables this feature again. Thank you.
+  (void) file_path;
+  return false;
+
+  /*
+  const string command = "gofmt -w " + file_path;
+
+  if (system(command.c_str()) == 0) {
+    return true;
+  }
+
+  fprintf(stderr, "WARNING - Running '%s' failed.\n", command.c_str());
+  return false;
+  */
+ }
+
+THRIFT_REGISTER_GENERATOR(go, "Go",
+                          "    package_prefix=  Package prefix for generated files.\n" \
+                          "    thrift_import=   Override thrift package import path (default:" + DEFAULT_THRIFT_IMPORT + ")\n" \
+                          "    package=         Package name (default: inferred from thrift file name)\n" \
+                          "    ignore_initialisms\n"
+                          "                     Disable automatic spelling correction of initialisms (e.g. \"URL\")\n" \
+                          "    read_write_private\n"
+                          "                     Make read/write methods private, default is public Read/Write\n")
diff --git a/compiler/cpp/src/thrift/generate/t_gv_generator.cc b/compiler/cpp/src/thrift/generate/t_gv_generator.cc
new file mode 100644
index 0000000..7f8301a
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_gv_generator.cc
@@ -0,0 +1,345 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <map>
+#include <list>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "thrift/platform.h"
+#include "thrift/generate/t_generator.h"
+
+using std::map;
+using std::ofstream;
+using std::ostringstream;
+using std::pair;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * Graphviz code generator
+ */
+class t_gv_generator : public t_generator {
+public:
+  t_gv_generator(t_program* program,
+                 const std::map<std::string, std::string>& parsed_options,
+                 const std::string& option_string)
+    : t_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    exception_arrows = false;
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("exceptions") == 0) {
+        exception_arrows = true;
+      } else {
+        throw "unknown option gv:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-gv";
+  }
+
+  /**
+   * Init and end of generator
+   */
+  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_service(t_service* tservice);
+
+protected:
+  /**
+   * Helpers
+   */
+  void print_type(t_type* ttype, string struct_field_ref);
+  void print_const_value(t_type* type, t_const_value* tvalue);
+
+private:
+  ofstream_with_content_based_conditional_update f_out_;
+  std::list<string> edges;
+  bool exception_arrows;
+};
+
+/**
+ * Init generator:
+ * - Adds some escaping for the Graphviz domain.
+ * - Create output directory and open file for writting.
+ * - Write the file header.
+ */
+void t_gv_generator::init_generator() {
+  escape_['{'] = "\\{";
+  escape_['}'] = "\\}";
+
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+  string fname = get_out_dir() + program_->get_name() + ".gv";
+  f_out_.open(fname.c_str());
+  f_out_ << "digraph \"" << escape_string(program_name_) << "\" {" << endl;
+  f_out_ << "node [style=filled, shape=record];" << endl;
+  f_out_ << "edge [arrowsize=0.5];" << endl;
+  f_out_ << "rankdir=LR" << endl;
+}
+
+/**
+ * Closes generator:
+ * - Print accumulated nodes connections.
+ * - Print footnote.
+ * - Closes file.
+ */
+void t_gv_generator::close_generator() {
+  // Print edges
+  std::list<string>::iterator iter = edges.begin();
+  for (; iter != edges.end(); iter++) {
+    f_out_ << (*iter) << endl;
+  }
+
+  // Print graph end } and close file
+  f_out_ << "}" << endl;
+  f_out_.close();
+}
+
+void t_gv_generator::generate_typedef(t_typedef* ttypedef) {
+  string name = ttypedef->get_name();
+  f_out_ << "node [fillcolor=azure];" << endl;
+  f_out_ << name << " [label=\"";
+
+  f_out_ << escape_string(name);
+  f_out_ << " :: ";
+  print_type(ttypedef->get_type(), name);
+
+  f_out_ << "\"];" << endl;
+}
+
+void t_gv_generator::generate_enum(t_enum* tenum) {
+  string name = tenum->get_name();
+  f_out_ << "node [fillcolor=white];" << endl;
+  f_out_ << name << " [label=\"enum " << escape_string(name);
+
+  vector<t_enum_value*> values = tenum->get_constants();
+  vector<t_enum_value*>::iterator val_iter;
+  for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) {
+    f_out_ << '|' << (*val_iter)->get_name();
+    f_out_ << " = ";
+    f_out_ << (*val_iter)->get_value();
+  }
+
+  f_out_ << "\"];" << endl;
+}
+
+void t_gv_generator::generate_const(t_const* tconst) {
+  string name = tconst->get_name();
+
+  f_out_ << "node [fillcolor=aliceblue];" << endl;
+  f_out_ << "const_" << name << " [label=\"";
+
+  f_out_ << escape_string(name);
+  f_out_ << " = ";
+  print_const_value(tconst->get_type(), tconst->get_value());
+  f_out_ << " :: ";
+  print_type(tconst->get_type(), "const_" + name);
+
+  f_out_ << "\"];" << endl;
+}
+
+void t_gv_generator::generate_struct(t_struct* tstruct) {
+  string name = tstruct->get_name();
+
+  if (tstruct->is_xception()) {
+    f_out_ << "node [fillcolor=lightpink];" << endl;
+    f_out_ << name << " [label=\"";
+    f_out_ << "exception " << escape_string(name);
+  } else if (tstruct->is_union()) {
+    f_out_ << "node [fillcolor=lightcyan];" << endl;
+    f_out_ << name << " [label=\"";
+    f_out_ << "union " << escape_string(name);
+  } else {
+    f_out_ << "node [fillcolor=beige];" << endl;
+    f_out_ << name << " [label=\"";
+    f_out_ << "struct " << escape_string(name);
+  }
+
+  vector<t_field*> members = tstruct->get_members();
+  vector<t_field*>::iterator mem_iter = members.begin();
+  for (; mem_iter != members.end(); mem_iter++) {
+    string field_name = (*mem_iter)->get_name();
+
+    // print port (anchor reference)
+    f_out_ << "|<field_" << field_name << '>';
+
+    // field name :: field type
+    f_out_ << (*mem_iter)->get_name();
+    f_out_ << " :: ";
+    print_type((*mem_iter)->get_type(), name + ":field_" + field_name);
+  }
+
+  f_out_ << "\"];" << endl;
+}
+
+void t_gv_generator::print_type(t_type* ttype, string struct_field_ref) {
+  if (ttype->is_container()) {
+    if (ttype->is_list()) {
+      f_out_ << "list\\<";
+      print_type(((t_list*)ttype)->get_elem_type(), struct_field_ref);
+      f_out_ << "\\>";
+    } else if (ttype->is_set()) {
+      f_out_ << "set\\<";
+      print_type(((t_set*)ttype)->get_elem_type(), struct_field_ref);
+      f_out_ << "\\>";
+    } else if (ttype->is_map()) {
+      f_out_ << "map\\<";
+      print_type(((t_map*)ttype)->get_key_type(), struct_field_ref);
+      f_out_ << ", ";
+      print_type(((t_map*)ttype)->get_val_type(), struct_field_ref);
+      f_out_ << "\\>";
+    }
+  } else if (ttype->is_base_type()) {
+    f_out_ << (ttype->is_binary() ? "binary" : ttype->get_name());
+  } else {
+    f_out_ << ttype->get_name();
+    edges.push_back(struct_field_ref + " -> " + ttype->get_name());
+  }
+}
+
+/**
+ * Prints out an string representation of the provided constant value
+ */
+void t_gv_generator::print_const_value(t_type* type, t_const_value* tvalue) {
+  bool first = true;
+  switch (tvalue->get_type()) {
+  case t_const_value::CV_INTEGER:
+    f_out_ << tvalue->get_integer();
+    break;
+  case t_const_value::CV_DOUBLE:
+    f_out_ << tvalue->get_double();
+    break;
+  case t_const_value::CV_STRING:
+    f_out_ << "\\\"" << get_escaped_string(tvalue) << "\\\"";
+    break;
+  case t_const_value::CV_MAP: {
+    f_out_ << "\\{ ";
+    map<t_const_value*, t_const_value*, t_const_value::value_compare> map_elems = tvalue->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::iterator map_iter;
+    for (map_iter = map_elems.begin(); map_iter != map_elems.end(); map_iter++) {
+      if (!first) {
+        f_out_ << ", ";
+      }
+      first = false;
+      print_const_value(((t_map*)type)->get_key_type(), map_iter->first);
+      f_out_ << " = ";
+      print_const_value(((t_map*)type)->get_val_type(), map_iter->second);
+    }
+    f_out_ << " \\}";
+  } break;
+  case t_const_value::CV_LIST: {
+    f_out_ << "\\{ ";
+    vector<t_const_value*> list_elems = tvalue->get_list();
+    ;
+    vector<t_const_value*>::iterator list_iter;
+    for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) {
+      if (!first) {
+        f_out_ << ", ";
+      }
+      first = false;
+      if (type->is_list()) {
+        print_const_value(((t_list*)type)->get_elem_type(), *list_iter);
+      } else {
+        print_const_value(((t_set*)type)->get_elem_type(), *list_iter);
+      }
+    }
+    f_out_ << " \\}";
+  } break;
+  case t_const_value::CV_IDENTIFIER:
+    f_out_ << escape_string(type->get_name()) << "."
+           << escape_string(tvalue->get_identifier_name());
+    break;
+  default:
+    f_out_ << "UNKNOWN";
+    break;
+  }
+}
+
+void t_gv_generator::generate_service(t_service* tservice) {
+  string service_name = get_service_name(tservice);
+  f_out_ << "subgraph cluster_" << service_name << " {" << endl;
+  f_out_ << "node [fillcolor=bisque];" << endl;
+  f_out_ << "style=dashed;" << endl;
+  f_out_ << "label = \"" << escape_string(service_name) << " service\";" << endl;
+
+  // TODO: service extends
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator fn_iter = functions.begin();
+  for (; fn_iter != functions.end(); fn_iter++) {
+    string fn_name = (*fn_iter)->get_name();
+
+    f_out_ << "function_" << service_name << fn_name;
+    f_out_ << "[label=\"<return_type>function " << escape_string(fn_name);
+    f_out_ << " :: ";
+    print_type((*fn_iter)->get_returntype(), "function_" + service_name + fn_name + ":return_type");
+
+    vector<t_field*> args = (*fn_iter)->get_arglist()->get_members();
+    vector<t_field*>::iterator arg_iter = args.begin();
+    for (; arg_iter != args.end(); arg_iter++) {
+      f_out_ << "|<param_" << (*arg_iter)->get_name() << ">";
+      f_out_ << (*arg_iter)->get_name();
+      if ((*arg_iter)->get_value() != NULL) {
+        f_out_ << " = ";
+        print_const_value((*arg_iter)->get_type(), (*arg_iter)->get_value());
+      }
+      f_out_ << " :: ";
+      print_type((*arg_iter)->get_type(),
+                 "function_" + service_name + fn_name + ":param_" + (*arg_iter)->get_name());
+    }
+    // end of node
+    f_out_ << "\"];" << endl;
+
+    // Exception edges
+    if (exception_arrows) {
+      vector<t_field*> excepts = (*fn_iter)->get_xceptions()->get_members();
+      vector<t_field*>::iterator ex_iter = excepts.begin();
+      for (; ex_iter != excepts.end(); ex_iter++) {
+        edges.push_back("function_" + service_name + fn_name + " -> "
+                        + (*ex_iter)->get_type()->get_name() + " [color=red]");
+      }
+    }
+  }
+
+  f_out_ << " }" << endl;
+}
+
+THRIFT_REGISTER_GENERATOR(
+    gv,
+    "Graphviz",
+    "    exceptions:      Whether to draw arrows from functions to exception.\n")
diff --git a/compiler/cpp/src/thrift/generate/t_haxe_generator.cc b/compiler/cpp/src/thrift/generate/t_haxe_generator.cc
new file mode 100644
index 0000000..3b88c4d
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_haxe_generator.cc
@@ -0,0 +1,2983 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <cctype>
+
+#include <sys/stat.h>
+#include <stdexcept>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * Haxe code generator.
+ *
+ */
+class t_haxe_generator : public t_oop_generator {
+public:
+  t_haxe_generator(t_program* program,
+                   const std::map<std::string, std::string>& parsed_options,
+                   const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    callbacks_ = false;
+    rtti_ = false;
+    buildmacro_ = "";
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("callbacks") == 0) {
+        callbacks_ = true;
+      } else if( iter->first.compare("rtti") == 0) {
+        rtti_ = true;
+      } else if( iter->first.compare("buildmacro") == 0) {
+        buildmacro_ = (iter->second);
+      } else {
+        throw "unknown option haxe:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-haxe";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  void generate_consts(std::vector<t_const*> consts);
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_struct(t_struct* tstruct);
+  void generate_xception(t_struct* txception);
+  void generate_service(t_service* tservice);
+
+  void print_const_value(std::ostream& out,
+                         std::string name,
+                         t_type* type,
+                         t_const_value* value,
+                         bool in_static,
+                         bool defval = false);
+  std::string render_const_value(ostream& out,
+                                 std::string name,
+                                 t_type* type,
+                                 t_const_value* value);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_haxe_struct(t_struct* tstruct, bool is_exception, bool is_result = false);
+
+  void generate_haxe_struct_definition(std::ostream& out,
+                                       t_struct* tstruct,
+                                       bool is_xception = false,
+                                       bool is_result = false);
+  // removed -- equality,compare_to
+  void generate_haxe_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_haxe_validator(std::ostream& out, t_struct* tstruct);
+  void generate_haxe_struct_result_writer(std::ostream& out, t_struct* tstruct);
+  void generate_haxe_struct_writer(std::ostream& out, t_struct* tstruct);
+  void generate_haxe_struct_tostring(std::ostream& out, t_struct* tstruct);
+  void generate_haxe_meta_data_map(std::ostream& out, t_struct* tstruct);
+  void generate_field_value_meta_data(std::ostream& out, t_type* type);
+  std::string get_haxe_type_string(t_type* type);
+  void generate_reflection_setters(std::ostringstream& out,
+                                   t_type* type,
+                                   std::string field_name,
+                                   std::string cap_name);
+  void generate_reflection_getters(std::ostringstream& out,
+                                   t_type* type,
+                                   std::string field_name,
+                                   std::string cap_name);
+  void generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct);
+  void generate_generic_isset_method(std::ostream& out, t_struct* tstruct);
+  void generate_property_getters_setters(std::ostream& out, t_struct* tstruct);
+
+  void generate_function_helpers(t_function* tfunction);
+  std::string get_cap_name(std::string name);
+  std::string generate_isset_check(t_field* field);
+  std::string generate_isset_check(std::string field);
+  void generate_isset_set(ostream& out, t_field* field);
+  // removed std::string isset_field_id(t_field* field);
+
+  void generate_service_interface(t_service* tservice);
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_client(t_service* tservice);
+  void generate_service_server(t_service* tservice);
+  void generate_process_function(t_service* tservice, t_function* tfunction);
+  void generate_service_method_signature(t_function* tfunction, bool is_interface);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
+  void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+  void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+  void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         std::string prefix = "");
+
+  void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string iter,
+                                      std::string map);
+
+  void generate_haxe_doc(std::ostream& out, t_doc* tdoc);
+  void generate_haxe_doc(std::ostream& out, t_function* tdoc);
+
+  void generate_rtti_decoration(std::ostream& out);
+  void generate_macro_decoration(std::ostream& out);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string haxe_package();
+  std::string haxe_type_imports();
+  std::string haxe_thrift_imports();
+  std::string haxe_thrift_gen_imports(t_struct* tstruct, string& imports);
+  std::string haxe_thrift_gen_imports(t_service* tservice);
+  std::string type_name(t_type* ttype, bool in_container = false, bool in_init = false);
+  std::string base_type_name(t_base_type* tbase, bool in_container = false);
+  std::string declare_field(t_field* tfield, bool init = false);
+  std::string function_signature_callback(t_function* tfunction);
+  std::string function_signature_normal(t_function* tfunction);
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string get_enum_class_name(t_type* type);
+  string generate_service_method_onsuccess(t_function* tfunction, bool as_type, bool omit_name);
+  void generate_service_method_signature_callback(t_function* tfunction, bool is_interface);
+  void generate_service_method_signature_normal(t_function* tfunction, bool is_interface);
+
+  bool type_can_be_null(t_type* ttype) {
+    ttype = get_true_type(ttype);
+
+    if (ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string()) {
+      return true;
+    }
+
+    if (ttype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_STRING:
+        // case t_base_type::TYPE_I64:  - Int64 is not really nullable, even though it behaved that
+        // way before Haxe 3.2.0
+        return true;
+      default:
+        return false;
+      }
+    }
+
+    return false;
+  }
+
+  std::string constant_name(std::string name);
+
+private:
+  bool callbacks_;
+  bool rtti_;
+  string buildmacro_;
+
+  /**
+   * File streams
+   */
+
+  std::string package_name_;
+  ofstream_with_content_based_conditional_update f_service_;
+  std::string package_dir_;
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_haxe_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+  package_name_ = program_->get_namespace("haxe");
+
+  // Haxe package names are lowercase
+  if (package_name_.length() > 0) {
+    package_name_[0] = tolower(package_name_[0]);
+    size_t index = package_name_.find('.');
+    while (index != std::string::npos) {
+      if (++index < package_name_.length()) {
+        package_name_[index] = tolower(package_name_[index]);
+      }
+      index = package_name_.find('.', index);
+    }
+  }
+
+  string dir = package_name_;
+  string subdir = get_out_dir();
+  string::size_type loc;
+  while ((loc = dir.find(".")) != string::npos) {
+    subdir = subdir + "/" + dir.substr(0, loc);
+    MKDIR(subdir.c_str());
+    dir = dir.substr(loc + 1);
+  }
+  if (dir.size() > 0) {
+    subdir = subdir + "/" + dir;
+    MKDIR(subdir.c_str());
+  }
+
+  package_dir_ = subdir;
+}
+
+/**
+ * Packages the generated file
+ *
+ * @return String of the package, i.e. "package org.apache.thriftdemo;"
+ */
+string t_haxe_generator::haxe_package() {
+  if (!package_name_.empty()) {
+    return string("package ") + package_name_;
+  }
+  return "package";
+}
+
+/**
+ * Prints standard haxe imports
+ *
+ * @return List of imports for haxe types that are used in here
+ */
+string t_haxe_generator::haxe_type_imports() {
+  return string() + "import org.apache.thrift.helper.*;\n" + "import haxe.io.Bytes;\n"
+         + "import haxe.ds.IntMap;\n" + "import haxe.ds.StringMap;\n"
+         + "import haxe.ds.ObjectMap;\n" + "\n" + "#if flash\n"
+         + "import flash.errors.ArgumentError;\n" + "#end\n" + "\n";
+}
+
+/**
+ * Prints standard haxe imports
+ *
+ * @return List of imports necessary for thrift
+ */
+string t_haxe_generator::haxe_thrift_imports() {
+  return string() + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n"
+         + "import org.apache.thrift.protocol.*;\n" + "\n";
+}
+
+/**
+ * Prints imports needed for a given type
+ *
+ * @return List of imports necessary for a given t_struct
+ */
+string t_haxe_generator::haxe_thrift_gen_imports(t_struct* tstruct, string& imports) {
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  // For each type check if it is from a different namespace
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_program* program = (*m_iter)->get_type()->get_program();
+    if (program != NULL && program != program_) {
+      string package = program->get_namespace("haxe");
+      if (!package.empty()) {
+        if (imports.find(package + "." + (*m_iter)->get_type()->get_name()) == string::npos) {
+          imports.append("import " + package + "." + (*m_iter)->get_type()->get_name() + ";\n");
+        }
+      }
+    }
+  }
+  return imports;
+}
+
+/**
+ * Prints imports needed for a given type
+ *
+ * @return List of imports necessary for a given t_service
+ */
+string t_haxe_generator::haxe_thrift_gen_imports(t_service* tservice) {
+  string imports;
+  const vector<t_function*>& functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+
+  // For each type check if it is from a different namespace
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_program* program = (*f_iter)->get_returntype()->get_program();
+    if (program != NULL && program != program_) {
+      string package = program->get_namespace("haxe");
+      if (!package.empty()) {
+        if (imports.find(package + "." + (*f_iter)->get_returntype()->get_name()) == string::npos) {
+          imports.append("import " + package + "." + (*f_iter)->get_returntype()->get_name()
+                         + ";\n");
+        }
+      }
+    }
+
+    haxe_thrift_gen_imports((*f_iter)->get_arglist(), imports);
+    haxe_thrift_gen_imports((*f_iter)->get_xceptions(), imports);
+  }
+
+  return imports;
+}
+
+/**
+ * Nothing in haxe
+ */
+void t_haxe_generator::close_generator() {
+}
+
+/**
+ * Generates a typedef. This is not done in haxe, since it does
+ * not support arbitrary name replacements, and it'd be a wacky waste
+ * of overhead to make wrapper classes.
+ *
+ * @param ttypedef The type definition
+ */
+void t_haxe_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+/**
+ * Enums are a class with a set of static constants.
+ *
+ * @param tenum The enumeration
+ */
+void t_haxe_generator::generate_enum(t_enum* tenum) {
+  // Make output file
+  string f_enum_name = package_dir_ + "/" + get_cap_name(tenum->get_name()) + ".hx";
+  ofstream_with_content_based_conditional_update f_enum;
+  f_enum.open(f_enum_name.c_str());
+
+  // Comment and package it
+  f_enum << autogen_comment() << haxe_package() << ";" << endl << endl;
+
+  // Add haxe imports
+  f_enum << string() + "import org.apache.thrift.helper.*;" << endl << endl;
+
+  generate_rtti_decoration(f_enum);
+  generate_macro_decoration(f_enum);
+  indent(f_enum) << "class " << get_cap_name(tenum->get_name()) << " ";
+  scope_up(f_enum);
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    indent(f_enum) << "public static inline var " << (*c_iter)->get_name() << " : Int = " << value
+                   << ";" << endl;
+  }
+
+  // Create a static Set with all valid values for this enum
+  f_enum << endl;
+
+  indent(f_enum) << "public static var VALID_VALUES = { new IntSet( [";
+  indent_up();
+  bool firstValue = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    // populate set
+    f_enum << (firstValue ? "" : ", ") << (*c_iter)->get_name();
+    firstValue = false;
+  }
+  indent_down();
+  f_enum << "]); };" << endl;
+
+  indent(f_enum) << "public static var VALUES_TO_NAMES = { [";
+  indent_up();
+  firstValue = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    f_enum << (firstValue ? "" : ",") << endl;
+    indent(f_enum) << (*c_iter)->get_name() << " => \"" << (*c_iter)->get_name() << "\"";
+    firstValue = false;
+  }
+  f_enum << endl;
+  indent_down();
+  indent(f_enum) << "]; };" << endl;
+
+  scope_down(f_enum); // end class
+
+  f_enum.close();
+}
+
+/**
+ * Generates a class that holds all the constants.
+ */
+void t_haxe_generator::generate_consts(std::vector<t_const*> consts) {
+  if (consts.empty()) {
+    return;
+  }
+
+  string f_consts_name = package_dir_ + "/" + get_cap_name(program_name_) + "Constants.hx";
+  ofstream_with_content_based_conditional_update f_consts;
+  f_consts.open(f_consts_name.c_str());
+
+  // Print header
+  f_consts << autogen_comment() << haxe_package() << ";" << endl << endl;
+
+  f_consts << endl;
+
+  f_consts << haxe_type_imports();
+
+  generate_rtti_decoration(f_consts);
+  generate_macro_decoration(f_consts);
+  indent(f_consts) << "class " << get_cap_name(program_name_) << "Constants {" << endl << endl;
+  indent_up();
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    print_const_value(f_consts,
+                      (*c_iter)->get_name(),
+                      (*c_iter)->get_type(),
+                      (*c_iter)->get_value(),
+                      false);
+  }
+  indent_down();
+  indent(f_consts) << "}" << endl;
+  f_consts.close();
+}
+
+void t_haxe_generator::print_const_value(std::ostream& out,
+                                         string name,
+                                         t_type* type,
+                                         t_const_value* value,
+                                         bool in_static,
+                                         bool defval) {
+  type = get_true_type(type);
+
+  indent(out);
+  if (!defval) {
+    out << (in_static ? "var " : "public static inline var  ");
+  }
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, name, type, value);
+    out << name;
+    if (!defval) {
+      out << ":" << type_name(type);
+    }
+    out << " = " << v2 << ";" << endl << endl;
+  } else if (type->is_enum()) {
+    out << name;
+    if (!defval) {
+      out << ":" << type_name(type);
+    }
+    out << " = " << value->get_integer() << ";" << endl << endl;
+  } else if (type->is_struct() || type->is_xception()) {
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    out << name << ":" << type_name(type) << " = new " << type_name(type, false, true) << "();"
+        << endl;
+    if (!in_static) {
+      indent(out) << "{" << endl;
+      indent_up();
+      indent(out) << "new function() : Void {" << endl;
+      indent_up();
+    }
+    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();
+      }
+      string val = render_const_value(out, name, field_type, v_iter->second);
+      indent(out) << name << ".";
+      out << v_iter->first->get_string() << " = " << val << ";" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}();" << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else if (type->is_map()) {
+    out << name;
+    if (!defval) {
+      out << ":" << type_name(type);
+    }
+    out << " = new " << type_name(type, false, true) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "{" << endl;
+      indent_up();
+      indent(out) << "new function() : Void {" << endl;
+      indent_up();
+    }
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, name, ktype, v_iter->first);
+      string val = render_const_value(out, name, vtype, v_iter->second);
+      indent(out) << name << "[" << key << "] = " << val << ";" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}();" << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else if (type->is_list() || type->is_set()) {
+    out << name;
+    if (!defval) {
+      out << ":" << type_name(type);
+    }
+    out << " = new " << type_name(type, false, true) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "{" << endl;
+      indent_up();
+      indent(out) << "new function() : Void {" << endl;
+      indent_up();
+    }
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(out, name, etype, *v_iter);
+      indent(out) << name << "." << (type->is_list() ? "push" : "add") << "(" << val << ");"
+                  << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}();" << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else {
+    throw "compiler error: no const of type " + type->get_name();
+  }
+}
+
+string t_haxe_generator::render_const_value(ostream& out,
+                                            string name,
+                                            t_type* type,
+                                            t_const_value* value) {
+  (void)name;
+  type = get_true_type(type);
+  std::ostringstream render;
+
+  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:
+      render << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "true" : "false");
+      break;
+    case t_base_type::TYPE_I8:
+      render << "(byte)" << value->get_integer();
+      break;
+    case t_base_type::TYPE_I16:
+      render << "(short)" << value->get_integer();
+      break;
+    case t_base_type::TYPE_I32:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_I64:
+      render << value->get_integer() << "L";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << "(double)" << value->get_integer();
+      } else {
+        render << 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()) {
+    render << value->get_integer();
+  } else {
+    string t = tmp("tmp");
+    print_const_value(out, t, type, value, true);
+    render << t;
+  }
+
+  return render.str();
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This is a class
+ * with data members, read(), write(), and an inner Isset class.
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_struct(t_struct* tstruct) {
+  generate_haxe_struct(tstruct, false);
+}
+
+/**
+ * Exceptions are structs, but they inherit from Exception
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_xception(t_struct* txception) {
+  generate_haxe_struct(txception, true);
+}
+
+/**
+ * Haxe struct definition.
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_haxe_struct(t_struct* tstruct, bool is_exception, bool is_result) {
+  // Make output file
+  string f_struct_name = package_dir_ + "/" + get_cap_name(tstruct->get_name()) + ".hx";
+  ofstream_with_content_based_conditional_update f_struct;
+  f_struct.open(f_struct_name.c_str());
+
+  f_struct << autogen_comment() << haxe_package() << ";" << endl;
+
+  f_struct << endl;
+
+  string imports;
+
+  f_struct << haxe_type_imports() << haxe_thrift_imports()
+           << haxe_thrift_gen_imports(tstruct, imports) << endl;
+
+  generate_haxe_struct_definition(f_struct, tstruct, is_exception, is_result);
+
+  f_struct.close();
+}
+
+/**
+ * haxe struct definition. This has various parameters, as it could be
+ * generated standalone or inside another class as a helper. If it
+ * is a helper than it is a static class.
+ *
+ * @param tstruct      The struct definition
+ * @param is_exception Is this an exception?
+ * @param in_class     If inside a class, needs to be static class
+ * @param is_result    If this is a result it needs a different writer
+ */
+void t_haxe_generator::generate_haxe_struct_definition(ostream& out,
+                                                       t_struct* tstruct,
+                                                       bool is_exception,
+                                                       bool is_result) {
+  generate_haxe_doc(out, tstruct);
+
+  string clsname = get_cap_name(tstruct->get_name());
+
+  generate_rtti_decoration(out);
+  generate_macro_decoration(out);
+  indent(out) << "class " << clsname << " ";
+
+  if (is_exception) {
+    out << "extends TException ";
+  }
+  out << "implements TBase ";
+
+  scope_up(out);
+  indent(out) << endl;
+
+  indent(out) << "static var STRUCT_DESC = { new TStruct(\"" << tstruct->get_name() << "\"); };"
+              << endl;
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) << "static var " << constant_name((*m_iter)->get_name())
+                << "_FIELD_DESC = { new TField(\"" << (*m_iter)->get_name() << "\", "
+                << type_to_enum((*m_iter)->get_type()) << ", " << (*m_iter)->get_key() << "); };"
+                << endl;
+  }
+  out << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    generate_haxe_doc(out, *m_iter);
+    // indent(out) << "private var _" << (*m_iter)->get_name() + " : " +
+    // type_name((*m_iter)->get_type()) << ";" << endl;
+    indent(out) << "@:isVar" << endl;
+    indent(out) << "public var "
+                << (*m_iter)->get_name() + "(get,set) : "
+                   + get_cap_name(type_name((*m_iter)->get_type())) << ";" << endl;
+  }
+
+  out << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) << "inline static var " << upcase_string((*m_iter)->get_name())
+                << "_FIELD_ID : Int = " << (*m_iter)->get_key() << ";" << endl;
+  }
+
+  out << endl;
+
+  // Inner Isset class
+  if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (!type_can_be_null((*m_iter)->get_type())) {
+        indent(out) << "private var __isset_" << (*m_iter)->get_name() << " : Bool = false;"
+                    << endl;
+      }
+    }
+  }
+
+  out << endl;
+
+  // Static initializer to populate global class to struct metadata map
+  if (false) {
+    // TODO: reactivate when needed
+    generate_haxe_meta_data_map(out, tstruct);
+    indent(out) << "{" << endl;
+    indent_up();
+    indent(out) << "FieldMetaData.addStructMetaDataMap(" << type_name(tstruct) << ", metaDataMap);"
+                << endl;
+    indent_down();
+    indent(out) << "}" << endl;
+    indent(out) << "}" << endl;
+  }
+
+  // Default constructor
+  indent(out) << "public function new() {" << endl;
+  indent_up();
+  if (is_exception) {
+    indent(out) << "super();" << endl;
+  }
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if ((*m_iter)->get_value() != NULL) {
+      indent(out) << "this." << (*m_iter)->get_name() << " = "
+                  << (*m_iter)->get_value()->get_integer() << ";" << endl;
+    }
+  }
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  generate_property_getters_setters(out, tstruct);
+  generate_generic_field_getters_setters(out, tstruct);
+  generate_generic_isset_method(out, tstruct);
+
+  generate_haxe_struct_reader(out, tstruct);
+  if (is_result) {
+    generate_haxe_struct_result_writer(out, tstruct);
+  } else {
+    generate_haxe_struct_writer(out, tstruct);
+  }
+  generate_haxe_struct_tostring(out, tstruct);
+  generate_haxe_validator(out, tstruct);
+  scope_down(out);
+  out << endl;
+}
+
+/**
+ * Generates a function to read all the fields of the struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_haxe_struct_reader(ostream& out, t_struct* tstruct) {
+  out << indent() << "public function read( iprot : TProtocol) : Void {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "iprot.IncrementRecursionDepth();" << endl;
+  indent(out) << "try" << endl;
+  scope_up(out);
+
+  // Declare stack tmp variables and read struct header
+  out << indent() << "var field : TField;" << endl << indent() << "iprot.readStructBegin();"
+      << endl;
+
+  // Loop over reading in fields
+  indent(out) << "while (true)" << endl;
+  scope_up(out);
+
+  // Read beginning field marker
+  indent(out) << "field = iprot.readFieldBegin();" << endl;
+
+  // Check for field STOP marker and break
+  indent(out) << "if (field.type == TType.STOP) { " << endl;
+  indent_up();
+  indent(out) << "break;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+
+  // Switch statement on the field we are reading
+  indent(out) << "switch (field.id)" << endl;
+
+  scope_up(out);
+
+  // Generate deserialization code for known cases
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) << "case " << upcase_string((*f_iter)->get_name()) << "_FIELD_ID:" << endl;
+    indent_up();
+    indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+    indent_up();
+
+    generate_deserialize_field(out, *f_iter, "this.");
+    generate_isset_set(out, *f_iter);
+    indent_down();
+    out << indent() << "} else { " << endl << indent() << "  TProtocolUtil.skip(iprot, field.type);"
+        << endl << indent() << "}" << endl;
+    indent_down();
+  }
+
+  // In the default case we skip the field
+  out << indent() << "default:" << endl << indent() << "  TProtocolUtil.skip(iprot, field.type);"
+      << endl;
+
+  scope_down(out);
+
+  // Read field end marker
+  indent(out) << "iprot.readFieldEnd();" << endl;
+
+  scope_down(out);
+
+  out << indent() << "iprot.readStructEnd();" << endl << endl;
+
+  indent(out) << "iprot.DecrementRecursionDepth();" << endl;
+  scope_down(out);
+  indent(out) << "catch(e:Dynamic)" << endl;
+  scope_up(out);
+  indent(out) << "iprot.DecrementRecursionDepth();" << endl;
+  indent(out) << "throw e;" << endl;
+  scope_down(out);
+
+  // check for required fields of primitive type
+  // (which can be checked here but not in the general validate method)
+  out << endl << indent() << "// check for required fields of primitive type, which can't be "
+                             "checked in the validate method" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) {
+      out << indent() << "if (!__isset_" << (*f_iter)->get_name() << ") {" << endl << indent()
+          << "  throw new TProtocolException(TProtocolException.UNKNOWN, \"Required field '"
+          << (*f_iter)->get_name()
+          << "' was not found in serialized data! Struct: \" + toString());" << endl << indent()
+          << "}" << endl;
+    }
+  }
+
+  // performs various checks (e.g. check that all required fields are set)
+  indent(out) << "validate();" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+// generates haxe method to perform various checks
+// (e.g. check that all required fields are set)
+void t_haxe_generator::generate_haxe_validator(ostream& out, t_struct* tstruct) {
+  indent(out) << "public function validate() : Void {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out << indent() << "// check for required fields" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      if (type_can_be_null((*f_iter)->get_type())) {
+        indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl;
+        indent(out)
+            << "  throw new TProtocolException(TProtocolException.UNKNOWN, \"Required field '"
+            << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" << endl;
+        indent(out) << "}" << endl;
+      } else {
+        indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name()
+                    << "' because it's a primitive." << endl;
+      }
+    }
+  }
+
+  // check that fields of type enum have valid values
+  out << indent() << "// check that fields of type enum have valid values" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = (*f_iter);
+    t_type* type = field->get_type();
+    // if field is an enum, check that its value is valid
+    if (type->is_enum()) {
+      indent(out) << "if (" << generate_isset_check(field) << " && !"
+                  << get_cap_name(get_enum_class_name(type)) << ".VALID_VALUES.contains("
+                  << field->get_name() << ")){" << endl;
+      indent_up();
+      indent(out) << "throw new TProtocolException(TProtocolException.UNKNOWN, \"The field '"
+                  << field->get_name() << "' has been assigned the invalid value \" + "
+                  << field->get_name() << ");" << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_haxe_struct_writer(ostream& out, t_struct* tstruct) {
+  out << indent() << "public function write(oprot:TProtocol) : Void {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // performs various checks (e.g. check that all required fields are set)
+  indent(out) << "validate();" << endl;
+  indent(out) << "oprot.IncrementRecursionDepth();" << endl;
+  indent(out) << "try" << endl;
+  scope_up(out);
+
+  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
+    if (could_be_unset) {
+      indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl;
+      indent_up();
+    }
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    if (null_allowed) {
+      out << indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
+      indent_up();
+    }
+
+    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name())
+                << "_FIELD_DESC);" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "this.");
+
+    // Write field closer
+    indent(out) << "oprot.writeFieldEnd();" << endl;
+
+    if (null_allowed) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    if (could_be_unset) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+
+  indent(out) << "oprot.writeFieldStop();" << endl;
+  indent(out) << "oprot.writeStructEnd();" << endl;
+
+  indent(out) << "oprot.DecrementRecursionDepth();" << endl;
+  scope_down(out);
+  indent(out) << "catch(e:Dynamic)" << endl;
+  scope_up(out);
+  indent(out) << "oprot.DecrementRecursionDepth();" << endl;
+  indent(out) << "throw e;" << endl;
+  scope_down(out);
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct,
+ * which is a function result. These fields are only written
+ * if they are set in the Isset array, and only one of them
+ * can be set at a time.
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_haxe_struct_result_writer(ostream& out, t_struct* tstruct) {
+  out << indent() << "public function write(oprot:TProtocol) : Void {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "oprot.IncrementRecursionDepth();" << endl;
+  indent(out) << "try" << endl;
+  scope_up(out);
+
+  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
+
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      out << endl << indent() << "if ";
+    } else {
+      out << " else if ";
+    }
+
+    out << "(this." << generate_isset_check(*f_iter) << ") {" << endl;
+
+    indent_up();
+
+    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name())
+                << "_FIELD_DESC);" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "this.");
+
+    // Write field closer
+    indent(out) << "oprot.writeFieldEnd();" << endl;
+
+    indent_down();
+    indent(out) << "}";
+  }
+
+  indent(out) << endl;
+  indent(out) << "oprot.writeFieldStop();" << endl;
+  indent(out) << "oprot.writeStructEnd();" << endl;
+
+  indent(out) << "oprot.DecrementRecursionDepth();" << endl;
+  scope_down(out);
+  indent(out) << "catch(e:Dynamic)" << endl;
+  scope_up(out);
+  indent(out) << "oprot.DecrementRecursionDepth();" << endl;
+  indent(out) << "throw e;" << endl;
+  scope_down(out);
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+void t_haxe_generator::generate_reflection_getters(ostringstream& out,
+                                                   t_type* type,
+                                                   string field_name,
+                                                   string cap_name) {
+  (void)type;
+  (void)cap_name;
+  indent(out) << "case " << upcase_string(field_name) << "_FIELD_ID:" << endl;
+  indent_up();
+  indent(out) << "return this." << field_name << ";" << endl;
+  indent_down();
+}
+
+void t_haxe_generator::generate_reflection_setters(ostringstream& out,
+                                                   t_type* type,
+                                                   string field_name,
+                                                   string cap_name) {
+  (void)type;
+  (void)cap_name;
+  indent(out) << "case " << upcase_string(field_name) << "_FIELD_ID:" << endl;
+  indent_up();
+  indent(out) << "if (value == null) {" << endl;
+  indent(out) << "  unset" << get_cap_name(field_name) << "();" << endl;
+  indent(out) << "} else {" << endl;
+  indent(out) << "  this." << field_name << " = value;" << endl;
+  indent(out) << "}" << endl << endl;
+
+  indent_down();
+}
+
+void t_haxe_generator::generate_generic_field_getters_setters(std::ostream& out,
+                                                              t_struct* tstruct) {
+
+  std::ostringstream getter_stream;
+  std::ostringstream setter_stream;
+
+  // build up the bodies of both the getter and setter at once
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    t_type* type = get_true_type(field->get_type());
+    std::string field_name = field->get_name();
+    std::string cap_name = get_cap_name(field_name);
+
+    indent_up();
+    generate_reflection_setters(setter_stream, type, field_name, cap_name);
+    generate_reflection_getters(getter_stream, type, field_name, cap_name);
+    indent_down();
+  }
+
+  // create the setter
+  indent(out) << "public function setFieldValue(fieldID : Int, value : Dynamic) : Void {" << endl;
+  indent_up();
+
+  if (fields.size() > 0) {
+    indent(out) << "switch (fieldID) {" << endl;
+    out << setter_stream.str();
+    indent(out) << "default:" << endl;
+    indent(out) << "  throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+    indent(out) << "}" << endl;
+  } else {
+    indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  // create the getter
+  indent(out) << "public function getFieldValue(fieldID : Int) : Dynamic {" << endl;
+  indent_up();
+
+  if (fields.size() > 0) {
+    indent(out) << "switch (fieldID) {" << endl;
+    out << getter_stream.str();
+    indent(out) << "default:" << endl;
+    indent(out) << "  throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+    indent(out) << "}" << endl;
+  } else {
+    indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+  }
+
+  indent_down();
+
+  indent(out) << "}" << endl << endl;
+}
+
+// Creates a generic isSet method that takes the field number as argument
+void t_haxe_generator::generate_generic_isset_method(std::ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // create the isSet method
+  indent(out) << "// Returns true if field corresponding to fieldID is set (has been assigned a "
+                 "value) and false otherwise" << endl;
+  indent(out) << "public function isSet(fieldID : Int) : Bool {" << endl;
+  indent_up();
+  if (fields.size() > 0) {
+    indent(out) << "switch (fieldID) {" << endl;
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      t_field* field = *f_iter;
+      indent(out) << "case " << upcase_string(field->get_name()) << "_FIELD_ID:" << endl;
+      indent_up();
+      indent(out) << "return " << generate_isset_check(field) << ";" << endl;
+      indent_down();
+    }
+
+    indent(out) << "default:" << endl;
+    indent(out) << "  throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+    indent(out) << "}" << endl;
+  } else {
+    indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl;
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a set of property setters/getters for the given struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_property_getters_setters(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    t_type* type = get_true_type(field->get_type());
+    std::string field_name = field->get_name();
+    std::string cap_name = get_cap_name(field_name);
+
+    // Simple getter
+    generate_haxe_doc(out, field);
+    indent(out) << "public function get_" << field_name << "() : " << get_cap_name(type_name(type))
+                << " {" << endl;
+    indent_up();
+    indent(out) << "return this." << field_name << ";" << endl;
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // Simple setter
+    generate_haxe_doc(out, field);
+    indent(out) << "public function set_" << field_name << "(" << field_name << ":"
+                << get_cap_name(type_name(type)) << ") : " << get_cap_name(type_name(type)) << " {"
+                << endl;
+    indent_up();
+    indent(out) << "this." << field_name << " = " << field_name << ";" << endl;
+    generate_isset_set(out, field);
+    indent(out) << "return this." << field_name << ";" << endl;
+
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // Unsetter
+    indent(out) << "public function unset" << cap_name << "() : Void {" << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "this." << field_name << " = null;" << endl;
+    } else {
+      indent(out) << "this.__isset_" << field_name << " = false;" << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // isSet method
+    indent(out) << "// Returns true if field " << field_name
+                << " is set (has been assigned a value) and false otherwise" << endl;
+    indent(out) << "public function is" << get_cap_name("set") << cap_name << "() : Bool {" << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "return this." << field_name << " != null;" << endl;
+    } else {
+      indent(out) << "return this.__isset_" << field_name << ";" << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+}
+
+/**
+ * Generates a toString() method for the given struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_haxe_struct_tostring(ostream& out, t_struct* tstruct) {
+  out << indent() << "public "
+      << "function toString() : String {" << endl;
+  indent_up();
+
+  out << indent() << "var ret : String = \"" << tstruct->get_name() << "(\";" << endl;
+  out << indent() << "var first : Bool = true;" << endl << endl;
+
+  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) {
+    bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
+    if (could_be_unset) {
+      indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl;
+      indent_up();
+    }
+
+    t_field* field = (*f_iter);
+
+    if (!first) {
+      indent(out) << "if (!first) ret +=  \", \";" << endl;
+    }
+    indent(out) << "ret += \"" << (*f_iter)->get_name() << ":\";" << endl;
+    bool can_be_null = type_can_be_null(field->get_type());
+    if (can_be_null) {
+      indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl;
+      indent(out) << "  ret += \"null\";" << endl;
+      indent(out) << "} else {" << endl;
+      indent_up();
+    }
+
+    if (field->get_type()->is_binary()) {
+      indent(out) << "  ret += \"BINARY\";" << endl;
+    } else if (field->get_type()->is_enum()) {
+      indent(out) << "var " << field->get_name()
+                  << "_name : String = " << get_cap_name(get_enum_class_name(field->get_type()))
+                  << ".VALUES_TO_NAMES[this." << (*f_iter)->get_name() << "];" << endl;
+      indent(out) << "if (" << field->get_name() << "_name != null) {" << endl;
+      indent(out) << "  ret += " << field->get_name() << "_name;" << endl;
+      indent(out) << "  ret += \" (\";" << endl;
+      indent(out) << "}" << endl;
+      indent(out) << "ret += this." << field->get_name() << ";" << endl;
+      indent(out) << "if (" << field->get_name() << "_name != null) {" << endl;
+      indent(out) << "  ret += \")\";" << endl;
+      indent(out) << "}" << endl;
+    } else {
+      indent(out) << "ret += this." << (*f_iter)->get_name() << ";" << endl;
+    }
+
+    if (can_be_null) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    indent(out) << "first = false;" << endl;
+
+    if (could_be_unset) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    first = false;
+  }
+  out << indent() << "ret += \")\";" << endl << indent() << "return ret;" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a static map with meta data to store information such as fieldID to
+ * fieldName mapping
+ *
+ * @param tstruct The struct definition
+ */
+void t_haxe_generator::generate_haxe_meta_data_map(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Static Map with fieldID -> FieldMetaData mappings
+  indent(out) << "inline static var metaDataMap : IntMap = new IntMap();" << endl;
+
+  if (fields.size() > 0) {
+    // Populate map
+    scope_up(out);
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      t_field* field = *f_iter;
+      std::string field_name = field->get_name();
+      indent(out) << "metaDataMap[" << upcase_string(field_name)
+                  << "_FIELD_ID] = new FieldMetaData(\"" << field_name << "\", ";
+
+      // Set field requirement type (required, optional, etc.)
+      if (field->get_req() == t_field::T_REQUIRED) {
+        out << "TFieldRequirementType.REQUIRED, ";
+      } else if (field->get_req() == t_field::T_OPTIONAL) {
+        out << "TFieldRequirementType.OPTIONAL, ";
+      } else {
+        out << "TFieldRequirementType.DEFAULT, ";
+      }
+
+      // Create value meta data
+      generate_field_value_meta_data(out, field->get_type());
+      out << ");" << endl;
+    }
+    scope_down(out);
+  }
+}
+
+/**
+ * Returns a string with the haxe representation of the given thrift type
+ * (e.g. for the type struct it returns "TType.STRUCT")
+ */
+std::string t_haxe_generator::get_haxe_type_string(t_type* type) {
+  if (type->is_list()) {
+    return "TType.LIST";
+  } else if (type->is_map()) {
+    return "TType.MAP";
+  } else if (type->is_set()) {
+    return "TType.SET";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.STRUCT";
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_typedef()) {
+    return get_haxe_type_string(((t_typedef*)type)->get_type());
+  } else if (type->is_base_type()) {
+    switch (((t_base_type*)type)->get_base()) {
+    case t_base_type::TYPE_VOID:
+      return "TType.VOID";
+      break;
+    case t_base_type::TYPE_STRING:
+      return "TType.STRING";
+      break;
+    case t_base_type::TYPE_BOOL:
+      return "TType.BOOL";
+      break;
+    case t_base_type::TYPE_I8:
+      return "TType.BYTE";
+      break;
+    case t_base_type::TYPE_I16:
+      return "TType.I16";
+      break;
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+      break;
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      return "TType.DOUBLE";
+      break;
+    default:
+      throw std::runtime_error("Unknown thrift type \"" + type->get_name()
+                               + "\" passed to t_haxe_generator::get_haxe_type_string!");
+      break; // This should never happen!
+    }
+  } else {
+    throw std::runtime_error(
+        "Unknown thrift type \"" + type->get_name()
+        + "\" passed to t_haxe_generator::get_haxe_type_string!"); // This should never happen!
+  }
+}
+
+void t_haxe_generator::generate_field_value_meta_data(std::ostream& out, t_type* type) {
+  out << endl;
+  indent_up();
+  indent_up();
+  if (type->is_struct()) {
+    indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type);
+  } else if (type->is_container()) {
+    if (type->is_list()) {
+      indent(out) << "new ListMetaData(TType.LIST, ";
+      t_type* elem_type = ((t_list*)type)->get_elem_type();
+      generate_field_value_meta_data(out, elem_type);
+    } else if (type->is_set()) {
+      indent(out) << "new SetMetaData(TType.SET, ";
+      t_type* elem_type = ((t_list*)type)->get_elem_type();
+      generate_field_value_meta_data(out, elem_type);
+    } else { // map
+      indent(out) << "new MapMetaData(TType.MAP, ";
+      t_type* key_type = ((t_map*)type)->get_key_type();
+      t_type* val_type = ((t_map*)type)->get_val_type();
+      generate_field_value_meta_data(out, key_type);
+      out << ", ";
+      generate_field_value_meta_data(out, val_type);
+    }
+  } else {
+    indent(out) << "new FieldValueMetaData(" << get_haxe_type_string(type);
+  }
+  out << ")";
+  indent_down();
+  indent_down();
+}
+
+/**
+ * Generates a thrift service. In C++, this comprises an entirely separate
+ * header and source file. The header file defines the methods and includes
+ * the data types defined in the main header file, and the implementation
+ * file contains implementations of the basic printer and default interfaces.
+ *
+ * @param tservice The service definition
+ */
+void t_haxe_generator::generate_service(t_service* tservice) {
+  // Make interface file
+  string f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + ".hx";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << autogen_comment() << haxe_package() << ";" << endl;
+
+  f_service_ << endl << haxe_type_imports() << haxe_thrift_imports()
+             << haxe_thrift_gen_imports(tservice);
+
+  if (tservice->get_extends() != NULL) {
+    t_type* parent = tservice->get_extends();
+    string parent_namespace = parent->get_program()->get_namespace("haxe");
+    if (!parent_namespace.empty() && parent_namespace != package_name_) {
+      f_service_ << "import " << type_name(parent) << ";" << endl;
+    }
+  }
+
+  f_service_ << endl;
+
+  generate_service_interface(tservice);
+
+  f_service_.close();
+
+  // Now make the implementation/client file
+  f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + "Impl.hx";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << autogen_comment() << haxe_package() << ";" << endl << endl << haxe_type_imports()
+             << haxe_thrift_imports() << haxe_thrift_gen_imports(tservice) << endl;
+
+  if (tservice->get_extends() != NULL) {
+    t_type* parent = tservice->get_extends();
+    string parent_namespace = parent->get_program()->get_namespace("haxe");
+    if (!parent_namespace.empty() && parent_namespace != package_name_) {
+      f_service_ << "import " << type_name(parent) << "Impl;" << endl;
+    }
+  }
+
+  f_service_ << endl;
+
+  generate_service_client(tservice);
+
+  f_service_.close();
+
+  // Now make the helper class files
+  generate_service_helpers(tservice);
+
+  // Now make the processor/server file
+  f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + "Processor.hx";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << autogen_comment() << haxe_package() << ";" << endl << endl << haxe_type_imports()
+             << haxe_thrift_imports() << haxe_thrift_gen_imports(tservice) << endl;
+
+  if (!package_name_.empty()) {
+    f_service_ << "import " << package_name_ << ".*;" << endl;
+    f_service_ << "import " << package_name_ << "." << get_cap_name(service_name_).c_str()
+               << "Impl;" << endl;
+    f_service_ << endl;
+  }
+
+  generate_service_server(tservice);
+
+  f_service_.close();
+}
+
+/**
+ * Generates the code snippet for the onSuccess callbacks
+ *
+ * @param tfunction The service function to generate code for.
+ */
+string t_haxe_generator::generate_service_method_onsuccess(t_function* tfunction,
+                                                           bool as_type,
+                                                           bool omit_name) {
+  if (tfunction->is_oneway()) {
+    return "";
+  }
+
+  string name = "";
+  if (!omit_name) {
+    name = "onSuccess";
+    if (as_type) {
+      name += " : ";
+    }
+  }
+
+  if (tfunction->get_returntype()->is_void()) {
+    if (as_type) {
+      return name + "Void->Void = null";
+    } else {
+      return name + "() : Void";
+    }
+  }
+
+  if (as_type) {
+    return name + type_name(tfunction->get_returntype()) + "->Void = null";
+  } else {
+    return name + "( retval : " + type_name(tfunction->get_returntype()) + ")";
+  }
+}
+
+/**
+ * Generates a service method header
+ *
+ * @param tfunction The service function to generate code for.
+ */
+void t_haxe_generator::generate_service_method_signature(t_function* tfunction, bool is_interface) {
+  if (callbacks_) {
+    generate_service_method_signature_callback(tfunction, is_interface);
+  } else {
+    generate_service_method_signature_normal(tfunction, is_interface);
+  }
+}
+
+/**
+ * Generates a service method header in "normal" style
+ *
+ * @param tfunction The service function to generate code for.
+ */
+void t_haxe_generator::generate_service_method_signature_normal(t_function* tfunction,
+                                                                bool is_interface) {
+  if (is_interface) {
+    indent(f_service_) << function_signature_normal(tfunction) << ";" << endl << endl;
+  } else {
+    indent(f_service_) << "public " << function_signature_normal(tfunction) << " {" << endl;
+  }
+}
+
+/**
+ * Generates a service method header in "callback" style
+ *
+ * @param tfunction The service function to generate code for.
+ */
+void t_haxe_generator::generate_service_method_signature_callback(t_function* tfunction,
+                                                                  bool is_interface) {
+  if (!tfunction->is_oneway()) {
+    std::string on_success_impl = generate_service_method_onsuccess(tfunction, false, false);
+    indent(f_service_) << "// function onError(Dynamic) : Void;" << endl;
+    indent(f_service_) << "// function " << on_success_impl.c_str() << ";" << endl;
+  }
+
+  if (is_interface) {
+    indent(f_service_) << function_signature_callback(tfunction) << ";" << endl << endl;
+  } else {
+    indent(f_service_) << "public " << function_signature_callback(tfunction) << " {" << endl;
+  }
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_haxe_generator::generate_service_interface(t_service* tservice) {
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends_iface = " extends " + tservice->get_extends()->get_name();
+  }
+
+  generate_haxe_doc(f_service_, tservice);
+  // generate_rtti_decoration(f_service_); - not yet, because of
+  // https://github.com/HaxeFoundation/haxe/issues/3626
+  generate_macro_decoration(f_service_);
+  f_service_ << indent() << "interface " << get_cap_name(service_name_) << extends_iface << " {"
+             << endl << endl;
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_haxe_doc(f_service_, *f_iter);
+    generate_service_method_signature(*f_iter, true);
+  }
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates structs for all the service args and return types
+ *
+ * @param tservice The service
+ */
+void t_haxe_generator::generate_service_helpers(t_service* tservice) {
+  f_service_ << endl << endl;
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_haxe_struct(ts, false);
+    generate_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_haxe_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = get_cap_name(tservice->get_extends()->get_name());
+    extends_client = " extends " + extends + "Impl";
+  }
+
+  generate_rtti_decoration(f_service_);
+  // build macro is inherited from interface
+  indent(f_service_) << "class " << get_cap_name(service_name_) << "Impl" << extends_client
+                     << " implements " << get_cap_name(service_name_) << " {" << endl << endl;
+  indent_up();
+
+  indent(f_service_) << "public function new( iprot : TProtocol, oprot : TProtocol = null)" << endl;
+  scope_up(f_service_);
+  if (extends.empty()) {
+    f_service_ << indent() << "iprot_ = iprot;" << endl;
+    f_service_ << indent() << "if (oprot == null) {" << endl;
+    indent_up();
+    f_service_ << indent() << "oprot_ = iprot;" << endl;
+    indent_down();
+    f_service_ << indent() << "} else {" << endl;
+    indent_up();
+    f_service_ << indent() << "oprot_ = oprot;" << endl;
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+  } else {
+    f_service_ << indent() << "super(iprot, oprot);" << endl;
+  }
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_ << indent() << "private var iprot_ : TProtocol;" << endl << indent()
+               << "private var oprot_ : TProtocol;" << endl << indent()
+               << "private var seqid_ : Int;" << endl << endl;
+
+    indent(f_service_) << "public function getInputProtocol() : TProtocol" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "return this.iprot_;" << endl;
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    indent(f_service_) << "public function getOutputProtocol() : TProtocol" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "return this.oprot_;" << endl;
+    scope_down(f_service_);
+    f_service_ << 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) {
+    string funname = (*f_iter)->get_name();
+
+    // Open function
+    generate_service_method_signature(*f_iter, false);
+
+    indent_up();
+
+    // Get the struct of function call params
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+
+    string argsname = get_cap_name((*f_iter)->get_name() + "_args");
+    vector<t_field*>::const_iterator fld_iter;
+    const vector<t_field*>& fields = arg_struct->get_members();
+
+    // Serialize the request
+    string calltype = (*f_iter)->is_oneway() ? "ONEWAY" : "CALL";
+    f_service_ << indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname
+               << "\", TMessageType." << calltype << ", seqid_));" << endl << indent()
+               << "var args : " << argsname << " = new " << argsname << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << indent() << "args." << (*fld_iter)->get_name() << " = "
+                 << (*fld_iter)->get_name() << ";" << endl;
+    }
+
+    f_service_ << indent() << "args.write(oprot_);" << endl << indent()
+               << "oprot_.writeMessageEnd();" << endl;
+
+    if (!((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) {
+      f_service_ << indent() << "var retval : " << type_name((*f_iter)->get_returntype()) << ";"
+                 << endl;
+    }
+
+    if ((*f_iter)->is_oneway()) {
+      f_service_ << indent() << "oprot_.getTransport().flush();" << endl;
+    } else {
+      indent(f_service_) << "oprot_.getTransport().flush(function(error:Dynamic) : Void {" << endl;
+      indent_up();
+      if (callbacks_) {
+        indent(f_service_) << "try {" << endl;
+        indent_up();
+      }
+      string resultname = get_cap_name((*f_iter)->get_name() + "_result");
+      indent(f_service_) << "if (error != null) {" << endl;
+      indent_up();
+      if (callbacks_) {
+        indent(f_service_) << "if (onError != null) onError(error);" << endl;
+        indent(f_service_) << "return;" << endl;
+      } else {
+        indent(f_service_) << "throw error;" << endl;
+      }
+      indent_down();
+      indent(f_service_) << "}" << endl;
+      indent(f_service_) << "var msg : TMessage = iprot_.readMessageBegin();" << endl;
+      indent(f_service_) << "if (msg.type == TMessageType.EXCEPTION) {" << endl;
+      indent_up();
+      indent(f_service_) << "var x = TApplicationException.read(iprot_);" << endl;
+      indent(f_service_) << "iprot_.readMessageEnd();" << endl;
+      if (callbacks_) {
+        indent(f_service_) << "if (onError != null) onError(x);" << endl;
+        indent(f_service_) << "return;" << endl;
+      } else {
+        indent(f_service_) << "throw x;" << endl;
+      }
+      indent_down();
+      indent(f_service_) << "}" << endl;
+      indent(f_service_) << "var result : " << resultname << " = new " << resultname << "();"
+                         << endl;
+      indent(f_service_) << "result.read(iprot_);" << endl;
+      indent(f_service_) << "iprot_.readMessageEnd();" << endl;
+
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) << "if (result." << generate_isset_check("success") << ") {" << endl;
+        indent_up();
+        if (callbacks_) {
+          indent(f_service_) << "if (onSuccess != null) onSuccess(result.success);" << endl;
+          indent(f_service_) << "return;" << endl;
+        } else {
+          indent(f_service_) << "retval = result.success;" << endl;
+          indent(f_service_) << "return;" << endl;
+        }
+        indent_down();
+        indent(f_service_) << "}" << 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) {
+        indent(f_service_) << "if (result." << (*x_iter)->get_name() << " != null) {" << endl;
+        indent_up();
+        if (callbacks_) {
+          indent(f_service_) << "if (onError != null) onError(result." << (*x_iter)->get_name()
+                             << ");" << endl;
+          indent(f_service_) << "return;" << endl;
+        } else {
+          indent(f_service_) << "throw result." << (*x_iter)->get_name() << ";" << endl;
+        }
+        indent_down();
+        indent(f_service_) << "}" << endl;
+      }
+
+      // If you get here it's an exception, unless a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        if (callbacks_) {
+          indent(f_service_) << "if (onSuccess != null) onSuccess();" << endl;
+        }
+        indent(f_service_) << "return;" << endl;
+      } else {
+        if (callbacks_) {
+          indent(f_service_) << "if (onError != null)" << endl;
+          indent_up();
+          indent(f_service_)
+              << "onError( new TApplicationException(TApplicationException.MISSING_RESULT," << endl;
+          indent(f_service_) << "                               \"" << (*f_iter)->get_name()
+                             << " failed: unknown result\"));" << endl;
+          indent_down();
+        } else {
+          indent(f_service_)
+              << "throw new TApplicationException(TApplicationException.MISSING_RESULT," << endl;
+          indent(f_service_) << "                            \"" << (*f_iter)->get_name()
+                             << " failed: unknown result\");" << endl;
+        }
+      }
+
+      if (callbacks_) {
+        indent_down();
+        indent(f_service_) << "} catch( e : TException) {" << endl;
+        indent_up();
+        indent(f_service_) << "if (onError != null) onError(e);" << endl;
+        indent_down();
+        indent(f_service_) << "}" << endl;
+      }
+
+      indent_down();
+      indent(f_service_) << "});" << endl;
+    }
+
+    if (!((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) {
+      f_service_ << indent() << "return retval;" << endl;
+    }
+
+    // Close function
+    scope_down(f_service_);
+    f_service_ << endl;
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl;
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_haxe_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  // Extends stuff
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = get_cap_name(type_name(tservice->get_extends()));
+    extends_processor = " extends " + extends + "Processor";
+  }
+
+  // Generate the header portion
+  generate_rtti_decoration(f_service_);
+  generate_macro_decoration(f_service_);
+  indent(f_service_) << "class " << get_cap_name(service_name_) << "Processor" << extends_processor
+                     << " implements TProcessor {" << endl << endl;
+  indent_up();
+
+  f_service_ << indent() << "private var " << get_cap_name(service_name_)
+             << "_iface_ : " << get_cap_name(service_name_) << ";" << endl;
+
+  if (extends.empty()) {
+    f_service_ << indent()
+               << "private var PROCESS_MAP = new StringMap< Int->TProtocol->TProtocol->Void >();"
+               << endl;
+  }
+
+  f_service_ << endl;
+
+  indent(f_service_) << "public function new( iface : " << get_cap_name(service_name_) << ")"
+                     << endl;
+  scope_up(f_service_);
+  if (!extends.empty()) {
+    f_service_ << indent() << "super(iface);" << endl;
+  }
+  f_service_ << indent() << get_cap_name(service_name_) << "_iface_ = iface;" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << indent() << "PROCESS_MAP.set(\"" << (*f_iter)->get_name() << "\", "
+               << (*f_iter)->get_name() << "());" << endl;
+  }
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generate the server implementation
+  string override = "";
+  if (tservice->get_extends() != NULL) {
+    override = "override ";
+  }
+  indent(f_service_) << override
+                     << "public function process( iprot : TProtocol, oprot : TProtocol) : Bool"
+                     << endl;
+  scope_up(f_service_);
+
+  f_service_ << indent() << "var msg : TMessage = iprot.readMessageBegin();" << endl;
+
+  // TODO(mcslee): validate message, was the seqid etc. legit?
+  // AS- If all method is oneway:
+  // do you have an oprot?
+  // do you you need nullcheck?
+  f_service_
+      << indent() << "var fn  = PROCESS_MAP.get(msg.name);" << endl << indent()
+      << "if (fn == null) {" << endl << indent() << "  TProtocolUtil.skip(iprot, TType.STRUCT);"
+      << endl << indent() << "  iprot.readMessageEnd();" << endl << indent()
+      << "  var x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, \"Invalid "
+         "method name: '\"+msg.name+\"'\");" << endl << indent()
+      << "  oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));"
+      << endl << indent() << "  x.write(oprot);" << endl << indent() << "  oprot.writeMessageEnd();"
+      << endl << indent() << "  oprot.getTransport().flush();" << endl << indent()
+      << "  return true;" << endl << indent() << "}" << endl << indent()
+      << "fn( msg.seqid, iprot, oprot);" << endl;
+
+  f_service_ << indent() << "return true;" << endl;
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl << endl;
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_haxe_generator::generate_function_helpers(t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return;
+  }
+
+  string resultname = get_cap_name(tfunction->get_name() + "_result");
+  t_struct result(program_, resultname);
+  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_haxe_struct(&result, false, true);
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_haxe_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+  // Open class
+  indent(f_service_) << "private function " << tfunction->get_name()
+                     << "() : Int->TProtocol->TProtocol->Void {" << endl;
+  indent_up();
+
+  // Open function
+  indent(f_service_) << "return function( seqid : Int, iprot : TProtocol, oprot : TProtocol) : Void"
+                     << endl;
+  scope_up(f_service_);
+
+  string argsname = get_cap_name(tfunction->get_name() + "_args");
+  string resultname = get_cap_name(tfunction->get_name() + "_result");
+
+  f_service_ << indent() << "var args : " << argsname << " = new " << argsname << "();" << endl
+             << indent() << "args.read(iprot);" << endl << indent() << "iprot.readMessageEnd();"
+             << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << "var result : " << resultname << " = new " << resultname << "();"
+               << endl;
+  }
+
+  // Try block for any  function to catch (defined or undefined) exceptions
+  f_service_ << indent() << "try {" << endl;
+  indent_up();
+
+  if (callbacks_) {
+    // callback function style onError/onSuccess
+
+    // 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_ << indent();
+    f_service_ << get_cap_name(service_name_) << "_iface_." << 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." << (*f_iter)->get_name();
+    }
+
+    if (tfunction->is_oneway()) {
+      f_service_ << ");" << endl;
+    } else {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      string on_success = generate_service_method_onsuccess(tfunction, false, true);
+      indent_up();
+      f_service_ << endl;
+      indent(f_service_) << "null,  // errors are thrown by the handler" << endl;
+      if (tfunction->get_returntype()->is_void()) {
+        indent(f_service_) << "null); // no retval" << endl;
+      } else {
+        indent(f_service_) << "function" << on_success.c_str() << " {" << endl;
+        if (!tfunction->get_returntype()->is_void()) {
+          indent_up();
+          indent(f_service_) << "result.success = retval;" << endl;
+          indent_down();
+        }
+        indent(f_service_) << "});" << endl;
+      }
+      indent_down();
+    }
+
+  } else {
+    // normal function():result style
+
+    // 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_ << indent();
+    if (!(tfunction->is_oneway() || tfunction->get_returntype()->is_void())) {
+      f_service_ << "result.success = ";
+    }
+    f_service_ << get_cap_name(service_name_) << "_iface_." << 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." << (*f_iter)->get_name();
+    }
+    f_service_ << ");" << endl;
+  }
+
+  indent_down();
+  f_service_ << indent() << "}";
+  if (!tfunction->is_oneway()) {
+    // catch exceptions defined in the IDL
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << " catch (" << (*x_iter)->get_name() << ":"
+                 << get_cap_name(type_name((*x_iter)->get_type(), false, false)) << ") {" << endl;
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        f_service_ << indent() << "result." << (*x_iter)->get_name() << " = "
+                   << (*x_iter)->get_name() << ";" << endl;
+        indent_down();
+        f_service_ << indent() << "}";
+      } else {
+        f_service_ << "}";
+      }
+    }
+  }
+
+  // always catch all exceptions to prevent from service denial
+  f_service_ << " catch (th : Dynamic) {" << endl;
+  indent_up();
+  indent(f_service_) << "trace(\"Internal error processing " << tfunction->get_name() << "\", th);"
+                     << endl;
+  if (!tfunction->is_oneway()) {
+    indent(f_service_) << "var x = new TApplicationException(TApplicationException.INTERNAL_ERROR, "
+                          "\"Internal error processing " << tfunction->get_name() << "\");" << endl;
+    indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name()
+                       << "\", TMessageType.EXCEPTION, seqid));" << endl;
+    indent(f_service_) << "x.write(oprot);" << endl;
+    indent(f_service_) << "oprot.writeMessageEnd();" << endl;
+    indent(f_service_) << "oprot.getTransport().flush();" << endl;
+  }
+  indent(f_service_) << "return;" << endl;
+  indent_down();
+  f_service_ << indent() << "}" << endl;
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    f_service_ << indent() << "return;" << endl;
+    scope_down(f_service_);
+
+    // Close class
+    indent_down();
+    f_service_ << indent() << "}" << endl << endl;
+    return;
+  }
+
+  f_service_ << indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name()
+             << "\", TMessageType.REPLY, seqid));" << endl << indent() << "result.write(oprot);"
+             << endl << indent() << "oprot.writeMessageEnd();" << endl << indent()
+             << "oprot.getTransport().flush();" << endl;
+
+  // Close function
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Close class
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+/**
+ * Deserializes a field of any type.
+ *
+ * @param tfield The field
+ * @param prefix The variable name or container for this field
+ */
+void t_haxe_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name();
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    indent(out) << name << " = 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:
+        if (type->is_binary()) {
+          out << "readBinary();";
+        } else {
+          out << "readString();";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "readBool();";
+        break;
+      case t_base_type::TYPE_I8:
+        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 Haxe name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "readI32();";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a struct, invokes read()
+ */
+void t_haxe_generator::generate_deserialize_struct(ostream& out,
+                                                   t_struct* tstruct,
+                                                   string prefix) {
+  out << indent() << prefix << " = new " << get_cap_name(type_name(tstruct)) << "();" << endl
+      << indent() << prefix << ".read(iprot);" << endl;
+}
+
+/**
+ * Deserializes a container by reading its size and then iterating
+ */
+void t_haxe_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  string obj;
+
+  if (ttype->is_map()) {
+    obj = tmp("_map");
+  } else if (ttype->is_set()) {
+    obj = tmp("_set");
+  } else if (ttype->is_list()) {
+    obj = tmp("_list");
+  }
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    indent(out) << "var " << obj << " = iprot.readMapBegin();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "var " << obj << " = iprot.readSetBegin();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "var " << obj << " = iprot.readListBegin();" << endl;
+  }
+
+  indent(out) << prefix << " = new " << type_name(ttype, false, true)
+              // size the collection correctly
+              << "("
+              << ");" << endl;
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) << "for( " << i << " in 0 ... " << obj << ".size)" << endl;
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  scope_down(out);
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "iprot.readMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "iprot.readSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "iprot.readListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_haxe_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) << declare_field(&fkey) << endl;
+  indent(out) << declare_field(&fval) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) << prefix << ".set( " << key << ", " << val << ");" << endl;
+}
+
+/**
+ * Deserializes a set element
+ */
+void t_haxe_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".add(" << elem << ");" << endl;
+}
+
+/**
+ * Deserializes a list element
+ */
+void t_haxe_generator::generate_deserialize_list_element(ostream& out,
+                                                         t_list* tlist,
+                                                         string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".add(" << elem << ");" << endl;
+}
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_haxe_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name());
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, prefix + tfield->get_name());
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    string name = prefix + tfield->get_name();
+    indent(out) << "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:
+        if (type->is_binary()) {
+          out << "writeBinary(" << name << ");";
+        } else {
+          out << "writeString(" << name << ");";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ");";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "writeByte(" << name << ");";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16(" << name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32(" << name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64(" << name << ");";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble(" << name << ");";
+        break;
+      default:
+        throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32(" << name << ");";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_haxe_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  (void)tstruct;
+  out << indent() << prefix << ".write(oprot);" << endl;
+}
+
+/**
+ * Serializes a container by writing its size then the elements.
+ *
+ * @param ttype  The type of container
+ * @param prefix String prefix for fields
+ */
+void t_haxe_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    string iter = tmp("_key");
+    string counter = tmp("_sizeCounter");
+    indent(out) << "var " << counter << " : Int = 0;" << endl;
+    indent(out) << "for( " << iter << " in " << prefix << ") {" << endl;
+    indent(out) << "  " << counter << +"++;" << endl;
+    indent(out) << "}" << endl;
+
+    indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type())
+                << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << counter << "));"
+                << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type())
+                << ", " << prefix << ".size));" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.writeListBegin(new TList("
+                << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".length));"
+                << endl;
+  }
+
+  string iter = tmp("elem");
+  if (ttype->is_map()) {
+    indent(out) << "for( " << iter << " in " << prefix << ".keys())" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "for( " << iter << " in " << prefix << ".toArray())" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "for( " << iter << " in " << prefix << ")" << endl;
+  }
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
+  } else if (ttype->is_set()) {
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+  } else if (ttype->is_list()) {
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+  }
+
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "oprot.writeMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.writeSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.writeListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ */
+void t_haxe_generator::generate_serialize_map_element(ostream& out,
+                                                      t_map* tmap,
+                                                      string iter,
+                                                      string map) {
+  t_field kfield(tmap->get_key_type(), iter);
+  generate_serialize_field(out, &kfield, "");
+  t_field vfield(tmap->get_val_type(), map + ".get(" + iter + ")");
+  generate_serialize_field(out, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_haxe_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_haxe_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Returns a haxe type name
+ *
+ * @param ttype The type
+ * @param container Is the type going inside a container?
+ * @return haxe type name, i.e. HashMap<Key,Value>
+ */
+string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_init) {
+  (void)in_init;
+
+  // typedefs are just resolved to their real type
+  ttype = get_true_type(ttype);
+  string prefix;
+
+  if (ttype->is_base_type()) {
+    return base_type_name((t_base_type*)ttype, in_container);
+  }
+
+  if (ttype->is_enum()) {
+    return "Int";
+  }
+
+  if (ttype->is_map()) {
+    t_type* tkey = get_true_type(((t_map*)ttype)->get_key_type());
+    t_type* tval = get_true_type(((t_map*)ttype)->get_val_type());
+    if (tkey->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)tkey)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_STRING:
+        if (!(tkey->is_binary())) {
+          return "StringMap< " + type_name(tval) + ">";
+        }
+        break; // default to ObjectMap<>
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+        return "IntMap< " + type_name(tval) + ">";
+      case t_base_type::TYPE_I64:
+        return "Int64Map< " + type_name(tval) + ">";
+      default:
+        break; // default to ObjectMap<>
+      }
+    }
+    if (tkey->is_enum()) {
+      return "IntMap< " + type_name(tval) + ">";
+    }
+    return "ObjectMap< " + type_name(tkey) + ", " + type_name(tval) + ">";
+  }
+
+  if (ttype->is_set()) {
+    t_type* tkey = get_true_type(((t_set*)ttype)->get_elem_type());
+    if (tkey->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)tkey)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_STRING:
+        if (!(tkey->is_binary())) {
+          return "StringSet";
+        }
+        break; // default to ObjectSet
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+        return "IntSet";
+      case t_base_type::TYPE_I64:
+        return "Int64Set";
+      default:
+        break; // default to ObjectSet
+      }
+    }
+    if (tkey->is_enum()) {
+      return "IntSet";
+    }
+    return "ObjectSet< " + type_name(tkey) + ">";
+  }
+
+  if (ttype->is_list()) {
+    t_type* telm = ((t_list*)ttype)->get_elem_type();
+    return "List< " + type_name(telm) + ">";
+  }
+
+  // Check for namespacing
+  t_program* program = ttype->get_program();
+  if (program != NULL && program != program_) {
+    string package = program->get_namespace("haxe");
+    if (!package.empty()) {
+      return package + "." + ttype->get_name();
+    }
+  }
+
+  return ttype->get_name();
+}
+
+/**
+ * Returns the haxe type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ * @param container Is it going in a haxe container?
+ */
+string t_haxe_generator::base_type_name(t_base_type* type, bool in_container) {
+  (void)in_container;
+  t_base_type::t_base tbase = type->get_base();
+
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "Void";
+  case t_base_type::TYPE_STRING:
+    if (type->is_binary()) {
+      return "haxe.io.Bytes";
+    } else {
+      return "String";
+    }
+  case t_base_type::TYPE_BOOL:
+    return "Bool";
+  case t_base_type::TYPE_I8:
+  case t_base_type::TYPE_I16:
+  case t_base_type::TYPE_I32:
+    return "haxe.Int32";
+  case t_base_type::TYPE_I64:
+    return "haxe.Int64";
+  case t_base_type::TYPE_DOUBLE:
+    return "Float";
+  default:
+    throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_haxe_generator::declare_field(t_field* tfield, bool init) {
+  // TODO(mcslee): do we ever need to initialize the field?
+  string result = "var " + tfield->get_name() + " : " + type_name(tfield->get_type());
+  if (init) {
+    t_type* ttype = get_true_type(tfield->get_type());
+    if (ttype->is_base_type() && tfield->get_value() != NULL) {
+      std::ofstream dummy;
+      result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
+    } else if (ttype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "NO T_VOID CONSTRUCT";
+      case t_base_type::TYPE_STRING:
+        result += " = null";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = false";
+        break;
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = (double)0";
+        break;
+      }
+
+    } else if (ttype->is_enum()) {
+      result += " = 0";
+    } else if (ttype->is_container()) {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    } else {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    }
+  }
+  return result + ";";
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_haxe_generator::function_signature_callback(t_function* tfunction) {
+  std::string on_error_success = "onError : Dynamic->Void = null, "
+                                 + generate_service_method_onsuccess(tfunction, true, false);
+
+  std::string arguments = argument_list(tfunction->get_arglist());
+  if (!tfunction->is_oneway()) {
+    if (arguments != "") {
+      arguments += ", ";
+    }
+    arguments += on_error_success; //"onError : Function, onSuccess : Function";
+  }
+
+  std::string result = "function " + tfunction->get_name() + "(" + arguments + ") : Void";
+  return result;
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_haxe_generator::function_signature_normal(t_function* tfunction) {
+  std::string arguments = argument_list(tfunction->get_arglist());
+
+  std::string resulttype;
+  if (tfunction->is_oneway() || tfunction->get_returntype()->is_void()) {
+    resulttype = "Void";
+  } else {
+    resulttype = type_name(tfunction->get_returntype());
+  }
+
+  std::string result = "function " + tfunction->get_name() + "(" + arguments + ") : " + resulttype;
+  return result;
+}
+
+/**
+ * Renders a comma separated field list, with type names
+ */
+string t_haxe_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_name((*f_iter)->get_type());
+  }
+  return result;
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ */
+string t_haxe_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 "TType.STRING";
+    case t_base_type::TYPE_BOOL:
+      return "TType.BOOL";
+    case t_base_type::TYPE_I8:
+      return "TType.BYTE";
+    case t_base_type::TYPE_I16:
+      return "TType.I16";
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "TType.DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.STRUCT";
+  } else if (type->is_map()) {
+    return "TType.MAP";
+  } else if (type->is_set()) {
+    return "TType.SET";
+  } else if (type->is_list()) {
+    return "TType.LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Haxe class names must start with uppercase letter, but Haxe namespaces must not.
+ */
+std::string t_haxe_generator::get_cap_name(std::string name) {
+  if (name.length() == 0) {
+    return name;
+  }
+
+  // test.for.Generic< data.Type, or.the.Like> and handle it recursively
+  size_t generic_first = name.find('<');
+  size_t generic_last = name.rfind('>');
+  if ((generic_first != std::string::npos) && (generic_last != std::string::npos)) {
+    string outer_type = name.substr(0, generic_first);
+    string inner_types = name.substr(generic_first + 1, generic_last - generic_first - 1);
+
+    string new_inner = "";
+    size_t comma_start = 0;
+    while (comma_start < inner_types.length()) {
+      size_t comma_pos = comma_start;
+      int nested = 0;
+
+      while (comma_pos < inner_types.length()) {
+        bool found = false;
+        switch (inner_types[comma_pos]) {
+        case '<':
+          ++nested;
+          break;
+        case '>':
+          --nested;
+          break;
+        case ',':
+          found = (nested == 0);
+          break;
+        }
+        if (found) {
+          break;
+        }
+        ++comma_pos;
+      }
+
+      if (new_inner.length() > 0) {
+        new_inner += ",";
+      }
+
+      string inner = inner_types.substr(comma_start, comma_pos - comma_start);
+      new_inner += get_cap_name(inner);
+      comma_start = ++comma_pos;
+    }
+
+    return get_cap_name(outer_type) + "<" + new_inner + ">";
+  }
+
+  // package name
+  size_t index = name.find_first_not_of(" \n\r\t");
+  if (index < name.length()) {
+    name[index] = tolower(name[index]);
+    index = name.find('.');
+    while (index != std::string::npos) {
+      if (++index < name.length()) {
+        name[index] = tolower(name[index]);
+      }
+      index = name.find('.', index);
+    }
+  }
+
+  // class name
+  index = name.rfind('.');
+  if (index != std::string::npos) {
+    ++index;
+  } else {
+    index = name.find_first_not_of(" \n\r\t");
+  }
+
+  if (index < name.length()) {
+    name[index] = toupper(name[index]);
+  }
+
+  return name;
+}
+
+string t_haxe_generator::constant_name(string name) {
+  string constant_name;
+
+  bool is_first = true;
+  bool was_previous_char_upper = false;
+  for (string::iterator iter = name.begin(); iter != name.end(); ++iter) {
+    string::value_type character = (*iter);
+
+    bool is_upper = isupper(character);
+
+    if (is_upper && !is_first && !was_previous_char_upper) {
+      constant_name += '_';
+    }
+    constant_name += toupper(character);
+
+    is_first = false;
+    was_previous_char_upper = is_upper;
+  }
+
+  return constant_name;
+}
+
+/**
+ * Enables RTTI for a class or interface
+ */
+void t_haxe_generator::generate_rtti_decoration(ostream& out) {
+  if (rtti_) {
+    out << "@:rtti" << endl;
+  }
+}
+
+/**
+ * Adds build macros to a class or interface
+ */
+void t_haxe_generator::generate_macro_decoration(ostream& out) {
+  if (!buildmacro_.empty()) {
+    out << "#if ! macro" << endl;
+    out << "@:build( " << buildmacro_ << ")" << endl;     // current class/interface
+    out << "@:autoBuild( " << buildmacro_ << ")" << endl; // inherited classes/interfaces
+    out << "#end" << endl;
+  }
+}
+
+/**
+ * Emits a haxeDoc comment if the provided object has a doc in Thrift
+ */
+void t_haxe_generator::generate_haxe_doc(ostream& out, t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    generate_docstring_comment(out, "/**\n", " * ", tdoc->get_doc(), " */\n");
+  }
+}
+
+/**
+ * Emits a haxeDoc comment if the provided function object has a doc in Thrift
+ */
+void t_haxe_generator::generate_haxe_doc(ostream& out, t_function* tfunction) {
+  if (tfunction->has_doc()) {
+    stringstream ss;
+    ss << tfunction->get_doc();
+    const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+    vector<t_field*>::const_iterator p_iter;
+    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
+      t_field* p = *p_iter;
+      ss << "\n@param " << p->get_name();
+      if (p->has_doc()) {
+        ss << " " << p->get_doc();
+      }
+    }
+    generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n");
+  }
+}
+
+std::string t_haxe_generator::generate_isset_check(t_field* field) {
+  return generate_isset_check(field->get_name());
+}
+
+std::string t_haxe_generator::generate_isset_check(std::string field_name) {
+  return "is" + get_cap_name("set") + get_cap_name(field_name) + "()";
+}
+
+void t_haxe_generator::generate_isset_set(ostream& out, t_field* field) {
+  if (!type_can_be_null(field->get_type())) {
+    indent(out) << "this.__isset_" << field->get_name() << " = true;" << endl;
+  }
+}
+
+std::string t_haxe_generator::get_enum_class_name(t_type* type) {
+  string package = "";
+  t_program* program = type->get_program();
+  if (program != NULL /*&& program != program_*/) {
+    package = program->get_namespace("haxe") + ".";
+  }
+  return package + type->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(
+    haxe,
+    "Haxe",
+    "    callbacks        Use onError()/onSuccess() callbacks for service methods (like AS3)\n"
+    "    rtti             Enable @:rtti for generated classes and interfaces\n"
+    "    buildmacro=my.macros.Class.method(args)\n"
+    "                     Add @:build macro calls to generated classes and interfaces\n")
diff --git a/compiler/cpp/src/thrift/generate/t_hs_generator.cc b/compiler/cpp/src/thrift/generate/t_hs_generator.cc
new file mode 100644
index 0000000..8f6d4b0
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_hs_generator.cc
@@ -0,0 +1,1728 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+
+#include "thrift/platform.h"
+#include "thrift/version.h"
+
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * Haskell code generator.
+ *
+ */
+class t_hs_generator : public t_oop_generator {
+public:
+  t_hs_generator(t_program* program,
+                 const map<string, string>& parsed_options,
+                 const string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    /* no options yet */
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      throw "unknown option hs:" + iter->first;
+    }
+
+    out_dir_base_ = "gen-hs";
+  }
+
+  /**
+   * 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);
+
+  string render_const_value(t_type* type, t_const_value* value);
+
+  /**
+   * Struct generation code
+   */
+
+  void generate_hs_struct(t_struct* tstruct, bool is_exception);
+
+  void generate_hs_struct_definition(ostream& out,
+                                     t_struct* tstruct,
+                                     bool is_xception = false,
+                                     bool helper = false);
+
+  void generate_hs_struct_reader(ostream& out, t_struct* tstruct);
+
+  void generate_hs_struct_writer(ostream& out, t_struct* tstruct);
+
+  void generate_hs_struct_arbitrary(ostream& out, t_struct* tstruct);
+
+  void generate_hs_function_helpers(t_function* tfunction);
+
+  void generate_hs_typemap(ostream& out, t_struct* tstruct);
+
+  void generate_hs_default(ostream& out, t_struct* tstruct);
+
+  /**
+   * 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_server(t_service* tservice);
+  void generate_process_function(t_service* tservice, t_function* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field(ostream& out, t_field* tfield, string prefix);
+
+  void generate_deserialize_struct(ostream& out, t_struct* tstruct, string name = "");
+
+  void generate_deserialize_container(ostream& out, t_type* ttype, string arg = "");
+
+  void generate_deserialize_set_element(ostream& out, t_set* tset);
+
+  void generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix = "");
+
+  void generate_deserialize_type(ostream& out, t_type* type, string arg = "");
+
+  void generate_serialize_type(ostream& out, t_type* type, string name = "");
+
+  void generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix = "");
+
+  void generate_serialize_container(ostream& out, t_type* ttype, string prefix = "");
+
+  void generate_serialize_map_element(ostream& out, t_map* tmap, string kiter, string viter);
+
+  void generate_serialize_set_element(ostream& out, t_set* tmap, string iter);
+
+  void generate_serialize_list_element(ostream& out, t_list* tlist, string iter);
+
+  /**
+   * Helper rendering functions
+   */
+
+  string hs_autogen_comment();
+  string hs_language_pragma();
+  string hs_imports();
+
+  string type_name(t_type* ttype, string function_prefix = "");
+
+  string field_name(string tname, string fname);
+
+  string function_type(t_function* tfunc,
+                       bool options = false,
+                       bool io = false,
+                       bool method = false);
+
+  string type_to_enum(t_type* ttype);
+
+  string type_to_default(t_type* ttype);
+
+  string render_hs_type(t_type* type, bool needs_parens);
+
+  string type_to_constructor(t_type* ttype);
+
+  string render_hs_type_for_function_name(t_type* type);
+
+private:
+  ofstream_with_content_based_conditional_update f_types_;
+  ofstream_with_content_based_conditional_update f_consts_;
+  ofstream_with_content_based_conditional_update f_service_;
+  ofstream_with_content_based_conditional_update f_iface_;
+  ofstream_with_content_based_conditional_update f_client_;
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_hs_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  // Make output file
+  string pname = capitalize(program_name_);
+  string f_types_name = get_out_dir() + pname + "_Types.hs";
+  f_types_.open(f_types_name.c_str());
+
+  string f_consts_name = get_out_dir() + pname + "_Consts.hs";
+  f_consts_.open(f_consts_name.c_str());
+
+  // Print header
+  f_types_ << hs_language_pragma() << endl;
+  f_types_ << hs_autogen_comment() << endl;
+  f_types_ << "module " << pname << "_Types where" << endl;
+  f_types_ << hs_imports() << endl;
+
+  f_consts_ << hs_language_pragma() << endl;
+  f_consts_ << hs_autogen_comment() << endl;
+  f_consts_ << "module " << pname << "_Consts where" << endl;
+  f_consts_ << hs_imports() << endl;
+  f_consts_ << "import " << pname << "_Types" << endl;
+}
+
+string t_hs_generator::hs_language_pragma() {
+  return string(
+      "{-# LANGUAGE DeriveDataTypeable #-}\n"
+      "{-# LANGUAGE DeriveGeneric #-}\n"
+      "{-# LANGUAGE OverloadedStrings #-}\n"
+      "{-# OPTIONS_GHC -fno-warn-missing-fields #-}\n"
+      "{-# OPTIONS_GHC -fno-warn-missing-signatures #-}\n"
+      "{-# OPTIONS_GHC -fno-warn-name-shadowing #-}\n"
+      "{-# OPTIONS_GHC -fno-warn-unused-imports #-}\n"
+      "{-# OPTIONS_GHC -fno-warn-unused-matches #-}\n");
+}
+
+/**
+ * Autogen'd comment
+ */
+string t_hs_generator::hs_autogen_comment() {
+  return string("-----------------------------------------------------------------\n")
+         + "-- Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")                      --\n"
+         + "--                                                             --\n"
+         + "-- DO NOT EDIT UNLESS YOU ARE SURE YOU KNOW WHAT YOU ARE DOING --\n"
+         + "-----------------------------------------------------------------\n";
+}
+
+/**
+ * Prints standard thrift imports
+ */
+string t_hs_generator::hs_imports() {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = string(
+      "import Prelude (($), (.), (>>=), (==), (++))\n"
+      "import qualified Prelude as P\n"
+      "import qualified Control.Exception as X\n"
+      "import qualified Control.Monad as M ( liftM, ap, when )\n"
+      "import Data.Functor ( (<$>) )\n"
+      "import qualified Data.ByteString.Lazy as LBS\n"
+      "import qualified Data.Hashable as H\n"
+      "import qualified Data.Int as I\n"
+      "import qualified Data.Maybe as M (catMaybes)\n"
+      "import qualified Data.Text.Lazy.Encoding as E ( decodeUtf8, encodeUtf8 )\n"
+      "import qualified Data.Text.Lazy as LT\n"
+      "import qualified GHC.Generics as G (Generic)\n"
+      "import qualified Data.Typeable as TY ( Typeable )\n"
+      "import qualified Data.HashMap.Strict as Map\n"
+      "import qualified Data.HashSet as Set\n"
+      "import qualified Data.Vector as Vector\n"
+      "import qualified Test.QuickCheck.Arbitrary as QC ( Arbitrary(..) )\n"
+      "import qualified Test.QuickCheck as QC ( elements )\n"
+      "\n"
+      "import qualified Thrift as T\n"
+      "import qualified Thrift.Types as T\n"
+      "import qualified Thrift.Arbitraries as T\n"
+      "\n");
+
+  for (size_t i = 0; i < includes.size(); ++i)
+    result += "import qualified " + capitalize(includes[i]->get_name()) + "_Types\n";
+
+  if (includes.size() > 0)
+    result += "\n";
+
+  return result;
+}
+
+/**
+ * Closes the type files
+ */
+void t_hs_generator::close_generator() {
+  // Close types file
+  f_types_.close();
+  f_consts_.close();
+}
+
+/**
+ * Generates a typedef. Ez.
+ *
+ * @param ttypedef The type definition
+ */
+void t_hs_generator::generate_typedef(t_typedef* ttypedef) {
+  string tname = capitalize(ttypedef->get_symbolic());
+  string tdef = render_hs_type(ttypedef->get_type(), false);
+  indent(f_types_) << "type " << tname << " = " << tdef << endl;
+  f_types_ << endl;
+}
+
+/**
+ * Generates code for an enumerated type.
+ * the values.
+ *
+ * @param tenum The enumeration
+ */
+void t_hs_generator::generate_enum(t_enum* tenum) {
+  indent(f_types_) << "data " << capitalize(tenum->get_name()) << " = ";
+  indent_up();
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+
+  bool first = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    string name = capitalize((*c_iter)->get_name());
+    f_types_ << (first ? "" : "|");
+    f_types_ << name;
+    first = false;
+  }
+  indent(f_types_) << "deriving (P.Show, P.Eq, G.Generic, TY.Typeable, P.Ord, P.Bounded)" << endl;
+  indent_down();
+
+  string ename = capitalize(tenum->get_name());
+
+  indent(f_types_) << "instance P.Enum " << ename << " where" << endl;
+  indent_up();
+  indent(f_types_) << "fromEnum t = case t of" << endl;
+  indent_up();
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    string name = capitalize((*c_iter)->get_name());
+    indent(f_types_) << name << " -> " << value << endl;
+  }
+  indent_down();
+  indent(f_types_) << "toEnum t = case t of" << endl;
+  indent_up();
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    string name = capitalize((*c_iter)->get_name());
+    indent(f_types_) << value << " -> " << name << endl;
+  }
+  indent(f_types_) << "_ -> X.throw T.ThriftException" << endl;
+  indent_down();
+  indent_down();
+
+  indent(f_types_) << "instance H.Hashable " << ename << " where" << endl;
+  indent_up();
+  indent(f_types_) << "hashWithSalt salt = H.hashWithSalt salt P.. P.fromEnum" << endl;
+  indent_down();
+
+  indent(f_types_) << "instance QC.Arbitrary " << ename << " where" << endl;
+  indent_up();
+  indent(f_types_) << "arbitrary = QC.elements (P.enumFromTo P.minBound P.maxBound)" << endl;
+  indent_down();
+}
+
+/**
+ * Generate a constant value
+ */
+void t_hs_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = decapitalize(tconst->get_name());
+
+  t_const_value* value = tconst->get_value();
+
+  indent(f_consts_) << name << " :: " << render_hs_type(type, false) << endl;
+  indent(f_consts_) << name << " = " << render_const_value(type, value) << endl;
+  f_consts_ << 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_hs_generator::render_const_value(t_type* type, t_const_value* value) {
+  if (value == NULL)
+    return type_to_default(type);
+
+  type = get_true_type(type);
+  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 ? "P.True" : "P.False");
+      break;
+
+    case t_base_type::TYPE_I8:
+    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()) {
+    t_enum* tenum = (t_enum*)type;
+    vector<t_enum_value*> constants = tenum->get_constants();
+    for (vector<t_enum_value*>::iterator c_iter = constants.begin(); c_iter != constants.end();
+         ++c_iter) {
+      int val = (*c_iter)->get_value();
+      if (val == value->get_integer()) {
+        t_program* prog = type->get_program();
+        if (prog != NULL && prog != program_)
+          out << capitalize(prog->get_name()) << "_Types.";
+        out << capitalize((*c_iter)->get_name());
+        break;
+      }
+    }
+
+  } else if (type->is_struct() || type->is_xception()) {
+    string cname = type_name(type);
+    out << "default_" << cname << "{";
+
+    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+
+    bool first = true;
+    for (map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter = val.begin();
+         v_iter != val.end();
+         ++v_iter) {
+      t_field* field = NULL;
+
+      for (vector<t_field*>::const_iterator f_iter = fields.begin(); f_iter != fields.end();
+           ++f_iter)
+        if ((*f_iter)->get_name() == v_iter->first->get_string())
+          field = (*f_iter);
+
+      if (field == NULL)
+        throw "type error: " + cname + " has no field " + v_iter->first->get_string();
+
+      string fname = v_iter->first->get_string();
+      string const_value = render_const_value(field->get_type(), v_iter->second);
+
+      out << (first ? "" : ", ");
+      out << field_name(cname, fname) << " = ";
+      if (field->get_req() == t_field::T_OPTIONAL || ((t_type*)field->get_type())->is_xception()) {
+        out << "P.Just ";
+      }
+      out << const_value;
+      first = false;
+    }
+
+    out << "}";
+
+  } 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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+
+    out << "(Map.fromList [";
+
+    bool first = true;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(ktype, v_iter->first);
+      string val = render_const_value(vtype, v_iter->second);
+      out << (first ? "" : ",");
+      out << "(" << key << "," << val << ")";
+      first = false;
+    }
+    out << "])";
+
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype = type->is_list() ? ((t_list*)type)->get_elem_type()
+                                    : ((t_set*)type)->get_elem_type();
+
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+
+    if (type->is_set())
+      out << "(Set.fromList [";
+    else
+      out << "(Vector.fromList [";
+
+    bool first = true;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << (first ? "" : ",");
+      out << render_const_value(etype, *v_iter);
+      first = false;
+    }
+
+    out << "])";
+
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+
+  return out.str();
+}
+
+/**
+ * Generates a "struct"
+ */
+void t_hs_generator::generate_struct(t_struct* tstruct) {
+  generate_hs_struct(tstruct, false);
+}
+
+/**
+ * Generates a struct definition for a thrift exception. Basically the same
+ * as a struct, but also has an exception declaration.
+ *
+ * @param txception The struct definition
+ */
+void t_hs_generator::generate_xception(t_struct* txception) {
+  generate_hs_struct(txception, true);
+}
+
+/**
+ * Generates a Haskell struct
+ */
+void t_hs_generator::generate_hs_struct(t_struct* tstruct, bool is_exception) {
+  generate_hs_struct_definition(f_types_, tstruct, is_exception, false);
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_hs_generator::generate_hs_struct_definition(ostream& out,
+                                                   t_struct* tstruct,
+                                                   bool is_exception,
+                                                   bool helper) {
+  (void)helper;
+  string tname = type_name(tstruct);
+  string name = tstruct->get_name();
+  const vector<t_field*>& members = tstruct->get_members();
+
+  indent(out) << "data " << tname << " = " << tname;
+  if (members.size() > 0) {
+    indent_up();
+    bool first = true;
+    for (vector<t_field*>::const_iterator m_iter = members.begin(); m_iter != members.end();
+         ++m_iter) {
+      if (first) {
+        indent(out) << "{ ";
+        first = false;
+      } else {
+        indent(out) << ", ";
+      }
+      string mname = (*m_iter)->get_name();
+      out << field_name(tname, mname) << " :: ";
+      if ((*m_iter)->get_req() == t_field::T_OPTIONAL
+          || ((t_type*)(*m_iter)->get_type())->is_xception()) {
+        out << "P.Maybe ";
+      }
+      out << render_hs_type((*m_iter)->get_type(), true) << endl;
+    }
+    indent(out) << "}";
+    indent_down();
+  }
+
+  out << " deriving (P.Show,P.Eq,G.Generic,TY.Typeable)" << endl;
+
+  if (is_exception)
+    out << "instance X.Exception " << tname << endl;
+
+  indent(out) << "instance H.Hashable " << tname << " where" << endl;
+  indent_up();
+  indent(out) << "hashWithSalt salt record = salt";
+  for (vector<t_field*>::const_iterator m_iter = members.begin(); m_iter != members.end();
+       ++m_iter) {
+    string mname = (*m_iter)->get_name();
+    indent(out) << " `H.hashWithSalt` " << field_name(tname, mname) << " record";
+  }
+  indent(out) << endl;
+  indent_down();
+
+  generate_hs_struct_arbitrary(out, tstruct);
+  generate_hs_struct_writer(out, tstruct);
+  generate_hs_struct_reader(out, tstruct);
+  generate_hs_typemap(out, tstruct);
+  generate_hs_default(out, tstruct);
+}
+
+void t_hs_generator::generate_hs_struct_arbitrary(ostream& out, t_struct* tstruct) {
+  string tname = type_name(tstruct);
+  string name = tstruct->get_name();
+  const vector<t_field*>& members = tstruct->get_members();
+
+  indent(out) << "instance QC.Arbitrary " << tname << " where " << endl;
+  indent_up();
+  if (members.size() > 0) {
+    indent(out) << "arbitrary = M.liftM " << tname;
+    indent_up();
+    indent_up();
+    indent_up();
+    indent_up();
+    bool first = true;
+    for (vector<t_field*>::const_iterator m_iter = members.begin(); m_iter != members.end();
+         ++m_iter) {
+      if (first) {
+        first = false;
+        out << " ";
+      } else {
+        indent(out) << "`M.ap`";
+      }
+      out << "(";
+      if ((*m_iter)->get_req() == t_field::T_OPTIONAL
+          || ((t_type*)(*m_iter)->get_type())->is_xception()) {
+        out << "M.liftM P.Just ";
+      }
+      out << "QC.arbitrary)" << endl;
+    }
+    indent_down();
+    indent_down();
+    indent_down();
+    indent_down();
+
+    // Shrink
+    indent(out) << "shrink obj | obj == default_" << tname << " = []" << endl;
+    indent(out) << "           | P.otherwise = M.catMaybes" << endl;
+    indent_up();
+    first = true;
+    for (vector<t_field*>::const_iterator m_iter = members.begin(); m_iter != members.end();
+         ++m_iter) {
+      if (first) {
+        first = false;
+        indent(out) << "[ ";
+      } else {
+        indent(out) << ", ";
+      }
+      string fname = field_name(tname, (*m_iter)->get_name());
+      out << "if obj == default_" << tname;
+      out << "{" << fname << " = " << fname << " obj} ";
+      out << "then P.Nothing ";
+      out << "else P.Just $ default_" << tname;
+      out << "{" << fname << " = " << fname << " obj}" << endl;
+    }
+    indent(out) << "]" << endl;
+    indent_down();
+  } else { /* 0 == members.size() */
+    indent(out) << "arbitrary = QC.elements [" << tname << "]" << endl;
+  }
+  indent_down();
+}
+
+/**
+ * Generates the read method for a struct
+ */
+void t_hs_generator::generate_hs_struct_reader(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+
+  string sname = type_name(tstruct);
+  string id = tmp("_id");
+  string val = tmp("_val");
+
+  indent(out) << "to_" << sname << " :: T.ThriftVal -> " << sname << endl;
+  indent(out) << "to_" << sname << " (T.TStruct fields) = " << sname << "{" << endl;
+  indent_up();
+
+  bool first = true;
+
+  // Generate deserialization code for known cases
+  for (vector<t_field*>::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    int32_t key = (*f_iter)->get_key();
+    string etype = type_to_enum((*f_iter)->get_type());
+    string fname = (*f_iter)->get_name();
+
+    if (first) {
+      first = false;
+    } else {
+      out << "," << endl;
+    }
+
+    // Fill in Field
+    indent(out) << field_name(sname, fname) << " = ";
+
+    out << "P.maybe (";
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      out << "P.error \"Missing required field: " << fname << "\"";
+    } else {
+      if (((*f_iter)->get_req() == t_field::T_OPTIONAL
+           || ((t_type*)(*f_iter)->get_type())->is_xception()) && (*f_iter)->get_value() == NULL) {
+        out << "P.Nothing";
+      } else {
+        out << field_name(sname, fname) << " default_" << sname;
+      }
+    }
+    out << ") ";
+
+    out << "(\\(_," << val << ") -> ";
+    if ((*f_iter)->get_req() == t_field::T_OPTIONAL
+        || ((t_type*)(*f_iter)->get_type())->is_xception())
+      out << "P.Just ";
+    generate_deserialize_field(out, *f_iter, val);
+    out << ")";
+    out << " (Map.lookup (" << key << ") fields)";
+  }
+
+  out << endl;
+  indent(out) << "}" << endl;
+  indent_down();
+
+  // read
+  string tmap = type_name(tstruct, "typemap_");
+  indent(out) << "to_" << sname << " _ = P.error \"not a struct\"" << endl;
+
+  indent(out) << "read_" << sname << " :: T.Protocol p => p -> P.IO " << sname
+              << endl;
+  indent(out) << "read_" << sname << " iprot = to_" << sname;
+  out << " <$> T.readVal iprot (T.T_STRUCT " << tmap << ")" << endl;
+
+  indent(out) << "decode_" << sname
+              << " :: T.StatelessProtocol p => p -> LBS.ByteString -> " << sname << endl;
+  indent(out) << "decode_" << sname << " iprot bs = to_" << sname << " $ ";
+  out << "T.deserializeVal iprot (T.T_STRUCT " << tmap << ") bs" << endl;
+}
+
+void t_hs_generator::generate_hs_struct_writer(ostream& out, t_struct* tstruct) {
+  string name = type_name(tstruct);
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  string str = tmp("_str");
+  string f = tmp("_f");
+  string v = tmp("_v");
+
+  indent(out) << "from_" << name << " :: " << name << " -> T.ThriftVal" << endl;
+  indent(out) << "from_" << name << " record = T.TStruct $ Map.fromList ";
+  indent_up();
+
+  // Get Exceptions
+  bool hasExn = false;
+  for (vector<t_field*>::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (((t_type*)(*f_iter)->get_type())->is_xception()) {
+      hasExn = true;
+      break;
+    }
+  }
+
+  bool isfirst = true;
+  if (hasExn) {
+    out << endl;
+    indent(out) << "(let exns = M.catMaybes ";
+    indent_up();
+    for (vector<t_field*>::const_iterator f_iter = fields.begin(); f_iter != fields.end();
+         ++f_iter) {
+      if (((t_type*)(*f_iter)->get_type())->is_xception()) {
+        if (isfirst) {
+          out << "[ ";
+          isfirst = false;
+        } else {
+          out << ", ";
+        }
+        string mname = (*f_iter)->get_name();
+        int32_t key = (*f_iter)->get_key();
+        out << "(\\" << v << " -> (" << key << ", (\"" << mname << "\",";
+        generate_serialize_type(out, (*f_iter)->get_type(), v);
+        out << "))) <$> " << field_name(name, mname) << " record";
+      }
+    }
+    if (!isfirst) {
+      out << "]" << endl;
+    }
+    indent_down();
+    indent(out) << "in if P.not (P.null exns) then exns else ";
+    indent_up();
+  } else {
+    out << "$ ";
+  }
+
+  out << "M.catMaybes" << endl;
+  // Get the Rest
+  isfirst = true;
+  for (vector<t_field*>::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    // Write field header
+    if (isfirst) {
+      indent(out) << "[ ";
+      isfirst = false;
+    } else {
+      indent(out) << ", ";
+    }
+    string mname = (*f_iter)->get_name();
+    int32_t key = (*f_iter)->get_key();
+    out << "(\\";
+    out << v << " -> ";
+    if ((*f_iter)->get_req() != t_field::T_OPTIONAL
+        && !((t_type*)(*f_iter)->get_type())->is_xception()) {
+      out << "P.Just ";
+    }
+    out << "(" << key << ", (\"" << mname << "\",";
+    generate_serialize_type(out, (*f_iter)->get_type(), v);
+    out << "))) ";
+    if ((*f_iter)->get_req() != t_field::T_OPTIONAL
+        && !((t_type*)(*f_iter)->get_type())->is_xception()) {
+      out << "$";
+    } else {
+      out << "<$>";
+    }
+    out << " " << field_name(name, mname) << " record" << endl;
+  }
+
+  // Write the struct map
+  if (isfirst) {
+    indent(out) << "[]" << endl;
+  } else {
+    indent(out) << "]" << endl;
+  }
+  if (hasExn) {
+    indent(out) << ")" << endl;
+    indent_down();
+  }
+  indent_down();
+
+  // write
+  indent(out) << "write_" << name << " :: T.Protocol p => p -> " << name
+              << " -> P.IO ()" << endl;
+  indent(out) << "write_" << name << " oprot record = T.writeVal oprot $ from_";
+  out << name << " record" << endl;
+
+  // encode
+  indent(out) << "encode_" << name << " :: T.StatelessProtocol p => p -> " << name
+              << " -> LBS.ByteString" << endl;
+  indent(out) << "encode_" << name << " oprot record = T.serializeVal oprot $ ";
+  out << "from_" << name << " record" << endl;
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_hs_generator::generate_service(t_service* tservice) {
+  string f_service_name = get_out_dir() + capitalize(service_name_) + ".hs";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << hs_language_pragma() << endl;
+  f_service_ << hs_autogen_comment() << endl;
+  f_service_ << "module " << capitalize(service_name_) << " where" << endl;
+  f_service_ << hs_imports() << endl;
+
+  if (tservice->get_extends()) {
+    f_service_ << "import qualified " << capitalize(tservice->get_extends()->get_name()) << endl;
+  }
+
+  f_service_ << "import " << capitalize(program_name_) << "_Types" << endl;
+  f_service_ << "import qualified " << capitalize(service_name_) << "_Iface as Iface" << endl;
+
+  // Generate the three main parts of the service
+  generate_service_helpers(tservice);
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+
+  // Close service file
+  f_service_.close();
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_hs_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  indent(f_service_) << "-- HELPER FUNCTIONS AND STRUCTURES --" << endl;
+  indent(f_service_) << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_hs_struct_definition(f_service_, ts, false);
+    generate_hs_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_hs_generator::generate_hs_function_helpers(t_function* tfunction) {
+  t_struct result(program_, field_name(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_hs_struct_definition(f_service_, &result, false);
+}
+
+/**
+ * Generate the map from field names to (type, id)
+ * @param tstruct the Struct
+ */
+void t_hs_generator::generate_hs_typemap(ostream& out, t_struct* tstruct) {
+  string name = type_name(tstruct);
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+
+  indent(out) << "typemap_" << name << " :: T.TypeMap" << endl;
+  indent(out) << "typemap_" << name << " = Map.fromList [";
+  bool first = true;
+  for (vector<t_field*>::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    string mname = (*f_iter)->get_name();
+    if (!first) {
+      out << ",";
+    }
+
+    t_type* type = get_true_type((*f_iter)->get_type());
+    int32_t key = (*f_iter)->get_key();
+    out << "(" << key << ",(\"" << mname << "\"," << type_to_enum(type) << "))";
+    first = false;
+  }
+  out << "]" << endl;
+}
+
+/**
+ * generate the struct with default values filled in
+ * @param tstruct the Struct
+ */
+void t_hs_generator::generate_hs_default(ostream& out, t_struct* tstruct) {
+  string name = type_name(tstruct);
+  string fname = type_name(tstruct, "default_");
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+
+  indent(out) << fname << " :: " << name << endl;
+  indent(out) << fname << " = " << name << "{" << endl;
+  indent_up();
+  bool first = true;
+  for (vector<t_field*>::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    string mname = (*f_iter)->get_name();
+    if (first) {
+      first = false;
+    } else {
+      out << "," << endl;
+    }
+
+    t_type* type = get_true_type((*f_iter)->get_type());
+    t_const_value* value = (*f_iter)->get_value();
+    indent(out) << field_name(name, mname) << " = ";
+    if ((*f_iter)->get_req() == t_field::T_OPTIONAL
+        || ((t_type*)(*f_iter)->get_type())->is_xception()) {
+      if (value == NULL) {
+        out << "P.Nothing";
+      } else {
+        out << "P.Just " << render_const_value(type, value);
+      }
+    } else {
+      out << render_const_value(type, value);
+    }
+  }
+  out << "}" << endl;
+  indent_down();
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_hs_generator::generate_service_interface(t_service* tservice) {
+  string f_iface_name = get_out_dir() + capitalize(service_name_) + "_Iface.hs";
+  f_iface_.open(f_iface_name.c_str());
+
+  f_iface_ << hs_language_pragma() << endl;
+  f_iface_ << hs_autogen_comment() << endl;
+
+  f_iface_ << "module " << capitalize(service_name_) << "_Iface where" << endl;
+
+  f_iface_ << hs_imports() << endl;
+  f_iface_ << "import " << capitalize(program_name_) << "_Types" << endl;
+  f_iface_ << endl;
+
+  string sname = capitalize(service_name_);
+  if (tservice->get_extends() != NULL) {
+    string extends = type_name(tservice->get_extends());
+
+    indent(f_iface_) << "import " << extends << "_Iface" << endl;
+    indent(f_iface_) << "class " << extends << "_Iface a => " << sname << "_Iface a where" << endl;
+
+  } else {
+    indent(f_iface_) << "class " << sname << "_Iface a where" << endl;
+  }
+
+  indent_up();
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string ft = function_type(*f_iter, true, true, true);
+    indent(f_iface_) << decapitalize((*f_iter)->get_name()) << " :: a -> " << ft << endl;
+  }
+
+  indent_down();
+  f_iface_.close();
+}
+
+/**
+ * Generates a service client definition. Note that in Haskell, the client doesn't implement iface.
+ *This is because
+ * The client does not (and should not have to) deal with arguments being Nothing.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_hs_generator::generate_service_client(t_service* tservice) {
+  string f_client_name = get_out_dir() + capitalize(service_name_) + "_Client.hs";
+  f_client_.open(f_client_name.c_str());
+  f_client_ << hs_language_pragma() << endl;
+  f_client_ << hs_autogen_comment() << endl;
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+
+  string extends = "";
+  string exports = "";
+
+  bool first = true;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    exports += (first ? "" : ",");
+    string funname = (*f_iter)->get_name();
+    exports += decapitalize(funname);
+    first = false;
+  }
+
+  string sname = capitalize(service_name_);
+  indent(f_client_) << "module " << sname << "_Client(" << exports << ") where" << endl;
+
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    indent(f_client_) << "import " << extends << "_Client" << endl;
+  }
+
+  indent(f_client_) << "import qualified Data.IORef as R" << endl;
+  indent(f_client_) << hs_imports() << endl;
+  indent(f_client_) << "import " << capitalize(program_name_) << "_Types" << endl;
+  indent(f_client_) << "import " << capitalize(service_name_) << endl;
+
+  // DATS RITE A GLOBAL VAR
+  indent(f_client_) << "seqid = R.newIORef 0" << endl;
+
+  // Generate client method implementations
+  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 = (*f_iter)->get_name();
+
+    string fargs = "";
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter)
+      fargs += " arg_" + (*fld_iter)->get_name();
+
+    // Open function
+    indent(f_client_) << decapitalize(funname) << " (ip,op)" << fargs << " = do" << endl;
+    indent_up();
+    indent(f_client_) << "send_" << funname << " op" << fargs;
+
+    f_client_ << endl;
+
+    if (!(*f_iter)->is_oneway())
+      indent(f_client_) << "recv_" << funname << " ip" << endl;
+
+    indent_down();
+
+    indent(f_client_) << "send_" << funname << " op" << fargs << " = do" << endl;
+    indent_up();
+
+    indent(f_client_) << "seq <- seqid" << endl;
+    indent(f_client_) << "seqn <- R.readIORef seq" << endl;
+    string argsname = capitalize((*f_iter)->get_name() + "_args");
+
+    // Serialize the request header
+    string fname = (*f_iter)->get_name();
+    string msgType = (*f_iter)->is_oneway() ? "T.M_ONEWAY" : "T.M_CALL";
+    indent(f_client_) << "T.writeMessage op (\"" << fname << "\", " << msgType << ", seqn) $"
+                      << endl;
+    indent_up();
+    indent(f_client_) << "write_" << argsname << " op (" << argsname << "{";
+
+    bool first = true;
+    for (vector<t_field*>::const_iterator fld_iter = fields.begin(); fld_iter != fields.end();
+         ++fld_iter) {
+      string fieldname = (*fld_iter)->get_name();
+      f_client_ << (first ? "" : ",");
+      f_client_ << field_name(argsname, fieldname) << "=";
+      if ((*fld_iter)->get_req() == t_field::T_OPTIONAL
+          || ((t_type*)(*fld_iter)->get_type())->is_xception())
+        f_client_ << "P.Just ";
+      f_client_ << "arg_" << fieldname;
+      first = false;
+    }
+    f_client_ << "})" << endl;
+    indent_down();
+    indent_down();
+
+    if (!(*f_iter)->is_oneway()) {
+      string resultname = capitalize((*f_iter)->get_name() + "_result");
+      t_struct noargs(program_);
+
+      string funname = string("recv_") + (*f_iter)->get_name();
+      t_function recv_function((*f_iter)->get_returntype(), funname, &noargs);
+
+      // Open function
+      indent(f_client_) << funname << " ip = do" << endl;
+      indent_up();
+
+      indent(f_client_) << "T.readMessage ip $ \\(fname, mtype, rseqid) -> do" << endl;
+      indent_up();
+      indent(f_client_) << "M.when (mtype == T.M_EXCEPTION) $ do { exn <- T.readAppExn ip ; "
+                           "X.throw exn }" << endl;
+
+      indent(f_client_) << "res <- read_" << resultname << " ip" << endl;
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const vector<t_field*>& xceptions = xs->get_members();
+
+      for (vector<t_field*>::const_iterator x_iter = xceptions.begin(); x_iter != xceptions.end();
+           ++x_iter) {
+        indent(f_client_) << "P.maybe (P.return ()) X.throw ("
+                          << field_name(resultname, (*x_iter)->get_name()) << " res)" << endl;
+      }
+
+      if (!(*f_iter)->get_returntype()->is_void())
+        indent(f_client_) << "P.return $ " << field_name(resultname, "success") << " res" << endl;
+      else
+        indent(f_client_) << "P.return ()" << endl;
+
+      // Close function
+      indent_down();
+      indent_down();
+    }
+  }
+
+  f_client_.close();
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_hs_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
+    generate_process_function(tservice, *f_iter);
+
+  indent(f_service_) << "proc_ handler (iprot,oprot) (name,typ,seqid) = case name of" << endl;
+  indent_up();
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string fname = (*f_iter)->get_name();
+    indent(f_service_) << "\"" << fname << "\" -> process_" << decapitalize(fname)
+                       << " (seqid,iprot,oprot,handler)" << endl;
+  }
+
+  indent(f_service_) << "_ -> ";
+  if (tservice->get_extends() != NULL) {
+    f_service_ << type_name(tservice->get_extends())
+               << ".proc_ handler (iprot,oprot) (name,typ,seqid)" << endl;
+
+  } else {
+    f_service_ << "do" << endl;
+    indent_up();
+    indent(f_service_) << "_ <- T.readVal iprot (T.T_STRUCT Map.empty)" << endl;
+    indent(f_service_) << "T.writeMessage oprot (name,T.M_EXCEPTION,seqid) $" << endl;
+    indent_up();
+    indent(f_service_) << "T.writeAppExn oprot (T.AppExn T.AE_UNKNOWN_METHOD (\"Unknown function "
+                          "\" ++ LT.unpack name))" << endl;
+    indent_down();
+    indent_down();
+  }
+
+  indent_down();
+
+  // Generate the server implementation
+  indent(f_service_) << "process handler (iprot, oprot) = do" << endl;
+  indent_up();
+
+  indent(f_service_) << "T.readMessage iprot (" << endl;
+  indent(f_service_) << "  proc_ handler (iprot,oprot))" << endl;
+  indent(f_service_) << "P.return P.True" << endl;
+  indent_down();
+}
+
+bool hasNoArguments(t_function* func) {
+  return (func->get_arglist()->get_members().empty());
+}
+
+string t_hs_generator::render_hs_type_for_function_name(t_type* type) {
+  string type_str = render_hs_type(type, false);
+  std::string::size_type found = -1;
+
+  while (true) {
+    found = type_str.find_first_of("[]. ", found + 1);
+    if (string::npos == size_t(found)) {
+      break;
+    }
+
+    if (type_str[found] == '.')
+      type_str[found] = '_';
+    else
+      type_str[found] = 'Z';
+  }
+  return type_str;
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_hs_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+  // Open function
+  string funname = decapitalize(tfunction->get_name());
+  indent(f_service_) << "process_" << funname << " (seqid, iprot, oprot, handler) = do" << endl;
+  indent_up();
+
+  string argsname = capitalize(tfunction->get_name()) + "_args";
+  string resultname = capitalize(tfunction->get_name()) + "_result";
+
+  // Generate the function call
+  t_struct* arg_struct = tfunction->get_arglist();
+  const vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(f_service_) << "args <- read_" << argsname << " iprot" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  size_t n = xceptions.size() + 1;
+  // Try block for a function with exceptions
+  if (n > 0) {
+    for (size_t i = 0; i < n; i++) {
+      indent(f_service_) << "(X.catch" << endl;
+      indent_up();
+    }
+  }
+
+  if (n > 0) {
+    indent(f_service_) << "(do" << endl;
+    indent_up();
+  }
+  indent(f_service_);
+
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void())
+    f_service_ << "val <- ";
+
+  f_service_ << "Iface." << decapitalize(tfunction->get_name()) << " handler";
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+    f_service_ << " (" << field_name(argsname, (*f_iter)->get_name()) << " args)";
+
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << endl;
+    indent(f_service_) << "let res = default_" << resultname << "{"
+                       << field_name(resultname, "success") << " = val}";
+
+  } else if (!tfunction->is_oneway()) {
+    f_service_ << endl;
+    indent(f_service_) << "let res = default_" << resultname;
+  }
+  f_service_ << endl;
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    indent(f_service_) << "P.return ()";
+  } else {
+    indent(f_service_) << "T.writeMessage oprot (\"" << tfunction->get_name()
+                       << "\", T.M_REPLY, seqid) $" << endl;
+    indent_up();
+    indent(f_service_) << "write_" << resultname << " oprot res";
+    indent_down();
+  }
+  if (n > 0) {
+    f_service_ << ")";
+    indent_down();
+  }
+  f_service_ << endl;
+
+  if (n > 0) {
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      indent(f_service_) << "(\\e  -> do" << endl;
+      indent_up();
+
+      if (!tfunction->is_oneway()) {
+        indent(f_service_) << "let res = default_" << resultname << "{"
+                           << field_name(resultname, (*x_iter)->get_name()) << " = P.Just e}"
+                           << endl;
+        indent(f_service_) << "T.writeMessage oprot (\"" << tfunction->get_name()
+                           << "\", T.M_REPLY, seqid) $" << endl;
+        indent_up();
+        indent(f_service_) << "write_" << resultname << " oprot res";
+        indent_down();
+      } else {
+        indent(f_service_) << "P.return ()";
+      }
+
+      f_service_ << "))" << endl;
+      indent_down();
+      indent_down();
+    }
+    indent(f_service_) << "((\\_ -> do" << endl;
+    indent_up();
+
+    if (!tfunction->is_oneway()) {
+      indent(f_service_) << "T.writeMessage oprot (\"" << tfunction->get_name()
+                         << "\", T.M_EXCEPTION, seqid) $" << endl;
+      indent_up();
+      indent(f_service_) << "T.writeAppExn oprot (T.AppExn T.AE_UNKNOWN \"\")";
+      indent_down();
+    } else {
+      indent(f_service_) << "P.return ()";
+    }
+
+    f_service_ << ") :: X.SomeException -> P.IO ()))" << endl;
+    indent_down();
+    indent_down();
+  }
+  // Close function
+  indent_down();
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_hs_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) {
+  (void)prefix;
+  t_type* type = tfield->get_type();
+  generate_deserialize_type(out, type, prefix);
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_hs_generator::generate_deserialize_type(ostream& out, t_type* type, string arg) {
+  type = get_true_type(type);
+  string val = tmp("_val");
+  out << "(case " << arg << " of {" << type_to_constructor(type) << " " << val << " -> ";
+
+  if (type->is_void())
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE";
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, val);
+
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, val);
+
+  } else if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    if (tbase == t_base_type::TYPE_STRING && !type->is_binary()) {
+      out << "E.decodeUtf8 ";
+    }
+    out << val;
+    if (type->is_binary()) {
+      // Since wire type of binary is the same as string, we actually receive T.TString not
+      // T.TBinary
+      out << "; T.TString " << val << " -> " << val;
+    }
+  } else if (type->is_enum()) {
+    out << "P.toEnum $ P.fromIntegral " << val;
+
+  } else {
+    throw "DO NOT KNOW HOW TO DESERIALIZE TYPE " + type->get_name();
+  }
+  out << "; _ -> P.error \"wrong type\"})";
+}
+
+/**
+ * Generates an unserializer for a struct, calling read()
+ */
+void t_hs_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string name) {
+
+  out << "(" << type_name(tstruct, "to_") << " (T.TStruct " << name << "))";
+}
+
+/**
+ * Serialize a container by writing out the header followed by
+ * data and then a footer.
+ */
+void t_hs_generator::generate_deserialize_container(ostream& out, t_type* ttype, string arg) {
+
+  string val = tmp("_v");
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    string key = tmp("_k");
+    out << "(Map.fromList $ P.map (\\(" << key << "," << val << ") -> (";
+    generate_deserialize_type(out, ((t_map*)ttype)->get_key_type(), key);
+
+    out << ",";
+    generate_deserialize_type(out, ((t_map*)ttype)->get_val_type(), val);
+
+    out << ")) " << arg << ")";
+
+  } else if (ttype->is_set()) {
+    out << "(Set.fromList $ P.map (\\" << val << " -> ";
+    generate_deserialize_type(out, ((t_set*)ttype)->get_elem_type(), val);
+    out << ") " << arg << ")";
+
+  } else if (ttype->is_list()) {
+    out << "(Vector.fromList $ P.map (\\" << val << " -> ";
+    generate_deserialize_type(out, ((t_list*)ttype)->get_elem_type(), val);
+    out << ") " << arg << ")";
+  }
+}
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_hs_generator::generate_serialize_type(ostream& out, t_type* type, string name) {
+
+  type = get_true_type(type);
+  // Do nothing for void types
+  if (type->is_void())
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE";
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, name);
+
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, name);
+
+  } else if (type->is_base_type() || type->is_enum()) {
+    if (type->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+      out << type_to_constructor(type) << " ";
+      if (tbase == t_base_type::TYPE_STRING && !type->is_binary()) {
+        out << "$ E.encodeUtf8 ";
+      }
+      out << name;
+
+    } else if (type->is_enum()) {
+      string ename = capitalize(type->get_name());
+      out << "T.TI32 $ P.fromIntegral $ P.fromEnum " << name;
+    }
+
+  } else {
+    throw "DO NOT KNOW HOW TO SERIALIZE FIELD OF TYPE " + type->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_hs_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  out << type_name(tstruct, "from_") << " " << prefix;
+}
+
+void t_hs_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  string k = tmp("_k");
+  string v = tmp("_v");
+
+  if (ttype->is_map()) {
+    t_type* ktype = ((t_map*)ttype)->get_key_type();
+    t_type* vtype = ((t_map*)ttype)->get_val_type();
+    out << "T.TMap " << type_to_enum(ktype) << " " << type_to_enum(vtype);
+    out << " $ P.map (\\(" << k << "," << v << ") -> (";
+    generate_serialize_type(out, ktype, k);
+    out << ", ";
+    generate_serialize_type(out, vtype, v);
+    out << ")) $ Map.toList " << prefix;
+
+  } else if (ttype->is_set()) {
+    out << "T.TSet " << type_to_enum(((t_set*)ttype)->get_elem_type());
+    out << " $ P.map (\\" << v << " -> ";
+    generate_serialize_type(out, ((t_set*)ttype)->get_elem_type(), v);
+    out << ") $ Set.toList " << prefix;
+
+  } else if (ttype->is_list()) {
+    out << "T.TList " << type_to_enum(((t_list*)ttype)->get_elem_type());
+    out << " $ P.map (\\" << v << " -> ";
+    generate_serialize_type(out, ((t_list*)ttype)->get_elem_type(), v);
+    out << ") $ Vector.toList " << prefix;
+  }
+}
+
+string t_hs_generator::function_type(t_function* tfunc, bool options, bool io, bool method) {
+  string result = "";
+
+  const vector<t_field*>& fields = tfunc->get_arglist()->get_members();
+  for (vector<t_field*>::const_iterator f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_OPTIONAL
+        || ((t_type*)(*f_iter)->get_type())->is_xception())
+      result += "P.Maybe ";
+    result += render_hs_type((*f_iter)->get_type(), options);
+    result += " -> ";
+  }
+
+  if (fields.empty() && !method)
+    result += "() -> ";
+
+  if (io)
+    result += "P.IO ";
+
+  result += render_hs_type(tfunc->get_returntype(), io);
+  return result;
+}
+
+string t_hs_generator::type_name(t_type* ttype, string function_prefix) {
+  string prefix = "";
+  t_program* program = ttype->get_program();
+
+  if (program != NULL && program != program_)
+    if (!ttype->is_service())
+      prefix = capitalize(program->get_name()) + "_Types.";
+
+  return prefix + function_prefix + capitalize(ttype->get_name());
+}
+
+string t_hs_generator::field_name(string tname, string fname) {
+  return decapitalize(tname) + "_" + fname;
+}
+
+/**
+ * Converts the parse type to a Protocol.t_type enum
+ */
+string t_hs_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:
+      return "T.T_VOID";
+    case t_base_type::TYPE_STRING:
+      return type->is_binary() ? "T.T_BINARY" : "T.T_STRING";
+    case t_base_type::TYPE_BOOL:
+      return "T.T_BOOL";
+    case t_base_type::TYPE_I8:
+      return "T.T_BYTE";
+    case t_base_type::TYPE_I16:
+      return "T.T_I16";
+    case t_base_type::TYPE_I32:
+      return "T.T_I32";
+    case t_base_type::TYPE_I64:
+      return "T.T_I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "T.T_DOUBLE";
+    }
+
+  } else if (type->is_enum()) {
+    return "T.T_I32";
+
+  } else if (type->is_struct() || type->is_xception()) {
+    return "(T.T_STRUCT " + type_name((t_struct*)type, "typemap_") + ")";
+
+  } else if (type->is_map()) {
+    string ktype = type_to_enum(((t_map*)type)->get_key_type());
+    string vtype = type_to_enum(((t_map*)type)->get_val_type());
+    return "(T.T_MAP " + ktype + " " + vtype + ")";
+
+  } else if (type->is_set()) {
+    return "(T.T_SET " + type_to_enum(((t_set*)type)->get_elem_type()) + ")";
+
+  } else if (type->is_list()) {
+    return "(T.T_LIST " + type_to_enum(((t_list*)type)->get_elem_type()) + ")";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Converts the parse type to a default value
+ */
+string t_hs_generator::type_to_default(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:
+      return "P.error \"No default value for type T_VOID\"";
+    case t_base_type::TYPE_STRING:
+      return "\"\"";
+    case t_base_type::TYPE_BOOL:
+      return "P.False";
+    case t_base_type::TYPE_I8:
+      return "0";
+    case t_base_type::TYPE_I16:
+      return "0";
+    case t_base_type::TYPE_I32:
+      return "0";
+    case t_base_type::TYPE_I64:
+      return "0";
+    case t_base_type::TYPE_DOUBLE:
+      return "0";
+    }
+
+  } else if (type->is_enum()) {
+    return "(P.toEnum 0)";
+
+  } else if (type->is_struct() || type->is_xception()) {
+    return type_name((t_struct*)type, "default_");
+
+  } else if (type->is_map()) {
+    return "Map.empty";
+
+  } else if (type->is_set()) {
+    return "Set.empty";
+
+  } else if (type->is_list()) {
+    return "Vector.empty";
+  }
+
+  throw "INVALID TYPE IN type_to_default: " + type->get_name();
+}
+
+/**
+ * Converts the parse type to an haskell type
+ */
+string t_hs_generator::render_hs_type(t_type* type, bool needs_parens) {
+  type = get_true_type(type);
+  string type_repr;
+
+  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:
+      return "()";
+    case t_base_type::TYPE_STRING:
+      return (type->is_binary() ? "LBS.ByteString" : "LT.Text");
+    case t_base_type::TYPE_BOOL:
+      return "P.Bool";
+    case t_base_type::TYPE_I8:
+      return "I.Int8";
+    case t_base_type::TYPE_I16:
+      return "I.Int16";
+    case t_base_type::TYPE_I32:
+      return "I.Int32";
+    case t_base_type::TYPE_I64:
+      return "I.Int64";
+    case t_base_type::TYPE_DOUBLE:
+      return "P.Double";
+    }
+
+  } else if (type->is_enum()) {
+    return type_name((t_enum*)type);
+
+  } else if (type->is_struct() || type->is_xception()) {
+    return type_name((t_struct*)type);
+
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    type_repr = "Map.HashMap " + render_hs_type(ktype, true) + " " + render_hs_type(vtype, true);
+
+  } else if (type->is_set()) {
+    t_type* etype = ((t_set*)type)->get_elem_type();
+    type_repr = "Set.HashSet " + render_hs_type(etype, true);
+
+  } else if (type->is_list()) {
+    t_type* etype = ((t_list*)type)->get_elem_type();
+    type_repr = "Vector.Vector " + render_hs_type(etype, true);
+
+  } else {
+    throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+  }
+
+  return needs_parens ? "(" + type_repr + ")" : type_repr;
+}
+
+/**
+ * Converts the parse type to a haskell constructor
+ */
+string t_hs_generator::type_to_constructor(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: T_VOID";
+    case t_base_type::TYPE_STRING:
+      return type->is_binary() ? "T.TBinary" : "T.TString";
+    case t_base_type::TYPE_BOOL:
+      return "T.TBool";
+    case t_base_type::TYPE_I8:
+      return "T.TByte";
+    case t_base_type::TYPE_I16:
+      return "T.TI16";
+    case t_base_type::TYPE_I32:
+      return "T.TI32";
+    case t_base_type::TYPE_I64:
+      return "T.TI64";
+    case t_base_type::TYPE_DOUBLE:
+      return "T.TDouble";
+    }
+
+  } else if (type->is_enum()) {
+    return "T.TI32";
+
+  } else if (type->is_struct() || type->is_xception()) {
+    return "T.TStruct";
+
+  } else if (type->is_map()) {
+    return "T.TMap _ _";
+
+  } else if (type->is_set()) {
+    return "T.TSet _";
+
+  } else if (type->is_list()) {
+    return "T.TList _";
+  }
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(hs, "Haskell", "")
diff --git a/compiler/cpp/src/thrift/generate/t_html_generator.cc b/compiler/cpp/src/thrift/generate/t_html_generator.cc
new file mode 100644
index 0000000..8dfa389
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_html_generator.cc
@@ -0,0 +1,1088 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <map>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "thrift/platform.h"
+#include "thrift/generate/t_generator.h"
+#include "thrift/generate/t_html_generator.h"
+
+using std::map;
+using std::ofstream;
+using std::ostringstream;
+using std::pair;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+enum input_type { INPUT_UNKNOWN, INPUT_UTF8, INPUT_PLAIN };
+
+/**
+ * HTML code generator
+ *
+ * mostly copy/pasting/tweaking from mcslee's work.
+ */
+class t_html_generator : public t_generator {
+public:
+  t_html_generator(t_program* program,
+                   const std::map<std::string, std::string>& parsed_options,
+                   const std::string& option_string)
+    : t_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    standalone_ = false;
+    unsafe_ = false;
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("standalone") == 0) {
+        standalone_ = true;
+      } else if( iter->first.compare("noescape") == 0) {
+        unsafe_ = true;
+      } else {
+        throw "unknown option html:" + iter->first;
+      }
+    }
+
+
+    out_dir_base_ = "gen-html";
+    input_type_ = INPUT_UNKNOWN;
+
+    escape_.clear();
+    escape_['&'] = "&amp;";
+    escape_['<'] = "&lt;";
+    escape_['>'] = "&gt;";
+    escape_['"'] = "&quot;";
+    escape_['\''] = "&apos;";
+
+    init_allowed__markup();
+  }
+
+  void generate_program();
+  void generate_program_toc();
+  void generate_program_toc_row(t_program* tprog);
+  void generate_program_toc_rows(t_program* tprog, std::vector<t_program*>& finished);
+  void generate_index();
+  std::string escape_html(std::string const& str);
+  std::string escape_html_tags(std::string const& str);
+  void generate_css();
+  void generate_css_content(std::ostream& f_target);
+  void generate_style_tag();
+  std::string make_file_link(std::string name);
+  bool is_utf8_sequence(std::string const& str, size_t firstpos);
+  void detect_input_encoding(std::string const& str, size_t firstpos);
+  void init_allowed__markup();
+
+  /**
+   * 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_service(t_service* tservice);
+  void generate_xception(t_struct* txception);
+
+  void print_doc(t_doc* tdoc);
+  int print_type(t_type* ttype);
+  void print_const_value(t_type* type, t_const_value* tvalue);
+  void print_fn_args_doc(t_function* tfunction);
+
+private:
+  ofstream_with_content_based_conditional_update f_out_;
+  std::string current_file_;
+  input_type input_type_;
+  std::map<std::string, int> allowed_markup;
+  bool standalone_;
+  bool unsafe_;
+};
+
+/**
+ * Emits the Table of Contents links at the top of the module's page
+ */
+void t_html_generator::generate_program_toc() {
+  f_out_ << "<table class=\"table-bordered table-striped "
+            "table-condensed\"><thead><th>Module</th><th>Services</th>"
+         << "<th>Data types</th><th>Constants</th></thead>" << endl;
+  generate_program_toc_row(program_);
+  f_out_ << "</table>" << endl;
+}
+
+/**
+ * Recurses through from the provided program and generates a ToC row
+ * for each discovered program exactly once by maintaining the list of
+ * completed rows in 'finished'
+ */
+void t_html_generator::generate_program_toc_rows(t_program* tprog,
+                                                 std::vector<t_program*>& finished) {
+  for (vector<t_program*>::iterator iter = finished.begin(); iter != finished.end(); iter++) {
+    if (tprog->get_path() == (*iter)->get_path()) {
+      return;
+    }
+  }
+  finished.push_back(tprog);
+  generate_program_toc_row(tprog);
+  vector<t_program*> includes = tprog->get_includes();
+  for (vector<t_program*>::iterator iter = includes.begin(); iter != includes.end(); iter++) {
+    generate_program_toc_rows(*iter, finished);
+  }
+}
+
+/**
+ * Emits the Table of Contents links at the top of the module's page
+ */
+void t_html_generator::generate_program_toc_row(t_program* tprog) {
+  string fname = tprog->get_name() + ".html";
+  f_out_ << "<tr>" << endl << "<td>" << tprog->get_name() << "</td><td>";
+  if (!tprog->get_services().empty()) {
+    vector<t_service*> services = tprog->get_services();
+    vector<t_service*>::iterator sv_iter;
+    for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+      string name = get_service_name(*sv_iter);
+      f_out_ << "<a href=\"" << make_file_link(fname) << "#Svc_" << name << "\">" << name
+             << "</a><br/>" << endl;
+      f_out_ << "<ul>" << endl;
+      map<string, string> fn_html;
+      vector<t_function*> functions = (*sv_iter)->get_functions();
+      vector<t_function*>::iterator fn_iter;
+      for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) {
+        string fn_name = (*fn_iter)->get_name();
+        string html = "<li><a href=\"" + make_file_link(fname) + "#Fn_" + name + "_" + fn_name
+                      + "\">" + fn_name + "</a></li>";
+        fn_html.insert(pair<string, string>(fn_name, html));
+      }
+      for (map<string, string>::iterator html_iter = fn_html.begin(); html_iter != fn_html.end();
+           html_iter++) {
+        f_out_ << html_iter->second << endl;
+      }
+      f_out_ << "</ul>" << endl;
+    }
+  }
+  f_out_ << "</td>" << endl << "<td>";
+  map<string, string> data_types;
+  if (!tprog->get_enums().empty()) {
+    vector<t_enum*> enums = tprog->get_enums();
+    vector<t_enum*>::iterator en_iter;
+    for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+      string name = (*en_iter)->get_name();
+      // f_out_ << "<a href=\"" << make_file_link(fname) << "#Enum_" << name << "\">" << name
+      // <<  "</a><br/>" << endl;
+      string html = "<a href=\"" + make_file_link(fname) + "#Enum_" + name + "\">" + name + "</a>";
+      data_types.insert(pair<string, string>(name, html));
+    }
+  }
+  if (!tprog->get_typedefs().empty()) {
+    vector<t_typedef*> typedefs = tprog->get_typedefs();
+    vector<t_typedef*>::iterator td_iter;
+    for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
+      string name = (*td_iter)->get_symbolic();
+      // f_out_ << "<a href=\"" << make_file_link(fname) << "#Typedef_" << name << "\">" << name
+      // << "</a><br/>" << endl;
+      string html = "<a href=\"" + make_file_link(fname) + "#Typedef_" + name + "\">" + name
+                    + "</a>";
+      data_types.insert(pair<string, string>(name, html));
+    }
+  }
+  if (!tprog->get_objects().empty()) {
+    vector<t_struct*> objects = tprog->get_objects();
+    vector<t_struct*>::iterator o_iter;
+    for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
+      string name = (*o_iter)->get_name();
+      // f_out_ << "<a href=\"" << make_file_link(fname) << "#Struct_" << name << "\">" << name
+      //<< "</a><br/>" << endl;
+      string html = "<a href=\"" + make_file_link(fname) + "#Struct_" + name + "\">" + name
+                    + "</a>";
+      data_types.insert(pair<string, string>(name, html));
+    }
+  }
+  for (map<string, string>::iterator dt_iter = data_types.begin(); dt_iter != data_types.end();
+       dt_iter++) {
+    f_out_ << dt_iter->second << "<br/>" << endl;
+  }
+  f_out_ << "</td>" << endl << "<td>";
+  if (!tprog->get_consts().empty()) {
+    map<string, string> const_html;
+    vector<t_const*> consts = tprog->get_consts();
+    vector<t_const*>::iterator con_iter;
+    for (con_iter = consts.begin(); con_iter != consts.end(); ++con_iter) {
+      string name = (*con_iter)->get_name();
+      string html = "<code><a href=\"" + make_file_link(fname) + "#Const_" + name + "\">" + name
+                    + "</a></code>";
+      const_html.insert(pair<string, string>(name, html));
+    }
+    for (map<string, string>::iterator con_iter = const_html.begin(); con_iter != const_html.end();
+         con_iter++) {
+      f_out_ << con_iter->second << "<br/>" << endl;
+    }
+  }
+  f_out_ << "</code></td>" << endl << "</tr>";
+}
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * stream.
+ */
+void t_html_generator::generate_program() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+  current_file_ = program_->get_name() + ".html";
+  string fname = get_out_dir() + current_file_;
+  f_out_.open(fname.c_str());
+  f_out_ << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"" << endl;
+  f_out_ << "    \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" << endl;
+  f_out_ << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl;
+  f_out_ << "<head>" << endl;
+  f_out_ << "<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" />" << endl;
+  generate_style_tag();
+  f_out_ << "<title>Thrift module: " << program_->get_name() << "</title></head><body>" << endl
+         << "<div class=\"container-fluid\">" << endl
+         << "<h1>Thrift module: " << program_->get_name() << "</h1>" << endl;
+
+  print_doc(program_);
+
+  generate_program_toc();
+
+  if (!program_->get_consts().empty()) {
+    f_out_ << "<hr/><h2 id=\"Constants\">Constants</h2>" << endl;
+    vector<t_const*> consts = program_->get_consts();
+    f_out_ << "<table class=\"table-bordered table-striped table-condensed\">";
+    f_out_ << "<thead><th>Constant</th><th>Type</th><th>Value</th></thead>" << endl;
+    generate_consts(consts);
+    f_out_ << "</table>";
+  }
+
+  if (!program_->get_enums().empty()) {
+    f_out_ << "<hr/><h2 id=\"Enumerations\">Enumerations</h2>" << endl;
+    // Generate enums
+    vector<t_enum*> enums = program_->get_enums();
+    vector<t_enum*>::iterator en_iter;
+    for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+      generate_enum(*en_iter);
+    }
+  }
+
+  if (!program_->get_typedefs().empty()) {
+    f_out_ << "<hr/><h2 id=\"Typedefs\">Type declarations</h2>" << endl;
+    // Generate typedefs
+    vector<t_typedef*> typedefs = program_->get_typedefs();
+    vector<t_typedef*>::iterator td_iter;
+    for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
+      generate_typedef(*td_iter);
+    }
+  }
+
+  if (!program_->get_objects().empty()) {
+    f_out_ << "<hr/><h2 id=\"Structs\">Data structures</h2>" << endl;
+    // Generate structs and exceptions in declared order
+    vector<t_struct*> objects = program_->get_objects();
+    vector<t_struct*>::iterator o_iter;
+    for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
+      if ((*o_iter)->is_xception()) {
+        generate_xception(*o_iter);
+      } else {
+        generate_struct(*o_iter);
+      }
+    }
+  }
+
+  if (!program_->get_services().empty()) {
+    f_out_ << "<hr/><h2 id=\"Services\">Services</h2>" << endl;
+    // Generate services
+    vector<t_service*> services = program_->get_services();
+    vector<t_service*>::iterator sv_iter;
+    for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+      service_name_ = get_service_name(*sv_iter);
+      generate_service(*sv_iter);
+    }
+  }
+
+  f_out_ << "</div></body></html>" << endl;
+  f_out_.close();
+
+  generate_index();
+  generate_css();
+}
+
+/**
+ * Emits the index.html file for the recursive set of Thrift programs
+ */
+void t_html_generator::generate_index() {
+  current_file_ = "index.html";
+  string index_fname = get_out_dir() + current_file_;
+  f_out_.open(index_fname.c_str());
+  f_out_ << "<html><head>" << endl;
+  generate_style_tag();
+  f_out_ << "<title>All Thrift declarations</title></head><body>" << endl
+         << "<div class=\"container-fluid\">" << endl << "<h1>All Thrift declarations</h1>" << endl;
+  f_out_ << "<table class=\"table-bordered table-striped "
+            "table-condensed\"><thead><th>Module</th><th>Services</th><th>Data types</th>"
+         << "<th>Constants</th></thead>" << endl;
+  vector<t_program*> programs;
+  generate_program_toc_rows(program_, programs);
+  f_out_ << "</table>" << endl;
+  f_out_ << "</div></body></html>" << endl;
+  f_out_.close();
+}
+
+void t_html_generator::generate_css() {
+  if (!standalone_) {
+    current_file_ = "style.css";
+    string css_fname = get_out_dir() + current_file_;
+    f_out_.open(css_fname.c_str());
+    generate_css_content(f_out_);
+    f_out_.close();
+  }
+}
+
+void t_html_generator::generate_css_content(std::ostream& f_target) {
+  f_target << BOOTSTRAP_CSS() << endl;
+  f_target << "/* Auto-generated CSS for generated Thrift docs */" << endl;
+  f_target << "h3, h4 { margin-bottom: 6px; }" << endl;
+  f_target << "div.definition { border: 1px solid #CCC; margin-bottom: 10px; padding: 10px; }"
+           << endl;
+  f_target << "div.extends { margin: -0.5em 0 1em 5em }" << endl;
+  f_target << "td { vertical-align: top; }" << endl;
+  f_target << "table { empty-cells: show; }" << endl;
+  f_target << "code { line-height: 20px; }" << endl;
+  f_target << ".table-bordered th, .table-bordered td { border-bottom: 1px solid #DDDDDD; }"
+           << endl;
+}
+
+/**
+ * Generates the CSS tag.
+ * Depending on "standalone", either a CSS file link (default), or the entire CSS is embedded
+ * inline.
+ */
+void t_html_generator::generate_style_tag() {
+  if (!standalone_) {
+    f_out_ << "<link href=\"style.css\" rel=\"stylesheet\" type=\"text/css\"/>" << endl;
+  } else {
+    f_out_ << "<style type=\"text/css\"/><!--" << endl;
+    generate_css_content(f_out_);
+    f_out_ << "--></style>" << endl;
+  }
+}
+
+/**
+ * Returns the target file for a <a href> link
+ * The returned string is empty, whenever filename refers to the current file.
+ */
+std::string t_html_generator::make_file_link(std::string filename) {
+  return (current_file_.compare(filename) != 0) ? filename : "";
+}
+
+/**
+ * If the provided documentable object has documentation attached, this
+ * will emit it to the output stream in HTML format.
+ */
+void t_html_generator::print_doc(t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    if (unsafe_) {
+      f_out_ << tdoc->get_doc() << "<br/>";
+    } else {
+      f_out_ << "<pre>" << escape_html(tdoc->get_doc()) << "</pre><br/>";
+    }
+  }
+}
+
+bool t_html_generator::is_utf8_sequence(std::string const& str, size_t firstpos) {
+  // leading char determines the length of the sequence
+  unsigned char c = str.at(firstpos);
+  int count = 0;
+  if ((c & 0xE0) == 0xC0) {
+    count = 1;
+  } else if ((c & 0xF0) == 0xE0) {
+    count = 2;
+  } else if ((c & 0xF8) == 0xF0) {
+    count = 3;
+  } else if ((c & 0xFC) == 0xF8) {
+    count = 4;
+  } else if ((c & 0xFE) == 0xFC) {
+    count = 5;
+  } else {
+    // pdebug("UTF-8 test: char '%c' (%d) is not a valid UTF-8 leading byte", c, int(c));
+    return false; // no UTF-8
+  }
+
+  // following chars
+  size_t pos = firstpos + 1;
+  while ((pos < str.length()) && (0 < count)) {
+    c = str.at(pos);
+    if ((c & 0xC0) != 0x80) {
+      // pdebug("UTF-8 test: char '%c' (%d) is not a valid UTF-8 following byte", c, int(c));
+      return false; // no UTF-8
+    }
+    --count;
+    ++pos;
+  }
+
+  // true if the sequence is complete
+  return (0 == count);
+}
+
+void t_html_generator::detect_input_encoding(std::string const& str, size_t firstpos) {
+  if (is_utf8_sequence(str, firstpos)) {
+    pdebug("Input seems to be already UTF-8 encoded");
+    input_type_ = INPUT_UTF8;
+    return;
+  }
+
+  // fallback
+  pwarning(1, "Input is not UTF-8, treating as plain ANSI");
+  input_type_ = INPUT_PLAIN;
+}
+
+void t_html_generator::init_allowed__markup() {
+  allowed_markup.clear();
+  // standalone tags
+  allowed_markup["br"] = 1;
+  allowed_markup["br/"] = 1;
+  allowed_markup["img"] = 1;
+  // paired tags
+  allowed_markup["b"] = 1;
+  allowed_markup["/b"] = 1;
+  allowed_markup["u"] = 1;
+  allowed_markup["/u"] = 1;
+  allowed_markup["i"] = 1;
+  allowed_markup["/i"] = 1;
+  allowed_markup["s"] = 1;
+  allowed_markup["/s"] = 1;
+  allowed_markup["big"] = 1;
+  allowed_markup["/big"] = 1;
+  allowed_markup["small"] = 1;
+  allowed_markup["/small"] = 1;
+  allowed_markup["sup"] = 1;
+  allowed_markup["/sup"] = 1;
+  allowed_markup["sub"] = 1;
+  allowed_markup["/sub"] = 1;
+  allowed_markup["pre"] = 1;
+  allowed_markup["/pre"] = 1;
+  allowed_markup["tt"] = 1;
+  allowed_markup["/tt"] = 1;
+  allowed_markup["ul"] = 1;
+  allowed_markup["/ul"] = 1;
+  allowed_markup["ol"] = 1;
+  allowed_markup["/ol"] = 1;
+  allowed_markup["li"] = 1;
+  allowed_markup["/li"] = 1;
+  allowed_markup["a"] = 1;
+  allowed_markup["/a"] = 1;
+  allowed_markup["p"] = 1;
+  allowed_markup["/p"] = 1;
+  allowed_markup["code"] = 1;
+  allowed_markup["/code"] = 1;
+  allowed_markup["dl"] = 1;
+  allowed_markup["/dl"] = 1;
+  allowed_markup["dt"] = 1;
+  allowed_markup["/dt"] = 1;
+  allowed_markup["dd"] = 1;
+  allowed_markup["/dd"] = 1;
+  allowed_markup["h1"] = 1;
+  allowed_markup["/h1"] = 1;
+  allowed_markup["h2"] = 1;
+  allowed_markup["/h2"] = 1;
+  allowed_markup["h3"] = 1;
+  allowed_markup["/h3"] = 1;
+  allowed_markup["h4"] = 1;
+  allowed_markup["/h4"] = 1;
+  allowed_markup["h5"] = 1;
+  allowed_markup["/h5"] = 1;
+  allowed_markup["h6"] = 1;
+  allowed_markup["/h6"] = 1;
+}
+
+std::string t_html_generator::escape_html_tags(std::string const& str) {
+  std::ostringstream result;
+
+  unsigned char c = '?';
+  size_t lastpos;
+  size_t firstpos = 0;
+  while (firstpos < str.length()) {
+
+    // look for non-ASCII char
+    lastpos = firstpos;
+    while (lastpos < str.length()) {
+      c = str.at(lastpos);
+      if (('<' == c) || ('>' == c)) {
+        break;
+      }
+      ++lastpos;
+    }
+
+    // copy what we got so far
+    if (lastpos > firstpos) {
+      result << str.substr(firstpos, lastpos - firstpos);
+      firstpos = lastpos;
+    }
+
+    // reached the end?
+    if (firstpos >= str.length()) {
+      break;
+    }
+
+    // tag end without corresponding begin
+    ++firstpos;
+    if ('>' == c) {
+      result << "&gt;";
+      continue;
+    }
+
+    // extract the tag
+    std::ostringstream tagstream;
+    while (firstpos < str.length()) {
+      c = str.at(firstpos);
+      ++firstpos;
+      if ('<' == c) {
+        tagstream << "&lt;"; // nested begin?
+      } else if ('>' == c) {
+        break;
+      } else {
+        tagstream << c; // not very efficient, but tags should be quite short
+      }
+    }
+
+    // we allow for several markup in docstrings, all else will become escaped
+    string tag_content = tagstream.str();
+    string tag_key = tag_content;
+    size_t first_white = tag_key.find_first_of(" \t\f\v\n\r");
+    if (first_white != string::npos) {
+      tag_key.erase(first_white);
+    }
+    for (std::string::size_type i = 0; i < tag_key.length(); ++i) {
+      tag_key[i] = tolower(tag_key[i]);
+    }
+    if (allowed_markup.find(tag_key) != allowed_markup.end()) {
+      result << "<" << tag_content << ">";
+    } else {
+      result << "&lt;" << tagstream.str() << "&gt;";
+      pverbose("illegal markup <%s> in doc-comment\n", tag_key.c_str());
+    }
+  }
+
+  return result.str();
+}
+
+std::string t_html_generator::escape_html(std::string const& str) {
+  // the generated HTML header says it is UTF-8 encoded
+  // if UTF-8 input has been detected before, we don't need to change anything
+  if (input_type_ == INPUT_UTF8) {
+    return escape_html_tags(str);
+  }
+
+  // convert unsafe chars to their &#<num>; equivalent
+  std::ostringstream result;
+  unsigned char c = '?';
+  unsigned int ic = 0;
+  size_t lastpos;
+  size_t firstpos = 0;
+  while (firstpos < str.length()) {
+
+    // look for non-ASCII char
+    lastpos = firstpos;
+    while (lastpos < str.length()) {
+      c = str.at(lastpos);
+      ic = c;
+      if ((32 > ic) || (127 < ic)) {
+        break;
+      }
+      ++lastpos;
+    }
+
+    // copy what we got so far
+    if (lastpos > firstpos) {
+      result << str.substr(firstpos, lastpos - firstpos);
+      firstpos = lastpos;
+    }
+
+    // reached the end?
+    if (firstpos >= str.length()) {
+      break;
+    }
+
+    // some control code?
+    if (ic <= 31) {
+      switch (c) {
+      case '\r':
+      case '\n':
+      case '\t':
+        result << c;
+        break;
+      default: // silently consume all other ctrl chars
+        break;
+      }
+      ++firstpos;
+      continue;
+    }
+
+    // reached the end?
+    if (firstpos >= str.length()) {
+      break;
+    }
+
+    // try to detect input encoding
+    if (input_type_ == INPUT_UNKNOWN) {
+      detect_input_encoding(str, firstpos);
+      if (input_type_ == INPUT_UTF8) {
+        lastpos = str.length();
+        result << str.substr(firstpos, lastpos - firstpos);
+        break;
+      }
+    }
+
+    // convert the character to something useful based on the detected encoding
+    switch (input_type_) {
+    case INPUT_PLAIN:
+      result << "&#" << ic << ";";
+      ++firstpos;
+      break;
+    default:
+      throw "Unexpected or unrecognized input encoding";
+    }
+  }
+
+  return escape_html_tags(result.str());
+}
+
+/**
+ * Prints out the provided type in HTML
+ */
+int t_html_generator::print_type(t_type* ttype) {
+  std::string::size_type len = 0;
+  f_out_ << "<code>";
+  if (ttype->is_container()) {
+    if (ttype->is_list()) {
+      f_out_ << "list&lt;";
+      len = 6 + print_type(((t_list*)ttype)->get_elem_type());
+      f_out_ << "&gt;";
+    } else if (ttype->is_set()) {
+      f_out_ << "set&lt;";
+      len = 5 + print_type(((t_set*)ttype)->get_elem_type());
+      f_out_ << "&gt;";
+    } else if (ttype->is_map()) {
+      f_out_ << "map&lt;";
+      len = 5 + print_type(((t_map*)ttype)->get_key_type());
+      f_out_ << ", ";
+      len += print_type(((t_map*)ttype)->get_val_type());
+      f_out_ << "&gt;";
+    }
+  } else if (ttype->is_base_type()) {
+    f_out_ << (ttype->is_binary() ? "binary" : ttype->get_name());
+    len = ttype->get_name().size();
+  } else {
+    string prog_name = ttype->get_program()->get_name();
+    string type_name = ttype->get_name();
+    f_out_ << "<a href=\"" << make_file_link(prog_name + ".html") << "#";
+    if (ttype->is_typedef()) {
+      f_out_ << "Struct_";
+    } else if (ttype->is_struct() || ttype->is_xception()) {
+      f_out_ << "Struct_";
+    } else if (ttype->is_enum()) {
+      f_out_ << "Enum_";
+    } else if (ttype->is_service()) {
+      f_out_ << "Svc_";
+    }
+    f_out_ << type_name << "\">";
+    len = type_name.size();
+    if (ttype->get_program() != program_) {
+      f_out_ << prog_name << ".";
+      len += prog_name.size() + 1;
+    }
+    f_out_ << type_name << "</a>";
+  }
+  f_out_ << "</code>";
+  return (int)len;
+}
+
+/**
+ * Prints out an HTML representation of the provided constant value
+ */
+void t_html_generator::print_const_value(t_type* type, t_const_value* tvalue) {
+
+  // if tvalue is an identifier, the constant content is already shown elsewhere
+  if (tvalue->get_type() == t_const_value::CV_IDENTIFIER) {
+    string fname = program_->get_name() + ".html";
+    string name = escape_html(tvalue->get_identifier());
+    f_out_ << "<code><a href=\"" + make_file_link(fname) + "#Const_" + name + "\">" + name
+              + "</a></code>";
+    return;
+  }
+
+  t_type* truetype = type;
+  while (truetype->is_typedef()) {
+    truetype = ((t_typedef*)truetype)->get_type();
+  }
+
+  bool first = true;
+  if (truetype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)truetype)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      f_out_ << '"' << escape_html(get_escaped_string(tvalue)) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      f_out_ << ((tvalue->get_integer() != 0) ? "true" : "false");
+      break;
+    case t_base_type::TYPE_I8:
+      f_out_ << tvalue->get_integer();
+      break;
+    case t_base_type::TYPE_I16:
+      f_out_ << tvalue->get_integer();
+      break;
+    case t_base_type::TYPE_I32:
+      f_out_ << tvalue->get_integer();
+      break;
+    case t_base_type::TYPE_I64:
+      f_out_ << tvalue->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (tvalue->get_type() == t_const_value::CV_INTEGER) {
+        f_out_ << tvalue->get_integer();
+      } else {
+        f_out_ << tvalue->get_double();
+      }
+      break;
+    default:
+      f_out_ << "UNKNOWN BASE TYPE";
+      break;
+    }
+  } else if (truetype->is_enum()) {
+    f_out_ << escape_html(truetype->get_name()) << "."
+           << escape_html(tvalue->get_identifier_name());
+  } else if (truetype->is_struct() || truetype->is_xception()) {
+    f_out_ << "{ ";
+    const vector<t_field*>& fields = ((t_struct*)truetype)->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = tvalue->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::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: " + truetype->get_name() + " has no field "
+            + v_iter->first->get_string();
+      }
+      if (!first) {
+        f_out_ << ", ";
+      }
+      first = false;
+      f_out_ << escape_html(v_iter->first->get_string()) << " = ";
+      print_const_value(field_type, v_iter->second);
+    }
+    f_out_ << " }";
+  } else if (truetype->is_map()) {
+    f_out_ << "{ ";
+    map<t_const_value*, t_const_value*, t_const_value::value_compare> map_elems = tvalue->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::iterator map_iter;
+    for (map_iter = map_elems.begin(); map_iter != map_elems.end(); map_iter++) {
+      if (!first) {
+        f_out_ << ", ";
+      }
+      first = false;
+      print_const_value(((t_map*)truetype)->get_key_type(), map_iter->first);
+      f_out_ << " = ";
+      print_const_value(((t_map*)truetype)->get_val_type(), map_iter->second);
+    }
+    f_out_ << " }";
+  } else if (truetype->is_list()) {
+    f_out_ << "{ ";
+    vector<t_const_value*> list_elems = tvalue->get_list();
+    ;
+    vector<t_const_value*>::iterator list_iter;
+    for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) {
+      if (!first) {
+        f_out_ << ", ";
+      }
+      first = false;
+      print_const_value(((t_list*)truetype)->get_elem_type(), *list_iter);
+    }
+    f_out_ << " }";
+  } else if (truetype->is_set()) {
+    f_out_ << "{ ";
+    vector<t_const_value*> list_elems = tvalue->get_list();
+    ;
+    vector<t_const_value*>::iterator list_iter;
+    for (list_iter = list_elems.begin(); list_iter != list_elems.end(); list_iter++) {
+      if (!first) {
+        f_out_ << ", ";
+      }
+      first = false;
+      print_const_value(((t_set*)truetype)->get_elem_type(), *list_iter);
+    }
+    f_out_ << " }";
+  } else {
+    f_out_ << "UNKNOWN TYPE";
+  }
+}
+
+/**
+ * Prints out documentation for arguments/exceptions of a function, if any documentation has been
+ * supplied.
+ */
+void t_html_generator::print_fn_args_doc(t_function* tfunction) {
+  bool has_docs = false;
+  vector<t_field*> args = tfunction->get_arglist()->get_members();
+  vector<t_field*>::iterator arg_iter = args.begin();
+  if (arg_iter != args.end()) {
+    for (; arg_iter != args.end(); arg_iter++) {
+      if ((*arg_iter)->has_doc() && !(*arg_iter)->get_doc().empty())
+        has_docs = true;
+    }
+    if (has_docs) {
+      arg_iter = args.begin();
+      f_out_ << "<br/><h4 id=\"Parameters_" << service_name_ << "_" << tfunction->get_name()
+             << "\">Parameters</h4>" << endl;
+      f_out_ << "<table class=\"table-bordered table-striped table-condensed\">";
+      f_out_ << "<thead><th>Name</th><th>Description</th></thead>";
+      for (; arg_iter != args.end(); arg_iter++) {
+        f_out_ << "<tr><td>" << (*arg_iter)->get_name();
+        f_out_ << "</td><td>";
+        f_out_ << escape_html((*arg_iter)->get_doc());
+        f_out_ << "</td></tr>" << endl;
+      }
+      f_out_ << "</table>";
+    }
+  }
+
+  has_docs = false;
+  vector<t_field*> excepts = tfunction->get_xceptions()->get_members();
+  vector<t_field*>::iterator ex_iter = excepts.begin();
+  if (ex_iter != excepts.end()) {
+    for (; ex_iter != excepts.end(); ex_iter++) {
+      if ((*ex_iter)->has_doc() && !(*ex_iter)->get_doc().empty())
+        has_docs = true;
+    }
+    if (has_docs) {
+      ex_iter = excepts.begin();
+      f_out_ << "<br/><h4 id=\"Exceptions_" << service_name_ << "_" << tfunction->get_name()
+             << "\">Exceptions</h4>" << endl;
+      f_out_ << "<table class=\"table-bordered table-striped table-condensed\">";
+      f_out_ << "<thead><th>Type</th><th>Description</th></thead>";
+      for (; ex_iter != excepts.end(); ex_iter++) {
+        f_out_ << "<tr><td>" << (*ex_iter)->get_type()->get_name();
+        f_out_ << "</td><td>";
+        f_out_ << escape_html((*ex_iter)->get_doc());
+        f_out_ << "</td></tr>" << endl;
+      }
+      f_out_ << "</table>";
+    }
+  }
+}
+
+/**
+ * Generates a typedef.
+ *
+ * @param ttypedef The type definition
+ */
+void t_html_generator::generate_typedef(t_typedef* ttypedef) {
+  string name = ttypedef->get_name();
+  f_out_ << "<div class=\"definition\">";
+  f_out_ << "<h3 id=\"Typedef_" << name << "\">Typedef: " << name << "</h3>" << endl;
+  f_out_ << "<p><strong>Base type:</strong>&nbsp;";
+  print_type(ttypedef->get_type());
+  f_out_ << "</p>" << endl;
+  print_doc(ttypedef);
+  f_out_ << "</div>" << endl;
+}
+
+/**
+ * Generates code for an enumerated type.
+ *
+ * @param tenum The enumeration
+ */
+void t_html_generator::generate_enum(t_enum* tenum) {
+  string name = tenum->get_name();
+  f_out_ << "<div class=\"definition\">";
+  f_out_ << "<h3 id=\"Enum_" << name << "\">Enumeration: " << name << "</h3>" << endl;
+  print_doc(tenum);
+  vector<t_enum_value*> values = tenum->get_constants();
+  vector<t_enum_value*>::iterator val_iter;
+  f_out_ << "<br/><table class=\"table-bordered table-striped table-condensed\">" << endl;
+  for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) {
+    f_out_ << "<tr><td><code>";
+    f_out_ << (*val_iter)->get_name();
+    f_out_ << "</code></td><td><code>";
+    f_out_ << (*val_iter)->get_value();
+    f_out_ << "</code></td><td>" << endl;
+    print_doc((*val_iter));
+    f_out_ << "</td></tr>" << endl;
+  }
+  f_out_ << "</table></div>" << endl;
+}
+
+/**
+ * Generates a constant value
+ */
+void t_html_generator::generate_const(t_const* tconst) {
+  string name = tconst->get_name();
+  f_out_ << "<tr id=\"Const_" << name << "\"><td><code>" << name << "</code></td><td>";
+  print_type(tconst->get_type());
+  f_out_ << "</td><td><code>";
+  print_const_value(tconst->get_type(), tconst->get_value());
+  f_out_ << "</code></td></tr>";
+  if (tconst->has_doc()) {
+    f_out_ << "<tr><td colspan=\"3\"><blockquote>";
+    print_doc(tconst);
+    f_out_ << "</blockquote></td></tr>";
+  }
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_html_generator::generate_struct(t_struct* tstruct) {
+  string name = tstruct->get_name();
+  f_out_ << "<div class=\"definition\">";
+  f_out_ << "<h3 id=\"Struct_" << name << "\">";
+  if (tstruct->is_xception()) {
+    f_out_ << "Exception: ";
+  } else if (tstruct->is_union()) {
+    f_out_ << "Union: ";
+  } else {
+    f_out_ << "Struct: ";
+  }
+  f_out_ << name << "</h3>" << endl;
+  vector<t_field*> members = tstruct->get_members();
+  vector<t_field*>::iterator mem_iter = members.begin();
+  f_out_ << "<table class=\"table-bordered table-striped table-condensed\">";
+  f_out_ << "<thead><th>Key</th><th>Field</th><th>Type</th><th>Description</th><th>Requiredness</"
+            "th><th>Default value</th></thead>" << endl;
+  for (; mem_iter != members.end(); mem_iter++) {
+    f_out_ << "<tr><td>" << (*mem_iter)->get_key() << "</td><td>";
+    f_out_ << (*mem_iter)->get_name();
+    f_out_ << "</td><td>";
+    print_type((*mem_iter)->get_type());
+    f_out_ << "</td><td>";
+    f_out_ << escape_html((*mem_iter)->get_doc());
+    f_out_ << "</td><td>";
+    if ((*mem_iter)->get_req() == t_field::T_OPTIONAL) {
+      f_out_ << "optional";
+    } else if ((*mem_iter)->get_req() == t_field::T_REQUIRED) {
+      f_out_ << "required";
+    } else {
+      f_out_ << "default";
+    }
+    f_out_ << "</td><td>";
+    t_const_value* default_val = (*mem_iter)->get_value();
+    if (default_val != NULL) {
+      f_out_ << "<code>";
+      print_const_value((*mem_iter)->get_type(), default_val);
+      f_out_ << "</code>";
+    }
+    f_out_ << "</td></tr>" << endl;
+  }
+  f_out_ << "</table><br/>";
+  print_doc(tstruct);
+  f_out_ << "</div>";
+}
+
+/**
+ * Exceptions are special structs
+ *
+ * @param tstruct The struct definition
+ */
+void t_html_generator::generate_xception(t_struct* txception) {
+  generate_struct(txception);
+}
+
+/**
+ * Generates the HTML block for a Thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_html_generator::generate_service(t_service* tservice) {
+  f_out_ << "<h3 id=\"Svc_" << service_name_ << "\">Service: " << service_name_ << "</h3>" << endl;
+
+  if (tservice->get_extends()) {
+    f_out_ << "<div class=\"extends\"><em>extends</em> ";
+    print_type(tservice->get_extends());
+    f_out_ << "</div>\n";
+  }
+  print_doc(tservice);
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator fn_iter = functions.begin();
+  for (; fn_iter != functions.end(); fn_iter++) {
+    string fn_name = (*fn_iter)->get_name();
+    f_out_ << "<div class=\"definition\">";
+    f_out_ << "<h4 id=\"Fn_" << service_name_ << "_" << fn_name << "\">Function: " << service_name_
+           << "." << fn_name << "</h4>" << endl;
+    f_out_ << "<pre>";
+    std::string::size_type offset = print_type((*fn_iter)->get_returntype());
+    bool first = true;
+    f_out_ << " " << fn_name << "(";
+    offset += fn_name.size() + 2;
+    vector<t_field*> args = (*fn_iter)->get_arglist()->get_members();
+    vector<t_field*>::iterator arg_iter = args.begin();
+    for (; arg_iter != args.end(); arg_iter++) {
+      if (!first) {
+        f_out_ << "," << endl;
+        for (std::string::size_type i = 0; i < offset; ++i) {
+          f_out_ << " ";
+        }
+      }
+      first = false;
+      print_type((*arg_iter)->get_type());
+      f_out_ << " " << (*arg_iter)->get_name();
+      if ((*arg_iter)->get_value() != NULL) {
+        f_out_ << " = ";
+        print_const_value((*arg_iter)->get_type(), (*arg_iter)->get_value());
+      }
+    }
+    f_out_ << ")" << endl;
+    first = true;
+    vector<t_field*> excepts = (*fn_iter)->get_xceptions()->get_members();
+    vector<t_field*>::iterator ex_iter = excepts.begin();
+    if (ex_iter != excepts.end()) {
+      f_out_ << "    throws ";
+      for (; ex_iter != excepts.end(); ex_iter++) {
+        if (!first) {
+          f_out_ << ", ";
+        }
+        first = false;
+        print_type((*ex_iter)->get_type());
+      }
+      f_out_ << endl;
+    }
+    f_out_ << "</pre>";
+    print_doc(*fn_iter);
+    print_fn_args_doc(*fn_iter);
+    f_out_ << "</div>";
+  }
+}
+
+THRIFT_REGISTER_GENERATOR(
+    html,
+    "HTML",
+    "    standalone:      Self-contained mode, includes all CSS in the HTML files.\n"
+    "                     Generates no style.css file, but HTML files will be larger.\n"
+    "    noescape:        Do not escape html in doc text.\n")
diff --git a/compiler/cpp/src/thrift/generate/t_html_generator.h b/compiler/cpp/src/thrift/generate/t_html_generator.h
new file mode 100644
index 0000000..600b17f
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_html_generator.h
@@ -0,0 +1,240 @@
+#define BOOTSTRAP_CSS()                                                                            \
+  "/*!\n"                                                                                          \
+  " * Bootstrap v2.0.3\n"                                                                          \
+  " *\n"                                                                                           \
+  " * Copyright 2012 Twitter, Inc\n"                                                               \
+  " * Licensed under the Apache License v2.0\n"                                                    \
+  " * http://www.apache.org/licenses/LICENSE-2.0\n"                                                \
+  " *\n"                                                                                           \
+  " * Designed and built with all the love in the world @twitter by @mdo and @fat.\n"              \
+  " */\n"                                                                                          \
+  ".clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:\"\";}\n"             \
+  ".clearfix:after{clear:both;}\n"                                                                 \
+  ".hide-text{font:0/0 "                                                                           \
+  "a;color:transparent;text-shadow:none;background-color:transparent;border:0;}\n"                 \
+  ".input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-"    \
+  "moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;}\n"                  \
+  "article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}\n"     \
+  "audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}\n"                            \
+  "audio:not([controls]){display:none;}\n"                                                         \
+  "html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}\n"                \
+  "a:focus{outline:thin dotted #333;outline:5px auto "                                             \
+  "-webkit-focus-ring-color;outline-offset:-2px;}\n"                                               \
+  "a:hover,a:active{outline:0;}\n"                                                                 \
+  "sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}\n"              \
+  "sup{top:-0.5em;}\n"                                                                             \
+  "sub{bottom:-0.25em;}\n"                                                                         \
+  "img{max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;}\n"           \
+  "button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}\n"                 \
+  "button,input{*overflow:visible;line-height:normal;}\n"                                          \
+  "button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}\n"                        \
+  "button,input[type=\"button\"],input[type=\"reset\"],input[type=\"submit\"]{cursor:pointer;-"    \
+  "webkit-appearance:button;}\n"                                                                   \
+  "input[type=\"search\"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:"  \
+  "content-box;-webkit-appearance:textfield;}\n"                                                   \
+  "input[type=\"search\"]::-webkit-search-decoration,input[type=\"search\"]::-webkit-search-"      \
+  "cancel-button{-webkit-appearance:none;}\n"                                                      \
+  "textarea{overflow:auto;vertical-align:top;}\n"                                                  \
+  "body{margin:0;font-family:\"Helvetica "                                                         \
+  "Neue\",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-"    \
+  "color:#ffffff;}\n"                                                                              \
+  "a{color:#0088cc;text-decoration:none;}\n"                                                       \
+  "a:hover{color:#005580;text-decoration:underline;}\n"                                            \
+  ".row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:\"\";}\n"          \
+  ".row:after{clear:both;}\n"                                                                      \
+  "[class*=\"span\"]{float:left;margin-left:20px;}\n"                                              \
+  ".container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}\n"        \
+  ".span12{width:940px;}\n"                                                                        \
+  ".span11{width:860px;}\n"                                                                        \
+  ".span10{width:780px;}\n"                                                                        \
+  ".span9{width:700px;}\n"                                                                         \
+  ".span8{width:620px;}\n"                                                                         \
+  ".span7{width:540px;}\n"                                                                         \
+  ".span6{width:460px;}\n"                                                                         \
+  ".span5{width:380px;}\n"                                                                         \
+  ".span4{width:300px;}\n"                                                                         \
+  ".span3{width:220px;}\n"                                                                         \
+  ".span2{width:140px;}\n"                                                                         \
+  ".span1{width:60px;}\n"                                                                          \
+  ".offset12{margin-left:980px;}\n"                                                                \
+  ".offset11{margin-left:900px;}\n"                                                                \
+  ".offset10{margin-left:820px;}\n"                                                                \
+  ".offset9{margin-left:740px;}\n"                                                                 \
+  ".offset8{margin-left:660px;}\n"                                                                 \
+  ".offset7{margin-left:580px;}\n"                                                                 \
+  ".offset6{margin-left:500px;}\n"                                                                 \
+  ".offset5{margin-left:420px;}\n"                                                                 \
+  ".offset4{margin-left:340px;}\n"                                                                 \
+  ".offset3{margin-left:260px;}\n"                                                                 \
+  ".offset2{margin-left:180px;}\n"                                                                 \
+  ".offset1{margin-left:100px;}\n"                                                                 \
+  ".row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:\"\";}" \
+  "\n"                                                                                             \
+  ".row-fluid:after{clear:both;}\n"                                                                \
+  ".row-fluid "                                                                                    \
+  "[class*=\"span\"]{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-" \
+  "box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:"  \
+  "2.127659574%;*margin-left:2.0744680846382977%;}\n"                                              \
+  ".row-fluid [class*=\"span\"]:first-child{margin-left:0;}\n"                                     \
+  ".row-fluid .span12{width:99.99999998999999%;*width:99.94680850063828%;}\n"                      \
+  ".row-fluid .span11{width:91.489361693%;*width:91.4361702036383%;}\n"                            \
+  ".row-fluid .span10{width:82.97872339599999%;*width:82.92553190663828%;}\n"                      \
+  ".row-fluid .span9{width:74.468085099%;*width:74.4148936096383%;}\n"                             \
+  ".row-fluid .span8{width:65.95744680199999%;*width:65.90425531263828%;}\n"                       \
+  ".row-fluid .span7{width:57.446808505%;*width:57.3936170156383%;}\n"                             \
+  ".row-fluid .span6{width:48.93617020799999%;*width:48.88297871863829%;}\n"                       \
+  ".row-fluid .span5{width:40.425531911%;*width:40.3723404216383%;}\n"                             \
+  ".row-fluid .span4{width:31.914893614%;*width:31.8617021246383%;}\n"                             \
+  ".row-fluid .span3{width:23.404255317%;*width:23.3510638276383%;}\n"                             \
+  ".row-fluid .span2{width:14.89361702%;*width:14.8404255306383%;}\n"                              \
+  ".row-fluid .span1{width:6.382978723%;*width:6.329787233638298%;}\n"                             \
+  ".container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{"     \
+  "display:table;content:\"\";}\n"                                                                 \
+  ".container:after{clear:both;}\n"                                                                \
+  ".container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,."       \
+  "container-fluid:after{display:table;content:\"\";}\n"                                           \
+  ".container-fluid:after{clear:both;}\n"                                                          \
+  "p{margin:0 0 9px;font-family:\"Helvetica "                                                      \
+  "Neue\",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p "                          \
+  "small{font-size:11px;color:#999999;}\n"                                                         \
+  ".lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;}\n"                   \
+  "h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:"  \
+  "optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 "                           \
+  "small{font-weight:normal;color:#999999;}\n"                                                     \
+  "h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;}\n"                                \
+  "h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;}\n"                                \
+  "h3{font-size:18px;line-height:27px;}h3 small{font-size:14px;}\n"                                \
+  "h4,h5,h6{line-height:18px;}\n"                                                                  \
+  "h4{font-size:14px;}h4 small{font-size:12px;}\n"                                                 \
+  "h5{font-size:12px;}\n"                                                                          \
+  "h6{font-size:11px;color:#999999;text-transform:uppercase;}\n"                                   \
+  ".page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;}\n"             \
+  ".page-header h1{line-height:1;}\n"                                                              \
+  "ul,ol{padding:0;margin:0 0 9px 25px;}\n"                                                        \
+  "ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}\n"                                                    \
+  "ul{list-style:disc;}\n"                                                                         \
+  "ol{list-style:decimal;}\n"                                                                      \
+  "li{line-height:18px;}\n"                                                                        \
+  "ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}\n"                                      \
+  "dl{margin-bottom:18px;}\n"                                                                      \
+  "dt,dd{line-height:18px;}\n"                                                                     \
+  "dt{font-weight:bold;line-height:17px;}\n"                                                       \
+  "dd{margin-left:9px;}\n"                                                                         \
+  ".dl-horizontal "                                                                                \
+  "dt{float:left;width:120px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;"  \
+  "white-space:nowrap;}\n"                                                                         \
+  ".dl-horizontal dd{margin-left:130px;}\n"                                                        \
+  "hr{margin:18px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}\n"     \
+  "strong{font-weight:bold;}\n"                                                                    \
+  "em{font-style:italic;}\n"                                                                       \
+  ".muted{color:#999999;}\n"                                                                       \
+  "abbr[title]{cursor:help;border-bottom:1px dotted #ddd;}\n"                                      \
+  "abbr.initialism{font-size:90%;text-transform:uppercase;}\n"                                     \
+  "blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote "       \
+  "p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;}\n"                        \
+  "blockquote small{display:block;line-height:18px;color:#999999;}blockquote "                     \
+  "small:before{content:'\\2014 \\00A0';}\n"                                                       \
+  "blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid "    \
+  "#eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right "                          \
+  "small{text-align:right;}\n"                                                                     \
+  "q:before,q:after,blockquote:before,blockquote:after{content:\"\";}\n"                           \
+  "address{display:block;margin-bottom:18px;font-style:normal;line-height:18px;}\n"                \
+  "small{font-size:100%;}\n"                                                                       \
+  "cite{font-style:normal;}\n"                                                                     \
+  "code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,Consolas,\"Courier "                        \
+  "New\",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;" \
+  "border-radius:3px;}\n"                                                                          \
+  "code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;}\n"          \
+  "pre{display:block;padding:8.5px;margin:0 0 "                                                    \
+  "9px;font-size:12.025px;line-height:18px;word-break:break-all;word-wrap:break-word;white-space:" \
+  "pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid "      \
+  "rgba(0, 0, 0, "                                                                                 \
+  "0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}pre.prettyprint{"     \
+  "margin-bottom:18px;}\n"                                                                         \
+  "pre code{padding:0;color:inherit;background-color:transparent;border:0;}\n"                     \
+  ".pre-scrollable{max-height:340px;overflow-y:scroll;}\n"                                         \
+  ".label,.badge{font-size:10.998px;font-weight:bold;line-height:14px;color:#ffffff;vertical-"     \
+  "align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, "                          \
+  "0.25);background-color:#999999;}\n"                                                             \
+  ".label{padding:1px 4px "                                                                        \
+  "2px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}\n"                     \
+  ".badge{padding:1px 9px "                                                                        \
+  "2px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;}\n"                     \
+  "a.label:hover,a.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;}\n"              \
+  ".label-important,.badge-important{background-color:#b94a48;}\n"                                 \
+  ".label-important[href],.badge-important[href]{background-color:#953b39;}\n"                     \
+  ".label-warning,.badge-warning{background-color:#f89406;}\n"                                     \
+  ".label-warning[href],.badge-warning[href]{background-color:#c67605;}\n"                         \
+  ".label-success,.badge-success{background-color:#468847;}\n"                                     \
+  ".label-success[href],.badge-success[href]{background-color:#356635;}\n"                         \
+  ".label-info,.badge-info{background-color:#3a87ad;}\n"                                           \
+  ".label-info[href],.badge-info[href]{background-color:#2d6987;}\n"                               \
+  ".label-inverse,.badge-inverse{background-color:#333333;}\n"                                     \
+  ".label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;}\n"                         \
+  "table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;}"  \
+  "\n"                                                                                             \
+  ".table{width:100%;margin-bottom:18px;}.table th,.table "                                        \
+  "td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid "       \
+  "#dddddd;}\n"                                                                                    \
+  ".table th{font-weight:bold;}\n"                                                                 \
+  ".table thead th{vertical-align:bottom;}\n"                                                      \
+  ".table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table "          \
+  "colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table "               \
+  "thead:first-child tr:first-child th,.table thead:first-child tr:first-child "                   \
+  "td{border-top:0;}\n"                                                                            \
+  ".table tbody+tbody{border-top:2px solid #dddddd;}\n"                                            \
+  ".table-condensed th,.table-condensed td{padding:4px 5px;}\n"                                    \
+  ".table-bordered{border:1px solid "                                                              \
+  "#dddddd;border-collapse:separate;*border-collapse:collapsed;border-left:0;-webkit-border-"      \
+  "radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered "       \
+  "td{border-left:1px solid #dddddd;}\n"                                                           \
+  ".table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child "  \
+  "th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead "             \
+  "tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered "            \
+  "colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child "             \
+  "th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child "      \
+  "tr:first-child td{border-top:0;}\n"                                                             \
+  ".table-bordered thead:first-child tr:first-child th:first-child,.table-bordered "               \
+  "tbody:first-child tr:first-child "                                                              \
+  "td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-"      \
+  "radius-topleft:4px;}\n"                                                                         \
+  ".table-bordered thead:first-child tr:first-child th:last-child,.table-bordered "                \
+  "tbody:first-child tr:first-child "                                                              \
+  "td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-"     \
+  "radius-topright:4px;}\n"                                                                        \
+  ".table-bordered thead:last-child tr:last-child th:first-child,.table-bordered "                 \
+  "tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 "                     \
+  "4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 "                                          \
+  "4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-"    \
+  "bottomleft:4px;}\n"                                                                             \
+  ".table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child " \
+  "tr:last-child "                                                                                 \
+  "td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-"      \
+  "border-radius-bottomright:4px;}\n"                                                              \
+  ".table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) "              \
+  "th{background-color:#f9f9f9;}\n"                                                                \
+  ".table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5;}\n"                 \
+  "table .span1{float:none;width:44px;margin-left:0;}\n"                                           \
+  "table .span2{float:none;width:124px;margin-left:0;}\n"                                          \
+  "table .span3{float:none;width:204px;margin-left:0;}\n"                                          \
+  "table .span4{float:none;width:284px;margin-left:0;}\n"                                          \
+  "table .span5{float:none;width:364px;margin-left:0;}\n"                                          \
+  "table .span6{float:none;width:444px;margin-left:0;}\n"                                          \
+  "table .span7{float:none;width:524px;margin-left:0;}\n"                                          \
+  "table .span8{float:none;width:604px;margin-left:0;}\n"                                          \
+  "table .span9{float:none;width:684px;margin-left:0;}\n"                                          \
+  "table .span10{float:none;width:764px;margin-left:0;}\n"                                         \
+  "table .span11{float:none;width:844px;margin-left:0;}\n"                                         \
+  "table .span12{float:none;width:924px;margin-left:0;}\n"                                         \
+  "table .span13{float:none;width:1004px;margin-left:0;}\n"                                        \
+  "table .span14{float:none;width:1084px;margin-left:0;}\n"                                        \
+  "table .span15{float:none;width:1164px;margin-left:0;}\n"                                        \
+  "table .span16{float:none;width:1244px;margin-left:0;}\n"                                        \
+  "table .span17{float:none;width:1324px;margin-left:0;}\n"                                        \
+  "table .span18{float:none;width:1404px;margin-left:0;}\n"                                        \
+  "table .span19{float:none;width:1484px;margin-left:0;}\n"                                        \
+  "table .span20{float:none;width:1564px;margin-left:0;}\n"                                        \
+  "table .span21{float:none;width:1644px;margin-left:0;}\n"                                        \
+  "table .span22{float:none;width:1724px;margin-left:0;}\n"                                        \
+  "table .span23{float:none;width:1804px;margin-left:0;}\n"                                        \
+  "table .span24{float:none;width:1884px;margin-left:0;}"
diff --git a/compiler/cpp/src/thrift/generate/t_java_generator.cc b/compiler/cpp/src/thrift/generate/t_java_generator.cc
new file mode 100644
index 0000000..2c84551
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_java_generator.cc
@@ -0,0 +1,5454 @@
+/*
+ * 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.
+ */
+
+#include <cassert>
+#include <ctime>
+
+#include <sstream>
+#include <string>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <limits>
+#include <vector>
+#include <cctype>
+
+#include <sys/stat.h>
+#include <stdexcept>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::setfill;
+using std::setw;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * Java code generator.
+ *
+ */
+class t_java_generator : public t_oop_generator {
+public:
+  t_java_generator(t_program* program,
+                   const std::map<std::string, std::string>& parsed_options,
+                   const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    bean_style_ = false;
+    android_style_ = false;
+    private_members_ = false;
+    nocamel_style_ = false;
+    fullcamel_style_ = false;
+    android_legacy_ = false;
+    sorted_containers_ = false;
+    java5_ = false;
+    reuse_objects_ = false;
+    use_option_type_ = false;
+    undated_generated_annotations_  = false;
+    suppress_generated_annotations_ = false;
+    rethrow_unhandled_exceptions_ = false;
+    unsafe_binaries_ = false;
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("beans") == 0) {
+        bean_style_ = true;
+      } else if( iter->first.compare("android") == 0) {
+        android_style_ = true;
+      } else if( iter->first.compare("private-members") == 0) {
+        private_members_ = true;
+      } else if( iter->first.compare("nocamel") == 0) {
+        nocamel_style_ = true;
+      } else if( iter->first.compare("fullcamel") == 0) {
+        fullcamel_style_ = true;
+      } else if( iter->first.compare("android_legacy") == 0) {
+        android_legacy_ = true;
+      } else if( iter->first.compare("sorted_containers") == 0) {
+        sorted_containers_ = true;
+      } else if( iter->first.compare("java5") == 0) {
+        java5_ = true;
+      } else if( iter->first.compare("reuse-objects") == 0) {
+        reuse_objects_ = true;
+      } else if( iter->first.compare("option_type") == 0) {
+        use_option_type_ = true;
+      } else if( iter->first.compare("rethrow_unhandled_exceptions") == 0) {
+        rethrow_unhandled_exceptions_ = true;
+      } else if( iter->first.compare("generated_annotations") == 0) {
+        if( iter->second.compare("undated") == 0) {
+          undated_generated_annotations_  = true;
+        } else if(iter->second.compare("suppress") == 0) {
+          suppress_generated_annotations_ = true;
+        } else {
+          throw "unknown option java:" + iter->first + "=" + iter->second;
+        }
+      } else if( iter->first.compare("unsafe_binaries") == 0) {
+        unsafe_binaries_ = true;
+      } else {
+        throw "unknown option java:" + iter->first;
+      }
+    }
+
+    if (java5_) {
+      android_legacy_ = true;
+    }
+
+    out_dir_base_ = (bean_style_ ? "gen-javabean" : "gen-java");
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  void generate_consts(std::vector<t_const*> consts);
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_struct(t_struct* tstruct);
+  void generate_union(t_struct* tunion);
+  void generate_xception(t_struct* txception);
+  void generate_service(t_service* tservice);
+
+  void print_const_value(std::ostream& out,
+                         std::string name,
+                         t_type* type,
+                         t_const_value* value,
+                         bool in_static,
+                         bool defval = false);
+  std::string render_const_value(std::ostream& out, t_type* type, t_const_value* value);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_java_struct(t_struct* tstruct, bool is_exception);
+
+  void generate_java_struct_definition(std::ostream& out,
+                                       t_struct* tstruct,
+                                       bool is_xception = false,
+                                       bool in_class = false,
+                                       bool is_result = false);
+  void generate_java_struct_parcelable(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_equality(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_compare_to(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_java_validator(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_result_writer(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_writer(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_tostring(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_clear(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_write_object(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_read_object(std::ostream& out, t_struct* tstruct);
+  void generate_java_meta_data_map(std::ostream& out, t_struct* tstruct);
+  void generate_field_value_meta_data(std::ostream& out, t_type* type);
+  std::string get_java_type_string(t_type* type);
+  void generate_java_struct_field_by_id(ostream& out, t_struct* tstruct);
+  void generate_reflection_setters(std::ostringstream& out,
+                                   t_type* type,
+                                   std::string field_name,
+                                   std::string cap_name);
+  void generate_reflection_getters(std::ostringstream& out,
+                                   t_type* type,
+                                   std::string field_name,
+                                   std::string cap_name);
+  void generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct);
+  void generate_generic_isset_method(std::ostream& out, t_struct* tstruct);
+  void generate_java_bean_boilerplate(std::ostream& out, t_struct* tstruct);
+
+  void generate_function_helpers(t_function* tfunction);
+  std::string as_camel_case(std::string name, bool ucfirst = true);
+  std::string get_rpc_method_name(std::string name);
+  std::string get_cap_name(std::string name);
+  std::string generate_isset_check(t_field* field);
+  std::string generate_isset_check(std::string field);
+  void generate_isset_set(ostream& out, t_field* field, std::string prefix);
+  std::string isset_field_id(t_field* field);
+
+  void generate_service_interface(t_service* tservice);
+  void generate_service_async_interface(t_service* tservice);
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_client(t_service* tservice);
+  void generate_service_async_client(t_service* tservice);
+  void generate_service_server(t_service* tservice);
+  void generate_service_async_server(t_service* tservice);
+  void generate_process_function(t_service* tservice, t_function* tfunction);
+  void generate_process_async_function(t_service* tservice, t_function* tfunction);
+
+  void generate_java_union(t_struct* tstruct);
+  void generate_union_constructor(ostream& out, t_struct* tstruct);
+  void generate_union_getters_and_setters(ostream& out, t_struct* tstruct);
+  void generate_union_is_set_methods(ostream& out, t_struct* tstruct);
+  void generate_union_abstract_methods(ostream& out, t_struct* tstruct);
+  void generate_check_type(ostream& out, t_struct* tstruct);
+  void generate_standard_scheme_read_value(ostream& out, t_struct* tstruct);
+  void generate_standard_scheme_write_value(ostream& out, t_struct* tstruct);
+  void generate_tuple_scheme_read_value(ostream& out, t_struct* tstruct);
+  void generate_tuple_scheme_write_value(ostream& out, t_struct* tstruct);
+  void generate_get_field_desc(ostream& out, t_struct* tstruct);
+  void generate_get_struct_desc(ostream& out, t_struct* tstruct);
+  void generate_get_field_name(ostream& out, t_struct* tstruct);
+
+  void generate_union_comparisons(ostream& out, t_struct* tstruct);
+  void generate_union_hashcode(ostream& out, t_struct* tstruct);
+
+  void generate_scheme_map(ostream& out, t_struct* tstruct);
+  void generate_standard_writer(ostream& out, t_struct* tstruct, bool is_result);
+  void generate_standard_reader(ostream& out, t_struct* tstruct);
+  void generate_java_struct_standard_scheme(ostream& out, t_struct* tstruct, bool is_result);
+
+  void generate_java_struct_tuple_scheme(ostream& out, t_struct* tstruct);
+  void generate_java_struct_tuple_reader(ostream& out, t_struct* tstruct);
+  void generate_java_struct_tuple_writer(ostream& out, t_struct* tstruct);
+
+  void generate_java_scheme_lookup(ostream& out);
+
+  void generate_javax_generated_annotation(ostream& out);
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field(std::ostream& out,
+                                  t_field* tfield,
+                                  std::string prefix = "",
+                                  bool has_metadata = true);
+
+  void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_deserialize_container(std::ostream& out,
+                                      t_type* ttype,
+                                      std::string prefix = "",
+                                      bool has_metadata = true);
+
+  void generate_deserialize_set_element(std::ostream& out,
+                                        t_set* tset,
+                                        std::string prefix = "",
+                                        std::string obj = "",
+                                        bool has_metadata = true);
+
+  void generate_deserialize_map_element(std::ostream& out,
+                                        t_map* tmap,
+                                        std::string prefix = "",
+                                        std::string obj = "",
+                                        bool has_metadata = true);
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         std::string prefix = "",
+                                         std::string obj = "",
+                                         bool has_metadata = true);
+
+  void generate_serialize_field(std::ostream& out,
+                                t_field* tfield,
+                                std::string prefix = "",
+                                bool has_metadata = true);
+
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(std::ostream& out,
+                                    t_type* ttype,
+                                    std::string prefix = "",
+                                    bool has_metadata = true);
+
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string iter,
+                                      std::string map,
+                                      bool has_metadata = true);
+
+  void generate_serialize_set_element(std::ostream& out,
+                                      t_set* tmap,
+                                      std::string iter,
+                                      bool has_metadata = true);
+
+  void generate_serialize_list_element(std::ostream& out,
+                                       t_list* tlist,
+                                       std::string iter,
+                                       bool has_metadata = true);
+
+  void generate_deep_copy_container(std::ostream& out,
+                                    std::string source_name_p1,
+                                    std::string source_name_p2,
+                                    std::string result_name,
+                                    t_type* type);
+  void generate_deep_copy_non_container(std::ostream& out,
+                                        std::string source_name,
+                                        std::string dest_name,
+                                        t_type* type);
+
+  enum isset_type { ISSET_NONE, ISSET_PRIMITIVE, ISSET_BITSET };
+  isset_type needs_isset(t_struct* tstruct, std::string* outPrimitiveType = NULL);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string java_package();
+  std::string java_suppressions();
+  std::string java_nullable_annotation();
+  std::string type_name(t_type* ttype,
+                        bool in_container = false,
+                        bool in_init = false,
+                        bool skip_generic = false,
+                        bool force_namespace = false);
+  std::string base_type_name(t_base_type* tbase, bool in_container = false);
+  std::string declare_field(t_field* tfield, bool init = false, bool comment = false);
+  std::string function_signature(t_function* tfunction, std::string prefix = "");
+  std::string function_signature_async(t_function* tfunction,
+                                       bool use_base_method = false,
+                                       std::string prefix = "");
+  std::string argument_list(t_struct* tstruct, bool include_types = true);
+  std::string async_function_call_arglist(t_function* tfunc,
+                                          bool use_base_method = true,
+                                          bool include_types = true);
+  std::string async_argument_list(t_function* tfunct,
+                                  t_struct* tstruct,
+                                  t_type* ttype,
+                                  bool include_types = false);
+  std::string type_to_enum(t_type* ttype);
+  void generate_struct_desc(ostream& out, t_struct* tstruct);
+  void generate_field_descs(ostream& out, t_struct* tstruct);
+  void generate_field_name_constants(ostream& out, t_struct* tstruct);
+
+  std::string make_valid_java_filename(std::string const& fromName);
+  std::string make_valid_java_identifier(std::string const& fromName);
+
+  bool type_can_be_null(t_type* ttype) {
+    ttype = get_true_type(ttype);
+
+    return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string()
+           || ttype->is_enum();
+  }
+
+  bool is_deprecated(const std::map<std::string, std::string>& annotations) {
+    return annotations.find("deprecated") != annotations.end();
+  }
+
+  bool is_enum_set(t_type* ttype) {
+    if (!sorted_containers_) {
+      ttype = get_true_type(ttype);
+      if (ttype->is_set()) {
+        t_set* tset = (t_set*)ttype;
+        t_type* elem_type = get_true_type(tset->get_elem_type());
+        return elem_type->is_enum();
+      }
+    }
+    return false;
+  }
+
+  bool is_enum_map(t_type* ttype) {
+    if (!sorted_containers_) {
+      ttype = get_true_type(ttype);
+      if (ttype->is_map()) {
+        t_map* tmap = (t_map*)ttype;
+        t_type* key_type = get_true_type(tmap->get_key_type());
+        return key_type->is_enum();
+      }
+    }
+    return false;
+  }
+
+  std::string inner_enum_type_name(t_type* ttype) {
+    ttype = get_true_type(ttype);
+    if (ttype->is_map()) {
+      t_map* tmap = (t_map*)ttype;
+      t_type* key_type = get_true_type(tmap->get_key_type());
+      return type_name(key_type, true) + ".class";
+    } else if (ttype->is_set()) {
+      t_set* tset = (t_set*)ttype;
+      t_type* elem_type = get_true_type(tset->get_elem_type());
+      return type_name(elem_type, true) + ".class";
+    }
+    return "";
+  }
+
+  std::string constant_name(std::string name);
+
+private:
+  /**
+   * File streams
+   */
+
+  std::string package_name_;
+  ofstream_with_content_based_conditional_update f_service_;
+  std::string package_dir_;
+
+  bool bean_style_;
+  bool android_style_;
+  bool private_members_;
+  bool nocamel_style_;
+  bool fullcamel_style_;
+  bool android_legacy_;
+  bool java5_;
+  bool sorted_containers_;
+  bool reuse_objects_;
+  bool use_option_type_;
+  bool undated_generated_annotations_;
+  bool suppress_generated_annotations_;
+  bool rethrow_unhandled_exceptions_;
+  bool unsafe_binaries_;
+
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_java_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+  package_name_ = program_->get_namespace("java");
+
+  string dir = package_name_;
+  string subdir = get_out_dir();
+  string::size_type loc;
+  while ((loc = dir.find(".")) != string::npos) {
+    subdir = subdir + "/" + dir.substr(0, loc);
+    MKDIR(subdir.c_str());
+    dir = dir.substr(loc + 1);
+  }
+  if (dir.size() > 0) {
+    subdir = subdir + "/" + dir;
+    MKDIR(subdir.c_str());
+  }
+
+  package_dir_ = subdir;
+}
+
+/**
+ * Packages the generated file
+ *
+ * @return String of the package, i.e. "package org.apache.thriftdemo;"
+ */
+string t_java_generator::java_package() {
+  if (!package_name_.empty()) {
+    return string("package ") + package_name_ + ";\n\n";
+  }
+  return "";
+}
+
+string t_java_generator::java_suppressions() {
+  return "@SuppressWarnings({\"cast\", \"rawtypes\", \"serial\", \"unchecked\", \"unused\"})\n";
+}
+
+string t_java_generator::java_nullable_annotation() {
+  return "@org.apache.thrift.annotation.Nullable";
+}
+
+/**
+ * Nothing in Java
+ */
+void t_java_generator::close_generator() {
+}
+
+/**
+ * Generates a typedef. This is not done in Java, since it does
+ * not support arbitrary name replacements, and it'd be a wacky waste
+ * of overhead to make wrapper classes.
+ *
+ * @param ttypedef The type definition
+ */
+void t_java_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+/**
+ * Enums are a class with a set of static constants.
+ *
+ * @param tenum The enumeration
+ */
+void t_java_generator::generate_enum(t_enum* tenum) {
+  bool is_deprecated = this->is_deprecated(tenum->annotations_);
+  // Make output file
+  string f_enum_name = package_dir_ + "/" + make_valid_java_filename(tenum->get_name()) + ".java";
+  ofstream_with_content_based_conditional_update f_enum;
+  f_enum.open(f_enum_name.c_str());
+
+  // Comment and package it
+  f_enum << autogen_comment() << java_package() << endl;
+
+  generate_java_doc(f_enum, tenum);
+
+  if (!suppress_generated_annotations_) {
+    generate_javax_generated_annotation(f_enum);
+  }
+
+  if (is_deprecated) {
+    indent(f_enum) << "@Deprecated" << endl;
+  }
+  indent(f_enum) << "public enum " << tenum->get_name() << " implements org.apache.thrift.TEnum ";
+  scope_up(f_enum);
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  bool first = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+
+    if (first) {
+      first = false;
+    } else {
+      f_enum << "," << endl;
+    }
+
+    generate_java_doc(f_enum, *c_iter);
+    if (this->is_deprecated((*c_iter)->annotations_)) {
+      indent(f_enum) << "@Deprecated" << endl;
+    }
+    indent(f_enum) << (*c_iter)->get_name() << "(" << value << ")";
+  }
+  f_enum << ";" << endl << endl;
+
+  // Field for thriftCode
+  indent(f_enum) << "private final int value;" << endl << endl;
+
+  indent(f_enum) << "private " << tenum->get_name() << "(int value) {" << endl;
+  indent(f_enum) << "  this.value = value;" << endl;
+  indent(f_enum) << "}" << endl << endl;
+
+  indent(f_enum) << "/**" << endl;
+  indent(f_enum) << " * Get the integer value of this enum value, as defined in the Thrift IDL."
+                 << endl;
+  indent(f_enum) << " */" << endl;
+  indent(f_enum) << "public int getValue() {" << endl;
+  indent(f_enum) << "  return value;" << endl;
+  indent(f_enum) << "}" << endl << endl;
+
+  indent(f_enum) << "/**" << endl;
+  indent(f_enum) << " * Find a the enum type by its integer value, as defined in the Thrift IDL."
+                 << endl;
+  indent(f_enum) << " * @return null if the value is not found." << endl;
+  indent(f_enum) << " */" << endl;
+  indent(f_enum) << java_nullable_annotation() << endl;
+  indent(f_enum) << "public static " + tenum->get_name() + " findByValue(int value) { " << endl;
+
+  indent_up();
+
+  indent(f_enum) << "switch (value) {" << endl;
+  indent_up();
+
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    indent(f_enum) << "case " << value << ":" << endl;
+    indent(f_enum) << "  return " << (*c_iter)->get_name() << ";" << endl;
+  }
+
+  indent(f_enum) << "default:" << endl;
+  indent(f_enum) << "  return null;" << endl;
+
+  indent_down();
+
+  indent(f_enum) << "}" << endl;
+
+  indent_down();
+
+  indent(f_enum) << "}" << endl;
+
+  scope_down(f_enum);
+
+  f_enum.close();
+}
+
+/**
+ * Generates a class that holds all the constants.
+ */
+void t_java_generator::generate_consts(std::vector<t_const*> consts) {
+  if (consts.empty()) {
+    return;
+  }
+
+  string f_consts_name = package_dir_ + '/' + make_valid_java_filename(program_name_)
+                         + "Constants.java";
+  ofstream_with_content_based_conditional_update f_consts;
+  f_consts.open(f_consts_name.c_str());
+
+  // Print header
+  f_consts << autogen_comment() << java_package() << java_suppressions();
+
+  f_consts << "public class " << make_valid_java_identifier(program_name_) << "Constants {" << endl
+           << endl;
+  indent_up();
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    generate_java_doc(f_consts, (*c_iter));
+    print_const_value(f_consts,
+                      (*c_iter)->get_name(),
+                      (*c_iter)->get_type(),
+                      (*c_iter)->get_value(),
+                      false);
+  }
+  indent_down();
+  indent(f_consts) << "}" << endl;
+  f_consts.close();
+}
+
+
+/**
+ * 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
+ */
+void t_java_generator::print_const_value(std::ostream& out,
+                                         string name,
+                                         t_type* type,
+                                         t_const_value* value,
+                                         bool in_static,
+                                         bool defval) {
+  type = get_true_type(type);
+
+  indent(out);
+  if (!defval) {
+    out << (in_static ? "" : "public static final ") << type_name(type) << " ";
+  }
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, type, value);
+    out << name << " = " << v2 << ";" << endl << endl;
+  } else if (type->is_enum()) {
+    out << name << " = " << render_const_value(out, type, value) << ";" << endl << endl;
+  } else if (type->is_struct() || type->is_xception()) {
+    const vector<t_field*>& unsorted_fields = ((t_struct*)type)->get_members();
+    vector<t_field*> fields = unsorted_fields;
+    std::sort(fields.begin(), fields.end(), t_field::key_compare());
+    vector<t_field*>::const_iterator f_iter;
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    out << name << " = new " << type_name(type, false, true) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "static {" << endl;
+      indent_up();
+    }
+    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();
+      }
+      string val = render_const_value(out, field_type, v_iter->second);
+      indent(out) << name << ".";
+      std::string cap_name = get_cap_name(v_iter->first->get_string());
+      out << "set" << cap_name << "(" << val << ");" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else if (type->is_map()) {
+    std::string constructor_args;
+    if (is_enum_map(type)) {
+      constructor_args = inner_enum_type_name(type);
+    }
+    out << name << " = new " << type_name(type, false, true) << "(" << constructor_args << ");" << endl;
+    if (!in_static) {
+      indent(out) << "static {" << endl;
+      indent_up();
+    }
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, ktype, v_iter->first);
+      string val = render_const_value(out, vtype, v_iter->second);
+      indent(out) << name << ".put(" << key << ", " << val << ");" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else if (type->is_list() || type->is_set()) {
+    if (is_enum_set(type)) {
+      out << name << " = " << type_name(type, false, true, true) << ".noneOf(" << inner_enum_type_name(type) << ");" << endl;
+    } else {
+      out << name << " = new " << type_name(type, false, true) << "();" << endl;
+    }
+    if (!in_static) {
+      indent(out) << "static {" << endl;
+      indent_up();
+    }
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(out, etype, *v_iter);
+      indent(out) << name << ".add(" << val << ");" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else {
+    throw "compiler error: no const of type " + type->get_name();
+  }
+}
+
+string t_java_generator::render_const_value(ostream& out, t_type* type, t_const_value* value) {
+  type = get_true_type(type);
+  std::ostringstream render;
+
+  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:
+      render << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "true" : "false");
+      break;
+    case t_base_type::TYPE_I8:
+      render << "(byte)" << value->get_integer();
+      break;
+    case t_base_type::TYPE_I16:
+      render << "(short)" << value->get_integer();
+      break;
+    case t_base_type::TYPE_I32:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_I64:
+      render << value->get_integer() << "L";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << value->get_integer() << "d";
+      } else {
+        render << emit_double_as_string(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()) {
+    std::string namespace_prefix = type->get_program()->get_namespace("java");
+    if (namespace_prefix.length() > 0) {
+      namespace_prefix += ".";
+    }
+    render << namespace_prefix << value->get_identifier_with_parent();
+  } else {
+    string t = tmp("tmp");
+    print_const_value(out, t, type, value, true);
+    render << t;
+  }
+
+  return render.str();
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This will be a org.apache.thrift.TBase
+ * implementor.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_struct(t_struct* tstruct) {
+  if (tstruct->is_union()) {
+    generate_java_union(tstruct);
+  } else {
+    generate_java_struct(tstruct, false);
+  }
+}
+
+/**
+ * Exceptions are structs, but they inherit from Exception
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_xception(t_struct* txception) {
+  generate_java_struct(txception, true);
+}
+
+/**
+ * Java struct definition.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_struct(t_struct* tstruct, bool is_exception) {
+  // Make output file
+  string f_struct_name = package_dir_ + "/" + make_valid_java_filename(tstruct->get_name())
+                         + ".java";
+  ofstream_with_content_based_conditional_update f_struct;
+  f_struct.open(f_struct_name.c_str());
+
+  f_struct << autogen_comment() << java_package() << java_suppressions();
+
+  generate_java_struct_definition(f_struct, tstruct, is_exception);
+  f_struct.close();
+}
+
+/**
+ * Java union definition.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_union(t_struct* tstruct) {
+  // Make output file
+  string f_struct_name = package_dir_ + "/" + make_valid_java_filename(tstruct->get_name())
+                         + ".java";
+  ofstream_with_content_based_conditional_update f_struct;
+  f_struct.open(f_struct_name.c_str());
+
+  f_struct << autogen_comment() << java_package() << java_suppressions();
+
+  generate_java_doc(f_struct, tstruct);
+
+  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+  bool is_deprecated = this->is_deprecated(tstruct->annotations_);
+
+  if (!suppress_generated_annotations_) {
+    generate_javax_generated_annotation(f_struct);
+  }
+
+  if (is_deprecated) {
+    indent(f_struct) << "@Deprecated" << endl;
+  }
+  indent(f_struct) << "public " << (is_final ? "final " : "") << "class " << tstruct->get_name()
+                   << " extends org.apache.thrift.TUnion<" << tstruct->get_name() << ", "
+                   << tstruct->get_name() << "._Fields> ";
+
+  scope_up(f_struct);
+
+  generate_struct_desc(f_struct, tstruct);
+  generate_field_descs(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_field_name_constants(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_java_meta_data_map(f_struct, tstruct);
+
+  generate_union_constructor(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_union_abstract_methods(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_java_struct_field_by_id(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_union_getters_and_setters(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_union_is_set_methods(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_union_comparisons(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_union_hashcode(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_java_struct_write_object(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_java_struct_read_object(f_struct, tstruct);
+
+  f_struct << endl;
+
+  scope_down(f_struct);
+
+  f_struct.close();
+}
+
+void t_java_generator::generate_union_constructor(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  indent(out) << "public " << type_name(tstruct) << "() {" << endl;
+  indent_up();
+  bool default_value = false;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* type = get_true_type((*m_iter)->get_type());
+    if ((*m_iter)->get_value() != NULL) {
+      indent(out) << "super(_Fields." << constant_name((*m_iter)->get_name()) << ", "
+                  << render_const_value(out, type, (*m_iter)->get_value()) << ");" << endl;
+      default_value = true;
+      break;
+    }
+  }
+  if (default_value == false) {
+    indent(out) << "super();" << endl;
+  }
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  indent(out) << "public " << type_name(tstruct) << "(_Fields setField, java.lang.Object value) {" << endl;
+  indent(out) << "  super(setField, value);" << endl;
+  indent(out) << "}" << endl << endl;
+
+  indent(out) << "public " << type_name(tstruct) << "(" << type_name(tstruct) << " other) {"
+              << endl;
+  indent(out) << "  super(other);" << endl;
+  indent(out) << "}" << endl;
+
+  indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl;
+  indent(out) << "  return new " << tstruct->get_name() << "(this);" << endl;
+  indent(out) << "}" << endl << endl;
+
+  // generate "constructors" for each field
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* type = (*m_iter)->get_type();
+    indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() << "("
+                << type_name(type) << " value) {" << endl;
+    indent(out) << "  " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" << endl;
+    indent(out) << "  x.set" << get_cap_name((*m_iter)->get_name()) << "(value);" << endl;
+    indent(out) << "  return x;" << endl;
+    indent(out) << "}" << endl << endl;
+
+    if (type->is_binary()) {
+      indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name()
+                  << "(byte[] value) {" << endl;
+      indent(out) << "  " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();"
+                  << endl;
+      indent(out) << "  x.set" << get_cap_name((*m_iter)->get_name());
+      if(unsafe_binaries_) {
+        indent(out) << "(java.nio.ByteBuffer.wrap(value));" << endl;
+      }else{
+        indent(out) << "(java.nio.ByteBuffer.wrap(value.clone()));" << endl;
+      }
+      indent(out) << "  return x;" << endl;
+      indent(out) << "}" << endl << endl;
+    }
+  }
+}
+
+void t_java_generator::generate_union_getters_and_setters(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  bool first = true;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if (first) {
+      first = false;
+    } else {
+      out << endl;
+    }
+
+    t_field* field = (*m_iter);
+    t_type* type = field->get_type();
+    std::string cap_name = get_cap_name(field->get_name());
+    bool is_deprecated = this->is_deprecated(field->annotations_);
+
+    generate_java_doc(out, field);
+    if (type->is_binary()) {
+      if (is_deprecated) {
+        indent(out) << "@Deprecated" << endl;
+      }
+      indent(out) << "public byte[] get" << cap_name << "() {" << endl;
+      indent(out) << "  set" << cap_name << "(org.apache.thrift.TBaseHelper.rightSize(buffer"
+                  << get_cap_name("for") << cap_name << "()));" << endl;
+      indent(out) << "  java.nio.ByteBuffer b = buffer" << get_cap_name("for") << cap_name << "();" << endl;
+      indent(out) << "  return b == null ? null : b.array();" << endl;
+      indent(out) << "}" << endl;
+
+      out << endl;
+
+      indent(out) << "public java.nio.ByteBuffer buffer" << get_cap_name("for")
+                  << get_cap_name(field->get_name()) << "() {" << endl;
+      indent(out) << "  if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {"
+                  << endl;
+
+      if(unsafe_binaries_){
+        indent(out)
+          << "    return (java.nio.ByteBuffer)getFieldValue();"
+          << endl;
+      }else{
+        indent(out)
+          << "    return org.apache.thrift.TBaseHelper.copyBinary((java.nio.ByteBuffer)getFieldValue());"
+          << endl;
+      }
+
+      indent(out) << "  } else {" << endl;
+      indent(out) << "    throw new java.lang.RuntimeException(\"Cannot get field '" << field->get_name()
+                  << "' because union is currently set to \" + getFieldDesc(getSetField()).name);"
+                  << endl;
+      indent(out) << "  }" << endl;
+      indent(out) << "}" << endl;
+    } else {
+      if (is_deprecated) {
+        indent(out) << "@Deprecated" << endl;
+      }
+      indent(out) << "public " << type_name(field->get_type()) << " get"
+                  << get_cap_name(field->get_name()) << "() {" << endl;
+      indent(out) << "  if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {"
+                  << endl;
+      indent(out) << "    return (" << type_name(field->get_type(), true) << ")getFieldValue();"
+                  << endl;
+      indent(out) << "  } else {" << endl;
+      indent(out) << "    throw new java.lang.RuntimeException(\"Cannot get field '" << field->get_name()
+                  << "' because union is currently set to \" + getFieldDesc(getSetField()).name);"
+                  << endl;
+      indent(out) << "  }" << endl;
+      indent(out) << "}" << endl;
+    }
+
+    out << endl;
+
+    generate_java_doc(out, field);
+    if (type->is_binary()) {
+      if (is_deprecated) {
+        indent(out) << "@Deprecated" << endl;
+      }
+      indent(out) << "public void set" << get_cap_name(field->get_name()) << "(byte[] value) {"
+                  << endl;
+      indent(out) << "  set" << get_cap_name(field->get_name());
+
+      if(unsafe_binaries_){
+        indent(out) << "(java.nio.ByteBuffer.wrap(value));" << endl;
+      }else{
+        indent(out) << "(java.nio.ByteBuffer.wrap(value.clone()));" << endl;
+      }
+
+      indent(out) << "}" << endl;
+
+      out << endl;
+    }
+    if (is_deprecated) {
+      indent(out) << "@Deprecated" << endl;
+    }
+    indent(out) << "public void set" << get_cap_name(field->get_name()) << "("
+                << type_name(field->get_type()) << " value) {" << endl;
+    if (type_can_be_null(field->get_type())) {
+      indent(out) << "  if (value == null) throw new java.lang.NullPointerException();" << endl;
+    }
+    indent(out) << "  setField_ = _Fields." << constant_name(field->get_name()) << ";" << endl;
+    indent(out) << "  value_ = value;" << endl;
+    indent(out) << "}" << endl;
+  }
+}
+
+void t_java_generator::generate_union_is_set_methods(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  bool first = true;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if (first) {
+      first = false;
+    } else {
+      out << endl;
+    }
+
+    std::string field_name = (*m_iter)->get_name();
+
+    indent(out) << "public boolean is" << get_cap_name("set") << get_cap_name(field_name) << "() {"
+                << endl;
+    indent_up();
+    indent(out) << "return setField_ == _Fields." << constant_name(field_name) << ";" << endl;
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+}
+
+void t_java_generator::generate_union_abstract_methods(ostream& out, t_struct* tstruct) {
+  generate_check_type(out, tstruct);
+  out << endl;
+  generate_standard_scheme_read_value(out, tstruct);
+  out << endl;
+  generate_standard_scheme_write_value(out, tstruct);
+  out << endl;
+  generate_tuple_scheme_read_value(out, tstruct);
+  out << endl;
+  generate_tuple_scheme_write_value(out, tstruct);
+  out << endl;
+  generate_get_field_desc(out, tstruct);
+  out << endl;
+  generate_get_struct_desc(out, tstruct);
+  out << endl;
+  indent(out) << "@Override" << endl;
+  indent(out) << "protected _Fields enumForId(short id) {" << endl;
+  indent(out) << "  return _Fields.findByThriftIdOrThrow(id);" << endl;
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_check_type(ostream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out)
+      << "protected void checkType(_Fields setField, java.lang.Object value) throws java.lang.ClassCastException {"
+      << endl;
+  indent_up();
+
+  indent(out) << "switch (setField) {" << endl;
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+
+    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
+    indent(out) << "  if (value instanceof " << type_name(field->get_type(), true, false, true)
+                << ") {" << endl;
+    indent(out) << "    break;" << endl;
+    indent(out) << "  }" << endl;
+    indent(out) << "  throw new java.lang.ClassCastException(\"Was expecting value of type "
+                << type_name(field->get_type(), true, false) << " for field '" << field->get_name()
+                << "', but got \" + value.getClass().getSimpleName());" << endl;
+    // do the real check here
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new java.lang.IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_standard_scheme_read_value(ostream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out) << "protected java.lang.Object standardSchemeReadValue(org.apache.thrift.protocol.TProtocol "
+                 "iprot, org.apache.thrift.protocol.TField field) throws "
+                 "org.apache.thrift.TException {" << endl;
+
+  indent_up();
+
+  indent(out) << "_Fields setField = _Fields.findByThriftId(field.id);" << endl;
+  indent(out) << "if (setField != null) {" << endl;
+  indent_up();
+  indent(out) << "switch (setField) {" << endl;
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+
+    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
+    indent_up();
+    indent(out) << "if (field.type == " << constant_name(field->get_name()) << "_FIELD_DESC.type) {"
+                << endl;
+    indent_up();
+    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";"
+                << endl;
+    generate_deserialize_field(out, field, "");
+    indent(out) << "return " << field->get_name() << ";" << endl;
+    indent_down();
+    indent(out) << "} else {" << endl;
+    indent(out) << "  org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);" << endl;
+    indent(out) << "  return null;" << endl;
+    indent(out) << "}" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new java.lang.IllegalStateException(\"setField wasn't null, but didn't match any "
+                 "of the case statements!\");" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "} else {" << endl;
+  indent_up();
+  indent(out) << "org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);" << endl;
+  indent(out) << "return null;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_standard_scheme_write_value(ostream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out) << "protected void standardSchemeWriteValue(org.apache.thrift.protocol.TProtocol "
+                 "oprot) throws org.apache.thrift.TException {" << endl;
+
+  indent_up();
+
+  indent(out) << "switch (setField_) {" << endl;
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+
+    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
+    indent_up();
+    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << " = ("
+                << type_name(field->get_type(), true, false) << ")value_;" << endl;
+    generate_serialize_field(out, field, "");
+    indent(out) << "return;" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new java.lang.IllegalStateException(\"Cannot write union with unknown field \" + "
+                 "setField_);" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_tuple_scheme_read_value(ostream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out) << "protected java.lang.Object tupleSchemeReadValue(org.apache.thrift.protocol.TProtocol "
+                 "iprot, short fieldID) throws org.apache.thrift.TException {" << endl;
+
+  indent_up();
+
+  indent(out) << "_Fields setField = _Fields.findByThriftId(fieldID);" << endl;
+  indent(out) << "if (setField != null) {" << endl;
+  indent_up();
+  indent(out) << "switch (setField) {" << endl;
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+
+    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
+    indent_up();
+    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";"
+                << endl;
+    generate_deserialize_field(out, field, "");
+    indent(out) << "return " << field->get_name() << ";" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new java.lang.IllegalStateException(\"setField wasn't null, but didn't match any "
+                 "of the case statements!\");" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "} else {" << endl;
+  indent_up();
+  indent(out) << "throw new org.apache.thrift.protocol.TProtocolException(\"Couldn't find a field with field id \" + fieldID);"
+              << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_tuple_scheme_write_value(ostream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out) << "protected void tupleSchemeWriteValue(org.apache.thrift.protocol.TProtocol oprot) "
+                 "throws org.apache.thrift.TException {" << endl;
+
+  indent_up();
+
+  indent(out) << "switch (setField_) {" << endl;
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+
+    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
+    indent_up();
+    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << " = ("
+                << type_name(field->get_type(), true, false) << ")value_;" << endl;
+    generate_serialize_field(out, field, "");
+    indent(out) << "return;" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new java.lang.IllegalStateException(\"Cannot write union with unknown field \" + "
+                 "setField_);" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_get_field_desc(ostream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out) << "protected org.apache.thrift.protocol.TField getFieldDesc(_Fields setField) {"
+              << endl;
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  indent(out) << "switch (setField) {" << endl;
+  indent_up();
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
+    indent(out) << "  return " << constant_name(field->get_name()) << "_FIELD_DESC;" << endl;
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new java.lang.IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_get_struct_desc(ostream& out, t_struct* tstruct) {
+  (void)tstruct;
+  indent(out) << "@Override" << endl;
+  indent(out) << "protected org.apache.thrift.protocol.TStruct getStructDesc() {" << endl;
+  indent(out) << "  return STRUCT_DESC;" << endl;
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_union_comparisons(ostream& out, t_struct* tstruct) {
+  // equality
+  indent(out) << "public boolean equals(java.lang.Object other) {" << endl;
+  indent(out) << "  if (other instanceof " << tstruct->get_name() << ") {" << endl;
+  indent(out) << "    return equals((" << tstruct->get_name() << ")other);" << endl;
+  indent(out) << "  } else {" << endl;
+  indent(out) << "    return false;" << endl;
+  indent(out) << "  }" << endl;
+  indent(out) << "}" << endl;
+
+  out << endl;
+
+  indent(out) << "public boolean equals(" << tstruct->get_name() << " other) {" << endl;
+  indent(out) << "  return other != null && getSetField() == other.getSetField() && "
+                 "getFieldValue().equals(other.getFieldValue());" << endl;
+  indent(out) << "}" << endl;
+  out << endl;
+
+  indent(out) << "@Override" << endl;
+  indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl;
+  indent(out) << "  int lastComparison = org.apache.thrift.TBaseHelper.compareTo(getSetField(), "
+                 "other.getSetField());" << endl;
+  indent(out) << "  if (lastComparison == 0) {" << endl;
+  indent(out) << "    return org.apache.thrift.TBaseHelper.compareTo(getFieldValue(), "
+                 "other.getFieldValue());" << endl;
+  indent(out) << "  }" << endl;
+  indent(out) << "  return lastComparison;" << endl;
+  indent(out) << "}" << endl;
+  out << endl;
+}
+
+void t_java_generator::generate_union_hashcode(ostream& out, t_struct* tstruct) {
+  (void)tstruct;
+  indent(out) << "@Override" << endl;
+  indent(out) << "public int hashCode() {" << endl;
+  indent(out) << "  java.util.List<java.lang.Object> list = new java.util.ArrayList<java.lang.Object>();" << endl;
+  indent(out) << "  list.add(this.getClass().getName());" << endl;
+  indent(out) << "  org.apache.thrift.TFieldIdEnum setField = getSetField();" << endl;
+  indent(out) << "  if (setField != null) {" << endl;
+  indent(out) << "    list.add(setField.getThriftFieldId());" << endl;
+  indent(out) << "    java.lang.Object value = getFieldValue();" << endl;
+  indent(out) << "    if (value instanceof org.apache.thrift.TEnum) {" << endl;
+  indent(out) << "      list.add(((org.apache.thrift.TEnum)getFieldValue()).getValue());" << endl;
+  indent(out) << "    } else {" << endl;
+  indent(out) << "      list.add(value);" << endl;
+  indent(out) << "    }" << endl;
+  indent(out) << "  }" << endl;
+  indent(out) << "  return list.hashCode();" << endl;
+  indent(out) << "}";
+}
+
+/**
+ * Java struct definition. This has various parameters, as it could be
+ * generated standalone or inside another class as a helper. If it
+ * is a helper than it is a static class.
+ *
+ * @param tstruct      The struct definition
+ * @param is_exception Is this an exception?
+ * @param in_class     If inside a class, needs to be static class
+ * @param is_result    If this is a result it needs a different writer
+ */
+void t_java_generator::generate_java_struct_definition(ostream& out,
+                                                       t_struct* tstruct,
+                                                       bool is_exception,
+                                                       bool in_class,
+                                                       bool is_result) {
+  generate_java_doc(out, tstruct);
+
+  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+  bool is_deprecated = this->is_deprecated(tstruct->annotations_);
+
+  if (!in_class && !suppress_generated_annotations_) {
+    generate_javax_generated_annotation(out);
+  }
+
+  if (is_deprecated) {
+    indent(out) << "@Deprecated" << endl;
+  }
+  indent(out) << "public " << (is_final ? "final " : "") << (in_class ? "static " : "") << "class "
+              << tstruct->get_name() << " ";
+
+  if (is_exception) {
+    out << "extends org.apache.thrift.TException ";
+  }
+  out << "implements org.apache.thrift.TBase<" << tstruct->get_name() << ", " << tstruct->get_name()
+      << "._Fields>, java.io.Serializable, Cloneable, Comparable<" << tstruct->get_name() << ">";
+
+  if (android_style_) {
+    out << ", android.os.Parcelable";
+  }
+
+  out << " ";
+
+  scope_up(out);
+
+  generate_struct_desc(out, tstruct);
+
+  // Members are public for -java, private for -javabean
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  out << endl;
+
+  generate_field_descs(out, tstruct);
+
+  out << endl;
+
+  generate_scheme_map(out, tstruct);
+
+  out << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if (bean_style_ || private_members_) {
+      indent(out) << "private ";
+    } else {
+      generate_java_doc(out, *m_iter);
+      indent(out) << "public ";
+    }
+    out << declare_field(*m_iter, false, true) << endl;
+  }
+
+  out << endl;
+
+  if (android_style_) {
+    generate_java_struct_parcelable(out, tstruct);
+  }
+
+  generate_field_name_constants(out, tstruct);
+
+  // isset data
+  if (members.size() > 0) {
+    out << endl;
+
+    indent(out) << "// isset id assignments" << endl;
+
+    int i = 0;
+    int optionals = 0;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if ((*m_iter)->get_req() == t_field::T_OPTIONAL) {
+        optionals++;
+      }
+      if (!type_can_be_null((*m_iter)->get_type())) {
+        indent(out) << "private static final int " << isset_field_id(*m_iter) << " = " << i << ";"
+                    << endl;
+        i++;
+      }
+    }
+
+    std::string primitiveType;
+    switch (needs_isset(tstruct, &primitiveType)) {
+    case ISSET_NONE:
+      break;
+    case ISSET_PRIMITIVE:
+      indent(out) << "private " << primitiveType << " __isset_bitfield = 0;" << endl;
+      break;
+    case ISSET_BITSET:
+      indent(out) << "private java.util.BitSet __isset_bit_vector = new java.util.BitSet(" << i << ");" << endl;
+      break;
+    }
+
+    if (optionals > 0) {
+      std::string output_string = "private static final _Fields optionals[] = {";
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        if ((*m_iter)->get_req() == t_field::T_OPTIONAL) {
+          output_string = output_string + "_Fields." + constant_name((*m_iter)->get_name()) + ",";
+        }
+      }
+      indent(out) << output_string.substr(0, output_string.length() - 1) << "};" << endl;
+    }
+  }
+
+  generate_java_meta_data_map(out, tstruct);
+
+  bool all_optional_members = true;
+
+  // Default constructor
+  indent(out) << "public " << tstruct->get_name() << "() {" << endl;
+  indent_up();
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    if ((*m_iter)->get_value() != NULL) {
+      print_const_value(out,
+                        "this." + (*m_iter)->get_name(),
+                        t,
+                        (*m_iter)->get_value(),
+                        true,
+                        true);
+    }
+    if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
+      all_optional_members = false;
+    }
+  }
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  if (!members.empty() && !all_optional_members) {
+    // Full constructor for all fields
+    indent(out) << "public " << tstruct->get_name() << "(" << endl;
+    indent_up();
+    bool first = true;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
+        if (!first) {
+          out << "," << endl;
+        }
+        first = false;
+        indent(out) << type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name();
+      }
+    }
+    out << ")" << endl;
+    indent_down();
+    indent(out) << "{" << endl;
+    indent_up();
+    indent(out) << "this();" << endl;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
+        t_type* type = get_true_type((*m_iter)->get_type());
+        if (type->is_binary()) {
+          if(unsafe_binaries_){
+            indent(out) << "this." << (*m_iter)->get_name()
+                        << " = " << (*m_iter)->get_name()
+                        << ";" << endl;
+          }else{
+            indent(out) << "this." << (*m_iter)->get_name()
+                        << " = org.apache.thrift.TBaseHelper.copyBinary(" << (*m_iter)->get_name()
+                        << ");" << endl;
+          }
+        } else {
+          indent(out) << "this." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << ";"
+                      << endl;
+        }
+        generate_isset_set(out, (*m_iter), "");
+      }
+    }
+
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+
+  // copy constructor
+  indent(out) << "/**" << endl;
+  indent(out) << " * Performs a deep copy on <i>other</i>." << endl;
+  indent(out) << " */" << endl;
+  indent(out) << "public " << tstruct->get_name() << "(" << tstruct->get_name() << " other) {"
+              << endl;
+  indent_up();
+
+  switch (needs_isset(tstruct)) {
+  case ISSET_NONE:
+    break;
+  case ISSET_PRIMITIVE:
+    indent(out) << "__isset_bitfield = other.__isset_bitfield;" << endl;
+    break;
+  case ISSET_BITSET:
+    indent(out) << "__isset_bit_vector.clear();" << endl;
+    indent(out) << "__isset_bit_vector.or(other.__isset_bit_vector);" << endl;
+    break;
+  }
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+    std::string field_name = field->get_name();
+    t_type* type = field->get_type()->get_true_type();
+    bool can_be_null = type_can_be_null(type);
+
+    if (can_be_null) {
+      indent(out) << "if (other." << generate_isset_check(field) << ") {" << endl;
+      indent_up();
+    }
+
+    if (type->is_container()) {
+      generate_deep_copy_container(out, "other", field_name, "__this__" + field_name, type);
+      indent(out) << "this." << field_name << " = __this__" << field_name << ";" << endl;
+    } else {
+      indent(out) << "this." << field_name << " = ";
+      generate_deep_copy_non_container(out, "other." + field_name, field_name, type);
+      out << ";" << endl;
+    }
+
+    if (can_be_null) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  // clone method, so that you can deep copy an object when you don't know its class.
+  indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl;
+  indent(out) << "  return new " << tstruct->get_name() << "(this);" << endl;
+  indent(out) << "}" << endl << endl;
+
+  generate_java_struct_clear(out, tstruct);
+
+  generate_java_bean_boilerplate(out, tstruct);
+  generate_generic_field_getters_setters(out, tstruct);
+  generate_generic_isset_method(out, tstruct);
+
+  generate_java_struct_equality(out, tstruct);
+  generate_java_struct_compare_to(out, tstruct);
+  generate_java_struct_field_by_id(out, tstruct);
+
+  generate_java_struct_reader(out, tstruct);
+  if (is_result) {
+    generate_java_struct_result_writer(out, tstruct);
+  } else {
+    generate_java_struct_writer(out, tstruct);
+  }
+  generate_java_struct_tostring(out, tstruct);
+  generate_java_validator(out, tstruct);
+
+  generate_java_struct_write_object(out, tstruct);
+  generate_java_struct_read_object(out, tstruct);
+
+  generate_java_struct_standard_scheme(out, tstruct, is_result);
+  generate_java_struct_tuple_scheme(out, tstruct);
+  generate_java_scheme_lookup(out);
+
+  scope_down(out);
+  out << endl;
+}
+
+/**
+ * generates parcelable interface implementation
+ */
+void t_java_generator::generate_java_struct_parcelable(ostream& out, t_struct* tstruct) {
+  string tname = tstruct->get_name();
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  out << indent() << "@Override" << endl << indent()
+      << "public void writeToParcel(android.os.Parcel out, int flags) {" << endl;
+  indent_up();
+  string bitsetPrimitiveType = "";
+  switch (needs_isset(tstruct, &bitsetPrimitiveType)) {
+  case ISSET_NONE:
+    break;
+  case ISSET_PRIMITIVE:
+    indent(out) << "//primitive bitfield of type: " << bitsetPrimitiveType << endl;
+    if (bitsetPrimitiveType == "byte") {
+      indent(out) << "out.writeByte(__isset_bitfield);" << endl;
+    } else if (bitsetPrimitiveType == "short") {
+      indent(out) << "out.writeInt(new Short(__isset_bitfield).intValue());" << endl;
+    } else if (bitsetPrimitiveType == "int") {
+      indent(out) << "out.writeInt(__isset_bitfield);" << endl;
+    } else if (bitsetPrimitiveType == "long") {
+      indent(out) << "out.writeLong(__isset_bitfield);" << endl;
+    }
+    out << endl;
+    break;
+  case ISSET_BITSET:
+    indent(out) << "//BitSet" << endl;
+    indent(out) << "out.writeSerializable(__isset_bit_vector);" << endl;
+    out << endl;
+    break;
+  }
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    string name = (*m_iter)->get_name();
+
+    if (t->is_struct()) {
+      indent(out) << "out.writeParcelable(" << name << ", flags);" << endl;
+    } else if (type_name(t) == "float") {
+      indent(out) << "out.writeFloat(" << name << ");" << endl;
+    } else if (t->is_enum()) {
+      indent(out) << "out.writeInt(" << name << " != null ? " << name << ".getValue() : -1);" << endl;
+    } else if (t->is_list()) {
+      if (((t_list*)t)->get_elem_type()->get_true_type()->is_struct()) {
+        indent(out) << "out.writeTypedList(" << name << ");" << endl;
+      } else {
+        indent(out) << "out.writeList(" << name << ");" << endl;
+      }
+    } else if (t->is_map()) {
+      indent(out) << "out.writeMap(" << name << ");" << endl;
+    } else if (t->is_base_type()) {
+      if (t->is_binary()) {
+        indent(out) << "out.writeInt(" << name << "!=null ? 1 : 0);" << endl;
+        indent(out) << "if(" << name << " != null) { " << endl;
+        indent_up();
+        indent(out) << "out.writeByteArray(" << name << ".array(), " << name << ".position() + "
+                    << name << ".arrayOffset(), " << name << ".limit() - " << name
+                    << ".position() );" << endl;
+        scope_down(out);
+      } else {
+        switch (((t_base_type*)t)->get_base()) {
+        case t_base_type::TYPE_I16:
+          indent(out) << "out.writeInt(new Short(" << name << ").intValue());" << endl;
+          break;
+        case t_base_type::TYPE_I32:
+          indent(out) << "out.writeInt(" << name << ");" << endl;
+          break;
+        case t_base_type::TYPE_I64:
+          indent(out) << "out.writeLong(" << name << ");" << endl;
+          break;
+        case t_base_type::TYPE_BOOL:
+          indent(out) << "out.writeInt(" << name << " ? 1 : 0);" << endl;
+          break;
+        case t_base_type::TYPE_I8:
+          indent(out) << "out.writeByte(" << name << ");" << endl;
+          break;
+        case t_base_type::TYPE_DOUBLE:
+          indent(out) << "out.writeDouble(" << name << ");" << endl;
+          break;
+        case t_base_type::TYPE_STRING:
+          indent(out) << "out.writeString(" << name << ");" << endl;
+          break;
+        case t_base_type::TYPE_VOID:
+          break;
+        }
+      }
+    }
+  }
+  scope_down(out);
+  out << endl;
+
+  out << indent() << "@Override" << endl << indent() << "public int describeContents() {" << endl;
+  indent_up();
+  out << indent() << "return 0;" << endl;
+  scope_down(out);
+  out << endl;
+
+  indent(out) << "public " << tname << "(android.os.Parcel in) {" << endl;
+  indent_up();
+  // read in the required bitfield
+  switch (needs_isset(tstruct, &bitsetPrimitiveType)) {
+  case ISSET_NONE:
+    break;
+  case ISSET_PRIMITIVE:
+    indent(out) << "//primitive bitfield of type: " << bitsetPrimitiveType << endl;
+    if (bitsetPrimitiveType == "byte") {
+      indent(out) << "__isset_bitfield = in.readByte();" << endl;
+    } else if (bitsetPrimitiveType == "short") {
+      indent(out) << "__isset_bitfield = (short) in.readInt();" << endl;
+    } else if (bitsetPrimitiveType == "int") {
+      indent(out) << "__isset_bitfield = in.readInt();" << endl;
+    } else if (bitsetPrimitiveType == "long") {
+      indent(out) << "__isset_bitfield = in.readLong();" << endl;
+    }
+    out << endl;
+    break;
+  case ISSET_BITSET:
+    indent(out) << "//BitSet" << endl;
+    indent(out) << "__isset_bit_vector = (java.util.BitSet) in.readSerializable();" << endl;
+    out << endl;
+    break;
+  }
+  // read all the fields
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    string name = (*m_iter)->get_name();
+    string prefix = "this." + name;
+
+    if (t->is_struct()) {
+      indent(out) << prefix << "= in.readParcelable(" << tname << ".class.getClassLoader());"
+                  << endl;
+    } else if (t->is_enum()) {
+      indent(out) << prefix << " = " << type_name(t) << ".findByValue(in.readInt());" << endl;
+    } else if (t->is_list()) {
+      t_list* list = (t_list*)t;
+      indent(out) << prefix << " = new " << type_name(t, false, true) << "();" << endl;
+      if (list->get_elem_type()->get_true_type()->is_struct()) {
+        indent(out) << "in.readTypedList(" << prefix << ", " << type_name(list->get_elem_type())
+                    << ".CREATOR);" << endl;
+      } else {
+        indent(out) << "in.readList(" << prefix << ", " << tname << ".class.getClassLoader());"
+                    << endl;
+      }
+    } else if (t->is_map()) {
+      indent(out) << prefix << " = new " << type_name(t, false, true) << "();" << endl;
+      indent(out) << " in.readMap(" << prefix << ", " << tname << ".class.getClassLoader());"
+                  << endl;
+    } else if (type_name(t) == "float") {
+      indent(out) << prefix << " = in.readFloat();" << endl;
+    } else if (t->is_base_type()) {
+      t_base_type* bt = (t_base_type*)t;
+      if (bt->is_binary()) {
+        indent(out) << "if(in.readInt()==1) {" << endl;
+        indent_up();
+        indent(out) << prefix << " = java.nio.ByteBuffer.wrap(in.createByteArray());" << endl;
+        scope_down(out);
+      } else {
+        switch (bt->get_base()) {
+        case t_base_type::TYPE_I16:
+          indent(out) << prefix << " = (short) in.readInt();" << endl;
+          break;
+        case t_base_type::TYPE_I32:
+          indent(out) << prefix << " = in.readInt();" << endl;
+          break;
+        case t_base_type::TYPE_I64:
+          indent(out) << prefix << " = in.readLong();" << endl;
+          break;
+        case t_base_type::TYPE_BOOL:
+          indent(out) << prefix << " = (in.readInt()==1);" << endl;
+          break;
+        case t_base_type::TYPE_I8:
+          indent(out) << prefix << " = in.readByte();" << endl;
+          break;
+        case t_base_type::TYPE_DOUBLE:
+          indent(out) << prefix << " = in.readDouble();" << endl;
+          break;
+        case t_base_type::TYPE_STRING:
+          indent(out) << prefix << "= in.readString();" << endl;
+          break;
+        case t_base_type::TYPE_VOID:
+          break;
+        }
+      }
+    }
+  }
+
+  scope_down(out);
+  out << endl;
+
+  indent(out) << "public static final android.os.Parcelable.Creator<" << tname
+              << "> CREATOR = new android.os.Parcelable.Creator<" << tname << ">() {" << endl;
+  indent_up();
+
+  indent(out) << "@Override" << endl << indent() << "public " << tname << "[] newArray(int size) {"
+              << endl;
+  indent_up();
+  indent(out) << "return new " << tname << "[size];" << endl;
+  scope_down(out);
+  out << endl;
+
+  indent(out) << "@Override" << endl << indent() << "public " << tname
+              << " createFromParcel(android.os.Parcel in) {" << endl;
+  indent_up();
+  indent(out) << "return new " << tname << "(in);" << endl;
+  scope_down(out);
+
+  indent_down();
+  indent(out) << "};" << endl;
+  out << endl;
+}
+
+/**
+ * Generates equals methods and a hashCode method for a structure.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_struct_equality(ostream& out, t_struct* tstruct) {
+  out << indent() << "@Override" << endl << indent() << "public boolean equals(java.lang.Object that) {"
+      << endl;
+  indent_up();
+  out << indent() << "if (that == null)" << endl << indent() << "  return false;" << endl
+      << indent() << "if (that instanceof " << tstruct->get_name() << ")" << endl << indent()
+      << "  return this.equals((" << tstruct->get_name() << ")that);" << endl << indent()
+      << "return false;" << endl;
+  scope_down(out);
+  out << endl;
+
+  out << indent() << "public boolean equals(" << tstruct->get_name() << " that) {" << endl;
+  indent_up();
+  out << indent() << "if (that == null)" << endl << indent() << "  return false;" << endl
+      << indent() << "if (this == that)" << endl << indent() << "  return true;"  << endl;
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    out << endl;
+
+    t_type* t = get_true_type((*m_iter)->get_type());
+    // Most existing Thrift code does not use isset or optional/required,
+    // so we treat "default" fields as required.
+    bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
+    bool can_be_null = type_can_be_null(t);
+    string name = (*m_iter)->get_name();
+
+    string this_present = "true";
+    string that_present = "true";
+    string unequal;
+
+    if (is_optional || can_be_null) {
+      this_present += " && this." + generate_isset_check(*m_iter);
+      that_present += " && that." + generate_isset_check(*m_iter);
+    }
+
+    out << indent() << "boolean this_present_" << name << " = " << this_present << ";" << endl
+        << indent() << "boolean that_present_" << name << " = " << that_present << ";" << endl
+        << indent() << "if ("
+        << "this_present_" << name << " || that_present_" << name << ") {" << endl;
+    indent_up();
+    out << indent() << "if (!("
+        << "this_present_" << name << " && that_present_" << name << "))" << endl << indent()
+        << "  return false;" << endl;
+
+    if (t->is_binary()) {
+      unequal = "!this." + name + ".equals(that." + name + ")";
+    } else if (can_be_null) {
+      unequal = "!this." + name + ".equals(that." + name + ")";
+    } else {
+      unequal = "this." + name + " != that." + name;
+    }
+
+    out << indent() << "if (" << unequal << ")" << endl << indent() << "  return false;" << endl;
+
+    scope_down(out);
+  }
+  out << endl;
+  indent(out) << "return true;" << endl;
+  scope_down(out);
+  out << endl;
+
+  const int MUL = 8191; // HashCode multiplier
+  const int B_YES = 131071;
+  const int B_NO = 524287;
+  out << indent() << "@Override" << endl << indent() << "public int hashCode() {" << endl;
+  indent_up();
+  indent(out) << "int hashCode = 1;" << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    out << endl;
+
+    t_type* t = get_true_type((*m_iter)->get_type());
+    bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
+    bool can_be_null = type_can_be_null(t);
+    string name = (*m_iter)->get_name();
+
+    if (is_optional || can_be_null) {
+      indent(out) << "hashCode = hashCode * " << MUL << " + ((" << generate_isset_check(*m_iter)
+                  << ") ? " << B_YES << " : " << B_NO << ");" << endl;
+    }
+
+    if (is_optional || can_be_null) {
+      indent(out) << "if (" + generate_isset_check(*m_iter) + ")" << endl;
+      indent_up();
+    }
+
+    if (t->is_enum()) {
+      indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ".getValue();" << endl;
+    } else if (t->is_base_type()) {
+      switch(((t_base_type*)t)->get_base()) {
+      case t_base_type::TYPE_STRING:
+        indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ".hashCode();" << endl;
+        break;
+      case t_base_type::TYPE_BOOL:
+        indent(out) << "hashCode = hashCode * " << MUL << " + ((" << name << ") ? "
+                    << B_YES << " : " << B_NO << ");" << endl;
+        break;
+      case t_base_type::TYPE_I8:
+        indent(out) << "hashCode = hashCode * " << MUL << " + (int) (" << name << ");" << endl;
+        break;
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+        indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ";" << endl;
+        break;
+      case t_base_type::TYPE_I64:
+      case t_base_type::TYPE_DOUBLE:
+        indent(out) << "hashCode = hashCode * " << MUL << " + org.apache.thrift.TBaseHelper.hashCode(" << name << ");" << endl;
+        break;
+      case t_base_type::TYPE_VOID:
+        throw std::logic_error("compiler error: a struct field cannot be void");
+      default:
+        throw std::logic_error("compiler error: the following base type has no hashcode generator: " +
+               t_base_type::t_base_name(((t_base_type*)t)->get_base()));
+      }
+    } else {
+      indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ".hashCode();" << endl;
+    }
+
+    if (is_optional || can_be_null) {
+      indent_down();
+    }
+  }
+
+  out << endl;
+  indent(out) << "return hashCode;" << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+void t_java_generator::generate_java_struct_compare_to(ostream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl;
+  indent_up();
+
+  indent(out) << "if (!getClass().equals(other.getClass())) {" << endl;
+  indent(out) << "  return getClass().getName().compareTo(other.getClass().getName());" << endl;
+  indent(out) << "}" << endl;
+  out << endl;
+
+  indent(out) << "int lastComparison = 0;" << endl;
+  out << endl;
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = *m_iter;
+    indent(out) << "lastComparison = java.lang.Boolean.valueOf(" << generate_isset_check(field)
+                << ").compareTo(other." << generate_isset_check(field) << ");" << endl;
+    indent(out) << "if (lastComparison != 0) {" << endl;
+    indent(out) << "  return lastComparison;" << endl;
+    indent(out) << "}" << endl;
+
+    indent(out) << "if (" << generate_isset_check(field) << ") {" << endl;
+    indent(out) << "  lastComparison = org.apache.thrift.TBaseHelper.compareTo(this."
+                << field->get_name() << ", other." << field->get_name() << ");" << endl;
+    indent(out) << "  if (lastComparison != 0) {" << endl;
+    indent(out) << "    return lastComparison;" << endl;
+    indent(out) << "  }" << endl;
+    indent(out) << "}" << endl;
+  }
+
+  indent(out) << "return 0;" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to read all the fields of the struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_struct_reader(ostream& out, t_struct* tstruct) {
+  (void)tstruct;
+  indent(out) << "public void read(org.apache.thrift.protocol.TProtocol iprot) throws "
+                 "org.apache.thrift.TException {" << endl;
+  indent_up();
+  indent(out) << "scheme(iprot).read(iprot, this);" << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+// generates java method to perform various checks
+// (e.g. check that all required fields are set)
+void t_java_generator::generate_java_validator(ostream& out, t_struct* tstruct) {
+  indent(out) << "public void validate() throws org.apache.thrift.TException {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out << indent() << "// check for required fields" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      if (bean_style_) {
+        out << indent() << "if (!" << generate_isset_check(*f_iter) << ") {" << endl << indent()
+            << "  throw new org.apache.thrift.protocol.TProtocolException(\"Required field '"
+            << (*f_iter)->get_name() << "' is unset! Struct:\" + toString());" << endl << indent()
+            << "}" << endl << endl;
+      } else {
+        if (type_can_be_null((*f_iter)->get_type())) {
+          indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl;
+          indent(out)
+              << "  throw new org.apache.thrift.protocol.TProtocolException(\"Required field '"
+              << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" << endl;
+          indent(out) << "}" << endl;
+        } else {
+          indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name()
+                      << "' because it's a primitive and you chose the non-beans generator."
+                      << endl;
+        }
+      }
+    }
+  }
+
+  out << indent() << "// check for sub-struct validity" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_type* type = (*f_iter)->get_type();
+    if (type->is_struct() && !((t_struct*)type)->is_union()) {
+      out << indent() << "if (" << (*f_iter)->get_name() << " != null) {" << endl;
+      out << indent() << "  " << (*f_iter)->get_name() << ".validate();" << endl;
+      out << indent() << "}" << endl;
+    }
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_struct_writer(ostream& out, t_struct* tstruct) {
+  (void)tstruct;
+  indent(out) << "public void write(org.apache.thrift.protocol.TProtocol oprot) throws "
+                 "org.apache.thrift.TException {" << endl;
+  indent_up();
+  indent(out) << "scheme(oprot).write(oprot, this);" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct,
+ * which is a function result. These fields are only written
+ * if they are set in the Isset array, and only one of them
+ * can be set at a time.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_struct_result_writer(ostream& out, t_struct* tstruct) {
+  (void)tstruct;
+  indent(out) << "public void write(org.apache.thrift.protocol.TProtocol oprot) throws "
+                 "org.apache.thrift.TException {" << endl;
+  indent_up();
+  indent(out) << "scheme(oprot).write(oprot, this);" << endl;
+
+  indent_down();
+  indent(out) << "  }" << endl << endl;
+}
+
+void t_java_generator::generate_java_struct_field_by_id(ostream& out, t_struct* tstruct) {
+  (void)tstruct;
+  indent(out) << java_nullable_annotation() << endl;
+  indent(out) << "public _Fields fieldForId(int fieldId) {" << endl;
+  indent(out) << "  return _Fields.findByThriftId(fieldId);" << endl;
+  indent(out) << "}" << endl << endl;
+}
+
+void t_java_generator::generate_reflection_getters(ostringstream& out,
+                                                   t_type* type,
+                                                   string field_name,
+                                                   string cap_name) {
+  indent(out) << "case " << constant_name(field_name) << ":" << endl;
+  indent_up();
+  indent(out) << "return " << (type->is_bool() ? "is" : "get") << cap_name << "();" << endl << endl;
+  indent_down();
+}
+
+void t_java_generator::generate_reflection_setters(ostringstream& out,
+                                                   t_type* type,
+                                                   string field_name,
+                                                   string cap_name) {
+  const bool is_binary = type->is_binary();
+  indent(out) << "case " << constant_name(field_name) << ":" << endl;
+  indent_up();
+  indent(out) << "if (value == null) {" << endl;
+  indent(out) << "  unset" << get_cap_name(field_name) << "();" << endl;
+  indent(out) << "} else {" << endl;
+  if (is_binary) {
+    indent_up();
+    indent(out) << "if (value instanceof byte[]) {" << endl;
+    indent(out) << "  set" << cap_name << "((byte[])value);" << endl;
+    indent(out) << "} else {" << endl;
+  }
+  indent(out) << "  set" << cap_name << "((" << type_name(type, true, false) << ")value);" << endl;
+  if (is_binary) {
+    indent(out) << "}" << endl;
+    indent_down();
+  }
+  indent(out) << "}" << endl;
+  indent(out) << "break;" << endl << endl;
+
+  indent_down();
+}
+
+void t_java_generator::generate_generic_field_getters_setters(std::ostream& out,
+                                                              t_struct* tstruct) {
+  std::ostringstream getter_stream;
+  std::ostringstream setter_stream;
+
+  // build up the bodies of both the getter and setter at once
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    t_type* type = get_true_type(field->get_type());
+    std::string field_name = field->get_name();
+    std::string cap_name = get_cap_name(field_name);
+
+    indent_up();
+    generate_reflection_setters(setter_stream, type, field_name, cap_name);
+    generate_reflection_getters(getter_stream, type, field_name, cap_name);
+    indent_down();
+  }
+
+  // create the setter
+
+  indent(out) << "public void setFieldValue(_Fields field, " << java_nullable_annotation()
+              << " java.lang.Object value) {" << endl;
+  indent(out) << "  switch (field) {" << endl;
+  out << setter_stream.str();
+  indent(out) << "  }" << endl;
+  indent(out) << "}" << endl << endl;
+
+  // create the getter
+  indent(out) << java_nullable_annotation() << endl;
+  indent(out) << "public java.lang.Object getFieldValue(_Fields field) {" << endl;
+  indent_up();
+  indent(out) << "switch (field) {" << endl;
+  out << getter_stream.str();
+  indent(out) << "}" << endl;
+  indent(out) << "throw new java.lang.IllegalStateException();" << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+// Creates a generic isSet method that takes the field number as argument
+void t_java_generator::generate_generic_isset_method(std::ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // create the isSet method
+  indent(out) << "/** Returns true if field corresponding to fieldID is set (has been assigned a "
+                 "value) and false otherwise */" << endl;
+  indent(out) << "public boolean isSet(_Fields field) {" << endl;
+  indent_up();
+  indent(out) << "if (field == null) {" << endl;
+  indent(out) << "  throw new java.lang.IllegalArgumentException();" << endl;
+  indent(out) << "}" << endl << endl;
+
+  indent(out) << "switch (field) {" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
+    indent_up();
+    indent(out) << "return " << generate_isset_check(field) << ";" << endl;
+    indent_down();
+  }
+
+  indent(out) << "}" << endl;
+  indent(out) << "throw new java.lang.IllegalStateException();" << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a set of Java Bean boilerplate functions (setters, getters, etc.)
+ * for the given struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_bean_boilerplate(ostream& out, t_struct* tstruct) {
+  isset_type issetType = needs_isset(tstruct);
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    t_type* type = get_true_type(field->get_type());
+    std::string field_name = field->get_name();
+    std::string cap_name = get_cap_name(field_name);
+    bool optional = use_option_type_ && field->get_req() == t_field::T_OPTIONAL;
+    bool is_deprecated = this->is_deprecated(field->annotations_);
+
+    if (type->is_container()) {
+      // Method to return the size of the collection
+      if (optional) {
+        if (is_deprecated) {
+          indent(out) << "@Deprecated" << endl;
+        }
+        indent(out) << "public org.apache.thrift.Option<Integer> get" << cap_name;
+        out << get_cap_name("size() {") << endl;
+
+        indent_up();
+        indent(out) << "if (this." << field_name << " == null) {" << endl;
+        indent_up();
+        indent(out) << "return org.apache.thrift.Option.none();" << endl;
+        indent_down();
+        indent(out) << "} else {" << endl;
+        indent_up();
+        indent(out) << "return org.apache.thrift.Option.some(this." << field_name << ".size());" << endl;
+        indent_down();
+        indent(out) << "}" << endl;
+        indent_down();
+        indent(out) << "}" << endl << endl;
+      } else {
+        if (is_deprecated) {
+          indent(out) << "@Deprecated" << endl;
+        }
+        indent(out) << "public int get" << cap_name;
+        out << get_cap_name("size() {") << endl;
+
+        indent_up();
+        indent(out) << "return (this." << field_name << " == null) ? 0 : "
+                    << "this." << field_name << ".size();" << endl;
+        indent_down();
+        indent(out) << "}" << endl << endl;
+      }
+    }
+
+    if (type->is_set() || type->is_list()) {
+      t_type* element_type;
+      if (type->is_set()) {
+        element_type = ((t_set*)type)->get_elem_type();
+      } else {
+        element_type = ((t_list*)type)->get_elem_type();
+      }
+
+      // Iterator getter for sets and lists
+      if (optional) {
+        if (is_deprecated) {
+          indent(out) << "@Deprecated" << endl;
+        }
+        indent(out) << "public org.apache.thrift.Option<java.util.Iterator<" << type_name(element_type, true, false)
+                    << ">> get" << cap_name;
+        out << get_cap_name("iterator() {") << endl;
+
+        indent_up();
+        indent(out) << "if (this." << field_name << " == null) {" << endl;
+        indent_up();
+        indent(out) << "return org.apache.thrift.Option.none();" << endl;
+        indent_down();
+        indent(out) << "} else {" << endl;
+        indent_up();
+        indent(out) << "return org.apache.thrift.Option.some(this." << field_name << ".iterator());" << endl;
+        indent_down();
+        indent(out) << "}" << endl;
+        indent_down();
+        indent(out) << "}" << endl << endl;
+      } else {
+        if (is_deprecated) {
+          indent(out) << "@Deprecated" << endl;
+        }
+        indent(out) << java_nullable_annotation() << endl;
+        indent(out) << "public java.util.Iterator<" << type_name(element_type, true, false)
+                    << "> get" << cap_name;
+        out << get_cap_name("iterator() {") << endl;
+
+        indent_up();
+        indent(out) << "return (this." << field_name << " == null) ? null : "
+                    << "this." << field_name << ".iterator();" << endl;
+        indent_down();
+        indent(out) << "}" << endl << endl;
+      }
+
+      // Add to set or list, create if the set/list is null
+      if (is_deprecated) {
+        indent(out) << "@Deprecated" << endl;
+      }
+      indent(out) << "public void add" << get_cap_name("to");
+      out << cap_name << "(" << type_name(element_type) << " elem) {" << endl;
+
+      indent_up();
+      indent(out) << "if (this." << field_name << " == null) {" << endl;
+      indent_up();
+      indent(out) << "this." << field_name;
+      if (is_enum_set(type)) {
+        out << " = " << type_name(type, false, true, true) << ".noneOf(" << inner_enum_type_name(type) << ");" << endl;
+      } else {
+        out << " = new " << type_name(type, false, true) << "();" << endl;
+      }
+      indent_down();
+      indent(out) << "}" << endl;
+      indent(out) << "this." << field_name << ".add(elem);" << endl;
+      indent_down();
+      indent(out) << "}" << endl << endl;
+    } else if (type->is_map()) {
+      // Put to map
+      t_type* key_type = ((t_map*)type)->get_key_type();
+      t_type* val_type = ((t_map*)type)->get_val_type();
+
+      if (is_deprecated) {
+        indent(out) << "@Deprecated" << endl;
+      }
+      indent(out) << "public void put" << get_cap_name("to");
+      out << cap_name << "(" << type_name(key_type) << " key, " << type_name(val_type) << " val) {"
+          << endl;
+
+      indent_up();
+      indent(out) << "if (this." << field_name << " == null) {" << endl;
+      indent_up();
+      std::string constructor_args;
+      if (is_enum_map(type)) {
+        constructor_args = inner_enum_type_name(type);
+      }
+      indent(out) << "this." << field_name << " = new " << type_name(type, false, true) << "(" << constructor_args << ");"
+                  << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+      indent(out) << "this." << field_name << ".put(key, val);" << endl;
+      indent_down();
+      indent(out) << "}" << endl << endl;
+    }
+
+    // Simple getter
+    generate_java_doc(out, field);
+    if (type->is_binary()) {
+      if (is_deprecated) {
+        indent(out) << "@Deprecated" << endl;
+      }
+      indent(out) << "public byte[] get" << cap_name << "() {" << endl;
+      indent(out) << "  set" << cap_name << "(org.apache.thrift.TBaseHelper.rightSize("
+                  << field_name << "));" << endl;
+      indent(out) << "  return " << field_name << " == null ? null : " << field_name << ".array();"
+                  << endl;
+      indent(out) << "}" << endl << endl;
+
+      indent(out) << "public java.nio.ByteBuffer buffer" << get_cap_name("for") << cap_name << "() {"
+                  << endl;
+      if(unsafe_binaries_){
+        indent(out) << "  return " << field_name << ";"
+                    << endl;
+      }else {
+        indent(out) << "  return org.apache.thrift.TBaseHelper.copyBinary(" << field_name << ");"
+                    << endl;
+      }
+      indent(out) << "}" << endl << endl;
+    } else {
+      if (optional) {
+        if (is_deprecated) {
+          indent(out) << "@Deprecated" << endl;
+        }
+        indent(out) << "public org.apache.thrift.Option<" << type_name(type, true) << ">";
+        if (type->is_base_type() && ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) {
+          out << " is";
+        } else {
+          out << " get";
+        }
+        out << cap_name << "() {" << endl;
+        indent_up();
+
+        indent(out) << "if (this.isSet" << cap_name << "()) {" << endl;
+        indent_up();
+        indent(out) << "return org.apache.thrift.Option.some(this." << field_name << ");" << endl;
+        indent_down();
+        indent(out) << "} else {" << endl;
+        indent_up();
+        indent(out) << "return org.apache.thrift.Option.none();" << endl;
+        indent_down();
+        indent(out) << "}" << endl;
+        indent_down();
+        indent(out) << "}" << endl << endl;
+      } else {
+        if (is_deprecated) {
+          indent(out) << "@Deprecated" << endl;
+        }
+        if (type_can_be_null(type)) {
+          indent(out) << java_nullable_annotation() << endl;
+        }
+        indent(out) << "public " << type_name(type);
+        if (type->is_base_type() && ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) {
+          out << " is";
+        } else {
+          out << " get";
+        }
+        out << cap_name << "() {" << endl;
+        indent_up();
+        indent(out) << "return this." << field_name << ";" << endl;
+        indent_down();
+        indent(out) << "}" << endl << endl;
+      }
+    }
+
+    // Simple setter
+    generate_java_doc(out, field);
+    if (type->is_binary()) {
+      if (is_deprecated) {
+        indent(out) << "@Deprecated" << endl;
+      }
+      indent(out) << "public ";
+      if (bean_style_) {
+        out << "void";
+      } else {
+        out << type_name(tstruct);
+      }
+      out << " set" << cap_name << "(byte[] " << field_name << ") {" << endl;
+      indent(out) << "  this." << field_name << " = " << field_name << " == null ? (java.nio.ByteBuffer)null";
+
+      if(unsafe_binaries_){
+        indent(out) << " : java.nio.ByteBuffer.wrap(" << field_name << ");" << endl;
+      }else{
+        indent(out) << " : java.nio.ByteBuffer.wrap(" << field_name << ".clone());" << endl;
+      }
+                 
+      if (!bean_style_) {
+        indent(out) << "  return this;" << endl;
+      }
+      indent(out) << "}" << endl << endl;
+    }
+    if (is_deprecated) {
+      indent(out) << "@Deprecated" << endl;
+    }
+    indent(out) << "public ";
+    if (bean_style_) {
+      out << "void";
+    } else {
+      out << type_name(tstruct);
+    }
+    out << " set" << cap_name << "(" << (type_can_be_null(type) ? (java_nullable_annotation() + " ") : "")
+        << type_name(type) << " " << field_name << ") {" << endl;
+    indent_up();
+    indent(out) << "this." << field_name << " = ";
+    if (type->is_binary() && !unsafe_binaries_) {
+      out << "org.apache.thrift.TBaseHelper.copyBinary(" << field_name << ")";
+    } else {
+      out << field_name;
+    }
+    out << ";" << endl;
+    generate_isset_set(out, field, "");
+    if (!bean_style_) {
+      indent(out) << "return this;" << endl;
+    }
+
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // Unsetter
+    if (is_deprecated) {
+      indent(out) << "@Deprecated" << endl;
+    }
+    indent(out) << "public void unset" << cap_name << "() {" << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "this." << field_name << " = null;" << endl;
+    } else if (issetType == ISSET_PRIMITIVE) {
+      indent(out) << "__isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, "
+                  << isset_field_id(field) << ");" << endl;
+    } else {
+      indent(out) << "__isset_bit_vector.clear(" << isset_field_id(field) << ");" << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // isSet method
+    indent(out) << "/** Returns true if field " << field_name
+                << " is set (has been assigned a value) and false otherwise */" << endl;
+    if (is_deprecated) {
+      indent(out) << "@Deprecated" << endl;
+    }
+    indent(out) << "public boolean is" << get_cap_name("set") << cap_name << "() {" << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "return this." << field_name << " != null;" << endl;
+    } else if (issetType == ISSET_PRIMITIVE) {
+      indent(out) << "return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, " << isset_field_id(field)
+                  << ");" << endl;
+    } else {
+      indent(out) << "return __isset_bit_vector.get(" << isset_field_id(field) << ");" << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    if (is_deprecated) {
+      indent(out) << "@Deprecated" << endl;
+    }
+    indent(out) << "public void set" << cap_name << get_cap_name("isSet") << "(boolean value) {"
+                << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "if (!value) {" << endl;
+      indent(out) << "  this." << field_name << " = null;" << endl;
+      indent(out) << "}" << endl;
+    } else if (issetType == ISSET_PRIMITIVE) {
+      indent(out) << "__isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, "
+                  << isset_field_id(field) << ", value);" << endl;
+    } else {
+      indent(out) << "__isset_bit_vector.set(" << isset_field_id(field) << ", value);" << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+}
+
+/**
+ * Generates a toString() method for the given struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_struct_tostring(ostream& out, t_struct* tstruct) {
+  out << indent() << "@Override" << endl << indent() << "public java.lang.String toString() {" << endl;
+  indent_up();
+
+  out << indent() << "java.lang.StringBuilder sb = new java.lang.StringBuilder(\"" << tstruct->get_name() << "(\");"
+      << endl;
+  out << indent() << "boolean first = true;" << endl << endl;
+
+  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) {
+    bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
+    if (could_be_unset) {
+      indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl;
+      indent_up();
+    }
+
+    t_field* field = (*f_iter);
+
+    if (!first) {
+      indent(out) << "if (!first) sb.append(\", \");" << endl;
+    }
+    indent(out) << "sb.append(\"" << (*f_iter)->get_name() << ":\");" << endl;
+    bool can_be_null = type_can_be_null(field->get_type());
+    if (can_be_null) {
+      indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl;
+      indent(out) << "  sb.append(\"null\");" << endl;
+      indent(out) << "} else {" << endl;
+      indent_up();
+    }
+
+    if (get_true_type(field->get_type())->is_binary()) {
+      indent(out) << "org.apache.thrift.TBaseHelper.toString(this." << field->get_name() << ", sb);"
+                  << endl;
+    } else if ((field->get_type()->is_set())
+               && (get_true_type(((t_set*)field->get_type())->get_elem_type())->is_binary())) {
+      indent(out) << "org.apache.thrift.TBaseHelper.toString(this." << field->get_name() << ", sb);"
+                  << endl;
+    } else if ((field->get_type()->is_list())
+               && (get_true_type(((t_list*)field->get_type())->get_elem_type())->is_binary())) {
+      indent(out) << "org.apache.thrift.TBaseHelper.toString(this." << field->get_name() << ", sb);"
+                  << endl;
+    } else {
+      indent(out) << "sb.append(this." << (*f_iter)->get_name() << ");" << endl;
+    }
+
+    if (can_be_null) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    indent(out) << "first = false;" << endl;
+
+    if (could_be_unset) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    first = false;
+  }
+  out << indent() << "sb.append(\")\");" << endl << indent() << "return sb.toString();" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a static map with meta data to store information such as fieldID to
+ * fieldName mapping
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_meta_data_map(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Static Map with fieldID -> org.apache.thrift.meta_data.FieldMetaData mappings
+  indent(out)
+      << "public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;"
+      << endl;
+  indent(out) << "static {" << endl;
+  indent_up();
+
+  indent(out) << "java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new "
+                 "java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);"
+              << endl;
+
+  // Populate map
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    std::string field_name = field->get_name();
+    indent(out) << "tmpMap.put(_Fields." << constant_name(field_name)
+                << ", new org.apache.thrift.meta_data.FieldMetaData(\"" << field_name << "\", ";
+
+    // Set field requirement type (required, optional, etc.)
+    if (field->get_req() == t_field::T_REQUIRED) {
+      out << "org.apache.thrift.TFieldRequirementType.REQUIRED, ";
+    } else if (field->get_req() == t_field::T_OPTIONAL) {
+      out << "org.apache.thrift.TFieldRequirementType.OPTIONAL, ";
+    } else {
+      out << "org.apache.thrift.TFieldRequirementType.DEFAULT, ";
+    }
+
+    // Create value meta data
+    generate_field_value_meta_data(out, field->get_type());
+    out << "));" << endl;
+  }
+
+  indent(out) << "metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);" << endl;
+
+  indent(out) << "org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap("
+              << type_name(tstruct) << ".class, metaDataMap);" << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Returns a string with the java representation of the given thrift type
+ * (e.g. for the type struct it returns "org.apache.thrift.protocol.TType.STRUCT")
+ */
+std::string t_java_generator::get_java_type_string(t_type* type) {
+  if (type->is_list()) {
+    return "org.apache.thrift.protocol.TType.LIST";
+  } else if (type->is_map()) {
+    return "org.apache.thrift.protocol.TType.MAP";
+  } else if (type->is_set()) {
+    return "org.apache.thrift.protocol.TType.SET";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "org.apache.thrift.protocol.TType.STRUCT";
+  } else if (type->is_enum()) {
+    return "org.apache.thrift.protocol.TType.ENUM";
+  } else if (type->is_typedef()) {
+    return get_java_type_string(((t_typedef*)type)->get_type());
+  } else if (type->is_base_type()) {
+    switch (((t_base_type*)type)->get_base()) {
+    case t_base_type::TYPE_VOID:
+      return "org.apache.thrift.protocol.TType.VOID";
+      break;
+    case t_base_type::TYPE_STRING:
+      return "org.apache.thrift.protocol.TType.STRING";
+      break;
+    case t_base_type::TYPE_BOOL:
+      return "org.apache.thrift.protocol.TType.BOOL";
+      break;
+    case t_base_type::TYPE_I8:
+      return "org.apache.thrift.protocol.TType.BYTE";
+      break;
+    case t_base_type::TYPE_I16:
+      return "org.apache.thrift.protocol.TType.I16";
+      break;
+    case t_base_type::TYPE_I32:
+      return "org.apache.thrift.protocol.TType.I32";
+      break;
+    case t_base_type::TYPE_I64:
+      return "org.apache.thrift.protocol.TType.I64";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      return "org.apache.thrift.protocol.TType.DOUBLE";
+      break;
+    default:
+      throw std::runtime_error("Unknown thrift type \"" + type->get_name()
+                               + "\" passed to t_java_generator::get_java_type_string!");
+      return "Unknown thrift type \"" + type->get_name()
+             + "\" passed to t_java_generator::get_java_type_string!";
+      break; // This should never happen!
+    }
+  } else {
+    throw std::runtime_error("Unknown thrift type \"" + type->get_name()
+                             + "\" passed to t_java_generator::get_java_type_string!");
+    // This should never happen!
+  }
+}
+
+void t_java_generator::generate_field_value_meta_data(std::ostream& out, t_type* type) {
+  out << endl;
+  indent_up();
+  indent_up();
+  if (type->is_struct() || type->is_xception()) {
+    indent(out) << "new "
+                   "org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType."
+                   "STRUCT, " << type_name(type) << ".class";
+  } else if (type->is_container()) {
+    if (type->is_list()) {
+      indent(out)
+          << "new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, ";
+      t_type* elem_type = ((t_list*)type)->get_elem_type();
+      generate_field_value_meta_data(out, elem_type);
+    } else if (type->is_set()) {
+      indent(out)
+          << "new org.apache.thrift.meta_data.SetMetaData(org.apache.thrift.protocol.TType.SET, ";
+      t_type* elem_type = ((t_set*)type)->get_elem_type();
+      generate_field_value_meta_data(out, elem_type);
+    } else { // map
+      indent(out)
+          << "new org.apache.thrift.meta_data.MapMetaData(org.apache.thrift.protocol.TType.MAP, ";
+      t_type* key_type = ((t_map*)type)->get_key_type();
+      t_type* val_type = ((t_map*)type)->get_val_type();
+      generate_field_value_meta_data(out, key_type);
+      out << ", ";
+      generate_field_value_meta_data(out, val_type);
+    }
+  } else if (type->is_enum()) {
+    indent(out)
+        << "new org.apache.thrift.meta_data.EnumMetaData(org.apache.thrift.protocol.TType.ENUM, "
+        << type_name(type) << ".class";
+  } else {
+    indent(out) << "new org.apache.thrift.meta_data.FieldValueMetaData("
+                << get_java_type_string(type);
+    if (type->is_typedef()) {
+      indent(out) << ", \"" << ((t_typedef*)type)->get_symbolic() << "\"";
+    } else if (type->is_binary()) {
+      indent(out) << ", true";
+    }
+  }
+  out << ")";
+  indent_down();
+  indent_down();
+}
+
+/**
+ * Generates a thrift service. In C++, this comprises an entirely separate
+ * header and source file. The header file defines the methods and includes
+ * the data types defined in the main header file, and the implementation
+ * file contains implementations of the basic printer and default interfaces.
+ *
+ * @param tservice The service definition
+ */
+void t_java_generator::generate_service(t_service* tservice) {
+  // Make output file
+  string f_service_name = package_dir_ + "/" + make_valid_java_filename(service_name_) + ".java";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << autogen_comment() << java_package() << java_suppressions();
+
+  if (!suppress_generated_annotations_) {
+    generate_javax_generated_annotation(f_service_);
+  }
+  f_service_ << "public class " << service_name_ << " {" << endl << endl;
+  indent_up();
+
+  // Generate the three main parts of the service
+  generate_service_interface(tservice);
+  generate_service_async_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_async_client(tservice);
+  generate_service_server(tservice);
+  generate_service_async_server(tservice);
+  generate_service_helpers(tservice);
+
+  indent_down();
+  f_service_ << "}" << endl;
+  f_service_.close();
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_java_generator::generate_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_iface = " extends " + extends + ".Iface";
+  }
+
+  generate_java_doc(f_service_, tservice);
+  f_service_ << indent() << "public interface Iface" << extends_iface << " {" << endl << endl;
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_java_doc(f_service_, *f_iter);
+    indent(f_service_) << "public " << function_signature(*f_iter) << ";" << endl << endl;
+  }
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+void t_java_generator::generate_service_async_interface(t_service* tservice) {
+  string extends = "";
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_iface = " extends " + extends + " .AsyncIface";
+  }
+
+  f_service_ << indent() << "public interface AsyncIface" << extends_iface << " {" << endl << endl;
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    indent(f_service_) << "public " << function_signature_async(*f_iter, true)
+                       << " throws org.apache.thrift.TException;" << endl << endl;
+  }
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates structs for all the service args and return types
+ *
+ * @param tservice The service
+ */
+void t_java_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_java_struct_definition(f_service_, ts, false, true);
+    generate_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_java_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() == NULL) {
+    extends_client = "org.apache.thrift.TServiceClient";
+  } else {
+    extends = type_name(tservice->get_extends());
+    extends_client = extends + ".Client";
+  }
+
+  indent(f_service_) << "public static class Client extends " << extends_client
+                     << " implements Iface {" << endl;
+  indent_up();
+
+  indent(f_service_)
+      << "public static class Factory implements org.apache.thrift.TServiceClientFactory<Client> {"
+      << endl;
+  indent_up();
+  indent(f_service_) << "public Factory() {}" << endl;
+  indent(f_service_) << "public Client getClient(org.apache.thrift.protocol.TProtocol prot) {"
+                     << endl;
+  indent_up();
+  indent(f_service_) << "return new Client(prot);" << endl;
+  indent_down();
+  indent(f_service_) << "}" << endl;
+  indent(f_service_) << "public Client getClient(org.apache.thrift.protocol.TProtocol iprot, "
+                        "org.apache.thrift.protocol.TProtocol oprot) {" << endl;
+  indent_up();
+  indent(f_service_) << "return new Client(iprot, oprot);" << endl;
+  indent_down();
+  indent(f_service_) << "}" << endl;
+  indent_down();
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "public Client(org.apache.thrift.protocol.TProtocol prot)" << endl;
+  scope_up(f_service_);
+  indent(f_service_) << "super(prot, prot);" << endl;
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  indent(f_service_) << "public Client(org.apache.thrift.protocol.TProtocol iprot, "
+                        "org.apache.thrift.protocol.TProtocol oprot) {" << endl;
+  indent(f_service_) << "  super(iprot, oprot);" << endl;
+  indent(f_service_) << "}" << 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) {
+    string funname = (*f_iter)->get_name();
+    string sep = "_";
+    string javaname = funname;
+    if (fullcamel_style_) {
+      sep = "";
+      javaname = as_camel_case(funname);
+    }
+
+    // Open function
+    indent(f_service_) << "public " << function_signature(*f_iter) << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "send" << sep << javaname << "(";
+
+    // Get the struct of function call params
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+
+    // Declare the function arguments
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    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;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "return ";
+      }
+      f_service_ << "recv" << sep << javaname << "();" << endl;
+    }
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    t_function send_function(g_type_void,
+                             string("send") + sep + javaname,
+                             (*f_iter)->get_arglist());
+
+    string argsname = (*f_iter)->get_name() + "_args";
+
+    // Open function
+    indent(f_service_) << "public " << function_signature(&send_function) << endl;
+    scope_up(f_service_);
+
+    // Serialize the request
+    indent(f_service_) << argsname << " args = new " << argsname << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      indent(f_service_) << "args.set" << get_cap_name((*fld_iter)->get_name()) << "("
+                         << (*fld_iter)->get_name() << ");" << endl;
+    }
+
+    const string sendBaseName = (*f_iter)->is_oneway() ? "sendBaseOneway" : "sendBase";
+    indent(f_service_) << sendBaseName << "(\"" << funname << "\", args);" << endl;
+
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      string resultname = (*f_iter)->get_name() + "_result";
+
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv") + sep + javaname,
+                               &noargs,
+                               (*f_iter)->get_xceptions());
+      // Open function
+      indent(f_service_) << "public " << function_signature(&recv_function) << endl;
+      scope_up(f_service_);
+
+      f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl
+                 << indent() << "receiveBase(result, \"" << funname << "\");" << endl;
+
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << indent() << "if (result." << generate_isset_check("success") << ") {" << endl
+                   << indent() << "  return result.success;" << endl << indent() << "}" << 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." << (*x_iter)->get_name() << " != null) {" << endl
+                   << indent() << "  throw result." << (*x_iter)->get_name() << ";" << endl
+                   << indent() << "}" << endl;
+      }
+
+      // If you get here it's an exception, unless a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) << "return;" << endl;
+      } else {
+        f_service_ << indent() << "throw new "
+                                  "org.apache.thrift.TApplicationException(org.apache.thrift."
+                                  "TApplicationException.MISSING_RESULT, \""
+                   << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
+      }
+
+      // Close function
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl;
+}
+
+void t_java_generator::generate_service_async_client(t_service* tservice) {
+  string extends = "org.apache.thrift.async.TAsyncClient";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends()) + ".AsyncClient";
+  }
+
+  indent(f_service_) << "public static class AsyncClient extends " << extends
+                     << " implements AsyncIface {" << endl;
+  indent_up();
+
+  // Factory method
+  indent(f_service_) << "public static class Factory implements "
+                        "org.apache.thrift.async.TAsyncClientFactory<AsyncClient> {" << endl;
+  indent(f_service_) << "  private org.apache.thrift.async.TAsyncClientManager clientManager;"
+                     << endl;
+  indent(f_service_) << "  private org.apache.thrift.protocol.TProtocolFactory protocolFactory;"
+                     << endl;
+  indent(f_service_) << "  public Factory(org.apache.thrift.async.TAsyncClientManager "
+                        "clientManager, org.apache.thrift.protocol.TProtocolFactory "
+                        "protocolFactory) {" << endl;
+  indent(f_service_) << "    this.clientManager = clientManager;" << endl;
+  indent(f_service_) << "    this.protocolFactory = protocolFactory;" << endl;
+  indent(f_service_) << "  }" << endl;
+  indent(f_service_) << "  public AsyncClient "
+                        "getAsyncClient(org.apache.thrift.transport.TNonblockingTransport "
+                        "transport) {" << endl;
+  indent(f_service_) << "    return new AsyncClient(protocolFactory, clientManager, transport);"
+                     << endl;
+  indent(f_service_) << "  }" << endl;
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "public AsyncClient(org.apache.thrift.protocol.TProtocolFactory "
+                        "protocolFactory, org.apache.thrift.async.TAsyncClientManager "
+                        "clientManager, org.apache.thrift.transport.TNonblockingTransport "
+                        "transport) {" << endl;
+  indent(f_service_) << "  super(protocolFactory, clientManager, transport);" << endl;
+  indent(f_service_) << "}" << 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) {
+    string funname = (*f_iter)->get_name();
+    string sep = "_";
+    string javaname = funname;
+    if (fullcamel_style_) {
+      sep = "";
+      javaname = as_camel_case(javaname);
+    }
+    t_type* ret_type = (*f_iter)->get_returntype();
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    string funclassname = funname + "_call";
+    const vector<t_field*>& fields = arg_struct->get_members();
+    const std::vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    string args_name = (*f_iter)->get_name() + "_args";
+    string result_name = (*f_iter)->get_name() + "_result";
+
+    // Main method body
+    indent(f_service_) << "public " << function_signature_async(*f_iter, false)
+                       << " throws org.apache.thrift.TException {" << endl;
+    indent(f_service_) << "  checkReady();" << endl;
+    indent(f_service_) << "  " << funclassname << " method_call = new " + funclassname + "("
+                       << async_argument_list(*f_iter, arg_struct, ret_type)
+                       << ", this, ___protocolFactory, ___transport);" << endl;
+    indent(f_service_) << "  this.___currentMethod = method_call;" << endl;
+    indent(f_service_) << "  ___manager.call(method_call);" << endl;
+    indent(f_service_) << "}" << endl;
+
+    f_service_ << endl;
+
+    // TAsyncMethod object for this function call
+    indent(f_service_) << "public static class " + funclassname
+                          + " extends org.apache.thrift.async.TAsyncMethodCall<"
+                          + type_name((*f_iter)->get_returntype(), true) + "> {" << endl;
+    indent_up();
+
+    // Member variables
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      indent(f_service_) << "private " + type_name((*fld_iter)->get_type()) + " "
+                            + (*fld_iter)->get_name() + ";" << endl;
+    }
+
+    // NOTE since we use a new Client instance to deserialize, let's keep seqid to 0 for now
+    // indent(f_service_) << "private int seqid;" << endl << endl;
+
+    // Constructor
+    indent(f_service_) << "public " + funclassname + "("
+                          + async_argument_list(*f_iter, arg_struct, ret_type, true)
+                       << ", org.apache.thrift.async.TAsyncClient client, "
+                          "org.apache.thrift.protocol.TProtocolFactory protocolFactory, "
+                          "org.apache.thrift.transport.TNonblockingTransport transport) throws "
+                          "org.apache.thrift.TException {" << endl;
+    indent(f_service_) << "  super(client, protocolFactory, transport, resultHandler, "
+                       << ((*f_iter)->is_oneway() ? "true" : "false") << ");" << endl;
+
+    // Assign member variables
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      indent(f_service_) << "  this." + (*fld_iter)->get_name() + " = " + (*fld_iter)->get_name()
+                            + ";" << endl;
+    }
+
+    indent(f_service_) << "}" << endl << endl;
+
+    indent(f_service_) << "public void write_args(org.apache.thrift.protocol.TProtocol prot) "
+                          "throws org.apache.thrift.TException {" << endl;
+    indent_up();
+
+    // Serialize request
+    // NOTE we are leaving seqid as 0, for now (see above)
+    f_service_ << indent() << "prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage(\""
+               << funname << "\", org.apache.thrift.protocol."
+               << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL") << ", 0));"
+               << endl << indent() << args_name << " args = new " << args_name << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << indent() << "args.set" << get_cap_name((*fld_iter)->get_name()) << "("
+                 << (*fld_iter)->get_name() << ");" << endl;
+    }
+
+    f_service_ << indent() << "args.write(prot);" << endl << indent() << "prot.writeMessageEnd();"
+               << endl;
+
+    indent_down();
+    indent(f_service_) << "}" << endl << endl;
+
+    // Return method
+    indent(f_service_) << "public " + type_name(ret_type, true) + " getResult() throws ";
+    vector<t_field*>::const_iterator x_iter;
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << type_name((*x_iter)->get_type(), false, false) + ", ";
+    }
+    f_service_ << "org.apache.thrift.TException {" << endl;
+
+    indent_up();
+    f_service_
+        << indent()
+        << "if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {"
+        << endl << indent() << "  throw new java.lang.IllegalStateException(\"Method call not finished!\");"
+        << endl << indent() << "}" << endl << indent()
+        << "org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new "
+           "org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());" << endl
+        << indent() << "org.apache.thrift.protocol.TProtocol prot = "
+                       "client.getProtocolFactory().getProtocol(memoryTransport);" << endl;
+    indent(f_service_);
+    if (ret_type->is_void()) { // NB: Includes oneways which always return void.
+      f_service_ << "return null;" << endl;
+    } else {
+      f_service_ << "return (new Client(prot)).recv" + sep + javaname + "();" << endl;
+    }
+
+    // Close function
+    indent_down();
+    indent(f_service_) << "}" << endl;
+
+    // Close class
+    indent_down();
+    indent(f_service_) << "}" << endl << endl;
+  }
+
+  // Close AsyncClient
+  scope_down(f_service_);
+  f_service_ << endl;
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_java_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  // Extends stuff
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() == NULL) {
+    extends_processor = "org.apache.thrift.TBaseProcessor<I>";
+  } else {
+    extends = type_name(tservice->get_extends());
+    extends_processor = extends + ".Processor<I>";
+  }
+
+  // Generate the header portion
+  indent(f_service_) << "public static class Processor<I extends Iface> extends "
+                     << extends_processor << " implements org.apache.thrift.TProcessor {" << endl;
+  indent_up();
+
+  indent(f_service_)
+      << "private static final org.slf4j.Logger _LOGGER = org.slf4j.LoggerFactory.getLogger(Processor.class.getName());"
+      << endl;
+
+  indent(f_service_) << "public Processor(I iface) {" << endl;
+  indent(f_service_) << "  super(iface, getProcessMap(new java.util.HashMap<java.lang.String, "
+                        "org.apache.thrift.ProcessFunction<I, ? extends "
+                        "org.apache.thrift.TBase>>()));" << endl;
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "protected Processor(I iface, java.util.Map<java.lang.String, "
+                        "org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>> "
+                        "processMap) {" << endl;
+  indent(f_service_) << "  super(iface, getProcessMap(processMap));" << endl;
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "private static <I extends Iface> java.util.Map<java.lang.String,  "
+                        "org.apache.thrift.ProcessFunction<I, ? extends org.apache.thrift.TBase>> "
+                        "getProcessMap(java.util.Map<java.lang.String, org.apache.thrift.ProcessFunction<I, ? extends "
+                        " org.apache.thrift.TBase>> processMap) {" << endl;
+  indent_up();
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    indent(f_service_) << "processMap.put(\"" << (*f_iter)->get_name() << "\", new "
+                       << (*f_iter)->get_name() << "());" << endl;
+  }
+  indent(f_service_) << "return processMap;" << endl;
+  indent_down();
+  indent(f_service_) << "}" << endl << endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl << endl;
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_java_generator::generate_service_async_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  // Extends stuff
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() == NULL) {
+    extends_processor = "org.apache.thrift.TBaseAsyncProcessor<I>";
+  } else {
+    extends = type_name(tservice->get_extends());
+    extends_processor = extends + ".AsyncProcessor<I>";
+  }
+
+  // Generate the header portion
+  indent(f_service_) << "public static class AsyncProcessor<I extends AsyncIface> extends "
+                     << extends_processor << " {" << endl;
+  indent_up();
+
+  indent(f_service_) << "private static final org.slf4j.Logger _LOGGER = "
+                        "org.slf4j.LoggerFactory.getLogger(AsyncProcessor.class.getName());" << endl;
+
+  indent(f_service_) << "public AsyncProcessor(I iface) {" << endl;
+  indent(f_service_) << "  super(iface, getProcessMap(new java.util.HashMap<java.lang.String, "
+                        "org.apache.thrift.AsyncProcessFunction<I, ? extends "
+                        "org.apache.thrift.TBase, ?>>()));" << endl;
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "protected AsyncProcessor(I iface, java.util.Map<java.lang.String,  "
+                        "org.apache.thrift.AsyncProcessFunction<I, ? extends  "
+                        "org.apache.thrift.TBase, ?>> processMap) {" << endl;
+  indent(f_service_) << "  super(iface, getProcessMap(processMap));" << endl;
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "private static <I extends AsyncIface> java.util.Map<java.lang.String,  "
+                        "org.apache.thrift.AsyncProcessFunction<I, ? extends  "
+                        "org.apache.thrift.TBase,?>> getProcessMap(java.util.Map<java.lang.String,  "
+                        "org.apache.thrift.AsyncProcessFunction<I, ? extends  "
+                        "org.apache.thrift.TBase, ?>> processMap) {" << endl;
+  indent_up();
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    indent(f_service_) << "processMap.put(\"" << (*f_iter)->get_name() << "\", new "
+                       << (*f_iter)->get_name() << "());" << endl;
+  }
+  indent(f_service_) << "return processMap;" << endl;
+  indent_down();
+  indent(f_service_) << "}" << endl << endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_async_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl << endl;
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_java_generator::generate_function_helpers(t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return;
+  }
+
+  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_java_struct_definition(f_service_, &result, false, true, true);
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_java_generator::generate_process_async_function(t_service* tservice, t_function* tfunction) {
+  string argsname = tfunction->get_name() + "_args";
+
+  string resultname = tfunction->get_name() + "_result";
+  if (tfunction->is_oneway()) {
+    resultname = "org.apache.thrift.TBase";
+  }
+
+  string resulttype = type_name(tfunction->get_returntype(), true);
+
+  (void)tservice;
+  // Open class
+  indent(f_service_) << "public static class " << tfunction->get_name()
+                     << "<I extends AsyncIface> extends org.apache.thrift.AsyncProcessFunction<I, "
+                     << argsname << ", " << resulttype << "> {" << endl;
+  indent_up();
+
+  indent(f_service_) << "public " << tfunction->get_name() << "() {" << endl;
+  indent(f_service_) << "  super(\"" << tfunction->get_name() << "\");" << endl;
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "public " << argsname << " getEmptyArgsInstance() {" << endl;
+  indent(f_service_) << "  return new " << argsname << "();" << endl;
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "public org.apache.thrift.async.AsyncMethodCallback<" << resulttype
+                     << "> getResultHandler(final org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer fb, final int seqid) {" << endl;
+  indent_up();
+  indent(f_service_) << "final org.apache.thrift.AsyncProcessFunction fcall = this;" << endl;
+  indent(f_service_) << "return new org.apache.thrift.async.AsyncMethodCallback<" << resulttype
+                     << ">() { " << endl;
+  indent_up();
+  indent(f_service_) << "public void onComplete(" << resulttype << " o) {" << endl;
+
+  indent_up();
+  if (!tfunction->is_oneway()) {
+    indent(f_service_) << resultname << " result = new " << resultname << "();" << endl;
+
+    if (!tfunction->get_returntype()->is_void()) {
+      indent(f_service_) << "result.success = o;" << endl;
+      // Set isset on success field
+      if (!type_can_be_null(tfunction->get_returntype())) {
+        indent(f_service_) << "result.set" << get_cap_name("success") << get_cap_name("isSet")
+                           << "(true);" << endl;
+      }
+    }
+
+    indent(f_service_) << "try {" << endl;
+    indent(f_service_)
+        << "  fcall.sendResponse(fb, result, org.apache.thrift.protocol.TMessageType.REPLY,seqid);"
+        << endl;
+    indent(f_service_) << "} catch (org.apache.thrift.transport.TTransportException e) {" << endl;
+    indent_up();
+    f_service_ << indent()
+               << "_LOGGER.error(\"TTransportException writing to internal frame buffer\", e);"
+               << endl
+               << indent() << "fb.close();" << endl;
+    indent_down();
+    indent(f_service_) << "} catch (java.lang.Exception e) {" << endl;
+    indent_up();
+    f_service_ << indent() << "_LOGGER.error(\"Exception writing to internal frame buffer\", e);"
+               << endl
+               << indent() << "onError(e);" << endl;
+    indent_down();
+    indent(f_service_) << "}" << endl;
+  }
+  indent_down();
+  indent(f_service_) << "}" << endl;
+
+  indent(f_service_) << "public void onError(java.lang.Exception e) {" << endl;
+  indent_up();
+
+  if (tfunction->is_oneway()) {
+    indent(f_service_) << "if (e instanceof org.apache.thrift.transport.TTransportException) {"
+                       << endl;
+    indent_up();
+
+    f_service_ << indent() << "_LOGGER.error(\"TTransportException inside handler\", e);" << endl
+               << indent() << "fb.close();" << endl;
+
+    indent_down();
+    indent(f_service_) << "} else {" << endl;
+    indent_up();
+
+    f_service_ << indent() << "_LOGGER.error(\"Exception inside oneway handler\", e);" << endl;
+
+    indent_down();
+    indent(f_service_) << "}" << endl;
+  } else {
+    indent(f_service_) << "byte msgType = org.apache.thrift.protocol.TMessageType.REPLY;" << endl;
+    indent(f_service_) << "org.apache.thrift.TSerializable msg;" << endl;
+    indent(f_service_) << resultname << " result = new " << resultname << "();" << endl;
+
+    t_struct* xs = tfunction->get_xceptions();
+    const std::vector<t_field*>& xceptions = xs->get_members();
+
+    vector<t_field*>::const_iterator x_iter;
+    if (xceptions.size() > 0) {
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        if (x_iter == xceptions.begin())
+          f_service_ << indent();
+        string type = type_name((*x_iter)->get_type(), false, false);
+        string name = (*x_iter)->get_name();
+        f_service_ << "if (e instanceof " << type << ") {" << endl;
+        indent_up();
+        f_service_ << indent() << "result." << name << " = (" << type << ") e;" << endl
+                   << indent() << "result.set" << get_cap_name(name) << get_cap_name("isSet")
+                   << "(true);" << endl
+                   << indent() << "msg = result;" << endl;
+        indent_down();
+        indent(f_service_) << "} else ";
+      }
+    } else {
+      indent(f_service_);
+    }
+    f_service_ << "if (e instanceof org.apache.thrift.transport.TTransportException) {" << endl;
+    indent_up();
+    f_service_ << indent() << "_LOGGER.error(\"TTransportException inside handler\", e);" << endl
+               << indent() << "fb.close();" << endl
+               << indent() << "return;" << endl;
+    indent_down();
+    indent(f_service_) << "} else if (e instanceof org.apache.thrift.TApplicationException) {"
+                       << endl;
+    indent_up();
+    f_service_ << indent() << "_LOGGER.error(\"TApplicationException inside handler\", e);" << endl
+               << indent() << "msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;" << endl
+               << indent() << "msg = (org.apache.thrift.TApplicationException)e;" << endl;
+    indent_down();
+    indent(f_service_) << "} else {" << endl;
+    indent_up();
+    f_service_ << indent() << "_LOGGER.error(\"Exception inside handler\", e);" << endl
+               << indent() << "msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;" << endl
+               << indent() << "msg = new "
+                              "org.apache.thrift.TApplicationException(org.apache.thrift."
+                              "TApplicationException.INTERNAL_ERROR, e.getMessage());"
+               << endl;
+    indent_down();
+    f_service_ << indent() << "}" << endl
+               << indent() << "try {" << endl
+               << indent() << "  fcall.sendResponse(fb,msg,msgType,seqid);" << endl
+               << indent() << "} catch (java.lang.Exception ex) {" << endl
+               << indent() << "  _LOGGER.error(\"Exception writing to internal frame buffer\", ex);"
+               << endl
+               << indent() << "  fb.close();" << endl
+               << indent() << "}" << endl;
+  }
+  indent_down();
+  indent(f_service_) << "}" << endl;
+  indent_down();
+  indent(f_service_) << "};" << endl;
+  indent_down();
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "protected boolean isOneway() {" << endl;
+  indent(f_service_) << "  return " << ((tfunction->is_oneway()) ? "true" : "false") << ";" << endl;
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "public void start(I iface, " << argsname
+                     << " args, org.apache.thrift.async.AsyncMethodCallback<" << resulttype
+                     << "> resultHandler) throws org.apache.thrift.TException {" << endl;
+  indent_up();
+
+  // 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_ << indent();
+
+  f_service_ << "iface." << get_rpc_method_name(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." << (*f_iter)->get_name();
+  }
+  if (!first)
+    f_service_ << ",";
+  f_service_ << "resultHandler";
+  f_service_ << ");" << endl;
+
+  indent_down();
+  indent(f_service_) << "}";
+
+  // Close function
+  f_service_ << endl;
+
+  // Close class
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_java_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  string argsname = tfunction->get_name() + "_args";
+  string resultname = tfunction->get_name() + "_result";
+  if (tfunction->is_oneway()) {
+    resultname = "org.apache.thrift.TBase";
+  }
+
+  (void)tservice;
+  // Open class
+  indent(f_service_) << "public static class " << tfunction->get_name()
+                     << "<I extends Iface> extends org.apache.thrift.ProcessFunction<I, "
+                     << argsname << "> {" << endl;
+  indent_up();
+
+  indent(f_service_) << "public " << tfunction->get_name() << "() {" << endl;
+  indent(f_service_) << "  super(\"" << tfunction->get_name() << "\");" << endl;
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "public " << argsname << " getEmptyArgsInstance() {" << endl;
+  indent(f_service_) << "  return new " << argsname << "();" << endl;
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "protected boolean isOneway() {" << endl;
+  indent(f_service_) << "  return " << ((tfunction->is_oneway()) ? "true" : "false") << ";" << endl;
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "@Override" << endl;
+  indent(f_service_) << "protected boolean rethrowUnhandledExceptions() {" << endl;
+  indent(f_service_) << "  return " << ((rethrow_unhandled_exceptions_) ? "true" : "false") << ";" << endl;
+  indent(f_service_) << "}" << endl << endl;
+
+  indent(f_service_) << "public " << resultname << " getResult(I iface, " << argsname
+                     << " args) throws org.apache.thrift.TException {" << endl;
+  indent_up();
+  if (!tfunction->is_oneway()) {
+    indent(f_service_) << resultname << " result = new " << resultname << "();" << endl;
+  }
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Try block for a function with exceptions
+  if (xceptions.size() > 0) {
+    f_service_ << indent() << "try {" << endl;
+    indent_up();
+  }
+
+  // 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_ << indent();
+
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "result.success = ";
+  }
+  f_service_ << "iface." << get_rpc_method_name(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." << (*f_iter)->get_name();
+  }
+  f_service_ << ");" << endl;
+
+  // Set isset on success field
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()
+      && !type_can_be_null(tfunction->get_returntype())) {
+    indent(f_service_) << "result.set" << get_cap_name("success") << get_cap_name("isSet")
+                       << "(true);" << endl;
+  }
+
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    indent_down();
+    f_service_ << indent() << "}";
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " "
+                 << (*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();
+        f_service_ << indent() << "}";
+      } else {
+        f_service_ << "}";
+      }
+    }
+    f_service_ << endl;
+  }
+
+  if (tfunction->is_oneway()) {
+    indent(f_service_) << "return null;" << endl;
+  } else {
+    indent(f_service_) << "return result;" << endl;
+  }
+  indent_down();
+  indent(f_service_) << "}";
+
+  // Close function
+  f_service_ << endl;
+
+  // Close class
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+/**
+ * Deserializes a field of any type.
+ *
+ * @param tfield The field
+ * @param prefix The variable name or container for this field
+ */
+void t_java_generator::generate_deserialize_field(ostream& out,
+                                                  t_field* tfield,
+                                                  string prefix,
+                                                  bool has_metadata) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name();
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name, has_metadata);
+  } else if (type->is_base_type()) {
+    indent(out) << name << " = iprot.";
+
+    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:
+      if (type->is_binary()) {
+        out << "readBinary();";
+      } else {
+        out << "readString();";
+      }
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << "readBool();";
+      break;
+    case t_base_type::TYPE_I8:
+      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 Java name for base type " + t_base_type::t_base_name(tbase);
+    }
+    out << endl;
+  } else if (type->is_enum()) {
+    indent(out) << name << " = "
+                << type_name(tfield->get_type(), true, false, false, true)
+                   + ".findByValue(iprot.readI32());" << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a struct, invokes read()
+ */
+void t_java_generator::generate_deserialize_struct(ostream& out,
+                                                   t_struct* tstruct,
+                                                   string prefix) {
+
+  if (reuse_objects_) {
+    indent(out) << "if (" << prefix << " == null) {" << endl;
+    indent_up();
+  }
+  indent(out) << prefix << " = new " << type_name(tstruct) << "();" << endl;
+  if (reuse_objects_) {
+    indent_down();
+    indent(out) << "}" << endl;
+  }
+  indent(out) << prefix << ".read(iprot);" << endl;
+}
+
+/**
+ * Deserializes a container by reading its size and then iterating
+ */
+void t_java_generator::generate_deserialize_container(ostream& out,
+                                                      t_type* ttype,
+                                                      string prefix,
+                                                      bool has_metadata) {
+
+  scope_up(out);
+
+  string obj;
+
+  if (ttype->is_map()) {
+    obj = tmp("_map");
+  } else if (ttype->is_set()) {
+    obj = tmp("_set");
+  } else if (ttype->is_list()) {
+    obj = tmp("_list");
+  }
+
+  if (has_metadata) {
+    // Declare variables, read header
+    if (ttype->is_map()) {
+      indent(out) << "org.apache.thrift.protocol.TMap " << obj << " = iprot.readMapBegin();"
+                  << endl;
+    } else if (ttype->is_set()) {
+      indent(out) << "org.apache.thrift.protocol.TSet " << obj << " = iprot.readSetBegin();"
+                  << endl;
+    } else if (ttype->is_list()) {
+      indent(out) << "org.apache.thrift.protocol.TList " << obj << " = iprot.readListBegin();"
+                  << endl;
+    }
+  } else {
+    // Declare variables, read header
+    if (ttype->is_map()) {
+      indent(out) << "org.apache.thrift.protocol.TMap " << obj
+                  << " = new org.apache.thrift.protocol.TMap("
+                  << type_to_enum(((t_map*)ttype)->get_key_type()) << ", "
+                  << type_to_enum(((t_map*)ttype)->get_val_type()) << ", "
+                  << "iprot.readI32());" << endl;
+    } else if (ttype->is_set()) {
+      indent(out) << "org.apache.thrift.protocol.TSet " << obj
+                  << " = new org.apache.thrift.protocol.TSet("
+                  << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", iprot.readI32());"
+                  << endl;
+    } else if (ttype->is_list()) {
+      indent(out) << "org.apache.thrift.protocol.TList " << obj
+                  << " = new org.apache.thrift.protocol.TList("
+                  << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", iprot.readI32());"
+                  << endl;
+    }
+  }
+
+  if (reuse_objects_) {
+    indent(out) << "if (" << prefix << " == null) {" << endl;
+    indent_up();
+  }
+
+  if (is_enum_set(ttype)) {
+    out << indent() << prefix << " = " << type_name(ttype, false, true, true) << ".noneOf";
+  } else {
+    out << indent() << prefix << " = new " << type_name(ttype, false, true);
+  }
+
+  // construct the collection correctly i.e. with appropriate size/type
+  if (is_enum_set(ttype) || is_enum_map(ttype)) {
+    out << "(" << inner_enum_type_name(ttype) << ");" << endl;
+  } else if (sorted_containers_ && (ttype->is_map() || ttype->is_set())) {
+    // TreeSet and TreeMap don't have any constructor which takes a capacity as an argument
+    out << "();" << endl;
+  } else {
+    out << "(" << (ttype->is_list() ? "" : "2*") << obj << ".size"
+        << ");" << endl;
+  }
+
+  if (reuse_objects_) {
+    indent_down();
+    indent(out) << "}" << endl;
+  }
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix, obj, has_metadata);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix, obj, has_metadata);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix, obj, has_metadata);
+  }
+
+  scope_down(out);
+
+  if (has_metadata) {
+    // Read container end
+    if (ttype->is_map()) {
+      indent(out) << "iprot.readMapEnd();" << endl;
+    } else if (ttype->is_set()) {
+      indent(out) << "iprot.readSetEnd();" << endl;
+    } else if (ttype->is_list()) {
+      indent(out) << "iprot.readListEnd();" << endl;
+    }
+  }
+  scope_down(out);
+}
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_java_generator::generate_deserialize_map_element(ostream& out,
+                                                        t_map* tmap,
+                                                        string prefix,
+                                                        string obj,
+                                                        bool has_metadata) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) << declare_field(&fkey, reuse_objects_, false) << endl;
+  indent(out) << declare_field(&fval, reuse_objects_, false) << endl;
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size"
+              << "; "
+              << "++" << i << ")" << endl;
+
+  scope_up(out);
+
+  generate_deserialize_field(out, &fkey, "", has_metadata);
+  generate_deserialize_field(out, &fval, "", has_metadata);
+
+  if (get_true_type(fkey.get_type())->is_enum()) {
+    indent(out) << "if (" << key << " != null)" << endl;
+    scope_up(out);
+  }
+
+  indent(out) << prefix << ".put(" << key << ", " << val << ");" << endl;
+
+  if (get_true_type(fkey.get_type())->is_enum()) {
+    scope_down(out);
+  }
+
+  if (reuse_objects_ && !get_true_type(fkey.get_type())->is_base_type()) {
+    indent(out) << key << " = null;" << endl;
+  }
+
+  if (reuse_objects_ && !get_true_type(fval.get_type())->is_base_type()) {
+    indent(out) << val << " = null;" << endl;
+  }
+}
+
+/**
+ * Deserializes a set element
+ */
+void t_java_generator::generate_deserialize_set_element(ostream& out,
+                                                        t_set* tset,
+                                                        string prefix,
+                                                        string obj,
+                                                        bool has_metadata) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem, reuse_objects_, false) << endl;
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size"
+              << "; "
+              << "++" << i << ")" << endl;
+  scope_up(out);
+
+  generate_deserialize_field(out, &felem, "", has_metadata);
+
+  if (get_true_type(felem.get_type())->is_enum()) {
+    indent(out) << "if (" << elem << " != null)" << endl;
+    scope_up(out);
+  }
+
+  indent(out) << prefix << ".add(" << elem << ");" << endl;
+
+  if (get_true_type(felem.get_type())->is_enum()) {
+    scope_down(out);
+  }
+
+  if (reuse_objects_ && !get_true_type(felem.get_type())->is_base_type()) {
+    indent(out) << elem << " = null;" << endl;
+  }
+}
+
+/**
+ * Deserializes a list element
+ */
+void t_java_generator::generate_deserialize_list_element(ostream& out,
+                                                         t_list* tlist,
+                                                         string prefix,
+                                                         string obj,
+                                                         bool has_metadata) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem, reuse_objects_, false) << endl;
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size"
+              << "; "
+              << "++" << i << ")" << endl;
+  scope_up(out);
+
+  generate_deserialize_field(out, &felem, "", has_metadata);
+
+  if (get_true_type(felem.get_type())->is_enum()) {
+    indent(out) << "if (" << elem << " != null)" << endl;
+    scope_up(out);
+  }
+
+  indent(out) << prefix << ".add(" << elem << ");" << endl;
+
+  if (get_true_type(felem.get_type())->is_enum()) {
+    scope_down(out);
+  }
+
+  if (reuse_objects_ && !get_true_type(felem.get_type())->is_base_type()) {
+    indent(out) << elem << " = null;" << endl;
+  }
+}
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_java_generator::generate_serialize_field(ostream& out,
+                                                t_field* tfield,
+                                                string prefix,
+                                                bool has_metadata) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name());
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, prefix + tfield->get_name(), has_metadata);
+  } else if (type->is_enum()) {
+    indent(out) << "oprot.writeI32(" << prefix + tfield->get_name() << ".getValue());" << endl;
+  } else if (type->is_base_type()) {
+    string name = prefix + tfield->get_name();
+    indent(out) << "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:
+        if (type->is_binary()) {
+          out << "writeBinary(" << name << ");";
+        } else {
+          out << "writeString(" << name << ");";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ");";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "writeByte(" << name << ");";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16(" << name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32(" << name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64(" << name << ");";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble(" << name << ");";
+        break;
+      default:
+        throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32(struct." << name << ");";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_java_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  (void)tstruct;
+  out << indent() << prefix << ".write(oprot);" << endl;
+}
+
+/**
+ * Serializes a container by writing its size then the elements.
+ *
+ * @param ttype  The type of container
+ * @param prefix String prefix for fields
+ */
+void t_java_generator::generate_serialize_container(ostream& out,
+                                                    t_type* ttype,
+                                                    string prefix,
+                                                    bool has_metadata) {
+  scope_up(out);
+
+  if (has_metadata) {
+    if (ttype->is_map()) {
+      indent(out) << "oprot.writeMapBegin(new org.apache.thrift.protocol.TMap("
+                  << type_to_enum(((t_map*)ttype)->get_key_type()) << ", "
+                  << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix << ".size()));"
+                  << endl;
+    } else if (ttype->is_set()) {
+      indent(out) << "oprot.writeSetBegin(new org.apache.thrift.protocol.TSet("
+                  << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix
+                  << ".size()));" << endl;
+    } else if (ttype->is_list()) {
+      indent(out) << "oprot.writeListBegin(new org.apache.thrift.protocol.TList("
+                  << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix
+                  << ".size()));" << endl;
+    }
+  } else {
+    indent(out) << "oprot.writeI32(" << prefix << ".size());" << endl;
+  }
+
+  string iter = tmp("_iter");
+  if (ttype->is_map()) {
+    indent(out) << "for (java.util.Map.Entry<" << type_name(((t_map*)ttype)->get_key_type(), true, false)
+                << ", " << type_name(((t_map*)ttype)->get_val_type(), true, false) << "> " << iter
+                << " : " << prefix << ".entrySet())";
+  } else if (ttype->is_set()) {
+    indent(out) << "for (" << type_name(((t_set*)ttype)->get_elem_type()) << " " << iter << " : "
+                << prefix << ")";
+  } else if (ttype->is_list()) {
+    indent(out) << "for (" << type_name(((t_list*)ttype)->get_elem_type()) << " " << iter << " : "
+                << prefix << ")";
+  }
+
+  out << endl;
+  scope_up(out);
+  if (ttype->is_map()) {
+    generate_serialize_map_element(out, (t_map*)ttype, iter, prefix, has_metadata);
+  } else if (ttype->is_set()) {
+    generate_serialize_set_element(out, (t_set*)ttype, iter, has_metadata);
+  } else if (ttype->is_list()) {
+    generate_serialize_list_element(out, (t_list*)ttype, iter, has_metadata);
+  }
+  scope_down(out);
+
+  if (has_metadata) {
+    if (ttype->is_map()) {
+      indent(out) << "oprot.writeMapEnd();" << endl;
+    } else if (ttype->is_set()) {
+      indent(out) << "oprot.writeSetEnd();" << endl;
+    } else if (ttype->is_list()) {
+      indent(out) << "oprot.writeListEnd();" << endl;
+    }
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ */
+void t_java_generator::generate_serialize_map_element(ostream& out,
+                                                      t_map* tmap,
+                                                      string iter,
+                                                      string map,
+                                                      bool has_metadata) {
+  (void)map;
+  t_field kfield(tmap->get_key_type(), iter + ".getKey()");
+  generate_serialize_field(out, &kfield, "", has_metadata);
+  t_field vfield(tmap->get_val_type(), iter + ".getValue()");
+  generate_serialize_field(out, &vfield, "", has_metadata);
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_java_generator::generate_serialize_set_element(ostream& out,
+                                                      t_set* tset,
+                                                      string iter,
+                                                      bool has_metadata) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "", has_metadata);
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_java_generator::generate_serialize_list_element(ostream& out,
+                                                       t_list* tlist,
+                                                       string iter,
+                                                       bool has_metadata) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "", has_metadata);
+}
+
+/**
+ * Returns a Java type name
+ *
+ * @param ttype The type
+ * @param container Is the type going inside a container?
+ * @return Java type name, i.e. java.util.HashMap<Key,Value>
+ */
+string t_java_generator::type_name(t_type* ttype,
+                                   bool in_container,
+                                   bool in_init,
+                                   bool skip_generic,
+                                   bool force_namespace) {
+  // In Java typedefs are just resolved to their real type
+  ttype = get_true_type(ttype);
+  string prefix;
+
+  if (ttype->is_base_type()) {
+    return base_type_name((t_base_type*)ttype, in_container);
+  } else if (ttype->is_map()) {
+    t_map* tmap = (t_map*)ttype;
+    if (in_init) {
+      if (is_enum_map(tmap)) {
+        prefix = "java.util.EnumMap";
+      } else if (sorted_containers_) {
+        prefix = "java.util.TreeMap";
+      } else {
+        prefix = "java.util.HashMap";
+      }
+    } else {
+      prefix = "java.util.Map";
+    }
+    return prefix + (skip_generic ? "" : "<" + type_name(tmap->get_key_type(), true) + ","
+                                         + type_name(tmap->get_val_type(), true) + ">");
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*)ttype;
+    if (in_init) {
+      if (is_enum_set(tset)) {
+        prefix = "java.util.EnumSet";
+      } else if (sorted_containers_) {
+        prefix = "java.util.TreeSet";
+      } else {
+        prefix = "java.util.HashSet";
+      }
+    } else {
+      prefix = "java.util.Set";
+    }
+    return prefix + (skip_generic ? "" : "<" + type_name(tset->get_elem_type(), true) + ">");
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*)ttype;
+    if (in_init) {
+      prefix = "java.util.ArrayList";
+    } else {
+      prefix = "java.util.List";
+    }
+    return prefix + (skip_generic ? "" : "<" + type_name(tlist->get_elem_type(), true) + ">");
+  }
+
+  // Check for namespacing
+  t_program* program = ttype->get_program();
+  if ((program != NULL) && ((program != program_) || force_namespace)) {
+    string package = program->get_namespace("java");
+    if (!package.empty()) {
+      return package + "." + ttype->get_name();
+    }
+  }
+
+  return ttype->get_name();
+}
+
+/**
+ * Returns the Java type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ * @param container Is it going in a Java container?
+ */
+string t_java_generator::base_type_name(t_base_type* type, bool in_container) {
+  t_base_type::t_base tbase = type->get_base();
+
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return (in_container ? "Void" : "void");
+  case t_base_type::TYPE_STRING:
+    if (type->is_binary()) {
+      return "java.nio.ByteBuffer";
+    } else {
+      return "java.lang.String";
+    }
+  case t_base_type::TYPE_BOOL:
+    return (in_container ? "java.lang.Boolean" : "boolean");
+  case t_base_type::TYPE_I8:
+    return (in_container ? "java.lang.Byte" : "byte");
+  case t_base_type::TYPE_I16:
+    return (in_container ? "java.lang.Short" : "short");
+  case t_base_type::TYPE_I32:
+    return (in_container ? "java.lang.Integer" : "int");
+  case t_base_type::TYPE_I64:
+    return (in_container ? "java.lang.Long" : "long");
+  case t_base_type::TYPE_DOUBLE:
+    return (in_container ? "java.lang.Double" : "double");
+  default:
+    throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param tfield The field
+ * @param init Whether to initialize the field
+ */
+string t_java_generator::declare_field(t_field* tfield, bool init, bool comment) {
+  // TODO(mcslee): do we ever need to initialize the field?
+  string result = "";
+  t_type* ttype = get_true_type(tfield->get_type());
+  if (type_can_be_null(ttype)) {
+    result += java_nullable_annotation() + " ";
+  }
+  result += type_name(tfield->get_type()) + " " + tfield->get_name();
+  if (init) {
+    if (ttype->is_base_type() && tfield->get_value() != NULL) {
+      std::ofstream dummy;
+      result += " = " + render_const_value(dummy, ttype, tfield->get_value());
+    } else if (ttype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "NO T_VOID CONSTRUCT";
+      case t_base_type::TYPE_STRING:
+        result += " = null";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = false";
+        break;
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = (double)0";
+        break;
+      }
+    } else if (ttype->is_enum()) {
+      result += " = null";
+    } else if (ttype->is_container()) {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    } else {
+      result += " = new " + type_name(ttype, false, true) + "()";
+      ;
+    }
+  }
+  result += ";";
+  if (comment) {
+    result += " // ";
+    if (tfield->get_req() == t_field::T_OPTIONAL) {
+      result += "optional";
+    } else {
+      result += "required";
+    }
+  }
+  return result;
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_java_generator::function_signature(t_function* tfunction, string prefix) {
+  t_type* ttype = tfunction->get_returntype();
+  std::string fn_name = get_rpc_method_name(tfunction->get_name());
+  std::string result = type_name(ttype) + " " + prefix + fn_name + "("
+                       + argument_list(tfunction->get_arglist()) + ") throws ";
+  t_struct* xs = tfunction->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) {
+    result += type_name((*x_iter)->get_type(), false, false) + ", ";
+  }
+  result += "org.apache.thrift.TException";
+  return result;
+}
+
+/**
+ * Renders a function signature of the form 'void name(args, resultHandler)'
+ *
+ * @params tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_java_generator::function_signature_async(t_function* tfunction,
+                                                  bool use_base_method,
+                                                  string prefix) {
+  std::string arglist = async_function_call_arglist(tfunction, use_base_method, true);
+
+  std::string ret_type = "";
+  if (use_base_method) {
+    ret_type += "AsyncClient.";
+  }
+  ret_type += tfunction->get_name() + "_call";
+
+  std::string fn_name = get_rpc_method_name(tfunction->get_name());
+
+  std::string result = prefix + "void " + fn_name + "(" + arglist + ")";
+  return result;
+}
+
+string t_java_generator::async_function_call_arglist(t_function* tfunc,
+                                                     bool use_base_method,
+                                                     bool include_types) {
+  (void)use_base_method;
+  std::string arglist = "";
+  if (tfunc->get_arglist()->get_members().size() > 0) {
+    arglist = argument_list(tfunc->get_arglist(), include_types) + ", ";
+  }
+
+  if (include_types) {
+    arglist += "org.apache.thrift.async.AsyncMethodCallback<";
+    arglist += type_name(tfunc->get_returntype(), true) + "> ";
+  }
+  arglist += "resultHandler";
+
+  return arglist;
+}
+
+/**
+ * Renders a comma separated field list, with type names
+ */
+string t_java_generator::argument_list(t_struct* tstruct, bool include_types) {
+  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 += ", ";
+    }
+    if (include_types) {
+      result += type_name((*f_iter)->get_type()) + " ";
+    }
+    result += (*f_iter)->get_name();
+  }
+  return result;
+}
+
+string t_java_generator::async_argument_list(t_function* tfunct,
+                                             t_struct* tstruct,
+                                             t_type* ttype,
+                                             bool include_types) {
+  (void)tfunct;
+  (void)ttype;
+  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 += ", ";
+    }
+    if (include_types) {
+      result += type_name((*f_iter)->get_type()) + " ";
+    }
+    result += (*f_iter)->get_name();
+  }
+  if (!first) {
+    result += ", ";
+  }
+  if (include_types) {
+    result += "org.apache.thrift.async.AsyncMethodCallback<";
+    result += type_name(tfunct->get_returntype(), true) + "> ";
+  }
+  result += "resultHandler";
+  return result;
+}
+
+/**
+ * Converts the parse type to a Java enum string for the given type.
+ */
+string t_java_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 "org.apache.thrift.protocol.TType.STRING";
+    case t_base_type::TYPE_BOOL:
+      return "org.apache.thrift.protocol.TType.BOOL";
+    case t_base_type::TYPE_I8:
+      return "org.apache.thrift.protocol.TType.BYTE";
+    case t_base_type::TYPE_I16:
+      return "org.apache.thrift.protocol.TType.I16";
+    case t_base_type::TYPE_I32:
+      return "org.apache.thrift.protocol.TType.I32";
+    case t_base_type::TYPE_I64:
+      return "org.apache.thrift.protocol.TType.I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "org.apache.thrift.protocol.TType.DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "org.apache.thrift.protocol.TType.I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "org.apache.thrift.protocol.TType.STRUCT";
+  } else if (type->is_map()) {
+    return "org.apache.thrift.protocol.TType.MAP";
+  } else if (type->is_set()) {
+    return "org.apache.thrift.protocol.TType.SET";
+  } else if (type->is_list()) {
+    return "org.apache.thrift.protocol.TType.LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Takes a name and produes a valid Java source file name from it
+ *
+ * @param fromName The name which shall become a valid Java source file name
+ * @return The produced identifier
+ */
+std::string t_java_generator::make_valid_java_filename(std::string const& fromName) {
+  // if any further rules apply to source file names in Java, modify as necessary
+  return make_valid_java_identifier(fromName);
+}
+
+/**
+ * Takes a name and produes a valid Java identifier from it
+ *
+ * @param fromName The name which shall become a valid Java identifier
+ * @return The produced identifier
+ */
+std::string t_java_generator::make_valid_java_identifier(std::string const& fromName) {
+  std::string str = fromName;
+  if (str.empty()) {
+    return str;
+  }
+
+  // tests rely on this
+  assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
+
+  // if the first letter is a number, we add an additional underscore in front of it
+  char c = str.at(0);
+  if (('0' <= c) && (c <= '9')) {
+    str = "_" + str;
+  }
+
+  // following chars: letter, number or underscore
+  for (size_t i = 0; i < str.size(); ++i) {
+    c = str.at(i);
+    if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9'))
+        && ('_' != c)) {
+      str.replace(i, 1, "_");
+    }
+  }
+
+  return str;
+}
+
+std::string t_java_generator::as_camel_case(std::string name, bool ucfirst) {
+  std::string new_name;
+  size_t i = 0;
+  for (i = 0; i < name.size(); i++) {
+    if (name[i] != '_')
+      break;
+  }
+  if (ucfirst) {
+    new_name += toupper(name[i++]);
+  } else {
+    new_name += tolower(name[i++]);
+  }
+  for (; i < name.size(); i++) {
+    if (name[i] == '_') {
+      if (i < name.size() - 1) {
+        i++;
+        new_name += toupper(name[i]);
+      }
+    } else {
+      new_name += name[i];
+    }
+  }
+  return new_name;
+}
+
+std::string t_java_generator::get_rpc_method_name(std::string name) {
+  if (fullcamel_style_) {
+    return as_camel_case(name, false);
+  } else {
+    return name;
+  }
+}
+
+/**
+ * Applies the correct style to a string based on the value of nocamel_style_
+ * and/or fullcamel_style_
+ */
+std::string t_java_generator::get_cap_name(std::string name) {
+  if (nocamel_style_) {
+    return "_" + name;
+  } else if (fullcamel_style_) {
+    return as_camel_case(name);
+  } else {
+    name[0] = toupper(name[0]);
+    return name;
+  }
+}
+
+string t_java_generator::constant_name(string name) {
+  string constant_name;
+
+  bool is_first = true;
+  bool was_previous_char_upper = false;
+  for (string::iterator iter = name.begin(); iter != name.end(); ++iter) {
+    string::value_type character = (*iter);
+
+    bool is_upper = isupper(character);
+
+    if (is_upper && !is_first && !was_previous_char_upper) {
+      constant_name += '_';
+    }
+    constant_name += toupper(character);
+
+    is_first = false;
+    was_previous_char_upper = is_upper;
+  }
+
+  return constant_name;
+}
+
+void t_java_generator::generate_deep_copy_container(ostream& out,
+                                                    std::string source_name_p1,
+                                                    std::string source_name_p2,
+                                                    std::string result_name,
+                                                    t_type* type) {
+
+  t_container* container = (t_container*)type;
+  std::string source_name;
+  if (source_name_p2 == "")
+    source_name = source_name_p1;
+  else
+    source_name = source_name_p1 + "." + source_name_p2;
+
+  bool copy_construct_container;
+  if (container->is_map()) {
+    t_map* tmap = (t_map*)container;
+    copy_construct_container = tmap->get_key_type()->is_base_type()
+                               && tmap->get_val_type()->is_base_type();
+  } else {
+    t_type* elem_type = container->is_list() ? ((t_list*)container)->get_elem_type()
+                                             : ((t_set*)container)->get_elem_type();
+    copy_construct_container = elem_type->is_base_type();
+  }
+
+  if (copy_construct_container) {
+    // deep copy of base types can be done much more efficiently than iterating over all the
+    // elements manually
+    indent(out) << type_name(type, true, false) << " " << result_name << " = new "
+                << type_name(container, false, true) << "(" << source_name << ");" << endl;
+    return;
+  }
+
+  std::string constructor_args;
+  if (is_enum_set(container) || is_enum_map(container)) {
+    constructor_args = inner_enum_type_name(container);
+  } else if (!(sorted_containers_ && (container->is_map() || container->is_set()))) {
+    // unsorted containers accept a capacity value
+    constructor_args = source_name + ".size()";
+  }
+
+  if (is_enum_set(container)) {
+    indent(out) << type_name(type, true, false) << " " << result_name << " = "
+                << type_name(container, false, true, true) << ".noneOf(" << constructor_args << ");" << endl;
+  } else {
+    indent(out) << type_name(type, true, false) << " " << result_name << " = new "
+                << type_name(container, false, true) << "(" << constructor_args << ");" << endl;
+  }
+
+  std::string iterator_element_name = source_name_p1 + "_element";
+  std::string result_element_name = result_name + "_copy";
+
+  if (container->is_map()) {
+    t_type* key_type = ((t_map*)container)->get_key_type();
+    t_type* val_type = ((t_map*)container)->get_val_type();
+
+    indent(out) << "for (java.util.Map.Entry<" << type_name(key_type, true, false) << ", "
+                << type_name(val_type, true, false) << "> " << iterator_element_name << " : "
+                << source_name << ".entrySet()) {" << endl;
+    indent_up();
+
+    out << endl;
+
+    indent(out) << type_name(key_type, true, false) << " " << iterator_element_name
+                << "_key = " << iterator_element_name << ".getKey();" << endl;
+    indent(out) << type_name(val_type, true, false) << " " << iterator_element_name
+                << "_value = " << iterator_element_name << ".getValue();" << endl;
+
+    out << endl;
+
+    if (key_type->is_container()) {
+      generate_deep_copy_container(out,
+                                   iterator_element_name + "_key",
+                                   "",
+                                   result_element_name + "_key",
+                                   key_type);
+    } else {
+      indent(out) << type_name(key_type, true, false) << " " << result_element_name << "_key = ";
+      generate_deep_copy_non_container(out,
+                                       iterator_element_name + "_key",
+                                       result_element_name + "_key",
+                                       key_type);
+      out << ";" << endl;
+    }
+
+    out << endl;
+
+    if (val_type->is_container()) {
+      generate_deep_copy_container(out,
+                                   iterator_element_name + "_value",
+                                   "",
+                                   result_element_name + "_value",
+                                   val_type);
+    } else {
+      indent(out) << type_name(val_type, true, false) << " " << result_element_name << "_value = ";
+      generate_deep_copy_non_container(out,
+                                       iterator_element_name + "_value",
+                                       result_element_name + "_value",
+                                       val_type);
+      out << ";" << endl;
+    }
+
+    out << endl;
+
+    indent(out) << result_name << ".put(" << result_element_name << "_key, " << result_element_name
+                << "_value);" << endl;
+
+    indent_down();
+    indent(out) << "}" << endl;
+
+  } else {
+    t_type* elem_type;
+
+    if (container->is_set()) {
+      elem_type = ((t_set*)container)->get_elem_type();
+    } else {
+      elem_type = ((t_list*)container)->get_elem_type();
+    }
+
+    indent(out) << "for (" << type_name(elem_type, true, false) << " " << iterator_element_name
+                << " : " << source_name << ") {" << endl;
+
+    indent_up();
+
+    if (elem_type->is_container()) {
+      // recursive deep copy
+      generate_deep_copy_container(out, iterator_element_name, "", result_element_name, elem_type);
+      indent(out) << result_name << ".add(" << result_element_name << ");" << endl;
+    } else {
+      // iterative copy
+      if (elem_type->is_binary()) {
+        indent(out) << "java.nio.ByteBuffer temp_binary_element = ";
+        generate_deep_copy_non_container(out,
+                                         iterator_element_name,
+                                         "temp_binary_element",
+                                         elem_type);
+        out << ";" << endl;
+        indent(out) << result_name << ".add(temp_binary_element);" << endl;
+      } else {
+        indent(out) << result_name << ".add(";
+        generate_deep_copy_non_container(out, iterator_element_name, result_name, elem_type);
+        out << ");" << endl;
+      }
+    }
+
+    indent_down();
+
+    indent(out) << "}" << endl;
+  }
+}
+
+void t_java_generator::generate_deep_copy_non_container(ostream& out,
+                                                        std::string source_name,
+                                                        std::string dest_name,
+                                                        t_type* type) {
+  (void)dest_name;
+  type = get_true_type(type);
+  if (type->is_base_type() || type->is_enum() || type->is_typedef()) {
+    if (type->is_binary()) {
+      out << "org.apache.thrift.TBaseHelper.copyBinary(" << source_name << ")";
+    } else {
+      // everything else can be copied directly
+      out << source_name;
+    }
+  } else {
+    out << "new " << type_name(type, true, true) << "(" << source_name << ")";
+  }
+}
+
+std::string t_java_generator::generate_isset_check(t_field* field) {
+  return generate_isset_check(field->get_name());
+}
+
+std::string t_java_generator::isset_field_id(t_field* field) {
+  return "__" + upcase_string(field->get_name() + "_isset_id");
+}
+
+std::string t_java_generator::generate_isset_check(std::string field_name) {
+  return "is" + get_cap_name("set") + get_cap_name(field_name) + "()";
+}
+
+void t_java_generator::generate_isset_set(ostream& out, t_field* field, string prefix) {
+  if (!type_can_be_null(field->get_type())) {
+    indent(out) << prefix << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet")
+                << "(true);" << endl;
+  }
+}
+
+void t_java_generator::generate_struct_desc(ostream& out, t_struct* tstruct) {
+  indent(out) << "private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new "
+                 "org.apache.thrift.protocol.TStruct(\"" << tstruct->get_name() << "\");" << endl;
+}
+
+void t_java_generator::generate_field_descs(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) << "private static final org.apache.thrift.protocol.TField "
+                << constant_name((*m_iter)->get_name())
+                << "_FIELD_DESC = new org.apache.thrift.protocol.TField(\"" << (*m_iter)->get_name()
+                << "\", " << type_to_enum((*m_iter)->get_type()) << ", "
+                << "(short)" << (*m_iter)->get_key() << ");" << endl;
+  }
+}
+
+void t_java_generator::generate_scheme_map(ostream& out, t_struct* tstruct) {
+  indent(out) << "private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new "
+      << tstruct->get_name() << "StandardSchemeFactory();" << endl;
+  indent(out) << "private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new "
+      << tstruct->get_name() << "TupleSchemeFactory();" << endl;
+}
+
+void t_java_generator::generate_field_name_constants(ostream& out, t_struct* tstruct) {
+  indent(out) << "/** The set of fields this struct contains, along with convenience methods for "
+                 "finding and manipulating them. */" << endl;
+  indent(out) << "public enum _Fields implements org.apache.thrift.TFieldIdEnum {" << endl;
+
+  indent_up();
+  bool first = true;
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if (!first) {
+      out << "," << endl;
+    }
+    first = false;
+    generate_java_doc(out, *m_iter);
+    indent(out) << constant_name((*m_iter)->get_name()) << "((short)" << (*m_iter)->get_key()
+                << ", \"" << (*m_iter)->get_name() << "\")";
+  }
+
+  out << ";" << endl << endl;
+
+  indent(out)
+      << "private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();"
+      << endl;
+  out << endl;
+
+  indent(out) << "static {" << endl;
+  indent(out) << "  for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {" << endl;
+  indent(out) << "    byName.put(field.getFieldName(), field);" << endl;
+  indent(out) << "  }" << endl;
+  indent(out) << "}" << endl << endl;
+
+  indent(out) << "/**" << endl;
+  indent(out) << " * Find the _Fields constant that matches fieldId, or null if its not found."
+              << endl;
+  indent(out) << " */" << endl;
+  indent(out) << java_nullable_annotation() << endl;
+  indent(out) << "public static _Fields findByThriftId(int fieldId) {" << endl;
+  indent_up();
+  indent(out) << "switch(fieldId) {" << endl;
+  indent_up();
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) << "case " << (*m_iter)->get_key() << ": // "
+                << constant_name((*m_iter)->get_name()) << endl;
+    indent(out) << "  return " << constant_name((*m_iter)->get_name()) << ";" << endl;
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  return null;" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  indent(out) << "/**" << endl;
+  indent(out) << " * Find the _Fields constant that matches fieldId, throwing an exception" << endl;
+  indent(out) << " * if it is not found." << endl;
+  indent(out) << " */" << endl;
+  indent(out) << "public static _Fields findByThriftIdOrThrow(int fieldId) {" << endl;
+  indent(out) << "  _Fields fields = findByThriftId(fieldId);" << endl;
+  indent(out) << "  if (fields == null) throw new java.lang.IllegalArgumentException(\"Field \" + fieldId + "
+                 "\" doesn't exist!\");" << endl;
+  indent(out) << "  return fields;" << endl;
+  indent(out) << "}" << endl << endl;
+
+  indent(out) << "/**" << endl;
+  indent(out) << " * Find the _Fields constant that matches name, or null if its not found."
+              << endl;
+  indent(out) << " */" << endl;
+  indent(out) << java_nullable_annotation() << endl;
+  indent(out) << "public static _Fields findByName(java.lang.String name) {" << endl;
+  indent(out) << "  return byName.get(name);" << endl;
+  indent(out) << "}" << endl << endl;
+
+  indent(out) << "private final short _thriftId;" << endl;
+  indent(out) << "private final java.lang.String _fieldName;" << endl << endl;
+
+  indent(out) << "_Fields(short thriftId, java.lang.String fieldName) {" << endl;
+  indent(out) << "  _thriftId = thriftId;" << endl;
+  indent(out) << "  _fieldName = fieldName;" << endl;
+  indent(out) << "}" << endl << endl;
+
+  indent(out) << "public short getThriftFieldId() {" << endl;
+  indent(out) << "  return _thriftId;" << endl;
+  indent(out) << "}" << endl << endl;
+
+  indent(out) << "public java.lang.String getFieldName() {" << endl;
+  indent(out) << "  return _fieldName;" << endl;
+  indent(out) << "}" << endl;
+
+  indent_down();
+
+  indent(out) << "}" << endl;
+}
+
+t_java_generator::isset_type t_java_generator::needs_isset(t_struct* tstruct,
+                                                           std::string* outPrimitiveType) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  int count = 0;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if (!type_can_be_null(get_true_type((*m_iter)->get_type()))) {
+      count++;
+    }
+  }
+  if (count == 0) {
+    return ISSET_NONE;
+  } else if (count <= 64) {
+    if (outPrimitiveType != NULL) {
+      if (count <= 8)
+        *outPrimitiveType = "byte";
+      else if (count <= 16)
+        *outPrimitiveType = "short";
+      else if (count <= 32)
+        *outPrimitiveType = "int";
+      else if (count <= 64)
+        *outPrimitiveType = "long";
+    }
+    return ISSET_PRIMITIVE;
+  } else {
+    return ISSET_BITSET;
+  }
+}
+
+void t_java_generator::generate_java_struct_clear(std::ostream& out, t_struct* tstruct) {
+  if (!java5_) {
+    indent(out) << "@Override" << endl;
+  }
+  indent(out) << "public void clear() {" << endl;
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  indent_up();
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = *m_iter;
+    t_type* t = get_true_type(field->get_type());
+
+    if (field->get_value() != NULL) {
+      print_const_value(out, "this." + field->get_name(), t, field->get_value(), true, true);
+      continue;
+    }
+
+    if (type_can_be_null(t)) {
+
+      if (reuse_objects_ && (t->is_container() || t->is_struct())) {
+        indent(out) << "if (this." << field->get_name() << " != null) {" << endl;
+        indent_up();
+        indent(out) << "this." << field->get_name() << ".clear();" << endl;
+        indent_down();
+        indent(out) << "}" << endl;
+
+      } else {
+
+        indent(out) << "this." << field->get_name() << " = null;" << endl;
+      }
+      continue;
+    }
+
+    // must be a base type
+    // means it also needs to be explicitly unset
+    indent(out) << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet") << "(false);"
+                << endl;
+    t_base_type* base_type = (t_base_type*)t;
+
+    switch (base_type->get_base()) {
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      indent(out) << "this." << field->get_name() << " = 0;" << endl;
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      indent(out) << "this." << field->get_name() << " = 0.0;" << endl;
+      break;
+    case t_base_type::TYPE_BOOL:
+      indent(out) << "this." << field->get_name() << " = false;" << endl;
+      break;
+    default:
+      throw "unsupported type: " + base_type->get_name() + " for field " + field->get_name();
+    }
+  }
+  indent_down();
+
+  indent(out) << "}" << endl << endl;
+}
+
+// generates java method to serialize (in the Java sense) the object
+void t_java_generator::generate_java_struct_write_object(ostream& out, t_struct* tstruct) {
+  (void)tstruct;
+  indent(out)
+      << "private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {"
+      << endl;
+  indent(out) << "  try {" << endl;
+  indent(out) << "    write(new org.apache.thrift.protocol.TCompactProtocol(new "
+                 "org.apache.thrift.transport.TIOStreamTransport(out)));" << endl;
+  indent(out) << "  } catch (org.apache.thrift.TException te) {" << endl;
+  indent(out) << "    throw new java.io.IOException(te" << (android_legacy_ ? ".getMessage()" : "")
+              << ");" << endl;
+  indent(out) << "  }" << endl;
+  indent(out) << "}" << endl << endl;
+}
+
+// generates java method to serialize (in the Java sense) the object
+void t_java_generator::generate_java_struct_read_object(ostream& out, t_struct* tstruct) {
+  indent(out) << "private void readObject(java.io.ObjectInputStream in) throws "
+                 "java.io.IOException, java.lang.ClassNotFoundException {" << endl;
+  indent(out) << "  try {" << endl;
+  if (!tstruct->is_union()) {
+    switch (needs_isset(tstruct)) {
+    case ISSET_NONE:
+      break;
+    case ISSET_PRIMITIVE:
+      indent(out) << "    // it doesn't seem like you should have to do this, but java "
+                     "serialization is wacky, and doesn't call the default constructor." << endl;
+      indent(out) << "    __isset_bitfield = 0;" << endl;
+      break;
+    case ISSET_BITSET:
+      indent(out) << "    // it doesn't seem like you should have to do this, but java "
+                     "serialization is wacky, and doesn't call the default constructor." << endl;
+      indent(out) << "    __isset_bit_vector = new java.util.BitSet(1);" << endl;
+      break;
+    }
+  }
+  indent(out) << "    read(new org.apache.thrift.protocol.TCompactProtocol(new "
+                 "org.apache.thrift.transport.TIOStreamTransport(in)));" << endl;
+  indent(out) << "  } catch (org.apache.thrift.TException te) {" << endl;
+  indent(out) << "    throw new java.io.IOException(te" << (android_legacy_ ? ".getMessage()" : "")
+              << ");" << endl;
+  indent(out) << "  }" << endl;
+  indent(out) << "}" << endl << endl;
+}
+
+void t_java_generator::generate_standard_reader(ostream& out, t_struct* tstruct) {
+  out << indent() << "public void read(org.apache.thrift.protocol.TProtocol iprot, "
+      << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Declare stack tmp variables and read struct header
+  out << indent() << "org.apache.thrift.protocol.TField schemeField;" << endl << indent()
+      << "iprot.readStructBegin();" << endl;
+
+  // Loop over reading in fields
+  indent(out) << "while (true)" << endl;
+  scope_up(out);
+
+  // Read beginning field marker
+  indent(out) << "schemeField = iprot.readFieldBegin();" << endl;
+
+  // Check for field STOP marker and break
+  indent(out) << "if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { " << endl;
+  indent_up();
+  indent(out) << "break;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+
+  // Switch statement on the field we are reading
+  indent(out) << "switch (schemeField.id) {" << endl;
+
+  indent_up();
+
+  // Generate deserialization code for known cases
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) << "case " << (*f_iter)->get_key() << ": // "
+                << constant_name((*f_iter)->get_name()) << endl;
+    indent_up();
+    indent(out) << "if (schemeField.type == " << type_to_enum((*f_iter)->get_type()) << ") {"
+                << endl;
+    indent_up();
+
+    generate_deserialize_field(out, *f_iter, "struct.", true);
+    indent(out) << "struct."
+                << "set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet")
+                << "(true);" << endl;
+    indent_down();
+    out << indent() << "} else { " << endl << indent()
+        << "  org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);" << endl
+        << indent() << "}" << endl << indent() << "break;" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);"
+              << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  // Read field end marker
+  indent(out) << "iprot.readFieldEnd();" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  out << indent() << "iprot.readStructEnd();" << endl;
+
+  // in non-beans style, check for required fields of primitive type
+  // (which can be checked here but not in the general validate method)
+  if (!bean_style_) {
+    out << endl << indent() << "// check for required fields of primitive type, which can't be "
+                               "checked in the validate method" << endl;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) {
+        out << indent() << "if (!struct." << generate_isset_check(*f_iter) << ") {" << endl
+            << indent()
+            << "  throw new org.apache.thrift.protocol.TProtocolException(\"Required field '"
+            << (*f_iter)->get_name()
+            << "' was not found in serialized data! Struct: \" + toString());" << endl << indent()
+            << "}" << endl;
+      }
+    }
+  }
+
+  // performs various checks (e.g. check that all required fields are set)
+  indent(out) << "struct.validate();" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl;
+}
+
+void t_java_generator::generate_standard_writer(ostream& out, t_struct* tstruct, bool is_result) {
+  indent_up();
+  out << indent() << "public void write(org.apache.thrift.protocol.TProtocol oprot, "
+      << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl;
+  indent_up();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // performs various checks (e.g. check that all required fields are set)
+  indent(out) << "struct.validate();" << endl << endl;
+
+  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    if (null_allowed) {
+      out << indent() << "if (struct." << (*f_iter)->get_name() << " != null) {" << endl;
+      indent_up();
+    }
+    bool optional = ((*f_iter)->get_req() == t_field::T_OPTIONAL) || (is_result && !null_allowed);
+    if (optional) {
+      indent(out) << "if ("
+                  << "struct." << generate_isset_check((*f_iter)) << ") {" << endl;
+      indent_up();
+    }
+
+    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name())
+                << "_FIELD_DESC);" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "struct.", true);
+
+    // Write field closer
+    indent(out) << "oprot.writeFieldEnd();" << endl;
+
+    if (optional) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    if (null_allowed) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+  // Write the struct map
+  out << indent() << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();"
+      << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+  indent_down();
+}
+
+void t_java_generator::generate_java_struct_standard_scheme(ostream& out,
+                                                            t_struct* tstruct,
+                                                            bool is_result) {
+  indent(out) << "private static class " << tstruct->get_name()
+              << "StandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {" << endl;
+  indent_up();
+  indent(out) << "public " << tstruct->get_name() << "StandardScheme getScheme() {" << endl;
+  indent_up();
+  indent(out) << "return new " << tstruct->get_name() << "StandardScheme();" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  out << indent() << "private static class " << tstruct->get_name()
+      << "StandardScheme extends org.apache.thrift.scheme.StandardScheme<" << tstruct->get_name() << "> {" << endl << endl;
+  indent_up();
+  generate_standard_reader(out, tstruct);
+  indent_down();
+  out << endl;
+  generate_standard_writer(out, tstruct, is_result);
+
+  out << indent() << "}" << endl << endl;
+}
+
+void t_java_generator::generate_java_struct_tuple_reader(ostream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out) << "public void read(org.apache.thrift.protocol.TProtocol prot, "
+              << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl;
+  indent_up();
+  indent(out) << "org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;" << endl;
+  int optional_count = 0;
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_OPTIONAL
+        || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
+      optional_count++;
+    }
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      generate_deserialize_field(out, (*f_iter), "struct.", false);
+      indent(out) << "struct.set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet")
+                  << "(true);" << endl;
+    }
+  }
+  if (optional_count > 0) {
+    indent(out) << "java.util.BitSet incoming = iprot.readBitSet(" << optional_count << ");" << endl;
+    int i = 0;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      if ((*f_iter)->get_req() == t_field::T_OPTIONAL
+          || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
+        indent(out) << "if (incoming.get(" << i << ")) {" << endl;
+        indent_up();
+        generate_deserialize_field(out, (*f_iter), "struct.", false);
+        indent(out) << "struct.set" << get_cap_name((*f_iter)->get_name()) << get_cap_name("isSet")
+                    << "(true);" << endl;
+        indent_down();
+        indent(out) << "}" << endl;
+        i++;
+      }
+    }
+  }
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_java_struct_tuple_writer(ostream& out, t_struct* tstruct) {
+  indent(out) << "@Override" << endl;
+  indent(out) << "public void write(org.apache.thrift.protocol.TProtocol prot, "
+              << tstruct->get_name() << " struct) throws org.apache.thrift.TException {" << endl;
+  indent_up();
+  indent(out) << "org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;" << endl;
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  bool has_optional = false;
+  int optional_count = 0;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_OPTIONAL
+        || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
+      optional_count++;
+      has_optional = true;
+    }
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      generate_serialize_field(out, (*f_iter), "struct.", false);
+    }
+  }
+  if (has_optional) {
+    indent(out) << "java.util.BitSet optionals = new java.util.BitSet();" << endl;
+    int i = 0;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      if ((*f_iter)->get_req() == t_field::T_OPTIONAL
+          || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
+        indent(out) << "if (struct." << generate_isset_check((*f_iter)) << ") {" << endl;
+        indent_up();
+        indent(out) << "optionals.set(" << i << ");" << endl;
+        indent_down();
+        indent(out) << "}" << endl;
+        i++;
+      }
+    }
+
+    indent(out) << "oprot.writeBitSet(optionals, " << optional_count << ");" << endl;
+    int j = 0;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      if ((*f_iter)->get_req() == t_field::T_OPTIONAL
+          || (*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
+        indent(out) << "if (struct." << generate_isset_check(*f_iter) << ") {" << endl;
+        indent_up();
+        generate_serialize_field(out, (*f_iter), "struct.", false);
+        indent_down();
+        indent(out) << "}" << endl;
+        j++;
+      }
+    }
+  }
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_java_struct_tuple_scheme(ostream& out, t_struct* tstruct) {
+  indent(out) << "private static class " << tstruct->get_name()
+              << "TupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {" << endl;
+  indent_up();
+  indent(out) << "public " << tstruct->get_name() << "TupleScheme getScheme() {" << endl;
+  indent_up();
+  indent(out) << "return new " << tstruct->get_name() << "TupleScheme();" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+  out << indent() << "private static class " << tstruct->get_name()
+      << "TupleScheme extends org.apache.thrift.scheme.TupleScheme<" << tstruct->get_name() << "> {" << endl << endl;
+  indent_up();
+  generate_java_struct_tuple_writer(out, tstruct);
+  out << endl;
+  generate_java_struct_tuple_reader(out, tstruct);
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+void t_java_generator::generate_java_scheme_lookup(ostream& out) {
+  indent(out) << "private static <S extends org.apache.thrift.scheme.IScheme> S scheme("
+      << "org.apache.thrift.protocol.TProtocol proto) {" << endl;
+  indent_up();
+  indent(out) << "return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) "
+      << "? STANDARD_SCHEME_FACTORY "
+      << ": TUPLE_SCHEME_FACTORY"
+      << ").getScheme();" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_javax_generated_annotation(ostream& out) {
+  time_t seconds = time(NULL);
+  struct tm* now = localtime(&seconds);
+  indent(out) << "@javax.annotation.Generated(value = \"" << autogen_summary() << "\"";
+  if (undated_generated_annotations_) {
+    out << ")" << endl;
+  } else {
+    indent(out) << ", date = \"" << (now->tm_year + 1900) << "-" << setfill('0') << setw(2)
+                << (now->tm_mon + 1) << "-" << setfill('0') << setw(2) << now->tm_mday
+                << "\")" << endl;
+  }
+}
+
+THRIFT_REGISTER_GENERATOR(
+    java,
+    "Java",
+    "    beans:           Members will be private, and setter methods will return void.\n"
+    "    private-members: Members will be private, but setter methods will return 'this' like "
+    "usual.\n"
+    "    nocamel:         Do not use CamelCase field accessors with beans.\n"
+    "    fullcamel:       Convert underscored_accessor_or_service_names to camelCase.\n"
+    "    android:         Generated structures are Parcelable.\n"
+    "    android_legacy:  Do not use java.io.IOException(throwable) (available for Android 2.3 and "
+    "above).\n"
+    "    option_type:     Wrap optional fields in an Option type.\n"
+    "    rethrow_unhandled_exceptions:\n"
+    "                     Enable rethrow of unhandled exceptions and let them propagate futher."
+    " (Default behavior is to catch and log it.)\n"
+    "    java5:           Generate Java 1.5 compliant code (includes android_legacy flag).\n"
+    "    reuse-objects:   Data objects will not be allocated, but existing instances will be used "
+    "(read and write).\n"
+    "    sorted_containers:\n"
+    "                     Use TreeSet/TreeMap instead of HashSet/HashMap as a implementation of "
+    "set/map.\n"
+    "    generated_annotations=[undated|suppress]:\n"
+    "                     undated: suppress the date at @Generated annotations\n"
+    "                     suppress: suppress @Generated annotations entirely\n"
+    "    unsafe_binaries: Do not copy ByteBuffers in constructors, getters, and setters.\n")
diff --git a/compiler/cpp/src/thrift/generate/t_javame_generator.cc b/compiler/cpp/src/thrift/generate/t_javame_generator.cc
new file mode 100644
index 0000000..fa743ca
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_javame_generator.cc
@@ -0,0 +1,3296 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <cctype>
+
+#include <sys/stat.h>
+#include <stdexcept>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * Java code generator.
+ *
+ */
+class t_javame_generator : public t_oop_generator {
+public:
+  t_javame_generator(t_program* program,
+                     const std::map<std::string, std::string>& parsed_options,
+                     const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)parsed_options;
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    /* no options yet */
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      throw "unknown option javame:" + iter->first;
+    }
+
+    out_dir_base_ = "gen-javame";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  void generate_consts(std::vector<t_const*> consts);
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_struct(t_struct* tstruct);
+  void generate_union(t_struct* tunion);
+  void generate_xception(t_struct* txception);
+  void generate_service(t_service* tservice);
+
+  void print_const_value(std::ostream& out,
+                         std::string name,
+                         t_type* type,
+                         t_const_value* value,
+                         bool in_static,
+                         bool defval = false);
+  std::string render_const_value(std::ostream& out,
+                                 std::string name,
+                                 t_type* type,
+                                 t_const_value* value);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_java_struct(t_struct* tstruct, bool is_exception);
+
+  void generate_java_struct_definition(std::ostream& out,
+                                       t_struct* tstruct,
+                                       bool is_xception = false,
+                                       bool in_class = false,
+                                       bool is_result = false);
+  void generate_java_struct_equality(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_compare_to(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_java_validator(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_result_writer(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_writer(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_tostring(std::ostream& out, t_struct* tstruct);
+  void generate_java_struct_clear(std::ostream& out, t_struct* tstruct);
+  void generate_field_value_meta_data(std::ostream& out, t_type* type);
+  std::string get_java_type_string(t_type* type);
+  void generate_reflection_setters(std::ostringstream& out,
+                                   t_type* type,
+                                   std::string field_name,
+                                   std::string cap_name);
+  void generate_reflection_getters(std::ostringstream& out,
+                                   t_type* type,
+                                   std::string field_name,
+                                   std::string cap_name);
+  void generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct);
+  void generate_java_bean_boilerplate(std::ostream& out, t_struct* tstruct);
+
+  void generate_function_helpers(t_function* tfunction);
+  std::string get_cap_name(std::string name);
+  std::string generate_isset_check(t_field* field);
+  std::string generate_isset_check(std::string field);
+  void generate_isset_set(ostream& out, t_field* field);
+  std::string isset_field_id(t_field* field);
+
+  void generate_primitive_service_interface(t_service* tservice);
+  void generate_service_interface(t_service* tservice);
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_client(t_service* tservice);
+  void generate_service_server(t_service* tservice);
+  void generate_process_function(t_service* tservice, t_function* tfunction);
+
+  void generate_java_union(t_struct* tstruct);
+  void generate_union_constructor(ostream& out, t_struct* tstruct);
+  void generate_union_getters_and_setters(ostream& out, t_struct* tstruct);
+  void generate_union_abstract_methods(ostream& out, t_struct* tstruct);
+  void generate_check_type(ostream& out, t_struct* tstruct);
+  void generate_read_value(ostream& out, t_struct* tstruct);
+  void generate_write_value(ostream& out, t_struct* tstruct);
+  void generate_get_field_desc(ostream& out, t_struct* tstruct);
+  void generate_get_struct_desc(ostream& out, t_struct* tstruct);
+  void generate_get_field_name(ostream& out, t_struct* tstruct);
+
+  void generate_union_comparisons(ostream& out, t_struct* tstruct);
+  void generate_union_hashcode(ostream& out, t_struct* tstruct);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
+
+  void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+
+  void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         std::string prefix = "");
+
+  void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
+
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string iter,
+                                      std::string map);
+
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  void generate_java_doc(std::ostream& out, t_field* field);
+
+  void generate_java_doc(std::ostream& out, t_doc* tdoc);
+
+  void generate_java_doc(std::ostream& out, t_function* tdoc);
+
+  void generate_java_docstring_comment(std::ostream& out, string contents);
+
+  void generate_deep_copy_container(std::ostream& out,
+                                    std::string source_name_p1,
+                                    std::string source_name_p2,
+                                    std::string result_name,
+                                    t_type* type);
+  void generate_deep_copy_non_container(std::ostream& out,
+                                        std::string source_name,
+                                        std::string dest_name,
+                                        t_type* type);
+
+  bool has_bit_vector(t_struct* tstruct);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string java_package();
+  std::string java_type_imports();
+  std::string java_thrift_imports();
+  std::string type_name(t_type* ttype,
+                        bool in_container = false,
+                        bool in_init = false,
+                        bool skip_generic = false);
+  std::string base_type_name(t_base_type* tbase, bool in_container = false);
+  std::string declare_field(t_field* tfield, bool init = false);
+  std::string function_signature(t_function* tfunction, std::string prefix = "");
+  std::string argument_list(t_struct* tstruct, bool include_types = true);
+  std::string type_to_enum(t_type* ttype);
+  std::string get_enum_class_name(t_type* type);
+  void generate_struct_desc(ostream& out, t_struct* tstruct);
+  void generate_field_descs(ostream& out, t_struct* tstruct);
+  std::string box_type(t_type* type, string value);
+
+  bool type_can_be_null(t_type* ttype) {
+    ttype = get_true_type(ttype);
+
+    return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string()
+           || ttype->is_enum();
+  }
+
+  std::string constant_name(std::string name);
+
+private:
+  /**
+   * File streams
+   */
+
+  std::string package_name_;
+  ofstream_with_content_based_conditional_update f_service_;
+  std::string package_dir_;
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_javame_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+  package_name_ = program_->get_namespace("java");
+
+  string dir = package_name_;
+  string subdir = get_out_dir();
+  string::size_type loc;
+  while ((loc = dir.find(".")) != string::npos) {
+    subdir = subdir + "/" + dir.substr(0, loc);
+    MKDIR(subdir.c_str());
+    dir = dir.substr(loc + 1);
+  }
+  if (dir.size() > 0) {
+    subdir = subdir + "/" + dir;
+    MKDIR(subdir.c_str());
+  }
+
+  package_dir_ = subdir;
+}
+
+/**
+ * Packages the generated file
+ *
+ * @return String of the package, i.e. "package org.apache.thriftdemo;"
+ */
+string t_javame_generator::java_package() {
+  if (!package_name_.empty()) {
+    return string("package ") + package_name_ + ";\n\n";
+  }
+  return "";
+}
+
+/**
+ * Prints standard java imports
+ *
+ * @return List of imports for Java types that are used in here
+ */
+string t_javame_generator::java_type_imports() {
+  return string() + "import java.util.Hashtable;\n" + "import java.util.Vector;\n"
+         + "import java.util.Enumeration;\n\n";
+}
+
+/**
+ * Prints standard java imports
+ *
+ * @return List of imports necessary for thrift
+ */
+string t_javame_generator::java_thrift_imports() {
+  return string() + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n"
+         + "import org.apache.thrift.transport.*;\n" + "import org.apache.thrift.protocol.*;\n\n";
+}
+
+/**
+ * Nothing in Java
+ */
+void t_javame_generator::close_generator() {
+}
+
+/**
+ * Generates a typedef. This is not done in Java, since it does
+ * not support arbitrary name replacements, and it'd be a wacky waste
+ * of overhead to make wrapper classes.
+ *
+ * @param ttypedef The type definition
+ */
+void t_javame_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+/**
+ * Enums are a class with a set of static constants.
+ *
+ * @param tenum The enumeration
+ */
+void t_javame_generator::generate_enum(t_enum* tenum) {
+  // Make output file
+  string f_enum_name = package_dir_ + "/" + (tenum->get_name()) + ".java";
+  ofstream_with_content_based_conditional_update f_enum;
+  f_enum.open(f_enum_name.c_str());
+
+  // Comment and package it
+  f_enum << autogen_comment() << java_package();
+
+  generate_java_doc(f_enum, tenum);
+  indent(f_enum) << "public class " << tenum->get_name() << " implements org.apache.thrift.TEnum ";
+  scope_up(f_enum);
+  f_enum << endl;
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    generate_java_doc(f_enum, *c_iter);
+    indent(f_enum) << "public static final " << tenum->get_name() << " " << (*c_iter)->get_name()
+                   << " = new " << tenum->get_name() << "(" << value << ");" << endl;
+  }
+  f_enum << endl;
+
+  // Field for thriftCode
+  indent(f_enum) << "private final int value;" << endl << endl;
+
+  indent(f_enum) << "private " << tenum->get_name() << "(int value) {" << endl;
+  indent(f_enum) << "  this.value = value;" << endl;
+  indent(f_enum) << "}" << endl << endl;
+
+  indent(f_enum) << "/**" << endl;
+  indent(f_enum) << " * Get the integer value of this enum value, as defined in the Thrift IDL."
+                 << endl;
+  indent(f_enum) << " */" << endl;
+  indent(f_enum) << "public int getValue() {" << endl;
+  indent(f_enum) << "  return value;" << endl;
+  indent(f_enum) << "}" << endl << endl;
+
+  indent(f_enum) << "/**" << endl;
+  indent(f_enum) << " * Find a the enum type by its integer value, as defined in the Thrift IDL."
+                 << endl;
+  indent(f_enum) << " * @return null if the value is not found." << endl;
+  indent(f_enum) << " */" << endl;
+  indent(f_enum) << "public static " + tenum->get_name() + " findByValue(int value) { " << endl;
+
+  indent_up();
+
+  indent(f_enum) << "switch (value) {" << endl;
+  indent_up();
+
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    indent(f_enum) << "case " << value << ":" << endl;
+    indent(f_enum) << "  return " << (*c_iter)->get_name() << ";" << endl;
+  }
+
+  indent(f_enum) << "default:" << endl;
+  indent(f_enum) << "  return null;" << endl;
+
+  indent_down();
+
+  indent(f_enum) << "}" << endl;
+
+  indent_down();
+
+  indent(f_enum) << "}" << endl;
+
+  scope_down(f_enum);
+
+  f_enum.close();
+}
+
+/**
+ * Generates a class that holds all the constants.
+ */
+void t_javame_generator::generate_consts(std::vector<t_const*> consts) {
+  if (consts.empty()) {
+    return;
+  }
+
+  string f_consts_name = package_dir_ + "/" + program_name_ + "Constants.java";
+  ofstream_with_content_based_conditional_update f_consts;
+  f_consts.open(f_consts_name.c_str());
+
+  // Print header
+  f_consts << autogen_comment() << java_package() << java_type_imports();
+
+  f_consts << "public class " << program_name_ << "Constants {" << endl << endl;
+  indent_up();
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    print_const_value(f_consts,
+                      (*c_iter)->get_name(),
+                      (*c_iter)->get_type(),
+                      (*c_iter)->get_value(),
+                      false);
+  }
+  indent_down();
+  indent(f_consts) << "}" << endl;
+  f_consts.close();
+}
+
+/**
+ * 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
+ */
+void t_javame_generator::print_const_value(std::ostream& out,
+                                           string name,
+                                           t_type* type,
+                                           t_const_value* value,
+                                           bool in_static,
+                                           bool defval) {
+  type = get_true_type(type);
+
+  indent(out);
+  if (!defval) {
+    out << (in_static ? "" : "public static final ") << type_name(type) << " ";
+  }
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, name, type, value);
+    out << name << " = " << v2 << ";" << endl << endl;
+  } else if (type->is_enum()) {
+    out << name << " = " << render_const_value(out, name, type, value) << ";" << endl << endl;
+  } else if (type->is_struct() || type->is_xception()) {
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    out << name << " = new " << type_name(type, false, true) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "static {" << endl;
+      indent_up();
+    }
+    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();
+      }
+      string val = render_const_value(out, name, field_type, v_iter->second);
+      indent(out) << name << ".";
+      std::string cap_name = get_cap_name(v_iter->first->get_string());
+      out << "set" << cap_name << "(" << val << ");" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else if (type->is_map()) {
+    out << name << " = new " << type_name(type, false, true) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "static {" << endl;
+      indent_up();
+    }
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, name, ktype, v_iter->first);
+      string val = render_const_value(out, name, vtype, v_iter->second);
+      indent(out) << name << ".put(" << box_type(ktype, key) << ", " << box_type(vtype, val) << ");"
+                  << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else if (type->is_list() || type->is_set()) {
+    out << name << " = new " << type_name(type, false, true) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "static {" << endl;
+      indent_up();
+    }
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(out, name, etype, *v_iter);
+      if (type->is_list()) {
+        indent(out) << name << ".addElement(" << box_type(etype, val) << ");" << endl;
+      } else {
+        indent(out) << name << ".put(" << box_type(etype, val) << ", " << box_type(etype, val)
+                    << ");" << endl;
+      }
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else {
+    throw "compiler error: no const of type " + type->get_name();
+  }
+}
+
+string t_javame_generator::render_const_value(ostream& out,
+                                              string name,
+                                              t_type* type,
+                                              t_const_value* value) {
+  (void)name;
+  type = get_true_type(type);
+  std::ostringstream render;
+
+  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:
+      render << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "true" : "false");
+      break;
+    case t_base_type::TYPE_I8:
+      render << "(byte)" << value->get_integer();
+      break;
+    case t_base_type::TYPE_I16:
+      render << "(short)" << value->get_integer();
+      break;
+    case t_base_type::TYPE_I32:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_I64:
+      render << value->get_integer() << "L";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << "(double)" << value->get_integer();
+      } else {
+        render << 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()) {
+    render << type_name(type, false, false) << "." << value->get_identifier();
+  } else {
+    string t = tmp("tmp");
+    print_const_value(out, t, type, value, true);
+    render << t;
+  }
+
+  return render.str();
+}
+
+string t_javame_generator::box_type(t_type* type, string value) {
+  if (type->is_base_type()) {
+    switch (((t_base_type*)type)->get_base()) {
+    case t_base_type::TYPE_BOOL:
+      return "new Boolean(" + value + ")";
+    case t_base_type::TYPE_I8:
+      return "new Byte(" + value + ")";
+    case t_base_type::TYPE_I16:
+      return "new Short(" + value + ")";
+    case t_base_type::TYPE_I32:
+      return "new Integer(" + value + ")";
+    case t_base_type::TYPE_I64:
+      return "new Long(" + value + ")";
+    case t_base_type::TYPE_DOUBLE:
+      return "new Double(" + value + ")";
+    default:
+      break;
+    }
+  }
+  return value;
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This will be a TBase
+ * implementor.
+ *
+ * @param tstruct The struct definition
+ */
+void t_javame_generator::generate_struct(t_struct* tstruct) {
+  if (tstruct->is_union()) {
+    generate_java_union(tstruct);
+  } else {
+    generate_java_struct(tstruct, false);
+  }
+}
+
+/**
+ * Exceptions are structs, but they inherit from Exception
+ *
+ * @param tstruct The struct definition
+ */
+void t_javame_generator::generate_xception(t_struct* txception) {
+  generate_java_struct(txception, true);
+}
+
+/**
+ * Java struct definition.
+ *
+ * @param tstruct The struct definition
+ */
+void t_javame_generator::generate_java_struct(t_struct* tstruct, bool is_exception) {
+  // Make output file
+  string f_struct_name = package_dir_ + "/" + (tstruct->get_name()) + ".java";
+  ofstream_with_content_based_conditional_update f_struct;
+  f_struct.open(f_struct_name.c_str());
+
+  f_struct << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports();
+
+  generate_java_struct_definition(f_struct, tstruct, is_exception);
+  f_struct.close();
+}
+
+/**
+ * Java union definition.
+ *
+ * @param tstruct The struct definition
+ */
+void t_javame_generator::generate_java_union(t_struct* tstruct) {
+  // Make output file
+  string f_struct_name = package_dir_ + "/" + (tstruct->get_name()) + ".java";
+  ofstream_with_content_based_conditional_update f_struct;
+  f_struct.open(f_struct_name.c_str());
+
+  f_struct << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports();
+
+  generate_java_doc(f_struct, tstruct);
+
+  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+
+  indent(f_struct) << "public " << (is_final ? "final " : "") << "class " << tstruct->get_name()
+                   << " extends TUnion ";
+
+  scope_up(f_struct);
+
+  generate_struct_desc(f_struct, tstruct);
+  generate_field_descs(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_union_constructor(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_union_abstract_methods(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_union_getters_and_setters(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_union_comparisons(f_struct, tstruct);
+
+  f_struct << endl;
+
+  generate_union_hashcode(f_struct, tstruct);
+
+  f_struct << endl;
+
+  scope_down(f_struct);
+
+  f_struct.close();
+}
+
+void t_javame_generator::generate_union_constructor(ostream& out, t_struct* tstruct) {
+  indent(out) << "public " << type_name(tstruct) << "() {" << endl;
+  indent(out) << "  super();" << endl;
+  indent(out) << "}" << endl << endl;
+
+  indent(out) << "public " << type_name(tstruct) << "(_Fields setField, Object value) {" << endl;
+  indent(out) << "  super(setField, value);" << endl;
+  indent(out) << "}" << endl << endl;
+
+  indent(out) << "public " << type_name(tstruct) << "(" << type_name(tstruct) << " other) {"
+              << endl;
+  indent(out) << "  super(other);" << endl;
+  indent(out) << "}" << endl;
+
+  indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl;
+  indent(out) << "  return new " << tstruct->get_name() << "(this);" << endl;
+  indent(out) << "}" << endl << endl;
+
+  // generate "constructors" for each field
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() << "("
+                << type_name((*m_iter)->get_type()) << " value) {" << endl;
+    indent(out) << "  " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" << endl;
+    indent(out) << "  x.set" << get_cap_name((*m_iter)->get_name()) << "(value);" << endl;
+    indent(out) << "  return x;" << endl;
+    indent(out) << "}" << endl << endl;
+  }
+}
+
+void t_javame_generator::generate_union_getters_and_setters(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  bool first = true;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if (first) {
+      first = false;
+    } else {
+      out << endl;
+    }
+
+    t_field* field = (*m_iter);
+
+    generate_java_doc(out, field);
+    indent(out) << "public " << type_name(field->get_type()) << " get"
+                << get_cap_name(field->get_name()) << "() {" << endl;
+    indent(out) << "  if (getSetField() == _Fields." << constant_name(field->get_name()) << ") {"
+                << endl;
+    indent(out) << "    return (" << type_name(field->get_type(), true) << ")getFieldValue();"
+                << endl;
+    indent(out) << "  } else {" << endl;
+    indent(out) << "    throw new RuntimeException(\"Cannot get field '" << field->get_name()
+                << "' because union is currently set to \" + getFieldDesc(getSetField()).name);"
+                << endl;
+    indent(out) << "  }" << endl;
+    indent(out) << "}" << endl;
+
+    out << endl;
+
+    generate_java_doc(out, field);
+    indent(out) << "public void set" << get_cap_name(field->get_name()) << "("
+                << type_name(field->get_type()) << " value) {" << endl;
+    if (type_can_be_null(field->get_type())) {
+      indent(out) << "  if (value == null) throw new NullPointerException();" << endl;
+    }
+    indent(out) << "  setField_ = _Fields." << constant_name(field->get_name()) << ";" << endl;
+    indent(out) << "  value_ = value;" << endl;
+    indent(out) << "}" << endl;
+  }
+}
+
+void t_javame_generator::generate_union_abstract_methods(ostream& out, t_struct* tstruct) {
+  generate_check_type(out, tstruct);
+  out << endl;
+  generate_read_value(out, tstruct);
+  out << endl;
+  generate_write_value(out, tstruct);
+  out << endl;
+  generate_get_field_desc(out, tstruct);
+  out << endl;
+  generate_get_struct_desc(out, tstruct);
+  out << endl;
+}
+
+void t_javame_generator::generate_check_type(ostream& out, t_struct* tstruct) {
+  indent(out)
+      << "protected void checkType(_Fields setField, Object value) throws ClassCastException {"
+      << endl;
+  indent_up();
+
+  indent(out) << "switch (setField) {" << endl;
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+
+    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
+    indent(out) << "  if (value instanceof " << type_name(field->get_type(), true, false, true)
+                << ") {" << endl;
+    indent(out) << "    break;" << endl;
+    indent(out) << "  }" << endl;
+    indent(out) << "  throw new ClassCastException(\"Was expecting value of type "
+                << type_name(field->get_type(), true, false) << " for field '" << field->get_name()
+                << "', but got \" + value.getClass().getSimpleName());" << endl;
+    // do the real check here
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_javame_generator::generate_read_value(ostream& out, t_struct* tstruct) {
+  indent(out) << "protected Object readValue(TProtocol iprot, TField field) throws TException {"
+              << endl;
+
+  indent_up();
+
+  indent(out) << "_Fields setField = _Fields.findByThriftId(field.id);" << endl;
+  indent(out) << "if (setField != null) {" << endl;
+  indent_up();
+  indent(out) << "switch (setField) {" << endl;
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+
+    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
+    indent_up();
+    indent(out) << "if (field.type == " << constant_name(field->get_name()) << "_FIELD_DESC.type) {"
+                << endl;
+    indent_up();
+    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";"
+                << endl;
+    generate_deserialize_field(out, field, "");
+    indent(out) << "return " << field->get_name() << ";" << endl;
+    indent_down();
+    indent(out) << "} else {" << endl;
+    indent(out) << "  TProtocolUtil.skip(iprot, field.type);" << endl;
+    indent(out) << "  return null;" << endl;
+    indent(out) << "}" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new IllegalStateException(\"setField wasn't null, but didn't match any "
+                 "of the case statements!\");" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "} else {" << endl;
+  indent_up();
+  indent(out) << "TProtocolUtil.skip(iprot, field.type);" << endl;
+  indent(out) << "return null;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_javame_generator::generate_write_value(ostream& out, t_struct* tstruct) {
+  indent(out) << "protected void writeValue(TProtocol oprot) throws TException {" << endl;
+
+  indent_up();
+
+  indent(out) << "switch (setField_) {" << endl;
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+
+    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
+    indent_up();
+    indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << " = ("
+                << type_name(field->get_type(), true, false) << ")value_;" << endl;
+    generate_serialize_field(out, field, "");
+    indent(out) << "return;" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new IllegalStateException(\"Cannot write union with unknown field \" + "
+                 "setField_);" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+
+  indent(out) << "}" << endl;
+}
+
+void t_javame_generator::generate_get_field_desc(ostream& out, t_struct* tstruct) {
+  indent(out) << "protected TField getFieldDesc(_Fields setField) {" << endl;
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  indent(out) << "switch (setField) {" << endl;
+  indent_up();
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+    indent(out) << "case " << constant_name(field->get_name()) << ":" << endl;
+    indent(out) << "  return " << constant_name(field->get_name()) << "_FIELD_DESC;" << endl;
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_javame_generator::generate_get_struct_desc(ostream& out, t_struct* tstruct) {
+  (void)tstruct;
+  indent(out) << "protected TStruct getStructDesc() {" << endl;
+  indent(out) << "  return STRUCT_DESC;" << endl;
+  indent(out) << "}" << endl;
+}
+
+void t_javame_generator::generate_union_comparisons(ostream& out, t_struct* tstruct) {
+  // equality
+  indent(out) << "public boolean equals(Object other) {" << endl;
+  indent(out) << "  if (other instanceof " << tstruct->get_name() << ") {" << endl;
+  indent(out) << "    return equals((" << tstruct->get_name() << ")other);" << endl;
+  indent(out) << "  } else {" << endl;
+  indent(out) << "    return false;" << endl;
+  indent(out) << "  }" << endl;
+  indent(out) << "}" << endl;
+
+  out << endl;
+
+  indent(out) << "public boolean equals(" << tstruct->get_name() << " other) {" << endl;
+  indent(out) << "  return other != null && getSetField() == other.getSetField() && "
+                 "getFieldValue().equals(other.getFieldValue());" << endl;
+  indent(out) << "}" << endl;
+  out << endl;
+
+  indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl;
+  indent(out) << "  int lastComparison = TBaseHelper.compareTo(getSetField(), other.getSetField());"
+              << endl;
+  indent(out) << "  if (lastComparison == 0) {" << endl;
+  indent(out) << "    return TBaseHelper.compareTo(getFieldValue(), other.getFieldValue());"
+              << endl;
+  indent(out) << "  }" << endl;
+  indent(out) << "  return lastComparison;" << endl;
+  indent(out) << "}" << endl;
+  out << endl;
+}
+
+void t_javame_generator::generate_union_hashcode(ostream& out, t_struct* tstruct) {
+  (void)tstruct;
+  indent(out) << "/**" << endl;
+  indent(out)
+      << " * If you'd like this to perform more respectably, use the hashcode generator option."
+      << endl;
+  indent(out) << " */" << endl;
+  indent(out) << "public int hashCode() {" << endl;
+  indent(out) << "  return 0;" << endl;
+  indent(out) << "}" << endl;
+}
+
+/**
+ * Java struct definition. This has various parameters, as it could be
+ * generated standalone or inside another class as a helper. If it
+ * is a helper than it is a static class.
+ *
+ * @param tstruct      The struct definition
+ * @param is_exception Is this an exception?
+ * @param in_class     If inside a class, needs to be static class
+ * @param is_result    If this is a result it needs a different writer
+ */
+void t_javame_generator::generate_java_struct_definition(ostream& out,
+                                                         t_struct* tstruct,
+                                                         bool is_exception,
+                                                         bool in_class,
+                                                         bool is_result) {
+  generate_java_doc(out, tstruct);
+
+  bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+
+  indent(out) << "public " << (is_final ? "final " : "") << (in_class ? "static " : "") << "class "
+              << tstruct->get_name() << " ";
+
+  if (is_exception) {
+    out << "extends Exception ";
+  }
+  out << "implements TBase ";
+
+  scope_up(out);
+
+  generate_struct_desc(out, tstruct);
+
+  // Members are public for -java, private for -javabean
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  out << endl;
+
+  generate_field_descs(out, tstruct);
+
+  out << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) << "private ";
+    out << declare_field(*m_iter, false) << endl;
+  }
+
+  // isset data
+  if (members.size() > 0) {
+    out << endl;
+
+    indent(out) << "// isset id assignments" << endl;
+
+    int i = 0;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (!type_can_be_null((*m_iter)->get_type())) {
+        indent(out) << "private static final int " << isset_field_id(*m_iter) << " = " << i << ";"
+                    << endl;
+        i++;
+      }
+    }
+
+    if (i > 0) {
+      indent(out) << "private boolean[] __isset_vector = new boolean[" << i << "];" << endl;
+    }
+
+    out << endl;
+  }
+
+  bool all_optional_members = true;
+
+  // Default constructor
+  indent(out) << "public " << tstruct->get_name() << "() {" << endl;
+  indent_up();
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    if ((*m_iter)->get_value() != NULL) {
+      print_const_value(out,
+                        "this." + (*m_iter)->get_name(),
+                        t,
+                        (*m_iter)->get_value(),
+                        true,
+                        true);
+    }
+    if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
+      all_optional_members = false;
+    }
+  }
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  if (!members.empty() && !all_optional_members) {
+    // Full constructor for all fields
+    indent(out) << "public " << tstruct->get_name() << "(" << endl;
+    indent_up();
+    bool first = true;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
+        if (!first) {
+          out << "," << endl;
+        }
+        first = false;
+        indent(out) << type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name();
+      }
+    }
+    out << ")" << endl;
+    indent_down();
+    indent(out) << "{" << endl;
+    indent_up();
+    indent(out) << "this();" << endl;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
+        indent(out) << "this." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << ";"
+                    << endl;
+        generate_isset_set(out, (*m_iter));
+      }
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+
+  // copy constructor
+  indent(out) << "/**" << endl;
+  indent(out) << " * Performs a deep copy on <i>other</i>." << endl;
+  indent(out) << " */" << endl;
+  indent(out) << "public " << tstruct->get_name() << "(" << tstruct->get_name() << " other) {"
+              << endl;
+  indent_up();
+
+  if (has_bit_vector(tstruct)) {
+    indent(out) << "System.arraycopy(other.__isset_vector, 0, __isset_vector, 0, "
+                   "other.__isset_vector.length);" << endl;
+  }
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = (*m_iter);
+    std::string field_name = field->get_name();
+    t_type* type = field->get_type();
+    bool can_be_null = type_can_be_null(type);
+
+    if (can_be_null) {
+      indent(out) << "if (other." << generate_isset_check(field) << ") {" << endl;
+      indent_up();
+    }
+
+    if (type->is_container()) {
+      generate_deep_copy_container(out, "other", field_name, "__this__" + field_name, type);
+      indent(out) << "this." << field_name << " = __this__" << field_name << ";" << endl;
+    } else {
+      indent(out) << "this." << field_name << " = ";
+      generate_deep_copy_non_container(out, "other." + field_name, field_name, type);
+      out << ";" << endl;
+    }
+
+    if (can_be_null) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+
+  // clone method, so that you can deep copy an object when you don't know its class.
+  indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl;
+  indent(out) << "  return new " << tstruct->get_name() << "(this);" << endl;
+  indent(out) << "}" << endl << endl;
+
+  generate_java_struct_clear(out, tstruct);
+
+  generate_java_bean_boilerplate(out, tstruct);
+  generate_generic_field_getters_setters(out, tstruct);
+
+  generate_java_struct_equality(out, tstruct);
+  generate_java_struct_compare_to(out, tstruct);
+
+  generate_java_struct_reader(out, tstruct);
+  if (is_result) {
+    generate_java_struct_result_writer(out, tstruct);
+  } else {
+    generate_java_struct_writer(out, tstruct);
+  }
+  generate_java_struct_tostring(out, tstruct);
+  generate_java_validator(out, tstruct);
+  scope_down(out);
+  out << endl;
+}
+
+/**
+ * Generates equals methods and a hashCode method for a structure.
+ *
+ * @param tstruct The struct definition
+ */
+void t_javame_generator::generate_java_struct_equality(ostream& out, t_struct* tstruct) {
+  out << indent() << "public boolean equals(Object that) {" << endl;
+  indent_up();
+  out << indent() << "if (that == null)" << endl << indent() << "  return false;" << endl
+      << indent() << "if (that instanceof " << tstruct->get_name() << ")" << endl << indent()
+      << "  return this.equals((" << tstruct->get_name() << ")that);" << endl << indent()
+      << "return false;" << endl;
+  scope_down(out);
+  out << endl;
+
+  out << indent() << "public boolean equals(" << tstruct->get_name() << " that) {" << endl;
+  indent_up();
+  out << indent() << "if (that == null)" << endl << indent() << "  return false;" << endl
+      << indent() << "if (this == that)" << endl << indent() << "  return true;"  << endl;
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    out << endl;
+
+    t_type* t = get_true_type((*m_iter)->get_type());
+    // Most existing Thrift code does not use isset or optional/required,
+    // so we treat "default" fields as required.
+    bool is_optional = (*m_iter)->get_req() == t_field::T_OPTIONAL;
+    bool can_be_null = type_can_be_null(t);
+    string name = (*m_iter)->get_name();
+
+    string this_present = "true";
+    string that_present = "true";
+    string unequal;
+
+    if (is_optional || can_be_null) {
+      this_present += " && this." + generate_isset_check(*m_iter);
+      that_present += " && that." + generate_isset_check(*m_iter);
+    }
+
+    out << indent() << "boolean this_present_" << name << " = " << this_present << ";" << endl
+        << indent() << "boolean that_present_" << name << " = " << that_present << ";" << endl
+        << indent() << "if ("
+        << "this_present_" << name << " || that_present_" << name << ") {" << endl;
+    indent_up();
+    out << indent() << "if (!("
+        << "this_present_" << name << " && that_present_" << name << "))" << endl << indent()
+        << "  return false;" << endl;
+
+    if (t->is_binary()) {
+      unequal = "TBaseHelper.compareTo(this." + name + ", that." + name + ") != 0";
+    } else if (can_be_null) {
+      unequal = "!this." + name + ".equals(that." + name + ")";
+    } else {
+      unequal = "this." + name + " != that." + name;
+    }
+
+    out << indent() << "if (" << unequal << ")" << endl << indent() << "  return false;" << endl;
+
+    scope_down(out);
+  }
+  out << endl;
+  indent(out) << "return true;" << endl;
+  scope_down(out);
+  out << endl;
+
+  out << indent() << "public int hashCode() {" << endl;
+  indent_up();
+  indent(out) << "return 0;" << endl;
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+void t_javame_generator::generate_java_struct_compare_to(ostream& out, t_struct* tstruct) {
+  indent(out) << "public int compareTo(Object otherObject) {" << endl;
+  //  indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl;
+  indent_up();
+
+  indent(out) << "if (!getClass().equals(otherObject.getClass())) {" << endl;
+  indent(out) << "  return getClass().getName().compareTo(otherObject.getClass().getName());"
+              << endl;
+  indent(out) << "}" << endl;
+  out << endl;
+  indent(out) << type_name(tstruct) << " other = (" << type_name(tstruct) << ")otherObject;";
+
+  indent(out) << "int lastComparison = 0;" << endl;
+  out << endl;
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_field* field = *m_iter;
+    indent(out) << "lastComparison = TBaseHelper.compareTo(" << generate_isset_check(field)
+                << ", other." << generate_isset_check(field) << ");" << endl;
+    indent(out) << "if (lastComparison != 0) {" << endl;
+    indent(out) << "  return lastComparison;" << endl;
+    indent(out) << "}" << endl;
+
+    indent(out) << "if (" << generate_isset_check(field) << ") {" << endl;
+    if (field->get_type()->is_struct() || field->get_type()->is_xception()) {
+      indent(out) << "  lastComparison = this." << field->get_name() << ".compareTo(other."
+                  << field->get_name() << ");" << endl;
+    } else {
+      indent(out) << "  lastComparison = TBaseHelper.compareTo(this." << field->get_name()
+                  << ", other." << field->get_name() << ");" << endl;
+    }
+
+    indent(out) << "  if (lastComparison != 0) {" << endl;
+    indent(out) << "    return lastComparison;" << endl;
+    indent(out) << "  }" << endl;
+    indent(out) << "}" << endl;
+  }
+
+  indent(out) << "return 0;" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to read all the fields of the struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_javame_generator::generate_java_struct_reader(ostream& out, t_struct* tstruct) {
+  out << indent() << "public void read(TProtocol iprot) throws TException {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Declare stack tmp variables and read struct header
+  out << indent() << "TField field;" << endl << indent() << "iprot.readStructBegin();" << endl;
+
+  // Loop over reading in fields
+  indent(out) << "while (true)" << endl;
+  scope_up(out);
+
+  // Read beginning field marker
+  indent(out) << "field = iprot.readFieldBegin();" << endl;
+
+  // Check for field STOP marker and break
+  indent(out) << "if (field.type == TType.STOP) { " << endl;
+  indent_up();
+  indent(out) << "break;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+
+  // Switch statement on the field we are reading
+  indent(out) << "switch (field.id) {" << endl;
+
+  indent_up();
+
+  // Generate deserialization code for known cases
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) << "case " << (*f_iter)->get_key() << ": // "
+                << constant_name((*f_iter)->get_name()) << endl;
+    indent_up();
+    indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+    indent_up();
+
+    generate_deserialize_field(out, *f_iter, "this.");
+    generate_isset_set(out, *f_iter);
+    indent_down();
+    out << indent() << "} else { " << endl << indent() << "  TProtocolUtil.skip(iprot, field.type);"
+        << endl << indent() << "}" << endl << indent() << "break;" << endl;
+    indent_down();
+  }
+
+  indent(out) << "default:" << endl;
+  indent(out) << "  TProtocolUtil.skip(iprot, field.type);" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  // Read field end marker
+  indent(out) << "iprot.readFieldEnd();" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl;
+
+  out << indent() << "iprot.readStructEnd();" << endl;
+
+  // performs various checks (e.g. check that all required fields are set)
+  indent(out) << "validate();" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+// generates java method to perform various checks
+// (e.g. check that all required fields are set)
+void t_javame_generator::generate_java_validator(ostream& out, t_struct* tstruct) {
+  indent(out) << "public void validate() throws TException {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out << indent() << "// check for required fields" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
+      out << indent() << "if (!" << generate_isset_check(*f_iter) << ") {" << endl << indent()
+          << "  throw new TProtocolException(\"Required field '" << (*f_iter)->get_name()
+          << "' is unset! Struct:\" + toString());" << endl << indent() << "}" << endl << endl;
+    }
+  }
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_javame_generator::generate_java_struct_writer(ostream& out, t_struct* tstruct) {
+  out << indent() << "public void write(TProtocol oprot) throws TException {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // performs various checks (e.g. check that all required fields are set)
+  indent(out) << "validate();" << endl << endl;
+
+  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    bool null_allowed = type_can_be_null((*f_iter)->get_type());
+    if (null_allowed) {
+      out << indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
+      indent_up();
+    }
+    bool optional = (*f_iter)->get_req() == t_field::T_OPTIONAL;
+    if (optional) {
+      indent(out) << "if (" << generate_isset_check((*f_iter)) << ") {" << endl;
+      indent_up();
+    }
+
+    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name())
+                << "_FIELD_DESC);" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "this.");
+
+    // Write field closer
+    indent(out) << "oprot.writeFieldEnd();" << endl;
+
+    if (optional) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    if (null_allowed) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+  // Write the struct map
+  out << indent() << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();"
+      << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates a function to write all the fields of the struct,
+ * which is a function result. These fields are only written
+ * if they are set in the Isset array, and only one of them
+ * can be set at a time.
+ *
+ * @param tstruct The struct definition
+ */
+void t_javame_generator::generate_java_struct_result_writer(ostream& out, t_struct* tstruct) {
+  out << indent() << "public void write(TProtocol oprot) throws TException {" << endl;
+  indent_up();
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl;
+
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      out << endl << indent() << "if ";
+    } else {
+      out << " else if ";
+    }
+
+    out << "(this." << generate_isset_check(*f_iter) << ") {" << endl;
+
+    indent_up();
+
+    indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name())
+                << "_FIELD_DESC);" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "this.");
+
+    // Write field closer
+    indent(out) << "oprot.writeFieldEnd();" << endl;
+
+    indent_down();
+    indent(out) << "}";
+  }
+  // Write the struct map
+  out << endl << indent() << "oprot.writeFieldStop();" << endl << indent()
+      << "oprot.writeStructEnd();" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+void t_javame_generator::generate_reflection_getters(ostringstream& out,
+                                                     t_type* type,
+                                                     string field_name,
+                                                     string cap_name) {
+  indent(out) << "case " << constant_name(field_name) << ":" << endl;
+  indent_up();
+
+  if (type->is_base_type() && !type->is_string()) {
+    t_base_type* base_type = (t_base_type*)type;
+
+    indent(out) << "return new " << type_name(type, true, false) << "("
+                << (base_type->is_bool() ? "is" : "get") << cap_name << "());" << endl << endl;
+  } else {
+    indent(out) << "return get" << cap_name << "();" << endl << endl;
+  }
+
+  indent_down();
+}
+
+void t_javame_generator::generate_reflection_setters(ostringstream& out,
+                                                     t_type* type,
+                                                     string field_name,
+                                                     string cap_name) {
+  indent(out) << "case " << constant_name(field_name) << ":" << endl;
+  indent_up();
+  indent(out) << "if (value == null) {" << endl;
+  indent(out) << "  unset" << get_cap_name(field_name) << "();" << endl;
+  indent(out) << "} else {" << endl;
+  indent(out) << "  set" << cap_name << "((" << type_name(type, true, false) << ")value);" << endl;
+  indent(out) << "}" << endl;
+  indent(out) << "break;" << endl << endl;
+
+  indent_down();
+}
+
+void t_javame_generator::generate_generic_field_getters_setters(std::ostream& out,
+                                                                t_struct* tstruct) {
+  (void)out;
+  std::ostringstream getter_stream;
+  std::ostringstream setter_stream;
+
+  // build up the bodies of both the getter and setter at once
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    t_type* type = get_true_type(field->get_type());
+    std::string field_name = field->get_name();
+    std::string cap_name = get_cap_name(field_name);
+
+    indent_up();
+    generate_reflection_setters(setter_stream, type, field_name, cap_name);
+    generate_reflection_getters(getter_stream, type, field_name, cap_name);
+    indent_down();
+  }
+}
+
+/**
+ * Generates a set of Java Bean boilerplate functions (setters, getters, etc.)
+ * for the given struct.
+ *
+ * @param tstruct The struct definition
+ */
+void t_javame_generator::generate_java_bean_boilerplate(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = *f_iter;
+    t_type* type = get_true_type(field->get_type());
+    std::string field_name = field->get_name();
+    std::string cap_name = get_cap_name(field_name);
+
+    if (type->is_container()) {
+      // Method to return the size of the collection
+      indent(out) << "public int get" << cap_name;
+      out << get_cap_name("size() {") << endl;
+
+      indent_up();
+      indent(out) << "return (this." << field_name << " == null) ? 0 : "
+                  << "this." << field_name << ".size();" << endl;
+      indent_down();
+      indent(out) << "}" << endl << endl;
+    }
+
+    if (type->is_set() || type->is_list()) {
+
+      t_type* element_type;
+      if (type->is_set()) {
+        element_type = ((t_set*)type)->get_elem_type();
+      } else {
+        element_type = ((t_list*)type)->get_elem_type();
+      }
+
+      // Iterator getter for sets and lists
+      indent(out) << "public Enumeration get" << cap_name;
+      out << get_cap_name("Enumeration() {") << endl;
+
+      indent_up();
+      indent(out) << "return (this." << field_name << " == null) ? null : "
+                  << "this." << field_name << ".elements();" << endl;
+      indent_down();
+      indent(out) << "}" << endl << endl;
+
+      // Add to set or list, create if the set/list is null
+      indent(out);
+      out << "public void add" << get_cap_name("to");
+      out << cap_name << "(" << type_name(element_type) << " elem) {" << endl;
+
+      indent_up();
+      indent(out) << "if (this." << field_name << " == null) {" << endl;
+      indent_up();
+      indent(out) << "this." << field_name << " = new " << type_name(type, false, true) << "();"
+                  << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+      if (type->is_set()) {
+        indent(out) << "this." << field_name << ".put(" << box_type(element_type, "elem") << ", "
+                    << box_type(element_type, "elem") << ");" << endl;
+      } else {
+        indent(out) << "this." << field_name << ".addElement(" << box_type(element_type, "elem")
+                    << ");" << endl;
+      }
+      indent_down();
+      indent(out) << "}" << endl << endl;
+
+    } else if (type->is_map()) {
+      // Put to map
+      t_type* key_type = ((t_map*)type)->get_key_type();
+      t_type* val_type = ((t_map*)type)->get_val_type();
+
+      indent(out);
+      out << "public void putTo" << cap_name << "(" << type_name(key_type, true) << " key, "
+          << type_name(val_type, true) << " val) {" << endl;
+
+      indent_up();
+      indent(out) << "if (this." << field_name << " == null) {" << endl;
+      indent_up();
+      indent(out) << "this." << field_name << " = new " << type_name(type, false, true) << "();"
+                  << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+      indent(out) << "this." << field_name << ".put(key, val);" << endl;
+      indent_down();
+      indent(out) << "}" << endl << endl;
+    }
+
+    // Simple getter
+    generate_java_doc(out, field);
+    indent(out) << "public " << type_name(type);
+    if (type->is_base_type() && ((t_base_type*)type)->get_base() == t_base_type::TYPE_BOOL) {
+      out << " is";
+    } else {
+      out << " get";
+    }
+    out << cap_name << "() {" << endl;
+    indent_up();
+    indent(out) << "return this." << field_name << ";" << endl;
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // Simple setter
+    generate_java_doc(out, field);
+    indent(out) << "public ";
+    out << "void";
+    out << " set" << cap_name << "(" << type_name(type) << " " << field_name << ") {" << endl;
+    indent_up();
+    indent(out) << "this." << field_name << " = " << field_name << ";" << endl;
+    generate_isset_set(out, field);
+
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // Unsetter
+    indent(out) << "public void unset" << cap_name << "() {" << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "this." << field_name << " = null;" << endl;
+    } else {
+      indent(out) << "__isset_vector[" << isset_field_id(field) << "] = false;" << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    // isSet method
+    indent(out) << "/** Returns true if field " << field_name
+                << " is set (has been assigned a value) and false otherwise */" << endl;
+    indent(out) << "public boolean is" << get_cap_name("set") << cap_name << "() {" << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "return this." << field_name << " != null;" << endl;
+    } else {
+      indent(out) << "return __isset_vector[" << isset_field_id(field) << "];" << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+
+    indent(out) << "public void set" << cap_name << get_cap_name("isSet") << "(boolean value) {"
+                << endl;
+    indent_up();
+    if (type_can_be_null(type)) {
+      indent(out) << "if (!value) {" << endl;
+      indent(out) << "  this." << field_name << " = null;" << endl;
+      indent(out) << "}" << endl;
+    } else {
+      indent(out) << "__isset_vector[" << isset_field_id(field) << "] = value;" << endl;
+    }
+    indent_down();
+    indent(out) << "}" << endl << endl;
+  }
+}
+
+/**
+ * Generates a toString() method for the given struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_javame_generator::generate_java_struct_tostring(ostream& out, t_struct* tstruct) {
+  out << indent() << "public String toString() {" << endl;
+  indent_up();
+
+  out << indent() << "StringBuffer sb = new StringBuffer(\"" << tstruct->get_name() << "(\");"
+      << endl;
+  out << indent() << "boolean first = true;" << endl << endl;
+
+  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) {
+    bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
+    if (could_be_unset) {
+      indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl;
+      indent_up();
+    }
+
+    t_field* field = (*f_iter);
+
+    if (!first) {
+      indent(out) << "if (!first) sb.append(\", \");" << endl;
+    }
+    indent(out) << "sb.append(\"" << (*f_iter)->get_name() << ":\");" << endl;
+    bool can_be_null = type_can_be_null(field->get_type());
+    if (can_be_null) {
+      indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl;
+      indent(out) << "  sb.append(\"null\");" << endl;
+      indent(out) << "} else {" << endl;
+      indent_up();
+    }
+
+    if (field->get_type()->is_binary()) {
+      indent(out) << "TBaseHelper.toString(this." << field->get_name() << ", sb);" << endl;
+    } else {
+      indent(out) << "sb.append(this." << (*f_iter)->get_name() << ");" << endl;
+    }
+
+    if (can_be_null) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    indent(out) << "first = false;" << endl;
+
+    if (could_be_unset) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    first = false;
+  }
+  out << indent() << "sb.append(\")\");" << endl << indent() << "return sb.toString();" << endl;
+
+  indent_down();
+  indent(out) << "}" << endl << endl;
+}
+
+/**
+ * Returns a string with the java representation of the given thrift type
+ * (e.g. for the type struct it returns "TType.STRUCT")
+ */
+std::string t_javame_generator::get_java_type_string(t_type* type) {
+  if (type->is_list()) {
+    return "TType.LIST";
+  } else if (type->is_map()) {
+    return "TType.MAP";
+  } else if (type->is_set()) {
+    return "TType.SET";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.STRUCT";
+  } else if (type->is_enum()) {
+    return "TType.ENUM";
+  } else if (type->is_typedef()) {
+    return get_java_type_string(((t_typedef*)type)->get_type());
+  } else if (type->is_base_type()) {
+    switch (((t_base_type*)type)->get_base()) {
+    case t_base_type::TYPE_VOID:
+      return "TType.VOID";
+      break;
+    case t_base_type::TYPE_STRING:
+      return "TType.STRING";
+      break;
+    case t_base_type::TYPE_BOOL:
+      return "TType.BOOL";
+      break;
+    case t_base_type::TYPE_I8:
+      return "TType.BYTE";
+      break;
+    case t_base_type::TYPE_I16:
+      return "TType.I16";
+      break;
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+      break;
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      return "TType.DOUBLE";
+      break;
+    default:
+      throw std::runtime_error("Unknown thrift type \"" + type->get_name()
+                               + "\" passed to t_javame_generator::get_java_type_string!");
+      break; // This should never happen!
+    }
+  } else {
+    throw std::runtime_error(
+        "Unknown thrift type \"" + type->get_name()
+        + "\" passed to t_javame_generator::get_java_type_string!"); // This should never happen!
+  }
+}
+
+void t_javame_generator::generate_field_value_meta_data(std::ostream& out, t_type* type) {
+  out << endl;
+  indent_up();
+  indent_up();
+  if (type->is_struct() || type->is_xception()) {
+    indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type) << ".class";
+  } else if (type->is_container()) {
+    if (type->is_list()) {
+      indent(out) << "new ListMetaData(TType.LIST, ";
+      t_type* elem_type = ((t_list*)type)->get_elem_type();
+      generate_field_value_meta_data(out, elem_type);
+    } else if (type->is_set()) {
+      indent(out) << "new SetMetaData(TType.SET, ";
+      t_type* elem_type = ((t_list*)type)->get_elem_type();
+      generate_field_value_meta_data(out, elem_type);
+    } else { // map
+      indent(out) << "new MapMetaData(TType.MAP, ";
+      t_type* key_type = ((t_map*)type)->get_key_type();
+      t_type* val_type = ((t_map*)type)->get_val_type();
+      generate_field_value_meta_data(out, key_type);
+      out << ", ";
+      generate_field_value_meta_data(out, val_type);
+    }
+  } else if (type->is_enum()) {
+    indent(out) << "new EnumMetaData(TType.ENUM, " << type_name(type) << ".class";
+  } else {
+    indent(out) << "new FieldValueMetaData(" << get_java_type_string(type);
+    if (type->is_typedef()) {
+      indent(out) << ", \"" << ((t_typedef*)type)->get_symbolic() << "\"";
+    }
+  }
+  out << ")";
+  indent_down();
+  indent_down();
+}
+
+/**
+ * Generates a thrift service. In C++, this comprises an entirely separate
+ * header and source file. The header file defines the methods and includes
+ * the data types defined in the main header file, and the implementation
+ * file contains implementations of the basic printer and default interfaces.
+ *
+ * @param tservice The service definition
+ */
+void t_javame_generator::generate_service(t_service* tservice) {
+  // Make output file
+  string f_service_name = package_dir_ + "/" + service_name_ + ".java";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports();
+
+  f_service_ << "public class " << service_name_ << " {" << endl << endl;
+  indent_up();
+
+  // Generate the three main parts of the service
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+
+  indent_down();
+  f_service_ << "}" << endl;
+  f_service_.close();
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_javame_generator::generate_primitive_service_interface(t_service* tservice) {
+  f_service_ << indent() << "public interface Iface extends " << service_name_ << "Iface { }"
+             << endl << endl;
+
+  string f_interface_name = package_dir_ + "/" + service_name_ + "Iface.java";
+  ofstream_with_content_based_conditional_update f_iface;
+  f_iface.open(f_interface_name.c_str());
+
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends_iface = " extends " + type_name(tservice->get_extends()) + "Iface";
+  }
+
+  f_iface << autogen_comment() << java_package() << java_type_imports() << java_thrift_imports();
+  generate_java_doc(f_iface, tservice);
+  f_iface << "public interface " << service_name_ << "Iface" << extends_iface << " {" << endl
+          << endl;
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_java_doc(f_iface, *f_iter);
+    f_iface << "  public " << function_signature(*f_iter) << ";" << endl << endl;
+  }
+  f_iface << "}" << endl << endl;
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_javame_generator::generate_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_iface = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_iface = " extends " + extends + ".Iface";
+  }
+
+  generate_java_doc(f_service_, tservice);
+  f_service_ << indent() << "public interface Iface" << extends_iface << " {" << endl << endl;
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_java_doc(f_service_, *f_iter);
+    indent(f_service_) << "public " << function_signature(*f_iter) << ";" << endl << endl;
+  }
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates structs for all the service args and return types
+ *
+ * @param tservice The service
+ */
+void t_javame_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_java_struct_definition(f_service_, ts, false, true);
+    generate_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_javame_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_client = " extends " + extends + ".Client";
+  }
+
+  indent(f_service_) << "public static class Client" << extends_client
+                     << " implements TServiceClient, Iface {" << endl;
+  indent_up();
+
+  indent(f_service_) << "public Client(TProtocol prot)" << endl;
+  scope_up(f_service_);
+  indent(f_service_) << "this(prot, prot);" << endl;
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  indent(f_service_) << "public Client(TProtocol iprot, TProtocol oprot)" << endl;
+  scope_up(f_service_);
+  if (extends.empty()) {
+    f_service_ << indent() << "iprot_ = iprot;" << endl << indent() << "oprot_ = oprot;" << endl;
+  } else {
+    f_service_ << indent() << "super(iprot, oprot);" << endl;
+  }
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_ << indent() << "protected TProtocol iprot_;" << endl << indent()
+               << "protected TProtocol oprot_;" << endl << endl << indent()
+               << "protected int seqid_;" << endl << endl;
+
+    indent(f_service_) << "public TProtocol getInputProtocol()" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "return this.iprot_;" << endl;
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    indent(f_service_) << "public TProtocol getOutputProtocol()" << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "return this.oprot_;" << endl;
+    scope_down(f_service_);
+    f_service_ << 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) {
+    string funname = (*f_iter)->get_name();
+
+    // Open function
+    indent(f_service_) << "public " << function_signature(*f_iter) << endl;
+    scope_up(f_service_);
+    indent(f_service_) << "send_" << funname << "(";
+
+    // Get the struct of function call params
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+
+    // Declare the function arguments
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    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;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "return ";
+      }
+      f_service_ << "recv_" << funname << "();" << endl;
+    }
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    t_function send_function(g_type_void,
+                             string("send_") + (*f_iter)->get_name(),
+                             (*f_iter)->get_arglist());
+
+    string argsname = (*f_iter)->get_name() + "_args";
+
+    // Open function
+    indent(f_service_) << "public " << function_signature(&send_function) << endl;
+    scope_up(f_service_);
+
+    // Serialize the request
+    f_service_ << indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname << "\", "
+               << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL")
+               << ", ++seqid_));" << endl << indent() << argsname << " args = new " << argsname
+               << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << indent() << "args.set" << get_cap_name((*fld_iter)->get_name()) << "("
+                 << (*fld_iter)->get_name() << ");" << endl;
+    }
+
+    f_service_ << indent() << "args.write(oprot_);" << endl << indent()
+               << "oprot_.writeMessageEnd();" << endl << indent()
+               << "oprot_.getTransport().flush();" << endl;
+
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      string resultname = (*f_iter)->get_name() + "_result";
+
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs,
+                               (*f_iter)->get_xceptions());
+      // Open function
+      indent(f_service_) << "public " << function_signature(&recv_function) << endl;
+      scope_up(f_service_);
+
+      f_service_ << indent() << "TMessage msg = iprot_.readMessageBegin();" << endl << indent()
+                 << "if (msg.type == TMessageType.EXCEPTION) {" << endl << indent()
+                 << "  TApplicationException x = TApplicationException.read(iprot_);" << endl
+                 << indent() << "  iprot_.readMessageEnd();" << endl << indent() << "  throw x;"
+                 << endl << indent() << "}" << endl << indent() << "if (msg.seqid != seqid_) {"
+                 << endl << indent()
+                 << "  throw new TApplicationException(TApplicationException.BAD_SEQUENCE_ID, \""
+                 << (*f_iter)->get_name() << " failed: out of sequence response\");" << endl
+                 << indent() << "}" << endl << indent() << resultname << " result = new "
+                 << resultname << "();" << endl << indent() << "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() << "if (result." << generate_isset_check("success") << ") {" << endl
+                   << indent() << "  return result.success;" << endl << indent() << "}" << 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." << (*x_iter)->get_name() << " != null) {" << endl
+                   << indent() << "  throw result." << (*x_iter)->get_name() << ";" << endl
+                   << indent() << "}" << endl;
+      }
+
+      // If you get here it's an exception, unless a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) << "return;" << endl;
+      } else {
+        f_service_ << indent()
+                   << "throw new TApplicationException(TApplicationException.MISSING_RESULT, \""
+                   << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
+      }
+
+      // Close function
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl;
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_javame_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  // Extends stuff
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_processor = " extends " + extends + ".Processor";
+  }
+
+  // Generate the header portion
+  indent(f_service_) << "public static class Processor" << extends_processor
+                     << " implements TProcessor {" << endl;
+  indent_up();
+
+  indent(f_service_) << "public Processor(Iface iface)" << endl;
+  scope_up(f_service_);
+  if (!extends.empty()) {
+    f_service_ << indent() << "super(iface);" << endl;
+  }
+  f_service_ << indent() << "iface_ = iface;" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << indent() << "processMap_.put(\"" << (*f_iter)->get_name() << "\", new "
+               << (*f_iter)->get_name() << "());" << endl;
+  }
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  if (extends.empty()) {
+    f_service_
+        << indent() << "protected static interface ProcessFunction {" << endl << indent()
+        << "  public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException;"
+        << endl << indent() << "}" << endl << endl;
+  }
+
+  f_service_ << indent() << "private Iface iface_;" << endl;
+
+  if (extends.empty()) {
+    f_service_ << indent() << "protected final Hashtable processMap_ = new Hashtable();" << endl;
+  }
+
+  f_service_ << endl;
+
+  // Generate the server implementation
+  indent(f_service_) << "public boolean process(TProtocol iprot, TProtocol oprot) throws TException"
+                     << endl;
+  scope_up(f_service_);
+
+  f_service_ << indent() << "TMessage msg = iprot.readMessageBegin();" << endl;
+
+  // TODO(mcslee): validate message, was the seqid etc. legit?
+
+  f_service_
+      << indent() << "ProcessFunction fn = (ProcessFunction)processMap_.get(msg.name);" << endl
+      << indent() << "if (fn == null) {" << endl << indent()
+      << "  TProtocolUtil.skip(iprot, TType.STRUCT);" << endl << indent()
+      << "  iprot.readMessageEnd();" << endl << indent()
+      << "  TApplicationException x = new "
+         "TApplicationException(TApplicationException.UNKNOWN_METHOD, \"Invalid method name: "
+         "'\"+msg.name+\"'\");" << endl << indent()
+      << "  oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));"
+      << endl << indent() << "  x.write(oprot);" << endl << indent() << "  oprot.writeMessageEnd();"
+      << endl << indent() << "  oprot.getTransport().flush();" << endl << indent()
+      << "  return true;" << endl << indent() << "}" << endl << indent()
+      << "fn.process(msg.seqid, iprot, oprot);" << endl;
+
+  f_service_ << indent() << "return true;" << endl;
+
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+  indent(f_service_) << "}" << endl << endl;
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_javame_generator::generate_function_helpers(t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return;
+  }
+
+  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_java_struct_definition(f_service_, &result, false, true, true);
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_javame_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+  // Open class
+  indent(f_service_) << "private class " << tfunction->get_name() << " implements ProcessFunction {"
+                     << endl;
+  indent_up();
+
+  // Open function
+  indent(f_service_)
+      << "public void process(int seqid, TProtocol iprot, TProtocol oprot) throws TException"
+      << endl;
+  scope_up(f_service_);
+
+  string argsname = tfunction->get_name() + "_args";
+  string resultname = tfunction->get_name() + "_result";
+
+  f_service_ << indent() << argsname << " args = new " << argsname << "();" << endl << indent()
+             << "try {" << endl;
+  indent_up();
+  f_service_ << indent() << "args.read(iprot);" << endl;
+  indent_down();
+  f_service_ << indent() << "} catch (TProtocolException e) {" << endl;
+  indent_up();
+  f_service_ << indent() << "iprot.readMessageEnd();" << endl << indent()
+             << "TApplicationException x = new "
+                "TApplicationException(TApplicationException.PROTOCOL_ERROR, e.getMessage());"
+             << endl << indent() << "oprot.writeMessageBegin(new TMessage(\""
+             << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl << indent()
+             << "x.write(oprot);" << endl << indent() << "oprot.writeMessageEnd();" << endl
+             << indent() << "oprot.getTransport().flush();" << endl << indent() << "return;"
+             << endl;
+  indent_down();
+  f_service_ << indent() << "}" << endl;
+  f_service_ << indent() << "iprot.readMessageEnd();" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << resultname << " result = new " << resultname << "();" << endl;
+  }
+
+  // Try block for a function with exceptions
+  if (xceptions.size() > 0) {
+    f_service_ << indent() << "try {" << endl;
+    indent_up();
+  }
+
+  // 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_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "result.success = ";
+  }
+  f_service_ << "iface_." << 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." << (*f_iter)->get_name();
+  }
+  f_service_ << ");" << endl;
+
+  // Set isset on success field
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()
+      && !type_can_be_null(tfunction->get_returntype())) {
+    f_service_ << indent() << "result.set" << get_cap_name("success") << get_cap_name("isSet")
+               << "(true);" << endl;
+  }
+
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    indent_down();
+    f_service_ << indent() << "}";
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << " catch (" << type_name((*x_iter)->get_type(), false, false) << " "
+                 << (*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();
+        f_service_ << indent() << "}";
+      } else {
+        f_service_ << "}";
+      }
+    }
+    f_service_ << " catch (Throwable th) {" << endl;
+    indent_up();
+    f_service_ << indent() << "TApplicationException x = new "
+                              "TApplicationException(TApplicationException.INTERNAL_ERROR, "
+                              "\"Internal error processing " << tfunction->get_name() << "\");"
+               << endl << indent() << "oprot.writeMessageBegin(new TMessage(\""
+               << tfunction->get_name() << "\", TMessageType.EXCEPTION, seqid));" << endl
+               << indent() << "x.write(oprot);" << endl << indent() << "oprot.writeMessageEnd();"
+               << endl << indent() << "oprot.getTransport().flush();" << endl << indent()
+               << "return;" << endl;
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+  }
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    f_service_ << indent() << "return;" << endl;
+    scope_down(f_service_);
+
+    // Close class
+    indent_down();
+    f_service_ << indent() << "}" << endl << endl;
+    return;
+  }
+
+  f_service_ << indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name()
+             << "\", TMessageType.REPLY, seqid));" << endl << indent() << "result.write(oprot);"
+             << endl << indent() << "oprot.writeMessageEnd();" << endl << indent()
+             << "oprot.getTransport().flush();" << endl;
+
+  // Close function
+  scope_down(f_service_);
+  f_service_ << endl;
+
+  // Close class
+  indent_down();
+  f_service_ << indent() << "}" << endl << endl;
+}
+
+/**
+ * Deserializes a field of any type.
+ *
+ * @param tfield The field
+ * @param prefix The variable name or container for this field
+ */
+void t_javame_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name();
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type()) {
+    indent(out) << name << " = iprot.";
+
+    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:
+      if (!type->is_binary()) {
+        out << "readString();";
+      } else {
+        out << "readBinary();";
+      }
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << "readBool();";
+      break;
+    case t_base_type::TYPE_I8:
+      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 Java name for base type " + t_base_type::t_base_name(tbase);
+    }
+    out << endl;
+  } else if (type->is_enum()) {
+    indent(out) << name << " = "
+                << type_name(tfield->get_type(), true, false) + ".findByValue(iprot.readI32());"
+                << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a struct, invokes read()
+ */
+void t_javame_generator::generate_deserialize_struct(ostream& out,
+                                                     t_struct* tstruct,
+                                                     string prefix) {
+  out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl << indent()
+      << prefix << ".read(iprot);" << endl;
+}
+
+/**
+ * Deserializes a container by reading its size and then iterating
+ */
+void t_javame_generator::generate_deserialize_container(ostream& out,
+                                                        t_type* ttype,
+                                                        string prefix) {
+  scope_up(out);
+
+  string obj;
+
+  if (ttype->is_map()) {
+    obj = tmp("_map");
+  } else if (ttype->is_set()) {
+    obj = tmp("_set");
+  } else if (ttype->is_list()) {
+    obj = tmp("_list");
+  }
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    indent(out) << "TMap " << obj << " = iprot.readMapBegin();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "TSet " << obj << " = iprot.readSetBegin();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "TList " << obj << " = iprot.readListBegin();" << endl;
+  }
+
+  indent(out) << prefix << " = new " << type_name(ttype, false, true)
+              // size the collection correctly
+              << "(" << (ttype->is_list() ? "" : "2*") << obj << ".size"
+              << ");" << endl;
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".size"
+              << "; "
+              << "++" << i << ")" << endl;
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  scope_down(out);
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "iprot.readMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "iprot.readSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "iprot.readListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_javame_generator::generate_deserialize_map_element(ostream& out,
+                                                          t_map* tmap,
+                                                          string prefix) {
+  string key = tmp("_key");
+  string val = tmp("_val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) << declare_field(&fkey) << endl;
+  indent(out) << declare_field(&fval) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) << prefix << ".put(" << box_type(tmap->get_key_type(), key) << ", "
+              << box_type(tmap->get_val_type(), val) << ");" << endl;
+}
+
+/**
+ * Deserializes a set element
+ */
+void t_javame_generator::generate_deserialize_set_element(ostream& out,
+                                                          t_set* tset,
+                                                          string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".put(" << box_type(tset->get_elem_type(), elem) << ", "
+              << box_type(tset->get_elem_type(), elem) << ");" << endl;
+}
+
+/**
+ * Deserializes a list element
+ */
+void t_javame_generator::generate_deserialize_list_element(ostream& out,
+                                                           t_list* tlist,
+                                                           string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) << declare_field(&felem) << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".addElement(" << box_type(tlist->get_elem_type(), elem) << ");" << endl;
+}
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_javame_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name());
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, prefix + tfield->get_name());
+  } else if (type->is_enum()) {
+    indent(out) << "oprot.writeI32(" << prefix + tfield->get_name() << ".getValue());" << endl;
+  } else if (type->is_base_type()) {
+    string name = prefix + tfield->get_name();
+    indent(out) << "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:
+        if (type->is_binary()) {
+          out << "writeBinary(" << name << ");";
+        } else {
+          out << "writeString(" << name << ");";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ");";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "writeByte(" << name << ");";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16(" << name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32(" << name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64(" << name << ");";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble(" << name << ");";
+        break;
+      default:
+        throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32(" << name << ");";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type_name(type).c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_javame_generator::generate_serialize_struct(ostream& out,
+                                                   t_struct* tstruct,
+                                                   string prefix) {
+  (void)tstruct;
+  out << indent() << prefix << ".write(oprot);" << endl;
+}
+
+/**
+ * Serializes a container by writing its size then the elements.
+ *
+ * @param ttype  The type of container
+ * @param prefix String prefix for fields
+ */
+void t_javame_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type())
+                << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix
+                << ".size()));" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type())
+                << ", " << prefix << ".size()));" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.writeListBegin(new TList("
+                << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".size()));"
+                << endl;
+  }
+
+  string iter = tmp("_iter");
+  if (ttype->is_map()) {
+    string enumer = iter + "_enum";
+    string key_type = type_name(((t_map*)ttype)->get_key_type(), true, false);
+    indent(out) << "for (Enumeration " << enumer << " = " << prefix << ".keys(); " << enumer
+                << ".hasMoreElements(); ) ";
+    scope_up(out);
+    indent(out) << key_type << " " << iter << " = (" << key_type << ")" << enumer
+                << ".nextElement();" << endl;
+  } else if (ttype->is_set()) {
+    string enumer = iter + "_enum";
+    string ele_type = type_name(((t_list*)ttype)->get_elem_type(), true);
+    indent(out) << "for (Enumeration " << enumer << " = " << prefix << ".keys(); " << enumer
+                << ".hasMoreElements(); ) ";
+    scope_up(out);
+    indent(out) << ele_type << " " << iter << " = (" << ele_type << ")" << enumer
+                << ".nextElement();" << endl;
+  } else if (ttype->is_list()) {
+    string enumer = iter + "_enum";
+    indent(out) << "for (Enumeration " << enumer << " = " << prefix << ".elements(); " << enumer
+                << ".hasMoreElements(); ) ";
+    scope_up(out);
+    string ele_type = type_name(((t_list*)ttype)->get_elem_type(), true);
+    indent(out) << ele_type << " " << iter << " = (" << ele_type << ")" << enumer
+                << ".nextElement();" << endl;
+  }
+
+  if (ttype->is_map()) {
+    generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
+  } else if (ttype->is_set()) {
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+  } else if (ttype->is_list()) {
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+  }
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "oprot.writeMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.writeSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.writeListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ */
+void t_javame_generator::generate_serialize_map_element(ostream& out,
+                                                        t_map* tmap,
+                                                        string iter,
+                                                        string map) {
+  t_field kfield(tmap->get_key_type(), iter);
+  generate_serialize_field(out, &kfield, "");
+  string val_type = type_name(tmap->get_val_type(), true, false);
+  t_field vfield(tmap->get_val_type(), "((" + val_type + ")" + map + ".get(" + iter + "))");
+  generate_serialize_field(out, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_javame_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_javame_generator::generate_serialize_list_element(ostream& out,
+                                                         t_list* tlist,
+                                                         string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Returns a Java type name
+ *
+ * @param ttype The type
+ * @param container Is the type going inside a container?
+ * @return Java type name, i.e. Vector
+ */
+string t_javame_generator::type_name(t_type* ttype,
+                                     bool in_container,
+                                     bool in_init,
+                                     bool skip_generic) {
+  (void)in_init;
+  (void)skip_generic;
+  // In Java typedefs are just resolved to their real type
+  ttype = get_true_type(ttype);
+  string prefix;
+
+  if (ttype->is_base_type()) {
+    return base_type_name((t_base_type*)ttype, in_container);
+  } else if (ttype->is_map()) {
+    return "Hashtable";
+  } else if (ttype->is_set()) {
+    return "Hashtable";
+  } else if (ttype->is_list()) {
+    return "Vector";
+  }
+
+  // Check for namespacing
+  t_program* program = ttype->get_program();
+  if (program != NULL && program != program_) {
+    string package = program->get_namespace("java");
+    if (!package.empty()) {
+      return package + "." + ttype->get_name();
+    }
+  }
+
+  return ttype->get_name();
+}
+
+/**
+ * Returns the C++ type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ * @param container Is it going in a Java container?
+ */
+string t_javame_generator::base_type_name(t_base_type* type, bool in_container) {
+  t_base_type::t_base tbase = type->get_base();
+
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    if (!type->is_binary()) {
+      return "String";
+    } else {
+      return "byte[]";
+    }
+  case t_base_type::TYPE_BOOL:
+    return (in_container ? "Boolean" : "boolean");
+  case t_base_type::TYPE_I8:
+    return (in_container ? "Byte" : "byte");
+  case t_base_type::TYPE_I16:
+    return (in_container ? "Short" : "short");
+  case t_base_type::TYPE_I32:
+    return (in_container ? "Integer" : "int");
+  case t_base_type::TYPE_I64:
+    return (in_container ? "Long" : "long");
+  case t_base_type::TYPE_DOUBLE:
+    return (in_container ? "Double" : "double");
+  default:
+    throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_javame_generator::declare_field(t_field* tfield, bool init) {
+  // TODO(mcslee): do we ever need to initialize the field?
+  string result = type_name(tfield->get_type()) + " " + tfield->get_name();
+  if (init) {
+    t_type* ttype = get_true_type(tfield->get_type());
+    if (ttype->is_base_type() && tfield->get_value() != NULL) {
+      std::ofstream dummy;
+      result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
+    } else if (ttype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "NO T_VOID CONSTRUCT";
+      case t_base_type::TYPE_STRING:
+        result += " = null";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = false";
+        break;
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = (double)0";
+        break;
+      }
+
+    } else if (ttype->is_enum()) {
+      result += " = 0";
+    } else if (ttype->is_container()) {
+      result += " = new " + type_name(ttype, false, true) + "()";
+    } else {
+      result += " = new " + type_name(ttype, false, true) + "()";
+      ;
+    }
+  }
+  return result + ";";
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_javame_generator::function_signature(t_function* tfunction, string prefix) {
+  t_type* ttype = tfunction->get_returntype();
+  std::string result = type_name(ttype) + " " + prefix + tfunction->get_name() + "("
+                       + argument_list(tfunction->get_arglist()) + ") throws ";
+  t_struct* xs = tfunction->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) {
+    result += type_name((*x_iter)->get_type(), false, false) + ", ";
+  }
+  result += "TException";
+  return result;
+}
+
+/**
+ * Renders a comma separated field list, with type names
+ */
+string t_javame_generator::argument_list(t_struct* tstruct, bool include_types) {
+  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 += ", ";
+    }
+    if (include_types) {
+      result += type_name((*f_iter)->get_type()) + " ";
+    }
+    result += (*f_iter)->get_name();
+  }
+  return result;
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ */
+string t_javame_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 "TType.STRING";
+    case t_base_type::TYPE_BOOL:
+      return "TType.BOOL";
+    case t_base_type::TYPE_I8:
+      return "TType.BYTE";
+    case t_base_type::TYPE_I16:
+      return "TType.I16";
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "TType.DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.STRUCT";
+  } else if (type->is_map()) {
+    return "TType.MAP";
+  } else if (type->is_set()) {
+    return "TType.SET";
+  } else if (type->is_list()) {
+    return "TType.LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Applies the correct style to a string based on the value of nocamel_style_
+ */
+std::string t_javame_generator::get_cap_name(std::string name) {
+  name[0] = toupper(name[0]);
+  return name;
+}
+
+string t_javame_generator::constant_name(string name) {
+  string constant_name;
+
+  bool is_first = true;
+  bool was_previous_char_upper = false;
+  for (string::iterator iter = name.begin(); iter != name.end(); ++iter) {
+    string::value_type character = (*iter);
+
+    bool is_upper = isupper(character);
+
+    if (is_upper && !is_first && !was_previous_char_upper) {
+      constant_name += '_';
+    }
+    constant_name += toupper(character);
+
+    is_first = false;
+    was_previous_char_upper = is_upper;
+  }
+
+  return constant_name;
+}
+
+void t_javame_generator::generate_java_docstring_comment(ostream& out, string contents) {
+  generate_docstring_comment(out, "/**\n", " * ", contents, " */\n");
+}
+
+void t_javame_generator::generate_java_doc(ostream& out, t_field* field) {
+  if (field->get_type()->is_enum()) {
+    string combined_message = field->get_doc() + "\n@see " + get_enum_class_name(field->get_type());
+    generate_java_docstring_comment(out, combined_message);
+  } else {
+    generate_java_doc(out, (t_doc*)field);
+  }
+}
+
+/**
+ * Emits a JavaDoc comment if the provided object has a doc in Thrift
+ */
+void t_javame_generator::generate_java_doc(ostream& out, t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    generate_java_docstring_comment(out, tdoc->get_doc());
+  }
+}
+
+/**
+ * Emits a JavaDoc comment if the provided function object has a doc in Thrift
+ */
+void t_javame_generator::generate_java_doc(ostream& out, t_function* tfunction) {
+  if (tfunction->has_doc()) {
+    stringstream ss;
+    ss << tfunction->get_doc();
+    const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+    vector<t_field*>::const_iterator p_iter;
+    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
+      t_field* p = *p_iter;
+      ss << "\n@param " << p->get_name();
+      if (p->has_doc()) {
+        ss << " " << p->get_doc();
+      }
+    }
+    generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n");
+  }
+}
+
+void t_javame_generator::generate_deep_copy_container(ostream& out,
+                                                      std::string source_name_p1,
+                                                      std::string source_name_p2,
+                                                      std::string result_name,
+                                                      t_type* type) {
+
+  t_container* container = (t_container*)type;
+  std::string source_name;
+  if (source_name_p2 == "")
+    source_name = source_name_p1;
+  else
+    source_name = source_name_p1 + "." + source_name_p2;
+
+  indent(out) << type_name(type, true, false) << " " << result_name << " = new "
+              << type_name(container, false, true) << "();" << endl;
+
+  std::string iterator_element_name = source_name_p1 + "_element";
+  std::string enumeration_name = source_name_p1 + "_enum";
+  std::string result_element_name = result_name + "_copy";
+
+  if (container->is_map()) {
+    t_type* key_type = ((t_map*)container)->get_key_type();
+    t_type* val_type = ((t_map*)container)->get_val_type();
+
+    indent(out) << "for (Enumeration " << enumeration_name << " = " << source_name << ".keys(); "
+                << enumeration_name << ".hasMoreElements(); ) {" << endl;
+    indent_up();
+
+    out << endl;
+
+    indent(out) << type_name(key_type, true, false) << " " << iterator_element_name << "_key = ("
+                << type_name(key_type, true, false) << ")" << enumeration_name << ".nextElement();"
+                << endl;
+    indent(out) << type_name(val_type, true, false) << " " << iterator_element_name << "_value = ("
+                << type_name(val_type, true, false) << ")" << source_name << ".get("
+                << iterator_element_name << "_key);" << endl;
+
+    out << endl;
+
+    if (key_type->is_container()) {
+      generate_deep_copy_container(out,
+                                   iterator_element_name + "_key",
+                                   "",
+                                   result_element_name + "_key",
+                                   key_type);
+    } else {
+      indent(out) << type_name(key_type, true, false) << " " << result_element_name << "_key = ";
+      generate_deep_copy_non_container(out,
+                                       iterator_element_name + "_key",
+                                       result_element_name + "_key",
+                                       key_type);
+      out << ";" << endl;
+    }
+
+    out << endl;
+
+    if (val_type->is_container()) {
+      generate_deep_copy_container(out,
+                                   iterator_element_name + "_value",
+                                   "",
+                                   result_element_name + "_value",
+                                   val_type);
+    } else {
+      indent(out) << type_name(val_type, true, false) << " " << result_element_name << "_value = ";
+      generate_deep_copy_non_container(out,
+                                       iterator_element_name + "_value",
+                                       result_element_name + "_value",
+                                       val_type);
+      out << ";" << endl;
+    }
+
+    out << endl;
+
+    indent(out) << result_name << ".put(" << result_element_name << "_key, " << result_element_name
+                << "_value);" << endl;
+
+    indent_down();
+    indent(out) << "}" << endl;
+
+  } else {
+    t_type* elem_type;
+
+    if (container->is_set()) {
+      elem_type = ((t_set*)container)->get_elem_type();
+    } else {
+      elem_type = ((t_list*)container)->get_elem_type();
+    }
+
+    indent(out) << "for (Enumeration " << enumeration_name << " = " << source_name
+                << ".elements(); " << enumeration_name << ".hasMoreElements(); ) {" << endl;
+    indent_up();
+    indent(out) << type_name(elem_type, true, false) << " " << iterator_element_name << " = ("
+                << type_name(elem_type, true, false) << ")" << enumeration_name << ".nextElement();"
+                << endl;
+    if (elem_type->is_container()) {
+      // recursive deep copy
+      generate_deep_copy_container(out, iterator_element_name, "", result_element_name, elem_type);
+      if (elem_type->is_list()) {
+        indent(out) << result_name << ".addElement(" << result_element_name << ");" << endl;
+      } else {
+        indent(out) << result_name << ".put(" << result_element_name << ", " << result_element_name
+                    << ");" << endl;
+      }
+    } else {
+      // iterative copy
+      if (elem_type->is_binary()) {
+        indent(out) << type_name(elem_type, true, false) << " temp_binary_element = ";
+        generate_deep_copy_non_container(out,
+                                         iterator_element_name,
+                                         "temp_binary_element",
+                                         elem_type);
+        out << ";" << endl;
+        if (elem_type->is_list()) {
+          indent(out) << result_name << ".addElement(temp_binary_element);" << endl;
+        } else {
+          indent(out) << result_name << ".put(temp_binary_element, temp_binary_element);" << endl;
+        }
+      } else {
+        indent(out) << result_name << ".addElement(";
+        generate_deep_copy_non_container(out, iterator_element_name, result_name, elem_type);
+        out << ");" << endl;
+      }
+    }
+
+    indent_down();
+
+    indent(out) << "}" << endl;
+  }
+}
+
+void t_javame_generator::generate_deep_copy_non_container(ostream& out,
+                                                          std::string source_name,
+                                                          std::string dest_name,
+                                                          t_type* type) {
+  if (type->is_base_type() || type->is_enum() || type->is_typedef()) {
+    // binary fields need to be copied with System.arraycopy
+    if (type->is_binary()) {
+      out << "new byte[" << source_name << ".length];" << endl;
+      indent(out) << "System.arraycopy(" << source_name << ", 0, " << dest_name << ", 0, "
+                  << source_name << ".length)";
+    }
+    // everything else can be copied directly
+    else
+      out << source_name;
+  } else {
+    out << "new " << type_name(type, true, true) << "(" << source_name << ")";
+  }
+}
+
+std::string t_javame_generator::generate_isset_check(t_field* field) {
+  return generate_isset_check(field->get_name());
+}
+
+std::string t_javame_generator::isset_field_id(t_field* field) {
+  return "__" + upcase_string(field->get_name() + "_isset_id");
+}
+
+std::string t_javame_generator::generate_isset_check(std::string field_name) {
+  return "is" + get_cap_name("set") + get_cap_name(field_name) + "()";
+}
+
+void t_javame_generator::generate_isset_set(ostream& out, t_field* field) {
+  if (!type_can_be_null(field->get_type())) {
+    indent(out) << "set" << get_cap_name(field->get_name()) << get_cap_name("isSet") << "(true);"
+                << endl;
+  }
+}
+
+std::string t_javame_generator::get_enum_class_name(t_type* type) {
+  string package = "";
+  t_program* program = type->get_program();
+  if (program != NULL && program != program_) {
+    package = program->get_namespace("java") + ".";
+  }
+  return package + type->get_name();
+}
+
+void t_javame_generator::generate_struct_desc(ostream& out, t_struct* tstruct) {
+  indent(out) << "private static final TStruct STRUCT_DESC = new TStruct(\"" << tstruct->get_name()
+              << "\");" << endl;
+}
+
+void t_javame_generator::generate_field_descs(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    indent(out) << "private static final TField " << constant_name((*m_iter)->get_name())
+                << "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", "
+                << type_to_enum((*m_iter)->get_type()) << ", "
+                << "(short)" << (*m_iter)->get_key() << ");" << endl;
+  }
+}
+
+bool t_javame_generator::has_bit_vector(t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if (!type_can_be_null(get_true_type((*m_iter)->get_type()))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void t_javame_generator::generate_java_struct_clear(std::ostream& out, t_struct* tstruct) {
+  indent(out) << "public void clear() {" << endl;
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  indent_up();
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    if ((*m_iter)->get_value() != NULL) {
+      print_const_value(out,
+                        "this." + (*m_iter)->get_name(),
+                        t,
+                        (*m_iter)->get_value(),
+                        true,
+                        true);
+    } else {
+      if (type_can_be_null(t)) {
+        indent(out) << "this." << (*m_iter)->get_name() << " = null;" << endl;
+      } else {
+        // must be a base type
+        // means it also needs to be explicitly unset
+        indent(out) << "set" << get_cap_name((*m_iter)->get_name()) << get_cap_name("isSet")
+                    << "(false);" << endl;
+        switch (((t_base_type*)t)->get_base()) {
+        case t_base_type::TYPE_I8:
+        case t_base_type::TYPE_I16:
+        case t_base_type::TYPE_I32:
+        case t_base_type::TYPE_I64:
+          indent(out) << "this." << (*m_iter)->get_name() << " = 0;" << endl;
+          break;
+        case t_base_type::TYPE_DOUBLE:
+          indent(out) << "this." << (*m_iter)->get_name() << " = 0.0;" << endl;
+          break;
+        case t_base_type::TYPE_BOOL:
+          indent(out) << "this." << (*m_iter)->get_name() << " = false;" << endl;
+          break;
+        default: // prevent gcc compiler warning
+          break;
+        }
+      }
+    }
+  }
+  indent_down();
+
+  indent(out) << "}" << endl << endl;
+}
+
+THRIFT_REGISTER_GENERATOR(javame, "Java ME", "")
diff --git a/compiler/cpp/src/thrift/generate/t_js_generator.cc b/compiler/cpp/src/thrift/generate/t_js_generator.cc
new file mode 100644
index 0000000..61782b9
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_js_generator.cc
@@ -0,0 +1,2721 @@
+/*
+ * 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.
+ */
+
+#include <map>
+#include <string>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <limits>
+#include <vector>
+#include <list>
+#include <cassert>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "thrift/platform.h"
+#include "thrift/version.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+#include "thrift/generate/t_oop_generator.h"
+
+
+/**
+ * JS code generator.
+ */
+class t_js_generator : public t_oop_generator {
+public:
+  t_js_generator(t_program* program,
+                 const std::map<std::string, std::string>& parsed_options,
+                 const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    gen_node_ = false;
+    gen_jquery_ = false;
+    gen_ts_ = false;
+    gen_es6_ = false;
+
+    bool with_ns_ = false;
+
+    for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("node") == 0) {
+        gen_node_ = true;
+      } else if( iter->first.compare("jquery") == 0) {
+        gen_jquery_ = true;
+      } else if( iter->first.compare("ts") == 0) {
+        gen_ts_ = true;
+      } else if( iter->first.compare("with_ns") == 0) {
+        with_ns_ = true;
+      } else if( iter->first.compare("es6") == 0) {
+        gen_es6_ = true;
+      } else {
+        throw "unknown option js:" + iter->first;
+      }
+    }
+
+    if (gen_es6_ && gen_jquery_) {
+      throw "Invalid switch: [-gen js:es6,jquery] options not compatible";
+    }
+
+    if (gen_node_ && gen_jquery_) {
+      throw "Invalid switch: [-gen js:node,jquery] options not compatible, try: [-gen js:node -gen "
+            "js:jquery]";
+    }
+
+    if (!gen_node_ && with_ns_) {
+      throw "Invalid switch: [-gen js:with_ns] is only valid when using node.js";
+    }
+
+    // Depending on the processing flags, we will update these to be ES6 compatible
+    js_const_type_ = "var ";
+    js_let_type_ = "var ";
+    js_var_type_ = "var ";
+    if (gen_es6_) {
+      js_const_type_ = "const ";
+      js_let_type_ = "let ";
+    }
+
+    if (gen_node_) {
+      out_dir_base_ = "gen-nodejs";
+      no_ns_ = !with_ns_;
+    } else {
+      out_dir_base_ = "gen-js";
+      no_ns_ = false;
+    }
+
+    escape_['\''] = "\\'";
+  }
+
+  /**
+   * 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_recv_throw(std::string var);
+  std::string render_recv_return(std::string var);
+
+  std::string render_const_value(t_type* type, t_const_value* value);
+
+  /**
+   * Structs!
+   */
+  void generate_js_struct(t_struct* tstruct, bool is_exception);
+  void generate_js_struct_definition(std::ostream& out,
+                                     t_struct* tstruct,
+                                     bool is_xception = false,
+                                     bool is_exported = true);
+  void generate_js_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_js_struct_writer(std::ostream& out, t_struct* tstruct);
+  void generate_js_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_rest(t_service* tservice);
+  void generate_service_client(t_service* tservice);
+  void generate_service_processor(t_service* tservice);
+  void generate_process_function(t_service* tservice, t_function* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field(std::ostream& out,
+                                  t_field* tfield,
+                                  std::string prefix = "",
+                                  bool inclass = false);
+
+  void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+
+  void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         std::string prefix = "");
+
+  void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
+
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string kiter,
+                                      std::string viter);
+
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string js_includes();
+  std::string ts_includes();
+  std::string render_includes();
+  std::string declare_field(t_field* tfield, bool init = false, bool obj = false);
+  std::string function_signature(t_function* tfunction,
+                                 std::string prefix = "",
+                                 bool include_callback = false);
+  std::string argument_list(t_struct* tstruct, bool include_callback = false);
+  std::string type_to_enum(t_type* ttype);
+  std::string make_valid_nodeJs_identifier(std::string const& name);
+
+  std::string autogen_comment() {
+    return std::string("//\n") + "// Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
+           + "//\n" + "// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n"
+           + "//\n";
+  }
+
+  t_type* get_contained_type(t_type* t);
+
+  std::vector<std::string> js_namespace_pieces(t_program* p) {
+    std::string ns = p->get_namespace("js");
+
+    std::string::size_type loc;
+    std::vector<std::string> pieces;
+
+    if (no_ns_) {
+      return pieces;
+    }
+
+    if (ns.size() > 0) {
+      while ((loc = ns.find(".")) != std::string::npos) {
+        pieces.push_back(ns.substr(0, loc));
+        ns = ns.substr(loc + 1);
+      }
+    }
+
+    if (ns.size() > 0) {
+      pieces.push_back(ns);
+    }
+
+    return pieces;
+  }
+
+  std::string js_type_namespace(t_program* p) {
+    if (gen_node_) {
+      if (p != NULL && p != program_) {
+        return make_valid_nodeJs_identifier(p->get_name()) + "_ttypes.";
+      }
+      return "ttypes.";
+    }
+    return js_namespace(p);
+  }
+
+  std::string js_export_namespace(t_program* p) {
+    if (gen_node_) {
+      return "exports.";
+    }
+    return js_namespace(p);
+  }
+
+  bool has_js_namespace(t_program* p) {
+    if (no_ns_) {
+      return false;
+    }
+    std::string ns = p->get_namespace("js");
+    return (ns.size() > 0);
+  }
+
+  std::string js_namespace(t_program* p) {
+    if (no_ns_) {
+      return "";
+    }
+    std::string ns = p->get_namespace("js");
+    if (ns.size() > 0) {
+      ns += ".";
+    }
+
+    return ns;
+  }
+
+  /**
+   * TypeScript Definition File helper functions
+   */
+
+  string ts_function_signature(t_function* tfunction, bool include_callback, bool optional_callback);
+  string ts_get_type(t_type* type);
+
+  /**
+   * Special indentation for TypeScript Definitions because of the module.
+   * Returns the normal indentation + "  " if a module was defined.
+   * @return string
+   */
+  string ts_indent() { return indent() + (!ts_module_.empty() ? "  " : ""); }
+
+  /**
+   * Returns "declare " if no module was defined.
+   * @return string
+   */
+  string ts_declare() { return (ts_module_.empty() ? "declare " : ""); }
+
+  /**
+   * Returns "?" if the given field is optional or has a default value.
+   * @param t_field The field to check
+   * @return string
+   */
+  string ts_get_req(t_field* field) {return (field->get_req() == t_field::T_OPTIONAL || field->get_value() != NULL ? "?" : ""); }
+
+  /**
+   * Returns the documentation, if the provided documentable object has one.
+   * @param t_doc The object to get the documentation from
+   * @return string The documentation
+   */
+  string ts_print_doc(t_doc* tdoc) {
+    string result = endl;
+
+    if (tdoc->has_doc()) {
+      std::stringstream doc(tdoc->get_doc());
+      string item;
+
+      result += ts_indent() + "/**" + endl;
+      while (std::getline(doc, item)) {
+        result += ts_indent() + " * " + item + endl;
+      }
+      result += ts_indent() + " */" + endl;
+    }
+    return result;
+  }
+
+private:
+  /**
+   * True if we should generate NodeJS-friendly RPC services.
+   */
+  bool gen_node_;
+
+  /**
+   * True if we should generate services that use jQuery ajax (async/sync).
+   */
+  bool gen_jquery_;
+
+  /**
+   * True if we should generate a TypeScript Definition File for each service.
+   */
+  bool gen_ts_;
+
+  /**
+   * True if we should generate ES6 code, i.e. with Promises
+   */
+  bool gen_es6_;
+
+  /**
+   * The name of the defined module(s), for TypeScript Definition Files.
+   */
+  string ts_module_;
+
+  /**
+   * True if we should not generate namespace objects for node.
+   */
+  bool no_ns_;
+
+  /**
+   * The variable decorator for "const" variables. Will default to "var" if in an incompatible language.
+   */
+  string js_const_type_;
+
+   /**
+   * The variable decorator for "let" variables. Will default to "var" if in an incompatible language.
+   */
+  string js_let_type_;
+
+   /**
+   * The default variable decorator. Supports all javascript languages, but is not scoped to functions or closures.
+   */
+  string js_var_type_;
+
+  /**
+   * File streams
+   */
+  ofstream_with_content_based_conditional_update f_types_;
+  ofstream_with_content_based_conditional_update f_service_;
+  ofstream_with_content_based_conditional_update f_types_ts_;
+  ofstream_with_content_based_conditional_update f_service_ts_;
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_js_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  string outdir = get_out_dir();
+
+  // Make output file(s)
+  string f_types_name = outdir + program_->get_name() + "_types.js";
+  f_types_.open(f_types_name.c_str());
+
+  if (gen_ts_) {
+    string f_types_ts_name = outdir + program_->get_name() + "_types.d.ts";
+    f_types_ts_.open(f_types_ts_name.c_str());
+  }
+
+  // Print header
+  f_types_ << autogen_comment();
+
+  if ((gen_node_ || gen_es6_) && no_ns_) {
+    f_types_ << "\"use strict\";" << endl << endl;
+  }
+
+  f_types_ << js_includes() << endl << render_includes() << endl;
+
+  if (gen_ts_) {
+    f_types_ts_ << autogen_comment() << ts_includes() << endl;
+  }
+
+  if (gen_node_) {
+    f_types_ << js_const_type_ << "ttypes = module.exports = {};" << endl;
+  }
+
+  string pns;
+
+  // setup the namespace
+  // TODO should the namespace just be in the directory structure for node?
+  vector<string> ns_pieces = js_namespace_pieces(program_);
+  if (ns_pieces.size() > 0) {
+    for (size_t i = 0; i < ns_pieces.size(); ++i) {
+      pns += ((i == 0) ? "" : ".") + ns_pieces[i];
+      f_types_ << "if (typeof " << pns << " === 'undefined') {" << endl;
+      f_types_ << "  " << pns << " = {};" << endl;
+      f_types_ << "}" << endl;
+    }
+    if (gen_ts_) {
+      ts_module_ = pns;
+      f_types_ts_ << "declare module " << ts_module_ << " {";
+    }
+  }
+}
+
+/**
+ * Prints standard js imports
+ */
+string t_js_generator::js_includes() {
+  if (gen_node_) {
+    string result = js_const_type_ + "thrift = require('thrift');\n"
+        + js_const_type_ + "Thrift = thrift.Thrift;\n";
+    if (!gen_es6_) {
+      result += js_const_type_ + "Q = thrift.Q;\n";
+    }
+    return result;
+  }
+
+  return "";
+}
+
+/**
+ * Prints standard ts imports
+ */
+string t_js_generator::ts_includes() {
+  if (gen_node_) {
+    return string(
+        "import thrift = require('thrift');\n"
+        "import Thrift = thrift.Thrift;\n"
+        "import Q = thrift.Q;\n");
+  }
+
+  return "";
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program
+ */
+string t_js_generator::render_includes() {
+  string result = "";
+
+  if (gen_node_) {
+    const vector<t_program*>& includes = program_->get_includes();
+    for (size_t i = 0; i < includes.size(); ++i) {
+      result += js_const_type_ + make_valid_nodeJs_identifier(includes[i]->get_name()) + "_ttypes = require('./" + includes[i]->get_name()
+                + "_types');\n";
+    }
+    if (includes.size() > 0) {
+      result += "\n";
+    }
+  }
+
+  return result;
+}
+
+/**
+ * Close up (or down) some filez.
+ */
+void t_js_generator::close_generator() {
+  // Close types file(s)
+
+  f_types_.close();
+
+  if (gen_ts_) {
+    if (!ts_module_.empty()) {
+      f_types_ts_ << "}";
+    }
+    f_types_ts_.close();
+  }
+}
+
+/**
+ * Generates a typedef. This is not done in JS, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_js_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+/**
+ * Generates code for an enumerated type. Since define is expensive to lookup
+ * in JS, we use a global array for this.
+ *
+ * @param tenum The enumeration
+ */
+void t_js_generator::generate_enum(t_enum* tenum) {
+  f_types_ << js_type_namespace(tenum->get_program()) << tenum->get_name() << " = {" << endl;
+
+  if (gen_ts_) {
+    f_types_ts_ << ts_print_doc(tenum) << ts_indent() << ts_declare() << "enum "
+                << tenum->get_name() << " {" << endl;
+  }
+
+  indent_up();
+
+  vector<t_enum_value*> const& constants = tenum->get_constants();
+  vector<t_enum_value*>::const_iterator c_iter;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    if (gen_ts_) {
+      f_types_ts_ << ts_indent() << (*c_iter)->get_name() << " = " << value << "," << endl;
+      // add 'value: key' in addition to 'key: value' for TypeScript enums
+      f_types_ << indent() << "'" << value << "' : '" << (*c_iter)->get_name() << "'," << endl;
+    }
+    f_types_ << indent() << "'" << (*c_iter)->get_name() << "' : " << value;
+    if (c_iter != constants.end() - 1) {
+      f_types_ << ",";
+    }
+    f_types_ << endl;
+  }
+
+  indent_down();
+
+  f_types_ << "};" << endl;
+
+  if (gen_ts_) {
+    f_types_ts_ << ts_indent() << "}" << endl;
+  }
+}
+
+/**
+ * Generate a constant value
+ */
+void t_js_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  f_types_ << js_type_namespace(program_) << name << " = ";
+  f_types_ << render_const_value(type, value) << ";" << endl;
+
+  if (gen_ts_) {
+    f_types_ts_ << ts_print_doc(tconst) << ts_indent() << ts_declare() << js_const_type_ << name << ": "
+                << ts_get_type(type) << ";" << 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_js_generator::render_const_value(t_type* type, t_const_value* value) {
+  std::ostringstream out;
+
+  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_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_I8:
+    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 << emit_double_as_string(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()) {
+    out << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    out << "new " << js_type_namespace(type->get_program()) << type->get_name() << "({";
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::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 (v_iter != val.begin())
+        out << ",";
+      out << endl << indent() << render_const_value(g_type_string, v_iter->first);
+      out << " : ";
+      out << render_const_value(field_type, v_iter->second);
+    }
+    indent_down();
+    out << endl << indent() << "})";
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    out << "{" << endl;
+    indent_up();
+
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      if (v_iter != val.begin())
+        out << "," << endl;
+
+      out << indent() << render_const_value(ktype, v_iter->first);
+
+      out << " : ";
+      out << render_const_value(vtype, v_iter->second);
+    }
+    indent_down();
+    out << endl << indent() << "}";
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    out << "[";
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      if (v_iter != val.begin())
+        out << ",";
+      out << render_const_value(etype, *v_iter);
+    }
+    out << "]";
+  }
+  return out.str();
+}
+
+/**
+ * Make a struct
+ */
+void t_js_generator::generate_struct(t_struct* tstruct) {
+  generate_js_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_js_generator::generate_xception(t_struct* txception) {
+  generate_js_struct(txception, true);
+}
+
+/**
+ * Structs can be normal or exceptions.
+ */
+void t_js_generator::generate_js_struct(t_struct* tstruct, bool is_exception) {
+  generate_js_struct_definition(f_types_, tstruct, is_exception);
+}
+
+/**
+ * Return type of contained elements for a container type. For maps
+ * this is type of value (keys are always strings in js)
+ */
+t_type* t_js_generator::get_contained_type(t_type* t) {
+  t_type* etype;
+  if (t->is_list()) {
+    etype = ((t_list*)t)->get_elem_type();
+  } else if (t->is_set()) {
+    etype = ((t_set*)t)->get_elem_type();
+  } else {
+    etype = ((t_map*)t)->get_val_type();
+  }
+  return etype;
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This is nothing in JS
+ * where the objects are all just associative arrays (unless of course we
+ * decide to start using objects for them...)
+ *
+ * @param tstruct The struct definition
+ */
+void t_js_generator::generate_js_struct_definition(ostream& out,
+                                                   t_struct* tstruct,
+                                                   bool is_exception,
+                                                   bool is_exported) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  if (gen_node_) {
+    string prefix = has_js_namespace(tstruct->get_program()) ? js_namespace(tstruct->get_program()) : js_const_type_;
+    out << prefix << tstruct->get_name() <<
+      (is_exported ? " = module.exports." + tstruct->get_name() : "");
+    if (gen_ts_) {
+      f_types_ts_ << ts_print_doc(tstruct) << ts_indent() << ts_declare() << "class "
+                  << tstruct->get_name() << (is_exception ? " extends Thrift.TException" : "")
+                  << " {" << endl;
+    }
+  } else {
+    out << js_namespace(tstruct->get_program()) << tstruct->get_name();
+    if (gen_ts_) {
+      f_types_ts_ << ts_print_doc(tstruct) << ts_indent() << ts_declare() << "class "
+                  << tstruct->get_name() << (is_exception ? " extends Thrift.TException" : "")
+                  << " {" << endl;
+    }
+  }
+
+  if (gen_es6_) {
+    if (gen_node_ && is_exception) {
+      out << " = class extends Thrift.TException {" << endl;
+    } else {
+      out << " = class {" << endl;
+    }
+    indent_up();
+    indent(out) << "constructor(args) {" << endl;
+  } else {
+    out << " = function(args) {" << endl;
+  }
+
+  indent_up();
+
+  // Call super() method on inherited Error class
+  if (gen_node_ && is_exception) {
+    if (gen_es6_) {
+      indent(out) << "super(args);" << endl;
+    } else {
+      indent(out) << "Thrift.TException.call(this, \"" << js_namespace(tstruct->get_program())
+        << tstruct->get_name() << "\");" << endl;
+    }
+    out << indent() << "this.name = \"" << js_namespace(tstruct->get_program())
+        << tstruct->get_name() << "\";" << endl;
+  }
+
+  // members with arguments
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    string dval = declare_field(*m_iter, false, true);
+    t_type* t = get_true_type((*m_iter)->get_type());
+    if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) {
+      dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value());
+      out << indent() << "this." << (*m_iter)->get_name() << " = " << dval << ";" << endl;
+    } else {
+      out << indent() << dval << ";" << endl;
+    }
+    if (gen_ts_) {
+      if (gen_node_) {
+        f_types_ts_ << ts_indent() << "public " << (*m_iter)->get_name() << ": "
+                    << ts_get_type((*m_iter)->get_type()) << ";" << endl;
+      } else {
+        f_types_ts_ << ts_indent() << (*m_iter)->get_name() << ": "
+                    << ts_get_type((*m_iter)->get_type()) << ";" << endl;
+      }
+      
+    }
+  }
+
+  // Generate constructor from array
+  if (members.size() > 0) {
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+      if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) {
+        indent(out) << "this." << (*m_iter)->get_name() << " = "
+                    << render_const_value(t, (*m_iter)->get_value()) << ";" << endl;
+      }
+    }
+
+    // Early returns for exceptions
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+      if (t->is_xception()) {
+        out << indent() << "if (args instanceof " << js_type_namespace(t->get_program())
+            << t->get_name() << ") {" << endl << indent() << indent() << "this."
+            << (*m_iter)->get_name() << " = args;" << endl << indent() << indent() << "return;"
+            << endl << indent() << "}" << endl;
+      }
+    }
+
+    indent(out) << "if (args) {" << endl;
+    indent_up();
+    if (gen_ts_) {
+      f_types_ts_ << endl << ts_indent() << "constructor(args?: { ";
+    }
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+      indent(out) << "if (args." << (*m_iter)->get_name() << " !== undefined && args." << (*m_iter)->get_name() << " !== null) {" << endl;
+      indent_up();
+      indent(out) << "this." << (*m_iter)->get_name();
+
+      if (t->is_struct()) {
+        out << (" = new " + js_type_namespace(t->get_program()) + t->get_name() +
+                "(args."+(*m_iter)->get_name() +");");
+        out << endl;
+      } else if (t->is_container()) {
+        t_type* etype = get_contained_type(t);
+        string copyFunc = t->is_map() ? "Thrift.copyMap" : "Thrift.copyList";
+        string type_list = "";
+
+        while (etype->is_container()) {
+          if (type_list.length() > 0) {
+            type_list += ", ";
+          }
+          type_list += etype->is_map() ? "Thrift.copyMap" : "Thrift.copyList";
+          etype = get_contained_type(etype);
+        }
+
+        if (etype->is_struct()) {
+          if (type_list.length() > 0) {
+            type_list += ", ";
+          }
+          type_list += js_type_namespace(etype->get_program()) + etype->get_name();
+        }
+        else {
+          if (type_list.length() > 0) {
+            type_list += ", ";
+          }
+          type_list += "null";
+        }
+
+        out << (" = " + copyFunc + "(args." + (*m_iter)->get_name() +
+                ", [" + type_list + "]);");
+        out << endl;
+      } else {
+        out << " = args." << (*m_iter)->get_name() << ";" << endl;
+      }
+
+      indent_down();
+      if (!(*m_iter)->get_req()) {
+        indent(out) << "} else {" << endl;
+         indent(out)
+            << "  throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.UNKNOWN, "
+               "'Required field " << (*m_iter)->get_name() << " is unset!');" << endl;
+      }
+      indent(out) << "}" << endl;
+      if (gen_ts_) {
+        f_types_ts_ << (*m_iter)->get_name() << ts_get_req(*m_iter) << ": "
+                    << ts_get_type((*m_iter)->get_type()) << "; ";
+      }
+    }
+    indent_down();
+    out << indent() << "}" << endl;
+    if (gen_ts_) {
+      f_types_ts_ << "});" << endl;
+    }
+  }
+
+  // Done with constructor
+  indent_down();
+  if (gen_es6_) {
+    indent(out) << "}" << endl << endl;
+  } else {
+    indent(out) << "};" << endl;
+  }
+
+  if (gen_ts_) {
+    f_types_ts_ << ts_indent() << "}" << endl;
+  }
+
+  if (!gen_es6_) {
+    if (is_exception) {
+      out << "Thrift.inherits(" << js_namespace(tstruct->get_program()) << tstruct->get_name()
+          << ", Thrift.TException);" << endl;
+      out << js_namespace(tstruct->get_program()) << tstruct->get_name() << ".prototype.name = '"
+          << tstruct->get_name() << "';" << endl;
+    } else {
+      // init prototype manually if we aren't using es6
+      out << js_namespace(tstruct->get_program()) << tstruct->get_name() << ".prototype = {};"
+          << endl;
+    }
+
+  }
+
+  generate_js_struct_reader(out, tstruct);
+  generate_js_struct_writer(out, tstruct);
+
+  // Close out the class definition
+  if (gen_es6_) {
+    indent_down();
+    indent(out) << "};" << endl;
+  }
+}
+
+/**
+ * Generates the read() method for a struct
+ */
+void t_js_generator::generate_js_struct_reader(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  if (gen_es6_) {
+    indent(out) << "read (input) {" << endl;
+  } else {
+    indent(out) << js_namespace(tstruct->get_program()) << tstruct->get_name()
+        << ".prototype.read = function(input) {" << endl;
+  }
+
+  indent_up();
+
+  indent(out) << "input.readStructBegin();" << endl;
+
+  // Loop over reading in fields
+  indent(out) << "while (true) {" << endl;
+
+  indent_up();
+
+  indent(out) << js_const_type_ << "ret = input.readFieldBegin();" << endl;
+  indent(out) << js_const_type_ << "ftype = ret.ftype;" << endl;
+  if (!fields.empty()) {
+    indent(out) << js_const_type_ << "fid = ret.fid;" << endl;
+  }
+
+  // Check for field STOP marker and break
+  indent(out) << "if (ftype == Thrift.Type.STOP) {" << endl;
+  indent_up();
+  indent(out) << "break;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+  if (!fields.empty()) {
+    // Switch statement on the field we are reading
+    indent(out) << "switch (fid) {" << endl;
+
+    indent_up();
+
+    // Generate deserialization code for known cases
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+
+      indent(out) << "case " << (*f_iter)->get_key() << ":" << endl;
+      indent(out) << "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+
+      indent_up();
+      generate_deserialize_field(out, *f_iter, "this.");
+      indent_down();
+
+      indent(out) << "} else {" << endl;
+
+      indent(out) << "  input.skip(ftype);" << endl;
+
+      out << indent() << "}" << endl << indent() << "break;" << endl;
+    }
+    if (fields.size() == 1) {
+      // pseudo case to make jslint happy
+      indent(out) << "case 0:" << endl;
+      indent(out) << "  input.skip(ftype);" << endl;
+      indent(out) << "  break;" << endl;
+    }
+    // In the default case we skip the field
+    indent(out) << "default:" << endl;
+    indent(out) << "  input.skip(ftype);" << endl;
+
+    scope_down(out);
+  } else {
+    indent(out) << "input.skip(ftype);" << endl;
+  }
+
+  indent(out) << "input.readFieldEnd();" << endl;
+
+  scope_down(out);
+
+  indent(out) << "input.readStructEnd();" << endl;
+
+  indent(out) << "return;" << endl;
+
+  indent_down();
+
+  if (gen_es6_) {
+    indent(out) << "}" << endl << endl;
+  } else {
+    indent(out) << "};" << endl << endl;
+  }
+}
+
+/**
+ * Generates the write() method for a struct
+ */
+void t_js_generator::generate_js_struct_writer(ostream& out, t_struct* tstruct) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  if (gen_es6_) {
+    indent(out) << "write (output) {" << endl;
+  } else {
+    indent(out) << js_namespace(tstruct->get_program()) << tstruct->get_name()
+        << ".prototype.write = function(output) {" << endl;
+  }
+
+  indent_up();
+
+  indent(out) << "output.writeStructBegin('" << name << "');" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    out << indent() << "if (this." << (*f_iter)->get_name() << " !== null && this."
+        << (*f_iter)->get_name() << " !== undefined) {" << endl;
+    indent_up();
+
+    indent(out) << "output.writeFieldBegin("
+                << "'" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type())
+                << ", " << (*f_iter)->get_key() << ");" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "this.");
+
+    indent(out) << "output.writeFieldEnd();" << endl;
+
+    indent_down();
+    indent(out) << "}" << endl;
+  }
+
+  out << indent() << "output.writeFieldStop();" << endl << indent() << "output.writeStructEnd();"
+      << endl;
+
+  out << indent() << "return;" << endl;
+
+  indent_down();
+  if (gen_es6_) {
+    out << indent() << "}" << endl << endl;
+  } else {
+    out << indent() << "};" << endl << endl;
+  }
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_js_generator::generate_service(t_service* tservice) {
+  string f_service_name = get_out_dir() + service_name_ + ".js";
+  f_service_.open(f_service_name.c_str());
+
+  if (gen_ts_) {
+    string f_service_ts_name = get_out_dir() + service_name_ + ".d.ts";
+    f_service_ts_.open(f_service_ts_name.c_str());
+  }
+
+  f_service_ << autogen_comment();
+
+  if ((gen_node_ || gen_es6_) && no_ns_) {
+    f_service_ << "\"use strict\";" << endl << endl;
+  }
+
+  f_service_ << js_includes() << endl << render_includes() << endl;
+
+  if (gen_ts_) {
+    if (tservice->get_extends() != NULL) {
+      f_service_ts_ << "/// <reference path=\"" << tservice->get_extends()->get_name()
+                    << ".d.ts\" />" << endl;
+    }
+    f_service_ts_ << autogen_comment() << endl;
+    if (gen_node_) {
+      f_service_ts_ << ts_includes() << endl;
+      f_service_ts_ << "import ttypes = require('./" + program_->get_name() + "_types');" << endl;
+      // Generate type aliases
+      // enum
+      vector<t_enum*> const& enums = program_->get_enums();
+      vector<t_enum*>::const_iterator e_iter;
+      for (e_iter = enums.begin(); e_iter != enums.end(); ++e_iter) {
+        f_service_ts_ << "import " << (*e_iter)->get_name() << " = ttypes."
+                  << js_namespace(program_) << (*e_iter)->get_name() << endl;
+      }
+      // const
+      vector<t_const*> const& consts = program_->get_consts();
+      vector<t_const*>::const_iterator c_iter;
+      for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+        f_service_ts_ << "import " << (*c_iter)->get_name() << " = ttypes."
+                  << js_namespace(program_) << (*c_iter)->get_name() << endl;
+      }
+      // exception
+      vector<t_struct*> const& exceptions = program_->get_xceptions();
+      vector<t_struct*>::const_iterator x_iter;
+      for (x_iter = exceptions.begin(); x_iter != exceptions.end(); ++x_iter) {
+        f_service_ts_ << "import " << (*x_iter)->get_name() << " = ttypes."
+                  << js_namespace(program_) << (*x_iter)->get_name() << endl;
+      }
+      // structs
+      vector<t_struct*> const& structs = program_->get_structs();
+      vector<t_struct*>::const_iterator s_iter;
+      for (s_iter = structs.begin(); s_iter != structs.end(); ++s_iter) {
+        f_service_ts_ << "import " << (*s_iter)->get_name() << " = ttypes."
+                  << js_namespace(program_) << (*s_iter)->get_name() << endl;
+      }
+    }
+    if (!ts_module_.empty()) {
+      f_service_ts_ << "declare module " << ts_module_ << " {";
+    }
+  }
+
+  if (gen_node_) {
+    if (tservice->get_extends() != NULL) {
+      f_service_ << js_const_type_ <<  tservice->get_extends()->get_name() << " = require('./"
+                 << tservice->get_extends()->get_name() << "');" << endl << js_const_type_
+                 << tservice->get_extends()->get_name()
+                 << "Client = " << tservice->get_extends()->get_name() << ".Client;" << endl
+                 << js_const_type_ << tservice->get_extends()->get_name()
+                 << "Processor = " << tservice->get_extends()->get_name() << ".Processor;" << endl;
+    }
+
+    f_service_ << js_const_type_ << "ttypes = require('./" + program_->get_name() + "_types');" << endl;
+  }
+
+  generate_service_helpers(tservice);
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+
+  if (gen_node_) {
+    generate_service_processor(tservice);
+  }
+
+  f_service_.close();
+  if (gen_ts_) {
+    if (!ts_module_.empty()) {
+      f_service_ts_ << "}";
+    }
+    f_service_ts_.close();
+  }
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_js_generator::generate_service_processor(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  if (gen_node_) {
+    string prefix = has_js_namespace(tservice->get_program()) ? js_namespace(tservice->get_program()) : js_const_type_;
+    f_service_ << prefix << service_name_ << "Processor = " << "exports.Processor";
+    if (gen_ts_) {
+      f_service_ts_ << endl << "declare class Processor ";
+      if (tservice->get_extends() != NULL) {
+        f_service_ts_ << "extends " << tservice->get_extends()->get_name() << "Processor ";
+      }
+      f_service_ts_ << "{" << endl;
+      indent_up();
+      f_service_ts_ << ts_indent() << "private _handler: Object;" << endl << endl;
+      f_service_ts_ << ts_indent() << "constructor(handler: Object);" << endl;
+      f_service_ts_ << ts_indent() << "process(input: Thrift.TJSONProtocol, output: Thrift.TJSONProtocol): void;" << endl;
+      indent_down();
+    }
+  } else {
+    f_service_ << js_namespace(tservice->get_program()) << service_name_ << "Processor = "
+             << "exports.Processor";
+  }
+
+  bool is_subclass_service = tservice->get_extends() != NULL;
+
+  // ES6 Constructor
+  if (gen_es6_) {
+    if (is_subclass_service) {
+      f_service_ << " = class extends " << tservice->get_extends()->get_name() << "Processor {" << endl;
+    } else {
+      f_service_ << " = class {" << endl;
+    }
+    indent_up();
+    indent(f_service_) << "constructor(handler) {" << endl;
+  } else {
+    f_service_ << " = function(handler) {" << endl;
+  }
+
+  indent_up();
+  if (gen_es6_ && is_subclass_service) {
+    indent(f_service_) << "super(handler);" << endl;
+  }
+  indent(f_service_) << "this._handler = handler;" << endl;
+  indent_down();
+
+  // Done with constructor
+  if (gen_es6_) {
+    indent(f_service_) << "}" << endl;
+  } else {
+    indent(f_service_) << "};" << endl;
+  }
+
+  // ES5 service inheritance
+  if (!gen_es6_ && is_subclass_service) {
+    indent(f_service_) << "Thrift.inherits(" << js_namespace(tservice->get_program())
+                       << service_name_ << "Processor, " << tservice->get_extends()->get_name()
+                       << "Processor);" << endl;
+  }
+
+  // Generate the server implementation
+  if (gen_es6_) {
+    indent(f_service_) << "process (input, output) {" << endl;
+  } else {
+    indent(f_service_) << js_namespace(tservice->get_program()) << service_name_
+                      << "Processor.prototype.process = function(input, output) {" << endl;
+  }
+
+  indent_up();
+
+  indent(f_service_) << js_const_type_ << "r = input.readMessageBegin();" << endl << indent()
+             << "if (this['process_' + r.fname]) {" << endl << indent()
+             << "  return this['process_' + r.fname].call(this, r.rseqid, input, output);" << endl
+             << indent() << "} else {" << endl << indent() << "  input.skip(Thrift.Type.STRUCT);"
+             << endl << indent() << "  input.readMessageEnd();" << endl << indent()
+             << "  " << js_const_type_ << "x = new "
+                "Thrift.TApplicationException(Thrift.TApplicationExceptionType.UNKNOWN_METHOD, "
+                "'Unknown function ' + r.fname);" << endl << indent()
+             << "  output.writeMessageBegin(r.fname, Thrift.MessageType.EXCEPTION, r.rseqid);"
+             << endl << indent() << "  x.write(output);" << endl << indent()
+             << "  output.writeMessageEnd();" << endl << indent() << "  output.flush();" << endl
+             << indent() << "}" << endl;
+
+  indent_down();
+  if (gen_es6_) {
+    indent(f_service_) << "}" << endl;
+  } else {
+    indent(f_service_) << "};" << endl;
+  }
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  // Close off the processor class definition
+  if (gen_es6_) {
+    indent_down();
+    indent(f_service_) << "};" << endl;
+  }
+  if (gen_node_ && gen_ts_) {
+    f_service_ts_ << "}" << endl;
+  }
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_js_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  if (gen_es6_) {
+    indent(f_service_) << "process_" + tfunction->get_name() + " (seqid, input, output) {" << endl;
+  } else {
+    indent(f_service_) << js_namespace(tservice->get_program()) << service_name_
+                      << "Processor.prototype.process_" + tfunction->get_name()
+                          + " = function(seqid, input, output) {" << endl;
+  }
+  if (gen_ts_) {
+    indent_up();
+    f_service_ts_ << ts_indent() << "process_" << tfunction->get_name() << "(seqid: number, input: Thrift.TJSONProtocol, output: Thrift.TJSONProtocol): void;" << endl;
+    indent_down();
+  }
+
+  indent_up();
+
+  string argsname = js_namespace(program_) + service_name_ + "_" + tfunction->get_name() + "_args";
+  string resultname = js_namespace(program_) + service_name_ + "_" + tfunction->get_name()
+                      + "_result";
+
+  indent(f_service_) << js_const_type_ << "args = new " << argsname << "();" << endl << indent()
+             << "args.read(input);" << endl << indent() << "input.readMessageEnd();" << endl;
+
+  // 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;
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    indent(f_service_) << "this._handler." << 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." << (*f_iter)->get_name();
+    }
+
+    f_service_ << ");" << endl;
+    indent_down();
+
+    if (gen_es6_) {
+      indent(f_service_) << "}" << endl;
+    } else {
+      indent(f_service_) << "};" << endl;
+    }
+    return;
+  }
+
+  // Promise style invocation
+  indent(f_service_) << "if (this._handler." << tfunction->get_name()
+             << ".length === " << fields.size() << ") {" << endl;
+  indent_up();
+
+  if (gen_es6_) {
+    indent(f_service_) << "Promise.resolve(this._handler." << tfunction->get_name() << ".bind(this._handler)(" << endl;
+  } else {
+    string maybeComma = (fields.size() > 0 ? "," : "");
+    indent(f_service_) << "Q.fcall(this._handler." << tfunction->get_name() << ".bind(this._handler)"
+                       << maybeComma << endl;
+  }
+
+  indent_up();
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    string maybeComma = (f_iter != fields.end() - 1 ? "," : "");
+    indent(f_service_) << "args." << (*f_iter)->get_name() << maybeComma << endl;
+  }
+  indent_down();
+
+  if (gen_es6_) {
+    indent(f_service_) << ")).then(result => {" << endl;
+  } else {
+    indent(f_service_) << ").then(function(result) {" << endl;
+  }
+
+  indent_up();
+  f_service_ << indent() << js_const_type_ << "result_obj = new " << resultname << "({success: result});" << endl
+             << indent() << "output.writeMessageBegin(\"" << tfunction->get_name()
+             << "\", Thrift.MessageType.REPLY, seqid);" << endl << indent()
+             << "result_obj.write(output);" << endl << indent() << "output.writeMessageEnd();" << endl
+             << indent() << "output.flush();" << endl;
+  indent_down();
+
+  if (gen_es6_) {
+    indent(f_service_) << "}).catch(err => {" << endl;
+  } else {
+    indent(f_service_) << "}).catch(function (err) {" << endl;
+  }
+  indent_up();
+  indent(f_service_) << js_let_type_ << "result;" << endl;
+
+  bool has_exception = false;
+  t_struct* exceptions = tfunction->get_xceptions();
+  if (exceptions) {
+    const vector<t_field*>& members = exceptions->get_members();
+    for (vector<t_field*>::const_iterator it = members.begin(); it != members.end(); ++it) {
+      t_type* t = get_true_type((*it)->get_type());
+      if (t->is_xception()) {
+        if (!has_exception) {
+          has_exception = true;
+          indent(f_service_) << "if (err instanceof " << js_type_namespace(t->get_program())
+                             << t->get_name();
+        } else {
+          f_service_ << " || err instanceof " << js_type_namespace(t->get_program())
+                     << t->get_name();
+        }
+      }
+    }
+  }
+
+  if (has_exception) {
+    f_service_ << ") {" << endl;
+    indent_up();
+    f_service_ << indent() << "result = new " << resultname << "(err);" << endl << indent()
+               << "output.writeMessageBegin(\"" << tfunction->get_name()
+               << "\", Thrift.MessageType.REPLY, seqid);" << endl;
+
+    indent_down();
+    indent(f_service_) << "} else {" << endl;
+    indent_up();
+  }
+
+  f_service_ << indent() << "result = new "
+                            "Thrift.TApplicationException(Thrift.TApplicationExceptionType.UNKNOWN,"
+                            " err.message);" << endl << indent() << "output.writeMessageBegin(\""
+             << tfunction->get_name() << "\", Thrift.MessageType.EXCEPTION, seqid);" << endl;
+
+  if (has_exception) {
+    indent_down();
+    indent(f_service_) << "}" << endl;
+  }
+
+  f_service_ << indent() << "result.write(output);" << endl << indent()
+             << "output.writeMessageEnd();" << endl << indent() << "output.flush();" << endl;
+  indent_down();
+  indent(f_service_) << "});" << endl;
+  indent_down();
+  // End promise style invocation
+
+  // Callback style invocation
+  indent(f_service_) << "} else {" << endl;
+  indent_up();
+  indent(f_service_) << "this._handler." << tfunction->get_name() << "(";
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    f_service_ << "args." << (*f_iter)->get_name() << ", ";
+  }
+
+  if (gen_es6_) {
+    f_service_ << "(err, result) => {" << endl;
+  } else {
+    f_service_ << "function (err, result) {" << endl;
+  }
+  indent_up();
+  indent(f_service_) << js_let_type_ << "result_obj;" << endl;
+
+  indent(f_service_) << "if ((err === null || typeof err === 'undefined')";
+  if (has_exception) {
+    const vector<t_field*>& members = exceptions->get_members();
+    for (vector<t_field*>::const_iterator it = members.begin(); it != members.end(); ++it) {
+      t_type* t = get_true_type((*it)->get_type());
+      if (t->is_xception()) {
+        f_service_ << " || err instanceof " << js_type_namespace(t->get_program()) << t->get_name();
+      }
+    }
+  }
+  f_service_ << ") {" << endl;
+  indent_up();
+  f_service_ << indent() << "result_obj = new " << resultname
+             << "((err !== null || typeof err === 'undefined') ? err : {success: result});" << endl << indent()
+             << "output.writeMessageBegin(\"" << tfunction->get_name()
+             << "\", Thrift.MessageType.REPLY, seqid);" << endl;
+  indent_down();
+  indent(f_service_) << "} else {" << endl;
+  indent_up();
+  f_service_ << indent() << "result_obj = new "
+                            "Thrift.TApplicationException(Thrift.TApplicationExceptionType.UNKNOWN,"
+                            " err.message);" << endl << indent() << "output.writeMessageBegin(\""
+             << tfunction->get_name() << "\", Thrift.MessageType.EXCEPTION, seqid);" << endl;
+  indent_down();
+  f_service_ << indent() << "}" << endl << indent() << "result_obj.write(output);" << endl << indent()
+             << "output.writeMessageEnd();" << endl << indent() << "output.flush();" << endl;
+
+  indent_down();
+  indent(f_service_) << "});" << endl;
+  indent_down();
+  indent(f_service_) << "}" << endl;
+  // End callback style invocation
+
+  indent_down();
+
+  if (gen_es6_) {
+    indent(f_service_) << "}" << endl;
+  } else {
+    indent(f_service_) << "};" << endl;
+  }
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_js_generator::generate_service_helpers(t_service* tservice) {
+  // Do not generate TS definitions for helper functions
+  bool gen_ts_tmp = gen_ts_;
+  gen_ts_ = false;
+
+  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();
+    string name = ts->get_name();
+    ts->set_name(service_name_ + "_" + name);
+    generate_js_struct_definition(f_service_, ts, false, false);
+    generate_js_function_helpers(*f_iter);
+    ts->set_name(name);
+  }
+
+  gen_ts_ = gen_ts_tmp;
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_js_generator::generate_js_function_helpers(t_function* tfunction) {
+  t_struct result(program_, service_name_ + "_" + 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_js_struct_definition(f_service_, &result, false, false);
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_js_generator::generate_service_interface(t_service* tservice) {
+  (void)tservice;
+}
+
+/**
+ * Generates a REST interface
+ */
+void t_js_generator::generate_service_rest(t_service* tservice) {
+  (void)tservice;
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_js_generator::generate_service_client(t_service* tservice) {
+
+  bool is_subclass_service = tservice->get_extends() != NULL;
+
+  if (gen_node_) {
+    string prefix = has_js_namespace(tservice->get_program()) ? js_namespace(tservice->get_program()) : js_const_type_;
+    f_service_ << prefix << service_name_ << "Client = " << "exports.Client";
+    if (gen_ts_) {
+      f_service_ts_ << ts_print_doc(tservice) << ts_indent() << ts_declare() << "class "
+                    << "Client ";
+      if (tservice->get_extends() != NULL) {
+        f_service_ts_ << "extends " << tservice->get_extends()->get_name() << "Client ";
+      }
+      f_service_ts_ << "{" << endl;
+    }
+  } else {
+    f_service_ << js_namespace(tservice->get_program()) << service_name_
+               << "Client";
+    if (gen_ts_) {
+      f_service_ts_ << ts_print_doc(tservice) << ts_indent() << ts_declare() << "class "
+                    << service_name_ << "Client ";
+      if (is_subclass_service) {
+        f_service_ts_ << "extends " << tservice->get_extends()->get_name() << "Client ";
+      }
+      f_service_ts_ << "{" << endl;
+    }
+  }
+
+  // ES6 Constructor
+  if (gen_es6_) {
+    if (is_subclass_service) {
+      f_service_ << " = class extends " << js_namespace(tservice->get_extends()->get_program())
+                       << tservice->get_extends()->get_name() << "Client {" << endl;
+    } else {
+      f_service_ << " = class {" << endl;
+    }
+    indent_up();
+    if (gen_node_) {
+      indent(f_service_) << "constructor(output, pClass) {" << endl;
+    } else {
+      indent(f_service_) << "constructor(input, output) {" << endl;
+    }
+  } else {
+    if (gen_node_) {
+      f_service_ << " = function(output, pClass) {" << endl;
+    } else {
+      f_service_ << " = function(input, output) {" << endl;
+    }
+  }
+
+  indent_up();
+
+  if (gen_node_) {
+    indent(f_service_) << "this.output = output;" << endl;
+    indent(f_service_) << "this.pClass = pClass;" << endl;
+    indent(f_service_) << "this._seqid = 0;" << endl;
+    indent(f_service_) << "this._reqs = {};" << endl;
+    if (gen_ts_) {
+      f_service_ts_ << ts_indent() << "private input: Thrift.TJSONProtocol;" << endl << ts_indent()
+                    << "private output: Thrift.TJSONProtocol;" << endl << ts_indent() << "private seqid: number;"
+                    << endl << endl << ts_indent()
+                    << "constructor(input: Thrift.TJSONProtocol, output?: Thrift.TJSONProtocol);"
+                    << endl;
+    }
+  } else {
+    indent(f_service_) << "this.input = input;" << endl;
+    indent(f_service_) << "this.output = (!output) ? input : output;" << endl;
+    indent(f_service_) << "this.seqid = 0;" << endl;
+    if (gen_ts_) {
+      f_service_ts_ << ts_indent() << "input: Thrift.TJSONProtocol;" << endl << ts_indent()
+                    << "output: Thrift.TJSONProtocol;" << endl << ts_indent() << "seqid: number;"
+                    << endl << endl << ts_indent()
+                    << "constructor(input: Thrift.TJSONProtocol, output?: Thrift.TJSONProtocol);"
+                    << endl;
+    }
+  }
+
+  indent_down();
+
+  if (gen_es6_) {
+    indent(f_service_) << "}" << endl;
+  } else {
+    indent(f_service_) << "};" << endl;
+    if (is_subclass_service) {
+      indent(f_service_) << "Thrift.inherits(" << js_namespace(tservice->get_program())
+                        << service_name_ << "Client, "
+                        << js_namespace(tservice->get_extends()->get_program())
+                        << tservice->get_extends()->get_name() << "Client);" << endl;
+    } else {
+      // init prototype
+      indent(f_service_) << js_namespace(tservice->get_program()) << service_name_
+                        << "Client.prototype = {};" << endl;
+    }
+  }
+
+  // utils for multiplexed services
+  if (gen_node_) {
+    if (gen_es6_) {
+      indent(f_service_) << "seqid () { return this._seqid; }" << endl;
+      indent(f_service_) << "new_seqid () { return this._seqid += 1; }" << endl;
+    } else {
+      indent(f_service_) << js_namespace(tservice->get_program()) << service_name_
+                        << "Client.prototype.seqid = function() { return this._seqid; };" << endl
+                        << js_namespace(tservice->get_program()) << service_name_
+                        << "Client.prototype.new_seqid = function() { return this._seqid += 1; };"
+                        << 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 = (*f_iter)->get_name();
+    string arglist = argument_list(arg_struct);
+
+    // Open function
+    f_service_ << endl;
+    if (gen_es6_) {
+      indent(f_service_) << funname << " (" << arglist << ") {" << endl;
+    } else {
+      indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ << "Client.prototype."
+                << function_signature(*f_iter, "", !gen_es6_) << " {" << endl;
+    }
+
+    indent_up();
+
+    if (gen_ts_) {
+      // function definition without callback
+      f_service_ts_ << ts_print_doc(*f_iter) << ts_indent() << ts_function_signature(*f_iter, false, false) << endl;
+      if (!gen_es6_) {
+        // overload with callback
+        f_service_ts_ << ts_print_doc(*f_iter) << ts_indent() << ts_function_signature(*f_iter, true, false) << endl;
+      } else {
+        // overload with callback
+        f_service_ts_ << ts_print_doc(*f_iter) << ts_indent() << ts_function_signature(*f_iter, true, true) << endl;
+      }
+    }
+
+    if (gen_es6_ && gen_node_) {
+      indent(f_service_) << "this._seqid = this.new_seqid();" << endl;
+      indent(f_service_) << js_const_type_ << "self = this;" << endl << indent()
+                 << "return new Promise((resolve, reject) => {" << endl;
+      indent_up();
+      indent(f_service_) << "self._reqs[self.seqid()] = (error, result) => {" << endl;
+      indent_up();
+      indent(f_service_) << "return error ? reject(error) : resolve(result);" << endl;
+      indent_down();
+      indent(f_service_) << "};" << endl;
+      indent(f_service_) << "self.send_" << funname << "(" << arglist << ");" << endl;
+      indent_down();
+      indent(f_service_) << "});" << endl;
+    } else if (gen_node_) { // Node.js output      ./gen-nodejs
+      f_service_ << indent() << "this._seqid = this.new_seqid();" << endl << indent()
+                 << "if (callback === undefined) {" << endl;
+      indent_up();
+      f_service_ << indent() << js_const_type_ << "_defer = Q.defer();" << endl << indent()
+                 << "this._reqs[this.seqid()] = function(error, result) {" << endl;
+      indent_up();
+      indent(f_service_) << "if (error) {" << endl;
+      indent_up();
+      indent(f_service_) << "_defer.reject(error);" << endl;
+      indent_down();
+      indent(f_service_) << "} else {" << endl;
+      indent_up();
+      indent(f_service_) << "_defer.resolve(result);" << endl;
+      indent_down();
+      indent(f_service_) << "}" << endl;
+      indent_down();
+      indent(f_service_) << "};" << endl;
+      f_service_ << indent() << "this.send_" << funname << "(" << arglist << ");" << endl
+                 << indent() << "return _defer.promise;" << endl;
+      indent_down();
+      indent(f_service_) << "} else {" << endl;
+      indent_up();
+      f_service_ << indent() << "this._reqs[this.seqid()] = callback;" << endl << indent()
+                 << "this.send_" << funname << "(" << arglist << ");" << endl;
+      indent_down();
+      indent(f_service_) << "}" << endl;
+    } else if (gen_es6_) {
+      f_service_ << indent() << js_const_type_ << "self = this;" << endl << indent()
+                 << "return new Promise((resolve, reject) => {" << endl;
+      indent_up();
+      f_service_ << indent() << "self.send_" << funname << "(" << arglist
+                 << (arglist.empty() ? "" : ", ") << "(error, result) => {" << endl;
+      indent_up();
+      indent(f_service_) << "return error ? reject(error) : resolve(result);" << endl;
+      indent_down();
+      f_service_ << indent() << "});" << endl;
+      indent_down();
+      f_service_ << indent() << "});" << endl;
+
+    } else if (gen_jquery_) { // jQuery output       ./gen-js
+      f_service_ << indent() << "if (callback === undefined) {" << endl;
+      indent_up();
+      f_service_ << indent() << "this.send_" << funname << "(" << arglist << ");" << endl;
+      if (!(*f_iter)->is_oneway()) {
+        f_service_ << indent();
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          f_service_ << "return ";
+        }
+        f_service_ << "this.recv_" << funname << "();" << endl;
+      }
+      indent_down();
+      f_service_ << indent() << "} else {" << endl;
+      indent_up();
+      f_service_ << indent() << js_const_type_ << "postData = this.send_" << funname << "(" << arglist
+                 << (arglist.empty() ? "" : ", ") << "true);" << endl;
+      f_service_ << indent() << "return this.output.getTransport()" << endl;
+      indent_up();
+      f_service_ << indent() << ".jqRequest(this, postData, arguments, this.recv_" << funname
+                 << ");" << endl;
+      indent_down();
+      indent_down();
+      f_service_ << indent() << "}" << endl;
+    } else { // Standard JavaScript ./gen-js
+      f_service_ << indent() << "this.send_" << funname << "(" << arglist
+                 << (arglist.empty() ? "" : ", ") << "callback); " << endl;
+      if (!(*f_iter)->is_oneway()) {
+        f_service_ << indent() << "if (!callback) {" << endl;
+        f_service_ << indent();
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          f_service_ << "  return ";
+        }
+        f_service_ << "this.recv_" << funname << "();" << endl;
+        f_service_ << indent() << "}" << endl;
+      }
+    }
+
+    indent_down();
+
+    if (gen_es6_) {
+      indent(f_service_) << "}" << endl << endl;
+    } else {
+      indent(f_service_) << "};" << endl << endl;
+    }
+
+    // Send function
+    if (gen_es6_) {
+      if (gen_node_) {
+        indent(f_service_) << "send_" << funname << " (" << arglist << ") {" << endl;
+      } else {
+        // ES6 js still uses callbacks here. Should refactor this to promise style later..
+        indent(f_service_) << "send_" << funname << " (" << argument_list(arg_struct, true) << ") {" << endl;
+      }
+    } else {
+      indent(f_service_) << js_namespace(tservice->get_program()) << service_name_ << "Client.prototype.send_"
+                << function_signature(*f_iter, "", !gen_node_) << " {" << endl;
+    }
+
+    indent_up();
+
+    std::string outputVar;
+    if (gen_node_) {
+      f_service_ << indent() << js_const_type_ << "output = new this.pClass(this.output);" << endl;
+      outputVar = "output";
+    } else {
+      outputVar = "this.output";
+    }
+
+    std::string argsname = js_namespace(program_) + service_name_ + "_" + (*f_iter)->get_name()
+                           + "_args";
+
+    std::string messageType = (*f_iter)->is_oneway() ? "Thrift.MessageType.ONEWAY"
+                                                     : "Thrift.MessageType.CALL";
+    // Build args
+    if (fields.size() > 0){
+      f_service_ << indent() << js_const_type_ << "params = {" << endl;
+      indent_up();
+      for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+        indent(f_service_) << (*fld_iter)->get_name() << ": " << (*fld_iter)->get_name();
+        if (fld_iter != fields.end()-1) {
+          f_service_ << "," << endl;
+        } else {
+          f_service_ << endl;
+        }
+      }
+      indent_down();
+      indent(f_service_) << "};" << endl;
+      indent(f_service_) << js_const_type_ << "args = new " << argsname << "(params);" << endl;
+    } else {
+      indent(f_service_) << js_const_type_ << "args = new " << argsname << "();" << endl;
+    }
+
+
+    // Serialize the request header within try/catch
+    indent(f_service_) << "try {" << endl;
+    indent_up();
+
+    if (gen_node_) {
+      f_service_ << indent() << outputVar << ".writeMessageBegin('" << (*f_iter)->get_name()
+                 << "', " << messageType << ", this.seqid());" << endl;
+    } else {
+      f_service_ << indent() << outputVar << ".writeMessageBegin('" << (*f_iter)->get_name()
+                 << "', " << messageType << ", this.seqid);" << endl;
+    }
+
+
+    // Write to the stream
+    f_service_ << indent() << "args.write(" << outputVar << ");" << endl << indent() << outputVar
+               << ".writeMessageEnd();" << endl;
+
+    if (gen_node_) {
+      if((*f_iter)->is_oneway()) {
+        f_service_ << indent() << "this.output.flush();" << endl;
+        f_service_ << indent() << js_const_type_ << "callback = this._reqs[this.seqid()] || function() {};" << endl;
+        f_service_ << indent() << "delete this._reqs[this.seqid()];" << endl;
+        f_service_ << indent() << "callback(null);" << endl;
+      } else {
+        f_service_ << indent() << "return this.output.flush();" << endl;
+      }
+    } else {
+      if (gen_jquery_) {
+        f_service_ << indent() << "return this.output.getTransport().flush(callback);" << endl;
+      } else if (gen_es6_) {
+        f_service_ << indent() << js_const_type_ << "self = this;" << endl;
+        if((*f_iter)->is_oneway()) {
+          f_service_ << indent() << "this.output.getTransport().flush(true, null);" << endl;
+          f_service_ << indent() << "callback();" << endl;
+        } else {
+          f_service_ << indent() << "this.output.getTransport().flush(true, () => {" << endl;
+          indent_up();
+          f_service_ << indent() << js_let_type_ << "error = null, result = null;" << endl;
+          f_service_ << indent() << "try {" << endl;
+          f_service_ << indent() << "  result = self.recv_" << funname << "();" << endl;
+          f_service_ << indent() << "} catch (e) {" << endl;
+          f_service_ << indent() << "  error = e;" << endl;
+          f_service_ << indent() << "}" << endl;
+          f_service_ << indent() << "callback(error, result);" << endl;
+          indent_down();
+          f_service_ << indent() << "});" << endl;
+        }
+      } else {
+        f_service_ << indent() << "if (callback) {" << endl;
+        indent_up();
+        if((*f_iter)->is_oneway()) {
+          f_service_ << indent() << "this.output.getTransport().flush(true, null);" << endl;
+          f_service_ << indent() << "callback();" << endl;
+        } else {
+          f_service_ << indent() << js_const_type_ << "self = this;" << endl;
+          f_service_ << indent() << "this.output.getTransport().flush(true, function() {" << endl;
+          indent_up();
+          f_service_ << indent() << js_let_type_ << "result = null;" << endl;
+          f_service_ << indent() << "try {" << endl;
+          f_service_ << indent() << "  result = self.recv_" << funname << "();" << endl;
+          f_service_ << indent() << "} catch (e) {" << endl;
+          f_service_ << indent() << "  result = e;" << endl;
+          f_service_ << indent() << "}" << endl;
+          f_service_ << indent() << "callback(result);" << endl;
+          indent_down();
+          f_service_ << indent() << "});" << endl;
+        }
+        indent_down();
+        f_service_ << indent() << "} else {" << endl;
+        f_service_ << indent() << "  return this.output.getTransport().flush();" << endl;
+        f_service_ << indent() << "}" << endl;
+      }
+    }
+
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+
+    // Reset the transport and delete registered callback if there was a serialization error
+    f_service_ << indent() << "catch (e) {" << endl;
+    indent_up();
+    if (gen_node_) {
+      f_service_ << indent() << "delete this._reqs[this.seqid()];" << endl;
+      f_service_ << indent() << "if (typeof " << outputVar << ".reset === 'function') {" << endl;
+      f_service_ << indent() << "  " << outputVar << ".reset();" << endl;
+      f_service_ << indent() << "}" << endl;
+    } else {
+      f_service_ << indent() << "if (typeof " << outputVar << ".getTransport().reset === 'function') {" << endl;
+      f_service_ << indent() << "  " << outputVar << ".getTransport().reset();" << endl;
+      f_service_ << indent() << "}" << endl;
+    }
+    f_service_ << indent() << "throw e;" << endl;
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+
+    indent_down();
+
+    // Close send function
+    if (gen_es6_) {
+      indent(f_service_) << "}" << endl;
+    } else {
+      indent(f_service_) << "};" << endl;
+    }
+
+    // Receive function
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultname = js_namespace(tservice->get_program()) + service_name_ + "_"
+                               + (*f_iter)->get_name() + "_result";
+
+      f_service_ << endl;
+      // Open receive function
+      if (gen_node_) {
+        if (gen_es6_) {
+          indent(f_service_) << "recv_" << (*f_iter)->get_name() << " (input, mtype, rseqid) {" << endl;
+        } else {
+          indent(f_service_) << js_namespace(tservice->get_program()) << service_name_
+                      << "Client.prototype.recv_" << (*f_iter)->get_name()
+                      << " = function(input,mtype,rseqid) {" << endl;
+        }
+      } else {
+        if (gen_es6_) {
+          indent(f_service_) << "recv_" << (*f_iter)->get_name() << " () {" << endl;
+        } else {
+          t_struct noargs(program_);
+
+          t_function recv_function((*f_iter)->get_returntype(),
+                                  string("recv_") + (*f_iter)->get_name(),
+                                  &noargs);
+          indent(f_service_) << js_namespace(tservice->get_program()) << service_name_
+                    << "Client.prototype." << function_signature(&recv_function) << " {" << endl;
+        }
+      }
+
+      indent_up();
+
+      std::string inputVar;
+      if (gen_node_) {
+        inputVar = "input";
+      } else {
+        inputVar = "this.input";
+      }
+
+      if (gen_node_) {
+        f_service_ << indent() << js_const_type_ << "callback = this._reqs[rseqid] || function() {};" << endl
+                   << indent() << "delete this._reqs[rseqid];" << endl;
+      } else {
+        f_service_ << indent() << js_const_type_ << "ret = this.input.readMessageBegin();" << endl
+                   << indent() << js_const_type_ << "mtype = ret.mtype;" << endl;
+      }
+
+      f_service_ << indent() << "if (mtype == Thrift.MessageType.EXCEPTION) {" << endl;
+
+      indent_up();
+      f_service_ << indent() << js_const_type_ << "x = new Thrift.TApplicationException();" << endl
+                 << indent() << "x.read(" << inputVar << ");" << endl
+                 << indent() << inputVar << ".readMessageEnd();" << endl
+                 << indent() << render_recv_throw("x") << endl;
+      scope_down(f_service_);
+
+      f_service_ << indent() << js_const_type_ << "result = new " << resultname << "();" << endl << indent()
+                 << "result.read(" << inputVar << ");" << endl;
+
+      f_service_ << indent() << inputVar << ".readMessageEnd();" << endl << 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 (null !== result." << (*x_iter)->get_name() << ") {" << endl
+                   << indent() << "  " << render_recv_throw("result." + (*x_iter)->get_name())
+                   << endl << indent() << "}" << endl;
+      }
+
+      // Careful, only return result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << indent() << "if (null !== result.success) {" << endl << indent() << "  "
+                   << render_recv_return("result.success") << endl << indent() << "}" << endl;
+        f_service_ << indent()
+                   << render_recv_throw("'" + (*f_iter)->get_name() + " failed: unknown result'")
+                   << endl;
+      } else {
+        if (gen_node_) {
+          indent(f_service_) << "callback(null);" << endl;
+        } else {
+          indent(f_service_) << "return;" << endl;
+        }
+      }
+
+      // Close receive function
+      indent_down();
+      if (gen_es6_) {
+        indent(f_service_) << "}" << endl;
+      } else {
+        indent(f_service_) << "};" << endl;
+      }
+    }
+  }
+
+  // Finish class definitions
+  if (gen_ts_) {
+    f_service_ts_ << ts_indent() << "}" << endl;
+  }
+  if (gen_es6_) {
+    indent_down();
+    f_service_ << "};" << endl;
+  }
+}
+
+std::string t_js_generator::render_recv_throw(std::string var) {
+  if (gen_node_) {
+    return "return callback(" + var + ");";
+  } else {
+    return "throw " + var + ";";
+  }
+}
+
+std::string t_js_generator::render_recv_return(std::string var) {
+  if (gen_node_) {
+    return "return callback(null, " + var + ");";
+  } else {
+    return "return " + var + ";";
+  }
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_js_generator::generate_deserialize_field(ostream& out,
+                                                t_field* tfield,
+                                                string prefix,
+                                                bool inclass) {
+  (void)inclass;
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name();
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) << name << " = input.";
+
+    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 << (type->is_binary() ? "readBinary()" : "readString()");
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "readBool()";
+        break;
+      case t_base_type::TYPE_I8:
+        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 JS name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "readI32()";
+    }
+
+    if (!gen_node_) {
+      out << ".value";
+    }
+
+    out << ";" << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a variable. This makes two key assumptions,
+ * first that there is a const char* variable named data that points to the
+ * buffer for deserialization, and that there is a variable protocol which
+ * is a reference to a TProtocol serialization object.
+ */
+void t_js_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  out << indent() << prefix << " = new " << js_type_namespace(tstruct->get_program())
+      << tstruct->get_name() << "();" << endl << indent() << prefix << ".read(input);" << endl;
+}
+
+void t_js_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) {
+  string size = tmp("_size");
+  string rtmp3 = tmp("_rtmp3");
+
+  t_field fsize(g_type_i32, size);
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    out << indent() << prefix << " = {};" << endl;
+
+    out << indent() << js_const_type_ << rtmp3 << " = input.readMapBegin();" << endl;
+    out << indent() << js_const_type_ << size << " = " << rtmp3 << ".size || 0;" << endl;
+
+  } else if (ttype->is_set()) {
+
+    out << indent() << prefix << " = [];" << endl
+        << indent() << js_const_type_ << rtmp3 << " = input.readSetBegin();" << endl
+        << indent() << js_const_type_ << size << " = " << rtmp3 << ".size || 0;" << endl;
+
+  } else if (ttype->is_list()) {
+
+    out << indent() << prefix << " = [];" << endl
+        << indent() << js_const_type_ << rtmp3 << " = input.readListBegin();" << endl
+        << indent() << js_const_type_ << size << " = " << rtmp3 << ".size || 0;" << endl;
+  }
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) << "for (" << js_let_type_ << i << " = 0; " << i << " < " << size << "; ++" << i << ") {" << endl;
+
+  indent_up();
+
+  if (ttype->is_map()) {
+    if (!gen_node_) {
+      out << indent() << "if (" << i << " > 0 ) {" << endl << indent()
+          << "  if (input.rstack.length > input.rpos[input.rpos.length -1] + 1) {" << endl
+          << indent() << "    input.rstack.pop();" << endl << indent() << "  }" << endl << indent()
+          << "}" << endl;
+    }
+
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  scope_down(out);
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "input.readMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "input.readSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "input.readListEnd();" << endl;
+  }
+}
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_js_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) {
+  string key = tmp("key");
+  string val = tmp("val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) << declare_field(&fkey, false, false) << ";" << endl;
+  indent(out) << declare_field(&fval, false, false) << ";" << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) << prefix << "[" << key << "] = " << val << ";" << endl;
+}
+
+void t_js_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) {
+  string elem = tmp("elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) << js_let_type_ << elem << " = null;" << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".push(" << elem << ");" << endl;
+}
+
+void t_js_generator::generate_deserialize_list_element(ostream& out,
+                                                       t_list* tlist,
+                                                       string prefix) {
+  string elem = tmp("elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) << js_let_type_ << elem << " = null;" << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  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_js_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name());
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, prefix + tfield->get_name());
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    string name = tfield->get_name();
+
+    // Hack for when prefix is defined (always a hash ref)
+    if (!prefix.empty())
+      name = prefix + tfield->get_name();
+
+    indent(out) << "output.";
+
+    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 << (type->is_binary() ? "writeBinary(" : "writeString(") << name << ")";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ")";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "writeByte(" << name << ")";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16(" << name << ")";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32(" << name << ")";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64(" << name << ")";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble(" << name << ")";
+        break;
+      default:
+        throw "compiler error: no JS name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32(" << name << ")";
+    }
+    out << ";" << endl;
+
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_js_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  (void)tstruct;
+  indent(out) << prefix << ".write(output);" << endl;
+}
+
+/**
+ * Writes out a container
+ */
+void t_js_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  if (ttype->is_map()) {
+    indent(out) << "output.writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", "
+                << type_to_enum(((t_map*)ttype)->get_val_type()) << ", "
+                << "Thrift.objectLength(" << prefix << "));" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "output.writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", "
+                << prefix << ".length);" << endl;
+
+  } else if (ttype->is_list()) {
+
+    indent(out) << "output.writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type())
+                << ", " << prefix << ".length);" << endl;
+  }
+
+  if (ttype->is_map()) {
+    string kiter = tmp("kiter");
+    string viter = tmp("viter");
+    indent(out) << "for (" << js_let_type_ << kiter << " in " << prefix << ") {" << endl;
+    indent_up();
+    indent(out) << "if (" << prefix << ".hasOwnProperty(" << kiter << ")) {" << endl;
+    indent_up();
+    indent(out) << js_let_type_ << viter << " = " << prefix << "[" << kiter << "];" << endl;
+    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
+    scope_down(out);
+    scope_down(out);
+
+  } else if (ttype->is_set()) {
+    string iter = tmp("iter");
+    indent(out) << "for (" << js_let_type_ << iter << " in " << prefix << ") {" << endl;
+    indent_up();
+    indent(out) << "if (" << prefix << ".hasOwnProperty(" << iter << ")) {" << endl;
+    indent_up();
+    indent(out) << iter << " = " << prefix << "[" << iter << "];" << endl;
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+    scope_down(out);
+    scope_down(out);
+
+  } else if (ttype->is_list()) {
+    string iter = tmp("iter");
+    indent(out) << "for (" << js_let_type_ << iter << " in " << prefix << ") {" << endl;
+    indent_up();
+    indent(out) << "if (" << prefix << ".hasOwnProperty(" << iter << ")) {" << endl;
+    indent_up();
+    indent(out) << iter << " = " << prefix << "[" << iter << "];" << endl;
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+    scope_down(out);
+    scope_down(out);
+  }
+
+  if (ttype->is_map()) {
+    indent(out) << "output.writeMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "output.writeSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "output.writeListEnd();" << endl;
+  }
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_js_generator::generate_serialize_map_element(ostream& out,
+                                                    t_map* tmap,
+                                                    string kiter,
+                                                    string viter) {
+  t_field kfield(tmap->get_key_type(), kiter);
+  generate_serialize_field(out, &kfield);
+
+  t_field vfield(tmap->get_val_type(), viter);
+  generate_serialize_field(out, &vfield);
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_js_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield);
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_js_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield);
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_js_generator::declare_field(t_field* tfield, bool init, bool obj) {
+  string result = "this." + tfield->get_name();
+
+  if (!obj) {
+    result = js_let_type_ + tfield->get_name();
+  }
+
+  if (init) {
+    t_type* type = get_true_type(tfield->get_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:
+        break;
+      case t_base_type::TYPE_STRING:
+      case t_base_type::TYPE_BOOL:
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+      case t_base_type::TYPE_DOUBLE:
+        result += " = null";
+        break;
+      default:
+        throw "compiler error: no JS initializer for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      result += " = null";
+    } else if (type->is_map()) {
+      result += " = null";
+    } else if (type->is_container()) {
+      result += " = null";
+    } else if (type->is_struct() || type->is_xception()) {
+      if (obj) {
+        result += " = new " + js_type_namespace(type->get_program()) + type->get_name() + "()";
+      } else {
+        result += " = null";
+      }
+    }
+  } else {
+    result += " = null";
+  }
+  return result;
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_js_generator::function_signature(t_function* tfunction,
+                                          string prefix,
+                                          bool include_callback) {
+
+  string str;
+
+  str = prefix + tfunction->get_name() + " = function(";
+
+  str += argument_list(tfunction->get_arglist(), include_callback);
+
+  str += ")";
+  return str;
+}
+
+/**
+ * Renders a field list
+ */
+string t_js_generator::argument_list(t_struct* tstruct, bool include_callback) {
+  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();
+  }
+
+  if (include_callback) {
+    if (!fields.empty()) {
+      result += ", ";
+    }
+    result += "callback";
+  }
+
+  return result;
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ */
+string t_js_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.Type.STRING";
+    case t_base_type::TYPE_BOOL:
+      return "Thrift.Type.BOOL";
+    case t_base_type::TYPE_I8:
+      return "Thrift.Type.BYTE";
+    case t_base_type::TYPE_I16:
+      return "Thrift.Type.I16";
+    case t_base_type::TYPE_I32:
+      return "Thrift.Type.I32";
+    case t_base_type::TYPE_I64:
+      return "Thrift.Type.I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "Thrift.Type.DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "Thrift.Type.I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "Thrift.Type.STRUCT";
+  } else if (type->is_map()) {
+    return "Thrift.Type.MAP";
+  } else if (type->is_set()) {
+    return "Thrift.Type.SET";
+  } else if (type->is_list()) {
+    return "Thrift.Type.LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Converts a t_type to a TypeScript type (string).
+ * @param t_type Type to convert to TypeScript
+ * @return String TypeScript type
+ */
+string t_js_generator::ts_get_type(t_type* type) {
+  std::string ts_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_STRING:
+      ts_type = "string";
+      break;
+    case t_base_type::TYPE_BOOL:
+      ts_type = "boolean";
+      break;
+    case t_base_type::TYPE_I8:
+      ts_type = "any";
+      break;
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+    case t_base_type::TYPE_DOUBLE:
+      ts_type = "number";
+      break;
+    case t_base_type::TYPE_VOID:
+      ts_type = "void";
+    }
+  } else if (type->is_enum() || type->is_struct() || type->is_xception()) {
+    std::string type_name;
+    if (type->get_program()) {
+      type_name = js_namespace(type->get_program());
+    }
+    type_name.append(type->get_name());
+    ts_type = type_name;
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+
+    ts_type = ts_get_type(etype) + "[]";
+  } else if (type->is_map()) {
+    string ktype = ts_get_type(((t_map*)type)->get_key_type());
+    string vtype = ts_get_type(((t_map*)type)->get_val_type());
+
+
+    if (ktype == "number" || ktype == "string" ) {
+      ts_type = "{ [k: " + ktype + "]: " + vtype + "; }";
+    } else if ((((t_map*)type)->get_key_type())->is_enum()) {
+      // Not yet supported (enum map): https://github.com/Microsoft/TypeScript/pull/2652
+      //ts_type = "{ [k: " + ktype + "]: " + vtype + "; }";
+      ts_type = "{ [k: number /*" + ktype + "*/]: " + vtype + "; }";
+    } else {
+      ts_type = "any";
+    }
+  }
+
+  return ts_type;
+}
+
+/**
+ * Renders a TypeScript function signature of the form 'name(args: types): type;'
+ *
+ * @param t_function Function definition
+ * @param bool in-/exclude the callback argument
+ * @return String of rendered function definition
+ */
+std::string t_js_generator::ts_function_signature(t_function* tfunction, bool include_callback, bool optional_callback) {
+  string str;
+  const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  str = tfunction->get_name() + "(";
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    str += (*f_iter)->get_name() + ts_get_req(*f_iter) + ": " + ts_get_type((*f_iter)->get_type());
+
+    if (f_iter + 1 != fields.end() || (include_callback && fields.size() > 0)) {
+      str += ", ";
+    }
+  }
+
+  if (include_callback) {
+    string callback_optional_string = optional_callback ? "?" : "";
+    if (gen_node_) {
+      t_struct* exceptions = tfunction->get_xceptions();
+      string exception_types;
+      if (exceptions) {
+        const vector<t_field*>& members = exceptions->get_members();
+        for (vector<t_field*>::const_iterator it = members.begin(); it != members.end(); ++it) {
+          t_type* t = get_true_type((*it)->get_type());
+          if (it == members.begin()) {
+            exception_types = t->get_name();
+          } else {
+            exception_types += " | " + t->get_name();
+          }
+        }
+      }
+      if (exception_types == "") {
+        str += "callback" + callback_optional_string + ": (error: void, response: " + ts_get_type(tfunction->get_returntype()) + ")=>void): ";
+      } else {
+        str += "callback" + callback_optional_string + ": (error: " + exception_types + ", response: " + ts_get_type(tfunction->get_returntype()) + ")=>void): ";
+      }
+    } else {
+      str += "callback" + callback_optional_string + ": (data: " + ts_get_type(tfunction->get_returntype()) + ")=>void): ";
+    }
+
+    if (gen_jquery_) {
+      str += "JQueryPromise<" + ts_get_type(tfunction->get_returntype()) +">;";
+    } else {
+      str += "void;";
+    }
+  } else {
+    if (gen_es6_) {
+      str += "): Promise<" + ts_get_type(tfunction->get_returntype()) + ">;";
+    }
+    else {
+      str += "): " + ts_get_type(tfunction->get_returntype()) + ";";
+    }
+  }
+
+  return str;
+}
+
+/**
+ * Takes a name and produces a valid NodeJS identifier from it
+ *
+ * @param name The name which shall become a valid NodeJS identifier
+ * @return The modified name with the updated identifier
+ */
+std::string t_js_generator::make_valid_nodeJs_identifier(std::string const& name) {
+  std::string str = name;
+  if (str.empty()) {
+    return str;
+  }
+
+  // tests rely on this
+  assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
+
+  // if the first letter is a number, we add an additional underscore in front of it
+  char c = str.at(0);
+  if (('0' <= c) && (c <= '9')) {
+    str = "_" + str;
+  }
+
+  // following chars: letter, number or underscore
+  for (size_t i = 0; i < str.size(); ++i) {
+    c = str.at(i);
+    if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9'))
+        && ('_' != c) && ('$' != c)) {
+      str.replace(i, 1, "_");
+    }
+  }
+
+  return str;
+}
+
+THRIFT_REGISTER_GENERATOR(js,
+                          "Javascript",
+                          "    jquery:          Generate jQuery compatible code.\n"
+                          "    node:            Generate node.js compatible code.\n"
+                          "    ts:              Generate TypeScript definition files.\n"
+                          "    with_ns:         Create global namespace objects when using node.js\n"
+                          "    es6:             Create ES6 code with Promises\n")
diff --git a/compiler/cpp/src/thrift/generate/t_json_generator.cc b/compiler/cpp/src/thrift/generate/t_json_generator.cc
new file mode 100644
index 0000000..cd53612
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_json_generator.cc
@@ -0,0 +1,793 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <limits>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_generator.h"
+
+using std::map;
+using std::ofstream;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+using std::stack;
+
+static const string endl = "\n";
+static const string quot = "\"";
+static const bool NO_INDENT = false;
+static const bool FORCE_STRING = true;
+
+class t_json_generator : public t_generator {
+public:
+  t_json_generator(t_program* program,
+                   const std::map<std::string, std::string>& parsed_options,
+                   const std::string& option_string)
+    : t_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    should_merge_includes_ = false;
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("merge") == 0) {
+        should_merge_includes_ = true;
+      } else {
+        throw "unknown option json:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-json";
+  }
+
+  virtual ~t_json_generator() {}
+
+  /**
+  * Init and close methods
+  */
+
+  void init_generator();
+  void close_generator();
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_program();
+  void generate_function(t_function* tfunc);
+  void generate_field(t_field* field);
+
+  void generate_service(t_service* tservice);
+  void generate_struct(t_struct* tstruct);
+
+private:
+  bool should_merge_includes_;
+
+  ofstream_with_content_based_conditional_update f_json_;
+  std::stack<bool> comma_needed_;
+
+  template <typename T>
+  string number_to_string(T t) {
+    std::ostringstream out;
+    out.imbue(std::locale::classic());
+    out.precision(std::numeric_limits<T>::digits10);
+    out << t;
+    return out.str();
+  }
+
+  template <typename T>
+  void write_number(T n) {
+    f_json_ << number_to_string(n);
+  }
+
+  string get_type_name(t_type* ttype);
+  string get_qualified_name(t_type* ttype);
+
+  void start_object(bool should_indent = true);
+  void start_array();
+  void end_object();
+  void end_array();
+  void write_comma_if_needed();
+  void indicate_comma_needed();
+  string escape_json_string(const string& input);
+  string json_str(const string& str);
+  void merge_includes(t_program*);
+
+  void generate_constant(t_const* con);
+
+  void write_type_spec_entry(const char* name, t_type* ttype);
+  void write_type_spec_object(const char* name, t_type* ttype);
+  void write_type_spec(t_type* ttype);
+  void write_string(const string& value);
+  void write_value(t_type* tvalue);
+  void write_const_value(t_const_value* value, bool force_string = false);
+  void write_key_and(string key);
+  void write_key_and_string(string key, string val);
+  void write_key_and_integer(string key, int val);
+  void write_key_and_bool(string key, bool val);
+};
+
+void t_json_generator::init_generator() {
+  MKDIR(get_out_dir().c_str());
+
+  string f_json_name = get_out_dir() + program_->get_name() + ".json";
+  f_json_.open(f_json_name.c_str());
+
+  // Merge all included programs into this one so we can output one big file.
+  if (should_merge_includes_) {
+    merge_includes(program_);
+  }
+}
+
+string t_json_generator::escape_json_string(const string& input) {
+  std::ostringstream ss;
+  for (std::string::const_iterator iter = input.begin(); iter != input.end(); iter++) {
+    switch (*iter) {
+    case '\\':
+      ss << "\\\\";
+      break;
+    case '"':
+      ss << "\\\"";
+      break;
+    case '/':
+      ss << "\\/";
+      break;
+    case '\b':
+      ss << "\\b";
+      break;
+    case '\f':
+      ss << "\\f";
+      break;
+    case '\n':
+      ss << "\\n";
+      break;
+    case '\r':
+      ss << "\\r";
+      break;
+    case '\t':
+      ss << "\\t";
+      break;
+    default:
+      ss << *iter;
+      break;
+    }
+  }
+  return ss.str();
+}
+
+void t_json_generator::start_object(bool should_indent) {
+  f_json_ << (should_indent ? indent() : "") << "{" << endl;
+  indent_up();
+  comma_needed_.push(false);
+}
+
+void t_json_generator::start_array() {
+  f_json_ << "[" << endl;
+  indent_up();
+  comma_needed_.push(false);
+}
+
+void t_json_generator::write_comma_if_needed() {
+  if (comma_needed_.top()) {
+    f_json_ << "," << endl;
+  }
+}
+
+void t_json_generator::indicate_comma_needed() {
+  comma_needed_.pop();
+  comma_needed_.push(true);
+}
+
+void t_json_generator::write_key_and(string key) {
+  write_comma_if_needed();
+  indent(f_json_) << json_str(key) << ": ";
+  indicate_comma_needed();
+}
+
+void t_json_generator::write_key_and_integer(string key, int val) {
+  write_comma_if_needed();
+  indent(f_json_) << json_str(key) << ": " << number_to_string(val);
+  indicate_comma_needed();
+}
+
+void t_json_generator::write_key_and_string(string key, string val) {
+  write_comma_if_needed();
+  indent(f_json_) << json_str(key) << ": " << json_str(val);
+  indicate_comma_needed();
+}
+
+void t_json_generator::write_key_and_bool(string key, bool val) {
+  write_comma_if_needed();
+  indent(f_json_) << json_str(key) << ": " << (val ? "true" : "false");
+  indicate_comma_needed();
+}
+
+void t_json_generator::end_object() {
+  indent_down();
+  f_json_ << endl << indent() << "}";
+  comma_needed_.pop();
+}
+
+void t_json_generator::end_array() {
+  indent_down();
+  if (comma_needed_.top()) {
+    f_json_ << endl;
+  }
+  indent(f_json_) << "]";
+  comma_needed_.pop();
+}
+
+void t_json_generator::write_type_spec_object(const char* name, t_type* ttype) {
+  ttype = ttype->get_true_type();
+  if (ttype->is_struct() || ttype->is_xception() || ttype->is_container()) {
+    write_key_and(name);
+    start_object(NO_INDENT);
+    write_key_and("typeId");
+    write_type_spec(ttype);
+    end_object();
+  }
+}
+
+void t_json_generator::write_type_spec_entry(const char* name, t_type* ttype) {
+  write_key_and(name);
+  write_type_spec(ttype);
+}
+
+void t_json_generator::write_type_spec(t_type* ttype) {
+  ttype = ttype->get_true_type();
+
+  write_string(get_type_name(ttype));
+
+  if (ttype->annotations_.size() > 0) {
+    write_key_and("annotations");
+    start_object();
+    for (map<string, string>::iterator it = ttype->annotations_.begin(); it != ttype->annotations_.end(); ++it) {
+      write_key_and_string(it->first, it->second);
+    }
+    end_object();
+  }
+
+  if (ttype->is_struct() || ttype->is_xception()) {
+    write_key_and_string("class", get_qualified_name(ttype));
+  } else if (ttype->is_map()) {
+    t_type* ktype = ((t_map*)ttype)->get_key_type();
+    t_type* vtype = ((t_map*)ttype)->get_val_type();
+    write_key_and_string("keyTypeId", get_type_name(ktype));
+    write_key_and_string("valueTypeId", get_type_name(vtype));
+    write_type_spec_object("keyType", ktype);
+    write_type_spec_object("valueType", vtype);
+  } else if (ttype->is_list()) {
+    t_type* etype = ((t_list*)ttype)->get_elem_type();
+    write_key_and_string("elemTypeId", get_type_name(etype));
+    write_type_spec_object("elemType", etype);
+  } else if (ttype->is_set()) {
+    t_type* etype = ((t_set*)ttype)->get_elem_type();
+    write_key_and_string("elemTypeId", get_type_name(etype));
+    write_type_spec_object("elemType", etype);
+  }
+}
+
+void t_json_generator::close_generator() {
+  f_json_ << endl;
+  f_json_.close();
+}
+
+void t_json_generator::merge_includes(t_program* program) {
+  vector<t_program*> includes = program->get_includes();
+  vector<t_program*>::iterator inc_iter;
+  for (inc_iter = includes.begin(); inc_iter != includes.end(); ++inc_iter) {
+    t_program* include = *inc_iter;
+    // recurse in case we get crazy
+    merge_includes(include);
+    // merge enums
+    vector<t_enum*> enums = include->get_enums();
+    vector<t_enum*>::iterator en_iter;
+    for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+      program->add_enum(*en_iter);
+    }
+    // merge typedefs
+    vector<t_typedef*> typedefs = include->get_typedefs();
+    vector<t_typedef*>::iterator td_iter;
+    for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
+      program->add_typedef(*td_iter);
+    }
+    // merge structs
+    vector<t_struct*> objects = include->get_objects();
+    vector<t_struct*>::iterator o_iter;
+    for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
+      program->add_struct(*o_iter);
+    }
+    // merge constants
+    vector<t_const*> consts = include->get_consts();
+    vector<t_const*>::iterator c_iter;
+    for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+      program->add_const(*c_iter);
+    }
+
+    // merge services
+    vector<t_service*> services = include->get_services();
+    vector<t_service*>::iterator sv_iter;
+    for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+      program->add_service(*sv_iter);
+    }
+  }
+}
+
+void t_json_generator::generate_program() {
+
+  init_generator();
+
+  start_object();
+  write_key_and_string("name", program_->get_name());
+  if (program_->has_doc()) {
+    write_key_and_string("doc", program_->get_doc());
+  }
+
+  // When merging includes, the "namespaces" and "includes" sections
+  // become ambiguous, so just skip them.
+  if (!should_merge_includes_) {
+    // Generate namespaces
+    write_key_and("namespaces");
+    start_object(NO_INDENT);
+    const map<string, string>& namespaces = program_->get_namespaces();
+    map<string, string>::const_iterator ns_it;
+    for (ns_it = namespaces.begin(); ns_it != namespaces.end(); ++ns_it) {
+      write_key_and_string(ns_it->first, ns_it->second);
+      indicate_comma_needed();
+    }
+    end_object();
+
+    // Generate includes
+    write_key_and("includes");
+    start_array();
+    const vector<t_program*> includes = program_->get_includes();
+    vector<t_program*>::const_iterator inc_it;
+    for (inc_it = includes.begin(); inc_it != includes.end(); ++inc_it) {
+      write_comma_if_needed();
+      write_string((*inc_it)->get_name());
+      indicate_comma_needed();
+    }
+    end_array();
+  }
+
+  // Generate enums
+  write_key_and("enums");
+  start_array();
+  vector<t_enum*> enums = program_->get_enums();
+  vector<t_enum*>::iterator en_iter;
+  for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+    write_comma_if_needed();
+    generate_enum(*en_iter);
+    indicate_comma_needed();
+  }
+  end_array();
+
+  // Generate typedefs
+  write_key_and("typedefs");
+  start_array();
+  vector<t_typedef*> typedefs = program_->get_typedefs();
+  vector<t_typedef*>::iterator td_iter;
+  for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
+    write_comma_if_needed();
+    generate_typedef(*td_iter);
+    indicate_comma_needed();
+  }
+  end_array();
+
+  // Generate structs, exceptions, and unions in declared order
+  write_key_and("structs");
+  start_array();
+  vector<t_struct*> objects = program_->get_objects();
+  vector<t_struct*>::iterator o_iter;
+  for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
+    write_comma_if_needed();
+    if ((*o_iter)->is_xception()) {
+      generate_xception(*o_iter);
+    } else {
+      generate_struct(*o_iter);
+    }
+    indicate_comma_needed();
+  }
+  end_array();
+
+  // Generate constants
+  write_key_and("constants");
+  start_array();
+  vector<t_const*> consts = program_->get_consts();
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    write_comma_if_needed();
+    generate_constant(*c_iter);
+    indicate_comma_needed();
+  }
+  end_array();
+
+  // Generate services
+  write_key_and("services");
+  start_array();
+  vector<t_service*> services = program_->get_services();
+  vector<t_service*>::iterator sv_iter;
+  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    write_comma_if_needed();
+    generate_service(*sv_iter);
+    indicate_comma_needed();
+  }
+  end_array();
+
+  end_object();
+
+  // Close the generator
+  close_generator();
+}
+
+void t_json_generator::generate_typedef(t_typedef* ttypedef) {
+  start_object();
+  write_key_and_string("name", get_qualified_name(ttypedef));
+  write_key_and_string("typeId", get_type_name(ttypedef->get_true_type()));
+  write_type_spec_object("type", ttypedef->get_true_type());
+  if (ttypedef->has_doc()) {
+    write_key_and_string("doc", ttypedef->get_doc());
+  }
+  if (ttypedef->annotations_.size() > 0) {
+    write_key_and("annotations");
+    start_object();
+    for (map<string, string>::iterator it = ttypedef->annotations_.begin(); it != ttypedef->annotations_.end(); ++it) {
+      write_key_and_string(it->first, it->second);
+    }
+    end_object();
+  }
+  end_object();
+}
+
+void t_json_generator::write_string(const string& value) {
+  f_json_ << quot << escape_json_string(value) << quot;
+}
+
+void t_json_generator::write_const_value(t_const_value* value, bool should_force_string) {
+
+  switch (value->get_type()) {
+
+  case t_const_value::CV_IDENTIFIER:
+  case t_const_value::CV_INTEGER:
+    if (should_force_string) {
+      write_string(number_to_string(value->get_integer()));
+    } else {
+      write_number(value->get_integer());
+    }
+    break;
+
+  case t_const_value::CV_DOUBLE:
+    if (should_force_string) {
+      write_string(number_to_string(value->get_double()));
+    } else {
+      write_number(value->get_double());
+    }
+    break;
+
+  case t_const_value::CV_STRING:
+    write_string(value->get_string());
+    break;
+
+  case t_const_value::CV_LIST: {
+    start_array();
+    std::vector<t_const_value*> list = value->get_list();
+    std::vector<t_const_value*>::iterator lit;
+    for (lit = list.begin(); lit != list.end(); ++lit) {
+      write_comma_if_needed();
+      f_json_ << indent();
+      write_const_value(*lit);
+      indicate_comma_needed();
+    }
+    end_array();
+    break;
+  }
+
+  case t_const_value::CV_MAP: {
+    start_object(NO_INDENT);
+    std::map<t_const_value*, t_const_value*, t_const_value::value_compare> map = value->get_map();
+    std::map<t_const_value*, t_const_value*, t_const_value::value_compare>::iterator mit;
+    for (mit = map.begin(); mit != map.end(); ++mit) {
+      write_comma_if_needed();
+      f_json_ << indent();
+      // JSON objects only allow string keys
+      write_const_value(mit->first, FORCE_STRING);
+      f_json_ << ": ";
+      write_const_value(mit->second);
+      indicate_comma_needed();
+    }
+    end_object();
+    break;
+  }
+
+  default:
+    f_json_ << "null";
+    break;
+  }
+}
+
+string t_json_generator::json_str(const string& str) {
+  return quot + escape_json_string(str) + quot;
+}
+
+void t_json_generator::generate_constant(t_const* con) {
+  start_object();
+
+  write_key_and_string("name", con->get_name());
+  write_key_and_string("typeId", get_type_name(con->get_type()));
+  write_type_spec_object("type", con->get_type());
+
+  if (con->has_doc()) {
+    write_key_and_string("doc", con->get_doc());
+  }
+
+  write_key_and("value");
+  write_const_value(con->get_value());
+
+  end_object();
+}
+
+void t_json_generator::generate_enum(t_enum* tenum) {
+  start_object();
+
+  write_key_and_string("name", tenum->get_name());
+
+  if (tenum->has_doc()) {
+    write_key_and_string("doc", tenum->get_doc());
+  }
+
+  if (tenum->annotations_.size() > 0) {
+      write_key_and("annotations");
+      start_object();
+      for (map<string, string>::iterator it = tenum->annotations_.begin(); it != tenum->annotations_.end(); ++it) {
+        write_key_and_string(it->first, it->second);
+      }
+      end_object();
+  }
+
+  write_key_and("members");
+  start_array();
+  vector<t_enum_value*> values = tenum->get_constants();
+  vector<t_enum_value*>::iterator val_iter;
+  for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) {
+    write_comma_if_needed();
+    t_enum_value* val = (*val_iter);
+    start_object();
+    write_key_and_string("name", val->get_name());
+    write_key_and_integer("value", val->get_value());
+    if (val->has_doc()) {
+      write_key_and_string("doc", val->get_doc());
+    }
+    end_object();
+    indicate_comma_needed();
+  }
+  end_array();
+
+  end_object();
+}
+
+void t_json_generator::generate_struct(t_struct* tstruct) {
+  start_object();
+
+  write_key_and_string("name", tstruct->get_name());
+
+  if (tstruct->has_doc()) {
+    write_key_and_string("doc", tstruct->get_doc());
+  }
+
+  if (tstruct->annotations_.size() > 0) {
+    write_key_and("annotations");
+    start_object();
+    for (map<string, string>::iterator it = tstruct->annotations_.begin(); it != tstruct->annotations_.end(); ++it) {
+      write_key_and_string(it->first, it->second);
+    }
+    end_object();
+  }
+
+  write_key_and_bool("isException", tstruct->is_xception());
+
+  write_key_and_bool("isUnion", tstruct->is_union());
+
+  write_key_and("fields");
+  start_array();
+  vector<t_field*> members = tstruct->get_members();
+  vector<t_field*>::iterator mem_iter;
+  for (mem_iter = members.begin(); mem_iter != members.end(); mem_iter++) {
+    write_comma_if_needed();
+    generate_field(*mem_iter);
+    indicate_comma_needed();
+  }
+  end_array();
+
+  end_object();
+}
+
+void t_json_generator::generate_service(t_service* tservice) {
+  start_object();
+
+  write_key_and_string("name", get_qualified_name(tservice));
+
+  if (tservice->get_extends()) {
+    write_key_and_string("extends", get_qualified_name(tservice->get_extends()));
+  }
+
+  if (tservice->has_doc()) {
+    write_key_and_string("doc", tservice->get_doc());
+  }
+
+  if (tservice->annotations_.size() > 0) {
+    write_key_and("annotations");
+    start_object();
+    for (map<string, string>::iterator it = tservice->annotations_.begin(); it != tservice->annotations_.end(); ++it) {
+      write_key_and_string(it->first, it->second);
+    }
+    end_object();
+  }
+
+  write_key_and("functions");
+  start_array();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator fn_iter = functions.begin();
+  for (; fn_iter != functions.end(); fn_iter++) {
+    write_comma_if_needed();
+    generate_function(*fn_iter);
+    indicate_comma_needed();
+  }
+  end_array();
+
+  end_object();
+}
+
+void t_json_generator::generate_function(t_function* tfunc) {
+  start_object();
+
+  write_key_and_string("name", tfunc->get_name());
+
+  write_key_and_string("returnTypeId", get_type_name(tfunc->get_returntype()));
+  write_type_spec_object("returnType", tfunc->get_returntype());
+
+  write_key_and_bool("oneway", tfunc->is_oneway());
+
+  if (tfunc->has_doc()) {
+    write_key_and_string("doc", tfunc->get_doc());
+  }
+
+  if (tfunc->annotations_.size() > 0) {
+    write_key_and("annotations");
+    start_object();
+    for (map<string, string>::iterator it = tfunc->annotations_.begin(); it != tfunc->annotations_.end(); ++it) {
+      write_key_and_string(it->first, it->second);
+    }
+    end_object();
+  }
+
+  write_key_and("arguments");
+  start_array();
+  vector<t_field*> members = tfunc->get_arglist()->get_members();
+  vector<t_field*>::iterator mem_iter = members.begin();
+  for (; mem_iter != members.end(); mem_iter++) {
+    write_comma_if_needed();
+    generate_field(*mem_iter);
+    indicate_comma_needed();
+  }
+  end_array();
+
+  write_key_and("exceptions");
+  start_array();
+  vector<t_field*> excepts = tfunc->get_xceptions()->get_members();
+  vector<t_field*>::iterator ex_iter = excepts.begin();
+  for (; ex_iter != excepts.end(); ex_iter++) {
+    write_comma_if_needed();
+    generate_field(*ex_iter);
+    indicate_comma_needed();
+  }
+  end_array();
+
+  end_object();
+}
+
+void t_json_generator::generate_field(t_field* field) {
+  start_object();
+
+  write_key_and_integer("key", field->get_key());
+  write_key_and_string("name", field->get_name());
+  write_key_and_string("typeId", get_type_name(field->get_type()));
+  write_type_spec_object("type", field->get_type());
+
+  if (field->has_doc()) {
+    write_key_and_string("doc", field->get_doc());
+  }
+
+  if (field->annotations_.size() > 0) {
+    write_key_and("annotations");
+    start_object();
+    for (map<string, string>::iterator it = field->annotations_.begin(); it != field->annotations_.end(); ++it) {
+      write_key_and_string(it->first, it->second);
+    }
+    end_object();
+  }
+
+  write_key_and("required");
+  switch (field->get_req()) {
+  case t_field::T_REQUIRED:
+    write_string("required");
+    break;
+  case t_field::T_OPT_IN_REQ_OUT:
+    write_string("req_out");
+    break;
+  default:
+    write_string("optional");
+    break;
+  }
+
+  if (field->get_value()) {
+    write_key_and("default");
+    write_const_value(field->get_value());
+  }
+
+  end_object();
+}
+
+string t_json_generator::get_type_name(t_type* ttype) {
+  ttype = ttype->get_true_type();
+  if (ttype->is_list()) {
+    return "list";
+  }
+  if (ttype->is_set()) {
+    return "set";
+  }
+  if (ttype->is_map()) {
+    return "map";
+  }
+  if (ttype->is_enum()) {
+    return "i32";
+  }
+  if (ttype->is_struct()) {
+    return ((t_struct*)ttype)->is_union() ? "union" : "struct";
+  }
+  if (ttype->is_xception()) {
+    return "exception";
+  }
+  if (ttype->is_base_type()) {
+    t_base_type* tbasetype = (t_base_type*)ttype;
+    return tbasetype->is_binary() ? "binary" : t_base_type::t_base_name(tbasetype->get_base());
+  }
+
+  return "(unknown)";
+}
+
+string t_json_generator::get_qualified_name(t_type* ttype) {
+  if (should_merge_includes_ || ttype->get_program() == program_) {
+    return ttype->get_name();
+  }
+  return ttype->get_program()->get_name() + "." + ttype->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(json,
+                          "JSON",
+                          "    merge:           Generate output with included files merged\n")
diff --git a/compiler/cpp/src/thrift/generate/t_lua_generator.cc b/compiler/cpp/src/thrift/generate/t_lua_generator.cc
new file mode 100644
index 0000000..adee896
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_lua_generator.cc
@@ -0,0 +1,1138 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::ostream;
+using std::string;
+using std::vector;
+using std::map;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * LUA code generator.
+ *
+ */
+class t_lua_generator : public t_oop_generator {
+public:
+  t_lua_generator(t_program* program,
+                  const std::map<std::string, std::string>& parsed_options,
+                  const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    gen_requires_ = true;
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("omit_requires") == 0) {
+        gen_requires_ = false;
+      } else {
+        throw "unknown option lua:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-lua";
+  }
+
+  /**
+   * 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);
+
+private:
+  /**
+   * True iff we should generate lua require statements.
+   */
+  bool gen_requires_;
+
+  /**
+   * Struct-level generation functions
+   */
+  void generate_lua_struct_definition(std::ostream& out,
+                                      t_struct* tstruct,
+                                      bool is_xception = false);
+  void generate_lua_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_lua_struct_writer(std::ostream& out, t_struct* tstruct);
+
+  /**
+   * Service-level generation functions
+   */
+  void generate_service_client(std::ostream& out, t_service* tservice);
+  void generate_service_interface(std::ostream& out, t_service* tservice);
+  void generate_service_processor(std::ostream& out, t_service* tservice);
+  void generate_process_function(std::ostream& out, t_service* tservice, t_function* tfunction);
+  void generate_service_helpers(ostream& out, t_service* tservice);
+  void generate_function_helpers(ostream& out, t_function* tfunction);
+
+  /**
+   * Deserialization (Read)
+   */
+  void generate_deserialize_field(std::ostream& out,
+                                  t_field* tfield,
+                                  bool local,
+                                  std::string prefix = "");
+
+  void generate_deserialize_struct(std::ostream& out,
+                                   t_struct* tstruct,
+                                   bool local,
+                                   std::string prefix = "");
+
+  void generate_deserialize_container(std::ostream& out,
+                                      t_type* ttype,
+                                      bool local,
+                                      std::string prefix = "");
+
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+
+  void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         std::string prefix = "");
+
+  /**
+   * Serialization (Write)
+   */
+  void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
+
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string kiter,
+                                      std::string viter);
+
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  /**
+   * Helper rendering functions
+   */
+  std::string lua_includes();
+  std::string function_signature(t_function* tfunction, std::string prefix = "");
+  std::string argument_list(t_struct* tstruct, std::string prefix = "");
+  std::string type_to_enum(t_type* ttype);
+  static std::string get_namespace(const t_program* program);
+
+  std::string autogen_comment() {
+    return std::string("--\n") + "-- Autogenerated by Thrift\n" + "--\n"
+           + "-- DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "-- @"
+                                                                                       "generated\n"
+           + "--\n";
+  }
+
+  /**
+   * File streams
+   */
+  ofstream_with_content_based_conditional_update f_types_;
+  ofstream_with_content_based_conditional_update f_consts_;
+  ofstream_with_content_based_conditional_update f_service_;
+};
+
+/**
+ * Init and close methods
+ */
+void t_lua_generator::init_generator() {
+  // Make output directory
+  string outdir = get_out_dir();
+  MKDIR(outdir.c_str());
+
+  // Make output files
+  string cur_namespace = get_namespace(program_);
+  string f_consts_name = outdir + cur_namespace + "constants.lua";
+  f_consts_.open(f_consts_name.c_str());
+  string f_types_name = outdir + cur_namespace + "ttypes.lua";
+  f_types_.open(f_types_name.c_str());
+
+  // Add headers
+  f_consts_ << autogen_comment() << lua_includes();
+  f_types_ << autogen_comment() << lua_includes();
+  if (gen_requires_) {
+    f_types_ << endl << "require '" << cur_namespace << "constants'";
+  }
+}
+
+void t_lua_generator::close_generator() {
+  // Close types file
+  f_types_.close();
+  f_consts_.close();
+}
+
+/**
+ * Generate a typedef (essentially a constant)
+ */
+void t_lua_generator::generate_typedef(t_typedef* ttypedef) {
+  f_types_ << endl << endl << indent() << ttypedef->get_symbolic() << " = "
+           << ttypedef->get_type()->get_name();
+}
+
+/**
+ * Generates code for an enumerated type (table)
+ */
+void t_lua_generator::generate_enum(t_enum* tenum) {
+  f_types_ << endl << endl << tenum->get_name() << " = {" << endl;
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  for (c_iter = constants.begin(); c_iter != constants.end();) {
+    int32_t value = (*c_iter)->get_value();
+
+    f_types_ << "  " << (*c_iter)->get_name() << " = " << value;
+    ++c_iter;
+    if (c_iter != constants.end()) {
+      f_types_ << ",";
+    }
+    f_types_ << endl;
+  }
+  f_types_ << "}";
+}
+
+/**
+ * Generate a constant (non-local) value
+ */
+void t_lua_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  f_consts_ << endl << endl << name << " = ";
+  f_consts_ << render_const_value(type, value);
+}
+
+/**
+ * Prints the value of a constant with the given type.
+ */
+string t_lua_generator::render_const_value(t_type* type, t_const_value* value) {
+  std::ostringstream out;
+
+  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_STRING:
+      out << "'" << value->get_string() << "'";
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "true" : "false");
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+      out << value->get_integer();
+      break;
+    case t_base_type::TYPE_I64:
+      out << "lualongnumber.new('" << value->get_string() << "')";
+      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()) {
+    out << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    out << type->get_name() << " = {" << 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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end();) {
+      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();
+      }
+
+      indent(out);
+      out << render_const_value(g_type_string, v_iter->first);
+      out << " = ";
+      out << render_const_value(field_type, v_iter->second);
+      ++v_iter;
+      if (v_iter != val.end()) {
+        out << ",";
+      }
+    }
+
+    out << "}";
+    indent_down();
+  } else if (type->is_map()) {
+    out << type->get_name() << "{" << endl;
+    indent_up();
+
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end();) {
+      indent(out) << "[" << render_const_value(ktype, v_iter->first)
+                  << "] = " << render_const_value(vtype, v_iter->second);
+      ++v_iter;
+      if (v_iter != val.end()) {
+        out << ",";
+      }
+      out << endl;
+    }
+    indent_down();
+    indent(out) << "}";
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    out << type->get_name() << " = {" << endl;
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end();) {
+      indent(out);
+      out << "[" << render_const_value(etype, *v_iter) << "]";
+      if (type->is_set()) {
+        out << " = true";
+      } else {
+        out << " = false";
+      }
+      ++v_iter;
+      if (v_iter != val.end()) {
+        out << "," << endl;
+      }
+    }
+    out << "}";
+  }
+  return out.str();
+}
+
+/**
+ * Generate a thrift struct
+ */
+void t_lua_generator::generate_struct(t_struct* tstruct) {
+  generate_lua_struct_definition(f_types_, tstruct, false);
+}
+
+/**
+ * Generate a thrift exception
+ */
+void t_lua_generator::generate_xception(t_struct* txception) {
+  generate_lua_struct_definition(f_types_, txception, true);
+}
+
+/**
+ * Generate a thrift struct or exception (lua table)
+ */
+void t_lua_generator::generate_lua_struct_definition(ostream& out,
+                                                     t_struct* tstruct,
+                                                     bool is_exception) {
+  vector<t_field*>::const_iterator m_iter;
+  const vector<t_field*>& members = tstruct->get_members();
+
+  indent(out) << endl << endl << tstruct->get_name();
+  if (is_exception) {
+    out << " = TException:new{" << endl << indent() << "  __type = '" << tstruct->get_name() << "'";
+    if (members.size() > 0) {
+      out << ",";
+    }
+    out << endl;
+  } else {
+    out << " = __TObject:new{" << endl;
+  }
+  indent_up();
+  for (m_iter = members.begin(); m_iter != members.end();) {
+    indent(out);
+    out << (*m_iter)->get_name();
+    ++m_iter;
+    if (m_iter != members.end()) {
+      out << "," << endl;
+    }
+  }
+  indent_down();
+  indent(out);
+  out << endl << "}";
+
+  generate_lua_struct_reader(out, tstruct);
+  generate_lua_struct_writer(out, tstruct);
+}
+
+/**
+ * Generate a struct/exception reader
+ */
+void t_lua_generator::generate_lua_struct_reader(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // function
+  indent(out) << endl << endl << "function " << tstruct->get_name() << ":read(iprot)" << endl;
+  indent_up();
+
+  indent(out) << "iprot:readStructBegin()" << endl;
+
+  // while: Read in fields
+  indent(out) << "while true do" << endl;
+  indent_up();
+
+  // if: Check what to read
+  indent(out) << "local fname, ftype, fid = iprot:readFieldBegin()" << endl;
+  indent(out) << "if ftype == TType.STOP then" << endl;
+  indent_up();
+  indent(out) << "break" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent_down();
+    indent(out) << "elseif fid == " << (*f_iter)->get_key() << " then" << endl;
+    indent_up();
+    indent(out) << "if ftype == " << type_to_enum((*f_iter)->get_type()) << " then" << endl;
+    indent_up();
+
+    // Read field contents
+    generate_deserialize_field(out, *f_iter, false, "self.");
+
+    indent_down();
+    indent(out) << "else" << endl;
+    indent(out) << "  iprot:skip(ftype)" << endl;
+    indent(out) << "end" << endl;
+  }
+
+  // end if
+  indent_down();
+  indent(out) << "else" << endl;
+  indent(out) << "  iprot:skip(ftype)" << endl;
+  indent(out) << "end" << endl;
+  indent(out) << "iprot:readFieldEnd()" << endl;
+
+  // end while
+  indent_down();
+  indent(out) << "end" << endl;
+  indent(out) << "iprot:readStructEnd()" << endl;
+
+  // end function
+  indent_down();
+  indent(out);
+  out << "end";
+}
+
+/**
+ * Generate a struct/exception writer
+ */
+void t_lua_generator::generate_lua_struct_writer(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // function
+  indent(out) << endl << endl << "function " << tstruct->get_name() << ":write(oprot)" << endl;
+  indent_up();
+
+  indent(out) << "oprot:writeStructBegin('" << tstruct->get_name() << "')" << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    // To check element of self whether nil or not.
+    // avoid the value(false) of BOOL is lost.
+    indent(out) << "if self." << (*f_iter)->get_name() << " ~= nil then" << endl;
+    indent_up();
+    indent(out) << "oprot:writeFieldBegin('" << (*f_iter)->get_name() << "', "
+                << type_to_enum((*f_iter)->get_type()) << ", " << (*f_iter)->get_key() << ")"
+                << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "self.");
+
+    indent(out) << "oprot:writeFieldEnd()" << endl;
+    indent_down();
+    indent(out) << "end" << endl;
+  }
+  indent(out) << "oprot:writeFieldStop()" << endl;
+  indent(out) << "oprot:writeStructEnd()" << endl;
+
+  // end function
+  indent_down();
+  indent(out);
+  out << "end";
+}
+
+/**
+ * Generate a thrift service
+ */
+void t_lua_generator::generate_service(t_service* tservice) {
+  // Get output directory
+  string outdir = get_out_dir();
+
+  // Open the file for writing
+  string cur_ns = get_namespace(program_);
+  string f_service_name = outdir + cur_ns + tservice->get_name() + ".lua";
+  f_service_.open(f_service_name.c_str());
+
+  // Headers
+  f_service_ << autogen_comment() << lua_includes();
+  if (gen_requires_) {
+    f_service_ << endl << "require '" << cur_ns << "ttypes'" << endl;
+
+    if (tservice->get_extends() != NULL) {
+      f_service_ << "require '" << get_namespace(tservice->get_extends()->get_program())
+                 << tservice->get_extends()->get_name() << "'" << endl;
+    }
+  }
+
+  f_service_ << endl;
+
+  generate_service_client(f_service_, tservice);
+  generate_service_interface(f_service_, tservice);
+  generate_service_processor(f_service_, tservice);
+  generate_service_helpers(f_service_, tservice);
+
+  // Close the file
+  f_service_.close();
+}
+
+void t_lua_generator::generate_service_interface(ostream& out, t_service* tservice) {
+  string classname = tservice->get_name() + "Iface";
+  t_service* extends_s = tservice->get_extends();
+
+  // Interface object definition
+  out << classname << " = ";
+  if (extends_s) {
+    out << extends_s->get_name() << "Iface:new{" << endl;
+  } else {
+    out << "__TObject:new{" << endl;
+  }
+  out << "  __type = '" << classname << "'" << endl << "}" << endl << endl;
+}
+
+void t_lua_generator::generate_service_client(ostream& out, t_service* tservice) {
+  string classname = tservice->get_name() + "Client";
+  t_service* extends_s = tservice->get_extends();
+
+  // Client object definition
+  out << classname << " = __TObject.new(";
+  if (extends_s != NULL) {
+    out << extends_s->get_name() << "Client";
+  } else {
+    out << "__TClient";
+  }
+  out << ", {" << endl << "  __type = '" << classname << "'" << endl << "})" << endl;
+
+  // Send/Recv functions
+  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) {
+    string sig = function_signature(*f_iter);
+    string funcname = (*f_iter)->get_name();
+
+    // Wrapper function
+    indent(out) << endl << "function " << classname << ":" << sig << endl;
+    indent_up();
+
+    indent(out) << "self:send_" << sig << endl << indent();
+    if (!(*f_iter)->is_oneway()) {
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        out << "return ";
+      }
+      out << "self:recv_" << sig << endl;
+    }
+
+    indent_down();
+    indent(out) << "end" << endl;
+
+    // Send function
+    indent(out) << endl << "function " << classname << ":send_" << sig << endl;
+    indent_up();
+
+    indent(out) << "self.oprot:writeMessageBegin('" << funcname << "', "
+                << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL")
+                << ", self._seqid)" << endl;
+    indent(out) << "local args = " << funcname << "_args:new{}" << endl;
+
+    // Set the args
+    const vector<t_field*>& args = (*f_iter)->get_arglist()->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    for (fld_iter = args.begin(); fld_iter != args.end(); ++fld_iter) {
+      std::string argname = (*fld_iter)->get_name();
+      indent(out) << "args." << argname << " = " << argname << endl;
+    }
+
+    indent(out) << "args:write(self.oprot)" << endl;
+    indent(out) << "self.oprot:writeMessageEnd()" << endl;
+    indent(out) << "self.oprot.trans:flush()" << endl;
+
+    indent_down();
+    indent(out) << "end" << endl;
+
+    // Recv function
+    if (!(*f_iter)->is_oneway()) {
+      indent(out) << endl << "function " << classname << ":recv_" << sig << endl;
+      indent_up();
+
+      out << indent() << "local fname, mtype, rseqid = self.iprot:"
+          << "readMessageBegin()" << endl << indent() << "if mtype == TMessageType.EXCEPTION then"
+          << endl << indent() << "  local x = TApplicationException:new{}" << endl << indent()
+          << "  x:read(self.iprot)" << endl << indent() << "  self.iprot:readMessageEnd()" << endl
+          << indent() << "  error(x)" << endl << indent() << "end" << endl << indent()
+          << "local result = " << funcname << "_result:new{}" << endl << indent()
+          << "result:read(self.iprot)" << endl << indent() << "self.iprot:readMessageEnd()" << endl;
+
+      // Return the result if it's not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        out << indent() << "if result.success ~= nil then" << endl << indent() << "  return result.success"
+            << endl;
+
+        // Throw custom exceptions
+        const std::vector<t_field*>& xf = (*f_iter)->get_xceptions()->get_members();
+        vector<t_field*>::const_iterator x_iter;
+        for (x_iter = xf.begin(); x_iter != xf.end(); ++x_iter) {
+          out << indent() << "elseif result." << (*x_iter)->get_name() << " then" << endl
+              << indent() << "  error(result." << (*x_iter)->get_name() << ")" << endl;
+        }
+
+        out << indent() << "end" << endl << indent()
+            << "error(TApplicationException:new{errorCode = "
+            << "TApplicationException.MISSING_RESULT})" << endl;
+      }
+
+      indent_down();
+      indent(out) << "end" << endl;
+    }
+  }
+}
+
+void t_lua_generator::generate_service_processor(ostream& out, t_service* tservice) {
+  string classname = tservice->get_name() + "Processor";
+  t_service* extends_s = tservice->get_extends();
+
+  // Define processor table
+  out << endl << classname << " = __TObject.new(";
+  if (extends_s != NULL) {
+    out << extends_s->get_name() << "Processor" << endl;
+  } else {
+    out << "__TProcessor" << endl;
+  }
+  out << ", {" << endl << " __type = '" << classname << "'" << endl << "})" << endl;
+
+  // Process function
+  indent(out) << endl << "function " << classname << ":process(iprot, oprot, server_ctx)" << endl;
+  indent_up();
+
+  indent(out) << "local name, mtype, seqid = iprot:readMessageBegin()" << endl;
+  indent(out) << "local func_name = 'process_' .. name" << endl;
+  indent(out) << "if not self[func_name] or ttype(self[func_name]) ~= 'function' then";
+  indent_up();
+  out << endl << indent() << "iprot:skip(TType.STRUCT)" << endl << indent()
+      << "iprot:readMessageEnd()" << endl << indent() << "x = TApplicationException:new{" << endl
+      << indent() << "  errorCode = TApplicationException.UNKNOWN_METHOD" << endl << indent() << "}"
+      << endl << indent() << "oprot:writeMessageBegin(name, TMessageType.EXCEPTION, "
+      << "seqid)" << endl << indent() << "x:write(oprot)" << endl << indent()
+      << "oprot:writeMessageEnd()" << endl << indent() << "oprot.trans:flush()" << endl;
+  indent_down();
+  indent(out) << "else" << endl << indent()
+              << "  self[func_name](self, seqid, iprot, oprot, server_ctx)" << endl << indent()
+              << "end" << endl;
+
+  indent_down();
+  indent(out) << "end" << endl;
+
+  // Generate the process subfunctions
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(out, tservice, *f_iter);
+  }
+}
+
+void t_lua_generator::generate_process_function(ostream& out,
+                                                t_service* tservice,
+                                                t_function* tfunction) {
+  string classname = tservice->get_name() + "Processor";
+  string argsname = tfunction->get_name() + "_args";
+  string resultname = tfunction->get_name() + "_result";
+  string fn_name = tfunction->get_name();
+
+  indent(out) << endl << "function " << classname << ":process_" << fn_name
+              << "(seqid, iprot, oprot, server_ctx)" << endl;
+  indent_up();
+
+  // Read the request
+  out << indent() << "local args = " << argsname << ":new{}" << endl << indent()
+      << "local reply_type = TMessageType.REPLY" << endl << indent() << "args:read(iprot)" << endl
+      << indent() << "iprot:readMessageEnd()" << endl << indent() << "local result = " << resultname
+      << ":new{}" << endl << indent() << "local status, res = pcall(self.handler." << fn_name
+      << ", self.handler";
+
+  // Print arguments
+  t_struct* args = tfunction->get_arglist();
+  if (args->get_members().size() > 0) {
+    out << ", " << argument_list(args, "args.");
+  }
+
+  // Check for errors
+  out << ")" << endl << indent() << "if not status then" << endl << indent()
+      << "  reply_type = TMessageType.EXCEPTION" << endl << indent()
+      << "  result = TApplicationException:new{message = res}" << endl;
+
+  // Handle custom exceptions
+  const std::vector<t_field*>& xf = tfunction->get_xceptions()->get_members();
+  if (xf.size() > 0) {
+    vector<t_field*>::const_iterator x_iter;
+    for (x_iter = xf.begin(); x_iter != xf.end(); ++x_iter) {
+      out << indent() << "elseif ttype(res) == '" << (*x_iter)->get_type()->get_name() << "' then"
+          << endl << indent() << "  result." << (*x_iter)->get_name() << " = res" << endl;
+    }
+  }
+
+  // Set the result and write the reply
+  out << indent() << "else" << endl << indent() << "  result.success = res" << endl << indent()
+      << "end" << endl << indent() << "oprot:writeMessageBegin('" << fn_name << "', reply_type, "
+      << "seqid)" << endl << indent() << "result:write(oprot)" << endl << indent()
+      << "oprot:writeMessageEnd()" << endl << indent() << "oprot.trans:flush()" << endl;
+
+  indent_down();
+  indent(out) << "end" << endl;
+}
+
+// Service helpers
+void t_lua_generator::generate_service_helpers(ostream& out, t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  out << endl << "-- HELPER FUNCTIONS AND STRUCTURES";
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_lua_struct_definition(out, ts, false);
+    generate_function_helpers(out, *f_iter);
+  }
+}
+
+void t_lua_generator::generate_function_helpers(ostream& out, t_function* tfunction) {
+  if (!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_lua_struct_definition(out, &result, false);
+  }
+}
+
+/**
+ * Deserialize (Read)
+ */
+void t_lua_generator::generate_deserialize_field(ostream& out,
+                                                 t_field* tfield,
+                                                 bool local,
+                                                 string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name();
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, local, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, local, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) << (local ? "local " : "") << name << " = 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_I8:
+        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 PHP name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "readI32()";
+    }
+    out << endl;
+
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+}
+
+void t_lua_generator::generate_deserialize_struct(ostream& out,
+                                                  t_struct* tstruct,
+                                                  bool local,
+                                                  string prefix) {
+  indent(out) << (local ? "local " : "") << prefix << " = " << tstruct->get_name() << ":new{}"
+              << endl << indent() << prefix << ":read(iprot)" << endl;
+}
+
+void t_lua_generator::generate_deserialize_container(ostream& out,
+                                                     t_type* ttype,
+                                                     bool local,
+                                                     string prefix) {
+  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_i8, ktype);
+  t_field fvtype(g_type_i8, vtype);
+  t_field fetype(g_type_i8, etype);
+
+  // Declare variables, read header
+  indent(out) << (local ? "local " : "") << prefix << " = {}" << endl;
+  if (ttype->is_map()) {
+    indent(out) << "local " << ktype << ", " << vtype << ", " << size << " = iprot:readMapBegin() "
+                << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "local " << etype << ", " << size << " = iprot:readSetBegin()" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "local " << etype << ", " << size << " = iprot:readListBegin()" << endl;
+  }
+
+  // Deserialize
+  indent(out) << "for _i=1," << size << " do" << endl;
+  indent_up();
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  indent_down();
+  indent(out) << "end" << endl;
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "iprot:readMapEnd()" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "iprot:readSetEnd()" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "iprot:readListEnd()" << endl;
+  }
+}
+
+void t_lua_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) {
+  // A map is represented by a table indexable by any lua type
+  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 << "[" << key << "] = " << val << endl;
+}
+
+void t_lua_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) {
+  // A set is represented by a table indexed by the value
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  generate_deserialize_field(out, &felem, true);
+
+  indent(out) << prefix << "[" << elem << "] = " << elem << endl;
+}
+
+void t_lua_generator::generate_deserialize_list_element(ostream& out,
+                                                        t_list* tlist,
+                                                        string prefix) {
+  // A list is represented by a table indexed by integer values
+  // LUA natively provides all of the functions required to maintain a list
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  generate_deserialize_field(out, &felem, true);
+
+  indent(out) << "table.insert(" << prefix << ", " << elem << ")" << endl;
+}
+
+/**
+ * Serialize (Write)
+ */
+void t_lua_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+  string name = prefix + 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);
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) << "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(" << name << ")";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ")";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "writeByte(" << name << ")";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16(" << name << ")";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32(" << name << ")";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64(" << name << ")";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble(" << 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(" << name << ")";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
+           name.c_str(),
+           type->get_name().c_str());
+  }
+}
+
+void t_lua_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  (void)tstruct;
+  indent(out) << prefix << ":write(oprot)" << endl;
+}
+
+void t_lua_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  // Begin writing
+  if (ttype->is_map()) {
+    indent(out) << "oprot:writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", "
+                << type_to_enum(((t_map*)ttype)->get_val_type()) << ", "
+                << "ttable_size(" << prefix << "))" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot:writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", "
+                << "ttable_size(" << prefix << "))" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot:writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type())
+                << ", "
+                << "#" << prefix << ")" << endl;
+  }
+
+  // Serialize
+  if (ttype->is_map()) {
+    string kiter = tmp("kiter");
+    string viter = tmp("viter");
+    indent(out) << "for " << kiter << "," << viter << " in pairs(" << prefix << ") do" << endl;
+    indent_up();
+    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
+    indent_down();
+    indent(out) << "end" << endl;
+  } else if (ttype->is_set()) {
+    string iter = tmp("iter");
+    indent(out) << "for " << iter << ",_ in pairs(" << prefix << ") do" << endl;
+    indent_up();
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+    indent_down();
+    indent(out) << "end" << endl;
+  } else if (ttype->is_list()) {
+    string iter = tmp("iter");
+    indent(out) << "for _," << iter << " in ipairs(" << prefix << ") do" << endl;
+    indent_up();
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+    indent_down();
+    indent(out) << "end" << endl;
+  }
+
+  // Finish writing
+  if (ttype->is_map()) {
+    indent(out) << "oprot:writeMapEnd()" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot:writeSetEnd()" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot:writeListEnd()" << endl;
+  }
+}
+
+void t_lua_generator::generate_serialize_map_element(ostream& out,
+                                                     t_map* tmap,
+                                                     string kiter,
+                                                     string viter) {
+  t_field kfield(tmap->get_key_type(), kiter);
+  generate_serialize_field(out, &kfield, "");
+
+  t_field vfield(tmap->get_val_type(), viter);
+  generate_serialize_field(out, &vfield, "");
+}
+
+void t_lua_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+void t_lua_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ *  Helper rendering functions
+ */
+string t_lua_generator::lua_includes() {
+  if (gen_requires_) {
+    return "\n\nrequire 'Thrift'";
+  } else {
+    return "";
+  }
+}
+
+string t_lua_generator::get_namespace(const t_program* program) {
+  std::string real_module = program->get_namespace("lua");
+  if (real_module.empty()) {
+    return program->get_name() + "_";
+  }
+  return real_module + "_";
+}
+
+string t_lua_generator::function_signature(t_function* tfunction, string prefix) {
+  (void)prefix;
+  std::string ret = tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")";
+  return ret;
+}
+
+string t_lua_generator::argument_list(t_struct* tstruct, string prefix) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator fld_iter;
+  std::string ret = "";
+  for (fld_iter = fields.begin(); fld_iter != fields.end();) {
+    ret += prefix + (*fld_iter)->get_name();
+    ++fld_iter;
+    if (fld_iter != fields.end()) {
+      ret += ", ";
+    }
+  }
+  return ret;
+}
+
+string t_lua_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 "TType.STRING";
+    case t_base_type::TYPE_BOOL:
+      return "TType.BOOL";
+    case t_base_type::TYPE_I8:
+      return "TType.BYTE";
+    case t_base_type::TYPE_I16:
+      return "TType.I16";
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "TType.DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.STRUCT";
+  } else if (type->is_map()) {
+    return "TType.MAP";
+  } else if (type->is_set()) {
+    return "TType.SET";
+  } else if (type->is_list()) {
+    return "TType.LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(
+    lua,
+    "Lua",
+    "    omit_requires:   Suppress generation of require 'somefile'.\n")
diff --git a/compiler/cpp/src/thrift/generate/t_netcore_generator.cc b/compiler/cpp/src/thrift/generate/t_netcore_generator.cc
new file mode 100644
index 0000000..d2e7da0
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_netcore_generator.cc
@@ -0,0 +1,3117 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+#include <cassert>
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <cctype>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+#include "thrift/generate/t_netcore_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+//TODO: check for indentation
+//TODO: Do we need seqId_ in generation?
+
+t_netcore_generator::t_netcore_generator(t_program* program, const map<string, string>& parsed_options, const string& option_string)
+    : t_oop_generator(program)
+{
+    (void)option_string;
+
+    nullable_ = false;
+    hashcode_ = false;
+    union_ = false;
+    serialize_ = false;
+    wcf_ = false;
+    wcf_namespace_.clear();
+
+    map<string, string>::const_iterator iter;
+
+    for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter)
+    {
+        if (iter->first.compare("nullable") == 0)
+        {
+            nullable_ = true;
+        }
+        else if (iter->first.compare("hashcode") == 0)
+        {
+            hashcode_ = true;
+        }
+        else if (iter->first.compare("union") == 0)
+        {
+            union_ = true;
+        }
+        else if (iter->first.compare("serial") == 0)
+        {
+            serialize_ = true;
+            wcf_namespace_ = iter->second; // since there can be only one namespace
+        }
+        else if (iter->first.compare("wcf") == 0)
+        {
+            wcf_ = true;
+            wcf_namespace_ = iter->second;
+        }
+        else
+        {
+            throw "unknown option netcore:" + iter->first;
+        }
+    }
+
+    out_dir_base_ = "gen-netcore";
+}
+
+static string correct_function_name_for_async(string const& function_name)
+{
+    string const async_end = "Async";
+    size_t i = function_name.find(async_end);
+    if (i != string::npos)
+    {
+        return function_name + async_end;
+    }
+
+    return function_name;
+}
+
+/**
+* \brief Search and replace "_args" substring in struct name if exist (for C# class naming)
+* \param struct_name
+* \return Modified struct name ("Struct_args" -> "StructArgs") or original name
+*/
+static string check_and_correct_struct_name(const string& struct_name)
+{
+    string args_end = "_args";
+    size_t i = struct_name.find(args_end);
+    if (i != string::npos)
+    {
+        string new_struct_name = struct_name;
+        new_struct_name.replace(i, args_end.length(), "Args");
+        return new_struct_name;
+    }
+
+    string result_end = "_result";
+    size_t j = struct_name.find(result_end);
+    if (j != string::npos)
+    {
+        string new_struct_name = struct_name;
+        new_struct_name.replace(j, result_end.length(), "Result");
+        return new_struct_name;
+    }
+
+    return struct_name;
+}
+
+static bool field_has_default(t_field* tfield) { return tfield->get_value() != NULL; }
+
+static bool field_is_required(t_field* tfield) { return tfield->get_req() == t_field::T_REQUIRED; }
+
+static bool type_can_be_null(t_type* ttype)
+{
+    while (ttype->is_typedef())
+    {
+        ttype = static_cast<t_typedef*>(ttype)->get_type();
+    }
+
+    return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string();
+}
+
+bool t_netcore_generator::is_wcf_enabled() const { return wcf_; }
+
+bool t_netcore_generator::is_nullable_enabled() const { return nullable_; }
+
+bool t_netcore_generator::is_hashcode_enabled() const { return hashcode_; }
+
+bool t_netcore_generator::is_serialize_enabled() const { return serialize_; }
+
+bool t_netcore_generator::is_union_enabled() const { return union_; }
+
+map<string, int> t_netcore_generator::get_keywords_list() const
+{
+    return netcore_keywords;
+}
+
+void t_netcore_generator::init_generator()
+{
+    MKDIR(get_out_dir().c_str());
+
+    // for usage of csharp namespaces in thrift files (from files for csharp)
+    namespace_name_ = program_->get_namespace("netcore");
+    if (namespace_name_.empty())
+    {
+        namespace_name_ = program_->get_namespace("netcore");
+    }
+
+    string dir = namespace_name_;
+    string subdir = get_out_dir().c_str();
+    string::size_type loc;
+
+    while ((loc = dir.find(".")) != string::npos)
+    {
+        subdir = subdir + "/" + dir.substr(0, loc);
+        MKDIR(subdir.c_str());
+        dir = dir.substr(loc + 1);
+    }
+    if (dir.size() > 0)
+    {
+        subdir = subdir + "/" + dir;
+        MKDIR(subdir.c_str());
+    }
+
+    namespace_dir_ = subdir;
+    init_keywords();
+
+    while (!member_mapping_scopes.empty())
+    {
+        cleanup_member_name_mapping(member_mapping_scopes.back().scope_member);
+    }
+
+    pverbose(".NET Core options:\n");
+    pverbose("- nullable ... %s\n", (nullable_ ? "ON" : "off"));
+    pverbose("- union ...... %s\n", (union_ ? "ON" : "off"));
+    pverbose("- hashcode ... %s\n", (hashcode_ ? "ON" : "off"));
+    pverbose("- serialize .. %s\n", (serialize_ ? "ON" : "off"));
+    pverbose("- wcf ........ %s\n", (wcf_ ? "ON" : "off"));
+}
+
+string t_netcore_generator::normalize_name(string name)
+{
+    string tmp(name);
+    transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast<int(*)(int)>(tolower));
+
+    // un-conflict keywords by prefixing with "@"
+    if (netcore_keywords.find(tmp) != netcore_keywords.end())
+    {
+        return "@" + name;
+    }
+
+    // no changes necessary
+    return name;
+}
+
+void t_netcore_generator::init_keywords()
+{
+    netcore_keywords.clear();
+
+    // C# keywords
+    netcore_keywords["abstract"] = 1;
+    netcore_keywords["as"] = 1;
+    netcore_keywords["base"] = 1;
+    netcore_keywords["bool"] = 1;
+    netcore_keywords["break"] = 1;
+    netcore_keywords["byte"] = 1;
+    netcore_keywords["case"] = 1;
+    netcore_keywords["catch"] = 1;
+    netcore_keywords["char"] = 1;
+    netcore_keywords["checked"] = 1;
+    netcore_keywords["class"] = 1;
+    netcore_keywords["const"] = 1;
+    netcore_keywords["continue"] = 1;
+    netcore_keywords["decimal"] = 1;
+    netcore_keywords["default"] = 1;
+    netcore_keywords["delegate"] = 1;
+    netcore_keywords["do"] = 1;
+    netcore_keywords["double"] = 1;
+    netcore_keywords["else"] = 1;
+    netcore_keywords["enum"] = 1;
+    netcore_keywords["event"] = 1;
+    netcore_keywords["explicit"] = 1;
+    netcore_keywords["extern"] = 1;
+    netcore_keywords["false"] = 1;
+    netcore_keywords["finally"] = 1;
+    netcore_keywords["fixed"] = 1;
+    netcore_keywords["float"] = 1;
+    netcore_keywords["for"] = 1;
+    netcore_keywords["foreach"] = 1;
+    netcore_keywords["goto"] = 1;
+    netcore_keywords["if"] = 1;
+    netcore_keywords["implicit"] = 1;
+    netcore_keywords["in"] = 1;
+    netcore_keywords["int"] = 1;
+    netcore_keywords["interface"] = 1;
+    netcore_keywords["internal"] = 1;
+    netcore_keywords["is"] = 1;
+    netcore_keywords["lock"] = 1;
+    netcore_keywords["long"] = 1;
+    netcore_keywords["namespace"] = 1;
+    netcore_keywords["new"] = 1;
+    netcore_keywords["null"] = 1;
+    netcore_keywords["object"] = 1;
+    netcore_keywords["operator"] = 1;
+    netcore_keywords["out"] = 1;
+    netcore_keywords["override"] = 1;
+    netcore_keywords["params"] = 1;
+    netcore_keywords["private"] = 1;
+    netcore_keywords["protected"] = 1;
+    netcore_keywords["public"] = 1;
+    netcore_keywords["readonly"] = 1;
+    netcore_keywords["ref"] = 1;
+    netcore_keywords["return"] = 1;
+    netcore_keywords["sbyte"] = 1;
+    netcore_keywords["sealed"] = 1;
+    netcore_keywords["short"] = 1;
+    netcore_keywords["sizeof"] = 1;
+    netcore_keywords["stackalloc"] = 1;
+    netcore_keywords["static"] = 1;
+    netcore_keywords["string"] = 1;
+    netcore_keywords["struct"] = 1;
+    netcore_keywords["switch"] = 1;
+    netcore_keywords["this"] = 1;
+    netcore_keywords["throw"] = 1;
+    netcore_keywords["true"] = 1;
+    netcore_keywords["try"] = 1;
+    netcore_keywords["typeof"] = 1;
+    netcore_keywords["uint"] = 1;
+    netcore_keywords["ulong"] = 1;
+    netcore_keywords["unchecked"] = 1;
+    netcore_keywords["unsafe"] = 1;
+    netcore_keywords["ushort"] = 1;
+    netcore_keywords["using"] = 1;
+    netcore_keywords["virtual"] = 1;
+    netcore_keywords["void"] = 1;
+    netcore_keywords["volatile"] = 1;
+    netcore_keywords["while"] = 1;
+
+    // C# contextual keywords
+    netcore_keywords["add"] = 1;
+    netcore_keywords["alias"] = 1;
+    netcore_keywords["ascending"] = 1;
+    netcore_keywords["async"] = 1;
+    netcore_keywords["await"] = 1;
+    netcore_keywords["descending"] = 1;
+    netcore_keywords["dynamic"] = 1;
+    netcore_keywords["from"] = 1;
+    netcore_keywords["get"] = 1;
+    netcore_keywords["global"] = 1;
+    netcore_keywords["group"] = 1;
+    netcore_keywords["into"] = 1;
+    netcore_keywords["join"] = 1;
+    netcore_keywords["let"] = 1;
+    netcore_keywords["orderby"] = 1;
+    netcore_keywords["partial"] = 1;
+    netcore_keywords["remove"] = 1;
+    netcore_keywords["select"] = 1;
+    netcore_keywords["set"] = 1;
+    netcore_keywords["value"] = 1;
+    netcore_keywords["var"] = 1;
+    netcore_keywords["where"] = 1;
+    netcore_keywords["yield"] = 1;
+
+	netcore_keywords["when"] = 1;
+}
+
+void t_netcore_generator::start_netcore_namespace(ostream& out)
+{
+    if (!namespace_name_.empty())
+    {
+        out << "namespace " << namespace_name_ << endl;
+        scope_up(out);
+    }
+}
+
+void t_netcore_generator::end_netcore_namespace(ostream& out)
+{
+    if (!namespace_name_.empty())
+    {
+        scope_down(out);
+    }
+}
+
+string t_netcore_generator::netcore_type_usings() const
+{
+    string namespaces =
+        "using System;\n"
+        "using System.Collections;\n"
+        "using System.Collections.Generic;\n"
+        "using System.Text;\n"
+        "using System.IO;\n"
+        "using System.Threading;\n"
+        "using System.Threading.Tasks;\n"
+        "using Thrift;\n"
+        "using Thrift.Collections;\n";
+
+    if (wcf_)
+    {
+        namespaces += "using System.ServiceModel;\n";
+        namespaces += "using System.Runtime.Serialization;\n";
+    }
+
+    return namespaces + endl;
+}
+
+string t_netcore_generator::netcore_thrift_usings() const
+{
+    string namespaces =
+        "using Thrift.Protocols;\n"
+        "using Thrift.Protocols.Entities;\n"
+        "using Thrift.Protocols.Utilities;\n"
+        "using Thrift.Transports;\n"
+        "using Thrift.Transports.Client;\n"
+        "using Thrift.Transports.Server;\n";
+
+    return namespaces + endl;
+}
+
+void t_netcore_generator::close_generator()
+{
+}
+
+void t_netcore_generator::generate_typedef(t_typedef* ttypedef)
+{
+    (void)ttypedef;
+}
+
+void t_netcore_generator::generate_enum(t_enum* tenum)
+{
+	int ic = indent_count();
+    string f_enum_name = namespace_dir_ + "/" + tenum->get_name() + ".cs";
+
+    ofstream_with_content_based_conditional_update f_enum;
+    f_enum.open(f_enum_name.c_str());
+
+	generate_enum(f_enum, tenum);
+
+    f_enum.close();
+	indent_validate(ic, "generate_enum");
+}
+
+void t_netcore_generator::generate_enum(ostream& out, t_enum* tenum)
+{
+	out << autogen_comment() << endl;
+
+	start_netcore_namespace(out);
+	generate_netcore_doc(out, tenum);
+
+	out << indent() << "public enum " << tenum->get_name() << endl;
+	scope_up(out);
+
+	vector<t_enum_value*> constants = tenum->get_constants();
+	vector<t_enum_value*>::iterator c_iter;
+
+	for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter)
+	{
+		generate_netcore_doc(out, *c_iter);
+		int value = (*c_iter)->get_value();
+		out << indent() << (*c_iter)->get_name() << " = " << value << "," << endl;
+	}
+
+	scope_down(out);
+	end_netcore_namespace(out);
+}
+
+void t_netcore_generator::generate_consts(vector<t_const*> consts)
+{
+    if (consts.empty())
+    {
+        return;
+    }
+
+    string f_consts_name = namespace_dir_ + '/' + program_name_ + ".Constants.cs";
+    ofstream_with_content_based_conditional_update f_consts;
+    f_consts.open(f_consts_name.c_str());
+
+    generate_consts(f_consts, consts);
+
+    f_consts.close();
+}
+
+void t_netcore_generator::generate_consts(ostream& out, vector<t_const*> consts)
+{
+    if (consts.empty())
+    {
+        return;
+    }
+
+    out << autogen_comment() << netcore_type_usings() << endl;
+
+    start_netcore_namespace(out);
+
+    out << indent() << "public static class " << make_valid_csharp_identifier(program_name_) << "Constants" << endl;
+
+    scope_up(out);
+
+    vector<t_const*>::iterator c_iter;
+    bool need_static_constructor = false;
+    for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter)
+    {
+        generate_netcore_doc(out, *c_iter);
+        if (print_const_value(out, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value(), false))
+        {
+            need_static_constructor = true;
+        }
+    }
+
+    if (need_static_constructor)
+    {
+        print_const_constructor(out, consts);
+    }
+
+    scope_down(out);
+    end_netcore_namespace(out);
+}
+
+void t_netcore_generator::print_const_def_value(ostream& out, string name, t_type* type, t_const_value* value)
+{
+    if (type->is_struct() || type->is_xception())
+    {
+        const vector<t_field*>& fields = static_cast<t_struct*>(type)->get_members();
+        const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+        vector<t_field*>::const_iterator f_iter;
+        map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+        prepare_member_name_mapping(static_cast<t_struct*>(type));
+
+        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter)
+        {
+            t_field* field = NULL;
+
+            for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+            {
+                if ((*f_iter)->get_name() == v_iter->first->get_string())
+                {
+                    field = *f_iter;
+                }
+            }
+
+            if (field == NULL)
+            {
+                throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+            }
+
+            t_type* field_type = field->get_type();
+
+            string val = render_const_value(out, name, field_type, v_iter->second);
+            out << indent() << name << "." << prop_name(field) << " = " << val << ";" << endl;
+        }
+
+        cleanup_member_name_mapping(static_cast<t_struct*>(type));
+    }
+    else if (type->is_map())
+    {
+        t_type* ktype = static_cast<t_map*>(type)->get_key_type();
+        t_type* vtype = static_cast<t_map*>(type)->get_val_type();
+        const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+        map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter)
+        {
+            string key = render_const_value(out, name, ktype, v_iter->first);
+            string val = render_const_value(out, name, vtype, v_iter->second);
+            out << indent() << name << "[" << key << "]" << " = " << val << ";" << endl;
+        }
+    }
+    else if (type->is_list() || type->is_set())
+    {
+        t_type* etype;
+        if (type->is_list())
+        {
+            etype = static_cast<t_list*>(type)->get_elem_type();
+        }
+        else
+        {
+            etype = static_cast<t_set*>(type)->get_elem_type();
+        }
+
+        const vector<t_const_value*>& val = value->get_list();
+        vector<t_const_value*>::const_iterator v_iter;
+        for (v_iter = val.begin(); v_iter != val.end(); ++v_iter)
+        {
+            string val = render_const_value(out, name, etype, *v_iter);
+            out << indent() << name << ".Add(" << val << ");" << endl;
+        }
+    }
+}
+
+void t_netcore_generator::print_const_constructor(ostream& out, vector<t_const*> consts)
+{
+    out << indent() << "static " << make_valid_csharp_identifier(program_name_).c_str() << "Constants()" << endl;
+    scope_up(out);
+
+    vector<t_const*>::iterator c_iter;
+    for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter)
+    {
+        string name = (*c_iter)->get_name();
+        t_type* type = (*c_iter)->get_type();
+        t_const_value* value = (*c_iter)->get_value();
+
+        print_const_def_value(out, name, type, value);
+    }
+    scope_down(out);
+}
+
+bool t_netcore_generator::print_const_value(ostream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval, bool needtype)
+{
+    out << indent();
+    bool need_static_construction = !in_static;
+    while (type->is_typedef())
+    {
+        type = static_cast<t_typedef*>(type)->get_type();
+    }
+
+    if (!defval || needtype)
+    {
+        out << (in_static ? "" : type->is_base_type() ? "public const " : "public static ") << type_name(type) << " ";
+    }
+
+    if (type->is_base_type())
+    {
+        string v2 = render_const_value(out, name, type, value);
+        out << normalize_name(name) << " = " << v2 << ";" << endl;
+        need_static_construction = false;
+    }
+    else if (type->is_enum())
+    {
+        out << name << " = " << type_name(type, false, true) << "." << value->get_identifier_name() << ";" << endl;
+        need_static_construction = false;
+    }
+    else if (type->is_struct() || type->is_xception())
+    {
+        out << name << " = new " << type_name(type) << "();" << endl;
+    }
+    else if (type->is_map())
+    {
+        out << name << " = new " << type_name(type, true, true) << "();" << endl;
+    }
+    else if (type->is_list() || type->is_set())
+    {
+        out << name << " = new " << type_name(type) << "();" << endl;
+    }
+
+    if (defval && !type->is_base_type() && !type->is_enum())
+    {
+        print_const_def_value(out, name, type, value);
+    }
+
+    return need_static_construction;
+}
+
+string t_netcore_generator::render_const_value(ostream& out, string name, t_type* type, t_const_value* value)
+{
+    (void)name;
+    ostringstream render;
+
+    if (type->is_base_type())
+    {
+        t_base_type::t_base tbase = static_cast<t_base_type*>(type)->get_base();
+        switch (tbase)
+        {
+        case t_base_type::TYPE_STRING:
+            render << '"' << get_escaped_string(value) << '"';
+            break;
+        case t_base_type::TYPE_BOOL:
+            render << ((value->get_integer() > 0) ? "true" : "false");
+            break;
+        case t_base_type::TYPE_I8:
+        case t_base_type::TYPE_I16:
+        case t_base_type::TYPE_I32:
+        case t_base_type::TYPE_I64:
+            render << value->get_integer();
+            break;
+        case t_base_type::TYPE_DOUBLE:
+            if (value->get_type() == t_const_value::CV_INTEGER)
+            {
+                render << value->get_integer();
+            }
+            else
+            {
+                render << 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())
+    {
+        render << type->get_name() << "." << value->get_identifier_name();
+    }
+    else
+    {
+        string t = tmp("tmp");
+        print_const_value(out, t, type, value, true, true, true);
+        render << t;
+    }
+
+    return render.str();
+}
+
+void t_netcore_generator::generate_struct(t_struct* tstruct)
+{
+    if (union_ && tstruct->is_union())
+    {
+        generate_netcore_union(tstruct);
+    }
+    else
+    {
+        generate_netcore_struct(tstruct, false);
+    }
+}
+
+void t_netcore_generator::generate_xception(t_struct* txception)
+{
+    generate_netcore_struct(txception, true);
+}
+
+void t_netcore_generator::generate_netcore_struct(t_struct* tstruct, bool is_exception)
+{
+    int ic = indent_count();
+
+    string f_struct_name = namespace_dir_ + "/" + (tstruct->get_name()) + ".cs";
+    ofstream_with_content_based_conditional_update f_struct;
+
+    f_struct.open(f_struct_name.c_str());
+
+    f_struct << autogen_comment() << netcore_type_usings() << netcore_thrift_usings() << endl;
+
+    generate_netcore_struct_definition(f_struct, tstruct, is_exception);
+
+    f_struct.close();
+
+    indent_validate(ic, "generate_netcore_struct");
+}
+
+void t_netcore_generator::generate_netcore_struct_definition(ostream& out, t_struct* tstruct, bool is_exception, bool in_class, bool is_result)
+{
+    if (!in_class)
+    {
+        start_netcore_namespace(out);
+    }
+
+    out << endl;
+
+    generate_netcore_doc(out, tstruct);
+    prepare_member_name_mapping(tstruct);
+
+    if ((serialize_ || wcf_) && !is_exception)
+    {
+        out << indent() << "[DataContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
+    }
+
+    bool is_final = tstruct->annotations_.find("final") != tstruct->annotations_.end();
+
+    string sharp_struct_name = check_and_correct_struct_name(normalize_name(tstruct->get_name()));
+
+    out << indent() << "public " << (is_final ? "sealed " : "") << "partial class " << sharp_struct_name << " : ";
+
+    if (is_exception)
+    {
+        out << "TException, ";
+    }
+
+    out << "TBase" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    const vector<t_field*>& members = tstruct->get_members();
+    vector<t_field*>::const_iterator m_iter;
+
+    // make private members with public Properties
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
+    {
+        // if the field is requied, then we use auto-properties
+        if (!field_is_required((*m_iter)) && (!nullable_ || field_has_default((*m_iter))))
+        {
+            out << indent() << "private " << declare_field(*m_iter, false, "_") << endl;
+        }
+    }
+    out << endl;
+
+    bool has_non_required_fields = false;
+    bool has_non_required_default_value_fields = false;
+    bool has_required_fields = false;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
+    {
+        generate_netcore_doc(out, *m_iter);
+        generate_property(out, *m_iter, true, true);
+        bool is_required = field_is_required((*m_iter));
+        bool has_default = field_has_default((*m_iter));
+        if (is_required)
+        {
+            has_required_fields = true;
+        }
+        else
+        {
+            if (has_default)
+            {
+                has_non_required_default_value_fields = true;
+            }
+            has_non_required_fields = true;
+        }
+    }
+
+    bool generate_isset = (nullable_ && has_non_required_default_value_fields) || (!nullable_ && has_non_required_fields);
+    if (generate_isset)
+    {
+        out << endl;
+        if (serialize_ || wcf_)
+        {
+            out << indent() << "[DataMember(Order = 1)]" << endl;
+        }
+        out << indent() << "public Isset __isset;" << endl;
+        if (serialize_ || wcf_)
+        {
+            out << indent() << "[DataContract]" << endl;
+        }
+
+        out << indent() << "public struct Isset" << endl
+            << indent() << "{" << endl;
+        indent_up();
+
+        for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
+        {
+            bool is_required = field_is_required((*m_iter));
+            bool has_default = field_has_default((*m_iter));
+            // if it is required, don't need Isset for that variable
+            // if it is not required, if it has a default value, we need to generate Isset
+            // if we are not nullable, then we generate Isset
+            if (!is_required && (!nullable_ || has_default))
+            {
+                if (serialize_ || wcf_)
+                {
+                    out << indent() << "[DataMember]" << endl;
+                }
+                out << indent() << "public bool " << normalize_name((*m_iter)->get_name()) << ";" << endl;
+            }
+        }
+
+        indent_down();
+        out << indent() << "}" << endl << endl;
+
+        if (generate_isset && (serialize_ || wcf_))
+        {
+            out << indent() << "#region XmlSerializer support" << endl << endl;
+
+            for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
+            {
+                bool is_required = field_is_required(*m_iter);
+                bool has_default = field_has_default(*m_iter);
+                // if it is required, don't need Isset for that variable
+                // if it is not required, if it has a default value, we need to generate Isset
+                // if we are not nullable, then we generate Isset
+                if (!is_required && (!nullable_ || has_default))
+                {
+                    out << indent() << "public bool ShouldSerialize" << prop_name(*m_iter) << "()" << endl
+                        << indent() << "{" << endl;
+                    indent_up();
+                    out << indent() << "return __isset." << normalize_name((*m_iter)->get_name()) << ";" << endl;
+                    indent_down();
+                    out << indent() << "}" << endl << endl;
+                }
+            }
+
+            out << indent() << "#endregion XmlSerializer support" << endl << endl;
+        }
+    }
+
+    // We always want a default, no argument constructor for Reading
+    out << indent() << "public " << sharp_struct_name << "()" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
+    {
+        t_type* t = (*m_iter)->get_type();
+        while (t->is_typedef())
+        {
+            t = static_cast<t_typedef*>(t)->get_type();
+        }
+        if ((*m_iter)->get_value() != NULL)
+        {
+            if (field_is_required((*m_iter)))
+            {
+                print_const_value(out, "this." + prop_name(*m_iter), t, (*m_iter)->get_value(), true, true);
+            }
+            else
+            {
+                print_const_value(out, "this._" + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true);
+                // Optionals with defaults are marked set
+                out << indent() << "this.__isset." << normalize_name((*m_iter)->get_name()) << " = true;" << endl;
+            }
+        }
+    }
+    indent_down();
+    out << indent() << "}" << endl << endl;
+
+    if (has_required_fields)
+    {
+        out << indent() << "public " << sharp_struct_name << "(";
+        bool first = true;
+        for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
+        {
+            if (field_is_required(*m_iter))
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    out << ", ";
+                }
+                out << type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name();
+            }
+        }
+        out << ") : this()" << endl
+            << indent() << "{" << endl;
+        indent_up();
+
+        for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
+        {
+            if (field_is_required(*m_iter))
+            {
+                out << indent() << "this." << prop_name(*m_iter) << " = " << (*m_iter)->get_name() << ";" << endl;
+            }
+        }
+
+        indent_down();
+        out << indent() << "}" << endl << endl;
+    }
+
+    generate_netcore_struct_reader(out, tstruct);
+    if (is_result)
+    {
+        generate_netcore_struct_result_writer(out, tstruct);
+    }
+    else
+    {
+        generate_netcore_struct_writer(out, tstruct);
+    }
+    if (hashcode_)
+    {
+        generate_netcore_struct_equals(out, tstruct);
+        generate_netcore_struct_hashcode(out, tstruct);
+    }
+    generate_netcore_struct_tostring(out, tstruct);
+
+    indent_down();
+    out << indent() << "}" << endl << endl;
+
+    // generate a corresponding WCF fault to wrap the exception
+    if ((serialize_ || wcf_) && is_exception)
+    {
+        generate_netcore_wcffault(out, tstruct);
+    }
+
+    cleanup_member_name_mapping(tstruct);
+    if (!in_class)
+    {
+        end_netcore_namespace(out);
+    }
+}
+
+void t_netcore_generator::generate_netcore_wcffault(ostream& out, t_struct* tstruct)
+{
+    out << endl;
+    out << indent() << "[DataContract]" << endl;
+
+    bool is_final = tstruct->annotations_.find("final") != tstruct->annotations_.end();
+
+    out << indent() << "public " << (is_final ? "sealed " : "") << "partial class " << tstruct->get_name() << "Fault" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    const vector<t_field*>& members = tstruct->get_members();
+    vector<t_field*>::const_iterator m_iter;
+
+    // make private members with public Properties
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
+    {
+        out << indent() << "private " << declare_field(*m_iter, false, "_") << endl;
+    }
+    out << endl;
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
+    {
+        generate_property(out, *m_iter, true, false);
+    }
+
+    indent_down();
+    out << indent() << "}" << endl << endl;
+}
+
+void t_netcore_generator::generate_netcore_struct_reader(ostream& out, t_struct* tstruct)
+{
+    out << indent() << "public async Task ReadAsync(TProtocol iprot, CancellationToken cancellationToken)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "iprot.IncrementRecursionDepth();" << endl
+        << indent() << "try" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    const vector<t_field*>& fields = tstruct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    // Required variables aren't in __isset, so we need tmp vars to check them
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+    {
+        if (field_is_required(*f_iter))
+        {
+            out << indent() << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
+        }
+    }
+
+    out << indent() << "TField field;" << endl
+        << indent() << "await iprot.ReadStructBeginAsync(cancellationToken);" << endl
+        << indent() << "while (true)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "field = await iprot.ReadFieldBeginAsync(cancellationToken);" << endl
+        << indent() << "if (field.Type == TType.Stop)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "break;" << endl;
+    indent_down();
+    out << indent() << "}" << endl << endl
+        << indent() << "switch (field.ID)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+    {
+        bool is_required = field_is_required(*f_iter);
+        out << indent() << "case " << (*f_iter)->get_key() << ":" << endl;
+        indent_up();
+        out << indent() << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ")" << endl
+            << indent() << "{" << endl;
+        indent_up();
+
+        generate_deserialize_field(out, *f_iter);
+        if (is_required)
+        {
+            out << indent() << "isset_" << (*f_iter)->get_name() << " = true;" << endl;
+        }
+
+        indent_down();
+        out << indent() << "}" << endl
+            << indent() << "else" << endl
+            << indent() << "{" << endl;
+        indent_up();
+        out << indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);" << endl;
+        indent_down();
+        out << indent() << "}" << endl
+            << indent() << "break;" << endl;
+        indent_down();
+    }
+
+    out << indent() << "default: " << endl;
+    indent_up();
+    out << indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);" << endl
+        << indent() << "break;" << endl;
+    indent_down();
+    indent_down();
+    out << indent() << "}" << endl
+        << endl
+        << indent() << "await iprot.ReadFieldEndAsync(cancellationToken);" << endl;
+    indent_down();
+    out << indent() << "}" << endl
+        << endl
+        << indent() << "await iprot.ReadStructEndAsync(cancellationToken);" << endl;
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+    {
+        if (field_is_required((*f_iter)))
+        {
+            out << indent() << "if (!isset_" << (*f_iter)->get_name() << ")" << endl
+                << indent() << "{" << endl;
+            indent_up();
+            out << indent() << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl;
+            indent_down();
+            out << indent() << "}" << endl;
+        }
+    }
+
+    indent_down();
+    out << indent() << "}" << endl;
+    out << indent() << "finally" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "iprot.DecrementRecursionDepth();" << endl;
+    indent_down();
+    out << indent() << "}" << endl;
+    indent_down();
+    out << indent() << "}" << endl << endl;
+}
+
+void t_netcore_generator::generate_netcore_struct_writer(ostream& out, t_struct* tstruct)
+{
+    out << indent() << "public async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    out << indent() << "oprot.IncrementRecursionDepth();" << endl
+        << indent() << "try" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    string name = tstruct->get_name();
+    const vector<t_field*>& fields = tstruct->get_sorted_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    out << indent() << "var struc = new TStruct(\"" << name << "\");" << endl
+        << indent() << "await oprot.WriteStructBeginAsync(struc, cancellationToken);" << endl;
+
+    if (fields.size() > 0)
+    {
+        out << indent() << "var field = new TField();" << endl;
+        for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+        {
+            bool is_required = field_is_required(*f_iter);
+            bool has_default = field_has_default(*f_iter);
+            if (nullable_ && !has_default && !is_required)
+            {
+                out << indent() << "if (" << prop_name(*f_iter) << " != null)" << endl
+                    << indent() << "{" << endl;
+                indent_up();
+            }
+            else if (!is_required)
+            {
+                bool null_allowed = type_can_be_null((*f_iter)->get_type());
+                if (null_allowed)
+                {
+                    out << indent() << "if (" << prop_name(*f_iter) << " != null && __isset." << normalize_name((*f_iter)->get_name()) << ")" << endl
+                        << indent() << "{" << endl;
+                    indent_up();
+                }
+                else
+                {
+                    out << indent() << "if (__isset." << normalize_name((*f_iter)->get_name()) << ")" << endl
+                        << indent() << "{" << endl;
+                    indent_up();
+                }
+            }
+            out << indent() << "field.Name = \"" << (*f_iter)->get_name() << "\";" << endl
+                << indent() << "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl
+                << indent() << "field.ID = " << (*f_iter)->get_key() << ";" << endl
+                << indent() << "await oprot.WriteFieldBeginAsync(field, cancellationToken);" << endl;
+
+            generate_serialize_field(out, *f_iter);
+
+            out << indent() << "await oprot.WriteFieldEndAsync(cancellationToken);" << endl;
+            if (!is_required)
+            {
+                indent_down();
+                out << indent() << "}" << endl;
+            }
+        }
+    }
+
+    out << indent() << "await oprot.WriteFieldStopAsync(cancellationToken);" << endl
+        << indent() << "await oprot.WriteStructEndAsync(cancellationToken);" << endl;
+    indent_down();
+    out << indent() << "}" << endl
+        << indent() << "finally" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "oprot.DecrementRecursionDepth();" << endl;
+    indent_down();
+    out << indent() << "}" << endl;
+    indent_down();
+    out << indent() << "}" << endl << endl;
+}
+
+void t_netcore_generator::generate_netcore_struct_result_writer(ostream& out, t_struct* tstruct)
+{
+    out << indent() << "public async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    out << indent() << "oprot.IncrementRecursionDepth();" << endl
+        << indent() << "try" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    string name = tstruct->get_name();
+    const vector<t_field*>& fields = tstruct->get_sorted_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    out << indent() << "var struc = new TStruct(\"" << name << "\");" << endl
+        << indent() << "await oprot.WriteStructBeginAsync(struc, cancellationToken);" << endl;
+
+    if (fields.size() > 0)
+    {
+        out << indent() << "var field = new TField();" << endl;
+        bool first = true;
+        for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+        {
+            if (first)
+            {
+                first = false;
+                out << endl << indent() << "if";
+            }
+            else
+            {
+                out << indent() << "else if";
+            }
+
+            if (nullable_)
+            {
+                out << "(this." << prop_name((*f_iter)) << " != null)" << endl
+                    << indent() << "{" << endl;
+            }
+            else
+            {
+                out << "(this.__isset." << normalize_name((*f_iter)->get_name()) << ")" << endl
+                    << indent() << "{" << endl;
+            }
+            indent_up();
+
+            bool null_allowed = !nullable_ && type_can_be_null((*f_iter)->get_type());
+            if (null_allowed)
+            {
+                out << indent() << "if (" << prop_name(*f_iter) << " != null)" << endl
+                    << indent() << "{" << endl;
+                indent_up();
+            }
+
+            out << indent() << "field.Name = \"" << prop_name(*f_iter) << "\";" << endl
+                << indent() << "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl
+                << indent() << "field.ID = " << (*f_iter)->get_key() << ";" << endl
+                << indent() << "await oprot.WriteFieldBeginAsync(field, cancellationToken);" << endl;
+
+            generate_serialize_field(out, *f_iter);
+
+            out << indent() << "await oprot.WriteFieldEndAsync(cancellationToken);" << endl;
+
+            if (null_allowed)
+            {
+                indent_down();
+                out << indent() << "}" << endl;
+            }
+
+            indent_down();
+            out << indent() << "}" << endl;
+        }
+    }
+
+    out << indent() << "await oprot.WriteFieldStopAsync(cancellationToken);" << endl
+        << indent() << "await oprot.WriteStructEndAsync(cancellationToken);" << endl;
+    indent_down();
+    out << indent() << "}" << endl
+        << indent() << "finally" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "oprot.DecrementRecursionDepth();" << endl;
+    indent_down();
+    out << indent() << "}" << endl;
+    indent_down();
+    out << indent() << "}" << endl << endl;
+}
+
+void t_netcore_generator::generate_netcore_struct_tostring(ostream& out, t_struct* tstruct)
+{
+    out << indent() << "public override string ToString()" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "var sb = new StringBuilder(\"" << tstruct->get_name() << "(\");" << endl;
+
+    const vector<t_field*>& fields = tstruct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    bool useFirstFlag = false;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+    {
+        if (!field_is_required((*f_iter)))
+        {
+            out << indent() << "bool __first = true;" << endl;
+            useFirstFlag = true;
+        }
+        break;
+    }
+
+    bool had_required = false; // set to true after first required field has been processed
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+    {
+        bool is_required = field_is_required((*f_iter));
+        bool has_default = field_has_default((*f_iter));
+        if (nullable_ && !has_default && !is_required)
+        {
+            out << indent() << "if (" << prop_name((*f_iter)) << " != null)" << endl
+                << indent() << "{" << endl;
+            indent_up();
+        }
+        else if (!is_required)
+        {
+            bool null_allowed = type_can_be_null((*f_iter)->get_type());
+            if (null_allowed)
+            {
+                out << indent() << "if (" << prop_name((*f_iter)) << " != null && __isset." << normalize_name((*f_iter)->get_name()) << ")" << endl
+                    << indent() << "{" << endl;
+                indent_up();
+            }
+            else
+            {
+                out << indent() << "if (__isset." << normalize_name((*f_iter)->get_name()) << ")" << endl
+                    << indent() << "{" << endl;
+                indent_up();
+            }
+        }
+
+        if (useFirstFlag && (!had_required))
+        {
+            out << indent() << "if(!__first) { sb.Append(\", \"); }" << endl;
+            if (!is_required)
+            {
+                out << indent() << "__first = false;" << endl;
+            }
+            out << indent() << "sb.Append(\"" << prop_name(*f_iter) << ": \");" << endl;
+        }
+        else
+        {
+            out << indent() << "sb.Append(\", " << prop_name(*f_iter) << ": \");" << endl;
+        }
+
+        t_type* ttype = (*f_iter)->get_type();
+        if (ttype->is_xception() || ttype->is_struct())
+        {
+            out << indent() << "sb.Append(" << prop_name(*f_iter) << "== null ? \"<null>\" : " << prop_name(*f_iter) << ".ToString());" << endl;
+        }
+        else
+        {
+            out << indent() << "sb.Append(" << prop_name(*f_iter) << ");" << endl;
+        }
+
+        if (!is_required)
+        {
+            indent_down();
+            out << indent() << "}" << endl;
+        }
+        else
+        {
+            had_required = true; // now __first must be false, so we don't need to check it anymore
+        }
+    }
+
+    out << indent() << "sb.Append(\")\");" << endl
+        << indent() << "return sb.ToString();" << endl;
+    indent_down();
+    out << indent() << "}" << endl;
+}
+
+void t_netcore_generator::generate_netcore_union(t_struct* tunion)
+{
+    int ic = indent_count();
+
+    string f_union_name = namespace_dir_ + "/" + (tunion->get_name()) + ".cs";
+    ofstream_with_content_based_conditional_update f_union;
+
+    f_union.open(f_union_name.c_str());
+
+    f_union << autogen_comment() << netcore_type_usings() << netcore_thrift_usings() << endl;
+
+    generate_netcore_union_definition(f_union, tunion);
+
+    f_union.close();
+
+    indent_validate(ic, "generate_netcore_union.");
+}
+
+void t_netcore_generator::generate_netcore_union_definition(ostream& out, t_struct* tunion)
+{
+    // Let's define the class first
+    start_netcore_namespace(out);
+
+    out << indent() << "public abstract partial class " << tunion->get_name() << " : TAbstractBase" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    out << indent() << "public abstract Task WriteAsync(TProtocol tProtocol, CancellationToken cancellationToken);" << endl
+        << indent() << "public readonly bool Isset;" << endl
+        << indent() << "public abstract object Data { get; }" << endl
+        << indent() << "protected " << tunion->get_name() << "(bool isset)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "Isset = isset;" << endl;
+    indent_down();
+    out << indent() << "}" << endl << endl;
+
+    out << indent() << "public class ___undefined : " << tunion->get_name() << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    out << indent() << "public override object Data { get { return null; } }" << endl
+        << indent() << "public ___undefined() : base(false) {}" << endl << endl;
+
+    out << indent() << "public override Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "throw new TProtocolException( TProtocolException.INVALID_DATA, \"Cannot persist an union type which is not set.\");" << endl;
+    indent_down();
+    out << indent() << "}" << endl << endl;
+    indent_down();
+    out << indent() << "}" << endl << endl;
+
+    const vector<t_field*>& fields = tunion->get_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+    {
+        generate_netcore_union_class(out, tunion, (*f_iter));
+    }
+
+    generate_netcore_union_reader(out, tunion);
+
+    indent_down();
+    out << indent() << "}" << endl << endl;
+
+    end_netcore_namespace(out);
+}
+
+void t_netcore_generator::generate_netcore_union_class(ostream& out, t_struct* tunion, t_field* tfield)
+{
+    out << indent() << "public class " << tfield->get_name() << " : " << tunion->get_name() << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    out << indent() << "private " << type_name(tfield->get_type()) << " _data;" << endl
+        << indent() << "public override object Data { get { return _data; } }" << endl
+        << indent() << "public " << tfield->get_name() << "(" << type_name(tfield->get_type()) << " data) : base(true)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "this._data = data;" << endl;
+    indent_down();
+    out << indent() << "}" << endl;
+
+    out << indent() << "public override async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken) {" << endl;
+    indent_up();
+
+    out << indent() << "oprot.IncrementRecursionDepth();" << endl
+        << indent() << "try" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    out << indent() << "var struc = new TStruct(\"" << tunion->get_name() << "\");" << endl
+        << indent() << "await oprot.WriteStructBeginAsync(struc, cancellationToken);" << endl;
+
+    out << indent() << "var field = new TField();" << endl
+        << indent() << "field.Name = \"" << tfield->get_name() << "\";" << endl
+        << indent() << "field.Type = " << type_to_enum(tfield->get_type()) << ";" << endl
+        << indent() << "field.ID = " << tfield->get_key() << ";" << endl
+        << indent() << "await oprot.WriteFieldBeginAsync(field, cancellationToken);" << endl;
+
+    generate_serialize_field(out, tfield, "_data", true, true);
+
+    out << indent() << "await oprot.WriteFieldEndAsync(cancellationToken);" << endl
+        << indent() << "await oprot.WriteFieldStopAsync(cancellationToken);" << endl
+        << indent() << "await oprot.WriteStructEndAsync(cancellationToken);" << endl;
+    indent_down();
+    out << indent() << "}" << endl
+        << indent() << "finally" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "oprot.DecrementRecursionDepth();" << endl;
+    indent_down();
+    out << indent() << "}" << endl;
+    out << indent() << "}" << endl;
+    indent_down();
+    out << indent() << "}" << endl << endl;
+}
+
+void t_netcore_generator::generate_netcore_struct_equals(ostream& out, t_struct* tstruct)
+{
+    out << indent() << "public override bool Equals(object that)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "var other = that as " << check_and_correct_struct_name(normalize_name(tstruct->get_name())) << ";" << endl
+        << indent() << "if (other == null) return false;" << endl
+        << indent() << "if (ReferenceEquals(this, other)) return true;" << endl;
+
+    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;
+            out << indent() << "return ";
+            indent_up();
+        }
+        else
+        {
+            out << endl;
+            out << indent() << "&& ";
+        }
+        if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter))))
+        {
+            out << "((__isset." << normalize_name((*f_iter)->get_name()) << " == other.__isset."
+                << normalize_name((*f_iter)->get_name()) << ") && ((!__isset."
+                << normalize_name((*f_iter)->get_name()) << ") || (";
+        }
+        t_type* ttype = (*f_iter)->get_type();
+        if (ttype->is_container() || ttype->is_binary())
+        {
+            out << "TCollections.Equals(";
+        }
+        else
+        {
+            out << "System.Object.Equals(";
+        }
+        out << prop_name((*f_iter)) << ", other." << prop_name((*f_iter)) << ")";
+        if (!field_is_required((*f_iter)) && !(nullable_ && !field_has_default((*f_iter))))
+        {
+            out << ")))";
+        }
+    }
+    if (first)
+    {
+        out << indent() << "return true;" << endl;
+    }
+    else
+    {
+        out << ";" << endl;
+        indent_down();
+    }
+
+    indent_down();
+    out << indent() << "}" << endl << endl;
+}
+
+void t_netcore_generator::generate_netcore_struct_hashcode(ostream& out, t_struct* tstruct)
+{
+    out << indent() << "public override int GetHashCode() {" << endl;
+    indent_up();
+
+    out << indent() << "int hashcode = 0;" << endl;
+    out << indent() << "unchecked {" << endl;
+    indent_up();
+
+    const vector<t_field*>& fields = tstruct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+    {
+        t_type* ttype = (*f_iter)->get_type();
+        out << indent() << "hashcode = (hashcode * 397) ^ ";
+        if (field_is_required((*f_iter)))
+        {
+            out << "(";
+        }
+        else if (nullable_)
+        {
+            out << "(" << prop_name((*f_iter)) << " == null ? 0 : ";
+        }
+        else
+        {
+            out << "(!__isset." << normalize_name((*f_iter)->get_name()) << " ? 0 : ";
+        }
+        if (ttype->is_container())
+        {
+            out << "(TCollections.GetHashCode(" << prop_name((*f_iter)) << "))";
+        }
+        else
+        {
+            out << "(" << prop_name((*f_iter)) << ".GetHashCode())";
+        }
+        out << ");" << endl;
+    }
+
+    indent_down();
+    out << indent() << "}" << endl;
+    out << indent() << "return hashcode;" << endl;
+
+    indent_down();
+    out << indent() << "}" << endl << endl;
+}
+
+void t_netcore_generator::generate_service(t_service* tservice)
+{
+    int ic = indent_count();
+
+    string f_service_name = namespace_dir_ + "/" + service_name_ + ".cs";
+    ofstream_with_content_based_conditional_update f_service;
+    f_service.open(f_service_name.c_str());
+
+    f_service << autogen_comment() << netcore_type_usings() << netcore_thrift_usings() << endl;
+
+    start_netcore_namespace(f_service);
+
+    f_service << indent() << "public partial class " << normalize_name(service_name_) << endl
+              << indent() << "{" << endl;
+    indent_up();
+
+    generate_service_interface(f_service, tservice);
+    generate_service_client(f_service, tservice);
+    generate_service_server(f_service, tservice);
+    generate_service_helpers(f_service, tservice);
+
+    indent_down();
+    f_service << indent() << "}" << endl;
+
+    end_netcore_namespace(f_service);
+    f_service.close();
+
+    indent_validate(ic, "generate_service.");
+}
+
+void t_netcore_generator::generate_service_interface(ostream& out, t_service* tservice)
+{
+    string extends = "";
+    string extends_iface = "";
+    if (tservice->get_extends() != NULL)
+    {
+        extends = type_name(tservice->get_extends());
+        extends_iface = " : " + extends + ".IAsync";
+    }
+
+    //out << endl << endl;
+
+    generate_netcore_doc(out, tservice);
+
+    if (wcf_)
+    {
+        out << indent() << "[ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
+    }
+
+    out << indent() << "public interface IAsync" << extends_iface << endl
+        << indent() << "{" << endl;
+
+    indent_up();
+    vector<t_function*> functions = tservice->get_functions();
+    vector<t_function*>::iterator f_iter;
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
+    {
+        generate_netcore_doc(out, *f_iter);
+
+        // if we're using WCF, add the corresponding attributes
+        if (wcf_)
+        {
+            out << indent() << "[OperationContract]" << endl;
+
+            const vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
+            vector<t_field*>::const_iterator x_iter;
+            for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter)
+            {
+                out << indent() << "[FaultContract(typeof(" + type_name((*x_iter)->get_type(), false, false) + "Fault))]" << endl;
+            }
+        }
+
+        out << indent() << function_signature_async(*f_iter) << ";" << endl << endl;
+    }
+    indent_down();
+    out << indent() << "}" << endl << endl;
+}
+
+void t_netcore_generator::generate_service_helpers(ostream& out, t_service* tservice)
+{
+    vector<t_function*> functions = tservice->get_functions();
+    vector<t_function*>::iterator f_iter;
+
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
+    {
+        t_struct* ts = (*f_iter)->get_arglist();
+        generate_netcore_struct_definition(out, ts, false, true);
+        generate_function_helpers(out, *f_iter);
+    }
+}
+
+void t_netcore_generator::generate_service_client(ostream& out, t_service* tservice)
+{
+    string extends = "";
+    string extends_client = "";
+    if (tservice->get_extends() != NULL)
+    {
+        extends = type_name(tservice->get_extends());
+        extends_client = extends + ".Client, ";
+    }
+    else
+    {
+        extends_client = "TBaseClient, IDisposable, ";
+    }
+
+    out << endl;
+
+    generate_netcore_doc(out, tservice);
+
+    out << indent() << "public class Client : " << extends_client << "IAsync" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    out << indent() << "public Client(TProtocol protocol) : this(protocol, protocol)" << endl
+        << indent() << "{" << endl
+        << indent() << "}" << endl
+        << endl
+        << indent() << "public Client(TProtocol inputProtocol, TProtocol outputProtocol) : base(inputProtocol, outputProtocol)"
+        << indent() << "{" << endl
+        << indent() << "}" << endl;
+
+    vector<t_function*> functions = tservice->get_functions();
+    vector<t_function*>::const_iterator functions_iterator;
+
+    for (functions_iterator = functions.begin(); functions_iterator != functions.end(); ++functions_iterator)
+    {
+        string function_name = correct_function_name_for_async((*functions_iterator)->get_name());
+
+        // async
+        out << indent() << "public async " << function_signature_async(*functions_iterator, "") << endl
+            << indent() << "{" << endl;
+        indent_up();
+
+        string argsname = (*functions_iterator)->get_name() + "Args";
+
+        out << indent() << "await OutputProtocol.WriteMessageBeginAsync(new TMessage(\"" << function_name
+            << "\", " << ((*functions_iterator)->is_oneway() ? "TMessageType.Oneway" : "TMessageType.Call") << ", SeqId), cancellationToken);" << endl
+            << indent() << endl
+            << indent() << "var args = new " << argsname << "();" << endl;
+
+        t_struct* arg_struct = (*functions_iterator)->get_arglist();
+        prepare_member_name_mapping(arg_struct);
+        const vector<t_field*>& fields = arg_struct->get_members();
+        vector<t_field*>::const_iterator fld_iter;
+
+        for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter)
+        {
+            out << indent() << "args." << prop_name(*fld_iter) << " = " << normalize_name((*fld_iter)->get_name()) << ";" << endl;
+        }
+
+        out << indent() << endl
+            << indent() << "await args.WriteAsync(OutputProtocol, cancellationToken);" << endl
+            << indent() << "await OutputProtocol.WriteMessageEndAsync(cancellationToken);" << endl
+            << indent() << "await OutputProtocol.Transport.FlushAsync(cancellationToken);" << endl;
+
+        if (!(*functions_iterator)->is_oneway())
+        {
+            string resultname = (*functions_iterator)->get_name() + "Result";
+            t_struct noargs(program_);
+            t_struct* xs = (*functions_iterator)->get_xceptions();
+            prepare_member_name_mapping(xs, xs->get_members(), resultname);
+
+            out << indent() << endl
+                << indent() << "var msg = await InputProtocol.ReadMessageBeginAsync(cancellationToken);" << endl
+                << indent() << "if (msg.Type == TMessageType.Exception)" << endl
+                << indent() << "{" << endl;
+            indent_up();
+
+            out << indent() << "var x = await TApplicationException.ReadAsync(InputProtocol, cancellationToken);" << endl
+                << indent() << "await InputProtocol.ReadMessageEndAsync(cancellationToken);" << endl
+                << indent() << "throw x;" << endl;
+            indent_down();
+
+            out << indent() << "}" << endl
+                << endl
+                << indent() << "var result = new " << resultname << "();" << endl
+                << indent() << "await result.ReadAsync(InputProtocol, cancellationToken);" << endl
+                << indent() << "await InputProtocol.ReadMessageEndAsync(cancellationToken);" << endl;
+
+            if (!(*functions_iterator)->get_returntype()->is_void())
+            {
+                if (nullable_)
+                {
+                    if (type_can_be_null((*functions_iterator)->get_returntype()))
+                    {
+                        out << indent() << "if (result.Success != null)" << endl
+                            << indent() << "{" << endl;
+                        indent_up();
+                        out << indent() << "return result.Success;" << endl;
+                        indent_down();
+                        out << indent() << "}" << endl;
+                    }
+                    else
+                    {
+                        out << indent() << "if (result.Success.HasValue)" << endl
+                            << indent() << "{" << endl;
+                        indent_up();
+                        out << indent() << "return result.Success.Value;" << endl;
+                        indent_down();
+                        out << indent() << "}" << endl;
+                    }
+                }
+                else
+                {
+                    out << indent() << "if (result.__isset.success)" << endl
+                        << indent() << "{" << endl;
+                    indent_up();
+                    out << indent() << "return result.Success;" << endl;
+                    indent_down();
+                    out << indent() << "}" << endl;
+                }
+            }
+
+            const 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)
+            {
+                if (nullable_)
+                {
+                    out << indent() << "if (result." << prop_name(*x_iter) << " != null)" << endl
+                        << indent() << "{" << endl;
+                    indent_up();
+                    out << indent() << "throw result." << prop_name(*x_iter) << ";" << endl;
+                    indent_down();
+                    out << indent() << "}" << endl;
+                }
+                else
+                {
+                    out << indent() << "if (result.__isset." << normalize_name((*x_iter)->get_name()) << ")" << endl
+                        << indent() << "{" << endl;
+                    indent_up();
+                    out << indent() << "throw result." << prop_name(*x_iter) << ";" << endl;
+                    indent_down();
+                    out << indent() << "}" << endl;
+                }
+            }
+
+            if ((*functions_iterator)->get_returntype()->is_void())
+            {
+                out << indent() << "return;" << endl;
+            }
+            else
+            {
+                out << indent() << "throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, \""
+                    << function_name << " failed: unknown result\");" << endl;
+            }
+
+            cleanup_member_name_mapping((*functions_iterator)->get_xceptions());
+            indent_down();
+            out << indent() << "}" << endl << endl;
+        }
+        else
+        {
+            indent_down();
+            out << indent() << "}" << endl;
+        }
+    }
+
+    indent_down();
+    out << indent() << "}" << endl << endl;
+}
+
+void t_netcore_generator::generate_service_server(ostream& out, t_service* tservice)
+{
+    vector<t_function*> functions = tservice->get_functions();
+    vector<t_function*>::iterator f_iter;
+
+    string extends = "";
+    string extends_processor = "";
+    if (tservice->get_extends() != NULL)
+    {
+        extends = type_name(tservice->get_extends());
+        extends_processor = extends + ".AsyncProcessor, ";
+    }
+
+    out << indent() << "public class AsyncProcessor : " << extends_processor << "ITAsyncProcessor" << endl
+        << indent() << "{" << endl;
+
+    indent_up();
+
+    out << indent() << "private IAsync _iAsync;" << endl
+        << endl
+        << indent() << "public AsyncProcessor(IAsync iAsync)";
+
+    if (!extends.empty())
+    {
+        out << " : base(iAsync)";
+    }
+
+    out << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    out << indent() << "if (iAsync == null) throw new ArgumentNullException(nameof(iAsync));" << endl
+        << endl
+        << indent() << "_iAsync = iAsync;" << endl;
+
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
+    {
+        string function_name = (*f_iter)->get_name();
+        out << indent() << "processMap_[\"" << correct_function_name_for_async(function_name) << "\"] = " << function_name << "_ProcessAsync;" << endl;
+    }
+
+    indent_down();
+    out << indent() << "}" << endl
+        << endl;
+
+    if (extends.empty())
+    {
+        out << indent() << "protected delegate Task ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken);" << endl;
+    }
+
+    if (extends.empty())
+    {
+        out << indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new Dictionary<string, ProcessFunction>();" << endl;
+    }
+
+    out << endl;
+
+    if (extends.empty())
+    {
+        out << indent() << "public async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl
+            << indent() << "{" << endl;
+        indent_up();
+        out << indent() << "return await ProcessAsync(iprot, oprot, CancellationToken.None);" << endl;
+        indent_down();
+        out << indent() << "}" << endl << endl;
+
+        out << indent() << "public async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)" << endl;
+    }
+    else
+    {
+        out << indent() << "public new async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl
+            << indent() << "{" << endl;
+        indent_up();
+        out << indent() << "return await ProcessAsync(iprot, oprot, CancellationToken.None);" << endl;
+        indent_down();
+        out << indent() << "}" << endl << endl;
+
+        out << indent() << "public new async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)" << endl;
+    }
+
+    out << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "try" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "var msg = await iprot.ReadMessageBeginAsync(cancellationToken);" << endl
+        << endl
+        << indent() << "ProcessFunction fn;" << endl
+        << indent() << "processMap_.TryGetValue(msg.Name, out fn);" << endl
+        << endl
+        << indent() << "if (fn == null)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "await TProtocolUtil.SkipAsync(iprot, TType.Struct, cancellationToken);" << endl
+        << indent() << "await iprot.ReadMessageEndAsync(cancellationToken);" << endl
+        << indent() << "var x = new TApplicationException (TApplicationException.ExceptionType.UnknownMethod, \"Invalid method name: '\" + msg.Name + \"'\");" << endl
+        << indent() << "await oprot.WriteMessageBeginAsync(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID), cancellationToken);" << endl
+        << indent() << "await x.WriteAsync(oprot, cancellationToken);" << endl
+        << indent() << "await oprot.WriteMessageEndAsync(cancellationToken);" << endl
+        << indent() << "await oprot.Transport.FlushAsync(cancellationToken);" << endl
+        << indent() << "return true;" << endl;
+    indent_down();
+    out << indent() << "}" << endl
+        << endl
+        << indent() << "await fn(msg.SeqID, iprot, oprot, cancellationToken);" << endl
+        << endl;
+    indent_down();
+    out << indent() << "}" << endl;
+    out << indent() << "catch (IOException)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+    out << indent() << "return false;" << endl;
+    indent_down();
+    out << indent() << "}" << endl
+        << endl
+        << indent() << "return true;" << endl;
+    indent_down();
+    out << indent() << "}" << endl << endl;
+
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
+    {
+        generate_process_function_async(out, tservice, *f_iter);
+    }
+
+    indent_down();
+    out << indent() << "}" << endl << endl;
+}
+
+void t_netcore_generator::generate_function_helpers(ostream& out, t_function* tfunction)
+{
+    if (tfunction->is_oneway())
+    {
+        return;
+    }
+
+    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_netcore_struct_definition(out, &result, false, true, true);
+}
+
+void t_netcore_generator::generate_process_function_async(ostream& out, t_service* tservice, t_function* tfunction)
+{
+    (void)tservice;
+    out << indent() << "public async Task " << tfunction->get_name()
+        << "_ProcessAsync(int seqid, TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    string argsname = tfunction->get_name() + "Args";
+    string resultname = tfunction->get_name() + "Result";
+
+    out << indent() << "var args = new " << argsname << "();" << endl
+        << indent() << "await args.ReadAsync(iprot, cancellationToken);" << endl
+        << indent() << "await iprot.ReadMessageEndAsync(cancellationToken);" << endl;
+
+    if (!tfunction->is_oneway())
+    {
+        out << indent() << "var result = new " << resultname << "();" << endl;
+    }
+
+    out << indent() << "try" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    t_struct* xs = tfunction->get_xceptions();
+    const vector<t_field*>& xceptions = xs->get_members();
+
+    if (xceptions.size() > 0)
+    {
+        out << indent() << "try" << endl
+            << indent() << "{" << endl;
+        indent_up();
+    }
+
+    t_struct* arg_struct = tfunction->get_arglist();
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    out << indent();
+    if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void())
+    {
+        out << "result.Success = ";
+    }
+
+    out << "await _iAsync." << normalize_name(tfunction->get_name()) << "Async(";
+
+    bool first = true;
+    prepare_member_name_mapping(arg_struct);
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+    {
+        if (first)
+        {
+            first = false;
+        }
+        else
+        {
+            out << ", ";
+        }
+
+        out << "args." << prop_name(*f_iter);
+        if (nullable_ && !type_can_be_null((*f_iter)->get_type()))
+        {
+            out << ".Value";
+        }
+    }
+
+    cleanup_member_name_mapping(arg_struct);
+
+    if (!first)
+    {
+        out << ", ";
+    }
+
+    out << "cancellationToken);" << endl;
+
+    vector<t_field*>::const_iterator x_iter;
+
+    prepare_member_name_mapping(xs, xs->get_members(), resultname);
+    if (xceptions.size() > 0)
+    {
+        indent_down();
+        out << indent() << "}" << endl;
+
+        for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter)
+        {
+            out << indent() << "catch (" << type_name((*x_iter)->get_type(), false, false) << " " << (*x_iter)->get_name() << ")" << endl
+                << indent() << "{" << endl;
+
+            if (!tfunction->is_oneway())
+            {
+                indent_up();
+                out << indent() << "result." << prop_name(*x_iter) << " = " << (*x_iter)->get_name() << ";" << endl;
+                indent_down();
+            }
+            out << indent() << "}" << endl;
+        }
+    }
+
+    if (!tfunction->is_oneway())
+    {
+        out << indent() << "await oprot.WriteMessageBeginAsync(new TMessage(\""
+                << correct_function_name_for_async(tfunction->get_name()) << "\", TMessageType.Reply, seqid), cancellationToken); " << endl
+            << indent() << "await result.WriteAsync(oprot, cancellationToken);" << endl;
+    }
+    indent_down();
+
+    cleanup_member_name_mapping(xs);
+
+    out << indent() << "}" << endl
+        << indent() << "catch (TTransportException)" << endl
+        << indent() << "{" << endl
+        << indent() << "  throw;" << endl
+        << indent() << "}" << endl
+        << indent() << "catch (Exception ex)" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    out << indent() << "Console.Error.WriteLine(\"Error occurred in processor:\");" << endl
+        << indent() << "Console.Error.WriteLine(ex.ToString());" << endl;
+
+    if (tfunction->is_oneway())
+    {
+        indent_down();
+        out << indent() << "}" << endl;
+    }
+    else
+    {
+        out << indent() << "var x = new TApplicationException(TApplicationException.ExceptionType.InternalError,\" Internal error.\");" << endl
+            << indent() << "await oprot.WriteMessageBeginAsync(new TMessage(\"" << correct_function_name_for_async(tfunction->get_name())
+            << "\", TMessageType.Exception, seqid), cancellationToken);" << endl
+            << indent() << "await x.WriteAsync(oprot, cancellationToken);" << endl;
+        indent_down();
+
+        out << indent() << "}" << endl
+            << indent() << "await oprot.WriteMessageEndAsync(cancellationToken);" << endl
+            << indent() << "await oprot.Transport.FlushAsync(cancellationToken);" << endl;
+    }
+
+    indent_down();
+    out << indent() << "}" << endl << endl;
+}
+
+void t_netcore_generator::generate_netcore_union_reader(ostream& out, t_struct* tunion)
+{
+    // Thanks to THRIFT-1768, we don't need to check for required fields in the union
+    const vector<t_field*>& fields = tunion->get_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    out << indent() << "public static async Task<" << tunion->get_name() << "> ReadAsync(TProtocol iprot, CancellationToken cancellationToken)" << endl;
+    scope_up(out);
+
+    out << indent() << "iprot.IncrementRecursionDepth();" << endl;
+    out << indent() << "try" << endl;
+    scope_up(out);
+
+    out << indent() << tunion->get_name() << " retval;" << endl;
+    out << indent() << "await iprot.ReadStructBeginAsync(cancellationToken);" << endl;
+    out << indent() << "TField field = await iprot.ReadFieldBeginAsync(cancellationToken);" << endl;
+    // we cannot have the first field be a stop -- we must have a single field defined
+    out << indent() << "if (field.Type == TType.Stop)" << endl;
+    scope_up(out);
+    out << indent() << "await iprot.ReadFieldEndAsync(cancellationToken);" << endl;
+    out << indent() << "retval = new ___undefined();" << endl;
+    scope_down(out);
+    out << indent() << "else" << endl;
+    scope_up(out);
+    out << indent() << "switch (field.ID)" << endl;
+    scope_up(out);
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+    {
+        out << indent() << "case " << (*f_iter)->get_key() << ":" << endl;
+        indent_up();
+        out << indent() << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+        indent_up();
+
+        out << indent() << type_name((*f_iter)->get_type()) << " temp;" << endl;
+        generate_deserialize_field(out, (*f_iter), "temp", true);
+        out << indent() << "retval = new " << (*f_iter)->get_name() << "(temp);" << endl;
+
+        indent_down();
+        out << indent() << "} else { " << endl << indent() << " await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);"
+            << endl << indent() << "  retval = new ___undefined();" << endl << indent() << "}" << endl
+            << indent() << "break;" << endl;
+        indent_down();
+    }
+
+    out << indent() << "default: " << endl;
+    indent_up();
+    out << indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);" << endl << indent()
+        << "retval = new ___undefined();" << endl;
+    out << indent() << "break;" << endl;
+    indent_down();
+
+    scope_down(out);
+
+    out << indent() << "await iprot.ReadFieldEndAsync(cancellationToken);" << endl;
+
+    out << indent() << "if ((await iprot.ReadFieldBeginAsync(cancellationToken)).Type != TType.Stop)" << endl;
+    scope_up(out);
+    out << indent() << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl;
+    scope_down(out);
+
+    // end of else for TStop
+    scope_down(out);
+    out << indent() << "await iprot.ReadStructEndAsync(cancellationToken);" << endl;
+    out << indent() << "return retval;" << endl;
+    indent_down();
+
+    scope_down(out);
+    out << indent() << "finally" << endl;
+    scope_up(out);
+    out << indent() << "iprot.DecrementRecursionDepth();" << endl;
+    scope_down(out);
+
+    out << indent() << "}" << endl << endl;
+}
+
+void t_netcore_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix, bool is_propertyless)
+{
+    t_type* type = tfield->get_type();
+    while (type->is_typedef())
+    {
+        type = static_cast<t_typedef*>(type)->get_type();
+    }
+
+    if (type->is_void())
+    {
+        throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+    }
+
+    string name = prefix + (is_propertyless ? "" : prop_name(tfield));
+
+    if (type->is_struct() || type->is_xception())
+    {
+        generate_deserialize_struct(out, static_cast<t_struct*>(type), name);
+    }
+    else if (type->is_container())
+    {
+        generate_deserialize_container(out, type, name);
+    }
+    else if (type->is_base_type() || type->is_enum())
+    {
+        out << indent() << name << " = ";
+
+        if (type->is_enum())
+        {
+            out << "(" << type_name(type, false, true) << ")";
+        }
+
+        out << "await iprot.";
+
+        if (type->is_base_type())
+        {
+            t_base_type::t_base tbase = static_cast<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:
+                if (type->is_binary())
+                {
+                    out << "ReadBinaryAsync(cancellationToken);";
+                }
+                else
+                {
+                    out << "ReadStringAsync(cancellationToken);";
+                }
+                break;
+            case t_base_type::TYPE_BOOL:
+                out << "ReadBoolAsync(cancellationToken);";
+                break;
+            case t_base_type::TYPE_I8:
+                out << "ReadByteAsync(cancellationToken);";
+                break;
+            case t_base_type::TYPE_I16:
+                out << "ReadI16Async(cancellationToken);";
+                break;
+            case t_base_type::TYPE_I32:
+                out << "ReadI32Async(cancellationToken);";
+                break;
+            case t_base_type::TYPE_I64:
+                out << "ReadI64Async(cancellationToken);";
+                break;
+            case t_base_type::TYPE_DOUBLE:
+                out << "ReadDoubleAsync(cancellationToken);";
+                break;
+            default:
+                throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase);
+            }
+        }
+        else if (type->is_enum())
+        {
+            out << "ReadI32Async(cancellationToken);";
+        }
+        out << endl;
+    }
+    else
+    {
+        printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type_name(type).c_str());
+    }
+}
+
+void t_netcore_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix)
+{
+    if (union_ && tstruct->is_union())
+    {
+        out << indent() << prefix << " = await " << type_name(tstruct) << ".ReadAsync(iprot, cancellationToken);" << endl;
+    }
+    else
+    {
+        out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl
+            << indent() << "await " << prefix << ".ReadAsync(iprot, cancellationToken);" << endl;
+    }
+}
+
+void t_netcore_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix)
+{
+    out << indent() << "{" << endl;
+    indent_up();
+
+    string obj;
+
+    if (ttype->is_map())
+    {
+        obj = tmp("_map");
+    }
+    else if (ttype->is_set())
+    {
+        obj = tmp("_set");
+    }
+    else if (ttype->is_list())
+    {
+        obj = tmp("_list");
+    }
+
+    out << indent() << prefix << " = new " << type_name(ttype, false, true) << "();" << endl;
+    if (ttype->is_map())
+    {
+        out << indent() << "TMap " << obj << " = await iprot.ReadMapBeginAsync(cancellationToken);" << endl;
+    }
+    else if (ttype->is_set())
+    {
+        out << indent() << "TSet " << obj << " = await iprot.ReadSetBeginAsync(cancellationToken);" << endl;
+    }
+    else if (ttype->is_list())
+    {
+        out << indent() << "TList " << obj << " = await iprot.ReadListBeginAsync(cancellationToken);" << endl;
+    }
+
+    string i = tmp("_i");
+    out << indent() << "for(int " << i << " = 0; " << i << " < " << obj << ".Count; ++" << i << ")" << endl
+        << indent() << "{" << endl;
+    indent_up();
+
+    if (ttype->is_map())
+    {
+        generate_deserialize_map_element(out, static_cast<t_map*>(ttype), prefix);
+    }
+    else if (ttype->is_set())
+    {
+        generate_deserialize_set_element(out, static_cast<t_set*>(ttype), prefix);
+    }
+    else if (ttype->is_list())
+    {
+        generate_deserialize_list_element(out, static_cast<t_list*>(ttype), prefix);
+    }
+
+    indent_down();
+    out << indent() << "}" << endl;
+
+    if (ttype->is_map())
+    {
+        out << indent() << "await iprot.ReadMapEndAsync(cancellationToken);" << endl;
+    }
+    else if (ttype->is_set())
+    {
+        out << indent() << "await iprot.ReadSetEndAsync(cancellationToken);" << endl;
+    }
+    else if (ttype->is_list())
+    {
+        out << indent() << "await iprot.ReadListEndAsync(cancellationToken);" << endl;
+    }
+
+    indent_down();
+    out << indent() << "}" << endl;
+}
+
+void t_netcore_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix)
+{
+    string key = tmp("_key");
+    string val = tmp("_val");
+
+    t_field fkey(tmap->get_key_type(), key);
+    t_field fval(tmap->get_val_type(), val);
+
+    out << indent() << declare_field(&fkey) << endl;
+    out << indent() << declare_field(&fval) << endl;
+
+    generate_deserialize_field(out, &fkey);
+    generate_deserialize_field(out, &fval);
+
+    out << indent() << prefix << "[" << key << "] = " << val << ";" << endl;
+}
+
+void t_netcore_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix)
+{
+    string elem = tmp("_elem");
+    t_field felem(tset->get_elem_type(), elem);
+
+    out << indent() << declare_field(&felem) << endl;
+
+    generate_deserialize_field(out, &felem);
+
+    out << indent() << prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_netcore_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix)
+{
+    string elem = tmp("_elem");
+    t_field felem(tlist->get_elem_type(), elem);
+
+    out << indent() << declare_field(&felem) << endl;
+
+    generate_deserialize_field(out, &felem);
+
+    out << indent() << prefix << ".Add(" << elem << ");" << endl;
+}
+
+void t_netcore_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix, bool is_element, bool is_propertyless)
+{
+    t_type* type = tfield->get_type();
+    while (type->is_typedef())
+    {
+        type = static_cast<t_typedef*>(type)->get_type();
+    }
+
+    string name = prefix + (is_propertyless ? "" : prop_name(tfield));
+
+    if (type->is_void())
+    {
+        throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
+    }
+
+    if (type->is_struct() || type->is_xception())
+    {
+        generate_serialize_struct(out, static_cast<t_struct*>(type), name);
+    }
+    else if (type->is_container())
+    {
+        generate_serialize_container(out, type, name);
+    }
+    else if (type->is_base_type() || type->is_enum())
+    {
+        out << indent() << "await oprot.";
+
+        string nullable_name = nullable_ && !is_element && !field_is_required(tfield) ? name + ".Value" : name;
+
+        if (type->is_base_type())
+        {
+            t_base_type::t_base tbase = static_cast<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;
+            case t_base_type::TYPE_STRING:
+                if (type->is_binary())
+                {
+                    out << "WriteBinaryAsync(";
+                }
+                else
+                {
+                    out << "WriteStringAsync(";
+                }
+                out << name << ", cancellationToken);";
+                break;
+            case t_base_type::TYPE_BOOL:
+                out << "WriteBoolAsync(" << nullable_name << ", cancellationToken);";
+                break;
+            case t_base_type::TYPE_I8:
+                out << "WriteByteAsync(" << nullable_name << ", cancellationToken);";
+                break;
+            case t_base_type::TYPE_I16:
+                out << "WriteI16Async(" << nullable_name << ", cancellationToken);";
+                break;
+            case t_base_type::TYPE_I32:
+                out << "WriteI32Async(" << nullable_name << ", cancellationToken);";
+                break;
+            case t_base_type::TYPE_I64:
+                out << "WriteI64Async(" << nullable_name << ", cancellationToken);";
+                break;
+            case t_base_type::TYPE_DOUBLE:
+                out << "WriteDoubleAsync(" << nullable_name << ", cancellationToken);";
+                break;
+            default:
+                throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase);
+            }
+        }
+        else if (type->is_enum())
+        {
+            out << "WriteI32Async((int)" << nullable_name << ", cancellationToken);";
+        }
+        out << endl;
+    }
+    else
+    {
+        printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), type_name(type).c_str());
+    }
+}
+
+void t_netcore_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix)
+{
+    (void)tstruct;
+    out << indent() << "await " << prefix << ".WriteAsync(oprot, cancellationToken);" << endl;
+}
+
+void t_netcore_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix)
+{
+    out << indent() << "{" << endl;
+    indent_up();
+
+    if (ttype->is_map())
+    {
+        out << indent() << "await oprot.WriteMapBeginAsync(new TMap(" << type_to_enum(static_cast<t_map*>(ttype)->get_key_type())
+            << ", " << type_to_enum(static_cast<t_map*>(ttype)->get_val_type()) << ", " << prefix
+            << ".Count), cancellationToken);" << endl;
+    }
+    else if (ttype->is_set())
+    {
+        out << indent() << "await oprot.WriteSetBeginAsync(new TSet(" << type_to_enum(static_cast<t_set*>(ttype)->get_elem_type())
+            << ", " << prefix << ".Count), cancellationToken);" << endl;
+    }
+    else if (ttype->is_list())
+    {
+        out << indent() << "await oprot.WriteListBeginAsync(new TList("
+            << type_to_enum(static_cast<t_list*>(ttype)->get_elem_type()) << ", " << prefix << ".Count), cancellationToken);"
+            << endl;
+    }
+
+    string iter = tmp("_iter");
+    if (ttype->is_map())
+    {
+        out << indent() << "foreach (" << type_name(static_cast<t_map*>(ttype)->get_key_type()) << " " << iter
+            << " in " << prefix << ".Keys)";
+    }
+    else if (ttype->is_set())
+    {
+        out << indent() << "foreach (" << type_name(static_cast<t_set*>(ttype)->get_elem_type()) << " " << iter
+            << " in " << prefix << ")";
+    }
+    else if (ttype->is_list())
+    {
+        out << indent() << "foreach (" << type_name(static_cast<t_list*>(ttype)->get_elem_type()) << " " << iter
+            << " in " << prefix << ")";
+    }
+
+    out << endl;
+    out << indent() << "{" << endl;
+    indent_up();
+
+    if (ttype->is_map())
+    {
+        generate_serialize_map_element(out, static_cast<t_map*>(ttype), iter, prefix);
+    }
+    else if (ttype->is_set())
+    {
+        generate_serialize_set_element(out, static_cast<t_set*>(ttype), iter);
+    }
+    else if (ttype->is_list())
+    {
+        generate_serialize_list_element(out, static_cast<t_list*>(ttype), iter);
+    }
+
+    indent_down();
+    out << indent() << "}" << endl;
+
+    if (ttype->is_map())
+    {
+        out << indent() << "await oprot.WriteMapEndAsync(cancellationToken);" << endl;
+    }
+    else if (ttype->is_set())
+    {
+        out << indent() << "await oprot.WriteSetEndAsync(cancellationToken);" << endl;
+    }
+    else if (ttype->is_list())
+    {
+        out << indent() << "await oprot.WriteListEndAsync(cancellationToken);" << endl;
+    }
+
+    indent_down();
+    out << indent() << "}" << endl;
+}
+
+void t_netcore_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string iter, string map)
+{
+    t_field kfield(tmap->get_key_type(), iter);
+    generate_serialize_field(out, &kfield, "", true);
+    t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
+    generate_serialize_field(out, &vfield, "", true);
+}
+
+void t_netcore_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter)
+{
+    t_field efield(tset->get_elem_type(), iter);
+    generate_serialize_field(out, &efield, "", true);
+}
+
+void t_netcore_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter)
+{
+    t_field efield(tlist->get_elem_type(), iter);
+    generate_serialize_field(out, &efield, "", true);
+}
+
+void t_netcore_generator::generate_property(ostream& out, t_field* tfield, bool isPublic, bool generateIsset)
+{
+    generate_netcore_property(out, tfield, isPublic, generateIsset, "_");
+}
+
+void t_netcore_generator::generate_netcore_property(ostream& out, t_field* tfield, bool isPublic, bool generateIsset, string fieldPrefix)
+{
+    if ((serialize_ || wcf_) && isPublic)
+    {
+        out << indent() << "[DataMember(Order = 0)]" << endl;
+    }
+    bool has_default = field_has_default(tfield);
+    bool is_required = field_is_required(tfield);
+    if ((nullable_ && !has_default) || is_required)
+    {
+        out << indent() << (isPublic ? "public " : "private ") << type_name(tfield->get_type(), false, false, true, is_required) << " " << prop_name(tfield) << " { get; set; }" << endl;
+    }
+    else
+    {
+        out << indent() << (isPublic ? "public " : "private ")  << type_name(tfield->get_type(), false, false, true) << " " << prop_name(tfield) << endl
+            << indent() << "{" << endl;
+        indent_up();
+
+        out << indent() << "get" << endl
+            << indent() << "{" << endl;
+        indent_up();
+
+        bool use_nullable = false;
+        if (nullable_)
+        {
+            t_type* ttype = tfield->get_type();
+            while (ttype->is_typedef())
+            {
+                ttype = static_cast<t_typedef*>(ttype)->get_type();
+            }
+            if (ttype->is_base_type())
+            {
+                use_nullable = static_cast<t_base_type*>(ttype)->get_base() != t_base_type::TYPE_STRING;
+            }
+        }
+
+        out << indent() << "return " << fieldPrefix + tfield->get_name() << ";" << endl;
+        indent_down();
+        out << indent() << "}" << endl
+            << indent() << "set" << endl
+            << indent() << "{" << endl;
+        indent_up();
+
+        if (use_nullable)
+        {
+            if (generateIsset)
+            {
+                out << indent() << "__isset." << normalize_name(tfield->get_name()) << " = value.HasValue;" << endl;
+            }
+            out << indent() << "if (value.HasValue) this." << fieldPrefix + tfield->get_name() << " = value.Value;" << endl;
+        }
+        else
+        {
+            if (generateIsset)
+            {
+                out << indent() << "__isset." << normalize_name(tfield->get_name()) << " = true;" << endl;
+            }
+            out << indent() << "this." << fieldPrefix + tfield->get_name() << " = value;" << endl;
+        }
+
+        indent_down();
+        out << indent() << "}" << endl;
+        indent_down();
+        out << indent() << "}" << endl;
+    }
+    out << endl;
+}
+
+string t_netcore_generator::make_valid_csharp_identifier(string const& fromName)
+{
+    string str = fromName;
+    if (str.empty())
+    {
+        return str;
+    }
+
+    // tests rely on this
+    assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
+
+    // if the first letter is a number, we add an additional underscore in front of it
+    char c = str.at(0);
+    if (('0' <= c) && (c <= '9'))
+    {
+        str = "_" + str;
+    }
+
+    // following chars: letter, number or underscore
+    for (size_t i = 0; i < str.size(); ++i)
+    {
+        c = str.at(i);
+        if (('A' > c || c > 'Z') && ('a' > c || c > 'z') && ('0' > c || c > '9') && '_' != c)
+        {
+            str.replace(i, 1, "_");
+        }
+    }
+
+    return str;
+}
+
+void t_netcore_generator::cleanup_member_name_mapping(void* scope)
+{
+    if (member_mapping_scopes.empty())
+    {
+        throw "internal error: cleanup_member_name_mapping() no scope active";
+    }
+
+    member_mapping_scope& active = member_mapping_scopes.back();
+    if (active.scope_member != scope)
+    {
+        throw "internal error: cleanup_member_name_mapping() called for wrong struct";
+    }
+
+    member_mapping_scopes.pop_back();
+}
+
+string t_netcore_generator::get_mapped_member_name(string name)
+{
+    if (!member_mapping_scopes.empty())
+    {
+        member_mapping_scope& active = member_mapping_scopes.back();
+        map<string, string>::iterator iter = active.mapping_table.find(name);
+        if (active.mapping_table.end() != iter)
+        {
+            return iter->second;
+        }
+    }
+
+    pverbose("no mapping for member %s\n", name.c_str());
+    return name;
+}
+
+void t_netcore_generator::prepare_member_name_mapping(t_struct* tstruct)
+{
+    prepare_member_name_mapping(tstruct, tstruct->get_members(), tstruct->get_name());
+}
+
+void t_netcore_generator::prepare_member_name_mapping(void* scope, const vector<t_field*>& members, const string& structname)
+{
+    // begin new scope
+    member_mapping_scopes.push_back(member_mapping_scope());
+    member_mapping_scope& active = member_mapping_scopes.back();
+    active.scope_member = scope;
+
+    // current C# generator policy:
+    // - prop names are always rendered with an Uppercase first letter
+    // - struct names are used as given
+    std::set<string> used_member_names;
+    vector<t_field*>::const_iterator iter;
+
+    // prevent name conflicts with struct (CS0542 error)
+    used_member_names.insert(structname);
+
+    // prevent name conflicts with known methods (THRIFT-2942)
+    used_member_names.insert("Read");
+    used_member_names.insert("Write");
+
+    for (iter = members.begin(); iter != members.end(); ++iter)
+    {
+        string oldname = (*iter)->get_name();
+        string newname = prop_name(*iter, true);
+        while (true)
+        {
+            // new name conflicts with another member
+            if (used_member_names.find(newname) != used_member_names.end())
+            {
+                pverbose("struct %s: member %s conflicts with another member\n", structname.c_str(), newname.c_str());
+                newname += '_';
+                continue;
+            }
+
+            // add always, this helps us to detect edge cases like
+            // different spellings ("foo" and "Foo") within the same struct
+            pverbose("struct %s: member mapping %s => %s\n", structname.c_str(), oldname.c_str(), newname.c_str());
+            active.mapping_table[oldname] = newname;
+            used_member_names.insert(newname);
+            break;
+        }
+    }
+}
+
+string t_netcore_generator::prop_name(t_field* tfield, bool suppress_mapping)
+{
+    string name(tfield->get_name());
+    if (suppress_mapping)
+    {
+        name[0] = toupper(name[0]);
+    }
+    else
+    {
+        name = get_mapped_member_name(name);
+    }
+    return name;
+}
+
+string t_netcore_generator::type_name(t_type* ttype, bool in_container, bool in_init, bool in_param, bool is_required)
+{
+    (void)in_init;
+
+    while (ttype->is_typedef())
+    {
+        ttype = static_cast<t_typedef*>(ttype)->get_type();
+    }
+
+    if (ttype->is_base_type())
+    {
+        return base_type_name(static_cast<t_base_type*>(ttype), in_container, in_param, is_required);
+    }
+
+    if (ttype->is_map())
+    {
+        t_map* tmap = static_cast<t_map*>(ttype);
+        return "Dictionary<" + type_name(tmap->get_key_type(), true) + ", " + type_name(tmap->get_val_type(), true) + ">";
+    }
+
+    if (ttype->is_set())
+    {
+        t_set* tset = static_cast<t_set*>(ttype);
+        return "THashSet<" + type_name(tset->get_elem_type(), true) + ">";
+    }
+
+    if (ttype->is_list())
+    {
+        t_list* tlist = static_cast<t_list*>(ttype);
+        return "List<" + type_name(tlist->get_elem_type(), true) + ">";
+    }
+
+    t_program* program = ttype->get_program();
+    string postfix = (!is_required && nullable_ && in_param && ttype->is_enum()) ? "?" : "";
+    if (program != NULL && program != program_)
+    {
+        string ns = program->get_namespace("netcore");
+        if (!ns.empty())
+        {
+            return ns + "." + normalize_name(ttype->get_name()) + postfix;
+        }
+    }
+
+    return normalize_name(ttype->get_name()) + postfix;
+}
+
+string t_netcore_generator::base_type_name(t_base_type* tbase, bool in_container, bool in_param, bool is_required)
+{
+    (void)in_container;
+    string postfix = (!is_required && nullable_ && in_param) ? "?" : "";
+    switch (tbase->get_base())
+    {
+    case t_base_type::TYPE_VOID:
+        return "void";
+    case t_base_type::TYPE_STRING:
+        {
+            if (tbase->is_binary())
+            {
+                return "byte[]";
+            }
+            return "string";
+        }
+    case t_base_type::TYPE_BOOL:
+        return "bool" + postfix;
+    case t_base_type::TYPE_I8:
+        return "sbyte" + postfix;
+    case t_base_type::TYPE_I16:
+        return "short" + postfix;
+    case t_base_type::TYPE_I32:
+        return "int" + postfix;
+    case t_base_type::TYPE_I64:
+        return "long" + postfix;
+    case t_base_type::TYPE_DOUBLE:
+        return "double" + postfix;
+    default:
+        throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase->get_base());
+    }
+}
+
+string t_netcore_generator::declare_field(t_field* tfield, bool init, string prefix)
+{
+    string result = type_name(tfield->get_type()) + " " + prefix + tfield->get_name();
+    if (init)
+    {
+        t_type* ttype = tfield->get_type();
+        while (ttype->is_typedef())
+        {
+            ttype = static_cast<t_typedef*>(ttype)->get_type();
+        }
+        if (ttype->is_base_type() && field_has_default(tfield))
+        {
+            std::ofstream dummy;
+            result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
+        }
+        else if (ttype->is_base_type())
+        {
+            t_base_type::t_base tbase = static_cast<t_base_type*>(ttype)->get_base();
+            switch (tbase)
+            {
+            case t_base_type::TYPE_VOID:
+                throw "NO T_VOID CONSTRUCT";
+            case t_base_type::TYPE_STRING:
+                result += " = null";
+                break;
+            case t_base_type::TYPE_BOOL:
+                result += " = false";
+                break;
+            case t_base_type::TYPE_I8:
+            case t_base_type::TYPE_I16:
+            case t_base_type::TYPE_I32:
+            case t_base_type::TYPE_I64:
+                result += " = 0";
+                break;
+            case t_base_type::TYPE_DOUBLE:
+                result += " = (double)0";
+                break;
+            }
+        }
+        else if (ttype->is_enum())
+        {
+            result += " = (" + type_name(ttype, false, true) + ")0";
+        }
+        else if (ttype->is_container())
+        {
+            result += " = new " + type_name(ttype, false, true) + "()";
+        }
+        else
+        {
+            result += " = new " + type_name(ttype, false, true) + "()";
+        }
+    }
+    return result + ";";
+}
+
+string t_netcore_generator::function_signature(t_function* tfunction, string prefix)
+{
+    t_type* ttype = tfunction->get_returntype();
+    return type_name(ttype) + " " + normalize_name(prefix + tfunction->get_name()) + "(" + argument_list(tfunction->get_arglist()) + ")";
+}
+
+string t_netcore_generator::function_signature_async(t_function* tfunction, string prefix)
+{
+    t_type* ttype = tfunction->get_returntype();
+    string task = "Task";
+    if (!ttype->is_void())
+    {
+        task += "<" + type_name(ttype) + ">";
+    }
+
+    string result = task + " " + normalize_name(prefix + tfunction->get_name()) + "Async(";
+    string args = argument_list(tfunction->get_arglist());
+    result += args;
+    if (!args.empty())
+    {
+        result += ", ";
+    }
+    result += "CancellationToken cancellationToken)";
+
+    return result;
+}
+
+string t_netcore_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 += type_name((*f_iter)->get_type()) + " " + normalize_name((*f_iter)->get_name());
+    }
+    return result;
+}
+
+string t_netcore_generator::type_to_enum(t_type* type)
+{
+    while (type->is_typedef())
+    {
+        type = static_cast<t_typedef*>(type)->get_type();
+    }
+
+    if (type->is_base_type())
+    {
+        t_base_type::t_base tbase = static_cast<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 "TType.String";
+        case t_base_type::TYPE_BOOL:
+            return "TType.Bool";
+        case t_base_type::TYPE_I8:
+            return "TType.Byte";
+        case t_base_type::TYPE_I16:
+            return "TType.I16";
+        case t_base_type::TYPE_I32:
+            return "TType.I32";
+        case t_base_type::TYPE_I64:
+            return "TType.I64";
+        case t_base_type::TYPE_DOUBLE:
+            return "TType.Double";
+        }
+    }
+    else if (type->is_enum())
+    {
+        return "TType.I32";
+    }
+    else if (type->is_struct() || type->is_xception())
+    {
+        return "TType.Struct";
+    }
+    else if (type->is_map())
+    {
+        return "TType.Map";
+    }
+    else if (type->is_set())
+    {
+        return "TType.Set";
+    }
+    else if (type->is_list())
+    {
+        return "TType.List";
+    }
+
+    throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+void t_netcore_generator::generate_netcore_docstring_comment(ostream& out, string contents)
+{
+    docstring_comment(out, "/// <summary>" + endl, "/// ", contents, "/// </summary>" + endl);
+}
+
+void t_netcore_generator::generate_netcore_doc(ostream& out, t_field* field)
+{
+    if (field->get_type()->is_enum())
+    {
+        string combined_message = field->get_doc() + endl + "<seealso cref=\"" + get_enum_class_name(field->get_type()) + "\"/>";
+        generate_netcore_docstring_comment(out, combined_message);
+    }
+    else
+    {
+        generate_netcore_doc(out, static_cast<t_doc*>(field));
+    }
+}
+
+void t_netcore_generator::generate_netcore_doc(ostream& out, t_doc* tdoc)
+{
+    if (tdoc->has_doc())
+    {
+        generate_netcore_docstring_comment(out, tdoc->get_doc());
+    }
+}
+
+void t_netcore_generator::generate_netcore_doc(ostream& out, t_function* tfunction)
+{
+    if (tfunction->has_doc())
+    {
+        stringstream ps;
+        const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+        vector<t_field*>::const_iterator p_iter;
+        for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter)
+        {
+            t_field* p = *p_iter;
+            ps << endl << "<param name=\"" << p->get_name() << "\">";
+            if (p->has_doc())
+            {
+                string str = p->get_doc();
+                str.erase(remove(str.begin(), str.end(), '\n'), str.end());
+                ps << str;
+            }
+            ps << "</param>";
+        }
+
+        docstring_comment(out,
+                                   "",
+                                   "/// ",
+                                   "<summary>" + endl + tfunction->get_doc() + "</summary>" + ps.str(),
+                                   "");
+    }
+}
+
+void t_netcore_generator::docstring_comment(ostream& out, const string& comment_start, const string& line_prefix, const string& contents, const string& comment_end)
+{
+    if (comment_start != "")
+    {
+        out << indent() << comment_start;
+    }
+
+    stringstream docs(contents, std::ios_base::in);
+
+    while (!(docs.eof() || docs.fail()))
+    {
+        char line[1024];
+        docs.getline(line, 1024);
+
+        // Just prnt a newline when the line & prefix are empty.
+        if (strlen(line) == 0 && line_prefix == "" && !docs.eof())
+        {
+            out << endl;
+        }
+        else if (strlen(line) > 0 || !docs.eof())
+        { // skip the empty last line
+            out << indent() << line_prefix << line << endl;
+        }
+    }
+    if (comment_end != "")
+    {
+        out << indent() << comment_end;
+    }
+}
+
+string t_netcore_generator::get_enum_class_name(t_type* type)
+{
+    string package = "";
+    t_program* program = type->get_program();
+    if (program != NULL && program != program_)
+    {
+        package = program->get_namespace("netcore") + ".";
+    }
+    return package + type->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(
+    netcore,
+    "C#",
+    "    wcf:             Adds bindings for WCF to generated classes.\n"
+    "    serial:          Add serialization support to generated classes.\n"
+    "    nullable:        Use nullable types for properties.\n"
+    "    hashcode:        Generate a hashcode and equals implementation for classes.\n"
+    "    union:           Use new union typing, which includes a static read function for union types.\n"
+)
diff --git a/compiler/cpp/src/thrift/generate/t_netcore_generator.h b/compiler/cpp/src/thrift/generate/t_netcore_generator.h
new file mode 100644
index 0000000..6efc922
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_netcore_generator.h
@@ -0,0 +1,137 @@
+#include <cassert>
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <cctype>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+class t_netcore_generator : public t_oop_generator
+{
+
+    struct member_mapping_scope
+    {
+    public:
+        member_mapping_scope() : scope_member(0) { }
+        void* scope_member;
+        map<string, string> mapping_table;
+    };
+
+public:
+    t_netcore_generator(t_program* program, const map<string, string>& parsed_options, const string& option_string);
+
+    bool is_wcf_enabled() const;
+    bool is_nullable_enabled() const;
+    bool is_hashcode_enabled() const;
+    bool is_serialize_enabled() const;
+    bool is_union_enabled() const;
+    map<string, int> get_keywords_list() const;
+
+    // overrides
+    void init_generator();
+    void close_generator();
+    void generate_consts(vector<t_const*> consts);
+    void generate_consts(ostream& out, vector<t_const*> consts);
+    void generate_typedef(t_typedef* ttypedef);
+    void generate_enum(t_enum* tenum);
+    void generate_enum(ostream& out, t_enum* tenum);
+    void generate_struct(t_struct* tstruct);
+    void generate_xception(t_struct* txception);
+    void generate_service(t_service* tservice);
+
+    void generate_property(ostream& out, t_field* tfield, bool isPublic, bool generateIsset);
+    void generate_netcore_property(ostream& out, t_field* tfield, bool isPublic, bool includeIsset = true, string fieldPrefix = "");
+    bool print_const_value(ostream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval = false, bool needtype = false);
+    string render_const_value(ostream& out, string name, t_type* type, t_const_value* value);
+    void print_const_constructor(ostream& out, vector<t_const*> consts);
+    void print_const_def_value(ostream& out, string name, t_type* type, t_const_value* value);
+    void generate_netcore_struct(t_struct* tstruct, bool is_exception);
+    void generate_netcore_union(t_struct* tunion);
+    void generate_netcore_struct_definition(ostream& out, t_struct* tstruct, bool is_xception = false, bool in_class = false, bool is_result = false);
+    void generate_netcore_union_definition(ostream& out, t_struct* tunion);
+    void generate_netcore_union_class(ostream& out, t_struct* tunion, t_field* tfield);
+    void generate_netcore_wcffault(ostream& out, t_struct* tstruct);
+    void generate_netcore_struct_reader(ostream& out, t_struct* tstruct);
+    void generate_netcore_struct_result_writer(ostream& out, t_struct* tstruct);
+    void generate_netcore_struct_writer(ostream& out, t_struct* tstruct);
+    void generate_netcore_struct_tostring(ostream& out, t_struct* tstruct);
+    void generate_netcore_struct_equals(ostream& out, t_struct* tstruct);
+    void generate_netcore_struct_hashcode(ostream& out, t_struct* tstruct);
+    void generate_netcore_union_reader(ostream& out, t_struct* tunion);
+    void generate_function_helpers(ostream& out, t_function* tfunction);
+    void generate_service_interface(ostream& out, t_service* tservice);
+    void generate_service_helpers(ostream& out, t_service* tservice);
+    void generate_service_client(ostream& out, t_service* tservice);
+    void generate_service_server(ostream& out, t_service* tservice);
+    void generate_process_function_async(ostream& out, t_service* tservice, t_function* function);
+    void generate_deserialize_field(ostream& out, t_field* tfield, string prefix = "", bool is_propertyless = false);
+    void generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix = "");
+    void generate_deserialize_container(ostream& out, t_type* ttype, string prefix = "");
+    void generate_deserialize_set_element(ostream& out, t_set* tset, string prefix = "");
+    void generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix = "");
+    void generate_deserialize_list_element(ostream& out, t_list* list, string prefix = "");
+    void generate_serialize_field(ostream& out, t_field* tfield, string prefix = "", bool is_element = false, bool is_propertyless = false);
+    void generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix = "");
+    void generate_serialize_container(ostream& out, t_type* ttype, string prefix = "");
+    void generate_serialize_map_element(ostream& out, t_map* tmap, string iter, string map);
+    void generate_serialize_set_element(ostream& out, t_set* tmap, string iter);
+    void generate_serialize_list_element(ostream& out, t_list* tlist, string iter);
+    void generate_netcore_doc(ostream& out, t_field* field);
+    void generate_netcore_doc(ostream& out, t_doc* tdoc);
+    void generate_netcore_doc(ostream& out, t_function* tdoc);
+    void generate_netcore_docstring_comment(ostream& out, string contents);
+    void docstring_comment(ostream& out, const string& comment_start, const string& line_prefix, const string& contents, const string& comment_end);
+    void start_netcore_namespace(ostream& out);
+    void end_netcore_namespace(ostream& out);
+
+    string netcore_type_usings() const;
+    string netcore_thrift_usings() const;
+
+    string type_name(t_type* ttype, bool in_countainer = false, bool in_init = false, bool in_param = false, bool is_required = false);
+    string base_type_name(t_base_type* tbase, bool in_container = false, bool in_param = false, bool is_required = false);
+    string declare_field(t_field* tfield, bool init = false, string prefix = "");
+    string function_signature_async(t_function* tfunction, string prefix = "");
+    string function_signature(t_function* tfunction, string prefix = "");
+    string argument_list(t_struct* tstruct);
+    string type_to_enum(t_type* ttype);
+    string prop_name(t_field* tfield, bool suppress_mapping = false);
+    string get_enum_class_name(t_type* type);
+
+private:
+    string namespace_name_;
+    string namespace_dir_;
+
+    bool nullable_;
+    bool union_;
+    bool hashcode_;
+    bool serialize_;
+    bool wcf_;
+
+    string wcf_namespace_;
+    map<string, int> netcore_keywords;
+    vector<member_mapping_scope> member_mapping_scopes;
+
+    void init_keywords();
+    string normalize_name(string name);
+    string make_valid_csharp_identifier(string const& fromName);
+    void prepare_member_name_mapping(t_struct* tstruct);
+    void prepare_member_name_mapping(void* scope, const vector<t_field*>& members, const string& structname);
+    void cleanup_member_name_mapping(void* scope);
+    string get_mapped_member_name(string oldname);
+};
diff --git a/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc b/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc
new file mode 100644
index 0000000..0ec81ba
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc
@@ -0,0 +1,1762 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+#include "thrift/platform.h"
+#include "thrift/version.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::ios;
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * OCaml code generator.
+ *
+ */
+class t_ocaml_generator : public t_oop_generator {
+public:
+  t_ocaml_generator(t_program* program,
+                    const std::map<std::string, std::string>& parsed_options,
+                    const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    /* no options yet */
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      throw "unknown option ocaml:" + iter->first;
+    }
+
+    out_dir_base_ = "gen-ocaml";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  /**
+   * Program-level generation functions
+   */
+  void generate_program();
+  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);
+  bool struct_member_persistent(t_field* tmember);
+  bool struct_member_omitable(t_field* tmember);
+  bool struct_member_default_cheaply_comparable(t_field* tmember);
+  std::string struct_member_copy_of(t_type* type, string what);
+
+  /**
+   * Struct generation code
+   */
+
+  void generate_ocaml_struct(t_struct* tstruct, bool is_exception);
+  void generate_ocaml_struct_definition(std::ostream& out,
+                                        t_struct* tstruct,
+                                        bool is_xception = false);
+  void generate_ocaml_struct_member(std::ostream& out, string tname, t_field* tmember);
+  void generate_ocaml_struct_sig(std::ostream& out, t_struct* tstruct, bool is_exception);
+  void generate_ocaml_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_ocaml_struct_writer(std::ostream& out, t_struct* tstruct);
+  void generate_ocaml_function_helpers(t_function* tfunction);
+  void generate_ocaml_method_copy(std::ostream& out, const vector<t_field*>& members);
+  void generate_ocaml_member_copy(std::ostream& out, t_field* member);
+
+  /**
+   * 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_server(t_service* tservice);
+  void generate_process_function(t_service* tservice, t_function* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix);
+
+  void generate_deserialize_struct(std::ostream& out, t_struct* tstruct);
+
+  void generate_deserialize_container(std::ostream& out, t_type* ttype);
+
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset);
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         std::string prefix = "");
+  void generate_deserialize_type(std::ostream& out, t_type* type);
+
+  void generate_serialize_field(std::ostream& out, t_field* tfield, std::string name = "");
+
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string kiter,
+                                      std::string viter);
+
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string ocaml_autogen_comment();
+  std::string ocaml_imports();
+  std::string type_name(t_type* ttype);
+  std::string function_signature(t_function* tfunction, std::string prefix = "");
+  std::string function_type(t_function* tfunc, bool method = false, bool options = false);
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string render_ocaml_type(t_type* type);
+
+private:
+  /**
+   * File streams
+   */
+
+  ofstream_with_content_based_conditional_update f_types_;
+  ofstream_with_content_based_conditional_update f_consts_;
+  ofstream_with_content_based_conditional_update f_service_;
+
+  ofstream_with_content_based_conditional_update f_types_i_;
+  ofstream_with_content_based_conditional_update f_service_i_;
+};
+
+/*
+ * This is necessary because we want typedefs to appear later,
+ * after all the types have been declared.
+ */
+void t_ocaml_generator::generate_program() {
+  // Initialize the generator
+  init_generator();
+
+  // Generate enums
+  vector<t_enum*> enums = program_->get_enums();
+  vector<t_enum*>::iterator en_iter;
+  for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+    generate_enum(*en_iter);
+  }
+
+  // Generate structs
+  vector<t_struct*> structs = program_->get_structs();
+  vector<t_struct*>::iterator st_iter;
+  for (st_iter = structs.begin(); st_iter != structs.end(); ++st_iter) {
+    generate_struct(*st_iter);
+  }
+
+  // Generate xceptions
+  vector<t_struct*> xceptions = program_->get_xceptions();
+  vector<t_struct*>::iterator x_iter;
+  for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+    generate_xception(*x_iter);
+  }
+
+  // Generate typedefs
+  vector<t_typedef*> typedefs = program_->get_typedefs();
+  vector<t_typedef*>::iterator td_iter;
+  for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
+    generate_typedef(*td_iter);
+  }
+
+  // Generate services
+  vector<t_service*> services = program_->get_services();
+  vector<t_service*>::iterator sv_iter;
+  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    service_name_ = get_service_name(*sv_iter);
+    generate_service(*sv_iter);
+  }
+
+  // Generate constants
+  vector<t_const*> consts = program_->get_consts();
+  generate_consts(consts);
+
+  // Close the generator
+  close_generator();
+}
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_ocaml_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  // Make output file
+  string f_types_name = get_out_dir() + program_name_ + "_types.ml";
+  f_types_.open(f_types_name.c_str());
+  string f_types_i_name = get_out_dir() + program_name_ + "_types.mli";
+  f_types_i_.open(f_types_i_name.c_str());
+
+  string f_consts_name = get_out_dir() + program_name_ + "_consts.ml";
+  f_consts_.open(f_consts_name.c_str());
+
+  // Print header
+  f_types_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl;
+  f_types_i_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl;
+  f_consts_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl << "open "
+            << capitalize(program_name_) << "_types" << endl;
+}
+
+/**
+ * Autogen'd comment
+ */
+string t_ocaml_generator::ocaml_autogen_comment() {
+  return std::string("(*\n") + " Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + "\n"
+         + " DO NOT EDIT UNLESS YOU ARE SURE YOU KNOW WHAT YOU ARE DOING\n" + "*)\n";
+}
+
+/**
+ * Prints standard thrift imports
+ */
+string t_ocaml_generator::ocaml_imports() {
+  return "open Thrift";
+}
+
+/**
+ * Closes the type files
+ */
+void t_ocaml_generator::close_generator() {
+  // Close types file
+  f_types_.close();
+}
+
+/**
+ * Generates a typedef. Ez.
+ *
+ * @param ttypedef The type definition
+ */
+void t_ocaml_generator::generate_typedef(t_typedef* ttypedef) {
+  f_types_ << indent() << "type " << decapitalize(ttypedef->get_symbolic()) << " = "
+           << render_ocaml_type(ttypedef->get_type()) << endl << endl;
+  f_types_i_ << indent() << "type " << decapitalize(ttypedef->get_symbolic()) << " = "
+             << render_ocaml_type(ttypedef->get_type()) << endl << endl;
+}
+
+/**
+ * Generates code for an enumerated type.
+ * the values.
+ *
+ * @param tenum The enumeration
+ */
+void t_ocaml_generator::generate_enum(t_enum* tenum) {
+  indent(f_types_) << "module " << capitalize(tenum->get_name()) << " = " << endl << "struct"
+                   << endl;
+  indent(f_types_i_) << "module " << capitalize(tenum->get_name()) << " : " << endl << "sig"
+                     << endl;
+  indent_up();
+  indent(f_types_) << "type t = " << endl;
+  indent(f_types_i_) << "type t = " << endl;
+  indent_up();
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    string name = capitalize((*c_iter)->get_name());
+    indent(f_types_) << "| " << name << endl;
+    indent(f_types_i_) << "| " << name << endl;
+  }
+  indent_down();
+
+  indent(f_types_) << "let to_i = function" << endl;
+  indent(f_types_i_) << "val to_i : t -> Int32.t" << endl;
+  indent_up();
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    string name = capitalize((*c_iter)->get_name());
+    indent(f_types_) << "| " << name << " -> " << value << "l" << endl;
+  }
+  indent_down();
+
+  indent(f_types_) << "let of_i = function" << endl;
+  indent(f_types_i_) << "val of_i : Int32.t -> t" << endl;
+  indent_up();
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    string name = capitalize((*c_iter)->get_name());
+    indent(f_types_) << "| " << value << "l -> " << name << endl;
+  }
+  indent(f_types_) << "| _ -> raise Thrift_error" << endl;
+  indent_down();
+  indent_down();
+  indent(f_types_) << "end" << endl;
+  indent(f_types_i_) << "end" << endl;
+}
+
+/**
+ * Generate a constant value
+ */
+void t_ocaml_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = decapitalize(tconst->get_name());
+  t_const_value* value = tconst->get_value();
+
+  indent(f_consts_) << "let " << name << " = " << render_const_value(type, value) << endl << 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_ocaml_generator::render_const_value(t_type* type, t_const_value* value) {
+  type = get_true_type(type);
+  std::ostringstream out;
+  // OCaml requires all floating point numbers contain a decimal point
+  out.setf(ios::showpoint);
+  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_I8:
+    case t_base_type::TYPE_I16:
+      out << value->get_integer();
+      break;
+    case t_base_type::TYPE_I32:
+      out << value->get_integer() << "l";
+      break;
+    case t_base_type::TYPE_I64:
+      out << value->get_integer() << "L";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        out << value->get_integer() << ".0";
+      } 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()) {
+    t_enum* tenum = (t_enum*)type;
+    vector<t_enum_value*> constants = tenum->get_constants();
+    vector<t_enum_value*>::iterator c_iter;
+    for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+      int val = (*c_iter)->get_value();
+      if (val == value->get_integer()) {
+        indent(out) << capitalize(tenum->get_name()) << "." << capitalize((*c_iter)->get_name());
+        break;
+      }
+    }
+  } else if (type->is_struct() || type->is_xception()) {
+    string cname = type_name(type);
+    string ct = tmp("_c");
+    out << endl;
+    indent_up();
+    indent(out) << "(let " << ct << " = new " << cname << " in" << 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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::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();
+      }
+      string fname = v_iter->first->get_string();
+      out << indent();
+      out << ct << "#set_" << fname << " ";
+      out << render_const_value(field_type, v_iter->second);
+      out << ";" << endl;
+    }
+    indent(out) << ct << ")";
+    indent_down();
+    indent_down();
+  } 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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    string hm = tmp("_hm");
+    out << endl;
+    indent_up();
+    indent(out) << "(let " << hm << " = Hashtbl.create " << val.size() << " in" << endl;
+    indent_up();
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(ktype, v_iter->first);
+      string val = render_const_value(vtype, v_iter->second);
+      indent(out) << "Hashtbl.add " << hm << " " << key << " " << val << ";" << endl;
+    }
+    indent(out) << hm << ")";
+    indent_down();
+    indent_down();
+  } else if (type->is_list()) {
+    t_type* etype;
+    etype = ((t_list*)type)->get_elem_type();
+    out << "[" << endl;
+    indent_up();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent();
+      out << render_const_value(etype, *v_iter);
+      out << ";" << endl;
+    }
+    indent_down();
+    indent(out) << "]";
+  } else if (type->is_set()) {
+    t_type* etype = ((t_set*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    string hm = tmp("_hm");
+    indent(out) << "(let " << hm << " = Hashtbl.create " << val.size() << " in" << endl;
+    indent_up();
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(etype, *v_iter);
+      indent(out) << "Hashtbl.add " << hm << " " << val << " true;" << endl;
+    }
+    indent(out) << hm << ")" << endl;
+    indent_down();
+    out << endl;
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+  return out.str();
+}
+
+/**
+ * Generates a "struct"
+ */
+void t_ocaml_generator::generate_struct(t_struct* tstruct) {
+  generate_ocaml_struct(tstruct, false);
+}
+
+/**
+ * Generates a struct definition for a thrift exception. Basically the same
+ * as a struct, but also has an exception declaration.
+ *
+ * @param txception The struct definition
+ */
+void t_ocaml_generator::generate_xception(t_struct* txception) {
+  generate_ocaml_struct(txception, true);
+}
+
+/**
+ * Generates an OCaml struct
+ */
+void t_ocaml_generator::generate_ocaml_struct(t_struct* tstruct, bool is_exception) {
+  generate_ocaml_struct_definition(f_types_, tstruct, is_exception);
+  generate_ocaml_struct_sig(f_types_i_, tstruct, is_exception);
+}
+
+void t_ocaml_generator::generate_ocaml_method_copy(ostream& out, const vector<t_field*>& members) {
+  vector<t_field*>::const_iterator m_iter;
+
+  /* Create a copy of the current object */
+  indent(out) << "method copy =" << endl;
+  indent_up();
+  indent_up();
+  indent(out) << "let _new = Oo.copy self in" << endl;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
+    generate_ocaml_member_copy(out, *m_iter);
+
+  indent_down();
+  indent(out) << "_new" << endl;
+  indent_down();
+}
+
+string t_ocaml_generator::struct_member_copy_of(t_type* type, string what) {
+  if (type->is_struct() || type->is_xception()) {
+    return what + string("#copy");
+  }
+  if (type->is_map()) {
+    string copy_of_k = struct_member_copy_of(((t_map*)type)->get_key_type(), "k");
+    string copy_of_v = struct_member_copy_of(((t_map*)type)->get_val_type(), "v");
+
+    if (copy_of_k == "k" && copy_of_v == "v") {
+      return string("(Hashtbl.copy ") + what + string(")");
+    } else {
+      return string(
+                 "((fun oh -> let nh = Hashtbl.create (Hashtbl.length oh) in Hashtbl.iter (fun k v "
+                 "-> Hashtbl.add nh ") + copy_of_k + string(" ") + copy_of_v + string(") oh; nh) ")
+             + what + ")";
+    }
+  }
+  if (type->is_set()) {
+    string copy_of = struct_member_copy_of(((t_set*)type)->get_elem_type(), "k");
+
+    if (copy_of == "k") {
+      return string("(Hashtbl.copy ") + what + string(")");
+    } else {
+      return string(
+                 "((fun oh -> let nh = Hashtbl.create (Hashtbl.length oh) in Hashtbl.iter (fun k v "
+                 "-> Hashtbl.add nh ") + copy_of + string(" true") + string(") oh; nh) ") + what
+             + ")";
+    }
+  }
+  if (type->is_list()) {
+    string copy_of = struct_member_copy_of(((t_list*)type)->get_elem_type(), "x");
+    if (copy_of != "x") {
+      return string("(List.map (fun x -> ") + copy_of + string(") ") + what + string(")");
+    } else {
+      return what;
+    }
+  }
+  return what;
+}
+
+void t_ocaml_generator::generate_ocaml_member_copy(ostream& out, t_field* tmember) {
+  string mname = decapitalize(tmember->get_name());
+  t_type* type = get_true_type(tmember->get_type());
+
+  string grab_field = string("self#grab_") + mname;
+  string copy_of = struct_member_copy_of(type, grab_field);
+  if (copy_of != grab_field) {
+    indent(out);
+    if (!struct_member_persistent(tmember)) {
+      out << "if _" << mname << " <> None then" << endl;
+      indent(out) << "  ";
+    }
+    out << "_new#set_" << mname << " " << copy_of << ";" << endl;
+  }
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_ocaml_generator::generate_ocaml_struct_definition(ostream& out,
+                                                         t_struct* tstruct,
+                                                         bool is_exception) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  string tname = type_name(tstruct);
+  indent(out) << "class " << tname << " =" << endl;
+  indent(out) << "object (self)" << endl;
+
+  indent_up();
+
+  if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      generate_ocaml_struct_member(out, tname, (*m_iter));
+      out << endl;
+    }
+  }
+  generate_ocaml_method_copy(out, members);
+  generate_ocaml_struct_writer(out, tstruct);
+  indent_down();
+  indent(out) << "end" << endl;
+
+  if (is_exception) {
+    indent(out) << "exception " << capitalize(tname) << " of " << tname << endl;
+  }
+
+  generate_ocaml_struct_reader(out, tstruct);
+}
+
+/**
+ * Generates a structure member for a thrift data type.
+ *
+ * @param tname Name of the parent structure for the member
+ * @param tmember Member definition
+ */
+void t_ocaml_generator::generate_ocaml_struct_member(ostream& out,
+                                                     string tname,
+                                                     t_field* tmember) {
+  string x = tmp("_x");
+  string mname = decapitalize(tmember->get_name());
+
+  indent(out) << "val mutable _" << mname << " : " << render_ocaml_type(tmember->get_type());
+  t_const_value* val = tmember->get_value();
+  if (val) {
+    if (struct_member_persistent(tmember))
+      out << " = " << render_const_value(tmember->get_type(), tmember->get_value()) << endl;
+    else
+      out << " option = Some " << render_const_value(tmember->get_type(), tmember->get_value())
+          << endl;
+  } else {
+    // assert(!struct_member_persistent(tmember))
+    out << " option = None" << endl;
+  }
+
+  if (struct_member_persistent(tmember)) {
+    indent(out) << "method get_" << mname << " = Some _" << mname << endl;
+    indent(out) << "method grab_" << mname << " = _" << mname << endl;
+    indent(out) << "method set_" << mname << " " << x << " = _" << mname << " <- " << x << endl;
+  } else {
+    indent(out) << "method get_" << mname << " = _" << mname << endl;
+    indent(out) << "method grab_" << mname << " = match _" << mname
+                << " with None->raise (Field_empty \"" << tname << "." << mname << "\") | Some "
+                << x << " -> " << x << endl;
+    indent(out) << "method set_" << mname << " " << x << " = _" << mname << " <- Some " << x
+                << endl;
+    indent(out) << "method unset_" << mname << " = _" << mname << " <- None" << endl;
+  }
+
+  indent(out) << "method reset_" << mname << " = _" << mname << " <- ";
+  if (val) {
+    if (struct_member_persistent(tmember))
+      out << render_const_value(tmember->get_type(), tmember->get_value()) << endl;
+    else
+      out << "Some " << render_const_value(tmember->get_type(), tmember->get_value()) << endl;
+  } else {
+    out << "None" << endl;
+  }
+}
+
+/**
+ * Check whether a member of the structure can not have undefined value
+ *
+ * @param tmember Member definition
+ */
+bool t_ocaml_generator::struct_member_persistent(t_field* tmember) {
+  t_const_value* val = tmember->get_value();
+  return (val ? true : false);
+}
+
+/**
+ * Check whether a member of the structure can be skipped during encoding
+ *
+ * @param tmember Member definition
+ */
+bool t_ocaml_generator::struct_member_omitable(t_field* tmember) {
+  return (tmember->get_req() != t_field::T_REQUIRED);
+}
+
+/**
+ * Figure out whether a member of the structure has
+ * a cheaply comparable default value.
+ *
+ * @param tmember Member definition
+ */
+bool t_ocaml_generator::struct_member_default_cheaply_comparable(t_field* tmember) {
+  t_type* type = get_true_type(tmember->get_type());
+  t_const_value* val = tmember->get_value();
+  if (!val) {
+    return false;
+  } else if (type->is_base_type()) {
+    // Base types are generally cheaply compared for structural equivalence.
+    switch (((t_base_type*)type)->get_base()) {
+    case t_base_type::TYPE_DOUBLE:
+      if (val->get_double() == 0.0)
+        return true;
+      else
+        return false;
+    default:
+      return true;
+    }
+  } else if (type->is_list()) {
+    // Empty lists are cheaply compared for structural equivalence.
+    // Is empty list?
+    if (val->get_list().size() == 0)
+      return true;
+    else
+      return false;
+  } else {
+    return false;
+  }
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_ocaml_generator::generate_ocaml_struct_sig(ostream& out,
+                                                  t_struct* tstruct,
+                                                  bool is_exception) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  string tname = type_name(tstruct);
+  indent(out) << "class " << tname << " :" << endl;
+  indent(out) << "object ('a)" << endl;
+
+  indent_up();
+
+  string x = tmp("_x");
+  if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      string mname = decapitalize((*m_iter)->get_name());
+      string type = render_ocaml_type((*m_iter)->get_type());
+      indent(out) << "method get_" << mname << " : " << type << " option" << endl;
+      indent(out) << "method grab_" << mname << " : " << type << endl;
+      indent(out) << "method set_" << mname << " : " << type << " -> unit" << endl;
+      if (!struct_member_persistent(*m_iter))
+        indent(out) << "method unset_" << mname << " : unit" << endl;
+      indent(out) << "method reset_" << mname << " : unit" << endl;
+    }
+  }
+  indent(out) << "method copy : 'a" << endl;
+  indent(out) << "method write : Protocol.t -> unit" << endl;
+  indent_down();
+  indent(out) << "end" << endl;
+
+  if (is_exception) {
+    indent(out) << "exception " << capitalize(tname) << " of " << tname << endl;
+  }
+
+  indent(out) << "val read_" << tname << " : Protocol.t -> " << tname << endl;
+}
+
+/**
+ * Generates the read method for a struct
+ */
+void t_ocaml_generator::generate_ocaml_struct_reader(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  string sname = type_name(tstruct);
+  string str = tmp("_str");
+  string t = tmp("_t");
+  string id = tmp("_id");
+  indent(out) << "let rec read_" << sname << " (iprot : Protocol.t) =" << endl;
+  indent_up();
+  indent(out) << "let " << str << " = new " << sname << " in" << endl;
+  indent_up();
+  indent(out) << "ignore(iprot#readStructBegin);" << endl;
+
+  // Loop over reading in fields
+  indent(out) << "(try while true do" << endl;
+  indent_up();
+  indent_up();
+
+  // Read beginning field marker
+  indent(out) << "let (_," << t << "," << id << ") = iprot#readFieldBegin in" << endl;
+
+  // Check for field STOP marker and break
+  indent(out) << "if " << t << " = Protocol.T_STOP then" << endl;
+  indent_up();
+  indent(out) << "raise Break" << endl;
+  indent_down();
+  indent(out) << "else ();" << endl;
+
+  indent(out) << "(match " << id << " with " << endl;
+  indent_up();
+  // Generate deserialization code for known cases
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) << "| " << (*f_iter)->get_key() << " -> (";
+    out << "if " << t << " = " << type_to_enum((*f_iter)->get_type()) << " then" << endl;
+    indent_up();
+    indent_up();
+    generate_deserialize_field(out, *f_iter, str);
+    indent_down();
+    out << indent() << "else" << endl << indent() << "  iprot#skip " << t << ")" << endl;
+    indent_down();
+  }
+
+  // In the default case we skip the field
+  out << indent() << "| _ -> "
+      << "iprot#skip " << t << ");" << endl;
+  indent_down();
+  // Read field end marker
+  indent(out) << "iprot#readFieldEnd;" << endl;
+  indent_down();
+  indent(out) << "done; ()" << endl;
+  indent_down();
+  indent(out) << "with Break -> ());" << endl;
+
+  indent(out) << "iprot#readStructEnd;" << endl;
+
+  indent(out) << str << endl << endl;
+  indent_down();
+  indent_down();
+}
+
+void t_ocaml_generator::generate_ocaml_struct_writer(ostream& out, t_struct* tstruct) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+  string str = tmp("_str");
+  string f = tmp("_f");
+
+  indent(out) << "method write (oprot : Protocol.t) =" << endl;
+  indent_up();
+  indent(out) << "oprot#writeStructBegin \"" << name << "\";" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* tmember = (*f_iter);
+    string mname = "_" + decapitalize(tmember->get_name());
+    string _v;
+
+    if (struct_member_persistent(tmember)) {
+
+      if (struct_member_omitable(tmember) && struct_member_default_cheaply_comparable(tmember)) {
+        _v = "_v";
+        // Avoid redundant encoding of members having default values.
+        indent(out) << "(match " << mname << " with "
+                    << render_const_value(tmember->get_type(), tmember->get_value()) << " -> () | "
+                    << _v << " -> " << endl;
+      } else {
+        _v = mname;
+        indent(out) << "(" << endl;
+      }
+
+    } else {
+
+      indent(out) << "(match " << mname << " with ";
+
+      if (struct_member_omitable(tmember)) {
+        out << "None -> ()";
+
+        if (struct_member_default_cheaply_comparable(tmember)) {
+          // Avoid redundant encoding of members having default values.
+          out << " | Some " << render_const_value(tmember->get_type(), tmember->get_value())
+              << " -> ()";
+        }
+        out << " | Some _v -> " << endl;
+      } else {
+        out << endl;
+        indent(out) << "| None -> raise (Field_empty \"" << type_name(tstruct) << "." << mname
+                    << "\")" << endl;
+        indent(out) << "| Some _v -> " << endl;
+      }
+
+      _v = "_v";
+    }
+    indent_up();
+    // Write field header
+    indent(out) << "oprot#writeFieldBegin(\"" << tmember->get_name() << "\","
+                << type_to_enum(tmember->get_type()) << "," << tmember->get_key() << ");" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, tmember, _v);
+
+    // Write field closer
+    indent(out) << "oprot#writeFieldEnd" << endl;
+
+    indent_down();
+    indent(out) << ");" << endl;
+  }
+
+  // Write the struct map
+  out << indent() << "oprot#writeFieldStop;" << endl << indent() << "oprot#writeStructEnd" << endl;
+
+  indent_down();
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_ocaml_generator::generate_service(t_service* tservice) {
+  string f_service_name = get_out_dir() + capitalize(service_name_) + ".ml";
+  f_service_.open(f_service_name.c_str());
+  string f_service_i_name = get_out_dir() + capitalize(service_name_) + ".mli";
+  f_service_i_.open(f_service_i_name.c_str());
+
+  f_service_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl;
+  f_service_i_ << ocaml_autogen_comment() << endl << ocaml_imports() << endl;
+
+  /* if (tservice->get_extends() != NULL) {
+    f_service_ <<
+      "open " << capitalize(tservice->get_extends()->get_name()) << endl;
+    f_service_i_ <<
+      "open " << capitalize(tservice->get_extends()->get_name()) << endl;
+  }
+  */
+  f_service_ << "open " << capitalize(program_name_) << "_types" << endl << endl;
+
+  f_service_i_ << "open " << capitalize(program_name_) << "_types" << endl << endl;
+
+  // Generate the three main parts of the service
+  generate_service_helpers(tservice);
+  generate_service_interface(tservice);
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+
+  // Close service file
+  f_service_.close();
+  f_service_i_.close();
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_ocaml_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  indent(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_ocaml_struct_definition(f_service_, ts, false);
+    generate_ocaml_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_ocaml_generator::generate_ocaml_function_helpers(t_function* tfunction) {
+  t_struct result(program_, decapitalize(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_ocaml_struct_definition(f_service_, &result, false);
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_ocaml_generator::generate_service_interface(t_service* tservice) {
+  f_service_ << indent() << "class virtual iface =" << endl << "object (self)" << endl;
+  f_service_i_ << indent() << "class virtual iface :" << endl << "object" << endl;
+
+  indent_up();
+
+  if (tservice->get_extends() != NULL) {
+    string extends = type_name(tservice->get_extends());
+    indent(f_service_) << "inherit " << extends << ".iface" << endl;
+    indent(f_service_i_) << "inherit " << extends << ".iface" << endl;
+  }
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string ft = function_type(*f_iter, true, true);
+    f_service_ << indent() << "method virtual " << decapitalize((*f_iter)->get_name()) << " : "
+               << ft << endl;
+    f_service_i_ << indent() << "method virtual " << decapitalize((*f_iter)->get_name()) << " : "
+                 << ft << endl;
+  }
+  indent_down();
+  indent(f_service_) << "end" << endl << endl;
+  indent(f_service_i_) << "end" << endl << endl;
+}
+
+/**
+ * Generates a service client definition. Note that in OCaml, the client doesn't implement iface.
+ *This is because
+ * The client does not (and should not have to) deal with arguments being None.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_ocaml_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  indent(f_service_) << "class client (iprot : Protocol.t) (oprot : Protocol.t) =" << endl
+                     << "object (self)" << endl;
+  indent(f_service_i_) << "class client : Protocol.t -> Protocol.t -> " << endl << "object" << endl;
+  indent_up();
+
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    indent(f_service_) << "inherit " << extends << ".client iprot oprot as super" << endl;
+    indent(f_service_i_) << "inherit " << extends << ".client" << endl;
+  }
+  indent(f_service_) << "val mutable seqid = 0" << 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 = (*f_iter)->get_name();
+
+    // Open function
+    indent(f_service_) << "method " << function_signature(*f_iter) << " = " << endl;
+    indent(f_service_i_) << "method " << decapitalize((*f_iter)->get_name()) << " : "
+                         << function_type(*f_iter, true, false) << endl;
+    indent_up();
+    indent(f_service_) << "self#send_" << funname;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << " " << decapitalize((*fld_iter)->get_name());
+    }
+    f_service_ << ";" << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << indent();
+      f_service_ << "self#recv_" << funname << endl;
+    }
+    indent_down();
+
+    indent(f_service_) << "method private send_" << function_signature(*f_iter) << " = " << endl;
+    indent_up();
+
+    std::string argsname = decapitalize((*f_iter)->get_name() + "_args");
+
+    // Serialize the request header
+    f_service_ << indent() << "oprot#writeMessageBegin (\"" << (*f_iter)->get_name() << "\", "
+               << ((*f_iter)->is_oneway() ? "Protocol.ONEWAY" : "Protocol.CALL") << ", seqid);"
+               << endl;
+
+    f_service_ << indent() << "let args = new " << argsname << " in" << endl;
+    indent_up();
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << indent() << "args#set_" << (*fld_iter)->get_name() << " "
+                 << (*fld_iter)->get_name() << ";" << endl;
+    }
+
+    // Write to the stream
+    f_service_ << indent() << "args#write oprot;" << endl << indent() << "oprot#writeMessageEnd;"
+               << endl << indent() << "oprot#getTransport#flush" << endl;
+
+    indent_down();
+    indent_down();
+
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultname = decapitalize((*f_iter)->get_name() + "_result");
+      t_struct noargs(program_);
+
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+      // Open function
+      f_service_ << indent() << "method private " << function_signature(&recv_function) << " ="
+                 << endl;
+      indent_up();
+
+      // TODO(mcslee): Validate message reply here, seq ids etc.
+
+      f_service_ << indent() << "let (fname, mtype, rseqid) = iprot#readMessageBegin in" << endl;
+      indent_up();
+      f_service_ << indent() << "(if mtype = Protocol.EXCEPTION then" << endl << indent()
+                 << "  let x = Application_Exn.read iprot in" << endl;
+      indent_up();
+      f_service_ << indent() << "  (iprot#readMessageEnd;" << indent()
+                 << "   raise (Application_Exn.E x))" << endl;
+      indent_down();
+      f_service_ << indent() << "else ());" << endl;
+      string res = "_";
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+
+      if (!(*f_iter)->get_returntype()->is_void() || xceptions.size() > 0) {
+        res = "result";
+      }
+      f_service_ << indent() << "let " << res << " = read_" << resultname << " iprot in" << endl;
+      indent_up();
+      f_service_ << indent() << "iprot#readMessageEnd;" << endl;
+
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << indent() << "match result#get_success with Some v -> v | None -> (" << endl;
+        indent_up();
+      }
+
+      vector<t_field*>::const_iterator x_iter;
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        f_service_ << indent() << "(match result#get_" << (*x_iter)->get_name()
+                   << " with None -> () | Some _v ->" << endl;
+        indent(f_service_) << "  raise (" << capitalize(type_name((*x_iter)->get_type()))
+                           << " _v));" << endl;
+      }
+
+      // Careful, only return _result if not a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) << "()" << endl;
+      } else {
+        f_service_
+            << indent()
+            << "raise (Application_Exn.E (Application_Exn.create Application_Exn.MISSING_RESULT \""
+            << (*f_iter)->get_name() << " failed: unknown result\")))" << endl;
+        indent_down();
+      }
+
+      // Close function
+      indent_down();
+      indent_down();
+      indent_down();
+    }
+  }
+
+  indent_down();
+  indent(f_service_) << "end" << endl << endl;
+  indent(f_service_i_) << "end" << endl << endl;
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_ocaml_generator::generate_service_server(t_service* tservice) {
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  // Generate the header portion
+  indent(f_service_) << "class processor (handler : iface) =" << endl << indent() << "object (self)"
+                     << endl;
+  indent(f_service_i_) << "class processor : iface ->" << endl << indent() << "object" << endl;
+  indent_up();
+
+  f_service_ << indent() << "inherit Processor.t" << endl << endl;
+  f_service_i_ << indent() << "inherit Processor.t" << endl << endl;
+  string extends = "";
+
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    indent(f_service_) << "inherit " + extends + ".processor (handler :> " + extends + ".iface)"
+                       << endl;
+    indent(f_service_i_) << "inherit " + extends + ".processor" << endl;
+  }
+
+  if (extends.empty()) {
+    indent(f_service_) << "val processMap = Hashtbl.create " << functions.size() << endl;
+  }
+  indent(f_service_i_)
+      << "val processMap : (string, int * Protocol.t * Protocol.t -> unit) Hashtbl.t" << endl;
+
+  // Generate the server implementation
+  indent(f_service_) << "method process iprot oprot =" << endl;
+  indent(f_service_i_) << "method process : Protocol.t -> Protocol.t -> bool" << endl;
+  indent_up();
+
+  f_service_ << indent() << "let (name, typ, seqid)  = iprot#readMessageBegin in" << endl;
+  indent_up();
+  // TODO(mcslee): validate message
+
+  // HOT: dictionary function lookup
+  f_service_ << indent() << "if Hashtbl.mem processMap name then" << endl << indent()
+             << "  (Hashtbl.find processMap name) (seqid, iprot, oprot)" << endl << indent()
+             << "else (" << endl << indent() << "  iprot#skip(Protocol.T_STRUCT);" << endl
+             << indent() << "  iprot#readMessageEnd;" << endl << indent()
+             << "  let x = Application_Exn.create Application_Exn.UNKNOWN_METHOD (\"Unknown "
+                "function \"^name) in" << endl << indent()
+             << "    oprot#writeMessageBegin(name, Protocol.EXCEPTION, seqid);" << endl << indent()
+             << "    x#write oprot;" << endl << indent() << "    oprot#writeMessageEnd;" << endl
+             << indent() << "    oprot#getTransport#flush" << endl << indent() << ");" << endl;
+
+  // Read end of args field, the T_STOP, and the struct close
+  f_service_ << indent() << "true" << endl;
+  indent_down();
+  indent_down();
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent(f_service_) << "initializer" << endl;
+  indent_up();
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << indent() << "Hashtbl.add processMap \"" << (*f_iter)->get_name()
+               << "\" self#process_" << (*f_iter)->get_name() << ";" << endl;
+  }
+  indent_down();
+
+  indent_down();
+  indent(f_service_) << "end" << endl << endl;
+  indent(f_service_i_) << "end" << endl << endl;
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_ocaml_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+  // Open function
+  indent(f_service_) << "method private process_" << tfunction->get_name()
+                     << " (seqid, iprot, oprot) =" << endl;
+  indent_up();
+
+  string argsname = decapitalize(tfunction->get_name()) + "_args";
+  string resultname = decapitalize(tfunction->get_name()) + "_result";
+
+  // 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;
+
+  string args = "args";
+  if (fields.size() == 0) {
+    args = "_";
+  }
+
+  f_service_ << indent() << "let " << args << " = read_" << argsname << " iprot in" << endl;
+  indent_up();
+  f_service_ << indent() << "iprot#readMessageEnd;" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << "let result = new " << resultname << " in" << endl;
+    indent_up();
+  }
+
+  // Try block for a function with exceptions
+  if (xceptions.size() > 0) {
+    f_service_ << indent() << "(try" << endl;
+    indent_up();
+  }
+
+  f_service_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "result#set_success ";
+  }
+  f_service_ << "(handler#" << tfunction->get_name();
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    f_service_ << " args#get_" << (*f_iter)->get_name();
+  }
+  f_service_ << ");" << endl;
+
+  if (xceptions.size() > 0) {
+    indent_down();
+    indent(f_service_) << "with" << endl;
+    indent_up();
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << indent() << "| " << capitalize(type_name((*x_iter)->get_type())) << " "
+                 << (*x_iter)->get_name() << " -> " << endl;
+      indent_up();
+      indent_up();
+      if (!tfunction->is_oneway()) {
+        f_service_ << indent() << "result#set_" << (*x_iter)->get_name() << " "
+                   << (*x_iter)->get_name() << endl;
+      } else {
+        indent(f_service_) << "()";
+      }
+      indent_down();
+      indent_down();
+    }
+    indent_down();
+    f_service_ << indent() << ");" << endl;
+  }
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    f_service_ << indent() << "()" << endl;
+    indent_down();
+    indent_down();
+    return;
+  }
+
+  f_service_ << indent() << "oprot#writeMessageBegin (\"" << tfunction->get_name()
+             << "\", Protocol.REPLY, seqid);" << endl << indent() << "result#write oprot;" << endl
+             << indent() << "oprot#writeMessageEnd;" << endl << indent()
+             << "oprot#getTransport#flush" << endl;
+
+  // Close function
+  indent_down();
+  indent_down();
+  indent_down();
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_ocaml_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = tfield->get_type();
+
+  string name = decapitalize(tfield->get_name());
+  indent(out) << prefix << "#set_" << name << " ";
+  generate_deserialize_type(out, type);
+  out << endl;
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_ocaml_generator::generate_deserialize_type(ostream& out, t_type* type) {
+  type = get_true_type(type);
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE";
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type);
+  } else if (type->is_base_type()) {
+    out << "iprot#";
+    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";
+      break;
+    case t_base_type::TYPE_STRING:
+      out << "readString";
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << "readBool";
+      break;
+    case t_base_type::TYPE_I8:
+      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 ocaml name for base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    string ename = capitalize(type->get_name());
+    out << "(" << ename << ".of_i iprot#readI32)";
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE TYPE '%s'\n", type->get_name().c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a struct, calling read()
+ */
+void t_ocaml_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct) {
+  string prefix = "";
+  t_program* program = tstruct->get_program();
+  if (program != NULL && program != program_) {
+    prefix = capitalize(program->get_name()) + "_types.";
+  }
+  string name = decapitalize(tstruct->get_name());
+  out << "(" << prefix << "read_" << name << " iprot)";
+}
+
+/**
+ * Serialize a container by writing out the header followed by
+ * data and then a footer.
+ */
+void t_ocaml_generator::generate_deserialize_container(ostream& out, t_type* ttype) {
+  string size = tmp("_size");
+  string ktype = tmp("_ktype");
+  string vtype = tmp("_vtype");
+  string etype = tmp("_etype");
+  string con = tmp("_con");
+
+  t_field fsize(g_type_i32, size);
+  t_field fktype(g_type_i8, ktype);
+  t_field fvtype(g_type_i8, vtype);
+  t_field fetype(g_type_i8, etype);
+
+  out << endl;
+  indent_up();
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    indent(out) << "(let (" << ktype << "," << vtype << "," << size << ") = iprot#readMapBegin in"
+                << endl;
+    indent(out) << "let " << con << " = Hashtbl.create " << size << " in" << endl;
+    indent_up();
+    indent(out) << "for i = 1 to " << size << " do" << endl;
+    indent_up();
+    indent(out) << "let _k = ";
+    generate_deserialize_type(out, ((t_map*)ttype)->get_key_type());
+    out << " in" << endl;
+    indent(out) << "let _v = ";
+    generate_deserialize_type(out, ((t_map*)ttype)->get_val_type());
+    out << " in" << endl;
+    indent_up();
+    indent(out) << "Hashtbl.add " << con << " _k _v" << endl;
+    indent_down();
+    indent_down();
+    indent(out) << "done; iprot#readMapEnd; " << con << ")";
+    indent_down();
+  } else if (ttype->is_set()) {
+    indent(out) << "(let (" << etype << "," << size << ") = iprot#readSetBegin in" << endl;
+    indent(out) << "let " << con << " = Hashtbl.create " << size << " in" << endl;
+    indent_up();
+    indent(out) << "for i = 1 to " << size << " do" << endl;
+    indent_up();
+    indent(out) << "Hashtbl.add " << con << " ";
+    generate_deserialize_type(out, ((t_set*)ttype)->get_elem_type());
+    out << " true" << endl;
+    indent_down();
+    indent(out) << "done; iprot#readSetEnd; " << con << ")";
+    indent_down();
+  } else if (ttype->is_list()) {
+    indent(out) << "(let (" << etype << "," << size << ") = iprot#readListBegin in" << endl;
+    indent_up();
+    indent(out) << "let " << con << " = (Array.to_list (Array.init " << size << " (fun _ -> ";
+    generate_deserialize_type(out, ((t_list*)ttype)->get_elem_type());
+    out << "))) in" << endl;
+    indent_up();
+    indent(out) << "iprot#readListEnd; " << con << ")";
+    indent_down();
+    indent_down();
+  }
+  indent_down();
+}
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_ocaml_generator::generate_serialize_field(ostream& out, t_field* tfield, string name) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + tfield->get_name();
+  }
+
+  if (name.length() == 0) {
+    name = decapitalize(tfield->get_name());
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    indent(out) << "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(" << name << ")";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ")";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "writeByte(" << name << ")";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16(" << name << ")";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32(" << name << ")";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64(" << name << ")";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble(" << name << ")";
+        break;
+      default:
+        throw "compiler error: no ocaml name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      string ename = capitalize(type->get_name());
+      out << "writeI32(" << ename << ".to_i " << name << ")";
+    }
+
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+  out << ";" << endl;
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_ocaml_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  (void)tstruct;
+  indent(out) << prefix << "#write(oprot)";
+}
+
+void t_ocaml_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  if (ttype->is_map()) {
+    indent(out) << "oprot#writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ",";
+    out << type_to_enum(((t_map*)ttype)->get_val_type()) << ",";
+    out << "Hashtbl.length " << prefix << ");" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot#writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ",";
+    out << "Hashtbl.length " << prefix << ");" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot#writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type())
+                << ",";
+    out << "List.length " << prefix << ");" << endl;
+  }
+
+  if (ttype->is_map()) {
+    string kiter = tmp("_kiter");
+    string viter = tmp("_viter");
+    indent(out) << "Hashtbl.iter (fun " << kiter << " -> fun " << viter << " -> " << endl;
+    indent_up();
+    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
+    indent_down();
+    indent(out) << ") " << prefix << ";" << endl;
+  } else if (ttype->is_set()) {
+    string iter = tmp("_iter");
+    indent(out) << "Hashtbl.iter (fun " << iter << " -> fun _ -> ";
+    indent_up();
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+    indent_down();
+    indent(out) << ") " << prefix << ";" << endl;
+  } else if (ttype->is_list()) {
+    string iter = tmp("_iter");
+    indent(out) << "List.iter (fun " << iter << " -> ";
+    indent_up();
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+    indent_down();
+    indent(out) << ") " << prefix << ";" << endl;
+  }
+
+  if (ttype->is_map()) {
+    indent(out) << "oprot#writeMapEnd";
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot#writeSetEnd";
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot#writeListEnd";
+  }
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_ocaml_generator::generate_serialize_map_element(ostream& out,
+                                                       t_map* tmap,
+                                                       string kiter,
+                                                       string viter) {
+  t_field kfield(tmap->get_key_type(), kiter);
+  generate_serialize_field(out, &kfield);
+
+  t_field vfield(tmap->get_val_type(), viter);
+  generate_serialize_field(out, &vfield);
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_ocaml_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield);
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_ocaml_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield);
+}
+
+/**
+ * Renders a function signature of the form 'name args'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_ocaml_generator::function_signature(t_function* tfunction, string prefix) {
+  return prefix + decapitalize(tfunction->get_name()) + " "
+         + argument_list(tfunction->get_arglist());
+}
+
+string t_ocaml_generator::function_type(t_function* tfunc, bool method, bool options) {
+  string result = "";
+
+  const vector<t_field*>& fields = tfunc->get_arglist()->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    result += render_ocaml_type((*f_iter)->get_type());
+    if (options)
+      result += " option";
+    result += " -> ";
+  }
+  if (fields.empty() && !method) {
+    result += "unit -> ";
+  }
+  result += render_ocaml_type(tfunc->get_returntype());
+  return result;
+}
+
+/**
+ * Renders a field list
+ */
+string t_ocaml_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();
+  }
+  return result;
+}
+
+string t_ocaml_generator::type_name(t_type* ttype) {
+  string prefix = "";
+  t_program* program = ttype->get_program();
+  if (program != NULL && program != program_) {
+    if (!ttype->is_service()) {
+      prefix = capitalize(program->get_name()) + "_types.";
+    }
+  }
+
+  string name = ttype->get_name();
+  if (ttype->is_service()) {
+    name = capitalize(name);
+  } else {
+    name = decapitalize(name);
+  }
+  return prefix + name;
+}
+
+/**
+ * Converts the parse type to a Protocol.t_type enum
+ */
+string t_ocaml_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:
+      return "Protocol.T_VOID";
+    case t_base_type::TYPE_STRING:
+      return "Protocol.T_STRING";
+    case t_base_type::TYPE_BOOL:
+      return "Protocol.T_BOOL";
+    case t_base_type::TYPE_I8:
+      return "Protocol.T_BYTE";
+    case t_base_type::TYPE_I16:
+      return "Protocol.T_I16";
+    case t_base_type::TYPE_I32:
+      return "Protocol.T_I32";
+    case t_base_type::TYPE_I64:
+      return "Protocol.T_I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "Protocol.T_DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "Protocol.T_I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "Protocol.T_STRUCT";
+  } else if (type->is_map()) {
+    return "Protocol.T_MAP";
+  } else if (type->is_set()) {
+    return "Protocol.T_SET";
+  } else if (type->is_list()) {
+    return "Protocol.T_LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Converts the parse type to an ocaml type
+ */
+string t_ocaml_generator::render_ocaml_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:
+      return "unit";
+    case t_base_type::TYPE_STRING:
+      return "string";
+    case t_base_type::TYPE_BOOL:
+      return "bool";
+    case t_base_type::TYPE_I8:
+      return "int";
+    case t_base_type::TYPE_I16:
+      return "int";
+    case t_base_type::TYPE_I32:
+      return "Int32.t";
+    case t_base_type::TYPE_I64:
+      return "Int64.t";
+    case t_base_type::TYPE_DOUBLE:
+      return "float";
+    }
+  } else if (type->is_enum()) {
+    return capitalize(((t_enum*)type)->get_name()) + ".t";
+  } else if (type->is_struct() || type->is_xception()) {
+    return type_name((t_struct*)type);
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    return "(" + render_ocaml_type(ktype) + "," + render_ocaml_type(vtype) + ") Hashtbl.t";
+  } else if (type->is_set()) {
+    t_type* etype = ((t_set*)type)->get_elem_type();
+    return "(" + render_ocaml_type(etype) + ",bool) Hashtbl.t";
+  } else if (type->is_list()) {
+    t_type* etype = ((t_list*)type)->get_elem_type();
+    return render_ocaml_type(etype) + " list";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(ocaml, "OCaml", "")
diff --git a/compiler/cpp/src/thrift/generate/t_oop_generator.h b/compiler/cpp/src/thrift/generate/t_oop_generator.h
new file mode 100644
index 0000000..f8da547
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_oop_generator.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#ifndef T_OOP_GENERATOR_H
+#define T_OOP_GENERATOR_H
+
+#include <string>
+#include <iostream>
+
+#include "thrift/common.h"
+#include "thrift/generate/t_generator.h"
+
+#include <algorithm>
+
+/**
+ * Class with utility methods shared across common object oriented languages.
+ * Specifically, most of this stuff is for C++/Java.
+ *
+ */
+class t_oop_generator : public t_generator {
+public:
+  t_oop_generator(t_program* program) : t_generator(program) {}
+
+  /**
+   * Scoping, using curly braces!
+   */
+
+  void scope_up(std::ostream& out) {
+    indent(out) << "{" << std::endl;
+    indent_up();
+  }
+
+  void scope_down(std::ostream& out) {
+    indent_down();
+    indent(out) << "}" << std::endl;
+  }
+
+  std::string upcase_string(std::string original) {
+    std::transform(original.begin(), original.end(), original.begin(), (int (*)(int))toupper);
+    return original;
+  }
+
+  virtual std::string get_enum_class_name(t_type* type) {
+    std::string package = "";
+    t_program* program = type->get_program();
+    if (program != NULL && program != program_) {
+      package = program->get_namespace("java") + ".";
+    }
+    return package + type->get_name();
+  }
+
+  virtual void generate_java_docstring_comment(std::ostream& out, std::string contents) {
+    generate_docstring_comment(out, "/**\n", " * ", contents, " */\n");
+  }
+
+  virtual void generate_java_doc(std::ostream& out, t_field* field) {
+    if (field->get_type()->is_enum()) {
+      std::string combined_message = field->get_doc() + "\n@see "
+                                     + get_enum_class_name(field->get_type());
+      generate_java_docstring_comment(out, combined_message);
+    } else {
+      generate_java_doc(out, (t_doc*)field);
+    }
+  }
+
+  /**
+   * Emits a JavaDoc comment if the provided object has a doc in Thrift
+   */
+  virtual void generate_java_doc(std::ostream& out, t_doc* tdoc) {
+    if (tdoc->has_doc()) {
+      generate_java_docstring_comment(out, tdoc->get_doc());
+    }
+  }
+
+  /**
+   * Emits a JavaDoc comment if the provided function object has a doc in Thrift
+   */
+  virtual void generate_java_doc(std::ostream& out, t_function* tfunction) {
+    if (tfunction->has_doc()) {
+      std::stringstream ss;
+      ss << tfunction->get_doc();
+      const std::vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+      std::vector<t_field*>::const_iterator p_iter;
+      for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
+        t_field* p = *p_iter;
+        ss << "\n@param " << p->get_name();
+        if (p->has_doc()) {
+          ss << " " << p->get_doc();
+        }
+      }
+      generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n");
+    }
+  }
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/generate/t_perl_generator.cc b/compiler/cpp/src/thrift/generate/t_perl_generator.cc
new file mode 100644
index 0000000..8924a76
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_perl_generator.cc
@@ -0,0 +1,1683 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <list>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "thrift/platform.h"
+#include "thrift/version.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * PERL code generator.
+ *
+ */
+class t_perl_generator : public t_oop_generator {
+public:
+  t_perl_generator(t_program* program,
+                   const std::map<std::string, std::string>& parsed_options,
+                   const std::string& option_string)
+    : t_oop_generator(program), f_types_use_includes_emitted_(false) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    /* no options yet */
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      throw "unknown option perl:" + iter->first;
+    }
+
+    out_dir_base_ = "gen-perl";
+    escape_['$'] = "\\$";
+    escape_['@'] = "\\@";
+  }
+
+  /**
+   * 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);
+
+  /**
+   * Structs!
+   */
+
+  void generate_perl_struct(t_struct* tstruct, bool is_exception);
+  void generate_perl_struct_definition(std::ostream& out,
+                                       t_struct* tstruct,
+                                       bool is_xception = false);
+  void generate_perl_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_perl_struct_writer(std::ostream& out, t_struct* tstruct);
+  void generate_perl_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_rest(t_service* tservice);
+  void generate_service_client(t_service* tservice);
+  void generate_service_processor(t_service* tservice);
+  void generate_process_function(t_service* tservice, t_function* tfunction);
+  void generate_use_includes(std::ostream& os, bool& done, t_type *type, bool selfish);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field(std::ostream& out,
+                                  t_field* tfield,
+                                  std::string prefix = "",
+                                  bool inclass = false);
+
+  void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+
+  void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         std::string prefix = "");
+
+  void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
+
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string kiter,
+                                      std::string viter);
+
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string perl_includes();
+  std::string declare_field(t_field* tfield, bool init = false, bool obj = false);
+  std::string function_signature(t_function* tfunction, std::string prefix = "");
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+
+  std::string autogen_comment() {
+    return std::string("#\n") + "# Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
+           + "#\n" + "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "#\n";
+  }
+
+  void perl_namespace_dirs(t_program* p, std::list<std::string>& dirs) {
+    std::string ns = p->get_namespace("perl");
+    std::string::size_type loc;
+
+    if (ns.size() > 0) {
+      while ((loc = ns.find(".")) != std::string::npos) {
+        dirs.push_back(ns.substr(0, loc));
+        ns = ns.substr(loc + 1);
+      }
+    }
+
+    if (ns.size() > 0) {
+      dirs.push_back(ns);
+    }
+  }
+
+  std::string perl_namespace(t_program* p) {
+    std::string ns = p->get_namespace("perl");
+    std::string result = "";
+    std::string::size_type loc;
+
+    if (ns.size() > 0) {
+      while ((loc = ns.find(".")) != std::string::npos) {
+        result += ns.substr(0, loc);
+        result += "::";
+        ns = ns.substr(loc + 1);
+      }
+
+      if (ns.size() > 0) {
+        result += ns + "::";
+      }
+    }
+
+    return result;
+  }
+
+  std::string get_namespace_out_dir() {
+    std::string outdir = get_out_dir();
+    std::list<std::string> dirs;
+    perl_namespace_dirs(program_, dirs);
+    std::list<std::string>::iterator it;
+    for (it = dirs.begin(); it != dirs.end(); it++) {
+      outdir += *it + "/";
+    }
+    return outdir;
+  }
+
+private:
+  /**
+   * File streams
+   */
+  ofstream_with_content_based_conditional_update f_types_;
+  ofstream_with_content_based_conditional_update f_consts_;
+  ofstream_with_content_based_conditional_update f_helpers_;
+  ofstream_with_content_based_conditional_update f_service_;
+
+  bool f_types_use_includes_emitted_;
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_perl_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  string outdir = get_out_dir();
+  std::list<std::string> dirs;
+  perl_namespace_dirs(program_, dirs);
+  std::list<std::string>::iterator it;
+  for (it = dirs.begin(); it != dirs.end(); it++) {
+    outdir += *it + "/";
+    MKDIR(outdir.c_str());
+  }
+
+  // Make output file
+  string f_types_name = outdir + "Types.pm";
+  f_types_.open(f_types_name.c_str());
+  string f_consts_name = outdir + "Constants.pm";
+  f_consts_.open(f_consts_name.c_str());
+
+  // Print header
+  f_types_ << autogen_comment() << perl_includes();
+
+  // Print header
+  f_consts_ << autogen_comment() << "package " << perl_namespace(program_) << "Constants;" << endl
+            << perl_includes() << endl;
+}
+
+/**
+ * Prints standard java imports
+ */
+string t_perl_generator::perl_includes() {
+  string inc;
+
+  inc  = "use 5.10.0;\n";
+  inc += "use strict;\n";
+  inc += "use warnings;\n";
+  inc += "use Thrift::Exception;\n";
+  inc += "use Thrift::MessageType;\n";
+  inc += "use Thrift::Type;\n\n";
+
+  return inc;
+}
+
+/**
+ * Close up (or down) some filez.
+ */
+void t_perl_generator::close_generator() {
+  // Close types file
+  f_types_ << "1;" << endl;
+  f_types_.close();
+
+  f_consts_ << "1;" << endl;
+  f_consts_.close();
+}
+
+/**
+ * Generates a typedef. This is not done in PERL, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_perl_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+/**
+ * Generates code for an enumerated type. Since define is expensive to lookup
+ * in PERL, we use a global array for this.
+ *
+ * @param tenum The enumeration
+ */
+void t_perl_generator::generate_enum(t_enum* tenum) {
+  f_types_ << "package " << perl_namespace(program_) << tenum->get_name() << ";" << endl;
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    f_types_ << "use constant " << (*c_iter)->get_name() << " => " << value << ";" << endl;
+  }
+}
+
+/**
+ * Generate a constant value
+ */
+void t_perl_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  f_consts_ << "use constant " << name << " => ";
+  f_consts_ << render_const_value(type, value);
+  f_consts_ << ";" << endl << 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_perl_generator::render_const_value(t_type* type, t_const_value* value) {
+  std::ostringstream out;
+
+  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_STRING:
+      out << '"' << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "1" : "0");
+      break;
+    case t_base_type::TYPE_I8:
+    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()) {
+    out << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    out << perl_namespace(type->get_program()) << type->get_name() << "->new({" << 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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::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();
+      }
+      indent(out) << render_const_value(g_type_string, v_iter->first);
+      out << " => ";
+      out << render_const_value(field_type, v_iter->second);
+      out << ",";
+      out << endl;
+    }
+    indent_down();
+    indent(out) << "})";
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    out << "{" << endl;
+    indent_up();
+
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      indent(out) << render_const_value(ktype, v_iter->first);
+      out << " => ";
+      out << render_const_value(vtype, v_iter->second);
+      out << "," << endl;
+    }
+    indent_down();
+    indent(out) << "}";
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    out << "[" << endl;
+    indent_up();
+
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+
+      indent(out) << render_const_value(etype, *v_iter);
+      if (type->is_set()) {
+        out << " => 1";
+      }
+      out << "," << endl;
+    }
+    indent_down();
+    indent(out) << "]";
+  }
+  return out.str();
+}
+
+/**
+ * Make a struct
+ */
+void t_perl_generator::generate_struct(t_struct* tstruct) {
+  generate_perl_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_perl_generator::generate_xception(t_struct* txception) {
+  generate_perl_struct(txception, true);
+}
+
+/**
+ * Structs can be normal or exceptions.
+ */
+void t_perl_generator::generate_perl_struct(t_struct* tstruct, bool is_exception) {
+  generate_use_includes(f_types_, f_types_use_includes_emitted_, tstruct, false);
+  generate_perl_struct_definition(f_types_, tstruct, is_exception);
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This is nothing in PERL
+ * where the objects are all just associative arrays (unless of course we
+ * decide to start using objects for them...)
+ *
+ * @param tstruct The struct definition
+ */
+void t_perl_generator::generate_perl_struct_definition(ostream& out,
+                                                       t_struct* tstruct,
+                                                       bool is_exception) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  out << "package " << perl_namespace(tstruct->get_program()) << tstruct->get_name() << ";\n";
+  if (is_exception) {
+    out << "use base qw(Thrift::TException);\n";
+  }
+
+  // Create simple acessor methods
+  out << "use base qw(Class::Accessor);\n";
+
+  if (members.size() > 0) {
+    out << perl_namespace(tstruct->get_program()) << tstruct->get_name() << "->mk_accessors( qw( ";
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+      if (!t->is_xception()) {
+        out << (*m_iter)->get_name() << " ";
+      }
+    }
+
+    out << ") );\n";
+  }
+
+  out << endl;
+
+  // new()
+  indent_up();
+  out << "sub new {" << endl << indent() << "my $classname = shift;" << endl << indent()
+      << "my $self      = {};" << endl << indent() << "my $vals      = shift || {};" << endl;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    string dval = "undef";
+    t_type* t = get_true_type((*m_iter)->get_type());
+    if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) {
+      dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value());
+    }
+    out << indent() << "$self->{" << (*m_iter)->get_name() << "} = " << dval << ";" << endl;
+  }
+
+  // Generate constructor from array
+  if (members.size() > 0) {
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+      if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) {
+        indent(out) << "$self->{" << (*m_iter)->get_name()
+                    << "} = " << render_const_value(t, (*m_iter)->get_value()) << ";" << endl;
+      }
+    }
+
+    out << indent() << "if (UNIVERSAL::isa($vals,'HASH')) {" << endl;
+    indent_up();
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      out << indent() << "if (defined $vals->{" << (*m_iter)->get_name() << "}) {" << endl
+          << indent() << "  $self->{" << (*m_iter)->get_name() << "} = $vals->{"
+          << (*m_iter)->get_name() << "};" << endl << indent() << "}" << endl;
+    }
+    indent_down();
+    out << indent() << "}" << endl;
+  }
+
+  out << indent() << "return bless ($self, $classname);" << endl;
+  indent_down();
+  out << "}\n\n";
+
+  out << "sub getName {" << endl << indent() << "  return '" << tstruct->get_name() << "';" << endl
+      << indent() << "}" << endl << endl;
+
+  generate_perl_struct_reader(out, tstruct);
+  generate_perl_struct_writer(out, tstruct);
+}
+
+/**
+ * Generates the read() method for a struct
+ */
+void t_perl_generator::generate_perl_struct_reader(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out << "sub read {" << endl;
+
+  indent_up();
+
+  out << indent() << "my ($self, $input) = @_;" << endl << indent() << "my $xfer  = 0;" << endl
+      << indent() << "my $fname;" << endl << indent() << "my $ftype = 0;" << endl << indent()
+      << "my $fid   = 0;" << endl;
+
+  indent(out) << "$xfer += $input->readStructBegin(\\$fname);" << endl;
+
+  // Loop over reading in fields
+  indent(out) << "while (1)" << endl;
+
+  scope_up(out);
+
+  indent(out) << "$xfer += $input->readFieldBegin(\\$fname, \\$ftype, \\$fid);" << endl;
+
+  // Check for field STOP marker and break
+  indent(out) << "if ($ftype == Thrift::TType::STOP) {" << endl;
+  indent_up();
+  indent(out) << "last;" << endl;
+  indent_down();
+  indent(out) << "}" << endl;
+
+  // Switch statement on the field we are reading
+  indent(out) << "SWITCH: for($fid)" << endl;
+
+  scope_up(out);
+
+  // Generate deserialization code for known cases
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+
+    indent(out) << "/^" << (*f_iter)->get_key() << "$/ && do{";
+    indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+
+    indent_up();
+    generate_deserialize_field(out, *f_iter, "self->");
+    indent_down();
+
+    indent(out) << "} else {" << endl;
+
+    indent(out) << "  $xfer += $input->skip($ftype);" << endl;
+
+    out << indent() << "}" << endl << indent() << "last; };" << endl;
+  }
+  // In the default case we skip the field
+
+  indent(out) << "  $xfer += $input->skip($ftype);" << endl;
+
+  scope_down(out);
+
+  indent(out) << "$xfer += $input->readFieldEnd();" << endl;
+
+  scope_down(out);
+
+  indent(out) << "$xfer += $input->readStructEnd();" << endl;
+
+  indent(out) << "return $xfer;" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates the write() method for a struct
+ */
+void t_perl_generator::generate_perl_struct_writer(ostream& out, t_struct* tstruct) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out << "sub write {" << endl;
+
+  indent_up();
+  indent(out) << "my ($self, $output) = @_;" << endl;
+  indent(out) << "my $xfer   = 0;" << endl;
+
+  indent(out) << "$xfer += $output->writeStructBegin('" << name << "');" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    out << indent() << "if (defined $self->{" << (*f_iter)->get_name() << "}) {" << endl;
+    indent_up();
+
+    indent(out) << "$xfer += $output->writeFieldBegin("
+                << "'" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type())
+                << ", " << (*f_iter)->get_key() << ");" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "self->");
+
+    indent(out) << "$xfer += $output->writeFieldEnd();" << endl;
+
+    indent_down();
+    indent(out) << "}" << endl;
+  }
+
+  out << indent() << "$xfer += $output->writeFieldStop();" << endl << indent()
+      << "$xfer += $output->writeStructEnd();" << endl;
+
+  out << indent() << "return $xfer;" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+}
+
+/**
+ * Generates use clauses for included entities
+ *
+ * @param  os       The output stream
+ * @param  done     A flag reference to debounce the action
+ * @param  type     The type being processed
+ * @param  selfish  Flag to indicate if the current namespace types should be "use"d as well.
+ */
+void t_perl_generator::generate_use_includes(std::ostream& os, bool& done, t_type *type, bool selfish) {
+  t_program *current = type->get_program();
+  if (current && !done) {
+    std::vector<t_program*>& currInc = current->get_includes();
+    std::vector<t_program*>::size_type numInc = currInc.size();
+    if (selfish) {
+      os << "use " << perl_namespace(current) << "Types;" << endl;
+    }
+    for (std::vector<t_program*>::size_type i = 0; i < numInc; ++i) {
+      t_program* incProgram = currInc.at(i);
+      os << "use " << perl_namespace(incProgram) << "Types;" << endl;
+    }
+    os << endl;
+    done = true;
+  }
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_perl_generator::generate_service(t_service* tservice) {
+  string f_service_name = get_namespace_out_dir() + service_name_ + ".pm";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << autogen_comment() << perl_includes();
+
+  bool done = false;
+  generate_use_includes(f_service_, done, tservice, true);
+
+  t_service* extends_s = tservice->get_extends();
+  if (extends_s != NULL) {
+    f_service_ << "use " << perl_namespace(extends_s->get_program()) << extends_s->get_name() << ";"
+               << endl;
+  }
+
+  f_service_ << endl;
+
+  // Generate the three main parts of the service (well, two for now in PERL)
+  generate_service_helpers(tservice);
+  generate_service_interface(tservice);
+  generate_service_rest(tservice);
+  generate_service_client(tservice);
+  generate_service_processor(tservice);
+
+  // Close service file
+  f_service_ << "1;" << endl;
+  f_service_.close();
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_perl_generator::generate_service_processor(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 = "";
+  t_service* extends_s = tservice->get_extends();
+  if (extends_s != NULL) {
+    extends = perl_namespace(extends_s->get_program()) + extends_s->get_name();
+    extends_processor = "use base qw(" + extends + "Processor);";
+  }
+
+  indent_up();
+
+  // Generate the header portion
+  f_service_ << "package " << perl_namespace(program_) << service_name_ << "Processor;" << endl
+             << endl << "use strict;" << endl << extends_processor << endl << endl;
+
+  if (extends.empty()) {
+    f_service_ << "sub new {" << endl;
+
+    indent_up();
+
+    f_service_ << indent() << "my ($classname, $handler) = @_;" << endl << indent()
+               << "my $self      = {};" << endl;
+
+    f_service_ << indent() << "$self->{handler} = $handler;" << endl;
+
+    f_service_ << indent() << "return bless ($self, $classname);" << endl;
+
+    indent_down();
+
+    f_service_ << "}" << endl << endl;
+  }
+
+  // Generate the server implementation
+  f_service_ << "sub process {" << endl;
+  indent_up();
+
+  f_service_ << indent() << "my ($self, $input, $output) = @_;" << endl;
+
+  f_service_ << indent() << "my $rseqid = 0;" << endl << indent() << "my $fname  = undef;" << endl
+             << indent() << "my $mtype  = 0;" << endl << endl;
+
+  f_service_ << indent() << "$input->readMessageBegin(\\$fname, \\$mtype, \\$rseqid);" << endl;
+
+  // HOT: check for method implementation
+  f_service_ << indent() << "my $methodname = 'process_'.$fname;" << endl << indent()
+             << "if (!$self->can($methodname)) {" << endl;
+  indent_up();
+
+  f_service_ << indent() << "$input->skip(Thrift::TType::STRUCT);" << endl << indent()
+             << "$input->readMessageEnd();" << endl << indent()
+             << "my $x = Thrift::TApplicationException->new('Function '.$fname.' not implemented.', "
+                "Thrift::TApplicationException::UNKNOWN_METHOD);" << endl << indent()
+             << "$output->writeMessageBegin($fname, Thrift::TMessageType::EXCEPTION, $rseqid);" << endl
+             << indent() << "$x->write($output);" << endl << indent()
+             << "$output->writeMessageEnd();" << endl << indent()
+             << "$output->getTransport()->flush();" << endl << indent() << "return;" << endl;
+
+  indent_down();
+  f_service_ << indent() << "}" << endl << indent()
+             << "$self->$methodname($rseqid, $input, $output);" << endl << indent() << "return 1;"
+             << endl;
+
+  indent_down();
+
+  f_service_ << "}" << endl << endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(tservice, *f_iter);
+  }
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_perl_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  // Open function
+  f_service_ << "sub process_" << tfunction->get_name() << " {" << endl;
+
+  indent_up();
+
+  f_service_ << indent() << "my ($self, $seqid, $input, $output) = @_;" << endl;
+
+  string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_"
+                    + tfunction->get_name() + "_args";
+  string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_"
+                      + tfunction->get_name() + "_result";
+
+  f_service_ << indent() << "my $args = " << argsname << "->new();" << endl << indent()
+             << "$args->read($input);" << endl;
+
+  f_service_ << indent() << "$input->readMessageEnd();" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << "my $result = " << resultname << "->new();" << endl;
+  }
+
+  // Try block for a function with exceptions
+  if (xceptions.size() > 0) {
+    f_service_ << indent() << "eval {" << endl;
+    indent_up();
+  }
+
+  // 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_ << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "$result->{success} = ";
+  }
+  f_service_ << "$self->{handler}->" << 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->" << (*f_iter)->get_name();
+  }
+  f_service_ << ");" << endl;
+
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    indent_down();
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_ << indent() << "}; if( UNIVERSAL::isa($@,'"
+                 << perl_namespace((*x_iter)->get_type()->get_program())
+                 << (*x_iter)->get_type()->get_name() << "') ){ " << endl;
+
+      indent_up();
+      f_service_ << indent() << "$result->{" << (*x_iter)->get_name() << "} = $@;" << endl;
+      f_service_ << indent() << "$@ = undef;" << endl;
+      indent_down();
+      f_service_ << indent();
+    }
+    f_service_ << "}" << endl;
+
+    // catch-all for unexpected exceptions (THRIFT-3191)
+    f_service_ << indent() << "if ($@) {" << endl;
+    indent_up();
+    f_service_ << indent() << "$@ =~ s/^\\s+|\\s+$//g;" << endl
+               << indent() << "my $err = Thrift::TApplicationException->new(\"Unexpected Exception: \" . $@, Thrift::TApplicationException::INTERNAL_ERROR);" << endl
+               << indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', Thrift::TMessageType::EXCEPTION, $seqid);" << endl
+               << indent() << "$err->write($output);" << endl
+               << indent() << "$output->writeMessageEnd();" << endl
+               << indent() << "$output->getTransport()->flush();" << endl
+               << indent() << "$@ = undef;" << endl
+               << indent() << "return;" << endl;
+    indent_down();
+    f_service_ << indent() << "}" << endl;
+  }
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    f_service_ << indent() << "return;" << endl;
+    indent_down();
+    f_service_ << "}" << endl;
+    return;
+  }
+
+  // Serialize the reply
+  f_service_ << indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', Thrift::TMessageType::REPLY, $seqid);" << endl
+             << indent() << "$result->write($output);" << endl
+             << indent() << "$output->writeMessageEnd();" << endl
+             << indent() << "$output->getTransport()->flush();" << endl;
+
+  // Close function
+  indent_down();
+  f_service_ << "}" << endl << endl;
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_perl_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();
+    string name = ts->get_name();
+    ts->set_name(service_name_ + "_" + name);
+    generate_perl_struct_definition(f_service_, ts, false);
+    generate_perl_function_helpers(*f_iter);
+    ts->set_name(name);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_perl_generator::generate_perl_function_helpers(t_function* tfunction) {
+  t_struct result(program_, service_name_ + "_" + 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_perl_struct_definition(f_service_, &result, false);
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_perl_generator::generate_service_interface(t_service* tservice) {
+  string extends_if = "";
+  t_service* extends_s = tservice->get_extends();
+  if (extends_s != NULL) {
+    extends_if = "use base qw(" + perl_namespace(extends_s->get_program()) + extends_s->get_name()
+                 + "If);";
+  }
+
+  f_service_ << "package " << perl_namespace(program_) << service_name_ << "If;" << endl << endl
+             << "use strict;" << endl << extends_if << endl << endl;
+
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << "sub " << function_signature(*f_iter) << endl << "  die 'implement interface';\n}"
+               << endl << endl;
+  }
+  indent_down();
+}
+
+/**
+ * Generates a REST interface
+ */
+void t_perl_generator::generate_service_rest(t_service* tservice) {
+  string extends = "";
+  string extends_if = "";
+  t_service* extends_s = tservice->get_extends();
+  if (extends_s != NULL) {
+    extends = extends_s->get_name();
+    extends_if = "use base qw(" + perl_namespace(extends_s->get_program()) + extends_s->get_name()
+                 + "Rest);";
+  }
+  f_service_ << "package " << perl_namespace(program_) << service_name_ << "Rest;" << endl << endl
+             << "use strict;" << endl << extends_if << endl << endl;
+
+  if (extends.empty()) {
+    f_service_ << "sub new {" << endl;
+
+    indent_up();
+
+    f_service_ << indent() << "my ($classname, $impl) = @_;" << endl << indent()
+               << "my $self     ={ impl => $impl };" << endl << endl << indent()
+               << "return bless($self,$classname);" << endl;
+
+    indent_down();
+
+    f_service_ << "}" << endl << endl;
+  }
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << "sub " << (*f_iter)->get_name() << "{" << endl;
+
+    indent_up();
+
+    f_service_ << indent() << "my ($self, $request) = @_;" << endl << endl;
+
+    const vector<t_field*>& args = (*f_iter)->get_arglist()->get_members();
+    vector<t_field*>::const_iterator a_iter;
+    for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
+      t_type* atype = get_true_type((*a_iter)->get_type());
+      string req = "$request->{'" + (*a_iter)->get_name() + "'}";
+      f_service_ << indent() << "my $" << (*a_iter)->get_name() << " = (" << req << ") ? " << req
+                 << " : undef;" << endl;
+      if (atype->is_string() && ((t_base_type*)atype)->is_string_list()) {
+        f_service_ << indent() << "my @" << (*a_iter)->get_name() << " = split(/,/, $"
+                   << (*a_iter)->get_name() << ");" << endl << indent() << "$"
+                   << (*a_iter)->get_name() << " = \\@" << (*a_iter)->get_name() << endl;
+      }
+    }
+    f_service_ << indent() << "return $self->{impl}->" << (*f_iter)->get_name() << "("
+               << argument_list((*f_iter)->get_arglist()) << ");" << endl;
+    indent_down();
+    indent(f_service_) << "}" << endl << endl;
+  }
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_perl_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  t_service* extends_s = tservice->get_extends();
+  if (extends_s != NULL) {
+    extends = perl_namespace(extends_s->get_program()) + extends_s->get_name();
+    extends_client = "use base qw(" + extends + "Client);";
+  }
+
+  f_service_ << "package " << perl_namespace(program_) << service_name_ << "Client;" << endl << endl
+             << extends_client << endl << "use base qw(" << perl_namespace(program_)
+             << service_name_ << "If);" << endl;
+
+  // Constructor function
+  f_service_ << "sub new {" << endl;
+
+  indent_up();
+
+  f_service_ << indent() << "my ($classname, $input, $output) = @_;" << endl << indent()
+             << "my $self      = {};" << endl;
+
+  if (!extends.empty()) {
+    f_service_ << indent() << "$self = $classname->SUPER::new($input, $output);" << endl;
+  } else {
+    f_service_ << indent() << "$self->{input}  = $input;" << endl << indent()
+               << "$self->{output} = defined $output ? $output : $input;" << endl << indent()
+               << "$self->{seqid}  = 0;" << endl;
+  }
+
+  f_service_ << indent() << "return bless($self,$classname);" << endl;
+
+  indent_down();
+
+  f_service_ << "}" << 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 = (*f_iter)->get_name();
+
+    // Open function
+    f_service_ << "sub " << function_signature(*f_iter) << endl;
+
+    indent_up();
+
+    indent(f_service_) << indent() << "$self->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;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_ << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "return ";
+      }
+      f_service_ << "$self->recv_" << funname << "();" << endl;
+    }
+
+    indent_down();
+
+    f_service_ << "}" << endl << endl;
+
+    f_service_ << "sub send_" << function_signature(*f_iter) << endl;
+
+    indent_up();
+
+    std::string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_"
+                           + (*f_iter)->get_name() + "_args";
+
+    // Serialize the request header
+    f_service_ << indent() << "$self->{output}->writeMessageBegin('" << (*f_iter)->get_name()
+               << "', " << ((*f_iter)->is_oneway() ? "Thrift::TMessageType::ONEWAY" : "Thrift::TMessageType::CALL")
+               << ", $self->{seqid});" << endl;
+
+    f_service_ << indent() << "my $args = " << argsname << "->new();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << indent() << "$args->{" << (*fld_iter)->get_name() << "} = $"
+                 << (*fld_iter)->get_name() << ";" << endl;
+    }
+
+    // Write to the stream
+    f_service_ << indent() << "$args->write($self->{output});" << endl << indent()
+               << "$self->{output}->writeMessageEnd();" << endl << indent()
+               << "$self->{output}->getTransport()->flush();" << endl;
+
+    indent_down();
+
+    f_service_ << "}" << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_"
+                               + (*f_iter)->get_name() + "_result";
+      t_struct noargs(program_);
+
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+      // Open function
+      f_service_ << endl << "sub " << function_signature(&recv_function) << endl;
+
+      indent_up();
+
+      f_service_ << indent() << "my $rseqid = 0;" << endl << indent() << "my $fname;" << endl
+                 << indent() << "my $mtype = 0;" << endl << endl;
+
+      f_service_ << indent() << "$self->{input}->readMessageBegin(\\$fname, \\$mtype, \\$rseqid);"
+                 << endl << indent() << "if ($mtype == Thrift::TMessageType::EXCEPTION) {" << endl
+                 << indent() << "  my $x = Thrift::TApplicationException->new();" << endl << indent()
+                 << "  $x->read($self->{input});" << endl << indent()
+                 << "  $self->{input}->readMessageEnd();" << endl << indent() << "  die $x;" << endl
+                 << indent() << "}" << endl;
+
+      f_service_ << indent() << "my $result = " << resultname << "->new();" << endl << indent()
+                 << "$result->read($self->{input});" << endl;
+
+      f_service_ << indent() << "$self->{input}->readMessageEnd();" << endl << endl;
+
+      // Careful, only return result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << indent() << "if (defined $result->{success} ) {" << endl << indent()
+                   << "  return $result->{success};" << endl << indent() << "}" << 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 (defined $result->{" << (*x_iter)->get_name() << "}) {"
+                   << endl << indent() << "  die $result->{" << (*x_iter)->get_name() << "};"
+                   << endl << indent() << "}" << endl;
+      }
+
+      // Careful, only return _result if not a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) << "return;" << endl;
+      } else {
+        f_service_ << indent() << "die \"" << (*f_iter)->get_name() << " failed: unknown result\";"
+                   << endl;
+      }
+
+      // Close function
+      indent_down();
+      f_service_ << "}" << endl;
+    }
+  }
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_perl_generator::generate_deserialize_field(ostream& out,
+                                                  t_field* tfield,
+                                                  string prefix,
+                                                  bool inclass) {
+  (void)inclass;
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = tfield->get_name();
+
+  // Hack for when prefix is defined (always a hash ref)
+  if (!prefix.empty()) {
+    name = prefix + "{" + tfield->get_name() + "}";
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) << "$xfer += $input->";
+
+    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(\\$" << name << ");";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "readBool(\\$" << name << ");";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "readByte(\\$" << name << ");";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "readI16(\\$" << name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "readI32(\\$" << name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "readI64(\\$" << name << ");";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "readDouble(\\$" << name << ");";
+        break;
+      default:
+        throw "compiler error: no PERL name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "readI32(\\$" << name << ");";
+    }
+    out << endl;
+
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a variable. This makes two key assumptions,
+ * first that there is a const char* variable named data that points to the
+ * buffer for deserialization, and that there is a variable protocol which
+ * is a reference to a TProtocol serialization object.
+ */
+void t_perl_generator::generate_deserialize_struct(ostream& out,
+                                                   t_struct* tstruct,
+                                                   string prefix) {
+  out << indent() << "$" << prefix << " = " << perl_namespace(tstruct->get_program())
+      << tstruct->get_name() << "->new();" << endl << indent() << "$xfer += $" << prefix
+      << "->read($input);" << endl;
+}
+
+void t_perl_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  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_i8, ktype);
+  t_field fvtype(g_type_i8, vtype);
+  t_field fetype(g_type_i8, etype);
+
+  out << indent() << "my $" << size << " = 0;" << endl;
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    out << indent() << "$" << prefix << " = {};" << endl << indent() << "my $" << ktype << " = 0;"
+        << endl << indent() << "my $" << vtype << " = 0;" << endl;
+
+    out << indent() << "$xfer += $input->readMapBegin("
+        << "\\$" << ktype << ", \\$" << vtype << ", \\$" << size << ");" << endl;
+
+  } else if (ttype->is_set()) {
+
+    out << indent() << "$" << prefix << " = {};" << endl << indent() << "my $" << etype << " = 0;"
+        << endl << indent() << "$xfer += $input->readSetBegin("
+        << "\\$" << etype << ", \\$" << size << ");" << endl;
+
+  } else if (ttype->is_list()) {
+
+    out << indent() << "$" << prefix << " = [];" << endl << indent() << "my $" << etype << " = 0;"
+        << endl << indent() << "$xfer += $input->readListBegin("
+        << "\\$" << etype << ", \\$" << size << ");" << endl;
+  }
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) << "for (my $" << i << " = 0; $" << i << " < $" << size << "; ++$" << i << ")"
+              << endl;
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  scope_down(out);
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "$xfer += $input->readMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "$xfer += $input->readSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "$xfer += $input->readListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_perl_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) {
+  string key = tmp("key");
+  string val = tmp("val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) << declare_field(&fkey, true, true) << endl;
+  indent(out) << declare_field(&fval, true, true) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) << "$" << prefix << "->{$" << key << "} = $" << val << ";" << endl;
+}
+
+void t_perl_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) {
+  string elem = tmp("elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) << "my $" << elem << " = undef;" << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << "$" << prefix << "->{$" << elem << "} = 1;" << endl;
+}
+
+void t_perl_generator::generate_deserialize_list_element(ostream& out,
+                                                         t_list* tlist,
+                                                         string prefix) {
+  string elem = tmp("elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) << "my $" << elem << " = undef;" << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << "push(@{$" << prefix << "},$" << elem << ");" << endl;
+}
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_perl_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, prefix + "{" + tfield->get_name() + "}");
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, prefix + "{" + tfield->get_name() + "}");
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    string name = tfield->get_name();
+
+    // Hack for when prefix is defined (always a hash ref)
+    if (!prefix.empty())
+      name = prefix + "{" + tfield->get_name() + "}";
+
+    indent(out) << "$xfer += $output->";
+
+    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($" << name << ");";
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool($" << name << ");";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "writeByte($" << name << ");";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16($" << name << ");";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32($" << name << ");";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64($" << name << ");";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble($" << name << ");";
+        break;
+      default:
+        throw "compiler error: no PERL name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32($" << name << ");";
+    }
+    out << endl;
+
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_perl_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  (void)tstruct;
+  indent(out) << "$xfer += $" << prefix << "->write($output);" << endl;
+}
+
+/**
+ * Writes out a container
+ */
+void t_perl_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "$xfer += $output->writeMapBegin("
+                << type_to_enum(((t_map*)ttype)->get_key_type()) << ", "
+                << type_to_enum(((t_map*)ttype)->get_val_type()) << ", "
+                << "scalar(keys %{$" << prefix << "}));" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "$xfer += $output->writeSetBegin("
+                << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", "
+                << "scalar(@{$" << prefix << "}));" << endl;
+
+  } else if (ttype->is_list()) {
+
+    indent(out) << "$xfer += $output->writeListBegin("
+                << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", "
+                << "scalar(@{$" << prefix << "}));" << endl;
+  }
+
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    string kiter = tmp("kiter");
+    string viter = tmp("viter");
+    indent(out) << "while( my ($" << kiter << ",$" << viter << ") = each %{$" << prefix << "}) "
+                << endl;
+
+    scope_up(out);
+    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
+    scope_down(out);
+
+  } else if (ttype->is_set()) {
+    string iter = tmp("iter");
+    indent(out) << "foreach my $" << iter << " (@{$" << prefix << "})" << endl;
+    scope_up(out);
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+    scope_down(out);
+
+  } else if (ttype->is_list()) {
+    string iter = tmp("iter");
+    indent(out) << "foreach my $" << iter << " (@{$" << prefix << "}) " << endl;
+    scope_up(out);
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+    scope_down(out);
+  }
+
+  scope_down(out);
+
+  if (ttype->is_map()) {
+    indent(out) << "$xfer += $output->writeMapEnd();" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "$xfer += $output->writeSetEnd();" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "$xfer += $output->writeListEnd();" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_perl_generator::generate_serialize_map_element(ostream& out,
+                                                      t_map* tmap,
+                                                      string kiter,
+                                                      string viter) {
+  t_field kfield(tmap->get_key_type(), kiter);
+  generate_serialize_field(out, &kfield);
+
+  t_field vfield(tmap->get_val_type(), viter);
+  generate_serialize_field(out, &vfield);
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_perl_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield);
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_perl_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield);
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_perl_generator::declare_field(t_field* tfield, bool init, bool obj) {
+  string result = "my $" + tfield->get_name();
+  if (init) {
+    t_type* type = get_true_type(tfield->get_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:
+        break;
+      case t_base_type::TYPE_STRING:
+        result += " = ''";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = 0.0";
+        break;
+      default:
+        throw "compiler error: no PERL initializer for base type "
+            + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      result += " = 0";
+    } else if (type->is_container()) {
+      result += " = []";
+    } else if (type->is_struct() || type->is_xception()) {
+      if (obj) {
+        result += " = " + perl_namespace(type->get_program()) + type->get_name() + "->new()";
+      } else {
+        result += " = undef";
+      }
+    }
+  }
+  return result + ";";
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_perl_generator::function_signature(t_function* tfunction, string prefix) {
+
+  string str;
+
+  str = prefix + tfunction->get_name() + "{\n";
+  str += "  my $self = shift;\n";
+
+  // Need to create perl function arg inputs
+  const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    str += "  my $" + (*f_iter)->get_name() + " = shift;\n";
+  }
+
+  return str;
+}
+
+/**
+ * Renders a field list
+ */
+string t_perl_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();
+  }
+  return result;
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ */
+string t_perl_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::TType::STRING";
+    case t_base_type::TYPE_BOOL:
+      return "Thrift::TType::BOOL";
+    case t_base_type::TYPE_I8:
+      return "Thrift::TType::BYTE";
+    case t_base_type::TYPE_I16:
+      return "Thrift::TType::I16";
+    case t_base_type::TYPE_I32:
+      return "Thrift::TType::I32";
+    case t_base_type::TYPE_I64:
+      return "Thrift::TType::I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "Thrift::TType::DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "Thrift::TType::I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "Thrift::TType::STRUCT";
+  } else if (type->is_map()) {
+    return "Thrift::TType::MAP";
+  } else if (type->is_set()) {
+    return "Thrift::TType::SET";
+  } else if (type->is_list()) {
+    return "Thrift::TType::LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(perl, "Perl", "")
diff --git a/compiler/cpp/src/thrift/generate/t_php_generator.cc b/compiler/cpp/src/thrift/generate/t_php_generator.cc
new file mode 100644
index 0000000..50a4415
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_php_generator.cc
@@ -0,0 +1,2785 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+#define NSGLOBAL (nsglobal_.size() ? nsglobal_ : "")
+#define NSGLOBAL_A ("\\" + NSGLOBAL)
+#define NSGLOBAL_B (NSGLOBAL + "\\")
+#define NSGLOBAL_AB ("\\" + NSGLOBAL + "\\")
+
+/**
+ * PHP code generator.
+ *
+ */
+class t_php_generator : public t_oop_generator {
+public:
+  t_php_generator(t_program* program,
+                  const std::map<std::string, std::string>& parsed_options,
+                  const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    binary_inline_ = false;
+    rest_ = false;
+    phps_ = false;
+    oop_ = false;
+    validate_ = false;
+    json_serializable_ = false;
+    nsglobal_ = ""; // by default global namespace is empty
+    classmap_ = false;
+    for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if (iter->first.compare("inlined") == 0) {
+        binary_inline_ = true;
+      } else if (iter->first.compare("rest") == 0) {
+        rest_ = true;
+      } else if (iter->first.compare("server") == 0) {
+        phps_ = true;
+      } else if (iter->first.compare("oop") == 0) {
+        oop_ = true;
+      } else if (iter->first.compare("validate") == 0) {
+        validate_ = true;
+      } else if (iter->first.compare("json") == 0) {
+        json_serializable_ = true;
+      } else if (iter->first.compare("nsglobal") == 0) {
+        nsglobal_ = iter->second;
+      } else if (iter->first.compare("classmap") == 0) {
+        classmap_ = true;
+      } else if (iter->first.compare("psr4") == 0) {
+        if(classmap_){
+          throw "psr4 and classmap are mutually exclusive.";
+        } else {
+          pwarning(0, "psr4 is default option! needn't add psr4 option!\n");
+        }
+      } else {
+        throw "unknown option php:" + iter->first;
+      }
+    }
+
+    if (oop_ && binary_inline_) {
+      throw "oop and inlined are mutually exclusive.";
+    }
+
+    out_dir_base_ = (binary_inline_ ? "gen-phpi" : "gen-php");
+    escape_['$'] = "\\$";
+  }
+
+  virtual std::string indent_str() const {
+    return "    ";
+  }
+
+  static bool is_valid_namespace(const std::string& sub_namespace);
+
+  /**
+   * 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_consts(vector<t_const*> consts);
+  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);
+
+  /**
+   * Structs!
+   */
+
+  void generate_php_struct(t_struct* tstruct, bool is_exception);
+  void generate_php_struct_definition(std::ostream& out,
+                                      t_struct* tstruct,
+                                      bool is_xception = false,
+                                      bool is_result = false);
+  void generate_php_struct_reader(std::ostream& out, t_struct* tstruct, bool is_result);
+  void generate_php_struct_writer(std::ostream& out, t_struct* tstruct, bool is_result);
+  void generate_php_function_helpers(t_service* tservice, t_function* tfunction);
+  void generate_php_struct_required_validator(ostream& out,
+                                              t_struct* tstruct,
+                                              std::string method_name,
+                                              bool write_mode);
+  void generate_php_struct_read_validator(ostream& out, t_struct* tstruct);
+  void generate_php_struct_write_validator(ostream& out, t_struct* tstruct);
+  void generate_php_struct_json_serialize(ostream& out, t_struct* tstruct, bool is_result);
+  bool needs_php_write_validator(t_struct* tstruct, bool is_result);
+  bool needs_php_read_validator(t_struct* tstruct, bool is_result);
+  int get_php_num_required_fields(const vector<t_field*>& fields, bool write_mode);
+
+  void generate_php_type_spec(std::ostream& out, t_type* t);
+  void generate_php_struct_spec(std::ostream& out, t_struct* tstruct);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_interface(t_service* tservice);
+  void generate_service_rest(t_service* tservice);
+  void generate_service_client(t_service* tservice);
+  void generate_service_processor(t_service* tservice);
+  void generate_process_function(std::ostream& out, t_service* tservice, t_function* tfunction);
+  void generate_service_header(t_service* tservice, std::ostream& file);
+  void generate_program_header(std::ostream& file);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field(std::ostream& out,
+                                  t_field* tfield,
+                                  std::string prefix = "",
+                                  bool inclass = false);
+
+  void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+
+  void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         std::string prefix = "");
+
+  void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
+
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string kiter,
+                                      std::string viter);
+
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  void generate_php_doc(std::ostream& out, t_doc* tdoc);
+
+  void generate_php_doc(std::ostream& out, t_field* tfield);
+
+  void generate_php_doc(std::ostream& out, t_function* tfunction);
+
+  void generate_php_docstring_comment(std::ostream& out, string contents);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string php_includes();
+  std::string declare_field(t_field* tfield, bool init = false, bool obj = false);
+  std::string function_signature(t_function* tfunction, std::string prefix = "");
+  std::string argument_list(t_struct* tstruct, bool addTypeHints = true);
+  std::string type_to_cast(t_type* ttype);
+  std::string type_to_enum(t_type* ttype);
+  std::string type_to_phpdoc(t_type* ttype);
+
+  bool php_is_scalar(t_type *ttype) {
+    ttype = ttype->get_true_type();
+    if(ttype->is_base_type()) {
+      return true;
+    } else if(ttype->is_enum()) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  std::string php_namespace_base(const t_program* p) {
+    std::string ns = p->get_namespace("php");
+    const char* delimiter = "\\";
+    size_t position = ns.find('.');
+    while (position != string::npos) {
+      ns.replace(position, 1, delimiter);
+      position = ns.find('.', position + 1);
+    }
+    return ns;
+  }
+
+  // general use namespace prefixing: \my\namespace\ or my_namespace_
+  string php_namespace(const t_program* p) {
+    string ns = php_namespace_base(p);
+    return (nsglobal_.size() ? NSGLOBAL_AB : NSGLOBAL_B) + (ns.size() ? (ns + "\\") : "");
+  }
+
+  // return the namespace of a file:
+  // global\ns\sub\ns or global\ns or sub\ns
+  string php_namespace_suffix(const t_program* p) {
+    string ns = php_namespace_base(p);
+
+    return NSGLOBAL
+      + (ns.size() && NSGLOBAL.size() ? "\\" : "")
+      + ns;
+  }
+
+  // add a directory to already existing namespace
+  string php_namespace_directory(string directory, bool end = true) {
+    (void)directory;
+    if (end) {
+      return ";";
+    } else {
+      return "";
+    }
+  }
+
+  // writing an autload identifier into globa;ls: my\namespace\ or my_namespace_
+  string php_namespace_autoload(const t_program* p) {
+    std::string ns = php_namespace_base(p);
+    return (nsglobal_.size() ? NSGLOBAL_B : NSGLOBAL) + (ns.size() ? (ns + "\\") : "");
+  }
+
+  // declaring a type: typename or my_namespace_typename
+  string php_namespace_declaration(t_type* t) { return t->get_name(); }
+
+  std::string php_path(t_program* p) {
+    std::string ns = p->get_namespace("php.path");
+    if (ns.empty()) {
+      return p->get_name();
+    }
+
+    // Transform the java-style namespace into a path.
+    for (std::string::iterator it = ns.begin(); it != ns.end(); ++it) {
+      if (*it == '.') {
+        *it = '/';
+      }
+    }
+
+    return ns + '/';
+  }
+
+  /**
+   * Transform class_method into ClassMethod
+   *
+   * @param str
+   * @return stirng
+   */
+  string classify(string str) {
+    string classe = "";
+
+    vector<string> x = split(str, '_');
+
+    for (size_t i = 0; i < x.size(); ++i) {
+      classe = classe + capitalize(x[i]);
+    }
+
+    return classe;
+  }
+
+  /**
+   * Split method
+   * @param s
+   * @param delim
+   * @param elems
+   * @return
+   */
+  vector<string>& split(const string& s, char delim, vector<string>& elems) {
+    stringstream ss(s);
+    string item;
+
+    while (getline(ss, item, delim)) {
+      elems.push_back(item);
+    }
+
+    return elems;
+  }
+
+  vector<string> split(const string& s, char delim) {
+    vector<string> elems;
+
+    return split(s, delim, elems);
+  }
+
+  /**
+   * Capitalize method
+   * @param str
+   * @return
+   */
+  string capitalize(string str) {
+    string::iterator it(str.begin());
+
+    if (it != str.end())
+      str[0] = toupper((unsigned char)str[0]);
+
+    //    while(++it != str.end())
+    //    {
+    //      *it = tolower((unsigned char)*it);
+    //    }
+    return str;
+  }
+
+private:
+  /**
+   * File streams
+   */
+  ofstream_with_content_based_conditional_update f_types_;
+  ofstream_with_content_based_conditional_update f_service_;
+
+  std::string package_dir_;
+  /**
+   * Generate protocol-independent template? Or Binary inline code?
+   */
+  bool binary_inline_;
+
+  /**
+   * Generate a REST handler class
+   */
+  bool rest_;
+
+  /**
+   * Generate stubs for a PHP server
+   */
+  bool phps_;
+
+  /**
+   * Whether to use OOP base class TBase
+   */
+  bool oop_;
+
+  /**
+   * Whether to generate old-style PHP file to use classmap autoloading
+   */
+  bool classmap_;
+
+  /**
+   * Whether to generate validator code
+   */
+  bool validate_;
+
+  /**
+   * Whether to generate JsonSerializable classes
+   */
+  bool json_serializable_;
+
+  /**
+   * Global namespace for PHP 5.3
+   */
+  std::string nsglobal_;
+};
+
+bool t_php_generator::is_valid_namespace(const std::string& sub_namespace) {
+  return sub_namespace == "path";
+}
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_php_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  // Create Real directory Namespaces
+  vector<string> NSx = split(php_namespace_suffix(get_program()), '\\');
+  package_dir_ = get_out_dir();
+
+  for (size_t i = 0; i < NSx.size(); ++i) {
+    package_dir_ = package_dir_ + "/" + NSx[i] + "/";
+    MKDIR(package_dir_.c_str());
+  }
+
+  // Prepare output file for all the types in classmap mode
+  if (classmap_) {
+    // Make output file
+    string f_types_name = package_dir_ + "Types.php";
+    f_types_.open(f_types_name.c_str());
+    generate_program_header(f_types_);
+  }
+}
+
+/**
+ * Prints standard php includes
+ */
+string t_php_generator::php_includes() {
+  string includes = "use Thrift\\Base\\TBase;\n"
+                    "use Thrift\\Type\\TType;\n"
+                    "use Thrift\\Type\\TMessageType;\n"
+                    "use Thrift\\Exception\\TException;\n"
+                    "use Thrift\\Exception\\TProtocolException;\n"
+                    "use Thrift\\Protocol\\TProtocol;\n"
+                    "use Thrift\\Protocol\\TBinaryProtocolAccelerated;\n"
+                    "use Thrift\\Exception\\TApplicationException;\n";
+
+  if (json_serializable_) {
+    includes += "use JsonSerializable;\n"
+                "use stdClass;\n";
+  }
+
+  return includes;
+}
+
+/**
+ * Close up (or down) some filez.
+ */
+void t_php_generator::close_generator() {
+  if (classmap_) {
+    // Close types file
+    f_types_.close();
+  }
+}
+
+/**
+ * Generates a typedef. This is not done in PHP, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_php_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+/**
+ * Generates service header contains namespace suffix and includes inside file specified
+ */
+void t_php_generator::generate_service_header(t_service* tservice, std::ostream& file) {
+  file << "<?php" << endl;
+  if (!php_namespace_suffix(tservice->get_program()).empty()) {
+    file << "namespace " << php_namespace_suffix(tservice->get_program()) << ";" << endl
+         << endl;
+  }
+  file << autogen_comment() << php_includes();
+
+  file << endl;
+}
+
+/**
+ * Generates program header contains namespace suffix and includes inside file specified
+ */
+void t_php_generator::generate_program_header(std::ostream& file) {
+  file << "<?php" << endl;
+  if (!php_namespace_suffix(get_program()).empty()) {
+    file << "namespace " << php_namespace_suffix(get_program()) << ";" << endl
+         << endl;
+  }
+  file << autogen_comment() << php_includes();
+
+  file << endl;
+}
+
+/**
+ * Generates code for an enumerated type. Since define is expensive to lookup
+ * in PHP, we use a global array for this.
+ *
+ * @param tenum The enumeration
+ */
+void t_php_generator::generate_enum(t_enum* tenum) {
+  ofstream_with_content_based_conditional_update& f_enum = f_types_;
+  if (!classmap_) {
+    string f_enum_name = package_dir_ + tenum->get_name() + ".php";
+    f_enum.open(f_enum_name.c_str());
+    generate_program_header(f_enum);
+  }
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+
+  // We're also doing it this way to see how it performs. It's more legible
+  // code but you can't do things like an 'extract' on it, which is a bit of
+  // a downer.
+  generate_php_doc(f_enum, tenum);
+  f_enum << "final class " << tenum->get_name() << endl
+         << "{" << endl;
+  indent_up();
+
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    generate_php_doc(f_enum, *c_iter);
+    indent(f_enum) << "const " << (*c_iter)->get_name() << " = " << value << ";" << endl
+                   << endl;
+  }
+
+  indent(f_enum) << "static public $__names = array(" << endl;
+
+  indent_up();
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    indent(f_enum) << value << " => '" << (*c_iter)->get_name() << "'," << endl;
+  }
+  indent_down();
+  indent(f_enum) << ");" << endl;
+
+  indent_down();
+
+  f_enum << "}" << endl << endl;
+  if (!classmap_) {
+    f_enum.close();
+  }
+}
+
+/**
+ * Generate constant class
+ *
+ * Override the one from t_generator
+ */
+void t_php_generator::generate_consts(vector<t_const*> consts) {
+  vector<t_const*>::iterator c_iter;
+
+  // Create class only if needed
+  if (consts.size() > 0) {
+
+    ofstream_with_content_based_conditional_update& f_consts = f_types_;
+    if (!classmap_) {
+      string f_consts_name = package_dir_ + "Constant.php";
+      f_consts.open(f_consts_name.c_str());
+      generate_program_header(f_consts);
+    }
+    f_consts << "final class Constant extends \\Thrift\\Type\\TConstant"<< endl
+             << "{" << endl;
+
+    indent_up();
+
+    // Create static property
+    for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+      string name = (*c_iter)->get_name();
+
+      indent(f_consts) << "static protected $" << name << ";" << endl;
+    }
+
+    // Create init function
+    for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+      string name = (*c_iter)->get_name();
+
+      f_consts << endl;
+
+      f_consts << indent() << "protected static function init_" << name << "()" <<endl
+               << indent() << "{" << endl;
+      indent_up();
+
+      indent(f_consts) << "return ";
+      generate_php_doc(f_consts, *c_iter);
+      f_consts << render_const_value((*c_iter)->get_type(), (*c_iter)->get_value());
+      f_consts << ";" << endl;
+
+      indent_down();
+      indent(f_consts) << "}" << endl;
+    }
+
+    indent_down();
+    f_consts << "}" << endl;
+    if (!classmap_) {
+      f_consts.close();
+    }
+  }
+}
+
+/**
+ * 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_php_generator::render_const_value(t_type* type, t_const_value* value) {
+  std::ostringstream out;
+  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_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_I8:
+    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 " << php_namespace(type->get_program()) << type->get_name() << "(array(" << 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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::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();
+      }
+      out << indent();
+      out << render_const_value(g_type_string, v_iter->first);
+      out << " => ";
+      out << render_const_value(field_type, v_iter->second);
+      out << "," << endl;
+    }
+    indent_down();
+    indent(out) << "))";
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    out << "array(" << endl;
+    indent_up();
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent();
+      out << render_const_value(ktype, v_iter->first);
+      out << " => ";
+      out << render_const_value(vtype, v_iter->second);
+      out << "," << endl;
+    }
+    indent_down();
+    indent(out) << ")";
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    out << "array(" << endl;
+    indent_up();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent();
+      out << render_const_value(etype, *v_iter);
+      if (type->is_set()) {
+        out << " => true";
+      }
+      out << "," << endl;
+    }
+    indent_down();
+    indent(out) << ")";
+  }
+  return out.str();
+}
+
+/**
+ * Make a struct
+ */
+void t_php_generator::generate_struct(t_struct* tstruct) {
+  generate_php_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_php_generator::generate_xception(t_struct* txception) {
+  generate_php_struct(txception, true);
+}
+
+/**
+ * Structs can be normal or exceptions.
+ */
+void t_php_generator::generate_php_struct(t_struct* tstruct, bool is_exception) {
+  ofstream_with_content_based_conditional_update& f_struct = f_types_;
+  if (!classmap_) {
+    string f_struct_name = package_dir_ + tstruct->get_name() + ".php";
+    f_struct.open(f_struct_name.c_str());
+    generate_program_header(f_struct);
+  }
+  generate_php_struct_definition(f_struct, tstruct, is_exception);
+  if (!classmap_) {
+    f_struct.close();
+  }
+}
+
+void t_php_generator::generate_php_type_spec(ostream& out, t_type* t) {
+  t = get_true_type(t);
+  indent(out) << "'type' => " << type_to_enum(t) << "," << endl;
+
+  if (t->is_base_type() || t->is_enum()) {
+    // Noop, type is all we need
+  } else if (t->is_struct() || t->is_xception()) {
+    indent(out) << "'class' => '" << php_namespace(t->get_program()) << t->get_name() << "',"
+                << endl;
+  } else if (t->is_map()) {
+    t_type* ktype = get_true_type(((t_map*)t)->get_key_type());
+    t_type* vtype = get_true_type(((t_map*)t)->get_val_type());
+    indent(out) << "'ktype' => " << type_to_enum(ktype) << "," << endl;
+    indent(out) << "'vtype' => " << type_to_enum(vtype) << "," << endl;
+    indent(out) << "'key' => array(" << endl;
+    indent_up();
+    generate_php_type_spec(out, ktype);
+    indent_down();
+    indent(out) << ")," << endl;
+    indent(out) << "'val' => array(" << endl;
+    indent_up();
+    generate_php_type_spec(out, vtype);
+    indent(out) << ")," << endl;
+    indent_down();
+  } else if (t->is_list() || t->is_set()) {
+    t_type* etype;
+    if (t->is_list()) {
+      etype = get_true_type(((t_list*)t)->get_elem_type());
+    } else {
+      etype = get_true_type(((t_set*)t)->get_elem_type());
+    }
+    indent(out) << "'etype' => " << type_to_enum(etype) << "," << endl;
+    indent(out) << "'elem' => array(" << endl;
+    indent_up();
+    generate_php_type_spec(out, etype);
+    indent(out) << ")," << endl;
+    indent_down();
+  } else {
+    throw "compiler error: no type for php struct spec field";
+  }
+}
+
+/**
+ * Generates the struct specification structure, which fully qualifies enough
+ * type information to generalize serialization routines.
+ */
+void t_php_generator::generate_php_struct_spec(ostream& out, t_struct* tstruct) {
+  indent(out) << "static public $_TSPEC = array(" << endl;
+  indent_up();
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    indent(out) << (*m_iter)->get_key() << " => array(" << endl;
+    indent_up();
+    out << indent() << "'var' => '" << (*m_iter)->get_name() << "'," << endl;
+    out << indent() << "'isRequired' => " << ((*m_iter)->get_req() == t_field::T_REQUIRED ? "true" : "false") << "," << endl;
+    generate_php_type_spec(out, t);
+    indent_down();
+    indent(out) << ")," << endl;
+  }
+
+  indent_down();
+  indent(out) << ");" << endl << endl;
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This is nothing in PHP
+ * where the objects are all just associative arrays (unless of course we
+ * decide to start using objects for them...)
+ *
+ * @param tstruct The struct definition
+ */
+void t_php_generator::generate_php_struct_definition(ostream& out,
+                                                     t_struct* tstruct,
+                                                     bool is_exception,
+                                                     bool is_result) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  generate_php_doc(out, tstruct);
+  out << "class " << php_namespace_declaration(tstruct);
+  if (is_exception) {
+    out << " extends "
+        << "TException";
+  } else if (oop_) {
+    out << " extends "
+        << "TBase";
+  }
+  if (json_serializable_) {
+    out << " implements JsonSerializable";
+  }
+  out << endl
+      << "{" << endl;
+  indent_up();
+
+  out << indent() << "static public $isValidate = " << (validate_ ? "true" : "false") << ";" << endl << endl;
+
+  generate_php_struct_spec(out, tstruct);
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    string dval = "null";
+    t_type* t = get_true_type((*m_iter)->get_type());
+    if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) {
+      dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value());
+    }
+    generate_php_doc(out, *m_iter);
+    indent(out) << "public $" << (*m_iter)->get_name() << " = " << dval << ";" << endl;
+  }
+
+  out << endl;
+
+  // Generate constructor from array
+  string param = (members.size() > 0) ? "$vals = null" : "";
+  out << indent() << "public function __construct(" << param << ")"<< endl
+      << indent() << "{" << endl;
+  indent_up();
+
+  if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      t_type* t = get_true_type((*m_iter)->get_type());
+      if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) {
+        indent(out) << "$this->" << (*m_iter)->get_name() << " = "
+                    << render_const_value(t, (*m_iter)->get_value()) << ";" << endl;
+      }
+    }
+    out << indent() << "if (is_array($vals)) {" << endl;
+    indent_up();
+    if (oop_) {
+      out << indent() << "parent::__construct(self::$_TSPEC, $vals);" << endl;
+    } else {
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        out << indent() << "if (isset($vals['" << (*m_iter)->get_name() << "'])) {" << endl;
+
+        indent_up();
+        out << indent() << "$this->" << (*m_iter)->get_name() << " = $vals['"
+            << (*m_iter)->get_name() << "'];" << endl;
+
+        indent_down();
+        out << indent() << "}" << endl;
+      }
+    }
+    indent_down();
+    out << indent() << "}" << endl;
+  }
+  scope_down(out);
+  out << endl;
+
+  out << indent() << "public function getName()" << endl
+      << indent() << "{" << endl;
+
+  indent_up();
+  out << indent() << "return '" << tstruct->get_name() << "';" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl << endl;
+
+  out << endl;
+  generate_php_struct_reader(out, tstruct, is_result);
+  out << endl;
+  generate_php_struct_writer(out, tstruct, is_result);
+  if (needs_php_read_validator(tstruct, is_result)) {
+    out << endl;
+    generate_php_struct_read_validator(out, tstruct);
+  }
+  if (needs_php_write_validator(tstruct, is_result)) {
+    out << endl;
+    generate_php_struct_write_validator(out, tstruct);
+  }
+  if (json_serializable_) {
+    out << endl;
+    generate_php_struct_json_serialize(out, tstruct, is_result);
+  }
+
+  indent_down();
+  out << indent() << "}" << endl;
+}
+
+/**
+ * Generates the read() method for a struct
+ */
+void t_php_generator::generate_php_struct_reader(ostream& out, t_struct* tstruct, bool is_result) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "public function read($input)" << endl;
+  scope_up(out);
+
+  if (oop_) {
+    if (needs_php_read_validator(tstruct, is_result)) {
+      indent(out) << "$tmp = $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);"
+                  << endl;
+      indent(out) << "$this->_validateForRead();" << endl;
+      indent(out) << "return $tmp;" << endl;
+    } else {
+      indent(out) << "return $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);"
+                  << endl;
+    }
+    scope_down(out);
+    out << endl;
+    return;
+  }
+
+  out << indent() << "$xfer = 0;" << endl << indent() << "$fname = null;" << endl << indent()
+      << "$ftype = 0;" << endl << indent() << "$fid = 0;" << endl;
+
+  // Declare stack tmp variables
+  if (!binary_inline_) {
+    indent(out) << "$xfer += $input->readStructBegin($fname);" << endl;
+  }
+
+  // Loop over reading in fields
+  indent(out) << "while (true) {" << endl;
+
+  indent_up();
+
+  // Read beginning field marker
+  if (binary_inline_) {
+    t_field fftype(g_type_i8, "ftype");
+    t_field ffid(g_type_i16, "fid");
+    generate_deserialize_field(out, &fftype);
+    out << indent() << "if ($ftype == "
+        << "TType::STOP) {" << endl << indent() << "  break;" << endl << indent() << "}" << endl;
+    generate_deserialize_field(out, &ffid);
+  } else {
+    indent(out) << "$xfer += $input->readFieldBegin($fname, $ftype, $fid);" << endl;
+    // Check for field STOP marker and break
+    indent(out) << "if ($ftype == "
+                << "TType::STOP) {" << endl;
+    indent_up();
+    indent(out) << "break;" << endl;
+    indent_down();
+    indent(out) << "}" << endl;
+  }
+
+  // Switch statement on the field we are reading
+  indent(out) << "switch ($fid) {" << endl;
+
+  indent_up();
+
+  // Generate deserialization code for known cases
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) << "case " << (*f_iter)->get_key() << ":" << endl;
+    indent_up();
+    indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+    indent_up();
+    generate_deserialize_field(out, *f_iter, "this->");
+    indent_down();
+    out << indent() << "} else {" << endl;
+
+    indent_up();
+    if (binary_inline_) {
+      indent(out) << "$xfer += TProtocol::skipBinary($input, $ftype);" << endl;
+    } else {
+      indent(out) << "$xfer += $input->skip($ftype);" << endl;
+    }
+
+    indent_down();
+    out << indent() << "}" << endl << indent() << "break;" << endl;
+    indent_down();
+  }
+
+  // In the default case we skip the field
+  indent(out) << "default:" << endl;
+
+  indent_up();
+  if (binary_inline_) {
+    indent(out) << "$xfer += "
+                << "TProtocol::skipBinary($input, $ftype);" << endl;
+  } else {
+    indent(out) << "$xfer += $input->skip($ftype);" << endl;
+  }
+  indent(out) << "break;" << endl;
+  indent_down();
+
+  scope_down(out);
+
+  if (!binary_inline_) {
+    // Read field end marker
+    indent(out) << "$xfer += $input->readFieldEnd();" << endl;
+  }
+
+  scope_down(out);
+
+  if (!binary_inline_) {
+    indent(out) << "$xfer += $input->readStructEnd();" << endl;
+  }
+
+  if (needs_php_read_validator(tstruct, is_result)) {
+    indent(out) << "$this->_validateForRead();" << endl;
+  }
+
+  indent(out) << "return $xfer;" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl;
+}
+
+/**
+ * Generates the write() method for a struct
+ */
+void t_php_generator::generate_php_struct_writer(ostream& out, t_struct* tstruct, bool is_result) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  if (binary_inline_) {
+    indent(out) << "public function write(&$output)" << endl;
+  } else {
+    indent(out) << "public function write($output)" << endl;
+  }
+  indent(out) << "{" << endl;
+  indent_up();
+
+  if (needs_php_write_validator(tstruct, is_result)) {
+    indent(out) << "$this->_validateForWrite();" << endl;
+  }
+
+  if (oop_) {
+    indent(out) << "return $this->_write('" << tstruct->get_name() << "', self::$_TSPEC, $output);"
+                << endl;
+    scope_down(out);
+    out << endl;
+    return;
+  }
+
+  indent(out) << "$xfer = 0;" << endl;
+
+  if (!binary_inline_) {
+    indent(out) << "$xfer += $output->writeStructBegin('" << name << "');" << endl;
+  }
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    out << indent() << "if ($this->" << (*f_iter)->get_name() << " !== null) {" << endl;
+    indent_up();
+
+    t_type* type = get_true_type((*f_iter)->get_type());
+    string expect;
+    if (type->is_container()) {
+      expect = "array";
+    } else if (type->is_struct()) {
+      expect = "object";
+    }
+    if (!expect.empty()) {
+      out << indent() << "if (!is_" << expect << "($this->" << (*f_iter)->get_name() << ")) {"
+          << endl;
+      indent_up();
+      out << indent() << "throw new "
+          << "TProtocolException('Bad type in structure.', "
+          << "TProtocolException::INVALID_DATA);" << endl;
+      scope_down(out);
+    }
+
+    // Write field header
+    if (binary_inline_) {
+      out << indent() << "$output .= pack('c', " << type_to_enum((*f_iter)->get_type()) << ");"
+          << endl << indent() << "$output .= pack('n', " << (*f_iter)->get_key() << ");" << endl;
+    } else {
+      indent(out) << "$xfer += $output->writeFieldBegin("
+                  << "'" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type())
+                  << ", " << (*f_iter)->get_key() << ");" << endl;
+    }
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "this->");
+
+    // Write field closer
+    if (!binary_inline_) {
+      indent(out) << "$xfer += $output->writeFieldEnd();" << endl;
+    }
+
+    indent_down();
+    indent(out) << "}" << endl;
+  }
+
+  if (binary_inline_) {
+    out << indent() << "$output .= pack('c', "
+        << "TType::STOP);" << endl;
+  } else {
+    out << indent() << "$xfer += $output->writeFieldStop();" << endl << indent()
+        << "$xfer += $output->writeStructEnd();" << endl;
+  }
+
+  out << indent() << "return $xfer;" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl;
+}
+
+void t_php_generator::generate_php_struct_read_validator(ostream& out, t_struct* tstruct) {
+  generate_php_struct_required_validator(out, tstruct, "_validateForRead", false);
+}
+
+void t_php_generator::generate_php_struct_write_validator(ostream& out, t_struct* tstruct) {
+  generate_php_struct_required_validator(out, tstruct, "_validateForWrite", true);
+}
+
+void t_php_generator::generate_php_struct_required_validator(ostream& out,
+                                                             t_struct* tstruct,
+                                                             std::string method_name,
+                                                             bool write_mode) {
+  indent(out) << "private function " << method_name << "() {" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+
+  if (fields.size() > 0) {
+    vector<t_field*>::const_iterator f_iter;
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      t_field* field = (*f_iter);
+      if (field->get_req() == t_field::T_REQUIRED
+          || (field->get_req() == t_field::T_OPT_IN_REQ_OUT && write_mode)) {
+        indent(out) << "if ($this->" << field->get_name() << " === null) {" << endl;
+        indent_up();
+        indent(out) << "throw new TProtocolException('Required field " << tstruct->get_name() << "."
+                    << field->get_name() << " is unset!');" << endl;
+        indent_down();
+        indent(out) << "}" << endl;
+      }
+    }
+  }
+
+  indent_down();
+  indent(out) << "}" << endl;
+}
+
+void t_php_generator::generate_php_struct_json_serialize(ostream& out,
+                                                         t_struct* tstruct,
+                                                         bool is_result) {
+  indent(out) << "public function jsonSerialize() {" << endl;
+  indent_up();
+
+  if (needs_php_write_validator(tstruct, is_result)) {
+    indent(out) << "$this->_validateForWrite();" << endl;
+  }
+
+  indent(out) << "$json = new stdClass;" << endl;
+
+  const vector<t_field*>& fields = tstruct->get_members();
+
+  if (fields.size() > 0) {
+    vector<t_field*>::const_iterator f_iter;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      t_field* field = (*f_iter);
+      t_type* type = field->get_type();
+      const string& name = field->get_name();
+      if (type->is_map()) {
+        t_type* key_type = ((t_map*)type)->get_key_type();
+        if (!(key_type->is_base_type() || key_type->is_enum())) {
+          // JSON object keys must be strings. PHP's json_encode()
+          // function will convert any scalar key to strings, but
+          // we skip thrift maps with non-scalar keys.
+          continue;
+        }
+      }
+      indent(out) << "if ($this->" << name << " !== null) {" << endl;
+      indent_up();
+      indent(out) << "$json->" << name << " = ";
+      if (type->is_map()) {
+        out << "(object)";
+      } else {
+        out << type_to_cast(type);
+      }
+      out << "$this->" << name << ";" << endl;
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+  }
+
+  indent(out) << "return $json;" << endl;
+  indent_down();
+
+  indent(out) << "}" << endl;
+}
+
+int t_php_generator::get_php_num_required_fields(const vector<t_field*>& fields, bool write_mode) {
+  int num_req = 0;
+
+  if (fields.size() > 0) {
+    vector<t_field*>::const_iterator f_iter;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      if ((*f_iter)->get_req() == t_field::T_REQUIRED
+          || ((*f_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT && write_mode)) {
+        ++num_req;
+      }
+    }
+  }
+  return num_req;
+}
+
+bool t_php_generator::needs_php_write_validator(t_struct* tstruct, bool is_result) {
+  return (validate_ && !is_result && !tstruct->is_union()
+          && get_php_num_required_fields(tstruct->get_members(), true) > 0);
+}
+
+bool t_php_generator::needs_php_read_validator(t_struct* tstruct, bool is_result) {
+  return (validate_ && !is_result
+          && (get_php_num_required_fields(tstruct->get_members(), false) > 0));
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_php_generator::generate_service(t_service* tservice) {
+  if(classmap_) {
+    string f_service_name = package_dir_ + service_name_ + ".php";
+    f_service_.open(f_service_name.c_str());
+    generate_service_header(tservice, f_service_);
+  }
+
+  // Generate the three main parts of the service (well, two for now in PHP)
+  generate_service_interface(tservice);
+  if (rest_) {
+    generate_service_rest(tservice);
+  }
+  generate_service_client(tservice);
+  generate_service_helpers(tservice);
+  if (phps_) {
+    generate_service_processor(tservice);
+  }
+
+  if(classmap_) {
+    // Close service file
+    f_service_ << endl;
+    f_service_.close();
+  }
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_php_generator::generate_service_processor(t_service* tservice) {
+  ofstream_with_content_based_conditional_update& f_service_processor = f_service_;
+  if (!classmap_) {
+    string f_service_processor_name = package_dir_ + service_name_ + "Processor.php";
+    f_service_processor.open(f_service_processor_name.c_str());
+    generate_service_header(tservice, f_service_processor);
+  }
+
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  string extends = "";
+  string extends_processor = "";
+  if (tservice->get_extends() != NULL) {
+    extends = tservice->get_extends()->get_name();
+    extends_processor = " extends " + php_namespace(tservice->get_extends()->get_program())
+                        + extends + "Processor";
+  }
+
+  // Generate the header portion
+  f_service_processor << "class " << service_name_ << "Processor" << extends_processor << endl
+                      << "{" << endl;
+  indent_up();
+
+  if (extends.empty()) {
+    f_service_processor << indent() << "protected $handler_ = null;" << endl;
+  }
+
+  f_service_processor << indent() << "public function __construct($handler)"<< endl
+                      << indent() << "{" << endl;
+
+  indent_up();
+  if (extends.empty()) {
+    f_service_processor << indent() << "$this->handler_ = $handler;" << endl;
+  } else {
+    f_service_processor << indent() << "parent::__construct($handler);" << endl;
+  }
+
+  indent_down();
+  f_service_processor << indent() << "}" << endl << endl;
+
+  // Generate the server implementation
+  f_service_processor << indent() << "public function process($input, $output)" << endl
+                      << indent() << "{" << endl;
+  indent_up();
+
+  f_service_processor << indent() << "$rseqid = 0;" << endl << indent() << "$fname = null;" << endl
+                      << indent() << "$mtype = 0;" << endl << endl;
+
+  if (binary_inline_) {
+    t_field ffname(g_type_string, "fname");
+    t_field fmtype(g_type_i8, "mtype");
+    t_field fseqid(g_type_i32, "rseqid");
+    generate_deserialize_field(f_service_processor, &ffname, "", true);
+    generate_deserialize_field(f_service_processor, &fmtype, "", true);
+    generate_deserialize_field(f_service_processor, &fseqid, "", true);
+  } else {
+    f_service_processor << indent() << "$input->readMessageBegin($fname, $mtype, $rseqid);" << endl;
+  }
+
+  // HOT: check for method implementation
+  f_service_processor << indent() << "$methodname = 'process_'.$fname;" << endl
+                      << indent() << "if (!method_exists($this, $methodname)) {" << endl;
+
+  indent_up();
+  if (binary_inline_) {
+    f_service_processor << indent() << "throw new \\Exception('Function '.$fname.' not implemented.');" << endl;
+  } else {
+    f_service_processor << indent() << "  $input->skip("
+                        << "TType::STRUCT);" << endl << indent() << "  $input->readMessageEnd();" << endl
+                        << indent() << "  $x = new "
+                        << "TApplicationException('Function '.$fname.' not implemented.', "
+                        << "TApplicationException::UNKNOWN_METHOD);" << endl << indent()
+                        << "  $output->writeMessageBegin($fname, "
+                        << "TMessageType::EXCEPTION, $rseqid);" << endl << indent()
+                        << "  $x->write($output);" << endl << indent() << "  $output->writeMessageEnd();"
+                        << endl << indent() << "  $output->getTransport()->flush();" << endl << indent()
+                        << "  return;" << endl;
+  }
+
+  indent_down();
+  f_service_processor << indent() << "}" << endl
+                      << indent() << "$this->$methodname($rseqid, $input, $output);" << endl
+                      << indent() << "return true;" << endl;
+
+  indent_down();
+  f_service_processor << indent() << "}" << endl << endl;
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_process_function(f_service_processor, tservice, *f_iter);
+  }
+
+  indent_down();
+  f_service_processor << "}" << endl;
+
+  if (!classmap_) {
+    f_service_processor.close();
+  }
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_php_generator::generate_process_function(std::ostream& out, t_service* tservice, t_function* tfunction) {
+  // Open function
+  out << indent() << "protected function process_" << tfunction->get_name() << "($seqid, $input, $output)" << endl
+      << indent() << "{" << endl;
+  indent_up();
+
+  string argsname = php_namespace(tservice->get_program()) + service_name_ + "_"
+                    + tfunction->get_name() + "_args";
+  string resultname = php_namespace(tservice->get_program()) + service_name_ + "_"
+                      + tfunction->get_name() + "_result";
+
+  out << indent() << "$bin_accel = ($input instanceof "
+             << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_read_binary_after_message_begin');"
+             << endl;
+  out << indent() << "if ($bin_accel) {" << endl;
+  indent_up();
+
+  out << indent() << "$args = thrift_protocol_read_binary_after_message_begin(" <<endl;
+
+  indent_up();
+  out << indent() << "$input,"<<endl
+      << indent() << "'" << argsname << "'," << endl
+      << indent() << "$input->isStrictRead()" <<endl;
+
+  indent_down();
+  out << indent() <<");" << endl;
+
+  indent_down();
+  out << indent() << "} else {" << endl;
+
+  indent_up();
+  out << indent() << "$args = new " << argsname << "();" << endl
+      << indent() << "$args->read($input);" << endl;
+
+  indent_down();
+  out << indent() << "}" << endl;
+
+  if (!binary_inline_) {
+    out << indent() << "$input->readMessageEnd();" << endl;
+  }
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    out << indent() << "$result = new " << resultname << "();" << endl;
+  }
+
+  // Try block for a function with exceptions
+  if (xceptions.size() > 0) {
+    out << indent() << "try {" << endl;
+    indent_up();
+  }
+
+  // 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;
+
+  out << indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    out << "$result->success = ";
+  }
+  out << "$this->handler_->" << tfunction->get_name() << "(";
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      out << ", ";
+    }
+    out << "$args->" << (*f_iter)->get_name();
+  }
+  out << ");" << endl;
+
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    indent_down();
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      out << indent() << "} catch ("
+                 << php_namespace(get_true_type((*x_iter)->get_type())->get_program())
+                 << (*x_iter)->get_type()->get_name() << " $" << (*x_iter)->get_name() << ") {"
+                 << endl;
+      if (!tfunction->is_oneway()) {
+        indent_up();
+        out << indent() << "$result->" << (*x_iter)->get_name() << " = $"
+                   << (*x_iter)->get_name() << ";" << endl;
+        indent_down();
+        out << indent();
+      }
+    }
+    out << "}" << endl;
+  }
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    out << indent() << "return;" << endl;
+    indent_down();
+    out << indent() << "}" << endl;
+    return;
+  }
+
+  out << indent() << "$bin_accel = ($output instanceof "
+             << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');"
+             << endl;
+
+  out << indent() << "if ($bin_accel) {" << endl;
+  indent_up();
+
+  out << indent() << "thrift_protocol_write_binary(" << endl;
+
+  indent_up();
+  out << indent() << "$output,"<<endl
+      << indent() << "'" << tfunction->get_name()<< "'," <<endl
+      << indent() << "TMessageType::REPLY,"<< endl
+      << indent() << "$result," << endl
+      << indent() << "$seqid," << endl
+      << indent() << "$output->isStrictWrite()"<<endl;
+
+  indent_down();
+  out << indent() << ");" << endl;
+
+  indent_down();
+  out << indent() << "} else {" << endl;
+  indent_up();
+
+  // Serialize the request header
+  if (binary_inline_) {
+    out << indent() << "$buff = pack('N', (0x80010000 | "
+        << "TMessageType::REPLY)); " << endl << indent() << "$buff .= pack('N', strlen('"
+        << tfunction->get_name() << "'));" << endl << indent() << "$buff .= '"
+        << tfunction->get_name() << "';" << endl << indent() << "$buff .= pack('N', $seqid);"
+        << endl << indent() << "$result->write($buff);" << endl << indent()
+        << "$output->write($buff);" << endl << indent() << "$output->flush();" << endl;
+  } else {
+    out << indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', "
+        << "TMessageType::REPLY, $seqid);" << endl << indent() << "$result->write($output);"
+        << endl << indent() << "$output->writeMessageEnd();" << endl << indent()
+        << "$output->getTransport()->flush();" << endl;
+  }
+
+  scope_down(out);
+
+  // Close function
+  indent_down();
+  out << indent() << "}" << endl;
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_php_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  ofstream_with_content_based_conditional_update& f_struct_definition = f_service_;
+  if (classmap_) {
+    f_struct_definition << "// HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
+  }
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    string name = ts->get_name();
+    ts->set_name(service_name_ + "_" + name);
+
+    if (!classmap_) {
+      string f_struct_definition_name = package_dir_ + service_name_ + "_" + name + ".php";
+      f_struct_definition.open(f_struct_definition_name.c_str());
+      generate_service_header(tservice, f_struct_definition);
+    }
+
+    generate_php_struct_definition(f_struct_definition, ts);
+    if (!classmap_) {
+      f_struct_definition.close();
+    }
+
+    generate_php_function_helpers(tservice, *f_iter);
+    ts->set_name(name);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_php_generator::generate_php_function_helpers(t_service* tservice, t_function* tfunction) {
+  if (!tfunction->is_oneway()) {
+    t_struct result(program_, service_name_ + "_" + 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);
+    }
+
+    ofstream_with_content_based_conditional_update& f_struct_helper = f_service_;
+    if (!classmap_) {
+      string f_struct_helper_name = package_dir_ + result.get_name() + ".php";
+      f_struct_helper.open(f_struct_helper_name.c_str());
+      generate_service_header(tservice, f_struct_helper);
+    }
+    generate_php_struct_definition(f_struct_helper, &result, false, true);
+    if (!classmap_) {
+      f_struct_helper.close();
+    }
+  }
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_php_generator::generate_service_interface(t_service* tservice) {
+  ofstream_with_content_based_conditional_update& f_service_interface = f_service_;
+  if (!classmap_) {
+    string f_service_interface_name = package_dir_ + service_name_ + "If.php";
+    f_service_interface.open(f_service_interface_name.c_str());
+    generate_service_header(tservice, f_service_interface);
+  }
+
+  string extends = "";
+  string extends_if = "";
+  if (tservice->get_extends() != NULL) {
+    extends = " extends " + php_namespace(tservice->get_extends()->get_program())
+              + tservice->get_extends()->get_name();
+    extends_if = " extends " + php_namespace(tservice->get_extends()->get_program())
+                 + tservice->get_extends()->get_name() + "If";
+  }
+  generate_php_doc(f_service_interface, tservice);
+  f_service_interface << "interface " << php_namespace_declaration(tservice) << "If" << extends_if << endl
+                      << "{" << endl;
+
+  indent_up();
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_php_doc(f_service_interface, *f_iter);
+    indent(f_service_interface) << "public function " << function_signature(*f_iter) << ";" << endl;
+  }
+  indent_down();
+  f_service_interface << "}" << endl;
+
+  // Close service interface file
+  if (!classmap_) {
+    f_service_interface.close();
+  }
+}
+
+/**
+ * Generates a REST interface
+ */
+void t_php_generator::generate_service_rest(t_service* tservice) {
+  ofstream_with_content_based_conditional_update& f_service_rest = f_service_;
+  if (!classmap_) {
+    string f_service_rest_name = package_dir_ + service_name_ + "Rest.php";
+    f_service_rest.open(f_service_rest_name.c_str());
+    generate_service_header(tservice, f_service_rest);
+  }
+
+  string extends = "";
+  string extends_if = "";
+  if (tservice->get_extends() != NULL) {
+    extends = " extends " + php_namespace(tservice->get_extends()->get_program())
+              + tservice->get_extends()->get_name();
+    extends_if = " extends " + php_namespace(tservice->get_extends()->get_program())
+                 + tservice->get_extends()->get_name() + "Rest";
+  }
+  f_service_rest << "class " << service_name_ << "Rest" << extends_if << endl
+                 << "{" << endl;
+  indent_up();
+
+  if (extends.empty()) {
+    f_service_rest << indent() << "protected $impl_;" << endl << endl;
+  }
+
+  f_service_rest << indent() << "public function __construct($impl) {" << endl << indent()
+             << "  $this->impl_ = $impl;" << endl << indent() << "}" << endl << endl;
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    indent(f_service_rest) << "public function " << (*f_iter)->get_name() << "($request) {" << endl;
+    indent_up();
+    const vector<t_field*>& args = (*f_iter)->get_arglist()->get_members();
+    vector<t_field*>::const_iterator a_iter;
+    for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
+      t_type* atype = get_true_type((*a_iter)->get_type());
+      string cast = type_to_cast(atype);
+      string req = "$request['" + (*a_iter)->get_name() + "']";
+      if (atype->is_bool()) {
+        f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = " << cast << "(!empty(" << req
+                   << ") && (" << req << " !== 'false'));" << endl;
+      } else {
+        f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = isset(" << req << ") ? "
+                   << cast << req << " : null;" << endl;
+      }
+      if (atype->is_string() && ((t_base_type*)atype)->is_string_list()) {
+        f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = explode(',', $"
+                       << (*a_iter)->get_name() << ");" << endl;
+      } else if (atype->is_map() || atype->is_list()) {
+        f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = json_decode($"
+                       << (*a_iter)->get_name() << ", true);" << endl;
+      } else if (atype->is_set()) {
+        f_service_rest << indent() << "$" << (*a_iter)->get_name() << " = array_fill_keys(json_decode($"
+                       << (*a_iter)->get_name() << ", true), 1);" << endl;
+      } else if (atype->is_struct() || atype->is_xception()) {
+        f_service_rest << indent() << "if ($" << (*a_iter)->get_name() << " !== null) {" << endl
+                       << indent() << "  $" << (*a_iter)->get_name() << " = new "
+                       << php_namespace(atype->get_program()) << atype->get_name() << "(json_decode($"
+                       << (*a_iter)->get_name() << ", true));" << endl << indent() << "}" << endl;
+      }
+    }
+    f_service_rest << indent() << "return $this->impl_->" << (*f_iter)->get_name() << "("
+               << argument_list((*f_iter)->get_arglist(), false) << ");" << endl;
+    indent_down();
+    indent(f_service_rest) << "}" << endl << endl;
+  }
+  indent_down();
+  f_service_rest << "}" << endl << endl;
+
+  // Close service rest file
+  f_service_rest << endl;
+  if (!classmap_) {
+    f_service_rest.close();
+  }
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_php_generator::generate_service_client(t_service* tservice) {
+  ofstream_with_content_based_conditional_update& f_service_client = f_service_;
+  if (!classmap_) {
+    string f_service_client_name = package_dir_ + service_name_ + "Client.php";
+    f_service_client.open(f_service_client_name.c_str());
+    generate_service_header(tservice, f_service_client);
+  }
+
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = tservice->get_extends()->get_name();
+    extends_client = " extends " + php_namespace(tservice->get_extends()->get_program()) + extends
+                     + "Client";
+  }
+
+  f_service_client << "class " << php_namespace_declaration(tservice) << "Client" << extends_client
+             << " implements " << php_namespace(tservice->get_program()) << service_name_ << "If" << endl
+             <<"{"<< endl;
+  indent_up();
+
+  // Private members
+  if (extends.empty()) {
+    f_service_client << indent() << "protected $input_ = null;" << endl << indent()
+               << "protected $output_ = null;" << endl << endl;
+    f_service_client << indent() << "protected $seqid_ = 0;" << endl << endl;
+  }
+
+  // Constructor function
+  f_service_client << indent() << "public function __construct($input, $output = null)" << endl
+                   << indent() << "{" << endl;
+
+  indent_up();
+  if (!extends.empty()) {
+    f_service_client << indent() << "parent::__construct($input, $output);" << endl;
+  } else {
+    f_service_client << indent() << "$this->input_ = $input;" << endl
+                     << indent() << "$this->output_ = $output ? $output : $input;" << endl;
+  }
+
+  indent_down();
+  f_service_client << 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 = (*f_iter)->get_name();
+
+    f_service_client << endl;
+
+    // Open function
+    indent(f_service_client) << "public function " << function_signature(*f_iter) << endl;
+    scope_up(f_service_client);
+    indent(f_service_client) << "$this->send_" << funname << "(";
+
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_client << ", ";
+      }
+      f_service_client << "$" << (*fld_iter)->get_name();
+    }
+    f_service_client << ");" << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_client << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_client << "return ";
+      }
+      f_service_client << "$this->recv_" << funname << "();" << endl;
+    }
+    scope_down(f_service_client);
+    f_service_client << endl;
+
+    indent(f_service_client) << "public function send_" << function_signature(*f_iter) << endl;
+    scope_up(f_service_client);
+
+    std::string argsname = php_namespace(tservice->get_program()) + service_name_ + "_"
+                           + (*f_iter)->get_name() + "_args";
+
+    f_service_client << indent() << "$args = new " << argsname << "();" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_client << indent() << "$args->" << (*fld_iter)->get_name() << " = $"
+                 << (*fld_iter)->get_name() << ";" << endl;
+    }
+
+    f_service_client << indent() << "$bin_accel = ($this->output_ instanceof "
+               << "TBinaryProtocolAccelerated) && function_exists('thrift_protocol_write_binary');"
+               << endl;
+
+    f_service_client << indent() << "if ($bin_accel) {" << endl;
+    indent_up();
+
+    string messageType = (*f_iter)->is_oneway() ? "TMessageType::ONEWAY" : "TMessageType::CALL";
+
+    f_service_client << indent() << "thrift_protocol_write_binary(" << endl;
+
+    indent_up();
+    f_service_client << indent() << "$this->output_," << endl
+               << indent() << "'" << (*f_iter)->get_name() << "'," << endl
+               << indent() << messageType << "," << endl
+               << indent() << "$args," << endl
+               << indent() << "$this->seqid_," << endl
+               << indent() << "$this->output_->isStrictWrite()" << endl;
+
+    indent_down();
+    f_service_client << indent() << ");" << endl;
+
+    indent_down();
+    f_service_client << indent() << "} else {" << endl;
+    indent_up();
+
+    // Serialize the request header
+    if (binary_inline_) {
+      f_service_client << indent() << "$buff = pack('N', (0x80010000 | " << messageType << "));" << endl
+                       << indent() << "$buff .= pack('N', strlen('" << funname << "'));" << endl
+                       << indent() << "$buff .= '" << funname << "';" << endl << indent()
+                       << "$buff .= pack('N', $this->seqid_);" << endl;
+    } else {
+      f_service_client << indent() << "$this->output_->writeMessageBegin('" << (*f_iter)->get_name()
+                       << "', " << messageType << ", $this->seqid_);" << endl;
+    }
+
+    // Write to the stream
+    if (binary_inline_) {
+      f_service_client << indent() << "$args->write($buff);" << endl << indent()
+                       << "$this->output_->write($buff);" << endl << indent()
+                       << "$this->output_->flush();" << endl;
+    } else {
+      f_service_client << indent() << "$args->write($this->output_);" << endl << indent()
+                       << "$this->output_->writeMessageEnd();" << endl << indent()
+                       << "$this->output_->getTransport()->flush();" << endl;
+    }
+
+    scope_down(f_service_client);
+
+    scope_down(f_service_client);
+
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultname = php_namespace(tservice->get_program()) + service_name_ + "_"
+                               + (*f_iter)->get_name() + "_result";
+      t_struct noargs(program_);
+
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+      // Open function
+      f_service_client << endl << indent() << "public function " << function_signature(&recv_function)
+                       << endl;
+      scope_up(f_service_client);
+
+      f_service_client << indent() << "$bin_accel = ($this->input_ instanceof "
+                       << "TBinaryProtocolAccelerated)"
+                       << " && function_exists('thrift_protocol_read_binary');" << endl;
+
+      f_service_client << indent() << "if ($bin_accel) {" << endl;
+
+      indent_up();
+      f_service_client << indent() << "$result = thrift_protocol_read_binary(" << endl;
+
+      indent_up();
+      f_service_client << indent() << "$this->input_," << endl
+                       << indent() << "'" << resultname << "'," << endl
+                       << indent() << "$this->input_->isStrictRead()" << endl;
+
+      indent_down();
+      f_service_client << indent() << ");" << endl;
+
+      indent_down();
+      f_service_client << indent() << "} else {" << endl;
+
+      indent_up();
+      f_service_client << indent() << "$rseqid = 0;" << endl
+                       << indent() << "$fname = null;" << endl
+                       << indent() << "$mtype = 0;" << endl << endl;
+
+      if (binary_inline_) {
+        t_field ffname(g_type_string, "fname");
+        t_field fseqid(g_type_i32, "rseqid");
+        f_service_client << indent() << "$ver = unpack('N', $this->input_->readAll(4));" << endl
+                         << indent() << "$ver = $ver[1];" << endl << indent() << "$mtype = $ver & 0xff;"
+                         << endl << indent() << "$ver = $ver & 0xffff0000;" << endl << indent()
+                         << "if ($ver != 0x80010000) throw new "
+                         << "TProtocolException('Bad version identifier: '.$ver, "
+                         << "TProtocolException::BAD_VERSION);" << endl;
+        generate_deserialize_field(f_service_client, &ffname, "", true);
+        generate_deserialize_field(f_service_client, &fseqid, "", true);
+      } else {
+        f_service_client << indent() << "$this->input_->readMessageBegin($fname, $mtype, $rseqid);" << endl
+                         << indent() << "if ($mtype == TMessageType::EXCEPTION) {" << endl;
+
+        indent_up();
+        f_service_client << indent() << "$x = new TApplicationException();" << endl
+                         << indent() << "$x->read($this->input_);" << endl
+                         << indent() << "$this->input_->readMessageEnd();" << endl
+                         << indent() << "throw $x;" << endl;
+        indent_down();
+        f_service_client << indent() << "}" << endl;
+      }
+
+      f_service_client << indent() << "$result = new " << resultname << "();" << endl
+                       << indent() << "$result->read($this->input_);" << endl;
+
+      if (!binary_inline_) {
+        f_service_client << indent() << "$this->input_->readMessageEnd();" << endl;
+      }
+
+      scope_down(f_service_client);
+
+      // Careful, only return result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_client << indent() << "if ($result->success !== null) {" << endl;
+
+        indent_up();
+        f_service_client << indent() << "return $result->success;" << endl;
+
+        indent_down();
+        f_service_client << indent() << "}" << 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_client << indent() << "if ($result->" << (*x_iter)->get_name() << " !== null) {" << endl;
+
+        indent_up();
+        f_service_client << indent() << "throw $result->" << (*x_iter)->get_name() << ";" << endl;
+
+        indent_down();
+        f_service_client << indent() << "}" << endl;
+      }
+
+      // Careful, only return _result if not a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_client) << "return;" << endl;
+      } else {
+        f_service_client << indent() << "throw new \\Exception(\"" << (*f_iter)->get_name()
+                         << " failed: unknown result\");" << endl;
+      }
+
+      // Close function
+      scope_down(f_service_client);
+    }
+  }
+
+  indent_down();
+  f_service_client << "}" << endl;
+
+  // Close service client file
+  if (!classmap_) {
+    f_service_client.close();
+  }
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_php_generator::generate_deserialize_field(ostream& out,
+                                                 t_field* tfield,
+                                                 string prefix,
+                                                 bool inclass) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name();
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else {
+
+    if (type->is_container()) {
+      generate_deserialize_container(out, type, name);
+    } else if (type->is_base_type() || type->is_enum()) {
+
+      if (binary_inline_) {
+        std::string itrans = (inclass ? "$this->input_" : "$input");
+
+        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 << indent() << "$len = unpack('N', " << itrans << "->readAll(4));" << endl
+                << indent() << "$len = $len[1];" << endl << indent() << "if ($len > 0x7fffffff) {"
+                << endl << indent() << "  $len = 0 - (($len - 1) ^ 0xffffffff);" << endl << indent()
+                << "}" << endl << indent() << "$" << name << " = " << itrans << "->readAll($len);"
+                << endl;
+            break;
+          case t_base_type::TYPE_BOOL:
+            out << indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));"
+                << endl << indent() << "$" << name << " = (bool)$" << name << "[1];" << endl;
+            break;
+          case t_base_type::TYPE_I8:
+            out << indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));"
+                << endl << indent() << "$" << name << " = $" << name << "[1];" << endl;
+            break;
+          case t_base_type::TYPE_I16:
+            out << indent() << "$val = unpack('n', " << itrans << "->readAll(2));" << endl
+                << indent() << "$val = $val[1];" << endl << indent() << "if ($val > 0x7fff) {"
+                << endl << indent() << "  $val = 0 - (($val - 1) ^ 0xffff);" << endl << indent()
+                << "}" << endl << indent() << "$" << name << " = $val;" << endl;
+            break;
+          case t_base_type::TYPE_I32:
+            out << indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl
+                << indent() << "$val = $val[1];" << endl << indent() << "if ($val > 0x7fffffff) {"
+                << endl << indent() << "  $val = 0 - (($val - 1) ^ 0xffffffff);" << endl << indent()
+                << "}" << endl << indent() << "$" << name << " = $val;" << endl;
+            break;
+          case t_base_type::TYPE_I64:
+            out << indent() << "$arr = unpack('N2', " << itrans << "->readAll(8));" << endl
+                << indent() << "if ($arr[1] & 0x80000000) {" << endl << indent()
+                << "  $arr[1] = $arr[1] ^ 0xFFFFFFFF;" << endl << indent()
+                << "  $arr[2] = $arr[2] ^ 0xFFFFFFFF;" << endl << indent() << "  $" << name
+                << " = 0 - $arr[1]*4294967296 - $arr[2] - 1;" << endl << indent() << "} else {"
+                << endl << indent() << "  $" << name << " = $arr[1]*4294967296 + $arr[2];" << endl
+                << indent() << "}" << endl;
+            break;
+          case t_base_type::TYPE_DOUBLE:
+            out << indent() << "$arr = unpack('d', strrev(" << itrans << "->readAll(8)));" << endl
+                << indent() << "$" << name << " = $arr[1];" << endl;
+            break;
+          default:
+            throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase)
+                + tfield->get_name();
+          }
+        } else if (type->is_enum()) {
+          out << indent() << "$val = unpack('N', " << itrans << "->readAll(4));" << endl << indent()
+              << "$val = $val[1];" << endl << indent() << "if ($val > 0x7fffffff) {" << endl
+              << indent() << "  $val = 0 - (($val - 1) ^ 0xffffffff);" << endl << indent() << "}"
+              << endl << indent() << "$" << name << " = $val;" << endl;
+        }
+      } else {
+
+        indent(out) << "$xfer += $input->";
+
+        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($" << name << ");";
+            break;
+          case t_base_type::TYPE_BOOL:
+            out << "readBool($" << name << ");";
+            break;
+          case t_base_type::TYPE_I8:
+            out << "readByte($" << name << ");";
+            break;
+          case t_base_type::TYPE_I16:
+            out << "readI16($" << name << ");";
+            break;
+          case t_base_type::TYPE_I32:
+            out << "readI32($" << name << ");";
+            break;
+          case t_base_type::TYPE_I64:
+            out << "readI64($" << name << ");";
+            break;
+          case t_base_type::TYPE_DOUBLE:
+            out << "readDouble($" << 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 << "readI32($" << name << ");";
+        }
+        out << endl;
+      }
+    } else {
+      printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+             tfield->get_name().c_str(),
+             type->get_name().c_str());
+    }
+  }
+}
+
+/**
+ * Generates an unserializer for a variable. This makes two key assumptions,
+ * first that there is a const char* variable named data that points to the
+ * buffer for deserialization, and that there is a variable protocol which
+ * is a reference to a TProtocol serialization object.
+ */
+void t_php_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  out << indent() << "$" << prefix << " = new " << php_namespace(tstruct->get_program())
+      << tstruct->get_name() << "();" << endl << indent() << "$xfer += $" << prefix
+      << "->read($input);" << endl;
+}
+
+void t_php_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) {
+  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_i8, ktype);
+  t_field fvtype(g_type_i8, vtype);
+  t_field fetype(g_type_i8, etype);
+
+  out << indent() << "$" << prefix << " = array();" << endl << indent() << "$" << size << " = 0;"
+      << endl;
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    out << indent() << "$" << ktype << " = 0;" << endl << indent() << "$" << vtype << " = 0;"
+        << endl;
+    if (binary_inline_) {
+      generate_deserialize_field(out, &fktype);
+      generate_deserialize_field(out, &fvtype);
+      generate_deserialize_field(out, &fsize);
+    } else {
+      out << indent() << "$xfer += $input->readMapBegin("
+          << "$" << ktype << ", $" << vtype << ", $" << size << ");" << endl;
+    }
+  } else if (ttype->is_set()) {
+    if (binary_inline_) {
+      generate_deserialize_field(out, &fetype);
+      generate_deserialize_field(out, &fsize);
+    } else {
+      out << indent() << "$" << etype << " = 0;" << endl << indent()
+          << "$xfer += $input->readSetBegin("
+          << "$" << etype << ", $" << size << ");" << endl;
+    }
+  } else if (ttype->is_list()) {
+    if (binary_inline_) {
+      generate_deserialize_field(out, &fetype);
+      generate_deserialize_field(out, &fsize);
+    } else {
+      out << indent() << "$" << etype << " = 0;" << endl << indent()
+          << "$xfer += $input->readListBegin("
+          << "$" << etype << ", $" << size << ");" << endl;
+    }
+  }
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) << "for ($" << i << " = 0; $" << i << " < $" << size << "; ++$" << i << ") {" << endl;
+
+  indent_up();
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  scope_down(out);
+
+  if (!binary_inline_) {
+    // Read container end
+    if (ttype->is_map()) {
+      indent(out) << "$xfer += $input->readMapEnd();" << endl;
+    } else if (ttype->is_set()) {
+      indent(out) << "$xfer += $input->readSetEnd();" << endl;
+    } else if (ttype->is_list()) {
+      indent(out) << "$xfer += $input->readListEnd();" << endl;
+    }
+  }
+}
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_php_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) {
+  string key = tmp("key");
+  string val = tmp("val");
+  t_field fkey(tmap->get_key_type(), key);
+  t_field fval(tmap->get_val_type(), val);
+
+  indent(out) << declare_field(&fkey, true, true) << endl;
+  indent(out) << declare_field(&fval, true, true) << endl;
+
+  generate_deserialize_field(out, &fkey);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) << "$" << prefix << "[$" << key << "] = $" << val << ";" << endl;
+}
+
+void t_php_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) {
+  string elem = tmp("elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  indent(out) << "$" << elem << " = null;" << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  t_type* elem_type = tset->get_elem_type();
+  if(php_is_scalar(elem_type)) {
+    indent(out) << "$" << prefix << "[$" << elem << "] = true;" << endl;
+  } else {
+    indent(out) << "$" << prefix << "[] = $" << elem << ";" << endl;
+  }
+}
+
+void t_php_generator::generate_deserialize_list_element(ostream& out,
+                                                        t_list* tlist,
+                                                        string prefix) {
+  string elem = tmp("elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  indent(out) << "$" << elem << " = null;" << endl;
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << "$" << prefix << " []= $" << elem << ";" << endl;
+}
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_php_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name());
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, prefix + tfield->get_name());
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    string name = prefix + tfield->get_name();
+
+    if (binary_inline_) {
+      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 << indent() << "$output .= pack('N', strlen($" << name << "));" << endl << indent()
+              << "$output .= $" << name << ";" << endl;
+          break;
+        case t_base_type::TYPE_BOOL:
+          out << indent() << "$output .= pack('c', $" << name << " ? 1 : 0);" << endl;
+          break;
+        case t_base_type::TYPE_I8:
+          out << indent() << "$output .= pack('c', $" << name << ");" << endl;
+          break;
+        case t_base_type::TYPE_I16:
+          out << indent() << "$output .= pack('n', $" << name << ");" << endl;
+          break;
+        case t_base_type::TYPE_I32:
+          out << indent() << "$output .= pack('N', $" << name << ");" << endl;
+          break;
+        case t_base_type::TYPE_I64:
+          out << indent() << "$output .= pack('N2', $" << name << " >> 32, $" << name
+              << " & 0xFFFFFFFF);" << endl;
+          break;
+        case t_base_type::TYPE_DOUBLE:
+          out << indent() << "$output .= strrev(pack('d', $" << name << "));" << endl;
+          break;
+        default:
+          throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
+        }
+      } else if (type->is_enum()) {
+        out << indent() << "$output .= pack('N', $" << name << ");" << endl;
+      }
+    } else {
+
+      indent(out) << "$xfer += $output->";
+
+      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($" << name << ");";
+          break;
+        case t_base_type::TYPE_BOOL:
+          out << "writeBool($" << name << ");";
+          break;
+        case t_base_type::TYPE_I8:
+          out << "writeByte($" << name << ");";
+          break;
+        case t_base_type::TYPE_I16:
+          out << "writeI16($" << name << ");";
+          break;
+        case t_base_type::TYPE_I32:
+          out << "writeI32($" << name << ");";
+          break;
+        case t_base_type::TYPE_I64:
+          out << "writeI64($" << name << ");";
+          break;
+        case t_base_type::TYPE_DOUBLE:
+          out << "writeDouble($" << 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($" << name << ");";
+      }
+      out << endl;
+    }
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_php_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  (void)tstruct;
+  indent(out) << "$xfer += $" << prefix << "->write($output);" << endl;
+}
+
+/**
+ * Writes out a container
+ */
+void t_php_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  if (ttype->is_map()) {
+    if (binary_inline_) {
+      out << indent() << "$output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_key_type())
+          << ");" << endl << indent() << "$output .= pack('c', "
+          << type_to_enum(((t_map*)ttype)->get_val_type()) << ");" << endl << indent()
+          << "$output .= strrev(pack('l', count($" << prefix << ")));" << endl;
+    } else {
+      indent(out) << "$output->writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type())
+                  << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", "
+                  << "count($" << prefix << "));" << endl;
+    }
+  } else if (ttype->is_set()) {
+    if (binary_inline_) {
+      out << indent() << "$output .= pack('c', " << type_to_enum(((t_set*)ttype)->get_elem_type())
+          << ");" << endl << indent() << "$output .= strrev(pack('l', count($" << prefix << ")));"
+          << endl;
+
+    } else {
+      indent(out) << "$output->writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type())
+                  << ", "
+                  << "count($" << prefix << "));" << endl;
+    }
+  } else if (ttype->is_list()) {
+    if (binary_inline_) {
+      out << indent() << "$output .= pack('c', " << type_to_enum(((t_list*)ttype)->get_elem_type())
+          << ");" << endl << indent() << "$output .= strrev(pack('l', count($" << prefix << ")));"
+          << endl;
+
+    } else {
+      indent(out) << "$output->writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type())
+                  << ", "
+                  << "count($" << prefix << "));" << endl;
+    }
+  }
+
+  if (ttype->is_map()) {
+    string kiter = tmp("kiter");
+    string viter = tmp("viter");
+    indent(out) << "foreach ($" << prefix << " as "
+                << "$" << kiter << " => $" << viter << ") {" << endl;
+    indent_up();
+    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
+    scope_down(out);
+  } else if (ttype->is_set()) {
+    string iter = tmp("iter");
+    string iter_val = tmp("iter");
+    indent(out) << "foreach ($" << prefix << " as $" << iter << " => $" << iter_val << ") {" << endl;
+    indent_up();
+
+    t_type* elem_type = ((t_set*)ttype)->get_elem_type();
+    if(php_is_scalar(elem_type)) {
+      generate_serialize_set_element(out, (t_set*)ttype, iter);
+    } else {
+      generate_serialize_set_element(out, (t_set*)ttype, iter_val);
+    }
+    scope_down(out);
+  } else if (ttype->is_list()) {
+    string iter = tmp("iter");
+    indent(out) << "foreach ($" << prefix << " as $" << iter << ") {" << endl;
+    indent_up();
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+    scope_down(out);
+  }
+
+  if (!binary_inline_) {
+    if (ttype->is_map()) {
+      indent(out) << "$output->writeMapEnd();" << endl;
+    } else if (ttype->is_set()) {
+      indent(out) << "$output->writeSetEnd();" << endl;
+    } else if (ttype->is_list()) {
+      indent(out) << "$output->writeListEnd();" << endl;
+    }
+  }
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_php_generator::generate_serialize_map_element(ostream& out,
+                                                     t_map* tmap,
+                                                     string kiter,
+                                                     string viter) {
+  t_field kfield(tmap->get_key_type(), kiter);
+  generate_serialize_field(out, &kfield, "");
+
+  t_field vfield(tmap->get_val_type(), viter);
+  generate_serialize_field(out, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_php_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_php_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Emits a PHPDoc comment for the given contents
+ */
+void t_php_generator::generate_php_docstring_comment(ostream& out, string contents) {
+  generate_docstring_comment(out, "/**\n", " * ", contents, " */\n");
+}
+
+/**
+ * Emits a PHPDoc comment if the provided object has a doc in Thrift
+ */
+void t_php_generator::generate_php_doc(ostream& out, t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    generate_php_docstring_comment(out, tdoc->get_doc());
+  }
+}
+
+/**
+ * Emits a PHPDoc comment for a field
+ */
+void t_php_generator::generate_php_doc(ostream& out, t_field* field) {
+  stringstream ss;
+
+  // prepend free-style doc if available
+  if (field->has_doc()) {
+    ss << field->get_doc() << endl;
+  }
+
+  // append @var tag
+  t_type* type = get_true_type(field->get_type());
+  ss << "@var " << type_to_phpdoc(type) << endl;
+
+  generate_php_docstring_comment(out, ss.str());
+}
+
+/**
+ * Emits a PHPDoc comment for a function
+ */
+void t_php_generator::generate_php_doc(ostream& out, t_function* function) {
+  stringstream ss;
+  if (function->has_doc()) {
+    ss << function->get_doc() << endl;
+  }
+
+  // generate parameter types doc
+  const vector<t_field*>& args = function->get_arglist()->get_members();
+  vector<t_field*>::const_iterator a_iter;
+  for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
+    t_field* arg = *a_iter;
+    ss << "@param " << type_to_phpdoc(arg->get_type()) << " $" << arg->get_name();
+    if (arg->has_doc()) {
+      ss << " " << arg->get_doc();
+    }
+    ss << endl;
+  }
+
+  // generate return type doc
+  t_type* ret_type = function->get_returntype();
+  if (!ret_type->is_void() || ret_type->has_doc()) {
+    ss << "@return " << type_to_phpdoc(ret_type);
+    if (ret_type->has_doc()) {
+      ss << " " << ret_type->get_doc();
+    }
+    ss << endl;
+  }
+
+  // generate exceptions doc
+  const vector<t_field*>& excs = function->get_xceptions()->get_members();
+  vector<t_field*>::const_iterator e_iter;
+  for (e_iter = excs.begin(); e_iter != excs.end(); ++e_iter) {
+    t_field* exc = *e_iter;
+    ss << "@throws " << type_to_phpdoc(exc->get_type());
+    if (exc->has_doc()) {
+      ss << " " << exc->get_doc();
+    }
+    ss << endl;
+  }
+
+  generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n");
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_php_generator::declare_field(t_field* tfield, bool init, bool obj) {
+  string result = "$" + tfield->get_name();
+  if (init) {
+    t_type* type = get_true_type(tfield->get_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:
+        break;
+      case t_base_type::TYPE_STRING:
+        result += " = ''";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = false";
+        break;
+      case t_base_type::TYPE_I8:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = 0.0";
+        break;
+      default:
+        throw "compiler error: no PHP initializer for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      result += " = 0";
+    } else if (type->is_container()) {
+      result += " = array()";
+    } else if (type->is_struct() || type->is_xception()) {
+      if (obj) {
+        result += " = new " + php_namespace(type->get_program()) + type->get_name() + "()";
+      } else {
+        result += " = null";
+      }
+    }
+  }
+  return result + ";";
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_php_generator::function_signature(t_function* tfunction, string prefix) {
+  return prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")";
+}
+
+/**
+ * Renders a field list
+ */
+string t_php_generator::argument_list(t_struct* tstruct, bool addTypeHints) {
+  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 += ", ";
+    }
+
+    t_type* type = (*f_iter)->get_type();
+
+    // Set type name
+    if (addTypeHints) {
+      if (type->is_struct()) {
+        string className = php_namespace(type->get_program())
+                           + php_namespace_directory("Definition", false)
+                           + classify(type->get_name());
+
+        result += className + " ";
+      } else if (type->is_container()) {
+        result += "array ";
+      }
+    }
+
+    result += "$" + (*f_iter)->get_name();
+  }
+  return result;
+}
+
+/**
+ * Gets a typecast string for a particular type.
+ */
+string t_php_generator::type_to_cast(t_type* type) {
+  if (type->is_base_type()) {
+    t_base_type* btype = (t_base_type*)type;
+    switch (btype->get_base()) {
+    case t_base_type::TYPE_BOOL:
+      return "(bool)";
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      return "(int)";
+    case t_base_type::TYPE_DOUBLE:
+      return "(double)";
+    case t_base_type::TYPE_STRING:
+      return "(string)";
+    default:
+      return "";
+    }
+  } else if (type->is_enum()) {
+    return "(int)";
+  }
+  return "";
+}
+
+/**
+ * Converts the parse type to a C++ enum string for the given type.
+ */
+string t_php_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 "TType::STRING";
+    case t_base_type::TYPE_BOOL:
+      return "TType::BOOL";
+    case t_base_type::TYPE_I8:
+      return "TType::BYTE";
+    case t_base_type::TYPE_I16:
+      return "TType::I16";
+    case t_base_type::TYPE_I32:
+      return "TType::I32";
+    case t_base_type::TYPE_I64:
+      return "TType::I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "TType::DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "TType::I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType::STRUCT";
+  } else if (type->is_map()) {
+    return "TType::MAP";
+  } else if (type->is_set()) {
+    return "TType::SET";
+  } else if (type->is_list()) {
+    return "TType::LST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ * Converts the parse type to a PHPDoc string for the given type.
+ */
+string t_php_generator::type_to_phpdoc(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:
+      return "void";
+    case t_base_type::TYPE_STRING:
+      return "string";
+    case t_base_type::TYPE_BOOL:
+      return "bool";
+    case t_base_type::TYPE_I8:
+      return "int";
+    case t_base_type::TYPE_I16:
+      return "int";
+    case t_base_type::TYPE_I32:
+      return "int";
+    case t_base_type::TYPE_I64:
+      return "int";
+    case t_base_type::TYPE_DOUBLE:
+      return "double";
+    }
+  } else if (type->is_enum()) {
+    return "int";
+  } else if (type->is_struct() || type->is_xception()) {
+    return php_namespace(type->get_program()) + type->get_name();
+  } else if (type->is_map()) {
+    return "array";
+  } else if (type->is_set()) {
+    t_set* tset = static_cast<t_set*>(type);
+    t_type* t_elem = tset->get_elem_type();
+    if (t_elem->is_container()) {
+      return "(" + type_to_phpdoc(t_elem) + ")[]";
+    } else {
+      return type_to_phpdoc(t_elem) + "[]";
+    }
+  } else if (type->is_list()) {
+    t_list* tlist = static_cast<t_list*>(type);
+    t_type* t_elem = tlist->get_elem_type();
+    if (t_elem->is_container()) {
+      return "(" + type_to_phpdoc(t_elem) + ")[]";
+    } else {
+      return type_to_phpdoc(t_elem) + "[]";
+    }
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(
+    php,
+    "PHP",
+    "    inlined:         Generate PHP inlined files\n"
+    "    server:          Generate PHP server stubs\n"
+    "    oop:             Generate PHP with object oriented subclasses\n"
+    "    classmap:        Generate old-style PHP files (use classmap autoloading)\n"
+    "    rest:            Generate PHP REST processors\n"
+    "    nsglobal=NAME:   Set global namespace\n"
+    "    validate:        Generate PHP validator methods\n"
+    "    json:            Generate JsonSerializable classes (requires PHP >= 5.4)\n")
diff --git a/compiler/cpp/src/thrift/generate/t_py_generator.cc b/compiler/cpp/src/thrift/generate/t_py_generator.cc
new file mode 100644
index 0000000..e46207a
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_py_generator.cc
@@ -0,0 +1,2767 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <limits>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+#include <algorithm>
+#include "thrift/platform.h"
+#include "thrift/version.h"
+#include "thrift/generate/t_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * Python code generator.
+ *
+ */
+class t_py_generator : public t_generator {
+public:
+  t_py_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;
+
+    gen_newstyle_ = true;
+    gen_utf8strings_ = true;
+    gen_dynbase_ = false;
+    gen_slots_ = false;
+    gen_tornado_ = false;
+    gen_zope_interface_ = false;
+    gen_twisted_ = false;
+    gen_dynamic_ = false;
+    coding_ = "";
+    gen_dynbaseclass_ = "";
+    gen_dynbaseclass_exc_ = "";
+    gen_dynbaseclass_frozen_ = "";
+    import_dynbase_ = "";
+    package_prefix_ = "";
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("new_style") == 0) {
+        pwarning(0, "new_style is enabled by default, so the option will be removed in the near future.\n");
+      } else if( iter->first.compare("old_style") == 0) {
+        gen_newstyle_ = false;
+        pwarning(0, "old_style is deprecated and may be removed in the future.\n");
+      } else if( iter->first.compare("utf8strings") == 0) {
+        pwarning(0, "utf8strings is enabled by default, so the option will be removed in the near future.\n");
+      } else if( iter->first.compare("no_utf8strings") == 0) {
+        gen_utf8strings_ = false;
+      } else if( iter->first.compare("slots") == 0) {
+        gen_slots_ = true;
+      } else if( iter->first.compare("package_prefix") == 0) {
+        package_prefix_ = iter->second;
+      } else if( iter->first.compare("dynamic") == 0) {
+        gen_dynamic_ = true;
+        gen_newstyle_ = false; // dynamic is newstyle
+        if( gen_dynbaseclass_.empty()) {
+          gen_dynbaseclass_ = "TBase";
+        }
+        if( gen_dynbaseclass_frozen_.empty()) {
+          gen_dynbaseclass_frozen_ = "TFrozenBase";
+        }
+        if( gen_dynbaseclass_exc_.empty()) {
+          gen_dynbaseclass_exc_ = "TExceptionBase";
+        }
+        if( import_dynbase_.empty()) {
+          import_dynbase_ = "from thrift.protocol.TBase import TBase, TFrozenBase, TExceptionBase, TTransport\n";
+        }
+      } else if( iter->first.compare("dynbase") == 0) {
+        gen_dynbase_ = true;
+        gen_dynbaseclass_ = (iter->second);
+      } else if( iter->first.compare("dynfrozen") == 0) {
+        gen_dynbaseclass_frozen_ = (iter->second);
+      } else if( iter->first.compare("dynexc") == 0) {
+        gen_dynbaseclass_exc_ = (iter->second);
+      } else if( iter->first.compare("dynimport") == 0) {
+        gen_dynbase_ = true;
+        import_dynbase_ = (iter->second);
+      } else if( iter->first.compare("zope.interface") == 0) {
+        gen_zope_interface_ = true;
+      } else if( iter->first.compare("twisted") == 0) {
+        gen_twisted_ = true;
+        gen_zope_interface_ = true;
+      } else if( iter->first.compare("tornado") == 0) {
+        gen_tornado_ = true;
+      } else if( iter->first.compare("coding") == 0) {
+        coding_ = iter->second;
+      } else {
+        throw "unknown option py:" + iter->first;
+      }
+    }
+
+    if (gen_twisted_ && gen_tornado_) {
+      throw "at most one of 'twisted' and 'tornado' are allowed";
+    }
+
+    copy_options_ = option_string;
+
+    if (gen_twisted_) {
+      out_dir_base_ = "gen-py.twisted";
+    } else if (gen_tornado_) {
+      out_dir_base_ = "gen-py.tornado";
+    } else {
+      out_dir_base_ = "gen-py";
+    }
+  }
+
+  virtual std::string indent_str() const {
+    return "    ";
+  }
+
+  /**
+   * 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_forward_declaration(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);
+
+  /**
+   * Struct generation code
+   */
+
+  void generate_py_struct(t_struct* tstruct, bool is_exception);
+  void generate_py_thrift_spec(std::ostream& out, t_struct* tstruct, bool is_exception);
+  void generate_py_struct_definition(std::ostream& out,
+                                     t_struct* tstruct,
+                                     bool is_xception = false);
+  void generate_py_struct_reader(std::ostream& out, t_struct* tstruct);
+  void generate_py_struct_writer(std::ostream& out, t_struct* tstruct);
+  void generate_py_struct_required_validator(std::ostream& out, t_struct* tstruct);
+  void generate_py_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::ostream& out,
+                                  t_field* tfield,
+                                  std::string prefix = "");
+
+  void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
+
+  void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         std::string prefix = "");
+
+  void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
+
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string kiter,
+                                      std::string viter);
+
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  void generate_python_docstring(std::ostream& out, t_struct* tstruct);
+
+  void generate_python_docstring(std::ostream& out, t_function* tfunction);
+
+  void generate_python_docstring(std::ostream& out,
+                                 t_doc* tdoc,
+                                 t_struct* tstruct,
+                                 const char* subheader);
+
+  void generate_python_docstring(std::ostream& out, t_doc* tdoc);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string py_autogen_comment();
+  std::string py_imports();
+  std::string render_includes();
+  std::string declare_argument(t_field* tfield);
+  std::string render_field_default_value(t_field* tfield);
+  std::string type_name(t_type* ttype);
+  std::string function_signature(t_function* tfunction, bool interface = false);
+  std::string argument_list(t_struct* tstruct,
+                            std::vector<std::string>* pre = NULL,
+                            std::vector<std::string>* post = NULL);
+  std::string type_to_enum(t_type* ttype);
+  std::string type_to_spec_args(t_type* ttype);
+
+  static bool is_valid_namespace(const std::string& sub_namespace) {
+    return sub_namespace == "twisted";
+  }
+
+  static std::string get_real_py_module(const t_program* program, bool gen_twisted, std::string package_dir="") {
+    if (gen_twisted) {
+      std::string twisted_module = program->get_namespace("py.twisted");
+      if (!twisted_module.empty()) {
+        return twisted_module;
+      }
+    }
+
+    std::string real_module = program->get_namespace("py");
+    if (real_module.empty()) {
+      return program->get_name();
+    }
+    return package_dir + real_module;
+  }
+
+  static bool is_immutable(t_type* ttype) {
+    return ttype->annotations_.find("python.immutable") != ttype->annotations_.end();
+  }
+
+private:
+
+  /**
+   * True if we should generate new-style classes.
+   */
+  bool gen_newstyle_;
+
+  /**
+  * True if we should generate dynamic style classes.
+  */
+  bool gen_dynamic_;
+
+  bool gen_dynbase_;
+  std::string gen_dynbaseclass_;
+  std::string gen_dynbaseclass_frozen_;
+  std::string gen_dynbaseclass_exc_;
+
+  std::string import_dynbase_;
+
+  bool gen_slots_;
+
+  std::string copy_options_;
+
+  /**
+   * True if we should generate code for use with zope.interface.
+   */
+  bool gen_zope_interface_;
+
+  /**
+   * True if we should generate Twisted-friendly RPC services.
+   */
+  bool gen_twisted_;
+
+  /**
+   * True if we should generate code for use with Tornado
+   */
+  bool gen_tornado_;
+
+  /**
+   * True if strings should be encoded using utf-8.
+   */
+  bool gen_utf8strings_;
+
+  /**
+   * specify generated file encoding
+   * eg. # -*- coding: utf-8 -*-
+   */
+  string coding_;
+
+  string package_prefix_;
+
+  /**
+   * File streams
+   */
+
+  ofstream_with_content_based_conditional_update f_types_;
+  ofstream_with_content_based_conditional_update f_consts_;
+  ofstream_with_content_based_conditional_update f_service_;
+
+  std::string package_dir_;
+  std::string module_;
+
+protected:
+  virtual std::set<std::string> lang_keywords() const {
+    std::string keywords[] = { "False", "None", "True", "and", "as", "assert", "break", "class",
+          "continue", "def", "del", "elif", "else", "except", "exec", "finally", "for", "from",
+          "global", "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass", "print",
+          "raise", "return", "try", "while", "with", "yield" };
+    return std::set<std::string>(keywords, keywords + sizeof(keywords)/sizeof(keywords[0]) );
+  }
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_py_generator::init_generator() {
+  // Make output directory
+  string module = get_real_py_module(program_, gen_twisted_);
+  package_dir_ = get_out_dir();
+  module_ = module;
+  while (true) {
+    // TODO: Do better error checking here.
+    MKDIR(package_dir_.c_str());
+    std::ofstream init_py((package_dir_ + "/__init__.py").c_str(), std::ios_base::app);
+    init_py.close();
+    if (module.empty()) {
+      break;
+    }
+    string::size_type pos = module.find('.');
+    if (pos == string::npos) {
+      package_dir_ += "/";
+      package_dir_ += module;
+      module.clear();
+    } else {
+      package_dir_ += "/";
+      package_dir_ += module.substr(0, pos);
+      module.erase(0, pos + 1);
+    }
+  }
+
+  // Make output file
+  string f_types_name = package_dir_ + "/" + "ttypes.py";
+  f_types_.open(f_types_name.c_str());
+
+  string f_consts_name = package_dir_ + "/" + "constants.py";
+  f_consts_.open(f_consts_name.c_str());
+
+  string f_init_name = package_dir_ + "/__init__.py";
+  ofstream_with_content_based_conditional_update f_init;
+  f_init.open(f_init_name.c_str());
+  f_init << "__all__ = ['ttypes', 'constants'";
+  vector<t_service*> services = program_->get_services();
+  vector<t_service*>::iterator sv_iter;
+  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    f_init << ", '" << (*sv_iter)->get_name() << "'";
+  }
+  f_init << "]" << endl;
+  f_init.close();
+
+  // Print header
+  f_types_ << py_autogen_comment() << endl
+           << py_imports() << endl
+           << render_includes() << endl
+           << "from thrift.transport import TTransport" << endl
+           << import_dynbase_;
+
+  f_types_ << "all_structs = []" << endl;
+
+  f_consts_ <<
+    py_autogen_comment() << endl <<
+    py_imports() << endl <<
+    "from .ttypes import *" << endl;
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program
+ */
+string t_py_generator::render_includes() {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = "";
+  for (size_t i = 0; i < includes.size(); ++i) {
+    result += "import " + get_real_py_module(includes[i], gen_twisted_, package_prefix_) + ".ttypes\n";
+  }
+  return result;
+}
+
+/**
+ * Autogen'd comment
+ */
+string t_py_generator::py_autogen_comment() {
+  string coding;
+  if (!coding_.empty()) {
+      coding = "# -*- coding: " + coding_ + " -*-\n";
+  }
+  return coding + std::string("#\n") + "# Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
+         + "#\n" + "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "#\n"
+         + "#  options string: " + copy_options_ + "\n" + "#\n";
+}
+
+/**
+ * Prints standard thrift imports
+ */
+string t_py_generator::py_imports() {
+  ostringstream ss;
+  ss << "from thrift.Thrift import TType, TMessageType, TFrozenDict, TException, "
+        "TApplicationException"
+     << endl
+     << "from thrift.protocol.TProtocol import TProtocolException"
+     << endl
+     << "from thrift.TRecursive import fix_spec"
+     << endl;
+
+  if (gen_utf8strings_) {
+    ss << endl << "import sys";
+  }
+  return ss.str();
+}
+
+/**
+ * Closes the type files
+ */
+void t_py_generator::close_generator() {
+
+  // Fix thrift_spec definitions for recursive structs.
+  f_types_ << "fix_spec(all_structs)" << endl;
+  f_types_ << "del all_structs" << endl;
+
+  // Close types file
+  f_types_.close();
+  f_consts_.close();
+}
+
+/**
+ * Generates a typedef. This is not done in Python, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_py_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+/**
+ * Generates code for an enumerated type. Done using a class to scope
+ * the values.
+ *
+ * @param tenum The enumeration
+ */
+void t_py_generator::generate_enum(t_enum* tenum) {
+  std::ostringstream to_string_mapping, from_string_mapping;
+
+  f_types_ << endl << endl << "class " << tenum->get_name() << (gen_newstyle_ ? "(object)" : "")
+           << (gen_dynamic_ ? "(" + gen_dynbaseclass_ + ")" : "") << ":" << endl;
+  indent_up();
+  generate_python_docstring(f_types_, tenum);
+
+  to_string_mapping << indent() << "_VALUES_TO_NAMES = {" << endl;
+  from_string_mapping << indent() << "_NAMES_TO_VALUES = {" << endl;
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    indent(f_types_) << (*c_iter)->get_name() << " = " << value << endl;
+
+    // Dictionaries to/from string names of enums
+    to_string_mapping << indent() << indent() << value << ": \""
+                      << escape_string((*c_iter)->get_name()) << "\"," << endl;
+    from_string_mapping << indent() << indent() << '"' << escape_string((*c_iter)->get_name())
+                        << "\": " << value << ',' << endl;
+  }
+  to_string_mapping << indent() << "}" << endl;
+  from_string_mapping << indent() << "}" << endl;
+
+  indent_down();
+  f_types_ << endl;
+  f_types_ << to_string_mapping.str() << endl << from_string_mapping.str();
+}
+
+/**
+ * Generate a constant value
+ */
+void t_py_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  indent(f_consts_) << name << " = " << render_const_value(type, value);
+  f_consts_ << 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_py_generator::render_const_value(t_type* type, t_const_value* value) {
+  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_I8:
+    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 << "float(" << value->get_integer() << ")";
+      } else {
+        out << emit_double_as_string(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()) {
+    out << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    out << type_name(type) << "(**{" << 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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::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();
+      }
+      indent(out) << render_const_value(g_type_string, v_iter->first) << ": "
+          << render_const_value(field_type, v_iter->second) << "," << endl;
+    }
+    indent_down();
+    indent(out) << "})";
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    if (is_immutable(type)) {
+      out << "TFrozenDict(";
+    }
+    out << "{" << endl;
+    indent_up();
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      indent(out) << render_const_value(ktype, v_iter->first) << ": "
+          << render_const_value(vtype, v_iter->second) << "," << endl;
+    }
+    indent_down();
+    indent(out) << "}";
+    if (is_immutable(type)) {
+      out << ")";
+    }
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    if (type->is_set()) {
+      if (is_immutable(type)) {
+        out << "frozen";
+      }
+      out << "set(";
+    }
+    if (is_immutable(type) || type->is_set()) {
+      out << "(" << endl;
+    } else {
+      out << "[" << endl;
+    }
+    indent_up();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      indent(out) << render_const_value(etype, *v_iter) << "," << endl;
+    }
+    indent_down();
+    if (is_immutable(type) || type->is_set()) {
+      indent(out) << ")";
+    } else {
+      indent(out) << "]";
+    }
+    if (type->is_set()) {
+      out << ")";
+    }
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+
+  return out.str();
+}
+
+/**
+ * Generates the "forward declarations" for python structs.
+ * These are actually full class definitions so that calls to generate_struct
+ * can add the thrift_spec field.  This is needed so that all thrift_spec
+ * definitions are grouped at the end of the file to enable co-recursive structs.
+ */
+void t_py_generator::generate_forward_declaration(t_struct* tstruct) {
+    generate_py_struct(tstruct, tstruct->is_xception());
+}
+
+/**
+ * Generates a python struct
+ */
+void t_py_generator::generate_struct(t_struct* tstruct) {
+  generate_py_thrift_spec(f_types_, 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_py_generator::generate_xception(t_struct* txception) {
+  generate_py_thrift_spec(f_types_, txception, true);
+}
+
+/**
+ * Generates a python struct
+ */
+void t_py_generator::generate_py_struct(t_struct* tstruct, bool is_exception) {
+  generate_py_struct_definition(f_types_, tstruct, is_exception);
+}
+
+
+/**
+ * Generate the thrift_spec for a struct
+ * For example,
+ *   all_structs.append(Recursive)
+ *   Recursive.thrift_spec = (
+ *       None,  # 0
+ *       (1, TType.LIST, 'Children', (TType.STRUCT, (Recursive, None), False), None, ),  # 1
+ *   )
+ */
+void t_py_generator::generate_py_thrift_spec(ostream& out,
+                                             t_struct* tstruct,
+                                             bool /*is_exception*/) {
+  const vector<t_field*>& sorted_members = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  // Add struct definition to list so thrift_spec can be fixed for recursive structures.
+  indent(out) << "all_structs.append(" << tstruct->get_name() << ")" << endl;
+
+  if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) {
+    indent(out) << tstruct->get_name() << ".thrift_spec = (" << endl;
+    indent_up();
+
+    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++) {
+        indent(out) << "None,  # " << sorted_keys_pos << endl;
+      }
+
+      indent(out) << "(" << (*m_iter)->get_key() << ", " << type_to_enum((*m_iter)->get_type())
+                  << ", "
+                  << "'" << (*m_iter)->get_name() << "'"
+                  << ", " << type_to_spec_args((*m_iter)->get_type()) << ", "
+                  << render_field_default_value(*m_iter) << ", "
+                  << "),"
+                  << "  # " << sorted_keys_pos << endl;
+
+      sorted_keys_pos++;
+    }
+
+    indent_down();
+    indent(out) << ")" << endl;
+  } else {
+    indent(out) << tstruct->get_name() << ".thrift_spec = ()" << endl;
+  }
+}
+
+/**
+ * Generates a struct definition for a thrift data type.
+ *
+ * @param tstruct The struct definition
+ */
+void t_py_generator::generate_py_struct_definition(ostream& out,
+                                                   t_struct* tstruct,
+                                                   bool is_exception) {
+  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;
+
+  out << endl << endl << "class " << tstruct->get_name();
+  if (is_exception) {
+    if (gen_dynamic_) {
+      out << "(" << gen_dynbaseclass_exc_ << ")";
+    } else {
+      out << "(TException)";
+    }
+  } else if (gen_dynamic_) {
+    if (is_immutable(tstruct)) {
+      out << "(" << gen_dynbaseclass_frozen_ << ")";
+    } else  {
+      out << "(" << gen_dynbaseclass_ << ")";
+    }
+  } else if (gen_newstyle_) {
+    out << "(object)";
+  }
+  out << ":" << endl;
+  indent_up();
+  generate_python_docstring(out, tstruct);
+
+  out << 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 -> None | (tag, type_enum, name, spec_args, default)
+     tag -> integer
+     type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ...
+     name -> string_literal
+     default -> None  # Handled by __init__
+     spec_args -> None  # 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.
+  */
+
+  if (gen_slots_) {
+    indent(out) << "__slots__ = (" << endl;
+    indent_up();
+    for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) {
+      indent(out) << "'" << (*m_iter)->get_name() << "'," << endl;
+    }
+    indent_down();
+    indent(out) << ")" << endl << endl;
+  }
+
+  // TODO(dreiss): Look into generating an empty tuple instead of None
+  // for structures with no members.
+  // TODO(dreiss): Test encoding of structs where some inner structs
+  // don't have thrift_spec.
+
+  if (members.size() > 0) {
+    out << endl;
+    out << indent() << "def __init__(self,";
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      out << " " << declare_argument(*m_iter) << ",";
+    }
+    out << "):" << endl;
+
+    indent_up();
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      // Initialize fields
+      t_type* type = (*m_iter)->get_type();
+      if (!type->is_base_type() && !type->is_enum() && (*m_iter)->get_value() != NULL) {
+        indent(out) << "if " << (*m_iter)->get_name() << " is "
+                    << "self.thrift_spec[" << (*m_iter)->get_key() << "][4]:" << endl;
+        indent_up();
+        indent(out) << (*m_iter)->get_name() << " = " << render_field_default_value(*m_iter)
+                    << endl;
+        indent_down();
+      }
+
+      if (is_immutable(tstruct)) {
+        if (gen_newstyle_ || gen_dynamic_) {
+          indent(out) << "super(" << tstruct->get_name() << ", self).__setattr__('"
+                      << (*m_iter)->get_name() << "', " << (*m_iter)->get_name() << ")" << endl;
+        } else {
+          indent(out) << "self.__dict__['" << (*m_iter)->get_name()
+                      << "'] = " << (*m_iter)->get_name() << endl;
+        }
+      } else {
+        indent(out) << "self." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << endl;
+      }
+    }
+
+    indent_down();
+  }
+
+  if (is_immutable(tstruct)) {
+    out << endl;
+    out << indent() << "def __setattr__(self, *args):" << endl
+        << indent() << indent_str() << "raise TypeError(\"can't modify immutable instance\")" << endl
+        << endl;
+    out << indent() << "def __delattr__(self, *args):" << endl
+        << indent() << indent_str() << "raise TypeError(\"can't modify immutable instance\")" << endl
+        << endl;
+
+    // Hash all of the members in order, and also hash in the class
+    // to avoid collisions for stuff like single-field structures.
+    out << indent() << "def __hash__(self):" << endl
+        << indent() << indent_str() << "return hash(self.__class__) ^ hash((";
+
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      out << "self." << (*m_iter)->get_name() << ", ";
+    }
+
+    out << "))" << endl;
+  }
+
+  if (!gen_dynamic_) {
+    out << endl;
+    generate_py_struct_reader(out, tstruct);
+    generate_py_struct_writer(out, tstruct);
+  }
+
+  // For exceptions only, generate a __str__ method. This is
+  // because when raised exceptions are printed to the console, __repr__
+  // isn't used. See python bug #5882
+  if (is_exception) {
+    out << endl;
+    out << indent() << "def __str__(self):" << endl
+        << indent() << indent_str() << "return repr(self)" << endl;
+  }
+
+  if (!gen_slots_) {
+    out << endl;
+    // Printing utilities so that on the command line thrift
+    // structs look pretty like dictionaries
+    indent(out) << "def __repr__(self):" << endl;
+    indent_up();
+    out << indent() << "L = ['%s=%r' % (key, value)" << endl
+        << indent() << "     for key, value in self.__dict__.items()]" << endl
+        << indent() << "return '%s(%s)' % (self.__class__.__name__, ', '.join(L))" << endl
+        << endl;
+    indent_down();
+
+    // Equality and inequality methods that compare by value
+    out << indent() << "def __eq__(self, other):" << endl;
+    indent_up();
+    out << indent() << "return isinstance(other, self.__class__) and "
+                       "self.__dict__ == other.__dict__" << endl;
+    indent_down();
+    out << endl;
+
+    out << indent() << "def __ne__(self, other):" << endl;
+    indent_up();
+
+    out << indent() << "return not (self == other)" << endl;
+    indent_down();
+  } else if (!gen_dynamic_) {
+    out << endl;
+    // no base class available to implement __eq__ and __repr__ and __ne__ for us
+    // so we must provide one that uses __slots__
+    indent(out) << "def __repr__(self):" << endl;
+    indent_up();
+    out << indent() << "L = ['%s=%r' % (key, getattr(self, key))" << endl
+        << indent() << "     for key in self.__slots__]" << endl
+        << indent() << "return '%s(%s)' % (self.__class__.__name__, ', '.join(L))" << endl
+        << endl;
+    indent_down();
+
+    // Equality method that compares each attribute by value and type, walking __slots__
+    out << indent() << "def __eq__(self, other):" << endl;
+    indent_up();
+    out << indent() << "if not isinstance(other, self.__class__):" << endl
+        << indent() << indent_str() << "return False" << endl
+        << indent() << "for attr in self.__slots__:" << endl
+        << indent() << indent_str() << "my_val = getattr(self, attr)" << endl
+        << indent() << indent_str() << "other_val = getattr(other, attr)" << endl
+        << indent() << indent_str() << "if my_val != other_val:" << endl
+        << indent() << indent_str() << indent_str() << "return False" << endl
+        << indent() << "return True" << endl
+        << endl;
+    indent_down();
+
+    out << indent() << "def __ne__(self, other):" << endl
+        << indent() << indent_str() << "return not (self == other)" << endl;
+  }
+  indent_down();
+}
+
+/**
+ * Generates the read method for a struct
+ */
+void t_py_generator::generate_py_struct_reader(ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  if (is_immutable(tstruct)) {
+    out << indent() << "@classmethod" << endl << indent() << "def read(cls, iprot):" << endl;
+  } else {
+    indent(out) << "def read(self, iprot):" << endl;
+  }
+  indent_up();
+
+  const char* id = is_immutable(tstruct) ? "cls" : "self";
+
+  indent(out) << "if iprot._fast_decode is not None "
+                 "and isinstance(iprot.trans, TTransport.CReadableTransport) "
+                 "and "
+              << id << ".thrift_spec is not None:" << endl;
+  indent_up();
+
+  if (is_immutable(tstruct)) {
+    indent(out) << "return iprot._fast_decode(None, iprot, [cls, cls.thrift_spec])" << endl;
+  } else {
+    indent(out) << "iprot._fast_decode(self, iprot, [self.__class__, self.thrift_spec])" << endl;
+    indent(out) << "return" << endl;
+  }
+  indent_down();
+
+  indent(out) << "iprot.readStructBegin()" << endl;
+  
+  if (is_immutable(tstruct)) {
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      t_field* tfield = *f_iter;
+      std::ostringstream result;
+      result << tfield->get_name() << " = ";
+      if (tfield->get_value() != NULL) {
+        result << render_field_default_value(tfield);
+      } else {
+        result << "None";
+      }
+      indent(out) << result.str() << endl;
+     }
+  }
+
+  // Loop over reading in fields
+  indent(out) << "while True:" << endl;
+  indent_up();
+
+  // Read beginning field marker
+  indent(out) << "(fname, ftype, fid) = iprot.readFieldBegin()" << endl;
+
+  // Check for field STOP marker and break
+  indent(out) << "if ftype == TType.STOP:" << endl;
+  indent_up();
+  indent(out) << "break" << endl;
+  indent_down();
+
+  // Switch statement on the field we are reading
+  bool first = true;
+
+  // Generate deserialization code for known cases
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+      out << indent() << "if ";
+    } else {
+      out << indent() << "elif ";
+    }
+    out << "fid == " << (*f_iter)->get_key() << ":" << endl;
+    indent_up();
+    indent(out) << "if ftype == " << type_to_enum((*f_iter)->get_type()) << ":" << endl;
+    indent_up();
+    if (is_immutable(tstruct)) {
+      generate_deserialize_field(out, *f_iter);
+    } else {
+      generate_deserialize_field(out, *f_iter, "self.");
+    }
+    indent_down();
+    out << indent() << "else:" << endl << indent() << indent_str() << "iprot.skip(ftype)" << endl;
+    indent_down();
+  }
+
+  // In the default case we skip the field
+  out << indent() << "else:" << endl << indent() << indent_str() << "iprot.skip(ftype)" << endl;
+
+  // Read field end marker
+  indent(out) << "iprot.readFieldEnd()" << endl;
+
+  indent_down();
+
+  indent(out) << "iprot.readStructEnd()" << endl;
+
+  if (is_immutable(tstruct)) {
+    indent(out) << "return cls(" << endl;
+    indent_up();
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      indent(out) << (*f_iter)->get_name() << "=" << (*f_iter)->get_name() << "," << endl;
+    }
+    indent_down();
+    indent(out) << ")" << endl;
+  }
+
+  indent_down();
+  out << endl;
+}
+
+void t_py_generator::generate_py_struct_writer(ostream& out, t_struct* tstruct) {
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "def write(self, oprot):" << endl;
+  indent_up();
+
+  indent(out) << "if oprot._fast_encode is not None and self.thrift_spec is not None:" << endl;
+  indent_up();
+
+  indent(out)
+      << "oprot.trans.write(oprot._fast_encode(self, [self.__class__, self.thrift_spec]))"
+      << endl;
+  indent(out) << "return" << endl;
+  indent_down();
+
+  indent(out) << "oprot.writeStructBegin('" << name << "')" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    // Write field header
+    indent(out) << "if self." << (*f_iter)->get_name() << " is not None:" << endl;
+    indent_up();
+    indent(out) << "oprot.writeFieldBegin("
+                << "'" << (*f_iter)->get_name() << "', " << type_to_enum((*f_iter)->get_type())
+                << ", " << (*f_iter)->get_key() << ")" << endl;
+
+    // Write field contents
+    generate_serialize_field(out, *f_iter, "self.");
+
+    // Write field closer
+    indent(out) << "oprot.writeFieldEnd()" << endl;
+
+    indent_down();
+  }
+
+  // Write the struct map
+  out << indent() << "oprot.writeFieldStop()" << endl << indent() << "oprot.writeStructEnd()"
+      << endl;
+
+  out << endl;
+
+  indent_down();
+  generate_py_struct_required_validator(out, tstruct);
+}
+
+void t_py_generator::generate_py_struct_required_validator(ostream& out, t_struct* tstruct) {
+  indent(out) << "def validate(self):" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+
+  if (fields.size() > 0) {
+    vector<t_field*>::const_iterator f_iter;
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      t_field* field = (*f_iter);
+      if (field->get_req() == t_field::T_REQUIRED) {
+        indent(out) << "if self." << field->get_name() << " is None:" << endl;
+        indent(out) << indent_str() << "raise TProtocolException(message='Required field "
+                    << field->get_name() << " is unset!')" << endl;
+      }
+    }
+  }
+
+  indent(out) << "return" << endl;
+  indent_down();
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_py_generator::generate_service(t_service* tservice) {
+  string f_service_name = package_dir_ + "/" + service_name_ + ".py";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << py_autogen_comment() << endl << py_imports() << endl;
+
+  if (tservice->get_extends() != NULL) {
+    f_service_ << "import "
+               << get_real_py_module(tservice->get_extends()->get_program(), gen_twisted_, package_prefix_) << "."
+               << tservice->get_extends()->get_name() << endl;
+  }
+
+  f_service_ << "import logging" << endl
+             << "from .ttypes import *" << endl
+             << "from thrift.Thrift import TProcessor" << endl
+             << "from thrift.transport import TTransport" << endl
+             << import_dynbase_;
+  if (gen_zope_interface_) {
+    f_service_ << "from zope.interface import Interface, implementer" << endl;
+  }
+
+  if (gen_twisted_) {
+    f_service_ << "from twisted.internet import defer" << endl
+               << "from thrift.transport import TTwisted" << endl;
+  } else if (gen_tornado_) {
+    f_service_ << "from tornado import gen" << endl;
+    f_service_ << "from tornado import concurrent" << endl;
+  }
+
+  f_service_ << "all_structs = []" << endl;
+
+  // Generate the three main parts of the service
+  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_ << "fix_spec(all_structs)" << endl
+             << "del all_structs" << endl << endl;
+  f_service_.close();
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_py_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  f_service_ << endl << "# HELPER FUNCTIONS AND STRUCTURES" << endl;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_struct* ts = (*f_iter)->get_arglist();
+    generate_py_struct_definition(f_service_, ts, false);
+    generate_py_thrift_spec(f_service_, ts, false);
+    generate_py_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_py_generator::generate_py_function_helpers(t_function* tfunction) {
+  if (!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_py_struct_definition(f_service_, &result, false);
+    generate_py_thrift_spec(f_service_, &result, false);
+  }
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_py_generator::generate_service_interface(t_service* tservice) {
+  string extends = "";
+  string extends_if = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_if = "(" + extends + ".Iface)";
+  } else {
+    if (gen_zope_interface_) {
+      extends_if = "(Interface)";
+    } else if (gen_newstyle_ || gen_dynamic_ || gen_tornado_) {
+      extends_if = "(object)";
+    }
+  }
+
+  f_service_ << endl << endl << "class Iface" << extends_if << ":" << endl;
+  indent_up();
+  generate_python_docstring(f_service_, tservice);
+  vector<t_function*> functions = tservice->get_functions();
+  if (functions.empty()) {
+    f_service_ << indent() << "pass" << endl;
+  } else {
+    vector<t_function*>::iterator f_iter;
+    bool first = true;
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << endl;
+      }
+      f_service_ << indent() << "def " << function_signature(*f_iter, true) << ":" << endl;
+      indent_up();
+      generate_python_docstring(f_service_, (*f_iter));
+      f_service_ << indent() << "pass" << endl;
+      indent_down();
+    }
+  }
+
+  indent_down();
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_py_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    if (gen_zope_interface_) {
+      extends_client = "(" + extends + ".Client)";
+    } else {
+      extends_client = extends + ".Client, ";
+    }
+  } else {
+    if (gen_zope_interface_ && (gen_newstyle_ || gen_dynamic_)) {
+      extends_client = "(object)";
+    }
+  }
+
+  f_service_ << endl << endl;
+
+  if (gen_zope_interface_) {
+    f_service_ << "@implementer(Iface)" << endl
+               << "class Client" << extends_client << ":" << endl
+               << endl;
+  } else {
+    f_service_ << "class Client(" << extends_client << "Iface):" << endl;
+  }
+  indent_up();
+  generate_python_docstring(f_service_, tservice);
+
+  // Constructor function
+  if (gen_twisted_) {
+    f_service_ << indent() << "def __init__(self, transport, oprot_factory):" << endl;
+  } else if (gen_tornado_) {
+    f_service_ << indent()
+               << "def __init__(self, transport, iprot_factory, oprot_factory=None):" << endl;
+  } else {
+    f_service_ << indent() << "def __init__(self, iprot, oprot=None):" << endl;
+  }
+  indent_up();
+  if (extends.empty()) {
+    if (gen_twisted_) {
+      f_service_ << indent() << "self._transport = transport" << endl
+                 << indent() << "self._oprot_factory = oprot_factory" << endl
+                 << indent() << "self._seqid = 0" << endl
+                 << indent() << "self._reqs = {}" << endl;
+    } else if (gen_tornado_) {
+      f_service_ << indent() << "self._transport = transport" << endl
+                 << indent() << "self._iprot_factory = iprot_factory" << endl
+                 << indent() << "self._oprot_factory = (oprot_factory if oprot_factory is not None"
+                 << endl
+                 << indent() << "                       else iprot_factory)" << endl
+                 << indent() << "self._seqid = 0" << endl
+                 << indent() << "self._reqs = {}" << endl
+                 << indent() << "self._transport.io_loop.spawn_callback(self._start_receiving)"
+                 << endl;
+    } else {
+      f_service_ << indent() << "self._iprot = self._oprot = iprot" << endl
+                 << indent() << "if oprot is not None:" << endl
+                 << indent() << indent_str() << "self._oprot = oprot" << endl
+                 << indent() << "self._seqid = 0" << endl;
+    }
+  } else {
+    if (gen_twisted_) {
+      f_service_ << indent() << extends
+                 << ".Client.__init__(self, transport, oprot_factory)" << endl;
+    } else if (gen_tornado_) {
+      f_service_ << indent() << extends
+                 << ".Client.__init__(self, transport, iprot_factory, oprot_factory)" << endl;
+    } else {
+      f_service_ << indent() << extends << ".Client.__init__(self, iprot, oprot)" << endl;
+    }
+  }
+  indent_down();
+
+  if (gen_tornado_ && extends.empty()) {
+    f_service_ << endl <<
+      indent() << "@gen.engine" << endl <<
+      indent() << "def _start_receiving(self):" << endl;
+    indent_up();
+    indent(f_service_) << "while True:" << endl;
+    indent_up();
+    f_service_ << indent() << "try:" << endl
+               << indent() << indent_str() << "frame = yield self._transport.readFrame()" << endl
+               << indent() << "except TTransport.TTransportException as e:" << endl
+               << indent() << indent_str() << "for future in self._reqs.values():" << endl
+               << indent() << indent_str() << indent_str() << "future.set_exception(e)" << endl
+               << indent() << indent_str() << "self._reqs = {}" << endl
+               << indent() << indent_str() << "return" << endl
+               << indent() << "tr = TTransport.TMemoryBuffer(frame)" << endl
+               << indent() << "iprot = self._iprot_factory.getProtocol(tr)" << endl
+               << indent() << "(fname, mtype, rseqid) = iprot.readMessageBegin()" << endl
+               << indent() << "method = getattr(self, 'recv_' + fname)" << endl
+               << indent() << "future = self._reqs.pop(rseqid, None)" << endl
+               << indent() << "if not future:" << endl
+               << indent() << indent_str() << "# future has already been discarded" << endl
+               << indent() << indent_str() << "continue" << endl
+               << indent() << "try:" << endl
+               << indent() << indent_str() << "result = method(iprot, mtype, rseqid)" << endl
+               << indent() << "except Exception as e:" << endl
+               << indent() << indent_str() << "future.set_exception(e)" << endl
+               << indent() << "else:" << endl
+               << indent() << indent_str() << "future.set_result(result)" << endl;
+    indent_down();
+    indent_down();
+  }
+
+  // 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 = (*f_iter)->get_name();
+
+    f_service_ << endl;
+    // Open function
+    indent(f_service_) << "def " << function_signature(*f_iter, false) << ":" << endl;
+    indent_up();
+    generate_python_docstring(f_service_, (*f_iter));
+    if (gen_twisted_) {
+      indent(f_service_) << "seqid = self._seqid = self._seqid + 1" << endl;
+      indent(f_service_) << "self._reqs[seqid] = defer.Deferred()" << endl << endl;
+      indent(f_service_) << "d = defer.maybeDeferred(self.send_" << funname;
+
+    } else if (gen_tornado_) {
+      indent(f_service_) << "self._seqid += 1" << endl;
+      if (!(*f_iter)->is_oneway()) {
+        indent(f_service_) << "future = self._reqs[self._seqid] = concurrent.Future()" << endl;
+      }
+      indent(f_service_) << "self.send_" << funname << "(";
+
+    } else {
+      indent(f_service_) << "self.send_" << funname << "(";
+    }
+
+    bool first = true;
+    if (gen_twisted_) {
+      // we need a leading comma if there are args, since it's called as maybeDeferred(funcname,
+      // arg)
+      first = false;
+    }
+    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;
+
+    if (!(*f_iter)->is_oneway()) {
+      if (gen_twisted_) {
+        // nothing. See the next block.
+      } else if (gen_tornado_) {
+        indent(f_service_) << "return future" << endl;
+      } else {
+        f_service_ << indent();
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          f_service_ << "return ";
+        }
+        f_service_ << "self.recv_" << funname << "()" << endl;
+      }
+    }
+    indent_down();
+
+    if (gen_twisted_) {
+      // This block injects the body of the send_<> method for twisted (and a cb/eb pair)
+      indent_up();
+      indent(f_service_) << "d.addCallbacks(" << endl;
+
+      indent_up();
+      f_service_ << indent() << "callback=self.cb_send_" << funname << "," << endl << indent()
+                 << "callbackArgs=(seqid,)," << endl << indent() << "errback=self.eb_send_"
+                 << funname << "," << endl << indent() << "errbackArgs=(seqid,))" << endl;
+      indent_down();
+
+      indent(f_service_) << "return d" << endl;
+      indent_down();
+      f_service_ << endl;
+
+      indent(f_service_) << "def cb_send_" << funname << "(self, _, seqid):" << endl;
+      indent_up();
+      if ((*f_iter)->is_oneway()) {
+        // if one-way, fire the deferred & remove it from _reqs
+        f_service_ << indent() << "d = self._reqs.pop(seqid)" << endl << indent()
+                   << "d.callback(None)" << endl << indent() << "return d" << endl;
+      } else {
+        f_service_ << indent() << "return self._reqs[seqid]" << endl;
+      }
+      indent_down();
+      f_service_ << endl;
+
+      // add an errback to fail the request if the call to send_<> raised an exception
+      indent(f_service_) << "def eb_send_" << funname << "(self, f, seqid):" << endl;
+      indent_up();
+      f_service_ << indent() << "d = self._reqs.pop(seqid)" << endl << indent() << "d.errback(f)"
+                 << endl << indent() << "return d" << endl;
+      indent_down();
+    }
+
+    f_service_ << endl;
+    indent(f_service_) << "def send_" << function_signature(*f_iter, false) << ":" << endl;
+    indent_up();
+
+    std::string argsname = (*f_iter)->get_name() + "_args";
+    std::string messageType = (*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL";
+
+    // Serialize the request header
+    if (gen_twisted_ || gen_tornado_) {
+      f_service_ << indent() << "oprot = self._oprot_factory.getProtocol(self._transport)" << endl
+                 << indent() << "oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', "
+                 << messageType << ", self._seqid)" << endl;
+    } else {
+      f_service_ << indent() << "self._oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', "
+                 << messageType << ", self._seqid)" << endl;
+    }
+
+    f_service_ << indent() << "args = " << argsname << "()" << endl;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << indent() << "args." << (*fld_iter)->get_name() << " = "
+                 << (*fld_iter)->get_name() << endl;
+    }
+
+    // Write to the stream
+    if (gen_twisted_ || gen_tornado_) {
+      f_service_ << indent() << "args.write(oprot)" << endl << indent() << "oprot.writeMessageEnd()"
+                 << endl << indent() << "oprot.trans.flush()" << endl;
+    } else {
+      f_service_ << indent() << "args.write(self._oprot)" << endl << indent()
+                 << "self._oprot.writeMessageEnd()" << endl << indent()
+                 << "self._oprot.trans.flush()" << endl;
+    }
+
+    indent_down();
+
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultname = (*f_iter)->get_name() + "_result";
+      // Open function
+      f_service_ << endl;
+      if (gen_twisted_ || gen_tornado_) {
+        f_service_ << indent() << "def recv_" << (*f_iter)->get_name()
+                   << "(self, iprot, mtype, rseqid):" << endl;
+      } else {
+        t_struct noargs(program_);
+        t_function recv_function((*f_iter)->get_returntype(),
+                                 string("recv_") + (*f_iter)->get_name(),
+                                 &noargs);
+        f_service_ << indent() << "def " << function_signature(&recv_function) << ":" << endl;
+      }
+      indent_up();
+
+      // TODO(mcslee): Validate message reply here, seq ids etc.
+
+      if (gen_twisted_) {
+        f_service_ << indent() << "d = self._reqs.pop(rseqid)" << endl;
+      } else if (gen_tornado_) {
+      } else {
+        f_service_ << indent() << "iprot = self._iprot" << endl << indent()
+                   << "(fname, mtype, rseqid) = iprot.readMessageBegin()" << endl;
+      }
+
+      f_service_ << indent() << "if mtype == TMessageType.EXCEPTION:" << endl
+                 << indent() << indent_str() << "x = TApplicationException()" << endl;
+
+      if (gen_twisted_) {
+        f_service_ << indent() << indent_str() << "x.read(iprot)" << endl << indent()
+                   << indent_str() << "iprot.readMessageEnd()" << endl << indent() << indent_str() << "return d.errback(x)"
+                   << endl << indent() << "result = " << resultname << "()" << endl << indent()
+                   << "result.read(iprot)" << endl << indent() << "iprot.readMessageEnd()" << endl;
+      } else {
+        f_service_ << indent() << indent_str() << "x.read(iprot)" << endl << indent()
+                   << indent_str() << "iprot.readMessageEnd()" << endl << indent() << indent_str() << "raise x" << endl
+                   << indent() << "result = " << resultname << "()" << endl << indent()
+                   << "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() << "if result.success is not None:" << endl;
+        if (gen_twisted_) {
+          f_service_ << indent() << indent_str() << "return d.callback(result.success)" << endl;
+        } else {
+          f_service_ << indent() << indent_str() << "return 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) {
+        const string& xname = (*x_iter)->get_name();
+        f_service_ << indent() << "if result." << xname << " is not None:" << endl;
+        if (gen_twisted_) {
+          f_service_ << indent() << indent_str() << "return d.errback(result." << xname << ")"
+                     << endl;
+        } else {
+          f_service_ << indent() << indent_str() << "raise result." << xname << "" << endl;
+        }
+      }
+
+      // Careful, only return _result if not a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        if (gen_twisted_) {
+          f_service_ << indent() << "return d.callback(None)" << endl;
+        } else {
+          f_service_ << indent() << "return" << endl;
+        }
+      } else {
+        if (gen_twisted_) {
+          f_service_
+              << indent()
+              << "return d.errback(TApplicationException(TApplicationException.MISSING_RESULT, \""
+              << (*f_iter)->get_name() << " failed: unknown result\"))" << endl;
+        } else {
+          f_service_ << indent()
+                     << "raise TApplicationException(TApplicationException.MISSING_RESULT, \""
+                     << (*f_iter)->get_name() << " failed: unknown result\")" << endl;
+        }
+      }
+
+      // Close function
+      indent_down();
+    }
+  }
+
+  indent_down();
+}
+
+/**
+ * Generates a command line tool for making remote requests
+ *
+ * @param tservice The service to generate a remote for.
+ */
+void t_py_generator::generate_service_remote(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  // Get all function from parents
+  t_service* parent = tservice->get_extends();
+  while (parent != NULL) {
+    vector<t_function*> p_functions = parent->get_functions();
+    functions.insert(functions.end(), p_functions.begin(), p_functions.end());
+    parent = parent->get_extends();
+  }
+  vector<t_function*>::iterator f_iter;
+
+  string f_remote_name = package_dir_ + "/" + service_name_ + "-remote";
+  ofstream_with_content_based_conditional_update f_remote;
+  f_remote.open(f_remote_name.c_str());
+
+  f_remote <<
+    "#!/usr/bin/env python" << endl <<
+    py_autogen_comment() << endl <<
+    "import sys" << endl <<
+    "import pprint" << endl <<
+    "if sys.version_info[0] > 2:" << endl <<
+    indent_str() << "from urllib.parse import urlparse" << endl <<
+    "else:" << endl <<
+    indent_str() << "from urlparse import urlparse" << endl <<
+    "from thrift.transport import TTransport, TSocket, TSSLSocket, THttpClient" << endl <<
+    "from thrift.protocol.TBinaryProtocol import TBinaryProtocol" << endl <<
+    endl;
+
+  f_remote <<
+    "from " << module_ << " import " << service_name_ << endl <<
+    "from " << module_ << ".ttypes import *" << endl <<
+    endl;
+
+  f_remote <<
+    "if len(sys.argv) <= 1 or sys.argv[1] == '--help':" << endl <<
+    indent_str() << "print('')" << endl <<
+    indent_str() << "print('Usage: ' + sys.argv[0] + ' [-h host[:port]] [-u url] [-f[ramed]] [-s[sl]] [-novalidate] [-ca_certs certs] [-keyfile keyfile] [-certfile certfile] function [arg1 [arg2...]]')" << endl <<
+    indent_str() << "print('')" << endl <<
+    indent_str() << "print('Functions:')" << endl;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_remote << indent_str() << "print('  " << (*f_iter)->get_returntype()->get_name() << " "
+             << (*f_iter)->get_name() << "(";
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const std::vector<t_field*>& args = arg_struct->get_members();
+    std::vector<t_field*>::size_type num_args = args.size();
+    bool first = true;
+    for (std::vector<t_field*>::size_type i = 0; i < num_args; ++i) {
+      if (first) {
+        first = false;
+      } else {
+        f_remote << ", ";
+      }
+      f_remote << args[i]->get_type()->get_name() << " " << args[i]->get_name();
+    }
+    f_remote << ")')" << endl;
+  }
+  f_remote << indent_str() << "print('')" << endl << indent_str() << "sys.exit(0)" << endl << endl;
+
+  f_remote << "pp = pprint.PrettyPrinter(indent=2)" << endl
+           << "host = 'localhost'" << endl
+           << "port = 9090" << endl
+           << "uri = ''" << endl
+           << "framed = False" << endl
+           << "ssl = False" << endl
+           << "validate = True" << endl
+           << "ca_certs = None" << endl
+           << "keyfile = None" << endl
+           << "certfile = None" << endl
+           << "http = False" << endl
+           << "argi = 1" << endl
+           << endl
+           << "if sys.argv[argi] == '-h':" << endl
+           << indent_str() << "parts = sys.argv[argi + 1].split(':')" << endl
+           << indent_str() << "host = parts[0]" << endl
+           << indent_str() << "if len(parts) > 1:" << endl
+           << indent_str() << indent_str() << "port = int(parts[1])" << endl
+           << indent_str() << "argi += 2" << endl
+           << endl
+           << "if sys.argv[argi] == '-u':" << endl
+           << indent_str() << "url = urlparse(sys.argv[argi + 1])" << endl
+           << indent_str() << "parts = url[1].split(':')" << endl
+           << indent_str() << "host = parts[0]" << endl
+           << indent_str() << "if len(parts) > 1:" << endl
+           << indent_str() << indent_str() << "port = int(parts[1])" << endl
+           << indent_str() << "else:" << endl
+           << indent_str() << indent_str() << "port = 80" << endl
+           << indent_str() << "uri = url[2]" << endl
+           << indent_str() << "if url[4]:" << endl
+           << indent_str() << indent_str() << "uri += '?%s' % url[4]" << endl
+           << indent_str() << "http = True" << endl
+           << indent_str() << "argi += 2" << endl
+           << endl
+           << "if sys.argv[argi] == '-f' or sys.argv[argi] == '-framed':" << endl
+           << indent_str() << "framed = True" << endl
+           << indent_str() << "argi += 1" << endl
+           << endl
+           << "if sys.argv[argi] == '-s' or sys.argv[argi] == '-ssl':" << endl
+           << indent_str() << "ssl = True" << endl
+           << indent_str() << "argi += 1" << endl
+           << endl
+           << "if sys.argv[argi] == '-novalidate':" << endl
+           << indent_str() << "validate = False" << endl
+           << indent_str() << "argi += 1" << endl
+           << endl
+           << "if sys.argv[argi] == '-ca_certs':" << endl
+           << indent_str() << "ca_certs = sys.argv[argi+1]" << endl
+           << indent_str() << "argi += 2" << endl
+           << endl
+           << "if sys.argv[argi] == '-keyfile':" << endl
+           << indent_str() << "keyfile = sys.argv[argi+1]" << endl
+           << indent_str() << "argi += 2" << endl
+           << endl
+           << "if sys.argv[argi] == '-certfile':" << endl
+           << indent_str() << "certfile = sys.argv[argi+1]" << endl
+           << indent_str() << "argi += 2" << endl
+           << endl
+           << "cmd = sys.argv[argi]" << endl
+           << "args = sys.argv[argi + 1:]" << endl
+           << endl
+           << "if http:" << endl
+           << indent_str() << "transport = THttpClient.THttpClient(host, port, uri)" << endl
+           << "else:" << endl
+           << indent_str() << "if ssl:" << endl
+           << indent_str() << indent_str() << "socket = TSSLSocket.TSSLSocket(host, port, "
+              "validate=validate, ca_certs=ca_certs, keyfile=keyfile, certfile=certfile)"
+           << endl
+           << indent_str() << "else:" << endl
+           << indent_str() << indent_str() << "socket = TSocket.TSocket(host, port)" << endl
+           << indent_str() << "if framed:" << endl
+           << indent_str() << indent_str() << "transport = TTransport.TFramedTransport(socket)" << endl
+           << indent_str() << "else:" << endl
+           << indent_str() << indent_str() << "transport = TTransport.TBufferedTransport(socket)" << endl
+           << "protocol = TBinaryProtocol(transport)" << endl
+           << "client = " << service_name_ << ".Client(protocol)" << endl
+           << "transport.open()" << endl
+           << endl;
+
+  // Generate the dispatch methods
+  bool first = true;
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_remote << "el";
+    }
+
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    const std::vector<t_field*>& args = arg_struct->get_members();
+    std::vector<t_field*>::size_type num_args = args.size();
+
+    f_remote << "if cmd == '" << (*f_iter)->get_name() << "':" << endl;
+    indent_up();
+    f_remote << indent() << "if len(args) != " << num_args << ":" << endl
+             << indent() << indent_str() << "print('" << (*f_iter)->get_name() << " requires " << num_args
+             << " args')" << endl
+             << indent() << indent_str() << "sys.exit(1)" << endl
+             << indent() << "pp.pprint(client." << (*f_iter)->get_name() << "(";
+    indent_down();
+    bool first_arg = true;
+    for (std::vector<t_field*>::size_type i = 0; i < num_args; ++i) {
+      if (first_arg)
+        first_arg = false;
+      else
+        f_remote << " ";
+      if (args[i]->get_type()->is_string()) {
+        f_remote << "args[" << i << "],";
+      } else {
+        f_remote << "eval(args[" << i << "]),";
+      }
+    }
+    f_remote << "))" << endl;
+
+    f_remote << endl;
+  }
+
+  if (functions.size() > 0) {
+    f_remote << "else:" << endl;
+    f_remote << indent_str() << "print('Unrecognized method %s' % cmd)" << endl;
+    f_remote << indent_str() << "sys.exit(1)" << endl;
+    f_remote << endl;
+  }
+
+  f_remote << "transport.close()" << endl;
+
+  // Close service file
+  f_remote.close();
+
+#ifndef _MSC_VER
+
+  // Make file executable, love that bitwise OR action
+  chmod(f_remote_name.c_str(),
+        S_IRUSR | S_IWUSR | S_IXUSR
+#ifndef _WIN32
+        | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
+#endif
+        );
+
+#endif // _MSC_VER
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_py_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 = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_processor = extends + ".Processor, ";
+  }
+
+  f_service_ << endl << endl;
+
+  // Generate the header portion
+  if (gen_zope_interface_) {
+    f_service_ << "@implementer(Iface)" << endl
+               << "class Processor(" << extends_processor << "TProcessor):" << endl;
+  } else {
+    f_service_ << "class Processor(" << extends_processor << "Iface, TProcessor):" << endl;
+  }
+
+  indent_up();
+
+  indent(f_service_) << "def __init__(self, handler):" << endl;
+  indent_up();
+  if (extends.empty()) {
+    if (gen_zope_interface_) {
+      f_service_ << indent() << "self._handler = Iface(handler)" << endl;
+    } else {
+      f_service_ << indent() << "self._handler = handler" << endl;
+    }
+
+    f_service_ << indent() << "self._processMap = {}" << endl;
+  } else {
+    if (gen_zope_interface_) {
+      f_service_ << indent() << extends << ".Processor.__init__(self, Iface(handler))" << endl;
+    } else {
+      f_service_ << indent() << extends << ".Processor.__init__(self, handler)" << endl;
+    }
+  }
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << indent() << "self._processMap[\"" << (*f_iter)->get_name()
+               << "\"] = Processor.process_" << (*f_iter)->get_name() << endl;
+  }
+  indent_down();
+  f_service_ << endl;
+
+  // Generate the server implementation
+  f_service_ << indent() << "def process(self, iprot, oprot):" << endl;
+  indent_up();
+
+  f_service_ << indent() << "(name, type, seqid) = iprot.readMessageBegin()" << endl;
+
+  // TODO(mcslee): validate message
+
+  // HOT: dictionary function lookup
+  f_service_ << indent() << "if name not in self._processMap:" << endl;
+  indent_up();
+  f_service_ << indent() << "iprot.skip(TType.STRUCT)" << endl
+             << indent() << "iprot.readMessageEnd()" << endl
+             << indent()
+             << "x = TApplicationException(TApplicationException.UNKNOWN_METHOD, 'Unknown "
+                "function %s' % (name))"
+             << endl
+             << indent() << "oprot.writeMessageBegin(name, TMessageType.EXCEPTION, seqid)" << endl
+             << indent() << "x.write(oprot)" << endl
+             << indent() << "oprot.writeMessageEnd()" << endl
+             << indent() << "oprot.trans.flush()" << endl;
+
+  if (gen_twisted_) {
+    f_service_ << indent() << "return defer.succeed(None)" << endl;
+  } else {
+    f_service_ << indent() << "return" << endl;
+  }
+  indent_down();
+
+  f_service_ << indent() << "else:" << endl;
+
+  if (gen_twisted_ || gen_tornado_) {
+    f_service_ << indent() << indent_str()
+               << "return self._processMap[name](self, seqid, iprot, oprot)" << endl;
+  } else {
+    f_service_ << indent() << indent_str() << "self._processMap[name](self, seqid, iprot, oprot)"
+               << endl;
+
+    // Read end of args field, the T_STOP, and the struct close
+    f_service_ << indent() << "return True" << endl;
+  }
+
+  indent_down();
+
+  // Generate the process subfunctions
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_service_ << endl;
+    generate_process_function(tservice, *f_iter);
+  }
+
+  indent_down();
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_py_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+  // Open function
+  if (gen_tornado_) {
+    f_service_ << indent() << "@gen.coroutine" << endl << indent() << "def process_"
+               << tfunction->get_name() << "(self, seqid, iprot, oprot):" << endl;
+  } else {
+    f_service_ << indent() << "def process_" << tfunction->get_name()
+               << "(self, seqid, iprot, oprot):" << endl;
+  }
+
+  indent_up();
+
+  string argsname = tfunction->get_name() + "_args";
+  string resultname = tfunction->get_name() + "_result";
+
+  f_service_ << indent() << "args = " << argsname << "()" << endl << indent() << "args.read(iprot)"
+             << endl << indent() << "iprot.readMessageEnd()" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    f_service_ << indent() << "result = " << resultname << "()" << endl;
+  }
+
+  if (gen_twisted_) {
+    // 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_ << indent() << "d = defer.maybeDeferred(self._handler." << 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." << (*f_iter)->get_name();
+    }
+    f_service_ << ")" << endl;
+
+    if (tfunction->is_oneway()) {
+      f_service_ << indent() << "d.addErrback(self.handle_exception_" << tfunction->get_name()
+                 << ", seqid)" << endl;
+    } else {
+      f_service_ << indent() << "d.addCallback(self.write_results_success_" << tfunction->get_name()
+                 << ", result, seqid, oprot)" << endl
+                 << indent() << "d.addErrback(self.write_results_exception_"
+                 << tfunction->get_name() << ", result, seqid, oprot)" << endl;
+    }
+    f_service_ << indent() << "return d" << endl << endl;
+
+    indent_down();
+
+    if (tfunction->is_oneway()) {
+      indent(f_service_) << "def handle_exception_" << tfunction->get_name()
+                         << "(self, error, seqid):" << endl;
+    } else {
+      indent(f_service_) << "def write_results_success_" << tfunction->get_name()
+                         << "(self, success, result, seqid, oprot):" << endl;
+      indent_up();
+      if (!tfunction->get_returntype()->is_void()) {
+        f_service_ << indent() << "result.success = success" << endl;
+      }
+      f_service_ << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name()
+                 << "\", TMessageType.REPLY, seqid)" << endl
+                 << indent() << "result.write(oprot)" << endl
+                 << indent() << "oprot.writeMessageEnd()" << endl
+                 << indent() << "oprot.trans.flush()" << endl
+                 << endl;
+      indent_down();
+
+      indent(f_service_) << "def write_results_exception_" << tfunction->get_name()
+                         << "(self, error, result, seqid, oprot):" << endl;
+    }
+    indent_up();
+    if (!tfunction->is_oneway()) {
+      f_service_ << indent() << "msg_type = TMessageType.REPLY" << endl;
+    }
+    f_service_ << indent() << "try:" << endl;
+
+    // Kinda absurd
+    f_service_ << indent() << indent_str() << "error.raiseException()" << endl;
+    if (!tfunction->is_oneway()) {
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        const string& xname = (*x_iter)->get_name();
+        f_service_ << indent() << "except " << type_name((*x_iter)->get_type()) << " as " << xname
+                   << ":" << endl;
+        indent_up();
+        f_service_ << indent() << "result." << xname << " = " << xname << endl;
+        indent_down();
+      }
+    }
+    f_service_ << indent() << "except TTransport.TTransportException:" << endl
+               << indent() << indent_str() << "raise" << endl;
+    if (!tfunction->is_oneway()) {
+      f_service_ << indent() << "except TApplicationException as ex:" << endl
+                 << indent() << indent_str()
+                 << "logging.exception('TApplication exception in handler')" << endl
+                 << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl
+                 << indent() << indent_str() << "result = ex" << endl
+                 << indent() << "except Exception:" << endl
+                 << indent() << indent_str()
+                 << "logging.exception('Unexpected exception in handler')" << endl
+                 << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl
+                 << indent() << indent_str()
+                 << "result = TApplicationException(TApplicationException.INTERNAL_ERROR, "
+                    "'Internal error')"
+                 << endl
+                 << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name()
+                 << "\", msg_type, seqid)" << endl
+                 << indent() << "result.write(oprot)" << endl
+                 << indent() << "oprot.writeMessageEnd()" << endl
+                 << indent() << "oprot.trans.flush()" << endl;
+    } else {
+      f_service_ << indent() << "except Exception:" << endl
+                 << indent() << indent_str()
+                 << "logging.exception('Exception in oneway handler')" << endl;
+    }
+    indent_down();
+
+  } else if (gen_tornado_) {
+    // 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;
+
+    if (!tfunction->is_oneway()) {
+      indent(f_service_) << "msg_type = TMessageType.REPLY" << endl;
+    }
+    f_service_ << indent() << "try:" << endl;
+    indent_up();
+    f_service_ << indent();
+    if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+      f_service_ << "result.success = ";
+    }
+    f_service_ << "yield gen.maybe_future(self._handler." << 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." << (*f_iter)->get_name();
+    }
+    f_service_ << "))" << endl;
+
+    indent_down();
+    if (!tfunction->is_oneway()) {
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        const string& xname = (*x_iter)->get_name();
+        f_service_ << indent() << "except " << type_name((*x_iter)->get_type()) << " as " << xname
+                   << ":" << endl
+                   << indent() << indent_str() << "result." << xname << " = " << xname << endl;
+      }
+    }
+    f_service_ << indent() << "except TTransport.TTransportException:" << endl
+               << indent() << indent_str() << "raise" << endl;
+    if (!tfunction->is_oneway()) {
+      f_service_ << indent() << "except TApplicationException as ex:" << endl
+                 << indent() << indent_str()
+                 << "logging.exception('TApplication exception in handler')" << endl
+                 << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl
+                 << indent() << indent_str() << "result = ex" << endl
+                 << indent() << "except Exception:" << endl
+                 << indent() << indent_str()
+                 << "logging.exception('Unexpected exception in handler')" << endl
+                 << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl
+                 << indent() << indent_str()
+                 << "result = TApplicationException(TApplicationException.INTERNAL_ERROR, "
+                    "'Internal error')"
+                 << endl;
+    } else {
+      f_service_ << indent() << "except Exception:" << endl
+                 << indent() << indent_str()
+                 << "logging.exception('Exception in oneway handler')" << endl;
+    }
+
+    if (!tfunction->is_oneway()) {
+      f_service_ << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name()
+                 << "\", msg_type, seqid)" << endl
+                 << indent() << "result.write(oprot)" << endl
+                 << indent() << "oprot.writeMessageEnd()" << endl
+                 << indent() << "oprot.trans.flush()" << endl;
+    }
+
+    // Close function
+    indent_down();
+
+  } else { // py
+    // Try block for a function with exceptions
+    // It also catches arbitrary exceptions raised by handler method to propagate them to the client
+    f_service_ << indent() << "try:" << endl;
+    indent_up();
+
+    // 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_ << indent();
+    if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+      f_service_ << "result.success = ";
+    }
+    f_service_ << "self._handler." << 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." << (*f_iter)->get_name();
+    }
+    f_service_ << ")" << endl;
+    if (!tfunction->is_oneway()) {
+      f_service_ << indent() << "msg_type = TMessageType.REPLY" << endl;
+    }
+
+    indent_down();
+    f_service_ << indent()
+               << "except TTransport.TTransportException:" << endl
+               << indent() << indent_str() << "raise" << endl;
+
+    if (!tfunction->is_oneway()) {
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+        const string& xname = (*x_iter)->get_name();
+        f_service_ << indent() << "except " << type_name((*x_iter)->get_type()) << " as " << xname
+                   << ":" << endl;
+        indent_up();
+        f_service_ << indent() << "msg_type = TMessageType.REPLY" << endl;
+        f_service_ << indent() << "result." << xname << " = " << xname << endl;
+        indent_down();
+      }
+
+      f_service_ << indent() << "except TApplicationException as ex:" << endl
+                 << indent() << indent_str()
+                 << "logging.exception('TApplication exception in handler')" << endl
+                 << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl
+                 << indent() << indent_str() << "result = ex" << endl
+                 << indent() << "except Exception:" << endl
+                 << indent() << indent_str()
+                 << "logging.exception('Unexpected exception in handler')" << endl
+                 << indent() << indent_str() << "msg_type = TMessageType.EXCEPTION" << endl
+                 << indent() << indent_str()
+                 << "result = TApplicationException(TApplicationException.INTERNAL_ERROR, "
+                    "'Internal error')"
+                 << endl
+                 << indent() << "oprot.writeMessageBegin(\"" << tfunction->get_name()
+                 << "\", msg_type, seqid)" << endl
+                 << indent() << "result.write(oprot)" << endl
+                 << indent() << "oprot.writeMessageEnd()" << endl
+                 << indent() << "oprot.trans.flush()" << endl;
+    } else {
+      f_service_ << indent() << "except Exception:" << endl
+                 << indent() << indent_str() << "logging.exception('Exception in oneway handler')" << endl;
+    }
+
+    // Close function
+    indent_down();
+  }
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_py_generator::generate_deserialize_field(ostream& out,
+                                                t_field* tfield,
+                                                string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name();
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_deserialize_struct(out, (t_struct*)type, name);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name);
+  } else if (type->is_base_type() || type->is_enum()) {
+    indent(out) << name << " = 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;
+      case t_base_type::TYPE_STRING:
+        if (type->is_binary()) {
+          out << "readBinary()";
+        } else if(!gen_utf8strings_) {
+          out << "readString()";
+        } else {
+          out << "readString().decode('utf-8') if sys.version_info[0] == 2 else iprot.readString()";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "readBool()";
+        break;
+      case t_base_type::TYPE_I8:
+        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 Python name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "readI32()";
+    }
+    out << endl;
+
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a struct, calling read()
+ */
+void t_py_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  if (is_immutable(tstruct)) {
+    out << indent() << prefix << " = " << type_name(tstruct) << ".read(iprot)" << endl;
+  } else {
+    out << indent() << prefix << " = " << type_name(tstruct) << "()" << endl
+        << indent() << prefix << ".read(iprot)" << endl;
+  }
+}
+
+/**
+ * Serialize a container by writing out the header followed by
+ * data and then a footer.
+ */
+void t_py_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) {
+  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_i8, ktype);
+  t_field fvtype(g_type_i8, vtype);
+  t_field fetype(g_type_i8, etype);
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    out << indent() << prefix << " = {}" << endl << indent() << "(" << ktype << ", " << vtype
+        << ", " << size << ") = iprot.readMapBegin()" << endl;
+  } else if (ttype->is_set()) {
+    out << indent() << prefix << " = set()" << endl << indent() << "(" << etype << ", " << size
+        << ") = iprot.readSetBegin()" << endl;
+  } else if (ttype->is_list()) {
+    out << indent() << prefix << " = []" << endl << indent() << "(" << etype << ", " << size
+        << ") = iprot.readListBegin()" << endl;
+  }
+
+  // For loop iterates over elements
+  string i = tmp("_i");
+  indent(out) <<
+    "for " << i << " in range(" << size << "):" << endl;
+
+  indent_up();
+
+  if (ttype->is_map()) {
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
+  } else if (ttype->is_set()) {
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
+  } else if (ttype->is_list()) {
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
+  }
+
+  indent_down();
+
+  // Read container end
+  if (ttype->is_map()) {
+    indent(out) << "iprot.readMapEnd()" << endl;
+    if (is_immutable(ttype)) {
+      indent(out) << prefix << " = TFrozenDict(" << prefix << ")" << endl;
+    }
+  } else if (ttype->is_set()) {
+    indent(out) << "iprot.readSetEnd()" << endl;
+    if (is_immutable(ttype)) {
+      indent(out) << prefix << " = frozenset(" << prefix << ")" << endl;
+    }
+  } else if (ttype->is_list()) {
+    if (is_immutable(ttype)) {
+      indent(out) << prefix << " = tuple(" << prefix << ")" << endl;
+    }
+    indent(out) << "iprot.readListEnd()" << endl;
+  }
+}
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_py_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) {
+  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);
+  generate_deserialize_field(out, &fval);
+
+  indent(out) << prefix << "[" << key << "] = " << val << endl;
+}
+
+/**
+ * Write a set element
+ */
+void t_py_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tset->get_elem_type(), elem);
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".add(" << elem << ")" << endl;
+}
+
+/**
+ * Write a list element
+ */
+void t_py_generator::generate_deserialize_list_element(ostream& out,
+                                                       t_list* tlist,
+                                                       string prefix) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+
+  generate_deserialize_field(out, &felem);
+
+  indent(out) << prefix << ".append(" << elem << ")" << endl;
+}
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_py_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name());
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, prefix + tfield->get_name());
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    string name = prefix + tfield->get_name();
+
+    indent(out) << "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:
+        if (type->is_binary()) {
+          out << "writeBinary(" << name << ")";
+        } else if (!gen_utf8strings_) {
+          out << "writeString(" << name << ")";
+        } else {
+          out << "writeString(" << name << ".encode('utf-8') if sys.version_info[0] == 2 else " << name << ")";
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "writeBool(" << name << ")";
+        break;
+      case t_base_type::TYPE_I8:
+        out << "writeByte(" << name << ")";
+        break;
+      case t_base_type::TYPE_I16:
+        out << "writeI16(" << name << ")";
+        break;
+      case t_base_type::TYPE_I32:
+        out << "writeI32(" << name << ")";
+        break;
+      case t_base_type::TYPE_I64:
+        out << "writeI64(" << name << ")";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "writeDouble(" << name << ")";
+        break;
+      default:
+        throw "compiler error: no Python name for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      out << "writeI32(" << name << ")";
+    }
+    out << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
+           prefix.c_str(),
+           tfield->get_name().c_str(),
+           type->get_name().c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_py_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
+  (void)tstruct;
+  indent(out) << prefix << ".write(oprot)" << endl;
+}
+
+void t_py_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
+  if (ttype->is_map()) {
+    indent(out) << "oprot.writeMapBegin(" << type_to_enum(((t_map*)ttype)->get_key_type()) << ", "
+                << type_to_enum(((t_map*)ttype)->get_val_type()) << ", "
+                << "len(" << prefix << "))" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.writeSetBegin(" << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", "
+                << "len(" << prefix << "))" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.writeListBegin(" << type_to_enum(((t_list*)ttype)->get_elem_type())
+                << ", "
+                << "len(" << prefix << "))" << endl;
+  }
+
+  if (ttype->is_map()) {
+    string kiter = tmp("kiter");
+    string viter = tmp("viter");
+    indent(out) << "for " << kiter << ", " << viter << " in " << prefix << ".items():" << endl;
+    indent_up();
+    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
+    indent_down();
+  } else if (ttype->is_set()) {
+    string iter = tmp("iter");
+    indent(out) << "for " << iter << " in " << prefix << ":" << endl;
+    indent_up();
+    generate_serialize_set_element(out, (t_set*)ttype, iter);
+    indent_down();
+  } else if (ttype->is_list()) {
+    string iter = tmp("iter");
+    indent(out) << "for " << iter << " in " << prefix << ":" << endl;
+    indent_up();
+    generate_serialize_list_element(out, (t_list*)ttype, iter);
+    indent_down();
+  }
+
+  if (ttype->is_map()) {
+    indent(out) << "oprot.writeMapEnd()" << endl;
+  } else if (ttype->is_set()) {
+    indent(out) << "oprot.writeSetEnd()" << endl;
+  } else if (ttype->is_list()) {
+    indent(out) << "oprot.writeListEnd()" << endl;
+  }
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_py_generator::generate_serialize_map_element(ostream& out,
+                                                    t_map* tmap,
+                                                    string kiter,
+                                                    string viter) {
+  t_field kfield(tmap->get_key_type(), kiter);
+  generate_serialize_field(out, &kfield, "");
+
+  t_field vfield(tmap->get_val_type(), viter);
+  generate_serialize_field(out, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_py_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
+  t_field efield(tset->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_py_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) {
+  t_field efield(tlist->get_elem_type(), iter);
+  generate_serialize_field(out, &efield, "");
+}
+
+/**
+ * Generates the docstring for a given struct.
+ */
+void t_py_generator::generate_python_docstring(ostream& out, t_struct* tstruct) {
+  generate_python_docstring(out, tstruct, tstruct, "Attributes");
+}
+
+/**
+ * Generates the docstring for a given function.
+ */
+void t_py_generator::generate_python_docstring(ostream& out, t_function* tfunction) {
+  generate_python_docstring(out, tfunction, tfunction->get_arglist(), "Parameters");
+}
+
+/**
+ * Generates the docstring for a struct or function.
+ */
+void t_py_generator::generate_python_docstring(ostream& 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 << " - " << 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_py_generator::generate_python_docstring(ostream& 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_py_generator::declare_argument(t_field* tfield) {
+  std::ostringstream result;
+  result << tfield->get_name() << "=";
+  if (tfield->get_value() != NULL) {
+    result << render_field_default_value(tfield);
+  } else {
+    result << "None";
+  }
+  return result.str();
+}
+
+/**
+ * Renders a field default value, returns None otherwise.
+ *
+ * @param tfield The field
+ */
+string t_py_generator::render_field_default_value(t_field* tfield) {
+  t_type* type = get_true_type(tfield->get_type());
+  if (tfield->get_value() != NULL) {
+    return render_const_value(type, tfield->get_value());
+  } else {
+    return "None";
+  }
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_py_generator::function_signature(t_function* tfunction, bool interface) {
+  vector<string> pre;
+  vector<string> post;
+  string signature = tfunction->get_name() + "(";
+
+  if (!(gen_zope_interface_ && interface)) {
+    pre.push_back("self");
+  }
+
+  signature += argument_list(tfunction->get_arglist(), &pre, &post) + ")";
+  return signature;
+}
+
+/**
+ * Renders a field list
+ */
+string t_py_generator::argument_list(t_struct* tstruct, vector<string>* pre, vector<string>* post) {
+  string result = "";
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  vector<string>::const_iterator s_iter;
+  bool first = true;
+  if (pre) {
+    for (s_iter = pre->begin(); s_iter != pre->end(); ++s_iter) {
+      if (first) {
+        first = false;
+      } else {
+        result += ", ";
+      }
+      result += *s_iter;
+    }
+  }
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      result += ", ";
+    }
+    result += (*f_iter)->get_name();
+  }
+  if (post) {
+    for (s_iter = post->begin(); s_iter != post->end(); ++s_iter) {
+      if (first) {
+        first = false;
+      } else {
+        result += ", ";
+      }
+      result += *s_iter;
+    }
+  }
+  return result;
+}
+
+string t_py_generator::type_name(t_type* ttype) {
+  while (ttype->is_typedef()) {
+    ttype = ((t_typedef*)ttype)->get_type();
+  }
+
+  t_program* program = ttype->get_program();
+  if (ttype->is_service()) {
+    return get_real_py_module(program, gen_twisted_, package_prefix_) + "." + ttype->get_name();
+  }
+  if (program != NULL && program != program_) {
+    return get_real_py_module(program, gen_twisted_, package_prefix_) + ".ttypes." + ttype->get_name();
+  }
+  return ttype->get_name();
+}
+
+/**
+ * Converts the parse type to a Python tyoe
+ */
+string t_py_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 "TType.STRING";
+    case t_base_type::TYPE_BOOL:
+      return "TType.BOOL";
+    case t_base_type::TYPE_I8:
+      return "TType.BYTE";
+    case t_base_type::TYPE_I16:
+      return "TType.I16";
+    case t_base_type::TYPE_I32:
+      return "TType.I32";
+    case t_base_type::TYPE_I64:
+      return "TType.I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "TType.DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "TType.I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType.STRUCT";
+  } else if (type->is_map()) {
+    return "TType.MAP";
+  } else if (type->is_set()) {
+    return "TType.SET";
+  } else if (type->is_list()) {
+    return "TType.LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/** See the comment inside generate_py_struct_definition for what this is. */
+string t_py_generator::type_to_spec_args(t_type* ttype) {
+  while (ttype->is_typedef()) {
+    ttype = ((t_typedef*)ttype)->get_type();
+  }
+
+  if (ttype->is_binary()) {
+    return  "'BINARY'";
+  } else if (gen_utf8strings_ && ttype->is_base_type()
+             && reinterpret_cast<t_base_type*>(ttype)->is_string()) {
+    return "'UTF8'";
+  } else if (ttype->is_base_type() || ttype->is_enum()) {
+    return  "None";
+  } else if (ttype->is_struct() || ttype->is_xception()) {
+    return "[" + type_name(ttype) + ", None]";
+  } 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()) + ", "
+           + (is_immutable(ttype) ? "True" : "False") + ")";
+
+  } 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()) + ", "
+           + (is_immutable(ttype) ? "True" : "False") + ")";
+
+  } 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()) + ", "
+           + (is_immutable(ttype) ? "True" : "False") + ")";
+  }
+
+  throw "INVALID TYPE IN type_to_spec_args: " + ttype->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(
+    py,
+    "Python",
+    "    zope.interface:  Generate code for use with zope.interface.\n"
+    "    twisted:         Generate Twisted-friendly RPC services.\n"
+    "    tornado:         Generate code for use with Tornado.\n"
+    "    no_utf8strings:  Do not Encode/decode strings using utf8 in the generated code. Basically no effect for Python 3.\n"
+    "    coding=CODING:   Add file encoding declare in generated file.\n"
+    "    slots:           Generate code using slots for instance members.\n"
+    "    dynamic:         Generate dynamic code, less code generated but slower.\n"
+    "    dynbase=CLS      Derive generated classes from class CLS instead of TBase.\n"
+    "    dynfrozen=CLS    Derive generated immutable classes from class CLS instead of TFrozenBase.\n"
+    "    dynexc=CLS       Derive generated exceptions from CLS instead of TExceptionBase.\n"
+    "    dynimport='from foo.bar import CLS'\n"
+    "                     Add an import line to generated code to find the dynbase class.\n"
+    "    package_prefix='top.package.'\n"
+    "                     Package prefix for generated files.\n"
+    "    old_style:       Deprecated. Generate old-style classes.\n")
diff --git a/compiler/cpp/src/thrift/generate/t_rb_generator.cc b/compiler/cpp/src/thrift/generate/t_rb_generator.cc
new file mode 100644
index 0000000..13ea249
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_rb_generator.cc
@@ -0,0 +1,1288 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <algorithm>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+
+#include "thrift/platform.h"
+#include "thrift/version.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ofstream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * A subclass of std::ofstream that includes indenting functionality.
+ */
+class t_rb_ofstream : public std::ofstream {
+private:
+  int indent_;
+
+public:
+  t_rb_ofstream() : std::ofstream(), indent_(0) {}
+  explicit t_rb_ofstream(const char* filename,
+                         ios_base::openmode mode = ios_base::out,
+                         int indent = 0)
+    : std::ofstream(filename, mode), indent_(indent) {}
+
+  t_rb_ofstream& indent() {
+    for (int i = 0; i < indent_; ++i) {
+      *this << "  ";
+    }
+    return *this;
+  }
+
+  void indent_up() { indent_++; }
+  void indent_down() { indent_--; }
+};
+
+/**
+ * Ruby code generator.
+ *
+ */
+class t_rb_generator : public t_oop_generator {
+public:
+  t_rb_generator(t_program* program,
+                 const std::map<std::string, std::string>& parsed_options,
+                 const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    require_rubygems_ = false;
+    namespaced_ = false;
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("rubygems") == 0) {
+        require_rubygems_ = true;
+      } else if( iter->first.compare("namespaced") == 0) {
+        namespaced_ = true;
+      } else {
+        throw "unknown option ruby:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-rb";
+  }
+
+  /**
+   * 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_forward_declaration(t_struct* tstruct);
+  void generate_union(t_struct* tunion);
+  void generate_xception(t_struct* txception);
+  void generate_service(t_service* tservice);
+
+  t_rb_ofstream& render_const_value(t_rb_ofstream& out, t_type* type, t_const_value* value);
+
+  /**
+   * Struct generation code
+   */
+
+  void generate_rb_struct_declaration(t_rb_ofstream& out, t_struct* tstruct, bool is_exception);
+  void generate_rb_struct(t_rb_ofstream& out, t_struct* tstruct, bool is_exception);
+  void generate_rb_struct_required_validator(t_rb_ofstream& out, t_struct* tstruct);
+  void generate_rb_union(t_rb_ofstream& out, t_struct* tstruct, bool is_exception);
+  void generate_rb_union_validator(t_rb_ofstream& out, t_struct* tstruct);
+  void generate_rb_function_helpers(t_function* tfunction);
+  void generate_rb_simple_constructor(t_rb_ofstream& out, t_struct* tstruct);
+  void generate_rb_simple_exception_constructor(t_rb_ofstream& out, t_struct* tstruct);
+  void generate_field_constants(t_rb_ofstream& out, t_struct* tstruct);
+  void generate_field_constructors(t_rb_ofstream& out, t_struct* tstruct);
+  void generate_field_defns(t_rb_ofstream& out, t_struct* tstruct);
+  void generate_field_data(t_rb_ofstream& out,
+                           t_type* field_type,
+                           const std::string& field_name,
+                           t_const_value* field_value,
+                           bool optional);
+
+  /**
+   * 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_server(t_service* tservice);
+  void generate_process_function(t_service* tservice, t_function* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field(t_rb_ofstream& out,
+                                  t_field* tfield,
+                                  std::string prefix = "",
+                                  bool inclass = false);
+
+  void generate_deserialize_struct(t_rb_ofstream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_deserialize_container(t_rb_ofstream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_deserialize_set_element(t_rb_ofstream& out, t_set* tset, std::string prefix = "");
+
+  void generate_deserialize_map_element(t_rb_ofstream& out, t_map* tmap, std::string prefix = "");
+
+  void generate_deserialize_list_element(t_rb_ofstream& out,
+                                         t_list* tlist,
+                                         std::string prefix = "");
+
+  void generate_serialize_field(t_rb_ofstream& out, t_field* tfield, std::string prefix = "");
+
+  void generate_serialize_struct(t_rb_ofstream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(t_rb_ofstream& out, t_type* ttype, std::string prefix = "");
+
+  void generate_serialize_map_element(t_rb_ofstream& out,
+                                      t_map* tmap,
+                                      std::string kiter,
+                                      std::string viter);
+
+  void generate_serialize_set_element(t_rb_ofstream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(t_rb_ofstream& out, t_list* tlist, std::string iter);
+
+  void generate_rdoc(t_rb_ofstream& out, t_doc* tdoc);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string rb_autogen_comment();
+  std::string render_require_thrift();
+  std::string render_includes();
+  std::string declare_field(t_field* tfield);
+  std::string type_name(const t_type* ttype);
+  std::string full_type_name(const t_type* ttype);
+  std::string function_signature(t_function* tfunction, std::string prefix = "");
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string rb_namespace_to_path_prefix(std::string rb_namespace);
+
+  std::vector<std::string> ruby_modules(const t_program* p) {
+    std::string ns = p->get_namespace("rb");
+    std::vector<std::string> modules;
+    if (ns.empty()) {
+      return modules;
+    }
+
+    std::string::iterator pos = ns.begin();
+    while (true) {
+      std::string::iterator delim = std::find(pos, ns.end(), '.');
+      modules.push_back(capitalize(std::string(pos, delim)));
+      pos = delim;
+      if (pos == ns.end()) {
+        break;
+      }
+      ++pos;
+    }
+
+    return modules;
+  }
+
+  void begin_namespace(t_rb_ofstream&, std::vector<std::string>);
+  void end_namespace(t_rb_ofstream&, std::vector<std::string>);
+
+private:
+  /**
+   * File streams
+   */
+
+  t_rb_ofstream f_types_;
+  t_rb_ofstream f_consts_;
+  t_rb_ofstream f_service_;
+
+  std::string namespace_dir_;
+  std::string require_prefix_;
+
+  /** If true, add a "require 'rubygems'" line to the top of each gen-rb file. */
+  bool require_rubygems_;
+
+  /** If true, generate files in idiomatic namespaced directories. */
+  bool namespaced_;
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_rb_generator::init_generator() {
+  string subdir = get_out_dir();
+
+  // Make output directory
+  MKDIR(subdir.c_str());
+
+  if (namespaced_) {
+    require_prefix_ = rb_namespace_to_path_prefix(program_->get_namespace("rb"));
+
+    string dir = require_prefix_;
+    string::size_type loc;
+
+    while ((loc = dir.find("/")) != string::npos) {
+      subdir = subdir + dir.substr(0, loc) + "/";
+      MKDIR(subdir.c_str());
+      dir = dir.substr(loc + 1);
+    }
+  }
+
+  namespace_dir_ = subdir;
+
+  // Make output file
+  string f_types_name = namespace_dir_ + underscore(program_name_) + "_types.rb";
+  f_types_.open(f_types_name.c_str());
+
+  string f_consts_name = namespace_dir_ + underscore(program_name_) + "_constants.rb";
+  f_consts_.open(f_consts_name.c_str());
+
+  // Print header
+  f_types_ << rb_autogen_comment() << endl << render_require_thrift() << render_includes() << endl;
+  begin_namespace(f_types_, ruby_modules(program_));
+
+  f_consts_ << rb_autogen_comment() << endl << render_require_thrift() << "require '"
+            << require_prefix_ << underscore(program_name_) << "_types'" << endl << endl;
+  begin_namespace(f_consts_, ruby_modules(program_));
+}
+
+/**
+ * Renders the require of thrift itself, and possibly of the rubygems dependency.
+ */
+string t_rb_generator::render_require_thrift() {
+  if (require_rubygems_) {
+    return "require 'rubygems'\nrequire 'thrift'\n";
+  } else {
+    return "require 'thrift'\n";
+  }
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program
+ */
+string t_rb_generator::render_includes() {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = "";
+  for (size_t i = 0; i < includes.size(); ++i) {
+    if (namespaced_) {
+      t_program* included = includes[i];
+      std::string included_require_prefix
+          = rb_namespace_to_path_prefix(included->get_namespace("rb"));
+      std::string included_name = included->get_name();
+      result += "require '" + included_require_prefix + underscore(included_name) + "_types'\n";
+    } else {
+      result += "require '" + underscore(includes[i]->get_name()) + "_types'\n";
+    }
+  }
+  if (includes.size() > 0) {
+    result += "\n";
+  }
+  return result;
+}
+
+/**
+ * Autogen'd comment
+ */
+string t_rb_generator::rb_autogen_comment() {
+  return std::string("#\n") + "# Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
+         + "#\n" + "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "#\n";
+}
+
+/**
+ * Closes the type files
+ */
+void t_rb_generator::close_generator() {
+  // Close types file
+  end_namespace(f_types_, ruby_modules(program_));
+  end_namespace(f_consts_, ruby_modules(program_));
+  f_types_.close();
+  f_consts_.close();
+}
+
+/**
+ * Generates a typedef. This is not done in Ruby, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_rb_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+/**
+ * Generates code for an enumerated type. Done using a class to scope
+ * the values.
+ *
+ * @param tenum The enumeration
+ */
+void t_rb_generator::generate_enum(t_enum* tenum) {
+  f_types_.indent() << "module " << capitalize(tenum->get_name()) << endl;
+  f_types_.indent_up();
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+
+    // Ruby class constants have to be capitalized... omg i am so on the fence
+    // about languages strictly enforcing capitalization why can't we just all
+    // agree and play nice.
+    string name = capitalize((*c_iter)->get_name());
+
+    generate_rdoc(f_types_, *c_iter);
+    f_types_.indent() << name << " = " << value << endl;
+  }
+
+  // Create a hash mapping values back to their names (as strings) since ruby has no native enum
+  // type
+  f_types_.indent() << "VALUE_MAP = {";
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    // Populate the hash
+    int value = (*c_iter)->get_value();
+    if (c_iter != constants.begin())
+      f_types_ << ", ";
+    f_types_ << value << " => \"" << capitalize((*c_iter)->get_name()) << "\"";
+  }
+  f_types_ << "}" << endl;
+
+  // Create a set with valid values for this enum
+  f_types_.indent() << "VALID_VALUES = Set.new([";
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    // Populate the set
+    if (c_iter != constants.begin())
+      f_types_ << ", ";
+    f_types_ << capitalize((*c_iter)->get_name());
+  }
+  f_types_ << "]).freeze" << endl;
+
+  f_types_.indent_down();
+  f_types_.indent() << "end" << endl << endl;
+}
+
+/**
+ * Generate a constant value
+ */
+void t_rb_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  name[0] = toupper(name[0]);
+
+  f_consts_.indent() << name << " = ";
+  render_const_value(f_consts_, type, value) << endl << 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
+ */
+t_rb_ofstream& t_rb_generator::render_const_value(t_rb_ofstream& out,
+                                                  t_type* type,
+                                                  t_const_value* value) {
+  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_STRING:
+      out << "%q\"" << get_escaped_string(value) << '"';
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "true" : "false");
+      break;
+    case t_base_type::TYPE_I8:
+    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()) {
+    out.indent() << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    out << full_type_name(type) << ".new({" << endl;
+    out.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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::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();
+      }
+      out.indent();
+      render_const_value(out, g_type_string, v_iter->first) << " => ";
+      render_const_value(out, field_type, v_iter->second) << "," << endl;
+    }
+    out.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();
+    out << "{" << endl;
+    out.indent_up();
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out.indent();
+      render_const_value(out, ktype, v_iter->first) << " => ";
+      render_const_value(out, vtype, v_iter->second) << "," << endl;
+    }
+    out.indent_down();
+    out.indent() << "}";
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    if (type->is_set()) {
+      out << "Set.new([" << endl;
+    } else {
+      out << "[" << endl;
+    }
+    out.indent_up();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out.indent();
+      render_const_value(out, etype, *v_iter) << "," << endl;
+    }
+    out.indent_down();
+    if (type->is_set()) {
+      out.indent() << "])";
+    } else {
+      out.indent() << "]";
+    }
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+  return out;
+}
+
+/**
+ * Generates a ruby struct
+ */
+void t_rb_generator::generate_struct(t_struct* tstruct) {
+  if (tstruct->is_union()) {
+    generate_rb_union(f_types_, tstruct, false);
+  } else {
+    generate_rb_struct(f_types_, tstruct, false);
+  }
+}
+
+
+/**
+ * Generates the "forward declarations" for ruby structs.
+ * These are simply a declaration of each class with proper inheritance.
+ * The rest of the struct is still generated in generate_struct as has
+ * always been the case. These declarations allow thrift to generate valid
+ * ruby in cases where thrift structs rely on recursive definitions.
+ */
+void t_rb_generator::generate_forward_declaration(t_struct* tstruct) {
+  generate_rb_struct_declaration(f_types_, tstruct, tstruct->is_xception());
+}
+
+void t_rb_generator::generate_rb_struct_declaration(t_rb_ofstream& out, t_struct* tstruct, bool is_exception) {
+  out.indent() << "class " << type_name(tstruct);
+  if (tstruct->is_union()) {
+    out << " < ::Thrift::Union";
+  }
+  if (is_exception) {
+    out << " < ::Thrift::Exception";
+  }
+  out << "; end" << endl << endl;
+}
+
+/**
+ * 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_rb_generator::generate_xception(t_struct* txception) {
+  generate_rb_struct(f_types_, txception, true);
+}
+
+/**
+ * Generates a ruby struct
+ */
+void t_rb_generator::generate_rb_struct(t_rb_ofstream& out,
+                                        t_struct* tstruct,
+                                        bool is_exception = false) {
+  generate_rdoc(out, tstruct);
+  out.indent() << "class " << type_name(tstruct);
+  if (is_exception) {
+    out << " < ::Thrift::Exception";
+  }
+  out << endl;
+
+  out.indent_up();
+  out.indent() << "include ::Thrift::Struct, ::Thrift::Struct_Union" << endl;
+
+  if (is_exception) {
+    generate_rb_simple_exception_constructor(out, tstruct);
+  }
+
+  generate_field_constants(out, tstruct);
+  generate_field_defns(out, tstruct);
+  generate_rb_struct_required_validator(out, tstruct);
+
+  out.indent() << "::Thrift::Struct.generate_accessors self" << endl;
+
+  out.indent_down();
+  out.indent() << "end" << endl << endl;
+}
+
+/**
+ * Generates a ruby union
+ */
+void t_rb_generator::generate_rb_union(t_rb_ofstream& out,
+                                       t_struct* tstruct,
+                                       bool is_exception = false) {
+  (void)is_exception;
+  generate_rdoc(out, tstruct);
+  out.indent() << "class " << type_name(tstruct) << " < ::Thrift::Union" << endl;
+
+  out.indent_up();
+  out.indent() << "include ::Thrift::Struct_Union" << endl;
+
+  generate_field_constructors(out, tstruct);
+
+  generate_field_constants(out, tstruct);
+  generate_field_defns(out, tstruct);
+  generate_rb_union_validator(out, tstruct);
+
+  out.indent() << "::Thrift::Union.generate_accessors self" << endl;
+
+  out.indent_down();
+  out.indent() << "end" << endl << endl;
+}
+
+void t_rb_generator::generate_field_constructors(t_rb_ofstream& out, t_struct* tstruct) {
+
+  out.indent() << "class << self" << endl;
+  out.indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (f_iter != fields.begin()) {
+      out << endl;
+    }
+    std::string field_name = (*f_iter)->get_name();
+
+    out.indent() << "def " << field_name << "(val)" << endl;
+    out.indent() << "  " << tstruct->get_name() << ".new(:" << field_name << ", val)" << endl;
+    out.indent() << "end" << endl;
+  }
+
+  out.indent_down();
+  out.indent() << "end" << endl;
+
+  out << endl;
+}
+
+void t_rb_generator::generate_rb_simple_exception_constructor(t_rb_ofstream& out,
+                                                              t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+
+  if (members.size() == 1) {
+    vector<t_field*>::const_iterator m_iter = members.begin();
+
+    if ((*m_iter)->get_type()->is_string()) {
+      string name = (*m_iter)->get_name();
+
+      out.indent() << "def initialize(message=nil)" << endl;
+      out.indent_up();
+      out.indent() << "super()" << endl;
+      out.indent() << "self." << name << " = message" << endl;
+      out.indent_down();
+      out.indent() << "end" << endl << endl;
+
+      if (name != "message") {
+        out.indent() << "def message; " << name << " end" << endl << endl;
+      }
+    }
+  }
+}
+
+void t_rb_generator::generate_field_constants(t_rb_ofstream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    std::string field_name = (*f_iter)->get_name();
+    std::string cap_field_name = upcase_string(field_name);
+
+    out.indent() << cap_field_name << " = " << (*f_iter)->get_key() << endl;
+  }
+  out << endl;
+}
+
+void t_rb_generator::generate_field_defns(t_rb_ofstream& out, t_struct* tstruct) {
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out.indent() << "FIELDS = {" << endl;
+  out.indent_up();
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (f_iter != fields.begin()) {
+      out << "," << endl;
+    }
+
+    // generate the field docstrings within the FIELDS constant. no real better place...
+    generate_rdoc(out, *f_iter);
+
+    out.indent() << upcase_string((*f_iter)->get_name()) << " => ";
+
+    generate_field_data(out,
+                        (*f_iter)->get_type(),
+                        (*f_iter)->get_name(),
+                        (*f_iter)->get_value(),
+                        (*f_iter)->get_req() == t_field::T_OPTIONAL);
+  }
+  out.indent_down();
+  out << endl;
+  out.indent() << "}" << endl << endl;
+
+  out.indent() << "def struct_fields; FIELDS; end" << endl << endl;
+}
+
+void t_rb_generator::generate_field_data(t_rb_ofstream& out,
+                                         t_type* field_type,
+                                         const std::string& field_name = "",
+                                         t_const_value* field_value = NULL,
+                                         bool optional = false) {
+  field_type = get_true_type(field_type);
+
+  // Begin this field's defn
+  out << "{:type => " << type_to_enum(field_type);
+
+  if (!field_name.empty()) {
+    out << ", :name => '" << field_name << "'";
+  }
+
+  if (field_value != NULL) {
+    out << ", :default => ";
+    render_const_value(out, field_type, field_value);
+  }
+
+  if (!field_type->is_base_type()) {
+    if (field_type->is_struct() || field_type->is_xception()) {
+      out << ", :class => " << full_type_name((t_struct*)field_type);
+    } else if (field_type->is_list()) {
+      out << ", :element => ";
+      generate_field_data(out, ((t_list*)field_type)->get_elem_type());
+    } else if (field_type->is_map()) {
+      out << ", :key => ";
+      generate_field_data(out, ((t_map*)field_type)->get_key_type());
+      out << ", :value => ";
+      generate_field_data(out, ((t_map*)field_type)->get_val_type());
+    } else if (field_type->is_set()) {
+      out << ", :element => ";
+      generate_field_data(out, ((t_set*)field_type)->get_elem_type());
+    }
+  } else {
+    if (((t_base_type*)field_type)->is_binary()) {
+      out << ", :binary => true";
+    }
+  }
+
+  if (optional) {
+    out << ", :optional => true";
+  }
+
+  if (field_type->is_enum()) {
+    out << ", :enum_class => " << full_type_name(field_type);
+  }
+
+  // End of this field's defn
+  out << "}";
+}
+
+void t_rb_generator::begin_namespace(t_rb_ofstream& out, vector<std::string> modules) {
+  for (vector<std::string>::iterator m_iter = modules.begin(); m_iter != modules.end(); ++m_iter) {
+    out.indent() << "module " << *m_iter << endl;
+    out.indent_up();
+  }
+}
+
+void t_rb_generator::end_namespace(t_rb_ofstream& out, vector<std::string> modules) {
+  for (vector<std::string>::reverse_iterator m_iter = modules.rbegin(); m_iter != modules.rend();
+       ++m_iter) {
+    out.indent_down();
+    out.indent() << "end" << endl;
+  }
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_rb_generator::generate_service(t_service* tservice) {
+  string f_service_name = namespace_dir_ + underscore(service_name_) + ".rb";
+  f_service_.open(f_service_name.c_str());
+
+  f_service_ << rb_autogen_comment() << endl << render_require_thrift();
+
+  if (tservice->get_extends() != NULL) {
+    if (namespaced_) {
+      f_service_ << "require '" << rb_namespace_to_path_prefix(
+                                       tservice->get_extends()->get_program()->get_namespace("rb"))
+                 << underscore(tservice->get_extends()->get_name()) << "'" << endl;
+    } else {
+      f_service_ << "require '" << require_prefix_
+                 << underscore(tservice->get_extends()->get_name()) << "'" << endl;
+    }
+  }
+
+  f_service_ << "require '" << require_prefix_ << underscore(program_name_) << "_types'" << endl
+             << endl;
+
+  begin_namespace(f_service_, ruby_modules(tservice->get_program()));
+
+  f_service_.indent() << "module " << capitalize(tservice->get_name()) << endl;
+  f_service_.indent_up();
+
+  // Generate the three main parts of the service (well, two for now in PHP)
+  generate_service_client(tservice);
+  generate_service_server(tservice);
+  generate_service_helpers(tservice);
+
+  f_service_.indent_down();
+  f_service_.indent() << "end" << endl << endl;
+
+  end_namespace(f_service_, ruby_modules(tservice->get_program()));
+
+  // Close service file
+  f_service_.close();
+}
+
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_rb_generator::generate_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  f_service_.indent() << "# 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_rb_struct(f_service_, ts);
+    generate_rb_function_helpers(*f_iter);
+  }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_rb_generator::generate_rb_function_helpers(t_function* tfunction) {
+  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_rb_struct(f_service_, &result);
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_rb_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = full_type_name(tservice->get_extends());
+    extends_client = " < " + extends + "::Client ";
+  }
+
+  f_service_.indent() << "class Client" << extends_client << endl;
+  f_service_.indent_up();
+
+  f_service_.indent() << "include ::Thrift::Client" << 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 = (*f_iter)->get_name();
+
+    // Open function
+    f_service_.indent() << "def " << function_signature(*f_iter) << endl;
+    f_service_.indent_up();
+    f_service_.indent() << "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;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_service_.indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "return ";
+      }
+      f_service_ << "recv_" << funname << "()" << endl;
+    }
+    f_service_.indent_down();
+    f_service_.indent() << "end" << endl;
+    f_service_ << endl;
+
+    f_service_.indent() << "def send_" << function_signature(*f_iter) << endl;
+    f_service_.indent_up();
+
+    std::string argsname = capitalize((*f_iter)->get_name() + "_args");
+    std::string messageSendProc = (*f_iter)->is_oneway() ? "send_oneway_message" : "send_message";
+
+    f_service_.indent() << messageSendProc << "('" << funname << "', " << argsname;
+
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << ", :" << (*fld_iter)->get_name() << " => " << (*fld_iter)->get_name();
+    }
+
+    f_service_ << ")" << endl;
+
+    f_service_.indent_down();
+    f_service_.indent() << "end" << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      std::string resultname = capitalize((*f_iter)->get_name() + "_result");
+      t_struct noargs(program_);
+
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+      // Open function
+      f_service_ << endl;
+      f_service_.indent() << "def " << function_signature(&recv_function) << endl;
+      f_service_.indent_up();
+
+      // TODO(mcslee): Validate message reply here, seq ids etc.
+
+      f_service_.indent() << "result = receive_message(" << resultname << ")" << endl;
+
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_.indent() << "return result.success unless result.success.nil?" << 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() << "raise result." << (*x_iter)->get_name() << " unless result."
+                            << (*x_iter)->get_name() << ".nil?" << endl;
+      }
+
+      // Careful, only return _result if not a void function
+      if ((*f_iter)->get_returntype()->is_void()) {
+        f_service_.indent() << "return" << endl;
+      } else {
+        f_service_.indent() << "raise "
+                               "::Thrift::ApplicationException.new(::Thrift::ApplicationException::"
+                               "MISSING_RESULT, '" << (*f_iter)->get_name()
+                            << " failed: unknown result')" << endl;
+      }
+
+      // Close function
+      f_service_.indent_down();
+      f_service_.indent() << "end" << endl << endl;
+    }
+  }
+
+  f_service_.indent_down();
+  f_service_.indent() << "end" << endl << endl;
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_rb_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 = "";
+  if (tservice->get_extends() != NULL) {
+    extends = full_type_name(tservice->get_extends());
+    extends_processor = " < " + extends + "::Processor ";
+  }
+
+  // Generate the header portion
+  f_service_.indent() << "class Processor" << extends_processor << endl;
+  f_service_.indent_up();
+
+  f_service_.indent() << "include ::Thrift::Processor" << 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_.indent_down();
+  f_service_.indent() << "end" << endl << endl;
+}
+
+/**
+ * Generates a process function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_rb_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
+  (void)tservice;
+  // Open function
+  f_service_.indent() << "def process_" << tfunction->get_name() << "(seqid, iprot, oprot)" << endl;
+  f_service_.indent_up();
+
+  string argsname = capitalize(tfunction->get_name()) + "_args";
+  string resultname = capitalize(tfunction->get_name()) + "_result";
+
+  f_service_.indent() << "args = read_args(iprot, " << argsname << ")" << endl;
+
+  t_struct* xs = tfunction->get_xceptions();
+  const std::vector<t_field*>& xceptions = xs->get_members();
+  vector<t_field*>::const_iterator x_iter;
+
+  // Declare result for non oneway function
+  if (!tfunction->is_oneway()) {
+    f_service_.indent() << "result = " << resultname << ".new()" << endl;
+  }
+
+  // Try block for a function with exceptions
+  if (xceptions.size() > 0) {
+    f_service_.indent() << "begin" << endl;
+    f_service_.indent_up();
+  }
+
+  // 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_.indent();
+  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
+    f_service_ << "result.success = ";
+  }
+  f_service_ << "@handler." << 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." << (*f_iter)->get_name();
+  }
+  f_service_ << ")" << endl;
+
+  if (!tfunction->is_oneway() && xceptions.size() > 0) {
+    f_service_.indent_down();
+    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+      f_service_.indent() << "rescue " << full_type_name((*x_iter)->get_type()) << " => "
+                          << (*x_iter)->get_name() << endl;
+      if (!tfunction->is_oneway()) {
+        f_service_.indent_up();
+        f_service_.indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name()
+                            << endl;
+        f_service_.indent_down();
+      }
+    }
+    f_service_.indent() << "end" << endl;
+  }
+
+  // Shortcut out here for oneway functions
+  if (tfunction->is_oneway()) {
+    f_service_.indent() << "return" << endl;
+    f_service_.indent_down();
+    f_service_.indent() << "end" << endl << endl;
+    return;
+  }
+
+  f_service_.indent() << "write_result(result, oprot, '" << tfunction->get_name() << "', seqid)"
+                      << endl;
+
+  // Close function
+  f_service_.indent_down();
+  f_service_.indent() << "end" << endl << endl;
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_rb_generator::function_signature(t_function* tfunction, string prefix) {
+  // TODO(mcslee): Nitpicky, no ',' if argument_list is empty
+  return prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ")";
+}
+
+/**
+ * Renders a field list
+ */
+string t_rb_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();
+  }
+  return result;
+}
+
+string t_rb_generator::type_name(const t_type* ttype) {
+  string prefix = "";
+
+  string name = ttype->get_name();
+  if (ttype->is_struct() || ttype->is_xception() || ttype->is_enum()) {
+    name = capitalize(ttype->get_name());
+  }
+
+  return prefix + name;
+}
+
+string t_rb_generator::full_type_name(const t_type* ttype) {
+  string prefix = "::";
+  vector<std::string> modules = ruby_modules(ttype->get_program());
+  for (vector<std::string>::iterator m_iter = modules.begin(); m_iter != modules.end(); ++m_iter) {
+    prefix += *m_iter + "::";
+  }
+  return prefix + type_name(ttype);
+}
+
+/**
+ * Converts the parse type to a Ruby tyoe
+ */
+string t_rb_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::Types::STRING";
+    case t_base_type::TYPE_BOOL:
+      return "::Thrift::Types::BOOL";
+    case t_base_type::TYPE_I8:
+      return "::Thrift::Types::BYTE";
+    case t_base_type::TYPE_I16:
+      return "::Thrift::Types::I16";
+    case t_base_type::TYPE_I32:
+      return "::Thrift::Types::I32";
+    case t_base_type::TYPE_I64:
+      return "::Thrift::Types::I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "::Thrift::Types::DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "::Thrift::Types::I32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "::Thrift::Types::STRUCT";
+  } else if (type->is_map()) {
+    return "::Thrift::Types::MAP";
+  } else if (type->is_set()) {
+    return "::Thrift::Types::SET";
+  } else if (type->is_list()) {
+    return "::Thrift::Types::LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+string t_rb_generator::rb_namespace_to_path_prefix(string rb_namespace) {
+  string namespaces_left = rb_namespace;
+  string::size_type loc;
+
+  string path_prefix = "";
+
+  while ((loc = namespaces_left.find(".")) != string::npos) {
+    path_prefix = path_prefix + underscore(namespaces_left.substr(0, loc)) + "/";
+    namespaces_left = namespaces_left.substr(loc + 1);
+  }
+  if (namespaces_left.size() > 0) {
+    path_prefix = path_prefix + underscore(namespaces_left) + "/";
+  }
+  return path_prefix;
+}
+
+void t_rb_generator::generate_rdoc(t_rb_ofstream& out, t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    out.indent();
+    generate_docstring_comment(out, "", "# ", tdoc->get_doc(), "");
+  }
+}
+
+void t_rb_generator::generate_rb_struct_required_validator(t_rb_ofstream& out, t_struct* tstruct) {
+  out.indent() << "def validate" << endl;
+  out.indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = (*f_iter);
+    if (field->get_req() == t_field::T_REQUIRED) {
+      out.indent() << "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, "
+                      "'Required field " << field->get_name() << " is unset!')";
+      if (field->get_type()->is_bool()) {
+        out << " if @" << field->get_name() << ".nil?";
+      } else {
+        out << " unless @" << field->get_name();
+      }
+      out << endl;
+    }
+  }
+
+  // if field is an enum, check that its value is valid
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field* field = (*f_iter);
+
+    if (field->get_type()->is_enum()) {
+      out.indent() << "unless @" << field->get_name() << ".nil? || "
+                   << full_type_name(field->get_type()) << "::VALID_VALUES.include?(@"
+                   << field->get_name() << ")" << endl;
+      out.indent_up();
+      out.indent() << "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, "
+                      "'Invalid value of field " << field->get_name() << "!')" << endl;
+      out.indent_down();
+      out.indent() << "end" << endl;
+    }
+  }
+
+  out.indent_down();
+  out.indent() << "end" << endl << endl;
+}
+
+void t_rb_generator::generate_rb_union_validator(t_rb_ofstream& out, t_struct* tstruct) {
+  out.indent() << "def validate" << endl;
+  out.indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out.indent()
+      << "raise(StandardError, 'Union fields are not set.') if get_set_field.nil? || get_value.nil?"
+      << endl;
+
+  // if field is an enum, check that its value is valid
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    const t_field* field = (*f_iter);
+
+    if (field->get_type()->is_enum()) {
+      out.indent() << "if get_set_field == :" << field->get_name() << endl;
+      out.indent() << "  raise "
+                      "::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, "
+                      "'Invalid value of field " << field->get_name() << "!') unless "
+                   << full_type_name(field->get_type()) << "::VALID_VALUES.include?(get_value)"
+                   << endl;
+      out.indent() << "end" << endl;
+    }
+  }
+
+  out.indent_down();
+  out.indent() << "end" << endl << endl;
+}
+
+THRIFT_REGISTER_GENERATOR(
+    rb,
+    "Ruby",
+    "    rubygems:        Add a \"require 'rubygems'\" line to the top of each generated file.\n"
+    "    namespaced:      Generate files in idiomatic namespaced directories.\n")
diff --git a/compiler/cpp/src/thrift/generate/t_rs_generator.cc b/compiler/cpp/src/thrift/generate/t_rs_generator.cc
new file mode 100644
index 0000000..9843d7a
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_rs_generator.cc
@@ -0,0 +1,3339 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_generator.h"
+
+using std::map;
+using std::ofstream;
+using std::ostringstream;
+using std::string;
+using std::vector;
+using std::set;
+
+static const string endl("\n"); // avoid ostream << std::endl flushes
+static const string SERVICE_RESULT_VARIABLE("result_value");
+static const string RESULT_STRUCT_SUFFIX("Result");
+static const string RUST_RESERVED_WORDS[] = {
+  "abstract", "alignof", "as", "become",
+  "box", "break", "const", "continue",
+  "crate", "do", "else", "enum",
+  "extern", "false", "final", "fn",
+  "for", "if", "impl", "in",
+  "let", "loop", "macro", "match",
+  "mod", "move", "mut", "offsetof",
+  "override", "priv", "proc", "pub",
+  "pure", "ref", "return", "Self",
+  "self", "sizeof", "static", "struct",
+  "super", "trait", "true", "type",
+  "typeof", "unsafe", "unsized", "use",
+  "virtual", "where", "while", "yield"
+};
+const set<string> RUST_RESERVED_WORDS_SET(
+  RUST_RESERVED_WORDS,
+  RUST_RESERVED_WORDS + sizeof(RUST_RESERVED_WORDS)/sizeof(RUST_RESERVED_WORDS[0])
+);
+
+static const string SYNC_CLIENT_GENERIC_BOUND_VARS("<IP, OP>");
+static const string SYNC_CLIENT_GENERIC_BOUNDS("where IP: TInputProtocol, OP: TOutputProtocol");
+
+// FIXME: extract common TMessageIdentifier function
+// FIXME: have to_rust_type deal with Option
+
+class t_rs_generator : public t_generator {
+public:
+  t_rs_generator(
+    t_program* program,
+    const std::map<std::string, std::string>&,
+    const std::string&
+  ) : t_generator(program) {
+    gen_dir_ = get_out_dir();
+  }
+
+  /**
+   * 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);
+
+private:
+  // struct type
+  // T_REGULAR: user-defined struct in the IDL
+  // T_ARGS: struct used to hold all service-call parameters
+  // T_RESULT: struct used to hold all service-call returns and exceptions
+  // T_EXCEPTION: user-defined exception in the IDL
+  enum e_struct_type { T_REGULAR, T_ARGS, T_RESULT, T_EXCEPTION };
+
+  // Directory to which generated code is written.
+  string gen_dir_;
+
+  // File to which generated code is written.
+  ofstream_with_content_based_conditional_update f_gen_;
+
+  // Write the common compiler attributes and module includes to the top of the auto-generated file.
+  void render_attributes_and_includes();
+
+  // Create the closure of Rust modules referenced by this service.
+  void compute_service_referenced_modules(t_service *tservice, set<string> &referenced_modules);
+
+  // Write the rust representation of an enum.
+  void render_enum_definition(t_enum* tenum, const string& enum_name);
+
+  // Write the impl blocks associated with the traits necessary to convert an enum to/from an i32.
+  void render_enum_conversion(t_enum* tenum, const string& enum_name);
+
+  // Write the impl block associated with the rust representation of an enum. This includes methods
+  // to write the enum to a protocol, read it from a protocol, etc.
+  void render_enum_impl(const string& enum_name);
+
+  // Write a simple rust const value (ie. `pub const FOO: foo...`).
+  void render_const_value(const string& name, t_type* ttype, t_const_value* tvalue);
+
+  // Write a constant list, set, map or struct. These constants require allocation and cannot be defined
+  // using a 'pub const'. As a result, I create a holder struct with a single `const_value` method that
+  // returns the initialized instance.
+  void render_const_value_holder(const string& name, t_type* ttype, t_const_value* tvalue);
+
+  // Write the actual const value - the right side of a const definition.
+  void render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned = true);
+
+  // Write a const struct (returned from `const_value` method).
+  void render_const_struct(t_type* ttype, t_const_value* tvalue);
+
+  // Write a const list (returned from `const_value` method).
+  void render_const_list(t_type* ttype, t_const_value* tvalue);
+
+  // Write a const set (returned from `const_value` method).
+  void render_const_set(t_type* ttype, t_const_value* tvalue);
+
+  // Write a const map (returned from `const_value` method).
+  void render_const_map(t_type* ttype, t_const_value* tvalue);
+
+  // Write the code to insert constant values into a rust vec or set. The
+  // `insert_function` is the rust function that we'll use to insert the elements.
+  void render_container_const_value(
+    const string& insert_function,
+    t_type* ttype,
+    t_const_value* tvalue
+  );
+
+  // Write the rust representation of a thrift struct to the generated file. Set `struct_type` to `T_ARGS`
+  // if rendering the struct used to pack arguments for a service call. When `struct_type` is `T_ARGS` the
+  // struct and its members have module visibility, and all fields are required. When `struct_type` is
+  // anything else the struct and its members have public visibility and fields have the visibility set
+  // in their definition.
+  void render_struct(const string& struct_name, t_struct* tstruct, t_rs_generator::e_struct_type struct_type);
+
+  // Write the comment block preceding a type definition (and implementation).
+  void render_type_comment(const string& struct_name);
+
+  // Write the rust representation of a thrift struct. Supports argument structs, result structs,
+  // user-defined structs and exception structs. The exact struct type to be generated is controlled
+  // by the `struct_type` parameter, which (among other things) modifies the visibility of the
+  // written struct and members, controls which trait implementations are generated.
+  void render_struct_definition(
+    const string& struct_name,
+    t_struct* tstruct,
+    t_rs_generator::e_struct_type struct_type
+  );
+
+  // Writes the impl block associated with the rust representation of a struct. At minimum this
+  // contains the methods to read from a protocol and write to a protocol. Additional methods may
+  // be generated depending on `struct_type`.
+  void render_struct_impl(
+    const string& struct_name,
+    t_struct* tstruct,
+    t_rs_generator::e_struct_type struct_type
+  );
+
+  // Generate a `fn new(...)` for a struct with name `struct_name` and type `t_struct`. The auto-generated
+  // code may include generic type parameters to make the constructor more ergonomic. `struct_type` controls
+  // the visibility of the generated constructor.
+  void render_struct_constructor(
+    const string& struct_name,
+    t_struct* tstruct,
+    t_rs_generator::e_struct_type struct_type
+  );
+
+  // Write the `ok_or` method added to all Thrift service call result structs. You can use this method
+  // to convert a struct into a `Result` and use it in a `try!` or combinator chain.
+  void render_result_struct_to_result_method(t_struct* tstruct);
+
+  // Write the implementations for the `Error` and `Debug` traits. These traits are necessary for a
+  // user-defined exception to be properly handled as Rust errors.
+  void render_exception_struct_error_trait_impls(const string& struct_name, t_struct* tstruct);
+
+  // Write the implementations for the `Default`. This trait allows you to specify only the fields you want
+  // and use `..Default::default()` to fill in the rest.
+  void render_struct_default_trait_impl(const string& struct_name, t_struct* tstruct);
+
+  // Write the function that serializes a struct to its wire representation. If `struct_type` is `T_ARGS`
+  // then all fields are considered "required", if not, the default optionality is used.
+  void render_struct_sync_write(t_struct *tstruct, t_rs_generator::e_struct_type struct_type);
+
+  // Helper function that serializes a single struct field to its wire representation. Unpacks the
+  // variable (since it may be optional) and serializes according to the optionality rules required by `req`.
+  // Variables in auto-generated code are passed by reference. Since this function may be called in
+  // contexts where the variable is *already* a reference you can set `field_var_is_ref` to `true` to avoid
+  // generating an extra, unnecessary `&` that the compiler will have to automatically dereference.
+  void render_struct_field_sync_write(
+    const string &field_var,
+    bool field_var_is_ref,
+    t_field *tfield,
+    t_field::e_req req);
+
+  // Write the rust function that serializes a single type (i.e. a i32 etc.) to its wire representation.
+  // Variables in auto-generated code are passed by reference. Since this function may be called in
+  // contexts where the variable is *already* a reference you can set `type_var_is_ref` to `true` to avoid
+  // generating an extra, unnecessary `&` that the compiler will have to automatically dereference.
+  void render_type_sync_write(const string &type_var, bool type_var_is_ref, t_type *ttype);
+
+  // Write a list to the output protocol. `list_variable` is the variable containing the list
+  // that will be written to the output protocol.
+  // Variables in auto-generated code are passed by reference. Since this function may be called in
+  // contexts where the variable is *already* a reference you can set `list_var_is_ref` to `true` to avoid
+  // generating an extra, unnecessary `&` that the compiler will have to automatically dereference.
+  void render_list_sync_write(const string &list_var, bool list_var_is_ref, t_list *tlist);
+
+  // Write a set to the output protocol. `set_variable` is the variable containing the set that will
+  // be written to the output protocol.
+  // Variables in auto-generated code are passed by reference. Since this function may be called in
+  // contexts where the variable is *already* a reference you can set `set_var_is_ref` to `true` to avoid
+  // generating an extra, unnecessary `&` that the compiler will have to automatically dereference.
+  void render_set_sync_write(const string &set_var, bool set_var_is_ref, t_set *tset);
+
+  // Write a map to the output protocol. `map_variable` is the variable containing the map that will
+  // be written to the output protocol.
+  // Variables in auto-generated code are passed by reference. Since this function may be called in
+  // contexts where the variable is *already* a reference you can set `map_var_is_ref` to `true` to avoid
+  // generating an extra, unnecessary `&` that the compiler will have to automatically dereference.
+  void render_map_sync_write(const string &map_var, bool map_var_is_ref, t_map *tset);
+
+  // Return `true` if we need to dereference ths type when writing an element from a container.
+  // Iterations on rust containers are performed as follows: `for v in &values { ... }`
+  // where `v` has type `&RUST_TYPE` All defined functions take primitives by value, so, if the
+  // rendered code is calling such a function it has to dereference `v`.
+  bool needs_deref_on_container_write(t_type* ttype);
+
+  // Return the variable (including all dereferences) required to write values from a rust container
+  // to the output protocol. For example, if you were iterating through a container and using the temp
+  // variable `v` to represent each element, then `ttype` is the type stored in the container and
+  // `base_var` is "v". The return value is the actual string you will have to use to properly reference
+  // the temp variable for writing to the output protocol.
+  string string_container_write_variable(t_type* ttype, const string& base_var);
+
+  // Write the code to read bytes from the wire into the given `t_struct`. `struct_name` is the
+  // actual Rust name of the `t_struct`. If `struct_type` is `T_ARGS` then all struct fields are
+  // necessary. Otherwise, the field's default optionality is used.
+  void render_struct_sync_read(const string &struct_name, t_struct *tstruct, t_rs_generator::e_struct_type struct_type);
+
+  // Write the rust function that deserializes a single type (i.e. i32 etc.) from its wire representation.
+  // Set `is_boxed` to `true` if the resulting value should be wrapped in a `Box::new(...)`.
+  void render_type_sync_read(const string &type_var, t_type *ttype, bool is_boxed = false);
+
+  // Read the wire representation of a list and convert it to its corresponding rust implementation.
+  // The deserialized list is stored in `list_variable`.
+  void render_list_sync_read(t_list *tlist, const string &list_variable);
+
+  // Read the wire representation of a set and convert it to its corresponding rust implementation.
+  // The deserialized set is stored in `set_variable`.
+  void render_set_sync_read(t_set *tset, const string &set_variable);
+
+  // Read the wire representation of a map and convert it to its corresponding rust implementation.
+  // The deserialized map is stored in `map_variable`.
+  void render_map_sync_read(t_map *tmap, const string &map_variable);
+
+  // Return a temporary variable used to store values when deserializing nested containers.
+  string struct_field_read_temp_variable(t_field* tfield);
+
+  // Top-level function that calls the various render functions necessary to write the rust representation
+  // of a thrift union (i.e. an enum).
+  void render_union(t_struct* tstruct);
+
+  // Write the enum corresponding to the Thrift union.
+  void render_union_definition(const string& union_name, t_struct* tstruct);
+
+  // Write the enum impl (with read/write functions) for the Thrift union.
+  void render_union_impl(const string& union_name, t_struct* tstruct);
+
+  // Write the `ENUM::write_to_out_protocol` function.
+  void render_union_sync_write(const string &union_name, t_struct *tstruct);
+
+  // Write the `ENUM::read_from_in_protocol` function.
+  void render_union_sync_read(const string &union_name, t_struct *tstruct);
+
+  // Top-level function that calls the various render functions necessary to write the rust representation
+  // of a Thrift client.
+  void render_sync_client(t_service* tservice);
+
+  // Write the trait with the service-call methods for `tservice`.
+  void render_sync_client_trait(t_service *tservice);
+
+  // Write the trait to be implemented by the client impl if end users can use it to make service calls.
+  void render_sync_client_marker_trait(t_service *tservice);
+
+  // Write the code to create the Thrift service sync client struct and its matching 'impl' block.
+  void render_sync_client_definition_and_impl(const string& client_impl_name);
+
+  // Write the code to create the `SyncClient::new` functions as well as any other functions
+  // callers would like to use on the Thrift service sync client.
+  void render_sync_client_lifecycle_functions(const string& client_struct);
+
+  // Write the code to create the impl block for the `TThriftClient` trait. Since generated
+  // Rust Thrift clients perform all their operations using methods defined in this trait, we
+  // have to implement it for the client structs.
+  void render_sync_client_tthriftclient_impl(const string &client_impl_name);
+
+  // Write the marker traits for any service(s) being extended, including the one for the current
+  // service itself (i.e. `tservice`)
+  void render_sync_client_marker_trait_impls(t_service *tservice, const string &impl_struct_name);
+
+  // Generate a list of all the traits this Thrift client struct extends.
+  string sync_client_marker_traits_for_extension(t_service *tservice);
+
+  // Top-level function that writes the code to make the Thrift service calls.
+  void render_sync_client_process_impl(t_service* tservice);
+
+  // Write the actual function that calls out to the remote service and processes its response.
+  void render_sync_send_recv_wrapper(t_function* tfunc);
+
+  // Write the `send` functionality for a Thrift service call represented by a `t_service->t_function`.
+  void render_sync_send(t_function* tfunc);
+
+  // Write the `recv` functionality for a Thrift service call represented by a `t_service->t_function`.
+  // This method is only rendered if the function is *not* oneway.
+  void render_sync_recv(t_function* tfunc);
+
+  void render_sync_processor(t_service *tservice);
+
+  void render_sync_handler_trait(t_service *tservice);
+  void render_sync_processor_definition_and_impl(t_service *tservice);
+  void render_sync_process_delegation_functions(t_service *tservice);
+  void render_sync_process_function(t_function *tfunc, const string &handler_type);
+  void render_process_match_statements(t_service* tservice);
+  void render_sync_handler_succeeded(t_function *tfunc);
+  void render_sync_handler_failed(t_function *tfunc);
+  void render_sync_handler_failed_user_exception_branch(t_function *tfunc);
+  void render_sync_handler_failed_application_exception_branch(t_function *tfunc, const string &app_err_var);
+  void render_sync_handler_failed_default_exception_branch(t_function *tfunc);
+  void render_sync_handler_send_exception_response(t_function *tfunc, const string &err_var);
+  void render_service_call_structs(t_service* tservice);
+  void render_service_call_args_struct(t_function* tfunc);
+  void render_service_call_result_value_struct(t_function* tfunc);
+
+  string handler_successful_return_struct(t_function* tfunc);
+
+  // Writes the result of `render_thrift_error_struct` wrapped in an `Err(thrift::Error(...))`.
+  void render_thrift_error(
+    const string& error_kind,
+    const string& error_struct,
+    const string& sub_error_kind,
+    const string& error_message
+  );
+
+  // Write a thrift::Error variant struct. Error structs take the form:
+  // ```
+  // pub struct error_struct {
+  //   kind: sub_error_kind,
+  //   message: error_message,
+  // }
+  // ```
+  // A concrete example is:
+  // ```
+  //  pub struct ApplicationError {
+  //    kind: ApplicationErrorKind::Unknown,
+  //    message: "This is some error message",
+  //  }
+  // ```
+  void render_thrift_error_struct(
+    const string& error_struct,
+    const string& sub_error_kind,
+    const string& error_message
+  );
+
+  // Return a string containing all the unpacked service call args given a service call function
+  // `t_function`. Prepends the args with either `&mut self` or `&self` and includes the arg types
+  // in the returned string, for example:
+  // `fn foo(&mut self, field_0: String)`.
+  string rust_sync_service_call_declaration(t_function* tfunc, bool self_is_mutable);
+
+  // Return a string containing all the unpacked service call args given a service call function
+  // `t_function`. Only includes the arg names, each of which is prefixed with the optional prefix
+  // `field_prefix`, for example: `self.field_0`.
+  string rust_sync_service_call_invocation(t_function* tfunc, const string& field_prefix = "");
+
+  // Return a string containing all fields in the struct `tstruct` for use in a function declaration.
+  // Each field is followed by its type, for example: `field_0: String`.
+  string struct_to_declaration(t_struct* tstruct, t_rs_generator::e_struct_type struct_type);
+
+  // Return a string containing all fields in the struct `tstruct` for use in a function call,
+  // for example: `field_0: String`.
+  string struct_to_invocation(t_struct* tstruct, const string& field_prefix = "");
+
+  // Write the documentation for a struct, service-call or other documentation-annotated element.
+  void render_rustdoc(t_doc* tdoc);
+
+  // Return `true` if the true type of `ttype` is a thrift double, `false` otherwise.
+  bool is_double(t_type* ttype);
+
+  // Return a string representing the rust type given a `t_type`.
+  string to_rust_type(t_type* ttype, bool ordered_float = true);
+
+  // Return a string representing the `const` rust type given a `t_type`
+  string to_rust_const_type(t_type* ttype, bool ordered_float = true);
+
+  // Return a string representing the rift `protocol::TType` given a `t_type`.
+  string to_rust_field_type_enum(t_type* ttype);
+
+  // Return the default value to be used when initializing a struct field which has `OPT_IN_REQ_OUT`
+  // optionality.
+  string opt_in_req_out_value(t_type* ttype);
+
+  // Return `true` if we can write a const of the form `pub const FOO: ...`.
+  bool can_generate_simple_const(t_type* ttype);
+
+  // Return `true` if we cannot write a standard Rust constant (because the type needs some allocation).
+  bool can_generate_const_holder(t_type* ttype);
+
+  // Return `true` if this type is a void, and should be represented by the rust `()` type.
+  bool is_void(t_type* ttype);
+
+  t_field::e_req actual_field_req(t_field* tfield, t_rs_generator::e_struct_type struct_type);
+
+  // Return `true` if this `t_field::e_req` is either `t_field::T_OPTIONAL` or `t_field::T_OPT_IN_REQ_OUT`
+  // and needs to be wrapped by an `Option<TYPE_NAME>`, `false` otherwise.
+  bool is_optional(t_field::e_req req);
+
+  // Return `true` if the service call has arguments, `false` otherwise.
+  bool has_args(t_function* tfunc);
+
+  // Return `true` if a service call has non-`()` arguments, `false` otherwise.
+  bool has_non_void_args(t_function* tfunc);
+
+  // Return `pub ` (notice trailing whitespace!) if the struct should be public, `` (empty string) otherwise.
+  string visibility_qualifier(t_rs_generator::e_struct_type struct_type);
+
+  // Returns the namespace prefix for a given Thrift service. If the type is defined in the presently-computed
+  // Thrift program, then an empty string is returned.
+  string rust_namespace(t_service* tservice);
+
+  // Returns the namespace prefix for a given Thrift type. If the type is defined in the presently-computed
+  // Thrift program, then an empty string is returned.
+  string rust_namespace(t_type* ttype);
+
+  // Returns the camel-cased name for a Rust struct type. Handles the case where `tstruct->get_name()` is
+  // a reserved word.
+  string rust_struct_name(t_struct* tstruct);
+
+  // Returns the snake-cased name for a Rust field or local variable. Handles the case where
+  // `tfield->get_name()` is a reserved word.
+  string rust_field_name(t_field* tstruct);
+
+  // Returns the camel-cased name for a Rust union type. Handles the case where `tstruct->get_name()` is
+  // a reserved word.
+  string rust_union_field_name(t_field* tstruct);
+
+  // Converts any variable name into a 'safe' variant that does not clash with any Rust reserved keywords.
+  string rust_safe_name(const string& name);
+
+  // Return `true` if the name is a reserved Rust keyword, `false` otherwise.
+  bool is_reserved(const string& name);
+
+  // Return the name of the function that users will invoke to make outgoing service calls.
+  string service_call_client_function_name(t_function* tfunc);
+
+  // Return the name of the function that users will have to implement to handle incoming service calls.
+  string service_call_handler_function_name(t_function* tfunc);
+
+  // Return the name of the struct used to pack the arguments for the thrift service call.
+  string service_call_args_struct_name(t_function* tfunc);
+
+  // Return the name of the struct used to pack the return value
+  // and user-defined exceptions for the thrift service call.
+  string service_call_result_struct_name(t_function* tfunc);
+
+  string rust_sync_client_marker_trait_name(t_service* tservice);
+
+  // Return the trait name for the sync service client given a `t_service`.
+  string rust_sync_client_trait_name(t_service* tservice);
+
+  // Return the name for the sync service client struct given a `t_service`.
+  string rust_sync_client_impl_name(t_service* tservice);
+
+  // Return the trait name that users will have to implement for the server half of a Thrift service.
+  string rust_sync_handler_trait_name(t_service* tservice);
+
+  // Return the struct name for the  server half of a Thrift service.
+  string rust_sync_processor_name(t_service* tservice);
+
+  // Return the struct name for the struct that contains all the service-call implementations for
+  // the server half of a Thrift service.
+  string rust_sync_processor_impl_name(t_service *tservice);
+
+  // Return the variant name for an enum variant
+  string rust_enum_variant_name(const string& name);
+
+  // Properly uppercase names for use in Rust.
+  string rust_upper_case(const string& name);
+
+  // Snake-case field, parameter and function names and make them Rust friendly.
+  string rust_snake_case(const string& name);
+
+  // Camel-case type/variant names and make them Rust friendly.
+  string rust_camel_case(const string& name);
+
+  // Replace all instances of `search_string` with `replace_string` in `target`.
+  void string_replace(string& target, const string& search_string, const string& replace_string);
+};
+
+void t_rs_generator::init_generator() {
+  // make output directory for this thrift program
+  MKDIR(gen_dir_.c_str());
+
+  // create the file into which we're going to write the generated code
+  string f_gen_name = gen_dir_ + "/" + rust_snake_case(get_program()->get_name()) + ".rs";
+  f_gen_.open(f_gen_name.c_str());
+
+  // header comment
+  f_gen_ << "// " << autogen_summary() << endl;
+  f_gen_ << "// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING" << endl;
+  f_gen_ << endl;
+
+  render_attributes_and_includes();
+}
+
+void t_rs_generator::render_attributes_and_includes() {
+  // turn off some compiler/clippy warnings
+
+  // code always includes BTreeMap/BTreeSet/OrderedFloat
+  f_gen_ << "#![allow(unused_imports)]" << endl;
+  // code might not include imports from crates
+  f_gen_ << "#![allow(unused_extern_crates)]" << endl;
+  // constructors take *all* struct parameters, which can trigger the "too many arguments" warning
+  // some auto-gen'd types can be deeply nested. clippy recommends factoring them out which is hard to autogen
+  f_gen_ << "#![cfg_attr(feature = \"cargo-clippy\", allow(too_many_arguments, type_complexity))]" << endl;
+  // prevent rustfmt from running against this file
+  // lines are too long, code is (thankfully!) not visual-indented, etc.
+  f_gen_ << "#![cfg_attr(rustfmt, rustfmt_skip)]" << endl;
+  f_gen_ << endl;
+
+  // add standard includes
+  f_gen_ << "extern crate ordered_float;" << endl;
+  f_gen_ << "extern crate thrift;" << endl;
+  f_gen_ << "extern crate try_from;" << endl;
+  f_gen_ << endl;
+  f_gen_ << "use ordered_float::OrderedFloat;" << endl;
+  f_gen_ << "use std::cell::RefCell;" << endl;
+  f_gen_ << "use std::collections::{BTreeMap, BTreeSet};" << endl;
+  f_gen_ << "use std::convert::From;" << endl;
+  f_gen_ << "use std::default::Default;" << endl;
+  f_gen_ << "use std::error::Error;" << endl;
+  f_gen_ << "use std::fmt;" << endl;
+  f_gen_ << "use std::fmt::{Display, Formatter};" << endl;
+  f_gen_ << "use std::rc::Rc;" << endl;
+  f_gen_ << "use try_from::TryFrom;" << endl;
+  f_gen_ << endl;
+  f_gen_ << "use thrift::{ApplicationError, ApplicationErrorKind, ProtocolError, ProtocolErrorKind, TThriftClient};" << endl;
+  f_gen_ << "use thrift::protocol::{TFieldIdentifier, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, TInputProtocol, TOutputProtocol, TSetIdentifier, TStructIdentifier, TType};" << endl;
+  f_gen_ << "use thrift::protocol::field_id;" << endl;
+  f_gen_ << "use thrift::protocol::verify_expected_message_type;" << endl;
+  f_gen_ << "use thrift::protocol::verify_expected_sequence_number;" << endl;
+  f_gen_ << "use thrift::protocol::verify_expected_service_call;" << endl;
+  f_gen_ << "use thrift::protocol::verify_required_field_exists;" << endl;
+  f_gen_ << "use thrift::server::TProcessor;" << endl;
+  f_gen_ << endl;
+
+  // add all the program includes
+  // NOTE: this is more involved than you would expect because of service extension
+  // Basically, I have to find the closure of all the services and include their modules at the top-level
+
+  set<string> referenced_modules;
+
+  // first, start by adding explicit thrift includes
+  const vector<t_program*> includes = get_program()->get_includes();
+  vector<t_program*>::const_iterator includes_iter;
+  for(includes_iter = includes.begin(); includes_iter != includes.end(); ++includes_iter) {
+    referenced_modules.insert((*includes_iter)->get_name());
+  }
+
+  // next, recursively iterate through all the services and add the names of any programs they reference
+  const vector<t_service*> services = get_program()->get_services();
+  vector<t_service*>::const_iterator service_iter;
+  for (service_iter = services.begin(); service_iter != services.end(); ++service_iter) {
+    compute_service_referenced_modules(*service_iter, referenced_modules);
+  }
+
+  // finally, write all the "pub use..." declarations
+  if (!referenced_modules.empty()) {
+    set<string>::iterator module_iter;
+    for (module_iter = referenced_modules.begin(); module_iter != referenced_modules.end(); ++module_iter) {
+      f_gen_ << "use " << rust_snake_case(*module_iter) << ";" << endl;
+    }
+    f_gen_ << endl;
+  }
+}
+
+void t_rs_generator::compute_service_referenced_modules(
+  t_service *tservice,
+  set<string> &referenced_modules
+) {
+  t_service* extends = tservice->get_extends();
+  if (extends) {
+    if (extends->get_program() != get_program()) {
+      referenced_modules.insert(extends->get_program()->get_name());
+    }
+    compute_service_referenced_modules(extends, referenced_modules);
+  }
+}
+
+void t_rs_generator::close_generator() {
+  f_gen_.close();
+}
+
+//-----------------------------------------------------------------------------
+//
+// Consts
+//
+// NOTE: consider using macros to generate constants
+//
+//-----------------------------------------------------------------------------
+
+// This is worse than it should be because constants
+// aren't (sensibly) limited to scalar types
+void t_rs_generator::generate_const(t_const* tconst) {
+  string name = tconst->get_name();
+  t_type* ttype = tconst->get_type();
+  t_const_value* tvalue = tconst->get_value();
+
+  if (can_generate_simple_const(ttype)) {
+    render_const_value(name, ttype, tvalue);
+  } else if (can_generate_const_holder(ttype)) {
+    render_const_value_holder(name, ttype, tvalue);
+  } else {
+    throw "cannot generate const for " + name;
+  }
+}
+
+void t_rs_generator::render_const_value(const string& name, t_type* ttype, t_const_value* tvalue) {
+  if (!can_generate_simple_const(ttype)) {
+    throw "cannot generate simple rust constant for " + ttype->get_name();
+  }
+
+  f_gen_ << "pub const " << rust_upper_case(name) << ": " << to_rust_const_type(ttype) << " = ";
+  render_const_value(ttype, tvalue, false);
+  f_gen_ << ";" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_const_value_holder(const string& name, t_type* ttype, t_const_value* tvalue) {
+  if (!can_generate_const_holder(ttype)) {
+    throw "cannot generate constant holder for " + ttype->get_name();
+  }
+
+  string holder_name("Const" + rust_camel_case(name));
+
+  f_gen_ << indent() << "pub struct " << holder_name << ";" << endl;
+  f_gen_ << indent() << "impl " << holder_name << " {" << endl;
+  indent_up();
+
+  f_gen_ << indent() << "pub fn const_value() -> " << to_rust_type(ttype) << " {" << endl;
+  indent_up();
+  render_const_value(ttype, tvalue);
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned) {
+  if (ttype->is_base_type()) {
+    t_base_type* tbase_type = (t_base_type*)ttype;
+    switch (tbase_type->get_base()) {
+    case t_base_type::TYPE_STRING:
+      if (tbase_type->is_binary()) {
+        if (is_owned) {
+          f_gen_ << "\"" << tvalue->get_string() << "\""<<  ".to_owned().into_bytes()";
+        } else {
+          f_gen_ << "b\"" << tvalue->get_string() << "\"";
+        }
+      } else {
+        f_gen_ << "\"" << tvalue->get_string() << "\"";
+        if (is_owned) {
+          f_gen_ << ".to_owned()";
+        }
+      }
+      break;
+    case t_base_type::TYPE_BOOL:
+      f_gen_ << (tvalue->get_integer() ? "true" : "false");
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      f_gen_ << tvalue->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      f_gen_ << "OrderedFloat::from(" << tvalue->get_double() << " as f64)";
+      break;
+    default:
+      throw "cannot generate const value for " + t_base_type::t_base_name(tbase_type->get_base());
+    }
+  } else if (ttype->is_typedef()) {
+    render_const_value(get_true_type(ttype), tvalue);
+  } else if (ttype->is_enum()) {
+    f_gen_ << indent() << "{" << endl;
+    indent_up();
+    f_gen_
+      << indent()
+      << to_rust_type(ttype)
+      << "::try_from("
+      << tvalue->get_integer()
+      << ").expect(\"expecting valid const value\")"
+      << endl;
+    indent_down();
+    f_gen_ << indent() << "}" << endl;
+  } else if (ttype->is_struct() || ttype->is_xception()) {
+    render_const_struct(ttype, tvalue);
+  } else if (ttype->is_container()) {
+    f_gen_ << indent() << "{" << endl;
+    indent_up();
+
+    if (ttype->is_list()) {
+      render_const_list(ttype, tvalue);
+    } else if (ttype->is_set()) {
+      render_const_set(ttype, tvalue);
+    } else if (ttype->is_map()) {
+      render_const_map(ttype, tvalue);
+    } else {
+      throw "cannot generate const container value for " + ttype->get_name();
+    }
+
+    indent_down();
+    f_gen_ << indent() << "}" << endl;
+  } else {
+    throw "cannot generate const value for " + ttype->get_name();
+  }
+}
+
+void t_rs_generator::render_const_struct(t_type* ttype, t_const_value*) {
+  if (((t_struct*)ttype)->is_union()) {
+    f_gen_ << indent() << "{" << endl;
+    indent_up();
+    f_gen_ << indent() << "unimplemented!()" << endl;
+    indent_down();
+    f_gen_ << indent() << "}" << endl;
+  } else {
+    f_gen_ << indent() << "{" << endl;
+    indent_up();
+    f_gen_ << indent() << "unimplemented!()" << endl;
+    indent_down();
+    f_gen_ << indent() << "}" << endl;
+  }
+}
+
+void t_rs_generator::render_const_list(t_type* ttype, t_const_value* tvalue) {
+  t_type* elem_type = ((t_list*)ttype)->get_elem_type();
+  f_gen_ << indent() << "let mut l: Vec<" << to_rust_type(elem_type) << "> = Vec::new();" << endl;
+  const vector<t_const_value*>& elems = tvalue->get_list();
+  vector<t_const_value*>::const_iterator elem_iter;
+  for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
+    t_const_value* elem_value = (*elem_iter);
+    render_container_const_value("l.push", elem_type, elem_value);
+  }
+  f_gen_ << indent() << "l" << endl;
+}
+
+void t_rs_generator::render_const_set(t_type* ttype, t_const_value* tvalue) {
+  t_type* elem_type = ((t_set*)ttype)->get_elem_type();
+  f_gen_ << indent() << "let mut s: BTreeSet<" << to_rust_type(elem_type) << "> = BTreeSet::new();" << endl;
+  const vector<t_const_value*>& elems = tvalue->get_list();
+  vector<t_const_value*>::const_iterator elem_iter;
+  for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
+    t_const_value* elem_value = (*elem_iter);
+    render_container_const_value("s.insert", elem_type, elem_value);
+  }
+  f_gen_ << indent() << "s" << endl;
+}
+
+void t_rs_generator::render_const_map(t_type* ttype, t_const_value* tvalue) {
+  t_type* key_type = ((t_map*)ttype)->get_key_type();
+  t_type* val_type = ((t_map*)ttype)->get_val_type();
+  f_gen_
+    << indent()
+    << "let mut m: BTreeMap<"
+    << to_rust_type(key_type) << ", " << to_rust_type(val_type)
+    << "> = BTreeMap::new();"
+    << endl;
+  const map<t_const_value*, t_const_value*, t_const_value::value_compare>& elems = tvalue->get_map();
+  map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator elem_iter;
+  for (elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
+    t_const_value* key_value = elem_iter->first;
+    t_const_value* val_value = elem_iter->second;
+    if (get_true_type(key_type)->is_base_type()) {
+      f_gen_ << indent() << "let k = ";
+      render_const_value(key_type, key_value);
+      f_gen_ << ";" << endl;
+    } else {
+      f_gen_ << indent() << "let k = {" << endl;
+      indent_up();
+      render_const_value(key_type, key_value);
+      indent_down();
+      f_gen_ << indent() << "};" << endl;
+    }
+    if (get_true_type(val_type)->is_base_type()) {
+      f_gen_ << indent() << "let v = ";
+      render_const_value(val_type, val_value);
+      f_gen_ << ";" << endl;
+    } else {
+      f_gen_ << indent() << "let v = {" << endl;
+      indent_up();
+      render_const_value(val_type, val_value);
+      indent_down();
+      f_gen_ << indent() << "};" << endl;
+    }
+    f_gen_ <<  indent() << "m.insert(k, v);" << endl;
+  }
+  f_gen_ << indent() << "m" << endl;
+}
+
+void t_rs_generator::render_container_const_value(
+  const string& insert_function,
+  t_type* ttype,
+  t_const_value* tvalue
+) {
+  if (get_true_type(ttype)->is_base_type()) {
+    f_gen_ << indent() << insert_function << "(";
+    render_const_value(ttype, tvalue);
+    f_gen_ << ");" << endl;
+  } else {
+    f_gen_ << indent() << insert_function << "(" << endl;
+    indent_up();
+    render_const_value(ttype, tvalue);
+    indent_down();
+    f_gen_ << indent() << ");" << endl;
+  }
+}
+
+//-----------------------------------------------------------------------------
+//
+// Typedefs
+//
+//-----------------------------------------------------------------------------
+
+void t_rs_generator::generate_typedef(t_typedef* ttypedef) {
+  std::string actual_type = to_rust_type(ttypedef->get_type());
+  f_gen_ << "pub type " << rust_safe_name(ttypedef->get_symbolic()) << " = " << actual_type << ";" << endl;
+  f_gen_ << endl;
+}
+
+//-----------------------------------------------------------------------------
+//
+// Enums
+//
+//-----------------------------------------------------------------------------
+
+void t_rs_generator::generate_enum(t_enum* tenum) {
+  string enum_name(rust_camel_case(tenum->get_name()));
+  render_enum_definition(tenum, enum_name);
+  render_enum_impl(enum_name);
+  render_enum_conversion(tenum, enum_name);
+}
+
+void t_rs_generator::render_enum_definition(t_enum* tenum, const string& enum_name) {
+  render_rustdoc((t_doc*) tenum);
+  f_gen_ << "#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl;
+  f_gen_ << "pub enum " << enum_name << " {" << endl;
+  indent_up();
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator constants_iter;
+  for (constants_iter = constants.begin(); constants_iter != constants.end(); ++constants_iter) {
+    t_enum_value* val = (*constants_iter);
+    render_rustdoc((t_doc*) val);
+    f_gen_
+      << indent()
+      << rust_enum_variant_name(val->get_name())
+      << " = "
+      << val->get_value()
+      << ","
+      << endl;
+  }
+
+  indent_down();
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_enum_impl(const string& enum_name) {
+  f_gen_ << "impl " << enum_name << " {" << endl;
+  indent_up();
+
+  f_gen_
+    << indent()
+    << "pub fn write_to_out_protocol(&self, o_prot: &mut TOutputProtocol) -> thrift::Result<()> {"
+    << endl;
+  indent_up();
+  f_gen_ << indent() << "o_prot.write_i32(*self as i32)" << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+
+  f_gen_
+    << indent()
+    << "pub fn read_from_in_protocol(i_prot: &mut TInputProtocol) -> thrift::Result<" << enum_name << "> {"
+    << endl;
+  indent_up();
+
+  f_gen_ << indent() << "let enum_value = i_prot.read_i32()?;" << endl;
+  f_gen_ << indent() << enum_name << "::try_from(enum_value)";
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+
+  indent_down();
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_enum_conversion(t_enum* tenum, const string& enum_name) {
+  f_gen_ << "impl TryFrom<i32> for " << enum_name << " {" << endl;
+  indent_up();
+
+  f_gen_ << indent() << "type Err = thrift::Error;";
+
+  f_gen_ << indent() << "fn try_from(i: i32) -> Result<Self, Self::Err> {" << endl;
+  indent_up();
+
+  f_gen_ << indent() << "match i {" << endl;
+  indent_up();
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator constants_iter;
+  for (constants_iter = constants.begin(); constants_iter != constants.end(); ++constants_iter) {
+    t_enum_value* val = (*constants_iter);
+    f_gen_
+      << indent()
+      << val->get_value()
+      << " => Ok(" << enum_name << "::" << rust_enum_variant_name(val->get_name()) << "),"
+      << endl;
+  }
+  f_gen_ << indent() << "_ => {" << endl;
+  indent_up();
+  render_thrift_error(
+    "Protocol",
+    "ProtocolError",
+    "ProtocolErrorKind::InvalidData",
+    "format!(\"cannot convert enum constant {} to " + enum_name + "\", i)"
+  );
+  indent_down();
+  f_gen_ << indent() << "}," << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+
+  indent_down();
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+}
+
+//-----------------------------------------------------------------------------
+//
+// Structs, Unions and Exceptions
+//
+//-----------------------------------------------------------------------------
+
+void t_rs_generator::generate_xception(t_struct* txception) {
+  render_struct(rust_struct_name(txception), txception, t_rs_generator::T_EXCEPTION);
+}
+
+void t_rs_generator::generate_struct(t_struct* tstruct) {
+  if (tstruct->is_union()) {
+    render_union(tstruct);
+  } else if (tstruct->is_struct()) {
+    render_struct(rust_struct_name(tstruct), tstruct, t_rs_generator::T_REGULAR);
+  } else {
+    throw "cannot generate struct for exception";
+  }
+}
+
+void t_rs_generator::render_struct(
+  const string& struct_name,
+  t_struct* tstruct,
+  t_rs_generator::e_struct_type struct_type
+) {
+  render_type_comment(struct_name);
+  render_struct_definition(struct_name, tstruct, struct_type);
+  render_struct_impl(struct_name, tstruct, struct_type);
+  if (struct_type == t_rs_generator::T_REGULAR || struct_type == t_rs_generator::T_EXCEPTION) {
+    render_struct_default_trait_impl(struct_name, tstruct);
+  }
+  if (struct_type == t_rs_generator::T_EXCEPTION) {
+    render_exception_struct_error_trait_impls(struct_name, tstruct);
+  }
+}
+
+void t_rs_generator::render_struct_definition(
+  const string& struct_name,
+  t_struct* tstruct,
+  t_rs_generator::e_struct_type struct_type
+) {
+  render_rustdoc((t_doc*) tstruct);
+  f_gen_ << "#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl;
+  f_gen_ << visibility_qualifier(struct_type) << "struct " << struct_name << " {" << endl;
+
+  // render the members
+  vector<t_field*> members = tstruct->get_sorted_members();
+  if (!members.empty()) {
+    indent_up();
+
+    vector<t_field*>::iterator members_iter;
+    for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+      t_field* member = (*members_iter);
+      t_field::e_req member_req = actual_field_req(member, struct_type);
+
+      string rust_type = to_rust_type(member->get_type());
+      rust_type = is_optional(member_req) ? "Option<" + rust_type + ">" : rust_type;
+
+      render_rustdoc((t_doc*) member);
+      f_gen_
+        << indent()
+        << visibility_qualifier(struct_type)
+        << rust_field_name(member) << ": " << rust_type << ","
+        << endl;
+    }
+
+    indent_down();
+  }
+
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_exception_struct_error_trait_impls(const string& struct_name, t_struct* tstruct) {
+  // error::Error trait
+  f_gen_ << "impl Error for " << struct_name << " {" << endl;
+  indent_up();
+  f_gen_ << indent() << "fn description(&self) -> &str {" << endl;
+  indent_up();
+  f_gen_ << indent() << "\"" << "remote service threw " << tstruct->get_name() << "\"" << endl; // use *original* name
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  indent_down();
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+
+  // convert::From trait
+  f_gen_ << "impl From<" << struct_name << "> for thrift::Error {" << endl;
+  indent_up();
+  f_gen_ << indent() << "fn from(e: " << struct_name << ") -> Self {" << endl;
+  indent_up();
+  f_gen_ << indent() << "thrift::Error::User(Box::new(e))" << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  indent_down();
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+
+  // fmt::Display trait
+  f_gen_ << "impl Display for " << struct_name << " {" << endl;
+  indent_up();
+  f_gen_ << indent() << "fn fmt(&self, f: &mut Formatter) -> fmt::Result {" << endl;
+  indent_up();
+  f_gen_ << indent() << "self.description().fmt(f)" << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  indent_down();
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_struct_default_trait_impl(const string& struct_name, t_struct* tstruct) {
+  bool has_required_field = false;
+
+  const vector<t_field*>& members = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator members_iter;
+  for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+    t_field* member = *members_iter;
+    if (!is_optional(member->get_req())) {
+      has_required_field = true;
+      break;
+    }
+  }
+
+  if (has_required_field) {
+    return;
+  }
+
+  f_gen_ << "impl Default for " << struct_name << " {" << endl;
+  indent_up();
+  f_gen_ << indent() << "fn default() -> Self {" << endl;
+  indent_up();
+
+  if (members.empty()) {
+    f_gen_ << indent() << struct_name << "{}" << endl;
+  } else {
+    f_gen_ << indent() << struct_name << "{" << endl;
+    indent_up();
+    for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+      t_field *member = (*members_iter);
+      string member_name(rust_field_name(member));
+      f_gen_ << indent() << member_name << ": " << opt_in_req_out_value(member->get_type()) << "," << endl;
+    }
+    indent_down();
+    f_gen_ << indent() << "}" << endl;
+  }
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  indent_down();
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_struct_impl(
+  const string& struct_name,
+  t_struct* tstruct,
+  t_rs_generator::e_struct_type struct_type
+) {
+  f_gen_ << "impl " << struct_name << " {" << endl;
+  indent_up();
+
+  if (struct_type == t_rs_generator::T_REGULAR || struct_type == t_rs_generator::T_EXCEPTION) {
+    render_struct_constructor(struct_name, tstruct, struct_type);
+  }
+
+  render_struct_sync_read(struct_name, tstruct, struct_type);
+  render_struct_sync_write(tstruct, struct_type);
+
+  if (struct_type == t_rs_generator::T_RESULT) {
+    render_result_struct_to_result_method(tstruct);
+  }
+
+  indent_down();
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_struct_constructor(
+  const string& struct_name,
+  t_struct* tstruct,
+  t_rs_generator::e_struct_type struct_type
+) {
+  const vector<t_field*>& members = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator members_iter;
+
+  // build the convenience type parameters that allows us to pass unwrapped values to a constructor and
+  // have them automatically converted into Option<value>
+  bool first_arg = true;
+
+  ostringstream generic_type_parameters;
+  ostringstream generic_type_qualifiers;
+  for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+    t_field* member = (*members_iter);
+    t_field::e_req member_req = actual_field_req(member, struct_type);
+
+    if (is_optional(member_req)) {
+      if (first_arg) {
+        first_arg = false;
+      } else {
+        generic_type_parameters << ", ";
+        generic_type_qualifiers << ", ";
+      }
+      generic_type_parameters << "F" << member->get_key();
+      generic_type_qualifiers << "F" << member->get_key() << ": Into<Option<" << to_rust_type(member->get_type()) << ">>";
+    }
+  }
+
+  string type_parameter_string = generic_type_parameters.str();
+  if (type_parameter_string.length() != 0) {
+    type_parameter_string = "<" + type_parameter_string + ">";
+  }
+
+  string type_qualifier_string = generic_type_qualifiers.str();
+  if (type_qualifier_string.length() != 0) {
+    type_qualifier_string = "where " + type_qualifier_string + " ";
+  }
+
+  // now build the actual constructor arg list
+  // when we're building this list we have to use the type parameters in place of the actual type names
+  // if necessary
+  ostringstream args;
+  first_arg = true;
+  for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+    t_field* member = (*members_iter);
+    t_field::e_req member_req = actual_field_req(member, struct_type);
+    string member_name(rust_field_name(member));
+
+    if (first_arg) {
+      first_arg = false;
+    } else {
+      args << ", ";
+    }
+
+    if (is_optional(member_req)) {
+      args << member_name << ": " << "F" << member->get_key();
+    } else {
+      args << member_name << ": " << to_rust_type(member->get_type());
+    }
+  }
+
+  string arg_string = args.str();
+
+  string visibility(visibility_qualifier(struct_type));
+  f_gen_
+    << indent()
+    << visibility
+    << "fn new"
+    << type_parameter_string
+    << "("
+    << arg_string
+    << ") -> "
+    << struct_name
+    << " "
+    << type_qualifier_string
+    << "{"
+    << endl;
+  indent_up();
+
+  if (members.size() == 0) {
+    f_gen_ << indent() << struct_name << " {}" << endl;
+  } else {
+    f_gen_ << indent() << struct_name << " {" << endl;
+    indent_up();
+
+    for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+      t_field* member = (*members_iter);
+      t_field::e_req member_req = actual_field_req(member, struct_type);
+      string member_name(rust_field_name(member));
+
+      if (is_optional(member_req)) {
+        f_gen_ << indent() << member_name << ": " << member_name << ".into()," << endl;
+      } else {
+        f_gen_ << indent() << member_name << ": " << member_name << "," << endl;
+      }
+    }
+
+    indent_down();
+    f_gen_ << indent() << "}" << endl;
+  }
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+void t_rs_generator::render_result_struct_to_result_method(t_struct* tstruct) {
+  // we don't use the rust struct name in this method, just the service call name
+  string service_call_name = tstruct->get_name();
+
+  // check that we actually have a result
+  size_t index = service_call_name.find(RESULT_STRUCT_SUFFIX, 0);
+  if (index == std::string::npos) {
+    throw "result struct " + service_call_name + " missing result suffix";
+  } else {
+     service_call_name.replace(index, 6, "");
+  }
+
+  const vector<t_field*>& members = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator members_iter;
+
+  // find out what the call's expected return type was
+  string rust_return_type = "()";
+  for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+    t_field* member = (*members_iter);
+    if (member->get_name() == SERVICE_RESULT_VARIABLE) { // don't have to check safe name here
+      rust_return_type = to_rust_type(member->get_type());
+      break;
+    }
+  }
+
+  // NOTE: ideally I would generate the branches and render them separately
+  // I tried this however, and the resulting code was harder to understand
+  // maintaining a rendered branch count (while a little ugly) got me the
+  // rendering I wanted with code that was reasonably understandable
+
+  f_gen_ << indent() << "fn ok_or(self) -> thrift::Result<" << rust_return_type << "> {" << endl;
+  indent_up();
+
+  int rendered_branch_count = 0;
+
+  // render the exception branches
+  for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+    t_field* tfield = (*members_iter);
+    if (tfield->get_name() != SERVICE_RESULT_VARIABLE) { // don't have to check safe name here
+      string field_name("self." + rust_field_name(tfield));
+      string branch_statement = rendered_branch_count == 0 ? "if" : "} else if";
+
+      f_gen_ << indent() << branch_statement << " " << field_name << ".is_some() {" << endl;
+      indent_up();
+      f_gen_ << indent() << "Err(thrift::Error::User(Box::new(" << field_name << ".unwrap())))" << endl;
+      indent_down();
+
+      rendered_branch_count++;
+    }
+  }
+
+  // render the return value branches
+  if (rust_return_type == "()") {
+    if (rendered_branch_count == 0) {
+      // we have the unit return and this service call has no user-defined
+      // exceptions. this means that we've a trivial return (happens with oneways)
+      f_gen_ << indent() << "Ok(())" << endl;
+    } else {
+      // we have the unit return, but there are user-defined exceptions
+      // if we've gotten this far then we have the default return (i.e. call successful)
+      f_gen_ << indent() << "} else {" << endl;
+      indent_up();
+      f_gen_ << indent() << "Ok(())" << endl;
+      indent_down();
+      f_gen_ << indent() << "}" << endl;
+    }
+  } else {
+    string branch_statement = rendered_branch_count == 0 ? "if" : "} else if";
+    f_gen_ << indent() << branch_statement << " self." << SERVICE_RESULT_VARIABLE << ".is_some() {" << endl;
+    indent_up();
+    f_gen_ << indent() << "Ok(self." << SERVICE_RESULT_VARIABLE << ".unwrap())" << endl;
+    indent_down();
+    f_gen_ << indent() << "} else {" << endl;
+    indent_up();
+    // if we haven't found a valid return value *or* a user exception
+    // then we're in trouble; return a default error
+    render_thrift_error(
+      "Application",
+      "ApplicationError",
+      "ApplicationErrorKind::MissingResult",
+      "\"no result received for " + service_call_name + "\""
+    );
+    indent_down();
+    f_gen_ << indent() << "}" << endl;
+  }
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+void t_rs_generator::render_union(t_struct* tstruct) {
+  string union_name(rust_struct_name(tstruct));
+  render_type_comment(union_name);
+  render_union_definition(union_name, tstruct);
+  render_union_impl(union_name, tstruct);
+}
+
+void t_rs_generator::render_union_definition(const string& union_name, t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_sorted_members();
+  if (members.empty()) {
+    throw "cannot generate rust enum with 0 members"; // may be valid thrift, but it's invalid rust
+  }
+
+  f_gen_ << "#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl;
+  f_gen_ << "pub enum " << union_name << " {" << endl;
+  indent_up();
+
+  vector<t_field*>::const_iterator member_iter;
+  for(member_iter = members.begin(); member_iter != members.end(); ++member_iter) {
+    t_field* tfield = (*member_iter);
+    f_gen_
+      << indent()
+      << rust_union_field_name(tfield)
+      << "(" << to_rust_type(tfield->get_type()) << "),"
+      << endl;
+  }
+
+  indent_down();
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_union_impl(const string& union_name, t_struct* tstruct) {
+  f_gen_ << "impl " << union_name << " {" << endl;
+  indent_up();
+
+  render_union_sync_read(union_name, tstruct);
+  render_union_sync_write(union_name, tstruct);
+
+  indent_down();
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+}
+
+//-----------------------------------------------------------------------------
+//
+// Sync Struct Write
+//
+//-----------------------------------------------------------------------------
+
+void t_rs_generator::render_struct_sync_write(
+    t_struct *tstruct,
+    t_rs_generator::e_struct_type struct_type
+) {
+  f_gen_
+    << indent()
+    << visibility_qualifier(struct_type)
+    << "fn write_to_out_protocol(&self, o_prot: &mut TOutputProtocol) -> thrift::Result<()> {"
+    << endl;
+  indent_up();
+
+  // write struct header to output protocol
+  // note: use the *original* struct name here
+  f_gen_ << indent() << "let struct_ident = TStructIdentifier::new(\"" + tstruct->get_name() + "\");" << endl;
+  f_gen_ << indent() << "o_prot.write_struct_begin(&struct_ident)?;" << endl;
+
+  // write struct members to output protocol
+  vector<t_field*> members = tstruct->get_sorted_members();
+  if (!members.empty()) {
+    vector<t_field*>::iterator members_iter;
+    for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+      t_field* member = (*members_iter);
+      t_field::e_req member_req = actual_field_req(member, struct_type);
+      string member_var("self." + rust_field_name(member));
+      render_struct_field_sync_write(member_var, false, member, member_req);
+    }
+  }
+
+  // write struct footer to output protocol
+  f_gen_ << indent() << "o_prot.write_field_stop()?;" << endl;
+  f_gen_ << indent() << "o_prot.write_struct_end()" << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+void t_rs_generator::render_union_sync_write(const string &union_name, t_struct *tstruct) {
+  f_gen_
+    << indent()
+    << "pub fn write_to_out_protocol(&self, o_prot: &mut TOutputProtocol) -> thrift::Result<()> {"
+    << endl;
+  indent_up();
+
+  // write struct header to output protocol
+  // note: use the *original* struct name here
+  f_gen_ << indent() << "let struct_ident = TStructIdentifier::new(\"" + tstruct->get_name() + "\");" << endl;
+  f_gen_ << indent() << "o_prot.write_struct_begin(&struct_ident)?;" << endl;
+
+  // write the enum field to the output protocol
+  vector<t_field*> members = tstruct->get_sorted_members();
+  if (!members.empty()) {
+    f_gen_ << indent() << "match *self {" << endl;
+    indent_up();
+    vector<t_field*>::iterator members_iter;
+    for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+      t_field* member = (*members_iter);
+      t_field::e_req member_req = t_field::T_REQUIRED;
+      t_type* ttype = member->get_type();
+      string match_var((ttype->is_base_type() && !ttype->is_string()) ? "f" : "ref f");
+      f_gen_
+        << indent()
+        << union_name << "::" << rust_union_field_name(member)
+        << "(" << match_var << ") => {"
+        << endl;
+      indent_up();
+      render_struct_field_sync_write("f", true, member, member_req);
+      indent_down();
+      f_gen_ << indent() << "}," << endl;
+    }
+    indent_down();
+    f_gen_ << indent() << "}" << endl;
+  }
+
+  // write struct footer to output protocol
+  f_gen_ << indent() << "o_prot.write_field_stop()?;" << endl;
+  f_gen_ << indent() << "o_prot.write_struct_end()" << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+void t_rs_generator::render_struct_field_sync_write(
+  const string &field_var,
+  bool field_var_is_ref,
+  t_field *tfield,
+  t_field::e_req req
+) {
+  t_type* field_type = tfield->get_type();
+  t_type* actual_type = get_true_type(field_type);
+
+  ostringstream field_stream;
+  field_stream
+    << "TFieldIdentifier::new("
+    << "\"" << tfield->get_name() << "\"" << ", " // note: use *original* name
+    << to_rust_field_type_enum(field_type) << ", "
+    << tfield->get_key() << ")";
+  string field_ident_string = field_stream.str();
+
+  if (is_optional(req)) {
+    string let_var((actual_type->is_base_type() && !actual_type->is_string()) ? "fld_var" : "ref fld_var");
+    f_gen_ << indent() << "if let Some(" << let_var << ") = " << field_var << " {" << endl;
+    indent_up();
+    f_gen_ << indent() << "o_prot.write_field_begin(&" << field_ident_string << ")?;" << endl;
+    render_type_sync_write("fld_var", true, field_type);
+    f_gen_ << indent() << "o_prot.write_field_end()?;" << endl;
+    f_gen_ << indent() << "()" << endl; // FIXME: remove this extraneous '()'
+    indent_down();
+    f_gen_ << indent() << "} else {" << endl; // FIXME: remove else branch
+    indent_up();
+    /* FIXME: rethink how I deal with OPT_IN_REQ_OUT
+    if (req == t_field::T_OPT_IN_REQ_OUT) {
+      f_gen_ << indent() << "let field_ident = " << field_ident_string << ";" << endl;
+      f_gen_ << indent() << "o_prot.write_field_begin(&field_ident)?;" << endl;
+      f_gen_ << indent() << "o_prot.write_field_end()?;" << endl;
+    }*/
+    f_gen_ << indent() << "()" << endl;
+    indent_down();
+    f_gen_ << indent() << "}" << endl;
+  } else {
+    f_gen_ << indent() << "o_prot.write_field_begin(&" << field_ident_string << ")?;" << endl;
+    render_type_sync_write(field_var, field_var_is_ref, tfield->get_type());
+    f_gen_ << indent() << "o_prot.write_field_end()?;" << endl;
+  }
+}
+
+void t_rs_generator::render_type_sync_write(const string &type_var, bool type_var_is_ref, t_type *ttype) {
+  if (ttype->is_base_type()) {
+    t_base_type* tbase_type = (t_base_type*)ttype;
+    switch (tbase_type->get_base()) {
+    case t_base_type::TYPE_VOID:
+      throw "cannot write field of type TYPE_VOID to output protocol";
+    case t_base_type::TYPE_STRING: {
+      string ref(type_var_is_ref ? "" : "&");
+      if (tbase_type->is_binary()) {
+        f_gen_ << indent() << "o_prot.write_bytes(" + ref + type_var + ")?;" << endl;
+      } else {
+        f_gen_ << indent() << "o_prot.write_string(" + ref + type_var + ")?;" << endl;
+      }
+      return;
+    }
+    case t_base_type::TYPE_BOOL:
+      f_gen_ << indent() << "o_prot.write_bool(" + type_var + ")?;" << endl;
+      return;
+    case t_base_type::TYPE_I8:
+      f_gen_ << indent() << "o_prot.write_i8(" + type_var + ")?;" << endl;
+      return;
+    case t_base_type::TYPE_I16:
+      f_gen_ << indent() << "o_prot.write_i16(" + type_var + ")?;" << endl;
+      return;
+    case t_base_type::TYPE_I32:
+      f_gen_ << indent() << "o_prot.write_i32(" + type_var + ")?;" << endl;
+      return;
+    case t_base_type::TYPE_I64:
+      f_gen_ << indent() << "o_prot.write_i64(" + type_var + ")?;" << endl;
+      return;
+    case t_base_type::TYPE_DOUBLE:
+      f_gen_ << indent() << "o_prot.write_double(" + type_var + ".into())?;" << endl;
+      return;
+    }
+  } else if (ttype->is_typedef()) {
+    t_typedef* ttypedef = (t_typedef*) ttype;
+    render_type_sync_write(type_var, type_var_is_ref, ttypedef->get_type());
+    return;
+  } else if (ttype->is_enum() || ttype->is_struct() || ttype->is_xception()) {
+    f_gen_ << indent() << type_var + ".write_to_out_protocol(o_prot)?;" << endl;
+    return;
+  } else if (ttype->is_map()) {
+    render_map_sync_write(type_var, type_var_is_ref, (t_map *) ttype);
+    return;
+  } else if (ttype->is_set()) {
+    render_set_sync_write(type_var, type_var_is_ref, (t_set *) ttype);
+    return;
+  } else if (ttype->is_list()) {
+    render_list_sync_write(type_var, type_var_is_ref, (t_list *) ttype);
+    return;
+  }
+
+  throw "cannot write unsupported type " + ttype->get_name();
+}
+
+void t_rs_generator::render_list_sync_write(const string &list_var, bool list_var_is_ref, t_list *tlist) {
+  t_type* elem_type = tlist->get_elem_type();
+
+  f_gen_
+    << indent()
+    << "o_prot.write_list_begin("
+    << "&TListIdentifier::new("
+    << to_rust_field_type_enum(elem_type) << ", "
+    << list_var << ".len() as i32" << ")"
+    << ")?;"
+    << endl;
+
+  string ref(list_var_is_ref ? "" : "&");
+  f_gen_ << indent() << "for e in " << ref << list_var << " {" << endl;
+  indent_up();
+  render_type_sync_write(string_container_write_variable(elem_type, "e"), true, elem_type);
+  f_gen_ << indent() << "o_prot.write_list_end()?;" << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+void t_rs_generator::render_set_sync_write(const string &set_var, bool set_var_is_ref, t_set *tset) {
+  t_type* elem_type = tset->get_elem_type();
+
+  f_gen_
+    << indent()
+    << "o_prot.write_set_begin("
+    << "&TSetIdentifier::new("
+    << to_rust_field_type_enum(elem_type) << ", "
+    << set_var << ".len() as i32" << ")"
+    << ")?;"
+    << endl;
+
+  string ref(set_var_is_ref ? "" : "&");
+  f_gen_ << indent() << "for e in " << ref << set_var << " {" << endl;
+  indent_up();
+  render_type_sync_write(string_container_write_variable(elem_type, "e"), true, elem_type);
+  f_gen_ << indent() << "o_prot.write_set_end()?;" << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+void t_rs_generator::render_map_sync_write(const string &map_var, bool map_var_is_ref, t_map *tmap) {
+  t_type* key_type = tmap->get_key_type();
+  t_type* val_type = tmap->get_val_type();
+
+  f_gen_
+    << indent()
+    << "o_prot.write_map_begin("
+    << "&TMapIdentifier::new("
+    << to_rust_field_type_enum(key_type) << ", "
+    << to_rust_field_type_enum(val_type) << ", "
+    << map_var << ".len() as i32)"
+    << ")?;"
+    << endl;
+
+  string ref(map_var_is_ref ? "" : "&");
+  f_gen_ << indent() << "for (k, v) in " << ref << map_var << " {" << endl;
+  indent_up();
+  render_type_sync_write(string_container_write_variable(key_type, "k"), true, key_type);
+  render_type_sync_write(string_container_write_variable(val_type, "v"), true, val_type);
+  f_gen_ << indent() << "o_prot.write_map_end()?;" << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+string t_rs_generator::string_container_write_variable(t_type* ttype, const string& base_var) {
+  bool type_needs_deref = needs_deref_on_container_write(ttype);
+  bool type_is_double = is_double(ttype);
+
+  string write_variable;
+
+  if (type_is_double && type_needs_deref) {
+    write_variable = "(*" + base_var + ")";
+  } else if (type_needs_deref) {
+    write_variable = "*" + base_var;
+  } else {
+    write_variable = base_var;
+  }
+
+  return write_variable;
+}
+
+bool t_rs_generator::needs_deref_on_container_write(t_type* ttype) {
+  ttype = get_true_type(ttype);
+  return ttype->is_base_type() && !ttype->is_string();
+}
+
+//-----------------------------------------------------------------------------
+//
+// Sync Struct Read
+//
+//-----------------------------------------------------------------------------
+
+void t_rs_generator::render_struct_sync_read(
+    const string &struct_name,
+    t_struct *tstruct, t_rs_generator::e_struct_type struct_type
+) {
+  f_gen_
+    << indent()
+    << visibility_qualifier(struct_type)
+    << "fn read_from_in_protocol(i_prot: &mut TInputProtocol) -> thrift::Result<" << struct_name << "> {"
+    << endl;
+
+  indent_up();
+
+  f_gen_ << indent() << "i_prot.read_struct_begin()?;" << endl;
+
+  // create temporary variables: one for each field in the struct
+  const vector<t_field*> members = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator members_iter;
+  for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+    t_field* member = (*members_iter);
+    t_field::e_req member_req = actual_field_req(member, struct_type);
+
+    f_gen_
+      << indent()
+      << "let mut " << struct_field_read_temp_variable(member)
+      << ": Option<" << to_rust_type(member->get_type()) << "> = ";
+      if (member_req == t_field::T_OPT_IN_REQ_OUT) {
+        f_gen_ << opt_in_req_out_value(member->get_type()) << ";";
+      } else {
+        f_gen_ << "None;";
+      }
+      f_gen_ << endl;
+  }
+
+  // now loop through the fields we've received
+  f_gen_ << indent() << "loop {" << endl; // start loop
+  indent_up();
+
+  // break out if you've found the Stop field
+  f_gen_ << indent() << "let field_ident = i_prot.read_field_begin()?;" << endl;
+  f_gen_ << indent() << "if field_ident.field_type == TType::Stop {" << endl;
+  indent_up();
+  f_gen_ << indent() << "break;" << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+
+  // now read all the fields found
+  f_gen_ << indent() << "let field_id = field_id(&field_ident)?;" << endl;
+  f_gen_ << indent() << "match field_id {" << endl; // start match
+  indent_up();
+
+  for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+    t_field* tfield = (*members_iter);
+    f_gen_ << indent() << tfield->get_key() << " => {" << endl;
+    indent_up();
+    render_type_sync_read("val", tfield->get_type());
+    f_gen_ << indent() << struct_field_read_temp_variable(tfield) << " = Some(val);" << endl;
+    indent_down();
+    f_gen_ << indent() << "}," << endl;
+  }
+
+  // default case (skip fields)
+  f_gen_ << indent() << "_ => {" << endl;
+  indent_up();
+  f_gen_ << indent() << "i_prot.skip(field_ident.field_type)?;" << endl;
+  indent_down();
+  f_gen_ << indent() << "}," << endl;
+
+  indent_down();
+  f_gen_ << indent() << "};" << endl; // finish match
+  f_gen_ << indent() << "i_prot.read_field_end()?;" << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl; // finish loop
+  f_gen_ << indent() << "i_prot.read_struct_end()?;" << endl; // read message footer from the wire
+
+  // verify that all required fields exist
+  for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+    t_field* tfield = (*members_iter);
+    t_field::e_req req = actual_field_req(tfield, struct_type);
+    if (!is_optional(req)) {
+      f_gen_
+        << indent()
+        << "verify_required_field_exists("
+        << "\"" << struct_name << "." << rust_field_name(tfield) << "\""
+        << ", "
+        << "&" << struct_field_read_temp_variable(tfield)
+        << ")?;" << endl;
+    }
+  }
+
+  // construct the struct
+  if (members.size() == 0) {
+    f_gen_ << indent() << "let ret = " << struct_name << " {};" << endl;
+  } else {
+    f_gen_ << indent() << "let ret = " << struct_name << " {" << endl;
+    indent_up();
+
+    for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+      t_field* tfield = (*members_iter);
+      t_field::e_req req = actual_field_req(tfield, struct_type);
+      string field_name(rust_field_name(tfield));
+      string field_key = struct_field_read_temp_variable(tfield);
+      if (is_optional(req)) {
+        f_gen_ << indent() << field_name << ": " << field_key << "," << endl;
+      } else {
+        f_gen_
+          << indent()
+          << field_name
+          << ": "
+          << field_key
+          << ".expect(\"auto-generated code should have checked for presence of required fields\")"
+          << ","
+          << endl;
+      }
+    }
+
+    indent_down();
+    f_gen_ << indent() << "};" << endl;
+  }
+
+  // return the constructed value
+  f_gen_ << indent() << "Ok(ret)" << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+void t_rs_generator::render_union_sync_read(const string &union_name, t_struct *tstruct) {
+  f_gen_
+    << indent()
+    << "pub fn read_from_in_protocol(i_prot: &mut TInputProtocol) -> thrift::Result<" << union_name << "> {"
+    << endl;
+  indent_up();
+
+  // create temporary variables to hold the
+  // completed union as well as a count of fields read
+  f_gen_ << indent() << "let mut ret: Option<" << union_name << "> = None;" << endl;
+  f_gen_ << indent() << "let mut received_field_count = 0;" << endl;
+
+  // read the struct preamble
+  f_gen_ << indent() << "i_prot.read_struct_begin()?;" << endl;
+
+  // now loop through the fields we've received
+  f_gen_ << indent() << "loop {" << endl; // start loop
+  indent_up();
+
+  // break out if you've found the Stop field
+  f_gen_ << indent() << "let field_ident = i_prot.read_field_begin()?;" << endl;
+  f_gen_ << indent() << "if field_ident.field_type == TType::Stop {" << endl;
+  indent_up();
+  f_gen_ << indent() << "break;" << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+
+  // now read all the fields found
+  f_gen_ << indent() << "let field_id = field_id(&field_ident)?;" << endl;
+  f_gen_ << indent() << "match field_id {" << endl; // start match
+  indent_up();
+
+  const vector<t_field*> members = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator members_iter;
+  for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+    t_field* member = (*members_iter);
+    f_gen_ << indent() << member->get_key() << " => {" << endl;
+    indent_up();
+    render_type_sync_read("val", member->get_type());
+    f_gen_ << indent() << "if ret.is_none() {" << endl;
+    indent_up();
+    f_gen_
+      << indent()
+      << "ret = Some(" << union_name << "::" << rust_union_field_name(member) << "(val));"
+      << endl;
+    indent_down();
+    f_gen_ << indent() << "}" << endl;
+    f_gen_ << indent() << "received_field_count += 1;" << endl;
+    indent_down();
+    f_gen_ << indent() << "}," << endl;
+  }
+
+  // default case (skip fields)
+  f_gen_ << indent() << "_ => {" << endl;
+  indent_up();
+  f_gen_ << indent() << "i_prot.skip(field_ident.field_type)?;" << endl;
+  f_gen_ << indent() << "received_field_count += 1;" << endl;
+  indent_down();
+  f_gen_ << indent() << "}," << endl;
+
+  indent_down();
+  f_gen_ << indent() << "};" << endl; // finish match
+  f_gen_ << indent() << "i_prot.read_field_end()?;" << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl; // finish loop
+  f_gen_ << indent() << "i_prot.read_struct_end()?;" << endl; // finish reading message from wire
+
+  // return the value or an error
+  f_gen_ << indent() << "if received_field_count == 0 {" << endl;
+  indent_up();
+  render_thrift_error(
+    "Protocol",
+    "ProtocolError",
+    "ProtocolErrorKind::InvalidData",
+    "\"received empty union from remote " + union_name + "\""
+  );
+  indent_down();
+  f_gen_ << indent() << "} else if received_field_count > 1 {" << endl;
+  indent_up();
+  render_thrift_error(
+    "Protocol",
+    "ProtocolError",
+    "ProtocolErrorKind::InvalidData",
+    "\"received multiple fields for union from remote " + union_name + "\""
+  );
+  indent_down();
+  f_gen_ << indent() << "} else {" << endl;
+  indent_up();
+  f_gen_ << indent() << "Ok(ret.expect(\"return value should have been constructed\"))" << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+// Construct the rust representation of all supported types from the wire.
+void t_rs_generator::render_type_sync_read(const string &type_var, t_type *ttype, bool is_boxed) {
+  if (ttype->is_base_type()) {
+    t_base_type* tbase_type = (t_base_type*)ttype;
+    switch (tbase_type->get_base()) {
+    case t_base_type::TYPE_VOID:
+      throw "cannot read field of type TYPE_VOID from input protocol";
+    case t_base_type::TYPE_STRING:
+      if (tbase_type->is_binary()) {
+        f_gen_ << indent() << "let " << type_var << " = i_prot.read_bytes()?;" << endl;
+      } else {
+        f_gen_ << indent() << "let " << type_var << " = i_prot.read_string()?;" << endl;
+      }
+      return;
+    case t_base_type::TYPE_BOOL:
+      f_gen_ << indent() << "let " << type_var << " = i_prot.read_bool()?;" << endl;
+      return;
+    case t_base_type::TYPE_I8:
+      f_gen_ << indent() << "let " << type_var << " = i_prot.read_i8()?;" << endl;
+      return;
+    case t_base_type::TYPE_I16:
+      f_gen_ << indent() << "let " << type_var << " = i_prot.read_i16()?;" << endl;
+      return;
+    case t_base_type::TYPE_I32:
+      f_gen_ << indent() << "let " << type_var << " = i_prot.read_i32()?;" << endl;
+      return;
+    case t_base_type::TYPE_I64:
+      f_gen_ << indent() << "let " << type_var << " = i_prot.read_i64()?;" << endl;
+      return;
+    case t_base_type::TYPE_DOUBLE:
+      f_gen_ << indent() << "let " << type_var << " = OrderedFloat::from(i_prot.read_double()?);" << endl;
+      return;
+    }
+  } else if (ttype->is_typedef()) {
+    // FIXME: not a fan of separate `is_boxed` parameter
+    // This is problematic because it's an optional parameter, and only comes
+    // into play once. The core issue is that I lose an important piece of type
+    // information (whether the type is a fwd ref) by unwrapping the typedef'd
+    // type and making the recursive call using it. I can't modify or wrap the
+    // generated string after the fact because it's written directly into the file,
+    // so I have to pass this parameter along. Going with this approach because it
+    // seems like the lowest-cost option to easily support recursive types.
+    t_typedef* ttypedef = (t_typedef*)ttype;
+    render_type_sync_read(type_var, ttypedef->get_type(), ttypedef->is_forward_typedef());
+    return;
+  } else if (ttype->is_enum() || ttype->is_struct() || ttype->is_xception()) {
+    string read_call(to_rust_type(ttype) + "::read_from_in_protocol(i_prot)?");
+    read_call = is_boxed ? "Box::new(" + read_call + ")" : read_call;
+    f_gen_
+      << indent()
+      << "let " << type_var << " = " <<  read_call << ";"
+      << endl;
+    return;
+  } else if (ttype->is_map()) {
+    render_map_sync_read((t_map *) ttype, type_var);
+    return;
+  } else if (ttype->is_set()) {
+    render_set_sync_read((t_set *) ttype, type_var);
+    return;
+  } else if (ttype->is_list()) {
+    render_list_sync_read((t_list *) ttype, type_var);
+    return;
+  }
+
+  throw "cannot read unsupported type " + ttype->get_name();
+}
+
+// Construct the rust representation of a list from the wire.
+void t_rs_generator::render_list_sync_read(t_list *tlist, const string &list_var) {
+  t_type* elem_type = tlist->get_elem_type();
+
+  f_gen_ << indent() << "let list_ident = i_prot.read_list_begin()?;" << endl;
+  f_gen_
+    << indent()
+    << "let mut " << list_var << ": " << to_rust_type((t_type*) tlist)
+    << " = Vec::with_capacity(list_ident.size as usize);"
+    << endl;
+  f_gen_ << indent() << "for _ in 0..list_ident.size {" << endl;
+
+  indent_up();
+
+  string list_elem_var = tmp("list_elem_");
+  render_type_sync_read(list_elem_var, elem_type);
+  f_gen_ << indent() << list_var << ".push(" << list_elem_var << ");" << endl;
+
+  indent_down();
+
+  f_gen_ << indent() << "}" << endl;
+  f_gen_ << indent() << "i_prot.read_list_end()?;" << endl;
+}
+
+// Construct the rust representation of a set from the wire.
+void t_rs_generator::render_set_sync_read(t_set *tset, const string &set_var) {
+  t_type* elem_type = tset->get_elem_type();
+
+  f_gen_ << indent() << "let set_ident = i_prot.read_set_begin()?;" << endl;
+  f_gen_
+    << indent()
+    << "let mut " << set_var << ": " << to_rust_type((t_type*) tset)
+    << " = BTreeSet::new();"
+    << endl;
+  f_gen_ << indent() << "for _ in 0..set_ident.size {" << endl;
+
+  indent_up();
+
+  string set_elem_var = tmp("set_elem_");
+  render_type_sync_read(set_elem_var, elem_type);
+  f_gen_ << indent() << set_var << ".insert(" << set_elem_var << ");" << endl;
+
+  indent_down();
+
+  f_gen_ << indent() << "}" << endl;
+  f_gen_ << indent() << "i_prot.read_set_end()?;" << endl;
+}
+
+// Construct the rust representation of a map from the wire.
+void t_rs_generator::render_map_sync_read(t_map *tmap, const string &map_var) {
+  t_type* key_type = tmap->get_key_type();
+  t_type* val_type = tmap->get_val_type();
+
+  f_gen_ << indent() << "let map_ident = i_prot.read_map_begin()?;" << endl;
+  f_gen_
+    << indent()
+    << "let mut " << map_var << ": " << to_rust_type((t_type*) tmap)
+    << " = BTreeMap::new();"
+    << endl;
+  f_gen_ << indent() << "for _ in 0..map_ident.size {" << endl;
+
+  indent_up();
+
+  string key_elem_var = tmp("map_key_");
+  render_type_sync_read(key_elem_var, key_type);
+  string val_elem_var = tmp("map_val_");
+  render_type_sync_read(val_elem_var, val_type);
+  f_gen_ << indent() << map_var << ".insert(" << key_elem_var << ", " << val_elem_var << ");" << endl;
+
+  indent_down();
+
+  f_gen_ << indent() << "}" << endl;
+  f_gen_ << indent() << "i_prot.read_map_end()?;" << endl;
+}
+
+string t_rs_generator::struct_field_read_temp_variable(t_field* tfield) {
+  std::ostringstream foss;
+  foss << "f_" << tfield->get_key();
+  return foss.str();
+}
+
+//-----------------------------------------------------------------------------
+//
+// Sync Client
+//
+//-----------------------------------------------------------------------------
+
+void t_rs_generator::generate_service(t_service* tservice) {
+  render_sync_client(tservice);
+  render_sync_processor(tservice);
+  render_service_call_structs(tservice);
+}
+
+void t_rs_generator::render_service_call_structs(t_service* tservice) {
+  const std::vector<t_function*> functions = tservice->get_functions();
+  std::vector<t_function*>::const_iterator func_iter;
+
+  // thrift args for service calls are packed
+  // into a struct that's transmitted over the wire, so
+  // generate structs for those too
+  //
+  // thrift returns are *also* packed into a struct
+  // that's passed over the wire, so, generate the struct
+  // for that too. Note that this result struct *also*
+  // contains the exceptions as well
+  for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) {
+    t_function* tfunc = (*func_iter);
+    render_service_call_args_struct(tfunc);
+    if (!tfunc->is_oneway()) {
+      render_service_call_result_value_struct(tfunc);
+    }
+  }
+}
+
+void t_rs_generator::render_sync_client(t_service* tservice) {
+  string client_impl_name(rust_sync_client_impl_name(tservice));
+
+  render_type_comment(tservice->get_name() + " service client"); // note: use *original* name
+  render_sync_client_trait(tservice);
+  render_sync_client_marker_trait(tservice);
+  render_sync_client_definition_and_impl(client_impl_name);
+  render_sync_client_tthriftclient_impl(client_impl_name);
+  render_sync_client_marker_trait_impls(tservice, client_impl_name); f_gen_ << endl;
+  render_sync_client_process_impl(tservice);
+}
+
+void t_rs_generator::render_sync_client_trait(t_service *tservice) {
+  string extension = "";
+  if (tservice->get_extends()) {
+    t_service* extends = tservice->get_extends();
+    extension = " : " + rust_namespace(extends) + rust_sync_client_trait_name(extends);
+  }
+
+  render_rustdoc((t_doc*) tservice);
+  f_gen_ << "pub trait " << rust_sync_client_trait_name(tservice) << extension << " {" << endl;
+  indent_up();
+
+  const std::vector<t_function*> functions = tservice->get_functions();
+  std::vector<t_function*>::const_iterator func_iter;
+  for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) {
+    t_function* tfunc = (*func_iter);
+    string func_name = service_call_client_function_name(tfunc);
+    string func_args = rust_sync_service_call_declaration(tfunc, true);
+    string func_return = to_rust_type(tfunc->get_returntype());
+    render_rustdoc((t_doc*) tfunc);
+    f_gen_ << indent() << "fn " << func_name <<  func_args << " -> thrift::Result<" << func_return << ">;" << endl;
+  }
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_sync_client_marker_trait(t_service *tservice) {
+  f_gen_ << indent() << "pub trait " << rust_sync_client_marker_trait_name(tservice) << " {}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_sync_client_marker_trait_impls(t_service *tservice, const string &impl_struct_name) {
+  f_gen_
+    << indent()
+    << "impl "
+    << SYNC_CLIENT_GENERIC_BOUND_VARS
+    << " "
+    << rust_namespace(tservice) << rust_sync_client_marker_trait_name(tservice)
+    << " for "
+    << impl_struct_name << SYNC_CLIENT_GENERIC_BOUND_VARS
+    << " "
+    << SYNC_CLIENT_GENERIC_BOUNDS
+    << " {}"
+    << endl;
+
+  t_service* extends = tservice->get_extends();
+  if (extends) {
+    render_sync_client_marker_trait_impls(extends, impl_struct_name);
+  }
+}
+
+void t_rs_generator::render_sync_client_definition_and_impl(const string& client_impl_name) {
+
+  // render the definition for the client struct
+  f_gen_
+    << "pub struct "
+    << client_impl_name
+    << SYNC_CLIENT_GENERIC_BOUND_VARS
+    << " "
+    << SYNC_CLIENT_GENERIC_BOUNDS
+    << " {"
+    << endl;
+  indent_up();
+  f_gen_ << indent() << "_i_prot: IP," << endl;
+  f_gen_ << indent() << "_o_prot: OP," << endl;
+  f_gen_ << indent() << "_sequence_number: i32," << endl;
+  indent_down();
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+
+  // render the struct implementation
+  // this includes the new() function as well as the helper send/recv methods for each service call
+  f_gen_
+    << "impl "
+    << SYNC_CLIENT_GENERIC_BOUND_VARS
+    << " "
+    << client_impl_name
+    << SYNC_CLIENT_GENERIC_BOUND_VARS
+    << " "
+    << SYNC_CLIENT_GENERIC_BOUNDS
+    << " {"
+    << endl;
+  indent_up();
+  render_sync_client_lifecycle_functions(client_impl_name);
+  indent_down();
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_sync_client_lifecycle_functions(const string& client_struct) {
+  f_gen_
+    << indent()
+    << "pub fn new(input_protocol: IP, output_protocol: OP) -> "
+    << client_struct
+    << SYNC_CLIENT_GENERIC_BOUND_VARS
+    << " {"
+    << endl;
+  indent_up();
+
+  f_gen_
+    << indent()
+    << client_struct
+    << " { _i_prot: input_protocol, _o_prot: output_protocol, _sequence_number: 0 }"
+    << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+void t_rs_generator::render_sync_client_tthriftclient_impl(const string &client_impl_name) {
+  f_gen_
+    << indent()
+    << "impl "
+    << SYNC_CLIENT_GENERIC_BOUND_VARS
+    << " TThriftClient for "
+    << client_impl_name
+    << SYNC_CLIENT_GENERIC_BOUND_VARS
+    << " "
+    << SYNC_CLIENT_GENERIC_BOUNDS
+    << " {" << endl;
+  indent_up();
+
+  f_gen_ << indent() << "fn i_prot_mut(&mut self) -> &mut TInputProtocol { &mut self._i_prot }" << endl;
+  f_gen_ << indent() << "fn o_prot_mut(&mut self) -> &mut TOutputProtocol { &mut self._o_prot }" << endl;
+  f_gen_ << indent() << "fn sequence_number(&self) -> i32 { self._sequence_number }" << endl;
+  f_gen_
+    << indent()
+    << "fn increment_sequence_number(&mut self) -> i32 { self._sequence_number += 1; self._sequence_number }"
+    << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_sync_client_process_impl(t_service* tservice) {
+  string marker_extension = "" + sync_client_marker_traits_for_extension(tservice);
+
+  f_gen_
+    << "impl <C: TThriftClient + " << rust_sync_client_marker_trait_name(tservice) << marker_extension << "> "
+    << rust_sync_client_trait_name(tservice)
+    << " for C {" << endl;
+  indent_up();
+
+  const std::vector<t_function*> functions = tservice->get_functions();
+  std::vector<t_function*>::const_iterator func_iter;
+  for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) {
+    t_function* func = (*func_iter);
+    render_sync_send_recv_wrapper(func);
+  }
+
+  indent_down();
+  f_gen_ << "}" << endl;
+  f_gen_ << endl;
+}
+
+string t_rs_generator::sync_client_marker_traits_for_extension(t_service *tservice) {
+  string marker_extension;
+
+  t_service* extends = tservice->get_extends();
+  if (extends) {
+    marker_extension = " + " + rust_namespace(extends) + rust_sync_client_marker_trait_name(extends);
+    marker_extension = marker_extension + sync_client_marker_traits_for_extension(extends);
+  }
+
+  return marker_extension;
+}
+
+void t_rs_generator::render_sync_send_recv_wrapper(t_function* tfunc) {
+  string func_name = service_call_client_function_name(tfunc);
+  string func_decl_args = rust_sync_service_call_declaration(tfunc, true);
+  string func_call_args = rust_sync_service_call_invocation(tfunc);
+  string func_return = to_rust_type(tfunc->get_returntype());
+
+  f_gen_
+    << indent()
+    << "fn " << func_name <<  func_decl_args << " -> thrift::Result<" << func_return
+    << "> {"
+    << endl;
+  indent_up();
+
+  f_gen_ << indent() << "(" << endl;
+  indent_up();
+  render_sync_send(tfunc);
+  indent_down();
+  f_gen_ << indent() << ")?;" << endl;
+  if (tfunc->is_oneway()) {
+    f_gen_ << indent() << "Ok(())" << endl;
+  } else {
+    render_sync_recv(tfunc);
+  }
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+void t_rs_generator::render_sync_send(t_function* tfunc) {
+  f_gen_ << indent() << "{" << endl;
+  indent_up();
+
+  // increment the sequence number and generate the call header
+  string message_type = tfunc->is_oneway() ? "TMessageType::OneWay" : "TMessageType::Call";
+  f_gen_ << indent() << "self.increment_sequence_number();" << endl;
+  f_gen_
+    << indent()
+    << "let message_ident = "
+    << "TMessageIdentifier::new(\"" << tfunc->get_name() << "\", " // note: use *original* name
+    << message_type << ", "
+    << "self.sequence_number());"
+    << endl;
+  // pack the arguments into the containing struct that we'll write out over the wire
+  // note that this struct is generated even if we have 0 args
+  ostringstream struct_definition;
+  vector<t_field*> members = tfunc->get_arglist()->get_sorted_members();
+  vector<t_field*>::iterator members_iter;
+  for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+    t_field* member = (*members_iter);
+    string member_name(rust_field_name(member));
+    struct_definition << member_name << ": " << member_name << ", ";
+  }
+  string struct_fields = struct_definition.str();
+  if (struct_fields.size() > 0) {
+    struct_fields = struct_fields.substr(0, struct_fields.size() - 2); // strip trailing comma
+  }
+  f_gen_
+    << indent()
+    << "let call_args = "
+    << service_call_args_struct_name(tfunc)
+    << " { "
+    << struct_fields
+    << " };"
+    << endl;
+  // write everything over the wire
+  f_gen_ << indent() << "self.o_prot_mut().write_message_begin(&message_ident)?;" << endl;
+  f_gen_ << indent() << "call_args.write_to_out_protocol(self.o_prot_mut())?;" << endl; // written even if we have 0 args
+  f_gen_ << indent() << "self.o_prot_mut().write_message_end()?;" << endl;
+  f_gen_ << indent() << "self.o_prot_mut().flush()" << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+void t_rs_generator::render_sync_recv(t_function* tfunc) {
+  f_gen_ << indent() << "{" << endl;
+  indent_up();
+
+  f_gen_ << indent() << "let message_ident = self.i_prot_mut().read_message_begin()?;" << endl;
+  f_gen_ << indent() << "verify_expected_sequence_number(self.sequence_number(), message_ident.sequence_number)?;" << endl;
+  f_gen_ << indent() << "verify_expected_service_call(\"" << tfunc->get_name() <<"\", &message_ident.name)?;" << endl; // note: use *original* name
+  // FIXME: replace with a "try" block
+  f_gen_ << indent() << "if message_ident.message_type == TMessageType::Exception {" << endl;
+  indent_up();
+  f_gen_ << indent() << "let remote_error = thrift::Error::read_application_error_from_in_protocol(self.i_prot_mut())?;" << endl;
+  f_gen_ << indent() << "self.i_prot_mut().read_message_end()?;" << endl;
+  f_gen_ << indent() << "return Err(thrift::Error::Application(remote_error))" << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  f_gen_ << indent() << "verify_expected_message_type(TMessageType::Reply, message_ident.message_type)?;" << endl;
+  f_gen_ << indent() << "let result = " << service_call_result_struct_name(tfunc) << "::read_from_in_protocol(self.i_prot_mut())?;" << endl;
+  f_gen_ << indent() << "self.i_prot_mut().read_message_end()?;" << endl;
+  f_gen_ << indent() << "result.ok_or()" << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+string t_rs_generator::rust_sync_service_call_declaration(t_function* tfunc, bool self_is_mutable) {
+  ostringstream func_args;
+
+  if (self_is_mutable) {
+    func_args << "(&mut self";
+  } else {
+    func_args << "(&self";
+  }
+
+  if (has_args(tfunc)) {
+    func_args << ", "; // put comma after "self"
+    func_args << struct_to_declaration(tfunc->get_arglist(), T_ARGS);
+  }
+
+  func_args << ")";
+  return func_args.str();
+}
+
+string t_rs_generator::rust_sync_service_call_invocation(t_function* tfunc, const string& field_prefix) {
+  ostringstream func_args;
+  func_args << "(";
+
+  if (has_args(tfunc)) {
+    func_args << struct_to_invocation(tfunc->get_arglist(), field_prefix);
+  }
+
+  func_args << ")";
+  return func_args.str();
+}
+
+string t_rs_generator::struct_to_declaration(t_struct* tstruct, t_rs_generator::e_struct_type struct_type) {
+  ostringstream args;
+
+  bool first_arg = true;
+  std::vector<t_field*> fields = tstruct->get_sorted_members();
+  std::vector<t_field*>::iterator field_iter;
+  for (field_iter = fields.begin(); field_iter != fields.end(); ++field_iter) {
+    t_field* tfield = (*field_iter);
+    t_field::e_req field_req = actual_field_req(tfield, struct_type);
+    string rust_type = to_rust_type(tfield->get_type());
+    rust_type = is_optional(field_req) ? "Option<" + rust_type + ">" : rust_type;
+
+    if (first_arg) {
+      first_arg = false;
+    } else {
+      args << ", ";
+    }
+
+    args << rust_field_name(tfield) << ": " << rust_type;
+  }
+
+  return args.str();
+}
+
+string t_rs_generator::struct_to_invocation(t_struct* tstruct, const string& field_prefix) {
+  ostringstream args;
+
+  bool first_arg = true;
+  std::vector<t_field*> fields = tstruct->get_sorted_members();
+  std::vector<t_field*>::iterator field_iter;
+  for (field_iter = fields.begin(); field_iter != fields.end(); ++field_iter) {
+    t_field* tfield = (*field_iter);
+
+    if (first_arg) {
+      first_arg = false;
+    } else {
+      args << ", ";
+    }
+
+    args << field_prefix << rust_field_name(tfield);
+  }
+
+  return args.str();
+}
+
+void t_rs_generator::render_service_call_args_struct(t_function* tfunc) {
+    string args_struct_name(service_call_args_struct_name(tfunc));
+    render_struct(args_struct_name, tfunc->get_arglist(), t_rs_generator::T_ARGS);
+}
+
+void t_rs_generator::render_service_call_result_value_struct(t_function* tfunc) {
+  string result_struct_name = service_call_result_struct_name(tfunc);
+  t_struct result(program_, result_struct_name);
+
+  t_field return_value(tfunc->get_returntype(), SERVICE_RESULT_VARIABLE, 0);
+  return_value.set_req(t_field::T_OPTIONAL);
+  if (!tfunc->get_returntype()->is_void()) {
+    result.append(&return_value);
+  }
+
+  t_struct* exceptions = tfunc->get_xceptions();
+  const vector<t_field*>& exception_types = exceptions->get_members();
+  vector<t_field*>::const_iterator exception_iter;
+  for(exception_iter = exception_types.begin(); exception_iter != exception_types.end(); ++exception_iter) {
+    t_field* exception_type = *exception_iter;
+    exception_type->set_req(t_field::T_OPTIONAL);
+    result.append(exception_type);
+  }
+
+  render_struct(result_struct_name, &result, t_rs_generator::T_RESULT);
+}
+
+//-----------------------------------------------------------------------------
+//
+// Sync Processor
+//
+//-----------------------------------------------------------------------------
+
+void t_rs_generator::render_sync_processor(t_service *tservice) {
+  render_type_comment(tservice->get_name() + " service processor"); // note: use *original* name
+  render_sync_handler_trait(tservice);
+  render_sync_processor_definition_and_impl(tservice);
+}
+
+void t_rs_generator::render_sync_handler_trait(t_service *tservice) {
+  string extension = "";
+  if (tservice->get_extends() != NULL) {
+    t_service* extends = tservice->get_extends();
+    extension = " : " + rust_namespace(extends) + rust_sync_handler_trait_name(extends);
+  }
+
+  const std::vector<t_function*> functions = tservice->get_functions();
+  std::vector<t_function*>::const_iterator func_iter;
+
+  render_rustdoc((t_doc*) tservice);
+  f_gen_ << "pub trait " << rust_sync_handler_trait_name(tservice) << extension << " {" << endl;
+  indent_up();
+  for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) {
+    t_function* tfunc = (*func_iter);
+    string func_name = service_call_handler_function_name(tfunc);
+    string func_args = rust_sync_service_call_declaration(tfunc, false);
+    string func_return = to_rust_type(tfunc->get_returntype());
+    render_rustdoc((t_doc*) tfunc);
+    f_gen_
+      << indent()
+      << "fn "
+      << func_name <<  func_args
+      << " -> thrift::Result<" << func_return << ">;"
+      << endl;
+  }
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_sync_processor_definition_and_impl(t_service *tservice) {
+  string service_processor_name = rust_sync_processor_name(tservice);
+  string handler_trait_name = rust_sync_handler_trait_name(tservice);
+
+  // struct
+  f_gen_
+    << indent()
+    << "pub struct " << service_processor_name
+    << "<H: " << handler_trait_name
+    << "> {"
+    << endl;
+  indent_up();
+  f_gen_ << indent() << "handler: H," << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  f_gen_ << endl;
+
+  // delegating impl
+  f_gen_
+    << indent()
+    << "impl <H: " << handler_trait_name << "> "
+    << service_processor_name
+    << "<H> {"
+    << endl;
+  indent_up();
+  f_gen_ << indent() << "pub fn new(handler: H) -> " << service_processor_name << "<H> {" << endl;
+  indent_up();
+  f_gen_ << indent() << service_processor_name << " {" << endl;
+  indent_up();
+  f_gen_ << indent() << "handler," << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  render_sync_process_delegation_functions(tservice);
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  f_gen_ << endl;
+
+  // actual impl
+  string service_actual_processor_name = rust_sync_processor_impl_name(tservice);
+  f_gen_ << indent() << "pub struct " << service_actual_processor_name << ";" << endl;
+  f_gen_ << endl;
+  f_gen_ << indent() << "impl " << service_actual_processor_name << " {" << endl;
+  indent_up();
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator func_iter;
+  for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) {
+    t_function* tfunc = (*func_iter);
+    render_sync_process_function(tfunc, handler_trait_name);
+  }
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  f_gen_ << endl;
+
+  // processor impl
+  f_gen_
+    << indent()
+    << "impl <H: "
+    << handler_trait_name << "> TProcessor for "
+    << service_processor_name
+    << "<H> {"
+    << endl;
+  indent_up();
+
+  f_gen_
+    << indent()
+    << "fn process(&self, i_prot: &mut TInputProtocol, o_prot: &mut TOutputProtocol) -> thrift::Result<()> {"
+    << endl;
+  indent_up();
+
+  f_gen_ << indent() << "let message_ident = i_prot.read_message_begin()?;" << endl;
+
+  f_gen_ << indent() << "let res = match &*message_ident.name {" << endl; // [sigh] explicit deref coercion
+  indent_up();
+  render_process_match_statements(tservice);
+  f_gen_ << indent() << "method => {" << endl;
+  indent_up();
+  render_thrift_error(
+    "Application",
+    "ApplicationError",
+    "ApplicationErrorKind::UnknownMethod",
+    "format!(\"unknown method {}\", method)"
+  );
+  indent_down();
+  f_gen_ << indent() << "}," << endl;
+
+  indent_down();
+  f_gen_ << indent() << "};" << endl;
+  f_gen_ << indent() << "thrift::server::handle_process_result(&message_ident, res, o_prot)" << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+  f_gen_ << endl;
+}
+
+void t_rs_generator::render_sync_process_delegation_functions(t_service *tservice) {
+  string actual_processor(rust_namespace(tservice) + rust_sync_processor_impl_name(tservice));
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator func_iter;
+  for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) {
+    t_function* tfunc = (*func_iter);
+    string function_name("process_" + rust_snake_case(tfunc->get_name()));
+    f_gen_
+      << indent()
+      << "fn " << function_name
+      << "(&self, "
+      << "incoming_sequence_number: i32, "
+      << "i_prot: &mut TInputProtocol, "
+      << "o_prot: &mut TOutputProtocol) "
+      << "-> thrift::Result<()> {"
+      << endl;
+    indent_up();
+
+    f_gen_
+      << indent()
+      << actual_processor
+      << "::" << function_name
+      << "("
+      << "&self.handler, "
+      << "incoming_sequence_number, "
+      << "i_prot, "
+      << "o_prot"
+      << ")"
+      << endl;
+
+    indent_down();
+    f_gen_ << indent() << "}" << endl;
+  }
+
+  t_service* extends = tservice->get_extends();
+  if (extends) {
+    render_sync_process_delegation_functions(extends);
+  }
+}
+
+void t_rs_generator::render_process_match_statements(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator func_iter;
+  for(func_iter = functions.begin(); func_iter != functions.end(); ++func_iter) {
+    t_function* tfunc = (*func_iter);
+    f_gen_ << indent() << "\"" << tfunc->get_name() << "\"" << " => {" << endl; // note: use *original* name
+    indent_up();
+    f_gen_
+      << indent()
+      << "self.process_" << rust_snake_case(tfunc->get_name())
+      << "(message_ident.sequence_number, i_prot, o_prot)"
+      << endl;
+    indent_down();
+    f_gen_ << indent() << "}," << endl;
+  }
+
+  t_service* extends = tservice->get_extends();
+  if (extends) {
+    render_process_match_statements(extends);
+  }
+}
+
+void t_rs_generator::render_sync_process_function(t_function *tfunc, const string &handler_type) {
+  string sequence_number_param("incoming_sequence_number");
+  string output_protocol_param("o_prot");
+
+  if (tfunc->is_oneway()) {
+    sequence_number_param = "_";
+    output_protocol_param = "_";
+  }
+
+  f_gen_
+    << indent()
+    << "pub fn process_" << rust_snake_case(tfunc->get_name())
+    << "<H: " << handler_type << ">"
+    << "(handler: &H, "
+    << sequence_number_param << ": i32, "
+    << "i_prot: &mut TInputProtocol, "
+    << output_protocol_param << ": &mut TOutputProtocol) "
+    << "-> thrift::Result<()> {"
+    << endl;
+
+  indent_up();
+
+  // *always* read arguments from the input protocol
+  f_gen_
+    << indent()
+    << "let "
+    << (has_non_void_args(tfunc) ? "args" : "_")
+    << " = "
+    << service_call_args_struct_name(tfunc)
+    << "::read_from_in_protocol(i_prot)?;"
+    << endl;
+
+  f_gen_
+    << indent()
+    << "match handler."
+    << service_call_handler_function_name(tfunc)
+    << rust_sync_service_call_invocation(tfunc, "args.")
+    << " {"
+    << endl; // start match
+  indent_up();
+
+  // handler succeeded
+  string handler_return_variable = tfunc->is_oneway() || tfunc->get_returntype()->is_void() ? "_" : "handler_return";
+  f_gen_ << indent() << "Ok(" << handler_return_variable << ") => {" << endl;
+  indent_up();
+  render_sync_handler_succeeded(tfunc);
+  indent_down();
+  f_gen_ << indent() << "}," << endl;
+  // handler failed
+  f_gen_ << indent() << "Err(e) => {" << endl;
+  indent_up();
+  render_sync_handler_failed(tfunc);
+  indent_down();
+  f_gen_ << indent() << "}," << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl; // end match
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl; // end function
+}
+
+void t_rs_generator::render_sync_handler_succeeded(t_function *tfunc) {
+  if (tfunc->is_oneway()) {
+    f_gen_ << indent() << "Ok(())" << endl;
+  } else {
+    f_gen_
+      << indent()
+      << "let message_ident = TMessageIdentifier::new("
+      << "\"" << tfunc->get_name() << "\", " // note: use *original* name
+      << "TMessageType::Reply, "
+      << "incoming_sequence_number);"
+      << endl;
+    f_gen_ << indent() << "o_prot.write_message_begin(&message_ident)?;" << endl;
+    f_gen_ << indent() << "let ret = " << handler_successful_return_struct(tfunc) <<";" << endl;
+    f_gen_ << indent() << "ret.write_to_out_protocol(o_prot)?;" << endl;
+    f_gen_ << indent() << "o_prot.write_message_end()?;" << endl;
+    f_gen_ << indent() << "o_prot.flush()" << endl;
+  }
+}
+
+void t_rs_generator::render_sync_handler_failed(t_function *tfunc) {
+  string err_var("e");
+
+  f_gen_ << indent() << "match " << err_var << " {" << endl;
+  indent_up();
+
+  // if there are any user-defined exceptions for this service call handle them first
+  if (tfunc->get_xceptions() != NULL && tfunc->get_xceptions()->get_sorted_members().size() > 0) {
+    string user_err_var("usr_err");
+    f_gen_ << indent() << "thrift::Error::User(" << user_err_var << ") => {" << endl;
+    indent_up();
+    render_sync_handler_failed_user_exception_branch(tfunc);
+    indent_down();
+    f_gen_ << indent() << "}," << endl;
+  }
+
+  // application error
+  string app_err_var("app_err");
+  f_gen_ << indent() << "thrift::Error::Application(" << app_err_var << ") => {" << endl;
+  indent_up();
+  render_sync_handler_failed_application_exception_branch(tfunc, app_err_var);
+  indent_down();
+  f_gen_ << indent() << "}," << endl;
+
+  // default case
+  f_gen_ << indent() << "_ => {" << endl;
+  indent_up();
+  render_sync_handler_failed_default_exception_branch(tfunc);
+  indent_down();
+  f_gen_ << indent() << "}," << endl;
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+void t_rs_generator::render_sync_handler_failed_user_exception_branch(t_function *tfunc) {
+  if (tfunc->get_xceptions() == NULL || tfunc->get_xceptions()->get_sorted_members().empty()) {
+    throw "cannot render user exception branches if no user exceptions defined";
+  }
+
+  const vector<t_field*> txceptions = tfunc->get_xceptions()->get_sorted_members();
+  vector<t_field*>::const_iterator xception_iter;
+  int branches_rendered = 0;
+
+  // run through all user-defined exceptions
+  for (xception_iter = txceptions.begin(); xception_iter != txceptions.end(); ++xception_iter) {
+    t_field* xception_field = (*xception_iter);
+
+    string if_statement(branches_rendered == 0 ? "if usr_err" : "} else if usr_err");
+    string exception_type(to_rust_type(xception_field->get_type()));
+    f_gen_ << indent() << if_statement << ".downcast_ref::<" << exception_type << ">().is_some() {" << endl;
+    indent_up();
+
+    f_gen_
+      << indent()
+      << "let err = usr_err.downcast::<" << exception_type << ">().expect(\"downcast already checked\");"
+      << endl;
+
+    // render the members of the return struct
+    ostringstream members;
+
+    bool has_result_variable = !(tfunc->is_oneway() || tfunc->get_returntype()->is_void());
+    if (has_result_variable) {
+      members << SERVICE_RESULT_VARIABLE << ": None, ";
+    }
+
+    vector<t_field*>::const_iterator xception_members_iter;
+    for(xception_members_iter = txceptions.begin(); xception_members_iter != txceptions.end(); ++xception_members_iter) {
+      t_field* member = (*xception_members_iter);
+      string member_name(rust_field_name(member));
+      if (member == xception_field) {
+        members << member_name << ": Some(*err), ";
+      } else {
+        members << member_name << ": None, ";
+      }
+    }
+
+    string member_string = members.str();
+    member_string.replace(member_string.size() - 2, 2, " "); // trim trailing comma
+
+    // now write out the return struct
+    f_gen_
+      << indent()
+      << "let ret_err = "
+      << service_call_result_struct_name(tfunc)
+      << "{ " << member_string << "};"
+      << endl;
+
+    f_gen_
+      << indent()
+      << "let message_ident = "
+      << "TMessageIdentifier::new("
+      << "\"" << tfunc->get_name() << "\", " // note: use *original* name
+      << "TMessageType::Reply, "
+      << "incoming_sequence_number);"
+      << endl;
+    f_gen_ << indent() << "o_prot.write_message_begin(&message_ident)?;" << endl;
+    f_gen_ << indent() << "ret_err.write_to_out_protocol(o_prot)?;" << endl;
+    f_gen_ << indent() << "o_prot.write_message_end()?;" << endl;
+    f_gen_ << indent() << "o_prot.flush()" << endl;
+
+    indent_down();
+
+    branches_rendered++;
+  }
+
+  // the catch all, if somehow it was a user exception that we don't support
+  f_gen_ << indent() << "} else {" << endl;
+  indent_up();
+
+  // FIXME: same as default block below
+
+  f_gen_ << indent() << "let ret_err = {" << endl;
+  indent_up();
+  render_thrift_error_struct("ApplicationError", "ApplicationErrorKind::Unknown", "usr_err.description()");
+  indent_down();
+  f_gen_ << indent() << "};" << endl;
+  render_sync_handler_send_exception_response(tfunc, "ret_err");
+
+  indent_down();
+  f_gen_ << indent() << "}" << endl;
+}
+
+void t_rs_generator::render_sync_handler_failed_application_exception_branch(
+    t_function *tfunc,
+    const string &app_err_var
+) {
+  if (tfunc->is_oneway()) {
+    f_gen_ << indent() << "Err(thrift::Error::Application(" << app_err_var << "))" << endl;
+  } else {
+    render_sync_handler_send_exception_response(tfunc, app_err_var);
+  }
+}
+
+void t_rs_generator::render_sync_handler_failed_default_exception_branch(t_function *tfunc) {
+  f_gen_ << indent() << "let ret_err = {" << endl;
+  indent_up();
+  render_thrift_error_struct("ApplicationError", "ApplicationErrorKind::Unknown", "e.description()");
+  indent_down();
+  f_gen_ << indent() << "};" << endl;
+  if (tfunc->is_oneway()) {
+    f_gen_ << indent() << "Err(thrift::Error::Application(ret_err))" << endl;
+  } else {
+    render_sync_handler_send_exception_response(tfunc, "ret_err");
+  }
+}
+
+void t_rs_generator::render_sync_handler_send_exception_response(t_function *tfunc, const string &err_var) {
+  f_gen_
+      << indent()
+      << "let message_ident = TMessageIdentifier::new("
+      << "\"" << tfunc->get_name() << "\", " // note: use *original* name
+      << "TMessageType::Exception, "
+      << "incoming_sequence_number);"
+      << endl;
+  f_gen_ << indent() << "o_prot.write_message_begin(&message_ident)?;" << endl;
+  f_gen_ << indent() << "thrift::Error::write_application_error_to_out_protocol(&" << err_var << ", o_prot)?;" << endl;
+  f_gen_ << indent() << "o_prot.write_message_end()?;" << endl;
+  f_gen_ << indent() << "o_prot.flush()" << endl;
+}
+
+string t_rs_generator::handler_successful_return_struct(t_function* tfunc) {
+  int member_count = 0;
+  ostringstream return_struct;
+
+  return_struct << service_call_result_struct_name(tfunc) << " { ";
+
+  // actual return
+  if (!tfunc->get_returntype()->is_void()) {
+    return_struct << "result_value: Some(handler_return)";
+    member_count++;
+  }
+
+  // any user-defined exceptions
+  if (tfunc->get_xceptions() != NULL) {
+    t_struct* txceptions = tfunc->get_xceptions();
+    const vector<t_field*> members = txceptions->get_sorted_members();
+    vector<t_field*>::const_iterator members_iter;
+    for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+      t_field* xception_field = (*members_iter);
+      if (member_count > 0) { return_struct << ", "; }
+      return_struct << rust_field_name(xception_field) << ": None";
+      member_count++;
+    }
+  }
+
+  return_struct << " }";
+
+  return  return_struct.str();
+}
+
+//-----------------------------------------------------------------------------
+//
+// Utility
+//
+//-----------------------------------------------------------------------------
+
+void t_rs_generator::render_type_comment(const string& type_name) {
+  f_gen_ << "//" << endl;
+  f_gen_ << "// " << type_name << endl;
+  f_gen_ << "//" << endl;
+  f_gen_ << endl;
+}
+
+// NOTE: do *not* put in an extra newline after doc is generated.
+// This is because rust docs have to abut the line they're documenting.
+void t_rs_generator::render_rustdoc(t_doc* tdoc) {
+  if (!tdoc->has_doc()) {
+    return;
+  }
+
+  generate_docstring_comment(f_gen_, "", "/// ", tdoc->get_doc(), "");
+}
+
+void t_rs_generator::render_thrift_error(
+  const string& error_kind,
+  const string& error_struct,
+  const string& sub_error_kind,
+  const string& error_message
+) {
+  f_gen_ << indent() << "Err(" << endl;
+  indent_up();
+  f_gen_ << indent() << "thrift::Error::" << error_kind << "(" << endl;
+  indent_up();
+  render_thrift_error_struct(error_struct, sub_error_kind, error_message);
+  indent_down();
+  f_gen_ << indent() << ")" << endl;
+  indent_down();
+  f_gen_ << indent() << ")" << endl;
+}
+
+void t_rs_generator::render_thrift_error_struct(
+  const string& error_struct,
+  const string& sub_error_kind,
+  const string& error_message
+) {
+  f_gen_ << indent() << error_struct << "::new(" << endl;
+  indent_up();
+  f_gen_ << indent() << sub_error_kind << "," << endl;
+  f_gen_ << indent() << error_message << endl;
+  indent_down();
+  f_gen_ << indent() << ")" << endl;
+}
+
+bool t_rs_generator::is_double(t_type* ttype) {
+  ttype = get_true_type(ttype);
+  if (ttype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+    if (tbase == t_base_type::TYPE_DOUBLE) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+string t_rs_generator::to_rust_type(t_type* ttype, bool ordered_float) {
+  // ttype = get_true_type(ttype); <-- recurses through as many typedef layers as necessary
+  if (ttype->is_base_type()) {
+    t_base_type* tbase_type = ((t_base_type*)ttype);
+    switch (tbase_type->get_base()) {
+    case t_base_type::TYPE_VOID:
+      return "()";
+    case t_base_type::TYPE_STRING:
+      if (tbase_type->is_binary()) {
+        return "Vec<u8>";
+      } else {
+        return "String";
+      }
+    case t_base_type::TYPE_BOOL:
+      return "bool";
+    case t_base_type::TYPE_I8:
+      return "i8";
+    case t_base_type::TYPE_I16:
+      return "i16";
+    case t_base_type::TYPE_I32:
+      return "i32";
+    case t_base_type::TYPE_I64:
+      return "i64";
+    case t_base_type::TYPE_DOUBLE:
+      if (ordered_float) {
+        return "OrderedFloat<f64>";
+      } else {
+        return "f64";
+      }
+    }
+  } else if (ttype->is_typedef()) {
+    t_typedef* ttypedef = (t_typedef*)ttype;
+    string rust_type = rust_namespace(ttype) + ttypedef->get_symbolic();
+    rust_type =  ttypedef->is_forward_typedef() ? "Box<" + rust_type + ">" : rust_type;
+    return rust_type;
+  } else if (ttype->is_enum()) {
+    return rust_namespace(ttype) + rust_camel_case(ttype->get_name());
+  } else if (ttype->is_struct() || ttype->is_xception()) {
+    return rust_namespace(ttype) + rust_camel_case(ttype->get_name());
+  } else if (ttype->is_map()) {
+    t_map* tmap = (t_map*)ttype;
+    return "BTreeMap<" + to_rust_type(tmap->get_key_type()) + ", " + to_rust_type(tmap->get_val_type()) + ">";
+  } else if (ttype->is_set()) {
+    t_set* tset = (t_set*)ttype;
+    return "BTreeSet<" + to_rust_type(tset->get_elem_type()) + ">";
+  } else if (ttype->is_list()) {
+    t_list* tlist = (t_list*)ttype;
+    return "Vec<" + to_rust_type(tlist->get_elem_type()) + ">";
+  }
+
+  throw "cannot find rust type for " + ttype->get_name();
+}
+
+string t_rs_generator::to_rust_const_type(t_type* ttype, bool ordered_float) {
+  if (ttype->is_base_type()) {
+    t_base_type* tbase_type = ((t_base_type*)ttype);
+    if (tbase_type->get_base() == t_base_type::TYPE_STRING) {
+      if (tbase_type->is_binary()) {
+        return "&[u8]";
+      } else {
+        return "&str";
+      }
+    }
+  }
+
+  return to_rust_type(ttype, ordered_float);
+}
+
+string t_rs_generator::to_rust_field_type_enum(t_type* ttype) {
+  ttype = get_true_type(ttype);
+  if (ttype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "will not generate protocol::TType for TYPE_VOID";
+    case t_base_type::TYPE_STRING: // both strings and binary are actually encoded as TType::String
+      return "TType::String";
+    case t_base_type::TYPE_BOOL:
+      return "TType::Bool";
+    case t_base_type::TYPE_I8:
+      return "TType::I08";
+    case t_base_type::TYPE_I16:
+      return "TType::I16";
+    case t_base_type::TYPE_I32:
+      return "TType::I32";
+    case t_base_type::TYPE_I64:
+      return "TType::I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "TType::Double";
+    }
+  } else if (ttype->is_enum()) {
+    return "TType::I32";
+  } else if (ttype->is_struct() || ttype->is_xception()) {
+    return "TType::Struct";
+  } else if (ttype->is_map()) {
+    return "TType::Map";
+  } else if (ttype->is_set()) {
+    return "TType::Set";
+  } else if (ttype->is_list()) {
+    return "TType::List";
+  }
+
+  throw "cannot find TType for " + ttype->get_name();
+}
+
+string t_rs_generator::opt_in_req_out_value(t_type* ttype) {
+  ttype = get_true_type(ttype);
+  if (ttype->is_base_type()) {
+    t_base_type* tbase_type = ((t_base_type*)ttype);
+    switch (tbase_type->get_base()) {
+    case t_base_type::TYPE_VOID:
+      throw "cannot generate OPT_IN_REQ_OUT value for void";
+    case t_base_type::TYPE_STRING:
+      if (tbase_type->is_binary()) {
+        return "Some(Vec::new())";
+      } else {
+        return "Some(\"\".to_owned())";
+      }
+    case t_base_type::TYPE_BOOL:
+      return "Some(false)";
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      return "Some(0)";
+    case t_base_type::TYPE_DOUBLE:
+      return "Some(OrderedFloat::from(0.0))";
+    }
+
+  } else if (ttype->is_enum() || ttype->is_struct() || ttype->is_xception()) {
+    return "None";
+  } else if (ttype->is_list()) {
+    return "Some(Vec::new())";
+  } else if (ttype->is_set()) {
+    return "Some(BTreeSet::new())";
+  } else if (ttype->is_map()) {
+    return "Some(BTreeMap::new())";
+  }
+
+  throw "cannot generate opt-in-req-out value for type " + ttype->get_name();
+}
+
+bool t_rs_generator::can_generate_simple_const(t_type* ttype) {
+  t_type* actual_type = get_true_type(ttype);
+  if (actual_type->is_base_type()) {
+    t_base_type* tbase_type = (t_base_type*)actual_type;
+    return !(tbase_type->get_base() == t_base_type::TYPE_DOUBLE);
+  } else {
+    return false;
+  }
+}
+
+bool t_rs_generator::can_generate_const_holder(t_type* ttype) {
+  t_type* actual_type = get_true_type(ttype);
+  return !can_generate_simple_const(actual_type) && !actual_type->is_service();
+}
+
+bool t_rs_generator::is_void(t_type* ttype) {
+  return ttype->is_base_type() && ((t_base_type*)ttype)->get_base() == t_base_type::TYPE_VOID;
+}
+
+bool t_rs_generator::is_optional(t_field::e_req req) {
+  return req == t_field::T_OPTIONAL || req == t_field::T_OPT_IN_REQ_OUT;
+}
+
+t_field::e_req t_rs_generator::actual_field_req(t_field* tfield, t_rs_generator::e_struct_type struct_type) {
+  return struct_type == t_rs_generator::T_ARGS ? t_field::T_REQUIRED : tfield->get_req();
+}
+
+bool t_rs_generator::has_args(t_function* tfunc) {
+  return tfunc->get_arglist() != NULL && !tfunc->get_arglist()->get_sorted_members().empty();
+}
+
+bool t_rs_generator::has_non_void_args(t_function* tfunc) {
+  bool has_non_void_args = false;
+
+  const vector<t_field*> args = tfunc->get_arglist()->get_sorted_members();
+  vector<t_field*>::const_iterator args_iter;
+  for (args_iter = args.begin(); args_iter != args.end(); ++args_iter) {
+    t_field* tfield = (*args_iter);
+    if (!tfield->get_type()->is_void()) {
+      has_non_void_args = true;
+      break;
+    }
+  }
+
+  return has_non_void_args;
+}
+
+string t_rs_generator::visibility_qualifier(t_rs_generator::e_struct_type struct_type) {
+  switch(struct_type) {
+  case t_rs_generator::T_ARGS:
+  case t_rs_generator::T_RESULT:
+    return "";
+  default:
+    return "pub ";
+  }
+}
+
+string t_rs_generator::rust_namespace(t_service* tservice) {
+  if (tservice->get_program()->get_name() != get_program()->get_name()) {
+    return rust_snake_case(tservice->get_program()->get_name()) + "::";
+  } else {
+    return "";
+  }
+}
+
+string t_rs_generator::rust_namespace(t_type* ttype) {
+  if (ttype->get_program()->get_name() != get_program()->get_name()) {
+    return rust_snake_case(ttype->get_program()->get_name()) + "::";
+  } else {
+    return "";
+  }
+}
+
+bool t_rs_generator::is_reserved(const string& name) {
+  return RUST_RESERVED_WORDS_SET.find(name) != RUST_RESERVED_WORDS_SET.end();
+}
+
+string t_rs_generator::rust_struct_name(t_struct* tstruct) {
+  string base_struct_name(rust_camel_case(tstruct->get_name()));
+  return rust_safe_name(base_struct_name);
+}
+
+string t_rs_generator::rust_field_name(t_field* tfield) {
+  string base_field_name(rust_snake_case(tfield->get_name()));
+  return rust_safe_name(base_field_name);
+}
+
+string t_rs_generator::rust_union_field_name(t_field* tfield) {
+  string base_field_name(rust_camel_case(tfield->get_name()));
+  return rust_safe_name(base_field_name);
+}
+
+string t_rs_generator::rust_safe_name(const string& name) {
+  if (is_reserved(name)) {
+    return name + "_";
+  } else {
+    return name;
+  }
+}
+
+string t_rs_generator::service_call_client_function_name(t_function* tfunc) {
+  return rust_snake_case(tfunc->get_name());
+}
+
+string t_rs_generator::service_call_handler_function_name(t_function* tfunc) {
+  return "handle_" + rust_snake_case(tfunc->get_name());
+}
+
+string t_rs_generator::service_call_args_struct_name(t_function* tfunc) {
+  // Thrift automatically appends `Args` to the arglist name. No need to do it here.
+  return rust_camel_case(service_name_) + rust_camel_case(tfunc->get_arglist()->get_name());
+}
+
+string t_rs_generator::service_call_result_struct_name(t_function* tfunc) {
+  return rust_camel_case(service_name_) + rust_camel_case(tfunc->get_name()) + RESULT_STRUCT_SUFFIX;
+}
+
+string t_rs_generator::rust_sync_client_marker_trait_name(t_service* tservice) {
+  return "T" + rust_camel_case(tservice->get_name()) + "SyncClientMarker";
+}
+
+string t_rs_generator::rust_sync_client_trait_name(t_service* tservice) {
+  return "T" + rust_camel_case(tservice->get_name()) + "SyncClient";
+}
+
+string t_rs_generator::rust_sync_client_impl_name(t_service* tservice) {
+  return rust_camel_case(tservice->get_name()) + "SyncClient";
+}
+
+string t_rs_generator::rust_sync_handler_trait_name(t_service* tservice) {
+  return rust_camel_case(tservice->get_name()) + "SyncHandler";
+}
+
+string t_rs_generator::rust_sync_processor_name(t_service* tservice) {
+  return rust_camel_case(tservice->get_name()) + "SyncProcessor";
+}
+
+string t_rs_generator::rust_sync_processor_impl_name(t_service *tservice) {
+  return "T" + rust_camel_case(tservice->get_name()) + "ProcessFunctions";
+}
+
+string t_rs_generator::rust_enum_variant_name(const string &name) {
+  bool all_uppercase = true;
+
+  for (size_t i = 0; i < name.size(); i++) {
+    if (isalnum(name[i]) && islower(name[i])) {
+      all_uppercase = false;
+      break;
+    }
+  }
+
+  if (all_uppercase) {
+    return capitalize(camelcase(lowercase(name)));
+  } else {
+    return capitalize(camelcase(name));
+  }
+}
+
+string t_rs_generator::rust_upper_case(const string& name) {
+  string str(uppercase(underscore(name)));
+  string_replace(str, "__", "_");
+  return str;
+}
+
+string t_rs_generator::rust_snake_case(const string& name) {
+  string str(decapitalize(underscore(name)));
+  string_replace(str, "__", "_");
+  return str;
+}
+
+string t_rs_generator::rust_camel_case(const string& name) {
+  string str(capitalize(camelcase(name)));
+  string_replace(str, "_", "");
+  return str;
+}
+
+void t_rs_generator::string_replace(string& target, const string& search_string, const string& replace_string) {
+  if (target.empty()) {
+    return;
+  }
+
+  size_t match_len = search_string.length();
+  size_t replace_len = replace_string.length();
+
+  size_t search_idx = 0;
+  size_t match_idx;
+  while ((match_idx = target.find(search_string, search_idx)) != string::npos) {
+    target.replace(match_idx, match_len, replace_string);
+    search_idx = match_idx + replace_len;
+  }
+}
+
+THRIFT_REGISTER_GENERATOR(
+  rs,
+  "Rust",
+  "\n") // no Rust-generator-specific options
diff --git a/compiler/cpp/src/thrift/generate/t_st_generator.cc b/compiler/cpp/src/thrift/generate/t_st_generator.cc
new file mode 100644
index 0000000..595a949
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_st_generator.cc
@@ -0,0 +1,1056 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+
+#include "thrift/platform.h"
+#include "thrift/version.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ofstream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * Smalltalk code generator.
+ *
+ */
+class t_st_generator : public t_oop_generator {
+public:
+  t_st_generator(t_program* program,
+                 const std::map<std::string, std::string>& parsed_options,
+                 const std::string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    temporary_var = 0;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    /* no options yet */
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      throw "unknown option st:" + iter->first;
+    }
+
+    out_dir_base_ = "gen-st";
+  }
+
+  /**
+   * 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);
+  void generate_class_side_definition();
+  void generate_force_consts();
+
+  std::string render_const_value(t_type* type, t_const_value* value);
+
+  /**
+   * Struct generation code
+   */
+
+  void generate_st_struct(std::ostream& out, t_struct* tstruct, bool is_exception);
+  void generate_accessors(std::ostream& out, t_struct* tstruct);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_service_client(t_service* tservice);
+
+  void generate_send_method(t_function* tfunction);
+  void generate_recv_method(t_function* tfunction);
+
+  std::string map_reader(t_map* tmap);
+  std::string list_reader(t_list* tlist);
+  std::string set_reader(t_set* tset);
+  std::string struct_reader(t_struct* tstruct, std::string clsName);
+
+  std::string map_writer(t_map* tmap, std::string name);
+  std::string list_writer(t_list* tlist, std::string name);
+  std::string set_writer(t_set* tset, std::string name);
+  std::string struct_writer(t_struct* tstruct, std::string fname);
+
+  std::string write_val(t_type* t, std::string fname);
+  std::string read_val(t_type* t);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string st_autogen_comment();
+
+  void st_class_def(std::ostream& out, std::string name);
+  void st_method(std::ostream& out, std::string cls, std::string name);
+  void st_method(std::ostream& out, std::string cls, std::string name, std::string category);
+  void st_close_method(std::ostream& out);
+  void st_class_method(std::ostream& out, std::string cls, std::string name);
+  void st_class_method(std::ostream& out, std::string cls, std::string name, std::string category);
+  void st_setter(std::ostream& out, std::string cls, std::string name, std::string type);
+  void st_getter(std::ostream& out, std::string cls, std::string name);
+  void st_accessors(std::ostream& out, std::string cls, std::string name, std::string type);
+
+  std::string class_name();
+  static bool is_valid_namespace(const std::string& sub_namespace);
+  std::string client_class_name();
+  std::string prefix(std::string name);
+  std::string declare_field(t_field* tfield);
+  std::string type_name(t_type* ttype);
+
+  std::string function_signature(t_function* tfunction);
+  std::string argument_list(t_struct* tstruct);
+  std::string function_types_comment(t_function* fn);
+
+  std::string type_to_enum(t_type* ttype);
+  std::string a_type(t_type* type);
+  bool is_vowel(char c);
+  std::string temp_name();
+  std::string generated_category();
+
+private:
+  /**
+   * File streams
+   */
+  int temporary_var;
+  ofstream_with_content_based_conditional_update f_;
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_st_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  temporary_var = 0;
+
+  // Make output file
+  string f_name = get_out_dir() + "/" + program_name_ + ".st";
+  f_.open(f_name.c_str());
+
+  // Print header
+  f_ << st_autogen_comment() << endl;
+
+  st_class_def(f_, program_name_);
+  generate_class_side_definition();
+
+  // Generate enums
+  vector<t_enum*> enums = program_->get_enums();
+  vector<t_enum*>::iterator en_iter;
+  for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+    generate_enum(*en_iter);
+  }
+}
+
+string t_st_generator::class_name() {
+  return capitalize(program_name_);
+}
+
+bool t_st_generator::is_valid_namespace(const std::string& sub_namespace) {
+  return sub_namespace == "prefix" || sub_namespace == "category";
+}
+
+string t_st_generator::prefix(string class_name) {
+  string prefix = program_->get_namespace("smalltalk.prefix");
+  string name = capitalize(class_name);
+  name = prefix.empty() ? name : (prefix + name);
+  return name;
+}
+
+string t_st_generator::client_class_name() {
+  return capitalize(service_name_) + "Client";
+}
+
+/**
+ * Autogen'd comment
+ */
+string t_st_generator::st_autogen_comment() {
+  return std::string("'") + "Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + "\n"
+         + "DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "'!\n";
+}
+
+void t_st_generator::generate_force_consts() {
+  f_ << prefix(class_name()) << " enums keysAndValuesDo: [:k :v | " << prefix(class_name())
+     << " enums at: k put: v value].!" << endl;
+
+  f_ << prefix(class_name()) << " constants keysAndValuesDo: [:k :v | " << prefix(class_name())
+     << " constants at: k put: v value].!" << endl;
+}
+
+void t_st_generator::close_generator() {
+  generate_force_consts();
+  f_.close();
+}
+
+string t_st_generator::generated_category() {
+  string cat = program_->get_namespace("smalltalk.category");
+  // For compatibility with the Thrift grammar, the category must
+  // be punctuated by dots.  Replaces them with dashes here.
+  for (string::iterator iter = cat.begin(); iter != cat.end(); ++iter) {
+    if (*iter == '.') {
+      *iter = '-';
+    }
+  }
+  return cat.size() ? cat : "Generated-" + class_name();
+}
+
+/**
+ * Generates a typedef. This is not done in Smalltalk, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_st_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+void t_st_generator::st_class_def(std::ostream& out, string name) {
+  out << "Object subclass: #" << prefix(name) << endl;
+  indent_up();
+  out << indent() << "instanceVariableNames: ''" << endl << indent() << "classVariableNames: ''"
+      << endl << indent() << "poolDictionaries: ''" << endl << indent() << "category: '"
+      << generated_category() << "'!" << endl << endl;
+}
+
+void t_st_generator::st_method(std::ostream& out, string cls, string name) {
+  st_method(out, cls, name, "as yet uncategorized");
+}
+
+void t_st_generator::st_class_method(std::ostream& out, string cls, string name) {
+  st_method(out, cls + " class", name);
+}
+
+void t_st_generator::st_class_method(std::ostream& out, string cls, string name, string category) {
+  st_method(out, cls, name, category);
+}
+
+void t_st_generator::st_method(std::ostream& out, string cls, string name, string category) {
+  char timestr[50];
+  time_t rawtime;
+  struct tm* tinfo;
+
+  time(&rawtime);
+  tinfo = localtime(&rawtime);
+  strftime(timestr, 50, "%m/%d/%Y %H:%M", tinfo);
+
+  out << "!" << prefix(cls) << " methodsFor: '" + category + "' stamp: 'thrift " << timestr
+      << "'!\n" << name << endl;
+
+  indent_up();
+  out << indent();
+}
+
+void t_st_generator::st_close_method(std::ostream& out) {
+  out << "! !" << endl << endl;
+  indent_down();
+}
+
+void t_st_generator::st_setter(std::ostream& out,
+                               string cls,
+                               string name,
+                               string type = "anObject") {
+  st_method(out, cls, name + ": " + type);
+  out << name << " := " + type;
+  st_close_method(out);
+}
+
+void t_st_generator::st_getter(std::ostream& out, string cls, string name) {
+  st_method(out, cls, name + "");
+  out << "^ " << name;
+  st_close_method(out);
+}
+
+void t_st_generator::st_accessors(std::ostream& out,
+                                  string cls,
+                                  string name,
+                                  string type = "anObject") {
+  st_setter(out, cls, name, type);
+  st_getter(out, cls, name);
+}
+
+void t_st_generator::generate_class_side_definition() {
+  f_ << prefix(class_name()) << " class" << endl << "\tinstanceVariableNames: 'constants enums'!"
+     << endl << endl;
+
+  st_accessors(f_, class_name() + " class", "enums");
+  st_accessors(f_, class_name() + " class", "constants");
+
+  f_ << prefix(class_name()) << " enums: Dictionary new!" << endl;
+  f_ << prefix(class_name()) << " constants: Dictionary new!" << endl;
+
+  f_ << endl;
+}
+
+/**
+ * Generates code for an enumerated type. Done using a class to scope
+ * the values.
+ *
+ * @param tenum The enumeration
+ */
+void t_st_generator::generate_enum(t_enum* tenum) {
+  string cls_name = program_name_ + capitalize(tenum->get_name());
+
+  f_ << prefix(class_name()) << " enums at: '" << tenum->get_name() << "' put: ["
+     << "(Dictionary new " << endl;
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    int value = (*c_iter)->get_value();
+    f_ << "\tat: '" << (*c_iter)->get_name() << "' put: " << value << ";" << endl;
+  }
+
+  f_ << "\tyourself)]!" << endl << endl;
+}
+
+/**
+ * Generate a constant value
+ */
+void t_st_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  f_ << prefix(class_name()) << " constants at: '" << name << "' put: ["
+     << render_const_value(type, value) << "]!" << endl << 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_st_generator::render_const_value(t_type* type, t_const_value* value) {
+  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_I8:
+    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 << "(" << capitalize(type->get_name()) << " new " << 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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::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();
+      }
+
+      out << indent() << v_iter->first->get_string() << ": "
+          << render_const_value(field_type, v_iter->second) << ";" << endl;
+    }
+    out << indent() << "yourself)";
+
+    indent_down();
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    out << "(Dictionary new" << endl;
+    indent_up();
+    indent_up();
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent() << indent();
+      out << "at: " << render_const_value(ktype, v_iter->first);
+      out << " put: ";
+      out << render_const_value(vtype, v_iter->second);
+      out << ";" << endl;
+    }
+    out << indent() << indent() << "yourself)";
+    indent_down();
+    indent_down();
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    if (type->is_set()) {
+      out << "(Set new" << endl;
+    } else {
+      out << "(OrderedCollection new" << endl;
+    }
+    indent_up();
+    indent_up();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent() << indent();
+      out << "add: " << render_const_value(etype, *v_iter);
+      out << ";" << endl;
+    }
+    out << indent() << indent() << "yourself)";
+    indent_down();
+    indent_down();
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+  return out.str();
+}
+
+/**
+ * Generates a Smalltalk struct
+ */
+void t_st_generator::generate_struct(t_struct* tstruct) {
+  generate_st_struct(f_, 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_st_generator::generate_xception(t_struct* txception) {
+  generate_st_struct(f_, txception, true);
+}
+
+/**
+ * Generates a smalltalk class to represent a struct
+ */
+void t_st_generator::generate_st_struct(std::ostream& out,
+                                        t_struct* tstruct,
+                                        bool is_exception = false) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  if (is_exception)
+    out << "Error";
+  else
+    out << "Object";
+
+  out << " subclass: #" << prefix(type_name(tstruct)) << endl << "\tinstanceVariableNames: '";
+
+  if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (m_iter != members.begin())
+        out << " ";
+      out << camelcase((*m_iter)->get_name());
+    }
+  }
+
+  out << "'\n"
+      << "\tclassVariableNames: ''\n"
+      << "\tpoolDictionaries: ''\n"
+      << "\tcategory: '" << generated_category() << "'!\n\n";
+
+  generate_accessors(out, tstruct);
+}
+
+bool t_st_generator::is_vowel(char c) {
+  switch (tolower(c)) {
+  case 'a':
+  case 'e':
+  case 'i':
+  case 'o':
+  case 'u':
+    return true;
+  }
+  return false;
+}
+
+string t_st_generator::a_type(t_type* type) {
+  string prefix;
+
+  if (is_vowel(type_name(type)[0]))
+    prefix = "an";
+  else
+    prefix = "a";
+
+  return prefix + capitalize(type_name(type));
+}
+
+void t_st_generator::generate_accessors(std::ostream& out, t_struct* tstruct) {
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  string type;
+  string prefix;
+
+  if (members.size() > 0) {
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      st_accessors(out,
+                   capitalize(type_name(tstruct)),
+                   camelcase((*m_iter)->get_name()),
+                   a_type((*m_iter)->get_type()));
+    }
+    out << endl;
+  }
+}
+
+/**
+ * Generates a thrift service.
+ *
+ * @param tservice The service definition
+ */
+void t_st_generator::generate_service(t_service* tservice) {
+  generate_service_client(tservice);
+  // generate_service_server(tservice);
+}
+
+string t_st_generator::temp_name() {
+  std::ostringstream out;
+  out << "temp" << temporary_var++;
+  return out.str();
+}
+
+string t_st_generator::map_writer(t_map* tmap, string fname) {
+  std::ostringstream out;
+  string key = temp_name();
+  string val = temp_name();
+
+  out << "[oprot writeMapBegin: (TMap new keyType: " << type_to_enum(tmap->get_key_type())
+      << "; valueType: " << type_to_enum(tmap->get_val_type()) << "; size: " << fname << " size)."
+      << endl;
+  indent_up();
+
+  out << indent() << fname << " keysAndValuesDo: [:" << key << " :" << val << " |" << endl;
+  indent_up();
+
+  out << indent() << write_val(tmap->get_key_type(), key) << "." << endl << indent()
+      << write_val(tmap->get_val_type(), val);
+  indent_down();
+
+  out << "]." << endl << indent() << "oprot writeMapEnd] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::map_reader(t_map* tmap) {
+  std::ostringstream out;
+  string desc = temp_name();
+  string val = temp_name();
+
+  out << "[|" << desc << " " << val << "| " << endl;
+  indent_up();
+
+  out << indent() << desc << " := iprot readMapBegin." << endl << indent() << val
+      << " := Dictionary new." << endl << indent() << desc << " size timesRepeat: [" << endl;
+
+  indent_up();
+  out << indent() << val << " at: " << read_val(tmap->get_key_type())
+      << " put: " << read_val(tmap->get_val_type());
+  indent_down();
+
+  out << "]." << endl << indent() << "iprot readMapEnd." << endl << indent() << val << "] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::list_writer(t_list* tlist, string fname) {
+  std::ostringstream out;
+  string val = temp_name();
+
+  out << "[oprot writeListBegin: (TList new elemType: " << type_to_enum(tlist->get_elem_type())
+      << "; size: " << fname << " size)." << endl;
+  indent_up();
+
+  out << indent() << fname << " do: [:" << val << "|" << endl;
+  indent_up();
+
+  out << indent() << write_val(tlist->get_elem_type(), val) << endl;
+  indent_down();
+
+  out << "]." << endl << indent() << "oprot writeListEnd] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::list_reader(t_list* tlist) {
+  std::ostringstream out;
+  string desc = temp_name();
+  string val = temp_name();
+
+  out << "[|" << desc << " " << val << "| " << desc << " := iprot readListBegin." << endl;
+  indent_up();
+
+  out << indent() << val << " := OrderedCollection new." << endl << indent() << desc
+      << " size timesRepeat: [" << endl;
+
+  indent_up();
+  out << indent() << val << " add: " << read_val(tlist->get_elem_type());
+  indent_down();
+
+  out << "]." << endl << indent() << "iprot readListEnd." << endl << indent() << val << "] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::set_writer(t_set* tset, string fname) {
+  std::ostringstream out;
+  string val = temp_name();
+
+  out << "[oprot writeSetBegin: (TSet new elemType: " << type_to_enum(tset->get_elem_type())
+      << "; size: " << fname << " size)." << endl;
+  indent_up();
+
+  out << indent() << fname << " do: [:" << val << "|" << endl;
+  indent_up();
+
+  out << indent() << write_val(tset->get_elem_type(), val) << endl;
+  indent_down();
+
+  out << "]." << endl << indent() << "oprot writeSetEnd] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::set_reader(t_set* tset) {
+  std::ostringstream out;
+  string desc = temp_name();
+  string val = temp_name();
+
+  out << "[|" << desc << " " << val << "| " << desc << " := iprot readSetBegin." << endl;
+  indent_up();
+
+  out << indent() << val << " := Set new." << endl << indent() << desc << " size timesRepeat: ["
+      << endl;
+
+  indent_up();
+  out << indent() << val << " add: " << read_val(tset->get_elem_type());
+  indent_down();
+
+  out << "]." << endl << indent() << "iprot readSetEnd." << endl << indent() << val << "] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::struct_writer(t_struct* tstruct, string sname) {
+  std::ostringstream out;
+  const vector<t_field*>& fields = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator fld_iter;
+
+  out << "[oprot writeStructBegin: "
+      << "(TStruct new name: '" + tstruct->get_name() + "')." << endl;
+  indent_up();
+
+  for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+    bool optional = (*fld_iter)->get_req() == t_field::T_OPTIONAL;
+    string fname = camelcase((*fld_iter)->get_name());
+    string accessor = sname + " " + camelcase(fname);
+
+    if (optional) {
+      out << indent() << accessor << " ifNotNil: [" << endl;
+      indent_up();
+    }
+
+    out << indent() << "oprot writeFieldBegin: (TField new name: '" << fname
+        << "'; type: " << type_to_enum((*fld_iter)->get_type())
+        << "; id: " << (*fld_iter)->get_key() << ")." << endl;
+
+    out << indent() << write_val((*fld_iter)->get_type(), accessor) << "." << endl << indent()
+        << "oprot writeFieldEnd";
+
+    if (optional) {
+      out << "]";
+      indent_down();
+    }
+
+    out << "." << endl;
+  }
+
+  out << indent() << "oprot writeFieldStop; writeStructEnd] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::struct_reader(t_struct* tstruct, string clsName = "") {
+  std::ostringstream out;
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator fld_iter;
+  string val = temp_name();
+  string desc = temp_name();
+  string found = temp_name();
+
+  if (clsName.size() == 0) {
+    clsName = tstruct->get_name();
+  }
+
+  out << "[|" << desc << " " << val << "|" << endl;
+  indent_up();
+
+  // This is nasty, but without it we'll break things by prefixing TResult.
+  string name = ((capitalize(clsName) == "TResult") ? capitalize(clsName) : prefix(clsName));
+  out << indent() << val << " := " << name << " new." << endl;
+
+  out << indent() << "iprot readStructBegin." << endl << indent() << "[" << desc
+      << " := iprot readFieldBegin." << endl << indent() << desc
+      << " type = TType stop] whileFalse: [|" << found << "|" << endl;
+  indent_up();
+
+  for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+    out << indent() << desc << " id = " << (*fld_iter)->get_key() << " ifTrue: [" << endl;
+    indent_up();
+
+    out << indent() << found << " := true." << endl << indent() << val << " "
+        << camelcase((*fld_iter)->get_name()) << ": " << read_val((*fld_iter)->get_type());
+    indent_down();
+
+    out << "]." << endl;
+  }
+
+  out << indent() << found << " ifNil: [iprot skip: " << desc << " type]]." << endl;
+  indent_down();
+
+  out << indent() << "oprot readStructEnd." << endl << indent() << val << "] value";
+  indent_down();
+
+  return out.str();
+}
+
+string t_st_generator::write_val(t_type* t, string fname) {
+  t = get_true_type(t);
+
+  if (t->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)t)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_DOUBLE:
+      return "iprot writeDouble: " + fname + " asFloat";
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      return "iprot write" + capitalize(type_name(t)) + ": " + fname + " asInteger";
+    default:
+      return "iprot write" + capitalize(type_name(t)) + ": " + fname;
+    }
+  } else if (t->is_map()) {
+    return map_writer((t_map*)t, fname);
+  } else if (t->is_struct() || t->is_xception()) {
+    return struct_writer((t_struct*)t, fname);
+  } else if (t->is_list()) {
+    return list_writer((t_list*)t, fname);
+  } else if (t->is_set()) {
+    return set_writer((t_set*)t, fname);
+  } else if (t->is_enum()) {
+    return "iprot writeI32: " + fname;
+  } else {
+    throw "Sorry, I don't know how to write this: " + type_name(t);
+  }
+}
+
+string t_st_generator::read_val(t_type* t) {
+  t = get_true_type(t);
+
+  if (t->is_base_type()) {
+    return "iprot read" + capitalize(type_name(t));
+  } else if (t->is_map()) {
+    return map_reader((t_map*)t);
+  } else if (t->is_struct() || t->is_xception()) {
+    return struct_reader((t_struct*)t);
+  } else if (t->is_list()) {
+    return list_reader((t_list*)t);
+  } else if (t->is_set()) {
+    return set_reader((t_set*)t);
+  } else if (t->is_enum()) {
+    return "iprot readI32";
+  } else {
+    throw "Sorry, I don't know how to read this: " + type_name(t);
+  }
+}
+
+void t_st_generator::generate_send_method(t_function* function) {
+  string funname = function->get_name();
+  string signature = function_signature(function);
+  t_struct* arg_struct = function->get_arglist();
+  const vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator fld_iter;
+
+  st_method(f_, client_class_name(), "send" + capitalize(signature));
+  f_ << "oprot writeMessageBegin:" << endl;
+  indent_up();
+
+  f_ << indent() << "(TCallMessage new" << endl;
+  indent_up();
+
+  f_ << indent() << "name: '" << funname << "'; " << endl << indent() << "seqid: self nextSeqid)."
+     << endl;
+  indent_down();
+  indent_down();
+
+  f_ << indent() << "oprot writeStructBegin: "
+     << "(TStruct new name: '" + capitalize(camelcase(funname)) + "_args')." << endl;
+
+  for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+    string fname = camelcase((*fld_iter)->get_name());
+
+    f_ << indent() << "oprot writeFieldBegin: (TField new name: '" << fname
+       << "'; type: " << type_to_enum((*fld_iter)->get_type()) << "; id: " << (*fld_iter)->get_key()
+       << ")." << endl;
+
+    f_ << indent() << write_val((*fld_iter)->get_type(), fname) << "." << endl << indent()
+       << "oprot writeFieldEnd." << endl;
+  }
+
+  f_ << indent() << "oprot writeFieldStop; writeStructEnd; writeMessageEnd." << endl;
+  f_ << indent() << "oprot transport flush";
+
+  st_close_method(f_);
+}
+
+// We only support receiving TResult structures (so this won't work on the server side)
+void t_st_generator::generate_recv_method(t_function* function) {
+  string funname = camelcase(function->get_name());
+  string signature = function_signature(function);
+
+  t_struct result(program_, "TResult");
+  t_field success(function->get_returntype(), "success", 0);
+  result.append(&success);
+
+  t_struct* xs = function->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) {
+    // duplicate the field, but call it "exception"... we don't need a dynamic name
+    t_field* exception = new t_field((*f_iter)->get_type(), "exception", (*f_iter)->get_key());
+    result.append(exception);
+  }
+
+  st_method(f_, client_class_name(), "recv" + capitalize(funname));
+  f_ << "| f msg res | " << endl << indent() << "msg := oprot readMessageBegin." << endl << indent()
+     << "self validateRemoteMessage: msg." << endl << indent()
+     << "res := " << struct_reader(&result) << "." << endl << indent() << "oprot readMessageEnd."
+     << endl << indent() << "oprot transport flush." << endl << indent()
+     << "res exception ifNotNil: [res exception signal]." << endl << indent() << "^ res";
+  st_close_method(f_);
+}
+
+string t_st_generator::function_types_comment(t_function* fn) {
+  std::ostringstream out;
+  const vector<t_field*>& fields = fn->get_arglist()->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  out << "\"";
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    out << camelcase((*f_iter)->get_name()) << ": " << type_name((*f_iter)->get_type());
+    if ((f_iter + 1) != fields.end()) {
+      out << ", ";
+    }
+  }
+
+  out << "\"";
+
+  return out.str();
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_st_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "TClient";
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_client = extends + "Client";
+  }
+
+  f_ << extends_client << " subclass: #" << prefix(client_class_name()) << endl
+     << "\tinstanceVariableNames: ''\n"
+     << "\tclassVariableNames: ''\n"
+     << "\tpoolDictionaries: ''\n"
+     << "\tcategory: '" << generated_category() << "'!\n\n";
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string funname = camelcase((*f_iter)->get_name());
+    string signature = function_signature(*f_iter);
+
+    st_method(f_, client_class_name(), signature);
+    f_ << function_types_comment(*f_iter) << endl << indent() << "self send"
+       << capitalize(signature) << "." << endl;
+
+    if (!(*f_iter)->is_oneway()) {
+      f_ << indent() << "^ self recv" << capitalize(funname) << " success " << endl;
+    }
+
+    st_close_method(f_);
+
+    generate_send_method(*f_iter);
+    if (!(*f_iter)->is_oneway()) {
+      generate_recv_method(*f_iter);
+    }
+  }
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_st_generator::function_signature(t_function* tfunction) {
+  return camelcase(tfunction->get_name()) + capitalize(argument_list(tfunction->get_arglist()));
+}
+
+/**
+ * Renders a field list
+ */
+string t_st_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 += " ";
+    }
+    string name = camelcase((*f_iter)->get_name());
+    result += name + ": " + name;
+  }
+  return result;
+}
+
+string t_st_generator::type_name(t_type* ttype) {
+  string prefix = "";
+  t_program* program = ttype->get_program();
+  if (program != NULL && program != program_) {
+    if (!ttype->is_service()) {
+      prefix = program->get_name() + "_types.";
+    }
+  }
+
+  string name = ttype->get_name();
+  if (ttype->is_struct() || ttype->is_xception()) {
+    name = capitalize(ttype->get_name());
+  }
+
+  return prefix + name;
+}
+
+/* Convert t_type to Smalltalk type code */
+string t_st_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 "TType string";
+    case t_base_type::TYPE_BOOL:
+      return "TType bool";
+    case t_base_type::TYPE_I8:
+      return "TType byte";
+    case t_base_type::TYPE_I16:
+      return "TType i16";
+    case t_base_type::TYPE_I32:
+      return "TType i32";
+    case t_base_type::TYPE_I64:
+      return "TType i64";
+    case t_base_type::TYPE_DOUBLE:
+      return "TType double";
+    }
+  } else if (type->is_enum()) {
+    return "TType i32";
+  } else if (type->is_struct() || type->is_xception()) {
+    return "TType struct";
+  } else if (type->is_map()) {
+    return "TType map";
+  } else if (type->is_set()) {
+    return "TType set";
+  } else if (type->is_list()) {
+    return "TType list";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+THRIFT_REGISTER_GENERATOR(st, "Smalltalk", "")
diff --git a/compiler/cpp/src/thrift/generate/t_swift_generator.cc b/compiler/cpp/src/thrift/generate/t_swift_generator.cc
new file mode 100644
index 0000000..31db04d
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_swift_generator.cc
@@ -0,0 +1,3199 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <set>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "thrift/platform.h"
+#include "thrift/generate/t_oop_generator.h"
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::set;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * Swift 3 code generator.
+ *
+ * Designed from the Swift/Cocoa code generator(s)
+ */
+class t_swift_generator : public t_oop_generator {
+public:
+  t_swift_generator(t_program* program,
+                    const map<string, string>& parsed_options,
+                    const string& option_string)
+    : t_oop_generator(program) {
+    (void)option_string;
+    map<string, string>::const_iterator iter;
+
+    log_unexpected_ = false;
+    async_clients_ = false;
+    debug_descriptions_ = false;
+    no_strict_ = false;
+    namespaced_ = false;
+    gen_cocoa_ = false;
+    promise_kit_ = false;
+    safe_enums_ = false;
+
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("log_unexpected") == 0) {
+        log_unexpected_ = true;
+      } else if( iter->first.compare("async_clients") == 0) {
+        async_clients_ = true;
+      } else if( iter->first.compare("no_strict") == 0) {
+        no_strict_ = true;
+      } else if( iter->first.compare("debug_descriptions") == 0) {
+        debug_descriptions_ = true;
+      } else if( iter->first.compare("namespaced") == 0) {
+        namespaced_ = true;
+      } else if( iter->first.compare("cocoa") == 0) {
+        gen_cocoa_ = true;
+      } else if( iter->first.compare("safe_enums") == 0) {
+        safe_enums_ = true;
+      } else if( iter->first.compare("promise_kit") == 0) {
+        if (gen_cocoa_ == false) {
+          throw "PromiseKit only available with Swift 2.x, use `cocoa` option" + iter->first;
+        }
+        promise_kit_ = true;
+      } else {
+        throw "unknown option swift:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-swift";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  void generate_consts(vector<t_const*> consts);
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_struct(t_struct* tstruct);
+  void generate_xception(t_struct* txception);
+  void generate_service(t_service* tservice);
+
+
+  void render_const_value(ostream& out,
+                          t_type* type,
+                          t_const_value* value);
+
+  void generate_swift_struct(ostream& out,
+                             t_struct* tstruct,
+                             bool is_private);
+
+  void generate_swift_struct_init(ostream& out,
+                                  t_struct* tstruct,
+                                  bool all,
+                                  bool is_private);
+
+  void generate_swift_struct_implementation(ostream& out,
+                                            t_struct* tstruct,
+                                            bool is_result,
+                                            bool is_private);
+  void generate_swift_struct_hashable_extension(ostream& out,
+                                                t_struct* tstruct,
+                                                bool is_private);
+  void generate_swift_struct_equatable_extension(ostream& out,
+                                                 t_struct* tstruct,
+                                                 bool is_private);
+  void generate_swift_struct_thrift_extension(ostream& out,
+                                              t_struct* tstruct,
+                                              bool is_result,
+                                              bool is_private);
+  void generate_swift_struct_reader(ostream& out, t_struct* tstruct, bool is_private);
+
+
+  void generate_swift_struct_printable_extension(ostream& out, t_struct* tstruct);
+  void generate_swift_union_reader(ostream& out, t_struct* tstruct);
+
+  string function_result_helper_struct_type(t_service *tservice, t_function* tfunction);
+  string function_args_helper_struct_type(t_service* tservice, t_function* tfunction);
+  void generate_function_helpers(t_service *tservice, t_function* tfunction);
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_swift_service_protocol(ostream& out, t_service* tservice);
+  void generate_swift_service_protocol_async(ostream& out, t_service* tservice);
+
+  void generate_swift_service_client(ostream& out, t_service* tservice);
+  void generate_swift_service_client_async(ostream& out, t_service* tservice);
+
+  void generate_swift_service_client_send_function_implementation(ostream& out,
+                                                                  t_service* tservice,
+                                                                  t_function* tfunction,
+                                                                  bool needs_protocol);
+  void generate_swift_service_client_send_function_invocation(ostream& out, t_function* tfunction);
+  void generate_swift_service_client_send_async_function_invocation(ostream& out,
+                                                                    t_function* tfunction);
+  void generate_swift_service_client_recv_function_implementation(ostream& out,
+                                                                  t_service* tservice,
+                                                                  t_function* tfunction,
+                                                                  bool needs_protocol);
+  void generate_swift_service_client_implementation(ostream& out, t_service* tservice);
+  void generate_swift_service_client_async_implementation(ostream& out, t_service* tservice);
+
+  void generate_swift_service_server(ostream& out, t_service* tservice);
+  void generate_swift_service_server_implementation(ostream& out, t_service* tservice);
+  void generate_swift_service_helpers(t_service* tservice);
+
+  /**
+   * Helper rendering functions
+   */
+
+  string swift_imports();
+  string swift_thrift_imports();
+  string type_name(t_type* ttype, bool is_optional=false, bool is_forced=false);
+  string base_type_name(t_base_type* tbase);
+  string declare_property(t_field* tfield, bool is_private);
+  string function_signature(t_function* tfunction);
+  string async_function_signature(t_function* tfunction);
+
+
+  string argument_list(t_struct* tstruct, string protocol_name, bool is_internal);
+  string type_to_enum(t_type* ttype, bool qualified=false);
+  string maybe_escape_identifier(const string& identifier);
+  void populate_reserved_words();
+  /** Swift 3 specific */
+  string enum_case_name(t_enum_value* tenum_case, bool declaration);
+  string enum_const_name(string enum_identifier);
+  void function_docstring(ostream& out, t_function* tfunction);
+  void async_function_docstring(ostream& out, t_function* tfunction);
+  void generate_docstring(ostream& out, string& doc);
+
+  /** Swift 2/Cocoa carryover */
+  string promise_function_signature(t_function* tfunction);
+  string function_name(t_function* tfunction);
+  void generate_old_swift_struct_writer(ostream& out,t_struct* tstruct, bool is_private);
+  void generate_old_swift_struct_result_writer(ostream& out, t_struct* tstruct);
+
+  /** Swift 2/Cocoa backwards compatibility*/
+  void generate_old_enum(t_enum* tenum);
+  void generate_old_swift_struct(ostream& out,
+                                 t_struct* tstruct,
+                                 bool is_private);
+  void generate_old_swift_service_client_async_implementation(ostream& out,
+                                                              t_service* tservice);
+
+  static std::string get_real_swift_module(const t_program* program) {
+    std::string real_module = program->get_namespace("swift");
+    if (real_module.empty()) {
+      return program->get_name();
+    }
+    return real_module;
+  }
+private:
+
+  void block_open(ostream& out) {
+    out << " {" << endl;
+    indent_up();
+  }
+
+  void block_close(ostream& out, bool end_line=true) {
+    indent_down();
+    indent(out) << "}";
+    if (end_line) out << endl;
+  }
+
+  bool field_is_optional(t_field* tfield) {
+    bool opt = tfield->get_req() == t_field::T_OPTIONAL;
+    if (tfield->annotations_.find("swift.nullable") != tfield->annotations_.end() && tfield->get_req() != t_field::T_REQUIRED) {
+      opt = true;
+    }
+    if (gen_cocoa_) { // Backwards compatibility, only if its actually "optional"
+      opt = tfield->get_req() == t_field::T_OPTIONAL;
+    }
+    return opt;
+  }
+
+  bool struct_has_required_fields(t_struct* tstruct) {
+    const vector<t_field*>& members = tstruct->get_members();
+    vector<t_field*>::const_iterator m_iter;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (!field_is_optional(*m_iter)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool struct_has_optional_fields(t_struct* tstruct) {
+    const vector<t_field*>& members = tstruct->get_members();
+    vector<t_field*>::const_iterator m_iter;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      if (field_is_optional(*m_iter)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  string constants_declarations_;
+
+  /**
+   * File streams
+   */
+
+  ofstream_with_content_based_conditional_update f_decl_;
+  ofstream_with_content_based_conditional_update f_impl_;
+
+  bool log_unexpected_;
+  bool async_clients_;
+
+  bool debug_descriptions_;
+  bool no_strict_;
+  bool namespaced_;
+  bool safe_enums_;
+  set<string> swift_reserved_words_;
+
+  /** Swift 2/Cocoa compatibility */
+  bool gen_cocoa_;
+  bool promise_kit_;
+
+};
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ */
+void t_swift_generator::init_generator() {
+  // Make output directory
+  string module = get_real_swift_module(program_);
+  string out_dir = get_out_dir();
+  string module_path = out_dir;
+  string name = program_name_;
+  if (namespaced_ && !module.empty()) {
+    module_path = module_path + "/" + module;
+    name = module;
+  }
+  MKDIR(module_path.c_str());
+
+  populate_reserved_words();
+
+  // we have a .swift declarations file...
+  string f_decl_name = name + ".swift";
+  string f_decl_fullname = module_path + "/" + f_decl_name;
+  f_decl_.open(f_decl_fullname.c_str());
+
+  f_decl_ << autogen_comment() << endl;
+
+  f_decl_ << swift_imports() << swift_thrift_imports() << endl;
+
+  // ...and a .swift implementation extensions file
+  string f_impl_name = name + "+Exts.swift";
+  string f_impl_fullname = module_path + "/" + f_impl_name;
+  f_impl_.open(f_impl_fullname.c_str());
+
+  f_impl_ << autogen_comment() << endl;
+
+  f_impl_ << swift_imports() << swift_thrift_imports() << endl;
+
+}
+
+/**
+ * Prints standard Cocoa imports
+ *
+ * @return List of imports for Cocoa libraries
+ */
+string t_swift_generator::swift_imports() {
+
+  vector<string> includes_list;
+  includes_list.push_back("Foundation");
+
+  ostringstream includes;
+
+  vector<string>::const_iterator i_iter;
+  for (i_iter=includes_list.begin(); i_iter!=includes_list.end(); ++i_iter) {
+    includes << "import " << *i_iter << endl;
+  }
+
+  if (namespaced_) {
+    const vector<t_program*>& program_includes = program_->get_includes();
+    for (size_t i = 0; i < program_includes.size(); ++i) {
+      includes << ("import " + get_real_swift_module(program_includes[i])) << endl;
+    }
+  }
+  includes << endl;
+
+  return includes.str();
+}
+
+/**
+ * Prints Thrift runtime imports
+ *
+ * @return List of imports necessary for Thrift runtime
+ */
+string t_swift_generator::swift_thrift_imports() {
+
+  vector<string> includes_list;
+  includes_list.push_back("Thrift");
+
+  if (gen_cocoa_ && promise_kit_) {
+    includes_list.push_back("PromiseKit");
+  }
+
+  ostringstream includes;
+
+  vector<string>::const_iterator i_iter;
+  for (i_iter=includes_list.begin(); i_iter!=includes_list.end(); ++i_iter) {
+    includes << "import " << *i_iter << endl;
+  }
+
+  includes << endl;
+
+  return includes.str();
+}
+
+/**
+ * Finish up generation.
+ */
+void t_swift_generator::close_generator() {
+  // stick our constants declarations at the end of the header file
+  // since they refer to things we are defining.
+  f_decl_ << constants_declarations_ << endl;
+}
+
+/**
+ * Generates a typedef. This is just a simple 1-liner in Swift
+ *
+ * @param ttypedef The type definition
+ */
+void t_swift_generator::generate_typedef(t_typedef* ttypedef) {
+  f_decl_ << indent() << "public typealias " << ttypedef->get_symbolic()
+          << " = " << type_name(ttypedef->get_type()) << endl;
+  f_decl_ << endl;
+}
+
+
+/**
+ * Generates code for an enumerated type. In Swift, this is
+ * essentially the same as the thrift definition itself, using
+ * Swift syntax.  Conforms to TEnum which
+ * implementes read/write.
+ *
+ * @param tenum The enumeration
+ */
+void t_swift_generator::generate_enum(t_enum* tenum) {
+  if (gen_cocoa_) {
+    generate_old_enum(tenum);
+    return;
+  }
+  f_decl_ << indent() << "public enum " << tenum->get_name() << " : TEnum";
+  block_open(f_decl_);
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    f_decl_ << indent() << "case " << enum_case_name((*c_iter), true) << endl;
+  }
+
+  // unknown associated value case for safety and similar behavior to other languages
+  if (safe_enums_) {
+    f_decl_ << indent() << "case unknown(Int32)" << endl;
+  }
+  f_decl_ << endl;
+
+  // TSerializable read(from:)
+  f_decl_ << indent() << "public static func read(from proto: TProtocol) throws -> "
+          << tenum->get_name();
+  block_open(f_decl_);
+  f_decl_ << indent() << "let raw: Int32 = try proto.read()" << endl;
+  f_decl_ << indent() << "let new = " << tenum->get_name() << "(rawValue: raw)" << endl;
+
+  f_decl_ << indent() << "if let unwrapped = new {" << endl;
+  indent_up();
+  f_decl_ << indent() << "return unwrapped" << endl;
+  indent_down();
+  f_decl_ << indent() << "} else {" << endl;
+  indent_up();
+  f_decl_ << indent() << "throw TProtocolError(error: .invalidData," << endl;
+  f_decl_ << indent() << "                     message: \"Invalid enum value (\\(raw)) for \\("
+          << tenum->get_name() << ".self)\")" << endl;
+  indent_down();
+  f_decl_ << indent() << "}" << endl;
+  block_close(f_decl_);
+
+  // empty init for TSerializable
+  f_decl_ << endl;
+  f_decl_ << indent() << "public init()";
+  block_open(f_decl_);
+
+  f_decl_ << indent() << "self = ." << enum_case_name(constants.front(), false) << endl;
+  block_close(f_decl_);
+  f_decl_ << endl;
+
+  // rawValue getter
+  f_decl_ << indent() << "public var rawValue: Int32";
+  block_open(f_decl_);
+  f_decl_ << indent() << "switch self {" << endl;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    f_decl_ << indent() << "case ." << enum_case_name((*c_iter), true)
+            << ": return " << (*c_iter)->get_value() << endl;
+  }
+  if (safe_enums_) {
+    f_decl_ << indent() << "case .unknown(let value): return value" << endl;
+  }
+  f_decl_ << indent() << "}" << endl;
+  block_close(f_decl_);
+  f_decl_ << endl;
+
+  // convenience rawValue initalizer
+  f_decl_ << indent() << "public init?(rawValue: Int32)";
+  block_open(f_decl_);
+  f_decl_ << indent() << "switch rawValue {" << endl;;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    f_decl_ << indent() << "case " << (*c_iter)->get_value()
+            << ": self = ." << enum_case_name((*c_iter), true) << endl;
+  }
+  if (!safe_enums_) {
+    f_decl_ << indent() << "default: return nil" << endl;
+  } else {
+    f_decl_ << indent() << "default: self = .unknown(rawValue)" << endl;
+  }
+  f_decl_ << indent() << "}" << endl;
+  block_close(f_decl_);
+
+
+
+
+  block_close(f_decl_);
+  f_decl_ << endl;
+}
+
+/**
+ * Generates code for an enumerated type. This is for Swift 2.x/Cocoa
+ * backwards compatibility
+ *
+ * @param tenum The enumeration
+ */
+void t_swift_generator::generate_old_enum(t_enum* tenum) {
+  f_decl_ << indent() << "public enum " << tenum->get_name() << " : Int32";
+  block_open(f_decl_);
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    f_decl_ << indent() << "case " << (*c_iter)->get_name()
+            << " = " << (*c_iter)->get_value() << endl;
+  }
+
+  f_decl_ << endl;
+  f_decl_ << indent() << "public init() { self.init(rawValue: " << constants.front()->get_value() << ")! }" << endl;
+
+  block_close(f_decl_);
+  f_decl_ << endl;
+
+  f_impl_ << indent() << "extension " << tenum->get_name() << " : TEnum";
+  block_open(f_impl_);
+
+  f_impl_ << endl;
+
+  f_impl_ << indent() << "public static func readValueFromProtocol(proto: TProtocol) throws -> " << tenum->get_name();
+  block_open(f_impl_);
+  f_impl_ << indent() << "var raw = Int32()" << endl
+          << indent() << "try proto.readI32(&raw)" << endl
+          << indent() << "return " << tenum->get_name() << "(rawValue: raw)!" << endl;
+  block_close(f_impl_);
+  f_impl_ << endl;
+
+  f_impl_ << indent() << "public static func writeValue(value: " << tenum->get_name() << ", toProtocol proto: TProtocol) throws";
+  block_open(f_impl_);
+  f_impl_ << indent() << "try proto.writeI32(value.rawValue)" << endl;
+  block_close(f_impl_);
+  f_impl_ << endl;
+
+  block_close(f_impl_);
+  f_impl_ << endl;
+}
+
+string t_swift_generator::enum_case_name(t_enum_value* tenum_case, bool declaration) {
+  string name = tenum_case->get_name();
+  // force to lowercase for Swift style, maybe escape if its a keyword
+  std::transform(name.begin(), name.end(), name.begin(), ::tolower);
+  if (declaration) {
+    name = maybe_escape_identifier(name);
+  }
+  return name;
+}
+
+/**
+ * Renders a constant enum value by transforming the value portion to lowercase
+ * for Swift style.
+ */
+string t_swift_generator::enum_const_name(string enum_identifier) {
+  string::iterator it;
+  for (it = enum_identifier.begin(); it < enum_identifier.end(); ++it) {
+    if ((*it) == '.') {
+      break;
+    }
+  }
+  std::transform(it, enum_identifier.end(), it, ::tolower);
+  return enum_identifier;
+}
+
+/**
+ * Generates public constants for all Thrift constants.
+ *
+ * @param consts Constants to generate
+ */
+void t_swift_generator::generate_consts(vector<t_const*> consts) {
+
+  ostringstream const_interface;
+
+  // Public constants for base types & strings
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    t_type* type = (*c_iter)->get_type();
+    const_interface << "public let " << capitalize((*c_iter)->get_name()) << " : " << type_name(type) << " = ";
+    render_const_value(const_interface, type, (*c_iter)->get_value());
+    const_interface << endl << endl;
+  }
+
+  // this gets spit into the header file in ::close_generator
+  constants_declarations_ = const_interface.str();
+
+}
+
+/**
+ * Generates a struct definition for a thrift data type. This is a struct
+ * with public members. Optional types are used for optional properties to
+ * allow them to be tested for availability. Separate inits are included for
+ * required properties & all properties.
+ *
+ * Generates extensions to provide conformance to TStruct, TSerializable,
+ * Hashable & Equatable
+ *
+ * @param tstruct The struct definition
+ */
+void t_swift_generator::generate_struct(t_struct* tstruct) {
+  generate_swift_struct(f_decl_, tstruct, false);
+  generate_swift_struct_implementation(f_impl_, tstruct, false, false);
+}
+
+/**
+ * Exceptions are structs, but they conform to Error
+ *
+ * @param tstruct The struct definition
+ */
+void t_swift_generator::generate_xception(t_struct* txception) {
+  generate_swift_struct(f_decl_, txception, false);
+  generate_swift_struct_implementation(f_impl_, txception, false, false);
+}
+
+void t_swift_generator::generate_docstring(ostream& out, string& doc) {
+  if (doc != "") {
+    std::vector<std::string> strings;
+
+    std::string::size_type pos = 0;
+    std::string::size_type prev = 0;
+    while (((pos = doc.find("\n", prev)) != std::string::npos)
+        || ((pos = doc.find("\r", prev)) != std::string::npos)
+        || ((pos = doc.find("\r\n", prev)) != std::string::npos))
+    {
+        strings.push_back(doc.substr(prev, pos - prev));
+        prev = pos + 1;
+    }
+
+    // To get the last substring (or only, if delimiter is not found)
+    strings.push_back(doc.substr(prev));
+
+    vector<string>::const_iterator d_iter;
+    for (d_iter = strings.begin(); d_iter != strings.end(); ++d_iter) {
+      if ((*d_iter) != "") {
+        out << indent() << "/// " << (*d_iter) << endl;
+      }
+    }
+  }
+}
+
+
+
+/**
+ * Generate the interface for a struct. Only properties and
+ * init methods are included.
+ *
+ * @param tstruct The struct definition
+ * @param is_private
+ *                Is the struct public or private
+ */
+void t_swift_generator::generate_swift_struct(ostream& out,
+                                              t_struct* tstruct,
+                                              bool is_private) {
+
+  if (gen_cocoa_) {
+    generate_old_swift_struct(out, tstruct, is_private);
+    return;
+  }
+  string doc = tstruct->get_doc();
+  generate_docstring(out, doc);
+
+
+  // properties
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+
+  if (tstruct->is_union()) {
+    // special, unions
+    out << indent() << "public enum " << tstruct->get_name();
+    block_open(out);
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      out << endl;
+      string doc = (*m_iter)->get_doc();
+      generate_docstring(out, doc);
+      out << indent() << "case "
+          << maybe_escape_identifier((*m_iter)->get_name()) << "(val: "
+          << type_name((*m_iter)->get_type(), false) << ")" << endl;
+    }
+  } else {
+    // Normal structs
+
+    string visibility = is_private ? (gen_cocoa_ ? "private" : "fileprivate") : "public";
+
+    out << indent() << visibility << " final class " << tstruct->get_name();
+
+    if (tstruct->is_xception()) {
+      out << " : Swift.Error"; // Error seems to be a common exception name in thrift
+    }
+
+    block_open(out);
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      out << endl;
+      // TODO: Defaults
+
+      string doc = (*m_iter)->get_doc();
+      generate_docstring(out, doc);
+
+      out << indent() << declare_property(*m_iter, is_private) << endl;
+    }
+
+    out << endl;
+    out << endl;
+
+    if (!struct_has_required_fields(tstruct)) {
+      indent(out) << visibility << " init() { }" << endl;
+    }
+    if (struct_has_required_fields(tstruct)) {
+      generate_swift_struct_init(out, tstruct, false, is_private);
+    }
+    if (struct_has_optional_fields(tstruct)) {
+      generate_swift_struct_init(out, tstruct, true, is_private);
+    }
+  }
+
+  block_close(out);
+
+  out << endl;
+}
+
+/**
+ * Legacy Swift2/Cocoa generator
+ *
+ * @param tstruct
+ * @param is_private
+ */
+
+
+void t_swift_generator::generate_old_swift_struct(ostream& out,
+                                                  t_struct* tstruct,
+                                                  bool is_private) {
+  string visibility = is_private ? "private" : "public";
+
+  out << indent() << visibility << " final class " << tstruct->get_name();
+
+  if (tstruct->is_xception()) {
+    out << " : ErrorType";
+  }
+
+  block_open(out);
+
+  // properties
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    out << endl;
+    out << indent() << declare_property(*m_iter, is_private) << endl;
+  }
+
+  out << endl;
+
+  // init
+
+  indent(out) << visibility << " init()";
+  block_open(out);
+  block_close(out);
+
+  out << endl;
+
+  if (struct_has_required_fields(tstruct)) {
+    generate_swift_struct_init(out, tstruct, false, is_private);
+  }
+  if (struct_has_optional_fields(tstruct)) {
+    generate_swift_struct_init(out, tstruct, true, is_private);
+  }
+
+  block_close(out);
+
+  out << endl;
+}
+
+/**
+ * Generate struct init for properties
+ *
+ * @param tstruct The structure definition
+ * @param all     Generate init with all or just required properties
+ * @param is_private
+ *                Is the initializer public or private
+ */
+void t_swift_generator::generate_swift_struct_init(ostream& out,
+                                                   t_struct* tstruct,
+                                                   bool all,
+                                                   bool is_private) {
+
+  string visibility = is_private ? (gen_cocoa_ ? "private" : "fileprivate") : "public";
+
+  indent(out) << visibility << " init(";
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  bool first=true;
+  for (m_iter = members.begin(); m_iter != members.end();) {
+    if (all || !field_is_optional(*m_iter)) {
+      if (first) {
+        first = false;
+      }
+      else {
+        out << ", ";
+      }
+      out << (*m_iter)->get_name() << ": "
+          << maybe_escape_identifier(type_name((*m_iter)->get_type(), field_is_optional(*m_iter)));
+    }
+    ++m_iter;
+  }
+  out << ")";
+
+  block_open(out);
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if (!gen_cocoa_) {
+      bool should_set = all;
+      should_set = should_set || !field_is_optional((*m_iter));
+      if (should_set) {
+        out << indent() << "self." << maybe_escape_identifier((*m_iter)->get_name()) << " = "
+            << maybe_escape_identifier((*m_iter)->get_name()) << endl;
+      }
+    } else {
+      /** legacy Swift2/Cocoa */
+      if (all || (*m_iter)->get_req() == t_field::T_REQUIRED || (*m_iter)->get_req() == t_field::T_OPT_IN_REQ_OUT) {
+        out << indent() << "self." << maybe_escape_identifier((*m_iter)->get_name()) << " = "
+            << maybe_escape_identifier((*m_iter)->get_name()) << endl;
+      }
+    }
+  }
+
+  block_close(out);
+
+  out << endl;
+}
+
+/**
+ * Generate the hashable protocol implmentation
+ *
+ * @param tstruct The structure definition
+ * @param is_private
+ *                Is the struct public or private
+ */
+void t_swift_generator::generate_swift_struct_hashable_extension(ostream& out,
+                                                                 t_struct* tstruct,
+                                                                 bool is_private) {
+
+  string visibility = is_private ? (gen_cocoa_ ? "private" : "fileprivate") : "public";
+  indent(out) << "extension " << tstruct->get_name() << " : Hashable";
+  block_open(out);
+  out << endl;
+  indent(out) << visibility << " var hashValue : Int";
+  block_open(out);
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  if (!members.empty()) {
+    indent(out) << "let prime = 31" << endl;
+    indent(out) << "var result = 1" << endl;
+    if (!tstruct->is_union()) {
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        t_field* tfield = *m_iter;
+        string accessor = field_is_optional(tfield) ? "?." : ".";
+        string defaultor = field_is_optional(tfield) ? " ?? 0" : "";
+        indent(out) << "result = prime &* result &+ (" << maybe_escape_identifier(tfield->get_name()) << accessor
+                    <<  "hashValue" << defaultor << ")" << endl;
+      }
+    } else {
+      indent(out) << "switch self {" << endl;
+      for (m_iter = members.begin(); m_iter != members.end(); m_iter++) {
+        t_field *tfield = *m_iter;
+        indent(out) << "case ." << tfield->get_name() << "(let val): result = prime &* val.hashValue" << endl;
+      }
+      indent(out) << "}" << endl << endl;
+    }
+    indent(out) << "return result" << endl;
+  }
+  else {
+    indent(out) << "return 31" << endl;
+  }
+
+  block_close(out);
+  out << endl;
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generate the equatable protocol implementation
+ *
+ * @param tstruct The structure definition
+ * @param is_private
+ *                Is the struct public or private
+ */
+void t_swift_generator::generate_swift_struct_equatable_extension(ostream& out,
+                                                                  t_struct* tstruct,
+                                                                  bool is_private) {
+
+  string visibility = is_private ? (gen_cocoa_ ? "private" : "fileprivate") : "public";
+
+  indent(out) << visibility << " func ==(lhs: " << type_name(tstruct) << ", rhs: "
+              << type_name(tstruct) << ") -> Bool";
+  block_open(out);
+  indent(out) << "return";
+
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  if (members.size()) {
+    if (!tstruct->is_union()) {
+      out << endl;
+      indent_up();
+
+      for (m_iter = members.begin(); m_iter != members.end();) {
+        t_field* tfield = *m_iter;
+        indent(out) << "(lhs." << maybe_escape_identifier(tfield->get_name())
+                    << (gen_cocoa_ ? " ?" : " ") << "== rhs." << maybe_escape_identifier(tfield->get_name()) << ")"; // swift 2 ?== operator not in 3?
+        if (++m_iter != members.end()) {
+          out << " &&";
+        }
+        out << endl;
+      }
+      indent_down();
+    } else {
+      block_open(out);
+      indent(out) << "switch (lhs, rhs) {" << endl;
+      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+        t_field* tfield = *m_iter;
+        indent(out) << "case (." << tfield->get_name() << "(let lval), ."
+                    << tfield->get_name() << "(let rval)): return lval == rval"
+                    << endl;
+      }
+      indent(out) << "default: return false" << endl;
+      indent(out) << "}" << endl;
+      indent_down();
+      indent(out) << "}()" << endl;
+    }
+  }
+  else {
+    out << " true" << endl;
+  }
+
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generate struct implementation. Produces extensions that
+ * fulfill the requisite protocols to complete the value.
+ *
+ * @param tstruct The struct definition
+ * @param is_result
+ *                If this is a result it needs a different writer
+ * @param is_private
+ *                Is the struct public or private
+ */
+void t_swift_generator::generate_swift_struct_implementation(ostream& out,
+                                                             t_struct* tstruct,
+                                                             bool is_result,
+                                                             bool is_private) {
+
+  generate_swift_struct_equatable_extension(out, tstruct, is_private);
+
+  if (!is_private && !is_result && !gen_cocoa_) {  // old compiler didn't use debug_descriptions, OR it with gen_cocoa_ so the flag doesn't matter w/ cocoa
+    generate_swift_struct_printable_extension(out, tstruct);
+  }
+
+  generate_swift_struct_hashable_extension(out, tstruct, is_private);
+  generate_swift_struct_thrift_extension(out, tstruct, is_result, is_private);
+
+  out << endl << endl;
+}
+
+/**
+ * Generate the TStruct protocol implementation.
+ *
+ * @param tstruct The structure definition
+ * @param is_result
+ *                Is the struct a result value
+ * @param is_private
+ *                Is the struct public or private
+ */
+void t_swift_generator::generate_swift_struct_thrift_extension(ostream& out,
+                                                               t_struct* tstruct,
+                                                               bool is_result,
+                                                               bool is_private) {
+
+  indent(out) << "extension " << tstruct->get_name() << " : TStruct";
+
+  block_open(out);
+
+  out << endl;
+  if (!gen_cocoa_) {
+    /** Swift 3, no writer we just write field ID's */
+    string access = (is_private) ? (gen_cocoa_ ? "private" : "fileprivate") : "public";
+    // generate fieldID's dictionary
+    out << indent() << access << " static var fieldIds: [String: Int32]";
+    block_open(out);
+    out << indent() << "return [";
+    const vector<t_field*>& fields = tstruct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    bool wrote = false;
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      wrote = true;
+      out << "\"" << (*f_iter)->get_name() << "\": " << (*f_iter)->get_key() << ", ";
+    }
+    if (!wrote) {
+      // pad a colon
+      out << ":";
+    }
+    out << "]" << endl;
+    block_close(out);
+    out << endl;
+    out << indent() << access << " static var structName: String { return \""
+        << tstruct->get_name() << "\" }" << endl << endl;
+
+    if (tstruct->is_union()) {
+      generate_swift_union_reader(out, tstruct);
+    } else {
+      generate_swift_struct_reader(out, tstruct, is_private);
+    }
+  } else {
+    /** Legacy Swift2/Cocoa */
+
+    generate_swift_struct_reader(out, tstruct, is_private);
+
+    if (is_result) {
+      generate_old_swift_struct_result_writer(out, tstruct);
+    }
+    else {
+      generate_old_swift_struct_writer(out, tstruct, is_private);
+    }
+  }
+
+  block_close(out);
+  out << endl;
+}
+
+void t_swift_generator::generate_swift_union_reader(ostream& out, t_struct* tstruct) {
+  indent(out) << "public static func read(from proto: TProtocol) throws -> "
+              << tstruct->get_name();
+  block_open(out);
+  indent(out) << "_ = try proto.readStructBegin()" << endl;
+
+  indent(out) << "var ret: " << tstruct->get_name() << "?";
+  out << endl;
+  indent(out) << "fields: while true";
+  block_open(out);
+  out << endl;
+  indent(out) << "let (_, fieldType, fieldID) = try proto.readFieldBegin()" << endl << endl;
+  indent(out) << "switch (fieldID, fieldType)";
+  block_open(out);
+  indent(out) << "case (_, .stop):            break fields" << endl;
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(out) << "case (" << (*f_iter)->get_key() << ", " << type_to_enum((*f_iter)->get_type()) << "):";
+    string padding = "";
+
+    t_type* type = get_true_type((*f_iter)->get_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_STRING:
+        case t_base_type::TYPE_DOUBLE:
+          padding = "           ";
+          break;
+
+        case t_base_type::TYPE_BOOL:
+        case t_base_type::TYPE_I8:
+          padding = "            ";
+          break;
+        case t_base_type::TYPE_I16:
+        case t_base_type::TYPE_I32:
+        case t_base_type::TYPE_I64:
+          padding = "             ";
+          break;
+        default: break;
+      }
+    } else if (type->is_enum() || type->is_set() || type->is_map()) {
+      padding = "             ";
+    } else if (type->is_struct() || type->is_xception()) {
+      padding = "           ";
+    } else if (type->is_list()) {
+      padding = "            ";
+    }
+
+    indent(out) << padding << "ret = " << tstruct->get_name() << "."
+                << (*f_iter)->get_name() << "(val: " << "try "
+                << type_name((*f_iter)->get_type(), false, false)
+                << ".read(from: proto))" << endl;
+  }
+
+  indent(out) << "case let (_, unknownType):  try proto.skip(type: unknownType)" << endl;
+
+  block_close(out);
+  indent(out) << "try proto.readFieldEnd()" << endl;
+
+  block_close(out);
+  out << endl;
+
+  indent(out) << "try proto.readStructEnd()" << endl;
+
+  indent(out) << "if let ret = ret";
+  block_open(out);
+  indent(out) << "return ret" << endl;
+  block_close(out);
+  out << endl;
+  indent(out) << "throw TProtocolError(error: .unknown, message: \"Missing required value for type: "
+              << tstruct->get_name() << "\")";
+  block_close(out);
+  out << endl;
+
+}
+
+/**
+ * Generates a function to read a struct from
+ * from a protocol. (TStruct compliance)
+ *
+ * @param tstruct The structure definition
+ * @param is_private
+ *                Is the struct public or private
+ */
+void t_swift_generator::generate_swift_struct_reader(ostream& out,
+                                                     t_struct* tstruct,
+                                                     bool is_private) {
+
+  if (!gen_cocoa_) {
+    /** Swift 3 case */
+    string visibility = is_private ? "fileprivate" : "public";
+
+    indent(out) << visibility << " static func read(from proto: TProtocol) throws -> "
+               << tstruct->get_name();
+
+    block_open(out);
+    indent(out) << "_ = try proto.readStructBegin()" << endl;
+
+    const vector<t_field*>& fields = tstruct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      bool optional = field_is_optional(*f_iter);
+      indent(out) << "var " << maybe_escape_identifier((*f_iter)->get_name()) << ": "
+                  << type_name((*f_iter)->get_type(), optional, !optional) << endl;
+    }
+
+    out << endl;
+
+    // Loop over reading in fields
+    indent(out) << "fields: while true";
+    block_open(out);
+    out << endl;
+
+    indent(out) << "let (_, fieldType, fieldID) = try proto.readFieldBegin()" << endl << endl;
+    indent(out) << "switch (fieldID, fieldType)";
+    block_open(out);
+    indent(out) << "case (_, .stop):            break fields" << endl;
+
+
+    // Generate deserialization code for known cases
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      indent(out) << "case (" << (*f_iter)->get_key() << ", " << type_to_enum((*f_iter)->get_type()) << "):";
+      string padding = "";
+
+      t_type* type = get_true_type((*f_iter)->get_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_STRING:
+          case t_base_type::TYPE_DOUBLE:
+            padding = "           ";
+          break;
+
+          case t_base_type::TYPE_BOOL:
+          case t_base_type::TYPE_I8:
+            padding = "            ";
+          break;
+          case t_base_type::TYPE_I16:
+          case t_base_type::TYPE_I32:
+          case t_base_type::TYPE_I64:
+            padding = "             ";
+          break;
+          default: break;
+        }
+      } else if (type->is_enum() || type->is_set() || type->is_map()) {
+        padding = "             ";
+      } else if (type->is_struct() || type->is_xception()) {
+        padding = "           ";
+      } else if (type->is_list()) {
+        padding = "            ";
+      }
+
+      out << padding << maybe_escape_identifier((*f_iter)->get_name()) << " = try "
+          << type_name((*f_iter)->get_type(), false, false) << ".read(from: proto)" << endl;
+    }
+
+    indent(out) << "case let (_, unknownType):  try proto.skip(type: unknownType)" << endl;
+    block_close(out);
+    out << endl;
+
+    // Read field end marker
+    indent(out) << "try proto.readFieldEnd()" << endl;
+    block_close(out);
+    out << endl;
+    indent(out) << "try proto.readStructEnd()" << endl;
+
+    if (struct_has_required_fields(tstruct)) {
+      // performs various checks (e.g. check that all required fields are set)
+      indent(out) << "// Required fields" << endl;
+
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if (field_is_optional(*f_iter)) {
+          continue;
+        }
+        indent(out) << "try proto.validateValue(" << (*f_iter)->get_name() << ", "
+                    << "named: \"" << (*f_iter)->get_name() << "\")" << endl;
+      }
+    }
+
+    out << endl;
+
+    indent(out) << "return " << tstruct->get_name() << "(";
+    for (f_iter = fields.begin(); f_iter != fields.end();) {
+      out << (*f_iter)->get_name() << ": " << maybe_escape_identifier((*f_iter)->get_name());
+      if (++f_iter != fields.end()) {
+        out << ", ";
+      }
+    }
+
+  } else {
+    /** Legacy Swif2/Cocoa case */
+    string visibility = is_private ? "private" : "public";
+
+    indent(out) << visibility << " static func readValueFromProtocol(__proto: TProtocol) throws -> "
+                << tstruct->get_name();
+
+    block_open(out);
+    out << endl;
+    indent(out) << "try __proto.readStructBegin()" << endl << endl;
+
+    const vector<t_field*>& fields = tstruct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+      bool optional = field_is_optional(*f_iter);
+      indent(out) << "var " << maybe_escape_identifier((*f_iter)->get_name()) << " : "
+                  << type_name((*f_iter)->get_type(), optional, !optional) << endl;
+    }
+
+    out << endl;
+
+    // Loop over reading in fields
+    indent(out) << "fields: while true";
+    block_open(out);
+    out << endl;
+
+    indent(out) << "let (_, fieldType, fieldID) = try __proto.readFieldBegin()" << endl << endl;
+    indent(out) << "switch (fieldID, fieldType)";
+
+    block_open(out);
+
+    indent(out) << "case (_, .STOP):" << endl;
+    indent_up();
+    indent(out) << "break fields" << endl << endl;
+    indent_down();
+
+    // Generate deserialization code for known cases
+    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+
+      indent(out) << "case (" << (*f_iter)->get_key() << ", " << type_to_enum((*f_iter)->get_type()) << "):" << endl;
+      indent_up();
+      indent(out) << maybe_escape_identifier((*f_iter)->get_name()) << " = try __proto.readValue() as "
+                  << type_name((*f_iter)->get_type()) << endl << endl;
+      indent_down();
+
+    }
+
+    indent(out) << "case let (_, unknownType):" << endl;
+    indent_up();
+    indent(out) << "try __proto.skipType(unknownType)" << endl;
+    indent_down();
+    block_close(out);
+    out << endl;
+
+    // Read field end marker
+    indent(out) << "try __proto.readFieldEnd()" << endl;
+
+    block_close(out);
+    out << endl;
+    indent(out) << "try __proto.readStructEnd()" << endl;
+    out << endl;
+
+    if (struct_has_required_fields(tstruct)) {
+      // performs various checks (e.g. check that all required fields are set)
+      indent(out) << "// Required fields" << endl;
+
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if (field_is_optional(*f_iter)) {
+          continue;
+        }
+        indent(out) << "try __proto.validateValue(" << (*f_iter)->get_name() << ", "
+                    << "named: \"" << (*f_iter)->get_name() << "\")" << endl;
+      }
+    }
+
+    out << endl;
+
+    indent(out) << "return " << tstruct->get_name() << "(";
+    for (f_iter = fields.begin(); f_iter != fields.end();) {
+      out << (*f_iter)->get_name() << ": " << maybe_escape_identifier((*f_iter)->get_name());
+      if (++f_iter != fields.end()) {
+        out << ", ";
+      }
+    }
+  }
+  out << ")" << endl;
+
+  block_close(out);
+
+  out << endl;
+}
+
+/**
+ * Generates a function to write a struct to
+ * a protocol. (TStruct compliance) ONLY FOR SWIFT2/COCOA
+ *
+ * @param tstruct The structure definition
+ * @param is_private
+ *                Is the struct public or private
+ */
+void t_swift_generator::generate_old_swift_struct_writer(ostream& out,
+                                                         t_struct* tstruct,
+                                                         bool is_private) {
+
+  string visibility = is_private ? "private" : "public";
+
+  indent(out) << visibility << " static func writeValue(__value: " << tstruct->get_name()
+              << ", toProtocol __proto: TProtocol) throws";
+  block_open(out);
+  out << endl;
+
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "try __proto.writeStructBeginWithName(\"" << name << "\")" << endl;
+  out << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field *tfield = *f_iter;
+
+    bool optional = field_is_optional(tfield);
+    if (optional) {
+      indent(out) << "if let " << maybe_escape_identifier(tfield->get_name())
+                  << " = __value." << maybe_escape_identifier(tfield->get_name());
+      block_open(out);
+    }
+
+    indent(out) << "try __proto.writeFieldValue("
+                << (optional ? "" : "__value.") << maybe_escape_identifier(tfield->get_name()) << ", "
+                << "name: \"" << tfield->get_name() << "\", "
+                << "type: " << type_to_enum(tfield->get_type()) << ", "
+                << "id: " << tfield->get_key() << ")" << endl;
+
+    if (optional) {
+      block_close(out);
+    }
+
+    out << endl;
+  }
+
+  indent(out) << "try __proto.writeFieldStop()" << endl << endl;
+  indent(out) << "try __proto.writeStructEnd()" << endl;
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generates a function to read a struct from
+ * from a protocol. (TStruct compliance)  ONLY FOR SWIFT 2/COCOA
+ *
+ * This is specifically a function result. Only
+ * the first available field is written.
+ *
+ * @param tstruct The structure definition
+ */
+void t_swift_generator::generate_old_swift_struct_result_writer(ostream& out, t_struct* tstruct) {
+
+  indent(out) << "private static func writeValue(__value: " << tstruct->get_name()
+              << ", toProtocol __proto: TProtocol) throws";
+  block_open(out);
+  out << endl;
+  string name = tstruct->get_name();
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  indent(out) << "try __proto.writeStructBeginWithName(\"" << name << "\")" << endl;
+  out << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field *tfield = *f_iter;
+
+    indent(out) << "if let result = __value." << (*f_iter)->get_name();
+
+    block_open(out);
+
+    indent(out) << "try __proto.writeFieldValue(result, "
+                << "name: \"" << tfield->get_name() << "\", "
+                << "type: " << type_to_enum(tfield->get_type()) << ", "
+                << "id: " << tfield->get_key() << ")" << endl;
+
+    block_close(out);
+  }
+  // Write the struct map
+  indent(out) << "try __proto.writeFieldStop()" << endl << endl;
+  indent(out) << "try __proto.writeStructEnd()" << endl;
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generates a description method for the given struct
+ *
+ * @param tstruct The struct definition
+ */
+void t_swift_generator::generate_swift_struct_printable_extension(ostream& out, t_struct* tstruct) {
+
+  // Allow use of debugDescription so the app can add description via a cateogory/extension
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  indent(out) << "extension " << tstruct->get_name() << " : "
+              << (debug_descriptions_ ? "CustomDebugStringConvertible" : "CustomStringConvertible");
+
+  block_open(out);
+  out << endl;
+  indent(out) << "public var description : String";
+  block_open(out);
+  indent(out) << "var desc = \"" << tstruct->get_name();
+
+  if (!gen_cocoa_) {
+    if (!tstruct->is_union()) {
+      out << "(\"" << endl;
+      for (f_iter = fields.begin(); f_iter != fields.end();) {
+        indent(out) << "desc += \"" << (*f_iter)->get_name()
+                    << "=\\(String(describing: self." << maybe_escape_identifier((*f_iter)->get_name()) << "))";
+        if (++f_iter != fields.end()) {
+          out << ", ";
+        }
+        out << "\"" << endl;
+      }
+    } else {
+      out << ".\"" << endl;
+      indent(out) << "switch self {" << endl;
+      for (f_iter = fields.begin(); f_iter != fields.end();f_iter++) {
+        indent(out) << "case ." << (*f_iter)->get_name() << "(let val): "
+                    << "desc += \"" << (*f_iter)->get_name() << "(val: \\(val))\""
+                    << endl;
+      }
+      indent(out) << "}" << endl;
+    }
+  } else {
+    out << "(\"" << endl;
+    for (f_iter = fields.begin(); f_iter != fields.end();) {
+      indent(out) << "desc += \"" << (*f_iter)->get_name()
+                  << "=\\(self." << maybe_escape_identifier((*f_iter)->get_name()) << ")";
+      if (++f_iter != fields.end()) {
+        out << ", ";
+      }
+      out << "\"" << endl;
+    }
+    indent(out) << "desc += \")\"" << endl;
+  }
+
+  indent(out) << "return desc" << endl;
+  block_close(out);
+  out << endl;
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generates a thrift service.  In Swift this consists of a
+ * protocol definition and a client (with it's implementation
+ * separated into exts file).
+ *
+ * @param tservice The service definition
+ */
+void t_swift_generator::generate_service(t_service* tservice) {
+
+  generate_swift_service_protocol(f_decl_, tservice);
+  generate_swift_service_client(f_decl_, tservice);
+  if (async_clients_) {
+    generate_swift_service_protocol_async(f_decl_, tservice);
+    generate_swift_service_client_async(f_decl_, tservice);
+  }
+  generate_swift_service_server(f_decl_, tservice);
+
+  generate_swift_service_helpers(tservice);
+
+  generate_swift_service_client_implementation(f_impl_, tservice);
+  if (async_clients_) {
+    generate_swift_service_client_async_implementation(f_impl_, tservice);
+  }
+  generate_swift_service_server_implementation(f_impl_, tservice);
+}
+
+/**
+ * Generates structs for all the service return types
+ *
+ * @param tservice The service
+ */
+void t_swift_generator::generate_swift_service_helpers(t_service* tservice) {
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+
+    t_struct* ts = (*f_iter)->get_arglist();
+
+    string qname = function_args_helper_struct_type(tservice, *f_iter);
+
+    t_struct qname_ts = t_struct(ts->get_program(), qname);
+
+    const vector<t_field*>& members = ts->get_members();
+    vector<t_field*>::const_iterator m_iter;
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      qname_ts.append(*m_iter);
+    }
+
+    generate_swift_struct(f_impl_, &qname_ts, true);
+    generate_swift_struct_implementation(f_impl_, &qname_ts, false, true);
+    generate_function_helpers(tservice, *f_iter);
+  }
+}
+
+string t_swift_generator::function_result_helper_struct_type(t_service *tservice, t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return tservice->get_name() + "_" + tfunction->get_name();
+  } else {
+    return tservice->get_name() + "_" + tfunction->get_name() + "_result";
+  }
+}
+
+string t_swift_generator::function_args_helper_struct_type(t_service *tservice, t_function* tfunction) {
+  return tservice->get_name() + "_" + tfunction->get_name() + "_args";
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_swift_generator::generate_function_helpers(t_service *tservice, t_function* tfunction) {
+  if (tfunction->is_oneway()) {
+    return;
+  }
+
+  // create a result struct with a success field of the return type,
+  // and a field for each type of exception thrown
+  t_struct result(program_, function_result_helper_struct_type(tservice, tfunction));
+  if (!tfunction->get_returntype()->is_void()) {
+    t_field* success = new t_field(tfunction->get_returntype(), "success", 0);
+    success->set_req(t_field::T_OPTIONAL);
+    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) {
+    t_field *x = *f_iter;
+    t_field *ox = new t_field(x->get_type(), x->get_name(), x->get_key());
+    ox->set_req(t_field::T_OPTIONAL);
+    result.append(ox);
+  }
+
+  // generate the result struct
+  generate_swift_struct(f_impl_, &result, true);
+  generate_swift_struct_implementation(f_impl_, &result, true, true);
+
+  for (f_iter = result.get_members().begin(); f_iter != result.get_members().end(); ++f_iter) {
+    delete *f_iter;
+  }
+}
+
+/**
+ * Generates a service protocol definition.
+ *
+ * @param tservice The service to generate a protocol definition for
+ */
+void t_swift_generator::generate_swift_service_protocol(ostream& out, t_service* tservice) {
+  if (!gen_cocoa_) {
+    string doc = tservice->get_doc();
+    generate_docstring(out, doc);
+
+    indent(out) << "public protocol " << tservice->get_name();
+    t_service* parent = tservice->get_extends();
+    if (parent != NULL) {
+      out << " : " << parent->get_name();
+    }
+    block_open(out);
+    out << endl;
+
+    vector<t_function*> functions = tservice->get_functions();
+    vector<t_function*>::iterator f_iter;
+
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      function_docstring(out, *f_iter);
+      indent(out) << function_signature(*f_iter) << endl << endl;
+    }
+
+  } else {
+    indent(out) << "public protocol " << tservice->get_name();
+    block_open(out);
+
+    vector<t_function*> functions = tservice->get_functions();
+    vector<t_function*>::iterator f_iter;
+
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      out << endl;
+      indent(out) << function_signature(*f_iter) << "  // exceptions: ";
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const 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) {
+        out << type_name((*x_iter)->get_type()) + ", ";
+      }
+      out << endl;
+    }
+  }
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generates an asynchronous service protocol definition.
+ *
+ * @param tservice The service to generate a protocol definition for
+ */
+void t_swift_generator::generate_swift_service_protocol_async(ostream& out, t_service* tservice) {
+  if (!gen_cocoa_) {
+    string doc = tservice->get_doc();
+    generate_docstring(out, doc);
+  }
+  indent(out) << "public protocol " << tservice->get_name() << "Async";
+
+  block_open(out);
+  if (!gen_cocoa_) {  out << endl; }
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  if (!gen_cocoa_) {
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      async_function_docstring(out, *f_iter);
+      indent(out) << async_function_signature(*f_iter) << endl << endl;
+    }
+  } else {
+    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+      out << endl;
+      indent(out) << async_function_signature(*f_iter) << endl;
+      if (promise_kit_) {
+        indent(out) << promise_function_signature(*f_iter) << endl;
+      } //
+      out << endl;
+    }
+  }
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generates a service client interface definition.
+ *
+ * @param tservice The service to generate a client interface definition for
+ */
+void t_swift_generator::generate_swift_service_client(ostream& out, t_service* tservice) {
+  if (!gen_cocoa_) {
+    indent(out) << "open class " << tservice->get_name() << "Client";// : "
+
+    // Inherit from ParentClient
+    t_service* parent = tservice->get_extends();
+    out << " : " << ((parent == NULL) ? "TClient" : parent->get_name() + "Client");
+    out <<  " /* , " << tservice->get_name() << " */";
+    block_open(out);
+    out << endl;
+  } else {
+    // a
+    indent(out) << "public class " << tservice->get_name() << "Client /* : " << tservice->get_name() << " */";
+    block_open(out);
+    out << endl;
+
+    indent(out) << "let __inProtocol : TProtocol" << endl << endl;
+    indent(out) << "let __outProtocol : TProtocol" << endl << endl;
+    indent(out) << "public init(inoutProtocol: TProtocol)";
+    block_open(out);
+
+    indent(out) << "__inProtocol = inoutProtocol" << endl;
+    indent(out) << "__outProtocol = inoutProtocol" << endl;
+    block_close(out);
+    out << endl;
+
+    indent(out) << "public init(inProtocol: TProtocol, outProtocol: TProtocol)";
+    block_open(out);
+    indent(out) << "__inProtocol = inProtocol" << endl;
+    indent(out) << "__outProtocol = outProtocol" << endl;
+    block_close(out);
+    out << endl;
+  }
+
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generates a service client interface definition.
+ *
+ * @param tservice The service to generate a client interface definition for
+ */
+void t_swift_generator::generate_swift_service_client_async(ostream& out, t_service* tservice) {
+  if (!gen_cocoa_) {
+    indent(out) << "open class " << tservice->get_name()
+                << "AsyncClient<Protocol: TProtocol, Factory: TAsyncTransportFactory>";// : "
+
+    // Inherit from ParentClient
+    t_service* parent = tservice->get_extends();
+
+    out << " : " << ((parent == NULL) ? "T" :  parent->get_name()) + "AsyncClient<Protocol, Factory>";
+    out <<  " /* , " << tservice->get_name() << " */";
+
+    block_open(out);
+    out << endl;
+  } else {
+    indent(out) << "public class " << tservice->get_name() << "AsyncClient /* : " << tservice->get_name() << " */";
+    block_open(out);
+    out << endl;
+
+    indent(out) << "let __protocolFactory : TProtocolFactory" << endl << endl;
+    indent(out) << "let __transportFactory : TAsyncTransportFactory" << endl << endl;
+    indent(out) << "public init(protocolFactory: TProtocolFactory, transportFactory: TAsyncTransportFactory)";
+    block_open(out);
+
+    indent(out) << "__protocolFactory = protocolFactory" << endl;
+    indent(out) << "__transportFactory = transportFactory" << endl;
+    block_close(out);
+    out << endl;
+  }
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generates a service server interface definition. In other words,
+ * the TProcess implementation for the service definition.
+ *
+ * @param tservice The service to generate a client interface definition for
+ */
+void t_swift_generator::generate_swift_service_server(ostream& out, t_service* tservice) {
+  if (!gen_cocoa_) {
+    indent(out) << "open class " << tservice->get_name() << "Processor /* " << tservice->get_name() << " */";
+
+    block_open(out);
+    out << endl;
+    out << indent() << "typealias ProcessorHandlerDictionary = "
+        << "[String: (Int32, TProtocol, TProtocol, " << tservice->get_name() << ") throws -> Void]" << endl
+        << endl
+        << indent() << "public var service: " << tservice->get_name() << endl
+        << endl
+        << indent() << "public required init(service: " << tservice->get_name() << ")";
+  } else {
+    indent(out) << "public class " << tservice->get_name() << "Processor : NSObject /* "
+                << tservice->get_name() << " */";
+    block_open(out);
+    out << endl;
+
+    out << indent() << "typealias ProcessorHandlerDictionary = "
+        << "[String: (Int, TProtocol, TProtocol, " << tservice->get_name() << ") throws -> Void]" << endl
+        << endl
+        << indent() << "let service : " << tservice->get_name() << endl
+        << endl
+        << indent() << "public init(service: " << tservice->get_name() << ")";
+  }
+
+  block_open(out);
+  indent(out) << "self.service = service" << endl;
+  block_close(out);
+  out << endl;
+
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generates a function that will send the arguments
+ * for a service function via a protocol.
+ *
+ * @param tservice  The service to generate
+ * @param tfunction The function to generate
+ * @param needs_protocol
+ *                  Wether the first parameter must be a protocol or if
+ *                  the protocol is to be assumed
+ */
+void t_swift_generator::generate_swift_service_client_send_function_implementation(ostream& out,
+                                                                                   t_service *tservice,
+                                                                                   t_function* tfunction,
+                                                                                   bool needs_protocol) {
+
+  string funname = tfunction->get_name();
+
+  t_function send_function(g_type_bool,
+                           "send_" + tfunction->get_name(),
+                           tfunction->get_arglist());
+
+  string argsname = function_args_helper_struct_type(tservice, tfunction);
+  t_struct* arg_struct = tfunction->get_arglist();
+
+  string proto = needs_protocol ? (gen_cocoa_ ? "__outProtocol" : "on outProtocol") : "";
+  // Open function
+  indent(out) << "private func " << send_function.get_name() << "("
+              << argument_list(tfunction->get_arglist(), proto, true)
+              << ") throws";
+  block_open(out);
+  if (!gen_cocoa_) {
+    // Serialize the request
+    indent(out) << "try outProtocol.writeMessageBegin(name: \"" << funname << "\", "
+                << "type: " << (tfunction->is_oneway() ? ".oneway" : ".call") << ", "
+                << "sequenceID: 0)" << endl;
+
+    indent(out) << "let args = " << argsname << "(";
+
+    // write out function parameters
+
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    for (f_iter = fields.begin(); f_iter != fields.end();) {
+      t_field *tfield = (*f_iter);
+      out << tfield->get_name() << ": " << tfield->get_name();
+      if (++f_iter != fields.end()) {
+        out << ", ";
+      }
+    }
+    out << ")" << endl;
+    indent(out) << "try args.write(to: outProtocol)" << endl;
+    indent(out) << "try outProtocol.writeMessageEnd()" << endl;
+  } else {
+    out << endl;
+
+    // Serialize the request
+    indent(out) << "try __outProtocol.writeMessageBeginWithName(\"" << funname << "\", "
+                << "type: " << (tfunction->is_oneway() ? ".ONEWAY" : ".CALL") << ", "
+                << "sequenceID: 0)" << endl;
+
+    out << endl;
+
+    indent(out) << "let __args = " << argsname << "(";
+
+    // write out function parameters
+
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator f_iter;
+
+    for (f_iter = fields.begin(); f_iter != fields.end();) {
+      t_field *tfield = (*f_iter);
+      out << tfield->get_name() << ": " << tfield->get_name();
+      if (++f_iter != fields.end()) {
+        out << ", ";
+      }
+    }
+    out << ")" << endl;
+    indent(out) << "try " << argsname << ".writeValue(__args, toProtocol: __outProtocol)" << endl << endl;
+    indent(out) << "try __outProtocol.writeMessageEnd()" << endl;
+  }
+
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generates a function that will recv the result for a
+ * service function via a protocol.
+ *
+ * @param tservice  The service to generate
+ * @param tfunction The function to generate
+ * @param needs_protocol
+ *                  Wether the first parameter must be a protocol or if
+ *                  the protocol is to be assumed
+ */
+void t_swift_generator::generate_swift_service_client_recv_function_implementation(ostream& out,
+                                                                                   t_service* tservice,
+                                                                                   t_function* tfunction,
+                                                                                   bool needs_protocol) {
+
+  // Open function
+  indent(out) << "private func recv_" << tfunction->get_name() << "(";
+  if (!gen_cocoa_) {
+    if (needs_protocol) {
+      out << "on inProtocol: TProtocol";
+    }
+    out << ") throws";
+    if (!tfunction->get_returntype()->is_void()) {
+      out << " -> " << type_name(tfunction->get_returntype());
+    }
+
+    block_open(out);
+
+    // check for an exception
+
+    indent(out) << "try inProtocol.readResultMessageBegin() " << endl;
+
+    string resultname = function_result_helper_struct_type(tservice, tfunction);
+    indent(out);
+    if (!tfunction->get_returntype()->is_void() || !tfunction->get_xceptions()->get_members().empty()) {
+      out << "let result = ";
+    } else {
+      out << "_ = ";
+    }
+
+    string return_type_name = type_name(tfunction->get_returntype());
+    out << "try " << resultname << ".read(from: inProtocol)" << endl;
+
+    indent(out) << "try inProtocol.readMessageEnd()" << endl << endl;
+
+    // Careful, only return _result if not a void function
+    if (!tfunction->get_returntype()->is_void()) {
+      indent(out) << "if let success = result.success";
+      block_open(out);
+      indent(out) << "return success" << endl;
+      block_close(out);
+    }
+
+    t_struct* xs = tfunction->get_xceptions();
+    const 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) {
+      indent(out) << "if let " << (*x_iter)->get_name() << " = result." << (*x_iter)->get_name();
+      block_open(out);
+      indent(out) << "throw " << (*x_iter)->get_name() << endl;
+      block_close(out);
+    }
+
+    // If you get here it's an exception, unless a void function
+    if (!tfunction->get_returntype()->is_void()) {
+      indent(out) << "throw TApplicationError(error: .missingResult(methodName: \""
+                  << tfunction->get_name() << "\"))" << endl;
+    }
+  } else {
+    if (needs_protocol) {
+      out << "__inProtocol: TProtocol";
+    }
+
+    out << ") throws";
+
+    if (!tfunction->get_returntype()->is_void()) {
+      out << " -> " << type_name(tfunction->get_returntype());
+    }
+
+    block_open(out);
+
+    // check for an exception
+    out << endl;
+    indent(out) << "try __inProtocol.readResultMessageBegin() " << endl << endl;
+    string resultname = function_result_helper_struct_type(tservice, tfunction);
+    indent(out);
+    if (!tfunction->get_returntype()->is_void() || !tfunction->get_xceptions()->get_members().empty()) {
+      out << "let __result = ";
+    }
+    out << "try " << resultname << ".readValueFromProtocol(__inProtocol)" << endl << endl;
+
+    indent(out) << "try __inProtocol.readMessageEnd()" << endl << endl;
+
+    // Careful, only return _result if not a void function
+    if (!tfunction->get_returntype()->is_void()) {
+      indent(out) << "if let __success = __result.success";
+      block_open(out);
+      indent(out) << "return __success" << endl;
+      block_close(out);
+    }
+
+    t_struct* xs = tfunction->get_xceptions();
+    const 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) {
+      indent(out) << "if let " << (*x_iter)->get_name() << " = __result." << (*x_iter)->get_name();
+      block_open(out);
+      indent(out) << "throw " << (*x_iter)->get_name() << endl;
+      block_close(out);
+    }
+
+    // If you get here it's an exception, unless a void function
+    if (!tfunction->get_returntype()->is_void()) {
+      indent(out) << "throw NSError(" << endl;
+      indent_up();
+      indent(out) << "domain: TApplicationErrorDomain, " << endl;
+      indent(out) << "code: Int(TApplicationError.MissingResult.rawValue)," << endl;
+      indent(out) << "userInfo: [TApplicationErrorMethodKey: \"" << tfunction->get_name() << "\"])" << endl;
+      indent_down();
+    }
+  }
+
+  // Close function
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generates an invocation of a given the send function for the
+ * service function.
+ *
+ * @param tfunction The service to generate an implementation for
+ */
+void t_swift_generator::generate_swift_service_client_send_function_invocation(ostream& out,
+                                                                               t_function* tfunction) {
+
+  indent(out) << "try send_" << tfunction->get_name() << "(";
+
+  t_struct* arg_struct = tfunction->get_arglist();
+
+  const vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  for (f_iter = fields.begin(); f_iter != fields.end();) {
+    out << (*f_iter)->get_name() << ": " << (*f_iter)->get_name();
+    if (++f_iter != fields.end()) {
+      out << ", ";
+    }
+  }
+
+  out << ")" << endl;
+}
+
+/**
+ * Generates an invocation of a given the send function for the
+ * service function. This is for asynchronous protocols.
+ *
+ * @param tfunction The service to generate an implementation for
+ */
+void t_swift_generator::generate_swift_service_client_send_async_function_invocation(ostream& out,
+                                                                                     t_function* tfunction) {
+
+  t_struct* arg_struct = tfunction->get_arglist();
+  const vector<t_field*>& fields = arg_struct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  if (!gen_cocoa_) {
+    indent(out) << "try send_" << tfunction->get_name() << "(on: proto";
+  } else {
+    indent(out) << "try send_" << tfunction->get_name() << "(__protocol"; //
+  }
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    out << ", " << (*f_iter)->get_name() << ": " << (*f_iter)->get_name();
+  }
+
+  out << ")" << endl;
+}
+
+/**
+ * Generates a service client protocol implementation via extension.
+ *
+ * @param tservice The service to generate an implementation for
+ */
+void t_swift_generator::generate_swift_service_client_implementation(ostream& out,
+                                                                     t_service* tservice) {
+
+  string name = tservice->get_name() + "Client";
+  indent(out) << "extension " << name << " : " << tservice->get_name();
+  block_open(out);
+  out << 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) {
+
+    generate_swift_service_client_send_function_implementation(out, tservice, *f_iter, false);
+
+    if (!(*f_iter)->is_oneway()) {
+      generate_swift_service_client_recv_function_implementation(out, tservice, *f_iter, false);
+    }
+
+    // Open function
+    indent(out) << "public " << function_signature(*f_iter);
+    block_open(out);
+
+    if (gen_cocoa_) { out << endl; }
+
+    generate_swift_service_client_send_function_invocation(out, *f_iter);
+    if (!gen_cocoa_) {
+      indent(out) << "try outProtocol.transport.flush()" << endl;
+    } else {
+      out << endl;
+      indent(out) << "try __outProtocol.transport().flush()" << endl << endl;
+    }
+
+    if (!(*f_iter)->is_oneway()) {
+      if ((*f_iter)->get_returntype()->is_void()) {
+        indent(out) << "try recv_" << (*f_iter)->get_name() << "()" << endl;
+      } else {
+        indent(out) << "return try recv_" << (*f_iter)->get_name() << "()" << endl;
+      }
+    }
+    block_close(out);
+    out << endl;
+  }
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generates a service asynchronous client protocol implementation via extension.
+ *
+ * @param tservice The service to generate an implementation for
+ */
+void t_swift_generator::generate_swift_service_client_async_implementation(ostream& out, t_service* tservice) {
+  if (gen_cocoa_) {
+    generate_old_swift_service_client_async_implementation(out, tservice);
+    return;
+  }
+  string name = tservice->get_name() + "AsyncClient";
+  string protocol_name = tservice->get_name() + "Async";
+
+  indent(out) << "extension " << name << " : " << protocol_name;
+  block_open(out);
+  out << 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) {
+
+    generate_swift_service_client_send_function_implementation(out, tservice, *f_iter, true);
+
+    if (!(*f_iter)->is_oneway()) {
+      generate_swift_service_client_recv_function_implementation(out, tservice, *f_iter, true);
+    }
+
+    indent(out) << "public " << async_function_signature(*f_iter);
+    block_open(out);
+    out << endl;
+    out << indent() << "let transport   = factory.newTransport()" << endl
+        << indent() << "let proto = Protocol(on: transport)" << endl
+        << endl;
+
+    out << indent() << "do";
+    block_open(out);
+
+    generate_swift_service_client_send_async_function_invocation(out, *f_iter);
+
+    indent_down();
+    out << indent() << "} catch let error {" << endl;
+    indent_up();
+    out << indent() << "completion(.error(error))" << endl;
+    block_close(out);
+
+    out << endl;
+
+    bool ret_is_void = (*f_iter)->get_returntype()->is_void();
+    bool is_oneway = (*f_iter)->is_oneway();
+
+    string error_completion_call = "completion(.error(error))";
+    indent(out) << "transport.flush";
+    block_open(out);
+    out << indent() << "(trans, error) in" << endl << endl;
+    out << indent() << "if let error = error";
+    block_open(out);
+    out << indent() << error_completion_call << endl;
+    block_close(out);
+
+    if (!is_oneway) {
+      out << indent() << "do";
+      block_open(out);
+      indent(out);
+      if (!ret_is_void) {
+        out << "let result = ";
+      }
+      out << "try self.recv_" << (*f_iter)->get_name() << "(on: proto)" << endl;
+
+      out << indent() << (ret_is_void ? "completion(.success(Void()))" : "completion(.success(result))") << endl;
+      indent_down();
+      out << indent() << "} catch let error {" << endl;
+      indent_up();
+      out << indent() << error_completion_call << endl;
+
+      block_close(out);
+    } else {
+      out << indent() << "completion(.success(Void()))" << endl;
+    }
+    block_close(out);
+    block_close(out);
+
+  }
+  block_close(out);
+  out << endl;
+}
+
+void t_swift_generator::generate_old_swift_service_client_async_implementation(ostream& out,
+                                                                               t_service* tservice) {
+
+  string name = tservice->get_name() + "AsyncClient";
+  string protocol_name = tservice->get_name() + "Async";
+
+  indent(out) << "extension " << name << " : " << protocol_name;
+  block_open(out);
+  out << 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) {
+
+    generate_swift_service_client_send_function_implementation(out, tservice, *f_iter, true);
+
+    if (!(*f_iter)->is_oneway()) {
+      generate_swift_service_client_recv_function_implementation(out, tservice, *f_iter, true);
+    }
+
+    indent(out) << "public " << async_function_signature(*f_iter);
+    block_open(out);
+    out << endl;
+
+    out << indent() << "let __transport = __transportFactory.newTransport()" << endl
+        << indent() << "let __protocol = __protocolFactory.newProtocolOnTransport(__transport)" << endl
+        << endl;
+
+    generate_swift_service_client_send_async_function_invocation(out, *f_iter);
+    out << endl;
+
+    indent(out) << "__transport.flushWithCompletion(";
+
+    if ((*f_iter)->is_oneway()) {
+      out << "success, failure: failure)" << endl;
+    }
+    else {
+      block_open(out);
+      indent(out) << "do";
+      block_open(out);
+
+      indent(out);
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        out << "let result = ";
+      }
+      out << "try self.recv_" << (*f_iter)->get_name() << "(__protocol)" << endl;
+
+      out << indent() << "success(";
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        out << "result";
+      }
+      out << ")" << endl;
+
+      block_close(out);
+      indent(out) << "catch let error";
+      block_open(out);
+      indent(out) << "failure(error as NSError)" << endl;
+      block_close(out);
+      block_close(out);
+      indent(out) << ", failure: failure)" << endl;
+    }
+
+    block_close(out);
+    out << endl;
+
+    // Promise function
+    if (promise_kit_) {
+
+      indent(out) << "public " << promise_function_signature(*f_iter);
+      block_open(out);
+
+      out << indent() << "let (__promise, __fulfill, __reject) = Promise<" << type_name((*f_iter)->get_returntype()) << ">.pendingPromise()" << endl << endl
+          << indent() << "let __transport = __transportFactory.newTransport()" << endl
+          << indent() << "let __protocol = __protocolFactory.newProtocolOnTransport(__transport)" << endl
+          << endl;
+
+      generate_swift_service_client_send_async_function_invocation(out, *f_iter);
+      out << endl;
+      indent(out) << "__transport.flushWithCompletion(";
+
+      if ((*f_iter)->is_oneway()) {
+        out << "{ __fulfill() }, failure: { __reject($0) })" << endl;
+      }
+      else {
+        block_open(out);
+        indent(out) << "do";
+        block_open(out);
+
+        indent(out);
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          out << "let result = ";
+        }
+        out << "try self.recv_" << (*f_iter)->get_name() << "(__protocol)" << endl;
+
+        out << indent() << "__fulfill(";
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          out << "result";
+        }
+        out << ")" << endl;
+
+        block_close(out);
+        indent(out) << "catch let error";
+        block_open(out);
+        indent(out) << "__reject(error)" << endl;
+        block_close(out);
+        block_close(out);
+
+        indent(out) << ", failure: { error in " << endl;
+        indent_up();
+        indent(out) << "__reject(error)" << endl;
+        indent_down();
+        indent(out) << "})" << endl;
+      }
+
+      indent(out) << "return __promise" << endl;
+      block_close(out);
+      out << endl;
+
+    }
+
+  }
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Generates a service server implementation.
+ *
+ * Implemented by generating a block for each service function that
+ * handles the processing of that function. The blocks are stored in
+ * a map and looked up via function/message name.
+ *
+ * @param tservice The service to generate an implementation for
+ */
+void t_swift_generator::generate_swift_service_server_implementation(ostream& out,
+                                                                     t_service* tservice) {
+
+  string name = tservice->get_name() + "Processor";
+
+  indent(out) << "extension " << name << " : TProcessor";
+  block_open(out);
+  out << endl;
+  indent(out) << "static let processorHandlers" << (gen_cocoa_ ? " " : "") << ": ProcessorHandlerDictionary =";
+  block_open(out);
+
+  out << endl;
+  out << indent() << "var processorHandlers = ProcessorHandlerDictionary()" << endl << endl;
+
+  // generate method map for routing incoming calls
+  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_function* tfunction = *f_iter;
+
+    string args_type = function_args_helper_struct_type(tservice, *f_iter);
+
+    out << indent() << "processorHandlers[\"" << tfunction->get_name() << "\"] = { sequenceID, inProtocol, outProtocol, handler in" << endl
+        << endl;
+
+    indent_up();
+    if (!gen_cocoa_) {
+      out << indent() << "let args = try " << args_type << ".read(from: inProtocol)" << endl
+          << endl
+          << indent() << "try inProtocol.readMessageEnd()" << endl
+          << endl;
+    } else {
+      out << indent() << "let args = try " << args_type << ".readValueFromProtocol(inProtocol)" << endl
+          << endl
+          << indent() << "try inProtocol.readMessageEnd()" << endl
+          << endl;
+    }
+
+    if (!tfunction->is_oneway() ) {
+      string result_type = function_result_helper_struct_type(tservice, tfunction);
+      indent(out) << "var result = " << result_type << "()" << endl;
+
+      indent(out) << "do";
+      block_open(out);
+
+      indent(out);
+      if (!tfunction->get_returntype()->is_void()) {
+        out << "result.success = ";
+      }
+      out << "try handler." << (gen_cocoa_ ? function_name(tfunction) : tfunction->get_name()) << "(";
+
+      t_struct* arg_struct = tfunction->get_arglist();
+      const vector<t_field*>& fields = arg_struct->get_members();
+      vector<t_field*>::const_iterator f_iter;
+
+      for (f_iter = fields.begin(); f_iter != fields.end();) {
+        string fieldName = (*f_iter)->get_name();
+        if (!gen_cocoa_ || f_iter != fields.begin()) {
+          out << fieldName << ": ";
+        }
+
+        out << "args." << fieldName;
+        if (++f_iter != fields.end()) {
+          out << ", ";
+        }
+      }
+
+      out << ")" << endl;
+      block_close(out);
+
+      t_struct* xs = tfunction->get_xceptions();
+      const vector<t_field*>& xfields = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+
+      if (!gen_cocoa_) {
+        for (x_iter = xfields.begin(); x_iter != xfields.end(); ++x_iter) {
+          indent(out) << "catch let error as ";
+
+          t_program* program = (*x_iter)->get_type()->get_program();
+          if ((*x_iter)->get_type()->get_name() == "Error" && namespaced_ && program != program_) {
+            out << get_real_swift_module(program) << ".";
+          }
+          out << (*x_iter)->get_type()->get_name();
+
+          out << " { result." << (*x_iter)->get_name() << " = error }" << endl;
+        }
+
+        indent(out) << "catch let error { throw error }" << endl;
+        out << endl;
+
+        if (!tfunction->is_oneway()) {
+          out << indent() << "try outProtocol.writeMessageBegin(name: \"" << tfunction->get_name() << "\", type: .reply, sequenceID: sequenceID)" << endl
+              << indent() << "try result.write(to: outProtocol)" << endl
+              << indent() << "try outProtocol.writeMessageEnd()" << endl;
+        }
+      } else {
+        for (x_iter = xfields.begin(); x_iter != xfields.end(); ++x_iter) {
+          indent(out) << "catch let error as " << (*x_iter)->get_type()->get_name();
+          block_open(out);
+          indent(out) << "result." << (*x_iter)->get_name() << " = error" << endl;
+          block_close(out);
+        }
+
+        indent(out) << "catch let error";
+        block_open(out);
+        out << indent() << "throw error" << endl;
+        block_close(out);
+
+        out << endl;
+
+        if (!tfunction->is_oneway()) {
+          out << indent() << "try outProtocol.writeMessageBeginWithName(\"" << tfunction->get_name() << "\", type: .REPLY, sequenceID: sequenceID)" << endl
+              << indent() << "try " << result_type << ".writeValue(result, toProtocol: outProtocol)" << endl
+              << indent() << "try outProtocol.writeMessageEnd()" << endl;
+        }
+      }
+    }
+    block_close(out);
+
+  }
+
+  indent(out) << "return processorHandlers" << endl;
+
+  block_close(out,false);
+  out << "()" << endl;
+  out << endl;
+
+  if (!gen_cocoa_) {
+    indent(out) << "public func process(on inProtocol: TProtocol, outProtocol: TProtocol) throws";
+  } else {
+    indent(out) << "public func processOnInputProtocol(inProtocol: TProtocol, outputProtocol outProtocol: TProtocol) throws";
+  }
+  block_open(out);
+
+  out << endl;
+  out << indent() << "let (messageName, _, sequenceID) = try inProtocol.readMessageBegin()" << endl
+      << endl
+      << indent() << "if let processorHandler = " << name << ".processorHandlers[messageName]";
+  block_open(out);
+  out << indent() << "do";
+  block_open(out);
+  out << indent() << "try processorHandler(sequenceID, inProtocol, outProtocol, service)" << endl;
+  block_close(out);
+  if (!gen_cocoa_) {
+    out << indent() << "catch let error as TApplicationError";
+    block_open(out);
+    out << indent() << "try outProtocol.writeException(messageName: messageName, sequenceID: sequenceID, ex: error)" << endl;
+    block_close(out);
+    block_close(out);
+    out << indent() << "else";
+    block_open(out);
+    out << indent() << "try inProtocol.skip(type: .struct)" << endl
+        << indent() << "try inProtocol.readMessageEnd()" << endl
+        << indent() << "let ex = TApplicationError(error: .unknownMethod(methodName: messageName))" << endl
+        << indent() << "try outProtocol.writeException(messageName: messageName, "
+        << "sequenceID: sequenceID, ex: ex)" << endl;
+  } else {
+    out << indent() << "catch let error as NSError";
+    block_open(out);
+    out << indent() << "try outProtocol.writeExceptionForMessageName(messageName, sequenceID: sequenceID, ex: error)" << endl;
+    block_close(out);
+    block_close(out);
+    out << indent() << "else";
+    block_open(out);
+    out << indent() << "try inProtocol.skipType(.STRUCT)" << endl
+        << indent() << "try inProtocol.readMessageEnd()" << endl
+        << indent() << "try outProtocol.writeExceptionForMessageName(messageName," << endl;
+    indent_up();
+    out << indent() << "sequenceID: sequenceID," << endl
+        << indent() << "ex: NSError(" << endl;
+    indent_up();
+    out << indent() << "domain: TApplicationErrorDomain, " << endl
+        << indent() << "code: Int(TApplicationError.UnknownMethod.rawValue), " << endl
+        << indent() << "userInfo: [TApplicationErrorMethodKey: messageName]))" << endl;
+    indent_down();
+    indent_down();
+  }
+
+  block_close(out);
+  block_close(out);
+  block_close(out);
+  out << endl;
+}
+
+/**
+ * Returns an Swift name
+ *
+ * @param ttype The type
+ * @param class_ref Do we want a Class reference istead of a type reference?
+ * @return Swift type name, i.e. Dictionary<Key,Value>
+ */
+string t_swift_generator::type_name(t_type* ttype, bool is_optional, bool is_forced) {
+  string result = "";
+
+  if (ttype->is_base_type()) {
+    result += base_type_name((t_base_type*)ttype);
+  } else if (ttype->is_map()) {
+    t_map *map = (t_map *)ttype;
+    result += "TMap<" + type_name(map->get_key_type()) + ", " + type_name(map->get_val_type()) + ">";
+  } else if (ttype->is_set()) {
+    t_set *set = (t_set *)ttype;
+    result += "TSet<" + type_name(set->get_elem_type()) + ">";
+  } else if (ttype->is_list()) {
+    t_list *list = (t_list *)ttype;
+    result += "TList<" + type_name(list->get_elem_type()) + ">";
+  }
+  else {
+    t_program* program = ttype->get_program();
+    if (namespaced_ && program != program_) {
+      result += get_real_swift_module(program) + ".";
+    }
+    result += ttype->get_name();
+  }
+
+  if (is_optional) {
+    result += "?";
+  }
+  if (is_forced) {
+    result += "!";
+  }
+
+  return result;
+}
+
+/**
+ * Returns the Swift type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ */
+string t_swift_generator::base_type_name(t_base_type* type) {
+  t_base_type::t_base tbase = type->get_base();
+
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "Void";
+  case t_base_type::TYPE_STRING:
+    if (type->is_binary()) {
+      return gen_cocoa_ ? "TBinary" : "Data";
+    } else {
+      return "String";
+    }
+  case t_base_type::TYPE_BOOL:
+    return "Bool";
+  case t_base_type::TYPE_I8:
+    return "Int8";
+  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 "Double";
+  default:
+    throw "compiler error: no Swift name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+/**
+ * Renders full constant value (as would be seen after an '=')
+ *
+ */
+void t_swift_generator::render_const_value(ostream& out,
+                                           t_type* type,
+                                           t_const_value* value) {
+  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_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_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      out << type_name(type) << "(" << value->get_integer() << ")";
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      out << type_name(type) << "(";
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        out << value->get_integer();
+      } else {
+        out << value->get_double();
+      }
+      out << ")";
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    out << (gen_cocoa_ ? value->get_identifier() : enum_const_name(value->get_identifier())); // Swift2/Cocoa compatibility
+  } else if (type->is_struct() || type->is_xception()) {
+
+    out << type_name(type) << "(";
+
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+
+    for (f_iter = fields.begin(); f_iter != fields.end();) {
+      t_field* tfield = *f_iter;
+      t_const_value* value = NULL;
+      for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+        if (tfield->get_name() == v_iter->first->get_string()) {
+          value = v_iter->second;
+        }
+      }
+
+      if (value) {
+        out << tfield->get_name() << ": ";
+        render_const_value(out, tfield->get_type(), value);
+      }
+      else if (!field_is_optional(tfield)) {
+        throw "constant error: required field " + type->get_name() + "." + tfield->get_name() + " has no value";
+      }
+
+      if (++f_iter != fields.end()) {
+        out << ", ";
+      }
+    }
+
+    out << ")";
+
+  } else if (type->is_map()) {
+
+    out << "[";
+
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+
+    for (v_iter = val.begin(); v_iter != val.end();) {
+
+      render_const_value(out, ktype, v_iter->first);
+      out << ": ";
+      render_const_value(out, vtype, v_iter->second);
+
+      if (++v_iter != val.end()) {
+        out << ", ";
+      }
+    }
+
+    out << "]";
+
+  } else if (type->is_list()) {
+
+    out << "[";
+
+    t_type* etype = ((t_list*)type)->get_elem_type();
+
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+
+    for (v_iter = val.begin(); v_iter != val.end();) {
+
+      render_const_value(out, etype, v_iter->first);
+
+      if (++v_iter != val.end()) {
+        out << ", ";
+      }
+    }
+
+    out << "]";
+
+  } else if (type->is_set()) {
+
+    out << "[";
+
+    t_type* etype = ((t_set*)type)->get_elem_type();
+
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+
+    for (v_iter = val.begin(); v_iter != val.end();) {
+
+      render_const_value(out, etype, v_iter->first);
+
+      if (++v_iter != val.end()) {
+        out << ", ";
+      }
+    }
+
+    out << "]";
+
+  } else {
+    throw "compiler error: no const of type " + type->get_name();
+  }
+
+}
+
+/**
+ * Declares an Swift property.
+ *
+ * @param tfield The field to declare a property for
+ */
+string t_swift_generator::declare_property(t_field* tfield, bool is_private) {
+
+  string visibility = is_private ? (gen_cocoa_ ? "private" : "fileprivate") : "public";
+
+  ostringstream render;
+
+  render << visibility << " var " << maybe_escape_identifier(tfield->get_name());
+
+  if (field_is_optional(tfield)) {
+    render << (gen_cocoa_ ? " " : "") << ": " << type_name(tfield->get_type(), true);
+  }
+  else {
+    if (!gen_cocoa_) {
+      render << ": " << type_name(tfield->get_type(), false);
+    } else {
+      // Swift2/Cocoa backward compat, Bad, default init
+      render << " = " << type_name(tfield->get_type(), false) << "()";
+    }
+  }
+
+  return render.str();
+}
+
+/**
+ * Renders a function signature
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_swift_generator::function_signature(t_function* tfunction) {
+
+  string result = "func " + (gen_cocoa_ ? function_name(tfunction) : tfunction->get_name());
+
+  result += "(" + argument_list(tfunction->get_arglist(), "", false) + ") throws"; /// argsreview
+
+  t_type* ttype = tfunction->get_returntype();
+  if (!ttype->is_void()) {
+    result += " -> " + type_name(ttype);
+  }
+
+  return result;
+}
+
+/**
+ * Renders a function docstring
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+void t_swift_generator::function_docstring(ostream& out, t_function* tfunction) {
+
+    // Generate docstring with following format:
+    // /// <Description>
+    // /// <empty line>
+    // /// - Parameters:
+    // ///   - <parameter>: <parameter docstring>
+    // /// - Returns: <return type> (Thrift has no docstring on return val)
+    // /// - Throws: <exception types>
+
+    // Description
+    string doc = tfunction->get_doc();
+    generate_docstring(out, doc);
+    indent(out) << "///" << endl;
+
+    // Parameters
+    const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    if (!fields.empty()) {
+      indent(out) << "/// - Parameters:" << endl;
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        indent(out) << "///   - " << (*f_iter)->get_name() << ": ";
+        string doc = (*f_iter)->get_doc();
+        if (!doc.empty() && doc[doc.length()-1] == '\n') {
+            doc.erase(doc.length()-1);
+        }
+        out << doc << endl;
+      }
+    }
+
+    // Returns
+    t_type* ttype = tfunction->get_returntype();
+    if (!ttype->is_void()) {
+      indent(out) << "/// - Returns: " << type_name(ttype) << endl;
+    }
+
+    // Throws
+    indent(out) << "/// - Throws: ";
+    t_struct* xs = tfunction->get_xceptions();
+    const 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) {
+      out << type_name((*x_iter)->get_type());
+      if (*x_iter != xceptions.back()) {
+        out << ", ";
+      }    }
+    out << endl;
+}
+
+/**
+ * Renders a function docstring
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+void t_swift_generator::async_function_docstring(ostream& out, t_function* tfunction) {
+    // Generate docstring with following format:
+    // /// <Description>
+    // /// <empty line>
+    // /// - Parameters:
+    // ///   - <parameter>: <parameter docstring>
+    // ///   - callback: <callback types>
+
+    // Description
+    string doc = tfunction->get_doc();
+    generate_docstring(out, doc);
+    indent(out) << "///" << endl;
+
+    // Parameters
+    const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    if (!fields.empty()) {
+      indent(out) << "/// - Parameters:" << endl;
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        indent(out) << "///   - " << (*f_iter)->get_name() << ": ";
+        string doc = (*f_iter)->get_doc();
+        if (!doc.empty() && doc[doc.length()-1] == '\n') {
+            doc.erase(doc.length()-1);
+        }
+        out << doc << endl;
+      }
+    }
+
+    // completion
+    indent(out) << "///   - completion: TAsyncResult<" << type_name(tfunction->get_returntype())
+                << "> wrapping return and following Exceptions: ";
+    t_struct* xs = tfunction->get_xceptions();
+    const 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) {
+      out << type_name((*x_iter)->get_type());
+      if (*x_iter != xceptions.back()) {
+        out << ", ";
+      }
+    }
+    out << endl;
+}
+
+/**
+ * Renders a function signature that returns asynchronously via blocks.
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_swift_generator::async_function_signature(t_function* tfunction) {
+  t_type* ttype = tfunction->get_returntype();
+  t_struct* targlist = tfunction->get_arglist();
+  string result = "func " + (gen_cocoa_ ? function_name(tfunction) : tfunction->get_name());
+
+  if (!gen_cocoa_) {
+    string response_string = "(TAsyncResult<";
+    response_string += (ttype->is_void()) ? "Void" : type_name(ttype);
+    response_string += ">) -> Void";
+    result += "(" + argument_list(tfunction->get_arglist(), "", false)
+            + (targlist->get_members().size() ? ", " : "")
+            + "completion: @escaping " + response_string + ")";
+  } else {
+    string response_param = "(" + ((ttype->is_void()) ? "" : type_name(ttype)) + ") -> Void";
+    result += "(" + argument_list(tfunction->get_arglist(), "", false)
+            + (targlist->get_members().size() ? ", " : "")
+            + "success: " + response_param + ", "
+            + "failure: (NSError) -> Void) throws";
+  }
+  return result;
+}
+
+/**
+ * Renders a function signature that returns asynchronously via promises.
+ * ONLY FOR Swift2/Cocoa BACKWARDS COMPATIBILITY
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_swift_generator::promise_function_signature(t_function* tfunction) {
+  return "func " + function_name(tfunction) + "(" + argument_list(tfunction->get_arglist(), "", false) + ") throws "
+         + "-> Promise<" + type_name(tfunction->get_returntype()) + ">";
+}
+
+/**
+ * Renders a verbose function name suitable for a Swift method.  ONLY FOR Swift2/Cocoa BACKWARDS COMPATIBILITY
+ */
+string t_swift_generator::function_name(t_function* tfunction) {
+  string name = tfunction->get_name();
+  if (!tfunction->get_arglist()->get_members().empty()) {
+    string first_arg = tfunction->get_arglist()->get_members().front()->get_name();
+    if (name.size() < first_arg.size() ||
+        lowercase(name.substr(name.size()-first_arg.size())) != lowercase(first_arg)) {
+      name += "With" + capitalize(tfunction->get_arglist()->get_members()[0]->get_name());
+    }
+  }
+  return name;
+}
+
+/**
+ * Renders a Swift method argument list
+ */
+string t_swift_generator::argument_list(t_struct* tstruct, string protocol_name, bool is_internal) {
+  string result = "";
+  bool include_protocol = !protocol_name.empty();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  if (include_protocol) {
+    result += protocol_name + ": TProtocol";
+    if (!fields.empty()) {
+      result += ", ";
+    }
+  } else if (!fields.empty() && is_internal && gen_cocoa_) {
+    // Force first argument to be named, Swift2/Cocoa backwards compat
+    result += fields.front()->get_name() + " ";
+  }
+
+  for (f_iter = fields.begin(); f_iter != fields.end();) {
+    t_field* arg = *f_iter;
+
+    if (!gen_cocoa_) {
+      // optional args not usually permitted for some reason, even though dynamic langs handle it
+      // use annotation "swift.nullable" to achieve
+      result += arg->get_name() + ": " + type_name(arg->get_type(), field_is_optional(arg));
+    } else {
+      result += arg->get_name() + ": " + type_name(arg->get_type());
+    }
+
+    if (++f_iter != fields.end()) {
+      result += ", ";
+    }
+  }
+  return result;
+}
+
+/**
+ * https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html
+ *
+ */
+
+void t_swift_generator::populate_reserved_words() {
+  if (!gen_cocoa_) {
+    swift_reserved_words_.insert("__COLUMN__");
+    swift_reserved_words_.insert("__FILE__");
+    swift_reserved_words_.insert("__FUNCTION__");
+    swift_reserved_words_.insert("__LINE__");
+    swift_reserved_words_.insert("Any");
+    swift_reserved_words_.insert("as");
+    swift_reserved_words_.insert("associatedtype");
+    swift_reserved_words_.insert("associativity");
+    swift_reserved_words_.insert("break");
+    swift_reserved_words_.insert("case");
+    swift_reserved_words_.insert("catch");
+    swift_reserved_words_.insert("class");
+    swift_reserved_words_.insert("continue");
+    swift_reserved_words_.insert("convenience");
+    swift_reserved_words_.insert("default");
+    swift_reserved_words_.insert("defer");
+    swift_reserved_words_.insert("deinit");
+    swift_reserved_words_.insert("didSet");
+    swift_reserved_words_.insert("do");
+    swift_reserved_words_.insert("dynamic");
+    swift_reserved_words_.insert("dynamicType");
+    swift_reserved_words_.insert("else");
+    swift_reserved_words_.insert("enum");
+    swift_reserved_words_.insert("extension");
+    swift_reserved_words_.insert("fallthrough");
+    swift_reserved_words_.insert("false");
+    swift_reserved_words_.insert("fileprivate");
+    swift_reserved_words_.insert("final");
+    swift_reserved_words_.insert("for");
+    swift_reserved_words_.insert("func");
+    swift_reserved_words_.insert("get");
+    swift_reserved_words_.insert("guard");
+    swift_reserved_words_.insert("if");
+    swift_reserved_words_.insert("import");
+    swift_reserved_words_.insert("in");
+    swift_reserved_words_.insert("indirect");
+    swift_reserved_words_.insert("infix");
+    swift_reserved_words_.insert("init");
+    swift_reserved_words_.insert("inout");
+    swift_reserved_words_.insert("internal");
+    swift_reserved_words_.insert("is");
+    swift_reserved_words_.insert("lazy");
+    swift_reserved_words_.insert("left");
+    swift_reserved_words_.insert("let");
+    swift_reserved_words_.insert("mutating");
+    swift_reserved_words_.insert("nil");
+    swift_reserved_words_.insert("none");
+    swift_reserved_words_.insert("nonmutating");
+    swift_reserved_words_.insert("open");
+    swift_reserved_words_.insert("operator");
+    swift_reserved_words_.insert("optional");
+    swift_reserved_words_.insert("override");
+    swift_reserved_words_.insert("postfix");
+    swift_reserved_words_.insert("precedence");
+    swift_reserved_words_.insert("prefix");
+    swift_reserved_words_.insert("private");
+    swift_reserved_words_.insert("protocol");
+    swift_reserved_words_.insert("Protocol");
+    swift_reserved_words_.insert("public");
+    swift_reserved_words_.insert("repeat");
+    swift_reserved_words_.insert("required");
+    swift_reserved_words_.insert("rethrows");
+    swift_reserved_words_.insert("return");
+    swift_reserved_words_.insert("right");
+    swift_reserved_words_.insert("self");
+    swift_reserved_words_.insert("Self");
+    swift_reserved_words_.insert("set");
+    swift_reserved_words_.insert("static");
+    swift_reserved_words_.insert("struct");
+    swift_reserved_words_.insert("subscript");
+    swift_reserved_words_.insert("super");
+    swift_reserved_words_.insert("switch");
+    swift_reserved_words_.insert("throw");
+    swift_reserved_words_.insert("throws");
+    swift_reserved_words_.insert("true");
+    swift_reserved_words_.insert("try");
+    swift_reserved_words_.insert("Type");
+    swift_reserved_words_.insert("typealias");
+    swift_reserved_words_.insert("unowned");
+    swift_reserved_words_.insert("var");
+    swift_reserved_words_.insert("weak");
+    swift_reserved_words_.insert("where");
+    swift_reserved_words_.insert("while");
+    swift_reserved_words_.insert("willSet");
+  } else {
+    swift_reserved_words_.insert("Self");
+    swift_reserved_words_.insert("associatedtype");
+    swift_reserved_words_.insert("defer");
+    swift_reserved_words_.insert("deinit");
+    swift_reserved_words_.insert("dynamicType");
+    swift_reserved_words_.insert("enum");
+    swift_reserved_words_.insert("extension");
+    swift_reserved_words_.insert("fallthrough");
+    swift_reserved_words_.insert("false");
+    swift_reserved_words_.insert("func");
+    swift_reserved_words_.insert("guard");
+    swift_reserved_words_.insert("init");
+    swift_reserved_words_.insert("inout");
+    swift_reserved_words_.insert("internal");
+    swift_reserved_words_.insert("let");
+    swift_reserved_words_.insert("operator");
+    swift_reserved_words_.insert("protocol");
+    swift_reserved_words_.insert("repeat");
+    swift_reserved_words_.insert("rethrows");
+    swift_reserved_words_.insert("struct");
+    swift_reserved_words_.insert("subscript");
+    swift_reserved_words_.insert("throws");
+    swift_reserved_words_.insert("true");
+    swift_reserved_words_.insert("typealias");
+    swift_reserved_words_.insert("where");
+  }
+}
+
+string t_swift_generator::maybe_escape_identifier(const string& identifier) {
+  if (swift_reserved_words_.find(identifier) != swift_reserved_words_.end()) {
+    return "`" + identifier + "`";
+  }
+  return identifier;
+}
+
+/**
+ * Converts the parse type to a Swift TType enumeration.
+ */
+string t_swift_generator::type_to_enum(t_type* type, bool qualified) {
+  type = get_true_type(type);
+
+  string result = qualified ? "TType." : ".";
+  if (!gen_cocoa_) {
+    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 result + "string";
+        case t_base_type::TYPE_BOOL:
+          return result + "bool";
+        case t_base_type::TYPE_I8:
+          return result + "i8";
+        case t_base_type::TYPE_I16:
+          return result + "i16";
+        case t_base_type::TYPE_I32:
+          return result + "i32";
+        case t_base_type::TYPE_I64:
+          return result + "i64";
+        case t_base_type::TYPE_DOUBLE:
+          return result + "double";
+      }
+    } else if (type->is_enum()) {
+      return result + "i32";
+    } else if (type->is_struct() || type->is_xception()) {
+      return result + "struct";
+    } else if (type->is_map()) {
+      return result + "map";
+    } else if (type->is_set()) {
+      return result + "set";
+    } else if (type->is_list()) {
+      return result + "list";
+    }
+  } else {
+    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 result + "STRING";
+        case t_base_type::TYPE_BOOL:
+          return result + "BOOL";
+        case t_base_type::TYPE_I8:
+          return result + "BYTE";
+        case t_base_type::TYPE_I16:
+          return result + "I16";
+        case t_base_type::TYPE_I32:
+          return result + "I32";
+        case t_base_type::TYPE_I64:
+          return result + "I64";
+        case t_base_type::TYPE_DOUBLE:
+          return result + "DOUBLE";
+      }
+    } else if (type->is_enum()) {
+      return result + "I32";
+    } else if (type->is_struct() || type->is_xception()) {
+      return result + "STRUCT";
+    } else if (type->is_map()) {
+      return result + "MAP";
+    } else if (type->is_set()) {
+      return result + "SET";
+    } else if (type->is_list()) {
+      return result + "LIST";
+    }
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+
+THRIFT_REGISTER_GENERATOR(
+    swift,
+    "Swift 3.0",
+    "    log_unexpected:  Log every time an unexpected field ID or type is encountered.\n"
+    "    debug_descriptions:\n"
+    "                     Allow use of debugDescription so the app can add description via a cateogory/extension\n"
+    "    async_clients:   Generate clients which invoke asynchronously via block syntax.\n"
+    "    namespaced:      Generate source in Module scoped output directories for Swift Namespacing.\n"
+    "    cocoa:           Generate Swift 2.x code compatible with the Thrift/Cocoa library\n"
+    "    promise_kit:     Generate clients which invoke asynchronously via promises (only use with cocoa flag)\n"
+    "    safe_enums:      Generate enum types with an unknown case to handle unspecified values rather than throw a serialization error\n")
diff --git a/compiler/cpp/src/thrift/generate/t_xml_generator.cc b/compiler/cpp/src/thrift/generate/t_xml_generator.cc
new file mode 100644
index 0000000..35fed14
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_xml_generator.cc
@@ -0,0 +1,692 @@
+/*
+ * 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.
+ */
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <limits>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+
+#include "thrift/platform.h"
+#include "thrift/generate/t_generator.h"
+
+using std::map;
+using std::ofstream;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+using std::stack;
+using std::set;
+
+static const string endl = "\n";
+static const string quot = "\"";
+
+static const string default_ns_prefix = "http://thrift.apache.org/xml/ns/";
+
+/**
+ * This generator creates an XML model of the parsed IDL tree, and is designed
+ * to make it easy to use this file as the input for other template engines,
+ * such as XSLT.  To this end, the generated XML is slightly more verbose than
+ * you might expect... for example, references to "id" types (such as structs,
+ * unions, etc) always specify the name of the IDL document, even if the type
+ * is defined in the same document as the reference.
+ */
+class t_xml_generator : public t_generator {
+public:
+  t_xml_generator( t_program* program,
+                   const std::map<std::string, std::string>& parsed_options,
+                   const std::string& option_string)
+    : t_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    should_merge_includes_ = false;
+    should_use_default_ns_ = true;
+    should_use_namespaces_ = true;
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if( iter->first.compare("merge") == 0) {
+        should_merge_includes_ = true;
+      } else if( iter->first.compare("no_default_ns") == 0) {
+        should_use_default_ns_ = false;
+      } else if( iter->first.compare("no_namespaces") == 0) {
+        should_use_namespaces_ = false;
+      } else {
+        throw "unknown option xml:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-xml";
+  }
+
+  virtual ~t_xml_generator() {}
+
+  void init_generator();
+  void close_generator();
+  void generate_program();
+
+  void iterate_program(t_program* program);
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_function(t_function* tfunc);
+  void generate_field(t_field* field);
+
+  void generate_service(t_service* tservice);
+  void generate_struct(t_struct* tstruct);
+
+  void generate_annotations(std::map<std::string, std::string> annotations);
+
+private:
+  bool should_merge_includes_;
+  bool should_use_default_ns_;
+  bool should_use_namespaces_;
+
+  ofstream_with_content_based_conditional_update f_xml_;
+
+  std::set<string> programs_;
+  std::stack<string> elements_;
+  bool top_element_is_empty;
+  bool top_element_is_open;
+
+  string target_namespace(t_program* program);
+  void write_element_start(const string name);
+  void close_top_element();
+  void write_element_end();
+  void write_attribute(string key, string val);
+  void write_int_attribute(string key, int val);
+  string escape_xml_string(const string& input);
+
+  void write_xml_comment(string msg);
+
+  void write_type(t_type* ttype);
+  void write_doc(t_doc* tdoc);
+
+  template <typename T>
+  string number_to_string(T t) {
+    std::ostringstream out;
+    out.imbue(std::locale::classic());
+    out.precision(std::numeric_limits<T>::digits10);
+    out << t;
+    return out.str();
+  }
+
+  template <typename T>
+  void write_number(T n) {
+    f_xml_ << number_to_string(n);
+  }
+
+  template <typename T>
+  void write_element_number(string name, T n) {
+    write_element_string(name, number_to_string(n));
+  }
+
+  string get_type_name(t_type* ttype);
+
+  void generate_constant(t_const* con);
+
+  void write_element_string(string name, string value);
+  void write_value(t_type* tvalue);
+  void write_const_value(t_const_value* value);
+  virtual std::string xml_autogen_comment() {
+    return std::string("\n") + " * Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
+           + " *\n" + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n";
+  }
+};
+
+void t_xml_generator::init_generator() {
+  MKDIR(get_out_dir().c_str());
+
+  string f_xml_name = get_out_dir() + program_->get_name() + ".xml";
+  f_xml_.open(f_xml_name.c_str());
+
+  top_element_is_open = false;
+}
+
+string t_xml_generator::target_namespace(t_program* program) {
+  std::map<std::string, std::string> map;
+  std::map<std::string, std::string>::iterator iter;
+  map = program->get_namespace_annotations("xml");
+  if ((iter = map.find("targetNamespace")) != map.end()) {
+    return iter->second;
+  }
+  map = program->get_namespaces();
+  if ((iter = map.find("xml")) != map.end()) {
+    return default_ns_prefix + iter->second;
+  }
+  map = program->get_namespace_annotations("*");
+  if ((iter = map.find("xml.targetNamespace")) != map.end()) {
+    return iter->second;
+  }
+  map = program->get_namespaces();
+  if ((iter = map.find("*")) != map.end()) {
+    return default_ns_prefix + iter->second;
+  }
+  return default_ns_prefix + program->get_name();
+}
+
+void t_xml_generator::write_xml_comment(string msg) {
+  close_top_element();
+  // TODO: indent any EOLs that may occur with msg
+  // TODO: proper msg escaping needed?
+  f_xml_ << indent() << "<!-- " << msg << " -->"  << endl;
+  top_element_is_empty = false;
+}
+
+void t_xml_generator::close_top_element() {
+  if( top_element_is_open) {
+    top_element_is_open = false;
+    if (elements_.size() > 0 && top_element_is_empty) {
+      f_xml_ << ">" << endl;
+    }
+  }
+}
+
+void t_xml_generator::write_element_start(string name) {
+  if (should_use_namespaces_ && !should_use_default_ns_) {
+    name = "idl:" + name;
+  }
+  close_top_element();
+  f_xml_ << indent() << "<" << name;
+  elements_.push(name);
+  top_element_is_empty = true;
+  top_element_is_open = true;
+  indent_up();
+}
+
+void t_xml_generator::write_element_end() {
+  indent_down();
+  if (top_element_is_empty && top_element_is_open) {
+    f_xml_ << " />" << endl;
+  } else {
+    f_xml_ << indent() << "</" << elements_.top() << ">" << endl;
+  }
+  top_element_is_empty = false;
+  elements_.pop();
+}
+
+void t_xml_generator::write_attribute(string key, string val) {
+  f_xml_ << " " << key << "=\"" << escape_xml_string(val) << "\"";
+}
+
+void t_xml_generator::write_int_attribute(string key, int val) {
+  write_attribute(key, number_to_string(val));
+}
+
+void t_xml_generator::write_element_string(string name, string val) {
+  if (should_use_namespaces_ && !should_use_default_ns_) {
+    name = "idl:" + name;
+  }
+  close_top_element();
+  top_element_is_empty = false;
+  f_xml_ << indent()
+    << "<" << name << ">" << escape_xml_string(val) << "</" << name << ">"
+    << endl;
+}
+
+string t_xml_generator::escape_xml_string(const string& input) {
+  std::ostringstream ss;
+  for (std::string::const_iterator iter = input.begin(); iter != input.end(); iter++) {
+    switch (*iter) {
+    case '&':
+      ss << "&amp;";
+      break;
+    case '"':
+      ss << "&quot;";
+      break;
+    case '\'':
+      ss << "&apos;";
+      break;
+    case '<':
+      ss << "&lt;";
+      break;
+    case '>':
+      ss << "&gt;";
+      break;
+    default:
+      ss << *iter;
+      break;
+    }
+  }
+  return ss.str();
+}
+
+void t_xml_generator::close_generator() {
+  f_xml_.close();
+}
+
+void t_xml_generator::generate_program() {
+
+  init_generator();
+
+  write_element_start("idl");
+  if (should_use_namespaces_) {
+    if (should_use_default_ns_) {
+      write_attribute("xmlns", "http://thrift.apache.org/xml/idl");
+    }
+    write_attribute("xmlns:idl", "http://thrift.apache.org/xml/idl");
+  }
+
+  write_xml_comment( xml_autogen_comment());
+
+  iterate_program(program_);
+
+  write_element_end();
+
+  close_generator();
+
+}
+
+void t_xml_generator::iterate_program(t_program* program) {
+
+  write_element_start("document");
+  write_attribute("name", program->get_name());
+  if (should_use_namespaces_) {
+    const string targetNamespace = target_namespace(program);
+    write_attribute("targetNamespace", targetNamespace);
+    write_attribute("xmlns:" + program->get_name(), targetNamespace);
+  }
+  write_doc(program);
+
+  const vector<t_program*> includes = program->get_includes();
+  vector<t_program*>::const_iterator inc_it;
+  for (inc_it = includes.begin(); inc_it != includes.end(); ++inc_it) {
+    write_element_start("include");
+    write_attribute("name", (*inc_it)->get_name());
+    write_element_end();
+  }
+
+  const map<string, string>& namespaces = program->get_namespaces();
+  map<string, string>::const_iterator ns_it;
+  for (ns_it = namespaces.begin(); ns_it != namespaces.end(); ++ns_it) {
+    write_element_start("namespace");
+    write_attribute("name", ns_it->first);
+    write_attribute("value", ns_it->second);
+    generate_annotations(program->get_namespace_annotations(ns_it->first));
+    write_element_end();
+  }
+
+  // TODO: can constants have annotations?
+  vector<t_const*> consts = program->get_consts();
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    generate_constant(*c_iter);
+  }
+
+  vector<t_typedef*> typedefs = program->get_typedefs();
+  vector<t_typedef*>::iterator td_iter;
+  for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
+    generate_typedef(*td_iter);
+  }
+
+  vector<t_enum*> enums = program->get_enums();
+  vector<t_enum*>::iterator en_iter;
+  for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+    generate_enum(*en_iter);
+  }
+
+  vector<t_struct*> objects = program->get_objects();
+  vector<t_struct*>::iterator o_iter;
+  for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
+    if ((*o_iter)->is_xception()) {
+      generate_xception(*o_iter);
+    } else {
+      generate_struct(*o_iter);
+    }
+  }
+
+  vector<t_service*> services = program->get_services();
+  vector<t_service*>::iterator sv_iter;
+  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    generate_service(*sv_iter);
+  }
+
+  write_element_end();
+
+  if (should_merge_includes_) {
+    programs_.insert(program->get_name());
+    const vector<t_program*> programs = program->get_includes();
+    vector<t_program*>::const_iterator prog_it;
+    for (prog_it = programs.begin(); prog_it != programs.end(); ++prog_it) {
+      if (!programs_.count((*prog_it)->get_name())) {
+        iterate_program(*prog_it);
+      }
+    }
+  }
+
+}
+
+void t_xml_generator::generate_typedef(t_typedef* ttypedef) {
+  write_element_start("typedef");
+  write_attribute("name", ttypedef->get_name());
+  write_doc(ttypedef);
+  write_type(ttypedef->get_true_type());
+  generate_annotations(ttypedef->annotations_);
+  write_element_end();
+  return;
+}
+
+void t_xml_generator::write_type(t_type* ttype) {
+  const string type = get_type_name(ttype);
+  write_attribute("type", type);
+  if (type == "id") {
+    write_attribute("type-module", ttype->get_program()->get_name());
+    write_attribute("type-id", ttype->get_name());
+  } else if (type == "list") {
+    t_type* etype = ((t_list*)ttype)->get_elem_type();
+    write_element_start("elemType");
+    write_type(etype);
+    write_element_end();
+  } else if (type == "set") {
+    t_type* etype = ((t_set*)ttype)->get_elem_type();
+    write_element_start("elemType");
+    write_type(etype);
+    write_element_end();
+  } else if (type == "map") {
+    t_type* ktype = ((t_map*)ttype)->get_key_type();
+    write_element_start("keyType");
+    write_type(ktype);
+    write_element_end();
+    t_type* vtype = ((t_map*)ttype)->get_val_type();
+    write_element_start("valueType");
+    write_type(vtype);
+    write_element_end();
+  }
+}
+
+void t_xml_generator::write_doc(t_doc* tdoc) {
+  if (tdoc->has_doc()) {
+    string doc = tdoc->get_doc();
+    // for some reason there always seems to be a trailing newline on doc
+    // comments; loop below naively tries to strip off trailing cr/lf
+    int n = 0;
+    for (string::reverse_iterator i = doc.rbegin(); i != doc.rend(); i++,n++) {
+      if (*i != '\n' || *i == '\r') {
+        if (n > 0) {
+          doc.erase(doc.length() - n);
+        }
+        break;
+      }
+    }
+    write_attribute("doc", doc);
+  }
+}
+
+void t_xml_generator::generate_annotations(
+    std::map<std::string, std::string> annotations) {
+  std::map<std::string, std::string>::iterator iter;
+  for (iter = annotations.begin(); iter != annotations.end(); ++iter) {
+    write_element_start("annotation");
+    write_attribute("key", iter->first);
+    write_attribute("value", iter->second);
+    write_element_end();
+  }
+}
+
+void t_xml_generator::generate_constant(t_const* con) {
+  write_element_start("const");
+  write_attribute("name", con->get_name());
+  write_doc(con);
+  write_type(con->get_type());
+  write_const_value(con->get_value());
+  write_element_end();
+}
+
+void t_xml_generator::write_const_value(t_const_value* value) {
+
+  switch (value->get_type()) {
+
+  case t_const_value::CV_IDENTIFIER:
+  case t_const_value::CV_INTEGER:
+    write_element_number("int", value->get_integer());
+    break;
+
+  case t_const_value::CV_DOUBLE:
+    write_element_number("double", value->get_double());
+    break;
+
+  case t_const_value::CV_STRING:
+    write_element_string("string", value->get_string());
+    break;
+
+  case t_const_value::CV_LIST: {
+    write_element_start("list");
+    std::vector<t_const_value*> list = value->get_list();
+    std::vector<t_const_value*>::iterator lit;
+    for (lit = list.begin(); lit != list.end(); ++lit) {
+      write_element_start("entry");
+      write_const_value(*lit);
+      write_element_end();
+    }
+    write_element_end();
+    break;
+  }
+
+  case t_const_value::CV_MAP: {
+    write_element_start("map");
+    std::map<t_const_value*, t_const_value*, t_const_value::value_compare> map = value->get_map();
+    std::map<t_const_value*, t_const_value*, t_const_value::value_compare>::iterator mit;
+    for (mit = map.begin(); mit != map.end(); ++mit) {
+      write_element_start("entry");
+      write_element_start("key");
+      write_const_value(mit->first);
+      write_element_end();
+      write_element_start("value");
+      write_const_value(mit->second);
+      write_element_end();
+      write_element_end();
+    }
+    write_element_end();
+    break;
+  }
+
+  default:
+    indent_up();
+    f_xml_ << indent() << "<null />" << endl;
+    indent_down();
+    break;
+  }
+
+}
+
+void t_xml_generator::generate_enum(t_enum* tenum) {
+
+  write_element_start("enum");
+  write_attribute("name", tenum->get_name());
+  write_doc(tenum);
+
+  vector<t_enum_value*> values = tenum->get_constants();
+  vector<t_enum_value*>::iterator val_iter;
+  for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) {
+    t_enum_value* val = (*val_iter);
+    write_element_start("member");
+    write_attribute("name", val->get_name());
+    write_int_attribute("value", val->get_value());
+    write_doc(val);
+    generate_annotations(val->annotations_);
+    write_element_end();
+  }
+
+  generate_annotations(tenum->annotations_);
+
+  write_element_end();
+
+}
+
+void t_xml_generator::generate_struct(t_struct* tstruct) {
+
+  string tagname = "struct";
+  if (tstruct->is_union()) {
+    tagname = "union";
+  } else if (tstruct->is_xception()) {
+    tagname = "exception";
+  }
+
+  write_element_start(tagname);
+  write_attribute("name", tstruct->get_name());
+  write_doc(tstruct);
+  vector<t_field*> members = tstruct->get_members();
+  vector<t_field*>::iterator mem_iter;
+  for (mem_iter = members.begin(); mem_iter != members.end(); mem_iter++) {
+    write_element_start("field");
+    generate_field(*mem_iter);
+    write_element_end();
+  }
+
+  generate_annotations(tstruct->annotations_);
+
+  write_element_end();
+
+}
+
+void t_xml_generator::generate_field(t_field* field) {
+  write_attribute("name", field->get_name());
+  write_int_attribute("field-id", field->get_key());
+  write_doc(field);
+  string requiredness;
+  switch (field->get_req()) {
+  case t_field::T_REQUIRED:
+    requiredness = "required";
+    break;
+  case t_field::T_OPTIONAL:
+    requiredness = "optional";
+    break;
+  default:
+    requiredness = "";
+    break;
+  }
+  if (requiredness != "") {
+    write_attribute("required", requiredness);
+  }
+  write_type(field->get_type());
+  if (field->get_value()) {
+    write_element_start("default");
+    write_const_value(field->get_value());
+    write_element_end();
+  }
+  generate_annotations(field->annotations_);
+}
+
+void t_xml_generator::generate_service(t_service* tservice) {
+
+  write_element_start("service");
+  write_attribute("name", tservice->get_name());
+
+  if (should_use_namespaces_) {
+    string prog_ns = target_namespace(tservice->get_program());
+    if (*prog_ns.rbegin() != '/') {
+      prog_ns.push_back('/');
+    }
+    const string tns = prog_ns + tservice->get_name();
+    write_attribute("targetNamespace", tns);
+    write_attribute("xmlns:tns", tns);
+  }
+
+  if (tservice->get_extends()) {
+    const t_service* extends = tservice->get_extends();
+    write_attribute("parent-module", extends->get_program()->get_name());
+    write_attribute("parent-id", extends->get_name());
+  }
+
+  write_doc(tservice);
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator fn_iter = functions.begin();
+  for (; fn_iter != functions.end(); fn_iter++) {
+    generate_function(*fn_iter);
+  }
+
+  generate_annotations(tservice->annotations_);
+
+  write_element_end();
+
+}
+
+void t_xml_generator::generate_function(t_function* tfunc) {
+
+  write_element_start("method");
+
+  write_attribute("name", tfunc->get_name());
+  if (tfunc->is_oneway()) {
+    write_attribute("oneway", "true");
+  }
+
+  write_doc(tfunc);
+
+  write_element_start("returns");
+  write_type(tfunc->get_returntype());
+  write_element_end();
+
+  vector<t_field*> members = tfunc->get_arglist()->get_members();
+  vector<t_field*>::iterator mem_iter = members.begin();
+  for (; mem_iter != members.end(); mem_iter++) {
+    write_element_start("arg");
+    generate_field(*mem_iter);
+    write_element_end();
+  }
+
+  vector<t_field*> excepts = tfunc->get_xceptions()->get_members();
+  vector<t_field*>::iterator ex_iter = excepts.begin();
+  for (; ex_iter != excepts.end(); ex_iter++) {
+    write_element_start("throws");
+    generate_field(*ex_iter);
+    write_element_end();
+  }
+
+  generate_annotations(tfunc->annotations_);
+
+  write_element_end();
+
+}
+
+string t_xml_generator::get_type_name(t_type* ttype) {
+  if (ttype->is_list()) {
+    return "list";
+  }
+  if (ttype->is_set()) {
+    return "set";
+  }
+  if (ttype->is_map()) {
+    return "map";
+  }
+  if ((ttype->is_enum()    )||
+      (ttype->is_struct()  )||
+      (ttype->is_typedef() )||
+      (ttype->is_xception())){
+    return "id";
+  }
+  if (ttype->is_base_type()) {
+    t_base_type* tbasetype = (t_base_type*)ttype;
+    if (tbasetype->is_binary() ) {
+      return "binary";
+    }
+    return t_base_type::t_base_name(tbasetype->get_base());
+  }
+  return "(unknown)";
+}
+
+THRIFT_REGISTER_GENERATOR(
+  xml,
+  "XML",
+  "    merge:           Generate output with included files merged\n"
+  "    no_default_ns:   Omit default xmlns and add idl: prefix to all elements\n"
+  "    no_namespaces:   Do not add namespace definitions to the XML model\n")
diff --git a/compiler/cpp/src/thrift/generate/t_xsd_generator.cc b/compiler/cpp/src/thrift/generate/t_xsd_generator.cc
new file mode 100644
index 0000000..e487ffc
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_xsd_generator.cc
@@ -0,0 +1,376 @@
+/*
+ * 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.
+ */
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sstream>
+#include "thrift/version.h"
+#include "thrift/platform.h"
+#include "thrift/generate/t_generator.h"
+
+using std::map;
+using std::ofstream;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+/**
+ * XSD generator, creates an XSD for the base types etc.
+ *
+ */
+class t_xsd_generator : public t_generator {
+public:
+  t_xsd_generator(t_program* program,
+                  const std::map<std::string, std::string>& parsed_options,
+                  const std::string& option_string)
+    : t_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    /* no options yet */
+    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      throw "unknown option xsd:" + iter->first;
+    }
+
+    out_dir_base_ = "gen-xsd";
+  }
+
+  virtual ~t_xsd_generator() {}
+
+  /**
+   * 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)tenum; }
+
+  void generate_service(t_service* tservice);
+  void generate_struct(t_struct* tstruct);
+
+private:
+  void generate_element(std::ostream& out,
+                        std::string name,
+                        t_type* ttype,
+                        t_struct* attrs = NULL,
+                        bool optional = false,
+                        bool nillable = false,
+                        bool list_element = false);
+
+  std::string ns(std::string in, std::string ns) { return ns + ":" + in; }
+
+  std::string xsd(std::string in) { return ns(in, "xsd"); }
+
+  std::string type_name(t_type* ttype);
+  std::string base_type_name(t_base_type::t_base tbase);
+
+  virtual std::string xml_autogen_comment() {
+    return std::string("<!--\n") + " * Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
+           + " *\n" + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n"
+           + " -->\n";
+  }
+
+  /**
+   * Output xsd/php file
+   */
+  ofstream_with_content_based_conditional_update f_xsd_;
+  ofstream_with_content_based_conditional_update f_php_;
+
+  /**
+   * Output string stream
+   */
+  std::ostringstream s_xsd_types_;
+};
+
+void t_xsd_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  // Make output file
+  string f_php_name = get_out_dir() + program_->get_name() + "_xsd.php";
+  f_php_.open(f_php_name.c_str());
+
+  f_php_ << "<?php" << endl
+         << autogen_comment() << endl;
+}
+
+void t_xsd_generator::close_generator() {
+  f_php_ << "?>" << endl;
+  f_php_.close();
+}
+
+void t_xsd_generator::generate_typedef(t_typedef* ttypedef) {
+  indent(s_xsd_types_) << "<xsd:simpleType name=\"" << ttypedef->get_name() << "\">" << endl;
+  indent_up();
+  if (ttypedef->get_type()->is_string() && ((t_base_type*)ttypedef->get_type())->is_string_enum()) {
+    indent(s_xsd_types_) << "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\">"
+                         << endl;
+    indent_up();
+    const vector<string>& values = ((t_base_type*)ttypedef->get_type())->get_string_enum_vals();
+    vector<string>::const_iterator v_iter;
+    for (v_iter = values.begin(); v_iter != values.end(); ++v_iter) {
+      indent(s_xsd_types_) << "<xsd:enumeration value=\"" << (*v_iter) << "\" />" << endl;
+    }
+    indent_down();
+    indent(s_xsd_types_) << "</xsd:restriction>" << endl;
+  } else {
+    indent(s_xsd_types_) << "<xsd:restriction base=\"" << type_name(ttypedef->get_type()) << "\" />"
+                         << endl;
+  }
+  indent_down();
+  indent(s_xsd_types_) << "</xsd:simpleType>" << endl << endl;
+}
+
+void t_xsd_generator::generate_struct(t_struct* tstruct) {
+  vector<t_field*>::const_iterator m_iter;
+  const vector<t_field*>& members = tstruct->get_members();
+  bool xsd_all = tstruct->get_xsd_all();
+
+  indent(s_xsd_types_) << "<xsd:complexType name=\"" << tstruct->get_name() << "\">" << endl;
+  indent_up();
+  if (xsd_all) {
+    indent(s_xsd_types_) << "<xsd:all>" << endl;
+  } else {
+    indent(s_xsd_types_) << "<xsd:sequence>" << endl;
+  }
+  indent_up();
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    generate_element(s_xsd_types_,
+                     (*m_iter)->get_name(),
+                     (*m_iter)->get_type(),
+                     (*m_iter)->get_xsd_attrs(),
+                     (*m_iter)->get_xsd_optional() || xsd_all,
+                     (*m_iter)->get_xsd_nillable());
+  }
+
+  indent_down();
+  if (xsd_all) {
+    indent(s_xsd_types_) << "</xsd:all>" << endl;
+  } else {
+    indent(s_xsd_types_) << "</xsd:sequence>" << endl;
+  }
+  indent_down();
+  indent(s_xsd_types_) << "</xsd:complexType>" << endl << endl;
+}
+
+void t_xsd_generator::generate_element(ostream& out,
+                                       string name,
+                                       t_type* ttype,
+                                       t_struct* attrs,
+                                       bool optional,
+                                       bool nillable,
+                                       bool list_element) {
+  string sminOccurs = (optional || list_element) ? " minOccurs=\"0\"" : "";
+  string smaxOccurs = list_element ? " maxOccurs=\"unbounded\"" : "";
+  string soptional = sminOccurs + smaxOccurs;
+  string snillable = nillable ? " nillable=\"true\"" : "";
+
+  if (ttype->is_void() || ttype->is_list()) {
+    indent(out) << "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">" << endl;
+    indent_up();
+    if (attrs == NULL && ttype->is_void()) {
+      indent(out) << "<xsd:complexType />" << endl;
+    } else {
+      indent(out) << "<xsd:complexType>" << endl;
+      indent_up();
+      if (ttype->is_list()) {
+        indent(out) << "<xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">" << endl;
+        indent_up();
+        string subname;
+        t_type* subtype = ((t_list*)ttype)->get_elem_type();
+        if (subtype->is_base_type() || subtype->is_container()) {
+          subname = name + "_elt";
+        } else {
+          subname = type_name(subtype);
+        }
+        f_php_ << "$GLOBALS['" << program_->get_name() << "_xsd_elt_" << name << "'] = '" << subname
+               << "';" << endl;
+        generate_element(out, subname, subtype, NULL, false, false, true);
+        indent_down();
+        indent(out) << "</xsd:sequence>" << endl;
+        indent(out) << "<xsd:attribute name=\"list\" type=\"xsd:boolean\" />" << endl;
+      }
+      if (attrs != NULL) {
+        const vector<t_field*>& members = attrs->get_members();
+        vector<t_field*>::const_iterator a_iter;
+        for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
+          indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\""
+                      << type_name((*a_iter)->get_type()) << "\" />" << endl;
+        }
+      }
+      indent_down();
+      indent(out) << "</xsd:complexType>" << endl;
+    }
+    indent_down();
+    indent(out) << "</xsd:element>" << endl;
+  } else {
+    if (attrs == NULL) {
+      indent(out) << "<xsd:element name=\"" << name << "\""
+                  << " type=\"" << type_name(ttype) << "\"" << soptional << snillable << " />"
+                  << endl;
+    } else {
+      // Wow, all this work for a SIMPLE TYPE with attributes?!?!?!
+      indent(out) << "<xsd:element name=\"" << name << "\"" << soptional << snillable << ">"
+                  << endl;
+      indent_up();
+      indent(out) << "<xsd:complexType>" << endl;
+      indent_up();
+      indent(out) << "<xsd:complexContent>" << endl;
+      indent_up();
+      indent(out) << "<xsd:extension base=\"" << type_name(ttype) << "\">" << endl;
+      indent_up();
+      const vector<t_field*>& members = attrs->get_members();
+      vector<t_field*>::const_iterator a_iter;
+      for (a_iter = members.begin(); a_iter != members.end(); ++a_iter) {
+        indent(out) << "<xsd:attribute name=\"" << (*a_iter)->get_name() << "\" type=\""
+                    << type_name((*a_iter)->get_type()) << "\" />" << endl;
+      }
+      indent_down();
+      indent(out) << "</xsd:extension>" << endl;
+      indent_down();
+      indent(out) << "</xsd:complexContent>" << endl;
+      indent_down();
+      indent(out) << "</xsd:complexType>" << endl;
+      indent_down();
+      indent(out) << "</xsd:element>" << endl;
+    }
+  }
+}
+
+
+void t_xsd_generator::generate_service(t_service* tservice) {
+  // Make output file
+  string f_xsd_name = get_out_dir() + tservice->get_name() + ".xsd";
+  f_xsd_.open(f_xsd_name.c_str());
+
+  string ns = program_->get_namespace("xsd");
+  const std::map<std::string, std::string> annot = program_->get_namespace_annotations("xsd");
+  const std::map<std::string, std::string>::const_iterator uri = annot.find("uri");
+  if (uri != annot.end()) {
+    ns = uri->second;
+  }
+  if (ns.size() > 0) {
+    ns = " targetNamespace=\"" + ns + "\" xmlns=\"" + ns + "\" "
+         + "elementFormDefault=\"qualified\"";
+  }
+
+  // Print the XSD header
+  f_xsd_ << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" << endl
+         << "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" << ns << ">" << endl
+         << xml_autogen_comment()
+         << endl;
+
+  // Print out the type definitions
+  indent(f_xsd_) << s_xsd_types_.str();
+
+  // Keep a list of all the possible exceptions that might get thrown
+  map<string, t_struct*> all_xceptions;
+
+  // List the elements that you might actually get
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string elemname = (*f_iter)->get_name() + "_response";
+    t_type* returntype = (*f_iter)->get_returntype();
+    generate_element(f_xsd_, elemname, returntype);
+    f_xsd_ << 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) {
+      all_xceptions[(*x_iter)->get_name()] = (t_struct*)((*x_iter)->get_type());
+    }
+  }
+
+  map<string, t_struct*>::iterator ax_iter;
+  for (ax_iter = all_xceptions.begin(); ax_iter != all_xceptions.end(); ++ax_iter) {
+    generate_element(f_xsd_, ax_iter->first, ax_iter->second);
+  }
+
+  // Close the XSD document
+  f_xsd_ << endl << "</xsd:schema>" << endl;
+  f_xsd_.close();
+}
+
+string t_xsd_generator::type_name(t_type* ttype) {
+  if (ttype->is_typedef()) {
+    return ttype->get_name();
+  }
+
+  if (ttype->is_base_type()) {
+    return xsd(base_type_name(((t_base_type*)ttype)->get_base()));
+  }
+
+  if (ttype->is_enum()) {
+    return xsd("int");
+  }
+
+  if (ttype->is_struct() || ttype->is_xception()) {
+    return ttype->get_name();
+  }
+
+  return "container";
+}
+
+/**
+ * Returns the XSD type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ * @return Explicit XSD type, i.e. xsd:string
+ */
+string t_xsd_generator::base_type_name(t_base_type::t_base tbase) {
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    return "string";
+  case t_base_type::TYPE_BOOL:
+    return "boolean";
+  case t_base_type::TYPE_I8:
+    return "byte";
+  case t_base_type::TYPE_I16:
+    return "short";
+  case t_base_type::TYPE_I32:
+    return "int";
+  case t_base_type::TYPE_I64:
+    return "long";
+  case t_base_type::TYPE_DOUBLE:
+    return "decimal";
+  default:
+    throw "compiler error: no XSD base type name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+THRIFT_REGISTER_GENERATOR(xsd, "XSD", "")
diff --git a/compiler/cpp/README b/compiler/cpp/src/thrift/generate/thrift-t_php_generator.o-a60a38e9
similarity index 100%
rename from compiler/cpp/README
rename to compiler/cpp/src/thrift/generate/thrift-t_php_generator.o-a60a38e9
diff --git a/compiler/cpp/src/thrift/globals.h b/compiler/cpp/src/thrift/globals.h
new file mode 100644
index 0000000..961c6ef
--- /dev/null
+++ b/compiler/cpp/src/thrift/globals.h
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+#ifndef T_GLOBALS_H
+#define T_GLOBALS_H
+
+#include <set>
+#include <queue>
+#include <stack>
+#include <vector>
+#include <string>
+
+/**
+ * This module contains all the global variables (slap on the wrist) that are
+ * shared throughout the program. The reason for this is to facilitate simple
+ * interaction between the parser and the rest of the program. Before calling
+ * yyparse(), the main.cc program will make necessary adjustments to these
+ * global variables such that the parser does the right thing and puts entries
+ * into the right containers, etc.
+ *
+ */
+
+/**
+ * Hooray for forward declaration of types!
+ */
+
+class t_program;
+class t_scope;
+class t_type;
+
+/**
+ * Parsing mode, two passes up in this gin rummy!
+ */
+
+enum PARSE_MODE { INCLUDES = 1, PROGRAM = 2 };
+
+/**
+ * Strictness level
+ */
+extern int g_strict;
+
+/**
+ * The master program parse tree. This is accessed from within the parser code
+ * to build up the program elements.
+ */
+extern t_program* g_program;
+
+/**
+ * The scope that we are currently parsing into
+ */
+extern t_scope* g_scope;
+
+/**
+ * The parent scope to also load symbols into
+ */
+extern t_scope* g_parent_scope;
+
+/**
+ * The prefix for the parent scope entries
+ */
+extern std::string g_parent_prefix;
+
+/**
+ * The parsing pass that we are on. We do different things on each pass.
+ */
+extern PARSE_MODE g_parse_mode;
+
+/**
+ * Global time string, used in formatting error messages etc.
+ */
+extern char* g_time_str;
+
+/**
+ * The last parsed doctext comment.
+ */
+extern char* g_doctext;
+
+/**
+ * The location of the last parsed doctext comment.
+ */
+extern int g_doctext_lineno;
+
+/**
+ * Status of program level doctext candidate
+ */
+enum PROGDOCTEXT_STATUS {
+  INVALID = 0,
+  STILL_CANDIDATE = 1,   // the text may or may not be the program doctext
+  ALREADY_PROCESSED = 2, // doctext has been used and is no longer available
+  ABSOLUTELY_SURE = 3,   // this is the program doctext
+  NO_PROGRAM_DOCTEXT = 4 // there is no program doctext
+};
+
+/**
+ * The program level doctext. Stored separately to make parsing easier.
+ */
+extern char* g_program_doctext_candidate;
+extern int g_program_doctext_lineno;
+extern PROGDOCTEXT_STATUS g_program_doctext_status;
+
+/**
+ * Whether or not negative field keys are accepted.
+ *
+ * When a field does not have a user-specified key, thrift automatically
+ * assigns a negative value.  However, this is fragile since changes to the
+ * file may unintentionally change the key numbering, resulting in a new
+ * protocol that is not backwards compatible.
+ *
+ * When g_allow_neg_field_keys is enabled, users can explicitly specify
+ * negative keys.  This way they can write a .thrift file with explicitly
+ * specified keys that is still backwards compatible with older .thrift files
+ * that did not specify key values.
+ */
+extern int g_allow_neg_field_keys;
+
+/**
+ * Whether or not 64-bit constants will generate a warning.
+ *
+ * Some languages don't support 64-bit constants, but many do, so we can
+ * suppress this warning for projects that don't use any non-64-bit-safe
+ * languages.
+ */
+extern int g_allow_64bit_consts;
+
+#endif
diff --git a/compiler/cpp/src/thrift/logging.cc b/compiler/cpp/src/thrift/logging.cc
new file mode 100644
index 0000000..f821f5f
--- /dev/null
+++ b/compiler/cpp/src/thrift/logging.cc
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Logging functions copied from main.cc to avoid link errors for plugins
+ */
+
+#include "thrift/logging.h"
+#include "thrift/globals.h"
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+
+// TODO: make plugins accept log options from main compiler
+int g_debug = 0;
+int g_warn = 1;
+int g_verbose = 0;
+
+void pdebug(const char* fmt, ...) {
+  if (g_debug == 0) {
+    return;
+  }
+  va_list args;
+  // printf("[PARSE:%d] ", yylineno);
+  va_start(args, fmt);
+  vprintf(fmt, args);
+  va_end(args);
+  printf("\n");
+}
+
+void pverbose(const char* fmt, ...) {
+  if (g_verbose == 0) {
+    return;
+  }
+  va_list args;
+  va_start(args, fmt);
+  vprintf(fmt, args);
+  va_end(args);
+}
+
+void pwarning(int level, const char* fmt, ...) {
+  if (g_warn < level) {
+    return;
+  }
+  va_list args;
+  // printf("[WARNING:%s:%d] ", g_curpath.c_str(), yylineno);
+  va_start(args, fmt);
+  vprintf(fmt, args);
+  va_end(args);
+  printf("\n");
+}
+
+void failure(const char* fmt, ...) {
+  va_list args;
+  // fprintf(stderr, "[FAILURE:%s:%d] ", g_curpath.c_str(), yylineno);
+  va_start(args, fmt);
+  vfprintf(stderr, fmt, args);
+  va_end(args);
+  printf("\n");
+  exit(1);
+}
diff --git a/compiler/cpp/src/thrift/logging.h b/compiler/cpp/src/thrift/logging.h
new file mode 100644
index 0000000..ebefbf2
--- /dev/null
+++ b/compiler/cpp/src/thrift/logging.h
@@ -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.
+ */
+
+#ifndef T_LOGGING_H
+#define T_LOGGING_H
+
+extern int g_debug;
+extern int g_warn;
+extern int g_verbose;
+
+/**
+ * Parse debugging output, used to print helpful info
+ */
+void pdebug(const char* fmt, ...);
+
+/**
+ * Parser warning
+ */
+void pwarning(int level, const char* fmt, ...);
+
+/**
+ * Print verbose output message
+ */
+void pverbose(const char* fmt, ...);
+
+/**
+ * Failure!
+ */
+void failure(const char* fmt, ...);
+
+#endif
diff --git a/compiler/cpp/src/thrift/main.cc b/compiler/cpp/src/thrift/main.cc
new file mode 100644
index 0000000..cdc171c
--- /dev/null
+++ b/compiler/cpp/src/thrift/main.cc
@@ -0,0 +1,1308 @@
+/*
+ * 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.
+ */
+
+/**
+ * thrift - a lightweight cross-language rpc/serialization tool
+ *
+ * This file contains the main compiler engine for Thrift, which invokes the
+ * scanner/parser to build the thrift object tree. The interface generation
+ * code for each language lives in a file by the language name under the
+ * generate/ folder, and all parse structures live in parse/
+ *
+ */
+
+#include <cassert>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string>
+#include <algorithm>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+
+#ifdef _WIN32
+#include <windows.h> /* for GetFullPathName */
+#endif
+
+// Careful: must include globals first for extern definitions
+#include "thrift/common.h"
+#include "thrift/globals.h"
+
+#include "thrift/platform.h"
+#include "thrift/main.h"
+#include "thrift/parse/t_program.h"
+#include "thrift/parse/t_scope.h"
+#include "thrift/generate/t_generator.h"
+#include "thrift/audit/t_audit.h"
+#ifdef THRIFT_ENABLE_PLUGIN
+#include "thrift/plugin/plugin_output.h"
+#endif
+
+#include "thrift/version.h"
+
+using namespace std;
+
+/**
+ * Global program tree
+ */
+t_program* g_program;
+
+/**
+ * Global scope
+ */
+t_scope* g_scope;
+
+/**
+ * Parent scope to also parse types
+ */
+t_scope* g_parent_scope;
+
+/**
+ * Prefix for putting types in parent scope
+ */
+string g_parent_prefix;
+
+/**
+ * Parsing pass
+ */
+PARSE_MODE g_parse_mode;
+
+/**
+ * Current directory of file being parsed
+ */
+string g_curdir;
+
+/**
+ * Current file being parsed
+ */
+string g_curpath;
+
+/**
+ * Search path for inclusions
+ */
+vector<string> g_incl_searchpath;
+
+/**
+ * Global debug state
+ */
+int g_debug = 0;
+
+/**
+ * Strictness level
+ */
+int g_strict = 127;
+
+/**
+ * Warning level
+ */
+int g_warn = 1;
+
+/**
+ * Verbose output
+ */
+int g_verbose = 0;
+
+/**
+ * Global time string
+ */
+char* g_time_str;
+
+/**
+ * The last parsed doctext comment.
+ */
+char* g_doctext;
+
+/**
+ * The First doctext comment
+ */
+char* g_program_doctext_candidate;
+
+/**
+ * Whether or not negative field keys are accepted.
+ */
+int g_allow_neg_field_keys;
+
+/**
+ * Whether or not 64-bit constants will generate a warning.
+ */
+int g_allow_64bit_consts = 0;
+
+/**
+ * Flags to control code generation
+ */
+bool gen_recurse = false;
+
+/**
+ * Flags to control thrift audit
+ */
+bool g_audit = false;
+
+/**
+ * Flag to control return status
+ */
+bool g_return_failure = false;
+bool g_audit_fatal = true;
+bool g_generator_failure = false;
+
+/**
+ * Win32 doesn't have realpath, so use fallback implementation in that case,
+ * otherwise this just calls through to realpath
+ */
+char* saferealpath(const char* path, char* resolved_path) {
+#ifdef _WIN32
+  char buf[MAX_PATH];
+  char* basename;
+  DWORD len = GetFullPathName(path, MAX_PATH, buf, &basename);
+  if (len == 0 || len > MAX_PATH - 1) {
+    strcpy(resolved_path, path);
+  } else {
+    strcpy(resolved_path, buf);
+  }
+
+  // Replace backslashes with forward slashes so the
+  // rest of the code behaves correctly.
+  size_t resolved_len = strlen(resolved_path);
+  for (size_t i = 0; i < resolved_len; i++) {
+    if (resolved_path[i] == '\\') {
+      resolved_path[i] = '/';
+    }
+  }
+  return resolved_path;
+#else
+  return realpath(path, resolved_path);
+#endif
+}
+
+bool check_is_directory(const char* dir_name) {
+#ifdef _WIN32
+  DWORD attributes = ::GetFileAttributesA(dir_name);
+  if (attributes == INVALID_FILE_ATTRIBUTES) {
+    fprintf(stderr,
+            "Output directory %s is unusable: GetLastError() = %ld\n",
+            dir_name,
+            GetLastError());
+    return false;
+  }
+  if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) {
+    fprintf(stderr, "Output directory %s exists but is not a directory\n", dir_name);
+    return false;
+  }
+  return true;
+#else
+  struct stat sb;
+  if (stat(dir_name, &sb) < 0) {
+    fprintf(stderr, "Output directory %s is unusable: %s\n", dir_name, strerror(errno));
+    return false;
+  }
+  if (!S_ISDIR(sb.st_mode)) {
+    fprintf(stderr, "Output directory %s exists but is not a directory\n", dir_name);
+    return false;
+  }
+  return true;
+#endif
+}
+
+/**
+ * Report an error to the user. This is called yyerror for historical
+ * reasons (lex and yacc expect the error reporting routine to be called
+ * this). Call this function to report any errors to the user.
+ * yyerror takes printf style arguments.
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void yyerror(const char* fmt, ...) {
+  va_list args;
+  fprintf(stderr, "[ERROR:%s:%d] (last token was '%s')\n", g_curpath.c_str(), yylineno, yytext);
+
+  va_start(args, fmt);
+  vfprintf(stderr, fmt, args);
+  va_end(args);
+
+  fprintf(stderr, "\n");
+}
+
+/**
+ * Prints a debug message from the parser.
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void pdebug(const char* fmt, ...) {
+  if (g_debug == 0) {
+    return;
+  }
+  va_list args;
+  printf("[PARSE:%d] ", yylineno);
+  va_start(args, fmt);
+  vprintf(fmt, args);
+  va_end(args);
+  printf("\n");
+}
+
+/**
+ * Prints a verbose output mode message
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void pverbose(const char* fmt, ...) {
+  if (g_verbose == 0) {
+    return;
+  }
+  va_list args;
+  va_start(args, fmt);
+  vprintf(fmt, args);
+  va_end(args);
+}
+
+/**
+ * Prints a warning message
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void pwarning(int level, const char* fmt, ...) {
+  if (g_warn < level) {
+    return;
+  }
+  va_list args;
+  printf("[WARNING:%s:%d] ", g_curpath.c_str(), yylineno);
+  va_start(args, fmt);
+  vprintf(fmt, args);
+  va_end(args);
+  printf("\n");
+}
+
+/**
+ * Prints a failure message and exits
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void failure(const char* fmt, ...) {
+  va_list args;
+  fprintf(stderr, "[FAILURE:%s:%d] ", g_curpath.c_str(), yylineno);
+  va_start(args, fmt);
+  vfprintf(stderr, fmt, args);
+  va_end(args);
+  printf("\n");
+  exit(1);
+}
+
+/**
+ * Converts a string filename into a thrift program name
+ */
+string program_name(string filename) {
+  string::size_type slash = filename.rfind("/");
+  if (slash != string::npos) {
+    filename = filename.substr(slash + 1);
+  }
+  string::size_type dot = filename.rfind(".");
+  if (dot != string::npos) {
+    filename = filename.substr(0, dot);
+  }
+  return filename;
+}
+
+/**
+ * Gets the directory path of a filename
+ */
+string directory_name(string filename) {
+  string::size_type slash = filename.rfind("/");
+  // No slash, just use the current directory
+  if (slash == string::npos) {
+    return ".";
+  }
+  return filename.substr(0, slash);
+}
+
+/**
+ * Finds the appropriate file path for the given filename
+ */
+string include_file(string filename) {
+  // Absolute path? Just try that
+  if (filename[0] == '/') {
+    // Realpath!
+    char rp[THRIFT_PATH_MAX];
+    // cppcheck-suppress uninitvar
+    if (saferealpath(filename.c_str(), rp) == NULL) {
+      pwarning(0, "Cannot open include file %s\n", filename.c_str());
+      return std::string();
+    }
+
+    // Stat this file
+    struct stat finfo;
+    if (stat(rp, &finfo) == 0) {
+      return rp;
+    }
+  } else { // relative path, start searching
+    // new search path with current dir global
+    vector<string> sp = g_incl_searchpath;
+    sp.insert(sp.begin(), g_curdir);
+
+    // iterate through paths
+    vector<string>::iterator it;
+    for (it = sp.begin(); it != sp.end(); it++) {
+      string sfilename = *(it) + "/" + filename;
+
+      // Realpath!
+      char rp[THRIFT_PATH_MAX];
+      // cppcheck-suppress uninitvar
+      if (saferealpath(sfilename.c_str(), rp) == NULL) {
+        continue;
+      }
+
+      // Stat this files
+      struct stat finfo;
+      if (stat(rp, &finfo) == 0) {
+        return rp;
+      }
+    }
+  }
+
+  // Uh oh
+  pwarning(0, "Could not find include file %s\n", filename.c_str());
+  return std::string();
+}
+
+/**
+ * Clears any previously stored doctext string.
+ * Also prints a warning if we are discarding information.
+ */
+void clear_doctext() {
+  if (g_doctext != NULL) {
+    pwarning(2, "Uncaptured doctext at on line %d.", g_doctext_lineno);
+  }
+  free(g_doctext);
+  g_doctext = NULL;
+}
+
+/**
+ * Reset program doctext information after processing a file
+ */
+void reset_program_doctext_info() {
+  if (g_program_doctext_candidate != NULL) {
+    free(g_program_doctext_candidate);
+    g_program_doctext_candidate = NULL;
+  }
+  g_program_doctext_lineno = 0;
+  g_program_doctext_status = INVALID;
+  pdebug("%s", "program doctext set to INVALID");
+}
+
+/**
+ * We are sure the program doctext candidate is really the program doctext.
+ */
+void declare_valid_program_doctext() {
+  if ((g_program_doctext_candidate != NULL) && (g_program_doctext_status == STILL_CANDIDATE)) {
+    g_program_doctext_status = ABSOLUTELY_SURE;
+    pdebug("%s", "program doctext set to ABSOLUTELY_SURE");
+  } else {
+    g_program_doctext_status = NO_PROGRAM_DOCTEXT;
+    pdebug("%s", "program doctext set to NO_PROGRAM_DOCTEXT");
+  }
+}
+
+/**
+ * Cleans up text commonly found in doxygen-like comments
+ *
+ * Warning: if you mix tabs and spaces in a non-uniform way,
+ * you will get what you deserve.
+ */
+char* clean_up_doctext(char* doctext) {
+  // Convert to C++ string, and remove Windows's carriage returns.
+  string docstring = doctext;
+  docstring.erase(remove(docstring.begin(), docstring.end(), '\r'), docstring.end());
+
+  // Separate into lines.
+  vector<string> lines;
+  string::size_type pos = string::npos;
+  string::size_type last;
+  while (true) {
+    last = (pos == string::npos) ? 0 : pos + 1;
+    pos = docstring.find('\n', last);
+    if (pos == string::npos) {
+      // First bit of cleaning.  If the last line is only whitespace, drop it.
+      string::size_type nonwhite = docstring.find_first_not_of(" \t", last);
+      if (nonwhite != string::npos) {
+        lines.push_back(docstring.substr(last));
+      }
+      break;
+    }
+    lines.push_back(docstring.substr(last, pos - last));
+  }
+
+  // A very profound docstring.
+  if (lines.empty()) {
+    return NULL;
+  }
+
+  // Clear leading whitespace from the first line.
+  pos = lines.front().find_first_not_of(" \t");
+  lines.front().erase(0, pos);
+
+  // If every nonblank line after the first has the same number of spaces/tabs,
+  // then a star, remove them.
+  bool have_prefix = true;
+  bool found_prefix = false;
+  string::size_type prefix_len = 0;
+  vector<string>::iterator l_iter;
+  for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) {
+    if (l_iter->empty()) {
+      continue;
+    }
+
+    pos = l_iter->find_first_not_of(" \t");
+    if (!found_prefix) {
+      if (pos != string::npos) {
+        if (l_iter->at(pos) == '*') {
+          found_prefix = true;
+          prefix_len = pos;
+        } else {
+          have_prefix = false;
+          break;
+        }
+      } else {
+        // Whitespace-only line.  Truncate it.
+        l_iter->clear();
+      }
+    } else if (l_iter->size() > pos && l_iter->at(pos) == '*' && pos == prefix_len) {
+      // Business as usual.
+    } else if (pos == string::npos) {
+      // Whitespace-only line.  Let's truncate it for them.
+      l_iter->clear();
+    } else {
+      // The pattern has been broken.
+      have_prefix = false;
+      break;
+    }
+  }
+
+  // If our prefix survived, delete it from every line.
+  if (have_prefix) {
+    // Get the star too.
+    prefix_len++;
+    for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) {
+      l_iter->erase(0, prefix_len);
+    }
+  }
+
+  // Now delete the minimum amount of leading whitespace from each line.
+  prefix_len = string::npos;
+  for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) {
+    if (l_iter->empty()) {
+      continue;
+    }
+    pos = l_iter->find_first_not_of(" \t");
+    if (pos != string::npos && (prefix_len == string::npos || pos < prefix_len)) {
+      prefix_len = pos;
+    }
+  }
+
+  // If our prefix survived, delete it from every line.
+  if (prefix_len != string::npos) {
+    for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) {
+      l_iter->erase(0, prefix_len);
+    }
+  }
+
+  // Remove trailing whitespace from every line.
+  for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) {
+    pos = l_iter->find_last_not_of(" \t");
+    if (pos != string::npos && pos != l_iter->length() - 1) {
+      l_iter->erase(pos + 1);
+    }
+  }
+
+  // If the first line is empty, remove it.
+  // Don't do this earlier because a lot of steps skip the first line.
+  if (lines.front().empty()) {
+    lines.erase(lines.begin());
+  }
+
+  // Now rejoin the lines and copy them back into doctext.
+  docstring.clear();
+  for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) {
+    docstring += *l_iter;
+    docstring += '\n';
+  }
+
+  // assert(docstring.length() <= strlen(doctext));  may happen, see THRIFT-1755
+  if (docstring.length() <= strlen(doctext)) {
+    strcpy(doctext, docstring.c_str());
+  } else {
+    free(doctext); // too short
+    doctext = strdup(docstring.c_str());
+  }
+  return doctext;
+}
+
+/** Set to true to debug docstring parsing */
+static bool dump_docs = false;
+
+/**
+ * Dumps docstrings to stdout
+ * Only works for top-level definitions and the whole program doc
+ * (i.e., not enum constants, struct fields, or functions.
+ */
+void dump_docstrings(t_program* program) {
+  string progdoc = program->get_doc();
+  if (!progdoc.empty()) {
+    printf("Whole program doc:\n%s\n", progdoc.c_str());
+  }
+  const vector<t_typedef*>& typedefs = program->get_typedefs();
+  vector<t_typedef*>::const_iterator t_iter;
+  for (t_iter = typedefs.begin(); t_iter != typedefs.end(); ++t_iter) {
+    t_typedef* td = *t_iter;
+    if (td->has_doc()) {
+      printf("typedef %s:\n%s\n", td->get_name().c_str(), td->get_doc().c_str());
+    }
+  }
+  const vector<t_enum*>& enums = program->get_enums();
+  vector<t_enum*>::const_iterator e_iter;
+  for (e_iter = enums.begin(); e_iter != enums.end(); ++e_iter) {
+    t_enum* en = *e_iter;
+    if (en->has_doc()) {
+      printf("enum %s:\n%s\n", en->get_name().c_str(), en->get_doc().c_str());
+    }
+  }
+  const vector<t_const*>& consts = program->get_consts();
+  vector<t_const*>::const_iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    t_const* co = *c_iter;
+    if (co->has_doc()) {
+      printf("const %s:\n%s\n", co->get_name().c_str(), co->get_doc().c_str());
+    }
+  }
+  const vector<t_struct*>& structs = program->get_structs();
+  vector<t_struct*>::const_iterator s_iter;
+  for (s_iter = structs.begin(); s_iter != structs.end(); ++s_iter) {
+    t_struct* st = *s_iter;
+    if (st->has_doc()) {
+      printf("struct %s:\n%s\n", st->get_name().c_str(), st->get_doc().c_str());
+    }
+  }
+  const vector<t_struct*>& xceptions = program->get_xceptions();
+  vector<t_struct*>::const_iterator x_iter;
+  for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+    t_struct* xn = *x_iter;
+    if (xn->has_doc()) {
+      printf("xception %s:\n%s\n", xn->get_name().c_str(), xn->get_doc().c_str());
+    }
+  }
+  const vector<t_service*>& services = program->get_services();
+  vector<t_service*>::const_iterator v_iter;
+  for (v_iter = services.begin(); v_iter != services.end(); ++v_iter) {
+    t_service* sv = *v_iter;
+    if (sv->has_doc()) {
+      printf("service %s:\n%s\n", sv->get_name().c_str(), sv->get_doc().c_str());
+    }
+  }
+}
+
+/**
+ * Emits a warning on list<byte>, binary type is typically a much better choice.
+ */
+void check_for_list_of_bytes(t_type* list_elem_type) {
+  if ((g_parse_mode == PROGRAM) && (list_elem_type != NULL) && list_elem_type->is_base_type()) {
+    t_base_type* tbase = (t_base_type*)list_elem_type;
+    if (tbase->get_base() == t_base_type::TYPE_I8) {
+      pwarning(1, "Consider using the more efficient \"binary\" type instead of \"list<byte>\".");
+    }
+  }
+}
+
+static bool g_byte_warning_emitted = false;
+
+/**
+ * Emits a one-time warning on byte type, promoting the new i8 type instead
+ */
+void emit_byte_type_warning() {
+  if (!g_byte_warning_emitted) {
+    pwarning(1,
+             "The \"byte\" type is a compatibility alias for \"i8\". Use \"i8\" to emphasize the "
+             "signedness of this type.\n");
+    g_byte_warning_emitted = true;
+  }
+}
+
+/**
+ * Prints deprecation notice for old NS declarations that are no longer supported
+ * If new_form is NULL, old_form is assumed to be a language identifier, such as "cpp"
+ * If new_form is not NULL, both arguments are used exactly as given
+ */
+void error_unsupported_namespace_decl(const char* old_form, const char* new_form) {
+  const char* remainder = "";
+  if( new_form == NULL) {
+    new_form = old_form;
+    remainder = "_namespace";
+  }
+  failure("Unsupported declaration '%s%s'. Use 'namespace %s' instead.", old_form, remainder, new_form);
+}
+
+/**
+ * Prints the version number
+ */
+void version() {
+  printf("Thrift version %s\n", THRIFT_VERSION);
+}
+
+/**
+ * Display the usage message and then exit with an error code.
+ */
+void usage() {
+  fprintf(stderr, "Usage: thrift [options] file\n\n");
+  fprintf(stderr, "Use thrift -help for a list of options\n");
+  exit(1);
+}
+
+/**
+ * Diplays the help message and then exits with an error code.
+ */
+void help() {
+  fprintf(stderr, "Usage: thrift [options] file\n");
+  fprintf(stderr, "Options:\n");
+  fprintf(stderr, "  -version    Print the compiler version\n");
+  fprintf(stderr, "  -o dir      Set the output directory for gen-* packages\n");
+  fprintf(stderr, "               (default: current directory)\n");
+  fprintf(stderr, "  -out dir    Set the ouput location for generated files.\n");
+  fprintf(stderr, "               (no gen-* folder will be created)\n");
+  fprintf(stderr, "  -I dir      Add a directory to the list of directories\n");
+  fprintf(stderr, "                searched for include directives\n");
+  fprintf(stderr, "  -nowarn     Suppress all compiler warnings (BAD!)\n");
+  fprintf(stderr, "  -strict     Strict compiler warnings on\n");
+  fprintf(stderr, "  -v[erbose]  Verbose mode\n");
+  fprintf(stderr, "  -r[ecurse]  Also generate included files\n");
+  fprintf(stderr, "  -debug      Parse debug trace to stdout\n");
+  fprintf(stderr,
+          "  --allow-neg-keys  Allow negative field keys (Used to "
+          "preserve protocol\n");
+  fprintf(stderr, "                compatibility with older .thrift files)\n");
+  fprintf(stderr, "  --allow-64bit-consts  Do not print warnings about using 64-bit constants\n");
+  fprintf(stderr, "  --gen STR   Generate code with a dynamically-registered generator.\n");
+  fprintf(stderr, "                STR has the form language[:key1=val1[,key2[,key3=val3]]].\n");
+  fprintf(stderr, "                Keys and values are options passed to the generator.\n");
+  fprintf(stderr, "                Many options will not require values.\n");
+  fprintf(stderr, "\n");
+  fprintf(stderr, "Options related to audit operation\n");
+  fprintf(stderr, "   --audit OldFile   Old Thrift file to be audited with 'file'\n");
+  fprintf(stderr, "  -Iold dir    Add a directory to the list of directories\n");
+  fprintf(stderr, "                searched for include directives for old thrift file\n");
+  fprintf(stderr, "  -Inew dir    Add a directory to the list of directories\n");
+  fprintf(stderr, "                searched for include directives for new thrift file\n");
+  fprintf(stderr, "\n");
+  fprintf(stderr, "Available generators (and options):\n");
+
+  t_generator_registry::gen_map_t gen_map = t_generator_registry::get_generator_map();
+  t_generator_registry::gen_map_t::iterator iter;
+  for (iter = gen_map.begin(); iter != gen_map.end(); ++iter) {
+    fprintf(stderr,
+            "  %s (%s):\n",
+            iter->second->get_short_name().c_str(),
+            iter->second->get_long_name().c_str());
+    fprintf(stderr, "%s", iter->second->get_documentation().c_str());
+  }
+  exit(1);
+}
+
+/**
+ * You know, when I started working on Thrift I really thought it wasn't going
+ * to become a programming language because it was just a generator and it
+ * wouldn't need runtime type information and all that jazz. But then we
+ * decided to add constants, and all of a sudden that means runtime type
+ * validation and inference, except the "runtime" is the code generator
+ * runtime.
+ */
+void validate_const_rec(std::string name, t_type* type, t_const_value* value) {
+  if (type->is_void()) {
+    throw "type error: cannot declare a void const: " + name;
+  }
+
+  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:
+      if (value->get_type() != t_const_value::CV_STRING) {
+        throw "type error: const \"" + name + "\" was declared as string";
+      }
+      break;
+    case t_base_type::TYPE_BOOL:
+      if (value->get_type() != t_const_value::CV_INTEGER) {
+        throw "type error: const \"" + name + "\" was declared as bool";
+      }
+      break;
+    case t_base_type::TYPE_I8:
+      if (value->get_type() != t_const_value::CV_INTEGER) {
+        throw "type error: const \"" + name + "\" was declared as byte";
+      }
+      break;
+    case t_base_type::TYPE_I16:
+      if (value->get_type() != t_const_value::CV_INTEGER) {
+        throw "type error: const \"" + name + "\" was declared as i16";
+      }
+      break;
+    case t_base_type::TYPE_I32:
+      if (value->get_type() != t_const_value::CV_INTEGER) {
+        throw "type error: const \"" + name + "\" was declared as i32";
+      }
+      break;
+    case t_base_type::TYPE_I64:
+      if (value->get_type() != t_const_value::CV_INTEGER) {
+        throw "type error: const \"" + name + "\" was declared as i64";
+      }
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() != t_const_value::CV_INTEGER
+          && value->get_type() != t_const_value::CV_DOUBLE) {
+        throw "type error: const \"" + name + "\" was declared as double";
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase) + name;
+    }
+  } else if (type->is_enum()) {
+    if (value->get_type() != t_const_value::CV_IDENTIFIER) {
+      throw "type error: const \"" + name + "\" was declared as enum";
+    }
+
+    // see if there's a dot in the identifier
+    std::string name_portion = value->get_identifier_name();
+
+    const vector<t_enum_value*>& enum_values = ((t_enum*)type)->get_constants();
+    vector<t_enum_value*>::const_iterator c_iter;
+    bool found = false;
+
+    for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) {
+      if ((*c_iter)->get_name() == name_portion) {
+        found = true;
+        break;
+      }
+    }
+    if (!found) {
+      throw "type error: const " + name + " was declared as type " + type->get_name()
+          + " which is an enum, but " + value->get_identifier()
+          + " is not a valid value for that enum";
+    }
+  } else if (type->is_struct() || type->is_xception()) {
+    if (value->get_type() != t_const_value::CV_MAP) {
+      throw "type error: const \"" + name + "\" was declared as struct/xception";
+    }
+    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*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      if (v_iter->first->get_type() != t_const_value::CV_STRING) {
+        throw "type error: " + name + " struct key must be string";
+      }
+      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();
+      }
+
+      validate_const_rec(name + "." + v_iter->first->get_string(), field_type, v_iter->second);
+    }
+  } else if (type->is_map()) {
+    t_type* k_type = ((t_map*)type)->get_key_type();
+    t_type* v_type = ((t_map*)type)->get_val_type();
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      validate_const_rec(name + "<key>", k_type, v_iter->first);
+      validate_const_rec(name + "<val>", v_type, v_iter->second);
+    }
+  } else if (type->is_list() || type->is_set()) {
+    t_type* e_type;
+    if (type->is_list()) {
+      e_type = ((t_list*)type)->get_elem_type();
+    } else {
+      e_type = ((t_set*)type)->get_elem_type();
+    }
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      validate_const_rec(name + "<elem>", e_type, *v_iter);
+    }
+  }
+}
+
+/**
+ * Check simple identifier names
+ * It's easier to do it this way instead of rewriting the whole grammar etc.
+ */
+void validate_simple_identifier(const char* identifier) {
+  string name(identifier);
+  if (name.find(".") != string::npos) {
+    yyerror("Identifier %s can't have a dot.", identifier);
+    exit(1);
+  }
+}
+
+/**
+ * Check the type of the parsed const information against its declared type
+ */
+void validate_const_type(t_const* c) {
+  validate_const_rec(c->get_name(), c->get_type(), c->get_value());
+}
+
+/**
+ * Check the type of a default value assigned to a field.
+ */
+void validate_field_value(t_field* field, t_const_value* cv) {
+  validate_const_rec(field->get_name(), field->get_type(), cv);
+}
+
+/**
+ * Check that all the elements of a throws block are actually exceptions.
+ */
+bool validate_throws(t_struct* throws) {
+  const vector<t_field*>& members = throws->get_members();
+  vector<t_field*>::const_iterator m_iter;
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    if (!t_generator::get_true_type((*m_iter)->get_type())->is_xception()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+/**
+ * Skips UTF-8 BOM if there is one
+ */
+bool skip_utf8_bom(FILE* f) {
+
+  // pretty straightforward, but works
+  if (fgetc(f) == 0xEF) {
+    if (fgetc(f) == 0xBB) {
+      if (fgetc(f) == 0xBF) {
+        return true;
+      }
+    }
+  }
+
+  rewind(f);
+  return false;
+}
+
+/**
+ * Parses a program
+ */
+void parse(t_program* program, t_program* parent_program) {
+  // Get scope file path
+  string path = program->get_path();
+
+  // Set current dir global, which is used in the include_file function
+  g_curdir = directory_name(path);
+  g_curpath = path;
+
+  // Open the file
+  // skip UTF-8 BOM if there is one
+  yyin = fopen(path.c_str(), "r");
+  if (yyin == 0) {
+    failure("Could not open input file: \"%s\"", path.c_str());
+  }
+  if (skip_utf8_bom(yyin))
+    pverbose("Skipped UTF-8 BOM at %s\n", path.c_str());
+
+  // Create new scope and scan for includes
+  pverbose("Scanning %s for includes\n", path.c_str());
+  g_parse_mode = INCLUDES;
+  g_program = program;
+  g_scope = program->scope();
+  try {
+    yylineno = 1;
+    if (yyparse() != 0) {
+      failure("Parser error during include pass.");
+    }
+  } catch (string x) {
+    failure(x.c_str());
+  }
+  fclose(yyin);
+
+  // Recursively parse all the include programs
+  vector<t_program*>& includes = program->get_includes();
+  vector<t_program*>::iterator iter;
+  for (iter = includes.begin(); iter != includes.end(); ++iter) {
+    parse(*iter, program);
+  }
+
+  // reset program doctext status before parsing a new file
+  reset_program_doctext_info();
+
+  // Parse the program file
+  g_parse_mode = PROGRAM;
+  g_program = program;
+  g_scope = program->scope();
+  g_parent_scope = (parent_program != NULL) ? parent_program->scope() : NULL;
+  g_parent_prefix = program->get_name() + ".";
+  g_curpath = path;
+
+  // Open the file
+  // skip UTF-8 BOM if there is one
+  yyin = fopen(path.c_str(), "r");
+  if (yyin == 0) {
+    failure("Could not open input file: \"%s\"", path.c_str());
+  }
+  if (skip_utf8_bom(yyin))
+    pverbose("Skipped UTF-8 BOM at %s\n", path.c_str());
+
+  pverbose("Parsing %s for types\n", path.c_str());
+  yylineno = 1;
+  try {
+    if (yyparse() != 0) {
+      failure("Parser error during types pass.");
+    }
+  } catch (string x) {
+    failure(x.c_str());
+  }
+  fclose(yyin);
+}
+
+/**
+ * Generate code
+ */
+void generate(t_program* program, const vector<string>& generator_strings) {
+  // Oooohh, recursive code generation, hot!!
+  if (gen_recurse) {
+    const vector<t_program*>& includes = program->get_includes();
+    for (size_t i = 0; i < includes.size(); ++i) {
+      // Propagate output path from parent to child programs
+      includes[i]->set_out_path(program->get_out_path(), program->is_out_path_absolute());
+
+      generate(includes[i], generator_strings);
+    }
+  }
+
+  // Generate code!
+  try {
+    pverbose("Program: %s\n", program->get_path().c_str());
+
+    if (dump_docs) {
+      dump_docstrings(program);
+    }
+
+    vector<string>::const_iterator iter;
+    for (iter = generator_strings.begin(); iter != generator_strings.end(); ++iter) {
+      t_generator* generator = t_generator_registry::get_generator(program, *iter);
+
+      if (generator == NULL) {
+#ifdef THRIFT_ENABLE_PLUGIN
+        switch (plugin_output::delegateToPlugin(program, *iter)) {
+          case plugin_output::PLUGIN_NOT_FOUND:
+            pwarning(1, "Unable to get a generator for \"%s\".\n", iter->c_str());
+            g_generator_failure = true;
+            break;
+          case plugin_output::PLUGIN_FAILURE:
+            pwarning(1, "Plugin generator for \"%s\" failed.\n", iter->c_str());
+            g_generator_failure = true;
+            break;
+          case plugin_output::PLUGIN_SUCCEESS:
+            break;
+          default:
+            assert(false);
+            break;
+        }
+#else
+        pwarning(1, "Unable to get a generator for \"%s\".\n", iter->c_str());
+        g_generator_failure = true;
+#endif
+      } else if (generator) {
+        generator->validate_input();
+        pverbose("Generating \"%s\"\n", iter->c_str());
+        generator->generate_program();
+        delete generator;
+      }
+    }
+  } catch (string s) {
+    failure("Error: %s\n", s.c_str());
+  } catch (const char* exc) {
+    failure("Error: %s\n", exc);
+  }
+}
+
+void audit(t_program* new_program,
+           t_program* old_program,
+           string new_thrift_include_path,
+           string old_thrift_include_path) {
+  vector<string> temp_incl_searchpath = g_incl_searchpath;
+  if (!old_thrift_include_path.empty()) {
+    g_incl_searchpath.push_back(old_thrift_include_path);
+  }
+
+  parse(old_program, NULL);
+
+  g_incl_searchpath = temp_incl_searchpath;
+  if (!new_thrift_include_path.empty()) {
+    g_incl_searchpath.push_back(new_thrift_include_path);
+  }
+
+  parse(new_program, NULL);
+
+  compare_namespace(new_program, old_program);
+  compare_services(new_program->get_services(), old_program->get_services());
+  compare_enums(new_program->get_enums(), old_program->get_enums());
+  compare_structs(new_program->get_structs(), old_program->get_structs());
+  compare_structs(new_program->get_xceptions(), old_program->get_xceptions());
+  compare_consts(new_program->get_consts(), old_program->get_consts());
+}
+
+/**
+ * Parse it up.. then spit it back out, in pretty much every language. Alright
+ * not that many languages, but the cool ones that we care about.
+ */
+int main(int argc, char** argv) {
+  int i;
+  std::string out_path;
+  bool out_path_is_absolute = false;
+
+  // Setup time string
+  time_t now = time(NULL);
+  g_time_str = ctime(&now);
+
+  // Check for necessary arguments, you gotta have at least a filename and
+  // an output language flag
+  if (argc < 2) {
+    usage();
+  }
+
+  vector<string> generator_strings;
+  string old_thrift_include_path;
+  string new_thrift_include_path;
+  string old_input_file;
+
+  // Set the current path to a dummy value to make warning messages clearer.
+  g_curpath = "arguments";
+
+  // Hacky parameter handling... I didn't feel like using a library sorry!
+  for (i = 1; i < argc - 1; i++) {
+    char* arg;
+
+    arg = strtok(argv[i], " ");
+    while (arg != NULL) {
+      // Treat double dashes as single dashes
+      if (arg[0] == '-' && arg[1] == '-') {
+        ++arg;
+      }
+
+      if (strcmp(arg, "-help") == 0) {
+        help();
+      } else if (strcmp(arg, "-version") == 0) {
+        version();
+        exit(0);
+      } else if (strcmp(arg, "-debug") == 0) {
+        g_debug = 1;
+      } else if (strcmp(arg, "-nowarn") == 0) {
+        g_warn = 0;
+      } else if (strcmp(arg, "-strict") == 0) {
+        g_strict = 255;
+        g_warn = 2;
+      } else if (strcmp(arg, "-v") == 0 || strcmp(arg, "-verbose") == 0) {
+        g_verbose = 1;
+      } else if (strcmp(arg, "-r") == 0 || strcmp(arg, "-recurse") == 0) {
+        gen_recurse = true;
+      } else if (strcmp(arg, "-allow-neg-keys") == 0) {
+        g_allow_neg_field_keys = true;
+      } else if (strcmp(arg, "-allow-64bit-consts") == 0) {
+        g_allow_64bit_consts = true;
+      } else if (strcmp(arg, "-gen") == 0) {
+        arg = argv[++i];
+        if (arg == NULL) {
+          fprintf(stderr, "Missing generator specification\n");
+          usage();
+        }
+        generator_strings.push_back(arg);
+      } else if (strcmp(arg, "-I") == 0) {
+        // An argument of "-I\ asdf" is invalid and has unknown results
+        arg = argv[++i];
+
+        if (arg == NULL) {
+          fprintf(stderr, "Missing Include directory\n");
+          usage();
+        }
+        g_incl_searchpath.push_back(arg);
+      } else if ((strcmp(arg, "-o") == 0) || (strcmp(arg, "-out") == 0)) {
+        out_path_is_absolute = (strcmp(arg, "-out") == 0) ? true : false;
+        arg = argv[++i];
+        if (arg == NULL) {
+          fprintf(stderr, "-o: missing output directory\n");
+          usage();
+        }
+        out_path = arg;
+
+#ifdef _WIN32
+        // strip out trailing \ on Windows
+        std::string::size_type last = out_path.length() - 1;
+        if (out_path[last] == '\\') {
+          out_path.erase(last);
+        }
+#endif
+        if (!check_is_directory(out_path.c_str()))
+          return -1;
+      } else if (strcmp(arg, "-audit") == 0) {
+        g_audit = true;
+        arg = argv[++i];
+        if (arg == NULL) {
+          fprintf(stderr, "Missing old thrift file name for audit operation\n");
+          usage();
+        }
+        char old_thrift_file_rp[THRIFT_PATH_MAX];
+
+        // cppcheck-suppress uninitvar
+        if (saferealpath(arg, old_thrift_file_rp) == NULL) {
+          failure("Could not open input file with realpath: %s", arg);
+        }
+        old_input_file = string(old_thrift_file_rp);
+      } else if (strcmp(arg, "-audit-nofatal") == 0) {
+        g_audit_fatal = false;
+      } else if (strcmp(arg, "-Iold") == 0) {
+        arg = argv[++i];
+        if (arg == NULL) {
+          fprintf(stderr, "Missing Include directory for old thrift file\n");
+          usage();
+        }
+        old_thrift_include_path = string(arg);
+      } else if (strcmp(arg, "-Inew") == 0) {
+        arg = argv[++i];
+        if (arg == NULL) {
+          fprintf(stderr, "Missing Include directory for new thrift file\n");
+          usage();
+        }
+        new_thrift_include_path = string(arg);
+      } else {
+        fprintf(stderr, "Unrecognized option: %s\n", arg);
+        usage();
+      }
+
+      // Tokenize more
+      arg = strtok(NULL, " ");
+    }
+  }
+
+  // display help
+  if ((strcmp(argv[argc - 1], "-help") == 0) || (strcmp(argv[argc - 1], "--help") == 0)) {
+    help();
+  }
+
+  // if you're asking for version, you have a right not to pass a file
+  if ((strcmp(argv[argc - 1], "-version") == 0) || (strcmp(argv[argc - 1], "--version") == 0)) {
+    version();
+    exit(0);
+  }
+
+  // Initialize global types
+  initGlobals();
+
+  if (g_audit) {
+    // Audit operation
+
+    if (old_input_file.empty()) {
+      fprintf(stderr, "Missing file name of old thrift file for audit\n");
+      usage();
+    }
+
+    char new_thrift_file_rp[THRIFT_PATH_MAX];
+    if (argv[i] == NULL) {
+      fprintf(stderr, "Missing file name of new thrift file for audit\n");
+      usage();
+    }
+    // cppcheck-suppress uninitvar
+    if (saferealpath(argv[i], new_thrift_file_rp) == NULL) {
+      failure("Could not open input file with realpath: %s", argv[i]);
+    }
+    string new_input_file(new_thrift_file_rp);
+
+    t_program new_program(new_input_file);
+    t_program old_program(old_input_file);
+
+    audit(&new_program, &old_program, new_thrift_include_path, old_thrift_include_path);
+
+  } else {
+    // Generate options
+
+    // You gotta generate something!
+    if (generator_strings.empty()) {
+      fprintf(stderr, "No output language(s) specified\n");
+      usage();
+    }
+
+    // Real-pathify it
+    char rp[THRIFT_PATH_MAX];
+    if (argv[i] == NULL) {
+      fprintf(stderr, "Missing file name\n");
+      usage();
+    }
+    // cppcheck-suppress uninitvar
+    if (saferealpath(argv[i], rp) == NULL) {
+      failure("Could not open input file with realpath: %s", argv[i]);
+    }
+    string input_file(rp);
+
+    // Instance of the global parse tree
+    t_program* program = new t_program(input_file);
+    if (out_path.size()) {
+      program->set_out_path(out_path, out_path_is_absolute);
+    }
+
+    // Compute the cpp include prefix.
+    // infer this from the filename passed in
+    string input_filename = argv[i];
+    string include_prefix;
+
+    string::size_type last_slash = string::npos;
+    if ((last_slash = input_filename.rfind("/")) != string::npos) {
+      include_prefix = input_filename.substr(0, last_slash);
+    }
+
+    program->set_include_prefix(include_prefix);
+
+    // Parse it!
+    parse(program, NULL);
+
+    // The current path is not really relevant when we are doing generation.
+    // Reset the variable to make warning messages clearer.
+    g_curpath = "generation";
+    // Reset yylineno for the heck of it.  Use 1 instead of 0 because
+    // That is what shows up during argument parsing.
+    yylineno = 1;
+
+    // Generate it!
+    generate(program, generator_strings);
+    delete program;
+  }
+
+  // Clean up. Who am I kidding... this program probably orphans heap memory
+  // all over the place, but who cares because it is about to exit and it is
+  // all referenced and used by this wacky parse tree up until now anyways.
+  clearGlobals();
+
+  // Finished
+  if (g_return_failure && g_audit_fatal) {
+    exit(2);
+  }
+  if (g_generator_failure) {
+    exit(3);
+  }
+  // Finished
+  return 0;
+}
diff --git a/compiler/cpp/src/thrift/main.h b/compiler/cpp/src/thrift/main.h
new file mode 100644
index 0000000..54abb03
--- /dev/null
+++ b/compiler/cpp/src/thrift/main.h
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+#ifndef T_MAIN_H
+#define T_MAIN_H
+
+#include <string>
+#include <cstdio>
+
+#include "thrift/logging.h"
+
+#include "thrift/parse/t_const.h"
+#include "thrift/parse/t_field.h"
+
+/**
+ * Defined in the flex library
+ */
+
+extern "C" { int yylex(void); }
+
+int yyparse(void);
+
+/**
+ * Expected to be defined by Flex/Bison
+ */
+void yyerror(const char* fmt, ...);
+
+/**
+ * Check simple identifier names
+ */
+void validate_simple_identifier(const char* identifier);
+
+/**
+ * Check constant types
+ */
+void validate_const_type(t_const* c);
+
+/**
+ * Check constant types
+ */
+void validate_field_value(t_field* field, t_const_value* cv);
+
+/**
+ * Check members of a throws block
+ */
+bool validate_throws(t_struct* throws);
+
+/**
+ * Converts a string filename into a thrift program name
+ */
+std::string program_name(std::string filename);
+
+/**
+ * Gets the directory path of a filename
+ */
+std::string directory_name(std::string filename);
+
+/**
+ * Get the absolute path for an include file
+ */
+std::string include_file(std::string filename);
+
+/**
+ * Clears any previously stored doctext string.
+ */
+void clear_doctext();
+
+/**
+ * Cleans up text commonly found in doxygen-like comments
+ */
+char* clean_up_doctext(char* doctext);
+
+/**
+ * We are sure the program doctext candidate is really the program doctext.
+ */
+void declare_valid_program_doctext();
+
+/**
+ * Emits a warning on list<byte>, binary type is typically a much better choice.
+ */
+void check_for_list_of_bytes(t_type* list_elem_type);
+
+/**
+ * Emits a one-time warning on byte type, promoting the new i8 type instead
+ */
+void emit_byte_type_warning();
+
+/**
+ * Prints deprecation notice for old NS declarations that are no longer supported
+ * If new_form is NULL, old_form is assumed to be a language identifier, such as "cpp"
+ * If new_form is not NULL, both arguments are used exactly as given
+ */
+void error_unsupported_namespace_decl(const char* old_form, const char* new_form = NULL);
+
+/**
+ * Flex utilities
+ */
+
+extern int yylineno;
+extern char yytext[];
+extern std::FILE* yyin;
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/parse.cc b/compiler/cpp/src/thrift/parse/parse.cc
new file mode 100644
index 0000000..01f7637
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/parse.cc
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#include "thrift/parse/t_type.h"
+#include "thrift/parse/t_typedef.h"
+
+#include "thrift/main.h"
+
+t_type* t_type::get_true_type() {
+  t_type* type = this;
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+  return type;
+}
+
+const t_type* t_type::get_true_type() const {
+  const t_type* type = this;
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+  return type;
+}
diff --git a/compiler/cpp/src/thrift/parse/t_base_type.h b/compiler/cpp/src/thrift/parse/t_base_type.h
new file mode 100644
index 0000000..71398ba
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_base_type.h
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#ifndef T_BASE_TYPE_H
+#define T_BASE_TYPE_H
+
+#include <cstdlib>
+#include "thrift/parse/t_type.h"
+
+/**
+ * A thrift base type, which must be one of the defined enumerated types inside
+ * this definition.
+ *
+ */
+class t_base_type : public t_type {
+public:
+  /**
+   * Enumeration of thrift base types
+   */
+  enum t_base {
+    TYPE_VOID,
+    TYPE_STRING,
+    TYPE_BOOL,
+    TYPE_I8,
+    TYPE_I16,
+    TYPE_I32,
+    TYPE_I64,
+    TYPE_DOUBLE
+  };
+
+  t_base_type(std::string name, t_base base)
+    : t_type(name), base_(base), string_list_(false), binary_(false), string_enum_(false) {}
+
+  t_base get_base() const { return base_; }
+
+  bool is_void() const { return base_ == TYPE_VOID; }
+
+  bool is_string() const { return base_ == TYPE_STRING; }
+
+  bool is_bool() const { return base_ == TYPE_BOOL; }
+
+  void set_string_list(bool val) { string_list_ = val; }
+
+  bool is_string_list() const { return string_list_ && (base_ == TYPE_STRING); }
+
+  void set_binary(bool val) { binary_ = val; }
+
+  bool is_binary() const { return binary_ && (base_ == TYPE_STRING); }
+
+  void set_string_enum(bool val) { string_enum_ = val; }
+
+  bool is_string_enum() const { return string_enum_ && base_ == TYPE_STRING; }
+
+  void add_string_enum_val(std::string val) { string_enum_vals_.push_back(val); }
+
+  const std::vector<std::string>& get_string_enum_vals() const { return string_enum_vals_; }
+
+  bool is_base_type() const { return true; }
+
+  static std::string t_base_name(t_base tbase) {
+    switch (tbase) {
+    case TYPE_VOID:
+      return "void";
+      break;
+    case TYPE_STRING:
+      return "string";
+      break;
+    case TYPE_BOOL:
+      return "bool";
+      break;
+    case TYPE_I8:
+      return "i8";
+      break;
+    case TYPE_I16:
+      return "i16";
+      break;
+    case TYPE_I32:
+      return "i32";
+      break;
+    case TYPE_I64:
+      return "i64";
+      break;
+    case TYPE_DOUBLE:
+      return "double";
+      break;
+    default:
+      return "(unknown)";
+      break;
+    }
+  }
+
+private:
+  t_base base_;
+
+  bool string_list_;
+  bool binary_;
+  bool string_enum_;
+  std::vector<std::string> string_enum_vals_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_const.h b/compiler/cpp/src/thrift/parse/t_const.h
new file mode 100644
index 0000000..3c08e0d
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_const.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef T_CONST_H
+#define T_CONST_H
+
+#include "thrift/parse/t_type.h"
+#include "thrift/parse/t_const_value.h"
+
+/**
+ * A const is a constant value defined across languages that has a type and
+ * a value. The trick here is that the declared type might not match the type
+ * of the value object, since that is not determined until after parsing the
+ * whole thing out.
+ *
+ */
+class t_const : public t_doc {
+public:
+  t_const(t_type* type, std::string name, t_const_value* value)
+    : type_(type), name_(name), value_(value) {}
+
+  t_type* get_type() const { return type_; }
+
+  std::string get_name() const { return name_; }
+
+  t_const_value* get_value() const { return value_; }
+
+private:
+  t_type* type_;
+  std::string name_;
+  t_const_value* value_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_const_value.h b/compiler/cpp/src/thrift/parse/t_const_value.h
new file mode 100644
index 0000000..6a114cf
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_const_value.h
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+
+#ifndef T_CONST_VALUE_H
+#define T_CONST_VALUE_H
+
+#include "thrift/parse/t_enum.h"
+#include <stdint.h>
+#include <map>
+#include <vector>
+#include <string>
+
+namespace plugin_output {
+template <typename From, typename To>
+void convert(From*, To&);
+}
+
+/**
+ * A const value is something parsed that could be a map, set, list, struct
+ * or whatever.
+ *
+ */
+class t_const_value {
+public:
+  /**
+   * Comparator to sort fields in ascending order by key.
+   * Make this a functor instead of a function to help GCC inline it.
+   */
+  struct value_compare {
+  public:
+    bool operator()(t_const_value const* const& left, t_const_value const* const& right) const {
+      return *left < *right;
+    }
+  };
+
+  enum t_const_value_type { CV_INTEGER, CV_DOUBLE, CV_STRING, CV_MAP, CV_LIST, CV_IDENTIFIER, CV_UNKNOWN };
+
+  t_const_value() : intVal_(0), doubleVal_(0.0f), enum_((t_enum*)0), valType_(CV_UNKNOWN) {}
+
+  t_const_value(int64_t val) : doubleVal_(0.0f), enum_((t_enum*)0), valType_(CV_UNKNOWN) { set_integer(val); }
+
+  t_const_value(std::string val) : intVal_(0), doubleVal_(0.0f), enum_((t_enum*)0), valType_(CV_UNKNOWN) { set_string(val); }
+
+  void set_string(std::string val) {
+    valType_ = CV_STRING;
+    stringVal_ = val;
+  }
+
+  std::string get_string() const { return stringVal_; }
+
+  void set_integer(int64_t val) {
+    valType_ = CV_INTEGER;
+    intVal_ = val;
+  }
+
+  int64_t get_integer() const {
+    if (valType_ == CV_IDENTIFIER) {
+      if (enum_ == NULL) {
+        throw "have identifier \"" + get_identifier() + "\", but unset enum on line!";
+      }
+      std::string identifier = get_identifier();
+      std::string::size_type dot = identifier.rfind('.');
+      if (dot != std::string::npos) {
+        identifier = identifier.substr(dot + 1);
+      }
+      t_enum_value* val = enum_->get_constant_by_name(identifier);
+      if (val == NULL) {
+        throw "Unable to find enum value \"" + identifier + "\" in enum \"" + enum_->get_name()
+            + "\"";
+      }
+      return val->get_value();
+    } else {
+      return intVal_;
+    }
+  }
+
+  void set_double(double val) {
+    valType_ = CV_DOUBLE;
+    doubleVal_ = val;
+  }
+
+  double get_double() const { return doubleVal_; }
+
+  void set_map() { valType_ = CV_MAP; }
+
+  void add_map(t_const_value* key, t_const_value* val) { mapVal_[key] = val; }
+
+  const std::map<t_const_value*, t_const_value*, t_const_value::value_compare>& get_map() const { return mapVal_; }
+
+  void set_list() { valType_ = CV_LIST; }
+
+  void add_list(t_const_value* val) { listVal_.push_back(val); }
+
+  const std::vector<t_const_value*>& get_list() const { return listVal_; }
+
+  void set_identifier(std::string val) {
+    valType_ = CV_IDENTIFIER;
+    identifierVal_ = val;
+  }
+
+  std::string get_identifier() const { return identifierVal_; }
+
+  std::string get_identifier_name() const {
+    std::string ret = get_identifier();
+    size_t s = ret.find('.');
+    if (s == std::string::npos) {
+      throw "error: identifier " + ret + " is unqualified!";
+    }
+    ret = ret.substr(s + 1);
+    s = ret.find('.');
+    if (s != std::string::npos) {
+      ret = ret.substr(s + 1);
+    }
+    return ret;
+  }
+
+  std::string get_identifier_with_parent() const {
+    std::string ret = get_identifier();
+    size_t s = ret.find('.');
+    if (s == std::string::npos) {
+      throw "error: identifier " + ret + " is unqualified!";
+    }
+    size_t s2 = ret.find('.', s + 1);
+    if (s2 != std::string::npos) {
+      ret = ret.substr(s + 1);
+    }
+    return ret;
+  }
+
+  void set_enum(t_enum* tenum) { enum_ = tenum; }
+
+  t_const_value_type get_type() const { if (valType_ == CV_UNKNOWN) { throw std::string("unknown t_const_value"); } return valType_; }
+
+  /**
+   * Comparator to sort map fields in ascending order by key and then value.
+   * This is used for map comparison in lexicographic order.
+   */
+  struct map_entry_compare {
+  private:
+    typedef std::pair<t_const_value*, t_const_value*> ConstPair;
+  public:
+    bool operator()(ConstPair left, ConstPair right) const {
+      if (*(left.first) < *(right.first)) {
+        return true;
+      } else {
+        if (*(right.first) < *(left.first)) {
+          return false;
+        } else {
+          return *(left.second) < *(right.second);
+        }
+      }
+    }
+  };
+
+  bool operator < (const t_const_value& that) const {
+    ::t_const_value::t_const_value_type t1 = get_type();
+    ::t_const_value::t_const_value_type t2 = that.get_type();
+    if (t1 != t2)
+      return t1 < t2;
+    switch (t1) {
+    case ::t_const_value::CV_INTEGER:
+      return intVal_ < that.intVal_;
+    case ::t_const_value::CV_DOUBLE:
+      return doubleVal_ < that.doubleVal_;
+    case ::t_const_value::CV_STRING:
+      return stringVal_ < that.stringVal_;
+    case ::t_const_value::CV_IDENTIFIER:
+      return identifierVal_ < that.identifierVal_;
+    case ::t_const_value::CV_MAP:
+      return std::lexicographical_compare(
+          mapVal_.begin(), mapVal_.end(), that.mapVal_.begin(), that.mapVal_.end(), map_entry_compare());
+    case ::t_const_value::CV_LIST:
+      return std::lexicographical_compare(
+          listVal_.begin(), listVal_.end(), that.listVal_.begin(), that.listVal_.end(), value_compare());
+    case ::t_const_value::CV_UNKNOWN:
+    default:
+      throw "unknown value type";
+    }
+  }
+
+private:
+  std::map<t_const_value*, t_const_value*, value_compare> mapVal_;
+  std::vector<t_const_value*> listVal_;
+  std::string stringVal_;
+  int64_t intVal_;
+  double doubleVal_;
+  std::string identifierVal_;
+  t_enum* enum_;
+
+  t_const_value_type valType_;
+
+  // to read enum_
+  template <typename From, typename To>
+  friend void plugin_output::convert(From*, To&);
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_container.h b/compiler/cpp/src/thrift/parse/t_container.h
new file mode 100644
index 0000000..5bdab70
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_container.h
@@ -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.
+ */
+
+#ifndef T_CONTAINER_H
+#define T_CONTAINER_H
+
+#include "thrift/parse/t_type.h"
+
+class t_container : public t_type {
+public:
+  t_container() : cpp_name_(), has_cpp_name_(false) {}
+
+  virtual ~t_container() {}
+
+  void set_cpp_name(std::string cpp_name) {
+    cpp_name_ = cpp_name;
+    has_cpp_name_ = true;
+  }
+
+  bool has_cpp_name() const { return has_cpp_name_; }
+
+  std::string get_cpp_name() const { return cpp_name_; }
+
+  bool is_container() const { return true; }
+
+private:
+  std::string cpp_name_;
+  bool has_cpp_name_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_doc.h b/compiler/cpp/src/thrift/parse/t_doc.h
new file mode 100644
index 0000000..7bcb8f5
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_doc.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef T_DOC_H
+#define T_DOC_H
+
+#include "thrift/globals.h"
+#include "thrift/logging.h"
+
+/**
+ * Documentation stubs
+ *
+ */
+class t_doc {
+
+public:
+  t_doc() : has_doc_(false) {}
+  virtual ~t_doc() {}
+
+  void set_doc(const std::string& doc) {
+    doc_ = doc;
+    has_doc_ = true;
+    if ((g_program_doctext_lineno == g_doctext_lineno)
+        && (g_program_doctext_status == STILL_CANDIDATE)) {
+      g_program_doctext_status = ALREADY_PROCESSED;
+      pdebug("%s", "program doctext set to ALREADY_PROCESSED");
+    }
+  }
+
+  const std::string& get_doc() const { return doc_; }
+
+  bool has_doc() { return has_doc_; }
+
+private:
+  std::string doc_;
+  bool has_doc_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_enum.h b/compiler/cpp/src/thrift/parse/t_enum.h
new file mode 100644
index 0000000..9e23780
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_enum.h
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#ifndef T_ENUM_H
+#define T_ENUM_H
+
+#include <vector>
+
+#include "thrift/parse/t_enum_value.h"
+#include "thrift/parse/t_type.h"
+
+/**
+ * An enumerated type. A list of constant objects with a name for the type.
+ *
+ */
+class t_enum : public t_type {
+public:
+  t_enum(t_program* program) : t_type(program) {}
+
+  void set_name(const std::string& name) { name_ = name; }
+
+  void append(t_enum_value* constant) { constants_.push_back(constant); }
+
+  const std::vector<t_enum_value*>& get_constants() const { return constants_; }
+
+  t_enum_value* get_constant_by_name(const std::string& name) {
+    const std::vector<t_enum_value*>& enum_values = get_constants();
+    std::vector<t_enum_value*>::const_iterator c_iter;
+    for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) {
+      if ((*c_iter)->get_name() == name) {
+        return *c_iter;
+      }
+    }
+    return NULL;
+  }
+
+  t_enum_value* get_constant_by_value(int64_t value) {
+    const std::vector<t_enum_value*>& enum_values = get_constants();
+    std::vector<t_enum_value*>::const_iterator c_iter;
+    for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) {
+      if ((*c_iter)->get_value() == value) {
+        return *c_iter;
+      }
+    }
+    return NULL;
+  }
+
+  t_enum_value* get_min_value() {
+    const std::vector<t_enum_value*>& enum_values = get_constants();
+    std::vector<t_enum_value*>::const_iterator c_iter;
+    t_enum_value* min_value;
+    if (enum_values.size() == 0) {
+      min_value = NULL;
+    } else {
+      int min_value_value;
+      min_value = enum_values.front();
+      min_value_value = min_value->get_value();
+      for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) {
+        if ((*c_iter)->get_value() < min_value_value) {
+          min_value = (*c_iter);
+          min_value_value = min_value->get_value();
+        }
+      }
+    }
+    return min_value;
+  }
+
+  t_enum_value* get_max_value() {
+    const std::vector<t_enum_value*>& enum_values = get_constants();
+    std::vector<t_enum_value*>::const_iterator c_iter;
+    t_enum_value* max_value;
+    if (enum_values.size() == 0) {
+      max_value = NULL;
+    } else {
+      int max_value_value;
+      max_value = enum_values.back();
+      max_value_value = max_value->get_value();
+      for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) {
+        if ((*c_iter)->get_value() > max_value_value) {
+          max_value = (*c_iter);
+          max_value_value = max_value->get_value();
+        }
+      }
+    }
+    return max_value;
+  }
+
+  bool is_enum() const { return true; }
+
+private:
+  std::vector<t_enum_value*> constants_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_enum_value.h b/compiler/cpp/src/thrift/parse/t_enum_value.h
new file mode 100644
index 0000000..c0bf3ad
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_enum_value.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef T_ENUM_VALUE_H
+#define T_ENUM_VALUE_H
+
+#include <map>
+#include <string>
+#include "thrift/parse/t_doc.h"
+
+/**
+ * A constant. These are used inside of enum definitions. Constants are just
+ * symbol identifiers that may or may not have an explicit value associated
+ * with them.
+ *
+ */
+class t_enum_value : public t_doc {
+public:
+  t_enum_value(std::string name, int value) : name_(name), value_(value) {}
+
+  ~t_enum_value() {}
+
+  const std::string& get_name() const { return name_; }
+
+  int get_value() const { return value_; }
+
+  std::map<std::string, std::string> annotations_;
+
+private:
+  std::string name_;
+  int value_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_field.h b/compiler/cpp/src/thrift/parse/t_field.h
new file mode 100644
index 0000000..c5f1f80
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_field.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#ifndef T_FIELD_H
+#define T_FIELD_H
+
+#include <map>
+#include <string>
+#include <sstream>
+
+#include "thrift/parse/t_doc.h"
+#include "thrift/parse/t_type.h"
+
+// Forward declare for xsd_attrs
+class t_struct;
+
+/**
+ * Class to represent a field in a thrift structure. A field has a data type,
+ * a symbolic name, and a numeric identifier.
+ *
+ */
+class t_field : public t_doc {
+public:
+  t_field(t_type* type, std::string name)
+    : type_(type),
+      name_(name),
+      key_(0),
+      value_(NULL),
+      xsd_optional_(false),
+      xsd_nillable_(false),
+      xsd_attrs_(NULL),
+      reference_(false) {}
+
+  t_field(t_type* type, std::string name, int32_t key)
+    : type_(type),
+      name_(name),
+      key_(key),
+      req_(T_OPT_IN_REQ_OUT),
+      value_(NULL),
+      xsd_optional_(false),
+      xsd_nillable_(false),
+      xsd_attrs_(NULL),
+      reference_(false) {}
+
+  ~t_field() {}
+
+  t_type* get_type() { return type_; }
+
+  const t_type* get_type() const { return type_; }
+
+  const std::string& get_name() const { return name_; }
+
+  int32_t get_key() const { return key_; }
+
+  enum e_req { T_REQUIRED, T_OPTIONAL, T_OPT_IN_REQ_OUT };
+
+  void set_req(e_req req) { req_ = req; }
+
+  e_req get_req() const { return req_; }
+
+  void set_value(t_const_value* value) { value_ = value; }
+
+  t_const_value* get_value() { return value_; }
+
+  const t_const_value* get_value() const { return value_; }
+
+  void set_xsd_optional(bool xsd_optional) { xsd_optional_ = xsd_optional; }
+
+  bool get_xsd_optional() const { return xsd_optional_; }
+
+  void set_xsd_nillable(bool xsd_nillable) { xsd_nillable_ = xsd_nillable; }
+
+  bool get_xsd_nillable() const { return xsd_nillable_; }
+
+  void set_xsd_attrs(t_struct* xsd_attrs) { xsd_attrs_ = xsd_attrs; }
+
+  t_struct* get_xsd_attrs() { return xsd_attrs_; }
+
+  /**
+   * Comparator to sort fields in ascending order by key.
+   * Make this a functor instead of a function to help GCC inline it.
+   * The arguments are (const) references to const pointers to const t_fields.
+   */
+  struct key_compare {
+    bool operator()(t_field const* const& a, t_field const* const& b) {
+      return a->get_key() < b->get_key();
+    }
+  };
+
+  std::map<std::string, std::string> annotations_;
+
+  bool get_reference() { return reference_; }
+
+  void set_reference(bool reference) { reference_ = reference; }
+
+private:
+  t_type* type_;
+  std::string name_;
+  int32_t key_;
+  e_req req_;
+  t_const_value* value_;
+
+  bool xsd_optional_;
+  bool xsd_nillable_;
+  t_struct* xsd_attrs_;
+  bool reference_;
+};
+
+/**
+ * A simple struct for the parser to use to store a field ID, and whether or
+ * not it was specified by the user or automatically chosen.
+ */
+struct t_field_id {
+  int32_t value;
+  bool auto_assigned;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_function.h b/compiler/cpp/src/thrift/parse/t_function.h
new file mode 100644
index 0000000..22d2609
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_function.h
@@ -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.
+ */
+
+#ifndef T_FUNCTION_H
+#define T_FUNCTION_H
+
+#include <string>
+#include "thrift/parse/t_type.h"
+#include "thrift/parse/t_struct.h"
+#include "thrift/parse/t_doc.h"
+
+/**
+ * Representation of a function. Key parts are return type, function name,
+ * optional modifiers, and an argument list, which is implemented as a thrift
+ * struct.
+ *
+ */
+class t_function : public t_doc {
+public:
+  t_function(t_type* returntype, std::string name, t_struct* arglist, bool oneway = false)
+    : returntype_(returntype),
+      name_(name),
+      arglist_(arglist),
+      xceptions_(new t_struct(NULL)),
+      own_xceptions_(true),
+      oneway_(oneway) {
+    if (oneway_ && (!returntype_->is_void())) {
+      pwarning(1, "Oneway methods should return void.\n");
+    }
+  }
+
+  t_function(t_type* returntype,
+             std::string name,
+             t_struct* arglist,
+             t_struct* xceptions,
+             bool oneway = false)
+    : returntype_(returntype),
+      name_(name),
+      arglist_(arglist),
+      xceptions_(xceptions),
+      own_xceptions_(false),
+      oneway_(oneway) {
+    if (oneway_ && !xceptions_->get_members().empty()) {
+      throw std::string("Oneway methods can't throw exceptions.");
+    }
+    if (oneway_ && (!returntype_->is_void())) {
+      pwarning(1, "Oneway methods should return void.\n");
+    }
+  }
+
+  ~t_function() {
+    if (own_xceptions_)
+      delete xceptions_;
+  }
+
+  t_type* get_returntype() const { return returntype_; }
+
+  const std::string& get_name() const { return name_; }
+
+  t_struct* get_arglist() const { return arglist_; }
+
+  t_struct* get_xceptions() const { return xceptions_; }
+
+  bool is_oneway() const { return oneway_; }
+
+  std::map<std::string, std::string> annotations_;
+
+private:
+  t_type* returntype_;
+  std::string name_;
+  t_struct* arglist_;
+  t_struct* xceptions_;
+  bool own_xceptions_;
+  bool oneway_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_list.h b/compiler/cpp/src/thrift/parse/t_list.h
new file mode 100644
index 0000000..acf6865
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_list.h
@@ -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.
+ */
+
+#ifndef T_LIST_H
+#define T_LIST_H
+
+#include "thrift/parse/t_container.h"
+
+/**
+ * A list is a lightweight container type that just wraps another data type.
+ *
+ */
+class t_list : public t_container {
+public:
+  t_list(t_type* elem_type) : elem_type_(elem_type) {}
+
+  t_type* get_elem_type() const { return elem_type_; }
+
+  bool is_list() const { return true; }
+
+private:
+  t_type* elem_type_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_map.h b/compiler/cpp/src/thrift/parse/t_map.h
new file mode 100644
index 0000000..dd3f089
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_map.h
@@ -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.
+ */
+
+#ifndef T_MAP_H
+#define T_MAP_H
+
+#include "thrift/parse/t_container.h"
+
+/**
+ * A map is a lightweight container type that just wraps another two data
+ * types.
+ *
+ */
+class t_map : public t_container {
+public:
+  t_map(t_type* key_type, t_type* val_type) : key_type_(key_type), val_type_(val_type) {}
+
+  t_type* get_key_type() const { return key_type_; }
+
+  t_type* get_val_type() const { return val_type_; }
+
+  bool is_map() const { return true; }
+
+private:
+  t_type* key_type_;
+  t_type* val_type_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_program.h b/compiler/cpp/src/thrift/parse/t_program.h
new file mode 100644
index 0000000..43dd45a
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_program.h
@@ -0,0 +1,395 @@
+/*
+ * 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.
+ */
+
+#ifndef T_PROGRAM_H
+#define T_PROGRAM_H
+
+#include <map>
+#include <string>
+#include <vector>
+
+// For program_name()
+#include "thrift/main.h"
+
+#include "thrift/parse/t_doc.h"
+#include "thrift/parse/t_scope.h"
+#include "thrift/parse/t_base_type.h"
+#include "thrift/parse/t_typedef.h"
+#include "thrift/parse/t_enum.h"
+#include "thrift/parse/t_const.h"
+#include "thrift/parse/t_struct.h"
+#include "thrift/parse/t_service.h"
+#include "thrift/parse/t_list.h"
+#include "thrift/parse/t_map.h"
+#include "thrift/parse/t_set.h"
+#include "thrift/generate/t_generator_registry.h"
+//#include "thrift/parse/t_doc.h"
+
+/**
+ * Top level class representing an entire thrift program. A program consists
+ * fundamentally of the following:
+ *
+ *   Typedefs
+ *   Enumerations
+ *   Constants
+ *   Structs
+ *   Exceptions
+ *   Services
+ *
+ * The program module also contains the definitions of the base types.
+ *
+ */
+class t_program : public t_doc {
+public:
+  t_program(std::string path, std::string name)
+    : path_(path), name_(name), out_path_("./"), out_path_is_absolute_(false), scope_(new t_scope) {}
+
+  t_program(std::string path) : path_(path), out_path_("./"), out_path_is_absolute_(false) {
+    name_ = program_name(path);
+    scope_ = new t_scope();
+  }
+
+  ~t_program() {
+    if (scope_) {
+      delete scope_;
+      scope_ = NULL;
+    }
+  }
+
+  // Path accessor
+  const std::string& get_path() const { return path_; }
+
+  // Output path accessor
+  const std::string& get_out_path() const { return out_path_; }
+
+  // Create gen-* dir accessor
+  bool is_out_path_absolute() const { return out_path_is_absolute_; }
+
+  // Name accessor
+  const std::string& get_name() const { return name_; }
+
+  // Namespace
+  const std::string& get_namespace() const { return namespace_; }
+
+  // Include prefix accessor
+  const std::string& get_include_prefix() const { return include_prefix_; }
+
+  // Accessors for program elements
+  const std::vector<t_typedef*>& get_typedefs() const { return typedefs_; }
+  const std::vector<t_enum*>& get_enums() const { return enums_; }
+  const std::vector<t_const*>& get_consts() const { return consts_; }
+  const std::vector<t_struct*>& get_structs() const { return structs_; }
+  const std::vector<t_struct*>& get_xceptions() const { return xceptions_; }
+  const std::vector<t_struct*>& get_objects() const { return objects_; }
+  const std::vector<t_service*>& get_services() const { return services_; }
+  const std::map<std::string, std::string>& get_namespaces() const { return namespaces_; }
+
+  // Program elements
+  void add_typedef(t_typedef* td) { typedefs_.push_back(td); }
+  void add_enum(t_enum* te) { enums_.push_back(te); }
+  void add_const(t_const* tc) { consts_.push_back(tc); }
+  void add_struct(t_struct* ts) {
+    objects_.push_back(ts);
+    structs_.push_back(ts);
+  }
+  void add_xception(t_struct* tx) {
+    objects_.push_back(tx);
+    xceptions_.push_back(tx);
+  }
+  void add_service(t_service* ts) { services_.push_back(ts); }
+
+  // Programs to include
+  const std::vector<t_program*>& get_includes() const { return includes_; }
+
+  void set_out_path(std::string out_path, bool out_path_is_absolute) {
+    out_path_ = out_path;
+    out_path_is_absolute_ = out_path_is_absolute;
+    // Ensure that it ends with a trailing '/' (or '\' for windows machines)
+    char c = out_path_.at(out_path_.size() - 1);
+    if (!(c == '/' || c == '\\')) {
+      out_path_.push_back('/');
+    }
+  }
+
+  // Typename collision detection
+  /**
+   * Search for typename collisions
+   * @param t    the type to test for collisions
+   * @return     true if a certain collision was found, otherwise false
+   */
+  bool is_unique_typename(t_type* t) {
+    int occurrences = program_typename_count(this, t);
+    for (std::vector<t_program*>::iterator it = includes_.begin(); it != includes_.end(); ++it) {
+      occurrences += program_typename_count(*it, t);
+    }
+    return 0 == occurrences;
+  }
+
+  /**
+   * Search all type collections for duplicate typenames
+   * @param prog the program to search
+   * @param t    the type to test for collisions
+   * @return     the number of certain typename collisions
+   */
+  int program_typename_count(t_program* prog, t_type* t) {
+    int occurrences = 0;
+    occurrences += collection_typename_count(prog, prog->typedefs_, t);
+    occurrences += collection_typename_count(prog, prog->enums_, t);
+    occurrences += collection_typename_count(prog, prog->objects_, t);
+    occurrences += collection_typename_count(prog, prog->services_, t);
+    return occurrences;
+  }
+
+  /**
+   * Search a type collection for duplicate typenames
+   * @param prog            the program to search
+   * @param type_collection the type collection to search
+   * @param t               the type to test for collisions
+   * @return                the number of certain typename collisions
+   */
+  template <class T>
+  int collection_typename_count(t_program* prog, T type_collection, t_type* t) {
+    int occurrences = 0;
+    for (typename T::iterator it = type_collection.begin(); it != type_collection.end(); ++it)
+      if (t != *it && 0 == t->get_name().compare((*it)->get_name()) && is_common_namespace(prog, t))
+        ++occurrences;
+    return occurrences;
+  }
+
+  /**
+   * Determine whether identical typenames will collide based on namespaces.
+   *
+   * Because we do not know which languages the user will generate code for,
+   * collisions within programs (IDL files) having namespace declarations can be
+   * difficult to determine. Only guaranteed collisions return true (cause an error).
+   * Possible collisions involving explicit namespace declarations produce a warning.
+   * Other possible collisions go unreported.
+   * @param prog the program containing the preexisting typename
+   * @param t    the type containing the typename match
+   * @return     true if a collision within namespaces is found, otherwise false
+   */
+  bool is_common_namespace(t_program* prog, t_type* t) {
+    // Case 1: Typenames are in the same program [collision]
+    if (prog == t->get_program()) {
+      pwarning(1,
+               "Duplicate typename %s found in %s",
+               t->get_name().c_str(),
+               t->get_program()->get_name().c_str());
+      return true;
+    }
+
+    // Case 2: Both programs have identical namespace scope/name declarations [collision]
+    bool match = true;
+    for (std::map<std::string, std::string>::iterator it = prog->namespaces_.begin();
+         it != prog->namespaces_.end();
+         ++it) {
+      if (0 == it->second.compare(t->get_program()->get_namespace(it->first))) {
+        pwarning(1,
+                 "Duplicate typename %s found in %s,%s,%s and %s,%s,%s [file,scope,ns]",
+                 t->get_name().c_str(),
+                 t->get_program()->get_name().c_str(),
+                 it->first.c_str(),
+                 it->second.c_str(),
+                 prog->get_name().c_str(),
+                 it->first.c_str(),
+                 it->second.c_str());
+      } else {
+        match = false;
+      }
+    }
+    for (std::map<std::string, std::string>::iterator it = t->get_program()->namespaces_.begin();
+         it != t->get_program()->namespaces_.end();
+         ++it) {
+      if (0 == it->second.compare(prog->get_namespace(it->first))) {
+        pwarning(1,
+                 "Duplicate typename %s found in %s,%s,%s and %s,%s,%s [file,scope,ns]",
+                 t->get_name().c_str(),
+                 t->get_program()->get_name().c_str(),
+                 it->first.c_str(),
+                 it->second.c_str(),
+                 prog->get_name().c_str(),
+                 it->first.c_str(),
+                 it->second.c_str());
+      } else {
+        match = false;
+      }
+    }
+    if (0 == prog->namespaces_.size() && 0 == t->get_program()->namespaces_.size()) {
+      pwarning(1,
+               "Duplicate typename %s found in %s and %s",
+               t->get_name().c_str(),
+               t->get_program()->get_name().c_str(),
+               prog->get_name().c_str());
+    }
+    return match;
+  }
+
+  // Scoping and namespacing
+  void set_namespace(std::string name) { namespace_ = name; }
+
+  // Scope accessor
+  t_scope* scope() const { return scope_; }
+
+  // Includes
+
+  void add_include(t_program* program) {
+    includes_.push_back(program);
+  }
+
+  void add_include(std::string path, std::string include_site) {
+    t_program* program = new t_program(path);
+
+    // include prefix for this program is the site at which it was included
+    // (minus the filename)
+    std::string include_prefix;
+    std::string::size_type last_slash = std::string::npos;
+    if ((last_slash = include_site.rfind("/")) != std::string::npos) {
+      include_prefix = include_site.substr(0, last_slash);
+    }
+
+    program->set_include_prefix(include_prefix);
+    includes_.push_back(program);
+  }
+
+  std::vector<t_program*>& get_includes() { return includes_; }
+
+  void set_include_prefix(std::string include_prefix) {
+    include_prefix_ = include_prefix;
+
+    // this is intended to be a directory; add a trailing slash if necessary
+    std::string::size_type len = include_prefix_.size();
+    if (len > 0 && include_prefix_[len - 1] != '/') {
+      include_prefix_ += '/';
+    }
+  }
+
+  // Language neutral namespace / packaging
+  void set_namespace(std::string language, std::string name_space) {
+    if (language != "*") {
+      size_t sub_index = language.find('.');
+      std::string base_language = language.substr(0, sub_index);
+      std::string sub_namespace;
+
+      if (base_language == "smalltalk") {
+        pwarning(1, "Namespace 'smalltalk' is deprecated. Use 'st' instead");
+        base_language = "st";
+      }
+
+      t_generator_registry::gen_map_t my_copy = t_generator_registry::get_generator_map();
+
+      t_generator_registry::gen_map_t::iterator it;
+      it = my_copy.find(base_language);
+
+      if (it == my_copy.end()) {
+        std::string warning = "No generator named '" + base_language + "' could be found!";
+        pwarning(1, warning.c_str());
+      } else {
+        if (sub_index != std::string::npos) {
+          std::string sub_namespace = language.substr(sub_index + 1);
+          if (!it->second->is_valid_namespace(sub_namespace)) {
+            std::string warning = base_language + " generator does not accept '" + sub_namespace
+                                  + "' as sub-namespace!";
+            pwarning(1, warning.c_str());
+          }
+        }
+      }
+    }
+
+    namespaces_[language] = name_space;
+  }
+
+  std::string get_namespace(std::string language) const {
+    std::map<std::string, std::string>::const_iterator iter;
+    if ((iter = namespaces_.find(language)) != namespaces_.end()
+        || (iter = namespaces_.find("*")) != namespaces_.end()) {
+      return iter->second;
+    }
+    return std::string();
+  }
+
+  const std::map<std::string, std::string>& get_all_namespaces(){
+     return namespaces_;
+  }
+
+  void set_namespace_annotations(std::string language, std::map<std::string, std::string> annotations) {
+    namespace_annotations_[language] = annotations;
+  }
+
+  const std::map<std::string, std::string>& get_namespace_annotations(std::string language) {
+    return namespace_annotations_[language];
+  }
+
+  // Language specific namespace / packaging
+
+  void add_cpp_include(std::string path) { cpp_includes_.push_back(path); }
+
+  const std::vector<std::string>& get_cpp_includes() { return cpp_includes_; }
+
+  void add_c_include(std::string path) { c_includes_.push_back(path); }
+
+  const std::vector<std::string>& get_c_includes() { return c_includes_; }
+
+private:
+  // File path
+  std::string path_;
+
+  // Name
+  std::string name_;
+
+  // Output directory
+  std::string out_path_;
+
+  // Output directory is absolute location for generated source (no gen-*)
+  bool out_path_is_absolute_;
+
+  // Namespace
+  std::string namespace_;
+
+  // Included programs
+  std::vector<t_program*> includes_;
+
+  // Include prefix for this program, if any
+  std::string include_prefix_;
+
+  // Identifier lookup scope
+  t_scope* scope_;
+
+  // Components to generate code for
+  std::vector<t_typedef*> typedefs_;
+  std::vector<t_enum*> enums_;
+  std::vector<t_const*> consts_;
+  std::vector<t_struct*> objects_;
+  std::vector<t_struct*> structs_;
+  std::vector<t_struct*> xceptions_;
+  std::vector<t_service*> services_;
+
+  // Dynamic namespaces
+  std::map<std::string, std::string> namespaces_;
+
+  // Annotations for dynamic namespaces
+  std::map<std::string, std::map<std::string, std::string> > namespace_annotations_;
+
+  // C++ extra includes
+  std::vector<std::string> cpp_includes_;
+
+  // C extra includes
+  std::vector<std::string> c_includes_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_scope.h b/compiler/cpp/src/thrift/parse/t_scope.h
new file mode 100644
index 0000000..6f160a5
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_scope.h
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+
+#ifndef T_SCOPE_H
+#define T_SCOPE_H
+
+#include <map>
+#include <string>
+#include <sstream>
+
+#include "thrift/parse/t_type.h"
+#include "thrift/parse/t_service.h"
+#include "thrift/parse/t_const.h"
+#include "thrift/parse/t_const_value.h"
+#include "thrift/parse/t_base_type.h"
+#include "thrift/parse/t_map.h"
+#include "thrift/parse/t_list.h"
+#include "thrift/parse/t_set.h"
+
+namespace plugin_output {
+template <typename From, typename To>
+void convert(From*, To&);
+}
+
+/**
+ * This represents a variable scope used for looking up predefined types and
+ * services. Typically, a scope is associated with a t_program. Scopes are not
+ * used to determine code generation, but rather to resolve identifiers at
+ * parse time.
+ *
+ */
+class t_scope {
+public:
+  t_scope() {}
+
+  void add_type(std::string name, t_type* type) { types_[name] = type; }
+
+  t_type* get_type(std::string name) { return types_[name]; }
+
+  void add_service(std::string name, t_service* service) { services_[name] = service; }
+
+  t_service* get_service(std::string name) { return services_[name]; }
+
+  void add_constant(std::string name, t_const* constant) {
+    if (constants_.find(name) != constants_.end()) {
+      throw "Enum " + name + " is already defined!";
+    } else {
+      constants_[name] = constant;
+    }
+  }
+
+  t_const* get_constant(std::string name) { return constants_[name]; }
+
+  void print() {
+    std::map<std::string, t_type*>::iterator iter;
+    for (iter = types_.begin(); iter != types_.end(); ++iter) {
+      printf("%s => %s\n", iter->first.c_str(), iter->second->get_name().c_str());
+    }
+  }
+
+  void resolve_const_value(t_const_value* const_val, t_type* ttype) {
+    if (ttype->is_map()) {
+      const std::map<t_const_value*, t_const_value*, t_const_value::value_compare>& map = const_val->get_map();
+      std::map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+      for (v_iter = map.begin(); v_iter != map.end(); ++v_iter) {
+        resolve_const_value(v_iter->first, ((t_map*)ttype)->get_key_type());
+        resolve_const_value(v_iter->second, ((t_map*)ttype)->get_val_type());
+      }
+    } else if (ttype->is_list()) {
+      const std::vector<t_const_value*>& val = const_val->get_list();
+      std::vector<t_const_value*>::const_iterator v_iter;
+      for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+        resolve_const_value((*v_iter), ((t_list*)ttype)->get_elem_type());
+      }
+    } else if (ttype->is_set()) {
+      const std::vector<t_const_value*>& val = const_val->get_list();
+      std::vector<t_const_value*>::const_iterator v_iter;
+      for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+        resolve_const_value((*v_iter), ((t_set*)ttype)->get_elem_type());
+      }
+    } else if (ttype->is_struct()) {
+      t_struct* tstruct = (t_struct*)ttype;
+      const std::map<t_const_value*, t_const_value*, t_const_value::value_compare>& map = const_val->get_map();
+      std::map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+      for (v_iter = map.begin(); v_iter != map.end(); ++v_iter) {
+        t_field* field = tstruct->get_field_by_name(v_iter->first->get_string());
+        if (field == NULL) {
+          throw "No field named \"" + v_iter->first->get_string()
+              + "\" was found in struct of type \"" + tstruct->get_name() + "\"";
+        }
+        resolve_const_value(v_iter->second, field->get_type());
+      }
+    } else if (const_val->get_type() == t_const_value::CV_IDENTIFIER) {
+      if (ttype->is_enum()) {
+        const_val->set_enum((t_enum*)ttype);
+      } else {
+        t_const* constant = get_constant(const_val->get_identifier());
+        if (constant == NULL) {
+          throw "No enum value or constant found named \"" + const_val->get_identifier() + "\"!";
+        }
+
+        // Resolve typedefs to the underlying type
+        t_type* const_type = constant->get_type()->get_true_type();
+
+        if (const_type->is_base_type()) {
+          switch (((t_base_type*)const_type)->get_base()) {
+          case t_base_type::TYPE_I16:
+          case t_base_type::TYPE_I32:
+          case t_base_type::TYPE_I64:
+          case t_base_type::TYPE_BOOL:
+          case t_base_type::TYPE_I8:
+            const_val->set_integer(constant->get_value()->get_integer());
+            break;
+          case t_base_type::TYPE_STRING:
+            const_val->set_string(constant->get_value()->get_string());
+            break;
+          case t_base_type::TYPE_DOUBLE:
+            const_val->set_double(constant->get_value()->get_double());
+            break;
+          case t_base_type::TYPE_VOID:
+            throw "Constants cannot be of type VOID";
+          }
+        } else if (const_type->is_map()) {
+          const std::map<t_const_value*, t_const_value*, t_const_value::value_compare>& map = constant->get_value()->get_map();
+          std::map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+
+          const_val->set_map();
+          for (v_iter = map.begin(); v_iter != map.end(); ++v_iter) {
+            const_val->add_map(v_iter->first, v_iter->second);
+          }
+        } else if (const_type->is_list()) {
+          const std::vector<t_const_value*>& val = constant->get_value()->get_list();
+          std::vector<t_const_value*>::const_iterator v_iter;
+
+          const_val->set_list();
+          for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+            const_val->add_list(*v_iter);
+          }
+        }
+      }
+    } else if (ttype->is_enum()) {
+      // enum constant with non-identifier value. set the enum and find the
+      // value's name.
+      t_enum* tenum = (t_enum*)ttype;
+      t_enum_value* enum_value = tenum->get_constant_by_value(const_val->get_integer());
+      if (enum_value == NULL) {
+        std::ostringstream valstm;
+        valstm << const_val->get_integer();
+        throw "Couldn't find a named value in enum " + tenum->get_name() + " for value "
+            + valstm.str();
+      }
+      const_val->set_identifier(tenum->get_name() + "." + enum_value->get_name());
+      const_val->set_enum(tenum);
+    }
+  }
+
+private:
+  // Map of names to types
+  std::map<std::string, t_type*> types_;
+
+  // Map of names to constants
+  std::map<std::string, t_const*> constants_;
+
+  // Map of names to services
+  std::map<std::string, t_service*> services_;
+
+  // to list map entries
+  template <typename From, typename To>
+    friend void plugin_output::convert(From*, To&);
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_service.h b/compiler/cpp/src/thrift/parse/t_service.h
new file mode 100644
index 0000000..e2204ca
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_service.h
@@ -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.
+ */
+
+#ifndef T_SERVICE_H
+#define T_SERVICE_H
+
+#include "thrift/parse/t_function.h"
+#include <vector>
+
+class t_program;
+
+/**
+ * A service consists of a set of functions.
+ *
+ */
+class t_service : public t_type {
+public:
+  t_service(t_program* program) : t_type(program), extends_(NULL) {}
+
+  bool is_service() const { return true; }
+
+  void set_extends(t_service* extends) { extends_ = extends; }
+
+  void add_function(t_function* func) {
+    std::vector<t_function*>::const_iterator iter;
+    for (iter = functions_.begin(); iter != functions_.end(); ++iter) {
+      if (func->get_name() == (*iter)->get_name()) {
+        throw "Function " + func->get_name() + " is already defined";
+      }
+    }
+    functions_.push_back(func);
+  }
+
+  const std::vector<t_function*>& get_functions() const { return functions_; }
+
+  t_service* get_extends() { return extends_; }
+
+  const t_service* get_extends() const { return extends_; }
+
+private:
+  std::vector<t_function*> functions_;
+  t_service* extends_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_set.h b/compiler/cpp/src/thrift/parse/t_set.h
new file mode 100644
index 0000000..f913be4
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_set.h
@@ -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.
+ */
+
+#ifndef T_SET_H
+#define T_SET_H
+
+#include "thrift/parse/t_container.h"
+
+/**
+ * A set is a lightweight container type that just wraps another data type.
+ *
+ */
+class t_set : public t_container {
+public:
+  t_set(t_type* elem_type) : elem_type_(elem_type) {}
+
+  t_type* get_elem_type() const { return elem_type_; }
+
+  bool is_set() const { return true; }
+
+private:
+  t_type* elem_type_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_struct.h b/compiler/cpp/src/thrift/parse/t_struct.h
new file mode 100644
index 0000000..4102da7
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_struct.h
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#ifndef T_STRUCT_H
+#define T_STRUCT_H
+
+#include <algorithm>
+#include <vector>
+#include <utility>
+#include <string>
+
+#include "thrift/parse/t_type.h"
+#include "thrift/parse/t_field.h"
+
+// Forward declare that puppy
+class t_program;
+
+/**
+ * A struct is a container for a set of member fields that has a name. Structs
+ * are also used to implement exception types.
+ *
+ */
+class t_struct : public t_type {
+public:
+  typedef std::vector<t_field*> members_type;
+
+  t_struct(t_program* program)
+    : t_type(program),
+      is_xception_(false),
+      is_union_(false),
+      members_validated(false),
+      members_with_value(0),
+      xsd_all_(false) {}
+
+  t_struct(t_program* program, const std::string& name)
+    : t_type(program, name),
+      is_xception_(false),
+      is_union_(false),
+      members_validated(false),
+      members_with_value(0),
+      xsd_all_(false) {}
+
+  void set_name(const std::string& name) {
+    name_ = name;
+    validate_union_members();
+  }
+
+  void set_xception(bool is_xception) { is_xception_ = is_xception; }
+
+  void validate_union_member(t_field* field) {
+    if (is_union_ && (!name_.empty())) {
+
+      // 1) unions can't have required fields
+      // 2) union members are implicitly optional, otherwise bugs like THRIFT-3650 wait to happen
+      if (field->get_req() != t_field::T_OPTIONAL) {
+        // no warning on default requiredness, but do warn on anything else that is explicitly asked for
+        if(field->get_req() != t_field::T_OPT_IN_REQ_OUT) {
+          pwarning(1,
+                   "Union %s field %s: union members must be optional, ignoring specified requiredness.\n",
+                   name_.c_str(),
+                   field->get_name().c_str());
+        }
+        field->set_req(t_field::T_OPTIONAL);
+      }
+
+      // unions may have up to one member defaulted, but not more
+      if (field->get_value() != NULL) {
+        if (1 < ++members_with_value) {
+          throw "Error: Field " + field->get_name() + " provides another default value for union "
+              + name_;
+        }
+      }
+    }
+  }
+
+  void validate_union_members() {
+    if (is_union_ && (!name_.empty()) && (!members_validated)) {
+      members_type::const_iterator m_iter;
+      for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) {
+        validate_union_member(*m_iter);
+      }
+      members_validated = true;
+    }
+  }
+
+  void set_union(bool is_union) {
+    is_union_ = is_union;
+    validate_union_members();
+  }
+
+  void set_xsd_all(bool xsd_all) { xsd_all_ = xsd_all; }
+
+  bool get_xsd_all() const { return xsd_all_; }
+
+  bool append(t_field* elem) {
+    typedef members_type::iterator iter_type;
+    std::pair<iter_type, iter_type> bounds = std::equal_range(members_in_id_order_.begin(),
+                                                              members_in_id_order_.end(),
+                                                              elem,
+                                                              t_field::key_compare());
+    if (bounds.first != bounds.second) {
+      return false;
+    }
+    // returns false when there is a conflict of field names
+    if (get_field_by_name(elem->get_name()) != NULL) {
+      return false;
+    }
+    members_.push_back(elem);
+    members_in_id_order_.insert(bounds.second, elem);
+    validate_union_member(elem);
+    return true;
+  }
+
+  const members_type& get_members() const { return members_; }
+
+  const members_type& get_sorted_members() { return members_in_id_order_; }
+
+  bool is_struct() const { return !is_xception_; }
+
+  bool is_xception() const { return is_xception_; }
+
+  bool is_union() const { return is_union_; }
+
+  t_field* get_field_by_name(std::string field_name) {
+    members_type::const_iterator m_iter;
+    for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) {
+      if ((*m_iter)->get_name() == field_name) {
+        return *m_iter;
+      }
+    }
+    return NULL;
+  }
+
+  const t_field* get_field_by_name(std::string field_name) const {
+    members_type::const_iterator m_iter;
+    for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) {
+      if ((*m_iter)->get_name() == field_name) {
+        return *m_iter;
+      }
+    }
+    return NULL;
+  }
+
+private:
+  members_type members_;
+  members_type members_in_id_order_;
+  bool is_xception_;
+  bool is_union_;
+  bool members_validated;
+  int members_with_value;
+
+  bool xsd_all_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_type.h b/compiler/cpp/src/thrift/parse/t_type.h
new file mode 100644
index 0000000..3a6d1e0
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_type.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#ifndef T_TYPE_H
+#define T_TYPE_H
+
+#include <string>
+#include <map>
+#include <cstring>
+#include <stdint.h>
+#include "thrift/parse/t_doc.h"
+
+class t_program;
+
+/**
+ * Generic representation of a thrift type. These objects are used by the
+ * parser module to build up a tree of object that are all explicitly typed.
+ * The generic t_type class exports a variety of useful methods that are
+ * used by the code generator to branch based upon different handling for the
+ * various types.
+ *
+ */
+class t_type : public t_doc {
+public:
+  virtual ~t_type() {}
+
+  virtual void set_name(const std::string& name) { name_ = name; }
+
+  virtual const std::string& get_name() const { return name_; }
+
+  virtual bool is_void() const { return false; }
+  virtual bool is_base_type() const { return false; }
+  virtual bool is_string() const { return false; }
+  virtual bool is_binary() const { return false; }
+  virtual bool is_bool() const { return false; }
+  virtual bool is_typedef() const { return false; }
+  virtual bool is_enum() const { return false; }
+  virtual bool is_struct() const { return false; }
+  virtual bool is_xception() const { return false; }
+  virtual bool is_container() const { return false; }
+  virtual bool is_list() const { return false; }
+  virtual bool is_set() const { return false; }
+  virtual bool is_map() const { return false; }
+  virtual bool is_service() const { return false; }
+
+  t_program* get_program() { return program_; }
+
+  const t_program* get_program() const { return program_; }
+
+  t_type* get_true_type();
+  const t_type* get_true_type() const;
+
+  // This function will break (maybe badly) unless 0 <= num <= 16.
+  static char nybble_to_xdigit(int num) {
+    if (num < 10) {
+      return '0' + num;
+    } else {
+      return 'A' + num - 10;
+    }
+  }
+
+  static std::string byte_to_hex(uint8_t byte) {
+    std::string rv;
+    rv += nybble_to_xdigit(byte >> 4);
+    rv += nybble_to_xdigit(byte & 0x0f);
+    return rv;
+  }
+
+  std::map<std::string, std::string> annotations_;
+
+protected:
+  t_type() : program_(NULL) { ; }
+
+  t_type(t_program* program) : program_(program) { ; }
+
+  t_type(t_program* program, std::string name) : program_(program), name_(name) { ; }
+
+  t_type(std::string name) : program_(NULL), name_(name) { ; }
+
+  t_program* program_;
+  std::string name_;
+};
+
+/**
+ * Placeholder struct for returning the key and value of an annotation
+ * during parsing.
+ */
+struct t_annotation {
+  std::string key;
+  std::string val;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/parse/t_typedef.cc b/compiler/cpp/src/thrift/parse/t_typedef.cc
new file mode 100644
index 0000000..99ffdb8
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_typedef.cc
@@ -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.
+ */
+#include <cstdio>
+
+#include "thrift/parse/t_typedef.h"
+#include "thrift/parse/t_program.h"
+
+t_type* t_typedef::get_type() const {
+  if (type_ == NULL) {
+    t_type* type = get_program()->scope()->get_type(symbolic_);
+    if (type == NULL) {
+      printf("Type \"%s\" not defined\n", symbolic_.c_str());
+      exit(1);
+    }
+    return type;
+  }
+  return type_;
+}
diff --git a/compiler/cpp/src/thrift/parse/t_typedef.h b/compiler/cpp/src/thrift/parse/t_typedef.h
new file mode 100644
index 0000000..aad3a50
--- /dev/null
+++ b/compiler/cpp/src/thrift/parse/t_typedef.h
@@ -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.
+ */
+
+#ifndef T_TYPEDEF_H
+#define T_TYPEDEF_H
+
+#include <string>
+#include "thrift/parse/t_type.h"
+
+/**
+ * A typedef is a mapping from a symbolic name to another type. In dymanically
+ * typed languages (i.e. php/python) the code generator can actually usually
+ * ignore typedefs and just use the underlying type directly, though in C++
+ * the symbolic naming can be quite useful for code clarity.
+ *
+ */
+class t_typedef : public t_type {
+public:
+  t_typedef(t_program* program, t_type* type, const std::string& symbolic)
+    : t_type(program, symbolic), type_(type), symbolic_(symbolic), forward_(false) {}
+
+  /**
+   * This constructor is used to refer to a type that is lazily
+   * resolved at a later time, like for forward declarations or
+   * recursive types.
+   */
+  t_typedef(t_program* program, const std::string& symbolic, bool forward)
+    : t_type(program, symbolic),
+      type_(NULL),
+      symbolic_(symbolic),
+      forward_(forward)
+  {}
+
+  ~t_typedef() {}
+
+  t_type* get_type() const;
+
+  const std::string& get_symbolic() const { return symbolic_; }
+
+  bool is_forward_typedef() const { return forward_; }
+
+  bool is_typedef() const { return true; }
+
+private:
+  t_type* type_;
+  std::string symbolic_;
+  bool forward_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/platform.h b/compiler/cpp/src/thrift/platform.h
new file mode 100644
index 0000000..f49adb9
--- /dev/null
+++ b/compiler/cpp/src/thrift/platform.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+/**
+ * define for mkdir,since the method signature
+ * is different for the non-POSIX MinGW
+ */
+
+#ifdef _MSC_VER
+#include "thrift/windows/config.h"
+#endif
+
+#ifdef _WIN32
+#include <direct.h>
+#include <io.h>
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+#include <cerrno>
+
+// ignore EEXIST, throw on any other error
+#ifdef _WIN32
+#define MKDIR(x) { int r = _mkdir(x); if (r == -1 && errno != EEXIST) { throw (std::string(x) + ": ") + strerror(errno); } }
+#else
+#define MKDIR(x) { int r = mkdir(x, S_IRWXU | S_IRWXG | S_IRWXO); if (r == -1 && errno != EEXIST) { throw (std::string(x) + ": ") + strerror(errno); } }
+#endif
+
+#ifdef PATH_MAX
+#define THRIFT_PATH_MAX PATH_MAX
+#else
+#define THRIFT_PATH_MAX MAX_PATH
+#endif
diff --git a/compiler/cpp/src/thrift/plugin/Makefile.am b/compiler/cpp/src/thrift/plugin/Makefile.am
new file mode 100644
index 0000000..e84cdbd
--- /dev/null
+++ b/compiler/cpp/src/thrift/plugin/Makefile.am
@@ -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.
+#
+#
+# Contains some contributions under the Thrift Software License.
+# Please see doc/old-thrift-license.txt in the Thrift distribution for
+# details.
+
+AUTOMAKE_OPTIONS = subdir-objects
+
+if WITH_PLUGIN
+plugin_gen = plugin_types.h \
+             plugin_types.cpp \
+             plugin_constants.h \
+             plugin_constants.cpp
+
+BUILT_SOURCES = $(plugin_gen)
+gen.stamp: plugin.thrift $(top_builddir)/compiler/cpp/src/thrift/thrift-bootstrap
+	@$(RM) -f gen.tmp
+	@touch gen.tmp
+	$(top_builddir)/compiler/cpp/src/thrift/thrift-bootstrap -gen cpp -out . $<
+	@mv -f gen.tmp $@
+
+$(plugin_gen): gen.stamp
+	@if test -f $@; then :; else \
+	$(RM) -f gen.stamp; \
+	$(MAKE) $(AM_MAKEFLAGS) gen.stamp; \
+	fi
+
+clean-local:
+	$(RM) version.h windows/version.h $(plugin_gen)
+endif
diff --git a/compiler/cpp/src/thrift/plugin/plugin.cc b/compiler/cpp/src/thrift/plugin/plugin.cc
new file mode 100644
index 0000000..7c4c432
--- /dev/null
+++ b/compiler/cpp/src/thrift/plugin/plugin.cc
@@ -0,0 +1,511 @@
+/*
+ * 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.
+ */
+
+#include "thrift/plugin/plugin.h"
+
+#ifdef _WIN32
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+#include <cassert>
+#include <functional>
+#include <iostream>
+#include <memory>
+
+#include <boost/range/adaptor/map.hpp>
+#include <boost/range/algorithm/for_each.hpp>
+
+#include "thrift/generate/t_generator.h"
+#include "thrift/plugin/type_util.h"
+#include "thrift/protocol/TBinaryProtocol.h"
+#include "thrift/transport/TBufferTransports.h"
+#include "thrift/transport/TFDTransport.h"
+#include "thrift/plugin/plugin_types.h"
+
+namespace apache {
+namespace thrift {
+namespace plugin {
+
+using apache::thrift::protocol::TBinaryProtocol;
+using apache::thrift::transport::TFDTransport;
+using apache::thrift::transport::TFramedTransport;
+
+#define THRIFT_CONVERT_FORWARD(from_type)                                                          \
+  template <>                                                                                      \
+  typename ToType<from_type>::type* convert_forward<from_type>(const from_type& from)
+
+#define THRIFT_CONVERT_COMPLETE_DECL(from_type)                                                    \
+  template <>                                                                                      \
+  void convert(const from_type& from, ToType<from_type>::type* to)
+
+#define THRIFT_CONVERT_UNARY_DECL(from_type)                                                       \
+  template <>                                                                                      \
+  typename ToType<from_type>::type* convert<from_type>(const from_type& from)
+
+#define THRIFT_CONVERSION_DECL(from_type)                                                          \
+  THRIFT_CONVERT_FORWARD(from_type);                                                               \
+  THRIFT_CONVERT_COMPLETE_DECL(from_type);                                                         \
+  THRIFT_CONVERT_UNARY_DECL(from_type)
+
+#define THRIFT_CONVERT_COMPLETE(from_type)                                                         \
+  THRIFT_CONVERSION_DECL(from_type) {                                                              \
+    ToType<from_type>::type* to = convert_forward(from);                                           \
+    convert(from, to);                                                                             \
+    return to;                                                                                     \
+  }                                                                                                \
+  THRIFT_CONVERT_COMPLETE_DECL(from_type)
+
+#define THRIFT_CONVERSION(from_type, ...)                                                          \
+  THRIFT_CONVERT_FORWARD(from_type) {                                                              \
+    (void)from;                                                                                    \
+    return new ToType<from_type>::type(__VA_ARGS__);                                               \
+  }                                                                                                \
+  THRIFT_CONVERT_COMPLETE(from_type)
+
+#define THRIFT_ASSIGN_DOC()                                                                        \
+  do {                                                                                             \
+    if (from.__isset.doc)                                                                          \
+      to->set_doc(from.doc);                                                                       \
+  } while (0)
+
+#define THRIFT_ASSIGN_ANNOTATIONS()                                                                \
+  THRIFT_ASSIGN_DOC();                                                                             \
+  do {                                                                                             \
+    if (from.__isset.annotations)                                                                  \
+      to->annotations_ = from.annotations;                                                         \
+  } while (0)
+
+#define THRIFT_ASSIGN_METADATA()                                                                   \
+  do {                                                                                             \
+    to->set_name(from.metadata.name);                                                              \
+    if (from.metadata.__isset.doc)                                                                 \
+      to->set_doc(from.metadata.doc);                                                              \
+    if (from.metadata.__isset.annotations)                                                         \
+      to->annotations_ = from.metadata.annotations;                                                \
+  } while (0)
+
+::t_program* g_program = 0;
+
+template <typename C, typename S>
+struct TypeCache {
+  C* operator[](const int64_t& k) {
+    typename std::map<int64_t, C*>::iterator it = cache.find(k);
+    if (it != cache.end()) {
+      return it->second;
+    } else {
+      typename std::map<int64_t, S>::const_iterator cit = source->find(k);
+      if (cit == source->end()) {
+        throw ThriftPluginError("Type not found");
+      }
+      return (cache)[k] = convert_forward(cit->second);
+    }
+  }
+
+  void compileAll() {
+    boost::for_each(*source | boost::adaptors::map_keys,
+                    std::bind(&TypeCache::compile, this, std::placeholders::_1));
+  }
+
+  std::map<int64_t, S> const* source;
+
+  void clear() {
+    source = nullptr ;
+    cache.clear() ;
+  }
+
+protected:
+  std::map<int64_t, C*> cache;
+
+private:
+  void compile(const int64_t& k) {
+    typename std::map<int64_t, S>::const_iterator cit = source->find(k);
+    if (cit == source->end()) {
+      throw ThriftPluginError("Type not found ");
+    }
+    convert(cit->second, (*this)[k]);
+  }
+};
+std::map<int64_t, ::t_program*> g_program_cache;
+TypeCache< ::t_type, t_type> g_type_cache;
+TypeCache< ::t_const, t_const> g_const_cache;
+TypeCache< ::t_service, t_service> g_service_cache;
+
+void clear_global_cache() {
+  g_type_cache.clear();
+  g_const_cache.clear();
+  g_service_cache.clear();
+}
+
+void set_global_cache(const TypeRegistry& from) {
+  g_type_cache.source = &from.types;
+  g_const_cache.source = &from.constants;
+  g_service_cache.source = &from.services;
+
+  g_type_cache.compileAll();
+  g_const_cache.compileAll();
+  g_service_cache.compileAll();
+}
+
+template <typename T>
+T* resolve_type(int64_t name) {
+  return reinterpret_cast<T*>(g_type_cache[name]);
+}
+
+::t_const* resolve_const(int64_t name) {
+  return g_const_cache[name];
+}
+
+::t_service* resolve_service(int64_t name) {
+  return g_service_cache[name];
+}
+
+THRIFT_CONVERT_FORWARD(t_base_type) {
+#define T_BASETYPE_CASE(type)                                                                      \
+  case t_base::TYPE_##type:                                                                        \
+    t = ::t_base_type::TYPE_##type;                                                                \
+    break
+
+  ::t_base_type::t_base t = ::t_base_type::TYPE_VOID;
+  bool is_binary = false;
+  switch (from.value) {
+    T_BASETYPE_CASE(VOID);
+    T_BASETYPE_CASE(STRING);
+    T_BASETYPE_CASE(BOOL);
+    T_BASETYPE_CASE(I8);
+    T_BASETYPE_CASE(I16);
+    T_BASETYPE_CASE(I32);
+    T_BASETYPE_CASE(I64);
+    T_BASETYPE_CASE(DOUBLE);
+  case t_base::TYPE_BINARY:
+    t = ::t_base_type::TYPE_STRING;
+    is_binary = true;
+    break;
+  }
+  ::t_base_type* to = new ::t_base_type(from.metadata.name, t);
+  to->set_binary(is_binary);
+  return to;
+#undef T_BASETYPE_CASE
+}
+THRIFT_CONVERT_COMPLETE(t_base_type) {
+  THRIFT_ASSIGN_METADATA();
+}
+
+THRIFT_CONVERT_FORWARD(t_typedef) {
+  ::t_typedef* to;
+  if (from.forward) {
+    to = new ::t_typedef(g_program_cache[from.metadata.program_id], from.symbolic, true);
+  } else {
+    to = new ::t_typedef(g_program_cache[from.metadata.program_id],
+                         resolve_type< ::t_type>(from.type), from.symbolic);
+  }
+  return to;
+}
+THRIFT_CONVERT_COMPLETE(t_typedef) {
+  THRIFT_ASSIGN_METADATA();
+}
+THRIFT_CONVERSION(t_enum_value, from.name, from.value) {
+  assert(to);
+  THRIFT_ASSIGN_ANNOTATIONS();
+}
+THRIFT_CONVERSION(t_enum, g_program_cache[from.metadata.program_id]) {
+  assert(to);
+  THRIFT_ASSIGN_METADATA();
+  boost::for_each(from.constants | boost::adaptors::transformed(convert<t_enum_value>),
+                  std::bind(&::t_enum::append, to, std::placeholders::_1));
+}
+THRIFT_CONVERSION(t_list, resolve_type< ::t_type>(from.elem_type)) {
+  assert(to);
+  THRIFT_ASSIGN_METADATA();
+  if (from.__isset.cpp_name)
+    to->set_cpp_name(from.cpp_name);
+}
+THRIFT_CONVERSION(t_set, resolve_type< ::t_type>(from.elem_type)) {
+  assert(to);
+  THRIFT_ASSIGN_METADATA();
+  if (from.__isset.cpp_name)
+    to->set_cpp_name(from.cpp_name);
+}
+THRIFT_CONVERSION(t_map,
+                  resolve_type< ::t_type>(from.key_type),
+                  resolve_type< ::t_type>(from.val_type)) {
+  assert(to);
+  THRIFT_ASSIGN_METADATA();
+  if (from.__isset.cpp_name)
+    to->set_cpp_name(from.cpp_name);
+}
+THRIFT_CONVERSION(t_const_value, ) {
+#define T_CONST_VALUE_CASE(type)                                                                   \
+  if (from.__isset.type##_val)                                                                     \
+  to->set_##type(from.type##_val)
+
+  assert(to);
+  if (from.__isset.map_val) {
+    to->set_map();
+    for (std::map<t_const_value, t_const_value>::const_iterator it = from.map_val.begin();
+         it != from.map_val.end(); it++) {
+      to->add_map(convert(it->first), convert(it->second));
+    }
+  } else if (from.__isset.list_val) {
+    to->set_list();
+    boost::for_each(from.list_val | boost::adaptors::transformed(&convert<t_const_value>),
+                    std::bind(&::t_const_value::add_list, to, std::placeholders::_1));
+  } else
+    T_CONST_VALUE_CASE(string);
+  else T_CONST_VALUE_CASE(integer);
+  else T_CONST_VALUE_CASE(double);
+  else if (from.__isset.const_identifier_val) {
+    to->set_identifier(from.const_identifier_val.identifier_val) ;
+    to->set_enum(resolve_type< ::t_enum>(from.const_identifier_val.enum_val)) ;
+  }
+
+#undef T_CONST_VALUE_CASE
+}
+THRIFT_CONVERSION(t_field, resolve_type< ::t_type>(from.type), from.name, from.key) {
+  assert(to);
+  THRIFT_ASSIGN_ANNOTATIONS();
+  to->set_reference(from.reference);
+  to->set_req(static_cast< ::t_field::e_req>(from.req));
+  if (from.__isset.value) {
+    to->set_value(convert(from.value));
+  }
+}
+THRIFT_CONVERSION(t_struct, g_program_cache[from.metadata.program_id]) {
+  assert(to);
+  THRIFT_ASSIGN_METADATA();
+  to->set_union(from.is_union);
+  to->set_xception(from.is_xception);
+  boost::for_each(from.members | boost::adaptors::transformed(convert<t_field>),
+                  std::bind(&::t_struct::append, to, std::placeholders::_1));
+}
+THRIFT_CONVERSION(t_const,
+                  resolve_type< ::t_type>(from.type),
+                  from.name,
+                  convert<t_const_value>(from.value)) {
+  assert(to);
+  THRIFT_ASSIGN_DOC();
+}
+
+THRIFT_CONVERSION(t_function,
+                  resolve_type< ::t_type>(from.returntype),
+                  from.name,
+                  resolve_type< ::t_struct>(from.arglist),
+                  resolve_type< ::t_struct>(from.xceptions),
+                  from.is_oneway) {
+  assert(to);
+  THRIFT_ASSIGN_DOC();
+}
+
+THRIFT_CONVERSION(t_service, g_program_cache[from.metadata.program_id]) {
+  assert(to);
+  assert(from.metadata.program_id);
+  assert(g_program_cache[from.metadata.program_id]);
+  THRIFT_ASSIGN_METADATA();
+
+  boost::for_each(from.functions | boost::adaptors::transformed(convert<t_function>),
+                  std::bind(&::t_service::add_function, to, std::placeholders::_1));
+
+  if (from.__isset.extends_)
+    to->set_extends(resolve_service(from.extends_));
+}
+
+THRIFT_CONVERT_FORWARD(t_type) {
+#define T_TYPE_CASE_FW_T(case, type)                                                               \
+  if (from.__isset.case##_val)                                                                     \
+  return convert_forward<type>(from.case##_val)
+#define T_TYPE_CASE_FW(case) T_TYPE_CASE_FW_T(case, t_##case)
+
+  T_TYPE_CASE_FW(base_type);
+  T_TYPE_CASE_FW(typedef);
+  T_TYPE_CASE_FW(enum);
+  T_TYPE_CASE_FW(struct);
+  T_TYPE_CASE_FW_T(xception, t_struct);
+  T_TYPE_CASE_FW(list);
+  T_TYPE_CASE_FW(set);
+  T_TYPE_CASE_FW(map);
+  T_TYPE_CASE_FW(service);
+  throw ThriftPluginError("Invalid data: Type union has no value.");
+#undef T_TYPE_CASE_FW_T
+#undef T_TYPE_CASE_FW
+}
+THRIFT_CONVERT_COMPLETE(t_type) {
+#define T_TYPE_CASE_T(case, type)                                                                  \
+  else if (from.__isset.case##_val)                                                                \
+      convert<type, ::type>(from.case##_val, reinterpret_cast< ::type*>(to))
+#define T_TYPE_CASE(case) T_TYPE_CASE_T(case, t_##case)
+
+  if (false) {
+  }
+  T_TYPE_CASE(base_type);
+  T_TYPE_CASE(typedef);
+  T_TYPE_CASE(enum);
+  T_TYPE_CASE(struct);
+  T_TYPE_CASE_T(xception, t_struct);
+  T_TYPE_CASE(list);
+  T_TYPE_CASE(set);
+  T_TYPE_CASE(map);
+  T_TYPE_CASE(service);
+  else {
+    throw ThriftPluginError("Invalid data: Type union has no value.");
+  }
+#undef T_TYPE_CASE_T
+#undef T_TYPE_CASE
+}
+
+THRIFT_CONVERSION(t_scope, ) {
+  assert(to);
+#define T_SCOPE_RESOLVE(type, name, a)                                                             \
+  for (std::vector<int64_t>::const_iterator it = from.name##s.begin(); it != from.name##s.end();   \
+       it++) {                                                                                     \
+    ::t_##type* t = resolve_##type a(*it);                                                         \
+    to->add_##name(t->get_name(), t);                                                              \
+  }
+  T_SCOPE_RESOLVE(type, type, < ::t_type>);
+  T_SCOPE_RESOLVE(const, constant, );
+  T_SCOPE_RESOLVE(service, service, );
+#undef T_SCOPE_RESOLVE
+}
+
+THRIFT_CONVERT_FORWARD(t_program) {
+  ::t_program* to = new ::t_program(from.path, from.name);
+  for (std::vector<t_program>::const_iterator it = from.includes.begin(); it != from.includes.end();
+       it++) {
+    to->add_include(convert_forward(*it));
+  }
+  g_program_cache[from.program_id] = to;
+  return to;
+}
+THRIFT_CONVERT_COMPLETE(t_program) {
+  assert(to);
+  g_program = to;
+  convert<t_scope, ::t_scope>(from.scope, to->scope());
+  THRIFT_ASSIGN_DOC();
+
+  to->set_out_path(from.out_path, from.out_path_is_absolute);
+
+  boost::for_each(from.typedefs | boost::adaptors::transformed(&resolve_type< ::t_typedef>),
+                  std::bind(&::t_program::add_typedef, to, std::placeholders::_1));
+  boost::for_each(from.enums | boost::adaptors::transformed(&resolve_type< ::t_enum>),
+                  std::bind(&::t_program::add_enum, to, std::placeholders::_1));
+  for (std::vector<int64_t>::const_iterator it = from.objects.begin(); it != from.objects.end();
+       it++) {
+    ::t_struct* t2 = resolve_type< ::t_struct>(*it);
+    if (t2->is_xception()) {
+      to->add_xception(t2);
+    } else {
+      to->add_struct(t2);
+    }
+  }
+  boost::for_each(from.consts | boost::adaptors::transformed(&resolve_const),
+                  std::bind(&::t_program::add_const, to, std::placeholders::_1));
+  boost::for_each(from.services | boost::adaptors::transformed(&resolve_service),
+                  std::bind(&::t_program::add_service, to, std::placeholders::_1));
+
+  for (std::vector<t_program>::const_iterator it = from.includes.begin(); it != from.includes.end();
+       it++) {
+    convert(*it, g_program_cache[it->program_id]);
+  }
+  std::for_each(from.c_includes.begin(), from.c_includes.end(),
+                std::bind(&::t_program::add_c_include, to, std::placeholders::_1));
+  std::for_each(from.cpp_includes.begin(), from.cpp_includes.end(),
+                std::bind(&::t_program::add_cpp_include, to, std::placeholders::_1));
+  for (std::map<std::string, std::string>::const_iterator it = from.namespaces.begin();
+       it != from.namespaces.end(); it++) {
+    to->set_namespace(it->first, it->second);
+  }
+
+  to->set_include_prefix(from.include_prefix);
+  to->set_namespace(from.namespace_);
+}
+
+int GeneratorPlugin::exec(int, char* []) {
+#ifdef _WIN32
+  _setmode(fileno(stdin), _O_BINARY);
+#endif
+  std::shared_ptr<TFramedTransport> transport(
+      new TFramedTransport(std::make_shared<TFDTransport>(fileno(stdin))));
+  TBinaryProtocol proto(transport);
+  GeneratorInput input;
+  try {
+    input.read(&proto);
+  } catch (std::exception& err) {
+    std::cerr << "Error while receiving plugin data: " << err.what() << std::endl;
+    return -1;
+  }
+  initGlobals();
+  ::t_program* p = g_program = convert_forward(input.program);
+  set_global_cache(input.type_registry);
+  convert(input.program, p);
+
+  int ret = generate(p, input.parsed_options);
+  clearGlobals();
+
+  return ret;
+}
+
+::t_const_value::t_const_value_type const_value_case(const t_const_value& v) {
+  if (v.__isset.map_val)
+    return ::t_const_value::CV_MAP;
+  if (v.__isset.list_val)
+    return ::t_const_value::CV_LIST;
+  if (v.__isset.string_val)
+    return ::t_const_value::CV_STRING;
+  if (v.__isset.integer_val)
+    return ::t_const_value::CV_INTEGER;
+  if (v.__isset.double_val)
+    return ::t_const_value::CV_DOUBLE;
+  if (v.__isset.const_identifier_val)
+    return ::t_const_value::CV_IDENTIFIER;
+  throw ThriftPluginError("Unknown const value type");
+}
+
+bool t_const_value::operator<(const t_const_value& that) const {
+  ::t_const_value::t_const_value_type t1 = const_value_case(*this);
+  ::t_const_value::t_const_value_type t2 = const_value_case(that);
+  if (t1 != t2)
+    return t1 < t2;
+  switch (t1) {
+  case ::t_const_value::CV_INTEGER:
+    return integer_val < that.integer_val;
+  case ::t_const_value::CV_DOUBLE:
+    return double_val < that.double_val;
+  case ::t_const_value::CV_STRING:
+    return string_val < that.string_val;
+  case ::t_const_value::CV_MAP:
+    if (that.map_val.empty())
+      return false;
+    else if (map_val.empty())
+      return true;
+    else
+      return map_val.begin()->first < that.map_val.begin()->first;
+  case ::t_const_value::CV_LIST:
+    if (that.list_val.empty())
+      return false;
+    else if (list_val.empty())
+      return true;
+    else
+      return list_val.front() < that.list_val.front();
+  case ::t_const_value::CV_IDENTIFIER:
+    return integer_val < that.integer_val;
+  }
+  throw ThriftPluginError("Unknown const value type");
+}
+}
+}
+}
diff --git a/compiler/cpp/src/thrift/plugin/plugin.h b/compiler/cpp/src/thrift/plugin/plugin.h
new file mode 100644
index 0000000..705cd41
--- /dev/null
+++ b/compiler/cpp/src/thrift/plugin/plugin.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#ifndef T_PLUGIN_PLUGIN_H
+#define T_PLUGIN_PLUGIN_H
+
+#include "thrift/Thrift.h"
+
+class t_program;
+
+namespace apache {
+namespace thrift {
+namespace plugin {
+
+struct ThriftPluginError : public apache::thrift::TException {
+  ThriftPluginError(const std::string& msg) : apache::thrift::TException(msg) {}
+};
+
+class GeneratorPlugin {
+public:
+  int exec(int argc, char* argv[]);
+  virtual int generate(::t_program*, const std::map<std::string, std::string>&) = 0;
+};
+}
+}
+}
+
+#endif
diff --git a/compiler/cpp/src/thrift/plugin/plugin.thrift b/compiler/cpp/src/thrift/plugin/plugin.thrift
new file mode 100644
index 0000000..6d98f99
--- /dev/null
+++ b/compiler/cpp/src/thrift/plugin/plugin.thrift
@@ -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.
+ */
+
+namespace as3 org.apache.thrift.plugin
+namespace cpp apache.thrift.plugin
+namespace csharp Thrift.Plugin
+namespace d thrift.plugin
+namespace delphi Thrift.Plugin
+namespace erl thrift.plugin
+namespace go thrift
+namespace haxe org.apache.thrift.plugin
+namespace hs Thrift.Plugin
+namespace java org.apache.thrift.plugin
+namespace ocaml Thrift
+namespace perl Thrift.Plugin
+namespace php thrift.plugin
+namespace py thrift.plugin
+namespace rb Thrift
+
+typedef i64 t_program_id
+typedef i64 t_type_id
+typedef i64 t_const_id
+typedef i64 t_service_id
+
+enum t_base {
+    TYPE_VOID
+    TYPE_STRING
+    TYPE_BOOL
+    TYPE_I8
+    TYPE_I16
+    TYPE_I32
+    TYPE_I64
+    TYPE_DOUBLE
+    TYPE_BINARY
+}
+
+struct TypeMetadata {
+  1: required string name
+  2: required t_program_id program_id
+  99: optional map<string, string> annotations
+  100: optional string doc
+}
+
+struct t_base_type {
+  1: required TypeMetadata metadata
+  2: required t_base value
+}
+
+struct t_list {
+  1: required TypeMetadata metadata
+  2: optional string cpp_name
+  3: required t_type_id elem_type
+}
+
+struct t_set {
+  1: required TypeMetadata metadata
+  2: optional string cpp_name
+  3: required t_type_id elem_type
+}
+
+struct t_map {
+  1: required TypeMetadata metadata
+  2: optional string cpp_name
+  3: required t_type_id key_type
+  4: required t_type_id val_type
+}
+
+struct t_typedef {
+  1: required TypeMetadata metadata
+  2: required t_type_id type
+  3: required string symbolic
+  4: required bool forward
+}
+
+struct t_enum_value {
+  1: required string name
+  2: required i32 value
+  99: optional map<string, string> annotations
+  100: optional string doc
+}
+struct t_enum {
+  1: required TypeMetadata metadata
+  2: required list<t_enum_value> constants
+}
+
+enum Requiredness {
+  T_REQUIRED = 0
+  T_OPTIONAL = 1
+  T_OPT_IN_REQ_OUT = 2
+}
+
+struct t_const_identifier_value {
+  1: required string identifier_val
+  2: required t_type_id enum_val
+}
+
+union t_const_value {
+  1: optional map<t_const_value, t_const_value> map_val
+  2: optional list<t_const_value> list_val
+  3: optional string string_val
+  4: optional i64 integer_val
+  5: optional double double_val
+  8: optional t_const_identifier_value const_identifier_val
+}
+
+struct t_const {
+  1: required string name
+  2: required t_type_id type
+  3: required t_const_value value
+  100: optional string doc
+}
+struct t_field {
+  1: required string name
+  2: required t_type_id type
+  3: required i32 key
+  4: required Requiredness req
+  5: optional t_const_value value
+  10: required bool reference
+  99: optional map<string, string> annotations
+  100: optional string doc
+}
+struct t_struct {
+  1: required TypeMetadata metadata
+  2: required list<t_field> members
+  3: required bool is_union
+  4: required bool is_xception
+}
+struct t_function {
+  1: required string name
+  2: required t_type_id returntype
+  3: required t_type_id arglist
+  4: required t_type_id xceptions
+  5: required bool is_oneway
+  100: optional string doc
+}
+struct t_service {
+  1: required TypeMetadata metadata
+  2: required list<t_function> functions
+  3: optional t_service_id extends_
+}
+union t_type {
+  1: optional t_base_type base_type_val
+  2: optional t_typedef typedef_val
+  3: optional t_enum enum_val
+  4: optional t_struct struct_val
+  5: optional t_struct xception_val
+  6: optional t_list list_val
+  7: optional t_set set_val
+  8: optional t_map map_val
+  9: optional t_service service_val
+}
+struct t_scope {
+  1: required list<t_type_id> types
+  2: required list<t_const_id> constants
+  3: required list<t_service_id> services
+}
+
+struct TypeRegistry {
+  1: required map<t_type_id, t_type> types
+  2: required map<t_const_id, t_const> constants
+  3: required map<t_service_id, t_service> services
+}
+
+struct t_program {
+  1: required string name
+  2: required t_program_id program_id
+  3: required string path
+  4: required string namespace_
+  5: required string out_path
+  6: required bool out_path_is_absolute
+  8: required list<t_program> includes
+  9: required string include_prefix
+  10: required t_scope scope
+
+  11: required list<t_type_id> typedefs
+  12: required list<t_type_id> enums
+  13: required list<t_const_id> consts
+  14: required list<t_type_id> objects
+  15: required list<t_service_id> services
+
+  16: required map<string, string> namespaces
+  17: required list<string> cpp_includes
+  18: required list<string> c_includes
+  100: optional string doc
+}
+
+struct GeneratorInput {
+  1: required t_program program
+  2: required TypeRegistry type_registry
+  3: required map<string, string> parsed_options
+}
diff --git a/compiler/cpp/src/thrift/plugin/plugin_output.cc b/compiler/cpp/src/thrift/plugin/plugin_output.cc
new file mode 100644
index 0000000..f8223de
--- /dev/null
+++ b/compiler/cpp/src/thrift/plugin/plugin_output.cc
@@ -0,0 +1,455 @@
+/*
+ * 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.
+ */
+
+#ifdef _WIN32
+#include <cstdio>
+#include <fcntl.h>
+#include <io.h>
+#include <iostream>
+#define THRIFT_POPEN(cmd) _popen(cmd, "wb")
+#define THRIFT_PCLOSE _pclose
+#else
+#define THRIFT_POPEN(cmd) popen(cmd, "w")
+#define THRIFT_PCLOSE pclose
+#endif
+
+#include "thrift/plugin/plugin_output.h"
+
+#include <boost/range/adaptor/map.hpp>
+#include <boost/range/algorithm/copy.hpp>
+#include <boost/range/algorithm/transform.hpp>
+
+#include "thrift/generate/t_generator.h"
+#include "thrift/plugin/plugin.h"
+#include "thrift/plugin/type_util.h"
+#include "thrift/protocol/TBinaryProtocol.h"
+#include "thrift/transport/TBufferTransports.h"
+#include "thrift/transport/TFDTransport.h"
+
+#include "thrift/plugin/plugin_types.h"
+
+#include <memory>
+
+namespace plugin_output {
+
+template <typename From>
+typename apache::thrift::plugin::ToType<From>::type convert(From* from) {
+  typename apache::thrift::plugin::ToType<From>::type to;
+  convert(from, to);
+  return to;
+}
+
+using apache::thrift::protocol::TBinaryProtocol;
+using std::make_shared;
+using std::shared_ptr;
+using apache::thrift::transport::TFDTransport;
+using apache::thrift::transport::TFramedTransport;
+
+using namespace apache::thrift;
+
+#define THRIFT_CONVERSION_N(from_type, to_type)                                                    \
+  template <>                                                                                      \
+  void convert<from_type, to_type>(from_type * from, to_type & to)
+#define THRIFT_CONVERSION(type) THRIFT_CONVERSION_N(::type, plugin::type)
+
+#define THRIFT_ASSIGN_N(from_name, to_name, prefix)                                                \
+  do {                                                                                             \
+    if (from)                                                                                      \
+      to.__set_##to_name(prefix(from->from_name));                                                 \
+  } while (0)
+
+#define THRIFT_ASSIGN(name) THRIFT_ASSIGN_N(get_##name(), name, )
+#define THRIFT_ASSIGN_CONVERT(type, from_name, to_name)                                            \
+  do {                                                                                             \
+    if (from && from->from_name) {                                                                 \
+      to.__set_##to_name(convert(from->from_name));                                                \
+    }                                                                                              \
+  } while (0)
+
+#define THRIFT_ASSIGN_OPT(name)                                                                    \
+  do {                                                                                             \
+    if (from->has_##name())                                                                        \
+      THRIFT_ASSIGN(name);                                                                         \
+  } while (0)
+
+#define THRIFT_ASSIGN_LIST_N(type, from_name, to_name)                                             \
+  do {                                                                                             \
+    if (from && !from->from_name.empty()) {                                                        \
+      std::transform(from->from_name.begin(),                                                      \
+                     from->from_name.end(),                                                        \
+                     std::back_inserter(to.to_name),                                               \
+                     convert< ::type>);                                                            \
+    }                                                                                              \
+  } while (0)
+
+#define THRIFT_ASSIGN_METADATA() convert(reinterpret_cast<t_type*>(from), to.metadata)
+
+// a generator of sequential unique identifiers for addresses -- so
+// that the TypeCache below can use those IDs instead of
+// addresses. This allows GeneratorInput's various
+// t_{program,type,etc}_id types to be dense consecutively-numbered
+// integers, instead of large random-seeming integers.
+//
+// Furthermore, this allows GeneratorInput to be deterministic (no
+// addresses, so no pseudo-randomness) and that means reproducibility
+// of output.
+const int64_t ONE_MILLION = 1000 * 1000;
+class id_generator {
+public:
+  id_generator() : addr2id_(), next_id_(ONE_MILLION) {}
+
+  void clear() {
+    addr2id_.clear() ;
+    next_id_ = ONE_MILLION ;
+  }
+
+  int64_t gensym(const int64_t addr) {
+    if (!addr) return 0L ;
+    std::map<int64_t, int64_t>::iterator it = addr2id_.find(addr);
+    if (it != addr2id_.end()) return it->second ;
+    int64_t id = next_id_++ ;
+    addr2id_.insert(std::make_pair(addr, id)) ;
+    return id ;
+  }
+
+  std::map<int64_t, int64_t> addr2id_ ;
+  int64_t next_id_ ;
+} ;
+
+// To avoid multiple instances of same type, t_type, t_const and t_service are stored in one place
+// and referenced by ID.
+template <typename T>
+struct TypeCache {
+  typedef typename plugin::ToType<T>::type to_type;
+  id_generator idgen ;
+  std::map<int64_t, to_type> cache;
+
+  template <typename T2>
+  int64_t store(T2* t) {
+    intptr_t addr = reinterpret_cast<intptr_t>(t);
+    if (!addr) return 0L ;
+
+    int64_t id = idgen.gensym(addr) ;
+    if (cache.end() != cache.find(id)) return id ;
+
+    // HACK: fake resolve for recursive type
+    cache.insert(std::make_pair(id, to_type()));
+    // overwrite with true value
+    cache[id] = convert(t);
+    return id ;
+  }
+
+  void clear() { cache.clear() ; idgen.clear(); }
+};
+
+template <typename T>
+int64_t store_type(T* t);
+
+#define T_STORE(type)                                                                              \
+  TypeCache<t_##type> type##_cache;                                                                \
+  template <>                                                                                      \
+  plugin::t_##type##_id store_type<t_##type>(t_##type * t) {                                       \
+    return type##_cache.store<t_##type>(t);                                                        \
+  }
+T_STORE(type)
+T_STORE(const)
+T_STORE(service)
+#undef T_STORE
+// this id_generator is for gensymm-ing t_program_id
+id_generator program_cache ;
+
+#define THRIFT_ASSIGN_ID_N(t, from_name, to_name)                                                  \
+  do {                                                                                             \
+    if (from && from->from_name)                                                                   \
+      to.__set_##to_name(store_type<t>(from->from_name));                                          \
+  } while (0)
+
+#define THRIFT_ASSIGN_ID(name) THRIFT_ASSIGN_ID_N(t_type, get_##name(), name)
+
+#define THRIFT_ASSIGN_LIST_ID(t, name)                                                             \
+  do {                                                                                             \
+    if (from && !from->get_##name##s().empty()) {                                                  \
+      std::transform(from->get_##name##s().begin(),                                                \
+                     from->get_##name##s().end(),                                                  \
+                     std::back_inserter(to.name##s),                                               \
+                     &store_type<t>);                                                              \
+    }                                                                                              \
+  } while (0)
+
+THRIFT_CONVERSION_N(::t_type, plugin::TypeMetadata) {
+  to.program_id = program_cache.gensym(reinterpret_cast<int64_t>(from->get_program()));
+  THRIFT_ASSIGN_N(annotations_, annotations, );
+  if (from->has_doc()) {
+    to.__set_doc(from->get_doc());
+  }
+  THRIFT_ASSIGN(name);
+}
+
+THRIFT_CONVERSION(t_typedef) {
+  THRIFT_ASSIGN_METADATA();
+  THRIFT_ASSIGN_ID(type);
+  THRIFT_ASSIGN(symbolic);
+  THRIFT_ASSIGN_N(is_forward_typedef(), forward, );
+}
+
+THRIFT_CONVERSION(t_enum_value) {
+  THRIFT_ASSIGN_OPT(doc);
+  THRIFT_ASSIGN(name);
+  THRIFT_ASSIGN(value);
+}
+
+THRIFT_CONVERSION(t_enum) {
+  THRIFT_ASSIGN_METADATA();
+  THRIFT_ASSIGN_LIST_N(t_enum_value, get_constants(), constants);
+}
+
+THRIFT_CONVERSION(t_const_value) {
+  switch (from->get_type()) {
+  case t_const_value::CV_INTEGER:
+    THRIFT_ASSIGN_N(get_integer(), integer_val, );
+    break;
+  case t_const_value::CV_DOUBLE:
+    THRIFT_ASSIGN_N(get_double(), double_val, );
+    break;
+  case t_const_value::CV_STRING:
+    THRIFT_ASSIGN_N(get_string(), string_val, );
+    break;
+  case t_const_value::CV_IDENTIFIER:
+    if (from) {
+      apache::thrift::plugin::t_const_identifier_value cidval ;
+      if (from->enum_)
+	cidval.__set_enum_val(store_type<t_type>(from->enum_));
+      cidval.__set_identifier_val(from->get_identifier());
+      to.__set_const_identifier_val(cidval) ;
+    }
+    break;
+  case t_const_value::CV_MAP:
+    to.__isset.map_val = true;
+    if (from && !from->get_map().empty()) {
+      for (std::map< ::t_const_value*, ::t_const_value*>::const_iterator it
+           = from->get_map().begin();
+           it != from->get_map().end();
+           it++) {
+        to.map_val.insert(std::make_pair(convert(it->first), convert(it->second)));
+      }
+    }
+    break;
+  case t_const_value::CV_LIST:
+    to.__isset.list_val = true;
+    THRIFT_ASSIGN_LIST_N(t_const_value, get_list(), list_val);
+    break;
+  default:
+    throw plugin::ThriftPluginError("const value has no value");
+  }
+}
+THRIFT_CONVERSION(t_const) {
+  THRIFT_ASSIGN_OPT(doc);
+  THRIFT_ASSIGN(name);
+  THRIFT_ASSIGN_ID(type);
+  THRIFT_ASSIGN_CONVERT(t_const_value, get_value(), value);
+}
+THRIFT_CONVERSION(t_field) {
+  THRIFT_ASSIGN_OPT(doc);
+  THRIFT_ASSIGN(name);
+  THRIFT_ASSIGN(key);
+  THRIFT_ASSIGN_N(get_req(), req, (plugin::Requiredness::type));
+  THRIFT_ASSIGN(reference);
+  THRIFT_ASSIGN_ID(type);
+  THRIFT_ASSIGN_CONVERT(t_const_value, get_value(), value);
+}
+THRIFT_CONVERSION(t_struct) {
+  THRIFT_ASSIGN_METADATA();
+  THRIFT_ASSIGN_LIST_N(t_field, get_members(), members);
+  THRIFT_ASSIGN_N(is_union(), is_union, );
+  THRIFT_ASSIGN_N(is_xception(), is_xception, );
+}
+THRIFT_CONVERSION(t_function) {
+  THRIFT_ASSIGN_OPT(doc);
+  THRIFT_ASSIGN(name);
+  THRIFT_ASSIGN_ID(returntype);
+  THRIFT_ASSIGN_N(is_oneway(), is_oneway, );
+  THRIFT_ASSIGN_ID(arglist);
+  THRIFT_ASSIGN_ID(xceptions);
+}
+
+THRIFT_CONVERSION(t_list) {
+  THRIFT_ASSIGN_METADATA();
+  THRIFT_ASSIGN_OPT(cpp_name);
+  THRIFT_ASSIGN_ID(elem_type);
+}
+THRIFT_CONVERSION(t_set) {
+  THRIFT_ASSIGN_METADATA();
+  THRIFT_ASSIGN_OPT(cpp_name);
+  THRIFT_ASSIGN_ID(elem_type);
+}
+THRIFT_CONVERSION(t_map) {
+  THRIFT_ASSIGN_METADATA();
+  THRIFT_ASSIGN_OPT(cpp_name);
+  THRIFT_ASSIGN_ID(key_type);
+  THRIFT_ASSIGN_ID(val_type);
+}
+
+THRIFT_CONVERSION(t_service) {
+  THRIFT_ASSIGN_METADATA();
+  THRIFT_ASSIGN_LIST_N(t_function, get_functions(), functions);
+  THRIFT_ASSIGN_ID_N(t_service, get_extends(), extends_);
+}
+
+THRIFT_CONVERSION(t_base_type) {
+  THRIFT_ASSIGN_METADATA();
+  if (from->is_binary()) {
+    to.value = plugin::t_base::TYPE_BINARY;
+  } else {
+    switch (from->get_base()) {
+#define T_BASETYPE_CASE(name)                                                                      \
+  case t_base_type::TYPE_##name:                                                                   \
+    to.value = plugin::t_base::TYPE_##name;                                                        \
+    break
+      T_BASETYPE_CASE(VOID);
+      T_BASETYPE_CASE(STRING);
+      T_BASETYPE_CASE(BOOL);
+      T_BASETYPE_CASE(I8);
+      T_BASETYPE_CASE(I16);
+      T_BASETYPE_CASE(I32);
+      T_BASETYPE_CASE(I64);
+      T_BASETYPE_CASE(DOUBLE);
+    default:
+      throw plugin::ThriftPluginError("Base type union has no value");
+      break;
+#undef T_BASETYPE_CASE
+    }
+  }
+}
+THRIFT_CONVERSION(t_type) {
+#define T_CONVERT_UNION_N(name, type)                                                              \
+  else if (from->is_##name()) {                                                                    \
+    to.__isset.name##_val = true;                                                                  \
+    convert(reinterpret_cast< ::type*>(from), to.name##_val);                                      \
+  }
+#define T_CONVERT_UNION(name) T_CONVERT_UNION_N(name, t_##name)
+  if (false) {
+  }
+  T_CONVERT_UNION(base_type)
+  T_CONVERT_UNION(typedef)
+  T_CONVERT_UNION(enum)
+  T_CONVERT_UNION(struct)
+  T_CONVERT_UNION_N(xception, t_struct)
+  T_CONVERT_UNION(list)
+  T_CONVERT_UNION(set)
+  T_CONVERT_UNION(map)
+  T_CONVERT_UNION(service)
+  else {
+    throw plugin::ThriftPluginError("Type union has no value");
+  }
+#undef T_CONVERT_UNION_N
+#undef T_CONVERT_UNION
+}
+
+THRIFT_CONVERSION(t_scope) {
+#define T_SCOPE_ASSIGN(name, type)                                                                 \
+  boost::copy(from->name##s_ | boost::adaptors::map_values                                         \
+              | boost::adaptors::transformed(&store_type<type>),                                   \
+              std::back_inserter(to.name##s))
+  T_SCOPE_ASSIGN(type, t_type);
+  T_SCOPE_ASSIGN(constant, t_const);
+  T_SCOPE_ASSIGN(service, t_service);
+#undef T_SCOPE_ASSIGN
+}
+
+void get_global_cache(plugin::TypeRegistry& reg) {
+  reg.types = type_cache.cache;
+  reg.constants = const_cache.cache;
+  reg.services = service_cache.cache;
+}
+
+void clear_global_cache() {
+  type_cache.clear();
+  const_cache.clear();
+  service_cache.clear();
+  program_cache.clear() ;
+}
+
+THRIFT_CONVERSION(t_program) {
+  THRIFT_ASSIGN_CONVERT(t_scope, scope(), scope);
+  THRIFT_ASSIGN(path);
+  THRIFT_ASSIGN(out_path);
+  THRIFT_ASSIGN(name);
+  THRIFT_ASSIGN(include_prefix);
+  THRIFT_ASSIGN(cpp_includes);
+  THRIFT_ASSIGN(c_includes);
+  THRIFT_ASSIGN(namespaces);
+  THRIFT_ASSIGN_N(is_out_path_absolute(), out_path_is_absolute, );
+  THRIFT_ASSIGN_N(get_namespace(), namespace_, );
+  THRIFT_ASSIGN_LIST_ID(t_type, typedef);
+  THRIFT_ASSIGN_LIST_ID(t_type, enum);
+  THRIFT_ASSIGN_LIST_ID(t_type, object);
+  THRIFT_ASSIGN_LIST_ID(t_const, const);
+  THRIFT_ASSIGN_LIST_ID(t_service, service);
+  THRIFT_ASSIGN_LIST_N(t_program, get_includes(), includes);
+  to.program_id = program_cache.gensym(reinterpret_cast<plugin::t_program_id>(from));
+}
+
+PluginDelegateResult delegateToPlugin(t_program* program, const std::string& options) {
+  std::string language;
+  std::map<std::string, std::string> parsed_options;
+  t_generator::parse_options(options, language, parsed_options);
+  std::string cmd = "thrift-gen-";
+  if (language.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-0123456789")
+      != std::string::npos) {
+    std::cerr << "Invalid language name" << std::endl;
+    return PLUGIN_FAILURE;
+  }
+  cmd.append(language);
+  FILE* fd = THRIFT_POPEN(cmd.c_str());
+  if (fd) {
+#ifdef _WIN32
+    _setmode(fileno(fd), _O_BINARY);
+#endif
+    shared_ptr<TFramedTransport> transport(
+        new TFramedTransport(make_shared<TFDTransport>(fileno(fd))));
+    TBinaryProtocol proto(transport);
+
+    plugin::GeneratorInput input;
+    input.__set_parsed_options(parsed_options);
+    clear_global_cache();
+    convert(program, input.program);
+    get_global_cache(input.type_registry);
+    try {
+      input.write(&proto);
+      transport->flush();
+    } catch (std::exception& err) {
+      std::cerr << "Error while sending data to plugin: " << err.what() << std::endl;
+      THRIFT_PCLOSE(fd);
+      return PLUGIN_FAILURE;
+    }
+
+    // TODO: be prepared for hang or crash of child process
+    int ret = THRIFT_PCLOSE(fd);
+    if (!ret) {
+      return PLUGIN_SUCCEESS;
+    } else {
+      std::cerr << "plugin process returned non zero exit code: " << ret << std::endl;
+      return PLUGIN_FAILURE;
+    }
+  }
+  clear_global_cache();
+  return PLUGIN_NOT_FOUND;
+}
+}
+
diff --git a/compiler/cpp/src/thrift/plugin/plugin_output.h b/compiler/cpp/src/thrift/plugin/plugin_output.h
new file mode 100644
index 0000000..eab2d1b
--- /dev/null
+++ b/compiler/cpp/src/thrift/plugin/plugin_output.h
@@ -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.
+ */
+
+#ifndef T_PLUGIN_PLUGIN_OUTPUT_H
+#define T_PLUGIN_PLUGIN_OUTPUT_H
+
+#include <string>
+
+class t_program;
+
+namespace plugin_output {
+
+enum PluginDelegateResult {
+  PLUGIN_NOT_FOUND,
+  PLUGIN_FAILURE,
+  PLUGIN_SUCCEESS,
+};
+
+PluginDelegateResult delegateToPlugin(t_program* program, const std::string& options);
+}
+
+#endif
diff --git a/compiler/cpp/src/thrift/plugin/type_util.h b/compiler/cpp/src/thrift/plugin/type_util.h
new file mode 100644
index 0000000..996b5c6
--- /dev/null
+++ b/compiler/cpp/src/thrift/plugin/type_util.h
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef T_PLUGIN_TYPE_UTIL_H
+#define T_PLUGIN_TYPE_UTIL_H
+
+namespace apache {
+namespace thrift {
+namespace plugin {
+
+template <typename From>
+struct ToType {};
+
+template <typename From>
+typename ToType<From>::type* convert_forward(const From&);
+
+template <typename From, typename To>
+void convert(const From&, To*);
+
+template <typename From>
+typename ToType<From>::type* convert(const From& from);
+
+class TypeRegistry;
+void set_global_cache(const TypeRegistry&);
+void clear_global_cache();
+}
+}
+}
+
+// conversion from raw compiler types to plugin wire type
+namespace plugin_output {
+
+template <typename From, typename To>
+void convert(From* from, To& to);
+
+template <typename From>
+typename apache::thrift::plugin::ToType<From>::type convert(From* from);
+
+void get_global_cache(apache::thrift::plugin::TypeRegistry&);
+void clear_global_cache();
+}
+
+#define THRIFT_TYPE_MAPPING(TYPE)                                                                  \
+  class TYPE;                                                                                      \
+  namespace apache {                                                                               \
+  namespace thrift {                                                                               \
+  namespace plugin {                                                                               \
+  class TYPE;                                                                                      \
+  template <>                                                                                      \
+  struct ToType< ::TYPE> {                                                                         \
+    typedef TYPE type;                                                                             \
+  };                                                                                               \
+  template <>                                                                                      \
+  struct ToType<TYPE> {                                                                            \
+    typedef ::TYPE type;                                                                           \
+  };                                                                                               \
+  }                                                                                                \
+  }                                                                                                \
+  }
+THRIFT_TYPE_MAPPING(t_base_type)
+THRIFT_TYPE_MAPPING(t_const)
+THRIFT_TYPE_MAPPING(t_const_value)
+THRIFT_TYPE_MAPPING(t_container)
+THRIFT_TYPE_MAPPING(t_doc)
+THRIFT_TYPE_MAPPING(t_enum)
+THRIFT_TYPE_MAPPING(t_enum_value)
+THRIFT_TYPE_MAPPING(t_field)
+THRIFT_TYPE_MAPPING(t_function)
+THRIFT_TYPE_MAPPING(t_list)
+THRIFT_TYPE_MAPPING(t_map)
+THRIFT_TYPE_MAPPING(t_program)
+THRIFT_TYPE_MAPPING(t_scope)
+THRIFT_TYPE_MAPPING(t_service)
+THRIFT_TYPE_MAPPING(t_set)
+THRIFT_TYPE_MAPPING(t_struct)
+THRIFT_TYPE_MAPPING(t_type)
+THRIFT_TYPE_MAPPING(t_typedef)
+#undef THRIFT_TYPE_MAPPING
+#endif
diff --git a/compiler/cpp/src/thrift/thriftl.ll b/compiler/cpp/src/thrift/thriftl.ll
new file mode 100644
index 0000000..4f783be
--- /dev/null
+++ b/compiler/cpp/src/thrift/thriftl.ll
@@ -0,0 +1,363 @@
+/*
+ * 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.
+ */
+
+/**
+ * Thrift scanner.
+ *
+ * Tokenizes a thrift definition file.
+ */
+
+%{
+
+/* This is redundant with some of the flags in Makefile.am, but it works
+ * when people override CXXFLAGS without being careful. The pragmas are
+ * the 'right' way to do it, but don't work on old-enough GCC (in particular
+ * the GCC that ship on Mac OS X 10.6.5, *counter* to what the GNU docs say)
+ *
+ * We should revert the Makefile.am changes once Apple ships a reasonable
+ * GCC.
+ */
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-label"
+#endif
+
+#ifdef _MSC_VER
+#pragma warning( push )
+
+// warning C4102: 'find_rule' : unreferenced label
+#pragma warning( disable : 4102 )
+
+// warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data
+#pragma warning( disable : 4267 )
+
+// avoid isatty redefinition
+#define YY_NEVER_INTERACTIVE 1
+
+#define YY_NO_UNISTD_H 1
+#endif
+
+#include <cassert>
+#include <string>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifdef _MSC_VER
+#include "thrift/windows/config.h"
+#endif
+#include "thrift/main.h"
+#include "thrift/common.h"
+#include "thrift/globals.h"
+#include "thrift/parse/t_program.h"
+
+/**
+ * Must be included AFTER parse/t_program.h, but I can't remember why anymore
+ * because I wrote this a while ago.
+ */
+#if defined(BISON_USE_PARSER_H_EXTENSION)
+#include "thrift/thrifty.h"
+#else
+#include "thrift/thrifty.hh"
+#endif
+
+void integer_overflow(char* text) {
+  yyerror("This integer is too big: \"%s\"\n", text);
+  exit(1);
+}
+
+void unexpected_token(char* text) {
+  yyerror("Unexpected token in input: \"%s\"\n", text);
+  exit(1);
+}
+
+%}
+
+/**
+ * Provides the yylineno global, useful for debugging output
+ */
+%option lex-compat
+
+/**
+ * Our inputs are all single files, so no need for yywrap
+ */
+%option noyywrap
+
+/**
+ * We don't use it, and it fires up warnings at -Wall
+ */
+%option nounput
+
+/**
+ * Helper definitions, comments, constants, and whatnot
+ */
+
+intconstant   ([+-]?[0-9]+)
+hexconstant   ([+-]?"0x"[0-9A-Fa-f]+)
+dubconstant   ([+-]?[0-9]*(\.[0-9]+)?([eE][+-]?[0-9]+)?)
+identifier    ([a-zA-Z_](\.[a-zA-Z_0-9]|[a-zA-Z_0-9])*)
+whitespace    ([ \t\r\n]*)
+sillycomm     ("/*""*"*"*/")
+multicm_begin ("/*")
+doctext_begin ("/**")
+comment       ("//"[^\n]*)
+unixcomment   ("#"[^\n]*)
+symbol        ([:;\,\{\}\(\)\=<>\[\]])
+literal_begin (['\"])
+
+%%
+
+{whitespace}         { /* do nothing */                 }
+{sillycomm}          { /* do nothing */                 }
+
+{doctext_begin} {
+  std::string parsed("/**");
+  int state = 0;  // 0 = normal, 1 = "*" seen, "*/" seen
+  while(state < 2)
+  {
+    int ch = yyinput();
+    parsed.push_back(ch);
+    switch (ch) {
+      case EOF:
+        yyerror("Unexpected end of file in doc-comment at %d\n", yylineno);
+        exit(1);
+      case '*':
+        state = 1;
+        break;
+      case '/':
+        state = (state == 1) ? 2 : 0;
+        break;
+      default:
+        state = 0;
+        break;
+    }
+  }
+  pdebug("doctext = \"%s\"\n",parsed.c_str());
+
+ /* This does not show up in the parse tree. */
+ /* Rather, the parser will grab it out of the global. */
+  if (g_parse_mode == PROGRAM) {
+    clear_doctext();
+    g_doctext = strdup(parsed.c_str() + 3);
+    assert(strlen(g_doctext) >= 2);
+    g_doctext[strlen(g_doctext) - 2] = ' ';
+    g_doctext[strlen(g_doctext) - 1] = '\0';
+    g_doctext = clean_up_doctext(g_doctext);
+    g_doctext_lineno = yylineno;
+    if( (g_program_doctext_candidate == NULL) && (g_program_doctext_status == INVALID)){
+      g_program_doctext_candidate = strdup(g_doctext);
+      g_program_doctext_lineno = g_doctext_lineno;
+      g_program_doctext_status = STILL_CANDIDATE;
+      pdebug("%s","program doctext set to STILL_CANDIDATE");
+    }
+  }
+}
+
+{multicm_begin}  { /* parsed, but thrown away */
+  std::string parsed("/*");
+  int state = 0;  // 0 = normal, 1 = "*" seen, "*/" seen
+  while(state < 2)
+  {
+    int ch = yyinput();
+    parsed.push_back(ch);
+    switch (ch) {
+      case EOF:
+        yyerror("Unexpected end of file in multiline comment at %d\n", yylineno);
+        exit(1);
+      case '*':
+        state = 1;
+        break;
+      case '/':
+        state = (state == 1) ? 2 : 0;
+        break;
+      default:
+        state = 0;
+        break;
+    }
+  }
+  pdebug("multi_comm = \"%s\"\n",parsed.c_str());
+}
+
+{comment}            { /* do nothing */                 }
+{unixcomment}        { /* do nothing */                 }
+
+{symbol}             { return yytext[0];                }
+"*"                  { return yytext[0];                }
+
+"false"              { yylval.iconst=0; return tok_int_constant; }
+"true"               { yylval.iconst=1; return tok_int_constant; }
+
+"namespace"          { return tok_namespace;            }
+"cpp_namespace"      { error_unsupported_namespace_decl("cpp"); /* do nothing */ }
+"cpp_include"        { return tok_cpp_include;          }
+"cpp_type"           { return tok_cpp_type;             }
+"java_package"       { error_unsupported_namespace_decl("java_package", "java"); /* do nothing */ }
+"cocoa_prefix"       { error_unsupported_namespace_decl("cocoa_prefix", "cocoa"); /* do nothing */ }
+"csharp_namespace"   { error_unsupported_namespace_decl("csharp"); /* do nothing */ }
+"delphi_namespace"   { error_unsupported_namespace_decl("delphi"); /* do nothing */ }
+"php_namespace"      { error_unsupported_namespace_decl("php"); /* do nothing */ }
+"py_module"          { error_unsupported_namespace_decl("py_module", "py"); /* do nothing */ }
+"perl_package"       { error_unsupported_namespace_decl("perl_package", "perl"); /* do nothing */ }
+"ruby_namespace"     { error_unsupported_namespace_decl("ruby"); /* do nothing */ }
+"smalltalk_category" { error_unsupported_namespace_decl("smalltalk_category", "smalltalk.category"); /* do nothing */ }
+"smalltalk_prefix"   { error_unsupported_namespace_decl("smalltalk_category", "smalltalk.category"); /* do nothing */ }
+"xsd_all"            { return tok_xsd_all;              }
+"xsd_optional"       { return tok_xsd_optional;         }
+"xsd_nillable"       { return tok_xsd_nillable;         }
+"xsd_namespace"      { error_unsupported_namespace_decl("xsd"); /* do nothing */ }
+"xsd_attrs"          { return tok_xsd_attrs;            }
+"include"            { return tok_include;              }
+"void"               { return tok_void;                 }
+"bool"               { return tok_bool;                 }
+"byte"               {
+  emit_byte_type_warning();
+  return tok_i8;
+}
+"i8"                 { return tok_i8;                   }
+"i16"                { return tok_i16;                  }
+"i32"                { return tok_i32;                  }
+"i64"                { return tok_i64;                  }
+"double"             { return tok_double;               }
+"string"             { return tok_string;               }
+"binary"             { return tok_binary;               }
+"slist" {
+  pwarning(0, "\"slist\" is deprecated and will be removed in a future compiler version.  This type should be replaced with \"string\".\n");
+  return tok_slist;
+}
+"senum" {
+  pwarning(0, "\"senum\" is deprecated and will be removed in a future compiler version.  This type should be replaced with \"string\".\n");
+  return tok_senum;
+}
+"map"                { return tok_map;                  }
+"list"               { return tok_list;                 }
+"set"                { return tok_set;                  }
+"oneway"             { return tok_oneway;               }
+"typedef"            { return tok_typedef;              }
+"struct"             { return tok_struct;               }
+"union"              { return tok_union;                }
+"exception"          { return tok_xception;             }
+"extends"            { return tok_extends;              }
+"throws"             { return tok_throws;               }
+"service"            { return tok_service;              }
+"enum"               { return tok_enum;                 }
+"const"              { return tok_const;                }
+"required"           { return tok_required;             }
+"optional"           { return tok_optional;             }
+"async" {
+  pwarning(0, "\"async\" is deprecated.  It is called \"oneway\" now.\n");
+  return tok_oneway;
+}
+"&"                  { return tok_reference;            }
+
+{intconstant} {
+  errno = 0;
+  yylval.iconst = strtoll(yytext, NULL, 10);
+  if (errno == ERANGE) {
+    integer_overflow(yytext);
+  }
+  return tok_int_constant;
+}
+
+{hexconstant} {
+  errno = 0;
+  char sign = yytext[0];
+  int shift = sign == '0' ? 2 : 3;
+  yylval.iconst = strtoll(yytext+shift, NULL, 16);
+  if (sign == '-') {
+    yylval.iconst = -yylval.iconst;
+  }
+  if (errno == ERANGE) {
+    integer_overflow(yytext);
+  }
+  return tok_int_constant;
+}
+
+{identifier} {
+  yylval.id = strdup(yytext);
+  return tok_identifier;
+}
+
+{dubconstant} {
+ /* Deliberately placed after identifier, since "e10" is NOT a double literal (THRIFT-3477) */
+  yylval.dconst = atof(yytext);
+  return tok_dub_constant;
+}
+
+{literal_begin} {
+  char mark = yytext[0];
+  std::string result;
+  for(;;)
+  {
+    int ch = yyinput();
+    switch (ch) {
+      case EOF:
+        yyerror("End of file while read string at %d\n", yylineno);
+        exit(1);
+      case '\n':
+        yyerror("End of line while read string at %d\n", yylineno - 1);
+        exit(1);
+      case '\\':
+        ch = yyinput();
+        switch (ch) {
+          case 'r':
+            result.push_back('\r');
+            continue;
+          case 'n':
+            result.push_back('\n');
+            continue;
+          case 't':
+            result.push_back('\t');
+            continue;
+          case '"':
+            result.push_back('"');
+            continue;
+          case '\'':
+            result.push_back('\'');
+            continue;
+          case '\\':
+            result.push_back('\\');
+            continue;
+          default:
+            yyerror("Bad escape character\n");
+            return -1;
+        }
+        break;
+      default:
+        if (ch == mark) {
+          yylval.id = strdup(result.c_str());
+          return tok_literal;
+        } else {
+          result.push_back(ch);
+        }
+    }
+  }
+}
+
+
+. {
+  unexpected_token(yytext);
+}
+
+%%
+
+#ifdef _MSC_VER
+#pragma warning( pop )
+#endif
+
+/* vim: filetype=lex
+*/
diff --git a/compiler/cpp/src/thrift/thrifty.yy b/compiler/cpp/src/thrift/thrifty.yy
new file mode 100644
index 0000000..df34adf
--- /dev/null
+++ b/compiler/cpp/src/thrift/thrifty.yy
@@ -0,0 +1,1201 @@
+%code requires {
+#include "thrift/parse/t_program.h"
+}
+%{
+/*
+ * 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.
+ */
+
+/**
+ * Thrift parser.
+ *
+ * This parser is used on a thrift definition file.
+ *
+ */
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif
+#include <stdio.h>
+#include <string.h>
+#ifndef _MSC_VER
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif
+#include <limits.h>
+#ifdef _MSC_VER
+#include "thrift/windows/config.h"
+#endif
+#include "thrift/main.h"
+#include "thrift/common.h"
+#include "thrift/globals.h"
+#include "thrift/parse/t_program.h"
+#include "thrift/parse/t_scope.h"
+
+#ifdef _MSC_VER
+//warning C4065: switch statement contains 'default' but no 'case' labels
+#pragma warning(disable:4065)
+#endif
+
+/**
+ * This global variable is used for automatic numbering of field indices etc.
+ * when parsing the members of a struct. Field values are automatically
+ * assigned starting from -1 and working their way down.
+ */
+int y_field_val = -1;
+/**
+ * This global variable is used for automatic numbering of enum values.
+ * y_enum_val is the last value assigned; the next auto-assigned value will be
+ * y_enum_val+1, and then it continues working upwards.  Explicitly specified
+ * enum values reset y_enum_val to that value.
+ */
+int32_t y_enum_val = -1;
+int g_arglist = 0;
+const int struct_is_struct = 0;
+const int struct_is_union = 1;
+
+%}
+
+/**
+ * This structure is used by the parser to hold the data types associated with
+ * various parse nodes.
+ */
+%union {
+  char*          id;
+  int64_t        iconst;
+  double         dconst;
+  bool           tbool;
+  t_doc*         tdoc;
+  t_type*        ttype;
+  t_base_type*   tbase;
+  t_typedef*     ttypedef;
+  t_enum*        tenum;
+  t_enum_value*  tenumv;
+  t_const*       tconst;
+  t_const_value* tconstv;
+  t_struct*      tstruct;
+  t_service*     tservice;
+  t_function*    tfunction;
+  t_field*       tfield;
+  char*          dtext;
+  t_field::e_req ereq;
+  t_annotation*  tannot;
+  t_field_id     tfieldid;
+}
+
+/**
+ * Strings identifier
+ */
+%token<id>     tok_identifier
+%token<id>     tok_literal
+%token<dtext>  tok_doctext
+
+/**
+ * Constant values
+ */
+%token<iconst> tok_int_constant
+%token<dconst> tok_dub_constant
+
+/**
+ * Header keywords
+ */
+%token tok_include
+%token tok_namespace
+%token tok_cpp_include
+%token tok_cpp_type
+%token tok_xsd_all
+%token tok_xsd_optional
+%token tok_xsd_nillable
+%token tok_xsd_attrs
+
+/**
+ * Base datatype keywords
+ */
+%token tok_void
+%token tok_bool
+%token tok_string
+%token tok_binary
+%token tok_slist
+%token tok_senum
+%token tok_i8
+%token tok_i16
+%token tok_i32
+%token tok_i64
+%token tok_double
+
+/**
+ * Complex type keywords
+ */
+%token tok_map
+%token tok_list
+%token tok_set
+
+/**
+ * Function modifiers
+ */
+%token tok_oneway
+
+/**
+ * Thrift language keywords
+ */
+%token tok_typedef
+%token tok_struct
+%token tok_xception
+%token tok_throws
+%token tok_extends
+%token tok_service
+%token tok_enum
+%token tok_const
+%token tok_required
+%token tok_optional
+%token tok_union
+%token tok_reference
+
+/**
+ * Grammar nodes
+ */
+
+%type<ttype>     BaseType
+%type<ttype>     SimpleBaseType
+%type<ttype>     ContainerType
+%type<ttype>     SimpleContainerType
+%type<ttype>     MapType
+%type<ttype>     SetType
+%type<ttype>     ListType
+
+%type<tdoc>      Definition
+%type<ttype>     TypeDefinition
+
+%type<ttypedef>  Typedef
+
+%type<ttype>     TypeAnnotations
+%type<ttype>     TypeAnnotationList
+%type<tannot>    TypeAnnotation
+%type<id>        TypeAnnotationValue
+
+%type<tfield>    Field
+%type<tfieldid>  FieldIdentifier
+%type<ereq>      FieldRequiredness
+%type<ttype>     FieldType
+%type<tconstv>   FieldValue
+%type<tstruct>   FieldList
+%type<tbool>     FieldReference
+
+%type<tenum>     Enum
+%type<tenum>     EnumDefList
+%type<tenumv>    EnumDef
+%type<tenumv>    EnumValue
+
+%type<ttypedef>  Senum
+%type<tbase>     SenumDefList
+%type<id>        SenumDef
+
+%type<tconst>    Const
+%type<tconstv>   ConstValue
+%type<tconstv>   ConstList
+%type<tconstv>   ConstListContents
+%type<tconstv>   ConstMap
+%type<tconstv>   ConstMapContents
+
+%type<iconst>    StructHead
+%type<tstruct>   Struct
+%type<tstruct>   Xception
+%type<tservice>  Service
+
+%type<tfunction> Function
+%type<ttype>     FunctionType
+%type<tservice>  FunctionList
+
+%type<tstruct>   Throws
+%type<tservice>  Extends
+%type<tbool>     Oneway
+%type<tbool>     XsdAll
+%type<tbool>     XsdOptional
+%type<tbool>     XsdNillable
+%type<tstruct>   XsdAttributes
+%type<id>        CppType
+
+%type<dtext>     CaptureDocText
+
+%%
+
+/**
+ * Thrift Grammar Implementation.
+ *
+ * For the most part this source file works its way top down from what you
+ * might expect to find in a typical .thrift file, i.e. type definitions and
+ * namespaces up top followed by service definitions using those types.
+ */
+
+Program:
+  HeaderList DefinitionList
+    {
+      pdebug("Program -> Headers DefinitionList");
+      if((g_program_doctext_candidate != NULL) && (g_program_doctext_status != ALREADY_PROCESSED))
+      {
+        g_program->set_doc(g_program_doctext_candidate);
+        g_program_doctext_status = ALREADY_PROCESSED;
+      }
+      clear_doctext();
+    }
+
+CaptureDocText:
+    {
+      if (g_parse_mode == PROGRAM) {
+        $$ = g_doctext;
+        g_doctext = NULL;
+      } else {
+        $$ = NULL;
+      }
+    }
+
+/* TODO(dreiss): Try to DestroyDocText in all sorts or random places. */
+DestroyDocText:
+    {
+      if (g_parse_mode == PROGRAM) {
+        clear_doctext();
+      }
+    }
+
+/* We have to DestroyDocText here, otherwise it catches the doctext
+   on the first real element. */
+HeaderList:
+  HeaderList DestroyDocText Header
+    {
+      pdebug("HeaderList -> HeaderList Header");
+    }
+|
+    {
+      pdebug("HeaderList -> ");
+    }
+
+Header:
+  Include
+    {
+      pdebug("Header -> Include");
+    }
+| tok_namespace tok_identifier tok_identifier TypeAnnotations
+    {
+      pdebug("Header -> tok_namespace tok_identifier tok_identifier");
+      declare_valid_program_doctext();
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_namespace($2, $3);
+      }
+      if ($4 != NULL) {
+        g_program->set_namespace_annotations($2, $4->annotations_);
+        delete $4;
+      }
+    }
+| tok_namespace '*' tok_identifier
+    {
+      pdebug("Header -> tok_namespace * tok_identifier");
+      declare_valid_program_doctext();
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_namespace("*", $3);
+      }
+    }
+| tok_cpp_include tok_literal
+    {
+      pdebug("Header -> tok_cpp_include tok_literal");
+      declare_valid_program_doctext();
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_cpp_include($2);
+      }
+    }
+
+Include:
+  tok_include tok_literal
+    {
+      pdebug("Include -> tok_include tok_literal");
+      declare_valid_program_doctext();
+      if (g_parse_mode == INCLUDES) {
+        std::string path = include_file(std::string($2));
+        if (!path.empty()) {
+          g_program->add_include(path, std::string($2));
+        }
+      }
+    }
+
+DefinitionList:
+  DefinitionList CaptureDocText Definition
+    {
+      pdebug("DefinitionList -> DefinitionList Definition");
+      if ($2 != NULL && $3 != NULL) {
+        $3->set_doc($2);
+      }
+    }
+|
+    {
+      pdebug("DefinitionList -> ");
+    }
+
+Definition:
+  Const
+    {
+      pdebug("Definition -> Const");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_const($1);
+      }
+      $$ = $1;
+    }
+| TypeDefinition
+    {
+      pdebug("Definition -> TypeDefinition");
+      if (g_parse_mode == PROGRAM) {
+        g_scope->add_type($1->get_name(), $1);
+        if (g_parent_scope != NULL) {
+          g_parent_scope->add_type(g_parent_prefix + $1->get_name(), $1);
+        }
+        if (! g_program->is_unique_typename($1)) {
+          yyerror("Type \"%s\" is already defined.", $1->get_name().c_str());
+          exit(1);
+        }
+      }
+      $$ = $1;
+    }
+| Service
+    {
+      pdebug("Definition -> Service");
+      if (g_parse_mode == PROGRAM) {
+        g_scope->add_service($1->get_name(), $1);
+        if (g_parent_scope != NULL) {
+          g_parent_scope->add_service(g_parent_prefix + $1->get_name(), $1);
+        }
+        g_program->add_service($1);
+        if (! g_program->is_unique_typename($1)) {
+          yyerror("Type \"%s\" is already defined.", $1->get_name().c_str());
+          exit(1);
+        }
+      }
+      $$ = $1;
+    }
+
+TypeDefinition:
+  Typedef
+    {
+      pdebug("TypeDefinition -> Typedef");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_typedef($1);
+      }
+    }
+| Enum
+    {
+      pdebug("TypeDefinition -> Enum");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_enum($1);
+      }
+    }
+| Senum
+    {
+      pdebug("TypeDefinition -> Senum");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_typedef($1);
+      }
+    }
+| Struct
+    {
+      pdebug("TypeDefinition -> Struct");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_struct($1);
+      }
+    }
+| Xception
+    {
+      pdebug("TypeDefinition -> Xception");
+      if (g_parse_mode == PROGRAM) {
+        g_program->add_xception($1);
+      }
+    }
+
+CommaOrSemicolonOptional:
+  ','
+    {}
+| ';'
+    {}
+|
+    {}
+
+Typedef:
+  tok_typedef FieldType tok_identifier TypeAnnotations CommaOrSemicolonOptional
+    {
+      pdebug("TypeDef -> tok_typedef FieldType tok_identifier");
+      validate_simple_identifier( $3);
+      t_typedef *td = new t_typedef(g_program, $2, $3);
+      $$ = td;
+      if ($4 != NULL) {
+        $$->annotations_ = $4->annotations_;
+        delete $4;
+      }
+    }
+
+Enum:
+  tok_enum tok_identifier '{' EnumDefList '}' TypeAnnotations
+    {
+      pdebug("Enum -> tok_enum tok_identifier { EnumDefList }");
+      $$ = $4;
+      validate_simple_identifier( $2);
+      $$->set_name($2);
+      if ($6 != NULL) {
+        $$->annotations_ = $6->annotations_;
+        delete $6;
+      }
+
+      // make constants for all the enum values
+      if (g_parse_mode == PROGRAM) {
+        const std::vector<t_enum_value*>& enum_values = $$->get_constants();
+        std::vector<t_enum_value*>::const_iterator c_iter;
+        for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) {
+          std::string const_name = $$->get_name() + "." + (*c_iter)->get_name();
+          t_const_value* const_val = new t_const_value((*c_iter)->get_value());
+          const_val->set_enum($$);
+          g_scope->add_constant(const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val));
+          if (g_parent_scope != NULL) {
+            g_parent_scope->add_constant(g_parent_prefix + const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val));
+          }
+        }
+      }
+    }
+
+EnumDefList:
+  EnumDefList EnumDef
+    {
+      pdebug("EnumDefList -> EnumDefList EnumDef");
+      $$ = $1;
+      $$->append($2);
+    }
+|
+    {
+      pdebug("EnumDefList -> ");
+      $$ = new t_enum(g_program);
+      y_enum_val = -1;
+    }
+
+EnumDef:
+  CaptureDocText EnumValue TypeAnnotations CommaOrSemicolonOptional
+    {
+      pdebug("EnumDef -> EnumValue");
+      $$ = $2;
+      if ($1 != NULL) {
+        $$->set_doc($1);
+      }
+	  if ($3 != NULL) {
+        $$->annotations_ = $3->annotations_;
+        delete $3;
+      }
+    }
+
+EnumValue:
+  tok_identifier '=' tok_int_constant
+    {
+      pdebug("EnumValue -> tok_identifier = tok_int_constant");
+      if ($3 < INT32_MIN || $3 > INT32_MAX) {
+        // Note: this used to be just a warning.  However, since thrift always
+        // treats enums as i32 values, I'm changing it to a fatal error.
+        // I doubt this will affect many people, but users who run into this
+        // will have to update their thrift files to manually specify the
+        // truncated i32 value that thrift has always been using anyway.
+        failure("64-bit value supplied for enum %s will be truncated.", $1);
+      }
+      y_enum_val = static_cast<int32_t>($3);
+      $$ = new t_enum_value($1, y_enum_val);
+    }
+ |
+  tok_identifier
+    {
+      pdebug("EnumValue -> tok_identifier");
+      validate_simple_identifier( $1);
+      if (y_enum_val == INT32_MAX) {
+        failure("enum value overflow at enum %s", $1);
+      }
+      ++y_enum_val;
+      $$ = new t_enum_value($1, y_enum_val);
+    }
+
+Senum:
+  tok_senum tok_identifier '{' SenumDefList '}' TypeAnnotations
+    {
+      pdebug("Senum -> tok_senum tok_identifier { SenumDefList }");
+      validate_simple_identifier( $2);
+      $$ = new t_typedef(g_program, $4, $2);
+      if ($6 != NULL) {
+        $$->annotations_ = $6->annotations_;
+        delete $6;
+      }
+    }
+
+SenumDefList:
+  SenumDefList SenumDef
+    {
+      pdebug("SenumDefList -> SenumDefList SenumDef");
+      $$ = $1;
+      $$->add_string_enum_val($2);
+    }
+|
+    {
+      pdebug("SenumDefList -> ");
+      $$ = new t_base_type("string", t_base_type::TYPE_STRING);
+      $$->set_string_enum(true);
+    }
+
+SenumDef:
+  tok_literal CommaOrSemicolonOptional
+    {
+      pdebug("SenumDef -> tok_literal");
+      $$ = $1;
+    }
+
+Const:
+  tok_const FieldType tok_identifier '=' ConstValue CommaOrSemicolonOptional
+    {
+      pdebug("Const -> tok_const FieldType tok_identifier = ConstValue");
+      if (g_parse_mode == PROGRAM) {
+        validate_simple_identifier( $3);
+        g_scope->resolve_const_value($5, $2);
+        $$ = new t_const($2, $3, $5);
+        validate_const_type($$);
+
+        g_scope->add_constant($3, $$);
+        if (g_parent_scope != NULL) {
+          g_parent_scope->add_constant(g_parent_prefix + $3, $$);
+        }
+      } else {
+        $$ = NULL;
+      }
+    }
+
+ConstValue:
+  tok_int_constant
+    {
+      pdebug("ConstValue => tok_int_constant");
+      $$ = new t_const_value();
+      $$->set_integer($1);
+      if (!g_allow_64bit_consts && ($1 < INT32_MIN || $1 > INT32_MAX)) {
+        pwarning(1, "64-bit constant \"%" PRIi64"\" may not work in all languages.\n", $1);
+      }
+    }
+| tok_dub_constant
+    {
+      pdebug("ConstValue => tok_dub_constant");
+      $$ = new t_const_value();
+      $$->set_double($1);
+    }
+| tok_literal
+    {
+      pdebug("ConstValue => tok_literal");
+      $$ = new t_const_value($1);
+    }
+| tok_identifier
+    {
+      pdebug("ConstValue => tok_identifier");
+      $$ = new t_const_value();
+      $$->set_identifier($1);
+    }
+| ConstList
+    {
+      pdebug("ConstValue => ConstList");
+      $$ = $1;
+    }
+| ConstMap
+    {
+      pdebug("ConstValue => ConstMap");
+      $$ = $1;
+    }
+
+ConstList:
+  '[' ConstListContents ']'
+    {
+      pdebug("ConstList => [ ConstListContents ]");
+      $$ = $2;
+    }
+
+ConstListContents:
+  ConstListContents ConstValue CommaOrSemicolonOptional
+    {
+      pdebug("ConstListContents => ConstListContents ConstValue CommaOrSemicolonOptional");
+      $$ = $1;
+      $$->add_list($2);
+    }
+|
+    {
+      pdebug("ConstListContents =>");
+      $$ = new t_const_value();
+      $$->set_list();
+    }
+
+ConstMap:
+  '{' ConstMapContents '}'
+    {
+      pdebug("ConstMap => { ConstMapContents }");
+      $$ = $2;
+    }
+
+ConstMapContents:
+  ConstMapContents ConstValue ':' ConstValue CommaOrSemicolonOptional
+    {
+      pdebug("ConstMapContents => ConstMapContents ConstValue CommaOrSemicolonOptional");
+      $$ = $1;
+      $$->add_map($2, $4);
+    }
+|
+    {
+      pdebug("ConstMapContents =>");
+      $$ = new t_const_value();
+      $$->set_map();
+    }
+
+StructHead:
+  tok_struct
+    {
+      $$ = struct_is_struct;
+    }
+| tok_union
+    {
+      $$ = struct_is_union;
+    }
+
+Struct:
+  StructHead tok_identifier XsdAll '{' FieldList '}' TypeAnnotations
+    {
+      pdebug("Struct -> tok_struct tok_identifier { FieldList }");
+      validate_simple_identifier( $2);
+      $5->set_xsd_all($3);
+      $5->set_union($1 == struct_is_union);
+      $$ = $5;
+      $$->set_name($2);
+      if ($7 != NULL) {
+        $$->annotations_ = $7->annotations_;
+        delete $7;
+      }
+    }
+
+XsdAll:
+  tok_xsd_all
+    {
+      $$ = true;
+    }
+|
+    {
+      $$ = false;
+    }
+
+XsdOptional:
+  tok_xsd_optional
+    {
+      $$ = true;
+    }
+|
+    {
+      $$ = false;
+    }
+
+XsdNillable:
+  tok_xsd_nillable
+    {
+      $$ = true;
+    }
+|
+    {
+      $$ = false;
+    }
+
+XsdAttributes:
+  tok_xsd_attrs '{' FieldList '}'
+    {
+      $$ = $3;
+    }
+|
+    {
+      $$ = NULL;
+    }
+
+Xception:
+  tok_xception tok_identifier '{' FieldList '}' TypeAnnotations
+    {
+      pdebug("Xception -> tok_xception tok_identifier { FieldList }");
+      validate_simple_identifier( $2);
+      $4->set_name($2);
+      $4->set_xception(true);
+      $$ = $4;
+      if ($6 != NULL) {
+        $$->annotations_ = $6->annotations_;
+        delete $6;
+      }
+    }
+
+Service:
+  tok_service tok_identifier Extends '{' FlagArgs FunctionList UnflagArgs '}' TypeAnnotations
+    {
+      pdebug("Service -> tok_service tok_identifier { FunctionList }");
+      validate_simple_identifier( $2);
+      $$ = $6;
+      $$->set_name($2);
+      $$->set_extends($3);
+      if ($9 != NULL) {
+        $$->annotations_ = $9->annotations_;
+        delete $9;
+      }
+    }
+
+FlagArgs:
+    {
+       g_arglist = 1;
+    }
+
+UnflagArgs:
+    {
+       g_arglist = 0;
+    }
+
+Extends:
+  tok_extends tok_identifier
+    {
+      pdebug("Extends -> tok_extends tok_identifier");
+      $$ = NULL;
+      if (g_parse_mode == PROGRAM) {
+        $$ = g_scope->get_service($2);
+        if ($$ == NULL) {
+          yyerror("Service \"%s\" has not been defined.", $2);
+          exit(1);
+        }
+      }
+    }
+|
+    {
+      $$ = NULL;
+    }
+
+FunctionList:
+  FunctionList Function
+    {
+      pdebug("FunctionList -> FunctionList Function");
+      $$ = $1;
+      $1->add_function($2);
+    }
+|
+    {
+      pdebug("FunctionList -> ");
+      $$ = new t_service(g_program);
+    }
+
+Function:
+  CaptureDocText Oneway FunctionType tok_identifier '(' FieldList ')' Throws TypeAnnotations CommaOrSemicolonOptional
+    {
+      validate_simple_identifier( $4);
+      $6->set_name(std::string($4) + "_args");
+      $$ = new t_function($3, $4, $6, $8, $2);
+      if ($1 != NULL) {
+        $$->set_doc($1);
+      }
+      if ($9 != NULL) {
+        $$->annotations_ = $9->annotations_;
+        delete $9;
+      }
+    }
+
+Oneway:
+  tok_oneway
+    {
+      $$ = true;
+    }
+|
+    {
+      $$ = false;
+    }
+
+Throws:
+  tok_throws '(' FieldList ')'
+    {
+      pdebug("Throws -> tok_throws ( FieldList )");
+      $$ = $3;
+      if (g_parse_mode == PROGRAM && !validate_throws($$)) {
+        yyerror("Throws clause may not contain non-exception types");
+        exit(1);
+      }
+    }
+|
+    {
+      $$ = new t_struct(g_program);
+    }
+
+FieldList:
+  FieldList Field
+    {
+      pdebug("FieldList -> FieldList , Field");
+      $$ = $1;
+      if (!($$->append($2))) {
+        yyerror("\"%d: %s\" - field identifier/name has already been used", $2->get_key(), $2->get_name().c_str());
+        exit(1);
+      }
+    }
+|
+    {
+      pdebug("FieldList -> ");
+      y_field_val = -1;
+      $$ = new t_struct(g_program);
+    }
+
+Field:
+  CaptureDocText FieldIdentifier FieldRequiredness FieldType FieldReference tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes TypeAnnotations CommaOrSemicolonOptional
+    {
+      pdebug("tok_int_constant : Field -> FieldType tok_identifier");
+      if ($2.auto_assigned) {
+        pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $6);
+        if (g_strict >= 192) {
+          yyerror("Implicit field keys are deprecated and not allowed with -strict");
+          exit(1);
+        }
+      }
+      validate_simple_identifier($6);
+      $$ = new t_field($4, $6, $2.value);
+      $$->set_reference($5);
+      $$->set_req($3);
+      if ($7 != NULL) {
+        g_scope->resolve_const_value($7, $4);
+        validate_field_value($$, $7);
+        $$->set_value($7);
+      }
+      $$->set_xsd_optional($8);
+      $$->set_xsd_nillable($9);
+      if ($1 != NULL) {
+        $$->set_doc($1);
+      }
+      if ($10 != NULL) {
+        $$->set_xsd_attrs($10);
+      }
+      if ($11 != NULL) {
+        $$->annotations_ = $11->annotations_;
+        delete $11;
+      }
+    }
+
+FieldIdentifier:
+  tok_int_constant ':'
+    {
+      if ($1 <= 0) {
+        if (g_allow_neg_field_keys) {
+          /*
+           * g_allow_neg_field_keys exists to allow users to add explicitly
+           * specified key values to old .thrift files without breaking
+           * protocol compatibility.
+           */
+          if ($1 != y_field_val) {
+            /*
+             * warn if the user-specified negative value isn't what
+             * thrift would have auto-assigned.
+             */
+            pwarning(1, "Nonpositive field key (%" PRIi64") differs from what would be "
+                     "auto-assigned by thrift (%d).\n", $1, y_field_val);
+          }
+          /*
+           * Leave $1 as-is, and update y_field_val to be one less than $1.
+           * The FieldList parsing will catch any duplicate key values.
+           */
+          y_field_val = static_cast<int32_t>($1 - 1);
+          $$.value = static_cast<int32_t>($1);
+          $$.auto_assigned = false;
+        } else {
+          pwarning(1, "Nonpositive value (%d) not allowed as a field key.\n",
+                   $1);
+          $$.value = y_field_val--;
+          $$.auto_assigned = true;
+        }
+      } else {
+        $$.value = static_cast<int32_t>($1);
+        $$.auto_assigned = false;
+      }
+      if( (SHRT_MIN > $$.value) || ($$.value > SHRT_MAX)) {
+        pwarning(1, "Field key (%d) exceeds allowed range (%d..%d).\n",
+                 $$.value, SHRT_MIN, SHRT_MAX);
+      }
+    }
+|
+    {
+      $$.value = y_field_val--;
+      $$.auto_assigned = true;
+      if( (SHRT_MIN > $$.value) || ($$.value > SHRT_MAX)) {
+        pwarning(1, "Field key (%d) exceeds allowed range (%d..%d).\n",
+                 $$.value, SHRT_MIN, SHRT_MAX);
+      }
+    }
+
+FieldReference:
+  tok_reference
+    {
+      $$ = true;
+    }
+|
+   {
+     $$ = false;
+   }
+
+FieldRequiredness:
+  tok_required
+    {
+      $$ = t_field::T_REQUIRED;
+    }
+| tok_optional
+    {
+      if (g_arglist) {
+        if (g_parse_mode == PROGRAM) {
+          pwarning(1, "optional keyword is ignored in argument lists.\n");
+        }
+        $$ = t_field::T_OPT_IN_REQ_OUT;
+      } else {
+        $$ = t_field::T_OPTIONAL;
+      }
+    }
+|
+    {
+      $$ = t_field::T_OPT_IN_REQ_OUT;
+    }
+
+FieldValue:
+  '=' ConstValue
+    {
+      if (g_parse_mode == PROGRAM) {
+        $$ = $2;
+      } else {
+        $$ = NULL;
+      }
+    }
+|
+    {
+      $$ = NULL;
+    }
+
+FunctionType:
+  FieldType
+    {
+      pdebug("FunctionType -> FieldType");
+      $$ = $1;
+    }
+| tok_void
+    {
+      pdebug("FunctionType -> tok_void");
+      $$ = g_type_void;
+    }
+
+FieldType:
+  tok_identifier
+    {
+      pdebug("FieldType -> tok_identifier");
+      if (g_parse_mode == INCLUDES) {
+        // Ignore identifiers in include mode
+        $$ = NULL;
+      } else {
+        // Lookup the identifier in the current scope
+        $$ = g_scope->get_type($1);
+        if ($$ == NULL) {
+          /*
+           * Either this type isn't yet declared, or it's never
+             declared.  Either way allow it and we'll figure it out
+             during generation.
+           */
+          $$ = new t_typedef(g_program, $1, true);
+        }
+      }
+    }
+| BaseType
+    {
+      pdebug("FieldType -> BaseType");
+      $$ = $1;
+    }
+| ContainerType
+    {
+      pdebug("FieldType -> ContainerType");
+      $$ = $1;
+    }
+
+BaseType: SimpleBaseType TypeAnnotations
+    {
+      pdebug("BaseType -> SimpleBaseType TypeAnnotations");
+      if ($2 != NULL) {
+        $$ = new t_base_type(*static_cast<t_base_type*>($1));
+        $$->annotations_ = $2->annotations_;
+        delete $2;
+      } else {
+        $$ = $1;
+      }
+    }
+
+SimpleBaseType:
+  tok_string
+    {
+      pdebug("BaseType -> tok_string");
+      $$ = g_type_string;
+    }
+| tok_binary
+    {
+      pdebug("BaseType -> tok_binary");
+      $$ = g_type_binary;
+    }
+| tok_slist
+    {
+      pdebug("BaseType -> tok_slist");
+      $$ = g_type_slist;
+    }
+| tok_bool
+    {
+      pdebug("BaseType -> tok_bool");
+      $$ = g_type_bool;
+    }
+| tok_i8
+    {
+      pdebug("BaseType -> tok_i8");
+      $$ = g_type_i8;
+    }
+| tok_i16
+    {
+      pdebug("BaseType -> tok_i16");
+      $$ = g_type_i16;
+    }
+| tok_i32
+    {
+      pdebug("BaseType -> tok_i32");
+      $$ = g_type_i32;
+    }
+| tok_i64
+    {
+      pdebug("BaseType -> tok_i64");
+      $$ = g_type_i64;
+    }
+| tok_double
+    {
+      pdebug("BaseType -> tok_double");
+      $$ = g_type_double;
+    }
+
+ContainerType: SimpleContainerType TypeAnnotations
+    {
+      pdebug("ContainerType -> SimpleContainerType TypeAnnotations");
+      $$ = $1;
+      if ($2 != NULL) {
+        $$->annotations_ = $2->annotations_;
+        delete $2;
+      }
+    }
+
+SimpleContainerType:
+  MapType
+    {
+      pdebug("SimpleContainerType -> MapType");
+      $$ = $1;
+    }
+| SetType
+    {
+      pdebug("SimpleContainerType -> SetType");
+      $$ = $1;
+    }
+| ListType
+    {
+      pdebug("SimpleContainerType -> ListType");
+      $$ = $1;
+    }
+
+MapType:
+  tok_map CppType '<' FieldType ',' FieldType '>'
+    {
+      pdebug("MapType -> tok_map <FieldType, FieldType>");
+      $$ = new t_map($4, $6);
+      if ($2 != NULL) {
+        ((t_container*)$$)->set_cpp_name(std::string($2));
+      }
+    }
+
+SetType:
+  tok_set CppType '<' FieldType '>'
+    {
+      pdebug("SetType -> tok_set<FieldType>");
+      $$ = new t_set($4);
+      if ($2 != NULL) {
+        ((t_container*)$$)->set_cpp_name(std::string($2));
+      }
+    }
+
+ListType:
+  tok_list '<' FieldType '>' CppType
+    {
+      pdebug("ListType -> tok_list<FieldType>");
+      check_for_list_of_bytes($3);
+      $$ = new t_list($3);
+      if ($5 != NULL) {
+        ((t_container*)$$)->set_cpp_name(std::string($5));
+      }
+    }
+
+CppType:
+  tok_cpp_type tok_literal
+    {
+      $$ = $2;
+    }
+|
+    {
+      $$ = NULL;
+    }
+
+TypeAnnotations:
+  '(' TypeAnnotationList ')'
+    {
+      pdebug("TypeAnnotations -> ( TypeAnnotationList )");
+      $$ = $2;
+    }
+|
+    {
+      $$ = NULL;
+    }
+
+TypeAnnotationList:
+  TypeAnnotationList TypeAnnotation
+    {
+      pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation");
+      $$ = $1;
+      $$->annotations_[$2->key] = $2->val;
+      delete $2;
+    }
+|
+    {
+      /* Just use a dummy structure to hold the annotations. */
+      $$ = new t_struct(g_program);
+    }
+
+TypeAnnotation:
+  tok_identifier TypeAnnotationValue CommaOrSemicolonOptional
+    {
+      pdebug("TypeAnnotation -> TypeAnnotationValue");
+      $$ = new t_annotation;
+      $$->key = $1;
+      $$->val = $2;
+    }
+
+TypeAnnotationValue:
+  '=' tok_literal
+    {
+      pdebug("TypeAnnotationValue -> = tok_literal");
+      $$ = $2;
+    }
+|
+    {
+      pdebug("TypeAnnotationValue ->");
+      $$ = strdup("1");
+    }
+
+%%
diff --git a/compiler/cpp/src/thrift/version.h.in b/compiler/cpp/src/thrift/version.h.in
new file mode 100644
index 0000000..aef076f
--- /dev/null
+++ b/compiler/cpp/src/thrift/version.h.in
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_VERSION_H_
+#define _THRIFT_VERSION_H_ 1
+
+#if defined(_MSC_VER) && (_MSC_VER > 1200)
+#pragma once
+#endif // _MSC_VER
+
+#define THRIFT_VERSION "@PACKAGE_VERSION@"
+
+#endif // _THRIFT_VERSION_H_
diff --git a/compiler/cpp/src/thrift/windows/config.h b/compiler/cpp/src/thrift/windows/config.h
new file mode 100644
index 0000000..d2269cf
--- /dev/null
+++ b/compiler/cpp/src/thrift/windows/config.h
@@ -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.
+ */
+
+#ifndef _THRIFT_WINDOWS_CONFIG_H_
+#define _THRIFT_WINDOWS_CONFIG_H_ 1
+
+#if defined(_MSC_VER) && (_MSC_VER > 1200)
+#pragma once
+#endif // _MSC_VER
+
+#ifndef _WIN32
+#error "This is a Windows header only"
+#endif
+
+#include <io.h>
+#include <stdlib.h>
+#include <direct.h>
+
+#define strtoll(begin_ptr, end_ptr, length) _strtoi64(begin_ptr, end_ptr, length)
+
+#ifndef PRIu64
+#define PRIu64 "I64u"
+#endif
+
+#ifndef PRIi64
+#define PRIi64 "I64i"
+#endif
+// squelch deprecation warnings
+#pragma warning(disable : 4996)
+// squelch bool conversion performance warning
+#pragma warning(disable : 4800)
+
+// MSVC10 (2010) or later has stdint.h
+#if _MSC_VER >= 1600
+#define HAVE_STDINT_H 1
+#endif
+
+// Must be using VS2010 or later, or boost, so that C99 types are defined in the global namespace
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#else
+#include <boost/cstdint.hpp>
+
+typedef boost::int64_t int64_t;
+typedef boost::uint64_t uint64_t;
+typedef boost::int32_t int32_t;
+typedef boost::uint32_t uint32_t;
+typedef boost::int16_t int16_t;
+typedef boost::uint16_t uint16_t;
+typedef boost::int8_t int8_t;
+typedef boost::uint8_t uint8_t;
+#endif
+
+#endif // _THRIFT_WINDOWS_CONFIG_H_
diff --git a/compiler/cpp/src/thriftl.ll b/compiler/cpp/src/thriftl.ll
deleted file mode 100644
index 8538652..0000000
--- a/compiler/cpp/src/thriftl.ll
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * Thrift scanner.
- *
- * Tokenizes a thrift definition file.
- */
-
-%{
-
-/* This is redundant with some of the flags in Makefile.am, but it works
- * when people override CXXFLAGS without being careful. The pragmas are
- * the 'right' way to do it, but don't work on old-enough GCC (in particular
- * the GCC that ship on Mac OS X 10.6.5, *counter* to what the GNU docs say)
- *
- * We should revert the Makefile.am changes once Apple ships a reasonable
- * GCC.
- */
-#pragma GCC diagnostic ignored "-Wunused-function"
-#pragma GCC diagnostic ignored "-Wunused-label"
-
-#include <string>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "main.h"
-#include "globals.h"
-#include "parse/t_program.h"
-
-/**
- * Must be included AFTER parse/t_program.h, but I can't remember why anymore
- * because I wrote this a while ago.
- */
-#include "thrifty.h"
-
-void thrift_reserved_keyword(char* keyword) {
-  yyerror("Cannot use reserved language keyword: \"%s\"\n", keyword);
-  exit(1);
-}
-
-void integer_overflow(char* text) {
-  yyerror("This integer is too big: \"%s\"\n", text);
-  exit(1);
-}
-
-void unexpected_token(char* text) {
-  yyerror("Unexpected token in input: \"%s\"\n", text);
-  exit(1);
-}
-
-%}
-
-/**
- * Provides the yylineno global, useful for debugging output
- */
-%option lex-compat
-
-/**
- * Our inputs are all single files, so no need for yywrap
- */
-%option noyywrap
-
-/**
- * We don't use it, and it fires up warnings at -Wall
- */
-%option nounput
-
-/**
- * Helper definitions, comments, constants, and whatnot
- */
-
-intconstant   ([+-]?[0-9]+)
-hexconstant   ("0x"[0-9A-Fa-f]+)
-dubconstant   ([+-]?[0-9]*(\.[0-9]+)?([eE][+-]?[0-9]+)?)
-identifier    ([a-zA-Z_](\.[a-zA-Z_0-9]|[a-zA-Z_0-9])*)
-whitespace    ([ \t\r\n]*)
-sillycomm     ("/*""*"*"*/")
-multicomm     ("/*"[^*]"/"*([^*/]|[^*]"/"|"*"[^/])*"*"*"*/")
-doctext       ("/**"([^*/]|[^*]"/"|"*"[^/])*"*"*"*/")
-comment       ("//"[^\n]*)
-unixcomment   ("#"[^\n]*)
-symbol        ([:;\,\{\}\(\)\=<>\[\]])
-st_identifier ([a-zA-Z-](\.[a-zA-Z_0-9-]|[a-zA-Z_0-9-])*)
-literal_begin (['\"])
-
-%%
-
-{whitespace}         { /* do nothing */                 }
-{sillycomm}          { /* do nothing */                 }
-{multicomm}          { /* do nothing */                 }
-{comment}            { /* do nothing */                 }
-{unixcomment}        { /* do nothing */                 }
-
-{symbol}             { return yytext[0];                }
-"*"                  { return yytext[0];                }
-
-"false"              { yylval.iconst=0; return tok_int_constant; }
-"true"               { yylval.iconst=1; return tok_int_constant; }
-
-"namespace"          { return tok_namespace;            }
-"cpp_namespace"      { return tok_cpp_namespace;        }
-"cpp_include"        { return tok_cpp_include;          }
-"cpp_type"           { return tok_cpp_type;             }
-"java_package"       { return tok_java_package;         }
-"cocoa_prefix"       { return tok_cocoa_prefix;         }
-"csharp_namespace"   { return tok_csharp_namespace;     }
-"delphi_namespace"   { return tok_delphi_namespace;     }
-"php_namespace"      { return tok_php_namespace;        }
-"py_module"          { return tok_py_module;            }
-"perl_package"       { return tok_perl_package;         }
-"ruby_namespace"     { return tok_ruby_namespace;       }
-"smalltalk_category" { return tok_smalltalk_category;   }
-"smalltalk_prefix"   { return tok_smalltalk_prefix;     }
-"xsd_all"            { return tok_xsd_all;              }
-"xsd_optional"       { return tok_xsd_optional;         }
-"xsd_nillable"       { return tok_xsd_nillable;         }
-"xsd_namespace"      { return tok_xsd_namespace;        }
-"xsd_attrs"          { return tok_xsd_attrs;            }
-"include"            { return tok_include;              }
-"void"               { return tok_void;                 }
-"bool"               { return tok_bool;                 }
-"byte"               { return tok_byte;                 }
-"i16"                { return tok_i16;                  }
-"i32"                { return tok_i32;                  }
-"i64"                { return tok_i64;                  }
-"double"             { return tok_double;               }
-"string"             { return tok_string;               }
-"binary"             { return tok_binary;               }
-"slist" {
-  pwarning(0, "\"slist\" is deprecated and will be removed in a future compiler version.  This type should be replaced with \"string\".\n");
-  return tok_slist;
-}
-"senum" {
-  pwarning(0, "\"senum\" is deprecated and will be removed in a future compiler version.  This type should be replaced with \"string\".\n");
-  return tok_senum;
-}
-"map"                { return tok_map;                  }
-"list"               { return tok_list;                 }
-"set"                { return tok_set;                  }
-"oneway"             { return tok_oneway;               }
-"typedef"            { return tok_typedef;              }
-"struct"             { return tok_struct;               }
-"union"              { return tok_union;                }
-"exception"          { return tok_xception;             }
-"extends"            { return tok_extends;              }
-"throws"             { return tok_throws;               }
-"service"            { return tok_service;              }
-"enum"               { return tok_enum;                 }
-"const"              { return tok_const;                }
-"required"           { return tok_required;             }
-"optional"           { return tok_optional;             }
-"async" {
-  pwarning(0, "\"async\" is deprecated.  It is called \"oneway\" now.\n");
-  return tok_oneway;
-}
-
-
-"BEGIN"              { thrift_reserved_keyword(yytext); }
-"END"                { thrift_reserved_keyword(yytext); }
-"__CLASS__"          { thrift_reserved_keyword(yytext); }
-"__DIR__"            { thrift_reserved_keyword(yytext); }
-"__FILE__"           { thrift_reserved_keyword(yytext); }
-"__FUNCTION__"       { thrift_reserved_keyword(yytext); }
-"__LINE__"           { thrift_reserved_keyword(yytext); }
-"__METHOD__"         { thrift_reserved_keyword(yytext); }
-"__NAMESPACE__"      { thrift_reserved_keyword(yytext); }
-"abstract"           { thrift_reserved_keyword(yytext); }
-"alias"              { thrift_reserved_keyword(yytext); }
-"and"                { thrift_reserved_keyword(yytext); }
-"args"               { thrift_reserved_keyword(yytext); }
-"as"                 { thrift_reserved_keyword(yytext); }
-"assert"             { thrift_reserved_keyword(yytext); }
-"begin"              { thrift_reserved_keyword(yytext); }
-"break"              { thrift_reserved_keyword(yytext); }
-"case"               { thrift_reserved_keyword(yytext); }
-"catch"              { thrift_reserved_keyword(yytext); }
-"class"              { thrift_reserved_keyword(yytext); }
-"clone"              { thrift_reserved_keyword(yytext); }
-"continue"           { thrift_reserved_keyword(yytext); }
-"declare"            { thrift_reserved_keyword(yytext); }
-"def"                { thrift_reserved_keyword(yytext); }
-"default"            { thrift_reserved_keyword(yytext); }
-"del"                { thrift_reserved_keyword(yytext); }
-"delete"             { thrift_reserved_keyword(yytext); }
-"do"                 { thrift_reserved_keyword(yytext); }
-"dynamic"            { thrift_reserved_keyword(yytext); }
-"elif"               { thrift_reserved_keyword(yytext); }
-"else"               { thrift_reserved_keyword(yytext); }
-"elseif"             { thrift_reserved_keyword(yytext); }
-"elsif"              { thrift_reserved_keyword(yytext); }
-"end"                { thrift_reserved_keyword(yytext); }
-"enddeclare"         { thrift_reserved_keyword(yytext); }
-"endfor"             { thrift_reserved_keyword(yytext); }
-"endforeach"         { thrift_reserved_keyword(yytext); }
-"endif"              { thrift_reserved_keyword(yytext); }
-"endswitch"          { thrift_reserved_keyword(yytext); }
-"endwhile"           { thrift_reserved_keyword(yytext); }
-"ensure"             { thrift_reserved_keyword(yytext); }
-"except"             { thrift_reserved_keyword(yytext); }
-"exec"               { thrift_reserved_keyword(yytext); }
-"finally"            { thrift_reserved_keyword(yytext); }
-"float"              { thrift_reserved_keyword(yytext); }
-"for"                { thrift_reserved_keyword(yytext); }
-"foreach"            { thrift_reserved_keyword(yytext); }
-"function"           { thrift_reserved_keyword(yytext); }
-"global"             { thrift_reserved_keyword(yytext); }
-"goto"               { thrift_reserved_keyword(yytext); }
-"if"                 { thrift_reserved_keyword(yytext); }
-"implements"         { thrift_reserved_keyword(yytext); }
-"import"             { thrift_reserved_keyword(yytext); }
-"in"                 { thrift_reserved_keyword(yytext); }
-"inline"             { thrift_reserved_keyword(yytext); }
-"instanceof"         { thrift_reserved_keyword(yytext); }
-"interface"          { thrift_reserved_keyword(yytext); }
-"is"                 { thrift_reserved_keyword(yytext); }
-"lambda"             { thrift_reserved_keyword(yytext); }
-"module"             { thrift_reserved_keyword(yytext); }
-"native"             { thrift_reserved_keyword(yytext); }
-"new"                { thrift_reserved_keyword(yytext); }
-"next"               { thrift_reserved_keyword(yytext); }
-"nil"                { thrift_reserved_keyword(yytext); }
-"not"                { thrift_reserved_keyword(yytext); }
-"or"                 { thrift_reserved_keyword(yytext); }
-"pass"               { thrift_reserved_keyword(yytext); }
-"public"             { thrift_reserved_keyword(yytext); }
-"print"              { thrift_reserved_keyword(yytext); }
-"private"            { thrift_reserved_keyword(yytext); }
-"protected"          { thrift_reserved_keyword(yytext); }
-"public"             { thrift_reserved_keyword(yytext); }
-"raise"              { thrift_reserved_keyword(yytext); }
-"redo"               { thrift_reserved_keyword(yytext); }
-"rescue"             { thrift_reserved_keyword(yytext); }
-"retry"              { thrift_reserved_keyword(yytext); }
-"register"           { thrift_reserved_keyword(yytext); }
-"return"             { thrift_reserved_keyword(yytext); }
-"self"               { thrift_reserved_keyword(yytext); }
-"sizeof"             { thrift_reserved_keyword(yytext); }
-"static"             { thrift_reserved_keyword(yytext); }
-"super"              { thrift_reserved_keyword(yytext); }
-"switch"             { thrift_reserved_keyword(yytext); }
-"synchronized"       { thrift_reserved_keyword(yytext); }
-"then"               { thrift_reserved_keyword(yytext); }
-"this"               { thrift_reserved_keyword(yytext); }
-"throw"              { thrift_reserved_keyword(yytext); }
-"transient"          { thrift_reserved_keyword(yytext); }
-"try"                { thrift_reserved_keyword(yytext); }
-"undef"              { thrift_reserved_keyword(yytext); }
-"union"              { thrift_reserved_keyword(yytext); }
-"unless"             { thrift_reserved_keyword(yytext); }
-"unsigned"           { thrift_reserved_keyword(yytext); }
-"until"              { thrift_reserved_keyword(yytext); }
-"use"                { thrift_reserved_keyword(yytext); }
-"var"                { thrift_reserved_keyword(yytext); }
-"virtual"            { thrift_reserved_keyword(yytext); }
-"volatile"           { thrift_reserved_keyword(yytext); }
-"when"               { thrift_reserved_keyword(yytext); }
-"while"              { thrift_reserved_keyword(yytext); }
-"with"               { thrift_reserved_keyword(yytext); }
-"xor"                { thrift_reserved_keyword(yytext); }
-"yield"              { thrift_reserved_keyword(yytext); }
-
-{intconstant} {
-  errno = 0;
-  yylval.iconst = strtoll(yytext, NULL, 10);
-  if (errno == ERANGE) {
-    integer_overflow(yytext);
-  }
-  return tok_int_constant;
-}
-
-{hexconstant} {
-  errno = 0;
-  yylval.iconst = strtoll(yytext+2, NULL, 16);
-  if (errno == ERANGE) {
-    integer_overflow(yytext);
-  }
-  return tok_int_constant;
-}
-
-{dubconstant} {
-  yylval.dconst = atof(yytext);
-  return tok_dub_constant;
-}
-
-{identifier} {
-  yylval.id = strdup(yytext);
-  return tok_identifier;
-}
-
-{st_identifier} {
-  yylval.id = strdup(yytext);
-  return tok_st_identifier;
-}
-
-{literal_begin} {
-  char mark = yytext[0];
-  std::string result;
-  for(;;)
-  {
-    int ch = yyinput();
-    switch (ch) {
-      case EOF:
-        yyerror("End of file while read string at %d\n", yylineno);
-        exit(1);
-      case '\n':
-        yyerror("End of line while read string at %d\n", yylineno - 1);
-        exit(1);
-      case '\\':
-        ch = yyinput();
-        switch (ch) {
-          case 'r':
-            result.push_back('\r');
-            continue;
-          case 'n':
-            result.push_back('\n');
-            continue;
-          case 't':
-            result.push_back('\t');
-            continue;
-          case '"':
-            result.push_back('"');
-            continue;
-          case '\'':
-            result.push_back('\'');
-            continue;
-          case '\\':
-            result.push_back('\\');
-            continue;
-          default:
-            yyerror("Bad escape character\n");
-            return -1;
-        }
-        break;
-      default:
-        if (ch == mark) {
-          yylval.id = strdup(result.c_str());
-          return tok_literal;
-        } else {
-          result.push_back(ch);
-        }
-    }
-  }
-}
-
-
-{doctext} {
- /* This does not show up in the parse tree. */
- /* Rather, the parser will grab it out of the global. */
-  if (g_parse_mode == PROGRAM) {
-    clear_doctext();
-    g_doctext = strdup(yytext + 3);
-    g_doctext[strlen(g_doctext) - 2] = '\0';
-    g_doctext = clean_up_doctext(g_doctext);
-    g_doctext_lineno = yylineno;
-  }
-}
-
-. {
-  unexpected_token(yytext);
-}
-
-
-. {
-  /* Catch-all to let us catch "*" in the parser. */
-  return (int) yytext[0];
-}
-
-%%
-
-/* vim: filetype=lex
-*/
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
deleted file mode 100644
index 5b91a0a..0000000
--- a/compiler/cpp/src/thrifty.yy
+++ /dev/null
@@ -1,1232 +0,0 @@
-%{
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * Thrift parser.
- *
- * This parser is used on a thrift definition file.
- *
- */
-
-#define __STDC_LIMIT_MACROS
-#define __STDC_FORMAT_MACROS
-#include <stdio.h>
-#ifndef _MSC_VER
-#include <inttypes.h>
-#else
-#include <stdint.h>
-#endif
-#include <limits.h>
-#include "main.h"
-#include "globals.h"
-#include "parse/t_program.h"
-#include "parse/t_scope.h"
-
-/**
- * This global variable is used for automatic numbering of field indices etc.
- * when parsing the members of a struct. Field values are automatically
- * assigned starting from -1 and working their way down.
- */
-int y_field_val = -1;
-int g_arglist = 0;
-const int struct_is_struct = 0;
-const int struct_is_union = 1;
-
-%}
-
-/**
- * This structure is used by the parser to hold the data types associated with
- * various parse nodes.
- */
-%union {
-  char*          id;
-  int64_t        iconst;
-  double         dconst;
-  bool           tbool;
-  t_doc*         tdoc;
-  t_type*        ttype;
-  t_base_type*   tbase;
-  t_typedef*     ttypedef;
-  t_enum*        tenum;
-  t_enum_value*  tenumv;
-  t_const*       tconst;
-  t_const_value* tconstv;
-  t_struct*      tstruct;
-  t_service*     tservice;
-  t_function*    tfunction;
-  t_field*       tfield;
-  char*          dtext;
-  t_field::e_req ereq;
-  t_annotation*  tannot;
-  t_field_id     tfieldid;
-}
-
-/**
- * Strings identifier
- */
-%token<id>     tok_identifier
-%token<id>     tok_literal
-%token<dtext>  tok_doctext
-%token<id>     tok_st_identifier
-
-/**
- * Constant values
- */
-%token<iconst> tok_int_constant
-%token<dconst> tok_dub_constant
-
-/**
- * Header keywords
- */
-%token tok_include
-%token tok_namespace
-%token tok_cpp_namespace
-%token tok_cpp_include
-%token tok_cpp_type
-%token tok_php_namespace
-%token tok_py_module
-%token tok_perl_package
-%token tok_java_package
-%token tok_xsd_all
-%token tok_xsd_optional
-%token tok_xsd_nillable
-%token tok_xsd_namespace
-%token tok_xsd_attrs
-%token tok_ruby_namespace
-%token tok_smalltalk_category
-%token tok_smalltalk_prefix
-%token tok_cocoa_prefix
-%token tok_csharp_namespace
-%token tok_delphi_namespace
-
-/**
- * Base datatype keywords
- */
-%token tok_void
-%token tok_bool
-%token tok_byte
-%token tok_string
-%token tok_binary
-%token tok_slist
-%token tok_senum
-%token tok_i16
-%token tok_i32
-%token tok_i64
-%token tok_double
-
-/**
- * Complex type keywords
- */
-%token tok_map
-%token tok_list
-%token tok_set
-
-/**
- * Function modifiers
- */
-%token tok_oneway
-
-/**
- * Thrift language keywords
- */
-%token tok_typedef
-%token tok_struct
-%token tok_xception
-%token tok_throws
-%token tok_extends
-%token tok_service
-%token tok_enum
-%token tok_const
-%token tok_required
-%token tok_optional
-%token tok_union
-
-/**
- * Grammar nodes
- */
-
-%type<ttype>     BaseType
-%type<ttype>     SimpleBaseType
-%type<ttype>     ContainerType
-%type<ttype>     SimpleContainerType
-%type<ttype>     MapType
-%type<ttype>     SetType
-%type<ttype>     ListType
-
-%type<tdoc>      Definition
-%type<ttype>     TypeDefinition
-
-%type<ttypedef>  Typedef
-
-%type<ttype>     TypeAnnotations
-%type<ttype>     TypeAnnotationList
-%type<tannot>    TypeAnnotation
-
-%type<tfield>    Field
-%type<tfieldid>  FieldIdentifier
-%type<ereq>      FieldRequiredness
-%type<ttype>     FieldType
-%type<tconstv>   FieldValue
-%type<tstruct>   FieldList
-
-%type<tenum>     Enum
-%type<tenum>     EnumDefList
-%type<tenumv>    EnumDef
-
-%type<ttypedef>  Senum
-%type<tbase>     SenumDefList
-%type<id>        SenumDef
-
-%type<tconst>    Const
-%type<tconstv>   ConstValue
-%type<tconstv>   ConstList
-%type<tconstv>   ConstListContents
-%type<tconstv>   ConstMap
-%type<tconstv>   ConstMapContents
-
-%type<iconst>    StructHead
-%type<tstruct>   Struct
-%type<tstruct>   Xception
-%type<tservice>  Service
-
-%type<tfunction> Function
-%type<ttype>     FunctionType
-%type<tservice>  FunctionList
-
-%type<tstruct>   Throws
-%type<tservice>  Extends
-%type<tbool>     Oneway
-%type<tbool>     XsdAll
-%type<tbool>     XsdOptional
-%type<tbool>     XsdNillable
-%type<tstruct>   XsdAttributes
-%type<id>        CppType
-
-%type<dtext>     CaptureDocText
-
-%%
-
-/**
- * Thrift Grammar Implementation.
- *
- * For the most part this source file works its way top down from what you
- * might expect to find in a typical .thrift file, i.e. type definitions and
- * namespaces up top followed by service definitions using those types.
- */
-
-Program:
-  HeaderList DefinitionList
-    {
-      pdebug("Program -> Headers DefinitionList");
-      /*
-      TODO(dreiss): Decide whether full-program doctext is worth the trouble.
-      if ($1 != NULL) {
-        g_program->set_doc($1);
-      }
-      */
-      clear_doctext();
-    }
-
-CaptureDocText:
-    {
-      if (g_parse_mode == PROGRAM) {
-        $$ = g_doctext;
-        g_doctext = NULL;
-      } else {
-        $$ = NULL;
-      }
-    }
-
-/* TODO(dreiss): Try to DestroyDocText in all sorts or random places. */
-DestroyDocText:
-    {
-      if (g_parse_mode == PROGRAM) {
-        clear_doctext();
-      }
-    }
-
-/* We have to DestroyDocText here, otherwise it catches the doctext
-   on the first real element. */
-HeaderList:
-  HeaderList DestroyDocText Header
-    {
-      pdebug("HeaderList -> HeaderList Header");
-    }
-|
-    {
-      pdebug("HeaderList -> ");
-    }
-
-Header:
-  Include
-    {
-      pdebug("Header -> Include");
-    }
-| tok_namespace tok_identifier tok_identifier
-    {
-      pdebug("Header -> tok_namespace tok_identifier tok_identifier");
-      if (g_parse_mode == PROGRAM) {
-        g_program->set_namespace($2, $3);
-      }
-    }
-| tok_namespace '*' tok_identifier
-    {
-      pdebug("Header -> tok_namespace * tok_identifier");
-      if (g_parse_mode == PROGRAM) {
-        g_program->set_namespace("*", $3);
-      }
-    }
-/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
-| tok_cpp_namespace tok_identifier
-    {
-      pwarning(1, "'cpp_namespace' is deprecated. Use 'namespace cpp' instead");
-      pdebug("Header -> tok_cpp_namespace tok_identifier");
-      if (g_parse_mode == PROGRAM) {
-        g_program->set_namespace("cpp", $2);
-      }
-    }
-| tok_cpp_include tok_literal
-    {
-      pdebug("Header -> tok_cpp_include tok_literal");
-      if (g_parse_mode == PROGRAM) {
-        g_program->add_cpp_include($2);
-      }
-    }
-| tok_php_namespace tok_identifier
-    {
-      pwarning(1, "'php_namespace' is deprecated. Use 'namespace php' instead");
-      pdebug("Header -> tok_php_namespace tok_identifier");
-      if (g_parse_mode == PROGRAM) {
-        g_program->set_namespace("php", $2);
-      }
-    }
-/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
-| tok_py_module tok_identifier
-    {
-      pwarning(1, "'py_module' is deprecated. Use 'namespace py' instead");
-      pdebug("Header -> tok_py_module tok_identifier");
-      if (g_parse_mode == PROGRAM) {
-        g_program->set_namespace("py", $2);
-      }
-    }
-/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
-| tok_perl_package tok_identifier
-    {
-      pwarning(1, "'perl_package' is deprecated. Use 'namespace perl' instead");
-      pdebug("Header -> tok_perl_namespace tok_identifier");
-      if (g_parse_mode == PROGRAM) {
-        g_program->set_namespace("perl", $2);
-      }
-    }
-/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
-| tok_ruby_namespace tok_identifier
-    {
-      pwarning(1, "'ruby_namespace' is deprecated. Use 'namespace rb' instead");
-      pdebug("Header -> tok_ruby_namespace tok_identifier");
-      if (g_parse_mode == PROGRAM) {
-        g_program->set_namespace("rb", $2);
-      }
-    }
-/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
-| tok_smalltalk_category tok_st_identifier
-    {
-      pwarning(1, "'smalltalk_category' is deprecated. Use 'namespace smalltalk.category' instead");
-      pdebug("Header -> tok_smalltalk_category tok_st_identifier");
-      if (g_parse_mode == PROGRAM) {
-        g_program->set_namespace("smalltalk.category", $2);
-      }
-    }
-/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
-| tok_smalltalk_prefix tok_identifier
-    {
-      pwarning(1, "'smalltalk_prefix' is deprecated. Use 'namespace smalltalk.prefix' instead");
-      pdebug("Header -> tok_smalltalk_prefix tok_identifier");
-      if (g_parse_mode == PROGRAM) {
-        g_program->set_namespace("smalltalk.prefix", $2);
-      }
-    }
-/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
-| tok_java_package tok_identifier
-    {
-      pwarning(1, "'java_package' is deprecated. Use 'namespace java' instead");
-      pdebug("Header -> tok_java_package tok_identifier");
-      if (g_parse_mode == PROGRAM) {
-        g_program->set_namespace("java", $2);
-      }
-    }
-/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
-| tok_cocoa_prefix tok_identifier
-    {
-      pwarning(1, "'cocoa_prefix' is deprecated. Use 'namespace cocoa' instead");
-      pdebug("Header -> tok_cocoa_prefix tok_identifier");
-      if (g_parse_mode == PROGRAM) {
-        g_program->set_namespace("cocoa", $2);
-      }
-    }
-/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
-| tok_xsd_namespace tok_literal
-    {
-      pwarning(1, "'xsd_namespace' is deprecated. Use 'namespace xsd' instead");
-      pdebug("Header -> tok_xsd_namespace tok_literal");
-      if (g_parse_mode == PROGRAM) {
-        g_program->set_namespace("cocoa", $2);
-      }
-    }
-/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
-| tok_csharp_namespace tok_identifier
-   {
-     pwarning(1, "'csharp_namespace' is deprecated. Use 'namespace csharp' instead");
-     pdebug("Header -> tok_csharp_namespace tok_identifier");
-     if (g_parse_mode == PROGRAM) {
-       g_program->set_namespace("csharp", $2);
-     }
-   }
-/* TODO(dreiss): Get rid of this once everyone is using the new hotness. */
-| tok_delphi_namespace tok_identifier
-   {
-     pwarning(1, "'delphi_namespace' is deprecated. Use 'namespace delphi' instead");
-     pdebug("Header -> tok_delphi_namespace tok_identifier");
-     if (g_parse_mode == PROGRAM) {
-       g_program->set_namespace("delphi", $2);
-     }
-   }
-
-Include:
-  tok_include tok_literal
-    {
-      pdebug("Include -> tok_include tok_literal");
-      if (g_parse_mode == INCLUDES) {
-        std::string path = include_file(std::string($2));
-        if (!path.empty()) {
-          g_program->add_include(path, std::string($2));
-        }
-      }
-    }
-
-DefinitionList:
-  DefinitionList CaptureDocText Definition
-    {
-      pdebug("DefinitionList -> DefinitionList Definition");
-      if ($2 != NULL && $3 != NULL) {
-        $3->set_doc($2);
-      }
-    }
-|
-    {
-      pdebug("DefinitionList -> ");
-    }
-
-Definition:
-  Const
-    {
-      pdebug("Definition -> Const");
-      if (g_parse_mode == PROGRAM) {
-        g_program->add_const($1);
-      }
-      $$ = $1;
-    }
-| TypeDefinition
-    {
-      pdebug("Definition -> TypeDefinition");
-      if (g_parse_mode == PROGRAM) {
-        g_scope->add_type($1->get_name(), $1);
-        if (g_parent_scope != NULL) {
-          g_parent_scope->add_type(g_parent_prefix + $1->get_name(), $1);
-        }
-        if (! g_program->is_unique_typename($1)) {
-          yyerror("Type \"%s\" is already defined.", $1->get_name().c_str());
-          exit(1);
-        }
-      }
-      $$ = $1;
-    }
-| Service
-    {
-      pdebug("Definition -> Service");
-      if (g_parse_mode == PROGRAM) {
-        g_scope->add_service($1->get_name(), $1);
-        if (g_parent_scope != NULL) {
-          g_parent_scope->add_service(g_parent_prefix + $1->get_name(), $1);
-        }
-        g_program->add_service($1);
-        if (! g_program->is_unique_typename($1)) {
-          yyerror("Type \"%s\" is already defined.", $1->get_name().c_str());
-          exit(1);
-        }
-      }
-      $$ = $1;
-    }
-
-TypeDefinition:
-  Typedef
-    {
-      pdebug("TypeDefinition -> Typedef");
-      if (g_parse_mode == PROGRAM) {
-        g_program->add_typedef($1);
-      }
-    }
-| Enum
-    {
-      pdebug("TypeDefinition -> Enum");
-      if (g_parse_mode == PROGRAM) {
-        g_program->add_enum($1);
-      }
-    }
-| Senum
-    {
-      pdebug("TypeDefinition -> Senum");
-      if (g_parse_mode == PROGRAM) {
-        g_program->add_typedef($1);
-      }
-    }
-| Struct
-    {
-      pdebug("TypeDefinition -> Struct");
-      if (g_parse_mode == PROGRAM) {
-        g_program->add_struct($1);
-      }
-    }
-| Xception
-    {
-      pdebug("TypeDefinition -> Xception");
-      if (g_parse_mode == PROGRAM) {
-        g_program->add_xception($1);
-      }
-    }
-
-Typedef:
-  tok_typedef FieldType tok_identifier TypeAnnotations
-    {
-      pdebug("TypeDef -> tok_typedef FieldType tok_identifier");
-      t_typedef *td = new t_typedef(g_program, $2, $3);
-      $$ = td;
-      if ($4 != NULL) {
-        $$->annotations_ = $4->annotations_;
-        delete $4;
-      }
-    }
-
-CommaOrSemicolonOptional:
-  ','
-    {}
-| ';'
-    {}
-|
-    {}
-
-Enum:
-  tok_enum tok_identifier '{' EnumDefList '}' TypeAnnotations
-    {
-      pdebug("Enum -> tok_enum tok_identifier { EnumDefList }");
-      $$ = $4;
-      $$->set_name($2);
-      if ($6 != NULL) {
-        $$->annotations_ = $6->annotations_;
-        delete $6;
-      }
-      $$->resolve_values();
-      // make constants for all the enum values
-      if (g_parse_mode == PROGRAM) {
-        const std::vector<t_enum_value*>& enum_values = $$->get_constants();
-        std::vector<t_enum_value*>::const_iterator c_iter;
-        for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) {
-          std::string const_name = $$->get_name() + "." + (*c_iter)->get_name();
-          t_const_value* const_val = new t_const_value((*c_iter)->get_value());
-          const_val->set_enum($$);
-          g_scope->add_constant(const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val));
-          if (g_parent_scope != NULL) {
-            g_parent_scope->add_constant(g_parent_prefix + const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val));
-          }
-        }
-      }
-    }
-
-EnumDefList:
-  EnumDefList EnumDef
-    {
-      pdebug("EnumDefList -> EnumDefList EnumDef");
-      $$ = $1;
-      $$->append($2);
-    }
-|
-    {
-      pdebug("EnumDefList -> ");
-      $$ = new t_enum(g_program);
-    }
-
-EnumDef:
-  CaptureDocText tok_identifier '=' tok_int_constant TypeAnnotations CommaOrSemicolonOptional
-    {
-      pdebug("EnumDef -> tok_identifier = tok_int_constant");
-      if ($4 < 0) {
-        pwarning(1, "Negative value supplied for enum %s.\n", $2);
-      }
-      if ($4 > INT_MAX) {
-        pwarning(1, "64-bit value supplied for enum %s.\n", $2);
-      }
-      $$ = new t_enum_value($2, $4);
-      if ($1 != NULL) {
-        $$->set_doc($1);
-      }
-      if ($5 != NULL) {
-        $$->annotations_ = $5->annotations_;
-        delete $5;
-      }
-    }
-|
-  CaptureDocText tok_identifier TypeAnnotations CommaOrSemicolonOptional
-    {
-      pdebug("EnumDef -> tok_identifier");
-      $$ = new t_enum_value($2);
-      if ($1 != NULL) {
-        $$->set_doc($1);
-      }
-      if ($3 != NULL) {
-        $$->annotations_ = $3->annotations_;
-        delete $3;
-      }
-    }
-
-Senum:
-  tok_senum tok_identifier '{' SenumDefList '}' TypeAnnotations
-    {
-      pdebug("Senum -> tok_senum tok_identifier { SenumDefList }");
-      $$ = new t_typedef(g_program, $4, $2);
-      if ($6 != NULL) {
-        $$->annotations_ = $6->annotations_;
-        delete $6;
-      }
-    }
-
-SenumDefList:
-  SenumDefList SenumDef
-    {
-      pdebug("SenumDefList -> SenumDefList SenumDef");
-      $$ = $1;
-      $$->add_string_enum_val($2);
-    }
-|
-    {
-      pdebug("SenumDefList -> ");
-      $$ = new t_base_type("string", t_base_type::TYPE_STRING);
-      $$->set_string_enum(true);
-    }
-
-SenumDef:
-  tok_literal CommaOrSemicolonOptional
-    {
-      pdebug("SenumDef -> tok_literal");
-      $$ = $1;
-    }
-
-Const:
-  tok_const FieldType tok_identifier '=' ConstValue CommaOrSemicolonOptional
-    {
-      pdebug("Const -> tok_const FieldType tok_identifier = ConstValue");
-      if (g_parse_mode == PROGRAM) {
-        g_scope->resolve_const_value($5, $2);
-        $$ = new t_const($2, $3, $5);
-        validate_const_type($$);
-
-        g_scope->add_constant($3, $$);
-        if (g_parent_scope != NULL) {
-          g_parent_scope->add_constant(g_parent_prefix + $3, $$);
-        }
-      } else {
-        $$ = NULL;
-      }
-    }
-
-ConstValue:
-  tok_int_constant
-    {
-      pdebug("ConstValue => tok_int_constant");
-      $$ = new t_const_value();
-      $$->set_integer($1);
-      if (!g_allow_64bit_consts && ($1 < INT32_MIN || $1 > INT32_MAX)) {
-        pwarning(1, "64-bit constant \"%"PRIi64"\" may not work in all languages.\n", $1);
-      }
-    }
-| tok_dub_constant
-    {
-      pdebug("ConstValue => tok_dub_constant");
-      $$ = new t_const_value();
-      $$->set_double($1);
-    }
-| tok_literal
-    {
-      pdebug("ConstValue => tok_literal");
-      $$ = new t_const_value($1);
-    }
-| tok_identifier
-    {
-      pdebug("ConstValue => tok_identifier");
-      $$ = new t_const_value();
-      $$->set_identifier($1);
-    }
-| ConstList
-    {
-      pdebug("ConstValue => ConstList");
-      $$ = $1;
-    }
-| ConstMap
-    {
-      pdebug("ConstValue => ConstMap");
-      $$ = $1;
-    }
-
-ConstList:
-  '[' ConstListContents ']'
-    {
-      pdebug("ConstList => [ ConstListContents ]");
-      $$ = $2;
-    }
-
-ConstListContents:
-  ConstListContents ConstValue CommaOrSemicolonOptional
-    {
-      pdebug("ConstListContents => ConstListContents ConstValue CommaOrSemicolonOptional");
-      $$ = $1;
-      $$->add_list($2);
-    }
-|
-    {
-      pdebug("ConstListContents =>");
-      $$ = new t_const_value();
-      $$->set_list();
-    }
-
-ConstMap:
-  '{' ConstMapContents '}'
-    {
-      pdebug("ConstMap => { ConstMapContents }");
-      $$ = $2;
-    }
-
-ConstMapContents:
-  ConstMapContents ConstValue ':' ConstValue CommaOrSemicolonOptional
-    {
-      pdebug("ConstMapContents => ConstMapContents ConstValue CommaOrSemicolonOptional");
-      $$ = $1;
-      $$->add_map($2, $4);
-    }
-|
-    {
-      pdebug("ConstMapContents =>");
-      $$ = new t_const_value();
-      $$->set_map();
-    }
-
-StructHead:
-  tok_struct
-    {
-      $$ = struct_is_struct;
-    }
-| tok_union
-    {
-      $$ = struct_is_union;
-    }
-
-Struct:
-  StructHead tok_identifier XsdAll '{' FieldList '}' TypeAnnotations
-    {
-      pdebug("Struct -> tok_struct tok_identifier { FieldList }");
-      $5->set_xsd_all($3);
-      $5->set_union($1 == struct_is_union);
-      $$ = $5;
-      $$->set_name($2);
-      if ($7 != NULL) {
-        $$->annotations_ = $7->annotations_;
-        delete $7;
-      }
-    }
-    
-XsdAll:
-  tok_xsd_all
-    {
-      $$ = true;
-    }
-|
-    {
-      $$ = false;
-    }
-
-XsdOptional:
-  tok_xsd_optional
-    {
-      $$ = true;
-    }
-|
-    {
-      $$ = false;
-    }
-
-XsdNillable:
-  tok_xsd_nillable
-    {
-      $$ = true;
-    }
-|
-    {
-      $$ = false;
-    }
-
-XsdAttributes:
-  tok_xsd_attrs '{' FieldList '}'
-    {
-      $$ = $3;
-    }
-|
-    {
-      $$ = NULL;
-    }
-
-Xception:
-  tok_xception tok_identifier '{' FieldList '}' TypeAnnotations
-    {
-      pdebug("Xception -> tok_xception tok_identifier { FieldList }");
-      $4->set_name($2);
-      $4->set_xception(true);
-      $$ = $4;
-      if ($6 != NULL) {
-        $$->annotations_ = $6->annotations_;
-        delete $6;
-      }
-    }
-
-Service:
-  tok_service tok_identifier Extends '{' FlagArgs FunctionList UnflagArgs '}' TypeAnnotations
-    {
-      pdebug("Service -> tok_service tok_identifier { FunctionList }");
-      $$ = $6;
-      $$->set_name($2);
-      $$->set_extends($3);
-      if ($9 != NULL) {
-        $$->annotations_ = $9->annotations_;
-        delete $9;
-      }
-    }
-
-FlagArgs:
-    {
-       g_arglist = 1;
-    }
-
-UnflagArgs:
-    {
-       g_arglist = 0;
-    }
-
-Extends:
-  tok_extends tok_identifier
-    {
-      pdebug("Extends -> tok_extends tok_identifier");
-      $$ = NULL;
-      if (g_parse_mode == PROGRAM) {
-        $$ = g_scope->get_service($2);
-        if ($$ == NULL) {
-          yyerror("Service \"%s\" has not been defined.", $2);
-          exit(1);
-        }
-      }
-    }
-|
-    {
-      $$ = NULL;
-    }
-
-FunctionList:
-  FunctionList Function
-    {
-      pdebug("FunctionList -> FunctionList Function");
-      $$ = $1;
-      $1->add_function($2);
-    }
-|
-    {
-      pdebug("FunctionList -> ");
-      $$ = new t_service(g_program);
-    }
-
-Function:
-  CaptureDocText Oneway FunctionType tok_identifier '(' FieldList ')' Throws TypeAnnotations CommaOrSemicolonOptional
-    {
-      $6->set_name(std::string($4) + "_args");
-      $$ = new t_function($3, $4, $6, $8, $2);
-      if ($1 != NULL) {
-        $$->set_doc($1);
-      }
-      if ($9 != NULL) {
-        $$->annotations_ = $9->annotations_;
-        delete $9;
-      }
-    }
-
-Oneway:
-  tok_oneway
-    {
-      $$ = true;
-    }
-|
-    {
-      $$ = false;
-    }
-
-Throws:
-  tok_throws '(' FieldList ')'
-    {
-      pdebug("Throws -> tok_throws ( FieldList )");
-      $$ = $3;
-      if (g_parse_mode == PROGRAM && !validate_throws($$)) {
-        yyerror("Throws clause may not contain non-exception types");
-        exit(1);
-      }
-    }
-|
-    {
-      $$ = new t_struct(g_program);
-    }
-
-FieldList:
-  FieldList Field
-    {
-      pdebug("FieldList -> FieldList , Field");
-      $$ = $1;
-      if (!($$->append($2))) {
-        yyerror("\"%d: %s\" - field identifier/name has already been used", $2->get_key(), $2->get_name().c_str());
-        exit(1);
-      }
-    }
-|
-    {
-      pdebug("FieldList -> ");
-      y_field_val = -1;
-      $$ = new t_struct(g_program);
-    }
-
-Field:
-  CaptureDocText FieldIdentifier FieldRequiredness FieldType tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes TypeAnnotations CommaOrSemicolonOptional
-    {
-      pdebug("tok_int_constant : Field -> FieldType tok_identifier");
-      if ($2.auto_assigned) {
-        pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $5);
-        if (g_strict >= 192) {
-          yyerror("Implicit field keys are deprecated and not allowed with -strict");
-          exit(1);
-        }
-      }
-      $$ = new t_field($4, $5, $2.value);
-      $$->set_req($3);
-      if ($6 != NULL) {
-        g_scope->resolve_const_value($6, $4);
-        validate_field_value($$, $6);
-        $$->set_value($6);
-      }
-      $$->set_xsd_optional($7);
-      $$->set_xsd_nillable($8);
-      if ($1 != NULL) {
-        $$->set_doc($1);
-      }
-      if ($9 != NULL) {
-        $$->set_xsd_attrs($9);
-      }
-      if ($10 != NULL) {
-        $$->annotations_ = $10->annotations_;
-        delete $10;
-      }
-    }
-
-FieldIdentifier:
-  tok_int_constant ':'
-    {
-      if ($1 <= 0) {
-        if (g_allow_neg_field_keys) {
-          /*
-           * g_allow_neg_field_keys exists to allow users to add explicitly
-           * specified key values to old .thrift files without breaking
-           * protocol compatibility.
-           */
-          if ($1 != y_field_val) {
-            /*
-             * warn if the user-specified negative value isn't what
-             * thrift would have auto-assigned.
-             */
-            pwarning(1, "Nonpositive field key (%"PRIi64") differs from what would be "
-                     "auto-assigned by thrift (%d).\n", $1, y_field_val);
-          }
-          /*
-           * Leave $1 as-is, and update y_field_val to be one less than $1.
-           * The FieldList parsing will catch any duplicate key values.
-           */
-          y_field_val = $1 - 1;
-          $$.value = $1;
-          $$.auto_assigned = false;
-        } else {
-          pwarning(1, "Nonpositive value (%"PRIi64") not allowed as a field key.\n",
-                   $1);
-          $$.value = y_field_val--;
-          $$.auto_assigned = true;
-        }
-      } else {
-        $$.value = $1;
-        $$.auto_assigned = false;
-      }
-    }
-|
-    {
-      $$.value = y_field_val--;
-      $$.auto_assigned = true;
-    }
-
-FieldRequiredness:
-  tok_required
-    {
-      $$ = t_field::T_REQUIRED;
-    }
-| tok_optional
-    {
-      if (g_arglist) {
-        if (g_parse_mode == PROGRAM) {
-          pwarning(1, "optional keyword is ignored in argument lists.\n");
-        }
-        $$ = t_field::T_OPT_IN_REQ_OUT;
-      } else {
-        $$ = t_field::T_OPTIONAL;
-      }
-    }
-|
-    {
-      $$ = t_field::T_OPT_IN_REQ_OUT;
-    }
-
-FieldValue:
-  '=' ConstValue
-    {
-      if (g_parse_mode == PROGRAM) {
-        $$ = $2;
-      } else {
-        $$ = NULL;
-      }
-    }
-|
-    {
-      $$ = NULL;
-    }
-
-FunctionType:
-  FieldType
-    {
-      pdebug("FunctionType -> FieldType");
-      $$ = $1;
-    }
-| tok_void
-    {
-      pdebug("FunctionType -> tok_void");
-      $$ = g_type_void;
-    }
-
-FieldType:
-  tok_identifier
-    {
-      pdebug("FieldType -> tok_identifier");
-      if (g_parse_mode == INCLUDES) {
-        // Ignore identifiers in include mode
-        $$ = NULL;
-      } else {
-        // Lookup the identifier in the current scope
-        $$ = g_scope->get_type($1);
-        if ($$ == NULL) {
-          yyerror("Type \"%s\" has not been defined.", $1);
-          exit(1);
-        }
-      }
-    }
-| BaseType
-    {
-      pdebug("FieldType -> BaseType");
-      $$ = $1;
-    }
-| ContainerType
-    {
-      pdebug("FieldType -> ContainerType");
-      $$ = $1;
-    }
-
-BaseType: SimpleBaseType TypeAnnotations
-    {
-      pdebug("BaseType -> SimpleBaseType TypeAnnotations");
-      if ($2 != NULL) {
-        $$ = new t_base_type(*static_cast<t_base_type*>($1));
-        $$->annotations_ = $2->annotations_;
-        delete $2;
-      } else {
-        $$ = $1;
-      }
-    }
-
-SimpleBaseType:
-  tok_string
-    {
-      pdebug("BaseType -> tok_string");
-      $$ = g_type_string;
-    }
-| tok_binary
-    {
-      pdebug("BaseType -> tok_binary");
-      $$ = g_type_binary;
-    }
-| tok_slist
-    {
-      pdebug("BaseType -> tok_slist");
-      $$ = g_type_slist;
-    }
-| tok_bool
-    {
-      pdebug("BaseType -> tok_bool");
-      $$ = g_type_bool;
-    }
-| tok_byte
-    {
-      pdebug("BaseType -> tok_byte");
-      $$ = g_type_byte;
-    }
-| tok_i16
-    {
-      pdebug("BaseType -> tok_i16");
-      $$ = g_type_i16;
-    }
-| tok_i32
-    {
-      pdebug("BaseType -> tok_i32");
-      $$ = g_type_i32;
-    }
-| tok_i64
-    {
-      pdebug("BaseType -> tok_i64");
-      $$ = g_type_i64;
-    }
-| tok_double
-    {
-      pdebug("BaseType -> tok_double");
-      $$ = g_type_double;
-    }
-
-ContainerType: SimpleContainerType TypeAnnotations
-    {
-      pdebug("ContainerType -> SimpleContainerType TypeAnnotations");
-      $$ = $1;
-      if ($2 != NULL) {
-        $$->annotations_ = $2->annotations_;
-        delete $2;
-      }
-    }
-
-SimpleContainerType:
-  MapType
-    {
-      pdebug("SimpleContainerType -> MapType");
-      $$ = $1;
-    }
-| SetType
-    {
-      pdebug("SimpleContainerType -> SetType");
-      $$ = $1;
-    }
-| ListType
-    {
-      pdebug("SimpleContainerType -> ListType");
-      $$ = $1;
-    }
-
-MapType:
-  tok_map CppType '<' FieldType ',' FieldType '>'
-    {
-      pdebug("MapType -> tok_map <FieldType, FieldType>");
-      $$ = new t_map($4, $6);
-      if ($2 != NULL) {
-        ((t_container*)$$)->set_cpp_name(std::string($2));
-      }
-    }
-
-SetType:
-  tok_set CppType '<' FieldType '>'
-    {
-      pdebug("SetType -> tok_set<FieldType>");
-      $$ = new t_set($4);
-      if ($2 != NULL) {
-        ((t_container*)$$)->set_cpp_name(std::string($2));
-      }
-    }
-
-ListType:
-  tok_list '<' FieldType '>' CppType
-    {
-      pdebug("ListType -> tok_list<FieldType>");
-      $$ = new t_list($3);
-      if ($5 != NULL) {
-        ((t_container*)$$)->set_cpp_name(std::string($5));
-      }
-    }
-
-CppType:
-  tok_cpp_type tok_literal
-    {
-      $$ = $2;
-    }
-|
-    {
-      $$ = NULL;
-    }
-
-TypeAnnotations:
-  '(' TypeAnnotationList ')'
-    {
-      pdebug("TypeAnnotations -> ( TypeAnnotationList )");
-      $$ = $2;
-    }
-|
-    {
-      $$ = NULL;
-    }
-
-TypeAnnotationList:
-  TypeAnnotationList TypeAnnotation
-    {
-      pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation");
-      $$ = $1;
-      $$->annotations_[$2->key] = $2->val;
-      delete $2;
-    }
-|
-    {
-      /* Just use a dummy structure to hold the annotations. */
-      $$ = new t_struct(g_program);
-    }
-
-TypeAnnotation:
-  tok_identifier '=' tok_literal CommaOrSemicolonOptional
-    {
-      pdebug("TypeAnnotation -> tok_identifier = tok_literal");
-      $$ = new t_annotation;
-      $$->key = $1;
-      $$->val = $3;
-    }
-
-%%
diff --git a/compiler/cpp/src/windows/config.h b/compiler/cpp/src/windows/config.h
deleted file mode 100644
index 9d75e80..0000000
--- a/compiler/cpp/src/windows/config.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding 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.
- */
-
-#ifndef _THRIFT_WINDOWS_CONFIG_H_
-#define _THRIFT_WINDOWS_CONFIG_H_ 1
-
-#if defined(_MSC_VER) && (_MSC_VER > 1200)
-#pragma once
-#endif // _MSC_VER
-
-#ifndef _WIN32
-#error "This is a Windows header only"
-#endif
-
-#include <io.h>
-#include <stdlib.h>
-#include <direct.h>
-
-#define strtoll(begin_ptr, end_ptr, length) _strtoi64(begin_ptr, end_ptr, length)
-
-#define PRIu64 "I64d"
-#define PRIi64 "I64d"
-
-#pragma warning(disable:4996)
-
-#endif // _THRIFT_WINDOWS_CONFIG_H_
diff --git a/compiler/cpp/src/windows/version.h.in b/compiler/cpp/src/windows/version.h.in
deleted file mode 100644
index 94b7c56..0000000
--- a/compiler/cpp/src/windows/version.h.in
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding 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.
- */
-
-#ifndef _THRIFT_WINDOWS_VERSION_H_
-#define _THRIFT_WINDOWS_VERSION_H_ 1
-
-#if defined(_MSC_VER) && (_MSC_VER > 1200)
-#pragma once
-#endif // _MSC_VER
-
-#ifndef _WIN32
-#error "This is a Windows header only"
-#endif
-
-#define PATH_MAX MAX_PATH
-#define THRIFT_VERSION "@PACKAGE_VERSION@"
-
-#ifndef S_ISDIR
-#define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
-#endif
-
-#ifndef S_ISREG
-#define S_ISREG(mode)  (((mode) & S_IFMT) == S_IFREG)
-#endif
-
-#endif // _THRIFT_WINDOWS_VERSION_H_
diff --git a/compiler/cpp/test/CMakeLists.txt b/compiler/cpp/test/CMakeLists.txt
new file mode 100644
index 0000000..a09f23d
--- /dev/null
+++ b/compiler/cpp/test/CMakeLists.txt
@@ -0,0 +1,92 @@
+#
+# 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.
+#
+
+
+if(${WITH_PLUGIN})
+    include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
+
+    # Make sure gen-cpp files can be included
+    include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+
+    set(plugintest_SOURCES
+        plugin/conversion_test.cc
+    )
+    add_executable(plugintest ${plugintest_SOURCES})
+    if(WITH_SHARED_LIB AND NOT MSVC)
+        target_link_libraries(plugintest
+            thriftc
+            ${Boost_LIBRARIES}
+        )
+    else()
+        target_link_libraries(plugintest
+            thriftc_static
+            thrift_static
+            ${Boost_LIBRARIES}
+        )
+    endif()
+    add_test(NAME PluginUnitTest COMMAND plugintest)
+
+    set(thrift-gen-mycpp_SOURCES
+        ../src/thrift/generate/t_cpp_generator.cc
+        plugin/cpp_plugin.cc
+    )
+    add_executable(thrift-gen-mycpp ${thrift-gen-mycpp_SOURCES})
+    if(WITH_SHARED_LIB AND NOT MSVC)
+        target_link_libraries(thrift-gen-mycpp thriftc)
+    else()
+        target_link_libraries(thrift-gen-mycpp thriftc_static thrift_static)
+    endif()
+
+    if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+        set(BUILDTYPE "Debug")
+    else()
+        # RelWithDebInfo generates binaries in "Release" directory too
+        set(BUILDTYPE "Release")
+    endif()
+
+    set_directory_properties(PROPERTIES
+        ADDITIONAL_MAKE_CLEAN_FILES gen-cpp
+        ADDITIONAL_MAKE_CLEAN_FILES gen-mycpp)
+
+    file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp)
+    file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/gen-mycpp)
+    add_test(NAME PluginIntegrationTest
+             COMMAND ${CMAKE_COMMAND}
+                 -DTHRIFT_COMPILER=${THRIFT_COMPILER}
+                 -DBINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
+                 -DBUILDTYPE=${BUILDTYPE}
+                 -DCURDIR=${CMAKE_CURRENT_BINARY_DIR}
+                 -DSRCDIR=${CMAKE_CURRENT_SOURCE_DIR}
+                 -P ${CMAKE_CURRENT_SOURCE_DIR}/cpp_plugin_test.cmake)
+endif()
+
+file(GLOB KEYWORD_SAMPLES "${CMAKE_CURRENT_SOURCE_DIR}/keyword-samples/*.thrift")
+foreach(LANG ${thrift_compiler_LANGS})
+    foreach(SAMPLE ${KEYWORD_SAMPLES})
+        get_filename_component(FILENAME ${SAMPLE} NAME_WE)
+        add_test(NAME "${LANG}_${FILENAME}"
+            COMMAND thrift-compiler --gen ${LANG} ${SAMPLE})
+        set_tests_properties("${LANG}_${FILENAME}" PROPERTIES
+            PASS_REGULAR_EXPRESSION "Cannot use reserved language keyword")
+    endforeach()
+endforeach()
+
+
+find_package(PythonInterp REQUIRED)
+add_test(NAME StalenessCheckTest COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/compiler/staleness_check.py ${THRIFT_COMPILER})
diff --git a/compiler/cpp/test/Makefile.am b/compiler/cpp/test/Makefile.am
new file mode 100644
index 0000000..b7fc91d
--- /dev/null
+++ b/compiler/cpp/test/Makefile.am
@@ -0,0 +1,60 @@
+#
+# 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.
+#
+#
+# Contains some contributions under the Thrift Software License.
+# Please see doc/old-thrift-license.txt in the Thrift distribution for
+# details.
+
+AUTOMAKE_OPTIONS = subdir-objects serial-tests
+
+AM_CPPFLAGS = $(BOOST_CPPFLAGS) -I$(top_srcdir)/compiler/cpp/src
+AM_LDFLAGS = $(BOOST_LDFLAGS)
+AM_CXXFLAGS = -Wall -Wextra -pedantic
+
+if WITH_PLUGIN
+check_PROGRAMS = plugintest
+
+noinst_PROGRAMS = thrift-gen-mycpp
+
+all-local: thrift-gen-bincat
+
+AM_CPPFLAGS += -I$(top_srcdir)/lib/cpp/src -I$(top_builddir)/lib/cpp/src
+
+plugintest_SOURCES = plugin/conversion_test.cc
+plugintest_LDADD = $(top_builddir)/compiler/cpp/libthriftc.la
+
+thrift_gen_mycpp_SOURCES = plugin/cpp_plugin.cc \
+                           plugin/t_cpp_generator.cc
+thrift_gen_mycpp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/compiler/cpp -I$(top_srcdir)/compiler/cpp/src/generate
+thrift_gen_mycpp_LDADD = $(top_builddir)/compiler/cpp/libthriftc.la
+
+cpp_plugin_test.sh: thrift-gen-mycpp
+
+thrift-gen-bincat:
+	cp bincat.sh $@
+	chmod 755 $@
+
+plugin_stability_test.sh: thrift-gen-bincat
+
+TESTS = $(check_PROGRAMS) cpp_plugin_test.sh plugin_stability_test.sh
+
+clean-local:
+	$(RM) -rf gen-cpp gen-mycpp gen-bincat thrift-gen-bincat
+
+endif
diff --git a/compiler/cpp/test/bincat.sh b/compiler/cpp/test/bincat.sh
new file mode 100755
index 0000000..c7f9078
--- /dev/null
+++ b/compiler/cpp/test/bincat.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+exec /bin/cat
diff --git a/compiler/cpp/test/compiler/Included.thrift b/compiler/cpp/test/compiler/Included.thrift
new file mode 100644
index 0000000..ce84ab6
--- /dev/null
+++ b/compiler/cpp/test/compiler/Included.thrift
@@ -0,0 +1,18 @@
+const string foo = "bar"
+
+struct a_struct {
+  1: bool im_true,
+  2: bool im_false,
+  3: i8 a_bite,
+  4: i16 integer16,
+  5: i32 integer32,
+  6: i64 integer64,
+  7: double double_precision,
+  8: string some_characters,
+  9: string zomg_unicode,
+  10: bool what_who,
+}
+
+service AService {
+  i32 a_procedure(1: i32 arg)
+}
diff --git a/compiler/cpp/test/compiler/Including.thrift b/compiler/cpp/test/compiler/Including.thrift
new file mode 100644
index 0000000..677af7b
--- /dev/null
+++ b/compiler/cpp/test/compiler/Including.thrift
@@ -0,0 +1,7 @@
+include "Included.thrift"
+
+const string s = "string"
+
+struct BStruct {
+  1: Included.a_struct one_of_each
+}
diff --git a/compiler/cpp/test/compiler/Single.thrift b/compiler/cpp/test/compiler/Single.thrift
new file mode 100644
index 0000000..2ec301f
--- /dev/null
+++ b/compiler/cpp/test/compiler/Single.thrift
@@ -0,0 +1 @@
+const string foo = "bar"
diff --git a/compiler/cpp/test/compiler/staleness_check.py b/compiler/cpp/test/compiler/staleness_check.py
new file mode 100755
index 0000000..5b11dff
--- /dev/null
+++ b/compiler/cpp/test/compiler/staleness_check.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python3
+#
+# 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.
+#
+from __future__ import print_function
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import time
+import unittest
+
+
+class TestStalenessCheck(unittest.TestCase):
+
+    CURRENT_DIR_PATH = os.path.dirname(os.path.realpath(__file__))
+    THRIFT_EXECUTABLE_PATH = None
+    SINGLE_THRIFT_FILE_PATH = os.path.join(CURRENT_DIR_PATH, "Single.thrift")
+    INCLUDING_THRIFT_FILE_PATH = os.path.join(CURRENT_DIR_PATH, "Including.thrift")
+    INCLUDED_THRIFT_FILE_PATH = os.path.join(CURRENT_DIR_PATH, "Included.thrift")
+
+    def test_staleness_check_of_single_thrift_file_without_changed_output(self):
+        temp_dir = tempfile.mkdtemp(dir=TestStalenessCheck.CURRENT_DIR_PATH)
+
+        command = [TestStalenessCheck.THRIFT_EXECUTABLE_PATH, "-gen", "cpp", "-o", temp_dir]
+        command += [TestStalenessCheck.SINGLE_THRIFT_FILE_PATH]
+        subprocess.call(command)
+
+        used_file_path = os.path.join(temp_dir, "gen-cpp", "Single_constants.cpp")
+
+        first_modification_time = os.path.getmtime(os.path.join(used_file_path))
+
+        time.sleep(0.1)
+
+        subprocess.call(command)
+
+        second_modification_time = os.path.getmtime(used_file_path)
+
+        self.assertEqual(second_modification_time, first_modification_time)
+
+        shutil.rmtree(temp_dir, ignore_errors=True)
+
+    def test_staleness_check_of_single_thrift_file_with_changed_output(self):
+        temp_dir = tempfile.mkdtemp(dir=TestStalenessCheck.CURRENT_DIR_PATH)
+
+        command = [TestStalenessCheck.THRIFT_EXECUTABLE_PATH, "-gen", "cpp", "-o", temp_dir]
+        command += [TestStalenessCheck.SINGLE_THRIFT_FILE_PATH]
+        subprocess.call(command)
+
+        used_file_path = os.path.join(temp_dir, "gen-cpp", "Single_constants.cpp")
+
+        first_modification_time = os.path.getmtime(os.path.join(used_file_path))
+        used_file = open(used_file_path, "r")
+        first_contents = used_file.read()
+        used_file.close()
+
+        used_file = open(used_file_path, "a")
+        used_file.write("\n/* This is a comment */\n")
+        used_file.close()
+
+        time.sleep(0.1)
+
+        subprocess.call(command)
+
+        second_modification_time = os.path.getmtime(used_file_path)
+        used_file = open(used_file_path, "r")
+        second_contents = used_file.read()
+        used_file.close()
+
+        self.assertGreater(second_modification_time, first_modification_time)
+        self.assertEqual(first_contents, second_contents)
+
+        shutil.rmtree(temp_dir, ignore_errors=True)
+
+    def test_staleness_check_of_included_file(self):
+        temp_dir = tempfile.mkdtemp(dir=TestStalenessCheck.CURRENT_DIR_PATH)
+
+        temp_included_file_path = os.path.join(temp_dir, "Included.thrift")
+        temp_including_file_path = os.path.join(temp_dir, "Including.thrift")
+
+        shutil.copy2(TestStalenessCheck.INCLUDED_THRIFT_FILE_PATH, temp_included_file_path)
+        shutil.copy2(TestStalenessCheck.INCLUDING_THRIFT_FILE_PATH, temp_including_file_path)
+
+        command = [TestStalenessCheck.THRIFT_EXECUTABLE_PATH, "-gen", "cpp", "-recurse", "-o", temp_dir]
+        command += [temp_including_file_path]
+
+        subprocess.call(command)
+
+        included_constants_cpp_file_path = os.path.join(temp_dir, "gen-cpp", "Included_constants.cpp")
+        including_constants_cpp_file_path = os.path.join(temp_dir, "gen-cpp", "Including_constants.cpp")
+
+        included_constants_cpp_first_modification_time = os.path.getmtime(included_constants_cpp_file_path)
+        including_constants_cpp_first_modification_time = os.path.getmtime(including_constants_cpp_file_path)
+
+        temp_included_file = open(temp_included_file_path, "a")
+        temp_included_file.write("\nconst i32 an_integer = 42\n")
+        temp_included_file.close()
+
+        time.sleep(0.1)
+
+        subprocess.call(command)
+
+        included_constants_cpp_second_modification_time = os.path.getmtime(included_constants_cpp_file_path)
+        including_constants_cpp_second_modification_time = os.path.getmtime(including_constants_cpp_file_path)
+
+        self.assertGreater(
+            included_constants_cpp_second_modification_time, included_constants_cpp_first_modification_time)
+        self.assertEqual(
+            including_constants_cpp_first_modification_time, including_constants_cpp_second_modification_time)
+
+        shutil.rmtree(temp_dir, ignore_errors=True)
+
+
+def suite():
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
+    suite.addTest(loader.loadTestsFromTestCase(TestStalenessCheck))
+    return suite
+
+
+if __name__ == "__main__":
+    # The path of Thrift compiler  is  passed as an argument to the test script.
+    # Remove it to not confuse the unit testing framework
+    TestStalenessCheck.THRIFT_EXECUTABLE_PATH = sys.argv[-1]
+    del sys.argv[-1]
+    unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
diff --git a/compiler/cpp/test/cpp_plugin_test.cmake b/compiler/cpp/test/cpp_plugin_test.cmake
new file mode 100644
index 0000000..fd18281
--- /dev/null
+++ b/compiler/cpp/test/cpp_plugin_test.cmake
@@ -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.
+#
+
+file(MAKE_DIRECTORY ${CURDIR}/gen-cpp)
+execute_process(COMMAND ${THRIFT_COMPILER} -r -out ${CURDIR}/gen-cpp -gen cpp ${SRCDIR}/../../../test/Include.thrift)
+if(EXITCODE)
+  message(FATAL_ERROR "FAILED: \"${ARGV}\": \"${EXITCODE}\"")
+endif()
+if(WIN32)
+    set(ENV{PATH} "${BINDIR}/${BUILDTYPE};${BINDIR};$ENV{PATH}")
+else()
+    set(ENV{PATH} "${BINDIR}:$ENV{PATH}")
+endif()
+
+file(MAKE_DIRECTORY ${CURDIR}/gen-mycpp)
+execute_process(COMMAND ${THRIFT_COMPILER} -r -out ${CURDIR}/gen-mycpp -gen mycpp ${SRCDIR}/../../../test/Include.thrift RESULT_VARIABLE EXITCODE)
+if(EXITCODE)
+  message(FATAL_ERROR "FAILED: \"${EXITCODE}\"")
+endif()
+
+find_program(DIFF diff)
+if(DIFF)
+  execute_process(COMMAND ${DIFF} -urN gen-cpp gen-mycpp RESULT_VARIABLE EXITCODE)
+  if(EXITCODE)
+    message(FATAL_ERROR "FAILED: \"${EXITCODE}\"")
+  endif()
+else()
+    message(WARNING "diff executable is not available. Not validating plugin-generated code.")
+endif()
diff --git a/compiler/cpp/test/cpp_plugin_test.sh b/compiler/cpp/test/cpp_plugin_test.sh
new file mode 100755
index 0000000..ddb2e0a
--- /dev/null
+++ b/compiler/cpp/test/cpp_plugin_test.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# this file is intended to be invoked by make.
+set -e
+mkdir -p gen-cpp gen-mycpp
+PATH=.:"$PATH" ../thrift -r -out gen-cpp -gen cpp ../../../test/Include.thrift
+PATH=.:"$PATH" ../thrift -r -out gen-mycpp -gen mycpp ../../../test/Include.thrift
+diff -urN gen-cpp gen-mycpp
diff --git a/compiler/cpp/test/keyword-samples/const1_return.thrift b/compiler/cpp/test/keyword-samples/const1_return.thrift
new file mode 100644
index 0000000..735e4ac
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/const1_return.thrift
@@ -0,0 +1 @@
+const bool return = 0
diff --git a/compiler/cpp/test/keyword-samples/enum1_return.thrift b/compiler/cpp/test/keyword-samples/enum1_return.thrift
new file mode 100644
index 0000000..6d834e1
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/enum1_return.thrift
@@ -0,0 +1,2 @@
+enum return {
+}
diff --git a/compiler/cpp/test/keyword-samples/enum2_return.thrift b/compiler/cpp/test/keyword-samples/enum2_return.thrift
new file mode 100644
index 0000000..a2caa8e
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/enum2_return.thrift
@@ -0,0 +1,3 @@
+enum enum_name {
+  return
+}
diff --git a/compiler/cpp/test/keyword-samples/exception1_return.thrift b/compiler/cpp/test/keyword-samples/exception1_return.thrift
new file mode 100644
index 0000000..eadb338
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/exception1_return.thrift
@@ -0,0 +1 @@
+exception return {}
diff --git a/compiler/cpp/test/keyword-samples/exception2_return.thrift b/compiler/cpp/test/keyword-samples/exception2_return.thrift
new file mode 100644
index 0000000..493c352
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/exception2_return.thrift
@@ -0,0 +1,3 @@
+exception exception_name {
+  1: required i8 return
+}
diff --git a/compiler/cpp/test/keyword-samples/service1_return.thrift b/compiler/cpp/test/keyword-samples/service1_return.thrift
new file mode 100644
index 0000000..5286a36
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/service1_return.thrift
@@ -0,0 +1 @@
+service return {}
diff --git a/compiler/cpp/test/keyword-samples/service2_return.thrift b/compiler/cpp/test/keyword-samples/service2_return.thrift
new file mode 100644
index 0000000..6f7331d
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/service2_return.thrift
@@ -0,0 +1,3 @@
+service service_name {
+  bool function_name(1: i32 return)
+}
diff --git a/compiler/cpp/test/keyword-samples/service3_return.thrift b/compiler/cpp/test/keyword-samples/service3_return.thrift
new file mode 100644
index 0000000..c6dd946
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/service3_return.thrift
@@ -0,0 +1,3 @@
+service service_name {
+  void return()
+}
diff --git a/compiler/cpp/test/keyword-samples/service4_return.thrift b/compiler/cpp/test/keyword-samples/service4_return.thrift
new file mode 100644
index 0000000..d0787df
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/service4_return.thrift
@@ -0,0 +1,5 @@
+exception exception_name {}
+
+service service_name {
+  void function_name() throws ( 1: exception_name return)
+}
diff --git a/compiler/cpp/test/keyword-samples/struct1_return.thrift b/compiler/cpp/test/keyword-samples/struct1_return.thrift
new file mode 100644
index 0000000..c82b8b9
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/struct1_return.thrift
@@ -0,0 +1 @@
+struct return {}
diff --git a/compiler/cpp/test/keyword-samples/struct2_return.thrift b/compiler/cpp/test/keyword-samples/struct2_return.thrift
new file mode 100644
index 0000000..a0700d1
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/struct2_return.thrift
@@ -0,0 +1,3 @@
+struct struct_name {
+  1: required bool return = 1
+}
diff --git a/compiler/cpp/test/keyword-samples/typedef1_return.thrift b/compiler/cpp/test/keyword-samples/typedef1_return.thrift
new file mode 100644
index 0000000..f159bb8
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/typedef1_return.thrift
@@ -0,0 +1 @@
+typedef bool return
diff --git a/compiler/cpp/test/keyword-samples/union1_return.thrift b/compiler/cpp/test/keyword-samples/union1_return.thrift
new file mode 100644
index 0000000..368df13
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/union1_return.thrift
@@ -0,0 +1 @@
+union return {}
diff --git a/compiler/cpp/test/keyword-samples/union2_return.thrift b/compiler/cpp/test/keyword-samples/union2_return.thrift
new file mode 100644
index 0000000..9719d1e
--- /dev/null
+++ b/compiler/cpp/test/keyword-samples/union2_return.thrift
@@ -0,0 +1,3 @@
+union union_name {
+  1: optional bool return=1
+}
diff --git a/compiler/cpp/test/plugin/conversion_test.cc b/compiler/cpp/test/plugin/conversion_test.cc
new file mode 100644
index 0000000..3c8d812
--- /dev/null
+++ b/compiler/cpp/test/plugin/conversion_test.cc
@@ -0,0 +1,498 @@
+/*
+ * 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.
+ */
+
+#include "thrift/parse/t_program.h"
+#include "thrift/plugin/type_util.h"
+#include "thrift/plugin/plugin_types.h"
+
+#include <map>
+#include <vector>
+
+#include <boost/preprocessor.hpp>
+#include <boost/test/included/unit_test.hpp>
+#include <boost/test/parameterized_test.hpp>
+
+using namespace apache::thrift;
+using namespace boost::unit_test;
+
+namespace test_data {
+#define T_TEST_TYPES                                                                               \
+  BOOST_PP_TUPLE_TO_LIST(14,                                                                       \
+                         (program,                                                                 \
+                          base_type,                                                               \
+                          enum_value,                                                              \
+                          enum,                                                                    \
+                          const_value,                                                             \
+                          const,                                                                   \
+                          list,                                                                    \
+                          set,                                                                     \
+                          map,                                                                     \
+                          field,                                                                   \
+                          struct,                                                                  \
+                          typedef,                                                                 \
+                          function,                                                                \
+                          service))
+#define T_DELETE_TESTDATA(r, d, elem)                                                              \
+  for (std::vector<t_##elem*>::reverse_iterator it = elem##s.rbegin(); it != elem##s.rend(); it++) \
+    delete *it;
+#define T_DECL_TESTDATA(r, d, elem) static std::vector< ::t_##elem*> elem##s;
+BOOST_PP_LIST_FOR_EACH(T_DECL_TESTDATA, _, T_TEST_TYPES)
+#undef T_DECL_TESTDATA
+
+bool has_data = false;
+void cleanup() {
+  if (has_data) {
+    has_data = false;
+    BOOST_PP_LIST_FOR_EACH(T_DELETE_TESTDATA, _, T_TEST_TYPES)
+  }
+}
+
+void init_programs() {
+  programs.push_back(new t_program("prog path", "prog_name"));
+}
+
+void init_base_types() {
+  base_types.push_back(new ::t_base_type("name0", ::t_base_type::TYPE_VOID));
+  base_types.push_back(new ::t_base_type("name1", ::t_base_type::TYPE_STRING));
+  base_types.push_back(new ::t_base_type("name2", ::t_base_type::TYPE_BOOL));
+  base_types.push_back(new ::t_base_type("name3", ::t_base_type::TYPE_I8));
+  base_types.push_back(new ::t_base_type("name4", ::t_base_type::TYPE_I16));
+  base_types.push_back(new ::t_base_type("name5", ::t_base_type::TYPE_I32));
+  base_types.push_back(new ::t_base_type("name6", ::t_base_type::TYPE_I64));
+  base_types.push_back(new ::t_base_type("name7", ::t_base_type::TYPE_DOUBLE));
+}
+
+void init_const_values() {
+  const_values.push_back(new t_const_value(42));
+  const_values.push_back(new t_const_value("foo"));
+  {
+    t_const_value* x = new t_const_value;
+    x->set_double(3.1415);
+    const_values.push_back(x);
+  }
+  {
+    t_const_value* x = new t_const_value;
+    x->set_identifier("bar");
+    x->set_enum(enums[0]);
+    const_values.push_back(x);
+  }
+  {
+    t_const_value* x = new t_const_value;
+    x->set_map();
+    x->add_map(const_values[0], const_values[1]);
+    x->add_map(const_values[1], const_values[0]);
+    const_values.push_back(x);
+  }
+  {
+    t_const_value* x = new t_const_value;
+    x->set_list();
+    x->add_list(const_values[0]);
+    x->add_list(const_values[1]);
+    const_values.push_back(x);
+  }
+}
+
+void init_consts() {
+  // base_type/enum indexes for this and other tests are arbitrary
+  consts.push_back(new t_const(base_types[2], "aaa", const_values[0]));
+  consts.back()->set_doc("soem doc");
+  consts.push_back(new t_const(base_types[3], "bbb", const_values[1]));
+}
+
+void init_enum_values() {
+  enum_values.push_back(new t_enum_value("VAL1", 11));
+  enum_values.back()->set_doc("enum doc 1");
+  enum_values.back()->annotations_.insert(std::make_pair("anno1", "val1"));
+
+  enum_values.push_back(new t_enum_value("VAL2", 22));
+}
+
+void init_enums() {
+  enums.push_back(new t_enum(programs[0]));
+  enums.back()->set_doc("enum doc 1");
+  enums.back()->annotations_.insert(std::make_pair("anno1", "val1"));
+  enums.back()->set_name("fooo");
+  enums.back()->append(enum_values[0]);
+  enums.back()->append(enum_values[1]);
+}
+
+void init_lists() {
+  lists.push_back(new t_list(enums[0]));
+  lists.push_back(new t_list(base_types[5]));
+  lists.back()->set_cpp_name("list_cpp_name_1");
+}
+void init_sets() {
+  sets.push_back(new t_set(base_types[4]));
+  sets.push_back(new t_set(enums[0]));
+  sets.back()->set_cpp_name("set_cpp_name_1");
+}
+void init_maps() {
+  maps.push_back(new t_map(base_types[4], base_types[1]));
+  maps.push_back(new t_map(base_types[5], enums[0]));
+  maps.back()->set_cpp_name("map_cpp_name_1");
+}
+
+void init_typedefs() {
+  typedefs.push_back(new t_typedef(programs[0], base_types[3], "VAL1"));
+}
+void init_fields() {
+  fields.push_back(new t_field(base_types[1], "f1"));
+  fields.back()->set_reference(false);
+  fields.back()->set_req(t_field::T_OPTIONAL);
+  fields.push_back(new t_field(base_types[2], "f2", 9));
+  fields.back()->set_reference(true);
+  fields.push_back(new t_field(base_types[3], "f3", 11));
+  fields.back()->set_req(t_field::T_REQUIRED);
+  fields.back()->set_value(const_values[0]);
+}
+void init_structs() {
+  structs.push_back(new t_struct(programs[0], "struct1"));
+  structs.back()->append(fields[0]);
+  structs.back()->append(fields[1]);
+  structs.push_back(new t_struct(programs[0], "union1"));
+  structs.back()->append(fields[0]);
+  structs.back()->append(fields[1]);
+  structs.back()->set_union(true);
+  structs.push_back(new t_struct(programs[0], "xcept1"));
+  structs.back()->set_xception(true);
+}
+void init_functions() {
+  structs.push_back(new t_struct(programs[0], "errs1"));
+  t_struct* errors = structs.back();
+  structs.push_back(new t_struct(programs[0], "args1"));
+  t_struct* arglist = structs.back();
+  functions.push_back(new t_function(base_types[0], "func1", errors, arglist, false));
+  functions.push_back(new t_function(base_types[0], "func2", errors, arglist, true));
+}
+void init_services() {
+  services.push_back(new t_service(programs[0]));
+  services.back()->set_doc("srv1 doc");
+  services.back()->set_name("srv1");
+  services.back()->add_function(functions[0]);
+  services.back()->add_function(functions[1]);
+
+  services.push_back(new t_service(programs[0]));
+  services.back()->set_name("srv2");
+  services.back()->set_extends(services[0]);
+}
+
+std::vector<t_type*> types;
+void init_types() {
+#define T_COPY_TYPES(type) std::copy(type##s.begin(), type##s.end(), std::back_inserter(types))
+  T_COPY_TYPES(base_type);
+  T_COPY_TYPES(enum);
+  T_COPY_TYPES(typedef);
+  T_COPY_TYPES(struct);
+  T_COPY_TYPES(list);
+  T_COPY_TYPES(set);
+  T_COPY_TYPES(map);
+// T_COPY_TYPES(service);
+#undef T_COPY_TYPES
+}
+
+void init() {
+  if (!has_data) {
+    has_data = true;
+#define T_INIT_TESTDATA(r, d, elem) init_##elem##s();
+    BOOST_PP_LIST_FOR_EACH(T_INIT_TESTDATA, _, T_TEST_TYPES)
+    init_types();
+#undef T_INIT_TESTDATA
+  }
+}
+}
+struct GlobalFixture {
+  ~GlobalFixture() { test_data::cleanup(); }
+};
+#if (BOOST_VERSION >= 105900)
+BOOST_GLOBAL_FIXTURE(GlobalFixture);
+#else
+BOOST_GLOBAL_FIXTURE(GlobalFixture)
+#endif
+
+void migrate_global_cache() {
+  plugin::TypeRegistry reg;
+  plugin_output::get_global_cache(reg);
+  plugin::set_global_cache(reg);
+  plugin_output::clear_global_cache();
+}
+template <typename T>
+T* round_trip(T* t) {
+  typename plugin::ToType<T>::type p;
+  plugin::clear_global_cache();
+  plugin_output::clear_global_cache();
+  plugin_output::convert(t, p);
+  migrate_global_cache();
+  return plugin::convert(p);
+}
+
+void test_base_type(::t_base_type* sut) {
+  plugin::t_base_type p;
+  plugin_output::convert(sut, p);
+  boost::scoped_ptr< ::t_base_type> sut2(plugin::convert(p));
+
+#define THRIFT_CHECK(r, data, elem) BOOST_PP_EXPAND(BOOST_CHECK_EQUAL(data elem, sut2->elem));
+  BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+                         sut->,
+                         BOOST_PP_TUPLE_TO_LIST(7,
+                                                (is_void(),
+                                                 is_string(),
+                                                 is_bool(),
+                                                 is_string_list(),
+                                                 is_binary(),
+                                                 is_string_enum(),
+                                                 is_base_type())))
+}
+
+void test_const_value(t_const_value* sut) {
+  boost::scoped_ptr<t_const_value> sut2(round_trip(sut));
+
+  BOOST_CHECK_EQUAL(sut->get_type(), sut2->get_type());
+  switch (sut->get_type()) {
+#define T_CONST_VALUE_CASE(type, name)                                                             \
+  case t_const_value::type:                                                                        \
+    BOOST_CHECK_EQUAL(sut->get_##name(), sut2->get_##name());                                      \
+    break
+    T_CONST_VALUE_CASE(CV_INTEGER, integer);
+    T_CONST_VALUE_CASE(CV_DOUBLE, double);
+    T_CONST_VALUE_CASE(CV_STRING, string);
+    T_CONST_VALUE_CASE(CV_IDENTIFIER, identifier);
+#undef T_CONST_VALUE_CASE
+  case t_const_value::CV_MAP:
+    BOOST_CHECK_EQUAL(sut->get_map().size(), sut2->get_map().size());
+    {
+      std::map<t_const_value::t_const_value_type, t_const_value::t_const_value_type> sut_values;
+      for (std::map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator it = sut->get_map().begin();
+           it != sut->get_map().end(); it++) {
+        sut_values[it->first->get_type()] = it->second->get_type();
+      }
+      std::map<t_const_value::t_const_value_type, t_const_value::t_const_value_type> sut2_values;
+      for (std::map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator it = sut2->get_map().begin();
+           it != sut2->get_map().end(); it++) {
+        sut2_values[it->first->get_type()] = it->second->get_type();
+      }
+      BOOST_CHECK_EQUAL(sut_values.begin()->first, sut2_values.begin()->first);
+      BOOST_CHECK_EQUAL(sut_values.begin()->second, sut2_values.begin()->second);
+    }
+    break;
+  case t_const_value::CV_LIST:
+    BOOST_CHECK_EQUAL(sut->get_list().size(), sut2->get_list().size());
+    BOOST_CHECK_EQUAL(sut->get_list().front()->get_type(), sut2->get_list().front()->get_type());
+    break;
+  default:
+    BOOST_ASSERT(false);
+    break;
+  }
+}
+
+void test_const(t_const* sut) {
+  boost::scoped_ptr< ::t_const> sut2(round_trip(sut));
+
+  BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+                         sut->,
+                         BOOST_PP_TUPLE_TO_LIST(4,
+                                                (get_type()->get_name(),
+                                                 get_name(),
+                                                 get_value()->get_type(),
+                                                 get_doc())))
+}
+
+void test_enum_value(t_enum_value* sut) {
+  boost::scoped_ptr<t_enum_value> sut2(round_trip(sut));
+
+  BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+                         sut->,
+                         BOOST_PP_TUPLE_TO_LIST(3, (get_name(), get_value(), get_doc())))
+}
+
+void test_enum(t_enum* sut) {
+  boost::scoped_ptr< ::t_enum> sut2(round_trip(sut));
+
+  BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+                         sut->,
+                         BOOST_PP_TUPLE_TO_LIST(6,
+                                                (get_name(),
+                                                 get_min_value()->get_value(),
+                                                 get_max_value()->get_value(),
+                                                 get_constant_by_value(11)->get_value(),
+                                                 get_constant_by_name("VAL1")->get_value(),
+                                                 get_doc())))
+}
+
+void test_list(t_list* sut) {
+  boost::scoped_ptr<t_list> sut2(round_trip(sut));
+
+  BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+                         sut->,
+                         BOOST_PP_TUPLE_TO_LIST(4,
+                                                (get_elem_type()->get_name(),
+                                                 has_cpp_name(),
+                                                 get_doc(),
+                                                 get_name())))
+  if (sut->has_cpp_name())
+    BOOST_CHECK_EQUAL(sut->get_cpp_name(), sut2->get_cpp_name());
+}
+void test_set(t_set* sut) {
+  boost::scoped_ptr<t_set> sut2(round_trip(sut));
+
+  BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+                         sut->,
+                         BOOST_PP_TUPLE_TO_LIST(4,
+                                                (get_elem_type()->get_name(),
+                                                 has_cpp_name(),
+                                                 get_doc(),
+                                                 get_name())))
+  if (sut->has_cpp_name())
+    BOOST_CHECK_EQUAL(sut->get_cpp_name(), sut2->get_cpp_name());
+}
+void test_map(t_map* sut) {
+  boost::scoped_ptr<t_map> sut2(round_trip(sut));
+
+  BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+                         sut->,
+                         BOOST_PP_TUPLE_TO_LIST(5,
+                                                (get_key_type()->get_name(),
+                                                 get_val_type()->get_name(),
+                                                 has_cpp_name(),
+                                                 get_doc(),
+                                                 get_name())))
+  if (sut->has_cpp_name())
+    BOOST_CHECK_EQUAL(sut->get_cpp_name(), sut2->get_cpp_name());
+}
+
+void test_typedef(t_typedef* sut) {
+  boost::scoped_ptr<t_typedef> sut2(round_trip(sut));
+
+  BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+                         sut->,
+                         BOOST_PP_TUPLE_TO_LIST(4,
+                                                (get_doc(),
+                                                 get_name(),
+                                                 get_symbolic(),
+                                                 is_forward_typedef())))
+}
+
+void test_type(t_type* sut) {
+  boost::scoped_ptr<t_type> sut2(round_trip(sut));
+
+  BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+                         sut->,
+                         BOOST_PP_TUPLE_TO_LIST(15,
+                                                (is_void(),
+                                                 is_base_type(),
+                                                 is_string(),
+                                                 is_bool(),
+                                                 is_typedef(),
+                                                 is_enum(),
+                                                 is_struct(),
+                                                 is_xception(),
+                                                 is_container(),
+                                                 is_list(),
+                                                 is_set(),
+                                                 is_map(),
+                                                 is_service(),
+                                                 get_doc(),
+                                                 get_name())))
+}
+
+void test_field(t_field* sut) {
+  boost::scoped_ptr<t_field> sut2(round_trip(sut));
+
+  BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+                         sut->,
+                         BOOST_PP_TUPLE_TO_LIST(5,
+                                                (get_req(),
+                                                 get_reference(),
+                                                 get_key(),
+                                                 get_doc(),
+                                                 get_name())))
+  if (sut->get_value()) {
+    THRIFT_CHECK(, sut->, get_value()->get_type());
+  } else {
+    BOOST_CHECK(!sut2->get_value());
+  }
+  if (sut->get_type()) {
+    THRIFT_CHECK(, sut->, get_type()->get_name());
+  } else {
+    BOOST_CHECK(!sut2->get_type());
+  }
+}
+void test_struct(t_struct* sut) {
+  boost::scoped_ptr<t_struct> sut2(round_trip(sut));
+
+  BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+                         sut->,
+                         BOOST_PP_TUPLE_TO_LIST(5,
+                                                (is_union(),
+                                                 is_xception(),
+                                                 is_struct(),
+                                                 get_doc(),
+                                                 get_name())))
+}
+
+void test_function(t_function* sut) {
+  boost::scoped_ptr<t_function> sut2(round_trip(sut));
+
+  BOOST_PP_LIST_FOR_EACH(
+      THRIFT_CHECK,
+      sut->,
+      BOOST_PP_TUPLE_TO_LIST(4, (get_doc(), get_name(), get_returntype()->get_name(), is_oneway())))
+}
+void test_service(t_service* sut) {
+  boost::scoped_ptr<t_service> sut2(round_trip(sut));
+
+  BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK,
+                         sut->,
+                         BOOST_PP_TUPLE_TO_LIST(3, (get_doc(), get_name(), get_functions().size())))
+  if (sut->get_extends()) {
+    THRIFT_CHECK(, sut->, get_extends()->get_name());
+  } else {
+    BOOST_CHECK(!sut2->get_extends());
+  }
+}
+
+void test_program(t_program* sut) {
+  boost::scoped_ptr<t_program> sut2(round_trip(sut));
+
+  BOOST_PP_LIST_FOR_EACH(THRIFT_CHECK, sut->, BOOST_PP_TUPLE_TO_LIST(2, (get_doc(), get_name())))
+}
+boost::unit_test::test_suite* do_init_unit_test_suite() {
+  test_data::init();
+  test_suite* ts = BOOST_TEST_SUITE("PluginConversionTest");
+
+#define T_TEST_CASE(r, d, type)                                                                    \
+  ts->add(BOOST_PARAM_TEST_CASE(test_##type, test_data::type##s.begin(), test_data::type##s.end()));
+  BOOST_PP_LIST_FOR_EACH(T_TEST_CASE, _, T_TEST_TYPES)
+  T_TEST_CASE(_, _, type)
+#undef T_TEST_CASE
+  return ts;
+}
+
+#ifdef BOOST_TEST_DYN_LINK
+bool init_unit_test_suite() {
+  framework::master_test_suite().add(do_init_unit_test_suite());
+  return true;
+}
+int main(int argc, char* argv[]) {
+  return ::boost::unit_test::unit_test_main(&init_unit_test_suite, argc, argv);
+}
+#else
+boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
+  return do_init_unit_test_suite();
+}
+#endif
diff --git a/compiler/cpp/test/plugin/cpp_plugin.cc b/compiler/cpp/test/plugin/cpp_plugin.cc
new file mode 100644
index 0000000..6cc19f2
--- /dev/null
+++ b/compiler/cpp/test/plugin/cpp_plugin.cc
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#include "thrift/plugin/plugin.h"
+#include "thrift/generate/t_generator.h"
+
+namespace apache {
+namespace thrift {
+namespace plugin {
+
+class MyCppGenerator : public GeneratorPlugin {
+  virtual int generate(::t_program* program,
+                       const std::map<std::string, std::string>& parsed_options) {
+    t_generator* gen = t_generator_registry::get_generator(program, "cpp", parsed_options, "");
+    gen->generate_program();
+    delete gen;
+    return 0;
+  }
+};
+}
+}
+}
+
+int main(int argc, char* argv[]) {
+  apache::thrift::plugin::MyCppGenerator p;
+  return p.exec(argc, argv);
+}
diff --git a/compiler/cpp/test/plugin_stability_test.sh b/compiler/cpp/test/plugin_stability_test.sh
new file mode 100755
index 0000000..eb7c93d
--- /dev/null
+++ b/compiler/cpp/test/plugin_stability_test.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# this file is intended to be invoked by make.
+#
+# This file runs the compiler twice, using a plugin that just invokes
+# /bin/cat, and compares the output.  If GeneratorInput is
+# nondeterminsitic, you'd expect the output to differ from run-to-run.
+# So this tests that in fact, the output is stable from run-to-run.
+set -e
+mkdir -p gen-bincat
+PATH=.:"$PATH" ../thrift -r -gen bincat ../../../test/Include.thrift > gen-bincat/1.ser
+PATH=.:"$PATH" ../thrift -r -gen bincat ../../../test/Include.thrift > gen-bincat/2.ser
+diff --binary gen-bincat/1.ser gen-bincat/2.ser
diff --git a/compiler/cpp/tests/CMakeLists.txt b/compiler/cpp/tests/CMakeLists.txt
new file mode 100644
index 0000000..e2b100c
--- /dev/null
+++ b/compiler/cpp/tests/CMakeLists.txt
@@ -0,0 +1,153 @@
+#
+# 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.
+#
+cmake_minimum_required(VERSION 2.8.12)
+
+project(thrift_compiler_tests)
+
+set(THRIFT_COMPILER_SOURCE_DIR
+    ${CMAKE_CURRENT_SOURCE_DIR}/..
+)
+
+# don't generate ZERO_CHECK
+set(CMAKE_SUPPRESS_REGENERATION true)
+
+configure_file(${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/thrift/version.h)
+if(MSVC)
+    # The winflexbison generator outputs some macros that conflict with the Visual Studio 2010 copy of stdint.h
+    # This might be fixed in later versions of Visual Studio, but an easy solution is to include stdint.h first
+    if(HAVE_STDINT_H)
+        add_definitions(-D__STDC_LIMIT_MACROS)
+        add_definitions(/FI"stdint.h")
+    endif(HAVE_STDINT_H)
+endif()
+
+find_package(FLEX REQUIRED)
+find_package(BISON REQUIRED)
+
+# create directory for thrifty and thriftl
+file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/thrift/)
+
+# Create flex and bison files and build the lib parse static library
+BISON_TARGET(thrifty ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/thrifty.yy ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.cc)
+FLEX_TARGET(thriftl ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/thriftl.ll ${CMAKE_CURRENT_BINARY_DIR}/thrift/thriftl.cc)
+ADD_FLEX_BISON_DEPENDENCY(thriftl thrifty)
+
+set(parse_SOURCES
+    ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.cc
+    ${CMAKE_CURRENT_BINARY_DIR}/thrift/thriftl.cc
+    ${CMAKE_CURRENT_BINARY_DIR}/thrift/thrifty.hh
+)
+
+add_library(parse STATIC ${parse_SOURCES})
+
+# Thrift compiler tests
+set(thrift_compiler_tests
+)
+
+# you can add some files manually there 
+set(thrift_compiler_tests_manual_SOURCES
+    # tests file to avoid main in every test file
+    ${CMAKE_CURRENT_SOURCE_DIR}/tests_main.cc
+)
+
+# set variable for tests sources - will be filled later
+set(thrift_compiler_tests_SOURCES
+)
+
+set(thrift_compiler_SOURCES
+    ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/logging.cc # we use logging instead of main to avoid breaking compillation (2 main v)
+    ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/audit/t_audit.cpp
+    ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/common.cc
+    ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/generate/t_generator.cc
+    ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/parse/t_typedef.cc
+    ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/parse/parse.cc
+    ${CMAKE_CURRENT_BINARY_DIR}/thrift/version.h
+)
+
+# This macro adds an option THRIFT_COMPILER_${NAME}
+# that allows enabling or disabling certain languages
+macro(THRIFT_ADD_COMPILER name description initial)
+    string(TOUPPER "THRIFT_COMPILER_${name}" enabler)
+    set(src "${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/generate/t_${name}_generator.cc")
+    option(${enabler} ${description} ${initial})
+    if(${enabler})
+        list(APPEND thrift_compiler_SOURCES ${src})
+        file(GLOB thrift_compiler_tests_SOURCES
+            "${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.c*"
+            "${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.thrift"
+        )
+    endif()
+endmacro()
+
+# The following compiler with unit tests can be enabled or disabled
+THRIFT_ADD_COMPILER(c_glib  "Enable compiler for C with Glib" OFF)
+THRIFT_ADD_COMPILER(cpp     "Enable compiler for C++" OFF)
+THRIFT_ADD_COMPILER(java    "Enable compiler for Java"   OFF)
+THRIFT_ADD_COMPILER(as3     "Enable compiler for ActionScript 3" OFF)
+THRIFT_ADD_COMPILER(dart    "Enable compiler for Dart" OFF)
+THRIFT_ADD_COMPILER(haxe    "Enable compiler for Haxe" OFF)
+THRIFT_ADD_COMPILER(csharp  "Enable compiler for C#" OFF)
+THRIFT_ADD_COMPILER(netcore "Enable compiler for .NET Core" ON)
+THRIFT_ADD_COMPILER(py      "Enable compiler for Python 2.0" OFF)
+THRIFT_ADD_COMPILER(rb      "Enable compiler for Ruby" OFF)
+THRIFT_ADD_COMPILER(perl    "Enable compiler for Perl" OFF)
+THRIFT_ADD_COMPILER(php     "Enable compiler for PHP" OFF)
+THRIFT_ADD_COMPILER(erl     "Enable compiler for Erlang" OFF)
+THRIFT_ADD_COMPILER(cocoa   "Enable compiler for Cocoa Objective-C" OFF)
+THRIFT_ADD_COMPILER(swift   "Enable compiler for Cocoa Swift" OFF)
+THRIFT_ADD_COMPILER(st      "Enable compiler for Smalltalk" OFF)
+THRIFT_ADD_COMPILER(ocaml   "Enable compiler for OCaml" OFF)
+THRIFT_ADD_COMPILER(hs      "Enable compiler for Haskell" OFF)
+THRIFT_ADD_COMPILER(xsd     "Enable compiler for XSD" OFF)
+THRIFT_ADD_COMPILER(html    "Enable compiler for HTML Documentation" OFF)
+THRIFT_ADD_COMPILER(js      "Enable compiler for JavaScript" OFF)
+THRIFT_ADD_COMPILER(json    "Enable compiler for JSON" OFF)
+THRIFT_ADD_COMPILER(javame  "Enable compiler for Java ME" OFF)
+THRIFT_ADD_COMPILER(delphi  "Enable compiler for Delphi" OFF)
+THRIFT_ADD_COMPILER(go      "Enable compiler for Go" OFF)
+THRIFT_ADD_COMPILER(d       "Enable compiler for D" OFF)
+THRIFT_ADD_COMPILER(lua     "Enable compiler for Lua" OFF)
+THRIFT_ADD_COMPILER(gv      "Enable compiler for GraphViz" OFF)
+THRIFT_ADD_COMPILER(rs      "Enable compiler for Rust" OFF)
+THRIFT_ADD_COMPILER(xml     "Enable compiler for XML" OFF)
+
+# Thrift is looking for include files in the src directory
+# we also add the current binary directory for generated files
+include_directories(${CMAKE_CURRENT_BINARY_DIR} ${THRIFT_COMPILER_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/catch)
+
+add_library(thrift_compiler ${thrift_compiler_SOURCES})
+
+#link parse lib to thrift_compiler lib
+target_link_libraries(thrift_compiler parse)
+
+# add tests executable
+add_executable(thrift_compiler_tests ${thrift_compiler_tests_manual_SOURCES} ${thrift_compiler_tests_SOURCES})
+
+# if generates for Visual Studio set thrift_compiler_tests as default project
+if(MSVC)
+    set_property(TARGET thrift_compiler_tests PROPERTY VS_STARTUP_PROJECT thrift_compiler_tests)
+endif()
+
+set_target_properties(thrift_compiler_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY bin/)
+set_target_properties(thrift_compiler_tests PROPERTIES OUTPUT_NAME thrift_compiler_tests)
+
+target_link_libraries(thrift_compiler_tests thrift_compiler)
+
+enable_testing()
+add_test(NAME ThriftTests COMMAND thrift_compiler_tests)
\ No newline at end of file
diff --git a/compiler/cpp/tests/README.md b/compiler/cpp/tests/README.md
new file mode 100644
index 0000000..27be491
--- /dev/null
+++ b/compiler/cpp/tests/README.md
@@ -0,0 +1,88 @@
+# Build and run compiler tests using CMake
+
+<!-- TOC -->
+
+- [Build and run compiler tests using CMake](#build-and-run-compiler-tests-using-cmake)
+    - [General information](#general-information)
+    - [How to add your tests](#how-to-add-your-tests)
+    - [Build and run tests on Unix-like systems](#build-and-run-tests-on-unix-like-systems)
+        - [Prerequisites:](#prerequisites)
+        - [Build and run test with CMake](#build-and-run-test-with-cmake)
+    - [Build and run tests on Windows](#build-and-run-tests-on-windows)
+        - [Prerequisites:](#prerequisites-1)
+        - [Generation of VS project with CMake, build and run on Windows](#generation-of-vs-project-with-cmake-build-and-run-on-windows)
+
+<!-- /TOC -->
+
+## General information 
+
+Added generic way to cover code by tests for many languages (you just need to make a correct header file for generator for your language - example in **netcore** implementation)
+
+At current moment these tests use free Catch library (https://github.com/catchorg/Catch2/tree/Catch1.x) for easy test creation and usage.
+Decision to use it was because of simplicity, easy usage, one header file to use, stable community and growing interest  (https://cpp.libhunt.com/project/googletest-google/vs/catch?rel=cmp-cmp)
+
+Also, maybe, later it will be migrated to Catch2 (https://github.com/philsquared/Catch) - depends on need to support legacy compilers (c++98)
+
+## How to add your tests
+
+- Open **CMakeLists.txt**
+- Set **On** to call of **THRIFT_ADD_COMPILER** for your language
+
+``` cmake 
+THRIFT_ADD_COMPILER(netcore "Enable compiler for .NET Core" ON)
+```
+
+- Create folder with name specified in list of languages in **CMakeLists.txt**
+- Create tests in folder for your language (with extensions like *.c* - cc, cpp, etc)
+  - Don't forget to add include of catch.hpp in your test file
+  ``` C
+  #include "../catch/catch.hpp"
+  ```
+
+- If you need - add files manually to **thrift_compiler_tests_manual_SOURCES** in **CMakeLists.txt** similar to 
+
+``` cmake
+# you can add some files manually there 
+set(thrift_compiler_tests_manual_SOURCES
+    # tests file to avoid main in every test file
+    ${CMAKE_CURRENT_SOURCE_DIR}/tests_main.cc
+)
+```
+
+- Run **cmake** with arguments for your environment and compiler 
+- Enjoy
+
+## Build and run tests on Unix-like systems
+
+### Prerequisites:
+- Install CMake - <https://cmake.org/download/>
+- Install winflexbison - <https://sourceforge.net/projects/winflexbison/>
+
+### Build and run test with CMake
+
+- Run commands in command line in current directory:
+
+```
+mkdir cmake-vs && cd cmake-vs
+cmake ..
+cmake --build .
+ctest -C Debug -V
+```
+
+## Build and run tests on Windows
+
+### Prerequisites:
+- Install CMake - <https://cmake.org/download/>
+- Install winflexbison - <https://sourceforge.net/projects/winflexbison/>
+- Install VS2017 Community Edition - <https://www.visualstudio.com/vs/whatsnew/> (ensure that you installed workload "Desktop Development with C++" for VS2017)
+
+### Generation of VS project with CMake, build and run on Windows
+- Run commands in command line in current directory (ensure that VS installed):
+
+```
+mkdir cmake-vs
+cd cmake-vs
+cmake ..
+cmake --build .
+ctest -C Debug -V
+```
\ No newline at end of file
diff --git a/compiler/cpp/tests/catch/catch.hpp b/compiler/cpp/tests/catch/catch.hpp
new file mode 100644
index 0000000..33d037e
--- /dev/null
+++ b/compiler/cpp/tests/catch/catch.hpp
@@ -0,0 +1,11508 @@
+/*
+ *  Catch v1.9.4
+ *  Generated: 2017-05-16 13:51:55.506519
+ *  ----------------------------------------------------------
+ *  This file has been merged from multiple headers. Please don't edit it directly
+ *  Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
+#define TWOBLUECUBES_CATCH_HPP_INCLUDED
+
+#ifdef __clang__
+#    pragma clang system_header
+#elif defined __GNUC__
+#    pragma GCC system_header
+#endif
+
+// #included from: internal/catch_suppress_warnings.h
+
+#ifdef __clang__
+#   ifdef __ICC // icpc defines the __clang__ macro
+#       pragma warning(push)
+#       pragma warning(disable: 161 1682)
+#   else // __ICC
+#       pragma clang diagnostic ignored "-Wglobal-constructors"
+#       pragma clang diagnostic ignored "-Wvariadic-macros"
+#       pragma clang diagnostic ignored "-Wc99-extensions"
+#       pragma clang diagnostic ignored "-Wunused-variable"
+#       pragma clang diagnostic push
+#       pragma clang diagnostic ignored "-Wpadded"
+#       pragma clang diagnostic ignored "-Wc++98-compat"
+#       pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#       pragma clang diagnostic ignored "-Wswitch-enum"
+#       pragma clang diagnostic ignored "-Wcovered-switch-default"
+#    endif
+#elif defined __GNUC__
+#    pragma GCC diagnostic ignored "-Wvariadic-macros"
+#    pragma GCC diagnostic ignored "-Wunused-variable"
+#    pragma GCC diagnostic ignored "-Wparentheses"
+
+#    pragma GCC diagnostic push
+#    pragma GCC diagnostic ignored "-Wpadded"
+#endif
+#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
+#  define CATCH_IMPL
+#endif
+
+#ifdef CATCH_IMPL
+#  ifndef CLARA_CONFIG_MAIN
+#    define CLARA_CONFIG_MAIN_NOT_DEFINED
+#    define CLARA_CONFIG_MAIN
+#  endif
+#endif
+
+// #included from: internal/catch_notimplemented_exception.h
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
+
+// #included from: catch_common.h
+#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
+
+// #included from: catch_compiler_capabilities.h
+#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
+
+// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
+// The following features are defined:
+//
+// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported?
+// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
+// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
+// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported?
+// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported
+// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported?
+// CATCH_CONFIG_CPP11_OVERRIDE : is override supported?
+// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
+// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported?
+// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported?
+
+// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
+
+// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
+// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
+// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
+// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
+// ****************
+// Note to maintainers: if new toggles are added please document them
+// in configuration.md, too
+// ****************
+
+// In general each macro has a _NO_<feature name> form
+// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
+// can be combined, en-mass, with the _NO_ forms later.
+
+// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
+
+#ifdef __cplusplus
+
+#  if __cplusplus >= 201103L
+#    define CATCH_CPP11_OR_GREATER
+#  endif
+
+#  if __cplusplus >= 201402L
+#    define CATCH_CPP14_OR_GREATER
+#  endif
+
+#endif
+
+#ifdef __clang__
+
+#  if __has_feature(cxx_nullptr)
+#    define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#  endif
+
+#  if __has_feature(cxx_noexcept)
+#    define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#  endif
+
+#   if defined(CATCH_CPP11_OR_GREATER)
+#       define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+            _Pragma( "clang diagnostic push" ) \
+            _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" )
+#       define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+            _Pragma( "clang diagnostic pop" )
+
+#       define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+            _Pragma( "clang diagnostic push" ) \
+            _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
+#       define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+            _Pragma( "clang diagnostic pop" )
+#   endif
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// We know some environments not to support full POSIX signals
+#if defined(__CYGWIN__) || defined(__QNX__)
+
+#   if !defined(CATCH_CONFIG_POSIX_SIGNALS)
+#       define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
+#   endif
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Cygwin
+#ifdef __CYGWIN__
+
+// Required for some versions of Cygwin to declare gettimeofday
+// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
+#   define _BSD_SOURCE
+
+#endif // __CYGWIN__
+
+////////////////////////////////////////////////////////////////////////////////
+// Borland
+#ifdef __BORLANDC__
+
+#endif // __BORLANDC__
+
+////////////////////////////////////////////////////////////////////////////////
+// EDG
+#ifdef __EDG_VERSION__
+
+#endif // __EDG_VERSION__
+
+////////////////////////////////////////////////////////////////////////////////
+// Digital Mars
+#ifdef __DMC__
+
+#endif // __DMC__
+
+////////////////////////////////////////////////////////////////////////////////
+// GCC
+#ifdef __GNUC__
+
+#   if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
+#       define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#   endif
+
+// - otherwise more recent versions define __cplusplus >= 201103L
+// and will get picked up below
+
+#endif // __GNUC__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#ifdef _MSC_VER
+
+#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
+
+#if (_MSC_VER >= 1600)
+#   define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#   define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
+#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
+#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
+#endif
+
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Use variadic macros if the compiler supports them
+#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
+    ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
+    ( defined __GNUC__ && __GNUC__ >= 3 ) || \
+    ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L )
+
+#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+
+#endif
+
+// Use __COUNTER__ if the compiler supports it
+#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
+    ( defined __GNUC__  && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \
+    ( defined __clang__ && __clang_major__ >= 3 )
+
+#define CATCH_INTERNAL_CONFIG_COUNTER
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ language feature support
+
+// catch all support for C++11
+#if defined(CATCH_CPP11_OR_GREATER)
+
+#  if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR)
+#    define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#    define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#    define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
+#    define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE
+#    define CATCH_INTERNAL_CONFIG_CPP11_TUPLE
+#  endif
+
+#  ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+#    define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS
+#  endif
+
+#  if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG)
+#    define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG
+#  endif
+
+#  if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE)
+#    define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE
+#  endif
+#  if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
+#    define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#  endif
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE)
+#   define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
+#  endif
+# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS)
+#  define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
+# endif
+
+#endif // __cplusplus >= 201103L
+
+// Now set the actual defines based on the above + anything the user has configured
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_NULLPTR
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_NOEXCEPT
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_GENERATED_METHODS
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_IS_ENUM
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_TUPLE
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS)
+#   define CATCH_CONFIG_VARIADIC_MACROS
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_LONG_LONG
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_OVERRIDE
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_UNIQUE_PTR
+#endif
+// Use of __COUNTER__ is suppressed if __JETBRAINS_IDE__ is #defined (meaning we're being parsed by a JetBrains IDE for
+// analytics) because, at time of writing, __COUNTER__ is not properly handled by it.
+// This does not affect compilation
+#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) && !defined(__JETBRAINS_IDE__)
+#   define CATCH_CONFIG_COUNTER
+#endif
+#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11)
+#   define CATCH_CONFIG_CPP11_SHUFFLE
+#endif
+# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11)
+#  define CATCH_CONFIG_CPP11_TYPE_TRAITS
+# endif
+#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH)
+#   define CATCH_CONFIG_WINDOWS_SEH
+#endif
+// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
+#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
+#   define CATCH_CONFIG_POSIX_SIGNALS
+#endif
+
+#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
+#   define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
+#   define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
+#endif
+#if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS)
+#   define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
+#   define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+#endif
+
+// noexcept support:
+#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
+#  define CATCH_NOEXCEPT noexcept
+#  define CATCH_NOEXCEPT_IS(x) noexcept(x)
+#else
+#  define CATCH_NOEXCEPT throw()
+#  define CATCH_NOEXCEPT_IS(x)
+#endif
+
+// nullptr support
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+#   define CATCH_NULL nullptr
+#else
+#   define CATCH_NULL NULL
+#endif
+
+// override support
+#ifdef CATCH_CONFIG_CPP11_OVERRIDE
+#   define CATCH_OVERRIDE override
+#else
+#   define CATCH_OVERRIDE
+#endif
+
+// unique_ptr support
+#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR
+#   define CATCH_AUTO_PTR( T ) std::unique_ptr<T>
+#else
+#   define CATCH_AUTO_PTR( T ) std::auto_ptr<T>
+#endif
+
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
+#ifdef CATCH_CONFIG_COUNTER
+#  define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
+#else
+#  define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
+#endif
+
+#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
+#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
+
+#include <sstream>
+#include <algorithm>
+
+namespace Catch {
+
+    struct IConfig;
+
+    struct CaseSensitive { enum Choice {
+        Yes,
+        No
+    }; };
+
+    class NonCopyable {
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        NonCopyable( NonCopyable const& )              = delete;
+        NonCopyable( NonCopyable && )                  = delete;
+        NonCopyable& operator = ( NonCopyable const& ) = delete;
+        NonCopyable& operator = ( NonCopyable && )     = delete;
+#else
+        NonCopyable( NonCopyable const& info );
+        NonCopyable& operator = ( NonCopyable const& );
+#endif
+
+    protected:
+        NonCopyable() {}
+        virtual ~NonCopyable();
+    };
+
+    class SafeBool {
+    public:
+        typedef void (SafeBool::*type)() const;
+
+        static type makeSafe( bool value ) {
+            return value ? &SafeBool::trueValue : 0;
+        }
+    private:
+        void trueValue() const {}
+    };
+
+    template<typename ContainerT>
+    inline void deleteAll( ContainerT& container ) {
+        typename ContainerT::const_iterator it = container.begin();
+        typename ContainerT::const_iterator itEnd = container.end();
+        for(; it != itEnd; ++it )
+            delete *it;
+    }
+    template<typename AssociativeContainerT>
+    inline void deleteAllValues( AssociativeContainerT& container ) {
+        typename AssociativeContainerT::const_iterator it = container.begin();
+        typename AssociativeContainerT::const_iterator itEnd = container.end();
+        for(; it != itEnd; ++it )
+            delete it->second;
+    }
+
+    bool startsWith( std::string const& s, std::string const& prefix );
+    bool startsWith( std::string const& s, char prefix );
+    bool endsWith( std::string const& s, std::string const& suffix );
+    bool endsWith( std::string const& s, char suffix );
+    bool contains( std::string const& s, std::string const& infix );
+    void toLowerInPlace( std::string& s );
+    std::string toLower( std::string const& s );
+    std::string trim( std::string const& str );
+    bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
+
+    struct pluralise {
+        pluralise( std::size_t count, std::string const& label );
+
+        friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
+
+        std::size_t m_count;
+        std::string m_label;
+    };
+
+    struct SourceLineInfo {
+
+        SourceLineInfo();
+        SourceLineInfo( char const* _file, std::size_t _line );
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        SourceLineInfo(SourceLineInfo const& other)          = default;
+        SourceLineInfo( SourceLineInfo && )                  = default;
+        SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
+        SourceLineInfo& operator = ( SourceLineInfo && )     = default;
+#  endif
+        bool empty() const;
+        bool operator == ( SourceLineInfo const& other ) const;
+        bool operator < ( SourceLineInfo const& other ) const;
+
+        char const* file;
+        std::size_t line;
+    };
+
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
+
+    // This is just here to avoid compiler warnings with macro constants and boolean literals
+    inline bool isTrue( bool value ){ return value; }
+    inline bool alwaysTrue() { return true; }
+    inline bool alwaysFalse() { return false; }
+
+    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
+
+    void seedRng( IConfig const& config );
+    unsigned int rngSeed();
+
+    // Use this in variadic streaming macros to allow
+    //    >> +StreamEndStop
+    // as well as
+    //    >> stuff +StreamEndStop
+    struct StreamEndStop {
+        std::string operator+() {
+            return std::string();
+        }
+    };
+    template<typename T>
+    T const& operator + ( T const& value, StreamEndStop ) {
+        return value;
+    }
+}
+
+#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
+#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
+
+namespace Catch {
+
+    class NotImplementedException : public std::exception
+    {
+    public:
+        NotImplementedException( SourceLineInfo const& lineInfo );
+        NotImplementedException( NotImplementedException const& ) {}
+
+        virtual ~NotImplementedException() CATCH_NOEXCEPT {}
+
+        virtual const char* what() const CATCH_NOEXCEPT;
+
+    private:
+        std::string m_what;
+        SourceLineInfo m_lineInfo;
+    };
+
+} // end namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
+
+// #included from: internal/catch_context.h
+#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
+
+// #included from: catch_interfaces_generators.h
+#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct IGeneratorInfo {
+        virtual ~IGeneratorInfo();
+        virtual bool moveNext() = 0;
+        virtual std::size_t getCurrentIndex() const = 0;
+    };
+
+    struct IGeneratorsForTest {
+        virtual ~IGeneratorsForTest();
+
+        virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0;
+        virtual bool moveNext() = 0;
+    };
+
+    IGeneratorsForTest* createGeneratorsForTest();
+
+} // end namespace Catch
+
+// #included from: catch_ptr.hpp
+#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    // An intrusive reference counting smart pointer.
+    // T must implement addRef() and release() methods
+    // typically implementing the IShared interface
+    template<typename T>
+    class Ptr {
+    public:
+        Ptr() : m_p( CATCH_NULL ){}
+        Ptr( T* p ) : m_p( p ){
+            if( m_p )
+                m_p->addRef();
+        }
+        Ptr( Ptr const& other ) : m_p( other.m_p ){
+            if( m_p )
+                m_p->addRef();
+        }
+        ~Ptr(){
+            if( m_p )
+                m_p->release();
+        }
+        void reset() {
+            if( m_p )
+                m_p->release();
+            m_p = CATCH_NULL;
+        }
+        Ptr& operator = ( T* p ){
+            Ptr temp( p );
+            swap( temp );
+            return *this;
+        }
+        Ptr& operator = ( Ptr const& other ){
+            Ptr temp( other );
+            swap( temp );
+            return *this;
+        }
+        void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
+        T* get() const{ return m_p; }
+        T& operator*() const { return *m_p; }
+        T* operator->() const { return m_p; }
+        bool operator !() const { return m_p == CATCH_NULL; }
+        operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); }
+
+    private:
+        T* m_p;
+    };
+
+    struct IShared : NonCopyable {
+        virtual ~IShared();
+        virtual void addRef() const = 0;
+        virtual void release() const = 0;
+    };
+
+    template<typename T = IShared>
+    struct SharedImpl : T {
+
+        SharedImpl() : m_rc( 0 ){}
+
+        virtual void addRef() const {
+            ++m_rc;
+        }
+        virtual void release() const {
+            if( --m_rc == 0 )
+                delete this;
+        }
+
+        mutable unsigned int m_rc;
+    };
+
+} // end namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace Catch {
+
+    class TestCase;
+    class Stream;
+    struct IResultCapture;
+    struct IRunner;
+    struct IGeneratorsForTest;
+    struct IConfig;
+
+    struct IContext
+    {
+        virtual ~IContext();
+
+        virtual IResultCapture* getResultCapture() = 0;
+        virtual IRunner* getRunner() = 0;
+        virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0;
+        virtual bool advanceGeneratorsForCurrentTest() = 0;
+        virtual Ptr<IConfig const> getConfig() const = 0;
+    };
+
+    struct IMutableContext : IContext
+    {
+        virtual ~IMutableContext();
+        virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
+        virtual void setRunner( IRunner* runner ) = 0;
+        virtual void setConfig( Ptr<IConfig const> const& config ) = 0;
+    };
+
+    IContext& getCurrentContext();
+    IMutableContext& getCurrentMutableContext();
+    void cleanUpContext();
+    Stream createStream( std::string const& streamName );
+
+}
+
+// #included from: internal/catch_test_registry.hpp
+#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_interfaces_testcase.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
+
+#include <vector>
+
+namespace Catch {
+
+    class TestSpec;
+
+    struct ITestCase : IShared {
+        virtual void invoke () const = 0;
+    protected:
+        virtual ~ITestCase();
+    };
+
+    class TestCase;
+    struct IConfig;
+
+    struct ITestCaseRegistry {
+        virtual ~ITestCaseRegistry();
+        virtual std::vector<TestCase> const& getAllTests() const = 0;
+        virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
+    };
+
+    bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
+    std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
+    std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
+
+}
+
+namespace Catch {
+
+template<typename C>
+class MethodTestCase : public SharedImpl<ITestCase> {
+
+public:
+    MethodTestCase( void (C::*method)() ) : m_method( method ) {}
+
+    virtual void invoke() const {
+        C obj;
+        (obj.*m_method)();
+    }
+
+private:
+    virtual ~MethodTestCase() {}
+
+    void (C::*m_method)();
+};
+
+typedef void(*TestFunction)();
+
+struct NameAndDesc {
+    NameAndDesc( const char* _name = "", const char* _description= "" )
+    : name( _name ), description( _description )
+    {}
+
+    const char* name;
+    const char* description;
+};
+
+void registerTestCase
+    (   ITestCase* testCase,
+        char const* className,
+        NameAndDesc const& nameAndDesc,
+        SourceLineInfo const& lineInfo );
+
+struct AutoReg {
+
+    AutoReg
+        (   TestFunction function,
+            SourceLineInfo const& lineInfo,
+            NameAndDesc const& nameAndDesc );
+
+    template<typename C>
+    AutoReg
+        (   void (C::*method)(),
+            char const* className,
+            NameAndDesc const& nameAndDesc,
+            SourceLineInfo const& lineInfo ) {
+
+        registerTestCase
+            (   new MethodTestCase<C>( method ),
+                className,
+                nameAndDesc,
+                lineInfo );
+    }
+
+    ~AutoReg();
+
+private:
+    AutoReg( AutoReg const& );
+    void operator= ( AutoReg const& );
+};
+
+void registerTestCaseFunction
+    (   TestFunction function,
+        SourceLineInfo const& lineInfo,
+        NameAndDesc const& nameAndDesc );
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
+        static void TestName(); \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+        static void TestName()
+    #define INTERNAL_CATCH_TESTCASE( ... ) \
+        INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ \
+            struct TestName : ClassName{ \
+                void test(); \
+            }; \
+            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
+        } \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+        void TestName::test()
+    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
+        INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+#else
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \
+        static void TestName(); \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+        static void TestName()
+    #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
+        INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        namespace{ \
+            struct TestCaseName : ClassName{ \
+                void test(); \
+            }; \
+            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
+        } \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+        void TestCaseName::test()
+    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
+        INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc )
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \
+        CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+        Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); \
+        CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+#endif
+
+// #included from: internal/catch_capture.hpp
+#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
+
+// #included from: catch_result_builder.h
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
+
+// #included from: catch_result_type.h
+#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
+
+namespace Catch {
+
+    // ResultWas::OfType enum
+    struct ResultWas { enum OfType {
+        Unknown = -1,
+        Ok = 0,
+        Info = 1,
+        Warning = 2,
+
+        FailureBit = 0x10,
+
+        ExpressionFailed = FailureBit | 1,
+        ExplicitFailure = FailureBit | 2,
+
+        Exception = 0x100 | FailureBit,
+
+        ThrewException = Exception | 1,
+        DidntThrowException = Exception | 2,
+
+        FatalErrorCondition = 0x200 | FailureBit
+
+    }; };
+
+    inline bool isOk( ResultWas::OfType resultType ) {
+        return ( resultType & ResultWas::FailureBit ) == 0;
+    }
+    inline bool isJustInfo( int flags ) {
+        return flags == ResultWas::Info;
+    }
+
+    // ResultDisposition::Flags enum
+    struct ResultDisposition { enum Flags {
+        Normal = 0x01,
+
+        ContinueOnFailure = 0x02,   // Failures fail test, but execution continues
+        FalseTest = 0x04,           // Prefix expression with !
+        SuppressFail = 0x08         // Failures are reported but do not fail the test
+    }; };
+
+    inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
+        return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
+    }
+
+    inline bool shouldContinueOnFailure( int flags )    { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
+    inline bool isFalseTest( int flags )                { return ( flags & ResultDisposition::FalseTest ) != 0; }
+    inline bool shouldSuppressFailure( int flags )      { return ( flags & ResultDisposition::SuppressFail ) != 0; }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.h
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
+
+    struct DecomposedExpression
+    {
+        virtual ~DecomposedExpression() {}
+        virtual bool isBinaryExpression() const {
+            return false;
+        }
+        virtual void reconstructExpression( std::string& dest ) const = 0;
+
+        // Only simple binary comparisons can be decomposed.
+        // If more complex check is required then wrap sub-expressions in parentheses.
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
+        template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& );
+
+	private:
+		DecomposedExpression& operator = (DecomposedExpression const&);
+    };
+
+    struct AssertionInfo
+    {
+        AssertionInfo() {}
+        AssertionInfo(  std::string const& _macroName,
+                        SourceLineInfo const& _lineInfo,
+                        std::string const& _capturedExpression,
+                        ResultDisposition::Flags _resultDisposition );
+
+        std::string macroName;
+        SourceLineInfo lineInfo;
+        std::string capturedExpression;
+        ResultDisposition::Flags resultDisposition;
+    };
+
+    struct AssertionResultData
+    {
+        AssertionResultData() : decomposedExpression( CATCH_NULL )
+                              , resultType( ResultWas::Unknown )
+                              , negated( false )
+                              , parenthesized( false ) {}
+
+        void negate( bool parenthesize ) {
+            negated = !negated;
+            parenthesized = parenthesize;
+            if( resultType == ResultWas::Ok )
+                resultType = ResultWas::ExpressionFailed;
+            else if( resultType == ResultWas::ExpressionFailed )
+                resultType = ResultWas::Ok;
+        }
+
+        std::string const& reconstructExpression() const {
+            if( decomposedExpression != CATCH_NULL ) {
+                decomposedExpression->reconstructExpression( reconstructedExpression );
+                if( parenthesized ) {
+                    reconstructedExpression.insert( 0, 1, '(' );
+                    reconstructedExpression.append( 1, ')' );
+                }
+                if( negated ) {
+                    reconstructedExpression.insert( 0, 1, '!' );
+                }
+                decomposedExpression = CATCH_NULL;
+            }
+            return reconstructedExpression;
+        }
+
+        mutable DecomposedExpression const* decomposedExpression;
+        mutable std::string reconstructedExpression;
+        std::string message;
+        ResultWas::OfType resultType;
+        bool negated;
+        bool parenthesized;
+    };
+
+    class AssertionResult {
+    public:
+        AssertionResult();
+        AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
+        ~AssertionResult();
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+         AssertionResult( AssertionResult const& )              = default;
+         AssertionResult( AssertionResult && )                  = default;
+         AssertionResult& operator = ( AssertionResult const& ) = default;
+         AssertionResult& operator = ( AssertionResult && )     = default;
+#  endif
+
+        bool isOk() const;
+        bool succeeded() const;
+        ResultWas::OfType getResultType() const;
+        bool hasExpression() const;
+        bool hasMessage() const;
+        std::string getExpression() const;
+        std::string getExpressionInMacro() const;
+        bool hasExpandedExpression() const;
+        std::string getExpandedExpression() const;
+        std::string getMessage() const;
+        SourceLineInfo getSourceInfo() const;
+        std::string getTestMacroName() const;
+        void discardDecomposedExpression() const;
+        void expandDecomposedExpression() const;
+
+    protected:
+        AssertionInfo m_info;
+        AssertionResultData m_resultData;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_matchers.hpp
+#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+    namespace Impl {
+
+        template<typename ArgT> struct MatchAllOf;
+        template<typename ArgT> struct MatchAnyOf;
+        template<typename ArgT> struct MatchNotOf;
+
+        class MatcherUntypedBase {
+        public:
+            std::string toString() const {
+                if( m_cachedToString.empty() )
+                    m_cachedToString = describe();
+                return m_cachedToString;
+            }
+
+        protected:
+            virtual ~MatcherUntypedBase();
+            virtual std::string describe() const = 0;
+            mutable std::string m_cachedToString;
+        private:
+            MatcherUntypedBase& operator = ( MatcherUntypedBase const& );
+        };
+
+        template<typename ObjectT>
+        struct MatcherMethod {
+            virtual bool match( ObjectT const& arg ) const = 0;
+        };
+        template<typename PtrT>
+        struct MatcherMethod<PtrT*> {
+            virtual bool match( PtrT* arg ) const = 0;
+        };
+
+        template<typename ObjectT, typename ComparatorT = ObjectT>
+        struct MatcherBase : MatcherUntypedBase, MatcherMethod<ObjectT> {
+
+            MatchAllOf<ComparatorT> operator && ( MatcherBase const& other ) const;
+            MatchAnyOf<ComparatorT> operator || ( MatcherBase const& other ) const;
+            MatchNotOf<ComparatorT> operator ! () const;
+        };
+
+        template<typename ArgT>
+        struct MatchAllOf : MatcherBase<ArgT> {
+            virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if (!m_matchers[i]->match(arg))
+                        return false;
+                }
+                return true;
+            }
+            virtual std::string describe() const CATCH_OVERRIDE {
+                std::string description;
+                description.reserve( 4 + m_matchers.size()*32 );
+                description += "( ";
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if( i != 0 )
+                        description += " and ";
+                    description += m_matchers[i]->toString();
+                }
+                description += " )";
+                return description;
+            }
+
+            MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
+                m_matchers.push_back( &other );
+                return *this;
+            }
+
+            std::vector<MatcherBase<ArgT> const*> m_matchers;
+        };
+        template<typename ArgT>
+        struct MatchAnyOf : MatcherBase<ArgT> {
+
+            virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if (m_matchers[i]->match(arg))
+                        return true;
+                }
+                return false;
+            }
+            virtual std::string describe() const CATCH_OVERRIDE {
+                std::string description;
+                description.reserve( 4 + m_matchers.size()*32 );
+                description += "( ";
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if( i != 0 )
+                        description += " or ";
+                    description += m_matchers[i]->toString();
+                }
+                description += " )";
+                return description;
+            }
+
+            MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
+                m_matchers.push_back( &other );
+                return *this;
+            }
+
+            std::vector<MatcherBase<ArgT> const*> m_matchers;
+        };
+
+        template<typename ArgT>
+        struct MatchNotOf : MatcherBase<ArgT> {
+
+            MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}
+
+            virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
+                return !m_underlyingMatcher.match( arg );
+            }
+
+            virtual std::string describe() const CATCH_OVERRIDE {
+                return "not " + m_underlyingMatcher.toString();
+            }
+            MatcherBase<ArgT> const& m_underlyingMatcher;
+        };
+
+        template<typename ObjectT, typename ComparatorT>
+        MatchAllOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator && ( MatcherBase const& other ) const {
+            return MatchAllOf<ComparatorT>() && *this && other;
+        }
+        template<typename ObjectT, typename ComparatorT>
+        MatchAnyOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator || ( MatcherBase const& other ) const {
+            return MatchAnyOf<ComparatorT>() || *this || other;
+        }
+        template<typename ObjectT, typename ComparatorT>
+        MatchNotOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator ! () const {
+            return MatchNotOf<ComparatorT>( *this );
+        }
+
+    } // namespace Impl
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+    // - deprecated: prefer ||, && and !
+    template<typename T>
+    inline Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
+        return Impl::MatchNotOf<T>( underlyingMatcher );
+    }
+    template<typename T>
+    inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+        return Impl::MatchAllOf<T>() && m1 && m2;
+    }
+    template<typename T>
+    inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+        return Impl::MatchAllOf<T>() && m1 && m2 && m3;
+    }
+    template<typename T>
+    inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+        return Impl::MatchAnyOf<T>() || m1 || m2;
+    }
+    template<typename T>
+    inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+        return Impl::MatchAnyOf<T>() || m1 || m2 || m3;
+    }
+
+} // namespace Matchers
+
+using namespace Matchers;
+using Matchers::Impl::MatcherBase;
+
+} // namespace Catch
+
+namespace Catch {
+
+    struct TestFailureException{};
+
+    template<typename T> class ExpressionLhs;
+
+    struct CopyableStream {
+        CopyableStream() {}
+        CopyableStream( CopyableStream const& other ) {
+            oss << other.oss.str();
+        }
+        CopyableStream& operator=( CopyableStream const& other ) {
+            oss.str(std::string());
+            oss << other.oss.str();
+            return *this;
+        }
+        std::ostringstream oss;
+    };
+
+    class ResultBuilder : public DecomposedExpression {
+    public:
+        ResultBuilder(  char const* macroName,
+                        SourceLineInfo const& lineInfo,
+                        char const* capturedExpression,
+                        ResultDisposition::Flags resultDisposition,
+                        char const* secondArg = "" );
+        ~ResultBuilder();
+
+        template<typename T>
+        ExpressionLhs<T const&> operator <= ( T const& operand );
+        ExpressionLhs<bool> operator <= ( bool value );
+
+        template<typename T>
+        ResultBuilder& operator << ( T const& value ) {
+            m_stream.oss << value;
+            return *this;
+        }
+
+        ResultBuilder& setResultType( ResultWas::OfType result );
+        ResultBuilder& setResultType( bool result );
+
+        void endExpression( DecomposedExpression const& expr );
+
+        virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE;
+
+        AssertionResult build() const;
+        AssertionResult build( DecomposedExpression const& expr ) const;
+
+        void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
+        void captureResult( ResultWas::OfType resultType );
+        void captureExpression();
+        void captureExpectedException( std::string const& expectedMessage );
+        void captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher );
+        void handleResult( AssertionResult const& result );
+        void react();
+        bool shouldDebugBreak() const;
+        bool allowThrows() const;
+
+        template<typename ArgT, typename MatcherT>
+        void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString );
+
+        void setExceptionGuard();
+        void unsetExceptionGuard();
+
+    private:
+        AssertionInfo m_assertionInfo;
+        AssertionResultData m_data;
+        CopyableStream m_stream;
+
+        bool m_shouldDebugBreak;
+        bool m_shouldThrow;
+        bool m_guardException;
+    };
+
+} // namespace Catch
+
+// Include after due to circular dependency:
+// #included from: catch_expression_lhs.hpp
+#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
+
+// #included from: catch_evaluate.hpp
+#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
+#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
+#endif
+
+#include <cstddef>
+
+namespace Catch {
+namespace Internal {
+
+    enum Operator {
+        IsEqualTo,
+        IsNotEqualTo,
+        IsLessThan,
+        IsGreaterThan,
+        IsLessThanOrEqualTo,
+        IsGreaterThanOrEqualTo
+    };
+
+    template<Operator Op> struct OperatorTraits             { static const char* getName(){ return "*error*"; } };
+    template<> struct OperatorTraits<IsEqualTo>             { static const char* getName(){ return "=="; } };
+    template<> struct OperatorTraits<IsNotEqualTo>          { static const char* getName(){ return "!="; } };
+    template<> struct OperatorTraits<IsLessThan>            { static const char* getName(){ return "<"; } };
+    template<> struct OperatorTraits<IsGreaterThan>         { static const char* getName(){ return ">"; } };
+    template<> struct OperatorTraits<IsLessThanOrEqualTo>   { static const char* getName(){ return "<="; } };
+    template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
+
+    template<typename T>
+    inline T& opCast(T const& t) { return const_cast<T&>(t); }
+
+// nullptr_t support based on pull request #154 from Konstantin Baumann
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+    inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+    // So the compare overloads can be operator agnostic we convey the operator as a template
+    // enum, which is used to specialise an Evaluator for doing the comparison.
+    template<typename T1, typename T2, Operator Op>
+    class Evaluator{};
+
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs) {
+            return bool( opCast( lhs ) ==  opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsNotEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) != opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsLessThan> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) < opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsGreaterThan> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) > opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) >= opCast( rhs ) );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return bool( opCast( lhs ) <= opCast( rhs ) );
+        }
+    };
+
+    template<Operator Op, typename T1, typename T2>
+    bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
+        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
+    }
+
+    // This level of indirection allows us to specialise for integer types
+    // to avoid signed/ unsigned warnings
+
+    // "base" overload
+    template<Operator Op, typename T1, typename T2>
+    bool compare( T1 const& lhs, T2 const& rhs ) {
+        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
+    }
+
+    // unsigned X to int
+    template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+
+    // unsigned X to long
+    template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+
+    // int to unsigned X
+    template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+
+    // long to unsigned X
+    template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+
+    // pointer to long (when comparing against NULL)
+    template<Operator Op, typename T> bool compare( long lhs, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, long rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+    }
+
+    // pointer to int (when comparing against NULL)
+    template<Operator Op, typename T> bool compare( int lhs, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, int rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+    }
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+    // long long to unsigned X
+    template<Operator Op> bool compare( long long lhs, unsigned int rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long long lhs, unsigned long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long long lhs, unsigned long long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long long lhs, unsigned char rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+
+    // unsigned long long to X
+    template<Operator Op> bool compare( unsigned long long lhs, int rhs ) {
+        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( unsigned long long lhs, long rhs ) {
+        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( unsigned long long lhs, long long rhs ) {
+        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( unsigned long long lhs, char rhs ) {
+        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
+    }
+
+    // pointer to long long (when comparing against NULL)
+    template<Operator Op, typename T> bool compare( long long lhs, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, long long rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+    }
+#endif // CATCH_CONFIG_CPP11_LONG_LONG
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+    // pointer to nullptr_t (when comparing against nullptr)
+    template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( nullptr, rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, nullptr );
+    }
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+} // end of namespace Internal
+} // end of namespace Catch
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// #included from: catch_tostring.h
+#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
+
+#include <sstream>
+#include <iomanip>
+#include <limits>
+#include <vector>
+#include <cstddef>
+
+#ifdef __OBJC__
+// #included from: catch_objc_arc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
+
+#import <Foundation/Foundation.h>
+
+#ifdef __has_feature
+#define CATCH_ARC_ENABLED __has_feature(objc_arc)
+#else
+#define CATCH_ARC_ENABLED 0
+#endif
+
+void arcSafeRelease( NSObject* obj );
+id performOptionalSelector( id obj, SEL sel );
+
+#if !CATCH_ARC_ENABLED
+inline void arcSafeRelease( NSObject* obj ) {
+    [obj release];
+}
+inline id performOptionalSelector( id obj, SEL sel ) {
+    if( [obj respondsToSelector: sel] )
+        return [obj performSelector: sel];
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED
+#define CATCH_ARC_STRONG
+#else
+inline void arcSafeRelease( NSObject* ){}
+inline id performOptionalSelector( id obj, SEL sel ) {
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+#endif
+    if( [obj respondsToSelector: sel] )
+        return [obj performSelector: sel];
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
+#define CATCH_ARC_STRONG __strong
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+#include <tuple>
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_IS_ENUM
+#include <type_traits>
+#endif
+
+namespace Catch {
+
+// Why we're here.
+template<typename T>
+std::string toString( T const& value );
+
+// Built in overloads
+
+std::string toString( std::string const& value );
+std::string toString( std::wstring const& value );
+std::string toString( const char* const value );
+std::string toString( char* const value );
+std::string toString( const wchar_t* const value );
+std::string toString( wchar_t* const value );
+std::string toString( int value );
+std::string toString( unsigned long value );
+std::string toString( unsigned int value );
+std::string toString( const double value );
+std::string toString( const float value );
+std::string toString( bool value );
+std::string toString( char value );
+std::string toString( signed char value );
+std::string toString( unsigned char value );
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString( long long value );
+std::string toString( unsigned long long value );
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString( std::nullptr_t );
+#endif
+
+#ifdef __OBJC__
+    std::string toString( NSString const * const& nsstring );
+    std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
+    std::string toString( NSObject* const& nsObject );
+#endif
+
+namespace Detail {
+
+    extern const std::string unprintableString;
+
+ #if !defined(CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK)
+    struct BorgType {
+        template<typename T> BorgType( T const& );
+    };
+
+    struct TrueType { char sizer[1]; };
+    struct FalseType { char sizer[2]; };
+
+    TrueType& testStreamable( std::ostream& );
+    FalseType testStreamable( FalseType );
+
+    FalseType operator<<( std::ostream const&, BorgType const& );
+
+    template<typename T>
+    struct IsStreamInsertable {
+        static std::ostream &s;
+        static T  const&t;
+        enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
+    };
+#else
+    template<typename T>
+    class IsStreamInsertable {
+        template<typename SS, typename TT>
+        static auto test(int)
+        -> decltype( std::declval<SS&>() << std::declval<TT>(), std::true_type() );
+
+        template<typename, typename>
+        static auto test(...) -> std::false_type;
+
+    public:
+        static const bool value = decltype(test<std::ostream,const T&>(0))::value;
+    };
+#endif
+
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+    template<typename T,
+             bool IsEnum = std::is_enum<T>::value
+             >
+    struct EnumStringMaker
+    {
+        static std::string convert( T const& ) { return unprintableString; }
+    };
+
+    template<typename T>
+    struct EnumStringMaker<T,true>
+    {
+        static std::string convert( T const& v )
+        {
+            return ::Catch::toString(
+                static_cast<typename std::underlying_type<T>::type>(v)
+                );
+        }
+    };
+#endif
+    template<bool C>
+    struct StringMakerBase {
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+        template<typename T>
+        static std::string convert( T const& v )
+        {
+            return EnumStringMaker<T>::convert( v );
+        }
+#else
+        template<typename T>
+        static std::string convert( T const& ) { return unprintableString; }
+#endif
+    };
+
+    template<>
+    struct StringMakerBase<true> {
+        template<typename T>
+        static std::string convert( T const& _value ) {
+            std::ostringstream oss;
+            oss << _value;
+            return oss.str();
+        }
+    };
+
+    std::string rawMemoryToString( const void *object, std::size_t size );
+
+    template<typename T>
+    inline std::string rawMemoryToString( const T& object ) {
+      return rawMemoryToString( &object, sizeof(object) );
+    }
+
+} // end namespace Detail
+
+template<typename T>
+struct StringMaker :
+    Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
+
+template<typename T>
+struct StringMaker<T*> {
+    template<typename U>
+    static std::string convert( U* p ) {
+        if( !p )
+            return "NULL";
+        else
+            return Detail::rawMemoryToString( p );
+    }
+};
+
+template<typename R, typename C>
+struct StringMaker<R C::*> {
+    static std::string convert( R C::* p ) {
+        if( !p )
+            return "NULL";
+        else
+            return Detail::rawMemoryToString( p );
+    }
+};
+
+namespace Detail {
+    template<typename InputIterator>
+    std::string rangeToString( InputIterator first, InputIterator last );
+}
+
+//template<typename T, typename Allocator>
+//struct StringMaker<std::vector<T, Allocator> > {
+//    static std::string convert( std::vector<T,Allocator> const& v ) {
+//        return Detail::rangeToString( v.begin(), v.end() );
+//    }
+//};
+
+template<typename T, typename Allocator>
+std::string toString( std::vector<T,Allocator> const& v ) {
+    return Detail::rangeToString( v.begin(), v.end() );
+}
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+
+// toString for tuples
+namespace TupleDetail {
+  template<
+      typename Tuple,
+      std::size_t N = 0,
+      bool = (N < std::tuple_size<Tuple>::value)
+      >
+  struct ElementPrinter {
+      static void print( const Tuple& tuple, std::ostream& os )
+      {
+          os << ( N ? ", " : " " )
+             << Catch::toString(std::get<N>(tuple));
+          ElementPrinter<Tuple,N+1>::print(tuple,os);
+      }
+  };
+
+  template<
+      typename Tuple,
+      std::size_t N
+      >
+  struct ElementPrinter<Tuple,N,false> {
+      static void print( const Tuple&, std::ostream& ) {}
+  };
+
+}
+
+template<typename ...Types>
+struct StringMaker<std::tuple<Types...>> {
+
+    static std::string convert( const std::tuple<Types...>& tuple )
+    {
+        std::ostringstream os;
+        os << '{';
+        TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os );
+        os << " }";
+        return os.str();
+    }
+};
+#endif // CATCH_CONFIG_CPP11_TUPLE
+
+namespace Detail {
+    template<typename T>
+    std::string makeString( T const& value ) {
+        return StringMaker<T>::convert( value );
+    }
+} // end namespace Detail
+
+/// \brief converts any type to a string
+///
+/// The default template forwards on to ostringstream - except when an
+/// ostringstream overload does not exist - in which case it attempts to detect
+/// that and writes {?}.
+/// Overload (not specialise) this template for custom typs that you don't want
+/// to provide an ostream overload for.
+template<typename T>
+std::string toString( T const& value ) {
+    return StringMaker<T>::convert( value );
+}
+
+    namespace Detail {
+    template<typename InputIterator>
+    std::string rangeToString( InputIterator first, InputIterator last ) {
+        std::ostringstream oss;
+        oss << "{ ";
+        if( first != last ) {
+            oss << Catch::toString( *first );
+            for( ++first ; first != last ; ++first )
+                oss << ", " << Catch::toString( *first );
+        }
+        oss << " }";
+        return oss.str();
+    }
+}
+
+} // end namespace Catch
+
+namespace Catch {
+
+template<typename LhsT, Internal::Operator Op, typename RhsT>
+class BinaryExpression;
+
+template<typename ArgT, typename MatcherT>
+class MatchExpression;
+
+// Wraps the LHS of an expression and overloads comparison operators
+// for also capturing those and RHS (if any)
+template<typename T>
+class ExpressionLhs : public DecomposedExpression {
+public:
+    ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {}
+
+    ExpressionLhs& operator = ( const ExpressionLhs& );
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsEqualTo, RhsT const&>
+    operator == ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&>
+    operator != ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsNotEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsLessThan, RhsT const&>
+    operator < ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsLessThan>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsGreaterThan, RhsT const&>
+    operator > ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsGreaterThan>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&>
+    operator <= ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&>
+    operator >= ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
+    }
+
+    BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) {
+        return captureExpression<Internal::IsEqualTo>( rhs );
+    }
+
+    BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) {
+        return captureExpression<Internal::IsNotEqualTo>( rhs );
+    }
+
+    void endExpression() {
+        m_truthy = m_lhs ? true : false;
+        m_rb
+            .setResultType( m_truthy )
+            .endExpression( *this );
+    }
+
+    virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+        dest = Catch::toString( m_truthy );
+    }
+
+private:
+    template<Internal::Operator Op, typename RhsT>
+    BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const {
+        return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs );
+    }
+
+    template<Internal::Operator Op>
+    BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const {
+        return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs );
+    }
+
+private:
+    ResultBuilder& m_rb;
+    T m_lhs;
+    bool m_truthy;
+};
+
+template<typename LhsT, Internal::Operator Op, typename RhsT>
+class BinaryExpression : public DecomposedExpression {
+public:
+    BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs )
+        : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {}
+
+    BinaryExpression& operator = ( BinaryExpression& );
+
+    void endExpression() const {
+        m_rb
+            .setResultType( Internal::compare<Op>( m_lhs, m_rhs ) )
+            .endExpression( *this );
+    }
+
+    virtual bool isBinaryExpression() const CATCH_OVERRIDE {
+        return true;
+    }
+
+    virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+        std::string lhs = Catch::toString( m_lhs );
+        std::string rhs = Catch::toString( m_rhs );
+        char delim = lhs.size() + rhs.size() < 40 &&
+                     lhs.find('\n') == std::string::npos &&
+                     rhs.find('\n') == std::string::npos ? ' ' : '\n';
+        dest.reserve( 7 + lhs.size() + rhs.size() );
+                   // 2 for spaces around operator
+                   // 2 for operator
+                   // 2 for parentheses (conditionally added later)
+                   // 1 for negation (conditionally added later)
+        dest = lhs;
+        dest += delim;
+        dest += Internal::OperatorTraits<Op>::getName();
+        dest += delim;
+        dest += rhs;
+    }
+
+private:
+    ResultBuilder& m_rb;
+    LhsT m_lhs;
+    RhsT m_rhs;
+};
+
+template<typename ArgT, typename MatcherT>
+class MatchExpression : public DecomposedExpression {
+public:
+    MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString )
+        : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {}
+
+    virtual bool isBinaryExpression() const CATCH_OVERRIDE {
+        return true;
+    }
+
+    virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
+        std::string matcherAsString = m_matcher.toString();
+        dest = Catch::toString( m_arg );
+        dest += ' ';
+        if( matcherAsString == Detail::unprintableString )
+            dest += m_matcherString;
+        else
+            dest += matcherAsString;
+    }
+
+private:
+    ArgT m_arg;
+    MatcherT m_matcher;
+    char const* m_matcherString;
+};
+
+} // end namespace Catch
+
+
+namespace Catch {
+
+    template<typename T>
+    inline ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
+        return ExpressionLhs<T const&>( *this, operand );
+    }
+
+    inline ExpressionLhs<bool> ResultBuilder::operator <= ( bool value ) {
+        return ExpressionLhs<bool>( *this, value );
+    }
+
+    template<typename ArgT, typename MatcherT>
+    inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
+                                             char const* matcherString ) {
+        MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString );
+        setResultType( matcher.match( arg ) );
+        endExpression( expr );
+    }
+
+} // namespace Catch
+
+// #included from: catch_message.h
+#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct MessageInfo {
+        MessageInfo(    std::string const& _macroName,
+                        SourceLineInfo const& _lineInfo,
+                        ResultWas::OfType _type );
+
+        std::string macroName;
+        SourceLineInfo lineInfo;
+        ResultWas::OfType type;
+        std::string message;
+        unsigned int sequence;
+
+        bool operator == ( MessageInfo const& other ) const {
+            return sequence == other.sequence;
+        }
+        bool operator < ( MessageInfo const& other ) const {
+            return sequence < other.sequence;
+        }
+    private:
+        static unsigned int globalCount;
+    };
+
+    struct MessageBuilder {
+        MessageBuilder( std::string const& macroName,
+                        SourceLineInfo const& lineInfo,
+                        ResultWas::OfType type )
+        : m_info( macroName, lineInfo, type )
+        {}
+
+        template<typename T>
+        MessageBuilder& operator << ( T const& value ) {
+            m_stream << value;
+            return *this;
+        }
+
+        MessageInfo m_info;
+        std::ostringstream m_stream;
+    };
+
+    class ScopedMessage {
+    public:
+        ScopedMessage( MessageBuilder const& builder );
+        ScopedMessage( ScopedMessage const& other );
+        ~ScopedMessage();
+
+        MessageInfo m_info;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_capture.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    class TestCase;
+    class AssertionResult;
+    struct AssertionInfo;
+    struct SectionInfo;
+    struct SectionEndInfo;
+    struct MessageInfo;
+    class ScopedMessageBuilder;
+    struct Counts;
+
+    struct IResultCapture {
+
+        virtual ~IResultCapture();
+
+        virtual void assertionEnded( AssertionResult const& result ) = 0;
+        virtual bool sectionStarted(    SectionInfo const& sectionInfo,
+                                        Counts& assertions ) = 0;
+        virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
+        virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
+        virtual void pushScopedMessage( MessageInfo const& message ) = 0;
+        virtual void popScopedMessage( MessageInfo const& message ) = 0;
+
+        virtual std::string getCurrentTestName() const = 0;
+        virtual const AssertionResult* getLastResult() const = 0;
+
+        virtual void exceptionEarlyReported() = 0;
+
+        virtual void handleFatalErrorCondition( std::string const& message ) = 0;
+    };
+
+    IResultCapture& getResultCapture();
+}
+
+// #included from: catch_debugger.h
+#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
+
+// #included from: catch_platform.h
+#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
+
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#  define CATCH_PLATFORM_MAC
+#elif  defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+#  define CATCH_PLATFORM_IPHONE
+#elif defined(linux) || defined(__linux) || defined(__linux__)
+#  define CATCH_PLATFORM_LINUX
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#  define CATCH_PLATFORM_WINDOWS
+#  if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
+#    define CATCH_DEFINES_NOMINMAX
+#  endif
+#  if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
+#    define CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+#  endif
+#endif
+
+#include <string>
+
+namespace Catch{
+
+    bool isDebuggerActive();
+    void writeToDebugConsole( std::string const& text );
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+    // The following code snippet based on:
+    // http://cocoawithlove.com/2008/03/break-into-debugger.html
+    #if defined(__ppc64__) || defined(__ppc__)
+        #define CATCH_TRAP() \
+                __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
+                : : : "memory","r0","r3","r4" )
+    #else
+        #define CATCH_TRAP() __asm__("int $3\n" : : )
+    #endif
+
+#elif defined(CATCH_PLATFORM_LINUX)
+    // If we can use inline assembler, do it because this allows us to break
+    // directly at the location of the failing check instead of breaking inside
+    // raise() called from it, i.e. one stack frame below.
+    #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
+        #define CATCH_TRAP() asm volatile ("int $3")
+    #else // Fall back to the generic way.
+        #include <signal.h>
+
+        #define CATCH_TRAP() raise(SIGTRAP)
+    #endif
+#elif defined(_MSC_VER)
+    #define CATCH_TRAP() __debugbreak()
+#elif defined(__MINGW32__)
+    extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+    #define CATCH_TRAP() DebugBreak()
+#endif
+
+#ifdef CATCH_TRAP
+    #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
+#else
+    #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
+#endif
+
+// #included from: catch_interfaces_runner.h
+#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
+
+namespace Catch {
+    class TestCase;
+
+    struct IRunner {
+        virtual ~IRunner();
+        virtual bool aborting() const = 0;
+    };
+}
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+///////////////////////////////////////////////////////////////////////////////
+// We can speedup compilation significantly by breaking into debugger lower in
+// the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER
+// macro in each assertion
+#define INTERNAL_CATCH_REACT( resultBuilder ) \
+    resultBuilder.react();
+
+///////////////////////////////////////////////////////////////////////////////
+// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
+// macros.
+// This can potentially cause false negative, if the test code catches
+// the exception before it propagates back up to the runner.
+#define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        __catchResult.setExceptionGuard(); \
+        CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+        ( __catchResult <= expr ).endExpression(); \
+        CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+        __catchResult.unsetExceptionGuard(); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
+
+#define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
+        __catchResult.setExceptionGuard(); \
+        __catchResult.captureMatch( arg, matcher, #matcher ); \
+        __catchResult.unsetExceptionGuard(); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+#else
+///////////////////////////////////////////////////////////////////////////////
+// In the event of a failure works out if the debugger needs to be invoked
+// and/or an exception thrown and takes appropriate action.
+// This needs to be done as a macro so the debugger will stop in the user
+// source code rather than in Catch library code
+#define INTERNAL_CATCH_REACT( resultBuilder ) \
+    if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
+    resultBuilder.react();
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        try { \
+            CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+            ( __catchResult <= expr ).endExpression(); \
+            CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+        } \
+        catch( ... ) { \
+            __catchResult.useActiveException( resultDisposition ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+    // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \
+    INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
+    if( Catch::getResultCapture().getLastResult()->succeeded() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \
+    INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
+    if( !Catch::getResultCapture().getLastResult()->succeeded() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        try { \
+            static_cast<void>(expr); \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        } \
+        catch( ... ) { \
+            __catchResult.useActiveException( resultDisposition ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
+        if( __catchResult.allowThrows() ) \
+            try { \
+                static_cast<void>(expr); \
+                __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+            } \
+            catch( ... ) { \
+                __catchResult.captureExpectedException( matcher ); \
+            } \
+        else \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \
+        if( __catchResult.allowThrows() ) \
+            try { \
+                static_cast<void>(expr); \
+                __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+            } \
+            catch( exceptionType ) { \
+                __catchResult.captureResult( Catch::ResultWas::Ok ); \
+            } \
+            catch( ... ) { \
+                __catchResult.useActiveException( resultDisposition ); \
+            } \
+        else \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
+        do { \
+            Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
+            __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
+            __catchResult.captureResult( messageType ); \
+            INTERNAL_CATCH_REACT( __catchResult ) \
+        } while( Catch::alwaysFalse() )
+#else
+    #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \
+        do { \
+            Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
+            __catchResult << log + ::Catch::StreamEndStop(); \
+            __catchResult.captureResult( messageType ); \
+            INTERNAL_CATCH_REACT( __catchResult ) \
+        } while( Catch::alwaysFalse() )
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_INFO( macroName, log ) \
+    Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
+        try { \
+            __catchResult.captureMatch( arg, matcher, #matcher ); \
+        } catch( ... ) { \
+            __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+// #included from: internal/catch_section.h
+#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
+
+// #included from: catch_section_info.h
+#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
+
+// #included from: catch_totals.hpp
+#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
+
+#include <cstddef>
+
+namespace Catch {
+
+    struct Counts {
+        Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {}
+
+        Counts operator - ( Counts const& other ) const {
+            Counts diff;
+            diff.passed = passed - other.passed;
+            diff.failed = failed - other.failed;
+            diff.failedButOk = failedButOk - other.failedButOk;
+            return diff;
+        }
+        Counts& operator += ( Counts const& other ) {
+            passed += other.passed;
+            failed += other.failed;
+            failedButOk += other.failedButOk;
+            return *this;
+        }
+
+        std::size_t total() const {
+            return passed + failed + failedButOk;
+        }
+        bool allPassed() const {
+            return failed == 0 && failedButOk == 0;
+        }
+        bool allOk() const {
+            return failed == 0;
+        }
+
+        std::size_t passed;
+        std::size_t failed;
+        std::size_t failedButOk;
+    };
+
+    struct Totals {
+
+        Totals operator - ( Totals const& other ) const {
+            Totals diff;
+            diff.assertions = assertions - other.assertions;
+            diff.testCases = testCases - other.testCases;
+            return diff;
+        }
+
+        Totals delta( Totals const& prevTotals ) const {
+            Totals diff = *this - prevTotals;
+            if( diff.assertions.failed > 0 )
+                ++diff.testCases.failed;
+            else if( diff.assertions.failedButOk > 0 )
+                ++diff.testCases.failedButOk;
+            else
+                ++diff.testCases.passed;
+            return diff;
+        }
+
+        Totals& operator += ( Totals const& other ) {
+            assertions += other.assertions;
+            testCases += other.testCases;
+            return *this;
+        }
+
+        Counts assertions;
+        Counts testCases;
+    };
+}
+
+#include <string>
+
+namespace Catch {
+
+    struct SectionInfo {
+        SectionInfo
+            (   SourceLineInfo const& _lineInfo,
+                std::string const& _name,
+                std::string const& _description = std::string() );
+
+        std::string name;
+        std::string description;
+        SourceLineInfo lineInfo;
+    };
+
+    struct SectionEndInfo {
+        SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds )
+        : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
+        {}
+
+        SectionInfo sectionInfo;
+        Counts prevAssertions;
+        double durationInSeconds;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_timer.h
+#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
+
+#ifdef _MSC_VER
+
+namespace Catch {
+    typedef unsigned long long UInt64;
+}
+#else
+#include <stdint.h>
+namespace Catch {
+    typedef uint64_t UInt64;
+}
+#endif
+
+namespace Catch {
+    class Timer {
+    public:
+        Timer() : m_ticks( 0 ) {}
+        void start();
+        unsigned int getElapsedMicroseconds() const;
+        unsigned int getElapsedMilliseconds() const;
+        double getElapsedSeconds() const;
+
+    private:
+        UInt64 m_ticks;
+    };
+
+} // namespace Catch
+
+#include <string>
+
+namespace Catch {
+
+    class Section : NonCopyable {
+    public:
+        Section( SectionInfo const& info );
+        ~Section();
+
+        // This indicates whether the section should be executed or not
+        operator bool() const;
+
+    private:
+        SectionInfo m_info;
+
+        std::string m_name;
+        Counts m_assertions;
+        bool m_sectionIncluded;
+        Timer m_timer;
+    };
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define INTERNAL_CATCH_SECTION( ... ) \
+        if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
+#else
+    #define INTERNAL_CATCH_SECTION( name, desc ) \
+        if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) )
+#endif
+
+// #included from: internal/catch_generators.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <stdlib.h>
+
+namespace Catch {
+
+template<typename T>
+struct IGenerator {
+    virtual ~IGenerator() {}
+    virtual T getValue( std::size_t index ) const = 0;
+    virtual std::size_t size () const = 0;
+};
+
+template<typename T>
+class BetweenGenerator : public IGenerator<T> {
+public:
+    BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
+
+    virtual T getValue( std::size_t index ) const {
+        return m_from+static_cast<int>( index );
+    }
+
+    virtual std::size_t size() const {
+        return static_cast<std::size_t>( 1+m_to-m_from );
+    }
+
+private:
+
+    T m_from;
+    T m_to;
+};
+
+template<typename T>
+class ValuesGenerator : public IGenerator<T> {
+public:
+    ValuesGenerator(){}
+
+    void add( T value ) {
+        m_values.push_back( value );
+    }
+
+    virtual T getValue( std::size_t index ) const {
+        return m_values[index];
+    }
+
+    virtual std::size_t size() const {
+        return m_values.size();
+    }
+
+private:
+    std::vector<T> m_values;
+};
+
+template<typename T>
+class CompositeGenerator {
+public:
+    CompositeGenerator() : m_totalSize( 0 ) {}
+
+    // *** Move semantics, similar to auto_ptr ***
+    CompositeGenerator( CompositeGenerator& other )
+    :   m_fileInfo( other.m_fileInfo ),
+        m_totalSize( 0 )
+    {
+        move( other );
+    }
+
+    CompositeGenerator& setFileInfo( const char* fileInfo ) {
+        m_fileInfo = fileInfo;
+        return *this;
+    }
+
+    ~CompositeGenerator() {
+        deleteAll( m_composed );
+    }
+
+    operator T () const {
+        size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
+
+        typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
+        typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
+        for( size_t index = 0; it != itEnd; ++it )
+        {
+            const IGenerator<T>* generator = *it;
+            if( overallIndex >= index && overallIndex < index + generator->size() )
+            {
+                return generator->getValue( overallIndex-index );
+            }
+            index += generator->size();
+        }
+        CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
+        return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
+    }
+
+    void add( const IGenerator<T>* generator ) {
+        m_totalSize += generator->size();
+        m_composed.push_back( generator );
+    }
+
+    CompositeGenerator& then( CompositeGenerator& other ) {
+        move( other );
+        return *this;
+    }
+
+    CompositeGenerator& then( T value ) {
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( value );
+        add( valuesGen );
+        return *this;
+    }
+
+private:
+
+    void move( CompositeGenerator& other ) {
+        m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() );
+        m_totalSize += other.m_totalSize;
+        other.m_composed.clear();
+    }
+
+    std::vector<const IGenerator<T>*> m_composed;
+    std::string m_fileInfo;
+    size_t m_totalSize;
+};
+
+namespace Generators
+{
+    template<typename T>
+    CompositeGenerator<T> between( T from, T to ) {
+        CompositeGenerator<T> generators;
+        generators.add( new BetweenGenerator<T>( from, to ) );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2 ) {
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2, T val3 ){
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        valuesGen->add( val3 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        valuesGen->add( val3 );
+        valuesGen->add( val4 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+} // end namespace Generators
+
+using namespace Generators;
+
+} // end namespace Catch
+
+#define INTERNAL_CATCH_LINESTR2( line ) #line
+#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
+
+#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
+
+// #included from: internal/catch_interfaces_exception.h
+#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
+
+#include <string>
+#include <vector>
+
+// #included from: catch_interfaces_registry_hub.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    class TestCase;
+    struct ITestCaseRegistry;
+    struct IExceptionTranslatorRegistry;
+    struct IExceptionTranslator;
+    struct IReporterRegistry;
+    struct IReporterFactory;
+    struct ITagAliasRegistry;
+
+    struct IRegistryHub {
+        virtual ~IRegistryHub();
+
+        virtual IReporterRegistry const& getReporterRegistry() const = 0;
+        virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
+        virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
+
+        virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
+    };
+
+    struct IMutableRegistryHub {
+        virtual ~IMutableRegistryHub();
+        virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) = 0;
+        virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0;
+        virtual void registerTest( TestCase const& testInfo ) = 0;
+        virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
+        virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
+    };
+
+    IRegistryHub& getRegistryHub();
+    IMutableRegistryHub& getMutableRegistryHub();
+    void cleanUp();
+    std::string translateActiveException();
+
+}
+
+namespace Catch {
+
+    typedef std::string(*exceptionTranslateFunction)();
+
+    struct IExceptionTranslator;
+    typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
+
+    struct IExceptionTranslator {
+        virtual ~IExceptionTranslator();
+        virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
+    };
+
+    struct IExceptionTranslatorRegistry {
+        virtual ~IExceptionTranslatorRegistry();
+
+        virtual std::string translateActiveException() const = 0;
+    };
+
+    class ExceptionTranslatorRegistrar {
+        template<typename T>
+        class ExceptionTranslator : public IExceptionTranslator {
+        public:
+
+            ExceptionTranslator( std::string(*translateFunction)( T& ) )
+            : m_translateFunction( translateFunction )
+            {}
+
+            virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE {
+                try {
+                    if( it == itEnd )
+                        throw;
+                    else
+                        return (*it)->translate( it+1, itEnd );
+                }
+                catch( T& ex ) {
+                    return m_translateFunction( ex );
+                }
+            }
+
+        protected:
+            std::string(*m_translateFunction)( T& );
+        };
+
+    public:
+        template<typename T>
+        ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
+            getMutableRegistryHub().registerTranslator
+                ( new ExceptionTranslator<T>( translateFunction ) );
+        }
+    };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
+    static std::string translatorName( signature ); \
+    namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\
+    static std::string translatorName( signature )
+
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
+
+// #included from: internal/catch_approx.hpp
+#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
+
+#include <cmath>
+#include <limits>
+
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+#include <type_traits>
+#endif
+
+namespace Catch {
+namespace Detail {
+
+    class Approx {
+    public:
+        explicit Approx ( double value )
+        :   m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
+            m_margin( 0.0 ),
+            m_scale( 1.0 ),
+            m_value( value )
+        {}
+
+        Approx( Approx const& other )
+        :   m_epsilon( other.m_epsilon ),
+            m_margin( other.m_margin ),
+            m_scale( other.m_scale ),
+            m_value( other.m_value )
+        {}
+
+        static Approx custom() {
+            return Approx( 0 );
+        }
+
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx operator()( T value ) {
+            Approx approx( static_cast<double>(value) );
+            approx.epsilon( m_epsilon );
+            approx.margin( m_margin );
+            approx.scale( m_scale );
+            return approx;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        explicit Approx( T value ): Approx(static_cast<double>(value))
+        {}
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator == ( const T& lhs, Approx const& rhs ) {
+            // Thanks to Richard Harris for his help refining this formula
+            auto lhs_v = double(lhs);
+            bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value)));
+            if (relativeOK) {
+                return true;
+            }
+            return std::fabs(lhs_v - rhs.m_value) < rhs.m_margin;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator == ( Approx const& lhs, const T& rhs ) {
+            return operator==( rhs, lhs );
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator != ( T lhs, Approx const& rhs ) {
+            return !operator==( lhs, rhs );
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator != ( Approx const& lhs, T rhs ) {
+            return !operator==( rhs, lhs );
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator <= ( T lhs, Approx const& rhs ) {
+            return double(lhs) < rhs.m_value || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator <= ( Approx const& lhs, T rhs ) {
+            return lhs.m_value < double(rhs) || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator >= ( T lhs, Approx const& rhs ) {
+            return double(lhs) > rhs.m_value || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        friend bool operator >= ( Approx const& lhs, T rhs ) {
+            return lhs.m_value > double(rhs) || lhs == rhs;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx& epsilon( T newEpsilon ) {
+            m_epsilon = double(newEpsilon);
+            return *this;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx& margin( T newMargin ) {
+            m_margin = double(newMargin);
+            return *this;
+        }
+
+        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+        Approx& scale( T newScale ) {
+            m_scale = double(newScale);
+            return *this;
+        }
+
+#else
+
+        Approx operator()( double value ) {
+            Approx approx( value );
+            approx.epsilon( m_epsilon );
+            approx.margin( m_margin );
+            approx.scale( m_scale );
+            return approx;
+        }
+
+        friend bool operator == ( double lhs, Approx const& rhs ) {
+            // Thanks to Richard Harris for his help refining this formula
+            bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) );
+            if (relativeOK) {
+                return true;
+            }
+            return std::fabs(lhs - rhs.m_value) < rhs.m_margin;
+        }
+
+        friend bool operator == ( Approx const& lhs, double rhs ) {
+            return operator==( rhs, lhs );
+        }
+
+        friend bool operator != ( double lhs, Approx const& rhs ) {
+            return !operator==( lhs, rhs );
+        }
+
+        friend bool operator != ( Approx const& lhs, double rhs ) {
+            return !operator==( rhs, lhs );
+        }
+
+        friend bool operator <= ( double lhs, Approx const& rhs ) {
+            return lhs < rhs.m_value || lhs == rhs;
+        }
+
+        friend bool operator <= ( Approx const& lhs, double rhs ) {
+            return lhs.m_value < rhs || lhs == rhs;
+        }
+
+        friend bool operator >= ( double lhs, Approx const& rhs ) {
+            return lhs > rhs.m_value || lhs == rhs;
+        }
+
+        friend bool operator >= ( Approx const& lhs, double rhs ) {
+            return lhs.m_value > rhs || lhs == rhs;
+        }
+
+        Approx& epsilon( double newEpsilon ) {
+            m_epsilon = newEpsilon;
+            return *this;
+        }
+
+        Approx& margin( double newMargin ) {
+            m_margin = newMargin;
+            return *this;
+        }
+
+        Approx& scale( double newScale ) {
+            m_scale = newScale;
+            return *this;
+        }
+#endif
+
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << "Approx( " << Catch::toString( m_value ) << " )";
+            return oss.str();
+        }
+
+    private:
+        double m_epsilon;
+        double m_margin;
+        double m_scale;
+        double m_value;
+    };
+}
+
+template<>
+inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
+    return value.toString();
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_matchers_string.h
+#define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+
+    namespace StdString {
+
+        struct CasedString
+        {
+            CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity );
+            std::string adjustString( std::string const& str ) const;
+            std::string caseSensitivitySuffix() const;
+
+            CaseSensitive::Choice m_caseSensitivity;
+            std::string m_str;
+        };
+
+        struct StringMatcherBase : MatcherBase<std::string> {
+            StringMatcherBase( std::string const& operation, CasedString const& comparator );
+            virtual std::string describe() const CATCH_OVERRIDE;
+
+            CasedString m_comparator;
+            std::string m_operation;
+        };
+
+        struct EqualsMatcher : StringMatcherBase {
+            EqualsMatcher( CasedString const& comparator );
+            virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+        };
+        struct ContainsMatcher : StringMatcherBase {
+            ContainsMatcher( CasedString const& comparator );
+            virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+        };
+        struct StartsWithMatcher : StringMatcherBase {
+            StartsWithMatcher( CasedString const& comparator );
+            virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+        };
+        struct EndsWithMatcher : StringMatcherBase {
+            EndsWithMatcher( CasedString const& comparator );
+            virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
+        };
+
+    } // namespace StdString
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+
+    StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+    StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+    StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+    StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
+
+} // namespace Matchers
+} // namespace Catch
+
+// #included from: internal/catch_matchers_vector.h
+#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+
+    namespace Vector {
+
+        template<typename T>
+        struct ContainsElementMatcher : MatcherBase<std::vector<T>, T> {
+
+            ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
+
+            bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
+                return std::find(v.begin(), v.end(), m_comparator) != v.end();
+            }
+
+            virtual std::string describe() const CATCH_OVERRIDE {
+                return "Contains: " + Catch::toString( m_comparator );
+            }
+
+            T const& m_comparator;
+        };
+
+        template<typename T>
+        struct ContainsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
+
+            ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+
+            bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
+                // !TBD: see note in EqualsMatcher
+                if (m_comparator.size() > v.size())
+                    return false;
+                for (size_t i = 0; i < m_comparator.size(); ++i)
+                    if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end())
+                        return false;
+                return true;
+            }
+            virtual std::string describe() const CATCH_OVERRIDE {
+                return "Contains: " + Catch::toString( m_comparator );
+            }
+
+            std::vector<T> const& m_comparator;
+        };
+
+        template<typename T>
+        struct EqualsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
+
+            EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
+
+            bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
+                // !TBD: This currently works if all elements can be compared using !=
+                // - a more general approach would be via a compare template that defaults
+                // to using !=. but could be specialised for, e.g. std::vector<T> etc
+                // - then just call that directly
+                if (m_comparator.size() != v.size())
+                    return false;
+                for (size_t i = 0; i < v.size(); ++i)
+                    if (m_comparator[i] != v[i])
+                        return false;
+                return true;
+            }
+            virtual std::string describe() const CATCH_OVERRIDE {
+                return "Equals: " + Catch::toString( m_comparator );
+            }
+            std::vector<T> const& m_comparator;
+        };
+
+    } // namespace Vector
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+
+    template<typename T>
+    Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
+        return Vector::ContainsMatcher<T>( comparator );
+    }
+
+    template<typename T>
+    Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) {
+        return Vector::ContainsElementMatcher<T>( comparator );
+    }
+
+    template<typename T>
+    Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
+        return Vector::EqualsMatcher<T>( comparator );
+    }
+
+} // namespace Matchers
+} // namespace Catch
+
+// #included from: internal/catch_interfaces_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+// #included from: catch_tag_alias.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct TagAlias {
+        TagAlias( std::string const& _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
+
+        std::string tag;
+        SourceLineInfo lineInfo;
+    };
+
+    struct RegistrarForTagAliases {
+        RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
+    };
+
+} // end namespace Catch
+
+#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); }
+// #included from: catch_option.hpp
+#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
+
+namespace Catch {
+
+    // An optional type
+    template<typename T>
+    class Option {
+    public:
+        Option() : nullableValue( CATCH_NULL ) {}
+        Option( T const& _value )
+        : nullableValue( new( storage ) T( _value ) )
+        {}
+        Option( Option const& _other )
+        : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL )
+        {}
+
+        ~Option() {
+            reset();
+        }
+
+        Option& operator= ( Option const& _other ) {
+            if( &_other != this ) {
+                reset();
+                if( _other )
+                    nullableValue = new( storage ) T( *_other );
+            }
+            return *this;
+        }
+        Option& operator = ( T const& _value ) {
+            reset();
+            nullableValue = new( storage ) T( _value );
+            return *this;
+        }
+
+        void reset() {
+            if( nullableValue )
+                nullableValue->~T();
+            nullableValue = CATCH_NULL;
+        }
+
+        T& operator*() { return *nullableValue; }
+        T const& operator*() const { return *nullableValue; }
+        T* operator->() { return nullableValue; }
+        const T* operator->() const { return nullableValue; }
+
+        T valueOr( T const& defaultValue ) const {
+            return nullableValue ? *nullableValue : defaultValue;
+        }
+
+        bool some() const { return nullableValue != CATCH_NULL; }
+        bool none() const { return nullableValue == CATCH_NULL; }
+
+        bool operator !() const { return nullableValue == CATCH_NULL; }
+        operator SafeBool::type() const {
+            return SafeBool::makeSafe( some() );
+        }
+
+    private:
+        T *nullableValue;
+        union {
+            char storage[sizeof(T)];
+
+            // These are here to force alignment for the storage
+            long double dummy1;
+            void (*dummy2)();
+            long double dummy3;
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+            long long dummy4;
+#endif
+        };
+    };
+
+} // end namespace Catch
+
+namespace Catch {
+
+    struct ITagAliasRegistry {
+        virtual ~ITagAliasRegistry();
+        virtual Option<TagAlias> find( std::string const& alias ) const = 0;
+        virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
+
+        static ITagAliasRegistry const& get();
+    };
+
+} // end namespace Catch
+
+// These files are included here so the single_include script doesn't put them
+// in the conditionally compiled sections
+// #included from: internal/catch_test_case_info.h
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
+
+#include <string>
+#include <set>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    struct ITestCase;
+
+    struct TestCaseInfo {
+        enum SpecialProperties{
+            None = 0,
+            IsHidden = 1 << 1,
+            ShouldFail = 1 << 2,
+            MayFail = 1 << 3,
+            Throws = 1 << 4,
+            NonPortable = 1 << 5
+        };
+
+        TestCaseInfo(   std::string const& _name,
+                        std::string const& _className,
+                        std::string const& _description,
+                        std::set<std::string> const& _tags,
+                        SourceLineInfo const& _lineInfo );
+
+        TestCaseInfo( TestCaseInfo const& other );
+
+        friend void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags );
+
+        bool isHidden() const;
+        bool throws() const;
+        bool okToFail() const;
+        bool expectedToFail() const;
+
+        std::string name;
+        std::string className;
+        std::string description;
+        std::set<std::string> tags;
+        std::set<std::string> lcaseTags;
+        std::string tagsAsString;
+        SourceLineInfo lineInfo;
+        SpecialProperties properties;
+    };
+
+    class TestCase : public TestCaseInfo {
+    public:
+
+        TestCase( ITestCase* testCase, TestCaseInfo const& info );
+        TestCase( TestCase const& other );
+
+        TestCase withName( std::string const& _newName ) const;
+
+        void invoke() const;
+
+        TestCaseInfo const& getTestCaseInfo() const;
+
+        void swap( TestCase& other );
+        bool operator == ( TestCase const& other ) const;
+        bool operator < ( TestCase const& other ) const;
+        TestCase& operator = ( TestCase const& other );
+
+    private:
+        Ptr<ITestCase> test;
+    };
+
+    TestCase makeTestCase(  ITestCase* testCase,
+                            std::string const& className,
+                            std::string const& name,
+                            std::string const& description,
+                            SourceLineInfo const& lineInfo );
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+
+#ifdef __OBJC__
+// #included from: internal/catch_objc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
+
+#import <objc/runtime.h>
+
+#include <string>
+
+// NB. Any general catch headers included here must be included
+// in catch.hpp first to make sure they are included by the single
+// header for non obj-usage
+
+///////////////////////////////////////////////////////////////////////////////
+// This protocol is really only here for (self) documenting purposes, since
+// all its methods are optional.
+@protocol OcFixture
+
+@optional
+
+-(void) setUp;
+-(void) tearDown;
+
+@end
+
+namespace Catch {
+
+    class OcMethod : public SharedImpl<ITestCase> {
+
+    public:
+        OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
+
+        virtual void invoke() const {
+            id obj = [[m_cls alloc] init];
+
+            performOptionalSelector( obj, @selector(setUp)  );
+            performOptionalSelector( obj, m_sel );
+            performOptionalSelector( obj, @selector(tearDown)  );
+
+            arcSafeRelease( obj );
+        }
+    private:
+        virtual ~OcMethod() {}
+
+        Class m_cls;
+        SEL m_sel;
+    };
+
+    namespace Detail{
+
+        inline std::string getAnnotation(   Class cls,
+                                            std::string const& annotationName,
+                                            std::string const& testCaseName ) {
+            NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
+            SEL sel = NSSelectorFromString( selStr );
+            arcSafeRelease( selStr );
+            id value = performOptionalSelector( cls, sel );
+            if( value )
+                return [(NSString*)value UTF8String];
+            return "";
+        }
+    }
+
+    inline size_t registerTestMethods() {
+        size_t noTestMethods = 0;
+        int noClasses = objc_getClassList( CATCH_NULL, 0 );
+
+        Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
+        objc_getClassList( classes, noClasses );
+
+        for( int c = 0; c < noClasses; c++ ) {
+            Class cls = classes[c];
+            {
+                u_int count;
+                Method* methods = class_copyMethodList( cls, &count );
+                for( u_int m = 0; m < count ; m++ ) {
+                    SEL selector = method_getName(methods[m]);
+                    std::string methodName = sel_getName(selector);
+                    if( startsWith( methodName, "Catch_TestCase_" ) ) {
+                        std::string testCaseName = methodName.substr( 15 );
+                        std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
+                        std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
+                        const char* className = class_getName( cls );
+
+                        getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) );
+                        noTestMethods++;
+                    }
+                }
+                free(methods);
+            }
+        }
+        return noTestMethods;
+    }
+
+    namespace Matchers {
+        namespace Impl {
+        namespace NSStringMatchers {
+
+            struct StringHolder : MatcherBase<NSString*>{
+                StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
+                StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
+                StringHolder() {
+                    arcSafeRelease( m_substr );
+                }
+
+                virtual bool match( NSString* arg ) const CATCH_OVERRIDE {
+                    return false;
+                }
+
+                NSString* m_substr;
+            };
+
+            struct Equals : StringHolder {
+                Equals( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( NSString* str ) const CATCH_OVERRIDE {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str isEqualToString:m_substr];
+                }
+
+                virtual std::string describe() const CATCH_OVERRIDE {
+                    return "equals string: " + Catch::toString( m_substr );
+                }
+            };
+
+            struct Contains : StringHolder {
+                Contains( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( NSString* str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location != NSNotFound;
+                }
+
+                virtual std::string describe() const CATCH_OVERRIDE {
+                    return "contains string: " + Catch::toString( m_substr );
+                }
+            };
+
+            struct StartsWith : StringHolder {
+                StartsWith( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( NSString* str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location == 0;
+                }
+
+                virtual std::string describe() const CATCH_OVERRIDE {
+                    return "starts with: " + Catch::toString( m_substr );
+                }
+            };
+            struct EndsWith : StringHolder {
+                EndsWith( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( NSString* str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location == [str length] - [m_substr length];
+                }
+
+                virtual std::string describe() const CATCH_OVERRIDE {
+                    return "ends with: " + Catch::toString( m_substr );
+                }
+            };
+
+        } // namespace NSStringMatchers
+        } // namespace Impl
+
+        inline Impl::NSStringMatchers::Equals
+            Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
+
+        inline Impl::NSStringMatchers::Contains
+            Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
+
+        inline Impl::NSStringMatchers::StartsWith
+            StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
+
+        inline Impl::NSStringMatchers::EndsWith
+            EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
+
+    } // namespace Matchers
+
+    using namespace Matchers;
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define OC_TEST_CASE( name, desc )\
++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
+{\
+return @ name; \
+}\
++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
+{ \
+return @ desc; \
+} \
+-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
+
+#endif
+
+#ifdef CATCH_IMPL
+
+// !TBD: Move the leak detector code into a separate header
+#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
+#include <crtdbg.h>
+class LeakDetector {
+public:
+	LeakDetector() {
+		int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+		flag |= _CRTDBG_LEAK_CHECK_DF;
+		flag |= _CRTDBG_ALLOC_MEM_DF;
+		_CrtSetDbgFlag(flag);
+		_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+		_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+		// Change this to leaking allocation's number to break there
+		_CrtSetBreakAlloc(-1);
+	}
+};
+#else
+class LeakDetector {};
+#endif
+
+LeakDetector leakDetector;
+
+// #included from: internal/catch_impl.hpp
+#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
+
+// Collect all the implementation files together here
+// These are the equivalent of what would usually be cpp files
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+// #included from: ../catch_session.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
+
+// #included from: internal/catch_commandline.hpp
+#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
+
+// #included from: catch_config.hpp
+#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
+
+// #included from: catch_test_spec_parser.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_test_spec.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_wildcard_pattern.hpp
+#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED
+
+#include <stdexcept>
+
+namespace Catch
+{
+    class WildcardPattern {
+        enum WildcardPosition {
+            NoWildcard = 0,
+            WildcardAtStart = 1,
+            WildcardAtEnd = 2,
+            WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
+        };
+
+    public:
+
+        WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity )
+        :   m_caseSensitivity( caseSensitivity ),
+            m_wildcard( NoWildcard ),
+            m_pattern( adjustCase( pattern ) )
+        {
+            if( startsWith( m_pattern, '*' ) ) {
+                m_pattern = m_pattern.substr( 1 );
+                m_wildcard = WildcardAtStart;
+            }
+            if( endsWith( m_pattern, '*' ) ) {
+                m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
+                m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
+            }
+        }
+        virtual ~WildcardPattern();
+        virtual bool matches( std::string const& str ) const {
+            switch( m_wildcard ) {
+                case NoWildcard:
+                    return m_pattern == adjustCase( str );
+                case WildcardAtStart:
+                    return endsWith( adjustCase( str ), m_pattern );
+                case WildcardAtEnd:
+                    return startsWith( adjustCase( str ), m_pattern );
+                case WildcardAtBothEnds:
+                    return contains( adjustCase( str ), m_pattern );
+            }
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+            throw std::logic_error( "Unknown enum" );
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+        }
+    private:
+        std::string adjustCase( std::string const& str ) const {
+            return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
+        }
+        CaseSensitive::Choice m_caseSensitivity;
+        WildcardPosition m_wildcard;
+        std::string m_pattern;
+    };
+}
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+    class TestSpec {
+        struct Pattern : SharedImpl<> {
+            virtual ~Pattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const = 0;
+        };
+        class NamePattern : public Pattern {
+        public:
+            NamePattern( std::string const& name )
+            : m_wildcardPattern( toLower( name ), CaseSensitive::No )
+            {}
+            virtual ~NamePattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const {
+                return m_wildcardPattern.matches( toLower( testCase.name ) );
+            }
+        private:
+            WildcardPattern m_wildcardPattern;
+        };
+
+        class TagPattern : public Pattern {
+        public:
+            TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
+            virtual ~TagPattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const {
+                return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end();
+            }
+        private:
+            std::string m_tag;
+        };
+
+        class ExcludedPattern : public Pattern {
+        public:
+            ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
+            virtual ~ExcludedPattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
+        private:
+            Ptr<Pattern> m_underlyingPattern;
+        };
+
+        struct Filter {
+            std::vector<Ptr<Pattern> > m_patterns;
+
+            bool matches( TestCaseInfo const& testCase ) const {
+                // All patterns in a filter must match for the filter to be a match
+                for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
+                    if( !(*it)->matches( testCase ) )
+                        return false;
+                }
+                return true;
+            }
+        };
+
+    public:
+        bool hasFilters() const {
+            return !m_filters.empty();
+        }
+        bool matches( TestCaseInfo const& testCase ) const {
+            // A TestSpec matches if any filter matches
+            for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it )
+                if( it->matches( testCase ) )
+                    return true;
+            return false;
+        }
+
+    private:
+        std::vector<Filter> m_filters;
+
+        friend class TestSpecParser;
+    };
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace Catch {
+
+    class TestSpecParser {
+        enum Mode{ None, Name, QuotedName, Tag, EscapedName };
+        Mode m_mode;
+        bool m_exclusion;
+        std::size_t m_start, m_pos;
+        std::string m_arg;
+        std::vector<std::size_t> m_escapeChars;
+        TestSpec::Filter m_currentFilter;
+        TestSpec m_testSpec;
+        ITagAliasRegistry const* m_tagAliases;
+
+    public:
+        TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
+
+        TestSpecParser& parse( std::string const& arg ) {
+            m_mode = None;
+            m_exclusion = false;
+            m_start = std::string::npos;
+            m_arg = m_tagAliases->expandAliases( arg );
+            m_escapeChars.clear();
+            for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
+                visitChar( m_arg[m_pos] );
+            if( m_mode == Name )
+                addPattern<TestSpec::NamePattern>();
+            return *this;
+        }
+        TestSpec testSpec() {
+            addFilter();
+            return m_testSpec;
+        }
+    private:
+        void visitChar( char c ) {
+            if( m_mode == None ) {
+                switch( c ) {
+                case ' ': return;
+                case '~': m_exclusion = true; return;
+                case '[': return startNewMode( Tag, ++m_pos );
+                case '"': return startNewMode( QuotedName, ++m_pos );
+                case '\\': return escape();
+                default: startNewMode( Name, m_pos ); break;
+                }
+            }
+            if( m_mode == Name ) {
+                if( c == ',' ) {
+                    addPattern<TestSpec::NamePattern>();
+                    addFilter();
+                }
+                else if( c == '[' ) {
+                    if( subString() == "exclude:" )
+                        m_exclusion = true;
+                    else
+                        addPattern<TestSpec::NamePattern>();
+                    startNewMode( Tag, ++m_pos );
+                }
+                else if( c == '\\' )
+                    escape();
+            }
+            else if( m_mode == EscapedName )
+                m_mode = Name;
+            else if( m_mode == QuotedName && c == '"' )
+                addPattern<TestSpec::NamePattern>();
+            else if( m_mode == Tag && c == ']' )
+                addPattern<TestSpec::TagPattern>();
+        }
+        void startNewMode( Mode mode, std::size_t start ) {
+            m_mode = mode;
+            m_start = start;
+        }
+        void escape() {
+            if( m_mode == None )
+                m_start = m_pos;
+            m_mode = EscapedName;
+            m_escapeChars.push_back( m_pos );
+        }
+        std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
+        template<typename T>
+        void addPattern() {
+            std::string token = subString();
+            for( size_t i = 0; i < m_escapeChars.size(); ++i )
+                token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 );
+            m_escapeChars.clear();
+            if( startsWith( token, "exclude:" ) ) {
+                m_exclusion = true;
+                token = token.substr( 8 );
+            }
+            if( !token.empty() ) {
+                Ptr<TestSpec::Pattern> pattern = new T( token );
+                if( m_exclusion )
+                    pattern = new TestSpec::ExcludedPattern( pattern );
+                m_currentFilter.m_patterns.push_back( pattern );
+            }
+            m_exclusion = false;
+            m_mode = None;
+        }
+        void addFilter() {
+            if( !m_currentFilter.m_patterns.empty() ) {
+                m_testSpec.m_filters.push_back( m_currentFilter );
+                m_currentFilter = TestSpec::Filter();
+            }
+        }
+    };
+    inline TestSpec parseTestSpec( std::string const& arg ) {
+        return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
+    }
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// #included from: catch_interfaces_config.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+    struct Verbosity { enum Level {
+        NoOutput = 0,
+        Quiet,
+        Normal
+    }; };
+
+    struct WarnAbout { enum What {
+        Nothing = 0x00,
+        NoAssertions = 0x01
+    }; };
+
+    struct ShowDurations { enum OrNot {
+        DefaultForReporter,
+        Always,
+        Never
+    }; };
+    struct RunTests { enum InWhatOrder {
+        InDeclarationOrder,
+        InLexicographicalOrder,
+        InRandomOrder
+    }; };
+    struct UseColour { enum YesOrNo {
+        Auto,
+        Yes,
+        No
+    }; };
+
+    class TestSpec;
+
+    struct IConfig : IShared {
+
+        virtual ~IConfig();
+
+        virtual bool allowThrows() const = 0;
+        virtual std::ostream& stream() const = 0;
+        virtual std::string name() const = 0;
+        virtual bool includeSuccessfulResults() const = 0;
+        virtual bool shouldDebugBreak() const = 0;
+        virtual bool warnAboutMissingAssertions() const = 0;
+        virtual int abortAfter() const = 0;
+        virtual bool showInvisibles() const = 0;
+        virtual ShowDurations::OrNot showDurations() const = 0;
+        virtual TestSpec const& testSpec() const = 0;
+        virtual RunTests::InWhatOrder runOrder() const = 0;
+        virtual unsigned int rngSeed() const = 0;
+        virtual UseColour::YesOrNo useColour() const = 0;
+        virtual std::vector<std::string> const& getSectionsToRun() const = 0;
+
+    };
+}
+
+// #included from: catch_stream.h
+#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
+
+// #included from: catch_streambuf.h
+#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
+
+#include <streambuf>
+
+namespace Catch {
+
+    class StreamBufBase : public std::streambuf {
+    public:
+        virtual ~StreamBufBase() CATCH_NOEXCEPT;
+    };
+}
+
+#include <streambuf>
+#include <ostream>
+#include <fstream>
+#include <memory>
+
+namespace Catch {
+
+    std::ostream& cout();
+    std::ostream& cerr();
+
+    struct IStream {
+        virtual ~IStream() CATCH_NOEXCEPT;
+        virtual std::ostream& stream() const = 0;
+    };
+
+    class FileStream : public IStream {
+        mutable std::ofstream m_ofs;
+    public:
+        FileStream( std::string const& filename );
+        virtual ~FileStream() CATCH_NOEXCEPT;
+    public: // IStream
+        virtual std::ostream& stream() const CATCH_OVERRIDE;
+    };
+
+    class CoutStream : public IStream {
+        mutable std::ostream m_os;
+    public:
+        CoutStream();
+        virtual ~CoutStream() CATCH_NOEXCEPT;
+
+    public: // IStream
+        virtual std::ostream& stream() const CATCH_OVERRIDE;
+    };
+
+    class DebugOutStream : public IStream {
+        CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf;
+        mutable std::ostream m_os;
+    public:
+        DebugOutStream();
+        virtual ~DebugOutStream() CATCH_NOEXCEPT;
+
+    public: // IStream
+        virtual std::ostream& stream() const CATCH_OVERRIDE;
+    };
+}
+
+#include <memory>
+#include <vector>
+#include <string>
+#include <stdexcept>
+
+#ifndef CATCH_CONFIG_CONSOLE_WIDTH
+#define CATCH_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+namespace Catch {
+
+    struct ConfigData {
+
+        ConfigData()
+        :   listTests( false ),
+            listTags( false ),
+            listReporters( false ),
+            listTestNamesOnly( false ),
+            showSuccessfulTests( false ),
+            shouldDebugBreak( false ),
+            noThrow( false ),
+            showHelp( false ),
+            showInvisibles( false ),
+            filenamesAsTags( false ),
+            abortAfter( -1 ),
+            rngSeed( 0 ),
+            verbosity( Verbosity::Normal ),
+            warnings( WarnAbout::Nothing ),
+            showDurations( ShowDurations::DefaultForReporter ),
+            runOrder( RunTests::InDeclarationOrder ),
+            useColour( UseColour::Auto )
+        {}
+
+        bool listTests;
+        bool listTags;
+        bool listReporters;
+        bool listTestNamesOnly;
+
+        bool showSuccessfulTests;
+        bool shouldDebugBreak;
+        bool noThrow;
+        bool showHelp;
+        bool showInvisibles;
+        bool filenamesAsTags;
+
+        int abortAfter;
+        unsigned int rngSeed;
+
+        Verbosity::Level verbosity;
+        WarnAbout::What warnings;
+        ShowDurations::OrNot showDurations;
+        RunTests::InWhatOrder runOrder;
+        UseColour::YesOrNo useColour;
+
+        std::string outputFilename;
+        std::string name;
+        std::string processName;
+
+        std::vector<std::string> reporterNames;
+        std::vector<std::string> testsOrTags;
+        std::vector<std::string> sectionsToRun;
+    };
+
+    class Config : public SharedImpl<IConfig> {
+    private:
+        Config( Config const& other );
+        Config& operator = ( Config const& other );
+        virtual void dummy();
+    public:
+
+        Config()
+        {}
+
+        Config( ConfigData const& data )
+        :   m_data( data ),
+            m_stream( openStream() )
+        {
+            if( !data.testsOrTags.empty() ) {
+                TestSpecParser parser( ITagAliasRegistry::get() );
+                for( std::size_t i = 0; i < data.testsOrTags.size(); ++i )
+                    parser.parse( data.testsOrTags[i] );
+                m_testSpec = parser.testSpec();
+            }
+        }
+
+        virtual ~Config() {}
+
+        std::string const& getFilename() const {
+            return m_data.outputFilename ;
+        }
+
+        bool listTests() const { return m_data.listTests; }
+        bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
+        bool listTags() const { return m_data.listTags; }
+        bool listReporters() const { return m_data.listReporters; }
+
+        std::string getProcessName() const { return m_data.processName; }
+
+        std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; }
+        std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; }
+
+        virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; }
+
+        bool showHelp() const { return m_data.showHelp; }
+
+        // IConfig interface
+        virtual bool allowThrows() const CATCH_OVERRIDE                 { return !m_data.noThrow; }
+        virtual std::ostream& stream() const CATCH_OVERRIDE             { return m_stream->stream(); }
+        virtual std::string name() const CATCH_OVERRIDE                 { return m_data.name.empty() ? m_data.processName : m_data.name; }
+        virtual bool includeSuccessfulResults() const CATCH_OVERRIDE    { return m_data.showSuccessfulTests; }
+        virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE  { return m_data.warnings & WarnAbout::NoAssertions; }
+        virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; }
+        virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE   { return m_data.runOrder; }
+        virtual unsigned int rngSeed() const CATCH_OVERRIDE             { return m_data.rngSeed; }
+        virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE     { return m_data.useColour; }
+        virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; }
+        virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; }
+        virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; }
+
+    private:
+
+        IStream const* openStream() {
+            if( m_data.outputFilename.empty() )
+                return new CoutStream();
+            else if( m_data.outputFilename[0] == '%' ) {
+                if( m_data.outputFilename == "%debug" )
+                    return new DebugOutStream();
+                else
+                    throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename );
+            }
+            else
+                return new FileStream( m_data.outputFilename );
+        }
+        ConfigData m_data;
+
+        CATCH_AUTO_PTR( IStream const ) m_stream;
+        TestSpec m_testSpec;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_clara.h
+#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
+
+// Use Catch's value for console width (store Clara's off to the side, if present)
+#ifdef CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
+#undef CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+// Declare Clara inside the Catch namespace
+#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
+// #included from: ../external/clara.h
+
+// Version 0.0.2.4
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
+
+#ifndef STITCH_CLARA_OPEN_NAMESPACE
+#define TWOBLUECUBES_CLARA_H_INCLUDED
+#define STITCH_CLARA_OPEN_NAMESPACE
+#define STITCH_CLARA_CLOSE_NAMESPACE
+#else
+#define STITCH_CLARA_CLOSE_NAMESPACE }
+#endif
+
+#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
+
+// ----------- #included from tbc_text_format.h -----------
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
+#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+#define TBC_TEXT_FORMAT_H_INCLUDED
+#endif
+
+#include <string>
+#include <vector>
+#include <sstream>
+#include <algorithm>
+#include <cctype>
+
+// Use optional outer namespace
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+    const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+    struct TextAttributes {
+        TextAttributes()
+        :   initialIndent( std::string::npos ),
+            indent( 0 ),
+            width( consoleWidth-1 ),
+            tabChar( '\t' )
+        {}
+
+        TextAttributes& setInitialIndent( std::size_t _value )  { initialIndent = _value; return *this; }
+        TextAttributes& setIndent( std::size_t _value )         { indent = _value; return *this; }
+        TextAttributes& setWidth( std::size_t _value )          { width = _value; return *this; }
+        TextAttributes& setTabChar( char _value )               { tabChar = _value; return *this; }
+
+        std::size_t initialIndent;  // indent of first line, or npos
+        std::size_t indent;         // indent of subsequent lines, or all if initialIndent is npos
+        std::size_t width;          // maximum width of text, including indent. Longer text will wrap
+        char tabChar;               // If this char is seen the indent is changed to current pos
+    };
+
+    class Text {
+    public:
+        Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
+        : attr( _attr )
+        {
+            std::string wrappableChars = " [({.,/|\\-";
+            std::size_t indent = _attr.initialIndent != std::string::npos
+                ? _attr.initialIndent
+                : _attr.indent;
+            std::string remainder = _str;
+
+            while( !remainder.empty() ) {
+                if( lines.size() >= 1000 ) {
+                    lines.push_back( "... message truncated due to excessive size" );
+                    return;
+                }
+                std::size_t tabPos = std::string::npos;
+                std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
+                std::size_t pos = remainder.find_first_of( '\n' );
+                if( pos <= width ) {
+                    width = pos;
+                }
+                pos = remainder.find_last_of( _attr.tabChar, width );
+                if( pos != std::string::npos ) {
+                    tabPos = pos;
+                    if( remainder[width] == '\n' )
+                        width--;
+                    remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
+                }
+
+                if( width == remainder.size() ) {
+                    spliceLine( indent, remainder, width );
+                }
+                else if( remainder[width] == '\n' ) {
+                    spliceLine( indent, remainder, width );
+                    if( width <= 1 || remainder.size() != 1 )
+                        remainder = remainder.substr( 1 );
+                    indent = _attr.indent;
+                }
+                else {
+                    pos = remainder.find_last_of( wrappableChars, width );
+                    if( pos != std::string::npos && pos > 0 ) {
+                        spliceLine( indent, remainder, pos );
+                        if( remainder[0] == ' ' )
+                            remainder = remainder.substr( 1 );
+                    }
+                    else {
+                        spliceLine( indent, remainder, width-1 );
+                        lines.back() += "-";
+                    }
+                    if( lines.size() == 1 )
+                        indent = _attr.indent;
+                    if( tabPos != std::string::npos )
+                        indent += tabPos;
+                }
+            }
+        }
+
+        void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
+            lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
+            _remainder = _remainder.substr( _pos );
+        }
+
+        typedef std::vector<std::string>::const_iterator const_iterator;
+
+        const_iterator begin() const { return lines.begin(); }
+        const_iterator end() const { return lines.end(); }
+        std::string const& last() const { return lines.back(); }
+        std::size_t size() const { return lines.size(); }
+        std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << *this;
+            return oss.str();
+        }
+
+        inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+            for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
+                it != itEnd; ++it ) {
+                if( it != _text.begin() )
+                    _stream << "\n";
+                _stream << *it;
+            }
+            return _stream;
+        }
+
+    private:
+        std::string str;
+        TextAttributes attr;
+        std::vector<std::string> lines;
+    };
+
+} // end namespace Tbc
+
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TBC_TEXT_FORMAT_H_INCLUDED
+
+// ----------- end of #include from tbc_text_format.h -----------
+// ........... back in clara.h
+
+#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
+
+// ----------- #included from clara_compilers.h -----------
+
+#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
+#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
+
+// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
+// The following features are defined:
+//
+// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported?
+// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
+// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
+// CLARA_CONFIG_CPP11_OVERRIDE : is override supported?
+// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
+
+// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
+
+// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported?
+
+// In general each macro has a _NO_<feature name> form
+// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
+// Many features, at point of detection, define an _INTERNAL_ macro, so they
+// can be combined, en-mass, with the _NO_ forms later.
+
+// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11
+
+#ifdef __clang__
+
+#if __has_feature(cxx_nullptr)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+#if __has_feature(cxx_noexcept)
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#endif
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// GCC
+#ifdef __GNUC__
+
+#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+// - otherwise more recent versions define __cplusplus >= 201103L
+// and will get picked up below
+
+#endif // __GNUC__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#ifdef _MSC_VER
+
+#if (_MSC_VER >= 1600)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ language feature support
+
+// catch all support for C++11
+#if defined(__cplusplus) && __cplusplus >= 201103L
+
+#define CLARA_CPP11_OR_GREATER
+
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR)
+#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
+#endif
+
+#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
+#endif
+
+#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE)
+#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE
+#endif
+#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
+#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+#endif // __cplusplus >= 201103L
+
+// Now set the actual defines based on the above + anything the user has configured
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_NULLPTR
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_NOEXCEPT
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_GENERATED_METHODS
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_OVERRIDE
+#endif
+#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11)
+#define CLARA_CONFIG_CPP11_UNIQUE_PTR
+#endif
+
+// noexcept support:
+#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT)
+#define CLARA_NOEXCEPT noexcept
+#  define CLARA_NOEXCEPT_IS(x) noexcept(x)
+#else
+#define CLARA_NOEXCEPT throw()
+#  define CLARA_NOEXCEPT_IS(x)
+#endif
+
+// nullptr support
+#ifdef CLARA_CONFIG_CPP11_NULLPTR
+#define CLARA_NULL nullptr
+#else
+#define CLARA_NULL NULL
+#endif
+
+// override support
+#ifdef CLARA_CONFIG_CPP11_OVERRIDE
+#define CLARA_OVERRIDE override
+#else
+#define CLARA_OVERRIDE
+#endif
+
+// unique_ptr support
+#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR
+#   define CLARA_AUTO_PTR( T ) std::unique_ptr<T>
+#else
+#   define CLARA_AUTO_PTR( T ) std::auto_ptr<T>
+#endif
+
+#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
+
+// ----------- end of #include from clara_compilers.h -----------
+// ........... back in clara.h
+
+#include <map>
+#include <stdexcept>
+#include <memory>
+
+#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#define CLARA_PLATFORM_WINDOWS
+#endif
+
+// Use optional outer namespace
+#ifdef STITCH_CLARA_OPEN_NAMESPACE
+STITCH_CLARA_OPEN_NAMESPACE
+#endif
+
+namespace Clara {
+
+    struct UnpositionalTag {};
+
+    extern UnpositionalTag _;
+
+#ifdef CLARA_CONFIG_MAIN
+    UnpositionalTag _;
+#endif
+
+    namespace Detail {
+
+#ifdef CLARA_CONSOLE_WIDTH
+    const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+        using namespace Tbc;
+
+        inline bool startsWith( std::string const& str, std::string const& prefix ) {
+            return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix;
+        }
+
+        template<typename T> struct RemoveConstRef{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T&>{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T const&>{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T const>{ typedef T type; };
+
+        template<typename T>    struct IsBool       { static const bool value = false; };
+        template<>              struct IsBool<bool> { static const bool value = true; };
+
+        template<typename T>
+        void convertInto( std::string const& _source, T& _dest ) {
+            std::stringstream ss;
+            ss << _source;
+            ss >> _dest;
+            if( ss.fail() )
+                throw std::runtime_error( "Unable to convert " + _source + " to destination type" );
+        }
+        inline void convertInto( std::string const& _source, std::string& _dest ) {
+            _dest = _source;
+        }
+        char toLowerCh(char c) {
+            return static_cast<char>( std::tolower( c ) );
+        }
+        inline void convertInto( std::string const& _source, bool& _dest ) {
+            std::string sourceLC = _source;
+            std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh );
+            if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
+                _dest = true;
+            else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
+                _dest = false;
+            else
+                throw std::runtime_error( "Expected a boolean value but did not recognise:\n  '" + _source + "'" );
+        }
+
+        template<typename ConfigT>
+        struct IArgFunction {
+            virtual ~IArgFunction() {}
+#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS
+            IArgFunction()                      = default;
+            IArgFunction( IArgFunction const& ) = default;
+#endif
+            virtual void set( ConfigT& config, std::string const& value ) const = 0;
+            virtual bool takesArg() const = 0;
+            virtual IArgFunction* clone() const = 0;
+        };
+
+        template<typename ConfigT>
+        class BoundArgFunction {
+        public:
+            BoundArgFunction() : functionObj( CLARA_NULL ) {}
+            BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
+            BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {}
+            BoundArgFunction& operator = ( BoundArgFunction const& other ) {
+                IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL;
+                delete functionObj;
+                functionObj = newFunctionObj;
+                return *this;
+            }
+            ~BoundArgFunction() { delete functionObj; }
+
+            void set( ConfigT& config, std::string const& value ) const {
+                functionObj->set( config, value );
+            }
+            bool takesArg() const { return functionObj->takesArg(); }
+
+            bool isSet() const {
+                return functionObj != CLARA_NULL;
+            }
+        private:
+            IArgFunction<ConfigT>* functionObj;
+        };
+
+        template<typename C>
+        struct NullBinder : IArgFunction<C>{
+            virtual void set( C&, std::string const& ) const {}
+            virtual bool takesArg() const { return true; }
+            virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
+        };
+
+        template<typename C, typename M>
+        struct BoundDataMember : IArgFunction<C>{
+            BoundDataMember( M C::* _member ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                convertInto( stringValue, p.*member );
+            }
+            virtual bool takesArg() const { return !IsBool<M>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
+            M C::* member;
+        };
+        template<typename C, typename M>
+        struct BoundUnaryMethod : IArgFunction<C>{
+            BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                typename RemoveConstRef<M>::type value;
+                convertInto( stringValue, value );
+                (p.*member)( value );
+            }
+            virtual bool takesArg() const { return !IsBool<M>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
+            void (C::*member)( M );
+        };
+        template<typename C>
+        struct BoundNullaryMethod : IArgFunction<C>{
+            BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                bool value;
+                convertInto( stringValue, value );
+                if( value )
+                    (p.*member)();
+            }
+            virtual bool takesArg() const { return false; }
+            virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
+            void (C::*member)();
+        };
+
+        template<typename C>
+        struct BoundUnaryFunction : IArgFunction<C>{
+            BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {}
+            virtual void set( C& obj, std::string const& stringValue ) const {
+                bool value;
+                convertInto( stringValue, value );
+                if( value )
+                    function( obj );
+            }
+            virtual bool takesArg() const { return false; }
+            virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
+            void (*function)( C& );
+        };
+
+        template<typename C, typename T>
+        struct BoundBinaryFunction : IArgFunction<C>{
+            BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {}
+            virtual void set( C& obj, std::string const& stringValue ) const {
+                typename RemoveConstRef<T>::type value;
+                convertInto( stringValue, value );
+                function( obj, value );
+            }
+            virtual bool takesArg() const { return !IsBool<T>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
+            void (*function)( C&, T );
+        };
+
+    } // namespace Detail
+
+    inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) {
+        std::vector<std::string> args( static_cast<std::size_t>( argc ) );
+        for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i )
+            args[i] = argv[i];
+
+        return args;
+    }
+
+    class Parser {
+        enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional };
+        Mode mode;
+        std::size_t from;
+        bool inQuotes;
+    public:
+
+        struct Token {
+            enum Type { Positional, ShortOpt, LongOpt };
+            Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {}
+            Type type;
+            std::string data;
+        };
+
+        Parser() : mode( None ), from( 0 ), inQuotes( false ){}
+
+        void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) {
+            const std::string doubleDash = "--";
+            for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i )
+                parseIntoTokens( args[i], tokens);
+        }
+
+        void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
+            for( std::size_t i = 0; i < arg.size(); ++i ) {
+                char c = arg[i];
+                if( c == '"' )
+                    inQuotes = !inQuotes;
+                mode = handleMode( i, c, arg, tokens );
+            }
+            mode = handleMode( arg.size(), '\0', arg, tokens );
+        }
+        Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
+            switch( mode ) {
+                case None: return handleNone( i, c );
+                case MaybeShortOpt: return handleMaybeShortOpt( i, c );
+                case ShortOpt:
+                case LongOpt:
+                case SlashOpt: return handleOpt( i, c, arg, tokens );
+                case Positional: return handlePositional( i, c, arg, tokens );
+                default: throw std::logic_error( "Unknown mode" );
+            }
+        }
+
+        Mode handleNone( std::size_t i, char c ) {
+            if( inQuotes ) {
+                from = i;
+                return Positional;
+            }
+            switch( c ) {
+                case '-': return MaybeShortOpt;
+#ifdef CLARA_PLATFORM_WINDOWS
+                case '/': from = i+1; return SlashOpt;
+#endif
+                default: from = i; return Positional;
+            }
+        }
+        Mode handleMaybeShortOpt( std::size_t i, char c ) {
+            switch( c ) {
+                case '-': from = i+1; return LongOpt;
+                default: from = i; return ShortOpt;
+            }
+        }
+
+        Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
+            if( std::string( ":=\0", 3 ).find( c ) == std::string::npos )
+                return mode;
+
+            std::string optName = arg.substr( from, i-from );
+            if( mode == ShortOpt )
+                for( std::size_t j = 0; j < optName.size(); ++j )
+                    tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) );
+            else if( mode == SlashOpt && optName.size() == 1 )
+                tokens.push_back( Token( Token::ShortOpt, optName ) );
+            else
+                tokens.push_back( Token( Token::LongOpt, optName ) );
+            return None;
+        }
+        Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
+            if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos )
+                return mode;
+
+            std::string data = arg.substr( from, i-from );
+            tokens.push_back( Token( Token::Positional, data ) );
+            return None;
+        }
+    };
+
+    template<typename ConfigT>
+    struct CommonArgProperties {
+        CommonArgProperties() {}
+        CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {}
+
+        Detail::BoundArgFunction<ConfigT> boundField;
+        std::string description;
+        std::string detail;
+        std::string placeholder; // Only value if boundField takes an arg
+
+        bool takesArg() const {
+            return !placeholder.empty();
+        }
+        void validate() const {
+            if( !boundField.isSet() )
+                throw std::logic_error( "option not bound" );
+        }
+    };
+    struct OptionArgProperties {
+        std::vector<std::string> shortNames;
+        std::string longName;
+
+        bool hasShortName( std::string const& shortName ) const {
+            return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end();
+        }
+        bool hasLongName( std::string const& _longName ) const {
+            return _longName == longName;
+        }
+    };
+    struct PositionalArgProperties {
+        PositionalArgProperties() : position( -1 ) {}
+        int position; // -1 means non-positional (floating)
+
+        bool isFixedPositional() const {
+            return position != -1;
+        }
+    };
+
+    template<typename ConfigT>
+    class CommandLine {
+
+        struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties {
+            Arg() {}
+            Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {}
+
+            using CommonArgProperties<ConfigT>::placeholder; // !TBD
+
+            std::string dbgName() const {
+                if( !longName.empty() )
+                    return "--" + longName;
+                if( !shortNames.empty() )
+                    return "-" + shortNames[0];
+                return "positional args";
+            }
+            std::string commands() const {
+                std::ostringstream oss;
+                bool first = true;
+                std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
+                for(; it != itEnd; ++it ) {
+                    if( first )
+                        first = false;
+                    else
+                        oss << ", ";
+                    oss << "-" << *it;
+                }
+                if( !longName.empty() ) {
+                    if( !first )
+                        oss << ", ";
+                    oss << "--" << longName;
+                }
+                if( !placeholder.empty() )
+                    oss << " <" << placeholder << ">";
+                return oss.str();
+            }
+        };
+
+        typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr;
+
+        friend void addOptName( Arg& arg, std::string const& optName )
+        {
+            if( optName.empty() )
+                return;
+            if( Detail::startsWith( optName, "--" ) ) {
+                if( !arg.longName.empty() )
+                    throw std::logic_error( "Only one long opt may be specified. '"
+                        + arg.longName
+                        + "' already specified, now attempting to add '"
+                        + optName + "'" );
+                arg.longName = optName.substr( 2 );
+            }
+            else if( Detail::startsWith( optName, "-" ) )
+                arg.shortNames.push_back( optName.substr( 1 ) );
+            else
+                throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" );
+        }
+        friend void setPositionalArg( Arg& arg, int position )
+        {
+            arg.position = position;
+        }
+
+        class ArgBuilder {
+        public:
+            ArgBuilder( Arg* arg ) : m_arg( arg ) {}
+
+            // Bind a non-boolean data member (requires placeholder string)
+            template<typename C, typename M>
+            void bind( M C::* field, std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundDataMember<C,M>( field );
+                m_arg->placeholder = placeholder;
+            }
+            // Bind a boolean data member (no placeholder required)
+            template<typename C>
+            void bind( bool C::* field ) {
+                m_arg->boundField = new Detail::BoundDataMember<C,bool>( field );
+            }
+
+            // Bind a method taking a single, non-boolean argument (requires a placeholder string)
+            template<typename C, typename M>
+            void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod );
+                m_arg->placeholder = placeholder;
+            }
+
+            // Bind a method taking a single, boolean argument (no placeholder string required)
+            template<typename C>
+            void bind( void (C::* unaryMethod)( bool ) ) {
+                m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod );
+            }
+
+            // Bind a method that takes no arguments (will be called if opt is present)
+            template<typename C>
+            void bind( void (C::* nullaryMethod)() ) {
+                m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod );
+            }
+
+            // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
+            template<typename C>
+            void bind( void (* unaryFunction)( C& ) ) {
+                m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction );
+            }
+
+            // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
+            template<typename C, typename T>
+            void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction );
+                m_arg->placeholder = placeholder;
+            }
+
+            ArgBuilder& describe( std::string const& description ) {
+                m_arg->description = description;
+                return *this;
+            }
+            ArgBuilder& detail( std::string const& detail ) {
+                m_arg->detail = detail;
+                return *this;
+            }
+
+        protected:
+            Arg* m_arg;
+        };
+
+        class OptBuilder : public ArgBuilder {
+        public:
+            OptBuilder( Arg* arg ) : ArgBuilder( arg ) {}
+            OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {}
+
+            OptBuilder& operator[]( std::string const& optName ) {
+                addOptName( *ArgBuilder::m_arg, optName );
+                return *this;
+            }
+        };
+
+    public:
+
+        CommandLine()
+        :   m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
+            m_highestSpecifiedArgPosition( 0 ),
+            m_throwOnUnrecognisedTokens( false )
+        {}
+        CommandLine( CommandLine const& other )
+        :   m_boundProcessName( other.m_boundProcessName ),
+            m_options ( other.m_options ),
+            m_positionalArgs( other.m_positionalArgs ),
+            m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ),
+            m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
+        {
+            if( other.m_floatingArg.get() )
+                m_floatingArg.reset( new Arg( *other.m_floatingArg ) );
+        }
+
+        CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
+            m_throwOnUnrecognisedTokens = shouldThrow;
+            return *this;
+        }
+
+        OptBuilder operator[]( std::string const& optName ) {
+            m_options.push_back( Arg() );
+            addOptName( m_options.back(), optName );
+            OptBuilder builder( &m_options.back() );
+            return builder;
+        }
+
+        ArgBuilder operator[]( int position ) {
+            m_positionalArgs.insert( std::make_pair( position, Arg() ) );
+            if( position > m_highestSpecifiedArgPosition )
+                m_highestSpecifiedArgPosition = position;
+            setPositionalArg( m_positionalArgs[position], position );
+            ArgBuilder builder( &m_positionalArgs[position] );
+            return builder;
+        }
+
+        // Invoke this with the _ instance
+        ArgBuilder operator[]( UnpositionalTag ) {
+            if( m_floatingArg.get() )
+                throw std::logic_error( "Only one unpositional argument can be added" );
+            m_floatingArg.reset( new Arg() );
+            ArgBuilder builder( m_floatingArg.get() );
+            return builder;
+        }
+
+        template<typename C, typename M>
+        void bindProcessName( M C::* field ) {
+            m_boundProcessName = new Detail::BoundDataMember<C,M>( field );
+        }
+        template<typename C, typename M>
+        void bindProcessName( void (C::*_unaryMethod)( M ) ) {
+            m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod );
+        }
+
+        void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const {
+            typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
+            std::size_t maxWidth = 0;
+            for( it = itBegin; it != itEnd; ++it )
+                maxWidth = (std::max)( maxWidth, it->commands().size() );
+
+            for( it = itBegin; it != itEnd; ++it ) {
+                Detail::Text usage( it->commands(), Detail::TextAttributes()
+                                                        .setWidth( maxWidth+indent )
+                                                        .setIndent( indent ) );
+                Detail::Text desc( it->description, Detail::TextAttributes()
+                                                        .setWidth( width - maxWidth - 3 ) );
+
+                for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) {
+                    std::string usageCol = i < usage.size() ? usage[i] : "";
+                    os << usageCol;
+
+                    if( i < desc.size() && !desc[i].empty() )
+                        os  << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' )
+                            << desc[i];
+                    os << "\n";
+                }
+            }
+        }
+        std::string optUsage() const {
+            std::ostringstream oss;
+            optUsage( oss );
+            return oss.str();
+        }
+
+        void argSynopsis( std::ostream& os ) const {
+            for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) {
+                if( i > 1 )
+                    os << " ";
+                typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i );
+                if( it != m_positionalArgs.end() )
+                    os << "<" << it->second.placeholder << ">";
+                else if( m_floatingArg.get() )
+                    os << "<" << m_floatingArg->placeholder << ">";
+                else
+                    throw std::logic_error( "non consecutive positional arguments with no floating args" );
+            }
+            // !TBD No indication of mandatory args
+            if( m_floatingArg.get() ) {
+                if( m_highestSpecifiedArgPosition > 1 )
+                    os << " ";
+                os << "[<" << m_floatingArg->placeholder << "> ...]";
+            }
+        }
+        std::string argSynopsis() const {
+            std::ostringstream oss;
+            argSynopsis( oss );
+            return oss.str();
+        }
+
+        void usage( std::ostream& os, std::string const& procName ) const {
+            validate();
+            os << "usage:\n  " << procName << " ";
+            argSynopsis( os );
+            if( !m_options.empty() ) {
+                os << " [options]\n\nwhere options are: \n";
+                optUsage( os, 2 );
+            }
+            os << "\n";
+        }
+        std::string usage( std::string const& procName ) const {
+            std::ostringstream oss;
+            usage( oss, procName );
+            return oss.str();
+        }
+
+        ConfigT parse( std::vector<std::string> const& args ) const {
+            ConfigT config;
+            parseInto( args, config );
+            return config;
+        }
+
+        std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const {
+            std::string processName = args.empty() ? std::string() : args[0];
+            std::size_t lastSlash = processName.find_last_of( "/\\" );
+            if( lastSlash != std::string::npos )
+                processName = processName.substr( lastSlash+1 );
+            m_boundProcessName.set( config, processName );
+            std::vector<Parser::Token> tokens;
+            Parser parser;
+            parser.parseIntoTokens( args, tokens );
+            return populate( tokens, config );
+        }
+
+        std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            validate();
+            std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config );
+            unusedTokens = populateFixedArgs( unusedTokens, config );
+            unusedTokens = populateFloatingArgs( unusedTokens, config );
+            return unusedTokens;
+        }
+
+        std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            std::vector<Parser::Token> unusedTokens;
+            std::vector<std::string> errors;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
+                for(; it != itEnd; ++it ) {
+                    Arg const& arg = *it;
+
+                    try {
+                        if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) ||
+                            ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) {
+                            if( arg.takesArg() ) {
+                                if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
+                                    errors.push_back( "Expected argument to option: " + token.data );
+                                else
+                                    arg.boundField.set( config, tokens[++i].data );
+                            }
+                            else {
+                                arg.boundField.set( config, "true" );
+                            }
+                            break;
+                        }
+                    }
+                    catch( std::exception& ex ) {
+                        errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" );
+                    }
+                }
+                if( it == itEnd ) {
+                    if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
+                        unusedTokens.push_back( token );
+                    else if( errors.empty() && m_throwOnUnrecognisedTokens )
+                        errors.push_back( "unrecognised option: " + token.data );
+                }
+            }
+            if( !errors.empty() ) {
+                std::ostringstream oss;
+                for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
+                        it != itEnd;
+                        ++it ) {
+                    if( it != errors.begin() )
+                        oss << "\n";
+                    oss << *it;
+                }
+                throw std::runtime_error( oss.str() );
+            }
+            return unusedTokens;
+        }
+        std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            std::vector<Parser::Token> unusedTokens;
+            int position = 1;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position );
+                if( it != m_positionalArgs.end() )
+                    it->second.boundField.set( config, token.data );
+                else
+                    unusedTokens.push_back( token );
+                if( token.type == Parser::Token::Positional )
+                    position++;
+            }
+            return unusedTokens;
+        }
+        std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            if( !m_floatingArg.get() )
+                return tokens;
+            std::vector<Parser::Token> unusedTokens;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                if( token.type == Parser::Token::Positional )
+                    m_floatingArg->boundField.set( config, token.data );
+                else
+                    unusedTokens.push_back( token );
+            }
+            return unusedTokens;
+        }
+
+        void validate() const
+        {
+            if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() )
+                throw std::logic_error( "No options or arguments specified" );
+
+            for( typename std::vector<Arg>::const_iterator  it = m_options.begin(),
+                                                            itEnd = m_options.end();
+                    it != itEnd; ++it )
+                it->validate();
+        }
+
+    private:
+        Detail::BoundArgFunction<ConfigT> m_boundProcessName;
+        std::vector<Arg> m_options;
+        std::map<int, Arg> m_positionalArgs;
+        ArgAutoPtr m_floatingArg;
+        int m_highestSpecifiedArgPosition;
+        bool m_throwOnUnrecognisedTokens;
+    };
+
+} // end namespace Clara
+
+STITCH_CLARA_CLOSE_NAMESPACE
+#undef STITCH_CLARA_OPEN_NAMESPACE
+#undef STITCH_CLARA_CLOSE_NAMESPACE
+
+#endif // TWOBLUECUBES_CLARA_H_INCLUDED
+#undef STITCH_CLARA_OPEN_NAMESPACE
+
+// Restore Clara's value for console width, if present
+#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+#include <fstream>
+#include <ctime>
+
+namespace Catch {
+
+    inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
+    inline void abortAfterX( ConfigData& config, int x ) {
+        if( x < 1 )
+            throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" );
+        config.abortAfter = x;
+    }
+    inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
+    inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); }
+    inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); }
+
+    inline void addWarning( ConfigData& config, std::string const& _warning ) {
+        if( _warning == "NoAssertions" )
+            config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
+        else
+            throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' );
+    }
+    inline void setOrder( ConfigData& config, std::string const& order ) {
+        if( startsWith( "declared", order ) )
+            config.runOrder = RunTests::InDeclarationOrder;
+        else if( startsWith( "lexical", order ) )
+            config.runOrder = RunTests::InLexicographicalOrder;
+        else if( startsWith( "random", order ) )
+            config.runOrder = RunTests::InRandomOrder;
+        else
+            throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' );
+    }
+    inline void setRngSeed( ConfigData& config, std::string const& seed ) {
+        if( seed == "time" ) {
+            config.rngSeed = static_cast<unsigned int>( std::time(0) );
+        }
+        else {
+            std::stringstream ss;
+            ss << seed;
+            ss >> config.rngSeed;
+            if( ss.fail() )
+                throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" );
+        }
+    }
+    inline void setVerbosity( ConfigData& config, int level ) {
+        // !TBD: accept strings?
+        config.verbosity = static_cast<Verbosity::Level>( level );
+    }
+    inline void setShowDurations( ConfigData& config, bool _showDurations ) {
+        config.showDurations = _showDurations
+            ? ShowDurations::Always
+            : ShowDurations::Never;
+    }
+    inline void setUseColour( ConfigData& config, std::string const& value ) {
+        std::string mode = toLower( value );
+
+        if( mode == "yes" )
+            config.useColour = UseColour::Yes;
+        else if( mode == "no" )
+            config.useColour = UseColour::No;
+        else if( mode == "auto" )
+            config.useColour = UseColour::Auto;
+        else
+            throw std::runtime_error( "colour mode must be one of: auto, yes or no" );
+    }
+    inline void forceColour( ConfigData& config ) {
+        config.useColour = UseColour::Yes;
+    }
+    inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
+        std::ifstream f( _filename.c_str() );
+        if( !f.is_open() )
+            throw std::domain_error( "Unable to load input file: " + _filename );
+
+        std::string line;
+        while( std::getline( f, line ) ) {
+            line = trim(line);
+            if( !line.empty() && !startsWith( line, '#' ) ) {
+                if( !startsWith( line, '"' ) )
+                    line = '"' + line + '"';
+                addTestOrTags( config, line + ',' );
+            }
+        }
+    }
+
+    inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
+
+        using namespace Clara;
+        CommandLine<ConfigData> cli;
+
+        cli.bindProcessName( &ConfigData::processName );
+
+        cli["-?"]["-h"]["--help"]
+            .describe( "display usage information" )
+            .bind( &ConfigData::showHelp );
+
+        cli["-l"]["--list-tests"]
+            .describe( "list all/matching test cases" )
+            .bind( &ConfigData::listTests );
+
+        cli["-t"]["--list-tags"]
+            .describe( "list all/matching tags" )
+            .bind( &ConfigData::listTags );
+
+        cli["-s"]["--success"]
+            .describe( "include successful tests in output" )
+            .bind( &ConfigData::showSuccessfulTests );
+
+        cli["-b"]["--break"]
+            .describe( "break into debugger on failure" )
+            .bind( &ConfigData::shouldDebugBreak );
+
+        cli["-e"]["--nothrow"]
+            .describe( "skip exception tests" )
+            .bind( &ConfigData::noThrow );
+
+        cli["-i"]["--invisibles"]
+            .describe( "show invisibles (tabs, newlines)" )
+            .bind( &ConfigData::showInvisibles );
+
+        cli["-o"]["--out"]
+            .describe( "output filename" )
+            .bind( &ConfigData::outputFilename, "filename" );
+
+        cli["-r"]["--reporter"]
+//            .placeholder( "name[:filename]" )
+            .describe( "reporter to use (defaults to console)" )
+            .bind( &addReporterName, "name" );
+
+        cli["-n"]["--name"]
+            .describe( "suite name" )
+            .bind( &ConfigData::name, "name" );
+
+        cli["-a"]["--abort"]
+            .describe( "abort at first failure" )
+            .bind( &abortAfterFirst );
+
+        cli["-x"]["--abortx"]
+            .describe( "abort after x failures" )
+            .bind( &abortAfterX, "no. failures" );
+
+        cli["-w"]["--warn"]
+            .describe( "enable warnings" )
+            .bind( &addWarning, "warning name" );
+
+// - needs updating if reinstated
+//        cli.into( &setVerbosity )
+//            .describe( "level of verbosity (0=no output)" )
+//            .shortOpt( "v")
+//            .longOpt( "verbosity" )
+//            .placeholder( "level" );
+
+        cli[_]
+            .describe( "which test or tests to use" )
+            .bind( &addTestOrTags, "test name, pattern or tags" );
+
+        cli["-d"]["--durations"]
+            .describe( "show test durations" )
+            .bind( &setShowDurations, "yes|no" );
+
+        cli["-f"]["--input-file"]
+            .describe( "load test names to run from a file" )
+            .bind( &loadTestNamesFromFile, "filename" );
+
+        cli["-#"]["--filenames-as-tags"]
+            .describe( "adds a tag for the filename" )
+            .bind( &ConfigData::filenamesAsTags );
+
+        cli["-c"]["--section"]
+                .describe( "specify section to run" )
+                .bind( &addSectionToRun, "section name" );
+
+        // Less common commands which don't have a short form
+        cli["--list-test-names-only"]
+            .describe( "list all/matching test cases names only" )
+            .bind( &ConfigData::listTestNamesOnly );
+
+        cli["--list-reporters"]
+            .describe( "list all reporters" )
+            .bind( &ConfigData::listReporters );
+
+        cli["--order"]
+            .describe( "test case order (defaults to decl)" )
+            .bind( &setOrder, "decl|lex|rand" );
+
+        cli["--rng-seed"]
+            .describe( "set a specific seed for random numbers" )
+            .bind( &setRngSeed, "'time'|number" );
+
+        cli["--force-colour"]
+            .describe( "force colourised output (deprecated)" )
+            .bind( &forceColour );
+
+        cli["--use-colour"]
+            .describe( "should output be colourised" )
+            .bind( &setUseColour, "yes|no" );
+
+        return cli;
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_list.hpp
+#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
+
+// #included from: catch_text.h
+#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
+
+#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
+// #included from: ../external/tbc_text_format.h
+// Only use header guard if we are not using an outer namespace
+#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+#  ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#   define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#  endif
+# else
+#  define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+# endif
+#endif
+#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#include <string>
+#include <vector>
+#include <sstream>
+
+// Use optional outer namespace
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+    const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+    struct TextAttributes {
+        TextAttributes()
+        :   initialIndent( std::string::npos ),
+            indent( 0 ),
+            width( consoleWidth-1 )
+        {}
+
+        TextAttributes& setInitialIndent( std::size_t _value )  { initialIndent = _value; return *this; }
+        TextAttributes& setIndent( std::size_t _value )         { indent = _value; return *this; }
+        TextAttributes& setWidth( std::size_t _value )          { width = _value; return *this; }
+
+        std::size_t initialIndent;  // indent of first line, or npos
+        std::size_t indent;         // indent of subsequent lines, or all if initialIndent is npos
+        std::size_t width;          // maximum width of text, including indent. Longer text will wrap
+    };
+
+    class Text {
+    public:
+        Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
+        : attr( _attr )
+        {
+            const std::string wrappableBeforeChars = "[({<\t";
+            const std::string wrappableAfterChars = "])}>-,./|\\";
+            const std::string wrappableInsteadOfChars = " \n\r";
+            std::string indent = _attr.initialIndent != std::string::npos
+                ? std::string( _attr.initialIndent, ' ' )
+                : std::string( _attr.indent, ' ' );
+
+            typedef std::string::const_iterator iterator;
+            iterator it = _str.begin();
+            const iterator strEnd = _str.end();
+
+            while( it != strEnd ) {
+
+                if( lines.size() >= 1000 ) {
+                    lines.push_back( "... message truncated due to excessive size" );
+                    return;
+                }
+
+                std::string suffix;
+                std::size_t width = (std::min)( static_cast<size_t>( strEnd-it ), _attr.width-static_cast<size_t>( indent.size() ) );
+                iterator itEnd = it+width;
+                iterator itNext = _str.end();
+
+                iterator itNewLine = std::find( it, itEnd, '\n' );
+                if( itNewLine != itEnd )
+                    itEnd = itNewLine;
+
+                if( itEnd != strEnd  ) {
+                    bool foundWrapPoint = false;
+                    iterator findIt = itEnd;
+                    do {
+                        if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) {
+                            itEnd = findIt+1;
+                            itNext = findIt+1;
+                            foundWrapPoint = true;
+                        }
+                        else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) {
+                            itEnd = findIt;
+                            itNext = findIt;
+                            foundWrapPoint = true;
+                        }
+                        else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) {
+                            itNext = findIt+1;
+                            itEnd = findIt;
+                            foundWrapPoint = true;
+                        }
+                        if( findIt == it )
+                            break;
+                        else
+                            --findIt;
+                    }
+                    while( !foundWrapPoint );
+
+                    if( !foundWrapPoint ) {
+                        // No good wrap char, so we'll break mid word and add a hyphen
+                        --itEnd;
+                        itNext = itEnd;
+                        suffix = "-";
+                    }
+                    else {
+                        while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos )
+                            --itEnd;
+                    }
+                }
+                lines.push_back( indent + std::string( it, itEnd ) + suffix );
+
+                if( indent.size() != _attr.indent )
+                    indent = std::string( _attr.indent, ' ' );
+                it = itNext;
+            }
+        }
+
+        typedef std::vector<std::string>::const_iterator const_iterator;
+
+        const_iterator begin() const { return lines.begin(); }
+        const_iterator end() const { return lines.end(); }
+        std::string const& last() const { return lines.back(); }
+        std::size_t size() const { return lines.size(); }
+        std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << *this;
+            return oss.str();
+        }
+
+        inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+            for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
+                it != itEnd; ++it ) {
+                if( it != _text.begin() )
+                    _stream << "\n";
+                _stream << *it;
+            }
+            return _stream;
+        }
+
+    private:
+        std::string str;
+        TextAttributes attr;
+        std::vector<std::string> lines;
+    };
+
+} // end namespace Tbc
+
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+
+namespace Catch {
+    using Tbc::Text;
+    using Tbc::TextAttributes;
+}
+
+// #included from: catch_console_colour.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
+
+namespace Catch {
+
+    struct Colour {
+        enum Code {
+            None = 0,
+
+            White,
+            Red,
+            Green,
+            Blue,
+            Cyan,
+            Yellow,
+            Grey,
+
+            Bright = 0x10,
+
+            BrightRed = Bright | Red,
+            BrightGreen = Bright | Green,
+            LightGrey = Bright | Grey,
+            BrightWhite = Bright | White,
+
+            // By intention
+            FileName = LightGrey,
+            Warning = Yellow,
+            ResultError = BrightRed,
+            ResultSuccess = BrightGreen,
+            ResultExpectedFailure = Warning,
+
+            Error = BrightRed,
+            Success = Green,
+
+            OriginalExpression = Cyan,
+            ReconstructedExpression = Yellow,
+
+            SecondaryText = LightGrey,
+            Headers = White
+        };
+
+        // Use constructed object for RAII guard
+        Colour( Code _colourCode );
+        Colour( Colour const& other );
+        ~Colour();
+
+        // Use static method for one-shot changes
+        static void use( Code _colourCode );
+
+    private:
+        bool m_moved;
+    };
+
+    inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; }
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_reporter.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
+
+#include <string>
+#include <ostream>
+#include <map>
+
+namespace Catch
+{
+    struct ReporterConfig {
+        explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig )
+        :   m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
+
+        ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream )
+        :   m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
+
+        std::ostream& stream() const    { return *m_stream; }
+        Ptr<IConfig const> fullConfig() const { return m_fullConfig; }
+
+    private:
+        std::ostream* m_stream;
+        Ptr<IConfig const> m_fullConfig;
+    };
+
+    struct ReporterPreferences {
+        ReporterPreferences()
+        : shouldRedirectStdOut( false )
+        {}
+
+        bool shouldRedirectStdOut;
+    };
+
+    template<typename T>
+    struct LazyStat : Option<T> {
+        LazyStat() : used( false ) {}
+        LazyStat& operator=( T const& _value ) {
+            Option<T>::operator=( _value );
+            used = false;
+            return *this;
+        }
+        void reset() {
+            Option<T>::reset();
+            used = false;
+        }
+        bool used;
+    };
+
+    struct TestRunInfo {
+        TestRunInfo( std::string const& _name ) : name( _name ) {}
+        std::string name;
+    };
+    struct GroupInfo {
+        GroupInfo(  std::string const& _name,
+                    std::size_t _groupIndex,
+                    std::size_t _groupsCount )
+        :   name( _name ),
+            groupIndex( _groupIndex ),
+            groupsCounts( _groupsCount )
+        {}
+
+        std::string name;
+        std::size_t groupIndex;
+        std::size_t groupsCounts;
+    };
+
+    struct AssertionStats {
+        AssertionStats( AssertionResult const& _assertionResult,
+                        std::vector<MessageInfo> const& _infoMessages,
+                        Totals const& _totals )
+        :   assertionResult( _assertionResult ),
+            infoMessages( _infoMessages ),
+            totals( _totals )
+        {
+            if( assertionResult.hasMessage() ) {
+                // Copy message into messages list.
+                // !TBD This should have been done earlier, somewhere
+                MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
+                builder << assertionResult.getMessage();
+                builder.m_info.message = builder.m_stream.str();
+
+                infoMessages.push_back( builder.m_info );
+            }
+        }
+        virtual ~AssertionStats();
+
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        AssertionStats( AssertionStats const& )              = default;
+        AssertionStats( AssertionStats && )                  = default;
+        AssertionStats& operator = ( AssertionStats const& ) = default;
+        AssertionStats& operator = ( AssertionStats && )     = default;
+#  endif
+
+        AssertionResult assertionResult;
+        std::vector<MessageInfo> infoMessages;
+        Totals totals;
+    };
+
+    struct SectionStats {
+        SectionStats(   SectionInfo const& _sectionInfo,
+                        Counts const& _assertions,
+                        double _durationInSeconds,
+                        bool _missingAssertions )
+        :   sectionInfo( _sectionInfo ),
+            assertions( _assertions ),
+            durationInSeconds( _durationInSeconds ),
+            missingAssertions( _missingAssertions )
+        {}
+        virtual ~SectionStats();
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        SectionStats( SectionStats const& )              = default;
+        SectionStats( SectionStats && )                  = default;
+        SectionStats& operator = ( SectionStats const& ) = default;
+        SectionStats& operator = ( SectionStats && )     = default;
+#  endif
+
+        SectionInfo sectionInfo;
+        Counts assertions;
+        double durationInSeconds;
+        bool missingAssertions;
+    };
+
+    struct TestCaseStats {
+        TestCaseStats(  TestCaseInfo const& _testInfo,
+                        Totals const& _totals,
+                        std::string const& _stdOut,
+                        std::string const& _stdErr,
+                        bool _aborting )
+        : testInfo( _testInfo ),
+            totals( _totals ),
+            stdOut( _stdOut ),
+            stdErr( _stdErr ),
+            aborting( _aborting )
+        {}
+        virtual ~TestCaseStats();
+
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        TestCaseStats( TestCaseStats const& )              = default;
+        TestCaseStats( TestCaseStats && )                  = default;
+        TestCaseStats& operator = ( TestCaseStats const& ) = default;
+        TestCaseStats& operator = ( TestCaseStats && )     = default;
+#  endif
+
+        TestCaseInfo testInfo;
+        Totals totals;
+        std::string stdOut;
+        std::string stdErr;
+        bool aborting;
+    };
+
+    struct TestGroupStats {
+        TestGroupStats( GroupInfo const& _groupInfo,
+                        Totals const& _totals,
+                        bool _aborting )
+        :   groupInfo( _groupInfo ),
+            totals( _totals ),
+            aborting( _aborting )
+        {}
+        TestGroupStats( GroupInfo const& _groupInfo )
+        :   groupInfo( _groupInfo ),
+            aborting( false )
+        {}
+        virtual ~TestGroupStats();
+
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        TestGroupStats( TestGroupStats const& )              = default;
+        TestGroupStats( TestGroupStats && )                  = default;
+        TestGroupStats& operator = ( TestGroupStats const& ) = default;
+        TestGroupStats& operator = ( TestGroupStats && )     = default;
+#  endif
+
+        GroupInfo groupInfo;
+        Totals totals;
+        bool aborting;
+    };
+
+    struct TestRunStats {
+        TestRunStats(   TestRunInfo const& _runInfo,
+                        Totals const& _totals,
+                        bool _aborting )
+        :   runInfo( _runInfo ),
+            totals( _totals ),
+            aborting( _aborting )
+        {}
+        virtual ~TestRunStats();
+
+#  ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        TestRunStats( TestRunStats const& _other )
+        :   runInfo( _other.runInfo ),
+            totals( _other.totals ),
+            aborting( _other.aborting )
+        {}
+#  else
+        TestRunStats( TestRunStats const& )              = default;
+        TestRunStats( TestRunStats && )                  = default;
+        TestRunStats& operator = ( TestRunStats const& ) = default;
+        TestRunStats& operator = ( TestRunStats && )     = default;
+#  endif
+
+        TestRunInfo runInfo;
+        Totals totals;
+        bool aborting;
+    };
+
+    class MultipleReporters;
+
+    struct IStreamingReporter : IShared {
+        virtual ~IStreamingReporter();
+
+        // Implementing class must also provide the following static method:
+        // static std::string getDescription();
+
+        virtual ReporterPreferences getPreferences() const = 0;
+
+        virtual void noMatchingTestCases( std::string const& spec ) = 0;
+
+        virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
+
+        virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
+
+        virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
+
+        // The return value indicates if the messages buffer should be cleared:
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
+
+        virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
+        virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
+
+        virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
+
+        virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
+    };
+
+    struct IReporterFactory : IShared {
+        virtual ~IReporterFactory();
+        virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
+        virtual std::string getDescription() const = 0;
+    };
+
+    struct IReporterRegistry {
+        typedef std::map<std::string, Ptr<IReporterFactory> > FactoryMap;
+        typedef std::vector<Ptr<IReporterFactory> > Listeners;
+
+        virtual ~IReporterRegistry();
+        virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const = 0;
+        virtual FactoryMap const& getFactories() const = 0;
+        virtual Listeners const& getListeners() const = 0;
+    };
+
+    Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter );
+
+}
+
+#include <limits>
+#include <algorithm>
+
+namespace Catch {
+
+    inline std::size_t listTests( Config const& config ) {
+
+        TestSpec testSpec = config.testSpec();
+        if( config.testSpec().hasFilters() )
+            Catch::cout() << "Matching test cases:\n";
+        else {
+            Catch::cout() << "All available test cases:\n";
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        }
+
+        std::size_t matchedTests = 0;
+        TextAttributes nameAttr, tagsAttr;
+        nameAttr.setInitialIndent( 2 ).setIndent( 4 );
+        tagsAttr.setIndent( 6 );
+
+        std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            matchedTests++;
+            TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+            Colour::Code colour = testCaseInfo.isHidden()
+                ? Colour::SecondaryText
+                : Colour::None;
+            Colour colourGuard( colour );
+
+            Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl;
+            if( !testCaseInfo.tags.empty() )
+                Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
+        }
+
+        if( !config.testSpec().hasFilters() )
+            Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl;
+        else
+            Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl;
+        return matchedTests;
+    }
+
+    inline std::size_t listTestsNamesOnly( Config const& config ) {
+        TestSpec testSpec = config.testSpec();
+        if( !config.testSpec().hasFilters() )
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        std::size_t matchedTests = 0;
+        std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            matchedTests++;
+            TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+            if( startsWith( testCaseInfo.name, '#' ) )
+               Catch::cout() << '"' << testCaseInfo.name << '"' << std::endl;
+            else
+               Catch::cout() << testCaseInfo.name << std::endl;
+        }
+        return matchedTests;
+    }
+
+    struct TagInfo {
+        TagInfo() : count ( 0 ) {}
+        void add( std::string const& spelling ) {
+            ++count;
+            spellings.insert( spelling );
+        }
+        std::string all() const {
+            std::string out;
+            for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
+                        it != itEnd;
+                        ++it )
+                out += "[" + *it + "]";
+            return out;
+        }
+        std::set<std::string> spellings;
+        std::size_t count;
+    };
+
+    inline std::size_t listTags( Config const& config ) {
+        TestSpec testSpec = config.testSpec();
+        if( config.testSpec().hasFilters() )
+            Catch::cout() << "Tags for matching test cases:\n";
+        else {
+            Catch::cout() << "All available tags:\n";
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        }
+
+        std::map<std::string, TagInfo> tagCounts;
+
+        std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            for( std::set<std::string>::const_iterator  tagIt = it->getTestCaseInfo().tags.begin(),
+                                                        tagItEnd = it->getTestCaseInfo().tags.end();
+                    tagIt != tagItEnd;
+                    ++tagIt ) {
+                std::string tagName = *tagIt;
+                std::string lcaseTagName = toLower( tagName );
+                std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName );
+                if( countIt == tagCounts.end() )
+                    countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
+                countIt->second.add( tagName );
+            }
+        }
+
+        for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
+                                                            countItEnd = tagCounts.end();
+                countIt != countItEnd;
+                ++countIt ) {
+            std::ostringstream oss;
+            oss << "  " << std::setw(2) << countIt->second.count << "  ";
+            Text wrapper( countIt->second.all(), TextAttributes()
+                                                    .setInitialIndent( 0 )
+                                                    .setIndent( oss.str().size() )
+                                                    .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
+            Catch::cout() << oss.str() << wrapper << '\n';
+        }
+        Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
+        return tagCounts.size();
+    }
+
+    inline std::size_t listReporters( Config const& /*config*/ ) {
+        Catch::cout() << "Available reporters:\n";
+        IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+        IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
+        std::size_t maxNameLen = 0;
+        for(it = itBegin; it != itEnd; ++it )
+            maxNameLen = (std::max)( maxNameLen, it->first.size() );
+
+        for(it = itBegin; it != itEnd; ++it ) {
+            Text wrapper( it->second->getDescription(), TextAttributes()
+                                                        .setInitialIndent( 0 )
+                                                        .setIndent( 7+maxNameLen )
+                                                        .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
+            Catch::cout() << "  "
+                    << it->first
+                    << ':'
+                    << std::string( maxNameLen - it->first.size() + 2, ' ' )
+                    << wrapper << '\n';
+        }
+        Catch::cout() << std::endl;
+        return factories.size();
+    }
+
+    inline Option<std::size_t> list( Config const& config ) {
+        Option<std::size_t> listedCount;
+        if( config.listTests() )
+            listedCount = listedCount.valueOr(0) + listTests( config );
+        if( config.listTestNamesOnly() )
+            listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
+        if( config.listTags() )
+            listedCount = listedCount.valueOr(0) + listTags( config );
+        if( config.listReporters() )
+            listedCount = listedCount.valueOr(0) + listReporters( config );
+        return listedCount;
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_run_context.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
+
+// #included from: catch_test_case_tracker.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
+
+#include <algorithm>
+#include <string>
+#include <assert.h>
+#include <vector>
+#include <stdexcept>
+
+CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
+
+namespace Catch {
+namespace TestCaseTracking {
+
+    struct NameAndLocation {
+        std::string name;
+        SourceLineInfo location;
+
+        NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
+        :   name( _name ),
+            location( _location )
+        {}
+    };
+
+    struct ITracker : SharedImpl<> {
+        virtual ~ITracker();
+
+        // static queries
+        virtual NameAndLocation const& nameAndLocation() const = 0;
+
+        // dynamic queries
+        virtual bool isComplete() const = 0; // Successfully completed or failed
+        virtual bool isSuccessfullyCompleted() const = 0;
+        virtual bool isOpen() const = 0; // Started but not complete
+        virtual bool hasChildren() const = 0;
+
+        virtual ITracker& parent() = 0;
+
+        // actions
+        virtual void close() = 0; // Successfully complete
+        virtual void fail() = 0;
+        virtual void markAsNeedingAnotherRun() = 0;
+
+        virtual void addChild( Ptr<ITracker> const& child ) = 0;
+        virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0;
+        virtual void openChild() = 0;
+
+        // Debug/ checking
+        virtual bool isSectionTracker() const = 0;
+        virtual bool isIndexTracker() const = 0;
+    };
+
+    class  TrackerContext {
+
+        enum RunState {
+            NotStarted,
+            Executing,
+            CompletedCycle
+        };
+
+        Ptr<ITracker> m_rootTracker;
+        ITracker* m_currentTracker;
+        RunState m_runState;
+
+    public:
+
+        static TrackerContext& instance() {
+            static TrackerContext s_instance;
+            return s_instance;
+        }
+
+        TrackerContext()
+        :   m_currentTracker( CATCH_NULL ),
+            m_runState( NotStarted )
+        {}
+
+        ITracker& startRun();
+
+        void endRun() {
+            m_rootTracker.reset();
+            m_currentTracker = CATCH_NULL;
+            m_runState = NotStarted;
+        }
+
+        void startCycle() {
+            m_currentTracker = m_rootTracker.get();
+            m_runState = Executing;
+        }
+        void completeCycle() {
+            m_runState = CompletedCycle;
+        }
+
+        bool completedCycle() const {
+            return m_runState == CompletedCycle;
+        }
+        ITracker& currentTracker() {
+            return *m_currentTracker;
+        }
+        void setCurrentTracker( ITracker* tracker ) {
+            m_currentTracker = tracker;
+        }
+    };
+
+    class TrackerBase : public ITracker {
+    protected:
+        enum CycleState {
+            NotStarted,
+            Executing,
+            ExecutingChildren,
+            NeedsAnotherRun,
+            CompletedSuccessfully,
+            Failed
+        };
+        class TrackerHasName {
+            NameAndLocation m_nameAndLocation;
+        public:
+            TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
+            bool operator ()( Ptr<ITracker> const& tracker ) {
+                return
+                    tracker->nameAndLocation().name == m_nameAndLocation.name &&
+                    tracker->nameAndLocation().location == m_nameAndLocation.location;
+            }
+        };
+        typedef std::vector<Ptr<ITracker> > Children;
+        NameAndLocation m_nameAndLocation;
+        TrackerContext& m_ctx;
+        ITracker* m_parent;
+        Children m_children;
+        CycleState m_runState;
+    public:
+        TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+        :   m_nameAndLocation( nameAndLocation ),
+            m_ctx( ctx ),
+            m_parent( parent ),
+            m_runState( NotStarted )
+        {}
+        virtual ~TrackerBase();
+
+        virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE {
+            return m_nameAndLocation;
+        }
+        virtual bool isComplete() const CATCH_OVERRIDE {
+            return m_runState == CompletedSuccessfully || m_runState == Failed;
+        }
+        virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE {
+            return m_runState == CompletedSuccessfully;
+        }
+        virtual bool isOpen() const CATCH_OVERRIDE {
+            return m_runState != NotStarted && !isComplete();
+        }
+        virtual bool hasChildren() const CATCH_OVERRIDE {
+            return !m_children.empty();
+        }
+
+        virtual void addChild( Ptr<ITracker> const& child ) CATCH_OVERRIDE {
+            m_children.push_back( child );
+        }
+
+        virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE {
+            Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) );
+            return( it != m_children.end() )
+                ? it->get()
+                : CATCH_NULL;
+        }
+        virtual ITracker& parent() CATCH_OVERRIDE {
+            assert( m_parent ); // Should always be non-null except for root
+            return *m_parent;
+        }
+
+        virtual void openChild() CATCH_OVERRIDE {
+            if( m_runState != ExecutingChildren ) {
+                m_runState = ExecutingChildren;
+                if( m_parent )
+                    m_parent->openChild();
+            }
+        }
+
+        virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; }
+        virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; }
+
+        void open() {
+            m_runState = Executing;
+            moveToThis();
+            if( m_parent )
+                m_parent->openChild();
+        }
+
+        virtual void close() CATCH_OVERRIDE {
+
+            // Close any still open children (e.g. generators)
+            while( &m_ctx.currentTracker() != this )
+                m_ctx.currentTracker().close();
+
+            switch( m_runState ) {
+                case NotStarted:
+                case CompletedSuccessfully:
+                case Failed:
+                    throw std::logic_error( "Illogical state" );
+
+                case NeedsAnotherRun:
+                    break;;
+
+                case Executing:
+                    m_runState = CompletedSuccessfully;
+                    break;
+                case ExecutingChildren:
+                    if( m_children.empty() || m_children.back()->isComplete() )
+                        m_runState = CompletedSuccessfully;
+                    break;
+
+                default:
+                    throw std::logic_error( "Unexpected state" );
+            }
+            moveToParent();
+            m_ctx.completeCycle();
+        }
+        virtual void fail() CATCH_OVERRIDE {
+            m_runState = Failed;
+            if( m_parent )
+                m_parent->markAsNeedingAnotherRun();
+            moveToParent();
+            m_ctx.completeCycle();
+        }
+        virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE {
+            m_runState = NeedsAnotherRun;
+        }
+    private:
+        void moveToParent() {
+            assert( m_parent );
+            m_ctx.setCurrentTracker( m_parent );
+        }
+        void moveToThis() {
+            m_ctx.setCurrentTracker( this );
+        }
+    };
+
+    class SectionTracker : public TrackerBase {
+        std::vector<std::string> m_filters;
+    public:
+        SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+        :   TrackerBase( nameAndLocation, ctx, parent )
+        {
+            if( parent ) {
+                while( !parent->isSectionTracker() )
+                    parent = &parent->parent();
+
+                SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
+                addNextFilters( parentSection.m_filters );
+            }
+        }
+        virtual ~SectionTracker();
+
+        virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
+
+        static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
+            SectionTracker* section = CATCH_NULL;
+
+            ITracker& currentTracker = ctx.currentTracker();
+            if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
+                assert( childTracker );
+                assert( childTracker->isSectionTracker() );
+                section = static_cast<SectionTracker*>( childTracker );
+            }
+            else {
+                section = new SectionTracker( nameAndLocation, ctx, &currentTracker );
+                currentTracker.addChild( section );
+            }
+            if( !ctx.completedCycle() )
+                section->tryOpen();
+            return *section;
+        }
+
+        void tryOpen() {
+            if( !isComplete() && (m_filters.empty() || m_filters[0].empty() ||  m_filters[0] == m_nameAndLocation.name ) )
+                open();
+        }
+
+        void addInitialFilters( std::vector<std::string> const& filters ) {
+            if( !filters.empty() ) {
+                m_filters.push_back(""); // Root - should never be consulted
+                m_filters.push_back(""); // Test Case - not a section filter
+                m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
+            }
+        }
+        void addNextFilters( std::vector<std::string> const& filters ) {
+            if( filters.size() > 1 )
+                m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
+        }
+    };
+
+    class IndexTracker : public TrackerBase {
+        int m_size;
+        int m_index;
+    public:
+        IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
+        :   TrackerBase( nameAndLocation, ctx, parent ),
+            m_size( size ),
+            m_index( -1 )
+        {}
+        virtual ~IndexTracker();
+
+        virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
+
+        static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
+            IndexTracker* tracker = CATCH_NULL;
+
+            ITracker& currentTracker = ctx.currentTracker();
+            if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
+                assert( childTracker );
+                assert( childTracker->isIndexTracker() );
+                tracker = static_cast<IndexTracker*>( childTracker );
+            }
+            else {
+                tracker = new IndexTracker( nameAndLocation, ctx, &currentTracker, size );
+                currentTracker.addChild( tracker );
+            }
+
+            if( !ctx.completedCycle() && !tracker->isComplete() ) {
+                if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
+                    tracker->moveNext();
+                tracker->open();
+            }
+
+            return *tracker;
+        }
+
+        int index() const { return m_index; }
+
+        void moveNext() {
+            m_index++;
+            m_children.clear();
+        }
+
+        virtual void close() CATCH_OVERRIDE {
+            TrackerBase::close();
+            if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
+                m_runState = Executing;
+        }
+    };
+
+    inline ITracker& TrackerContext::startRun() {
+        m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL );
+        m_currentTracker = CATCH_NULL;
+        m_runState = Executing;
+        return *m_rootTracker;
+    }
+
+} // namespace TestCaseTracking
+
+using TestCaseTracking::ITracker;
+using TestCaseTracking::TrackerContext;
+using TestCaseTracking::SectionTracker;
+using TestCaseTracking::IndexTracker;
+
+} // namespace Catch
+
+CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
+// #included from: catch_fatal_condition.hpp
+#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
+
+namespace Catch {
+
+    // Report the error condition
+    inline void reportFatal( std::string const& message ) {
+        IContext& context = Catch::getCurrentContext();
+        IResultCapture* resultCapture = context.getResultCapture();
+        resultCapture->handleFatalErrorCondition( message );
+    }
+
+} // namespace Catch
+
+#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
+// #included from: catch_windows_h_proxy.h
+
+#define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED
+
+#ifdef CATCH_DEFINES_NOMINMAX
+#  define NOMINMAX
+#endif
+#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+#  define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+#ifdef CATCH_DEFINES_NOMINMAX
+#  undef NOMINMAX
+#endif
+#ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN
+#  undef WIN32_LEAN_AND_MEAN
+#endif
+
+
+#  if !defined ( CATCH_CONFIG_WINDOWS_SEH )
+
+namespace Catch {
+    struct FatalConditionHandler {
+        void reset() {}
+    };
+}
+
+#  else // CATCH_CONFIG_WINDOWS_SEH is defined
+
+namespace Catch {
+
+    struct SignalDefs { DWORD id; const char* name; };
+    extern SignalDefs signalDefs[];
+    // There is no 1-1 mapping between signals and windows exceptions.
+    // Windows can easily distinguish between SO and SigSegV,
+    // but SigInt, SigTerm, etc are handled differently.
+    SignalDefs signalDefs[] = {
+        { EXCEPTION_ILLEGAL_INSTRUCTION,  "SIGILL - Illegal instruction signal" },
+        { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
+        { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
+        { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
+    };
+
+    struct FatalConditionHandler {
+
+        static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
+            for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+                if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
+                    reportFatal(signalDefs[i].name);
+                }
+            }
+            // If its not an exception we care about, pass it along.
+            // This stops us from eating debugger breaks etc.
+            return EXCEPTION_CONTINUE_SEARCH;
+        }
+
+        FatalConditionHandler() {
+            isSet = true;
+            // 32k seems enough for Catch to handle stack overflow,
+            // but the value was found experimentally, so there is no strong guarantee
+            guaranteeSize = 32 * 1024;
+            exceptionHandlerHandle = CATCH_NULL;
+            // Register as first handler in current chain
+            exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
+            // Pass in guarantee size to be filled
+            SetThreadStackGuarantee(&guaranteeSize);
+        }
+
+        static void reset() {
+            if (isSet) {
+                // Unregister handler and restore the old guarantee
+                RemoveVectoredExceptionHandler(exceptionHandlerHandle);
+                SetThreadStackGuarantee(&guaranteeSize);
+                exceptionHandlerHandle = CATCH_NULL;
+                isSet = false;
+            }
+        }
+
+        ~FatalConditionHandler() {
+            reset();
+        }
+    private:
+        static bool isSet;
+        static ULONG guaranteeSize;
+        static PVOID exceptionHandlerHandle;
+    };
+
+    bool FatalConditionHandler::isSet = false;
+    ULONG FatalConditionHandler::guaranteeSize = 0;
+    PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL;
+
+} // namespace Catch
+
+#  endif // CATCH_CONFIG_WINDOWS_SEH
+
+#else // Not Windows - assumed to be POSIX compatible //////////////////////////
+
+#  if !defined(CATCH_CONFIG_POSIX_SIGNALS)
+
+namespace Catch {
+    struct FatalConditionHandler {
+        void reset() {}
+    };
+}
+
+#  else // CATCH_CONFIG_POSIX_SIGNALS is defined
+
+#include <signal.h>
+
+namespace Catch {
+
+    struct SignalDefs {
+        int id;
+        const char* name;
+    };
+    extern SignalDefs signalDefs[];
+    SignalDefs signalDefs[] = {
+            { SIGINT,  "SIGINT - Terminal interrupt signal" },
+            { SIGILL,  "SIGILL - Illegal instruction signal" },
+            { SIGFPE,  "SIGFPE - Floating point error signal" },
+            { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
+            { SIGTERM, "SIGTERM - Termination request signal" },
+            { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
+    };
+
+    struct FatalConditionHandler {
+
+        static bool isSet;
+        static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)];
+        static stack_t oldSigStack;
+        static char altStackMem[SIGSTKSZ];
+
+        static void handleSignal( int sig ) {
+            std::string name = "<unknown signal>";
+            for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+                SignalDefs &def = signalDefs[i];
+                if (sig == def.id) {
+                    name = def.name;
+                    break;
+                }
+            }
+            reset();
+            reportFatal(name);
+            raise( sig );
+        }
+
+        FatalConditionHandler() {
+            isSet = true;
+            stack_t sigStack;
+            sigStack.ss_sp = altStackMem;
+            sigStack.ss_size = SIGSTKSZ;
+            sigStack.ss_flags = 0;
+            sigaltstack(&sigStack, &oldSigStack);
+            struct sigaction sa = { 0 };
+
+            sa.sa_handler = handleSignal;
+            sa.sa_flags = SA_ONSTACK;
+            for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
+                sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
+            }
+        }
+
+        ~FatalConditionHandler() {
+            reset();
+        }
+        static void reset() {
+            if( isSet ) {
+                // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
+                for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
+                    sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL);
+                }
+                // Return the old stack
+                sigaltstack(&oldSigStack, CATCH_NULL);
+                isSet = false;
+            }
+        }
+    };
+
+    bool FatalConditionHandler::isSet = false;
+    struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
+    stack_t FatalConditionHandler::oldSigStack = {};
+    char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
+
+} // namespace Catch
+
+#  endif // CATCH_CONFIG_POSIX_SIGNALS
+
+#endif // not Windows
+
+#include <set>
+#include <string>
+
+namespace Catch {
+
+    class StreamRedirect {
+
+    public:
+        StreamRedirect( std::ostream& stream, std::string& targetString )
+        :   m_stream( stream ),
+            m_prevBuf( stream.rdbuf() ),
+            m_targetString( targetString )
+        {
+            stream.rdbuf( m_oss.rdbuf() );
+        }
+
+        ~StreamRedirect() {
+            m_targetString += m_oss.str();
+            m_stream.rdbuf( m_prevBuf );
+        }
+
+    private:
+        std::ostream& m_stream;
+        std::streambuf* m_prevBuf;
+        std::ostringstream m_oss;
+        std::string& m_targetString;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class RunContext : public IResultCapture, public IRunner {
+
+        RunContext( RunContext const& );
+        void operator =( RunContext const& );
+
+    public:
+
+        explicit RunContext( Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter )
+        :   m_runInfo( _config->name() ),
+            m_context( getCurrentMutableContext() ),
+            m_activeTestCase( CATCH_NULL ),
+            m_config( _config ),
+            m_reporter( reporter ),
+            m_shouldReportUnexpected ( true )
+        {
+            m_context.setRunner( this );
+            m_context.setConfig( m_config );
+            m_context.setResultCapture( this );
+            m_reporter->testRunStarting( m_runInfo );
+        }
+
+        virtual ~RunContext() {
+            m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
+        }
+
+        void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
+            m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
+        }
+        void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) {
+            m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) );
+        }
+
+        Totals runTest( TestCase const& testCase ) {
+            Totals prevTotals = m_totals;
+
+            std::string redirectedCout;
+            std::string redirectedCerr;
+
+            TestCaseInfo testInfo = testCase.getTestCaseInfo();
+
+            m_reporter->testCaseStarting( testInfo );
+
+            m_activeTestCase = &testCase;
+
+            do {
+                ITracker& rootTracker = m_trackerContext.startRun();
+                assert( rootTracker.isSectionTracker() );
+                static_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() );
+                do {
+                    m_trackerContext.startCycle();
+                    m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) );
+                    runCurrentTest( redirectedCout, redirectedCerr );
+                }
+                while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
+            }
+            // !TBD: deprecated - this will be replaced by indexed trackers
+            while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
+
+            Totals deltaTotals = m_totals.delta( prevTotals );
+            if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) {
+                deltaTotals.assertions.failed++;
+                deltaTotals.testCases.passed--;
+                deltaTotals.testCases.failed++;
+            }
+            m_totals.testCases += deltaTotals.testCases;
+            m_reporter->testCaseEnded( TestCaseStats(   testInfo,
+                                                        deltaTotals,
+                                                        redirectedCout,
+                                                        redirectedCerr,
+                                                        aborting() ) );
+
+            m_activeTestCase = CATCH_NULL;
+            m_testCaseTracker = CATCH_NULL;
+
+            return deltaTotals;
+        }
+
+        Ptr<IConfig const> config() const {
+            return m_config;
+        }
+
+    private: // IResultCapture
+
+        virtual void assertionEnded( AssertionResult const& result ) {
+            if( result.getResultType() == ResultWas::Ok ) {
+                m_totals.assertions.passed++;
+            }
+            else if( !result.isOk() ) {
+                m_totals.assertions.failed++;
+            }
+
+            // We have no use for the return value (whether messages should be cleared), because messages were made scoped
+            // and should be let to clear themselves out.
+            static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
+
+            // Reset working state
+            m_lastAssertionInfo = AssertionInfo( std::string(), m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
+            m_lastResult = result;
+        }
+
+        virtual bool sectionStarted (
+            SectionInfo const& sectionInfo,
+            Counts& assertions
+        )
+        {
+            ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) );
+            if( !sectionTracker.isOpen() )
+                return false;
+            m_activeSections.push_back( &sectionTracker );
+
+            m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
+
+            m_reporter->sectionStarting( sectionInfo );
+
+            assertions = m_totals.assertions;
+
+            return true;
+        }
+        bool testForMissingAssertions( Counts& assertions ) {
+            if( assertions.total() != 0 )
+                return false;
+            if( !m_config->warnAboutMissingAssertions() )
+                return false;
+            if( m_trackerContext.currentTracker().hasChildren() )
+                return false;
+            m_totals.assertions.failed++;
+            assertions.failed++;
+            return true;
+        }
+
+        virtual void sectionEnded( SectionEndInfo const& endInfo ) {
+            Counts assertions = m_totals.assertions - endInfo.prevAssertions;
+            bool missingAssertions = testForMissingAssertions( assertions );
+
+            if( !m_activeSections.empty() ) {
+                m_activeSections.back()->close();
+                m_activeSections.pop_back();
+            }
+
+            m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) );
+            m_messages.clear();
+        }
+
+        virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) {
+            if( m_unfinishedSections.empty() )
+                m_activeSections.back()->fail();
+            else
+                m_activeSections.back()->close();
+            m_activeSections.pop_back();
+
+            m_unfinishedSections.push_back( endInfo );
+        }
+
+        virtual void pushScopedMessage( MessageInfo const& message ) {
+            m_messages.push_back( message );
+        }
+
+        virtual void popScopedMessage( MessageInfo const& message ) {
+            m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() );
+        }
+
+        virtual std::string getCurrentTestName() const {
+            return m_activeTestCase
+                ? m_activeTestCase->getTestCaseInfo().name
+                : std::string();
+        }
+
+        virtual const AssertionResult* getLastResult() const {
+            return &m_lastResult;
+        }
+
+        virtual void exceptionEarlyReported() {
+            m_shouldReportUnexpected = false;
+        }
+
+        virtual void handleFatalErrorCondition( std::string const& message ) {
+            // Don't rebuild the result -- the stringification itself can cause more fatal errors
+            // Instead, fake a result data.
+            AssertionResultData tempResult;
+            tempResult.resultType = ResultWas::FatalErrorCondition;
+            tempResult.message = message;
+            AssertionResult result(m_lastAssertionInfo, tempResult);
+
+            getResultCapture().assertionEnded(result);
+
+            handleUnfinishedSections();
+
+            // Recreate section for test case (as we will lose the one that was in scope)
+            TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+            SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
+
+            Counts assertions;
+            assertions.failed = 1;
+            SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false );
+            m_reporter->sectionEnded( testCaseSectionStats );
+
+            TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
+
+            Totals deltaTotals;
+            deltaTotals.testCases.failed = 1;
+            m_reporter->testCaseEnded( TestCaseStats(   testInfo,
+                                                        deltaTotals,
+                                                        std::string(),
+                                                        std::string(),
+                                                        false ) );
+            m_totals.testCases.failed++;
+            testGroupEnded( std::string(), m_totals, 1, 1 );
+            m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
+        }
+
+    public:
+        // !TBD We need to do this another way!
+        bool aborting() const {
+            return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() );
+        }
+
+    private:
+
+        void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
+            TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+            SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
+            m_reporter->sectionStarting( testCaseSection );
+            Counts prevAssertions = m_totals.assertions;
+            double duration = 0;
+            m_shouldReportUnexpected = true;
+            try {
+                m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, std::string(), ResultDisposition::Normal );
+
+                seedRng( *m_config );
+
+                Timer timer;
+                timer.start();
+                if( m_reporter->getPreferences().shouldRedirectStdOut ) {
+                    StreamRedirect coutRedir( Catch::cout(), redirectedCout );
+                    StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr );
+                    invokeActiveTestCase();
+                }
+                else {
+                    invokeActiveTestCase();
+                }
+                duration = timer.getElapsedSeconds();
+            }
+            catch( TestFailureException& ) {
+                // This just means the test was aborted due to failure
+            }
+            catch(...) {
+                // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
+                // are reported without translation at the point of origin.
+                if (m_shouldReportUnexpected) {
+                    makeUnexpectedResultBuilder().useActiveException();
+                }
+            }
+            m_testCaseTracker->close();
+            handleUnfinishedSections();
+            m_messages.clear();
+
+            Counts assertions = m_totals.assertions - prevAssertions;
+            bool missingAssertions = testForMissingAssertions( assertions );
+
+            if( testCaseInfo.okToFail() ) {
+                std::swap( assertions.failedButOk, assertions.failed );
+                m_totals.assertions.failed -= assertions.failedButOk;
+                m_totals.assertions.failedButOk += assertions.failedButOk;
+            }
+
+            SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
+            m_reporter->sectionEnded( testCaseSectionStats );
+        }
+
+        void invokeActiveTestCase() {
+            FatalConditionHandler fatalConditionHandler; // Handle signals
+            m_activeTestCase->invoke();
+            fatalConditionHandler.reset();
+        }
+
+    private:
+
+        ResultBuilder makeUnexpectedResultBuilder() const {
+            return ResultBuilder(   m_lastAssertionInfo.macroName.c_str(),
+                                    m_lastAssertionInfo.lineInfo,
+                                    m_lastAssertionInfo.capturedExpression.c_str(),
+                                    m_lastAssertionInfo.resultDisposition );
+        }
+
+        void handleUnfinishedSections() {
+            // If sections ended prematurely due to an exception we stored their
+            // infos here so we can tear them down outside the unwind process.
+            for( std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
+                        itEnd = m_unfinishedSections.rend();
+                    it != itEnd;
+                    ++it )
+                sectionEnded( *it );
+            m_unfinishedSections.clear();
+        }
+
+        TestRunInfo m_runInfo;
+        IMutableContext& m_context;
+        TestCase const* m_activeTestCase;
+        ITracker* m_testCaseTracker;
+        ITracker* m_currentSectionTracker;
+        AssertionResult m_lastResult;
+
+        Ptr<IConfig const> m_config;
+        Totals m_totals;
+        Ptr<IStreamingReporter> m_reporter;
+        std::vector<MessageInfo> m_messages;
+        AssertionInfo m_lastAssertionInfo;
+        std::vector<SectionEndInfo> m_unfinishedSections;
+        std::vector<ITracker*> m_activeSections;
+        TrackerContext m_trackerContext;
+        bool m_shouldReportUnexpected;
+    };
+
+    IResultCapture& getResultCapture() {
+        if( IResultCapture* capture = getCurrentContext().getResultCapture() )
+            return *capture;
+        else
+            throw std::logic_error( "No result capture instance" );
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_version.h
+#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
+
+namespace Catch {
+
+    // Versioning information
+    struct Version {
+        Version(    unsigned int _majorVersion,
+                    unsigned int _minorVersion,
+                    unsigned int _patchNumber,
+                    char const * const _branchName,
+                    unsigned int _buildNumber );
+
+        unsigned int const majorVersion;
+        unsigned int const minorVersion;
+        unsigned int const patchNumber;
+
+        // buildNumber is only used if branchName is not null
+        char const * const branchName;
+        unsigned int const buildNumber;
+
+        friend std::ostream& operator << ( std::ostream& os, Version const& version );
+
+    private:
+        void operator=( Version const& );
+    };
+
+    inline Version libraryVersion();
+}
+
+#include <fstream>
+#include <stdlib.h>
+#include <limits>
+
+namespace Catch {
+
+    Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) {
+        Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() );
+        if( !reporter ) {
+            std::ostringstream oss;
+            oss << "No reporter registered with name: '" << reporterName << "'";
+            throw std::domain_error( oss.str() );
+        }
+        return reporter;
+    }
+
+    Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
+        std::vector<std::string> reporters = config->getReporterNames();
+        if( reporters.empty() )
+            reporters.push_back( "console" );
+
+        Ptr<IStreamingReporter> reporter;
+        for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
+                it != itEnd;
+                ++it )
+            reporter = addReporter( reporter, createReporter( *it, config ) );
+        return reporter;
+    }
+    Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) {
+        IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners();
+        for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end();
+                it != itEnd;
+                ++it )
+            reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) );
+        return reporters;
+    }
+
+    Totals runTests( Ptr<Config> const& config ) {
+
+        Ptr<IConfig const> iconfig = config.get();
+
+        Ptr<IStreamingReporter> reporter = makeReporter( config );
+        reporter = addListeners( iconfig, reporter );
+
+        RunContext context( iconfig, reporter );
+
+        Totals totals;
+
+        context.testGroupStarting( config->name(), 1, 1 );
+
+        TestSpec testSpec = config->testSpec();
+        if( !testSpec.hasFilters() )
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
+
+        std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig );
+        for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end();
+                it != itEnd;
+                ++it ) {
+            if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) )
+                totals += context.runTest( *it );
+            else
+                reporter->skipTest( *it );
+        }
+
+        context.testGroupEnded( iconfig->name(), totals, 1, 1 );
+        return totals;
+    }
+
+    void applyFilenamesAsTags( IConfig const& config ) {
+        std::vector<TestCase> const& tests = getAllTestCasesSorted( config );
+        for(std::size_t i = 0; i < tests.size(); ++i ) {
+            TestCase& test = const_cast<TestCase&>( tests[i] );
+            std::set<std::string> tags = test.tags;
+
+            std::string filename = test.lineInfo.file;
+            std::string::size_type lastSlash = filename.find_last_of( "\\/" );
+            if( lastSlash != std::string::npos )
+                filename = filename.substr( lastSlash+1 );
+
+            std::string::size_type lastDot = filename.find_last_of( "." );
+            if( lastDot != std::string::npos )
+                filename = filename.substr( 0, lastDot );
+
+            tags.insert( "#" + filename );
+            setTags( test, tags );
+        }
+    }
+
+    class Session : NonCopyable {
+        static bool alreadyInstantiated;
+
+    public:
+
+        struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
+
+        Session()
+        : m_cli( makeCommandLineParser() ) {
+            if( alreadyInstantiated ) {
+                std::string msg = "Only one instance of Catch::Session can ever be used";
+                Catch::cerr() << msg << std::endl;
+                throw std::logic_error( msg );
+            }
+            alreadyInstantiated = true;
+        }
+        ~Session() {
+            Catch::cleanUp();
+        }
+
+        void showHelp( std::string const& processName ) {
+            Catch::cout() << "\nCatch v" << libraryVersion() << "\n";
+
+            m_cli.usage( Catch::cout(), processName );
+            Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
+        }
+
+        int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
+            try {
+                m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
+                m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData );
+                if( m_configData.showHelp )
+                    showHelp( m_configData.processName );
+                m_config.reset();
+            }
+            catch( std::exception& ex ) {
+                {
+                    Colour colourGuard( Colour::Red );
+                    Catch::cerr()
+                        << "\nError(s) in input:\n"
+                        << Text( ex.what(), TextAttributes().setIndent(2) )
+                        << "\n\n";
+                }
+                m_cli.usage( Catch::cout(), m_configData.processName );
+                return (std::numeric_limits<int>::max)();
+            }
+            return 0;
+        }
+
+        void useConfigData( ConfigData const& _configData ) {
+            m_configData = _configData;
+            m_config.reset();
+        }
+
+        int run( int argc, char const* const* const argv ) {
+
+            int returnCode = applyCommandLine( argc, argv );
+            if( returnCode == 0 )
+                returnCode = run();
+            return returnCode;
+        }
+
+    #if defined(WIN32) && defined(UNICODE)
+        int run( int argc, wchar_t const* const* const argv ) {
+
+            char **utf8Argv = new char *[ argc ];
+
+            for ( int i = 0; i < argc; ++i ) {
+                int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
+
+                utf8Argv[ i ] = new char[ bufSize ];
+
+                WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
+            }
+
+            int returnCode = applyCommandLine( argc, utf8Argv );
+            if( returnCode == 0 )
+                returnCode = run();
+
+            for ( int i = 0; i < argc; ++i )
+                delete [] utf8Argv[ i ];
+
+            delete [] utf8Argv;
+
+            return returnCode;
+        }
+    #endif
+
+        int run() {
+            if( m_configData.showHelp )
+                return 0;
+
+            try
+            {
+                config(); // Force config to be constructed
+
+                seedRng( *m_config );
+
+                if( m_configData.filenamesAsTags )
+                    applyFilenamesAsTags( *m_config );
+
+                // Handle list request
+                if( Option<std::size_t> listed = list( config() ) )
+                    return static_cast<int>( *listed );
+
+                return static_cast<int>( runTests( m_config ).assertions.failed );
+            }
+            catch( std::exception& ex ) {
+                Catch::cerr() << ex.what() << std::endl;
+                return (std::numeric_limits<int>::max)();
+            }
+        }
+
+        Clara::CommandLine<ConfigData> const& cli() const {
+            return m_cli;
+        }
+        std::vector<Clara::Parser::Token> const& unusedTokens() const {
+            return m_unusedTokens;
+        }
+        ConfigData& configData() {
+            return m_configData;
+        }
+        Config& config() {
+            if( !m_config )
+                m_config = new Config( m_configData );
+            return *m_config;
+        }
+    private:
+        Clara::CommandLine<ConfigData> m_cli;
+        std::vector<Clara::Parser::Token> m_unusedTokens;
+        ConfigData m_configData;
+        Ptr<Config> m_config;
+    };
+
+    bool Session::alreadyInstantiated = false;
+
+} // end namespace Catch
+
+// #included from: catch_registry_hub.hpp
+#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
+
+// #included from: catch_test_case_registry_impl.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
+
+#include <vector>
+#include <set>
+#include <sstream>
+#include <algorithm>
+
+namespace Catch {
+
+    struct RandomNumberGenerator {
+        typedef std::ptrdiff_t result_type;
+
+        result_type operator()( result_type n ) const { return std::rand() % n; }
+
+#ifdef CATCH_CONFIG_CPP11_SHUFFLE
+        static constexpr result_type min() { return 0; }
+        static constexpr result_type max() { return 1000000; }
+        result_type operator()() const { return std::rand() % max(); }
+#endif
+        template<typename V>
+        static void shuffle( V& vector ) {
+            RandomNumberGenerator rng;
+#ifdef CATCH_CONFIG_CPP11_SHUFFLE
+            std::shuffle( vector.begin(), vector.end(), rng );
+#else
+            std::random_shuffle( vector.begin(), vector.end(), rng );
+#endif
+        }
+    };
+
+    inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
+
+        std::vector<TestCase> sorted = unsortedTestCases;
+
+        switch( config.runOrder() ) {
+            case RunTests::InLexicographicalOrder:
+                std::sort( sorted.begin(), sorted.end() );
+                break;
+            case RunTests::InRandomOrder:
+                {
+                    seedRng( config );
+                    RandomNumberGenerator::shuffle( sorted );
+                }
+                break;
+            case RunTests::InDeclarationOrder:
+                // already in declaration order
+                break;
+        }
+        return sorted;
+    }
+    bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
+        return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
+    }
+
+    void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
+        std::set<TestCase> seenFunctions;
+        for( std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end();
+            it != itEnd;
+            ++it ) {
+            std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it );
+            if( !prev.second ) {
+                std::ostringstream ss;
+
+                ss  << Colour( Colour::Red )
+                    << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
+                    << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n'
+                    << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
+
+                throw std::runtime_error(ss.str());
+            }
+        }
+    }
+
+    std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
+        std::vector<TestCase> filtered;
+        filtered.reserve( testCases.size() );
+        for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
+                it != itEnd;
+                ++it )
+            if( matchTest( *it, testSpec, config ) )
+                filtered.push_back( *it );
+        return filtered;
+    }
+    std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
+        return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
+    }
+
+    class TestRegistry : public ITestCaseRegistry {
+    public:
+        TestRegistry()
+        :   m_currentSortOrder( RunTests::InDeclarationOrder ),
+            m_unnamedCount( 0 )
+        {}
+        virtual ~TestRegistry();
+
+        virtual void registerTest( TestCase const& testCase ) {
+            std::string name = testCase.getTestCaseInfo().name;
+            if( name.empty() ) {
+                std::ostringstream oss;
+                oss << "Anonymous test case " << ++m_unnamedCount;
+                return registerTest( testCase.withName( oss.str() ) );
+            }
+            m_functions.push_back( testCase );
+        }
+
+        virtual std::vector<TestCase> const& getAllTests() const {
+            return m_functions;
+        }
+        virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const {
+            if( m_sortedFunctions.empty() )
+                enforceNoDuplicateTestCases( m_functions );
+
+            if(  m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
+                m_sortedFunctions = sortTests( config, m_functions );
+                m_currentSortOrder = config.runOrder();
+            }
+            return m_sortedFunctions;
+        }
+
+    private:
+        std::vector<TestCase> m_functions;
+        mutable RunTests::InWhatOrder m_currentSortOrder;
+        mutable std::vector<TestCase> m_sortedFunctions;
+        size_t m_unnamedCount;
+        std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class FreeFunctionTestCase : public SharedImpl<ITestCase> {
+    public:
+
+        FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
+
+        virtual void invoke() const {
+            m_fun();
+        }
+
+    private:
+        virtual ~FreeFunctionTestCase();
+
+        TestFunction m_fun;
+    };
+
+    inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
+        std::string className = classOrQualifiedMethodName;
+        if( startsWith( className, '&' ) )
+        {
+            std::size_t lastColons = className.rfind( "::" );
+            std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
+            if( penultimateColons == std::string::npos )
+                penultimateColons = 1;
+            className = className.substr( penultimateColons, lastColons-penultimateColons );
+        }
+        return className;
+    }
+
+    void registerTestCase
+        (   ITestCase* testCase,
+            char const* classOrQualifiedMethodName,
+            NameAndDesc const& nameAndDesc,
+            SourceLineInfo const& lineInfo ) {
+
+        getMutableRegistryHub().registerTest
+            ( makeTestCase
+                (   testCase,
+                    extractClassName( classOrQualifiedMethodName ),
+                    nameAndDesc.name,
+                    nameAndDesc.description,
+                    lineInfo ) );
+    }
+    void registerTestCaseFunction
+        (   TestFunction function,
+            SourceLineInfo const& lineInfo,
+            NameAndDesc const& nameAndDesc ) {
+        registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    AutoReg::AutoReg
+        (   TestFunction function,
+            SourceLineInfo const& lineInfo,
+            NameAndDesc const& nameAndDesc ) {
+        registerTestCaseFunction( function, lineInfo, nameAndDesc );
+    }
+
+    AutoReg::~AutoReg() {}
+
+} // end namespace Catch
+
+// #included from: catch_reporter_registry.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+    class ReporterRegistry : public IReporterRegistry {
+
+    public:
+
+        virtual ~ReporterRegistry() CATCH_OVERRIDE {}
+
+        virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const CATCH_OVERRIDE {
+            FactoryMap::const_iterator it =  m_factories.find( name );
+            if( it == m_factories.end() )
+                return CATCH_NULL;
+            return it->second->create( ReporterConfig( config ) );
+        }
+
+        void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) {
+            m_factories.insert( std::make_pair( name, factory ) );
+        }
+        void registerListener( Ptr<IReporterFactory> const& factory ) {
+            m_listeners.push_back( factory );
+        }
+
+        virtual FactoryMap const& getFactories() const CATCH_OVERRIDE {
+            return m_factories;
+        }
+        virtual Listeners const& getListeners() const CATCH_OVERRIDE {
+            return m_listeners;
+        }
+
+    private:
+        FactoryMap m_factories;
+        Listeners m_listeners;
+    };
+}
+
+// #included from: catch_exception_translator_registry.hpp
+#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
+
+#ifdef __OBJC__
+#import "Foundation/Foundation.h"
+#endif
+
+namespace Catch {
+
+    class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
+    public:
+        ~ExceptionTranslatorRegistry() {
+            deleteAll( m_translators );
+        }
+
+        virtual void registerTranslator( const IExceptionTranslator* translator ) {
+            m_translators.push_back( translator );
+        }
+
+        virtual std::string translateActiveException() const {
+            try {
+#ifdef __OBJC__
+                // In Objective-C try objective-c exceptions first
+                @try {
+                    return tryTranslators();
+                }
+                @catch (NSException *exception) {
+                    return Catch::toString( [exception description] );
+                }
+#else
+                return tryTranslators();
+#endif
+            }
+            catch( TestFailureException& ) {
+                throw;
+            }
+            catch( std::exception& ex ) {
+                return ex.what();
+            }
+            catch( std::string& msg ) {
+                return msg;
+            }
+            catch( const char* msg ) {
+                return msg;
+            }
+            catch(...) {
+                return "Unknown exception";
+            }
+        }
+
+        std::string tryTranslators() const {
+            if( m_translators.empty() )
+                throw;
+            else
+                return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
+        }
+
+    private:
+        std::vector<const IExceptionTranslator*> m_translators;
+    };
+}
+
+// #included from: catch_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+    class TagAliasRegistry : public ITagAliasRegistry {
+    public:
+        virtual ~TagAliasRegistry();
+        virtual Option<TagAlias> find( std::string const& alias ) const;
+        virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const;
+        void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
+
+    private:
+        std::map<std::string, TagAlias> m_registry;
+    };
+
+} // end namespace Catch
+
+namespace Catch {
+
+    namespace {
+
+        class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
+
+            RegistryHub( RegistryHub const& );
+            void operator=( RegistryHub const& );
+
+        public: // IRegistryHub
+            RegistryHub() {
+            }
+            virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE {
+                return m_reporterRegistry;
+            }
+            virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE {
+                return m_testCaseRegistry;
+            }
+            virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE {
+                return m_exceptionTranslatorRegistry;
+            }
+            virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE {
+                return m_tagAliasRegistry;
+            }
+
+        public: // IMutableRegistryHub
+            virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
+                m_reporterRegistry.registerReporter( name, factory );
+            }
+            virtual void registerListener( Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
+                m_reporterRegistry.registerListener( factory );
+            }
+            virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE {
+                m_testCaseRegistry.registerTest( testInfo );
+            }
+            virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE {
+                m_exceptionTranslatorRegistry.registerTranslator( translator );
+            }
+            virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE {
+                m_tagAliasRegistry.add( alias, tag, lineInfo );
+            }
+
+        private:
+            TestRegistry m_testCaseRegistry;
+            ReporterRegistry m_reporterRegistry;
+            ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
+            TagAliasRegistry m_tagAliasRegistry;
+        };
+
+        // Single, global, instance
+        inline RegistryHub*& getTheRegistryHub() {
+            static RegistryHub* theRegistryHub = CATCH_NULL;
+            if( !theRegistryHub )
+                theRegistryHub = new RegistryHub();
+            return theRegistryHub;
+        }
+    }
+
+    IRegistryHub& getRegistryHub() {
+        return *getTheRegistryHub();
+    }
+    IMutableRegistryHub& getMutableRegistryHub() {
+        return *getTheRegistryHub();
+    }
+    void cleanUp() {
+        delete getTheRegistryHub();
+        getTheRegistryHub() = CATCH_NULL;
+        cleanUpContext();
+    }
+    std::string translateActiveException() {
+        return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_notimplemented_exception.hpp
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
+
+#include <sstream>
+
+namespace Catch {
+
+    NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo )
+    :   m_lineInfo( lineInfo ) {
+        std::ostringstream oss;
+        oss << lineInfo << ": function ";
+        oss << "not implemented";
+        m_what = oss.str();
+    }
+
+    const char* NotImplementedException::what() const CATCH_NOEXCEPT {
+        return m_what.c_str();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_context_impl.hpp
+#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
+
+// #included from: catch_stream.hpp
+#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
+
+#include <stdexcept>
+#include <cstdio>
+#include <iostream>
+
+namespace Catch {
+
+    template<typename WriterF, size_t bufferSize=256>
+    class StreamBufImpl : public StreamBufBase {
+        char data[bufferSize];
+        WriterF m_writer;
+
+    public:
+        StreamBufImpl() {
+            setp( data, data + sizeof(data) );
+        }
+
+        ~StreamBufImpl() CATCH_NOEXCEPT {
+            sync();
+        }
+
+    private:
+        int overflow( int c ) {
+            sync();
+
+            if( c != EOF ) {
+                if( pbase() == epptr() )
+                    m_writer( std::string( 1, static_cast<char>( c ) ) );
+                else
+                    sputc( static_cast<char>( c ) );
+            }
+            return 0;
+        }
+
+        int sync() {
+            if( pbase() != pptr() ) {
+                m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
+                setp( pbase(), epptr() );
+            }
+            return 0;
+        }
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    FileStream::FileStream( std::string const& filename ) {
+        m_ofs.open( filename.c_str() );
+        if( m_ofs.fail() ) {
+            std::ostringstream oss;
+            oss << "Unable to open file: '" << filename << '\'';
+            throw std::domain_error( oss.str() );
+        }
+    }
+
+    std::ostream& FileStream::stream() const {
+        return m_ofs;
+    }
+
+    struct OutputDebugWriter {
+
+        void operator()( std::string const&str ) {
+            writeToDebugConsole( str );
+        }
+    };
+
+    DebugOutStream::DebugOutStream()
+    :   m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
+        m_os( m_streamBuf.get() )
+    {}
+
+    std::ostream& DebugOutStream::stream() const {
+        return m_os;
+    }
+
+    // Store the streambuf from cout up-front because
+    // cout may get redirected when running tests
+    CoutStream::CoutStream()
+    :   m_os( Catch::cout().rdbuf() )
+    {}
+
+    std::ostream& CoutStream::stream() const {
+        return m_os;
+    }
+
+#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
+    std::ostream& cout() {
+        return std::cout;
+    }
+    std::ostream& cerr() {
+        return std::cerr;
+    }
+#endif
+}
+
+namespace Catch {
+
+    class Context : public IMutableContext {
+
+        Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {}
+        Context( Context const& );
+        void operator=( Context const& );
+
+    public:
+        virtual ~Context() {
+            deleteAllValues( m_generatorsByTestName );
+        }
+
+    public: // IContext
+        virtual IResultCapture* getResultCapture() {
+            return m_resultCapture;
+        }
+        virtual IRunner* getRunner() {
+            return m_runner;
+        }
+        virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) {
+            return getGeneratorsForCurrentTest()
+            .getGeneratorInfo( fileInfo, totalSize )
+            .getCurrentIndex();
+        }
+        virtual bool advanceGeneratorsForCurrentTest() {
+            IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+            return generators && generators->moveNext();
+        }
+
+        virtual Ptr<IConfig const> getConfig() const {
+            return m_config;
+        }
+
+    public: // IMutableContext
+        virtual void setResultCapture( IResultCapture* resultCapture ) {
+            m_resultCapture = resultCapture;
+        }
+        virtual void setRunner( IRunner* runner ) {
+            m_runner = runner;
+        }
+        virtual void setConfig( Ptr<IConfig const> const& config ) {
+            m_config = config;
+        }
+
+        friend IMutableContext& getCurrentMutableContext();
+
+    private:
+        IGeneratorsForTest* findGeneratorsForCurrentTest() {
+            std::string testName = getResultCapture()->getCurrentTestName();
+
+            std::map<std::string, IGeneratorsForTest*>::const_iterator it =
+                m_generatorsByTestName.find( testName );
+            return it != m_generatorsByTestName.end()
+                ? it->second
+                : CATCH_NULL;
+        }
+
+        IGeneratorsForTest& getGeneratorsForCurrentTest() {
+            IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+            if( !generators ) {
+                std::string testName = getResultCapture()->getCurrentTestName();
+                generators = createGeneratorsForTest();
+                m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
+            }
+            return *generators;
+        }
+
+    private:
+        Ptr<IConfig const> m_config;
+        IRunner* m_runner;
+        IResultCapture* m_resultCapture;
+        std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
+    };
+
+    namespace {
+        Context* currentContext = CATCH_NULL;
+    }
+    IMutableContext& getCurrentMutableContext() {
+        if( !currentContext )
+            currentContext = new Context();
+        return *currentContext;
+    }
+    IContext& getCurrentContext() {
+        return getCurrentMutableContext();
+    }
+
+    void cleanUpContext() {
+        delete currentContext;
+        currentContext = CATCH_NULL;
+    }
+}
+
+// #included from: catch_console_colour_impl.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
+
+// #included from: catch_errno_guard.hpp
+#define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED
+
+#include <cerrno>
+
+namespace Catch {
+
+    class ErrnoGuard {
+    public:
+        ErrnoGuard():m_oldErrno(errno){}
+        ~ErrnoGuard() { errno = m_oldErrno; }
+    private:
+        int m_oldErrno;
+    };
+
+}
+
+namespace Catch {
+    namespace {
+
+        struct IColourImpl {
+            virtual ~IColourImpl() {}
+            virtual void use( Colour::Code _colourCode ) = 0;
+        };
+
+        struct NoColourImpl : IColourImpl {
+            void use( Colour::Code ) {}
+
+            static IColourImpl* instance() {
+                static NoColourImpl s_instance;
+                return &s_instance;
+            }
+        };
+
+    } // anon namespace
+} // namespace Catch
+
+#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI )
+#   ifdef CATCH_PLATFORM_WINDOWS
+#       define CATCH_CONFIG_COLOUR_WINDOWS
+#   else
+#       define CATCH_CONFIG_COLOUR_ANSI
+#   endif
+#endif
+
+#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
+
+namespace Catch {
+namespace {
+
+    class Win32ColourImpl : public IColourImpl {
+    public:
+        Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
+        {
+            CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+            GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
+            originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
+            originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
+        }
+
+        virtual void use( Colour::Code _colourCode ) {
+            switch( _colourCode ) {
+                case Colour::None:      return setTextAttribute( originalForegroundAttributes );
+                case Colour::White:     return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+                case Colour::Red:       return setTextAttribute( FOREGROUND_RED );
+                case Colour::Green:     return setTextAttribute( FOREGROUND_GREEN );
+                case Colour::Blue:      return setTextAttribute( FOREGROUND_BLUE );
+                case Colour::Cyan:      return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
+                case Colour::Yellow:    return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
+                case Colour::Grey:      return setTextAttribute( 0 );
+
+                case Colour::LightGrey:     return setTextAttribute( FOREGROUND_INTENSITY );
+                case Colour::BrightRed:     return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
+                case Colour::BrightGreen:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
+                case Colour::BrightWhite:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+
+                case Colour::Bright: throw std::logic_error( "not a colour" );
+            }
+        }
+
+    private:
+        void setTextAttribute( WORD _textAttribute ) {
+            SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes );
+        }
+        HANDLE stdoutHandle;
+        WORD originalForegroundAttributes;
+        WORD originalBackgroundAttributes;
+    };
+
+    IColourImpl* platformColourInstance() {
+        static Win32ColourImpl s_instance;
+
+        Ptr<IConfig const> config = getCurrentContext().getConfig();
+        UseColour::YesOrNo colourMode = config
+            ? config->useColour()
+            : UseColour::Auto;
+        if( colourMode == UseColour::Auto )
+            colourMode = !isDebuggerActive()
+                ? UseColour::Yes
+                : UseColour::No;
+        return colourMode == UseColour::Yes
+            ? &s_instance
+            : NoColourImpl::instance();
+    }
+
+} // end anon namespace
+} // end namespace Catch
+
+#elif defined( CATCH_CONFIG_COLOUR_ANSI ) //////////////////////////////////////
+
+#include <unistd.h>
+
+namespace Catch {
+namespace {
+
+    // use POSIX/ ANSI console terminal codes
+    // Thanks to Adam Strzelecki for original contribution
+    // (http://github.com/nanoant)
+    // https://github.com/philsquared/Catch/pull/131
+    class PosixColourImpl : public IColourImpl {
+    public:
+        virtual void use( Colour::Code _colourCode ) {
+            switch( _colourCode ) {
+                case Colour::None:
+                case Colour::White:     return setColour( "[0m" );
+                case Colour::Red:       return setColour( "[0;31m" );
+                case Colour::Green:     return setColour( "[0;32m" );
+                case Colour::Blue:      return setColour( "[0;34m" );
+                case Colour::Cyan:      return setColour( "[0;36m" );
+                case Colour::Yellow:    return setColour( "[0;33m" );
+                case Colour::Grey:      return setColour( "[1;30m" );
+
+                case Colour::LightGrey:     return setColour( "[0;37m" );
+                case Colour::BrightRed:     return setColour( "[1;31m" );
+                case Colour::BrightGreen:   return setColour( "[1;32m" );
+                case Colour::BrightWhite:   return setColour( "[1;37m" );
+
+                case Colour::Bright: throw std::logic_error( "not a colour" );
+            }
+        }
+        static IColourImpl* instance() {
+            static PosixColourImpl s_instance;
+            return &s_instance;
+        }
+
+    private:
+        void setColour( const char* _escapeCode ) {
+            Catch::cout() << '\033' << _escapeCode;
+        }
+    };
+
+    IColourImpl* platformColourInstance() {
+        ErrnoGuard guard;
+        Ptr<IConfig const> config = getCurrentContext().getConfig();
+        UseColour::YesOrNo colourMode = config
+            ? config->useColour()
+            : UseColour::Auto;
+        if( colourMode == UseColour::Auto )
+            colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) )
+                ? UseColour::Yes
+                : UseColour::No;
+        return colourMode == UseColour::Yes
+            ? PosixColourImpl::instance()
+            : NoColourImpl::instance();
+    }
+
+} // end anon namespace
+} // end namespace Catch
+
+#else  // not Windows or ANSI ///////////////////////////////////////////////
+
+namespace Catch {
+
+    static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
+
+} // end namespace Catch
+
+#endif // Windows/ ANSI/ None
+
+namespace Catch {
+
+    Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); }
+    Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; }
+    Colour::~Colour(){ if( !m_moved ) use( None ); }
+
+    void Colour::use( Code _colourCode ) {
+        static IColourImpl* impl = platformColourInstance();
+        impl->use( _colourCode );
+    }
+
+} // end namespace Catch
+
+// #included from: catch_generators_impl.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <map>
+
+namespace Catch {
+
+    struct GeneratorInfo : IGeneratorInfo {
+
+        GeneratorInfo( std::size_t size )
+        :   m_size( size ),
+            m_currentIndex( 0 )
+        {}
+
+        bool moveNext() {
+            if( ++m_currentIndex == m_size ) {
+                m_currentIndex = 0;
+                return false;
+            }
+            return true;
+        }
+
+        std::size_t getCurrentIndex() const {
+            return m_currentIndex;
+        }
+
+        std::size_t m_size;
+        std::size_t m_currentIndex;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class GeneratorsForTest : public IGeneratorsForTest {
+
+    public:
+        ~GeneratorsForTest() {
+            deleteAll( m_generatorsInOrder );
+        }
+
+        IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) {
+            std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
+            if( it == m_generatorsByName.end() ) {
+                IGeneratorInfo* info = new GeneratorInfo( size );
+                m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
+                m_generatorsInOrder.push_back( info );
+                return *info;
+            }
+            return *it->second;
+        }
+
+        bool moveNext() {
+            std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
+            std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
+            for(; it != itEnd; ++it ) {
+                if( (*it)->moveNext() )
+                    return true;
+            }
+            return false;
+        }
+
+    private:
+        std::map<std::string, IGeneratorInfo*> m_generatorsByName;
+        std::vector<IGeneratorInfo*> m_generatorsInOrder;
+    };
+
+    IGeneratorsForTest* createGeneratorsForTest()
+    {
+        return new GeneratorsForTest();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.hpp
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
+
+namespace Catch {
+
+    AssertionInfo::AssertionInfo(   std::string const& _macroName,
+                                    SourceLineInfo const& _lineInfo,
+                                    std::string const& _capturedExpression,
+                                    ResultDisposition::Flags _resultDisposition )
+    :   macroName( _macroName ),
+        lineInfo( _lineInfo ),
+        capturedExpression( _capturedExpression ),
+        resultDisposition( _resultDisposition )
+    {}
+
+    AssertionResult::AssertionResult() {}
+
+    AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
+    :   m_info( info ),
+        m_resultData( data )
+    {}
+
+    AssertionResult::~AssertionResult() {}
+
+    // Result was a success
+    bool AssertionResult::succeeded() const {
+        return Catch::isOk( m_resultData.resultType );
+    }
+
+    // Result was a success, or failure is suppressed
+    bool AssertionResult::isOk() const {
+        return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
+    }
+
+    ResultWas::OfType AssertionResult::getResultType() const {
+        return m_resultData.resultType;
+    }
+
+    bool AssertionResult::hasExpression() const {
+        return !m_info.capturedExpression.empty();
+    }
+
+    bool AssertionResult::hasMessage() const {
+        return !m_resultData.message.empty();
+    }
+
+    std::string AssertionResult::getExpression() const {
+        if( isFalseTest( m_info.resultDisposition ) )
+            return '!' + m_info.capturedExpression;
+        else
+            return m_info.capturedExpression;
+    }
+    std::string AssertionResult::getExpressionInMacro() const {
+        if( m_info.macroName.empty() )
+            return m_info.capturedExpression;
+        else
+            return m_info.macroName + "( " + m_info.capturedExpression + " )";
+    }
+
+    bool AssertionResult::hasExpandedExpression() const {
+        return hasExpression() && getExpandedExpression() != getExpression();
+    }
+
+    std::string AssertionResult::getExpandedExpression() const {
+        return m_resultData.reconstructExpression();
+    }
+
+    std::string AssertionResult::getMessage() const {
+        return m_resultData.message;
+    }
+    SourceLineInfo AssertionResult::getSourceInfo() const {
+        return m_info.lineInfo;
+    }
+
+    std::string AssertionResult::getTestMacroName() const {
+        return m_info.macroName;
+    }
+
+    void AssertionResult::discardDecomposedExpression() const {
+        m_resultData.decomposedExpression = CATCH_NULL;
+    }
+
+    void AssertionResult::expandDecomposedExpression() const {
+        m_resultData.reconstructExpression();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_test_case_info.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
+
+#include <cctype>
+
+namespace Catch {
+
+    inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
+        if( startsWith( tag, '.' ) ||
+            tag == "hide" ||
+            tag == "!hide" )
+            return TestCaseInfo::IsHidden;
+        else if( tag == "!throws" )
+            return TestCaseInfo::Throws;
+        else if( tag == "!shouldfail" )
+            return TestCaseInfo::ShouldFail;
+        else if( tag == "!mayfail" )
+            return TestCaseInfo::MayFail;
+        else if( tag == "!nonportable" )
+            return TestCaseInfo::NonPortable;
+        else
+            return TestCaseInfo::None;
+    }
+    inline bool isReservedTag( std::string const& tag ) {
+        return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] );
+    }
+    inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
+        if( isReservedTag( tag ) ) {
+            std::ostringstream ss;
+            ss << Colour(Colour::Red)
+               << "Tag name [" << tag << "] not allowed.\n"
+               << "Tag names starting with non alpha-numeric characters are reserved\n"
+               << Colour(Colour::FileName)
+               << _lineInfo << '\n';
+            throw std::runtime_error(ss.str());
+        }
+    }
+
+    TestCase makeTestCase(  ITestCase* _testCase,
+                            std::string const& _className,
+                            std::string const& _name,
+                            std::string const& _descOrTags,
+                            SourceLineInfo const& _lineInfo )
+    {
+        bool isHidden( startsWith( _name, "./" ) ); // Legacy support
+
+        // Parse out tags
+        std::set<std::string> tags;
+        std::string desc, tag;
+        bool inTag = false;
+        for( std::size_t i = 0; i < _descOrTags.size(); ++i ) {
+            char c = _descOrTags[i];
+            if( !inTag ) {
+                if( c == '[' )
+                    inTag = true;
+                else
+                    desc += c;
+            }
+            else {
+                if( c == ']' ) {
+                    TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag );
+                    if( prop == TestCaseInfo::IsHidden )
+                        isHidden = true;
+                    else if( prop == TestCaseInfo::None )
+                        enforceNotReservedTag( tag, _lineInfo );
+
+                    tags.insert( tag );
+                    tag.clear();
+                    inTag = false;
+                }
+                else
+                    tag += c;
+            }
+        }
+        if( isHidden ) {
+            tags.insert( "hide" );
+            tags.insert( "." );
+        }
+
+        TestCaseInfo info( _name, _className, desc, tags, _lineInfo );
+        return TestCase( _testCase, info );
+    }
+
+    void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags )
+    {
+        testCaseInfo.tags = tags;
+        testCaseInfo.lcaseTags.clear();
+
+        std::ostringstream oss;
+        for( std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) {
+            oss << '[' << *it << ']';
+            std::string lcaseTag = toLower( *it );
+            testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
+            testCaseInfo.lcaseTags.insert( lcaseTag );
+        }
+        testCaseInfo.tagsAsString = oss.str();
+    }
+
+    TestCaseInfo::TestCaseInfo( std::string const& _name,
+                                std::string const& _className,
+                                std::string const& _description,
+                                std::set<std::string> const& _tags,
+                                SourceLineInfo const& _lineInfo )
+    :   name( _name ),
+        className( _className ),
+        description( _description ),
+        lineInfo( _lineInfo ),
+        properties( None )
+    {
+        setTags( *this, _tags );
+    }
+
+    TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )
+    :   name( other.name ),
+        className( other.className ),
+        description( other.description ),
+        tags( other.tags ),
+        lcaseTags( other.lcaseTags ),
+        tagsAsString( other.tagsAsString ),
+        lineInfo( other.lineInfo ),
+        properties( other.properties )
+    {}
+
+    bool TestCaseInfo::isHidden() const {
+        return ( properties & IsHidden ) != 0;
+    }
+    bool TestCaseInfo::throws() const {
+        return ( properties & Throws ) != 0;
+    }
+    bool TestCaseInfo::okToFail() const {
+        return ( properties & (ShouldFail | MayFail ) ) != 0;
+    }
+    bool TestCaseInfo::expectedToFail() const {
+        return ( properties & (ShouldFail ) ) != 0;
+    }
+
+    TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
+
+    TestCase::TestCase( TestCase const& other )
+    :   TestCaseInfo( other ),
+        test( other.test )
+    {}
+
+    TestCase TestCase::withName( std::string const& _newName ) const {
+        TestCase other( *this );
+        other.name = _newName;
+        return other;
+    }
+
+    void TestCase::swap( TestCase& other ) {
+        test.swap( other.test );
+        name.swap( other.name );
+        className.swap( other.className );
+        description.swap( other.description );
+        tags.swap( other.tags );
+        lcaseTags.swap( other.lcaseTags );
+        tagsAsString.swap( other.tagsAsString );
+        std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties );
+        std::swap( lineInfo, other.lineInfo );
+    }
+
+    void TestCase::invoke() const {
+        test->invoke();
+    }
+
+    bool TestCase::operator == ( TestCase const& other ) const {
+        return  test.get() == other.test.get() &&
+                name == other.name &&
+                className == other.className;
+    }
+
+    bool TestCase::operator < ( TestCase const& other ) const {
+        return name < other.name;
+    }
+    TestCase& TestCase::operator = ( TestCase const& other ) {
+        TestCase temp( other );
+        swap( temp );
+        return *this;
+    }
+
+    TestCaseInfo const& TestCase::getTestCaseInfo() const
+    {
+        return *this;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_version.hpp
+#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
+
+namespace Catch {
+
+    Version::Version
+        (   unsigned int _majorVersion,
+            unsigned int _minorVersion,
+            unsigned int _patchNumber,
+            char const * const _branchName,
+            unsigned int _buildNumber )
+    :   majorVersion( _majorVersion ),
+        minorVersion( _minorVersion ),
+        patchNumber( _patchNumber ),
+        branchName( _branchName ),
+        buildNumber( _buildNumber )
+    {}
+
+    std::ostream& operator << ( std::ostream& os, Version const& version ) {
+        os  << version.majorVersion << '.'
+            << version.minorVersion << '.'
+            << version.patchNumber;
+        // branchName is never null -> 0th char is \0 if it is empty
+        if (version.branchName[0]) {
+            os << '-' << version.branchName
+               << '.' << version.buildNumber;
+        }
+        return os;
+    }
+
+    inline Version libraryVersion() {
+        static Version version( 1, 9, 4, "", 0 );
+        return version;
+    }
+
+}
+
+// #included from: catch_message.hpp
+#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
+
+namespace Catch {
+
+    MessageInfo::MessageInfo(   std::string const& _macroName,
+                                SourceLineInfo const& _lineInfo,
+                                ResultWas::OfType _type )
+    :   macroName( _macroName ),
+        lineInfo( _lineInfo ),
+        type( _type ),
+        sequence( ++globalCount )
+    {}
+
+    // This may need protecting if threading support is added
+    unsigned int MessageInfo::globalCount = 0;
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    ScopedMessage::ScopedMessage( MessageBuilder const& builder )
+    : m_info( builder.m_info )
+    {
+        m_info.message = builder.m_stream.str();
+        getResultCapture().pushScopedMessage( m_info );
+    }
+    ScopedMessage::ScopedMessage( ScopedMessage const& other )
+    : m_info( other.m_info )
+    {}
+
+    ScopedMessage::~ScopedMessage() {
+        if ( !std::uncaught_exception() ){
+            getResultCapture().popScopedMessage(m_info);
+        }
+    }
+
+} // end namespace Catch
+
+// #included from: catch_legacy_reporter_adapter.hpp
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
+
+// #included from: catch_legacy_reporter_adapter.h
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
+
+namespace Catch
+{
+    // Deprecated
+    struct IReporter : IShared {
+        virtual ~IReporter();
+
+        virtual bool shouldRedirectStdout() const = 0;
+
+        virtual void StartTesting() = 0;
+        virtual void EndTesting( Totals const& totals ) = 0;
+        virtual void StartGroup( std::string const& groupName ) = 0;
+        virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
+        virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
+        virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
+        virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
+        virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
+        virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
+        virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
+        virtual void Aborted() = 0;
+        virtual void Result( AssertionResult const& result ) = 0;
+    };
+
+    class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
+    {
+    public:
+        LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter );
+        virtual ~LegacyReporterAdapter();
+
+        virtual ReporterPreferences getPreferences() const;
+        virtual void noMatchingTestCases( std::string const& );
+        virtual void testRunStarting( TestRunInfo const& );
+        virtual void testGroupStarting( GroupInfo const& groupInfo );
+        virtual void testCaseStarting( TestCaseInfo const& testInfo );
+        virtual void sectionStarting( SectionInfo const& sectionInfo );
+        virtual void assertionStarting( AssertionInfo const& );
+        virtual bool assertionEnded( AssertionStats const& assertionStats );
+        virtual void sectionEnded( SectionStats const& sectionStats );
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats );
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats );
+        virtual void testRunEnded( TestRunStats const& testRunStats );
+        virtual void skipTest( TestCaseInfo const& );
+
+    private:
+        Ptr<IReporter> m_legacyReporter;
+    };
+}
+
+namespace Catch
+{
+    LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter )
+    :   m_legacyReporter( legacyReporter )
+    {}
+    LegacyReporterAdapter::~LegacyReporterAdapter() {}
+
+    ReporterPreferences LegacyReporterAdapter::getPreferences() const {
+        ReporterPreferences prefs;
+        prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
+        return prefs;
+    }
+
+    void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {}
+    void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) {
+        m_legacyReporter->StartTesting();
+    }
+    void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) {
+        m_legacyReporter->StartGroup( groupInfo.name );
+    }
+    void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) {
+        m_legacyReporter->StartTestCase( testInfo );
+    }
+    void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) {
+        m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description );
+    }
+    void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) {
+        // Not on legacy interface
+    }
+
+    bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) {
+        if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
+            for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+                    it != itEnd;
+                    ++it ) {
+                if( it->type == ResultWas::Info ) {
+                    ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal );
+                    rb << it->message;
+                    rb.setResultType( ResultWas::Info );
+                    AssertionResult result = rb.build();
+                    m_legacyReporter->Result( result );
+                }
+            }
+        }
+        m_legacyReporter->Result( assertionStats.assertionResult );
+        return true;
+    }
+    void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) {
+        if( sectionStats.missingAssertions )
+            m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
+        m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
+    }
+    void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+        m_legacyReporter->EndTestCase
+            (   testCaseStats.testInfo,
+                testCaseStats.totals,
+                testCaseStats.stdOut,
+                testCaseStats.stdErr );
+    }
+    void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+        if( testGroupStats.aborting )
+            m_legacyReporter->Aborted();
+        m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
+    }
+    void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
+        m_legacyReporter->EndTesting( testRunStats.totals );
+    }
+    void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) {
+    }
+}
+
+// #included from: catch_timer.hpp
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++11-long-long"
+#endif
+
+#ifdef CATCH_PLATFORM_WINDOWS
+
+#else
+
+#include <sys/time.h>
+
+#endif
+
+namespace Catch {
+
+    namespace {
+#ifdef CATCH_PLATFORM_WINDOWS
+        UInt64 getCurrentTicks() {
+            static UInt64 hz=0, hzo=0;
+            if (!hz) {
+                QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &hz ) );
+                QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) );
+            }
+            UInt64 t;
+            QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) );
+            return ((t-hzo)*1000000)/hz;
+        }
+#else
+        UInt64 getCurrentTicks() {
+            timeval t;
+            gettimeofday(&t,CATCH_NULL);
+            return static_cast<UInt64>( t.tv_sec ) * 1000000ull + static_cast<UInt64>( t.tv_usec );
+        }
+#endif
+    }
+
+    void Timer::start() {
+        m_ticks = getCurrentTicks();
+    }
+    unsigned int Timer::getElapsedMicroseconds() const {
+        return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
+    }
+    unsigned int Timer::getElapsedMilliseconds() const {
+        return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
+    }
+    double Timer::getElapsedSeconds() const {
+        return getElapsedMicroseconds()/1000000.0;
+    }
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+// #included from: catch_common.hpp
+#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+
+#include <cstring>
+#include <cctype>
+
+namespace Catch {
+
+    bool startsWith( std::string const& s, std::string const& prefix ) {
+        return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
+    }
+    bool startsWith( std::string const& s, char prefix ) {
+        return !s.empty() && s[0] == prefix;
+    }
+    bool endsWith( std::string const& s, std::string const& suffix ) {
+        return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
+    }
+    bool endsWith( std::string const& s, char suffix ) {
+        return !s.empty() && s[s.size()-1] == suffix;
+    }
+    bool contains( std::string const& s, std::string const& infix ) {
+        return s.find( infix ) != std::string::npos;
+    }
+    char toLowerCh(char c) {
+        return static_cast<char>( std::tolower( c ) );
+    }
+    void toLowerInPlace( std::string& s ) {
+        std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
+    }
+    std::string toLower( std::string const& s ) {
+        std::string lc = s;
+        toLowerInPlace( lc );
+        return lc;
+    }
+    std::string trim( std::string const& str ) {
+        static char const* whitespaceChars = "\n\r\t ";
+        std::string::size_type start = str.find_first_not_of( whitespaceChars );
+        std::string::size_type end = str.find_last_not_of( whitespaceChars );
+
+        return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
+    }
+
+    bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
+        bool replaced = false;
+        std::size_t i = str.find( replaceThis );
+        while( i != std::string::npos ) {
+            replaced = true;
+            str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
+            if( i < str.size()-withThis.size() )
+                i = str.find( replaceThis, i+withThis.size() );
+            else
+                i = std::string::npos;
+        }
+        return replaced;
+    }
+
+    pluralise::pluralise( std::size_t count, std::string const& label )
+    :   m_count( count ),
+        m_label( label )
+    {}
+
+    std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
+        os << pluraliser.m_count << ' ' << pluraliser.m_label;
+        if( pluraliser.m_count != 1 )
+            os << 's';
+        return os;
+    }
+
+    SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){}
+    SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
+    :   file( _file ),
+        line( _line )
+    {}
+    bool SourceLineInfo::empty() const {
+        return file[0] == '\0';
+    }
+    bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
+        return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
+    }
+    bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const {
+        return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
+    }
+
+    void seedRng( IConfig const& config ) {
+        if( config.rngSeed() != 0 )
+            std::srand( config.rngSeed() );
+    }
+    unsigned int rngSeed() {
+        return getCurrentContext().getConfig()->rngSeed();
+    }
+
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
+#ifndef __GNUG__
+        os << info.file << '(' << info.line << ')';
+#else
+        os << info.file << ':' << info.line;
+#endif
+        return os;
+    }
+
+    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
+        std::ostringstream oss;
+        oss << locationInfo << ": Internal Catch error: '" << message << '\'';
+        if( alwaysTrue() )
+            throw std::logic_error( oss.str() );
+    }
+}
+
+// #included from: catch_section.hpp
+#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
+
+namespace Catch {
+
+    SectionInfo::SectionInfo
+        (   SourceLineInfo const& _lineInfo,
+            std::string const& _name,
+            std::string const& _description )
+    :   name( _name ),
+        description( _description ),
+        lineInfo( _lineInfo )
+    {}
+
+    Section::Section( SectionInfo const& info )
+    :   m_info( info ),
+        m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )
+    {
+        m_timer.start();
+    }
+
+    Section::~Section() {
+        if( m_sectionIncluded ) {
+            SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
+            if( std::uncaught_exception() )
+                getResultCapture().sectionEndedEarly( endInfo );
+            else
+                getResultCapture().sectionEnded( endInfo );
+        }
+    }
+
+    // This indicates whether the section should be executed or not
+    Section::operator bool() const {
+        return m_sectionIncluded;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_debugger.hpp
+#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
+
+#ifdef CATCH_PLATFORM_MAC
+
+    #include <assert.h>
+    #include <stdbool.h>
+    #include <sys/types.h>
+    #include <unistd.h>
+    #include <sys/sysctl.h>
+
+    namespace Catch{
+
+        // The following function is taken directly from the following technical note:
+        // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
+
+        // Returns true if the current process is being debugged (either
+        // running under the debugger or has a debugger attached post facto).
+        bool isDebuggerActive(){
+
+            int                 mib[4];
+            struct kinfo_proc   info;
+            size_t              size;
+
+            // Initialize the flags so that, if sysctl fails for some bizarre
+            // reason, we get a predictable result.
+
+            info.kp_proc.p_flag = 0;
+
+            // Initialize mib, which tells sysctl the info we want, in this case
+            // we're looking for information about a specific process ID.
+
+            mib[0] = CTL_KERN;
+            mib[1] = KERN_PROC;
+            mib[2] = KERN_PROC_PID;
+            mib[3] = getpid();
+
+            // Call sysctl.
+
+            size = sizeof(info);
+            if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) {
+                Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
+                return false;
+            }
+
+            // We're being debugged if the P_TRACED flag is set.
+
+            return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
+        }
+    } // namespace Catch
+
+#elif defined(CATCH_PLATFORM_LINUX)
+    #include <fstream>
+    #include <string>
+
+    namespace Catch{
+        // The standard POSIX way of detecting a debugger is to attempt to
+        // ptrace() the process, but this needs to be done from a child and not
+        // this process itself to still allow attaching to this process later
+        // if wanted, so is rather heavy. Under Linux we have the PID of the
+        // "debugger" (which doesn't need to be gdb, of course, it could also
+        // be strace, for example) in /proc/$PID/status, so just get it from
+        // there instead.
+        bool isDebuggerActive(){
+            // Libstdc++ has a bug, where std::ifstream sets errno to 0
+            // This way our users can properly assert over errno values
+            ErrnoGuard guard;
+            std::ifstream in("/proc/self/status");
+            for( std::string line; std::getline(in, line); ) {
+                static const int PREFIX_LEN = 11;
+                if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
+                    // We're traced if the PID is not 0 and no other PID starts
+                    // with 0 digit, so it's enough to check for just a single
+                    // character.
+                    return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
+                }
+            }
+
+            return false;
+        }
+    } // namespace Catch
+#elif defined(_MSC_VER)
+    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
+    }
+#elif defined(__MINGW32__)
+    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
+    }
+#else
+    namespace Catch {
+       inline bool isDebuggerActive() { return false; }
+    }
+#endif // Platform
+
+#ifdef CATCH_PLATFORM_WINDOWS
+
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            ::OutputDebugStringA( text.c_str() );
+        }
+    }
+#else
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            // !TBD: Need a version for Mac/ XCode and other IDEs
+            Catch::cout() << text;
+        }
+    }
+#endif // Platform
+
+// #included from: catch_tostring.hpp
+#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
+
+namespace Catch {
+
+namespace Detail {
+
+    const std::string unprintableString = "{?}";
+
+    namespace {
+        const int hexThreshold = 255;
+
+        struct Endianness {
+            enum Arch { Big, Little };
+
+            static Arch which() {
+                union _{
+                    int asInt;
+                    char asChar[sizeof (int)];
+                } u;
+
+                u.asInt = 1;
+                return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
+            }
+        };
+    }
+
+    std::string rawMemoryToString( const void *object, std::size_t size )
+    {
+        // Reverse order for little endian architectures
+        int i = 0, end = static_cast<int>( size ), inc = 1;
+        if( Endianness::which() == Endianness::Little ) {
+            i = end-1;
+            end = inc = -1;
+        }
+
+        unsigned char const *bytes = static_cast<unsigned char const *>(object);
+        std::ostringstream os;
+        os << "0x" << std::setfill('0') << std::hex;
+        for( ; i != end; i += inc )
+             os << std::setw(2) << static_cast<unsigned>(bytes[i]);
+       return os.str();
+    }
+}
+
+std::string toString( std::string const& value ) {
+    std::string s = value;
+    if( getCurrentContext().getConfig()->showInvisibles() ) {
+        for(size_t i = 0; i < s.size(); ++i ) {
+            std::string subs;
+            switch( s[i] ) {
+            case '\n': subs = "\\n"; break;
+            case '\t': subs = "\\t"; break;
+            default: break;
+            }
+            if( !subs.empty() ) {
+                s = s.substr( 0, i ) + subs + s.substr( i+1 );
+                ++i;
+            }
+        }
+    }
+    return '"' + s + '"';
+}
+std::string toString( std::wstring const& value ) {
+
+    std::string s;
+    s.reserve( value.size() );
+    for(size_t i = 0; i < value.size(); ++i )
+        s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?';
+    return Catch::toString( s );
+}
+
+std::string toString( const char* const value ) {
+    return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
+}
+
+std::string toString( char* const value ) {
+    return Catch::toString( static_cast<const char*>( value ) );
+}
+
+std::string toString( const wchar_t* const value )
+{
+    return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" );
+}
+
+std::string toString( wchar_t* const value )
+{
+    return Catch::toString( static_cast<const wchar_t*>( value ) );
+}
+
+std::string toString( int value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value > Detail::hexThreshold )
+        oss << " (0x" << std::hex << value << ')';
+    return oss.str();
+}
+
+std::string toString( unsigned long value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value > Detail::hexThreshold )
+        oss << " (0x" << std::hex << value << ')';
+    return oss.str();
+}
+
+std::string toString( unsigned int value ) {
+    return Catch::toString( static_cast<unsigned long>( value ) );
+}
+
+template<typename T>
+std::string fpToString( T value, int precision ) {
+    std::ostringstream oss;
+    oss << std::setprecision( precision )
+        << std::fixed
+        << value;
+    std::string d = oss.str();
+    std::size_t i = d.find_last_not_of( '0' );
+    if( i != std::string::npos && i != d.size()-1 ) {
+        if( d[i] == '.' )
+            i++;
+        d = d.substr( 0, i+1 );
+    }
+    return d;
+}
+
+std::string toString( const double value ) {
+    return fpToString( value, 10 );
+}
+std::string toString( const float value ) {
+    return fpToString( value, 5 ) + 'f';
+}
+
+std::string toString( bool value ) {
+    return value ? "true" : "false";
+}
+
+std::string toString( char value ) {
+    if ( value == '\r' )
+        return "'\\r'";
+    if ( value == '\f' )
+        return "'\\f'";
+    if ( value == '\n' )
+        return "'\\n'";
+    if ( value == '\t' )
+        return "'\\t'";
+    if ( '\0' <= value && value < ' ' )
+        return toString( static_cast<unsigned int>( value ) );
+    char chstr[] = "' '";
+    chstr[1] = value;
+    return chstr;
+}
+
+std::string toString( signed char value ) {
+    return toString( static_cast<char>( value ) );
+}
+
+std::string toString( unsigned char value ) {
+    return toString( static_cast<char>( value ) );
+}
+
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+std::string toString( long long value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value > Detail::hexThreshold )
+        oss << " (0x" << std::hex << value << ')';
+    return oss.str();
+}
+std::string toString( unsigned long long value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value > Detail::hexThreshold )
+        oss << " (0x" << std::hex << value << ')';
+    return oss.str();
+}
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString( std::nullptr_t ) {
+    return "nullptr";
+}
+#endif
+
+#ifdef __OBJC__
+    std::string toString( NSString const * const& nsstring ) {
+        if( !nsstring )
+            return "nil";
+        return "@" + toString([nsstring UTF8String]);
+    }
+    std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
+        if( !nsstring )
+            return "nil";
+        return "@" + toString([nsstring UTF8String]);
+    }
+    std::string toString( NSObject* const& nsObject ) {
+        return toString( [nsObject description] );
+    }
+#endif
+
+} // end namespace Catch
+
+// #included from: catch_result_builder.hpp
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
+
+namespace Catch {
+
+    std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) {
+        return secondArg.empty() || secondArg == "\"\""
+            ? capturedExpression
+            : capturedExpression + ", " + secondArg;
+    }
+    ResultBuilder::ResultBuilder(   char const* macroName,
+                                    SourceLineInfo const& lineInfo,
+                                    char const* capturedExpression,
+                                    ResultDisposition::Flags resultDisposition,
+                                    char const* secondArg )
+    :   m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ),
+        m_shouldDebugBreak( false ),
+        m_shouldThrow( false ),
+        m_guardException( false )
+    {}
+
+    ResultBuilder::~ResultBuilder() {
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+        if ( m_guardException ) {
+            m_stream.oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
+            captureResult( ResultWas::ThrewException );
+            getCurrentContext().getResultCapture()->exceptionEarlyReported();
+        }
+#endif
+    }
+
+    ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
+        m_data.resultType = result;
+        return *this;
+    }
+    ResultBuilder& ResultBuilder::setResultType( bool result ) {
+        m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
+        return *this;
+    }
+
+    void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
+        AssertionResult result = build( expr );
+        handleResult( result );
+    }
+
+    void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
+        m_assertionInfo.resultDisposition = resultDisposition;
+        m_stream.oss << Catch::translateActiveException();
+        captureResult( ResultWas::ThrewException );
+    }
+
+    void ResultBuilder::captureResult( ResultWas::OfType resultType ) {
+        setResultType( resultType );
+        captureExpression();
+    }
+
+    void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
+        if( expectedMessage.empty() )
+            captureExpectedException( Matchers::Impl::MatchAllOf<std::string>() );
+        else
+            captureExpectedException( Matchers::Equals( expectedMessage ) );
+    }
+
+    void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ) {
+
+        assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
+        AssertionResultData data = m_data;
+        data.resultType = ResultWas::Ok;
+        data.reconstructedExpression = m_assertionInfo.capturedExpression;
+
+        std::string actualMessage = Catch::translateActiveException();
+        if( !matcher.match( actualMessage ) ) {
+            data.resultType = ResultWas::ExpressionFailed;
+            data.reconstructedExpression = actualMessage;
+        }
+        AssertionResult result( m_assertionInfo, data );
+        handleResult( result );
+    }
+
+    void ResultBuilder::captureExpression() {
+        AssertionResult result = build();
+        handleResult( result );
+    }
+
+    void ResultBuilder::handleResult( AssertionResult const& result )
+    {
+        getResultCapture().assertionEnded( result );
+
+        if( !result.isOk() ) {
+            if( getCurrentContext().getConfig()->shouldDebugBreak() )
+                m_shouldDebugBreak = true;
+            if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) )
+                m_shouldThrow = true;
+        }
+    }
+
+    void ResultBuilder::react() {
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+        if (m_shouldDebugBreak) {
+            ///////////////////////////////////////////////////////////////////
+            // To inspect the state during test, you need to go one level up the callstack
+            // To go back to the test and change execution, jump over the throw statement
+            ///////////////////////////////////////////////////////////////////
+            CATCH_BREAK_INTO_DEBUGGER();
+        }
+#endif
+        if( m_shouldThrow )
+            throw Catch::TestFailureException();
+    }
+
+    bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
+    bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
+
+    AssertionResult ResultBuilder::build() const
+    {
+        return build( *this );
+    }
+
+    // CAVEAT: The returned AssertionResult stores a pointer to the argument expr,
+    //         a temporary DecomposedExpression, which in turn holds references to
+    //         operands, possibly temporary as well.
+    //         It should immediately be passed to handleResult; if the expression
+    //         needs to be reported, its string expansion must be composed before
+    //         the temporaries are destroyed.
+    AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const
+    {
+        assert( m_data.resultType != ResultWas::Unknown );
+        AssertionResultData data = m_data;
+
+        // Flip bool results if FalseTest flag is set
+        if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
+            data.negate( expr.isBinaryExpression() );
+        }
+
+        data.message = m_stream.oss.str();
+        data.decomposedExpression = &expr; // for lazy reconstruction
+        return AssertionResult( m_assertionInfo, data );
+    }
+
+    void ResultBuilder::reconstructExpression( std::string& dest ) const {
+        dest = m_assertionInfo.capturedExpression;
+    }
+
+    void ResultBuilder::setExceptionGuard() {
+        m_guardException = true;
+    }
+    void ResultBuilder::unsetExceptionGuard() {
+        m_guardException = false;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_tag_alias_registry.hpp
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+
+namespace Catch {
+
+    TagAliasRegistry::~TagAliasRegistry() {}
+
+    Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const {
+        std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias );
+        if( it != m_registry.end() )
+            return it->second;
+        else
+            return Option<TagAlias>();
+    }
+
+    std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
+        std::string expandedTestSpec = unexpandedTestSpec;
+        for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end();
+                it != itEnd;
+                ++it ) {
+            std::size_t pos = expandedTestSpec.find( it->first );
+            if( pos != std::string::npos ) {
+                expandedTestSpec =  expandedTestSpec.substr( 0, pos ) +
+                                    it->second.tag +
+                                    expandedTestSpec.substr( pos + it->first.size() );
+            }
+        }
+        return expandedTestSpec;
+    }
+
+    void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
+
+        if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) {
+            std::ostringstream oss;
+            oss << Colour( Colour::Red )
+                << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n"
+                << Colour( Colour::FileName )
+                << lineInfo << '\n';
+            throw std::domain_error( oss.str().c_str() );
+        }
+        if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
+            std::ostringstream oss;
+            oss << Colour( Colour::Red )
+                << "error: tag alias, \"" << alias << "\" already registered.\n"
+                << "\tFirst seen at "
+                << Colour( Colour::Red ) << find(alias)->lineInfo << '\n'
+                << Colour( Colour::Red ) << "\tRedefined at "
+                << Colour( Colour::FileName) << lineInfo << '\n';
+            throw std::domain_error( oss.str().c_str() );
+        }
+    }
+
+    ITagAliasRegistry::~ITagAliasRegistry() {}
+
+    ITagAliasRegistry const& ITagAliasRegistry::get() {
+        return getRegistryHub().getTagAliasRegistry();
+    }
+
+    RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
+        getMutableRegistryHub().registerTagAlias( alias, tag, lineInfo );
+    }
+
+} // end namespace Catch
+
+// #included from: catch_matchers_string.hpp
+
+namespace Catch {
+namespace Matchers {
+
+    namespace StdString {
+
+        CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
+        :   m_caseSensitivity( caseSensitivity ),
+            m_str( adjustString( str ) )
+        {}
+        std::string CasedString::adjustString( std::string const& str ) const {
+            return m_caseSensitivity == CaseSensitive::No
+                   ? toLower( str )
+                   : str;
+        }
+        std::string CasedString::caseSensitivitySuffix() const {
+            return m_caseSensitivity == CaseSensitive::No
+                   ? " (case insensitive)"
+                   : std::string();
+        }
+
+        StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator )
+        : m_comparator( comparator ),
+          m_operation( operation ) {
+        }
+
+        std::string StringMatcherBase::describe() const {
+            std::string description;
+            description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
+                                        m_comparator.caseSensitivitySuffix().size());
+            description += m_operation;
+            description += ": \"";
+            description += m_comparator.m_str;
+            description += "\"";
+            description += m_comparator.caseSensitivitySuffix();
+            return description;
+        }
+
+        EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {}
+
+        bool EqualsMatcher::match( std::string const& source ) const {
+            return m_comparator.adjustString( source ) == m_comparator.m_str;
+        }
+
+        ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {}
+
+        bool ContainsMatcher::match( std::string const& source ) const {
+            return contains( m_comparator.adjustString( source ), m_comparator.m_str );
+        }
+
+        StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {}
+
+        bool StartsWithMatcher::match( std::string const& source ) const {
+            return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+        }
+
+        EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {}
+
+        bool EndsWithMatcher::match( std::string const& source ) const {
+            return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
+        }
+
+    } // namespace StdString
+
+    StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+    StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+    StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+    StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
+        return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );
+    }
+
+} // namespace Matchers
+} // namespace Catch
+// #included from: ../reporters/catch_reporter_multi.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED
+
+namespace Catch {
+
+class MultipleReporters : public SharedImpl<IStreamingReporter> {
+    typedef std::vector<Ptr<IStreamingReporter> > Reporters;
+    Reporters m_reporters;
+
+public:
+    void add( Ptr<IStreamingReporter> const& reporter ) {
+        m_reporters.push_back( reporter );
+    }
+
+public: // IStreamingReporter
+
+    virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
+        return m_reporters[0]->getPreferences();
+    }
+
+    virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->noMatchingTestCases( spec );
+    }
+
+    virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testRunStarting( testRunInfo );
+    }
+
+    virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testGroupStarting( groupInfo );
+    }
+
+    virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testCaseStarting( testInfo );
+    }
+
+    virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->sectionStarting( sectionInfo );
+    }
+
+    virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->assertionStarting( assertionInfo );
+    }
+
+    // The return value indicates if the messages buffer should be cleared:
+    virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+        bool clearBuffer = false;
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            clearBuffer |= (*it)->assertionEnded( assertionStats );
+        return clearBuffer;
+    }
+
+    virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->sectionEnded( sectionStats );
+    }
+
+    virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testCaseEnded( testCaseStats );
+    }
+
+    virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testGroupEnded( testGroupStats );
+    }
+
+    virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->testRunEnded( testRunStats );
+    }
+
+    virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
+        for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end();
+                it != itEnd;
+                ++it )
+            (*it)->skipTest( testInfo );
+    }
+
+    virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE {
+        return this;
+    }
+
+};
+
+Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) {
+    Ptr<IStreamingReporter> resultingReporter;
+
+    if( existingReporter ) {
+        MultipleReporters* multi = existingReporter->tryAsMulti();
+        if( !multi ) {
+            multi = new MultipleReporters;
+            resultingReporter = Ptr<IStreamingReporter>( multi );
+            if( existingReporter )
+                multi->add( existingReporter );
+        }
+        else
+            resultingReporter = existingReporter;
+        multi->add( additionalReporter );
+    }
+    else
+        resultingReporter = additionalReporter;
+
+    return resultingReporter;
+}
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_xml.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
+
+// #included from: catch_reporter_bases.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
+
+#include <cstring>
+#include <cfloat>
+#include <cstdio>
+#include <assert.h>
+
+namespace Catch {
+
+    namespace {
+        // Because formatting using c++ streams is stateful, drop down to C is required
+        // Alternatively we could use stringstream, but its performance is... not good.
+        std::string getFormattedDuration( double duration ) {
+            // Max exponent + 1 is required to represent the whole part
+            // + 1 for decimal point
+            // + 3 for the 3 decimal places
+            // + 1 for null terminator
+            const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
+            char buffer[maxDoubleSize];
+
+            // Save previous errno, to prevent sprintf from overwriting it
+            ErrnoGuard guard;
+#ifdef _MSC_VER
+            sprintf_s(buffer, "%.3f", duration);
+#else
+            sprintf(buffer, "%.3f", duration);
+#endif
+            return std::string(buffer);
+        }
+    }
+
+    struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
+
+        StreamingReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = false;
+        }
+
+        virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
+            return m_reporterPrefs;
+        }
+
+        virtual ~StreamingReporterBase() CATCH_OVERRIDE;
+
+        virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {}
+
+        virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE {
+            currentTestRunInfo = _testRunInfo;
+        }
+        virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE {
+            currentGroupInfo = _groupInfo;
+        }
+
+        virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE {
+            currentTestCaseInfo = _testInfo;
+        }
+        virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
+            m_sectionStack.push_back( _sectionInfo );
+        }
+
+        virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE {
+            m_sectionStack.pop_back();
+        }
+        virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE {
+            currentTestCaseInfo.reset();
+        }
+        virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE {
+            currentGroupInfo.reset();
+        }
+        virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE {
+            currentTestCaseInfo.reset();
+            currentGroupInfo.reset();
+            currentTestRunInfo.reset();
+        }
+
+        virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {
+            // Don't do anything with this by default.
+            // It can optionally be overridden in the derived class.
+        }
+
+        Ptr<IConfig const> m_config;
+        std::ostream& stream;
+
+        LazyStat<TestRunInfo> currentTestRunInfo;
+        LazyStat<GroupInfo> currentGroupInfo;
+        LazyStat<TestCaseInfo> currentTestCaseInfo;
+
+        std::vector<SectionInfo> m_sectionStack;
+        ReporterPreferences m_reporterPrefs;
+    };
+
+    struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
+        template<typename T, typename ChildNodeT>
+        struct Node : SharedImpl<> {
+            explicit Node( T const& _value ) : value( _value ) {}
+            virtual ~Node() {}
+
+            typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
+            T value;
+            ChildNodes children;
+        };
+        struct SectionNode : SharedImpl<> {
+            explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
+            virtual ~SectionNode();
+
+            bool operator == ( SectionNode const& other ) const {
+                return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
+            }
+            bool operator == ( Ptr<SectionNode> const& other ) const {
+                return operator==( *other );
+            }
+
+            SectionStats stats;
+            typedef std::vector<Ptr<SectionNode> > ChildSections;
+            typedef std::vector<AssertionStats> Assertions;
+            ChildSections childSections;
+            Assertions assertions;
+            std::string stdOut;
+            std::string stdErr;
+        };
+
+        struct BySectionInfo {
+            BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
+            BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
+            bool operator() ( Ptr<SectionNode> const& node ) const {
+                return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
+            }
+        private:
+            void operator=( BySectionInfo const& );
+            SectionInfo const& m_other;
+        };
+
+        typedef Node<TestCaseStats, SectionNode> TestCaseNode;
+        typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
+        typedef Node<TestRunStats, TestGroupNode> TestRunNode;
+
+        CumulativeReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = false;
+        }
+        ~CumulativeReporterBase();
+
+        virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE {
+            return m_reporterPrefs;
+        }
+
+        virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {}
+        virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {}
+
+        virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {}
+
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
+            SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
+            Ptr<SectionNode> node;
+            if( m_sectionStack.empty() ) {
+                if( !m_rootSection )
+                    m_rootSection = new SectionNode( incompleteStats );
+                node = m_rootSection;
+            }
+            else {
+                SectionNode& parentNode = *m_sectionStack.back();
+                SectionNode::ChildSections::const_iterator it =
+                    std::find_if(   parentNode.childSections.begin(),
+                                    parentNode.childSections.end(),
+                                    BySectionInfo( sectionInfo ) );
+                if( it == parentNode.childSections.end() ) {
+                    node = new SectionNode( incompleteStats );
+                    parentNode.childSections.push_back( node );
+                }
+                else
+                    node = *it;
+            }
+            m_sectionStack.push_back( node );
+            m_deepestSection = node;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
+
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+            assert( !m_sectionStack.empty() );
+            SectionNode& sectionNode = *m_sectionStack.back();
+            sectionNode.assertions.push_back( assertionStats );
+            // AssertionResult holds a pointer to a temporary DecomposedExpression,
+            // which getExpandedExpression() calls to build the expression string.
+            // Our section stack copy of the assertionResult will likely outlive the
+            // temporary, so it must be expanded or discarded now to avoid calling
+            // a destroyed object later.
+            prepareExpandedExpression( sectionNode.assertions.back().assertionResult );
+            return true;
+        }
+        virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
+            assert( !m_sectionStack.empty() );
+            SectionNode& node = *m_sectionStack.back();
+            node.stats = sectionStats;
+            m_sectionStack.pop_back();
+        }
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+            Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
+            assert( m_sectionStack.size() == 0 );
+            node->children.push_back( m_rootSection );
+            m_testCases.push_back( node );
+            m_rootSection.reset();
+
+            assert( m_deepestSection );
+            m_deepestSection->stdOut = testCaseStats.stdOut;
+            m_deepestSection->stdErr = testCaseStats.stdErr;
+        }
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+            Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
+            node->children.swap( m_testCases );
+            m_testGroups.push_back( node );
+        }
+        virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
+            Ptr<TestRunNode> node = new TestRunNode( testRunStats );
+            node->children.swap( m_testGroups );
+            m_testRuns.push_back( node );
+            testRunEndedCumulative();
+        }
+        virtual void testRunEndedCumulative() = 0;
+
+        virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {}
+
+        virtual void prepareExpandedExpression( AssertionResult& result ) const {
+            if( result.isOk() )
+                result.discardDecomposedExpression();
+            else
+                result.expandDecomposedExpression();
+        }
+
+        Ptr<IConfig const> m_config;
+        std::ostream& stream;
+        std::vector<AssertionStats> m_assertions;
+        std::vector<std::vector<Ptr<SectionNode> > > m_sections;
+        std::vector<Ptr<TestCaseNode> > m_testCases;
+        std::vector<Ptr<TestGroupNode> > m_testGroups;
+
+        std::vector<Ptr<TestRunNode> > m_testRuns;
+
+        Ptr<SectionNode> m_rootSection;
+        Ptr<SectionNode> m_deepestSection;
+        std::vector<Ptr<SectionNode> > m_sectionStack;
+        ReporterPreferences m_reporterPrefs;
+
+    };
+
+    template<char C>
+    char const* getLineOfChars() {
+        static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
+        if( !*line ) {
+            std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
+            line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
+        }
+        return line;
+    }
+
+    struct TestEventListenerBase : StreamingReporterBase {
+        TestEventListenerBase( ReporterConfig const& _config )
+        :   StreamingReporterBase( _config )
+        {}
+
+        virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
+        virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE {
+            return false;
+        }
+    };
+
+} // end namespace Catch
+
+// #included from: ../internal/catch_reporter_registrars.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
+
+namespace Catch {
+
+    template<typename T>
+    class LegacyReporterRegistrar {
+
+        class ReporterFactory : public IReporterFactory {
+            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+                return new LegacyReporterAdapter( new T( config ) );
+            }
+
+            virtual std::string getDescription() const {
+                return T::getDescription();
+            }
+        };
+
+    public:
+
+        LegacyReporterRegistrar( std::string const& name ) {
+            getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
+        }
+    };
+
+    template<typename T>
+    class ReporterRegistrar {
+
+        class ReporterFactory : public SharedImpl<IReporterFactory> {
+
+            // *** Please Note ***:
+            // - If you end up here looking at a compiler error because it's trying to register
+            // your custom reporter class be aware that the native reporter interface has changed
+            // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
+            // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
+            // However please consider updating to the new interface as the old one is now
+            // deprecated and will probably be removed quite soon!
+            // Please contact me via github if you have any questions at all about this.
+            // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
+            // no idea who is actually using custom reporters at all (possibly no-one!).
+            // The new interface is designed to minimise exposure to interface changes in the future.
+            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+                return new T( config );
+            }
+
+            virtual std::string getDescription() const {
+                return T::getDescription();
+            }
+        };
+
+    public:
+
+        ReporterRegistrar( std::string const& name ) {
+            getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
+        }
+    };
+
+    template<typename T>
+    class ListenerRegistrar {
+
+        class ListenerFactory : public SharedImpl<IReporterFactory> {
+
+            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+                return new T( config );
+            }
+            virtual std::string getDescription() const {
+                return std::string();
+            }
+        };
+
+    public:
+
+        ListenerRegistrar() {
+            getMutableRegistryHub().registerListener( new ListenerFactory() );
+        }
+    };
+}
+
+#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
+    namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+
+#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
+    namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+
+// Deprecated - use the form without INTERNAL_
+#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \
+    namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
+
+#define CATCH_REGISTER_LISTENER( listenerType ) \
+    namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
+
+// #included from: ../internal/catch_xmlwriter.hpp
+#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <iomanip>
+
+namespace Catch {
+
+    class XmlEncode {
+    public:
+        enum ForWhat { ForTextNodes, ForAttributes };
+
+        XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes )
+        :   m_str( str ),
+            m_forWhat( forWhat )
+        {}
+
+        void encodeTo( std::ostream& os ) const {
+
+            // Apostrophe escaping not necessary if we always use " to write attributes
+            // (see: http://www.w3.org/TR/xml/#syntax)
+
+            for( std::size_t i = 0; i < m_str.size(); ++ i ) {
+                char c = m_str[i];
+                switch( c ) {
+                    case '<':   os << "&lt;"; break;
+                    case '&':   os << "&amp;"; break;
+
+                    case '>':
+                        // See: http://www.w3.org/TR/xml/#syntax
+                        if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' )
+                            os << "&gt;";
+                        else
+                            os << c;
+                        break;
+
+                    case '\"':
+                        if( m_forWhat == ForAttributes )
+                            os << "&quot;";
+                        else
+                            os << c;
+                        break;
+
+                    default:
+                        // Escape control chars - based on contribution by @espenalb in PR #465 and
+                        // by @mrpi PR #588
+                        if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) {
+                            // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
+                            os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
+                               << static_cast<int>( c );
+                        }
+                        else
+                            os << c;
+                }
+            }
+        }
+
+        friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
+            xmlEncode.encodeTo( os );
+            return os;
+        }
+
+    private:
+        std::string m_str;
+        ForWhat m_forWhat;
+    };
+
+    class XmlWriter {
+    public:
+
+        class ScopedElement {
+        public:
+            ScopedElement( XmlWriter* writer )
+            :   m_writer( writer )
+            {}
+
+            ScopedElement( ScopedElement const& other )
+            :   m_writer( other.m_writer ){
+                other.m_writer = CATCH_NULL;
+            }
+
+            ~ScopedElement() {
+                if( m_writer )
+                    m_writer->endElement();
+            }
+
+            ScopedElement& writeText( std::string const& text, bool indent = true ) {
+                m_writer->writeText( text, indent );
+                return *this;
+            }
+
+            template<typename T>
+            ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
+                m_writer->writeAttribute( name, attribute );
+                return *this;
+            }
+
+        private:
+            mutable XmlWriter* m_writer;
+        };
+
+        XmlWriter()
+        :   m_tagIsOpen( false ),
+            m_needsNewline( false ),
+            m_os( Catch::cout() )
+        {
+            writeDeclaration();
+        }
+
+        XmlWriter( std::ostream& os )
+        :   m_tagIsOpen( false ),
+            m_needsNewline( false ),
+            m_os( os )
+        {
+            writeDeclaration();
+        }
+
+        ~XmlWriter() {
+            while( !m_tags.empty() )
+                endElement();
+        }
+
+        XmlWriter& startElement( std::string const& name ) {
+            ensureTagClosed();
+            newlineIfNecessary();
+            m_os << m_indent << '<' << name;
+            m_tags.push_back( name );
+            m_indent += "  ";
+            m_tagIsOpen = true;
+            return *this;
+        }
+
+        ScopedElement scopedElement( std::string const& name ) {
+            ScopedElement scoped( this );
+            startElement( name );
+            return scoped;
+        }
+
+        XmlWriter& endElement() {
+            newlineIfNecessary();
+            m_indent = m_indent.substr( 0, m_indent.size()-2 );
+            if( m_tagIsOpen ) {
+                m_os << "/>";
+                m_tagIsOpen = false;
+            }
+            else {
+                m_os << m_indent << "</" << m_tags.back() << ">";
+            }
+            m_os << std::endl;
+            m_tags.pop_back();
+            return *this;
+        }
+
+        XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
+            if( !name.empty() && !attribute.empty() )
+                m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
+            return *this;
+        }
+
+        XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
+            m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
+            return *this;
+        }
+
+        template<typename T>
+        XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
+            std::ostringstream oss;
+            oss << attribute;
+            return writeAttribute( name, oss.str() );
+        }
+
+        XmlWriter& writeText( std::string const& text, bool indent = true ) {
+            if( !text.empty() ){
+                bool tagWasOpen = m_tagIsOpen;
+                ensureTagClosed();
+                if( tagWasOpen && indent )
+                    m_os << m_indent;
+                m_os << XmlEncode( text );
+                m_needsNewline = true;
+            }
+            return *this;
+        }
+
+        XmlWriter& writeComment( std::string const& text ) {
+            ensureTagClosed();
+            m_os << m_indent << "<!--" << text << "-->";
+            m_needsNewline = true;
+            return *this;
+        }
+
+        void writeStylesheetRef( std::string const& url ) {
+            m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
+        }
+
+        XmlWriter& writeBlankLine() {
+            ensureTagClosed();
+            m_os << '\n';
+            return *this;
+        }
+
+        void ensureTagClosed() {
+            if( m_tagIsOpen ) {
+                m_os << ">" << std::endl;
+                m_tagIsOpen = false;
+            }
+        }
+
+    private:
+        XmlWriter( XmlWriter const& );
+        void operator=( XmlWriter const& );
+
+        void writeDeclaration() {
+            m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+        }
+
+        void newlineIfNecessary() {
+            if( m_needsNewline ) {
+                m_os << std::endl;
+                m_needsNewline = false;
+            }
+        }
+
+        bool m_tagIsOpen;
+        bool m_needsNewline;
+        std::vector<std::string> m_tags;
+        std::string m_indent;
+        std::ostream& m_os;
+    };
+
+}
+// #included from: catch_reenable_warnings.h
+
+#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#    ifdef __ICC // icpc defines the __clang__ macro
+#        pragma warning(pop)
+#    else
+#        pragma clang diagnostic pop
+#    endif
+#elif defined __GNUC__
+#    pragma GCC diagnostic pop
+#endif
+
+
+namespace Catch {
+    class XmlReporter : public StreamingReporterBase {
+    public:
+        XmlReporter( ReporterConfig const& _config )
+        :   StreamingReporterBase( _config ),
+            m_xml(_config.stream()),
+            m_sectionDepth( 0 )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = true;
+        }
+
+        virtual ~XmlReporter() CATCH_OVERRIDE;
+
+        static std::string getDescription() {
+            return "Reports test results as an XML document";
+        }
+
+        virtual std::string getStylesheetRef() const {
+            return std::string();
+        }
+
+        void writeSourceInfo( SourceLineInfo const& sourceInfo ) {
+            m_xml
+                .writeAttribute( "filename", sourceInfo.file )
+                .writeAttribute( "line", sourceInfo.line );
+        }
+
+    public: // StreamingReporterBase
+
+        virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE {
+            StreamingReporterBase::noMatchingTestCases( s );
+        }
+
+        virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE {
+            StreamingReporterBase::testRunStarting( testInfo );
+            std::string stylesheetRef = getStylesheetRef();
+            if( !stylesheetRef.empty() )
+                m_xml.writeStylesheetRef( stylesheetRef );
+            m_xml.startElement( "Catch" );
+            if( !m_config->name().empty() )
+                m_xml.writeAttribute( "name", m_config->name() );
+        }
+
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
+            StreamingReporterBase::testGroupStarting( groupInfo );
+            m_xml.startElement( "Group" )
+                .writeAttribute( "name", groupInfo.name );
+        }
+
+        virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
+            StreamingReporterBase::testCaseStarting(testInfo);
+            m_xml.startElement( "TestCase" )
+                .writeAttribute( "name", trim( testInfo.name ) )
+                .writeAttribute( "description", testInfo.description )
+                .writeAttribute( "tags", testInfo.tagsAsString );
+
+            writeSourceInfo( testInfo.lineInfo );
+
+            if ( m_config->showDurations() == ShowDurations::Always )
+                m_testCaseTimer.start();
+            m_xml.ensureTagClosed();
+        }
+
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE {
+            StreamingReporterBase::sectionStarting( sectionInfo );
+            if( m_sectionDepth++ > 0 ) {
+                m_xml.startElement( "Section" )
+                    .writeAttribute( "name", trim( sectionInfo.name ) )
+                    .writeAttribute( "description", sectionInfo.description );
+                writeSourceInfo( sectionInfo.lineInfo );
+                m_xml.ensureTagClosed();
+            }
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { }
+
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+
+            AssertionResult const& result = assertionStats.assertionResult;
+
+            bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
+
+            if( includeResults ) {
+                // Print any info messages in <Info> tags.
+                for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+                     it != itEnd;
+                     ++it ) {
+                    if( it->type == ResultWas::Info ) {
+                        m_xml.scopedElement( "Info" )
+                                .writeText( it->message );
+                    } else if ( it->type == ResultWas::Warning ) {
+                        m_xml.scopedElement( "Warning" )
+                                .writeText( it->message );
+                    }
+                }
+            }
+
+            // Drop out if result was successful but we're not printing them.
+            if( !includeResults && result.getResultType() != ResultWas::Warning )
+                return true;
+
+            // Print the expression if there is one.
+            if( result.hasExpression() ) {
+                m_xml.startElement( "Expression" )
+                    .writeAttribute( "success", result.succeeded() )
+                    .writeAttribute( "type", result.getTestMacroName() );
+
+                writeSourceInfo( result.getSourceInfo() );
+
+                m_xml.scopedElement( "Original" )
+                    .writeText( result.getExpression() );
+                m_xml.scopedElement( "Expanded" )
+                    .writeText( result.getExpandedExpression() );
+            }
+
+            // And... Print a result applicable to each result type.
+            switch( result.getResultType() ) {
+                case ResultWas::ThrewException:
+                    m_xml.startElement( "Exception" );
+                    writeSourceInfo( result.getSourceInfo() );
+                    m_xml.writeText( result.getMessage() );
+                    m_xml.endElement();
+                    break;
+                case ResultWas::FatalErrorCondition:
+                    m_xml.startElement( "FatalErrorCondition" );
+                    writeSourceInfo( result.getSourceInfo() );
+                    m_xml.writeText( result.getMessage() );
+                    m_xml.endElement();
+                    break;
+                case ResultWas::Info:
+                    m_xml.scopedElement( "Info" )
+                        .writeText( result.getMessage() );
+                    break;
+                case ResultWas::Warning:
+                    // Warning will already have been written
+                    break;
+                case ResultWas::ExplicitFailure:
+                    m_xml.startElement( "Failure" );
+                    writeSourceInfo( result.getSourceInfo() );
+                    m_xml.writeText( result.getMessage() );
+                    m_xml.endElement();
+                    break;
+                default:
+                    break;
+            }
+
+            if( result.hasExpression() )
+                m_xml.endElement();
+
+            return true;
+        }
+
+        virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::sectionEnded( sectionStats );
+            if( --m_sectionDepth > 0 ) {
+                XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
+                e.writeAttribute( "successes", sectionStats.assertions.passed );
+                e.writeAttribute( "failures", sectionStats.assertions.failed );
+                e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );
+
+                if ( m_config->showDurations() == ShowDurations::Always )
+                    e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );
+
+                m_xml.endElement();
+            }
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::testCaseEnded( testCaseStats );
+            XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
+            e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
+
+            if ( m_config->showDurations() == ShowDurations::Always )
+                e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
+
+            if( !testCaseStats.stdOut.empty() )
+                m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false );
+            if( !testCaseStats.stdErr.empty() )
+                m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false );
+
+            m_xml.endElement();
+        }
+
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::testGroupEnded( testGroupStats );
+            // TODO: Check testGroupStats.aborting and act accordingly.
+            m_xml.scopedElement( "OverallResults" )
+                .writeAttribute( "successes", testGroupStats.totals.assertions.passed )
+                .writeAttribute( "failures", testGroupStats.totals.assertions.failed )
+                .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
+            m_xml.endElement();
+        }
+
+        virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::testRunEnded( testRunStats );
+            m_xml.scopedElement( "OverallResults" )
+                .writeAttribute( "successes", testRunStats.totals.assertions.passed )
+                .writeAttribute( "failures", testRunStats.totals.assertions.failed )
+                .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
+            m_xml.endElement();
+        }
+
+    private:
+        Timer m_testCaseTimer;
+        XmlWriter m_xml;
+        int m_sectionDepth;
+    };
+
+     INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_junit.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
+
+#include <assert.h>
+
+namespace Catch {
+
+    namespace {
+        std::string getCurrentTimestamp() {
+            // Beware, this is not reentrant because of backward compatibility issues
+            // Also, UTC only, again because of backward compatibility (%z is C++11)
+            time_t rawtime;
+            std::time(&rawtime);
+            const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z");
+
+#ifdef _MSC_VER
+            std::tm timeInfo = {};
+            gmtime_s(&timeInfo, &rawtime);
+#else
+            std::tm* timeInfo;
+            timeInfo = std::gmtime(&rawtime);
+#endif
+
+            char timeStamp[timeStampSize];
+            const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
+
+#ifdef _MSC_VER
+            std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
+#else
+            std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
+#endif
+            return std::string(timeStamp);
+        }
+
+    }
+
+    class JunitReporter : public CumulativeReporterBase {
+    public:
+        JunitReporter( ReporterConfig const& _config )
+        :   CumulativeReporterBase( _config ),
+            xml( _config.stream() ),
+            m_okToFail( false )
+        {
+            m_reporterPrefs.shouldRedirectStdOut = true;
+        }
+
+        virtual ~JunitReporter() CATCH_OVERRIDE;
+
+        static std::string getDescription() {
+            return "Reports test results in an XML format that looks like Ant's junitreport target";
+        }
+
+        virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {}
+
+        virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE {
+            CumulativeReporterBase::testRunStarting( runInfo );
+            xml.startElement( "testsuites" );
+        }
+
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE {
+            suiteTimer.start();
+            stdOutForSuite.str("");
+            stdErrForSuite.str("");
+            unexpectedExceptions = 0;
+            CumulativeReporterBase::testGroupStarting( groupInfo );
+        }
+
+        virtual void testCaseStarting( TestCaseInfo const& testCaseInfo ) CATCH_OVERRIDE {
+            m_okToFail = testCaseInfo.okToFail();
+        }
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
+            if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )
+                unexpectedExceptions++;
+            return CumulativeReporterBase::assertionEnded( assertionStats );
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE {
+            stdOutForSuite << testCaseStats.stdOut;
+            stdErrForSuite << testCaseStats.stdErr;
+            CumulativeReporterBase::testCaseEnded( testCaseStats );
+        }
+
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE {
+            double suiteTime = suiteTimer.getElapsedSeconds();
+            CumulativeReporterBase::testGroupEnded( testGroupStats );
+            writeGroup( *m_testGroups.back(), suiteTime );
+        }
+
+        virtual void testRunEndedCumulative() CATCH_OVERRIDE {
+            xml.endElement();
+        }
+
+        void writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
+            XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
+            TestGroupStats const& stats = groupNode.value;
+            xml.writeAttribute( "name", stats.groupInfo.name );
+            xml.writeAttribute( "errors", unexpectedExceptions );
+            xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
+            xml.writeAttribute( "tests", stats.totals.assertions.total() );
+            xml.writeAttribute( "hostname", "tbd" ); // !TBD
+            if( m_config->showDurations() == ShowDurations::Never )
+                xml.writeAttribute( "time", "" );
+            else
+                xml.writeAttribute( "time", suiteTime );
+            xml.writeAttribute( "timestamp", getCurrentTimestamp() );
+
+            // Write test cases
+            for( TestGroupNode::ChildNodes::const_iterator
+                    it = groupNode.children.begin(), itEnd = groupNode.children.end();
+                    it != itEnd;
+                    ++it )
+                writeTestCase( **it );
+
+            xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false );
+            xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false );
+        }
+
+        void writeTestCase( TestCaseNode const& testCaseNode ) {
+            TestCaseStats const& stats = testCaseNode.value;
+
+            // All test cases have exactly one section - which represents the
+            // test case itself. That section may have 0-n nested sections
+            assert( testCaseNode.children.size() == 1 );
+            SectionNode const& rootSection = *testCaseNode.children.front();
+
+            std::string className = stats.testInfo.className;
+
+            if( className.empty() ) {
+                if( rootSection.childSections.empty() )
+                    className = "global";
+            }
+            writeSection( className, "", rootSection );
+        }
+
+        void writeSection(  std::string const& className,
+                            std::string const& rootName,
+                            SectionNode const& sectionNode ) {
+            std::string name = trim( sectionNode.stats.sectionInfo.name );
+            if( !rootName.empty() )
+                name = rootName + '/' + name;
+
+            if( !sectionNode.assertions.empty() ||
+                !sectionNode.stdOut.empty() ||
+                !sectionNode.stdErr.empty() ) {
+                XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
+                if( className.empty() ) {
+                    xml.writeAttribute( "classname", name );
+                    xml.writeAttribute( "name", "root" );
+                }
+                else {
+                    xml.writeAttribute( "classname", className );
+                    xml.writeAttribute( "name", name );
+                }
+                xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) );
+
+                writeAssertions( sectionNode );
+
+                if( !sectionNode.stdOut.empty() )
+                    xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
+                if( !sectionNode.stdErr.empty() )
+                    xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
+            }
+            for( SectionNode::ChildSections::const_iterator
+                    it = sectionNode.childSections.begin(),
+                    itEnd = sectionNode.childSections.end();
+                    it != itEnd;
+                    ++it )
+                if( className.empty() )
+                    writeSection( name, "", **it );
+                else
+                    writeSection( className, name, **it );
+        }
+
+        void writeAssertions( SectionNode const& sectionNode ) {
+            for( SectionNode::Assertions::const_iterator
+                    it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end();
+                    it != itEnd;
+                    ++it )
+                writeAssertion( *it );
+        }
+        void writeAssertion( AssertionStats const& stats ) {
+            AssertionResult const& result = stats.assertionResult;
+            if( !result.isOk() ) {
+                std::string elementName;
+                switch( result.getResultType() ) {
+                    case ResultWas::ThrewException:
+                    case ResultWas::FatalErrorCondition:
+                        elementName = "error";
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        elementName = "failure";
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        elementName = "failure";
+                        break;
+                    case ResultWas::DidntThrowException:
+                        elementName = "failure";
+                        break;
+
+                    // We should never see these here:
+                    case ResultWas::Info:
+                    case ResultWas::Warning:
+                    case ResultWas::Ok:
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        elementName = "internalError";
+                        break;
+                }
+
+                XmlWriter::ScopedElement e = xml.scopedElement( elementName );
+
+                xml.writeAttribute( "message", result.getExpandedExpression() );
+                xml.writeAttribute( "type", result.getTestMacroName() );
+
+                std::ostringstream oss;
+                if( !result.getMessage().empty() )
+                    oss << result.getMessage() << '\n';
+                for( std::vector<MessageInfo>::const_iterator
+                        it = stats.infoMessages.begin(),
+                        itEnd = stats.infoMessages.end();
+                            it != itEnd;
+                            ++it )
+                    if( it->type == ResultWas::Info )
+                        oss << it->message << '\n';
+
+                oss << "at " << result.getSourceInfo();
+                xml.writeText( oss.str(), false );
+            }
+        }
+
+        XmlWriter xml;
+        Timer suiteTimer;
+        std::ostringstream stdOutForSuite;
+        std::ostringstream stdErrForSuite;
+        unsigned int unexpectedExceptions;
+        bool m_okToFail;
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_console.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
+
+#include <cfloat>
+#include <cstdio>
+
+namespace Catch {
+
+    struct ConsoleReporter : StreamingReporterBase {
+        ConsoleReporter( ReporterConfig const& _config )
+        :   StreamingReporterBase( _config ),
+            m_headerPrinted( false )
+        {}
+
+        virtual ~ConsoleReporter() CATCH_OVERRIDE;
+        static std::string getDescription() {
+            return "Reports test results as plain lines of text";
+        }
+
+        virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
+            stream << "No test cases matched '" << spec << '\'' << std::endl;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {
+        }
+
+        virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE {
+            AssertionResult const& result = _assertionStats.assertionResult;
+
+            bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
+
+            // Drop out if result was successful but we're not printing them.
+            if( !includeResults && result.getResultType() != ResultWas::Warning )
+                return false;
+
+            lazyPrint();
+
+            AssertionPrinter printer( stream, _assertionStats, includeResults );
+            printer.print();
+            stream << std::endl;
+            return true;
+        }
+
+        virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
+            m_headerPrinted = false;
+            StreamingReporterBase::sectionStarting( _sectionInfo );
+        }
+        virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE {
+            if( _sectionStats.missingAssertions ) {
+                lazyPrint();
+                Colour colour( Colour::ResultError );
+                if( m_sectionStack.size() > 1 )
+                    stream << "\nNo assertions in section";
+                else
+                    stream << "\nNo assertions in test case";
+                stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
+            }
+            if( m_config->showDurations() == ShowDurations::Always ) {
+                stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+            }
+            if( m_headerPrinted ) {
+                m_headerPrinted = false;
+            }
+            StreamingReporterBase::sectionEnded( _sectionStats );
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE {
+            StreamingReporterBase::testCaseEnded( _testCaseStats );
+            m_headerPrinted = false;
+        }
+        virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE {
+            if( currentGroupInfo.used ) {
+                printSummaryDivider();
+                stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
+                printTotals( _testGroupStats.totals );
+                stream << '\n' << std::endl;
+            }
+            StreamingReporterBase::testGroupEnded( _testGroupStats );
+        }
+        virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE {
+            printTotalsDivider( _testRunStats.totals );
+            printTotals( _testRunStats.totals );
+            stream << std::endl;
+            StreamingReporterBase::testRunEnded( _testRunStats );
+        }
+
+    private:
+
+        class AssertionPrinter {
+            void operator= ( AssertionPrinter const& );
+        public:
+            AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
+            :   stream( _stream ),
+                stats( _stats ),
+                result( _stats.assertionResult ),
+                colour( Colour::None ),
+                message( result.getMessage() ),
+                messages( _stats.infoMessages ),
+                printInfoMessages( _printInfoMessages )
+            {
+                switch( result.getResultType() ) {
+                    case ResultWas::Ok:
+                        colour = Colour::Success;
+                        passOrFail = "PASSED";
+                        //if( result.hasMessage() )
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "with messages";
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        if( result.isOk() ) {
+                            colour = Colour::Success;
+                            passOrFail = "FAILED - but was ok";
+                        }
+                        else {
+                            colour = Colour::Error;
+                            passOrFail = "FAILED";
+                        }
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "with messages";
+                        break;
+                    case ResultWas::ThrewException:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "due to unexpected exception with ";
+                        if (_stats.infoMessages.size() == 1)
+                            messageLabel += "message";
+                        if (_stats.infoMessages.size() > 1)
+                            messageLabel += "messages";
+                        break;
+                    case ResultWas::FatalErrorCondition:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "due to a fatal error condition";
+                        break;
+                    case ResultWas::DidntThrowException:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "because no exception was thrown where one was expected";
+                        break;
+                    case ResultWas::Info:
+                        messageLabel = "info";
+                        break;
+                    case ResultWas::Warning:
+                        messageLabel = "warning";
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        passOrFail = "FAILED";
+                        colour = Colour::Error;
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "explicitly with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "explicitly with messages";
+                        break;
+                    // These cases are here to prevent compiler warnings
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        passOrFail = "** internal error **";
+                        colour = Colour::Error;
+                        break;
+                }
+            }
+
+            void print() const {
+                printSourceInfo();
+                if( stats.totals.assertions.total() > 0 ) {
+                    if( result.isOk() )
+                        stream << '\n';
+                    printResultType();
+                    printOriginalExpression();
+                    printReconstructedExpression();
+                }
+                else {
+                    stream << '\n';
+                }
+                printMessage();
+            }
+
+        private:
+            void printResultType() const {
+                if( !passOrFail.empty() ) {
+                    Colour colourGuard( colour );
+                    stream << passOrFail << ":\n";
+                }
+            }
+            void printOriginalExpression() const {
+                if( result.hasExpression() ) {
+                    Colour colourGuard( Colour::OriginalExpression );
+                    stream  << "  ";
+                    stream << result.getExpressionInMacro();
+                    stream << '\n';
+                }
+            }
+            void printReconstructedExpression() const {
+                if( result.hasExpandedExpression() ) {
+                    stream << "with expansion:\n";
+                    Colour colourGuard( Colour::ReconstructedExpression );
+                    stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n';
+                }
+            }
+            void printMessage() const {
+                if( !messageLabel.empty() )
+                    stream << messageLabel << ':' << '\n';
+                for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
+                        it != itEnd;
+                        ++it ) {
+                    // If this assertion is a warning ignore any INFO messages
+                    if( printInfoMessages || it->type != ResultWas::Info )
+                        stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n';
+                }
+            }
+            void printSourceInfo() const {
+                Colour colourGuard( Colour::FileName );
+                stream << result.getSourceInfo() << ": ";
+            }
+
+            std::ostream& stream;
+            AssertionStats const& stats;
+            AssertionResult const& result;
+            Colour::Code colour;
+            std::string passOrFail;
+            std::string messageLabel;
+            std::string message;
+            std::vector<MessageInfo> messages;
+            bool printInfoMessages;
+        };
+
+        void lazyPrint() {
+
+            if( !currentTestRunInfo.used )
+                lazyPrintRunInfo();
+            if( !currentGroupInfo.used )
+                lazyPrintGroupInfo();
+
+            if( !m_headerPrinted ) {
+                printTestCaseAndSectionHeader();
+                m_headerPrinted = true;
+            }
+        }
+        void lazyPrintRunInfo() {
+            stream  << '\n' << getLineOfChars<'~'>() << '\n';
+            Colour colour( Colour::SecondaryText );
+            stream  << currentTestRunInfo->name
+                    << " is a Catch v"  << libraryVersion() << " host application.\n"
+                    << "Run with -? for options\n\n";
+
+            if( m_config->rngSeed() != 0 )
+                stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
+
+            currentTestRunInfo.used = true;
+        }
+        void lazyPrintGroupInfo() {
+            if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) {
+                printClosedHeader( "Group: " + currentGroupInfo->name );
+                currentGroupInfo.used = true;
+            }
+        }
+        void printTestCaseAndSectionHeader() {
+            assert( !m_sectionStack.empty() );
+            printOpenHeader( currentTestCaseInfo->name );
+
+            if( m_sectionStack.size() > 1 ) {
+                Colour colourGuard( Colour::Headers );
+
+                std::vector<SectionInfo>::const_iterator
+                    it = m_sectionStack.begin()+1, // Skip first section (test case)
+                    itEnd = m_sectionStack.end();
+                for( ; it != itEnd; ++it )
+                    printHeaderString( it->name, 2 );
+            }
+
+            SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
+
+            if( !lineInfo.empty() ){
+                stream << getLineOfChars<'-'>() << '\n';
+                Colour colourGuard( Colour::FileName );
+                stream << lineInfo << '\n';
+            }
+            stream << getLineOfChars<'.'>() << '\n' << std::endl;
+        }
+
+        void printClosedHeader( std::string const& _name ) {
+            printOpenHeader( _name );
+            stream << getLineOfChars<'.'>() << '\n';
+        }
+        void printOpenHeader( std::string const& _name ) {
+            stream  << getLineOfChars<'-'>() << '\n';
+            {
+                Colour colourGuard( Colour::Headers );
+                printHeaderString( _name );
+            }
+        }
+
+        // if string has a : in first line will set indent to follow it on
+        // subsequent lines
+        void printHeaderString( std::string const& _string, std::size_t indent = 0 ) {
+            std::size_t i = _string.find( ": " );
+            if( i != std::string::npos )
+                i+=2;
+            else
+                i = 0;
+            stream << Text( _string, TextAttributes()
+                                        .setIndent( indent+i)
+                                        .setInitialIndent( indent ) ) << '\n';
+        }
+
+        struct SummaryColumn {
+
+            SummaryColumn( std::string const& _label, Colour::Code _colour )
+            :   label( _label ),
+                colour( _colour )
+            {}
+            SummaryColumn addRow( std::size_t count ) {
+                std::ostringstream oss;
+                oss << count;
+                std::string row = oss.str();
+                for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) {
+                    while( it->size() < row.size() )
+                        *it = ' ' + *it;
+                    while( it->size() > row.size() )
+                        row = ' ' + row;
+                }
+                rows.push_back( row );
+                return *this;
+            }
+
+            std::string label;
+            Colour::Code colour;
+            std::vector<std::string> rows;
+
+        };
+
+        void printTotals( Totals const& totals ) {
+            if( totals.testCases.total() == 0 ) {
+                stream << Colour( Colour::Warning ) << "No tests ran\n";
+            }
+            else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
+                stream << Colour( Colour::ResultSuccess ) << "All tests passed";
+                stream << " ("
+                        << pluralise( totals.assertions.passed, "assertion" ) << " in "
+                        << pluralise( totals.testCases.passed, "test case" ) << ')'
+                        << '\n';
+            }
+            else {
+
+                std::vector<SummaryColumn> columns;
+                columns.push_back( SummaryColumn( "", Colour::None )
+                                        .addRow( totals.testCases.total() )
+                                        .addRow( totals.assertions.total() ) );
+                columns.push_back( SummaryColumn( "passed", Colour::Success )
+                                        .addRow( totals.testCases.passed )
+                                        .addRow( totals.assertions.passed ) );
+                columns.push_back( SummaryColumn( "failed", Colour::ResultError )
+                                        .addRow( totals.testCases.failed )
+                                        .addRow( totals.assertions.failed ) );
+                columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
+                                        .addRow( totals.testCases.failedButOk )
+                                        .addRow( totals.assertions.failedButOk ) );
+
+                printSummaryRow( "test cases", columns, 0 );
+                printSummaryRow( "assertions", columns, 1 );
+            }
+        }
+        void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) {
+            for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) {
+                std::string value = it->rows[row];
+                if( it->label.empty() ) {
+                    stream << label << ": ";
+                    if( value != "0" )
+                        stream << value;
+                    else
+                        stream << Colour( Colour::Warning ) << "- none -";
+                }
+                else if( value != "0" ) {
+                    stream  << Colour( Colour::LightGrey ) << " | ";
+                    stream  << Colour( it->colour )
+                            << value << ' ' << it->label;
+                }
+            }
+            stream << '\n';
+        }
+
+        static std::size_t makeRatio( std::size_t number, std::size_t total ) {
+            std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0;
+            return ( ratio == 0 && number > 0 ) ? 1 : ratio;
+        }
+        static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) {
+            if( i > j && i > k )
+                return i;
+            else if( j > k )
+                return j;
+            else
+                return k;
+        }
+
+        void printTotalsDivider( Totals const& totals ) {
+            if( totals.testCases.total() > 0 ) {
+                std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() );
+                std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() );
+                std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() );
+                while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 )
+                    findMax( failedRatio, failedButOkRatio, passedRatio )++;
+                while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 )
+                    findMax( failedRatio, failedButOkRatio, passedRatio )--;
+
+                stream << Colour( Colour::Error ) << std::string( failedRatio, '=' );
+                stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' );
+                if( totals.testCases.allPassed() )
+                    stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' );
+                else
+                    stream << Colour( Colour::Success ) << std::string( passedRatio, '=' );
+            }
+            else {
+                stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' );
+            }
+            stream << '\n';
+        }
+        void printSummaryDivider() {
+            stream << getLineOfChars<'-'>() << '\n';
+        }
+
+    private:
+        bool m_headerPrinted;
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_compact.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
+
+namespace Catch {
+
+    struct CompactReporter : StreamingReporterBase {
+
+        CompactReporter( ReporterConfig const& _config )
+        : StreamingReporterBase( _config )
+        {}
+
+        virtual ~CompactReporter();
+
+        static std::string getDescription() {
+            return "Reports test results on a single line, suitable for IDEs";
+        }
+
+        virtual ReporterPreferences getPreferences() const {
+            ReporterPreferences prefs;
+            prefs.shouldRedirectStdOut = false;
+            return prefs;
+        }
+
+        virtual void noMatchingTestCases( std::string const& spec ) {
+            stream << "No test cases matched '" << spec << '\'' << std::endl;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) {}
+
+        virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
+            AssertionResult const& result = _assertionStats.assertionResult;
+
+            bool printInfoMessages = true;
+
+            // Drop out if result was successful and we're not printing those
+            if( !m_config->includeSuccessfulResults() && result.isOk() ) {
+                if( result.getResultType() != ResultWas::Warning )
+                    return false;
+                printInfoMessages = false;
+            }
+
+            AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
+            printer.print();
+
+            stream << std::endl;
+            return true;
+        }
+
+        virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE {
+            if (m_config->showDurations() == ShowDurations::Always) {
+                stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+            }
+        }
+
+        virtual void testRunEnded( TestRunStats const& _testRunStats ) {
+            printTotals( _testRunStats.totals );
+            stream << '\n' << std::endl;
+            StreamingReporterBase::testRunEnded( _testRunStats );
+        }
+
+    private:
+        class AssertionPrinter {
+            void operator= ( AssertionPrinter const& );
+        public:
+            AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
+            : stream( _stream )
+            , stats( _stats )
+            , result( _stats.assertionResult )
+            , messages( _stats.infoMessages )
+            , itMessage( _stats.infoMessages.begin() )
+            , printInfoMessages( _printInfoMessages )
+            {}
+
+            void print() {
+                printSourceInfo();
+
+                itMessage = messages.begin();
+
+                switch( result.getResultType() ) {
+                    case ResultWas::Ok:
+                        printResultType( Colour::ResultSuccess, passedString() );
+                        printOriginalExpression();
+                        printReconstructedExpression();
+                        if ( ! result.hasExpression() )
+                            printRemainingMessages( Colour::None );
+                        else
+                            printRemainingMessages();
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        if( result.isOk() )
+                            printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) );
+                        else
+                            printResultType( Colour::Error, failedString() );
+                        printOriginalExpression();
+                        printReconstructedExpression();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::ThrewException:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "unexpected exception with message:" );
+                        printMessage();
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::FatalErrorCondition:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "fatal error condition with message:" );
+                        printMessage();
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::DidntThrowException:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "expected exception, got none" );
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::Info:
+                        printResultType( Colour::None, "info" );
+                        printMessage();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::Warning:
+                        printResultType( Colour::None, "warning" );
+                        printMessage();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "explicitly" );
+                        printRemainingMessages( Colour::None );
+                        break;
+                    // These cases are here to prevent compiler warnings
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        printResultType( Colour::Error, "** internal error **" );
+                        break;
+                }
+            }
+
+        private:
+            // Colour::LightGrey
+
+            static Colour::Code dimColour() { return Colour::FileName; }
+
+#ifdef CATCH_PLATFORM_MAC
+            static const char* failedString() { return "FAILED"; }
+            static const char* passedString() { return "PASSED"; }
+#else
+            static const char* failedString() { return "failed"; }
+            static const char* passedString() { return "passed"; }
+#endif
+
+            void printSourceInfo() const {
+                Colour colourGuard( Colour::FileName );
+                stream << result.getSourceInfo() << ':';
+            }
+
+            void printResultType( Colour::Code colour, std::string const& passOrFail ) const {
+                if( !passOrFail.empty() ) {
+                    {
+                        Colour colourGuard( colour );
+                        stream << ' ' << passOrFail;
+                    }
+                    stream << ':';
+                }
+            }
+
+            void printIssue( std::string const& issue ) const {
+                stream << ' ' << issue;
+            }
+
+            void printExpressionWas() {
+                if( result.hasExpression() ) {
+                    stream << ';';
+                    {
+                        Colour colour( dimColour() );
+                        stream << " expression was:";
+                    }
+                    printOriginalExpression();
+                }
+            }
+
+            void printOriginalExpression() const {
+                if( result.hasExpression() ) {
+                    stream << ' ' << result.getExpression();
+                }
+            }
+
+            void printReconstructedExpression() const {
+                if( result.hasExpandedExpression() ) {
+                    {
+                        Colour colour( dimColour() );
+                        stream << " for: ";
+                    }
+                    stream << result.getExpandedExpression();
+                }
+            }
+
+            void printMessage() {
+                if ( itMessage != messages.end() ) {
+                    stream << " '" << itMessage->message << '\'';
+                    ++itMessage;
+                }
+            }
+
+            void printRemainingMessages( Colour::Code colour = dimColour() ) {
+                if ( itMessage == messages.end() )
+                    return;
+
+                // using messages.end() directly yields compilation error:
+                std::vector<MessageInfo>::const_iterator itEnd = messages.end();
+                const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
+
+                {
+                    Colour colourGuard( colour );
+                    stream << " with " << pluralise( N, "message" ) << ':';
+                }
+
+                for(; itMessage != itEnd; ) {
+                    // If this assertion is a warning ignore any INFO messages
+                    if( printInfoMessages || itMessage->type != ResultWas::Info ) {
+                        stream << " '" << itMessage->message << '\'';
+                        if ( ++itMessage != itEnd ) {
+                            Colour colourGuard( dimColour() );
+                            stream << " and";
+                        }
+                    }
+                }
+            }
+
+        private:
+            std::ostream& stream;
+            AssertionStats const& stats;
+            AssertionResult const& result;
+            std::vector<MessageInfo> messages;
+            std::vector<MessageInfo>::const_iterator itMessage;
+            bool printInfoMessages;
+        };
+
+        // Colour, message variants:
+        // - white: No tests ran.
+        // -   red: Failed [both/all] N test cases, failed [both/all] M assertions.
+        // - white: Passed [both/all] N test cases (no assertions).
+        // -   red: Failed N tests cases, failed M assertions.
+        // - green: Passed [both/all] N tests cases with M assertions.
+
+        std::string bothOrAll( std::size_t count ) const {
+            return count == 1 ? std::string() : count == 2 ? "both " : "all " ;
+        }
+
+        void printTotals( const Totals& totals ) const {
+            if( totals.testCases.total() == 0 ) {
+                stream << "No tests ran.";
+            }
+            else if( totals.testCases.failed == totals.testCases.total() ) {
+                Colour colour( Colour::ResultError );
+                const std::string qualify_assertions_failed =
+                    totals.assertions.failed == totals.assertions.total() ?
+                        bothOrAll( totals.assertions.failed ) : std::string();
+                stream <<
+                    "Failed " << bothOrAll( totals.testCases.failed )
+                              << pluralise( totals.testCases.failed, "test case"  ) << ", "
+                    "failed " << qualify_assertions_failed <<
+                                 pluralise( totals.assertions.failed, "assertion" ) << '.';
+            }
+            else if( totals.assertions.total() == 0 ) {
+                stream <<
+                    "Passed " << bothOrAll( totals.testCases.total() )
+                              << pluralise( totals.testCases.total(), "test case" )
+                              << " (no assertions).";
+            }
+            else if( totals.assertions.failed ) {
+                Colour colour( Colour::ResultError );
+                stream <<
+                    "Failed " << pluralise( totals.testCases.failed, "test case"  ) << ", "
+                    "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.';
+            }
+            else {
+                Colour colour( Colour::ResultSuccess );
+                stream <<
+                    "Passed " << bothOrAll( totals.testCases.passed )
+                              << pluralise( totals.testCases.passed, "test case"  ) <<
+                    " with "  << pluralise( totals.assertions.passed, "assertion" ) << '.';
+            }
+        }
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter )
+
+} // end namespace Catch
+
+namespace Catch {
+    // These are all here to avoid warnings about not having any out of line
+    // virtual methods
+    NonCopyable::~NonCopyable() {}
+    IShared::~IShared() {}
+    IStream::~IStream() CATCH_NOEXCEPT {}
+    FileStream::~FileStream() CATCH_NOEXCEPT {}
+    CoutStream::~CoutStream() CATCH_NOEXCEPT {}
+    DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {}
+    StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
+    IContext::~IContext() {}
+    IResultCapture::~IResultCapture() {}
+    ITestCase::~ITestCase() {}
+    ITestCaseRegistry::~ITestCaseRegistry() {}
+    IRegistryHub::~IRegistryHub() {}
+    IMutableRegistryHub::~IMutableRegistryHub() {}
+    IExceptionTranslator::~IExceptionTranslator() {}
+    IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
+    IReporter::~IReporter() {}
+    IReporterFactory::~IReporterFactory() {}
+    IReporterRegistry::~IReporterRegistry() {}
+    IStreamingReporter::~IStreamingReporter() {}
+    AssertionStats::~AssertionStats() {}
+    SectionStats::~SectionStats() {}
+    TestCaseStats::~TestCaseStats() {}
+    TestGroupStats::~TestGroupStats() {}
+    TestRunStats::~TestRunStats() {}
+    CumulativeReporterBase::SectionNode::~SectionNode() {}
+    CumulativeReporterBase::~CumulativeReporterBase() {}
+
+    StreamingReporterBase::~StreamingReporterBase() {}
+    ConsoleReporter::~ConsoleReporter() {}
+    CompactReporter::~CompactReporter() {}
+    IRunner::~IRunner() {}
+    IMutableContext::~IMutableContext() {}
+    IConfig::~IConfig() {}
+    XmlReporter::~XmlReporter() {}
+    JunitReporter::~JunitReporter() {}
+    TestRegistry::~TestRegistry() {}
+    FreeFunctionTestCase::~FreeFunctionTestCase() {}
+    IGeneratorInfo::~IGeneratorInfo() {}
+    IGeneratorsForTest::~IGeneratorsForTest() {}
+    WildcardPattern::~WildcardPattern() {}
+    TestSpec::Pattern::~Pattern() {}
+    TestSpec::NamePattern::~NamePattern() {}
+    TestSpec::TagPattern::~TagPattern() {}
+    TestSpec::ExcludedPattern::~ExcludedPattern() {}
+    Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {}
+
+    void Config::dummy() {}
+
+    namespace TestCaseTracking {
+        ITracker::~ITracker() {}
+        TrackerBase::~TrackerBase() {}
+        SectionTracker::~SectionTracker() {}
+        IndexTracker::~IndexTracker() {}
+    }
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_MAIN
+// #included from: internal/catch_default_main.hpp
+#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
+
+#ifndef __OBJC__
+
+#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
+// Standard C/C++ Win32 Unicode wmain entry point
+extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
+#else
+// Standard C/C++ main entry point
+int main (int argc, char * argv[]) {
+#endif
+
+	int result = Catch::Session().run( argc, argv );
+    return ( result < 0xff ? result : 0xff );
+}
+
+#else // __OBJC__
+
+// Objective-C entry point
+int main (int argc, char * const argv[]) {
+#if !CATCH_ARC_ENABLED
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+#endif
+
+    Catch::registerTestMethods();
+    int result = Catch::Session().run( argc, (char* const*)argv );
+
+#if !CATCH_ARC_ENABLED
+    [pool drain];
+#endif
+
+    return ( result < 0xff ? result : 0xff );
+}
+
+#endif // __OBJC__
+
+#endif
+
+#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
+#  undef CLARA_CONFIG_MAIN
+#endif
+
+//////
+
+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
+#ifdef CATCH_CONFIG_PREFIX_ALL
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
+#else
+#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr  )
+#endif
+
+#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr )
+#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr )
+
+#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr )
+#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr )
+
+#define CATCH_CHECK_THROWS( expr )  INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr )
+#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr )
+
+#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#else
+#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#endif
+
+#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) )
+#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) )
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+    #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+    #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+    #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+    #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+    #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+    #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+    #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#else
+    #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
+    #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
+    #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
+    #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description )
+    #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
+    #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg )
+    #define CATCH_FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg )
+    #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg )
+#endif
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
+
+#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
+#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
+
+#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#else
+#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
+#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
+#endif
+#define CATCH_GIVEN( desc )    CATCH_SECTION( std::string( "Given: ") + desc, "" )
+#define CATCH_WHEN( desc )     CATCH_SECTION( std::string( " When: ") + desc, "" )
+#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( "  And: ") + desc, "" )
+#define CATCH_THEN( desc )     CATCH_SECTION( std::string( " Then: ") + desc, "" )
+#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( "  And: ") + desc, "" )
+
+// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
+#else
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE", Catch::ResultDisposition::Normal, expr )
+#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
+
+#else
+#define REQUIRE( expr ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, expr  )
+#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
+#endif
+
+#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr )
+#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr )
+
+#define CHECK( expr ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr )
+#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr )
+
+#define CHECK_THROWS( expr )  INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr )
+#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr )
+
+#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
+
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#else
+#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#endif
+
+#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) )
+#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) )
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#else
+#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
+    #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
+    #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
+    #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description )
+    #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
+    #define FAIL( msg ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg )
+    #define FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg )
+    #define SUCCEED( msg ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg )
+#endif
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
+
+#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
+#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
+
+#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
+
+#endif
+
+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#else
+#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
+#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
+#endif
+#define GIVEN( desc )    SECTION( std::string("   Given: ") + desc, "" )
+#define WHEN( desc )     SECTION( std::string("    When: ") + desc, "" )
+#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" )
+#define THEN( desc )     SECTION( std::string("    Then: ") + desc, "" )
+#define AND_THEN( desc ) SECTION( std::string("     And: ") + desc, "" )
+
+using Catch::Detail::Approx;
+
+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
diff --git a/compiler/cpp/tests/netcore/t_netcore_generator_functional_tests.cc b/compiler/cpp/tests/netcore/t_netcore_generator_functional_tests.cc
new file mode 100644
index 0000000..0b8c837
--- /dev/null
+++ b/compiler/cpp/tests/netcore/t_netcore_generator_functional_tests.cc
@@ -0,0 +1,339 @@
+// 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.
+
+#include "../catch/catch.hpp"
+#include <thrift/parse/t_program.h>
+#include <thrift/generate/t_netcore_generator.h>
+#include "t_netcore_generator_functional_tests_helpers.h"
+
+TEST_CASE( "t_netcore_generator should generate valid enum", "[functional]" )
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "wcf", "wcf" } };
+    string option_string = "";
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = new t_netcore_generator(program, parsed_options, option_string);
+
+    std::pair<string, t_enum*> pair = TestDataGenerator::get_test_enum_data(program);
+    string expected_result = pair.first;
+    t_enum* test_enum = pair.second;
+
+    string file_path = test_enum->get_name() + ".cs";
+    ofstream out;
+    out.open(file_path.c_str());
+
+    REQUIRE_NOTHROW(gen->generate_enum(out, test_enum));
+
+    out.close();
+
+    std::ifstream ifs(file_path);
+    string actual_result((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
+    std::remove(file_path.c_str());
+
+    REQUIRE(expected_result == actual_result);
+
+    delete test_enum;
+    delete gen;
+    delete program;	
+}
+
+TEST_CASE("t_netcore_generator should generate valid void", "[functional]")
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "wcf", "wcf" } };
+    string option_string = "";
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = new t_netcore_generator(program, parsed_options, option_string);
+
+    std::pair<string, t_const*> pair = TestDataGenerator::get_test_void_const_data(gen);
+    string expected_result = pair.first;
+    t_const* const_ = pair.second;
+    vector<t_const*> consts_;
+    consts_.push_back(const_);
+
+    string file_path = const_->get_name() + ".cs";
+    ofstream out;
+    out.open(file_path.c_str());
+
+    REQUIRE_THROWS(gen->generate_consts(out, consts_));
+
+    out.close();
+
+    std::ifstream ifs(file_path);
+    string actual_result((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
+    std::remove(file_path.c_str());
+
+    delete const_;
+    delete gen;
+    delete program;
+}
+
+TEST_CASE("t_netcore_generator should generate valid string with escaping keyword", "[functional]")
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "wcf", "wcf" } };
+    string option_string = "";
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = new t_netcore_generator(program, parsed_options, option_string);
+    gen->init_generator();
+
+    std::pair<string, t_const*> pair = TestDataGenerator::get_test_string_const_data(gen);
+    string expected_result = pair.first;
+    t_const* const_ = pair.second;
+    vector<t_const*> consts_;
+    consts_.push_back(const_);
+
+    string file_path = const_->get_name() + ".cs";
+    ofstream out;
+    out.open(file_path.c_str());
+
+    REQUIRE_NOTHROW(gen->generate_consts(out, consts_));
+
+    out.close();
+
+    std::ifstream ifs(file_path);
+    string actual_result((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
+    std::remove(file_path.c_str());
+
+    REQUIRE(expected_result == actual_result);
+
+    delete const_;
+    delete gen;
+    delete program;
+}
+
+TEST_CASE("t_netcore_generator should generate valid bool with escaping keyword", "[functional]")
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "wcf", "wcf" } };
+    string option_string = "";
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = new t_netcore_generator(program, parsed_options, option_string);
+    gen->init_generator();
+
+    std::pair<string, t_const*> pair = TestDataGenerator::get_test_bool_const_data(gen);
+    string expected_result = pair.first;
+    t_const* const_ = pair.second;
+    vector<t_const*> consts_;
+    consts_.push_back(const_);
+
+    string file_path = const_->get_name() + ".cs";
+    ofstream out;
+    out.open(file_path.c_str());
+
+    REQUIRE_NOTHROW(gen->generate_consts(out, consts_));
+
+    out.close();
+
+    std::ifstream ifs(file_path);
+    string actual_result((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
+    std::remove(file_path.c_str());
+
+    REQUIRE(expected_result == actual_result);
+
+    delete const_;
+    delete gen;
+    delete program;
+}
+
+TEST_CASE("t_netcore_generator should generate valid sbyte (i8) with escaping keyword", "[functional]")
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "wcf", "wcf" } };
+    string option_string = "";
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = new t_netcore_generator(program, parsed_options, option_string);
+    gen->init_generator();
+
+    std::pair<string, t_const*> pair = TestDataGenerator::get_test_i8_const_data(gen);
+    string expected_result = pair.first;
+    t_const* const_ = pair.second;
+    vector<t_const*> consts_;
+    consts_.push_back(const_);
+
+    string file_path = const_->get_name() + ".cs";
+    ofstream out;
+    out.open(file_path.c_str());
+
+    REQUIRE_NOTHROW(gen->generate_consts(out, consts_));
+
+    out.close();
+
+    std::ifstream ifs(file_path);
+    string actual_result((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
+    std::remove(file_path.c_str());
+
+    REQUIRE(expected_result == actual_result);
+
+    delete const_;
+    delete gen;
+    delete program;
+}
+
+TEST_CASE("t_netcore_generator should generate valid short (i16) with escaping keyword", "[functional]")
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "wcf", "wcf" } };
+    string option_string = "";
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = new t_netcore_generator(program, parsed_options, option_string);
+    gen->init_generator();
+
+    std::pair<string, t_const*> pair = TestDataGenerator::get_test_i16_const_data(gen);
+    string expected_result = pair.first;
+    t_const* const_ = pair.second;
+    vector<t_const*> consts_;
+    consts_.push_back(const_);
+
+    string file_path = const_->get_name() + ".cs";
+    ofstream out;
+    out.open(file_path.c_str());
+
+    REQUIRE_NOTHROW(gen->generate_consts(out, consts_));
+
+    out.close();
+
+    std::ifstream ifs(file_path);
+    string actual_result((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
+    std::remove(file_path.c_str());
+
+    REQUIRE(expected_result == actual_result);
+
+    delete const_;
+    delete gen;
+    delete program;
+}
+
+TEST_CASE("t_netcore_generator should generate valid integer (i32) with escaping keyword", "[functional]")
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "wcf", "wcf" } };
+    string option_string = "";
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = new t_netcore_generator(program, parsed_options, option_string);
+    gen->init_generator();
+
+    std::pair<string, t_const*> pair = TestDataGenerator::get_test_i32_const_data(gen);
+    string expected_result = pair.first;
+    t_const* const_ = pair.second;
+    vector<t_const*> consts_;
+    consts_.push_back(const_);
+
+    string file_path = const_->get_name() + ".cs";
+    ofstream out;
+    out.open(file_path.c_str());
+
+    REQUIRE_NOTHROW(gen->generate_consts(out, consts_));
+
+    out.close();
+
+    std::ifstream ifs(file_path);
+    string actual_result((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
+    std::remove(file_path.c_str());
+
+    REQUIRE(expected_result == actual_result);
+
+    delete const_;
+    delete gen;
+    delete program;
+}
+
+TEST_CASE("t_netcore_generator should generate valid long (i64) with escaping keyword", "[functional]")
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "wcf", "wcf" } };
+    string option_string = "";
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = new t_netcore_generator(program, parsed_options, option_string);
+    gen->init_generator();
+
+    std::pair<string, t_const*> pair = TestDataGenerator::get_test_i64_const_data(gen);
+    string expected_result = pair.first;
+    t_const* const_ = pair.second;
+    vector<t_const*> consts_;
+    consts_.push_back(const_);
+
+    string file_path = const_->get_name() + ".cs";
+    ofstream out;
+    out.open(file_path.c_str());
+
+    REQUIRE_NOTHROW(gen->generate_consts(out, consts_));
+
+    out.close();
+
+    std::ifstream ifs(file_path);
+    string actual_result((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
+    std::remove(file_path.c_str());
+
+    REQUIRE(expected_result == actual_result);
+
+    delete const_;
+    delete gen;
+    delete program;
+}
+
+TEST_CASE("t_netcore_generator should generate valid double with escaping keyword", "[functional]")
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "wcf", "wcf" } };
+    string option_string = "";
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = new t_netcore_generator(program, parsed_options, option_string);
+    gen->init_generator();
+
+    std::pair<string, t_const*> pair = TestDataGenerator::get_test_double_const_data(gen);
+    string expected_result = pair.first;
+    t_const* const_ = pair.second;
+    vector<t_const*> consts_;
+    consts_.push_back(const_);
+
+    string file_path = const_->get_name() + ".cs";
+    ofstream out;
+    out.open(file_path.c_str());
+
+    REQUIRE_NOTHROW(gen->generate_consts(out, consts_));
+
+    out.close();
+
+    std::ifstream ifs(file_path);
+    string actual_result((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
+    std::remove(file_path.c_str());
+
+    REQUIRE(expected_result == actual_result);
+
+    delete const_;
+    delete gen;
+    delete program;
+}
diff --git a/compiler/cpp/tests/netcore/t_netcore_generator_functional_tests_helpers.cc b/compiler/cpp/tests/netcore/t_netcore_generator_functional_tests_helpers.cc
new file mode 100644
index 0000000..92c170b
--- /dev/null
+++ b/compiler/cpp/tests/netcore/t_netcore_generator_functional_tests_helpers.cc
@@ -0,0 +1,237 @@
+// 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.
+
+#include <thrift/parse/t_program.h>
+#include "thrift/common.h"
+#include <thrift/generate/t_netcore_generator.h>
+#include "t_netcore_generator_functional_tests_helpers.h"
+
+const string TestDataGenerator::DEFAULT_FILE_HEADER = "/**" "\n"
+            " * Autogenerated by Thrift Compiler ()" "\n"
+            " *" "\n"
+            " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING" "\n"
+            " *  @generated" "\n"
+            " */";
+
+std::pair<string, t_enum*> TestDataGenerator::get_test_enum_data(t_program* program)
+{
+    string expected_result = DEFAULT_FILE_HEADER +
+        "\n"
+        "\n"
+        "/// <summary>\n"
+        "/// TestDoc\n"
+        "/// </summary>\n"
+        "public enum TestName\n"
+        "{\n"
+        "  None = 0,\n"
+        "  First = 1,\n"
+        "  Second = 2,\n"
+        "}\n";
+
+    t_enum* enum_ = new t_enum(program);
+    enum_->set_name("TestName");
+    enum_->set_doc("TestDoc");
+    enum_->append(new t_enum_value("None", 0));
+    enum_->append(new t_enum_value("First", 1));
+    enum_->append(new t_enum_value("Second", 2));
+
+    return std::pair<string, t_enum*>(expected_result, enum_);
+}
+
+std::pair<string, t_const*> TestDataGenerator::get_test_void_const_data(t_netcore_generator* gen)
+{
+    string expected_result = DEFAULT_FILE_HEADER;
+
+    t_type* type_ = new t_base_type("void", t_base_type::TYPE_VOID);
+    type_->set_doc("TestDoc");
+
+    t_const_value* const_value_ = new t_const_value();
+    const_value_->set_string("VoidValue");
+
+    t_const* const_ = new t_const(type_, "void", const_value_);
+    const_->set_doc("TestDoc");
+
+    return std::pair<string, t_const*>(expected_result, const_);
+}
+
+std::pair<string, t_const*> TestDataGenerator::get_test_string_const_data(t_netcore_generator* gen)
+{
+    string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netcore_type_usings() + 
+        "\n"
+        "public static class netcoreConstants\n"
+        "{\n"
+        "  /// <summary>\n"
+        "  /// TestDoc\n"
+        "  /// </summary>\n"
+        "  public const string @string = \"StringValue\";\n"
+        "}\n";
+
+    t_type* type_ = new t_base_type("string", t_base_type::TYPE_STRING);
+    type_->set_doc("TestDoc");
+
+    t_const_value* const_value_ = new t_const_value();
+    const_value_->set_string("StringValue");
+
+    t_const* const_ = new t_const(type_, "string", const_value_);
+    const_->set_doc("TestDoc");
+
+    return std::pair<string, t_const*>(expected_result, const_);
+}
+
+std::pair<string, t_const*> TestDataGenerator::get_test_bool_const_data(t_netcore_generator* gen)
+{
+    string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netcore_type_usings() +
+        "\n"
+        "public static class netcoreConstants\n"
+        "{\n"
+        "  /// <summary>\n"
+        "  /// TestDoc\n"
+        "  /// </summary>\n"
+        "  public const bool @bool = true;\n"
+        "}\n";
+
+    t_type* type_ = new t_base_type("bool", t_base_type::TYPE_BOOL);
+    type_->set_doc("TestDoc");
+
+    t_const_value* const_value_ = new t_const_value();
+    const_value_->set_integer(1);
+
+    t_const* const_ = new t_const(type_, "bool", const_value_);
+    const_->set_doc("TestDoc");
+
+    return std::pair<string, t_const*>(expected_result, const_);
+}
+
+std::pair<string, t_const*> TestDataGenerator::get_test_i8_const_data(t_netcore_generator* gen)
+{
+    string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netcore_type_usings() +
+        "\n"
+        "public static class netcoreConstants\n"
+        "{\n"
+        "  /// <summary>\n"
+        "  /// TestDoc\n"
+        "  /// </summary>\n"
+        "  public const sbyte @sbyte = 127;\n"
+        "}\n";
+
+    t_type* type_ = new t_base_type("I8", t_base_type::TYPE_I8);
+    type_->set_doc("TestDoc");
+
+    t_const_value* const_value_ = new t_const_value();
+    const_value_->set_integer(127);
+
+    t_const* const_ = new t_const(type_, "sbyte", const_value_);
+    const_->set_doc("TestDoc");
+
+    return std::pair<string, t_const*>(expected_result, const_);
+}
+
+std::pair<string, t_const*> TestDataGenerator::get_test_i16_const_data(t_netcore_generator* gen)
+{
+    string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netcore_type_usings() +
+        "\n"
+        "public static class netcoreConstants\n"
+        "{\n"
+        "  /// <summary>\n"
+        "  /// TestDoc\n"
+        "  /// </summary>\n"
+        "  public const short @short = 32767;\n"
+        "}\n";
+
+    t_type* type_ = new t_base_type("i16", t_base_type::TYPE_I16);
+    type_->set_doc("TestDoc");
+
+    t_const_value* const_value_ = new t_const_value();
+    const_value_->set_integer(32767);
+
+    t_const* const_ = new t_const(type_, "short", const_value_);
+    const_->set_doc("TestDoc");
+
+    return std::pair<string, t_const*>(expected_result, const_);
+}
+
+std::pair<string, t_const*> TestDataGenerator::get_test_i32_const_data(t_netcore_generator* gen)
+{
+    string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netcore_type_usings() +
+        "\n"
+        "public static class netcoreConstants\n"
+        "{\n"
+        "  /// <summary>\n"
+        "  /// TestDoc\n"
+        "  /// </summary>\n"
+        "  public const int @int = 2147483647;\n"
+        "}\n";
+
+    t_type* type_ = new t_base_type("i32", t_base_type::TYPE_I32);
+    type_->set_doc("TestDoc");
+
+    t_const_value* const_value_ = new t_const_value();
+    const_value_->set_integer(2147483647);
+
+    t_const* const_ = new t_const(type_, "int", const_value_);
+    const_->set_doc("TestDoc");
+
+    return std::pair<string, t_const*>(expected_result, const_);
+}
+
+std::pair<string, t_const*> TestDataGenerator::get_test_i64_const_data(t_netcore_generator* gen)
+{
+    string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netcore_type_usings() +
+        "\n"
+        "public static class netcoreConstants\n"
+        "{\n"
+        "  /// <summary>\n"
+        "  /// TestDoc\n"
+        "  /// </summary>\n"
+        "  public const long @long = 9223372036854775807;\n"
+        "}\n";
+
+    t_type* type_ = new t_base_type("i64", t_base_type::TYPE_I64);
+    type_->set_doc("TestDoc");
+
+    t_const_value* const_value_ = new t_const_value();
+    const_value_->set_integer(9223372036854775807);
+
+    t_const* const_ = new t_const(type_, "long", const_value_);
+    const_->set_doc("TestDoc");
+
+    return std::pair<string, t_const*>(expected_result, const_);
+}
+
+std::pair<string, t_const*> TestDataGenerator::get_test_double_const_data(t_netcore_generator* gen)
+{
+    string expected_result = DEFAULT_FILE_HEADER + "\n" +gen->netcore_type_usings() +
+        "\n"
+        "public static class netcoreConstants\n"
+        "{\n"
+        "  /// <summary>\n"
+        "  /// TestDoc\n"
+        "  /// </summary>\n"
+        "  public const double @double = 9.22337e+18;\n"
+        "}\n";
+
+    t_type* type_ = new t_base_type("double", t_base_type::TYPE_DOUBLE);
+    type_->set_doc("TestDoc");
+
+    t_const_value* const_value_ = new t_const_value();
+    const_value_->set_double(9223372036854775807.1);
+
+    t_const* const_ = new t_const(type_, "double", const_value_);
+    const_->set_doc("TestDoc");
+
+    return std::pair<string, t_const*>(expected_result, const_);
+}
diff --git a/compiler/cpp/tests/netcore/t_netcore_generator_functional_tests_helpers.h b/compiler/cpp/tests/netcore/t_netcore_generator_functional_tests_helpers.h
new file mode 100644
index 0000000..c6eaac2
--- /dev/null
+++ b/compiler/cpp/tests/netcore/t_netcore_generator_functional_tests_helpers.h
@@ -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.
+
+#include <thrift/parse/t_program.h>
+
+class TestDataGenerator
+{
+public:
+    static const string DEFAULT_FILE_HEADER;
+
+    static std::pair<string, t_enum*> get_test_enum_data(t_program* program);
+    static std::pair<string, t_const*> get_test_void_const_data(t_netcore_generator* gen);
+    static std::pair<string, t_const*> get_test_string_const_data(t_netcore_generator* gen);
+    static std::pair<string, t_const*> get_test_bool_const_data(t_netcore_generator* gen);
+    static std::pair<string, t_const*> get_test_i8_const_data(t_netcore_generator* gen);
+    static std::pair<string, t_const*> get_test_i16_const_data(t_netcore_generator* gen);
+    static std::pair<string, t_const*> get_test_i32_const_data(t_netcore_generator* gen);
+    static std::pair<string, t_const*> get_test_i64_const_data(t_netcore_generator* gen);
+    static std::pair<string, t_const*> get_test_double_const_data(t_netcore_generator* gen);
+};
diff --git a/compiler/cpp/tests/netcore/t_netcore_generator_helpers_tests.cc b/compiler/cpp/tests/netcore/t_netcore_generator_helpers_tests.cc
new file mode 100644
index 0000000..0bcbeed
--- /dev/null
+++ b/compiler/cpp/tests/netcore/t_netcore_generator_helpers_tests.cc
@@ -0,0 +1,209 @@
+// 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.
+
+#include "../catch/catch.hpp"
+#include <thrift/parse/t_program.h>
+#include <thrift/generate/t_netcore_generator.h>
+
+using std::vector;
+
+TEST_CASE("t_netcore_generator::netcore_type_usings() without option wcf should return valid namespaces", "[helpers]")
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "union", "union" } };
+    string option_string = "";
+
+    string expected_namespaces = "using System;\n"
+                                "using System.Collections;\n"
+                                "using System.Collections.Generic;\n"
+                                "using System.Text;\n"
+                                "using System.IO;\n"
+                                "using System.Threading;\n"
+                                "using System.Threading.Tasks;\n"
+                                "using Thrift;\n"
+                                "using Thrift.Collections;\n" + endl;
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = new t_netcore_generator(program, parsed_options, option_string);
+
+    REQUIRE_FALSE(gen->is_wcf_enabled());
+    REQUIRE(gen->netcore_type_usings() == expected_namespaces);
+
+    delete gen;
+    delete program;
+}
+
+TEST_CASE("t_netcore_generator::netcore_type_usings() with option wcf should return valid namespaces", "[helpers]")
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "wcf", "wcf" } };
+    string option_string = "";
+
+    string expected_namespaces_wcf = "using System;\n"
+                                    "using System.Collections;\n"
+                                    "using System.Collections.Generic;\n"
+                                    "using System.Text;\n"
+                                    "using System.IO;\n"
+                                    "using System.Threading;\n"
+                                    "using System.Threading.Tasks;\n"
+                                    "using Thrift;\n"
+                                    "using Thrift.Collections;\n"
+                                    "using System.ServiceModel;\n"
+                                    "using System.Runtime.Serialization;\n" + endl;
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = new t_netcore_generator(program, parsed_options, option_string);
+
+    REQUIRE(gen->is_wcf_enabled());
+    REQUIRE(gen->netcore_type_usings() == expected_namespaces_wcf);
+
+    delete gen;
+    delete program;
+}
+
+TEST_CASE("t_netcore_generator should contains latest C# keywords to normalize with @", "[helpers]")
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "wcf", "wcf" } };
+    string option_string = "";
+    vector<string> current_keywords = {
+        { "abstract" },
+        { "as" },
+        { "base" },
+        { "bool" },
+        { "break" },
+        { "byte" },
+        { "case" },
+        { "catch" },
+        { "char" },
+        { "checked" },
+        { "class" },
+        { "const" },
+        { "continue" },
+        { "decimal" },
+        { "default" },
+        { "delegate" },
+        { "do" },
+        { "double" },
+        { "else" },
+        { "enum" },
+        { "event" },
+        { "explicit" },
+        { "extern" },
+        { "false" },
+        { "finally" },
+        { "fixed" },
+        { "float" },
+        { "for" },
+        { "foreach" },
+        { "goto" },
+        { "if" },
+        { "implicit" },
+        { "in" },
+        { "int" },
+        { "interface" },
+        { "internal" },
+        { "is" },
+        { "lock" },
+        { "long" },
+        { "namespace" },
+        { "new" },
+        { "null" },
+        { "object" },
+        { "operator" },
+        { "out" },
+        { "override" },
+        { "params" },
+        { "private" },
+        { "protected" },
+        { "public" },
+        { "readonly" },
+        { "ref" },
+        { "return" },
+        { "sbyte" },
+        { "sealed" },
+        { "short" },
+        { "sizeof" },
+        { "stackalloc" },
+        { "static" },
+        { "string" },
+        { "struct" },
+        { "switch" },
+        { "this" },
+        { "throw" },
+        { "true" },
+        { "try" },
+        { "typeof" },
+        { "uint" },
+        { "ulong" },
+        { "unchecked" },
+        { "unsafe" },
+        { "ushort" },
+        { "using" },
+        { "void" },
+        { "volatile" },
+        { "while" },
+        // Contextual Keywords
+        { "add" },
+        { "alias" },
+        { "ascending" },
+        { "async" },
+        { "await" },
+        { "descending" },
+        { "dynamic" },
+        { "from" },
+        { "get" },
+        { "global" },
+        { "group" },
+        { "into" },
+        { "join" },
+        { "let" },
+        { "orderby" },
+        { "partial" },
+        { "remove" },
+        { "select" },
+        { "set" },
+        { "value" },
+        { "var" },
+        { "when" },
+        { "where" },
+        { "yield" }
+    };
+
+    string missed_keywords = "";
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = new t_netcore_generator(program, parsed_options, option_string);
+    gen->init_generator();
+    map<string, int> generators_keywords = gen->get_keywords_list();
+
+    for (vector<string>::iterator it = current_keywords.begin(); it != current_keywords.end(); ++it)
+    {
+        if (generators_keywords.find(*it) == generators_keywords.end())
+        {
+            missed_keywords = missed_keywords + *it + ",";
+        }
+    }
+
+    REQUIRE(missed_keywords == "");
+
+    delete gen;
+    delete program;
+}
diff --git a/compiler/cpp/tests/netcore/t_netcore_generator_initialization_tests.cc b/compiler/cpp/tests/netcore/t_netcore_generator_initialization_tests.cc
new file mode 100644
index 0000000..ec17733
--- /dev/null
+++ b/compiler/cpp/tests/netcore/t_netcore_generator_initialization_tests.cc
@@ -0,0 +1,74 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "../catch/catch.hpp"
+#include <thrift/parse/t_program.h>
+#include <thrift/generate/t_netcore_generator.h>
+
+TEST_CASE( "t_netcore_generator should throw error with unknown options", "[initialization]" )
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "keys", "keys" } };
+    string option_string = "";
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = nullptr;
+
+    REQUIRE_THROWS(gen = new t_netcore_generator(program, parsed_options, option_string));	
+
+    delete gen;
+    delete program;	
+}
+
+TEST_CASE("t_netcore_generator should create valid instance with valid options", "[initialization]")
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "wcf", "wcf" }, { "nullable", "nullable"} };
+    string option_string = "";
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = nullptr;
+
+    REQUIRE_NOTHROW(gen = new t_netcore_generator(program, parsed_options, option_string));
+    REQUIRE(gen != nullptr);
+    REQUIRE(gen->is_wcf_enabled());
+    REQUIRE(gen->is_nullable_enabled());
+    REQUIRE_FALSE(gen->is_hashcode_enabled());
+    REQUIRE_FALSE(gen->is_serialize_enabled());
+    REQUIRE_FALSE(gen->is_union_enabled());
+
+    delete gen;
+    delete program;
+}
+
+TEST_CASE("t_netcore_generator should pass init succesfully", "[initialization]")
+{
+    string path = "CassandraTest.thrift";
+    string name = "netcore";
+    map<string, string> parsed_options = { { "wcf", "wcf" },{ "nullable", "nullable" } };
+    string option_string = "";
+
+    t_program* program = new t_program(path, name);
+    t_netcore_generator* gen = new t_netcore_generator(program, parsed_options, option_string);
+
+    REQUIRE_NOTHROW(gen->init_generator());
+
+    delete gen;
+    delete program;
+}
diff --git a/compiler/cpp/tests/tests_main.cc b/compiler/cpp/tests/tests_main.cc
new file mode 100644
index 0000000..21d09b9
--- /dev/null
+++ b/compiler/cpp/tests/tests_main.cc
@@ -0,0 +1,19 @@
+// 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.
+
+#define CATCH_CONFIG_MAIN
+#include "catch/catch.hpp"
diff --git a/compiler/cpp/version.h.in b/compiler/cpp/version.h.in
deleted file mode 100644
index 5770ec9..0000000
--- a/compiler/cpp/version.h.in
+++ /dev/null
@@ -1 +0,0 @@
-#define THRIFT_VERSION "@PACKAGE_VERSION@"
diff --git a/composer.json b/composer.json
index 521841e..1d3a6c0 100644
--- a/composer.json
+++ b/composer.json
@@ -1,9 +1,11 @@
 {
     "name": "apache/thrift",
     "description": "Apache Thrift RPC system",
-    "homepage": "http://thrift.apache.org/",
+    "homepage": "http://thrift.apache.org",
     "type": "library",
+    "keywords": ["RPC"],
     "license": "Apache-2.0",
+    "readme": "README.md",
     "authors": [
         {
             "name": "Apache Thrift Developers",
@@ -16,10 +18,22 @@
         "issues": "https://issues.apache.org/jira/browse/THRIFT"
     },
     "require": {
-        "php": ">=5.3.0"
+        "php": "^5.5 || ^7.0"
+    },
+    "require-dev": {
+        "phpunit/phpunit": "~4.8.36",
+        "squizlabs/php_codesniffer": "3.*"
     },
     "autoload": {
-        "psr-0": {"Thrift": "lib/php/lib/"}
+        "psr-4": {"Thrift\\": "lib/php/lib/"}
     },
-    "minimum-stability": "dev"
+    "autoload-dev": {
+        "psr-4": {"Test\\Thrift\\": "lib/php/test/"}
+    },
+    "minimum-stability": "stable",
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.0.x-dev"
+        }
+    }
 }
diff --git a/configure.ac b/configure.ac
index 93e1a57..2174629 100755
--- a/configure.ac
+++ b/configure.ac
@@ -18,12 +18,13 @@
 #
 
 AC_PREREQ(2.65)
+AC_CONFIG_MACRO_DIR([./aclocal])
 
-AC_INIT([thrift], [0.9.1])
+AC_INIT([thrift], [1.0.0])
 
 AC_CONFIG_AUX_DIR([.])
 
-AM_INIT_AUTOMAKE([1.11 tar-ustar])
+AM_INIT_AUTOMAKE([1.13 subdir-objects tar-ustar])
 PKG_PROG_PKG_CONFIG
 
 AC_ARG_VAR([PY_PREFIX], [Prefix for installing Python modules.
@@ -33,10 +34,10 @@
 AS_IF([test "x$PY_PREFIX" = x], [PY_PREFIX="/usr"])
 
 AC_ARG_VAR([JAVA_PREFIX], [Prefix for installing the Java lib jar.
-                           (Normal --prefix is ignored for Java because
-                           Java has different conventions.)
                            Default = "/usr/local/lib"])
-AS_IF([test "x$JAVA_PREFIX" = x], [JAVA_PREFIX="/usr/local/lib"])
+AS_IF([test "x$JAVA_PREFIX" != x], [JAVA_PREFIX="$JAVA_PREFIX/usr/local/lib"],
+      [test "x$PREFIX" != x], [JAVA_PREFIX="$PREFIX/usr/local/lib"],
+      [JAVA_PREFIX="/usr/local/lib"])
 
 AC_ARG_VAR([RUBY_PREFIX], [Prefix for installing Ruby modules.
                            (Normal --prefix is ignored for Ruby because
@@ -82,12 +83,16 @@
 AC_ARG_VAR([DMD_LIBEVENT_FLAGS], [DMD flags for linking libevent (auto-detected if not set).])
 AC_ARG_VAR([DMD_OPENSSL_FLAGS], [DMD flags for linking OpenSSL (auto-detected if not set).])
 
+AC_ARG_VAR([THRIFT], [Path to the thrift tool (needed for cross-compilation).])
+AS_IF([test "x$THRIFT" = x], [THRIFT=`pwd`/compiler/cpp/thrift])
+
 AC_PROG_CC
 AC_PROG_CPP
 AC_PROG_CXX
 AC_PROG_INSTALL
 AC_PROG_LIBTOOL
 AC_PROG_MAKE_SET
+AC_PROG_BISON(2.5)
 AC_PROG_YACC
 AC_PROG_LEX
 AM_PROG_LEX
@@ -97,16 +102,60 @@
 AC_PROG_RANLIB
 
 AC_LANG([C++])
+AX_CXX_COMPILE_STDCXX_11([noext], [mandatory])
+
+AM_EXTRA_RECURSIVE_TARGETS([style])
+AC_SUBST(CPPSTYLE_CMD, 'find . -type f \( -iname "*.h" -or -iname "*.cpp" -or -iname "*.cc" -or -iname "*.tcc" \) -printf "Reformatting: %h/%f\n" -exec clang-format -i {} \;')
+# '
+# The above comment is to fix editor syntax highlighting
+
+AC_ARG_ENABLE([libs],
+  AS_HELP_STRING([--enable-libs], [build the Apache Thrift libraries [default=yes]]),
+  [], enable_libs=yes
+)
+have_libs=yes
+if test "$enable_libs" = "no"; then
+  have_libs="no"
+  with_cpp="no"
+  with_c_glib="no"
+  with_cl="no"
+  with_java="no"
+  with_csharp="no"
+  with_python="no"
+  with_py3="no"
+  with_ruby="no"
+  with_haskell="no"
+  with_haxe="no"
+  with_dotnetcore="no"
+  with_perl="no"
+  with_php="no"
+  with_php_extension="no"
+  with_dart="no"
+  with_erlang="no"
+  with_go="no"
+  with_d="no"
+  with_nodejs="no"
+  with_nodets="no"
+  with_lua="no"
+  with_rs="no"
+  with_swift="no"
+fi
 
 AX_THRIFT_LIB(cpp, [C++], yes)
 have_cpp=no
 if test "$with_cpp" = "yes";  then
-  AX_BOOST_BASE([1.40.0])
+  AX_BOOST_BASE([1.53.0])
   if test "x$succeeded" = "xyes" ; then
+    AC_SUBST([BOOST_LIB_DIR], [$(echo "$BOOST_LDFLAGS" | sed -e 's/^\-L//')])
+    AC_SUBST([BOOST_CHRONO_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_chrono.a")])
+    AC_SUBST([BOOST_FILESYSTEM_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_filesystem.a")])
+    AC_SUBST([BOOST_SYSTEM_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_system.a")])
+    AC_SUBST([BOOST_TEST_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_unit_test_framework.a")])
+    AC_SUBST([BOOST_THREAD_LDADD], [$(echo "$BOOST_LIB_DIR/libboost_thread.a")])
     have_cpp="yes"
   fi
 
-  AX_LIB_EVENT([1.0])
+  AX_LIB_EVENT([2.0])
   have_libevent=$success
 
   AX_LIB_ZLIB([1.2.3])
@@ -118,14 +167,33 @@
     PKG_CHECK_MODULES([QT], [QtCore >= 4.3, QtNetwork >= 4.3], have_qt=yes, have_qt=no)
   fi
   if test "$have_qt" = "yes"; then
-    AC_PATH_PROGS([QT_MOC], [moc-qt4 moc])
-    have_qt=$success
+    AC_PATH_PROGS([QT_MOC], [moc-qt4 moc], "fail")
+    if test "$QT_MOC" = "fail"; then
+      have_qt=no
+    fi
+  fi
+
+  AX_THRIFT_LIB(qt5, [Qt5], yes)
+  have_qt5=no
+  qt_reduce_reloc=""
+  if test "$with_qt5" = "yes";  then
+    PKG_CHECK_MODULES([QT5], [Qt5Core >= 5.0, Qt5Network >= 5.0],
+                      [have_qt5=yes;qt_reduce_reloc=`$PKG_CONFIG --variable=qt_config Qt5Core | grep "reduce_relocations"`],
+                      [have_qt5=no])
+  fi
+  if test "$have_qt5" = "yes"; then
+    AC_PATH_PROGS([QT5_MOC], [moc-qt5 moc], "fail")
+    if test "$QT5_MOC" = "fail"; then
+      have_qt5=no
+    fi
   fi
 fi
 AM_CONDITIONAL([WITH_CPP], [test "$have_cpp" = "yes"])
 AM_CONDITIONAL([AMX_HAVE_LIBEVENT], [test "$have_libevent" = "yes"])
 AM_CONDITIONAL([AMX_HAVE_ZLIB], [test "$have_zlib" = "yes"])
 AM_CONDITIONAL([AMX_HAVE_QT], [test "$have_qt" = "yes"])
+AM_CONDITIONAL([AMX_HAVE_QT5], [test "$have_qt5" = "yes"])
+AM_CONDITIONAL([QT5_REDUCE_RELOCATIONS], [test "x$qt_reduce_reloc" != "x"])
 
 AX_THRIFT_LIB(c_glib, [C (GLib)], yes)
 if test "$with_c_glib" = "yes"; then
@@ -137,8 +205,21 @@
 fi
 AM_CONDITIONAL(WITH_C_GLIB, [test "$have_glib2" = "yes" -a "$have_gobject2" = "yes"])
 
+echo "OpenSSL check"
+if test "$have_cpp" = "yes" -o "$have_c_glib" = "yes";  then
+  echo "Have cpp or c so we check for OpenSSL"
+  AX_CHECK_OPENSSL()
+fi
+
 AX_THRIFT_LIB(csharp, [C#], yes)
 if test "$with_csharp" = "yes";  then
+  PKG_CHECK_MODULES(MONO, mono >= 2.11.0, mono_2_11=yes, mono_2_11=no)
+  if test "$mono_2_11" == "yes"; then
+    AC_PATH_PROG([MCS], [mcs])
+    if test "x$MCS" != "x"; then
+      mono_mcs="yes"
+    fi
+  fi
   PKG_CHECK_MODULES(MONO, mono >= 2.0.0, net_3_5=yes, net_3_5=no)
   PKG_CHECK_MODULES(MONO, mono >= 1.2.4, have_mono=yes, have_mono=no)
   if test "$have_mono" = "yes" ; then
@@ -147,6 +228,7 @@
 fi
 AM_CONDITIONAL(WITH_MONO, [test "$have_csharp" = "yes"])
 AM_CONDITIONAL(NET_2_0, [test "$net_3_5" = "no"])
+AM_CONDITIONAL(MONO_MCS, [test "$mono_mcs" = "yes"])
 
 AX_THRIFT_LIB(java, [Java], yes)
 if test "$with_java" = "yes";  then
@@ -155,7 +237,8 @@
   AX_CHECK_ANT_VERSION($ANT, 1.7)
   AC_SUBST(CLASSPATH)
   AC_SUBST(ANT_FLAGS)
-  if test "x$JAVAC" != "x" && test "x$JAVAC" != "x" && test "x$ANT" != "x" ; then
+  AC_SUBST(GRADLE_OPTS)
+  if test "x$JAVA" != "x" && test "x$JAVAC" != "x" && test "x$ANT" != "x" ; then
     have_java="yes"
   fi
 fi
@@ -165,28 +248,90 @@
 if test "$with_erlang" = "yes";  then
   AC_ERLANG_PATH_ERL
   AC_ERLANG_PATH_ERLC
+  AC_PATH_PROG([REBAR], [rebar])
   if test -n "$ERLC" ; then
     AC_ERLANG_SUBST_LIB_DIR
     # Install into the detected Erlang directory instead of $libdir/erlang/lib
     ERLANG_INSTALL_LIB_DIR="$ERLANG_LIB_DIR"
     AC_ERLANG_SUBST_INSTALL_LIB_SUBDIR(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
   fi
-  if test -n "$ERL" -a -n "$ERLC" ; then
+  if test -n "$ERL" -a -n "$ERLC" && test "x$REBAR" != "x" ; then
     have_erlang="yes"
+
+    # otp_release is simply a number (like "17") for OTP17+ while "R16..." for OTP16 or less.
+    # OTP version is currently only used for running tests.
+    if $ERL -eval 'erlang:display(erlang:system_info(otp_release)),halt().' -noshell | grep "^\"R" >/dev/null; then
+      erlang_otp16_or_less="yes"
+    fi
   fi
 fi
 AM_CONDITIONAL(WITH_ERLANG, [test "$have_erlang" = "yes"])
+AM_CONDITIONAL(ERLANG_OTP16, [test "$erlang_otp16_or_less" = "yes"])
 
+AX_THRIFT_LIB(nodejs, [Nodejs], yes)
+have_nodejs=no
+if test "$with_nodejs" = "yes"; then
+  AC_PATH_PROGS([NODEJS], [nodejs node])
+  AC_PATH_PROG([NPM], [npm])
+  if test "x$NODEJS" != "x" -a "x$NPM" != "x"; then
+    have_nodejs="yes"
+  fi
+fi
+AM_CONDITIONAL(WITH_NODEJS, [test "$have_nodejs" = "yes"])
+AM_CONDITIONAL(HAVE_NPM, [test "x$NPM" != "x"])
+
+AX_THRIFT_LIB(nodets, [Nodets], yes)
+have_nodets=no
+if test "$with_nodets" = "yes"; then
+  AC_PATH_PROGS([NODETS], [nodets node])
+  AC_PATH_PROG([NPM], [npm])
+  if test "x$NODETS" != "x" -a "x$NPM" != "x"; then
+    have_nodets="yes"
+  fi
+fi
+AM_CONDITIONAL(WITH_NODETS, [test "$have_nodets" = "yes"])
+AM_CONDITIONAL(HAVE_NPM, [test "x$NPM" != "x"])
+
+AX_THRIFT_LIB(lua, [Lua], yes)
+have_lua=no
+if test "$with_lua" = "yes"; then
+  AX_PROG_LUA(5.2,, have_lua="yes", have_lua="no")
+  if test "$have_lua" = "yes"; then
+    AX_LUA_HEADERS(, have_lua="no")
+    AX_LUA_LIBS(, have_lua="no")
+  fi
+fi
+AM_CONDITIONAL(WITH_LUA, [test "$have_lua" = "yes"])
+
+# Find python regardless of with_python value, because it's needed by make cross
+AM_PATH_PYTHON(2.6,, :)
 AX_THRIFT_LIB(python, [Python], yes)
 if test "$with_python" = "yes";  then
-  AM_PATH_PYTHON(2.4,, :)
-  if test "x$PYTHON" != "x" && test "x$PYTHON" != "x:" ; then
+  if test -n "$PYTHON"; then
     have_python="yes"
   fi
+  AC_PATH_PROG([TRIAL], [trial])
+  if test -n "$TRIAL"; then
+    have_trial="yes"
+  fi
 fi
 AM_CONDITIONAL(WITH_PYTHON, [test "$have_python" = "yes"])
+AM_CONDITIONAL(WITH_TWISTED_TEST, [test "$have_trial" = "yes"])
 
-AC_PATH_PROG([TRIAL], [trial])
+# Find "python3" executable.
+# It's distro specific and far from ideal but needed to cross test py2-3 at once.
+# TODO: find "python2" if it's 3.x
+have_py3="no"
+AX_THRIFT_LIB(py3, [Py3], yes)
+if test "$with_py3" = "yes"; then
+  if $PYTHON --version 2>&1 | grep -q "Python 2"; then
+    AC_PATH_PROGS([PYTHON3], [python3 python3.7 python37 python3.6 python36 python3.5 python35 python3.4 python34])
+    if test -n "$PYTHON3"; then
+      have_py3="yes"
+    fi
+  fi
+fi
+AM_CONDITIONAL(WITH_PY3, [test "$have_py3" = "yes"])
 
 AX_THRIFT_LIB(perl, [Perl], yes)
 if test "$with_perl" = "yes"; then
@@ -194,9 +339,13 @@
   if test -n "$PERL" ; then
     AC_PROG_PERL_MODULES([Bit::Vector], success="yes", success="no")
     have_perl_bit_vector="$success"
+    AC_PROG_PERL_MODULES([Class::Accessor], success="yes", success="no")
+    have_perl_class_accessor="$success"
   fi
   if test -n "$PERL" -a "$have_perl_bit_vector" = "yes" ; then
-    have_perl="yes"
+    if test -n "$PERL" -a "$have_perl_class_accessor" = "yes" ; then
+      have_perl="yes"
+    fi
   fi
 fi
 AM_CONDITIONAL(WITH_PERL, [test "$have_perl" = "yes"])
@@ -212,24 +361,32 @@
 
 AX_THRIFT_LIB(php_extension, [PHP_EXTENSION], yes)
 if test "$with_php_extension" = "yes"; then
-  AC_PATH_PROG([PHP_CONFIG], [php-config])
-  if test -n "$PHP_CONFIG" ; then
-    AC_CONFIG_SUBDIRS([lib/php/src/ext/thrift_protocol])
-    have_php_extension="yes"
+  if test -f "lib/php/src/ext/thrift_protocol/configure"; then
+    AC_PATH_PROG([PHP_CONFIG], [php-config])
+    if test -n "$PHP_CONFIG" ; then
+      AC_CONFIG_SUBDIRS([lib/php/src/ext/thrift_protocol])
+      have_php_extension="yes"
+    fi
   fi
 fi
 AM_CONDITIONAL(WITH_PHP_EXTENSION, [test "$have_php_extension" = "yes"])
 
-AC_PATH_PROG([PHPUNIT], [phpunit])
-AM_CONDITIONAL(HAVE_PHPUNIT, [test "x$PHPUNIT" != "x"])
+AX_THRIFT_LIB(dart, [DART], yes)
+if test "$with_dart" = "yes"; then
+  AC_PATH_PROG([DART], [dart])
+  AC_PATH_PROG([DARTPUB], [pub])
+  if test "x$DART" != "x" -a "x$DARTPUB" != "x"; then
+    have_dart="yes"
+  fi
+fi
+AM_CONDITIONAL(WITH_DART, [test "$have_dart" = "yes"])
 
 AX_THRIFT_LIB(ruby, [Ruby], yes)
 have_ruby=no
 if test "$with_ruby" = "yes"; then
   AC_PATH_PROG([RUBY], [ruby])
-  AC_PATH_PROG([RAKE], [rake])
   AC_PATH_PROG([BUNDLER], [bundle])
-  if test "x$RUBY" != "x" -a "x$RAKE" != "x"; then
+  if test "x$RUBY" != "x" -a "x$BUNDLER" != "x"; then
     have_ruby="yes"
   fi
 fi
@@ -258,10 +415,99 @@
 if test "$with_go" = "yes";  then
   AC_PATH_PROG([GO], [go])
   if [[ -x "$GO" ]] ; then
-    have_go="yes"
+    AS_IF([test -n "$GO"],[
+      ax_go_version="1.4"
+      ax_go17_version="1.7"
+
+      AC_MSG_CHECKING([for Go version])
+      golang_version=`$GO version 2>&1 | $SED -e 's/\(go \)\(version \)\(go\)\(@<:@0-9@:>@.@<:@0-9@:>@.@<:@0-9@:>@\)\(@<:@\*@:>@*\).*/\4/'`
+      AC_MSG_RESULT($golang_version)
+      AC_SUBST([golang_version],[$golang_version])
+      AX_COMPARE_VERSION([$ax_go_version],[le],[$golang_version],[
+      :
+        have_go="yes"
+      ],[
+      :
+        have_go="no"
+      ])
+      AX_COMPARE_VERSION([$golang_version],[lt],[$ax_go17_version],[
+      :
+        go_version_lt_17="yes"
+      ],[
+      :
+        go_version_lt_17="no"
+      ])
+    ],[
+      AC_MSG_WARN([could not find Go ])
+      have_go="no"
+    ])
   fi
 fi
 AM_CONDITIONAL(WITH_GO, [test "$have_go" = "yes"])
+AM_CONDITIONAL([GOVERSION_LT_17], [test "$go_version_lt_17" = "yes"])
+
+AX_THRIFT_LIB(swift, [Swift], yes)
+have_swift="no"
+if test "$with_swift" = "yes"; then
+  AC_PATH_PROG([SWIFT], [swift])
+  if test "x$SWIFT" != "x" -a "x$SWIFT" != "x"; then
+    have_swift="yes"
+  fi
+fi
+AM_CONDITIONAL([WITH_SWIFT], [test "$have_swift" = "yes"])
+
+AX_THRIFT_LIB(rs, [Rust], yes)
+have_rs="no"
+if test "$with_rs" = "yes";  then
+  AC_PATH_PROG([CARGO], [cargo])
+  AC_PATH_PROG([RUSTC], [rustc])
+  if [[ -x "$CARGO" ]] && [[ -x "$RUSTC" ]]; then
+      min_rustc_version="1.13"
+
+      AC_MSG_CHECKING([for rustc version])
+      rustc_version=`$RUSTC --version 2>&1 | $SED -e 's/\(rustc \)\([0-9]\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\).*/\2.\3/'`
+      AC_MSG_RESULT($rustc_version)
+      AC_SUBST([rustc_version],[$rustc_version])
+
+      AX_COMPARE_VERSION([$min_rustc_version],[le],[$rustc_version],[
+      :
+        have_rs="yes"
+      ],[
+      :
+        have_rs="no"
+      ])
+  fi
+fi
+AM_CONDITIONAL(WITH_RS, [test "$have_rs" = "yes"])
+
+AX_THRIFT_LIB(cl, [Common Lisp], yes)
+have_cl="no"
+if test "$with_cl" = "yes";  then
+  AC_PATH_PROG([SBCL], [sbcl])
+  if test "x$SBCL" != "x"; then
+    have_cl="yes"
+  fi
+fi
+AM_CONDITIONAL(WITH_CL, [test "$have_cl" = "yes"])
+
+AX_THRIFT_LIB(haxe, [Haxe], yes)
+if test "$with_haxe" = "yes";  then
+  AC_PATH_PROG([HAXE], [haxe])
+  if [[ -x "$HAXE" ]] ; then
+    AX_PROG_HAXE_VERSION( [3.1.3], have_haxe="yes", have_haxe="no")
+  fi
+fi
+AM_CONDITIONAL(WITH_HAXE, [test "$have_haxe" = "yes"])
+
+
+AX_THRIFT_LIB(dotnetcore, [.NET Core], yes)
+if test "$with_dotnetcore" = "yes";  then
+  AC_PATH_PROG([DOTNETCORE], [dotnet])
+  if [[ -x "$DOTNETCORE" ]] ; then
+    AX_PROG_DOTNETCORE_VERSION( [2.0.0], have_dotnetcore="yes", have_dotnetcore="no")
+  fi
+fi
+AM_CONDITIONAL(WITH_DOTNETCORE, [test "$have_dotnetcore" = "yes"])
 
 
 AX_THRIFT_LIB(d, [D], yes)
@@ -304,7 +550,7 @@
       else
         AX_LIB_EVENT([2.0])
         if test "$success" = "yes"; then
-          DMD_LIBEVENT_FLAGS=$(echo "$LIBEVENT_LDFLAGS $LIBEVENT_LIBS" | \
+          DMD_LIBEVENT_FLAGS=$(echo "-fuse-ld=gold $LIBEVENT_LDFLAGS $LIBEVENT_LIBS" | \
             sed -e 's/^ *//g;s/ *$//g;s/^\(.\)/-L\1/g;s/  */ -L/g')
           with_d_event_tests="yes"
         else
@@ -328,7 +574,7 @@
       else
         AX_CHECK_OPENSSL([with_d_ssl_tests="yes"])
         if test "$with_d_ssl_tests" = "yes"; then
-          DMD_OPENSSL_FLAGS=$(echo "$OPENSSL_LDFLAGS $OPENSSL_LIBS" | \
+          DMD_OPENSSL_FLAGS=$(echo "-fuse-ld=gold $OPENSSL_LDFLAGS $OPENSSL_LIBS" | \
             sed -e 's/^ *//g;s/ *$//g;s/^\(.\)/-L\1/g;s/  */ -L/g')
         else
           AC_MSG_WARN([D OpenSSL interface present, but OpenSSL library not found.])
@@ -350,13 +596,40 @@
 AM_CONDITIONAL(WITH_D_SSL_TESTS, [test "$with_d_ssl_tests" = "yes"])
 AC_SUBST(DMD_OPENSSL_FLAGS)
 
-
+AC_ARG_ENABLE([tests],
+  AS_HELP_STRING([--enable-tests], [build tests [default=yes]]),
+  [], enable_tests=yes
+)
 have_tests=yes
-if test "$with_tests" = "no"; then
+if test "$enable_tests" = "no"; then
   have_tests="no"
 fi
 AM_CONDITIONAL(WITH_TESTS, [test "$have_tests" = "yes"])
 
+AC_ARG_ENABLE([plugin],
+  AS_HELP_STRING([--enable-plugin], [build compiler plugin support [default=no]]),
+  [], enable_plugin=no
+)
+have_plugin=yes
+if test "$have_cpp" = "no" ; then
+  have_plugin="no"
+fi
+if test "$enable_plugin" = "no"; then
+  have_plugin="no"
+fi
+AC_CONFIG_LINKS([compiler/cpp/test/plugin/t_cpp_generator.cc:compiler/cpp/src/thrift/generate/t_cpp_generator.cc])
+AM_CONDITIONAL(WITH_PLUGIN, [test "$have_plugin" = "yes"])
+
+AC_ARG_ENABLE([tutorial],
+  AS_HELP_STRING([--enable-tutorial], [build tutorial [default=yes]]),
+  [], enable_tutorial=yes
+)
+have_tutorial=yes
+if test "$enable_tutorial" = "no"; then
+  have_tutorial="no"
+fi
+AM_CONDITIONAL(WITH_TUTORIAL, [test "$have_tutorial" = "yes"])
+
 AM_CONDITIONAL(MINGW, false)
 case "${host_os}" in
 *mingw*)
@@ -386,11 +659,14 @@
 AC_CHECK_HEADERS([netdb.h])
 AC_CHECK_HEADERS([netinet/in.h])
 AC_CHECK_HEADERS([pthread.h])
+AC_CHECK_HEADERS([signal.h])
 AC_CHECK_HEADERS([stddef.h])
 AC_CHECK_HEADERS([stdlib.h])
+AC_CHECK_HEADERS([sys/ioctl.h])
 AC_CHECK_HEADERS([sys/socket.h])
 AC_CHECK_HEADERS([sys/time.h])
 AC_CHECK_HEADERS([sys/un.h])
+AC_CHECK_HEADERS([poll.h])
 AC_CHECK_HEADERS([sys/poll.h])
 AC_CHECK_HEADERS([sys/resource.h])
 AC_CHECK_HEADERS([unistd.h])
@@ -411,21 +687,6 @@
 AC_CHECK_LIB(rt, clock_gettime)
 AC_CHECK_LIB(socket, setsockopt)
 
-if test "$have_cpp" = "yes" ; then
-# mingw toolchain used to build "Thrift Compiler for Windows"
-# does not support libcrypto, so we just check if we building the cpp library
-AC_CHECK_LIB(crypto,
-    BN_init,
-    [AC_CHECK_LIB(ssl,
-        SSL_ctrl,
-        [LIBS="-lssl -lcrypto $LIBS"],
-        [AC_MSG_ERROR(["Error: libssl required"])],
-        -lcrypto
-    )],
-    [AC_MSG_ERROR(["Error: libcrypto required."])]
-)
-fi
-
 AC_TYPE_INT16_T
 AC_TYPE_INT32_T
 AC_TYPE_INT64_T
@@ -438,7 +699,7 @@
 AC_TYPE_UINT32_T
 AC_TYPE_UINT64_T
 AC_TYPE_UINT8_T
-AC_CHECK_TYPES([ptrdiff_t], [], [exit 1])
+AC_CHECK_TYPES([ptrdiff_t], [], [echo "ptrdiff_t not found or g++ not installed - cannot continue" && exit 1])
 
 AC_STRUCT_TM
 
@@ -466,12 +727,14 @@
 AC_CHECK_FUNCS([bzero])
 AC_CHECK_FUNCS([ftruncate])
 AC_CHECK_FUNCS([gethostbyname])
+AC_CHECK_FUNCS([gethostbyname_r])
 AC_CHECK_FUNCS([gettimeofday])
 AC_CHECK_FUNCS([memmove])
 AC_CHECK_FUNCS([memset])
 AC_CHECK_FUNCS([mkdir])
 AC_CHECK_FUNCS([realpath])
 AC_CHECK_FUNCS([select])
+AC_CHECK_FUNCS([setlocale])
 AC_CHECK_FUNCS([socket])
 AC_CHECK_FUNCS([strchr])
 AC_CHECK_FUNCS([strdup])
@@ -484,6 +747,8 @@
 AC_CHECK_FUNCS([clock_gettime])
 AC_CHECK_FUNCS([sched_get_priority_min])
 AC_CHECK_FUNCS([sched_get_priority_max])
+AC_CHECK_FUNCS([inet_ntoa])
+AC_CHECK_FUNCS([pow])
 
 if test "$cross_compiling" = "no" ; then
   AX_SIGNED_RIGHT_SHIFT
@@ -520,30 +785,13 @@
 AC_SUBST(GCOV_CXXFLAGS)
 AC_SUBST(GCOV_LDFLAGS)
 
-AC_ARG_ENABLE(boostthreads,
-              [  --enable-boostthreads      use boost threads, instead of POSIX pthread (experimental) ],
-              [case "${enableval}" in
-                yes) ENABLE_BOOSTTHREADS=1 ;;
-                no) ENABLE_BOOSTTHREADS=0 ;;
-                *) AC_MSG_ERROR(bad value ${enableval} for --enable-cov) ;;
-              esac],
-              [ENABLE_BOOSTTHREADS=2])
-
-
-if test "x[$]ENABLE_BOOSTTHREADS" = "x1"; then
-  AC_MSG_WARN(enable boostthreads)
-  AC_DEFINE([USE_BOOST_THREAD], [1], [experimental --enable-boostthreads that replaces POSIX pthread by boost::thread])
-  LIBS="-lboost_thread $LIBS"
-fi
-
-AM_CONDITIONAL([WITH_BOOSTTHREADS], [test "x[$]ENABLE_BOOSTTHREADS" = "x1"])
-
 AC_CONFIG_HEADERS(config.h:config.hin)
 AC_CONFIG_HEADERS(lib/cpp/src/thrift/config.h:config.hin)
+AC_CONFIG_HEADERS(lib/c_glib/src/thrift/config.h:config.hin)
 # gruard against pre defined config.h
 AH_TOP([
 #ifndef CONFIG_H
-#define CONFIG_H 
+#define CONFIG_H
 ])
 AH_BOTTOM([
 #endif
@@ -553,122 +801,213 @@
 AC_CONFIG_FILES([
   Makefile
   compiler/cpp/Makefile
-  compiler/cpp/version.h
-  compiler/cpp/src/windows/version.h
+  compiler/cpp/src/Makefile
+  compiler/cpp/src/thrift/plugin/Makefile
+  compiler/cpp/test/Makefile
+  compiler/cpp/src/thrift/version.h
   lib/Makefile
+  lib/cl/Makefile
   lib/cpp/Makefile
   lib/cpp/test/Makefile
   lib/cpp/thrift-nb.pc
   lib/cpp/thrift-z.pc
   lib/cpp/thrift-qt.pc
+  lib/cpp/thrift-qt5.pc
   lib/cpp/thrift.pc
   lib/c_glib/Makefile
   lib/c_glib/thrift_c_glib.pc
   lib/c_glib/test/Makefile
   lib/csharp/Makefile
+  lib/csharp/test/Multiplex/Makefile
   lib/d/Makefile
   lib/d/test/Makefile
   lib/erl/Makefile
   lib/go/Makefile
   lib/go/test/Makefile
+  lib/haxe/test/Makefile
   lib/hs/Makefile
   lib/java/Makefile
+  lib/js/Makefile
   lib/js/test/Makefile
+  lib/json/Makefile
+  lib/json/test/Makefile
+  lib/netcore/Makefile
+  lib/nodejs/Makefile
+  lib/nodets/Makefile
   lib/perl/Makefile
   lib/perl/test/Makefile
   lib/php/Makefile
   lib/php/test/Makefile
+  lib/dart/Makefile
   lib/py/Makefile
   lib/rb/Makefile
+  lib/rs/Makefile
+  lib/rs/test/Makefile
+  lib/lua/Makefile
+  lib/swift/Makefile
+  lib/xml/Makefile
+  lib/xml/test/Makefile
   test/Makefile
+  test/features/Makefile
+  test/c_glib/Makefile
+  test/cl/Makefile
   test/cpp/Makefile
+  test/csharp/Makefile
+  test/erl/Makefile
+  test/go/Makefile
+  test/haxe/Makefile
   test/hs/Makefile
-  test/nodejs/Makefile
+  test/lua/Makefile
+  test/netcore/Makefile
   test/php/Makefile
+  test/dart/Makefile
   test/perl/Makefile
   test/py/Makefile
   test/py.twisted/Makefile
   test/py.tornado/Makefile
   test/rb/Makefile
+  test/rs/Makefile
   tutorial/Makefile
+  tutorial/c_glib/Makefile
+  tutorial/cl/Makefile
   tutorial/cpp/Makefile
+  tutorial/d/Makefile
   tutorial/go/Makefile
+  tutorial/haxe/Makefile
+  tutorial/hs/Makefile
   tutorial/java/Makefile
   tutorial/js/Makefile
+  tutorial/netcore/Makefile
+  tutorial/nodejs/Makefile
+  tutorial/dart/Makefile
   tutorial/py/Makefile
   tutorial/py.twisted/Makefile
   tutorial/py.tornado/Makefile
   tutorial/rb/Makefile
+  tutorial/rs/Makefile
 ])
 
+if test "$have_cpp" = "yes" ; then MAYBE_CPP="cpp" ; else MAYBE_CPP="" ; fi
+AC_SUBST([MAYBE_CPP])
+if test "$have_c_glib" = "yes" ; then MAYBE_C_GLIB="c_glib" ; else MAYBE_C_GLIB="" ; fi
+AC_SUBST([MAYBE_C_GLIB])
+if test "$have_d" = "yes" -a "$have_deimos_event2" = "yes" -a "$have_deimos_openssl" = "yes"; then MAYBE_D="d" ; else MAYBE_D="" ; fi
+AC_SUBST([MAYBE_D])
+if test "$have_java" = "yes" ; then MAYBE_JAVA="java" ; else MAYBE_JAVA="" ; fi
+AC_SUBST([MAYBE_JAVA])
+if test "$have_csharp" = "yes" ; then MAYBE_CSHARP="csharp" ; else MAYBE_CSHARP="" ; fi
+AC_SUBST([MAYBE_CSHARP])
+if test "$have_python" = "yes" ; then MAYBE_PYTHON="py" ; else MAYBE_PYTHON="" ; fi
+AC_SUBST([MAYBE_PYTHON])
+if test "$have_py3" = "yes" ; then MAYBE_PY3="py3" ; else MAYBE_PY3="" ; fi
+AC_SUBST([MAYBE_PY3])
+if test "$have_ruby" = "yes" ; then MAYBE_RUBY="rb" ; else MAYBE_RUBY="" ; fi
+AC_SUBST([MAYBE_RUBY])
+if test "$have_haskell" = "yes" ; then MAYBE_HASKELL="hs" ; else MAYBE_HASKELL="" ; fi
+AC_SUBST([MAYBE_HASKELL])
+if test "$have_perl" = "yes" ; then MAYBE_PERL="perl" ; else MAYBE_PERL="" ; fi
+AC_SUBST([MAYBE_PERL])
+if test "$have_php" = "yes" ; then MAYBE_PHP="php" ; else MAYBE_PHP="" ; fi
+AC_SUBST([MAYBE_PHP])
+if test "$have_dart" = "yes" ; then MAYBE_DART="dart" ; else MAYBE_DART="" ; fi
+AC_SUBST([MAYBE_DART])
+if test "$have_go" = "yes" ; then MAYBE_GO="go" ; else MAYBE_GO="" ; fi
+AC_SUBST([MAYBE_GO])
+if test "$have_nodejs" = "yes" ; then MAYBE_NODEJS="nodejs" ; else MAYBE_NODEJS="" ; fi
+AC_SUBST([MAYBE_NODEJS])
+if test "$have_nodets" = "yes" ; then MAYBE_NODETS="nodets" ; else MAYBE_NODETS="" ; fi
+AC_SUBST([MAYBE_NODETS])
+if test "$have_erlang" = "yes" ; then MAYBE_ERLANG="erl" ; else MAYBE_ERLANG="" ; fi
+AC_SUBST([MAYBE_ERLANG])
+if test "$have_lua" = "yes" ; then MAYBE_LUA="lua" ; else MAYBE_LUA="" ; fi
+AC_SUBST([MAYBE_LUA])
+if test "$have_rs" = "yes" ; then MAYBE_RS="rs" ; else MAYBE_RS="" ; fi
+AC_SUBST([MAYBE_RS])
+if test "$have_swift" = "yes" ; then MAYBE_SWIFT="swift" ; else MAYBE_SWIFT="" ; fi
+AC_SUBST([MAYBE_SWIFT])
+if test "$have_dotnetcore" = "yes" ; then MAYBE_DOTNETCORE="netcore" ; else MAYBE_DOTNETCORE="" ; fi
+AC_SUBST([MAYBE_DOTNETCORE])
+if test "$have_cl" = "yes" ; then MAYBE_CL="cl" ; else MAYBE_CL="" ; fi
+AC_SUBST([MAYBE_CL])
+
 AC_OUTPUT
 
 
 echo
 echo "$PACKAGE $VERSION"
 echo
-echo "Building C++ Library ......... : $have_cpp"
 echo "Building C (GLib) Library .... : $have_c_glib"
-echo "Building Java Library ........ : $have_java"
-echo "Building C# Library .......... : $have_csharp"
-echo "Building Python Library ...... : $have_python"
-echo "Building Ruby Library ........ : $have_ruby"
-echo "Building Haskell Library ..... : $have_haskell"
-echo "Building Perl Library ........ : $have_perl"
-echo "Building PHP Library ......... : $have_php"
+echo "Building C# (Mono) Library ... : $have_csharp"
+echo "Building C++ Library ......... : $have_cpp"
+echo "Building Common Lisp Library.. : $have_cl"
+echo "Building D Library ........... : $have_d"
+echo "Building Dart Library ........ : $have_dart"
+echo "Building dotnetcore Library .. : $have_dotnetcore"
 echo "Building Erlang Library ...... : $have_erlang"
 echo "Building Go Library .......... : $have_go"
-echo "Building D Library ........... : $have_d"
+echo "Building Haskell Library ..... : $have_haskell"
+echo "Building Haxe Library ........ : $have_haxe"
+echo "Building Java Library ........ : $have_java"
+echo "Building Lua Library ......... : $have_lua"
+echo "Building NodeJS Library ...... : $have_nodejs"
+echo "Building Perl Library ........ : $have_perl"
+echo "Building PHP Library ......... : $have_php"
+echo "Building Plugin Support ...... : $have_plugin"
+echo "Building Python Library ...... : $have_python"
+echo "Building Py3 Library ......... : $have_py3"
+echo "Building Ruby Library ........ : $have_ruby"
+echo "Building Rust Library ........ : $have_rs"
+echo "Building Swift Library ....... : $have_swift"
 
-if test "$have_cpp" = "yes" ; then
-  echo
-  echo "C++ Library:"
-  echo "   Build TZlibTransport ...... : $have_zlib"
-  echo "   Build TNonblockingServer .. : $have_libevent"
-  echo "   Build TQTcpServer (Qt) .... : $have_qt"
-fi
-if test "$have_java" = "yes" ; then
-  echo
-  echo "Java Library:"
-  echo "   Using javac ............... : $JAVAC"
-  echo "   Using java ................ : $JAVA"
-  echo "   Using ant ................. : $ANT"
-fi
 if test "$have_csharp" = "yes" ; then
   echo
   echo "C# Library:"
   echo "   Using .NET 3.5 ............ : $net_3_5"
+  echo "   Using mono version ........ : $($MCS --version | head -1)"
 fi
-if test "$have_python" = "yes" ; then
+if test "$have_cpp" = "yes" ; then
   echo
-  echo "Python Library:"
-  echo "   Using Python .............. : $PYTHON"
+  echo "C++ Library:"
+  echo "   C++ compiler .............. : $CXX"
+  echo "   Build TZlibTransport ...... : $have_zlib"
+  echo "   Build TNonblockingServer .. : $have_libevent"
+  echo "   Build TQTcpServer (Qt4) ... : $have_qt"
+  echo "   Build TQTcpServer (Qt5) ... : $have_qt5"
+  echo "   C++ compiler version ...... : $($CXX --version | head -1)"
 fi
-if test "$have_php" = "yes" ; then
+if test "$have_cl" = "yes" ; then
   echo
-  echo "PHP Library:"
-  echo "   Using php-config .......... : $PHP_CONFIG"
+  echo "Common Lisp Library:"
+  echo "   Using Common Lisp ......... : $SBCL"
+  echo "   Using Common Lisp version . : $($SBCL --version)"
 fi
-if test "$have_ruby" = "yes" ; then
+if test "$have_d" = "yes" ; then
   echo
-  echo "Ruby Library:"
-  echo "   Using Ruby ................ : $RUBY"
+  echo "D Library:"
+  echo "   Using D Compiler .......... : $DMD"
+  echo "   Building D libevent tests . : $with_d_event_tests"
+  echo "   Building D SSL tests ...... : $with_d_ssl_tests"
+  echo "   Using D version ........... : $($DMD --version | head -1)"
 fi
-if test "$have_haskell" = "yes" ; then
+if test "$have_dart" = "yes" ; then
   echo
-  echo "Haskell Library:"
-  echo "   Using Haskell ............. : $RUNHASKELL"
-  echo "   Using Cabal ............... : $CABAL"
+  echo "Dart Library:"
+  echo "   Using Dart ................ : $DART"
+  echo "   Using Pub ................. : $DARTPUB"
+  echo "   Using Dart version ........ : $($DART --version 2>&1)"
 fi
-if test "$have_perl" = "yes" ; then
+if test "$have_dotnetcore" = "yes" ; then
   echo
-  echo "Perl Library:"
-  echo "   Using Perl ................ : $PERL"
+  echo ".NET Core Library:"
+  echo "   Using .NET Core ........... : $DOTNETCORE"
+  echo "   Using .NET Core version ... : $DOTNETCORE_VERSION"
 fi
 if test "$have_erlang" = "yes" ; then
   echo
   echo "Erlang Library:"
   echo "   Using erlc ................ : $ERLC"
+  echo "   Using rebar ............... : $REBAR"
+  echo "   Using erlc version ........ : $($ERL -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell | tr -d '\"')"
 fi
 if test "$have_go" = "yes" ; then
   echo
@@ -676,13 +1015,86 @@
   echo "   Using Go................... : $GO"
   echo "   Using Go version........... : $($GO version)"
 fi
-if test "$have_d" = "yes" ; then
+if test "$have_haskell" = "yes" ; then
   echo
-  echo "Using D Compiler ............. : $DMD"
-  echo "Building D libevent tests .... : $with_d_event_tests"
-  echo "Building D SSL tests ......... : $with_d_ssl_tests"
+  echo "Haskell Library:"
+  echo "   Using Cabal ............... : $CABAL"
+  echo "   Using Haskell ............. : $RUNHASKELL"
+  echo "   Using Haskell version ..... : $($RUNHASKELL --version)"
+fi
+if test "$have_haxe" = "yes" ; then
+  echo
+  echo "Haxe Library:"
+  echo "   Using Haxe ................ : $HAXE"
+  echo "   Using Haxe version ........ : $HAXE_VERSION"
+fi
+if test "$have_java" = "yes" ; then
+  echo
+  echo "Java Library:"
+  echo "   Using gradlew ............. : lib/java/gradlew"
+  echo "   Using java ................ : $JAVA"
+  echo "   Using javac ............... : $JAVAC"
+  echo "   Using Gradle version ...... : $(lib/java/gradlew --version --quiet | grep Gradle 2>&1)"
+  echo "   Using java version ........ : $($JAVA -version 2>&1 | grep 'version ')"
+fi
+if test "$have_lua" = "yes" ; then
+  echo
+  echo "Lua Library:"
+  echo "   Using Lua ................. : $LUA"
+  echo "   Using Lua version.......... : $($LUA -v)"
+fi
+if test "$have_nodejs" = "yes" ; then
+  echo
+  echo "NodeJS Library:"
+  echo "   Using NodeJS .............. : $NODEJS"
+  echo "   Using NodeJS version....... : $($NODEJS --version)"
+fi
+if test "$have_perl" = "yes" ; then
+  echo
+  echo "Perl Library:"
+  echo "   Using Perl ................ : $PERL"
+  echo "   Using Perl version ........ : $($PERL -v | grep 'version ')"
+fi
+if test "$have_php" = "yes" ; then
+  echo
+  echo "PHP Library:"
+  echo "   Using php-config .......... : $PHP_CONFIG"
+  echo "   Using php version ......... : $($PHP --version | head -1)"
+fi
+if test "$have_python" = "yes" ; then
+  echo
+  echo "Python Library:"
+  echo "   Using Python .............. : $PYTHON"
+  echo "   Using Python version ...... : $($PYTHON --version 2>&1)"
+  if test "$have_py3" = "yes" ; then
+  echo "   Using Python3 ............. : $PYTHON3"
+  echo "   Using Python3 version ..... : $($PYTHON3 --version)"
+  fi
+  if test "$have_trial" = "yes"; then
+  echo "   Using trial ............... : $TRIAL"
+  fi
+fi
+if test "$have_ruby" = "yes" ; then
+  echo
+  echo "Ruby Library:"
+  echo "   Using Ruby ................ : $RUBY"
+  echo "   Using Ruby version ........ : $($RUBY --version)"
+fi
+if test "$have_rs" = "yes" ; then
+  echo
+  echo "Rust Library:"
+  echo "   Using Cargo................ : $CARGO"
+  echo "   Using rustc................ : $RUSTC"
+  echo "   Using Rust version......... : $($RUSTC --version)"
+fi
+if test "$have_swift" = "yes" ; then
+  echo
+  echo "Swift Library:"
+  echo "   Using Swift ............... : $SWIFT"
+  echo "   Using Swift version ....... : $($SWIFT --version | head -1)"
 fi
 echo
 echo "If something is missing that you think should be present,"
 echo "please skim the output of configure to find the missing"
 echo "component.  Details are present in config.log."
+echo
diff --git a/contrib/Rebus/App.config b/contrib/Rebus/App.config
new file mode 100644
index 0000000..4208af6
--- /dev/null
+++ b/contrib/Rebus/App.config
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<configuration>
+  
+  <configSections>
+    <section name="rebus" type="Rebus.Configuration.RebusConfigurationSection, Rebus"/>
+  </configSections>
+
+  <rebus inputQueue="MyResponses" errorQueue="MyErrors" workers="1">
+    <endpoints>
+      <add messages="RebusSample.MathRequestCall, RebusSample" endpoint="MathRequests"/>
+      <add messages="RebusSample.MathResponseCall, RebusSample" endpoint="MathResponses"/>
+    </endpoints>
+  </rebus>
+
+  <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
diff --git a/contrib/Rebus/Program.cs b/contrib/Rebus/Program.cs
new file mode 100644
index 0000000..563c62a
--- /dev/null
+++ b/contrib/Rebus/Program.cs
@@ -0,0 +1,81 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using Rebus.Configuration;
+using Rebus.RabbitMQ;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using RebusSample.Client;
+using RebusSample.Server;
+
+namespace RebusSample
+{
+    class Program
+    {
+        static BuiltinContainerAdapter StartRequestServer(string server)
+        {
+            // client Rebus configuration
+            var adapter = new BuiltinContainerAdapter();
+            Configure.With(adapter)
+                .Transport(t => t.UseRabbitMq("amqp://" + server, "MathRequests", "MathRequestErrors"))
+                .MessageOwnership(o => o.FromRebusConfigurationSection())
+                .CreateBus().Start();
+
+            // register all relevant message handlers 
+            adapter.Register(typeof(MathRequestCallHandler));
+            return adapter;
+        }
+
+
+        static BuiltinContainerAdapter StartResponseServer(string server)
+        {
+            // client Rebus configuration
+            var adapter = new BuiltinContainerAdapter();
+            Configure.With(adapter)
+                .Transport(t => t.UseRabbitMq("amqp://" + server, "MathResponses", "MathResponseErrors"))
+                .MessageOwnership(o => o.FromRebusConfigurationSection())
+                .CreateBus().Start();
+
+            // register all relevant message handlers 
+            adapter.Register(typeof(MathResponseCallHandler));
+            return adapter;
+        }
+
+        static void Main(string[] args)
+        {
+            string server = "localhost";
+
+            // start all servers
+            var req = StartRequestServer(server);
+            var rsp = StartResponseServer(server);
+
+            // send the first message
+            var random = new Random();
+            var client = new MathRequestClient(server);
+            client.DoTheMath(random.Next(), random.Next());
+
+            // now what?
+            Console.Write("Hit <ENTER> to stop ... ");
+            Console.ReadLine();
+        }
+    }
+}
diff --git a/contrib/Rebus/Properties/AssemblyInfo.cs b/contrib/Rebus/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..e476eab
--- /dev/null
+++ b/contrib/Rebus/Properties/AssemblyInfo.cs
@@ -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.
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("RebusSample")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("RebusSample")]
+[assembly: AssemblyCopyright("Copyright ©  2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("0af10984-40d3-453d-b1e5-421529e8c7e2")]
+
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/contrib/Rebus/README.md b/contrib/Rebus/README.md
new file mode 100644
index 0000000..bbb9c49
--- /dev/null
+++ b/contrib/Rebus/README.md
@@ -0,0 +1,21 @@
+Sample code for the combination of Thrift with Rebus.
+
+Rebus is a .NET service bus, similar to NServiceBus, but more lightweight. 
+It ihas been mainly written by Mogens Heller Grabe and is currently hosted 
+on GitHub (https://github.com/rebus-org/Rebus)
+
+As with all ServiceBus or MQ scenarios, due to the highly asynchronous 
+operations it is recommended to do all calls as "oneway void" calls.
+
+The configuration can be done via App.Config, via code or even mixed from 
+both locations. Refer to the Rebus documentation for further details. For 
+this example, since we are effectively implementing two queue listeners in 
+only one single process, we do configuration of incoming and error queues 
+in the code.
+
+If you want to communicate with non-NET languages, you may need a customized 
+serializer as well, in order to override Rebus' default wire format. Please 
+refer to the Rebus docs on how to do that (it's not that hard, really).
+
+Additional requirements:
+- RabbitMQ .NET client (see nuget)
diff --git a/contrib/Rebus/RebusSample.csproj b/contrib/Rebus/RebusSample.csproj
new file mode 100644
index 0000000..4058a6d
--- /dev/null
+++ b/contrib/Rebus/RebusSample.csproj
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{264E2126-EDE0-4B47-89C1-B397B25BB13D}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>RebusSample</RootNamespace>
+    <AssemblyName>RebusSample</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="RabbitMQ.Client">
+      <HintPath>..\..\..\..\..\Toolbox\ServiceBus\3rdparty\rabbitmq-dotnet-client-3.2.1-dotnet-3.0\bin\RabbitMQ.Client.dll</HintPath>
+    </Reference>
+    <Reference Include="Rebus">
+      <HintPath>..\..\..\..\..\Toolbox\ServiceBus\3rdparty\Rebus-master\deploy\NET40\Rebus.dll</HintPath>
+    </Reference>
+    <Reference Include="Rebus.RabbitMQ">
+      <HintPath>..\..\..\..\..\Toolbox\ServiceBus\3rdparty\Rebus-master\deploy\NET40\Rebus.RabbitMQ.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="gen-csharp\BasicMathClient.cs" />
+    <Compile Include="gen-csharp\BasicMathServer.cs" />
+    <Compile Include="ServiceImpl\Both.cs" />
+    <Compile Include="ServiceImpl\Client.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="ServiceImpl\Server.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+  </ItemGroup>
+  <ItemGroup />
+  <ItemGroup>
+    <ProjectReference Include="..\..\lib\csharp\src\Thrift.csproj">
+      <Project>{499eb63c-d74c-47e8-ae48-a2fc94538e9d}</Project>
+      <Name>Thrift</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent>cd $(ProjectDir)
+if not exist gen-csharp\*.cs   thrift  -gen csharp sample.thrift
+</PreBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/contrib/Rebus/RebusSample.sln b/contrib/Rebus/RebusSample.sln
new file mode 100644
index 0000000..284ef36
--- /dev/null
+++ b/contrib/Rebus/RebusSample.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30110.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RebusSample", "RebusSample.csproj", "{264E2126-EDE0-4B47-89C1-B397B25BB13D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\lib\csharp\src\Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{264E2126-EDE0-4B47-89C1-B397B25BB13D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{264E2126-EDE0-4B47-89C1-B397B25BB13D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{264E2126-EDE0-4B47-89C1-B397B25BB13D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{264E2126-EDE0-4B47-89C1-B397B25BB13D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/contrib/Rebus/ServiceImpl/Both.cs b/contrib/Rebus/ServiceImpl/Both.cs
new file mode 100644
index 0000000..fba67ec
--- /dev/null
+++ b/contrib/Rebus/ServiceImpl/Both.cs
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+
+using System;
+
+
+namespace RebusSample
+{
+    // generic data container for serialized Thrift calls
+    public class GenericThriftServiceCall
+    {
+        public byte[] rawBytes;
+    }
+
+    // specific containers (one per Thrift service) to leverage Rebus' handler routing
+    public class MathRequestCall : GenericThriftServiceCall { }
+    public class MathResponseCall : GenericThriftServiceCall { }
+
+}
\ No newline at end of file
diff --git a/contrib/Rebus/ServiceImpl/Client.cs b/contrib/Rebus/ServiceImpl/Client.cs
new file mode 100644
index 0000000..2408041
--- /dev/null
+++ b/contrib/Rebus/ServiceImpl/Client.cs
@@ -0,0 +1,157 @@
+/**
+ * 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.
+ */
+
+using Rebus;
+using Rebus.Configuration;
+using Rebus.Messages;
+using Rebus.RabbitMQ;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Thrift.Protocol;
+using Thrift.Transport;
+
+/*
+ * The client emits calls to BasicMathServers
+ * 
+ * The client implements the BasicMathClient service. 
+ * If the server has processed our request, we get the results back through this service
+ */
+
+namespace RebusSample.Client
+{
+
+    // handler to be registered with Rebus
+    class MathResponseCallHandler : IHandleMessages<MathResponseCall>
+    {
+        public void Handle(MathResponseCall message)
+        {
+            // Thrift protocol/transport stack
+            var stm = new MemoryStream(message.rawBytes);
+            var trns = new TStreamTransport(stm, null);
+            var prot = new TBinaryProtocol(trns);
+
+            // create a processor and let him handle the call
+            var hndl = new MathResponsesHandler();
+            var proc = new BasicMathClient.Processor(hndl);
+            proc.Process(prot, null);  // oneway only
+        }      
+    }
+
+
+    // serves incoming responses with calculation results
+    internal class MathResponsesHandler : BasicMathClient.Iface
+    {
+        public void FourResults(int added, int multiplied, int subtracted, int divided)
+        {
+            Console.WriteLine("added = {0}", added);
+            Console.WriteLine("multiplied= {0}", multiplied);
+            Console.WriteLine("subtracted = {0}", subtracted);
+            Console.WriteLine("divided = {0}", divided);
+
+            PingAndDoAnotherCalculation();
+        }
+
+
+        public void ThreeResults(int added, int multiplied, int subtracted)
+        {
+            Console.WriteLine("added = {0}", added);
+            Console.WriteLine("multiplied= {0}", multiplied);
+            Console.WriteLine("subtracted = {0}", subtracted);
+            Console.WriteLine("DIV/0 error during division");
+
+            PingAndDoAnotherCalculation();
+        }
+
+
+        public void Pong(long value)
+        {
+            var latency = DateTime.Now.Ticks - value;
+            Console.WriteLine("Ping took {0} ms", new DateTime(latency).Millisecond);
+        }
+
+
+        private void PingAndDoAnotherCalculation()
+        {
+            var random = new Random();
+            var client = new MathRequestClient("localhost");
+            client.Ping(DateTime.Now.Ticks);
+            client.DoTheMath(random.Next(), random.Next());
+        }
+    }
+
+
+    // provides the client-side interface for calculation requests
+    internal class MathRequestClient : BasicMathServer.Iface
+    {
+        private BuiltinContainerAdapter MQAdapter;
+
+
+        public MathRequestClient(string server)
+        {
+            MQAdapter = new BuiltinContainerAdapter();
+            Configure.With(MQAdapter)
+                .Transport(t => t.UseRabbitMqInOneWayMode("amqp://" + server))  // we need send only
+                .MessageOwnership(o => o.FromRebusConfigurationSection())
+                .CreateBus().Start();
+        }
+
+
+        public void SerializeThriftCall(Action<BasicMathServer.Iface> action)
+        {
+            // Thrift protocol/transport stack
+            var stm = new MemoryStream();
+            var trns = new TStreamTransport(null, stm);
+            var prot = new TBinaryProtocol(trns);
+            
+            // serialize the call into a bunch of bytes
+            var client = new BasicMathServer.Client(prot);
+            if( action != null)
+                action(client);
+            else
+                throw new ArgumentException("action must not be null");
+
+            // make sure everything is written to the MemoryStream
+            trns.Flush();
+
+            // send the message
+            var msg = new MathRequestCall() { rawBytes = stm.ToArray() };
+            MQAdapter.Bus.Send(msg);
+        }
+
+
+        public void Ping(long value)
+        {
+            SerializeThriftCall(client =>
+            {
+                client.Ping(value);
+            });
+        }
+
+
+        public void DoTheMath( int arg1, int arg2)
+        {
+            SerializeThriftCall(client =>
+            {
+                client.DoTheMath(arg1, arg2);
+            });
+        }
+    }
+}
+
diff --git a/contrib/Rebus/ServiceImpl/Server.cs b/contrib/Rebus/ServiceImpl/Server.cs
new file mode 100644
index 0000000..149d513
--- /dev/null
+++ b/contrib/Rebus/ServiceImpl/Server.cs
@@ -0,0 +1,143 @@
+/**
+ * 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.
+ */
+
+using Rebus;
+using Rebus.Configuration;
+using Rebus.Messages;
+using Rebus.RabbitMQ;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Thrift.Protocol;
+using Thrift.Transport;
+
+/*
+ * The server implements the BasicMathServer service .
+ * All results are sent back to the client via the BasicMathClient service
+ */
+
+
+namespace RebusSample.Server
+{
+    // handler to be registered with Rebus
+    class MathRequestCallHandler : IHandleMessages<MathRequestCall>
+    {
+        public void Handle(MathRequestCall message)
+        {
+            // Thrift protocol/transport stack
+            var stm = new MemoryStream(message.rawBytes);
+            var trns = new TStreamTransport(stm, null);
+            var prot = new TBinaryProtocol(trns);
+
+            // create a processor and let him handle the call
+            var hndl = new MathRequestsHandler();
+            var proc = new BasicMathServer.Processor(hndl);
+            proc.Process(prot, null);  // oneway only
+        }
+    }
+
+
+    // serves incoming calculation requests
+    internal class MathRequestsHandler : BasicMathServer.Iface
+    {
+        public void Ping(long value)
+        {
+            var client = new MathResponseClient("localhost");
+            client.Pong(value);
+        }
+
+
+        public void DoTheMath(int arg1, int arg2)
+        {
+            var client = new MathResponseClient("localhost");
+            if( arg2 != 0)
+                client.FourResults( arg1+arg2, arg1*arg2, arg1-arg2, arg1/arg2);
+            else
+                client.ThreeResults( arg1+arg2, arg1*arg2, arg1-arg2);
+        }
+    }
+
+
+    // provides the client-side interface for calculation responses
+    internal class MathResponseClient : BasicMathClient.Iface
+    {
+        private BuiltinContainerAdapter MQAdapter;
+
+
+        public MathResponseClient(string server)
+        {
+            MQAdapter = new BuiltinContainerAdapter();
+            Configure.With(MQAdapter)
+                .Transport(t => t.UseRabbitMqInOneWayMode("amqp://" + server))  // we need send only
+                .MessageOwnership(o => o.FromRebusConfigurationSection())
+                .CreateBus().Start();
+        }
+
+
+        public void SerializeThriftCall(Action<BasicMathClient.Iface> action)
+        {
+            // Thrift protocol/transport stack
+            var stm = new MemoryStream();
+            var trns = new TStreamTransport(null, stm);
+            var prot = new TBinaryProtocol(trns);
+
+            // serialize the call into a bunch of bytes
+            var client = new BasicMathClient.Client(prot);
+            if (action != null)
+                action(client);
+            else
+                throw new ArgumentException("action must not be null");
+
+            // make sure everything is written to the MemoryStream
+            trns.Flush();
+
+            // send the message
+            var msg = new MathResponseCall() { rawBytes = stm.ToArray() };
+            MQAdapter.Bus.Send(msg);
+        }
+
+
+        public void Pong(long value)
+        {
+            SerializeThriftCall(client =>
+            {
+                client.Pong(value);
+            });
+        }
+
+
+        public void ThreeResults(int added, int multiplied, int suctracted)
+        {
+            SerializeThriftCall(client =>
+            {
+                client.ThreeResults(added, multiplied, suctracted);
+            });
+        }
+
+
+        public void FourResults(int added, int multiplied, int suctracted, int divided)
+        {
+            SerializeThriftCall(client =>
+            {
+                client.FourResults(added, multiplied, suctracted, divided);
+            });
+        }
+    }
+}
+
diff --git a/contrib/Rebus/sample.thrift b/contrib/Rebus/sample.thrift
new file mode 100644
index 0000000..785e2d3
--- /dev/null
+++ b/contrib/Rebus/sample.thrift
@@ -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.
+ */
+
+
+service BasicMathServer {
+    oneway void DoTheMath( 1: i32 arg1,  2: i32 arg2)
+    oneway void Ping(1: i64 value)
+}
+
+service BasicMathClient {
+    oneway void ThreeResults( 1 : i32 added, 2 : i32 multiplied, 3 : i32 subtracted);
+    oneway void FourResults(  1 : i32 added, 2 : i32 multiplied, 3 : i32 subtracted, 4 : i32 divided);
+    oneway void Pong(1: i64 value)
+}
diff --git a/contrib/Stomp/README.md b/contrib/Stomp/README.md
new file mode 100644
index 0000000..2e5f21c
--- /dev/null
+++ b/contrib/Stomp/README.md
@@ -0,0 +1,18 @@
+Sample code for STOMP-based Thrift clients and/or servers.
+
+Although the sample Thrift STOMP Transport is written in 
+Delphi/Pascal, it can easily serve as a starting point for 
+similar implementations in other languages.
+
+STOMP is a protocol widely supported by many messaging systems,
+such as Apache ActiveMQ, RabbitMQ and many others. In particular,
+it can be used to communicate with Service-Bus products like Rebus
+or NServiceBus, when running against a STOMP-capable MQ system.
+
+A prerequisite for this sample is the Delphi STOMP Adapter written
+by Daniele Teti (http://www.danieleteti.it/stomp-client), currently
+hosted at Google Code (http://code.google.com/p/delphistompclient).
+
+At the time of writing, the STOMP adapter does not fully support 
+binary data. Please check whether this has been fixed, otherwise 
+you have to use the JSON protocol (or to fix it on your own).
diff --git a/contrib/Stomp/Thrift.Transport.STOMP.pas b/contrib/Stomp/Thrift.Transport.STOMP.pas
new file mode 100644
index 0000000..7dfb376
--- /dev/null
+++ b/contrib/Stomp/Thrift.Transport.STOMP.pas
@@ -0,0 +1,200 @@
+(*
+ * 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.
+ *)
+
+unit Thrift.Transport.STOMP;
+
+interface
+
+uses
+  Classes,Windows, SysUtils,
+  Thrift,
+  Thrift.Transport,
+  Thrift.Protocol,
+  Thrift.Stream,
+  StompClient,
+  StompTypes;
+
+type
+  TStompTransportImpl = class( TStreamTransportImpl)
+  strict private
+    FData     : TStringStream;
+    FServer   : string;
+    FOutQueue : string;
+    FStompCli : IStompClient;
+  protected
+    function GetIsOpen: Boolean; override;
+    function Peek: Boolean; override;
+  public
+    constructor Create( const aServerAndPort, aOutQueue : string);
+    destructor Destroy;  override;
+
+    procedure Open();  override;
+    procedure Close();  override;
+    procedure Flush;  override;
+  end;
+
+
+  TStompServerTransportImpl = class( TServerTransportImpl)
+  strict private
+    FServer  : string;
+    FInQueue : string;
+    FClient  : IStompClient;
+  protected
+    procedure Listen; override;
+    procedure Close; override;
+    function Accept( const fnAccepting: TProc): ITransport; override;
+  public
+    constructor Create( const aServerAndPort, aInQueue : string);
+    destructor Destroy;  override;
+  end;
+
+
+const
+  QUEUE_PREFIX    = '/queue/';
+  TOPIC_PREFIX    = '/topic/';
+  EXCHANGE_PREFIX = '/exchange/';
+
+
+implementation
+
+
+
+constructor TStompTransportImpl.Create( const aServerAndPort, aOutQueue : string);
+var adapter : IThriftStream;
+begin
+  FData     := TStringStream.Create;
+  FServer   := aServerAndPort;
+  FOutQueue := aOutQueue;
+
+  adapter := TThriftStreamAdapterDelphi.Create( FData, FALSE);
+  inherited Create( nil, adapter);  // output only
+end;
+
+
+destructor TStompTransportImpl.Destroy;
+begin
+  inherited Destroy;
+  FreeAndNil( FData);
+  FStompCli := nil;
+end;
+
+
+function TStompTransportImpl.GetIsOpen: Boolean;
+begin
+  result := (FStompCli <> nil);
+end;
+
+
+function TStompTransportImpl.Peek: Boolean;
+begin
+  result := FALSE;  // output only
+end;
+
+
+procedure TStompTransportImpl.Open;
+begin
+  if FStompCli <> nil
+  then raise TTransportException.Create( TTransportException.TExceptionType.AlreadyOpen, 'already open')
+  else FStompCli := StompUtils.NewStomp( FServer);
+end;
+
+
+procedure TStompTransportImpl.Close;
+begin
+  FStompCli := nil;
+  FData.Clear;
+end;
+
+
+procedure TStompTransportImpl.Flush;
+begin
+  if FStompCli = nil
+  then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen, 'not open');
+
+  FStompCli.Send( FOutQueue, FData.DataString);
+  FData.Clear;
+end;
+
+
+//--- TStompServerTransportImpl --------------------------------------------
+
+
+constructor TStompServerTransportImpl.Create( const aServerAndPort, aInQueue : string);
+begin
+  inherited Create;
+  FServer  := aServerAndPort;
+  FInQueue := aInQueue;
+end;
+
+
+destructor TStompServerTransportImpl.Destroy;
+begin
+  try
+    Close;
+  finally
+    inherited Destroy;
+  end;
+end;
+
+
+procedure TStompServerTransportImpl.Listen;
+begin
+  FClient := StompUtils.NewStomp(FServer);
+  FClient.Subscribe( FInQueue);
+end;
+
+
+procedure TStompServerTransportImpl.Close;
+begin
+  if FClient <> nil then begin
+    FClient.Unsubscribe( FInQueue);
+    FClient := nil;
+  end;
+end;
+
+
+function TStompServerTransportImpl.Accept( const fnAccepting: TProc): ITransport;
+var frame   : IStompFrame;
+    adapter : IThriftStream;
+    stream  : TStringStream;
+begin
+  if FClient = nil
+  then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
+                                         'Not connected.');
+
+  if Assigned(fnAccepting)
+  then fnAccepting();
+
+  try
+    frame := FClient.Receive(MAXINT);
+    if frame = nil then Exit(nil);
+
+    stream  := TStringStream.Create( frame.GetBody);
+    adapter := TThriftStreamAdapterDelphi.Create( stream, TRUE);
+    result  := TStreamTransportImpl.Create( adapter, nil);
+
+  except
+    on E: Exception
+    do raise TTransportException.Create( E.ToString );
+  end;
+end;
+
+
+end.
+
diff --git a/contrib/Vagrantfile b/contrib/Vagrantfile
index fd67821..ff53316 100644
--- a/contrib/Vagrantfile
+++ b/contrib/Vagrantfile
@@ -22,54 +22,75 @@
 
 $build_and_test = <<SCRIPT
 echo "Provisioning system to compile and test Apache Thrift."
-sudo apt-get update -qq -y
-sudo apt-get upgrade -qq -y
+
+# Create swap space
+sudo fallocate -l 2G /swapfile
+sudo chmod 600 /swapfile
+sudo mkswap /swapfile
+sudo swapon /swapfile
+sudo swapon -s
+
+# Update the system
+sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq -y
+sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -qq -y
 
 # Install Dependencies
 # ---
 # General dependencies
-sudo apt-get install -qq libboost-dev libboost-test-dev libboost-program-options-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev make libqt4-dev git debhelper
+sudo apt-get install -qq automake libtool flex bison pkg-config g++ libssl-dev make libqt4-dev git debhelper
+
+# C++ dependencies
+sudo apt-get install -qq libboost-dev libboost-test-dev libboost-program-options-dev libboost-filesystem-dev libboost-system-dev libevent-dev 
 
 # Java dependencies
-sudo apt-get install -qq ant openjdk-7-jdk libcommons-lang3-java
+sudo apt-get install -qq ant openjdk-8-jdk maven
 
 # Python dependencies
-sudo apt-get install -qq python-all python-all-dev python-all-dbg python-setuptools
+sudo apt-get install -qq python-all python-all-dev python-all-dbg python-setuptools python-support python-six python3-six
 
 # Ruby dependencies
-sudo apt-get install -qq ruby rubygems
+sudo apt-get install -qq ruby ruby-dev
 sudo gem install bundler rake
 
 # Perl dependencies
-sudo apt-get install -qq libbit-vector-perl
+sudo apt-get install -qq libbit-vector-perl libclass-accessor-class-perl
 
 # Php dependencies
-sudo apt-get install -qq php5 php5-dev php5-cli php-pear
+sudo apt-get install -qq php5 php5-dev php5-cli php-pear re2c
 
 # GlibC dependencies
 sudo apt-get install -qq libglib2.0-dev
 
 # Erlang dependencies
-sudo apt-get install -qq erlang-base erlang-eunit erlang-dev
+sudo apt-get install -qq erlang-base erlang-eunit erlang-dev erlang-tools
 
 # GO dependencies
 echo "golang-go golang-go/dashboard boolean false" | debconf-set-selections
 sudo apt-get -y install -qq golang golang-go
 
 # Haskell dependencies
-sudo apt-get install -qq ghc6 cabal-install libghc6-binary-dev libghc6-network-dev libghc6-http-dev libghc-hashable-dev libghc-unordered-containers-dev libghc-vector-dev
+sudo apt-get install -qq ghc cabal-install libghc-binary-dev libghc-network-dev libghc-http-dev libghc-hashable-dev libghc-unordered-containers-dev libghc-vector-dev
+sudo cabal update
+
+# Lua dependencies
+sudo apt-get install -qq lua5.2 lua5.2-dev
 
 # Node.js dependencies
-sudo apt-get install -qq npm
+sudo apt-get install -qq nodejs nodejs-dev nodejs-legacy npm
 
 # CSharp
-sudo apt-get install -qq mono-gmcs mono-devel libmono-system-web2.0-cil
-sudo apt-get install -qq mingw32 mingw32-binutils mingw32-runtime
+sudo apt-get install -qq mono-gmcs mono-devel mono-xbuild mono-complete libmono-system-web2.0-cil
+sudo apt-get install -qq mingw32 mingw32-binutils mingw32-runtime nsis
+
+# D dependencies
+sudo wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list
+sudo apt-get update && sudo apt-get -y --allow-unauthenticated install --reinstall d-apt-keyring && sudo apt-get update
+sudo apt-get install -qq xdg-utils dmd-bin
 
 # Customize the system
 # ---
-# Default java to latest 1.7 version
-update-java-alternatives -s java-1.7.0-openjdk-amd64 
+# Default java to latest 1.8 version
+update-java-alternatives -s java-1.8.0-openjdk-amd64 
 
 # PHPUnit package broken in ubuntu. see https://bugs.launchpad.net/ubuntu/+source/phpunit/+bug/701544
 sudo apt-get upgrade pear
@@ -87,29 +108,26 @@
 echo "Starting Apache Thrift build..."
 cd /thrift
 sh bootstrap.sh
-sh configure --without-erlang
+sh configure
 make
-make dist
 make check
 echo "Finished building Apache Thrift."
 
 SCRIPT
 
 Vagrant.configure("2") do |config|
-  # Ubuntu 12.04 LTS (Precise Pangolin)
-  config.vm.box = "precise64"
-  config.vm.box_url = "http://cloud-images.ubuntu.com/precise/current/precise-server-cloudimg-vagrant-amd64-disk1.box"
-  # config.vm.box = "precise32"
-  # config.vm.box_url = "http://cloud-images.ubuntu.com/precise/current/precise-server-cloudimg-vagrant-i386-disk1.box"
+  # Ubuntu 14.04 LTS (Trusty Tahr)
+  config.vm.box = "trusty64"
+  config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box"
 
   config.vm.synced_folder "../", "/thrift"
 
   config.vm.provider :virtualbox do |vbox|
     vbox.customize ["modifyvm", :id, "--memory", "1024"]
     vbox.customize ["modifyvm", :id, "--cpus", "2"]
+    vbox.customize ["modifyvm", :id, "--rtcuseutc", "on"]
   end
 
-  # call the script
+  # Run the build script to configure the system
   config.vm.provision :shell, :inline => $build_and_test
-
 end
diff --git a/contrib/async-test/test-leaf.py b/contrib/async-test/test-leaf.py
index 8b7c3e3..4ea4a9b 100755
--- a/contrib/async-test/test-leaf.py
+++ b/contrib/async-test/test-leaf.py
@@ -7,16 +7,17 @@
 from thrift.server import THttpServer
 from aggr import Aggr
 
+
 class AggrHandler(Aggr.Iface):
-  def __init__(self):
-    self.values = []
+    def __init__(self):
+        self.values = []
 
-  def addValue(self, value):
-    self.values.append(value)
+    def addValue(self, value):
+        self.values.append(value)
 
-  def getValues(self, ):
-    time.sleep(1)
-    return self.values
+    def getValues(self, ):
+        time.sleep(1)
+        return self.values
 
 processor = Aggr.Processor(AggrHandler())
 pfactory = TBinaryProtocol.TBinaryProtocolFactory()
diff --git a/contrib/fb303/README b/contrib/fb303/README.md
similarity index 100%
rename from contrib/fb303/README
rename to contrib/fb303/README.md
diff --git a/contrib/fb303/TClientInfo.cpp b/contrib/fb303/TClientInfo.cpp
index 5959fb1..1fc6612 100644
--- a/contrib/fb303/TClientInfo.cpp
+++ b/contrib/fb303/TClientInfo.cpp
@@ -154,9 +154,8 @@
     }
 
     timespec start;
-    double secs = 0.0;
     info->getTime(&start);
-    secs = (double)(now.tv_sec - start.tv_sec) + (now.tv_nsec - start.tv_nsec)*0.000000001;
+    double secs = (double)(now.tv_sec - start.tv_sec) + (now.tv_nsec - start.tv_nsec)*0.000000001;
 
     char buf[256];
     snprintf(buf, sizeof buf, "%d %s %s %.3f %llu", i, addrStr, callStr, secs,
diff --git a/contrib/fb303/TClientInfo.h b/contrib/fb303/TClientInfo.h
index d0a9770..6668c19 100644
--- a/contrib/fb303/TClientInfo.h
+++ b/contrib/fb303/TClientInfo.h
@@ -192,7 +192,7 @@
 
   /**
    * Return as string the thrift call either currently being processed or
-   * most recently processed if the connection is still open for additonal
+   * most recently processed if the connection is still open for additional
    * calls.  Returns NULL if a call hasn't been made yet or processing
    * has ended.
    */
diff --git a/contrib/fb303/aclocal/ax_cxx_compile_stdcxx_11.m4 b/contrib/fb303/aclocal/ax_cxx_compile_stdcxx_11.m4
new file mode 100644
index 0000000..a4c9189
--- /dev/null
+++ b/contrib/fb303/aclocal/ax_cxx_compile_stdcxx_11.m4
@@ -0,0 +1,134 @@
+# ============================================================================
+#  http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the C++11
+#   standard; if necessary, add switches to CXXFLAGS to enable support.
+#
+#   The first argument, if specified, indicates whether you insist on an
+#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+#   -std=c++11).  If neither is specified, you get whatever works, with
+#   preference for an extended mode.
+#
+#   The second argument, if specified 'mandatory' or if left unspecified,
+#   indicates that baseline C++11 support is required and that the macro
+#   should error out if no mode with that support is found.  If specified
+#   'optional', then configuration proceeds regardless, after defining
+#   HAVE_CXX11 if and only if a supporting mode is found.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 3
+
+m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [
+  template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+    typedef check<check<bool>> right_angle_brackets;
+
+    int a;
+    decltype(a) b;
+
+    typedef check<int> check_type;
+    check_type c;
+    check_type&& cr = static_cast<check_type&&>(c);
+
+    auto d = a;
+])
+
+AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
+  m4_if([$1], [], [],
+        [$1], [ext], [],
+        [$1], [noext], [],
+        [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
+  m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
+        [$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
+        [$2], [optional], [ax_cxx_compile_cxx11_required=false],
+        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])dnl
+  AC_LANG_PUSH([C++])dnl
+  ac_success=no
+  AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
+  ax_cv_cxx_compile_cxx11,
+  [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+    [ax_cv_cxx_compile_cxx11=yes],
+    [ax_cv_cxx_compile_cxx11=no])])
+  if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+    ac_success=yes
+  fi
+
+  m4_if([$1], [noext], [], [dnl
+  if test x$ac_success = xno; then
+    for switch in -std=gnu++11; do
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+                     $cachevar,
+        [ac_save_CXXFLAGS="$CXXFLAGS"
+         CXXFLAGS="$CXXFLAGS $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXXFLAGS="$ac_save_CXXFLAGS"])
+      if eval test x\$$cachevar = xyes; then
+        CXXFLAGS="$CXXFLAGS $switch"
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+
+  m4_if([$1], [ext], [], [dnl
+  if test x$ac_success = xno; then
+    for switch in -std=c++11; do
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+                     $cachevar,
+        [ac_save_CXXFLAGS="$CXXFLAGS"
+         CXXFLAGS="$CXXFLAGS $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXXFLAGS="$ac_save_CXXFLAGS"])
+      if eval test x\$$cachevar = xyes; then
+        CXXFLAGS="$CXXFLAGS $switch"
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+  AC_LANG_POP([C++])
+  if test x$ax_cxx_compile_cxx11_required = xtrue; then
+    if test x$ac_success = xno; then
+      AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
+    fi
+  else
+    if test x$ac_success = xno; then
+      HAVE_CXX11=0
+      AC_MSG_NOTICE([No compiler with C++11 support was found])
+    else
+      HAVE_CXX11=1
+      AC_DEFINE(HAVE_CXX11,1,
+                [define if the compiler supports basic C++11 syntax])
+    fi
+
+    AC_SUBST(HAVE_CXX11)
+  fi
+])
+
diff --git a/contrib/fb303/aclocal/ax_javac_and_java.m4 b/contrib/fb303/aclocal/ax_javac_and_java.m4
index fdb4bf0..581b450 100644
--- a/contrib/fb303/aclocal/ax_javac_and_java.m4
+++ b/contrib/fb303/aclocal/ax_javac_and_java.m4
@@ -7,7 +7,7 @@
 dnl java command tested.  Otherwise, a hard-coded list will be used.
 dnl Similarly for "JAVAC".
 dnl
-dnl AX_JAVAC_AND_JAVA does not currenly support testing for a particular
+dnl AX_JAVAC_AND_JAVA does not currently support testing for a particular
 dnl Java version, testing for only one of "java" and "javac", or
 dnl compiling or running user-provided Java code.
 dnl
diff --git a/contrib/fb303/configure.ac b/contrib/fb303/configure.ac
index 5b99f2a..73b35ba 100644
--- a/contrib/fb303/configure.ac
+++ b/contrib/fb303/configure.ac
@@ -71,6 +71,7 @@
 # Example: sets $(thrift_home) variable with default path set to /usr/local.
 FB_WITH_PATH([thrift_home], [thriftpath], [/usr/local])
 
+AX_CXX_COMPILE_STDCXX_11([noext])
 AX_THRIFT_LIB(cpp, [C++], yes)
 have_cpp=no
 if test "$with_cpp" = "yes"; then
diff --git a/contrib/fb303/cpp/FacebookBase.cpp b/contrib/fb303/cpp/FacebookBase.cpp
index 8003340..3c56975 100644
--- a/contrib/fb303/cpp/FacebookBase.cpp
+++ b/contrib/fb303/cpp/FacebookBase.cpp
@@ -98,7 +98,7 @@
   // want our read/write structure to go over the wire
   counters_.acquireRead();
   for(ReadWriteCounterMap::iterator it = counters_.begin();
-      it != counters_.end(); it++)
+      it != counters_.end(); ++it)
   {
     _return[it->first] = it->second.value;
   }
diff --git a/contrib/fb303/cpp/FacebookBase.h b/contrib/fb303/cpp/FacebookBase.h
index 2159c95..daa5246 100644
--- a/contrib/fb303/cpp/FacebookBase.h
+++ b/contrib/fb303/cpp/FacebookBase.h
@@ -22,6 +22,7 @@
 
 #include "FacebookService.h"
 
+#include <boost/shared_ptr.hpp>
 #include <thrift/server/TServer.h>
 #include <thrift/concurrency/Mutex.h>
 
diff --git a/contrib/fb303/cpp/ServiceTracker.cpp b/contrib/fb303/cpp/ServiceTracker.cpp
index 2914ff6..7a61b21 100644
--- a/contrib/fb303/cpp/ServiceTracker.cpp
+++ b/contrib/fb303/cpp/ServiceTracker.cpp
@@ -251,7 +251,7 @@
   uint64_t count;
   for (iter = checkpointServiceDuration_.begin();
        iter != checkpointServiceDuration_.end();
-       iter++) {
+       ++iter) {
     count = iter->second.first;
     handler_->setCounter(string("checkpoint_count_") + iter->first, count);
     if (count == 0) {
diff --git a/contrib/fb303/if/fb303.thrift b/contrib/fb303/if/fb303.thrift
index 66c8315..89bd6eb 100644
--- a/contrib/fb303/if/fb303.thrift
+++ b/contrib/fb303/if/fb303.thrift
@@ -24,6 +24,7 @@
 namespace java com.facebook.fb303
 namespace cpp facebook.fb303
 namespace perl Facebook.FB303
+namespace netcore Facebook.FB303.Test
 
 /**
  * Common status reporting mechanism across all services
diff --git a/contrib/fb303/java/build.properties b/contrib/fb303/java/build.properties
new file mode 100644
index 0000000..8463668
--- /dev/null
+++ b/contrib/fb303/java/build.properties
@@ -0,0 +1,5 @@
+# Maven Ant tasks Jar details
+mvn.ant.task.version=2.1.3
+mvn.repo=http://repo1.maven.org/maven2
+mvn.ant.task.url=${mvn.repo}/org/apache/maven/maven-ant-tasks/${mvn.ant.task.version}
+mvn.ant.task.jar=maven-ant-tasks-${mvn.ant.task.version}.jar
diff --git a/contrib/fb303/java/build.xml b/contrib/fb303/java/build.xml
index 8f2fa51..7a1b8f1 100755
--- a/contrib/fb303/java/build.xml
+++ b/contrib/fb303/java/build.xml
@@ -7,9 +7,9 @@
  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
@@ -26,20 +26,20 @@
   <property name="interface.dir" value="${basedir}/../if"/>
   <property name="thrift.java.dir" location="${thrift.root}/lib/java"/>
   <property name="build.tools.dir" location="${thrift.java.dir}/build/tools/"/>
-  <property name="thrift_compiler" value="${thrift.root}/compiler/cpp/thrift"/> 
+  <property name="thrift_compiler" value="${thrift.root}/compiler/cpp/thrift"/>
+  <property file="${basedir}/build.properties"/>
 
   <!-- inherit from the java build file for version and other properties -->
-  <property file="${thrift.java.dir}/build.properties" />
+  <property file="${thrift.java.dir}/gradle.properties" />
 
   <property environment="env"/>
 
   <condition property="version" value="${thrift.version}">
     <isset property="release"/>
   </condition>
-  <property name="version" value="${thrift.version}-snapshot"/>
+  <property name="version" value="${thrift.version}-SNAPSHOT"/>
 
   <property name="fb303.final.name" value="${fb303.artifactid}-${version}"/>
-  <property name="thrift.java.libthrift" value="${thrift.java.dir}/build/libthrift-${version}.jar"/>
 
   <property name="src" value="${basedir}/src"/>
   <property name="gen" value="${basedir}/gen-java"/>
@@ -74,8 +74,12 @@
     <echo message="Building ${fb303.final.name}.jar"/>
     <javac destdir="${build.classes.dir}" debug="on">
       <classpath>
-        <pathelement location="${thrift.java.libthrift}"/>
-        <fileset dir="${thrift.root}/lib/java/build/lib">
+        <fileset dir="${thrift.java.dir}/build/libs">
+          <include name="libthrift*.jar" />
+          <exclude name="libthrift*javadoc.jar" />
+          <exclude name="libthrift*sources.jar" />
+        </fileset>
+        <fileset dir="${thrift.java.dir}/build/deps">
           <include name="*.jar"/>
         </fileset>
       </classpath>
@@ -120,21 +124,21 @@
     <artifact:remoteRepository id="apache" url="${apache.repo}"/>
 
     <!-- Pom file information -->
-    <artifact:pom id="pom" 
-      groupId="${thrift.groupid}" 
+    <artifact:pom id="pom"
+      groupId="${thrift.groupid}"
       artifactId="${fb303.artifactid}"
-      version="${version}" 
+      version="${version}"
       url="http://thrift.apache.org"
       name="Apache Thrift"
       description="Thrift is a software framework for scalable cross-language services development."
-      packaging="pom"
+      packaging="jar"
     >
       <remoteRepository refid="central"/>
       <remoteRepository refid="apache"/>
       <license name="The Apache Software License, Version 2.0" url="${license}"/>
-      <scm connection="scm:git:https://git-wip-us.apache.org/repos/asf/thrift.git" 
-      developerConnection="scm:git:https://git-wip-us.apache.org/repos/asf/thrift.git"
-      url="https://git-wip-us.apache.org/repos/asf?p=thrift.git"
+      <scm connection="scm:git:https://github.com/apache/thrift.git"
+      developerConnection="scm:git:https://github.com/apache/thrift.git"
+      url="https://github.com/apache/thrift"
     />
       <!-- Thrift Developers -->
       <developer id="mcslee" name="Mark Slee"/>
diff --git a/contrib/fb303/py/fb303/FacebookBase.py b/contrib/fb303/py/fb303/FacebookBase.py
index 685ff20..07db10c 100644
--- a/contrib/fb303/py/fb303/FacebookBase.py
+++ b/contrib/fb303/py/fb303/FacebookBase.py
@@ -24,59 +24,60 @@
 import thrift.reflection.limited
 from ttypes import fb_status
 
+
 class FacebookBase(FacebookService.Iface):
 
-  def __init__(self, name):
-    self.name = name
-    self.alive = int(time.time())
-    self.counters = {}
+    def __init__(self, name):
+        self.name = name
+        self.alive = int(time.time())
+        self.counters = {}
 
-  def getName(self, ):
-    return self.name
+    def getName(self, ):
+        return self.name
 
-  def getVersion(self, ):
-    return ''
+    def getVersion(self, ):
+        return ''
 
-  def getStatus(self, ):
-    return fb_status.ALIVE
+    def getStatus(self, ):
+        return fb_status.ALIVE
 
-  def getCounters(self):
-    return self.counters
+    def getCounters(self):
+        return self.counters
 
-  def resetCounter(self, key):
-    self.counters[key] = 0
+    def resetCounter(self, key):
+        self.counters[key] = 0
 
-  def getCounter(self, key):
-    if self.counters.has_key(key):
-      return self.counters[key]
-    return 0
+    def getCounter(self, key):
+        if self.counters.has_key(key):
+            return self.counters[key]
+        return 0
 
-  def incrementCounter(self, key):
-    self.counters[key] = self.getCounter(key) + 1
+    def incrementCounter(self, key):
+        self.counters[key] = self.getCounter(key) + 1
 
-  def setOption(self, key, value):
-    pass
+    def setOption(self, key, value):
+        pass
 
-  def getOption(self, key):
-    return ""
+    def getOption(self, key):
+        return ""
 
-  def getOptions(self):
-    return {}
+    def getOptions(self):
+        return {}
 
-  def getOptions(self):
-    return {}
+    def getOptions(self):
+        return {}
 
-  def aliveSince(self):
-    return self.alive
+    def aliveSince(self):
+        return self.alive
 
-  def getCpuProfile(self, duration):
-    return ""
+    def getCpuProfile(self, duration):
+        return ""
 
-  def getLimitedReflection(self):
-    return thrift.reflection.limited.Service()
+    def getLimitedReflection(self):
+        return thrift.reflection.limited.Service()
 
-  def reinitialize(self):
-    pass
+    def reinitialize(self):
+        pass
 
-  def shutdown(self):
-    pass
+    def shutdown(self):
+        pass
diff --git a/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py b/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py
index 4f8ce99..5c8f409 100644
--- a/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py
+++ b/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python 
 
 #
 # Licensed to the Apache Software Foundation (ASF) under one
@@ -19,7 +19,9 @@
 # under the License.
 #
 
-import sys, os
+from __future__ import print_function
+import sys
+import os
 from optparse import OptionParser
 
 from thrift.Thrift import *
@@ -31,11 +33,12 @@
 from fb303 import *
 from fb303.ttypes import *
 
+
 def service_ctrl(
-                 command,
-                 port,
-                 trans_factory = None,
-                 prot_factory = None):
+        command,
+        port,
+        trans_factory=None,
+        prot_factory=None):
     """
     service_ctrl is a generic function to execute standard fb303 functions
 
@@ -55,66 +58,59 @@
             msg = fb_status_string(status)
             if (len(status_details)):
                 msg += " - %s" % status_details
-            print msg
-
-            if (status == fb_status.ALIVE):
-                return 2
-            else:
-                return 3
+            print(msg)
+            return 2 if status == fb_status.ALIVE else 3
         except:
-            print "Failed to get status"
+            print("Failed to get status")
             return 3
 
     # scalar commands
-    if command in ["version","alive","name"]:
+    if command in ["version", "alive", "name"]:
         try:
-            result = fb303_wrapper(command,  port, trans_factory, prot_factory)
-            print result
+            result = fb303_wrapper(command, port, trans_factory, prot_factory)
+            print(result)
             return 0
         except:
-            print "failed to get ",command
+            print("failed to get ", command)
             return 3
 
     # counters
     if command in ["counters"]:
         try:
-            counters = fb303_wrapper('counters',  port, trans_factory, prot_factory)
+            counters = fb303_wrapper('counters', port, trans_factory, prot_factory)
             for counter in counters:
-                print "%s: %d" % (counter, counters[counter])
+                print("%s: %d" % (counter.encode('utf-8'), counters[counter]))
             return 0
         except:
-            print "failed to get counters"
+            print("failed to get counters")
             return 3
 
-
     # Only root should be able to run the following commands
     if os.getuid() == 0:
         # async commands
-        if command in ["stop","reload"] :
+        if command in ["stop", "reload"]:
             try:
                 fb303_wrapper(command, port, trans_factory, prot_factory)
                 return 0
             except:
-                print "failed to tell the service to ", command
+                print("failed to tell the service to ", command)
                 return 3
     else:
-        if command in ["stop","reload"]:
-            print "root privileges are required to stop or reload the service."
+        if command in ["stop", "reload"]:
+            print("root privileges are required to stop or reload the service.")
             return 4
 
-    print "The following commands are available:"
-    for command in ["counters","name","version","alive","status"]:
-        print "\t%s" % command
-    print "The following commands are available for users with root privileges:"
-    for command in ["stop","reload"]:
-        print "\t%s" % command
+    print("The following commands are available:")
+    for command in ["counters", "name", "version", "alive", "status"]:
+        print("\t%s" % command)
+    print("The following commands are available for users with root privileges:")
+    for command in ["stop", "reload"]:
+        print("\t%s" % command)
+
+    return 0
 
 
-
-    return 0;
-
-
-def fb303_wrapper(command, port, trans_factory = None, prot_factory = None):
+def fb303_wrapper(command, port, trans_factory=None, prot_factory=None):
     sock = TSocket.TSocket('localhost', port)
 
     # use input transport factory if provided
@@ -179,11 +175,11 @@
 
     # parse command line options
     parser = OptionParser()
-    commands=["stop","counters","status","reload","version","name","alive"]
+    commands = ["stop", "counters", "status", "reload", "version", "name", "alive"]
 
     parser.add_option("-c", "--command", dest="command", help="execute this API",
                       choices=commands, default="status")
-    parser.add_option("-p","--port",dest="port",help="the service's port",
+    parser.add_option("-p", "--port", dest="port", help="the service's port",
                       default=9082)
 
     (options, args) = parser.parse_args()
diff --git a/contrib/fb303/py/setup.py b/contrib/fb303/py/setup.py
index 6710c8f..d27c296 100644
--- a/contrib/fb303/py/setup.py
+++ b/contrib/fb303/py/setup.py
@@ -24,26 +24,25 @@
     from setuptools import setup, Extension
 except:
     from distutils.core import setup, Extension, Command
-        
-setup(name = 'thrift_fb303',
-    version = '1.0.0-dev',
-    description = 'Python bindings for the Apache Thrift FB303',
-    author = ['Thrift Developers'],
-    author_email = ['dev@thrift.apache.org'],
-    url = 'http://thrift.apache.org',
-    license = 'Apache License 2.0',
-    packages = [
-        'fb303',
-        'fb303_scripts',
-    ],
-    classifiers = [
-        'Development Status :: 5 - Production/Stable',
-        'Environment :: Console',
-        'Intended Audience :: Developers',
-        'Programming Language :: Python',
-        'Programming Language :: Python :: 2',
-        'Topic :: Software Development :: Libraries',
-        'Topic :: System :: Networking'
-    ],
-)
 
+setup(name='thrift_fb303',
+      version='1.0.0',
+      description='Python bindings for the Apache Thrift FB303',
+      author=['Apache Thrift Developers'],
+      author_email=['dev@thrift.apache.org'],
+      url='http://thrift.apache.org',
+      license='Apache License 2.0',
+      packages=[
+          'fb303',
+          'fb303_scripts',
+      ],
+      classifiers=[
+          'Development Status :: 7 - Inactive',
+          'Environment :: Console',
+          'Intended Audience :: Developers',
+          'Programming Language :: Python',
+          'Programming Language :: Python :: 2',
+          'Topic :: Software Development :: Libraries',
+          'Topic :: System :: Networking'
+      ],
+      )
diff --git a/contrib/mingw-cross-compile.sh b/contrib/mingw-cross-compile.sh
index 894ae5f..7ed5d47 100755
--- a/contrib/mingw-cross-compile.sh
+++ b/contrib/mingw-cross-compile.sh
@@ -2,21 +2,10 @@
 set -e
 
 ./configure \
-  --without-cpp \
-  --without-c_glib \
-  --without-java \
-  --without-csharp \
-  --without-python \
-  --without-ruby \
-  --without-haskell \
-  --without-perl \
-  --without-php \
-  --without-erlang \
-  --without-go \
-  --without-d \
+  --disable-libs \
   --build=i686-pc-linux-gnu \
   --host=i586-mingw32msvc \
-  CPPFLAGS='-DMINGW'
+  CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++
 
 make
 
diff --git a/contrib/parse_profiling.py b/contrib/parse_profiling.py
index 52d2211..0be5f29 100755
--- a/contrib/parse_profiling.py
+++ b/contrib/parse_profiling.py
@@ -42,10 +42,12 @@
         self.address = address
         self.sourceFile = None
         self.sourceLine = None
-        self.funtion = None
+        self.function = None
 
 
 g_addrs_by_filename = {}
+
+
 def get_address(filename, address):
     """
     Retrieve an AddressInfo object for the specified object file and address.
@@ -103,12 +105,12 @@
         idx = file_and_line.rfind(':')
         if idx < 0:
             msg = 'expected file and line number from addr2line; got %r' % \
-                    (file_and_line,)
+                (file_and_line,)
             msg += '\nfile=%r, address=%r' % (filename, address.address)
             raise Exception(msg)
 
         address.sourceFile = file_and_line[:idx]
-        address.sourceLine = file_and_line[idx+1:]
+        address.sourceLine = file_and_line[idx + 1:]
 
     (remaining_out, cmd_err) = proc.communicate()
     retcode = proc.wait()
@@ -180,7 +182,7 @@
 
     virt_call_regex = re.compile(r'^\s*T_VIRTUAL_CALL: (\d+) calls on (.*):$')
     gen_prot_regex = re.compile(
-            r'^\s*T_GENERIC_PROTOCOL: (\d+) calls to (.*) with a (.*):$')
+        r'^\s*T_GENERIC_PROTOCOL: (\d+) calls to (.*) with a (.*):$')
     bt_regex = re.compile(r'^\s*#(\d+)\s*(.*) \[(0x[0-9A-Za-z]+)\]$')
 
     # Parse all of the input, and store it as Entry objects
@@ -209,7 +211,7 @@
                 # "_Z" to the type name to make it look like an external name.
                 type_name = '_Z' + type_name
             header = 'T_VIRTUAL_CALL: %d calls on "%s"' % \
-                    (num_calls, type_name)
+                (num_calls, type_name)
             if current_entry is not None:
                 entries.append(current_entry)
             current_entry = Entry(header)
@@ -224,7 +226,7 @@
                 type_name1 = '_Z' + type_name1
                 type_name2 = '_Z' + type_name2
             header = 'T_GENERIC_PROTOCOL: %d calls to "%s" with a "%s"' % \
-                    (num_calls, type_name1, type_name2)
+                (num_calls, type_name1, type_name2)
             if current_entry is not None:
                 entries.append(current_entry)
             current_entry = Entry(header)
diff --git a/contrib/thrift-maven-plugin/pom.xml b/contrib/thrift-maven-plugin/pom.xml
new file mode 100644
index 0000000..1d66bc6
--- /dev/null
+++ b/contrib/thrift-maven-plugin/pom.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+<project 
+  xmlns="http://maven.apache.org/POM/4.0.0" 
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.thrift</groupId>
+  <artifactId>thrift-maven-plugin</artifactId>
+  <packaging>maven-plugin</packaging>
+  <name>thrift-maven-plugin</name>
+  <version>1.0.0</version>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.8</source>
+          <target>1.8</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>2.14.1</version>
+        <configuration>
+          <systemPropertyVariables>
+            <thriftExecutable>${thrift.compiler}</thriftExecutable>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+      <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.11</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-plugin-api</artifactId>
+      <version>3.1.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-project</artifactId>
+      <version>2.2.1</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+      <version>14.0.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+      <version>3.0.14</version>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <version>1.10.19</version>
+      <scope>test</scope>
+   </dependency>
+  </dependencies>
+  <properties>
+    <thrift.root>${basedir}/../..</thrift.root>
+    <thrift.compiler>${thrift.root}/compiler/cpp/thrift</thrift.compiler>
+    <thrift.test.home>${thrift.root}/test</thrift.test.home>
+  </properties>
+</project>
diff --git a/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/AbstractThriftMojo.java b/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/AbstractThriftMojo.java
new file mode 100644
index 0000000..869be95
--- /dev/null
+++ b/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/AbstractThriftMojo.java
@@ -0,0 +1,380 @@
+/*
+ * 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 org.apache.thrift.maven;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.MavenProjectHelper;
+import org.codehaus.plexus.util.cli.CommandLineException;
+import org.codehaus.plexus.util.io.RawInputStreamFacade;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Sets.newHashSet;
+import static java.lang.String.format;
+import static java.util.Arrays.asList;
+import static java.util.Collections.list;
+import static org.codehaus.plexus.util.FileUtils.cleanDirectory;
+import static org.codehaus.plexus.util.FileUtils.copyStreamToFile;
+import static org.codehaus.plexus.util.FileUtils.getFiles;
+
+/**
+ * Abstract Mojo implementation.
+ * <p/>
+ * This class is extended by {@link org.apache.thrift.maven.ThriftCompileMojo} and
+ * {@link org.apache.thrift.maven.ThriftTestCompileMojo} in order to override the specific configuration for
+ * compiling the main or test classes respectively.
+ */
+abstract class AbstractThriftMojo extends AbstractMojo {
+
+    private static final String THRIFT_FILE_SUFFIX = ".thrift";
+
+    private static final String DEFAULT_INCLUDES = "**/*" + THRIFT_FILE_SUFFIX;
+
+    /**
+     * The current Maven project.
+     *
+     * @parameter default-value="${project}"
+     * @readonly
+     * @required
+     */
+    protected MavenProject project;
+
+    /**
+     * A helper used to add resources to the project.
+     *
+     * @component
+     * @required
+     */
+    protected MavenProjectHelper projectHelper;
+
+    /**
+     * This is the path to the {@code thrift} executable. By default it will search the {@code $PATH}.
+     *
+     * @parameter default-value="thrift"
+     * @required
+     */
+    private String thriftExecutable;
+
+    /**
+     * This string is passed to the {@code --gen} option of the {@code thrift} parameter. By default
+     * it will generate Java output. The main reason for this option is to be able to add options
+     * to the Java generator - if you generate something else, you're on your own.
+     *
+     * @parameter default-value="java"
+     */
+    private String generator;
+
+    /**
+     * @parameter
+     */
+    private File[] additionalThriftPathElements = new File[]{};
+
+    /**
+     * Since {@code thrift} cannot access jars, thrift files in dependencies are extracted to this location
+     * and deleted on exit. This directory is always cleaned during execution.
+     *
+     * @parameter default-value="${project.build.directory}/thrift-dependencies"
+     * @required
+     */
+    private File temporaryThriftFileDirectory;
+
+    /**
+     * This is the path to the local maven {@code repository}.
+     *
+     * @parameter default-value="${localRepository}"
+     * @required
+     */
+    protected ArtifactRepository localRepository;
+
+    /**
+     * Set this to {@code false} to disable hashing of dependent jar paths.
+     * <p/>
+     * This plugin expands jars on the classpath looking for embedded .thrift files.
+     * Normally these paths are hashed (MD5) to avoid issues with long file names on windows.
+     * However if this property is set to {@code false} longer paths will be used.
+     *
+     * @parameter default-value="true"
+     * @required
+     */
+    protected boolean hashDependentPaths;
+
+    /**
+     * @parameter
+     */
+    private Set<String> includes = ImmutableSet.of(DEFAULT_INCLUDES);
+
+    /**
+     * @parameter
+     */
+    private Set<String> excludes = ImmutableSet.of();
+
+    /**
+     * @parameter
+     */
+    private long staleMillis = 0;
+
+    /**
+     * @parameter
+     */
+    private boolean checkStaleness = false;
+
+    /**
+     * Executes the mojo.
+     */
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        checkParameters();
+        final File thriftSourceRoot = getThriftSourceRoot();
+        if (thriftSourceRoot.exists()) {
+            try {
+                ImmutableSet<File> thriftFiles = findThriftFilesInDirectory(thriftSourceRoot);
+                final File outputDirectory = getOutputDirectory();
+                ImmutableSet<File> outputFiles = findGeneratedFilesInDirectory(getOutputDirectory());
+
+                if (thriftFiles.isEmpty()) {
+                    getLog().info("No thrift files to compile.");
+                } else if (checkStaleness && ((lastModified(thriftFiles) + staleMillis) < lastModified(outputFiles))) {
+                    getLog().info("Skipping compilation because target directory newer than sources.");
+                    attachFiles();
+                } else {
+                    ImmutableSet<File> derivedThriftPathElements =
+                            makeThriftPathFromJars(temporaryThriftFileDirectory, getDependencyArtifactFiles());
+                    outputDirectory.mkdirs();
+
+                    // Quick fix to fix issues with two mvn installs in a row (ie no clean)
+                    // cleanDirectory(outputDirectory);
+
+                    Thrift thrift = new Thrift.Builder(thriftExecutable, outputDirectory)
+                            .setGenerator(generator)
+                            .addThriftPathElement(thriftSourceRoot)
+                            .addThriftPathElements(derivedThriftPathElements)
+                            .addThriftPathElements(asList(additionalThriftPathElements))
+                            .addThriftFiles(thriftFiles)
+                            .build();
+                    final int exitStatus = thrift.compile();
+                    if (exitStatus != 0) {
+                        getLog().error("thrift failed output: " + thrift.getOutput());
+                        getLog().error("thrift failed error: " + thrift.getError());
+                        throw new MojoFailureException(
+                                "thrift did not exit cleanly. Review output for more information.");
+                    }
+                    attachFiles();
+                }
+            } catch (IOException e) {
+                throw new MojoExecutionException("An IO error occurred", e);
+            } catch (IllegalArgumentException e) {
+                throw new MojoFailureException("thrift failed to execute because: " + e.getMessage(), e);
+            } catch (CommandLineException e) {
+                throw new MojoExecutionException("An error occurred while invoking thrift.", e);
+            }
+        } else {
+            getLog().info(format("%s does not exist. Review the configuration or consider disabling the plugin.",
+                    thriftSourceRoot));
+        }
+    }
+
+    ImmutableSet<File> findGeneratedFilesInDirectory(File directory) throws IOException {
+        if (directory == null || !directory.isDirectory())
+            return ImmutableSet.of();
+
+        List<File> javaFilesInDirectory = getFiles(directory, "**/*.java", null);
+        return ImmutableSet.copyOf(javaFilesInDirectory);
+    }
+
+    private long lastModified(ImmutableSet<File> files) {
+        long result = 0;
+        for (File file : files) {
+            if (file.lastModified() > result)
+                result = file.lastModified();
+        }
+        return result;
+    }
+
+    private void checkParameters() {
+        checkNotNull(project, "project");
+        checkNotNull(projectHelper, "projectHelper");
+        checkNotNull(thriftExecutable, "thriftExecutable");
+        checkNotNull(generator, "generator");
+        final File thriftSourceRoot = getThriftSourceRoot();
+        checkNotNull(thriftSourceRoot);
+        checkArgument(!thriftSourceRoot.isFile(), "thriftSourceRoot is a file, not a directory");
+        checkNotNull(temporaryThriftFileDirectory, "temporaryThriftFileDirectory");
+        checkState(!temporaryThriftFileDirectory.isFile(), "temporaryThriftFileDirectory is a file, not a directory");
+        final File outputDirectory = getOutputDirectory();
+        checkNotNull(outputDirectory);
+        checkState(!outputDirectory.isFile(), "the outputDirectory is a file, not a directory");
+    }
+
+    protected abstract File getThriftSourceRoot();
+
+    protected abstract List<Artifact> getDependencyArtifacts();
+
+    protected abstract File getOutputDirectory();
+
+    protected abstract void attachFiles();
+
+    /**
+     * Gets the {@link File} for each dependency artifact.
+     *
+     * @return A set of all dependency artifacts.
+     */
+    private ImmutableSet<File> getDependencyArtifactFiles() {
+        Set<File> dependencyArtifactFiles = newHashSet();
+        for (Artifact artifact : getDependencyArtifacts()) {
+            dependencyArtifactFiles.add(artifact.getFile());
+        }
+        return ImmutableSet.copyOf(dependencyArtifactFiles);
+    }
+
+    /**
+     * @throws IOException
+     */
+    ImmutableSet<File> makeThriftPathFromJars(File temporaryThriftFileDirectory, Iterable<File> classpathElementFiles)
+            throws IOException, MojoExecutionException {
+        checkNotNull(classpathElementFiles, "classpathElementFiles");
+        // clean the temporary directory to ensure that stale files aren't used
+        if (temporaryThriftFileDirectory.exists()) {
+            cleanDirectory(temporaryThriftFileDirectory);
+        }
+
+        Set<File> thriftDirectories = newHashSet();
+
+        for (File classpathElementFile : classpathElementFiles) {
+            // for some reason under IAM, we receive poms as dependent files
+            // I am excluding .xml rather than including .jar as there may be other extensions in use (sar, har, zip)
+            if (classpathElementFile.isFile() && classpathElementFile.canRead() &&
+                    !classpathElementFile.getName().endsWith(".xml")) {
+
+                // create the jar file. the constructor validates.
+                JarFile classpathJar;
+                try {
+                    classpathJar = new JarFile(classpathElementFile);
+                } catch (IOException e) {
+                    throw new IllegalArgumentException(format(
+                            "%s was not a readable artifact", classpathElementFile));
+                }
+
+                /**
+                 * Copy each .thrift file found in the JAR into a temporary directory, preserving the
+                 * directory path it had relative to its containing JAR. Add the resulting root directory
+                 * (unique for each JAR processed) to the set of thrift include directories to use when
+                 * compiling.
+                 */
+                for (JarEntry jarEntry : list(classpathJar.entries())) {
+                    final String jarEntryName = jarEntry.getName();
+                    if (jarEntry.getName().endsWith(THRIFT_FILE_SUFFIX)) {
+                        final String truncatedJarPath = truncatePath(classpathJar.getName());
+                        final File thriftRootDirectory = new File(temporaryThriftFileDirectory, truncatedJarPath);
+                        final File uncompressedCopy =
+                                new File(thriftRootDirectory, jarEntryName);
+                        uncompressedCopy.getParentFile().mkdirs();
+                        copyStreamToFile(new RawInputStreamFacade(classpathJar
+                                .getInputStream(jarEntry)), uncompressedCopy);
+                        thriftDirectories.add(thriftRootDirectory);
+                    }
+                }
+
+            } else if (classpathElementFile.isDirectory()) {
+                File[] thriftFiles = classpathElementFile.listFiles(new FilenameFilter() {
+                    public boolean accept(File dir, String name) {
+                        return name.endsWith(THRIFT_FILE_SUFFIX);
+                    }
+                });
+
+                if (thriftFiles.length > 0) {
+                    thriftDirectories.add(classpathElementFile);
+                }
+            }
+        }
+
+        return ImmutableSet.copyOf(thriftDirectories);
+    }
+
+    ImmutableSet<File> findThriftFilesInDirectory(File directory) throws IOException {
+        checkNotNull(directory);
+        checkArgument(directory.isDirectory(), "%s is not a directory", directory);
+        List<File> thriftFilesInDirectory = getFiles(directory, 
+        		Joiner.on(",").join(includes),
+        		Joiner.on(",").join(excludes));
+        return ImmutableSet.copyOf(thriftFilesInDirectory);
+    }
+
+    /**
+     * Truncates the path of jar files so that they are relative to the local repository.
+     *
+     * @param jarPath the full path of a jar file.
+     * @return the truncated path relative to the local repository or root of the drive.
+     */
+    String truncatePath(final String jarPath) throws MojoExecutionException {
+
+        if (hashDependentPaths) {
+            try {
+                return toHexString(MessageDigest.getInstance("MD5").digest(jarPath.getBytes()));
+            } catch (NoSuchAlgorithmException e) {
+                throw new MojoExecutionException("Failed to expand dependent jar", e);
+            }
+        }
+
+        String repository = localRepository.getBasedir().replace('\\', '/');
+        if (!repository.endsWith("/")) {
+            repository += "/";
+        }
+
+        String path = jarPath.replace('\\', '/');
+        int repositoryIndex = path.indexOf(repository);
+        if (repositoryIndex != -1) {
+            path = path.substring(repositoryIndex + repository.length());
+        }
+
+        // By now the path should be good, but do a final check to fix windows machines.
+        int colonIndex = path.indexOf(':');
+        if (colonIndex != -1) {
+            // 2 = :\ in C:\
+            path = path.substring(colonIndex + 2);
+        }
+
+        return path;
+    }
+
+    private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
+
+    public static String toHexString(byte[] byteArray) {
+        final StringBuilder hexString = new StringBuilder(2 * byteArray.length);
+        for (final byte b : byteArray) {
+            hexString.append(HEX_CHARS[(b & 0xF0) >> 4]).append(HEX_CHARS[b & 0x0F]);
+        }
+        return hexString.toString();
+    }
+}
diff --git a/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/Thrift.java b/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/Thrift.java
new file mode 100644
index 0000000..6eea954
--- /dev/null
+++ b/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/Thrift.java
@@ -0,0 +1,262 @@
+/*
+ * 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 org.apache.thrift.maven;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import org.codehaus.plexus.util.cli.CommandLineException;
+import org.codehaus.plexus.util.cli.CommandLineUtils;
+import org.codehaus.plexus.util.cli.Commandline;
+import java.io.File;
+import java.util.List;
+import java.util.Set;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Lists.newLinkedList;
+import static com.google.common.collect.Sets.newHashSet;
+
+/**
+ * This class represents an invokable configuration of the {@code thrift}
+ * compiler. The actual executable is invoked using the plexus
+ * {@link Commandline}.
+ * <p/>
+ * This class currently only supports generating java source files.
+ */
+final class Thrift {
+
+    final static String GENERATED_JAVA = "gen-java";
+
+    private final String executable;
+    private final String generator;
+    private final ImmutableSet<File> thriftPathElements;
+    private final ImmutableSet<File> thriftFiles;
+    private final File javaOutputDirectory;
+    private final CommandLineUtils.StringStreamConsumer output;
+    private final CommandLineUtils.StringStreamConsumer error;
+
+    /**
+     * Constructs a new instance. This should only be used by the {@link Builder}.
+     *
+     * @param executable          The path to the {@code thrift} executable.
+     * @param generator           The value for the {@code --gen} option.
+     * @param thriftPath          The directories in which to search for imports.
+     * @param thriftFiles         The thrift source files to compile.
+     * @param javaOutputDirectory The directory into which the java source files
+     *                            will be generated.
+     */
+    private Thrift(String executable, String generator, ImmutableSet<File> thriftPath,
+                   ImmutableSet<File> thriftFiles, File javaOutputDirectory) {
+        this.executable = checkNotNull(executable, "executable");
+        this.generator = checkNotNull(generator, "generator");
+        this.thriftPathElements = checkNotNull(thriftPath, "thriftPath");
+        this.thriftFiles = checkNotNull(thriftFiles, "thriftFiles");
+        this.javaOutputDirectory = checkNotNull(javaOutputDirectory, "javaOutputDirectory");
+        this.error = new CommandLineUtils.StringStreamConsumer();
+        this.output = new CommandLineUtils.StringStreamConsumer();
+    }
+
+    /**
+     * Invokes the {@code thrift} compiler using the configuration specified at
+     * construction.
+     *
+     * @return The exit status of {@code thrift}.
+     * @throws CommandLineException
+     */
+    public int compile() throws CommandLineException {
+
+        for (File thriftFile : thriftFiles) {
+            Commandline cl = new Commandline();
+            cl.setExecutable(executable);
+            cl.addArguments(buildThriftCommand(thriftFile).toArray(new String[]{}));
+            final int result = CommandLineUtils.executeCommandLine(cl, null, output, error);
+
+            if (result != 0) {
+                return result;
+            }
+        }
+
+        // result will always be 0 here.
+        return 0;
+    }
+
+    /**
+     * Creates the command line arguments.
+     * <p/>
+     * This method has been made visible for testing only.
+     *
+     * @param thriftFile
+     * @return A list consisting of the executable followed by any arguments.
+     */
+    ImmutableList<String> buildThriftCommand(final File thriftFile) {
+        final List<String> command = newLinkedList();
+        // add the executable
+        for (File thriftPathElement : thriftPathElements) {
+            command.add("-I");
+            command.add(thriftPathElement.toString());
+        }
+        command.add("-out");
+        command.add(javaOutputDirectory.toString());
+        command.add("--gen");
+        command.add(generator);
+        command.add(thriftFile.toString());
+        return ImmutableList.copyOf(command);
+    }
+
+    /**
+     * @return the output
+     */
+    public String getOutput() {
+        return output.getOutput();
+    }
+
+    /**
+     * @return the error
+     */
+    public String getError() {
+        return error.getOutput();
+    }
+
+    /**
+     * This class builds {@link Thrift} instances.
+     */
+    static final class Builder {
+        private final String executable;
+        private final File javaOutputDirectory;
+        private Set<File> thriftPathElements;
+        private Set<File> thriftFiles;
+        private String generator;
+
+        /**
+         * Constructs a new builder. The two parameters are present as they are
+         * required for all {@link Thrift} instances.
+         *
+         * @param executable          The path to the {@code thrift} executable.
+         * @param javaOutputDirectory The directory into which the java source files
+         *                            will be generated.
+         * @throws NullPointerException     If either of the arguments are {@code null}.
+         * @throws IllegalArgumentException If the {@code javaOutputDirectory} is
+         *                                  not a directory.
+         */
+        public Builder(String executable, File javaOutputDirectory) {
+            this.executable = checkNotNull(executable, "executable");
+            this.javaOutputDirectory = checkNotNull(javaOutputDirectory);
+            checkArgument(javaOutputDirectory.isDirectory());
+            this.thriftFiles = newHashSet();
+            this.thriftPathElements = newHashSet();
+        }
+
+        /**
+         * Adds a thrift file to be compiled. Thrift files must be on the thriftpath
+         * and this method will fail if a thrift file is added without first adding a
+         * parent directory to the thriftpath.
+         *
+         * @param thriftFile
+         * @return The builder.
+         * @throws IllegalStateException If a thrift file is added without first
+         *                               adding a parent directory to the thriftpath.
+         * @throws NullPointerException  If {@code thriftFile} is {@code null}.
+         */
+        public Builder addThriftFile(File thriftFile) {
+            checkNotNull(thriftFile);
+            checkArgument(thriftFile.isFile());
+            checkArgument(thriftFile.getName().endsWith(".thrift"));
+            checkThriftFileIsInThriftPath(thriftFile);
+            thriftFiles.add(thriftFile);
+            return this;
+        }
+
+        /**
+         * Adds the option string for the Thrift executable's {@code --gen} parameter.
+         *
+         * @param generator
+         * @return The builder
+         * @throws NullPointerException If {@code generator} is {@code null}.
+         */
+        public Builder setGenerator(String generator) {
+            checkNotNull(generator);
+            this.generator = generator;
+            return this;
+        }
+
+        private void checkThriftFileIsInThriftPath(File thriftFile) {
+            assert thriftFile.isFile();
+            checkState(checkThriftFileIsInThriftPathHelper(thriftFile.getParentFile()));
+        }
+
+        private boolean checkThriftFileIsInThriftPathHelper(File directory) {
+            assert directory.isDirectory();
+            if (thriftPathElements.contains(directory)) {
+                return true;
+            } else {
+                final File parentDirectory = directory.getParentFile();
+                return (parentDirectory == null) ? false
+                        : checkThriftFileIsInThriftPathHelper(parentDirectory);
+            }
+        }
+
+        /**
+         * @see #addThriftFile(File)
+         */
+        public Builder addThriftFiles(Iterable<File> thriftFiles) {
+            for (File thriftFile : thriftFiles) {
+                addThriftFile(thriftFile);
+            }
+            return this;
+        }
+
+        /**
+         * Adds the {@code thriftPathElement} to the thriftPath.
+         *
+         * @param thriftPathElement A directory to be searched for imported thrift message
+         *                          buffer definitions.
+         * @return The builder.
+         * @throws NullPointerException     If {@code thriftPathElement} is {@code null}.
+         * @throws IllegalArgumentException If {@code thriftPathElement} is not a
+         *                                  directory.
+         */
+        public Builder addThriftPathElement(File thriftPathElement) {
+            checkNotNull(thriftPathElement);
+            checkArgument(thriftPathElement.isDirectory());
+            thriftPathElements.add(thriftPathElement);
+            return this;
+        }
+
+        /**
+         * @see #addThriftPathElement(File)
+         */
+        public Builder addThriftPathElements(Iterable<File> thriftPathElements) {
+            for (File thriftPathElement : thriftPathElements) {
+                addThriftPathElement(thriftPathElement);
+            }
+            return this;
+        }
+
+        /**
+         * @return A configured {@link Thrift} instance.
+         * @throws IllegalStateException If no thrift files have been added.
+         */
+        public Thrift build() {
+            checkState(!thriftFiles.isEmpty());
+            return new Thrift(executable, generator, ImmutableSet.copyOf(thriftPathElements),
+                    ImmutableSet.copyOf(thriftFiles), javaOutputDirectory);
+        }
+    }
+}
diff --git a/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftCompileMojo.java b/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftCompileMojo.java
new file mode 100644
index 0000000..b4f7571
--- /dev/null
+++ b/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftCompileMojo.java
@@ -0,0 +1,78 @@
+/*
+ * 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 org.apache.thrift.maven;
+
+import java.io.File;
+import java.util.List;
+import org.apache.maven.artifact.Artifact;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * This mojo executes the {@code thrift} compiler for generating java sources
+ * from thrift definitions. It also searches dependency artifacts for
+ * thrift files and includes them in the thriftPath so that they can be
+ * referenced. Finally, it adds the thrift files to the project as resources so
+ * that they are included in the final artifact.
+ *
+ * @phase generate-sources
+ * @goal compile
+ * @requiresDependencyResolution compile
+ */
+public final class ThriftCompileMojo extends AbstractThriftMojo {
+
+    /**
+     * The source directories containing the sources to be compiled.
+     *
+     * @parameter default-value="${basedir}/src/main/thrift"
+     * @required
+     */
+    private File thriftSourceRoot;
+
+    /**
+     * This is the directory into which the {@code .java} will be created.
+     *
+     * @parameter default-value="${project.build.directory}/generated-sources/thrift"
+     * @required
+     */
+    private File outputDirectory;
+
+    @Override
+    protected List<Artifact> getDependencyArtifacts() {
+        List<Artifact> compileArtifacts = project.getCompileArtifacts();
+        return compileArtifacts;
+    }
+
+    @Override
+    protected File getOutputDirectory() {
+        return outputDirectory;
+    }
+
+    @Override
+    protected File getThriftSourceRoot() {
+        return thriftSourceRoot;
+    }
+
+    @Override
+    protected void attachFiles() {
+        project.addCompileSourceRoot(outputDirectory.getAbsolutePath());
+        projectHelper.addResource(project, thriftSourceRoot.getAbsolutePath(),
+        		ImmutableList.of("**/*.thrift"), null);
+    }
+}
diff --git a/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftTestCompileMojo.java b/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftTestCompileMojo.java
new file mode 100644
index 0000000..1b1d99e
--- /dev/null
+++ b/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftTestCompileMojo.java
@@ -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 org.apache.thrift.maven;
+
+import java.io.File;
+import java.util.List;
+import org.apache.maven.artifact.Artifact;
+import com.google.common.collect.ImmutableList;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+
+/**
+ * @phase generate-test-sources
+ * @goal testCompile
+ * @requiresDependencyResolution test
+ */
+public final class ThriftTestCompileMojo extends AbstractThriftMojo {
+
+    /**
+     * The source directories containing the sources to be compiled.
+     *
+     * @parameter default-value="${basedir}/src/test/thrift"
+     * @required
+     */
+    private File thriftTestSourceRoot;
+
+    /**
+     * This is the directory into which the {@code .java} will be created.
+     *
+     * @parameter default-value="${project.build.directory}/generated-test-sources/thrift"
+     * @required
+     */
+    private File outputDirectory;
+
+    @Override
+    protected void attachFiles() {
+        project.addTestCompileSourceRoot(outputDirectory.getAbsolutePath());
+        projectHelper.addTestResource(project, thriftTestSourceRoot.getAbsolutePath(),
+        		ImmutableList.of("**/*.thrift"), null);
+    }
+
+    @Override
+    protected List<Artifact> getDependencyArtifacts() {
+        // TODO(gak): maven-project needs generics
+        @SuppressWarnings("unchecked")
+        List<Artifact> testArtifacts = project.getTestArtifacts();
+        return testArtifacts;
+    }
+
+    @Override
+    protected File getOutputDirectory() {
+        return outputDirectory;
+    }
+
+    @Override
+    protected File getThriftSourceRoot() {
+        return thriftTestSourceRoot;
+    }
+
+    /**
+     * Set the local maven ArtifactRepository. Exposed only to allow testing outside of Maven itself.
+     *
+     * @param localRepository local ArtifactRepository
+     */
+    public void setLocalMavenRepository(final ArtifactRepository localRepository) {
+        this.localRepository = localRepository;
+    }
+
+    /**
+     * Set the option to hash dependent JAR paths. Exposed only to allow testing outside of Maven itself.
+     *
+     * @param hashDependentPaths whether or not to hash paths to dependent JARs
+     */
+    public void setHashDependentPaths(final boolean hashDependentPaths) {
+        this.hashDependentPaths = hashDependentPaths;
+    }
+}
diff --git a/contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestAbstractThriftMojo.java b/contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestAbstractThriftMojo.java
new file mode 100644
index 0000000..c117671
--- /dev/null
+++ b/contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestAbstractThriftMojo.java
@@ -0,0 +1,102 @@
+/*
+ * 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 org.apache.thrift.maven;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.File;
+import java.util.Set;
+
+import static junit.framework.TestCase.assertEquals;
+
+
+public class TestAbstractThriftMojo {
+
+    private ThriftTestCompileMojo mojo;
+    private File testRootDir;
+    private ArtifactRepository mavenRepository;
+
+
+    @Before
+    public void setUp() throws Exception {
+        final File tmpDir = new File(System.getProperty("java.io.tmpdir"));
+        testRootDir = new File(tmpDir, "thrift-test");
+
+        // the truncatePath method assumes a maven repository, but it only cares about the base dir
+        mavenRepository = Mockito.mock(ArtifactRepository.class);
+        Mockito.when(mavenRepository.getBasedir()).thenReturn("/test/maven/repo/basedir");
+
+        mojo = new ThriftTestCompileMojo();
+        mojo.setLocalMavenRepository(mavenRepository);
+    }
+
+    @Test
+    public void testMakeThriftPathFromJars() throws Throwable {
+        final File temporaryThriftFileDirectory = testRootDir;
+
+        // The SharedIdl.jar file contains the same idl/shared.thrift and idl/tutorial.thrift hierarchy
+        // used by other tests. It's used here to represent a dependency of the project maven is building,
+        // one that is contributing .thrift IDL files as well as any other artifacts.
+        final Iterable<File> classpathElementFiles = Lists.newArrayList(
+                new File("src/test/resources/dependency-jar-test/SharedIdl.jar")
+        );
+
+        final Set<File> thriftDirectories = mojo.makeThriftPathFromJars(temporaryThriftFileDirectory, classpathElementFiles);
+
+        // The results should be a path to a directory named after the JAR itself (assuming no path hashing,
+        // but see below for a separate test of that) representing the root of a hierarchy containing thrift
+        // files, suitable for providing to the thrift compiler as an include directory. In this case, that
+        // means it points to the directory containing the "idl" hierarchy rather than to the idl directory
+        // itself.
+        final Set<File> expected = Sets.newHashSet(
+                new File(testRootDir, "src/test/resources/dependency-jar-test/SharedIdl.jar")
+        );
+
+        assertEquals("makeThriftPathFromJars should return thrift IDL base path from within JAR", expected, thriftDirectories);
+    }
+
+    @Test
+    public void testTruncatePath() throws Throwable {
+        // JAR path is unrelated to maven repo, and should be unchanged
+        assertEquals("/path/to/somejar.jar", mojo.truncatePath("/path/to/somejar.jar"));
+
+        // JAR path is within maven repo, and should be made relative to the repo
+        assertEquals("path/to/somejar.jar", mojo.truncatePath("/test/maven/repo/basedir/path/to/somejar.jar"));
+
+        // JAR path contains forward slashes that should be normalized
+        assertEquals("/path/to/somejar.jar", mojo.truncatePath("\\path\\to\\somejar.jar"));
+    }
+
+    @Test
+    public void testTruncatePathWithDependentPathHashing() throws Throwable {
+        mojo.setHashDependentPaths(true);
+
+        // hashDependentPaths set to true, the JAR path is immediately hashed (MD5) and converted to a hex string
+
+        assertEquals("1c85950987b23493462cf3c261d9510a", mojo.truncatePath("/path/to/somejar.jar"));
+        assertEquals("39fc2b4c34cb6cb0da38bed5d8b5fc67", mojo.truncatePath("/test/maven/repo/basedir/path/to/somejar.jar"));
+        assertEquals("25b6924f5b0e19486d0ff88448e999d5", mojo.truncatePath("\\path\\to\\somejar.jar"));
+    }
+
+}
diff --git a/contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestThrift.java b/contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestThrift.java
new file mode 100644
index 0000000..7c7891e
--- /dev/null
+++ b/contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestThrift.java
@@ -0,0 +1,163 @@
+/*
+ * 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 org.apache.thrift.maven;
+
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.cli.CommandLineException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class TestThrift {
+
+    private File testRootDir;
+    private File idlDir;
+    private File genJavaDir;
+    private Thrift.Builder builder;
+
+    @Before
+    public void setup() throws Exception {
+        final File tmpDir = new File(System.getProperty("java.io.tmpdir"));
+        testRootDir = new File(tmpDir, "thrift-test");
+
+        if (testRootDir.exists()) {
+            FileUtils.cleanDirectory(testRootDir);
+        } else {
+            assertTrue("Failed to create output directory for test: " + testRootDir.getPath(), testRootDir.mkdir());
+        }
+
+        File testResourceDir = new File("src/test/resources");
+        assertTrue("Unable to find test resources", testRootDir.exists());
+
+        String thriftExecutable = System.getProperty("thriftExecutable", "thrift");
+        if (!(new File(thriftExecutable).exists())) {
+            thriftExecutable = "thrift";
+        }
+        System.out.println("Thrift compiler: " + thriftExecutable);
+
+        idlDir = new File(testResourceDir, "idl");
+        genJavaDir = new File(testRootDir, Thrift.GENERATED_JAVA);
+        builder = new Thrift.Builder(thriftExecutable, testRootDir);
+        builder
+            .setGenerator("java")
+            .addThriftPathElement(idlDir);
+    }
+
+    @Test
+    public void testThriftCompile() throws Exception {
+        executeThriftCompile();
+    }
+
+    @Test
+    public void testThriftCompileWithGeneratorOption() throws Exception {
+        builder.setGenerator("java:private-members");
+        executeThriftCompile();
+    }
+
+    private void executeThriftCompile() throws CommandLineException {
+        final File thriftFile = new File(idlDir, "shared.thrift");
+
+        builder.addThriftFile(thriftFile);
+
+        final Thrift thrift = builder.build();
+
+        assertTrue("File not found: shared.thrift", thriftFile.exists());
+        assertFalse("gen-java directory should not exist", genJavaDir.exists());
+
+        // execute the compile
+        final int result = thrift.compile();
+        assertEquals(0, result);
+
+        assertFalse("gen-java directory was not removed", genJavaDir.exists());
+        assertTrue("generated java code doesn't exist",
+            new File(testRootDir, "shared/SharedService.java").exists());
+    }
+
+    @Test
+    public void testThriftMultipleFileCompile() throws Exception {
+        final File sharedThrift = new File(idlDir, "shared.thrift");
+        final File tutorialThrift = new File(idlDir, "tutorial.thrift");
+
+        builder.addThriftFile(sharedThrift);
+        builder.addThriftFile(tutorialThrift);
+
+        final Thrift thrift = builder.build();
+
+        assertTrue("File not found: shared.thrift", sharedThrift.exists());
+        assertFalse("gen-java directory should not exist", genJavaDir.exists());
+
+        // execute the compile
+        final int result = thrift.compile();
+        assertEquals(0, result);
+
+        assertFalse("gen-java directory was not removed", genJavaDir.exists());
+        assertTrue("generated java code doesn't exist",
+            new File(testRootDir, "shared/SharedService.java").exists());
+        assertTrue("generated java code doesn't exist",
+            new File(testRootDir, "tutorial/InvalidOperation.java").exists());
+    }
+
+    @Test
+    public void testBadCompile() throws Exception {
+        final File thriftFile = new File(testRootDir, "missing.thrift");
+        builder.addThriftPathElement(testRootDir);
+
+        // Hacking around checks in addThrift file.
+        assertTrue(thriftFile.createNewFile());
+        builder.addThriftFile(thriftFile);
+        assertTrue(thriftFile.delete());
+
+        final Thrift thrift = builder.build();
+
+        assertTrue(!thriftFile.exists());
+        assertFalse("gen-java directory should not exist", genJavaDir.exists());
+
+        // execute the compile
+        final int result = thrift.compile();
+        assertEquals(1, result);
+    }
+
+    @Test
+    public void testFileInPathPreCondition() throws Exception {
+        final File thriftFile = new File(testRootDir, "missing.thrift");
+
+        // Hacking around checks in addThrift file.
+        assertTrue(thriftFile.createNewFile());
+        try {
+            builder.addThriftFile(thriftFile);
+            fail("Expected IllegalStateException");
+        } catch (IllegalStateException e) {
+        }
+    }
+
+    @After
+    public void cleanup() throws Exception {
+        if (testRootDir.exists()) {
+            FileUtils.cleanDirectory(testRootDir);
+            assertTrue("Failed to delete output directory for test: " + testRootDir.getPath(), testRootDir.delete());
+        }
+    }
+}
diff --git a/contrib/thrift-maven-plugin/src/test/resources/idl/shared.thrift b/contrib/thrift-maven-plugin/src/test/resources/idl/shared.thrift
new file mode 100644
index 0000000..475e7f8
--- /dev/null
+++ b/contrib/thrift-maven-plugin/src/test/resources/idl/shared.thrift
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * This Thrift file can be included by other Thrift files that want to share
+ * these definitions.
+ */
+
+namespace cpp shared
+namespace java shared
+namespace perl shared
+
+struct SharedStruct {
+  1: i32 key
+  2: string value
+}
+
+service SharedService {
+  SharedStruct getStruct(1: i32 key)
+}
diff --git a/contrib/thrift-maven-plugin/src/test/resources/idl/tutorial.thrift b/contrib/thrift-maven-plugin/src/test/resources/idl/tutorial.thrift
new file mode 100644
index 0000000..86e433d
--- /dev/null
+++ b/contrib/thrift-maven-plugin/src/test/resources/idl/tutorial.thrift
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+# Thrift Tutorial
+# Mark Slee (mcslee@facebook.com)
+#
+# This file aims to teach you how to use Thrift, in a .thrift file. Neato. The
+# first thing to notice is that .thrift files support standard shell comments.
+# This lets you make your thrift file executable and include your Thrift build
+# step on the top line. And you can place comments like this anywhere you like.
+#
+# Before running this file, you will need to have installed the thrift compiler
+# into /usr/local/bin.
+
+/**
+ * The first thing to know about are types. The available types in Thrift are:
+ *
+ *  bool        Boolean, one byte
+ *  byte        Signed byte
+ *  i16         Signed 16-bit integer
+ *  i32         Signed 32-bit integer
+ *  i64         Signed 64-bit integer
+ *  double      64-bit floating point value
+ *  string      String
+ *  binary      Blob (byte array)
+ *  map<t1,t2>  Map from one type to another
+ *  list<t1>    Ordered list of one type
+ *  set<t1>     Set of unique elements of one type
+ *
+ * Did you also notice that Thrift supports C style comments?
+ */
+
+// Just in case you were wondering... yes. We support simple C comments too.
+
+/**
+ * Thrift files can reference other Thrift files to include common struct
+ * and service definitions. These are found using the current path, or by
+ * searching relative to any paths specified with the -I compiler flag.
+ *
+ * Included objects are accessed using the name of the .thrift file as a
+ * prefix. i.e. shared.SharedObject
+ */
+include "shared.thrift"
+
+/**
+ * Thrift files can namespace, package, or prefix their output in various
+ * target languages.
+ */
+namespace cpp tutorial
+namespace java tutorial
+namespace php tutorial
+namespace perl tutorial
+namespace smalltalk.category Thrift.Tutorial
+
+/**
+ * Thrift lets you do typedefs to get pretty names for your types. Standard
+ * C style here.
+ */
+typedef i32 MyInteger
+
+/**
+ * Thrift also lets you define constants for use across languages. Complex
+ * types and structs are specified using JSON notation.
+ */
+const i32 INT32CONSTANT = 9853
+const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}
+
+/**
+ * You can define enums, which are just 32 bit integers. Values are optional
+ * and start at 1 if not supplied, C style again.
+ */
+enum Operation {
+  ADD = 1,
+  SUBTRACT = 2,
+  MULTIPLY = 3,
+  DIVIDE = 4
+}
+
+/**
+ * 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.
+ */
+struct Work {
+  1: i32 num1 = 0,
+  2: i32 num2,
+  3: Operation op,
+  4: optional string comment,
+}
+
+/**
+ * Structs can also be exceptions, if they are nasty.
+ */
+exception InvalidOperation {
+  1: i32 what,
+  2: string why
+}
+
+/**
+ * Ahh, now onto the cool part, defining a service. Services just need a name
+ * and can optionally inherit from another service using the extends keyword.
+ */
+service Calculator extends shared.SharedService {
+
+  /**
+   * A method definition looks like C code. It has a return type, arguments,
+   * and optionally a list of exceptions that it may throw. Note that argument
+   * lists and exception lists are specified using the exact same syntax as
+   * field lists in struct or exception definitions.
+   */
+
+   void ping(),
+
+   i32 add(1:i32 num1, 2:i32 num2),
+
+   i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),
+
+   /**
+    * This method has a oneway modifier. That means the client only makes
+    * a request and does not listen for any response at all. Oneway methods
+    * must be void.
+    */
+   oneway void zip()
+
+}
+
+/**
+ * That just about covers the basics. Take a look in the test/ folder for more
+ * detailed examples. After you run this file, your generated code shows up
+ * in folders with names gen-<language>. The generated code isn't too scary
+ * to look at. It even has pretty indentation.
+ */
diff --git a/contrib/thrift.el b/contrib/thrift.el
index cd3e0e8..941a99f 100644
--- a/contrib/thrift.el
+++ b/contrib/thrift.el
@@ -1,4 +1,7 @@
-;;
+;;; thrift.el --- Major mode for Apache Thrift files
+
+;; Keywords: files
+
 ;; 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
@@ -17,9 +20,16 @@
 ;; under the License.
 ;;
 
+;;; Commentary:
+
+;;
+
+;;; Code:
+
 (require 'font-lock)
 
 (defvar thrift-mode-hook nil)
+;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.thrift\\'" . thrift-mode))
 
 (defvar thrift-indent-level 2
@@ -28,13 +38,12 @@
 ;; syntax coloring
 (defconst thrift-font-lock-keywords
   (list
-   '("#.*$" . font-lock-comment-face)  ;; perl style comments
    '("\\<\\(include\\|struct\\|exception\\|typedef\\|const\\|enum\\|service\\|extends\\|void\\|oneway\\|throws\\|optional\\|required\\)\\>" . font-lock-keyword-face)  ;; keywords
    '("\\<\\(bool\\|byte\\|i16\\|i32\\|i64\\|double\\|string\\|binary\\|map\\|list\\|set\\)\\>" . font-lock-type-face)  ;; built-in types
    '("\\<\\([0-9]+\\)\\>" . font-lock-variable-name-face)   ;; ordinals
    '("\\<\\(\\w+\\)\\s-*(" (1 font-lock-function-name-face))  ;; functions
    )
-  "Thrift Keywords")
+  "Thrift Keywords.")
 
 ;; indentation
 (defun thrift-indent-line ()
@@ -102,18 +111,20 @@
           (indent-line-to cur-indent)
         (indent-line-to 0)))))
 
-;; C/C++ comments; also allowing underscore in words
+;; C/C++- and sh-style comments; also allowing underscore in words
 (defvar thrift-mode-syntax-table
   (let ((thrift-mode-syntax-table (make-syntax-table)))
     (modify-syntax-entry ?_ "w" thrift-mode-syntax-table)
-    (modify-syntax-entry ?/ ". 1456" thrift-mode-syntax-table)
-    (modify-syntax-entry ?* ". 23" thrift-mode-syntax-table)
-    (modify-syntax-entry ?\n "> b" thrift-mode-syntax-table)
+    (modify-syntax-entry ?# "<" thrift-mode-syntax-table) ; sh-style comments
+    (modify-syntax-entry ?/ ". 124" thrift-mode-syntax-table) ; c/c++-style comments
+    (modify-syntax-entry ?* ". 23b" thrift-mode-syntax-table)
+    (modify-syntax-entry ?\n ">" thrift-mode-syntax-table)
     thrift-mode-syntax-table)
   "Syntax table for thrift-mode")
 
+;;;###autoload
 (defun thrift-mode ()
-  "Mode for editing Thrift files"
+  "Mode for editing Thrift files."
   (interactive)
   (kill-all-local-variables)
   (set-syntax-table thrift-mode-syntax-table)
@@ -123,4 +134,7 @@
   (run-hooks 'thrift-mode-hook)
   (set (make-local-variable 'indent-line-function) 'thrift-indent-line)
   )
-(provide 'thrift-mode)
+
+(provide 'thrift)
+;;; thrift.el ends here
+
diff --git a/contrib/thrift.spec b/contrib/thrift.spec
index d95a502..cc3c33c 100644
--- a/contrib/thrift.spec
+++ b/contrib/thrift.spec
@@ -17,6 +17,10 @@
 # under the License.
 #
 
+%define without_java 1
+%define without_python 1
+%define without_tests 1
+
 %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
 %{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
 
@@ -24,7 +28,7 @@
 License:        Apache License v2.0
 Group:          Development
 Summary:        RPC and serialization framework
-Version:        0.9.1
+Version:        1.0.0
 Release:        0
 URL:            http://thrift.apache.org
 Packager:       Thrift Developers <dev@thrift.apache.org>
@@ -42,6 +46,12 @@
 BuildRequires:  python-devel
 %endif
 
+%if 0%{!?without_ruby:1}
+%define gem_name %{name}
+BuildRequires:  ruby-devel
+BuildRequires:  rubygems-devel
+%endif
+
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
 %description
@@ -120,19 +130,68 @@
 %endif
 
 
+%if 0%{!?without_ruby:1}
+%package -n rubygem-%{gem_name}
+Summary: Thrift Ruby library
+Group:   Libraries
+Obsoletes: %{name}-lib-ruby
+
+%description -n rubygem-%{gem_name}
+Ruby libraries for Thrift.
+
+%files -n rubygem-%{gem_name}
+%defattr(-,root,root)
+%{gem_dir}/*
+%endif
+
+
+%if 0%{!?without_php:1}
+%package lib-php
+Summary: Thrift PHP library
+Group:   Libraries
+
+%description lib-php
+PHP libraries for Thrift.
+
+%files lib-php
+%defattr(-,root,root)
+/usr/lib/php/*
+%endif
+
+
 %prep
 %setup -q
 
 %build
+[[ -e Makefile.in ]] || ./bootstrap.sh
+export GEM_HOME=${PWD}/.gem-home
+export RUBYLIB=${PWD}/lib/rb/lib
 %configure \
   %{?without_libevent: --without-libevent } \
   %{?without_zlib:     --without-zlib     } \
-  --without-java \
+  %{?without_tests:    --without-tests    } \
+  %{?without_java:     --without-java     } \
+  %{?without_python:   --without-python   } \
+  %{?without_ruby:     --without-ruby     } \
+  %{?without_php:      --without-php      } \
+  %{!?without_php:     PHP_PREFIX=${RPM_BUILD_ROOT}/usr/lib/php } \
   --without-csharp \
-  --without-python \
   --without-erlang \
 
-make
+%if 0%{!?without_ruby:1}
+eval $(grep "^WITH_RUBY_TRUE" config.log)
+if [[ "${WITH_RUBY_TRUE}" != "" ]]; then
+  set +x
+  echo ""
+  echo "configure determined that ruby requirements are missing (bundler gem?), either install missing components" >&2
+  echo "or disable the ruby sub-packages as follows:"                                                              >&2
+  echo "     rpmbuild -D'%without_ruby 1' ..."                                                                     >&2
+  echo ""
+  exit 1
+fi
+%endif
+
+make %{?_smp_mflags}
 
 %if 0%{!?without_java:1}
 cd lib/java
@@ -146,7 +205,13 @@
 cd ../..
 %endif
 
+%if 0%{!?without_ruby:1}
+%gem_install -n lib/rb/thrift*.gem
+%endif
+
 %install
+export GEM_HOME=${PWD}/.gem-home
+export RUBYLIB=${PWD}/lib/rb/lib
 %makeinstall
 ln -s libthrift-%{version}.so ${RPM_BUILD_ROOT}%{_libdir}/libthrift.so.0
 ln -s libthriftnb-%{version}.so ${RPM_BUILD_ROOT}%{_libdir}/libthriftnb.so.0
@@ -154,7 +219,7 @@
 
 %if 0%{!?without_java:1}
 mkdir -p $RPM_BUILD_ROOT%{_javadir}
-cp -p lib/java/*.jar $RPM_BUILD_ROOT%{_javadir}
+cp -p lib/java/build/*.jar $RPM_BUILD_ROOT%{_javadir}
 %endif
 
 %if 0%{!?without_python:1}
@@ -163,6 +228,10 @@
 cd ../..
 %endif
 
+%if 0%{!?without_ruby:1}
+mkdir -p %{buildroot}%{gem_dir}
+cp -a ./%{gem_dir}/* %{buildroot}%{gem_dir}/
+%endif
 
 %clean
 rm -rf ${RPM_BUILD_ROOT}
diff --git a/contrib/thrift.vim b/contrib/thrift.vim
index 79ce547..6231955 100644
--- a/contrib/thrift.vim
+++ b/contrib/thrift.vim
@@ -51,8 +51,8 @@
 syn keyword thriftKeyword namespace
 syn keyword thriftKeyword xsd_all xsd_optional xsd_nillable xsd_attrs
 syn keyword thriftKeyword include cpp_include cpp_type const optional required
-syn keyword thriftBasicTypes void bool byte i16 i32 i64 double string binary
-syn keyword thriftStructure map list set struct typedef exception enum throws
+syn keyword thriftBasicTypes void bool byte i8 i16 i32 i64 double string binary
+syn keyword thriftStructure map list set struct typedef exception enum throws union
 
 " Special
 syn match thriftSpecial "\d\+:"
diff --git a/contrib/transport-sample/README.txt b/contrib/transport-sample/README.md
similarity index 100%
rename from contrib/transport-sample/README.txt
rename to contrib/transport-sample/README.md
diff --git a/contrib/transport-sample/ThriftCommon.h b/contrib/transport-sample/ThriftCommon.h
index d24d1a7..e16d87d 100644
--- a/contrib/transport-sample/ThriftCommon.h
+++ b/contrib/transport-sample/ThriftCommon.h
@@ -16,8 +16,6 @@
 //
 
 #ifdef _WIN32 //thrift is crashing when using boost threads on Mac OSX
-#  define USE_BOOST_THREAD 1
-#  include <boost/thread.hpp>
 #else
 #  include <sys/socket.h>
 #  include <netinet/in.h>
diff --git a/contrib/vagrant/centos-6.5/README.md b/contrib/vagrant/centos-6.5/README.md
new file mode 100644
index 0000000..55583f9
--- /dev/null
+++ b/contrib/vagrant/centos-6.5/README.md
@@ -0,0 +1,61 @@
+Apache Thrift Centos 6.5 Vagrant Support
+========================================
+This directory is the Vagrant project directory for Apache Thrift running on Centos 6.5. The Vagrantfile in this directory configures a Vagrant provisioned VM launched under VirtualBox. To use this project you must have a recent version of VirtualBox and Vagrant installed (in that order). To run the VM, open a shell, clone Apache Thrift, change to this directory and enter the Vagrant up command.
+
+   $ git clone https://github.com/apache/thrift
+   $ cd thrift/contrib/vagrant/centos-6.5
+   $ vagrant up
+
+This will download and launch the base box VM under VirtualBox and run the Apache Thrift provisioning script. This will take up to an hour depending on your hardware and network. Once complete you can login to the box with Vagrant ssh. The thrift source tree from your host os is mounted at /thrift.
+
+   $ vagrant ssh
+   [vagrant@thrift ~]$ cd /thrift
+   [vagrant@thrift thrift]$ compiler/cpp/thrift --version
+   Thrift version <version>
+
+The provisioning script (inside the Vagrantfile) runs ./bootstrap.sh, ./configure, make and make check, but does not install thrift. To install thrift run "make install".
+
+The Vagrant base box used here is a minimal Centos 6.5 VirtualBox with 2GB RAM and 2 CPUs. For more Vagrant information: https://www.vagrantup.com. A summary of the base box preparation follows:
+
+root password: vagrant
+
+#Create the vagrant user and give it sudo permission
+adduser vagrant
+passwd vagrant
+visudo  :  vagrant ALL=(ALL) NOPASSWD: ALL
+           #Defaults requiretty
+
+#Shut down the firewall and disable it
+service iptables stop
+chkconfig iptables off
+
+#Setup the vagrant ssh public key to allow vagrant to ssh
+mkdir /home/vagrant/.ssh
+chmod 700 /home/vagrant/.ssh
+cd /home/vagrant/.ssh
+wget --no-check-certificate 'https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub' -O authorized_keys
+chmod 600 /home/vagrant/.ssh/authorized_keys
+chown -R vagrant /home/vagrant/.ssh
+
+#Install EPEL (Extra Packages for Enterprise Linux) but protect the base
+#repositories so that EPEL does not mask base packages
+yum -y install yum-plugin-protectbase
+rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
+
+#Install perl, dynamic kernel modules, dev tools and kernel headers to support
+#Virtual box additions
+yum -y install perl
+yum -y --enablerepo epel install dkms
+yum -y groupinstall "Development Tools"
+yum -y install kernel-devel
+
+#Update everything and reboot
+yum update
+reboot
+
+#Install the VirtualBox Guest additions (using VirtualBox iso)
+mount /dev/cdrom /mnt
+/mnt/VBoxLinuxAdditions.run
+umount /mnt
+
+See the Vagrantfile for further details
diff --git a/contrib/vagrant/centos-6.5/Vagrantfile b/contrib/vagrant/centos-6.5/Vagrantfile
new file mode 100644
index 0000000..51a2239
--- /dev/null
+++ b/contrib/vagrant/centos-6.5/Vagrantfile
@@ -0,0 +1,274 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# 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.
+
+# APACHE THRIFT PROVISIONING SCRIPT
+##############################################################
+# This script is used to configure the base Centos 6.5
+# Vagrant box for Apache Thrift compiler and lib builds.
+# The base box is Centos 6.5 with no additional packages
+# except those required to support VirtualBox Guest tools:
+# perl, dkms, kernel-devel and the "Development Tools" group.
+# The epel repo was also added along with the
+# yum-plugin-protectbase package to prefer base repo packages.
+# The script below provisions ALL languages. This will take
+# time. You can greatly reduce the build time by commenting
+# out the LIB provisioning for uneeded language libraries.
+# Expect full provisioning to take 30 minutes on a fast
+# machine with an excellent Internet connection (and another
+# 15 minutes for the build).
+#
+# Machine accounts:
+# - User: vagrant/vagrant
+# - Admin: root/vagrant
+# Vagrant public ssh key also installed
+##############################################################
+
+$build_and_test = <<SCRIPT
+echo "Provisioning system to compile and test Apache Thrift."
+date > /etc/vagrant.provision_begin
+
+# Apache Thrift compiler dependencies
+#####################################
+
+#install an updated autoconf
+wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
+tar xvf autoconf-2.69.tar.gz
+cd autoconf-2.69
+./configure --prefix=/usr
+make
+sudo make install
+cd ..
+
+#install an updated automake
+wget http://ftp.gnu.org/gnu/automake/automake-1.14.tar.gz
+tar xvf automake-1.14.tar.gz
+cd automake-1.14
+./configure --prefix=/usr
+make
+sudo make install
+cd ..
+
+#install an updated bison
+wget http://ftp.gnu.org/gnu/bison/bison-2.5.1.tar.gz
+tar xvf bison-2.5.1.tar.gz
+cd bison-2.5.1
+./configure --prefix=/usr
+make
+sudo make install
+cd ..
+
+# C++98 LIB Dependencies
+#####################################
+sudo yum -y install libevent-devel zlib-devel openssl-devel
+
+#Install an updated Boost library
+wget http://sourceforge.net/projects/boost/files/boost/1.55.0/boost_1_55_0.tar.gz
+tar xvf boost_1_55_0.tar.gz
+cd boost_1_55_0
+./bootstrap.sh
+sudo ./b2 install
+
+# Java LIB Dependencies
+#####################################
+sudo yum install -y ant junit ant-nodeps ant-junit java-1.8.0-openjdk-devel
+
+# Python LIB Dependencies
+#####################################
+sudo yum install -y python-devel python-setuptools python-twisted
+
+# Ruby LIB Dependencies
+#####################################
+sudo yum install -y ruby ruby-devel rubygems
+sudo gem install bundler rake
+
+# Node.js LIB Dependencies
+#####################################
+sudo yum install -y nodejs nodejs-devel npm
+
+# Perl LIB Dependencies
+#####################################
+sudo yum install -y perl-Bit-Vector perl-Class-Accessor perl-ExtUtils-MakeMaker perl-Test-Simple
+
+# PHP LIB Dependencies
+#####################################
+sudo yum install -y php php-devel php-pear re2c
+
+# GLibC LIB Dependencies
+#####################################
+sudo yum install -y glib2-devel
+
+# Erlang LIB Dependencies
+#####################################
+sudo yum install -y erlang-kernel erlang-erts erlang-stdlib erlang-eunit erlang-rebar
+
+# Lua LIB Dependencies
+#####################################
+sudo yum install -y lua-devel
+
+# Go LIB Dependencies
+#####################################
+sudo yum install -y golang golang-pkg-linux-amd64
+
+# C# LIB Dependencies
+#####################################
+sudo yum install -y mono-core mono-devel mono-web-devel mono-extras mingw32-binutils mingw32-runtime mingw32-nsis
+
+# Haskell LIB Dependencies
+#####################################
+wget http://sherkin.justhub.org/el6/RPMS/x86_64/justhub-release-2.0-4.0.el6.x86_64.rpm
+sudo rpm -ivh justhub-release-2.0-4.0.el6.x86_64.rpm
+sudo yum -y install haskell
+sudo cabal update
+sudo cabal install cabal-install
+
+# Build and Test Apache Thrift
+#####################################
+date > /etc/vagrant.provision_end
+echo "Starting Apache Thrift build..."
+cd /thrift
+sh bootstrap.sh
+
+# At the time of this file's creation Ruby, Python, Go and Lua fail
+# their unit tests in this environment. To build and test any of these
+# libraries uncomment the appropriate --without switches below.
+
+sh configure --without-ruby --without-go --without-lua --without-python
+make
+echo "Starting Apache Thrift tests..."
+make check
+echo "Finished building and testing Apache Thrift."
+echo 'Use "make install" to install the compiler and libraries.'
+date > /etc/vagrant.make_end
+
+SCRIPT
+
+Vagrant.configure("2") do |config|
+  # Every Vagrant virtual environment requires a box to build off of.
+  ##### Centos 6.5 minimal system with VirtualBox Guest Additions
+  ##### Box maintained by ra@apache.org, see README.md for box config
+  config.vm.box = "RandyAbernethy/thrift-centos-6.5-64"
+
+  # Disable automatic box update checking. If you disable this, then
+  # boxes will only be checked for updates when the user runs
+  # `vagrant box outdated`. This is not recommended.
+  ##### This box will never change
+  config.vm.box_check_update = false
+
+  # Create a forwarded port mapping which allows access to a specific port
+  # within the machine from a port on the host machine. In the example below,
+  # accessing "localhost:8080" will access port 80 on the guest machine.
+  # config.vm.network "forwarded_port", guest: 80, host: 8080
+
+  # Create a private network, which allows host-only access to the machine
+  # using a specific IP.
+  # config.vm.network "private_network", ip: "192.168.33.10"
+
+  # Create a public network, which generally matched to bridged network.
+  # Bridged networks make the machine appear as another physical device on
+  # your network.
+  # config.vm.network "public_network"
+
+  # If true, then any SSH connections made will enable agent forwarding.
+  # Default value: false
+  # config.ssh.forward_agent = true
+
+  # Share an additional folder to the guest VM. The first argument is
+  # the path on the host to the actual folder. The second argument is
+  # the path on the guest to mount the folder. And the optional third
+  # argument is a set of non-required options.
+  # config.vm.synced_folder "../data", "/vagrant_data"
+  ##### By convention the thrift source tree is mapped to /thrift
+  config.vm.synced_folder "../../../", "/thrift"
+
+  # Provider-specific configuration so you can fine-tune various
+  # backing providers for Vagrant. These expose provider-specific options.
+  ##### The machine needs 2 CPUs and 2GB RAM for reasonable performance
+  config.vm.provider "virtualbox" do |vb|
+    vb.customize ["modifyvm", :id, "--memory", "2048"]
+    vb.customize ["modifyvm", :id, "--cpus", "2"]
+  end
+
+  # Enable provisioning with CFEngine. CFEngine Community packages are
+  # automatically installed. For example, configure the host as a
+  # policy server and optionally a policy file to run:
+  #
+  # config.vm.provision "cfengine" do |cf|
+  #   cf.am_policy_hub = true
+  #   # cf.run_file = "motd.cf"
+  # end
+  #
+  # You can also configure and bootstrap a client to an existing
+  # policy server:
+  #
+  # config.vm.provision "cfengine" do |cf|
+  #   cf.policy_server_address = "10.0.2.15"
+  # end
+
+  # Enable provisioning with Puppet stand alone.  Puppet manifests
+  # are contained in a directory path relative to this Vagrantfile.
+  # You will need to create the manifests directory and a manifest in
+  # the file default.pp in the manifests_path directory.
+  #
+  # config.vm.provision "puppet" do |puppet|
+  #   puppet.manifests_path = "manifests"
+  #   puppet.manifest_file  = "default.pp"
+  # end
+
+  # Enable provisioning with chef solo, specifying a cookbooks path, roles
+  # path, and data_bags path (all relative to this Vagrantfile), and adding
+  # some recipes and/or roles.
+  #
+  # config.vm.provision "chef_solo" do |chef|
+  #   chef.cookbooks_path = "../my-recipes/cookbooks"
+  #   chef.roles_path = "../my-recipes/roles"
+  #   chef.data_bags_path = "../my-recipes/data_bags"
+  #   chef.add_recipe "mysql"
+  #   chef.add_role "web"
+  #
+  #   # You may also specify custom JSON attributes:
+  #   chef.json = { mysql_password: "foo" }
+  # end
+
+  # Enable provisioning with chef server, specifying the chef server URL,
+  # and the path to the validation key (relative to this Vagrantfile).
+  #
+  # The Opscode Platform uses HTTPS. Substitute your organization for
+  # ORGNAME in the URL and validation key.
+  #
+  # If you have your own Chef Server, use the appropriate URL, which may be
+  # HTTP instead of HTTPS depending on your configuration. Also change the
+  # validation key to validation.pem.
+  #
+  # config.vm.provision "chef_client" do |chef|
+  #   chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
+  #   chef.validation_key_path = "ORGNAME-validator.pem"
+  # end
+  #
+  # If you're using the Opscode platform, your validator client is
+  # ORGNAME-validator, replacing ORGNAME with your organization name.
+  #
+  # If you have your own Chef Server, the default validation client name is
+  # chef-validator, unless you changed the configuration.
+  #
+  #   chef.validation_client_name = "ORGNAME-validator"
+
+  ##### Run the Apache Thrift provisioning script (declared above)
+  config.vm.provision :shell, :inline => $build_and_test
+end
diff --git a/contrib/zeromq/Makefile b/contrib/zeromq/Makefile
index a1d7156..ee398e2 100644
--- a/contrib/zeromq/Makefile
+++ b/contrib/zeromq/Makefile
@@ -1,6 +1,4 @@
 THRIFT = thrift
-CXXFLAGS = `pkg-config --cflags libzmq thrift`
-LDLIBS = `pkg-config --libs libzmq thrift`
 
 CXXFLAGS += -g3 -O0
 
@@ -16,15 +14,19 @@
 all: $(PYLIBS) $(PROGS)
 
 test-client: test-client.o TZmqClient.o $(GENOBJS)
+	$(CXX) $^ -o $@ -lzmq -lthrift
 test-server: test-server.o TZmqServer.o $(GENOBJS)
+	$(CXX) $^ -o $@ -lzmq -lthrift
 test-sender: test-sender.o TZmqClient.o $(GENOBJS)
+	$(CXX) $^ -o $@ -lzmq -lthrift
 test-receiver: test-receiver.o TZmqServer.o $(GENOBJS)
+	$(CXX) $^ -o $@ -lzmq -lthrift
 
 test-client.o test-server.o test-sender.o test-receiver.o: $(GENSRCS)
 
 storage/__init__.py: storage.thrift
 	$(RM) $(dir $@)
-	$(THRIFT) --gen py:newstyle $<
+	$(THRIFT) --gen py $<
 	mv gen-py/$(dir $@) .
 
 $(GENSRCS): storage.thrift
diff --git a/contrib/zeromq/README b/contrib/zeromq/README.md
similarity index 100%
rename from contrib/zeromq/README
rename to contrib/zeromq/README.md
diff --git a/contrib/zeromq/TZmqClient.cpp b/contrib/zeromq/TZmqClient.cpp
index 133204e..56278f3 100644
--- a/contrib/zeromq/TZmqClient.cpp
+++ b/contrib/zeromq/TZmqClient.cpp
@@ -22,7 +22,7 @@
 
 namespace apache { namespace thrift { namespace transport {
 
-uint32_t TZmqClient::read(uint8_t* buf, uint32_t len) {
+uint32_t TZmqClient::read_virt(uint8_t* buf, uint32_t len) {
   if (rbuf_.available_read() == 0) {
     (void)sock_.recv(&msg_);
     rbuf_.resetBuffer((uint8_t*)msg_.data(), msg_.size());
@@ -30,11 +30,11 @@
   return rbuf_.read(buf, len);
 }
 
-void TZmqClient::write(const uint8_t* buf, uint32_t len) {
+void TZmqClient::write_virt(const uint8_t* buf, uint32_t len) {
   return wbuf_.write(buf, len);
 }
 
-void TZmqClient::writeEnd() {
+uint32_t TZmqClient::writeEnd() {
   uint8_t* buf;
   uint32_t size;
   wbuf_.getBuffer(&buf, &size);
@@ -42,6 +42,7 @@
   std::memcpy(msg.data(), buf, size);
   (void)sock_.send(msg);
   wbuf_.resetBuffer(true);
+  return size;
 }
 
 }}} // apache::thrift::transport
diff --git a/contrib/zeromq/TZmqClient.h b/contrib/zeromq/TZmqClient.h
index 9fcfc06..df16e03 100644
--- a/contrib/zeromq/TZmqClient.h
+++ b/contrib/zeromq/TZmqClient.h
@@ -45,15 +45,15 @@
     }
   }
 
-  uint32_t read(uint8_t* buf, uint32_t len);
+  uint32_t read_virt(uint8_t* buf, uint32_t len);
 
-  void write(const uint8_t* buf, uint32_t len);
+  void write_virt(const uint8_t* buf, uint32_t len);
 
-  void writeEnd();
+  uint32_t writeEnd();
 
  protected:
-  std::string endpoint_;
   zmq::socket_t sock_;
+  std::string endpoint_;
   TMemoryBuffer wbuf_;
   TMemoryBuffer rbuf_;
   zmq::message_t msg_;
diff --git a/contrib/zeromq/TZmqClient.py b/contrib/zeromq/TZmqClient.py
index d560697..1bd60a1 100644
--- a/contrib/zeromq/TZmqClient.py
+++ b/contrib/zeromq/TZmqClient.py
@@ -20,44 +20,45 @@
 from cStringIO import StringIO
 from thrift.transport.TTransport import TTransportBase, CReadableTransport
 
+
 class TZmqClient(TTransportBase, CReadableTransport):
-  def __init__(self, ctx, endpoint, sock_type):
-    self._sock = ctx.socket(sock_type)
-    self._endpoint = endpoint
-    self._wbuf = StringIO()
-    self._rbuf = StringIO()
+    def __init__(self, ctx, endpoint, sock_type):
+        self._sock = ctx.socket(sock_type)
+        self._endpoint = endpoint
+        self._wbuf = StringIO()
+        self._rbuf = StringIO()
 
-  def open(self):
-    self._sock.connect(self._endpoint)
+    def open(self):
+        self._sock.connect(self._endpoint)
 
-  def read(self, size):
-    ret = self._rbuf.read(size)
-    if len(ret) != 0:
-      return ret
-    self._read_message()
-    return self._rbuf.read(size)
+    def read(self, size):
+        ret = self._rbuf.read(size)
+        if len(ret) != 0:
+            return ret
+        self._read_message()
+        return self._rbuf.read(size)
 
-  def _read_message(self):
-    msg = self._sock.recv()
-    self._rbuf = StringIO(msg)
+    def _read_message(self):
+        msg = self._sock.recv()
+        self._rbuf = StringIO(msg)
 
-  def write(self, buf):
-    self._wbuf.write(buf)
+    def write(self, buf):
+        self._wbuf.write(buf)
 
-  def flush(self):
-    msg = self._wbuf.getvalue()
-    self._wbuf = StringIO()
-    self._sock.send(msg)
+    def flush(self):
+        msg = self._wbuf.getvalue()
+        self._wbuf = StringIO()
+        self._sock.send(msg)
 
-  # Implement the CReadableTransport interface.
-  @property
-  def cstringio_buf(self):
-    return self._rbuf
+    # Implement the CReadableTransport interface.
+    @property
+    def cstringio_buf(self):
+        return self._rbuf
 
-  # NOTE: This will probably not actually work.
-  def cstringio_refill(self, prefix, reqlen):
-    while len(prefix) < reqlen:
-      self.read_message()
-      prefix += self._rbuf.getvalue()
-    self._rbuf = StringIO(prefix)
-    return self._rbuf
+    # NOTE: This will probably not actually work.
+    def cstringio_refill(self, prefix, reqlen):
+        while len(prefix) < reqlen:
+            self.read_message()
+            prefix += self._rbuf.getvalue()
+        self._rbuf = StringIO(prefix)
+        return self._rbuf
diff --git a/contrib/zeromq/TZmqServer.cpp b/contrib/zeromq/TZmqServer.cpp
index f255a66..88660a3 100644
--- a/contrib/zeromq/TZmqServer.cpp
+++ b/contrib/zeromq/TZmqServer.cpp
@@ -21,13 +21,12 @@
 #include <thrift/transport/TBufferTransports.h>
 #include <boost/scoped_ptr.hpp>
 
-using boost::shared_ptr;
+using apache::thrift::std::shared_ptr;
 using apache::thrift::transport::TMemoryBuffer;
 using apache::thrift::protocol::TProtocol;
 
 namespace apache { namespace thrift { namespace server {
 
-
 bool TZmqServer::serveOne(int recv_flags) {
   zmq::message_t msg;
   bool received = sock_.recv(&msg, recv_flags);
@@ -40,8 +39,9 @@
       inputProtocolFactory_->getProtocol(inputTransport));
   shared_ptr<TProtocol> outputProtocol(
       outputProtocolFactory_->getProtocol(outputTransport));
+  shared_ptr<TMemoryBuffer> transport(new TMemoryBuffer);
 
-  processor_->process(inputProtocol, outputProtocol);
+  processor_->process(inputProtocol, outputProtocol, NULL);
 
   if (zmq_type_ == ZMQ_REP) {
     uint8_t* buf;
diff --git a/contrib/zeromq/TZmqServer.h b/contrib/zeromq/TZmqServer.h
index f91c6e8..ecd13b4 100644
--- a/contrib/zeromq/TZmqServer.h
+++ b/contrib/zeromq/TZmqServer.h
@@ -20,6 +20,7 @@
 #ifndef _THRIFT_SERVER_TZMQSERVER_H_
 #define _THRIFT_SERVER_TZMQSERVER_H_ 1
 
+#include <memory>
 #include <zmq.hpp>
 #include <thrift/server/TServer.h>
 
@@ -28,9 +29,10 @@
 class TZmqServer : public TServer {
  public:
   TZmqServer(
-      boost::shared_ptr<TProcessor> processor,
+      std::shared_ptr<TProcessor> processor,
       zmq::context_t& ctx, const std::string& endpoint, int type)
     : TServer(processor)
+    , processor_(processor)
     , zmq_type_(type)
     , sock_(ctx, type)
   {
@@ -55,6 +57,7 @@
   }
 
  private:
+  std::shared_ptr<TProcessor> processor_;
   int zmq_type_;
   zmq::socket_t sock_;
 };
diff --git a/contrib/zeromq/TZmqServer.py b/contrib/zeromq/TZmqServer.py
index c83cc8d..15c1543 100644
--- a/contrib/zeromq/TZmqServer.py
+++ b/contrib/zeromq/TZmqServer.py
@@ -21,58 +21,59 @@
 import thrift.server.TServer
 import thrift.transport.TTransport
 
+
 class TZmqServer(thrift.server.TServer.TServer):
-  def __init__(self, processor, ctx, endpoint, sock_type):
-    thrift.server.TServer.TServer.__init__(self, processor, None)
-    self.zmq_type = sock_type
-    self.socket = ctx.socket(sock_type)
-    self.socket.bind(endpoint)
+    def __init__(self, processor, ctx, endpoint, sock_type):
+        thrift.server.TServer.TServer.__init__(self, processor, None)
+        self.zmq_type = sock_type
+        self.socket = ctx.socket(sock_type)
+        self.socket.bind(endpoint)
 
-  def serveOne(self):
-    msg = self.socket.recv()
-    itrans = thrift.transport.TTransport.TMemoryBuffer(msg)
-    otrans = thrift.transport.TTransport.TMemoryBuffer()
-    iprot = self.inputProtocolFactory.getProtocol(itrans)
-    oprot = self.outputProtocolFactory.getProtocol(otrans)
+    def serveOne(self):
+        msg = self.socket.recv()
+        itrans = thrift.transport.TTransport.TMemoryBuffer(msg)
+        otrans = thrift.transport.TTransport.TMemoryBuffer()
+        iprot = self.inputProtocolFactory.getProtocol(itrans)
+        oprot = self.outputProtocolFactory.getProtocol(otrans)
 
-    try:
-      self.processor.process(iprot, oprot)
-    except Exception:
-      logging.exception("Exception while processing request")
-      # Fall through and send back a response, even if empty or incomplete.
+        try:
+            self.processor.process(iprot, oprot)
+        except Exception:
+            logging.exception("Exception while processing request")
+            # Fall through and send back a response, even if empty or incomplete.
 
-    if self.zmq_type == zmq.REP:
-      msg = otrans.getvalue()
-      self.socket.send(msg)
+        if self.zmq_type == zmq.REP:
+            msg = otrans.getvalue()
+            self.socket.send(msg)
 
-  def serve(self):
-    while True:
-      self.serveOne()
+    def serve(self):
+        while True:
+            self.serveOne()
 
 
 class TZmqMultiServer(object):
-  def __init__(self):
-    self.servers = []
+    def __init__(self):
+        self.servers = []
 
-  def serveOne(self, timeout = -1):
-    self._serveActive(self._setupPoll(), timeout)
+    def serveOne(self, timeout=-1):
+        self._serveActive(self._setupPoll(), timeout)
 
-  def serveForever(self):
-    poll_info = self._setupPoll()
-    while True:
-      self._serveActive(poll_info, -1)
+    def serveForever(self):
+        poll_info = self._setupPoll()
+        while True:
+            self._serveActive(poll_info, -1)
 
-  def _setupPoll(self):
-    server_map = {}
-    poller = zmq.Poller()
-    for server in self.servers:
-      server_map[server.socket] = server
-      poller.register(server.socket, zmq.POLLIN)
-    return (server_map, poller)
+    def _setupPoll(self):
+        server_map = {}
+        poller = zmq.Poller()
+        for server in self.servers:
+            server_map[server.socket] = server
+            poller.register(server.socket, zmq.POLLIN)
+        return (server_map, poller)
 
-  def _serveActive(self, poll_info, timeout):
-    (server_map, poller) = poll_info
-    ready = dict(poller.poll())
-    for sock, state in ready.items():
-      assert (state & zmq.POLLIN) != 0
-      server_map[sock].serveOne()
+    def _serveActive(self, poll_info, timeout):
+        (server_map, poller) = poll_info
+        ready = dict(poller.poll())
+        for sock, state in ready.items():
+            assert (state & zmq.POLLIN) != 0
+            server_map[sock].serveOne()
diff --git a/contrib/zeromq/csharp/AssemblyInfo.cs b/contrib/zeromq/csharp/AssemblyInfo.cs
index 9ad48c6..12cd434 100644
--- a/contrib/zeromq/csharp/AssemblyInfo.cs
+++ b/contrib/zeromq/csharp/AssemblyInfo.cs
@@ -14,20 +14,20 @@
  * "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.

- */

+ * under the License.
+ */
 
 using System.Reflection;
 using System.Runtime.CompilerServices;
 
-// Information about this assembly is defined by the following attributes. 
+// Information about this assembly is defined by the following attributes.
 // Change them to the values specific to your project.
 
 [assembly: AssemblyTitle("ZmqServer")]
 [assembly: AssemblyDescription("Zmq Examples")]
-[assembly: AssemblyConfiguration("")]

+[assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("The Apache Software Foundation")]
-[assembly: AssemblyProduct("")]

+[assembly: AssemblyProduct("")]
 [assembly: AssemblyCopyright("The Apache Software Foundation")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
@@ -38,7 +38,7 @@
 
 [assembly: AssemblyVersion("1.0.*")]
 
-// The following attributes are used to specify the signing key for the assembly, 
+// The following attributes are used to specify the signing key for the assembly,
 // if desired. See the Mono documentation for more information about signing.
 
 //[assembly: AssemblyDelaySign(false)]
diff --git a/contrib/zeromq/csharp/TZmqClient.cs b/contrib/zeromq/csharp/TZmqClient.cs
index c792882..e9ab516 100644
--- a/contrib/zeromq/csharp/TZmqClient.cs
+++ b/contrib/zeromq/csharp/TZmqClient.cs
@@ -47,7 +47,7 @@
 				throw new NotImplementedException ();
 
 			if (_rbuf.Length == 0) {
-				//Fill the Buffer with the complete ZMQ Message which needs to be(?!) the complete Thrift reponse
+				//Fill the Buffer with the complete ZMQ Message which needs to be(?!) the complete Thrift response
 				debug ("Client_Read Filling buffer..");
 				byte[] tmpBuf = _sock.Recv ();
 				debug (string.Format("Client_Read filled with {0}b",tmpBuf.Length));
diff --git a/contrib/zeromq/csharp/ThriftZMQ.csproj b/contrib/zeromq/csharp/ThriftZMQ.csproj
index 1d5f13c..80ad1db 100755
--- a/contrib/zeromq/csharp/ThriftZMQ.csproj
+++ b/contrib/zeromq/csharp/ThriftZMQ.csproj
@@ -1,91 +1,91 @@
-<?xml version="1.0" encoding="utf-8"?>

-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

-  <PropertyGroup>

-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

-    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>

-    <ProductVersion>9.0.21022</ProductVersion>

-    <SchemaVersion>2.0</SchemaVersion>

-    <ProjectGuid>{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}</ProjectGuid>

-    <OutputType>Exe</OutputType>

-    <RootNamespace>ZmqServer</RootNamespace>

-    <AssemblyName>ThriftZMQ</AssemblyName>

-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>

-    <FileUpgradeFlags>

-    </FileUpgradeFlags>

-    <OldToolsVersion>3.5</OldToolsVersion>

-    <UpgradeBackupLocation />

-    <PublishUrl>publish\</PublishUrl>

-    <Install>true</Install>

-    <InstallFrom>Disk</InstallFrom>

-    <UpdateEnabled>false</UpdateEnabled>

-    <UpdateMode>Foreground</UpdateMode>

-    <UpdateInterval>7</UpdateInterval>

-    <UpdateIntervalUnits>Days</UpdateIntervalUnits>

-    <UpdatePeriodically>false</UpdatePeriodically>

-    <UpdateRequired>false</UpdateRequired>

-    <MapFileExtensions>true</MapFileExtensions>

-    <ApplicationRevision>0</ApplicationRevision>

-    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>

-    <IsWebBootstrapper>false</IsWebBootstrapper>

-    <UseApplicationTrust>false</UseApplicationTrust>

-    <BootstrapperEnabled>true</BootstrapperEnabled>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">

-    <DebugSymbols>true</DebugSymbols>

-    <DebugType>full</DebugType>

-    <Optimize>false</Optimize>

-    <OutputPath>bin\Debug</OutputPath>

-    <DefineConstants>DEBUG</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <PlatformTarget>x86</PlatformTarget>

-    <Externalconsole>true</Externalconsole>

-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">

-    <DebugType>none</DebugType>

-    <Optimize>false</Optimize>

-    <OutputPath>bin\Release</OutputPath>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <PlatformTarget>x86</PlatformTarget>

-    <Externalconsole>true</Externalconsole>

-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>

-  </PropertyGroup>

-  <ItemGroup>

-    <Reference Include="clrzmq, Version=2.1.0.0, Culture=neutral, processorArchitecture=x86">

-      <SpecificVersion>False</SpecificVersion>

-      <HintPath>.\clrzmq.dll</HintPath>

-    </Reference>

-    <Reference Include="System" />

-    <Reference Include="Thrift, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">

-      <SpecificVersion>False</SpecificVersion>

-      <HintPath>..\..\..\lib\csharp\Thrift.dll</HintPath>

-    </Reference>

-  </ItemGroup>

-  <ItemGroup>

-    <Compile Include="Main.cs" />

-    <Compile Include="AssemblyInfo.cs" />

-    <Compile Include="TZmqServer.cs" />

-    <Compile Include="TZmqClient.cs" />

-    <Compile Include="..\gen-csharp\Storage.cs" />

-  </ItemGroup>

-  <ItemGroup>

-    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">

-      <Visible>False</Visible>

-      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>

-      <Install>false</Install>

-    </BootstrapperPackage>

-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">

-      <Visible>False</Visible>

-      <ProductName>.NET Framework 3.5 SP1</ProductName>

-      <Install>true</Install>

-    </BootstrapperPackage>

-    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">

-      <Visible>False</Visible>

-      <ProductName>Windows Installer 3.1</ProductName>

-      <Install>true</Install>

-    </BootstrapperPackage>

-  </ItemGroup>

-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

-</Project>
\ No newline at end of file
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>ZmqServer</RootNamespace>
+    <AssemblyName>ThriftZMQ</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.0</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <Externalconsole>true</Externalconsole>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>none</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <Externalconsole>true</Externalconsole>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="clrzmq, Version=2.1.0.0, Culture=neutral, processorArchitecture=x86">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>.\clrzmq.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="Thrift, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\lib\csharp\Thrift.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Main.cs" />
+    <Compile Include="AssemblyInfo.cs" />
+    <Compile Include="TZmqServer.cs" />
+    <Compile Include="TZmqClient.cs" />
+    <Compile Include="..\gen-csharp\Storage.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project>
diff --git a/contrib/zeromq/csharp/ThriftZMQ.sln b/contrib/zeromq/csharp/ThriftZMQ.sln
index 404a747..6af57b6 100755
--- a/contrib/zeromq/csharp/ThriftZMQ.sln
+++ b/contrib/zeromq/csharp/ThriftZMQ.sln
@@ -1,42 +1,42 @@
-

-Microsoft Visual Studio Solution File, Format Version 11.00

-# Visual Studio 2010

-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftZMQ", "ThriftZMQ.csproj", "{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}"

-EndProject

-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\..\lib\csharp\src\Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}"

-EndProject

-Global

-	GlobalSection(SolutionConfigurationPlatforms) = preSolution

-		Debug|Any CPU = Debug|Any CPU

-		Debug|Mixed Platforms = Debug|Mixed Platforms

-		Debug|x86 = Debug|x86

-		Release|Any CPU = Release|Any CPU

-		Release|Mixed Platforms = Release|Mixed Platforms

-		Release|x86 = Release|x86

-	EndGlobalSection

-	GlobalSection(ProjectConfigurationPlatforms) = postSolution

-		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|Any CPU.ActiveCfg = Debug|x86

-		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|Mixed Platforms.ActiveCfg = Debug|x86

-		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|Mixed Platforms.Build.0 = Debug|x86

-		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|x86.ActiveCfg = Debug|x86

-		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|x86.Build.0 = Debug|x86

-		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|Any CPU.ActiveCfg = Release|x86

-		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|Mixed Platforms.ActiveCfg = Release|x86

-		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|Mixed Platforms.Build.0 = Release|x86

-		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|x86.ActiveCfg = Release|x86

-		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|x86.Build.0 = Release|x86

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|x86.ActiveCfg = Debug|Any CPU

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Mixed Platforms.Build.0 = Release|Any CPU

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|x86.ActiveCfg = Release|Any CPU

-	EndGlobalSection

-	GlobalSection(SolutionProperties) = preSolution

-		HideSolutionNode = FALSE

-	EndGlobalSection

-EndGlobal

+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftZMQ", "ThriftZMQ.csproj", "{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\..\lib\csharp\src\Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|Mixed Platforms = Debug|Mixed Platforms
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|Mixed Platforms = Release|Mixed Platforms
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|Mixed Platforms.Build.0 = Debug|x86
+		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|x86.ActiveCfg = Debug|x86
+		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|x86.Build.0 = Debug|x86
+		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|Any CPU.ActiveCfg = Release|x86
+		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|Mixed Platforms.ActiveCfg = Release|x86
+		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|Mixed Platforms.Build.0 = Release|x86
+		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|x86.ActiveCfg = Release|x86
+		{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|x86.Build.0 = Release|x86
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|x86.ActiveCfg = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/contrib/zeromq/test-client.cpp b/contrib/zeromq/test-client.cpp
index d2fc56c..159c250 100644
--- a/contrib/zeromq/test-client.cpp
+++ b/contrib/zeromq/test-client.cpp
@@ -6,7 +6,7 @@
 #include "TZmqClient.h"
 #include "Storage.h"
 
-using boost::shared_ptr;
+using apache::thrift::std::shared_ptr;
 using apache::thrift::transport::TZmqClient;
 using apache::thrift::protocol::TBinaryProtocol;
 
@@ -17,7 +17,7 @@
   if (argc > 1) {
     incr = atoi(argv[1]);
     if (incr) {
-      socktype = ZMQ_DOWNSTREAM;
+      socktype = ZMQ_PUSH;
       endpoint = "tcp://127.0.0.1:9091";
     }
   }
diff --git a/contrib/zeromq/test-client.py b/contrib/zeromq/test-client.py
index 1886d9c..d51216e 100755
--- a/contrib/zeromq/test-client.py
+++ b/contrib/zeromq/test-client.py
@@ -9,28 +9,28 @@
 
 
 def main(args):
-  endpoint = "tcp://127.0.0.1:9090"
-  socktype = zmq.REQ
-  incr = 0
-  if len(args) > 1:
-    incr = int(args[1])
+    endpoint = "tcp://127.0.0.1:9090"
+    socktype = zmq.REQ
+    incr = 0
+    if len(args) > 1:
+        incr = int(args[1])
+        if incr:
+            socktype = zmq.PUSH
+            endpoint = "tcp://127.0.0.1:9091"
+
+    ctx = zmq.Context()
+    transport = TZmqClient.TZmqClient(ctx, endpoint, socktype)
+    protocol = thrift.protocol.TBinaryProtocol.TBinaryProtocolAccelerated(transport)
+    client = storage.Storage.Client(protocol)
+    transport.open()
+
     if incr:
-      socktype = zmq.DOWNSTREAM
-      endpoint = "tcp://127.0.0.1:9091"
-
-  ctx = zmq.Context()
-  transport = TZmqClient.TZmqClient(ctx, endpoint, socktype)
-  protocol = thrift.protocol.TBinaryProtocol.TBinaryProtocolAccelerated(transport)
-  client = storage.Storage.Client(protocol)
-  transport.open()
-
-  if incr:
-    client.incr(incr)
-    time.sleep(0.05)
-  else:
-    value = client.get()
-    print value
+        client.incr(incr)
+        time.sleep(0.05)
+    else:
+        value = client.get()
+        print(value)
 
 
 if __name__ == "__main__":
-  main(sys.argv)
+    main(sys.argv)
diff --git a/contrib/zeromq/test-receiver.cpp b/contrib/zeromq/test-receiver.cpp
index 8fe69da..d465bff 100644
--- a/contrib/zeromq/test-receiver.cpp
+++ b/contrib/zeromq/test-receiver.cpp
@@ -2,7 +2,7 @@
 #include "TZmqServer.h"
 #include "Storage.h"
 
-using boost::shared_ptr;
+using apache::thrift::std::shared_ptr;
 using apache::thrift::TProcessor;
 using apache::thrift::server::TZmqServer;
 using apache::thrift::server::TZmqMultiServer;
diff --git a/contrib/zeromq/test-sender.cpp b/contrib/zeromq/test-sender.cpp
index 6b0eef1..5c086a1 100644
--- a/contrib/zeromq/test-sender.cpp
+++ b/contrib/zeromq/test-sender.cpp
@@ -6,7 +6,7 @@
 #include "TZmqClient.h"
 #include "Storage.h"
 
-using boost::shared_ptr;
+using apache::thrift::std::shared_ptr;
 using apache::thrift::transport::TZmqClient;
 using apache::thrift::protocol::TBinaryProtocol;
 
diff --git a/contrib/zeromq/test-server.cpp b/contrib/zeromq/test-server.cpp
index c624b0d..e6f1b20 100644
--- a/contrib/zeromq/test-server.cpp
+++ b/contrib/zeromq/test-server.cpp
@@ -2,7 +2,7 @@
 #include "TZmqServer.h"
 #include "Storage.h"
 
-using boost::shared_ptr;
+using apache::thrift::std::shared_ptr;
 using apache::thrift::TProcessor;
 using apache::thrift::server::TZmqServer;
 using apache::thrift::server::TZmqMultiServer;
@@ -33,7 +33,7 @@
 
   zmq::context_t ctx(1);
   TZmqServer reqrep_server(processor, ctx, "tcp://0.0.0.0:9090", ZMQ_REP);
-  TZmqServer oneway_server(processor, ctx, "tcp://0.0.0.0:9091", ZMQ_UPSTREAM);
+  TZmqServer oneway_server(processor, ctx, "tcp://0.0.0.0:9091", ZMQ_PULL);
   TZmqMultiServer multiserver;
   multiserver.servers().push_back(&reqrep_server);
   multiserver.servers().push_back(&oneway_server);
diff --git a/contrib/zeromq/test-server.py b/contrib/zeromq/test-server.py
index 5767b71..d89b37b 100755
--- a/contrib/zeromq/test-server.py
+++ b/contrib/zeromq/test-server.py
@@ -6,28 +6,28 @@
 
 
 class StorageHandler(storage.Storage.Iface):
-  def __init__(self):
-    self.value = 0
+    def __init__(self):
+        self.value = 0
 
-  def incr(self, amount):
-    self.value += amount
+    def incr(self, amount):
+        self.value += amount
 
-  def get(self):
-    return self.value
+    def get(self):
+        return self.value
 
 
 def main():
-  handler = StorageHandler()
-  processor = storage.Storage.Processor(handler)
+    handler = StorageHandler()
+    processor = storage.Storage.Processor(handler)
 
-  ctx = zmq.Context()
-  reqrep_server = TZmqServer.TZmqServer(processor, ctx, "tcp://0.0.0.0:9090", zmq.REP)
-  oneway_server = TZmqServer.TZmqServer(processor, ctx, "tcp://0.0.0.0:9091", zmq.UPSTREAM)
-  multiserver = TZmqServer.TZmqMultiServer()
-  multiserver.servers.append(reqrep_server)
-  multiserver.servers.append(oneway_server)
-  multiserver.serveForever()
+    ctx = zmq.Context()
+    reqrep_server = TZmqServer.TZmqServer(processor, ctx, "tcp://0.0.0.0:9090", zmq.REP)
+    oneway_server = TZmqServer.TZmqServer(processor, ctx, "tcp://0.0.0.0:9091", zmq.PULL)
+    multiserver = TZmqServer.TZmqMultiServer()
+    multiserver.servers.append(reqrep_server)
+    multiserver.servers.append(oneway_server)
+    multiserver.serveForever()
 
 
 if __name__ == "__main__":
-  main()
+    main()
diff --git a/debian/README b/debian/README
deleted file mode 100755
index 98d4da0..0000000
--- a/debian/README
+++ /dev/null
@@ -1,19 +0,0 @@
-some tips on Debian Packaging
-- Debian New Maintainers' Guide [http://www.debian.org/doc/debian-policy/]
-- Debian Policy Manual [http://www.debian.org/doc/manuals/maint-guide/]
-- Machine-readable debian/copyright file [http://dep.debian.net/deps/dep5/]
-
-build
-$ dpkg-buildpackage -d -tc
-  -d             do not check build dependencies and conflicts.
-  -tc            clean source tree when finished.
-
-update changelog
-$ date -R
-
-check packages
-$ dpkg -c *.deb
-$ lintian *.deb
-
-todo
-make it perfect!
diff --git a/debian/README.md b/debian/README.md
new file mode 100644
index 0000000..8ebfeea
--- /dev/null
+++ b/debian/README.md
@@ -0,0 +1,41 @@
+## Some tips on Debian Packaging
+
+- Debian New Maintainers' Guide [http://www.debian.org/doc/debian-policy/]
+- Debian Policy Manual [http://www.debian.org/doc/manuals/maint-guide/]
+- Machine-readable debian/copyright file [http://dep.debian.net/deps/dep5/]
+- DebSrc 3.0 guidelines [https://wiki.debian.org/Projects/DebSrc3.0]
+
+
+## Build using dpkg-buildpackage:
+
+```bash
+$ dpkg-buildpackage -d -tc
+  -d   # do not check build dependencies and conflicts.
+  -tc  # clean source tree when finished.
+```
+
+
+## Update changelog:
+
+```bash
+$ date -R
+```
+
+One can also install `devscripts` package and run:
+
+```bash
+$ dch -i
+```
+
+
+## Check packages:
+
+```bash
+$ dpkg -c *.deb
+$ lintian *.deb
+```
+
+
+## TODO
+
+Make it perfect!
diff --git a/debian/changelog b/debian/changelog
old mode 100755
new mode 100644
index ebe30e9..69b5f20
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,26 @@
-thrift (0.9.1) stable; urgency=low
+thrift (0.12.0) stable; urgency=low
 
-  * update to 0.9.1
+  * update to 0.12.0
 
- -- Jake Farrell <jfarrell@apache.org>  Sun, 18 Aug 2013 12:00:00 -0500
+ -- Apache Thrift Developers <dev@thrift.apache.org>  Wed, 28 Dec 2018 12:00:00 -0500
+
+thrift (0.11.0) stable; urgency=low
+
+  * update to 0.11.0
+
+ -- Jake Farrell <jfarrell@apache.org>  Wed, 07 Dec 2017 20:07:00 -0500
+
+thrift (0.10.0) stable; urgency=low
+
+  * update to 0.10.0
+
+ -- Jake Farrell <jfarrell@apache.org>  Wed, 03 Jan 2017 16:52:00 -0500
+
+thrift (0.9.3) stable; urgency=low
+
+  * update to 0.9.3
+
+ -- Jake Farrell <jfarrell@apache.org>  Wed, 11 Oct 2015 17:22:00 -0500
 
 thrift (0.9.0) stable; urgency=low
 
diff --git a/debian/compat b/debian/compat
index 7ed6ff8..ec63514 100644
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
-5
+9
diff --git a/debian/control b/debian/control
index 84e545e..9818a37 100644
--- a/debian/control
+++ b/debian/control
@@ -1,18 +1,21 @@
 Source: thrift
 Section: devel
 Priority: extra
-Build-Depends: debhelper (>= 5), build-essential, mono-gmcs, python-dev, ant,
-    mono-devel,  libmono-system-web2.0-cil, erlang-base, ruby1.8-dev, autoconf, python-support,
-    automake, pkg-config, libtool, bison, flex, libboost-dev | libboost1.40-dev, python-all,
-    python-all-dev, python-all-dbg, openjdk-6-jdk | java-sdk, libcommons-lang3-java,
-    libboost-test-dev | libboost-test1.40-dev, libevent-dev, perl (>= 5.8.0-7),
-    php5, php5-dev, libglib2.0-dev, libqt4-dev
+Build-Depends: debhelper (>= 9), build-essential, mono-mcs, python-dev, ant,
+    mono-devel,  libmono-system-web4.0-cil, erlang-base, ruby-dev | ruby1.9.1-dev, ruby-bundler ,autoconf, automake,
+    pkg-config, libtool, bison, flex, libboost-dev | libboost1.53-dev | libboost1.63-all-dev,
+    python-all, python-setuptools, python-all-dev, python-all-dbg,
+    python3-all, python3-setuptools, python3-all-dev, python3-all-dbg,
+    openjdk-7-jdk | openjdk-8-jdk | default-jdk,
+    libboost-test-dev | libboost-test1.53-dev | libboost-test1.63-dev, libevent-dev, libssl-dev, perl (>= 5.8.0-7),
+    php (>= 5), php-dev (>= 5), libglib2.0-dev, qtchooser, qtbase5-dev-tools
 Maintainer: Thrift Developer's <dev@thrift.apache.org>
 Homepage: http://thrift.apache.org/
-Vcs-Git: https://git-wip-us.apache.org/repos/asf/thrift.git
-Vcs-Browser: https://git-wip-us.apache.org/repos/asf?p=thrift.git
-Standards-Version: 3.7.2
-XS-Python-Version: >= 2.4
+Vcs-Git: https://github.com/apache/thrift.git
+Vcs-Browser: https://github.com/apache/thrift
+Standards-Version: 3.9.7
+X-Python-Version: >= 2.6
+X-Python3-Version: >= 3.3
 
 Package: thrift-compiler
 Architecture: any
@@ -29,10 +32,10 @@
 Package: python-thrift
 Architecture: any
 Section: python
-Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends}
-Recommends: python-twisted-core
+Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends}, python-six
+Recommends: python-twisted-web, python-backports.ssl-match-hostname, python-ipaddress
 Provides: ${python:Provides}
-Description: Python bindings for Thrift
+Description: Python bindings for Thrift (Python 2)
  Thrift is a software framework for scalable cross-language services
  development. It combines a software stack with a code generation engine to
  build services that work efficiently and seamlessly.
@@ -41,10 +44,12 @@
  tool (in the thrift-compiler package) to compile your definition to Python
  classes, and then the modules in this package will allow you to use those
  classes in your programs.
+ .
+ This package installs the library for Python 2.
 
 Package: python-thrift-dbg
 Architecture: any
-Section: python
+Section: debug
 Depends: ${shlibs:Depends}, ${misc:Depends}, python-thrift (= ${binary:Version}), python-all-dbg
 Provides: ${python:Provides}
 Description: Python bindings for Thrift (debug version)
@@ -57,6 +62,39 @@
  definition to Python classes, and then the modules in this package will allow
  you to use those classes in your programs.
 
+Package: python3-thrift
+Architecture: any
+Section: python
+Depends: ${python3:Depends}, ${shlibs:Depends}, ${misc:Depends}, python3-six
+Recommends: python3-twisted-web
+Provides: ${python:Provides}
+Description: Python bindings for Thrift (Python 3)
+ Thrift is a software framework for scalable cross-language services
+ development. It combines a software stack with a code generation engine to
+ build services that work efficiently and seamlessly.
+ .
+ This package contains the Python bindings for Thrift. You will need the thrift
+ tool (in the thrift-compiler package) to compile your definition to Python
+ classes, and then the modules in this package will allow you to use those
+ classes in your programs.
+ .
+ This package installs the library for Python 3.
+
+Package: python3-thrift-dbg
+Architecture: any
+Section: debug
+Depends: ${shlibs:Depends}, ${misc:Depends}, python3-thrift (= ${binary:Version}), python3-all-dbg
+Provides: ${python:Provides}
+Description: Python bindings for Thrift (debug version)
+ Thrift is a software framework for scalable cross-language services
+ development. It combines a software stack with a code generation engine to
+ build services that work efficiently and seamlessly.
+ .
+ This package contains the Python bindings for Thrift with debugging symbols.
+ You will need the thrift tool (in the thrift-compiler package) to compile your
+ definition to Python classes, and then the modules in this package will allow
+ you to use those classes in your programs.
+
 Package: ruby-thrift
 Architecture: all
 Section: libs
@@ -76,9 +114,8 @@
 
 Package: libthrift-java
 Architecture: all
-Section: libs
-Depends: java-gcj-compat | java1-runtime | java2-runtime, ${misc:Depends}
-Recommends: libcommons-lang3-java
+Section: java
+Depends: ${misc:Depends}
 Description: Java bindings for Thrift
  Thrift is a software framework for scalable cross-language services
  development. It combines a software stack with a code generation engine to
@@ -91,9 +128,9 @@
 
 Package: libthrift-cil
 Architecture: all
-Section: libs
-Depends: cli-common, libmono-corlib1.0-cil (>= 1.0), libmono-system1.0-cil (>= 1.0), 
-    libmono-system-web2.0-cil, ${misc:Depends}
+Section: cli-mono
+Depends: cli-common, libmono-corlib4.0-cil (>= 2.10) | libmono-corlib4.5-cil (>=3.2), libmono-system4.0-cil (>= 2.10),
+    libmono-system-web4.0-cil (>= 2.10), ${misc:Depends}
 Description: CLI bindings for Thrift
  Thrift is a software framework for scalable cross-language services
  development. It combines a software stack with a code generation engine to
@@ -129,10 +166,21 @@
  This package contains the runtime libraries needed for C++ applications
  using Thrift.
 
+Package: libthrift0-dbg
+Architecture: any
+Section: debug
+Depends: ${shlibs:Depends}, ${misc:Depends}, libthrift0 (= ${binary:Version})
+Description: Thrift C++ library debug symbols
+ Thrift is a software framework for scalable cross-language services
+ development. It combines a software stack with a code generation engine to
+ build services that work efficiently and seamlessly.
+ .
+ This package contains the debug symbols for the Thrift C++ runtime libraries.
+
 Package: libthrift-dev
 Architecture: any
 Section: libdevel
-Depends: ${shlibs:Depends}, ${misc:Depends}, libthrift0, libglib2.0-dev
+Depends: ${shlibs:Depends}, ${misc:Depends}, libthrift0 (= ${binary:Version}), libglib2.0-dev
 Description: Thrift C++ library (development headers)
  Thrift is a software framework for scalable cross-language services
  development. It combines a software stack with a code generation engine to
diff --git a/debian/copyright b/debian/copyright
index 25546b4..850643c 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -4,7 +4,7 @@
 This package and the Debian packaging is licensed under the Apache License,
 see `/usr/share/common-licenses/Apache-2.0'.
 
-The following informations was copied from Apache Thrift LICENSE file.
+The following information was copied from Apache Thrift LICENSE file.
 
 --------------------------------------------------
 SOFTWARE DISTRIBUTED WITH THRIFT:
diff --git a/debian/docs b/debian/docs
index e845566..b43bf86 100644
--- a/debian/docs
+++ b/debian/docs
@@ -1 +1 @@
-README
+README.md
diff --git a/debian/libthrift0.install b/debian/libthrift0.install
old mode 100755
new mode 100644
diff --git a/debian/rules b/debian/rules
index 8995f9c..9b436d9 100755
--- a/debian/rules
+++ b/debian/rules
@@ -18,12 +18,18 @@
 
 PYVERS := $(shell pyversions -r)
 
+export CPPFLAGS:=$(shell dpkg-buildflags --get CPPFLAGS)
+export CFLAGS:=$(shell dpkg-buildflags --get CFLAGS)
+export CXXFLAGS:=$(shell dpkg-buildflags --get CXXFLAGS)
+export LDFLAGS:=$(shell dpkg-buildflags --get LDFLAGS)
+
 configure: configure-stamp
 configure-stamp:
 	dh_testdir
+
 	# Add here commands to configure the package.
 	if [ -f bootstrap.sh ]; then $(CURDIR)/bootstrap.sh; fi
-	$(CURDIR)/configure --prefix=/usr --with-c_glib --without-erlang
+	$(CURDIR)/configure --prefix=/usr --enable-plugin=no
 
 	touch configure-stamp
 
@@ -34,7 +40,7 @@
 	# $(MAKE) -C test check
 
 build-arch: build-arch-stamp
-build-arch-stamp: configure-stamp
+$(CURDIR)/compiler/cpp/thrift build-arch-stamp: configure-stamp
 
 	# Compile compiler
 	$(MAKE) -C $(CURDIR)/compiler/cpp
@@ -55,19 +61,19 @@
 	# PHP
 	cd $(CURDIR)/lib/php/src/ext/thrift_protocol && \
 		phpize && \
-		./configure && make
+		./configure && $(MAKE)
 
 	touch $@
 
 build-indep: build-indep-stamp
-build-indep-stamp: configure-stamp
+build-indep-stamp: configure-stamp $(CURDIR)/compiler/cpp/thrift
 
 	# Add here commands to compile the indep part of the package.
 	#$(MAKE) doc
 
 	# Java
 	cd $(CURDIR)/lib/java && \
-		ant
+		./gradlew --no-daemon -Prelease=true jar
 
 	# C#
 	$(MAKE) -C $(CURDIR)/lib/csharp
@@ -85,33 +91,32 @@
 	dh_testroot
 	rm -f build-arch-stamp build-indep-stamp configure-stamp
 
+	cd $(CURDIR)/lib/py && python setup.py clean --all
+
 	# Add here commands to clean up after the build process.
 	-$(MAKE) clean
 
+	$(CURDIR)/cleanup.sh
+
 	dh_clean
 
 install: install-indep install-arch
 install-indep:
 	dh_testdir
 	dh_testroot
-	dh_clean -k -i
+	dh_prep -i
 	dh_installdirs -i
 
 	# Add here commands to install the indep part of the package into
 	# debian/<package>-doc.
 	#INSTALLDOC#
 
-        # Java
+	# Java
 	mkdir -p $(CURDIR)/debian/libthrift-java/usr/share/java/ && \
-	cp $(CURDIR)/lib/java/build/libthrift*.jar \
+	cp $(CURDIR)/lib/java/build/libs/libthrift*.jar \
 		$(CURDIR)/debian/libthrift-java/usr/share/java/
 
-        # Ruby
-	mkdir -p $(CURDIR)/debian/ruby-thrift/usr/lib/ruby/1.8 && \
-	cp $(CURDIR)/lib/rb/lib/thrift.rb \
-		$(CURDIR)/debian/ruby-thrift/usr/lib/ruby/1.8
-	cp -r $(CURDIR)/lib/rb/lib/thrift \
-		$(CURDIR)/debian/ruby-thrift/usr/lib/ruby/1.8
+	# Ruby
 	mkdir -p $(CURDIR)/debian/ruby-thrift/usr/lib/ruby/1.9.1 && \
 	cp $(CURDIR)/lib/rb/lib/thrift.rb \
 		$(CURDIR)/debian/ruby-thrift/usr/lib/ruby/1.9.1
@@ -124,7 +129,11 @@
 		$(CURDIR)/debian/libthrift-cil/usr/lib/cli/thrift/Thrift.dll
 
 	# Perl
-	$(MAKE) -C $(CURDIR)/lib/perl install DESTDIR=$(CURDIR)/debian/libthrift-perl/usr
+	$(MAKE) -C $(CURDIR)/lib/perl install DESTDIR=$(CURDIR)/debian/libthrift-perl
+	mkdir -p $(CURDIR)/debian/libthrift-perl/usr/share
+	mv $(CURDIR)/debian/libthrift-perl/usr/local/lib/perl5 $(CURDIR)/debian/libthrift-perl/usr/share
+	rmdir $(CURDIR)/debian/libthrift-perl/usr/local/lib
+	rmdir $(CURDIR)/debian/libthrift-perl/usr/local
 
 	dh_install -i
 
@@ -146,16 +155,27 @@
 
 	# Python
 	cd $(CURDIR)/lib/py && \
-	for py in $(PYVERS); do \
-		$$py setup.py install --no-compile --root=$(CURDIR)/debian/python-thrift; \
-		$$py-dbg setup.py install --no-compile --root=$(CURDIR)/debian/python-thrift-dbg; \
-	done
+	python2 setup.py install --install-layout=deb --no-compile --root=$(CURDIR)/debian/python-thrift && \
+	python2-dbg setup.py install --install-layout=deb --no-compile --root=$(CURDIR)/debian/python-thrift-dbg && \
+	python3 setup.py install --install-layout=deb --no-compile --root=$(CURDIR)/debian/python3-thrift && \
+	python3-dbg setup.py install --install-layout=deb --no-compile --root=$(CURDIR)/debian/python3-thrift-dbg
 
-	find $(CURDIR)/debian/python-thrift-dbg -name "*.pyc" -print0 | xargs -0 rm -f
+	find $(CURDIR)/debian/python-thrift -name "*.py[co]" -print0 | xargs -0 rm -f
+	find $(CURDIR)/debian/python-thrift -name "__pycache__" -print0 | xargs -0 rm -fr
+	find $(CURDIR)/debian/python-thrift-dbg -name "__pycache__" -print0 | xargs -0 rm -fr
+	find $(CURDIR)/debian/python-thrift-dbg -name "*.py[co]" -print0 | xargs -0 rm -f
 	find $(CURDIR)/debian/python-thrift-dbg -name "*.py" -print0 | xargs -0 rm -f
 	find $(CURDIR)/debian/python-thrift-dbg -name "*.egg-info" -print0 | xargs -0 rm -rf
 	find $(CURDIR)/debian/python-thrift-dbg -depth -type d -empty -exec rmdir {} \;
 
+	find $(CURDIR)/debian/python3-thrift -name "*.py[co]" -print0 | xargs -0 rm -f
+	find $(CURDIR)/debian/python3-thrift -name "__pycache__" -print0 | xargs -0 rm -fr
+	find $(CURDIR)/debian/python3-thrift-dbg -name "__pycache__" -print0 | xargs -0 rm -fr
+	find $(CURDIR)/debian/python3-thrift-dbg -name "*.py[co]" -print0 | xargs -0 rm -f
+	find $(CURDIR)/debian/python3-thrift-dbg -name "*.py" -print0 | xargs -0 rm -f
+	find $(CURDIR)/debian/python3-thrift-dbg -name "*.egg-info" -print0 | xargs -0 rm -rf
+	find $(CURDIR)/debian/python3-thrift-dbg -depth -type d -empty -exec rmdir {} \;
+
 	# PHP
 	mkdir -p $(CURDIR)/debian/php5-thrift
 	cd $(CURDIR)/lib/php && \
@@ -164,9 +184,9 @@
 	# C++ and C (glib)
 	mkdir -p $(CURDIR)/debian/tmp; \
 	cd $(CURDIR)/lib/cpp && \
-		make DESTDIR=$(CURDIR)/debian/tmp install
+		$(MAKE) DESTDIR=$(CURDIR)/debian/tmp install
 	cd $(CURDIR)/lib/c_glib && \
-		make DESTDIR=$(CURDIR)/debian/tmp install
+		$(MAKE) DESTDIR=$(CURDIR)/debian/tmp install
 
 	dh_install --sourcedir=debian/tmp -s
 
@@ -182,11 +202,12 @@
 	dh_installexamples
 	dh_installman
 	dh_link
-	dh_strip -Npython-thrift-dbg -Nthrift-compiler -Nlibthrift0 --dbg=python-thrift-dbg
-	dh_strip -Npython-thrift-dbg
+	dh_strip -plibthrift0 --dbg-package=libthrift0-dbg
+	dh_strip -ppython-thrift --dbg-package=python-thrift-dbg
+	dh_strip -ppython3-thrift --dbg-package=python3-thrift-dbg
+	dh_strip -pthrift-compiler
 	dh_compress
 	dh_fixperms
-	dh_pysupport
 	dh_makeshlibs
 	dh_installdeb
 	dh_perl
@@ -194,13 +215,13 @@
 	dh_gencontrol
 	dh_md5sums
 	dh_builddeb
-# Build architecture independant packages using the common target.
+# Build architecture independent packages using the common target.
 binary-indep: build-indep install-indep
 	$(MAKE) -f debian/rules DH_OPTIONS=-i binary-common
 
-# Build architecture dependant packages using the common target.
+# Build architecture dependent packages using the common target.
 binary-arch: build-arch install-arch
-	echo "php:Depends=phpapi-$(php-config5 --phpapi)" > debian/substvars
+	echo "php:Depends=phpapi-$(shell php-config5 --phpapi)" > $(CURDIR)/debian/substvars
 	$(MAKE) -f debian/rules DH_OPTIONS=-s binary-common
 
 binary: binary-arch binary-indep
diff --git a/debian/substvars b/debian/substvars
index badf572..9841f2d 100644
--- a/debian/substvars
+++ b/debian/substvars
@@ -1 +1 @@
-php:Depends=phpapi-
+php:Depends=phpapi-20121212
diff --git a/doap.rdf b/doap.rdf
index f110e43..cb76fac 100755
--- a/doap.rdf
+++ b/doap.rdf
@@ -38,23 +38,51 @@
     <programming-language>C++</programming-language>
     <programming-language>Cocoa</programming-language>
     <programming-language>D</programming-language>
+    <programming-language>Dart</programming-language>
     <programming-language>Delphi</programming-language>
     <programming-language>Erlang</programming-language>
     <programming-language>Go</programming-language>
     <programming-language>Haskell</programming-language>
+    <programming-language>Haxe</programming-language>
     <programming-language>Java</programming-language>
     <programming-language>JavaScript</programming-language>
     <programming-language>node.js</programming-language>
-    <programming-language>Ocaml</programming-language>
+    <programming-language>OCaml</programming-language>
     <programming-language>Perl</programming-language>
     <programming-language>PHP</programming-language>
     <programming-language>Python</programming-language>
+    <programming-language>Rust</programming-language>
     <programming-language>SmallTalk</programming-language>
     <category rdf:resource="http://projects.apache.org/category/http" />
     <category rdf:resource="http://projects.apache.org/category/library" />
     <category rdf:resource="http://projects.apache.org/category/network-client" />
     <category rdf:resource="http://projects.apache.org/category/network-server" />
-    <release>
+    <release rdf:parseType="Collection">
+      <Version>
+        <name>Apache Thrift</name>
+        <created>2018-12-28</created>
+        <revision>0.12.0</revision>
+      </Version>
+      <Version>
+        <name>Apache Thrift</name>
+        <created>2017-11-30</created>
+        <revision>0.11.0</revision>
+      </Version>
+      <Version>
+        <name>Apache Thrift</name>
+        <created>2017-03-01</created>
+        <revision>0.10.0</revision>
+      </Version>
+      <Version>
+        <name>Apache Thrift</name>
+        <created>2015-09-25</created>
+        <revision>0.9.3</revision>
+      </Version>
+      <Version>
+        <name>Apache Thrift</name>
+        <created>2014-11-05</created>
+        <revision>0.9.2</revision>
+      </Version>
       <Version>
         <name>Apache Thrift</name>
         <created>2013-08-22</created>
@@ -108,8 +136,8 @@
     </release>
     <repository>
       <GitRepository>
-        <location rdf:resource="https://git-wip-us.apache.org/repos/asf/thrift.git"/>
-        <browse rdf:resource="https://git-wip-us.apache.org/repos/asf?p=thrift.git"/>
+        <location rdf:resource="https://github.com/apache/thrift.git"/>
+        <browse rdf:resource="https://github.com/apache/thrift"/>
       </GitRepository>
     </repository>
     <maintainer>
diff --git a/doc/coding_standards.md b/doc/coding_standards.md
new file mode 100644
index 0000000..308100a
--- /dev/null
+++ b/doc/coding_standards.md
@@ -0,0 +1,48 @@
+# Thrift Coding Standards
+
+   Any fool can write code that a computer can understand.
+   Good programmers write code that humans can understand.
+                                  -- Martin Fowler, 1999
+
+The purpose of this document is to make everyone's life easier.
+
+It's easier when you read good, well formatted, with clearly defined purpose, code.
+But the only way to read clean code is to write such.
+
+This document can help achieve that, but keep in mind that
+those are not silver-bullet, fix-all-at-once rules. Just think about readability while writing code.
+Write code like you would have to read it in ten years from now.
+
+## General Coding Standards
+
+Thrift has some history. Not all existing code follows those rules.
+But we want to improve over time.
+When making small change / bugfix - like single line fix - do *not* refactor whole function.
+That disturbs code repository history.
+Whenever adding something new and / or making bigger refactoring
+ - follow those rules as strictly as you can.
+
+When in doubt - contact other developers (using dev@ mailing list or IRC).
+Code review is the best way to improve readability.
+
+### Basics
+ * Use spaces not tabs
+ * Use only ASCII characters in file and directory names
+ * Commit to repository using Unix-style line endings (LF)
+     On Windows:
+       git config core.autocrlf true
+ * Maximum line width - 100 characters
+ * If not specified otherwise in language specific standard - use 2 spaces as indent/tab
+
+### Comments
+ * Each file has to start with comment containing [Apache License](http://www.apache.org/licenses/LICENSE-2.0)
+ * Public API of library should be documented, preferably using format native for language specific documentation generation tools (Javadoc, Doxygen etc.)
+ * Other comments are discouraged - comments are lies. When one has to make comment it means one failed to write readable code. Instead of "I should write a comment here" think "I should clean it up"
+ * Do not leave "TODO/FIXME" comments - file [Jira](http://issues.apache.org/jira/browse/THRIFT) issue instead
+
+### Naming
+ Finding proper names is the most important and most difficult task in software development.
+
+## Language Specific Coding Standards
+
+For detailed information see `lib/LANG/coding_standards.md`
diff --git a/doc/committers.md b/doc/committers.md
new file mode 100644
index 0000000..dcdd7b7
--- /dev/null
+++ b/doc/committers.md
@@ -0,0 +1,54 @@
+## Process used by committers to review and submit patches
+
+1. Make sure that there is an issue for the patch(s) you are about to commit in our [Jira issue tracker](http://issues.apache.org/jira/browse/THRIFT)
+
+1. Check out the latest version of the source code
+
+  * git clone https://github.com/apache/thrift.git thrift
+
+1. Apply the patch
+
+  * curl https://issues.apache.org/jira/... |git apply --ignore-space-change
+
+  or
+
+  * curl https://github.com/<GitHub User>/thrift/commit/<Commit ID>.patch |git apply --ignore-space-change
+
+
+1. Inspect the applied patch to ensure that all [Legal aspects on Submission of Contributions (Patches)](http://www.apache.org/licenses/LICENSE-2.0.html#contributions) are met
+
+1. Run the necessary unit tests and cross language test cases to verify the patch
+
+1. Commit the patch
+
+        git --config user.name "Your Name"
+        git --config user.email "YourApacheID@apache.org"
+        git add -A
+        git commit
+
+1. The commit message should be in the format:
+
+       THRIFT-###:<Jira description>
+       Client: <component>
+       Patch: <Name of person contributing the patch>
+
+       Description of what was fixed or addressed.
+
+       <%
+           if this is a github pull request then add below comment
+            to automaticaly close GitHub request.
+       %>
+       This closes #XX
+
+
+1. Double check the patch committed and that nothing was missed then push the patch
+
+       git status
+       git show HEAD
+       git push origin master
+
+
+1. Resolve the jira issue and set the following for the changelog
+
+  * Component the patch is for
+  * fixVersion to the current version on master
diff --git a/doc/images/cgrn.png b/doc/images/cgrn.png
new file mode 100644
index 0000000..dc0964e
--- /dev/null
+++ b/doc/images/cgrn.png
Binary files differ
diff --git a/doc/images/cred.png b/doc/images/cred.png
new file mode 100644
index 0000000..086a5fb
--- /dev/null
+++ b/doc/images/cred.png
Binary files differ
diff --git a/doc/images/credfull.png b/doc/images/credfull.png
new file mode 100644
index 0000000..ff66404
--- /dev/null
+++ b/doc/images/credfull.png
Binary files differ
diff --git a/doc/images/cyel.png b/doc/images/cyel.png
new file mode 100644
index 0000000..7c1dfc7
--- /dev/null
+++ b/doc/images/cyel.png
Binary files differ
diff --git a/doc/images/thrift-layers.png b/doc/images/thrift-layers.png
new file mode 100644
index 0000000..c1accf4
--- /dev/null
+++ b/doc/images/thrift-layers.png
Binary files differ
diff --git a/doc/install/README.md b/doc/install/README.md
new file mode 100644
index 0000000..22231cd
--- /dev/null
+++ b/doc/install/README.md
@@ -0,0 +1,43 @@
+
+## Basic requirements
+* A relatively POSIX-compliant *NIX system
+    * Cygwin or MinGW can be used on Windows (but there are better options, see below)
+* g++ 4.2
+* boost 1.53.0
+* Runtime libraries for lex and yacc might be needed for the compiler.
+
+## Requirements for building from source
+* GNU build tools: 
+    * autoconf 2.65
+    * automake 1.13
+    * libtool 1.5.24
+* pkg-config autoconf macros (pkg.m4)
+* lex and yacc (developed primarily with flex and bison)
+* libssl-dev
+
+## Requirements for building the compiler from source on Windows
+* Visual Studio C++
+* Flex and Bison (e.g. the WinFlexBison package)
+
+## Language requirements
+These are only required if you choose to build the libraries for the given language
+
+* C++
+    * Boost 1.53.0
+    * libevent (optional, to build the nonblocking server)
+    * zlib (optional)
+* Java
+    * Java 1.8
+    * Apache Ant
+* C#: Mono 1.2.4 (and pkg-config to detect it) or Visual Studio 2005+
+* Python 2.6 (including header files for extension modules)
+* PHP 5.0 (optionally including header files for extension modules)
+* Ruby 1.8
+    * bundler gem
+* Erlang R12 (R11 works but not recommended)
+* Perl 5
+    * Bit::Vector
+    * Class::Accessor
+* Haxe 3.1.3
+* Go 1.4
+* Delphi 2010
diff --git a/doc/install/centos.md b/doc/install/centos.md
new file mode 100644
index 0000000..04932c2
--- /dev/null
+++ b/doc/install/centos.md
@@ -0,0 +1,75 @@
+# Building Apache Thrift on CentOS 6.5
+
+Starting with a minimal installation, the following steps are required to build Apache Thrift on Centos 6.5. This example builds from source, using the current development master branch. These instructions should also work with Apache Thrift releases beginning with 0.9.2.
+
+## Update the System
+
+	sudo yum -y update
+
+## Install the Platform Development Tools
+
+	sudo yum -y groupinstall "Development Tools"
+
+## Upgrade autoconf/automake/bison
+
+	sudo yum install -y wget
+
+### Upgrade autoconf
+
+	wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
+	tar xvf autoconf-2.69.tar.gz
+	cd autoconf-2.69
+	./configure --prefix=/usr
+	make
+	sudo make install
+	cd ..
+
+### Upgrade automake
+
+	wget http://ftp.gnu.org/gnu/automake/automake-1.14.tar.gz
+	tar xvf automake-1.14.tar.gz
+	cd automake-1.14
+	./configure --prefix=/usr
+	make
+	sudo make install
+	cd ..
+
+### Upgrade bison
+
+	wget http://ftp.gnu.org/gnu/bison/bison-2.5.1.tar.gz
+	tar xvf bison-2.5.1.tar.gz
+	cd bison-2.5.1
+	./configure --prefix=/usr
+	make
+	sudo make install
+	cd ..
+
+## Add Optional C++ Language Library Dependencies
+
+All languages require the Apache Thrift IDL Compiler and at this point everything needed to make the IDL Compiler is installed (if you only need the compiler you can skip to the Build step). 
+
+If you will be developing Apache Thrift clients/servers in C++ you will also need additional packages to support the C++ shared library build.
+
+### Install C++ Lib Dependencies
+
+	sudo yum -y install libevent-devel zlib-devel openssl-devel
+
+### Upgrade Boost >= 1.53
+
+	wget http://sourceforge.net/projects/boost/files/boost/1.53.0/boost_1_53_0.tar.gz
+	tar xvf boost_1_53_0.tar.gz
+	cd boost_1_53_0
+	./bootstrap.sh
+	sudo ./b2 install
+
+## Build and Install the Apache Thrift IDL Compiler
+
+	git clone https://github.com/apache/thrift.git
+	cd thrift
+	./bootstrap.sh
+	./configure --with-lua=no
+	make
+	sudo make install
+
+This will build the compiler (thrift/compiler/cpp/thrift --version) and any language libraries supported. The make install step installs the compiler on the path: /usr/local/bin/thrift
+You can use the ./configure --enable-libs=no switch to build the Apache Thrift IDL Compiler only without lib builds. To run tests use "make check".
diff --git a/doc/install/debian.md b/doc/install/debian.md
new file mode 100644
index 0000000..84f696e
--- /dev/null
+++ b/doc/install/debian.md
@@ -0,0 +1,62 @@
+## Debian/Ubuntu install
+The following command will install tools and libraries required to build and install the Apache Thrift compiler and C++ libraries on a Debian/Ubuntu Linux based system.
+
+	sudo apt-get install automake bison flex g++ git libboost-all-dev libevent-dev libssl-dev libtool make pkg-config
+
+Debian 7/Ubuntu 12 users need to manually install a more recent version of automake and (for C++ library and test support) boost:
+
+    wget http://ftp.debian.org/debian/pool/main/a/automake-1.15/automake_1.15-3_all.deb
+    sudo dpkg -i automake_1.15-3_all.deb
+
+    wget http://sourceforge.net/projects/boost/files/boost/1.60.0/boost_1_60_0.tar.gz                                                                      tar xvf boost_1_60_0.tar.gz
+    cd boost_1_60_0
+    ./bootstrap.sh
+    sudo ./b2 install
+
+## Optional packages
+
+If you would like to build Apache Thrift libraries for other programming languages you may need to install additional packages. The following languages require the specified additional packages:
+
+ * Java
+	* packages: ant  
+	* You will also need Java JDK v1.8 or higher. Type **javac** to see a list of available packages, pick the one you prefer and **apt-get install** it (e.g. default-jdk).
+ * Ruby
+	* ruby-full ruby-dev ruby-rspec rake rubygems bundler
+ * Python
+	* python-all python-all-dev python-all-dbg
+ * Perl
+	* libbit-vector-perl libclass-accessor-class-perl
+ * Php, install
+	* php5-dev php5-cli phpunit
+ * C_glib
+	* libglib2.0-dev
+ * Erlang
+	* erlang-base erlang-eunit erlang-dev rebar
+ * Csharp
+	* mono-gmcs mono-devel libmono-system-web2.0-cil nunit nunit-console
+ * Haskell
+	* ghc cabal-install libghc-binary-dev libghc-network-dev libghc-http-dev
+ * Thrift Compiler for Windows
+	* mingw-w64 mingw-w64-x86-64-dev nsis
+ * Rust
+	* rustc cargo
+ * Haxe
+	* haxe
+ * Lua
+    * lua5.3 liblua5.3-dev
+ * NodeJs
+    * nodejs npm
+ * dotnetcore
+    * https://www.microsoft.com/net/learn/get-started/linuxubuntu
+ * d-lang
+    * curl -fsS https://dlang.org/install.sh | bash -s dmd
+ * dart & pub
+    * https://www.dartlang.org/install/linux
+    * https://www.dartlang.org/tools/pub/installing
+	
+
+## Additional reading
+
+For more information on the requirements see: [Apache Thrift Requirements](/docs/install)
+
+For more information on building and installing Thrift see: [Building from source](/docs/BuildingFromSource)
diff --git a/doc/install/os_x.md b/doc/install/os_x.md
new file mode 100644
index 0000000..2d99ef4
--- /dev/null
+++ b/doc/install/os_x.md
@@ -0,0 +1,27 @@
+## OS X Setup
+The following command install all the required tools and libraries to build and install the Apache Thrift compiler on a OS X based system. 
+
+### Install Boost
+Download the boost library from [boost.org](http://www.boost.org) untar compile with
+
+	./bootstrap.sh
+	sudo ./b2 threading=multi address-model=64 variant=release stage install
+
+### Install libevent
+Download [libevent](http://monkey.org/~provos/libevent), untar and compile with
+
+	./configure --prefix=/usr/local 
+	make
+	sudo make install
+
+### Building Apache Thrift
+Download the latest version of [Apache Thrift](/download), untar and compile with
+
+	./configure --prefix=/usr/local/ --with-boost=/usr/local --with-libevent=/usr/local
+
+## Additional reading
+
+For more information on the requirements see: [Apache Thrift Requirements](/docs/install)
+
+For more information on building and installing Thrift see: [Building from source](/docs/BuildingFromSource)
+
diff --git a/doc/install/windows.md b/doc/install/windows.md
new file mode 100644
index 0000000..8618934
--- /dev/null
+++ b/doc/install/windows.md
@@ -0,0 +1,186 @@
+## Windows Setup
+
+The Thrift environment consists of two main parts: The Thrift compiler EXE and the language-dependent libraries. Most of these libraries will require some kind of build and/or installation. But regarding the Thrift compiler utility there are a number of different alternatives. 
+
+The first one of these alternatives is to download the **pre-built Thrift Compiler EXE** and only build the libraries needed from source, following one of the "Setup from source" methods outlined below.
+
+The other two options are to build the Thrift compiler from source. The most recommended way to achieve this is by means of the **Visual Studio C++ build project**. Alternatively, the Thrift compiler can also be built via **Cygwin** or **MinGW** build environments, however this method is not only less comfortable, but more time-consuming and requires much more manual effort. 
+
+
+## Prebuilt Thrift compiler
+
+The windows Thrift compiler is available as a prebuilt exe available [here](/download). Note that there is no installation tool, rather this EXE file *is* already the Thrift compiler utility. Download the file and put it into some suitable location of your choice.
+
+Now pick one of the "Build and install target libraries" below to continue.
+
+ 
+## Setup from source via Visual Studio C++ (recommended)
+
+### Requirements
+
+Thrift's compiler is written in C++ and designed to be portable, but there are some system requirements. Thrift's runtime libraries are written in various languages, which are also required for the particular language interface.
+
+ * Visual Studio C++, any recent version should do
+ * Flex and Bison, e.g. the WinFlexBison package
+ * [Apache Thrift Requirements](/docs/install)
+
+### Build and install the compiler
+ 
+After all requirements are in place, use the `compiler/cpp/compiler.vcxproj` build project to build the Thrift compiler. Copy the resulting EXE file to a location of your choice. 
+
+### Build and install target libraries
+
+A few of the target language libraries also do provide Visual Studio project files, such as C++ and C#. These are located in the `lib/<language>/` folders. 
+
+Most of the language packages must be built and installed manually using build tools better suited to those languages. Typical examples are Java, Ruby, Delphi, or PHP. Look for the `README.md` file in the `lib/<language>/` folder for more details on how to build and install each language's library package.
+ 
+
+## Setup from source via Cygwin
+
+### Requirements
+
+Thrift's compiler is written in C++ and designed to be portable, but there are some system requirements. Thrift's runtime libraries are written in various languages, which are also required for the particular language interface.
+
+ * Cygwin or MinGW 
+ * [Apache Thrift Requirements](/docs/install)
+
+### Installing from source
+
+If you are building from the first time out of the source repository, you will need to generate the configure scripts.  (This is not necessary if you downloaded a tarball.)  From the top directory, do:
+
+	./bootstrap.sh
+
+Once the configure scripts are generated, thrift can be configured. From the top directory, do:
+
+	export CXXFLAGS="-D PTHREAD_MUTEX_RECURSIVE_NP=PTHREAD_MUTEX_RECURSIVE"
+	./configure
+
+Setting the CXXFLAGS environmental variable works around compile errors with PTHREAD_MUTEX_RECURSIVE_NP being undeclared, by replacing it with the newer, portable PTHREAD_MUTEX_RECURSIVE. (Tested on cygwin 20100320, Thrift r760184, latest pthread.)
+
+**Optional:** You **may not** be able to make from the root  Thrift directory due to errors (see below to resolve). To make the compiler only, change to the compiler directory before running make:
+
+	cd compiler/cpp
+
+Now make the thrift compiler (& runtime libraries if make is run from the thrift root directory):
+
+	make
+	make install
+
+### Build and install target libraries
+
+Some language packages must be installed manually using build tools better suited to those languages. Typical examples are Java, Ruby, or PHP. Look for the README file in the `lib/<language>/` folder for more details on the installation of each language library package.
+
+### Possible issues with Cygwin install
+
+See also Possible issues with MinGW install.
+
+#### Syntax error in ./configure
+
+The following error occurs for some users when running ./configure:
+
+	./configure: line 21183: syntax error near unexpected token `MONO,'
+	./configure: line 21183: `  PKG_CHECK_MODULES(MONO, mono >= 1.2.6, have_mono=yes, have_mono=no)'
+
+To resolve this, you'll need to find your pkg.m4 (installed by the pkg-config package) file and copy it to the thrift/aclocal directory.  From the top-level thrift directory, you can copy the file by running
+
+	cp /usr/share/aclocal/pkg.m4 aclocal
+
+Finally, re-run ./bootstrap.sh and ./configure.  (Note that pkg.m4 is created by the pkg-config tool.  If your /usr/share/aclocal directory doesn't contain the pkg.m4 file, you may not have pkg-config installed.)
+
+#### Installing perl runtime libraries
+
+Sometimes, there will be an error during the install of the perl libraries with chmod.
+
+A workaround is to avoid installing the perl libraries if they are not needed.
+
+If you don't need perl, run configure with --without-perl.
+
+If you need perl, and are happy to manually install it, replace the contents of thrift/lib/perl/Makefile with the following, after building thrift:
+	
+	TODO
+
+#### Linking to installed C++ runtime libraries
+
+Sometimes, the installed libthrift.a will not link using g++, with linker errors about missing vtables and exceptions for Thrift classes.
+
+A workaround is to link the compiled object files directly from your Thrift build, corresponding to the missing classes.
+
+This can be implemented in a Makefile using the following lines:
+
+	THRIFT_O=<path to>/thrift/lib/cpp
+	LTHRIFT=$(THRIFT_O)/Thrift.o $(THRIFT_O)/TSocket.o $(THRIFT_O)/TBinaryProtocol.o $(THRIFT_O)/TBufferTransports.o
+
+Then linking using $(LTHRIFT) instead of -lthrift.
+
+	TODO - diagnose issue further
+
+#### C++ runtime segfault with cygwin 1.7.5-1, g++-4.3.4, fork() and throw
+
+If your thrift C++ programs segfault on throw after fork()ing, compile them with g++-3.
+
+The issue and patch are described on the Cygwin mailing list at http://cygwin.com/ml/cygwin/2010-05/msg00203.html
+
+This issue should be fixed in Cygwin versions after 1.7.5-1, or g++ 4.5.0.
+
+## Setup from source via MinGW
+
+### Requirements
+
+To compile the Thrift generator & runtime libraries (untested) without the cygwin.dll dependency you need to install MinGW (www.mingw.org). 
+
+ * MinGW 
+ * [Apache Thrift Requirements](/docs/install)
+
+In addition you need to add the following entry to your windows PATH variable.
+
+	C:\MINGW\BIN
+	
+Next, open compiler/cpp/Makefile.am and add the following line to thrift_CXXFLAGS
+
+	-DMINGW -mno-cygwin -lfl
+	
+Run bootstrap.sh:
+
+	./bootstrap.sh
+
+Make sure you have java in your $PATH variable, if not do(adjust path if necessary):
+
+	export PATH=$PATH:"/cygdrive/c/program files/java/jre1.8.0_191/bin"
+
+Run configure - using CXXFLAGS to work around an issue with an old pthreads define (untested on MinGW - works on Cygwin):
+
+	export CXXFLAGS="-D PTHREAD_MUTEX_RECURSIVE_NP=PTHREAD_MUTEX_RECURSIVE"
+	./configure
+
+''Optional:'' To make the compiler only, change to the compiler  directory before running make:
+
+	cd compiler/cpp
+	
+Run make:
+
+	mingw32-make.exe
+
+### Possible issues with MinGW install
+
+See also Possible issues with Cygwin install, including the discussion about PTHREAD_MUTEX_RECURSIVE_NP.
+
+#### yywrap is not found
+
+Make sure you add -lfl in your cxxflags in Makefile, also try adding -Lc:/cygwin/libs
+
+#### boost is not found
+
+Try and change the include dir to use the windows path from c like this: Edit compiler/cpp/Makefile, look for the declaration of BOOST_CPPFLAGS, change that line for
+
+	BOOST_CPPFLAGS = -Ic:/cygwin/usr/include/boost-1_53_0
+	
+#### realpath is not found
+
+add -DMINGW -mno-cygwin to the CXXDEFS variable in Makefile
+
+## Additional reading
+
+For more information on the requirements see: [Apache Thrift Requirements](/docs/install)
+
+For more information on building and installing Thrift see: [Building from source](/docs/BuildingFromSource)
+
diff --git a/doc/lgpl-2.1.txt b/doc/licenses/lgpl-2.1.txt
similarity index 100%
rename from doc/lgpl-2.1.txt
rename to doc/licenses/lgpl-2.1.txt
diff --git a/doc/otp-base-license.txt b/doc/licenses/otp-base-license.txt
similarity index 100%
rename from doc/otp-base-license.txt
rename to doc/licenses/otp-base-license.txt
diff --git a/doc/specs/HeaderFormat.md b/doc/specs/HeaderFormat.md
new file mode 100644
index 0000000..42ec7ae
--- /dev/null
+++ b/doc/specs/HeaderFormat.md
@@ -0,0 +1,82 @@
+<link href="http://kevinburke.bitbucket.org/markdowncss/markdown.css" rel="stylesheet"></link>
+
+Header format for the THeader.h
+===============================
+
+      0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 a b c d e f
+    +----------------------------------------------------------------+
+    | 0|                          LENGTH                             |
+    +----------------------------------------------------------------+
+    | 0|       HEADER MAGIC          |            FLAGS              |
+    +----------------------------------------------------------------+
+    |                         SEQUENCE NUMBER                        |
+    +----------------------------------------------------------------+
+    | 0|     Header Size(/32)        | ...
+    +---------------------------------
+
+                      Header is of variable size:
+                       (and starts at offset 14)
+
+    +----------------------------------------------------------------+
+    |         PROTOCOL ID  (varint)  |   NUM TRANSFORMS (varint)     |
+    +----------------------------------------------------------------+
+    |      TRANSFORM 0 ID (varint)   |        TRANSFORM 0 DATA ...
+    +----------------------------------------------------------------+
+    |         ...                              ...                   |
+    +----------------------------------------------------------------+
+    |        INFO 0 ID (varint)      |       INFO 0  DATA ...
+    +----------------------------------------------------------------+
+    |         ...                              ...                   |
+    +----------------------------------------------------------------+
+    |                                                                |
+    |                              PAYLOAD                           |
+    |                                                                |
+    +----------------------------------------------------------------+
+
+The `LENGTH` field is 32 bits, and counts the remaining bytes in the
+packet, NOT including the length field.  The header size field is 16
+bits, and defines the size of the header remaining NOT including the
+`HEADER MAGIC`, `FLAGS`, `SEQUENCE NUMBER` and header size fields.  The
+Header size field is in bytes/4.
+
+The transform ID's are varints.  The data for each transform is
+defined by the transform ID in the code - no size is given in the
+header.  If a transform ID is specified from a client and the server
+doesn't know about the transform ID, an error MUST be returned as we
+don't know how to transform the data.
+
+Conversely, data in the info headers is ignorable.  This should only
+be things like timestamps, debuging tracing, etc.  Using the header
+size you should be able to skip this data and read the payload safely
+if you don't know the info ID.
+
+Info's should be oldest supported to newest supported order, so that
+if we read an info ID we don't support, none of the remaining info
+ID's will be supported either, and we can safely skip to the payload.
+
+Info ID's and transform ID's should share the same ID space.
+
+### PADDING:
+
+Header will be padded out to next 4-byte boundary with `0x00`.
+
+Max frame size is `0x3FFFFFFF`, which is slightly less than `HTTP_MAGIC`.
+This allows us to distingush between different (older) transports.
+
+### Transform IDs:
+
+    ZLIB_TRANSFORM 0x01 - No data for this.  Use zlib to (de)compress the
+                          data.
+
+    HMAC_TRANSFORM 0x02 - Variable amount of mac data.  One byte to specify
+                          size. Mac data is appended at the end of the packet.
+    SNAPPY_TRANSFORM  0x03  - No data for this.  Use snappy to (de)compress the
+                          data.
+
+
+###Info IDs:
+
+    INFO_KEYVALUE 0x01 - varint32 number of headers.
+                       - key/value pairs of varstrings (varint16 length plus
+                         no-trailing-null string).
+
diff --git a/doc/specs/idl.md b/doc/specs/idl.md
new file mode 100644
index 0000000..bf22f54
--- /dev/null
+++ b/doc/specs/idl.md
@@ -0,0 +1,272 @@
+## Thrift interface description language
+The Thrift interface definition language (IDL) allows for the definition of [Thrift Types](/docs/types). A Thrift IDL file is processed by the Thrift code generator to produce code for the various target languages to support the defined structs and services in the IDL file.
+
+## Description
+
+*Under construction*
+
+Here is a description of the Thrift IDL.
+
+## Document
+
+Every Thrift document contains 0 or more headers followed by 0 or more definitions.
+
+    [1]  Document        ::=  Header* Definition*
+
+## Header
+
+A header is either a Thrift include, a C++ include, or a namespace declaration.
+
+    [2]  Header          ::=  Include | CppInclude | Namespace
+
+### Thrift Include
+
+An include makes all the symbols from another file visible (with a prefix) and adds corresponding include statements into the code generated for this Thrift document.
+
+    [3]  Include         ::=  'include' Literal
+
+### C++ Include
+
+A C++ include adds a custom C++ include to the output of the C++ code generator for this Thrift document. 
+
+    [4]  CppInclude      ::=  'cpp_include' Literal
+
+### Namespace
+
+A namespace declares which namespaces/package/module/etc. the type definitions in this file will be declared in for the target languages. The namespace scope indicates which language the namespace applies to; a scope of '*' indicates that the namespace applies to all target languages.
+
+    [5]  Namespace       ::=  ( 'namespace' ( NamespaceScope Identifier ) |
+                                            ( 'smalltalk.category' STIdentifier ) |
+                                            ( 'smalltalk.prefix' Identifier ) ) |
+                              ( 'php_namespace' Literal ) |
+                              ( 'xsd_namespace' Literal )
+
+    [6]  NamespaceScope  ::=  '*' | 'cpp' | 'java' | 'py' | 'perl' | 'rb' | 'cocoa' | 'csharp'
+
+N.B.: Smalltalk has two distinct types of namespace commands:
+
+- smalltalk.prefix: Prepended to generated classnames.
+  - Smalltalk does not have namespaces for classes, so prefixes
+    are used to avoid class-name collisions.
+    Often, the prefix is the author's initials, like "KB" or "JWS",
+    or an abbreviation of the package name, like "MC" for "Monticello".
+- smalltalk.category: Determines the category for generated classes.
+  Any dots in the identifier will be replaced with hyphens when generating
+  the category name.
+  If not provided, defaults to "Generated-" + the program name.
+  Methods will not be categorized beyond "as yet uncategorized".
+  - Smalltalk allows filing both classes and methods within classes into named
+    groups. These named groups of methods are called categories.
+
+N.B.: The `php_namespace` directive will be deprecated at some point in the future in favor of the scoped syntax, but the scoped syntax is not yet supported for PHP.
+
+N.B.: The `xsd_namespace` directive has some purpose internal to Facebook but serves no purpose in Thrift itself. Use of this feature is strongly discouraged
+
+## Definition
+
+    [7]  Definition      ::=  Const | Typedef | Enum | Senum | Struct | Union | Exception | Service
+
+### Const
+
+    [8]  Const           ::=  'const' FieldType Identifier '=' ConstValue ListSeparator?
+
+### Typedef
+
+A typedef creates an alternate name for a type.
+
+    [9]  Typedef         ::=  'typedef' DefinitionType Identifier
+
+### Enum
+
+An enum creates an enumerated type, with named values. If no constant value is supplied, the value is either 0 for the first element, or one greater than the preceding value for any subsequent element. Any constant value that is supplied must be non-negative.
+
+    [10] Enum            ::=  'enum' Identifier '{' (Identifier ('=' IntConstant)? ListSeparator?)* '}'
+
+### Senum
+
+Senum (and Slist) are now deprecated and should both be replaced with String.
+
+    [11] Senum           ::=  'senum' Identifier '{' (Literal ListSeparator?)* '}'
+
+### Struct
+
+Structs are the fundamental compositional type in Thrift. The name of each field must be unique within the struct.
+
+    [12] Struct          ::=  'struct' Identifier 'xsd_all'? '{' Field* '}'
+
+N.B.: The `xsd_all` keyword has some purpose internal to Facebook but serves no purpose in Thrift itself. Use of this feature is strongly discouraged
+
+### Union
+
+Unions are similar to structs, except that they provide a means to transport exactly one field of a possible set of fields, just like union {} in C++. Consequently, union members are implicitly considered optional (see requiredness).
+
+    [13] Union          ::=  'union' Identifier 'xsd_all'? '{' Field* '}'
+
+N.B.: The `xsd_all` keyword has some purpose internal to Facebook but serves no purpose in Thrift itself. Use of this feature is strongly discouraged
+
+### Exception
+
+Exceptions are similar to structs except that they are intended to integrate with the native exception handling mechanisms in the target languages. The name of each field must be unique within the exception.
+
+    [14] Exception       ::=  'exception' Identifier '{' Field* '}'
+
+### Service
+
+A service provides the interface for a set of functionality provided by a Thrift server. The interface is simply a list of functions. A service can extend another service, which simply means that it provides the functions of the extended service in addition to its own.
+
+    [15] Service         ::=  'service' Identifier ( 'extends' Identifier )? '{' Function* '}'
+
+## Field
+
+    [16] Field           ::=  FieldID? FieldReq? FieldType Identifier ('= ConstValue)? XsdFieldOptions ListSeparator?
+
+### Field ID
+
+    [17] FieldID         ::=  IntConstant ':'
+
+### Field Requiredness
+
+There are two explicit requiredness values, and a third one that is applied implicity if neither  *required* nor *optional* are given: *default* requiredness.
+
+    [18] FieldReq        ::=  'required' | 'optional' 
+
+The general rules for requiredness are as follows:
+
+#### required
+
+- Write: Required fields are always written and are expected to be set.
+- Read: Required fields are always read and are expected to be contained in the input stream.
+- Defaults values: are always written
+
+If a required field is missing during read, the expected behaviour is to indicate an unsuccessful read operation to the caller, e.g. by throwing an exception or returning an error. 
+
+Because of this behaviour, required fields drastically limit the options with regard to soft versioning. Because they must be present on read, the fields cannot be deprecated. If a required field would be removed (or changed to optional), the data are no longer compatible between versions.
+	
+#### optional
+
+- Write: Optional fields are only written when they are set
+- Read: Optional fields may, or may not be part of the input stream. 
+- Default values: are written when the isset flag is set
+
+Most language implementations use the recommended pratice of so-called "isset" flags to indicate whether a particular optional field is set or not. Only fields with this flag set are written, and conversely the flag is only set when a field value has been read from the input stream. 
+	
+#### default requiredness (implicit)
+
+- Write: In theory, the fields are always written. There are some exceptions to that rule, see below.
+- Read: Like optional, the field may, or may not be part of the input stream. 
+- Default values: may not be written (see next section)
+
+Default requiredness is a good starting point. The desired behaviour is a mix of optional and required, hence the internal name "opt-in, req-out". Although in theory these fields are supposed to be written ("req-out"), in reality unset fields are not always written. This is especially the case, when the field contains a <null> value, which by definition cannot be transported through thrift. The only way to achieve this is by not writing that field at all, and that's what most languages do.
+	
+#### Semantics of Default Values
+
+There are ongoing discussions about that topic, see JIRA for details. Not all implementations treat default values in the very same way, but the current status quo is more or less that default fields are typically set at initialization time. Therefore, a value that equals the default may not be written, because the read end will set the value implicitly. On the other hand, an implementation is free to write the default value anyways, as there is no hard restriction that prevents this. 
+
+The major point to keep in mind here is the fact, that any unwritten default value implicitly becomes part of the interface version. If that default is changed, the interface changes. If, in contrast, the default value is written into the output data, the default in the IDL can change at any time without affecting serialized data.
+
+### XSD Options
+
+N.B.: These have  some internal purpose at Facebook but serve no current purpose in Thrift. Use of these options is strongly discouraged.
+
+    [19] XsdFieldOptions ::=  'xsd_optional'? 'xsd_nillable'? XsdAttrs?
+
+    [20] XsdAttrs        ::=  'xsd_attrs' '{' Field* '}'
+
+## Functions
+
+    [21] Function        ::=  'oneway'? FunctionType Identifier '(' Field* ')' Throws? ListSeparator?
+
+    [22] FunctionType    ::=  FieldType | 'void'
+
+    [23] Throws          ::=  'throws' '(' Field* ')'
+
+## Types
+
+    [24] FieldType       ::=  Identifier | BaseType | ContainerType
+
+    [25] DefinitionType  ::=  BaseType | ContainerType
+
+    [26] BaseType        ::=  'bool' | 'byte' | 'i8' | 'i16' | 'i32' | 'i64' | 'double' | 'string' | 'binary' | 'slist'
+
+    [27] ContainerType   ::=  MapType | SetType | ListType
+
+    [28] MapType         ::=  'map' CppType? '<' FieldType ',' FieldType '>'
+
+    [29] SetType         ::=  'set' CppType? '<' FieldType '>'
+
+    [30] ListType        ::=  'list' '<' FieldType '>' CppType?
+
+    [31] CppType         ::=  'cpp_type' Literal
+
+## Constant Values
+
+    [32] ConstValue      ::=  IntConstant | DoubleConstant | Literal | Identifier | ConstList | ConstMap
+
+    [33] IntConstant     ::=  ('+' | '-')? Digit+
+
+    [34] DoubleConstant  ::=  ('+' | '-')? Digit* ('.' Digit+)? ( ('E' | 'e') IntConstant )?
+
+    [35] ConstList       ::=  '[' (ConstValue ListSeparator?)* ']'
+
+    [36] ConstMap        ::=  '{' (ConstValue ':' ConstValue ListSeparator?)* '}'
+
+## Basic Definitions
+
+### Literal
+
+    [37] Literal         ::=  ('"' [^"]* '"') | ("'" [^']* "'")
+
+### Identifier
+
+    [38] Identifier      ::=  ( Letter | '_' ) ( Letter | Digit | '.' | '_' )*
+
+    [39] STIdentifier    ::=  ( Letter | '_' ) ( Letter | Digit | '.' | '_' | '-' )*
+
+### List Separator
+
+    [40] ListSeparator   ::=  ',' | ';'
+
+### Letters and Digits
+
+    [41] Letter          ::=  ['A'-'Z'] | ['a'-'z']
+
+    [42] Digit           ::=  ['0'-'9']
+
+## Examples
+
+Here are some examples of Thrift definitions, using the Thrift IDL:
+
+ * [ThriftTest.thrift][] used by the Thrift TestFramework
+ * Thrift [tutorial][]
+ * Facebook's [fb303.thrift][]
+ * [Apache Cassandra's][] Thrift IDL: [cassandra.thrift][]
+ * [Evernote API][]
+
+ [ThriftTest.thrift]:  https://raw.githubusercontent.com/apache/thrift/master/test/ThriftTest.thrift
+ [tutorial]:           /tutorial/
+ [fb303.thrift]:       https://raw.githubusercontent.com/apache/thrift/master/contrib/fb303/if/fb303.thrift
+ [Apache Cassandra's]: http://cassandra.apache.org/
+ [cassandra.thrift]:   http://svn.apache.org/viewvc/cassandra/trunk/interface/cassandra.thrift?view=co
+ [Evernote API]:       http://www.evernote.com/about/developer/api/
+
+## To Do/Questions
+
+Initialization of Base Types for all Languages?
+
+ * Do all Languages initialize them to 0, bool=false and string=""? or null, undefined?
+
+Why does position of `CppType` vary between `SetType` and `ListType`?
+
+ * std::set does sort the elements automatically, that's the design. see [Thrift Types](/docs/types) or the [C++ std:set reference][] for further details
+ * The question is, how other languages are doing that? What about custom objects, do they have a Compare function the set the order correctly?
+
+ [C++ std:set reference]: http://www.cplusplus.com/reference/stl/set/
+
+Why can't `DefinitionType` be the same as `FieldType` (i.e. include `Identifier`)?
+
+Examine the `smalltalk.prefix` and `smalltalk.category` status (esp `smalltalk.category`, which takes `STIdentifier` as its argument)...
+
+What to do about `ListSeparator`? Do we really want to be as lax as we currently are?
+
+Should `Field*` really be `Field+` in `Struct`, `Enum`, etc.?
+
diff --git a/doc/specs/thrift-binary-protocol.md b/doc/specs/thrift-binary-protocol.md
new file mode 100644
index 0000000..a852685
--- /dev/null
+++ b/doc/specs/thrift-binary-protocol.md
@@ -0,0 +1,254 @@
+Thrift Binary protocol encoding 
+===============================
+
+<!--
+--------------------------------------------------------------------
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+
+--------------------------------------------------------------------
+-->
+
+This documents describes the wire encoding for RPC using the older Thrift *binary protocol*.
+
+The information here is _mostly_ based on the Java implementation in the Apache thrift library (version 0.9.1 and
+0.9.3). Other implementation however, should behave the same.
+
+For background on Thrift see the [Thrift whitepaper (pdf)](https://thrift.apache.org/static/files/thrift-20070401.pdf).
+
+# Contents
+
+* Binary protocol
+  * Base types
+  * Message
+  * Struct
+  * List and Set
+  * Map
+* BNF notation used in this document
+
+# Binary protocol
+
+## Base types
+
+### Integer encoding
+
+In the _binary protocol_ integers are encoded with the most significant byte first (big endian byte order, aka network
+order). An `int8` needs 1 byte, an `int16` 2, an `int32` 4 and an `int64` needs 8 bytes.
+
+The CPP version has the option to use the binary protocol with little endian order. Little endian gives a small but
+noticeable performance boost because contemporary CPUs use little endian when storing integers to RAM.
+
+### Enum encoding
+
+The generated code encodes `Enum`s by taking the ordinal value and then encoding that as an int32.
+
+### Binary encoding
+
+Binary is sent as follows:
+
+```
+Binary protocol, binary data, 4+ bytes:
++--------+--------+--------+--------+--------+...+--------+
+| byte length                       | bytes                |
++--------+--------+--------+--------+--------+...+--------+
+```
+
+Where:
+
+* `byte length` is the length of the byte array, a signed 32 bit integer encoded in network (big endian) order (must be >= 0).
+* `bytes` are the bytes of the byte array.
+
+### String encoding
+
+*String*s are first encoded to UTF-8, and then send as binary.
+
+### Double encoding
+
+Values of type `double` are first converted to an int64 according to the IEEE 754 floating-point "double format" bit
+layout. Most run-times provide a library to make this conversion. Both the binary protocol as the compact protocol then
+encode the int64 in 8 bytes in big endian order.
+
+### Boolean encoding
+
+Values of `bool` type are first converted to an int8. True is converted to `1`, false to `0`.
+
+## Message
+
+A `Message` can be encoded in two different ways:
+
+```
+Binary protocol Message, strict encoding, 12+ bytes:
++--------+--------+--------+--------+--------+--------+--------+--------+--------+...+--------+--------+--------+--------+--------+
+|1vvvvvvv|vvvvvvvv|unused  |00000mmm| name length                       | name                | seq id                            |
++--------+--------+--------+--------+--------+--------+--------+--------+--------+...+--------+--------+--------+--------+--------+
+```
+
+Where:
+
+* `vvvvvvvvvvvvvvv` is the version, an unsigned 15 bit number fixed to `1` (in binary: `000 0000 0000 0001`).
+  The leading bit is `1`.
+* `unused` is an ignored byte.
+* `mmm` is the message type, an unsigned 3 bit integer. The 5 leading bits must be `0` as some clients (checked for
+  java in 0.9.1) take the whole byte.
+* `name length` is the byte length of the name field, a signed 32 bit integer encoded in network (big endian) order (must be >= 0).
+* `name` is the method name, a UTF-8 encoded string.
+* `seq id` is the sequence id, a signed 32 bit integer encoded in network (big endian) order.
+
+The second, older encoding (aka non-strict) is:
+
+```
+Binary protocol Message, old encoding, 9+ bytes:
++--------+--------+--------+--------+--------+...+--------+--------+--------+--------+--------+--------+
+| name length                       | name                |00000mmm| seq id                            |
++--------+--------+--------+--------+--------+...+--------+--------+--------+--------+--------+--------+
+```
+
+Where `name length`, `name`, `mmm`, `seq id` are as above.
+
+Because `name length` must be positive (therefore the first bit is always `0`), the first bit allows the receiver to see
+whether the strict format or the old format is used. Therefore a server and client using the different variants of the
+binary protocol can transparently talk with each other. However, when strict mode is enforced, the old format is
+rejected.
+
+Message types are encoded with the following values:
+
+* _Call_: 1
+* _Reply_: 2
+* _Exception_: 3
+* _Oneway_: 4
+
+## Struct
+
+A *Struct* is a sequence of zero or more fields, followed by a stop field. Each field starts with a field header and
+is followed by the encoded field value. The encoding can be summarized by the following BNF:
+
+```
+struct        ::= ( field-header field-value )* stop-field
+field-header  ::= field-type field-id
+```
+
+Because each field header contains the field-id (as defined by the Thrift IDL file), the fields can be encoded in any
+order. Thrift's type system is not extensible; you can only encode the primitive types and structs. Therefore is also
+possible to handle unknown fields while decoding; these are simply ignored. While decoding the field type can be used to
+determine how to decode the field value.
+
+Note that the field name is not encoded so field renames in the IDL do not affect forward and backward compatibility.
+
+The default Java implementation (Apache Thrift 0.9.1) has undefined behavior when it tries to decode a field that has
+another field-type then what is expected. Theoretically this could be detected at the cost of some additional checking.
+Other implementation may perform this check and then either ignore the field, or return a protocol exception.
+
+A *Union* is encoded exactly the same as a struct with the additional restriction that at most 1 field may be encoded.
+
+An *Exception* is encoded exactly the same as a struct.
+
+### Struct encoding
+
+In the binary protocol field headers and the stop field are encoded as follows:
+
+```
+Binary protocol field header and field value:
++--------+--------+--------+--------+...+--------+
+|tttttttt| field id        | field value         |
++--------+--------+--------+--------+...+--------+
+
+Binary protocol stop field:
++--------+
+|00000000|
++--------+
+```
+
+Where:
+
+* `tttttttt` the field-type, a signed 8 bit integer.
+* `field id` the field-id, a signed 16 bit integer in big endian order.
+* `field-value` the encoded field value.
+
+The following field-types are used:
+
+* `BOOL`, encoded as `2`
+* `BYTE`, encoded as `3`
+* `DOUBLE`, encoded as `4`
+* `I16`, encoded as `6`
+* `I32`, encoded as `8`
+* `I64`, encoded as `10`
+* `STRING`, used for binary and string fields, encoded as `11`
+* `STRUCT`, used for structs and union fields, encoded as `12`
+* `MAP`, encoded as `13`
+* `SET`, encoded as `14`
+* `LIST`, encoded as `15`
+
+## List and Set
+
+List and sets are encoded the same: a header indicating the size and the element-type of the elements, followed by the
+encoded elements.
+
+```
+Binary protocol list (5+ bytes) and elements:
++--------+--------+--------+--------+--------+--------+...+--------+
+|tttttttt| size                              | elements            |
++--------+--------+--------+--------+--------+--------+...+--------+
+```
+
+Where:
+
+* `tttttttt` is the element-type, encoded as an int8
+* `size` is the size, encoded as an int32, positive values only
+* `elements` the element values
+
+The element-type values are the same as field-types. The full list is included in the struct section above.
+
+The maximum list/set size is configurable. By default there is no limit (meaning the limit is the maximum int32 value:
+2147483647).
+
+## Map
+
+Maps are encoded with a header indicating the size, the element-type of the keys and the element-type of the elements,
+followed by the encoded elements. The encoding follows this BNF:
+
+```
+map  ::=  key-element-type value-element-type size ( key value )*
+```
+
+```
+Binary protocol map (6+ bytes) and key value pairs:
++--------+--------+--------+--------+--------+--------+--------+...+--------+
+|kkkkkkkk|vvvvvvvv| size                              | key value pairs     |
++--------+--------+--------+--------+--------+--------+--------+...+--------+
+```
+
+Where:
+
+* `kkkkkkkk` is the key element-type, encoded as an int8
+* `vvvvvvvv` is the value element-type, encoded as an int8
+* `size` is the size of the map, encoded as an int32, positive values only
+* `key value pairs` are the encoded keys and values
+
+The element-type values are the same as field-types. The full list is included in the struct section above.
+
+The maximum map size is configurable. By default there is no limit (meaning the limit is the maximum int32 value:
+2147483647).
+
+# BNF notation used in this document
+
+The following BNF notation is used:
+
+* a plus `+` appended to an item represents repetition; the item is repeated 1 or more times
+* a star `*` appended to an item represents optional repetition; the item is repeated 0 or more times
+* a pipe `|` between items represents choice, the first matching item is selected
+* parenthesis `(` and `)` are used for grouping multiple items
diff --git a/doc/specs/thrift-compact-protocol.md b/doc/specs/thrift-compact-protocol.md
new file mode 100644
index 0000000..02467dd
--- /dev/null
+++ b/doc/specs/thrift-compact-protocol.md
@@ -0,0 +1,294 @@
+Thrift Compact protocol encoding 
+================================
+
+<!--
+--------------------------------------------------------------------
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+
+--------------------------------------------------------------------
+-->
+
+This documents describes the wire encoding for RPC using the Thrift *compact protocol*.
+
+The information here is _mostly_ based on the Java implementation in the Apache thrift library (version 0.9.1) and
+[THRIFT-110 A more compact format](https://issues.apache.org/jira/browse/THRIFT-110). Other implementation however,
+should behave the same.
+
+For background on Thrift see the [Thrift whitepaper (pdf)](https://thrift.apache.org/static/files/thrift-20070401.pdf).
+
+# Contents
+
+* Compact protocol
+  * Base types
+  * Message
+  * Struct
+  * List and Set
+  * Map
+* BNF notation used in this document
+
+# Compact protocol
+
+## Base types
+
+### Integer encoding
+
+The _compact protocol_ uses multiple encodings for ints: the _zigzag int_, and the _var int_.
+
+Values of type `int32` and `int64` are first transformed to a *zigzag int*. A zigzag int folds positive and negative
+numbers into the positive number space. When we read 0, 1, 2, 3, 4 or 5 from the wire, this is translated to 0, -1, 1,
+-2 or 2 respectively. Here are the (Scala) formulas to convert from int32/int64 to a zigzag int and back:
+
+```scala
+def intToZigZag(n: Int): Int = (n << 1) ^ (n >> 31)
+def zigzagToInt(n: Int): Int = (n >>> 1) ^ - (n & 1)
+def longToZigZag(n: Long): Long = (n << 1) ^ (n >> 63)
+def zigzagToLong(n: Long): Long = (n >>> 1) ^ - (n & 1)
+```
+
+The zigzag int is then encoded as a *var int*. Var ints take 1 to 5 bytes (int32) or 1 to 10 bytes (int64). The most
+significant bit of each byte indicates if more bytes follow. The concatenation of the least significant 7 bits from each
+byte form the number, where the first byte has the most significant bits (so they are in big endian or network order).
+
+Var ints are sometimes used directly inside the compact protocol to represent positive numbers.
+
+To encode an `int16` as zigzag int, it is first converted to an `int32` and then encoded as such. The type `int8` simply
+uses a single byte as in the binary protocol.
+
+### Enum encoding
+
+The generated code encodes `Enum`s by taking the ordinal value and then encoding that as an int32.
+
+### Binary encoding
+
+Binary is sent as follows:
+
+```
+Binary protocol, binary data, 1+ bytes:
++--------+...+--------+--------+...+--------+
+| byte length         | bytes               |
++--------+...+--------+--------+...+--------+
+```
+
+Where:
+
+* `byte length` is the length of the byte array, using var int encoding (must be >= 0).
+* `bytes` are the bytes of the byte array.
+
+### String encoding
+
+*String*s are first encoded to UTF-8, and then send as binary.
+
+### Double encoding
+
+Values of type `double` are first converted to an int64 according to the IEEE 754 floating-point "double format" bit
+layout. Most run-times provide a library to make this conversion. Both the binary protocol as the compact protocol then
+encode the int64 in 8 bytes in big endian order.
+
+### Boolean encoding
+
+Booleans are encoded differently depending on whether it is a field value (in a struct) or an element value (in a set,
+list or map). Field values are encoded directly in the field header. Element values of type `bool` are sent as an int8;
+true as `1` and false as `0`.
+
+## Message
+
+A `Message` on the wire looks as follows:
+
+```
+Compact protocol Message (4+ bytes):
++--------+--------+--------+...+--------+--------+...+--------+--------+...+--------+
+|pppppppp|mmmvvvvv| seq id              | name length         | name                |
++--------+--------+--------+...+--------+--------+...+--------+--------+...+--------+
+```
+
+Where:
+
+* `pppppppp` is the protocol id, fixed to `1000 0010`, 0x82.
+* `mmm` is the message type, an unsigned 3 bit integer.
+* `vvvvv` is the version, an unsigned 5 bit integer, fixed to `00001`.
+* `seq id` is the sequence id, a signed 32 bit integer encoded as a var int.
+* `name length` is the byte length of the name field, a signed 32 bit integer encoded as a var int (must be >= 0).
+* `name` is the method name to invoke, a UTF-8 encoded string.
+
+Message types are encoded with the following values:
+
+* _Call_: 1
+* _Reply_: 2
+* _Exception_: 3
+* _Oneway_: 4
+
+### Struct
+
+A *Struct* is a sequence of zero or more fields, followed by a stop field. Each field starts with a field header and
+is followed by the encoded field value. The encoding can be summarized by the following BNF:
+
+```
+struct        ::= ( field-header field-value )* stop-field
+field-header  ::= field-type field-id
+```
+
+Because each field header contains the field-id (as defined by the Thrift IDL file), the fields can be encoded in any
+order. Thrift's type system is not extensible; you can only encode the primitive types and structs. Therefore is also
+possible to handle unknown fields while decoding; these are simply ignored. While decoding the field type can be used to
+determine how to decode the field value.
+
+Note that the field name is not encoded so field renames in the IDL do not affect forward and backward compatibility.
+
+The default Java implementation (Apache Thrift 0.9.1) has undefined behavior when it tries to decode a field that has
+another field-type than what is expected. Theoretically this could be detected at the cost of some additional checking.
+Other implementation may perform this check and then either ignore the field, or return a protocol exception.
+
+A *Union* is encoded exactly the same as a struct with the additional restriction that at most 1 field may be encoded.
+
+An *Exception* is encoded exactly the same as a struct.
+
+### Struct encoding
+
+```
+Compact protocol field header (short form) and field value:
++--------+--------+...+--------+
+|ddddtttt| field value         |
++--------+--------+...+--------+
+
+Compact protocol field header (1 to 3 bytes, long form) and field value:
++--------+--------+...+--------+--------+...+--------+
+|0000tttt| field id            | field value         |
++--------+--------+...+--------+--------+...+--------+
+
+Compact protocol stop field:
++--------+
+|00000000|
++--------+
+```
+
+Where:
+
+* `dddd` is the field id delta, an unsigned 4 bits integer, strictly positive.
+* `tttt` is field-type id, an unsigned 4 bit integer.
+* `field id` the field id, a signed 16 bit integer encoded as zigzag int.
+* `field-value` the encoded field value.
+
+The field id delta can be computed by `current-field-id - previous-field-id`, or just `current-field-id` if this is the
+first of the struct. The short form should be used when the field id delta is in the range 1 - 15 (inclusive).
+
+The following field-types can be encoded:
+
+* `BOOLEAN_TRUE`, encoded as `1`
+* `BOOLEAN_FALSE`, encoded as `2`
+* `BYTE`, encoded as `3`
+* `I16`, encoded as `4`
+* `I32`, encoded as `5`
+* `I64`, encoded as `6`
+* `DOUBLE`, encoded as `7`
+* `BINARY`, used for binary and string fields, encoded as `8`
+* `LIST`, encoded as `9`
+* `SET`, encoded as `10`
+* `MAP`, encoded as `11`
+* `STRUCT`, used for both structs and union fields, encoded as `12`
+
+Note that because there are 2 specific field types for the boolean values, the encoding of a boolean field value has no
+length (0 bytes).
+
+## List and Set
+
+List and sets are encoded the same: a header indicating the size and the element-type of the elements, followed by the
+encoded elements.
+
+```
+Compact protocol list header (1 byte, short form) and elements:
++--------+--------+...+--------+
+|sssstttt| elements            |
++--------+--------+...+--------+
+
+Compact protocol list header (2+ bytes, long form) and elements:
++--------+--------+...+--------+--------+...+--------+
+|1111tttt| size                | elements            |
++--------+--------+...+--------+--------+...+--------+
+```
+
+Where:
+
+* `ssss` is the size, 4 bit unsigned int, values `0` - `14`
+* `tttt` is the element-type, a 4 bit unsigned int
+* `size` is the size, a var int (int32), positive values `15` or higher
+* `elements` are the encoded elements
+
+The short form should be used when the length is in the range 0 - 14 (inclusive).
+
+The following element-types are used (note that these are _different_ from the field-types):
+
+* `BOOL`, encoded as `2`
+* `BYTE`, encoded as `3`
+* `DOUBLE`, encoded as `4`
+* `I16`, encoded as `6`
+* `I32`, encoded as `8`
+* `I64`, encoded as `10`
+* `STRING`, used for binary and string fields, encoded as `11`
+* `STRUCT`, used for structs and union fields, encoded as `12`
+* `MAP`, encoded as `13`
+* `SET`, encoded as `14`
+* `LIST`, encoded as `15`
+
+
+The maximum list/set size is configurable. By default there is no limit (meaning the limit is the maximum int32 value:
+2147483647).
+
+## Map
+
+Maps are encoded with a header indicating the size, the type of the keys and the element-type of the elements, followed
+by the encoded elements. The encoding follows this BNF:
+
+```
+map           ::= empty-map | non-empty-map
+empty-map     ::= `0`
+non-empty-map ::= size key-element-type value-element-type (key value)+
+```
+
+```
+Compact protocol map header (1 byte, empty map):
++--------+
+|00000000|
++--------+
+
+Compact protocol map header (2+ bytes, non empty map) and key value pairs:
++--------+...+--------+--------+--------+...+--------+
+| size                |kkkkvvvv| key value pairs     |
++--------+...+--------+--------+--------+...+--------+
+```
+
+Where:
+
+* `size` is the size, a var int (int32), strictly positive values
+* `kkkk` is the key element-type, a 4 bit unsigned int
+* `vvvv` is the value element-type, a 4 bit unsigned int
+* `key value pairs` are the encoded keys and values
+
+The element-types are the same as for lists. The full list is included in the 'List and set' section.
+
+The maximum map size is configurable. By default there is no limit (meaning the limit is the maximum int32 value:
+2147483647).
+
+# BNF notation used in this document
+
+The following BNF notation is used:
+
+* a plus `+` appended to an item represents repetition; the item is repeated 1 or more times
+* a star `*` appended to an item represents optional repetition; the item is repeated 0 or more times
+* a pipe `|` between items represents choice, the first matching item is selected
+* parenthesis `(` and `)` are used for grouping multiple items
diff --git a/doc/specs/thrift-protocol-spec.md b/doc/specs/thrift-protocol-spec.md
new file mode 100644
index 0000000..0c1a61c
--- /dev/null
+++ b/doc/specs/thrift-protocol-spec.md
@@ -0,0 +1,101 @@
+Thrift Protocol Structure
+====================================================================
+
+Last Modified: 2007-Jun-29
+
+<!--
+--------------------------------------------------------------------
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+
+--------------------------------------------------------------------
+-->
+
+This document describes the structure of the Thrift protocol
+without specifying the encoding. Thus, the order of elements
+could in some cases be rearranged depending upon the TProtocol
+implementation, but this document specifies the minimum required
+structure. There are some "dumb" terminals like STRING and INT
+that take the place of an actual encoding specification.
+
+They key point to notice is that ALL messages are just one wrapped
+`<struct>`. Depending upon the message type, the `<struct>` can be
+interpreted as the argument list to a function, the return value
+of a function, or an exception.
+
+--------------------------------------------------------------------
+
+```
+       <message> ::= <message-begin> <struct> <message-end>
+
+ <message-begin> ::= <method-name> <message-type> <message-seqid>
+
+   <method-name> ::= STRING
+
+  <message-type> ::= T_CALL | T_REPLY | T_EXCEPTION | T_ONEWAY
+
+ <message-seqid> ::= I32
+
+        <struct> ::= <struct-begin> <field>* <field-stop> <struct-end>
+
+  <struct-begin> ::= <struct-name>
+
+   <struct-name> ::= STRING
+
+    <field-stop> ::= T_STOP
+
+         <field> ::= <field-begin> <field-data> <field-end>
+
+   <field-begin> ::= <field-name> <field-type> <field-id>
+
+    <field-name> ::= STRING
+
+    <field-type> ::= T_BOOL | T_BYTE | T_I8 | T_I16 | T_I32 | T_I64 | T_DOUBLE
+                     | T_STRING | T_BINARY | T_STRUCT | T_MAP | T_SET | T_LIST
+
+      <field-id> ::= I16
+
+    <field-data> ::= I8 | I16 | I32 | I64 | DOUBLE | STRING | BINARY
+                     <struct> | <map> | <list> | <set>
+
+           <map> ::= <map-begin> <field-datum>* <map-end>
+
+     <map-begin> ::= <map-key-type> <map-value-type> <map-size>
+
+  <map-key-type> ::= <field-type>
+
+<map-value-type> ::= <field-type>
+
+      <map-size> ::= I32
+
+          <list> ::= <list-begin> <field-data>* <list-end>
+
+    <list-begin> ::= <list-elem-type> <list-size>
+
+<list-elem-type> ::= <field-type>
+
+     <list-size> ::= I32
+
+           <set> ::= <set-begin> <field-data>* <set-end>
+
+     <set-begin> ::= <set-elem-type> <set-size>
+
+ <set-elem-type> ::= <field-type>
+
+      <set-size> ::= I32
+```
diff --git a/doc/specs/thrift-rpc.md b/doc/specs/thrift-rpc.md
new file mode 100644
index 0000000..d45c06f
--- /dev/null
+++ b/doc/specs/thrift-rpc.md
@@ -0,0 +1,178 @@
+Thrift Remote Procedure Call
+============================
+
+<!--
+--------------------------------------------------------------------
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+
+--------------------------------------------------------------------
+-->
+
+This document describes the high level message exchange between the Thrift RPC client and server.
+See [thrift-binary-protocol.md] and [thrift-compact-protocol.md] for a description of how the exchanges are encoded on
+the wire.
+
+In addition, this document compares the binary protocol with the compact protocol. Finally it describes the framed vs.
+unframed transport.
+
+The information here is _mostly_ based on the Java implementation in the Apache thrift library (version 0.9.1 and
+0.9.3). Other implementation however, should behave the same.
+
+For background on Thrift see the [Thrift whitepaper (pdf)](https://thrift.apache.org/static/files/thrift-20070401.pdf).
+
+# Contents
+
+* Thrift Message exchange for Remote Procedure Call
+  * Message
+  * Request struct
+  * Response struct
+* Protocol considerations
+  * Comparing binary and compact protocol
+  * Compatibility
+  * Framed vs unframed transport
+
+# Thrift Remote Procedure Call Message exchange
+
+Both the binary protocol and the compact protocol assume a transport layer that exposes a bi-directional byte stream,
+for example a TCP socket. Both use the following exchange:
+
+1. Client sends a `Message` (type `Call` or `Oneway`). The TMessage contains some metadata and the name of the method
+   to invoke.
+2. Client sends method arguments (a struct defined by the generate code).
+3. Server sends a `Message` (type `Reply` or `Exception`) to start the response.
+4. Server sends a struct containing the method result or exception.
+
+The pattern is a simple half duplex protocol where the parties alternate in sending a `Message` followed by a struct.
+What these are is described below.
+
+Although the standard Apache Thrift Java clients do not support pipelining (sending multiple requests without waiting
+for an response), the standard Apache Thrift Java servers do support it.
+
+## Message
+
+A *Message* contains:
+
+* _Name_, a string (can be empty).
+* _Message type_, a message types, one of `Call`, `Reply`, `Exception` and `Oneway`.
+* _Sequence id_, a signed int32 integer.
+
+The *sequence id* is a simple message id assigned by the client. The server will use the same sequence id in the
+message of the response. The client uses this number to detect out of order responses. Each client has an int32 field
+which is increased for each message. The sequence id simply wraps around when it overflows.
+
+The *name* indicates the service method name to invoke. The server copies the name in the response message.
+
+When the *multiplexed protocol* is used, the name contains the service name, a colon `:` and the method name. The
+multiplexed protocol is not compatible with other protocols.
+
+The *message type* indicates what kind of message is sent. Clients send requests with TMessages of type `Call` or
+`Oneway` (step 1 in the protocol exchange). Servers send responses with messages of type `Exception` or `Reply` (step
+3).
+
+Type `Reply` is used when the service method completes normally. That is, it returns a value or it throws one of the
+exceptions defined in the Thrift IDL file.
+
+Type `Exception` is used for other exceptions. That is: when the service method throws an exception that is not declared
+in the Thrift IDL file, or some other part of the Thrift stack throws an exception. For example when the server could
+not encode or decode a message or struct.
+
+In the Java implementation (0.9.3) there is different behavior for the synchronous and asynchronous server. In the async
+server all exceptions are send as a `TApplicationException` (see 'Response struct' below). In the synchronous Java
+implementation only (undeclared) exceptions that extend `TException` are send as a `TApplicationException`. Unchecked
+exceptions lead to an immediate close of the connection.
+
+Type `Oneway` is only used starting from Apache Thrift 0.9.3. Earlier versions do _not_ send TMessages of type `Oneway`,
+even for service methods defined with the `oneway` modifier.
+
+When client sends a request with type `Oneway`, the server must _not_ send a response (steps 3 and 4 are skipped). Note
+that the Thrift IDL enforces a return type of `void` and does not allow exceptions for oneway services.
+
+## Request struct
+
+The struct that follows the message of type `Call` or `Oneway` contains the arguments of the service method. The
+argument ids correspond to the field ids. The name of the struct is the name of the method with `_args` appended.
+For methods without arguments an struct is sent without fields.
+
+## Response struct
+
+The struct that follows the message of type `Reply` are structs in which exactly 1 of the following fields is encoded:
+
+* A field with name `success` and id `0`, used in case the method completed normally.
+* An exception field, name and id are as defined in the `throws` clause in the Thrift IDL's service method definition.
+
+When the message is of type `Exception` the struct is encoded as if it was declared by the following IDL:
+
+```
+exception TApplicationException {
+  1: string message,
+  2: i32 type
+}
+```
+
+The following exception types are defined in the java implementation (0.9.3):
+
+* _unknown_: 0, used in case the type from the peer is unknown.
+* _unknown method_: 1, used in case the method requested by the client is unknown by the server.
+* _invalid message type_: 2, no usage was found.
+* _wrong method name_: 3, no usage was found.
+* _bad sequence id_: 4, used internally by the client to indicate a wrong sequence id in the response.
+* _missing result_: 5, used internally by the client to indicate a response without any field (result nor exception).
+* _internal error_: 6, used when the server throws an exception that is not declared in the Thrift IDL file. 
+* _protocol error_: 7, used when something goes wrong during decoding. For example when a list is too long or a required
+ field is missing. 
+* _invalid transform_: 8, no usage was found.
+* _invalid protocol_: 9, no usage was found.
+* _unsupported client type_: 10, no usage was found.
+
+# Protocol considerations
+
+## Comparing binary and compact protocol
+
+The binary protocol is fairly simple and therefore easy to process. The compact protocol needs less bytes to send the
+same data at the cost of additional processing. As bandwidth is usually the bottleneck, the compact protocol is almost
+always slightly faster.
+
+## Compatibility
+
+A server could automatically determine whether a client talks the binary protocol or the compact protocol by
+investigating the first byte. If the value is `1000 0001` or `0000 0000` (assuming a name shorter then ±16 MB) it is the
+binary protocol. When the value is `1000 0010` it is talking the compact protocol.
+
+## Framed vs. unframed transport
+
+The first thrift binary wire format was unframed. This means that information is sent out in a single stream of bytes.
+With unframed transport the (generated) processors will read directly from the socket (though Apache Thrift does try to
+grab all available bytes from the socket in a buffer when it can).
+
+Later, Thrift introduced the framed transport.
+
+With framed transport the full request and response (the TMessage and the following struct) are first written to a
+buffer. Then when the struct is complete (transport method `flush` is hijacked for this), the length of the buffer is
+written to the socket first, followed by the buffered bytes. The combination is called a _frame_. On the receiver side
+the complete frame is first read in a buffer before the message is passed to a processor.
+
+The length prefix is a 4 byte signed int, send in network (big endian) order.
+The following must be true: `0` <= length <= `16384000` (16M).
+
+Framed transport was introduced to ease the implementation of async processors. An async processor is only invoked when
+all data is received. Unfortunately, framed transport is not ideal for large messages as the entire frame stays in
+memory until the message has been processed. In addition, the java implementation merges the incoming data to a single,
+growing byte array. Every time the byte array is full it needs to be copied to a new larger byte array.
+
+Framed and unframed transports are not compatible with each other.
diff --git a/doc/thrift-sasl-spec.txt b/doc/specs/thrift-sasl-spec.txt
similarity index 100%
rename from doc/thrift-sasl-spec.txt
rename to doc/specs/thrift-sasl-spec.txt
diff --git a/doc/thrift.tex b/doc/specs/thrift.tex
similarity index 100%
rename from doc/thrift.tex
rename to doc/specs/thrift.tex
diff --git a/doc/thrift.bnf b/doc/thrift.bnf
deleted file mode 100644
index 24d83f6..0000000
--- a/doc/thrift.bnf
+++ /dev/null
@@ -1,96 +0,0 @@
-Thrift Protocol Structure
-
-Last Modified: 2007-Jun-29
-
---------------------------------------------------------------------
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied. See the License for the
-specific language governing permissions and limitations
-under the License.
-
---------------------------------------------------------------------
-
-This document describes the structure of the Thrift protocol
-without specifying the encoding. Thus, the order of elements
-could in some cases be rearranged depending upon the TProtocol
-implementation, but this document specifies the minimum required
-structure. There are some "dumb" terminals like STRING and INT
-that take the place of an actual encoding specification.
-
-They key point to notice is that ALL messages are just one wrapped
-<struct>. Depending upon the message type, the <struct> can be
-interpreted as the argument list to a function, the return value
-of a function, or an exception.
-
---------------------------------------------------------------------
-
-       <message> ::= <message-begin> <struct> <message-end>
-
- <message-begin> ::= <method-name> <message-type> <message-seqid>
-
-   <method-name> ::= STRING
-
-  <message-type> ::= T_CALL | T_REPLY | T_EXCEPTION
-
- <message-seqid> ::= I32
-
-        <struct> ::= <struct-begin> <field>* <field-stop> <struct-end>
-
-  <struct-begin> ::= <struct-name>
-
-   <struct-name> ::= STRING
-
-    <field-stop> ::= T_STOP
-
-         <field> ::= <field-begin> <field-data> <field-end>
-
-   <field-begin> ::= <field-name> <field-type> <field-id>
-
-    <field-name> ::= STRING
-
-    <field-type> ::= T_BOOL | T_BYTE | T_I8 | T_I16 | T_I32 | T_I64 | T_DOUBLE
-                     | T_STRING | T_BINARY | T_STRUCT | T_MAP | T_SET | T_LIST
-
-      <field-id> ::= I16
-
-    <field-data> ::= I8 | I16 | I32 | I64 | DOUBLE | STRING | BINARY
-                     <struct> | <map> | <list> | <set>
-
-           <map> ::= <map-begin> <field-datum>* <map-end>
-
-     <map-begin> ::= <map-key-type> <map-value-type> <map-size>
-
-  <map-key-type> ::= <field-type>
-
-<map-value-type> ::= <field-type>
-
-      <map-size> ::= I32
-
-          <list> ::= <list-begin> <field-data>* <list-end>
-
-    <list-begin> ::= <list-elem-type> <list-size>
-
-<list-elem-type> ::= <field-type>
-
-     <list-size> ::= I32
-
-           <set> ::= <set-begin> <field-data>* <set-end>
-
-     <set-begin> ::= <set-elem-type> <set-size>
-
- <set-elem-type> ::= <field-type>
-
-      <set-size> ::= I32
diff --git a/dub.json b/dub.json
new file mode 100644
index 0000000..af76afc
--- /dev/null
+++ b/dub.json
@@ -0,0 +1,28 @@
+{
+  "name": "apache-thrift",
+  "description": "Apache Thrift D library",
+  "authors": [
+    "Apache Thrift Developers <dev@thrift.apache.org>"
+  ],
+  "homepage": "http://thrift.apache.org",
+  "license": "Apache-2.0",
+  "dependencies": {
+    "libevent": {
+      "version": "~>2.0.2"
+    },
+    "openssl": {
+      "version": ">=1.1.6"
+    }
+  },
+  "systemDependencies": "On systems with native openssl 1.0.x use dub package openssl~>1.1, on systems with native openssl 1.1.x use dub package openssl~>2.0",
+  "targetType": "library",
+  "sourcePaths": [
+    "lib/d/src" 
+  ],
+  "importPaths": [
+    "lib/d/src"
+  ],
+  "excludedSourceFiles": [
+    "lib/d/src/thrift/index.d"
+  ]
+}
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 1cc5c6c..b6ce20e 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -17,11 +17,15 @@
 # under the License.
 #
 
-SUBDIRS =
+SUBDIRS = json xml
+PRECROSS_TARGET =
 
 if WITH_CPP
+# cpp dir is picked directly by plugin build
+if !WITH_PLUGIN
 SUBDIRS += cpp
 endif
+endif
 
 if WITH_C_GLIB
 SUBDIRS += c_glib
@@ -33,9 +37,10 @@
 
 if WITH_JAVA
 SUBDIRS += java
+PRECROSS_TARGET += precross-java
 # JavaScript unit test depends on java
 # so test only if java, ant & co is available
-SUBDIRS += js/test
+SUBDIRS += js
 endif
 
 if WITH_PYTHON
@@ -62,23 +67,60 @@
 SUBDIRS += php
 endif
 
+if WITH_DART
+SUBDIRS += dart
+endif
+
+if WITH_DOTNETCORE
+SUBDIRS += netcore
+endif
+
 if WITH_GO
 SUBDIRS += go
 endif
 
 if WITH_D
 SUBDIRS += d
+PRECROSS_TARGET += precross-d
+endif
+
+if WITH_NODEJS
+SUBDIRS += nodejs
+PRECROSS_TARGET += precross-nodejs
+SUBDIRS += nodets
+endif
+
+if WITH_LUA
+SUBDIRS += lua
+endif
+
+if WITH_RS
+SUBDIRS += rs
+endif
+
+if WITH_CL
+SUBDIRS += cl
+endif
+
+if WITH_SWIFT
+SUBDIRS += swift
 endif
 
 # All of the libs that don't use Automake need to go in here
 # so they will end up in our release tarballs.
 EXTRA_DIST = \
-			as3 \
-			cocoa \
-			d \
-			delphi \
-			javame \
-			js \
-			nodejs \
-			ocaml \
-			st
+	as3 \
+	cocoa \
+	d \
+	dart \
+	delphi \
+	haxe \
+	javame \
+	js \
+	ocaml \
+	st \
+	ts
+
+precross-%:
+	$(MAKE) -C $* precross
+precross: $(PRECROSS_TARGET)
diff --git a/lib/as3/build.properties b/lib/as3/build.properties
new file mode 100644
index 0000000..8463668
--- /dev/null
+++ b/lib/as3/build.properties
@@ -0,0 +1,5 @@
+# Maven Ant tasks Jar details
+mvn.ant.task.version=2.1.3
+mvn.repo=http://repo1.maven.org/maven2
+mvn.ant.task.url=${mvn.repo}/org/apache/maven/maven-ant-tasks/${mvn.ant.task.version}
+mvn.ant.task.jar=maven-ant-tasks-${mvn.ant.task.version}.jar
diff --git a/lib/as3/build.xml b/lib/as3/build.xml
index 604da42..b0c4c85 100755
--- a/lib/as3/build.xml
+++ b/lib/as3/build.xml
@@ -7,9 +7,9 @@
  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
@@ -19,23 +19,24 @@
  -->
 <project name="libthrift-as3" default="compile" basedir="."
   xmlns:artifact="antlib:org.apache.maven.artifact.ant">
-	
+
   <property name="as3.artifactid" value="${ant.project.name}"/>
-	
+
   <property name="thrift.root" location="${basedir}/../../"/>
   <property name="thrift.java.dir" location="${thrift.root}/lib/java"/>
   <property name="build.tools.dir" location="${thrift.java.dir}/build/tools/"/>
-  <property name="thrift_compiler" value="${thrift.root}/compiler/cpp/thrift"/> 
+  <property name="thrift_compiler" value="${thrift.root}/compiler/cpp/thrift"/>
+  <property file="${basedir}/build.properties"/>
 
   <!-- inherit from the java build file for version and other properties -->
-  <property file="${thrift.java.dir}/build.properties" />
+  <property file="${thrift.java.dir}/gradle.properties" />
 
   <property environment="env"/>
 
   <condition property="version" value="${thrift.version}">
     <isset property="release"/>
   </condition>
-  <property name="version" value="${thrift.version}-snapshot"/>
+  <property name="version" value="${thrift.version}-SNAPSHOT"/>
 
   <property name="as3.final.name" value="${as3.artifactid}-${version}"/>
 
@@ -52,12 +53,13 @@
   <target name="setup.init">
     <tstamp/>
     <mkdir dir="${build.dir}"/>
+    <mkdir dir="${build.tools.dir}"/>
   </target>
 
   <target name="flex.check" unless="FLEX_HOME">
     <fail message='You must set the FLEX_HOME property pointing to your flex SDK, eg. ant -DFLEX_HOME="/Applications/Adobe Flex Builder 3/sdks/3.2.0"'/>
   </target>
-	
+
   <target name="flex.init" depends="flex.check" unless="flex.finished">
     <taskdef resource="flexTasks.tasks" classpath="${FLEX_HOME}/ant/lib/flexTasks.jar" />
     <property name="flex.finished" value="true"/>
@@ -69,10 +71,10 @@
         <include name="**/*.as"/>
       </fileset>
     </path>
-    <pathconvert 
-      property="as.src.classes" 
-      pathsep=" " 
-      dirsep="." 
+    <pathconvert
+      property="as.src.classes"
+      pathsep=" "
+      dirsep="."
       refid="as.src.files"
     >
       <map from="${src}/" to=""/>
@@ -108,21 +110,21 @@
     <artifact:remoteRepository id="apache" url="${apache.repo}"/>
 
     <!-- Pom file information -->
-    <artifact:pom id="pom" 
-      groupId="${thrift.groupid}" 
+    <artifact:pom id="pom"
+      groupId="${thrift.groupid}"
       artifactId="${as3.artifactid}"
-      version="${version}" 
+      version="${version}"
       url="http://thrift.apache.org"
       name="Apache Thrift"
       description="Thrift is a software framework for scalable cross-language services development."
-      packaging="pom"
+      packaging="swc"
     >
       <remoteRepository refid="central"/>
       <remoteRepository refid="apache"/>
       <license name="The Apache Software License, Version 2.0" url="${license}"/>
-      <scm connection="scm:git:https://git-wip-us.apache.org/repos/asf/thrift.git" 
-      developerConnection="scm:git:https://git-wip-us.apache.org/repos/asf/thrift.git"
-      url="https://git-wip-us.apache.org/repos/asf?p=thrift.git"
+      <scm connection="scm:git:https://github.com/apache/thrift.git"
+      developerConnection="scm:git:https://github.com/apache/thrift.git"
+      url="https://github.com/apache/thrift"
       />
       <!-- Thrift Developers -->
       <developer id="mcslee" name="Mark Slee"/>
@@ -176,5 +178,5 @@
     <!-- run with: ant -Drelease=true publish -->
     <signAndDeploy file="${as3.pom.xml}" packaging="pom" classifier="" pom="${as3.pom.xml}"/>
     <signAndDeploy file="${as3.swc.file}" packaging="swc" classifier="" pom="${as3.pom.xml}"/>
-  </target>	
+  </target>
 </project>
diff --git a/lib/as3/coding_standards.md b/lib/as3/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/as3/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/as3/src/org/apache/thrift/protocol/TProtocolError.as b/lib/as3/src/org/apache/thrift/protocol/TProtocolError.as
index c5788db..9fff730 100644
--- a/lib/as3/src/org/apache/thrift/protocol/TProtocolError.as
+++ b/lib/as3/src/org/apache/thrift/protocol/TProtocolError.as
@@ -29,6 +29,7 @@
     public static const SIZE_LIMIT:int = 3;
     public static const BAD_VERSION:int = 4;
     public static const NOT_IMPLEMENTED:int = 5;
+    public static const DEPTH_LIMIT:int = 6;
   
     public function TProtocolError(error:int = UNKNOWN, message:String = "") {
       super(message, error);
diff --git a/lib/as3/src/org/apache/thrift/transport/TFullDuplexHttpClient.as b/lib/as3/src/org/apache/thrift/transport/TFullDuplexHttpClient.as
index 3374986..863c59b 100644
--- a/lib/as3/src/org/apache/thrift/transport/TFullDuplexHttpClient.as
+++ b/lib/as3/src/org/apache/thrift/transport/TFullDuplexHttpClient.as
@@ -195,7 +195,7 @@
         {
             this.output = this.socket;
             this.input = this.socket;
-            this.output.writeUTF("CONNECT " + resource + " HTTP/1.1\n" + "Host: " + host + ":" + port + "\r\n" + "User-Agent: BattleNet\r\n" + "Transfer-Encoding: chunked\r\n" + "content-type: application/x-thrift\r\n" + "Accept: */*\r\n\r\n");
+            this.output.writeUTF("CONNECT " + resource + " HTTP/1.1\n" + "Host: " + host + ":" + port + "\r\n" + "User-Agent: Thrift/AS3\r\n" + "Transfer-Encoding: chunked\r\n" + "content-type: application/x-thrift\r\n" + "Accept: */*\r\n\r\n");
             this.eventDispatcher.dispatchEvent(event);
         }
 
diff --git a/lib/as3/src/org/apache/thrift/transport/TSocket.as b/lib/as3/src/org/apache/thrift/transport/TSocket.as
new file mode 100644
index 0000000..c60d711
--- /dev/null
+++ b/lib/as3/src/org/apache/thrift/transport/TSocket.as
@@ -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 org.apache.thrift.transport
+{
+
+  import flash.events.EventDispatcher;
+  import flash.events.Event;
+  import flash.events.IOErrorEvent;
+  import flash.events.ProgressEvent;
+  import flash.events.SecurityErrorEvent;
+  import flash.errors.EOFError;
+  import flash.errors.IOError;
+  import flash.net.URLLoader;
+  import flash.net.URLLoaderDataFormat;
+  import flash.net.URLRequest;
+  import flash.net.URLRequestMethod;
+  import flash.utils.IDataInput;
+  import flash.utils.IDataOutput;
+  import flash.utils.ByteArray;
+  import flash.net.Socket;
+
+
+  /**
+   * Socket implementation of the TTransport interface. Used for working with a
+   * Thrift Socket Server based implementations.
+   */
+
+  public class TSocket extends TTransport
+  {
+    private var socket:Socket = null;
+
+    private var host:String;
+
+    private var port:int;
+
+    private var obuffer:ByteArray = new ByteArray();
+
+    private var input:IDataInput;
+
+    private var output:IDataOutput;
+
+    private var ioCallback:Function = null;
+
+    private var eventDispatcher:EventDispatcher = new EventDispatcher();
+
+    public function TSocket(host:String, port:int):void
+    {
+      this.host = host;
+      this.port = port;
+    }
+
+    public override function close():void
+    {
+      this.input = null;
+      this.output = null;
+      socket.close()
+    }
+
+    public override function peek():Boolean
+    {
+      if(socket.connected)
+      {
+        trace("Bytes remained:" + socket.bytesAvailable);
+        return socket.bytesAvailable>0;
+      }
+      return false;
+    }
+
+    public override function read(buf:ByteArray, off:int, len:int):int
+    {
+      var n1:int = 0, n2:int = 0, n3:int = 0, n4:int = 0, cidx:int = 2;
+      var chunkSize:ByteArray = new ByteArray();
+
+      try
+      {
+        input.readBytes(buf, off, len);
+        return len;
+      }
+      catch (e:EOFError)
+      {
+        trace(e);
+        throw new TTransportError(TTransportError.END_OF_FILE, "No more data available.");
+      }
+      catch (e:IOError)
+      {
+        trace(e);
+        if(isOpen())
+        {
+          throw new TTransportError(TTransportError.UNKNOWN, "IO error while reading: " + e);
+        }
+        else
+        {
+          throw new TTransportError(TTransportError.NOT_OPEN, "Socket seem not to be opened: " + e);
+    	}
+      }
+      catch (e:Error)
+      {
+        trace(e);
+        throw new TTransportError(TTransportError.UNKNOWN, "Bad IO error: " + e);
+      }
+      return 0;
+    }
+
+    public override function write(buf:ByteArray, off:int, len:int):void
+    {
+      obuffer.writeBytes(buf, off, len);
+    }
+
+    public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
+    {
+      this.eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
+    }
+    
+    public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
+    {
+      this.eventDispatcher.removeEventListener(type, listener, useCapture);
+    }
+
+    public override function open():void
+    {
+      this.socket = new Socket();
+      this.socket.addEventListener(Event.CONNECT, socketConnected);
+      this.socket.addEventListener(IOErrorEvent.IO_ERROR, socketError);
+      this.socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, socketSecurityError);
+      this.socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
+      this.socket.connect(host, port);
+    }
+
+    public function socketConnected(event:Event):void
+    {
+      this.output = this.socket;
+      this.input = this.socket;
+      this.eventDispatcher.dispatchEvent(event);
+    }
+
+    public function socketError(event:IOErrorEvent):void
+    {
+      trace("Error Connecting:" + event);
+      this.close();
+      if (ioCallback == null)
+      {
+        return;
+      }
+      ioCallback(new TTransportError(TTransportError.UNKNOWN, "IOError: " + event.text));
+      this.eventDispatcher.dispatchEvent(event);
+    }
+
+    public function socketSecurityError(event:SecurityErrorEvent):void
+    {
+      trace("Security Error Connecting:" + event);
+      this.close();
+      this.eventDispatcher.dispatchEvent(event);
+    }
+
+    public function socketDataHandler(event:ProgressEvent):void
+    {
+      if (ioCallback != null)
+      {
+        ioCallback(null);
+      }
+      this.eventDispatcher.dispatchEvent(event);
+    }
+
+    public override function flush(callback:Function = null):void
+    {
+      this.ioCallback = callback;
+      this.output.writeBytes(this.obuffer);
+      this.socket.flush();
+      this.obuffer.clear();
+    }
+
+    public override function isOpen():Boolean
+    {
+      return (this.socket == null ? false : this.socket.connected);
+    }
+  }
+}
diff --git a/lib/c_glib/CMakeLists.txt b/lib/c_glib/CMakeLists.txt
new file mode 100644
index 0000000..3743a68
--- /dev/null
+++ b/lib/c_glib/CMakeLists.txt
@@ -0,0 +1,86 @@
+#
+# 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.
+#
+
+# Find required packages
+find_package(GLIB REQUIRED COMPONENTS gobject)
+include_directories(${GLIB_INCLUDE_DIRS})
+
+include_directories(src)
+
+# SYSLIBS contains libraries that need to be linked to all lib targets
+set(SYSLIBS ${GLIB_LIBRARIES} ${GLIB_GOBJECT_LIBRARIES})
+
+# Create the thrift C glib library
+set(thrift_c_glib_SOURCES
+    src/thrift/c_glib/thrift.c
+    src/thrift/c_glib/thrift_struct.c
+    src/thrift/c_glib/thrift_application_exception.c
+    src/thrift/c_glib/processor/thrift_processor.c
+    src/thrift/c_glib/processor/thrift_dispatch_processor.c
+    src/thrift/c_glib/processor/thrift_multiplexed_processor.c
+    src/thrift/c_glib/protocol/thrift_protocol.c
+    src/thrift/c_glib/protocol/thrift_protocol_factory.c
+    src/thrift/c_glib/protocol/thrift_protocol_decorator.c
+    src/thrift/c_glib/protocol/thrift_binary_protocol.c
+    src/thrift/c_glib/protocol/thrift_stored_message_protocol.c
+    src/thrift/c_glib/protocol/thrift_binary_protocol_factory.c
+    src/thrift/c_glib/protocol/thrift_compact_protocol.c
+    src/thrift/c_glib/protocol/thrift_compact_protocol_factory.c
+    src/thrift/c_glib/transport/thrift_transport.c
+    src/thrift/c_glib/transport/thrift_transport_factory.c
+    src/thrift/c_glib/transport/thrift_buffered_transport_factory.c
+    src/thrift/c_glib/transport/thrift_framed_transport_factory.c
+    src/thrift/c_glib/transport/thrift_socket.c
+    src/thrift/c_glib/transport/thrift_server_transport.c
+    src/thrift/c_glib/transport/thrift_server_socket.c
+    src/thrift/c_glib/transport/thrift_buffered_transport.c
+    src/thrift/c_glib/transport/thrift_fd_transport.c
+    src/thrift/c_glib/transport/thrift_framed_transport.c
+    src/thrift/c_glib/transport/thrift_memory_buffer.c
+    src/thrift/c_glib/server/thrift_server.c
+    src/thrift/c_glib/server/thrift_simple_server.c
+)
+
+# If OpenSSL is not found just ignore the OpenSSL stuff
+find_package(OpenSSL)
+if(OPENSSL_FOUND AND WITH_OPENSSL)
+    list( APPEND thriftcpp_SOURCES
+	    src/thrift/c_glib/transport/thrift_ssl_socket.c
+    )
+    include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
+    list(APPEND SYSLIBS "${OPENSSL_LIBRARIES}")
+endif()
+
+
+# Contains the thrift specific ADD_LIBRARY_THRIFT and TARGET_LINK_LIBRARIES_THRIFT
+include(ThriftMacros)
+
+ADD_LIBRARY_THRIFT(thrift_c_glib ${thrift_c_glib_SOURCES})
+TARGET_LINK_LIBRARIES_THRIFT(thrift_c_glib ${SYSLIBS})
+
+# Install the headers
+install(DIRECTORY "src/thrift" DESTINATION "${INCLUDE_INSTALL_DIR}"
+    FILES_MATCHING PATTERN "*.h")
+# Copy config.h file
+install(DIRECTORY "${CMAKE_BINARY_DIR}/thrift" DESTINATION "${INCLUDE_INSTALL_DIR}"
+    FILES_MATCHING PATTERN "*.h")
+
+if(BUILD_TESTING)
+    add_subdirectory(test)
+endif()
diff --git a/lib/c_glib/Makefile.am b/lib/c_glib/Makefile.am
index 3244f74..49b5b23 100755
--- a/lib/c_glib/Makefile.am
+++ b/lib/c_glib/Makefile.am
@@ -16,7 +16,7 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-.NOTPARALLEL:
+AUTOMAKE_OPTIONS = serial-tests
 SUBDIRS = . test
 
 pkgconfigdir = $(libdir)/pkgconfig
@@ -24,11 +24,8 @@
 lib_LTLIBRARIES = libthrift_c_glib.la
 pkgconfig_DATA = thrift_c_glib.pc
 
-common_cflags = -g -Wall -W -Werror -Isrc -I src/thrift/c_glib $(GLIB_CFLAGS)
-common_ldflags = -g -Wall -W $(GLIB_LDFLAGS) @GCOV_LDFLAGS@
-
-# this removes optimizations and adds coverage flags
-CFLAGS = @GCOV_CFLAGS@
+AM_CPPFLAGS = -Isrc -I src/thrift/c_glib
+AM_CFLAGS = -Wall -Wextra -pedantic
 
 # Define the source files for the module
 
@@ -36,22 +33,34 @@
                               src/thrift/c_glib/thrift_struct.c \
                               src/thrift/c_glib/thrift_application_exception.c \
                               src/thrift/c_glib/processor/thrift_processor.c \
+                              src/thrift/c_glib/processor/thrift_dispatch_processor.c \
+                              src/thrift/c_glib/processor/thrift_multiplexed_processor.c \
                               src/thrift/c_glib/protocol/thrift_protocol.c \
+                              src/thrift/c_glib/protocol/thrift_protocol_decorator.c \
                               src/thrift/c_glib/protocol/thrift_protocol_factory.c \
                               src/thrift/c_glib/protocol/thrift_binary_protocol.c \
+                              src/thrift/c_glib/protocol/thrift_stored_message_protocol.c \
+                              src/thrift/c_glib/protocol/thrift_multiplexed_protocol.c \
                               src/thrift/c_glib/protocol/thrift_binary_protocol_factory.c \
+                              src/thrift/c_glib/protocol/thrift_compact_protocol.c \
+                              src/thrift/c_glib/protocol/thrift_compact_protocol_factory.c \
                               src/thrift/c_glib/transport/thrift_transport.c \
                               src/thrift/c_glib/transport/thrift_transport_factory.c \
+                              src/thrift/c_glib/transport/thrift_buffered_transport_factory.c \
+                              src/thrift/c_glib/transport/thrift_framed_transport_factory.c \
                               src/thrift/c_glib/transport/thrift_socket.c \
+                              src/thrift/c_glib/transport/thrift_ssl_socket.c \
                               src/thrift/c_glib/transport/thrift_server_transport.c \
                               src/thrift/c_glib/transport/thrift_server_socket.c \
                               src/thrift/c_glib/transport/thrift_buffered_transport.c \
+                              src/thrift/c_glib/transport/thrift_fd_transport.c \
                               src/thrift/c_glib/transport/thrift_framed_transport.c \
                               src/thrift/c_glib/transport/thrift_memory_buffer.c \
                               src/thrift/c_glib/server/thrift_server.c \
                               src/thrift/c_glib/server/thrift_simple_server.c
 
-libthrift_c_glib_la_CFLAGS = $(common_cflags)
+libthrift_c_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(OPENSSL_INCLUDES)
+libthrift_c_glib_la_LDFLAGS = $(AM_LDFLAGS) $(GLIB_LIBS) $(GOBJECT_LIBS)  $(OPENSSL_LDFLAGS) $(OPENSSL_LIBS) 
 
 include_thriftdir = $(includedir)/thrift/c_glib
 include_thrift_HEADERS = \
@@ -62,30 +71,45 @@
 
 include_protocoldir = $(include_thriftdir)/protocol
 include_protocol_HEADERS = src/thrift/c_glib/protocol/thrift_protocol.h \
+                           src/thrift/c_glib/protocol/thrift_protocol_decorator.h \
                            src/thrift/c_glib/protocol/thrift_protocol_factory.h \
                            src/thrift/c_glib/protocol/thrift_binary_protocol.h \
-                           src/thrift/c_glib/protocol/thrift_binary_protocol_factory.h
+                           src/thrift/c_glib/protocol/thrift_binary_protocol_factory.h \
+                           src/thrift/c_glib/protocol/thrift_compact_protocol.h \
+                           src/thrift/c_glib/protocol/thrift_compact_protocol_factory.h \
+                           src/thrift/c_glib/protocol/thrift_multiplexed_protocol.h \
+                           src/thrift/c_glib/protocol/thrift_stored_message_protocol.h
+                           
 
 include_transportdir = $(include_thriftdir)/transport
 include_transport_HEADERS = src/thrift/c_glib/transport/thrift_buffered_transport.h \
+                            src/thrift/c_glib/transport/thrift_fd_transport.h \
                             src/thrift/c_glib/transport/thrift_framed_transport.h \
                             src/thrift/c_glib/transport/thrift_memory_buffer.h \
                             src/thrift/c_glib/transport/thrift_server_socket.h \
                             src/thrift/c_glib/transport/thrift_server_transport.h \
                             src/thrift/c_glib/transport/thrift_socket.h \
+                            src/thrift/c_glib/transport/thrift_platform_socket.h \
+                            src/thrift/c_glib/transport/thrift_ssl_socket.h \
                             src/thrift/c_glib/transport/thrift_transport.h \
-                            src/thrift/c_glib/transport/thrift_transport_factory.h
+                            src/thrift/c_glib/transport/thrift_transport_factory.h \
+                            src/thrift/c_glib/transport/thrift_buffered_transport_factory.h \
+                            src/thrift/c_glib/transport/thrift_framed_transport_factory.h
 
 include_serverdir = $(include_thriftdir)/server
 include_server_HEADERS = src/thrift/c_glib/server/thrift_server.h \
                          src/thrift/c_glib/server/thrift_simple_server.h
 
 include_processordir = $(include_thriftdir)/processor
-include_processor_HEADERS = src/thrift/c_glib/processor/thrift_processor.h
+include_processor_HEADERS = src/thrift/c_glib/processor/thrift_processor.h \
+                            src/thrift/c_glib/processor/thrift_dispatch_processor.h \
+                            src/thrift/c_glib/processor/thrift_multiplexed_processor.h
 
 
 EXTRA_DIST = \
-             README \
+             CMakeLists.txt \
+             coding_standards.md \
+             README.md \
              test/glib.suppress \
              thrift_c_glib.pc.in
 
diff --git a/lib/c_glib/README b/lib/c_glib/README
deleted file mode 100644
index fd70d08..0000000
--- a/lib/c_glib/README
+++ /dev/null
@@ -1,34 +0,0 @@
-Thrift C Software Library
-
-License
-=======
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-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.
-
-Using Thrift with C
-===================
-
-The Thrift C libraries are built using the GNU tools.  Follow the instructions
-in the top-level README in order to generate the Makefiles.
-
-Dependencies
-============
-
-GLib
-http://www.gtk.org/
-
diff --git a/lib/c_glib/README.md b/lib/c_glib/README.md
new file mode 100644
index 0000000..dd84f3d
--- /dev/null
+++ b/lib/c_glib/README.md
@@ -0,0 +1,49 @@
+Thrift C Software Library
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+Using Thrift with C
+===================
+
+The Thrift C libraries are built using the GNU tools.  Follow the instructions
+in the top-level README in order to generate the Makefiles.
+
+Dependencies
+============
+
+GLib
+http://www.gtk.org/
+
+Breaking Changes
+================
+
+0.12.0
+------
+
+The compiler's handling of namespaces when generating the name of types,
+functions and header files has been improved. This means code written to use
+classes generated by previous versions of the compiler may need to be updated to
+reflect the proper convention for class names, which is
+
+- A lowercase, [snake-case](https://en.wikipedia.org/wiki/Snake_case)
+  representation of the class' namespace, followed by
+- An underscore and
+- A lowercase, snake-case representation of the class' name.
diff --git a/lib/c_glib/coding_standards.md b/lib/c_glib/coding_standards.md
new file mode 100644
index 0000000..24b3a00
--- /dev/null
+++ b/lib/c_glib/coding_standards.md
@@ -0,0 +1,5 @@
+## C Glib Coding Standards
+
+Please follow:
+ * [Thrift General Coding Standards](/doc/coding_standards.md)
+ * [GNOME C Coding Style](https://help.gnome.org/users/programming-guidelines/stable/c-coding-style.html.en)
diff --git a/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.c b/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.c
new file mode 100644
index 0000000..57d6217
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.c
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/thrift_application_exception.h>
+#include <thrift/c_glib/processor/thrift_dispatch_processor.h>
+
+G_DEFINE_ABSTRACT_TYPE (ThriftDispatchProcessor,
+                        thrift_dispatch_processor,
+                        THRIFT_TYPE_PROCESSOR)
+
+gboolean
+thrift_dispatch_processor_process (ThriftProcessor *processor,
+                                   ThriftProtocol *in,
+                                   ThriftProtocol *out,
+                                   GError **error)
+{
+  gchar *fname;
+  ThriftMessageType mtype;
+  gint32 seqid;
+  ThriftDispatchProcessor *dispatch_processor =
+    THRIFT_DISPATCH_PROCESSOR (processor);
+
+  /* Read the start of the message, which we expect to be a method call */
+  if (thrift_protocol_read_message_begin (in,
+                                          &fname,
+                                          &mtype,
+                                          &seqid,
+                                          error) < 0) {
+    g_warning ("error reading start of message: %s",
+               (error != NULL) ? (*error)->message : "(null)");
+    return FALSE;
+  }
+  else if (mtype != T_CALL && mtype != T_ONEWAY) {
+    g_warning ("received invalid message type %d from client", mtype);
+    return FALSE;
+  }
+
+  /* Dispatch the method call */
+  return THRIFT_DISPATCH_PROCESSOR_GET_CLASS (dispatch_processor)
+    ->dispatch_call (dispatch_processor,
+                     in,
+                     out,
+                     fname,
+                     seqid,
+                     error);
+}
+
+static gboolean
+thrift_dispatch_processor_real_dispatch_call (ThriftDispatchProcessor *self,
+                                              ThriftProtocol *in,
+                                              ThriftProtocol *out,
+                                              gchar *fname,
+                                              gint32 seqid,
+                                              GError **error)
+{
+  ThriftTransport *transport;
+  ThriftApplicationException *xception;
+  gchar *message;
+  gint32 result;
+  gboolean dispatch_result = FALSE;
+
+  THRIFT_UNUSED_VAR (self);
+
+  /* By default, return an application exception to the client indicating the
+     method name is not recognized. */
+
+  if ((thrift_protocol_skip (in, T_STRUCT, error) < 0) ||
+      (thrift_protocol_read_message_end (in, error) < 0))
+    return FALSE;
+
+  g_object_get (in, "transport", &transport, NULL);
+  result = thrift_transport_read_end (transport, error);
+  g_object_unref (transport);
+  if (result < 0)
+    return FALSE;
+
+  if (thrift_protocol_write_message_begin (out,
+                                           fname,
+                                           T_EXCEPTION,
+                                           seqid,
+                                           error) < 0)
+    return FALSE;
+  message = g_strconcat ("Invalid method name: '", fname, "'", NULL);
+  g_free (fname);
+  xception =
+    g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION,
+                  "type",    THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN_METHOD,
+                  "message", message,
+                  NULL);
+  g_free (message);
+  result = thrift_struct_write (THRIFT_STRUCT (xception),
+                                out,
+                                error);
+  g_object_unref (xception);
+  if ((result < 0) ||
+      (thrift_protocol_write_message_end (out, error) < 0))
+    return FALSE;
+
+  g_object_get (out, "transport", &transport, NULL);
+  dispatch_result =
+    ((thrift_transport_write_end (transport, error) >= 0) &&
+     (thrift_transport_flush (transport, error) >= 0));
+  g_object_unref (transport);
+
+  return dispatch_result;
+}
+
+static void
+thrift_dispatch_processor_init (ThriftDispatchProcessor *self)
+{
+  THRIFT_UNUSED_VAR (self);
+}
+
+static void
+thrift_dispatch_processor_class_init (ThriftDispatchProcessorClass *klass)
+{
+  ThriftProcessorClass *processor_class =
+    THRIFT_PROCESSOR_CLASS (klass);
+
+  /* Implement ThriftProcessor's process method */
+  processor_class->process = thrift_dispatch_processor_process;
+
+  /* Provide a default implement for dispatch_call, which returns an exception
+     to the client indicating the method name was not recognized */
+  klass->dispatch_call = thrift_dispatch_processor_real_dispatch_call;
+}
diff --git a/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.h b/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.h
new file mode 100644
index 0000000..5afb85e
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.h
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef _THRIFT_DISPATCH_PROCESSOR_H
+#define _THRIFT_DISPATCH_PROCESSOR_H
+
+#include <glib-object.h>
+
+#include <thrift/c_glib/processor/thrift_processor.h>
+
+G_BEGIN_DECLS
+
+/*! \file thrift_dispatch_processor.h
+ *  \brief Parses a method-call message header and invokes a function
+ *         to dispatch the call by function name.
+ *
+ * ThriftDispatchProcessor is an abstract helper class that parses the
+ * header of a method-call message and invokes a member function,
+ * dispatch_call, with the method's name.
+ *
+ * Subclasses must implement dispatch_call to dispatch the method call
+ * to the implementing function.
+ */
+
+/* Type macros */
+#define THRIFT_TYPE_DISPATCH_PROCESSOR (thrift_dispatch_processor_get_type ())
+#define THRIFT_DISPATCH_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_DISPATCH_PROCESSOR, ThriftDispatchProcessor))
+#define THRIFT_IS_DISPATCH_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_DISPATCH_PROCESSOR))
+#define THRIFT_DISPATCH_PROCESSOR_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_DISPATCH_PROCESSOR, ThriftDispatchProcessorClass))
+#define THRIFT_IS_DISPATCH_PROCESSOR_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_DISPATCH_PROCESSOR))
+#define THRIFT_DISPATCH_PROCESSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_DISPATCH_PROCESSOR, ThriftDispatchProcessorClass))
+
+/*!
+ * Thrift Dispatch Processor object
+ */
+struct _ThriftDispatchProcessor
+{
+  ThriftProcessor parent;
+};
+typedef struct _ThriftDispatchProcessor ThriftDispatchProcessor;
+
+/*!
+ * Thrift Dispatch Processor class
+ */
+struct _ThriftDispatchProcessorClass
+{
+  ThriftProcessorClass parent;
+
+  /* public */
+  gboolean (*process) (ThriftProcessor *processor,
+                       ThriftProtocol *in,
+                       ThriftProtocol *out,
+                       GError **error);
+
+  /* protected */
+  gboolean (*dispatch_call) (ThriftDispatchProcessor *self,
+                             ThriftProtocol *in,
+                             ThriftProtocol *out,
+                             gchar *fname,
+                             gint32 seqid,
+                             GError **error);
+};
+typedef struct _ThriftDispatchProcessorClass ThriftDispatchProcessorClass;
+
+/* Used by THRIFT_TYPE_DISPATCH_PROCESSOR */
+GType thrift_dispatch_processor_get_type (void);
+
+/*!
+ * Processes a request.
+ * \public \memberof ThriftDispatchProcessorClass
+ */
+gboolean thrift_dispatch_processor_process (ThriftProcessor *processor,
+                                            ThriftProtocol *in,
+                                            ThriftProtocol *out,
+                                            GError **error);
+
+G_END_DECLS
+
+#endif /* _THRIFT_DISPATCH_PROCESSOR_H */
diff --git a/lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.c b/lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.c
new file mode 100644
index 0000000..68a0f4d
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.c
@@ -0,0 +1,346 @@
+/*
+ * 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.
+ */
+#include <string.h>
+#include <stdio.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/processor/thrift_processor.h>
+#include <thrift/c_glib/processor/thrift_multiplexed_processor.h>
+#include <thrift/c_glib/protocol/thrift_multiplexed_protocol.h>
+#include <thrift/c_glib/protocol/thrift_stored_message_protocol.h>
+#include <thrift/c_glib/thrift_application_exception.h>
+
+G_DEFINE_TYPE(ThriftMultiplexedProcessor, thrift_multiplexed_processor, THRIFT_TYPE_PROCESSOR)
+
+
+enum
+{
+  PROP_THRIFT_MULTIPLEXED_PROCESSOR_DEFAULT_SERVICE_NAME = 1,
+  PROP_THRIFT_MULTIPLEXED_PROCESSOR_END
+};
+
+static GParamSpec *thrift_multiplexed_processor_obj_properties[PROP_THRIFT_MULTIPLEXED_PROCESSOR_END] = { NULL, };
+
+
+static gboolean
+thrift_multiplexed_processor_register_processor_impl(ThriftProcessor *processor, const gchar * multiplexed_processor_name, ThriftProcessor * multiplexed_processor , GError **error)
+{
+  ThriftMultiplexedProcessor *self = THRIFT_MULTIPLEXED_PROCESSOR(processor);
+  g_hash_table_replace(self->multiplexed_services,
+		       g_strdup(multiplexed_processor_name),
+		       g_object_ref (multiplexed_processor));
+
+  /* Make first registered become default */
+  if(!self->default_processor_name){
+      self->default_processor_name = g_strdup(multiplexed_processor_name);
+  }
+  return TRUE;
+}
+
+
+static gboolean
+thrift_multiplexed_processor_process_impl (ThriftProcessor *processor, ThriftProtocol *in,
+					   ThriftProtocol *out, GError **error)
+{
+  gboolean retval = FALSE;
+  gboolean token_error = FALSE;
+  ThriftApplicationException *xception;
+  ThriftStoredMessageProtocol *stored_message_protocol = NULL;
+  ThriftMessageType message_type;
+  ThriftMultiplexedProcessor *self = THRIFT_MULTIPLEXED_PROCESSOR(processor);
+  ThriftProcessor *multiplexed_processor = NULL;
+  ThriftTransport *transport;
+  char *token=NULL;
+  int token_index=0;
+  char *state=NULL;
+  gchar *fname=NULL;
+  gint32 seqid, result;
+
+  /* FIXME It seems that previous processor is not managing error correctly */
+  if(*error!=NULL) {
+      g_debug ("thrift_multiplexed_processor: last error not removed: %s",
+      		   *error != NULL ? (*error)->message : "(null)");
+      g_clear_error (error);
+  }
+
+
+  THRIFT_PROTOCOL_GET_CLASS(in)->read_message_begin(in, &fname, &message_type, &seqid, error);
+
+  if(!(message_type == T_CALL || message_type == T_ONEWAY)) {
+      g_set_error (error,
+		   THRIFT_MULTIPLEXED_PROCESSOR_ERROR,
+		   THRIFT_MULTIPLEXED_PROCESSOR_ERROR_MESSAGE_TYPE,
+		   "message type invalid for this processor");
+  }else{
+      /* Split by the token */
+      for (token = strtok_r(fname, THRIFT_MULTIPLEXED_PROTOCOL_DEFAULT_SEPARATOR, &state),
+	  token_index=0;
+	  token != NULL && !token_error;
+	  token = strtok_r(NULL, THRIFT_MULTIPLEXED_PROTOCOL_DEFAULT_SEPARATOR, &state),
+	      token_index++)
+	{
+	  switch(token_index){
+	    case 0:
+	      /* It should be the service name */
+	      multiplexed_processor = g_hash_table_lookup(self->multiplexed_services, token);
+	      if(multiplexed_processor==NULL){
+		  token_error=TRUE;
+	      }
+	      break;
+	    case 1:
+	      /* It should be the function name */
+	      stored_message_protocol = g_object_new (THRIFT_TYPE_STORED_MESSAGE_PROTOCOL,
+						      "protocol", in,
+						      "name", token,
+						      "type", message_type,
+						      "seqid", seqid,
+						      NULL);
+	      break;
+	    default:
+	      g_set_error (error,
+			   THRIFT_MULTIPLEXED_PROCESSOR_ERROR,
+			   THRIFT_MULTIPLEXED_PROCESSOR_ERROR_MESSAGE_WRONGLY_MULTIPLEXED,
+			   "the message has more tokens than expected!");
+	      token_error=TRUE;
+	      break;
+	  }
+	}
+      /* Set default */
+      if(!stored_message_protocol &&
+	  !multiplexed_processor &&
+	  token_index==1 && self->default_processor_name){
+	  /* It should be the service name */
+	  multiplexed_processor = g_hash_table_lookup(self->multiplexed_services, self->default_processor_name);
+	  if(multiplexed_processor==NULL){
+	      g_set_error (error,
+			   THRIFT_MULTIPLEXED_PROCESSOR_ERROR,
+			   THRIFT_MULTIPLEXED_PROCESSOR_ERROR_SERVICE_UNAVAILABLE,
+			   "service %s not available on this processor",
+			   self->default_processor_name);
+	  }else{
+	      /* Set the message name to the original name */
+	      stored_message_protocol = g_object_new (THRIFT_TYPE_STORED_MESSAGE_PROTOCOL,
+						      "protocol", in,
+						      "name", fname,
+						      "type", message_type,
+						      "seqid", seqid,
+						      NULL);
+	  }
+
+      }
+
+      if(stored_message_protocol!=NULL && multiplexed_processor!=NULL){
+	  retval = THRIFT_PROCESSOR_GET_CLASS (multiplexed_processor)->process (multiplexed_processor, (ThriftProtocol *) stored_message_protocol, out, error) ;
+      }else{
+	  if(!error)
+	  g_set_error (error,
+		       THRIFT_MULTIPLEXED_PROCESSOR_ERROR,
+		       THRIFT_MULTIPLEXED_PROCESSOR_ERROR_SERVICE_UNAVAILABLE,
+		       "service %s is not multiplexed in this processor",
+		       fname);
+      }
+
+
+  }
+
+  if(!retval){
+      /* By default, return an application exception to the client indicating the
+          method name is not recognized. */
+      /* Copied from dispach processor */
+
+      if ((thrift_protocol_skip (in, T_STRUCT, error) < 0) ||
+	  (thrift_protocol_read_message_end (in, error) < 0))
+	return retval;
+
+      g_object_get (in, "transport", &transport, NULL);
+      result = thrift_transport_read_end (transport, error);
+      g_object_unref (transport);
+      if (result < 0) {
+	  /* We must free fname */
+	  g_free(fname);
+	  return retval;
+      }
+
+      if (thrift_protocol_write_message_begin (out,
+					       fname,
+					       T_EXCEPTION,
+					       seqid,
+					       error) < 0){
+	  /* We must free fname */
+	  g_free(fname);
+
+	  return retval;
+      }
+
+
+      xception =
+	  g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION,
+			"type",    THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN_METHOD,
+			"message", (*error)->message,
+			NULL);
+      result = thrift_struct_write (THRIFT_STRUCT (xception),
+				    out,
+				    error);
+      g_object_unref (xception);
+      if ((result < 0) ||
+	  (thrift_protocol_write_message_end (out, error) < 0))
+	return retval;
+
+      g_object_get (out, "transport", &transport, NULL);
+      retval =
+	  ((thrift_transport_write_end (transport, error) >= 0) &&
+	      (thrift_transport_flush (transport, error) >= 0));
+      g_object_unref (transport);
+  }else{
+      /* The protocol now has a copy we can free it */
+      g_free(fname);
+
+  }
+
+  /*
+  FIXME This makes everything fail, I don't know why.
+  if(stored_message_protocol!=NULL){
+	  // After its use we must free it
+	  g_object_unref(stored_message_protocol);
+  }
+  */
+  return retval;
+}
+
+/* define the GError domain for Thrift transports */
+GQuark
+thrift_multiplexed_processor_error_quark (void)
+{
+  return g_quark_from_static_string (THRIFT_MULTIPLEXED_PROCESSOR_ERROR_DOMAIN);
+}
+
+
+static void
+thrift_multiplexed_processor_set_property (GObject      *object,
+    guint         property_id,
+    const GValue *value,
+    GParamSpec   *pspec)
+{
+  ThriftMultiplexedProcessor *self = THRIFT_MULTIPLEXED_PROCESSOR (object);
+
+  switch (property_id)
+  {
+  case PROP_THRIFT_MULTIPLEXED_PROCESSOR_DEFAULT_SERVICE_NAME:
+    self->default_processor_name = g_value_dup_string (value);
+    break;
+
+  default:
+    /* We don't have any other property... */
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    break;
+  }
+}
+
+static void
+thrift_multiplexed_processor_get_property (GObject    *object,
+    guint       property_id,
+    GValue     *value,
+    GParamSpec *pspec)
+{
+  ThriftMultiplexedProcessor *self = THRIFT_MULTIPLEXED_PROCESSOR (object);
+
+  switch (property_id)
+  {
+  case PROP_THRIFT_MULTIPLEXED_PROCESSOR_DEFAULT_SERVICE_NAME:
+    g_value_set_string (value, self->default_processor_name);
+    break;
+
+  default:
+    /* We don't have any other property... */
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    break;
+  }
+}
+
+/* destructor */
+static void
+thrift_multiplexed_processor_finalize (GObject *object)
+{
+  ThriftMultiplexedProcessor *self = THRIFT_MULTIPLEXED_PROCESSOR(object);
+
+  /* Free our multiplexed hash table */
+  g_hash_table_unref (self->multiplexed_services);
+  self->multiplexed_services = NULL;
+
+  if(self->default_processor_name){
+      g_free(self->default_processor_name);
+      self->default_processor_name=NULL;
+  }
+
+  /* Chain up to parent */
+  if (G_OBJECT_CLASS (thrift_multiplexed_processor_parent_class)->finalize)
+    (*G_OBJECT_CLASS (thrift_multiplexed_processor_parent_class)->finalize) (object);
+}
+
+/* class initializer for ThriftMultiplexedProcessor */
+static void
+thrift_multiplexed_processor_class_init (ThriftMultiplexedProcessorClass *cls)
+{
+  /* Override */
+  THRIFT_PROCESSOR_CLASS(cls)->process = thrift_multiplexed_processor_process_impl;
+  GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
+
+  /* Object methods */
+  gobject_class->set_property = thrift_multiplexed_processor_set_property;
+  gobject_class->get_property = thrift_multiplexed_processor_get_property;
+  gobject_class->finalize = thrift_multiplexed_processor_finalize;
+
+  /* Class methods */
+  cls->register_processor = thrift_multiplexed_processor_register_processor_impl;
+
+
+  thrift_multiplexed_processor_obj_properties[PROP_THRIFT_MULTIPLEXED_PROCESSOR_DEFAULT_SERVICE_NAME] =
+      g_param_spec_string ("default",
+          "Default service name the protocol points to where no multiplexed client used",
+          "Set the default service name",
+          NULL,
+          (G_PARAM_READWRITE));
+
+  g_object_class_install_properties (gobject_class,
+				     PROP_THRIFT_MULTIPLEXED_PROCESSOR_END,
+      thrift_multiplexed_processor_obj_properties);
+
+}
+
+static void
+thrift_multiplexed_processor_init (ThriftMultiplexedProcessor *self)
+{
+
+  /* Create our multiplexed services hash table */
+  self->multiplexed_services = g_hash_table_new_full (
+      g_str_hash,
+      g_str_equal,
+      g_free,
+      g_object_unref);
+  self->default_processor_name = NULL;
+}
+
+
+gboolean
+thrift_multiplexed_processor_register_processor(ThriftProcessor *processor, const gchar * multiplexed_processor_name, ThriftProcessor * multiplexed_processor , GError **error)
+{
+  return THRIFT_MULTIPLEXED_PROCESSOR_GET_CLASS(processor)->register_processor(processor, multiplexed_processor_name, multiplexed_processor, error);
+}
+
+
diff --git a/lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.h b/lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.h
new file mode 100644
index 0000000..6406616
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/processor/thrift_multiplexed_processor.h
@@ -0,0 +1,114 @@
+/*
+ * thrift_multiplexed_processor.h
+ *
+ *  Created on: 14 sept. 2017
+ *      Author: gaguilar
+ */
+
+#ifndef _THRIFT_MULTIPLEXED_MULTIPLEXED_PROCESSOR_H_
+#define _THRIFT_MULTIPLEXED_MULTIPLEXED_PROCESSOR_H_
+
+
+#include <glib-object.h>
+
+#include <thrift/c_glib/processor/thrift_processor.h>
+
+
+G_BEGIN_DECLS
+
+/*! \file thrift_multiplexed_processor.h
+ *  \brief The multiplexed processor for c_glib.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_MULTIPLEXED_PROCESSOR (thrift_multiplexed_processor_get_type ())
+#define THRIFT_MULTIPLEXED_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_MULTIPLEXED_PROCESSOR, ThriftMultiplexedProcessor))
+#define THRIFT_IS_MULTIPLEXED_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_MULTIPLEXED_PROCESSOR))
+#define THRIFT_MULTIPLEXED_PROCESSOR_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_MULTIPLEXED_PROCESSOR, ThriftMultiplexedProcessorClass))
+#define THRIFT_IS_MULTIPLEXED_PROCESSOR_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_MULTIPLEXED_PROCESSOR))
+#define THRIFT_MULTIPLEXED_PROCESSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_MULTIPLEXED_PROCESSOR, ThriftMultiplexedProcessorClass))
+
+/* define the GError domain string */
+#define THRIFT_MULTIPLEXED_PROCESSOR_ERROR_DOMAIN "thrift-multiplexed-processor-error-quark"
+
+
+/*!
+ * Thrift MultiplexedProcessor object
+ */
+struct _ThriftMultiplexedProcessor
+{
+  ThriftProcessor parent;
+
+  /* private */
+  gchar * default_processor_name;
+  GHashTable *multiplexed_services;
+};
+typedef struct _ThriftMultiplexedProcessor ThriftMultiplexedProcessor;
+
+/*!
+ * Thrift MultiplexedProcessor class
+ */
+struct _ThriftMultiplexedProcessorClass
+{
+  ThriftProcessorClass parent;
+
+  gboolean (* register_processor) (ThriftProcessor *self, const gchar * multiplexed_processor_name, ThriftProcessor * multiplexed_processor , GError **error);
+
+};
+typedef struct _ThriftMultiplexedProcessorClass ThriftMultiplexedProcessorClass;
+
+/* used by THRIFT_TYPE_MULTIPLEXED_PROCESSOR */
+GType thrift_multiplexed_processor_get_type (void);
+
+/*!
+ * Processes the request.
+ * \public \memberof ThriftMultiplexedProcessorClass
+ */
+gboolean thrift_multiplexed_processor_process (ThriftMultiplexedProcessor *processor,
+                                   ThriftProtocol *in, ThriftProtocol *out,
+                                   GError **error);
+
+
+/* Public API */
+
+/**
+ * @brief Registers a processor in the multiplexed processor under its name. It
+ * will take a reference to the processor so refcount will be incremented.
+ * It will also be decremented on object destruction.
+ *
+ * The first registered processor becomes default. But you can override it with
+ * "default" property.
+ *
+ * It returns a compliant error if it cannot be registered.
+ *
+ * @param processor Pointer to the multiplexed processor.
+ * @param multiplexed_processor_name Name of the processor you want to register
+ * @param multiplexed_processor Pointer to implemented processor you want multiplex.
+ * @param error Error object where we should store errors.
+ *
+ * @see https://developer.gnome.org/glib/stable/glib-Error-Reporting.html#g-set-error
+ */
+gboolean thrift_multiplexed_processor_register_processor(ThriftProcessor *processor, const gchar * multiplexed_processor_name, ThriftProcessor * multiplexed_processor , GError **error);
+
+
+/* define error/exception types */
+typedef enum
+{
+  THRIFT_MULTIPLEXED_PROCESSOR_ERROR_UNKNOWN,
+  THRIFT_MULTIPLEXED_PROCESSOR_ERROR_SERVICE_UNAVAILABLE,
+  THRIFT_MULTIPLEXED_PROCESSOR_ERROR_MESSAGE_TYPE,
+  THRIFT_MULTIPLEXED_PROCESSOR_ERROR_MESSAGE_WRONGLY_MULTIPLEXED,
+  THRIFT_MULTIPLEXED_PROCESSOR_ERROR_SEND,
+  THRIFT_MULTIPLEXED_PROCESSOR_ERROR_RECEIVE,
+  THRIFT_MULTIPLEXED_PROCESSOR_ERROR_CLOSE
+} ThriftMultiplexedProcessorError;
+
+
+GQuark thrift_multiplexed_processor_error_quark (void);
+#define THRIFT_MULTIPLEXED_PROCESSOR_ERROR (thrift_multiplexed_processor_error_quark ())
+
+
+G_END_DECLS
+
+
+#endif /* _THRIFT_MULTIPLEXED_MULTIPLEXED_PROCESSOR_H_ */
diff --git a/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.c b/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.c
index dac8783..c242c25 100644
--- a/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.c
+++ b/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.c
@@ -24,9 +24,10 @@
 
 gboolean
 thrift_processor_process (ThriftProcessor *processor, ThriftProtocol *in,
-                          ThriftProtocol *out)
+                          ThriftProtocol *out, GError **error)
 {
-  return THRIFT_PROCESSOR_GET_CLASS (processor)->process (processor, in, out);
+  return
+    THRIFT_PROCESSOR_GET_CLASS (processor)->process (processor, in, out, error);
 }
 
 /* class initializer for ThriftProcessor */
diff --git a/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.h b/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.h
index a96a555..ff2d2da 100644
--- a/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.h
+++ b/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.h
@@ -56,7 +56,7 @@
 
   /* vtable */
   gboolean (*process) (ThriftProcessor *processor, ThriftProtocol *in,
-                       ThriftProtocol *out);
+                       ThriftProtocol *out, GError **error);
 };
 typedef struct _ThriftProcessorClass ThriftProcessorClass;
 
@@ -68,7 +68,8 @@
  * \public \memberof ThriftProcessorClass
  */
 gboolean thrift_processor_process (ThriftProcessor *processor,
-                                   ThriftProtocol *in, ThriftProtocol *out);
+                                   ThriftProtocol *in, ThriftProtocol *out,
+                                   GError **error);
 
 G_END_DECLS
 
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.c
index da59628..7c2d017 100644
--- a/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.c
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.c
@@ -53,13 +53,13 @@
     const gchar *name, const ThriftMessageType message_type,
     const gint32 seqid, GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
-
   gint32 version = (THRIFT_BINARY_PROTOCOL_VERSION_1)
                    | ((gint32) message_type);
   gint32 ret;
   gint32 xfer = 0;
 
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
   if ((ret = thrift_protocol_write_i32 (protocol, version, error)) < 0)
   {
     return -1;
@@ -117,12 +117,13 @@
                                           const gint16 field_id,
                                           GError **error)
 {
-  THRIFT_UNUSED_VAR (name);
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
-
   gint32 ret;
   gint32 xfer = 0;
 
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+  THRIFT_UNUSED_VAR (name);
+
   if ((ret = thrift_protocol_write_byte (protocol, (gint8) field_type,
                                          error)) < 0)
   {
@@ -162,11 +163,11 @@
                                         const guint32 size,
                                         GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
-
   gint32 ret;
   gint32 xfer = 0;
 
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
   if ((ret = thrift_protocol_write_byte (protocol, (gint8) key_type,
                                          error)) < 0)
   {
@@ -202,11 +203,11 @@
                                          const guint32 size, 
                                          GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1); 
-
   gint32 ret;
   gint32 xfer = 0;
 
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
   if ((ret = thrift_protocol_write_byte (protocol, (gint8) element_type,
                                          error)) < 0)
   {
@@ -256,8 +257,11 @@
 thrift_binary_protocol_write_bool (ThriftProtocol *protocol,
                                    const gboolean value, GError **error)
 {
+  guint8 tmp;
+
   g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
-  guint8 tmp = value ? 1 : 0;
+
+  tmp = value ? 1 : 0;
   return thrift_protocol_write_byte (protocol, tmp, error);
 }
 
@@ -280,9 +284,11 @@
 thrift_binary_protocol_write_i16 (ThriftProtocol *protocol, const gint16 value,
                                   GError **error)
 {
+  gint16 net;
+
   g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
 
-  gint16 net = g_htons (value);
+  net = g_htons (value);
   if (thrift_transport_write (protocol->transport,
                               (const gpointer) &net, 2, error))
   {
@@ -296,9 +302,11 @@
 thrift_binary_protocol_write_i32 (ThriftProtocol *protocol, const gint32 value,
                                   GError **error)
 {
+  gint32 net;
+
   g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
 
-  gint32 net = g_htonl (value);
+  net = g_htonl (value);
   if (thrift_transport_write (protocol->transport,
                               (const gpointer) &net, 4, error))
   {
@@ -312,9 +320,11 @@
 thrift_binary_protocol_write_i64 (ThriftProtocol *protocol, const gint64 value,
                                   GError **error)
 {
+  gint64 net;
+
   g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
 
-  gint64 net = GUINT64_TO_BE (value);
+  net = GUINT64_TO_BE (value);
   if (thrift_transport_write (protocol->transport,
                               (const gpointer) &net, 8, error))
   {
@@ -328,9 +338,11 @@
 thrift_binary_protocol_write_double (ThriftProtocol *protocol,
                                      const gdouble value, GError **error)
 {
+  guint64 bits;
+
   g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
 
-  guint64 bits = GUINT64_FROM_BE (thrift_bitwise_cast_guint64 (value));
+  bits = GUINT64_FROM_BE (thrift_bitwise_cast_guint64 (value));
   if (thrift_transport_write (protocol->transport,
                               (const gpointer) &bits, 8, error))
   {
@@ -344,9 +356,11 @@
 thrift_binary_protocol_write_string (ThriftProtocol *protocol,
                                      const gchar *str, GError **error)
 {
+  guint32 len;
+
   g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
 
-  guint32 len = str != NULL ? strlen (str) : 0;
+  len = str != NULL ? strlen (str) : 0;
   /* write the string length + 1 which includes the null terminator */
   return thrift_protocol_write_binary (protocol, (const gpointer) str, 
                                        len, error);
@@ -357,10 +371,11 @@
                                      const gpointer buf,
                                      const guint32 len, GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
   gint32 ret;
   gint32 xfer = 0;
 
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
   if ((ret = thrift_protocol_write_i32 (protocol, len, error)) < 0)
   {
     return -1;
@@ -386,12 +401,12 @@
                                            ThriftMessageType *message_type,
                                            gint32 *seqid, GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
-
   gint32 ret;
   gint32 xfer = 0;
   gint32 sz;
 
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
   if ((ret = thrift_protocol_read_i32 (protocol, &sz, error)) < 0)
   {
     return -1;
@@ -464,13 +479,14 @@
                                          gint16 *field_id,
                                          GError **error)
 {
-  THRIFT_UNUSED_VAR (name);
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
-
   gint32 ret;
   gint32 xfer = 0;
   gint8 type;
 
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
+  THRIFT_UNUSED_VAR (name);
+
   if ((ret = thrift_protocol_read_byte (protocol, &type, error)) < 0)
   {
     return -1;
@@ -506,13 +522,13 @@
                                        guint32 *size,
                                        GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
-
   gint32 ret;
   gint32 xfer = 0;
   gint8 k, v;
   gint32 sizei;
 
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
   if ((ret = thrift_protocol_read_byte (protocol, &k, error)) < 0)
   {
     return -1;
@@ -559,13 +575,13 @@
                                         ThriftType *element_type,
                                         guint32 *size, GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
-
   gint32 ret;
   gint32 xfer = 0;
   gint8 e;
   gint32 sizei;
 
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
   if ((ret = thrift_protocol_read_byte (protocol, &e, error)) < 0)
   {
     return -1;
@@ -623,13 +639,14 @@
 thrift_binary_protocol_read_bool (ThriftProtocol *protocol, gboolean *value,
                                   GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
   gint32 ret;
   gpointer b[1];
 
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
   if ((ret = 
-       thrift_transport_read (protocol->transport,
-                              b, 1, error)) < 0)
+       thrift_transport_read_all (protocol->transport,
+                                  b, 1, error)) < 0)
   {
     return -1;
   }
@@ -641,13 +658,14 @@
 thrift_binary_protocol_read_byte (ThriftProtocol *protocol, gint8 *value,
                                   GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
   gint32 ret;
   gpointer b[1];
 
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
   if ((ret =
-       thrift_transport_read (protocol->transport,
-                              b, 1, error)) < 0)
+       thrift_transport_read_all (protocol->transport,
+                                  b, 1, error)) < 0)
   {
     return -1;
   }
@@ -659,18 +677,22 @@
 thrift_binary_protocol_read_i16 (ThriftProtocol *protocol, gint16 *value,
                                  GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
   gint32 ret;
-  gpointer b[2];
+  union
+  {
+    gint8 byte_array[2];
+    gint16 int16;
+  } b;
+
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
 
   if ((ret =
-       thrift_transport_read (protocol->transport,
-                              b, 2, error)) < 0)
+       thrift_transport_read_all (protocol->transport,
+                                  b.byte_array, 2, error)) < 0)
   {
     return -1;
   }
-  *value = *(gint16 *) b;
-  *value = g_ntohs (*value);
+  *value = g_ntohs (b.int16);
   return ret;
 }
 
@@ -678,18 +700,22 @@
 thrift_binary_protocol_read_i32 (ThriftProtocol *protocol, gint32 *value,
                                  GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
   gint32 ret;
-  gpointer b[4];
+  union
+  {
+    gint8 byte_array[4];
+    gint32 int32;
+  } b;
+
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
 
   if ((ret =
-       thrift_transport_read (protocol->transport,
-                              b, 4, error)) < 0)
+       thrift_transport_read_all (protocol->transport,
+                                  b.byte_array, 4, error)) < 0)
   {
     return -1;
   }
-  *value = *(gint32 *) b;
-  *value = g_ntohl (*value);
+  *value = g_ntohl (b.int32);
   return ret;
 }
 
@@ -697,18 +723,22 @@
 thrift_binary_protocol_read_i64 (ThriftProtocol *protocol, gint64 *value,
                                  GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
   gint32 ret;
-  gpointer b[8];
+  union
+  {
+    gint8 byte_array[8];
+    gint64 int64;
+  } b;
+
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
 
   if ((ret =
-       thrift_transport_read (protocol->transport,
-                              b, 8, error)) < 0)
+       thrift_transport_read_all (protocol->transport,
+                                  b.byte_array, 8, error)) < 0)
   {
     return -1;
   }
-  *value = *(gint64 *) b;
-  *value = GUINT64_FROM_BE (*value);
+  *value = GUINT64_FROM_BE (b.int64);
   return ret;
 }
 
@@ -716,19 +746,22 @@
 thrift_binary_protocol_read_double (ThriftProtocol *protocol,
                                     gdouble *value, GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
   gint32 ret;
-  gpointer b[8];
+  union
+  {
+    gint8 byte_array[8];
+    guint64 uint64;
+  } b;
+
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
 
   if ((ret =
-       thrift_transport_read (protocol->transport,
-                              b, 8, error)) < 0)
+       thrift_transport_read_all (protocol->transport,
+                                  b.byte_array, 8, error)) < 0)
   {
     return -1;
   }
-  guint64 bits = *(guint64 *) b;
-  bits = GUINT64_FROM_BE (bits);
-  *value = thrift_bitwise_cast_gdouble (bits);
+  *value = thrift_bitwise_cast_gdouble (GUINT64_FROM_BE (b.uint64));
   return ret;
 }
 
@@ -736,12 +769,13 @@
 thrift_binary_protocol_read_string (ThriftProtocol *protocol,
                                     gchar **str, GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
   guint32 len;
   gint32 ret;
   gint32 xfer = 0;
   gint32 read_len = 0;
 
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
   /* read the length into read_len */
   if ((ret =
        thrift_protocol_read_i32 (protocol, &read_len, error)) < 0)
@@ -750,14 +784,21 @@
   }
   xfer += ret;
 
-  if (read_len > 0)
-  {
-    /* allocate the memory for the string */
-    len = (guint32) read_len + 1; // space for null terminator
-    *str = g_new0 (gchar, len);
+  if (read_len < 0) {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+                 "got negative size of %d", read_len);
+    *str = NULL;
+    return -1;
+  }
+
+  /* allocate the memory for the string */
+  len = (guint32) read_len + 1; /* space for null terminator */
+  *str = g_new0 (gchar, len);
+  if (read_len > 0) {
     if ((ret =
-         thrift_transport_read (protocol->transport,
-                                *str, read_len, error)) < 0)
+         thrift_transport_read_all (protocol->transport,
+                                    *str, read_len, error)) < 0)
     {
       g_free (*str);
       *str = NULL;
@@ -766,7 +807,7 @@
     }
     xfer += ret;
   } else {
-    *str = NULL;
+    **str = 0;
   }
 
   return xfer;
@@ -777,11 +818,12 @@
                                     gpointer *buf, guint32 *len,
                                     GError **error)
 {
-  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
   gint32 ret;
   gint32 xfer = 0;
   gint32 read_len = 0;
  
+  g_return_val_if_fail (THRIFT_IS_BINARY_PROTOCOL (protocol), -1);
+
   /* read the length into read_len */
   if ((ret =
        thrift_protocol_read_i32 (protocol, &read_len, error)) < 0)
@@ -796,8 +838,8 @@
     *len = (guint32) read_len;
     *buf = g_new (guchar, *len);
     if ((ret =
-         thrift_transport_read (protocol->transport,
-                                *buf, *len, error)) < 0)
+         thrift_transport_read_all (protocol->transport,
+                                    *buf, *len, error)) < 0)
     {
       g_free (*buf);
       *buf = NULL;
@@ -806,6 +848,7 @@
     }
     xfer += ret;
   } else {
+    *len = (guint32) read_len;
     *buf = NULL;
   }
 
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol_factory.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol_factory.c
index 390c809..774e9ad 100644
--- a/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol_factory.c
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol_factory.c
@@ -27,11 +27,11 @@
 thrift_binary_protocol_factory_get_protocol (ThriftProtocolFactory *factory,
                                              ThriftTransport *transport)
 {
-  THRIFT_UNUSED_VAR (factory);
-
   ThriftBinaryProtocol *tb = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
                                            "transport", transport, NULL);
 
+  THRIFT_UNUSED_VAR (factory);
+
   return THRIFT_PROTOCOL (tb);
 }
 
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c
new file mode 100644
index 0000000..cae4749
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c
@@ -0,0 +1,1609 @@
+/*
+ * 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.
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/protocol/thrift_compact_protocol.h>
+
+#include <thrift/config.h>
+
+/*
+ * *_to_zigzag depend on the fact that the right shift
+ * operator on a signed integer is an arithmetic (sign-extending) shift.
+ * If this is not the case, the current implementation will not work.
+ */
+#if !defined(SIGNED_RIGHT_SHIFT_IS) || !defined(ARITHMETIC_RIGHT_SHIFT)
+# error "Unable to determine the behavior of a signed right shift"
+#endif
+#if SIGNED_RIGHT_SHIFT_IS != ARITHMETIC_RIGHT_SHIFT
+# error "thrift_compact_protocol only works if signed right shift is arithmetic"
+#endif
+
+/* object properties */
+enum _ThriftCompactProtocolProperties
+{
+    PROP_0,
+    PROP_THRIFT_COMPACT_PROTOCOL_STRING_LIMIT,
+    PROP_THRIFT_COMPACT_PROTOCOL_CONTAINER_LIMIT
+};
+
+G_DEFINE_TYPE (ThriftCompactProtocol, thrift_compact_protocol,
+               THRIFT_TYPE_PROTOCOL)
+
+static const gint8 PROTOCOL_ID = (gint8)0x82u;
+static const gint8 VERSION_N = 1;
+static const gint8 VERSION_MASK = 0x1f;       /* 0001 1111 */
+static const gint8 TYPE_MASK = (gint8)0xe0u;  /* 1110 0000 */
+static const gint8 TYPE_BITS = 0x07;          /* 0000 0111 */
+static const gint32 TYPE_SHIFT_AMOUNT = 5;
+
+enum Types {
+  CT_STOP           = 0x00,
+  CT_BOOLEAN_TRUE   = 0x01,
+  CT_BOOLEAN_FALSE  = 0x02,
+  CT_BYTE           = 0x03,
+  CT_I16            = 0x04,
+  CT_I32            = 0x05,
+  CT_I64            = 0x06,
+  CT_DOUBLE         = 0x07,
+  CT_BINARY         = 0x08,
+  CT_LIST           = 0x09,
+  CT_SET            = 0x0A,
+  CT_MAP            = 0x0B,
+  CT_STRUCT         = 0x0C
+};
+
+static const gint8 TTypeToCType[16] = {
+  CT_STOP, /* T_STOP */
+  0, /* unused */
+  CT_BOOLEAN_TRUE, /* T_BOOL */
+  CT_BYTE, /* T_BYTE */
+  CT_DOUBLE, /* T_DOUBLE */
+  0, /* unused */
+  CT_I16, /* T_I16 */
+  0, /* unused */
+  CT_I32, /* T_I32 */
+  0, /* unused */
+  CT_I64, /* T_I64 */
+  CT_BINARY, /* T_STRING */
+  CT_STRUCT, /* T_STRUCT */
+  CT_MAP, /* T_MAP */
+  CT_SET, /* T_SET */
+  CT_LIST, /* T_LIST */
+};
+
+static guint64
+thrift_bitwise_cast_guint64 (const gdouble v)
+{
+  union {
+    gdouble from;
+    guint64 to;
+  } u;
+  u.from = v;
+  return u.to;
+}
+
+static gdouble
+thrift_bitwise_cast_gdouble (const guint64 v)
+{
+  union {
+    guint64 from;
+    gdouble to;
+  } u;
+  u.from = v;
+  return u.to;
+}
+
+/**
+ * Convert l into a zigzag long. This allows negative numbers to be
+ * represented compactly as a varint.
+ */
+static guint64
+i64_to_zigzag (const gint64 l)
+{
+  return (((guint64)l) << 1) ^ (l >> 63);
+}
+
+/**
+ * Convert n into a zigzag int. This allows negative numbers to be
+ * represented compactly as a varint.
+ */
+static guint32
+i32_to_zigzag (const gint32 n)
+{
+  return (((guint32)n) << 1) ^ (n >> 31);
+}
+
+/**
+ * Convert from zigzag int to int.
+ */
+static gint32
+zigzag_to_i32 (guint32 n)
+{
+  return (n >> 1) ^ (guint32) (-(gint32) (n & 1));
+}
+
+/**
+ * Convert from zigzag long to long.
+ */
+static gint64
+zigzag_to_i64 (guint64 n)
+{
+  return (n >> 1) ^ (guint64) (-(gint64) (n & 1));
+}
+
+ThriftType thrift_compact_protocol_get_ttype (ThriftCompactProtocol *protocol,
+                                              const gint8 type, GError **error)
+{
+  THRIFT_UNUSED_VAR (protocol);
+
+  switch (type) {
+    case T_STOP:
+      return T_STOP;
+    case CT_BOOLEAN_FALSE:
+    case CT_BOOLEAN_TRUE:
+      return T_BOOL;
+    case CT_BYTE:
+      return T_BYTE;
+    case CT_I16:
+      return T_I16;
+    case CT_I32:
+      return T_I32;
+    case CT_I64:
+      return T_I64;
+    case CT_DOUBLE:
+      return T_DOUBLE;
+    case CT_BINARY:
+      return T_STRING;
+    case CT_LIST:
+      return T_LIST;
+    case CT_SET:
+      return T_SET;
+    case CT_MAP:
+      return T_MAP;
+    case CT_STRUCT:
+      return T_STRUCT;
+    default:
+      g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                   THRIFT_PROTOCOL_ERROR_INVALID_DATA,
+                   "unrecognized type");
+      return -1;
+  }
+}
+
+/**
+ * Write an i32 as a varint. Results in 1-5 bytes on the wire.
+ */
+gint32
+thrift_compact_protocol_write_varint32 (ThriftCompactProtocol *protocol,
+                                        const guint32 n,
+                                        GError **error)
+{
+  guint8 buf[5];
+  gint32 xfer;
+  guint32 m;
+
+  THRIFT_UNUSED_VAR (error);
+
+  xfer = 0;
+  m = n;
+
+  while (TRUE) {
+    if ((m & ~0x7F) == 0) {
+      buf[xfer++] = (gint8)m;
+      break;
+    } else {
+      buf[xfer++] = (gint8)((m & 0x7F) | 0x80);
+      m >>= 7;
+    }
+  }
+
+  if (thrift_transport_write (THRIFT_PROTOCOL (protocol)->transport,
+                              (const gpointer) buf, xfer, error)) {
+    return xfer;
+  } else {
+    return -1;
+  }
+}
+
+/**
+ * Write an i64 as a varint. Results in 1-10 bytes on the wire.
+ */
+gint32
+thrift_compact_protocol_write_varint64 (ThriftCompactProtocol *protocol,
+                                        const guint64 n,
+                                        GError **error)
+{
+  guint8 buf[10];
+  gint32 xfer;
+  guint64 m;
+
+  THRIFT_UNUSED_VAR (error);
+
+  xfer = 0;
+  m = n;
+
+  while (TRUE) {
+    if ((m & ~0x7FL) == 0) {
+      buf[xfer++] = (gint8)m;
+      break;
+    } else {
+      buf[xfer++] = (gint8)((m & 0x7F) | 0x80);
+      m >>= 7;
+    }
+  }
+
+  if (thrift_transport_write (THRIFT_PROTOCOL (protocol)->transport,
+                              (const gpointer) buf, xfer, error)) {
+    return xfer;
+  } else {
+    return -1;
+  }
+}
+
+/**
+ * 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.
+ */
+gint32
+thrift_compact_protocol_read_varint64 (ThriftCompactProtocol *protocol,
+                                       gint64 *i64,
+                                       GError **error)
+{
+  ThriftProtocol *tp;
+  gint32 ret;
+  gint32 xfer;
+  guint64 val;
+  gint shift;
+  guint8 byte;
+
+  tp = THRIFT_PROTOCOL (protocol);
+  xfer = 0;
+  val = 0;
+  shift = 0;
+  byte = 0;
+
+  while (TRUE) {
+    if ((ret = thrift_transport_read_all (tp->transport,
+                                          (gpointer) &byte, 1, error)) < 0) {
+      return -1;
+    }
+    ++xfer;
+    val |= (guint64)(byte & 0x7f) << shift;
+    shift += 7;
+    if (!(byte & 0x80)) {
+      *i64 = (gint64) val;
+      return xfer;
+    }
+    if (G_UNLIKELY (xfer == 10)) { /* 7 * 9 < 64 < 7 * 10 */
+      g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                   THRIFT_PROTOCOL_ERROR_INVALID_DATA,
+                   "variable-length int over 10 bytes");
+      return -1;
+    }
+  }
+}
+
+/**
+ * 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.
+ */
+gint32
+thrift_compact_protocol_read_varint32 (ThriftCompactProtocol *protocol,
+                                       gint32 *i32,
+                                       GError **error)
+{
+  gint64 val;
+  gint32 ret;
+  gint32 xfer;
+
+  xfer = 0;
+
+  if ((ret = thrift_compact_protocol_read_varint64 (protocol, &val,
+                                                    error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  *i32 = (gint32)val;
+
+  return xfer;
+}
+
+gint32
+thrift_compact_protocol_write_field_begin_internal (ThriftCompactProtocol
+                                                      *protocol,
+                                                    const gchar *name,
+                                                    const ThriftType field_type,
+                                                    const gint16 field_id,
+                                                    const gint8 type_override,
+                                                    GError **error)
+{
+  gint32 ret;
+  gint32 xfer;
+  gint8 type_to_write;
+
+  THRIFT_UNUSED_VAR (name);
+
+  xfer = 0;
+
+  /* if there's a type override, use that. */
+  type_to_write
+    = (type_override == -1 ? TTypeToCType[field_type] : type_override);
+
+  /* check if we can use delta encoding for the field id */
+  if (field_id > protocol->_last_field_id
+      && field_id - protocol->_last_field_id <= 15) {
+    /* write them together */
+    if ((ret = thrift_protocol_write_byte (THRIFT_PROTOCOL (protocol),
+                                           (gint8) ((field_id
+                                                     - protocol->_last_field_id)
+                                                    << 4 | type_to_write),
+                                           error)) < 0) {
+      return -1;
+    }
+    xfer += ret;
+  } else {
+    /* write them separate */
+    if ((ret = thrift_protocol_write_byte (THRIFT_PROTOCOL (protocol),
+                                           type_to_write, error)) < 0) {
+      return -1;
+    }
+    xfer += ret;
+
+    if ((ret = thrift_protocol_write_i16 (THRIFT_PROTOCOL (protocol), field_id,
+                                          error)) < 0) {
+      return -1;
+    }
+    xfer += ret;
+  }
+
+  protocol->_last_field_id = field_id;
+  return xfer;
+}
+
+/**
+ * Method for writing the start of lists and sets. List and sets on
+ * the wire differ only by the type indicator.
+ */
+gint32
+thrift_compact_protocol_write_collection_begin (ThriftCompactProtocol *protocol,
+                                                const ThriftType elem_type,
+                                                guint32 size, GError **error)
+{
+  gint32 ret;
+  gint32 xfer;
+
+  xfer = 0;
+
+  if (size <= 14) {
+    if ((ret = thrift_protocol_write_byte (THRIFT_PROTOCOL (protocol),
+                                           (gint8) (size << 4
+                                                    | TTypeToCType[elem_type]),
+                                           error)) < 0) {
+      return -1;
+    }
+    xfer += ret;
+  } else {
+    if ((ret = thrift_protocol_write_byte (THRIFT_PROTOCOL (protocol),
+                                           (gint8) (0xf0
+                                                    | TTypeToCType[elem_type]),
+                                           error)) < 0) {
+      return -1;
+    }
+    xfer += ret;
+
+    if ((ret = thrift_compact_protocol_write_varint32 (protocol,
+                                                       (guint32) size,
+                                                       error)) < 0) {
+      return -1;
+    }
+    xfer += ret;
+  }
+
+  return xfer;
+}
+
+/*
+ * public methods
+ */
+
+gint32
+thrift_compact_protocol_write_message_begin (ThriftProtocol *protocol,
+                                             const gchar *name,
+                                             const ThriftMessageType
+                                               message_type,
+                                             const gint32 seqid, GError **error)
+{
+  gint8 version;
+  gint32 ret;
+  gint32 xfer;
+
+  ThriftCompactProtocol *cp;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  version = (VERSION_N & VERSION_MASK)
+            | (((gint32) message_type << TYPE_SHIFT_AMOUNT) & TYPE_MASK);
+  xfer = 0;
+
+  if ((ret = thrift_protocol_write_byte (protocol, PROTOCOL_ID, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  if ((ret = thrift_protocol_write_byte (protocol, version, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  if ((ret = thrift_compact_protocol_write_varint32 (cp,
+                                                     (guint32) seqid,
+                                                     error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  if ((ret = thrift_protocol_write_string (protocol, name, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  return xfer;
+}
+
+gint32
+thrift_compact_protocol_write_message_end (ThriftProtocol *protocol,
+                                           GError **error)
+{
+  /* satisfy -Wall */
+  THRIFT_UNUSED_VAR (protocol);
+  THRIFT_UNUSED_VAR (error);
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_write_struct_begin (ThriftProtocol *protocol,
+                                            const gchar *name,
+                                            GError **error)
+{
+  ThriftCompactProtocol *cp;
+  GQueue *q;
+
+  /* satisfy -Wall */
+  THRIFT_UNUSED_VAR (name);
+  THRIFT_UNUSED_VAR (error);
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+  q = &(cp->_last_field);
+
+  g_queue_push_tail (q, GINT_TO_POINTER ((gint) cp->_last_field_id));
+  cp->_last_field_id = 0;
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_write_struct_end (ThriftProtocol *protocol,
+                                          GError **error)
+{
+  ThriftCompactProtocol *cp;
+  GQueue *q;
+
+  /* satisfy -Wall */
+  THRIFT_UNUSED_VAR (error);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+  q = &(cp->_last_field);
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp->_last_field_id = (gint16) GPOINTER_TO_INT (g_queue_pop_tail (q));
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_write_field_begin (ThriftProtocol *protocol,
+                                           const gchar *name,
+                                           const ThriftType field_type,
+                                           const gint16 field_id,
+                                           GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  if (field_type == T_BOOL) {
+    cp->_bool_field_name = name;
+    cp->_bool_field_type = field_type;
+    cp->_bool_field_id = field_id;
+    return 0;
+  } else {
+    return thrift_compact_protocol_write_field_begin_internal (cp, name,
+                                                               field_type,
+                                                               field_id, -1,
+                                                               error);
+  }
+}
+
+gint32
+thrift_compact_protocol_write_field_end (ThriftProtocol *protocol,
+                                         GError **error)
+{
+  /* satisfy -Wall */
+  THRIFT_UNUSED_VAR (protocol);
+  THRIFT_UNUSED_VAR (error);
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_write_field_stop (ThriftProtocol *protocol,
+                                          GError **error)
+{
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+  return thrift_protocol_write_byte (protocol, (gint8) T_STOP, error);
+}
+
+gint32
+thrift_compact_protocol_write_map_begin (ThriftProtocol *protocol,
+                                         const ThriftType key_type,
+                                         const ThriftType value_type,
+                                         const guint32 size,
+                                         GError **error)
+{
+  gint32 ret;
+  gint32 xfer;
+
+  ThriftCompactProtocol *cp;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  xfer = 0;
+
+  if ((ret = thrift_compact_protocol_write_varint32 (cp, (guint32) size,
+                                                     error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  if (size > 0) {
+    if ((ret = thrift_protocol_write_byte (protocol,
+                                           (gint8) (TTypeToCType[key_type] << 4
+                                                    | TTypeToCType[value_type]),
+                                           error)) < 0) {
+      return -1;
+    }
+    xfer += ret;
+  }
+
+  return xfer;
+}
+
+gint32
+thrift_compact_protocol_write_map_end (ThriftProtocol *protocol,
+                                       GError **error)
+{
+  THRIFT_UNUSED_VAR (protocol);
+  THRIFT_UNUSED_VAR (error);
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_write_list_begin (ThriftProtocol *protocol,
+                                          const ThriftType element_type,
+                                          const guint32 size,
+                                          GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  return thrift_compact_protocol_write_collection_begin (cp, element_type,
+                                                         size, error);
+}
+
+gint32
+thrift_compact_protocol_write_list_end (ThriftProtocol *protocol,
+                                        GError **error)
+{
+  THRIFT_UNUSED_VAR (protocol);
+  THRIFT_UNUSED_VAR (error);
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_write_set_begin (ThriftProtocol *protocol,
+                                         const ThriftType element_type,
+                                         const guint32 size,
+                                         GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  return thrift_compact_protocol_write_collection_begin (cp, element_type,
+                                                         size, error);
+}
+
+gint32
+thrift_compact_protocol_write_set_end (ThriftProtocol *protocol, GError **error)
+{
+  THRIFT_UNUSED_VAR (protocol);
+  THRIFT_UNUSED_VAR (error);
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_write_bool (ThriftProtocol *protocol,
+                                    const gboolean value, GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  gint32 ret;
+  gint32 xfer;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  xfer = 0;
+
+  if (cp->_bool_field_name != NULL) {
+    /* we haven't written the field header yet */
+    if ((ret = thrift_compact_protocol_write_field_begin_internal (cp,
+                                 cp->_bool_field_name,
+                                 cp->_bool_field_type,
+                                 cp->_bool_field_id,
+                                 (gint8) (value
+                                          ? CT_BOOLEAN_TRUE : CT_BOOLEAN_FALSE),
+                                 error)) < 0) {
+      return -1;
+    }
+    xfer += ret;
+
+    cp->_bool_field_name = NULL;
+  } else {
+    /* we're not part of a field, so just write the value */
+    if ((ret = thrift_protocol_write_byte (protocol,
+                                           (gint8) (value ? CT_BOOLEAN_TRUE
+                                                          : CT_BOOLEAN_FALSE),
+                                           error)) < 0) {
+      return -1;
+    }
+    xfer += ret;
+  }
+  return xfer;
+}
+
+gint32
+thrift_compact_protocol_write_byte (ThriftProtocol *protocol, const gint8 value,
+                                    GError **error)
+{
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  if (thrift_transport_write (protocol->transport,
+                              (const gpointer) &value, 1, error)) {
+    return 1;
+  } else {
+    return -1;
+  }
+}
+
+gint32
+thrift_compact_protocol_write_i16 (ThriftProtocol *protocol, const gint16 value,
+                                   GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  return thrift_compact_protocol_write_varint32 (cp,
+                         i32_to_zigzag ((gint32) value),
+                         error);
+}
+
+gint32
+thrift_compact_protocol_write_i32 (ThriftProtocol *protocol, const gint32 value,
+                                   GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  return thrift_compact_protocol_write_varint32 (cp,
+                         i32_to_zigzag (value),
+                         error);
+}
+
+gint32
+thrift_compact_protocol_write_i64 (ThriftProtocol *protocol, const gint64 value,
+                                   GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  return thrift_compact_protocol_write_varint64 (cp,
+                         i64_to_zigzag (value),
+                         error);
+}
+
+gint32
+thrift_compact_protocol_write_double (ThriftProtocol *protocol,
+                                      const gdouble value, GError **error)
+{
+  guint64 bits;
+
+  g_assert (sizeof (gdouble) == sizeof (guint64));
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  bits = GUINT64_TO_LE (thrift_bitwise_cast_guint64 (value));
+  if (thrift_transport_write (protocol->transport,
+                              (const gpointer) &bits, 8, error)) {
+    return 8;
+  } else {
+    return -1;
+  }
+}
+
+gint32
+thrift_compact_protocol_write_string (ThriftProtocol *protocol,
+                                      const gchar *str, GError **error)
+{
+  size_t len;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  len = str != NULL ? strlen (str) : 0;
+  if (len > G_MAXINT32) {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+                 "string size (guess: %lu) is too large", (unsigned long) len);
+    return -1;
+  }
+
+  /* write the string length + 1 which includes the null terminator */
+  return thrift_protocol_write_binary (protocol, (const gpointer) str,
+                                       (const guint32) len, error);
+}
+
+gint32
+thrift_compact_protocol_write_binary (ThriftProtocol *protocol,
+                                      const gpointer buf,
+                                      const guint32 len, GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  gint32 ret;
+  gint32 xfer;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  xfer = 0;
+
+  if ((ret = thrift_compact_protocol_write_varint32 (cp, len, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  if (len > 0) {
+    /* checking len + xfer > uint_max, but we don't want to overflow while
+     * checking for overflows. transforming to len > uint_max - xfer.
+     */
+    if (len > (guint32) (G_MAXINT32 - xfer)) {
+      g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                   THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+                   "size %d + %d is too large", len, xfer);
+      return -1;
+    }
+
+    if (thrift_transport_write (protocol->transport,
+                                (const gpointer) buf, len, error) == FALSE) {
+      return -1;
+    }
+    xfer += len;
+  }
+
+  return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_message_begin (ThriftProtocol *protocol,
+                                            gchar **name,
+                                            ThriftMessageType *message_type,
+                                            gint32 *seqid, GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  gint32 ret;
+  gint32 xfer;
+
+  gint8 protocol_id, version_and_type, version;
+
+  xfer = 0;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  if ((ret = thrift_protocol_read_byte (protocol, &protocol_id, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  if (protocol_id != PROTOCOL_ID) {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_BAD_VERSION,
+                 "bad protocol id");
+    return -1;
+  }
+
+  if ((ret = thrift_protocol_read_byte (protocol, &version_and_type,
+                                        error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  version = (gint8)(version_and_type & VERSION_MASK);
+  if (version != VERSION_N) {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_BAD_VERSION,
+                 "bad version and/or type");
+    return -1;
+  }
+
+  *message_type
+    = (ThriftMessageType)((version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
+
+  if ((ret = thrift_compact_protocol_read_varint32 (cp, seqid, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  if ((ret = thrift_protocol_read_string (protocol, name, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_message_end (ThriftProtocol *protocol,
+                                          GError **error)
+{
+  THRIFT_UNUSED_VAR (protocol);
+  THRIFT_UNUSED_VAR (error);
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_read_struct_begin (ThriftProtocol *protocol,
+                                           gchar **name,
+                                           GError **error)
+{
+  ThriftCompactProtocol *cp;
+  GQueue *q;
+
+  THRIFT_UNUSED_VAR (error);
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+  q = &(cp->_last_field);
+
+  *name = NULL;
+
+  g_queue_push_tail (q, GINT_TO_POINTER ((gint) cp->_last_field_id));
+  cp->_last_field_id = 0;
+
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_read_struct_end (ThriftProtocol *protocol,
+                                         GError **error)
+{
+  ThriftCompactProtocol *cp;
+  GQueue *q;
+
+  THRIFT_UNUSED_VAR (error);
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+  q = &(cp->_last_field);
+
+  cp->_last_field_id = (gint16) GPOINTER_TO_INT (g_queue_pop_tail (q));
+
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_read_field_begin (ThriftProtocol *protocol,
+                                          gchar **name,
+                                          ThriftType *field_type,
+                                          gint16 *field_id,
+                                          GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  gint32 ret;
+  gint32 xfer;
+
+  gint16 modifier;
+  gint8 byte;
+  gint8 type;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  THRIFT_UNUSED_VAR (name);
+
+  xfer = 0;
+
+  if ((ret = thrift_protocol_read_byte (protocol, &byte, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  type = (byte & 0x0f);
+
+  /* if it's a stop, then we can return immediately, as the struct is over. */
+  if (type == T_STOP) {
+    *field_type = T_STOP;
+    *field_id = 0;
+    return xfer;
+  }
+
+  /* mask off the 4 MSB of the type header.
+   * it could contain a field id delta.
+   */
+  modifier = (gint16)(((guint8)byte & 0xf0) >> 4);
+  if (modifier == 0) {
+    /* not a delta, look ahead for the zigzag varint field id. */
+    if ((ret = thrift_protocol_read_i16 (protocol, field_id, error)) < 0) {
+      return -1;
+    }
+    xfer += ret;
+  } else {
+    *field_id = (gint16)(cp->_last_field_id + modifier);
+  }
+  if ((ret = thrift_compact_protocol_get_ttype (cp, type, error)) < 0) {
+    return -1;
+  }
+  *field_type = ret;
+
+  /* if this happens to be a boolean field, the value is encoded in the type */
+  if (type == CT_BOOLEAN_TRUE || type == CT_BOOLEAN_FALSE) {
+    /* save the boolean value in a special instance variable. */
+    cp->_has_bool_value = TRUE;
+    cp->_bool_value =
+      (type == CT_BOOLEAN_TRUE ? TRUE : FALSE);
+  }
+
+  /* push the new field onto the field stack so we can keep the deltas going. */
+  cp->_last_field_id = *field_id;
+
+  return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_field_end (ThriftProtocol *protocol,
+                                        GError **error)
+{
+  THRIFT_UNUSED_VAR (protocol);
+  THRIFT_UNUSED_VAR (error);
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_read_map_begin (ThriftProtocol *protocol,
+                                        ThriftType *key_type,
+                                        ThriftType *value_type,
+                                        guint32 *size,
+                                        GError **error)
+{
+  gint32 ret;
+  gint32 xfer;
+
+  gint8 kv_type;
+  gint32 msize;
+
+  ThriftCompactProtocol *cp;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  kv_type = 0;
+  msize = 0;
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  xfer = 0;
+
+  if ((ret = thrift_compact_protocol_read_varint32 (cp, &msize, error)) <0) {
+    return -1;
+  }
+  xfer += ret;
+
+  /* still read the kv byte if negative size */
+  if (msize != 0) {
+    if ((ret = thrift_protocol_read_byte (protocol, &kv_type, error)) < 0) {
+      return -1;
+    }
+    xfer += ret;
+  }
+
+  if (cp->container_limit > 0 && msize > cp->container_limit) {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+                 "got size over limit (%d > %d)", msize, cp->container_limit);
+    return -1;
+  } else if (msize > 0) {
+    if ((ret = thrift_compact_protocol_get_ttype (cp,
+                                                  (gint8)((guint8)kv_type
+                                                          >> 4),
+                                                  error)) < 0) {
+      return -1;
+    }
+    *key_type = ret;
+    if ((ret = thrift_compact_protocol_get_ttype (cp,
+                                                  (gint8)((guint8)kv_type
+                                                          & 0xf),
+                                                  error)) < 0) {
+      return -1;
+    }
+    *value_type = ret;
+    *size = (guint32) msize;
+  } else if (msize == 0) {
+    *key_type = 0;
+    *value_type = 0;
+    *size = 0;
+  } else {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+                 "got negative size of %d", msize);
+    return -1;
+  }
+
+  return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_map_end (ThriftProtocol *protocol,
+                                      GError **error)
+{
+  THRIFT_UNUSED_VAR (protocol);
+  THRIFT_UNUSED_VAR (error);
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_read_list_begin (ThriftProtocol *protocol,
+                                         ThriftType *element_type,
+                                         guint32 *size, GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  gint32 ret;
+  gint32 xfer;
+
+  gint8 size_and_type;
+  gint32 lsize;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  size_and_type = 0;
+
+  xfer = 0;
+
+  if ((ret = thrift_protocol_read_byte (protocol, &size_and_type, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  lsize = ((guint8)size_and_type >> 4) & 0x0f;
+  if (lsize == 15) {
+    if ((ret = thrift_compact_protocol_read_varint32 (cp, &lsize, error)) < 0) {
+      return -1;
+    }
+    xfer += ret;
+  }
+
+  if (lsize < 0) {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+                 "got negative size of %d", lsize);
+    return -1;
+  } else if (cp->container_limit > 0 && lsize > cp->container_limit) {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+                 "got size over limit (%d > %d)", lsize, cp->container_limit);
+    return -1;
+  }
+
+  if ((ret = thrift_compact_protocol_get_ttype (cp,
+                                                (gint8)(size_and_type & 0x0f),
+                                                error)) < 0) {
+    return -1;
+  }
+  *element_type = ret;
+  *size = (guint32) lsize;
+
+  return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_list_end (ThriftProtocol *protocol,
+                                       GError **error)
+{
+  THRIFT_UNUSED_VAR (protocol);
+  THRIFT_UNUSED_VAR (error);
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_read_set_begin (ThriftProtocol *protocol,
+                                        ThriftType *element_type,
+                                        guint32 *size, GError **error)
+{
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  return thrift_protocol_read_list_begin (protocol, element_type, size, error);
+}
+
+gint32
+thrift_compact_protocol_read_set_end (ThriftProtocol *protocol,
+                                      GError **error)
+{
+  THRIFT_UNUSED_VAR (protocol);
+  THRIFT_UNUSED_VAR (error);
+  return 0;
+}
+
+gint32
+thrift_compact_protocol_read_bool (ThriftProtocol *protocol, gboolean *value,
+                                   GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  gint32 ret;
+  gint32 xfer;
+
+  gint8 val;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  xfer = 0;
+
+  if (cp->_has_bool_value == TRUE) {
+    *value = cp->_bool_value;
+    cp->_has_bool_value = FALSE;
+    return 0;
+  } else {
+    if ((ret = thrift_protocol_read_byte (protocol, &val, error)) < 0) {
+      return -1;
+    }
+    xfer += ret;
+
+    *value = (val == CT_BOOLEAN_TRUE);
+    return xfer;
+  }
+}
+
+gint32
+thrift_compact_protocol_read_byte (ThriftProtocol *protocol, gint8 *value,
+                                   GError **error)
+{
+  gint32 ret;
+  gpointer b[1];
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  if ((ret =
+       thrift_transport_read_all (protocol->transport,
+                                  b, 1, error)) < 0) {
+    return -1;
+  }
+  *value = *(gint8 *) b;
+  return ret;
+}
+
+gint32
+thrift_compact_protocol_read_i16 (ThriftProtocol *protocol, gint16 *value,
+                                  GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  gint32 ret;
+  gint32 val;
+  gint32 xfer;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  xfer = 0;
+
+  if ((ret = thrift_compact_protocol_read_varint32 (cp, &val, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  *value = (gint16) zigzag_to_i32 ((guint32) val);
+
+  return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_i32 (ThriftProtocol *protocol, gint32 *value,
+                                  GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  gint32 ret;
+  gint32 val;
+  gint32 xfer;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  xfer = 0;
+
+  if ((ret = thrift_compact_protocol_read_varint32 (cp, &val, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  *value = zigzag_to_i32 ((guint32) val);
+
+  return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_i64 (ThriftProtocol *protocol, gint64 *value,
+                                  GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  gint32 ret;
+  gint64 val;
+  gint32 xfer;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  xfer = 0;
+
+  if ((ret = thrift_compact_protocol_read_varint64 (cp, &val, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  *value = zigzag_to_i64 ((guint64) val);
+
+  return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_double (ThriftProtocol *protocol,
+                                     gdouble *value, GError **error)
+{
+  gint32 ret;
+  union {
+    guint64 bits;
+    guint8 b[8];
+  } u;
+
+  g_assert (sizeof (gdouble) == sizeof (guint64));
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  if ((ret =
+       thrift_transport_read_all (protocol->transport,
+                                  u.b, 8, error)) < 0) {
+    return -1;
+  }
+  u.bits = GUINT64_FROM_LE (u.bits);
+  *value = thrift_bitwise_cast_gdouble (u.bits);
+  return ret;
+}
+
+gint32
+thrift_compact_protocol_read_string (ThriftProtocol *protocol,
+                                     gchar **str, GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  gint32 ret;
+  gint32 xfer;
+
+  gint32 read_len;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  xfer = 0;
+  read_len = 0;
+
+  /* read the length into read_len */
+  if ((ret =
+       thrift_compact_protocol_read_varint32 (cp, &read_len, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  if (cp->string_limit > 0 && read_len > cp->string_limit) {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+                 "got size over limit (%d > %d)", read_len, cp->string_limit);
+    *str = NULL;
+    return -1;
+  }
+
+  if (read_len < 0) {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+                 "got negative size of %d", read_len);
+    *str = NULL;
+    return -1;
+  }
+
+  /* allocate the memory as an array of unsigned char for binary data */
+  *str = g_new0 (gchar, read_len + 1);
+  if (read_len > 0) {
+    if ((ret =
+         thrift_transport_read_all (protocol->transport,
+                                    *str, read_len, error)) < 0) {
+      g_free (*str);
+      *str = NULL;
+      return -1;
+    }
+    xfer += ret;
+  } else {
+    **str = 0;
+  }
+
+  return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_binary (ThriftProtocol *protocol,
+                                     gpointer *buf, guint32 *len,
+                                     GError **error)
+{
+  ThriftCompactProtocol *cp;
+
+  gint32 ret;
+  gint32 xfer;
+
+  gint32 read_len;
+
+  g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+  cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+  xfer = 0;
+  read_len = 0;
+
+  /* read the length into read_len */
+  if ((ret =
+       thrift_compact_protocol_read_varint32 (cp, &read_len, error)) < 0) {
+    return -1;
+  }
+  xfer += ret;
+
+  if (cp->string_limit > 0 && read_len > cp->string_limit) {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+                 "got size over limit (%d > %d)", read_len, cp->string_limit);
+    *buf = NULL;
+    *len = 0;
+    return -1;
+  }
+
+  if (read_len > 0) {
+    /* allocate the memory as an array of unsigned char for binary data */
+    *len = (guint32) read_len;
+    *buf = g_new (guchar, *len);
+    if ((ret =
+         thrift_transport_read_all (protocol->transport,
+                                    *buf, *len, error)) < 0) {
+      g_free (*buf);
+      *buf = NULL;
+      *len = 0;
+      return -1;
+    }
+    xfer += ret;
+
+  } else if (read_len == 0) {
+    *len = (guint32) read_len;
+    *buf = NULL;
+
+  } else {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+                 "got negative size of %d", read_len);
+    *buf = NULL;
+    *len = 0;
+    return -1;
+  }
+
+  return xfer;
+}
+
+/* property accessor */
+void
+thrift_compact_protocol_get_property (GObject *object, guint property_id,
+                                      GValue *value, GParamSpec *pspec)
+{
+  ThriftCompactProtocol *tc;
+
+  THRIFT_UNUSED_VAR (pspec);
+
+  tc = THRIFT_COMPACT_PROTOCOL (object);
+
+  switch (property_id) {
+    case PROP_THRIFT_COMPACT_PROTOCOL_STRING_LIMIT:
+      g_value_set_int (value, tc->string_limit);
+      break;
+    case PROP_THRIFT_COMPACT_PROTOCOL_CONTAINER_LIMIT:
+      g_value_set_int (value, tc->container_limit);
+      break;
+  }
+}
+
+/* property mutator */
+void
+thrift_compact_protocol_set_property (GObject *object, guint property_id,
+                                      const GValue *value, GParamSpec *pspec)
+{
+  ThriftCompactProtocol *tc;
+
+  THRIFT_UNUSED_VAR (pspec);
+
+  tc = THRIFT_COMPACT_PROTOCOL (object);
+
+  switch (property_id) {
+    case PROP_THRIFT_COMPACT_PROTOCOL_STRING_LIMIT:
+      tc->string_limit = g_value_get_int (value);
+      break;
+    case PROP_THRIFT_COMPACT_PROTOCOL_CONTAINER_LIMIT:
+      tc->container_limit = g_value_get_int (value);
+      break;
+  }
+}
+
+/* initialize the class */
+static void
+thrift_compact_protocol_class_init (ThriftCompactProtocolClass *klass)
+{
+  ThriftProtocolClass *cls;
+  GObjectClass *gobject_class;
+  GParamSpec *param_spec;
+
+  cls = THRIFT_PROTOCOL_CLASS (klass);
+  gobject_class = G_OBJECT_CLASS (klass);
+  param_spec = NULL;
+
+  /* setup accessors and mutators */
+  gobject_class->get_property = thrift_compact_protocol_get_property;
+  gobject_class->set_property = thrift_compact_protocol_set_property;
+
+  param_spec = g_param_spec_int ("string_limit",
+                                 "Max allowed string size",
+                                 "Set the max string limit",
+                                 0, /* min */
+                                 G_MAXINT32, /* max */
+                                 0, /* default value */
+                                 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_THRIFT_COMPACT_PROTOCOL_STRING_LIMIT,
+                                   param_spec);
+
+  param_spec = g_param_spec_int ("container_limit",
+                                 "Max allowed container size",
+                                 "Set the max container limit",
+                                 0, /* min */
+                                 G_MAXINT32, /* max */
+                                 0, /* default value */
+                                 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_THRIFT_COMPACT_PROTOCOL_CONTAINER_LIMIT,
+                                   param_spec);
+
+  cls->write_message_begin = thrift_compact_protocol_write_message_begin;
+  cls->write_message_end = thrift_compact_protocol_write_message_end;
+  cls->write_struct_begin = thrift_compact_protocol_write_struct_begin;
+  cls->write_struct_end = thrift_compact_protocol_write_struct_end;
+  cls->write_field_begin = thrift_compact_protocol_write_field_begin;
+  cls->write_field_end = thrift_compact_protocol_write_field_end;
+  cls->write_field_stop = thrift_compact_protocol_write_field_stop;
+  cls->write_map_begin = thrift_compact_protocol_write_map_begin;
+  cls->write_map_end = thrift_compact_protocol_write_map_end;
+  cls->write_list_begin = thrift_compact_protocol_write_list_begin;
+  cls->write_list_end = thrift_compact_protocol_write_list_end;
+  cls->write_set_begin = thrift_compact_protocol_write_set_begin;
+  cls->write_set_end = thrift_compact_protocol_write_set_end;
+  cls->write_bool = thrift_compact_protocol_write_bool;
+  cls->write_byte = thrift_compact_protocol_write_byte;
+  cls->write_i16 = thrift_compact_protocol_write_i16;
+  cls->write_i32 = thrift_compact_protocol_write_i32;
+  cls->write_i64 = thrift_compact_protocol_write_i64;
+  cls->write_double = thrift_compact_protocol_write_double;
+  cls->write_string = thrift_compact_protocol_write_string;
+  cls->write_binary = thrift_compact_protocol_write_binary;
+  cls->read_message_begin = thrift_compact_protocol_read_message_begin;
+  cls->read_message_end = thrift_compact_protocol_read_message_end;
+  cls->read_struct_begin = thrift_compact_protocol_read_struct_begin;
+  cls->read_struct_end = thrift_compact_protocol_read_struct_end;
+  cls->read_field_begin = thrift_compact_protocol_read_field_begin;
+  cls->read_field_end = thrift_compact_protocol_read_field_end;
+  cls->read_map_begin = thrift_compact_protocol_read_map_begin;
+  cls->read_map_end = thrift_compact_protocol_read_map_end;
+  cls->read_list_begin = thrift_compact_protocol_read_list_begin;
+  cls->read_list_end = thrift_compact_protocol_read_list_end;
+  cls->read_set_begin = thrift_compact_protocol_read_set_begin;
+  cls->read_set_end = thrift_compact_protocol_read_set_end;
+  cls->read_bool = thrift_compact_protocol_read_bool;
+  cls->read_byte = thrift_compact_protocol_read_byte;
+  cls->read_i16 = thrift_compact_protocol_read_i16;
+  cls->read_i32 = thrift_compact_protocol_read_i32;
+  cls->read_i64 = thrift_compact_protocol_read_i64;
+  cls->read_double = thrift_compact_protocol_read_double;
+  cls->read_string = thrift_compact_protocol_read_string;
+  cls->read_binary = thrift_compact_protocol_read_binary;
+}
+
+static void
+thrift_compact_protocol_init (ThriftCompactProtocol *self)
+{
+  g_queue_init (&(self->_last_field));
+}
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.h b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.h
new file mode 100644
index 0000000..effcaad
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.h
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef _THRIFT_COMPACT_PROTOCOL_H
+#define _THRIFT_COMPACT_PROTOCOL_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/transport/thrift_transport.h>
+
+G_BEGIN_DECLS
+
+/*! \file thrift_compact_protocol.h
+ *  \brief Compact protocol implementation of a Thrift protocol.  Implements the
+ *         ThriftProtocol interface.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_COMPACT_PROTOCOL (thrift_compact_protocol_get_type ())
+#define THRIFT_COMPACT_PROTOCOL(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_COMPACT_PROTOCOL, \
+   ThriftCompactProtocol))
+#define THRIFT_IS_COMPACT_PROTOCOL(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_COMPACT_PROTOCOL))
+#define THRIFT_COMPACT_PROTOCOL_CLASS(c) \
+  (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_COMPACT_PROTOCOL, \
+   ThriftCompactProtocolClass))
+#define THRIFT_IS_COMPACT_PROTOCOL_CLASS(c) \
+  (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_COMPACT_PROTOCOL))
+#define THRIFT_COMPACT_PROTOCOL_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_COMPACT_PROTOCOL, \
+   ThriftCompactProtocolClass))
+
+
+typedef struct _ThriftCompactProtocol ThriftCompactProtocol;
+
+/*!
+ * Thrift Compact Protocol instance.
+ */
+struct _ThriftCompactProtocol
+{
+  ThriftProtocol parent;
+
+  /* protected */
+  gint32 string_limit;
+  gint32 container_limit;
+
+  /* private */
+
+  /**
+   * (Writing) If we encounter a boolean field begin, save the TField here
+   * so it can have the value incorporated.
+   */
+  const gchar* _bool_field_name;
+  ThriftType _bool_field_type;
+  gint16 _bool_field_id;
+
+  /**
+   * (Reading) If we read a field header, and it's a boolean field, save
+   * the boolean value here so that read_bool can use it.
+   */
+  gboolean _has_bool_value;
+  gboolean _bool_value;
+
+  /**
+   * Used to keep track of the last field for the current and previous structs,
+   * so we can do the delta stuff.
+   */
+
+  GQueue _last_field;
+  gint16 _last_field_id;
+};
+
+typedef struct _ThriftCompactProtocolClass ThriftCompactProtocolClass;
+
+/*!
+ * Thrift Compact Protocol class.
+ */
+struct _ThriftCompactProtocolClass
+{
+  ThriftProtocolClass parent;
+};
+
+/* used by THRIFT_TYPE_COMPACT_PROTOCOL */
+GType thrift_compact_protocol_get_type (void);
+
+G_END_DECLS
+
+#endif /* _THRIFT_COMPACT_PROTOCOL_H */
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.c
new file mode 100644
index 0000000..e725e1f
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.c
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/protocol/thrift_compact_protocol.h>
+#include <thrift/c_glib/protocol/thrift_compact_protocol_factory.h>
+
+/* object properties */
+enum _ThriftCompactProtocolFactoryProperties
+{
+    PROP_0,
+    PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_STRING_LIMIT,
+    PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_CONTAINER_LIMIT
+};
+
+G_DEFINE_TYPE (ThriftCompactProtocolFactory, thrift_compact_protocol_factory,
+               THRIFT_TYPE_PROTOCOL_FACTORY)
+
+ThriftProtocol *
+thrift_compact_protocol_factory_get_protocol (ThriftProtocolFactory *factory,
+                                              ThriftTransport *transport)
+{
+  ThriftCompactProtocolFactory *tcf;
+  ThriftCompactProtocol *tc;
+
+  tcf = THRIFT_COMPACT_PROTOCOL_FACTORY (factory);
+
+  tc = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL,
+                     "transport", transport,
+                     "string_limit", tcf->string_limit,
+                     "container_limit", tcf->container_limit,
+                     NULL);
+
+  return THRIFT_PROTOCOL (tc);
+}
+
+/* property accessor */
+void
+thrift_compact_protocol_factory_get_property (GObject *object, guint property_id,
+                                              GValue *value, GParamSpec *pspec)
+{
+  ThriftCompactProtocolFactory *tcf;
+
+  THRIFT_UNUSED_VAR (pspec);
+
+  tcf = THRIFT_COMPACT_PROTOCOL_FACTORY (object);
+
+  switch (property_id) {
+    case PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_STRING_LIMIT:
+      g_value_set_int (value, tcf->string_limit);
+      break;
+    case PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_CONTAINER_LIMIT:
+      g_value_set_int (value, tcf->container_limit);
+      break;
+  }
+}
+
+/* property mutator */
+void
+thrift_compact_protocol_factory_set_property (GObject *object, guint property_id,
+                                              const GValue *value, GParamSpec
+                                                *pspec)
+{
+  ThriftCompactProtocolFactory *tcf;
+
+  THRIFT_UNUSED_VAR (pspec);
+
+  tcf = THRIFT_COMPACT_PROTOCOL_FACTORY (object);
+
+  switch (property_id) {
+    case PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_STRING_LIMIT:
+      tcf->string_limit = g_value_get_int (value);
+      break;
+    case PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_CONTAINER_LIMIT:
+      tcf->container_limit = g_value_get_int (value);
+      break;
+  }
+}
+
+static void
+thrift_compact_protocol_factory_class_init (ThriftCompactProtocolFactoryClass
+                                              *klass)
+{
+  ThriftProtocolFactoryClass *cls;
+  GObjectClass *gobject_class;
+  GParamSpec *param_spec;
+
+  cls = THRIFT_PROTOCOL_FACTORY_CLASS (klass);
+  gobject_class = G_OBJECT_CLASS (klass);
+  param_spec = NULL;
+
+  /* setup accessors and mutators */
+  gobject_class->get_property = thrift_compact_protocol_factory_get_property;
+  gobject_class->set_property = thrift_compact_protocol_factory_set_property;
+
+  param_spec = g_param_spec_int ("string_limit",
+                                 "Max allowed string size",
+                                 "Set the max string limit",
+                                 0, /* min */
+                                 G_MAXINT32, /* max */
+                                 0, /* default value */
+                                 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_STRING_LIMIT,
+                                   param_spec);
+
+  param_spec = g_param_spec_int ("container_limit",
+                                 "Max allowed container size",
+                                 "Set the max container limit",
+                                 0, /* min */
+                                 G_MAXINT32, /* max */
+                                 0, /* default value */
+                                 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+    PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_CONTAINER_LIMIT, param_spec);
+
+  cls->get_protocol = thrift_compact_protocol_factory_get_protocol;
+}
+
+static void
+thrift_compact_protocol_factory_init (ThriftCompactProtocolFactory *factory)
+{
+  THRIFT_UNUSED_VAR (factory);
+}
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.h b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.h
new file mode 100644
index 0000000..3bf953b
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.h
@@ -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.
+ */
+
+#ifndef _THRIFT_COMPACT_PROTOCOL_FACTORY_H
+#define _THRIFT_COMPACT_PROTOCOL_FACTORY_H
+
+#include <glib-object.h>
+
+#include <thrift/c_glib/protocol/thrift_protocol_factory.h>
+
+G_BEGIN_DECLS
+
+/* type macros */
+#define THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY \
+  (thrift_compact_protocol_factory_get_type ())
+#define THRIFT_COMPACT_PROTOCOL_FACTORY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY, \
+   ThriftCompactProtocolFactory))
+#define THRIFT_IS_COMPACT_PROTOCOL_FACTORY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY))
+#define THRIFT_COMPACT_PROTOCOL_FACTORY_CLASS(c) \
+  (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY, \
+   ThriftCompactProtocolFactoryClass))
+#define THRIFT_IS_COMPACT_PROTOCOL_FACTORY_CLASS(c) \
+  (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY))
+#define THRIFT_COMPACT_PROTOCOL_FACTORY_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY, \
+   ThriftCompactProtocolFactoryClass))
+
+typedef struct _ThriftCompactProtocolFactory ThriftCompactProtocolFactory;
+
+struct _ThriftCompactProtocolFactory
+{
+  ThriftProtocolFactory parent;
+
+  /* protected */
+  gint32 string_limit;
+  gint32 container_limit;
+};
+
+typedef struct _ThriftCompactProtocolFactoryClass
+  ThriftCompactProtocolFactoryClass;
+
+struct _ThriftCompactProtocolFactoryClass
+{
+  ThriftProtocolFactoryClass parent;
+};
+
+/* used by THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY */
+GType thrift_compact_protocol_factory_get_type (void);
+
+G_END_DECLS
+
+#endif /* _THRIFT_COMPACT_PROTOCOL_FACTORY_H */
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_multiplexed_protocol.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_multiplexed_protocol.c
new file mode 100644
index 0000000..727f4a8
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_multiplexed_protocol.c
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/protocol/thrift_protocol_decorator.h>
+#include <thrift/c_glib/protocol/thrift_multiplexed_protocol.h>
+
+
+enum
+{
+  PROP_THRIFT_MULTIPLEXED_PROTOCOL_SERVICE_NAME = 1,
+  PROP_THRIFT_MULTIPLEXED_PROTOCOL_END
+};
+
+G_DEFINE_TYPE(ThriftMultiplexedProtocol, thrift_multiplexed_protocol, THRIFT_TYPE_PROTOCOL_DECORATOR)
+
+
+static GParamSpec *thrift_multiplexed_protocol_obj_properties[PROP_THRIFT_MULTIPLEXED_PROTOCOL_END] = { NULL, };
+
+gint32
+thrift_multiplexed_protocol_write_message_begin (ThriftMultiplexedProtocol *protocol,
+    const gchar *name, const ThriftMessageType message_type,
+    const gint32 seqid, GError **error)
+{
+  gint32 ret;
+  gchar *service_name = NULL;
+  g_return_val_if_fail (THRIFT_IS_MULTIPLEXED_PROTOCOL (protocol), -1);
+
+  ThriftMultiplexedProtocol *self = THRIFT_MULTIPLEXED_PROTOCOL (protocol);
+  ThriftMultiplexedProtocolClass *multiplexClass = THRIFT_MULTIPLEXED_PROTOCOL_GET_CLASS(self);
+
+  if( (message_type == T_CALL || message_type == T_ONEWAY) && self->service_name != NULL) {
+    service_name = g_strdup_printf("%s%s%s", self->service_name, THRIFT_MULTIPLEXED_PROTOCOL_DEFAULT_SEPARATOR, name);
+  }else{
+    service_name = g_strdup(name);
+  }
+
+  /* relay to the protocol_decorator */
+  ret = thrift_protocol_decorator_write_message_begin(protocol, service_name, message_type, seqid, error);
+
+  g_free(service_name);
+
+  return ret;
+}
+
+
+static void
+thrift_multiplexed_protocol_set_property (GObject      *object,
+    guint         property_id,
+    const GValue *value,
+    GParamSpec   *pspec)
+{
+  ThriftMultiplexedProtocol *self = THRIFT_MULTIPLEXED_PROTOCOL (object);
+
+  switch (property_id)
+  {
+  case PROP_THRIFT_MULTIPLEXED_PROTOCOL_SERVICE_NAME:
+    self->service_name = g_value_dup_string (value);
+    break;
+
+  default:
+    /* We don't have any other property... */
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    break;
+  }
+}
+
+static void
+thrift_multiplexed_protocol_get_property (GObject    *object,
+    guint       property_id,
+    GValue     *value,
+    GParamSpec *pspec)
+{
+  ThriftMultiplexedProtocol *self = THRIFT_MULTIPLEXED_PROTOCOL (object);
+
+  switch (property_id)
+  {
+  case PROP_THRIFT_MULTIPLEXED_PROTOCOL_SERVICE_NAME:
+    g_value_set_string (value, self->service_name);
+    break;
+
+  default:
+    /* We don't have any other property... */
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    break;
+  }
+}
+
+
+static void
+thrift_multiplexed_protocol_init (ThriftMultiplexedProtocol *protocol)
+{
+  protocol->service_name = NULL;
+}
+
+static void
+thrift_multiplexed_protocol_finalize (GObject *gobject)
+{
+  ThriftMultiplexedProtocol *self = THRIFT_MULTIPLEXED_PROTOCOL (gobject);
+
+  if (self->service_name) {
+    g_free(self->service_name);
+    self->service_name = NULL;
+  }
+
+  /* Always chain up to the parent class; as with dispose(), finalize()
+   * is guaranteed to exist on the parent's class virtual function table
+   */
+  G_OBJECT_CLASS (thrift_multiplexed_protocol_parent_class)->finalize(gobject);
+}
+
+
+/* initialize the class */
+static void
+thrift_multiplexed_protocol_class_init (ThriftMultiplexedProtocolClass *klass)
+{
+  ThriftProtocolClass *cls = THRIFT_PROTOCOL_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  cls->write_message_begin = thrift_multiplexed_protocol_write_message_begin;
+
+  object_class->set_property = thrift_multiplexed_protocol_set_property;
+  object_class->get_property = thrift_multiplexed_protocol_get_property;
+  object_class->finalize = thrift_multiplexed_protocol_finalize;
+
+  thrift_multiplexed_protocol_obj_properties[PROP_THRIFT_MULTIPLEXED_PROTOCOL_SERVICE_NAME] =
+      g_param_spec_string ("service-name",
+          "Service name the protocol points to",
+          "Set the service name",
+          NULL,
+          (G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+  g_object_class_install_properties (object_class,
+      PROP_THRIFT_MULTIPLEXED_PROTOCOL_END,
+      thrift_multiplexed_protocol_obj_properties);
+}
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_multiplexed_protocol.h b/lib/c_glib/src/thrift/c_glib/protocol/thrift_multiplexed_protocol.h
new file mode 100644
index 0000000..c6e08fb
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_multiplexed_protocol.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_MULTIPLEXED_PROTOCOL_H
+#define _THRIFT_MULTIPLEXED_PROTOCOL_H
+
+#include <glib-object.h>
+
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/protocol/thrift_protocol_decorator.h>
+#include <thrift/c_glib/transport/thrift_transport.h>
+
+G_BEGIN_DECLS
+
+/*! \file thrift_multiplexed_protocol.h
+ *  \brief Multiplexed protocol implementation of a Thrift protocol.  Implements the
+ *         ThriftProtocol interface.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_MULTIPLEXED_PROTOCOL (thrift_multiplexed_protocol_get_type ())
+#define THRIFT_MULTIPLEXED_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_MULTIPLEXED_PROTOCOL, ThriftMultiplexedProtocol))
+#define THRIFT_IS_MULTIPLEXED_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_MULTIPLEXED_PROTOCOL))
+#define THRIFT_MULTIPLEXED_PROTOCOL_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_MULTIPLEXED_PROTOCOL, ThriftMultiplexedProtocolClass))
+#define THRIFT_IS_MULTIPLEXED_PROTOCOL_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_MULTIPLEXED_PROTOCOL))
+#define THRIFT_MULTIPLEXED_PROTOCOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_MULTIPLEXED_PROTOCOL, ThriftMultiplexedProtocolClass))
+
+/* constant */
+#define THRIFT_MULTIPLEXED_PROTOCOL_DEFAULT_SEPARATOR ":"
+
+typedef struct _ThriftMultiplexedProtocol ThriftMultiplexedProtocol;
+
+
+
+/*!
+ * Thrift Multiplexed Protocol instance.
+ */
+struct _ThriftMultiplexedProtocol
+{
+  ThriftProtocolDecorator parent;
+
+  gchar *service_name;
+};
+
+typedef struct _ThriftMultiplexedProtocolClass ThriftMultiplexedProtocolClass;
+
+/*!
+ * Thrift Multiplexed Protocol class.
+ */
+struct _ThriftMultiplexedProtocolClass
+{
+  ThriftProtocolDecoratorClass parent;
+};
+
+/* used by THRIFT_TYPE_MULTIPLEXED_PROTOCOL */
+GType thrift_multiplexed_protocol_get_type (void);
+
+G_END_DECLS
+
+#endif /* _THRIFT_MULTIPLEXED_PROTOCOL_H */
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol.c
index d6315d8..8296a8c 100644
--- a/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol.c
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol.c
@@ -61,15 +61,15 @@
   switch (property_id)
   {
     case PROP_THRIFT_PROTOCOL_TRANSPORT:
-      protocol->transport = g_value_get_object (value);
+      protocol->transport = g_value_dup_object (value);
       break;
   }
 }
 
 
 gint32
-thrift_protocol_write_message_begin (ThriftProtocol *protocol, 
-                                     const gchar *name, 
+thrift_protocol_write_message_begin (ThriftProtocol *protocol,
+                                     const gchar *name,
                                      const ThriftMessageType message_type,
                                      const gint32 seqid, GError **error)
 {
@@ -243,7 +243,7 @@
                                                              len, error);
 }
 
-gint32 
+gint32
 thrift_protocol_read_message_begin (ThriftProtocol *protocol,
                                     gchar **name,
                                     ThriftMessageType *message_type,
@@ -254,7 +254,7 @@
                                                    seqid, error);
 }
 
-gint32 
+gint32
 thrift_protocol_read_message_end (ThriftProtocol *protocol,
                                   GError **error)
 {
@@ -262,7 +262,7 @@
                                                                  error);
 }
 
-gint32 
+gint32
 thrift_protocol_read_struct_begin (ThriftProtocol *protocol,
                                    gchar **name,
                                    GError **error)
@@ -279,7 +279,7 @@
                                                                 error);
 }
 
-gint32 
+gint32
 thrift_protocol_read_field_begin (ThriftProtocol *protocol,
                                   gchar **name,
                                   ThriftType *field_type,
@@ -293,7 +293,7 @@
                                                                  error);
 }
 
-gint32 
+gint32
 thrift_protocol_read_field_end (ThriftProtocol *protocol,
                                 GError **error)
 {
@@ -301,7 +301,7 @@
                                                                error);
 }
 
-gint32 
+gint32
 thrift_protocol_read_map_begin (ThriftProtocol *protocol,
                                 ThriftType *key_type,
                                 ThriftType *value_type, guint32 *size,
@@ -311,17 +311,17 @@
                                                                key_type,
                                                                value_type,
                                                                size,
-                                                               error); 
+                                                               error);
 }
 
-gint32 
+gint32
 thrift_protocol_read_map_end (ThriftProtocol *protocol, GError **error)
 {
   return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_map_end (protocol,
                                                              error);
 }
 
-gint32 
+gint32
 thrift_protocol_read_list_begin (ThriftProtocol *protocol,
                                  ThriftType *element_type,
                                  guint32 *size, GError **error)
@@ -412,7 +412,7 @@
 }
 
 gint32
-thrift_protocol_read_binary (ThriftProtocol *protocol, gpointer *buf, 
+thrift_protocol_read_binary (ThriftProtocol *protocol, gpointer *buf,
                              guint32 *len, GError **error)
 {
   return THRIFT_PROTOCOL_GET_CLASS (protocol)->read_binary (protocol, buf,
@@ -465,7 +465,7 @@
       }
     case T_STRUCT:
       {
-        guint32 result = 0;
+        gint32 result = 0;
         gchar *name;
         gint16 fid;
         ThriftType ftype;
@@ -475,6 +475,10 @@
         {
           result += thrift_protocol_read_field_begin (protocol, &name, &ftype,
                                                       &fid, error);
+          if (result < 0)
+          {
+            return result;  
+          }
           if (ftype == T_STOP)
           {
             break;
@@ -485,9 +489,9 @@
         result += thrift_protocol_read_struct_end (protocol, error);
         return result;
       }
-    case T_MAP:
+    case T_SET:
       {
-        guint32 result = 0;
+        gint32 result = 0;
         ThriftType elem_type;
         guint32 i, size;
         result += thrift_protocol_read_set_begin (protocol, &elem_type, &size,
@@ -499,9 +503,25 @@
         result += thrift_protocol_read_set_end (protocol, error);
         return result;
       }
+    case T_MAP:
+      {
+        gint32 result = 0;
+        ThriftType elem_type;
+        ThriftType key_type;
+        guint32 i, size;
+        result += thrift_protocol_read_map_begin (protocol, &key_type, &elem_type, &size,
+                                                  error);
+        for (i = 0; i < size; i++)
+        {
+          result += thrift_protocol_skip (protocol, key_type, error);
+          result += thrift_protocol_skip (protocol, elem_type, error);
+        }
+        result += thrift_protocol_read_map_end (protocol, error);
+        return result;
+      }
     case T_LIST:
       {
-        guint32 result = 0;
+        gint32 result = 0;
         ThriftType elem_type;
         guint32 i, size;
         result += thrift_protocol_read_list_begin (protocol, &elem_type, &size,
@@ -533,12 +553,27 @@
 }
 
 static void
+thrift_protocol_dispose (GObject *gobject)
+{
+  ThriftProtocol *self = THRIFT_PROTOCOL (gobject);
+
+  g_clear_object(&self->transport);
+
+  /* Always chain up to the parent class; there is no need to check if
+   * the parent class implements the dispose() virtual function: it is
+   * always guaranteed to do so
+   */
+  G_OBJECT_CLASS (thrift_protocol_parent_class)->dispose(gobject);
+}
+
+static void
 thrift_protocol_class_init (ThriftProtocolClass *cls)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
 
   gobject_class->get_property = thrift_protocol_get_property;
   gobject_class->set_property = thrift_protocol_set_property;
+  gobject_class->dispose = thrift_protocol_dispose;
 
   g_object_class_install_property (gobject_class,
       PROP_THRIFT_PROTOCOL_TRANSPORT,
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol.h b/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol.h
index df28a4a..58fe5e0 100644
--- a/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol.h
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol.h
@@ -328,7 +328,8 @@
   THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
   THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
   THRIFT_PROTOCOL_ERROR_BAD_VERSION,
-  THRIFT_PROTOCOL_ERROR_NOT_IMPLEMENTED
+  THRIFT_PROTOCOL_ERROR_NOT_IMPLEMENTED,
+  THRIFT_PROTOCOL_ERROR_DEPTH_LIMIT
 } ThriftProtocolError;
 
 /* define an error domain for GError to use */
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_decorator.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_decorator.c
new file mode 100644
index 0000000..03f9420
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_decorator.c
@@ -0,0 +1,623 @@
+/*
+ * 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.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/protocol/thrift_binary_protocol.h>
+#include <thrift/c_glib/protocol/thrift_protocol_decorator.h>
+
+G_DEFINE_TYPE(ThriftProtocolDecorator, thrift_protocol_decorator, THRIFT_TYPE_PROTOCOL)
+
+
+enum
+{
+  PROP_THRIFT_TYPE_PROTOCOL_DECORATOR_CONCRETE_PROTOCOL = 1,
+  PROP_THRIFT_TYPE_PROTOCOL_DECORATOR_END
+};
+
+static GParamSpec *thrift_protocol_decorator_obj_properties[PROP_THRIFT_TYPE_PROTOCOL_DECORATOR_END] = { NULL, };
+
+
+
+
+
+gint32
+thrift_protocol_decorator_write_message_begin (ThriftProtocol *protocol,
+                                     const gchar *name,
+                                     const ThriftMessageType message_type,
+                                     const gint32 seqid, GError **error)
+{
+
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+  ThriftProtocolClass *proto = THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol);
+
+  g_debug("Concrete protocol %p | %p", (void *)self->concrete_protocol, (void *)proto);
+
+  return proto->write_message_begin (self->concrete_protocol, name,
+                                    message_type, seqid,
+                                    error);
+}
+
+gint32
+thrift_protocol_decorator_write_message_end (ThriftProtocol *protocol, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_message_end (self->concrete_protocol,
+                                                                  error);
+}
+
+gint32
+thrift_protocol_decorator_write_struct_begin (ThriftProtocol *protocol, const gchar *name,
+                                    GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_struct_begin (self->concrete_protocol,
+                                                   name, error);
+}
+
+gint32
+thrift_protocol_decorator_write_struct_end (ThriftProtocol *protocol, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_struct_end (self->concrete_protocol,
+                                                                 error);
+}
+
+gint32
+thrift_protocol_decorator_write_field_begin (ThriftProtocol *protocol,
+                                   const gchar *name,
+                                   const ThriftType field_type,
+                                   const gint16 field_id,
+                                   GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_field_begin (self->concrete_protocol,
+                                                   name, field_type,
+                                                   field_id, error);
+}
+
+gint32
+thrift_protocol_decorator_write_field_end (ThriftProtocol *protocol, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_field_end (self->concrete_protocol,
+                                                                error);
+}
+
+gint32
+thrift_protocol_decorator_write_field_stop (ThriftProtocol *protocol, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_field_stop (self->concrete_protocol,
+                                                                 error);
+}
+
+gint32
+thrift_protocol_decorator_write_map_begin (ThriftProtocol *protocol,
+                                 const ThriftType key_type,
+                                 const ThriftType value_type,
+                                 const guint32 size, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_map_begin (self->concrete_protocol,
+                                                   key_type, value_type,
+                                                   size, error);
+}
+
+gint32
+thrift_protocol_decorator_write_map_end (ThriftProtocol *protocol, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_map_end (self->concrete_protocol,
+                                                              error);
+}
+
+gint32
+thrift_protocol_decorator_write_list_begin (ThriftProtocol *protocol,
+                                  const ThriftType element_type,
+                                  const guint32 size, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_list_begin (self->concrete_protocol,
+                                                   element_type, size,
+                                                   error);
+}
+
+gint32
+thrift_protocol_decorator_write_list_end (ThriftProtocol *protocol, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_list_end (self->concrete_protocol,
+                                                               error);
+}
+
+gint32
+thrift_protocol_decorator_write_set_begin (ThriftProtocol *protocol,
+                                 const ThriftType element_type,
+                                 const guint32 size, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_set_begin (self->concrete_protocol,
+                                                   element_type, size,
+                                                   error);
+}
+
+gint32
+thrift_protocol_decorator_write_set_end (ThriftProtocol *protocol, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_set_end (self->concrete_protocol,
+                                                              error);
+}
+
+gint32
+thrift_protocol_decorator_write_bool (ThriftProtocol *protocol,
+                            const gboolean value, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_bool (self->concrete_protocol, value,
+                                                           error);
+}
+
+gint32
+thrift_protocol_decorator_write_byte (ThriftProtocol *protocol, const gint8 value,
+                            GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_byte (self->concrete_protocol, value,
+                                                           error);
+}
+
+gint32
+thrift_protocol_decorator_write_i16 (ThriftProtocol *protocol, const gint16 value,
+                           GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_i16 (self->concrete_protocol, value,
+                                                          error);
+}
+
+gint32
+thrift_protocol_decorator_write_i32 (ThriftProtocol *protocol, const gint32 value,
+                           GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_i32 (self->concrete_protocol, value,
+                                                          error);
+}
+
+gint32
+thrift_protocol_decorator_write_i64 (ThriftProtocol *protocol, const gint64 value,
+                           GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_i64 (self->concrete_protocol, value,
+                                                          error);
+}
+
+gint32
+thrift_protocol_decorator_write_double (ThriftProtocol *protocol,
+                              const gdouble value, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_double (self->concrete_protocol,
+                                                             value, error);
+}
+
+gint32
+thrift_protocol_decorator_write_string (ThriftProtocol *protocol,
+                              const gchar *str, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_string (self->concrete_protocol, str,
+                                                             error);
+}
+
+gint32
+thrift_protocol_decorator_write_binary (ThriftProtocol *protocol, const gpointer buf,
+                              const guint32 len, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->write_binary (self->concrete_protocol, buf,
+                                                             len, error);
+}
+
+gint32
+thrift_protocol_decorator_read_message_begin (ThriftProtocol *protocol,
+                                    gchar **name,
+                                    ThriftMessageType *message_type,
+                                    gint32 *seqid, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_message_begin (self->concrete_protocol,
+                                                   name, message_type,
+                                                   seqid, error);
+}
+
+gint32
+thrift_protocol_decorator_read_message_end (ThriftProtocol *protocol,
+                                  GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_message_end (self->concrete_protocol,
+                                                                 error);
+}
+
+gint32
+thrift_protocol_decorator_read_struct_begin (ThriftProtocol *protocol,
+                                   gchar **name,
+                                   GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_struct_begin (self->concrete_protocol,
+                                                                  name,
+                                                                  error);
+}
+
+gint32
+thrift_protocol_decorator_read_struct_end (ThriftProtocol *protocol, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_struct_end (self->concrete_protocol,
+                                                                error);
+}
+
+gint32
+thrift_protocol_decorator_read_field_begin (ThriftProtocol *protocol,
+                                  gchar **name,
+                                  ThriftType *field_type,
+                                  gint16 *field_id,
+                                  GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_field_begin (self->concrete_protocol,
+                                                                 name,
+                                                                 field_type,
+                                                                 field_id,
+                                                                 error);
+}
+
+gint32
+thrift_protocol_decorator_read_field_end (ThriftProtocol *protocol,
+                                GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_field_end (self->concrete_protocol,
+                                                               error);
+}
+
+gint32
+thrift_protocol_decorator_read_map_begin (ThriftProtocol *protocol,
+                                ThriftType *key_type,
+                                ThriftType *value_type, guint32 *size,
+                                GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_map_begin (self->concrete_protocol,
+                                                               key_type,
+                                                               value_type,
+                                                               size,
+                                                               error);
+}
+
+gint32
+thrift_protocol_decorator_read_map_end (ThriftProtocol *protocol, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_map_end (self->concrete_protocol,
+                                                             error);
+}
+
+gint32
+thrift_protocol_decorator_read_list_begin (ThriftProtocol *protocol,
+                                 ThriftType *element_type,
+                                 guint32 *size, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_list_begin (self->concrete_protocol,
+                                                                element_type,
+                                                                size, error);
+}
+
+gint32
+thrift_protocol_decorator_read_list_end (ThriftProtocol *protocol, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_list_end (self->concrete_protocol,
+                                                              error);
+}
+
+gint32
+thrift_protocol_decorator_read_set_begin (ThriftProtocol *protocol,
+                                ThriftType *element_type,
+                                guint32 *size, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_set_begin (self->concrete_protocol,
+                                                               element_type,
+                                                               size, error);
+}
+
+gint32
+thrift_protocol_decorator_read_set_end (ThriftProtocol *protocol, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_set_end (self->concrete_protocol,
+                                                             error);
+}
+
+gint32
+thrift_protocol_decorator_read_bool (ThriftProtocol *protocol, gboolean *value,
+                           GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_bool (self->concrete_protocol, value,
+                                                          error);
+}
+
+gint32
+thrift_protocol_decorator_read_byte (ThriftProtocol *protocol, gint8 *value,
+                           GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_byte (self->concrete_protocol, value,
+                                                          error);
+}
+
+gint32
+thrift_protocol_decorator_read_i16 (ThriftProtocol *protocol, gint16 *value,
+                          GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_i16 (self->concrete_protocol, value,
+                                                         error);
+}
+
+gint32
+thrift_protocol_decorator_read_i32 (ThriftProtocol *protocol, gint32 *value,
+                          GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_i32 (self->concrete_protocol, value,
+                                                         error);
+}
+
+gint32
+thrift_protocol_decorator_read_i64 (ThriftProtocol *protocol, gint64 *value,
+                          GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_i64 (self->concrete_protocol, value,
+                                                         error);
+}
+
+gint32
+thrift_protocol_decorator_read_double (ThriftProtocol *protocol,
+                             gdouble *value, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_double (self->concrete_protocol, value,
+                                                            error);
+}
+
+gint32
+thrift_protocol_decorator_read_string (ThriftProtocol *protocol,
+                             gchar **str, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_string (self->concrete_protocol, str,
+                                                            error);
+}
+
+gint32
+thrift_protocol_decorator_read_binary (ThriftProtocol *protocol, gpointer *buf,
+                             guint32 *len, GError **error)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (protocol);
+
+  return THRIFT_PROTOCOL_GET_CLASS (self->concrete_protocol)->read_binary (self->concrete_protocol, buf,
+                                                            len, error);
+}
+
+
+static void
+thrift_protocol_decorator_set_property (GObject      *object,
+    guint         property_id,
+    const GValue *value,
+    GParamSpec   *pspec)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (object);
+
+  switch (property_id)
+  {
+  case PROP_THRIFT_TYPE_PROTOCOL_DECORATOR_CONCRETE_PROTOCOL:
+    self->concrete_protocol = g_value_dup_object (value);
+    break;
+
+  default:
+    /* We don't have any other property... */
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    break;
+  }
+}
+
+static void
+thrift_protocol_decorator_get_property (GObject    *object,
+    guint       property_id,
+    GValue     *value,
+    GParamSpec *pspec)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (object);
+
+  switch (property_id)
+  {
+  case PROP_THRIFT_TYPE_PROTOCOL_DECORATOR_CONCRETE_PROTOCOL:
+    g_value_set_object (value, self->concrete_protocol);
+    break;
+
+  default:
+    /* We don't have any other property... */
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    break;
+  }
+}
+
+
+ThriftProtocol *
+thrift_protocol_decorator_get_concrete_protocol(ThriftProtocolDecorator *protocol)
+{
+  ThriftProtocol *retval = NULL;
+  if(!THRIFT_IS_PROTOCOL_DECORATOR(protocol)){
+    g_warning("The type is not protocol decorator");
+    return NULL;
+  }
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR(protocol);
+  g_debug("Getting concrete protocol from %p -> %p", (void *)self, (void *)self->concrete_protocol);
+
+  return retval;
+}
+
+
+static void
+thrift_protocol_decorator_init (ThriftProtocolDecorator *protocol)
+{
+  protocol->concrete_protocol = NULL;
+}
+
+static void
+thrift_protocol_decorator_dispose (GObject *gobject)
+{
+  ThriftProtocolDecorator *self = THRIFT_PROTOCOL_DECORATOR (gobject);
+
+  g_clear_object(&self->concrete_protocol);
+
+  /* Always chain up to the parent class; there is no need to check if
+   * the parent class implements the dispose() virtual function: it is
+   * always guaranteed to do so
+   */
+  G_OBJECT_CLASS (thrift_protocol_decorator_parent_class)->dispose(gobject);
+}
+
+/* initialize the class */
+static void
+thrift_protocol_decorator_class_init (ThriftProtocolDecoratorClass *klass)
+{
+  ThriftProtocolClass *cls = THRIFT_PROTOCOL_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  object_class->set_property = thrift_protocol_decorator_set_property;
+  object_class->get_property = thrift_protocol_decorator_get_property;
+  object_class->dispose = thrift_protocol_decorator_dispose;
+
+  thrift_protocol_decorator_obj_properties[PROP_THRIFT_TYPE_PROTOCOL_DECORATOR_CONCRETE_PROTOCOL] =
+      g_param_spec_object ("protocol",
+          "Protocol",
+          "Set the protocol to be implemented", THRIFT_TYPE_PROTOCOL,
+          (G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+  g_object_class_install_properties (object_class,
+      PROP_THRIFT_TYPE_PROTOCOL_DECORATOR_END,
+      thrift_protocol_decorator_obj_properties);
+
+  g_debug("Current decorator write_message_begin addr %p, new %p", cls->write_message_begin, thrift_protocol_decorator_write_message_begin);
+
+  cls->write_message_begin = thrift_protocol_decorator_write_message_begin;
+  cls->write_message_end = thrift_protocol_decorator_write_message_end;
+  cls->write_struct_begin = thrift_protocol_decorator_write_struct_begin;
+  cls->write_struct_end = thrift_protocol_decorator_write_struct_end;
+  cls->write_field_begin = thrift_protocol_decorator_write_field_begin;
+  cls->write_field_end = thrift_protocol_decorator_write_field_end;
+  cls->write_field_stop = thrift_protocol_decorator_write_field_stop;
+  cls->write_map_begin = thrift_protocol_decorator_write_map_begin;
+  cls->write_map_end = thrift_protocol_decorator_write_map_end;
+  cls->write_list_begin = thrift_protocol_decorator_write_list_begin;
+  cls->write_list_end = thrift_protocol_decorator_write_list_end;
+  cls->write_set_begin = thrift_protocol_decorator_write_set_begin;
+  cls->write_set_end = thrift_protocol_decorator_write_set_end;
+  cls->write_bool = thrift_protocol_decorator_write_bool;
+  cls->write_byte = thrift_protocol_decorator_write_byte;
+  cls->write_i16 = thrift_protocol_decorator_write_i16;
+  cls->write_i32 = thrift_protocol_decorator_write_i32;
+  cls->write_i64 = thrift_protocol_decorator_write_i64;
+  cls->write_double = thrift_protocol_decorator_write_double;
+  cls->write_string = thrift_protocol_decorator_write_string;
+  cls->write_binary = thrift_protocol_decorator_write_binary;
+  cls->read_message_begin = thrift_protocol_decorator_read_message_begin;
+  cls->read_message_end = thrift_protocol_decorator_read_message_end;
+  cls->read_struct_begin = thrift_protocol_decorator_read_struct_begin;
+  cls->read_struct_end = thrift_protocol_decorator_read_struct_end;
+  cls->read_field_begin = thrift_protocol_decorator_read_field_begin;
+  cls->read_field_end = thrift_protocol_decorator_read_field_end;
+  cls->read_map_begin = thrift_protocol_decorator_read_map_begin;
+  cls->read_map_end = thrift_protocol_decorator_read_map_end;
+  cls->read_list_begin = thrift_protocol_decorator_read_list_begin;
+  cls->read_list_end = thrift_protocol_decorator_read_list_end;
+  cls->read_set_begin = thrift_protocol_decorator_read_set_begin;
+  cls->read_set_end = thrift_protocol_decorator_read_set_end;
+  cls->read_bool = thrift_protocol_decorator_read_bool;
+  cls->read_byte = thrift_protocol_decorator_read_byte;
+  cls->read_i16 = thrift_protocol_decorator_read_i16;
+  cls->read_i32 = thrift_protocol_decorator_read_i32;
+  cls->read_i64 = thrift_protocol_decorator_read_i64;
+  cls->read_double = thrift_protocol_decorator_read_double;
+  cls->read_string = thrift_protocol_decorator_read_string;
+  cls->read_binary = thrift_protocol_decorator_read_binary;
+}
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_decorator.h b/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_decorator.h
new file mode 100644
index 0000000..13b6af2
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_protocol_decorator.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_PROTOCOL_DECORATOR_H
+#define _THRIFT_PROTOCOL_DECORATOR_H
+
+#include <glib-object.h>
+
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/transport/thrift_transport.h>
+
+G_BEGIN_DECLS
+
+/*! \file thrift_protocol_decorator.h
+ *  \brief Multiplexed protocol implementation of a Thrift protocol.  Implements the
+ *         ThriftProtocol interface.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_PROTOCOL_DECORATOR (thrift_protocol_decorator_get_type ())
+#define THRIFT_PROTOCOL_DECORATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_PROTOCOL_DECORATOR, ThriftProtocolDecorator))
+#define THRIFT_IS_PROTOCOL_DECORATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_PROTOCOL_DECORATOR))
+#define THRIFT_PROTOCOL_DECORATOR_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_PROTOCOL_DECORATOR, ThriftProtocolDecoratorClass))
+#define THRIFT_IS_PROTOCOL_DECORATOR_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_PROTOCOL_DECORATOR))
+#define THRIFT_PROTOCOL_DECORATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_PROTOCOL_DECORATOR, ThriftProtocolDecoratorClass))
+
+typedef struct _ThriftProtocolDecorator ThriftProtocolDecorator;
+
+
+/*!
+ * Thrift Protocol Decorator instance.
+ */
+struct _ThriftProtocolDecorator
+{
+  ThriftProtocol parent;
+
+  ThriftProtocol *concrete_protocol;
+};
+
+typedef struct _ThriftProtocolDecoratorClass ThriftProtocolDecoratorClass;
+
+/*!
+ * Thrift Protocol Decorator class.
+ */
+struct _ThriftProtocolDecoratorClass
+{
+  ThriftProtocolClass parent;
+
+};
+
+/* used by THRIFT_TYPE_PROTOCOL_DECORATOR */
+GType thrift_protocol_decorator_get_type (void);
+
+G_END_DECLS
+
+#endif /* _THRIFT_PROTOCOL_DECORATOR_H */
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.c
new file mode 100644
index 0000000..a0d560b
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.c
@@ -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.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/protocol/thrift_protocol_decorator.h>
+#include <thrift/c_glib/protocol/thrift_stored_message_protocol.h>
+
+
+enum
+{
+  PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_NAME = 1,
+  PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_TYPE,
+  PROP_THRIFT_STORED_MESSAGE_PROTOCOL_SEQUENCE_ID,
+  PROP_THRIFT_STORED_MESSAGE_PROTOCOL_TRANSPORT, /* TODO ugly hack */
+  PROP_THRIFT_STORED_MESSAGE_PROTOCOL_END
+};
+
+G_DEFINE_TYPE(ThriftStoredMessageProtocol, thrift_stored_message_protocol, THRIFT_TYPE_PROTOCOL_DECORATOR)
+
+
+static GParamSpec *thrift_stored_message_protocol_obj_properties[PROP_THRIFT_STORED_MESSAGE_PROTOCOL_END] = { NULL, };
+
+gint32
+thrift_stored_message_protocol_read_message_begin (ThriftProtocol *protocol,
+					   gchar **name,
+					   ThriftMessageType *message_type,
+					   gint32 *seqid, GError **error)
+{
+  gint32 ret = 0;
+  g_return_val_if_fail (THRIFT_IS_STORED_MESSAGE_PROTOCOL (protocol), -1);
+  THRIFT_UNUSED_VAR (error);
+
+  ThriftStoredMessageProtocol *self = THRIFT_STORED_MESSAGE_PROTOCOL (protocol);
+
+  /* We return the stored values on construction */
+  *name = self->name;
+  *message_type = self->mtype;
+  *seqid = self->seqid;
+
+  return ret;
+}
+
+
+static void
+thrift_stored_message_protocol_set_property (GObject      *object,
+					     guint         property_id,
+					     const GValue *value,
+					     GParamSpec   *pspec)
+{
+  ThriftStoredMessageProtocol *self = THRIFT_STORED_MESSAGE_PROTOCOL (object);
+
+  switch (property_id)
+  {
+    case PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_NAME:
+      self->name = g_value_dup_string (value);
+      break;
+    case PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_TYPE:
+      self->mtype = g_value_get_int (value);
+      break;
+    case PROP_THRIFT_STORED_MESSAGE_PROTOCOL_SEQUENCE_ID:
+      self->seqid = g_value_get_int (value);
+      break;
+
+    default:
+      /* We don't have any other property... */
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static void
+thrift_stored_message_protocol_get_property (GObject    *object,
+					     guint       property_id,
+					     GValue     *value,
+					     GParamSpec *pspec)
+{
+  ThriftStoredMessageProtocol *self = THRIFT_STORED_MESSAGE_PROTOCOL (object);
+  ThriftProtocolDecorator *decorator = THRIFT_PROTOCOL_DECORATOR (object);
+  ThriftTransport *transport=NULL;
+  switch (property_id)
+  {
+    case PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_NAME:
+      g_value_set_string (value, self->name);
+      break;
+    case PROP_THRIFT_STORED_MESSAGE_PROTOCOL_TRANSPORT:
+      /* FIXME Since we don't override properties in the decorator as it should
+         we just override the properties that we know are used */
+      g_object_get(decorator->concrete_protocol,pspec->name, &transport, NULL);
+      g_value_set_pointer (value, transport);
+      break;
+
+    default:
+      /* We don't have any other property... */
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+
+static void
+thrift_stored_message_protocol_init (ThriftStoredMessageProtocol *protocol)
+{
+  protocol->name = NULL;
+}
+
+static void
+thrift_stored_message_protocol_finalize (GObject *gobject)
+{
+  ThriftStoredMessageProtocol *self = THRIFT_STORED_MESSAGE_PROTOCOL (gobject);
+
+  if (self->name) {
+      g_free(self->name);
+      self->name = NULL;
+  }
+
+  /* Always chain up to the parent class; as with dispose(), finalize()
+   * is guaranteed to exist on the parent's class virtual function table
+   */
+  G_OBJECT_CLASS (thrift_stored_message_protocol_parent_class)->finalize(gobject);
+}
+
+
+/* initialize the class */
+static void
+thrift_stored_message_protocol_class_init (ThriftStoredMessageProtocolClass *klass)
+{
+  ThriftProtocolClass *cls = THRIFT_PROTOCOL_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  cls->read_message_begin = thrift_stored_message_protocol_read_message_begin;
+
+  object_class->set_property = thrift_stored_message_protocol_set_property;
+  object_class->get_property = thrift_stored_message_protocol_get_property;
+  object_class->finalize = thrift_stored_message_protocol_finalize;
+
+  thrift_stored_message_protocol_obj_properties[PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_NAME] =
+      g_param_spec_string ("name",
+			   "Service name the protocol points to",
+			   "Set the service name",
+			   NULL,
+			   (G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+  thrift_stored_message_protocol_obj_properties[PROP_THRIFT_STORED_MESSAGE_PROTOCOL_MESSAGE_TYPE] =
+      g_param_spec_int ("type",
+			"Message type in the wire",
+			"Set the message type in the wire",
+			T_CALL, T_ONEWAY,
+			T_CALL,
+			(G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+  thrift_stored_message_protocol_obj_properties[PROP_THRIFT_STORED_MESSAGE_PROTOCOL_SEQUENCE_ID] =
+      g_param_spec_int ("seqid",
+			"Sequence id type in the wire",
+			"Set the Sequence id in the wire",
+			0, G_MAXINT,
+			0,
+			(G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+  /* TODO Ugly hack, in theory we must override all properties from underlaying
+     protocol */
+  thrift_stored_message_protocol_obj_properties[PROP_THRIFT_STORED_MESSAGE_PROTOCOL_TRANSPORT] =
+      g_param_spec_pointer ("transport",
+			"Transport on the underlaying implementation",
+			"Transport of decorated protocol",
+			G_PARAM_READABLE);
+
+
+
+  g_object_class_install_properties (object_class,
+				     PROP_THRIFT_STORED_MESSAGE_PROTOCOL_END,
+				     thrift_stored_message_protocol_obj_properties);
+}
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.h b/lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.h
new file mode 100644
index 0000000..88782ac
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_stored_message_protocol.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_STORED_MESSAGE_PROTOCOL_H
+#define _THRIFT_STORED_MESSAGE_PROTOCOL_H
+
+#include <glib-object.h>
+
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/protocol/thrift_protocol_decorator.h>
+#include <thrift/c_glib/transport/thrift_transport.h>
+
+G_BEGIN_DECLS
+
+/*! \file thrift_stored_message_protocol.h
+ *  \brief StoredMessage protocol implementation of a pre-stored message header
+ *  on Thrift protocol.  Implements the ThriftProtocol interface.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_STORED_MESSAGE_PROTOCOL (thrift_stored_message_protocol_get_type ())
+#define THRIFT_STORED_MESSAGE_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_STORED_MESSAGE_PROTOCOL, ThriftStoredMessageProtocol))
+#define THRIFT_IS_STORED_MESSAGE_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_STORED_MESSAGE_PROTOCOL))
+#define THRIFT_STORED_MESSAGE_PROTOCOL_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_STORED_MESSAGE_PROTOCOL, ThriftStoredMessageProtocolClass))
+#define THRIFT_IS_STORED_MESSAGE_PROTOCOL_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_STORED_MESSAGE_PROTOCOL))
+#define THRIFT_STORED_MESSAGE_PROTOCOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_STORED_MESSAGE_PROTOCOL, ThriftStoredMessageProtocolClass))
+
+/* constant */
+#define THRIFT_STORED_MESSAGE_PROTOCOL_DEFAULT_SEPARATOR ":"
+
+typedef struct _ThriftStoredMessageProtocol ThriftStoredMessageProtocol;
+
+
+
+/*!
+ * Thrift StoredMessage Protocol instance.
+ */
+struct _ThriftStoredMessageProtocol
+{
+  ThriftProtocolDecorator parent;
+
+  gchar *name;
+  ThriftMessageType mtype;
+  gint32 seqid;
+};
+
+typedef struct _ThriftStoredMessageProtocolClass ThriftStoredMessageProtocolClass;
+
+/*!
+ * Thrift StoredMessage Protocol class.
+ */
+struct _ThriftStoredMessageProtocolClass
+{
+  ThriftProtocolDecoratorClass parent;
+};
+
+/* used by THRIFT_TYPE_STORED_MESSAGE_PROTOCOL */
+GType thrift_stored_message_protocol_get_type (void);
+
+G_END_DECLS
+
+#endif /* _THRIFT_STORED_MESSAGE_PROTOCOL_H */
diff --git a/lib/c_glib/src/thrift/c_glib/server/thrift_server.c b/lib/c_glib/src/thrift/c_glib/server/thrift_server.c
index 0171cee..ccf9153 100644
--- a/lib/c_glib/src/thrift/c_glib/server/thrift_server.c
+++ b/lib/c_glib/src/thrift/c_glib/server/thrift_server.c
@@ -76,30 +76,30 @@
   switch (property_id)
   {
     case PROP_THRIFT_SERVER_PROCESSOR:
-      server->processor = g_value_get_object (value);
+      server->processor = g_value_dup_object (value);
       break;
     case PROP_THRIFT_SERVER_SERVER_TRANSPORT:
-      server->server_transport = g_value_get_object (value);
+      server->server_transport = g_value_dup_object (value);
       break;
     case PROP_THRIFT_SERVER_INPUT_TRANSPORT_FACTORY:
-      server->input_transport_factory = g_value_get_object (value);
+      server->input_transport_factory = g_value_dup_object (value);
       break;
     case PROP_THRIFT_SERVER_OUTPUT_TRANSPORT_FACTORY:
-      server->output_transport_factory = g_value_get_object (value);
+      server->output_transport_factory = g_value_dup_object (value);
       break;
     case PROP_THRIFT_SERVER_INPUT_PROTOCOL_FACTORY:
-      server->input_protocol_factory = g_value_get_object (value);
+      server->input_protocol_factory = g_value_dup_object (value);
       break;
     case PROP_THRIFT_SERVER_OUTPUT_PROTOCOL_FACTORY:
-      server->output_protocol_factory = g_value_get_object (value);
+      server->output_protocol_factory = g_value_dup_object (value);
       break;
   }
 }
 
-void
-thrift_server_serve (ThriftServer *server)
+gboolean
+thrift_server_serve (ThriftServer *server, GError **error)
 {
-  THRIFT_SERVER_GET_CLASS (server)->serve (server);
+  return THRIFT_SERVER_GET_CLASS (server)->serve (server, error);
 }
 
 void
@@ -120,7 +120,27 @@
   server->output_protocol_factory = NULL;
 }
 
-/* class initializer for ThriftServer
+static void
+thrift_server_dispose (GObject *gobject)
+{
+  ThriftServer *self = THRIFT_SERVER (gobject);
+
+  g_clear_object(&self->output_protocol_factory);
+  g_clear_object(&self->input_protocol_factory);
+  g_clear_object(&self->output_transport_factory);
+  g_clear_object(&self->input_transport_factory);
+  g_clear_object(&self->server_transport);
+  g_clear_object(&self->processor);
+
+  /* Always chain up to the parent class; there is no need to check if
+   * the parent class implements the dispose() virtual function: it is
+   * always guaranteed to do so
+   */
+  G_OBJECT_CLASS (thrift_server_parent_class)->dispose(gobject);
+}
+
+/*
+ * class initializer for ThriftServer
  * TODO: implement ServerEventHandler as a GClosure
  */
 static void
@@ -130,6 +150,7 @@
 
   gobject_class->get_property = thrift_server_get_property;
   gobject_class->set_property = thrift_server_set_property;
+  gobject_class->dispose = thrift_server_dispose;
 
   g_object_class_install_property (gobject_class,
       PROP_THRIFT_SERVER_PROCESSOR,
diff --git a/lib/c_glib/src/thrift/c_glib/server/thrift_server.h b/lib/c_glib/src/thrift/c_glib/server/thrift_server.h
index 2744f97..49beddc 100644
--- a/lib/c_glib/src/thrift/c_glib/server/thrift_server.h
+++ b/lib/c_glib/src/thrift/c_glib/server/thrift_server.h
@@ -69,7 +69,7 @@
   GObjectClass parent;
 
   /* vtable */
-  void (*serve) (ThriftServer *server);
+  gboolean (*serve) (ThriftServer *server, GError **error);
   void (*stop) (ThriftServer *server);
 };
 
@@ -80,7 +80,7 @@
  * Processes the request.
  * \public \memberof ThriftServerClass
  */
-void thrift_server_serve (ThriftServer *server);
+gboolean thrift_server_serve (ThriftServer *server, GError **error);
 
 /*!
  * Stop handling requests.
diff --git a/lib/c_glib/src/thrift/c_glib/server/thrift_simple_server.c b/lib/c_glib/src/thrift/c_glib/server/thrift_simple_server.c
index 7a39bc2..22a96c7 100644
--- a/lib/c_glib/src/thrift/c_glib/server/thrift_simple_server.c
+++ b/lib/c_glib/src/thrift/c_glib/server/thrift_simple_server.c
@@ -24,51 +24,71 @@
 
 G_DEFINE_TYPE(ThriftSimpleServer, thrift_simple_server, THRIFT_TYPE_SERVER)
 
-void
-thrift_simple_server_serve (ThriftServer *server)
+gboolean
+thrift_simple_server_serve (ThriftServer *server, GError **error)
 {
-  g_return_if_fail (THRIFT_IS_SIMPLE_SERVER (server));
-
   ThriftTransport *t = NULL;
   ThriftTransport *input_transport = NULL, *output_transport = NULL;
   ThriftProtocol *input_protocol = NULL, *output_protocol = NULL;
   ThriftSimpleServer *tss = THRIFT_SIMPLE_SERVER(server);
+  GError *process_error = NULL;
 
-  THRIFT_SERVER_TRANSPORT_GET_CLASS (server->server_transport)
-      ->listen (server->server_transport, NULL);
+  g_return_val_if_fail (THRIFT_IS_SIMPLE_SERVER (server), FALSE);
 
-  tss->running = TRUE;
-  while (tss->running == TRUE)
-  {
-    t = thrift_server_transport_accept (server->server_transport, NULL);
-    input_transport =
-        THRIFT_TRANSPORT_FACTORY_GET_CLASS (server->input_transport_factory)
-            ->get_transport (server->input_transport_factory, t);
-    output_transport = 
-        THRIFT_TRANSPORT_FACTORY_GET_CLASS (server->output_transport_factory)
-            ->get_transport (server->output_transport_factory, t);
-    input_protocol =
-        THRIFT_PROTOCOL_FACTORY_GET_CLASS (server->input_protocol_factory)
-            ->get_protocol (server->input_protocol_factory, t);
-    output_protocol =
-        THRIFT_PROTOCOL_FACTORY_GET_CLASS (server->output_protocol_factory)
-            ->get_protocol (server->output_protocol_factory, t);
-
-    while (THRIFT_PROCESSOR_GET_CLASS (server->processor)
-               ->process (server->processor, input_protocol, output_protocol))
+  if (thrift_server_transport_listen (server->server_transport, error)) {
+    tss->running = TRUE;
+    while (tss->running == TRUE)
     {
-      // TODO: implement transport peek ()
+      t = thrift_server_transport_accept (server->server_transport,
+                                          error);
+      if (t != NULL && tss->running) {
+        input_transport =
+          THRIFT_TRANSPORT_FACTORY_GET_CLASS (server->input_transport_factory)
+          ->get_transport (server->input_transport_factory, t);
+        output_transport =
+          THRIFT_TRANSPORT_FACTORY_GET_CLASS (server->output_transport_factory)
+          ->get_transport (server->output_transport_factory, t);
+        input_protocol =
+          THRIFT_PROTOCOL_FACTORY_GET_CLASS (server->input_protocol_factory)
+          ->get_protocol (server->input_protocol_factory, input_transport);
+        output_protocol =
+          THRIFT_PROTOCOL_FACTORY_GET_CLASS (server->output_protocol_factory)
+          ->get_protocol (server->output_protocol_factory, output_transport);
+
+        while (THRIFT_PROCESSOR_GET_CLASS (server->processor)
+               ->process (server->processor,
+                          input_protocol,
+                          output_protocol,
+                          &process_error) &&
+               thrift_transport_peek (input_transport, &process_error))
+        {
+        }
+
+        if (process_error != NULL)
+        {
+          g_message ("thrift_simple_server_serve: %s", process_error->message);
+          g_clear_error (&process_error);
+
+          /* Note we do not propagate processing errors to the caller as they
+           * normally are transient and not fatal to the server */
+        }
+
+        /* TODO: handle exceptions */
+        THRIFT_TRANSPORT_GET_CLASS (input_transport)->close (input_transport,
+                                                             NULL);
+        THRIFT_TRANSPORT_GET_CLASS (output_transport)->close (output_transport,
+                                                              NULL);
+      }
     }
 
-    // TODO: handle exceptions
-    THRIFT_TRANSPORT_GET_CLASS (input_transport)->close (input_transport, NULL);
-    THRIFT_TRANSPORT_GET_CLASS (output_transport)->close (output_transport,
-                                                          NULL);
-  } 
+    /* attempt to shutdown */
+    THRIFT_SERVER_TRANSPORT_GET_CLASS (server->server_transport)
+      ->close (server->server_transport, NULL);
+  }
 
-  // attempt to shutdown
-  THRIFT_SERVER_TRANSPORT_GET_CLASS (server->server_transport)
-      ->close (server->server_transport, NULL); 
+  /* Since this method is designed to run forever, it can only ever return on
+   * error */
+  return FALSE;
 }
 
 void
@@ -81,10 +101,10 @@
 static void
 thrift_simple_server_init (ThriftSimpleServer *tss)
 {
-  tss->running = FALSE;
-
   ThriftServer *server = THRIFT_SERVER(tss);
 
+  tss->running = FALSE;
+
   if (server->input_transport_factory == NULL)
   {
     server->input_transport_factory =
diff --git a/lib/c_glib/src/thrift/c_glib/thrift.c b/lib/c_glib/src/thrift/c_glib/thrift.c
index 0051df0..8de869f 100644
--- a/lib/c_glib/src/thrift/c_glib/thrift.c
+++ b/lib/c_glib/src/thrift/c_glib/thrift.c
@@ -25,8 +25,77 @@
 void
 thrift_hash_table_get_keys (gpointer key, gpointer value, gpointer user_data)
 {
-  THRIFT_UNUSED_VAR (value);
   GList **list = (GList **) user_data;
+
+  THRIFT_UNUSED_VAR (value);
+
   *list = g_list_append (*list, key);
 }
+void thrift_safe_hash_table_destroy(GHashTable* hash_table)
+{
+  if (hash_table)
+  {
+    g_hash_table_destroy(hash_table);
+  }
+}
 
+guint thrift_boolean_hash(gconstpointer v)
+{
+  const gboolean* p = v;
+  return p && *p ? 1 : 0;
+}
+gboolean thrift_boolean_equal(gconstpointer a, gconstpointer b)
+{
+  if (a == b) {
+    return TRUE;
+  }
+  if (!a || !b) {
+    return FALSE;
+  }
+  const gboolean* pa = a;
+  const gboolean* pb = b;
+  return *pa == *pb;
+}
+
+guint thrift_int8_hash(gconstpointer v)
+{
+  const gint8* p = v;
+  return p ? *p : 0;
+}
+gboolean thrift_int8_equal(gconstpointer a, gconstpointer b)
+{
+  if (a == b) {
+    return TRUE;
+  }
+  if (!a || !b) {
+    return FALSE;
+  }
+  const gint8* pa = a;
+  const gint8* pb = b;
+  return *pa == *pb;
+}
+
+guint thrift_int16_hash(gconstpointer v)
+{
+  const gint16* p = v;
+  return p ? *p : 0;
+}
+gboolean thrift_int16_equal(gconstpointer a, gconstpointer b)
+{
+  if (a == b) {
+    return TRUE;
+  }
+  if (!a || !b) {
+    return FALSE;
+  }
+  const gint16* pa = a;
+  const gint16* pb = b;
+  return *pa == *pb;
+}
+
+void
+thrift_string_free (gpointer str)
+{
+	GByteArray* ptr = str;
+	g_byte_array_unref(ptr);
+}
diff --git a/lib/c_glib/src/thrift/c_glib/thrift.h b/lib/c_glib/src/thrift/c_glib/thrift.h
index 0636a2f..94a6478 100644
--- a/lib/c_glib/src/thrift/c_glib/thrift.h
+++ b/lib/c_glib/src/thrift/c_glib/thrift.h
@@ -33,5 +33,17 @@
 
 void thrift_hash_table_get_keys (gpointer key, gpointer value,
                                  gpointer user_data);
+void thrift_safe_hash_table_destroy(GHashTable* hash_table);
 
-#endif // #ifndef _THRIFT_THRIFT_H
+guint thrift_boolean_hash(gconstpointer v);
+gboolean thrift_boolean_equal(gconstpointer a, gconstpointer b);
+
+guint thrift_int8_hash(gconstpointer v);
+gboolean thrift_int8_equal(gconstpointer a, gconstpointer b);
+
+guint thrift_int16_hash(gconstpointer v);
+gboolean thrift_int16_equal(gconstpointer a, gconstpointer b);
+
+void thrift_string_free (gpointer str);
+
+#endif /* #ifndef _THRIFT_THRIFT_H */
diff --git a/lib/c_glib/src/thrift/c_glib/thrift_application_exception.c b/lib/c_glib/src/thrift/c_glib/thrift_application_exception.c
index 2b8b395..1234cae 100644
--- a/lib/c_glib/src/thrift/c_glib/thrift_application_exception.c
+++ b/lib/c_glib/src/thrift/c_glib/thrift_application_exception.c
@@ -20,6 +20,14 @@
 #include "thrift_application_exception.h"
 #include <thrift/c_glib/protocol/thrift_protocol.h>
 
+/* object properties */
+enum _ThriftApplicationExceptionProperties
+{
+  PROP_0,
+  PROP_THRIFT_APPLICATION_EXCEPTION_TYPE,
+  PROP_THRIFT_APPLICATION_EXCEPTION_MESSAGE
+};
+
 G_DEFINE_TYPE(ThriftApplicationException, thrift_application_exception, THRIFT_TYPE_STRUCT)
 
 gint32
@@ -161,6 +169,55 @@
   return g_quark_from_static_string (THRIFT_APPLICATION_EXCEPTION_ERROR_DOMAIN);
 }
 
+static void
+thrift_application_exception_get_property (GObject *object,
+                                           guint property_id,
+                                           GValue *value,
+                                           GParamSpec *pspec)
+{
+  ThriftApplicationException *tae = THRIFT_APPLICATION_EXCEPTION (object);
+
+  switch (property_id)
+  {
+    case PROP_THRIFT_APPLICATION_EXCEPTION_TYPE:
+      g_value_set_int (value, tae->type);
+      break;
+    case PROP_THRIFT_APPLICATION_EXCEPTION_MESSAGE:
+      g_value_set_string (value, tae->message);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static void
+thrift_application_exception_set_property (GObject *object,
+                                           guint property_id,
+                                           const GValue *value,
+                                           GParamSpec *pspec)
+{
+  ThriftApplicationException *tae = THRIFT_APPLICATION_EXCEPTION (object);
+
+  switch (property_id)
+  {
+    case PROP_THRIFT_APPLICATION_EXCEPTION_TYPE:
+      tae->type = g_value_get_int (value);
+      tae->__isset_type = TRUE;
+      break;
+    case PROP_THRIFT_APPLICATION_EXCEPTION_MESSAGE:
+      if (tae->message != NULL)
+        g_free (tae->message);
+
+      tae->message = g_value_dup_string (value);
+      tae->__isset_message = TRUE;
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
 void
 thrift_application_exception_init (ThriftApplicationException *object)
 {
@@ -171,9 +228,50 @@
 }
 
 void
+thrift_application_exception_finalize (GObject *object)
+{
+  ThriftApplicationException *tae = THRIFT_APPLICATION_EXCEPTION (object);
+
+  if (tae->__isset_message) {
+		g_free(tae->message);
+  }
+}
+
+void
 thrift_application_exception_class_init (ThriftApplicationExceptionClass *class)
 {
+  GObjectClass *gobject_class = G_OBJECT_CLASS(class);
   ThriftStructClass *cls = THRIFT_STRUCT_CLASS(class);
+  GParamSpec *param_spec;
+
   cls->read = thrift_application_exception_read;
   cls->write = thrift_application_exception_write;
+
+  gobject_class->finalize = thrift_application_exception_finalize;
+  gobject_class->get_property = thrift_application_exception_get_property;
+  gobject_class->set_property = thrift_application_exception_set_property;
+
+  param_spec = g_param_spec_int ("type",
+                                 "Exception type",
+                                 "The type of the exception, one of the "
+                                 "values defined by the "
+                                 "ThriftApplicationExceptionError "
+                                 "enumeration.",
+                                 0,
+                                 THRIFT_APPLICATION_EXCEPTION_ERROR_N - 1,
+                                 0,
+                                 G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_THRIFT_APPLICATION_EXCEPTION_TYPE,
+                                   param_spec);
+
+  param_spec = g_param_spec_string ("message",
+                                    "Exception message",
+                                    "A string describing the exception that "
+                                    "occurred.",
+                                    NULL,
+                                    G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_THRIFT_APPLICATION_EXCEPTION_MESSAGE,
+                                   param_spec);
 }
diff --git a/lib/c_glib/src/thrift/c_glib/thrift_application_exception.h b/lib/c_glib/src/thrift/c_glib/thrift_application_exception.h
index ba3e97b..733f793 100644
--- a/lib/c_glib/src/thrift/c_glib/thrift_application_exception.h
+++ b/lib/c_glib/src/thrift/c_glib/thrift_application_exception.h
@@ -43,7 +43,7 @@
 {
   ThriftStruct parent;
 
-  /* public */
+  /* private */
   gint32 type;
   gboolean __isset_type;
   gchar *message;
@@ -72,7 +72,9 @@
   THRIFT_APPLICATION_EXCEPTION_ERROR_PROTOCOL_ERROR,
   THRIFT_APPLICATION_EXCEPTION_ERROR_INVALID_TRANSFORM,
   THRIFT_APPLICATION_EXCEPTION_ERROR_INVALID_PROTOCOL,
-  THRIFT_APPLICATION_EXCEPTION_ERROR_UNSUPPORTED_CLIENT_TYPE
+  THRIFT_APPLICATION_EXCEPTION_ERROR_UNSUPPORTED_CLIENT_TYPE,
+
+  THRIFT_APPLICATION_EXCEPTION_ERROR_N
 } ThriftApplicationExceptionError;
 
 /* define error domain for GError */
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport.c
index a32e5ad..0ab3e93 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport.c
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport.c
@@ -17,7 +17,6 @@
  * under the License.
  */
 
-#include <assert.h>
 #include <netdb.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -47,6 +46,14 @@
   return THRIFT_TRANSPORT_GET_CLASS (t->transport)->is_open (t->transport);
 }
 
+/* overrides thrift_transport_peek */
+gboolean
+thrift_buffered_transport_peek (ThriftTransport *transport, GError **error)
+{
+  ThriftBufferedTransport *t = THRIFT_BUFFERED_TRANSPORT (transport);
+  return (t->r_buf->len > 0) || thrift_transport_peek (t->transport, error);
+}
+
 /* implements thrift_transport_open */
 gboolean
 thrift_buffered_transport_open (ThriftTransport *transport, GError **error)
@@ -69,15 +76,16 @@
                                      guint32 len, GError **error)
 {
   ThriftBufferedTransport *t = THRIFT_BUFFERED_TRANSPORT (transport);
+  gint ret = 0;
   guint32 want = len;
   guint32 got = 0;
-  guchar tmpdata[len];
+  guchar *tmpdata = g_alloca (len);
   guint32 have = t->r_buf->len;
 
-  // we shouldn't hit this unless the buffer doesn't have enough to read
-  assert (t->r_buf->len < want);
+  /* we shouldn't hit this unless the buffer doesn't have enough to read */
+  g_assert (t->r_buf->len < want);
 
-  // first copy what we have in our buffer.
+  /* first copy what we have in our buffer. */
   if (have > 0)
   {
     memcpy (buf, t->r_buf, t->r_buf->len);
@@ -85,31 +93,39 @@
     t->r_buf = g_byte_array_remove_range (t->r_buf, 0, t->r_buf->len);
   }
 
-  // if the buffer is still smaller than what we want to read, then just
-  // read it directly.  otherwise, fill the buffer and then give out
-  // enough to satisfy the read.
+  /* if the buffer is still smaller than what we want to read, then just
+   * read it directly.  otherwise, fill the buffer and then give out
+   * enough to satisfy the read. */
   if (t->r_buf_size < want)
   {
-    got += THRIFT_TRANSPORT_GET_CLASS (t->transport)->read (t->transport,
-                                                            tmpdata,
-                                                            want,
-                                                            error);
+    if ((ret = THRIFT_TRANSPORT_GET_CLASS (t->transport)->read (t->transport,
+                                                                tmpdata,
+                                                                want,
+                                                                error)) < 0) {
+      return ret;
+    }
+    got += ret;
 
-    // copy the data starting from where we left off
-    memcpy (buf + have, tmpdata, got);
+    /* copy the data starting from where we left off */
+    memcpy ((guint8 *)buf + have, tmpdata, got);
     return got + have; 
   } else {
-    got += THRIFT_TRANSPORT_GET_CLASS (t->transport)->read (t->transport,
-                                                            tmpdata,
-                                                            want,
-                                                            error);
+    guint32 give;
+
+    if ((ret = THRIFT_TRANSPORT_GET_CLASS (t->transport)->read (t->transport,
+                                                                tmpdata,
+                                                                want,
+                                                                error)) < 0) {
+      return ret;
+    }
+    got += ret;
     t->r_buf = g_byte_array_append (t->r_buf, tmpdata, got);
     
-    // hand over what we have up to what the caller wants
-    guint32 give = want < t->r_buf->len ? want : t->r_buf->len;
+    /* hand over what we have up to what the caller wants */
+    give = want < t->r_buf->len ? want : t->r_buf->len;
 
 
-    memcpy (buf + len - want, t->r_buf->data, give);
+    memcpy ((guint8 *)buf + len - want, t->r_buf->data, give);
     t->r_buf = g_byte_array_remove_range (t->r_buf, 0, give);
     want -= give;
 
@@ -155,35 +171,37 @@
   guint32 have_bytes = t->w_buf->len;
   guint32 space = t->w_buf_size - t->w_buf->len;
 
-  // we need two syscalls because the buffered data plus the buffer itself
-  // is too big.
-  if ((have_bytes + len >= 2*t->w_buf->len) || (have_bytes == 0))
+  /* we need two syscalls because the buffered data plus the buffer itself
+   * is too big. */
+  if ((have_bytes + len >= 2*t->w_buf_size) || (have_bytes == 0))
   {
     if (have_bytes > 0)
     {
-      THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
-                                                        t->w_buf->data,
-                                                        have_bytes,
-                                                        error);
+      if (!THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
+                                                             t->w_buf->data,
+                                                             have_bytes,
+                                                             error)) {
+        return FALSE;
+      }
+      t->w_buf = g_byte_array_remove_range (t->w_buf, 0, have_bytes);
     }
-    THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
-                                                      buf, len, error);
-    if (t->w_buf->len > 0)
-    {
-      t->w_buf = g_byte_array_remove_range (t->w_buf, 0, t->w_buf->len);
+    if (!THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
+                                                           buf, len, error)) {
+      return FALSE;
     }
-
     return TRUE;
   }
 
   t->w_buf = g_byte_array_append (t->w_buf, buf, space);
-  THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
-                                                    t->w_buf->data,
-                                                    t->w_buf->len,
-                                                    error);
+  if (!THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
+                                                         t->w_buf->data,
+                                                         t->w_buf->len,
+                                                         error)) {
+    return FALSE;
+  }
 
   t->w_buf = g_byte_array_remove_range (t->w_buf, 0, t->w_buf->len);
-  t->w_buf = g_byte_array_append (t->w_buf, buf+space, len-space);
+  t->w_buf = g_byte_array_append (t->w_buf, (guint8 *)buf + space, len-space);
 
   return TRUE;
 }
@@ -225,11 +243,13 @@
 
   if (t->w_buf != NULL && t->w_buf->len > 0)
   {
-    // write the buffer and then empty it
-    THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
-                                                      t->w_buf->data,
-                                                      t->w_buf->len,
-                                                      error);
+    /* write the buffer and then empty it */
+    if (!THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
+                                                           t->w_buf->data,
+                                                           t->w_buf->len,
+                                                           error)) {
+      return FALSE;
+    }
     t->w_buf = g_byte_array_remove_range (t->w_buf, 0, t->w_buf->len);
   }
   THRIFT_TRANSPORT_GET_CLASS (t->transport)->flush (t->transport,
@@ -271,9 +291,10 @@
 thrift_buffered_transport_get_property (GObject *object, guint property_id,
                                         GValue *value, GParamSpec *pspec)
 {
-  THRIFT_UNUSED_VAR (pspec);
   ThriftBufferedTransport *transport = THRIFT_BUFFERED_TRANSPORT (object);
 
+  THRIFT_UNUSED_VAR (pspec);
+
   switch (property_id)
   {
     case PROP_THRIFT_BUFFERED_TRANSPORT_TRANSPORT:
@@ -293,9 +314,10 @@
 thrift_buffered_transport_set_property (GObject *object, guint property_id,
                                         const GValue *value, GParamSpec *pspec)
 {
-  THRIFT_UNUSED_VAR (pspec);
   ThriftBufferedTransport *transport = THRIFT_BUFFERED_TRANSPORT (object);
 
+  THRIFT_UNUSED_VAR (pspec);
+
   switch (property_id)
   {
     case PROP_THRIFT_BUFFERED_TRANSPORT_TRANSPORT:
@@ -314,6 +336,7 @@
 static void
 thrift_buffered_transport_class_init (ThriftBufferedTransportClass *cls)
 {
+  ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
   GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
   GParamSpec *param_spec = NULL;
 
@@ -354,10 +377,9 @@
                                    param_spec);
 
 
-  ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
-
   gobject_class->finalize = thrift_buffered_transport_finalize;
   ttc->is_open = thrift_buffered_transport_is_open;
+  ttc->peek = thrift_buffered_transport_peek;
   ttc->open = thrift_buffered_transport_open;
   ttc->close = thrift_buffered_transport_close;
   ttc->read = thrift_buffered_transport_read;
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.c
new file mode 100644
index 0000000..86050b6
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.c
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport_factory.h>
+
+G_DEFINE_TYPE (ThriftBufferedTransportFactory,
+               thrift_buffered_transport_factory,
+               THRIFT_TYPE_TRANSPORT_FACTORY)
+
+/* Wraps a transport with a ThriftBufferedTransport. */
+ThriftTransport *
+thrift_buffered_transport_factory_get_transport (ThriftTransportFactory *factory,
+                                                 ThriftTransport *transport)
+{
+  THRIFT_UNUSED_VAR (factory);
+
+  return THRIFT_TRANSPORT (g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+                                         "transport", transport,
+                                         NULL));
+}
+
+static void
+thrift_buffered_transport_factory_init (ThriftBufferedTransportFactory *self)
+{
+  THRIFT_UNUSED_VAR (self);
+}
+
+static void
+thrift_buffered_transport_factory_class_init (ThriftBufferedTransportFactoryClass *klass)
+{
+  ThriftTransportFactoryClass *base_class =
+    THRIFT_TRANSPORT_FACTORY_CLASS (klass);
+
+  base_class->get_transport =
+    klass->get_transport =
+    thrift_buffered_transport_factory_get_transport;
+}
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.h
new file mode 100644
index 0000000..d43f4e4
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_BUFFERED_TRANSPORT_FACTORY_H
+#define _THRIFT_BUFFERED_TRANSPORT_FACTORY_H
+
+#include <glib-object.h>
+
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_transport_factory.h>
+
+G_BEGIN_DECLS
+
+/*! \file thrift_buffered_transport_factory.h
+ *  \brief Wraps a transport with a ThriftBufferedTransport.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY          \
+  (thrift_buffered_transport_factory_get_type ())
+#define THRIFT_BUFFERED_TRANSPORT_FACTORY(obj)                          \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                                   \
+                               THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY,  \
+                               ThriftBufferedTransportFactory))
+#define THRIFT_IS_BUFFERED_TRANSPORT_FACTORY(obj)                       \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                                   \
+                               THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY))
+#define THRIFT_BUFFERED_TRANSPORT_FACTORY_CLASS(c)                      \
+  (G_TYPE_CHECK_CLASS_CAST ((c),                                        \
+                            THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY,     \
+                            ThriftBufferedTransportFactoryClass))
+#define THRIFT_IS_BUFFERED_TRANSPORT_FACTORY_CLASS(c)                   \
+  (G_TYPE_CHECK_CLASS_TYPE ((c),                                        \
+                            THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY))
+#define THRIFT_BUFFERED_TRANSPORT_FACTORY_GET_CLASS(obj)                \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                                    \
+                              THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY,   \
+                              ThriftBufferedTransportFactoryClass))
+
+typedef struct _ThriftBufferedTransportFactory ThriftBufferedTransportFactory;
+
+/* Thrift Buffered-Transport Factory instance */
+struct _ThriftBufferedTransportFactory
+{
+  ThriftTransportFactory parent;
+};
+
+typedef struct _ThriftBufferedTransportFactoryClass ThriftBufferedTransportFactoryClass;
+
+/* Thrift Buffered-Transport Factory class */
+struct _ThriftBufferedTransportFactoryClass
+{
+  ThriftTransportFactoryClass parent;
+
+  /* vtable */
+  ThriftTransport *(*get_transport) (ThriftTransportFactory *factory,
+                                     ThriftTransport *transport);
+};
+
+/* used by THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY */
+GType thrift_buffered_transport_factory_get_type (void);
+
+/* virtual public methods */
+ThriftTransport *
+thrift_buffered_transport_factory_get_transport (ThriftTransportFactory *factory,
+                                                 ThriftTransport *transport);
+
+G_END_DECLS
+
+#endif /* _THRIFT_BUFFERED_TRANSPORT_FACTORY_H */
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_fd_transport.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_fd_transport.c
new file mode 100644
index 0000000..14abff7
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_fd_transport.c
@@ -0,0 +1,265 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_fd_transport.h>
+
+/* object properties */
+enum _ThriftFDTransportProperties
+{
+  PROP_0,
+  PROP_THRIFT_FD_TRANSPORT_FD
+};
+
+G_DEFINE_TYPE (ThriftFDTransport, thrift_fd_transport, THRIFT_TYPE_TRANSPORT)
+
+/* implements thrift_transport_is_open */
+gboolean
+thrift_fd_transport_is_open (ThriftTransport *transport)
+{
+  ThriftFDTransport *t;
+  t = THRIFT_FD_TRANSPORT (transport);
+  return t->fd >= 0 && ! (fcntl (t->fd, F_GETFL) == -1 && errno == EBADF);
+}
+
+/* implements thrift_transport_open */
+gboolean
+thrift_fd_transport_open (ThriftTransport *transport, GError **error)
+{
+  THRIFT_UNUSED_VAR (error);
+  return thrift_fd_transport_is_open (transport);
+}
+
+/* implements thrift_transport_close */
+gboolean
+thrift_fd_transport_close (ThriftTransport *transport, GError **error)
+{
+  ThriftFDTransport *t;
+  t = THRIFT_FD_TRANSPORT (transport);
+
+#if GLIB_CHECK_VERSION (2, 36, 0)
+  return g_close (t->fd, error);
+#else
+  if (close (t->fd) == 0) {
+    g_clear_error (error);
+    return TRUE;
+  } else {
+    g_set_error (error,
+                 THRIFT_TRANSPORT_ERROR,
+                 THRIFT_TRANSPORT_ERROR_CLOSE,
+                 strerror (errno));
+    return FALSE;
+  }
+#endif
+}
+
+/* implements thrift_transport_read */
+gint32
+thrift_fd_transport_read (ThriftTransport *transport, gpointer buf,
+                          guint32 len, GError **error)
+{
+  ThriftFDTransport *t;
+  ssize_t n;
+
+  t = THRIFT_FD_TRANSPORT (transport);
+  n = read (t->fd, (guint8 *) buf, len);
+  if (n == -1) {
+    g_set_error (error,
+                 THRIFT_TRANSPORT_ERROR,
+                 THRIFT_TRANSPORT_ERROR_RECEIVE,
+                 "Failed to read from fd: %s",
+                 strerror (errno));
+    return -1;
+  }
+  return n;
+}
+
+/* implements thrift_transport_read_end
+ * called when write is complete.  nothing to do on our end. */
+gboolean
+thrift_fd_transport_read_end (ThriftTransport *transport, GError **error)
+{
+  /* satisfy -Wall */
+  THRIFT_UNUSED_VAR (transport);
+  THRIFT_UNUSED_VAR (error);
+  return TRUE;
+}
+
+/* implements thrift_transport_write */
+gboolean
+thrift_fd_transport_write (ThriftTransport *transport,
+                           const gpointer buf,
+                           const guint32 len, GError **error)
+{
+  ThriftFDTransport *t;
+  guint8 *_buf;
+  guint32 _len;
+  ssize_t n;
+
+  t = THRIFT_FD_TRANSPORT (transport);
+  _buf = (guint8 *) buf;
+  _len = len;
+  while (_len > 0) {
+    n = write (t->fd, _buf, _len);
+    if (n == -1) {
+      g_set_error (error,
+                   THRIFT_TRANSPORT_ERROR,
+                   THRIFT_TRANSPORT_ERROR_SEND,
+                   "Failed to write from fd: %s",
+                   strerror (errno));
+      return FALSE;
+    } else {
+      _buf += n;
+      _len -= n;
+    }
+  }
+  return TRUE;
+}
+
+/* implements thrift_transport_write_end
+ * called when write is complete.  nothing to do on our end. */
+gboolean
+thrift_fd_transport_write_end (ThriftTransport *transport, GError **error)
+{
+  THRIFT_UNUSED_VAR (transport);
+  THRIFT_UNUSED_VAR (error);
+  return TRUE;
+}
+
+/* implements thrift_transport_flush */
+gboolean
+thrift_fd_transport_flush (ThriftTransport *transport, GError **error)
+{
+  ThriftFDTransport *t;
+  t = THRIFT_FD_TRANSPORT (transport);
+  if (fsync (t->fd) == -1) {
+    g_set_error (error,
+                 THRIFT_TRANSPORT_ERROR,
+                 THRIFT_TRANSPORT_ERROR_UNKNOWN,
+                 "Failed to flush fd: %s",
+                 strerror (errno));
+    return FALSE;
+  } else {
+    return TRUE;
+  }
+}
+
+/* initializes the instance */
+static void
+thrift_fd_transport_init (ThriftFDTransport *transport)
+{
+  transport->fd = -1;
+}
+
+/* destructor */
+static void
+thrift_fd_transport_finalize (GObject *object)
+{
+  THRIFT_UNUSED_VAR (object);
+}
+
+/* property accessor */
+void
+thrift_fd_transport_get_property (GObject *object, guint property_id,
+                                  GValue *value, GParamSpec *pspec)
+{
+  ThriftFDTransport *t;
+
+  THRIFT_UNUSED_VAR (pspec);
+
+  t = THRIFT_FD_TRANSPORT (object);
+
+  switch (property_id) {
+    case PROP_THRIFT_FD_TRANSPORT_FD:
+      g_value_set_int (value, t->fd);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+/* property mutator */
+void
+thrift_fd_transport_set_property (GObject *object, guint property_id,
+                                  const GValue *value, GParamSpec *pspec)
+{
+  ThriftFDTransport *t;
+
+  THRIFT_UNUSED_VAR (pspec);
+
+  t = THRIFT_FD_TRANSPORT (object);
+
+  switch (property_id) {
+    case PROP_THRIFT_FD_TRANSPORT_FD:
+      t->fd = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+/* initializes the class */
+static void
+thrift_fd_transport_class_init (ThriftFDTransportClass *cls)
+{
+  ThriftTransportClass *ttc;
+  GObjectClass *gobject_class;
+  GParamSpec *param_spec;
+
+  ttc = THRIFT_TRANSPORT_CLASS (cls);
+  gobject_class = G_OBJECT_CLASS (cls);
+  param_spec = NULL;
+
+  /* setup accessors and mutators */
+  gobject_class->get_property = thrift_fd_transport_get_property;
+  gobject_class->set_property = thrift_fd_transport_set_property;
+
+  param_spec = g_param_spec_int ("fd",
+                                 "file descriptor (construct)",
+                                 "Set the file descriptor",
+                                 INT_MIN, /* min */
+                                 INT_MAX, /* max, 1024*1024 */
+                                 -1, /* default value */
+                                 G_PARAM_CONSTRUCT_ONLY |
+                                 G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_THRIFT_FD_TRANSPORT_FD,
+                                   param_spec);
+
+  gobject_class->finalize = thrift_fd_transport_finalize;
+  ttc->is_open = thrift_fd_transport_is_open;
+  ttc->open = thrift_fd_transport_open;
+  ttc->close = thrift_fd_transport_close;
+  ttc->read = thrift_fd_transport_read;
+  ttc->read_end = thrift_fd_transport_read_end;
+  ttc->write = thrift_fd_transport_write;
+  ttc->write_end = thrift_fd_transport_write_end;
+  ttc->flush = thrift_fd_transport_flush;
+}
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_fd_transport.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_fd_transport.h
new file mode 100644
index 0000000..0e6d5c4
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_fd_transport.h
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef _THRIFT_FD_TRANSPORT_H
+#define _THRIFT_FD_TRANSPORT_H
+
+#include <glib-object.h>
+
+#include "thrift_transport.h"
+
+G_BEGIN_DECLS
+
+/*! \file thrift_fd_transport.h
+ *  \brief Class for Thrift file descriptor transports.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_FD_TRANSPORT (thrift_fd_transport_get_type ())
+#define THRIFT_FD_TRANSPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_FD_TRANSPORT, \
+                               ThriftFDTransport))
+#define THRIFT_IS_FD_TRANSPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_FD_TRANSPORT))
+#define THRIFT_FD_TRANSPORT_CLASS(c) \
+  (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_FD_TRANSPORT, \
+                            ThriftFDTransportClass))
+#define THRIFT_IS_FD_TRANSPORT_CLASS(c) \
+  (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_FD_TRANSPORT))
+#define THRIFT_FD_TRANSPORT_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_FD_TRANSPORT, \
+                              ThriftFDTransportClass))
+
+typedef struct _ThriftFDTransport ThriftFDTransport;
+
+struct _ThriftFDTransport
+{
+  ThriftTransport parent;
+
+  /* protected */
+  gint fd;
+};
+
+typedef struct _ThriftFDTransportClass ThriftFDTransportClass;
+
+/*!
+ * Thrift Transport class
+ */
+struct _ThriftFDTransportClass
+{
+  ThriftTransportClass parent;
+};
+
+/* used by THRIFT_TYPE_FD_TRANSPORT */
+GType thrift_fd_transport_get_type (void);
+
+G_END_DECLS
+
+#endif /* _THRIFT_FD_TRANSPORT_H */
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport.c
index a58b875..c548246 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport.c
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport.c
@@ -17,7 +17,6 @@
  * under the License.
  */
 
-#include <assert.h>
 #include <netdb.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -49,6 +48,14 @@
   return THRIFT_TRANSPORT_GET_CLASS (t->transport)->is_open (t->transport);
 }
 
+/* overrides thrift_transport_peek */
+gboolean
+thrift_framed_transport_peek (ThriftTransport *transport, GError **error)
+{
+  ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
+  return (t->r_buf->len > 0) || thrift_transport_peek (t->transport, error);
+}
+
 /* implements thrift_transport_open */
 gboolean
 thrift_framed_transport_open (ThriftTransport *transport, GError **error)
@@ -71,25 +78,34 @@
                                     GError **error)
 {
   ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
-  gint32 sz, bytes;
+  guint32 sz;
+  gint32 bytes;
+  gboolean result = FALSE;
 
   /* read the size */
-  THRIFT_TRANSPORT_GET_CLASS (t->transport)->read (t->transport,
-                                                   (guint32 *) &sz,
-                                                   sizeof (sz), error);
-  sz = ntohl (sz);
+  if (thrift_transport_read (t->transport,
+                             &sz,
+                             sizeof (sz),
+                             error) == sizeof (sz))
+  {
+    guchar *tmpdata;
 
-  /* create a buffer to hold the data and read that much data */
-  guchar tmpdata[sz];
-  bytes = THRIFT_TRANSPORT_GET_CLASS (t->transport)->read (t->transport,
-                                                           tmpdata,
-                                                           sz,
-                                                           error);
+    sz = ntohl (sz);
 
-  /* add the data to the buffer */
-  g_byte_array_append (t->r_buf, tmpdata, bytes);
+    /* create a buffer to hold the data and read that much data */
+    tmpdata = g_alloca (sz);
+    bytes = thrift_transport_read (t->transport, tmpdata, sz, error);
 
-  return TRUE;
+    if (bytes > 0 && (error == NULL || *error == NULL))
+    {
+      /* add the data to the buffer */
+      g_byte_array_append (t->r_buf, tmpdata, bytes);
+
+      result = TRUE;
+    }
+  }
+
+  return result;
 }
 
 /* the actual read is "slow" because it calls the underlying transport */
@@ -100,11 +116,12 @@
   ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
   guint32 want = len;
   guint32 have = t->r_buf->len;
+  gint32 result = -1;
 
-  // we shouldn't hit this unless the buffer doesn't have enough to read
-  assert (t->r_buf->len < want);
+  /* we shouldn't hit this unless the buffer doesn't have enough to read */
+  g_assert (t->r_buf->len < want);
 
-  // first copy what we have in our buffer, if there is anything left
+  /* first copy what we have in our buffer, if there is anything left */
   if (have > 0)
   {
     memcpy (buf, t->r_buf, t->r_buf->len);
@@ -112,18 +129,21 @@
     t->r_buf = g_byte_array_remove_range (t->r_buf, 0, t->r_buf->len);
   }
 
-  // read a frame of input and buffer it
-  thrift_framed_transport_read_frame (transport, error);
+  /* read a frame of input and buffer it */
+  if (thrift_framed_transport_read_frame (transport, error) == TRUE)
+  {
+    /* hand over what we have up to what the caller wants */
+    guint32 give = want < t->r_buf->len ? want : t->r_buf->len;
 
-  // hand over what we have up to what the caller wants
-  guint32 give = want < t->r_buf->len ? want : t->r_buf->len;
+    /* copy the data into the buffer */
+    memcpy ((guint8 *)buf + len - want, t->r_buf->data, give);
+    t->r_buf = g_byte_array_remove_range (t->r_buf, 0, give);
+    want -= give;
 
-  // copy the data into the buffer
-  memcpy (buf + len - want, t->r_buf->data, give);
-  t->r_buf = g_byte_array_remove_range (t->r_buf, 0, give);
-  want -= give;
+    result = len - want;
+  }
 
-  return (len - want);
+  return result;
 }
 
 /* implements thrift_transport_read */
@@ -160,10 +180,11 @@
 thrift_framed_transport_write_slow (ThriftTransport *transport, gpointer buf,
                                     guint32 len, GError **error)
 {
-  THRIFT_UNUSED_VAR (error);
   ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
 
-  // append the data to the buffer and we're done
+  THRIFT_UNUSED_VAR (error);
+
+  /* append the data to the buffer and we're done */
   g_byte_array_append (t->w_buf, buf, len);
 
   return TRUE;
@@ -204,13 +225,14 @@
 {
   ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport);
   gint32 sz_hbo, sz_nbo;
+  guchar *tmpdata;
 
-  // get the size of the frame in host and network byte order
+  /* get the size of the frame in host and network byte order */
   sz_hbo = t->w_buf->len + sizeof(sz_nbo);
   sz_nbo = (gint32) htonl ((guint32) t->w_buf->len);
 
-  // copy the size of the frame and then the frame itself
-  guchar tmpdata[sz_hbo];
+  /* copy the size of the frame and then the frame itself */
+  tmpdata = g_alloca (sz_hbo);
   memcpy (tmpdata, (guint8 *) &sz_nbo, sizeof (sz_nbo));
 
   if (t->w_buf->len > 0)
@@ -219,7 +241,7 @@
     t->w_buf = g_byte_array_remove_range (t->w_buf, 0, t->w_buf->len);
   }
     
-  // write the buffer and then empty it
+  /* write the buffer and then empty it */
   THRIFT_TRANSPORT_GET_CLASS (t->transport)->write (t->transport,
                                                     tmpdata, sz_hbo,
                                                     error);
@@ -263,9 +285,10 @@
 thrift_framed_transport_get_property (GObject *object, guint property_id,
                                       GValue *value, GParamSpec *pspec)
 {
-  THRIFT_UNUSED_VAR (pspec);
   ThriftFramedTransport *transport = THRIFT_FRAMED_TRANSPORT (object);
 
+  THRIFT_UNUSED_VAR (pspec);
+
   switch (property_id)
   {
     case PROP_THRIFT_FRAMED_TRANSPORT_TRANSPORT:
@@ -285,9 +308,10 @@
 thrift_framed_transport_set_property (GObject *object, guint property_id,
                                       const GValue *value, GParamSpec *pspec)
 {
-  THRIFT_UNUSED_VAR (pspec);
   ThriftFramedTransport *transport = THRIFT_FRAMED_TRANSPORT (object);
 
+  THRIFT_UNUSED_VAR (pspec);
+
   switch (property_id)
   {
     case PROP_THRIFT_FRAMED_TRANSPORT_TRANSPORT:
@@ -306,6 +330,7 @@
 static void
 thrift_framed_transport_class_init (ThriftFramedTransportClass *cls)
 {
+  ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
   GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
   GParamSpec *param_spec = NULL;
 
@@ -345,11 +370,9 @@
                                    PROP_THRIFT_FRAMED_TRANSPORT_WRITE_BUFFER_SIZE,
                                    param_spec);
 
-
-  ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
-
   gobject_class->finalize = thrift_framed_transport_finalize;
   ttc->is_open = thrift_framed_transport_is_open;
+  ttc->peek = thrift_framed_transport_peek;
   ttc->open = thrift_framed_transport_open;
   ttc->close = thrift_framed_transport_close;
   ttc->read = thrift_framed_transport_read;
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.c
new file mode 100644
index 0000000..e68fe0a
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.c
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/transport/thrift_framed_transport.h>
+#include <thrift/c_glib/transport/thrift_framed_transport_factory.h>
+
+G_DEFINE_TYPE (ThriftFramedTransportFactory,
+               thrift_framed_transport_factory,
+               THRIFT_TYPE_TRANSPORT_FACTORY)
+
+/* Wraps a transport with a ThriftFramedTransport. */
+ThriftTransport *
+thrift_framed_transport_factory_get_transport (ThriftTransportFactory *factory,
+                                               ThriftTransport *transport)
+{
+  THRIFT_UNUSED_VAR (factory);
+
+  return THRIFT_TRANSPORT (g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
+                                         "transport", transport,
+                                         NULL));
+}
+
+static void
+thrift_framed_transport_factory_init (ThriftFramedTransportFactory *self)
+{
+  THRIFT_UNUSED_VAR (self);
+}
+
+static void
+thrift_framed_transport_factory_class_init (ThriftFramedTransportFactoryClass *klass)
+{
+  ThriftTransportFactoryClass *base_class =
+    THRIFT_TRANSPORT_FACTORY_CLASS (klass);
+
+  base_class->get_transport =
+    klass->get_transport =
+    thrift_framed_transport_factory_get_transport;
+}
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.h
new file mode 100644
index 0000000..c3e9496
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_FRAMED_TRANSPORT_FACTORY_H
+#define _THRIFT_FRAMED_TRANSPORT_FACTORY_H
+
+#include <glib-object.h>
+
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_transport_factory.h>
+
+G_BEGIN_DECLS
+
+/*! \file thrift_framed_transport_factory.h
+ *  \brief Wraps a transport with a ThriftFramedTransport.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY    \
+  (thrift_framed_transport_factory_get_type ())
+#define THRIFT_FRAMED_TRANSPORT_FACTORY(obj)                            \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                                   \
+                               THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY,    \
+                               ThriftFramedTransportFactory))
+#define THRIFT_IS_FRAMED_TRANSPORT_FACTORY(obj)                         \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                                   \
+                               THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY))
+#define THRIFT_FRAMED_TRANSPORT_FACTORY_CLASS(c)                        \
+  (G_TYPE_CHECK_CLASS_CAST ((c),                                        \
+                            THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY,       \
+                            ThriftFramedTransportFactoryClass))
+#define THRIFT_IS_FRAMED_TRANSPORT_FACTORY_CLASS(c)                     \
+  (G_TYPE_CHECK_CLASS_TYPE ((c),                                        \
+                            THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY))
+#define THRIFT_FRAMED_TRANSPORT_FACTORY_GET_CLASS(obj)                  \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                                    \
+                              THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY,     \
+                              ThriftFramedTransportFactoryClass))
+
+typedef struct _ThriftFramedTransportFactory ThriftFramedTransportFactory;
+
+/* Thrift Framed-Transport Factory instance */
+struct _ThriftFramedTransportFactory
+{
+  ThriftTransportFactory parent;
+};
+
+typedef struct _ThriftFramedTransportFactoryClass ThriftFramedTransportFactoryClass;
+
+/* Thrift Framed-Transport Factory class */
+struct _ThriftFramedTransportFactoryClass
+{
+  ThriftTransportFactoryClass parent;
+
+  /* vtable */
+  ThriftTransport *(*get_transport) (ThriftTransportFactory *factory,
+                                     ThriftTransport *transport);
+};
+
+/* used by THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY */
+GType thrift_framed_transport_factory_get_type (void);
+
+/* virtual public methods */
+ThriftTransport *
+thrift_framed_transport_factory_get_transport (ThriftTransportFactory *factory,
+                                               ThriftTransport *transport);
+
+G_END_DECLS
+
+#endif /* _THRIFT_FRAMED_TRANSPORT_FACTORY_H */
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_memory_buffer.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_memory_buffer.c
index aa05e96..91818e9 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_memory_buffer.c
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_memory_buffer.c
@@ -17,7 +17,6 @@
  * under the License.
  */
 
-#include <assert.h>
 #include <netdb.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -33,6 +32,8 @@
 {
   PROP_0,
   PROP_THRIFT_MEMORY_BUFFER_BUFFER_SIZE,
+  PROP_THRIFT_MEMORY_BUFFER_BUFFER,
+  PROP_THRIFT_MEMORY_BUFFER_OWNER
 };
 
 G_DEFINE_TYPE(ThriftMemoryBuffer, thrift_memory_buffer, THRIFT_TYPE_TRANSPORT)
@@ -68,10 +69,11 @@
 thrift_memory_buffer_read (ThriftTransport *transport, gpointer buf,
                            guint32 len, GError **error)
 {
-  THRIFT_UNUSED_VAR (error);
   ThriftMemoryBuffer *t = THRIFT_MEMORY_BUFFER (transport);
   guint32 give = len; 
 
+  THRIFT_UNUSED_VAR (error);
+
   /* if the requested bytes are more than what we have available,
    * just give all that we have the buffer */
   if (t->buf->len < len)
@@ -102,10 +104,10 @@
                             const gpointer buf,     
                             const guint32 len, GError **error)
 {
-  THRIFT_UNUSED_VAR (error);
-
   ThriftMemoryBuffer *t = THRIFT_MEMORY_BUFFER (transport);
 
+  THRIFT_UNUSED_VAR (error);
+
   /* return an exception if the buffer doesn't have enough space. */
   if (len > t->buf_size - t->buf->len)
   {
@@ -140,24 +142,24 @@
   return TRUE;
 }
 
-/* initializes the instance */
+/* initializes class before constructor properties are set */
 static void
-thrift_memory_buffer_init (ThriftMemoryBuffer *transport)
+thrift_memory_buffer_init (ThriftMemoryBuffer *t)
 {
-  transport->buf = g_byte_array_new ();
+  THRIFT_UNUSED_VAR (t);
 }
 
 /* destructor */
 static void
 thrift_memory_buffer_finalize (GObject *object)
 {
-  ThriftMemoryBuffer *transport = THRIFT_MEMORY_BUFFER (object);
+  ThriftMemoryBuffer *t = THRIFT_MEMORY_BUFFER (object);
 
-  if (transport->buf != NULL)
+  if (t->owner && t->buf != NULL)
   {
-    g_byte_array_free (transport->buf, TRUE);
+    g_byte_array_unref (t->buf);
   }
-  transport->buf = NULL;
+  t->buf = NULL;
 }
 
 /* property accessor */
@@ -165,13 +167,23 @@
 thrift_memory_buffer_get_property (GObject *object, guint property_id,
                                    GValue *value, GParamSpec *pspec)
 {
+  ThriftMemoryBuffer *t = THRIFT_MEMORY_BUFFER (object);
+
   THRIFT_UNUSED_VAR (pspec);
-  ThriftMemoryBuffer *transport = THRIFT_MEMORY_BUFFER (object);
 
   switch (property_id)
   {
     case PROP_THRIFT_MEMORY_BUFFER_BUFFER_SIZE:
-      g_value_set_uint (value, transport->buf_size);
+      g_value_set_uint (value, t->buf_size);
+      break;
+    case PROP_THRIFT_MEMORY_BUFFER_BUFFER:
+      g_value_set_pointer (value, (gpointer) (t->buf));
+      break;
+    case PROP_THRIFT_MEMORY_BUFFER_OWNER:
+      g_value_set_boolean (value, t->owner);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
   }
 }
@@ -181,21 +193,45 @@
 thrift_memory_buffer_set_property (GObject *object, guint property_id,
                                    const GValue *value, GParamSpec *pspec)
 {
+  ThriftMemoryBuffer *t = THRIFT_MEMORY_BUFFER (object);
+
   THRIFT_UNUSED_VAR (pspec);
-  ThriftMemoryBuffer *transport = THRIFT_MEMORY_BUFFER (object);
 
   switch (property_id)
   {
     case PROP_THRIFT_MEMORY_BUFFER_BUFFER_SIZE:
-      transport->buf_size = g_value_get_uint (value);
+      t->buf_size = g_value_get_uint (value);
+      break;
+    case PROP_THRIFT_MEMORY_BUFFER_BUFFER:
+      t->buf = (GByteArray*) g_value_get_pointer (value);
+      break;
+    case PROP_THRIFT_MEMORY_BUFFER_OWNER:
+      t->owner = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
   }
 }
 
+/* initializes class after constructor properties are set */
+static void
+thrift_memory_buffer_constructed (GObject *object)
+{
+  ThriftMemoryBuffer *t = THRIFT_MEMORY_BUFFER (object);
+
+  if (t->buf == NULL) {
+    t->buf = g_byte_array_new ();
+  }
+
+  G_OBJECT_CLASS (thrift_memory_buffer_parent_class)->constructed (object);
+}
+
 /* initializes the class */
 static void
 thrift_memory_buffer_class_init (ThriftMemoryBufferClass *cls)
 {
+  ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
   GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
   GParamSpec *param_spec = NULL;
 
@@ -205,18 +241,38 @@
 
   param_spec = g_param_spec_uint ("buf_size",
                                   "buffer size (construct)",
-                                  "Set the read buffer size",
+                                  "Set the read/write buffer size limit",
                                   0, /* min */
-                                  1048576, /* max, 1024*1024 */
-                                  512, /* default value */
+                                  G_MAXUINT32, /* max */
+                                  G_MAXUINT32, /* default */
                                   G_PARAM_CONSTRUCT_ONLY |
                                   G_PARAM_READWRITE);
   g_object_class_install_property (gobject_class,
                                    PROP_THRIFT_MEMORY_BUFFER_BUFFER_SIZE,
                                    param_spec);
 
-  ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
+  param_spec = g_param_spec_pointer ("buf",
+                                     "internal buffer (GByteArray)",
+                                     "Set the internal buffer (GByteArray)",
+                                     G_PARAM_CONSTRUCT_ONLY |
+                                     G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_THRIFT_MEMORY_BUFFER_BUFFER,
+                                   param_spec);
 
+  param_spec = g_param_spec_boolean ("owner",
+                                     "internal buffer memory management policy",
+                                     "Set whether internal buffer should be"
+                                       " unreferenced when thrift_memory_buffer"
+                                       " is finalized",
+                                     TRUE,
+                                     G_PARAM_CONSTRUCT_ONLY |
+                                     G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_THRIFT_MEMORY_BUFFER_OWNER,
+                                   param_spec);
+
+  gobject_class->constructed = thrift_memory_buffer_constructed;
   gobject_class->finalize = thrift_memory_buffer_finalize;
   ttc->is_open = thrift_memory_buffer_is_open;
   ttc->open = thrift_memory_buffer_open;
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_memory_buffer.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_memory_buffer.h
index 4ebe98f..d5d47b3 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_memory_buffer.h
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_memory_buffer.h
@@ -51,6 +51,7 @@
   /* private */
   GByteArray *buf;
   guint32 buf_size;
+  gboolean owner;
 };
 
 typedef struct _ThriftMemoryBufferClass ThriftMemoryBufferClass;
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_platform_socket.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_platform_socket.h
new file mode 100644
index 0000000..ede60f1
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_platform_socket.h
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+/* clang-format off */
+
+#ifndef _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_
+#  define _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_
+
+#ifdef _WIN32
+#  define THRIFT_GET_SOCKET_ERROR ::WSAGetLastError()
+#  define THRIFT_ERRNO (*_errno())
+#  define THRIFT_EINPROGRESS WSAEINPROGRESS
+#  define THRIFT_EAGAIN WSAEWOULDBLOCK
+#  define THRIFT_EINTR WSAEINTR
+#  define THRIFT_ECONNRESET WSAECONNRESET
+#  define THRIFT_ENOTCONN WSAENOTCONN
+#  define THRIFT_ETIMEDOUT WSAETIMEDOUT
+#  define THRIFT_EWOULDBLOCK WSAEWOULDBLOCK
+#  define THRIFT_EPIPE WSAECONNRESET
+#  define THRIFT_NO_SOCKET_CACHING SO_EXCLUSIVEADDRUSE
+#  define THRIFT_INVALID_SOCKET INVALID_SOCKET
+#  define THRIFT_SOCKETPAIR thrift_socketpair
+#  define THRIFT_FCNTL thrift_fcntl
+#  define THRIFT_O_NONBLOCK 1
+#  define THRIFT_F_GETFL 0
+#  define THRIFT_F_SETFL 1
+#  define THRIFT_GETTIMEOFDAY thrift_gettimeofday
+#  define THRIFT_CLOSESOCKET closesocket
+#  define THRIFT_CLOSE _close
+#  define THRIFT_OPEN _open
+#  define THRIFT_FTRUNCATE _chsize_s
+#  define THRIFT_FSYNC _commit
+#  define THRIFT_LSEEK _lseek
+#  define THRIFT_WRITE _write
+#  define THRIFT_READ _read
+#  define THRIFT_FSTAT _fstat
+#  define THRIFT_STAT _stat
+#  ifdef _WIN32_WCE
+#    define THRIFT_GAI_STRERROR(...) thrift_wstr2str(gai_strerrorW(__VA_ARGS__))
+#  else
+#    define THRIFT_GAI_STRERROR gai_strerrorA
+#  endif
+#  define THRIFT_SSIZET ptrdiff_t
+#  define THRIFT_SNPRINTF _snprintf
+#  define THRIFT_SLEEP_SEC thrift_sleep
+#  define THRIFT_SLEEP_USEC thrift_usleep
+#  define THRIFT_TIMESPEC thrift_timespec
+#  define THRIFT_CTIME_R thrift_ctime_r
+#  define THRIFT_POLL thrift_poll
+#  if WINVER <= 0x0502 /* XP, Server2003 */
+#    define THRIFT_POLLFD  thrift_pollfd
+#    define THRIFT_POLLIN  0x0300
+#    define THRIFT_POLLOUT 0x0010
+#  else /* Vista, Win7... */
+#    define THRIFT_POLLFD  pollfd
+#    define THRIFT_POLLIN  POLLIN
+#    define THRIFT_POLLOUT POLLOUT
+#  endif /* WINVER */
+#  define THRIFT_SHUT_RDWR SD_BOTH
+#else /* not _WIN32 */
+#  include <errno.h>
+#  define THRIFT_GET_SOCKET_ERROR errno
+#  define THRIFT_ERRNO errno
+#  define THRIFT_EINTR       EINTR
+#  define THRIFT_EINPROGRESS EINPROGRESS
+#  define THRIFT_ECONNRESET  ECONNRESET
+#  define THRIFT_ENOTCONN    ENOTCONN
+#  define THRIFT_ETIMEDOUT   ETIMEDOUT
+#  define THRIFT_EWOULDBLOCK EWOULDBLOCK
+#  define THRIFT_EAGAIN      EAGAIN
+#  define THRIFT_EPIPE       EPIPE
+#  define THRIFT_NO_SOCKET_CACHING SO_REUSEADDR
+#  define THRIFT_INVALID_SOCKET (-1)
+#  define THRIFT_SOCKETPAIR socketpair
+#  define THRIFT_FCNTL fcntl
+#  define THRIFT_O_NONBLOCK O_NONBLOCK
+#  define THRIFT_F_GETFL F_GETFL
+#  define THRIFT_F_SETFL F_SETFL
+#  define THRIFT_GETTIMEOFDAY gettimeofday
+#  define THRIFT_CLOSESOCKET close
+#  define THRIFT_CLOSE close
+#  define THRIFT_OPEN open
+#  define THRIFT_FTRUNCATE ftruncate
+#  define THRIFT_FSYNC fsync
+#  define THRIFT_LSEEK lseek
+#  define THRIFT_WRITE write
+#  define THRIFT_READ read
+#  define THRIFT_STAT stat
+#  define THRIFT_FSTAT fstat
+#  define THRIFT_GAI_STRERROR gai_strerror
+#  define THRIFT_SSIZET ssize_t
+#  define THRIFT_SNPRINTF snprintf
+#  define THRIFT_SLEEP_SEC sleep
+#  define THRIFT_SLEEP_USEC usleep
+#  define THRIFT_TIMESPEC timespec
+#  define THRIFT_CTIME_R ctime_r
+#  define THRIFT_POLL poll
+#  define THRIFT_POLLFD  pollfd
+#  define THRIFT_POLLIN  POLLIN
+#  define THRIFT_POLLOUT POLLOUT
+#  define THRIFT_SHUT_RDWR SHUT_RDWR
+#endif
+
+#endif /* _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_ */
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.c
index 6ab7fde..6ea897c 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.c
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.c
@@ -42,9 +42,6 @@
 /* define the GError domain string */
 #define THRIFT_SERVER_SOCKET_ERROR_DOMAIN "thrift-server-socket-error-quark"
 
-/* for errors coming from socket() and connect() */
-extern int errno;
-
 G_DEFINE_TYPE(ThriftServerSocket, thrift_server_socket, THRIFT_TYPE_SERVER_TRANSPORT)
 
 gboolean
@@ -103,7 +100,7 @@
 ThriftTransport *
 thrift_server_socket_accept (ThriftServerTransport *transport, GError **error)
 {
-  int sd = 0;
+  int sd = THRIFT_INVALID_SOCKET;
   guint addrlen = 0;
   struct sockaddr_in address;
   ThriftSocket *socket = NULL;
@@ -137,7 +134,7 @@
                  "unable to close socket - %s", strerror(errno));
     return FALSE;
   }
-  tsocket->sd = 0;
+  tsocket->sd = THRIFT_INVALID_SOCKET;
 
   return TRUE;
 }
@@ -153,7 +150,7 @@
 static void
 thrift_server_socket_init (ThriftServerSocket *socket)
 {
-  socket->sd = 0;
+  socket->sd = THRIFT_INVALID_SOCKET;
 }
 
 /* destructor */
@@ -162,11 +159,11 @@
 {
   ThriftServerSocket *socket = THRIFT_SERVER_SOCKET (object);
 
-  if (socket->sd != 0)
+  if (socket->sd != THRIFT_INVALID_SOCKET)
   {
     close (socket->sd);
   }
-  socket->sd = 0;
+  socket->sd = THRIFT_INVALID_SOCKET;
 }
 
 /* property accessor */
@@ -215,6 +212,7 @@
 static void
 thrift_server_socket_class_init (ThriftServerSocketClass *cls)
 {
+  ThriftServerTransportClass *tstc = THRIFT_SERVER_TRANSPORT_CLASS (cls);
   GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
   GParamSpec *param_spec = NULL;
 
@@ -226,12 +224,12 @@
                                   "port (construct)",
                                   "Set the port to listen to",
                                   0, /* min */
-                                  65534, /* max */
+                                  65535, /* max */
                                   9090, /* default by convention */
                                   G_PARAM_CONSTRUCT_ONLY |
                                   G_PARAM_READWRITE);
   g_object_class_install_property (gobject_class,
-                                   PROP_THRIFT_SERVER_SOCKET_PORT, 
+                                   PROP_THRIFT_SERVER_SOCKET_PORT,
                                    param_spec);
 
   param_spec = g_param_spec_uint ("backlog",
@@ -248,7 +246,6 @@
 
   gobject_class->finalize = thrift_server_socket_finalize;
 
-  ThriftServerTransportClass *tstc = THRIFT_SERVER_TRANSPORT_CLASS (cls);
   tstc->listen = thrift_server_socket_listen;
   tstc->accept = thrift_server_socket_accept;
   tstc->close = thrift_server_socket_close;
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.h
index f072cb0..fd04954 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.h
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.h
@@ -49,7 +49,7 @@
   ThriftServerTransport parent;
 
   /* private */
-  gshort port;
+  guint port;
   gshort backlog;
   int sd;
   guint8 *buf;
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c
index 694a84c..6dd0f0d 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c
@@ -37,9 +37,6 @@
   PROP_THRIFT_SOCKET_PORT
 };
 
-/* for errors coming from socket() and connect() */
-extern int errno;
-
 G_DEFINE_TYPE(ThriftSocket, thrift_socket, THRIFT_TYPE_TRANSPORT)
 
 /* implements thrift_transport_is_open */
@@ -47,58 +44,58 @@
 thrift_socket_is_open (ThriftTransport *transport)
 {
   ThriftSocket *socket = THRIFT_SOCKET (transport);
-  return socket->sd != 0;
+  return socket->sd != THRIFT_INVALID_SOCKET;
 }
 
-/* implements thrift_transport_open */
+/* overrides thrift_transport_peek */
 gboolean
-thrift_socket_open (ThriftTransport *transport, GError **error)
+thrift_socket_peek (ThriftTransport *transport, GError **error)
 {
-  struct hostent *hp = NULL;
-  struct sockaddr_in pin;
+  gboolean result = FALSE;
+  guint8 buf;
+  int r;
+  int errno_copy;
 
-  ThriftSocket *tsocket = THRIFT_SOCKET (transport);
-  g_return_val_if_fail (tsocket->sd == 0, FALSE);
+  ThriftSocket *socket = THRIFT_SOCKET (transport);
 
-  /* lookup the destination host */
-  if ((hp = gethostbyname (tsocket->hostname)) == NULL)
+  if (thrift_socket_is_open (transport))
   {
-    /* host lookup failed, bail out with an error */
-    g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_HOST,
-                 "host lookup failed for %s:%d - %s",
-                 tsocket->hostname, tsocket->port,
-                 hstrerror (h_errno));
-    return FALSE;
+    r = recv (socket->sd, &buf, 1, MSG_PEEK);
+    if (r == -1)
+    {
+      errno_copy = errno;
+
+      #if defined __FreeBSD__ || defined __MACH__
+      /* FreeBSD returns -1 and ECONNRESET if the socket was closed by the other
+         side */
+      if (errno_copy == ECONNRESET)
+      {
+        thrift_socket_close (transport, error);
+      }
+      else
+      {
+      #endif
+
+      g_set_error (error,
+                   THRIFT_TRANSPORT_ERROR,
+                   THRIFT_TRANSPORT_ERROR_SOCKET,
+                   "failed to peek at socket - %s",
+                   strerror (errno_copy));
+
+      #if defined __FreeBSD__ || defined __MACH__
+      }
+      #endif
+    }
+    else if (r > 0)
+    {
+      result = TRUE;
+    }
   }
 
-  /* create a socket structure */
-  memset (&pin, 0, sizeof(pin));
-  pin.sin_family = AF_INET;
-  pin.sin_addr.s_addr = ((struct in_addr *) (hp->h_addr))->s_addr;
-  pin.sin_port = htons (tsocket->port); 
-
-  /* create the socket */
-  if ((tsocket->sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
-  {
-    g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_SOCKET,
-                 "failed to create socket for host %s:%d - %s",
-                 tsocket->hostname, tsocket->port,
-                 strerror(errno));
-    return FALSE;
-  }
-
-  /* open a connection */
-  if (connect (tsocket->sd, (struct sockaddr *) &pin, sizeof(pin)) == -1)
-  {
-    g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_CONNECT,
-                 "failed to connect to host %s:%d - %s",
-                 tsocket->hostname, tsocket->port, strerror(errno));
-    return FALSE;
-  }
-
-  return TRUE;
+  return result;
 }
 
+
 /* implements thrift_transport_close */
 gboolean
 thrift_socket_close (ThriftTransport *transport, GError **error)
@@ -113,10 +110,70 @@
     return FALSE;
   }
 
-  socket->sd = 0;
+  socket->sd = THRIFT_INVALID_SOCKET;
   return TRUE;
 }
 
+/* implements thrift_transport_open */
+gboolean
+thrift_socket_open (ThriftTransport *transport, GError **error)
+{
+  struct hostent *hp = NULL;
+  struct sockaddr_in pin;
+  int err;
+#if defined(HAVE_GETHOSTBYNAME_R)
+  struct hostent he;
+  char buf[1024];
+#endif
+
+  ThriftSocket *tsocket = THRIFT_SOCKET (transport);
+  g_return_val_if_fail (tsocket->sd == THRIFT_INVALID_SOCKET, FALSE);
+
+  /* lookup the destination host */
+#if defined(HAVE_GETHOSTBYNAME_R)
+  if (gethostbyname_r (tsocket->hostname, &he, buf, 1024, &hp, &err) != 0 || hp == NULL)
+#else
+  if ((hp = gethostbyname (tsocket->hostname)) == NULL && (err = h_errno))
+#endif
+  {
+    /* host lookup failed, bail out with an error */
+    g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_HOST,
+                 "host lookup failed for %s:%d - %s",
+                 tsocket->hostname, tsocket->port,
+                 hstrerror (err));
+    return FALSE;
+  }
+
+  /* create a socket structure */
+  memset (&pin, 0, sizeof(pin));
+  pin.sin_family = AF_INET;
+  pin.sin_addr.s_addr = ((struct in_addr *) (hp->h_addr_list[0]))->s_addr;
+  pin.sin_port = htons (tsocket->port);
+
+  /* create the socket */
+  if ((tsocket->sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
+  {
+    g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_SOCKET,
+                 "failed to create socket for host %s:%d - %s",
+                 tsocket->hostname, tsocket->port,
+                 strerror(errno));
+    return FALSE;
+  }
+
+  /* open a connection */
+  if (connect (tsocket->sd, (struct sockaddr *) &pin, sizeof(pin)) == -1)
+  {
+      thrift_socket_close(tsocket, NULL);
+      g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_CONNECT,
+                 "failed to connect to host %s:%d - %s",
+                 tsocket->hostname, tsocket->port, strerror(errno));
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
 /* implements thrift_transport_read */
 gint32
 thrift_socket_read (ThriftTransport *transport, gpointer buf,
@@ -129,8 +186,8 @@
 
   while (got < len)
   {
-    ret = recv (socket->sd, buf+got, len-got, 0);
-    if (ret < 0)
+    ret = recv (socket->sd, (guint8 *)buf + got, len-got, 0);
+    if (ret <= 0)
     {
       g_set_error (error, THRIFT_TRANSPORT_ERROR,
                    THRIFT_TRANSPORT_ERROR_RECEIVE,
@@ -156,18 +213,18 @@
 
 /* implements thrift_transport_write */
 gboolean
-thrift_socket_write (ThriftTransport *transport, const gpointer buf,     
+thrift_socket_write (ThriftTransport *transport, const gpointer buf,
                      const guint32 len, GError **error)
 {
   gint ret = 0;
   guint sent = 0;
 
   ThriftSocket *socket = THRIFT_SOCKET (transport);
-  g_return_val_if_fail (socket->sd != 0, FALSE);
+  g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET, FALSE);
 
   while (sent < len)
   {
-    ret = send (socket->sd, buf + sent, len - sent, 0);
+    ret = send (socket->sd, (guint8 *)buf + sent, len - sent, 0);
     if (ret < 0)
     {
       g_set_error (error, THRIFT_TRANSPORT_ERROR,
@@ -207,7 +264,7 @@
 static void
 thrift_socket_init (ThriftSocket *socket)
 {
-  socket->sd = 0;
+  socket->sd = THRIFT_INVALID_SOCKET;
 }
 
 /* destructor */
@@ -222,11 +279,11 @@
   }
   socket->hostname = NULL;
 
-  if (socket->sd != 0)
+  if (socket->sd != THRIFT_INVALID_SOCKET)
   {
     close (socket->sd);
   }
-  socket->sd = 0;
+  socket->sd = THRIFT_INVALID_SOCKET;
 }
 
 /* property accessor */
@@ -234,9 +291,10 @@
 thrift_socket_get_property (GObject *object, guint property_id,
                             GValue *value, GParamSpec *pspec)
 {
-  THRIFT_UNUSED_VAR (pspec);
   ThriftSocket *socket = THRIFT_SOCKET (object);
 
+  THRIFT_UNUSED_VAR (pspec);
+
   switch (property_id)
   {
     case PROP_THRIFT_SOCKET_HOSTNAME:
@@ -253,12 +311,16 @@
 thrift_socket_set_property (GObject *object, guint property_id,
                             const GValue *value, GParamSpec *pspec)
 {
-  THRIFT_UNUSED_VAR (pspec);
   ThriftSocket *socket = THRIFT_SOCKET (object);
 
+  THRIFT_UNUSED_VAR (pspec);
+
   switch (property_id)
   {
     case PROP_THRIFT_SOCKET_HOSTNAME:
+      if (socket->hostname) {
+        g_free(socket->hostname);
+      }
       socket->hostname = g_strdup (g_value_get_string (value));
       break;
     case PROP_THRIFT_SOCKET_PORT:
@@ -271,6 +333,7 @@
 static void
 thrift_socket_class_init (ThriftSocketClass *cls)
 {
+  ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
   GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
   GParamSpec *param_spec = NULL;
 
@@ -290,18 +353,17 @@
   param_spec = g_param_spec_uint ("port",
                                   "port (construct)",
                                   "Set the port of the remote host",
-                                  0, /* min */
-                                  65534, /* max */
+                                  0u, /* min */
+                                  65535u, /* max */
                                   9090, /* default by convention */
                                   G_PARAM_CONSTRUCT_ONLY |
                                   G_PARAM_READWRITE);
   g_object_class_install_property (gobject_class, PROP_THRIFT_SOCKET_PORT,
                                    param_spec);
 
-  ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
-
   gobject_class->finalize = thrift_socket_finalize;
   ttc->is_open = thrift_socket_is_open;
+  ttc->peek = thrift_socket_peek;
   ttc->open = thrift_socket_open;
   ttc->close = thrift_socket_close;
   ttc->read = thrift_socket_read;
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.h
index 981577d..2f6f67d 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.h
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.h
@@ -50,11 +50,8 @@
 
   /* private */
   gchar *hostname;
-  gshort port;
+  guint port;
   int sd;
-  guint8 *buf;
-  guint32 buf_size;
-  guint32 buf_len;
 };
 
 typedef struct _ThriftSocketClass ThriftSocketClass;
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.c
new file mode 100644
index 0000000..ee55406
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.c
@@ -0,0 +1,806 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <openssl/ssl.h>
+#include <pthread.h>
+
+#include <glib-object.h>
+#include <glib.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_socket.h>
+#include <thrift/c_glib/transport/thrift_ssl_socket.h>
+
+
+#if defined(WIN32)
+#define MUTEX_TYPE            HANDLE
+#define MUTEX_SETUP(x)        (x) = CreateMutex(NULL, FALSE, NULL)
+#define MUTEX_CLEANUP(x)      CloseHandle(x)
+#define MUTEX_LOCK(x)         WaitForSingleObject((x), INFINITE)
+#define MUTEX_UNLOCK(x)       ReleaseMutex(x)
+#else
+#define MUTEX_TYPE            pthread_mutex_t
+#define MUTEX_SETUP(x)        pthread_mutex_init(&(x), NULL)
+#define MUTEX_CLEANUP(x)      pthread_mutex_destroy(&(x))
+#define MUTEX_LOCK(x)         pthread_mutex_lock(&(x))
+#define MUTEX_UNLOCK(x)       pthread_mutex_unlock(&(x))
+#endif
+
+#define OPENSSL_VERSION_NO_THREAD_ID 0x10000000L
+
+
+/* object properties */
+enum _ThriftSSLSocketProperties
+{
+  PROP_THRIFT_SSL_SOCKET_CONTEXT = 3,
+  PROP_THRIFT_SSL_SELF_SIGNED
+};
+
+/* To hold a global state management of openssl for all instances */
+static gboolean thrift_ssl_socket_openssl_initialized=FALSE;
+/* This array will store all of the mutexes available to OpenSSL. */
+static MUTEX_TYPE *thrift_ssl_socket_global_mutex_buf=NULL;
+
+
+/**
+ * OpenSSL uniq id function.
+ *
+ * @return    thread id
+ */
+static unsigned long thrift_ssl_socket_static_id_function(void)
+{
+#if defined(WIN32)
+  return GetCurrentThreadId();
+#else
+  return ((unsigned long) pthread_self());
+#endif
+}
+
+static void thrift_ssl_socket_static_locking_callback(int mode, int n, const char* unk, int id) {
+  if (mode & CRYPTO_LOCK)
+    MUTEX_LOCK(thrift_ssl_socket_global_mutex_buf[n]);
+  else
+    MUTEX_UNLOCK(thrift_ssl_socket_global_mutex_buf[n]);
+}
+
+static int thrift_ssl_socket_static_thread_setup(void)
+{
+  int i;
+
+  thrift_ssl_socket_global_mutex_buf = malloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE));
+  if (!thrift_ssl_socket_global_mutex_buf)
+    return 0;
+  for (i = 0;  i < CRYPTO_num_locks(  );  i++)
+    MUTEX_SETUP(thrift_ssl_socket_global_mutex_buf[i]);
+  CRYPTO_set_id_callback(thrift_ssl_socket_static_id_function);
+  CRYPTO_set_locking_callback(thrift_ssl_socket_static_locking_callback);
+  return 1;
+}
+
+static int thrift_ssl_socket_static_thread_cleanup(void)
+{
+  int i;
+  if (!thrift_ssl_socket_global_mutex_buf)
+    return 0;
+  CRYPTO_set_id_callback(NULL);
+  CRYPTO_set_locking_callback(NULL);
+  for (i = 0;  i < CRYPTO_num_locks(  );  i++)
+    MUTEX_CLEANUP(thrift_ssl_socket_global_mutex_buf[i]);
+  free(thrift_ssl_socket_global_mutex_buf);
+  thrift_ssl_socket_global_mutex_buf = NULL;
+  return 1;
+}
+
+/*
+static void* thrift_ssl_socket_dyn_lock_create_callback(const char* unk, int id) {
+  g_print("We should create a lock\n");
+  return NULL;
+}
+
+static void thrift_ssl_socket_dyn_lock_callback(int mode, void* lock, const char* unk, int id) {
+  if (lock != NULL) {
+    if (mode & CRYPTO_LOCK) {
+      g_printf("We should lock thread %d\n");
+    } else {
+      g_printf("We should unlock thread %d\n");
+    }
+  }
+}
+
+static void thrift_ssl_socket_dyn_lock_destroy_callback(void* lock, const char* unk, int id) {
+  g_printf("We must destroy the lock\n");
+}
+ */
+
+
+G_DEFINE_TYPE(ThriftSSLSocket, thrift_ssl_socket, THRIFT_TYPE_SOCKET)
+
+
+
+/**
+ * When there's a thread context attached, we pass the SSL socket context so it
+ * can check if the error is outside SSL, on I/O for example
+ * @param socket
+ * @param error_msg
+ * @param thrift_error_no
+ * @param ssl_error
+ * @param error
+ */
+static
+void thrift_ssl_socket_get_ssl_error(ThriftSSLSocket *socket, const guchar *error_msg, guint thrift_error_no, int ssl_error, GError **error)
+{
+  unsigned long error_code;
+  char buffer[1024];
+  int buffer_size=1024;
+  gboolean first_error = TRUE;
+  int ssl_error_type = SSL_get_error(socket->ssl, ssl_error);
+  if(ssl_error_type>0){
+      switch(ssl_error_type){
+	case SSL_ERROR_SSL:
+	  buffer_size-=snprintf(buffer, buffer_size, "SSL %s: ", error_msg);
+	  while ((error_code = ERR_get_error()) != 0 && buffer_size>1) {
+	      const char* reason = ERR_reason_error_string(error_code);
+	      if(reason!=NULL){
+		  if(!first_error) {
+		      buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "\n\t");
+		      first_error=FALSE;
+		  }
+		  buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "%lX(%s) -> %s", error_code, reason, SSL_state_string(socket->ssl));
+	      }
+	  }
+	  break;
+	case SSL_ERROR_SYSCALL:
+	  buffer_size-=snprintf(buffer, buffer_size, "%s: ", error_msg);
+	  buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "%lX -> %s", errno, strerror(errno));
+	  break;
+	case SSL_ERROR_WANT_READ:
+	  buffer_size-=snprintf(buffer, buffer_size, "%s: ", error_msg);
+	  buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "%lX -> %s", ssl_error_type, "Error while reading from underlaying layer");
+	  break;
+	case SSL_ERROR_WANT_WRITE:
+	  buffer_size-=snprintf(buffer, buffer_size, "%s: ", error_msg);
+	  buffer_size-=snprintf(buffer+(1024-buffer_size), buffer_size, "%lX -> %s", ssl_error_type, "Error while writting to underlaying layer");
+	  break;
+
+      }
+      g_set_error (error, THRIFT_TRANSPORT_ERROR,
+		   thrift_error_no, "%s", buffer);
+  }
+}
+
+/**
+ * For global SSL errors
+ * @param error_msg
+ * @param thrift_error_no
+ * @param error
+ */
+static
+void thrift_ssl_socket_get_error(const guchar *error_msg, guint thrift_error_no, GError **error)
+{
+  unsigned long error_code;
+  while ((error_code = ERR_get_error()) != 0) {
+      const char* reason = ERR_reason_error_string(error_code);
+      if (reason == NULL) {
+	  g_set_error (error, THRIFT_TRANSPORT_ERROR,
+		       thrift_error_no,
+		       "SSL error %lX: %s", error_code, error_msg);
+      }else{
+	  g_set_error (error, THRIFT_TRANSPORT_ERROR,
+		       thrift_error_no,
+		       "SSL error %lX %s: %s", error_code,reason, error_msg);
+      }
+  }
+}
+
+
+
+/* implements thrift_transport_is_open */
+gboolean
+thrift_ssl_socket_is_open (ThriftTransport *transport)
+{
+  return thrift_socket_is_open(transport);
+}
+
+/* overrides thrift_transport_peek */
+gboolean
+thrift_ssl_socket_peek (ThriftTransport *transport, GError **error)
+{
+  gboolean retval = FALSE;
+  ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
+  if (thrift_ssl_socket_is_open (transport))
+    {
+      int rc;
+      gchar byte;
+      rc = SSL_peek(ssl_socket->ssl, &byte, 1);
+      if (rc < 0) {
+	  thrift_ssl_socket_get_ssl_error(ssl_socket, "Check socket data",
+					  THRIFT_SSL_SOCKET_ERROR_SSL, rc, error);
+      }
+      if (rc == 0) {
+	  ERR_clear_error();
+      }
+      retval = (rc > 0);
+    }
+  return retval;
+}
+
+/* implements thrift_transport_open */
+gboolean
+thrift_ssl_socket_open (ThriftTransport *transport, GError **error)
+{
+  ERR_clear_error();
+
+  if (!thrift_socket_open(transport, error)) {
+      return FALSE;
+  }
+
+  if (!THRIFT_SSL_SOCKET_GET_CLASS(transport)->handle_handshake(transport, error)) {
+      thrift_ssl_socket_close(transport, NULL);
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* implements thrift_transport_close */
+gboolean
+thrift_ssl_socket_close (ThriftTransport *transport, GError **error)
+{
+  gboolean retval = FALSE;
+  ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET(transport);
+  if(ssl_socket!=NULL && ssl_socket->ssl) {
+      int rc = SSL_shutdown(ssl_socket->ssl);
+/*      if (rc < 0) {
+	  int errno_copy = THRIFT_SSL_SOCKET_ERROR_SSL;
+      }*/
+      SSL_free(ssl_socket->ssl);
+      ssl_socket->ssl = NULL;
+      ERR_remove_state(0);
+  }
+  return thrift_socket_close(transport, error);
+}
+
+/* implements thrift_transport_read */
+gint32
+thrift_ssl_socket_read (ThriftTransport *transport, gpointer buf,
+			guint32 len, GError **error)
+{
+  guint maxRecvRetries_ = 10;
+  ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
+  guint bytes = 0;
+  guint retries = 0;
+  ThriftSocket *socket = THRIFT_SOCKET (transport);
+  g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET && ssl_socket->ssl!=NULL, FALSE);
+
+  for (retries=0; retries < maxRecvRetries_; retries++) {
+      bytes = SSL_read(ssl_socket->ssl, buf, len);
+      if (bytes >= 0)
+	break;
+      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+      if (SSL_get_error(ssl_socket->ssl, bytes) == SSL_ERROR_SYSCALL) {
+	  if (ERR_get_error() == 0 && errno_copy == THRIFT_EINTR) {
+	      continue;
+	  }
+      }else{
+	  thrift_ssl_socket_get_ssl_error(ssl_socket, "Receive error",
+					  THRIFT_SSL_SOCKET_ERROR_SSL, bytes, error);
+
+      }
+      return -1;
+  }
+  return bytes;
+}
+
+/* implements thrift_transport_read_end
+ * called when write is complete.  nothing to do on our end. */
+gboolean
+thrift_ssl_socket_read_end (ThriftTransport *transport, GError **error)
+{
+  /* satisfy -Wall */
+  THRIFT_UNUSED_VAR (transport);
+  THRIFT_UNUSED_VAR (error);
+  return TRUE;
+}
+
+/* implements thrift_transport_write */
+gboolean
+thrift_ssl_socket_write (ThriftTransport *transport, const gpointer buf,
+			 const guint32 len, GError **error)
+{
+  ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
+  gint ret = 0;
+  guint sent = 0;
+  ThriftSocket *socket = THRIFT_SOCKET (transport);
+  g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET && ssl_socket->ssl!=NULL, FALSE);
+
+  while (sent < len)
+    {
+      ret = SSL_write (ssl_socket->ssl, (guint8 *)buf + sent, len - sent);
+      if (ret < 0)
+	{
+	  thrift_ssl_socket_get_ssl_error(ssl_socket, "Send error",
+					  THRIFT_SSL_SOCKET_ERROR_SSL, ret, error);
+	  return FALSE;
+	}
+      sent += ret;
+    }
+
+  return sent==len;
+}
+
+/* implements thrift_transport_write_end
+ * called when write is complete.  nothing to do on our end. */
+gboolean
+thrift_ssl_socket_write_end (ThriftTransport *transport, GError **error)
+{
+  /* satisfy -Wall */
+  THRIFT_UNUSED_VAR (transport);
+  THRIFT_UNUSED_VAR (error);
+  return TRUE;
+}
+
+/* implements thrift_transport_flush
+ * flush pending data.  since we are not buffered, this is a no-op */
+gboolean
+thrift_ssl_socket_flush (ThriftTransport *transport, GError **error)
+{
+  ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
+  gint ret = 0;
+  guint sent = 0;
+
+  ThriftSocket *socket = THRIFT_SOCKET (transport);
+  g_return_val_if_fail (socket->sd != THRIFT_INVALID_SOCKET && ssl_socket->ssl!=NULL, FALSE);
+
+  BIO* bio = SSL_get_wbio(ssl_socket->ssl);
+  if (bio == NULL) {
+      g_set_error (error, THRIFT_TRANSPORT_ERROR,
+		   THRIFT_TRANSPORT_ERROR_SEND,
+		   "failed to flush, wbio returned null");
+      return FALSE;
+  }
+  if (BIO_flush(bio) != 1) {
+      g_set_error (error, THRIFT_TRANSPORT_ERROR,
+		   THRIFT_TRANSPORT_ERROR_SEND,
+		   "failed to flush it returned error");
+      return FALSE;
+  }
+  return TRUE;
+}
+
+
+gboolean
+thrift_ssl_socket_handle_handshake(ThriftTransport * transport, GError **error)
+{
+  ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
+  ThriftSocket *socket = THRIFT_SOCKET (transport);
+  g_return_val_if_fail (thrift_transport_is_open (transport), FALSE);
+
+  if(THRIFT_SSL_SOCKET_GET_CLASS(ssl_socket)->create_ssl_context(transport, error)){
+      /*Context created*/
+      SSL_set_fd(ssl_socket->ssl, socket->sd);
+      int rc;
+      if(ssl_socket->server){
+	  rc = SSL_accept(ssl_socket->ssl);
+      }else{
+	  rc = SSL_connect(ssl_socket->ssl);
+      }
+      if (rc <= 0) {
+	  thrift_ssl_socket_get_ssl_error(ssl_socket, "Error while connect/bind", THRIFT_SSL_SOCKET_ERROR_CONNECT_BIND, rc, error);
+	  return FALSE;
+      }
+  }else
+    return FALSE;
+
+  return thrift_ssl_socket_authorize(transport, error);
+}
+
+gboolean
+thrift_ssl_socket_create_ssl_context(ThriftTransport * transport, GError **error)
+{
+  ThriftSSLSocket *socket = THRIFT_SSL_SOCKET (transport);
+
+  if(socket->ctx!=NULL){
+      if(socket->ssl!=NULL) {
+	  return TRUE;
+      }
+
+      socket->ssl = SSL_new(socket->ctx);
+      if (socket->ssl == NULL) {
+	  g_set_error (error, THRIFT_TRANSPORT_ERROR,
+		       THRIFT_SSL_SOCKET_ERROR_TRANSPORT,
+		       "Unable to create default SSL context");
+	  return FALSE;
+      }
+  }
+
+  return TRUE;
+}
+
+
+gboolean thrift_ssl_load_cert_from_file(ThriftSSLSocket *ssl_socket, const char *file_name)
+{
+  char error_buffer[255];
+  if (!thrift_ssl_socket_openssl_initialized) {
+      g_error("OpenSSL is not initialized yet");
+      return FALSE;
+  }
+  int rc = SSL_CTX_load_verify_locations(ssl_socket->ctx, file_name, NULL);
+  if (rc != 1) { /*verify authentication result*/
+      ERR_error_string_n(ERR_get_error(), error_buffer, 254);
+      g_warning("Load of certificates failed: %s!", error_buffer);
+      return FALSE;
+  }
+  return TRUE;
+}
+
+
+gboolean thrift_ssl_load_cert_from_buffer(ThriftSSLSocket *ssl_socket, const char chain_certs[])
+{
+  gboolean retval = FALSE;
+  /* Load chain of certs*/
+  X509 *cacert=NULL;
+  BIO *mem = BIO_new_mem_buf(chain_certs,strlen(chain_certs));
+  X509_STORE *cert_store = SSL_CTX_get_cert_store(ssl_socket->ctx);
+
+  if(cert_store!=NULL){
+      int index = 0;
+      while ((cacert = PEM_read_bio_X509(mem, NULL, 0, NULL))!=NULL) {
+	  if(cacert) {
+	      X509_STORE_add_cert(cert_store, cacert);
+	      X509_free(cacert);
+	      cacert=NULL;
+	  } /* Free immediately */
+	  index++;
+      }
+      retval=TRUE;
+  }
+  BIO_free(mem);
+  return retval;
+}
+
+gboolean
+thrift_ssl_socket_authorize(ThriftTransport * transport, GError **error)
+{
+  ThriftSocket *socket = THRIFT_SOCKET (transport);
+  ThriftSSLSocket *ssl_socket = THRIFT_SSL_SOCKET (transport);
+  ThriftSSLSocketClass *cls = THRIFT_SSL_SOCKET_GET_CLASS(ssl_socket);
+  gboolean authorization_result = FALSE;
+
+  if(cls!=NULL && ssl_socket->ssl!=NULL){
+      int rc = SSL_get_verify_result(ssl_socket->ssl);
+      if (rc != X509_V_OK) { /* verify authentication result */
+	  if (rc == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && ssl_socket->allow_selfsigned) {
+	      g_debug("The certificate is a self-signed certificate and configuration allows it");
+	  } else {
+	      g_set_error (error,
+			   THRIFT_TRANSPORT_ERROR,
+			   THRIFT_SSL_SOCKET_ERROR_SSL_CERT_VALIDATION_FAILED,
+			   "The certificate verification failed: %s (%d)", X509_verify_cert_error_string(rc), rc);
+	      return FALSE;
+	  }
+      }
+
+      X509* cert = SSL_get_peer_certificate(ssl_socket->ssl);
+      if (cert == NULL) {
+	  if (SSL_get_verify_mode(ssl_socket->ssl) & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+	      g_set_error (error,
+			   THRIFT_TRANSPORT_ERROR,
+			   THRIFT_SSL_SOCKET_ERROR_SSL_CERT_VALIDATION_FAILED,
+			   "No certificate present. Are you connecting SSL server?");
+	      return FALSE;
+	  }
+	  g_debug("No certificate required");
+	  return TRUE;
+      }
+
+      /* certificate is present, since we don't support access manager we are done */
+      if (cls->authorize_peer == NULL) {
+	  X509_free(cert);
+	  g_debug("Certificate presented but we're not checking it");
+	  return TRUE;
+      } else {
+	  /* both certificate and access manager are present */
+	  struct sockaddr_storage sa;
+	  socklen_t saLength = sizeof(struct sockaddr_storage);
+	  if (getpeername(socket->sd, (struct sockaddr*)&sa, &saLength) != 0) {
+	      sa.ss_family = AF_UNSPEC;
+	  }
+	  authorization_result = cls->authorize_peer(transport, cert, &sa, error);
+      }
+      if(cert != NULL) {
+	  X509_free(cert);
+      }
+  }
+
+  return authorization_result;
+}
+
+
+/* initializes the instance */
+static void
+thrift_ssl_socket_init (ThriftSSLSocket *socket)
+{
+  GError *error = NULL;
+  socket->ssl = NULL;
+  socket->ctx = thrift_ssl_socket_context_initialize(SSLTLS, &error);
+  if(socket->ctx == NULL) {
+      g_info("The SSL context was not automatically initialized with protocol %d", SSLTLS);
+      if(error!=NULL){
+	  g_info("Reported reason %s", error->message);
+	  g_error_free (error);
+      }
+  }
+  socket->server = FALSE;
+  socket->allow_selfsigned = FALSE;
+
+}
+
+/* destructor */
+static void
+thrift_ssl_socket_finalize (GObject *object)
+{
+  ThriftSSLSocket *socket = THRIFT_SSL_SOCKET (object);
+  GError *error=NULL;
+  if(socket!=NULL){
+      g_debug("Instance %p destroyed", (void *)socket);
+      if(socket->ssl != NULL)
+	{
+	  thrift_ssl_socket_close(THRIFT_TRANSPORT(object), &error);
+	  socket->ssl=NULL;
+	}
+
+      if(socket->ctx!=NULL){
+	  g_debug("Freeing the context for the instance");
+	  SSL_CTX_free(socket->ctx);
+	  socket->ctx=NULL;
+      }
+  }
+
+  if (G_OBJECT_CLASS (thrift_ssl_socket_parent_class)->finalize)
+    (*G_OBJECT_CLASS (thrift_ssl_socket_parent_class)->finalize) (object);
+}
+
+/* property accessor */
+void
+thrift_ssl_socket_get_property (GObject *object, guint property_id,
+				GValue *value, GParamSpec *pspec)
+{
+  ThriftSSLSocket *socket = THRIFT_SSL_SOCKET (object);
+  THRIFT_UNUSED_VAR (pspec);
+
+  switch (property_id)
+  {
+    case PROP_THRIFT_SSL_SOCKET_CONTEXT:
+      g_value_set_pointer (value, socket->ctx);
+      break;
+  }
+}
+
+/* property mutator */
+void
+thrift_ssl_socket_set_property (GObject *object, guint property_id,
+				const GValue *value, GParamSpec *pspec)
+{
+  ThriftSSLSocket *socket = THRIFT_SSL_SOCKET (object);
+
+  THRIFT_UNUSED_VAR (pspec);
+  switch (property_id)
+  {
+    case PROP_THRIFT_SSL_SOCKET_CONTEXT:
+      if(socket->ctx!=NULL){
+	  g_debug("Freeing the context since we are setting a new one");
+	  SSL_CTX_free(socket->ctx);
+      }
+      socket->ctx = g_value_get_pointer(value); /* We copy the context */
+      break;
+
+    case PROP_THRIFT_SSL_SELF_SIGNED:
+      socket->allow_selfsigned = g_value_get_boolean(value);
+      break;
+    default:
+      g_warning("Trying to set property %i that doesn't exists!", property_id);
+      /*    thrift_socket_set_property(object, property_id, value, pspec); */
+      break;
+  }
+}
+
+void
+thrift_ssl_socket_initialize_openssl(void)
+{
+  if(thrift_ssl_socket_openssl_initialized){
+      return;
+  }
+  thrift_ssl_socket_openssl_initialized=TRUE;
+  SSL_library_init();
+  ERR_load_crypto_strings();
+  SSL_load_error_strings();
+  ERR_load_BIO_strings();
+
+  /* Setup locking */
+  g_debug("We setup %d threads locks", thrift_ssl_socket_static_thread_setup());
+
+  /* dynamic locking
+  CRYPTO_set_dynlock_create_callback(thrift_ssl_socket_dyn_lock_create_callback);
+  CRYPTO_set_dynlock_lock_callback(thrift_ssl_socket_dyn_lock_callback);
+  CRYPTO_set_dynlock_destroy_callback(thrift_ssl_socket_dyn_lock_destroy_callback);
+   */
+}
+
+
+void thrift_ssl_socket_finalize_openssl(void)
+{
+  if (!thrift_ssl_socket_openssl_initialized) {
+      return;
+  }
+  thrift_ssl_socket_openssl_initialized = FALSE;
+
+  g_debug("We cleared %d threads locks", thrift_ssl_socket_static_thread_cleanup());
+  /* Not supported
+  CRYPTO_set_locking_callback(NULL);
+  CRYPTO_set_dynlock_create_callback(NULL);
+  CRYPTO_set_dynlock_lock_callback(NULL);
+  CRYPTO_set_dynlock_destroy_callback(NULL);
+   */
+  ERR_free_strings();
+  EVP_cleanup();
+  CRYPTO_cleanup_all_ex_data();
+  ERR_remove_state(0);
+}
+
+
+/* initializes the class */
+static void
+thrift_ssl_socket_class_init (ThriftSSLSocketClass *cls)
+{
+  ThriftTransportClass *ttc = THRIFT_TRANSPORT_CLASS (cls);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
+  GParamSpec *param_spec = NULL;
+
+  g_debug("Initialization of ThriftSSLSocketClass");
+  /* setup accessors and mutators */
+  gobject_class->get_property = thrift_ssl_socket_get_property;
+  gobject_class->set_property = thrift_ssl_socket_set_property;
+  param_spec = g_param_spec_pointer ("ssl_context",
+				     "SSLContext",
+				     "Set the SSL context for handshake with the remote host",
+				     G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_THRIFT_SSL_SOCKET_CONTEXT,
+				   param_spec);
+  param_spec = g_param_spec_boolean ("ssl_accept_selfsigned",
+				     "Accept Self Signed",
+				     "Whether or not accept self signed certificate",
+				     FALSE,
+				     G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_THRIFT_SSL_SELF_SIGNED,
+				   param_spec);
+  /* Class methods */
+  cls->handle_handshake = thrift_ssl_socket_handle_handshake;
+  cls->create_ssl_context = thrift_ssl_socket_create_ssl_context;
+
+  /* Override */
+  gobject_class->finalize = thrift_ssl_socket_finalize;
+  ttc->is_open = thrift_ssl_socket_is_open;
+  ttc->peek = thrift_ssl_socket_peek;
+  ttc->open = thrift_ssl_socket_open;
+  ttc->close = thrift_ssl_socket_close;
+  ttc->read = thrift_ssl_socket_read;
+  ttc->read_end = thrift_ssl_socket_read_end;
+  ttc->write = thrift_ssl_socket_write;
+  ttc->write_end = thrift_ssl_socket_write_end;
+  ttc->flush = thrift_ssl_socket_flush;
+}
+
+
+/*
+ * Public API
+ */
+ThriftSSLSocket*
+thrift_ssl_socket_new(ThriftSSLSocketProtocol ssl_protocol, GError **error)
+{
+  ThriftSSLSocket *thriftSSLSocket = NULL;
+  SSL_CTX *ssl_context = NULL;
+  /* Create the context */
+  if((ssl_context=thrift_ssl_socket_context_initialize(ssl_protocol, error))==NULL){
+      g_warning("We cannot initialize context for protocol %d", ssl_protocol);
+      return thriftSSLSocket;
+  }
+
+  /* FIXME if the protocol is different? */
+  thriftSSLSocket = g_object_new (THRIFT_TYPE_SSL_SOCKET, "ssl_context", ssl_context, NULL);
+  return thriftSSLSocket;
+}
+
+ThriftSSLSocket*
+thrift_ssl_socket_new_with_host(ThriftSSLSocketProtocol ssl_protocol, gchar *hostname, guint port, GError **error)
+{
+  ThriftSSLSocket *thriftSSLSocket = NULL;
+  SSL_CTX *ssl_context = NULL;
+  /* Create the context */
+  if((ssl_context=thrift_ssl_socket_context_initialize(ssl_protocol, error))==NULL){
+      /* FIXME Do error control */
+      return thriftSSLSocket;
+  }
+  /* FIXME if the protocol is different? */
+  thriftSSLSocket = g_object_new (THRIFT_TYPE_SSL_SOCKET, "ssl_context", ssl_context, "hostname", hostname, "port", port, NULL);
+  return thriftSSLSocket;
+}
+
+void thrift_ssl_socket_set_manager(ThriftSSLSocket *ssl_socket, AUTHORIZATION_MANAGER_CALLBACK callback)
+{
+  ThriftSSLSocketClass *sslSocketClass = THRIFT_SSL_SOCKET_GET_CLASS (ssl_socket);
+  if(sslSocketClass){
+      sslSocketClass->authorize_peer = callback;
+  }
+}
+
+
+SSL_CTX*
+thrift_ssl_socket_context_initialize(ThriftSSLSocketProtocol ssl_protocol, GError **error)
+{
+  SSL_CTX* context = NULL;
+  switch(ssl_protocol){
+    case SSLTLS:
+      context = SSL_CTX_new(SSLv23_method());
+      break;
+#ifndef OPENSSL_NO_SSL3
+    case SSLv3:
+      context = SSL_CTX_new(SSLv3_method());
+      break;
+#endif
+    case TLSv1_0:
+      context = SSL_CTX_new(TLSv1_method());
+      break;
+    case TLSv1_1:
+      context = SSL_CTX_new(TLSv1_1_method());
+      break;
+    case TLSv1_2:
+      context = SSL_CTX_new(TLSv1_2_method());
+      break;
+    default:
+      g_set_error (error, THRIFT_TRANSPORT_ERROR,
+		   THRIFT_SSL_SOCKET_ERROR_CIPHER_NOT_AVAILABLE,
+		   "The SSL protocol is unknown for %d", ssl_protocol);
+      return NULL;
+      break;
+  }
+
+  if (context == NULL) {
+      thrift_ssl_socket_get_error("No cipher overlay", THRIFT_SSL_SOCKET_ERROR_CIPHER_NOT_AVAILABLE, error);
+      return NULL;
+  }
+  SSL_CTX_set_mode(context, SSL_MODE_AUTO_RETRY);
+
+  /* Disable horribly insecure SSLv2 and SSLv3 protocols but allow a handshake
+     with older clients so they get a graceful denial. */
+  if (ssl_protocol == SSLTLS) {
+      SSL_CTX_set_options(context, SSL_OP_NO_SSLv2);
+      SSL_CTX_set_options(context, SSL_OP_NO_SSLv3);   /* THRIFT-3164 */
+  }
+
+  return context;
+}
+
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.h
new file mode 100644
index 0000000..0ca465a
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_ssl_socket.h
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_SSL_SOCKET_H
+#define _THRIFT_SSL_SOCKET_H
+
+#include <glib-object.h>
+#include <glib.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+#include <sys/socket.h>
+
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_socket.h>
+#include <thrift/c_glib/transport/thrift_platform_socket.h>
+
+G_BEGIN_DECLS
+
+/*! \file thrift_ssl_socket.h
+ *  \brief SSL Socket implementation of a Thrift transport.  Subclasses the
+ *         ThriftSocket class. Based on plain openssl.
+ *         In the future we should take a look to https://issues.apache.org/jira/browse/THRIFT-1016
+ */
+
+/* type macros */
+#define THRIFT_TYPE_SSL_SOCKET (thrift_ssl_socket_get_type ())
+#define THRIFT_SSL_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_SSL_SOCKET, ThriftSSLSocket))
+#define THRIFT_IS_SSL_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_SSL_SOCKET))
+#define THRIFT_SSL_SOCKET_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_SSL_SOCKET, ThriftSSLSocketClass))
+#define THRIFT_IS_SSL_SOCKET_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_SSL_SOCKET))
+#define THRIFT_SSL_SOCKET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_SSL_SOCKET, ThriftSSLSocketClass))
+
+
+/* define error/exception types */
+typedef enum
+{
+  THRIFT_SSL_SOCKET_ERROR_TRANSPORT=7,
+  THRIFT_SSL_SOCKET_ERROR_CONNECT_BIND,
+  THRIFT_SSL_SOCKET_ERROR_CIPHER_NOT_AVAILABLE,
+  THRIFT_SSL_SOCKET_ERROR_SSL,
+  THRIFT_SSL_SOCKET_ERROR_SSL_CERT_VALIDATION_FAILED
+} ThriftSSLSocketError;
+
+
+typedef struct _ThriftSSLSocket ThriftSSLSocket;
+
+/*!
+ * Thrift SSL Socket instance.
+ */
+struct _ThriftSSLSocket
+{
+  ThriftSocket parent;
+
+  /* private */
+  SSL *ssl;
+  SSL_CTX* ctx;
+  gboolean server;
+  gboolean allow_selfsigned;
+};
+
+typedef struct _ThriftSSLSocketClass ThriftSSLSocketClass;
+typedef gboolean (* AUTHORIZATION_MANAGER_CALLBACK) (ThriftTransport * transport, X509 *cert, struct sockaddr_storage *addr, GError **error);
+
+/*!
+ * Thrift Socket class.
+ */
+struct _ThriftSSLSocketClass
+{
+  ThriftSocketClass parent;
+
+  gboolean (* handle_handshake) (ThriftTransport * transport, GError **error);
+  gboolean (* create_ssl_context) (ThriftTransport * transport, GError **error);
+  gboolean (* authorize_peer) (ThriftTransport * transport, X509 *cert, struct sockaddr_storage *addr, GError **error);
+
+  /* Padding to allow adding up to 12 new virtual functions without
+   * breaking ABI. */
+  gpointer padding[12];
+};
+
+enum _ThriftSSLSocketProtocol {
+  SSLTLS  = 0,  /* Supports SSLv2 and SSLv3 handshake but only negotiates at TLSv1_0 or later. */
+/*SSLv2   = 1,   HORRIBLY INSECURE! */
+  SSLv3   = 2,  /* Supports SSLv3 only - also horribly insecure! */
+  TLSv1_0 = 3,  /* Supports TLSv1_0 or later. */
+  TLSv1_1 = 4,  /* Supports TLSv1_1 or later. */
+  TLSv1_2 = 5,  /* Supports TLSv1_2 or later. */
+  LATEST  = TLSv1_2
+};
+typedef enum _ThriftSSLSocketProtocol ThriftSSLSocketProtocol;
+
+
+/* Internal functions */
+SSL_CTX*
+thrift_ssl_socket_context_initialize(ThriftSSLSocketProtocol ssl_protocol, GError **error);
+
+
+/* used by THRIFT_TYPE_SSL_SOCKET */
+GType thrift_ssl_socket_get_type (void);
+
+/* Public API */
+
+/**
+ * @brief Set a pinning manager instead of the default one.
+ *
+ * The pinning manager will be used during the SSL handshake to check certificate
+ * and pinning parameters.
+ *
+ * @param ssl_socket SSL Socket to operate on.
+ * @param callback function that will take the control while validating pinning
+ *
+ */
+void thrift_ssl_socket_set_manager(ThriftSSLSocket *ssl_socket, AUTHORIZATION_MANAGER_CALLBACK callback);
+
+/* This is the SSL API */
+/**
+ * Convenience function to create a new SSL context with the protocol specified
+ * and assign this new context to the created ThriftSSLSocket with specified host:port.
+ * @param ssl_protocol
+ * @param hostname
+ * @param port
+ * @param error
+ * @return
+ */
+ThriftSSLSocket*
+thrift_ssl_socket_new_with_host(ThriftSSLSocketProtocol ssl_protocol, gchar *hostname, guint port, GError **error);
+
+/**
+ * Convenience function to create a new SSL context with the protocol specified
+ * and assign this new context to the created ThriftSSLSocket.
+ * @param ssl_protocol
+ * @param error
+ * @return
+ */
+ThriftSSLSocket*
+thrift_ssl_socket_new(ThriftSSLSocketProtocol ssl_protocol, GError **error);
+
+/**
+ * Load a certificate chain from a PEM file.
+ * @param ssl_socket The ssl socket
+ * @param file_name The file name of the PEM certificate chain
+ * @return
+ */
+gboolean
+thrift_ssl_load_cert_from_file(ThriftSSLSocket *ssl_socket, const char *file_name);
+
+/**
+ * Load a certificate chain from memory
+ * @param ssl_socket the ssl socket
+ * @param chain_certs the buffer to load PEM from
+ * @return
+ */
+gboolean
+thrift_ssl_load_cert_from_buffer(ThriftSSLSocket *ssl_socket, const char chain_certs[]);
+
+/**
+ * Check if the ssl socket is open and ready to send and receive
+ * @param transport
+ * @return true if open
+ */
+gboolean
+thrift_ssl_socket_is_open (ThriftTransport *transport);
+
+
+/**
+ * Open connection if required and set the socket to be ready to send and receive
+ * @param transport
+ * @param error
+ * @return true if operation was correct
+ */
+gboolean
+thrift_ssl_socket_open (ThriftTransport *transport, GError **error);
+
+
+/**
+ * @brief Initialization function
+ *
+ * It will initialize OpenSSL function. This initialization will be done app
+ * wide. So if you want to initialize it by yourself you should not call it.
+ * But it means you must handle OpenSSL initialization and handle locking.
+ *
+ * It should be called before anything else.
+ *
+ *
+ */
+void
+thrift_ssl_socket_initialize_openssl(void);
+/**
+ * @brief Finalization function
+ *
+ * It clears all resources initialized in initialize function.
+ *
+ * It should be called after anything else.
+ *
+ *
+ */
+void
+thrift_ssl_socket_finalize_openssl(void);
+
+G_END_DECLS
+#endif
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c
index 59d464c..9dd2671 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c
@@ -32,6 +32,12 @@
 }
 
 gboolean
+thrift_transport_peek (ThriftTransport *transport, GError **error)
+{
+  return THRIFT_TRANSPORT_GET_CLASS (transport)->peek (transport, error);
+}
+
+gboolean
 thrift_transport_open (ThriftTransport *transport, GError **error)
 {
   return THRIFT_TRANSPORT_GET_CLASS (transport)->open (transport, error);
@@ -79,6 +85,50 @@
   return THRIFT_TRANSPORT_GET_CLASS (transport)->flush (transport, error);
 }
 
+gint32
+thrift_transport_read_all (ThriftTransport *transport, gpointer buf,
+                           guint32 len, GError **error)
+{
+  return THRIFT_TRANSPORT_GET_CLASS (transport)->read_all (transport, buf,
+                                                           len, error);
+}
+
+/* by default, peek returns true if and only if the transport is open */
+static gboolean
+thrift_transport_real_peek (ThriftTransport *transport, GError **error)
+{
+  THRIFT_UNUSED_VAR (error);
+
+  return THRIFT_TRANSPORT_GET_CLASS (transport)->is_open (transport);
+}
+
+static gint32
+thrift_transport_real_read_all (ThriftTransport *transport, gpointer buf,
+                                guint32 len, GError **error)
+{
+  ThriftTransportClass *ttc;
+  guint32 have;
+  gint32 ret;
+  gint8 *bytes;
+
+  THRIFT_UNUSED_VAR (error);
+
+  ttc = THRIFT_TRANSPORT_GET_CLASS (transport);
+  have = 0;
+  ret = 0;
+  bytes = (gint8*) buf;
+
+  while (have < len) {
+    if ((ret = ttc->read (transport, (gpointer) (bytes + have), len - have,
+                          error)) < 0) {
+      return ret;
+    }
+    have += ret;
+  }
+
+  return have;
+}
+
 /* define the GError domain for Thrift transports */
 GQuark
 thrift_transport_error_quark (void)
@@ -99,6 +149,10 @@
   cls->write = thrift_transport_write;
   cls->write_end = thrift_transport_write_end;
   cls->flush = thrift_transport_flush;
+
+  /* provide a default implementation for the peek and read_all methods */
+  cls->peek = thrift_transport_real_peek;
+  cls->read_all = thrift_transport_real_read_all;
 }
 
 static void
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.h
index 20f6cd4..94bb6f5 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.h
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.h
@@ -63,6 +63,7 @@
 
   /* vtable */
   gboolean (*is_open) (ThriftTransport *transport);
+  gboolean (*peek) (ThriftTransport *transport, GError **error);
   gboolean (*open) (ThriftTransport *transport, GError **error);
   gboolean (*close) (ThriftTransport *transport, GError **error);
   gint32 (*read) (ThriftTransport *transport, gpointer buf,
@@ -72,6 +73,8 @@
                    const guint32 len, GError **error);
   gboolean (*write_end) (ThriftTransport *transport, GError **error);
   gboolean (*flush) (ThriftTransport *transport, GError **error);
+  gint32 (*read_all) (ThriftTransport *transport, gpointer buf,
+                      guint32 len, GError **error);
 };
 
 /* used by THRIFT_TYPE_TRANSPORT */
@@ -92,6 +95,17 @@
 gboolean thrift_transport_open (ThriftTransport *transport, GError **error);
 
 /*!
+ * Tests whether there is more data to read or if the remote side is still
+ * open. By default this is true whenever the transport is open, but
+ * implementations should add logic to test for this condition where possible
+ * (i.e. on a socket).
+ *
+ * This is used by a server to check if it should listen for another request.
+ * \public \memberof ThriftTransportInterface
+ */
+gboolean thrift_transport_peek (ThriftTransport *transport, GError **error);
+
+/*!
  * Close the transport.
  * \public \memberof ThriftTransportInterface
  */
@@ -131,6 +145,13 @@
  */
 gboolean thrift_transport_flush (ThriftTransport *transport, GError **error);
 
+/*!
+ * Read len bytes of data into the buffer buf.
+ * \public \memberof ThriftTransportInterface
+ */
+gint32 thrift_transport_read_all (ThriftTransport *transport, gpointer buf,
+                                  guint32 len, GError **error);
+
 /* define error/exception types */
 typedef enum
 {
@@ -147,6 +168,9 @@
 GQuark thrift_transport_error_quark (void);
 #define THRIFT_TRANSPORT_ERROR (thrift_transport_error_quark ())
 
+/* define macro for invalid socket */
+#define THRIFT_INVALID_SOCKET (-1)
+
 G_END_DECLS
 
 #endif /* _THRIFT_TRANSPORT_H */
diff --git a/lib/c_glib/test/CMakeLists.txt b/lib/c_glib/test/CMakeLists.txt
new file mode 100644
index 0000000..fb3e41c
--- /dev/null
+++ b/lib/c_glib/test/CMakeLists.txt
@@ -0,0 +1,202 @@
+#
+# 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.
+#
+
+
+set(TEST_PREFIX "c_glib")
+
+include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
+
+#Make sure gen-cpp and gen-c_glib files can be included
+include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+
+# Create the thrift C test library
+set(testgenc_SOURCES
+    gen-c_glib/t_test_debug_proto_test_types.c
+    gen-c_glib/t_test_enum_test_types.c
+    gen-c_glib/t_test_enum_test_service.c
+    gen-c_glib/t_test_empty_service.c
+    gen-c_glib/t_test_inherited.c
+    gen-c_glib/t_test_optional_required_test_types.c
+    gen-c_glib/t_test_reverse_order_service.c
+    gen-c_glib/t_test_second_service.c
+    gen-c_glib/t_test_service_for_exception_with_a_map.c
+    gen-c_glib/t_test_srv.c
+    gen-c_glib/t_test_thrift_test.c
+    gen-c_glib/t_test_thrift_test_types.c
+    gen-c_glib/t_test_debug_proto_test_types.h
+    gen-c_glib/t_test_enum_test_types.h
+    gen-c_glib/t_test_enum_test_service.h
+    gen-c_glib/t_test_empty_service.h
+    gen-c_glib/t_test_inherited.h
+    gen-c_glib/t_test_optional_required_test_types.h
+    gen-c_glib/t_test_reverse_order_service.h
+    gen-c_glib/t_test_second_service.h
+    gen-c_glib/t_test_service_for_exception_with_a_map.h
+    gen-c_glib/t_test_srv.h
+    gen-c_glib/t_test_thrift_test.h
+    gen-c_glib/t_test_thrift_test_types.h
+)
+
+add_library(testgenc STATIC ${testgenc_SOURCES})
+LINK_AGAINST_THRIFT_LIBRARY(testgenc thrift_c_glib)
+
+
+add_executable(testserialization testserialization.c)
+target_link_libraries(testserialization testgenc)
+LINK_AGAINST_THRIFT_LIBRARY(testserialization thrift_c_glib)
+add_test(NAME testserialization COMMAND testserialization)
+
+add_executable(testapplicationexception testapplicationexception.c)
+LINK_AGAINST_THRIFT_LIBRARY(testapplicationexception thrift_c_glib)
+add_test(NAME testapplicationexception COMMAND testapplicationexception)
+
+add_executable(testtransportsocket testtransportsocket.c)
+LINK_AGAINST_THRIFT_LIBRARY(testtransportsocket thrift_c_glib)
+add_test(NAME testtransportsocket COMMAND testtransportsocket)
+
+add_executable(testbinaryprotocol testbinaryprotocol.c)
+LINK_AGAINST_THRIFT_LIBRARY(testbinaryprotocol thrift_c_glib)
+add_test(NAME testbinaryprotocol COMMAND testbinaryprotocol)
+
+add_executable(testcompactprotocol testcompactprotocol.c)
+LINK_AGAINST_THRIFT_LIBRARY(testcompactprotocol thrift_c_glib)
+add_test(NAME testcompactprotocol COMMAND testcompactprotocol)
+
+add_executable(testbufferedtransport testbufferedtransport.c)
+LINK_AGAINST_THRIFT_LIBRARY(testbufferedtransport thrift_c_glib)
+add_test(NAME testbufferedtransport COMMAND testbufferedtransport)
+
+add_executable(testframedtransport testframedtransport.c)
+LINK_AGAINST_THRIFT_LIBRARY(testframedtransport thrift_c_glib)
+add_test(NAME testframedtransport COMMAND testframedtransport)
+
+add_executable(testfdtransport testfdtransport.c)
+LINK_AGAINST_THRIFT_LIBRARY(testfdtransport thrift_c_glib)
+add_test(NAME testfdtransport COMMAND testfdtransport)
+
+add_executable(testmemorybuffer testmemorybuffer.c)
+LINK_AGAINST_THRIFT_LIBRARY(testmemorybuffer thrift_c_glib)
+add_test(NAME testmemorybuffer COMMAND testmemorybuffer)
+
+add_executable(testsimpleserver testsimpleserver.c)
+LINK_AGAINST_THRIFT_LIBRARY(testsimpleserver thrift_c_glib)
+add_test(NAME testsimpleserver COMMAND testsimpleserver)
+
+add_executable(testdebugproto testdebugproto.c)
+target_link_libraries(testdebugproto testgenc)
+add_test(NAME testdebugproto COMMAND testdebugproto)
+
+add_executable(testoptionalrequired testoptionalrequired.c)
+target_link_libraries(testoptionalrequired testgenc)
+add_test(NAME testoptionalrequired COMMAND testoptionalrequired)
+
+include_directories("${PROJECT_SOURCE_DIR}/test/c_glib/src" "${CMAKE_CURRENT_BINARY_DIR}/gen-c_glib")
+
+add_executable(testthrifttest testthrifttest.c
+    ${PROJECT_SOURCE_DIR}/test/c_glib/src/thrift_test_handler.c
+    ${PROJECT_SOURCE_DIR}/test/c_glib/src/thrift_test_handler.h
+    ${PROJECT_SOURCE_DIR}/test/c_glib/src/thrift_second_service_handler.c
+    ${PROJECT_SOURCE_DIR}/test/c_glib/src/thrift_second_service_handler.h
+    gen-c_glib/t_test_thrift_test_types.h)
+target_link_libraries(testthrifttest testgenc)
+add_test(NAME testthrifttest COMMAND testthrifttest)
+
+
+if(BUILD_CPP)
+
+    include_directories("${PROJECT_SOURCE_DIR}/lib/cpp/src")
+
+    # Create the thrift C++ test library
+    set(testgenc_cpp_SOURCES
+        gen-cpp/ThriftTest.cpp
+        gen-cpp/ThriftTest_constants.cpp
+        gen-cpp/ThriftTest_types.cpp
+        gen-cpp/ThriftTest.h
+        gen-cpp/ThriftTest_constants.h
+        gen-cpp/ThriftTest_types.h
+    )
+
+    add_library(testgenc_cpp STATIC ${testgenc_cpp_SOURCES})
+    LINK_AGAINST_THRIFT_LIBRARY(testgenc_cpp thrift)
+
+    #HACK: testthrifttestclient.cpp includes ThriftTest.h without gen-*/ prefixes
+    # so we include it here
+    include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen-cpp" "${CMAKE_CURRENT_BINARY_DIR}/gen-c_glib")
+
+    add_executable(testthrifttestclient testthrifttestclient.cpp)
+    target_link_libraries(testthrifttestclient testgenc testgenc_cpp ${ZLIB_LIBRARIES})
+    add_test(NAME testthrifttestclient COMMAND testthrifttestclient)
+
+endif(BUILD_CPP)
+
+#
+# Common thrift code generation rules
+#
+
+add_custom_command(OUTPUT
+    gen-c_glib/t_test_debug_proto_test_types.c
+    gen-c_glib/t_test_debug_proto_test_types.h
+    gen-c_glib/t_test_empty_service.c
+    gen-c_glib/t_test_empty_service.h
+    gen-c_glib/t_test_inherited.c
+    gen-c_glib/t_test_inherited.h
+    gen-c_glib/t_test_reverse_order_service.c
+    gen-c_glib/t_test_reverse_order_service.h
+    gen-c_glib/t_test_service_for_exception_with_a_map.c
+    gen-c_glib/t_test_service_for_exception_with_a_map.h
+    gen-c_glib/t_test_srv.c
+    gen-c_glib/t_test_srv.h
+    COMMAND ${THRIFT_COMPILER} --gen c_glib ${PROJECT_SOURCE_DIR}/test/DebugProtoTest.thrift
+)
+
+add_custom_command(OUTPUT
+    gen-c_glib/t_test_enum_test_types.c
+    gen-c_glib/t_test_enum_test_types.h
+    gen-c_glib/t_test_enum_test_service.c
+    gen-c_glib/t_test_enum_test_service.h
+    COMMAND ${THRIFT_COMPILER} --gen c_glib ${PROJECT_SOURCE_DIR}/test/EnumTest.thrift
+)
+
+add_custom_command(OUTPUT
+    gen-c_glib/t_test_optional_required_test_types.c
+    gen-c_glib/t_test_optional_required_test_types.h
+    COMMAND ${THRIFT_COMPILER} --gen c_glib ${PROJECT_SOURCE_DIR}/test/OptionalRequiredTest.thrift
+)
+
+add_custom_command(OUTPUT
+    gen-c_glib/t_test_second_service.c
+    gen-c_glib/t_test_thrift_test.c
+    gen-c_glib/t_test_thrift_test_types.c
+    gen-c_glib/t_test_second_service.h
+    gen-c_glib/t_test_thrift_test.h
+    gen-c_glib/t_test_thrift_test_types.h
+    COMMAND ${THRIFT_COMPILER} --gen c_glib ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
+)
+
+add_custom_command(OUTPUT
+    gen-cpp/ThriftTest.cpp
+    gen-cpp/ThriftTest_constants.cpp
+    gen-cpp/ThriftTest_types.cpp
+    gen-cpp/ThriftTest.h
+    gen-cpp/ThriftTest_constants.h
+    gen-cpp/ThriftTest_types.h
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
+)
+
+# TODO: Add memory checks using ctest_memcheck or similar
diff --git a/lib/c_glib/test/ContainerTest.thrift b/lib/c_glib/test/ContainerTest.thrift
new file mode 100644
index 0000000..a92a9a5
--- /dev/null
+++ b/lib/c_glib/test/ContainerTest.thrift
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+namespace c_glib TTest
+
+typedef list<string> StringList
+typedef list<StringList> ListStringList
+
+struct ContainersWithDefaultValues {
+  1: list<string> StringList = [ "Apache", "Thrift" ];
+}
+
+service ContainerService {
+  void receiveStringList(1: list<string> stringList);
+  list<string> returnStringList();
+
+  list<list<string>> returnListStringList();
+  ListStringList returnTypedefdListStringList();
+}
diff --git a/lib/c_glib/test/Makefile.am b/lib/c_glib/test/Makefile.am
index 7fed8e8..5e9d2ea 100755
--- a/lib/c_glib/test/Makefile.am
+++ b/lib/c_glib/test/Makefile.am
@@ -16,20 +16,43 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-.NOTPARALLEL:
+AUTOMAKE_OPTIONS = subdir-objects serial-tests
+
 SUBDIRS =
 
-AM_CPPFLAGS = -g -Wall -I../src $(GLIB_CFLAGS)
-AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) @GCOV_LDFLAGS@
+BUILT_SOURCES = \
+        gen-c_glib/t_test_container_test_types.c \
+        gen-c_glib/t_test_container_test_types.h \
+        gen-c_glib/t_test_debug_proto_test_types.h \
+        gen-c_glib/t_test_empty_service.h \
+        gen-c_glib/t_test_inherited.h \
+        gen-c_glib/t_test_optional_required_test_types.h \
+        gen-c_glib/t_test_reverse_order_service.h \
+        gen-c_glib/t_test_second_service.h \
+        gen-c_glib/t_test_service_for_exception_with_a_map.h \
+        gen-c_glib/t_test_container_service.c \
+        gen-c_glib/t_test_container_service.h \
+        gen-c_glib/t_test_srv.h \
+        gen-c_glib/t_test_thrift_test.h \
+        gen-c_glib/t_test_thrift_test_types.h
 
-CFLAGS = @GCOV_CFLAGS@
-CXXFLAGS = -g
+AM_CPPFLAGS = -I../src -I./gen-c_glib
+AM_CFLAGS = -g -Wall -Wextra -pedantic $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(OPENSSL_INCLUDES) \
+	@GCOV_CFLAGS@
+AM_CXXFLAGS = $(AM_CFLAGS)
+AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) $(OPENSSL_LIBS) @GCOV_LDFLAGS@
 
 check_PROGRAMS = \
+  testserialization \
+  testapplicationexception \
+  testcontainertest \
   testtransportsocket \
+  testtransportsslsocket \
   testbinaryprotocol \
+  testcompactprotocol \
   testbufferedtransport \
   testframedtransport \
+  testfdtransport \
   testmemorybuffer \
   teststruct \
   testsimpleserver \
@@ -38,71 +61,129 @@
   testthrifttest
 
 if WITH_CPP
+  BUILT_SOURCES += gen-cpp/ThriftTest_types.cpp
   check_PROGRAMS += testthrifttestclient
 endif
 
+testserialization_SOURCES = testserialization.c
+testserialization_LDADD = \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+    libtestgenc.la
+
+testapplicationexception_SOURCES = testapplicationexception.c
+testapplicationexception_LDADD = \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/libthrift_c_glib_la-thrift_application_exception.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/libthrift_c_glib_la-thrift_struct.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o
+
+testcontainertest_SOURCES = testcontainertest.c
+testcontainertest_LDADD = \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/libthrift_c_glib_la-thrift_struct.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport_factory.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/processor/libthrift_c_glib_la-thrift_processor.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol_factory.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_binary_protocol.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_binary_protocol_factory.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_socket.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_socket.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/server/libthrift_c_glib_la-thrift_server.o \
+	  libtestgenc.la
+
 testtransportsocket_SOURCES = testtransportsocket.c
 testtransportsocket_LDADD = \
-    ../libthrift_c_glib_la-thrift_transport.o \
-    ../libthrift_c_glib_la-thrift_server_transport.o \
-    ../libthrift_c_glib_la-thrift_server_socket.o
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_buffered_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_socket.o
+
+
+testtransportsslsocket_SOURCES = testtransportsslsocket.c
+testtransportsslsocket_LDADD = \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_socket.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_buffered_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_socket.o
+
 
 testbinaryprotocol_SOURCES = testbinaryprotocol.c
 testbinaryprotocol_LDADD = \
-    ../libthrift_c_glib_la-thrift_protocol.o \
-    ../libthrift_c_glib_la-thrift_transport.o \
-    ../libthrift_c_glib_la-thrift_socket.o \
-    ../libthrift_c_glib_la-thrift_server_transport.o \
-    ../libthrift_c_glib_la-thrift_server_socket.o
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_framed_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_socket.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_socket.o
+
+testcompactprotocol_SOURCES = testcompactprotocol.c
+testcompactprotocol_LDADD = \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_framed_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_socket.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_socket.o
 
 testbufferedtransport_SOURCES = testbufferedtransport.c
 testbufferedtransport_LDADD = \
-    ../libthrift_c_glib_la-thrift_transport.o \
-    ../libthrift_c_glib_la-thrift_socket.o \
-    ../libthrift_c_glib_la-thrift_server_transport.o \
-    ../libthrift_c_glib_la-thrift_server_socket.o
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_socket.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_socket.o
 
 testframedtransport_SOURCES = testframedtransport.c
 testframedtransport_LDADD = \
-    ../libthrift_c_glib_la-thrift_transport.o \
-    ../libthrift_c_glib_la-thrift_socket.o \
-    ../libthrift_c_glib_la-thrift_server_transport.o \
-    ../libthrift_c_glib_la-thrift_server_socket.o
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_socket.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_socket.o
+
+testfdtransport_SOURCES = testfdtransport.c
+testfdtransport_LDADD = \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_fd_transport.o
 
 testmemorybuffer_SOURCES = testmemorybuffer.c
 testmemorybuffer_LDADD = \
-    ../libthrift_c_glib_la-thrift_transport.o
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o
 
 teststruct_SOURCES = teststruct.c
 teststruct_LDADD = \
-    ../libthrift_c_glib_la-thrift_protocol.o \
-    ../libthrift_c_glib_la-thrift_transport.o
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o
 
 testsimpleserver_SOURCES = testsimpleserver.c
 testsimpleserver_LDADD = \
-    ../libthrift_c_glib_la-thrift_protocol.o \
-    ../libthrift_c_glib_la-thrift_transport.o \
-    ../libthrift_c_glib_la-thrift_transport_factory.o \
-    ../libthrift_c_glib_la-thrift_processor.o \
-    ../libthrift_c_glib_la-thrift_protocol_factory.o \
-    ../libthrift_c_glib_la-thrift_binary_protocol.o \
-    ../libthrift_c_glib_la-thrift_binary_protocol_factory.o \
-    ../libthrift_c_glib_la-thrift_socket.o \
-    ../libthrift_c_glib_la-thrift_server_transport.o \
-    ../libthrift_c_glib_la-thrift_server_socket.o \
-    ../libthrift_c_glib_la-thrift_server.o
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport_factory.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/processor/libthrift_c_glib_la-thrift_processor.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol_factory.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_binary_protocol.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_binary_protocol_factory.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_socket.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_socket.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/server/libthrift_c_glib_la-thrift_server.o
 
 testdebugproto_SOURCES = testdebugproto.c
 testdebugproto_LDADD = libtestgenc.la
 
 testoptionalrequired_SOURCES = testoptionalrequired.c
 testoptionalrequired_LDADD = \
-    ../libthrift_c_glib_la-thrift_protocol.o \
-    ../libthrift_c_glib_la-thrift_transport.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol.o \
+    $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
     libtestgenc.la
 
 testthrifttest_SOURCES = testthrifttest.c
-testthrifttest_LDADD = libtestgenc.la
+testthrifttest_LDADD = libtestgenc.la \
+    $(top_builddir)/test/c_glib/src/thrift_test_handler.o
+testthrifttest_CFLAGS = -I$(top_srcdir)/test/c_glib/src -I./gen-c_glib $(GLIB_CFLAGS)
 
 testthrifttestclient_SOURCES = testthrifttestclient.cpp
 testthrifttestclient_CPPFLAGS = -I../../cpp/src $(BOOST_CPPFLAGS) -I./gen-cpp -I../src -I./gen-c_glib $(GLIB_CFLAGS)
@@ -116,7 +197,10 @@
 endif
 
 nodist_libtestgenc_la_SOURCES = \
+        gen-c_glib/t_test_container_test_types.c \
         gen-c_glib/t_test_debug_proto_test_types.c \
+        gen-c_glib/t_test_enum_test_types.c \
+        gen-c_glib/t_test_enum_test_service.c \
         gen-c_glib/t_test_empty_service.c \
         gen-c_glib/t_test_inherited.c \
         gen-c_glib/t_test_optional_required_test_types.c \
@@ -124,9 +208,13 @@
         gen-c_glib/t_test_second_service.c \
         gen-c_glib/t_test_service_for_exception_with_a_map.c \
         gen-c_glib/t_test_srv.c \
+        gen-c_glib/t_test_container_service.c \
         gen-c_glib/t_test_thrift_test.c \
         gen-c_glib/t_test_thrift_test_types.c \
+        gen-c_glib/t_test_container_test_types.h \
         gen-c_glib/t_test_debug_proto_test_types.h \
+        gen-c_glib/t_test_enum_test_types.h \
+        gen-c_glib/t_test_enum_test_service.h \
         gen-c_glib/t_test_empty_service.h \
         gen-c_glib/t_test_inherited.h \
         gen-c_glib/t_test_optional_required_test_types.h \
@@ -134,9 +222,11 @@
         gen-c_glib/t_test_second_service.h \
         gen-c_glib/t_test_service_for_exception_with_a_map.h \
         gen-c_glib/t_test_srv.h \
+        gen-c_glib/t_test_container_service.h \
         gen-c_glib/t_test_thrift_test.h \
         gen-c_glib/t_test_thrift_test_types.h
 libtestgenc_la_LIBADD = $(top_builddir)/lib/c_glib/libthrift_c_glib.la
+libtestgenc_la_CPPFLAGS = $(AM_CPPFLAGS) -Wno-unused-function
 
 nodist_libtestgencpp_la_SOURCES = \
         gen-cpp/ThriftTest.cpp \
@@ -147,18 +237,22 @@
         gen-cpp/ThriftTest_types.h
 libtestgencpp_la_CPPFLAGS = -I../../cpp/src $(BOOST_CPPFLAGS) -I./gen-cpp
 
-THRIFT = $(top_builddir)/compiler/cpp/thrift
-
-gen-c_glib/t_test_debug_proto_test_types.c gen-c_glib/t_test_debug_proto_test_types.h gen-c_glib/t_test_empty_service.c gen-c_glib/t_test_empty_service.h gen-c_glib/t_test_inherited.c gen-c_glib/t_test_inherited.h gen-c_glib/t_test_reverse_order_service.c gen-c_glib/t_test_reverse_order_service.h gen-c_glib/t_test_service_for_exception_with_a_map.c gen-c_glib/t_test_service_for_exception_with_a_map.h gen-c_glib/t_test_srv.c gen-c_glib/t_test_srv.h: ../../../test/DebugProtoTest.thrift
+gen-c_glib/t_test_container_test_types.c gen-c_glib/t_test_container_test_types.h gen-c_glib/t_test_container_service.c gen-c_glib/t_test_container_service.h: ContainerTest.thrift $(THRIFT)
 	$(THRIFT) --gen c_glib $<
 
-gen-c_glib/t_test_optional_required_test_types.c gen-c_glib/t_test_optional_required_test_types.h: ../../../test/OptionalRequiredTest.thrift
+gen-c_glib/t_test_debug_proto_test_types.c gen-c_glib/t_test_debug_proto_test_types.h gen-c_glib/t_test_empty_service.c gen-c_glib/t_test_empty_service.h gen-c_glib/t_test_inherited.c gen-c_glib/t_test_inherited.h gen-c_glib/t_test_reverse_order_service.c gen-c_glib/t_test_reverse_order_service.h gen-c_glib/t_test_service_for_exception_with_a_map.c gen-c_glib/t_test_service_for_exception_with_a_map.h gen-c_glib/t_test_srv.c gen-c_glib/t_test_srv.h: ../../../test/DebugProtoTest.thrift $(THRIFT)
 	$(THRIFT) --gen c_glib $<
 
-gen-c_glib/t_test_second_service.c gen-c_glib/t_test_thrift_test.c gen-c_glib/t_test_thrift_test_types.c gen-c_glib/t_test_second_service.h gen-c_glib/t_test_thrift_test-.h gen-c_glib/t_test_thrift_test_types.h: ../../../test/ThriftTest.thrift
+gen-c_glib/t_test_enum_test_types.c gen-c_glib/t_test_enum_test_types.h gen-c_glib/t_test_enum_test_service.c gen-c_glib/t_test_enum_test_service.h : ../../../test/EnumTest.thrift $(THRIFT)
 	$(THRIFT) --gen c_glib $<
 
-gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest.h: ../../../test/ThriftTest.thrift
+gen-c_glib/t_test_optional_required_test_types.c gen-c_glib/t_test_optional_required_test_types.h: ../../../test/OptionalRequiredTest.thrift $(THRIFT)
+	$(THRIFT) --gen c_glib $<
+
+gen-c_glib/t_test_second_service.c gen-c_glib/t_test_thrift_test.c gen-c_glib/t_test_thrift_test_types.c gen-c_glib/t_test_second_service.h gen-c_glib/t_test_thrift_test.h gen-c_glib/t_test_thrift_test_types.h: ../../../test/ThriftTest.thrift $(THRIFT)
+	$(THRIFT) --gen c_glib $<
+
+gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest_types.cpp: ../../../test/ThriftTest.thrift $(THRIFT)
 	$(THRIFT) --gen cpp $<
 
 TESTS = \
@@ -214,7 +308,7 @@
 	    ${$<_VALGRIND_LEAK_OPTS}  ./$<
 
 clean-local:
-	$(RM) -r gen-c_glib gen-cpp
+	$(RM) gen-c_glib/* gen-cpp/*
 
 CLEANFILES =                            \
     *.bb                                \
@@ -223,3 +317,8 @@
     *.gcno                              \
     *.gcda                              \
     *.gcov
+
+EXTRA_DIST = \
+             CMakeLists.txt \
+             ContainerTest.thrift
+
diff --git a/lib/c_glib/test/testapplicationexception.c b/lib/c_glib/test/testapplicationexception.c
new file mode 100644
index 0000000..89e39e2
--- /dev/null
+++ b/lib/c_glib/test/testapplicationexception.c
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+#include <glib.h>
+#include <string.h>
+
+#include <thrift/c_glib/thrift_application_exception.h>
+
+static void
+test_create_and_destroy (void)
+{
+  GObject *object = NULL;
+
+  /* A ThriftApplicationException can be created... */
+  object = g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION, NULL);
+
+  g_assert (object != NULL);
+  g_assert (THRIFT_IS_APPLICATION_EXCEPTION (object));
+
+  /* ...and destroyed */
+  g_object_unref (object);
+}
+
+static void
+test_initialize (void)
+{
+  ThriftApplicationException *xception = NULL;
+  gint32 type = THRIFT_APPLICATION_EXCEPTION_ERROR_INTERNAL_ERROR;
+  gchar *message = "Exception message";
+  gint32 retrieved_type = 0;
+  gchar *retrieved_message = NULL;
+
+  /* A ThriftApplicationException has "type" and "message" properties that can
+     be initialized at object creation */
+  xception =
+    g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION,
+                  "type",    type,
+                  "message", message,
+                  NULL);
+
+  g_assert (xception != NULL);
+
+  /* A ThriftApplicationException's properties can be retrieved */
+  g_object_get (xception,
+                "type",    &retrieved_type,
+                "message", &retrieved_message,
+                NULL);
+
+  g_assert (retrieved_type == type);
+  g_assert (retrieved_message != NULL);
+  g_assert_cmpstr (retrieved_message, ==, message);
+
+  g_free (retrieved_message);
+  g_object_unref (xception);
+}
+
+static void
+test_properties_test (void)
+{
+  ThriftApplicationException *xception = NULL;
+  gint32 retrieved_type;
+
+  xception = g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION, NULL);
+
+#define TEST_TYPE_VALUE(_type)                                  \
+  retrieved_type = -1;                                          \
+  g_object_set (xception, "type", _type, NULL);                 \
+  g_object_get (xception, "type", &retrieved_type, NULL);       \
+  g_assert_cmpint (retrieved_type, ==, _type);
+
+  /* The "type" property can be set to any valid Thrift exception type */
+  TEST_TYPE_VALUE (THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN);
+  TEST_TYPE_VALUE (THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN_METHOD);
+  TEST_TYPE_VALUE (THRIFT_APPLICATION_EXCEPTION_ERROR_INVALID_MESSAGE_TYPE);
+  TEST_TYPE_VALUE (THRIFT_APPLICATION_EXCEPTION_ERROR_WRONG_METHOD_NAME);
+  TEST_TYPE_VALUE (THRIFT_APPLICATION_EXCEPTION_ERROR_BAD_SEQUENCE_ID);
+  TEST_TYPE_VALUE (THRIFT_APPLICATION_EXCEPTION_ERROR_MISSING_RESULT);
+  TEST_TYPE_VALUE (THRIFT_APPLICATION_EXCEPTION_ERROR_INTERNAL_ERROR);
+  TEST_TYPE_VALUE (THRIFT_APPLICATION_EXCEPTION_ERROR_PROTOCOL_ERROR);
+  TEST_TYPE_VALUE (THRIFT_APPLICATION_EXCEPTION_ERROR_INVALID_TRANSFORM);
+  TEST_TYPE_VALUE (THRIFT_APPLICATION_EXCEPTION_ERROR_INVALID_PROTOCOL);
+  TEST_TYPE_VALUE (THRIFT_APPLICATION_EXCEPTION_ERROR_UNSUPPORTED_CLIENT_TYPE);
+
+/* "g_test_expect_message" is required for the property range tests below but is
+   not present in GLib before version 2.34 */
+#if (GLIB_CHECK_VERSION (2, 34, 0))
+  g_object_set (xception,
+                "type", THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN,
+                NULL);
+
+  /* The "type" property cannot be set to a value too low (less than zero) */
+  g_test_expect_message ("GLib-GObject",
+                         G_LOG_LEVEL_WARNING,
+                         "value*out of range*type*");
+  g_object_set (xception, "type", -1, NULL);
+  g_test_assert_expected_messages ();
+
+  g_object_get (xception, "type", &retrieved_type, NULL);
+  g_assert_cmpint (retrieved_type, !=, -1);
+  g_assert_cmpint (retrieved_type,
+                   ==,
+                   THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN);
+
+  /* The "type" property cannot be set to a value too high (greater than the
+     highest defined exception-type value) */
+  g_test_expect_message ("GLib-GObject",
+                         G_LOG_LEVEL_WARNING,
+                         "value*out of range*type*");
+  g_object_set (xception, "type", THRIFT_APPLICATION_EXCEPTION_ERROR_N, NULL);
+  g_test_assert_expected_messages ();
+
+  g_object_get (xception, "type", &retrieved_type, NULL);
+  g_assert_cmpint (retrieved_type, !=, THRIFT_APPLICATION_EXCEPTION_ERROR_N);
+  g_assert_cmpint (retrieved_type,
+                   ==,
+                   THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN);
+#endif
+
+  g_object_unref (xception);
+}
+
+static void
+test_properties_message (void)
+{
+  ThriftApplicationException *xception = NULL;
+  gchar *message = "Exception message";
+  gchar *retrieved_message;
+
+  xception = g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION, NULL);
+
+  /* The "message" property can be set to NULL */
+  g_object_set (xception, "message", NULL, NULL);
+  g_object_get (xception, "message", &retrieved_message, NULL);
+  g_assert (retrieved_message == NULL);
+
+  /* The "message" property can be set to a valid string */
+  g_object_set (xception, "message", message, NULL);
+  g_object_get (xception, "message", &retrieved_message, NULL);
+  g_assert_cmpint (strcmp (retrieved_message, message), ==, 0);
+
+  g_free (retrieved_message);
+  g_object_unref (xception);
+}
+
+int
+main (int argc, char **argv)
+{
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init ();
+#endif
+
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/testapplicationexception/CreateAndDestroy",
+    test_create_and_destroy);
+  g_test_add_func ("/testapplicationexception/Initialize",
+    test_initialize);
+  g_test_add_func ("/testapplicationexception/Properties/test",
+    test_properties_test);
+  g_test_add_func ("/testapplicationexception/Properties/message",
+    test_properties_message);
+
+  return g_test_run ();
+}
diff --git a/lib/c_glib/test/testbinaryprotocol.c b/lib/c_glib/test/testbinaryprotocol.c
index f75c796..14f4fb0 100755
--- a/lib/c_glib/test/testbinaryprotocol.c
+++ b/lib/c_glib/test/testbinaryprotocol.c
@@ -17,22 +17,31 @@
  * under the License.
  */
 
+/* Disable string-function optimizations when glibc is used, as these produce
+   compiler warnings about string length when a string function is used inside
+   a call to g_assert () */
+#ifdef __GLIBC__
+#include <features.h>
+#define __NO_STRING_INLINES 1
+#endif
+
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
-#include <assert.h>
 #include <netdb.h>
 #include <string.h>
+#include <sys/wait.h>
 
 #include <thrift/c_glib/protocol/thrift_protocol.h>
 #include <thrift/c_glib/transport/thrift_socket.h>
 #include <thrift/c_glib/transport/thrift_server_socket.h>
+#include <thrift/c_glib/transport/thrift_framed_transport.h>
 
 #define TEST_BOOL TRUE
 #define TEST_BYTE 123
 #define TEST_I16 12345
 #define TEST_I32 1234567890
-#define TEST_I64 123456789012345LL
+#define TEST_I64 G_GINT64_CONSTANT (123456789012345)
 #define TEST_DOUBLE 1234567890.123
 #define TEST_STRING "this is a test string 1234567890!@#$%^&*()"
 #define TEST_PORT 51199
@@ -41,14 +50,14 @@
 static int transport_read_error = 0;
 static int transport_read_error_at = -1;
 gint32
-my_thrift_transport_read (ThriftTransport *transport, gpointer buf,
-                          guint32 len, GError **error)
+my_thrift_transport_read_all (ThriftTransport *transport, gpointer buf,
+                              guint32 len, GError **error)
 {
   if (transport_read_count != transport_read_error_at
       && transport_read_error == 0)
   {
     transport_read_count++;
-    return thrift_transport_read (transport, buf, len, error);
+    return thrift_transport_read_all (transport, buf, len, error);
   }
   return -1;
 }
@@ -69,14 +78,15 @@
   return FALSE;
 }
 
-#define thrift_transport_read my_thrift_transport_read
+#define thrift_transport_read_all my_thrift_transport_read_all
 #define thrift_transport_write my_thrift_transport_write
 #include "../src/thrift/c_glib/protocol/thrift_binary_protocol.c"
-#undef thrift_transport_read
+#undef thrift_transport_read_all
 #undef thrift_transport_write
 
 static void thrift_server_primitives (const int port);
 static void thrift_server_complex_types (const int port);
+static void thrift_server_many_frames (const int port);
 
 static void
 test_create_and_destroy(void)
@@ -85,7 +95,7 @@
 
   /* create an object and then destroy it */
   object = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, NULL);
-  assert (object != NULL);
+  g_assert (object != NULL);
   g_object_unref (object);
 }
 
@@ -99,11 +109,11 @@
   /* create a ThriftTransport */
   tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
                           "port", 51188, NULL);
-  assert (tsocket != NULL);
+  g_assert (tsocket != NULL);
   /* create a ThriftBinaryProtocol using the Transport */
   protocol = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
                            tsocket, NULL);
-  assert (protocol != NULL);
+  g_assert (protocol != NULL);
   /* fetch the properties */
   g_object_get (G_OBJECT(protocol), "transport", &temp, NULL);
   g_object_unref (temp);
@@ -128,7 +138,7 @@
 
   /* fork a server from the client */
   pid = fork ();
-  assert (pid >= 0);
+  g_assert (pid >= 0);
 
   if (pid == 0)
   {
@@ -144,47 +154,48 @@
                             "port", port, NULL);
     transport = THRIFT_TRANSPORT (tsocket);
     thrift_transport_open (transport, NULL);
-    assert (thrift_transport_is_open (transport));
+    g_assert (thrift_transport_is_open (transport));
 
     /* create a ThriftBinaryTransport */
     tb = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
                        tsocket, NULL);
     protocol = THRIFT_PROTOCOL (tb);
-    assert (protocol != NULL);
+    g_assert (protocol != NULL);
 
     /* write a bunch of primitives */
-    assert (thrift_binary_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
-    assert (thrift_binary_protocol_write_byte (protocol, TEST_BYTE, NULL) > 0);
-    assert (thrift_binary_protocol_write_i16 (protocol, TEST_I16, NULL) > 0);
-    assert (thrift_binary_protocol_write_i32 (protocol, TEST_I32, NULL) > 0);
-    assert (thrift_binary_protocol_write_i64 (protocol, TEST_I64, NULL) > 0);
-    assert (thrift_binary_protocol_write_double (protocol, 
+    g_assert (thrift_binary_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+    g_assert (thrift_binary_protocol_write_byte (protocol, TEST_BYTE, NULL) > 0);
+    g_assert (thrift_binary_protocol_write_i16 (protocol, TEST_I16, NULL) > 0);
+    g_assert (thrift_binary_protocol_write_i32 (protocol, TEST_I32, NULL) > 0);
+    g_assert (thrift_binary_protocol_write_i64 (protocol, TEST_I64, NULL) > 0);
+    g_assert (thrift_binary_protocol_write_double (protocol, 
                                                  TEST_DOUBLE, NULL) > 0);
-    assert (thrift_binary_protocol_write_string (protocol,
+    g_assert (thrift_binary_protocol_write_string (protocol,
                                                  TEST_STRING, NULL) > 0);
-    assert (thrift_binary_protocol_write_binary (protocol, binary, 
+    g_assert (thrift_binary_protocol_write_string (protocol, "", NULL) > 0);
+    g_assert (thrift_binary_protocol_write_binary (protocol, binary, 
                                                  len, NULL) > 0);
-    assert (thrift_binary_protocol_write_binary (protocol, NULL, 0, NULL) > 0);
-    assert (thrift_binary_protocol_write_binary (protocol, binary,
+    g_assert (thrift_binary_protocol_write_binary (protocol, NULL, 0, NULL) > 0);
+    g_assert (thrift_binary_protocol_write_binary (protocol, binary,
                                                  len, NULL) > 0);
 
     /* test write errors */
     transport_write_error = 1;
-    assert (thrift_binary_protocol_write_byte (protocol, TEST_BYTE, 
+    g_assert (thrift_binary_protocol_write_byte (protocol, TEST_BYTE, 
                                                NULL) == -1);
-    assert (thrift_binary_protocol_write_i16 (protocol, TEST_I16, NULL) == -1);
-    assert (thrift_binary_protocol_write_i32 (protocol, TEST_I32, NULL) == -1);
-    assert (thrift_binary_protocol_write_i64 (protocol, TEST_I64, NULL) == -1);
-    assert (thrift_binary_protocol_write_double (protocol, TEST_DOUBLE,
+    g_assert (thrift_binary_protocol_write_i16 (protocol, TEST_I16, NULL) == -1);
+    g_assert (thrift_binary_protocol_write_i32 (protocol, TEST_I32, NULL) == -1);
+    g_assert (thrift_binary_protocol_write_i64 (protocol, TEST_I64, NULL) == -1);
+    g_assert (thrift_binary_protocol_write_double (protocol, TEST_DOUBLE,
                                                  NULL) == -1);
-    assert (thrift_binary_protocol_write_binary (protocol, binary, len,
+    g_assert (thrift_binary_protocol_write_binary (protocol, binary, len,
                                                  NULL) == -1);
     transport_write_error = 0;
 
     /* test binary partial failure */
     transport_write_count = 0;
     transport_write_error_at = 1;
-    assert (thrift_binary_protocol_write_binary (protocol, binary,
+    g_assert (thrift_binary_protocol_write_binary (protocol, binary,
                                                  len, NULL) == -1);
     transport_write_error_at = -1;
 
@@ -192,8 +203,8 @@
     thrift_transport_close (transport, NULL);
     g_object_unref (tsocket);
     g_object_unref (protocol);
-    assert (wait (&status) == pid);
-    assert (status == 0);
+    g_assert (wait (&status) == pid);
+    g_assert (status == 0);
   }
 }
 
@@ -210,7 +221,7 @@
 
   /* fork a server from the client */
   pid = fork ();
-  assert (pid >= 0);
+  g_assert (pid >= 0);
 
   if (pid == 0)
   {
@@ -226,33 +237,33 @@
                             "port", port, NULL);
     transport = THRIFT_TRANSPORT (tsocket);
     thrift_transport_open (transport, NULL);
-    assert (thrift_transport_is_open (transport));
+    g_assert (thrift_transport_is_open (transport));
 
     /* create a ThriftBinaryTransport */
     tb = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
                        tsocket, NULL);
     protocol = THRIFT_PROTOCOL (tb);
-    assert (protocol != NULL);
+    g_assert (protocol != NULL);
 
     /* test structures */
-    assert (thrift_binary_protocol_write_struct_begin (protocol, 
+    g_assert (thrift_binary_protocol_write_struct_begin (protocol, 
                                                        NULL, NULL) == 0);
-    assert (thrift_binary_protocol_write_struct_end (protocol, NULL) == 0);
+    g_assert (thrift_binary_protocol_write_struct_end (protocol, NULL) == 0);
 
-    assert (thrift_binary_protocol_write_field_begin (protocol, "test", T_VOID,
+    g_assert (thrift_binary_protocol_write_field_begin (protocol, "test", T_VOID,
                                                       1, NULL) > 0);
-    assert (thrift_binary_protocol_write_field_end (protocol, NULL) == 0);
+    g_assert (thrift_binary_protocol_write_field_end (protocol, NULL) == 0);
 
     /* test write error */
     transport_write_error = 1;
-    assert (thrift_binary_protocol_write_field_begin (protocol, "test", T_VOID, 
+    g_assert (thrift_binary_protocol_write_field_begin (protocol, "test", T_VOID, 
                                                       1, NULL) == -1);
     transport_write_error = 0;
 
     /* test 2nd write error */
     transport_write_count = 0;
     transport_write_error_at = 1;
-    assert (thrift_binary_protocol_write_field_begin (protocol, "test", T_VOID,
+    g_assert (thrift_binary_protocol_write_field_begin (protocol, "test", T_VOID,
                                                       1, NULL) == -1);
     transport_write_error_at = -1;
 
@@ -260,12 +271,12 @@
     thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
 
     /* test write_field_stop */
-    assert (thrift_binary_protocol_write_field_stop (protocol, NULL) > 0);
+    g_assert (thrift_binary_protocol_write_field_stop (protocol, NULL) > 0);
 
     /* write a map */
-    assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
+    g_assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
                                                     1, NULL) > 0);
-    assert (thrift_binary_protocol_write_map_end (protocol, NULL) == 0);
+    g_assert (thrift_binary_protocol_write_map_end (protocol, NULL) == 0);
 
     /* test 2nd read failure on a map */
     thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
@@ -276,21 +287,21 @@
 
     /* test 1st write failure on a map */
     transport_write_error = 1;
-    assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
+    g_assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
                                                     1, NULL) == -1);
     transport_write_error = 0;
 
     /* test 2nd write failure on a map */
     transport_write_count = 0;
     transport_write_error_at = 1;
-    assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
+    g_assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
                                                     1, NULL) == -1);
     transport_write_error_at = -1;
 
     /* test 3rd write failure on a map */
     transport_write_count = 0;
     transport_write_error_at = 2;
-    assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
+    g_assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
                                                     1, NULL) == -1);
     transport_write_error_at = -1;
 
@@ -300,9 +311,9 @@
     thrift_binary_protocol_write_i32 (protocol, -10, NULL);
 
     /* test list operations */
-    assert (thrift_binary_protocol_write_list_begin (protocol, T_VOID,
+    g_assert (thrift_binary_protocol_write_list_begin (protocol, T_VOID,
                                                      1, NULL) > 0);
-    assert (thrift_binary_protocol_write_list_end (protocol, NULL) == 0);
+    g_assert (thrift_binary_protocol_write_list_end (protocol, NULL) == 0);
 
     /* test 2nd read failure on a list */
     thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
@@ -313,27 +324,27 @@
 
     /* test first write error on a list */
     transport_write_error = 1;
-    assert (thrift_binary_protocol_write_list_begin (protocol, T_VOID,
+    g_assert (thrift_binary_protocol_write_list_begin (protocol, T_VOID,
                                                      1, NULL) == -1);
     transport_write_error = 0;
 
     /* test 2nd write error on a list */
     transport_write_count = 0;
     transport_write_error_at = 1;
-    assert (thrift_binary_protocol_write_list_begin (protocol, T_VOID,
+    g_assert (thrift_binary_protocol_write_list_begin (protocol, T_VOID,
                                                      1, NULL) == -1);
     transport_write_error_at = -1;
 
     /* test set operation s*/
-    assert (thrift_binary_protocol_write_set_begin (protocol, T_VOID,
+    g_assert (thrift_binary_protocol_write_set_begin (protocol, T_VOID,
                                                     1, NULL) > 0);
-    assert (thrift_binary_protocol_write_set_end (protocol, NULL) == 0);
+    g_assert (thrift_binary_protocol_write_set_end (protocol, NULL) == 0);
 
     /* invalid version */
-    assert (thrift_binary_protocol_write_i32 (protocol, -1, NULL) > 0);
+    g_assert (thrift_binary_protocol_write_i32 (protocol, -1, NULL) > 0);
 
     /* sz > 0 for a message */
-    assert (thrift_binary_protocol_write_i32 (protocol, 1, NULL) > 0);
+    g_assert (thrift_binary_protocol_write_i32 (protocol, 1, NULL) > 0);
 
     /* send a valid message */
     thrift_binary_protocol_write_i32 (protocol, 0x80010000, NULL);
@@ -348,26 +359,26 @@
     thrift_binary_protocol_write_string (protocol, "test", NULL);
 
     /* send a valid message */
-    assert (thrift_binary_protocol_write_message_begin (protocol, "test",
+    g_assert (thrift_binary_protocol_write_message_begin (protocol, "test",
                                                         T_CALL, 1, NULL) > 0);
 
-    assert (thrift_binary_protocol_write_message_end (protocol, NULL) == 0);
+    g_assert (thrift_binary_protocol_write_message_end (protocol, NULL) == 0);
 
     /* send broken writes */
     transport_write_error = 1;
-    assert (thrift_binary_protocol_write_message_begin (protocol, "test",
+    g_assert (thrift_binary_protocol_write_message_begin (protocol, "test",
                                                         T_CALL, 1, NULL) == -1);
     transport_write_error = 0;
 
     transport_write_count = 0;
     transport_write_error_at = 2;
-    assert (thrift_binary_protocol_write_message_begin (protocol, "test",
+    g_assert (thrift_binary_protocol_write_message_begin (protocol, "test",
                                                         T_CALL, 1, NULL) == -1);
     transport_write_error_at = -1;
 
     transport_write_count = 0;
     transport_write_error_at = 3;
-    assert (thrift_binary_protocol_write_message_begin (protocol, "test",
+    g_assert (thrift_binary_protocol_write_message_begin (protocol, "test",
                                                         T_CALL, 1, NULL) == -1);
     transport_write_error_at = -1;
 
@@ -375,8 +386,95 @@
     thrift_transport_close (transport, NULL);
     g_object_unref (tsocket);
     g_object_unref (protocol);
-    assert (wait (&status) == pid);
-    assert (status == 0);
+    g_assert (wait (&status) == pid);
+    g_assert (status == 0);
+  }
+}
+
+static void
+test_read_and_write_many_frames (void)
+{
+  int status;
+  pid_t pid;
+  ThriftSocket *tsocket = NULL;
+  ThriftTransport *transport = NULL;
+  ThriftFramedTransport *ft = NULL;
+  ThriftBinaryProtocol *tb = NULL;
+  ThriftProtocol *protocol = NULL;
+  gpointer binary = (gpointer *) TEST_STRING;
+  const guint32 len = strlen (TEST_STRING);
+  int port = TEST_PORT;
+
+  /* fork a server from the client */
+  pid = fork ();
+  g_assert (pid >= 0);
+
+  if (pid == 0)
+  {
+    /* child listens */
+    thrift_server_many_frames (port);
+    exit (0);
+  } else {
+    /* parent.  wait a bit for the socket to be created. */
+    sleep (1);
+
+    /* create a ThriftSocket */
+    tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                            "port", port, NULL);
+    g_assert (tsocket != NULL);
+    transport = THRIFT_TRANSPORT (tsocket);
+
+    /* wrap in a framed transport */
+    ft = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, "transport", transport,
+                       "w_buf_size", 1, NULL);
+    g_assert (ft != NULL);
+    transport = THRIFT_TRANSPORT (ft);
+
+    thrift_transport_open (transport, NULL);
+    g_assert (thrift_transport_is_open (transport));
+
+    /* create a binary protocol */
+    tb = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+                       transport, NULL);
+    protocol = THRIFT_PROTOCOL (tb);
+    g_assert (protocol != NULL);
+
+    /* write a bunch of primitives */
+    g_assert (thrift_binary_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_binary_protocol_write_byte (protocol, TEST_BYTE, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_binary_protocol_write_i16 (protocol, TEST_I16, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_binary_protocol_write_i32 (protocol, TEST_I32, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_binary_protocol_write_i64 (protocol, TEST_I64, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_binary_protocol_write_double (protocol,
+                                                 TEST_DOUBLE, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_binary_protocol_write_string (protocol,
+                                                 TEST_STRING, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_binary_protocol_write_string (protocol, "", NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_binary_protocol_write_binary (protocol, binary,
+                                                 len, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_binary_protocol_write_binary (protocol, NULL, 0, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_binary_protocol_write_binary (protocol, binary,
+                                                 len, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+
+    /* clean up */
+    thrift_transport_write_end (transport, NULL);
+    thrift_transport_close (transport, NULL);
+    g_object_unref (ft);
+    g_object_unref (tsocket);
+    g_object_unref (tb);
+    g_assert (wait (&status) == pid);
+    g_assert (status == 0);
   }
 }
 
@@ -395,6 +493,7 @@
   gint64 value_64 = 0;
   gdouble value_double = 0;
   gchar *string = NULL;
+  gchar *empty_string = NULL;
   gpointer binary = NULL;
   guint32 len = 0;
   void *comparator = (void *) TEST_STRING;
@@ -404,61 +503,68 @@
   transport = THRIFT_SERVER_TRANSPORT (tsocket);
   thrift_server_transport_listen (transport, NULL);
   client = thrift_server_transport_accept (transport, NULL);
-  assert (client != NULL);
+  g_assert (client != NULL);
 
   tbp = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
                       client, NULL);
   protocol = THRIFT_PROTOCOL (tbp);
 
-  assert (thrift_binary_protocol_read_bool (protocol,
+  g_assert (thrift_binary_protocol_read_bool (protocol,
                                             &value_boolean, NULL) > 0);
-  assert (thrift_binary_protocol_read_byte (protocol, &value_byte, NULL) > 0);
-  assert (thrift_binary_protocol_read_i16 (protocol, &value_16, NULL) > 0);
-  assert (thrift_binary_protocol_read_i32 (protocol, &value_32, NULL) > 0);
-  assert (thrift_binary_protocol_read_i64 (protocol, &value_64, NULL) > 0);
-  assert (thrift_binary_protocol_read_double (protocol,
+  g_assert (thrift_binary_protocol_read_byte (protocol, &value_byte, NULL) > 0);
+  g_assert (thrift_binary_protocol_read_i16 (protocol, &value_16, NULL) > 0);
+  g_assert (thrift_binary_protocol_read_i32 (protocol, &value_32, NULL) > 0);
+  g_assert (thrift_binary_protocol_read_i64 (protocol, &value_64, NULL) > 0);
+  g_assert (thrift_binary_protocol_read_double (protocol,
                                               &value_double, NULL) > 0);
-  assert (thrift_binary_protocol_read_string (protocol, &string, NULL) > 0);
-  assert (thrift_binary_protocol_read_binary (protocol, &binary,
+  g_assert (thrift_binary_protocol_read_string (protocol, &string, NULL) > 0);
+  g_assert (thrift_binary_protocol_read_string (protocol, &empty_string,
+                                              NULL) > 0);
+  g_assert (thrift_binary_protocol_read_binary (protocol, &binary,
                                               &len, NULL) > 0);
 
-  assert (value_boolean == TEST_BOOL);
-  assert (value_byte = TEST_BYTE);
-  assert (value_16 = TEST_I16);
-  assert (value_32 = TEST_I32);
-  assert (value_64 = TEST_I64);
-  assert (value_double = TEST_DOUBLE);
-  assert (strcmp (TEST_STRING, string) == 0);
-  assert (memcmp (comparator, binary, len) == 0);
+  g_assert (value_boolean == TEST_BOOL);
+  g_assert (value_byte == TEST_BYTE);
+  g_assert (value_16 == TEST_I16);
+  g_assert (value_32 == TEST_I32);
+  g_assert (value_64 == TEST_I64);
+  g_assert (value_double == TEST_DOUBLE);
+  g_assert (strcmp (TEST_STRING, string) == 0);
+  g_assert (strcmp ("", empty_string) == 0);
+  g_assert (memcmp (comparator, binary, len) == 0);
 
   g_free (string);
+  g_free (empty_string);
   g_free (binary);
 
-  thrift_binary_protocol_read_binary (protocol, &binary, &len, NULL);
+  g_assert (thrift_binary_protocol_read_binary (protocol, &binary,
+                                              &len, NULL) > 0);
+  g_assert (binary == NULL);
+  g_assert (len == 0);
   g_free (binary);
 
   transport_read_count = 0;
   transport_read_error_at = 0;
-  assert (thrift_binary_protocol_read_binary (protocol, &binary,
+  g_assert (thrift_binary_protocol_read_binary (protocol, &binary,
                                               &len, NULL) == -1);
   transport_read_error_at = -1;
 
   transport_read_count = 0;
   transport_read_error_at = 1;
-  assert (thrift_binary_protocol_read_binary (protocol, &binary,
+  g_assert (thrift_binary_protocol_read_binary (protocol, &binary,
                                               &len, NULL) == -1);
   transport_read_error_at = -1;
 
   transport_read_error = 1;
-  assert (thrift_binary_protocol_read_bool (protocol,
+  g_assert (thrift_binary_protocol_read_bool (protocol,
                                             &value_boolean, NULL) == -1);
-  assert (thrift_binary_protocol_read_byte (protocol,
+  g_assert (thrift_binary_protocol_read_byte (protocol,
                                             &value_byte, NULL) == -1);
-  assert (thrift_binary_protocol_read_i16 (protocol,
+  g_assert (thrift_binary_protocol_read_i16 (protocol,
                                            &value_16, NULL) == -1);
-  assert (thrift_binary_protocol_read_i32 (protocol, &value_32, NULL) == -1);
-  assert (thrift_binary_protocol_read_i64 (protocol, &value_64, NULL) == -1);
-  assert (thrift_binary_protocol_read_double (protocol,
+  g_assert (thrift_binary_protocol_read_i32 (protocol, &value_32, NULL) == -1);
+  g_assert (thrift_binary_protocol_read_i64 (protocol, &value_64, NULL) == -1);
+  g_assert (thrift_binary_protocol_read_double (protocol,
                                               &value_double, NULL) == -1);
   transport_read_error = 0;
 
@@ -496,7 +602,7 @@
   transport = THRIFT_SERVER_TRANSPORT (tsocket);
   thrift_server_transport_listen (transport, NULL);
   client = thrift_server_transport_accept (transport, NULL);
-  assert (client != NULL);
+  g_assert (client != NULL);
 
   tbp = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
                       client, NULL);
@@ -511,7 +617,7 @@
 
   /* test first read error on a field */
   transport_read_error = 1;
-  assert (thrift_binary_protocol_read_field_begin (protocol,
+  g_assert (thrift_binary_protocol_read_field_begin (protocol,
                                                    &field_name, &field_type,
                                                    &field_id, NULL) == -1);
   transport_read_error = 0;
@@ -522,7 +628,7 @@
   /* test 2nd read failure on a field */
   transport_read_count = 0;
   transport_read_error_at = 1;
-  assert (thrift_binary_protocol_read_field_begin (protocol,
+  g_assert (thrift_binary_protocol_read_field_begin (protocol,
                                                    &field_name, &field_type,
                                                    &field_id, NULL) == -1);
   transport_read_error_at = -1;
@@ -538,7 +644,7 @@
   /* test read failure on a map */
   transport_read_count = 0;
   transport_read_error_at = 0;
-  assert (thrift_binary_protocol_read_map_begin (protocol,
+  g_assert (thrift_binary_protocol_read_map_begin (protocol,
                                                  &key_type, &value_type,
                                                  &size, NULL) == -1);
   transport_read_error_at = -1;
@@ -546,7 +652,7 @@
   /* test 2nd read failure on a map */
   transport_read_count = 0;
   transport_read_error_at = 1;
-  assert (thrift_binary_protocol_read_map_begin (protocol,
+  g_assert (thrift_binary_protocol_read_map_begin (protocol,
                                                  &key_type, &value_type,
                                                  &size, NULL) == -1);
   transport_read_error_at = -1;
@@ -554,7 +660,7 @@
   /* test 3rd read failure on a map */
   transport_read_count = 0;
   transport_read_error_at = 2;
-  assert (thrift_binary_protocol_read_map_begin (protocol,
+  g_assert (thrift_binary_protocol_read_map_begin (protocol,
                                                  &key_type, &value_type,
                                                  &size, NULL) == -1);
   transport_read_error_at = -1;
@@ -567,7 +673,7 @@
   thrift_binary_protocol_read_byte (protocol, &value, NULL);
 
   /* test negative map size */
-  assert (thrift_binary_protocol_read_map_begin (protocol,
+  g_assert (thrift_binary_protocol_read_map_begin (protocol,
                                                  &key_type, &value_type,
                                                  &size, NULL) == -1);
 
@@ -577,7 +683,7 @@
 
   /* test read failure */
   transport_read_error = 1;
-  assert (thrift_binary_protocol_read_list_begin (protocol, &element_type,
+  g_assert (thrift_binary_protocol_read_list_begin (protocol, &element_type,
                                                   &size, NULL) == -1);
   transport_read_error = 0;
 
@@ -599,23 +705,23 @@
 
   /* broken read */
   transport_read_error = 1;
-  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+  g_assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
                                                      &message_type, &seqid,
                                                      NULL) == -1);
   transport_read_error = 0;
 
   /* invalid protocol version */
-  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+  g_assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
                                                      &message_type, &seqid,
                                                      NULL) == -1);
 
   /* sz > 0 */
-  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+  g_assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
                                                      &message_type, &seqid,
                                                      NULL) > 0);
 
   /* read a valid message */
-  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+  g_assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
                                                      &message_type, &seqid,
                                                      NULL) > 0);
   g_free (message_name);
@@ -623,7 +729,7 @@
   /* broken 2nd read on a message */
   transport_read_count = 0;
   transport_read_error_at = 1;
-  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+  g_assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
                                                      &message_type, &seqid,
                                                      NULL) == -1);
   transport_read_error_at = -1;
@@ -631,19 +737,19 @@
   /* broken 3rd read on a message */
   transport_read_count = 0;
   transport_read_error_at = 3; /* read_string does two reads */
-  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+  g_assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
                                                      &message_type, &seqid,
                                                      NULL) == -1);
   g_free (message_name);
   transport_read_error_at = -1;
 
   /* read a valid message */
-  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+  g_assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
                                                      &message_type, &seqid, 
                                                      NULL) > 0);
   g_free (message_name);
 
-  assert (thrift_binary_protocol_read_message_end (protocol, NULL) == 0);
+  g_assert (thrift_binary_protocol_read_message_end (protocol, NULL) == 0);
 
   /* handle 2nd write failure on a message */
   thrift_binary_protocol_read_i32 (protocol, &version, NULL);
@@ -653,20 +759,101 @@
   thrift_binary_protocol_read_string (protocol, &message_name, NULL);
 
   g_object_unref (client);
-  // TODO: investigate g_object_unref (tbp);
+  /* TODO: investigate g_object_unref (tbp); */
+  g_object_unref (tsocket);
+}
+
+static void
+thrift_server_many_frames (const int port)
+{
+  ThriftServerTransport *transport = NULL;
+  ThriftTransport *client = NULL;
+  ThriftBinaryProtocol *tbp = NULL;
+  ThriftProtocol *protocol = NULL;
+  ThriftServerSocket *tsocket = NULL;
+  gboolean value_boolean = FALSE;
+  gint8 value_byte = 0;
+  gint16 value_16 = 0;
+  gint32 value_32 = 0;
+  gint64 value_64 = 0;
+  gdouble value_double = 0;
+  gchar *string = NULL;
+  gchar *empty_string = NULL;
+  gpointer binary = NULL;
+  guint32 len = 0;
+  void *comparator = (void *) TEST_STRING;
+
+  tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET, "port", port, NULL);
+  transport = THRIFT_SERVER_TRANSPORT (tsocket);
+  thrift_server_transport_listen (transport, NULL);
+
+  /* wrap the client in a framed transport */
+  client = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, "transport",
+                         thrift_server_transport_accept (transport, NULL),
+                         "r_buf_size", 1, NULL);
+  g_assert (client != NULL);
+
+  tbp = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+                      client, NULL);
+  protocol = THRIFT_PROTOCOL (tbp);
+
+  g_assert (thrift_binary_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) > 0);
+  g_assert (thrift_binary_protocol_read_byte (protocol, &value_byte, NULL) > 0);
+  g_assert (thrift_binary_protocol_read_i16 (protocol, &value_16, NULL) > 0);
+  g_assert (thrift_binary_protocol_read_i32 (protocol, &value_32, NULL) > 0);
+  g_assert (thrift_binary_protocol_read_i64 (protocol, &value_64, NULL) > 0);
+  g_assert (thrift_binary_protocol_read_double (protocol,
+                                              &value_double, NULL) > 0);
+  g_assert (thrift_binary_protocol_read_string (protocol, &string, NULL) > 0);
+  g_assert (thrift_binary_protocol_read_string (protocol, &empty_string,
+                                              NULL) > 0);
+  g_assert (thrift_binary_protocol_read_binary (protocol, &binary,
+                                              &len, NULL) > 0);
+
+  g_assert (value_boolean == TEST_BOOL);
+  g_assert (value_byte == TEST_BYTE);
+  g_assert (value_16 == TEST_I16);
+  g_assert (value_32 == TEST_I32);
+  g_assert (value_64 == TEST_I64);
+  g_assert (value_double == TEST_DOUBLE);
+  g_assert (strcmp (TEST_STRING, string) == 0);
+  g_assert (strcmp ("", empty_string) == 0);
+  g_assert (memcmp (comparator, binary, len) == 0);
+
+  g_free (string);
+  g_free (empty_string);
+  g_free (binary);
+
+  g_assert (thrift_binary_protocol_read_binary (protocol, &binary,
+                                              &len, NULL) > 0);
+  g_assert (binary == NULL);
+  g_assert (len == 0);
+  g_free (binary);
+
+  thrift_transport_read_end (client, NULL);
+  thrift_transport_close (client, NULL);
+
+  g_object_unref (tbp);
+  g_object_unref (client);
   g_object_unref (tsocket);
 }
 
 int
 main(int argc, char *argv[])
 {
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
   g_type_init();
+#endif
+
   g_test_init (&argc, &argv, NULL);
 
   g_test_add_func ("/testbinaryprotocol/CreateAndDestroy", test_create_and_destroy);
   g_test_add_func ("/testbinaryprotocol/Initialize", test_initialize);
   g_test_add_func ("/testbinaryprotocol/ReadAndWritePrimitives", test_read_and_write_primitives);
   g_test_add_func ("/testbinaryprotocol/ReadAndWriteComplexTypes", test_read_and_write_complex_types);
+  g_test_add_func ("/testbinaryprotocol/ReadAndWriteManyFrames",
+                   test_read_and_write_many_frames);
 
   return g_test_run ();
 }
diff --git a/lib/c_glib/test/testbufferedtransport.c b/lib/c_glib/test/testbufferedtransport.c
index 86b5314..d01806d 100755
--- a/lib/c_glib/test/testbufferedtransport.c
+++ b/lib/c_glib/test/testbufferedtransport.c
@@ -17,8 +17,9 @@
  * under the License.
  */
 
-#include <assert.h>
 #include <netdb.h>
+#include <signal.h>
+#include <sys/wait.h>
 
 #include <thrift/c_glib/transport/thrift_transport.h>
 #include <thrift/c_glib/transport/thrift_socket.h>
@@ -29,10 +30,8 @@
 
 #include "../src/thrift/c_glib/transport/thrift_buffered_transport.c"
 
-static const char TEST_ADDRESS[] = "localhost";
-static const short TEST_PORT = 64444;
-
 static void thrift_server (const int port);
+static void thrift_socket_server_open (const int port, int times);
 
 /* test object creation and destruction */
 static void
@@ -44,10 +43,10 @@
 
   GObject *object = NULL;
   object = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT, NULL);
-  assert (object != NULL);
+  g_assert (object != NULL);
   g_object_get (G_OBJECT (object), "transport", &transport,
-                "r_buf_size", &r_buf_size,
-                "w_buf_size", &w_buf_size, NULL);
+		"r_buf_size", &r_buf_size,
+		"w_buf_size", &w_buf_size, NULL);
   g_object_unref (object);
 }
 
@@ -57,35 +56,52 @@
   ThriftSocket *tsocket = NULL;
   ThriftTransport *transport = NULL;
   GError *err = NULL;
+  pid_t pid;
+  int port = 51199;
+  int status;
 
-  /* create a ThriftSocket */
-  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
-                          "port", 51188, NULL); 
+  pid = fork ();
+  g_assert ( pid >= 0 );
 
-  /* create a BufferedTransport wrapper of the Socket */
-  transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
-                            "transport", THRIFT_TRANSPORT (tsocket), NULL);
+  if ( pid == 0 )
+    {
+      /* child listens */
+      thrift_socket_server_open (port,1);
+      exit (0);
+    } else {
+	/* parent connects, wait a bit for the socket to be created */
+	sleep (1);
+	/* create a ThriftSocket */
+	tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+				"port", port, NULL);
 
-  /* this shouldn't work */
-  assert (thrift_buffered_transport_open (transport, NULL) == FALSE);
-  assert (thrift_buffered_transport_is_open (transport) == TRUE);
-  assert (thrift_buffered_transport_close (transport, NULL) == TRUE);
-  g_object_unref (transport);
-  g_object_unref (tsocket);
+	/* create a BufferedTransport wrapper of the Socket */
+	transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+				  "transport", THRIFT_TRANSPORT (tsocket), NULL);
 
-  /* try and underlying socket failure */
-  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
-                          NULL);
+	/* this shouldn't work */
+	g_assert (thrift_buffered_transport_open (transport, NULL) == TRUE);
+	g_assert (thrift_buffered_transport_is_open (transport) == TRUE);
+	g_assert (thrift_buffered_transport_close (transport, NULL) == TRUE);
+	g_object_unref (transport);
+	g_object_unref (tsocket);
 
-  /* create a BufferedTransport wrapper of the Socket */
-  transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
-                            "transport", THRIFT_TRANSPORT (tsocket), NULL);
+	/* try and underlying socket failure */
+	tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
+				NULL);
 
-  assert (thrift_buffered_transport_open (transport, &err) == FALSE);
-  g_object_unref (transport);
-  g_object_unref (tsocket);
-  g_error_free (err);
-  err = NULL;
+	/* create a BufferedTransport wrapper of the Socket */
+	transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+				  "transport", THRIFT_TRANSPORT (tsocket), NULL);
+
+	g_assert (thrift_buffered_transport_open (transport, &err) == FALSE);
+	g_object_unref (transport);
+	g_object_unref (tsocket);
+	g_error_free (err);
+	err = NULL;
+	g_assert ( wait (&status) == pid );
+	g_assert ( status == 0 );
+    }
 }
 
 static void
@@ -99,60 +115,81 @@
   guchar buf[10] = TEST_DATA; /* a buffer */
 
   pid = fork ();
-  assert ( pid >= 0 );
+  g_assert ( pid >= 0 );
 
   if ( pid == 0 )
-  {
-    /* child listens */
-    thrift_server (port);
-    exit (0);
-  } else {
-    /* parent connects, wait a bit for the socket to be created */
-    sleep (1);
+    {
+      /* child listens */
+      thrift_server (port);
+      exit (0);
+    } else {
+	/* parent connects, wait a bit for the socket to be created */
+	sleep (1);
 
-    tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
-                            "port", port, NULL);
-    transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
-                              "transport", THRIFT_TRANSPORT (tsocket),
-                              "w_buf_size", 4, NULL);
+	tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+				"port", port, NULL);
+	transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+				  "transport", THRIFT_TRANSPORT (tsocket),
+				  "w_buf_size", 4, NULL);
 
-    assert (thrift_buffered_transport_open (transport, NULL) == TRUE);
-    assert (thrift_buffered_transport_is_open (transport));
+	g_assert (thrift_buffered_transport_open (transport, NULL) == TRUE);
+	g_assert (thrift_buffered_transport_is_open (transport));
 
-    /* write 10 bytes */
-    thrift_buffered_transport_write (transport, buf, 10, NULL);
+	/* write 10 bytes */
+	thrift_buffered_transport_write (transport, buf, 10, NULL);
 
-    /* write 1 byte at a time */
-    thrift_buffered_transport_write (transport, buf, 1, NULL);
-    thrift_buffered_transport_write (transport, buf, 1, NULL);
-    thrift_buffered_transport_write (transport, buf, 1, NULL);
+	/* write 1 byte at a time */
+	thrift_buffered_transport_write (transport, buf, 1, NULL);
+	thrift_buffered_transport_write (transport, buf, 1, NULL);
+	thrift_buffered_transport_write (transport, buf, 1, NULL);
 
-    /* overflow the buffer */
-    thrift_buffered_transport_write (transport, buf, 2, NULL);
-    thrift_buffered_transport_write (transport, buf, 1, NULL);
-    thrift_buffered_transport_flush (transport, NULL);
+	/* overflow the buffer */
+	thrift_buffered_transport_write (transport, buf, 2, NULL);
+	thrift_buffered_transport_write (transport, buf, 1, NULL);
+	thrift_buffered_transport_flush (transport, NULL);
 
-    /* write 1 byte and flush */
-    thrift_buffered_transport_write (transport, buf, 1, NULL);
-    thrift_buffered_transport_flush (transport, NULL);
+	/* write 1 byte and flush */
+	thrift_buffered_transport_write (transport, buf, 1, NULL);
+	thrift_buffered_transport_flush (transport, NULL);
 
-    /* write and overflow buffer with 2 system calls */
-    thrift_buffered_transport_write (transport, buf, 1, NULL);
-    thrift_buffered_transport_write (transport, buf, 3, NULL);
+	/* write and overflow buffer with 2 system calls */
+	thrift_buffered_transport_write (transport, buf, 1, NULL);
+	thrift_buffered_transport_write (transport, buf, 3, NULL);
 
-    /* write 10 bytes */
-    thrift_buffered_transport_write (transport, buf, 10, NULL);
+	/* write 10 bytes */
+	thrift_buffered_transport_write (transport, buf, 10, NULL);
 
-    thrift_buffered_transport_write_end (transport, NULL);
-    thrift_buffered_transport_flush (transport, NULL);
-    thrift_buffered_transport_close (transport, NULL);
+	thrift_buffered_transport_write_end (transport, NULL);
+	thrift_buffered_transport_flush (transport, NULL);
+	thrift_buffered_transport_close (transport, NULL);
 
-    g_object_unref (transport);
-    g_object_unref (tsocket);
+	g_object_unref (transport);
+	g_object_unref (tsocket);
 
-    assert ( wait (&status) == pid );
-    assert ( status == 0 );
+	g_assert ( wait (&status) == pid );
+	g_assert ( status == 0 );
+    }
+}
+
+
+static void
+thrift_socket_server_open (const int port, int times)
+{
+  ThriftServerTransport *transport = NULL;
+  ThriftTransport *client = NULL;
+  int i;
+  ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+					      "port", port, NULL);
+
+  transport = THRIFT_SERVER_TRANSPORT (tsocket);
+  thrift_server_transport_listen (transport, NULL);
+  for(i=0;i<times;i++){
+      client = thrift_server_transport_accept (transport, NULL);
+      g_assert (client != NULL);
+      thrift_socket_close (client, NULL);
+      g_object_unref (client);
   }
+  g_object_unref (tsocket);
 }
 
 static void
@@ -165,21 +202,21 @@
   guchar match[10] = TEST_DATA;
 
   ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
-                                              "port", port, NULL);
+					      "port", port, NULL);
 
   transport = THRIFT_SERVER_TRANSPORT (tsocket);
   thrift_server_transport_listen (transport, NULL);
 
   /* wrap the client in a BufferedTransport */
   client = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT, "transport",
-                         thrift_server_transport_accept (transport, NULL),
-                         "r_buf_size", 5, NULL);
-  assert (client != NULL);
+			 thrift_server_transport_accept (transport, NULL),
+			 "r_buf_size", 5, NULL);
+  g_assert (client != NULL);
 
   /* read 10 bytes */
   bytes = thrift_buffered_transport_read (client, buf, 10, NULL);
-  assert (bytes == 10); /* make sure we've read 10 bytes */
-  assert ( memcmp (buf, match, 10) == 0 ); /* make sure what we got matches */
+  g_assert (bytes == 10); /* make sure we've read 10 bytes */
+  g_assert ( memcmp (buf, match, 10) == 0 ); /* make sure what we got matches */
 
   /* read 1 byte */
   bytes = thrift_buffered_transport_read (client, buf, 1, NULL);
@@ -194,15 +231,94 @@
   g_object_unref (tsocket);
 }
 
+static void
+test_write_fail(void)
+{
+  int status;
+  pid_t pid;
+  ThriftSocket *tsocket = NULL;
+  ThriftTransport *transport = NULL;
+  int port = 51198;
+  guchar buf[10] = TEST_DATA; /* a buffer */
+
+  /* SIGPIPE when send to disconnected socket */
+  signal(SIGPIPE, SIG_IGN);
+
+  pid = fork ();
+  g_assert ( pid >= 0 );
+
+  if ( pid == 0 )
+    {
+      /* child listens */
+      ThriftServerTransport *transport = NULL;
+      ThriftTransport *client = NULL;
+
+      ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+						  "port", port, NULL);
+
+      transport = THRIFT_SERVER_TRANSPORT (tsocket);
+      thrift_server_transport_listen (transport, NULL);
+
+      /* wrap the client in a BufferedTransport */
+      client = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT, "transport",
+			     thrift_server_transport_accept (transport, NULL),
+			     "r_buf_size", 5, NULL);
+      g_assert (client != NULL);
+
+      /* just close socket */
+      thrift_buffered_transport_close (client, NULL);
+      g_object_unref (client);
+      g_object_unref (tsocket);
+      exit (0);
+    } else {
+	/* parent connects, wait a bit for the socket to be created */
+	sleep (1);
+
+	tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+				"port", port, NULL);
+	transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+				  "transport", THRIFT_TRANSPORT (tsocket),
+				  "w_buf_size", 4, NULL);
+
+
+	g_assert (thrift_buffered_transport_open (transport, NULL) == TRUE);
+	g_assert (thrift_buffered_transport_is_open (transport));
+
+	/* recognize disconnection */
+	sleep(1);
+	g_assert (thrift_buffered_transport_write (transport, buf, 10, NULL) == TRUE);
+	g_assert (thrift_buffered_transport_write (transport, buf, 10, NULL) == FALSE);
+
+	/* write and overflow buffer */
+	g_assert (thrift_buffered_transport_write (transport, buf, 10, NULL) == FALSE);
+
+	/* write 1 and flush */
+	g_assert (thrift_buffered_transport_write (transport, buf, 1, NULL) == TRUE);
+	g_assert (thrift_buffered_transport_flush (transport, NULL) == FALSE);
+
+	thrift_buffered_transport_close (transport, NULL);
+
+	g_object_unref (transport);
+	g_object_unref (tsocket);
+
+	g_assert ( wait (&status) == pid );
+	g_assert ( status == 0 );
+    }
+}
+
 int
 main(int argc, char *argv[])
 {
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
   g_type_init();
+#endif
+
   g_test_init (&argc, &argv, NULL);
 
   g_test_add_func ("/testbufferedtransport/CreateAndDestroy", test_create_and_destroy);
   g_test_add_func ("/testbufferedtransport/OpenAndClose", test_open_and_close);
   g_test_add_func ("/testbufferedtransport/ReadAndWrite", test_read_and_write);
+  g_test_add_func ("/testbufferedtransport/WriteFail", test_write_fail);
 
   return g_test_run ();
 }
diff --git a/lib/c_glib/test/testcompactprotocol.c b/lib/c_glib/test/testcompactprotocol.c
new file mode 100755
index 0000000..e5ad491
--- /dev/null
+++ b/lib/c_glib/test/testcompactprotocol.c
@@ -0,0 +1,1293 @@
+/*
+ * 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.
+ */
+
+/* Disable string-function optimizations when glibc is used, as these produce
+   compiler warnings about string length when a string function is used inside
+   a call to g_assert () */
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && \
+    !defined(__OpenBSD__) && !defined(__NetBSD__)
+#include <features.h>
+#endif
+
+#ifdef __GLIBC__
+#define __NO_STRING_INLINES 1
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/transport/thrift_socket.h>
+#include <thrift/c_glib/transport/thrift_server_socket.h>
+#include <thrift/c_glib/transport/thrift_framed_transport.h>
+
+#define TEST_BOOL TRUE
+#define TEST_BYTE 123
+#define TEST_I16 12345
+#define TEST_I32 1234567890
+#define TEST_I64 123456789012345
+#define TEST_NI16 (-12345)
+#define TEST_NI32 (-1234567890)
+#define TEST_NI64 (-123456789012345)
+#define TEST_DOUBLE 1234567890.123
+#define TEST_STRING "this is a test string 1234567890!@#$%^&*()"
+#define TEST_PORT 51199
+
+static int transport_read_count = 0;
+static int transport_read_error = 0;
+static int transport_read_error_at = -1;
+gint32
+my_thrift_transport_read_all (ThriftTransport *transport, gpointer buf,
+                              guint32 len, GError **error)
+{
+  if (transport_read_count != transport_read_error_at
+      && transport_read_error == 0)
+  {
+    transport_read_count++;
+    return thrift_transport_read_all (transport, buf, len, error);
+  }
+  return -1;
+}
+
+static int transport_write_count = 0;
+static int transport_write_error = 0;
+static int transport_write_error_at = -1;
+gboolean
+my_thrift_transport_write (ThriftTransport *transport, const gpointer buf,
+                           const guint32 len, GError **error)
+{
+  if (transport_write_count != transport_write_error_at
+      && transport_write_error == 0)
+  {
+    transport_write_count++;
+    return thrift_transport_write (transport, buf, len, error);
+  }
+  return FALSE;
+}
+
+#define thrift_transport_read_all my_thrift_transport_read_all
+#define thrift_transport_write my_thrift_transport_write
+#include "../src/thrift/c_glib/protocol/thrift_compact_protocol.c"
+#undef thrift_transport_read_all
+#undef thrift_transport_write
+
+static void thrift_server_primitives (const int port);
+static void thrift_server_complex_types (const int port);
+static void thrift_server_many_frames (const int port);
+
+static void
+test_create_and_destroy (void)
+{
+  GObject *object = NULL;
+
+  /* create an object and then destroy it */
+  object = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, NULL);
+  g_assert (object != NULL);
+  g_object_unref (object);
+}
+
+static void
+test_initialize (void)
+{
+  ThriftSocket *tsocket = NULL;
+  ThriftCompactProtocol *protocol = NULL;
+  ThriftSocket *temp = NULL;
+
+  /* create a ThriftTransport */
+  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                          "port", 51188, NULL);
+  g_assert (tsocket != NULL);
+  /* create a ThriftCompactProtocol using the Transport */
+  protocol = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, "transport",
+                           tsocket, NULL);
+  g_assert (protocol != NULL);
+  /* fetch the properties */
+  g_object_get (G_OBJECT (protocol), "transport", &temp, NULL);
+  g_object_unref (temp);
+
+  /* clean up memory */
+  g_object_unref (protocol);
+  g_object_unref (tsocket);
+}
+
+static void
+test_read_and_write_primitives (void)
+{
+  int status;
+  pid_t pid;
+  ThriftSocket *tsocket = NULL;
+  ThriftTransport *transport = NULL;
+  ThriftCompactProtocol *tc = NULL;
+  ThriftProtocol *protocol = NULL;
+  gpointer binary = (gpointer *) TEST_STRING;
+  guint32 len = strlen (TEST_STRING);
+  int port = TEST_PORT;
+
+  /* fork a server from the client */
+  pid = fork ();
+  g_assert (pid >= 0);
+
+  if (pid == 0)
+  {
+    /* child listens */
+    thrift_server_primitives (port);
+    exit (0);
+  } else {
+    /* parent.  wait a bit for the socket to be created. */
+    sleep (1);
+
+    /* create a ThriftSocket */
+    tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                            "port", port, NULL);
+    transport = THRIFT_TRANSPORT (tsocket);
+    thrift_transport_open (transport, NULL);
+    g_assert (thrift_transport_is_open (transport));
+
+    /* create a ThriftCompactTransport */
+    tc = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, "transport",
+                       tsocket, NULL);
+    protocol = THRIFT_PROTOCOL (tc);
+    g_assert (protocol != NULL);
+
+    /* write a bunch of primitives */
+    g_assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_byte (protocol, TEST_BYTE, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_i16 (protocol, TEST_I16, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_i32 (protocol, TEST_I32, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_i64 (protocol, TEST_I64, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_i16 (protocol, TEST_NI16, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_i32 (protocol, TEST_NI32, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_i64 (protocol, TEST_NI64, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_i16 (protocol, 2, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_i32 (protocol, 2, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_i64 (protocol, 2, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_i16 (protocol, -2, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_i32 (protocol, -2, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_i64 (protocol, -2, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_double (protocol,
+                                                 TEST_DOUBLE, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_string (protocol,
+                                                 TEST_STRING, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_string (protocol, "", NULL) > 0);
+    g_assert (thrift_compact_protocol_write_binary (protocol, binary,
+                                                 len, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_binary (protocol, NULL, 0, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_binary (protocol, binary,
+                                                 len, NULL) > 0);
+
+    /* test write errors */
+    transport_write_error = 1;
+    g_assert (thrift_compact_protocol_write_byte (protocol, TEST_BYTE,
+                                               NULL) == -1);
+    g_assert (thrift_compact_protocol_write_i16 (protocol, TEST_I16, NULL) == -1);
+    g_assert (thrift_compact_protocol_write_i32 (protocol, TEST_I32, NULL) == -1);
+    g_assert (thrift_compact_protocol_write_i64 (protocol, TEST_I64, NULL) == -1);
+    g_assert (thrift_compact_protocol_write_i16 (protocol, TEST_NI16,
+                                               NULL) == -1);
+    g_assert (thrift_compact_protocol_write_i32 (protocol, TEST_NI32,
+                                               NULL) == -1);
+    g_assert (thrift_compact_protocol_write_i64 (protocol, TEST_NI64,
+                                               NULL) == -1);
+    g_assert (thrift_compact_protocol_write_double (protocol, TEST_DOUBLE,
+                                                 NULL) == -1);
+    g_assert (thrift_compact_protocol_write_binary (protocol, binary, len,
+                                                 NULL) == -1);
+    transport_write_error = 0;
+
+    /* test binary partial failure */
+    transport_write_count = 0;
+    transport_write_error_at = 1;
+    g_assert (thrift_compact_protocol_write_binary (protocol, binary,
+                                                 len, NULL) == -1);
+    transport_write_error_at = -1;
+
+    /* clean up */
+    thrift_transport_close (transport, NULL);
+    g_object_unref (tsocket);
+    g_object_unref (protocol);
+    g_assert (wait (&status) == pid);
+    g_assert (status == 0);
+  }
+}
+
+static void
+test_read_and_write_complex_types (void)
+{
+  int status;
+  pid_t pid;
+  ThriftSocket *tsocket = NULL;
+  ThriftTransport *transport = NULL;
+  ThriftCompactProtocol *tc = NULL;
+  ThriftProtocol *protocol = NULL;
+  int port = TEST_PORT;
+
+  /* fork a server from the client */
+  pid = fork ();
+  g_assert (pid >= 0);
+
+  if (pid == 0)
+  {
+    /* child listens */
+    thrift_server_complex_types (port);
+    exit (0);
+  } else {
+    /* parent.  wait a bit for the socket to be created. */
+    sleep (1);
+
+    /* create a ThriftSocket */
+    tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                            "port", port, NULL);
+    transport = THRIFT_TRANSPORT (tsocket);
+    thrift_transport_open (transport, NULL);
+    g_assert (thrift_transport_is_open (transport));
+
+    /* create a ThriftCompactTransport */
+    tc = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, "transport",
+                       tsocket, NULL);
+    protocol = THRIFT_PROTOCOL (tc);
+    g_assert (protocol != NULL);
+
+    /* test structures */
+    g_assert (thrift_compact_protocol_write_struct_begin (protocol,
+                                                       NULL, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_struct_end (protocol, NULL) == 0);
+
+    /* test field state w.r.t. deltas */
+
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE, 1, NULL) == 1);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       16, NULL) == 1);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       17, NULL) == 1);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       15, NULL) > 1);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       30, NULL) == 1);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       46, NULL) > 1);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       47, NULL) == 1);
+
+    /* test fields */
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       1, NULL) > 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+
+    /* test field state w.r.t. structs */
+
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       1, NULL) > 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       16, NULL) == 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+
+    g_assert (thrift_compact_protocol_write_struct_begin (protocol,
+                                                       NULL, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       17, NULL) > 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+
+    g_assert (thrift_compact_protocol_write_struct_begin (protocol,
+                                                       NULL, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       18, NULL) > 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       19, NULL) == 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_struct_end (protocol, NULL) == 0);
+
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       18, NULL) == 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       25, NULL) == 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_struct_end (protocol, NULL) == 0);
+
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       17, NULL) == 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+
+    /* test field state w.r.t. bools */
+
+    /* deltas */
+    /* non-bool field -> bool field -> non-bool field */
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       18, NULL) == 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test", T_BOOL,
+                                                       19, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL,
+                                                NULL) == 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       20, NULL) == 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+    /* bool -> bool field -> bool */
+    g_assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test", T_BOOL,
+                                                       21, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL,
+                                                NULL) == 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+
+    /* no deltas */
+    /* non-bool field -> bool field -> non-bool field */
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       1, NULL) > 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test", T_BOOL,
+                                                      1, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       1, NULL) > 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+    /* bool -> bool field -> bool */
+    g_assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test", T_BOOL,
+                                                      1, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 1);
+    g_assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+    g_assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+
+    /* test write error */
+    transport_write_error = 1;
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       1, NULL) == -1);
+    transport_write_error = 0;
+
+    /* test 2nd write error */
+    transport_write_count = 0;
+    transport_write_error_at = 1;
+    g_assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+                                                       T_DOUBLE,
+                                                       1, NULL) == -1);
+    transport_write_error_at = -1;
+
+    /* test 2nd read failure on a field */
+    thrift_compact_protocol_write_byte (protocol, T_DOUBLE, NULL);
+
+    /* test write_field_stop */
+    g_assert (thrift_compact_protocol_write_field_stop (protocol, NULL) > 0);
+
+    /* write a map */
+    g_assert (thrift_compact_protocol_write_map_begin (protocol, T_DOUBLE,
+                                                     T_DOUBLE,
+                                                     1, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_map_end (protocol, NULL) == 0);
+
+    /* test 1st read failure on map---nothing to do on our side */
+
+    /* test 2nd read failure on a map */
+    thrift_compact_protocol_write_byte (protocol, T_DOUBLE, NULL);
+
+    /* test 1st write failure on a map */
+    transport_write_error = 1;
+    g_assert (thrift_compact_protocol_write_map_begin (protocol, T_DOUBLE,
+                                                     T_DOUBLE,
+                                                     1, NULL) == -1);
+    transport_write_error = 0;
+
+    /* test 2nd write failure on a map */
+    transport_write_count = 0;
+    transport_write_error_at = 1;
+    g_assert (thrift_compact_protocol_write_map_begin (protocol, T_DOUBLE,
+                                                     T_DOUBLE,
+                                                     1, NULL) == -1);
+    transport_write_error_at = -1;
+
+    /* test negative map size */
+    thrift_compact_protocol_write_varint32 (tc, -10, NULL);
+    thrift_compact_protocol_write_byte (protocol, T_DOUBLE, NULL);
+
+    /* test list operations */
+    g_assert (thrift_compact_protocol_write_list_begin (protocol, T_DOUBLE,
+                                                     15, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_list_end (protocol, NULL) == 0);
+
+    /* test 1st read failure on a small list---nothing to do on our end */
+
+    /* test 1st read failure on a big list---nothing to do on our end */
+
+    /* test 2nd read failure on a big list */
+    thrift_compact_protocol_write_byte (protocol, (gint8) 0xf0, NULL);
+
+    /* test negative list size */
+    thrift_compact_protocol_write_byte (protocol, (gint8) 0xf0, NULL);
+    thrift_compact_protocol_write_varint32 (tc, -10, NULL);
+
+    /* test first write error on a small list */
+    transport_write_error = 1;
+    g_assert (thrift_compact_protocol_write_list_begin (protocol, T_DOUBLE,
+                                                     14, NULL) == -1);
+    transport_write_error = 0;
+
+    /* test first write error on a big list */
+    transport_write_error = 1;
+    g_assert (thrift_compact_protocol_write_list_begin (protocol, T_DOUBLE,
+                                                     15, NULL) == -1);
+    transport_write_error = 0;
+
+    /* test 2nd write error on a big list */
+    transport_write_count = 0;
+    transport_write_error_at = 1;
+    g_assert (thrift_compact_protocol_write_list_begin (protocol, T_DOUBLE,
+                                                     15, NULL) == -1);
+    transport_write_error_at = -1;
+
+    /* test set operation s*/
+    g_assert (thrift_compact_protocol_write_set_begin (protocol, T_DOUBLE,
+                                                    1, NULL) > 0);
+    g_assert (thrift_compact_protocol_write_set_end (protocol, NULL) == 0);
+
+    /* invalid protocol */
+    g_assert (thrift_compact_protocol_write_byte (protocol, 0, NULL) > 0);
+
+    /* invalid version */
+    g_assert (thrift_compact_protocol_write_byte (protocol, (gint8) 0x82u,
+                                                NULL) > 0);
+    g_assert (thrift_compact_protocol_write_byte (protocol, 0, NULL) > 0);
+
+    /* send a valid message */
+    g_assert (thrift_compact_protocol_write_byte (protocol, (gint8) 0x82u,
+                                                NULL) > 0);
+    g_assert (thrift_compact_protocol_write_byte (protocol, 0x01u, NULL) > 0);
+    thrift_compact_protocol_write_varint32 (tc, 1, NULL);
+    thrift_compact_protocol_write_string (protocol, "test", NULL);
+
+    /* broken 2nd read */
+    thrift_compact_protocol_write_byte (protocol, (gint8) 0x82u, NULL);
+
+    /* send a broken 3rd read */
+    thrift_compact_protocol_write_byte (protocol, (gint8) 0x82u, NULL);
+    thrift_compact_protocol_write_byte (protocol, 0x01u, NULL);
+
+    /* send a broken 4th read */
+    thrift_compact_protocol_write_byte (protocol, (gint8) 0x82u, NULL);
+    thrift_compact_protocol_write_byte (protocol, 0x01u, NULL);
+    thrift_compact_protocol_write_varint32 (tc, 1, NULL);
+
+    /* send a valid message */
+    g_assert (thrift_compact_protocol_write_message_begin (protocol, "test",
+                                                        T_CALL, 1, NULL) > 0);
+
+    g_assert (thrift_compact_protocol_write_message_end (protocol, NULL) == 0);
+
+    /* send broken writes */
+    transport_write_error = 1;
+    g_assert (thrift_compact_protocol_write_message_begin (protocol, "test",
+                                                        T_CALL, 1, NULL) == -1);
+    transport_write_error = 0;
+
+    transport_write_count = 0;
+    transport_write_error_at = 1;
+    g_assert (thrift_compact_protocol_write_message_begin (protocol, "test",
+                                                        T_CALL, 1, NULL) == -1);
+    transport_write_error_at = -1;
+
+    transport_write_count = 0;
+    transport_write_error_at = 2;
+    g_assert (thrift_compact_protocol_write_message_begin (protocol, "test",
+                                                        T_CALL, 1, NULL) == -1);
+    transport_write_error_at = -1;
+
+    transport_write_count = 0;
+    transport_write_error_at = 3;
+    g_assert (thrift_compact_protocol_write_message_begin (protocol, "test",
+                                                        T_CALL, 1, NULL) == -1);
+    transport_write_error_at = -1;
+
+    /* clean up */
+    thrift_transport_close (transport, NULL);
+    g_object_unref (tsocket);
+    g_object_unref (protocol);
+    g_assert (wait (&status) == pid);
+    g_assert (status == 0);
+  }
+}
+
+static void
+test_read_and_write_many_frames (void)
+{
+  int status;
+  pid_t pid;
+  ThriftSocket *tsocket = NULL;
+  ThriftTransport *transport = NULL;
+  ThriftFramedTransport *ft = NULL;
+  ThriftCompactProtocol *tc = NULL;
+  ThriftProtocol *protocol = NULL;
+  gpointer binary = (gpointer *) TEST_STRING;
+  const guint32 len = strlen (TEST_STRING);
+  int port = TEST_PORT;
+
+  /* fork a server from the client */
+  pid = fork ();
+  g_assert (pid >= 0);
+
+  if (pid == 0)
+  {
+    /* child listens */
+    thrift_server_many_frames (port);
+    exit (0);
+  } else {
+    /* parent.  wait a bit for the socket to be created. */
+    sleep (1);
+
+    /* create a ThriftSocket */
+    tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                            "port", port, NULL);
+    g_assert (tsocket != NULL);
+    transport = THRIFT_TRANSPORT (tsocket);
+
+    /* wrap in a framed transport */
+    ft = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, "transport", transport,
+                       "w_buf_size", 1, NULL);
+    g_assert (ft != NULL);
+    transport = THRIFT_TRANSPORT (ft);
+
+    thrift_transport_open (transport, NULL);
+    g_assert (thrift_transport_is_open (transport));
+
+    /* create a compact protocol */
+    tc = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, "transport",
+                       transport, NULL);
+    protocol = THRIFT_PROTOCOL (tc);
+    g_assert (protocol != NULL);
+
+    /* write a bunch of primitives */
+    g_assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL,
+                                                NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_byte (protocol, TEST_BYTE,
+                                                NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_i16 (protocol, TEST_I16, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_i32 (protocol, TEST_I32, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_i64 (protocol, TEST_I64, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_i16 (protocol, TEST_NI16, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_i32 (protocol, TEST_NI32, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_i64 (protocol, TEST_NI64, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_i16 (protocol, 2, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_i32 (protocol, 2, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_i64 (protocol, 2, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_i16 (protocol, -2, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_i32 (protocol, -2, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_i64 (protocol, -2, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_double (protocol,
+                                                 TEST_DOUBLE, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_string (protocol,
+                                                 TEST_STRING, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_string (protocol, "", NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_binary (protocol, binary,
+                                                 len, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_binary (protocol, NULL,
+                                                  0, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+    g_assert (thrift_compact_protocol_write_binary (protocol, binary,
+                                                 len, NULL) > 0);
+    thrift_transport_flush (transport, NULL);
+
+    /* clean up */
+    thrift_transport_write_end (transport, NULL);
+    thrift_transport_close (transport, NULL);
+    g_object_unref (ft);
+    g_object_unref (tsocket);
+    g_object_unref (tc);
+    g_assert (wait (&status) == pid);
+    g_assert (status == 0);
+  }
+}
+
+
+static void
+thrift_server_primitives (const int port)
+{
+  ThriftServerTransport *transport = NULL;
+  ThriftTransport *client = NULL;
+  ThriftCompactProtocol *tc = NULL;
+  ThriftProtocol *protocol = NULL;
+  gboolean value_boolean = FALSE;
+  gint8 value_byte = 0,
+    zigzag_p16 = 0, zigzag_p32 = 0, zigzag_p64 = 0,
+    zigzag_n16 = 0, zigzag_n32 = 0, zigzag_n64 = 0;
+  gint16 value_16 = 0;
+  gint32 value_32 = 0;
+  gint64 value_64 = 0;
+  gint16 value_n16 = 0;
+  gint32 value_n32 = 0;
+  gint64 value_n64 = 0;
+  gdouble value_double = 0;
+  gchar *string = NULL;
+  gchar *empty_string = NULL;
+  gpointer binary = NULL;
+  guint32 len = 0;
+  void *comparator = (void *) TEST_STRING;
+
+  ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+                                              "port", port, NULL);
+  transport = THRIFT_SERVER_TRANSPORT (tsocket);
+  thrift_server_transport_listen (transport, NULL);
+  client = thrift_server_transport_accept (transport, NULL);
+  g_assert (client != NULL);
+
+  tc = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, "transport",
+                      client, NULL);
+  protocol = THRIFT_PROTOCOL (tc);
+
+  g_assert (thrift_compact_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &value_byte, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_i16 (protocol, &value_16, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_i32 (protocol, &value_32, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_i64 (protocol, &value_64, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_i16 (protocol, &value_n16, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_i32 (protocol, &value_n32, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_i64 (protocol, &value_n64, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &zigzag_p16, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &zigzag_p32, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &zigzag_p64, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &zigzag_n16, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &zigzag_n32, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &zigzag_n64, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_double (protocol,
+                                              &value_double, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_string (protocol, &string, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_string (protocol, &empty_string,
+                                               NULL) > 0);
+  g_assert (thrift_compact_protocol_read_binary (protocol, &binary,
+                                              &len, NULL) > 0);
+
+  g_assert (value_boolean == TEST_BOOL);
+  g_assert (value_byte == TEST_BYTE);
+  g_assert (value_16 == TEST_I16);
+  g_assert (value_32 == TEST_I32);
+  g_assert (value_64 == TEST_I64);
+  g_assert (value_n16 == TEST_NI16);
+  g_assert (value_n32 == TEST_NI32);
+  g_assert (value_n64 == TEST_NI64);
+  g_assert (zigzag_p16 == 4);
+  g_assert (zigzag_p32 == 4);
+  g_assert (zigzag_p64 == 4);
+  g_assert (zigzag_n16 == 3);
+  g_assert (zigzag_n32 == 3);
+  g_assert (zigzag_n64 == 3);
+  g_assert (value_double == TEST_DOUBLE);
+  g_assert (strcmp (TEST_STRING, string) == 0);
+  g_assert (strcmp ("", empty_string) == 0);
+  g_assert (memcmp (comparator, binary, len) == 0);
+
+  g_free (string);
+  g_free (empty_string);
+  g_free (binary);
+
+  g_assert (thrift_compact_protocol_read_binary (protocol, &binary,
+                                               &len, NULL) > 0);
+  g_assert (binary == NULL);
+  g_assert (len == 0);
+  g_free (binary);
+
+  transport_read_count = 0;
+  transport_read_error_at = 0;
+  g_assert (thrift_compact_protocol_read_binary (protocol, &binary,
+                                              &len, NULL) == -1);
+  transport_read_error_at = -1;
+
+  transport_read_count = 0;
+  transport_read_error_at = 1;
+  g_assert (thrift_compact_protocol_read_binary (protocol, &binary,
+                                              &len, NULL) == -1);
+  transport_read_error_at = -1;
+
+  transport_read_error = 1;
+  g_assert (thrift_compact_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) == -1);
+  g_assert (thrift_compact_protocol_read_byte (protocol,
+                                            &value_byte, NULL) == -1);
+  g_assert (thrift_compact_protocol_read_i16 (protocol,
+                                           &value_16, NULL) == -1);
+  g_assert (thrift_compact_protocol_read_i32 (protocol, &value_32, NULL) == -1);
+  g_assert (thrift_compact_protocol_read_i64 (protocol, &value_64, NULL) == -1);
+  g_assert (thrift_compact_protocol_read_i16 (protocol,
+                                           &value_n16, NULL) == -1);
+  g_assert (thrift_compact_protocol_read_i32 (protocol, &value_n32, NULL) == -1);
+  g_assert (thrift_compact_protocol_read_i64 (protocol, &value_n64, NULL) == -1);
+  g_assert (thrift_compact_protocol_read_double (protocol,
+                                              &value_double, NULL) == -1);
+  transport_read_error = 0;
+
+  /* test partial write failure */
+  thrift_protocol_read_i32 (protocol, &value_32, NULL);
+
+  thrift_transport_read_end (client, NULL);
+  thrift_transport_close (client, NULL);
+
+  g_object_unref (tc);
+  g_object_unref (client);
+  g_object_unref (tsocket);
+}
+
+static void
+thrift_server_complex_types (const int port)
+{
+  ThriftServerTransport *transport = NULL;
+  ThriftTransport *client = NULL;
+  ThriftCompactProtocol *tc = NULL;
+  ThriftProtocol *protocol = NULL;
+  gchar *struct_name = NULL;
+  gchar *field_name = NULL;
+  gchar *message_name = NULL;
+  ThriftType element_type, key_type, value_type, field_type;
+  ThriftMessageType message_type;
+  gboolean value_boolean = ! TEST_BOOL;
+  gint8 value = 0;
+  gint16 field_id = 0;
+  guint32 size = 0;
+  gint32 seqid = 0;
+  gint8 version_and_type = 0;
+  gint8 protocol_id = 0;
+
+  ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+                                              "port", port, NULL);
+  transport = THRIFT_SERVER_TRANSPORT (tsocket);
+  thrift_server_transport_listen (transport, NULL);
+  client = thrift_server_transport_accept (transport, NULL);
+  g_assert (client != NULL);
+
+  tc = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, "transport",
+                      client, NULL);
+  protocol = THRIFT_PROTOCOL (tc);
+
+  /* test struct operations */
+
+  thrift_compact_protocol_read_struct_begin (protocol, &struct_name, NULL);
+  thrift_compact_protocol_read_struct_end (protocol, NULL);
+
+  /* test field state w.r.t. deltas */
+
+  field_id = 0;
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) == 1);
+  g_assert (field_id == 1);
+  field_id = 0;
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) == 1);
+  g_assert (field_id == 16);
+  field_id = 0;
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) == 1);
+  g_assert (field_id == 17);
+  field_id = 0;
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) > 1);
+  g_assert (field_id == 15);
+  field_id = 0;
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) == 1);
+  g_assert (field_id == 30);
+  field_id = 0;
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) > 1);
+  g_assert (field_id == 46);
+  field_id = 0;
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) == 1);
+  g_assert (field_id == 47);
+  field_id = 0;
+
+  /* test field operations */
+
+  thrift_compact_protocol_read_field_begin (protocol, &field_name, &field_type,
+                                           &field_id, NULL);
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+
+  /* test field state w.r.t. structs */
+
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                                    &field_id, NULL) > 1);
+  g_assert (field_id == 1);
+  field_id = 0;
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                                    &field_id, NULL) == 1);
+  g_assert (field_id == 16);
+  field_id = 0;
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+
+  g_assert (thrift_compact_protocol_read_struct_begin (protocol,
+                                                     &struct_name, NULL) == 0);
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                                    &field_id, NULL) > 1);
+  g_assert (field_id == 17);
+  field_id = 0;
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+
+  g_assert (thrift_compact_protocol_read_struct_begin (protocol,
+                                                     &struct_name, NULL) == 0);
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                                    &field_id, NULL) > 1);
+  g_assert (field_id == 18);
+  field_id = 0;
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                                    &field_id, NULL) == 1);
+  g_assert (field_id == 19);
+  field_id = 0;
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+  g_assert (thrift_compact_protocol_read_struct_end (protocol, NULL) == 0);
+
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                                    &field_id, NULL) == 1);
+  g_assert (field_id == 18);
+  field_id = 0;
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                                    &field_id, NULL) == 1);
+  g_assert (field_id == 25);
+  field_id = 0;
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+  g_assert (thrift_compact_protocol_read_struct_end (protocol, NULL) == 0);
+
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                                    &field_id, NULL) == 1);
+  g_assert (field_id == 17);
+  field_id = 0;
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+
+  /* test field state w.r.t. bools */
+
+  /* deltas */
+  /* non-bool field -> bool field -> non-bool field */
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) == 1);
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) == 1);
+  g_assert (field_type == T_BOOL);
+  g_assert (thrift_compact_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) == 0);
+  g_assert (value_boolean == TEST_BOOL);
+  value_boolean = ! TEST_BOOL;
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) == 1);
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+  /* bool -> bool field -> bool */
+  g_assert (thrift_compact_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) > 0);
+  g_assert (value_boolean == TEST_BOOL);
+  value_boolean = ! TEST_BOOL;
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) == 1);
+  g_assert (field_type == T_BOOL);
+  g_assert (thrift_compact_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) == 0);
+  g_assert (value_boolean == TEST_BOOL);
+  value_boolean = ! TEST_BOOL;
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+  g_assert (thrift_compact_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) > 0);
+  g_assert (value_boolean == TEST_BOOL);
+  value_boolean = ! TEST_BOOL;
+
+  /* no deltas */
+  /* non-bool field -> bool field -> non-bool field */
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) > 1);
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) > 1);
+  g_assert (field_type == T_BOOL);
+  g_assert (thrift_compact_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) == 0);
+  g_assert (value_boolean == TEST_BOOL);
+  value_boolean = ! TEST_BOOL;
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) > 1);
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+  /* bool -> bool field -> bool */
+  g_assert (thrift_compact_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) > 0);
+  g_assert (value_boolean == TEST_BOOL);
+  value_boolean = ! TEST_BOOL;
+  g_assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+                                                    &field_type,
+                                           &field_id, NULL) > 1);
+  g_assert (field_type == T_BOOL);
+  g_assert (thrift_compact_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) == 0);
+  g_assert (value_boolean == TEST_BOOL);
+  value_boolean = ! TEST_BOOL;
+  thrift_compact_protocol_read_field_end (protocol, NULL);
+  g_assert (thrift_compact_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) > 0);
+  g_assert (value_boolean == TEST_BOOL);
+  value_boolean = ! TEST_BOOL;
+
+  /* test first read error on a field */
+  transport_read_error = 1;
+  g_assert (thrift_compact_protocol_read_field_begin (protocol,
+                                                   &field_name, &field_type,
+                                                   &field_id, NULL) == -1);
+  transport_read_error = 0;
+
+  /* test 2nd write failure */
+  thrift_compact_protocol_read_byte (protocol, &value, NULL);
+
+  /* test 2nd read failure on a field */
+  transport_read_count = 0;
+  transport_read_error_at = 1;
+  g_assert (thrift_compact_protocol_read_field_begin (protocol,
+                                                   &field_name, &field_type,
+                                                   &field_id, NULL) == -1);
+  transport_read_error_at = -1;
+
+  /* test field stop */
+  thrift_compact_protocol_read_field_begin (protocol, &field_name, &field_type,
+                                           &field_id, NULL);
+
+  /* test map operations */
+
+  thrift_compact_protocol_read_map_begin (protocol, &key_type, &value_type,
+                                         &size, NULL);
+  thrift_compact_protocol_read_map_end (protocol, NULL);
+
+  /* test 1st read failure on a map */
+  transport_read_count = 0;
+  transport_read_error_at = 0;
+  g_assert (thrift_compact_protocol_read_map_begin (protocol,
+                                                 &key_type, &value_type,
+                                                 &size, NULL) == -1);
+  transport_read_error_at = -1;
+
+  /* test 2nd read failure on a map */
+  transport_read_count = 0;
+  transport_read_error_at = 1;
+  g_assert (thrift_compact_protocol_read_map_begin (protocol,
+                                                 &key_type, &value_type,
+                                                 &size, NULL) == -1);
+  transport_read_error_at = -1;
+
+  /* test 1st write failure on map---nothing to do on our side */
+
+  /* test 2nd write failure */
+  thrift_compact_protocol_read_byte (protocol, &value, NULL);
+
+  /* test negative map size */
+  g_assert (thrift_compact_protocol_read_map_begin (protocol,
+                                                 &key_type, &value_type,
+                                                 &size, NULL) == -1);
+
+  /* test list operations */
+  thrift_compact_protocol_read_list_begin (protocol, &element_type, &size,
+                                           NULL);
+  thrift_compact_protocol_read_list_end (protocol, NULL);
+
+  /* test small list 1st read failure */
+  transport_read_error = 1;
+  g_assert (thrift_compact_protocol_read_list_begin (protocol, &element_type,
+                                                  &size, NULL) == -1);
+  transport_read_error = 0;
+
+  /* test big list 1st read failure */
+  transport_read_error = 1;
+  g_assert (thrift_compact_protocol_read_list_begin (protocol, &element_type,
+                                                  &size, NULL) == -1);
+  transport_read_error = 0;
+
+  /* test big list 2nd read failure */
+  transport_read_count = 0;
+  transport_read_error_at = 1;
+  thrift_compact_protocol_read_list_begin (protocol, &element_type, &size,
+                                           NULL);
+  transport_read_error_at = -1;
+
+  /* test negative list size failure */
+  thrift_compact_protocol_read_list_begin (protocol, &element_type, &size,
+                                           NULL);
+
+  /* test small list 1st write failure---nothing to do on our end */
+
+  /* test big list 1st write failure---nothing to do on our end */
+
+  /* test big list 2nd write failure */
+  thrift_compact_protocol_read_byte (protocol, &value, NULL);
+
+  /* test set operations */
+  thrift_compact_protocol_read_set_begin (protocol, &element_type, &size, NULL);
+  thrift_compact_protocol_read_set_end (protocol, NULL);
+
+  /* broken read */
+  transport_read_error = 1;
+  g_assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) == -1);
+  transport_read_error = 0;
+
+  /* invalid protocol */
+  g_assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) == -1);
+
+  /* invalid version */
+  g_assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) == -1);
+
+  /* read a valid message */
+  g_assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) > 0);
+  g_free (message_name);
+
+  /* broken 2nd read on a message */
+  transport_read_count = 0;
+  transport_read_error_at = 1;
+  g_assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) == -1);
+  transport_read_error_at = -1;
+
+  /* broken 3rd read on a message */
+  transport_read_count = 0;
+  transport_read_error_at = 2;
+  g_assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) == -1);
+  transport_read_error_at = -1;
+
+  /* broken 4th read on a message */
+  transport_read_count = 0;
+  transport_read_error_at = 3;
+  g_assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) == -1);
+  transport_read_error_at = -1;
+
+  /* read a valid message */
+  g_assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) > 0);
+  g_free (message_name);
+
+  g_assert (thrift_compact_protocol_read_message_end (protocol, NULL) == 0);
+
+  /* handle 2nd write failure on a message */
+  thrift_compact_protocol_read_byte (protocol, &protocol_id, NULL);
+
+  /* handle 3rd write failure on a message */
+  thrift_compact_protocol_read_byte (protocol, &protocol_id, NULL);
+  thrift_compact_protocol_read_byte (protocol, &version_and_type, NULL);
+
+  /* handle 4th write failure on a message */
+  thrift_compact_protocol_read_byte (protocol, &protocol_id, NULL);
+  thrift_compact_protocol_read_byte (protocol, &version_and_type, NULL);
+  thrift_compact_protocol_read_varint32 (tc, &seqid, NULL);
+
+  g_object_unref (client);
+  g_object_unref (tsocket);
+}
+
+static void
+thrift_server_many_frames (const int port)
+{
+  ThriftServerTransport *transport = NULL;
+  ThriftTransport *client = NULL;
+  ThriftCompactProtocol *tcp = NULL;
+  ThriftProtocol *protocol = NULL;
+  ThriftServerSocket *tsocket = NULL;
+  gboolean value_boolean = FALSE;
+  gint8 value_byte = 0,
+    zigzag_p16 = 0, zigzag_p32 = 0, zigzag_p64 = 0,
+    zigzag_n16 = 0, zigzag_n32 = 0, zigzag_n64 = 0;
+  gint16 value_16 = 0;
+  gint32 value_32 = 0;
+  gint64 value_64 = 0;
+  gint16 value_n16 = 0;
+  gint32 value_n32 = 0;
+  gint64 value_n64 = 0;
+  gdouble value_double = 0;
+  gchar *string = NULL;
+  gchar *empty_string = NULL;
+  gpointer binary = NULL;
+  guint32 len = 0;
+  void *comparator = (void *) TEST_STRING;
+
+  tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET, "port", port, NULL);
+  transport = THRIFT_SERVER_TRANSPORT (tsocket);
+  thrift_server_transport_listen (transport, NULL);
+
+  /* wrap the client in a framed transport */
+  client = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, "transport",
+                         thrift_server_transport_accept (transport, NULL),
+                         "r_buf_size", 1, NULL);
+  g_assert (client != NULL);
+
+  tcp = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, "transport",
+                      client, NULL);
+  protocol = THRIFT_PROTOCOL (tcp);
+
+  g_assert (thrift_compact_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &value_byte, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_i16 (protocol, &value_16, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_i32 (protocol, &value_32, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_i64 (protocol, &value_64, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_i16 (protocol, &value_n16, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_i32 (protocol, &value_n32, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_i64 (protocol, &value_n64, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &zigzag_p16, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &zigzag_p32, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &zigzag_p64, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &zigzag_n16, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &zigzag_n32, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_byte (protocol, &zigzag_n64, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_double (protocol,
+                                              &value_double, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_string (protocol, &string, NULL) > 0);
+  g_assert (thrift_compact_protocol_read_string (protocol, &empty_string,
+                                               NULL) > 0);
+  g_assert (thrift_compact_protocol_read_binary (protocol, &binary,
+                                              &len, NULL) > 0);
+
+  g_assert (value_boolean == TEST_BOOL);
+  g_assert (value_byte == TEST_BYTE);
+  g_assert (value_16 == TEST_I16);
+  g_assert (value_32 == TEST_I32);
+  g_assert (value_64 == TEST_I64);
+  g_assert (value_n16 == TEST_NI16);
+  g_assert (value_n32 == TEST_NI32);
+  g_assert (value_n64 == TEST_NI64);
+  g_assert (zigzag_p16 == 4);
+  g_assert (zigzag_p32 == 4);
+  g_assert (zigzag_p64 == 4);
+  g_assert (zigzag_n16 == 3);
+  g_assert (zigzag_n32 == 3);
+  g_assert (zigzag_n64 == 3);
+  g_assert (value_double == TEST_DOUBLE);
+  g_assert (strcmp (TEST_STRING, string) == 0);
+  g_assert (strcmp ("", empty_string) == 0);
+  g_assert (memcmp (comparator, binary, len) == 0);
+
+  g_free (string);
+  g_free (empty_string);
+  g_free (binary);
+
+  g_assert (thrift_compact_protocol_read_binary (protocol, &binary,
+                                               &len, NULL) > 0);
+  g_assert (binary == NULL);
+  g_assert (len == 0);
+  g_free (binary);
+
+  thrift_transport_read_end (client, NULL);
+  thrift_transport_close (client, NULL);
+
+  g_object_unref (tcp);
+  g_object_unref (client);
+  g_object_unref (tsocket);
+}
+
+int
+main (int argc, char *argv[])
+{
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init ();
+#endif
+
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/testcompactprotocol/CreateAndDestroy",
+                   test_create_and_destroy);
+  g_test_add_func ("/testcompactprotocol/Initialize", test_initialize);
+  g_test_add_func ("/testcompactprotocol/ReadAndWritePrimitives",
+                   test_read_and_write_primitives);
+  g_test_add_func ("/testcompactprotocol/ReadAndWriteComplexTypes",
+                   test_read_and_write_complex_types);
+  g_test_add_func ("/testcompactprotocol/ReadAndWriteManyFrames",
+                   test_read_and_write_many_frames);
+
+  return g_test_run ();
+}
diff --git a/lib/c_glib/test/testcontainertest.c b/lib/c_glib/test/testcontainertest.c
new file mode 100644
index 0000000..5fc51d5
--- /dev/null
+++ b/lib/c_glib/test/testcontainertest.c
@@ -0,0 +1,529 @@
+/*
+ * 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.
+ */
+
+#include "gen-c_glib/t_test_container_test_types.h"
+#include "gen-c_glib/t_test_container_service.h"
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/protocol/thrift_binary_protocol_factory.h>
+#include <thrift/c_glib/protocol/thrift_binary_protocol.h>
+#include <thrift/c_glib/protocol/thrift_protocol_factory.h>
+#include <thrift/c_glib/server/thrift_server.h>
+#include <thrift/c_glib/server/thrift_simple_server.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport_factory.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport.h>
+#include <thrift/c_glib/transport/thrift_server_socket.h>
+#include <thrift/c_glib/transport/thrift_server_transport.h>
+#include <thrift/c_glib/transport/thrift_socket.h>
+
+#include <glib-object.h>
+#include <glib.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#define TEST_SERVER_HOSTNAME "localhost"
+#define TEST_SERVER_PORT     9090
+
+/* --------------------------------------------------------------------------
+   The ContainerService handler we'll use for testing */
+
+G_BEGIN_DECLS
+
+GType test_container_service_handler_get_type (void);
+
+#define TYPE_TEST_CONTAINER_SERVICE_HANDLER \
+  (test_container_service_handler_get_type ())
+
+#define TEST_CONTAINER_SERVICE_HANDLER(obj)                             \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                                   \
+                               TYPE_TEST_CONTAINER_SERVICE_HANDLER,     \
+                               TestContainerServiceHandler))
+#define TEST_CONTAINER_SERVICE_HANDLER_CLASS(c)                         \
+  (G_TYPE_CHECK_CLASS_CAST ((c),                                        \
+                            TYPE_TEST_CONTAINER_SERVICE_HANDLER,        \
+                            TestContainerServiceHandlerClass))
+#define IS_TEST_CONTAINER_SERVICE_HANDLER(obj)                          \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                                   \
+                               TYPE_TEST_CONTAINER_SERVICE_HANDLER))
+#define IS_TEST_CONTAINER_SERVICE_HANDLER_CLASS(c)                      \
+  (G_TYPE_CHECK_CLASS_TYPE ((c),                                        \
+                            TYPE_TEST_CONTAINER_SERVICE_HANDLER))
+#define TEST_CONTAINER_SERVICE_HANDLER_GET_CLASS(obj)                   \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                                    \
+                              TYPE_TEST_CONTAINER_SERVICE_HANDLER,      \
+                              TestContainerServiceHandlerClass))
+
+struct _TestContainerServiceHandler {
+  TTestContainerServiceHandler parent_instance;
+
+  /* private */
+  GPtrArray *string_list;
+};
+typedef struct _TestContainerServiceHandler TestContainerServiceHandler;
+
+struct _TestContainerServiceHandlerClass {
+  TTestContainerServiceHandlerClass parent_class;
+};
+typedef struct _TestContainerServiceHandlerClass
+  TestContainerServiceHandlerClass;
+
+G_END_DECLS
+
+/* -------------------------------------------------------------------------- */
+
+G_DEFINE_TYPE (TestContainerServiceHandler,
+               test_container_service_handler,
+               T_TEST_TYPE_CONTAINER_SERVICE_HANDLER)
+
+/* A helper function used to append copies of strings to a string list */
+static void append_string_to_ptr_array (gpointer element, gpointer ptr_array)
+{
+  g_ptr_array_add ((GPtrArray *)ptr_array, g_strdup ((gchar *)element));
+}
+
+/* Accept a string list from the client and append its contents to our internal
+   list */
+static gboolean
+test_container_service_handler_receive_string_list (TTestContainerServiceIf *iface,
+                                                    const GPtrArray *stringList,
+                                                    GError **error)
+{
+  TestContainerServiceHandler *self = TEST_CONTAINER_SERVICE_HANDLER (iface);
+
+  /* Append the client's strings to our own internal string list */
+  g_ptr_array_foreach ((GPtrArray *)stringList,
+                       append_string_to_ptr_array,
+                       self->string_list);
+
+  g_clear_error (error);
+  return TRUE;
+}
+
+/* Return the contents of our internal string list to the client */
+static gboolean
+test_container_service_handler_return_string_list (TTestContainerServiceIf *iface,
+                                                   GPtrArray **_return,
+                                                   GError **error)
+{
+  TestContainerServiceHandler *self = TEST_CONTAINER_SERVICE_HANDLER (iface);
+
+  /* Return (copies of) the strings contained in our list */
+  g_ptr_array_foreach (self->string_list,
+                       append_string_to_ptr_array,
+                       *_return);
+
+  g_clear_error (error);
+  return TRUE;
+}
+
+static gboolean
+test_container_service_handler_return_list_string_list (TTestContainerServiceIf *iface,
+                                                        GPtrArray **_return,
+                                                        GError **error)
+{
+  TestContainerServiceHandler *self = TEST_CONTAINER_SERVICE_HANDLER (iface);
+  GPtrArray *nested_list;
+
+  /* Return a list containing our list of strings */
+  nested_list
+    = g_ptr_array_new_with_free_func ((GDestroyNotify)g_ptr_array_unref);
+  g_ptr_array_add (nested_list, self->string_list);
+  g_ptr_array_ref (self->string_list);
+
+  g_ptr_array_add (*_return, nested_list);
+
+  g_clear_error (error);
+  return TRUE;
+}
+
+static gboolean
+test_container_service_handler_return_typedefd_list_string_list (TTestContainerServiceIf *iface,
+                                                                 TTestListStringList **_return,
+                                                                 GError **error)
+{
+  TestContainerServiceHandler *self = TEST_CONTAINER_SERVICE_HANDLER (iface);
+  TTestStringList *nested_list;
+
+  /* Return a list containing our list of strings */
+  nested_list
+    = g_ptr_array_new_with_free_func ((GDestroyNotify)g_ptr_array_unref);
+  g_ptr_array_add (nested_list, self->string_list);
+  g_ptr_array_ref (self->string_list);
+
+  g_ptr_array_add (*_return, nested_list);
+
+  g_clear_error (error);
+  return TRUE;
+}
+
+static void
+test_container_service_handler_finalize (GObject *object) {
+  TestContainerServiceHandler *self = TEST_CONTAINER_SERVICE_HANDLER (object);
+
+  /* Destroy our internal containers */
+  g_ptr_array_unref (self->string_list);
+  self->string_list = NULL;
+
+  G_OBJECT_CLASS (test_container_service_handler_parent_class)->
+    finalize (object);
+}
+
+static void
+test_container_service_handler_init (TestContainerServiceHandler *self)
+{
+  /* Create our internal containers */
+  self->string_list = g_ptr_array_new_with_free_func (g_free);
+}
+
+static void
+test_container_service_handler_class_init (TestContainerServiceHandlerClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  TTestContainerServiceHandlerClass *parent_class =
+    T_TEST_CONTAINER_SERVICE_HANDLER_CLASS (klass);
+
+  gobject_class->finalize = test_container_service_handler_finalize;
+
+  parent_class->receive_string_list =
+    test_container_service_handler_receive_string_list;
+  parent_class->return_string_list =
+    test_container_service_handler_return_string_list;
+  parent_class->return_list_string_list =
+    test_container_service_handler_return_list_string_list;
+  parent_class->return_typedefd_list_string_list =
+    test_container_service_handler_return_typedefd_list_string_list;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Our test server, declared globally so we can access it within a signal
+   handler */
+ThriftServer *server = NULL;
+
+/* A signal handler used to detect when the child process (the test suite) has
+   exited so we know to shut down the server and terminate ourselves */
+static void
+sigchld_handler (int signal_number)
+{
+  THRIFT_UNUSED_VAR (signal_number);
+
+  /* The child process (the tests) has exited or been terminated; shut down the
+     server gracefully */
+  if (server != NULL)
+    thrift_server_stop (server);
+}
+
+/* A helper function that executes a test case against a newly constructed
+   service client */
+static void
+execute_with_service_client (void (*test_case)(TTestContainerServiceIf *,
+                                               GError **))
+{
+  ThriftSocket *socket;
+  ThriftTransport *transport;
+  ThriftProtocol *protocol;
+
+  TTestContainerServiceIf *client;
+
+  GError *error = NULL;
+
+  /* Create a client with which to access the server */
+  socket    = g_object_new (THRIFT_TYPE_SOCKET,
+                            "hostname", TEST_SERVER_HOSTNAME,
+                            "port",     TEST_SERVER_PORT,
+                            NULL);
+  transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+                            "transport", socket,
+                            NULL);
+  protocol  = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
+                            "transport", transport,
+                            NULL);
+
+  thrift_transport_open (transport, &error);
+  g_assert_no_error (error);
+
+  client = g_object_new (T_TEST_TYPE_CONTAINER_SERVICE_CLIENT,
+                         "input_protocol",  protocol,
+                         "output_protocol", protocol,
+                         NULL);
+
+  /* Execute the test against this client */
+  (*test_case)(client, &error);
+  g_assert_no_error (error);
+
+  /* Clean up and exit */
+  thrift_transport_close (transport, NULL);
+
+  g_object_unref (client);
+  g_object_unref (protocol);
+  g_object_unref (transport);
+  g_object_unref (socket);
+}
+
+static void
+test_containers_with_default_values (void)
+{
+  TTestContainersWithDefaultValues *default_values;
+  GPtrArray *string_list;
+
+  /* Fetch a new ContainersWithDefaultValues struct and its StringList member */
+  default_values = g_object_new (T_TEST_TYPE_CONTAINERS_WITH_DEFAULT_VALUES,
+                                 NULL);
+  g_object_get (default_values,
+                "StringList", &string_list,
+                NULL);
+
+  /* Make sure the list has been populated with its default values */
+  g_assert_cmpint (string_list->len, ==, 2);
+  g_assert_cmpstr (((gchar **)string_list->pdata)[0], ==, "Apache");
+  g_assert_cmpstr (((gchar **)string_list->pdata)[1], ==, "Thrift");
+
+  g_ptr_array_unref (string_list);
+  g_object_unref (default_values);
+}
+
+static void
+test_container_service_string_list_inner (TTestContainerServiceIf *client,
+                                          GError **error)
+{
+  gchar *test_data[] = { "one", "two", "three" };
+
+  GPtrArray *outgoing_string_list;
+  GPtrArray *incoming_string_list;
+  guint index;
+
+  g_clear_error (error);
+
+  /* Prepare our test data (our string list to send) */
+  outgoing_string_list = g_ptr_array_new ();
+  for (index = 0; index < 3; index += 1)
+    g_ptr_array_add (outgoing_string_list, &test_data[index]);
+
+  /* Send our data to the server and make sure we get the same data back on
+     retrieve */
+  g_assert
+    (t_test_container_service_client_receive_string_list (client,
+                                                          outgoing_string_list,
+                                                          error) &&
+     *error == NULL);
+
+  incoming_string_list = g_ptr_array_new ();
+  g_assert
+    (t_test_container_service_client_return_string_list (client,
+                                                         &incoming_string_list,
+                                                         error) &&
+     *error == NULL);
+
+  /* Make sure the two lists are equivalent */
+  g_assert_cmpint (incoming_string_list->len, ==, outgoing_string_list->len);
+  for (index = 0; index < incoming_string_list->len; index += 1)
+    g_assert_cmpstr (((gchar **)incoming_string_list->pdata)[index],
+                     ==,
+                     ((gchar **)outgoing_string_list->pdata)[index]);
+
+  /* Clean up and exit */
+  g_ptr_array_unref (incoming_string_list);
+  g_ptr_array_unref (outgoing_string_list);
+}
+
+static void
+test_container_service_string_list (void)
+{
+    execute_with_service_client (test_container_service_string_list_inner);
+}
+
+static void
+test_container_service_list_string_list_inner (TTestContainerServiceIf *client,
+                                               GError **error)
+{
+  GPtrArray *incoming_list;
+  GPtrArray *nested_list;
+
+  g_clear_error (error);
+
+  /* Receive a list of string lists from the server */
+  incoming_list =
+    g_ptr_array_new_with_free_func ((GDestroyNotify)g_ptr_array_unref);
+  g_assert
+    (t_test_container_service_client_return_list_string_list (client,
+                                                              &incoming_list,
+                                                              error) &&
+     *error == NULL);
+
+  /* Make sure the list and its contents are valid */
+  g_assert_cmpint (incoming_list->len, >, 0);
+
+  nested_list = (GPtrArray *)g_ptr_array_index (incoming_list, 0);
+  g_assert (nested_list != NULL);
+  g_assert_cmpint (nested_list->len, >=, 0);
+
+  /* Clean up and exit */
+  g_ptr_array_unref (incoming_list);
+}
+
+static void
+test_container_service_list_string_list (void)
+{
+  execute_with_service_client (test_container_service_list_string_list_inner);
+}
+
+static void
+test_container_service_typedefd_list_string_list_inner (TTestContainerServiceIf *client,
+                                                        GError **error)
+{
+  TTestListStringList *incoming_list;
+  TTestStringList *nested_list;
+
+  g_clear_error (error);
+
+  /* Receive a list of string lists from the server */
+  incoming_list =
+    g_ptr_array_new_with_free_func ((GDestroyNotify)g_ptr_array_unref);
+  g_assert
+    (t_test_container_service_client_return_list_string_list (client,
+                                                              &incoming_list,
+                                                              error) &&
+     *error == NULL);
+
+  /* Make sure the list and its contents are valid */
+  g_assert_cmpint (incoming_list->len, >, 0);
+
+  nested_list = (TTestStringList *)g_ptr_array_index (incoming_list, 0);
+  g_assert (nested_list != NULL);
+  g_assert_cmpint (nested_list->len, >=, 0);
+
+  /* Clean up and exit */
+  g_ptr_array_unref (incoming_list);
+}
+
+static void
+test_container_service_typedefd_list_string_list (void)
+{
+  execute_with_service_client
+    (test_container_service_typedefd_list_string_list_inner);
+}
+
+int
+main(int argc, char *argv[])
+{
+  pid_t pid;
+  int status;
+
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init ();
+#endif
+
+  /* Fork to run our test suite in a child process */
+  pid = fork ();
+  g_assert_cmpint (pid, >=, 0);
+
+  if (pid == 0) {    /* The child process */
+    /* Wait a moment for the server to finish starting */
+    sleep (1);
+
+    g_test_init (&argc, &argv, NULL);
+
+    g_test_add_func
+      ("/testcontainertest/ContainerTest/Structs/ContainersWithDefaultValues",
+       test_containers_with_default_values);
+    g_test_add_func
+      ("/testcontainertest/ContainerTest/Services/ContainerService/StringList",
+       test_container_service_string_list);
+    g_test_add_func
+      ("/testcontainertest/ContainerTest/Services/ContainerService/ListStringList",
+       test_container_service_list_string_list);
+    g_test_add_func
+      ("/testcontainertest/ContainerTest/Services/ContainerService/TypedefdListStringList",
+       test_container_service_typedefd_list_string_list);
+
+    /* Run the tests and make the result available to our parent process */
+    _exit (g_test_run ());
+  }
+  else {
+    TTestContainerServiceHandler *handler;
+    TTestContainerServiceProcessor *processor;
+
+    ThriftServerTransport *server_transport;
+    ThriftTransportFactory *transport_factory;
+    ThriftProtocolFactory *protocol_factory;
+
+    struct sigaction sigchld_action;
+
+    GError *error = NULL;
+    int exit_status = 1;
+
+    /* Trap the event of the child process terminating so we know to stop the
+       server and exit */
+    memset (&sigchld_action, 0, sizeof (sigchld_action));
+    sigchld_action.sa_handler = sigchld_handler;
+    sigchld_action.sa_flags = SA_RESETHAND;
+    sigaction (SIGCHLD, &sigchld_action, NULL);
+
+    /* Create our test server */
+    handler = g_object_new (TYPE_TEST_CONTAINER_SERVICE_HANDLER,
+                            NULL);
+    processor = g_object_new (T_TEST_TYPE_CONTAINER_SERVICE_PROCESSOR,
+                              "handler", handler,
+                              NULL);
+    server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+                                     "port", TEST_SERVER_PORT,
+                                     NULL);
+    transport_factory = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY,
+                                      NULL);
+    protocol_factory = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL_FACTORY,
+                                     NULL);
+
+    server = g_object_new (THRIFT_TYPE_SIMPLE_SERVER,
+                           "processor",                processor,
+                           "server_transport",         server_transport,
+                           "input_transport_factory",  transport_factory,
+                           "output_transport_factory", transport_factory,
+                           "input_protocol_factory",   protocol_factory,
+                           "output_protocol_factory",  protocol_factory,
+                           NULL);
+
+    /* Start the server */
+    thrift_server_serve (server, &error);
+
+    /* Make sure the server stopped only because it was interrupted (by the
+       child process terminating) */
+    g_assert(!error || g_error_matches(error,
+                                       THRIFT_SERVER_SOCKET_ERROR,
+                                       THRIFT_SERVER_SOCKET_ERROR_ACCEPT));
+
+    /* Free our resources */
+    g_clear_object (&server);
+    g_clear_object (&protocol_factory);
+    g_clear_object (&transport_factory);
+    g_clear_object (&server_transport);
+    g_clear_object (&processor);
+    g_clear_object (&handler);
+
+    /* Wait for the child process to complete and return its exit status */
+    g_assert (wait (&status) == pid);
+    if (WIFEXITED (status))
+      exit_status = WEXITSTATUS (status);
+
+    return exit_status;
+  }
+}
diff --git a/lib/c_glib/test/testdebugproto.c b/lib/c_glib/test/testdebugproto.c
index 689e001..109a48b 100644
--- a/lib/c_glib/test/testdebugproto.c
+++ b/lib/c_glib/test/testdebugproto.c
@@ -18,76 +18,924 @@
  */
 
 #include <math.h>
+#include <string.h>
 #include <glib-object.h>
 
 #ifndef M_PI
 #define M_PI 3.1415926535897932385
 #endif
 
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/protocol/thrift_binary_protocol.h>
+
 #include "gen-c_glib/t_test_debug_proto_test_types.h"
+#include "gen-c_glib/t_test_srv.h"
+#include "gen-c_glib/t_test_inherited.h"
 
 static void
-test_debug_proto(void)
+test_structs_doubles_create_and_destroy (void)
 {
-  TTestOneOfEach *ooe = NULL;
-  TTestNesting *n = NULL;
-  TTestHolyMoley *hm = NULL;
-  gchar *random = g_strdup("random string");
-  gchar *nothing = g_strdup("nothing");
+  GObject *object = NULL;
 
-  ooe = g_object_new (T_TEST_TYPE_ONE_OF_EACH, NULL);
-  ooe->im_true = TRUE;
-  ooe->im_false = FALSE;
-  ooe->a_bite = 0xd6;
-  ooe->integer16 = 27000;
-  ooe->integer32 = 1<<24;
-  ooe->integer64 = (guint64) 6000 * 1000 * 1000;
-  ooe->double_precision = M_PI;
-  ooe->some_characters = g_strdup("Debug THIS!");
-  ooe->zomg_unicode = g_strdup("\xd7\n\a\t");
+  /* A Doubles structure can be created... */
+  object = g_object_new (T_TEST_TYPE_DOUBLES, NULL);
 
-  n = g_object_new (T_TEST_TYPE_NESTING, NULL);
-  if (n->my_ooe != NULL)
-    g_object_unref(n->my_ooe);
+  g_assert (object != NULL);
+  g_assert (T_TEST_IS_DOUBLES (object));
 
-  n->my_ooe = ooe;
-  n->my_ooe->integer16 = 16;
-  n->my_ooe->integer32 = 32;
-  n->my_ooe->integer64 = 64;
-  n->my_ooe->double_precision = (sqrt(5.0) + 1) / 2;
-  n->my_ooe->some_characters = g_strdup(":R (me going \"rrrr\")");
-  n->my_ooe->zomg_unicode = g_strdup("\xd3\x80\xe2\x85\xae\xce\x9d\x20");
-  n->my_bonk->type = 31337;
-  n->my_bonk->message = g_strdup("I am a bonk... xor!");
+  /* ...and destroyed */
+  g_object_unref (object);
+}
 
-  hm = g_object_new (T_TEST_TYPE_HOLY_MOLEY, NULL);
-  g_ptr_array_add (hm->big, ooe);
-  g_ptr_array_add (hm->big, g_object_ref(n->my_ooe));
-  ((TTestOneOfEach *) g_ptr_array_index (hm->big, 0))->a_bite = 0x22;
-  ((TTestOneOfEach *) g_ptr_array_index (hm->big, 1))->a_bite = 0x33;
+static void
+test_structs_doubles_initialize (void)
+{
+  TTestDoubles *doubles = NULL;
+  gdouble nan;
+  gdouble inf;
+  gdouble neginf;
+  gdouble repeating;
+  gdouble big;
+  gdouble tiny;
+  gdouble zero;
+  gdouble negzero;
 
-  g_hash_table_insert (hm->contain, random, random);
+  /* Note there seems to be no way to get not-a-number ("NAN") values past
+     GObject's range-checking, so that portion of the test has been commented
+     out below. */
 
+  /* A Doubles structure's members are available as GObject properties
+     that can be initialized at construction... */
+  doubles = g_object_new (T_TEST_TYPE_DOUBLES,
+                          /* "nan",      0 * INFINITY, */
+                          "inf",          INFINITY,
+                          "neginf",      -INFINITY,
+                          "repeating",     1.0 / 3,
+                          "big",       G_MAXDOUBLE,
+                          "tiny",          10E-101,
+                          "zero",          1.0 * 0,
+                          "negzero",      -1.0 * 0,
+                          NULL);
+
+  g_assert (doubles != NULL);
+
+  /* ...and later retrieved */
+  g_object_get (doubles,
+                "nan",       &nan,
+                "inf",       &inf,
+                "neginf",    &neginf,
+                "repeating", &repeating,
+                "big",       &big,
+                "tiny",      &tiny,
+                "zero",      &zero,
+                "negzero",   &negzero,
+                NULL);
+
+  /* g_assert_cmpint (isnan (nan),    !=,  0); */
+  g_assert_cmpint (isinf (inf),    ==,  1);
+  g_assert_cmpint (isinf (neginf), ==, -1);
+
+  g_assert_cmpfloat (repeating, ==,     1.0 / 3);
+  g_assert_cmpfloat (big,       ==, G_MAXDOUBLE);
+  g_assert_cmpfloat (tiny,      ==,     10E-101);
+  g_assert_cmpfloat (zero,      ==,     1.0 * 0);
+  g_assert_cmpfloat (negzero,   ==,    -1.0 * 0);
+
+  g_object_unref (doubles);
+}
+
+static void
+test_structs_one_of_each_create_and_destroy (void)
+{
+  GObject *object = NULL;
+
+  /* A OneOfEach structure can be created... */
+  object = g_object_new (T_TEST_TYPE_ONE_OF_EACH, NULL);
+
+  g_assert (object != NULL);
+  g_assert (T_TEST_IS_ONE_OF_EACH (object));
+
+  /* ...and destroyed */
+  g_object_unref (object);
+}
+
+static void
+test_structs_one_of_each_initialize_default_values (void)
+{
+  TTestOneOfEach *one_of_each = NULL;
+  gint   a_bite;
+  gint   integer16;
+  gint64 integer64;
+  GArray *byte_list;
+  GArray *i16_list;
+  GArray *i64_list;
+
+  /* A OneOfEach structure created with no explicit property values
+     will hold the default values specified in the .thrift file */
+  one_of_each = g_object_new (T_TEST_TYPE_ONE_OF_EACH, NULL);
+
+  g_object_get (one_of_each,
+                "a_bite",    &a_bite,
+                "integer16", &integer16,
+                "integer64", &integer64,
+                "byte_list", &byte_list,
+                "i16_list",  &i16_list,
+                "i64_list",  &i64_list,
+                NULL);
+
+  g_assert_cmpint (a_bite,    ==, 0x7f);
+  g_assert_cmpint (integer16, ==, 0x7fff);
+  g_assert_cmpint (integer64, ==, G_GINT64_CONSTANT (10000000000));
+
+  g_assert (byte_list != NULL);
+  g_assert_cmpint (byte_list->len, ==, 3);
+  g_assert_cmpint (g_array_index (byte_list, gint8, 0), ==, 1);
+  g_assert_cmpint (g_array_index (byte_list, gint8, 1), ==, 2);
+  g_assert_cmpint (g_array_index (byte_list, gint8, 2), ==, 3);
+
+  g_assert (i16_list != NULL);
+  g_assert_cmpint (i16_list->len, ==, 3);
+  g_assert_cmpint (g_array_index (i16_list, gint16, 0), ==, 1);
+  g_assert_cmpint (g_array_index (i16_list, gint16, 1), ==, 2);
+  g_assert_cmpint (g_array_index (i16_list, gint16, 2), ==, 3);
+
+  g_assert (i64_list != NULL);
+  g_assert_cmpint (i64_list->len, ==, 3);
+  g_assert_cmpint (g_array_index (i64_list, gint64, 0), ==, 1);
+  g_assert_cmpint (g_array_index (i64_list, gint64, 1), ==, 2);
+  g_assert_cmpint (g_array_index (i64_list, gint64, 2), ==, 3);
+
+  g_array_unref (i64_list);
+  g_array_unref (i16_list);
+  g_array_unref (byte_list);
+  g_object_unref (one_of_each);
+}
+
+static void
+test_structs_one_of_each_initialize_specified_values (void)
+{
+  static const gint8 initial_byte_list[5] = { 13, 21, 34, 55, 89 };
+  static const gint16 initial_i16_list[5] = { 4181, 6765, 10946, 17711, 28657 };
+  static const gint64 initial_i64_list[5] =
+    {
+      G_GINT64_CONSTANT (1100087778366101931),
+      G_GINT64_CONSTANT (1779979416004714189),
+      G_GINT64_CONSTANT (2880067194370816120),
+      G_GINT64_CONSTANT (4660046610375530309),
+      G_GINT64_CONSTANT (7540113804746346429)
+    };
+  static const guint8 initial_base64[8] =
+    {
+      0x56, 0x47, 0x68, 0x79, 0x61, 0x57, 0x5a, 0x30
+    };
+
+  TTestOneOfEach *one_of_each;
+  gboolean im_true;
+  gboolean im_false;
+  gint a_bite;
+  gint integer16;
+  gint integer32;
+  gint64 integer64;
+  double double_precision;
+  gchar *some_characters;
+  gchar *zomg_unicode;
+  gboolean what_who;
+  GByteArray *base64;
+  GArray *byte_list;
+  GArray *i16_list;
+  GArray *i64_list;
+
+  base64 = g_byte_array_new ();
+  g_byte_array_append (base64, initial_base64, 8);
+
+  byte_list = g_array_new (FALSE, FALSE, sizeof (gint8));
+  g_array_append_vals (byte_list, initial_byte_list, 5);
+
+  i16_list = g_array_new (FALSE, FALSE, sizeof (gint16));
+  g_array_append_vals (i16_list, initial_i16_list, 5);
+
+  i64_list = g_array_new (FALSE, FALSE, sizeof (gint64));
+  g_array_append_vals (i64_list, initial_i64_list, 5);
+
+  /* All of OneOfEach's properties can be set at construction... */
+  one_of_each =
+    g_object_new (T_TEST_TYPE_ONE_OF_EACH,
+                  "im_true",          TRUE,
+                  "im_false",         FALSE,
+                  "a_bite",           0x50,
+                  "integer16",        0x7e57,
+                  "integer32",        0xdeadbeef,
+                  "integer64",        G_GINT64_CONSTANT (0xfa15efacade15bad),
+                  "double_precision", M_PI,
+                  "some_characters",  "Debug THIS!",
+                  "zomg_unicode",     "\xd7\n\a\t",
+                  "what_who",         TRUE,
+                  "base64",           base64,
+                  "byte_list",        byte_list,
+                  "i16_list",         i16_list,
+                  "i64_list",         i64_list,
+                  NULL);
+  g_assert (one_of_each != NULL);
+
+  g_array_unref (i64_list);
+  i64_list = NULL;
+  g_array_unref (i16_list);
+  i16_list = NULL;
+  g_array_unref (byte_list);
+  byte_list = NULL;
+  g_byte_array_unref (base64);
+  base64 = NULL;
+
+  /* ...and later retrieved */
+  g_object_get (one_of_each,
+                "im_true",          &im_true,
+                "im_false",         &im_false,
+                "a_bite",           &a_bite,
+                "integer16",        &integer16,
+                "integer32",        &integer32,
+                "integer64",        &integer64,
+                "double_precision", &double_precision,
+                "some_characters",  &some_characters,
+                "zomg_unicode",     &zomg_unicode,
+                "what_who",         &what_who,
+                "base64",           &base64,
+                "byte_list",        &byte_list,
+                "i16_list",         &i16_list,
+                "i64_list",         &i64_list,
+                NULL);
+
+  g_assert (im_true  == TRUE);
+  g_assert (im_false == FALSE);
+
+  g_assert_cmphex (a_bite,    ==, 0x50);
+  g_assert_cmphex (integer16, ==, 0x7e57);
+  g_assert_cmphex (integer32, ==, (gint32)0xdeadbeef);
+  g_assert_cmphex (integer64, ==, G_GINT64_CONSTANT (0xfa15efacade15bad));
+
+  g_assert_cmpfloat (double_precision, ==, M_PI);
+
+  g_assert_cmpstr (some_characters, ==, "Debug THIS!");
+  g_assert_cmpstr (zomg_unicode,    ==, "\xd7\n\a\t");
+
+  g_assert (what_who == TRUE);
+
+  g_assert_cmpint (base64->len, ==, 8);
+  g_assert_cmpint (memcmp (base64->data,
+                           initial_base64,
+                           8 * sizeof (guint8)), ==, 0);
+
+  g_assert_cmpint (byte_list->len, ==, 5);
+  g_assert_cmpint (memcmp (byte_list->data,
+                           initial_byte_list,
+                           5 * sizeof (gint8)),  ==, 0);
+
+  g_assert_cmpint (i16_list->len, ==, 5);
+  g_assert_cmpint (memcmp (i16_list->data,
+                           initial_i16_list,
+                           5 * sizeof (gint16)), ==, 0);
+
+  g_assert_cmpint (i64_list->len, ==, 5);
+  g_assert_cmpint (memcmp (i64_list->data,
+                           initial_i64_list,
+                           5 * sizeof (gint64)), ==, 0);
+
+  g_array_unref (i64_list);
+  g_array_unref (i16_list);
+  g_array_unref (byte_list);
+  g_byte_array_unref (base64);
+
+  g_object_unref (one_of_each);
+}
+
+static void
+test_structs_one_of_each_properties_byte_list (void)
+{
+  TTestOneOfEach *one_of_each;
+  GArray *byte_list = NULL;
+
+  one_of_each = g_object_new (T_TEST_TYPE_ONE_OF_EACH, NULL);
+
+  /* OneOfEach's "byte_list" member is a list that holds eight-bit-wide integer
+     values */
+  g_object_get (one_of_each, "byte_list", &byte_list, NULL);
+
+  g_assert (byte_list != NULL);
+  g_assert_cmpint (g_array_get_element_size (byte_list), ==, sizeof (gint8));
+
+  g_array_unref (byte_list);
+  g_object_unref (one_of_each);
+}
+
+static void
+test_structs_one_of_each_properties_i16_list (void)
+{
+  TTestOneOfEach *one_of_each;
+  GArray *i16_list = NULL;
+
+  one_of_each = g_object_new (T_TEST_TYPE_ONE_OF_EACH, NULL);
+
+  /* OneOfEach's "i16_list" member is a list that holds sixteen-bit-wide integer
+     values */
+  g_object_get (one_of_each, "i16_list", &i16_list, NULL);
+
+  g_assert (i16_list != NULL);
+  g_assert_cmpint (g_array_get_element_size (i16_list), ==, sizeof (gint16));
+
+  g_array_unref (i16_list);
+  g_object_unref (one_of_each);
+}
+
+static void
+test_structs_one_of_each_properties_i64_list (void)
+{
+  TTestOneOfEach *one_of_each;
+  GArray *i64_list = NULL;
+
+  one_of_each = g_object_new (T_TEST_TYPE_ONE_OF_EACH, NULL);
+
+  /* OneOfEach's "i64_list" member is a list that holds sixty-four-bit-wide
+     integer values */
+  g_object_get (one_of_each, "i64_list", &i64_list, NULL);
+
+  g_assert (i64_list != NULL);
+  g_assert_cmpint (g_array_get_element_size (i64_list), ==, sizeof (gint64));
+
+  g_array_unref (i64_list);
+  g_object_unref (one_of_each);
+}
+
+static void
+test_structs_nesting_create_and_destroy (void)
+{
+  GObject *object = NULL;
+
+  /* A Nesting structure can be created... */
+  object = g_object_new (T_TEST_TYPE_NESTING, NULL);
+
+  g_assert (object != NULL);
+  g_assert (T_TEST_IS_NESTING (object));
+
+  /* ...and destroyed */
+  g_object_unref (object);
+}
+
+static void
+test_structs_nesting_properties_my_bonk (void)
+{
+  TTestNesting *nesting;
   TTestBonk *bonk = NULL;
-  bonk = g_object_new (T_TEST_TYPE_BONK, NULL);
-  GPtrArray *bonks = g_ptr_array_new_with_free_func (g_object_unref);
-  g_ptr_array_add (bonks, bonk);
-  g_hash_table_insert (hm->bonks, nothing, bonks);
+  gint type;
+  gchar *message;
 
-  g_object_unref (hm);
+  nesting = g_object_new (T_TEST_TYPE_NESTING, NULL);
 
-  return 0;
+  /* Nesting's "my_bonk" member is initialized with a new, default Bonk object
+     during construction */
+  g_object_get (nesting, "my_bonk", &bonk, NULL);
+
+  g_assert (bonk != NULL);
+  g_assert (T_TEST_IS_BONK (bonk));
+
+  g_object_get (bonk,
+                "type",    &type,
+                "message", &message,
+                NULL);
+
+  g_assert_cmpint (type, ==, 0);
+  g_assert (message == NULL);
+
+  g_object_unref (bonk);
+  bonk = NULL;
+
+  /* It can be replaced... */
+  bonk = g_object_new (T_TEST_TYPE_BONK,
+                       "type",    100,
+                       "message", "Replacement Bonk",
+                       NULL);
+  g_object_set (nesting, "my_bonk", bonk, NULL);
+  g_object_unref (bonk);
+  bonk = NULL;
+
+  g_object_get (nesting, "my_bonk", &bonk, NULL);
+
+  g_assert (bonk != NULL);
+  g_assert (T_TEST_IS_BONK (bonk));
+
+  g_object_get (bonk,
+                "type",    &type,
+                "message", &message,
+                NULL);
+
+  g_assert_cmpint (type, ==, 100);
+  g_assert_cmpstr (message, ==, "Replacement Bonk");
+
+  g_free (message);
+  g_object_unref (bonk);
+  bonk = NULL;
+
+  /* ...or set to null */
+  g_object_set (nesting, "my_bonk", NULL, NULL);
+  g_object_get (nesting, "my_bonk", &bonk, NULL);
+
+  g_assert (bonk == NULL);
+
+  g_object_unref (nesting);
+}
+
+static void
+test_structs_nesting_properties_my_ooe (void)
+{
+  TTestNesting *nesting;
+  TTestOneOfEach *one_of_each = NULL;
+  gint a_bite;
+  gint integer16;
+
+  nesting = g_object_new (T_TEST_TYPE_NESTING, NULL);
+
+  /* Nesting's "my_ooe" member is initialized with a new, default OneOfEach
+     object during construction */
+  g_object_get (nesting, "my_ooe", &one_of_each, NULL);
+
+  g_assert (one_of_each != NULL);
+  g_assert (T_TEST_IS_ONE_OF_EACH (one_of_each));
+
+  g_object_get (one_of_each,
+                "a_bite",    &a_bite,
+                "integer16", &integer16,
+                NULL);
+
+  g_assert_cmphex (a_bite,    ==, 0x7f);
+  g_assert_cmphex (integer16, ==, 0x7fff);
+
+  g_object_unref (one_of_each);
+  one_of_each = NULL;
+
+  /* It can be replaced... */
+  one_of_each = g_object_new (T_TEST_TYPE_ONE_OF_EACH,
+                              "a_bite",    0x50,
+                              "integer16", 0x5050,
+                              NULL);
+  g_object_set (nesting, "my_ooe", one_of_each, NULL);
+  g_object_unref (one_of_each);
+  one_of_each = NULL;
+
+  g_object_get (nesting, "my_ooe", &one_of_each, NULL);
+
+  g_assert (one_of_each != NULL);
+  g_assert (T_TEST_IS_ONE_OF_EACH (one_of_each));
+
+  g_object_get (one_of_each,
+                "a_bite",    &a_bite,
+                "integer16", &integer16,
+                NULL);
+
+  g_assert_cmphex (a_bite,    ==, 0x50);
+  g_assert_cmphex (integer16, ==, 0x5050);
+
+  g_object_unref (one_of_each);
+  one_of_each = NULL;
+
+  /* ...or set to null */
+  g_object_set (nesting, "my_ooe", NULL, NULL);
+  g_object_get (nesting, "my_ooe", &one_of_each, NULL);
+
+  g_assert (one_of_each == NULL);
+
+  g_object_unref (nesting);
+}
+
+static void
+test_structs_holy_moley_create_and_destroy (void)
+{
+  GObject *object = NULL;
+
+  /* A HolyMoley structure can be created... */
+  object = g_object_new (T_TEST_TYPE_HOLY_MOLEY, NULL);
+
+  g_assert (object != NULL);
+  g_assert (T_TEST_IS_HOLY_MOLEY (object));
+
+  /* ...and destroyed */
+  g_object_unref (object);
+}
+
+static void
+test_structs_holy_moley_properties_big (void)
+{
+  TTestHolyMoley *holy_moley;
+  GPtrArray *big = NULL;
+  gint a_bite = 0;
+  gint integer16 = 0;
+
+  holy_moley = g_object_new (T_TEST_TYPE_HOLY_MOLEY, NULL);
+
+  /* A HolyMoley's "big" member is is initialized on construction */
+  g_object_get (holy_moley, "big", &big, NULL);
+
+  g_assert (big != NULL);
+  g_assert_cmpint (big->len, ==, 0);
+
+  /* It can be modified... */
+  g_ptr_array_add (big,
+                   g_object_new (T_TEST_TYPE_ONE_OF_EACH,
+                                 "a_bite",    0x50,
+                                 "integer16", 0x5050,
+                                 NULL));
+
+  g_ptr_array_unref (big);
+  big = NULL;
+
+  g_object_get (holy_moley, "big", &big, NULL);
+
+  g_assert_cmpint (big->len, ==, 1);
+  g_object_get (g_ptr_array_index (big, 0),
+                "a_bite",    &a_bite,
+                "integer16", &integer16,
+                NULL);
+
+  g_assert_cmphex (a_bite,    ==, 0x50);
+  g_assert_cmphex (integer16, ==, 0x5050);
+
+  g_ptr_array_unref (big);
+  big = NULL;
+
+  /* ...replaced... */
+  big = g_ptr_array_new_with_free_func (g_object_unref);
+  g_ptr_array_add (big,
+                   g_object_new (T_TEST_TYPE_ONE_OF_EACH,
+                                 "a_bite",    0x64,
+                                 "integer16", 0x1541,
+                                 NULL));
+
+  g_object_set (holy_moley, "big", big, NULL);
+
+  g_ptr_array_unref (big);
+  big = NULL;
+
+  g_object_get (holy_moley, "big", &big, NULL);
+
+  g_assert_cmpint (big->len, ==, 1);
+  g_object_get (g_ptr_array_index (big, 0),
+                "a_bite",    &a_bite,
+                "integer16", &integer16,
+                NULL);
+
+  g_assert_cmphex (a_bite,    ==, 0x64);
+  g_assert_cmphex (integer16, ==, 0x1541);
+
+  g_ptr_array_unref (big);
+  big = NULL;
+
+  /* ...or set to NULL */
+  g_object_set (holy_moley, "big", NULL, NULL);
+  g_object_get (holy_moley, "big", &big, NULL);
+
+  g_assert (big == NULL);
+
+  g_object_unref (holy_moley);
+}
+
+static void
+test_structs_holy_moley_properties_contain (void)
+{
+  static gchar *strings[2] = { "Apache", "Thrift" };
+
+  TTestHolyMoley *holy_moley;
+  GHashTable *contain = NULL;
+  GPtrArray *string_list;
+  GList *key_list;
+
+  holy_moley = g_object_new (T_TEST_TYPE_HOLY_MOLEY, NULL);
+
+  /* A HolyMoley's "contain" member is initialized on construction */
+  g_object_get (holy_moley, "contain", &contain, NULL);
+
+  g_assert (contain != NULL);
+  g_assert_cmpint (g_hash_table_size (contain), ==, 0);
+
+  /* It can be modified... */
+  string_list = g_ptr_array_new ();
+  g_ptr_array_add (string_list, strings[0]);
+  g_ptr_array_add (string_list, strings[1]);
+
+  g_hash_table_insert (contain, string_list, NULL);
+  string_list = NULL;
+
+  g_hash_table_unref (contain);
+  contain = NULL;
+
+  g_object_get (holy_moley, "contain", &contain, NULL);
+
+  g_assert_cmpint (g_hash_table_size (contain), ==, 1);
+
+  key_list = g_hash_table_get_keys (contain);
+  string_list = g_list_nth_data (key_list, 0);
+
+  g_assert_cmpint (string_list->len, ==, 2);
+  g_assert_cmpstr (g_ptr_array_index (string_list, 0), ==, "Apache");
+  g_assert_cmpstr (g_ptr_array_index (string_list, 1), ==, "Thrift");
+
+  g_list_free (key_list);
+  g_hash_table_unref (contain);
+  contain = NULL;
+
+  /* ...replaced... */
+  contain = g_hash_table_new_full (g_direct_hash,
+                                   g_direct_equal,
+                                   (GDestroyNotify) g_ptr_array_unref,
+                                   NULL);
+  g_object_set (holy_moley, "contain", contain, NULL);
+  g_hash_table_unref (contain);
+  contain = NULL;
+
+  g_object_get (holy_moley, "contain", &contain, NULL);
+
+  g_assert_cmpint (g_hash_table_size (contain), ==, 0);
+
+  g_hash_table_unref (contain);
+  contain = NULL;
+
+  /* ...or set to NULL */
+  g_object_set (holy_moley, "contain", NULL, NULL);
+  g_object_get (holy_moley, "contain", &contain, NULL);
+
+  g_assert (contain == NULL);
+
+  g_object_unref (holy_moley);
+}
+
+static void
+test_structs_holy_moley_properties_bonks (void)
+{
+  TTestHolyMoley *holy_moley;
+  GHashTable *bonks = NULL;
+  GPtrArray *bonk_list = NULL;
+  TTestBonk *bonk = NULL;
+  gint type;
+  gchar *message;
+  GList *key_list;
+
+  holy_moley = g_object_new (T_TEST_TYPE_HOLY_MOLEY, NULL);
+
+  /* A HolyMoley's "bonks" member is initialized on construction */
+  g_object_get (holy_moley, "bonks", &bonks, NULL);
+
+  g_assert (bonks != NULL);
+  g_assert_cmpint (g_hash_table_size (bonks), ==, 0);
+
+  /* It can be modified... */
+  bonk = g_object_new (T_TEST_TYPE_BONK,
+                       "type",    100,
+                       "message", "Sample Bonk",
+                       NULL);
+  bonk_list = g_ptr_array_new_with_free_func (g_object_unref);
+  g_ptr_array_add (bonk_list, bonk);
+  bonk = NULL;
+
+  g_hash_table_insert (bonks, g_strdup ("Sample Bonks"), bonk_list);
+  bonk_list = NULL;
+
+  g_hash_table_unref (bonks);
+  bonks = NULL;
+
+  g_object_get (holy_moley, "bonks", &bonks, NULL);
+
+  g_assert_cmpint (g_hash_table_size (bonks), ==, 1);
+
+  key_list = g_hash_table_get_keys (bonks);
+  bonk_list = g_hash_table_lookup (bonks, g_list_nth_data (key_list, 0));
+
+  g_assert_cmpint (bonk_list->len, ==, 1);
+
+  bonk = (g_ptr_array_index (bonk_list, 0));
+  g_object_get (bonk,
+                "type",    &type,
+                "message", &message,
+                NULL);
+
+  g_assert_cmpint (type, ==, 100);
+  g_assert_cmpstr (message, ==, "Sample Bonk");
+
+  bonk = NULL;
+  g_free (message);
+  g_list_free (key_list);
+  g_hash_table_unref (bonks);
+  bonks = NULL;
+
+  /* ...replaced... */
+  bonks = g_hash_table_new_full (g_str_hash,
+                                 g_str_equal,
+                                 g_free,
+                                 (GDestroyNotify) g_ptr_array_unref);
+  g_object_set (holy_moley, "bonks", bonks, NULL);
+  g_hash_table_unref (bonks);
+  bonks = NULL;
+
+  g_object_get (holy_moley, "bonks", &bonks, NULL);
+
+  g_assert_cmpint (g_hash_table_size (bonks), ==, 0);
+
+  g_hash_table_unref (bonks);
+  bonks = NULL;
+
+  /* ...or set to NULL */
+  g_object_set (holy_moley, "bonks", NULL, NULL);
+  g_object_get (holy_moley, "bonks", &bonks, NULL);
+
+  g_assert (bonks == NULL);
+
+  g_object_unref (holy_moley);
+}
+
+static void
+test_structs_empty (void)
+{
+  GObject *object = NULL;
+  GParamSpec **properties;
+  guint property_count;
+
+  /* An Empty structure can be created */
+  object = g_object_new (T_TEST_TYPE_EMPTY, NULL);
+
+  g_assert (object != NULL);
+  g_assert (T_TEST_IS_EMPTY (object));
+
+  /* An Empty structure has no members and thus no properties */
+  properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (object),
+                                               &property_count);
+  g_assert_cmpint (property_count, ==, 0);
+  g_free (properties);
+
+  /* An Empty structure can be destroyed  */
+  g_object_unref (object);
+}
+
+static void
+test_structs_wrapper_create_and_destroy (void)
+{
+  GObject *object = NULL;
+
+  /* A Wrapper structure can be created... */
+  object = g_object_new (T_TEST_TYPE_EMPTY, NULL);
+
+  g_assert (object != NULL);
+  g_assert (T_TEST_IS_EMPTY (object));
+
+  /* ...and destroyed  */
+  g_object_unref (object);
+}
+
+static void
+test_structs_wrapper_properties_foo (void) {
+  TTestWrapper *wrapper;
+  TTestEmpty *foo;
+
+  wrapper = g_object_new (T_TEST_TYPE_WRAPPER, NULL);
+
+  /* A Wrapper structure has one member, "foo", which is an Empty
+     structure initialized during construction */
+  g_object_get (wrapper, "foo", &foo, NULL);
+
+  g_assert (foo != NULL);
+  g_assert (T_TEST_IS_EMPTY (foo));
+
+  g_object_unref (foo);
+  foo = NULL;
+
+  /* A Wrapper's foo property can be replaced... */
+  foo = g_object_new (T_TEST_TYPE_EMPTY, NULL);
+  g_object_set (wrapper, "foo", foo, NULL);
+
+  g_object_unref (foo);
+  foo = NULL;
+
+  g_object_get (wrapper, "foo", &foo, NULL);
+  g_assert (foo != NULL);
+  g_assert (T_TEST_IS_EMPTY (foo));
+
+  g_object_unref (foo);
+  foo = NULL;
+
+  /* ...or set to NULL */
+  g_object_set (wrapper, "foo", NULL, NULL);
+  g_object_get (wrapper, "foo", &foo, NULL);
+
+  g_assert (foo == NULL);
+
+  g_object_unref (wrapper);
+}
+
+static void
+test_services_inherited (void)
+{
+  ThriftProtocol *protocol;
+  TTestInheritedClient *inherited_client;
+  GObject *input_protocol, *output_protocol;
+
+  protocol = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, NULL);
+  inherited_client = g_object_new (T_TEST_TYPE_INHERITED_CLIENT,
+                                   NULL);
+
+  /* TTestInheritedClient inherits from TTestSrvClient */
+  g_assert (g_type_is_a (T_TEST_TYPE_INHERITED_CLIENT,
+                       T_TEST_TYPE_SRV_CLIENT));
+
+  /* TTestInheritedClient implements TTestSrvClient's interface */
+  g_assert (g_type_is_a (T_TEST_TYPE_INHERITED_CLIENT,
+                       T_TEST_TYPE_SRV_IF));
+
+  /* TTestInheritedClient's inherited properties can be set and retrieved */
+  g_object_set (inherited_client,
+                "input_protocol", protocol,
+                "output_protocol", protocol,
+                NULL);
+
+  g_object_get (inherited_client,
+                "input_protocol", &input_protocol,
+                "output_protocol", &output_protocol,
+                NULL);
+
+  g_assert (input_protocol == G_OBJECT(protocol));
+  g_assert (output_protocol == G_OBJECT(protocol));
+
+  g_object_unref (output_protocol);
+  g_object_unref (input_protocol);
+  g_object_unref (inherited_client);
+  g_object_unref (protocol);
 }
 
 int
 main(int argc, char *argv[])
 {
-  g_type_init();
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init ();
+#endif
+
   g_test_init (&argc, &argv, NULL);
 
-  g_test_add_func ("/testdebugproto/DebugProto", test_debug_proto);
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/Doubles/CreateAndDestroy",
+     test_structs_doubles_create_and_destroy);
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/Doubles/Initialize",
+     test_structs_doubles_initialize);
+
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/OneOfEach/CreateAndDestroy",
+     test_structs_one_of_each_create_and_destroy);
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/OneOfEach/Initialize/DefaultValues",
+     test_structs_one_of_each_initialize_default_values);
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/OneOfEach/Initialize/SpecifiedValues",
+     test_structs_one_of_each_initialize_specified_values);
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/OneOfEach/Properties/byte_list",
+     test_structs_one_of_each_properties_byte_list);
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/OneOfEach/Properties/i16_list",
+     test_structs_one_of_each_properties_i16_list);
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/OneOfEach/Properties/i64_list",
+     test_structs_one_of_each_properties_i64_list);
+
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/Nesting/CreateAndDestroy",
+     test_structs_nesting_create_and_destroy);
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/Nesting/Properties/my_bonk",
+     test_structs_nesting_properties_my_bonk);
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/Nesting/Properties/my_ooe",
+     test_structs_nesting_properties_my_ooe);
+
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/HolyMoley/CreateAndDestroy",
+     test_structs_holy_moley_create_and_destroy);
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/HolyMoley/Properties/big",
+     test_structs_holy_moley_properties_big);
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/HolyMoley/Properties/contain",
+     test_structs_holy_moley_properties_contain);
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/HolyMoley/Properties/bonks",
+     test_structs_holy_moley_properties_bonks);
+
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/Empty",
+     test_structs_empty);
+
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/Wrapper/CreateAndDestroy",
+     test_structs_wrapper_create_and_destroy);
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Structs/Wrapper/Properties/foo",
+     test_structs_wrapper_properties_foo);
+
+  g_test_add_func
+    ("/testdebugproto/DebugProto/Services/Inherited",
+     test_services_inherited);
 
   return g_test_run ();
 }
-
-
diff --git a/lib/c_glib/test/testfdtransport.c b/lib/c_glib/test/testfdtransport.c
new file mode 100755
index 0000000..1ea89be
--- /dev/null
+++ b/lib/c_glib/test/testfdtransport.c
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ */
+
+
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_fd_transport.h>
+
+static const gchar TEST_DATA[12] = "abcde01234!";
+
+static void
+test_create_and_destroy (void)
+{
+  GObject *object;
+  object = g_object_new (THRIFT_TYPE_FD_TRANSPORT, "fd", -1, NULL);
+  g_assert (object != NULL);
+  g_object_unref (object);
+}
+
+static void
+test_open_and_close (void)
+{
+  ThriftTransport *transport;
+  ThriftTransportClass *klass;
+  GError *error;
+  gint fd;
+  gchar *filename;
+
+  error = NULL;
+  filename = NULL;
+
+  fd = g_file_open_tmp (NULL, &filename, &error);
+  g_assert (fd >= 0);
+
+  transport = THRIFT_TRANSPORT (g_object_new (THRIFT_TYPE_FD_TRANSPORT,
+                                              "fd", fd,
+                                              NULL));
+  klass = THRIFT_TRANSPORT_GET_CLASS (transport);
+
+  /* open is no-op */
+  g_assert (klass->is_open (transport));
+  g_assert (klass->peek (transport, &error));
+  g_assert (klass->open (transport, &error));
+  g_assert (klass->is_open (transport));
+  g_assert (klass->peek (transport, &error));
+
+  g_assert (klass->close (transport, &error));
+  g_assert (! klass->open (transport, &error));
+  g_assert (! klass->is_open (transport));
+  g_assert (! klass->peek (transport, &error));
+
+  /* already closed */
+  g_assert (close (fd) != 0);
+  g_assert (errno == EBADF);
+
+  g_object_unref (transport);
+
+  g_remove (filename);
+  g_free (filename);
+
+  /* test bad fd */
+  transport = THRIFT_TRANSPORT (g_object_new (THRIFT_TYPE_FD_TRANSPORT,
+                                              "fd", -1,
+                                              NULL));
+  klass = THRIFT_TRANSPORT_GET_CLASS (transport);
+
+  g_assert (! klass->is_open (transport));
+  error = NULL;
+  g_assert (! klass->peek (transport, &error));
+  error = NULL;
+  g_assert (! klass->open (transport, &error));
+  error = NULL;
+  g_assert (! klass->close (transport, &error));
+
+  g_object_unref (transport);
+}
+
+static void
+test_read_and_write (void)
+{
+  gchar out_buf[8];
+  gchar *b;
+  gint want, got;
+  ThriftTransport *transport;
+  ThriftTransportClass *klass;
+  GError *error;
+  gint fd;
+  gchar *filename;
+
+  error = NULL;
+  filename = NULL;
+
+  fd = g_file_open_tmp (NULL, &filename, &error);
+  g_assert (fd >= 0);
+
+  /* write */
+  transport = THRIFT_TRANSPORT (g_object_new (THRIFT_TYPE_FD_TRANSPORT,
+                                              "fd", fd,
+                                              NULL));
+  klass = THRIFT_TRANSPORT_GET_CLASS (transport);
+  g_assert (klass->is_open (transport));
+  g_assert (klass->write (transport, (gpointer) TEST_DATA, 11, &error));
+  g_assert (klass->flush (transport, &error));
+  g_assert (klass->close (transport, &error));
+  g_object_unref (transport);
+
+  /* read */
+  fd = open(filename, O_RDONLY, S_IRUSR | S_IWUSR);
+  g_assert (fd >= 0);
+
+  transport = THRIFT_TRANSPORT (g_object_new (THRIFT_TYPE_FD_TRANSPORT,
+                                              "fd", fd,
+                                              NULL));
+  klass = THRIFT_TRANSPORT_GET_CLASS (transport);
+
+  memset(out_buf, 0, 8);
+  b = out_buf;
+  want = 7;
+  while (want > 0) {
+    got = klass->read (transport, (gpointer) b, want, &error);
+    g_assert (got > 0 && got <= want);
+    b += got;
+    want -= got;
+  }
+  g_assert (memcmp (out_buf, TEST_DATA, 7) == 0);
+
+  memset(out_buf, 0, 8);
+  b = out_buf;
+  want = 4;
+  while (want > 0) {
+    got = klass->read (transport, (gpointer) b, want, &error);
+    g_assert (got > 0 && got <= want);
+    b += got;
+    want -= got;
+  }
+  g_assert (memcmp (out_buf, TEST_DATA + 7, 4) == 0);
+
+  g_assert (klass->close (transport, &error));
+  g_object_unref (transport);
+
+  /* clean up */
+
+  g_remove (filename);
+  g_free (filename);
+}
+
+int
+main (int argc, char *argv[])
+{
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init ();
+#endif
+
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/testfdtransport/CreateAndDestroy", test_create_and_destroy);
+  g_test_add_func ("/testfdtransport/OpenAndClose", test_open_and_close);
+  g_test_add_func ("/testfdtransport/ReadAndWrite", test_read_and_write);
+
+  return g_test_run ();
+}
diff --git a/lib/c_glib/test/testframedtransport.c b/lib/c_glib/test/testframedtransport.c
index 03c9f9b..008e61e 100755
--- a/lib/c_glib/test/testframedtransport.c
+++ b/lib/c_glib/test/testframedtransport.c
@@ -17,8 +17,8 @@
  * under the License.
  */
 
-#include <assert.h>
 #include <netdb.h>
+#include <sys/wait.h>
 
 #include <thrift/c_glib/transport/thrift_transport.h>
 #include <thrift/c_glib/transport/thrift_socket.h>
@@ -29,10 +29,8 @@
 
 #include "../src/thrift/c_glib/transport/thrift_framed_transport.c"
 
-static const char TEST_ADDRESS[] = "localhost";
-static const short TEST_PORT = 64444;
-
 static void thrift_server (const int port);
+static void thrift_socket_server_open (const int port, int times);
 
 /* test object creation and destruction */
 static void
@@ -44,10 +42,10 @@
 
   GObject *object = NULL;
   object = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, NULL);
-  assert (object != NULL);
+  g_assert (object != NULL);
   g_object_get (G_OBJECT (object), "transport", &transport,
-                "r_buf_size", &r_buf_size,
-                "w_buf_size", &w_buf_size, NULL);
+		"r_buf_size", &r_buf_size,
+		"w_buf_size", &w_buf_size, NULL);
   g_object_unref (object);
 }
 
@@ -57,35 +55,53 @@
   ThriftSocket *tsocket = NULL;
   ThriftTransport *transport = NULL;
   GError *err = NULL;
+  pid_t pid;
+  int port = 51199;
+  int status;
 
-  /* create a ThriftSocket */
-  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
-                          "port", 51188, NULL); 
+  pid = fork ();
+  g_assert ( pid >= 0 );
 
-  /* create a BufferedTransport wrapper of the Socket */
-  transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
-                            "transport", THRIFT_TRANSPORT (tsocket), NULL);
+  if ( pid == 0 )
+    {
+      /* child listens */
+      thrift_socket_server_open (port,1);
+      exit (0);
+    } else {
+	/* parent connects, wait a bit for the socket to be created */
+	sleep (1);
+	/* create a ThriftSocket */
+	tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+				"port", port, NULL);
 
-  /* this shouldn't work */
-  assert (thrift_framed_transport_open (transport, NULL) == FALSE);
-  assert (thrift_framed_transport_is_open (transport) == TRUE);
-  assert (thrift_framed_transport_close (transport, NULL) == TRUE);
-  g_object_unref (transport);
-  g_object_unref (tsocket);
+	/* create a BufferedTransport wrapper of the Socket */
+	transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
+				  "transport", THRIFT_TRANSPORT (tsocket), NULL);
 
-  /* try and underlying socket failure */
-  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
-                          NULL);
+	/* this shouldn't work */
+	g_assert (thrift_framed_transport_open (transport, NULL) == TRUE);
+	g_assert (thrift_framed_transport_is_open (transport) == TRUE);
+	g_assert (thrift_framed_transport_close (transport, NULL) == TRUE);
+	g_object_unref (transport);
+	g_object_unref (tsocket);
 
-  /* create a BufferedTransport wrapper of the Socket */
-  transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
-                            "transport", THRIFT_TRANSPORT (tsocket), NULL);
+	/* try and underlying socket failure */
+	tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
+				NULL);
 
-  assert (thrift_framed_transport_open (transport, &err) == FALSE);
-  g_object_unref (transport);
-  g_object_unref (tsocket);
-  g_error_free (err);
-  err = NULL;
+	/* create a BufferedTransport wrapper of the Socket */
+	transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
+				  "transport", THRIFT_TRANSPORT (tsocket), NULL);
+
+	g_assert (thrift_framed_transport_open (transport, &err) == FALSE);
+	g_object_unref (transport);
+	g_object_unref (tsocket);
+	g_error_free (err);
+	err = NULL;
+
+	g_assert ( wait (&status) == pid );
+	g_assert ( status == 0 );
+    }
 }
 
 static void
@@ -99,49 +115,156 @@
   guchar buf[10] = TEST_DATA; /* a buffer */
 
   pid = fork ();
-  assert ( pid >= 0 );
+  g_assert ( pid >= 0 );
 
   if ( pid == 0 )
-  {
-    /* child listens */
-    thrift_server (port);
-    exit (0);
-  } else {
-    /* parent connects, wait a bit for the socket to be created */
-    sleep (1);
+    {
+      /* child listens */
+      thrift_server (port);
+      exit (0);
+    } else {
+	/* parent connects, wait a bit for the socket to be created */
+	sleep (1);
 
-    tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
-                            "port", port, NULL);
-    transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
-                              "transport", THRIFT_TRANSPORT (tsocket),
-                              "w_buf_size", 4, NULL);
+	tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+				"port", port, NULL);
+	transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
+				  "transport", THRIFT_TRANSPORT (tsocket),
+				  "w_buf_size", 4, NULL);
 
-    assert (thrift_framed_transport_open (transport, NULL) == TRUE);
-    assert (thrift_framed_transport_is_open (transport));
+	g_assert (thrift_framed_transport_open (transport, NULL) == TRUE);
+	g_assert (thrift_framed_transport_is_open (transport));
 
-    /* write 10 bytes */
-    thrift_framed_transport_write (transport, buf, 10, NULL);
-    thrift_framed_transport_flush (transport, NULL);
+	/* write 10 bytes */
+	thrift_framed_transport_write (transport, buf, 10, NULL);
+	thrift_framed_transport_flush (transport, NULL);
 
-    thrift_framed_transport_write (transport, buf, 1, NULL);
-    thrift_framed_transport_flush (transport, NULL);
+	thrift_framed_transport_write (transport, buf, 1, NULL);
+	thrift_framed_transport_flush (transport, NULL);
 
-    thrift_framed_transport_write (transport, buf, 10, NULL);
-    thrift_framed_transport_flush (transport, NULL);
+	thrift_framed_transport_write (transport, buf, 10, NULL);
+	thrift_framed_transport_flush (transport, NULL);
 
-    thrift_framed_transport_write (transport, buf, 10, NULL);
-    thrift_framed_transport_flush (transport, NULL);
+	thrift_framed_transport_write (transport, buf, 10, NULL);
+	thrift_framed_transport_flush (transport, NULL);
 
-    thrift_framed_transport_write_end (transport, NULL);
-    thrift_framed_transport_flush (transport, NULL);
-    thrift_framed_transport_close (transport, NULL);
+	thrift_framed_transport_write_end (transport, NULL);
+	thrift_framed_transport_flush (transport, NULL);
+	thrift_framed_transport_close (transport, NULL);
 
-    g_object_unref (transport);
-    g_object_unref (tsocket);
+	g_object_unref (transport);
+	g_object_unref (tsocket);
 
-    assert ( wait (&status) == pid );
-    assert ( status == 0 );
+	g_assert ( wait (&status) == pid );
+	g_assert ( status == 0 );
+    }
+}
+
+/* test reading from the transport after the peer has unexpectedly
+   closed the connection */
+static void
+test_read_after_peer_close(void)
+{
+  int status;
+  pid_t pid;
+  int port = 51199;
+  GError *err = NULL;
+
+  pid = fork ();
+  g_assert (pid >= 0);
+
+  if (pid == 0)
+    {
+      ThriftServerTransport *server_transport = NULL;
+      ThriftTransport *client_transport = NULL;
+
+      /* child listens */
+      server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+				       "port", port,
+				       NULL);
+      g_assert (server_transport != NULL);
+
+      thrift_server_transport_listen (server_transport, &err);
+      g_assert (err == NULL);
+
+      /* wrap the client transport in a ThriftFramedTransport */
+      client_transport = g_object_new
+	  (THRIFT_TYPE_FRAMED_TRANSPORT,
+	   "transport",  thrift_server_transport_accept (server_transport, &err),
+	   "r_buf_size", 0,
+	   NULL);
+      g_assert (err == NULL);
+      g_assert (client_transport != NULL);
+
+      /* close the connection immediately after the client connects */
+      thrift_transport_close (client_transport, NULL);
+
+      g_object_unref (client_transport);
+      g_object_unref (server_transport);
+
+      exit (0);
+    } else {
+	ThriftSocket *tsocket = NULL;
+	ThriftTransport *transport = NULL;
+	guchar buf[10]; /* a buffer */
+
+	/* parent connects, wait a bit for the socket to be created */
+	sleep (1);
+
+	tsocket = g_object_new (THRIFT_TYPE_SOCKET,
+				"hostname", "localhost",
+				"port",     port,
+				NULL);
+	transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
+				  "transport",  THRIFT_TRANSPORT (tsocket),
+				  "w_buf_size", 0,
+				  NULL);
+
+	g_assert (thrift_transport_open (transport, NULL) == TRUE);
+	g_assert (thrift_transport_is_open (transport));
+
+	/* attempting to read from the transport after the peer has closed
+       the connection fails gracefully without generating a critical
+       warning or segmentation fault */
+	thrift_transport_read (transport, buf, 10, &err);
+	g_assert (err != NULL);
+
+	g_error_free (err);
+	err = NULL;
+
+	thrift_transport_read_end (transport, &err);
+	g_assert (err == NULL);
+
+	thrift_transport_close (transport, &err);
+	g_assert (err == NULL);
+
+	g_object_unref (transport);
+	g_object_unref (tsocket);
+
+	g_assert (wait (&status) == pid);
+	g_assert (status == 0);
+    }
+}
+
+static void
+thrift_socket_server_open (const int port, int times)
+{
+  ThriftServerTransport *transport = NULL;
+  ThriftTransport *client = NULL;
+  int i;
+
+  ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+					      "port", port, NULL);
+
+  transport = THRIFT_SERVER_TRANSPORT (tsocket);
+  thrift_server_transport_listen (transport, NULL);
+  for(i=0;i<times;i++){
+      client = thrift_server_transport_accept (transport, NULL);
+      g_assert (client != NULL);
+      thrift_socket_close (client, NULL);
+      g_object_unref (client);
   }
+  g_object_unref (tsocket);
 }
 
 static void
@@ -154,21 +277,21 @@
   guchar match[10] = TEST_DATA;
 
   ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
-                                              "port", port, NULL);
+					      "port", port, NULL);
 
   transport = THRIFT_SERVER_TRANSPORT (tsocket);
   thrift_server_transport_listen (transport, NULL);
 
   /* wrap the client in a BufferedTransport */
   client = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, "transport",
-                         thrift_server_transport_accept (transport, NULL),
-                         "r_buf_size", 5, NULL);
-  assert (client != NULL);
+			 thrift_server_transport_accept (transport, NULL),
+			 "r_buf_size", 5, NULL);
+  g_assert (client != NULL);
 
   /* read 10 bytes */
   bytes = thrift_framed_transport_read (client, buf, 10, NULL);
-  assert (bytes == 10); /* make sure we've read 10 bytes */
-  assert ( memcmp (buf, match, 10) == 0 ); /* make sure what we got matches */
+  g_assert (bytes == 10); /* make sure we've read 10 bytes */
+  g_assert ( memcmp (buf, match, 10) == 0 ); /* make sure what we got matches */
 
   bytes = thrift_framed_transport_read (client, buf, 6, NULL);
   bytes = thrift_framed_transport_read (client, buf, 5, NULL);
@@ -185,12 +308,16 @@
 int
 main(int argc, char *argv[])
 {
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
   g_type_init();
+#endif
+
   g_test_init (&argc, &argv, NULL);
 
   g_test_add_func ("/testframedtransport/CreateAndDestroy", test_create_and_destroy);
   g_test_add_func ("/testframedtransport/OpenAndClose", test_open_and_close);
   g_test_add_func ("/testframedtransport/ReadAndWrite", test_read_and_write);
+  g_test_add_func ("/testframedtransport/ReadAfterPeerClose", test_read_after_peer_close);
 
   return g_test_run ();
 }
diff --git a/lib/c_glib/test/testmemorybuffer.c b/lib/c_glib/test/testmemorybuffer.c
index 7169a5c..9fb68b9 100755
--- a/lib/c_glib/test/testmemorybuffer.c
+++ b/lib/c_glib/test/testmemorybuffer.c
@@ -17,7 +17,6 @@
  * under the License.
  */
 
-#include <assert.h>
 #include <netdb.h>
 
 #include <thrift/c_glib/transport/thrift_transport.h>
@@ -25,71 +24,200 @@
 #include <thrift/c_glib/transport/thrift_server_transport.h>
 #include <thrift/c_glib/transport/thrift_server_socket.h>
 
-#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
+static const gchar TEST_DATA[11] = "abcdefghij";
 
 #include "../src/thrift/c_glib/transport/thrift_memory_buffer.c"
 
 /* test object creation and destruction */
 static void
-test_create_and_destroy(void)
+test_create_and_destroy (void)
 {
   GObject *object = NULL;
-  object = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, NULL);
-  assert (object != NULL);
+  object = g_object_new (THRIFT_TYPE_MEMORY_BUFFER,
+                         "buf_size", 10,
+                         NULL);
+  g_assert (object != NULL);
   g_object_unref (object);
 }
 
 static void
-test_open_and_close(void)
+test_create_and_destroy_large (void)
+{
+  GObject *object = NULL;
+  object = g_object_new (THRIFT_TYPE_MEMORY_BUFFER,
+                         "buf_size", 10 * 1024 * 1024,
+                         NULL);
+  g_assert (object != NULL);
+  g_object_unref (object);
+}
+
+static void
+test_create_and_destroy_default (void)
+{
+  GObject *object = NULL;
+  object = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, NULL);
+  g_assert (object != NULL);
+  g_object_unref (object);
+}
+
+static void
+test_create_and_destroy_external (void)
+{
+  GObject *object = NULL;
+  GByteArray *buf = g_byte_array_new ();
+  g_assert (buf != NULL);
+  object = g_object_new (THRIFT_TYPE_MEMORY_BUFFER,
+                         "buf", buf,
+                         NULL);
+  g_assert (object != NULL);
+  g_object_unref (object);
+}
+
+static void
+test_create_and_destroy_unowned (void)
+{
+  GObject *object = NULL;
+  GValue val = G_VALUE_INIT;
+  GByteArray *buf;
+
+  object = g_object_new (THRIFT_TYPE_MEMORY_BUFFER,
+                         "owner", FALSE,
+                         NULL);
+  g_assert (object != NULL);
+
+  g_value_init (&val, G_TYPE_POINTER);
+  g_object_get_property (object, "buf", &val);
+  buf = (GByteArray*) g_value_get_pointer (&val);
+  g_assert (buf != NULL);
+
+  g_byte_array_unref (buf);
+  g_value_unset (&val);
+  g_object_unref (object);
+}
+
+static void
+test_open_and_close (void)
 {
   ThriftMemoryBuffer *tbuffer = NULL;
 
   /* create a ThriftMemoryBuffer */
   tbuffer = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, NULL);
 
-  /* this shouldn't work */
-  assert (thrift_memory_buffer_open (THRIFT_TRANSPORT (tbuffer), NULL) == TRUE);
-  assert (thrift_memory_buffer_is_open (THRIFT_TRANSPORT (tbuffer)) == TRUE);
-  assert (thrift_memory_buffer_close (THRIFT_TRANSPORT (tbuffer), NULL) == TRUE);
+  /* no-ops */
+  g_assert (thrift_memory_buffer_open (THRIFT_TRANSPORT (tbuffer), NULL) == TRUE);
+  g_assert (thrift_memory_buffer_is_open (THRIFT_TRANSPORT (tbuffer)) == TRUE);
+  g_assert (thrift_memory_buffer_close (THRIFT_TRANSPORT (tbuffer), NULL) == TRUE);
+
   g_object_unref (tbuffer);
 }
 
 static void
-test_read_and_write(void)
+test_read_and_write (void)
 {
   ThriftMemoryBuffer *tbuffer = NULL;
-  guchar buf[10] = TEST_DATA;
-  guchar read[10];
+  gint got, want;
+  gchar read[10];
+  gchar *b;
   GError *error = NULL;
 
   tbuffer = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, "buf_size", 5, NULL);
-  assert (thrift_memory_buffer_write (THRIFT_TRANSPORT (tbuffer),
-                                      (gpointer) buf,
+  g_assert (thrift_memory_buffer_write (THRIFT_TRANSPORT (tbuffer),
+                                      (gpointer) TEST_DATA,
                                       10, &error) == FALSE);
-  assert (error != NULL);
+  g_assert (error != NULL);
   g_error_free (error);
   error = NULL;
   g_object_unref (tbuffer);
 
   tbuffer = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, "buf_size", 15, NULL);
-  assert (thrift_memory_buffer_write (THRIFT_TRANSPORT (tbuffer),
-                                      (gpointer) buf, 10, &error) == TRUE);
-  assert (error == NULL);
+  g_assert (thrift_memory_buffer_write (THRIFT_TRANSPORT (tbuffer),
+                                      (gpointer) TEST_DATA, 10, &error) == TRUE);
+  g_assert (error == NULL);
 
-  assert (thrift_memory_buffer_read (THRIFT_TRANSPORT (tbuffer),
-                                     &read, 10, &error) > 0);
-  assert (error == NULL);
+  memset(read, 0, 10);
+  b = read;
+  want = 10;
+  while (want > 0) {
+    got = thrift_memory_buffer_read (THRIFT_TRANSPORT (tbuffer),
+                                     (gpointer) b, want, &error);
+    g_assert (got > 0 && got <= want);
+    g_assert (error == NULL);
+    b += got;
+    want -= got;
+  }
+  g_assert (memcmp (read, TEST_DATA, 10) == 0);
+  g_object_unref (tbuffer);
+}
+
+static void
+test_read_and_write_default (void)
+{
+  ThriftMemoryBuffer *tbuffer = NULL;
+  gint got, want, i;
+  gchar read[10];
+  gchar *b;
+  GError *error = NULL;
+
+  tbuffer = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, NULL);
+  for (i = 0; i < 100; ++i) {
+    g_assert (thrift_memory_buffer_write (THRIFT_TRANSPORT (tbuffer),
+                                        (gpointer) TEST_DATA, 10, &error) == TRUE);
+    g_assert (error == NULL);
+  }
+
+  for (i = 0; i < 100; ++i) {
+    memset(read, 0, 10);
+    b = read;
+    want = 10;
+    while (want > 0) {
+      got = thrift_memory_buffer_read (THRIFT_TRANSPORT (tbuffer),
+                                       (gpointer) b, want, &error);
+      g_assert (got > 0 && got <= want);
+      g_assert (error == NULL);
+      b += got;
+      want -= got;
+    }
+    g_assert (memcmp (read, TEST_DATA, 10) == 0);
+  }
+  g_object_unref (tbuffer);
+}
+
+static void
+test_read_and_write_external (void)
+{
+  ThriftMemoryBuffer *tbuffer = NULL;
+  gchar *b;
+  GError *error = NULL;
+  GByteArray *buf = g_byte_array_new ();
+  g_assert (buf != NULL);
+
+  tbuffer = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, "buf", buf, NULL);
+  g_assert (thrift_memory_buffer_write (THRIFT_TRANSPORT (tbuffer),
+                                      (gpointer) TEST_DATA, 10, &error) == TRUE);
+  g_assert (error == NULL);
+
+  g_assert (memcmp (buf->data, TEST_DATA, 10) == 0);
+  g_object_unref (tbuffer);
 }
 
 int
 main(int argc, char *argv[])
 {
-  g_type_init();
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init ();
+#endif
+
   g_test_init (&argc, &argv, NULL);
 
   g_test_add_func ("/testmemorybuffer/CreateAndDestroy", test_create_and_destroy);
+  g_test_add_func ("/testmemorybuffer/CreateAndDestroyLarge", test_create_and_destroy_large);
+  g_test_add_func ("/testmemorybuffer/CreateAndDestroyUnlimited", test_create_and_destroy_default);
+  g_test_add_func ("/testmemorybuffer/CreateAndDestroyExternal", test_create_and_destroy_external);
+  g_test_add_func ("/testmemorybuffer/CreateAndDestroyUnowned", test_create_and_destroy_unowned);
   g_test_add_func ("/testmemorybuffer/OpenAndClose", test_open_and_close);
   g_test_add_func ("/testmemorybuffer/ReadAndWrite", test_read_and_write);
+  g_test_add_func ("/testmemorybuffer/ReadAndWriteUnlimited", test_read_and_write_default);
+  g_test_add_func ("/testmemorybuffer/ReadAndWriteExternal", test_read_and_write_external);
 
   return g_test_run ();
 }
diff --git a/lib/c_glib/test/testoptionalrequired.c b/lib/c_glib/test/testoptionalrequired.c
index 2839dd4..636c36d 100755
--- a/lib/c_glib/test/testoptionalrequired.c
+++ b/lib/c_glib/test/testoptionalrequired.c
@@ -17,7 +17,6 @@
  * under the License.
  */
 
-#include <assert.h>
 #include <glib.h>
 
 #include <thrift/c_glib/thrift_struct.h>
@@ -74,20 +73,20 @@
   s2 = g_object_new (T_TEST_TYPE_SIMPLE, NULL);
   s3 = g_object_new (T_TEST_TYPE_SIMPLE, NULL);
 
-  // write-to-read with optional fields
+  /* write-to-read with optional fields */
   s1->im_optional = 10;
-  assert (s1->__isset_im_default == FALSE);
-  assert (s1->__isset_im_optional == FALSE);  
+  g_assert (s1->__isset_im_default == FALSE);
+  g_assert (s1->__isset_im_optional == FALSE);  
   write_to_read (THRIFT_STRUCT (s1), THRIFT_STRUCT (s2), NULL, NULL);
-  assert (s2->__isset_im_default = TRUE);
-  assert (s2->__isset_im_optional == FALSE);
-  assert (s2->im_optional == 0);
+  g_assert (s2->__isset_im_default == TRUE);
+  g_assert (s2->__isset_im_optional == FALSE);
+  g_assert (s2->im_optional == 0);
 
   s1->__isset_im_optional = TRUE;
   write_to_read (THRIFT_STRUCT (s1), THRIFT_STRUCT (s3), NULL, NULL);
-  assert (s3->__isset_im_default == TRUE);
-  assert (s3->__isset_im_optional == TRUE);
-  assert (s3->im_optional == 10);
+  g_assert (s3->__isset_im_default == TRUE);
+  g_assert (s3->__isset_im_optional == TRUE);
+  g_assert (s3->im_optional == 10);
 
   g_object_unref (s1);
   g_object_unref (s2);
@@ -109,10 +108,10 @@
   write_to_read (THRIFT_STRUCT (t2), THRIFT_STRUCT (t1), NULL, NULL);
   write_to_read (THRIFT_STRUCT (t1), THRIFT_STRUCT (t2), NULL, NULL);
 
-  assert (t1->__isset_im_default == FALSE);
-  assert (t2->__isset_im_optional == TRUE);
-  assert (t1->im_default == t2->im_optional);
-  assert (t1->im_default == 0);
+  g_assert (t1->__isset_im_default == FALSE);
+  g_assert (t2->__isset_im_optional == TRUE);
+  g_assert (t1->im_default == t2->im_optional);
+  g_assert (t1->im_default == 0);
 
   g_object_unref (t1);
   g_object_unref (t2);
@@ -133,7 +132,7 @@
   write_to_read (THRIFT_STRUCT (t1), THRIFT_STRUCT (t3), NULL, NULL);
   write_to_read (THRIFT_STRUCT (t3), THRIFT_STRUCT (t1), NULL, NULL);
 
-  assert (t1->__isset_im_default == TRUE);
+  g_assert (t1->__isset_im_default == TRUE);
 
   g_object_unref (t1);
   g_object_unref (t3);
@@ -174,23 +173,46 @@
   t2 = g_object_new (T_TEST_TYPE_TRICKY2, NULL);
   t3 = g_object_new (T_TEST_TYPE_TRICKY3, NULL);
 
-  // throws protocol exception
+  /* throws protocol exception */
   write_to_read (THRIFT_STRUCT (t2), THRIFT_STRUCT (t3), NULL, &read_error);
-  assert (read_error != NULL);
+  g_assert (read_error != NULL);
   g_error_free (read_error);
 
   write_to_read (THRIFT_STRUCT (t3), THRIFT_STRUCT (t2), NULL, NULL);
 
-  assert (t2->__isset_im_optional);
+  g_assert (t2->__isset_im_optional);
 
   g_object_unref (t2);
   g_object_unref (t3);
 }
 
+static void
+test_non_set_binary (void)
+{
+  TTestBinaries *b1 = NULL;
+  TTestBinaries *b2 = NULL;
+  GError *error = NULL;
+
+  b1 = g_object_new (T_TEST_TYPE_BINARIES, NULL);
+  b2 = g_object_new (T_TEST_TYPE_BINARIES, NULL);
+
+  write_to_read (THRIFT_STRUCT (b1), THRIFT_STRUCT (b2), NULL, &error);
+  g_assert(!error);
+  write_to_read (THRIFT_STRUCT (b2), THRIFT_STRUCT (b1), NULL, &error);
+  g_assert(!error);
+  /* OK. No segfault */
+
+  g_object_unref (b1);
+  g_object_unref (b2);
+}
+
 int
 main(int argc, char *argv[])
 {
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
   g_type_init();
+#endif
+
   g_test_init (&argc, &argv, NULL);
 
   g_test_add_func ("/testoptionalrequired/OldSchool", test_old_school1);
@@ -199,6 +221,7 @@
   g_test_add_func ("/testoptionalrequired/Tricky2", test_tricky2);
   g_test_add_func ("/testoptionalrequired/Tricky3", test_tricky3);
   g_test_add_func ("/testoptionalrequired/Tricky4", test_tricky4);
+  g_test_add_func ("/testoptionalrequired/Binary", test_non_set_binary);
 
   return g_test_run ();
 }
diff --git a/lib/c_glib/test/testserialization.c b/lib/c_glib/test/testserialization.c
new file mode 100644
index 0000000..67d411d
--- /dev/null
+++ b/lib/c_glib/test/testserialization.c
@@ -0,0 +1,95 @@
+#include <thrift/c_glib/protocol/thrift_binary_protocol.h>
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/transport/thrift_memory_buffer.h>
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include "gen-c_glib/t_test_debug_proto_test_types.h"
+#include "gen-c_glib/t_test_enum_test_types.h"
+
+static void enum_constants_read_write() {
+  GError* error = NULL;
+  ThriftTransport* transport
+      = THRIFT_TRANSPORT(g_object_new(THRIFT_TYPE_MEMORY_BUFFER, "buf_size", 1024, NULL));
+  ThriftProtocol* protocol
+      = THRIFT_PROTOCOL(g_object_new(THRIFT_TYPE_BINARY_PROTOCOL, "transport", transport, NULL));
+  TTestEnumTestStruct* src = T_TEST_ENUM_TEST;
+  TTestEnumTestStruct* dst = g_object_new(T_TEST_TYPE_ENUM_TEST_STRUCT, NULL);
+  TTestEnumTestStructClass* cls = T_TEST_ENUM_TEST_STRUCT_GET_CLASS(src);
+  int write_len;
+  int read_len;
+
+  write_len = THRIFT_STRUCT_CLASS(cls)->write(THRIFT_STRUCT(src), protocol, &error);
+  g_assert(!error);
+  g_assert(write_len > 0);
+
+  read_len = THRIFT_STRUCT_CLASS(cls)->read(THRIFT_STRUCT(dst), protocol, &error);
+  g_assert(!error);
+  g_assert_cmpint(write_len, ==, read_len);
+
+  g_object_unref(dst);
+  g_object_unref(protocol);
+  g_object_unref(transport);
+}
+
+static void struct_constants_read_write() {
+  GError* error = NULL;
+  ThriftTransport* transport
+      = THRIFT_TRANSPORT(g_object_new(THRIFT_TYPE_MEMORY_BUFFER, "buf_size", 4096, NULL));
+  ThriftProtocol* protocol
+      = THRIFT_PROTOCOL(g_object_new(THRIFT_TYPE_BINARY_PROTOCOL, "transport", transport, NULL));
+  TTestCompactProtoTestStruct* src = T_TEST_COMPACT_TEST;
+  TTestCompactProtoTestStruct* dst = g_object_new(T_TEST_TYPE_COMPACT_PROTO_TEST_STRUCT, NULL);
+  TTestCompactProtoTestStructClass* cls = T_TEST_COMPACT_PROTO_TEST_STRUCT_GET_CLASS(src);
+  int write_len;
+  int read_len;
+
+  write_len = THRIFT_STRUCT_CLASS(cls)->write(THRIFT_STRUCT(src), protocol, &error);
+  g_assert(!error);
+  g_assert(write_len > 0);
+
+  read_len = THRIFT_STRUCT_CLASS(cls)->read(THRIFT_STRUCT(dst), protocol, &error);
+  g_assert(!error);
+  g_assert_cmpint(write_len, ==, read_len);
+
+  g_object_unref(dst);
+  g_object_unref(protocol);
+  g_object_unref(transport);
+}
+
+static void struct_read_write_length_should_equal() {
+  GError* error = NULL;
+  ThriftTransport* transport
+      = THRIFT_TRANSPORT(g_object_new(THRIFT_TYPE_MEMORY_BUFFER, "buf_size", 2048, NULL));
+  ThriftProtocol* protocol
+      = THRIFT_PROTOCOL(g_object_new(THRIFT_TYPE_BINARY_PROTOCOL, "transport", transport, NULL));
+  TTestBonk* src = g_object_new(T_TEST_TYPE_BONK, NULL);
+  TTestBonk* dst = g_object_new(T_TEST_TYPE_BONK, NULL);
+  TTestBonkClass* cls = T_TEST_BONK_GET_CLASS(src);
+  int write_len;
+  int read_len;
+
+  write_len = THRIFT_STRUCT_CLASS(cls)->write(THRIFT_STRUCT(src), protocol, &error);
+  g_assert(!error);
+  g_assert(write_len > 0);
+
+  read_len = THRIFT_STRUCT_CLASS(cls)->read(THRIFT_STRUCT(dst), protocol, &error);
+  g_assert(!error);
+  g_assert_cmpint(write_len, ==, read_len);
+
+  g_object_unref(dst);
+  g_object_unref(src);
+  g_object_unref(protocol);
+  g_object_unref(transport);
+}
+
+int main(int argc, char* argv[]) {
+#if (!GLIB_CHECK_VERSION(2, 36, 0))
+  g_type_init();
+#endif
+  g_test_init(&argc, &argv, NULL);
+
+  g_test_add_func("/testserialization/StructReadWriteLengthShouldEqual",
+                  struct_read_write_length_should_equal);
+  g_test_add_func("/testserialization/StructConstants", struct_constants_read_write);
+  g_test_add_func("/testserialization/EnumConstants", enum_constants_read_write);
+  return g_test_run();
+}
diff --git a/lib/c_glib/test/testsimpleserver.c b/lib/c_glib/test/testsimpleserver.c
index fca2dcd..3c6f2e8 100755
--- a/lib/c_glib/test/testsimpleserver.c
+++ b/lib/c_glib/test/testsimpleserver.c
@@ -17,7 +17,6 @@
  * under the License.
  */
 
-#include <assert.h>
 #include <glib.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -51,8 +50,13 @@
 
 gboolean
 test_processor_process (ThriftProcessor *processor, ThriftProtocol *in,
-                        ThriftProtocol *out)
+                        ThriftProtocol *out, GError **error)
 {
+  THRIFT_UNUSED_VAR (processor);
+  THRIFT_UNUSED_VAR (in);
+  THRIFT_UNUSED_VAR (out);
+  THRIFT_UNUSED_VAR (error);
+
   return FALSE;
 }
 
@@ -84,11 +88,12 @@
 
   /* run the server in a child process */
   pid = fork ();
-  assert (pid >= 0);
+  g_assert (pid >= 0);
 
   if (pid == 0)
   {
-    THRIFT_SERVER_GET_CLASS (THRIFT_SERVER (ss))->serve (THRIFT_SERVER (ss));
+    THRIFT_SERVER_GET_CLASS (THRIFT_SERVER (ss))->serve (THRIFT_SERVER (ss),
+                                                         NULL);
     exit (0);
   } else {
     sleep (5);
@@ -97,15 +102,18 @@
     g_object_unref (ss);
     g_object_unref (tss);
     g_object_unref (p);
-    assert (wait (&status) == pid);
-    assert (status == SIGINT);
+    g_assert (wait (&status) == pid);
+    g_assert (status == SIGINT);
   }
 }
 
 int
 main(int argc, char *argv[])
 {
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
   g_type_init();
+#endif
+
   g_test_init (&argc, &argv, NULL);
 
   g_test_add_func ("/testsimpleserver/SimpleServer", test_server);
diff --git a/lib/c_glib/test/teststruct.c b/lib/c_glib/test/teststruct.c
index 182a6ac..d120cbc 100755
--- a/lib/c_glib/test/teststruct.c
+++ b/lib/c_glib/test/teststruct.c
@@ -17,7 +17,6 @@
  * under the License.
  */
 
-#include <assert.h>
 #include <glib-object.h>
 
 #include "../src/thrift/c_glib/thrift_struct.c"
@@ -51,6 +50,10 @@
 thrift_test_struct_read (ThriftStruct *object, ThriftProtocol *protocol,
                          GError **error)
 {
+  THRIFT_UNUSED_VAR (object);
+  THRIFT_UNUSED_VAR (protocol);
+  THRIFT_UNUSED_VAR (error);
+
   return 0;
 }
 
@@ -58,6 +61,10 @@
 thrift_test_struct_write (ThriftStruct *object, ThriftProtocol *protocol,
                           GError **error)
 {
+  THRIFT_UNUSED_VAR (object);
+  THRIFT_UNUSED_VAR (protocol);
+  THRIFT_UNUSED_VAR (error);
+
   return 0;
 }
 
@@ -81,7 +88,7 @@
   ThriftTestStruct *t = NULL;
 
   t = g_object_new (THRIFT_TYPE_TEST_STRUCT, NULL);
-  assert ( THRIFT_IS_STRUCT (t));
+  g_assert ( THRIFT_IS_STRUCT (t));
   thrift_struct_read (THRIFT_STRUCT (t), NULL, NULL);
   thrift_struct_write (THRIFT_STRUCT (t), NULL, NULL);
   thrift_test_struct_read (THRIFT_STRUCT (t), NULL, NULL);
@@ -92,7 +99,10 @@
 int
 main(int argc, char *argv[])
 {
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
   g_type_init();
+#endif
+
   g_test_init (&argc, &argv, NULL);
 
   g_test_add_func ("/teststruct/InitializeObject", test_initialize_object);
diff --git a/lib/c_glib/test/testthrifttest.c b/lib/c_glib/test/testthrifttest.c
index a42d089..23a934d 100755
--- a/lib/c_glib/test/testthrifttest.c
+++ b/lib/c_glib/test/testthrifttest.c
@@ -1,14 +1,17 @@
-#include <assert.h>
 #include <netdb.h>
 
+#include <thrift/c_glib/thrift.h>
 #include <thrift/c_glib/transport/thrift_server_transport.h>
 #include <thrift/c_glib/transport/thrift_server_socket.h>
 
+#include "t_test_thrift_test_types.h"
+#include "thrift_test_handler.h"
+
 static const char TEST_ADDRESS[] = "localhost";
 static const int TEST_PORT = 64444;
 
 static void
-test_thrift_server (const int port)
+test_thrift_server (void)
 {
   ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
                                               "port", TEST_PORT, NULL);
@@ -16,13 +19,94 @@
   g_object_unref (tsocket);
 }
 
+static void
+set_indicator (gpointer data, GObject *where_the_object_was) {
+  THRIFT_UNUSED_VAR(where_the_object_was);
+
+  *(gboolean *) data = TRUE;
+}
+
+static void
+test_thrift_handler (void)
+{
+  GError *error;
+  GHashTable *_return;
+  TTestInsanity *argument;
+  gboolean indicator;
+
+  TTestXtruct  *xtruct,  *xtruct2;
+  TTestNumberz numberz;
+  TTestNumberz numberz2;
+  TTestUserId user_id, *user_id_ptr, *user_id_ptr2;
+  GHashTable *user_map;
+  GPtrArray *xtructs;
+
+  error = NULL;
+  indicator = FALSE;
+
+  user_map = NULL;
+  xtructs = NULL;
+
+  argument = g_object_new (T_TEST_TYPE_INSANITY, NULL);
+  g_object_get (argument,
+                "userMap", &user_map,
+                "xtructs", &xtructs,
+                NULL);
+
+  numberz = T_TEST_NUMBERZ_FIVE;
+  numberz2 = T_TEST_NUMBERZ_EIGHT;
+  user_id_ptr = g_malloc (sizeof *user_id_ptr);
+  *user_id_ptr = 5;
+  user_id_ptr2 = g_malloc (sizeof *user_id_ptr);
+  *user_id_ptr2 = 8;
+  g_hash_table_insert (user_map, (gpointer)numberz, user_id_ptr);
+  g_hash_table_insert (user_map, (gpointer)numberz2, user_id_ptr2);
+  g_hash_table_unref (user_map);
+
+  xtruct = g_object_new (T_TEST_TYPE_XTRUCT,
+                         "string_thing", "Hello2",
+                         "byte_thing",   2,
+                         "i32_thing",    2,
+                         "i64_thing",    2LL,
+                         NULL);
+  xtruct2 = g_object_new (T_TEST_TYPE_XTRUCT,
+                          "string_thing", "Goodbye4",
+                          "byte_thing",   4,
+                          "i32_thing",    4,
+                          "i64_thing",    4LL,
+                          NULL);
+  g_ptr_array_add (xtructs, xtruct2);
+  g_ptr_array_add (xtructs, xtruct);
+  g_ptr_array_unref (xtructs);
+
+  _return = g_hash_table_new_full (g_int64_hash,
+                                   g_int64_equal,
+                                   g_free,
+                                   (GDestroyNotify)g_hash_table_unref);
+
+  g_object_weak_ref (G_OBJECT (argument), set_indicator, (gpointer) &indicator);
+
+  g_assert (thrift_test_handler_test_insanity (NULL, &_return, argument, &error));
+  g_assert (! indicator);
+
+  g_hash_table_unref (_return);
+  g_assert (! indicator);
+
+  g_object_unref (argument);
+  g_assert (indicator);
+}
+
 int
 main(int argc, char *argv[])
 {
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
   g_type_init();
+#endif
+
   g_test_init (&argc, &argv, NULL);
 
   g_test_add_func ("/testthrift/Server", test_thrift_server);
+  g_test_add_func ("/testthrift/Handler", test_thrift_handler);
 
   return g_test_run ();
 }
diff --git a/lib/c_glib/test/testthrifttestclient.cpp b/lib/c_glib/test/testthrifttestclient.cpp
index 48ece70..1910c8a 100755
--- a/lib/c_glib/test/testthrifttestclient.cpp
+++ b/lib/c_glib/test/testthrifttestclient.cpp
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-/* test a C client with a C++ server */
+/* test a C client with a C++ server  (that makes sense...) */
 
 #include <signal.h>
 #include <sys/types.h>
@@ -25,23 +25,34 @@
 #include <thrift/protocol/TBinaryProtocol.h>
 #include <thrift/protocol/TDebugProtocol.h>
 #include <thrift/server/TSimpleServer.h>
+#include <memory>
 #include <thrift/transport/TServerSocket.h>
 #include "ThriftTest.h"
 #include "ThriftTest_types.h"
 
 #include <iostream>
-
-using namespace std;
-using namespace boost;
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
 
 using namespace apache::thrift;
 using namespace apache::thrift::concurrency;
 using namespace apache::thrift::protocol;
-using namespace apache::thrift::transport;
 using namespace apache::thrift::server;
+using namespace apache::thrift::transport;
 
 using namespace thrift::test;
 
+using std::cout;
+using std::endl;
+using std::fixed;
+using std::make_pair;
+using std::map;
+using std::set;
+using std::string;
+using std::vector;
+
 #define TEST_PORT 9980
 
 // Extra functions required for ThriftTest_types to work
@@ -59,119 +70,130 @@
   TestHandler() {}
 
   void testVoid() {
-    printf("[C -> C++] testVoid()\n");
+    cout << "[C -> C++] testVoid()" << endl;
   }
 
   void testString(string& out, const string &thing) {
-    printf("[C -> C++] testString(\"%s\")\n", thing.c_str());
+    cout << "[C -> C++] testString(\"" << thing << "\")" << endl;
     out = thing;
   }
 
+  bool testBool(const bool thing) {
+    cout << "[C -> C++] testBool(" << (thing ? "true" : "false") << ")" << endl;
+    return thing;
+  }
   int8_t testByte(const int8_t thing) {
-    printf("[C -> C++] testByte(%d)\n", (int)thing);
+    cout << "[C -> C++] testByte(" << (int)thing << ")" << endl;
     return thing;
   }
   int32_t testI32(const int32_t thing) {
-    printf("[C -> C++] testI32(%d)\n", thing);
+    cout << "[C -> C++] testI32(" << thing << ")" << endl;
     return thing;
   }
 
   int64_t testI64(const int64_t thing) {
-    printf("[C -> C++] testI64(%lld)\n", thing);
+    cout << "[C -> C++] testI64(" << thing << ")" << endl;
     return thing;
   }
 
   double testDouble(const double thing) {
-    printf("[C -> C++] testDouble(%lf)\n", thing);
+    cout.precision(6);
+    cout << "[C -> C++] testDouble(" << fixed << thing << ")" << endl;
     return thing;
   }
 
+  void testBinary(string& out, const string &thing) {
+    cout << "[C -> C++] testBinary(\"" << thing << "\")" << endl;
+    out = thing;
+  }
+
   void testStruct(Xtruct& out, const Xtruct &thing) {
-    printf("[C -> C++] testStruct({\"%s\", %d, %d, %lld})\n", thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing);
+    cout << "[C -> C++] testStruct({\"" << thing.string_thing << "\", " << (int)thing.byte_thing << ", " << thing.i32_thing << ", " << thing.i64_thing << "})" << endl;
     out = thing;
   }
 
   void testNest(Xtruct2& out, const Xtruct2& nest) {
     const Xtruct &thing = nest.struct_thing;
-    printf("[C -> C++] testNest({%d, {\"%s\", %d, %d, %lld}, %d})\n", (int)nest.byte_thing, thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing, nest.i32_thing);
+    cout << "[C -> C++] testNest({" << (int)nest.byte_thing << ", {\"" << thing.string_thing << "\", " << (int)thing.byte_thing << ", " << thing.i32_thing << ", " << thing.i64_thing << "}, " << nest.i32_thing << "})" << endl;
     out = nest;
   }
 
   void testMap(map<int32_t, int32_t> &out, const map<int32_t, int32_t> &thing) {
-    printf("[C -> C++] testMap({");
+    cout << "[C -> C++] testMap({";
     map<int32_t, int32_t>::const_iterator m_iter;
     bool first = true;
     for (m_iter = thing.begin(); m_iter != thing.end(); ++m_iter) {
       if (first) {
         first = false;
       } else {
-        printf(", ");
+        cout << ", ";
       }
-      printf("%d => %d", m_iter->first, m_iter->second);
+      cout << m_iter->first << " => " << m_iter->second;
     }
-    printf("})\n");
+    cout << "})" << endl;
     out = thing;
   }
 
   void testStringMap(map<std::string, std::string> &out, const map<std::string, std::string> &thing) {
-    printf("[C -> C++] testStringMap({");
+    cout << "[C -> C++] testStringMap({";
     map<std::string, std::string>::const_iterator m_iter;
     bool first = true;
     for (m_iter = thing.begin(); m_iter != thing.end(); ++m_iter) {
       if (first) {
         first = false;
       } else {
-        printf(", ");
+        cout << ", ";
       }
-      printf("\"%s\" => \"%s\"", (m_iter->first).c_str(), (m_iter->second).c_str());
+      cout << "\"" << m_iter->first << "\" => \"" << m_iter->second << "\"";
     }
-    printf("})\n");
+    cout << "})" << endl;
     out = thing;
   }
 
 
   void testSet(set<int32_t> &out, const set<int32_t> &thing) {
-    printf("[C -> C++] testSet({");
+    cout << "[C -> C++] testSet({";
     set<int32_t>::const_iterator s_iter;
     bool first = true;
     for (s_iter = thing.begin(); s_iter != thing.end(); ++s_iter) {
       if (first) {
         first = false;
       } else {
-        printf(", ");
+        cout << ", ";
       }
-      printf("%d", *s_iter);
+      cout << *s_iter;
     }
-    printf("})\n");
+    cout << "})" << endl;
     out = thing;
   }
 
   void testList(vector<int32_t> &out, const vector<int32_t> &thing) {
-    printf("[C -> C++] testList({");
+    cout << "[C -> C++] testList({";
     vector<int32_t>::const_iterator l_iter;
     bool first = true;
     for (l_iter = thing.begin(); l_iter != thing.end(); ++l_iter) {
       if (first) {
         first = false;
-      } else {        printf(", ");
+      } else {
+        cout << ", ";
       }
-      printf("%d", *l_iter);
+      cout << *l_iter;
     }
-    printf("})\n");
+    cout << "})" << endl;
     out = thing;
   }
 
   Numberz::type testEnum(const Numberz::type thing) {
-    printf("[C -> C++] testEnum(%d)\n", thing);
+    cout << "[C -> C++] testEnum(" << thing << ")" << endl;
     return thing;
   }
 
   UserId testTypedef(const UserId thing) {
-    printf("[C -> C++] testTypedef(%lld)\n", thing);
+    cout << "[C -> C++] testTypedef(" << thing << ")" << endl;
     return thing;  }
 
   void testMapMap(map<int32_t, map<int32_t,int32_t> > &mapmap, const int32_t hello) {
-    printf("[C -> C++] testMapMap(%d)\n", hello);
+    cout << "[C -> C++] testMapMap(" << hello << ")" << endl;
 
     map<int32_t,int32_t> pos;
     map<int32_t,int32_t> neg;
@@ -186,7 +208,9 @@
   }
 
   void testInsanity(map<UserId, map<Numberz::type,Insanity> > &insane, const Insanity &argument) {
-    printf("[C -> C++] testInsanity()\n");
+    THRIFT_UNUSED_VARIABLE (argument);
+
+    cout << "[C -> C++] testInsanity()" << endl;
 
     Xtruct hello;
     hello.string_thing = "Hello2";
@@ -219,43 +243,46 @@
     insane.insert(make_pair(1, first_map));
     insane.insert(make_pair(2, second_map));
 
-    printf("return");
-    printf(" = {");
+    cout << "return = {";
     map<UserId, map<Numberz::type,Insanity> >::const_iterator i_iter;
     for (i_iter = insane.begin(); i_iter != insane.end(); ++i_iter) {
-      printf("%lld => {", i_iter->first);
+      cout << i_iter->first << " => {";
       map<Numberz::type,Insanity>::const_iterator i2_iter;
       for (i2_iter = i_iter->second.begin();
            i2_iter != i_iter->second.end();
            ++i2_iter) {
-        printf("%d => {", i2_iter->first);
+        cout << i2_iter->first << " => {";
         map<Numberz::type, UserId> userMap = i2_iter->second.userMap;
         map<Numberz::type, UserId>::const_iterator um;
-        printf("{");
+        cout << "{";
         for (um = userMap.begin(); um != userMap.end(); ++um) {
-          printf("%d => %lld, ", um->first, um->second);
+          cout << um->first << " => " << um->second << ", ";
         }
-        printf("}, ");
+        cout << "}, ";
 
         vector<Xtruct> xtructs = i2_iter->second.xtructs;
         vector<Xtruct>::const_iterator x;
-        printf("{");
+        cout << "{";
         for (x = xtructs.begin(); x != xtructs.end(); ++x) {
-          printf("{\"%s\", %d, %d, %lld}, ", x->string_thing.c_str(), (int)x->byte_thing, x->i32_thing, x->i64_thing);
+          cout << "{\"" << x->string_thing << "\", " << (int)x->byte_thing << ", " << x->i32_thing << ", " << x->i64_thing << "}, ";
         }
-        printf("}");
+        cout << "}";
 
-        printf("}, ");
+        cout << "}, ";
       }
-      printf("}, ");
+      cout << "}, ";
     }
-    printf("}\n");
+    cout << "}" << endl;
 
 
   }
 
   void testMulti(Xtruct &hello, const int8_t arg0, const int32_t arg1, const int64_t arg2, const std::map<int16_t, std::string>  &arg3, const Numberz::type arg4, const UserId arg5) {
-    printf("[C -> C++] testMulti()\n");
+    THRIFT_UNUSED_VARIABLE (arg3);
+    THRIFT_UNUSED_VARIABLE (arg4);
+    THRIFT_UNUSED_VARIABLE (arg5);
+
+    cout << "[C -> C++] testMulti()" << endl;
 
     hello.string_thing = "Hello2";
     hello.byte_thing = arg0;
@@ -266,7 +293,7 @@
   void testException(const std::string &arg)
     throw(Xception, apache::thrift::TException)
   {
-    printf("[C -> C++] testException(%s)\n", arg.c_str());
+    cout << "[C -> C++] testException(" << arg << ")" << endl;
     if (arg.compare("Xception") == 0) {
       Xception e;
       e.errorCode = 1001;
@@ -284,7 +311,7 @@
 
   void testMultiException(Xtruct &result, const std::string &arg0, const std::string &arg1) throw(Xception, Xception2) {
 
-    printf("[C -> C++] testMultiException(%s, %s)\n", arg0.c_str(), arg1.c_str());
+    cout << "[C -> C++] testMultiException(" << arg0 << ", " << arg1 << ")" << endl;
 
     if (arg0.compare("Xception") == 0) {
       Xception e;
@@ -303,15 +330,17 @@
   }
 
   void testOneway(int sleepFor) {
-    printf("testOneway(%d): Sleeping...\n", sleepFor);
+    cout << "testOneway(" << sleepFor << "): Sleeping..." << endl;
     sleep(sleepFor);
-    printf("testOneway(%d): done sleeping!\n", sleepFor);
+    cout << "testOneway(" << sleepFor << "): done sleeping!" << endl;
   }
 };
 
 // C CLIENT
 extern "C" {
 
+#undef THRIFT_SOCKET /* from lib/cpp */
+
 #include "t_test_thrift_test.h"
 #include "t_test_thrift_test_types.h"
 #include <thrift/c_glib/transport/thrift_socket.h>
@@ -329,7 +358,7 @@
   gchar *string = NULL;
   gint8 byte = 0;
   gint16 i16 = 0;
-  gint32 i32 = 0, another_i32 = 56789; 
+  gint32 i32 = 0, another_i32 = 56789;
   gint64 i64 = 0;
   double dbl = 0.0;
   TTestXtruct *xtruct_in, *xtruct_out;
@@ -338,7 +367,7 @@
   GHashTable *set_in = NULL, *set_out = NULL;
   GArray *list_in = NULL, *list_out = NULL;
   TTestNumberz enum_in, enum_out;
-  TTestUserId user_id_in, user_id_out; 
+  TTestUserId user_id_in, user_id_out;
   GHashTable *insanity_in = NULL;
   TTestXtruct *xtruct1, *xtruct2;
   TTestInsanity *insanity_out = NULL;
@@ -347,11 +376,13 @@
   TTestXception *xception = NULL;
   TTestXception2 *xception2 = NULL;
 
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
   // initialize gobject
   g_type_init ();
+#endif
 
   // create a C client
-  tsocket = (ThriftSocket *) g_object_new (THRIFT_TYPE_SOCKET, 
+  tsocket = (ThriftSocket *) g_object_new (THRIFT_TYPE_SOCKET,
                           "hostname", "localhost",
                           "port", TEST_PORT, NULL);
   protocol = (ThriftBinaryProtocol *) g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
@@ -471,7 +502,7 @@
   // insanity
   insanity_out = (TTestInsanity *) g_object_new (T_TEST_TYPE_INSANITY, NULL);
   insanity_out->userMap = g_hash_table_new (NULL, NULL);
-  g_hash_table_insert (insanity_out->userMap, &enum_out, &user_id_out);
+  g_hash_table_insert (insanity_out->userMap, GINT_TO_POINTER (enum_out), &user_id_out);
 
   xtruct1 = (TTestXtruct *) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
   xtruct1->byte_thing = 1;
@@ -521,8 +552,7 @@
   assert (t_test_thrift_test_client_test_exception (iface, "ApplicationException", &xception, &error) == FALSE);
   g_error_free (error);
   error = NULL;
-  g_object_unref (xception);
-  xception = NULL;
+  assert (xception == NULL);
 
   assert (t_test_thrift_test_client_test_exception (iface, "Test", &xception, &error) == TRUE);
   assert (error == NULL);
@@ -574,11 +604,13 @@
 static void
 bailout (int signum)
 {
+  THRIFT_UNUSED_VARIABLE (signum);
+
   exit (1);
 }
 
 int
-main (int argc, char **argv)
+main (void)
 {
   int status;
   int pid = fork ();
@@ -586,11 +618,11 @@
 
   if (pid == 0) /* child */
   {
-    shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
-    shared_ptr<TestHandler> testHandler(new TestHandler());
-    shared_ptr<ThriftTestProcessor> testProcessor(new ThriftTestProcessor(testHandler));
-    shared_ptr<TServerSocket> serverSocket(new TServerSocket(TEST_PORT));
-    shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
+    std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+    std::shared_ptr<TestHandler> testHandler(new TestHandler());
+    std::shared_ptr<ThriftTestProcessor> testProcessor(new ThriftTestProcessor(testHandler));
+    std::shared_ptr<TServerSocket> serverSocket(new TServerSocket(TEST_PORT));
+    std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
     TSimpleServer simpleServer(testProcessor, serverSocket, transportFactory, protocolFactory);
     signal (SIGALRM, bailout);
     alarm (60);
@@ -599,7 +631,7 @@
     sleep (1);
     test_thrift_client ();
     kill (pid, SIGINT);
-    wait (&status) == pid;
+    assert (wait (&status) == pid);
   }
 
   return 0;
diff --git a/lib/c_glib/test/testtransportsocket.c b/lib/c_glib/test/testtransportsocket.c
index 836ddd0..89c61b9 100755
--- a/lib/c_glib/test/testtransportsocket.c
+++ b/lib/c_glib/test/testtransportsocket.c
@@ -17,10 +17,11 @@
  * under the License.
  */
 
-#include <assert.h>
 #include <netdb.h>
+#include <sys/wait.h>
 
 #include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport.h>
 #include <thrift/c_glib/transport/thrift_server_transport.h>
 #include <thrift/c_glib/transport/thrift_server_socket.h>
 
@@ -32,9 +33,9 @@
 my_socket(int domain, int type, int protocol)
 {
   if (socket_error == 0)
-  {
-    return socket (domain, type, protocol);
-  }
+    {
+      return socket (domain, type, protocol);
+    }
   return -1;
 }
 
@@ -43,9 +44,9 @@
 my_recv(int socket, void *buffer, size_t length, int flags)
 {
   if (recv_error == 0)
-  {
-    return recv (socket, buffer, length, flags);
-  }
+    {
+      return recv (socket, buffer, length, flags);
+    }
   return -1;
 }
 
@@ -54,9 +55,9 @@
 my_send(int socket, const void *buffer, size_t length, int flags)
 {
   if (send_error == 0)
-  {
-    return send (socket, buffer, length, flags);
-  }
+    {
+      return send (socket, buffer, length, flags);
+    }
   return -1;
 }
 
@@ -68,11 +69,8 @@
 #undef recv
 #undef send
 
-static const char TEST_ADDRESS[] = "localhost";
-static const short TEST_PORT = 64444;
-
 static void thrift_socket_server (const int port);
-
+static void thrift_socket_server_open (const int port, int times);
 /* test object creation and destruction */
 static void
 test_create_and_destroy(void)
@@ -82,7 +80,7 @@
 
   GObject *object = NULL;
   object = g_object_new (THRIFT_TYPE_SOCKET, NULL);
-  assert (object != NULL);
+  g_assert (object != NULL);
   g_object_get (G_OBJECT(object), "hostname", &hostname, "port", &port, NULL);
   g_free (hostname);
 
@@ -95,85 +93,223 @@
   ThriftSocket *tsocket = NULL;
   ThriftTransport *transport = NULL;
   GError *err = NULL;
+  int port = 51199;
+  pid_t pid;
+  int status;
 
-  /* open a connection and close it */
-  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
-                          "port", 51188, NULL); 
-  transport = THRIFT_TRANSPORT (tsocket);
-  thrift_socket_open (transport, NULL);
-  assert (thrift_socket_is_open (transport) == TRUE);
-  thrift_socket_close (transport, NULL);
-  assert (thrift_socket_is_open (transport) == FALSE);
+  pid = fork ();
+  g_assert ( pid >= 0 );
 
-  /* test close failure */
-  tsocket->sd = -1;
-  thrift_socket_close (transport, NULL);
-  g_object_unref (tsocket);
+  if ( pid == 0 )
+    {
+      /* child listens */
+      thrift_socket_server_open (port, 1);
+      exit (0);
+    } else {
+	/* parent connects, wait a bit for the socket to be created */
+	sleep (1);
 
-  /* try a hostname lookup failure */
-  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
-                          NULL);
-  transport = THRIFT_TRANSPORT (tsocket);
-  assert (thrift_socket_open (transport, &err) == FALSE);
-  g_object_unref (tsocket);
-  g_error_free (err);
-  err = NULL;
+	/* open a connection and close it */
+	tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+				"port", port, NULL);
+	transport = THRIFT_TRANSPORT (tsocket);
+	thrift_socket_open (transport, NULL);
+	g_assert (thrift_socket_is_open (transport) == TRUE);
+	thrift_socket_close (transport, NULL);
+	g_assert (thrift_socket_is_open (transport) == FALSE);
 
-  /* try an error call to socket() */
-  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost", NULL);
-  transport = THRIFT_TRANSPORT (tsocket);
-  socket_error = 1;
-  assert (thrift_socket_open (transport, &err) == FALSE);
-  socket_error = 0;
-  g_object_unref (tsocket);
-  g_error_free (err);
+	/* test close failure */
+	tsocket->sd = -1;
+	thrift_socket_close (transport, NULL);
+	g_object_unref (tsocket);
+
+	/* try a hostname lookup failure */
+	tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
+				NULL);
+	transport = THRIFT_TRANSPORT (tsocket);
+	g_assert (thrift_socket_open (transport, &err) == FALSE);
+	g_object_unref (tsocket);
+	g_error_free (err);
+	err = NULL;
+
+	/* try an error call to socket() */
+	tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost", NULL);
+	transport = THRIFT_TRANSPORT (tsocket);
+	socket_error = 1;
+	g_assert (thrift_socket_open (transport, &err) == FALSE);
+	socket_error = 0;
+	g_object_unref (tsocket);
+	g_error_free (err);
+	g_assert ( wait (&status) == pid );
+	g_assert ( status == 0 );
+    }
 }
 
 static void
 test_read_and_write(void)
 {
-  int status;
-  pid_t pid;
   ThriftSocket *tsocket = NULL;
   ThriftTransport *transport = NULL;
+  pid_t pid;
   int port = 51199;
+  int status;
   guchar buf[10] = TEST_DATA; /* a buffer */
 
   pid = fork ();
-  assert ( pid >= 0 );
+  g_assert ( pid >= 0 );
 
   if ( pid == 0 )
-  {
-    /* child listens */
-    thrift_socket_server (port);
-    exit (0);
-  } else {
-    /* parent connects, wait a bit for the socket to be created */
-    sleep (1);
+    {
+      /* child listens */
+      thrift_socket_server (port);
+      exit (0);
+    } else {
+	/* parent connects, wait a bit for the socket to be created */
+	sleep (1);
 
-    tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
-                            "port", port, NULL);
-    transport = THRIFT_TRANSPORT (tsocket);
-    assert (thrift_socket_open (transport, NULL) == TRUE);
-    assert (thrift_socket_is_open (transport));
-    thrift_socket_write (transport, buf, 10, NULL);
+	tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+				"port", port, NULL);
+	transport = THRIFT_TRANSPORT (tsocket);
+	g_assert (thrift_socket_open (transport, NULL) == TRUE);
+	g_assert (thrift_socket_is_open (transport));
+	thrift_socket_write (transport, buf, 10, NULL);
 
-    /* write fail */
-    send_error = 1;
-    thrift_socket_write (transport, buf, 1, NULL);
-    send_error = 0;
+	/* write fail */
+	send_error = 1;
+	thrift_socket_write (transport, buf, 1, NULL);
+	send_error = 0;
 
-    thrift_socket_write_end (transport, NULL);
-    thrift_socket_flush (transport, NULL);
-    thrift_socket_close (transport, NULL);
-    g_object_unref (tsocket);
+	thrift_socket_write_end (transport, NULL);
+	thrift_socket_flush (transport, NULL);
+	thrift_socket_close (transport, NULL);
+	g_object_unref (tsocket);
 
-    assert ( wait (&status) == pid );
-    assert ( status == 0 );
+	g_assert ( wait (&status) == pid );
+	g_assert ( status == 0 );
+    }
+}
+
+/* test ThriftSocket's peek() implementation */
+static void
+test_peek(void)
+{
+  gint status;
+  pid_t pid;
+  guint port = 51199;
+  gchar data = 'A';
+  ThriftTransport *client_transport;
+  GError *error = NULL;
+
+  client_transport = g_object_new (THRIFT_TYPE_SOCKET,
+				   "hostname", "localhost",
+				   "port",     port,
+				   NULL);
+
+  /* thrift_transport_peek returns FALSE when the socket is closed */
+  g_assert (thrift_transport_is_open (client_transport) == FALSE);
+  g_assert (thrift_transport_peek (client_transport, &error) == FALSE);
+  g_assert (error == NULL);
+
+  pid = fork ();
+  g_assert (pid >= 0);
+
+  if (pid == 0)
+    {
+      ThriftServerTransport *server_transport = NULL;
+
+      g_object_unref (client_transport);
+
+      /* child listens */
+      server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+				       "port", port,
+				       NULL);
+      g_assert (server_transport != NULL);
+
+      thrift_server_transport_listen (server_transport, &error);
+      g_assert (error == NULL);
+
+      client_transport = g_object_new
+	  (THRIFT_TYPE_BUFFERED_TRANSPORT,
+	   "transport",  thrift_server_transport_accept (server_transport, &error),
+	   "r_buf_size", 0,
+	   "w_buf_size", sizeof data,
+	   NULL);
+      g_assert (error == NULL);
+      g_assert (client_transport != NULL);
+
+      /* write exactly one character to the client */
+      g_assert (thrift_transport_write (client_transport,
+					&data,
+					sizeof data,
+					&error) == TRUE);
+
+      thrift_transport_flush (client_transport, &error);
+      thrift_transport_write_end (client_transport, &error);
+      thrift_transport_close (client_transport, &error);
+
+      g_object_unref (client_transport);
+      g_object_unref (server_transport);
+
+      exit (0);
+    }
+  else {
+      /* parent connects, wait a bit for the socket to be created */
+      sleep (1);
+
+      /* connect to the child */
+      thrift_transport_open (client_transport, &error);
+      g_assert (error == NULL);
+      g_assert (thrift_transport_is_open (client_transport) == TRUE);
+
+      /* thrift_transport_peek returns TRUE when the socket is open and there is
+       data available to be read */
+      g_assert (thrift_transport_peek (client_transport, &error) == TRUE);
+      g_assert (error == NULL);
+
+      /* read exactly one character from the server */
+      g_assert_cmpint (thrift_transport_read (client_transport,
+					      &data,
+					      sizeof data,
+					      &error), ==, sizeof data);
+
+      /* thrift_transport_peek returns FALSE when the socket is open but there is
+       no (more) data available to be read */
+      g_assert (thrift_transport_is_open (client_transport) == TRUE);
+      g_assert (thrift_transport_peek (client_transport, &error) == FALSE);
+      g_assert (error == NULL);
+
+      thrift_transport_read_end (client_transport, &error);
+      thrift_transport_close (client_transport, &error);
+
+      g_object_unref (client_transport);
+
+      g_assert (wait (&status) == pid);
+      g_assert (status == 0);
   }
 }
 
 static void
+thrift_socket_server_open (const int port, int times)
+{
+  ThriftServerTransport *transport = NULL;
+  ThriftTransport *client = NULL;
+  int i;
+  ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+					      "port", port, NULL);
+
+  transport = THRIFT_SERVER_TRANSPORT (tsocket);
+  thrift_server_transport_listen (transport, NULL);
+  for(i=0;i<times;i++){
+      client = thrift_server_transport_accept (transport, NULL);
+      g_assert (client != NULL);
+      thrift_socket_close (client, NULL);
+      g_object_unref (client);
+  }
+  g_object_unref (tsocket);
+}
+
+
+static void
 thrift_socket_server (const int port)
 {
   int bytes = 0;
@@ -183,17 +319,17 @@
   guchar match[10] = TEST_DATA;
 
   ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
-                                              "port", port, NULL);
+					      "port", port, NULL);
 
   transport = THRIFT_SERVER_TRANSPORT (tsocket);
   thrift_server_transport_listen (transport, NULL);
   client = thrift_server_transport_accept (transport, NULL);
-  assert (client != NULL);
+  g_assert (client != NULL);
 
   /* read 10 bytes */
   bytes = thrift_socket_read (client, buf, 10, NULL);
-  assert (bytes == 10); /* make sure we've read 10 bytes */
-  assert ( memcmp(buf, match, 10) == 0 ); /* make sure what we got matches */
+  g_assert (bytes == 10); /* make sure we've read 10 bytes */
+  g_assert ( memcmp(buf, match, 10) == 0 ); /* make sure what we got matches */
 
   /* failed read */
   recv_error = 1;
@@ -209,12 +345,16 @@
 int
 main(int argc, char *argv[])
 {
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
   g_type_init();
+#endif
+
   g_test_init (&argc, &argv, NULL);
 
   g_test_add_func ("/testtransportsocket/CreateAndDestroy", test_create_and_destroy);
   g_test_add_func ("/testtransportsocket/OpenAndClose", test_open_and_close);
   g_test_add_func ("/testtransportsocket/ReadAndWrite", test_read_and_write);
+  g_test_add_func ("/testtransportsocket/Peek", test_peek);
 
   return g_test_run ();
 }
diff --git a/lib/c_glib/test/testtransportsslsocket.c b/lib/c_glib/test/testtransportsslsocket.c
new file mode 100644
index 0000000..3c2644d
--- /dev/null
+++ b/lib/c_glib/test/testtransportsslsocket.c
@@ -0,0 +1,542 @@
+/*
+ * 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.
+ */
+#define _POSIX_C_SOURCE 200112L /* https://stackoverflow.com/questions/37541985/storage-size-of-addrinfo-isnt-known */
+
+
+#include <sys/wait.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport.h>
+#include <thrift/c_glib/transport/thrift_server_transport.h>
+#include <thrift/c_glib/transport/thrift_server_socket.h>
+#include <thrift/c_glib/transport/thrift_ssl_socket.h>
+
+/* #define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' } */
+#define TEST_DATA { "GET / HTTP/1.1\n\n" }
+
+
+/* substituted functions to test failures of system and library calls */
+static int socket_error = 0;
+int
+my_socket(int domain, int type, int protocol)
+{
+  if (socket_error == 0)
+    {
+      return socket (domain, type, protocol);
+    }
+  return -1;
+}
+
+static int recv_error = 0;
+ssize_t
+my_recv(int socket, void *buffer, size_t length, int flags)
+{
+  if (recv_error == 0)
+    {
+      return recv (socket, buffer, length, flags);
+    }
+  return -1;
+}
+
+static int send_error = 0;
+ssize_t
+my_send(int socket, const void *buffer, size_t length, int flags)
+{
+  if (send_error == 0)
+    {
+      return send (socket, buffer, length, flags);
+    }
+  return -1;
+}
+
+#define socket my_socket
+#define recv my_recv
+#define send my_send
+#include "../src/thrift/c_glib/transport/thrift_ssl_socket.c"
+#undef socket
+#undef recv
+#undef send
+
+static void thrift_socket_server (const int port);
+
+/* test object creation and destruction */
+static void
+test_ssl_create_and_destroy(void)
+{
+  gchar *hostname = NULL;
+  guint port = 0;
+
+  GObject *object = NULL;
+  object = g_object_new (THRIFT_TYPE_SSL_SOCKET, NULL);
+  g_assert (object != NULL);
+  g_object_get (G_OBJECT(object), "hostname", &hostname, "port", &port, NULL);
+  g_free (hostname);
+  g_object_unref (object);
+}
+
+static void
+test_ssl_create_and_set_properties(void)
+{
+  gchar *hostname = NULL;
+  guint port = 0;
+  SSL_CTX* ssl_ctx= NULL;
+  GError *error=NULL;
+
+  GObject *object = NULL;
+  object = thrift_ssl_socket_new(SSLTLS, &error);
+  g_object_get (G_OBJECT(object), "hostname", &hostname, "port", &port, "ssl_context", &ssl_ctx, NULL);
+  g_assert (ssl_ctx!=NULL);
+
+  g_free (hostname);
+  g_object_unref (object);
+}
+
+static void
+test_ssl_open_and_close_non_ssl_server(void)
+{
+  ThriftSSLSocket *tSSLSocket = NULL;
+  ThriftTransport *transport = NULL;
+  GError *error=NULL;
+  pid_t pid;
+  int non_ssl_port = 51198;
+  char errormsg[255];
+
+
+  pid = fork ();
+  g_assert ( pid >= 0 );
+
+  if ( pid == 0 )
+    {
+      /* child listens */
+      /* This is a non SSL server */
+      thrift_socket_server (non_ssl_port);
+      exit (0);
+    } else {
+	/* parent connects, wait a bit for the socket to be created */
+	sleep (1);
+
+	/* open a connection and close it */
+	tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost", non_ssl_port, &error);
+
+	transport = THRIFT_TRANSPORT (tSSLSocket);
+	g_assert (thrift_ssl_socket_open (transport, &error) == FALSE);
+	g_assert_cmpstr(error->message, == ,"Error while connect/bind: 68 -> Connection reset by peer");
+	g_clear_error (&error);
+	g_assert (thrift_ssl_socket_is_open (transport) == FALSE);
+	thrift_ssl_socket_close (transport, NULL);
+	g_assert (thrift_ssl_socket_is_open (transport) == FALSE);
+
+	/* test close failure */
+	THRIFT_SOCKET(tSSLSocket)->sd = -1;
+	thrift_ssl_socket_close (transport, NULL);
+	g_object_unref (tSSLSocket);
+
+	/* try a hostname lookup failure */
+	tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost.broken", non_ssl_port, &error);
+	transport = THRIFT_TRANSPORT (tSSLSocket);
+	g_assert (thrift_ssl_socket_open (transport, &error) == FALSE);
+	snprintf(errormsg, 255, "host lookup failed for localhost.broken:%d - Unknown host", non_ssl_port);
+	g_assert_cmpstr(error->message, ==, errormsg);
+	g_clear_error (&error);
+	g_object_unref (tSSLSocket);
+	error = NULL;
+
+		/* try an error call to socket() */
+	/*
+		tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost", port, &error);
+		transport = THRIFT_TRANSPORT (tSSLSocket);
+		socket_error = 1;
+		assert (thrift_ssl_socket_open (transport, &error) == FALSE);
+		socket_error = 0;
+		g_object_unref (tSSLSocket);
+		g_error_free (error);
+	 */
+    }
+}
+
+static void
+test_ssl_write_invalid_socket(void)
+{
+  ThriftSSLSocket *tSSLSocket = NULL;
+  ThriftTransport *transport = NULL;
+  GError *error=NULL;
+  char buffer[] = "this must not break";
+
+  /* open a connection and close it */
+  tSSLSocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost", 51188+1, &error);
+
+  transport = THRIFT_TRANSPORT (tSSLSocket);
+  g_assert (thrift_ssl_socket_open (transport, NULL) == FALSE);
+  g_assert (thrift_ssl_socket_is_open (transport) == FALSE);
+
+  /* FIXME This must be tested but since the assertion inside thrift_ssl_socket_write breaks the test unit
+   it's disabled. They idea is to disable trap/coredump during this test
+  g_assert (thrift_ssl_socket_write(transport, buffer, sizeof(buffer), &error) == FALSE);
+  g_message ("write_failed_with_error: %s",
+	     error != NULL ? error->message : "No");
+  g_clear_error (&error);
+  */
+  thrift_ssl_socket_close (transport, NULL);
+  g_assert (thrift_ssl_socket_is_open (transport) == FALSE);
+
+  /* test close failure */
+  THRIFT_SOCKET(tSSLSocket)->sd = -1;
+  thrift_ssl_socket_close (transport, NULL);
+  g_object_unref (tSSLSocket);
+}
+
+
+
+/**
+ * Print the common name of certificate
+ */
+unsigned char * get_cn_name(X509_NAME* const name)
+{
+  int idx = -1;
+  unsigned char *utf8 = NULL;
+
+  do
+    {
+      if(!name) break; /* failed */
+
+      idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
+      if(!(idx > -1))  break; /* failed */
+
+      X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, idx);
+      if(!entry) break; /* failed */
+
+      ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry);
+      if(!data) break; /* failed */
+
+      int length = ASN1_STRING_to_UTF8(&utf8, data);
+      if(!utf8 || !(length > 0))  break; /* failed */
+
+    } while (0);
+  return utf8;
+}
+
+/*
+ * Handle IPV4 and IPV6 addr
+ */
+void *get_in_addr(struct sockaddr *sa)
+{
+  if (sa->sa_family == AF_INET)
+    return &(((struct sockaddr_in*)sa)->sin_addr);
+  return &(((struct sockaddr_in6*)sa)->sin6_addr);
+}
+
+int verify_ip(char * hostname, struct sockaddr_storage *addr)
+{
+  struct addrinfo *addr_info,*p;
+  struct addrinfo hints;
+  int res;
+  int retval = 0;
+
+
+  memset(&hints, 0, sizeof (struct addrinfo));
+  hints.ai_family = AF_UNSPEC; /* use AF_INET6 to force IPv6 */
+  hints.ai_socktype = SOCK_STREAM;
+
+
+  if ( (res = getaddrinfo(hostname, NULL, &hints, &addr_info) ) != 0)
+    {
+      /* get the host info */
+      g_error("Cannot get the host address");
+      return retval;
+    }
+  /* loop through all the results and connect to the first we can */
+  char dnshost[INET6_ADDRSTRLEN]; /* bigger addr supported IPV6 */
+  char socket_ip[INET6_ADDRSTRLEN];
+  if(inet_ntop(addr->ss_family, get_in_addr(addr), socket_ip, INET6_ADDRSTRLEN)==socket_ip){
+      g_debug("We are connected to host %s checking against certificate...", socket_ip);
+      int sizeip = socket_ip!=NULL ? strlen(socket_ip) : 0;
+      for(p = addr_info; p != NULL; p = p->ai_next) {
+	  if(inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), dnshost, INET6_ADDRSTRLEN)==dnshost){
+	      if(dnshost!=NULL){
+		  g_info("DNS address [%i -> %s]", p->ai_addr, dnshost);
+		  if(!strncmp(dnshost, socket_ip, sizeip)){
+		      retval=1;
+		      break; /* if we get here, we must have connected successfully */
+		  }
+	      }
+	  }
+      }
+  }
+
+  if(addr_info)
+    freeaddrinfo(addr_info);
+
+  return retval;
+}
+
+static void
+read_from_file(char *buffer, long size, const char *file_name)
+{
+  char ch;
+  long index=0;
+  FILE *fp;
+
+  fp = fopen(file_name,"r"); /* read mode */
+
+  if( fp == NULL )
+    {
+      perror("Error while opening the file.\n");
+      exit(EXIT_FAILURE);
+    }
+
+  printf("The contents of %s file are :\n", file_name);
+
+  while(index<size && ( ch = fgetc(fp) ) != EOF ){
+      buffer[index++] = ch;
+  }
+
+  fclose(fp);
+}
+
+#define ISSUER_CN_PINNING "The Apache Software Foundation"
+#define SUBJECT_CN_PINNING "localhost"
+#define CERT_SERIAL_NUMBER "1"
+
+gboolean verify_certificate_sn(X509 *cert, const unsigned char *serial_number)
+{
+  gboolean retval = FALSE;
+
+  ASN1_INTEGER *serial = X509_get_serialNumber(cert);
+
+  BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
+  if (!bn) {
+      fprintf(stderr, "unable to convert ASN1INTEGER to BN\n");
+      return EXIT_FAILURE;
+  }
+  char *tmp = BN_bn2dec(bn);
+  if (!tmp) {
+      g_warning(stderr, "unable to convert BN to decimal string.\n");
+      BN_free(bn);
+      return EXIT_FAILURE;
+  }
+  /*
+    if (strlen(tmp) >= len) {
+      g_warn(stderr, "buffer length shorter than serial number\n");
+      BN_free(bn);
+      OPENSSL_free(tmp);
+      return EXIT_FAILURE;
+    }
+  */
+  if(!strncmp(serial_number, tmp, strlen(serial_number))){
+      retval=TRUE;
+  }else{
+      g_warning("Serial number is not valid");
+  }
+
+  BN_free(bn);
+  OPENSSL_free(tmp);
+  return retval;
+}
+
+gboolean my_access_manager(ThriftTransport * transport, X509 *cert, struct sockaddr_storage *addr, GError **error)
+{
+  ThriftSSLSocket *sslSocket = THRIFT_SSL_SOCKET (transport);
+
+  g_info("Processing access to the server");
+  X509_NAME* iname = cert ? X509_get_issuer_name(cert) : NULL;
+  X509_NAME* sname = cert ? X509_get_subject_name(cert) : NULL;
+
+  /* Issuer is the authority we trust that warrants nothing useful */
+  const unsigned char * issuer = get_cn_name(iname);
+  if(issuer){
+      gboolean valid = TRUE;
+      g_info("Issuer (cn) %s", issuer);
+
+      /* Issuer pinning */
+      if(strncmp(ISSUER_CN_PINNING, issuer, strlen(ISSUER_CN_PINNING))){
+	  g_warning("The Issuer of the certificate is not valid");
+	  valid=FALSE;
+      }
+      OPENSSL_free(issuer);
+      if(!valid)
+	return valid;
+  }
+
+
+  /* Subject is who the certificate is issued to by the authority  */
+  const unsigned char * subject = get_cn_name(sname);
+  if(subject){
+      g_info("Subject (cn) %s", subject);
+      gboolean valid = TRUE;
+
+      /* Subject pinning */
+      if(strncmp(SUBJECT_CN_PINNING, subject, strlen(SUBJECT_CN_PINNING))){
+	  g_warning("The subject of the certificate is not valid");
+	  valid=FALSE;
+      }
+
+      if(!valid)
+	return valid;
+
+      /* Host pinning       */
+      if(verify_ip(subject, addr)){
+	  g_info("Verified subject");
+      }else{
+	  g_info("Cannot verify subject");
+	  valid=FALSE;
+      }
+      OPENSSL_free(subject);
+
+      if(!valid)
+	return valid;
+  }
+
+  if(!verify_certificate_sn(cert, CERT_SERIAL_NUMBER)){
+      return FALSE;
+  }else{
+      g_info("Verified serial number");
+  }
+
+  return TRUE;
+
+}
+
+
+
+
+#ifdef BUILD_SERVER
+static void
+test_ssl_authorization_manager(void)
+{
+  int status=0;
+  pid_t pid;
+  ThriftSSLSocket *tSSLsocket = NULL;
+  ThriftTransport *transport = NULL;
+  /*  int port = 51199; */
+  int port = 443;
+  GError *error=NULL;
+
+  guchar buf[17] = TEST_DATA; /* a buffer */
+
+/*
+  pid = fork ();
+    g_assert ( pid >= 0 );
+
+    if ( pid == 0 )
+    {
+      thrift_ssl_socket_server (port);
+      exit (0);
+    } else {
+	*/
+  /* parent connects, wait a bit for the socket to be created */
+  sleep (1);
+
+  /* Test against level2 owncloud certificate */
+  tSSLsocket = thrift_ssl_socket_new_with_host(SSLTLS, "localhost", port, &error);
+  thrift_ssl_socket_set_manager(tSSLsocket, my_access_manager);           /* Install pinning manager */
+  /* thrift_ssl_load_cert_from_file(tSSLsocket, "./owncloud.level2crm.pem"); */
+  unsigned char cert_buffer[65534];
+  read_from_file(cert_buffer, 65534, "../../keys/client.pem");
+  if(!thrift_ssl_load_cert_from_buffer(tSSLsocket, cert_buffer)){
+      g_warning("Certificates cannot be loaded!");
+  }
+
+  transport = THRIFT_TRANSPORT (tSSLsocket);
+  g_assert (thrift_ssl_socket_open (transport, NULL) == TRUE);
+  g_assert (thrift_ssl_socket_is_open (transport));
+
+  thrift_ssl_socket_write (transport, buf, 17, NULL);
+
+  /* write fail */
+  send_error = 1;
+  /*
+      thrift_ssl_socket_write (transport, buf, 1, NULL);
+     send_error = 0;
+      thrift_ssl_socket_write_end (transport, NULL);
+      thrift_ssl_socket_flush (transport, NULL);
+      */
+  thrift_ssl_socket_close (transport, NULL);
+  g_object_unref (tSSLsocket);
+
+  /*    g_assert ( wait (&status) == pid ); */
+  g_assert ( status == 0 );
+  /*  } */
+}
+#endif
+
+
+static void
+thrift_socket_server (const int port)
+{
+  int bytes = 0;
+  ThriftServerTransport *transport = NULL;
+  ThriftTransport *client = NULL;
+  guchar buf[10]; /* a buffer */
+  guchar match[10] = TEST_DATA;
+
+  ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+					      "port", port, NULL);
+
+  transport = THRIFT_SERVER_TRANSPORT (tsocket);
+  thrift_server_transport_listen (transport, NULL);
+  client = thrift_server_transport_accept (transport, NULL);
+  g_assert (client != NULL);
+
+  /* read 10 bytes */
+  bytes = thrift_ssl_socket_read (client, buf, 10, NULL);
+  g_assert (bytes == 10); /* make sure we've read 10 bytes */
+  g_assert ( memcmp(buf, match, 10) == 0 ); /* make sure what we got matches */
+
+  /* failed read */
+  recv_error = 1;
+  thrift_ssl_socket_read (client, buf, 1, NULL);
+  recv_error = 0;
+
+  thrift_ssl_socket_read_end (client, NULL);
+  thrift_ssl_socket_close (client, NULL);
+  g_object_unref (tsocket);
+  g_object_unref (client);
+}
+
+int
+main(int argc, char *argv[])
+{
+  int retval;
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init();
+#endif
+
+  g_test_init (&argc, &argv, NULL);
+
+  thrift_ssl_socket_initialize_openssl();
+
+  g_test_add_func ("/testtransportsslsocket/CreateAndDestroy", test_ssl_create_and_destroy);
+  g_test_add_func ("/testtransportsslsocket/CreateAndSetProperties", test_ssl_create_and_set_properties);
+  g_test_add_func ("/testtransportsslsocket/OpenAndCloseNonSSLServer", test_ssl_open_and_close_non_ssl_server);
+  g_test_add_func ("/testtransportsslsocket/OpenAndWriteInvalidSocket", test_ssl_write_invalid_socket);
+
+
+
+
+  retval = g_test_run ();
+
+  thrift_ssl_socket_finalize_openssl();
+
+  return retval;
+}
+
diff --git a/lib/c_glib/thrift_c_glib.pc.in b/lib/c_glib/thrift_c_glib.pc.in
index 3921d05..568c7a2 100644
--- a/lib/c_glib/thrift_c_glib.pc.in
+++ b/lib/c_glib/thrift_c_glib.pc.in
@@ -27,4 +27,4 @@
 Version: @VERSION@
 Requires: glib-2.0 gobject-2.0
 Libs: -L${libdir} -lthrift_c_glib
-Cflags: -I${includedir}/thrift/c_glib
+Cflags: -I${includedir}
diff --git a/lib/cl/Makefile.am b/lib/cl/Makefile.am
new file mode 100644
index 0000000..34b3886
--- /dev/null
+++ b/lib/cl/Makefile.am
@@ -0,0 +1,40 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+all-local:
+	bash ensure-externals.sh
+
+run-tests: test/make-test-binary.lisp
+	$(SBCL) --script test/make-test-binary.lisp
+
+check-local: run-tests
+	./run-tests
+
+clean-local:
+	$(RM) run-tests quicklisp.lisp backport-update.zip
+	$(RM) -rf lib externals quicklisp
+
+EXTRA_DIST = \
+	README.md \
+	READMES \
+	load-locally.lisp \
+	test \
+	ensure-externals.sh
diff --git a/lib/cl/README.md b/lib/cl/README.md
new file mode 100644
index 0000000..1d6eafb
--- /dev/null
+++ b/lib/cl/README.md
@@ -0,0 +1,253 @@
+Thrift Common Lisp Library
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+
+
+Using Thrift with Common Lisp
+============================
+
+ Thrift is a protocol and library for language-independent communication between cooperating
+ processes. The communication takes the form of request and response messages, of which the forms
+ are specified in advance throufh a shared interface definition. A Thrift definition file is translated
+ into Lisp source files, which comprise several definitions:
+
+  * Three packages, one for the namespace of the implementation operators, and one each for request and
+  response operators.
+  * Various type definitions as implementations for Thrift typedef and enum definitions.
+  * DEF-STRUCT and DEF-EXCEPTION forms for Thrift struct and exception definitions.
+  * DEF-SERVICE forms for thrift service definitions.
+
+ Each service definition expands in a collection of generic function definitions. For each `op`
+ in the service definition, two functions are defined
+
+  * `op`-request is defined for use by a client. It accepts an additional initial `protocol` argument,
+    to act as the client proxy for the operation and mediate the interaction with a remote process
+    through a Thrift-encoded transport stream.
+  * `op`-response is defined for use by a server. It accepts a single `protocol` argument. A server
+    uses it to decode the request message, invoke the base `op` function with the message arguments,
+    encode and send the the result as a response, and handles exceptions.
+
+ The client interface is one operator
+
+  * `with-client (variable location) . body` : creates a connection in a dynamic context and closes it
+    upon exit. The variable is bound to a client proxy stream/protocol instance, which wraps the
+    base i/o stream - socket, file, etc, with an operators which implement the Thrift protocol
+    and transport mechanisms.
+
+ The server interface combines server and service objects
+
+  * `serve (location service)` : accepts connections on the designated port and responds to
+    requests of the service's operations.
+
+
+Building 
+--------
+
+The Thrift Common Lisp library is packaged as the ASDF[[1]] system `thrift`.
+It depends on the systems
+
+* puri[[2]] : for the thrift uri class
+* closer-mop[[3]] : for class metadata
+* trivial-utf-8[[4]] : for string codecs
+* usocket[[5]] : for the socket transport
+* ieee-floats[[6]] : for conversion between ints and floats
+* trivial-gray-streams[[7]] : an abstraction layer for gray streams
+* alexandria[[8]] : handy utilities
+
+The dependencies are bundled for local builds of tests and tutorial binaries - 
+it is possible to use those bundles to load the library, too.
+
+In order to build it, register those systems with ASDF and evaluate:
+
+    (asdf:load-system :thrift)
+
+This will compile and load the Lisp compiler for Thrift definition files, the
+transport and protocol implementations, and the client and server interface
+functions. In order to use Thrift in an application, one must also author and/or
+load the interface definitions for the remote service.[[9]] If one is implementing a service,
+one must also define the actual functions to which Thrift is to act as the proxy
+interface. The remainder of this document follows the Thrift tutorial to illustrate how
+to perform the steps
+
+  * implement the service
+  * translate the Thrift IDL
+  * load the Lisp service interfaces
+  * run a server for the service
+  * use a client to access the service remotely
+
+Note that, if one is to implement a new service, one will also need to author the
+IDL files, as there is no facility to generate them from a service implementation.
+
+
+Implement the Service
+---------------------
+
+The tutorial comprises serveral functions: `add`, `ping`, `zip`, and `calculate`.
+Each translated IDL file generates three packages for every service. In the case of
+the tutorial file, the relevant packages are:
+
+  * tutorial.calculator
+  * tutorial.calculator-implementation
+  * tutorial.calculator-response
+  
+This is to separate the request (generated), response (generated) and implementation
+(meant to be implemented by the programmer) functions for defined Thrift methods.
+
+It is suggested to work in the `tutorial-implementation` package while implementing
+the services - it imports the `common-lisp` package, while the service-specific ones
+don't (to avoid conflicts between Thrift method names and function names in `common-lisp`).
+
+    ;; define the base operations
+    
+    (in-package :tutorial-implementation)
+    
+    (defun tutorial.calculator-implementation:add (num1 num2)
+      (format t "~&Asked to add ~A and ~A." num1 num2)
+      (+ num1 num2))
+    
+    (defun tutorial.calculator-implementation:ping ()
+      (print :ping))
+    
+    (defun tutorial.calculator-implementation:zip ()
+      (print :zip))
+    
+    (defun tutorial.calculator-implementation:calculate (logid task)
+      (calculate-op (work-op task) (work-num1 task) (work-num2 task)))
+    
+    (defgeneric calculate-op (op arg1 arg2)
+      (:method :around (op arg1 arg2)
+        (let ((result (call-next-method)))
+          (format t "~&Asked to calculate: ~d on  ~A and ~A = ~d." op arg1 arg2 result)
+          result))
+    
+      (:method ((op (eql operation.add)) arg1 arg2)
+        (+ arg1 arg2))
+      (:method ((op (eql operation.subtract)) arg1 arg2)
+        (- arg1 arg2))
+      (:method ((op (eql operation.multiply)) arg1 arg2)
+        (* arg1 arg2))
+      (:method ((op (eql operation.divide)) arg1 arg2)
+        (/ arg1 arg2)))
+    
+    (defun zip () (print 'zip))
+
+
+Translate the Thrift IDL
+------------------------
+
+IDL files employ the file extension `thrift`. In this case, there are two files to translate
+  * `tutorial.thrift`
+  * `shared.thrift`
+As the former includes the latter, one uses it to generate the interfaces:
+
+    $THRIFT/bin/thrift -r --gen cl $THRIFT/tutorial/tutorial.thrift
+    
+`-r` stands for recursion, while `--gen` lets one choose the language to translate to.
+
+
+Load the Lisp translated service interfaces
+-------------------------------------------
+
+The translator generates three files for each IDL file. For example `tutorial-types.lisp`,
+`tutorial-vars.lisp` and an `.asd` file that can be used to load them both and pull in
+other includes (like `shared` within the tutorial) as dependencies.
+
+
+Run a Server for the Service
+----------------------------
+
+The actual service name, as specified in the `def-service` form in `tutorial.lisp`, is `calculator`. 
+Each service definition defines a global variable with the service name and binds it to a
+service instance whch describes the operations.
+
+In order to start a service, specify a location and the service instance. 
+
+    (in-package :tutorial)
+    (serve #u"thrift://127.0.0.1:9091" calculator)
+
+
+Use a Client to Access the Service Remotely
+-------------------------------------------
+
+
+[in some other process] run the client
+
+    (in-package :cl-user)
+
+    (macrolet ((show (form)
+                 `(format *trace-output* "~%~s =>~{ ~s~}"
+                          ',form
+                          (multiple-value-list (ignore-errors ,form)))))
+      (with-client (protocol #u"thrift://127.0.0.1:9091")
+        (show (tutorial.calculator:ping protocol))
+        (show (tutorial.calculator:add protocol 1 2))
+        (show (tutorial.calculator:add protocol 1 4))
+    
+        (let ((task (make-instance 'tutorial:work
+                      :op operation.subtract :num1 15 :num2 10)))
+          (show (tutorial.calculator:calculate protocol 1 task))
+        
+          (setf (tutorial:work-op task) operation.divide
+                (tutorial:work-num1 task) 1
+                (tutorial:work-num2 task) 0)
+          (show (tutorial.calculator:calculate protocol 1 task)))
+        
+        (show (shared.shared-service:get-struct protocol 1))
+    
+        (show (zip protocol))))
+
+Issues
+------
+
+### optional fields 
+ Where the IDL declares a field options, the def-struct form includes no
+ initform for the slot and the encoding operator skips an unbound slot. This leave some ambiguity
+ with bool fields.
+
+### instantiation protocol :
+ struct classes are standard classes and exception classes are
+ whatever the implementation prescribes. decoders apply make-struct to an initargs list.
+ particularly at the service end, there are advantages to resourcing structs and decoding
+ with direct side-effects on slot-values
+
+### maps:
+ Maps are now represented as hash tables. As data through the call/reply interface is all statically
+ typed, it is not necessary for the objects to themselves indicate the coding form. Association lists
+ would be sufficient. As the key type is arbitrary, property lists offer no additional convenience:
+ as `getf` operates with `eq` a new access interface would be necessary and they would not be
+ available for function application.
+
+
+ [1]: www.common-lisp.net/asdf
+ [2]: http://github.com/lisp/com.b9.puri.ppcre
+ [3]: www.common-lisp.net/closer-mop
+ [4]: trivial-utf-8
+ [5]: https://github.com/usocket/usocket
+ [6]: https://github.com/marijnh/ieee-floats
+ [7]: https://github.com/trivial-gray-streams/trivial-gray-streams
+ [8]: https://gitlab.common-lisp.net/alexandria/alexandria
+ [9]: http://wiki.apache.org/thrift/ThriftGeneration
+
+* usocket[[5]] : for the socket transport
+* ieee-floats[[6]] : for conversion between ints and floats
+* trivial-gray-streams[[7]] : an abstraction layer for gray streams
+* alexandria[[8]] : handy utilities
diff --git a/lib/cl/READMES/readme-cassandra.lisp b/lib/cl/READMES/readme-cassandra.lisp
new file mode 100644
index 0000000..72744ea
--- /dev/null
+++ b/lib/cl/READMES/readme-cassandra.lisp
@@ -0,0 +1,64 @@
+(in-package :cl-user)
+
+#+(or ccl sbcl) /development/source/library/
+(load "build-init.lisp")
+
+;;; ! first, select the api version in the cassandra system definition
+;;; as only one should be loaded at a time.
+(asdf:load-system :de.setf.cassandra)
+
+(in-package :de.setf.cassandra)
+
+(defparameter *c-location*
+  ;; remote
+  ;; #u"thrift://ec2-174-129-66-148.compute-1.amazonaws.com:9160"
+  ;; local
+  #u"thrift://127.0.0.1:9160"
+  "A cassandra service location - either the local one or a remote service 
+ - always a 'thrift' uri.")
+
+(defparameter *c* (thrift:client *c-location*))
+
+
+(cassandra:describe-keyspaces *c*)
+;; => ("Keyspace1" "system")
+
+(cassandra:describe-cluster-name *c*)
+;; =>"Test Cluster"
+
+(cassandra:describe-version *c*)
+;; => "2.1.0"
+
+(loop for space in (cassandra:describe-keyspaces *c*)
+      collect (loop for key being each hash-key of (cassandra:describe-keyspace *c* space)
+                    using (hash-value value)
+                    collect (cons key
+                                  (loop for key being each hash-key of value
+                                        using (hash-value value)
+                                        collect (cons key value)))))
+
+
+(close *c*)
+
+(defun describe-cassandra (location &optional (stream *standard-output*))
+  "Print the first-order store metadata for a cassandra LOCATION."
+
+  (thrift:with-client (cassandra location)
+    (let* ((keyspace-names (cassandra:describe-keyspaces cassandra))
+           (cluster (cassandra:describe-cluster-name cassandra))
+           (version (cassandra:describe-version cassandra))
+           (keyspace-descriptions (loop for space in keyspace-names
+                                        collect (cons space
+                                                      (loop for key being each hash-key
+                                                            of (cassandra:describe-keyspace cassandra space)
+                                                            using (hash-value value)
+                                                            collect (cons key
+                                                                          (loop for key being each hash-key of value
+                                                                                using (hash-value value)
+                                                                                collect (cons key value))))))))
+      (format stream "~&connection to : ~a" cassandra)
+      (format stream "~&version : ~a" version)
+      (format stream "~&cluster : ~a" cluster)
+      (format stream "~&keyspaces~{~{~%~%space: ~a~@{~%  ~{~a :~@{~20t~:w~^~%~}~}~}~}~}" keyspace-descriptions))))
+
+;;; (describe-cassandra *c-location*)
diff --git a/lib/cl/ensure-externals.sh b/lib/cl/ensure-externals.sh
new file mode 100755
index 0000000..0495f03
--- /dev/null
+++ b/lib/cl/ensure-externals.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+if [[ ! -e quicklisp.lisp ]]; then curl -O https://beta.quicklisp.org/quicklisp.lisp; fi
+sbcl --load quicklisp.lisp \
+     --eval "(ignore-errors (quicklisp-quickstart:install :path \"quicklisp/\"))" \
+     --eval "(load \"quicklisp/setup.lisp\")" \
+     --eval "(quicklisp:bundle-systems '(#:puri #:usocket #:closer-mop #:trivial-utf-8 #:ieee-floats #:trivial-gray-streams #:alexandria #:bordeaux-threads #:cl-ppcre #:fiasco #:net.didierverna.clon) :to \"externals/\")" \
+     --eval "(quit)" \
+     --no-userinit
+if [[ ! -e backport-update.zip ]]; then
+    curl -O -L https://github.com/TurtleWarePL/de.setf.thrift/archive/backport-update.zip;
+fi
+mkdir -p lib
+unzip -u backport-update.zip -d lib
diff --git a/lib/cl/load-locally.lisp b/lib/cl/load-locally.lisp
new file mode 100644
index 0000000..d12c704
--- /dev/null
+++ b/lib/cl/load-locally.lisp
@@ -0,0 +1,23 @@
+(in-package #:cl-user)
+
+;;;; Licensed under the Apache License, Version 2.0 (the "License");
+;;;; you may not use this file except in compliance with the License.
+;;;; You may obtain a copy of the License at
+;;;;
+;;;;     http://www.apache.org/licenses/LICENSE-2.0
+;;;;
+;;;; Unless required by applicable law or agreed to in writing, software
+;;;; distributed under the License is distributed on an "AS IS" BASIS,
+;;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;;;; See the License for the specific language governing permissions and
+;;;; limitations under the License.
+
+;;;; Just a script for loading the library itself, using bundled dependencies.
+;;;; This is here for when we want to build the self-test and cross-test
+;;;; binaries.
+
+(require "asdf")
+
+(load (merge-pathnames "externals/bundle.lisp" *load-truename*))
+(asdf:load-asd (merge-pathnames "lib/de.setf.thrift-backport-update/thrift.asd" *load-truename*))
+(asdf:load-system :thrift)
diff --git a/lib/cl/test/make-test-binary.lisp b/lib/cl/test/make-test-binary.lisp
new file mode 100644
index 0000000..4e7a58c
--- /dev/null
+++ b/lib/cl/test/make-test-binary.lisp
@@ -0,0 +1,31 @@
+;;;; Licensed under the Apache License, Version 2.0 (the "License");
+;;;; you may not use this file except in compliance with the License.
+;;;; You may obtain a copy of the License at
+;;;;
+;;;;     http://www.apache.org/licenses/LICENSE-2.0
+;;;;
+;;;; Unless required by applicable law or agreed to in writing, software
+;;;; distributed under the License is distributed on an "AS IS" BASIS,
+;;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;;;; See the License for the specific language governing permissions and
+;;;; limitations under the License.
+
+;;;; This file is used to build the binary that runs all self-tests. The
+;;;; binary is then meant to be hooked up to Thrift's `make check` facility,
+;;;; but can easily be run on its own as well.
+
+(in-package #:cl-user)
+
+(require "asdf")
+(load (merge-pathnames "../load-locally.lisp" *load-truename*))
+(asdf:load-asd (merge-pathnames "../lib/de.setf.thrift-backport-update/test/thrift-test.asd" *load-truename*))
+(asdf:load-system :thrift-test)
+(asdf:load-system :net.didierverna.clon)
+
+(net.didierverna.clon:nickname-package)
+
+(defun main ()
+  (let ((result (if (fiasco:run-tests 'thrift-test) 0 -1)))
+    (clon:exit result)))
+
+(clon:dump "run-tests" main)
diff --git a/lib/cocoa/README b/lib/cocoa/README.md
similarity index 100%
rename from lib/cocoa/README
rename to lib/cocoa/README.md
diff --git a/lib/cocoa/coding_standards.md b/lib/cocoa/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/cocoa/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/cocoa/src/TApplicationError.h b/lib/cocoa/src/TApplicationError.h
new file mode 100644
index 0000000..079881a
--- /dev/null
+++ b/lib/cocoa/src/TApplicationError.h
@@ -0,0 +1,55 @@
+/*
+ * 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 "TProtocol.h"
+
+extern NSString *TApplicationErrorDomain;
+
+typedef NS_ENUM (int, TApplicationError) {
+  TApplicationErrorUnknown                = 0,
+  TApplicationErrorUnknownMethod          = 1,
+  TApplicationErrorInvalidMessageType     = 2,
+  TApplicationErrorWrongMethodName        = 3,
+  TApplicationErrorBadSequenceId          = 4,
+  TApplicationErrorMissingResult          = 5,
+  TApplicationErrorInternalError          = 6,
+  TApplicationErrorProtocolError          = 7,
+  TApplicationErrorInvalidTransform       = 8,
+  TApplicationErrorInvalidProtocol        = 9,
+  TApplicationErrorUnsupportedClientType  = 10,
+};
+
+
+extern NSString *TApplicationErrorNameKey;
+extern NSString *TApplicationErrorReasonKey;
+extern NSString *TApplicationErrorMethodKey;
+
+
+@interface NSError (TApplicationError)
+
+@property (readonly, copy) NSString *name;
+@property (readonly, copy) NSString *reason;
+
++(instancetype) errorWithType:(TApplicationError)type reason:(NSString *)reason;
+
++(instancetype) read:(id<TProtocol>)protocol;
+
+-(BOOL) write:(id<TProtocol>)outProtocol error:(NSError *__autoreleasing *)error;
+
+@end
diff --git a/lib/cocoa/src/TApplicationError.m b/lib/cocoa/src/TApplicationError.m
new file mode 100644
index 0000000..080bc0b
--- /dev/null
+++ b/lib/cocoa/src/TApplicationError.m
@@ -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.
+ */
+
+#import "TApplicationError.h"
+#import "TProtocolUtil.h"
+
+
+NSString *TApplicationErrorDomain = @"TApplicationErrorDomain";
+
+
+NSString *TApplicationErrorNameKey = @"name";
+NSString *TApplicationErrorReasonKey = @"reason";
+NSString *TApplicationErrorMethodKey = @"method";
+
+
+@implementation NSError (TApplicationError)
+
+-(NSString *) reason
+{
+  return self.userInfo[TApplicationErrorReasonKey];
+}
+
+-(NSString *) name
+{
+  return self.userInfo[TApplicationErrorNameKey];
+}
+
++(instancetype) errorWithType:(TApplicationError)type reason:(NSString *)reason
+{
+  NSString *name;
+  switch (type) {
+  case TApplicationErrorUnknownMethod:
+    name = @"Unknown Method";
+    break;
+
+  case TApplicationErrorInvalidMessageType:
+    name = @"Invalid Message Type";
+    break;
+
+  case TApplicationErrorWrongMethodName:
+    name = @"Wrong Method Name";
+    break;
+
+  case TApplicationErrorBadSequenceId:
+    name = @"Bad Sequence ID";
+    break;
+
+  case TApplicationErrorMissingResult:
+    name = @"Missing Result";
+    break;
+
+  case TApplicationErrorInternalError:
+    name = @"Internal Error";
+    break;
+
+  case TApplicationErrorProtocolError:
+    name = @"Protocol Error";
+    break;
+
+  case TApplicationErrorInvalidTransform:
+    name = @"Invalid Transform";
+    break;
+
+  case TApplicationErrorInvalidProtocol:
+    name = @"Invalid Protocol";
+    break;
+
+  case TApplicationErrorUnsupportedClientType:
+    name = @"Unsupported Client Type";
+    break;
+
+  default:
+    name = @"Unknown";
+    break;
+  }
+
+  NSDictionary *userInfo;
+  if (reason) {
+    userInfo = @{TApplicationErrorNameKey:name,
+                 TApplicationErrorReasonKey:reason};
+  }
+  else {
+    userInfo = @{TApplicationErrorNameKey:name};
+  }
+
+  return [NSError errorWithDomain:TApplicationErrorDomain
+                             code:type
+                         userInfo:userInfo];
+}
+
+
++(instancetype) read:(id<TProtocol>)protocol
+{
+  NSString *reason = nil;
+  SInt32 type = TApplicationErrorUnknown;
+  SInt32 fieldType;
+  SInt32 fieldID;
+
+  NSError *error;
+  if (![protocol readStructBeginReturningName:NULL error:&error]) {
+    return error;
+  }
+
+  while (true) {
+
+    if (![protocol readFieldBeginReturningName:NULL
+                                          type:&fieldType
+                                       fieldID:&fieldID
+                                         error:&error])
+    {
+      return error;
+    }
+
+    if (fieldType == TTypeSTOP) {
+      break;
+    }
+
+    switch (fieldID) {
+    case 1:
+      if (fieldType == TTypeSTRING) {
+        if (![protocol readString:&reason error:&error]) {
+          return error;
+        }
+      }
+      else {
+        if (![TProtocolUtil skipType:fieldType onProtocol:protocol error:&error]) {
+          return error;
+        }
+      }
+      break;
+
+    case 2:
+      if (fieldType == TTypeI32) {
+        if (![protocol readI32:&type error:&error]) {
+          return error;
+        }
+      }
+      else {
+        if (![TProtocolUtil skipType:fieldType onProtocol:protocol error:&error]) {
+          return error;
+        }
+      }
+      break;
+
+    default:
+      if (![TProtocolUtil skipType:fieldType onProtocol:protocol error:&error]) {
+        return error;
+      }
+      break;
+    }
+    if (![protocol readFieldEnd:&error]) {
+      return error;
+    }
+
+  }
+
+  if (![protocol readStructEnd:&error]) {
+    return error;
+  }
+
+  return [NSError errorWithType:type reason:reason];
+}
+
+
+-(BOOL) write:(id<TProtocol>)protocol error:(NSError *__autoreleasing *)error
+{
+  if (![protocol writeStructBeginWithName:@"TApplicationException" error:error]) {
+    return NO;
+  }
+
+  if (self.localizedDescription != nil) {
+    if (![protocol writeFieldBeginWithName:@"message"
+                                      type:TTypeSTRING
+                                   fieldID:1 error:error])
+    {
+      return NO;
+    }
+
+    if (![protocol writeString:self.localizedDescription error:error]) {
+      return NO;
+    }
+
+    if (![protocol writeFieldEnd:error]) {
+      return NO;
+    }
+  }
+
+  if (![protocol writeFieldBeginWithName:@"type"
+                                    type:TTypeI32
+                                 fieldID:2
+                                   error:error])
+  {
+    return NO;
+  }
+
+  if (![protocol writeI32:(SInt32)self.code error:error]) {
+    return NO;
+  }
+
+  if (![protocol writeFieldEnd:error]) {
+    return NO;
+  }
+
+  if (![protocol writeFieldStop:error]) {
+    return NO;
+  }
+
+  if (![protocol writeStructEnd:error]) {
+    return NO;
+  }
+
+  return YES;
+}
+
+@end
diff --git a/lib/cocoa/src/TApplicationException.h b/lib/cocoa/src/TApplicationException.h
deleted file mode 100644
index 7b027d6..0000000
--- a/lib/cocoa/src/TApplicationException.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import "TException.h"
-#import "TProtocol.h"
-
-enum {
-  TApplicationException_UNKNOWN = 0,
-  TApplicationException_UNKNOWN_METHOD = 1,
-  TApplicationException_INVALID_MESSAGE_TYPE = 2,
-  TApplicationException_WRONG_METHOD_NAME = 3,
-  TApplicationException_BAD_SEQUENCE_ID = 4,
-  TApplicationException_MISSING_RESULT = 5,
-  TApplicationException_INTERNAL_ERROR = 6,
-  TApplicationException_PROTOCOL_ERROR = 7,
-  TApplicationException_INVALID_TRANSFORM = 8,
-  TApplicationException_INVALID_PROTOCOL = 9,
-  TApplicationException_UNSUPPORTED_CLIENT_TYPE = 10
-};
-
-// FIXME
-@interface TApplicationException : TException {
-  int mType;
-}
-
-+ (TApplicationException *) read: (id <TProtocol>) protocol;
-
-- (void) write: (id <TProtocol>) protocol;
-
-+ (TApplicationException *) exceptionWithType: (int) type
-                                       reason: (NSString *) message;
-
-@end
diff --git a/lib/cocoa/src/TApplicationException.m b/lib/cocoa/src/TApplicationException.m
deleted file mode 100644
index 974dfc5..0000000
--- a/lib/cocoa/src/TApplicationException.m
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import "TApplicationException.h"
-#import "TProtocolUtil.h"
-#import "TObjective-C.h"
-
-@implementation TApplicationException
-
-- (id) initWithType: (int) type
-             reason: (NSString *) reason
-{
-  mType = type;
-
-  NSString * name;
-  switch (type) {
-  case TApplicationException_UNKNOWN_METHOD:
-    name = @"Unknown method";
-    break;
-  case TApplicationException_INVALID_MESSAGE_TYPE:
-    name = @"Invalid message type";
-    break;
-  case TApplicationException_WRONG_METHOD_NAME:
-    name = @"Wrong method name";
-    break;
-  case TApplicationException_BAD_SEQUENCE_ID:
-    name = @"Bad sequence ID";
-    break;
-  case TApplicationException_MISSING_RESULT:
-    name = @"Missing result";
-    break;
-  case TApplicationException_INTERNAL_ERROR:
-    name = @"Internal error";
-    break;
-  case TApplicationException_PROTOCOL_ERROR:
-    name = @"Protocol error";
-    break;
-  case TApplicationException_INVALID_TRANSFORM:
-    name = @"Invalid transform";
-    break;
-  case TApplicationException_INVALID_PROTOCOL:
-    name = @"Invalid protocol";
-    break;
-  case TApplicationException_UNSUPPORTED_CLIENT_TYPE:
-    name = @"Unsupported client type";
-    break;
-  default:
-    name = @"Unknown";
-    break;
-  }
-
-  self = [super initWithName: name reason: reason userInfo: nil];
-  return self;
-}
-
-
-+ (TApplicationException *) read: (id <TProtocol>) protocol
-{
-  NSString * reason = nil;
-  int type = TApplicationException_UNKNOWN;
-  int fieldType;
-  int fieldID;
-
-  [protocol readStructBeginReturningName: NULL];
-
-  while (true) {
-    [protocol readFieldBeginReturningName: NULL
-              type: &fieldType
-              fieldID: &fieldID];
-    if (fieldType == TType_STOP) {
-      break;
-    }
-    switch (fieldID) {
-    case 1:
-      if (fieldType == TType_STRING) {
-        reason = [protocol readString];
-      } else {
-        [TProtocolUtil skipType: fieldType onProtocol: protocol];
-      }
-      break;
-    case 2:
-      if (fieldType == TType_I32) {
-        type = [protocol readI32];
-      } else {
-        [TProtocolUtil skipType: fieldType onProtocol: protocol];
-      }
-      break;
-    default:
-      [TProtocolUtil skipType: fieldType onProtocol: protocol];
-      break;
-    }
-    [protocol readFieldEnd];
-  }
-  [protocol readStructEnd];
-
-  return [TApplicationException exceptionWithType: type reason: reason];
-}
-
-
-- (void) write: (id <TProtocol>) protocol
-{
-  [protocol writeStructBeginWithName: @"TApplicationException"];
-
-  if ([self reason] != nil) {
-    [protocol writeFieldBeginWithName: @"message"
-                 type: TType_STRING
-                 fieldID: 1];
-    [protocol writeString: [self reason]];
-    [protocol writeFieldEnd];
-  }
-
-  [protocol writeFieldBeginWithName: @"type"
-               type: TType_I32
-               fieldID: 2];
-  [protocol writeI32: mType];
-  [protocol writeFieldEnd];
-
-  [protocol writeFieldStop];
-  [protocol writeStructEnd];
-}
-
-
-+ (TApplicationException *) exceptionWithType: (int) type
-                                      reason: (NSString *) reason
-{
-  return [[[TApplicationException alloc] initWithType: type
-                                         reason: reason] autorelease_stub];
-}
-
-@end
diff --git a/lib/cocoa/src/TBaseClient.h b/lib/cocoa/src/TBaseClient.h
new file mode 100644
index 0000000..0f73aa0
--- /dev/null
+++ b/lib/cocoa/src/TBaseClient.h
@@ -0,0 +1,27 @@
+/*
+ * 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 "TProtocol.h"
+#import "TApplicationError.h"
+
+@interface TBaseClient : NSObject
+
+-(NSError *) checkIncomingMessageException:(id<TProtocol>)protocol;
+
+@end
diff --git a/lib/cocoa/src/TBaseClient.m b/lib/cocoa/src/TBaseClient.m
new file mode 100644
index 0000000..249cae0
--- /dev/null
+++ b/lib/cocoa/src/TBaseClient.m
@@ -0,0 +1,51 @@
+/*
+ * 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 "TBaseClient.h"
+#import "TApplicationError.h"
+
+
+@interface TBaseClient ()
+@end
+
+
+@implementation TBaseClient
+
+-(NSError *) checkIncomingMessageException:(id<TProtocol>)inProtocol
+{
+  NSError *thriftError;
+
+  SInt32 msgType = 0;
+  if (![inProtocol readMessageBeginReturningName:nil type:&msgType sequenceID:NULL error:&thriftError]) {
+    return thriftError;
+  }
+
+  if (msgType == TMessageTypeEXCEPTION) {
+
+    thriftError = [NSError read:inProtocol];
+
+    [inProtocol readMessageEnd:NULL];
+
+    return thriftError;
+  }
+
+  return nil;
+}
+
+@end
diff --git a/lib/cocoa/src/TBinary.swift b/lib/cocoa/src/TBinary.swift
new file mode 100644
index 0000000..c8a3660
--- /dev/null
+++ b/lib/cocoa/src/TBinary.swift
@@ -0,0 +1,122 @@
+/*
+ * 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 Foundation
+
+
+public struct TBinary : TSerializable {
+  
+  public static var thriftType : TType { return .STRING }
+  
+  private var storage : NSData
+  
+  public init() {
+    self.storage = NSData()
+  }
+  
+  public init(contentsOfFile file: String, options: NSDataReadingOptions = []) throws {
+    self.storage = try NSData(contentsOfFile: file, options: options)
+  }
+  
+  public init(contentsOfURL URL: NSURL, options: NSDataReadingOptions = []) throws {
+    self.storage = try NSData(contentsOfURL: URL, options: options)
+  }
+  
+  public init?(base64EncodedData base64Data: NSData, options: NSDataBase64DecodingOptions = []) {
+    guard let storage = NSData(base64EncodedData: base64Data, options: options) else {
+      return nil
+    }
+    self.storage = storage
+  }
+  
+  public init(data: NSData) {
+    self.storage = data
+  }
+  
+  public var length : Int {
+    return storage.length
+  }
+  
+  public var hashValue : Int {
+    return storage.hashValue
+  }
+  
+  public var bytes : UnsafePointer<Void> {
+    return storage.bytes
+  }
+  
+  public func getBytes(buffer: UnsafeMutablePointer<Void>, length: Int) {
+    storage.getBytes(buffer, length: length)
+  }
+  
+  public func getBytes(buffer: UnsafeMutablePointer<Void>, range: Range<Int>) {
+    storage.getBytes(buffer, range: NSRange(range))
+  }
+  
+  public func subBinaryWithRange(range: Range<Int>) -> TBinary {
+    return TBinary(data: storage.subdataWithRange(NSRange(range)))
+  }
+  
+  public func writeToFile(path: String, options: NSDataWritingOptions = []) throws {
+    try storage.writeToFile(path, options: options)
+  }
+  
+  public func writeToURL(url: NSURL, options: NSDataWritingOptions = []) throws {
+    try storage.writeToURL(url, options: options)
+  }
+  
+  public func rangeOfData(dataToFind data: NSData, options: NSDataSearchOptions, range: Range<Int>) -> Range<Int>? {
+    return storage.rangeOfData(data, options: options, range: NSRange(range)).toRange()
+  }
+  
+  public func enumerateByteRangesUsingBlock(block: (UnsafePointer<Void>, Range<Int>, inout Bool) -> Void) {
+    storage.enumerateByteRangesUsingBlock { bytes, range, stop in
+      var stopTmp = Bool(stop.memory)
+      block(bytes, range.toRange()!, &stopTmp)
+      stop.memory = ObjCBool(stopTmp)
+    }
+  }
+  
+  public static func readValueFromProtocol(proto: TProtocol) throws -> TBinary {
+    var data : NSData?
+    try proto.readBinary(&data)
+    return TBinary(data: data!)
+  }
+  
+  public static func writeValue(value: TBinary, toProtocol proto: TProtocol) throws {
+    try proto.writeBinary(value.storage)
+  }
+  
+}
+
+extension TBinary : CustomStringConvertible, CustomDebugStringConvertible {
+  
+  public var description : String {
+    return storage.description
+  }
+  
+  public var debugDescription : String {
+    return storage.debugDescription
+  }
+  
+}
+
+public func ==(lhs: TBinary, rhs: TBinary) -> Bool {
+  return lhs.storage == rhs.storage
+}
diff --git a/lib/cocoa/src/TEnum.swift b/lib/cocoa/src/TEnum.swift
new file mode 100644
index 0000000..562a53a
--- /dev/null
+++ b/lib/cocoa/src/TEnum.swift
@@ -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.
+ */
+
+import Foundation
+
+
+public protocol TEnum : TSerializable {
+  
+}
+
+public extension TEnum {
+  
+  public static var thriftType : TType { return TType.I32 }
+  
+}
diff --git a/lib/cocoa/src/TError.h b/lib/cocoa/src/TError.h
new file mode 100644
index 0000000..abb72c7
--- /dev/null
+++ b/lib/cocoa/src/TError.h
@@ -0,0 +1,23 @@
+/*
+ * 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 <Foundation/Foundation.h>
+
+
+extern NSString *TErrorDomain;
diff --git a/lib/cocoa/src/TError.m b/lib/cocoa/src/TError.m
new file mode 100644
index 0000000..df7f92d
--- /dev/null
+++ b/lib/cocoa/src/TError.m
@@ -0,0 +1,23 @@
+/*
+ * 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 "TError.h"
+
+
+NSString *TErrorDomain = @"TErrorDomain";
diff --git a/lib/cocoa/src/TException.h b/lib/cocoa/src/TException.h
deleted file mode 100644
index e56f4fa..0000000
--- a/lib/cocoa/src/TException.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import <Foundation/Foundation.h>
-
-@interface TException : NSException {
-}
-
-+ (id) exceptionWithName: (NSString *) name;
-
-+ (id) exceptionWithName: (NSString *) name
-                  reason: (NSString *) reason;
-
-+ (id) exceptionWithName: (NSString *) name
-                  reason: (NSString *) reason
-                   error: (NSError *) error;
-
-@end
diff --git a/lib/cocoa/src/TException.m b/lib/cocoa/src/TException.m
deleted file mode 100644
index 0160e3b..0000000
--- a/lib/cocoa/src/TException.m
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import "TException.h"
-#import "TObjective-C.h"
-
-@implementation TException
-
-+ (id) exceptionWithName: (NSString *) name
-{
-  return [self exceptionWithName: name reason: @"unknown" error: nil];
-}
-
-
-+ (id) exceptionWithName: (NSString *) name
-                  reason: (NSString *) reason
-{
-  return [self exceptionWithName: name reason: reason error: nil];
-}
-
-
-+ (id) exceptionWithName: (NSString *) name
-                  reason: (NSString *) reason
-                   error: (NSError *) error
-{
-  NSDictionary * userInfo = nil;
-  if (error != nil) {
-    userInfo = [NSDictionary dictionaryWithObject: error forKey: @"error"];
-  }
-
-  return [super exceptionWithName: name
-                reason: reason
-                userInfo: userInfo];
-}
-
-
-- (NSString *) description
-{
-  NSMutableString * result = [NSMutableString stringWithString: [self name]];
-  [result appendFormat: @": %@", [self reason]];
-  if ([self userInfo] != nil) {
-    [result appendFormat: @"\n  userInfo = %@", [self userInfo]];
-  }
-
-  return result;
-}
-
-
-@end
diff --git a/lib/cocoa/src/TList.swift b/lib/cocoa/src/TList.swift
new file mode 100644
index 0000000..005bd81
--- /dev/null
+++ b/lib/cocoa/src/TList.swift
@@ -0,0 +1,148 @@
+/*
+ * 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 Foundation
+
+
+
+public struct TList<Element : TSerializable> : MutableCollectionType, Hashable, ArrayLiteralConvertible, TSerializable {
+  
+  public static var thriftType : TType { return .LIST }
+  
+  typealias Storage = Array<Element>
+
+  public typealias Index = Storage.Index
+  
+  private var storage = Storage()
+  
+  public var startIndex : Index {
+    return storage.startIndex
+  }
+  
+  public var endIndex : Index {
+    return storage.endIndex
+  }
+
+  public subscript (position: Index) -> Element {
+    get {
+      return storage[position]
+    }
+    set {
+      storage[position] = newValue
+    }
+  }
+  
+  public var hashValue : Int {
+    let prime = 31
+    var result = 1
+    for element in storage {
+      result = prime * result + element.hashValue
+    }
+    return result
+  }
+  
+  public init(arrayLiteral elements: Element...) {
+    self.storage = Storage(storage)
+  }
+  
+  public init() {
+    self.storage = Storage()
+  }
+  
+  public mutating func append(newElement: Element) {
+    self.storage.append(newElement)
+  }
+  
+  public mutating func appendContentsOf<C : CollectionType where C.Generator.Element == Element>(newstorage: C) {
+    self.storage.appendContentsOf(newstorage)
+  }
+  
+  public mutating func insert(newElement: Element, atIndex index: Int) {
+    self.storage.insert(newElement, atIndex: index)
+  }
+  
+  public mutating func insertContentsOf<C : CollectionType where C.Generator.Element == Element>(newElements: C, at index: Int) {
+    self.storage.insertContentsOf(newElements, at: index)
+  }
+  
+  public mutating func removeAll(keepCapacity keepCapacity: Bool = true) {
+    self.storage.removeAll(keepCapacity: keepCapacity)
+  }
+  
+  public mutating func removeAtIndex(index: Index) {
+    self.storage.removeAtIndex(index)
+  }
+  
+  public mutating func removeFirst(n: Int = 0) {
+    self.storage.removeFirst(n)
+  }
+  
+  public mutating func removeLast() -> Element {
+    return self.storage.removeLast()
+  }
+  
+  public mutating func removeRange(subRange: Range<Index>) {
+    self.storage.removeRange(subRange)
+  }
+  
+  public mutating func reserveCapacity(minimumCapacity: Int) {
+    self.storage.reserveCapacity(minimumCapacity)
+  }
+  
+  public static func readValueFromProtocol(proto: TProtocol) throws -> TList {
+    let (elementType, size) = try proto.readListBegin()
+    if elementType != Element.thriftType {
+      throw NSError(
+        domain: TProtocolErrorDomain,
+        code: Int(TProtocolError.InvalidData.rawValue),
+        userInfo: [TProtocolErrorExtendedErrorKey: NSNumber(int: TProtocolExtendedError.UnexpectedType.rawValue)])
+    }
+    var list = TList()
+    for _ in 0..<size {
+      let element = try Element.readValueFromProtocol(proto)
+      list.storage.append(element)
+    }
+    try proto.readListEnd()
+    return list
+  }
+  
+  public static func writeValue(value: TList, toProtocol proto: TProtocol) throws {
+    try proto.writeListBeginWithElementType(Element.thriftType, size: value.count)
+    for element in value.storage {
+      try Element.writeValue(element, toProtocol: proto)
+    }
+    try proto.writeListEnd()
+  }
+}
+
+extension TList : CustomStringConvertible, CustomDebugStringConvertible {
+  
+  public var description : String {
+    return storage.description
+  }
+  
+  public var debugDescription : String {
+    return storage.debugDescription
+  }
+  
+}
+
+public func ==<Element>(lhs: TList<Element>, rhs: TList<Element>) -> Bool {
+  return lhs.storage == rhs.storage
+}
diff --git a/lib/cocoa/src/TMap.swift b/lib/cocoa/src/TMap.swift
new file mode 100644
index 0000000..e96e747
--- /dev/null
+++ b/lib/cocoa/src/TMap.swift
@@ -0,0 +1,158 @@
+/*
+ * 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 Foundation
+
+
+public struct TMap<Key : TSerializable, Value : TSerializable> : CollectionType, DictionaryLiteralConvertible, TSerializable {
+  
+  public static var thriftType : TType { return .MAP }
+
+  typealias Storage = Dictionary<Key, Value>
+
+  public typealias Index = Storage.Index
+
+  public typealias Element = Storage.Element
+  
+  private var storage : Storage
+
+  public var startIndex : Index {
+    return storage.startIndex
+  }
+  
+  public var endIndex: Index {
+    return storage.endIndex
+  }
+
+  public var keys: LazyMapCollection<[Key : Value], Key> {
+    return storage.keys
+  }
+  
+  public var values: LazyMapCollection<[Key : Value], Value> {
+    return storage.values
+  }
+  
+  public init() {
+    storage = Storage()
+  }
+  
+  public init(dictionaryLiteral elements: (Key, Value)...) {
+    storage = Storage()
+    for (key, value) in elements {
+      storage[key] = value
+    }
+  }
+  
+  public init(minimumCapacity: Int) {
+    storage = Storage(minimumCapacity: minimumCapacity)
+  }
+  
+  public subscript (position: Index) -> Element {
+    get {
+      return storage[position]
+    }
+  }
+  
+  public func indexForKey(key: Key) -> Index? {
+    return storage.indexForKey(key)
+  }
+  
+  public subscript (key: Key) -> Value? {
+    get {
+      return storage[key]
+    }
+    set {
+      storage[key] = newValue
+    }
+  }
+
+  public mutating func updateValue(value: Value, forKey key: Key) -> Value? {
+    return updateValue(value, forKey: key)
+  }
+  
+  public mutating func removeAtIndex(index: DictionaryIndex<Key, Value>) -> (Key, Value) {
+    return removeAtIndex(index)
+  }
+  
+  public mutating func removeValueForKey(key: Key) -> Value? {
+    return storage.removeValueForKey(key)
+  }
+  
+  public mutating func removeAll(keepCapacity keepCapacity: Bool = false) {
+    storage.removeAll(keepCapacity: keepCapacity)
+  }
+
+  public var hashValue : Int {
+    let prime = 31
+    var result = 1
+    for (key, value) in storage {
+      result = prime * result + key.hashValue
+      result = prime * result + value.hashValue
+    }
+    return result
+  }
+  
+  public static func readValueFromProtocol(proto: TProtocol) throws -> TMap {
+    let (keyType, valueType, size) = try proto.readMapBegin()
+    if keyType != Key.thriftType || valueType != Value.thriftType {
+      throw NSError(
+        domain: TProtocolErrorDomain,
+        code: Int(TProtocolError.InvalidData.rawValue),
+        userInfo: [TProtocolErrorExtendedErrorKey: NSNumber(int: TProtocolExtendedError.UnexpectedType.rawValue)])
+    }
+    var map = TMap()
+    for _ in 0..<size {
+      let key = try Key.readValueFromProtocol(proto)
+      let value = try Value.readValueFromProtocol(proto)
+      map.storage[key] = value
+    }
+    try proto.readMapEnd()
+    return map
+  }
+  
+  public static func writeValue(value: TMap, toProtocol proto: TProtocol) throws {
+    try proto.writeMapBeginWithKeyType(Key.thriftType, valueType: Value.thriftType, size: value.count)
+    for (key, value) in value.storage {
+      try Key.writeValue(key, toProtocol: proto)
+      try Value.writeValue(value, toProtocol: proto)
+    }
+    try proto.writeMapEnd()
+  }
+  
+}
+
+
+extension TMap : CustomStringConvertible, CustomDebugStringConvertible {
+  
+  public var description : String {
+    return storage.description
+  }
+  
+  public var debugDescription : String {
+    return storage.debugDescription
+  }
+  
+}
+
+public func ==<Key, Value>(lhs: TMap<Key,Value>, rhs: TMap<Key, Value>) -> Bool {
+  if lhs.count != rhs.count {
+    return false
+  }
+  return lhs.storage == rhs.storage
+}
diff --git a/lib/cocoa/src/TObjective-C.h b/lib/cocoa/src/TObjective-C.h
deleted file mode 100644
index 9c0831d..0000000
--- a/lib/cocoa/src/TObjective-C.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*
- * TObjective-C.h is for supporting coexistence of both the ARC (Automatic 
- * Reference Counting) mode and the Non-ARC mode of Objective-C 
- * in the same source code.
- *
- *                  2011/11/14  HIRANO Satoshi (AIST, Japan)
- *
- * Before:
- *
- *    var = [aObject retain];
- *    [aObject release];
- *    [aObject autorelease];
- *    [super dealloc];
- *    CFFunction(obj);
- *
- * ARC and Non-ARC compatible:
- *
- *    #import "TObjective-C.h"
- *    var = [aObject retain_stub];
- *    [aObject release_stub];
- *    [aObject autorelease_stub];
- *    [super dealloc_stub];
- *    CFFunction(bridge_stub obj);
- *
- *    Don't use retain_stub for @property(retain).
- *    Use NSAutoreleasePool like this:
- *        #if __has_feature(objc_arc)
- *          @autoreleasepool {
- *              // code 
- *          }
- *        #else
- *          NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init...
- *          // code
- *          [pool release];
- *        #endif
- */
-
-
-#if !defined(retain_stub)
-#if __has_feature(objc_arc)
-#define retain_stub self
-#define autorelease_stub self
-#define release_stub self
-#define dealloc_stub self
-#define bridge_stub __bridge
-#else
-#define retain_stub retain
-#define autorelease_stub autorelease
-#define release_stub release
-#define dealloc_stub dealloc
-#define bridge_stub
-#endif
-#endif
diff --git a/lib/cocoa/src/TProcessor.h b/lib/cocoa/src/TProcessor.h
index 980be94..20c72e2 100644
--- a/lib/cocoa/src/TProcessor.h
+++ b/lib/cocoa/src/TProcessor.h
@@ -20,10 +20,16 @@
 #import <Foundation/Foundation.h>
 #import "TProtocol.h"
 
+NS_ASSUME_NONNULL_BEGIN
+
 
 @protocol TProcessor <NSObject>
 
-- (BOOL) processOnInputProtocol: (id <TProtocol>) inProtocol
-                 outputProtocol: (id <TProtocol>) outProtocol;
+-(BOOL) processOnInputProtocol:(id <TProtocol>)inProtocol
+                outputProtocol:(id <TProtocol>)outProtocol
+                         error:(NSError **)error;
 
 @end
+
+
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/TProcessorFactory.h b/lib/cocoa/src/TProcessorFactory.h
index 29d12b3..85020a5 100644
--- a/lib/cocoa/src/TProcessorFactory.h
+++ b/lib/cocoa/src/TProcessorFactory.h
@@ -20,8 +20,14 @@
 #import <Foundation/Foundation.h>
 #import "TProcessor.h"
 
+NS_ASSUME_NONNULL_BEGIN
+
+
 @protocol TProcessorFactory <NSObject>
 
-- (id<TProcessor>) processorForTransport: (id<TTransport>) transport;
+-(id<TProcessor>) processorForTransport:(id<TTransport>)transport;
 
 @end
+
+
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/TProtocol.swift b/lib/cocoa/src/TProtocol.swift
new file mode 100644
index 0000000..1775849
--- /dev/null
+++ b/lib/cocoa/src/TProtocol.swift
@@ -0,0 +1,190 @@
+/*
+ * 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 Foundation
+
+
+public extension TProtocol {
+  
+  public func readMessageBegin() throws -> (String, TMessageType, Int) {
+    
+    var name : NSString?
+    var type : Int32 = -1
+    var sequenceID : Int32 = -1
+    
+    try readMessageBeginReturningName(&name, type: &type, sequenceID: &sequenceID)
+    
+    return (name as String!, TMessageType(rawValue: type)!, Int(sequenceID))
+  }
+  
+  public func writeMessageBeginWithName(name: String, type: TMessageType, sequenceID: Int) throws {
+    try writeMessageBeginWithName(name, type: type.rawValue, sequenceID: Int32(sequenceID))
+  }
+  
+  public func readStructBegin() throws -> (String?) {
+    
+    var name : NSString? = nil
+    
+    try readStructBeginReturningName(&name)
+    
+    return (name as String?)
+  }
+  
+  public func readFieldBegin() throws -> (String?, TType, Int) {
+    
+    var name : NSString? = nil
+    var type : Int32 = -1
+    var fieldID : Int32 = -1
+    
+    try readFieldBeginReturningName(&name, type: &type, fieldID: &fieldID)
+    
+    return (name as String?, TType(rawValue: type)!, Int(fieldID))
+  }
+  
+  public func writeFieldBeginWithName(name: String, type: TType, fieldID: Int) throws {
+    try writeFieldBeginWithName(name, type: type.rawValue, fieldID: Int32(fieldID))
+  }
+  
+  public func readMapBegin() throws -> (TType, TType, Int32) {
+    
+    var keyType : Int32 = -1
+    var valueType : Int32 = -1
+    var size : Int32 = 0
+    
+    try readMapBeginReturningKeyType(&keyType, valueType: &valueType, size: &size)
+    
+    return (TType(rawValue: keyType)!, TType(rawValue: valueType)!, size)
+  }
+  
+  public func writeMapBeginWithKeyType(keyType: TType, valueType: TType, size: Int) throws {
+    try writeMapBeginWithKeyType(keyType.rawValue, valueType: valueType.rawValue, size: Int32(size))
+  }
+  
+  public func readSetBegin() throws -> (TType, Int32) {
+    
+    var elementType : Int32 = -1
+    var size : Int32 = 0
+    
+    try readSetBeginReturningElementType(&elementType, size: &size)
+    
+    return (TType(rawValue: elementType)!, size)
+  }
+  
+  public func writeSetBeginWithElementType(elementType: TType, size: Int) throws {
+    try writeSetBeginWithElementType(elementType.rawValue, size: Int32(size))
+  }
+  
+  public func readListBegin() throws -> (TType, Int32) {
+    
+    var elementType : Int32 = -1
+    var size : Int32 = 0
+    
+    try readListBeginReturningElementType(&elementType, size: &size)
+    
+    return (TType(rawValue: elementType)!, size)
+  }
+  
+  public func writeListBeginWithElementType(elementType: TType, size: Int) throws {
+    try writeListBeginWithElementType(elementType.rawValue, size: Int32(size))
+  }
+  
+  public func writeFieldValue<T: TSerializable>(value: T, name: String, type: TType, id: Int32) throws {
+    try writeFieldBeginWithName(name, type: type.rawValue, fieldID: id)
+    try writeValue(value)
+    try writeFieldEnd()
+  }
+  
+  public func readValue<T: TSerializable>() throws -> T {
+    return try T.readValueFromProtocol(self)
+  }
+  
+  public func writeValue<T: TSerializable>(value: T) throws {
+    try T.writeValue(value, toProtocol: self)
+  }
+  
+  public func readResultMessageBegin() throws {
+    
+    let (_, type, _) = try readMessageBegin();
+    
+    if type == .EXCEPTION {
+      let x = try readException()
+      throw x
+    }
+    
+    return
+  }
+  
+  public func validateValue(value: Any?, named name: String) throws {
+    
+    if value == nil {
+      throw NSError(
+        domain: TProtocolErrorDomain,
+        code: Int(TProtocolError.Unknown.rawValue),
+        userInfo: [TProtocolErrorFieldNameKey: name])
+    }
+    
+  }
+  
+  public func readException() throws -> ErrorType {
+    
+    var reason : String?
+    var type = TApplicationError.Unknown
+    
+    try readStructBegin()
+    
+    fields: while (true) {
+      
+      let (_, fieldType, fieldID) = try readFieldBegin()
+      
+      switch (fieldID, fieldType) {
+      case (_, .STOP):
+        break fields
+        
+      case (1, .STRING):
+        reason = try readValue() as String
+        
+      case (2, .I32):
+        let typeVal = try readValue() as Int32
+        if let tmp = TApplicationError(rawValue: typeVal) {
+          type = tmp
+        }
+        
+      case let (_, unknownType):
+        try skipType(unknownType)
+      }
+      
+      try readFieldEnd()
+    }
+    
+    try readStructEnd()
+    
+    return NSError(type:type, reason:reason ?? "")
+  }
+  
+  public func writeExceptionForMessageName(name: String, sequenceID: Int, ex: NSError) throws {
+    try writeMessageBeginWithName(name, type: .EXCEPTION, sequenceID: sequenceID)
+    try ex.write(self)
+    try writeMessageEnd()
+  }
+  
+  public func skipType(type: TType) throws {
+    try TProtocolUtil.skipType(type.rawValue, onProtocol: self)
+  }
+  
+}
diff --git a/lib/cocoa/src/TSerializable.swift b/lib/cocoa/src/TSerializable.swift
new file mode 100644
index 0000000..3fdfd41
--- /dev/null
+++ b/lib/cocoa/src/TSerializable.swift
@@ -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.
+ */
+
+import Foundation
+
+
+public protocol TSerializable : Hashable {
+  
+  static var thriftType : TType { get }
+  
+  init()
+  
+  static func readValueFromProtocol(proto: TProtocol) throws -> Self
+  
+  static func writeValue(value: Self, toProtocol proto: TProtocol) throws
+  
+}
+
+
+
+infix operator ?== {}
+
+public func ?==<T: TSerializable>(lhs: T?, rhs: T?) -> Bool {
+  if let l = lhs, r = rhs {
+    return l == r
+  }
+  return lhs == rhs
+}
+
+public func ?==<T: TSerializable>(lhs: T, rhs: T) -> Bool {
+  return lhs == rhs
+}
+
+
+
+extension Bool : TSerializable {
+  
+  public static let thriftType = TType.BOOL
+  
+  public static func readValueFromProtocol(proto: TProtocol) throws -> Bool {
+    var value : ObjCBool = false
+    try proto.readBool(&value)
+    return value.boolValue
+  }
+  
+  public static func writeValue(value: Bool, toProtocol proto: TProtocol) throws {
+    try proto.writeBool(value)
+  }
+  
+}
+
+extension Int8 : TSerializable {
+  
+  public static let thriftType = TType.BYTE
+  
+  public static func readValueFromProtocol(proto: TProtocol) throws -> Int8 {
+    var value = UInt8()
+    try proto.readByte(&value)
+    return Int8(value)
+  }
+  
+  public static func writeValue(value: Int8, toProtocol proto: TProtocol) throws {
+    try proto.writeByte(UInt8(value))
+  }
+  
+}
+
+extension Int16 : TSerializable {
+  
+  public static let thriftType = TType.I16
+  
+  public static func readValueFromProtocol(proto: TProtocol) throws -> Int16 {
+    var value = Int16()
+    try proto.readI16(&value)
+    return value
+  }
+  
+  public static func writeValue(value: Int16, toProtocol proto: TProtocol) throws {
+    try proto.writeI16(value)
+  }
+  
+}
+
+extension Int : TSerializable {
+  
+  public static let thriftType = TType.I32
+  
+  public static func readValueFromProtocol(proto: TProtocol) throws -> Int {
+    var value = Int32()
+    try proto.readI32(&value)
+    return Int(value)
+  }
+  
+  public static func writeValue(value: Int, toProtocol proto: TProtocol) throws {
+    try proto.writeI32(Int32(value))
+  }
+  
+}
+
+extension Int32 : TSerializable {
+  
+  public static let thriftType = TType.I32
+  
+  public static func readValueFromProtocol(proto: TProtocol) throws -> Int32 {
+    var value = Int32()
+    try proto.readI32(&value)
+    return value
+  }
+  
+  public static func writeValue(value: Int32, toProtocol proto: TProtocol) throws {
+    try proto.writeI32(value)
+  }
+  
+}
+
+extension Int64 : TSerializable {
+  
+  public static let thriftType = TType.I64
+  
+  public static func readValueFromProtocol(proto: TProtocol) throws -> Int64 {
+    var value = Int64()
+    try proto.readI64(&value)
+    return value
+  }
+  
+  public static func writeValue(value: Int64, toProtocol proto: TProtocol) throws {
+    try proto.writeI64(value)
+  }
+  
+}
+
+extension Double : TSerializable {
+  
+  public static let thriftType = TType.DOUBLE
+  
+  public static func readValueFromProtocol(proto: TProtocol) throws -> Double {
+    var value = Double()
+    try proto.readDouble(&value)
+    return value
+  }
+  
+  public static func writeValue(value: Double, toProtocol proto: TProtocol) throws {
+    try proto.writeDouble(value)
+  }
+  
+}
+
+extension String : TSerializable {
+  
+  public static let thriftType = TType.STRING
+  
+  public static func readValueFromProtocol(proto: TProtocol) throws -> String {
+    var value : NSString?
+    try proto.readString(&value)
+    return value as! String
+  }
+  
+  public static func writeValue(value: String, toProtocol proto: TProtocol) throws {
+    try proto.writeString(value)
+  }
+  
+}
diff --git a/lib/cocoa/src/TSet.swift b/lib/cocoa/src/TSet.swift
new file mode 100644
index 0000000..85833e5
--- /dev/null
+++ b/lib/cocoa/src/TSet.swift
@@ -0,0 +1,161 @@
+/*
+ * 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 Foundation
+
+
+public struct TSet<Element : TSerializable> : CollectionType, ArrayLiteralConvertible, TSerializable {
+  
+  public static var thriftType : TType { return .SET }
+  
+  public typealias Index = Storage.Index
+  
+  typealias Storage = Set<Element>
+  
+  private var storage : Storage
+  
+  public init() {
+    storage = Storage()
+  }
+  
+  public init(arrayLiteral elements: Element...) {
+    storage = Storage(elements)
+  }
+  
+  public init<S : SequenceType where S.Generator.Element == Element>(_ sequence: S) {
+    storage = Storage(sequence)    
+  }
+  
+  public var startIndex : Index { return storage.startIndex }
+  
+  public var endIndex : Index { return storage.endIndex }
+  
+  public mutating func insert(member: Element) {
+    return storage.insert(member)
+  }
+  
+  public mutating func remove(element: Element) -> Element? {
+    return storage.remove(element)
+  }
+  
+  public mutating func removeAll(keepCapacity keepCapacity: Bool = false) {
+    return storage.removeAll(keepCapacity: keepCapacity)
+  }
+  
+  public mutating func removeAtIndex(index: SetIndex<Element>) -> Element {
+    return storage.removeAtIndex(index)
+  }
+  
+  public subscript (position: SetIndex<Element>) -> Element {
+    return storage[position]
+  }
+  
+  public func union(other: TSet) -> TSet {
+    return TSet(storage.union(other))
+  }
+  
+  public func intersect(other: TSet) -> TSet {
+    return TSet(storage.intersect(other))
+  }
+  
+  public func exclusiveOr(other: TSet) -> TSet {
+    return TSet(storage.exclusiveOr(other))
+  }
+  
+  public func subtract(other: TSet) -> TSet {
+    return TSet(storage.subtract(other))
+  }
+  
+  public mutating func intersectInPlace(other: TSet) {
+    storage.intersectInPlace(other)
+  }
+
+  public mutating func exclusiveOrInPlace(other: TSet) {
+    storage.exclusiveOrInPlace(other)
+  }
+
+  public mutating func subtractInPlace(other: TSet) {
+    storage.subtractInPlace(other)
+  }  
+
+  public func isSubsetOf(other: TSet) -> Bool {
+    return storage.isSubsetOf(other)
+  }
+
+  public func isDisjointWith(other: TSet) -> Bool {
+    return storage.isDisjointWith(other)
+  }
+  
+  public func isSupersetOf(other: TSet) -> Bool {
+    return storage.isSupersetOf(other)
+  }
+
+  public var isEmpty: Bool { return storage.isEmpty }
+
+  public var hashValue : Int {
+    let prime = 31
+    var result = 1
+    for element in storage {
+      result = prime * result + element.hashValue
+    }
+    return result
+  }
+  
+  public static func readValueFromProtocol(proto: TProtocol) throws -> TSet {
+    let (elementType, size) = try proto.readSetBegin()
+    if elementType != Element.thriftType {
+      throw NSError(
+        domain: TProtocolErrorDomain,
+        code: Int(TProtocolError.InvalidData.rawValue),
+        userInfo: [TProtocolErrorExtendedErrorKey: NSNumber(int: elementType.rawValue)])
+    }
+    var set = TSet()
+    for _ in 0..<size {
+      let element = try Element.readValueFromProtocol(proto)
+      set.storage.insert(element)
+    }
+    try proto.readSetEnd()
+    return set
+  }
+  
+  public static func writeValue(value: TSet, toProtocol proto: TProtocol) throws {
+    try proto.writeSetBeginWithElementType(Element.thriftType, size: value.count)
+    for element in value.storage {
+      try Element.writeValue(element, toProtocol: proto)
+    }
+    try proto.writeSetEnd()
+  }
+  
+}
+
+extension TSet : CustomStringConvertible, CustomDebugStringConvertible {
+  
+  public var description : String {
+    return storage.description
+  }
+  
+  public var debugDescription : String {
+    return storage.debugDescription
+  }
+  
+}
+
+public func ==<Element>(lhs: TSet<Element>, rhs: TSet<Element>) -> Bool {
+  return lhs.storage == rhs.storage
+}
diff --git a/lib/cocoa/src/TSharedProcessorFactory.h b/lib/cocoa/src/TSharedProcessorFactory.h
index cf4a462..c75fad1 100644
--- a/lib/cocoa/src/TSharedProcessorFactory.h
+++ b/lib/cocoa/src/TSharedProcessorFactory.h
@@ -20,8 +20,9 @@
 #import <Foundation/Foundation.h>
 #import "TProcessorFactory.h"
 
-@interface TSharedProcessorFactory : NSObject <TProcessorFactory> {
-  id<TProcessor> mSharedProcessor;
-}
-- (id) initWithSharedProcessor: (id<TProcessor>) sharedProcessor;
+
+@interface TSharedProcessorFactory : NSObject <TProcessorFactory>
+
+-(id) initWithSharedProcessor:(id<TProcessor>)sharedProcessor;
+
 @end
diff --git a/lib/cocoa/src/TSharedProcessorFactory.m b/lib/cocoa/src/TSharedProcessorFactory.m
index a0007c0..3d55f47 100644
--- a/lib/cocoa/src/TSharedProcessorFactory.m
+++ b/lib/cocoa/src/TSharedProcessorFactory.m
@@ -19,34 +19,31 @@
 
 
 #import "TSharedProcessorFactory.h"
-#import "TObjective-C.h"
+
+
+@interface TSharedProcessorFactory ()
+
+@property(strong, nonatomic) id<TProcessor> sharedProcessor;
+
+@end
 
 
 @implementation TSharedProcessorFactory
 
 
-- (id) initWithSharedProcessor: (id<TProcessor>) sharedProcessor
+-(id) initWithSharedProcessor:(id<TProcessor>)sharedProcessor
 {
   self = [super init];
-  if (!self) {
-    return nil;
+  if (self) {
+    _sharedProcessor = sharedProcessor;
   }
-  
-  mSharedProcessor = [sharedProcessor retain_stub];
+
   return self;
 }
 
-
-- (void) dealloc
+-(id<TProcessor>) processorForTransport:(id<TTransport>)transport
 {
-  [mSharedProcessor release_stub];
-  [super dealloc_stub];
-}
-
-
-- (id<TProcessor>) processorForTransport: (id<TTransport>) transport
-{
-  return [[mSharedProcessor retain_stub] autorelease_stub];
+  return _sharedProcessor;
 }
 
 @end
diff --git a/lib/cocoa/src/TStruct.swift b/lib/cocoa/src/TStruct.swift
new file mode 100644
index 0000000..cea72e7
--- /dev/null
+++ b/lib/cocoa/src/TStruct.swift
@@ -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.
+ */
+
+import Foundation
+
+
+public protocol TStruct : TSerializable {
+}
+
+
+public extension TStruct {
+  
+  public static var thriftType : TType { return TType.STRUCT }
+  
+}
diff --git a/lib/cocoa/src/Thrift.h b/lib/cocoa/src/Thrift.h
new file mode 100644
index 0000000..d01826d
--- /dev/null
+++ b/lib/cocoa/src/Thrift.h
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+#define ThriftVersion @"1.0.0"
diff --git a/lib/cocoa/src/protocol/TBase.h b/lib/cocoa/src/protocol/TBase.h
index 33037ef..9935d50 100644
--- a/lib/cocoa/src/protocol/TBase.h
+++ b/lib/cocoa/src/protocol/TBase.h
@@ -26,16 +26,21 @@
 /**
  * De-serialize object from the given input protocol
  *
- * @param input protocol used for reading 
+ * @param inProtocol protocol used for reading
  */
-- (void) read: (id <TProtocol>) inProtocol;
+-(BOOL) read:(id <TProtocol>)inProtocol error:(NSError **)error;
 
 /**
  * Serialize object to the given protocol
  *
- * @param buf output protocol used for writing
+ * @param outProtocol output protocol used for writing
  */
-- (void) write: (id <TProtocol>) outProtocol;
+-(BOOL) write:(id <TProtocol>)outProtocol error:(NSError **)error;
+
+
+/**
+ * Validate required fields
+ */
+-(BOOL) validate:(NSError *__autoreleasing *)__thriftError;
 
 @end
-
diff --git a/lib/cocoa/src/protocol/TBinaryProtocol.h b/lib/cocoa/src/protocol/TBinaryProtocol.h
index 52cf266..bb90fad 100644
--- a/lib/cocoa/src/protocol/TBinaryProtocol.h
+++ b/lib/cocoa/src/protocol/TBinaryProtocol.h
@@ -21,31 +21,29 @@
 #import "TTransport.h"
 #import "TProtocolFactory.h"
 
+NS_ASSUME_NONNULL_BEGIN
 
-@interface TBinaryProtocol : NSObject <TProtocol> {
-  id <TTransport> mTransport;
-  BOOL mStrictRead;
-  BOOL mStrictWrite;
-  int32_t mMessageSizeLimit;
-}
 
-- (id) initWithTransport: (id <TTransport>) transport;
+@interface TBinaryProtocol : NSObject <TProtocol>
 
-- (id) initWithTransport: (id <TTransport>) transport
-              strictRead: (BOOL) strictRead
-             strictWrite: (BOOL) strictWrite;
+@property (assign, nonatomic) UInt32 messageSizeLimit;
 
-- (int32_t) messageSizeLimit;
-- (void) setMessageSizeLimit: (int32_t) sizeLimit;
+-(id) initWithTransport:(id <TTransport>)transport;
+
+-(id) initWithTransport:(id <TTransport>)transport
+             strictRead:(BOOL)strictRead
+            strictWrite:(BOOL)strictWrite;
 
 @end;
 
 
-@interface TBinaryProtocolFactory : NSObject <TProtocolFactory> {
-}
+@interface TBinaryProtocolFactory : NSObject <TProtocolFactory>
 
-+ (TBinaryProtocolFactory *) sharedFactory;
++(TBinaryProtocolFactory *) sharedFactory;
 
-- (TBinaryProtocol *) newProtocolOnTransport: (id <TTransport>) transport;
+-(TBinaryProtocol *) newProtocolOnTransport:(id <TTransport>)transport;
 
 @end
+
+
+NS_ASSUME_NONNULL_END
\ No newline at end of file
diff --git a/lib/cocoa/src/protocol/TBinaryProtocol.m b/lib/cocoa/src/protocol/TBinaryProtocol.m
index 1508acc..1f9e57a 100644
--- a/lib/cocoa/src/protocol/TBinaryProtocol.m
+++ b/lib/cocoa/src/protocol/TBinaryProtocol.m
@@ -18,18 +18,20 @@
  */
 
 #import "TBinaryProtocol.h"
-#import "TProtocolException.h"
-#import "TObjective-C.h"
-
-int32_t VERSION_1 = 0x80010000;
-int32_t VERSION_MASK = 0xffff0000;
+#import "TProtocolError.h"
 
 
-static TBinaryProtocolFactory * gSharedFactory = nil;
+static SInt32 VERSION_1 = 0x80010000;
+static SInt32 VERSION_MASK = 0xffff0000;
+
+
+static TBinaryProtocolFactory *gSharedFactory = nil;
+
 
 @implementation TBinaryProtocolFactory
 
-+ (TBinaryProtocolFactory *) sharedFactory {
++(TBinaryProtocolFactory *) sharedFactory
+{
   if (gSharedFactory == nil) {
     gSharedFactory = [[TBinaryProtocolFactory alloc] init];
   }
@@ -37,358 +39,553 @@
   return gSharedFactory;
 }
 
-- (TBinaryProtocol *) newProtocolOnTransport: (id <TTransport>) transport {
-  return [[TBinaryProtocol alloc] initWithTransport: transport];
+-(NSString *) protocolName
+{
+  return @"binary";
+}
+
+-(TBinaryProtocol *) newProtocolOnTransport:(id <TTransport>)transport
+{
+  return [[TBinaryProtocol alloc] initWithTransport:transport];
 }
 
 @end
 
 
+@interface TBinaryProtocol ()
+
+@property(strong, nonatomic) id <TTransport> transport;
+
+@property(assign, nonatomic) BOOL strictRead;
+@property(assign, nonatomic) BOOL strictWrite;
+
+@property(strong, nonatomic) NSString *currentMessageName;
+@property(strong, nonatomic) NSString *currentFieldName;
+
+@end
+
 
 @implementation TBinaryProtocol
 
-- (id) initWithTransport: (id <TTransport>) transport
+-(id) initWithTransport:(id <TTransport>)aTransport
 {
-  return [self initWithTransport: transport strictRead: NO strictWrite: YES];
+  return [self initWithTransport:aTransport strictRead:NO strictWrite:YES];
 }
 
-- (id) initWithTransport: (id <TTransport>) transport
-              strictRead: (BOOL) strictRead
-             strictWrite: (BOOL) strictWrite
+-(id) initWithTransport:(id <TTransport>)transport
+             strictRead:(BOOL)strictRead
+            strictWrite:(BOOL)strictWrite
 {
   self = [super init];
-  mTransport = [transport retain_stub];
-  mStrictRead = strictRead;
-  mStrictWrite = strictWrite;
+  if (self) {
+    _transport = transport;
+    _strictRead = strictRead;
+    _strictWrite = strictWrite;
+  }
   return self;
 }
 
-
-- (int32_t) messageSizeLimit
+-(id <TTransport>) transport
 {
-  return mMessageSizeLimit;
+  return _transport;
 }
 
-
-- (void) setMessageSizeLimit: (int32_t) sizeLimit
+-(NSString *) readStringBody:(int)size error:(NSError **)error
 {
-  mMessageSizeLimit = sizeLimit;
-}
-
-
-- (void) dealloc
-{
-  [mTransport release_stub];
-  [super dealloc_stub];
-}
-
-
-- (id <TTransport>) transport
-{
-  return mTransport;
-}
-
-
-- (NSString *) readStringBody: (int) size
-{
-  char * buffer = malloc(size+1);
-  if (!buffer) {
-    @throw [TProtocolException exceptionWithName: @"TProtocolException"
-                                          reason: [NSString stringWithFormat: @"Unable to allocate memory in %s, size: %i",
-                                                   __PRETTY_FUNCTION__,
-                                                   size]];;
+  NSMutableData *data = [NSMutableData dataWithLength:size];
+  if (!data) {
+    PROTOCOL_ERROR(nil, Unknown, @"Unable to allocate %d bytes", size);
   }
-  [mTransport readAll: (uint8_t *) buffer offset: 0 length: size];
-  buffer[size] = 0;
-  NSString * result = [NSString stringWithUTF8String: buffer];
-  free(buffer);
-  return result;
+
+  if (![_transport readAll:data.mutableBytes offset:0 length:size error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(nil, error, @"Transport read failed");
+  }
+
+  return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
 }
 
 
-- (void) readMessageBeginReturningName: (NSString **) name
-                                  type: (int *) type
-                            sequenceID: (int *) sequenceID
+-(BOOL) readMessageBeginReturningName:(NSString **)name
+                                 type:(SInt32 *)type
+                           sequenceID:(SInt32 *)sequenceID
+                                error:(NSError *__autoreleasing *)error
 {
-  int32_t size = [self readI32];
+  SInt32 size;
+  if (![self readI32:&size error:error]) {
+    return NO;
+  }
+  ;
+
   if (size < 0) {
     int version = size & VERSION_MASK;
     if (version != VERSION_1) {
-      @throw [TProtocolException exceptionWithName: @"TProtocolException"
-                                 reason: @"Bad version in readMessageBegin"];
+      PROTOCOL_ERROR(NO, BadVersion, @"Bad message version");
     }
     if (type != NULL) {
       *type = size & 0x00FF;
     }
-    NSString * messageName = [self readString];
+    NSString *messageName;
+    if (![self readString:&messageName error:error]) {
+      return NO;
+    }
+    if (name != nil) {
+      *name = messageName;
+    }
+  }
+  else {
+
+    if (_strictRead) {
+      PROTOCOL_ERROR(NO, InvalidData, @"Missing message version, old client?");
+    }
+
+    if (_messageSizeLimit > 0 && size > _messageSizeLimit) {
+      PROTOCOL_ERROR(NO, SizeLimit, @"Message exceeeds size limit of %d", (int)size);
+    }
+
+    NSString *messageName = [self readStringBody:size error:error];
+    if (!messageName) {
+      return NO;
+    }
+
     if (name != NULL) {
       *name = messageName;
     }
-    int seqID = [self readI32];
-    if (sequenceID != NULL) {
-      *sequenceID = seqID;
+
+    UInt8 messageType;
+    if (![self readByte:&messageType error:error]) {
+      return NO;
     }
-  } else {
-    if (mStrictRead) {
-      @throw [TProtocolException exceptionWithName: @"TProtocolException"
-                                 reason: @"Missing version in readMessageBegin, old client?"];
-    }
-    if ([self messageSizeLimit] > 0 && size > [self messageSizeLimit]) {
-      @throw [TProtocolException exceptionWithName: @"TProtocolException"
-                                            reason: [NSString stringWithFormat: @"Message too big.  Size limit is: %d Message size is: %d",
-                                                     mMessageSizeLimit,
-                                                     size]];
-    }
-    NSString * messageName = [self readStringBody: size];
-    if (name != NULL) {
-      *name = messageName;
-    }
-    int messageType = [self readByte];
+
     if (type != NULL) {
       *type = messageType;
     }
-    int seqID = [self readI32];
-    if (sequenceID != NULL) {
-      *sequenceID = seqID;
-    }
   }
+
+  SInt32 seqID;
+  if (![self readI32:&seqID error:error]) {
+    return NO;
+  }
+  if (sequenceID != NULL) {
+    *sequenceID = seqID;
+  }
+
+  return YES;
 }
 
 
-- (void) readMessageEnd {}
-
-
-- (void) readStructBeginReturningName: (NSString **) name
+-(BOOL) readMessageEnd:(NSError *__autoreleasing *)error
 {
-  if (name != NULL) {
-    *name = nil;
-  }
+  return YES;
 }
 
 
-- (void) readStructEnd {}
-
-
-- (void) readFieldBeginReturningName: (NSString **) name
-                                type: (int *) fieldType
-                             fieldID: (int *) fieldID
+-(BOOL) readStructBeginReturningName:(NSString *__autoreleasing *)name error:(NSError *__autoreleasing *)error
 {
-  if (name != NULL) {
+  return YES;
+}
+
+
+-(BOOL) readStructEnd:(NSError *__autoreleasing *)error
+{
+  return YES;
+}
+
+
+-(BOOL) readFieldBeginReturningName:(NSString *__autoreleasing *)name
+                               type:(SInt32 *)fieldType
+                            fieldID:(SInt32 *)fieldID
+                              error:(NSError *__autoreleasing *)error
+{
+  if (name != nil) {
     *name = nil;
   }
-  int ft = [self readByte];
+
+  UInt8 ft;
+  if (![self readByte:&ft error:error]) {
+    return NO;
+  }
   if (fieldType != NULL) {
     *fieldType = ft;
   }
-  if (ft != TType_STOP) {
-    int fid = [self readI16];
+  if (ft != TTypeSTOP) {
+    SInt16 fid;
+    if (![self readI16:&fid error:error]) {
+      return NO;
+    }
     if (fieldID != NULL) {
       *fieldID = fid;
     }
   }
+  return YES;
 }
 
 
-- (void) readFieldEnd {}
-
-
-- (int32_t) readI32
+-(BOOL) readFieldEnd:(NSError *__autoreleasing *)error
 {
-  uint8_t i32rd[4];
-  [mTransport readAll: i32rd offset: 0 length: 4];
-  return
+  return YES;
+}
+
+
+-(BOOL) readString:(NSString *__autoreleasing *)value error:(NSError *__autoreleasing *)error
+{
+  SInt32 size;
+  if (![self readI32:&size error:error]) {
+    return NO;
+  }
+
+  NSString *string = [self readStringBody:size error:error];
+  if (!string) {
+    return NO;
+  }
+
+  *value = string;
+
+  return YES;
+}
+
+
+-(BOOL) readBool:(BOOL *)value error:(NSError *__autoreleasing *)error
+{
+  UInt8 byte;
+  if (![self readByte:&byte error:error]) {
+    return NO;
+  }
+
+  *value = byte == 1;
+
+  return YES;
+}
+
+
+-(BOOL) readByte:(UInt8 *)value error:(NSError *__autoreleasing *)error
+{
+  UInt8 buff[1];
+  if (![_transport readAll:buff offset:0 length:1 error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport read failed");
+  }
+
+  *value = buff[0];
+
+  return YES;
+}
+
+
+-(BOOL) readI16:(SInt16 *)value error:(NSError *__autoreleasing *)error
+{
+  UInt8 buff[2];
+  if (![_transport readAll:buff offset:0 length:2 error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport read failed");
+  }
+
+  *value =
+    ((SInt16)(buff[0] & 0xff) << 8) |
+    ((SInt16)(buff[1] & 0xff));
+
+  return YES;
+}
+
+
+-(BOOL) readI32:(SInt32 *)value error:(NSError *__autoreleasing *)error
+{
+  UInt8 i32rd[4];
+  if (![_transport readAll:i32rd offset:0 length:4 error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport read failed");
+  }
+
+  *value =
     ((i32rd[0] & 0xff) << 24) |
     ((i32rd[1] & 0xff) << 16) |
     ((i32rd[2] & 0xff) <<  8) |
     ((i32rd[3] & 0xff));
+
+  return YES;
 }
 
 
-- (NSString *) readString
+-(BOOL) readI64:(SInt64 *)value error:(NSError *__autoreleasing *)error
 {
-  int size = [self readI32];
-  return [self readStringBody: size];
+  UInt8 buff[8];
+  if (![_transport readAll:buff offset:0 length:8 error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport read failed");
+  }
+
+  *value =
+    ((SInt64)(buff[0] & 0xff) << 56) |
+    ((SInt64)(buff[1] & 0xff) << 48) |
+    ((SInt64)(buff[2] & 0xff) << 40) |
+    ((SInt64)(buff[3] & 0xff) << 32) |
+    ((SInt64)(buff[4] & 0xff) << 24) |
+    ((SInt64)(buff[5] & 0xff) << 16) |
+    ((SInt64)(buff[6] & 0xff) <<  8) |
+    ((SInt64)(buff[7] & 0xff));
+
+  return YES;
 }
 
 
-- (BOOL) readBool
-{
-  return [self readByte] == 1;
-}
-
-- (uint8_t) readByte
-{
-  uint8_t myByte;
-  [mTransport readAll: &myByte offset: 0 length: 1];
-  return myByte;
-}
-
-- (short) readI16
-{
-  uint8_t buff[2];
-  [mTransport readAll: buff offset: 0 length: 2];
-  return (short)
-    (((buff[0] & 0xff) << 8) |
-     ((buff[1] & 0xff)));
-  return 0;
-}
-
-- (int64_t) readI64;
-{
-  uint8_t i64rd[8];
-  [mTransport readAll: i64rd offset: 0 length: 8];
-  return
-    ((int64_t)(i64rd[0] & 0xff) << 56) |
-    ((int64_t)(i64rd[1] & 0xff) << 48) |
-    ((int64_t)(i64rd[2] & 0xff) << 40) |
-    ((int64_t)(i64rd[3] & 0xff) << 32) |
-    ((int64_t)(i64rd[4] & 0xff) << 24) |
-    ((int64_t)(i64rd[5] & 0xff) << 16) |
-    ((int64_t)(i64rd[6] & 0xff) <<  8) |
-    ((int64_t)(i64rd[7] & 0xff));
-}
-
-- (double) readDouble;
+-(BOOL) readDouble:(double *)value error:(NSError *__autoreleasing *)error
 {
   // FIXME - will this get us into trouble on PowerPC?
-  int64_t ieee754 = [self readI64];
-  return *((double *) &ieee754);
+  return [self readI64:(SInt64 *)value error:error];
 }
 
 
-- (NSData *) readBinary
+-(BOOL) readBinary:(NSData *__autoreleasing *)value error:(NSError *__autoreleasing *)error
 {
-  int32_t size = [self readI32];
-  uint8_t * buff = malloc(size);
-  if (buff == NULL) {
-    @throw [TProtocolException
-             exceptionWithName: @"TProtocolException"
-             reason: [NSString stringWithFormat: @"Out of memory.  Unable to allocate %d bytes trying to read binary data.",
-                               size]];
+  SInt32 size;
+  if (![self readI32:&size error:error]) {
+    return NO;
   }
-  [mTransport readAll: buff offset: 0 length: size];
-  return [NSData dataWithBytesNoCopy: buff length: size];
+
+  NSMutableData *data = [NSMutableData dataWithLength:size];
+  if (!data) {
+    PROTOCOL_ERROR(NO, Unknown, @"Unable to allocate %d bytes", (int)size);
+  }
+
+  if (![_transport readAll:data.mutableBytes offset:0 length:size error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport read failed");
+  }
+
+  *value = data;
+
+  return YES;
 }
 
 
-- (void) readMapBeginReturningKeyType: (int *) keyType
-                            valueType: (int *) valueType
-                                 size: (int *) size
+-(BOOL) readMapBeginReturningKeyType:(SInt32 *)keyType
+                           valueType:(SInt32 *)valueType
+                                size:(SInt32 *)size
+                               error:(NSError *__autoreleasing *)error
 {
-  int kt = [self readByte];
-  int vt = [self readByte];
-  int s = [self readI32];
+  UInt8 kt;
+  if (![self readByte:&kt error:error]) {
+    return NO;
+  }
+
+  UInt8 vt;
+  if (![self readByte:&vt error:error]) {
+    return NO;
+  }
+
+  SInt32 s;
+  if (![self readI32:&s error:error]) {
+    return NO;
+  }
+
   if (keyType != NULL) {
     *keyType = kt;
   }
+
   if (valueType != NULL) {
     *valueType = vt;
   }
+
   if (size != NULL) {
     *size = s;
   }
+
+  return YES;
 }
 
-- (void) readMapEnd {}
 
-
-- (void) readSetBeginReturningElementType: (int *) elementType
-                                     size: (int *) size
+-(BOOL) readMapEnd:(NSError *__autoreleasing *)error
 {
-  int et = [self readByte];
-  int s = [self readI32];
+  return YES;
+}
+
+
+-(BOOL) readSetBeginReturningElementType:(SInt32 *)elementType
+                                    size:(SInt32 *)size
+                                   error:(NSError *__autoreleasing *)error
+{
+  UInt8 et;
+  if (![self readByte:&et error:error]) {
+    return NO;
+  }
+
+  SInt32 s;
+  if (![self readI32:&s error:error]) {
+    return NO;
+  }
+
   if (elementType != NULL) {
     *elementType = et;
   }
+
   if (size != NULL) {
     *size = s;
   }
+
+  return YES;
 }
 
 
-- (void) readSetEnd {}
-
-
-- (void) readListBeginReturningElementType: (int *) elementType
-                                      size: (int *) size
+-(BOOL) readSetEnd:(NSError *__autoreleasing *)error
 {
-  int et = [self readByte];
-  int s = [self readI32];
+  return YES;
+}
+
+
+-(BOOL) readListBeginReturningElementType:(SInt32 *)elementType
+                                     size:(SInt32 *)size
+                                    error:(NSError *__autoreleasing *)error
+{
+  UInt8 et;
+  if (![self readByte:&et error:error]) {
+    return NO;
+  }
+
+  SInt32 s;
+  if (![self readI32:&s error:error]) {
+    return NO;
+  }
+
   if (elementType != NULL) {
     *elementType = et;
   }
+
   if (size != NULL) {
     *size = s;
   }
+
+  return YES;
 }
 
 
-- (void) readListEnd {}
-
-
-- (void) writeByte: (uint8_t) value
+-(BOOL) readListEnd:(NSError *__autoreleasing *)error
 {
-  [mTransport write: &value offset: 0 length: 1];
+  return YES;
 }
 
 
-- (void) writeMessageBeginWithName: (NSString *) name
-                              type: (int) messageType
-                        sequenceID: (int) sequenceID
+
+-(BOOL) writeMessageBeginWithName:(NSString *)name
+                             type:(SInt32)messageType
+                       sequenceID:(SInt32)sequenceID
+                            error:(NSError *__autoreleasing *)error
 {
-  if (mStrictWrite) {
+  if (_strictWrite) {
+
     int version = VERSION_1 | messageType;
-    [self writeI32: version];
-    [self writeString: name];
-    [self writeI32: sequenceID];
-  } else {
-    [self writeString: name];
-    [self writeByte: messageType];
-    [self writeI32: sequenceID];
+
+    if (![self writeI32:version error:error]) {
+      return NO;
+    }
+
+    if (![self writeString:name error:error]) {
+      return NO;
+    }
+
+    if (![self writeI32:sequenceID error:error]) {
+      return NO;
+    }
   }
+  else {
+
+    if (![self writeString:name error:error]) {
+      return NO;
+    }
+
+    if (![self writeByte:messageType error:error]) {
+      return NO;
+    }
+
+    if (![self writeI32:sequenceID error:error]) {
+      return NO;
+    }
+  }
+
+  _currentMessageName = name;
+
+  return YES;
 }
 
 
-- (void) writeMessageEnd {}
-
-
-- (void) writeStructBeginWithName: (NSString *) name {}
-
-
-- (void) writeStructEnd {}
-
-
-- (void) writeFieldBeginWithName: (NSString *) name
-                            type: (int) fieldType
-                         fieldID: (int) fieldID
+-(BOOL) writeMessageEnd:(NSError *__autoreleasing *)error
 {
-  [self writeByte: fieldType];
-  [self writeI16: fieldID];
+  _currentMessageName = nil;
+  return YES;
 }
 
 
-- (void) writeI32: (int32_t) value
+-(BOOL) writeStructBeginWithName:(NSString *)name
+                           error:(NSError *__autoreleasing *)error
 {
-  uint8_t buff[4];
+  return YES;
+}
+
+
+-(BOOL) writeStructEnd:(NSError *__autoreleasing *)error
+{
+  return YES;
+}
+
+
+-(BOOL) writeFieldBeginWithName:(NSString *)name
+                           type:(SInt32)fieldType
+                        fieldID:(SInt32)fieldID
+                          error:(NSError *__autoreleasing *)error
+{
+  if (![self writeByte:fieldType error:error]) {
+    return NO;
+  }
+
+  if (![self writeI16:fieldID error:error]) {
+    return NO;
+  }
+
+  return YES;
+}
+
+
+-(BOOL) writeBool:(BOOL)value error:(NSError *__autoreleasing *)error
+{
+  return [self writeByte:(value ? 1 : 0) error:error];
+}
+
+
+-(BOOL) writeByte:(UInt8)value error:(NSError *__autoreleasing *)error
+{
+  if (![_transport write:&value offset:0 length:1 error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
+  }
+  return YES;
+}
+
+
+-(BOOL) writeI16:(short)value error:(NSError *__autoreleasing *)error
+{
+  UInt8 buff[2];
+  buff[0] = 0xff & (value >> 8);
+  buff[1] = 0xff & value;
+
+  if (![_transport write:buff offset:0 length:2 error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
+  }
+
+  return YES;
+}
+
+
+-(BOOL) writeI32:(SInt32)value error:(NSError *__autoreleasing *)error
+{
+  UInt8 buff[4];
   buff[0] = 0xFF & (value >> 24);
   buff[1] = 0xFF & (value >> 16);
   buff[2] = 0xFF & (value >> 8);
   buff[3] = 0xFF & value;
-  [mTransport write: buff offset: 0 length: 4];
-}
 
-- (void) writeI16: (short) value
-{
-  uint8_t buff[2];
-  buff[0] = 0xff & (value >> 8);
-  buff[1] = 0xff & value;
-  [mTransport write: buff offset: 0 length: 2];
+  if (![_transport write:buff offset:0 length:4 error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
+  }
+
+  return YES;
 }
 
 
-- (void) writeI64: (int64_t) value
+-(BOOL) writeI64:(SInt64)value error:(NSError *__autoreleasing *)error
 {
-  uint8_t buff[8];
+  UInt8 buff[8];
   buff[0] = 0xFF & (value >> 56);
   buff[1] = 0xFF & (value >> 48);
   buff[2] = 0xFF & (value >> 40);
@@ -397,82 +594,147 @@
   buff[5] = 0xFF & (value >> 16);
   buff[6] = 0xFF & (value >> 8);
   buff[7] = 0xFF & value;
-  [mTransport write: buff offset: 0 length: 8];
+
+  if (![_transport write:buff offset:0 length:8 error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
+  }
+
+  return YES;
 }
 
-- (void) writeDouble: (double) value
+
+-(BOOL) writeDouble:(double)value error:(NSError *__autoreleasing *)error
 {
-  // spit out IEEE 754 bits - FIXME - will this get us in trouble on
-  // PowerPC?
-  [self writeI64: *((int64_t *) &value)];
+  // FIXME - will this get us in trouble on PowerPC?
+  if (![self writeI64:*(SInt64 *)&value error:error]) {
+    return NO;
+  }
+
+  return YES;
 }
 
 
-- (void) writeString: (NSString *) value
+-(BOOL) writeString:(NSString *)value error:(NSError *__autoreleasing *)error
 {
   if (value != nil) {
-    const char * utf8Bytes = [value UTF8String];
-    size_t length = strlen(utf8Bytes);
-    [self writeI32: length];
-    [mTransport write: (uint8_t *) utf8Bytes offset: 0 length: length];
-  } else {
+
+    const char *utf8Bytes = [value UTF8String];
+
+    SInt32 length = (SInt32)strlen(utf8Bytes);
+    if (![self writeI32:length error:error]) {
+      return NO;
+    }
+
+    if (![_transport write:(UInt8 *)utf8Bytes offset:0 length:(int)length error:error]) {
+      PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
+    }
+
+  }
+  else {
+
     // instead of crashing when we get null, let's write out a zero
     // length string
-    [self writeI32: 0];
+    if (![self writeI32:0 error:error]) {
+      return NO;
+    }
+
   }
+
+  return YES;
 }
 
 
-- (void) writeBinary: (NSData *) data
+-(BOOL) writeBinary:(NSData *)data error:(NSError *__autoreleasing *)error
 {
-  [self writeI32: [data length]];
-  [mTransport write: [data bytes] offset: 0 length: [data length]];
-}
+  if (![self writeI32:(SInt32)data.length error:error]) {
+    return NO;
+  }
 
-- (void) writeFieldStop
-{
-  [self writeByte: TType_STOP];
+  if (![_transport write:data.bytes offset:0 length:(UInt32)data.length error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
+  }
+
+  return YES;
 }
 
 
-- (void) writeFieldEnd {}
-
-
-- (void) writeMapBeginWithKeyType: (int) keyType
-                        valueType: (int) valueType
-                             size: (int) size
+-(BOOL) writeFieldStop:(NSError *__autoreleasing *)error
 {
-  [self writeByte: keyType];
-  [self writeByte: valueType];
-  [self writeI32: size];
+  if (![self writeByte:TTypeSTOP error:error]) {
+    return NO;
+  }
+
+  return YES;
 }
 
-- (void) writeMapEnd {}
 
-
-- (void) writeSetBeginWithElementType: (int) elementType
-                                 size: (int) size
+-(BOOL) writeFieldEnd:(NSError *__autoreleasing *)error
 {
-  [self writeByte: elementType];
-  [self writeI32: size];
+  return YES;
 }
 
-- (void) writeSetEnd {}
 
-
-- (void) writeListBeginWithElementType: (int) elementType
-                                  size: (int) size
+-(BOOL) writeMapBeginWithKeyType:(SInt32)keyType
+                       valueType:(SInt32)valueType
+                            size:(SInt32)size
+                           error:(NSError *__autoreleasing *)error
 {
-  [self writeByte: elementType];
-  [self writeI32: size];
+  if (![self writeByte:keyType error:error]) {
+    return NO;
+  }
+  if (![self writeByte:valueType error:error]) {
+    return NO;
+  }
+  if (![self writeI32:(int)size error:error]) {
+    return NO;
+  }
+  return YES;
 }
 
-- (void) writeListEnd {}
 
-
-- (void) writeBool: (BOOL) value
+-(BOOL) writeMapEnd:(NSError *__autoreleasing *)error
 {
-  [self writeByte: (value ? 1 : 0)];
+  return YES;
+}
+
+
+-(BOOL) writeSetBeginWithElementType:(SInt32)elementType
+                                size:(SInt32)size
+                               error:(NSError *__autoreleasing *)error
+{
+  if (![self writeByte:elementType error:error]) {
+    return NO;
+  }
+  if (![self writeI32:size error:error]) {
+    return NO;
+  }
+  return YES;
+}
+
+
+-(BOOL) writeSetEnd:(NSError *__autoreleasing *)error
+{
+  return YES;
+}
+
+
+-(BOOL) writeListBeginWithElementType:(SInt32)elementType
+                                 size:(SInt32)size
+                                error:(NSError *__autoreleasing *)error
+{
+  if (![self writeByte:elementType error:error]) {
+    return NO;
+  }
+  if (![self writeI32:size error:error]) {
+    return NO;
+  }
+  return YES;
+}
+
+
+-(BOOL) writeListEnd:(NSError *__autoreleasing *)error
+{
+  return YES;
 }
 
 @end
diff --git a/lib/cocoa/src/protocol/TCompactProtocol.h b/lib/cocoa/src/protocol/TCompactProtocol.h
new file mode 100644
index 0000000..3f6accc
--- /dev/null
+++ b/lib/cocoa/src/protocol/TCompactProtocol.h
@@ -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.
+ */
+
+#import "TProtocol.h"
+#import "TTransport.h"
+#import "TProtocolFactory.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+@interface TCompactProtocol : NSObject <TProtocol>
+
+-(id) initWithTransport:(id <TTransport>)transport;
+
+@end
+
+@interface TCompactProtocolFactory : NSObject <TProtocolFactory>
+
++(TCompactProtocolFactory *) sharedFactory;
+
+-(TCompactProtocol *) newProtocolOnTransport:(id <TTransport>)transport;
+
+@end
+
+
+NS_ASSUME_NONNULL_END
\ No newline at end of file
diff --git a/lib/cocoa/src/protocol/TCompactProtocol.m b/lib/cocoa/src/protocol/TCompactProtocol.m
new file mode 100644
index 0000000..9b0ebb2
--- /dev/null
+++ b/lib/cocoa/src/protocol/TCompactProtocol.m
@@ -0,0 +1,983 @@
+/*
+ * 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 "TCompactProtocol.h"
+#import "TProtocolError.h"
+
+static const UInt8 COMPACT_PROTOCOL_ID = 0x82;
+static const UInt8 COMPACT_VERSION = 1;
+static const UInt8 COMPACT_VERSION_MASK = 0x1F; // 0001 1111
+static const UInt8 COMPACT_TYPE_MASK = 0xE0; // 1110 0000
+static const UInt8 COMPACT_TYPE_BITS = 0x07; // 0000 0111
+static const int COMPACT_TYPE_SHIFT_AMOUNT = 5;
+
+enum {
+  TCType_STOP = 0x00,
+  TCType_BOOLEAN_TRUE = 0x01,
+  TCType_BOOLEAN_FALSE = 0x02,
+  TCType_BYTE = 0x03,
+  TCType_I16 = 0x04,
+  TCType_I32 = 0x05,
+  TCType_I64 = 0x06,
+  TCType_DOUBLE = 0x07,
+  TCType_BINARY = 0x08,
+  TCType_LIST = 0x09,
+  TCType_SET = 0x0A,
+  TCType_MAP = 0x0B,
+  TCType_STRUCT = 0x0C,
+};
+
+@implementation TCompactProtocolFactory
+
++(TCompactProtocolFactory *) sharedFactory
+{
+  static TCompactProtocolFactory *gSharedFactory = nil;
+  if (gSharedFactory == nil) {
+    gSharedFactory = [[TCompactProtocolFactory alloc] init];
+  }
+
+  return gSharedFactory;
+}
+
+-(NSString *) protocolName
+{
+  return @"compact";
+}
+
+-(TCompactProtocol *) newProtocolOnTransport:(id <TTransport>)transport
+{
+  return [[TCompactProtocol alloc] initWithTransport:transport];
+}
+
+@end
+
+
+@interface TCompactProtocol ()
+
+@property(strong, nonatomic) id <TTransport> transport;
+
+@property(strong, nonatomic) NSMutableArray *lastField;
+@property(assign, nonatomic) short lastFieldId;
+
+@property(strong, nonatomic) NSString *boolFieldName;
+@property(strong, nonatomic) NSNumber *boolFieldType;
+@property(strong, nonatomic) NSNumber *boolFieldId;
+@property(strong, nonatomic) NSNumber *booleanValue;
+
+@property(strong, nonatomic) NSString *currentMessageName;
+
+@end
+
+
+@implementation TCompactProtocol
+
+-(id) init
+{
+  self = [super init];
+
+  if (self != nil) {
+    _lastField = [[NSMutableArray alloc] init];
+  }
+
+  return self;
+}
+
+-(id) initWithTransport:(id <TTransport>)aTransport
+{
+  self = [self init];
+
+  if (self != nil) {
+    _transport = aTransport;
+  }
+
+  return self;
+}
+
+-(id <TTransport>) transport
+{
+  return _transport;
+}
+
+-(BOOL) writeByteDirect:(UInt8)n error:(NSError *__autoreleasing *)error
+{
+  if (![_transport write:(UInt8 *)&n offset:0 length:1 error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
+  }
+  return YES;
+}
+
+-(BOOL) writeVarint32:(UInt32)n error:(NSError *__autoreleasing *)error
+{
+  UInt8 i32buf[5] = {0};
+  UInt32 idx = 0;
+
+  while (true) {
+    if ((n & ~0x7F) == 0) {
+      i32buf[idx++] = (UInt8)n;
+      break;
+    }
+    else {
+      i32buf[idx++] = (UInt8)((n & 0x7F) | 0x80);
+      n >>= 7;
+    }
+  }
+
+  if (![_transport write:i32buf offset:0 length:idx error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
+  }
+
+  return YES;
+}
+
+-(BOOL) writeMessageBeginWithName:(NSString *)name
+                             type:(SInt32)messageType
+                       sequenceID:(SInt32)sequenceID
+                            error:(NSError *__autoreleasing *)error
+{
+  if (![self writeByteDirect:COMPACT_PROTOCOL_ID error:error]) {
+    return NO;
+  }
+  if (![self writeByteDirect:(UInt8)((COMPACT_VERSION & COMPACT_VERSION_MASK) |
+                                     ((((UInt32)messageType) << COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_MASK)) error:error])
+  {
+    return NO;
+  }
+  if (![self writeVarint32:(UInt32)sequenceID error:error]) {
+    return NO;
+  }
+  if (![self writeString:name error:error]) {
+    return NO;
+  }
+
+  _currentMessageName = name;
+
+  return YES;
+}
+
+-(BOOL) writeStructBeginWithName:(NSString *)name error:(NSError *__autoreleasing *)error
+{
+  [_lastField addObject:@(_lastFieldId)];
+  _lastFieldId = 0;
+  return YES;
+}
+
+-(BOOL) writeStructEnd:(NSError *__autoreleasing *)error
+{
+  _lastFieldId = [_lastField.lastObject shortValue];
+  [_lastField removeLastObject];
+  return YES;
+}
+
+-(BOOL) writeFieldBeginWithName:(NSString *)name
+                           type:(SInt32)fieldType
+                        fieldID:(SInt32)fieldID
+                          error:(NSError *__autoreleasing *)error
+{
+  if (fieldType == TTypeBOOL) {
+    _boolFieldName = [name copy];
+    _boolFieldType = @(fieldType);
+    _boolFieldId = @(fieldID);
+    return YES;
+  }
+  else {
+    return [self writeFieldBeginInternalWithName:name
+                                            type:fieldType
+                                         fieldID:fieldID
+                                    typeOverride:0xFF
+                                           error:error];
+  }
+}
+
+-(BOOL) writeFieldBeginInternalWithName:(NSString *)name
+                                   type:(SInt32)fieldType
+                                fieldID:(SInt32)fieldID
+                           typeOverride:(UInt8)typeOverride
+                                  error:(NSError *__autoreleasing *)error
+{
+  UInt8 typeToWrite = typeOverride == 0xFF ? [self compactTypeForTType:fieldType] : typeOverride;
+
+  // check if we can use delta encoding for the field id
+  if (fieldID > _lastFieldId && fieldID - _lastFieldId <= 15) {
+    // Write them together
+    if (![self writeByteDirect:(fieldID - _lastFieldId) << 4 | typeToWrite error:error]) {
+      return NO;
+    }
+  }
+  else {
+    // Write them separate
+    if (![self writeByteDirect:typeToWrite error:error]) {
+      return NO;
+    }
+    if (![self writeI16:fieldID error:error]) {
+      return NO;
+    }
+  }
+
+  _lastFieldId = fieldID;
+
+  return YES;
+}
+
+-(BOOL) writeFieldStop:(NSError *__autoreleasing *)error
+{
+  return [self writeByteDirect:TCType_STOP error:error];
+}
+
+-(BOOL) writeMapBeginWithKeyType:(SInt32)keyType
+                       valueType:(SInt32)valueType
+                            size:(SInt32)size
+                           error:(NSError *__autoreleasing *)error
+{
+  if (size == 0) {
+    if (![self writeByteDirect:0 error:error]) {
+      return NO;
+    }
+  }
+  else {
+    if (![self writeVarint32:(UInt32)size error:error]) {
+      return NO;
+    }
+    if (![self writeByteDirect:[self compactTypeForTType:keyType] << 4 | [self compactTypeForTType:valueType] error:error]) {
+      return NO;
+    }
+  }
+  return YES;
+}
+
+-(BOOL) writeListBeginWithElementType:(SInt32)elementType
+                                 size:(SInt32)size
+                                error:(NSError *__autoreleasing *)error
+{
+  return [self writeCollectionBeginWithElementType:elementType size:size error:error];
+}
+
+-(BOOL) writeSetBeginWithElementType:(SInt32)elementType
+                                size:(SInt32)size
+                               error:(NSError *__autoreleasing *)error
+{
+  return [self writeCollectionBeginWithElementType:elementType size:size error:error];
+}
+
+-(BOOL) writeBool:(BOOL)b error:(NSError *__autoreleasing *)error
+{
+  BOOL result;
+  if (_boolFieldId != nil && _boolFieldName != nil && _boolFieldType != nil) {
+    // we haven't written the field header yet
+    result = [self writeFieldBeginInternalWithName:_boolFieldName
+                                              type:_boolFieldType.intValue
+                                           fieldID:_boolFieldId.intValue
+                                      typeOverride:b ? TCType_BOOLEAN_TRUE : TCType_BOOLEAN_FALSE
+                                             error:error];
+    _boolFieldId = nil;
+    _boolFieldName = nil;
+    _boolFieldType = nil;
+  }
+  else {
+    // we're not part of a field, so just Write the value.
+    result = [self writeByteDirect:b ? TCType_BOOLEAN_TRUE : TCType_BOOLEAN_FALSE error:error];
+  }
+  return result;
+}
+
+-(BOOL) writeByte:(UInt8)value error:(NSError *__autoreleasing *)error
+{
+  return [self writeByteDirect:value error:error];
+}
+
+-(BOOL) writeI16:(SInt16)value error:(NSError *__autoreleasing *)error
+{
+  return [self writeVarint32:[self i32ToZigZag:value] error:error];
+}
+
+-(BOOL) writeI32:(SInt32)value error:(NSError *__autoreleasing *)error
+{
+  return [self writeVarint32:[self i32ToZigZag:value] error:error];
+}
+
+-(BOOL) writeI64:(SInt64)value error:(NSError *__autoreleasing *)error
+{
+  return [self writeVarint64:[self i64ToZigZag:value] error:error];
+}
+
+-(BOOL) writeDouble:(double)value error:(NSError *__autoreleasing *)error
+{
+  // Safe bit-casting double->uint64
+
+  UInt64 bits = 0;
+  memcpy(&bits, &value, 8);
+
+  bits = OSSwapHostToLittleInt64(bits);
+
+  if (![_transport write:(UInt8 *)&bits offset:0 length:8 error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
+  }
+
+  return YES;
+}
+
+-(BOOL) writeString:(NSString *)value error:(NSError *__autoreleasing *)error
+{
+  return [self writeBinary:[value dataUsingEncoding:NSUTF8StringEncoding] error:error];
+}
+
+-(BOOL) writeBinary:(NSData *)data error:(NSError *__autoreleasing *)error
+{
+  if (![self writeVarint32:(UInt32)data.length error:error]) {
+    return NO;
+  }
+  if (![_transport write:data.bytes offset:0 length:(UInt32)data.length error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
+  }
+  return YES;
+}
+
+-(BOOL) writeMessageEnd:(NSError *__autoreleasing *)error
+{
+  _currentMessageName = nil;
+  return YES;
+}
+
+-(BOOL) writeMapEnd:(NSError *__autoreleasing *)error
+{
+  return YES;
+}
+
+-(BOOL) writeListEnd:(NSError *__autoreleasing *)error
+{
+  return YES;
+}
+
+-(BOOL) writeSetEnd:(NSError *__autoreleasing *)error
+{
+  return YES;
+}
+
+-(BOOL) writeFieldEnd:(NSError *__autoreleasing *)error
+{
+  return YES;
+}
+
+-(BOOL) writeCollectionBeginWithElementType:(SInt32)elementType
+                                       size:(SInt32)size
+                                      error:(NSError *__autoreleasing *)error
+{
+  UInt8 ctypeElement = [self compactTypeForTType:elementType];
+
+  if (size <= 14) {
+    if (![self writeByteDirect:size << 4 | ctypeElement error:error]) {
+      return NO;
+    }
+  }
+  else {
+    if (![self writeByteDirect:0xf0 | ctypeElement error:error]) {
+      return NO;
+    }
+    if (![self writeVarint32:(UInt32)size error:error]) {
+      return NO;
+    }
+  }
+  return YES;
+}
+
+-(BOOL) writeVarint64:(UInt64)n error:(NSError *__autoreleasing *)error
+{
+  UInt8 varint64out[10] = {0};
+  int idx = 0;
+
+  while (true) {
+    if ((n & ~0x7FL) == 0) {
+      varint64out[idx++] = (UInt8)n;
+      break;
+    }
+    else {
+      varint64out[idx++] = (UInt8)((n & 0x7F) | 0x80);
+      n >>= 7;
+    }
+  }
+
+  if (![_transport write:varint64out offset:0 length:idx error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport write failed");
+  }
+
+  return YES;
+}
+
+-(UInt32) i32ToZigZag:(SInt32)n
+{
+  /*
+     ZigZag encoding maps signed integers to unsigned integers so that
+     numbers with a small absolute value (for instance, -1) have
+     a small varint encoded value too. It does this in a way that
+     "zig-zags" back and forth through the positive and negative integers,
+     so that -1 is encoded as 1, 1 is encoded as 2, -2 is encoded as 3, and so
+         on
+   */
+  return (UInt32)(n << 1) ^ (UInt32)(n >> 31);
+}
+
+-(UInt64) i64ToZigZag:(SInt64)n
+{
+  return (UInt64)(n << 1) ^ (UInt64)(n >> 63);
+}
+
+-(BOOL) readMessageBeginReturningName:(NSString **)pname
+                                 type:(SInt32 *)ptype
+                           sequenceID:(SInt32 *)psequenceID
+                                error:(NSError *__autoreleasing *)error
+{
+  UInt8 protocolId;
+  if (![self readByte:&protocolId error:error]) {
+    return NO;
+  }
+
+  if (protocolId != COMPACT_PROTOCOL_ID) {
+    if (error) {
+      *error = [NSError errorWithDomain:TProtocolErrorDomain
+                                   code:TProtocolErrorUnknown
+                               userInfo:@{TProtocolErrorExtendedErrorKey: @(TProtocolExtendedErrorMismatchedProtocol),
+                                          TProtocolErrorExpectedIdKey: @(COMPACT_PROTOCOL_ID)}];
+    }
+    return NO;
+  }
+
+  UInt8 versionAndType;
+  if (![self readByte:&versionAndType error:error]) {
+    return NO;
+  }
+
+  UInt8 version = versionAndType & COMPACT_VERSION_MASK;
+  if (version != COMPACT_VERSION) {
+    if (error) {
+      *error = [NSError errorWithDomain:TProtocolErrorDomain
+                                   code:TProtocolErrorBadVersion
+                               userInfo:@{TProtocolErrorExpectedVersionKey: @(COMPACT_VERSION)}];
+    }
+    return NO;
+  }
+
+  int type = (versionAndType >> COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_BITS;
+  UInt32 sequenceID;
+  if (![self readVarint32:&sequenceID error:error]) {
+    return NO;
+  }
+  NSString *name;
+  if (![self readString:&name error:error]) {
+    return NO;
+  }
+
+  if (ptype != NULL) {
+    *ptype = type;
+  }
+  if (psequenceID != NULL) {
+    *psequenceID = sequenceID;
+  }
+  if (pname != NULL) {
+    *pname = name;
+  }
+  return YES;
+}
+
+-(BOOL) readStructBeginReturningName:(NSString **)pname error:(NSError *__autoreleasing *)error
+{
+  [_lastField addObject:@(_lastFieldId)];
+  _lastFieldId = 0;
+
+  if (pname != NULL) {
+    *pname = @"";
+  }
+
+  return YES;
+}
+
+-(BOOL) readStructEnd:(NSError *__autoreleasing *)error
+{
+  _lastFieldId = [_lastField.lastObject shortValue];
+  [_lastField removeLastObject];
+  return YES;
+}
+
+-(BOOL) readFieldBeginReturningName:(NSString **)pname
+                               type:(SInt32 *)pfieldType
+                            fieldID:(SInt32 *)pfieldID
+                              error:(NSError *__autoreleasing *)error
+{
+  UInt8 byte;
+  if (![self readByte:&byte error:error]) {
+    return NO;
+  }
+
+  UInt8 type = byte & 0x0f;
+
+  // if it's a stop, then we can return immediately, as the struct is over.
+  if (type == TCType_STOP) {
+    if (pname != NULL) {
+      *pname = @"";
+    }
+    if (pfieldType != NULL) {
+      *pfieldType = TTypeSTOP;
+    }
+    if (pfieldID != NULL) {
+      *pfieldID = 0;
+    }
+    return YES;
+  }
+
+  short fieldId = 0;
+
+  // mask off the 4 MSB of the type header. it could contain a field id delta.
+  short modifier = (byte & 0xf0) >> 4;
+  if (modifier == 0) {
+    // not a delta. look ahead for the zigzag varint field id.
+    if (![self readI16:&fieldId error:error]) {
+      return NO;
+    }
+  }
+  else {
+    // has a delta. add the delta to the last Read field id.
+    fieldId = _lastFieldId + modifier;
+  }
+
+  UInt8 fieldType;
+  if (![self ttype:&fieldType forCompactType:type error:error]) {
+    return NO;
+  }
+
+  if (pname != NULL) {
+    *pname = @"";
+  }
+  if (pfieldType != NULL) {
+    *pfieldType = fieldType;
+  }
+  if (pfieldID != NULL) {
+    *pfieldID = fieldId;
+  }
+
+  // if this happens to be a boolean field, the value is encoded in the type
+  if (type == TCType_BOOLEAN_TRUE ||
+      type == TCType_BOOLEAN_FALSE)
+  {
+    // save the boolean value in a special instance variable.
+    _booleanValue = [NSNumber numberWithBool:type == TCType_BOOLEAN_TRUE];
+  }
+
+  // push the new field onto the field stack so we can keep the deltas going.
+  _lastFieldId = fieldId;
+
+  return YES;
+}
+
+-(BOOL) readMapBeginReturningKeyType:(SInt32 *)pkeyType
+                           valueType:(SInt32 *)pvalueType
+                                size:(SInt32 *)psize
+                               error:(NSError *__autoreleasing *)error
+{
+  UInt8 keyAndValueType = 0;
+  UInt32 size;
+  if (![self readVarint32:&size error:error]) {
+    return NO;
+  }
+  if (size != 0) {
+    if (![self readByte:&keyAndValueType error:error]) {
+      return NO;
+    }
+  }
+
+  UInt8 keyType;
+  if (![self ttype:&keyType forCompactType:keyAndValueType >> 4 error:error]) {
+    return NO;
+  }
+
+  UInt8 valueType;
+  if (![self ttype:&valueType forCompactType:keyAndValueType & 0xf error:error]) {
+    return NO;
+  }
+
+  if (pkeyType != NULL) {
+    *pkeyType = keyType;
+  }
+  if (pvalueType != NULL) {
+    *pvalueType = valueType;
+  }
+  if (psize != NULL) {
+    *psize = size;
+  }
+
+  return YES;
+}
+
+-(BOOL) readListBeginReturningElementType:(SInt32 *)pelementType
+                                     size:(SInt32 *)psize
+                                    error:(NSError *__autoreleasing *)error
+{
+  UInt8 sizeAndType;
+  if (![self readByte:&sizeAndType error:error]) {
+    return NO;
+  }
+
+  UInt32 size = (sizeAndType >> 4) & 0x0f;
+  if (size == 15) {
+    if (![self readVarint32:&size error:error]) {
+      return NO;
+    }
+  }
+
+  UInt8 elementType;
+  if (![self ttype:&elementType forCompactType:sizeAndType & 0x0f error:error]) {
+    return NO;
+  }
+
+  if (pelementType != NULL) {
+    *pelementType = elementType;
+  }
+  if (psize != NULL) {
+    *psize = size;
+  }
+
+  return YES;
+}
+
+-(BOOL) readSetBeginReturningElementType:(SInt32 *)pelementType
+                                    size:(SInt32 *)psize
+                                   error:(NSError *__autoreleasing *)error
+{
+  return [self readListBeginReturningElementType:pelementType size:psize error:error];
+}
+
+-(BOOL) readBool:(BOOL *)value error:(NSError *__autoreleasing *)error
+{
+  if (_booleanValue != nil) {
+
+    BOOL result = _booleanValue.boolValue;
+    _booleanValue = nil;
+
+    *value = result;
+  }
+  else {
+
+    UInt8 result;
+    if (![self readByte:&result error:error]) {
+      return NO;
+    }
+
+    *value = result == TCType_BOOLEAN_TRUE;
+  }
+
+  return YES;
+}
+
+-(BOOL) readByte:(UInt8 *)value error:(NSError *__autoreleasing *)error
+{
+  if (![_transport readAll:value offset:0 length:1 error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport read failed");
+  }
+  return YES;
+}
+
+-(BOOL) readI16:(SInt16 *)value error:(NSError *__autoreleasing *)error
+{
+  UInt32 v;
+  if (![self readVarint32:&v error:error]) {
+    return NO;
+  }
+
+  if (value) {
+    *value = (SInt16)[self zigZagToi32:v];
+  }
+
+  return YES;
+}
+
+-(BOOL) readI32:(SInt32 *)value error:(NSError *__autoreleasing *)error
+{
+  UInt32 v;
+  if (![self readVarint32:&v error:error]) {
+    return NO;
+  }
+
+  if (value) {
+    *value = [self zigZagToi32:v];
+  }
+
+  return YES;
+}
+
+-(BOOL) readI64:(SInt64 *)value error:(NSError *__autoreleasing *)error
+{
+  UInt64 v;
+  if (![self readVarint64:&v error:error]) {
+    return NO;
+  }
+
+  if (value) {
+    *value = [self zigZagToi64:v];
+  }
+
+  return YES;
+}
+
+-(BOOL) readDouble:(double *)value error:(NSError *__autoreleasing *)error
+{
+  UInt64 bits;
+  if (![_transport readAll:(UInt8 *)&bits offset:0 length:8 error:error]) {
+    PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport read failed");
+  }
+
+  bits = OSSwapLittleToHostInt64(bits);
+
+  if (value) {
+    memcpy(value, &bits, sizeof(bits));
+  }
+
+  return YES;
+}
+
+-(BOOL) readString:(NSString *__autoreleasing *)value error:(NSError *__autoreleasing *)error
+{
+  UInt32 length;
+  if (![self readVarint32:&length error:error]) {
+    return NO;
+  }
+
+  NSString *result;
+
+  if (length != 0) {
+
+    NSData *data;
+    if (![self readBinaryOfLength:length data:&data error:error]) {
+      return NO;
+    }
+
+    result = [[NSString alloc] initWithData:data
+                                   encoding:NSUTF8StringEncoding];
+  }
+  else {
+    result = @"";
+  }
+
+  if (value) {
+    *value = result;
+  }
+
+  return YES;
+}
+
+-(BOOL) readBinary:(NSData *__autoreleasing *)value error:(NSError *__autoreleasing *)error
+{
+  UInt32 length;
+  if (![self readVarint32:&length error:error]) {
+    return NO;
+  }
+
+  return [self readBinaryOfLength:length data:value error:error];
+}
+
+-(BOOL) readBinaryOfLength:(UInt32)length data:(NSData *__autoreleasing *)value error:(NSError *__autoreleasing *)error
+{
+  NSData *result;
+
+  if (length != 0) {
+
+    NSMutableData *buf = [NSMutableData dataWithLength:length];
+    if (![_transport readAll:buf.mutableBytes offset:0 length:length error:error]) {
+      PROTOCOL_TRANSPORT_ERROR(NO, error, @"Transport read failed");
+    }
+
+    result = buf;
+  }
+  else {
+
+    result = [NSData data];
+
+  }
+
+  if (value) {
+    *value = result;
+  }
+
+  return YES;
+}
+
+-(BOOL) readMessageEnd:(NSError *__autoreleasing *)error
+{
+  return YES;
+}
+-(BOOL) readFieldEnd:(NSError *__autoreleasing *)error
+{
+  return YES;
+}
+-(BOOL) readMapEnd:(NSError *__autoreleasing *)error
+{
+  return YES;
+}
+-(BOOL) readListEnd:(NSError *__autoreleasing *)error
+{
+  return YES;
+}
+-(BOOL) readSetEnd:(NSError *__autoreleasing *)error
+{
+  return YES;
+}
+
+-(BOOL) readVarint32:(UInt32 *)value error:(NSError *__autoreleasing *)error
+{
+  UInt32 result = 0;
+  int shift = 0;
+
+  while (true) {
+
+    UInt8 byte;
+    if (![self readByte:&byte error:error]) {
+      return NO;
+    }
+
+    result |= (UInt32)(byte & 0x7f) << shift;
+    if (!(byte & 0x80)) {
+      break;
+    }
+
+    shift += 7;
+  }
+
+  if (value) {
+    *value = result;
+  }
+
+  return YES;
+}
+
+-(BOOL) readVarint64:(UInt64 *)value error:(NSError *__autoreleasing *)error
+{
+  int shift = 0;
+  UInt64 result = 0;
+
+  while (true) {
+
+    UInt8 byte;
+    if (![self readByte:&byte error:error]) {
+      return NO;
+    }
+
+    result |= (UInt64)(byte & 0x7f) << shift;
+    if (!(byte & 0x80)) {
+      break;
+    }
+
+    shift += 7;
+  }
+
+  if (value) {
+    *value = result;
+  }
+
+  return YES;
+}
+
+-(SInt32) zigZagToi32:(UInt32)n
+{
+  return (SInt32)(n >> 1) ^ (-(SInt32)(n & 1));
+}
+
+-(SInt64) zigZagToi64:(UInt64)n
+{
+  return (SInt64)(n >> 1) ^ (-(SInt64)(n & 1));
+}
+
+-(BOOL) ttype:(UInt8 *)ttype forCompactType:(UInt8)ctype error:(NSError *__autoreleasing *)error
+{
+  switch (ctype & 0x0f) {
+  case TCType_STOP:
+    *ttype = TTypeSTOP;
+    return YES;
+
+  case TCType_BOOLEAN_FALSE:
+  case TCType_BOOLEAN_TRUE:
+    *ttype = TTypeBOOL;
+    return YES;
+
+  case TCType_BYTE:
+    *ttype = TTypeBYTE;
+    return YES;
+
+  case TCType_I16:
+    *ttype = TTypeI16;
+    return YES;
+
+  case TCType_I32:
+    *ttype = TTypeI32;
+    return YES;
+
+  case TCType_I64:
+    *ttype = TTypeI64;
+    return YES;
+
+  case TCType_DOUBLE:
+    *ttype = TTypeDOUBLE;
+    return YES;
+
+  case TCType_BINARY:
+    *ttype = TTypeSTRING;
+    return YES;
+
+  case TCType_LIST:
+    *ttype = TTypeLIST;
+    return YES;
+
+  case TCType_SET:
+    *ttype = TTypeSET;
+    return YES;
+
+  case TCType_MAP:
+    *ttype = TTypeMAP;
+    return YES;
+
+  case TCType_STRUCT:
+    *ttype = TTypeSTRUCT;
+    return YES;
+
+  default:
+    if (error) {
+      *error = [NSError errorWithDomain:TProtocolErrorDomain
+                                   code:TProtocolErrorUnknown
+                               userInfo:@{TProtocolErrorTypeKey: @((UInt8)(ctype & 0x0F))}];
+    }
+    return NO;
+  }
+}
+
+-(UInt8) compactTypeForTType:(UInt8)ttype
+{
+  static UInt8 ttypeToCompactType[] = {
+    [TTypeSTOP] = TCType_STOP,
+    [TTypeBOOL] = TCType_BOOLEAN_FALSE,
+    [TTypeBYTE] = TCType_BYTE,
+    [TTypeDOUBLE] = TCType_DOUBLE,
+    [TTypeI16] = TCType_I16,
+    [TTypeI32] = TCType_I32,
+    [TTypeI64] = TCType_I64,
+    [TTypeSTRING] = TCType_BINARY,
+    [TTypeSTRUCT] = TCType_STRUCT,
+    [TTypeMAP] = TCType_MAP,
+    [TTypeSET] = TCType_SET,
+    [TTypeLIST] = TCType_LIST
+  };
+
+  return ttypeToCompactType[ttype];
+}
+
+@end
diff --git a/lib/cocoa/src/protocol/TMultiplexedProtocol.h b/lib/cocoa/src/protocol/TMultiplexedProtocol.h
new file mode 100644
index 0000000..b8ce361
--- /dev/null
+++ b/lib/cocoa/src/protocol/TMultiplexedProtocol.h
@@ -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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "TProtocolDecorator.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+extern NSString *TMultiplexedProtocolSeperator;
+
+
+@interface TMultiplexedProtocol : TProtocolDecorator
+
+-(id) initWithProtocol:(id <TProtocol>)protocol
+           serviceName:(NSString *)name;
+
+@end
+
+
+NS_ASSUME_NONNULL_END
\ No newline at end of file
diff --git a/lib/cocoa/src/protocol/TMultiplexedProtocol.m b/lib/cocoa/src/protocol/TMultiplexedProtocol.m
new file mode 100644
index 0000000..5838c57
--- /dev/null
+++ b/lib/cocoa/src/protocol/TMultiplexedProtocol.m
@@ -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.
+ */
+
+#import "TMultiplexedProtocol.h"
+
+#import "TProtocol.h"
+
+NSString *TMultiplexedProtocolSeperator = @":";
+
+
+@interface TMultiplexedProtocol ()
+
+@property(strong, nonatomic) NSString *serviceName;
+
+@end
+
+
+@implementation TMultiplexedProtocol
+
+-(id) initWithProtocol:(id <TProtocol>)protocol
+           serviceName:(NSString *)name
+{
+  self = [super initWithProtocol:protocol];
+  if (self) {
+    _serviceName = name;
+  }
+  return self;
+}
+
+-(BOOL) writeMessageBeginWithName:(NSString *)name
+                             type:(SInt32)messageType
+                       sequenceID:(SInt32)sequenceID
+                            error:(NSError *__autoreleasing *)error
+{
+  switch (messageType) {
+  case TMessageTypeCALL:
+  case TMessageTypeONEWAY: {
+    NSMutableString *serviceFunction = [[NSMutableString alloc] initWithString:_serviceName];
+    [serviceFunction appendString:TMultiplexedProtocolSeperator];
+    [serviceFunction appendString:name];
+    return [super writeMessageBeginWithName:serviceFunction type:messageType sequenceID:sequenceID error:error];
+  }
+  break;
+
+  default:
+    return [super writeMessageBeginWithName:name type:messageType sequenceID:sequenceID error:error];
+  }
+}
+
+@end
diff --git a/lib/cocoa/src/protocol/TProtocol.h b/lib/cocoa/src/protocol/TProtocol.h
index 281239d..841059f 100644
--- a/lib/cocoa/src/protocol/TProtocol.h
+++ b/lib/cocoa/src/protocol/TProtocol.h
@@ -22,127 +22,143 @@
 #import "TTransport.h"
 
 
-enum {
-  TMessageType_CALL = 1,
-  TMessageType_REPLY = 2,
-  TMessageType_EXCEPTION = 3,
-  TMessageType_ONEWAY = 4
+NS_ASSUME_NONNULL_BEGIN
+
+
+typedef NS_ENUM (int, TMessageType) {
+  TMessageTypeCALL = 1,
+  TMessageTypeREPLY = 2,
+  TMessageTypeEXCEPTION = 3,
+  TMessageTypeONEWAY = 4
 };
 
-enum {
-  TType_STOP   = 0,
-  TType_VOID   = 1,
-  TType_BOOL   = 2,
-  TType_BYTE   = 3,
-  TType_DOUBLE = 4,
-  TType_I16    = 6,
-  TType_I32    = 8,
-  TType_I64    = 10,
-  TType_STRING = 11,
-  TType_STRUCT = 12,
-  TType_MAP    = 13,
-  TType_SET    = 14,
-  TType_LIST   = 15
+typedef NS_ENUM (int, TType) {
+  TTypeSTOP   = 0,
+  TTypeVOID   = 1,
+  TTypeBOOL   = 2,
+  TTypeBYTE   = 3,
+  TTypeDOUBLE = 4,
+  TTypeI16    = 6,
+  TTypeI32    = 8,
+  TTypeI64    = 10,
+  TTypeSTRING = 11,
+  TTypeSTRUCT = 12,
+  TTypeMAP    = 13,
+  TTypeSET    = 14,
+  TTypeLIST   = 15
 };
 
 
 @protocol TProtocol <NSObject>
 
-- (id <TTransport>) transport;
+-(id <TTransport>) transport;
 
-- (void) readMessageBeginReturningName: (NSString **) name
-                                  type: (int *) type
-                            sequenceID: (int *) sequenceID;
-- (void) readMessageEnd;
+-(BOOL) readMessageBeginReturningName:(NSString *__nullable __autoreleasing *__nullable)name
+                                 type:(nullable SInt32 *)type
+                           sequenceID:(nullable SInt32 *)sequenceID
+                                error:(NSError *__autoreleasing *)error;
+-(BOOL) readMessageEnd:(NSError *__autoreleasing *)error;
 
-- (void) readStructBeginReturningName: (NSString **) name;
-- (void) readStructEnd;
+-(BOOL) readStructBeginReturningName:(NSString *__nullable __autoreleasing *__nullable)name
+                               error:(NSError *__autoreleasing *)error;
+-(BOOL) readStructEnd:(NSError *__autoreleasing *)error;
 
-- (void) readFieldBeginReturningName: (NSString **) name
-                                type: (int *) fieldType
-                             fieldID: (int *) fieldID;
-- (void) readFieldEnd;
+-(BOOL) readFieldBeginReturningName:(NSString *__nullable __autoreleasing *__nullable)name
+                               type:(SInt32 *)fieldType
+                            fieldID:(nullable SInt32 *)fieldID
+                              error:(NSError *__autoreleasing *)error;
+-(BOOL) readFieldEnd:(NSError *__autoreleasing *)error;
 
-- (NSString *) readString;
+-(BOOL) readString:(NSString *__nonnull __autoreleasing *__nonnull)value error:(NSError **)error;
 
-- (BOOL) readBool;
+-(BOOL) readBool:(BOOL *)value error:(NSError *__autoreleasing *)error;
 
-- (unsigned char) readByte;
+-(BOOL) readByte:(UInt8 *)value error:(NSError *__autoreleasing *)error;
 
-- (short) readI16;
+-(BOOL) readI16:(SInt16 *)value error:(NSError *__autoreleasing *)error;
 
-- (int32_t) readI32;
+-(BOOL) readI32:(SInt32 *)value error:(NSError *__autoreleasing *)error;
 
-- (int64_t) readI64;
+-(BOOL) readI64:(SInt64 *)value error:(NSError *__autoreleasing *)error;
 
-- (double) readDouble;
+-(BOOL) readDouble:(double *)value error:(NSError *__autoreleasing *)error;
 
-- (NSData *) readBinary;
+-(BOOL) readBinary:(NSData *__nonnull __autoreleasing *__nonnull)value error:(NSError **)error;
 
-- (void) readMapBeginReturningKeyType: (int *) keyType
-                            valueType: (int *) valueType
-                                 size: (int *) size;
-- (void) readMapEnd;
+-(BOOL) readMapBeginReturningKeyType:(nullable SInt32 *)keyType
+                           valueType:(nullable SInt32 *)valueType
+                                size:(SInt32 *)size
+                               error:(NSError *__autoreleasing *)error;
+-(BOOL) readMapEnd:(NSError *__autoreleasing *)error;
 
 
-- (void) readSetBeginReturningElementType: (int *) elementType
-                                     size: (int *) size;
-- (void) readSetEnd;
+-(BOOL) readSetBeginReturningElementType:(nullable SInt32 *)elementType
+                                    size:(SInt32 *)size
+                                   error:(NSError *__autoreleasing *)error;
+-(BOOL) readSetEnd:(NSError *__autoreleasing *)error;
 
 
-- (void) readListBeginReturningElementType: (int *) elementType
-                                      size: (int *) size;
-- (void) readListEnd;
+-(BOOL) readListBeginReturningElementType:(nullable SInt32 *)elementType
+                                     size:(SInt32 *)size
+                                    error:(NSError *__autoreleasing *)error;
+-(BOOL) readListEnd:(NSError *__autoreleasing *)error;
 
 
-- (void) writeMessageBeginWithName: (NSString *) name
-                              type: (int) messageType
-                        sequenceID: (int) sequenceID;
-- (void) writeMessageEnd;
+-(BOOL) writeMessageBeginWithName:(NSString *)name
+                             type:(SInt32)messageType
+                       sequenceID:(SInt32)sequenceID
+                            error:(NSError *__autoreleasing *)error;
+-(BOOL) writeMessageEnd:(NSError *__autoreleasing *)error;
 
-- (void) writeStructBeginWithName: (NSString *) name;
-- (void) writeStructEnd;
+-(BOOL) writeStructBeginWithName:(NSString *)name error:(NSError **)error;
+-(BOOL) writeStructEnd:(NSError *__autoreleasing *)error;
 
-- (void) writeFieldBeginWithName: (NSString *) name
-                            type: (int) fieldType
-                         fieldID: (int) fieldID;
+-(BOOL) writeFieldBeginWithName:(NSString *)name
+                           type:(SInt32)fieldType
+                        fieldID:(SInt32)fieldID
+                          error:(NSError *__autoreleasing *)error;
 
-- (void) writeI32: (int32_t) value;
+-(BOOL) writeI32:(SInt32)value error:(NSError *__autoreleasing *)error;
 
-- (void) writeI64: (int64_t) value;
+-(BOOL) writeI64:(SInt64)value error:(NSError *__autoreleasing *)error;
 
-- (void) writeI16: (short) value;
+-(BOOL) writeI16:(short)value error:(NSError *__autoreleasing *)error;
 
-- (void) writeByte: (uint8_t) value;
+-(BOOL) writeByte:(UInt8)value error:(NSError *__autoreleasing *)error;
 
-- (void) writeString: (NSString *) value;
+-(BOOL) writeString:(NSString *)value error:(NSError *__autoreleasing *)error;
 
-- (void) writeDouble: (double) value;
+-(BOOL) writeDouble:(double)value error:(NSError *__autoreleasing *)error;
 
-- (void) writeBool: (BOOL) value;
+-(BOOL) writeBool:(BOOL)value error:(NSError *__autoreleasing *)error;
 
-- (void) writeBinary: (NSData *) data;
+-(BOOL) writeBinary:(NSData *)data error:(NSError *__autoreleasing *)error;
 
-- (void) writeFieldStop;
+-(BOOL) writeFieldStop:(NSError *__autoreleasing *)error;
 
-- (void) writeFieldEnd;
+-(BOOL) writeFieldEnd:(NSError *__autoreleasing *)error;
 
-- (void) writeMapBeginWithKeyType: (int) keyType
-                        valueType: (int) valueType
-                             size: (int) size;
-- (void) writeMapEnd;
+-(BOOL) writeMapBeginWithKeyType:(SInt32)keyType
+                       valueType:(SInt32)valueType
+                            size:(SInt32)size
+                           error:(NSError *__autoreleasing *)error;
+-(BOOL) writeMapEnd:(NSError *__autoreleasing *)error;
 
 
-- (void) writeSetBeginWithElementType: (int) elementType
-                                 size: (int) size;
-- (void) writeSetEnd;
+-(BOOL) writeSetBeginWithElementType:(SInt32)elementType
+                                size:(SInt32)size
+                               error:(NSError *__autoreleasing *)error;
+-(BOOL) writeSetEnd:(NSError *__autoreleasing *)error;
 
 
-- (void) writeListBeginWithElementType: (int) elementType
-                                  size: (int) size;
+-(BOOL) writeListBeginWithElementType:(SInt32)elementType
+                                 size:(SInt32)size
+                                error:(NSError *__autoreleasing *)error;
 
-- (void) writeListEnd;
+-(BOOL) writeListEnd:(NSError *__autoreleasing *)error;
 
 
 @end
 
+
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/protocol/TProtocolDecorator.h b/lib/cocoa/src/protocol/TProtocolDecorator.h
new file mode 100644
index 0000000..369b6a2
--- /dev/null
+++ b/lib/cocoa/src/protocol/TProtocolDecorator.h
@@ -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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "TProtocol.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+@interface TProtocolDecorator : NSObject <TProtocol>
+
+-(id) initWithProtocol:(id <TProtocol>)protocol;
+
+@end
+
+
+NS_ASSUME_NONNULL_END
\ No newline at end of file
diff --git a/lib/cocoa/src/protocol/TProtocolDecorator.m b/lib/cocoa/src/protocol/TProtocolDecorator.m
new file mode 100644
index 0000000..218f900
--- /dev/null
+++ b/lib/cocoa/src/protocol/TProtocolDecorator.m
@@ -0,0 +1,295 @@
+/*
+ * 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 "TProtocolDecorator.h"
+
+
+@interface TProtocolDecorator ()
+
+@property(strong, nonatomic) id<TProtocol> concreteProtocol;
+
+@end
+
+
+@implementation TProtocolDecorator
+
+-(id) initWithProtocol:(id <TProtocol>)protocol
+{
+  self = [super init];
+  if (self) {
+    _concreteProtocol = protocol;
+  }
+  return self;
+}
+
+-(id <TTransport>) transport
+{
+  return [_concreteProtocol transport];
+}
+
+-(BOOL) readMessageBeginReturningName:(NSString **)name
+                                 type:(SInt32 *)type
+                           sequenceID:(SInt32 *)sequenceID
+                                error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readMessageBeginReturningName:name
+                                                     type:type
+                                               sequenceID:sequenceID
+                                                    error:error];
+}
+
+-(BOOL) readMessageEnd:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readMessageEnd:error];
+}
+
+-(BOOL) readStructBeginReturningName:(NSString **)name
+                               error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readStructBeginReturningName:name error:error];
+}
+
+-(BOOL) readStructEnd:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readStructEnd:error];
+}
+
+-(BOOL) readFieldBeginReturningName:(NSString **)name
+                               type:(SInt32 *)fieldType
+                            fieldID:(SInt32 *)fieldID
+                              error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readFieldBeginReturningName:name
+                                                   type:fieldType
+                                                fieldID:fieldID
+                                                  error:error];
+}
+-(BOOL) readFieldEnd:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readFieldEnd:error];
+}
+
+-(BOOL) readString:(NSString *__autoreleasing *)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readString:value error:error];
+}
+
+-(BOOL) readBool:(BOOL *)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readBool:value error:error];
+}
+
+-(BOOL) readByte:(UInt8 *)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readByte:value error:error];
+}
+
+-(BOOL) readI16:(SInt16 *)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readI16:value error:error];
+}
+
+-(BOOL) readI32:(SInt32 *)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readI32:value error:error];
+}
+
+-(BOOL) readI64:(SInt64 *)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readI64:value error:error];
+}
+
+-(BOOL) readDouble:(double *)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readDouble:value error:error];
+}
+
+-(BOOL) readBinary:(NSData *__autoreleasing *)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readBinary:value error:error];
+}
+
+-(BOOL) readMapBeginReturningKeyType:(SInt32 *)keyType
+                           valueType:(SInt32 *)valueType
+                                size:(SInt32 *)size
+                               error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readMapBeginReturningKeyType:keyType
+                                               valueType:valueType
+                                                    size:size
+                                                   error:error];
+}
+-(BOOL) readMapEnd:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readMapEnd:error];
+}
+
+
+-(BOOL) readSetBeginReturningElementType:(SInt32 *)elementType
+                                    size:(SInt32 *)size
+                                   error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readSetBeginReturningElementType:elementType
+                                                        size:size
+                                                       error:error];
+}
+-(BOOL) readSetEnd:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readSetEnd:error];
+}
+
+-(BOOL) readListBeginReturningElementType:(SInt32 *)elementType
+                                     size:(SInt32 *)size
+                                    error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readListBeginReturningElementType:elementType
+                                                         size:size
+                                                        error:error];
+}
+-(BOOL) readListEnd:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol readListEnd:error];
+}
+
+-(BOOL) writeMessageBeginWithName:(NSString *)name
+                             type:(SInt32)messageType
+                       sequenceID:(SInt32)sequenceID
+                            error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeMessageBeginWithName:name
+                                                 type:messageType
+                                           sequenceID:sequenceID
+                                                error:error];
+}
+-(BOOL) writeMessageEnd:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeMessageEnd:error];
+}
+
+-(BOOL) writeStructBeginWithName:(NSString *)name error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeStructBeginWithName:name error:error];
+}
+-(BOOL) writeStructEnd:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeStructEnd:error];
+}
+
+-(BOOL) writeFieldBeginWithName:(NSString *)name
+                           type:(SInt32)fieldType
+                        fieldID:(SInt32)fieldID
+                          error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeFieldBeginWithName:name
+                                               type:fieldType
+                                            fieldID:fieldID
+                                              error:error];
+}
+
+-(BOOL) writeI32:(SInt32)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeI32:value error:error];
+}
+
+-(BOOL) writeI64:(SInt64)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeI64:value error:error];
+}
+
+-(BOOL) writeI16:(SInt16)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeI16:value error:error];
+}
+
+-(BOOL) writeByte:(UInt8)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeByte:value error:error];
+}
+
+-(BOOL) writeString:(NSString *)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeString:value error:error];
+}
+
+-(BOOL) writeDouble:(double)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeDouble:value error:error];
+}
+
+-(BOOL) writeBool:(BOOL)value error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeBool:value error:error];
+}
+
+-(BOOL) writeBinary:(NSData *)data error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeBinary:data error:error];
+}
+
+-(BOOL) writeFieldStop:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeFieldStop:error];
+}
+
+-(BOOL) writeFieldEnd:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeFieldEnd:error];
+}
+
+-(BOOL) writeMapBeginWithKeyType:(SInt32)keyType
+                       valueType:(SInt32)valueType
+                            size:(SInt32)size
+                           error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeMapBeginWithKeyType:keyType
+                                           valueType:valueType
+                                                size:size
+                                               error:error];
+}
+
+-(BOOL) writeMapEnd:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeMapEnd:error];
+}
+
+-(BOOL) writeSetBeginWithElementType:(SInt32)elementType
+                                size:(SInt32)size
+                               error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeSetBeginWithElementType:elementType size:size error:error];
+}
+
+-(BOOL) writeSetEnd:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeSetEnd:error];
+}
+
+-(BOOL) writeListBeginWithElementType:(SInt32)elementType
+                                 size:(SInt32)size
+                                error:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeListBeginWithElementType:elementType size:size error:error];
+}
+
+-(BOOL) writeListEnd:(NSError *__autoreleasing *)error
+{
+  return [_concreteProtocol writeListEnd:error];
+}
+
+@end
diff --git a/lib/cocoa/src/protocol/TProtocolError.h b/lib/cocoa/src/protocol/TProtocolError.h
new file mode 100644
index 0000000..ab0bc40
--- /dev/null
+++ b/lib/cocoa/src/protocol/TProtocolError.h
@@ -0,0 +1,76 @@
+/*
+ * 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 "TError.h"
+
+
+extern NSString *TProtocolErrorDomain;
+
+typedef NS_ENUM (int, TProtocolError) {
+  TProtocolErrorUnknown                   = 0,
+  TProtocolErrorInvalidData               = 1,
+  TProtocolErrorNegativeSize              = 2,
+  TProtocolErrorSizeLimit                 = 3,
+  TProtocolErrorBadVersion                = 4,
+  TProtocolErrorNotImplemented            = 5,
+  TProtocolErrorDepthLimit                = 6,
+};
+
+
+typedef NS_ENUM(int, TProtocolExtendedError) {
+  TProtocolExtendedErrorMissingRequiredField  = 1001,
+  TProtocolExtendedErrorUnexpectedType        = 1002,
+  TProtocolExtendedErrorMismatchedProtocol    = 1003,
+};
+
+extern NSString *TProtocolErrorExtendedErrorKey;
+extern NSString *TProtocolErrorFieldNameKey;
+extern NSString *TProtocolErrorExpectedIdKey;
+extern NSString *TProtocolErrorExpectedVersionKey;
+extern NSString *TProtocolErrorTypeKey;
+extern NSString *TProtocolErrorSourceLineKey;
+extern NSString *TProtocolErrorSourceFileKey;
+extern NSString *TProtocolErrorSourceMethodKey;
+extern NSString *TProtocolErrorMessageNameKey;
+
+
+#define PROTOCOL_ERROR(ret, err, ...) \
+  if (error) {  \
+    *error = [NSError errorWithDomain:TProtocolErrorDomain \
+                                 code:TProtocolError ## err \
+                             userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:__VA_ARGS__], \
+                                        @"SourceFile": [NSString stringWithUTF8String:__FILE__], \
+                                        @"SourceLine": @(__LINE__), \
+                                        @"SourceFunction": [NSString stringWithUTF8String:__PRETTY_FUNCTION__], \
+                                        @"Message": self.currentMessageName ? self.currentMessageName : @""}]; \
+  } \
+  return ret
+
+#define PROTOCOL_TRANSPORT_ERROR(ret, errorPtr, ...) \
+  if (errorPtr) { \
+    *error = [NSError errorWithDomain:TProtocolErrorDomain \
+                                 code:TProtocolErrorUnknown \
+                             userInfo:@{NSLocalizedDescriptionKey: [[NSString stringWithFormat:__VA_ARGS__] stringByAppendingFormat:@": %@", [(*errorPtr) localizedDescription]], \
+                                        TProtocolErrorSourceFileKey: [NSString stringWithUTF8String:__FILE__], \
+                                        TProtocolErrorSourceLineKey: @(__LINE__), \
+                                        TProtocolErrorSourceMethodKey: [NSString stringWithUTF8String:__PRETTY_FUNCTION__], \
+                                        TProtocolErrorMessageNameKey: self.currentMessageName ? self.currentMessageName : @"", \
+                                        NSUnderlyingErrorKey: *errorPtr}]; \
+  } \
+  return ret
diff --git a/lib/cocoa/src/protocol/TProtocolError.m b/lib/cocoa/src/protocol/TProtocolError.m
new file mode 100644
index 0000000..953673b
--- /dev/null
+++ b/lib/cocoa/src/protocol/TProtocolError.m
@@ -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.
+ */
+
+#import "TProtocolError.h"
+
+
+NSString *TProtocolErrorDomain = @"TProtocolErrorDomain";
+
+NSString *TProtocolErrorExtendedErrorKey = @"extendedError";
+NSString *TProtocolErrorFieldNameKey = @"field";
+NSString *TProtocolErrorExpectedIdKey = @"expectedId";
+NSString *TProtocolErrorExpectedVersionKey = @"expectedVersion";
+NSString *TProtocolErrorTypeKey = @"type";
+NSString *TProtocolErrorSourceLineKey = @"sourceLine";
+NSString *TProtocolErrorSourceFileKey = @"sourceFile";
+NSString *TProtocolErrorSourceMethodKey = @"sourceMethod";
+NSString *TProtocolErrorMessageNameKey = @"messageName";
diff --git a/lib/cocoa/src/protocol/TProtocolException.h b/lib/cocoa/src/protocol/TProtocolException.h
deleted file mode 100644
index ad354fc..0000000
--- a/lib/cocoa/src/protocol/TProtocolException.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import "TException.h"
-
-@interface TProtocolException : TException {
-}
-
-@end
diff --git a/lib/cocoa/src/protocol/TProtocolException.m b/lib/cocoa/src/protocol/TProtocolException.m
deleted file mode 100644
index 681487a..0000000
--- a/lib/cocoa/src/protocol/TProtocolException.m
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import "TProtocolException.h"
-
-@implementation TProtocolException
-@end
diff --git a/lib/cocoa/src/protocol/TProtocolFactory.h b/lib/cocoa/src/protocol/TProtocolFactory.h
index f200a6d..a022a7f 100644
--- a/lib/cocoa/src/protocol/TProtocolFactory.h
+++ b/lib/cocoa/src/protocol/TProtocolFactory.h
@@ -21,9 +21,16 @@
 #import "TProtocol.h"
 #import "TTransport.h"
 
+NS_ASSUME_NONNULL_BEGIN
+
 
 @protocol TProtocolFactory <NSObject>
 
-- (id <TProtocol>) newProtocolOnTransport: (id <TTransport>) transport;
+@property (readonly, nonatomic) NSString *protocolName;
+
+-(id<TProtocol>) newProtocolOnTransport:(id<TTransport>)transport;
 
 @end
+
+
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/protocol/TProtocolUtil.h b/lib/cocoa/src/protocol/TProtocolUtil.h
index c2d2521..82510cf 100644
--- a/lib/cocoa/src/protocol/TProtocolUtil.h
+++ b/lib/cocoa/src/protocol/TProtocolUtil.h
@@ -20,10 +20,14 @@
 #import "TProtocol.h"
 #import "TTransport.h"
 
-@interface TProtocolUtil : NSObject {
+NS_ASSUME_NONNULL_BEGIN
 
-}
 
-+ (void) skipType: (int) type onProtocol: (id <TProtocol>) protocol;
+@interface TProtocolUtil : NSObject
+
++(BOOL) skipType:(int)type onProtocol:(id <TProtocol>)protocol error:(NSError **)error;
 
 @end;
+
+
+NS_ASSUME_NONNULL_END
\ No newline at end of file
diff --git a/lib/cocoa/src/protocol/TProtocolUtil.m b/lib/cocoa/src/protocol/TProtocolUtil.m
index 13d7095..c0d65ac 100644
--- a/lib/cocoa/src/protocol/TProtocolUtil.m
+++ b/lib/cocoa/src/protocol/TProtocolUtil.m
@@ -21,84 +21,151 @@
 
 @implementation TProtocolUtil
 
-+ (void) skipType: (int) type onProtocol: (id <TProtocol>) protocol
++(BOOL) skipType:(int)type onProtocol:(id <TProtocol>)protocol error:(NSError **)error
 {
   switch (type) {
-  case TType_BOOL:
-    [protocol readBool];
-    break;
-  case TType_BYTE:
-    [protocol readByte];
-    break;
-  case TType_I16:
-    [protocol readI16];
-    break;
-  case TType_I32:
-    [protocol readI32];
-    break;
-  case TType_I64:
-    [protocol readI64];
-    break;
-  case TType_DOUBLE:
-    [protocol readDouble];
-    break;
-  case TType_STRING:
-    [protocol readString];
-    break;
-  case TType_STRUCT:
-    [protocol readStructBeginReturningName: NULL];
+  case TTypeBOOL: {
+    BOOL val;
+    if (![protocol readBool:&val error:error]) {
+      return NO;
+    }
+  }
+  break;
+
+  case TTypeBYTE: {
+    UInt8 val;
+    if (![protocol readByte:&val error:error]) {
+      return NO;
+    }
+  }
+  break;
+
+  case TTypeI16: {
+    SInt16 val;
+    if (![protocol readI16:&val error:error]) {
+      return NO;
+    }
+  }
+  break;
+
+  case TTypeI32: {
+    SInt32 val;
+    if (![protocol readI32:&val error:error]) {
+      return NO;
+    }
+  }
+  break;
+
+  case TTypeI64: {
+    SInt64 val;
+    if (![protocol readI64:&val error:error]) {
+      return NO;
+    }
+  }
+  break;
+
+  case TTypeDOUBLE: {
+    double val;
+    if (![protocol readDouble:&val error:error]) {
+      return NO;
+    }
+  }
+  break;
+
+  case TTypeSTRING: {
+    NSString *val;
+    if (![protocol readString:&val error:error]) {
+      return NO;
+    }
+  }
+  break;
+
+  case TTypeSTRUCT: {
+    if (![protocol readStructBeginReturningName:NULL error:error]) {
+      return NO;
+    }
     while (true) {
-      int fieldType;
-      [protocol readFieldBeginReturningName: nil type: &fieldType fieldID: nil];
-      if (fieldType == TType_STOP) {
+      SInt32 fieldType;
+      if (![protocol readFieldBeginReturningName:nil type:&fieldType fieldID:nil error:error]) {
+        return NO;
+      }
+      if (fieldType == TTypeSTOP) {
         break;
       }
-      [TProtocolUtil skipType: fieldType onProtocol: protocol];
-      [protocol readFieldEnd];
+      if (![self skipType:fieldType onProtocol:protocol error:error]) {
+        return NO;
+      }
+      if (![protocol readFieldEnd:error]) {
+        return NO;
+      }
     }
-    [protocol readStructEnd];
-    break;
-  case TType_MAP:
-  {
-    int keyType;
-    int valueType;
-    int size;
-    [protocol readMapBeginReturningKeyType: &keyType valueType: &valueType size: &size];
+    if (![protocol readStructEnd:error]) {
+      return NO;
+    }
+  }
+  break;
+
+  case TTypeMAP: {
+    SInt32 keyType;
+    SInt32 valueType;
+    SInt32 size;
+    if (![protocol readMapBeginReturningKeyType:&keyType valueType:&valueType size:&size error:error]) {
+      return NO;
+    }
     int i;
     for (i = 0; i < size; i++) {
-      [TProtocolUtil skipType: keyType onProtocol: protocol];
-      [TProtocolUtil skipType: valueType onProtocol: protocol];
-    }
-    [protocol readMapEnd];
-  }
-    break;
-    case TType_SET:
-    {
-      int elemType;
-      int size;
-      [protocol readSetBeginReturningElementType: &elemType size: &size];
-      int i;
-      for (i = 0; i < size; i++) {
-        [TProtocolUtil skipType: elemType onProtocol: protocol];
+      if (![TProtocolUtil skipType:keyType onProtocol:protocol error:error]) {
+        return NO;
       }
-      [protocol readSetEnd];
-    }
-      break;
-    case TType_LIST:
-    {
-      int elemType;
-      int size;
-      [protocol readListBeginReturningElementType: &elemType size: &size];
-      int i;
-      for (i = 0; i < size; i++) {
-        [TProtocolUtil skipType: elemType onProtocol: protocol];
+      if (![TProtocolUtil skipType:valueType onProtocol:protocol error:error]) {
+        return NO;
       }
-      [protocol readListEnd];
     }
-      break;
-    default:
-      return;
+    if (![protocol readMapEnd:error]) {
+      return NO;
+    }
   }
+  break;
+
+  case TTypeSET: {
+    SInt32 elemType;
+    SInt32 size;
+    if (![protocol readSetBeginReturningElementType:&elemType size:&size error:error]) {
+      return NO;
+    }
+    int i;
+    for (i = 0; i < size; i++) {
+      if (![TProtocolUtil skipType:elemType onProtocol:protocol error:error]) {
+        return NO;
+      }
+    }
+    if (![protocol readSetEnd:error]) {
+      return NO;
+    }
+  }
+  break;
+
+  case TTypeLIST: {
+    SInt32 elemType;
+    SInt32 size;
+    if (![protocol readListBeginReturningElementType:&elemType size:&size error:error]) {
+      return NO;
+    }
+    int i;
+    for (i = 0; i < size; i++) {
+      if (![TProtocolUtil skipType:elemType onProtocol:protocol error:error]) {
+        return NO;
+      }
+    }
+    if (![protocol readListEnd:error]) {
+      return NO;
+    }
+  }
+  break;
+
+  }
+
+  return YES;
 }
 
 @end
diff --git a/lib/cocoa/src/server/TSocketServer.h b/lib/cocoa/src/server/TSocketServer.h
index c8ff9f0..95b0d3c 100644
--- a/lib/cocoa/src/server/TSocketServer.h
+++ b/lib/cocoa/src/server/TSocketServer.h
@@ -27,23 +27,25 @@
 #import <CFNetwork/CFNetwork.h>
 #endif
 
-extern NSString * const kTSocketServer_ClientConnectionFinishedForProcessorNotification;
-extern NSString * const kTSocketServer_ProcessorKey;
-extern NSString * const kTSockerServer_TransportKey;
+NS_ASSUME_NONNULL_BEGIN
 
 
-@interface TSocketServer : NSObject {
-  NSFileHandle * mSocketFileHandle;
-  id <TProtocolFactory> mInputProtocolFactory;
-  id <TProtocolFactory> mOutputProtocolFactory;
-  id <TProcessorFactory> mProcessorFactory;
-}
+extern NSString *const TSocketServerClientConnectionFinished;
+extern NSString *const TSocketServerProcessorKey;
+extern NSString *const TSockerServerTransportKey;
 
-- (id) initWithPort: (int) port
-    protocolFactory: (id <TProtocolFactory>) protocolFactory
-   processorFactory: (id <TProcessorFactory>) processorFactory;
+
+@interface TSocketServer : NSObject
+
+-(instancetype) initWithPort:(int)port
+             protocolFactory:(id <TProtocolFactory>)protocolFactory
+            processorFactory:(id <TProcessorFactory>)processorFactory;
+
+- (instancetype) initWithPath: (NSString *) path
+              protocolFactory: (id <TProtocolFactory>) protocolFactory
+             processorFactory: (id <TProcessorFactory>) processorFactory;
 
 @end
 
 
-
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/server/TSocketServer.m b/lib/cocoa/src/server/TSocketServer.m
index 4941445..09b603c 100644
--- a/lib/cocoa/src/server/TSocketServer.m
+++ b/lib/cocoa/src/server/TSocketServer.m
@@ -21,36 +21,92 @@
 #import "TSocketServer.h"
 #import "TNSFileHandleTransport.h"
 #import "TProtocol.h"
-#import "TTransportException.h"
-#import "TObjective-C.h"
+#import "TTransportError.h"
+
 #import <sys/socket.h>
 #include <netinet/in.h>
+#include <sys/un.h>
 
 
+NSString *const TSocketServerClientConnectionFinished = @"TSocketServerClientConnectionFinished";
+NSString *const TSocketServerProcessorKey = @"TSocketServerProcessor";
+NSString *const TSockerServerTransportKey = @"TSockerServerTransport";
 
-NSString * const kTSocketServer_ClientConnectionFinishedForProcessorNotification = @"TSocketServer_ClientConnectionFinishedForProcessorNotification";
-NSString * const kTSocketServer_ProcessorKey = @"TSocketServer_Processor";
-NSString * const kTSockerServer_TransportKey = @"TSockerServer_Transport";
+
+@interface TSocketServer ()
+
+@property(strong, nonatomic) id<TProtocolFactory> inputProtocolFactory;
+@property(strong, nonatomic) id<TProtocolFactory> outputProtocolFactory;
+@property(strong, nonatomic) id<TProcessorFactory> processorFactory;
+@property(strong, nonatomic) NSFileHandle *socketFileHandle;
+@property(strong, nonatomic) dispatch_queue_t processingQueue;
+@property(strong, nonatomic) NSString *domainSocketPath;
+
+@end
 
 
 @implementation TSocketServer
 
-- (id) initWithPort: (int) port
-    protocolFactory: (id <TProtocolFactory>) protocolFactory
-   processorFactory: (id <TProcessorFactory>) processorFactory;
+-(instancetype) initWithSocket:(CFSocketRef)socket
+             protocolFactory:(id <TProtocolFactory>)protocolFactory
+            processorFactory:(id <TProcessorFactory>)processorFactory;
 {
   self = [super init];
 
-  mInputProtocolFactory = [protocolFactory retain_stub];
-  mOutputProtocolFactory = [protocolFactory retain_stub];
-  mProcessorFactory = [processorFactory retain_stub];
+  _inputProtocolFactory = protocolFactory;
+  _outputProtocolFactory = protocolFactory;
+  _processorFactory = processorFactory;
+
+  dispatch_queue_attr_t processingQueueAttr =
+    dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_BACKGROUND, 0);
+
+  _processingQueue = dispatch_queue_create("TSocketServer.processing", processingQueueAttr);
 
   // create a socket.
-  int fd = -1;
+  int fd = CFSocketGetNative(socket);
+
+  // wrap it in a file handle so we can get messages from it
+  _socketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fd
+                                                    closeOnDealloc:YES];
+
+  // throw away our socket
+  CFSocketInvalidate(socket);
+  CFRelease(socket);
+
+  // register for notifications of accepted incoming connections
+  [[NSNotificationCenter defaultCenter] addObserver:self
+                                           selector:@selector(connectionAccepted:)
+                                               name:NSFileHandleConnectionAcceptedNotification
+                                             object:_socketFileHandle];
+
+  // tell socket to listen
+  [_socketFileHandle acceptConnectionInBackgroundAndNotify];
+
+  return self;
+}
+
+- (id) initWithPort: (int) port
+    protocolFactory: (id <TProtocolFactory>) protocolFactory
+   processorFactory: (id <TProcessorFactory>) processorFactory
+{
+  CFSocketRef socket = [[self class] createSocketWithPort:port];
+  if (socket == NULL) {
+    return nil;
+  }
+
+  if (self = [self initWithSocket:socket protocolFactory:protocolFactory processorFactory:processorFactory]) {
+    NSLog(@"TSocketServer: Listening on TCP port %d", port);
+  }
+  return self;
+}
+
+
++(CFSocketRef) createSocketWithPort:(int)port
+{
   CFSocketRef socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL);
   if (socket) {
     CFSocketSetSocketFlags(socket, CFSocketGetSocketFlags(socket) & ~kCFSocketCloseOnInvalidate);
-    fd = CFSocketGetNative(socket);
+    int fd = CFSocketGetNative(socket);
     int yes = 1;
     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
 
@@ -61,134 +117,123 @@
     addr.sin_port = htons(port);
     addr.sin_addr.s_addr = htonl(INADDR_ANY);
     NSData *address = [NSData dataWithBytes:&addr length:sizeof(addr)];
-    if (CFSocketSetAddress(socket, (bridge_stub CFDataRef)address) != kCFSocketSuccess) {
+    if (CFSocketSetAddress(socket, (__bridge CFDataRef)address) != kCFSocketSuccess) {
       CFSocketInvalidate(socket);
       CFRelease(socket);
-      NSLog(@"*** Could not bind to address");
-      return nil;
+      NSLog(@"TSocketServer: Could not bind to address");
+      return NULL;
     }
-  } else {
-    NSLog(@"*** No server socket");
+
+    return socket;
+  }
+  else {
+    NSLog(@"TSocketServer: No server socket");
+    return NULL;
+  }
+}
+
+- (id) initWithPath: (NSString *) path
+    protocolFactory: (id <TProtocolFactory>) protocolFactory
+   processorFactory: (id <TProcessorFactory>) processorFactory
+{
+  _domainSocketPath = path;
+  CFSocketRef socket = [[self class] createSocketWithPath:path];
+  if (socket == NULL) {
     return nil;
   }
-  
-  // wrap it in a file handle so we can get messages from it
-  mSocketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor: fd
-                                                    closeOnDealloc: YES];
-  
-  // throw away our socket
-  CFSocketInvalidate(socket);
-  CFRelease(socket);
-  
-    // register for notifications of accepted incoming connections
-  [[NSNotificationCenter defaultCenter] addObserver: self
-                                           selector: @selector(connectionAccepted:)
-                                               name: NSFileHandleConnectionAcceptedNotification
-                                             object: mSocketFileHandle];
-  
-  // tell socket to listen
-  [mSocketFileHandle acceptConnectionInBackgroundAndNotify];
-  
-  NSLog(@"Listening on TCP port %d", port);
-  
+
+  if (self = [self initWithSocket:socket protocolFactory:protocolFactory processorFactory:processorFactory]) {
+    NSLog(@"TSocketServer: Listening on path %@", path);
+  }
   return self;
 }
 
-
-- (void) dealloc {
-  [[NSNotificationCenter defaultCenter] removeObserver:self];
-  [mInputProtocolFactory release_stub];
-  [mOutputProtocolFactory release_stub];
-  [mProcessorFactory release_stub];
-  [mSocketFileHandle release_stub];
-  [super dealloc_stub];
-}
-
-
-- (void) connectionAccepted: (NSNotification *) aNotification
++ (CFSocketRef) createSocketWithPath: (NSString *) path
 {
-  NSFileHandle * socket = [[aNotification userInfo] objectForKey: NSFileHandleNotificationFileHandleItem];
+  CFSocketRef socket = CFSocketCreate(kCFAllocatorDefault, PF_LOCAL, SOCK_STREAM, IPPROTO_IP, 0, NULL, NULL);
+  if (socket) {
+    CFSocketSetSocketFlags(socket,  CFSocketGetSocketFlags(socket) & ~kCFSocketCloseOnInvalidate);
+    int fd = CFSocketGetNative(socket);
+    int yes = 1;
+    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
 
-  // now that we have a client connected, spin off a thread to handle activity
-  [NSThread detachNewThreadSelector: @selector(handleClientConnection:)
-                           toTarget: self
-                         withObject: socket];
-
-  [[aNotification object] acceptConnectionInBackgroundAndNotify];
-}
-
-
-- (void) handleClientConnection: (NSFileHandle *) clientSocket
-{
-#if __has_feature(objc_arc)
-    @autoreleasepool {
-        TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
-        id<TProcessor> processor = [mProcessorFactory processorForTransport: transport];
-        
-        id <TProtocol> inProtocol = [mInputProtocolFactory newProtocolOnTransport: transport];
-        id <TProtocol> outProtocol = [mOutputProtocolFactory newProtocolOnTransport: transport];
-        
-        @try {
-            BOOL result = NO;
-            do {
-                @autoreleasepool {
-                    result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
-                }
-            } while (result);
-        }
-        @catch (TTransportException * te) {
-            //NSLog(@"Caught transport exception, abandoning client connection: %@", te);
-        }
-        
-        NSNotification * n = [NSNotification notificationWithName: kTSocketServer_ClientConnectionFinishedForProcessorNotification
-                                                           object: self
-                                                         userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
-                                                                    processor,
-                                                                    kTSocketServer_ProcessorKey,
-                                                                    transport,
-                                                                    kTSockerServer_TransportKey,
-                                                                    nil]];
-        [[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
-        
+    size_t nullTerminatedPathLength = path.length + 1;
+    struct sockaddr_un addr;
+    if (nullTerminatedPathLength> sizeof(addr.sun_path)) {
+      NSLog(@"TSocketServer: Unable to create socket at path %@. Path is too long.", path);
+      return NULL;
     }
-#else
-  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-  
-  TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
-  id<TProcessor> processor = [mProcessorFactory processorForTransport: transport];
-  
-  id <TProtocol> inProtocol = [[mInputProtocolFactory newProtocolOnTransport: transport] autorelease];
-  id <TProtocol> outProtocol = [[mOutputProtocolFactory newProtocolOnTransport: transport] autorelease];
 
-  @try {
-    BOOL result = NO;
-    do {
-      NSAutoreleasePool * myPool = [[NSAutoreleasePool alloc] init];
-      result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
-      [myPool release];
-    } while (result);
-  }
-  @catch (TTransportException * te) {
-    //NSLog(@"Caught transport exception, abandoning client connection: %@", te);
-  }
+    addr.sun_family = AF_LOCAL;
+    memcpy(addr.sun_path, path.UTF8String, nullTerminatedPathLength);
+    addr.sun_len = SUN_LEN(&addr);
 
-  NSNotification * n = [NSNotification notificationWithName: kTSocketServer_ClientConnectionFinishedForProcessorNotification
-                                                     object: self
-                                                   userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
-                                                              processor,
-                                                              kTSocketServer_ProcessorKey,
-                                                              transport,
-                                                              kTSockerServer_TransportKey,
-                                                              nil]];
-  [[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
-  
-  [pool release];
-#endif
+    NSData *address = [NSData dataWithBytes:&addr length:sizeof(addr)];
+    if (CFSocketSetAddress(socket, (__bridge CFDataRef)address) != kCFSocketSuccess) {
+      CFSocketInvalidate(socket);
+      CFRelease(socket);
+      NSLog(@"TSocketServer: Could not bind to address");
+      return NULL;
+    }
+
+    return socket;
+  } else {
+    NSLog(@"TSocketServer: No server socket");
+    return NULL;
+  }
+}
+
+-(void) dealloc
+{
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+  if (_domainSocketPath != nil) {
+    unlink(_domainSocketPath.UTF8String);
+  }
 }
 
 
+-(void) connectionAccepted:(NSNotification *)notification
+{
+  NSFileHandle *socket = [notification.userInfo objectForKey:NSFileHandleNotificationFileHandleItem];
+
+  // Now that we have a client connected, handle request on queue
+  dispatch_async(_processingQueue, ^{
+
+    [self handleClientConnection:socket];
+
+  });
+
+  // Continue accepting connections
+  [_socketFileHandle acceptConnectionInBackgroundAndNotify];
+}
+
+
+-(void) handleClientConnection:(NSFileHandle *)clientSocket
+{
+  @autoreleasepool {
+
+    TNSFileHandleTransport *transport = [[TNSFileHandleTransport alloc] initWithFileHandle:clientSocket];
+    id<TProcessor> processor = [_processorFactory processorForTransport:transport];
+
+    id <TProtocol> inProtocol = [_inputProtocolFactory newProtocolOnTransport:transport];
+    id <TProtocol> outProtocol = [_outputProtocolFactory newProtocolOnTransport:transport];
+
+    NSError *error;
+    if (![processor processOnInputProtocol:inProtocol outputProtocol:outProtocol error:&error]) {
+      // Handle error
+      NSLog(@"Error processing request: %@", error);
+    }
+
+    dispatch_async(dispatch_get_main_queue(), ^{
+
+      [NSNotificationCenter.defaultCenter postNotificationName:TSocketServerClientConnectionFinished
+                                                        object:self
+                                                      userInfo:@{TSocketServerProcessorKey: processor,
+                                                                 TSockerServerTransportKey: transport}];
+    });
+
+  }
+}
 
 @end
-
-
-
diff --git a/lib/cocoa/src/transport/TAsyncTransport.h b/lib/cocoa/src/transport/TAsyncTransport.h
new file mode 100644
index 0000000..bab4fbd
--- /dev/null
+++ b/lib/cocoa/src/transport/TAsyncTransport.h
@@ -0,0 +1,46 @@
+/*
+ * 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 "TTransport.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+@protocol TAsyncTransport;
+
+
+@protocol TAsyncTransportFactory <NSObject>
+
+-(id<TAsyncTransport>) newTransport;
+
+@end
+
+
+typedef void (^TAsyncCompletionBlock)();
+typedef void (^TAsyncFailureBlock)(NSError * __nonnull);
+
+
+@protocol TAsyncTransport <TTransport>
+
+-(void) flushWithCompletion:(TAsyncCompletionBlock)completed failure:(TAsyncFailureBlock)failure;
+
+@end
+
+
+NS_ASSUME_NONNULL_END
\ No newline at end of file
diff --git a/lib/cocoa/src/transport/TFramedTransport.h b/lib/cocoa/src/transport/TFramedTransport.h
index fc38877..ea68ac4 100644
--- a/lib/cocoa/src/transport/TFramedTransport.h
+++ b/lib/cocoa/src/transport/TFramedTransport.h
@@ -20,10 +20,14 @@
 #import <Foundation/Foundation.h>
 #import "TTransport.h"
 
-@interface TFramedTransport : NSObject <TTransport> {
-    id <TTransport> mTransport;
-}
+NS_ASSUME_NONNULL_BEGIN
 
-- (id) initWithTransport: (id <TTransport>) transport;
+
+@interface TFramedTransport : NSObject <TTransport>
+
+-(id) initWithTransport:(id <TTransport>)transport;
 
 @end
+
+
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/transport/TFramedTransport.m b/lib/cocoa/src/transport/TFramedTransport.m
index 085f9b6..4db65c4 100644
--- a/lib/cocoa/src/transport/TFramedTransport.m
+++ b/lib/cocoa/src/transport/TFramedTransport.m
@@ -18,109 +18,163 @@
  */
 
 #import "TFramedTransport.h"
-#import "TTransportException.h"
-#import "TObjective-C.h"
+#import "TTransportError.h"
 
 #define HEADER_SIZE 4
 #define INIT_FRAME_SIZE 1024
 
-@implementation TFramedTransport {
-    NSMutableData* writeBuffer;
-    NSMutableData* readBuffer;
-    NSUInteger readOffset;
-    uint8_t dummy_header[HEADER_SIZE];
-}
 
-- (id) initWithTransport:(id <TTransport>)transport
+@interface TFramedTransport ()
+
+@property(strong, nonatomic) id<TTransport> transport;
+@property(strong, nonatomic) NSMutableData *writeBuffer;
+@property(strong, nonatomic) NSMutableData *readBuffer;
+@property(assign, nonatomic) NSUInteger readOffset;
+
+@end
+
+
+@implementation TFramedTransport
+
+-(id) initWithTransport:(id <TTransport>)aTransport
 {
-    mTransport = [transport retain_stub];
-    readBuffer = nil;
-    readOffset = 0;
-    writeBuffer = [[NSMutableData alloc] initWithCapacity:INIT_FRAME_SIZE];
-    [writeBuffer appendBytes:dummy_header length:HEADER_SIZE];
-    return self;
+  if ((self = [self init])) {
+    _transport = aTransport;
+    _readBuffer = nil;
+    _readOffset = 0;
+    _writeBuffer = [NSMutableData dataWithLength:HEADER_SIZE];
+  }
+  return self;
 }
 
-- (void) dealloc
+-(BOOL) flush:(NSError **)error
 {
-    [mTransport release_stub];
-    [writeBuffer release_stub];
-    if (readBuffer != nil)
-        [readBuffer release_stub];
-    [super dealloc_stub];
-}
-
-- (void)flush
-{
-    int len = [writeBuffer length];
-    int data_len = len - HEADER_SIZE;
-    if (data_len < 0)
-        @throw [TTransportException exceptionWithReason:@"Framed transport buffer has no header"];
-
-    uint8_t i32rd[HEADER_SIZE];
-    i32rd[0] = (uint8_t)(0xff & (data_len >> 24));
-    i32rd[1] = (uint8_t)(0xff & (data_len >> 16));
-    i32rd[2] = (uint8_t)(0xff & (data_len >> 8));
-    i32rd[3] = (uint8_t)(0xff & (data_len));
-
-    // should we make a copy of the writeBuffer instead? Better for threaded operations!
-    [writeBuffer replaceBytesInRange:NSMakeRange(0, HEADER_SIZE) withBytes:i32rd length:HEADER_SIZE];
-    [mTransport write:[writeBuffer mutableBytes] offset:0 length:len];
-    [mTransport flush];
-
-    // reuse old memory buffer
-    [writeBuffer setLength:0];
-    [writeBuffer appendBytes:dummy_header length:HEADER_SIZE];
-}
-
-- (void)write:(const uint8_t *)data offset:(unsigned int)offset length:(unsigned int)length
-{
-    [writeBuffer appendBytes:data+offset length:length];
-}
-
-- (int)readAll:(uint8_t *)buf offset:(int)off length:(int)len {
-    if (readBuffer == nil) {
-        [self readFrame];
+  int len = (int)[_writeBuffer length];
+  int data_len = len - HEADER_SIZE;
+  if (data_len < 0) {
+    if (error) {
+      *error = [NSError errorWithDomain:TTransportErrorDomain
+                                   code:TTransportErrorUnknown
+                               userInfo:@{}];
     }
-    
-    if (readBuffer != nil) {
-        int buffer_len = [readBuffer length];
-        if (buffer_len-readOffset >= len) {
-            [readBuffer getBytes:buf range:NSMakeRange(readOffset,len)]; // copy data
-            readOffset += len;
-        } else {
-            // void the previous readBuffer data and request a new frame
-            [self readFrame];
-            [readBuffer getBytes:buf range:NSMakeRange(0,len)]; // copy data
-            readOffset = len;
-        }
-    }
-    return len;
+    return NO;
+  }
+
+  UInt8 i32rd[HEADER_SIZE];
+  i32rd[0] = (UInt8)(0xff & (data_len >> 24));
+  i32rd[1] = (UInt8)(0xff & (data_len >> 16));
+  i32rd[2] = (UInt8)(0xff & (data_len >> 8));
+  i32rd[3] = (UInt8)(0xff & (data_len));
+
+  // should we make a copy of the writeBuffer instead? Better for threaded
+  //  operations!
+  [_writeBuffer replaceBytesInRange:NSMakeRange(0, HEADER_SIZE)
+                          withBytes:i32rd length:HEADER_SIZE];
+
+  if (![_transport write:_writeBuffer.mutableBytes offset:0 length:len error:error]) {
+    return NO;
+  }
+
+  if (![_transport flush:error]) {
+    return NO;
+  }
+
+  _writeBuffer.length = HEADER_SIZE;
+
+  return YES;
 }
 
-- (void)readFrame
+-(BOOL) write:(const UInt8 *)data offset:(UInt32)offset length:(UInt32)length error:(NSError *__autoreleasing *)error
 {
-    uint8_t i32rd[HEADER_SIZE];
-    [mTransport readAll: i32rd offset: 0 length: HEADER_SIZE];
-    int size =
-        ((i32rd[0] & 0xff) << 24) |
-        ((i32rd[1] & 0xff) << 16) |
-        ((i32rd[2] & 0xff) <<  8) |
-        ((i32rd[3] & 0xff));
+  [_writeBuffer appendBytes:data+offset length:length];
 
-    if (readBuffer == nil) {
-        readBuffer = [[NSMutableData alloc] initWithLength:size];
-    } else {
-        int len = [readBuffer length];
-        if (len >= size) {
-            [readBuffer setLength:size];
-        } else {
-            // increase length of data buffer
-            [readBuffer increaseLengthBy:size-len];
-        }
+  return YES;
+}
+
+-(BOOL) readAll:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset length:(UInt32)length error:(NSError *__autoreleasing *)error
+{
+  UInt32 got = [self readAvail:outBuffer offset:outBufferOffset maxLength:length error:error];
+  if (got != length) {
+
+    // Report underflow only if readAvail didn't report error already
+    if (error && !*error) {
+      *error = [NSError errorWithDomain:TTransportErrorDomain
+                                   code:TTransportErrorEndOfFile
+                               userInfo:nil];
     }
-    // copy into internal memory buffer
-    [mTransport readAll:[readBuffer mutableBytes] offset:0 length:size];
+
+    return NO;
+  }
+
+  return YES;
+}
+
+-(UInt32) readAvail:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset maxLength:(UInt32)length error:(NSError *__autoreleasing *)error
+{
+  UInt32 got = 0;
+  while (got < length) {
+
+    NSUInteger avail = _readBuffer.length - _readOffset;
+    if (avail == 0) {
+      if (![self readFrame:error]) {
+        return 0;
+      }
+      avail = _readBuffer.length;
+    }
+
+    NSRange range;
+    range.location = _readOffset;
+    range.length = MIN(length - got, avail);
+
+    [_readBuffer getBytes:outBuffer+outBufferOffset+got range:range];
+    _readOffset += range.length;
+    got += range.length;
+  }
+
+  return got;
+}
+
+-(BOOL) readFrame:(NSError **)error
+{
+  UInt8 i32rd[HEADER_SIZE];
+  if (![_transport readAll:i32rd offset:0 length:HEADER_SIZE error:error]) {
+    return NO;
+  }
+
+  SInt32 size =
+    ((i32rd[0] & 0xff) << 24) |
+    ((i32rd[1] & 0xff) << 16) |
+    ((i32rd[2] & 0xff) <<  8) |
+    ((i32rd[3] & 0xff));
+
+  if (_readBuffer == nil) {
+
+    _readBuffer = [NSMutableData dataWithLength:size];
+
+  }
+  else {
+
+    SInt32 len = (SInt32)_readBuffer.length;
+    if (len >= size) {
+
+      _readBuffer.length = size;
+
+    }
+    else {
+
+      // increase length of data buffer
+      [_readBuffer increaseLengthBy:size-len];
+
+    }
+
+  }
+
+  // copy into internal memory buffer
+  if (![_transport readAll:_readBuffer.mutableBytes offset:0 length:size error:error]) {
+    return NO;
+  }
+
+  return YES;
 }
 
 @end
diff --git a/lib/cocoa/src/transport/THTTPClient.h b/lib/cocoa/src/transport/THTTPClient.h
deleted file mode 100644
index 4d57840..0000000
--- a/lib/cocoa/src/transport/THTTPClient.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import <Foundation/Foundation.h>
-#import "TTransport.h"
-
-@interface THTTPClient : NSObject <TTransport> {
-  NSURL * mURL;
-  NSMutableURLRequest * mRequest;
-  NSMutableData * mRequestData;
-  NSData * mResponseData;
-  int mResponseDataOffset;
-  NSString * mUserAgent;
-  int mTimeout;
-}
-
-- (id) initWithURL: (NSURL *) aURL;
-
-- (id) initWithURL: (NSURL *) aURL
-         userAgent: (NSString *) userAgent
-           timeout: (int) timeout;
-
-- (void) setURL: (NSURL *) aURL;
-
-@end
-
diff --git a/lib/cocoa/src/transport/THTTPClient.m b/lib/cocoa/src/transport/THTTPClient.m
deleted file mode 100644
index 5617d45..0000000
--- a/lib/cocoa/src/transport/THTTPClient.m
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import "THTTPClient.h"
-#import "TTransportException.h"
-#import "TObjective-C.h"
-
-@implementation THTTPClient
-
-
-- (void) setupRequest
-{
-  if (mRequest != nil) {
-    [mRequest release_stub];
-  }
-
-  // set up our request object that we'll use for each request
-  mRequest = [[NSMutableURLRequest alloc] initWithURL: mURL];
-  [mRequest setHTTPMethod: @"POST"];
-  [mRequest setValue: @"application/x-thrift" forHTTPHeaderField: @"Content-Type"];
-  [mRequest setValue: @"application/x-thrift" forHTTPHeaderField: @"Accept"];
-
-  NSString * userAgent = mUserAgent;
-  if (!userAgent) {
-    userAgent = @"Cocoa/THTTPClient";
-  }
-  [mRequest setValue: userAgent forHTTPHeaderField: @"User-Agent"];
-
-  [mRequest setCachePolicy: NSURLRequestReloadIgnoringCacheData];
-  if (mTimeout) {
-    [mRequest setTimeoutInterval: mTimeout];
-  }
-}
-
-
-- (id) initWithURL: (NSURL *) aURL
-{
-  return [self initWithURL: aURL
-                 userAgent: nil
-                   timeout: 0];
-}
-
-
-- (id) initWithURL: (NSURL *) aURL
-         userAgent: (NSString *) userAgent
-           timeout: (int) timeout
-{
-  self = [super init];
-  if (!self) {
-    return nil;
-  }
-
-  mTimeout = timeout;
-  if (userAgent) {
-    mUserAgent = [userAgent retain_stub];
-  }
-  mURL = [aURL retain_stub];
-
-  [self setupRequest];
-
-  // create our request data buffer
-  mRequestData = [[NSMutableData alloc] initWithCapacity: 1024];
-
-  return self;
-}
-
-
-- (void) setURL: (NSURL *) aURL
-{
-  [aURL retain_stub];
-  [mURL release_stub];
-  mURL = aURL;
-
-  [self setupRequest];
-}
-
-
-- (void) dealloc
-{
-  [mURL release_stub];
-  [mUserAgent release_stub];
-  [mRequest release_stub];
-  [mRequestData release_stub];
-  [mResponseData release_stub];
-  [super dealloc_stub];
-}
-
-
-- (int) readAll: (uint8_t *) buf offset: (int) off length: (int) len
-{
-  NSRange r;
-  r.location = mResponseDataOffset;
-  r.length = len;
-
-  [mResponseData getBytes: buf+off range: r];
-  mResponseDataOffset += len;
-
-  return len;
-}
-
-
-- (void) write: (const uint8_t *) data offset: (unsigned int) offset length: (unsigned int) length
-{
-  [mRequestData appendBytes: data+offset length: length];
-}
-
-
-- (void) flush
-{
-  [mRequest setHTTPBody: mRequestData]; // not sure if it copies the data
-
-  // make the HTTP request
-  NSURLResponse * response;
-  NSError * error;
-  NSData * responseData =
-    [NSURLConnection sendSynchronousRequest: mRequest returningResponse: &response error: &error];
-
-  [mRequestData setLength: 0];
-
-  if (responseData == nil) {
-    @throw [TTransportException exceptionWithName: @"TTransportException"
-                                reason: @"Could not make HTTP request"
-                                error: error];
-  }
-  if (![response isKindOfClass: [NSHTTPURLResponse class]]) {
-    @throw [TTransportException exceptionWithName: @"TTransportException"
-                                           reason: [NSString stringWithFormat: @"Unexpected NSURLResponse type: %@",
-                                                    NSStringFromClass([response class])]];
-  }
-
-  NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *) response;
-  if ([httpResponse statusCode] != 200) {
-    @throw [TTransportException exceptionWithName: @"TTransportException"
-                                           reason: [NSString stringWithFormat: @"Bad response from HTTP server: %d",
-                                                    [httpResponse statusCode]]];
-  }
-
-  // phew!
-  [mResponseData release_stub];
-  mResponseData = [responseData retain_stub];
-  mResponseDataOffset = 0;
-}
-
-
-@end
diff --git a/lib/cocoa/src/transport/THTTPSessionTransport.h b/lib/cocoa/src/transport/THTTPSessionTransport.h
new file mode 100644
index 0000000..003499b
--- /dev/null
+++ b/lib/cocoa/src/transport/THTTPSessionTransport.h
@@ -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.
+ */
+
+#import <Foundation/Foundation.h>
+#import "TAsyncTransport.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+typedef NSError *__nullable (^THTTPSessionTransportResponseValidateBlock) (NSHTTPURLResponse *response, NSData *responseData);
+
+
+@interface THTTPSessionTransportFactory : NSObject<TAsyncTransportFactory>
+
+@property (strong, nonatomic) THTTPSessionTransportResponseValidateBlock responseValidate;
+
++(void) setupDefaultsForSessionConfiguration:(NSURLSessionConfiguration *)config
+                            withProtocolName:(NSString *)protocolName;
+
+-(id) initWithSession:(NSURLSession *)session
+                  URL:(NSURL *)aURL;
+
+@end
+
+
+@interface THTTPSessionTransport : NSObject <TAsyncTransport>
+
+@end
+
+
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/transport/THTTPSessionTransport.m b/lib/cocoa/src/transport/THTTPSessionTransport.m
new file mode 100644
index 0000000..c10b7fc
--- /dev/null
+++ b/lib/cocoa/src/transport/THTTPSessionTransport.m
@@ -0,0 +1,268 @@
+/*
+ * 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 "THTTPSessionTransport.h"
+#import "TTransportError.h"
+
+
+@interface THTTPSessionTransportFactory ()
+
+@property (strong, nonatomic) NSURLSession *session;
+@property (strong, nonatomic) NSURL *url;
+
+@end
+
+
+@interface THTTPSessionTransport ()
+
+@property (strong, nonatomic) THTTPSessionTransportFactory *factory;
+@property (strong, nonatomic) NSMutableData *requestData;
+@property (strong, nonatomic) NSData *responseData;
+@property (assign, nonatomic) NSUInteger responseDataOffset;
+
+-(instancetype) initWithFactory:(THTTPSessionTransportFactory *)factory;
+
+@end
+
+
+@implementation THTTPSessionTransportFactory
+
++(void) setupDefaultsForSessionConfiguration:(NSURLSessionConfiguration *)config withProtocolName:(NSString *)protocolName
+{
+  NSString *thriftContentType = @"application/x-thrift";
+  if (protocolName.length) {
+    thriftContentType = [thriftContentType stringByAppendingFormat:@"; p=%@", protocolName];
+  }
+
+  config.requestCachePolicy = NSURLRequestReloadIgnoringCacheData;
+  config.HTTPShouldUsePipelining = YES;
+  config.HTTPShouldSetCookies = NO;
+  config.URLCache = nil;
+  config.HTTPAdditionalHeaders = @{@"Content-Type":thriftContentType,
+                                   @"Accept":thriftContentType,
+                                   @"User-Agent":@"Thrift/Cocoa (Session)"};
+}
+
+
+-(id) initWithSession:(NSURLSession *)session URL:(NSURL *)url
+{
+  self = [super init];
+  if (self) {
+    _session = session;
+    _url = url;
+  }
+
+  return self;
+}
+
+-(id<TAsyncTransport>) newTransport
+{
+  return [[THTTPSessionTransport alloc] initWithFactory:self];
+}
+
+-(NSURLSessionDataTask *) taskWithRequest:(NSURLRequest *)request
+                        completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler
+                                    error:(NSError *__autoreleasing *)error
+{
+  NSURLSessionDataTask *newTask = [_session dataTaskWithRequest:request completionHandler:completionHandler];
+  if (!newTask) {
+    if (error) {
+      *error = [NSError errorWithDomain:TTransportErrorDomain
+                                   code:TTransportErrorUnknown
+                               userInfo:@{NSLocalizedDescriptionKey:@"Failed to create session data task"}];
+    }
+    return nil;
+  }
+
+  return newTask;
+}
+
+-(NSError *) validateResponse:(NSHTTPURLResponse *)response data:(NSData *)data
+{
+  if (_responseValidate) {
+    return _responseValidate(response, data);
+  }
+  return nil;
+}
+
+@end
+
+
+
+@implementation THTTPSessionTransport
+
+-(instancetype) initWithFactory:(THTTPSessionTransportFactory *)factory
+{
+  self = [super init];
+  if (self) {
+    _factory = factory;
+  }
+  return self;
+}
+
+-(BOOL) readAll:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset length:(UInt32)length error:(NSError *__autoreleasing *)error
+{
+  UInt32 got = [self readAvail:outBuffer offset:outBufferOffset maxLength:length error:error];
+  if (got != length) {
+
+    // Report underflow only if readAvail didn't report error already
+    if (error && !*error) {
+      *error = [NSError errorWithDomain:TTransportErrorDomain
+                                   code:TTransportErrorEndOfFile
+                               userInfo:nil];
+    }
+
+    return NO;
+  }
+
+  return YES;
+}
+
+-(UInt32) readAvail:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset maxLength:(UInt32)maxLength error:(NSError *__autoreleasing *)error
+{
+  NSUInteger avail = _responseData.length - _responseDataOffset;
+
+  NSRange range;
+  range.location = _responseDataOffset;
+  range.length = MIN(maxLength, avail);
+
+  [_responseData getBytes:outBuffer+outBufferOffset range:range];
+  _responseDataOffset += range.length;
+
+  return (UInt32)range.length;
+}
+
+-(BOOL) write:(const UInt8 *)data offset:(UInt32)offset length:(UInt32)length error:(NSError *__autoreleasing *)error
+{
+  if (!_requestData) {
+    _requestData = [NSMutableData dataWithCapacity:256];
+  }
+
+  [_requestData appendBytes:data+offset length:length];
+
+  return YES;
+}
+
+-(void) flushWithCompletion:(TAsyncCompletionBlock)completed failure:(TAsyncFailureBlock)failure
+{
+  NSError *error;
+
+  NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:_factory.url];
+  request.HTTPMethod = @"POST";
+  request.HTTPBody = _requestData;
+
+  _requestData = nil;
+
+  NSURLSessionDataTask *task = [_factory taskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+
+    // Check response type
+    if (!error && ![response isKindOfClass:NSHTTPURLResponse.class]) {
+
+      error = [NSError errorWithDomain:TTransportErrorDomain
+                                   code:TTransportErrorUnknown
+                               userInfo:@{TTransportErrorHttpErrorKey: @(THttpTransportErrorInvalidResponse)}];
+
+    }
+
+    // Check status code
+    NSHTTPURLResponse *httpResponse = (id)response;
+    if (!error && httpResponse.statusCode != 200) {
+
+      THttpTransportError code;
+      if (httpResponse.statusCode == 401) {
+        code = THttpTransportErrorAuthentication;
+      }
+      else {
+        code = THttpTransportErrorInvalidStatus;
+      }
+
+      error = [NSError errorWithDomain:TTransportErrorDomain
+                                  code:TTransportErrorUnknown
+                              userInfo:@{TTransportErrorHttpErrorKey: @(code),
+                                         @"statusCode":@(httpResponse.statusCode)}];
+    }
+
+    // Allow factory to check
+    if (!error) {
+      error = [_factory validateResponse:httpResponse data:data];
+    }
+
+    _responseDataOffset = 0;
+
+    if (error) {
+
+      _responseData = nil;
+
+      failure(error);
+
+    }
+    else {
+
+      if (data == nil) {
+        data = [NSData data];
+      }
+
+      _responseData = data;
+
+      completed(self);
+    }
+
+  } error:&error];
+
+  if (!task) {
+    failure(error);
+    return;
+  }
+
+  [task resume];
+}
+
+-(BOOL) flush:(NSError *__autoreleasing *)error
+{
+  dispatch_semaphore_t completed = dispatch_semaphore_create(0);
+
+  __block BOOL result;
+  __block NSError *internalError;
+
+  [self flushWithCompletion:^(id < TAsyncTransport > transport) {
+
+    result = YES;
+
+    dispatch_semaphore_signal(completed);
+
+  } failure:^(NSError *error) {
+
+    internalError = error;
+
+    result = NO;
+
+    dispatch_semaphore_signal(completed);
+
+  }];
+
+  dispatch_semaphore_wait(completed, DISPATCH_TIME_FOREVER);
+
+  if (error) {
+    *error = internalError;
+  }
+
+  return result;
+}
+
+@end
diff --git a/lib/cocoa/src/transport/THTTPTransport.h b/lib/cocoa/src/transport/THTTPTransport.h
new file mode 100644
index 0000000..3c35daf
--- /dev/null
+++ b/lib/cocoa/src/transport/THTTPTransport.h
@@ -0,0 +1,39 @@
+/*
+ * 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 <Foundation/Foundation.h>
+#import "TTransport.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+@interface THTTPTransport : NSObject <TTransport>
+
+-(id) initWithURL:(NSURL *)aURL;
+
+-(id) initWithURL:(NSURL *)aURL
+        userAgent:(nullable NSString *)userAgent
+          timeout:(int)timeout;
+
+-(void) setURL:(NSURL *)aURL;
+
+@end
+
+
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/transport/THTTPTransport.m b/lib/cocoa/src/transport/THTTPTransport.m
new file mode 100644
index 0000000..e4046c6
--- /dev/null
+++ b/lib/cocoa/src/transport/THTTPTransport.m
@@ -0,0 +1,182 @@
+/*
+ * 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 "THTTPTransport.h"
+#import "TTransportError.h"
+
+
+@interface THTTPTransport ()
+
+@property (strong, nonatomic) NSURL *url;
+@property (strong, nonatomic) NSMutableURLRequest *request;
+@property (strong, nonatomic) NSMutableData *requestData;
+@property (strong, nonatomic) NSData *responseData;
+@property (assign, nonatomic) NSUInteger responseDataOffset;
+@property (strong, nonatomic) NSString *userAgent;
+@property (assign, nonatomic) NSTimeInterval timeout;
+
+@end
+
+
+@implementation THTTPTransport
+
+-(void) setupRequest
+{
+  // set up our request object that we'll use for each request
+  _request = [[NSMutableURLRequest alloc] initWithURL:_url];
+  [_request setHTTPMethod:@"POST"];
+  [_request setValue:@"application/x-thrift" forHTTPHeaderField:@"Content-Type"];
+  [_request setValue:@"application/x-thrift" forHTTPHeaderField:@"Accept"];
+
+  NSString *userAgent = _userAgent;
+  if (!userAgent) {
+    userAgent = @"Thrift/Cocoa";
+  }
+  [_request setValue:userAgent forHTTPHeaderField:@"User-Agent"];
+
+  [_request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
+  if (_timeout) {
+    [_request setTimeoutInterval:_timeout];
+  }
+}
+
+
+-(id) initWithURL:(NSURL *)aURL
+{
+  return [self initWithURL:aURL
+                 userAgent:nil
+                   timeout:0];
+}
+
+
+-(id) initWithURL:(NSURL *)aURL
+        userAgent:(NSString *)aUserAgent
+          timeout:(int)aTimeout
+{
+  self = [super init];
+  if (!self) {
+    return nil;
+  }
+
+  _timeout = aTimeout;
+  _userAgent = aUserAgent;
+  _url = aURL;
+
+  [self setupRequest];
+
+  // create our request data buffer
+  _requestData = [[NSMutableData alloc] initWithCapacity:1024];
+
+  return self;
+}
+
+-(void) setURL:(NSURL *)aURL
+{
+  _url = aURL;
+
+  [self setupRequest];
+}
+
+-(BOOL) readAll:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset length:(UInt32)length error:(NSError *__autoreleasing *)error
+{
+  UInt32 got = [self readAvail:outBuffer offset:outBufferOffset maxLength:length error:error];
+  if (got != length) {
+
+    // Report underflow only if readAvail didn't report error already
+    if (error && !*error) {
+      *error = [NSError errorWithDomain:TTransportErrorDomain
+                                   code:TTransportErrorEndOfFile
+                               userInfo:nil];
+    }
+
+    return NO;
+  }
+
+  return YES;
+}
+
+-(UInt32) readAvail:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset maxLength:(UInt32)maxLength error:(NSError *__autoreleasing *)error
+{
+  NSUInteger avail = _responseData.length - _responseDataOffset;
+
+  NSRange range;
+  range.location = _responseDataOffset;
+  range.length = MIN(maxLength, avail);
+
+  [_responseData getBytes:outBuffer+outBufferOffset range:range];
+  _responseDataOffset += range.length;
+
+  return (UInt32)range.length;
+}
+
+-(BOOL) write:(const UInt8 *)data offset:(UInt32)offset length:(UInt32)length error:(NSError *__autoreleasing *)error
+{
+  [_requestData appendBytes:data+offset length:length];
+
+  return YES;
+}
+
+-(BOOL) flush:(NSError *__autoreleasing *)error
+{
+  [_request setHTTPBody:_requestData];
+
+  _responseDataOffset = 0;
+
+  // make the HTTP request
+  NSURLResponse *response;
+  _responseData = [NSURLConnection sendSynchronousRequest:_request returningResponse:&response error:error];
+  if (!_responseData) {
+    return NO;
+  }
+
+  [_requestData setLength:0];
+
+  if (![response isKindOfClass:NSHTTPURLResponse.class]) {
+    if (error) {
+      *error = [NSError errorWithDomain:TTransportErrorDomain
+                                   code:TTransportErrorUnknown
+                               userInfo:@{TTransportErrorHttpErrorKey: @(THttpTransportErrorInvalidResponse)}];
+    }
+    return NO;
+  }
+
+  NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
+  if ([httpResponse statusCode] != 200) {
+    if (error) {
+
+      THttpTransportError code;
+      if (httpResponse.statusCode == 401) {
+        code = THttpTransportErrorAuthentication;
+      }
+      else {
+        code = THttpTransportErrorInvalidStatus;
+      }
+
+      *error = [NSError errorWithDomain:TTransportErrorDomain
+                                   code:TTransportErrorUnknown
+                               userInfo:@{TTransportErrorHttpErrorKey: @(code),
+                                          @"statusCode":@(httpResponse.statusCode)}];
+    }
+    return NO;
+  }
+
+  return YES;
+}
+
+@end
diff --git a/lib/cocoa/src/transport/TMemoryBuffer.h b/lib/cocoa/src/transport/TMemoryBuffer.h
index fa4d371..6249d32 100644
--- a/lib/cocoa/src/transport/TMemoryBuffer.h
+++ b/lib/cocoa/src/transport/TMemoryBuffer.h
@@ -20,10 +20,18 @@
 #import <Foundation/Foundation.h>
 #import "TTransport.h"
 
-@interface TMemoryBuffer : NSObject <TTransport> {
-	NSMutableData *mBuffer;
-	NSUInteger mOffset;
-}
-- (id)initWithData:(NSData *)data;
-- (NSData *)getBuffer;
+NS_ASSUME_NONNULL_BEGIN
+
+
+@interface TMemoryBuffer : NSObject <TTransport>
+
+-(NSData *) buffer;
+
+-(id) initWithData:(NSData *)data;
+
+-(id) initWithDataNoCopy:(NSMutableData *)data;
+
 @end
+
+
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/transport/TMemoryBuffer.m b/lib/cocoa/src/transport/TMemoryBuffer.m
index c3801c7..ec19cc8 100644
--- a/lib/cocoa/src/transport/TMemoryBuffer.m
+++ b/lib/cocoa/src/transport/TMemoryBuffer.m
@@ -18,55 +18,104 @@
  */
 
 #import "TMemoryBuffer.h"
-#import "TTransportException.h"
-#import "TObjective-C.h"
+#import "TTransportError.h"
+
 
 #define GARBAGE_BUFFER_SIZE 4096 // 4KiB
 
+
+@interface TMemoryBuffer ()
+
+@property(strong, nonatomic) NSMutableData *buffer;
+@property(assign, nonatomic) UInt32 bufferOffset;
+
+@end
+
+
 @implementation TMemoryBuffer
-- (id)init {
-	if (self = [super init]) {
-		mBuffer = [[NSMutableData alloc] init];
-		mOffset = 0;
-	}
-	return self;
+
+-(id) init
+{
+  if ((self = [super init])) {
+    _buffer = [NSMutableData new];
+    _bufferOffset = 0;
+  }
+  return self;
 }
 
-- (id)initWithData:(NSData *)data {
-	if (self = [super init]) {
-		mBuffer = [data mutableCopy];
-		mOffset = 0;
-	}
-	return self;
+-(id) initWithData:(NSData *)data
+{
+  if (self = [super init]) {
+    _buffer = [data mutableCopy];
+    _bufferOffset = 0;
+  }
+  return self;
 }
 
-- (int)readAll:(uint8_t *)buf offset:(int)off length:(int)len {
-	if ([mBuffer length] - mOffset < len) {
-		@throw [TTransportException exceptionWithReason:@"Not enough bytes remain in buffer"];
-	}
-	[mBuffer getBytes:buf range:NSMakeRange(mOffset, len)];
-	mOffset += len;
-	if (mOffset >= GARBAGE_BUFFER_SIZE) {
-		[mBuffer replaceBytesInRange:NSMakeRange(0, mOffset) withBytes:NULL length:0];
-		mOffset = 0;
-	}
-	return len;
+-(id) initWithDataNoCopy:(NSMutableData *)data
+{
+  if (self = [super init]) {
+    _buffer = data;
+    _bufferOffset = 0;
+  }
+  return self;
 }
 
-- (void)write:(const uint8_t *)data offset:(unsigned int)offset length:(unsigned int)length {
-	[mBuffer appendBytes:data+offset length:length];
+-(BOOL) readAll:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset length:(UInt32)length error:(NSError *__autoreleasing *)error
+{
+  UInt32 got = [self readAvail:outBuffer offset:outBufferOffset maxLength:length error:error];
+  if (got != length) {
+
+    // Report underflow only if readAvail didn't report error already
+    if (error && !*error) {
+      *error = [NSError errorWithDomain:TTransportErrorDomain
+                                   code:TTransportErrorEndOfFile
+                               userInfo:nil];
+    }
+
+    return NO;
+  }
+
+  return YES;
 }
 
-- (void)flush {
-	// noop
+-(UInt32) readAvail:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset maxLength:(UInt32)maxLength error:(NSError *__autoreleasing *)error
+{
+  UInt32 avail = (UInt32)_buffer.length - _bufferOffset;
+  if (avail == 0) {
+    return 0;
+  }
+
+  NSRange range;
+  range.location = _bufferOffset;
+  range.length = MIN(maxLength, avail);
+
+  [_buffer getBytes:outBuffer + outBufferOffset range:range];
+  _bufferOffset += range.length;
+
+  if (_bufferOffset >= GARBAGE_BUFFER_SIZE) {
+    [_buffer replaceBytesInRange:NSMakeRange(0, _bufferOffset) withBytes:NULL length:0];
+    _bufferOffset = 0;
+  }
+
+  return (UInt32)range.length;
 }
 
-- (NSData *)getBuffer {
-	return [[mBuffer copy] autorelease_stub];
+-(BOOL) write:(const UInt8 *)inBuffer offset:(UInt32)inBufferOffset length:(UInt32)length error:(NSError *__autoreleasing *)error
+{
+  [_buffer appendBytes:inBuffer + inBufferOffset length:length];
+
+  return YES;
 }
 
-- (void)dealloc {
-	[mBuffer release_stub];
-	[super dealloc_stub];
+-(NSData *) buffer
+{
+  return _buffer;
 }
+
+-(BOOL) flush:(NSError *__autoreleasing *)error
+{
+  return YES;
+}
+
 @end
diff --git a/lib/cocoa/src/transport/TNSFileHandleTransport.h b/lib/cocoa/src/transport/TNSFileHandleTransport.h
index ba2a209..db6edf3 100644
--- a/lib/cocoa/src/transport/TNSFileHandleTransport.h
+++ b/lib/cocoa/src/transport/TNSFileHandleTransport.h
@@ -21,15 +21,18 @@
 #import <Foundation/Foundation.h>
 #import "TTransport.h"
 
-@interface TNSFileHandleTransport : NSObject <TTransport> {
-  NSFileHandle * mInputFileHandle;
-  NSFileHandle * mOutputFileHandle;
-}
+NS_ASSUME_NONNULL_BEGIN
 
-- (id) initWithFileHandle: (NSFileHandle *) fileHandle;
 
-- (id) initWithInputFileHandle: (NSFileHandle *) inputFileHandle
-              outputFileHandle: (NSFileHandle *) outputFileHandle;
+@interface TNSFileHandleTransport : NSObject <TTransport>
+
+-(id) initWithFileHandle:(NSFileHandle *)fileHandle;
+
+-(id) initWithInputFileHandle:(NSFileHandle *)inputFileHandle
+             outputFileHandle:(NSFileHandle *)outputFileHandle;
 
 
 @end
+
+
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/transport/TNSFileHandleTransport.m b/lib/cocoa/src/transport/TNSFileHandleTransport.m
index 0ff200b..c907f87 100644
--- a/lib/cocoa/src/transport/TNSFileHandleTransport.m
+++ b/lib/cocoa/src/transport/TNSFileHandleTransport.m
@@ -19,75 +19,100 @@
 
 
 #import "TNSFileHandleTransport.h"
-#import "TTransportException.h"
-#import "TObjective-C.h"
+#import "TTransportError.h"
+
+
+@interface TNSFileHandleTransport ()
+
+@property(strong, nonatomic) NSFileHandle *inputFileHandle;
+@property(strong, nonatomic) NSFileHandle *outputFileHandle;
+
+@end
 
 
 @implementation TNSFileHandleTransport
 
-- (id) initWithFileHandle: (NSFileHandle *) fileHandle
+-(id) initWithFileHandle:(NSFileHandle *)fileHandle
 {
-  return [self initWithInputFileHandle: fileHandle
-                      outputFileHandle: fileHandle];
+  return [self initWithInputFileHandle:fileHandle
+                      outputFileHandle:fileHandle];
 }
 
 
-- (id) initWithInputFileHandle: (NSFileHandle *) inputFileHandle
-              outputFileHandle: (NSFileHandle *) outputFileHandle
+-(id) initWithInputFileHandle:(NSFileHandle *)aInputFileHandle
+             outputFileHandle:(NSFileHandle *)aOutputFileHandle
 {
   self = [super init];
-
-  mInputFileHandle = [inputFileHandle retain_stub];
-  mOutputFileHandle = [outputFileHandle retain_stub];
-
+  if (self) {
+    _inputFileHandle = aInputFileHandle;
+    _outputFileHandle = aOutputFileHandle;
+  }
   return self;
 }
 
 
-- (void) dealloc {
-  [mInputFileHandle release_stub];
-  [mOutputFileHandle release_stub];
-  [super dealloc_stub];
+-(BOOL) readAll:(UInt8 *)buf offset:(UInt32)off length:(UInt32)len error:(NSError *__autoreleasing *)error
+{
+  UInt32 got = 0;
+  while (got < len) {
+
+    NSData *d = [_inputFileHandle readDataOfLength:len-got];
+    if (d.length == 0) {
+      if (error) {
+        *error = [NSError errorWithDomain:TTransportErrorDomain
+                                     code:TTransportErrorEndOfFile
+                                 userInfo:nil];
+      }
+      return NO;
+    }
+
+    [d getBytes:buf+got length:d.length];
+    got += d.length;
+  }
+  return YES;
 }
 
 
-- (int) readAll: (uint8_t *) buf offset: (int) off length: (int) len
+-(UInt32) readAvail:(UInt8 *)buf offset:(UInt32)off maxLength:(UInt32)len error:(NSError *__autoreleasing *)error
 {
-  int got = 0;
+  UInt32 got = 0;
   while (got < len) {
-    NSData * d = [mInputFileHandle readDataOfLength: len-got];
-    if ([d length] == 0) {
-      @throw [TTransportException exceptionWithName: @"TTransportException"
-                                  reason: @"Cannot read. No more data."];
+
+    NSData *d = [_inputFileHandle readDataOfLength:len-got];
+    if (d.length == 0) {
+      break;
     }
-    [d getBytes: buf+got];
-    got += [d length];
+
+    [d getBytes:buf+got length:d.length];
+    got += d.length;
   }
   return got;
 }
 
 
-- (void) write: (const uint8_t *) data offset: (unsigned int) offset length: (unsigned int) length
+-(BOOL) write:(const UInt8 *)data offset:(UInt32)offset length:(UInt32)length error:(NSError *__autoreleasing *)error
 {
-  void *pos = (void *) data + offset;
-  NSData * dataObject = [[NSData alloc] initWithBytesNoCopy: pos // data+offset
-                                                     length: length
-                                               freeWhenDone: NO];
+  void *pos = (void *)data + offset;
 
   @try {
-    [mOutputFileHandle writeData: dataObject];
-  } @catch (NSException * e) {
-    @throw [TTransportException exceptionWithName: @"TTransportException"
-                                           reason: [NSString stringWithFormat: @"%s: Unable to write data: %@", __PRETTY_FUNCTION__, e]];
+    [_outputFileHandle writeData:[NSData dataWithBytesNoCopy:pos length:length freeWhenDone:NO]];
+  }
+  @catch (NSException *e) {
+    if (error) {
+      *error = [NSError errorWithDomain:TTransportErrorDomain
+                                   code:TTransportErrorNotOpen
+                               userInfo:@{}];
+    }
+    return NO;
   }
 
-  [dataObject release_stub];
+  return YES;
 }
 
 
-- (void) flush
+-(BOOL) flush:(NSError *__autoreleasing *)error
 {
-
+  return YES;
 }
 
 @end
diff --git a/lib/cocoa/src/transport/TNSStreamTransport.h b/lib/cocoa/src/transport/TNSStreamTransport.h
index d7be40b..54c4884 100644
--- a/lib/cocoa/src/transport/TNSStreamTransport.h
+++ b/lib/cocoa/src/transport/TNSStreamTransport.h
@@ -20,19 +20,24 @@
 #import <Foundation/Foundation.h>
 #import "TTransport.h"
 
-@interface TNSStreamTransport : NSObject <TTransport> {
-  NSInputStream * mInput;
-  NSOutputStream * mOutput;
-}
+NS_ASSUME_NONNULL_BEGIN
 
-- (id) initWithInputStream: (NSInputStream *) input
-              outputStream: (NSOutputStream *) output;
 
-- (id) initWithInputStream: (NSInputStream *) input;
+@interface TNSStreamTransport : NSObject <TTransport>
 
-- (id) initWithOutputStream: (NSOutputStream *) output;
+@property (strong, nonatomic) NSInputStream *input;
+@property (strong, nonatomic) NSOutputStream *output;
+
+-(id) initWithInputStream:(nullable NSInputStream *)input
+             outputStream:(nullable NSOutputStream *)output;
+
+-(id) initWithInputStream:(NSInputStream *)input;
+
+-(id) initWithOutputStream:(NSOutputStream *)output;
+
+-(void) close;
 
 @end
 
 
-
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/transport/TNSStreamTransport.m b/lib/cocoa/src/transport/TNSStreamTransport.m
index 265e0ba..18c41d3 100644
--- a/lib/cocoa/src/transport/TNSStreamTransport.m
+++ b/lib/cocoa/src/transport/TNSStreamTransport.m
@@ -18,73 +18,136 @@
  */
 
 #import "TNSStreamTransport.h"
-#import "TTransportException.h"
-#import "TObjective-C.h"
+#import "TTransportError.h"
+
+
+@interface TNSStreamTransport ()
+@end
 
 
 @implementation TNSStreamTransport
 
-- (id) initWithInputStream: (NSInputStream *) input
-              outputStream: (NSOutputStream *) output
+-(id) initWithInputStream:(NSInputStream *)input
+             outputStream:(NSOutputStream *)output
 {
   self = [super init];
-  mInput = [input retain_stub];
-  mOutput = [output retain_stub];
+  if (self) {
+    _input = input;
+    _output = output;
+  }
   return self;
 }
 
-- (id) initWithInputStream: (NSInputStream *) input
+-(id) initWithInputStream:(NSInputStream *)input
 {
-  return [self initWithInputStream: input outputStream: nil];
+  return [self initWithInputStream:input outputStream:nil];
 }
 
-- (id) initWithOutputStream: (NSOutputStream *) output
+-(id) initWithOutputStream:(NSOutputStream *)output
 {
-  return [self initWithInputStream: nil outputStream: output];
+  return [self initWithInputStream:nil outputStream:output];
 }
 
-- (void) dealloc
+-(void) dealloc
 {
-  [mInput release_stub];
-  [mOutput release_stub];
-  [super dealloc_stub];
+  [self close];
 }
 
-
-- (int) readAll: (uint8_t *) buf offset: (int) off length: (int) len
+-(BOOL) readAll:(UInt8 *)buf offset:(UInt32)off length:(UInt32)len error:(NSError *__autoreleasing *)error
 {
-  int got = 0;
-  int ret = 0;
+  UInt32 got = 0;
   while (got < len) {
-    ret = [mInput read: buf+off+got maxLength: len-got];
-    if (ret <= 0) {
-      @throw [TTransportException exceptionWithReason: @"Cannot read. Remote side has closed."];
+
+    UInt32 read = (UInt32)[_input read:buf+off+got maxLength:len-got];
+    if (read <= 0) {
+      if (error) {
+        *error = [NSError errorWithDomain:TTransportErrorDomain
+                                     code:TTransportErrorNotOpen
+                                 userInfo:@{}];
+      }
+      return NO;
     }
-    got += ret;
+
+    got += read;
   }
+
+  return YES;
+}
+
+
+-(UInt32) readAvail:(UInt8 *)buf offset:(UInt32)off maxLength:(UInt32)len error:(NSError *__autoreleasing *)error
+{
+  UInt32 got = 0;
+  while (got < len) {
+
+    UInt32 read = (UInt32)[_input read:buf+off+got maxLength:len-got];
+    if (read <= 0) {
+      break;
+    }
+
+    got += read;
+  }
+
   return got;
 }
 
 
-- (void) write: (const uint8_t *) data offset: (unsigned int) offset length: (unsigned int) length
+-(BOOL) write:(const UInt8 *)data offset:(UInt32)offset length:(UInt32)length error:(NSError *__autoreleasing *)error
 {
-  int got = 0;
-  int result = 0;
+  UInt32 got = 0;
+  NSInteger total = 0;
   while (got < length) {
-    result = [mOutput write: data+offset+got maxLength: length-got];
-    if (result == -1) {
-      @throw [TTransportException exceptionWithReason: @"Error writing to transport output stream."
-                                                error: [mOutput streamError]];
-    } else if (result == 0) {
-      @throw [TTransportException exceptionWithReason: @"End of output stream."];
+
+    total = [_output write:data+offset+got maxLength:length-got];
+    if (total == -1) {
+      if (error) {
+        *error = [NSError errorWithDomain:TTransportErrorDomain
+                                     code:TTransportErrorNotOpen
+                                 userInfo:@{}];
+      }
+      return NO;
     }
-    got += result;
+    else if (total == 0) {
+      if (error) {
+        *error = [NSError errorWithDomain:TTransportErrorDomain
+                                     code:TTransportErrorEndOfFile
+                                 userInfo:@{}];
+      }
+      return NO;
+    }
+
+    got += total;
   }
+
+  return YES;
 }
 
-- (void) flush
+-(BOOL) flush:(NSError *__autoreleasing *)error
 {
-  // no flush for you!
+  return YES;
+}
+
+-(void) close
+{
+  NSInputStream *input = self.input;
+  if (input) {
+    // Close and reset inputstream
+    CFReadStreamSetProperty((__bridge CFReadStreamRef)(input), kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
+    [input setDelegate:nil];
+    [input close];
+    [input removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+    input = nil;
+  }
+
+  NSOutputStream *output = self.output;
+  if (output) {
+    // Close and reset outputstream
+    CFWriteStreamSetProperty((__bridge CFWriteStreamRef)(output), kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
+    [output setDelegate:nil];
+    [output close];
+    [output removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+    output = nil;
+  }
 }
 
 @end
diff --git a/lib/cocoa/src/transport/TSSLSocketTransport.h b/lib/cocoa/src/transport/TSSLSocketTransport.h
new file mode 100644
index 0000000..b606c4a
--- /dev/null
+++ b/lib/cocoa/src/transport/TSSLSocketTransport.h
@@ -0,0 +1,37 @@
+/*
+ * 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 <Foundation/Foundation.h>
+#import "TNSStreamTransport.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+@interface TSSLSocketTransport : TNSStreamTransport <NSStreamDelegate>
+
+-(id) initWithHostname:(NSString *)hostname
+                  port:(int)port
+                 error:(NSError **)error;
+
+-(BOOL) isOpen;
+
+@end
+
+
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/transport/TSSLSocketTransport.m b/lib/cocoa/src/transport/TSSLSocketTransport.m
new file mode 100644
index 0000000..1b1214f
--- /dev/null
+++ b/lib/cocoa/src/transport/TSSLSocketTransport.m
@@ -0,0 +1,304 @@
+/*
+ * 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 <Foundation/Foundation.h>
+#import <CoreFoundation/CoreFoundation.h>
+#import "TSSLSocketTransport.h"
+#import "TSSLSocketTransportError.h"
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#if !TARGET_OS_IPHONE
+#import <CoreServices/CoreServices.h>
+#else
+#import <CFNetwork/CFNetwork.h>
+#endif
+
+@interface TSSLSocketTransport ()
+
+@property(strong, nonatomic) NSString *sslHostname;
+@property(assign, nonatomic) int sd;
+
+@end
+
+
+@implementation TSSLSocketTransport
+
+-(id) initWithHostname:(NSString *)hostname
+                  port:(int)port
+                 error:(NSError **)error
+{
+  _sslHostname = hostname;
+  CFReadStreamRef readStream = NULL;
+  CFWriteStreamRef writeStream = NULL;
+
+
+  /* create a socket structure */
+  struct sockaddr_in pin;
+  struct hostent *hp = NULL;
+  for (int i = 0; i < 10; i++) {
+
+
+
+    if ((hp = gethostbyname([hostname UTF8String])) == NULL) {
+      NSLog(@"failed to resolve hostname %@", hostname);
+      herror("resolv");
+      if (i == 9) {
+        if (error) {
+          *error = [NSError errorWithDomain:TSSLSocketTransportErrorDomain
+                                       code:TSSLSocketTransportErrorHostanameResolution
+                                   userInfo:nil];
+        }
+        return nil;
+      }
+      [NSThread sleepForTimeInterval:0.2];
+    }
+    else {
+      break;
+    }
+  }
+
+  memset(&pin, 0, sizeof(pin));
+  pin.sin_family = AF_INET;
+  memcpy(&pin.sin_addr, hp->h_addr, sizeof(struct in_addr));
+  pin.sin_port = htons(port);
+
+  /* create the socket */
+  if ((_sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+    NSLog(@"failed to create socket for host %@:%d", hostname, port);
+    if (error) {
+      *error = [NSError errorWithDomain:TSSLSocketTransportErrorDomain
+                                   code:TSSLSocketTransportErrorSocketCreate
+                               userInfo:nil];
+    }
+    return nil;
+  }
+
+  /* open a connection */
+  if (connect(_sd, (struct sockaddr *)&pin, sizeof(pin)) == -1) {
+    NSLog(@"failed to create conenct to host %@:%d", hostname, port);
+    if (error) {
+      *error = [NSError errorWithDomain:TSSLSocketTransportErrorDomain
+                                   code:TSSLSocketTransportErrorConnect
+                               userInfo:nil];
+    }
+    return nil;
+  }
+  CFStreamCreatePairWithSocket(kCFAllocatorDefault, _sd, &readStream, &writeStream);
+
+  CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
+  CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
+
+  NSInputStream *inputStream;
+  NSOutputStream *outputStream;
+
+  if (readStream && writeStream) {
+
+    CFReadStreamSetProperty(readStream,
+                            kCFStreamPropertySocketSecurityLevel,
+                            kCFStreamSocketSecurityLevelTLSv1);
+
+    NSDictionary *settings = @{(__bridge NSString *)kCFStreamSSLValidatesCertificateChain: @YES};
+
+    CFReadStreamSetProperty((CFReadStreamRef)readStream,
+                            kCFStreamPropertySSLSettings,
+                            (CFTypeRef)settings);
+
+    CFWriteStreamSetProperty((CFWriteStreamRef)writeStream,
+                             kCFStreamPropertySSLSettings,
+                             (CFTypeRef)settings);
+
+    inputStream = (__bridge NSInputStream *)readStream;
+    [inputStream setDelegate:self];
+    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+    [inputStream open];
+
+    outputStream = (__bridge NSOutputStream *)writeStream;
+    [outputStream setDelegate:self];
+    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+    [outputStream open];
+
+    CFRelease(readStream);
+    CFRelease(writeStream);
+  }
+
+  self = [super initWithInputStream:inputStream outputStream:outputStream];
+
+  return self;
+}
+
+-(void) dealloc
+{
+  [self close];
+}
+
+#pragma mark -
+#pragma mark NSStreamDelegate
+
+-(void) stream:(NSStream *)aStream
+   handleEvent:(NSStreamEvent)eventCode
+{
+  switch (eventCode) {
+  case NSStreamEventNone:
+    break;
+
+  case NSStreamEventHasBytesAvailable:
+    break;
+
+  case NSStreamEventOpenCompleted:
+    break;
+
+  case NSStreamEventHasSpaceAvailable: {
+
+    BOOL proceed = NO;
+    SecTrustResultType trustResult = kSecTrustResultInvalid;
+    CFMutableArrayRef newPolicies = NULL;
+
+    do {
+
+      SecTrustRef trust = (__bridge SecTrustRef)[aStream propertyForKey:(NSString *)kCFStreamPropertySSLPeerTrust];
+
+      // Add new policy to current list of policies
+      SecPolicyRef policy = SecPolicyCreateSSL(NO, (__bridge CFStringRef)(_sslHostname));
+      if (!policy) {
+        break;
+      }
+
+      CFArrayRef policies;
+      if (SecTrustCopyPolicies(trust, &policies) != errSecSuccess) {
+        CFRelease(policy);
+        break;
+      }
+
+      newPolicies = CFArrayCreateMutableCopy(NULL, 0, policies);
+      CFArrayAppendValue(newPolicies, policy);
+
+      CFRelease(policies);
+      CFRelease(policy);
+
+      // Update trust policies
+      if (SecTrustSetPolicies(trust, newPolicies) != errSecSuccess) {
+        break;
+      }
+
+      // Evaluate the trust chain
+      if (SecTrustEvaluate(trust, &trustResult) != errSecSuccess) {
+        break;
+      }
+
+      switch (trustResult) {
+      case kSecTrustResultProceed:
+        // NSLog(@"Trusted by USER");
+        proceed = YES;
+        break;
+
+      case kSecTrustResultUnspecified:
+        // NSLog(@"Trusted by OS");
+        proceed = YES;
+        break;
+
+      case kSecTrustResultRecoverableTrustFailure:
+        proceed = recoverFromTrustFailure(trust, trustResult);
+        break;
+
+      case kSecTrustResultDeny:
+        // NSLog(@"Deny");
+        break;
+
+      case kSecTrustResultFatalTrustFailure:
+        // NSLog(@"FatalTrustFailure");
+        break;
+
+      case kSecTrustResultOtherError:
+        // NSLog(@"OtherError");
+        break;
+
+      case kSecTrustResultInvalid:
+        // NSLog(@"Invalid");
+        break;
+
+      default:
+        // NSLog(@"Default");
+        break;
+      }
+
+    }
+    while (NO);
+
+    if (!proceed) {
+      NSLog(@"TSSLSocketTransport: Cannot trust certificate. Result: %u", trustResult);
+      [aStream close];
+    }
+
+    if (newPolicies) {
+      CFRelease(newPolicies);
+    }
+
+  }
+  break;
+
+  case NSStreamEventErrorOccurred: {
+    NSLog(@"TSSLSocketTransport: Error occurred opening stream: %@", [aStream streamError]);
+    break;
+  }
+
+  case NSStreamEventEndEncountered:
+    break;
+  }
+}
+
+BOOL recoverFromTrustFailure(SecTrustRef myTrust, SecTrustResultType lastTrustResult)
+{
+  CFAbsoluteTime trustTime = SecTrustGetVerifyTime(myTrust);
+  CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent();
+
+  CFAbsoluteTime timeIncrement = 31536000;
+  CFAbsoluteTime newTime = currentTime - timeIncrement;
+
+  if (trustTime - newTime) {
+
+    CFDateRef newDate = CFDateCreate(NULL, newTime);
+    SecTrustSetVerifyDate(myTrust, newDate);
+    CFRelease(newDate);
+
+    if (SecTrustEvaluate(myTrust, &lastTrustResult) != errSecSuccess) {
+      return NO;
+    }
+
+  }
+
+  if (lastTrustResult == kSecTrustResultProceed || lastTrustResult == kSecTrustResultUnspecified) {
+    return YES;
+  }
+
+  NSLog(@"TSSLSocketTransport: Unable to recover certificate trust failure");
+  return YES;
+}
+
+-(BOOL) isOpen
+{
+  if (_sd > 0) {
+    return TRUE;
+  }
+  else {
+    return FALSE;
+  }
+}
+
+@end
diff --git a/lib/cocoa/src/transport/TSSLSocketTransportError.h b/lib/cocoa/src/transport/TSSLSocketTransportError.h
new file mode 100644
index 0000000..e17f39e
--- /dev/null
+++ b/lib/cocoa/src/transport/TSSLSocketTransportError.h
@@ -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.
+ */
+
+#import "TTransportError.h"
+
+
+extern NSString *TSSLSocketTransportErrorDomain;
+
+
+typedef NS_ENUM (int, TSSLSocketTransportError) {
+  TSSLSocketTransportErrorHostanameResolution  = -10000,
+  TSSLSocketTransportErrorSocketCreate         = -10001,
+  TSSLSocketTransportErrorConnect              = -10002,
+};
diff --git a/lib/cocoa/src/transport/TSSLSocketTransportError.m b/lib/cocoa/src/transport/TSSLSocketTransportError.m
new file mode 100644
index 0000000..bcf941c
--- /dev/null
+++ b/lib/cocoa/src/transport/TSSLSocketTransportError.m
@@ -0,0 +1,23 @@
+/*
+ * 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 "TSSLSocketTransportError.h"
+
+
+NSString *TSSLSocketTransportErrorDomain = @"TSSLSocketTransportErrorDomain";
diff --git a/lib/cocoa/src/transport/TSocketClient.h b/lib/cocoa/src/transport/TSocketClient.h
deleted file mode 100644
index 372850f..0000000
--- a/lib/cocoa/src/transport/TSocketClient.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import <Foundation/Foundation.h>
-#import "TNSStreamTransport.h"
-
-@interface TSocketClient : TNSStreamTransport 
-#if TARGET_OS_IPHONE || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
-<NSStreamDelegate>
-#endif
-{
-}
-
-- (id) initWithHostname: (NSString *) hostname
-                   port: (int) port;
-
-@end
-
-
-
diff --git a/lib/cocoa/src/transport/TSocketClient.m b/lib/cocoa/src/transport/TSocketClient.m
deleted file mode 100644
index 1a7eea8..0000000
--- a/lib/cocoa/src/transport/TSocketClient.m
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-#import "TSocketClient.h"
-#import "TObjective-C.h"
-
-#if !TARGET_OS_IPHONE
-#import <CoreServices/CoreServices.h>
-#else
-#import <CFNetwork/CFNetwork.h>
-#endif
-
-@interface TSocketClient ()
-{
-    NSInputStream * inputStream;
-	NSOutputStream * outputStream;
-}
-@end
-
-@implementation TSocketClient
-
-- (id) initWithHostname: (NSString *) hostname
-                   port: (int) port
-{
-	inputStream = NULL;
-	outputStream = NULL;
-	CFReadStreamRef readStream = NULL;
-	CFWriteStreamRef writeStream = NULL;
-	CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (bridge_stub CFStringRef)hostname, port, &readStream, &writeStream);
-	if (readStream && writeStream) {
-		CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
-		CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
-		
-		inputStream = (bridge_stub NSInputStream *)readStream;
-		[inputStream retain_stub];
-		[inputStream setDelegate:self];
-		[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
-		[inputStream open];
-		
-		outputStream = (bridge_stub NSOutputStream *)writeStream;
-		[outputStream retain_stub];
-		[outputStream setDelegate:self];
-		[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
-		[outputStream open];
-        CFRelease(readStream);
-        CFRelease(writeStream);
-	}
-	
-	self = [super initWithInputStream: inputStream outputStream: outputStream];
-	
-	return self;
-}
-
--(void)dealloc
-{
-    [inputStream close];
-    [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
-    [inputStream setDelegate:nil];
-    [inputStream release_stub];
-    
-    [outputStream close];
-    [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
-    [outputStream setDelegate:nil];
-    [outputStream release_stub];
-    [super dealloc_stub];
-}
-
-
-@end
-
-
-
diff --git a/lib/cocoa/src/transport/TSocketTransport.h b/lib/cocoa/src/transport/TSocketTransport.h
new file mode 100644
index 0000000..a7b91a2
--- /dev/null
+++ b/lib/cocoa/src/transport/TSocketTransport.h
@@ -0,0 +1,36 @@
+/*
+ * 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 <Foundation/Foundation.h>
+#import "TNSStreamTransport.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+@interface TSocketTransport : TNSStreamTransport
+
+-(id) initWithHostname:(NSString *)hostname
+                  port:(int)port;
+
+-(id) initWithPath:(NSString *)path;
+
+@end
+
+
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/transport/TSocketTransport.m b/lib/cocoa/src/transport/TSocketTransport.m
new file mode 100644
index 0000000..9c58abb
--- /dev/null
+++ b/lib/cocoa/src/transport/TSocketTransport.m
@@ -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.
+ */
+#import "TSocketTransport.h"
+
+#if !TARGET_OS_IPHONE
+#import <CoreServices/CoreServices.h>
+#else
+#import <CFNetwork/CFNetwork.h>
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+@interface TSocketTransport () <NSStreamDelegate>
+@end
+
+
+@implementation TSocketTransport
+
+- (id) initWithReadStream: (CFReadStreamRef) readStream writeStream: (CFWriteStreamRef) writeStream
+{
+  NSInputStream *inputStream = nil;
+  NSOutputStream *outputStream = nil;
+
+  if (readStream && writeStream) {
+
+    CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
+    CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
+
+    inputStream = (__bridge NSInputStream *)readStream;
+    [inputStream setDelegate:self];
+    [inputStream scheduleInRunLoop:NSRunLoop.currentRunLoop forMode:NSDefaultRunLoopMode];
+    [inputStream open];
+
+    outputStream = (__bridge NSOutputStream *)writeStream;
+    [outputStream setDelegate:self];
+    [outputStream scheduleInRunLoop:NSRunLoop.currentRunLoop forMode:NSDefaultRunLoopMode];
+    [outputStream open];
+  }
+  else {
+
+    if (readStream) {
+      CFRelease(readStream);
+    }
+
+    if (writeStream) {
+      CFRelease(writeStream);
+    }
+
+    return nil;
+  }
+
+  return [super initWithInputStream:inputStream outputStream:outputStream];
+}
+
+- (id) initWithHostname: (NSString *) hostname
+                   port: (int) port
+{
+  CFReadStreamRef readStream = NULL;
+  CFWriteStreamRef writeStream = NULL;
+  CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef)hostname, port, &readStream, &writeStream);
+  return [self initWithReadStream:readStream writeStream:writeStream];
+}
+
+- (id) initWithPath: (NSString *) path
+{
+  CFSocketNativeHandle sockfd = socket(AF_LOCAL, SOCK_STREAM, IPPROTO_IP);
+  int yes = 1;
+  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
+  {
+    NSLog(@"TSocketTransport: Unable to set REUSEADDR property of socket.");
+    return nil;
+  }
+
+  NSData *serverAddress = [[self class] createAddressWithPath:path];
+
+  CFReadStreamRef readStream = NULL;
+  CFWriteStreamRef writeStream = NULL;
+  CFStreamCreatePairWithSocket(kCFAllocatorDefault, sockfd, &readStream, &writeStream);
+  if (!readStream || !writeStream)
+  {
+    NSLog(@"TSocketTransport: Unable to create read/write stream pair for socket.");
+    return nil;
+  }
+
+  if (connect(sockfd, (struct sockaddr *)serverAddress.bytes, (socklen_t) serverAddress.length) < 0)
+  {
+    NSLog(@"TSocketTransport: Connect error: %s\n", strerror(errno));
+    return nil;
+  }
+
+  return [self initWithReadStream:readStream writeStream:writeStream];
+}
+
++ (NSData *) createAddressWithPath: (NSString *)path
+{
+  struct sockaddr_un servaddr;
+
+  size_t nullTerminatedPathLength = path.length + 1;
+  if (nullTerminatedPathLength> sizeof(servaddr.sun_path)) {
+    NSLog(@"TSocketTransport: Unable to create socket at path %@. Path is too long.", path);
+    return nil;
+  }
+
+  bzero(&servaddr,sizeof(servaddr));
+  servaddr.sun_family = AF_LOCAL;
+  memcpy(servaddr.sun_path, path.UTF8String, nullTerminatedPathLength);
+  servaddr.sun_len = SUN_LEN(&servaddr);
+
+  return [NSData dataWithBytes:&servaddr length:sizeof(servaddr)];
+}
+
+
+@end
diff --git a/lib/cocoa/src/transport/TTransport.h b/lib/cocoa/src/transport/TTransport.h
index 61ebbd2..558cf60 100644
--- a/lib/cocoa/src/transport/TTransport.h
+++ b/lib/cocoa/src/transport/TTransport.h
@@ -17,20 +17,32 @@
  * under the License.
  */
 
+#import <Foundation/Foundation.h>
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+
 @protocol TTransport <NSObject>
 
-  /**
-   * Guarantees that all of len bytes are read
-   *
-   * @param buf Buffer to read into
-   * @param off Index in buffer to start storing bytes at
-   * @param len Maximum number of bytes to read
-   * @return The number of bytes actually read, which must be equal to len
-   * @throws TTransportException if there was an error reading data
-   */
-- (int) readAll: (uint8_t *) buf offset: (int) off length: (int) len;
+/**
+ * Guarantees that all of len bytes are read
+ *
+ * @param buf Buffer to read into
+ * @param off Index in buffer to start storing bytes at
+ * @param len Maximum number of bytes to read
+ * @return YES if succeeded, NO if failed
+ * @throws TTransportError if there was an error reading data
+ */
+-(BOOL) readAll:(UInt8 *)buf offset:(UInt32)off length:(UInt32)len error:(NSError *__autoreleasing *)error;
 
-- (void) write: (const uint8_t *) data offset: (unsigned int) offset length: (unsigned int) length;
+-(UInt32) readAvail:(UInt8 *)buf offset:(UInt32)off maxLength:(UInt32)maxLen error:(NSError *__autoreleasing *)error;
 
-- (void) flush;
+-(BOOL) write:(const UInt8 *)data offset:(UInt32)offset length:(UInt32)length error:(NSError *__autoreleasing *)error;
+
+-(BOOL) flush:(NSError *__autoreleasing *)error;
+
 @end
+
+
+NS_ASSUME_NONNULL_END
diff --git a/lib/cocoa/src/transport/TTransportError.h b/lib/cocoa/src/transport/TTransportError.h
new file mode 100644
index 0000000..c8c9f06
--- /dev/null
+++ b/lib/cocoa/src/transport/TTransportError.h
@@ -0,0 +1,43 @@
+/*
+ * 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 "TError.h"
+
+
+extern NSString *TTransportErrorDomain;
+
+
+typedef NS_ENUM (int, TTransportError) {
+  TTransportErrorUnknown        = 0,
+  TTransportErrorNotOpen        = 1,
+  TTransportErrorAlreadyOpen    = 2,
+  TTransportErrorTimedOut       = 3,
+  TTransportErrorEndOfFile      = 4,
+};
+
+
+extern NSString *TTransportErrorExtendedErrorKey;
+extern NSString *TTransportErrorHttpErrorKey;
+
+
+typedef NS_ENUM(int, THttpTransportError) {
+  THttpTransportErrorInvalidResponse  = 1001,
+  THttpTransportErrorInvalidStatus    = 1002,
+  THttpTransportErrorAuthentication   = 1003,
+};
diff --git a/lib/cocoa/src/transport/TTransportError.m b/lib/cocoa/src/transport/TTransportError.m
new file mode 100644
index 0000000..b1af076
--- /dev/null
+++ b/lib/cocoa/src/transport/TTransportError.m
@@ -0,0 +1,27 @@
+/*
+ * 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 "TTransportError.h"
+
+
+NSString *TTransportErrorDomain = @"TTransportErrorDomain";
+
+
+NSString *TTransportErrorExtendedErrorKey = @"extendedError";
+NSString *TTransportErrorHttpErrorKey = @"httpError";
diff --git a/lib/cocoa/src/transport/TTransportException.h b/lib/cocoa/src/transport/TTransportException.h
deleted file mode 100644
index 6749fe2..0000000
--- a/lib/cocoa/src/transport/TTransportException.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import "TException.h"
-
-@interface TTransportException : TException {
-}
-
-+ (id) exceptionWithReason: (NSString *) reason
-                     error: (NSError *) error;
-
-+ (id) exceptionWithReason: (NSString *) reason;
-
-@end
diff --git a/lib/cocoa/src/transport/TTransportException.m b/lib/cocoa/src/transport/TTransportException.m
deleted file mode 100644
index 43cdfbd..0000000
--- a/lib/cocoa/src/transport/TTransportException.m
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#import "TTransportException.h"
-#import "TObjective-C.h"
-
-@implementation TTransportException
-
-+ (id) exceptionWithReason: (NSString *) reason
-                     error: (NSError *) error
-{
-  NSDictionary * userInfo = nil;
-  if (error != nil) {
-    userInfo = [NSDictionary dictionaryWithObject: error forKey: @"error"];
-  }
-
-  return [super exceptionWithName: @"TTransportException"
-                           reason: reason
-                         userInfo: userInfo];
-}
-
-
-+ (id) exceptionWithReason: (NSString *) reason
-{
-  return [self exceptionWithReason: reason error: nil];
-}
-
-@end
diff --git a/lib/cpp/3rdparty.props b/lib/cpp/3rdparty.props
new file mode 100644
index 0000000..528d40a
--- /dev/null
+++ b/lib/cpp/3rdparty.props
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ImportGroup Label="PropertySheets" />
+  <PropertyGroup Label="UserMacros">
+    <BOOST_ROOT>$(THIRD_PARTY)\boost\boost_1_47_0</BOOST_ROOT>
+    <OPENSSL_ROOT_DIR>$(THIRD_PARTY)\openssl\OpenSSL-Win32</OPENSSL_ROOT_DIR>
+    <LIBEVENT_ROOT>$(THIRD_PARTY)\libevent-2.0.21-stable</LIBEVENT_ROOT>
+  </PropertyGroup>
+  <PropertyGroup />
+  <ItemDefinitionGroup />
+  <ItemGroup>
+    <BuildMacro Include="BOOST_ROOT">
+      <Value>$(BOOST_ROOT)</Value>
+      <EnvironmentVariable>true</EnvironmentVariable>
+    </BuildMacro>
+    <BuildMacro Include="OPENSSL_ROOT_DIR">
+      <Value>$(OPENSSL_ROOT_DIR)</Value>
+      <EnvironmentVariable>true</EnvironmentVariable>
+    </BuildMacro>
+    <BuildMacro Include="LIBEVENT_ROOT">
+      <Value>$(LIBEVENT_ROOT)</Value>
+      <EnvironmentVariable>true</EnvironmentVariable>
+    </BuildMacro>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/lib/cpp/CMakeLists.txt b/lib/cpp/CMakeLists.txt
new file mode 100755
index 0000000..9ea82c3
--- /dev/null
+++ b/lib/cpp/CMakeLists.txt
@@ -0,0 +1,212 @@
+#
+# 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.
+#
+
+include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
+include_directories(src)
+
+# SYSLIBS contains libraries that need to be linked to all lib targets
+set(SYSLIBS "")
+
+# Create the thrift C++ library
+set( thriftcpp_SOURCES
+   src/thrift/TApplicationException.cpp
+   src/thrift/TOutput.cpp
+   src/thrift/async/TAsyncChannel.cpp
+   src/thrift/async/TAsyncProtocolProcessor.cpp
+   src/thrift/async/TConcurrentClientSyncInfo.h
+   src/thrift/async/TConcurrentClientSyncInfo.cpp
+   src/thrift/concurrency/ThreadManager.cpp
+   src/thrift/concurrency/TimerManager.cpp
+   src/thrift/concurrency/Util.cpp
+   src/thrift/processor/PeekProcessor.cpp
+   src/thrift/protocol/TBase64Utils.cpp
+   src/thrift/protocol/TDebugProtocol.cpp
+   src/thrift/protocol/TJSONProtocol.cpp
+   src/thrift/protocol/TMultiplexedProtocol.cpp
+   src/thrift/protocol/TProtocol.cpp
+   src/thrift/transport/TTransportException.cpp
+   src/thrift/transport/TFDTransport.cpp
+   src/thrift/transport/TSimpleFileTransport.cpp
+   src/thrift/transport/THttpTransport.cpp
+   src/thrift/transport/THttpClient.cpp
+   src/thrift/transport/THttpServer.cpp
+   src/thrift/transport/TSocket.cpp
+   src/thrift/transport/TSocketPool.cpp
+   src/thrift/transport/TServerSocket.cpp
+   src/thrift/transport/TTransportUtils.cpp
+   src/thrift/transport/TBufferTransports.cpp
+   src/thrift/server/TConnectedClient.cpp
+   src/thrift/server/TServerFramework.cpp
+   src/thrift/server/TSimpleServer.cpp
+   src/thrift/server/TThreadPoolServer.cpp
+   src/thrift/server/TThreadedServer.cpp
+)
+
+# These files don't work on Windows CE as there is no pipe support
+# TODO: These files won't work with UNICODE support on windows. If fixed this can be re-added.
+if (NOT WINCE)
+    list(APPEND thriftcpp_SOURCES
+       src/thrift/transport/TPipe.cpp
+       src/thrift/transport/TPipeServer.cpp
+       src/thrift/transport/TFileTransport.cpp
+    )
+endif()
+
+
+if (WIN32)
+    list(APPEND thriftcpp_SOURCES
+        src/thrift/windows/TWinsockSingleton.cpp
+        src/thrift/windows/SocketPair.cpp
+        src/thrift/windows/GetTimeOfDay.cpp
+        src/thrift/windows/WinFcntl.cpp
+    )
+    if(NOT WINCE)
+        # This file uses pipes so it currently won't work on Windows CE
+        list(APPEND thriftcpp_SOURCES
+            src/thrift/windows/OverlappedSubmissionThread.cpp
+        )
+    endif()
+else()
+    # These files evaluate to nothing on Windows, so omit them from the
+    # Windows build
+    list(APPEND thriftcpp_SOURCES
+        src/thrift/VirtualProfiling.cpp
+        src/thrift/server/TServer.cpp
+    )
+endif()
+
+# If OpenSSL is not found just ignore the OpenSSL stuff
+find_package(OpenSSL)
+if(OPENSSL_FOUND AND WITH_OPENSSL)
+    list( APPEND thriftcpp_SOURCES
+       src/thrift/transport/TSSLSocket.cpp
+       src/thrift/transport/TSSLServerSocket.cpp
+    )
+    include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
+    list(APPEND SYSLIBS "${OPENSSL_LIBRARIES}")
+endif()
+
+# WITH_*THREADS selects which threading library to use
+if(UNIX AND NOT WITH_STDTHREADS)
+    if(ANDROID)
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
+    else()
+        list(APPEND SYSLIBS pthread)
+    endif()
+    set( thriftcpp_threads_SOURCES
+        src/thrift/concurrency/PosixThreadFactory.cpp
+        src/thrift/concurrency/Mutex.cpp
+        src/thrift/concurrency/Monitor.cpp
+    )
+else()
+    if(UNIX)
+        if(ANDROID)
+            set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
+        else()
+            list(APPEND SYSLIBS pthread)
+        endif()
+    endif()
+    set( thriftcpp_threads_SOURCES
+        src/thrift/concurrency/StdThreadFactory.cpp
+        src/thrift/concurrency/StdMutex.cpp
+        src/thrift/concurrency/StdMonitor.cpp
+    )
+endif()
+
+# Thrift non blocking server
+set( thriftcppnb_SOURCES
+    src/thrift/server/TNonblockingServer.cpp
+    src/thrift/transport/TNonblockingServerSocket.cpp
+    src/thrift/transport/TNonblockingSSLServerSocket.cpp
+    src/thrift/async/TEvhttpServer.cpp
+    src/thrift/async/TEvhttpClientChannel.cpp
+)
+
+# Thrift zlib server
+set( thriftcppz_SOURCES
+    src/thrift/transport/TZlibTransport.cpp
+    src/thrift/protocol/THeaderProtocol.cpp
+    src/thrift/transport/THeaderTransport.cpp
+    src/thrift/protocol/THeaderProtocol.cpp
+    src/thrift/transport/THeaderTransport.cpp
+)
+
+# Thrift Qt4 server
+set( thriftcppqt_SOURCES
+    src/thrift/qt/TQIODeviceTransport.cpp
+    src/thrift/qt/TQTcpServer.cpp
+)
+
+# Contains the thrift specific ADD_LIBRARY_THRIFT and TARGET_LINK_LIBRARIES_THRIFT
+include(ThriftMacros)
+
+ADD_LIBRARY_THRIFT(thrift ${thriftcpp_SOURCES} ${thriftcpp_threads_SOURCES})
+if(WIN32)
+    TARGET_LINK_LIBRARIES_THRIFT(thrift ${SYSLIBS} ws2_32)
+else()
+    TARGET_LINK_LIBRARIES_THRIFT(thrift ${SYSLIBS})
+endif()
+
+if(WITH_LIBEVENT)
+    find_package(Libevent REQUIRED)  # Libevent comes with CMake support form upstream
+    include_directories(SYSTEM ${LIBEVENT_INCLUDE_DIRS})
+
+    ADD_LIBRARY_THRIFT(thriftnb ${thriftcppnb_SOURCES})
+    TARGET_LINK_LIBRARIES_THRIFT(thriftnb ${SYSLIBS} ${LIBEVENT_LIBRARIES})
+    TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY(thriftnb thrift)
+endif()
+
+if(WITH_ZLIB)
+    find_package(ZLIB REQUIRED)
+    include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
+
+    ADD_LIBRARY_THRIFT(thriftz ${thriftcppz_SOURCES})
+    TARGET_LINK_LIBRARIES_THRIFT(thriftz ${SYSLIBS} ${ZLIB_LIBRARIES})
+    TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY(thriftz thrift)
+endif()
+
+if(WITH_QT4)
+    set(CMAKE_AUTOMOC ON)
+    find_package(Qt4 REQUIRED COMPONENTS QtCore QtNetwork)
+    ADD_LIBRARY_THRIFT(thriftqt ${thriftcppqt_SOURCES})
+    TARGET_LINK_LIBRARIES_THRIFT(thriftqt ${SYSLIBS} Qt4::QtCore Qt4::QtNetwork)
+    TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY(thriftqt thrift)
+endif()
+
+if(WITH_QT5)
+    # Qt5 has its own directory to avoid conflict with Qt4 caused by CMAKE_AUTOMOC
+    add_subdirectory(src/thrift/qt)
+endif()
+
+if(MSVC)
+    add_definitions("-DUNICODE -D_UNICODE")
+endif()
+
+add_definitions("-D__STDC_LIMIT_MACROS")
+
+# Install the headers
+install(DIRECTORY "src/thrift" DESTINATION "${INCLUDE_INSTALL_DIR}"
+    FILES_MATCHING PATTERN "*.h" PATTERN "*.tcc")
+# Copy config.h file
+install(DIRECTORY "${CMAKE_BINARY_DIR}/thrift" DESTINATION "${INCLUDE_INSTALL_DIR}"
+    FILES_MATCHING PATTERN "*.h")
+
+if(BUILD_TESTING)
+    add_subdirectory(test)
+endif()
diff --git a/lib/cpp/Makefile.am b/lib/cpp/Makefile.am
index 7b879f3..85bb9ab 100755
--- a/lib/cpp/Makefile.am
+++ b/lib/cpp/Makefile.am
@@ -17,20 +17,30 @@
 # under the License.
 #
 
+AUTOMAKE_OPTIONS = subdir-objects
+
 moc_%.cpp: %.h
 	$(QT_MOC) $(QT_CFLAGS) $< -o $@
 
+moc__%.cpp: %.h
+	$(QT5_MOC) $(QT5_CFLAGS) $< -o $@
+
 SUBDIRS = .
 
 if WITH_TESTS
+# This file is needed by compiler with plugin, while test/Makefile.am needs compiler
+# So test directory is directly picked by top level Makefile.am for plugin build
+if !WITH_PLUGIN
 SUBDIRS += test
 endif
+endif
 
 pkgconfigdir = $(libdir)/pkgconfig
 
 lib_LTLIBRARIES = libthrift.la
 pkgconfig_DATA = thrift.pc
-libthrift_la_LDFLAGS = -release $(VERSION) $(BOOST_LDFLAGS)
+libthrift_la_LDFLAGS = -release $(VERSION)
+libthrift_la_LIBADD = $(BOOST_LDFLAGS) $(OPENSSL_LDFLAGS) $(OPENSSL_LIBS)
 
 ## We only build the extra libraries if we have the dependencies,
 ## but we install all of the headers unconditionally.
@@ -46,24 +56,31 @@
 lib_LTLIBRARIES += libthriftqt.la
 pkgconfig_DATA += thrift-qt.pc
 endif
+if AMX_HAVE_QT5
+lib_LTLIBRARIES += libthriftqt5.la
+pkgconfig_DATA += thrift-qt5.pc
+endif
 
-AM_CXXFLAGS = -Wall
-AM_CPPFLAGS = $(BOOST_CPPFLAGS) -I$(srcdir)/src
-AM_LDFLAGS = $(BOOST_LDFLAGS)
+AM_CXXFLAGS = -Wall -Wextra -pedantic
+AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(OPENSSL_INCLUDES) -I$(srcdir)/src -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
 
 # Define the source files for the module
 
-libthrift_la_SOURCES = src/thrift/Thrift.cpp \
-                       src/thrift/TApplicationException.cpp \
+libthrift_la_SOURCES = src/thrift/TApplicationException.cpp \
+                       src/thrift/TOutput.cpp \
                        src/thrift/VirtualProfiling.cpp \
+                       src/thrift/async/TAsyncChannel.cpp \
+                       src/thrift/async/TAsyncProtocolProcessor.cpp \
+                       src/thrift/async/TConcurrentClientSyncInfo.cpp \
                        src/thrift/concurrency/ThreadManager.cpp \
                        src/thrift/concurrency/TimerManager.cpp \
                        src/thrift/concurrency/Util.cpp \
+                       src/thrift/processor/PeekProcessor.cpp \
                        src/thrift/protocol/TDebugProtocol.cpp \
-                       src/thrift/protocol/TDenseProtocol.cpp \
                        src/thrift/protocol/TJSONProtocol.cpp \
                        src/thrift/protocol/TBase64Utils.cpp \
                        src/thrift/protocol/TMultiplexedProtocol.cpp \
+                       src/thrift/protocol/TProtocol.cpp \
                        src/thrift/transport/TTransportException.cpp \
                        src/thrift/transport/TFDTransport.cpp \
                        src/thrift/transport/TFileTransport.cpp \
@@ -78,48 +95,58 @@
                        src/thrift/transport/TSocketPool.cpp \
                        src/thrift/transport/TServerSocket.cpp \
                        src/thrift/transport/TSSLServerSocket.cpp \
+                       src/thrift/transport/TNonblockingServerSocket.cpp \
+                       src/thrift/transport/TNonblockingSSLServerSocket.cpp \
                        src/thrift/transport/TTransportUtils.cpp \
                        src/thrift/transport/TBufferTransports.cpp \
+                       src/thrift/server/TConnectedClient.cpp \
                        src/thrift/server/TServer.cpp \
+                       src/thrift/server/TServerFramework.cpp \
                        src/thrift/server/TSimpleServer.cpp \
                        src/thrift/server/TThreadPoolServer.cpp \
-                       src/thrift/server/TThreadedServer.cpp \
-                       src/thrift/async/TAsyncChannel.cpp \
-                       src/thrift/processor/PeekProcessor.cpp
+                       src/thrift/server/TThreadedServer.cpp
 
-if WITH_BOOSTTHREADS
-libthrift_la_SOURCES += src/thrift/concurrency/BoostThreadFactory.cpp \
-                        src/thrift/concurrency/BoostMonitor.cpp \
-                        src/thrift/concurrency/BoostMutex.cpp
-else
 libthrift_la_SOURCES += src/thrift/concurrency/Mutex.cpp \
                         src/thrift/concurrency/Monitor.cpp \
                         src/thrift/concurrency/PosixThreadFactory.cpp
-endif
 
 libthriftnb_la_SOURCES = src/thrift/server/TNonblockingServer.cpp \
-                         src/thrift/async/TAsyncProtocolProcessor.cpp \
                          src/thrift/async/TEvhttpServer.cpp \
-                         src/thrift/async/TEvhttpClientChannel.cpp 
+                         src/thrift/async/TEvhttpClientChannel.cpp
 
-libthriftz_la_SOURCES = src/thrift/transport/TZlibTransport.cpp
+libthriftz_la_SOURCES = src/thrift/transport/TZlibTransport.cpp \
+                        src/thrift/transport/THeaderTransport.cpp \
+                        src/thrift/protocol/THeaderProtocol.cpp
+
 
 libthriftqt_la_MOC = src/thrift/qt/moc_TQTcpServer.cpp
-libthriftqt_la_SOURCES = $(libthriftqt_la_MOC) \
-                         src/thrift/qt/TQIODeviceTransport.cpp \
+nodist_libthriftqt_la_SOURCES = $(libthriftqt_la_MOC)
+libthriftqt_la_SOURCES = src/thrift/qt/TQIODeviceTransport.cpp \
                          src/thrift/qt/TQTcpServer.cpp
 CLEANFILES = $(libthriftqt_la_MOC)
 
+libthriftqt5_la_MOC = src/thrift/qt/moc__TQTcpServer.cpp
+nodist_libthriftqt5_la_SOURCES = $(libthriftqt5_la_MOC)
+libthriftqt5_la_SOURCES = src/thrift/qt/TQIODeviceTransport.cpp \
+                          src/thrift/qt/TQTcpServer.cpp
+CLEANFILES += $(libthriftqt5_la_MOC)
+
 # Flags for the various libraries
 libthriftnb_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBEVENT_CPPFLAGS)
 libthriftz_la_CPPFLAGS  = $(AM_CPPFLAGS) $(ZLIB_CPPFLAGS)
 libthriftqt_la_CPPFLAGS = $(AM_CPPFLAGS) $(QT_CFLAGS)
+libthriftqt5_la_CPPFLAGS = $(AM_CPPFLAGS) $(QT5_CFLAGS)
+if QT5_REDUCE_RELOCATIONS
+libthriftqt5_la_CPPFLAGS += -fPIC
+endif
 libthriftnb_la_CXXFLAGS = $(AM_CXXFLAGS)
 libthriftz_la_CXXFLAGS  = $(AM_CXXFLAGS)
 libthriftqt_la_CXXFLAGS  = $(AM_CXXFLAGS)
+libthriftqt5_la_CXXFLAGS  = $(AM_CXXFLAGS)
 libthriftnb_la_LDFLAGS  = -release $(VERSION) $(BOOST_LDFLAGS)
-libthriftz_la_LDFLAGS   = -release $(VERSION) $(BOOST_LDFLAGS)
+libthriftz_la_LDFLAGS   = -release $(VERSION) $(BOOST_LDFLAGS) $(ZLIB_LIBS)
 libthriftqt_la_LDFLAGS   = -release $(VERSION) $(BOOST_LDFLAGS) $(QT_LIBS)
+libthriftqt5_la_LDFLAGS   = -release $(VERSION) $(BOOST_LDFLAGS) $(QT5_LIBS)
 
 include_thriftdir = $(includedir)/thrift
 include_thrift_HEADERS = \
@@ -127,15 +154,15 @@
                          src/thrift/thrift-config.h \
                          src/thrift/TDispatchProcessor.h \
                          src/thrift/Thrift.h \
-                         src/thrift/TReflectionLocal.h \
+                         src/thrift/TOutput.h \
                          src/thrift/TProcessor.h \
                          src/thrift/TApplicationException.h \
                          src/thrift/TLogging.h \
-                         src/thrift/cxxfunctional.h
+                         src/thrift/TToString.h \
+                         src/thrift/TBase.h
 
 include_concurrencydir = $(include_thriftdir)/concurrency
 include_concurrency_HEADERS = \
-                         src/thrift/concurrency/BoostThreadFactory.h \
                          src/thrift/concurrency/Exception.h \
                          src/thrift/concurrency/Mutex.h \
                          src/thrift/concurrency/Monitor.h \
@@ -157,13 +184,14 @@
                          src/thrift/protocol/TBinaryProtocol.tcc \
                          src/thrift/protocol/TCompactProtocol.h \
                          src/thrift/protocol/TCompactProtocol.tcc \
-                         src/thrift/protocol/TDenseProtocol.h \
                          src/thrift/protocol/TDebugProtocol.h \
+                         src/thrift/protocol/THeaderProtocol.h \
                          src/thrift/protocol/TBase64Utils.h \
                          src/thrift/protocol/TJSONProtocol.h \
                          src/thrift/protocol/TMultiplexedProtocol.h \
                          src/thrift/protocol/TProtocolDecorator.h \
                          src/thrift/protocol/TProtocolTap.h \
+                         src/thrift/protocol/TProtocolTypes.h \
                          src/thrift/protocol/TProtocolException.h \
                          src/thrift/protocol/TVirtualProtocol.h \
                          src/thrift/protocol/TProtocol.h
@@ -173,10 +201,14 @@
                          src/thrift/transport/PlatformSocket.h \
                          src/thrift/transport/TFDTransport.h \
                          src/thrift/transport/TFileTransport.h \
+                         src/thrift/transport/THeaderTransport.h \
                          src/thrift/transport/TSimpleFileTransport.h \
                          src/thrift/transport/TServerSocket.h \
                          src/thrift/transport/TSSLServerSocket.h \
                          src/thrift/transport/TServerTransport.h \
+                         src/thrift/transport/TNonblockingServerTransport.h \
+                         src/thrift/transport/TNonblockingServerSocket.h \
+                         src/thrift/transport/TNonblockingSSLServerSocket.h \
                          src/thrift/transport/THttpTransport.h \
                          src/thrift/transport/THttpClient.h \
                          src/thrift/transport/THttpServer.h \
@@ -195,7 +227,9 @@
 
 include_serverdir = $(include_thriftdir)/server
 include_server_HEADERS = \
+                         src/thrift/server/TConnectedClient.h \
                          src/thrift/server/TServer.h \
+                         src/thrift/server/TServerFramework.h \
                          src/thrift/server/TSimpleServer.h \
                          src/thrift/server/TThreadPoolServer.h \
                          src/thrift/server/TThreadedServer.h \
@@ -214,6 +248,7 @@
                      src/thrift/async/TAsyncProcessor.h \
                      src/thrift/async/TAsyncBufferProcessor.h \
                      src/thrift/async/TAsyncProtocolProcessor.h \
+                     src/thrift/async/TConcurrentClientSyncInfo.h \
                      src/thrift/async/TEvhttpClientChannel.h \
                      src/thrift/async/TEvhttpServer.h
 
@@ -222,22 +257,26 @@
                   src/thrift/qt/TQIODeviceTransport.h \
                   src/thrift/qt/TQTcpServer.h
 
-THRIFT = $(top_builddir)/compiler/cpp/thrift
-
 WINDOWS_DIST = \
-             README_WINDOWS \
              src/thrift/windows \
              thrift.sln \
              libthrift.vcxproj \
              libthrift.vcxproj.filters \
              libthriftnb.vcxproj \
-             libthriftnb.vcxproj.filters
+             libthriftnb.vcxproj.filters \
+             3rdparty.props
 
 EXTRA_DIST = \
-             README \
-             README.SSL \
+             CMakeLists.txt \
+             coding_standards.md \
+             README.md \
              thrift-nb.pc.in \
              thrift.pc.in \
              thrift-z.pc.in \
              thrift-qt.pc.in \
+             thrift-qt5.pc.in \
+             src/thrift/qt/CMakeLists.txt \
              $(WINDOWS_DIST)
+
+style-local:
+	$(CPPSTYLE_CMD)
diff --git a/lib/cpp/README b/lib/cpp/README
deleted file mode 100644
index 576d017..0000000
--- a/lib/cpp/README
+++ /dev/null
@@ -1,67 +0,0 @@
-Thrift C++ Software Library
-
-License
-=======
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-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.
-
-Using Thrift with C++
-=====================
-
-The Thrift C++ libraries are built using the GNU tools. Follow the instructions
-in the top-level README, or run bootstrap.sh in this folder to generate the
-Makefiles.
-
-In case you do not want to open another README file, do this:
-  ./bootstrap.sh
-  ./configure (--with-boost=/usr/local)
-  make
-  sudo make install
-
-Thrift is divided into two libraries.
-
-libthrift
-  The core Thrift library contains all the core Thrift code. It requires
-  boost shared pointers, pthreads, and librt.
-
-libthriftnb
-  This library contains the Thrift nonblocking server, which uses libevent.
-  To link this library you will also need to link libevent.
-
-Linking Against Thrift
-======================
-
-After you build and install Thrift the libraries are installed to
-/usr/local/lib by default. Make sure this is in your LDPATH.
-
-On Linux, the best way to do this is to ensure that /usr/local/lib is in
-your /etc/ld.so.conf and then run /sbin/ldconfig.
-
-Depending upon whether you are linking dynamically or statically and how
-your build environment it set up, you may need to include additional
-libraries when linking against thrift, such as librt and/or libpthread. If
-you are using libthriftnb you will also need libevent.
-
-Dependencies
-============
-
-boost shared pointers
-http://www.boost.org/libs/smart_ptr/smart_ptr.htm
-
-libevent (for libthriftnb only)
-http://monkey.org/~provos/libevent/
diff --git a/lib/cpp/README.SSL b/lib/cpp/README.SSL
deleted file mode 100644
index a928057..0000000
--- a/lib/cpp/README.SSL
+++ /dev/null
@@ -1,135 +0,0 @@
-Notes on Thrift/SSL
-
-Author: Ping Li <pingli@facebook.com>
-
-1. Scope
-
-   This SSL only supports blocking mode socket I/O. It can only be used with
-   TSimpleServer, TThreadedServer, and TThreadPoolServer.
-
-2. Implementation
-
-   There're two main classes TSSLSocketFactory and TSSLSocket. Instances of
-   TSSLSocket are always created from TSSLSocketFactory.
-
-   PosixSSLThreadFactory creates PosixSSLThread. The only difference from the
-   PthreadThread type is that it cleanups OpenSSL error queue upon exiting
-   the thread. Ideally, OpenSSL APIs should only be called from PosixSSLThread.
-
-3. How to use SSL APIs
-
-   // This is for demo. In real code, typically only one TSSLSocketFactory
-   // instance is needed.
-   shared_ptr<TSSLSocketFactory> getSSLSocketFactory() {
-     shared_ptr<TSSLSocketFactory> factory(new TSSLSocketFactory());
-     // client: load trusted certificates
-     factory->loadTrustedCertificates("my-trusted-ca-certificates.pem");
-     // client: optionally set your own access manager, otherwise,
-     //         the default client access manager will be loaded.
-
-     factory->loadCertificate("my-certificate-signed-by-ca.pem");
-     factory->loadPrivateKey("my-private-key.pem");
-     // server: optionally setup access manager
-     // shared_ptr<AccessManager> accessManager(new MyAccessManager);
-     // factory->access(accessManager);
-     ...
-   }
-
-   // client code sample
-   shared_ptr<TSSLSocketFactory> factory = getSSLSocketFactory();
-   shared_ptr<TSocket> socket = factory.createSocket(host, port);
-   shared_ptr<TBufferedTransport> transport(new TBufferedTransport(socket));
-   ...
-
-   // server code sample
-   shared_ptr<TSSLSocketFactory> factory = getSSLSocketFactory();
-   shared_ptr<TSSLServerSocket> socket(new TSSLServerSocket(port, factory));
-   shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory));
-   ...
-
-4. AccessManager
-
-   AccessManager defines a callback interface. It has three callback methods:
-
-   (a) Decision verify(const sockaddr_storage& sa);
-   (b) Decision verify(const string& host, const char* name, int size);
-   (c) Decision verify(const sockaddr_storage& sa, const char* data, int size);
-
-   After SSL handshake completes, additional checks are conducted. Application
-   is given the chance to decide whether or not to continue the conversation
-   with the remote. Application is queried through the above three "verify"
-   method. They are called at different points of the verification process.
-
-   Decisions can be one of ALLOW, DENY, and SKIP. ALLOW and DENY means the
-   conversation should be continued or disconnected, respectively. ALLOW and
-   DENY decision stops the verification process. SKIP means there's no decision
-   based on the given input, continue the verification process.
-
-   First, (a) is called with the remote IP. It is called once at the beginning.
-   "sa" is the IP address of the remote peer.
-
-   Then, the certificate of remote peer is loaded. SubjectAltName extensions
-   are extracted and sent to application for verification. When a DNS
-   subjectAltName field is extracted, (b) is called. When an IP subjectAltName
-   field is extracted, (c) is called.
-
-   The "host" in (b) is the value from TSocket::getHost() if this is a client
-   side socket, or TSocket::getPeerHost() if this is a server side socket. The
-   reason is client side socket initiates the connection. TSocket::getHost()
-   is the remote host name. On server side, the remote host name is unknown
-   unless it's retrieved through TSocket::getPeerHost(). Either way, "host"
-   should be the remote host name. Keep in mind, if TSocket::getPeerHost()
-   failed, it would return the remote host name in numeric format.
-
-   If all subjectAltName extensions were "skipped", the common name field would
-   be checked. It is sent to application through (c), where "sa" is the remote
-   IP address. "data" is the IP address extracted from subjectAltName IP
-   extension, and "size" is the length of the extension data.
-
-   If any of the above "verify" methods returned a decision ALLOW or DENY, the
-   verification process would be stopped.
-
-   If any of the above "verify" methods returned SKIP, that decision would be
-   ignored and the verification process would move on till the last item is
-   examined. At that point, if there's still no decision, the connection is
-   terminated.
-
-   Thread safety, an access manager should not store state information if it's
-   to be used by many SSL sockets.
-
-5. SIGPIPE signal
-
-   Applications running OpenSSL over network connections may crash if SIGPIPE
-   is not ignored. This happens when they receive a connection reset by remote
-   peer exception, which somehow triggers a SIGPIPE signal. If not handled,
-   this signal would kill the application.
-
-6. How to run test client/server in SSL mode
-
-   The server expects the followings from the current working directory,
-   - "server-certificate.pem"
-   - "server-private-key.pem"
-
-   The client loads "trusted-ca-certificate.pem" from current directory.
-
-   The file names are hard coded in the source code. You need to create these
-   certificates before you can run the test code in SSL mode. Make sure at least
-   one of the followings is included in "server-certificate.pem",
-   - subjectAltName, DNS localhost
-   - subjectAltName, IP  127.0.0.1
-   - common name,    localhost
-
-   Run,
-   - "./test_server --ssl" to start server
-   - "./test_client --ssl" to run client
-
-   If "-h <host>" is used to run client, the above "localhost" in the above
-   server-certificate.pem has to be replaced with that host name.
-
-7. TSSLSocketFactory::randomize()
-
-   The default implementation of OpenSSLSocketFactory::randomize() simply calls
-   OpenSSL's RAND_poll() when OpenSSL library is first initialized.
-
-   The PRNG seed is key to the application security. This method should be
-   overridden if it's not strong enough for you.
diff --git a/lib/cpp/README.md b/lib/cpp/README.md
new file mode 100755
index 0000000..e744a6a
--- /dev/null
+++ b/lib/cpp/README.md
@@ -0,0 +1,296 @@
+Thrift C++ Software Library
+
+# License
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+# Using Thrift with C++
+
+The Thrift C++ libraries are built using the GNU tools. Follow the instructions
+in the top-level README.md
+
+In case you do not want to open another README.md file, do this thrift src:
+
+    ./bootstrap.sh
+    ./configure (--with-boost=/usr/local)
+    make
+    sudo make install
+
+Thrift is divided into two libraries.
+
+* libthrift - The core Thrift library contains all the core Thrift code. It requires
+  boost shared pointers, pthreads, and librt.
+
+* libthriftnb - This library contains the Thrift nonblocking server, which uses libevent.
+  To link this library you will also need to link libevent.
+
+## Linking Against Thrift
+
+After you build and install Thrift the libraries are installed to
+/usr/local/lib by default. Make sure this is in your LDPATH.
+
+On Linux, the best way to do this is to ensure that /usr/local/lib is in
+your /etc/ld.so.conf and then run /sbin/ldconfig.
+
+Depending upon whether you are linking dynamically or statically and how
+your build environment it set up, you may need to include additional
+libraries when linking against thrift, such as librt and/or libpthread. If
+you are using libthriftnb you will also need libevent.
+
+## Dependencies
+
+If your C++ environment implements C++11 or later, thrift will automatically use
+std::shared_ptr.  Otherwise you will need the boost library to provide a shared_ptr
+implementation for C++ environments pre-C++11.  If you are linking against code
+that expects to be using boost::shared_ptr, you can define the preprocessor
+variable FORCE_BOOST_SMART_PTR for your build of thrift to make it use boost instead
+of std for a number of memory related classes.  See thrift/stdcxx.h for more.
+
+libevent (for libthriftnb only)
+http://monkey.org/~provos/libevent/
+
+# Using Thrift with C++ on Windows
+
+Both the autoconf and cmake build systems are able to automatically detect many
+system configurations without the need to specify library locations, however if
+you run into problems or want to redirect thrift to build and link against your
+own provided third party libraries:
+
+BOOST_ROOT : For boost, e.g. D:\boost_1_55_0
+OPENSSL_ROOT_DIR : For OpenSSL, e.g. D:\OpenSSL-Win32
+
+only required by libthriftnb:
+
+LIBEVENT_ROOT_DIR : For Libevent e.g. D:\libevent-2.0.21-stable
+
+See /3rdparty.user for more details.
+
+The same linking guidelines described above for libthriftnb apply to windows as well.
+
+## Linking Against Thrift
+
+You need to link your project that uses thrift against all the thrift
+dependencies; in the case of libthrift, boost and for
+libthriftnb, libevent.
+
+In the project properties you must also set HAVE_CONFIG_H as force include
+the config header: "windows/confg.h"
+
+## Dependencies
+
+The same dependencies for shared_ptr as described above apply to windows as well.
+
+boost thread
+http://www.boost.org/doc/libs/release/doc/html/thread.html
+
+libevent (for libthriftnb only)
+http://monkey.org/~provos/libevent/
+
+## Notes on boost thread (static vs shared):
+
+By default lib/cpp/windows/force_inc.h defines:
+
+    #define BOOST_ALL_NO_LIB 1
+    #define BOOST_THREAD_NO_LIB 1
+
+This has for effect to have the host application linking against Thrift
+to have to link with boost thread as a static library.
+
+If you wanted instead to link with boost thread as a shared library,
+you'll need to uncomment those two lines, and recompile.
+
+## Windows version compatibility
+
+The Thrift library targets Windows XP for broadest compatbility. A notable
+difference is in the Windows-specific implementation of the socket poll
+function. To target Vista, Win7 or other versions, comment out the line
+
+    #define TARGET_WIN_XP.
+
+## Named Pipes
+
+Named Pipe transport has been added in the TPipe and TPipeServer classes. This
+is currently Windows-only. Named pipe transport for *NIX has not been
+implemented. Domain sockets are a better choice for local IPC under non-Windows
+OS's. *NIX named pipes only support 1:1 client-server connection.
+
+# Thrift/SSL
+
+## Scope
+
+This SSL only supports blocking mode socket I/O. It can only be used with
+TSimpleServer, TThreadedServer, and TThreadPoolServer.
+
+## Implementation
+
+There're two main classes TSSLSocketFactory and TSSLSocket. Instances of
+TSSLSocket are always created from TSSLSocketFactory.
+
+PosixSSLThreadFactory creates PosixSSLThread. The only difference from the
+PthreadThread type is that it cleanups OpenSSL error queue upon exiting
+the thread. Ideally, OpenSSL APIs should only be called from PosixSSLThread.
+
+## How to use SSL APIs
+
+This is for demo. In real code, typically only one TSSLSocketFactory
+instance is needed.
+
+    shared_ptr<TSSLSocketFactory> getSSLSocketFactory() {
+      shared_ptr<TSSLSocketFactory> factory(new TSSLSocketFactory());
+      // client: load trusted certificates
+      factory->loadTrustedCertificates("my-trusted-ca-certificates.pem");
+      // client: optionally set your own access manager, otherwise,
+      //         the default client access manager will be loaded.
+
+      factory->loadCertificate("my-certificate-signed-by-ca.pem");
+      factory->loadPrivateKey("my-private-key.pem");
+      // server: optionally setup access manager
+      // shared_ptr<AccessManager> accessManager(new MyAccessManager);
+      // factory->access(accessManager);
+      ...
+    }
+
+
+client code sample
+
+    shared_ptr<TSSLSocketFactory> factory = getSSLSocketFactory();
+    shared_ptr<TSocket> socket = factory.createSocket(host, port);
+    shared_ptr<TBufferedTransport> transport(new TBufferedTransport(socket));
+    ...
+
+
+server code sample
+
+    shared_ptr<TSSLSocketFactory> factory = getSSLSocketFactory();
+    shared_ptr<TSSLServerSocket> socket(new TSSLServerSocket(port, factory));
+    shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory));
+    ...
+
+## AccessManager
+
+AccessManager defines a callback interface. It has three callback methods:
+
+(a) Decision verify(const sockaddr_storage& sa);
+
+(b) Decision verify(const string& host, const char* name, int size);
+
+(c) Decision verify(const sockaddr_storage& sa, const char* data, int size);
+
+After SSL handshake completes, additional checks are conducted. Application
+is given the chance to decide whether or not to continue the conversation
+with the remote. Application is queried through the above three "verify"
+method. They are called at different points of the verification process.
+
+Decisions can be one of ALLOW, DENY, and SKIP. ALLOW and DENY means the
+conversation should be continued or disconnected, respectively. ALLOW and
+DENY decision stops the verification process. SKIP means there's no decision
+based on the given input, continue the verification process.
+
+First, (a) is called with the remote IP. It is called once at the beginning.
+"sa" is the IP address of the remote peer.
+
+Then, the certificate of remote peer is loaded. SubjectAltName extensions
+are extracted and sent to application for verification. When a DNS
+subjectAltName field is extracted, (b) is called. When an IP subjectAltName
+field is extracted, (c) is called.
+
+The "host" in (b) is the value from TSocket::getHost() if this is a client
+side socket, or TSocket::getPeerHost() if this is a server side socket. The
+reason is client side socket initiates the connection. TSocket::getHost()
+is the remote host name. On server side, the remote host name is unknown
+unless it's retrieved through TSocket::getPeerHost(). Either way, "host"
+should be the remote host name. Keep in mind, if TSocket::getPeerHost()
+failed, it would return the remote host name in numeric format.
+
+If all subjectAltName extensions were "skipped", the common name field would
+be checked. It is sent to application through (c), where "sa" is the remote
+IP address. "data" is the IP address extracted from subjectAltName IP
+extension, and "size" is the length of the extension data.
+
+If any of the above "verify" methods returned a decision ALLOW or DENY, the
+verification process would be stopped.
+
+If any of the above "verify" methods returned SKIP, that decision would be
+ignored and the verification process would move on till the last item is
+examined. At that point, if there's still no decision, the connection is
+terminated.
+
+Thread safety, an access manager should not store state information if it's
+to be used by many SSL sockets.
+
+## SIGPIPE signal
+
+Applications running OpenSSL over network connections may crash if SIGPIPE
+is not ignored. This happens when they receive a connection reset by remote
+peer exception, which somehow triggers a SIGPIPE signal. If not handled,
+this signal would kill the application.
+
+## How to run test client/server in SSL mode
+
+The server and client expects the followings from the directory /test/
+
+- keys/server.crt
+- keys/server.key
+- keys/CA.pem
+
+The file names are hard coded in the source code. You need to create these
+certificates before you can run the test code in SSL mode. Make sure at least
+one of the followings is included in "keys/server.crt",
+
+- subjectAltName, DNS localhost
+- subjectAltName, IP  127.0.0.1
+- common name,    localhost
+
+Run within /test/ folder,
+
+         ./cpp/TestServer --ssl &
+         ./cpp/TestClient --ssl
+
+If "-h <host>" is used to run client, the above "localhost" in the above
+keys/server.crt has to be replaced with that host name.
+
+## TSSLSocketFactory::randomize()
+
+The default implementation of OpenSSLSocketFactory::randomize() simply calls
+OpenSSL's RAND_poll() when OpenSSL library is first initialized.
+
+The PRNG seed is key to the application security. This method should be
+overridden if it's not strong enough for you.
+
+# Breaking Changes
+
+## 0.11.0
+
+Older versions of thrift depended on the <boost/smart_ptr.hpp> classes which
+were used in thrift headers to define interfaces.  Thrift now detects C++11
+at build time and will prefer to use <memory> classes from C++11 instead.
+You can force the library to build with boost memory classes by defining the
+preprocessor macro `FORCE_BOOST_SMART_PTR`.  (THRIFT-2221)
+
+In the pthread mutex implementation, the contention profiling code was enabled
+by default in all builds.  This changed to be disabled by default.  (THRIFT-4151)
+
+In older releases, if a TSSLSocketFactory's lifetime was not at least as long
+as the TSSLSockets it created, we silently reverted openssl to unsafe multithread behavior
+and so the results were undefined.  Changes were made in 0.11.0 that cause either an
+assertion or a core instead of undefined behavior.  The lifetime of a TSSLSocketFactory
+*must* be longer than any TSSLSocket that it creates, otherwise openssl will be cleaned
+up too early.  If the static boolean is set to disable openssl initialization and
+cleanup and leave it up to the consuming application, this requirement is not needed.
+(THRIFT-4164)
+
diff --git a/lib/cpp/README_WINDOWS b/lib/cpp/README_WINDOWS
deleted file mode 100644
index f4c887c..0000000
--- a/lib/cpp/README_WINDOWS
+++ /dev/null
@@ -1,107 +0,0 @@
-Thrift C++ Software Library
-
-License
-=======
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-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.
-
-Using Thrift with C++
-=====================
-
-You need to define an enviroment variable called THIRD_PARTY. The project
-assumes that you have extracted the dependancies into their default structure
-into the path defined by THIRD_PARTY.
-
-e.g. $(THIRD_PARTY)/boost/boost_1_47_0/
-
-Thrift is divided into two libraries.
-
-libthrift
-  The core Thrift library contains all the core Thrift code. It requires
-  boost shared pointers and boost thread.
-
-libthriftnb
-  This library contains the Thrift nonblocking server, which uses libevent.
-  To link this library you will also need to link libevent.
-
-Linking Against Thrift
-======================
-
-You need to link your project that uses thrift against all the thrift
-dependancies; in the case of libthrift, boost and for
-libthriftnb, libevent.
-
-In the project properties you must also set HAVE_CONFIG_H as force include
-the config header: "windows/confg.h"
-
-Dependencies
-============
-
-boost shared pointers
-http://www.boost.org/libs/smart_ptr/smart_ptr.htm
-
-boost thread
-http://www.boost.org/doc/libs/release/doc/html/thread.html
-
-libevent (for libthriftnb only)
-http://monkey.org/~provos/libevent/
-
-Notes on boost thread (static vs shared):
-=========================================
-
-By default lib/cpp/windows/force_inc.h defines:
-
-#define BOOST_ALL_NO_LIB 1
-#define BOOST_THREAD_NO_LIB 1
-
-This has for effect to have the host application linking against Thrift
-to have to link with boost thread as a static library.
-
-If you wanted instead to link with boost thread as a shared library,
-you'll need to uncomment those two lines, and recompile.
-
-Windows version compatibility
-=============================
-The Thrift library targets Windows XP for broadest compatbility. A notable
-difference is in the Windows-specific implementation of the socket poll
-function. To target Vista, Win7 or other versions, comment out the line
-#define TARGET_WIN_XP.
-
-Named Pipes
-===========
-- Named Pipe transport has been added in the TPipe and TPipeServer classes.
-  This is currently Windows-only (see below).
-
-Known issues
-============
-
-- Named pipe transport for *NIX has not been implemented. Domain sockets are
-  a better choice for local IPC under non-Windows OS's. *NIX named pipes 
-  only support 1:1 client-server connection.
-
-TODO
-====
-
-- Port remaining classes in libthrift:
-    - TSSLSocket
-
-- Port test cases. (Not even started this. Run test cases in release mode?)
-
-- Autolink libraries depending on debug\release build.
-
-- Auto versioning.
diff --git a/lib/cpp/coding_standards.md b/lib/cpp/coding_standards.md
new file mode 100644
index 0000000..8018c77
--- /dev/null
+++ b/lib/cpp/coding_standards.md
@@ -0,0 +1,4 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
+
+ * see .clang-format in root dir for settings of accepted format
+ * clang-format (3.5 or newer) can be used to automaticaly reformat code ('make style' command)
diff --git a/lib/cpp/libthrift.vcxproj b/lib/cpp/libthrift.vcxproj
index e9990a5..d1097ec 100644
--- a/lib/cpp/libthrift.vcxproj
+++ b/lib/cpp/libthrift.vcxproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
     <ProjectConfiguration Include="Debug-mt|Win32">
@@ -36,29 +36,30 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="src\thrift\async\TAsyncChannel.cpp"/>
+    <ClCompile Include="src\thrift\async\TConcurrentClientSyncInfo.cpp"/>
     <ClCompile Include="src\thrift\concurrency\BoostMonitor.cpp" />
     <ClCompile Include="src\thrift\concurrency\BoostMutex.cpp" />
     <ClCompile Include="src\thrift\concurrency\BoostThreadFactory.cpp" />
+    <ClCompile Include="src\thrift\concurrency\StdThreadFactory.cpp" />
     <ClCompile Include="src\thrift\concurrency\ThreadManager.cpp"/>
     <ClCompile Include="src\thrift\concurrency\TimerManager.cpp"/>
     <ClCompile Include="src\thrift\concurrency\Util.cpp"/>
     <ClCompile Include="src\thrift\processor\PeekProcessor.cpp"/>
     <ClCompile Include="src\thrift\protocol\TBase64Utils.cpp" />
     <ClCompile Include="src\thrift\protocol\TDebugProtocol.cpp"/>
-    <ClCompile Include="src\thrift\protocol\TDenseProtocol.cpp"/>
     <ClCompile Include="src\thrift\protocol\TJSONProtocol.cpp"/>
+    <ClCompile Include="src\thrift\protocol\TProtocol.cpp"/>
+    <ClCompile Include="src\thrift\protocol\TMultiplexedProtocol.cpp"/>
     <ClCompile Include="src\thrift\server\TSimpleServer.cpp"/>
     <ClCompile Include="src\thrift\server\TThreadPoolServer.cpp"/>
+    <ClCompile Include="src\thrift\server\TThreadedServer.cpp"/>
+    <ClCompile Include="src\thrift\server\TConnectedClient.cpp"/>
+    <ClCompile Include="src\thrift\server\TNonblockingServer.cpp"/>
+    <ClCompile Include="src\thrift\server\TServerFramework.cpp"/>
     <ClCompile Include="src\thrift\TApplicationException.cpp"/>
-    <ClCompile Include="src\thrift\Thrift.cpp"/>
+    <ClCompile Include="src\thrift\TOutput.cpp"/>
     <ClCompile Include="src\thrift\transport\TBufferTransports.cpp"/>
     <ClCompile Include="src\thrift\transport\TFDTransport.cpp" />
-    <ClCompile Include="src\thrift\transport\TFileTransport.cpp">
-      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
-      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'">true</ExcludedFromBuild>
-      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
-      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'">true</ExcludedFromBuild>
-    </ClCompile>
     <ClCompile Include="src\thrift\transport\THttpClient.cpp" />
     <ClCompile Include="src\thrift\transport\THttpServer.cpp" />
     <ClCompile Include="src\thrift\transport\THttpTransport.cpp"/>
@@ -66,41 +67,39 @@
     <ClCompile Include="src\thrift\transport\TPipeServer.cpp" />
     <ClCompile Include="src\thrift\transport\TServerSocket.cpp"/>
     <ClCompile Include="src\thrift\transport\TSimpleFileTransport.cpp" />
+    <ClCompile Include="src\thrift\transport\TFileTransport.cpp" />
     <ClCompile Include="src\thrift\transport\TSocket.cpp"/>
-    <ClCompile Include="src\thrift\transport\TSSLSocket.cpp">
-      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
-      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-mt|Win32'">true</ExcludedFromBuild>
-      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
-      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-mt|x64'">true</ExcludedFromBuild>
-      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
-      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'">true</ExcludedFromBuild>
-      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
-      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'">true</ExcludedFromBuild>
-    </ClCompile>
+    <ClCompile Include="src\thrift\transport\TSSLSocket.cpp"/>
     <ClCompile Include="src\thrift\transport\TTransportException.cpp"/>
     <ClCompile Include="src\thrift\transport\TTransportUtils.cpp"/>
     <ClCompile Include="src\thrift\windows\GetTimeOfDay.cpp" />
+    <ClCompile Include="src\thrift\windows\OverlappedSubmissionThread.cpp" />
     <ClCompile Include="src\thrift\windows\SocketPair.cpp" />
     <ClCompile Include="src\thrift\windows\TWinsockSingleton.cpp" />
     <ClCompile Include="src\thrift\windows\WinFcntl.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\thrift\async\TAsyncChannel.h" />
+    <ClInclude Include="src\thrift\async\TConcurrentClientSyncInfo.h" />
     <ClInclude Include="src\thrift\concurrency\BoostThreadFactory.h" />
+    <ClInclude Include="src\thrift\concurrency\StdThreadFactory.h" />
     <ClInclude Include="src\thrift\concurrency\Exception.h" />
     <ClInclude Include="src\thrift\concurrency\PlatformThreadFactory.h" />
     <ClInclude Include="src\thrift\processor\PeekProcessor.h" />
+    <ClInclude Include="src\thrift\processor\TMultiplexedProcessor.h" />
     <ClInclude Include="src\thrift\protocol\TBinaryProtocol.h" />
     <ClInclude Include="src\thrift\protocol\TDebugProtocol.h" />
-    <ClInclude Include="src\thrift\protocol\TDenseProtocol.h" />
     <ClInclude Include="src\thrift\protocol\TJSONProtocol.h" />
+    <ClInclude Include="src\thrift\protocol\TMultiplexedProtocol.h" />
     <ClInclude Include="src\thrift\protocol\TProtocol.h" />
     <ClInclude Include="src\thrift\protocol\TVirtualProtocol.h" />
     <ClInclude Include="src\thrift\server\TServer.h" />
     <ClInclude Include="src\thrift\server\TSimpleServer.h" />
     <ClInclude Include="src\thrift\server\TThreadPoolServer.h" />
+    <ClInclude Include="src\thrift\server\TThreadedServer.h" />
     <ClInclude Include="src\thrift\TApplicationException.h" />
     <ClInclude Include="src\thrift\Thrift.h" />
+    <ClInclude Include="src\thrift\TOutput.h" />
     <ClInclude Include="src\thrift\TProcessor.h" />
     <ClInclude Include="src\thrift\transport\TBufferTransports.h" />
     <ClInclude Include="src\thrift\transport\TFDTransport.h" />
@@ -121,6 +120,7 @@
     <ClInclude Include="src\thrift\windows\config.h" />
     <ClInclude Include="src\thrift\windows\GetTimeOfDay.h" />
     <ClInclude Include="src\thrift\windows\Operators.h" />
+    <ClInclude Include="src\thrift\windows\OverlappedSubmissionThread.h" />
     <ClInclude Include="src\thrift\windows\SocketPair.h" />
     <ClInclude Include="src\thrift\windows\TWinsockSingleton.h" />
     <ClInclude Include="src\thrift\windows\WinFcntl.h" />
@@ -184,52 +184,60 @@
   </ImportGroup>
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|Win32'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|x64'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\openssl\OpenSSL-Win32\include\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|Win32'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\openssl\OpenSSL-Win32\include\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\openssl\OpenSSL-Win32\include\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|x64'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\openssl\OpenSSL-Win32\include\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\openssl\OpenSSL-Win32\include\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\openssl\OpenSSL-Win32\include\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\openssl\OpenSSL-Win32\include\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\openssl\OpenSSL-Win32\include\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
@@ -355,4 +363,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/lib/cpp/libthrift.vcxproj.filters b/lib/cpp/libthrift.vcxproj.filters
index 3922988..5f64f78 100644
--- a/lib/cpp/libthrift.vcxproj.filters
+++ b/lib/cpp/libthrift.vcxproj.filters
@@ -4,7 +4,7 @@
     <ClCompile Include="src\thrift\transport\TBufferTransports.cpp">
       <Filter>transport</Filter>
     </ClCompile>
-    <ClCompile Include="src\thrift\Thrift.cpp" />
+    <ClCompile Include="src\thrift\TOutput.cpp" />
     <ClCompile Include="src\thrift\TApplicationException.cpp" />
     <ClCompile Include="src\thrift\windows\StdAfx.cpp">
       <Filter>windows</Filter>
@@ -25,16 +25,16 @@
       <Filter>concurrency</Filter>
     </ClCompile>
     <ClCompile Include="src\thrift\protocol\TDebugProtocol.cpp">
-      <Filter>protocal</Filter>
-    </ClCompile>
-    <ClCompile Include="src\thrift\protocol\TDenseProtocol.cpp">
-      <Filter>protocal</Filter>
+      <Filter>protocol</Filter>
     </ClCompile>
     <ClCompile Include="src\thrift\protocol\TBase64Utils.cpp">
-      <Filter>protocal</Filter>
+      <Filter>protocol</Filter>
     </ClCompile>
     <ClCompile Include="src\thrift\protocol\TJSONProtocol.cpp">
-      <Filter>protocal</Filter>
+      <Filter>protocol</Filter>
+    </ClCompile>
+    <ClCompile Include="src\thrift\protocol\TMultiplexedProtocol.cpp">
+      <Filter>protocol</Filter>
     </ClCompile>
     <ClCompile Include="src\thrift\transport\TFDTransport.cpp">
       <Filter>transport</Filter>
@@ -66,9 +66,15 @@
     <ClCompile Include="src\thrift\server\TThreadPoolServer.cpp">
       <Filter>server</Filter>
     </ClCompile>
+    <ClCompile Include="src\thrift\server\TThreadedServer.cpp">
+      <Filter>server</Filter>
+    </ClCompile>
     <ClCompile Include="src\thrift\async\TAsyncChannel.cpp">
       <Filter>async</Filter>
     </ClCompile>
+    <ClCompile Include="src\thrift\async\TConcurrentClientSyncInfo.cpp">
+      <Filter>async</Filter>
+    </ClCompile>
     <ClCompile Include="src\thrift\processor\PeekProcessor.cpp">
       <Filter>processor</Filter>
     </ClCompile>
@@ -93,6 +99,9 @@
     <ClCompile Include="src\thrift\concurrency\BoostThreadFactory.cpp">
       <Filter>concurrency</Filter>
     </ClCompile>
+    <ClCompile Include="src\thrift\concurrency\StdThreadFactory.cpp">
+      <Filter>concurrency</Filter>
+    </ClCompile>
     <ClCompile Include="src\thrift\windows\WinFcntl.cpp">
       <Filter>windows</Filter>
     </ClCompile>
@@ -111,7 +120,7 @@
       <Filter>transport</Filter>
     </ClInclude>
     <ClInclude Include="src\thrift\protocol\TBinaryProtocol.h">
-      <Filter>protocal</Filter>
+      <Filter>protocol</Filter>
     </ClInclude>
     <ClInclude Include="src\thrift\Thrift.h" />
     <ClInclude Include="src\thrift\TProcessor.h" />
@@ -144,10 +153,10 @@
       <Filter>windows</Filter>
     </ClInclude>
     <ClInclude Include="src\thrift\protocol\TProtocol.h">
-      <Filter>protocal</Filter>
+      <Filter>protocol</Filter>
     </ClInclude>
     <ClInclude Include="src\thrift\protocol\TVirtualProtocol.h">
-      <Filter>protocal</Filter>
+      <Filter>protocol</Filter>
     </ClInclude>
     <ClInclude Include="src\thrift\server\TServer.h">
       <Filter>server</Filter>
@@ -158,12 +167,21 @@
     <ClInclude Include="src\thrift\server\TThreadPoolServer.h">
       <Filter>server</Filter>
     </ClInclude>
+    <ClInclude Include="src\thrift\server\TThreadedServer.h">
+      <Filter>server</Filter>
+    </ClInclude>
     <ClInclude Include="src\thrift\async\TAsyncChannel.h">
       <Filter>async</Filter>
     </ClInclude>
+    <ClInclude Include="src\thrift\async\TConcurrentClientSyncInfo.h">
+      <Filter>async</Filter>
+    </ClInclude>
     <ClInclude Include="src\thrift\processor\PeekProcessor.h">
       <Filter>processor</Filter>
     </ClInclude>
+    <ClInclude Include="src\thrift\processor\TMultiplexedProcessor.h">
+      <Filter>processor</Filter>
+    </ClInclude>
     <ClInclude Include="src\thrift\transport\TFDTransport.h">
       <Filter>transport</Filter>
     </ClInclude>
@@ -186,13 +204,13 @@
       <Filter>transport</Filter>
     </ClInclude>
     <ClInclude Include="src\thrift\protocol\TJSONProtocol.h">
-      <Filter>protocal</Filter>
+      <Filter>protocol</Filter>
     </ClInclude>
-    <ClInclude Include="src\thrift\protocol\TDenseProtocol.h">
-      <Filter>protocal</Filter>
+    <ClInclude Include="src\thrift\protocol\TMultiplexedProtocol.h">
+      <Filter>protocol</Filter>
     </ClInclude>
     <ClInclude Include="src\thrift\protocol\TDebugProtocol.h">
-      <Filter>protocal</Filter>
+      <Filter>protocol</Filter>
     </ClInclude>
     <ClInclude Include="src\thrift\transport\TServerSocket.h">
       <Filter>transport</Filter>
@@ -212,6 +230,9 @@
     <ClInclude Include="src\thrift\concurrency\BoostThreadFactory.h">
       <Filter>concurrency</Filter>
     </ClInclude>
+    <ClInclude Include="src\thrift\concurrency\StdThreadFactory.h">
+      <Filter>concurrency</Filter>
+    </ClInclude>
     <ClInclude Include="src\thrift\concurrency\PlatformThreadFactory.h">
       <Filter>concurrency</Filter>
     </ClInclude>
@@ -226,7 +247,7 @@
     </ClInclude>
   </ItemGroup>
   <ItemGroup>
-    <Filter Include="protocal">
+    <Filter Include="protocol">
       <UniqueIdentifier>{07ced19b-b72a-4105-9ffb-6d2bcf64497e}</UniqueIdentifier>
     </Filter>
     <Filter Include="transport">
@@ -253,10 +274,10 @@
   </ItemGroup>
   <ItemGroup>
     <None Include="src\thrift\protocol\TBinaryProtocol.tcc">
-      <Filter>protocal</Filter>
+      <Filter>protocol</Filter>
     </None>
     <None Include="src\thrift\windows\tr1\functional">
       <Filter>windows\tr1</Filter>
     </None>
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/lib/cpp/libthriftnb.vcxproj b/lib/cpp/libthriftnb.vcxproj
index b186e83..9a6ffe6 100755
--- a/lib/cpp/libthriftnb.vcxproj
+++ b/lib/cpp/libthriftnb.vcxproj
@@ -35,16 +35,21 @@
     </ProjectConfiguration>
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="src\thrift\async\TAsyncProtocolProcessor.cpp"/>
-    <ClCompile Include="src\thrift\async\TEvhttpClientChannel.cpp"/>
-    <ClCompile Include="src\thrift\async\TEvhttpServer.cpp"/>
-    <ClCompile Include="src\thrift\server\TNonblockingServer.cpp"/>
+    <ClCompile Include="src\thrift\async\TAsyncProtocolProcessor.cpp" />
+    <ClCompile Include="src\thrift\async\TEvhttpClientChannel.cpp" />
+    <ClCompile Include="src\thrift\async\TEvhttpServer.cpp" />
+    <ClCompile Include="src\thrift\server\TNonblockingServer.cpp" />
+    <ClCompile Include="src\thrift\transport\TNonblockingServerSocket.cpp" />
+    <ClCompile Include="src\thrift\transport\TNonblockingSSLServerSocket.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\thrift\async\TAsyncProtocolProcessor.h" />
     <ClInclude Include="src\thrift\async\TEvhttpClientChannel.h" />
     <ClInclude Include="src\thrift\async\TEvhttpServer.h" />
     <ClInclude Include="src\thrift\server\TNonblockingServer.h" />
+    <ClInclude Include="src\thrift\transport\TNonblockingServerSocket.h" />
+    <ClInclude Include="src\thrift\transport\TNonblockingServerTransport.h" />
+    <ClInclude Include="src\thrift\transport\TNonblockingSSLServerSocket.h" />
     <ClInclude Include="src\thrift\windows\config.h" />
     <ClInclude Include="src\thrift\windows\force_inc.h" />
     <ClInclude Include="src\thrift\windows\TargetVersion.h" />
@@ -104,52 +109,60 @@
   </ImportGroup>
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|Win32'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|x64'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="3rdparty.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\WIN32-Code\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\include;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|Win32'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\WIN32-Code\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\include;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\WIN32-Code\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\include;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|x64'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\WIN32-Code\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\include;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\WIN32-Code\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\include;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\WIN32-Code\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\include;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\WIN32-Code\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\include;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'">
-    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(THIRD_PARTY)\boost\boost_1_47_0\include;$(THIRD_PARTY)\boost\boost_1_47_0\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\WIN32-Code\;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\include;$(THIRD_PARTY)\libevent\libevent-2.0.13-stable\;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
diff --git a/lib/cpp/libthriftnb.vcxproj.filters b/lib/cpp/libthriftnb.vcxproj.filters
index 5245544..85703dd 100644
--- a/lib/cpp/libthriftnb.vcxproj.filters
+++ b/lib/cpp/libthriftnb.vcxproj.filters
@@ -10,6 +10,9 @@
     <Filter Include="windows">
       <UniqueIdentifier>{60fc9e5e-0866-4aba-8662-439bb4a461d3}</UniqueIdentifier>
     </Filter>
+    <Filter Include="transport">
+      <UniqueIdentifier>{23fe2fde-a7c9-43ec-a409-7f53df5eee64}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="src\thrift\server\TNonblockingServer.cpp">
@@ -27,6 +30,12 @@
     <ClCompile Include="src\thrift\windows\StdAfx.cpp">
       <Filter>windows</Filter>
     </ClCompile>
+    <ClCompile Include="src\thrift\transport\TNonblockingServerSocket.cpp">
+      <Filter>transport</Filter>
+    </ClCompile>
+    <ClCompile Include="src\thrift\transport\TNonblockingSSLServerSocket.cpp">
+      <Filter>transport</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\thrift\server\TNonblockingServer.h">
@@ -53,5 +62,14 @@
     <ClInclude Include="src\thrift\windows\force_inc.h">
       <Filter>windows</Filter>
     </ClInclude>
+    <ClInclude Include="src\thrift\transport\TNonblockingServerSocket.h">
+      <Filter>transport</Filter>
+    </ClInclude>
+    <ClInclude Include="src\thrift\transport\TNonblockingServerTransport.h">
+      <Filter>transport</Filter>
+    </ClInclude>
+    <ClInclude Include="src\thrift\transport\TNonblockingSSLServerSocket.h">
+      <Filter>transport</Filter>
+    </ClInclude>
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/lib/cpp/src/thrift/TApplicationException.cpp b/lib/cpp/src/thrift/TApplicationException.cpp
index 1110ba2..2f14653 100644
--- a/lib/cpp/src/thrift/TApplicationException.cpp
+++ b/lib/cpp/src/thrift/TApplicationException.cpp
@@ -20,7 +20,8 @@
 #include <thrift/TApplicationException.h>
 #include <thrift/protocol/TProtocol.h>
 
-namespace apache { namespace thrift {
+namespace apache {
+namespace thrift {
 
 uint32_t TApplicationException::read(apache::thrift::protocol::TProtocol* iprot) {
   uint32_t xfer = 0;
@@ -76,5 +77,5 @@
   xfer += oprot->writeStructEnd();
   return xfer;
 }
-
-}} // apache::thrift
+}
+} // apache::thrift
diff --git a/lib/cpp/src/thrift/TApplicationException.h b/lib/cpp/src/thrift/TApplicationException.h
index d32a21d..60618fb 100644
--- a/lib/cpp/src/thrift/TApplicationException.h
+++ b/lib/cpp/src/thrift/TApplicationException.h
@@ -22,16 +22,15 @@
 
 #include <thrift/Thrift.h>
 
-
-namespace apache { namespace thrift {
+namespace apache {
+namespace thrift {
 
 namespace protocol {
-  class TProtocol;
+class TProtocol;
 }
 
 class TApplicationException : public TException {
- public:
-
+public:
   /**
    * Error codes for the various types of exceptions.
    */
@@ -49,24 +48,16 @@
     UNSUPPORTED_CLIENT_TYPE = 10
   };
 
-  TApplicationException() :
-    TException(),
-    type_(UNKNOWN) {}
+  TApplicationException() : TException(), type_(UNKNOWN) {}
 
-  TApplicationException(TApplicationExceptionType type) :
-    TException(),
-    type_(type) {}
+  TApplicationException(TApplicationExceptionType type) : TException(), type_(type) {}
 
-  TApplicationException(const std::string& message) :
-    TException(message),
-    type_(UNKNOWN) {}
+  TApplicationException(const std::string& message) : TException(message), type_(UNKNOWN) {}
 
-  TApplicationException(TApplicationExceptionType type,
-                        const std::string& message) :
-    TException(message),
-    type_(type) {}
+  TApplicationException(TApplicationExceptionType type, const std::string& message)
+    : TException(message), type_(type) {}
 
-  virtual ~TApplicationException() throw() {}
+  virtual ~TApplicationException() noexcept {}
 
   /**
    * Returns an error code that provides information about the type of error
@@ -74,25 +65,35 @@
    *
    * @return Error code
    */
-  TApplicationExceptionType getType() {
-    return type_;
-  }
+  TApplicationExceptionType getType() const { return type_; }
 
-  virtual const char* what() const throw() {
+  virtual const char* what() const noexcept {
     if (message_.empty()) {
       switch (type_) {
-        case UNKNOWN                 : return "TApplicationException: Unknown application exception";
-        case UNKNOWN_METHOD          : return "TApplicationException: Unknown method";
-        case INVALID_MESSAGE_TYPE    : return "TApplicationException: Invalid message type";
-        case WRONG_METHOD_NAME       : return "TApplicationException: Wrong method name";
-        case BAD_SEQUENCE_ID         : return "TApplicationException: Bad sequence identifier";
-        case MISSING_RESULT          : return "TApplicationException: Missing result";
-        case INTERNAL_ERROR          : return "TApplicationException: Internal error";
-        case PROTOCOL_ERROR          : return "TApplicationException: Protocol error";
-        case INVALID_TRANSFORM       : return "TApplicationException: Invalid transform";
-        case INVALID_PROTOCOL        : return "TApplicationException: Invalid protocol";
-        case UNSUPPORTED_CLIENT_TYPE : return "TApplicationException: Unsupported client type";
-        default                      : return "TApplicationException: (Invalid exception type)";
+      case UNKNOWN:
+        return "TApplicationException: Unknown application exception";
+      case UNKNOWN_METHOD:
+        return "TApplicationException: Unknown method";
+      case INVALID_MESSAGE_TYPE:
+        return "TApplicationException: Invalid message type";
+      case WRONG_METHOD_NAME:
+        return "TApplicationException: Wrong method name";
+      case BAD_SEQUENCE_ID:
+        return "TApplicationException: Bad sequence identifier";
+      case MISSING_RESULT:
+        return "TApplicationException: Missing result";
+      case INTERNAL_ERROR:
+        return "TApplicationException: Internal error";
+      case PROTOCOL_ERROR:
+        return "TApplicationException: Protocol error";
+      case INVALID_TRANSFORM:
+        return "TApplicationException: Invalid transform";
+      case INVALID_PROTOCOL:
+        return "TApplicationException: Invalid protocol";
+      case UNSUPPORTED_CLIENT_TYPE:
+        return "TApplicationException: Unsupported client type";
+      default:
+        return "TApplicationException: (Invalid exception type)";
       };
     } else {
       return message_.c_str();
@@ -102,14 +103,13 @@
   uint32_t read(protocol::TProtocol* iprot);
   uint32_t write(protocol::TProtocol* oprot) const;
 
- protected:
+protected:
   /**
    * Error code
    */
   TApplicationExceptionType type_;
-
 };
-
-}} // apache::thrift
+}
+} // apache::thrift
 
 #endif // #ifndef _THRIFT_TAPPLICATIONEXCEPTION_H_
diff --git a/lib/cpp/src/thrift/TBase.h b/lib/cpp/src/thrift/TBase.h
new file mode 100644
index 0000000..a274bcd
--- /dev/null
+++ b/lib/cpp/src/thrift/TBase.h
@@ -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.
+ */
+
+#ifndef _THRIFT_TBASE_H_
+#define _THRIFT_TBASE_H_ 1
+
+#include <thrift/Thrift.h>
+#include <thrift/protocol/TProtocol.h>
+
+namespace apache {
+namespace thrift {
+
+class TBase {
+public:
+  virtual ~TBase(){};
+  virtual uint32_t read(protocol::TProtocol* iprot) = 0;
+  virtual uint32_t write(protocol::TProtocol* oprot) const = 0;
+};
+}
+} // apache::thrift
+
+#endif // #ifndef _THRIFT_TBASE_H_
diff --git a/lib/cpp/src/thrift/TDispatchProcessor.h b/lib/cpp/src/thrift/TDispatchProcessor.h
index 33ec22e..28d347d 100644
--- a/lib/cpp/src/thrift/TDispatchProcessor.h
+++ b/lib/cpp/src/thrift/TDispatchProcessor.h
@@ -21,7 +21,8 @@
 
 #include <thrift/TProcessor.h>
 
-namespace apache { namespace thrift {
+namespace apache {
+namespace thrift {
 
 /**
  * TDispatchProcessor is a helper class to parse the message header then call
@@ -31,9 +32,9 @@
  */
 template <class Protocol_>
 class TDispatchProcessorT : public TProcessor {
- public:
-  virtual bool process(boost::shared_ptr<protocol::TProtocol> in,
-                       boost::shared_ptr<protocol::TProtocol> out,
+public:
+  virtual bool process(std::shared_ptr<protocol::TProtocol> in,
+                       std::shared_ptr<protocol::TProtocol> out,
                        void* connectionContext) {
     protocol::TProtocol* inRaw = in.get();
     protocol::TProtocol* outRaw = out.get();
@@ -60,15 +61,14 @@
     // (The old generated processor code used to try to skip a T_STRUCT and
     // continue.  However, that seems unsafe.)
     if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
-      GlobalOutput.printf("received invalid message type %d from client",
-                          mtype);
+      GlobalOutput.printf("received invalid message type %d from client", mtype);
       return false;
     }
 
     return this->dispatchCall(inRaw, outRaw, fname, seqid, connectionContext);
   }
 
- protected:
+protected:
   bool processFast(Protocol_* in, Protocol_* out, void* connectionContext) {
     std::string fname;
     protocol::TMessageType mtype;
@@ -76,13 +76,11 @@
     in->readMessageBegin(fname, mtype, seqid);
 
     if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
-      GlobalOutput.printf("received invalid message type %d from client",
-                          mtype);
+      GlobalOutput.printf("received invalid message type %d from client", mtype);
       return false;
     }
 
-    return this->dispatchCallTemplated(in, out, fname,
-                                       seqid, connectionContext);
+    return this->dispatchCallTemplated(in, out, fname, seqid, connectionContext);
   }
 
   /**
@@ -90,11 +88,14 @@
    */
   virtual bool dispatchCall(apache::thrift::protocol::TProtocol* in,
                             apache::thrift::protocol::TProtocol* out,
-                            const std::string& fname, int32_t seqid,
+                            const std::string& fname,
+                            int32_t seqid,
                             void* callContext) = 0;
 
-  virtual bool dispatchCallTemplated(Protocol_* in, Protocol_* out,
-                                     const std::string& fname, int32_t seqid,
+  virtual bool dispatchCallTemplated(Protocol_* in,
+                                     Protocol_* out,
+                                     const std::string& fname,
+                                     int32_t seqid,
                                      void* callContext) = 0;
 };
 
@@ -103,9 +104,9 @@
  * perform a dynamic_cast.
  */
 class TDispatchProcessor : public TProcessor {
- public:
-  virtual bool process(boost::shared_ptr<protocol::TProtocol> in,
-                       boost::shared_ptr<protocol::TProtocol> out,
+public:
+  virtual bool process(std::shared_ptr<protocol::TProtocol> in,
+                       std::shared_ptr<protocol::TProtocol> out,
                        void* connectionContext) {
     std::string fname;
     protocol::TMessageType mtype;
@@ -113,30 +114,28 @@
     in->readMessageBegin(fname, mtype, seqid);
 
     if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
-      GlobalOutput.printf("received invalid message type %d from client",
-                          mtype);
+      GlobalOutput.printf("received invalid message type %d from client", mtype);
       return false;
     }
 
     return dispatchCall(in.get(), out.get(), fname, seqid, connectionContext);
   }
 
- protected:
+protected:
   virtual bool dispatchCall(apache::thrift::protocol::TProtocol* in,
                             apache::thrift::protocol::TProtocol* out,
-                            const std::string& fname, int32_t seqid,
+                            const std::string& fname,
+                            int32_t seqid,
                             void* callContext) = 0;
 };
 
 // Specialize TDispatchProcessorT for TProtocol and TDummyProtocol just to use
 // the generic TDispatchProcessor.
 template <>
-class TDispatchProcessorT<protocol::TDummyProtocol> :
-  public TDispatchProcessor {};
+class TDispatchProcessorT<protocol::TDummyProtocol> : public TDispatchProcessor {};
 template <>
-class TDispatchProcessorT<protocol::TProtocol> :
-  public TDispatchProcessor {};
-
-}} // apache::thrift
+class TDispatchProcessorT<protocol::TProtocol> : public TDispatchProcessor {};
+}
+} // apache::thrift
 
 #endif // _THRIFT_TDISPATCHPROCESSOR_H_
diff --git a/lib/cpp/src/thrift/TLogging.h b/lib/cpp/src/thrift/TLogging.h
index 4c8bddc..07ff030 100644
--- a/lib/cpp/src/thrift/TLogging.h
+++ b/lib/cpp/src/thrift/TLogging.h
@@ -39,13 +39,11 @@
  */
 #define T_GLOBAL_DEBUGGING_LEVEL 0
 
-
 /**
  * T_GLOBAL_LOGGING_LEVEL = 0: all logging turned off, logging macros undefined
  * T_GLOBAL_LOGGING_LEVEL = 1: all logging turned on
  */
-#define T_GLOBAL_LOGGING_LEVEL   1
-
+#define T_GLOBAL_LOGGING_LEVEL 1
 
 /**
  * Standard wrapper around fprintf what will prefix the file name and line
@@ -55,106 +53,115 @@
  * @param format_string
  */
 #if T_GLOBAL_DEBUGGING_LEVEL > 0
-  #define T_DEBUG(format_string,...)                                        \
-    if (T_GLOBAL_DEBUGGING_LEVEL > 0) {                                     \
-      fprintf(stderr,"[%s,%d] " format_string " \n", __FILE__, __LINE__,##__VA_ARGS__); \
+#define T_DEBUG(format_string, ...)                                                                \
+  if (T_GLOBAL_DEBUGGING_LEVEL > 0) {                                                              \
+    fprintf(stderr, "[%s,%d] " format_string " \n", __FILE__, __LINE__, ##__VA_ARGS__);            \
   }
 #else
-  #define T_DEBUG(format_string,...)
+#define T_DEBUG(format_string, ...)
 #endif
 
-
 /**
- * analagous to T_DEBUG but also prints the time
+ * analogous to T_DEBUG but also prints the time
  *
  * @param string  format_string input: printf style format string
  */
 #if T_GLOBAL_DEBUGGING_LEVEL > 0
-  #define T_DEBUG_T(format_string,...)                                    \
-    {                                                                     \
-      if (T_GLOBAL_DEBUGGING_LEVEL > 0) {                                 \
-        time_t now;                                                       \
-        char dbgtime[26] ;                                                \
-        time(&now);                                                       \
-        THRIFT_CTIME_R(&now, dbgtime);                                           \
-        dbgtime[24] = '\0';                                               \
-        fprintf(stderr,"[%s,%d] [%s] " format_string " \n", __FILE__, __LINE__,dbgtime,##__VA_ARGS__); \
-      }                                                                   \
-    }
+#define T_DEBUG_T(format_string, ...)                                                              \
+  {                                                                                                \
+    if (T_GLOBAL_DEBUGGING_LEVEL > 0) {                                                            \
+      time_t now;                                                                                  \
+      char dbgtime[26];                                                                            \
+      time(&now);                                                                                  \
+      THRIFT_CTIME_R(&now, dbgtime);                                                               \
+      dbgtime[24] = '\0';                                                                          \
+      fprintf(stderr,                                                                              \
+              "[%s,%d] [%s] " format_string " \n",                                                 \
+              __FILE__,                                                                            \
+              __LINE__,                                                                            \
+              dbgtime,                                                                             \
+              ##__VA_ARGS__);                                                                      \
+    }                                                                                              \
+  }
 #else
-  #define T_DEBUG_T(format_string,...)
+#define T_DEBUG_T(format_string, ...)
 #endif
 
-
 /**
- * analagous to T_DEBUG but uses input level to determine whether or not the string
+ * analogous to T_DEBUG but uses input level to determine whether or not the string
  * should be logged.
  *
  * @param int     level: specified debug level
  * @param string  format_string input: format string
  */
-#define T_DEBUG_L(level, format_string,...)                               \
-  if ((level) > 0) {                                                      \
-    fprintf(stderr,"[%s,%d] " format_string " \n", __FILE__, __LINE__,##__VA_ARGS__); \
+#define T_DEBUG_L(level, format_string, ...)                                                       \
+  if ((level) > 0) {                                                                               \
+    fprintf(stderr, "[%s,%d] " format_string " \n", __FILE__, __LINE__, ##__VA_ARGS__);            \
   }
 
-
 /**
  * Explicit error logging. Prints time, file name and line number
  *
  * @param string  format_string input: printf style format string
  */
-#define T_ERROR(format_string,...)                                      \
-  {                                                                     \
-    time_t now;                                                         \
-    char dbgtime[26] ;                                                  \
-    time(&now);                                                         \
-    THRIFT_CTIME_R(&now, dbgtime);                                             \
-    dbgtime[24] = '\0';                                                 \
-    fprintf(stderr,"[%s,%d] [%s] ERROR: " format_string " \n", __FILE__, __LINE__,dbgtime,##__VA_ARGS__); \
+#define T_ERROR(format_string, ...)                                                                \
+  {                                                                                                \
+    time_t now;                                                                                    \
+    char dbgtime[26];                                                                              \
+    time(&now);                                                                                    \
+    THRIFT_CTIME_R(&now, dbgtime);                                                                 \
+    dbgtime[24] = '\0';                                                                            \
+    fprintf(stderr,                                                                                \
+            "[%s,%d] [%s] ERROR: " format_string " \n",                                            \
+            __FILE__,                                                                              \
+            __LINE__,                                                                              \
+            dbgtime,                                                                               \
+            ##__VA_ARGS__);                                                                        \
   }
 
-
 /**
- * Analagous to T_ERROR, additionally aborting the process.
+ * Analogous to T_ERROR, additionally aborting the process.
  * WARNING: macro calls abort(), ending program execution
  *
  * @param string  format_string input: printf style format string
  */
-#define T_ERROR_ABORT(format_string,...)                                \
-  {                                                                     \
-    time_t now;                                                         \
-    char dbgtime[26] ;                                                  \
-    time(&now);                                                         \
-    THRIFT_CTIME_R(&now, dbgtime);                                             \
-    dbgtime[24] = '\0';                                                 \
-    fprintf(stderr,"[%s,%d] [%s] ERROR: Going to abort " format_string " \n", __FILE__, __LINE__,dbgtime,##__VA_ARGS__); \
-    exit(1);                                                            \
+#define T_ERROR_ABORT(format_string, ...)                                                          \
+  {                                                                                                \
+    time_t now;                                                                                    \
+    char dbgtime[26];                                                                              \
+    time(&now);                                                                                    \
+    THRIFT_CTIME_R(&now, dbgtime);                                                                 \
+    dbgtime[24] = '\0';                                                                            \
+    fprintf(stderr,                                                                                \
+            "[%s,%d] [%s] ERROR: Going to abort " format_string " \n",                             \
+            __FILE__,                                                                              \
+            __LINE__,                                                                              \
+            dbgtime,                                                                               \
+            ##__VA_ARGS__);                                                                        \
+    exit(1);                                                                                       \
   }
 
-
 /**
  * Log input message
  *
  * @param string  format_string input: printf style format string
  */
 #if T_GLOBAL_LOGGING_LEVEL > 0
-  #define T_LOG_OPER(format_string,...)                                       \
-    {                                                                         \
-      if (T_GLOBAL_LOGGING_LEVEL > 0) {                                       \
-        time_t now;                                                           \
-        char dbgtime[26] ;                                                    \
-        time(&now);                                                           \
-        THRIFT_CTIME_R(&now, dbgtime);                                               \
-        dbgtime[24] = '\0';                                                   \
-        fprintf(stderr,"[%s] " format_string " \n", dbgtime,##__VA_ARGS__);  \
-      }                                                                       \
-    }
+#define T_LOG_OPER(format_string, ...)                                                             \
+  {                                                                                                \
+    if (T_GLOBAL_LOGGING_LEVEL > 0) {                                                              \
+      time_t now;                                                                                  \
+      char dbgtime[26];                                                                            \
+      time(&now);                                                                                  \
+      THRIFT_CTIME_R(&now, dbgtime);                                                               \
+      dbgtime[24] = '\0';                                                                          \
+      fprintf(stderr, "[%s] " format_string " \n", dbgtime, ##__VA_ARGS__);                        \
+    }                                                                                              \
+  }
 #else
-  #define T_LOG_OPER(format_string,...)
+#define T_LOG_OPER(format_string, ...)
 #endif
 
-
 /**
  * T_GLOBAL_DEBUG_VIRTUAL = 0 or unset: normal operation,
  *                                      virtual call debug messages disabled
@@ -165,29 +172,24 @@
  *                                      apache::thrift::profile_print_info()
  */
 #if T_GLOBAL_DEBUG_VIRTUAL > 1
-  #define T_VIRTUAL_CALL()                                                \
-    ::apache::thrift::profile_virtual_call(typeid(*this))
-  #define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot) \
-    do {                                                                  \
-      if (!(specific_prot)) {                                             \
-        ::apache::thrift::profile_generic_protocol(                     \
-            typeid(*template_class), typeid(*generic_prot));              \
-      }                                                                   \
-    } while (0)
+#define T_VIRTUAL_CALL() ::apache::thrift::profile_virtual_call(typeid(*this))
+#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot)                            \
+  do {                                                                                             \
+    if (!(specific_prot)) {                                                                        \
+      ::apache::thrift::profile_generic_protocol(typeid(*template_class), typeid(*generic_prot));  \
+    }                                                                                              \
+  } while (0)
 #elif T_GLOBAL_DEBUG_VIRTUAL == 1
-  #define T_VIRTUAL_CALL()                                                \
-    fprintf(stderr,"[%s,%d] virtual call\n", __FILE__, __LINE__)
-  #define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot) \
-    do {                                                                  \
-      if (!(specific_prot)) {                                             \
-        fprintf(stderr,                                                   \
-                "[%s,%d] failed to cast to specific protocol type\n",     \
-                __FILE__, __LINE__);                                      \
-      }                                                                   \
-    } while (0)
+#define T_VIRTUAL_CALL() fprintf(stderr, "[%s,%d] virtual call\n", __FILE__, __LINE__)
+#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot)                            \
+  do {                                                                                             \
+    if (!(specific_prot)) {                                                                        \
+      fprintf(stderr, "[%s,%d] failed to cast to specific protocol type\n", __FILE__, __LINE__);   \
+    }                                                                                              \
+  } while (0)
 #else
-  #define T_VIRTUAL_CALL()
-  #define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot)
+#define T_VIRTUAL_CALL()
+#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot)
 #endif
 
 #endif // #ifndef _THRIFT_TLOGGING_H_
diff --git a/lib/cpp/src/thrift/TOutput.cpp b/lib/cpp/src/thrift/TOutput.cpp
new file mode 100644
index 0000000..ae3a9e2
--- /dev/null
+++ b/lib/cpp/src/thrift/TOutput.cpp
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <thrift/Thrift.h>
+#include <thrift/TToString.h>
+#include <cstring>
+#include <cstdlib>
+#include <stdarg.h>
+#include <stdio.h>
+
+namespace apache {
+namespace thrift {
+
+TOutput GlobalOutput;
+
+void TOutput::printf(const char* message, ...) {
+#ifndef THRIFT_SQUELCH_CONSOLE_OUTPUT
+  // Try to reduce heap usage, even if printf is called rarely.
+  static const int STACK_BUF_SIZE = 256;
+  char stack_buf[STACK_BUF_SIZE];
+  va_list ap;
+
+#ifdef _MSC_VER
+  va_start(ap, message);
+  int need = _vscprintf(message, ap);
+  va_end(ap);
+
+  if (need < STACK_BUF_SIZE) {
+    va_start(ap, message);
+    vsnprintf_s(stack_buf, STACK_BUF_SIZE, _TRUNCATE, message, ap);
+    va_end(ap);
+    f_(stack_buf);
+    return;
+  }
+#else
+  va_start(ap, message);
+  int need = vsnprintf(stack_buf, STACK_BUF_SIZE, message, ap);
+  va_end(ap);
+
+  if (need < STACK_BUF_SIZE) {
+    f_(stack_buf);
+    return;
+  }
+#endif
+
+  char* heap_buf = (char*)malloc((need + 1) * sizeof(char));
+  if (heap_buf == NULL) {
+#ifdef _MSC_VER
+    va_start(ap, message);
+    vsnprintf_s(stack_buf, STACK_BUF_SIZE, _TRUNCATE, message, ap);
+    va_end(ap);
+#endif
+    // Malloc failed.  We might as well print the stack buffer.
+    f_(stack_buf);
+    return;
+  }
+
+  va_start(ap, message);
+  int rval = vsnprintf(heap_buf, need + 1, message, ap);
+  va_end(ap);
+  // TODO(shigin): inform user
+  if (rval != -1) {
+    f_(heap_buf);
+  }
+  free(heap_buf);
+#endif
+}
+
+void TOutput::errorTimeWrapper(const char* msg) {
+#ifndef THRIFT_SQUELCH_CONSOLE_OUTPUT
+  time_t now;
+  char dbgtime[26];
+  time(&now);
+  THRIFT_CTIME_R(&now, dbgtime);
+  dbgtime[24] = 0;
+  fprintf(stderr, "Thrift: %s %s\n", dbgtime, msg);
+#endif
+}
+
+void TOutput::perror(const char* message, int errno_copy) {
+  std::string out = message + std::string(": ") + strerror_s(errno_copy);
+  f_(out.c_str());
+}
+
+std::string TOutput::strerror_s(int errno_copy) {
+#ifndef HAVE_STRERROR_R
+  return "errno = " + to_string(errno_copy);
+#else // HAVE_STRERROR_R
+
+  char b_errbuf[1024] = {'\0'};
+#ifdef STRERROR_R_CHAR_P
+  char* b_error = strerror_r(errno_copy, b_errbuf, sizeof(b_errbuf));
+#else
+  char* b_error = b_errbuf;
+  int rv = strerror_r(errno_copy, b_errbuf, sizeof(b_errbuf));
+  if (rv == -1) {
+    // strerror_r failed.  omgwtfbbq.
+    return "XSI-compliant strerror_r() failed with errno = "
+           + to_string(errno_copy);
+  }
+#endif
+  // Can anyone prove that explicit cast is probably not necessary
+  // to ensure that the string object is constructed before
+  // b_error becomes invalid?
+  return std::string(b_error);
+
+#endif // HAVE_STRERROR_R
+}
+}
+} // apache::thrift
diff --git a/lib/cpp/src/thrift/TOutput.h b/lib/cpp/src/thrift/TOutput.h
new file mode 100644
index 0000000..1375f73
--- /dev/null
+++ b/lib/cpp/src/thrift/TOutput.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_OUTPUT_H_
+#define _THRIFT_OUTPUT_H_ 1
+
+namespace apache {
+namespace thrift {
+
+class TOutput {
+public:
+  TOutput() : f_(&errorTimeWrapper) {}
+
+  inline void setOutputFunction(void (*function)(const char*)) { f_ = function; }
+
+  inline void operator()(const char* message) { f_(message); }
+
+  // It is important to have a const char* overload here instead of
+  // just the string version, otherwise errno could be corrupted
+  // if there is some problem allocating memory when constructing
+  // the string.
+  void perror(const char* message, int errno_copy);
+  inline void perror(const std::string& message, int errno_copy) {
+    perror(message.c_str(), errno_copy);
+  }
+
+  void printf(const char* message, ...);
+
+  static void errorTimeWrapper(const char* msg);
+
+  /** Just like strerror_r but returns a C++ string object. */
+  static std::string strerror_s(int errno_copy);
+
+private:
+  void (*f_)(const char*);
+};
+
+extern TOutput GlobalOutput;
+}
+} // namespace apache::thrift
+
+#endif //_THRIFT_OUTPUT_H_
diff --git a/lib/cpp/src/thrift/TProcessor.h b/lib/cpp/src/thrift/TProcessor.h
index b4a4657..6a46466 100644
--- a/lib/cpp/src/thrift/TProcessor.h
+++ b/lib/cpp/src/thrift/TProcessor.h
@@ -22,9 +22,9 @@
 
 #include <string>
 #include <thrift/protocol/TProtocol.h>
-#include <boost/shared_ptr.hpp>
 
-namespace apache { namespace thrift {
+namespace apache {
+namespace thrift {
 
 /**
  * Virtual interface class that can handle events from the processor. To
@@ -34,8 +34,7 @@
  * instance's state).
  */
 class TProcessorEventHandler {
- public:
-
+public:
   virtual ~TProcessorEventHandler() {}
 
   /**
@@ -45,8 +44,8 @@
    * for that function invocation.
    */
   virtual void* getContext(const char* fn_name, void* serverContext) {
-    (void) fn_name;
-    (void) serverContext;
+    (void)fn_name;
+    (void)serverContext;
     return NULL;
   }
 
@@ -54,61 +53,61 @@
    * Expected to free resources associated with a context.
    */
   virtual void freeContext(void* ctx, const char* fn_name) {
-    (void) ctx;
-    (void) fn_name;
+    (void)ctx;
+    (void)fn_name;
   }
 
   /**
    * Called before reading arguments.
    */
   virtual void preRead(void* ctx, const char* fn_name) {
-    (void) ctx;
-    (void) fn_name;
+    (void)ctx;
+    (void)fn_name;
   }
 
   /**
    * Called between reading arguments and calling the handler.
    */
   virtual void postRead(void* ctx, const char* fn_name, uint32_t bytes) {
-    (void) ctx;
-    (void) fn_name;
-    (void) bytes;
+    (void)ctx;
+    (void)fn_name;
+    (void)bytes;
   }
 
   /**
    * Called between calling the handler and writing the response.
    */
   virtual void preWrite(void* ctx, const char* fn_name) {
-    (void) ctx;
-    (void) fn_name;
+    (void)ctx;
+    (void)fn_name;
   }
 
   /**
    * Called after writing the response.
    */
   virtual void postWrite(void* ctx, const char* fn_name, uint32_t bytes) {
-    (void) ctx;
-    (void) fn_name;
-    (void) bytes;
+    (void)ctx;
+    (void)fn_name;
+    (void)bytes;
   }
 
   /**
    * Called when an async function call completes successfully.
    */
   virtual void asyncComplete(void* ctx, const char* fn_name) {
-    (void) ctx;
-    (void) fn_name;
+    (void)ctx;
+    (void)fn_name;
   }
 
   /**
    * Called if the handler throws an undeclared exception.
    */
   virtual void handlerError(void* ctx, const char* fn_name) {
-    (void) ctx;
-    (void) fn_name;
+    (void)ctx;
+    (void)fn_name;
   }
 
- protected:
+protected:
   TProcessorEventHandler() {}
 };
 
@@ -116,12 +115,16 @@
  * A helper class used by the generated code to free each context.
  */
 class TProcessorContextFreer {
- public:
-  TProcessorContextFreer(TProcessorEventHandler* handler, void* context, const char* method) :
-    handler_(handler), context_(context), method_(method) {}
-  ~TProcessorContextFreer() { if (handler_ != NULL) handler_->freeContext(context_, method_); }
+public:
+  TProcessorContextFreer(TProcessorEventHandler* handler, void* context, const char* method)
+    : handler_(handler), context_(context), method_(method) {}
+  ~TProcessorContextFreer() {
+    if (handler_ != NULL)
+      handler_->freeContext(context_, method_);
+  }
   void unregister() { handler_ = NULL; }
- private:
+
+private:
   apache::thrift::TProcessorEventHandler* handler_;
   void* context_;
   const char* method_;
@@ -135,34 +138,31 @@
  *
  */
 class TProcessor {
- public:
+public:
   virtual ~TProcessor() {}
 
-  virtual bool process(boost::shared_ptr<protocol::TProtocol> in,
-                       boost::shared_ptr<protocol::TProtocol> out,
+  virtual bool process(std::shared_ptr<protocol::TProtocol> in,
+                       std::shared_ptr<protocol::TProtocol> out,
                        void* connectionContext) = 0;
 
-  bool process(boost::shared_ptr<apache::thrift::protocol::TProtocol> io,
-               void* connectionContext) {
+  bool process(std::shared_ptr<apache::thrift::protocol::TProtocol> io, void* connectionContext) {
     return process(io, io, connectionContext);
   }
 
-  boost::shared_ptr<TProcessorEventHandler> getEventHandler() {
-    return eventHandler_;
-  }
+  std::shared_ptr<TProcessorEventHandler> getEventHandler() const { return eventHandler_; }
 
-  void setEventHandler(boost::shared_ptr<TProcessorEventHandler> eventHandler) {
+  void setEventHandler(std::shared_ptr<TProcessorEventHandler> eventHandler) {
     eventHandler_ = eventHandler;
   }
 
- protected:
+protected:
   TProcessor() {}
 
-  boost::shared_ptr<TProcessorEventHandler> eventHandler_;
+  std::shared_ptr<TProcessorEventHandler> eventHandler_;
 };
 
 /**
- * This is a helper class to allow boost::shared_ptr to be used with handler
+ * This is a helper class to allow std::shared_ptr to be used with handler
  * pointers returned by the generated handler factories.
  *
  * The handler factory classes generated by the thrift compiler return raw
@@ -173,35 +173,35 @@
  * parameter to a shared_ptr, so that factory->releaseHandler() will be called
  * when the object is no longer needed, instead of deleting the pointer.
  */
-template<typename HandlerFactory_>
+template <typename HandlerFactory_>
 class ReleaseHandler {
- public:
-   ReleaseHandler(const boost::shared_ptr<HandlerFactory_>& handlerFactory) :
-       handlerFactory_(handlerFactory) {}
+public:
+  ReleaseHandler(const std::shared_ptr<HandlerFactory_>& handlerFactory)
+    : handlerFactory_(handlerFactory) {}
 
-   void operator()(typename HandlerFactory_::Handler* handler) {
-     if (handler) {
-       handlerFactory_->releaseHandler(handler);
-     }
-   }
+  void operator()(typename HandlerFactory_::Handler* handler) {
+    if (handler) {
+      handlerFactory_->releaseHandler(handler);
+    }
+  }
 
- private:
-   boost::shared_ptr<HandlerFactory_> handlerFactory_;
+private:
+  std::shared_ptr<HandlerFactory_> handlerFactory_;
 };
 
 struct TConnectionInfo {
   // The input and output protocols
-  boost::shared_ptr<protocol::TProtocol> input;
-  boost::shared_ptr<protocol::TProtocol> output;
+  std::shared_ptr<protocol::TProtocol> input;
+  std::shared_ptr<protocol::TProtocol> output;
   // The underlying transport used for the connection
   // This is the transport that was returned by TServerTransport::accept(),
   // and it may be different than the transport pointed to by the input and
   // output protocols.
-  boost::shared_ptr<transport::TTransport> transport;
+  std::shared_ptr<transport::TTransport> transport;
 };
 
 class TProcessorFactory {
- public:
+public:
   virtual ~TProcessorFactory() {}
 
   /**
@@ -211,23 +211,19 @@
    * accepted on.  This generally means that this call does not need to be
    * thread safe, as it will always be invoked from a single thread.
    */
-  virtual boost::shared_ptr<TProcessor> getProcessor(
-      const TConnectionInfo& connInfo) = 0;
+  virtual std::shared_ptr<TProcessor> getProcessor(const TConnectionInfo& connInfo) = 0;
 };
 
 class TSingletonProcessorFactory : public TProcessorFactory {
- public:
-  TSingletonProcessorFactory(boost::shared_ptr<TProcessor> processor) :
-      processor_(processor) {}
+public:
+  TSingletonProcessorFactory(std::shared_ptr<TProcessor> processor) : processor_(processor) {}
 
-  boost::shared_ptr<TProcessor> getProcessor(const TConnectionInfo&) {
-    return processor_;
-  }
+  std::shared_ptr<TProcessor> getProcessor(const TConnectionInfo&) { return processor_; }
 
- private:
-  boost::shared_ptr<TProcessor> processor_;
+private:
+  std::shared_ptr<TProcessor> processor_;
 };
-
-}} // apache::thrift
+}
+} // apache::thrift
 
 #endif // #ifndef _THRIFT_TPROCESSOR_H_
diff --git a/lib/cpp/src/thrift/TReflectionLocal.h b/lib/cpp/src/thrift/TReflectionLocal.h
deleted file mode 100644
index 2ef7511..0000000
--- a/lib/cpp/src/thrift/TReflectionLocal.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef _THRIFT_TREFLECTIONLOCAL_H_
-#define _THRIFT_TREFLECTIONLOCAL_H_ 1
-
-#include <stdint.h>
-#include <cstring>
-#include <thrift/protocol/TProtocol.h>
-
-/**
- * Local Reflection is a blanket term referring to the the structure
- * and generation of this particular representation of Thrift types.
- * (It is called local because it cannot be serialized by Thrift).
- *
- */
-
-namespace apache { namespace thrift { namespace reflection { namespace local {
-
-using apache::thrift::protocol::TType;
-
-// We include this many bytes of the structure's fingerprint when serializing
-// a top-level structure.  Long enough to make collisions unlikely, short
-// enough to not significantly affect the amount of memory used.
-const int FP_PREFIX_LEN = 4;
-
-struct FieldMeta {
-  int16_t tag;
-  bool is_optional;
-};
-
-struct TypeSpec {
-  TType ttype;
-  uint8_t    fp_prefix[FP_PREFIX_LEN];
-
-  // Use an anonymous union here so we can fit two TypeSpecs in one cache line.
-  union {
-    struct {
-      // Use parallel arrays here for denser packing (of the arrays).
-      FieldMeta* metas;
-      TypeSpec** specs;
-    } tstruct;
-    struct {
-      TypeSpec *subtype1;
-      TypeSpec *subtype2;
-    } tcontainer;
-  };
-
-  // Static initialization of unions isn't really possible,
-  // so take the plunge and use constructors.
-  // Hopefully they'll be evaluated at compile time.
-
-  TypeSpec(TType ttype) : ttype(ttype) {
-    std::memset(fp_prefix, 0, FP_PREFIX_LEN);
-  }
-
-  TypeSpec(TType ttype,
-           const uint8_t* fingerprint,
-           FieldMeta* metas,
-           TypeSpec** specs) :
-    ttype(ttype)
-  {
-    std::memcpy(fp_prefix, fingerprint, FP_PREFIX_LEN);
-    tstruct.metas = metas;
-    tstruct.specs = specs;
-  }
-
-  TypeSpec(TType ttype, TypeSpec* subtype1, TypeSpec* subtype2) :
-    ttype(ttype)
-  {
-    std::memset(fp_prefix, 0, FP_PREFIX_LEN);
-    tcontainer.subtype1 = subtype1;
-    tcontainer.subtype2 = subtype2;
-  }
-
-};
-
-}}}} // apache::thrift::reflection::local
-
-#endif // #ifndef _THRIFT_TREFLECTIONLOCAL_H_
diff --git a/lib/cpp/src/thrift/TToString.h b/lib/cpp/src/thrift/TToString.h
new file mode 100644
index 0000000..25780f9
--- /dev/null
+++ b/lib/cpp/src/thrift/TToString.h
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_TOSTRING_H_
+#define _THRIFT_TOSTRING_H_ 1
+
+#include <cmath>
+#include <limits>
+#include <map>
+#include <set>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace apache {
+namespace thrift {
+
+template <typename T>
+std::string to_string(const T& t) {
+  std::ostringstream o;
+  o << t;
+  return o.str();
+}
+
+// TODO: replace the computations below with std::numeric_limits::max_digits10 once C++11
+// is enabled.
+inline std::string to_string(const float& t) {
+  std::ostringstream o;
+  o.precision(static_cast<std::streamsize>(std::ceil(static_cast<double>(std::numeric_limits<float>::digits * std::log10(2.0f) + 1))));
+  o << t;
+  return o.str();
+}
+
+inline std::string to_string(const double& t) {
+  std::ostringstream o;
+  o.precision(static_cast<std::streamsize>(std::ceil(static_cast<double>(std::numeric_limits<double>::digits * std::log10(2.0f) + 1))));
+  o << t;
+  return o.str();
+}
+
+inline std::string to_string(const long double& t) {
+  std::ostringstream o;
+  o.precision(static_cast<std::streamsize>(std::ceil(static_cast<double>(std::numeric_limits<long double>::digits * std::log10(2.0f) + 1))));
+  o << t;
+  return o.str();
+}
+
+template <typename K, typename V>
+std::string to_string(const std::map<K, V>& m);
+
+template <typename T>
+std::string to_string(const std::set<T>& s);
+
+template <typename T>
+std::string to_string(const std::vector<T>& t);
+
+template <typename K, typename V>
+std::string to_string(const typename std::pair<K, V>& v) {
+  std::ostringstream o;
+  o << to_string(v.first) << ": " << to_string(v.second);
+  return o.str();
+}
+
+template <typename T>
+std::string to_string(const T& beg, const T& end) {
+  std::ostringstream o;
+  for (T it = beg; it != end; ++it) {
+    if (it != beg)
+      o << ", ";
+    o << to_string(*it);
+  }
+  return o.str();
+}
+
+template <typename T>
+std::string to_string(const std::vector<T>& t) {
+  std::ostringstream o;
+  o << "[" << to_string(t.begin(), t.end()) << "]";
+  return o.str();
+}
+
+template <typename K, typename V>
+std::string to_string(const std::map<K, V>& m) {
+  std::ostringstream o;
+  o << "{" << to_string(m.begin(), m.end()) << "}";
+  return o.str();
+}
+
+template <typename T>
+std::string to_string(const std::set<T>& s) {
+  std::ostringstream o;
+  o << "{" << to_string(s.begin(), s.end()) << "}";
+  return o.str();
+}
+}
+} // apache::thrift
+
+#endif // _THRIFT_TOSTRING_H_
diff --git a/lib/cpp/src/thrift/Thrift.cpp b/lib/cpp/src/thrift/Thrift.cpp
deleted file mode 100644
index b1e1386..0000000
--- a/lib/cpp/src/thrift/Thrift.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <thrift/Thrift.h>
-#include <cstring>
-#include <cstdlib>
-#include <boost/lexical_cast.hpp>
-#include <stdarg.h>
-#include <stdio.h>
-
-namespace apache { namespace thrift {
-
-TOutput GlobalOutput;
-
-void TOutput::printf(const char *message, ...) {
-#ifndef THRIFT_SQUELCH_CONSOLE_OUTPUT
-  // Try to reduce heap usage, even if printf is called rarely.
-  static const int STACK_BUF_SIZE = 256;
-  char stack_buf[STACK_BUF_SIZE];
-  va_list ap;
-
-#ifdef _MSC_VER
-  va_start(ap, message);
-  int need = _vscprintf(message, ap);
-  va_end(ap);
-
-  if (need < STACK_BUF_SIZE) {
-    va_start(ap, message);
-    vsnprintf_s(stack_buf, STACK_BUF_SIZE, _TRUNCATE, message, ap);
-    va_end(ap);
-    f_(stack_buf);
-    return;
-  }
-#else
-  va_start(ap, message);
-  int need = vsnprintf(stack_buf, STACK_BUF_SIZE, message, ap);
-  va_end(ap);
-
-  if (need < STACK_BUF_SIZE) {
-    f_(stack_buf);
-    return;
-  }
-#endif
-
-  char *heap_buf = (char*)malloc((need+1) * sizeof(char));
-  if (heap_buf == NULL) {
-#ifdef _MSC_VER
-    va_start(ap, message);
-    vsnprintf_s(stack_buf, STACK_BUF_SIZE, _TRUNCATE, message, ap);
-    va_end(ap);
-#endif
-    // Malloc failed.  We might as well print the stack buffer.
-    f_(stack_buf);
-    return;
-  }
-
-  va_start(ap, message);
-  int rval = vsnprintf(heap_buf, need+1, message, ap);
-  va_end(ap);
-  // TODO(shigin): inform user
-  if (rval != -1) {
-    f_(heap_buf);
-  }
-  free(heap_buf);
-#endif
-}
-
-void TOutput::errorTimeWrapper(const char* msg) {
-#ifndef THRIFT_SQUELCH_CONSOLE_OUTPUT
-  time_t now;
-  char dbgtime[26];
-  time(&now);
-  THRIFT_CTIME_R(&now, dbgtime);
-  dbgtime[24] = 0;
-  fprintf(stderr, "Thrift: %s %s\n", dbgtime, msg);
-#endif
-}
-
-void TOutput::perror(const char *message, int errno_copy) {
-  std::string out = message + strerror_s(errno_copy);
-  f_(out.c_str());
-}
-
-std::string TOutput::strerror_s(int errno_copy) {
-#ifndef HAVE_STRERROR_R
-  return "errno = " + boost::lexical_cast<std::string>(errno_copy);
-#else  // HAVE_STRERROR_R
-
-  char b_errbuf[1024] = { '\0' };
-#ifdef STRERROR_R_CHAR_P
-  char *b_error = strerror_r(errno_copy, b_errbuf, sizeof(b_errbuf));
-#else
-  char *b_error = b_errbuf;
-  int rv = strerror_r(errno_copy, b_errbuf, sizeof(b_errbuf));
-  if (rv == -1) {
-    // strerror_r failed.  omgwtfbbq.
-    return "XSI-compliant strerror_r() failed with errno = " +
-      boost::lexical_cast<std::string>(errno_copy);
-  }
-#endif
-  // Can anyone prove that explicit cast is probably not necessary
-  // to ensure that the string object is constructed before
-  // b_error becomes invalid?
-  return std::string(b_error);
-
-#endif  // HAVE_STRERROR_R
-}
-
-}} // apache::thrift
diff --git a/lib/cpp/src/thrift/Thrift.h b/lib/cpp/src/thrift/Thrift.h
index 03caa9e..6322742 100644
--- a/lib/cpp/src/thrift/Thrift.h
+++ b/lib/cpp/src/thrift/Thrift.h
@@ -42,110 +42,46 @@
 #include <exception>
 #include <typeinfo>
 
-#include <boost/utility/enable_if.hpp>
-#include <boost/type_traits/is_convertible.hpp>
-
 #include <thrift/TLogging.h>
+#include <thrift/TOutput.h>
 
-/**
- * Helper macros to allow function overloading even when using
- * boost::shared_ptr.
- *
- * shared_ptr makes overloading really annoying, since shared_ptr defines
- * constructor methods to allow one shared_ptr type to be constructed from any
- * other shared_ptr type.  (Even if it would be a compile error to actually try
- * to instantiate the constructor.)  These macros add an extra argument to the
- * function to cause it to only be instantiated if a pointer of type T is
- * convertible to a pointer of type U.
- *
- * THRIFT_OVERLOAD_IF should be used in function declarations.
- * THRIFT_OVERLOAD_IF_DEFN should be used in the function definition, if it is
- * defined separately from where it is declared.
- */
-#define THRIFT_OVERLOAD_IF_DEFN(T, Y) \
-  typename ::boost::enable_if<typename ::boost::is_convertible<T*, Y*>::type, \
-                              void*>::type
+#define THRIFT_UNUSED_VARIABLE(x) ((void)(x))
 
-#define THRIFT_OVERLOAD_IF(T, Y) \
-  THRIFT_OVERLOAD_IF_DEFN(T, Y) = NULL
+namespace apache {
+namespace thrift {
 
-#define THRIFT_UNUSED_VARIABLE(x) ((x)=(x))
+class TEnumIterator
+    : public std::iterator<std::forward_iterator_tag, std::pair<int, const char*> > {
+public:
+  TEnumIterator(int n, int* enums, const char** names)
+    : ii_(0), n_(n), enums_(enums), names_(names) {}
 
-namespace apache { namespace thrift {
+  int operator++() { return ++ii_; }
 
-class TEnumIterator : public std::iterator<std::forward_iterator_tag, std::pair<int, const char*> > {
- public:
-  TEnumIterator(int n,
-                int* enums,
-                const char** names) :
-      ii_(0), n_(n), enums_(enums), names_(names) {
-  }
-
-  int operator ++() {
-    return ++ii_;
-  }
-
-  bool operator !=(const TEnumIterator& end) {
+  bool operator!=(const TEnumIterator& end) {
+    THRIFT_UNUSED_VARIABLE(end);
     assert(end.n_ == -1);
     return (ii_ != n_);
   }
 
-  std::pair<int, const char*> operator*() const {
-    return std::make_pair(enums_[ii_], names_[ii_]);
-  }
+  std::pair<int, const char*> operator*() const { return std::make_pair(enums_[ii_], names_[ii_]); }
 
- private:
+private:
   int ii_;
   const int n_;
   int* enums_;
   const char** names_;
 };
 
-class TOutput {
- public:
-  TOutput() : f_(&errorTimeWrapper) {}
-
-  inline void setOutputFunction(void (*function)(const char *)){
-    f_ = function;
-  }
-
-  inline void operator()(const char *message){
-    f_(message);
-  }
-
-  // It is important to have a const char* overload here instead of
-  // just the string version, otherwise errno could be corrupted
-  // if there is some problem allocating memory when constructing
-  // the string.
-  void perror(const char *message, int errno_copy);
-  inline void perror(const std::string &message, int errno_copy) {
-    perror(message.c_str(), errno_copy);
-  }
-
-  void printf(const char *message, ...);
-
-  static void errorTimeWrapper(const char* msg);
-
-  /** Just like strerror_r but returns a C++ string object. */
-  static std::string strerror_s(int errno_copy);
-
- private:
-  void (*f_)(const char *);
-};
-
-extern TOutput GlobalOutput;
-
 class TException : public std::exception {
- public:
-  TException():
-    message_() {}
+public:
+  TException() : message_() {}
 
-  TException(const std::string& message) :
-    message_(message) {}
+  TException(const std::string& message) : message_(message) {}
 
-  virtual ~TException() throw() {}
+  virtual ~TException() noexcept {}
 
-  virtual const char* what() const throw() {
+  virtual const char* what() const noexcept {
     if (message_.empty()) {
       return "Default TException.";
     } else {
@@ -153,33 +89,29 @@
     }
   }
 
- protected:
+protected:
   std::string message_;
-
 };
 
-
-// Forward declare this structure used by TDenseProtocol
-namespace reflection { namespace local {
-struct TypeSpec;
-}}
-
 class TDelayedException {
- public:
-  template <class E> static TDelayedException* delayException(const E& e);
+public:
+  template <class E>
+  static TDelayedException* delayException(const E& e);
   virtual void throw_it() = 0;
-  virtual ~TDelayedException() {};
+  virtual ~TDelayedException(){};
 };
 
-template <class E> class TExceptionWrapper : public TDelayedException {
- public:
+template <class E>
+class TExceptionWrapper : public TDelayedException {
+public:
   TExceptionWrapper(const E& e) : e_(e) {}
   virtual void throw_it() {
     E temp(e_);
     delete this;
     throw temp;
   }
- private:
+
+private:
   E e_;
 };
 
@@ -190,13 +122,12 @@
 
 #if T_GLOBAL_DEBUG_VIRTUAL > 1
 void profile_virtual_call(const std::type_info& info);
-void profile_generic_protocol(const std::type_info& template_type,
-                              const std::type_info& prot_type);
-void profile_print_info(FILE *f);
+void profile_generic_protocol(const std::type_info& template_type, const std::type_info& prot_type);
+void profile_print_info(FILE* f);
 void profile_print_info();
 void profile_write_pprof(FILE* gen_calls_f, FILE* virtual_calls_f);
 #endif
-
-}} // apache::thrift
+}
+} // apache::thrift
 
 #endif // #ifndef _THRIFT_THRIFT_H_
diff --git a/lib/cpp/src/thrift/VirtualProfiling.cpp b/lib/cpp/src/thrift/VirtualProfiling.cpp
index 180cfb7..6ce346b 100644
--- a/lib/cpp/src/thrift/VirtualProfiling.cpp
+++ b/lib/cpp/src/thrift/VirtualProfiling.cpp
@@ -35,14 +35,14 @@
 #error "Thrift virtual function profiling currently requires glibc"
 #endif // !__GLIBC__
 
-
 #include <thrift/concurrency/Mutex.h>
 
 #include <ext/hash_map>
 #include <execinfo.h>
 #include <stdio.h>
 
-namespace apache { namespace thrift {
+namespace apache {
+namespace thrift {
 
 using ::apache::thrift::concurrency::Mutex;
 using ::apache::thrift::concurrency::Guard;
@@ -53,20 +53,18 @@
  * A stack trace
  */
 class Backtrace {
- public:
+public:
   Backtrace(int skip = 0);
-  Backtrace(Backtrace const &bt);
+  Backtrace(Backtrace const& bt);
 
-  void operator=(Backtrace const &bt) {
+  void operator=(Backtrace const& bt) {
     numCallers_ = bt.numCallers_;
     if (numCallers_ >= 0) {
       memcpy(callers_, bt.callers_, numCallers_ * sizeof(void*));
     }
   }
 
-  bool operator==(Backtrace const &bt) const {
-    return (cmp(bt) == 0);
-  }
+  bool operator==(Backtrace const& bt) const { return (cmp(bt) == 0); }
 
   size_t hash() const {
     intptr_t ret = 0;
@@ -83,8 +81,8 @@
     }
 
     for (int n = 0; n < numCallers_; ++n) {
-      int diff = reinterpret_cast<intptr_t>(callers_[n]) -
-        reinterpret_cast<intptr_t>(bt.callers_[n]);
+      int diff = reinterpret_cast<intptr_t>(callers_[n])
+                 - reinterpret_cast<intptr_t>(bt.callers_[n]);
       if (diff != 0) {
         return diff;
       }
@@ -93,8 +91,8 @@
     return 0;
   }
 
-  void print(FILE *f, int indent=0, int start=0) const {
-    char **strings = backtrace_symbols(callers_, numCallers_);
+  void print(FILE* f, int indent = 0, int start = 0) const {
+    char** strings = backtrace_symbols(callers_, numCallers_);
     if (strings) {
       start += skip_;
       if (start < 0) {
@@ -109,11 +107,9 @@
     }
   }
 
-  int getDepth() const {
-    return numCallers_ - skip_;
-  }
+  int getDepth() const { return numCallers_ - skip_; }
 
-  void *getFrame(int index) const {
+  void* getFrame(int index) const {
     int adjusted_index = index + skip_;
     if (adjusted_index < 0 || adjusted_index >= numCallers_) {
       return NULL;
@@ -121,8 +117,8 @@
     return callers_[adjusted_index];
   }
 
- private:
-  void *callers_[MAX_STACK_DEPTH];
+private:
+  void* callers_[MAX_STACK_DEPTH];
   int numCallers_;
   int skip_;
 };
@@ -138,9 +134,7 @@
   }
 }
 
-Backtrace::Backtrace(Backtrace const &bt)
-  : numCallers_(bt.numCallers_)
-  , skip_(bt.skip_) {
+Backtrace::Backtrace(Backtrace const& bt) : numCallers_(bt.numCallers_), skip_(bt.skip_) {
   if (numCallers_ >= 0) {
     memcpy(callers_, bt.callers_, numCallers_ * sizeof(void*));
   }
@@ -150,32 +144,20 @@
  * A backtrace, plus one or two type names
  */
 class Key {
- public:
+public:
   class Hash {
-   public:
-    size_t operator()(Key const& k) const {
-      return k.hash();
-    }
+  public:
+    size_t operator()(Key const& k) const { return k.hash(); }
   };
 
   Key(const Backtrace* bt, const std::type_info& type_info)
-    : backtrace_(bt)
-    , typeName1_(type_info.name())
-    , typeName2_(NULL) {
-  }
+    : backtrace_(bt), typeName1_(type_info.name()), typeName2_(NULL) {}
 
-  Key(const Backtrace* bt, const std::type_info& type_info1,
-      const std::type_info& type_info2)
-    : backtrace_(bt)
-    , typeName1_(type_info1.name())
-    , typeName2_(type_info2.name()) {
-  }
+  Key(const Backtrace* bt, const std::type_info& type_info1, const std::type_info& type_info2)
+    : backtrace_(bt), typeName1_(type_info1.name()), typeName2_(type_info2.name()) {}
 
   Key(const Key& k)
-    : backtrace_(k.backtrace_)
-    , typeName1_(k.typeName1_)
-    , typeName2_(k.typeName2_) {
-  }
+    : backtrace_(k.backtrace_), typeName1_(k.typeName1_), typeName2_(k.typeName2_) {}
 
   void operator=(const Key& k) {
     backtrace_ = k.backtrace_;
@@ -183,17 +165,11 @@
     typeName2_ = k.typeName2_;
   }
 
-  const Backtrace* getBacktrace() const {
-    return backtrace_;
-  }
+  const Backtrace* getBacktrace() const { return backtrace_; }
 
-  const char* getTypeName() const {
-    return typeName1_;
-  }
+  const char* getTypeName() const { return typeName1_; }
 
-  const char* getTypeName2() const {
-    return typeName2_;
-  }
+  const char* getTypeName2() const { return typeName2_; }
 
   void makePersistent() {
     // Copy the Backtrace object
@@ -233,20 +209,17 @@
     return k.typeName2_ - typeName2_;
   }
 
-  bool operator==(const Key& k) const {
-    return cmp(k) == 0;
-  }
+  bool operator==(const Key& k) const { return cmp(k) == 0; }
 
   size_t hash() const {
     // NOTE: As above, we just use the name pointer value.
     // Works with GNU libstdc++, but not guaranteed to be correct on all
     // implementations.
-    return backtrace_->hash() ^
-      reinterpret_cast<size_t>(typeName1_) ^
-      reinterpret_cast<size_t>(typeName2_);
+    return backtrace_->hash() ^ reinterpret_cast<size_t>(typeName1_)
+           ^ reinterpret_cast<size_t>(typeName2_);
   }
 
- private:
+private:
   const Backtrace* backtrace_;
   const char* typeName1_;
   const char* typeName2_;
@@ -257,9 +230,8 @@
  * has a higher count.
  */
 class CountGreater {
- public:
-  bool operator()(std::pair<Key, size_t> bt1,
-                  std::pair<Key, size_t> bt2) const {
+public:
+  bool operator()(std::pair<Key, size_t> bt1, std::pair<Key, size_t> bt2) const {
     return bt1.second > bt2.second;
   }
 };
@@ -278,8 +250,7 @@
 BacktraceMap generic_calls;
 Mutex generic_calls_mutex;
 
-
-void _record_backtrace(BacktraceMap* map, const Mutex& mutex, Key *k) {
+void _record_backtrace(BacktraceMap* map, const Mutex& mutex, Key* k) {
   Guard guard(mutex);
 
   BacktraceMap::iterator it = map->find(*k);
@@ -324,7 +295,7 @@
  * Print the recorded profiling information to the specified file.
  */
 void profile_print_info(FILE* f) {
-  typedef std::vector< std::pair<Key, size_t> > BacktraceVector;
+  typedef std::vector<std::pair<Key, size_t> > BacktraceVector;
 
   CountGreater is_greater;
 
@@ -342,13 +313,14 @@
   BacktraceVector gp_sorted(generic_calls.begin(), generic_calls.end());
   std::sort(gp_sorted.begin(), gp_sorted.end(), is_greater);
 
-  for (BacktraceVector::const_iterator it = gp_sorted.begin();
-       it != gp_sorted.end();
-       ++it) {
-    Key const &key = it->first;
+  for (BacktraceVector::const_iterator it = gp_sorted.begin(); it != gp_sorted.end(); ++it) {
+    Key const& key = it->first;
     size_t const count = it->second;
-    fprintf(f, "T_GENERIC_PROTOCOL: %zu calls to %s with a %s:\n",
-            count, key.getTypeName(), key.getTypeName2());
+    fprintf(f,
+            "T_GENERIC_PROTOCOL: %zu calls to %s with a %s:\n",
+            count,
+            key.getTypeName(),
+            key.getTypeName2());
     key.getBacktrace()->print(f, 2);
     fprintf(f, "\n");
   }
@@ -357,10 +329,8 @@
   BacktraceVector vc_sorted(virtual_calls.begin(), virtual_calls.end());
   std::sort(vc_sorted.begin(), vc_sorted.end(), is_greater);
 
-  for (BacktraceVector::const_iterator it = vc_sorted.begin();
-       it != vc_sorted.end();
-       ++it) {
-    Key const &key = it->first;
+  for (BacktraceVector::const_iterator it = vc_sorted.begin(); it != vc_sorted.end(); ++it) {
+    Key const& key = it->first;
     size_t const count = it->second;
     fprintf(f, "T_VIRTUAL_CALL: %zu calls on %s:\n", count, key.getTypeName());
     key.getBacktrace()->print(f, 2);
@@ -380,7 +350,7 @@
  */
 static void profile_write_pprof_file(FILE* f, BacktraceMap const& map) {
   // Write the header
-  uintptr_t header[5] = { 0, 3, 0, 0, 0 };
+  uintptr_t header[5] = {0, 3, 0, 0, 0};
   fwrite(&header, sizeof(header), 1, f);
 
   // Write the profile records
@@ -399,12 +369,12 @@
   }
 
   // Write the trailer
-  uintptr_t trailer[3] = { 0, 1, 0 };
+  uintptr_t trailer[3] = {0, 1, 0};
   fwrite(&trailer, sizeof(trailer), 1, f);
 
   // Write /proc/self/maps
   // TODO(simpkins): This only works on linux
-  FILE *proc_maps = fopen("/proc/self/maps", "r");
+  FILE* proc_maps = fopen("/proc/self/maps", "r");
   if (proc_maps) {
     uint8_t buf[4096];
     while (true) {
@@ -434,7 +404,7 @@
  *                        profile_virtual_call() will be written to this file.
  */
 void profile_write_pprof(FILE* gen_calls_f, FILE* virtual_calls_f) {
-  typedef std::vector< std::pair<Key, size_t> > BacktraceVector;
+  typedef std::vector<std::pair<Key, size_t> > BacktraceVector;
 
   CountGreater is_greater;
 
@@ -449,7 +419,7 @@
   // write the info from virtual_calls
   profile_write_pprof_file(virtual_calls_f, virtual_calls);
 }
-
-}} // apache::thrift
+}
+} // apache::thrift
 
 #endif // T_GLOBAL_PROFILE_VIRTUAL > 0
diff --git a/lib/cpp/src/thrift/async/TAsyncBufferProcessor.h b/lib/cpp/src/thrift/async/TAsyncBufferProcessor.h
index ad7c639..9c96b14 100644
--- a/lib/cpp/src/thrift/async/TAsyncBufferProcessor.h
+++ b/lib/cpp/src/thrift/async/TAsyncBufferProcessor.h
@@ -20,27 +20,27 @@
 #ifndef _THRIFT_TASYNC_BUFFER_PROCESSOR_H_
 #define _THRIFT_TASYNC_BUFFER_PROCESSOR_H_ 1
 
-#include <thrift/cxxfunctional.h>
-#include <boost/shared_ptr.hpp>
-
+#include <memory>
 #include <thrift/transport/TBufferTransports.h>
 
-namespace apache { namespace thrift { namespace async {
+namespace apache {
+namespace thrift {
+namespace async {
 
 class TAsyncBufferProcessor {
- public:
+public:
   // Process data in "in", putting the result in "out".
   // Call _return(true) when done, or _return(false) to
   // forcefully close the connection (if applicable).
   // "in" and "out" should be TMemoryBuffer or similar,
   // not a wrapper around a socket.
-  virtual void process(
-      apache::thrift::stdcxx::function<void(bool healthy)> _return,
-      boost::shared_ptr<apache::thrift::transport::TBufferBase> ibuf,
-      boost::shared_ptr<apache::thrift::transport::TBufferBase> obuf) = 0;
+  virtual void process(std::function<void(bool healthy)> _return,
+                       std::shared_ptr<transport::TBufferBase> ibuf,
+                       std::shared_ptr<transport::TBufferBase> obuf) = 0;
   virtual ~TAsyncBufferProcessor() {}
 };
-
-}}} // apache::thrift::async
+}
+}
+} // apache::thrift::async
 
 #endif // #ifndef _THRIFT_TASYNC_BUFFER_PROCESSOR_H_
diff --git a/lib/cpp/src/thrift/async/TAsyncChannel.cpp b/lib/cpp/src/thrift/async/TAsyncChannel.cpp
index 64dfe5f..01b9113 100644
--- a/lib/cpp/src/thrift/async/TAsyncChannel.cpp
+++ b/lib/cpp/src/thrift/async/TAsyncChannel.cpp
@@ -18,17 +18,19 @@
  */
 
 #include <thrift/async/TAsyncChannel.h>
-#include <thrift/cxxfunctional.h>
 
-namespace apache { namespace thrift { namespace async {
+namespace apache {
+namespace thrift {
+namespace async {
 
 void TAsyncChannel::sendAndRecvMessage(const VoidCallback& cob,
                                        TMemoryBuffer* sendBuf,
                                        TMemoryBuffer* recvBuf) {
-  apache::thrift::stdcxx::function<void()> send_done =
-    apache::thrift::stdcxx::bind(&TAsyncChannel::recvMessage, this, cob, recvBuf);
+  std::function<void()> send_done
+      = std::bind(&TAsyncChannel::recvMessage, this, cob, recvBuf);
 
   sendMessage(send_done, sendBuf);
 }
-
-}}}  // apache::thrift::async
+}
+}
+} // apache::thrift::async
diff --git a/lib/cpp/src/thrift/async/TAsyncChannel.h b/lib/cpp/src/thrift/async/TAsyncChannel.h
index 0f202fd..d7ace96 100644
--- a/lib/cpp/src/thrift/async/TAsyncChannel.h
+++ b/lib/cpp/src/thrift/async/TAsyncChannel.h
@@ -20,19 +20,26 @@
 #ifndef _THRIFT_ASYNC_TASYNCCHANNEL_H_
 #define _THRIFT_ASYNC_TASYNCCHANNEL_H_ 1
 
-#include <thrift/cxxfunctional.h>
+#include <functional>
+#include <memory>
 #include <thrift/Thrift.h>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 class TMemoryBuffer;
-}}}
+}
+}
+}
 
-namespace apache { namespace thrift { namespace async {
+namespace apache {
+namespace thrift {
+namespace async {
 using apache::thrift::transport::TMemoryBuffer;
 
 class TAsyncChannel {
- public:
-  typedef apache::thrift::stdcxx::function<void()> VoidCallback;
+public:
+  typedef std::function<void()> VoidCallback;
 
   virtual ~TAsyncChannel() {}
 
@@ -45,22 +52,23 @@
    * Send a message over the channel.
    */
   virtual void sendMessage(const VoidCallback& cob,
-    apache::thrift::transport::TMemoryBuffer* message) = 0;
+                           apache::thrift::transport::TMemoryBuffer* message) = 0;
 
   /**
    * Receive a message from the channel.
    */
   virtual void recvMessage(const VoidCallback& cob,
-    apache::thrift::transport::TMemoryBuffer* message) = 0;
+                           apache::thrift::transport::TMemoryBuffer* message) = 0;
 
   /**
    * Send a message over the channel and receive a response.
    */
   virtual void sendAndRecvMessage(const VoidCallback& cob,
-    apache::thrift::transport::TMemoryBuffer* sendBuf,
-    apache::thrift::transport::TMemoryBuffer* recvBuf);
+                                  apache::thrift::transport::TMemoryBuffer* sendBuf,
+                                  apache::thrift::transport::TMemoryBuffer* recvBuf);
 };
-
-}}} // apache::thrift::async
+}
+}
+} // apache::thrift::async
 
 #endif // #ifndef _THRIFT_ASYNC_TASYNCCHANNEL_H_
diff --git a/lib/cpp/src/thrift/async/TAsyncDispatchProcessor.h b/lib/cpp/src/thrift/async/TAsyncDispatchProcessor.h
index 15b5bce..59db597 100644
--- a/lib/cpp/src/thrift/async/TAsyncDispatchProcessor.h
+++ b/lib/cpp/src/thrift/async/TAsyncDispatchProcessor.h
@@ -21,7 +21,9 @@
 
 #include <thrift/async/TAsyncProcessor.h>
 
-namespace apache { namespace thrift { namespace async {
+namespace apache {
+namespace thrift {
+namespace async {
 
 /**
  * TAsyncDispatchProcessor is a helper class to parse the message header then
@@ -31,10 +33,10 @@
  */
 template <class Protocol_>
 class TAsyncDispatchProcessorT : public TAsyncProcessor {
- public:
-  virtual void process(apache::thrift::stdcxx::function<void(bool success)> _return,
-                       boost::shared_ptr<protocol::TProtocol> in,
-                       boost::shared_ptr<protocol::TProtocol> out) {
+public:
+  virtual void process(std::function<void(bool success)> _return,
+                       std::shared_ptr<protocol::TProtocol> in,
+                       std::shared_ptr<protocol::TProtocol> out) {
     protocol::TProtocol* inRaw = in.get();
     protocol::TProtocol* outRaw = out.get();
 
@@ -60,8 +62,7 @@
     // (The old generated processor code used to try to skip a T_STRUCT and
     // continue.  However, that seems unsafe.)
     if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
-      GlobalOutput.printf("received invalid message type %d from client",
-                          mtype);
+      GlobalOutput.printf("received invalid message type %d from client", mtype);
       _return(false);
       return;
     }
@@ -69,16 +70,16 @@
     return this->dispatchCall(_return, inRaw, outRaw, fname, seqid);
   }
 
-  void processFast(apache::thrift::stdcxx::function<void(bool success)> _return,
-                   Protocol_* in, Protocol_* out) {
+  void processFast(std::function<void(bool success)> _return,
+                   Protocol_* in,
+                   Protocol_* out) {
     std::string fname;
     protocol::TMessageType mtype;
     int32_t seqid;
     in->readMessageBegin(fname, mtype, seqid);
 
     if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
-      GlobalOutput.printf("received invalid message type %d from client",
-                          mtype);
+      GlobalOutput.printf("received invalid message type %d from client", mtype);
       _return(false);
       return;
     }
@@ -86,13 +87,15 @@
     return this->dispatchCallTemplated(_return, in, out, fname, seqid);
   }
 
-  virtual void dispatchCall(apache::thrift::stdcxx::function<void(bool ok)> _return,
+  virtual void dispatchCall(std::function<void(bool ok)> _return,
                             apache::thrift::protocol::TProtocol* in,
                             apache::thrift::protocol::TProtocol* out,
-                            const std::string& fname, int32_t seqid) = 0;
+                            const std::string& fname,
+                            int32_t seqid) = 0;
 
-  virtual void dispatchCallTemplated(apache::thrift::stdcxx::function<void(bool ok)> _return,
-                                     Protocol_* in, Protocol_* out,
+  virtual void dispatchCallTemplated(std::function<void(bool ok)> _return,
+                                     Protocol_* in,
+                                     Protocol_* out,
                                      const std::string& fname,
                                      int32_t seqid) = 0;
 };
@@ -102,10 +105,10 @@
  * that doesn't bother trying to perform a dynamic_cast.
  */
 class TAsyncDispatchProcessor : public TAsyncProcessor {
- public:
-  virtual void process(apache::thrift::stdcxx::function<void(bool success)> _return,
-                       boost::shared_ptr<protocol::TProtocol> in,
-                       boost::shared_ptr<protocol::TProtocol> out) {
+public:
+  virtual void process(std::function<void(bool success)> _return,
+                       std::shared_ptr<protocol::TProtocol> in,
+                       std::shared_ptr<protocol::TProtocol> out) {
     protocol::TProtocol* inRaw = in.get();
     protocol::TProtocol* outRaw = out.get();
 
@@ -120,8 +123,7 @@
     // (The old generated processor code used to try to skip a T_STRUCT and
     // continue.  However, that seems unsafe.)
     if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
-      GlobalOutput.printf("received invalid message type %d from client",
-                          mtype);
+      GlobalOutput.printf("received invalid message type %d from client", mtype);
       _return(false);
       return;
     }
@@ -129,21 +131,21 @@
     return dispatchCall(_return, inRaw, outRaw, fname, seqid);
   }
 
-  virtual void dispatchCall(apache::thrift::stdcxx::function<void(bool ok)> _return,
+  virtual void dispatchCall(std::function<void(bool ok)> _return,
                             apache::thrift::protocol::TProtocol* in,
                             apache::thrift::protocol::TProtocol* out,
-                            const std::string& fname, int32_t seqid) = 0;
+                            const std::string& fname,
+                            int32_t seqid) = 0;
 };
 
 // Specialize TAsyncDispatchProcessorT for TProtocol and TDummyProtocol just to
 // use the generic TDispatchProcessor.
 template <>
-class TAsyncDispatchProcessorT<protocol::TDummyProtocol> :
-  public TAsyncDispatchProcessor {};
+class TAsyncDispatchProcessorT<protocol::TDummyProtocol> : public TAsyncDispatchProcessor {};
 template <>
-class TAsyncDispatchProcessorT<protocol::TProtocol> :
-  public TAsyncDispatchProcessor {};
-
-}}} // apache::thrift::async
+class TAsyncDispatchProcessorT<protocol::TProtocol> : public TAsyncDispatchProcessor {};
+}
+}
+} // apache::thrift::async
 
 #endif // _THRIFT_ASYNC_TASYNCDISPATCHPROCESSOR_H_
diff --git a/lib/cpp/src/thrift/async/TAsyncProcessor.h b/lib/cpp/src/thrift/async/TAsyncProcessor.h
index a03d1dc..fdb976d 100644
--- a/lib/cpp/src/thrift/async/TAsyncProcessor.h
+++ b/lib/cpp/src/thrift/async/TAsyncProcessor.h
@@ -20,58 +20,46 @@
 #ifndef _THRIFT_TASYNCPROCESSOR_H_
 #define _THRIFT_TASYNCPROCESSOR_H_ 1
 
-#include <thrift/cxxfunctional.h>
-#include <boost/shared_ptr.hpp>
 #include <thrift/protocol/TProtocol.h>
+#include <memory>
 #include <thrift/TProcessor.h>
 
-namespace apache { namespace thrift { namespace async {
+namespace apache {
+namespace thrift {
+namespace async {
 
 /**
  * Async version of a TProcessor.  It is not expected to complete by the time
  * the call to process returns.  Instead, it calls a cob to signal completion.
  */
 
-class TEventServer; // forward declaration
-
 class TAsyncProcessor {
- public:
+public:
   virtual ~TAsyncProcessor() {}
 
-  virtual void process(apache::thrift::stdcxx::function<void(bool success)> _return,
-                       boost::shared_ptr<protocol::TProtocol> in,
-                       boost::shared_ptr<protocol::TProtocol> out) = 0;
+  virtual void process(std::function<void(bool success)> _return,
+                       std::shared_ptr<protocol::TProtocol> in,
+                       std::shared_ptr<protocol::TProtocol> out) = 0;
 
-  void process(apache::thrift::stdcxx::function<void(bool success)> _return,
-               boost::shared_ptr<apache::thrift::protocol::TProtocol> io) {
+  void process(std::function<void(bool success)> _return,
+               std::shared_ptr<protocol::TProtocol> io) {
     return process(_return, io, io);
   }
 
-  boost::shared_ptr<TProcessorEventHandler> getEventHandler() {
-    return eventHandler_;
-  }
+  std::shared_ptr<TProcessorEventHandler> getEventHandler() const { return eventHandler_; }
 
-  void setEventHandler(boost::shared_ptr<TProcessorEventHandler> eventHandler) {
+  void setEventHandler(std::shared_ptr<TProcessorEventHandler> eventHandler) {
     eventHandler_ = eventHandler;
   }
 
-  const TEventServer* getAsyncServer() {
-    return asyncServer_;
-  }
- protected:
+protected:
   TAsyncProcessor() {}
 
-  boost::shared_ptr<TProcessorEventHandler> eventHandler_;
-  const TEventServer* asyncServer_;
- private:
-  friend class TEventServer;
-  void setAsyncServer(const TEventServer* server) {
-    asyncServer_ = server;
-  }
+  std::shared_ptr<TProcessorEventHandler> eventHandler_;
 };
 
 class TAsyncProcessorFactory {
- public:
+public:
   virtual ~TAsyncProcessorFactory() {}
 
   /**
@@ -81,17 +69,16 @@
    * accepted on.  This generally means that this call does not need to be
    * thread safe, as it will always be invoked from a single thread.
    */
-  virtual boost::shared_ptr<TAsyncProcessor> getProcessor(
-      const TConnectionInfo& connInfo) = 0;
+  virtual std::shared_ptr<TAsyncProcessor> getProcessor(const TConnectionInfo& connInfo) = 0;
 };
+}
+}
+} // apache::thrift::async
 
-
-
-}}} // apache::thrift::async
-
-// XXX I'm lazy for now
-namespace apache { namespace thrift {
-using apache::thrift::async::TAsyncProcessor;
-}}
+namespace apache {
+namespace thrift {
+  using apache::thrift::async::TAsyncProcessor;
+}
+}
 
 #endif // #ifndef _THRIFT_TASYNCPROCESSOR_H_
diff --git a/lib/cpp/src/thrift/async/TAsyncProtocolProcessor.cpp b/lib/cpp/src/thrift/async/TAsyncProtocolProcessor.cpp
index 2096289..cb5201b 100644
--- a/lib/cpp/src/thrift/async/TAsyncProtocolProcessor.cpp
+++ b/lib/cpp/src/thrift/async/TAsyncProtocolProcessor.cpp
@@ -22,30 +22,32 @@
 using apache::thrift::transport::TBufferBase;
 using apache::thrift::protocol::TProtocol;
 
-namespace apache { namespace thrift { namespace async {
+namespace apache {
+namespace thrift {
+namespace async {
 
-void TAsyncProtocolProcessor::process(
-    apache::thrift::stdcxx::function<void(bool healthy)> _return,
-    boost::shared_ptr<TBufferBase> ibuf,
-    boost::shared_ptr<TBufferBase> obuf) {
-  boost::shared_ptr<TProtocol> iprot(pfact_->getProtocol(ibuf));
-  boost::shared_ptr<TProtocol> oprot(pfact_->getProtocol(obuf));
-  return underlying_->process(
-      apache::thrift::stdcxx::bind(
-        &TAsyncProtocolProcessor::finish,
-        _return,
-        oprot,
-        apache::thrift::stdcxx::placeholders::_1),
-      iprot, oprot);
+void TAsyncProtocolProcessor::process(std::function<void(bool healthy)> _return,
+                                      std::shared_ptr<TBufferBase> ibuf,
+                                      std::shared_ptr<TBufferBase> obuf) {
+  std::shared_ptr<TProtocol> iprot(pfact_->getProtocol(ibuf));
+  std::shared_ptr<TProtocol> oprot(pfact_->getProtocol(obuf));
+  return underlying_
+      ->process(std::bind(&TAsyncProtocolProcessor::finish,
+                                             _return,
+                                             oprot,
+                                             std::placeholders::_1),
+                iprot,
+                oprot);
 }
 
 /* static */ void TAsyncProtocolProcessor::finish(
-    apache::thrift::stdcxx::function<void(bool healthy)> _return,
-    boost::shared_ptr<TProtocol> oprot,
+    std::function<void(bool healthy)> _return,
+    std::shared_ptr<TProtocol> oprot,
     bool healthy) {
-  (void) oprot;
+  (void)oprot;
   // This is a stub function to hold a reference to oprot.
   return _return(healthy);
 }
-
-}}} // apache::thrift::async
+}
+}
+} // apache::thrift::async
diff --git a/lib/cpp/src/thrift/async/TAsyncProtocolProcessor.h b/lib/cpp/src/thrift/async/TAsyncProtocolProcessor.h
index 840b4dd..8052cf3 100644
--- a/lib/cpp/src/thrift/async/TAsyncProtocolProcessor.h
+++ b/lib/cpp/src/thrift/async/TAsyncProtocolProcessor.h
@@ -24,34 +24,32 @@
 #include <thrift/async/TAsyncBufferProcessor.h>
 #include <thrift/protocol/TProtocol.h>
 
-namespace apache { namespace thrift { namespace async {
+namespace apache {
+namespace thrift {
+namespace async {
 
 class TAsyncProtocolProcessor : public TAsyncBufferProcessor {
- public:
-  TAsyncProtocolProcessor(
-      boost::shared_ptr<TAsyncProcessor> underlying,
-      boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> pfact)
-    : underlying_(underlying)
-    , pfact_(pfact)
-  {}
+public:
+  TAsyncProtocolProcessor(std::shared_ptr<TAsyncProcessor> underlying,
+                          std::shared_ptr<apache::thrift::protocol::TProtocolFactory> pfact)
+    : underlying_(underlying), pfact_(pfact) {}
 
-  virtual void process(
-      apache::thrift::stdcxx::function<void(bool healthy)> _return,
-      boost::shared_ptr<apache::thrift::transport::TBufferBase> ibuf,
-      boost::shared_ptr<apache::thrift::transport::TBufferBase> obuf);
+  virtual void process(std::function<void(bool healthy)> _return,
+                       std::shared_ptr<apache::thrift::transport::TBufferBase> ibuf,
+                       std::shared_ptr<apache::thrift::transport::TBufferBase> obuf);
 
   virtual ~TAsyncProtocolProcessor() {}
 
- private:
-  static void finish(
-      apache::thrift::stdcxx::function<void(bool healthy)> _return,
-      boost::shared_ptr<apache::thrift::protocol::TProtocol> oprot,
-      bool healthy);
+private:
+  static void finish(std::function<void(bool healthy)> _return,
+                     std::shared_ptr<apache::thrift::protocol::TProtocol> oprot,
+                     bool healthy);
 
-  boost::shared_ptr<TAsyncProcessor> underlying_;
-  boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> pfact_;
+  std::shared_ptr<TAsyncProcessor> underlying_;
+  std::shared_ptr<apache::thrift::protocol::TProtocolFactory> pfact_;
 };
-
-}}} // apache::thrift::async
+}
+}
+} // apache::thrift::async
 
 #endif // #ifndef _THRIFT_TNAME_ME_H_
diff --git a/lib/cpp/src/thrift/async/TConcurrentClientSyncInfo.cpp b/lib/cpp/src/thrift/async/TConcurrentClientSyncInfo.cpp
new file mode 100644
index 0000000..c7e27c0
--- /dev/null
+++ b/lib/cpp/src/thrift/async/TConcurrentClientSyncInfo.cpp
@@ -0,0 +1,242 @@
+/*
+ * 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.
+ */
+
+#include <thrift/async/TConcurrentClientSyncInfo.h>
+#include <thrift/TApplicationException.h>
+#include <thrift/transport/TTransportException.h>
+#include <limits>
+
+namespace apache { namespace thrift { namespace async {
+
+using namespace ::apache::thrift::concurrency;
+
+TConcurrentClientSyncInfo::TConcurrentClientSyncInfo() :
+  stop_(false),
+  seqidMutex_(),
+  // test rollover all the time
+  nextseqid_((std::numeric_limits<int32_t>::max)()-10),
+  seqidToMonitorMap_(),
+  freeMonitors_(),
+  writeMutex_(),
+  readMutex_(),
+  recvPending_(false),
+  wakeupSomeone_(false),
+  seqidPending_(0),
+  fnamePending_(),
+  mtypePending_(::apache::thrift::protocol::T_CALL)
+{
+  freeMonitors_.reserve(MONITOR_CACHE_SIZE);
+}
+
+bool TConcurrentClientSyncInfo::getPending(
+  std::string &fname,
+  ::apache::thrift::protocol::TMessageType &mtype,
+  int32_t &rseqid)
+{
+  if(stop_)
+    throwDeadConnection_();
+  wakeupSomeone_ = false;
+  if(recvPending_)
+  {
+    recvPending_ = false;
+    rseqid = seqidPending_;
+    fname  = fnamePending_;
+    mtype  = mtypePending_;
+    return true;
+  }
+  return false;
+}
+
+void TConcurrentClientSyncInfo::updatePending(
+  const std::string &fname,
+  ::apache::thrift::protocol::TMessageType mtype,
+  int32_t rseqid)
+{
+  recvPending_ = true;
+  seqidPending_ = rseqid;
+  fnamePending_ = fname;
+  mtypePending_ = mtype;
+  MonitorPtr monitor;
+  {
+    Guard seqidGuard(seqidMutex_);
+    MonitorMap::iterator i = seqidToMonitorMap_.find(rseqid);
+    if(i == seqidToMonitorMap_.end())
+      throwBadSeqId_();
+    monitor = i->second;
+  }
+  monitor->notify();
+}
+
+void TConcurrentClientSyncInfo::waitForWork(int32_t seqid)
+{
+  MonitorPtr m;
+  {
+    Guard seqidGuard(seqidMutex_);
+    m = seqidToMonitorMap_[seqid];
+  }
+  while(true)
+  {
+    // be very careful about setting state in this loop that affects waking up.  You may exit
+    // this function, attempt to grab some work, and someone else could have beaten you (or not
+    // left) the read mutex, and that will put you right back in this loop, with the mangled
+    // state you left behind.
+    if(stop_)
+      throwDeadConnection_();
+    if(wakeupSomeone_)
+      return;
+    if(recvPending_ && seqidPending_ == seqid)
+      return;
+    m->waitForever();
+  }
+}
+
+void TConcurrentClientSyncInfo::throwBadSeqId_()
+{
+  throw apache::thrift::TApplicationException(
+    TApplicationException::BAD_SEQUENCE_ID,
+    "server sent a bad seqid");
+}
+
+void TConcurrentClientSyncInfo::throwDeadConnection_()
+{
+  throw apache::thrift::transport::TTransportException(
+    apache::thrift::transport::TTransportException::NOT_OPEN,
+    "this client died on another thread, and is now in an unusable state");
+}
+
+void TConcurrentClientSyncInfo::wakeupAnyone_(const Guard &)
+{
+  wakeupSomeone_ = true;
+  if(!seqidToMonitorMap_.empty())
+  {
+    // The monitor map maps integers to monitors.  Larger integers are more recent
+    // messages.  Since this is ordered, it means that the last element is the most recent.
+    // We are trying to guess which thread will have its message complete next, so we are picking
+    // the most recent. The oldest message is likely to be some polling, long lived message.
+    // If we guess right, the thread we wake up will handle the message that comes in.
+    // If we guess wrong, the thread we wake up will hand off the work to the correct thread,
+    // costing us an extra context switch.
+    seqidToMonitorMap_.rbegin()->second->notify();
+  }
+}
+
+void TConcurrentClientSyncInfo::markBad_(const Guard &)
+{
+  wakeupSomeone_ = true;
+  stop_ = true;
+  for(MonitorMap::iterator i = seqidToMonitorMap_.begin(); i != seqidToMonitorMap_.end(); ++i)
+    i->second->notify();
+}
+
+TConcurrentClientSyncInfo::MonitorPtr
+TConcurrentClientSyncInfo::newMonitor_(const Guard &)
+{
+  if(freeMonitors_.empty())
+    return MonitorPtr(new Monitor(&readMutex_));
+  MonitorPtr retval;
+  //swapping to avoid an atomic operation
+  retval.swap(freeMonitors_.back());
+  freeMonitors_.pop_back();
+  return retval;
+}
+
+void TConcurrentClientSyncInfo::deleteMonitor_(
+  const Guard &,
+  TConcurrentClientSyncInfo::MonitorPtr &m) /*noexcept*/
+{
+  if(freeMonitors_.size() > MONITOR_CACHE_SIZE)
+  {
+    m.reset();
+    return;
+  }
+  //freeMonitors_ was reserved up to MONITOR_CACHE_SIZE in the ctor,
+  //so this shouldn't throw
+  freeMonitors_.push_back(TConcurrentClientSyncInfo::MonitorPtr());
+  //swapping to avoid an atomic operation
+  m.swap(freeMonitors_.back());
+}
+
+int32_t TConcurrentClientSyncInfo::generateSeqId()
+{
+  Guard seqidGuard(seqidMutex_);
+  if(stop_)
+    throwDeadConnection_();
+
+  if(!seqidToMonitorMap_.empty())
+    if(nextseqid_ == seqidToMonitorMap_.begin()->first)
+      throw apache::thrift::TApplicationException(
+        TApplicationException::BAD_SEQUENCE_ID,
+        "about to repeat a seqid");
+  int32_t newSeqId = nextseqid_++;
+  seqidToMonitorMap_[newSeqId] = newMonitor_(seqidGuard);
+  return newSeqId;
+}
+
+TConcurrentRecvSentry::TConcurrentRecvSentry(TConcurrentClientSyncInfo *sync, int32_t seqid) :
+  sync_(*sync),
+  seqid_(seqid),
+  committed_(false)
+{
+  sync_.getReadMutex().lock();
+}
+
+TConcurrentRecvSentry::~TConcurrentRecvSentry()
+{
+  {
+    Guard seqidGuard(sync_.seqidMutex_);
+    sync_.deleteMonitor_(seqidGuard, sync_.seqidToMonitorMap_[seqid_]);
+
+    sync_.seqidToMonitorMap_.erase(seqid_);
+    if(committed_)
+      sync_.wakeupAnyone_(seqidGuard);
+    else
+      sync_.markBad_(seqidGuard);
+  }
+  sync_.getReadMutex().unlock();
+}
+
+void TConcurrentRecvSentry::commit()
+{
+  committed_ = true;
+}
+
+TConcurrentSendSentry::TConcurrentSendSentry(TConcurrentClientSyncInfo *sync) :
+  sync_(*sync),
+  committed_(false)
+{
+  sync_.getWriteMutex().lock();
+}
+
+TConcurrentSendSentry::~TConcurrentSendSentry()
+{
+  if(!committed_)
+  {
+    Guard seqidGuard(sync_.seqidMutex_);
+    sync_.markBad_(seqidGuard);
+  }
+  sync_.getWriteMutex().unlock();
+}
+
+void TConcurrentSendSentry::commit()
+{
+  committed_ = true;
+}
+
+
+}}} // apache::thrift::async
diff --git a/lib/cpp/src/thrift/async/TConcurrentClientSyncInfo.h b/lib/cpp/src/thrift/async/TConcurrentClientSyncInfo.h
new file mode 100644
index 0000000..0bc5eb5
--- /dev/null
+++ b/lib/cpp/src/thrift/async/TConcurrentClientSyncInfo.h
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifndef _THRIFT_TCONCURRENTCLIENTSYNCINFO_H_
+#define _THRIFT_TCONCURRENTCLIENTSYNCINFO_H_ 1
+
+#include <thrift/protocol/TProtocol.h>
+#include <thrift/concurrency/Mutex.h>
+#include <thrift/concurrency/Monitor.h>
+#include <memory>
+#include <vector>
+#include <string>
+#include <map>
+
+namespace apache {
+namespace thrift {
+namespace async {
+
+class TConcurrentClientSyncInfo;
+
+class TConcurrentSendSentry {
+public:
+  explicit TConcurrentSendSentry(TConcurrentClientSyncInfo* sync);
+  ~TConcurrentSendSentry();
+
+  void commit();
+
+private:
+  TConcurrentClientSyncInfo& sync_;
+  bool committed_;
+};
+
+class TConcurrentRecvSentry {
+public:
+  TConcurrentRecvSentry(TConcurrentClientSyncInfo* sync, int32_t seqid);
+  ~TConcurrentRecvSentry();
+
+  void commit();
+
+private:
+  TConcurrentClientSyncInfo& sync_;
+  int32_t seqid_;
+  bool committed_;
+};
+
+class TConcurrentClientSyncInfo {
+private: // typedefs
+  typedef std::shared_ptr< ::apache::thrift::concurrency::Monitor> MonitorPtr;
+  typedef std::map<int32_t, MonitorPtr> MonitorMap;
+
+public:
+  TConcurrentClientSyncInfo();
+
+  int32_t generateSeqId();
+
+  bool getPending(std::string& fname,
+                  ::apache::thrift::protocol::TMessageType& mtype,
+                  int32_t& rseqid); /* requires readMutex_ */
+
+  void updatePending(const std::string& fname,
+                     ::apache::thrift::protocol::TMessageType mtype,
+                     int32_t rseqid); /* requires readMutex_ */
+
+  void waitForWork(int32_t seqid); /* requires readMutex_ */
+
+  ::apache::thrift::concurrency::Mutex& getReadMutex() { return readMutex_; }
+  ::apache::thrift::concurrency::Mutex& getWriteMutex() { return writeMutex_; }
+
+private: // constants
+  enum { MONITOR_CACHE_SIZE = 10 };
+
+private: // functions
+  MonitorPtr newMonitor_(
+      const ::apache::thrift::concurrency::Guard& seqidGuard); /* requires seqidMutex_ */
+  void deleteMonitor_(const ::apache::thrift::concurrency::Guard& seqidGuard, MonitorPtr& m);
+      /*noexcept*/ /* requires seqidMutex_ */
+  void wakeupAnyone_(
+      const ::apache::thrift::concurrency::Guard& seqidGuard);           /* requires seqidMutex_ */
+  void markBad_(const ::apache::thrift::concurrency::Guard& seqidGuard); /* requires seqidMutex_ */
+  void throwBadSeqId_();
+  void throwDeadConnection_();
+
+private: // data members
+  volatile bool stop_;
+
+  ::apache::thrift::concurrency::Mutex seqidMutex_;
+  // begin seqidMutex_ protected members
+  int32_t nextseqid_;
+  MonitorMap seqidToMonitorMap_;
+  std::vector<MonitorPtr> freeMonitors_;
+  // end seqidMutex_ protected members
+
+  ::apache::thrift::concurrency::Mutex writeMutex_;
+
+  ::apache::thrift::concurrency::Mutex readMutex_;
+  // begin readMutex_ protected members
+  bool recvPending_;
+  bool wakeupSomeone_;
+  int32_t seqidPending_;
+  std::string fnamePending_;
+  ::apache::thrift::protocol::TMessageType mtypePending_;
+  // end readMutex_ protected members
+
+  friend class TConcurrentSendSentry;
+  friend class TConcurrentRecvSentry;
+};
+}
+}
+} // apache::thrift::async
+
+#endif // _THRIFT_TCONCURRENTCLIENTSYNCINFO_H_
diff --git a/lib/cpp/src/thrift/async/TEvhttpClientChannel.cpp b/lib/cpp/src/thrift/async/TEvhttpClientChannel.cpp
index 7ad7537..6af8104 100644
--- a/lib/cpp/src/thrift/async/TEvhttpClientChannel.cpp
+++ b/lib/cpp/src/thrift/async/TEvhttpClientChannel.cpp
@@ -19,6 +19,8 @@
 
 #include <thrift/async/TEvhttpClientChannel.h>
 #include <evhttp.h>
+#include <event2/buffer.h>
+#include <event2/buffer_compat.h>
 #include <thrift/transport/TBufferTransports.h>
 #include <thrift/protocol/TProtocolException.h>
 
@@ -28,42 +30,33 @@
 using namespace apache::thrift::protocol;
 using apache::thrift::transport::TTransportException;
 
-namespace apache { namespace thrift { namespace async {
+namespace apache {
+namespace thrift {
+namespace async {
 
+TEvhttpClientChannel::TEvhttpClientChannel(const std::string& host,
+                                           const std::string& path,
+                                           const char* address,
+                                           int port,
+                                           struct event_base* eb,
+                                           struct evdns_base* dnsbase)
 
-TEvhttpClientChannel::TEvhttpClientChannel(
-    const std::string& host,
-    const std::string& path,
-    const char* address,
-    int port,
-    struct event_base* eb)
-  : host_(host)
-  , path_(path)
-  , recvBuf_(NULL)
-  , conn_(NULL)
-{
-  conn_ = evhttp_connection_new(address, port);
+  : host_(host), path_(path), conn_(NULL) {
+  conn_ = evhttp_connection_base_new(eb, dnsbase, address, port);
   if (conn_ == NULL) {
     throw TException("evhttp_connection_new failed");
   }
-  evhttp_connection_set_base(conn_, eb);
 }
 
-
 TEvhttpClientChannel::~TEvhttpClientChannel() {
   if (conn_ != NULL) {
     evhttp_connection_free(conn_);
   }
 }
 
-
-void TEvhttpClientChannel::sendAndRecvMessage(
-    const VoidCallback& cob,
-    apache::thrift::transport::TMemoryBuffer* sendBuf,
-    apache::thrift::transport::TMemoryBuffer* recvBuf) {
-  cob_ = cob;
-  recvBuf_ = recvBuf;
-
+void TEvhttpClientChannel::sendAndRecvMessage(const VoidCallback& cob,
+                                              apache::thrift::transport::TMemoryBuffer* sendBuf,
+                                              apache::thrift::transport::TMemoryBuffer* recvBuf) {
   struct evhttp_request* req = evhttp_request_new(response, this);
   if (req == NULL) {
     throw TException("evhttp_request_new failed");
@@ -93,70 +86,71 @@
   if (rv != 0) {
     throw TException("evhttp_make_request failed");
   }
+
+  completionQueue_.push(Completion(cob, recvBuf));
 }
 
-
-void TEvhttpClientChannel::sendMessage(
-    const VoidCallback& cob, apache::thrift::transport::TMemoryBuffer* message) {
-  (void) cob;
-  (void) message;
+void TEvhttpClientChannel::sendMessage(const VoidCallback& cob,
+                                       apache::thrift::transport::TMemoryBuffer* message) {
+  (void)cob;
+  (void)message;
   throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
-			   "Unexpected call to TEvhttpClientChannel::sendMessage");
+                           "Unexpected call to TEvhttpClientChannel::sendMessage");
 }
 
-
-void TEvhttpClientChannel::recvMessage(
-    const VoidCallback& cob, apache::thrift::transport::TMemoryBuffer* message) {
-  (void) cob;
-  (void) message;
+void TEvhttpClientChannel::recvMessage(const VoidCallback& cob,
+                                       apache::thrift::transport::TMemoryBuffer* message) {
+  (void)cob;
+  (void)message;
   throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
-			   "Unexpected call to TEvhttpClientChannel::recvMessage");
+                           "Unexpected call to TEvhttpClientChannel::recvMessage");
 }
 
-
 void TEvhttpClientChannel::finish(struct evhttp_request* req) {
+  assert(!completionQueue_.empty());
+  Completion completion = completionQueue_.front();
+  completionQueue_.pop();
   if (req == NULL) {
-  try {
-    cob_();
-  } catch(const TTransportException& e) {
-    if(e.getType() == TTransportException::END_OF_FILE)
-      throw TException("connect failed");
-    else
-      throw;
-  }
-  return;
+    try {
+      completion.first();
+    } catch (const TTransportException& e) {
+      if (e.getType() == TTransportException::END_OF_FILE)
+        throw TException("connect failed");
+      else
+        throw;
+    }
+    return;
   } else if (req->response_code != 200) {
-  try {
-    cob_();
-  } catch(const TTransportException& e) {
-    std::stringstream ss;
-    ss << "server returned code " << req->response_code;
-	if(req->response_code_line)
-		ss << ": " << req->response_code_line;
-    if(e.getType() == TTransportException::END_OF_FILE)
-      throw TException(ss.str());
-    else
-      throw;
+    try {
+      completion.first();
+    } catch (const TTransportException& e) {
+      std::stringstream ss;
+      ss << "server returned code " << req->response_code;
+      if (req->response_code_line)
+        ss << ": " << req->response_code_line;
+      if (e.getType() == TTransportException::END_OF_FILE)
+        throw TException(ss.str());
+      else
+        throw;
+    }
+    return;
   }
-  return;
-  }
-  recvBuf_->resetBuffer(
-      EVBUFFER_DATA(req->input_buffer),
-      static_cast<uint32_t>(EVBUFFER_LENGTH(req->input_buffer)));
-  cob_();
+  completion.second->resetBuffer(EVBUFFER_DATA(req->input_buffer),
+                        static_cast<uint32_t>(EVBUFFER_LENGTH(req->input_buffer)));
+  completion.first();
   return;
 }
 
-
 /* static */ void TEvhttpClientChannel::response(struct evhttp_request* req, void* arg) {
   TEvhttpClientChannel* self = (TEvhttpClientChannel*)arg;
   try {
     self->finish(req);
-  } catch(std::exception& e) {
+  } catch (std::exception& e) {
     // don't propagate a C++ exception in C code (e.g. libevent)
-    std::cerr << "TEvhttpClientChannel::response exception thrown (ignored): " << e.what() << std::endl;
+    std::cerr << "TEvhttpClientChannel::response exception thrown (ignored): " << e.what()
+              << std::endl;
   }
 }
-
-
-}}} // apache::thrift::async
+}
+}
+} // apache::thrift::async
diff --git a/lib/cpp/src/thrift/async/TEvhttpClientChannel.h b/lib/cpp/src/thrift/async/TEvhttpClientChannel.h
index a7229e9..a321f41 100644
--- a/lib/cpp/src/thrift/async/TEvhttpClientChannel.h
+++ b/lib/cpp/src/thrift/async/TEvhttpClientChannel.h
@@ -20,57 +20,69 @@
 #ifndef _THRIFT_TEVHTTP_CLIENT_CHANNEL_H_
 #define _THRIFT_TEVHTTP_CLIENT_CHANNEL_H_ 1
 
+#include <queue>
 #include <string>
-#include <boost/shared_ptr.hpp>
+#include <utility>
+#include <memory>
 #include <thrift/async/TAsyncChannel.h>
 
 struct event_base;
+struct evdns_base;
 struct evhttp_connection;
 struct evhttp_request;
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 class TMemoryBuffer;
-}}}
+}
+}
+}
 
-namespace apache { namespace thrift { namespace async {
+namespace apache {
+namespace thrift {
+namespace async {
 
 class TEvhttpClientChannel : public TAsyncChannel {
- public:
+public:
   using TAsyncChannel::VoidCallback;
 
-  TEvhttpClientChannel(
-      const std::string& host,
-      const std::string& path,
-      const char* address,
-      int port,
-      struct event_base* eb);
+  TEvhttpClientChannel(const std::string& host,
+                       const std::string& path,
+                       const char* address,
+                       int port,
+                       struct event_base* eb,
+                       struct evdns_base *dnsbase = 0);
   ~TEvhttpClientChannel();
 
   virtual void sendAndRecvMessage(const VoidCallback& cob,
                                   apache::thrift::transport::TMemoryBuffer* sendBuf,
                                   apache::thrift::transport::TMemoryBuffer* recvBuf);
 
-  virtual void sendMessage(const VoidCallback& cob, apache::thrift::transport::TMemoryBuffer* message);
-  virtual void recvMessage(const VoidCallback& cob, apache::thrift::transport::TMemoryBuffer* message);
+  virtual void sendMessage(const VoidCallback& cob,
+                           apache::thrift::transport::TMemoryBuffer* message);
+  virtual void recvMessage(const VoidCallback& cob,
+                           apache::thrift::transport::TMemoryBuffer* message);
 
   void finish(struct evhttp_request* req);
 
-  //XXX
+  // XXX
   virtual bool good() const { return true; }
   virtual bool error() const { return false; }
   virtual bool timedOut() const { return false; }
 
- private:
+private:
   static void response(struct evhttp_request* req, void* arg);
 
   std::string host_;
   std::string path_;
-  VoidCallback cob_;
-  apache::thrift::transport::TMemoryBuffer* recvBuf_;
+  typedef std::pair<VoidCallback, apache::thrift::transport::TMemoryBuffer*> Completion;
+  typedef std::queue<Completion> CompletionQueue;
+  CompletionQueue completionQueue_;
   struct evhttp_connection* conn_;
-
 };
-
-}}} // apache::thrift::async
+}
+}
+} // apache::thrift::async
 
 #endif // #ifndef _THRIFT_TEVHTTP_CLIENT_CHANNEL_H_
diff --git a/lib/cpp/src/thrift/async/TEvhttpServer.cpp b/lib/cpp/src/thrift/async/TEvhttpServer.cpp
index fa8d782..bdc3266 100644
--- a/lib/cpp/src/thrift/async/TEvhttpServer.cpp
+++ b/lib/cpp/src/thrift/async/TEvhttpServer.cpp
@@ -20,8 +20,10 @@
 #include <thrift/async/TEvhttpServer.h>
 #include <thrift/async/TAsyncBufferProcessor.h>
 #include <thrift/transport/TBufferTransports.h>
+#include <memory>
 #include <evhttp.h>
-
+#include <event2/buffer.h>
+#include <event2/buffer_compat.h>
 #include <iostream>
 
 #ifndef HTTP_INTERNAL // libevent < 2
@@ -29,31 +31,26 @@
 #endif
 
 using apache::thrift::transport::TMemoryBuffer;
+using std::shared_ptr;
 
-namespace apache { namespace thrift { namespace async {
-
+namespace apache {
+namespace thrift {
+namespace async {
 
 struct TEvhttpServer::RequestContext {
   struct evhttp_request* req;
-  boost::shared_ptr<apache::thrift::transport::TMemoryBuffer> ibuf;
-  boost::shared_ptr<apache::thrift::transport::TMemoryBuffer> obuf;
+  std::shared_ptr<apache::thrift::transport::TMemoryBuffer> ibuf;
+  std::shared_ptr<apache::thrift::transport::TMemoryBuffer> obuf;
 
   RequestContext(struct evhttp_request* req);
 };
 
+TEvhttpServer::TEvhttpServer(std::shared_ptr<TAsyncBufferProcessor> processor)
+  : processor_(processor), eb_(NULL), eh_(NULL) {
+}
 
-TEvhttpServer::TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor)
-  : processor_(processor)
-  , eb_(NULL)
-  , eh_(NULL)
-{}
-
-
-TEvhttpServer::TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor, int port)
-  : processor_(processor)
-  , eb_(NULL)
-  , eh_(NULL)
-{
+TEvhttpServer::TEvhttpServer(std::shared_ptr<TAsyncBufferProcessor> processor, int port)
+  : processor_(processor), eb_(NULL), eh_(NULL) {
   // Create event_base and evhttp.
   eb_ = event_base_new();
   if (eb_ == NULL) {
@@ -70,7 +67,7 @@
   if (ret < 0) {
     evhttp_free(eh_);
     event_base_free(eb_);
-	throw TException("evhttp_bind_socket failed");
+    throw TException("evhttp_bind_socket failed");
   }
 
   // Register a handler.  If you use the other constructor,
@@ -79,7 +76,6 @@
   evhttp_set_cb(eh_, "/", request, (void*)this);
 }
 
-
 TEvhttpServer::~TEvhttpServer() {
   if (eh_ != NULL) {
     evhttp_free(eh_);
@@ -89,7 +85,6 @@
   }
 }
 
-
 int TEvhttpServer::serve() {
   if (eb_ == NULL) {
     throw TException("Unexpected call to TEvhttpServer::serve");
@@ -97,38 +92,34 @@
   return event_base_dispatch(eb_);
 }
 
-
-TEvhttpServer::RequestContext::RequestContext(struct evhttp_request* req) : req(req)
-  , ibuf(new TMemoryBuffer(EVBUFFER_DATA(req->input_buffer), static_cast<uint32_t>(EVBUFFER_LENGTH(req->input_buffer))))
-  , obuf(new TMemoryBuffer())
-{}
-
+TEvhttpServer::RequestContext::RequestContext(struct evhttp_request* req)
+  : req(req),
+    ibuf(new TMemoryBuffer(EVBUFFER_DATA(req->input_buffer),
+                           static_cast<uint32_t>(EVBUFFER_LENGTH(req->input_buffer)))),
+    obuf(new TMemoryBuffer()) {
+}
 
 void TEvhttpServer::request(struct evhttp_request* req, void* self) {
   try {
     static_cast<TEvhttpServer*>(self)->process(req);
-  } catch(std::exception& e) {
+  } catch (std::exception& e) {
     evhttp_send_reply(req, HTTP_INTERNAL, e.what(), 0);
   }
 }
 
-
 void TEvhttpServer::process(struct evhttp_request* req) {
   RequestContext* ctx = new RequestContext(req);
-  return processor_->process(
-      apache::thrift::stdcxx::bind(
-        &TEvhttpServer::complete,
-        this,
-        ctx,
-        apache::thrift::stdcxx::placeholders::_1),
-      ctx->ibuf,
-      ctx->obuf);
+  return processor_->process(std::bind(&TEvhttpServer::complete,
+                                                          this,
+                                                          ctx,
+                                                          std::placeholders::_1),
+                             ctx->ibuf,
+                             ctx->obuf);
 }
 
-
 void TEvhttpServer::complete(RequestContext* ctx, bool success) {
-  (void) success;
-  std::auto_ptr<RequestContext> ptr(ctx);
+  (void)success;
+  std::unique_ptr<RequestContext> ptr(ctx);
 
   int code = success ? 200 : 400;
   const char* reason = success ? "OK" : "Bad Request";
@@ -142,7 +133,7 @@
   struct evbuffer* buf = evbuffer_new();
   if (buf == NULL) {
     // TODO: Log an error.
-      std::cerr << "evbuffer_new failed " << __FILE__ << ":" <<  __LINE__ << std::endl;
+    std::cerr << "evbuffer_new failed " << __FILE__ << ":" << __LINE__ << std::endl;
   } else {
     uint8_t* obuf;
     uint32_t sz;
@@ -150,7 +141,8 @@
     int ret = evbuffer_add(buf, obuf, sz);
     if (ret != 0) {
       // TODO: Log an error.
-      std::cerr << "evhttp_add failed with " << ret << " " << __FILE__ << ":" <<  __LINE__ << std::endl;
+      std::cerr << "evhttp_add failed with " << ret << " " << __FILE__ << ":" << __LINE__
+                << std::endl;
     }
   }
 
@@ -160,10 +152,9 @@
   }
 }
 
-
 struct event_base* TEvhttpServer::getEventBase() {
   return eb_;
 }
-
-
-}}} // apache::thrift::async
+}
+}
+} // apache::thrift::async
diff --git a/lib/cpp/src/thrift/async/TEvhttpServer.h b/lib/cpp/src/thrift/async/TEvhttpServer.h
index edc6ffb..c5bf3b6 100644
--- a/lib/cpp/src/thrift/async/TEvhttpServer.h
+++ b/lib/cpp/src/thrift/async/TEvhttpServer.h
@@ -20,18 +20,20 @@
 #ifndef _THRIFT_TEVHTTP_SERVER_H_
 #define _THRIFT_TEVHTTP_SERVER_H_ 1
 
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
 struct event_base;
 struct evhttp;
 struct evhttp_request;
 
-namespace apache { namespace thrift { namespace async {
+namespace apache {
+namespace thrift {
+namespace async {
 
 class TAsyncBufferProcessor;
 
 class TEvhttpServer {
- public:
+public:
   /**
    * Create a TEvhttpServer for use with an external evhttp instance.
    * Must be manually installed with evhttp_set_cb, using
@@ -39,14 +41,14 @@
    * address of the server as the extra arg.
    * Do not call "serve" on this server.
    */
-  TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor);
+  TEvhttpServer(std::shared_ptr<TAsyncBufferProcessor> processor);
 
   /**
    * Create a TEvhttpServer with an embedded event_base and evhttp,
    * listening on port and responding on the endpoint "/".
    * Call "serve" on this server to serve forever.
    */
-  TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor, int port);
+  TEvhttpServer(std::shared_ptr<TAsyncBufferProcessor> processor, int port);
 
   ~TEvhttpServer();
 
@@ -55,17 +57,18 @@
 
   struct event_base* getEventBase();
 
- private:
+private:
   struct RequestContext;
 
   void process(struct evhttp_request* req);
   void complete(RequestContext* ctx, bool success);
 
-  boost::shared_ptr<TAsyncBufferProcessor> processor_;
+  std::shared_ptr<TAsyncBufferProcessor> processor_;
   struct event_base* eb_;
   struct evhttp* eh_;
 };
-
-}}} // apache::thrift::async
+}
+}
+} // apache::thrift::async
 
 #endif // #ifndef _THRIFT_TEVHTTP_SERVER_H_
diff --git a/lib/cpp/src/thrift/concurrency/BoostMonitor.cpp b/lib/cpp/src/thrift/concurrency/BoostMonitor.cpp
deleted file mode 100644
index 1027157..0000000
--- a/lib/cpp/src/thrift/concurrency/BoostMonitor.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <thrift/thrift-config.h>
-
-#include <thrift/concurrency/Monitor.h>
-#include <thrift/concurrency/Exception.h>
-#include <thrift/concurrency/Util.h>
-#include <thrift/transport/PlatformSocket.h>
-#include <assert.h>
-
-#include <boost/scoped_ptr.hpp>
-#include <boost/thread.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
-
-namespace apache { namespace thrift { namespace concurrency {
-
-/**
- * Monitor implementation using the boost thread library
- *
- * @version $Id:$
- */
-class Monitor::Impl : public boost::condition_variable_any {
-
- public:
-
-  Impl()
-     : ownedMutex_(new Mutex()),
-       mutex_(NULL) {
-    init(ownedMutex_.get());
-  }
-
-  Impl(Mutex* mutex)
-     : mutex_(NULL) {
-    init(mutex);
-  }
-
-  Impl(Monitor* monitor)
-     : mutex_(NULL) {
-    init(&(monitor->mutex()));
-  }
-
-  Mutex& mutex() { return *mutex_; }
-  void lock() { mutex().lock(); }
-  void unlock() { mutex().unlock(); }
-
-  /**
-   * Exception-throwing version of waitForTimeRelative(), called simply
-   * wait(int64) for historical reasons.  Timeout is in milliseconds.
-   *
-   * If the condition occurs,  this function returns cleanly; on timeout or
-   * error an exception is thrown.
-   */
-  void wait(int64_t timeout_ms) {
-    int result = waitForTimeRelative(timeout_ms);
-    if (result == THRIFT_ETIMEDOUT) {
-      throw TimedOutException();
-    } else if (result != 0) {
-      throw TException(
-        "Monitor::wait() failed");
-    }
-  }
-
-  /**
-   * Waits until the specified timeout in milliseconds for the condition to
-   * occur, or waits forever if timeout_ms == 0.
-   *
-   * Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
-   */
-  int waitForTimeRelative(int64_t timeout_ms) {
-    if (timeout_ms == 0LL) {
-      return waitForever();
-    }
-
-    assert(mutex_);
-	boost::timed_mutex* mutexImpl =
-      reinterpret_cast<boost::timed_mutex*>(mutex_->getUnderlyingImpl());
-    assert(mutexImpl);
-
-	boost::timed_mutex::scoped_lock lock(*mutexImpl, boost::adopt_lock);
-	int res = timed_wait(lock, boost::get_system_time()+boost::posix_time::milliseconds(timeout_ms)) ? 0 : THRIFT_ETIMEDOUT;
-	lock.release();
-	return res;
-  }
-
-  /**
-   * Waits until the absolute time specified using struct THRIFT_TIMESPEC.
-   * Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
-   */
-  int waitForTime(const THRIFT_TIMESPEC* abstime) {
-    struct timeval temp;
-    temp.tv_sec  = static_cast<long>(abstime->tv_sec);
-    temp.tv_usec = static_cast<long>(abstime->tv_nsec) / 1000;
-    return waitForTime(&temp);
-  }
-
-  /**
-   * Waits until the absolute time specified using struct timeval.
-   * Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
-   */
-  int waitForTime(const struct timeval* abstime) {
-    assert(mutex_);
-    boost::timed_mutex* mutexImpl =
-      static_cast<boost::timed_mutex*>(mutex_->getUnderlyingImpl());
-    assert(mutexImpl);
-
-    struct timeval currenttime;
-    Util::toTimeval(currenttime, Util::currentTime());
-
-	long tv_sec = static_cast<long>(abstime->tv_sec - currenttime.tv_sec);
-	long tv_usec = static_cast<long>(abstime->tv_usec - currenttime.tv_usec);
-	if(tv_sec < 0)
-		tv_sec = 0;
-	if(tv_usec < 0)
-		tv_usec = 0;
-
-	boost::timed_mutex::scoped_lock lock(*mutexImpl, boost::adopt_lock);
-	int res = timed_wait(lock, boost::get_system_time() +
-		boost::posix_time::seconds(tv_sec) +
-		boost::posix_time::microseconds(tv_usec)
-		) ? 0 : THRIFT_ETIMEDOUT;
-	lock.release();
-	return res;
-  }
-
-  /**
-   * Waits forever until the condition occurs.
-   * Returns 0 if condition occurs, or an error code otherwise.
-   */
-  int waitForever() {
-    assert(mutex_);
-    boost::timed_mutex* mutexImpl =
-      reinterpret_cast<boost::timed_mutex*>(mutex_->getUnderlyingImpl());
-    assert(mutexImpl);
-
-	boost::timed_mutex::scoped_lock lock(*mutexImpl, boost::adopt_lock);
-	((boost::condition_variable_any*)this)->wait(lock);
-	lock.release();
-    return 0;
-  }
-
-
-  void notify() {
-	  notify_one();
-  }
-
-  void notifyAll() {
-	  notify_all();
-  }
-
- private:
-
-  void init(Mutex* mutex) {
-    mutex_ = mutex;
-  }
-
-  boost::scoped_ptr<Mutex> ownedMutex_;
-  Mutex* mutex_;
-};
-
-Monitor::Monitor() : impl_(new Monitor::Impl()) {}
-Monitor::Monitor(Mutex* mutex) : impl_(new Monitor::Impl(mutex)) {}
-Monitor::Monitor(Monitor* monitor) : impl_(new Monitor::Impl(monitor)) {}
-
-Monitor::~Monitor() { delete impl_; }
-
-Mutex& Monitor::mutex() const { return const_cast<Monitor::Impl*>(impl_)->mutex(); }
-
-void Monitor::lock() const { const_cast<Monitor::Impl*>(impl_)->lock(); }
-
-void Monitor::unlock() const { const_cast<Monitor::Impl*>(impl_)->unlock(); }
-
-void Monitor::wait(int64_t timeout) const { const_cast<Monitor::Impl*>(impl_)->wait(timeout); }
-
-int Monitor::waitForTime(const THRIFT_TIMESPEC* abstime) const {
-  return const_cast<Monitor::Impl*>(impl_)->waitForTime(abstime);
-}
-
-int Monitor::waitForTime(const timeval* abstime) const {
-  return const_cast<Monitor::Impl*>(impl_)->waitForTime(abstime);
-}
-
-int Monitor::waitForTimeRelative(int64_t timeout_ms) const {
-  return const_cast<Monitor::Impl*>(impl_)->waitForTimeRelative(timeout_ms);
-}
-
-int Monitor::waitForever() const {
-  return const_cast<Monitor::Impl*>(impl_)->waitForever();
-}
-
-void Monitor::notify() const { const_cast<Monitor::Impl*>(impl_)->notify(); }
-
-void Monitor::notifyAll() const { const_cast<Monitor::Impl*>(impl_)->notifyAll(); }
-
-}}} // apache::thrift::concurrency
diff --git a/lib/cpp/src/thrift/concurrency/BoostMutex.cpp b/lib/cpp/src/thrift/concurrency/BoostMutex.cpp
deleted file mode 100644
index eb0c3c1..0000000
--- a/lib/cpp/src/thrift/concurrency/BoostMutex.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <thrift/thrift-config.h>
-
-#include <thrift/concurrency/Mutex.h>
-#include <thrift/concurrency/Util.h>
-
-#include <cassert>
-#include <boost/thread.hpp>
-#include <boost/thread/mutex.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
-
-namespace apache { namespace thrift { namespace concurrency {
-
-/**
- * Implementation of Mutex class using boost interprocess mutex
- *
- * @version $Id:$
- */
-class Mutex::impl : public boost::timed_mutex {
-};
-
-Mutex::Mutex(Initializer init) : impl_(new Mutex::impl()) {}
-
-void* Mutex::getUnderlyingImpl() const { return impl_.get(); }
-
-void Mutex::lock() const { impl_->lock(); }
-
-bool Mutex::trylock() const { return impl_->try_lock(); }
-
-bool Mutex::timedlock(int64_t ms) const { return impl_->timed_lock(boost::get_system_time()+boost::posix_time::milliseconds(ms)); }
-
-void Mutex::unlock() const { impl_->unlock(); }
-
-void Mutex::DEFAULT_INITIALIZER(void* arg) {
-}
-
-}}} // apache::thrift::concurrency
-
diff --git a/lib/cpp/src/thrift/concurrency/BoostThreadFactory.cpp b/lib/cpp/src/thrift/concurrency/BoostThreadFactory.cpp
deleted file mode 100644
index decacce..0000000
--- a/lib/cpp/src/thrift/concurrency/BoostThreadFactory.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <thrift/thrift-config.h>
-
-#include <thrift/concurrency/BoostThreadFactory.h>
-#include <thrift/concurrency/Exception.h>
-
-#include <cassert>
-
-#include <boost/weak_ptr.hpp>
-#include <boost/thread.hpp>
-
-namespace apache { namespace thrift { namespace concurrency {
-
-using boost::shared_ptr;
-using boost::weak_ptr;
-
-/**
- * The boost thread class.
- *
- * @version $Id:$
- */
-class BoostThread: public Thread {
- public:
-
-  enum STATE {
-    uninitialized,
-    starting,
-    started,
-    stopping,
-    stopped
-  };
-
-  static void* threadMain(void* arg);
-
- private:
-  std::auto_ptr<boost::thread> thread_;
-  STATE state_;
-  weak_ptr<BoostThread> self_;
-  bool detached_;
-
- public:
-
-  BoostThread(bool detached, shared_ptr<Runnable> runnable) :
-    state_(uninitialized),
-    detached_(detached) {
-      this->Thread::runnable(runnable);
-    }
-
-  ~BoostThread() {
-    if(!detached_) {
-      try {
-        join();
-      } catch(...) {
-        // We're really hosed.
-      }
-    }
-  }
-
-  void start() {
-    if (state_ != uninitialized) {
-      return;
-    }
-  
-  // Create reference
-    shared_ptr<BoostThread>* selfRef = new shared_ptr<BoostThread>();
-    *selfRef = self_.lock();
-
-    state_ = starting;
-
-    thread_ = std::auto_ptr<boost::thread>(new boost::thread(boost::bind(threadMain, (void*)selfRef)));
-
-    if(detached_)
-      thread_->detach();
-  }
-
-  void join() {
-    if (!detached_ && state_ != uninitialized) {
-      thread_->join();
-    }
-  }
-
-  Thread::id_t getId() {
-    return thread_.get() ? thread_->get_id() : boost::thread::id();
-  }
-
-  shared_ptr<Runnable> runnable() const { return Thread::runnable(); }
-
-  void runnable(shared_ptr<Runnable> value) { Thread::runnable(value); }
-
-  void weakRef(shared_ptr<BoostThread> self) {
-    assert(self.get() == this);
-    self_ = weak_ptr<BoostThread>(self);
-  }
-};
-
-void* BoostThread::threadMain(void* arg) {
-  shared_ptr<BoostThread> thread = *(shared_ptr<BoostThread>*)arg;
-  delete reinterpret_cast<shared_ptr<BoostThread>*>(arg);
-
-  if (!thread) {
-    return (void*)0;
-  }
-
-  if (thread->state_ != starting) {
-    return (void*)0;
-  }
-
-  thread->state_ = started;
-  thread->runnable()->run();
-
-  if (thread->state_ != stopping && thread->state_ != stopped) {
-    thread->state_ = stopping;
-  }
-  return (void*)0;
-}
-
-/**
- * POSIX Thread factory implementation
- */
-class BoostThreadFactory::Impl {
-
- private:
-  bool detached_;
-
- public:
-
-  Impl(bool detached) :
-    detached_(detached) {}
-
-  /**
-   * Creates a new POSIX thread to run the runnable object
-   *
-   * @param runnable A runnable object
-   */
-  shared_ptr<Thread> newThread(shared_ptr<Runnable> runnable) const {
-    shared_ptr<BoostThread> result = shared_ptr<BoostThread>(new BoostThread(detached_, runnable));
-    result->weakRef(result);
-    runnable->thread(result);
-    return result;
-  }
-
-  bool isDetached() const { return detached_; }
-
-  void setDetached(bool value) { detached_ = value; }
-
-  Thread::id_t getCurrentThreadId() const {
-    return boost::this_thread::get_id();
-  }
-};
-
-BoostThreadFactory::BoostThreadFactory(bool detached) :
-  impl_(new BoostThreadFactory::Impl(detached)) {}
-
-shared_ptr<Thread> BoostThreadFactory::newThread(shared_ptr<Runnable> runnable) const { return impl_->newThread(runnable); }
-
-bool BoostThreadFactory::isDetached() const { return impl_->isDetached(); }
-
-void BoostThreadFactory::setDetached(bool value) { impl_->setDetached(value); }
-
-Thread::id_t BoostThreadFactory::getCurrentThreadId() const { return impl_->getCurrentThreadId(); }
-
-}}} // apache::thrift::concurrency
diff --git a/lib/cpp/src/thrift/concurrency/BoostThreadFactory.h b/lib/cpp/src/thrift/concurrency/BoostThreadFactory.h
deleted file mode 100644
index 6a236d3..0000000
--- a/lib/cpp/src/thrift/concurrency/BoostThreadFactory.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef _THRIFT_CONCURRENCY_BOOSTTHREADFACTORY_H_
-#define _THRIFT_CONCURRENCY_BOOSTTHREADFACTORY_H_ 1
-
-#include <thrift/concurrency/Thread.h>
-
-#include <boost/shared_ptr.hpp>
-
-namespace apache { namespace thrift { namespace concurrency {
-
-/**
- * A thread factory to create posix threads
- *
- * @version $Id:$
- */
-class BoostThreadFactory : public ThreadFactory {
-
- public:
-
-  /**
-   * Boost thread factory.  All threads created by a factory are reference-counted
-   * via boost::shared_ptr and boost::weak_ptr.  The factory guarantees that threads and
-   * the Runnable tasks they host will be properly cleaned up once the last strong reference
-   * to both is given up.
-   *
-   * Threads are created with the specified boost policy, priority, stack-size. A detachable thread is not
-   * joinable.
-   *
-   * By default threads are not joinable.
-   */
-
-  BoostThreadFactory(bool detached=true);
-
-  // From ThreadFactory;
-  boost::shared_ptr<Thread> newThread(boost::shared_ptr<Runnable> runnable) const;
-
-  // From ThreadFactory;
-  Thread::id_t getCurrentThreadId() const;
-
-  /**
-   * Sets detached mode of threads
-   */
-  virtual void setDetached(bool detached);
-
-  /**
-   * Gets current detached mode
-   */
-  virtual bool isDetached() const;
-
-private:
-  class Impl;
-  boost::shared_ptr<Impl> impl_;
-};
-
-}}} // apache::thrift::concurrency
-
-#endif // #ifndef _THRIFT_CONCURRENCY_BOOSTTHREADFACTORY_H_
diff --git a/lib/cpp/src/thrift/concurrency/Exception.h b/lib/cpp/src/thrift/concurrency/Exception.h
index c62f116..6438fda 100644
--- a/lib/cpp/src/thrift/concurrency/Exception.h
+++ b/lib/cpp/src/thrift/concurrency/Exception.h
@@ -23,7 +23,9 @@
 #include <exception>
 #include <thrift/Thrift.h>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 class NoSuchTaskException : public apache::thrift::TException {};
 
@@ -39,26 +41,24 @@
 
 class TimedOutException : public apache::thrift::TException {
 public:
-  TimedOutException():TException("TimedOutException"){};
-  TimedOutException(const std::string& message ) :
-    TException(message) {}
+  TimedOutException() : TException("TimedOutException"){};
+  TimedOutException(const std::string& message) : TException(message) {}
 };
 
 class TooManyPendingTasksException : public apache::thrift::TException {
 public:
-  TooManyPendingTasksException():TException("TooManyPendingTasksException"){};
-  TooManyPendingTasksException(const std::string& message ) :
-    TException(message) {}
+  TooManyPendingTasksException() : TException("TooManyPendingTasksException"){};
+  TooManyPendingTasksException(const std::string& message) : TException(message) {}
 };
 
 class SystemResourceException : public apache::thrift::TException {
 public:
-    SystemResourceException() {}
+  SystemResourceException() {}
 
-    SystemResourceException(const std::string& message) :
-        TException(message) {}
+  SystemResourceException(const std::string& message) : TException(message) {}
 };
-
-}}} // apache::thrift::concurrency
+}
+}
+} // apache::thrift::concurrency
 
 #endif // #ifndef _THRIFT_CONCURRENCY_EXCEPTION_H_
diff --git a/lib/cpp/src/thrift/concurrency/FunctionRunner.h b/lib/cpp/src/thrift/concurrency/FunctionRunner.h
index e3b2bf3..8ad176e 100644
--- a/lib/cpp/src/thrift/concurrency/FunctionRunner.h
+++ b/lib/cpp/src/thrift/concurrency/FunctionRunner.h
@@ -20,10 +20,12 @@
 #ifndef _THRIFT_CONCURRENCY_FUNCTION_RUNNER_H
 #define _THRIFT_CONCURRENCY_FUNCTION_RUNNER_H 1
 
-#include <thrift/cxxfunctional.h>
 #include <thrift/concurrency/Thread.h>
+#include <memory>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 /**
  * Convenient implementation of Runnable that will execute arbitrary callbacks.
@@ -42,53 +44,49 @@
  *  A* a = new A();
  *  // To create a thread that executes a.foo() every 100 milliseconds:
  *  factory->newThread(FunctionRunner::create(
- *    apache::thrift::stdcxx::bind(&A::foo, a), 100))->start();
+ *    std::bind(&A::foo, a), 100))->start();
  *
  */
 
 class FunctionRunner : public Runnable {
- public:
+public:
   // This is the type of callback 'pthread_create()' expects.
-  typedef void* (*PthreadFuncPtr)(void *arg);
+  typedef void* (*PthreadFuncPtr)(void* arg);
   // This a fully-generic void(void) callback for custom bindings.
-  typedef apache::thrift::stdcxx::function<void()> VoidFunc;
+  typedef std::function<void()> VoidFunc;
 
-  typedef apache::thrift::stdcxx::function<bool()> BoolFunc;
+  typedef std::function<bool()> BoolFunc;
 
   /**
    * Syntactic sugar to make it easier to create new FunctionRunner
    * objects wrapped in shared_ptr.
    */
-  static boost::shared_ptr<FunctionRunner> create(const VoidFunc& cob) {
-    return boost::shared_ptr<FunctionRunner>(new FunctionRunner(cob));
+  static std::shared_ptr<FunctionRunner> create(const VoidFunc& cob) {
+    return std::shared_ptr<FunctionRunner>(new FunctionRunner(cob));
   }
 
-  static boost::shared_ptr<FunctionRunner> create(PthreadFuncPtr func,
-                                                  void* arg) {
-    return boost::shared_ptr<FunctionRunner>(new FunctionRunner(func, arg));
+  static std::shared_ptr<FunctionRunner> create(PthreadFuncPtr func, void* arg) {
+    return std::shared_ptr<FunctionRunner>(new FunctionRunner(func, arg));
   }
 
 private:
-  static void pthread_func_wrapper(PthreadFuncPtr func, void *arg)
-  {
-    //discard return value
+  static void pthread_func_wrapper(PthreadFuncPtr func, void* arg) {
+    // discard return value
     func(arg);
   }
+
 public:
   /**
    * Given a 'pthread_create' style callback, this FunctionRunner will
    * execute the given callback.  Note that the 'void*' return value is ignored.
    */
   FunctionRunner(PthreadFuncPtr func, void* arg)
-   : func_(apache::thrift::stdcxx::bind(pthread_func_wrapper, func, arg))
-  { }
+    : func_(std::bind(pthread_func_wrapper, func, arg)), intervalMs_(-1) {}
 
   /**
    * Given a generic callback, this FunctionRunner will execute it.
    */
-  FunctionRunner(const VoidFunc& cob)
-   : func_(cob)
-  { }
+  FunctionRunner(const VoidFunc& cob) : func_(cob), intervalMs_(-1) {}
 
   /**
    * Given a bool foo(...) type callback, FunctionRunner will execute
@@ -96,26 +94,25 @@
    * until it returns false. Note that the actual interval between calls will
    * be intervalMs plus execution time of the callback.
    */
-  FunctionRunner(const BoolFunc& cob, int intervalMs)
-   : repFunc_(cob), intervalMs_(intervalMs)
-  { }
+  FunctionRunner(const BoolFunc& cob, int intervalMs) : repFunc_(cob), intervalMs_(intervalMs) {}
 
   void run() {
     if (repFunc_) {
-      while(repFunc_()) {
-        THRIFT_SLEEP_USEC(intervalMs_*1000);
+      while (repFunc_()) {
+        THRIFT_SLEEP_USEC(intervalMs_ * 1000);
       }
     } else {
       func_();
     }
   }
 
- private:
+private:
   VoidFunc func_;
   BoolFunc repFunc_;
   int intervalMs_;
 };
-
-}}} // apache::thrift::concurrency
+}
+}
+} // apache::thrift::concurrency
 
 #endif // #ifndef _THRIFT_CONCURRENCY_FUNCTION_RUNNER_H
diff --git a/lib/cpp/src/thrift/concurrency/Monitor.cpp b/lib/cpp/src/thrift/concurrency/Monitor.cpp
index d94b2a4..9570cc6 100644
--- a/lib/cpp/src/thrift/concurrency/Monitor.cpp
+++ b/lib/cpp/src/thrift/concurrency/Monitor.cpp
@@ -17,12 +17,13 @@
  * under the License.
  */
 
+#include <thrift/thrift-config.h>
+
 #include <thrift/concurrency/Monitor.h>
 #include <thrift/concurrency/Exception.h>
 #include <thrift/concurrency/Util.h>
 #include <thrift/transport/PlatformSocket.h>
-
-#include <boost/scoped_ptr.hpp>
+#include <memory>
 
 #include <assert.h>
 
@@ -30,9 +31,13 @@
 
 #include <pthread.h>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
 
-using boost::scoped_ptr;
+using std::unique_ptr;
+using std::shared_ptr;
+
+namespace concurrency {
 
 /**
  * Monitor implementation using the POSIX pthread library
@@ -41,26 +46,14 @@
  */
 class Monitor::Impl {
 
- public:
-
-  Impl()
-     : ownedMutex_(new Mutex()),
-       mutex_(NULL),
-       condInitialized_(false) {
+public:
+  Impl() : ownedMutex_(new Mutex()), mutex_(NULL), condInitialized_(false) {
     init(ownedMutex_.get());
   }
 
-  Impl(Mutex* mutex)
-     : mutex_(NULL),
-       condInitialized_(false) {
-    init(mutex);
-  }
+  Impl(Mutex* mutex) : mutex_(NULL), condInitialized_(false) { init(mutex); }
 
-  Impl(Monitor* monitor)
-     : mutex_(NULL),
-       condInitialized_(false) {
-    init(&(monitor->mutex()));
-  }
+  Impl(Monitor* monitor) : mutex_(NULL), condInitialized_(false) { init(&(monitor->mutex())); }
 
   ~Impl() { cleanup(); }
 
@@ -80,11 +73,10 @@
     if (result == THRIFT_ETIMEDOUT) {
       // pthread_cond_timedwait has been observed to return early on
       // various platforms, so comment out this assert.
-      //assert(Util::currentTime() >= (now + timeout));
+      // assert(Util::currentTime() >= (now + timeout));
       throw TimedOutException();
     } else if (result != 0) {
-      throw TException(
-        "pthread_cond_wait() or pthread_cond_timedwait() failed");
+      throw TException("pthread_cond_wait() or pthread_cond_timedwait() failed");
     }
   }
 
@@ -110,19 +102,16 @@
    */
   int waitForTime(const THRIFT_TIMESPEC* abstime) const {
     assert(mutex_);
-    pthread_mutex_t* mutexImpl =
-      reinterpret_cast<pthread_mutex_t*>(mutex_->getUnderlyingImpl());
+    pthread_mutex_t* mutexImpl = reinterpret_cast<pthread_mutex_t*>(mutex_->getUnderlyingImpl());
     assert(mutexImpl);
 
     // XXX Need to assert that caller owns mutex
-    return pthread_cond_timedwait(&pthread_cond_,
-                                  mutexImpl,
-                                  abstime);
+    return pthread_cond_timedwait(&pthread_cond_, mutexImpl, abstime);
   }
 
   int waitForTime(const struct timeval* abstime) const {
     struct THRIFT_TIMESPEC temp;
-    temp.tv_sec  = abstime->tv_sec;
+    temp.tv_sec = abstime->tv_sec;
     temp.tv_nsec = abstime->tv_usec * 1000;
     return waitForTime(&temp);
   }
@@ -132,13 +121,11 @@
    */
   int waitForever() const {
     assert(mutex_);
-    pthread_mutex_t* mutexImpl =
-      reinterpret_cast<pthread_mutex_t*>(mutex_->getUnderlyingImpl());
+    pthread_mutex_t* mutexImpl = reinterpret_cast<pthread_mutex_t*>(mutex_->getUnderlyingImpl());
     assert(mutexImpl);
     return pthread_cond_wait(&pthread_cond_, mutexImpl);
   }
 
-
   void notify() {
     // XXX Need to assert that caller owns mutex
     int iret = pthread_cond_signal(&pthread_cond_);
@@ -153,8 +140,7 @@
     assert(iret == 0);
   }
 
- private:
-
+private:
   void init(Mutex* mutex) {
     mutex_ = mutex;
 
@@ -177,26 +163,39 @@
     }
   }
 
-  scoped_ptr<Mutex> ownedMutex_;
+  unique_ptr<Mutex> ownedMutex_;
   Mutex* mutex_;
 
   mutable pthread_cond_t pthread_cond_;
   mutable bool condInitialized_;
 };
 
-Monitor::Monitor() : impl_(new Monitor::Impl()) {}
-Monitor::Monitor(Mutex* mutex) : impl_(new Monitor::Impl(mutex)) {}
-Monitor::Monitor(Monitor* monitor) : impl_(new Monitor::Impl(monitor)) {}
+Monitor::Monitor() : impl_(new Monitor::Impl()) {
+}
+Monitor::Monitor(Mutex* mutex) : impl_(new Monitor::Impl(mutex)) {
+}
+Monitor::Monitor(Monitor* monitor) : impl_(new Monitor::Impl(monitor)) {
+}
 
-Monitor::~Monitor() { delete impl_; }
+Monitor::~Monitor() {
+  delete impl_;
+}
 
-Mutex& Monitor::mutex() const { return impl_->mutex(); }
+Mutex& Monitor::mutex() const {
+  return impl_->mutex();
+}
 
-void Monitor::lock() const { impl_->lock(); }
+void Monitor::lock() const {
+  impl_->lock();
+}
 
-void Monitor::unlock() const { impl_->unlock(); }
+void Monitor::unlock() const {
+  impl_->unlock();
+}
 
-void Monitor::wait(int64_t timeout) const { impl_->wait(timeout); }
+void Monitor::wait(int64_t timeout) const {
+  impl_->wait(timeout);
+}
 
 int Monitor::waitForTime(const THRIFT_TIMESPEC* abstime) const {
   return impl_->waitForTime(abstime);
@@ -214,8 +213,13 @@
   return impl_->waitForever();
 }
 
-void Monitor::notify() const { impl_->notify(); }
+void Monitor::notify() const {
+  impl_->notify();
+}
 
-void Monitor::notifyAll() const { impl_->notifyAll(); }
-
-}}} // apache::thrift::concurrency
+void Monitor::notifyAll() const {
+  impl_->notifyAll();
+}
+}
+}
+} // apache::thrift::concurrency
diff --git a/lib/cpp/src/thrift/concurrency/Monitor.h b/lib/cpp/src/thrift/concurrency/Monitor.h
index 811e0e1..2399a98 100644
--- a/lib/cpp/src/thrift/concurrency/Monitor.h
+++ b/lib/cpp/src/thrift/concurrency/Monitor.h
@@ -20,13 +20,18 @@
 #ifndef _THRIFT_CONCURRENCY_MONITOR_H_
 #define _THRIFT_CONCURRENCY_MONITOR_H_ 1
 
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
 #include <thrift/concurrency/Exception.h>
 #include <thrift/concurrency/Mutex.h>
 
 #include <boost/utility.hpp>
 
-
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 /**
  * A monitor is a combination mutex and condition-event.  Waiting and
@@ -47,7 +52,7 @@
  * @version $Id:$
  */
 class Monitor : boost::noncopyable {
- public:
+public:
   /** Creates a new mutex, and takes ownership of it. */
   Monitor();
 
@@ -101,30 +106,28 @@
    */
   void wait(int64_t timeout_ms = 0LL) const;
 
-
   /** Wakes up one thread waiting on this monitor. */
   virtual void notify() const;
 
   /** Wakes up all waiting threads on this monitor. */
   virtual void notifyAll() const;
 
- private:
-
+private:
   class Impl;
 
   Impl* impl_;
 };
 
 class Synchronized {
- public:
- Synchronized(const Monitor* monitor) : g(monitor->mutex()) { }
- Synchronized(const Monitor& monitor) : g(monitor.mutex()) { }
+public:
+  Synchronized(const Monitor* monitor) : g(monitor->mutex()) {}
+  Synchronized(const Monitor& monitor) : g(monitor.mutex()) {}
 
- private:
+private:
   Guard g;
 };
-
-
-}}} // apache::thrift::concurrency
+}
+}
+} // apache::thrift::concurrency
 
 #endif // #ifndef _THRIFT_CONCURRENCY_MONITOR_H_
diff --git a/lib/cpp/src/thrift/concurrency/Mutex.cpp b/lib/cpp/src/thrift/concurrency/Mutex.cpp
index 3f7bb5b..a526461 100644
--- a/lib/cpp/src/thrift/concurrency/Mutex.cpp
+++ b/lib/cpp/src/thrift/concurrency/Mutex.cpp
@@ -17,63 +17,69 @@
  * under the License.
  */
 
+// needed to test for pthread implementation capabilities:
+#define __USE_GNU
+
 #include <thrift/thrift-config.h>
 
 #include <thrift/Thrift.h>
+#include <thrift/concurrency/Exception.h>
 #include <thrift/concurrency/Mutex.h>
 #include <thrift/concurrency/Util.h>
 
 #include <assert.h>
-#ifdef HAVE_PTHREAD_H
+#include <stdlib.h>
 #include <pthread.h>
-#endif
 #include <signal.h>
+#include <string.h>
 
-using boost::shared_ptr;
+#include <boost/format.hpp>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
-#ifndef THRIFT_NO_CONTENTION_PROFILING
+// Enable this to turn on mutex contention profiling support
+// #define THRIFT_PTHREAD_MUTEX_CONTENTION_PROFILING
 
-static sig_atomic_t mutexProfilingSampleRate = 0;
+#ifdef THRIFT_PTHREAD_MUTEX_CONTENTION_PROFILING
+
+static int32_t mutexProfilingCounter = 0;
+static int32_t mutexProfilingSampleRate = 0;
 static MutexWaitCallback mutexProfilingCallback = 0;
 
-volatile static sig_atomic_t mutexProfilingCounter = 0;
-
-void enableMutexProfiling(int32_t profilingSampleRate,
-                          MutexWaitCallback callback) {
+void enableMutexProfiling(int32_t profilingSampleRate, MutexWaitCallback callback) {
   mutexProfilingSampleRate = profilingSampleRate;
   mutexProfilingCallback = callback;
 }
 
-#define PROFILE_MUTEX_START_LOCK() \
-    int64_t _lock_startTime = maybeGetProfilingStartTime();
+#define PROFILE_MUTEX_START_LOCK() int64_t _lock_startTime = maybeGetProfilingStartTime();
 
-#define PROFILE_MUTEX_NOT_LOCKED() \
-  do { \
-    if (_lock_startTime > 0) { \
-      int64_t endTime = Util::currentTimeUsec(); \
-      (*mutexProfilingCallback)(this, endTime - _lock_startTime); \
-    } \
+#define PROFILE_MUTEX_NOT_LOCKED()                                                                 \
+  do {                                                                                             \
+    if (_lock_startTime > 0) {                                                                     \
+      int64_t endTime = Util::currentTimeUsec();                                                   \
+      (*mutexProfilingCallback)(this, endTime - _lock_startTime);                                  \
+    }                                                                                              \
   } while (0)
 
-#define PROFILE_MUTEX_LOCKED() \
-  do { \
-    profileTime_ = _lock_startTime; \
-    if (profileTime_ > 0) { \
-      profileTime_ = Util::currentTimeUsec() - profileTime_; \
-    } \
+#define PROFILE_MUTEX_LOCKED()                                                                     \
+  do {                                                                                             \
+    profileTime_ = _lock_startTime;                                                                \
+    if (profileTime_ > 0) {                                                                        \
+      profileTime_ = Util::currentTimeUsec() - profileTime_;                                       \
+    }                                                                                              \
   } while (0)
 
-#define PROFILE_MUTEX_START_UNLOCK() \
-  int64_t _temp_profileTime = profileTime_; \
+#define PROFILE_MUTEX_START_UNLOCK()                                                               \
+  int64_t _temp_profileTime = profileTime_;                                                        \
   profileTime_ = 0;
 
-#define PROFILE_MUTEX_UNLOCKED() \
-  do { \
-    if (_temp_profileTime > 0) { \
-      (*mutexProfilingCallback)(this, _temp_profileTime); \
-    } \
+#define PROFILE_MUTEX_UNLOCKED()                                                                   \
+  do {                                                                                             \
+    if (_temp_profileTime > 0) {                                                                   \
+      (*mutexProfilingCallback)(this, _temp_profileTime);                                          \
+    }                                                                                              \
   } while (0)
 
 static inline int64_t maybeGetProfilingStartTime() {
@@ -101,22 +107,30 @@
 }
 
 #else
-#  define PROFILE_MUTEX_START_LOCK()
-#  define PROFILE_MUTEX_NOT_LOCKED()
-#  define PROFILE_MUTEX_LOCKED()
-#  define PROFILE_MUTEX_START_UNLOCK()
-#  define PROFILE_MUTEX_UNLOCKED()
-#endif // THRIFT_NO_CONTENTION_PROFILING
+#define PROFILE_MUTEX_START_LOCK()
+#define PROFILE_MUTEX_NOT_LOCKED()
+#define PROFILE_MUTEX_LOCKED()
+#define PROFILE_MUTEX_START_UNLOCK()
+#define PROFILE_MUTEX_UNLOCKED()
+#endif // THRIFT_PTHREAD_MUTEX_CONTENTION_PROFILING
+
+#define EINTR_LOOP(_CALL)          int ret; do { ret = _CALL; } while (ret == EINTR)
+#define ABORT_ONFAIL(_CALL)      { EINTR_LOOP(_CALL); if (ret) { abort(); } }
+#define THROW_SRE(_CALLSTR, RET) { throw SystemResourceException(boost::str(boost::format("%1% returned %2% (%3%)") % _CALLSTR % RET % ::strerror(RET))); }
+#define THROW_SRE_ONFAIL(_CALL)  { EINTR_LOOP(_CALL); if (ret) { THROW_SRE(#_CALL, ret); } }
+#define THROW_SRE_TRYFAIL(_CALL) { EINTR_LOOP(_CALL); if (ret == 0) { return true; } else if (ret == EBUSY) { return false; } THROW_SRE(#_CALL, ret); }
 
 /**
  * Implementation of Mutex class using POSIX mutex
  *
+ * Throws apache::thrift::concurrency::SystemResourceException on error.
+ *
  * @version $Id:$
  */
 class Mutex::impl {
- public:
+public:
   impl(Initializer init) : initialized_(false) {
-#ifndef THRIFT_NO_CONTENTION_PROFILING
+#ifdef THRIFT_PTHREAD_MUTEX_CONTENTION_PROFILING
     profileTime_ = 0;
 #endif
     init(&pthread_mutex_);
@@ -126,19 +140,19 @@
   ~impl() {
     if (initialized_) {
       initialized_ = false;
-      int ret = pthread_mutex_destroy(&pthread_mutex_);
-      THRIFT_UNUSED_VARIABLE(ret);
-      assert(ret == 0);
+      ABORT_ONFAIL(pthread_mutex_destroy(&pthread_mutex_));
     }
   }
 
   void lock() const {
     PROFILE_MUTEX_START_LOCK();
-    pthread_mutex_lock(&pthread_mutex_);
+    THROW_SRE_ONFAIL(pthread_mutex_lock(&pthread_mutex_));
     PROFILE_MUTEX_LOCKED();
   }
 
-  bool trylock() const { return (0 == pthread_mutex_trylock(&pthread_mutex_)); }
+  bool trylock() const {
+    THROW_SRE_TRYFAIL(pthread_mutex_trylock(&pthread_mutex_));
+  }
 
   bool timedlock(int64_t milliseconds) const {
 #if defined(_POSIX_TIMEOUTS) && _POSIX_TIMEOUTS >= 200112L
@@ -146,14 +160,16 @@
 
     struct THRIFT_TIMESPEC ts;
     Util::toTimespec(ts, milliseconds + Util::currentTime());
-    int ret = pthread_mutex_timedlock(&pthread_mutex_, &ts);
+    EINTR_LOOP(pthread_mutex_timedlock(&pthread_mutex_, &ts));
     if (ret == 0) {
       PROFILE_MUTEX_LOCKED();
       return true;
+    } else if (ret == ETIMEDOUT) {
+      PROFILE_MUTEX_NOT_LOCKED();
+      return false;
     }
 
-    PROFILE_MUTEX_NOT_LOCKED();
-    return false;
+    THROW_SRE("pthread_mutex_timedlock(&pthread_mutex_, &ts)", ret);
 #else
     /* Otherwise follow solution used by Mono for Android */
     struct THRIFT_TIMESPEC sleepytime, now, to;
@@ -178,55 +194,55 @@
 
   void unlock() const {
     PROFILE_MUTEX_START_UNLOCK();
-    pthread_mutex_unlock(&pthread_mutex_);
+    THROW_SRE_ONFAIL(pthread_mutex_unlock(&pthread_mutex_));
     PROFILE_MUTEX_UNLOCKED();
   }
 
-  void* getUnderlyingImpl() const { return (void*) &pthread_mutex_; }
+  void* getUnderlyingImpl() const { return (void*)&pthread_mutex_; }
 
- private:
+private:
   mutable pthread_mutex_t pthread_mutex_;
   mutable bool initialized_;
-#ifndef THRIFT_NO_CONTENTION_PROFILING
+#ifdef THRIFT_PTHREAD_MUTEX_CONTENTION_PROFILING
   mutable int64_t profileTime_;
 #endif
 };
 
-Mutex::Mutex(Initializer init) : impl_(new Mutex::impl(init)) {}
+Mutex::Mutex(Initializer init) : impl_(new Mutex::impl(init)) {
+}
 
-void* Mutex::getUnderlyingImpl() const { return impl_->getUnderlyingImpl(); }
+void* Mutex::getUnderlyingImpl() const {
+  return impl_->getUnderlyingImpl();
+}
 
-void Mutex::lock() const { impl_->lock(); }
+void Mutex::lock() const {
+  impl_->lock();
+}
 
-bool Mutex::trylock() const { return impl_->trylock(); }
+bool Mutex::trylock() const {
+  return impl_->trylock();
+}
 
-bool Mutex::timedlock(int64_t ms) const { return impl_->timedlock(ms); }
+bool Mutex::timedlock(int64_t ms) const {
+  return impl_->timedlock(ms);
+}
 
-void Mutex::unlock() const { impl_->unlock(); }
+void Mutex::unlock() const {
+  impl_->unlock();
+}
 
 void Mutex::DEFAULT_INITIALIZER(void* arg) {
   pthread_mutex_t* pthread_mutex = (pthread_mutex_t*)arg;
-  int ret = pthread_mutex_init(pthread_mutex, NULL);
-  THRIFT_UNUSED_VARIABLE(ret);
-  assert(ret == 0);
+  THROW_SRE_ONFAIL(pthread_mutex_init(pthread_mutex, NULL));
 }
 
-#if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) || defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
+#if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) || defined(PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP) || defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
 static void init_with_kind(pthread_mutex_t* mutex, int kind) {
   pthread_mutexattr_t mutexattr;
-  int ret = pthread_mutexattr_init(&mutexattr);
-  assert(ret == 0);
-
-  // Apparently, this can fail.  Should we really be aborting?
-  ret = pthread_mutexattr_settype(&mutexattr, kind);
-  assert(ret == 0);
-
-  ret = pthread_mutex_init(mutex, &mutexattr);
-  assert(ret == 0);
-
-  ret = pthread_mutexattr_destroy(&mutexattr);
-  assert(ret == 0);
-  THRIFT_UNUSED_VARIABLE(ret);
+  THROW_SRE_ONFAIL(pthread_mutexattr_init(&mutexattr));
+  THROW_SRE_ONFAIL(pthread_mutexattr_settype(&mutexattr, kind));
+  THROW_SRE_ONFAIL(pthread_mutex_init(mutex, &mutexattr));
+  THROW_SRE_ONFAIL(pthread_mutexattr_destroy(&mutexattr));
 }
 #endif
 
@@ -244,13 +260,18 @@
 }
 #endif
 
+#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
+void Mutex::ERRORCHECK_INITIALIZER(void* arg) {
+  init_with_kind((pthread_mutex_t*)arg, PTHREAD_MUTEX_ERRORCHECK);
+}
+#endif
+
 #ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
 void Mutex::RECURSIVE_INITIALIZER(void* arg) {
   init_with_kind((pthread_mutex_t*)arg, PTHREAD_MUTEX_RECURSIVE_NP);
 }
 #endif
 
-
 /**
  * Implementation of ReadWriteMutex class using POSIX rw lock
  *
@@ -259,70 +280,77 @@
 class ReadWriteMutex::impl {
 public:
   impl() : initialized_(false) {
-#ifndef THRIFT_NO_CONTENTION_PROFILING
+#ifdef THRIFT_PTHREAD_MUTEX_CONTENTION_PROFILING
     profileTime_ = 0;
 #endif
-    int ret = pthread_rwlock_init(&rw_lock_, NULL);
-    THRIFT_UNUSED_VARIABLE(ret);
-    assert(ret == 0);
+    THROW_SRE_ONFAIL(pthread_rwlock_init(&rw_lock_, NULL));
     initialized_ = true;
   }
 
   ~impl() {
-    if(initialized_) {
+    if (initialized_) {
       initialized_ = false;
-      int ret = pthread_rwlock_destroy(&rw_lock_);
-      THRIFT_UNUSED_VARIABLE(ret);
-      assert(ret == 0);
+      ABORT_ONFAIL(pthread_rwlock_destroy(&rw_lock_));
     }
   }
 
   void acquireRead() const {
     PROFILE_MUTEX_START_LOCK();
-    pthread_rwlock_rdlock(&rw_lock_);
-    PROFILE_MUTEX_NOT_LOCKED();  // not exclusive, so use not-locked path
+    THROW_SRE_ONFAIL(pthread_rwlock_rdlock(&rw_lock_));
+    PROFILE_MUTEX_NOT_LOCKED(); // not exclusive, so use not-locked path
   }
 
   void acquireWrite() const {
     PROFILE_MUTEX_START_LOCK();
-    pthread_rwlock_wrlock(&rw_lock_);
+    THROW_SRE_ONFAIL(pthread_rwlock_wrlock(&rw_lock_));
     PROFILE_MUTEX_LOCKED();
   }
 
-  bool attemptRead() const { return !pthread_rwlock_tryrdlock(&rw_lock_); }
+  bool attemptRead() const { THROW_SRE_TRYFAIL(pthread_rwlock_tryrdlock(&rw_lock_)); }
 
-  bool attemptWrite() const { return !pthread_rwlock_trywrlock(&rw_lock_); }
+  bool attemptWrite() const { THROW_SRE_TRYFAIL(pthread_rwlock_trywrlock(&rw_lock_)); }
 
   void release() const {
     PROFILE_MUTEX_START_UNLOCK();
-    pthread_rwlock_unlock(&rw_lock_);
+    THROW_SRE_ONFAIL(pthread_rwlock_unlock(&rw_lock_));
     PROFILE_MUTEX_UNLOCKED();
   }
 
 private:
   mutable pthread_rwlock_t rw_lock_;
   mutable bool initialized_;
-#ifndef THRIFT_NO_CONTENTION_PROFILING
+#ifdef THRIFT_PTHREAD_MUTEX_CONTENTION_PROFILING
   mutable int64_t profileTime_;
 #endif
 };
 
-ReadWriteMutex::ReadWriteMutex() : impl_(new ReadWriteMutex::impl()) {}
+ReadWriteMutex::ReadWriteMutex() : impl_(new ReadWriteMutex::impl()) {
+}
 
-void ReadWriteMutex::acquireRead() const { impl_->acquireRead(); }
+void ReadWriteMutex::acquireRead() const {
+  impl_->acquireRead();
+}
 
-void ReadWriteMutex::acquireWrite() const { impl_->acquireWrite(); }
+void ReadWriteMutex::acquireWrite() const {
+  impl_->acquireWrite();
+}
 
-bool ReadWriteMutex::attemptRead() const { return impl_->attemptRead(); }
+bool ReadWriteMutex::attemptRead() const {
+  return impl_->attemptRead();
+}
 
-bool ReadWriteMutex::attemptWrite() const { return impl_->attemptWrite(); }
+bool ReadWriteMutex::attemptWrite() const {
+  return impl_->attemptWrite();
+}
 
-void ReadWriteMutex::release() const { impl_->release(); }
+void ReadWriteMutex::release() const {
+  impl_->release();
+}
 
-NoStarveReadWriteMutex::NoStarveReadWriteMutex() : writerWaiting_(false) {}
+NoStarveReadWriteMutex::NoStarveReadWriteMutex() : writerWaiting_(false) {
+}
 
-void NoStarveReadWriteMutex::acquireRead() const
-{
+void NoStarveReadWriteMutex::acquireRead() const {
   if (writerWaiting_) {
     // writer is waiting, block on the writer's mutex until he's done with it
     mutex_.lock();
@@ -332,8 +360,7 @@
   ReadWriteMutex::acquireRead();
 }
 
-void NoStarveReadWriteMutex::acquireWrite() const
-{
+void NoStarveReadWriteMutex::acquireWrite() const {
   // if we can acquire the rwlock the easy way, we're done
   if (attemptWrite()) {
     return;
@@ -348,6 +375,6 @@
   writerWaiting_ = false;
   mutex_.unlock();
 }
-
-}}} // apache::thrift::concurrency
-
+}
+}
+} // apache::thrift::concurrency
diff --git a/lib/cpp/src/thrift/concurrency/Mutex.h b/lib/cpp/src/thrift/concurrency/Mutex.h
index 3cd8440..a1f5396 100644
--- a/lib/cpp/src/thrift/concurrency/Mutex.h
+++ b/lib/cpp/src/thrift/concurrency/Mutex.h
@@ -20,10 +20,13 @@
 #ifndef _THRIFT_CONCURRENCY_MUTEX_H_
 #define _THRIFT_CONCURRENCY_MUTEX_H_ 1
 
-#include <boost/shared_ptr.hpp>
+#include <memory>
 #include <boost/noncopyable.hpp>
+#include <stdint.h>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 #ifndef THRIFT_NO_CONTENTION_PROFILING
 
@@ -46,22 +49,27 @@
  * particular time period.
  */
 typedef void (*MutexWaitCallback)(const void* id, int64_t waitTimeMicros);
-void enableMutexProfiling(int32_t profilingSampleRate,
-                          MutexWaitCallback callback);
+void enableMutexProfiling(int32_t profilingSampleRate, MutexWaitCallback callback);
 
 #endif
 
 /**
+ * NOTE: All mutex implementations throw an exception on failure.  See each
+ *       specific implementation to understand the exception type(s) used.
+ */
+
+/**
  * A simple mutex class
  *
  * @version $Id:$
  */
 class Mutex {
- public:
+public:
   typedef void (*Initializer)(void*);
 
   Mutex(Initializer init = DEFAULT_INITIALIZER);
   virtual ~Mutex() {}
+
   virtual void lock() const;
   virtual bool trylock() const;
   virtual bool timedlock(int64_t milliseconds) const;
@@ -69,14 +77,16 @@
 
   void* getUnderlyingImpl() const;
 
-  static void DEFAULT_INITIALIZER(void*);
+  // If you attempt to use one of these and it fails to link, it means
+  // your version of pthreads does not support it - try another one.
   static void ADAPTIVE_INITIALIZER(void*);
+  static void DEFAULT_INITIALIZER(void*);
+  static void ERRORCHECK_INITIALIZER(void*);
   static void RECURSIVE_INITIALIZER(void*);
 
- private:
-
+private:
   class impl;
-  boost::shared_ptr<impl> impl_;
+  std::shared_ptr<impl> impl_;
 };
 
 class ReadWriteMutex {
@@ -96,9 +106,8 @@
   virtual void release() const;
 
 private:
-
   class impl;
-  boost::shared_ptr<impl> impl_;
+  std::shared_ptr<impl> impl_;
 };
 
 /**
@@ -121,7 +130,7 @@
 };
 
 class Guard : boost::noncopyable {
- public:
+public:
   Guard(const Mutex& value, int64_t timeout = 0) : mutex_(&value) {
     if (timeout == 0) {
       value.lock();
@@ -141,48 +150,40 @@
     }
   }
 
-  operator bool() const {
-    return (mutex_ != NULL);
-  }
+  operator bool() const { return (mutex_ != NULL); }
 
- private:
+private:
   const Mutex* mutex_;
 };
 
 // Can be used as second argument to RWGuard to make code more readable
 // as to whether we're doing acquireRead() or acquireWrite().
-enum RWGuardType {
-  RW_READ = 0,
-  RW_WRITE = 1
-};
-
+enum RWGuardType { RW_READ = 0, RW_WRITE = 1 };
 
 class RWGuard : boost::noncopyable {
-  public:
-    RWGuard(const ReadWriteMutex& value, bool write = false)
-         : rw_mutex_(value) {
-      if (write) {
-        rw_mutex_.acquireWrite();
-      } else {
-        rw_mutex_.acquireRead();
-      }
+public:
+  RWGuard(const ReadWriteMutex& value, bool write = false) : rw_mutex_(value) {
+    if (write) {
+      rw_mutex_.acquireWrite();
+    } else {
+      rw_mutex_.acquireRead();
     }
+  }
 
-    RWGuard(const ReadWriteMutex& value, RWGuardType type)
-         : rw_mutex_(value) {
-      if (type == RW_WRITE) {
-        rw_mutex_.acquireWrite();
-      } else {
-        rw_mutex_.acquireRead();
-      }
+  RWGuard(const ReadWriteMutex& value, RWGuardType type) : rw_mutex_(value) {
+    if (type == RW_WRITE) {
+      rw_mutex_.acquireWrite();
+    } else {
+      rw_mutex_.acquireRead();
     }
-    ~RWGuard() {
-      rw_mutex_.release();
-    }
-  private:
-    const ReadWriteMutex& rw_mutex_;
+  }
+  ~RWGuard() { rw_mutex_.release(); }
+
+private:
+  const ReadWriteMutex& rw_mutex_;
 };
-
-}}} // apache::thrift::concurrency
+}
+}
+} // apache::thrift::concurrency
 
 #endif // #ifndef _THRIFT_CONCURRENCY_MUTEX_H_
diff --git a/lib/cpp/src/thrift/concurrency/PlatformThreadFactory.h b/lib/cpp/src/thrift/concurrency/PlatformThreadFactory.h
index 6e46dfc..99b4403 100644
--- a/lib/cpp/src/thrift/concurrency/PlatformThreadFactory.h
+++ b/lib/cpp/src/thrift/concurrency/PlatformThreadFactory.h
@@ -20,25 +20,29 @@
 #ifndef _THRIFT_CONCURRENCY_PLATFORMTHREADFACTORY_H_
 #define _THRIFT_CONCURRENCY_PLATFORMTHREADFACTORY_H_ 1
 
+// clang-format off
 #include <thrift/thrift-config.h>
-#if USE_BOOST_THREAD
-#  include <thrift/concurrency/BoostThreadFactory.h>
-#elif USE_STD_THREAD
+#if USE_STD_THREAD
 #  include <thrift/concurrency/StdThreadFactory.h>
 #else
 #  include <thrift/concurrency/PosixThreadFactory.h>
 #endif
+// clang-format on
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
-#ifdef USE_BOOST_THREAD
-  typedef BoostThreadFactory PlatformThreadFactory;
-#elif USE_STD_THREAD
+// clang-format off
+#if USE_STD_THREAD
   typedef StdThreadFactory PlatformThreadFactory;
 #else
   typedef PosixThreadFactory PlatformThreadFactory;
 #endif
+// clang-format on
 
-}}} // apache::thrift::concurrency
+}
+}
+} // apache::thrift::concurrency
 
 #endif // #ifndef _THRIFT_CONCURRENCY_PLATFORMTHREADFACTORY_H_
diff --git a/lib/cpp/src/thrift/concurrency/PosixThreadFactory.cpp b/lib/cpp/src/thrift/concurrency/PosixThreadFactory.cpp
index 52ceead..5c59269 100644
--- a/lib/cpp/src/thrift/concurrency/PosixThreadFactory.cpp
+++ b/lib/cpp/src/thrift/concurrency/PosixThreadFactory.cpp
@@ -19,11 +19,12 @@
 
 #include <thrift/thrift-config.h>
 
-#include <thrift/concurrency/PosixThreadFactory.h>
 #include <thrift/concurrency/Exception.h>
+#include <thrift/concurrency/Monitor.h>
+#include <thrift/concurrency/PosixThreadFactory.h>
 
 #if GOOGLE_PERFTOOLS_REGISTER_THREAD
-#  include <google/profiler.h>
+#include <google/profiler.h>
 #endif
 
 #include <assert.h>
@@ -31,55 +32,51 @@
 
 #include <iostream>
 
-#include <boost/weak_ptr.hpp>
+#include <memory>
 
-namespace apache { namespace thrift { namespace concurrency {
-
-using boost::shared_ptr;
-using boost::weak_ptr;
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 /**
  * The POSIX thread class.
  *
  * @version $Id:$
  */
-class PthreadThread: public Thread {
- public:
-
-  enum STATE {
-    uninitialized,
-    starting,
-    started,
-    stopping,
-    stopped
-  };
+class PthreadThread : public Thread {
+public:
+  enum STATE { uninitialized, starting, started, stopping, stopped };
 
   static const int MB = 1024 * 1024;
 
   static void* threadMain(void* arg);
 
- private:
+private:
   pthread_t pthread_;
-  STATE state_;
+  Monitor monitor_;		// guard to protect state_ and also notification
+  STATE state_;         // to protect proper thread start behavior
   int policy_;
   int priority_;
   int stackSize_;
-  weak_ptr<PthreadThread> self_;
+  std::weak_ptr<PthreadThread> self_;
   bool detached_;
 
- public:
-
-  PthreadThread(int policy, int priority, int stackSize, bool detached, shared_ptr<Runnable> runnable) :
+public:
+  PthreadThread(int policy,
+                int priority,
+                int stackSize,
+                bool detached,
+                std::shared_ptr<Runnable> runnable)
+    :
 
 #ifndef _WIN32
-    pthread_(0),
+      pthread_(0),
 #endif // _WIN32
-
-    state_(uninitialized),
-    policy_(policy),
-    priority_(priority),
-    stackSize_(stackSize),
-    detached_(detached) {
+      state_(uninitialized),
+      policy_(policy),
+      priority_(priority),
+      stackSize_(stackSize),
+      detached_(detached) {
 
     this->Thread::runnable(runnable);
   }
@@ -88,30 +85,47 @@
     /* Nothing references this thread, if is is not detached, do a join
        now, otherwise the thread-id and, possibly, other resources will
        be leaked. */
-    if(!detached_) {
+    if (!detached_) {
       try {
         join();
-      } catch(...) {
+      } catch (...) {
         // We're really hosed.
       }
     }
   }
 
+  STATE getState() const
+  {
+    Synchronized sync(monitor_);
+    return state_;
+  }
+
+  void setState(STATE newState)
+  {
+    Synchronized sync(monitor_);
+    state_ = newState;
+
+    // unblock start() with the knowledge that the thread has actually
+    // started running, which avoids a race in detached threads.
+    if (newState == started) {
+	  monitor_.notify();
+    }
+  }
+
   void start() {
-    if (state_ != uninitialized) {
+    if (getState() != uninitialized) {
       return;
     }
 
     pthread_attr_t thread_attr;
     if (pthread_attr_init(&thread_attr) != 0) {
-        throw SystemResourceException("pthread_attr_init failed");
+      throw SystemResourceException("pthread_attr_init failed");
     }
 
-    if(pthread_attr_setdetachstate(&thread_attr,
-                                   detached_ ?
-                                   PTHREAD_CREATE_DETACHED :
-                                   PTHREAD_CREATE_JOINABLE) != 0) {
-        throw SystemResourceException("pthread_attr_setdetachstate failed");
+    if (pthread_attr_setdetachstate(&thread_attr,
+                                    detached_ ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE)
+        != 0) {
+      throw SystemResourceException("pthread_attr_setdetachstate failed");
     }
 
     // Set thread stack size
@@ -119,15 +133,18 @@
       throw SystemResourceException("pthread_attr_setstacksize failed");
     }
 
-    // Set thread policy
-    #ifdef _WIN32
-	//WIN32 Pthread implementation doesn't seem to support sheduling policies other then PosixThreadFactory::OTHER - runtime error
-	policy_ = PosixThreadFactory::OTHER;
-    #endif
+// Set thread policy
+#ifdef _WIN32
+    // WIN32 Pthread implementation doesn't seem to support sheduling policies other then
+    // PosixThreadFactory::OTHER - runtime error
+    policy_ = PosixThreadFactory::OTHER;
+#endif
 
+#if _POSIX_THREAD_PRIORITY_SCHEDULING > 0
     if (pthread_attr_setschedpolicy(&thread_attr, policy_) != 0) {
       throw SystemResourceException("pthread_attr_setschedpolicy failed");
     }
+#endif
 
     struct sched_param sched_param;
     sched_param.sched_priority = priority_;
@@ -138,18 +155,27 @@
     }
 
     // Create reference
-    shared_ptr<PthreadThread>* selfRef = new shared_ptr<PthreadThread>();
+    std::shared_ptr<PthreadThread>* selfRef = new std::shared_ptr<PthreadThread>();
     *selfRef = self_.lock();
 
-    state_ = starting;
+    setState(starting);
 
+	Synchronized sync(monitor_);
+	
     if (pthread_create(&pthread_, &thread_attr, threadMain, (void*)selfRef) != 0) {
       throw SystemResourceException("pthread_create failed");
     }
+    
+    // The caller may not choose to guarantee the scope of the Runnable
+    // being used in the thread, so we must actually wait until the thread
+    // starts before we return.  If we do not wait, it would be possible
+    // for the caller to start destructing the Runnable and the Thread,
+    // and we would end up in a race.  This was identified with valgrind.
+    monitor_.wait();
   }
 
   void join() {
-    if (!detached_ && state_ != uninitialized) {
+    if (!detached_ && getState() != uninitialized) {
       void* ignore;
       /* XXX
          If join fails it is most likely due to the fact
@@ -163,8 +189,6 @@
       if (res != 0) {
         GlobalOutput.printf("PthreadThread::join(): fail with code %d", res);
       }
-    } else {
-      GlobalOutput.printf("PthreadThread::join(): detached thread");
     }
   }
 
@@ -177,165 +201,135 @@
 #endif // _WIN32
   }
 
-  shared_ptr<Runnable> runnable() const { return Thread::runnable(); }
+  std::shared_ptr<Runnable> runnable() const { return Thread::runnable(); }
 
-  void runnable(shared_ptr<Runnable> value) { Thread::runnable(value); }
+  void runnable(std::shared_ptr<Runnable> value) { Thread::runnable(value); }
 
-  void weakRef(shared_ptr<PthreadThread> self) {
+  void weakRef(std::shared_ptr<PthreadThread> self) {
     assert(self.get() == this);
-    self_ = weak_ptr<PthreadThread>(self);
+    self_ = std::weak_ptr<PthreadThread>(self);
   }
 };
 
 void* PthreadThread::threadMain(void* arg) {
-  shared_ptr<PthreadThread> thread = *(shared_ptr<PthreadThread>*)arg;
-  delete reinterpret_cast<shared_ptr<PthreadThread>*>(arg);
-
-  if (thread == NULL) {
-    return (void*)0;
-  }
-
-  if (thread->state_ != starting) {
-    return (void*)0;
-  }
+  std::shared_ptr<PthreadThread> thread = *(std::shared_ptr<PthreadThread>*)arg;
+  delete reinterpret_cast<std::shared_ptr<PthreadThread>*>(arg);
 
 #if GOOGLE_PERFTOOLS_REGISTER_THREAD
   ProfilerRegisterThread();
 #endif
 
-  thread->state_ = started;
+  thread->setState(started);
+
   thread->runnable()->run();
-  if (thread->state_ != stopping && thread->state_ != stopped) {
-    thread->state_ = stopping;
+
+  STATE _s = thread->getState();
+  if (_s != stopping && _s != stopped) {
+    thread->setState(stopping);
   }
 
   return (void*)0;
 }
 
 /**
- * POSIX Thread factory implementation
+ * Converts generic posix thread schedule policy enums into pthread
+ * API values.
  */
-class PosixThreadFactory::Impl {
-
- private:
-  POLICY policy_;
-  PRIORITY priority_;
-  int stackSize_;
-  bool detached_;
-
-  /**
-   * Converts generic posix thread schedule policy enums into pthread
-   * API values.
-   */
-  static int toPthreadPolicy(POLICY policy) {
-    switch (policy) {
-    case OTHER:
-      return SCHED_OTHER;
-    case FIFO:
-      return SCHED_FIFO;
-    case ROUND_ROBIN:
-      return SCHED_RR;
-    }
+static int toPthreadPolicy(PosixThreadFactory::POLICY policy) {
+  switch (policy) {
+  case PosixThreadFactory::OTHER:
     return SCHED_OTHER;
+  case PosixThreadFactory::FIFO:
+    return SCHED_FIFO;
+  case PosixThreadFactory::ROUND_ROBIN:
+    return SCHED_RR;
   }
+  return SCHED_OTHER;
+}
 
-  /**
-   * Converts relative thread priorities to absolute value based on posix
-   * thread scheduler policy
-   *
-   *  The idea is simply to divide up the priority range for the given policy
-   * into the correpsonding relative priority level (lowest..highest) and
-   * then pro-rate accordingly.
-   */
-  static int toPthreadPriority(POLICY policy, PRIORITY priority) {
-    int pthread_policy = toPthreadPolicy(policy);
-    int min_priority = 0;
-    int max_priority = 0;
+/**
+ * Converts relative thread priorities to absolute value based on posix
+ * thread scheduler policy
+ *
+ *  The idea is simply to divide up the priority range for the given policy
+ * into the correpsonding relative priority level (lowest..highest) and
+ * then pro-rate accordingly.
+ */
+static int toPthreadPriority(PosixThreadFactory::POLICY policy, PosixThreadFactory::PRIORITY priority) {
+  int pthread_policy = toPthreadPolicy(policy);
+  int min_priority = 0;
+  int max_priority = 0;
 #ifdef HAVE_SCHED_GET_PRIORITY_MIN
-    min_priority = sched_get_priority_min(pthread_policy);
+  min_priority = sched_get_priority_min(pthread_policy);
 #endif
 #ifdef HAVE_SCHED_GET_PRIORITY_MAX
-    max_priority = sched_get_priority_max(pthread_policy);
+  max_priority = sched_get_priority_max(pthread_policy);
 #endif
-    int quanta = (HIGHEST - LOWEST) + 1;
-    float stepsperquanta = (float)(max_priority - min_priority) / quanta;
+  int quanta = (PosixThreadFactory::HIGHEST - PosixThreadFactory::LOWEST) + 1;
+  float stepsperquanta = (float)(max_priority - min_priority) / quanta;
 
-    if (priority <= HIGHEST) {
-      return (int)(min_priority + stepsperquanta * priority);
-    } else {
-      // should never get here for priority increments.
-      assert(false);
-      return (int)(min_priority + stepsperquanta * NORMAL);
-    }
+  if (priority <= PosixThreadFactory::HIGHEST) {
+    return (int)(min_priority + stepsperquanta * priority);
+  } else {
+    // should never get here for priority increments.
+    assert(false);
+    return (int)(min_priority + stepsperquanta * PosixThreadFactory::NORMAL);
   }
+}
 
- public:
-
-  Impl(POLICY policy, PRIORITY priority, int stackSize, bool detached) :
+PosixThreadFactory::PosixThreadFactory(POLICY policy,
+                                       PRIORITY priority,
+                                       int stackSize,
+                                       bool detached)
+  : ThreadFactory(detached),
     policy_(policy),
     priority_(priority),
-    stackSize_(stackSize),
-    detached_(detached) {}
+    stackSize_(stackSize) {
+}
 
-  /**
-   * Creates a new POSIX thread to run the runnable object
-   *
-   * @param runnable A runnable object
-   */
-  shared_ptr<Thread> newThread(shared_ptr<Runnable> runnable) const {
-    shared_ptr<PthreadThread> result = shared_ptr<PthreadThread>(new PthreadThread(toPthreadPolicy(policy_), toPthreadPriority(policy_, priority_), stackSize_, detached_, runnable));
-    result->weakRef(result);
-    runnable->thread(result);
-    return result;
-  }
+PosixThreadFactory::PosixThreadFactory(bool detached)
+  : ThreadFactory(detached),
+    policy_(ROUND_ROBIN),
+    priority_(NORMAL),
+    stackSize_(1) {
+}
 
-  int getStackSize() const { return stackSize_; }
+std::shared_ptr<Thread> PosixThreadFactory::newThread(std::shared_ptr<Runnable> runnable) const {
+  std::shared_ptr<PthreadThread> result
+      = std::shared_ptr<PthreadThread>(new PthreadThread(toPthreadPolicy(policy_),
+                                                    toPthreadPriority(policy_, priority_),
+                                                    stackSize_,
+                                                    isDetached(),
+                                                    runnable));
+  result->weakRef(result);
+  runnable->thread(result);
+  return result;
+}
 
-  void setStackSize(int value) { stackSize_ = value; }
+int PosixThreadFactory::getStackSize() const {
+  return stackSize_;
+}
 
-  PRIORITY getPriority() const { return priority_; }
+void PosixThreadFactory::setStackSize(int value) {
+  stackSize_ = value;
+}
 
-  /**
-   * Sets priority.
-   *
-   *  XXX
-   *  Need to handle incremental priorities properly.
-   */
-  void setPriority(PRIORITY value) { priority_ = value; }
+PosixThreadFactory::PRIORITY PosixThreadFactory::getPriority() const {
+  return priority_;
+}
 
-  bool isDetached() const { return detached_; }
+void PosixThreadFactory::setPriority(PRIORITY value) {
+  priority_ = value;
+}
 
-  void setDetached(bool value) { detached_ = value; }
-
-  Thread::id_t getCurrentThreadId() const {
-
+Thread::id_t PosixThreadFactory::getCurrentThreadId() const {
 #ifndef _WIN32
-    return (Thread::id_t)pthread_self();
+  return (Thread::id_t)pthread_self();
 #else
-    return (Thread::id_t)pthread_self().p;
+  return (Thread::id_t)pthread_self().p;
 #endif // _WIN32
+}
 
-  }
-
-};
-
-PosixThreadFactory::PosixThreadFactory(POLICY policy, PRIORITY priority, int stackSize, bool detached) :
-  impl_(new PosixThreadFactory::Impl(policy, priority, stackSize, detached)) {}
-
-shared_ptr<Thread> PosixThreadFactory::newThread(shared_ptr<Runnable> runnable) const { return impl_->newThread(runnable); }
-
-int PosixThreadFactory::getStackSize() const { return impl_->getStackSize(); }
-
-void PosixThreadFactory::setStackSize(int value) { impl_->setStackSize(value); }
-
-PosixThreadFactory::PRIORITY PosixThreadFactory::getPriority() const { return impl_->getPriority(); }
-
-void PosixThreadFactory::setPriority(PosixThreadFactory::PRIORITY value) { impl_->setPriority(value); }
-
-bool PosixThreadFactory::isDetached() const { return impl_->isDetached(); }
-
-void PosixThreadFactory::setDetached(bool value) { impl_->setDetached(value); }
-
-Thread::id_t PosixThreadFactory::getCurrentThreadId() const { return impl_->getCurrentThreadId(); }
-
-}}} // apache::thrift::concurrency
+}
+}
+} // apache::thrift::concurrency
diff --git a/lib/cpp/src/thrift/concurrency/PosixThreadFactory.h b/lib/cpp/src/thrift/concurrency/PosixThreadFactory.h
index 72368ca..cb3b17c 100644
--- a/lib/cpp/src/thrift/concurrency/PosixThreadFactory.h
+++ b/lib/cpp/src/thrift/concurrency/PosixThreadFactory.h
@@ -22,9 +22,11 @@
 
 #include <thrift/concurrency/Thread.h>
 
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 /**
  * A thread factory to create posix threads
@@ -33,23 +35,18 @@
  */
 class PosixThreadFactory : public ThreadFactory {
 
- public:
-
+public:
   /**
    * POSIX Thread scheduler policies
    */
-  enum POLICY {
-    OTHER,
-    FIFO,
-    ROUND_ROBIN
-  };
+  enum POLICY { OTHER, FIFO, ROUND_ROBIN };
 
   /**
    * POSIX Thread scheduler relative priorities,
    *
    * Absolute priority is determined by scheduler policy and OS. This
    * enumeration specifies relative priorities such that one can specify a
-   * priority withing a giving scheduler policy without knowing the absolute
+   * priority within a giving scheduler policy without knowing the absolute
    * value of the priority.
    */
   enum PRIORITY {
@@ -66,9 +63,9 @@
 
   /**
    * Posix thread (pthread) factory.  All threads created by a factory are reference-counted
-   * via boost::shared_ptr and boost::weak_ptr.  The factory guarantees that threads and
-   * the Runnable tasks they host will be properly cleaned up once the last strong reference
-   * to both is given up.
+   * via std::shared_ptr.  The factory guarantees that threads and the Runnable tasks 
+   * they host will be properly cleaned up once the last strong reference to both is
+   * given up.
    *
    * Threads are created with the specified policy, priority, stack-size and detachable-mode
    * detached means the thread is free-running and will release all system resources the
@@ -77,24 +74,34 @@
    *
    * By default threads are not joinable.
    */
+  PosixThreadFactory(POLICY policy = ROUND_ROBIN,
+                     PRIORITY priority = NORMAL,
+                     int stackSize = 1,
+                     bool detached = true);
 
-  PosixThreadFactory(POLICY policy=ROUND_ROBIN, PRIORITY priority=NORMAL, int stackSize=1, bool detached=true);
+  /**
+   * Provide a constructor compatible with the other factories
+   * The default policy is POLICY::ROUND_ROBIN.
+   * The default priority is PRIORITY::NORMAL.
+   * The default stackSize is 1.
+   */
+  PosixThreadFactory(bool detached);
 
   // From ThreadFactory;
-  boost::shared_ptr<Thread> newThread(boost::shared_ptr<Runnable> runnable) const;
+  std::shared_ptr<Thread> newThread(std::shared_ptr<Runnable> runnable) const;
 
   // From ThreadFactory;
   Thread::id_t getCurrentThreadId() const;
 
   /**
-   * Gets stack size for created threads
+   * Gets stack size for newly created threads
    *
    * @return int size in megabytes
    */
   virtual int getStackSize() const;
 
   /**
-   * Sets stack size for created threads
+   * Sets stack size for newly created threads
    *
    * @param value size in megabytes
    */
@@ -110,21 +117,13 @@
    */
   virtual void setPriority(PRIORITY priority);
 
-  /**
-   * Sets detached mode of threads
-   */
-  virtual void setDetached(bool detached);
-
-  /**
-   * Gets current detached mode
-   */
-  virtual bool isDetached() const;
-
- private:
-  class Impl;
-  boost::shared_ptr<Impl> impl_;
+private:
+  POLICY policy_;
+  PRIORITY priority_;
+  int stackSize_;
 };
-
-}}} // apache::thrift::concurrency
+}
+}
+} // apache::thrift::concurrency
 
 #endif // #ifndef _THRIFT_CONCURRENCY_POSIXTHREADFACTORY_H_
diff --git a/lib/cpp/src/thrift/concurrency/StdMonitor.cpp b/lib/cpp/src/thrift/concurrency/StdMonitor.cpp
index cf257e6..7b3b209 100644
--- a/lib/cpp/src/thrift/concurrency/StdMonitor.cpp
+++ b/lib/cpp/src/thrift/concurrency/StdMonitor.cpp
@@ -30,7 +30,9 @@
 #include <thread>
 #include <mutex>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 /**
  * Monitor implementation using the std thread library
@@ -39,26 +41,12 @@
  */
 class Monitor::Impl {
 
- public:
+public:
+  Impl() : ownedMutex_(new Mutex()), conditionVariable_(), mutex_(NULL) { init(ownedMutex_.get()); }
 
-  Impl()
-     : ownedMutex_(new Mutex()),
-       conditionVariable_(),
-       mutex_(NULL) {
-    init(ownedMutex_.get());
-  }
+  Impl(Mutex* mutex) : ownedMutex_(), conditionVariable_(), mutex_(NULL) { init(mutex); }
 
-  Impl(Mutex* mutex)
-     : ownedMutex_(),
-       conditionVariable_(),
-       mutex_(NULL) {
-    init(mutex);
-  }
-
-  Impl(Monitor* monitor)
-     : ownedMutex_(),
-       conditionVariable_(),
-       mutex_(NULL) {
+  Impl(Monitor* monitor) : ownedMutex_(), conditionVariable_(), mutex_(NULL) {
     init(&(monitor->mutex()));
   }
 
@@ -78,8 +66,7 @@
     if (result == THRIFT_ETIMEDOUT) {
       throw TimedOutException();
     } else if (result != 0) {
-      throw TException(
-        "Monitor::wait() failed");
+      throw TException("Monitor::wait() failed");
     }
   }
 
@@ -95,12 +82,12 @@
     }
 
     assert(mutex_);
-    std::timed_mutex* mutexImpl =
-      static_cast<std::timed_mutex*>(mutex_->getUnderlyingImpl());
+    std::timed_mutex* mutexImpl = static_cast<std::timed_mutex*>(mutex_->getUnderlyingImpl());
     assert(mutexImpl);
 
     std::unique_lock<std::timed_mutex> lock(*mutexImpl, std::adopt_lock);
-    bool timedout = (conditionVariable_.wait_for(lock, std::chrono::milliseconds(timeout_ms)) == std::cv_status::timeout);
+    bool timedout = (conditionVariable_.wait_for(lock, std::chrono::milliseconds(timeout_ms))
+                     == std::cv_status::timeout);
     lock.release();
     return (timedout ? THRIFT_ETIMEDOUT : 0);
   }
@@ -111,7 +98,7 @@
    */
   int waitForTime(const THRIFT_TIMESPEC* abstime) {
     struct timeval temp;
-    temp.tv_sec  = static_cast<long>(abstime->tv_sec);
+    temp.tv_sec = static_cast<long>(abstime->tv_sec);
     temp.tv_usec = static_cast<long>(abstime->tv_nsec) / 1000;
     return waitForTime(&temp);
   }
@@ -122,24 +109,24 @@
    */
   int waitForTime(const struct timeval* abstime) {
     assert(mutex_);
-    std::timed_mutex* mutexImpl =
-      static_cast<std::timed_mutex*>(mutex_->getUnderlyingImpl());
+    std::timed_mutex* mutexImpl = static_cast<std::timed_mutex*>(mutex_->getUnderlyingImpl());
     assert(mutexImpl);
 
     struct timeval currenttime;
     Util::toTimeval(currenttime, Util::currentTime());
 
-    long tv_sec  = static_cast<long>(abstime->tv_sec  - currenttime.tv_sec);
+    long tv_sec = static_cast<long>(abstime->tv_sec - currenttime.tv_sec);
     long tv_usec = static_cast<long>(abstime->tv_usec - currenttime.tv_usec);
-    if(tv_sec < 0)
+    if (tv_sec < 0)
       tv_sec = 0;
-    if(tv_usec < 0)
+    if (tv_usec < 0)
       tv_usec = 0;
 
     std::unique_lock<std::timed_mutex> lock(*mutexImpl, std::adopt_lock);
     bool timedout = (conditionVariable_.wait_for(lock,
-      std::chrono::seconds(tv_sec) +
-      std::chrono::microseconds(tv_usec)) == std::cv_status::timeout);
+                                                 std::chrono::seconds(tv_sec)
+                                                 + std::chrono::microseconds(tv_usec))
+                     == std::cv_status::timeout);
     lock.release();
     return (timedout ? THRIFT_ETIMEDOUT : 0);
   }
@@ -150,8 +137,7 @@
    */
   int waitForever() {
     assert(mutex_);
-    std::timed_mutex* mutexImpl =
-      static_cast<std::timed_mutex*>(mutex_->getUnderlyingImpl());
+    std::timed_mutex* mutexImpl = static_cast<std::timed_mutex*>(mutex_->getUnderlyingImpl());
     assert(mutexImpl);
 
     std::unique_lock<std::timed_mutex> lock(*mutexImpl, std::adopt_lock);
@@ -160,39 +146,44 @@
     return 0;
   }
 
+  void notify() { conditionVariable_.notify_one(); }
 
-  void notify() {
-    conditionVariable_.notify_one();
-  }
+  void notifyAll() { conditionVariable_.notify_all(); }
 
-  void notifyAll() {
-    conditionVariable_.notify_all();
-  }
-
- private:
-
-  void init(Mutex* mutex) {
-    mutex_ = mutex;
-  }
+private:
+  void init(Mutex* mutex) { mutex_ = mutex; }
 
   const std::unique_ptr<Mutex> ownedMutex_;
   std::condition_variable_any conditionVariable_;
   Mutex* mutex_;
 };
 
-Monitor::Monitor() : impl_(new Monitor::Impl()) {}
-Monitor::Monitor(Mutex* mutex) : impl_(new Monitor::Impl(mutex)) {}
-Monitor::Monitor(Monitor* monitor) : impl_(new Monitor::Impl(monitor)) {}
+Monitor::Monitor() : impl_(new Monitor::Impl()) {
+}
+Monitor::Monitor(Mutex* mutex) : impl_(new Monitor::Impl(mutex)) {
+}
+Monitor::Monitor(Monitor* monitor) : impl_(new Monitor::Impl(monitor)) {
+}
 
-Monitor::~Monitor() { delete impl_; }
+Monitor::~Monitor() {
+  delete impl_;
+}
 
-Mutex& Monitor::mutex() const { return const_cast<Monitor::Impl*>(impl_)->mutex(); }
+Mutex& Monitor::mutex() const {
+  return const_cast<Monitor::Impl*>(impl_)->mutex();
+}
 
-void Monitor::lock() const { const_cast<Monitor::Impl*>(impl_)->lock(); }
+void Monitor::lock() const {
+  const_cast<Monitor::Impl*>(impl_)->lock();
+}
 
-void Monitor::unlock() const { const_cast<Monitor::Impl*>(impl_)->unlock(); }
+void Monitor::unlock() const {
+  const_cast<Monitor::Impl*>(impl_)->unlock();
+}
 
-void Monitor::wait(int64_t timeout) const { const_cast<Monitor::Impl*>(impl_)->wait(timeout); }
+void Monitor::wait(int64_t timeout) const {
+  const_cast<Monitor::Impl*>(impl_)->wait(timeout);
+}
 
 int Monitor::waitForTime(const THRIFT_TIMESPEC* abstime) const {
   return const_cast<Monitor::Impl*>(impl_)->waitForTime(abstime);
@@ -210,8 +201,13 @@
   return const_cast<Monitor::Impl*>(impl_)->waitForever();
 }
 
-void Monitor::notify() const { const_cast<Monitor::Impl*>(impl_)->notify(); }
+void Monitor::notify() const {
+  const_cast<Monitor::Impl*>(impl_)->notify();
+}
 
-void Monitor::notifyAll() const { const_cast<Monitor::Impl*>(impl_)->notifyAll(); }
-
-}}} // apache::thrift::concurrency
+void Monitor::notifyAll() const {
+  const_cast<Monitor::Impl*>(impl_)->notifyAll();
+}
+}
+}
+} // apache::thrift::concurrency
diff --git a/lib/cpp/src/thrift/concurrency/StdMutex.cpp b/lib/cpp/src/thrift/concurrency/StdMutex.cpp
index 28f889a..e0f79fa 100644
--- a/lib/cpp/src/thrift/concurrency/StdMutex.cpp
+++ b/lib/cpp/src/thrift/concurrency/StdMutex.cpp
@@ -26,30 +26,46 @@
 #include <chrono>
 #include <mutex>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 /**
  * Implementation of Mutex class using C++11 std::timed_mutex
  *
+ * Methods throw std::system_error on error.
+ *
  * @version $Id:$
  */
-class Mutex::impl : public std::timed_mutex {
-};
+class Mutex::impl : public std::timed_mutex {};
 
-Mutex::Mutex(Initializer init) : impl_(new Mutex::impl()) {}
-
-void* Mutex::getUnderlyingImpl() const { return impl_.get(); }
-
-void Mutex::lock() const { impl_->lock(); }
-
-bool Mutex::trylock() const { return impl_->try_lock(); }
-
-bool Mutex::timedlock(int64_t ms) const { return impl_->try_lock_for(std::chrono::milliseconds(ms)); }
-
-void Mutex::unlock() const { impl_->unlock(); }
-
-void Mutex::DEFAULT_INITIALIZER(void* arg) {
+Mutex::Mutex(Initializer init) : impl_(new Mutex::impl()) {
+  ((void)init);
 }
 
-}}} // apache::thrift::concurrency
+void* Mutex::getUnderlyingImpl() const {
+  return impl_.get();
+}
 
+void Mutex::lock() const {
+  impl_->lock();
+}
+
+bool Mutex::trylock() const {
+  return impl_->try_lock();
+}
+
+bool Mutex::timedlock(int64_t ms) const {
+  return impl_->try_lock_for(std::chrono::milliseconds(ms));
+}
+
+void Mutex::unlock() const {
+  impl_->unlock();
+}
+
+void Mutex::DEFAULT_INITIALIZER(void* arg) {
+  ((void)arg);
+}
+}
+}
+} // apache::thrift::concurrency
diff --git a/lib/cpp/src/thrift/concurrency/StdThreadFactory.cpp b/lib/cpp/src/thrift/concurrency/StdThreadFactory.cpp
index 3239bd9..c885f3a 100644
--- a/lib/cpp/src/thrift/concurrency/StdThreadFactory.cpp
+++ b/lib/cpp/src/thrift/concurrency/StdThreadFactory.cpp
@@ -19,16 +19,19 @@
 
 #include <thrift/thrift-config.h>
 
-#include <thrift/concurrency/StdThreadFactory.h>
+#if USE_STD_THREAD
+
 #include <thrift/concurrency/Exception.h>
+#include <thrift/concurrency/Monitor.h>
+#include <thrift/concurrency/StdThreadFactory.h>
+#include <memory>
 
 #include <cassert>
-
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/weak_ptr.hpp>
 #include <thread>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 /**
  * The C++11 thread class.
@@ -39,54 +42,70 @@
  *
  * @version $Id:$
  */
-class StdThread: public Thread, public boost::enable_shared_from_this<StdThread> {
- public:
+class StdThread : public Thread, public std::enable_shared_from_this<StdThread> {
+public:
+  enum STATE { uninitialized, starting, started, stopping, stopped };
 
-  enum STATE {
-    uninitialized,
-    starting,
-    started,
-    stopping,
-    stopped
-  };
+  static void threadMain(std::shared_ptr<StdThread> thread);
 
-   static void threadMain(boost::shared_ptr<StdThread> thread);
-
- private:
+private:
   std::unique_ptr<std::thread> thread_;
+  Monitor monitor_;
   STATE state_;
   bool detached_;
 
- public:
-
-  StdThread(bool detached, boost::shared_ptr<Runnable> runnable) :
-      state_(uninitialized),
-      detached_(detached) {
+public:
+  StdThread(bool detached, std::shared_ptr<Runnable> runnable)
+    : state_(uninitialized), detached_(detached) {
     this->Thread::runnable(runnable);
   }
 
   ~StdThread() {
-    if(!detached_) {
+    if (!detached_ && thread_->joinable()) {
       try {
         join();
-      } catch(...) {
+      } catch (...) {
         // We're really hosed.
       }
     }
   }
 
+  STATE getState() const
+  {
+    Synchronized sync(monitor_);
+    return state_;
+  }
+
+  void setState(STATE newState)
+  {
+    Synchronized sync(monitor_);
+    state_ = newState;
+
+    // unblock start() with the knowledge that the thread has actually
+    // started running, which avoids a race in detached threads.
+    if (newState == started) {
+	  monitor_.notify();
+    }
+  }
+
   void start() {
-    if (state_ != uninitialized) {
+    if (getState() != uninitialized) {
       return;
     }
-	
-    boost::shared_ptr<StdThread> selfRef = shared_from_this();
-    state_ = starting;
 
+    std::shared_ptr<StdThread> selfRef = shared_from_this();
+    setState(starting);
+
+    Synchronized sync(monitor_);
     thread_ = std::unique_ptr<std::thread>(new std::thread(threadMain, selfRef));
 
-    if(detached_)
+    if (detached_)
       thread_->detach();
+    
+    // Wait for the thread to start and get far enough to grab everything
+    // that it needs from the calling context, thus absolving the caller
+    // from being required to hold on to runnable indefinitely.
+    monitor_.wait();
   }
 
   void join() {
@@ -95,77 +114,40 @@
     }
   }
 
-  Thread::id_t getId() {
-    return thread_.get() ? thread_->get_id() : std::thread::id();
-  }
+  Thread::id_t getId() { return thread_.get() ? thread_->get_id() : std::thread::id(); }
 
-  boost::shared_ptr<Runnable> runnable() const { return Thread::runnable(); }
+  std::shared_ptr<Runnable> runnable() const { return Thread::runnable(); }
 
-  void runnable(boost::shared_ptr<Runnable> value) { Thread::runnable(value); }
+  void runnable(std::shared_ptr<Runnable> value) { Thread::runnable(value); }
 };
 
-void StdThread::threadMain(boost::shared_ptr<StdThread> thread) {
-  if (thread == NULL) {
-    return;
-  }
+void StdThread::threadMain(std::shared_ptr<StdThread> thread) {
+#if GOOGLE_PERFTOOLS_REGISTER_THREAD
+  ProfilerRegisterThread();
+#endif
 
-  if (thread->state_ != starting) {
-    return;
-  }
-
-  thread->state_ = started;
+  thread->setState(started);
   thread->runnable()->run();
 
-  if (thread->state_ != stopping && thread->state_ != stopped) {
-    thread->state_ = stopping;
+  if (thread->getState() != stopping && thread->getState() != stopped) {
+    thread->setState(stopping);
   }
-
-  return;
 }
 
-/**
- * std::thread factory implementation
- */
-class StdThreadFactory::Impl {
+StdThreadFactory::StdThreadFactory(bool detached) : ThreadFactory(detached) {
+}
 
- private:
-  bool detached_;
+std::shared_ptr<Thread> StdThreadFactory::newThread(std::shared_ptr<Runnable> runnable) const {
+  std::shared_ptr<StdThread> result = std::shared_ptr<StdThread>(new StdThread(isDetached(), runnable));
+  runnable->thread(result);
+  return result;
+}
 
- public:
+Thread::id_t StdThreadFactory::getCurrentThreadId() const {
+  return std::this_thread::get_id();
+}
+}
+}
+} // apache::thrift::concurrency
 
-  Impl(bool detached) :
-    detached_(detached) {}
-
-  /**
-   * Creates a new std::thread to run the runnable object
-   *
-   * @param runnable A runnable object
-   */
-  boost::shared_ptr<Thread> newThread(boost::shared_ptr<Runnable> runnable) const {
-    boost::shared_ptr<StdThread> result = boost::shared_ptr<StdThread>(new StdThread(detached_, runnable));
-    runnable->thread(result);
-    return result;
-  }
-
-  bool isDetached() const { return detached_; }
-
-  void setDetached(bool value) { detached_ = value; }
-
-  Thread::id_t getCurrentThreadId() const {
-    return std::this_thread::get_id();
-  }
-
-};
-
-StdThreadFactory::StdThreadFactory(bool detached) :
-  impl_(new StdThreadFactory::Impl(detached)) {}
-
-boost::shared_ptr<Thread> StdThreadFactory::newThread(boost::shared_ptr<Runnable> runnable) const { return impl_->newThread(runnable); }
-
-bool StdThreadFactory::isDetached() const { return impl_->isDetached(); }
-
-void StdThreadFactory::setDetached(bool value) { impl_->setDetached(value); }
-
-Thread::id_t StdThreadFactory::getCurrentThreadId() const { return impl_->getCurrentThreadId(); }
-
-}}} // apache::thrift::concurrency
+#endif // USE_STD_THREAD
diff --git a/lib/cpp/src/thrift/concurrency/StdThreadFactory.h b/lib/cpp/src/thrift/concurrency/StdThreadFactory.h
index 307f970..e74046b 100644
--- a/lib/cpp/src/thrift/concurrency/StdThreadFactory.h
+++ b/lib/cpp/src/thrift/concurrency/StdThreadFactory.h
@@ -22,9 +22,11 @@
 
 #include <thrift/concurrency/Thread.h>
 
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 /**
  * A thread factory to create std::threads.
@@ -33,40 +35,27 @@
  */
 class StdThreadFactory : public ThreadFactory {
 
- public:
-
+public:
   /**
    * Std thread factory.  All threads created by a factory are reference-counted
-   * via boost::shared_ptr and boost::weak_ptr.  The factory guarantees that threads and
-   * the Runnable tasks they host will be properly cleaned up once the last strong reference
+   * via std::shared_ptr.  The factory guarantees that threads and the Runnable tasks
+   * they host will be properly cleaned up once the last strong reference
    * to both is given up.
    *
    * By default threads are not joinable.
    */
 
-  StdThreadFactory(bool detached=true);
+  StdThreadFactory(bool detached = true);
 
   // From ThreadFactory;
-  boost::shared_ptr<Thread> newThread(boost::shared_ptr<Runnable> runnable) const;
+  std::shared_ptr<Thread> newThread(std::shared_ptr<Runnable> runnable) const;
 
   // From ThreadFactory;
   Thread::id_t getCurrentThreadId() const;
-
-  /**
-   * Sets detached mode of threads
-   */
-  virtual void setDetached(bool detached);
-
-  /**
-   * Gets current detached mode
-   */
-  virtual bool isDetached() const;
-
-private:
-  class Impl;
-  boost::shared_ptr<Impl> impl_;
 };
 
-}}} // apache::thrift::concurrency
+}
+}
+} // apache::thrift::concurrency
 
 #endif // #ifndef _THRIFT_CONCURRENCY_STDTHREADFACTORY_H_
diff --git a/lib/cpp/src/thrift/concurrency/Thread.h b/lib/cpp/src/thrift/concurrency/Thread.h
old mode 100755
new mode 100644
index 7012933..b2ea4e2
--- a/lib/cpp/src/thrift/concurrency/Thread.h
+++ b/lib/cpp/src/thrift/concurrency/Thread.h
@@ -21,22 +21,21 @@
 #define _THRIFT_CONCURRENCY_THREAD_H_ 1
 
 #include <stdint.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
+#include <memory>
 
 #include <thrift/thrift-config.h>
 
-#if USE_BOOST_THREAD
-#  include <boost/thread.hpp>
-#elif USE_STD_THREAD
-#  include <thread>
+#if USE_STD_THREAD
+#include <thread>
 #else
-#  ifdef HAVE_PTHREAD_H
-#    include <pthread.h>
-#  endif
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
 #endif
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 class Thread;
 
@@ -47,24 +46,24 @@
  */
 class Runnable {
 
- public:
-  virtual ~Runnable() {};
+public:
+  virtual ~Runnable(){};
   virtual void run() = 0;
 
   /**
    * Gets the thread object that is hosting this runnable object  - can return
-   * an empty boost::shared pointer if no references remain on thet thread  object
+   * an empty boost::shared pointer if no references remain on that thread object
    */
-  virtual boost::shared_ptr<Thread> thread() { return thread_.lock(); }
+  virtual std::shared_ptr<Thread> thread() { return thread_.lock(); }
 
   /**
    * Sets the thread that is executing this object.  This is only meant for
    * use by concrete implementations of Thread.
    */
-  virtual void thread(boost::shared_ptr<Thread> value) { thread_ = value; }
+  virtual void thread(std::shared_ptr<Thread> value) { thread_ = value; }
 
- private:
-  boost::weak_ptr<Thread> thread_;
+private:
+  std::weak_ptr<Thread> thread_;
 };
 
 /**
@@ -78,14 +77,8 @@
  */
 class Thread {
 
- public:
-
-#if USE_BOOST_THREAD
-  typedef boost::thread::id id_t;
-
-  static inline bool is_current(id_t t) { return t == boost::this_thread::get_id(); }
-  static inline id_t get_current() { return boost::this_thread::get_id(); }
-#elif USE_STD_THREAD
+public:
+#if USE_STD_THREAD
   typedef std::thread::id id_t;
 
   static inline bool is_current(id_t t) { return t == std::this_thread::get_id(); }
@@ -97,7 +90,7 @@
   static inline id_t get_current() { return pthread_self(); }
 #endif
 
-  virtual ~Thread() {};
+  virtual ~Thread(){};
 
   /**
    * Starts the thread. Does platform specific thread creation and
@@ -107,8 +100,9 @@
   virtual void start() = 0;
 
   /**
-   * Join this thread. Current thread blocks until this target thread
-   * completes.
+   * Join this thread. If this thread is joinable, the calling thread blocks
+   * until this thread completes.  If the target thread is not joinable, then
+   * nothing happens.
    */
   virtual void join() = 0;
 
@@ -120,14 +114,13 @@
   /**
    * Gets the runnable object this thread is hosting
    */
-  virtual boost::shared_ptr<Runnable> runnable() const { return _runnable; }
+  virtual std::shared_ptr<Runnable> runnable() const { return _runnable; }
 
- protected:
-  virtual void runnable(boost::shared_ptr<Runnable> value) { _runnable = value; }
+protected:
+  virtual void runnable(std::shared_ptr<Runnable> value) { _runnable = value; }
 
- private:
-  boost::shared_ptr<Runnable> _runnable;
-
+private:
+  std::shared_ptr<Runnable> _runnable;
 };
 
 /**
@@ -135,18 +128,43 @@
  * object for execution
  */
 class ThreadFactory {
+protected:
+  ThreadFactory(bool detached) : detached_(detached) { }
 
- public:
-  virtual ~ThreadFactory() {}
-  virtual boost::shared_ptr<Thread> newThread(boost::shared_ptr<Runnable> runnable) const = 0;
+public:
+  virtual ~ThreadFactory() { }
 
-  /** Gets the current thread id or unknown_thread_id if the current thread is not a thrift thread */
+  /**
+   * Gets current detached mode
+   */
+  bool isDetached() const { return detached_; }
 
+  /**
+   * Sets the detached disposition of newly created threads.
+   */
+  void setDetached(bool detached) { detached_ = detached; }
+
+  /**
+   * Create a new thread.
+   */
+  virtual std::shared_ptr<Thread> newThread(std::shared_ptr<Runnable> runnable) const = 0;
+
+  /**
+   * Gets the current thread id or unknown_thread_id if the current thread is not a thrift thread
+   */
+  virtual Thread::id_t getCurrentThreadId() const = 0;
+
+  /**
+   * For code readability define the unknown/undefined thread id
+   */
   static const Thread::id_t unknown_thread_id;
 
-  virtual Thread::id_t getCurrentThreadId() const = 0;
+private:
+  bool detached_;
 };
 
-}}} // apache::thrift::concurrency
+}
+}
+} // apache::thrift::concurrency
 
 #endif // #ifndef _THRIFT_CONCURRENCY_THREAD_H_
diff --git a/lib/cpp/src/thrift/concurrency/ThreadManager.cpp b/lib/cpp/src/thrift/concurrency/ThreadManager.cpp
index f2c0fa5..58025f9 100644
--- a/lib/cpp/src/thrift/concurrency/ThreadManager.cpp
+++ b/lib/cpp/src/thrift/concurrency/ThreadManager.cpp
@@ -24,20 +24,18 @@
 #include <thrift/concurrency/Monitor.h>
 #include <thrift/concurrency/Util.h>
 
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
-#include <assert.h>
-#include <queue>
+#include <stdexcept>
+#include <deque>
 #include <set>
 
-#if defined(DEBUG)
-#include <iostream>
-#endif //defined(DEBUG)
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
-namespace apache { namespace thrift { namespace concurrency {
-
-using boost::shared_ptr;
-using boost::dynamic_pointer_cast;
+using std::shared_ptr;
+using std::dynamic_pointer_cast;
 
 /**
  * ThreadManager class
@@ -47,40 +45,42 @@
  * it maintains statistics on number of idle threads, number of active threads,
  * task backlog, and average wait and service times.
  *
+ * There are three different monitors used for signaling different conditions
+ * however they all share the same mutex_.
+ *
  * @version $Id:$
  */
-class ThreadManager::Impl : public ThreadManager  {
+class ThreadManager::Impl : public ThreadManager {
 
- public:
-  Impl() :
-    workerCount_(0),
-    workerMaxCount_(0),
-    idleCount_(0),
-    pendingTaskCountMax_(0),
-    expiredCount_(0),
-    state_(ThreadManager::UNINITIALIZED),
-    monitor_(&mutex_),
-    maxMonitor_(&mutex_) {}
+public:
+  Impl()
+    : workerCount_(0),
+      workerMaxCount_(0),
+      idleCount_(0),
+      pendingTaskCountMax_(0),
+      expiredCount_(0),
+      state_(ThreadManager::UNINITIALIZED),
+      monitor_(&mutex_),
+      maxMonitor_(&mutex_),
+      workerMonitor_(&mutex_) {}
 
   ~Impl() { stop(); }
 
   void start();
+  void stop();
 
-  void stop() { stopImpl(false); }
-
-  void join() { stopImpl(true); }
-
-  ThreadManager::STATE state() const {
-    return state_;
-  }
+  ThreadManager::STATE state() const { return state_; }
 
   shared_ptr<ThreadFactory> threadFactory() const {
-    Synchronized s(monitor_);
+    Guard g(mutex_);
     return threadFactory_;
   }
 
   void threadFactory(shared_ptr<ThreadFactory> value) {
-    Synchronized s(monitor_);
+    Guard g(mutex_);
+    if (threadFactory_ && threadFactory_->isDetached() != value->isDetached()) {
+      throw InvalidArgumentException();
+    }
     threadFactory_ = value;
   }
 
@@ -88,56 +88,68 @@
 
   void removeWorker(size_t value);
 
-  size_t idleWorkerCount() const {
-    return idleCount_;
-  }
+  size_t idleWorkerCount() const { return idleCount_; }
 
   size_t workerCount() const {
-    Synchronized s(monitor_);
+    Guard g(mutex_);
     return workerCount_;
   }
 
   size_t pendingTaskCount() const {
-    Synchronized s(monitor_);
+    Guard g(mutex_);
     return tasks_.size();
   }
 
   size_t totalTaskCount() const {
-    Synchronized s(monitor_);
+    Guard g(mutex_);
     return tasks_.size() + workerCount_ - idleCount_;
   }
 
   size_t pendingTaskCountMax() const {
-    Synchronized s(monitor_);
+    Guard g(mutex_);
     return pendingTaskCountMax_;
   }
 
   size_t expiredTaskCount() {
-    Synchronized s(monitor_);
-    size_t result = expiredCount_;
-    expiredCount_ = 0;
-    return result;
+    Guard g(mutex_);
+    return expiredCount_;
   }
 
   void pendingTaskCountMax(const size_t value) {
-    Synchronized s(monitor_);
+    Guard g(mutex_);
     pendingTaskCountMax_ = value;
   }
 
-  bool canSleep();
-
   void add(shared_ptr<Runnable> value, int64_t timeout, int64_t expiration);
 
   void remove(shared_ptr<Runnable> task);
 
   shared_ptr<Runnable> removeNextPending();
 
-  void removeExpiredTasks();
+  void removeExpiredTasks() {
+    removeExpired(false);
+  }
 
   void setExpireCallback(ExpireCallback expireCallback);
 
 private:
-  void stopImpl(bool join);
+  /**
+   * Remove one or more expired tasks.
+   * \param[in]  justOne  if true, try to remove just one task and return
+   */
+  void removeExpired(bool justOne);
+
+  /**
+   * \returns whether it is acceptable to block, depending on the current thread id
+   */
+  bool canSleep() const;
+
+  /**
+   * Lowers the maximum worker count and blocks until enough worker threads complete
+   * to get to the new maximum worker limit.  The caller is responsible for acquiring
+   * a lock on the class mutex_.
+   */
+  void removeWorkersUnderLock(size_t value);
 
   size_t workerCount_;
   size_t workerMaxCount_;
@@ -149,13 +161,13 @@
   ThreadManager::STATE state_;
   shared_ptr<ThreadFactory> threadFactory_;
 
-
   friend class ThreadManager::Task;
-  std::queue<shared_ptr<Task> > tasks_;
+  typedef std::deque<shared_ptr<Task> > TaskQueue;
+  TaskQueue tasks_;
   Mutex mutex_;
   Monitor monitor_;
   Monitor maxMonitor_;
-  Monitor workerMonitor_;
+  Monitor workerMonitor_;       // used to synchronize changes in worker count
 
   friend class ThreadManager::Worker;
   std::set<shared_ptr<Thread> > workers_;
@@ -165,18 +177,13 @@
 
 class ThreadManager::Task : public Runnable {
 
- public:
-  enum STATE {
-    WAITING,
-    EXECUTING,
-    CANCELLED,
-    COMPLETE
-  };
+public:
+  enum STATE { WAITING, EXECUTING, TIMEDOUT, COMPLETE };
 
-  Task(shared_ptr<Runnable> runnable, int64_t expiration=0LL)  :
-    runnable_(runnable),
-    state_(WAITING),
-    expireTime_(expiration != 0LL ? Util::currentTime() + expiration : 0LL) {}
+  Task(shared_ptr<Runnable> runnable, int64_t expiration = 0LL)
+    : runnable_(runnable),
+      state_(WAITING),
+      expireTime_(expiration != 0LL ? Util::currentTime() + expiration : 0LL) {}
 
   ~Task() {}
 
@@ -187,46 +194,32 @@
     }
   }
 
-  shared_ptr<Runnable> getRunnable() {
-    return runnable_;
-  }
+  shared_ptr<Runnable> getRunnable() { return runnable_; }
 
-  int64_t getExpireTime() const {
-    return expireTime_;
-  }
+  int64_t getExpireTime() const { return expireTime_; }
 
- private:
+private:
   shared_ptr<Runnable> runnable_;
   friend class ThreadManager::Worker;
   STATE state_;
   int64_t expireTime_;
 };
 
-class ThreadManager::Worker: public Runnable {
-  enum STATE {
-    UNINITIALIZED,
-    STARTING,
-    STARTED,
-    STOPPING,
-    STOPPED
-  };
+class ThreadManager::Worker : public Runnable {
+  enum STATE { UNINITIALIZED, STARTING, STARTED, STOPPING, STOPPED };
 
- public:
-  Worker(ThreadManager::Impl* manager) :
-    manager_(manager),
-    state_(UNINITIALIZED),
-    idle_(false) {}
+public:
+  Worker(ThreadManager::Impl* manager) : manager_(manager), state_(UNINITIALIZED) {}
 
   ~Worker() {}
 
- private:
+private:
   bool isActive() const {
-    return
-      (manager_->workerCount_ <= manager_->workerMaxCount_) ||
-      (manager_->state_ == JOINING && !manager_->tasks_.empty());
+    return (manager_->workerCount_ <= manager_->workerMaxCount_)
+           || (manager_->state_ == JOINING && !manager_->tasks_.empty());
   }
 
- public:
+public:
   /**
    * Worker entry point
    *
@@ -234,328 +227,338 @@
    * execute.
    */
   void run() {
-    bool active = false;
-    bool notifyManager = false;
+    Guard g(manager_->mutex_);
+
+    /**
+     * This method has three parts; one is to check for and account for
+     * admitting a task which happens under a lock.  Then the lock is released
+     * and the task itself is executed.  Finally we do some accounting
+     * under lock again when the task completes.
+     */
+
+    /**
+     * Admitting
+     */
 
     /**
      * Increment worker semaphore and notify manager if worker count reached
      * desired max
-     *
-     * Note: We have to release the monitor and acquire the workerMonitor
-     * since that is what the manager blocks on for worker add/remove
      */
-    {
-      Synchronized s(manager_->monitor_);
-      active = manager_->workerCount_ < manager_->workerMaxCount_;
-      if (active) {
-        manager_->workerCount_++;
-        notifyManager = manager_->workerCount_ == manager_->workerMaxCount_;
-      }
-    }
-
-    if (notifyManager) {
-      Synchronized s(manager_->workerMonitor_);
-      manager_->workerMonitor_.notify();
-      notifyManager = false;
-    }
-
-    while (active) {
-      shared_ptr<ThreadManager::Task> task;
-
-      /**
-       * While holding manager monitor block for non-empty task queue (Also
-       * check that the thread hasn't been requested to stop). Once the queue
-       * is non-empty, dequeue a task, release monitor, and execute. If the
-       * worker max count has been decremented such that we exceed it, mark
-       * ourself inactive, decrement the worker count and notify the manager
-       * (technically we're notifying the next blocked thread but eventually
-       * the manager will see it.
-       */
-      {
-        Guard g(manager_->mutex_);
-        active = isActive();
-
-        while (active && manager_->tasks_.empty()) {
-          manager_->idleCount_++;
-          idle_ = true;
-          manager_->monitor_.wait();
-          active = isActive();
-          idle_ = false;
-          manager_->idleCount_--;
-        }
-
-        if (active) {
-          manager_->removeExpiredTasks();
-
-          if (!manager_->tasks_.empty()) {
-            task = manager_->tasks_.front();
-            manager_->tasks_.pop();
-            if (task->state_ == ThreadManager::Task::WAITING) {
-              task->state_ = ThreadManager::Task::EXECUTING;
-            }
-
-            /* If we have a pending task max and we just dropped below it, wakeup any
-               thread that might be blocked on add. */
-            if (manager_->pendingTaskCountMax_ != 0 &&
-                manager_->tasks_.size() <= manager_->pendingTaskCountMax_ - 1) {
-              manager_->maxMonitor_.notify();
-            }
-          }
-        } else {
-          idle_ = true;
-          manager_->workerCount_--;
-          notifyManager = (manager_->workerCount_ == manager_->workerMaxCount_);
-        }
-      }
-
-      if (task) {
-        if (task->state_ == ThreadManager::Task::EXECUTING) {
-          try {
-            task->run();
-          } catch(...) {
-            // XXX need to log this
-          }
-        }
-      }
-    }
-
-    {
-      Synchronized s(manager_->workerMonitor_);
-      manager_->deadWorkers_.insert(this->thread());
-      if (notifyManager) {
+    bool active = manager_->workerCount_ < manager_->workerMaxCount_;
+    if (active) {
+      if (++manager_->workerCount_ == manager_->workerMaxCount_) {
         manager_->workerMonitor_.notify();
       }
     }
 
-    return;
+    while (active) {
+      /**
+        * While holding manager monitor block for non-empty task queue (Also
+        * check that the thread hasn't been requested to stop). Once the queue
+        * is non-empty, dequeue a task, release monitor, and execute. If the
+        * worker max count has been decremented such that we exceed it, mark
+        * ourself inactive, decrement the worker count and notify the manager
+        * (technically we're notifying the next blocked thread but eventually
+        * the manager will see it.
+        */
+      active = isActive();
+
+      while (active && manager_->tasks_.empty()) {
+        manager_->idleCount_++;
+        manager_->monitor_.wait();
+        active = isActive();
+        manager_->idleCount_--;
+      }
+
+      shared_ptr<ThreadManager::Task> task;
+
+      if (active) {
+        if (!manager_->tasks_.empty()) {
+          task = manager_->tasks_.front();
+          manager_->tasks_.pop_front();
+          if (task->state_ == ThreadManager::Task::WAITING) {
+            // If the state is changed to anything other than EXECUTING or TIMEDOUT here
+            // then the execution loop needs to be changed below.
+            task->state_ =
+                (task->getExpireTime() && task->getExpireTime() < Util::currentTime()) ?
+                    ThreadManager::Task::TIMEDOUT :
+                    ThreadManager::Task::EXECUTING;
+          }
+        }
+
+        /* If we have a pending task max and we just dropped below it, wakeup any
+            thread that might be blocked on add. */
+        if (manager_->pendingTaskCountMax_ != 0
+            && manager_->tasks_.size() <= manager_->pendingTaskCountMax_ - 1) {
+          manager_->maxMonitor_.notify();
+        }
+      }
+
+      /**
+       * Execution - not holding a lock
+       */
+      if (task) {
+        if (task->state_ == ThreadManager::Task::EXECUTING) {
+
+          // Release the lock so we can run the task without blocking the thread manager
+          manager_->mutex_.unlock();
+
+          try {
+            task->run();
+          } catch (const std::exception& e) {
+            GlobalOutput.printf("[ERROR] task->run() raised an exception: %s", e.what());
+          } catch (...) {
+            GlobalOutput.printf("[ERROR] task->run() raised an unknown exception");
+          }
+
+          // Re-acquire the lock to proceed in the thread manager
+          manager_->mutex_.lock();
+
+        } else if (manager_->expireCallback_) {
+          // The only other state the task could have been in is TIMEDOUT (see above)
+          manager_->expireCallback_(task->getRunnable());
+          manager_->expiredCount_++;
+        }
+      }
+    }
+
+    /**
+     * Final accounting for the worker thread that is done working
+     */
+    manager_->deadWorkers_.insert(this->thread());
+    if (--manager_->workerCount_ == manager_->workerMaxCount_) {
+      manager_->workerMonitor_.notify();
+    }
   }
 
-  private:
-    ThreadManager::Impl* manager_;
-    friend class ThreadManager::Impl;
-    STATE state_;
-    bool idle_;
+private:
+  ThreadManager::Impl* manager_;
+  friend class ThreadManager::Impl;
+  STATE state_;
 };
 
-
-  void ThreadManager::Impl::addWorker(size_t value) {
+void ThreadManager::Impl::addWorker(size_t value) {
   std::set<shared_ptr<Thread> > newThreads;
   for (size_t ix = 0; ix < value; ix++) {
-    shared_ptr<ThreadManager::Worker> worker = shared_ptr<ThreadManager::Worker>(new ThreadManager::Worker(this));
+    shared_ptr<ThreadManager::Worker> worker
+        = shared_ptr<ThreadManager::Worker>(new ThreadManager::Worker(this));
     newThreads.insert(threadFactory_->newThread(worker));
   }
 
-  {
-    Synchronized s(monitor_);
-    workerMaxCount_ += value;
-    workers_.insert(newThreads.begin(), newThreads.end());
-  }
+  Guard g(mutex_);
+  workerMaxCount_ += value;
+  workers_.insert(newThreads.begin(), newThreads.end());
 
-  for (std::set<shared_ptr<Thread> >::iterator ix = newThreads.begin(); ix != newThreads.end(); ix++) {
-    shared_ptr<ThreadManager::Worker> worker = dynamic_pointer_cast<ThreadManager::Worker, Runnable>((*ix)->runnable());
+  for (std::set<shared_ptr<Thread> >::iterator ix = newThreads.begin(); ix != newThreads.end();
+       ++ix) {
+    shared_ptr<ThreadManager::Worker> worker
+        = dynamic_pointer_cast<ThreadManager::Worker, Runnable>((*ix)->runnable());
     worker->state_ = ThreadManager::Worker::STARTING;
     (*ix)->start();
     idMap_.insert(std::pair<const Thread::id_t, shared_ptr<Thread> >((*ix)->getId(), *ix));
   }
 
-  {
-    Synchronized s(workerMonitor_);
-    while (workerCount_ != workerMaxCount_) {
-      workerMonitor_.wait();
-    }
+  while (workerCount_ != workerMaxCount_) {
+    workerMonitor_.wait();
   }
 }
 
 void ThreadManager::Impl::start() {
-
+  Guard g(mutex_);
   if (state_ == ThreadManager::STOPPED) {
     return;
   }
 
-  {
-    Synchronized s(monitor_);
-    if (state_ == ThreadManager::UNINITIALIZED) {
-      if (!threadFactory_) {
-        throw InvalidArgumentException();
-      }
-      state_ = ThreadManager::STARTED;
-      monitor_.notifyAll();
+  if (state_ == ThreadManager::UNINITIALIZED) {
+    if (!threadFactory_) {
+      throw InvalidArgumentException();
     }
+    state_ = ThreadManager::STARTED;
+    monitor_.notifyAll();
+  }
 
-    while (state_ == STARTING) {
-      monitor_.wait();
-    }
+  while (state_ == STARTING) {
+    monitor_.wait();
   }
 }
 
-void ThreadManager::Impl::stopImpl(bool join) {
+void ThreadManager::Impl::stop() {
+  Guard g(mutex_);
   bool doStop = false;
-  if (state_ == ThreadManager::STOPPED) {
-    return;
-  }
 
-  {
-    Synchronized s(monitor_);
-    if (state_ != ThreadManager::STOPPING &&
-        state_ != ThreadManager::JOINING &&
-        state_ != ThreadManager::STOPPED) {
-      doStop = true;
-      state_ = join ? ThreadManager::JOINING : ThreadManager::STOPPING;
-    }
+  if (state_ != ThreadManager::STOPPING && state_ != ThreadManager::JOINING
+      && state_ != ThreadManager::STOPPED) {
+    doStop = true;
+    state_ = ThreadManager::JOINING;
   }
 
   if (doStop) {
-    removeWorker(workerCount_);
+    removeWorkersUnderLock(workerCount_);
   }
 
-  // XXX
-  // should be able to block here for transition to STOPPED since we're no
-  // using shared_ptrs
-
-  {
-    Synchronized s(monitor_);
-    state_ = ThreadManager::STOPPED;
-  }
-
+  state_ = ThreadManager::STOPPED;
 }
 
 void ThreadManager::Impl::removeWorker(size_t value) {
-  std::set<shared_ptr<Thread> > removedThreads;
-  {
-    Synchronized s(monitor_);
-    if (value > workerMaxCount_) {
-      throw InvalidArgumentException();
-    }
-
-    workerMaxCount_ -= value;
-
-    if (idleCount_ < value) {
-      for (size_t ix = 0; ix < idleCount_; ix++) {
-        monitor_.notify();
-      }
-    } else {
-      monitor_.notifyAll();
-    }
-  }
-
-  {
-    Synchronized s(workerMonitor_);
-
-    while (workerCount_ != workerMaxCount_) {
-      workerMonitor_.wait();
-    }
-
-    for (std::set<shared_ptr<Thread> >::iterator ix = deadWorkers_.begin(); ix != deadWorkers_.end(); ix++) {
-      idMap_.erase((*ix)->getId());
-      workers_.erase(*ix);
-    }
-
-    deadWorkers_.clear();
-  }
+  Guard g(mutex_);
+  removeWorkersUnderLock(value);
 }
 
-  bool ThreadManager::Impl::canSleep() {
-    const Thread::id_t id = threadFactory_->getCurrentThreadId();
-    return idMap_.find(id) == idMap_.end();
+void ThreadManager::Impl::removeWorkersUnderLock(size_t value) {
+  if (value > workerMaxCount_) {
+    throw InvalidArgumentException();
   }
 
-  void ThreadManager::Impl::add(shared_ptr<Runnable> value,
-                                int64_t timeout,
-                                int64_t expiration) {
-    Guard g(mutex_, timeout);
+  workerMaxCount_ -= value;
 
-    if (!g) {
-      throw TimedOutException();
-    }
-
-    if (state_ != ThreadManager::STARTED) {
-      throw IllegalStateException("ThreadManager::Impl::add ThreadManager "
-                                  "not started");
-    }
-
-    removeExpiredTasks();
-    if (pendingTaskCountMax_ > 0 && (tasks_.size() >= pendingTaskCountMax_)) {
-      if (canSleep() && timeout >= 0) {
-        while (pendingTaskCountMax_ > 0 && tasks_.size() >= pendingTaskCountMax_) {
-          // This is thread safe because the mutex is shared between monitors.
-          maxMonitor_.wait(timeout);
-        }
-      } else {
-        throw TooManyPendingTasksException();
-      }
-    }
-
-    tasks_.push(shared_ptr<ThreadManager::Task>(new ThreadManager::Task(value, expiration)));
-
-    // If idle thread is available notify it, otherwise all worker threads are
-    // running and will get around to this task in time.
-    if (idleCount_ > 0) {
+  if (idleCount_ > value) {
+    // There are more idle workers than we need to remove,
+    // so notify enough of them so they can terminate.
+    for (size_t ix = 0; ix < value; ix++) {
       monitor_.notify();
     }
+  } else {
+    // There are as many or less idle workers than we need to remove,
+    // so just notify them all so they can terminate.
+    monitor_.notifyAll();
   }
 
-void ThreadManager::Impl::remove(shared_ptr<Runnable> task) {
-  (void) task;
-  Synchronized s(monitor_);
+  while (workerCount_ != workerMaxCount_) {
+    workerMonitor_.wait();
+  }
+
+  for (std::set<shared_ptr<Thread> >::iterator ix = deadWorkers_.begin();
+       ix != deadWorkers_.end();
+       ++ix) {
+
+    // when used with a joinable thread factory, we join the threads as we remove them
+    if (!threadFactory_->isDetached()) {
+      (*ix)->join();
+    }
+
+    idMap_.erase((*ix)->getId());
+    workers_.erase(*ix);
+  }
+
+  deadWorkers_.clear();
+}
+
+bool ThreadManager::Impl::canSleep() const {
+  const Thread::id_t id = threadFactory_->getCurrentThreadId();
+  return idMap_.find(id) == idMap_.end();
+}
+
+void ThreadManager::Impl::add(shared_ptr<Runnable> value, int64_t timeout, int64_t expiration) {
+  Guard g(mutex_, timeout);
+
+  if (!g) {
+    throw TimedOutException();
+  }
+
   if (state_ != ThreadManager::STARTED) {
-    throw IllegalStateException("ThreadManager::Impl::remove ThreadManager not "
-                                "started");
+    throw IllegalStateException(
+        "ThreadManager::Impl::add ThreadManager "
+        "not started");
+  }
+
+  // if we're at a limit, remove an expired task to see if the limit clears
+  if (pendingTaskCountMax_ > 0 && (tasks_.size() >= pendingTaskCountMax_)) {
+    removeExpired(true);
+  }
+
+  if (pendingTaskCountMax_ > 0 && (tasks_.size() >= pendingTaskCountMax_)) {
+    if (canSleep() && timeout >= 0) {
+      while (pendingTaskCountMax_ > 0 && tasks_.size() >= pendingTaskCountMax_) {
+        // This is thread safe because the mutex is shared between monitors.
+        maxMonitor_.wait(timeout);
+      }
+    } else {
+      throw TooManyPendingTasksException();
+    }
+  }
+
+  tasks_.push_back(shared_ptr<ThreadManager::Task>(new ThreadManager::Task(value, expiration)));
+
+  // If idle thread is available notify it, otherwise all worker threads are
+  // running and will get around to this task in time.
+  if (idleCount_ > 0) {
+    monitor_.notify();
   }
 }
 
-boost::shared_ptr<Runnable> ThreadManager::Impl::removeNextPending() {
+void ThreadManager::Impl::remove(shared_ptr<Runnable> task) {
   Guard g(mutex_);
   if (state_ != ThreadManager::STARTED) {
-    throw IllegalStateException("ThreadManager::Impl::removeNextPending "
-                                "ThreadManager not started");
+    throw IllegalStateException(
+        "ThreadManager::Impl::remove ThreadManager not "
+        "started");
+  }
+
+  for (TaskQueue::iterator it = tasks_.begin(); it != tasks_.end(); ++it)
+  {
+    if ((*it)->getRunnable() == task)
+    {
+      tasks_.erase(it);
+      return;
+    }
+  }
+}
+
+std::shared_ptr<Runnable> ThreadManager::Impl::removeNextPending() {
+  Guard g(mutex_);
+  if (state_ != ThreadManager::STARTED) {
+    throw IllegalStateException(
+        "ThreadManager::Impl::removeNextPending "
+        "ThreadManager not started");
   }
 
   if (tasks_.empty()) {
-    return boost::shared_ptr<Runnable>();
+    return std::shared_ptr<Runnable>();
   }
 
   shared_ptr<ThreadManager::Task> task = tasks_.front();
-  tasks_.pop();
-  
+  tasks_.pop_front();
+
   return task->getRunnable();
 }
 
-void ThreadManager::Impl::removeExpiredTasks() {
-  int64_t now = 0LL; // we won't ask for the time untile we need it
+void ThreadManager::Impl::removeExpired(bool justOne) {
+  // this is always called under a lock
+  int64_t now = 0LL;
 
-  // note that this loop breaks at the first non-expiring task
-  while (!tasks_.empty()) {
-    shared_ptr<ThreadManager::Task> task = tasks_.front();
-    if (task->getExpireTime() == 0LL) {
-      break;
-    }
+  for (TaskQueue::iterator it = tasks_.begin(); it != tasks_.end(); )
+  {
     if (now == 0LL) {
       now = Util::currentTime();
     }
-    if (task->getExpireTime() > now) {
-      break;
+
+    if ((*it)->getExpireTime() > 0LL && (*it)->getExpireTime() < now) {
+      if (expireCallback_) {
+        expireCallback_((*it)->getRunnable());
+      }
+      it = tasks_.erase(it);
+      ++expiredCount_;
+      if (justOne) {
+        return;
+      }
     }
-    if (expireCallback_) {
-      expireCallback_(task->getRunnable());
+    else
+    {
+      ++it;
     }
-    tasks_.pop();
-    expiredCount_++;
   }
 }
 
-
 void ThreadManager::Impl::setExpireCallback(ExpireCallback expireCallback) {
+  Guard g(mutex_);
   expireCallback_ = expireCallback;
 }
 
 class SimpleThreadManager : public ThreadManager::Impl {
 
- public:
-  SimpleThreadManager(size_t workerCount=4, size_t pendingTaskCountMax=0) :
-    workerCount_(workerCount),
-    pendingTaskCountMax_(pendingTaskCountMax),
-    firstTime_(true) {
-  }
+public:
+  SimpleThreadManager(size_t workerCount = 4, size_t pendingTaskCountMax = 0)
+    : workerCount_(workerCount), pendingTaskCountMax_(pendingTaskCountMax) {}
 
   void start() {
     ThreadManager::Impl::pendingTaskCountMax(pendingTaskCountMax_);
@@ -563,21 +566,19 @@
     addWorker(workerCount_);
   }
 
- private:
+private:
   const size_t workerCount_;
   const size_t pendingTaskCountMax_;
-  bool firstTime_;
-  Monitor monitor_;
 };
 
-
 shared_ptr<ThreadManager> ThreadManager::newThreadManager() {
   return shared_ptr<ThreadManager>(new ThreadManager::Impl());
 }
 
-shared_ptr<ThreadManager> ThreadManager::newSimpleThreadManager(size_t count, size_t pendingTaskCountMax) {
+shared_ptr<ThreadManager> ThreadManager::newSimpleThreadManager(size_t count,
+                                                                size_t pendingTaskCountMax) {
   return shared_ptr<ThreadManager>(new SimpleThreadManager(count, pendingTaskCountMax));
 }
-
-}}} // apache::thrift::concurrency
-
+}
+}
+} // apache::thrift::concurrency
diff --git a/lib/cpp/src/thrift/concurrency/ThreadManager.h b/lib/cpp/src/thrift/concurrency/ThreadManager.h
index de45d56..470fc0a 100644
--- a/lib/cpp/src/thrift/concurrency/ThreadManager.h
+++ b/lib/cpp/src/thrift/concurrency/ThreadManager.h
@@ -20,12 +20,14 @@
 #ifndef _THRIFT_CONCURRENCY_THREADMANAGER_H_
 #define _THRIFT_CONCURRENCY_THREADMANAGER_H_ 1
 
-#include <boost/shared_ptr.hpp>
-#include <thrift/cxxfunctional.h>
+#include <functional>
+#include <memory>
 #include <sys/types.h>
 #include <thrift/concurrency/Thread.h>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 /**
  * Thread Pool Manager and related classes
@@ -39,26 +41,25 @@
  *
  * This class manages a pool of threads. It uses a ThreadFactory to create
  * threads. It never actually creates or destroys worker threads, rather
- * It maintains statistics on number of idle threads, number of active threads,
+ * it maintains statistics on number of idle threads, number of active threads,
  * task backlog, and average wait and service times and informs the PoolPolicy
  * object bound to instances of this manager of interesting transitions. It is
  * then up the PoolPolicy object to decide if the thread pool size needs to be
  * adjusted and call this object addWorker and removeWorker methods to make
  * changes.
  *
- * This design allows different policy implementations to used this code to
+ * This design allows different policy implementations to use this code to
  * handle basic worker thread management and worker task execution and focus on
  * policy issues. The simplest policy, StaticPolicy, does nothing other than
  * create a fixed number of threads.
  */
 class ThreadManager {
 
- protected:
+protected:
   ThreadManager() {}
 
- public:
-  class Task;
-  typedef apache::thrift::stdcxx::function<void(boost::shared_ptr<Runnable>)> ExpireCallback;
+public:
+  typedef std::function<void(std::shared_ptr<Runnable>)> ExpireCallback;
 
   virtual ~ThreadManager() {}
 
@@ -70,38 +71,46 @@
 
   /**
    * Stops the thread manager. Aborts all remaining unprocessed task, shuts
-   * down all created worker threads, and realeases all allocated resources.
+   * down all created worker threads, and releases all allocated resources.
    * This method blocks for all worker threads to complete, thus it can
    * potentially block forever if a worker thread is running a task that
    * won't terminate.
+   *
+   * Worker threads will be joined depending on the threadFactory's detached
+   * disposition.
    */
   virtual void stop() = 0;
 
-  /**
-   * Joins the thread manager. This is the same as stop, except that it will
-   * block until all the workers have finished their work. At that point
-   * the ThreadManager will transition into the STOPPED state.
-   */
-  virtual void join() = 0;
-
-  enum STATE {
-    UNINITIALIZED,
-    STARTING,
-    STARTED,
-    JOINING,
-    STOPPING,
-    STOPPED
-  };
+  enum STATE { UNINITIALIZED, STARTING, STARTED, JOINING, STOPPING, STOPPED };
 
   virtual STATE state() const = 0;
 
-  virtual boost::shared_ptr<ThreadFactory> threadFactory() const = 0;
+  /**
+   * \returns the current thread factory
+   */
+  virtual std::shared_ptr<ThreadFactory> threadFactory() const = 0;
 
-  virtual void threadFactory(boost::shared_ptr<ThreadFactory> value) = 0;
+  /**
+   * Set the thread factory.
+   * \throws InvalidArgumentException if the new thread factory has a different
+   *                                  detached disposition than the one replacing it
+   */
+  virtual void threadFactory(std::shared_ptr<ThreadFactory> value) = 0;
 
-  virtual void addWorker(size_t value=1) = 0;
+  /**
+   * Adds worker thread(s).
+   */
+  virtual void addWorker(size_t value = 1) = 0;
 
-  virtual void removeWorker(size_t value=1) = 0;
+  /**
+   * Removes worker thread(s).
+   * Threads are joined if the thread factory detached disposition allows it.
+   * Blocks until the number of worker threads reaches the new limit.
+   * \param[in]  value  the number to remove
+   * \throws InvalidArgumentException if the value is greater than the number
+   *                                  of workers
+   */
+  virtual void removeWorker(size_t value = 1) = 0;
 
   /**
    * Gets the current number of idle worker threads
@@ -116,7 +125,7 @@
   /**
    * Gets the current number of pending tasks
    */
-  virtual size_t pendingTaskCount() const  = 0;
+  virtual size_t pendingTaskCount() const = 0;
 
   /**
    * Gets the current number of pending and executing tasks
@@ -129,7 +138,8 @@
   virtual size_t pendingTaskCountMax() const = 0;
 
   /**
-   * Gets the number of tasks which have been expired without being run.
+   * Gets the number of tasks which have been expired without being run
+   * since start() was called.
    */
   virtual size_t expiredTaskCount() = 0;
 
@@ -152,21 +162,21 @@
    *
    * @throws TooManyPendingTasksException Pending task count exceeds max pending task count
    */
-  virtual void add(boost::shared_ptr<Runnable>task,
-                   int64_t timeout=0LL,
-                   int64_t expiration=0LL) = 0;
+  virtual void add(std::shared_ptr<Runnable> task,
+                   int64_t timeout = 0LL,
+                   int64_t expiration = 0LL) = 0;
 
   /**
    * Removes a pending task
    */
-  virtual void remove(boost::shared_ptr<Runnable> task) = 0;
+  virtual void remove(std::shared_ptr<Runnable> task) = 0;
 
   /**
    * Remove the next pending task which would be run.
    *
    * @return the task removed.
    */
-  virtual boost::shared_ptr<Runnable> removeNextPending() = 0;
+  virtual std::shared_ptr<Runnable> removeNextPending() = 0;
 
   /**
    * Remove tasks from front of task queue that have expired.
@@ -181,14 +191,15 @@
    */
   virtual void setExpireCallback(ExpireCallback expireCallback) = 0;
 
-  static boost::shared_ptr<ThreadManager> newThreadManager();
+  static std::shared_ptr<ThreadManager> newThreadManager();
 
   /**
    * Creates a simple thread manager the uses count number of worker threads and has
    * a pendingTaskCountMax maximum pending tasks. The default, 0, specified no limit
    * on pending tasks
    */
-  static boost::shared_ptr<ThreadManager> newSimpleThreadManager(size_t count=4, size_t pendingTaskCountMax=0);
+  static std::shared_ptr<ThreadManager> newSimpleThreadManager(size_t count = 4,
+                                                                 size_t pendingTaskCountMax = 0);
 
   class Task;
 
@@ -196,7 +207,8 @@
 
   class Impl;
 };
-
-}}} // apache::thrift::concurrency
+}
+}
+} // apache::thrift::concurrency
 
 #endif // #ifndef _THRIFT_CONCURRENCY_THREADMANAGER_H_
diff --git a/lib/cpp/src/thrift/concurrency/TimerManager.cpp b/lib/cpp/src/thrift/concurrency/TimerManager.cpp
index 6821b2e..61a34ff 100644
--- a/lib/cpp/src/thrift/concurrency/TimerManager.cpp
+++ b/lib/cpp/src/thrift/concurrency/TimerManager.cpp
@@ -25,9 +25,12 @@
 #include <iostream>
 #include <set>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
-using boost::shared_ptr;
+using std::shared_ptr;
+using std::weak_ptr;
 
 /**
  * TimerManager class
@@ -36,20 +39,12 @@
  */
 class TimerManager::Task : public Runnable {
 
- public:
-  enum STATE {
-    WAITING,
-    EXECUTING,
-    CANCELLED,
-    COMPLETE
-  };
+public:
+  enum STATE { WAITING, EXECUTING, CANCELLED, COMPLETE };
 
-  Task(shared_ptr<Runnable> runnable) :
-    runnable_(runnable),
-    state_(WAITING) {}
+  Task(shared_ptr<Runnable> runnable) : runnable_(runnable), state_(WAITING) {}
 
-  ~Task() {
-  }
+  ~Task() {}
 
   void run() {
     if (state_ == EXECUTING) {
@@ -58,17 +53,20 @@
     }
   }
 
- private:
+  bool operator==(const shared_ptr<Runnable> & runnable) const { return runnable_ == runnable; }
+
+  task_iterator it_;
+
+private:
   shared_ptr<Runnable> runnable_;
   friend class TimerManager::Dispatcher;
   STATE state_;
 };
 
-class TimerManager::Dispatcher: public Runnable {
+class TimerManager::Dispatcher : public Runnable {
 
- public:
-  Dispatcher(TimerManager* manager) :
-    manager_(manager) {}
+public:
+  Dispatcher(TimerManager* manager) : manager_(manager) {}
 
   ~Dispatcher() {}
 
@@ -93,16 +91,19 @@
         Synchronized s(manager_->monitor_);
         task_iterator expiredTaskEnd;
         int64_t now = Util::currentTime();
-        while (manager_->state_ == TimerManager::STARTED &&
-               (expiredTaskEnd = manager_->taskMap_.upper_bound(now)) == manager_->taskMap_.begin()) {
+        while (manager_->state_ == TimerManager::STARTED
+               && (expiredTaskEnd = manager_->taskMap_.upper_bound(now))
+                  == manager_->taskMap_.begin()) {
           int64_t timeout = 0LL;
           if (!manager_->taskMap_.empty()) {
             timeout = manager_->taskMap_.begin()->first - now;
           }
-          assert((timeout != 0 && manager_->taskCount_ > 0) || (timeout == 0 && manager_->taskCount_ == 0));
+          assert((timeout != 0 && manager_->taskCount_ > 0)
+                 || (timeout == 0 && manager_->taskCount_ == 0));
           try {
             manager_->monitor_.wait(timeout);
-          } catch (TimedOutException &) {}
+          } catch (TimedOutException&) {
+          }
           now = Util::currentTime();
         }
 
@@ -110,6 +111,7 @@
           for (task_iterator ix = manager_->taskMap_.begin(); ix != expiredTaskEnd; ix++) {
             shared_ptr<TimerManager::Task> task = ix->second;
             expiredTasks.insert(task);
+            task->it_ = manager_->taskMap_.end();
             if (task->state_ == TimerManager::Task::WAITING) {
               task->state_ = TimerManager::Task::EXECUTING;
             }
@@ -119,7 +121,9 @@
         }
       }
 
-      for (std::set<shared_ptr<Task> >::iterator ix =  expiredTasks.begin(); ix != expiredTasks.end(); ix++) {
+      for (std::set<shared_ptr<Task> >::iterator ix = expiredTasks.begin();
+           ix != expiredTasks.end();
+           ++ix) {
         (*ix)->run();
       }
 
@@ -135,20 +139,20 @@
     return;
   }
 
- private:
+private:
   TimerManager* manager_;
   friend class TimerManager;
 };
 
 #if defined(_MSC_VER)
 #pragma warning(push)
-#pragma warning(disable: 4355) // 'this' used in base member initializer list
+#pragma warning(disable : 4355) // 'this' used in base member initializer list
 #endif
 
-TimerManager::TimerManager() :
-  taskCount_(0),
-  state_(TimerManager::UNINITIALIZED),
-  dispatcher_(shared_ptr<Dispatcher>(new Dispatcher(this))) {
+TimerManager::TimerManager()
+  : taskCount_(0),
+    state_(TimerManager::UNINITIALIZED),
+    dispatcher_(shared_ptr<Dispatcher>(new Dispatcher(this))) {
 }
 
 #if defined(_MSC_VER)
@@ -163,9 +167,8 @@
   if (state_ != STOPPED) {
     try {
       stop();
-    } catch(...) {
-      throw;
-      // uhoh
+    } catch (...) {
+      // We're really hosed.
     }
   }
 }
@@ -203,7 +206,7 @@
     Synchronized s(monitor_);
     if (state_ == TimerManager::UNINITIALIZED) {
       state_ = TimerManager::STOPPED;
-    } else if (state_ != STOPPING &&  state_ != STOPPED) {
+    } else if (state_ != STOPPING && state_ != STOPPED) {
       doStop = true;
       state_ = STOPPING;
       monitor_.notifyAll();
@@ -227,7 +230,7 @@
   return threadFactory_;
 }
 
-void TimerManager::threadFactory(shared_ptr<const ThreadFactory>  value) {
+void TimerManager::threadFactory(shared_ptr<const ThreadFactory> value) {
   Synchronized s(monitor_);
   threadFactory_ = value;
 }
@@ -236,7 +239,7 @@
   return taskCount_;
 }
 
-void TimerManager::add(shared_ptr<Runnable> task, int64_t timeout) {
+TimerManager::Timer TimerManager::add(shared_ptr<Runnable> task, int64_t timeout) {
   int64_t now = Util::currentTime();
   timeout += now;
 
@@ -251,8 +254,9 @@
     // because the new task might insert at the front.
     bool notifyRequired = (taskCount_ == 0) ? true : timeout < taskMap_.begin()->first;
 
+    shared_ptr<Task> timer(new Task(task));
     taskCount_++;
-    taskMap_.insert(std::pair<int64_t, shared_ptr<Task> >(timeout, shared_ptr<Task>(new Task(task))));
+    timer->it_ = taskMap_.insert(std::pair<int64_t, shared_ptr<Task> >(timeout, timer));
 
     // If the task map was empty, or if we have an expiration that is earlier
     // than any previously seen, kick the dispatcher so it can update its
@@ -260,10 +264,13 @@
     if (notifyRequired) {
       monitor_.notify();
     }
+
+    return timer;
   }
 }
 
-void TimerManager::add(shared_ptr<Runnable> task, const struct THRIFT_TIMESPEC& value) {
+TimerManager::Timer TimerManager::add(shared_ptr<Runnable> task,
+    const struct THRIFT_TIMESPEC& value) {
 
   int64_t expiration;
   Util::toMilliseconds(expiration, value);
@@ -271,13 +278,14 @@
   int64_t now = Util::currentTime();
 
   if (expiration < now) {
-    throw  InvalidArgumentException();
+    throw InvalidArgumentException();
   }
 
-  add(task, expiration - now);
+  return add(task, expiration - now);
 }
 
-void TimerManager::add(shared_ptr<Runnable> task, const struct timeval& value) {
+TimerManager::Timer TimerManager::add(shared_ptr<Runnable> task,
+    const struct timeval& value) {
 
   int64_t expiration;
   Util::toMilliseconds(expiration, value);
@@ -285,21 +293,55 @@
   int64_t now = Util::currentTime();
 
   if (expiration < now) {
-    throw  InvalidArgumentException();
+    throw InvalidArgumentException();
   }
 
-  add(task, expiration - now);
+  return add(task, expiration - now);
 }
 
 void TimerManager::remove(shared_ptr<Runnable> task) {
-  (void) task;
   Synchronized s(monitor_);
   if (state_ != TimerManager::STARTED) {
     throw IllegalStateException();
   }
+  bool found = false;
+  for (task_iterator ix = taskMap_.begin(); ix != taskMap_.end();) {
+    if (*ix->second == task) {
+      found = true;
+      taskCount_--;
+      taskMap_.erase(ix++);
+    } else {
+      ++ix;
+    }
+  }
+  if (!found) {
+    throw NoSuchTaskException();
+  }
 }
 
-TimerManager::STATE TimerManager::state() const { return state_; }
+void TimerManager::remove(Timer handle) {
+  Synchronized s(monitor_);
+  if (state_ != TimerManager::STARTED) {
+    throw IllegalStateException();
+  }
 
-}}} // apache::thrift::concurrency
+  shared_ptr<Task> task = handle.lock();
+  if (!task) {
+    throw NoSuchTaskException();
+  }
 
+  if (task->it_ == taskMap_.end()) {
+    // Task is being executed
+    throw UncancellableTaskException();
+  }
+
+  taskMap_.erase(task->it_);
+  taskCount_--;
+}
+
+TimerManager::STATE TimerManager::state() const {
+  return state_;
+}
+}
+}
+} // apache::thrift::concurrency
diff --git a/lib/cpp/src/thrift/concurrency/TimerManager.h b/lib/cpp/src/thrift/concurrency/TimerManager.h
index d8200cb..ba79226 100644
--- a/lib/cpp/src/thrift/concurrency/TimerManager.h
+++ b/lib/cpp/src/thrift/concurrency/TimerManager.h
@@ -24,11 +24,13 @@
 #include <thrift/concurrency/Monitor.h>
 #include <thrift/concurrency/Thread.h>
 
-#include <boost/shared_ptr.hpp>
+#include <memory>
 #include <map>
 #include <time.h>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 /**
  * Timer Manager
@@ -39,15 +41,17 @@
  */
 class TimerManager {
 
- public:
+public:
+  class Task;
+  typedef std::weak_ptr<Task> Timer;
 
   TimerManager();
 
   virtual ~TimerManager();
 
-  virtual boost::shared_ptr<const ThreadFactory> threadFactory() const;
+  virtual std::shared_ptr<const ThreadFactory> threadFactory() const;
 
-  virtual void threadFactory(boost::shared_ptr<const ThreadFactory> value);
+  virtual void threadFactory(std::shared_ptr<const ThreadFactory> value);
 
   /**
    * Starts the timer manager service
@@ -61,35 +65,40 @@
    */
   virtual void stop();
 
-  virtual size_t taskCount() const ;
+  virtual size_t taskCount() const;
 
   /**
    * Adds a task to be executed at some time in the future by a worker thread.
    *
    * @param task The task to execute
    * @param timeout Time in milliseconds to delay before executing task
+   * @return Handle of the timer, which can be used to remove the timer.
    */
-  virtual void add(boost::shared_ptr<Runnable> task, int64_t timeout);
+  virtual Timer add(std::shared_ptr<Runnable> task, int64_t timeout);
 
   /**
    * Adds a task to be executed at some time in the future by a worker thread.
    *
    * @param task The task to execute
    * @param timeout Absolute time in the future to execute task.
+   * @return Handle of the timer, which can be used to remove the timer.
    */
-  virtual void add(boost::shared_ptr<Runnable> task, const struct THRIFT_TIMESPEC& timeout);
+  virtual Timer add(std::shared_ptr<Runnable> task, const struct THRIFT_TIMESPEC& timeout);
 
   /**
    * Adds a task to be executed at some time in the future by a worker thread.
    *
    * @param task The task to execute
    * @param timeout Absolute time in the future to execute task.
+   * @return Handle of the timer, which can be used to remove the timer.
    */
-  virtual void add(boost::shared_ptr<Runnable> task, const struct timeval& timeout);
+  virtual Timer add(std::shared_ptr<Runnable> task, const struct timeval& timeout);
 
   /**
    * Removes a pending task
    *
+   * @param task The task to remove. All timers which execute this task will
+   * be removed.
    * @throws NoSuchTaskException Specified task doesn't exist. It was either
    *                             processed already or this call was made for a
    *                             task that was never added to this timer
@@ -97,34 +106,42 @@
    * @throws UncancellableTaskException Specified task is already being
    *                                    executed or has completed execution.
    */
-  virtual void remove(boost::shared_ptr<Runnable> task);
+  virtual void remove(std::shared_ptr<Runnable> task);
 
-  enum STATE {
-    UNINITIALIZED,
-    STARTING,
-    STARTED,
-    STOPPING,
-    STOPPED
-  };
+  /**
+   * Removes a single pending task
+   *
+   * @param timer The timer to remove. The timer is returned when calling the
+   * add() method.
+   * @throws NoSuchTaskException Specified task doesn't exist. It was either
+   *                             processed already or this call was made for a
+   *                             task that was never added to this timer
+   *
+   * @throws UncancellableTaskException Specified task is already being
+   *                                    executed or has completed execution.
+   */
+  virtual void remove(Timer timer);
+
+  enum STATE { UNINITIALIZED, STARTING, STARTED, STOPPING, STOPPED };
 
   virtual STATE state() const;
 
- private:
-  boost::shared_ptr<const ThreadFactory> threadFactory_;
-  class Task;
+private:
+  std::shared_ptr<const ThreadFactory> threadFactory_;
   friend class Task;
-  std::multimap<int64_t, boost::shared_ptr<Task> > taskMap_;
+  std::multimap<int64_t, std::shared_ptr<Task> > taskMap_;
   size_t taskCount_;
   Monitor monitor_;
   STATE state_;
   class Dispatcher;
   friend class Dispatcher;
-  boost::shared_ptr<Dispatcher> dispatcher_;
-  boost::shared_ptr<Thread> dispatcherThread_;
-  typedef std::multimap<int64_t, boost::shared_ptr<TimerManager::Task> >::iterator task_iterator;
+  std::shared_ptr<Dispatcher> dispatcher_;
+  std::shared_ptr<Thread> dispatcherThread_;
+  typedef std::multimap<int64_t, std::shared_ptr<TimerManager::Task> >::iterator task_iterator;
   typedef std::pair<task_iterator, task_iterator> task_range;
 };
-
-}}} // apache::thrift::concurrency
+}
+}
+} // apache::thrift::concurrency
 
 #endif // #ifndef _THRIFT_CONCURRENCY_TIMERMANAGER_H_
diff --git a/lib/cpp/src/thrift/concurrency/Util.cpp b/lib/cpp/src/thrift/concurrency/Util.cpp
index 7d9085e..dd6d19f 100644
--- a/lib/cpp/src/thrift/concurrency/Util.cpp
+++ b/lib/cpp/src/thrift/concurrency/Util.cpp
@@ -26,16 +26,19 @@
 #include <sys/time.h>
 #endif
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 int64_t Util::currentTimeTicks(int64_t ticksPerSec) {
   int64_t result;
   struct timeval now;
   int ret = THRIFT_GETTIMEOFDAY(&now, NULL);
   assert(ret == 0);
-  THRIFT_UNUSED_VARIABLE(ret); //squelching "unused variable" warning
+  THRIFT_UNUSED_VARIABLE(ret); // squelching "unused variable" warning
   toTicks(result, now, ticksPerSec);
   return result;
 }
-
-}}} // apache::thrift::concurrency
+}
+}
+} // apache::thrift::concurrency
diff --git a/lib/cpp/src/thrift/concurrency/Util.h b/lib/cpp/src/thrift/concurrency/Util.h
index 63d80a2..1a91599 100644
--- a/lib/cpp/src/thrift/concurrency/Util.h
+++ b/lib/cpp/src/thrift/concurrency/Util.h
@@ -31,7 +31,9 @@
 
 #include <thrift/transport/PlatformSocket.h>
 
-namespace apache { namespace thrift { namespace concurrency {
+namespace apache {
+namespace thrift {
+namespace concurrency {
 
 /**
  * Utility methods
@@ -55,8 +57,7 @@
   static const int64_t NS_PER_US = NS_PER_S / US_PER_S;
   static const int64_t US_PER_MS = US_PER_S / MS_PER_S;
 
- public:
-
+public:
   /**
    * Converts millisecond timestamp into a THRIFT_TIMESPEC struct
    *
@@ -64,17 +65,20 @@
    * @param time or duration in milliseconds
    */
   static void toTimespec(struct THRIFT_TIMESPEC& result, int64_t value) {
-    result.tv_sec = value / MS_PER_S; // ms to s
+    result.tv_sec = value / MS_PER_S;                // ms to s
     result.tv_nsec = (value % MS_PER_S) * NS_PER_MS; // ms to ns
   }
 
   static void toTimeval(struct timeval& result, int64_t value) {
-    result.tv_sec  = static_cast<uint32_t>(value / MS_PER_S); // ms to s
+    result.tv_sec = static_cast<uint32_t>(value / MS_PER_S);                // ms to s
     result.tv_usec = static_cast<uint32_t>((value % MS_PER_S) * US_PER_MS); // ms to us
   }
 
-  static void toTicks(int64_t& result, int64_t secs, int64_t oldTicks,
-                      int64_t oldTicksPerSec, int64_t newTicksPerSec) {
+  static void toTicks(int64_t& result,
+                      int64_t secs,
+                      int64_t oldTicks,
+                      int64_t oldTicksPerSec,
+                      int64_t newTicksPerSec) {
     result = secs * newTicksPerSec;
     result += oldTicks * newTicksPerSec / oldTicksPerSec;
 
@@ -86,34 +90,28 @@
   /**
    * Converts struct THRIFT_TIMESPEC to arbitrary-sized ticks since epoch
    */
-  static void toTicks(int64_t& result,
-                      const struct THRIFT_TIMESPEC& value,
-                      int64_t ticksPerSec) {
+  static void toTicks(int64_t& result, const struct THRIFT_TIMESPEC& value, int64_t ticksPerSec) {
     return toTicks(result, value.tv_sec, value.tv_nsec, NS_PER_S, ticksPerSec);
   }
 
   /**
    * Converts struct timeval to arbitrary-sized ticks since epoch
    */
-  static void toTicks(int64_t& result,
-                      const struct timeval& value,
-                      int64_t ticksPerSec) {
-    return toTicks(result, value.tv_sec, value.tv_usec, US_PER_S, ticksPerSec);
+  static void toTicks(int64_t& result, const struct timeval& value, int64_t ticksPerSec) {
+    return toTicks(result, (unsigned long)value.tv_sec, (unsigned long)value.tv_usec, US_PER_S, ticksPerSec);
   }
 
   /**
    * Converts struct THRIFT_TIMESPEC to milliseconds
    */
-  static void toMilliseconds(int64_t& result,
-                             const struct THRIFT_TIMESPEC& value) {
+  static void toMilliseconds(int64_t& result, const struct THRIFT_TIMESPEC& value) {
     return toTicks(result, value, MS_PER_S);
   }
 
   /**
    * Converts struct timeval to milliseconds
    */
-  static void toMilliseconds(int64_t& result,
-                             const struct timeval& value) {
+  static void toMilliseconds(int64_t& result, const struct timeval& value) {
     return toTicks(result, value, MS_PER_S);
   }
 
@@ -146,7 +144,8 @@
    */
   static int64_t currentTimeUsec() { return currentTimeTicks(US_PER_S); }
 };
-
-}}} // apache::thrift::concurrency
+}
+}
+} // apache::thrift::concurrency
 
 #endif // #ifndef _THRIFT_CONCURRENCY_UTIL_H_
diff --git a/lib/cpp/src/thrift/cxxfunctional.h b/lib/cpp/src/thrift/cxxfunctional.h
deleted file mode 100644
index c24b91b..0000000
--- a/lib/cpp/src/thrift/cxxfunctional.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef _THRIFT_CXXFUNCTIONAL_H_
-#define _THRIFT_CXXFUNCTIONAL_H_ 1
-
-/**
- * Loads <functional> from the 'right' location, depending
- * on compiler and whether or not it's using C++03 with TR1
- * or C++11.
- */
-
-/*
- * MSVC 10 and 11 have the <functional> stuff at <functional>.
- * In MSVC 10 all of the implementations live in std::tr1.
- * In MSVC 11 all of the implementations live in std, with aliases
- *  in std::tr1 to point to the ones in std.
- */
-#ifdef _WIN32
-  #define _THRIFT_USING_MICROSOFT_STDLIB 1
-#endif
-
-#ifdef __clang__
-  /* Clang has two options, depending on standard library:
-   * - no -stdlib or -stdlib=libstdc++ set; uses GNU libstdc++.
-   *    <tr1/functional>
-   * - -stdlib=libc++; uses LLVM libc++.
-   *    <functional>, no 'std::tr1'.
-   *
-   * The compiler itself doesn't define anything differently
-   * depending on the value of -stdlib, but the library headers
-   * will set different preprocessor options. In order to check,
-   * though, we have to pull in some library header.
-   */
-  #include <utility>
-
-  /* With LLVM libc++, utility pulls in __config, which sets
-     _LIBCPP_VERSION. */
-  #if defined(_LIBCPP_VERSION)
-    #define _THRIFT_USING_CLANG_LIBCXX 1
-
-  /* With GNU libstdc++, utility pulls in bits/c++config.h,
-     which sets __GLIBCXX__. */
-  #elif defined(__GLIBCXX__)
-    #define _THRIFT_USING_GNU_LIBSTDCXX 1
-
-  /* No idea. */
-  #else
-    #error Unable to detect which C++ standard library is in use.
-  #endif
-#elif __GNUC__
-  #define _THRIFT_USING_GNU_LIBSTDCXX 1
-#endif
-
-#if _THRIFT_USING_MICROSOFT_STDLIB
-  #include <functional>
-
-  namespace apache { namespace thrift { namespace stdcxx {
-    using ::std::tr1::function;
-    using ::std::tr1::bind;
-
-    namespace placeholders {
-      using ::std::tr1::placeholders::_1;
-      using ::std::tr1::placeholders::_2;
-      using ::std::tr1::placeholders::_3;
-      using ::std::tr1::placeholders::_4;
-      using ::std::tr1::placeholders::_5;
-      using ::std::tr1::placeholders::_6;
-    } // apache::thrift::stdcxx::placeholders
-  }}} // apache::thrift::stdcxx
-
-#elif _THRIFT_USING_CLANG_LIBCXX
-  #include <functional>
-
-  namespace apache { namespace thrift { namespace stdcxx {
-    using ::std::function;
-    using ::std::bind;
-
-    namespace placeholders {
-      using ::std::placeholders::_1;
-      using ::std::placeholders::_2;
-      using ::std::placeholders::_3;
-      using ::std::placeholders::_4;
-      using ::std::placeholders::_5;
-      using ::std::placeholders::_6;
-    } // apache::thrift::stdcxx::placeholders
-  }}} // apache::thrift::stdcxx
-
-#elif _THRIFT_USING_GNU_LIBSTDCXX
-  #include <tr1/functional>
-
-  namespace apache { namespace thrift { namespace stdcxx {
-    using ::std::tr1::function;
-    using ::std::tr1::bind;
-
-    namespace placeholders {
-      using ::std::tr1::placeholders::_1;
-      using ::std::tr1::placeholders::_2;
-      using ::std::tr1::placeholders::_3;
-      using ::std::tr1::placeholders::_4;
-      using ::std::tr1::placeholders::_5;
-      using ::std::tr1::placeholders::_6;
-    } // apache::thrift::stdcxx::placeholders
-  }}} // apache::thrift::stdcxx
-#endif
-
-  // Alias for thrift c++ compatibility namespace
-  namespace tcxx = apache::thrift::stdcxx;
-
-#endif // #ifndef _THRIFT_CXXFUNCTIONAL_H_
diff --git a/lib/cpp/src/thrift/processor/PeekProcessor.cpp b/lib/cpp/src/thrift/processor/PeekProcessor.cpp
index bfc4ac7..07f6ba5 100644
--- a/lib/cpp/src/thrift/processor/PeekProcessor.cpp
+++ b/lib/cpp/src/thrift/processor/PeekProcessor.cpp
@@ -23,42 +23,47 @@
 using namespace apache::thrift::protocol;
 using namespace apache::thrift;
 
-namespace apache { namespace thrift { namespace processor {
+namespace apache {
+namespace thrift {
+namespace processor {
 
 PeekProcessor::PeekProcessor() {
   memoryBuffer_.reset(new TMemoryBuffer());
   targetTransport_ = memoryBuffer_;
 }
-PeekProcessor::~PeekProcessor() {}
+PeekProcessor::~PeekProcessor() {
+}
 
-void PeekProcessor::initialize(boost::shared_ptr<TProcessor> actualProcessor,
-                               boost::shared_ptr<TProtocolFactory> protocolFactory,
-                               boost::shared_ptr<TPipedTransportFactory> transportFactory) {
+void PeekProcessor::initialize(std::shared_ptr<TProcessor> actualProcessor,
+                               std::shared_ptr<TProtocolFactory> protocolFactory,
+                               std::shared_ptr<TPipedTransportFactory> transportFactory) {
   actualProcessor_ = actualProcessor;
   pipedProtocol_ = protocolFactory->getProtocol(targetTransport_);
   transportFactory_ = transportFactory;
   transportFactory_->initializeTargetTransport(targetTransport_);
 }
 
-boost::shared_ptr<TTransport> PeekProcessor::getPipedTransport(boost::shared_ptr<TTransport> in) {
+std::shared_ptr<TTransport> PeekProcessor::getPipedTransport(std::shared_ptr<TTransport> in) {
   return transportFactory_->getTransport(in);
 }
 
-void PeekProcessor::setTargetTransport(boost::shared_ptr<TTransport> targetTransport) {
+void PeekProcessor::setTargetTransport(std::shared_ptr<TTransport> targetTransport) {
   targetTransport_ = targetTransport;
-  if (boost::dynamic_pointer_cast<TMemoryBuffer>(targetTransport_)) {
-    memoryBuffer_ = boost::dynamic_pointer_cast<TMemoryBuffer>(targetTransport);
-  } else if (boost::dynamic_pointer_cast<TPipedTransport>(targetTransport_)) {
-    memoryBuffer_ = boost::dynamic_pointer_cast<TMemoryBuffer>(boost::dynamic_pointer_cast<TPipedTransport>(targetTransport_)->getTargetTransport());
+  if (std::dynamic_pointer_cast<TMemoryBuffer>(targetTransport_)) {
+    memoryBuffer_ = std::dynamic_pointer_cast<TMemoryBuffer>(targetTransport);
+  } else if (std::dynamic_pointer_cast<TPipedTransport>(targetTransport_)) {
+    memoryBuffer_ = std::dynamic_pointer_cast<TMemoryBuffer>(
+        std::dynamic_pointer_cast<TPipedTransport>(targetTransport_)->getTargetTransport());
   }
 
   if (!memoryBuffer_) {
-    throw TException("Target transport must be a TMemoryBuffer or a TPipedTransport with TMemoryBuffer");
+    throw TException(
+        "Target transport must be a TMemoryBuffer or a TPipedTransport with TMemoryBuffer");
   }
 }
 
-bool PeekProcessor::process(boost::shared_ptr<TProtocol> in,
-                            boost::shared_ptr<TProtocol> out,
+bool PeekProcessor::process(std::shared_ptr<TProtocol> in,
+                            std::shared_ptr<TProtocol> out,
                             void* connectionContext) {
 
   std::string fname;
@@ -66,7 +71,7 @@
   int32_t seqid;
   in->readMessageBegin(fname, mtype, seqid);
 
-  if (mtype != T_CALL) {
+  if (mtype != T_CALL && mtype != T_ONEWAY) {
     throw TException("Unexpected message type");
   }
 
@@ -107,21 +112,21 @@
 }
 
 void PeekProcessor::peekName(const std::string& fname) {
-  (void) fname;
+  (void)fname;
 }
 
 void PeekProcessor::peekBuffer(uint8_t* buffer, uint32_t size) {
-  (void) buffer;
-  (void) size;
+  (void)buffer;
+  (void)size;
 }
 
-void PeekProcessor::peek(boost::shared_ptr<TProtocol> in,
-                         TType ftype,
-                         int16_t fid) {
-  (void) fid;
+void PeekProcessor::peek(std::shared_ptr<TProtocol> in, TType ftype, int16_t fid) {
+  (void)fid;
   in->skip(ftype);
 }
 
-void PeekProcessor::peekEnd() {}
-
-}}}
+void PeekProcessor::peekEnd() {
+}
+}
+}
+}
diff --git a/lib/cpp/src/thrift/processor/PeekProcessor.h b/lib/cpp/src/thrift/processor/PeekProcessor.h
index 9cfb35a..efac2b9 100644
--- a/lib/cpp/src/thrift/processor/PeekProcessor.h
+++ b/lib/cpp/src/thrift/processor/PeekProcessor.h
@@ -25,9 +25,11 @@
 #include <thrift/transport/TTransport.h>
 #include <thrift/transport/TTransportUtils.h>
 #include <thrift/transport/TBufferTransports.h>
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
-namespace apache { namespace thrift { namespace processor {
+namespace apache {
+namespace thrift {
+namespace processor {
 
 /*
  * Class for peeking at the raw data that is being processed by another processor
@@ -36,7 +38,7 @@
  */
 class PeekProcessor : public apache::thrift::TProcessor {
 
- public:
+public:
   PeekProcessor();
   virtual ~PeekProcessor();
 
@@ -44,35 +46,38 @@
   //             protocolFactory  - the protocol factory used to wrap the memory buffer
   //             transportFactory - this TPipedTransportFactory is used to wrap the source transport
   //                                via a call to getPipedTransport
-  void initialize(boost::shared_ptr<apache::thrift::TProcessor> actualProcessor,
-                  boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> protocolFactory,
-                  boost::shared_ptr<apache::thrift::transport::TPipedTransportFactory> transportFactory);
+  void initialize(
+      std::shared_ptr<apache::thrift::TProcessor> actualProcessor,
+      std::shared_ptr<apache::thrift::protocol::TProtocolFactory> protocolFactory,
+      std::shared_ptr<apache::thrift::transport::TPipedTransportFactory> transportFactory);
 
-  boost::shared_ptr<apache::thrift::transport::TTransport> getPipedTransport(boost::shared_ptr<apache::thrift::transport::TTransport> in);
+  std::shared_ptr<apache::thrift::transport::TTransport> getPipedTransport(
+      std::shared_ptr<apache::thrift::transport::TTransport> in);
 
-  void setTargetTransport(boost::shared_ptr<apache::thrift::transport::TTransport> targetTransport);
+  void setTargetTransport(std::shared_ptr<apache::thrift::transport::TTransport> targetTransport);
 
-  virtual bool process(boost::shared_ptr<apache::thrift::protocol::TProtocol> in,
-                       boost::shared_ptr<apache::thrift::protocol::TProtocol> out,
+  virtual bool process(std::shared_ptr<apache::thrift::protocol::TProtocol> in,
+                       std::shared_ptr<apache::thrift::protocol::TProtocol> out,
                        void* connectionContext);
 
   // The following three functions can be overloaded by child classes to
   // achieve desired peeking behavior
   virtual void peekName(const std::string& fname);
   virtual void peekBuffer(uint8_t* buffer, uint32_t size);
-  virtual void peek(boost::shared_ptr<apache::thrift::protocol::TProtocol> in,
+  virtual void peek(std::shared_ptr<apache::thrift::protocol::TProtocol> in,
                     apache::thrift::protocol::TType ftype,
                     int16_t fid);
   virtual void peekEnd();
 
- private:
-  boost::shared_ptr<apache::thrift::TProcessor> actualProcessor_;
-  boost::shared_ptr<apache::thrift::protocol::TProtocol> pipedProtocol_;
-  boost::shared_ptr<apache::thrift::transport::TPipedTransportFactory> transportFactory_;
-  boost::shared_ptr<apache::thrift::transport::TMemoryBuffer> memoryBuffer_;
-  boost::shared_ptr<apache::thrift::transport::TTransport> targetTransport_;
+private:
+  std::shared_ptr<apache::thrift::TProcessor> actualProcessor_;
+  std::shared_ptr<apache::thrift::protocol::TProtocol> pipedProtocol_;
+  std::shared_ptr<apache::thrift::transport::TPipedTransportFactory> transportFactory_;
+  std::shared_ptr<apache::thrift::transport::TMemoryBuffer> memoryBuffer_;
+  std::shared_ptr<apache::thrift::transport::TTransport> targetTransport_;
 };
-
-}}} // apache::thrift::processor
+}
+}
+} // apache::thrift::processor
 
 #endif
diff --git a/lib/cpp/src/thrift/processor/StatsProcessor.h b/lib/cpp/src/thrift/processor/StatsProcessor.h
index 58cd1dc..e98efb8 100644
--- a/lib/cpp/src/thrift/processor/StatsProcessor.h
+++ b/lib/cpp/src/thrift/processor/StatsProcessor.h
@@ -20,12 +20,14 @@
 #ifndef STATSPROCESSOR_H
 #define STATSPROCESSOR_H
 
-#include <boost/shared_ptr.hpp>
+#include <memory>
 #include <thrift/transport/TTransport.h>
 #include <thrift/protocol/TProtocol.h>
 #include <TProcessor.h>
 
-namespace apache { namespace thrift { namespace processor {
+namespace apache {
+namespace thrift {
+namespace processor {
 
 /*
  * Class for keeping track of function call statistics and printing them if desired
@@ -33,14 +35,11 @@
  */
 class StatsProcessor : public apache::thrift::TProcessor {
 public:
-  StatsProcessor(bool print, bool frequency)
-    : print_(print),
-      frequency_(frequency)
-  {}
-  virtual ~StatsProcessor() {};
+  StatsProcessor(bool print, bool frequency) : print_(print), frequency_(frequency) {}
+  virtual ~StatsProcessor(){};
 
-  virtual bool process(boost::shared_ptr<apache::thrift::protocol::TProtocol> piprot,
-                       boost::shared_ptr<apache::thrift::protocol::TProtocol> poprot,
+  virtual bool process(std::shared_ptr<apache::thrift::protocol::TProtocol> piprot,
+                       std::shared_ptr<apache::thrift::protocol::TProtocol> poprot,
                        void* serverContext) {
 
     piprot_ = piprot;
@@ -50,7 +49,7 @@
     int32_t seqid;
 
     piprot_->readMessageBegin(fname, mtype, seqid);
-    if (mtype != apache::thrift::protocol::T_CALL) {
+    if (mtype != apache::thrift::protocol::T_CALL && mtype != apache::thrift::protocol::T_ONEWAY) {
       if (print_) {
         printf("Unknown message type\n");
       }
@@ -88,179 +87,156 @@
     return true;
   }
 
-  const std::map<std::string, int64_t>& get_frequency_map() {
-    return frequency_map_;
-  }
+  const std::map<std::string, int64_t>& get_frequency_map() { return frequency_map_; }
 
 protected:
   void printAndPassToBuffer(apache::thrift::protocol::TType ftype) {
     switch (ftype) {
-      case apache::thrift::protocol::T_BOOL:
-        {
-          bool boolv;
-          piprot_->readBool(boolv);
-          if (print_) {
-            printf("%d", boolv);
-          }
+    case apache::thrift::protocol::T_BOOL: {
+      bool boolv;
+      piprot_->readBool(boolv);
+      if (print_) {
+        printf("%d", boolv);
+      }
+    } break;
+    case apache::thrift::protocol::T_BYTE: {
+      int8_t bytev;
+      piprot_->readByte(bytev);
+      if (print_) {
+        printf("%d", bytev);
+      }
+    } break;
+    case apache::thrift::protocol::T_I16: {
+      int16_t i16;
+      piprot_->readI16(i16);
+      if (print_) {
+        printf("%d", i16);
+      }
+    } break;
+    case apache::thrift::protocol::T_I32: {
+      int32_t i32;
+      piprot_->readI32(i32);
+      if (print_) {
+        printf("%d", i32);
+      }
+    } break;
+    case apache::thrift::protocol::T_I64: {
+      int64_t i64;
+      piprot_->readI64(i64);
+      if (print_) {
+        printf("%ld", i64);
+      }
+    } break;
+    case apache::thrift::protocol::T_DOUBLE: {
+      double dub;
+      piprot_->readDouble(dub);
+      if (print_) {
+        printf("%f", dub);
+      }
+    } break;
+    case apache::thrift::protocol::T_STRING: {
+      std::string str;
+      piprot_->readString(str);
+      if (print_) {
+        printf("%s", str.c_str());
+      }
+    } break;
+    case apache::thrift::protocol::T_STRUCT: {
+      std::string name;
+      int16_t fid;
+      apache::thrift::protocol::TType ftype;
+      piprot_->readStructBegin(name);
+      if (print_) {
+        printf("<");
+      }
+      while (true) {
+        piprot_->readFieldBegin(name, ftype, fid);
+        if (ftype == apache::thrift::protocol::T_STOP) {
+          break;
         }
-        break;
-      case apache::thrift::protocol::T_BYTE:
-        {
-          int8_t bytev;
-          piprot_->readByte(bytev);
-          if (print_) {
-            printf("%d", bytev);
-          }
+        printAndPassToBuffer(ftype);
+        if (print_) {
+          printf(",");
         }
-        break;
-      case apache::thrift::protocol::T_I16:
-        {
-          int16_t i16;
-          piprot_->readI16(i16);
-          if (print_) {
-            printf("%d", i16);
-          }
+        piprot_->readFieldEnd();
+      }
+      piprot_->readStructEnd();
+      if (print_) {
+        printf("\b>");
+      }
+    } break;
+    case apache::thrift::protocol::T_MAP: {
+      apache::thrift::protocol::TType keyType;
+      apache::thrift::protocol::TType valType;
+      uint32_t i, size;
+      piprot_->readMapBegin(keyType, valType, size);
+      if (print_) {
+        printf("{");
+      }
+      for (i = 0; i < size; i++) {
+        printAndPassToBuffer(keyType);
+        if (print_) {
+          printf("=>");
         }
-        break;
-      case apache::thrift::protocol::T_I32:
-        {
-          int32_t i32;
-          piprot_->readI32(i32);
-          if (print_) {
-            printf("%d", i32);
-          }
+        printAndPassToBuffer(valType);
+        if (print_) {
+          printf(",");
         }
-        break;
-      case apache::thrift::protocol::T_I64:
-        {
-          int64_t i64;
-          piprot_->readI64(i64);
-          if (print_) {
-            printf("%ld", i64);
-          }
+      }
+      piprot_->readMapEnd();
+      if (print_) {
+        printf("\b}");
+      }
+    } break;
+    case apache::thrift::protocol::T_SET: {
+      apache::thrift::protocol::TType elemType;
+      uint32_t i, size;
+      piprot_->readSetBegin(elemType, size);
+      if (print_) {
+        printf("{");
+      }
+      for (i = 0; i < size; i++) {
+        printAndPassToBuffer(elemType);
+        if (print_) {
+          printf(",");
         }
-        break;
-      case apache::thrift::protocol::T_DOUBLE:
-        {
-          double dub;
-          piprot_->readDouble(dub);
-          if (print_) {
-            printf("%f", dub);
-          }
+      }
+      piprot_->readSetEnd();
+      if (print_) {
+        printf("\b}");
+      }
+    } break;
+    case apache::thrift::protocol::T_LIST: {
+      apache::thrift::protocol::TType elemType;
+      uint32_t i, size;
+      piprot_->readListBegin(elemType, size);
+      if (print_) {
+        printf("[");
+      }
+      for (i = 0; i < size; i++) {
+        printAndPassToBuffer(elemType);
+        if (print_) {
+          printf(",");
         }
-        break;
-      case apache::thrift::protocol::T_STRING:
-        {
-          std::string str;
-          piprot_->readString(str);
-          if (print_) {
-            printf("%s", str.c_str());
-          }
-        }
-        break;
-      case apache::thrift::protocol::T_STRUCT:
-        {
-          std::string name;
-          int16_t fid;
-          apache::thrift::protocol::TType ftype;
-          piprot_->readStructBegin(name);
-          if (print_) {
-            printf("<");
-          }
-          while (true) {
-            piprot_->readFieldBegin(name, ftype, fid);
-            if (ftype == apache::thrift::protocol::T_STOP) {
-              break;
-            }
-            printAndPassToBuffer(ftype);
-            if (print_) {
-              printf(",");
-            }
-            piprot_->readFieldEnd();
-          }
-          piprot_->readStructEnd();
-          if (print_) {
-            printf("\b>");
-          }
-        }
-        break;
-      case apache::thrift::protocol::T_MAP:
-        {
-          apache::thrift::protocol::TType keyType;
-          apache::thrift::protocol::TType valType;
-          uint32_t i, size;
-          piprot_->readMapBegin(keyType, valType, size);
-          if (print_) {
-            printf("{");
-          }
-          for (i = 0; i < size; i++) {
-            printAndPassToBuffer(keyType);
-            if (print_) {
-              printf("=>");
-            }
-            printAndPassToBuffer(valType);
-            if (print_) {
-              printf(",");
-            }
-          }
-          piprot_->readMapEnd();
-          if (print_) {
-            printf("\b}");
-          }
-        }
-        break;
-      case apache::thrift::protocol::T_SET:
-        {
-          apache::thrift::protocol::TType elemType;
-          uint32_t i, size;
-          piprot_->readSetBegin(elemType, size);
-          if (print_) {
-            printf("{");
-          }
-          for (i = 0; i < size; i++) {
-            printAndPassToBuffer(elemType);
-            if (print_) {
-              printf(",");
-            }
-          }
-          piprot_->readSetEnd();
-          if (print_) {
-            printf("\b}");
-          }
-        }
-        break;
-      case apache::thrift::protocol::T_LIST:
-        {
-          apache::thrift::protocol::TType elemType;
-          uint32_t i, size;
-          piprot_->readListBegin(elemType, size);
-          if (print_) {
-            printf("[");
-          }
-          for (i = 0; i < size; i++) {
-            printAndPassToBuffer(elemType);
-            if (print_) {
-              printf(",");
-            }
-          }
-          piprot_->readListEnd();
-          if (print_) {
-            printf("\b]");
-          }
-        }
-        break;
-      default:
-        break;
+      }
+      piprot_->readListEnd();
+      if (print_) {
+        printf("\b]");
+      }
+    } break;
+    default:
+      break;
     }
   }
 
-  boost::shared_ptr<apache::thrift::protocol::TProtocol> piprot_;
+  std::shared_ptr<apache::thrift::protocol::TProtocol> piprot_;
   std::map<std::string, int64_t> frequency_map_;
 
   bool print_;
   bool frequency_;
 };
-
-}}} // apache::thrift::processor
+}
+}
+} // apache::thrift::processor
 
 #endif
diff --git a/lib/cpp/src/thrift/processor/TMultiplexedProcessor.h b/lib/cpp/src/thrift/processor/TMultiplexedProcessor.h
index 494ec10..2aa7f75 100644
--- a/lib/cpp/src/thrift/processor/TMultiplexedProcessor.h
+++ b/lib/cpp/src/thrift/processor/TMultiplexedProcessor.h
@@ -25,194 +25,200 @@
 #include <thrift/TProcessor.h>
 #include <boost/tokenizer.hpp>
 
-namespace apache 
-{ 
-    namespace thrift 
-    { 
-        using boost::shared_ptr;
+namespace apache {
+namespace thrift {
+namespace protocol {
 
-        namespace protocol {
+/**
+ *  To be able to work with any protocol, we needed
+ *  to allow them to call readMessageBegin() and get a TMessage in exactly
+ *  the standard format, without the service name prepended to TMessage.name.
+ */
+class StoredMessageProtocol : public TProtocolDecorator {
+public:
+  StoredMessageProtocol(std::shared_ptr<protocol::TProtocol> _protocol,
+                        const std::string& _name,
+                        const TMessageType _type,
+                        const int32_t _seqid)
+    : TProtocolDecorator(_protocol), name(_name), type(_type), seqid(_seqid) {}
 
-            /**
-             *  To be able to work with any protocol, we needed
-             *  to allow them to call readMessageBegin() and get a TMessage in exactly
-             *  the standard format, without the service name prepended to TMessage.name.
-             */
-            class StoredMessageProtocol : public TProtocolDecorator
-            {
-            public:
-                StoredMessageProtocol( shared_ptr<protocol::TProtocol> _protocol,
-                    const std::string& _name, const TMessageType _type, 
-                    const int32_t _seqid) :
-                    TProtocolDecorator(_protocol),
-                    name(_name),
-                    type(_type),
-                    seqid(_seqid)
-                {
-                }
+  uint32_t readMessageBegin_virt(std::string& _name, TMessageType& _type, int32_t& _seqid) {
 
-                uint32_t readMessageBegin_virt(std::string& _name, TMessageType& _type, int32_t& _seqid)
-                {
-                    
-                    _name  = name;
-                    _type  = type;
-                    _seqid = seqid;
+    _name = name;
+    _type = type;
+    _seqid = seqid;
 
-                    return 0; // (Normal TProtocol read functions return number of bytes read)
-                }
+    return 0; // (Normal TProtocol read functions return number of bytes read)
+  }
 
-                std::string name;
-                TMessageType type;
-                int32_t seqid;
-            };
-        } //namespace protocol
+  std::string name;
+  TMessageType type;
+  int32_t seqid;
+};
+} // namespace protocol
 
-        /**
-         * <code>TMultiplexedProcessor</code> is a <code>TProcessor</code> allowing
-         * a single <code>TServer</code> to provide multiple services.
-         *
-         * <p>To do so, you instantiate the processor and then register additional
-         * processors with it, as shown in the following example:</p>
-         *
-         * <blockquote><code>
-         *     shared_ptr<TMultiplexedProcessor> processor(new TMultiplexedProcessor());
-         *
-         *     processor->registerProcessor(
-         *         "Calculator",
-         *         shared_ptr<TProcessor>( new CalculatorProcessor(
-         *             shared_ptr<CalculatorHandler>( new CalculatorHandler()))));
-         *
-         *     processor->registerProcessor(
-         *         "WeatherReport",
-         *         shared_ptr<TProcessor>( new WeatherReportProcessor(
-         *             shared_ptr<WeatherReportHandler>( new WeatherReportHandler()))));
-         *
-         *     shared_ptr<TServerTransport> transport(new TServerSocket(9090));
-         *     TSimpleServer server(processor, transport);
-         *
-         *     server.serve();
-         * </code></blockquote>
-         */
-        class TMultiplexedProcessor : public TProcessor
-        {
-        public:
-            typedef std::map< std::string, shared_ptr<TProcessor> > services_t;
+/**
+ * <code>TMultiplexedProcessor</code> is a <code>TProcessor</code> allowing
+ * a single <code>TServer</code> to provide multiple services.
+ *
+ * <p>To do so, you instantiate the processor and then register additional
+ * processors with it, as shown in the following example:</p>
+ *
+ * <blockquote><code>
+ *     std::shared_ptr<TMultiplexedProcessor> processor(new TMultiplexedProcessor());
+ *
+ *     processor->registerProcessor(
+ *         "Calculator",
+ *         std::shared_ptr<TProcessor>( new CalculatorProcessor(
+ *             std::shared_ptr<CalculatorHandler>( new CalculatorHandler()))));
+ *
+ *     processor->registerProcessor(
+ *         "WeatherReport",
+ *         std::shared_ptr<TProcessor>( new WeatherReportProcessor(
+ *             std::shared_ptr<WeatherReportHandler>( new WeatherReportHandler()))));
+ *
+ *     std::shared_ptr<TServerTransport> transport(new TServerSocket(9090));
+ *     TSimpleServer server(processor, transport);
+ *
+ *     server.serve();
+ * </code></blockquote>
+ */
+class TMultiplexedProcessor : public TProcessor {
+public:
+  typedef std::map<std::string, std::shared_ptr<TProcessor> > services_t;
 
-           /**
-             * 'Register' a service with this <code>TMultiplexedProcessor</code>.  This
-             * allows us to broker requests to individual services by using the service
-             * name to select them at request time.
-             *
-             * \param [in] serviceName Name of a service, has to be identical to the name
-             *                         declared in the Thrift IDL, e.g. "WeatherReport".
-             * \param [in] processor   Implementation of a service, ususally referred to
-             *                         as "handlers", e.g. WeatherReportHandler,
-             *                         implementing WeatherReportIf interface.
-             */
-            void registerProcessor( const std::string & serviceName, 
-                                    shared_ptr<TProcessor> processor )
-            {
-                services[serviceName] = processor;
-            }
+  /**
+    * 'Register' a service with this <code>TMultiplexedProcessor</code>.  This
+    * allows us to broker requests to individual services by using the service
+    * name to select them at request time.
+    *
+    * \param [in] serviceName Name of a service, has to be identical to the name
+    *                         declared in the Thrift IDL, e.g. "WeatherReport".
+    * \param [in] processor   Implementation of a service, usually referred to
+    *                         as "handlers", e.g. WeatherReportHandler,
+    *                         implementing WeatherReportIf interface.
+    */
+  void registerProcessor(const std::string& serviceName, std::shared_ptr<TProcessor> processor) {
+    services[serviceName] = processor;
+  }
 
-            /**
-             * This implementation of <code>process</code> performs the following steps:
-             *
-             * <ol>
-             *     <li>Read the beginning of the message.</li>
-             *     <li>Extract the service name from the message.</li>
-             *     <li>Using the service name to locate the appropriate processor.</li>
-             *     <li>Dispatch to the processor, with a decorated instance of TProtocol
-             *         that allows readMessageBegin() to return the original TMessage.</li>
-             * </ol>
-             *  
-             * \throws TException If the message type is not T_CALL or T_ONEWAY, if
-             * the service name was not found in the message, or if the service
-             * name was not found in the service map. 
-             */
-            bool process( shared_ptr<protocol::TProtocol> in, 
-                          shared_ptr<protocol::TProtocol> out,
-                          void *connectionContext)
-            {
-                std::string name;
-                protocol::TMessageType type;
-                int32_t seqid;
+  /**
+   * Register a service to be called to process queries without service name
+   * \param [in] processor   Implementation of a service.
+   */
+  void registerDefault(const std::shared_ptr<TProcessor>& processor) {
+    defaultProcessor = processor;
+  }
 
-                // Use the actual underlying protocol (e.g. TBinaryProtocol) to read the
-                // message header.  This pulls the message "off the wire", which we'll
-                // deal with at the end of this method.
-                in->readMessageBegin(name, type, seqid);
+  /**
+   * Chew up invalid input and return an exception to throw.
+   */
+  TException protocol_error(std::shared_ptr<protocol::TProtocol> in,
+                            std::shared_ptr<protocol::TProtocol> out,
+                            const std::string& name, 
+                            int32_t seqid, 
+                            const std::string& msg) const {
+    in->skip(::apache::thrift::protocol::T_STRUCT);
+    in->readMessageEnd();
+    in->getTransport()->readEnd();
+    ::apache::thrift::TApplicationException
+      x(::apache::thrift::TApplicationException::PROTOCOL_ERROR,
+        "TMultiplexedProcessor: " + msg);
+    out->writeMessageBegin(name, ::apache::thrift::protocol::T_EXCEPTION, seqid);
+    x.write(out.get());
+    out->writeMessageEnd();
+    out->getTransport()->writeEnd();
+    out->getTransport()->flush();
+    return TException(msg);
+}
+   
+  /**
+   * This implementation of <code>process</code> performs the following steps:
+   *
+   * <ol>
+   *     <li>Read the beginning of the message.</li>
+   *     <li>Extract the service name from the message.</li>
+   *     <li>Using the service name to locate the appropriate processor.</li>
+   *     <li>Dispatch to the processor, with a decorated instance of TProtocol
+   *         that allows readMessageBegin() to return the original TMessage.</li>
+   * </ol>
+   *
+   * \throws TException If the message type is not T_CALL or T_ONEWAY, if
+   * the service name was not found in the message, or if the service
+   * name was not found in the service map.
+   */
+  bool process(std::shared_ptr<protocol::TProtocol> in,
+               std::shared_ptr<protocol::TProtocol> out,
+               void* connectionContext) {
+    std::string name;
+    protocol::TMessageType type;
+    int32_t seqid;
 
-                if( type != protocol::T_CALL && type != protocol::T_ONEWAY ) {
-                    // Unexpected message type. 
-                    in->skip(::apache::thrift::protocol::T_STRUCT);
-                    in->readMessageEnd();
-                    in->getTransport()->readEnd();
-                    const std::string msg("TMultiplexedProcessor: Unexpected message type");
-                    ::apache::thrift::TApplicationException x(
-                        ::apache::thrift::TApplicationException::PROTOCOL_ERROR, 
-                        msg);
-                    out->writeMessageBegin(name, ::apache::thrift::protocol::T_EXCEPTION, seqid);
-                    x.write(out.get());
-                    out->writeMessageEnd();
-                    out->getTransport()->writeEnd();
-                    out->getTransport()->flush();
-                    throw TException(msg);
-                }
+    // Use the actual underlying protocol (e.g. TBinaryProtocol) to read the
+    // message header.  This pulls the message "off the wire", which we'll
+    // deal with at the end of this method.
+    in->readMessageBegin(name, type, seqid);
 
-                // Extract the service name
-                
-                boost::tokenizer<boost::char_separator<char> > tok( name, boost::char_separator<char>(":") );
-
-                std::vector<std::string> tokens;
-                std::copy( tok.begin(), tok.end(), std::back_inserter(tokens) );
-
-                // A valid message should consist of two tokens: the service
-                // name and the name of the method to call.
-                if( tokens.size() == 2 )
-                {
-                    // Search for a processor associated with this service name.
-                    services_t::iterator it = services.find(tokens[0]);
-
-                    if( it != services.end() )
-                    {
-                        shared_ptr<TProcessor> processor = it->second;
-                        // Let the processor registered for this service name 
-                        // process the message.
-                        return processor->process( 
-                            shared_ptr<protocol::TProtocol>( 
-                                new protocol::StoredMessageProtocol( in, tokens[1], type, seqid ) ), 
-                            out, connectionContext );
-                    }
-                    else
-                    {
-                        // Unknown service. 
-                        in->skip(::apache::thrift::protocol::T_STRUCT);
-                        in->readMessageEnd();
-                        in->getTransport()->readEnd();
-                        
-                        std::string msg("TMultiplexedProcessor: Unknown service: ");
-                        msg += tokens[0];
-                        ::apache::thrift::TApplicationException x(
-                            ::apache::thrift::TApplicationException::PROTOCOL_ERROR, 
-                            msg);
-                        out->writeMessageBegin(name, ::apache::thrift::protocol::T_EXCEPTION, seqid);
-                        x.write(out.get());
-                        out->writeMessageEnd();
-                        out->getTransport()->writeEnd();
-                        out->getTransport()->flush();
-                        msg += ". Did you forget to call registerProcessor()?";
-                        throw TException(msg);
-                    }
-                }
-                return false;
-            }
-
-        private:
-            /** Map of service processor objects, indexed by service names. */
-            services_t services;
-        };
+    if (type != protocol::T_CALL && type != protocol::T_ONEWAY) {
+      // Unexpected message type.
+      throw protocol_error(in, out, name, seqid, "Unexpected message type");
     }
-} 
+
+    // Extract the service name
+    boost::tokenizer<boost::char_separator<char> > tok(name, boost::char_separator<char>(":"));
+
+    std::vector<std::string> tokens;
+    std::copy(tok.begin(), tok.end(), std::back_inserter(tokens));
+
+    // A valid message should consist of two tokens: the service
+    // name and the name of the method to call.
+    if (tokens.size() == 2) {
+      // Search for a processor associated with this service name.
+      services_t::iterator it = services.find(tokens[0]);
+
+      if (it != services.end()) {
+        std::shared_ptr<TProcessor> processor = it->second;
+        // Let the processor registered for this service name
+        // process the message.
+        return processor
+            ->process(std::shared_ptr<protocol::TProtocol>(
+                          new protocol::StoredMessageProtocol(in, tokens[1], type, seqid)),
+                      out,
+                      connectionContext);
+      } else {
+        // Unknown service.
+        throw protocol_error(in, out, name, seqid, 
+            "Unknown service: " + tokens[0] +
+				". Did you forget to call registerProcessor()?");
+      }
+    } else if (tokens.size() == 1) {
+	  if (defaultProcessor) {
+        // non-multiplexed client forwards to default processor
+        return defaultProcessor            
+            ->process(std::shared_ptr<protocol::TProtocol>(
+                          new protocol::StoredMessageProtocol(in, tokens[0], type, seqid)),
+                      out,
+                      connectionContext);
+	  } else {
+		throw protocol_error(in, out, name, seqid,
+			"Non-multiplexed client request dropped. "
+			"Did you forget to call defaultProcessor()?");
+	  }
+    } else {
+		throw protocol_error(in, out, name, seqid,
+		    "Wrong number of tokens.");
+    }
+  }
+
+private:
+  /** Map of service processor objects, indexed by service names. */
+  services_t services;
+  
+  //! If a non-multi client requests something, it goes to the
+  //! default processor (if one is defined) for backwards compatibility.
+  std::shared_ptr<TProcessor> defaultProcessor;
+};
+}
+}
 
 #endif // THRIFT_TMULTIPLEXEDPROCESSOR_H_
diff --git a/lib/cpp/src/thrift/protocol/TBase64Utils.cpp b/lib/cpp/src/thrift/protocol/TBase64Utils.cpp
index cd343ed..7474f5a 100644
--- a/lib/cpp/src/thrift/protocol/TBase64Utils.cpp
+++ b/lib/cpp/src/thrift/protocol/TBase64Utils.cpp
@@ -19,17 +19,16 @@
 
 #include <thrift/protocol/TBase64Utils.h>
 
-#include <boost/static_assert.hpp>
-
 using std::string;
 
-namespace apache { namespace thrift { namespace protocol {
+namespace apache {
+namespace thrift {
+namespace protocol {
 
+static const uint8_t* kBase64EncodeTable
+    = (const uint8_t*)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
-static const uint8_t *kBase64EncodeTable = (const uint8_t *)
-  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-void  base64_encode(const uint8_t *in, uint32_t len, uint8_t *buf) {
+void base64_encode(const uint8_t* in, uint32_t len, uint8_t* buf) {
   buf[0] = kBase64EncodeTable[(in[0] >> 2) & 0x3f];
   if (len == 3) {
     buf[1] = kBase64EncodeTable[((in[0] << 4) & 0x30) | ((in[1] >> 4) & 0x0f)];
@@ -38,42 +37,279 @@
   } else if (len == 2) {
     buf[1] = kBase64EncodeTable[((in[0] << 4) & 0x30) | ((in[1] >> 4) & 0x0f)];
     buf[2] = kBase64EncodeTable[(in[1] << 2) & 0x3c];
-  } else  { // len == 1
+  } else { // len == 1
     buf[1] = kBase64EncodeTable[(in[0] << 4) & 0x30];
   }
 }
 
-static const uint8_t kBase64DecodeTable[256] ={
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3e,0xff,0xff,0xff,0x3f,
-0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
-0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0xff,0xff,0xff,0xff,0xff,
-0xff,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
-0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
-0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+static const uint8_t kBase64DecodeTable[256] = {
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0x3e,
+    0xff,
+    0xff,
+    0xff,
+    0x3f,
+    0x34,
+    0x35,
+    0x36,
+    0x37,
+    0x38,
+    0x39,
+    0x3a,
+    0x3b,
+    0x3c,
+    0x3d,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0x00,
+    0x01,
+    0x02,
+    0x03,
+    0x04,
+    0x05,
+    0x06,
+    0x07,
+    0x08,
+    0x09,
+    0x0a,
+    0x0b,
+    0x0c,
+    0x0d,
+    0x0e,
+    0x0f,
+    0x10,
+    0x11,
+    0x12,
+    0x13,
+    0x14,
+    0x15,
+    0x16,
+    0x17,
+    0x18,
+    0x19,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0x1a,
+    0x1b,
+    0x1c,
+    0x1d,
+    0x1e,
+    0x1f,
+    0x20,
+    0x21,
+    0x22,
+    0x23,
+    0x24,
+    0x25,
+    0x26,
+    0x27,
+    0x28,
+    0x29,
+    0x2a,
+    0x2b,
+    0x2c,
+    0x2d,
+    0x2e,
+    0x2f,
+    0x30,
+    0x31,
+    0x32,
+    0x33,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
+    0xff,
 };
 
-void base64_decode(uint8_t *buf, uint32_t len) {
-  buf[0] = (kBase64DecodeTable[buf[0]] << 2) |
-           (kBase64DecodeTable[buf[1]] >> 4);
+void base64_decode(uint8_t* buf, uint32_t len) {
+  buf[0] = (kBase64DecodeTable[buf[0]] << 2) | (kBase64DecodeTable[buf[1]] >> 4);
   if (len > 2) {
-    buf[1] = ((kBase64DecodeTable[buf[1]] << 4) & 0xf0) |
-              (kBase64DecodeTable[buf[2]] >> 2);
+    buf[1] = ((kBase64DecodeTable[buf[1]] << 4) & 0xf0) | (kBase64DecodeTable[buf[2]] >> 2);
     if (len > 3) {
-      buf[2] = ((kBase64DecodeTable[buf[2]] << 6) & 0xc0) |
-                (kBase64DecodeTable[buf[3]]);
+      buf[2] = ((kBase64DecodeTable[buf[2]] << 6) & 0xc0) | (kBase64DecodeTable[buf[3]]);
     }
   }
 }
-
-
-}}} // apache::thrift::protocol
+}
+}
+} // apache::thrift::protocol
diff --git a/lib/cpp/src/thrift/protocol/TBase64Utils.h b/lib/cpp/src/thrift/protocol/TBase64Utils.h
index 3def733..1ea6744 100644
--- a/lib/cpp/src/thrift/protocol/TBase64Utils.h
+++ b/lib/cpp/src/thrift/protocol/TBase64Utils.h
@@ -23,20 +23,23 @@
 #include <stdint.h>
 #include <string>
 
-namespace apache { namespace thrift { namespace protocol {
+namespace apache {
+namespace thrift {
+namespace protocol {
 
 // in must be at least len bytes
 // len must be 1, 2, or 3
 // buf must be a buffer of at least 4 bytes and may not overlap in
 // the data is not padded with '='; the caller can do this if desired
-void base64_encode(const uint8_t *in, uint32_t len, uint8_t *buf);
+void base64_encode(const uint8_t* in, uint32_t len, uint8_t* buf);
 
 // buf must be a buffer of at least 4 bytes and contain base64 encoded values
 // buf will be changed to contain output bytes
 // len is number of bytes to consume from input (must be 2, 3, or 4)
 // no '=' padding should be included in the input
-void base64_decode(uint8_t *buf, uint32_t len);
-
-}}} // apache::thrift::protocol
+void base64_decode(uint8_t* buf, uint32_t len);
+}
+}
+} // apache::thrift::protocol
 
 #endif // #define _THRIFT_PROTOCOL_TBASE64UTILS_H_
diff --git a/lib/cpp/src/thrift/protocol/TBinaryProtocol.h b/lib/cpp/src/thrift/protocol/TBinaryProtocol.h
index a5b19e5..9067758 100644
--- a/lib/cpp/src/thrift/protocol/TBinaryProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TBinaryProtocol.h
@@ -23,62 +23,47 @@
 #include <thrift/protocol/TProtocol.h>
 #include <thrift/protocol/TVirtualProtocol.h>
 
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
-namespace apache { namespace thrift { namespace protocol {
+namespace apache {
+namespace thrift {
+namespace protocol {
 
 /**
  * The default binary protocol for thrift. Writes all data in a very basic
  * binary format, essentially just spitting out the raw bytes.
  *
  */
-template <class Transport_>
-class TBinaryProtocolT
-  : public TVirtualProtocol< TBinaryProtocolT<Transport_> > {
- protected:
+template <class Transport_, class ByteOrder_ = TNetworkBigEndian>
+class TBinaryProtocolT : public TVirtualProtocol<TBinaryProtocolT<Transport_, ByteOrder_> > {
+public:
   static const int32_t VERSION_MASK = ((int32_t)0xffff0000);
   static const int32_t VERSION_1 = ((int32_t)0x80010000);
-  // VERSION_2 (0x80020000)  is taken by TDenseProtocol.
+  // VERSION_2 (0x80020000) was taken by TDenseProtocol (which has since been removed)
 
- public:
-  TBinaryProtocolT(boost::shared_ptr<Transport_> trans) :
-    TVirtualProtocol< TBinaryProtocolT<Transport_> >(trans),
-    trans_(trans.get()),
-    string_limit_(0),
-    container_limit_(0),
-    strict_read_(false),
-    strict_write_(true),
-    string_buf_(NULL),
-    string_buf_size_(0) {}
+  TBinaryProtocolT(std::shared_ptr<Transport_> trans)
+    : TVirtualProtocol<TBinaryProtocolT<Transport_, ByteOrder_> >(trans),
+      trans_(trans.get()),
+      string_limit_(0),
+      container_limit_(0),
+      strict_read_(false),
+      strict_write_(true) {}
 
-  TBinaryProtocolT(boost::shared_ptr<Transport_> trans,
+  TBinaryProtocolT(std::shared_ptr<Transport_> trans,
                    int32_t string_limit,
                    int32_t container_limit,
                    bool strict_read,
-                   bool strict_write) :
-    TVirtualProtocol< TBinaryProtocolT<Transport_> >(trans),
-    trans_(trans.get()),
-    string_limit_(string_limit),
-    container_limit_(container_limit),
-    strict_read_(strict_read),
-    strict_write_(strict_write),
-    string_buf_(NULL),
-    string_buf_size_(0) {}
+                   bool strict_write)
+    : TVirtualProtocol<TBinaryProtocolT<Transport_, ByteOrder_> >(trans),
+      trans_(trans.get()),
+      string_limit_(string_limit),
+      container_limit_(container_limit),
+      strict_read_(strict_read),
+      strict_write_(strict_write) {}
 
-  ~TBinaryProtocolT() {
-    if (string_buf_ != NULL) {
-      std::free(string_buf_);
-      string_buf_size_ = 0;
-    }
-  }
+  void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; }
 
-  void setStringSizeLimit(int32_t string_limit) {
-    string_limit_ = string_limit;
-  }
-
-  void setContainerSizeLimit(int32_t container_limit) {
-    container_limit_ = container_limit;
-  }
+  void setContainerSizeLimit(int32_t container_limit) { container_limit_ = container_limit; }
 
   void setStrict(bool strict_read, bool strict_write) {
     strict_read_ = strict_read;
@@ -95,22 +80,17 @@
 
   /*ol*/ uint32_t writeMessageEnd();
 
-
   inline uint32_t writeStructBegin(const char* name);
 
   inline uint32_t writeStructEnd();
 
-  inline uint32_t writeFieldBegin(const char* name,
-                                  const TType fieldType,
-                                  const int16_t fieldId);
+  inline uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId);
 
   inline uint32_t writeFieldEnd();
 
   inline uint32_t writeFieldStop();
 
-  inline uint32_t writeMapBegin(const TType keyType,
-                                const TType valType,
-                                const uint32_t size);
+  inline uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size);
 
   inline uint32_t writeMapEnd();
 
@@ -143,10 +123,7 @@
    * Reading functions
    */
 
-
-  /*ol*/ uint32_t readMessageBegin(std::string& name,
-                                   TMessageType& messageType,
-                                   int32_t& seqid);
+  /*ol*/ uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid);
 
   /*ol*/ uint32_t readMessageEnd();
 
@@ -154,15 +131,11 @@
 
   inline uint32_t readStructEnd();
 
-  inline uint32_t readFieldBegin(std::string& name,
-                                 TType& fieldType,
-                                 int16_t& fieldId);
+  inline uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId);
 
   inline uint32_t readFieldEnd();
 
-  inline uint32_t readMapBegin(TType& keyType,
-                               TType& valType,
-                               uint32_t& size);
+  inline uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size);
 
   inline uint32_t readMapEnd();
 
@@ -176,7 +149,7 @@
 
   inline uint32_t readBool(bool& value);
   // Provide the default readBool() implementation for std::vector<bool>
-  using TVirtualProtocol< TBinaryProtocolT<Transport_> >::readBool;
+  using TVirtualProtocol<TBinaryProtocolT<Transport_, ByteOrder_> >::readBool;
 
   inline uint32_t readByte(int8_t& byte);
 
@@ -188,13 +161,13 @@
 
   inline uint32_t readDouble(double& dub);
 
-  template<typename StrType>
+  template <typename StrType>
   inline uint32_t readString(StrType& str);
 
   inline uint32_t readBinary(std::string& str);
 
- protected:
-  template<typename StrType>
+protected:
+  template <typename StrType>
   uint32_t readStringBody(StrType& str, int32_t sz);
 
   Transport_* trans_;
@@ -205,77 +178,72 @@
   // Enforce presence of version identifier
   bool strict_read_;
   bool strict_write_;
-
-  // Buffer for reading strings, save for the lifetime of the protocol to
-  // avoid memory churn allocating memory on every string read
-  uint8_t* string_buf_;
-  int32_t string_buf_size_;
-
 };
 
 typedef TBinaryProtocolT<TTransport> TBinaryProtocol;
+typedef TBinaryProtocolT<TTransport, TNetworkLittleEndian> TLEBinaryProtocol;
 
 /**
  * Constructs binary protocol handlers
  */
-template <class Transport_>
+template <class Transport_, class ByteOrder_ = TNetworkBigEndian>
 class TBinaryProtocolFactoryT : public TProtocolFactory {
- public:
-  TBinaryProtocolFactoryT() :
-    string_limit_(0),
-    container_limit_(0),
-    strict_read_(false),
-    strict_write_(true) {}
+public:
+  TBinaryProtocolFactoryT()
+    : string_limit_(0), container_limit_(0), strict_read_(false), strict_write_(true) {}
 
-  TBinaryProtocolFactoryT(int32_t string_limit, int32_t container_limit,
-                          bool strict_read, bool strict_write) :
-    string_limit_(string_limit),
-    container_limit_(container_limit),
-    strict_read_(strict_read),
-    strict_write_(strict_write) {}
+  TBinaryProtocolFactoryT(int32_t string_limit,
+                          int32_t container_limit,
+                          bool strict_read,
+                          bool strict_write)
+    : string_limit_(string_limit),
+      container_limit_(container_limit),
+      strict_read_(strict_read),
+      strict_write_(strict_write) {}
 
   virtual ~TBinaryProtocolFactoryT() {}
 
-  void setStringSizeLimit(int32_t string_limit) {
-    string_limit_ = string_limit;
-  }
+  void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; }
 
-  void setContainerSizeLimit(int32_t container_limit) {
-    container_limit_ = container_limit;
-  }
+  void setContainerSizeLimit(int32_t container_limit) { container_limit_ = container_limit; }
 
   void setStrict(bool strict_read, bool strict_write) {
     strict_read_ = strict_read;
     strict_write_ = strict_write;
   }
 
-  boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) {
-    boost::shared_ptr<Transport_> specific_trans =
-      boost::dynamic_pointer_cast<Transport_>(trans);
+  std::shared_ptr<TProtocol> getProtocol(std::shared_ptr<TTransport> trans) {
+    std::shared_ptr<Transport_> specific_trans = std::dynamic_pointer_cast<Transport_>(trans);
     TProtocol* prot;
     if (specific_trans) {
-      prot = new TBinaryProtocolT<Transport_>(specific_trans, string_limit_,
-                                              container_limit_, strict_read_,
-                                              strict_write_);
+      prot = new TBinaryProtocolT<Transport_, ByteOrder_>(specific_trans,
+                                                          string_limit_,
+                                                          container_limit_,
+                                                          strict_read_,
+                                                          strict_write_);
     } else {
-      prot = new TBinaryProtocol(trans, string_limit_, container_limit_,
-                                 strict_read_, strict_write_);
+      prot = new TBinaryProtocolT<TTransport, ByteOrder_>(trans,
+                                                          string_limit_,
+                                                          container_limit_,
+                                                          strict_read_,
+                                                          strict_write_);
     }
 
-    return boost::shared_ptr<TProtocol>(prot);
+    return std::shared_ptr<TProtocol>(prot);
   }
 
- private:
+private:
   int32_t string_limit_;
   int32_t container_limit_;
   bool strict_read_;
   bool strict_write_;
-
 };
 
 typedef TBinaryProtocolFactoryT<TTransport> TBinaryProtocolFactory;
-
-}}} // apache::thrift::protocol
+typedef TBinaryProtocolFactoryT<TTransport, TNetworkLittleEndian> TLEBinaryProtocolFactory;
+}
+}
+} // apache::thrift::protocol
 
 #include <thrift/protocol/TBinaryProtocol.tcc>
 
diff --git a/lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc b/lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc
index 54d79b7..fe73992 100644
--- a/lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc
+++ b/lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc
@@ -24,13 +24,14 @@
 
 #include <limits>
 
+namespace apache {
+namespace thrift {
+namespace protocol {
 
-namespace apache { namespace thrift { namespace protocol {
-
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeMessageBegin(const std::string& name,
-                                                         const TMessageType messageType,
-                                                         const int32_t seqid) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMessageBegin(const std::string& name,
+                                                                     const TMessageType messageType,
+                                                                     const int32_t seqid) {
   if (this->strict_write_) {
     int32_t version = (VERSION_1) | ((int32_t)messageType);
     uint32_t wsize = 0;
@@ -47,48 +48,47 @@
   }
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeMessageEnd() {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMessageEnd() {
   return 0;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeStructBegin(const char* name) {
-  (void) name;
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeStructBegin(const char* name) {
+  (void)name;
   return 0;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeStructEnd() {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeStructEnd() {
   return 0;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeFieldBegin(const char* name,
-                                                       const TType fieldType,
-                                                       const int16_t fieldId) {
-  (void) name;
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldBegin(const char* name,
+                                                                   const TType fieldType,
+                                                                   const int16_t fieldId) {
+  (void)name;
   uint32_t wsize = 0;
   wsize += writeByte((int8_t)fieldType);
   wsize += writeI16(fieldId);
   return wsize;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeFieldEnd() {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldEnd() {
   return 0;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeFieldStop() {
-  return
-    writeByte((int8_t)T_STOP);
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldStop() {
+  return writeByte((int8_t)T_STOP);
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeMapBegin(const TType keyType,
-                                                     const TType valType,
-                                                     const uint32_t size) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMapBegin(const TType keyType,
+                                                                 const TType valType,
+                                                                 const uint32_t size) {
   uint32_t wsize = 0;
   wsize += writeByte((int8_t)keyType);
   wsize += writeByte((int8_t)valType);
@@ -96,89 +96,88 @@
   return wsize;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeMapEnd() {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMapEnd() {
   return 0;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeListBegin(const TType elemType,
-                                                      const uint32_t size) {
-  uint32_t wsize = 0;
-  wsize += writeByte((int8_t) elemType);
-  wsize += writeI32((int32_t)size);
-  return wsize;
-}
-
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeListEnd() {
-  return 0;
-}
-
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeSetBegin(const TType elemType,
-                                                     const uint32_t size) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeListBegin(const TType elemType,
+                                                                  const uint32_t size) {
   uint32_t wsize = 0;
   wsize += writeByte((int8_t)elemType);
   wsize += writeI32((int32_t)size);
   return wsize;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeSetEnd() {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeListEnd() {
   return 0;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeBool(const bool value) {
-  uint8_t tmp =  value ? 1 : 0;
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeSetBegin(const TType elemType,
+                                                                 const uint32_t size) {
+  uint32_t wsize = 0;
+  wsize += writeByte((int8_t)elemType);
+  wsize += writeI32((int32_t)size);
+  return wsize;
+}
+
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeSetEnd() {
+  return 0;
+}
+
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeBool(const bool value) {
+  uint8_t tmp = value ? 1 : 0;
   this->trans_->write(&tmp, 1);
   return 1;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeByte(const int8_t byte) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeByte(const int8_t byte) {
   this->trans_->write((uint8_t*)&byte, 1);
   return 1;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeI16(const int16_t i16) {
-  int16_t net = (int16_t)htons(i16);
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI16(const int16_t i16) {
+  int16_t net = (int16_t)ByteOrder_::toWire16(i16);
   this->trans_->write((uint8_t*)&net, 2);
   return 2;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeI32(const int32_t i32) {
-  int32_t net = (int32_t)htonl(i32);
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI32(const int32_t i32) {
+  int32_t net = (int32_t)ByteOrder_::toWire32(i32);
   this->trans_->write((uint8_t*)&net, 4);
   return 4;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeI64(const int64_t i64) {
-  int64_t net = (int64_t)htonll(i64);
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI64(const int64_t i64) {
+  int64_t net = (int64_t)ByteOrder_::toWire64(i64);
   this->trans_->write((uint8_t*)&net, 8);
   return 8;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeDouble(const double dub) {
-  BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
-  BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeDouble(const double dub) {
+  static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
+  static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
 
   uint64_t bits = bitwise_cast<uint64_t>(dub);
-  bits = htonll(bits);
+  bits = ByteOrder_::toWire64(bits);
   this->trans_->write((uint8_t*)&bits, 8);
   return 8;
 }
 
-
-template <class Transport_>
-template<typename StrType>
-uint32_t TBinaryProtocolT<Transport_>::writeString(const StrType& str) {
-  if(str.size() > static_cast<size_t>((std::numeric_limits<int32_t>::max)()))
+template <class Transport_, class ByteOrder_>
+template <typename StrType>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeString(const StrType& str) {
+  if (str.size() > static_cast<size_t>((std::numeric_limits<int32_t>::max)()))
     throw TProtocolException(TProtocolException::SIZE_LIMIT);
   uint32_t size = static_cast<uint32_t>(str.size());
   uint32_t result = writeI32((int32_t)size);
@@ -188,19 +187,19 @@
   return result + size;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::writeBinary(const std::string& str) {
-  return TBinaryProtocolT<Transport_>::writeString(str);
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeBinary(const std::string& str) {
+  return TBinaryProtocolT<Transport_, ByteOrder_>::writeString(str);
 }
 
 /**
  * Reading functions
  */
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readMessageBegin(std::string& name,
-                                                        TMessageType& messageType,
-                                                        int32_t& seqid) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMessageBegin(std::string& name,
+                                                                    TMessageType& messageType,
+                                                                    int32_t& seqid) {
   uint32_t result = 0;
   int32_t sz;
   result += readI32(sz);
@@ -216,7 +215,8 @@
     result += readI32(seqid);
   } else {
     if (this->strict_read_) {
-      throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
+      throw TProtocolException(TProtocolException::BAD_VERSION,
+                               "No version identifier... old protocol client in strict mode?");
     } else {
       // Handle pre-versioned input
       int8_t type;
@@ -229,27 +229,27 @@
   return result;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readMessageEnd() {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMessageEnd() {
   return 0;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readStructBegin(std::string& name) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStructBegin(std::string& name) {
   name = "";
   return 0;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readStructEnd() {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStructEnd() {
   return 0;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readFieldBegin(std::string& name,
-                                                      TType& fieldType,
-                                                      int16_t& fieldId) {
-  (void) name;
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readFieldBegin(std::string& name,
+                                                                  TType& fieldType,
+                                                                  int16_t& fieldId) {
+  (void)name;
   uint32_t result = 0;
   int8_t type;
   result += readByte(type);
@@ -262,15 +262,15 @@
   return result;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readFieldEnd() {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readFieldEnd() {
   return 0;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readMapBegin(TType& keyType,
-                                                    TType& valType,
-                                                    uint32_t& size) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMapBegin(TType& keyType,
+                                                                TType& valType,
+                                                                uint32_t& size) {
   int8_t k, v;
   uint32_t result = 0;
   int32_t sizei;
@@ -288,14 +288,13 @@
   return result;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readMapEnd() {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMapEnd() {
   return 0;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readListBegin(TType& elemType,
-                                                     uint32_t& size) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readListBegin(TType& elemType, uint32_t& size) {
   int8_t e;
   uint32_t result = 0;
   int32_t sizei;
@@ -311,14 +310,13 @@
   return result;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readListEnd() {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readListEnd() {
   return 0;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readSetBegin(TType& elemType,
-                                                    uint32_t& size) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readSetBegin(TType& elemType, uint32_t& size) {
   int8_t e;
   uint32_t result = 0;
   int32_t sizei;
@@ -334,93 +332,92 @@
   return result;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readSetEnd() {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readSetEnd() {
   return 0;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readBool(bool& value) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readBool(bool& value) {
   uint8_t b[1];
   this->trans_->readAll(b, 1);
   value = *(int8_t*)b != 0;
   return 1;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readByte(int8_t& byte) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readByte(int8_t& byte) {
   uint8_t b[1];
   this->trans_->readAll(b, 1);
   byte = *(int8_t*)b;
   return 1;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readI16(int16_t& i16) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI16(int16_t& i16) {
   union bytes {
     uint8_t b[2];
     int16_t all;
   } theBytes;
   this->trans_->readAll(theBytes.b, 2);
-  i16 = (int16_t)ntohs(theBytes.all);
+  i16 = (int16_t)ByteOrder_::fromWire16(theBytes.all);
   return 2;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readI32(int32_t& i32) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI32(int32_t& i32) {
   union bytes {
     uint8_t b[4];
     int32_t all;
   } theBytes;
   this->trans_->readAll(theBytes.b, 4);
-  i32 = (int32_t)ntohl(theBytes.all);
+  i32 = (int32_t)ByteOrder_::fromWire32(theBytes.all);
   return 4;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readI64(int64_t& i64) {
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI64(int64_t& i64) {
   union bytes {
     uint8_t b[8];
     int64_t all;
   } theBytes;
   this->trans_->readAll(theBytes.b, 8);
-  i64 = (int64_t)ntohll(theBytes.all);
+  i64 = (int64_t)ByteOrder_::fromWire64(theBytes.all);
   return 8;
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readDouble(double& dub) {
-  BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
-  BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readDouble(double& dub) {
+  static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
+  static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
 
   union bytes {
     uint8_t b[8];
     uint64_t all;
   } theBytes;
   this->trans_->readAll(theBytes.b, 8);
-  theBytes.all = ntohll(theBytes.all);
+  theBytes.all = ByteOrder_::fromWire64(theBytes.all);
   dub = bitwise_cast<double>(theBytes.all);
   return 8;
 }
 
-template <class Transport_>
-template<typename StrType>
-uint32_t TBinaryProtocolT<Transport_>::readString(StrType& str) {
+template <class Transport_, class ByteOrder_>
+template <typename StrType>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readString(StrType& str) {
   uint32_t result;
   int32_t size;
   result = readI32(size);
   return result + readStringBody(str, size);
 }
 
-template <class Transport_>
-uint32_t TBinaryProtocolT<Transport_>::readBinary(std::string& str) {
-  return TBinaryProtocolT<Transport_>::readString(str);
+template <class Transport_, class ByteOrder_>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readBinary(std::string& str) {
+  return TBinaryProtocolT<Transport_, ByteOrder_>::readString(str);
 }
 
-template <class Transport_>
-template<typename StrType>
-uint32_t TBinaryProtocolT<Transport_>::readStringBody(StrType& str,
-                                                      int32_t size) {
+template <class Transport_, class ByteOrder_>
+template <typename StrType>
+uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStringBody(StrType& str, int32_t size) {
   uint32_t result = 0;
 
   // Catch error cases
@@ -446,20 +443,12 @@
     return size;
   }
 
-  // Use the heap here to prevent stack overflow for v. large strings
-  if (size > this->string_buf_size_ || this->string_buf_ == NULL) {
-    void* new_string_buf = std::realloc(this->string_buf_, (uint32_t)size);
-    if (new_string_buf == NULL) {
-      throw std::bad_alloc();
-    }
-    this->string_buf_ = (uint8_t*)new_string_buf;
-    this->string_buf_size_ = size;
-  }
-  this->trans_->readAll(this->string_buf_, size);
-  str.assign((char*)this->string_buf_, size);
+  str.resize(size);
+  this->trans_->readAll(reinterpret_cast<uint8_t*>(&str[0]), size);
   return (uint32_t)size;
 }
-
-}}} // apache::thrift::protocol
+}
+}
+} // apache::thrift::protocol
 
 #endif // #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_
diff --git a/lib/cpp/src/thrift/protocol/TCompactProtocol.h b/lib/cpp/src/thrift/protocol/TCompactProtocol.h
index d6da745..5cfb47d 100644
--- a/lib/cpp/src/thrift/protocol/TCompactProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TCompactProtocol.h
@@ -23,22 +23,25 @@
 #include <thrift/protocol/TVirtualProtocol.h>
 
 #include <stack>
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
-namespace apache { namespace thrift { namespace protocol {
+namespace apache {
+namespace thrift {
+namespace protocol {
 
 /**
  * C++ Implementation of the Compact Protocol as described in THRIFT-110
  */
 template <class Transport_>
-class TCompactProtocolT
-  : public TVirtualProtocol< TCompactProtocolT<Transport_> > {
+class TCompactProtocolT : public TVirtualProtocol<TCompactProtocolT<Transport_> > {
+public:
+  static const int8_t PROTOCOL_ID = (int8_t)0x82u;
+  static const int8_t VERSION_N = 1;
+  static const int8_t VERSION_MASK = 0x1f;       // 0001 1111
 
- protected:
-  static const int8_t  PROTOCOL_ID = (int8_t)0x82u;
-  static const int8_t  VERSION_N = 1;
-  static const int8_t  VERSION_MASK = 0x1f; // 0001 1111
-  static const int8_t  TYPE_MASK = (int8_t)0xE0u; // 1110 0000
+protected:
+  static const int8_t TYPE_MASK = (int8_t)0xE0u; // 1110 0000
+  static const int8_t TYPE_BITS = 0x07;          // 0000 0111
   static const int32_t TYPE_SHIFT_AMOUNT = 5;
 
   Transport_* trans_;
@@ -70,37 +73,34 @@
   std::stack<int16_t> lastField_;
   int16_t lastFieldId_;
 
- public:
-  TCompactProtocolT(boost::shared_ptr<Transport_> trans) :
-    TVirtualProtocol< TCompactProtocolT<Transport_> >(trans),
-    trans_(trans.get()),
-    lastFieldId_(0),
-    string_limit_(0),
-    string_buf_(NULL),
-    string_buf_size_(0),
-    container_limit_(0) {
+public:
+  TCompactProtocolT(std::shared_ptr<Transport_> trans)
+    : TVirtualProtocol<TCompactProtocolT<Transport_> >(trans),
+      trans_(trans.get()),
+      lastFieldId_(0),
+      string_limit_(0),
+      string_buf_(NULL),
+      string_buf_size_(0),
+      container_limit_(0) {
     booleanField_.name = NULL;
     boolValue_.hasBoolValue = false;
   }
 
-  TCompactProtocolT(boost::shared_ptr<Transport_> trans,
+  TCompactProtocolT(std::shared_ptr<Transport_> trans,
                     int32_t string_limit,
-                    int32_t container_limit) :
-    TVirtualProtocol< TCompactProtocolT<Transport_> >(trans),
-    trans_(trans.get()),
-    lastFieldId_(0),
-    string_limit_(string_limit),
-    string_buf_(NULL),
-    string_buf_size_(0),
-    container_limit_(container_limit) {
+                    int32_t container_limit)
+    : TVirtualProtocol<TCompactProtocolT<Transport_> >(trans),
+      trans_(trans.get()),
+      lastFieldId_(0),
+      string_limit_(string_limit),
+      string_buf_(NULL),
+      string_buf_size_(0),
+      container_limit_(container_limit) {
     booleanField_.name = NULL;
     boolValue_.hasBoolValue = false;
   }
 
-  ~TCompactProtocolT() {
-    free(string_buf_);
-  }
-
+  ~TCompactProtocolT() { free(string_buf_); }
 
   /**
    * Writing functions
@@ -114,21 +114,15 @@
 
   uint32_t writeStructEnd();
 
-  uint32_t writeFieldBegin(const char* name,
-                           const TType fieldType,
-                           const int16_t fieldId);
+  uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId);
 
   uint32_t writeFieldStop();
 
-  uint32_t writeListBegin(const TType elemType,
-                          const uint32_t size);
+  uint32_t writeListBegin(const TType elemType, const uint32_t size);
 
-  uint32_t writeSetBegin(const TType elemType,
-                         const uint32_t size);
+  uint32_t writeSetBegin(const TType elemType, const uint32_t size);
 
-  virtual uint32_t writeMapBegin(const TType keyType,
-                                 const TType valType,
-                                 const uint32_t size);
+  virtual uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size);
 
   uint32_t writeBool(const bool value);
 
@@ -156,7 +150,7 @@
   uint32_t writeSetEnd() { return 0; }
   uint32_t writeFieldEnd() { return 0; }
 
- protected:
+protected:
   int32_t writeFieldBeginInternal(const char* name,
                                   const TType fieldType,
                                   const int16_t fieldId,
@@ -168,32 +162,24 @@
   uint32_t i32ToZigzag(const int32_t n);
   inline int8_t getCompactType(const TType ttype);
 
- public:
-  uint32_t readMessageBegin(std::string& name,
-                            TMessageType& messageType,
-                            int32_t& seqid);
+public:
+  uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid);
 
   uint32_t readStructBegin(std::string& name);
 
   uint32_t readStructEnd();
 
-  uint32_t readFieldBegin(std::string& name,
-                          TType& fieldType,
-                          int16_t& fieldId);
+  uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId);
 
-  uint32_t readMapBegin(TType& keyType,
-                        TType& valType,
-                        uint32_t& size);
+  uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size);
 
-  uint32_t readListBegin(TType& elemType,
-                         uint32_t& size);
+  uint32_t readListBegin(TType& elemType, uint32_t& size);
 
-  uint32_t readSetBegin(TType& elemType,
-                        uint32_t& size);
+  uint32_t readSetBegin(TType& elemType, uint32_t& size);
 
   uint32_t readBool(bool& value);
   // Provide the default readBool() implementation for std::vector<bool>
-  using TVirtualProtocol< TCompactProtocolT<Transport_> >::readBool;
+  using TVirtualProtocol<TCompactProtocolT<Transport_> >::readBool;
 
   uint32_t readByte(int8_t& byte);
 
@@ -219,7 +205,7 @@
   uint32_t readListEnd() { return 0; }
   uint32_t readSetEnd() { return 0; }
 
- protected:
+protected:
   uint32_t readVarint32(int32_t& i32);
   uint32_t readVarint64(int64_t& i64);
   int32_t zigzagToI32(uint32_t n);
@@ -241,48 +227,39 @@
  */
 template <class Transport_>
 class TCompactProtocolFactoryT : public TProtocolFactory {
- public:
-  TCompactProtocolFactoryT() :
-    string_limit_(0),
-    container_limit_(0) {}
+public:
+  TCompactProtocolFactoryT() : string_limit_(0), container_limit_(0) {}
 
-  TCompactProtocolFactoryT(int32_t string_limit, int32_t container_limit) :
-    string_limit_(string_limit),
-    container_limit_(container_limit) {}
+  TCompactProtocolFactoryT(int32_t string_limit, int32_t container_limit)
+    : string_limit_(string_limit), container_limit_(container_limit) {}
 
   virtual ~TCompactProtocolFactoryT() {}
 
-  void setStringSizeLimit(int32_t string_limit) {
-    string_limit_ = string_limit;
-  }
+  void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; }
 
-  void setContainerSizeLimit(int32_t container_limit) {
-    container_limit_ = container_limit;
-  }
+  void setContainerSizeLimit(int32_t container_limit) { container_limit_ = container_limit; }
 
-  boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) {
-    boost::shared_ptr<Transport_> specific_trans =
-      boost::dynamic_pointer_cast<Transport_>(trans);
+  std::shared_ptr<TProtocol> getProtocol(std::shared_ptr<TTransport> trans) {
+    std::shared_ptr<Transport_> specific_trans = std::dynamic_pointer_cast<Transport_>(trans);
     TProtocol* prot;
     if (specific_trans) {
-      prot = new TCompactProtocolT<Transport_>(specific_trans, string_limit_,
-                                               container_limit_);
+      prot = new TCompactProtocolT<Transport_>(specific_trans, string_limit_, container_limit_);
     } else {
       prot = new TCompactProtocol(trans, string_limit_, container_limit_);
     }
 
-    return boost::shared_ptr<TProtocol>(prot);
+    return std::shared_ptr<TProtocol>(prot);
   }
 
- private:
+private:
   int32_t string_limit_;
   int32_t container_limit_;
-
 };
 
 typedef TCompactProtocolFactoryT<TTransport> TCompactProtocolFactory;
-
-}}} // apache::thrift::protocol
+}
+}
+} // apache::thrift::protocol
 
 #include <thrift/protocol/TCompactProtocol.tcc>
 
diff --git a/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc b/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc
index 62d6485..8efec6e 100644
--- a/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc
+++ b/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc
@@ -21,6 +21,8 @@
 
 #include <limits>
 
+#include "thrift/config.h"
+
 /*
  * TCompactProtocol::i*ToZigzag depend on the fact that the right shift
  * operator on a signed integer is an arithmetic (sign-extending) shift.
@@ -251,17 +253,17 @@
  */
 template <class Transport_>
 uint32_t TCompactProtocolT<Transport_>::writeDouble(const double dub) {
-  BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
-  BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
+  static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
+  static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
 
   uint64_t bits = bitwise_cast<uint64_t>(dub);
-  bits = htolell(bits);
+  bits = THRIFT_htolell(bits);
   trans_->write((uint8_t*)&bits, 8);
   return 8;
 }
 
 /**
- * Write a string to the wire with a varint size preceeding.
+ * Write a string to the wire with a varint size preceding.
  */
 template <class Transport_>
 uint32_t TCompactProtocolT<Transport_>::writeString(const std::string& str) {
@@ -270,8 +272,15 @@
 
 template <class Transport_>
 uint32_t TCompactProtocolT<Transport_>::writeBinary(const std::string& str) {
-  uint32_t ssize = str.size();
-  uint32_t wsize = writeVarint32(ssize) + ssize;
+  if(str.size() > (std::numeric_limits<uint32_t>::max)())
+    throw TProtocolException(TProtocolException::SIZE_LIMIT);
+  uint32_t ssize = static_cast<uint32_t>(str.size());
+  uint32_t wsize = writeVarint32(ssize) ;
+  // checking ssize + wsize > uint_max, but we don't want to overflow while checking for overflows.
+  // transforming the check to ssize > uint_max - wsize
+  if(ssize > (std::numeric_limits<uint32_t>::max)() - wsize)
+    throw TProtocolException(TProtocolException::SIZE_LIMIT);
+  wsize += ssize;
   trans_->write((uint8_t*)str.data(), ssize);
   return wsize;
 }
@@ -378,7 +387,7 @@
  */
 template <class Transport_>
 uint64_t TCompactProtocolT<Transport_>::i64ToZigzag(const int64_t l) {
-  return (l << 1) ^ (l >> 63);
+  return (static_cast<uint64_t>(l) << 1) ^ (l >> 63);
 }
 
 /**
@@ -387,7 +396,7 @@
  */
 template <class Transport_>
 uint32_t TCompactProtocolT<Transport_>::i32ToZigzag(const int32_t n) {
-  return (n << 1) ^ (n >> 31);
+  return (static_cast<uint32_t>(n) << 1) ^ (n >> 31);
 }
 
 /**
@@ -426,7 +435,7 @@
     throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol version");
   }
 
-  messageType = (TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & 0x03);
+  messageType = (TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
   rsize += readVarint32(seqid);
   rsize += readString(name);
 
@@ -644,15 +653,15 @@
  */
 template <class Transport_>
 uint32_t TCompactProtocolT<Transport_>::readDouble(double& dub) {
-  BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
-  BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
+  static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
+  static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
 
   union {
     uint64_t bits;
     uint8_t b[8];
   } u;
   trans_->readAll(u.b, 8);
-  u.bits = letohll(u.bits);
+  u.bits = THRIFT_letohll(u.bits);
   dub = bitwise_cast<double>(u.bits);
   return 8;
 }
@@ -768,7 +777,7 @@
  */
 template <class Transport_>
 int32_t TCompactProtocolT<Transport_>::zigzagToI32(uint32_t n) {
-  return (n >> 1) ^ -static_cast<int32_t>(n & 1);
+  return (n >> 1) ^ static_cast<uint32_t>(-static_cast<int32_t>(n & 1));
 }
 
 /**
@@ -776,7 +785,7 @@
  */
 template <class Transport_>
 int64_t TCompactProtocolT<Transport_>::zigzagToI64(uint64_t n) {
-  return (n >> 1) ^ -static_cast<int32_t>(n & 1);
+  return (n >> 1) ^ static_cast<uint64_t>(-static_cast<int64_t>(n & 1));
 }
 
 template <class Transport_>
@@ -810,7 +819,6 @@
     default:
       throw TException(std::string("don't know what type: ") + (char)type);
   }
-  return T_STOP;
 }
 
 }}} // apache::thrift::protocol
diff --git a/lib/cpp/src/thrift/protocol/TDebugProtocol.cpp b/lib/cpp/src/thrift/protocol/TDebugProtocol.cpp
index 63ea14d..0e6d4a2 100644
--- a/lib/cpp/src/thrift/protocol/TDebugProtocol.cpp
+++ b/lib/cpp/src/thrift/protocol/TDebugProtocol.cpp
@@ -19,16 +19,14 @@
 
 #include <thrift/protocol/TDebugProtocol.h>
 
+#include <thrift/TToString.h>
 #include <cassert>
 #include <cctype>
 #include <cstdio>
 #include <stdexcept>
-#include <boost/static_assert.hpp>
-#include <boost/lexical_cast.hpp>
 
 using std::string;
 
-
 static string byte_to_hex(const uint8_t byte) {
   char buf[3];
   int ret = std::sprintf(buf, "%02x", (int)byte);
@@ -38,28 +36,46 @@
   return buf;
 }
 
-
-namespace apache { namespace thrift { namespace protocol {
+namespace apache {
+namespace thrift {
+namespace protocol {
 
 string TDebugProtocol::fieldTypeName(TType type) {
   switch (type) {
-    case T_STOP   : return "stop"   ;
-    case T_VOID   : return "void"   ;
-    case T_BOOL   : return "bool"   ;
-    case T_BYTE   : return "byte"   ;
-    case T_I16    : return "i16"    ;
-    case T_I32    : return "i32"    ;
-    case T_U64    : return "u64"    ;
-    case T_I64    : return "i64"    ;
-    case T_DOUBLE : return "double" ;
-    case T_STRING : return "string" ;
-    case T_STRUCT : return "struct" ;
-    case T_MAP    : return "map"    ;
-    case T_SET    : return "set"    ;
-    case T_LIST   : return "list"   ;
-    case T_UTF8   : return "utf8"   ;
-    case T_UTF16  : return "utf16"  ;
-    default: return "unknown";
+  case T_STOP:
+    return "stop";
+  case T_VOID:
+    return "void";
+  case T_BOOL:
+    return "bool";
+  case T_BYTE:
+    return "byte";
+  case T_I16:
+    return "i16";
+  case T_I32:
+    return "i32";
+  case T_U64:
+    return "u64";
+  case T_I64:
+    return "i64";
+  case T_DOUBLE:
+    return "double";
+  case T_STRING:
+    return "string";
+  case T_STRUCT:
+    return "struct";
+  case T_MAP:
+    return "map";
+  case T_SET:
+    return "set";
+  case T_LIST:
+    return "list";
+  case T_UTF8:
+    return "utf8";
+  case T_UTF16:
+    return "utf16";
+  default:
+    return "unknown";
   }
 }
 
@@ -75,19 +91,19 @@
 }
 
 uint32_t TDebugProtocol::writePlain(const string& str) {
-  if(str.length() > (std::numeric_limits<uint32_t>::max)())
+  if (str.length() > (std::numeric_limits<uint32_t>::max)())
     throw TProtocolException(TProtocolException::SIZE_LIMIT);
   trans_->write((uint8_t*)str.data(), static_cast<uint32_t>(str.length()));
   return static_cast<uint32_t>(str.length());
 }
 
 uint32_t TDebugProtocol::writeIndented(const string& str) {
-  if(str.length() > (std::numeric_limits<uint32_t>::max)())
+  if (str.length() > (std::numeric_limits<uint32_t>::max)())
     throw TProtocolException(TProtocolException::SIZE_LIMIT);
-  if(indent_str_.length() > (std::numeric_limits<uint32_t>::max)())
+  if (indent_str_.length() > (std::numeric_limits<uint32_t>::max)())
     throw TProtocolException(TProtocolException::SIZE_LIMIT);
   uint64_t total_len = indent_str_.length() + str.length();
-  if(total_len > (std::numeric_limits<uint32_t>::max)())
+  if (total_len > (std::numeric_limits<uint32_t>::max)())
     throw TProtocolException(TProtocolException::SIZE_LIMIT);
   trans_->write((uint8_t*)indent_str_.data(), static_cast<uint32_t>(indent_str_.length()));
   trans_->write((uint8_t*)str.data(), static_cast<uint32_t>(str.length()));
@@ -98,52 +114,51 @@
   uint32_t size;
 
   switch (write_state_.back()) {
-    case UNINIT:
-      // XXX figure out what to do here.
-      //throw TProtocolException(TProtocolException::INVALID_DATA);
-      //return writeIndented(str);
-      return 0;
-    case STRUCT:
-      return 0;
-    case SET:
-      return writeIndented("");
-    case MAP_KEY:
-      return writeIndented("");
-    case MAP_VALUE:
-      return writePlain(" -> ");
-    case LIST:
-      size = writeIndented(
-          "[" + boost::lexical_cast<string>(list_idx_.back()) + "] = ");
-      list_idx_.back()++;
-      return size;
-    default:
-      throw std::logic_error("Invalid enum value.");
+  case UNINIT:
+    // XXX figure out what to do here.
+    // throw TProtocolException(TProtocolException::INVALID_DATA);
+    // return writeIndented(str);
+    return 0;
+  case STRUCT:
+    return 0;
+  case SET:
+    return writeIndented("");
+  case MAP_KEY:
+    return writeIndented("");
+  case MAP_VALUE:
+    return writePlain(" -> ");
+  case LIST:
+    size = writeIndented("[" + to_string(list_idx_.back()) + "] = ");
+    list_idx_.back()++;
+    return size;
+  default:
+    throw std::logic_error("Invalid enum value.");
   }
 }
 
 uint32_t TDebugProtocol::endItem() {
-  //uint32_t size;
+  // uint32_t size;
 
   switch (write_state_.back()) {
-    case UNINIT:
-      // XXX figure out what to do here.
-      //throw TProtocolException(TProtocolException::INVALID_DATA);
-      //return writeIndented(str);
-      return 0;
-    case STRUCT:
-      return writePlain(",\n");
-    case SET:
-      return writePlain(",\n");
-    case MAP_KEY:
-      write_state_.back() = MAP_VALUE;
-      return 0;
-    case MAP_VALUE:
-      write_state_.back() = MAP_KEY;
-      return writePlain(",\n");
-    case LIST:
-      return writePlain(",\n");
-    default:
-      throw std::logic_error("Invalid enum value.");
+  case UNINIT:
+    // XXX figure out what to do here.
+    // throw TProtocolException(TProtocolException::INVALID_DATA);
+    // return writeIndented(str);
+    return 0;
+  case STRUCT:
+    return writePlain(",\n");
+  case SET:
+    return writePlain(",\n");
+  case MAP_KEY:
+    write_state_.back() = MAP_VALUE;
+    return 0;
+  case MAP_VALUE:
+    write_state_.back() = MAP_KEY;
+    return writePlain(",\n");
+  case LIST:
+    return writePlain(",\n");
+  default:
+    throw std::logic_error("Invalid enum value.");
   }
 }
 
@@ -158,13 +173,21 @@
 uint32_t TDebugProtocol::writeMessageBegin(const std::string& name,
                                            const TMessageType messageType,
                                            const int32_t seqid) {
-  (void) seqid;
+  (void)seqid;
   string mtype;
   switch (messageType) {
-    case T_CALL      : mtype = "call"   ; break;
-    case T_REPLY     : mtype = "reply"  ; break;
-    case T_EXCEPTION : mtype = "exn"    ; break;
-    case T_ONEWAY    : mtype = "oneway" ; break;
+  case T_CALL:
+    mtype = "call";
+    break;
+  case T_REPLY:
+    mtype = "reply";
+    break;
+  case T_EXCEPTION:
+    mtype = "exn";
+    break;
+  case T_ONEWAY:
+    mtype = "oneway";
+    break;
   }
 
   uint32_t size = writeIndented("(" + mtype + ") " + name + "(");
@@ -199,13 +222,11 @@
                                          const TType fieldType,
                                          const int16_t fieldId) {
   // sprintf(id_str, "%02d", fieldId);
-  string id_str = boost::lexical_cast<string>(fieldId);
-  if (id_str.length() == 1) id_str = '0' + id_str;
+  string id_str = to_string(fieldId);
+  if (id_str.length() == 1)
+    id_str = '0' + id_str;
 
-  return writeIndented(
-      id_str + ": " +
-      name + " (" +
-      fieldTypeName(fieldType) + ") = ");
+  return writeIndented(id_str + ": " + name + " (" + fieldTypeName(fieldType) + ") = ");
 }
 
 uint32_t TDebugProtocol::writeFieldEnd() {
@@ -215,7 +236,7 @@
 
 uint32_t TDebugProtocol::writeFieldStop() {
   return 0;
-    //writeIndented("***STOP***\n");
+  // writeIndented("***STOP***\n");
 }
 
 uint32_t TDebugProtocol::writeMapBegin(const TType keyType,
@@ -226,7 +247,7 @@
   bsize += startItem();
   bsize += writePlain(
       "map<" + fieldTypeName(keyType) + "," + fieldTypeName(valType) + ">"
-      "[" + boost::lexical_cast<string>(size) + "] {\n");
+      "[" + to_string(size) + "] {\n");
   indentUp();
   write_state_.push_back(MAP_KEY);
   return bsize;
@@ -241,14 +262,13 @@
   return size;
 }
 
-uint32_t TDebugProtocol::writeListBegin(const TType elemType,
-                                        const uint32_t size) {
+uint32_t TDebugProtocol::writeListBegin(const TType elemType, const uint32_t size) {
   // TODO(dreiss): Optimize short arrays.
   uint32_t bsize = 0;
   bsize += startItem();
   bsize += writePlain(
       "list<" + fieldTypeName(elemType) + ">"
-      "[" + boost::lexical_cast<string>(size) + "] {\n");
+      "[" + to_string(size) + "] {\n");
   indentUp();
   write_state_.push_back(LIST);
   list_idx_.push_back(0);
@@ -265,14 +285,13 @@
   return size;
 }
 
-uint32_t TDebugProtocol::writeSetBegin(const TType elemType,
-                                       const uint32_t size) {
+uint32_t TDebugProtocol::writeSetBegin(const TType elemType, const uint32_t size) {
   // TODO(dreiss): Optimize short sets.
   uint32_t bsize = 0;
   bsize += startItem();
   bsize += writePlain(
       "set<" + fieldTypeName(elemType) + ">"
-      "[" + boost::lexical_cast<string>(size) + "] {\n");
+      "[" + to_string(size) + "] {\n");
   indentUp();
   write_state_.push_back(SET);
   return bsize;
@@ -296,29 +315,28 @@
 }
 
 uint32_t TDebugProtocol::writeI16(const int16_t i16) {
-  return writeItem(boost::lexical_cast<string>(i16));
+  return writeItem(to_string(i16));
 }
 
 uint32_t TDebugProtocol::writeI32(const int32_t i32) {
-  return writeItem(boost::lexical_cast<string>(i32));
+  return writeItem(to_string(i32));
 }
 
 uint32_t TDebugProtocol::writeI64(const int64_t i64) {
-  return writeItem(boost::lexical_cast<string>(i64));
+  return writeItem(to_string(i64));
 }
 
 uint32_t TDebugProtocol::writeDouble(const double dub) {
-  return writeItem(boost::lexical_cast<string>(dub));
+  return writeItem(to_string(dub));
 }
 
-
 uint32_t TDebugProtocol::writeString(const string& str) {
   // XXX Raw/UTF-8?
 
   string to_show = str;
   if (to_show.length() > (string::size_type)string_limit_) {
     to_show = str.substr(0, string_prefix_size_);
-    to_show += "[...](" + boost::lexical_cast<string>(str.length()) + ")";
+    to_show += "[...](" + to_string(str.length()) + ")";
   }
 
   string output = "\"";
@@ -328,20 +346,36 @@
       output += "\\\\";
     } else if (*it == '"') {
       output += "\\\"";
-    } else if (std::isprint(*it)) {
+      // passing characters <0 to std::isprint causes asserts. isprint takes an
+      // int, so we need to be careful of sign extension
+    } else if (std::isprint((unsigned char)*it)) {
       output += *it;
     } else {
       switch (*it) {
-        case '\a': output += "\\a"; break;
-        case '\b': output += "\\b"; break;
-        case '\f': output += "\\f"; break;
-        case '\n': output += "\\n"; break;
-        case '\r': output += "\\r"; break;
-        case '\t': output += "\\t"; break;
-        case '\v': output += "\\v"; break;
-        default:
-          output += "\\x";
-          output += byte_to_hex(*it);
+      case '\a':
+        output += "\\a";
+        break;
+      case '\b':
+        output += "\\b";
+        break;
+      case '\f':
+        output += "\\f";
+        break;
+      case '\n':
+        output += "\\n";
+        break;
+      case '\r':
+        output += "\\r";
+        break;
+      case '\t':
+        output += "\\t";
+        break;
+      case '\v':
+        output += "\\v";
+        break;
+      default:
+        output += "\\x";
+        output += byte_to_hex(*it);
       }
     }
   }
@@ -354,5 +388,6 @@
   // XXX Hex?
   return TDebugProtocol::writeString(str);
 }
-
-}}} // apache::thrift::protocol
+}
+}
+} // apache::thrift::protocol
diff --git a/lib/cpp/src/thrift/protocol/TDebugProtocol.h b/lib/cpp/src/thrift/protocol/TDebugProtocol.h
index f85e691..c079624 100644
--- a/lib/cpp/src/thrift/protocol/TDebugProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TDebugProtocol.h
@@ -22,9 +22,11 @@
 
 #include <thrift/protocol/TVirtualProtocol.h>
 
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
-namespace apache { namespace thrift { namespace protocol {
+namespace apache {
+namespace thrift {
+namespace protocol {
 
 /*
 
@@ -39,44 +41,30 @@
 
 */
 
-
 /**
  * Protocol that prints the payload in a nice human-readable format.
  * Reading from this protocol is not supported.
  *
  */
 class TDebugProtocol : public TVirtualProtocol<TDebugProtocol> {
- private:
-  enum write_state_t
-  { UNINIT
-  , STRUCT
-  , LIST
-  , SET
-  , MAP_KEY
-  , MAP_VALUE
-  };
+private:
+  enum write_state_t { UNINIT, STRUCT, LIST, SET, MAP_KEY, MAP_VALUE };
 
- public:
-  TDebugProtocol(boost::shared_ptr<TTransport> trans)
-    : TVirtualProtocol<TDebugProtocol>(trans)
-    , trans_(trans.get())
-    , string_limit_(DEFAULT_STRING_LIMIT)
-    , string_prefix_size_(DEFAULT_STRING_PREFIX_SIZE)
-  {
+public:
+  TDebugProtocol(std::shared_ptr<TTransport> trans)
+    : TVirtualProtocol<TDebugProtocol>(trans),
+      trans_(trans.get()),
+      string_limit_(DEFAULT_STRING_LIMIT),
+      string_prefix_size_(DEFAULT_STRING_PREFIX_SIZE) {
     write_state_.push_back(UNINIT);
   }
 
   static const int32_t DEFAULT_STRING_LIMIT = 256;
   static const int32_t DEFAULT_STRING_PREFIX_SIZE = 16;
 
-  void setStringSizeLimit(int32_t string_limit) {
-    string_limit_ = string_limit;
-  }
+  void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; }
 
-  void setStringPrefixSize(int32_t string_prefix_size) {
-    string_prefix_size_ = string_prefix_size;
-  }
-
+  void setStringPrefixSize(int32_t string_prefix_size) { string_prefix_size_ = string_prefix_size; }
 
   uint32_t writeMessageBegin(const std::string& name,
                              const TMessageType messageType,
@@ -84,32 +72,25 @@
 
   uint32_t writeMessageEnd();
 
-
   uint32_t writeStructBegin(const char* name);
 
   uint32_t writeStructEnd();
 
-  uint32_t writeFieldBegin(const char* name,
-                           const TType fieldType,
-                           const int16_t fieldId);
+  uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId);
 
   uint32_t writeFieldEnd();
 
   uint32_t writeFieldStop();
 
-  uint32_t writeMapBegin(const TType keyType,
-                         const TType valType,
-                         const uint32_t size);
+  uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size);
 
   uint32_t writeMapEnd();
 
-  uint32_t writeListBegin(const TType elemType,
-                          const uint32_t size);
+  uint32_t writeListBegin(const TType elemType, const uint32_t size);
 
   uint32_t writeListEnd();
 
-  uint32_t writeSetBegin(const TType elemType,
-                         const uint32_t size);
+  uint32_t writeSetBegin(const TType elemType, const uint32_t size);
 
   uint32_t writeSetEnd();
 
@@ -129,8 +110,7 @@
 
   uint32_t writeBinary(const std::string& str);
 
-
- private:
+private:
   void indentUp();
   void indentDown();
   uint32_t writePlain(const std::string& str);
@@ -157,30 +137,30 @@
  * Constructs debug protocol handlers
  */
 class TDebugProtocolFactory : public TProtocolFactory {
- public:
+public:
   TDebugProtocolFactory() {}
   virtual ~TDebugProtocolFactory() {}
 
-  boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) {
-    return boost::shared_ptr<TProtocol>(new TDebugProtocol(trans));
+  std::shared_ptr<TProtocol> getProtocol(std::shared_ptr<TTransport> trans) {
+    return std::shared_ptr<TProtocol>(new TDebugProtocol(trans));
   }
-
 };
-
-}}} // apache::thrift::protocol
-
+}
+}
+} // apache::thrift::protocol
 
 // TODO(dreiss): Move (part of) ThriftDebugString into a .cpp file and remove this.
 #include <thrift/transport/TBufferTransports.h>
 
-namespace apache { namespace thrift {
+namespace apache {
+namespace thrift {
 
-template<typename ThriftStruct>
+template <typename ThriftStruct>
 std::string ThriftDebugString(const ThriftStruct& ts) {
   using namespace apache::thrift::transport;
   using namespace apache::thrift::protocol;
   TMemoryBuffer* buffer = new TMemoryBuffer;
-  boost::shared_ptr<TTransport> trans(buffer);
+  std::shared_ptr<TTransport> trans(buffer);
   TDebugProtocol protocol(trans);
 
   ts.write(&protocol);
@@ -198,7 +178,7 @@
   using namespace apache::thrift::transport;
   using namespace apache::thrift::protocol;
   TMemoryBuffer* buffer = new TMemoryBuffer;
-  boost::shared_ptr<TTransport> trans(buffer);
+  std::shared_ptr<TTransport> trans(buffer);
   TDebugProtocol protocol(trans);
 
   // I am gross!
@@ -218,10 +198,7 @@
   return std::string((char*)buf, (unsigned int)size);
 }
 #endif // 0
-
-}} // apache::thrift
-
+}
+} // apache::thrift
 
 #endif // #ifndef _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_
-
-
diff --git a/lib/cpp/src/thrift/protocol/TDenseProtocol.cpp b/lib/cpp/src/thrift/protocol/TDenseProtocol.cpp
deleted file mode 100644
index 4fbfc13..0000000
--- a/lib/cpp/src/thrift/protocol/TDenseProtocol.cpp
+++ /dev/null
@@ -1,768 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*
-
-IMPLEMENTATION DETAILS
-
-TDenseProtocol was designed to have a smaller serialized form than
-TBinaryProtocol.  This is accomplished using two techniques.  The first is
-variable-length integer encoding.  We use the same technique that the Standard
-MIDI File format uses for "variable-length quantities"
-(http://en.wikipedia.org/wiki/Variable-length_quantity).
-All integers (including i16, but not byte) are first cast to uint64_t,
-then written out as variable-length quantities.  This has the unfortunate side
-effect that all negative numbers require 10 bytes, but negative numbers tend
-to be far less common than positive ones.
-
-The second technique eliminating the field ids used by TBinaryProtocol.  This
-decision required support from the Thrift compiler and also sacrifices some of
-the backward and forward compatibility of TBinaryProtocol.
-
-We considered implementing this technique by generating separate readers and
-writers for the dense protocol (this is how Pillar, Thrift's predecessor,
-worked), but this idea had a few problems:
-- Our abstractions go out the window.
-- We would have to maintain a second code generator.
-- Preserving compatibility with old versions of the structures would be a
-  nightmare.
-
-Therefore, we chose an alternate implementation that stored the description of
-the data neither in the data itself (like TBinaryProtocol) nor in the
-serialization code (like Pillar), but instead in a separate data structure,
-called a TypeSpec.  TypeSpecs are generated by the Thrift compiler
-(specifically in the t_cpp_generator), and their structure should be
-documented there (TODO(dreiss): s/should be/is/).
-
-We maintain a stack of TypeSpecs within the protocol so it knows where the
-generated code is in the reading/writing process.  For example, if we are
-writing an i32 contained in a struct bar, contained in a struct foo, then the
-stack would look like: TOP , i32 , struct bar , struct foo , BOTTOM.
-The following invariant: whenever we are about to read/write an object
-(structBegin, containerBegin, or a scalar), the TypeSpec on the top of the
-stack must match the type being read/written.  The main reasons that this
-invariant must be maintained is that if we ever start reading a structure, we
-must have its exact TypeSpec in order to pass the right tags to the
-deserializer.
-
-We use the following strategies for maintaining this invariant:
-
-- For structures, we have a separate stack of indexes, one for each structure
-  on the TypeSpec stack.  These are indexes into the list of fields in the
-  structure's TypeSpec.  When we {read,write}FieldBegin, we push on the
-  TypeSpec for the field.
-- When we begin writing a list or set, we push on the TypeSpec for the
-  element type.
-- For maps, we have a separate stack of booleans, one for each map on the
-  TypeSpec stack.  The boolean is true if we are writing the key for that
-  map, and false if we are writing the value.  Maps are the trickiest case
-  because the generated code does not call any protocol method between
-  the key and the value.  As a result, we potentially have to switch
-  between map key state and map value state after reading/writing any object.
-- This job is handled by the stateTransition method.  It is called after
-  reading/writing every object.  It pops the current TypeSpec off the stack,
-  then optionally pushes a new one on, depending on what the next TypeSpec is.
-  If it is a struct, the job is left to the next writeFieldBegin.  If it is a
-  set or list, the just-popped typespec is pushed back on.  If it is a map,
-  the top of the key/value stack is toggled, and the appropriate TypeSpec
-  is pushed.
-
-Optional fields are a little tricky also.  We write a zero byte if they are
-absent and prefix them with an 0x01 byte if they are present
-*/
-
-#define __STDC_LIMIT_MACROS
-#include <stdint.h>
-#include <thrift/protocol/TDenseProtocol.h>
-#include <thrift/TReflectionLocal.h>
-
-// Leaving this on for now.  Disabling it will turn off asserts, which should
-// give a performance boost.  When we have *really* thorough test cases,
-// we should drop this.
-#define DEBUG_TDENSEPROTOCOL
-
-// NOTE: Assertions should *only* be used to detect bugs in code,
-//       either in TDenseProtocol itself, or in code using it.
-//       (For example, using the wrong TypeSpec.)
-//       Invalid data should NEVER cause an assertion failure,
-//       no matter how grossly corrupted, nor how ingeniously crafted.
-#ifdef DEBUG_TDENSEPROTOCOL
-#undef NDEBUG
-#else
-#define NDEBUG
-#endif
-#include <cassert>
-
-using std::string;
-
-#ifdef __GNUC__
-#define UNLIKELY(val) (__builtin_expect((val), 0))
-#else
-#define UNLIKELY(val) (val)
-#endif
-
-namespace apache { namespace thrift { namespace protocol {
-
-const int TDenseProtocol::FP_PREFIX_LEN =
-  apache::thrift::reflection::local::FP_PREFIX_LEN;
-
-// Top TypeSpec.  TypeSpec of the structure being encoded.
-#define TTS  (ts_stack_.back())  // type = TypeSpec*
-// InDeX.  Index into TTS of the current/next field to encode.
-#define IDX (idx_stack_.back())  // type = int
-// Field TypeSpec.  TypeSpec of the current/next field to encode.
-#define FTS (TTS->tstruct.specs[IDX])  // type = TypeSpec*
-// Field MeTa.  Metadata of the current/next field to encode.
-#define FMT (TTS->tstruct.metas[IDX])  // type = FieldMeta
-// SubType 1/2.  TypeSpec of the first/second subtype of this container.
-#define ST1 (TTS->tcontainer.subtype1)
-#define ST2 (TTS->tcontainer.subtype2)
-
-
-/**
- * Checks that @c ttype is indeed the ttype that we should be writing,
- * according to our typespec.  Aborts if the test fails and debugging in on.
- */
-inline void TDenseProtocol::checkTType(const TType ttype) {
-  assert(!ts_stack_.empty());
-  assert(TTS->ttype == ttype);
-}
-
-/**
- * Makes sure that the TypeSpec stack is correct for the next object.
- * See top-of-file comments.
- */
-inline void TDenseProtocol::stateTransition() {
-  TypeSpec* old_tts = ts_stack_.back();
-  ts_stack_.pop_back();
-
-  // If this is the end of the top-level write, we should have just popped
-  // the TypeSpec passed to the constructor.
-  if (ts_stack_.empty()) {
-    assert(old_tts = type_spec_);
-    return;
-  }
-
-  switch (TTS->ttype) {
-
-    case T_STRUCT:
-      assert(old_tts == FTS);
-      break;
-
-    case T_LIST:
-    case T_SET:
-      assert(old_tts == ST1);
-      ts_stack_.push_back(old_tts);
-      break;
-
-    case T_MAP:
-      assert(old_tts == (mkv_stack_.back() ? ST1 : ST2));
-      mkv_stack_.back() = !mkv_stack_.back();
-      ts_stack_.push_back(mkv_stack_.back() ? ST1 : ST2);
-      break;
-
-    default:
-      assert(!"Invalid TType in stateTransition.");
-      break;
-
-  }
-}
-
-
-/*
- * Variable-length quantity functions.
- */
-
-inline uint32_t TDenseProtocol::vlqRead(uint64_t& vlq) {
-  uint32_t used = 0;
-  uint64_t val = 0;
-  uint8_t buf[10];  // 64 bits / (7 bits/byte) = 10 bytes.
-  uint32_t buf_size = sizeof(buf);
-  const uint8_t* borrowed = trans_->borrow(buf, &buf_size);
-
-  // Fast path.  TODO(dreiss): Make it faster.
-  if (borrowed != NULL) {
-    while (true) {
-      uint8_t byte = borrowed[used];
-      used++;
-      val = (val << 7) | (byte & 0x7f);
-      if (!(byte & 0x80)) {
-        vlq = val;
-        trans_->consume(used);
-        return used;
-      }
-      // Have to check for invalid data so we don't crash.
-      if (UNLIKELY(used == sizeof(buf))) {
-        resetState();
-        throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
-      }
-    }
-  }
-
-  // Slow path.
-  else {
-    while (true) {
-      uint8_t byte;
-      used += trans_->readAll(&byte, 1);
-      val = (val << 7) | (byte & 0x7f);
-      if (!(byte & 0x80)) {
-        vlq = val;
-        return used;
-      }
-      // Might as well check for invalid data on the slow path too.
-      if (UNLIKELY(used >= sizeof(buf))) {
-        resetState();
-        throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
-      }
-    }
-  }
-}
-
-inline uint32_t TDenseProtocol::vlqWrite(uint64_t vlq) {
-  uint8_t buf[10];  // 64 bits / (7 bits/byte) = 10 bytes.
-  int32_t pos = sizeof(buf) - 1;
-
-  // Write the thing from back to front.
-  buf[pos] = vlq & 0x7f;
-  vlq >>= 7;
-  pos--;
-
-  while (vlq > 0) {
-    assert(pos >= 0);
-    buf[pos] = static_cast<uint8_t>(vlq | 0x80);
-    vlq >>= 7;
-    pos--;
-  }
-
-  // Back up one step before writing.
-  pos++;
-
-  trans_->write(buf+pos, static_cast<uint32_t>(sizeof(buf) - pos));
-  return static_cast<uint32_t>(sizeof(buf) - pos);
-}
-
-
-
-/*
- * Writing functions.
- */
-
-uint32_t TDenseProtocol::writeMessageBegin(const std::string& name,
-                                           const TMessageType messageType,
-                                           const int32_t seqid) {
-  throw TException("TDenseProtocol doesn't work with messages (yet).");
-
-  int32_t version = (VERSION_2) | ((int32_t)messageType);
-  uint32_t wsize = 0;
-  wsize += subWriteI32(version);
-  wsize += subWriteString(name);
-  wsize += subWriteI32(seqid);
-  return wsize;
-}
-
-uint32_t TDenseProtocol::writeMessageEnd() {
-  return 0;
-}
-
-uint32_t TDenseProtocol::writeStructBegin(const char* name) {
-  (void) name;
-  uint32_t xfer = 0;
-
-  // The TypeSpec stack should be empty if this is the top-level read/write.
-  // If it is, we push the TypeSpec passed to the constructor.
-  if (ts_stack_.empty()) {
-    assert(standalone_);
-
-    if (type_spec_ == NULL) {
-      resetState();
-      throw TException("TDenseProtocol: No type specified.");
-    } else {
-      assert(type_spec_->ttype == T_STRUCT);
-      ts_stack_.push_back(type_spec_);
-      // Write out a prefix of the structure fingerprint.
-      trans_->write(type_spec_->fp_prefix, FP_PREFIX_LEN);
-      xfer += FP_PREFIX_LEN;
-    }
-  }
-
-  // We need a new field index for this structure.
-  idx_stack_.push_back(0);
-  return 0;
-}
-
-uint32_t TDenseProtocol::writeStructEnd() {
-  idx_stack_.pop_back();
-  stateTransition();
-  return 0;
-}
-
-uint32_t TDenseProtocol::writeFieldBegin(const char* name,
-                                         const TType fieldType,
-                                         const int16_t fieldId) {
-  (void) name;
-  uint32_t xfer = 0;
-
-  // Skip over optional fields.
-  while (FMT.tag != fieldId) {
-    // TODO(dreiss): Old meta here.
-    assert(FTS->ttype != T_STOP);
-    assert(FMT.is_optional);
-    // Write a zero byte so the reader can skip it.
-    xfer += subWriteBool(false);
-    // And advance to the next field.
-    IDX++;
-  }
-
-  // TODO(dreiss): give a better exception.
-  assert(FTS->ttype == fieldType);
-
-  if (FMT.is_optional) {
-    subWriteBool(true);
-    xfer += 1;
-  }
-
-  // writeFieldStop shares all lot of logic up to this point.
-  // Instead of replicating it all, we just call this method from that one
-  // and use a gross special case here.
-  if (UNLIKELY(FTS->ttype != T_STOP)) {
-    // For normal fields, push the TypeSpec that we're about to use.
-    ts_stack_.push_back(FTS);
-  }
-  return xfer;
-}
-
-uint32_t TDenseProtocol::writeFieldEnd() {
-  // Just move on to the next field.
-  IDX++;
-  return 0;
-}
-
-uint32_t TDenseProtocol::writeFieldStop() {
-  return TDenseProtocol::writeFieldBegin("", T_STOP, 0);
-}
-
-uint32_t TDenseProtocol::writeMapBegin(const TType keyType,
-                                       const TType valType,
-                                       const uint32_t size) {
-  checkTType(T_MAP);
-
-  assert(keyType == ST1->ttype);
-  assert(valType == ST2->ttype);
-
-  ts_stack_.push_back(ST1);
-  mkv_stack_.push_back(true);
-
-  return subWriteI32((int32_t)size);
-}
-
-uint32_t TDenseProtocol::writeMapEnd() {
-  // Pop off the value type, as well as our entry in the map key/value stack.
-  // stateTransition takes care of popping off our TypeSpec.
-  ts_stack_.pop_back();
-  mkv_stack_.pop_back();
-  stateTransition();
-  return 0;
-}
-
-uint32_t TDenseProtocol::writeListBegin(const TType elemType,
-                                        const uint32_t size) {
-  checkTType(T_LIST);
-
-  assert(elemType == ST1->ttype);
-  ts_stack_.push_back(ST1);
-  return subWriteI32((int32_t)size);
-}
-
-uint32_t TDenseProtocol::writeListEnd() {
-  // Pop off the element type.  stateTransition takes care of popping off ours.
-  ts_stack_.pop_back();
-  stateTransition();
-  return 0;
-}
-
-uint32_t TDenseProtocol::writeSetBegin(const TType elemType,
-                                       const uint32_t size) {
-  checkTType(T_SET);
-
-  assert(elemType == ST1->ttype);
-  ts_stack_.push_back(ST1);
-  return subWriteI32((int32_t)size);
-}
-
-uint32_t TDenseProtocol::writeSetEnd() {
-  // Pop off the element type.  stateTransition takes care of popping off ours.
-  ts_stack_.pop_back();
-  stateTransition();
-  return 0;
-}
-
-uint32_t TDenseProtocol::writeBool(const bool value) {
-  checkTType(T_BOOL);
-  stateTransition();
-  return TBinaryProtocol::writeBool(value);
-}
-
-uint32_t TDenseProtocol::writeByte(const int8_t byte) {
-  checkTType(T_BYTE);
-  stateTransition();
-  return TBinaryProtocol::writeByte(byte);
-}
-
-uint32_t TDenseProtocol::writeI16(const int16_t i16) {
-  checkTType(T_I16);
-  stateTransition();
-  return vlqWrite(i16);
-}
-
-uint32_t TDenseProtocol::writeI32(const int32_t i32) {
-  checkTType(T_I32);
-  stateTransition();
-  return vlqWrite(i32);
-}
-
-uint32_t TDenseProtocol::writeI64(const int64_t i64) {
-  checkTType(T_I64);
-  stateTransition();
-  return vlqWrite(i64);
-}
-
-uint32_t TDenseProtocol::writeDouble(const double dub) {
-  checkTType(T_DOUBLE);
-  stateTransition();
-  return TBinaryProtocol::writeDouble(dub);
-}
-
-uint32_t TDenseProtocol::writeString(const std::string& str) {
-  checkTType(T_STRING);
-  stateTransition();
-  return subWriteString(str);
-}
-
-uint32_t TDenseProtocol::writeBinary(const std::string& str) {
-  return TDenseProtocol::writeString(str);
-}
-
-inline uint32_t TDenseProtocol::subWriteI32(const int32_t i32) {
-  return vlqWrite(i32);
-}
-
-uint32_t TDenseProtocol::subWriteString(const std::string& str) {
-  if(str.size() > static_cast<size_t>((std::numeric_limits<int32_t>::max)()))
-    throw TProtocolException(TProtocolException::SIZE_LIMIT);
-  uint32_t size = static_cast<uint32_t>(str.size());
-  uint32_t xfer = subWriteI32((int32_t)size);
-  if (size > 0) {
-    trans_->write((uint8_t*)str.data(), size);
-  }
-  return xfer + size;
-}
-
-
-
-/*
- * Reading functions
- *
- * These have a lot of the same logic as the writing functions, so if
- * something is confusing, look for comments in the corresponding writer.
- */
-
-uint32_t TDenseProtocol::readMessageBegin(std::string& name,
-                                          TMessageType& messageType,
-                                          int32_t& seqid) {
-  throw TException("TDenseProtocol doesn't work with messages (yet).");
-
-  uint32_t xfer = 0;
-  int32_t sz;
-  xfer += subReadI32(sz);
-
-  if (sz < 0) {
-    // Check for correct version number
-    int32_t version = sz & VERSION_MASK;
-    if (version != VERSION_2) {
-      throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
-    }
-    messageType = (TMessageType)(sz & 0x000000ff);
-    xfer += subReadString(name);
-    xfer += subReadI32(seqid);
-  } else {
-    throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
-  }
-  return xfer;
-}
-
-uint32_t TDenseProtocol::readMessageEnd() {
-  return 0;
-}
-
-uint32_t TDenseProtocol::readStructBegin(string& name) {
-  (void) name;
-  uint32_t xfer = 0;
-
-  if (ts_stack_.empty()) {
-    assert(standalone_);
-
-    if (type_spec_ == NULL) {
-      resetState();
-      throw TException("TDenseProtocol: No type specified.");
-    } else {
-      assert(type_spec_->ttype == T_STRUCT);
-      ts_stack_.push_back(type_spec_);
-
-      // Check the fingerprint prefix.
-      uint8_t buf[FP_PREFIX_LEN];
-      xfer += trans_->read(buf, FP_PREFIX_LEN);
-      if (std::memcmp(buf, type_spec_->fp_prefix, FP_PREFIX_LEN) != 0) {
-        resetState();
-        throw TProtocolException(TProtocolException::INVALID_DATA,
-            "Fingerprint in data does not match type_spec.");
-      }
-    }
-  }
-
-  // We need a new field index for this structure.
-  idx_stack_.push_back(0);
-  return 0;
-}
-
-uint32_t TDenseProtocol::readStructEnd() {
-  idx_stack_.pop_back();
-  stateTransition();
-  return 0;
-}
-
-uint32_t TDenseProtocol::readFieldBegin(string& name,
-                                        TType& fieldType,
-                                        int16_t& fieldId) {
-  (void) name;
-  uint32_t xfer = 0;
-
-  // For optional fields, check to see if they are there.
-  while (FMT.is_optional) {
-    bool is_present;
-    xfer += subReadBool(is_present);
-    if (is_present) {
-      break;
-    }
-    IDX++;
-  }
-
-  // Once we hit a mandatory field, or an optional field that is present,
-  // we know that FMT and FTS point to the appropriate field.
-
-  fieldId   = FMT.tag;
-  fieldType = FTS->ttype;
-
-  // Normally, we push the TypeSpec that we are about to read,
-  // but no reading is done for T_STOP.
-  if (FTS->ttype != T_STOP) {
-    ts_stack_.push_back(FTS);
-  }
-  return xfer;
-}
-
-uint32_t TDenseProtocol::readFieldEnd() {
-  IDX++;
-  return 0;
-}
-
-uint32_t TDenseProtocol::readMapBegin(TType& keyType,
-                                      TType& valType,
-                                      uint32_t& size) {
-  checkTType(T_MAP);
-
-  uint32_t xfer = 0;
-  int32_t sizei;
-  xfer += subReadI32(sizei);
-  if (sizei < 0) {
-    resetState();
-    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
-  } else if (container_limit_ && sizei > container_limit_) {
-    resetState();
-    throw TProtocolException(TProtocolException::SIZE_LIMIT);
-  }
-  size = (uint32_t)sizei;
-
-  keyType = ST1->ttype;
-  valType = ST2->ttype;
-
-  ts_stack_.push_back(ST1);
-  mkv_stack_.push_back(true);
-
-  return xfer;
-}
-
-uint32_t TDenseProtocol::readMapEnd() {
-  ts_stack_.pop_back();
-  mkv_stack_.pop_back();
-  stateTransition();
-  return 0;
-}
-
-uint32_t TDenseProtocol::readListBegin(TType& elemType,
-                                       uint32_t& size) {
-  checkTType(T_LIST);
-
-  uint32_t xfer = 0;
-  int32_t sizei;
-  xfer += subReadI32(sizei);
-  if (sizei < 0) {
-    resetState();
-    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
-  } else if (container_limit_ && sizei > container_limit_) {
-    resetState();
-    throw TProtocolException(TProtocolException::SIZE_LIMIT);
-  }
-  size = (uint32_t)sizei;
-
-  elemType = ST1->ttype;
-
-  ts_stack_.push_back(ST1);
-
-  return xfer;
-}
-
-uint32_t TDenseProtocol::readListEnd() {
-  ts_stack_.pop_back();
-  stateTransition();
-  return 0;
-}
-
-uint32_t TDenseProtocol::readSetBegin(TType& elemType,
-                                      uint32_t& size) {
-  checkTType(T_SET);
-
-  uint32_t xfer = 0;
-  int32_t sizei;
-  xfer += subReadI32(sizei);
-  if (sizei < 0) {
-    resetState();
-    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
-  } else if (container_limit_ && sizei > container_limit_) {
-    resetState();
-    throw TProtocolException(TProtocolException::SIZE_LIMIT);
-  }
-  size = (uint32_t)sizei;
-
-  elemType = ST1->ttype;
-
-  ts_stack_.push_back(ST1);
-
-  return xfer;
-}
-
-uint32_t TDenseProtocol::readSetEnd() {
-  ts_stack_.pop_back();
-  stateTransition();
-  return 0;
-}
-
-uint32_t TDenseProtocol::readBool(bool& value) {
-  checkTType(T_BOOL);
-  stateTransition();
-  return TBinaryProtocol::readBool(value);
-}
-
-uint32_t TDenseProtocol::readByte(int8_t& byte) {
-  checkTType(T_BYTE);
-  stateTransition();
-  return TBinaryProtocol::readByte(byte);
-}
-
-uint32_t TDenseProtocol::readI16(int16_t& i16) {
-  checkTType(T_I16);
-  stateTransition();
-  uint64_t u64;
-  uint32_t rv = vlqRead(u64);
-  int64_t val = (int64_t)u64;
-  if (UNLIKELY(val > INT16_MAX || val < INT16_MIN)) {
-    resetState();
-    throw TProtocolException(TProtocolException::INVALID_DATA,
-                             "i16 out of range.");
-  }
-  i16 = (int16_t)val;
-  return rv;
-}
-
-uint32_t TDenseProtocol::readI32(int32_t& i32) {
-  checkTType(T_I32);
-  stateTransition();
-  uint64_t u64;
-  uint32_t rv = vlqRead(u64);
-  int64_t val = (int64_t)u64;
-  if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
-    resetState();
-    throw TProtocolException(TProtocolException::INVALID_DATA,
-                             "i32 out of range.");
-  }
-  i32 = (int32_t)val;
-  return rv;
-}
-
-uint32_t TDenseProtocol::readI64(int64_t& i64) {
-  checkTType(T_I64);
-  stateTransition();
-  uint64_t u64;
-  uint32_t rv = vlqRead(u64);
-  int64_t val = (int64_t)u64;
-  if (UNLIKELY(val > INT64_MAX || val < INT64_MIN)) {
-    resetState();
-    throw TProtocolException(TProtocolException::INVALID_DATA,
-                             "i64 out of range.");
-  }
-  i64 = (int64_t)val;
-  return rv;
-}
-
-uint32_t TDenseProtocol::readDouble(double& dub) {
-  checkTType(T_DOUBLE);
-  stateTransition();
-  return TBinaryProtocol::readDouble(dub);
-}
-
-uint32_t TDenseProtocol::readString(std::string& str) {
-  checkTType(T_STRING);
-  stateTransition();
-  return subReadString(str);
-}
-
-uint32_t TDenseProtocol::readBinary(std::string& str) {
-  return TDenseProtocol::readString(str);
-}
-
-uint32_t TDenseProtocol::subReadI32(int32_t& i32) {
-  uint64_t u64;
-  uint32_t rv = vlqRead(u64);
-  int64_t val = (int64_t)u64;
-  if (UNLIKELY(val > INT32_MAX || val < INT32_MIN)) {
-    resetState();
-    throw TProtocolException(TProtocolException::INVALID_DATA,
-                             "i32 out of range.");
-  }
-  i32 = (int32_t)val;
-  return rv;
-}
-
-uint32_t TDenseProtocol::subReadString(std::string& str) {
-  uint32_t xfer;
-  int32_t size;
-  xfer = subReadI32(size);
-  return xfer + readStringBody(str, size);
-}
-
-}}} // apache::thrift::protocol
diff --git a/lib/cpp/src/thrift/protocol/TDenseProtocol.h b/lib/cpp/src/thrift/protocol/TDenseProtocol.h
deleted file mode 100644
index 4808d79..0000000
--- a/lib/cpp/src/thrift/protocol/TDenseProtocol.h
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef _THRIFT_PROTOCOL_TDENSEPROTOCOL_H_
-#define _THRIFT_PROTOCOL_TDENSEPROTOCOL_H_ 1
-
-#include <thrift/protocol/TBinaryProtocol.h>
-
-namespace apache { namespace thrift { namespace protocol {
-
-/**
- * !!!WARNING!!!
- * This class is still highly experimental.  Incompatible changes
- * WILL be made to it without notice.  DO NOT USE IT YET unless
- * you are coordinating your testing with the author.
- *
- * The dense protocol is designed to use as little space as possible.
- *
- * There are two types of dense protocol instances.  Standalone instances
- * are not used for RPC and just encoded and decode structures of
- * a predetermined type.  Non-standalone instances are used for RPC.
- * Currently, only standalone instances exist.
- *
- * To use a standalone dense protocol object, you must set the type_spec
- * property (either in the constructor, or with setTypeSpec) to the local
- * reflection TypeSpec of the structures you will write to (or read from) the
- * protocol instance.
- *
- * BEST PRACTICES:
- * - Never use optional for primitives or containers.
- * - Only use optional for structures if they are very big and very rarely set.
- * - All integers are variable-length, so you can use i64 without bloating.
- * - NEVER EVER change the struct definitions IN ANY WAY without either
- *   changing your cache keys or talking to dreiss.
- *
- * TODO(dreiss): New class write with old meta.
- *
- * We override all of TBinaryProtocol's methods.
- * We inherit so that we can can explicitly call TBPs's primitive-writing
- * methods within our versions.
- *
- */
-class TDenseProtocol
-  : public TVirtualProtocol<TDenseProtocol, TBinaryProtocol> {
- protected:
-  static const int32_t VERSION_MASK = ((int32_t)0xffff0000);
-  // VERSION_1 (0x80010000)  is taken by TBinaryProtocol.
-  static const int32_t VERSION_2 = ((int32_t)0x80020000);
-
- public:
-  typedef apache::thrift::reflection::local::TypeSpec TypeSpec;
-  static const int FP_PREFIX_LEN;
-
-  /**
-   * @param tran       The transport to use.
-   * @param type_spec  The TypeSpec of the structures using this protocol.
-   */
-  TDenseProtocol(boost::shared_ptr<TTransport> trans,
-                 TypeSpec* type_spec = NULL) :
-    TVirtualProtocol<TDenseProtocol, TBinaryProtocol>(trans),
-    type_spec_(type_spec),
-    standalone_(true)
-  {}
-
-  void setTypeSpec(TypeSpec* type_spec) {
-    type_spec_ = type_spec;
-  }
-  TypeSpec* getTypeSpec() {
-    return type_spec_;
-  }
-
-
-  /*
-   * Writing functions.
-   */
-
-  uint32_t writeMessageBegin(const std::string& name,
-                             const TMessageType messageType,
-                             const int32_t seqid);
-
-  uint32_t writeMessageEnd();
-
-
-  uint32_t writeStructBegin(const char* name);
-
-  uint32_t writeStructEnd();
-
-  uint32_t writeFieldBegin(const char* name,
-                           const TType fieldType,
-                           const int16_t fieldId);
-
-  uint32_t writeFieldEnd();
-
-  uint32_t writeFieldStop();
-
-  uint32_t writeMapBegin(const TType keyType,
-                         const TType valType,
-                         const uint32_t size);
-
-  uint32_t writeMapEnd();
-
-  uint32_t writeListBegin(const TType elemType, const uint32_t size);
-
-  uint32_t writeListEnd();
-
-  uint32_t writeSetBegin(const TType elemType, const uint32_t size);
-
-  uint32_t writeSetEnd();
-
-  uint32_t writeBool(const bool value);
-
-  uint32_t writeByte(const int8_t byte);
-
-  uint32_t writeI16(const int16_t i16);
-
-  uint32_t writeI32(const int32_t i32);
-
-  uint32_t writeI64(const int64_t i64);
-
-  uint32_t writeDouble(const double dub);
-
-  uint32_t writeString(const std::string& str);
-
-  uint32_t writeBinary(const std::string& str);
-
-
-  /*
-   * Helper writing functions (don't do state transitions).
-   */
-  inline uint32_t subWriteI32(const int32_t i32);
-
-  inline uint32_t subWriteString(const std::string& str);
-
-  uint32_t subWriteBool(const bool value) {
-    return TBinaryProtocol::writeBool(value);
-  }
-
-
-  /*
-   * Reading functions
-   */
-
-  uint32_t readMessageBegin(std::string& name,
-                            TMessageType& messageType,
-                            int32_t& seqid);
-
-  uint32_t readMessageEnd();
-
-  uint32_t readStructBegin(std::string& name);
-
-  uint32_t readStructEnd();
-
-  uint32_t readFieldBegin(std::string& name,
-                          TType& fieldType,
-                          int16_t& fieldId);
-
-  uint32_t readFieldEnd();
-
-  uint32_t readMapBegin(TType& keyType,
-                        TType& valType,
-                        uint32_t& size);
-
-  uint32_t readMapEnd();
-
-  uint32_t readListBegin(TType& elemType,
-                         uint32_t& size);
-
-  uint32_t readListEnd();
-
-  uint32_t readSetBegin(TType& elemType,
-                        uint32_t& size);
-
-  uint32_t readSetEnd();
-
-  uint32_t readBool(bool& value);
-  // Provide the default readBool() implementation for std::vector<bool>
-  using TVirtualProtocol<TDenseProtocol, TBinaryProtocol>::readBool;
-
-  uint32_t readByte(int8_t& byte);
-
-  uint32_t readI16(int16_t& i16);
-
-  uint32_t readI32(int32_t& i32);
-
-  uint32_t readI64(int64_t& i64);
-
-  uint32_t readDouble(double& dub);
-
-  uint32_t readString(std::string& str);
-
-  uint32_t readBinary(std::string& str);
-
-  /*
-   * Helper reading functions (don't do state transitions).
-   */
-  inline uint32_t subReadI32(int32_t& i32);
-
-  inline uint32_t subReadString(std::string& str);
-
-  uint32_t subReadBool(bool& value) {
-    return TBinaryProtocol::readBool(value);
-  }
-
-
- private:
-
-  // Implementation functions, documented in the .cpp.
-  inline void checkTType(const TType ttype);
-  inline void stateTransition();
-
-  // Read and write variable-length integers.
-  // Uses the same technique as the MIDI file format.
-  inline uint32_t vlqRead(uint64_t& vlq);
-  inline uint32_t vlqWrite(uint64_t vlq);
-
-  // Called before throwing an exception to make the object reusable.
-  void resetState() {
-    ts_stack_.clear();
-    idx_stack_.clear();
-    mkv_stack_.clear();
-  }
-
-  // TypeSpec of the top-level structure to write,
-  // for standalone protocol objects.
-  TypeSpec* type_spec_;
-
-  std::vector<TypeSpec*> ts_stack_;   // TypeSpec stack.
-  std::vector<int>       idx_stack_;  // InDeX stack.
-  std::vector<bool>      mkv_stack_;  // Map Key/Vlue stack.
-                                      // True = key, False = value.
-
-  // True iff this is a standalone instance (no RPC).
-  bool standalone_;
-};
-
-}}} // apache::thrift::protocol
-
-#endif // #ifndef _THRIFT_PROTOCOL_TDENSEPROTOCOL_H_
diff --git a/lib/cpp/src/thrift/protocol/THeaderProtocol.cpp b/lib/cpp/src/thrift/protocol/THeaderProtocol.cpp
new file mode 100644
index 0000000..6242e30
--- /dev/null
+++ b/lib/cpp/src/thrift/protocol/THeaderProtocol.cpp
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ */
+#ifndef THRIFT_PROTOCOL_THEADERPROTOCOL_CPP_
+#define THRIFT_PROTOCOL_THEADERPROTOCOL_CPP_ 1
+
+#include <thrift/protocol/THeaderProtocol.h>
+#include <thrift/protocol/TCompactProtocol.h>
+#include <thrift/protocol/TBinaryProtocol.h>
+#include <thrift/TApplicationException.h>
+
+#include <limits>
+
+#include <memory>
+
+namespace apache {
+namespace thrift {
+namespace protocol {
+
+void THeaderProtocol::resetProtocol() {
+  if (proto_ && protoId_ == trans_->getProtocolId()) {
+    return;
+  }
+
+  protoId_ = trans_->getProtocolId();
+
+  switch (protoId_) {
+  case T_BINARY_PROTOCOL:
+    proto_ = std::make_shared<TBinaryProtocolT<THeaderTransport> >(trans_);
+    break;
+
+  case T_COMPACT_PROTOCOL:
+    proto_ = std::make_shared<TCompactProtocolT<THeaderTransport> >(trans_);
+    break;
+
+  default:
+    throw TApplicationException(TApplicationException::INVALID_PROTOCOL,
+                                "Unknown protocol requested");
+  }
+}
+
+uint32_t THeaderProtocol::writeMessageBegin(const std::string& name,
+                                            const TMessageType messageType,
+                                            const int32_t seqId) {
+  resetProtocol(); // Reset in case we changed protocols
+  trans_->setSequenceNumber(seqId);
+  return proto_->writeMessageBegin(name, messageType, seqId);
+}
+
+uint32_t THeaderProtocol::writeMessageEnd() {
+  return proto_->writeMessageEnd();
+}
+
+uint32_t THeaderProtocol::writeStructBegin(const char* name) {
+  return proto_->writeStructBegin(name);
+}
+
+uint32_t THeaderProtocol::writeStructEnd() {
+  return proto_->writeStructEnd();
+}
+
+uint32_t THeaderProtocol::writeFieldBegin(const char* name,
+                                          const TType fieldType,
+                                          const int16_t fieldId) {
+  return proto_->writeFieldBegin(name, fieldType, fieldId);
+}
+
+uint32_t THeaderProtocol::writeFieldEnd() {
+  return proto_->writeFieldEnd();
+}
+
+uint32_t THeaderProtocol::writeFieldStop() {
+  return proto_->writeFieldStop();
+}
+
+uint32_t THeaderProtocol::writeMapBegin(const TType keyType,
+                                        const TType valType,
+                                        const uint32_t size) {
+  return proto_->writeMapBegin(keyType, valType, size);
+}
+
+uint32_t THeaderProtocol::writeMapEnd() {
+  return proto_->writeMapEnd();
+}
+
+uint32_t THeaderProtocol::writeListBegin(const TType elemType, const uint32_t size) {
+  return proto_->writeListBegin(elemType, size);
+}
+
+uint32_t THeaderProtocol::writeListEnd() {
+  return proto_->writeListEnd();
+}
+
+uint32_t THeaderProtocol::writeSetBegin(const TType elemType, const uint32_t size) {
+  return proto_->writeSetBegin(elemType, size);
+}
+
+uint32_t THeaderProtocol::writeSetEnd() {
+  return proto_->writeSetEnd();
+}
+
+uint32_t THeaderProtocol::writeBool(const bool value) {
+  return proto_->writeBool(value);
+}
+
+uint32_t THeaderProtocol::writeByte(const int8_t byte) {
+  return proto_->writeByte(byte);
+}
+
+uint32_t THeaderProtocol::writeI16(const int16_t i16) {
+  return proto_->writeI16(i16);
+}
+
+uint32_t THeaderProtocol::writeI32(const int32_t i32) {
+  return proto_->writeI32(i32);
+}
+
+uint32_t THeaderProtocol::writeI64(const int64_t i64) {
+  return proto_->writeI64(i64);
+}
+
+uint32_t THeaderProtocol::writeDouble(const double dub) {
+  return proto_->writeDouble(dub);
+}
+
+uint32_t THeaderProtocol::writeString(const std::string& str) {
+  return proto_->writeString(str);
+}
+
+uint32_t THeaderProtocol::writeBinary(const std::string& str) {
+  return proto_->writeBinary(str);
+}
+
+/**
+ * Reading functions
+ */
+
+uint32_t THeaderProtocol::readMessageBegin(std::string& name,
+                                           TMessageType& messageType,
+                                           int32_t& seqId) {
+  // Read the next frame, and change protocols if needed
+  try {
+    trans_->resetProtocol();
+    resetProtocol();
+  } catch (const TApplicationException& ex) {
+    writeMessageBegin("", T_EXCEPTION, 0);
+    ex.write((TProtocol*)this);
+    writeMessageEnd();
+    trans_->flush();
+
+    // The framing is still good, but we don't know about this protocol.
+    // In the future, this could be made a client-side only error if
+    // connection pooling is used.
+    throw ex;
+  }
+  return proto_->readMessageBegin(name, messageType, seqId);
+}
+
+uint32_t THeaderProtocol::readMessageEnd() {
+  return proto_->readMessageEnd();
+}
+
+uint32_t THeaderProtocol::readStructBegin(std::string& name) {
+  return proto_->readStructBegin(name);
+}
+
+uint32_t THeaderProtocol::readStructEnd() {
+  return proto_->readStructEnd();
+}
+
+uint32_t THeaderProtocol::readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) {
+  return proto_->readFieldBegin(name, fieldType, fieldId);
+}
+
+uint32_t THeaderProtocol::readFieldEnd() {
+  return proto_->readFieldEnd();
+}
+
+uint32_t THeaderProtocol::readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
+  return proto_->readMapBegin(keyType, valType, size);
+}
+
+uint32_t THeaderProtocol::readMapEnd() {
+  return proto_->readMapEnd();
+}
+
+uint32_t THeaderProtocol::readListBegin(TType& elemType, uint32_t& size) {
+  return proto_->readListBegin(elemType, size);
+}
+
+uint32_t THeaderProtocol::readListEnd() {
+  return proto_->readListEnd();
+}
+
+uint32_t THeaderProtocol::readSetBegin(TType& elemType, uint32_t& size) {
+  return proto_->readSetBegin(elemType, size);
+}
+
+uint32_t THeaderProtocol::readSetEnd() {
+  return proto_->readSetEnd();
+}
+
+uint32_t THeaderProtocol::readBool(bool& value) {
+  return proto_->readBool(value);
+}
+
+uint32_t THeaderProtocol::readByte(int8_t& byte) {
+  return proto_->readByte(byte);
+}
+
+uint32_t THeaderProtocol::readI16(int16_t& i16) {
+  return proto_->readI16(i16);
+}
+
+uint32_t THeaderProtocol::readI32(int32_t& i32) {
+  return proto_->readI32(i32);
+}
+
+uint32_t THeaderProtocol::readI64(int64_t& i64) {
+  return proto_->readI64(i64);
+}
+
+uint32_t THeaderProtocol::readDouble(double& dub) {
+  return proto_->readDouble(dub);
+}
+
+uint32_t THeaderProtocol::readString(std::string& str) {
+  return proto_->readString(str);
+}
+
+uint32_t THeaderProtocol::readBinary(std::string& binary) {
+  return proto_->readBinary(binary);
+}
+}
+}
+} // apache::thrift::protocol
+
+#endif // #ifndef THRIFT_PROTOCOL_THEADERPROTOCOL_CPP_
diff --git a/lib/cpp/src/thrift/protocol/THeaderProtocol.h b/lib/cpp/src/thrift/protocol/THeaderProtocol.h
new file mode 100644
index 0000000..e5e2b65
--- /dev/null
+++ b/lib/cpp/src/thrift/protocol/THeaderProtocol.h
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+#ifndef THRIFT_PROTOCOL_THEADERPROTOCOL_H_
+#define THRIFT_PROTOCOL_THEADERPROTOCOL_H_ 1
+
+#include <thrift/protocol/TProtocol.h>
+#include <thrift/protocol/TProtocolTypes.h>
+#include <thrift/protocol/TVirtualProtocol.h>
+#include <thrift/transport/THeaderTransport.h>
+
+#include <memory>
+
+using apache::thrift::transport::THeaderTransport;
+
+namespace apache {
+namespace thrift {
+namespace protocol {
+
+/**
+ * The header protocol for thrift. Reads unframed, framed, header format,
+ * and http
+ *
+ */
+class THeaderProtocol : public TVirtualProtocol<THeaderProtocol> {
+protected:
+public:
+  void resetProtocol();
+
+  explicit THeaderProtocol(const std::shared_ptr<TTransport>& trans,
+                           uint16_t protoId = T_COMPACT_PROTOCOL)
+    : TVirtualProtocol<THeaderProtocol>(std::shared_ptr<TTransport>(new THeaderTransport(trans))),
+      trans_(std::dynamic_pointer_cast<THeaderTransport>(getTransport())),
+      protoId_(protoId) {
+    trans_->setProtocolId(protoId);
+    resetProtocol();
+  }
+
+  THeaderProtocol(const std::shared_ptr<TTransport>& inTrans,
+                  const std::shared_ptr<TTransport>& outTrans,
+                  uint16_t protoId = T_COMPACT_PROTOCOL)
+    : TVirtualProtocol<THeaderProtocol>(
+          std::shared_ptr<TTransport>(new THeaderTransport(inTrans, outTrans))),
+      trans_(std::dynamic_pointer_cast<THeaderTransport>(getTransport())),
+      protoId_(protoId) {
+    trans_->setProtocolId(protoId);
+    resetProtocol();
+  }
+
+  ~THeaderProtocol() {}
+
+  /**
+   * Functions to work with headers by calling into THeaderTransport
+   */
+  void setProtocolId(uint16_t protoId) {
+    trans_->setProtocolId(protoId);
+    resetProtocol();
+  }
+
+  typedef THeaderTransport::StringToStringMap StringToStringMap;
+
+  // these work with write headers
+  void setHeader(const std::string& key, const std::string& value) {
+    trans_->setHeader(key, value);
+  }
+
+  void clearHeaders() { trans_->clearHeaders(); }
+
+  StringToStringMap& getWriteHeaders() { return trans_->getWriteHeaders(); }
+
+  // these work with read headers
+  const StringToStringMap& getHeaders() const { return trans_->getHeaders(); }
+
+  /**
+   * Writing functions.
+   */
+
+  /*ol*/ uint32_t writeMessageBegin(const std::string& name,
+                                    const TMessageType messageType,
+                                    const int32_t seqId);
+
+  /*ol*/ uint32_t writeMessageEnd();
+
+  uint32_t writeStructBegin(const char* name);
+
+  uint32_t writeStructEnd();
+
+  uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId);
+
+  uint32_t writeFieldEnd();
+
+  uint32_t writeFieldStop();
+
+  uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size);
+
+  uint32_t writeMapEnd();
+
+  uint32_t writeListBegin(const TType elemType, const uint32_t size);
+
+  uint32_t writeListEnd();
+
+  uint32_t writeSetBegin(const TType elemType, const uint32_t size);
+
+  uint32_t writeSetEnd();
+
+  uint32_t writeBool(const bool value);
+
+  uint32_t writeByte(const int8_t byte);
+
+  uint32_t writeI16(const int16_t i16);
+
+  uint32_t writeI32(const int32_t i32);
+
+  uint32_t writeI64(const int64_t i64);
+
+  uint32_t writeDouble(const double dub);
+
+  uint32_t writeString(const std::string& str);
+
+  uint32_t writeBinary(const std::string& str);
+
+  /**
+   * Reading functions
+   */
+
+  /*ol*/ uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqId);
+
+  /*ol*/ uint32_t readMessageEnd();
+
+  uint32_t readStructBegin(std::string& name);
+
+  uint32_t readStructEnd();
+
+  uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId);
+
+  uint32_t readFieldEnd();
+
+  uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size);
+
+  uint32_t readMapEnd();
+
+  uint32_t readListBegin(TType& elemType, uint32_t& size);
+
+  uint32_t readListEnd();
+
+  uint32_t readSetBegin(TType& elemType, uint32_t& size);
+
+  uint32_t readSetEnd();
+
+  uint32_t readBool(bool& value);
+  // Provide the default readBool() implementation for std::vector<bool>
+  using TVirtualProtocol<THeaderProtocol>::readBool;
+
+  uint32_t readByte(int8_t& byte);
+
+  uint32_t readI16(int16_t& i16);
+
+  uint32_t readI32(int32_t& i32);
+
+  uint32_t readI64(int64_t& i64);
+
+  uint32_t readDouble(double& dub);
+
+  uint32_t readString(std::string& str);
+
+  uint32_t readBinary(std::string& binary);
+
+protected:
+  std::shared_ptr<THeaderTransport> trans_;
+
+  std::shared_ptr<TProtocol> proto_;
+  uint32_t protoId_;
+};
+
+class THeaderProtocolFactory : public TProtocolFactory {
+public:
+  virtual std::shared_ptr<TProtocol> getProtocol(std::shared_ptr<transport::TTransport> trans) {
+    THeaderProtocol* headerProtocol
+        = new THeaderProtocol(trans, trans, T_BINARY_PROTOCOL);
+    return std::shared_ptr<TProtocol>(headerProtocol);
+  }
+
+  virtual std::shared_ptr<TProtocol> getProtocol(
+      std::shared_ptr<transport::TTransport> inTrans,
+      std::shared_ptr<transport::TTransport> outTrans) {
+    THeaderProtocol* headerProtocol = new THeaderProtocol(inTrans, outTrans, T_BINARY_PROTOCOL);
+    return std::shared_ptr<TProtocol>(headerProtocol);
+  }
+};
+}
+}
+} // apache::thrift::protocol
+
+#endif // #ifndef THRIFT_PROTOCOL_THEADERPROTOCOL_H_
diff --git a/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp b/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
index a0cc8e2..4576fa1 100644
--- a/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
+++ b/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
@@ -19,15 +19,25 @@
 
 #include <thrift/protocol/TJSONProtocol.h>
 
-#include <math.h>
-#include <boost/lexical_cast.hpp>
+#include <boost/locale.hpp>
+#include <boost/math/special_functions/fpclassify.hpp>
+#include <boost/math/special_functions/sign.hpp>
+
+#include <cmath>
+#include <limits>
+#include <locale>
+#include <sstream>
+#include <stdexcept>
+
 #include <thrift/protocol/TBase64Utils.h>
 #include <thrift/transport/TTransportException.h>
+#include <thrift/TToString.h>
 
 using namespace apache::thrift::transport;
 
-namespace apache { namespace thrift { namespace protocol {
-
+namespace apache {
+namespace thrift {
+namespace protocol {
 
 // Static data
 
@@ -35,12 +45,10 @@
 static const uint8_t kJSONObjectEnd = '}';
 static const uint8_t kJSONArrayStart = '[';
 static const uint8_t kJSONArrayEnd = ']';
-static const uint8_t kJSONNewline = '\n';
 static const uint8_t kJSONPairSeparator = ':';
 static const uint8_t kJSONElemSeparator = ',';
 static const uint8_t kJSONBackslash = '\\';
 static const uint8_t kJSONStringDelimiter = '"';
-static const uint8_t kJSONZeroChar = '0';
 static const uint8_t kJSONEscapeChar = 'u';
 
 static const std::string kJSONEscapePrefix("\\u00");
@@ -63,7 +71,7 @@
 static const std::string kTypeNameList("lst");
 static const std::string kTypeNameSet("set");
 
-static const std::string &getTypeNameForTypeID(TType typeID) {
+static const std::string& getTypeNameForTypeID(TType typeID) {
   switch (typeID) {
   case T_BOOL:
     return kTypeNameBool;
@@ -88,12 +96,11 @@
   case T_LIST:
     return kTypeNameList;
   default:
-    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
-                             "Unrecognized type");
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, "Unrecognized type");
   }
 }
 
-static TType getTypeIDForTypeName(const std::string &name) {
+static TType getTypeIDForTypeName(const std::string& name) {
   TType result = T_STOP; // Sentinel value
   if (name.length() > 1) {
     switch (name[0]) {
@@ -128,8 +135,7 @@
     case 's':
       if (name[1] == 't') {
         result = T_STRING;
-      }
-      else if (name[1] == 'e') {
+      } else if (name[1] == 'e') {
         result = T_SET;
       }
       break;
@@ -139,25 +145,67 @@
     }
   }
   if (result == T_STOP) {
-    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
-                             "Unrecognized type");
+    throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, "Unrecognized type");
   }
   return result;
 }
 
-
 // This table describes the handling for the first 0x30 characters
 //  0 : escape using "\u00xx" notation
 //  1 : just output index
 // <other> : escape using "\<other>" notation
 static const uint8_t kJSONCharTable[0x30] = {
-//  0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
-    0,  0,  0,  0,  0,  0,  0,  0,'b','t','n',  0,'f','r',  0,  0, // 0
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 1
-    1,  1,'"',  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, // 2
+    //  0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    'b',
+    't',
+    'n',
+    0,
+    'f',
+    'r',
+    0,
+    0, // 0
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0, // 1
+    1,
+    1,
+    '"',
+    1,
+    1,
+    1,
+    1,
+    1,
+    1,
+    1,
+    1,
+    1,
+    1,
+    1,
+    1,
+    1, // 2
 };
 
-
 // This string's characters must match up with the elements in kEscapeCharVals.
 // I don't have '/' on this list even though it appears on www.json.org --
 // it is not in the RFC
@@ -166,23 +214,26 @@
 // The elements of this array must match up with the sequence of characters in
 // kEscapeChars
 const static uint8_t kEscapeCharVals[7] = {
-  '"', '\\', '\b', '\f', '\n', '\r', '\t',
+    '"',
+    '\\',
+    '\b',
+    '\f',
+    '\n',
+    '\r',
+    '\t',
 };
 
-
 // Static helper functions
 
 // Read 1 character from the transport trans and verify that it is the
 // expected character ch.
 // Throw a protocol exception if it is not.
-static uint32_t readSyntaxChar(TJSONProtocol::LookaheadReader &reader,
-                               uint8_t ch) {
+static uint32_t readSyntaxChar(TJSONProtocol::LookaheadReader& reader, uint8_t ch) {
   uint8_t ch2 = reader.read();
   if (ch2 != ch) {
     throw TProtocolException(TProtocolException::INVALID_DATA,
-                             "Expected \'" + std::string((char *)&ch, 1) +
-                             "\'; got \'" + std::string((char *)&ch2, 1) +
-                             "\'.");
+                             "Expected \'" + std::string((char*)&ch, 1) + "\'; got \'"
+                             + std::string((char*)&ch2, 1) + "\'.");
   }
   return 1;
 }
@@ -192,14 +243,12 @@
 static uint8_t hexVal(uint8_t ch) {
   if ((ch >= '0') && (ch <= '9')) {
     return ch - '0';
-  }
-  else if ((ch >= 'a') && (ch <= 'f')) {
+  } else if ((ch >= 'a') && (ch <= 'f')) {
     return ch - 'a' + 10;
-  }
-  else {
+  } else {
     throw TProtocolException(TProtocolException::INVALID_DATA,
-                             "Expected hex val ([0-9a-f]); got \'"
-                               + std::string((char *)&ch, 1) + "\'.");
+                             "Expected hex val ([0-9a-f]); got \'" + std::string((char*)&ch, 1)
+                             + "\'.");
   }
 }
 
@@ -209,8 +258,7 @@
   val &= 0x0F;
   if (val < 10) {
     return val + '0';
-  }
-  else {
+  } else {
     return val - 10 + 'a';
   }
 }
@@ -238,6 +286,15 @@
   return false;
 }
 
+// Return true if the code unit is high surrogate
+static bool isHighSurrogate(uint16_t val) {
+  return val >= 0xD800 && val <= 0xDBFF;
+}
+
+// Return true if the code unit is low surrogate
+static bool isLowSurrogate(uint16_t val) {
+  return val >= 0xDC00 && val <= 0xDFFF;
+}
 
 /**
  * Class to serve as base JSON context and as base class for other context
@@ -245,25 +302,24 @@
  */
 class TJSONContext {
 
- public:
+public:
+  TJSONContext(){};
 
-  TJSONContext() {};
-
-  virtual ~TJSONContext() {};
+  virtual ~TJSONContext(){};
 
   /**
    * Write context data to the transport. Default is to do nothing.
    */
-  virtual uint32_t write(TTransport &trans) {
-    (void) trans;
+  virtual uint32_t write(TTransport& trans) {
+    (void)trans;
     return 0;
   };
 
   /**
    * Read context data from the transport. Default is to do nothing.
    */
-  virtual uint32_t read(TJSONProtocol::LookaheadReader &reader) {
-    (void) reader;
+  virtual uint32_t read(TJSONProtocol::LookaheadReader& reader) {
+    (void)reader;
     return 0;
   };
 
@@ -271,41 +327,33 @@
    * Return true if numbers need to be escaped as strings in this context.
    * Default behavior is to return false.
    */
-  virtual bool escapeNum() {
-    return false;
-  }
+  virtual bool escapeNum() { return false; }
 };
 
 // Context class for object member key-value pairs
 class JSONPairContext : public TJSONContext {
 
 public:
+  JSONPairContext() : first_(true), colon_(true) {}
 
-  JSONPairContext() :
-    first_(true),
-    colon_(true) {
-  }
-
-  uint32_t write(TTransport &trans) {
+  uint32_t write(TTransport& trans) {
     if (first_) {
       first_ = false;
       colon_ = true;
       return 0;
-    }
-    else {
+    } else {
       trans.write(colon_ ? &kJSONPairSeparator : &kJSONElemSeparator, 1);
       colon_ = !colon_;
       return 1;
     }
   }
 
-  uint32_t read(TJSONProtocol::LookaheadReader &reader) {
+  uint32_t read(TJSONProtocol::LookaheadReader& reader) {
     if (first_) {
       first_ = false;
       colon_ = true;
       return 0;
-    }
-    else {
+    } else {
       uint8_t ch = (colon_ ? kJSONPairSeparator : kJSONElemSeparator);
       colon_ = !colon_;
       return readSyntaxChar(reader, ch);
@@ -313,61 +361,53 @@
   }
 
   // Numbers must be turned into strings if they are the key part of a pair
-  virtual bool escapeNum() {
-    return colon_;
-  }
+  virtual bool escapeNum() { return colon_; }
 
-  private:
-
-    bool first_;
-    bool colon_;
+private:
+  bool first_;
+  bool colon_;
 };
 
 // Context class for lists
 class JSONListContext : public TJSONContext {
 
 public:
+  JSONListContext() : first_(true) {}
 
-  JSONListContext() :
-    first_(true) {
-  }
-
-  uint32_t write(TTransport &trans) {
+  uint32_t write(TTransport& trans) {
     if (first_) {
       first_ = false;
       return 0;
-    }
-    else {
+    } else {
       trans.write(&kJSONElemSeparator, 1);
       return 1;
     }
   }
 
-  uint32_t read(TJSONProtocol::LookaheadReader &reader) {
+  uint32_t read(TJSONProtocol::LookaheadReader& reader) {
     if (first_) {
       first_ = false;
       return 0;
-    }
-    else {
+    } else {
       return readSyntaxChar(reader, kJSONElemSeparator);
     }
   }
 
-  private:
-    bool first_;
+private:
+  bool first_;
 };
 
-
-TJSONProtocol::TJSONProtocol(boost::shared_ptr<TTransport> ptrans) :
-  TVirtualProtocol<TJSONProtocol>(ptrans),
-  trans_(ptrans.get()),
-  context_(new TJSONContext()),
-  reader_(*ptrans) {
+TJSONProtocol::TJSONProtocol(std::shared_ptr<TTransport> ptrans)
+  : TVirtualProtocol<TJSONProtocol>(ptrans),
+    trans_(ptrans.get()),
+    context_(new TJSONContext()),
+    reader_(*ptrans) {
 }
 
-TJSONProtocol::~TJSONProtocol() {}
+TJSONProtocol::~TJSONProtocol() {
+}
 
-void TJSONProtocol::pushContext(boost::shared_ptr<TJSONContext> c) {
+void TJSONProtocol::pushContext(std::shared_ptr<TJSONContext> c) {
   contexts_.push(context_);
   context_ = c;
 }
@@ -379,7 +419,7 @@
 
 // Write the character ch as a JSON escape sequence ("\u00xx")
 uint32_t TJSONProtocol::writeJSONEscapeChar(uint8_t ch) {
-  trans_->write((const uint8_t *)kJSONEscapePrefix.c_str(),
+  trans_->write((const uint8_t*)kJSONEscapePrefix.c_str(),
                 static_cast<uint32_t>(kJSONEscapePrefix.length()));
   uint8_t outCh = hexChar(ch >> 4);
   trans_->write(&outCh, 1);
@@ -395,25 +435,21 @@
       trans_->write(&kJSONBackslash, 1);
       trans_->write(&kJSONBackslash, 1);
       return 2;
-    }
-    else {
+    } else {
       trans_->write(&ch, 1);
       return 1;
     }
-  }
-  else {
+  } else {
     uint8_t outCh = kJSONCharTable[ch];
     // Check if regular character, backslash escaped, or JSON escaped
     if (outCh == 1) {
       trans_->write(&ch, 1);
       return 1;
-    }
-    else if (outCh > 1) {
+    } else if (outCh > 1) {
       trans_->write(&kJSONBackslash, 1);
       trans_->write(&outCh, 1);
       return 2;
-    }
-    else {
+    } else {
       return writeJSONEscapeChar(ch);
     }
   }
@@ -421,7 +457,7 @@
 
 // Write out the contents of the string str as a JSON string, escaping
 // characters as appropriate.
-uint32_t TJSONProtocol::writeJSONString(const std::string &str) {
+uint32_t TJSONProtocol::writeJSONString(const std::string& str) {
   uint32_t result = context_->write(*trans_);
   result += 2; // For quotes
   trans_->write(&kJSONStringDelimiter, 1);
@@ -436,13 +472,13 @@
 
 // Write out the contents of the string as JSON string, base64-encoding
 // the string's contents, and escaping as appropriate
-uint32_t TJSONProtocol::writeJSONBase64(const std::string &str) {
+uint32_t TJSONProtocol::writeJSONBase64(const std::string& str) {
   uint32_t result = context_->write(*trans_);
   result += 2; // For quotes
   trans_->write(&kJSONStringDelimiter, 1);
   uint8_t b[4];
-  const uint8_t *bytes = (const uint8_t *)str.c_str();
-  if(str.length() > (std::numeric_limits<uint32_t>::max)())
+  const uint8_t* bytes = (const uint8_t*)str.c_str();
+  if (str.length() > (std::numeric_limits<uint32_t>::max)())
     throw TProtocolException(TProtocolException::SIZE_LIMIT);
   uint32_t len = static_cast<uint32_t>(str.length());
   while (len >= 3) {
@@ -451,7 +487,7 @@
     trans_->write(b, 4);
     result += 4;
     bytes += 3;
-    len -=3;
+    len -= 3;
   }
   if (len) { // Handle remainder
     base64_encode(bytes, len, b);
@@ -467,15 +503,15 @@
 template <typename NumberType>
 uint32_t TJSONProtocol::writeJSONInteger(NumberType num) {
   uint32_t result = context_->write(*trans_);
-  std::string val(boost::lexical_cast<std::string>(num));
+  std::string val(to_string(num));
   bool escapeNum = context_->escapeNum();
   if (escapeNum) {
     trans_->write(&kJSONStringDelimiter, 1);
     result += 1;
   }
-  if(val.length() > (std::numeric_limits<uint32_t>::max)())
+  if (val.length() > (std::numeric_limits<uint32_t>::max)())
     throw TProtocolException(TProtocolException::SIZE_LIMIT);
-  trans_->write((const uint8_t *)val.c_str(), static_cast<uint32_t>(val.length()));
+  trans_->write((const uint8_t*)val.c_str(), static_cast<uint32_t>(val.length()));
   result += static_cast<uint32_t>(val.length());
   if (escapeNum) {
     trans_->write(&kJSONStringDelimiter, 1);
@@ -484,30 +520,39 @@
   return result;
 }
 
+namespace {
+std::string doubleToString(double d) {
+  std::ostringstream str;
+  str.imbue(std::locale::classic());
+  const std::streamsize max_digits10 = 2 + std::numeric_limits<double>::digits10;
+  str.precision(max_digits10);
+  str << d;
+  return str.str();
+}
+}
+
 // Convert the given double to a JSON string, which is either the number,
 // "NaN" or "Infinity" or "-Infinity".
 uint32_t TJSONProtocol::writeJSONDouble(double num) {
   uint32_t result = context_->write(*trans_);
-  std::string val(boost::lexical_cast<std::string>(num));
+  std::string val;
 
-  // Normalize output of boost::lexical_cast for NaNs and Infinities
   bool special = false;
-  switch (val[0]) {
-  case 'N':
-  case 'n':
+  switch (boost::math::fpclassify(num)) {
+  case FP_INFINITE:
+    if (boost::math::signbit(num)) {
+      val = kThriftNegativeInfinity;
+    } else {
+      val = kThriftInfinity;
+    }
+    special = true;
+    break;
+  case FP_NAN:
     val = kThriftNan;
     special = true;
     break;
-  case 'I':
-  case 'i':
-    val = kThriftInfinity;
-    special = true;
-    break;
-  case '-':
-    if ((val[1] == 'I') || (val[1] == 'i')) {
-      val = kThriftNegativeInfinity;
-      special = true;
-    }
+  default:
+    val = doubleToString(num);
     break;
   }
 
@@ -516,9 +561,9 @@
     trans_->write(&kJSONStringDelimiter, 1);
     result += 1;
   }
-  if(val.length() > (std::numeric_limits<uint32_t>::max)())
+  if (val.length() > (std::numeric_limits<uint32_t>::max)())
     throw TProtocolException(TProtocolException::SIZE_LIMIT);
-  trans_->write((const uint8_t *)val.c_str(), static_cast<uint32_t>(val.length()));
+  trans_->write((const uint8_t*)val.c_str(), static_cast<uint32_t>(val.length()));
   result += static_cast<uint32_t>(val.length());
   if (escapeNum) {
     trans_->write(&kJSONStringDelimiter, 1);
@@ -530,7 +575,7 @@
 uint32_t TJSONProtocol::writeJSONObjectStart() {
   uint32_t result = context_->write(*trans_);
   trans_->write(&kJSONObjectStart, 1);
-  pushContext(boost::shared_ptr<TJSONContext>(new JSONPairContext()));
+  pushContext(std::shared_ptr<TJSONContext>(new JSONPairContext()));
   return result + 1;
 }
 
@@ -543,7 +588,7 @@
 uint32_t TJSONProtocol::writeJSONArrayStart() {
   uint32_t result = context_->write(*trans_);
   trans_->write(&kJSONArrayStart, 1);
-  pushContext(boost::shared_ptr<TJSONContext>(new JSONListContext()));
+  pushContext(std::shared_ptr<TJSONContext>(new JSONListContext()));
   return result + 1;
 }
 
@@ -569,7 +614,7 @@
 }
 
 uint32_t TJSONProtocol::writeStructBegin(const char* name) {
-  (void) name;
+  (void)name;
   return writeJSONObjectStart();
 }
 
@@ -580,7 +625,7 @@
 uint32_t TJSONProtocol::writeFieldBegin(const char* name,
                                         const TType fieldType,
                                         const int16_t fieldId) {
-  (void) name;
+  (void)name;
   uint32_t result = writeJSONInteger(fieldId);
   result += writeJSONObjectStart();
   result += writeJSONString(getTypeNameForTypeID(fieldType));
@@ -607,11 +652,12 @@
 }
 
 uint32_t TJSONProtocol::writeMapEnd() {
-  return writeJSONObjectEnd() + writeJSONArrayEnd();
+  uint32_t result = writeJSONObjectEnd();
+  result += writeJSONArrayEnd();
+  return result;
 }
 
-uint32_t TJSONProtocol::writeListBegin(const TType elemType,
-                                       const uint32_t size) {
+uint32_t TJSONProtocol::writeListBegin(const TType elemType, const uint32_t size) {
   uint32_t result = writeJSONArrayStart();
   result += writeJSONString(getTypeNameForTypeID(elemType));
   result += writeJSONInteger((int64_t)size);
@@ -622,8 +668,7 @@
   return writeJSONArrayEnd();
 }
 
-uint32_t TJSONProtocol::writeSetBegin(const TType elemType,
-                                      const uint32_t size) {
+uint32_t TJSONProtocol::writeSetBegin(const TType elemType, const uint32_t size) {
   uint32_t result = writeJSONArrayStart();
   result += writeJSONString(getTypeNameForTypeID(elemType));
   result += writeJSONInteger((int64_t)size);
@@ -639,7 +684,7 @@
 }
 
 uint32_t TJSONProtocol::writeByte(const int8_t byte) {
-  // writeByte() must be handled specially becuase boost::lexical cast sees
+  // writeByte() must be handled specially because to_string sees
   // int8_t as a text type instead of an integer type
   return writeJSONInteger((int16_t)byte);
 }
@@ -668,9 +713,9 @@
   return writeJSONBase64(str);
 }
 
-  /**
-   * Reading functions
-   */
+/**
+ * Reading functions
+ */
 
 // Reads 1 byte and verifies that it matches ch.
 uint32_t TJSONProtocol::readJSONSyntaxChar(uint8_t ch) {
@@ -678,21 +723,25 @@
 }
 
 // Decodes the four hex parts of a JSON escaped string character and returns
-// the character via out. The first two characters must be "00".
-uint32_t TJSONProtocol::readJSONEscapeChar(uint8_t *out) {
-  uint8_t b[2];
-  readJSONSyntaxChar(kJSONZeroChar);
-  readJSONSyntaxChar(kJSONZeroChar);
+// the UTF-16 code unit via out.
+uint32_t TJSONProtocol::readJSONEscapeChar(uint16_t* out) {
+  uint8_t b[4];
   b[0] = reader_.read();
   b[1] = reader_.read();
-  *out = (hexVal(b[0]) << 4) + hexVal(b[1]);
+  b[2] = reader_.read();
+  b[3] = reader_.read();
+
+  *out = (hexVal(b[0]) << 12)
+    + (hexVal(b[1]) << 8) + (hexVal(b[2]) << 4) + hexVal(b[3]);
+
   return 4;
 }
 
 // Decodes a JSON string, including unescaping, and returns the string via str
-uint32_t TJSONProtocol::readJSONString(std::string &str, bool skipContext) {
+uint32_t TJSONProtocol::readJSONString(std::string& str, bool skipContext) {
   uint32_t result = (skipContext ? 0 : context_->read(reader_));
   result += readJSONSyntaxChar(kJSONStringDelimiter);
+  std::vector<uint16_t> codeunits;
   uint8_t ch;
   str.clear();
   while (true) {
@@ -705,35 +754,65 @@
       ch = reader_.read();
       ++result;
       if (ch == kJSONEscapeChar) {
-        result += readJSONEscapeChar(&ch);
-      }
-      else {
+        uint16_t cp;
+        result += readJSONEscapeChar(&cp);
+        if (isHighSurrogate(cp)) {
+          codeunits.push_back(cp);
+        } else {
+          if (isLowSurrogate(cp)
+               && codeunits.empty()) {
+            throw TProtocolException(TProtocolException::INVALID_DATA,
+                                     "Missing UTF-16 high surrogate pair.");
+          }
+          codeunits.push_back(cp);
+          codeunits.push_back(0);
+          str += boost::locale::conv::utf_to_utf<char>(codeunits.data());
+          codeunits.clear();
+        }
+        continue;
+      } else {
         size_t pos = kEscapeChars.find(ch);
-        if (pos == std::string::npos) {
+        if (pos == kEscapeChars.npos) {
           throw TProtocolException(TProtocolException::INVALID_DATA,
-                                   "Expected control char, got '" +
-                                   std::string((const char *)&ch, 1)  + "'.");
+                                   "Expected control char, got '" + std::string((const char*)&ch, 1)
+                                   + "'.");
         }
         ch = kEscapeCharVals[pos];
       }
     }
+    if (!codeunits.empty()) {
+      throw TProtocolException(TProtocolException::INVALID_DATA,
+                               "Missing UTF-16 low surrogate pair.");
+    }
     str += ch;
   }
+
+  if (!codeunits.empty()) {
+    throw TProtocolException(TProtocolException::INVALID_DATA,
+                             "Missing UTF-16 low surrogate pair.");
+  }
   return result;
 }
 
 // Reads a block of base64 characters, decoding it, and returns via str
-uint32_t TJSONProtocol::readJSONBase64(std::string &str) {
+uint32_t TJSONProtocol::readJSONBase64(std::string& str) {
   std::string tmp;
   uint32_t result = readJSONString(tmp);
-  uint8_t *b = (uint8_t *)tmp.c_str();
-  if(tmp.length() > (std::numeric_limits<uint32_t>::max)())
+  uint8_t* b = (uint8_t*)tmp.c_str();
+  if (tmp.length() > (std::numeric_limits<uint32_t>::max)())
     throw TProtocolException(TProtocolException::SIZE_LIMIT);
   uint32_t len = static_cast<uint32_t>(tmp.length());
   str.clear();
+  // Ignore padding
+  if (len >= 2)  {
+    uint32_t bound = len - 2;
+    for (uint32_t i = len - 1; i >= bound && b[i] == '='; --i) {
+      --len;
+    }
+  }
   while (len >= 4) {
     base64_decode(b, 4);
-    str.append((const char *)b, 3);
+    str.append((const char*)b, 3);
     b += 4;
     len -= 4;
   }
@@ -741,14 +820,14 @@
   // base64 but legal for skip of regular string type)
   if (len > 1) {
     base64_decode(b, len);
-    str.append((const char *)b, len - 1);
+    str.append((const char*)b, len - 1);
   }
   return result;
 }
 
 // Reads a sequence of characters, stopping at the first one that is not
 // a valid JSON numeric character.
-uint32_t TJSONProtocol::readJSONNumericChars(std::string &str) {
+uint32_t TJSONProtocol::readJSONNumericChars(std::string& str) {
   uint32_t result = 0;
   str.clear();
   while (true) {
@@ -763,10 +842,23 @@
   return result;
 }
 
+namespace {
+template <typename T>
+T fromString(const std::string& s) {
+  T t;
+  std::istringstream str(s);
+  str.imbue(std::locale::classic());
+  str >> t;
+  if (str.bad() || !str.eof())
+    throw std::runtime_error(s);
+  return t;
+}
+}
+
 // Reads a sequence of characters and assembles them into a number,
 // returning them via num
 template <typename NumberType>
-uint32_t TJSONProtocol::readJSONInteger(NumberType &num) {
+uint32_t TJSONProtocol::readJSONInteger(NumberType& num) {
   uint32_t result = context_->read(reader_);
   if (context_->escapeNum()) {
     result += readJSONSyntaxChar(kJSONStringDelimiter);
@@ -774,12 +866,10 @@
   std::string str;
   result += readJSONNumericChars(str);
   try {
-    num = boost::lexical_cast<NumberType>(str);
-  }
-  catch (boost::bad_lexical_cast e) {
-    throw new TProtocolException(TProtocolException::INVALID_DATA,
-                                 "Expected numeric value; got \"" + str +
-                                  "\"");
+    num = fromString<NumberType>(str);
+  } catch (const std::runtime_error&) {
+    throw TProtocolException(TProtocolException::INVALID_DATA,
+                             "Expected numeric value; got \"" + str + "\"");
   }
   if (context_->escapeNum()) {
     result += readJSONSyntaxChar(kJSONStringDelimiter);
@@ -788,50 +878,42 @@
 }
 
 // Reads a JSON number or string and interprets it as a double.
-uint32_t TJSONProtocol::readJSONDouble(double &num) {
+uint32_t TJSONProtocol::readJSONDouble(double& num) {
   uint32_t result = context_->read(reader_);
   std::string str;
   if (reader_.peek() == kJSONStringDelimiter) {
     result += readJSONString(str, true);
     // Check for NaN, Infinity and -Infinity
     if (str == kThriftNan) {
-      num = HUGE_VAL/HUGE_VAL; // generates NaN
-    }
-    else if (str == kThriftInfinity) {
+      num = HUGE_VAL / HUGE_VAL; // generates NaN
+    } else if (str == kThriftInfinity) {
       num = HUGE_VAL;
-    }
-    else if (str == kThriftNegativeInfinity) {
+    } else if (str == kThriftNegativeInfinity) {
       num = -HUGE_VAL;
-    }
-    else {
+    } else {
       if (!context_->escapeNum()) {
         // Throw exception -- we should not be in a string in this case
-        throw new TProtocolException(TProtocolException::INVALID_DATA,
+        throw TProtocolException(TProtocolException::INVALID_DATA,
                                      "Numeric data unexpectedly quoted");
       }
       try {
-        num = boost::lexical_cast<double>(str);
-      }
-      catch (boost::bad_lexical_cast e) {
-        throw new TProtocolException(TProtocolException::INVALID_DATA,
-                                     "Expected numeric value; got \"" + str +
-                                     "\"");
+        num = fromString<double>(str);
+      } catch (std::runtime_error& e) {
+        throw TProtocolException(TProtocolException::INVALID_DATA,
+                                     "Expected numeric value; got \"" + str + "\"");
       }
     }
-  }
-  else {
+  } else {
     if (context_->escapeNum()) {
       // This will throw - we should have had a quote if escapeNum == true
       readJSONSyntaxChar(kJSONStringDelimiter);
     }
     result += readJSONNumericChars(str);
     try {
-      num = boost::lexical_cast<double>(str);
-    }
-    catch (boost::bad_lexical_cast e) {
-      throw new TProtocolException(TProtocolException::INVALID_DATA,
-                                   "Expected numeric value; got \"" + str +
-                                   "\"");
+      num = fromString<double>(str);
+    } catch (std::runtime_error& e) {
+      throw TProtocolException(TProtocolException::INVALID_DATA,
+                                   "Expected numeric value; got \"" + str + "\"");
     }
   }
   return result;
@@ -840,7 +922,7 @@
 uint32_t TJSONProtocol::readJSONObjectStart() {
   uint32_t result = context_->read(reader_);
   result += readJSONSyntaxChar(kJSONObjectStart);
-  pushContext(boost::shared_ptr<TJSONContext>(new JSONPairContext()));
+  pushContext(std::shared_ptr<TJSONContext>(new JSONPairContext()));
   return result;
 }
 
@@ -853,7 +935,7 @@
 uint32_t TJSONProtocol::readJSONArrayStart() {
   uint32_t result = context_->read(reader_);
   result += readJSONSyntaxChar(kJSONArrayStart);
-  pushContext(boost::shared_ptr<TJSONContext>(new JSONListContext()));
+  pushContext(std::shared_ptr<TJSONContext>(new JSONListContext()));
   return result;
 }
 
@@ -870,14 +952,13 @@
   uint64_t tmpVal = 0;
   result += readJSONInteger(tmpVal);
   if (tmpVal != kThriftVersion1) {
-    throw TProtocolException(TProtocolException::BAD_VERSION,
-                             "Message contained bad version.");
+    throw TProtocolException(TProtocolException::BAD_VERSION, "Message contained bad version.");
   }
   result += readJSONString(name);
   result += readJSONInteger(tmpVal);
   messageType = (TMessageType)tmpVal;
   result += readJSONInteger(tmpVal);
-  if(tmpVal > static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
+  if (tmpVal > static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
     throw TProtocolException(TProtocolException::SIZE_LIMIT);
   seqid = static_cast<int32_t>(tmpVal);
   return result;
@@ -888,7 +969,7 @@
 }
 
 uint32_t TJSONProtocol::readStructBegin(std::string& name) {
-  (void) name;
+  (void)name;
   return readJSONObjectStart();
 }
 
@@ -896,21 +977,18 @@
   return readJSONObjectEnd();
 }
 
-uint32_t TJSONProtocol::readFieldBegin(std::string& name,
-                                       TType& fieldType,
-                                       int16_t& fieldId) {
-  (void) name;
+uint32_t TJSONProtocol::readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) {
+  (void)name;
   uint32_t result = 0;
   // Check if we hit the end of the list
   uint8_t ch = reader_.peek();
   if (ch == kJSONObjectEnd) {
     fieldType = apache::thrift::protocol::T_STOP;
-  }
-  else {
+  } else {
     uint64_t tmpVal = 0;
     std::string tmpStr;
     result += readJSONInteger(tmpVal);
-    if(tmpVal > static_cast<uint32_t>((std::numeric_limits<int16_t>::max)()))
+    if (tmpVal > static_cast<uint32_t>((std::numeric_limits<int16_t>::max)()))
       throw TProtocolException(TProtocolException::SIZE_LIMIT);
     fieldId = static_cast<int16_t>(tmpVal);
     result += readJSONObjectStart();
@@ -924,9 +1002,7 @@
   return readJSONObjectEnd();
 }
 
-uint32_t TJSONProtocol::readMapBegin(TType& keyType,
-                                     TType& valType,
-                                     uint32_t& size) {
+uint32_t TJSONProtocol::readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
   uint64_t tmpVal = 0;
   std::string tmpStr;
   uint32_t result = readJSONArrayStart();
@@ -935,7 +1011,7 @@
   result += readJSONString(tmpStr);
   valType = getTypeIDForTypeName(tmpStr);
   result += readJSONInteger(tmpVal);
-  if(tmpVal > (std::numeric_limits<uint32_t>::max)())
+  if (tmpVal > (std::numeric_limits<uint32_t>::max)())
     throw TProtocolException(TProtocolException::SIZE_LIMIT);
   size = static_cast<uint32_t>(tmpVal);
   result += readJSONObjectStart();
@@ -943,18 +1019,19 @@
 }
 
 uint32_t TJSONProtocol::readMapEnd() {
-  return readJSONObjectEnd() + readJSONArrayEnd();
+  uint32_t result = readJSONObjectEnd();
+  result += readJSONArrayEnd();
+  return result;
 }
 
-uint32_t TJSONProtocol::readListBegin(TType& elemType,
-                                      uint32_t& size) {
+uint32_t TJSONProtocol::readListBegin(TType& elemType, uint32_t& size) {
   uint64_t tmpVal = 0;
   std::string tmpStr;
   uint32_t result = readJSONArrayStart();
   result += readJSONString(tmpStr);
   elemType = getTypeIDForTypeName(tmpStr);
   result += readJSONInteger(tmpVal);
-  if(tmpVal > (std::numeric_limits<uint32_t>::max)())
+  if (tmpVal > (std::numeric_limits<uint32_t>::max)())
     throw TProtocolException(TProtocolException::SIZE_LIMIT);
   size = static_cast<uint32_t>(tmpVal);
   return result;
@@ -964,15 +1041,14 @@
   return readJSONArrayEnd();
 }
 
-uint32_t TJSONProtocol::readSetBegin(TType& elemType,
-                                     uint32_t& size) {
+uint32_t TJSONProtocol::readSetBegin(TType& elemType, uint32_t& size) {
   uint64_t tmpVal = 0;
   std::string tmpStr;
   uint32_t result = readJSONArrayStart();
   result += readJSONString(tmpStr);
   elemType = getTypeIDForTypeName(tmpStr);
   result += readJSONInteger(tmpVal);
-  if(tmpVal > (std::numeric_limits<uint32_t>::max)())
+  if (tmpVal > (std::numeric_limits<uint32_t>::max)())
     throw TProtocolException(TProtocolException::SIZE_LIMIT);
   size = static_cast<uint32_t>(tmpVal);
   return result;
@@ -986,11 +1062,11 @@
   return readJSONInteger(value);
 }
 
-// readByte() must be handled properly becuase boost::lexical cast sees int8_t
+// readByte() must be handled properly because boost::lexical cast sees int8_t
 // as a text type instead of an integer type
 uint32_t TJSONProtocol::readByte(int8_t& byte) {
-  int16_t tmp = (int16_t) byte;
-  uint32_t result =  readJSONInteger(tmp);
+  int16_t tmp = (int16_t)byte;
+  uint32_t result = readJSONInteger(tmp);
   assert(tmp < 256);
   byte = (int8_t)tmp;
   return result;
@@ -1012,12 +1088,13 @@
   return readJSONDouble(dub);
 }
 
-uint32_t TJSONProtocol::readString(std::string &str) {
+uint32_t TJSONProtocol::readString(std::string& str) {
   return readJSONString(str);
 }
 
-uint32_t TJSONProtocol::readBinary(std::string &str) {
+uint32_t TJSONProtocol::readBinary(std::string& str) {
   return readJSONBase64(str);
 }
-
-}}} // apache::thrift::protocol
+}
+}
+} // apache::thrift::protocol
diff --git a/lib/cpp/src/thrift/protocol/TJSONProtocol.h b/lib/cpp/src/thrift/protocol/TJSONProtocol.h
index edfc744..9c2f872 100644
--- a/lib/cpp/src/thrift/protocol/TJSONProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TJSONProtocol.h
@@ -24,7 +24,9 @@
 
 #include <stack>
 
-namespace apache { namespace thrift { namespace protocol {
+namespace apache {
+namespace thrift {
+namespace protocol {
 
 // Forward declaration
 class TJSONContext;
@@ -41,7 +43,7 @@
  * 2. Thrift doubles are represented as JSON numbers. Some special values are
  *    represented as strings:
  *    a. "NaN" for not-a-number values
- *    b. "Infinity" for postive infinity
+ *    b. "Infinity" for positive infinity
  *    c. "-Infinity" for negative infinity
  *
  * 3. Thrift string values are emitted as JSON strings, with appropriate
@@ -51,6 +53,10 @@
  *    The readBinary() method is written such that it will properly skip if
  *    called on a Thrift string (although it will decode garbage data).
  *
+ *    NOTE: Base64 padding is optional for Thrift binary value encoding. So
+ *    the readBinary() method needs to decode both input strings with padding
+ *    and those without one.
+ *
  * 5. Thrift structs are represented as JSON objects, with the field ID as the
  *    key, and the field value represented as a JSON object with a single
  *    key-value pair. The key is a short string identifier for that type,
@@ -81,22 +87,21 @@
  * the current implementation is to match as closely as possible the behavior
  * of Java's Double.toString(), which has no precision loss.  Implementors in
  * other languages should strive to achieve that where possible. I have not
- * yet verified whether boost:lexical_cast, which is doing that work for me in
- * C++, loses any precision, but I am leaving this as a future improvement. I
- * may try to provide a C component for this, so that other languages could
- * bind to the same underlying implementation for maximum consistency.
+ * yet verified whether std::istringstream::operator>>, which is doing that
+ * work for me in C++, loses any precision, but I am leaving this as a future
+ * improvement. I may try to provide a C component for this, so that other
+ * languages could bind to the same underlying implementation for maximum
+ * consistency.
  *
  */
 class TJSONProtocol : public TVirtualProtocol<TJSONProtocol> {
- public:
-
-  TJSONProtocol(boost::shared_ptr<TTransport> ptrans);
+public:
+  TJSONProtocol(std::shared_ptr<TTransport> ptrans);
 
   ~TJSONProtocol();
 
- private:
-
-  void pushContext(boost::shared_ptr<TJSONContext> c);
+private:
+  void pushContext(std::shared_ptr<TJSONContext> c);
 
   void popContext();
 
@@ -104,16 +109,16 @@
 
   uint32_t writeJSONChar(uint8_t ch);
 
-  uint32_t writeJSONString(const std::string &str);
+  uint32_t writeJSONString(const std::string& str);
 
-  uint32_t writeJSONBase64(const std::string &str);
+  uint32_t writeJSONBase64(const std::string& str);
 
   template <typename NumberType>
   uint32_t writeJSONInteger(NumberType num);
 
   uint32_t writeJSONDouble(double num);
 
-  uint32_t writeJSONObjectStart() ;
+  uint32_t writeJSONObjectStart();
 
   uint32_t writeJSONObjectEnd();
 
@@ -123,18 +128,18 @@
 
   uint32_t readJSONSyntaxChar(uint8_t ch);
 
-  uint32_t readJSONEscapeChar(uint8_t *out);
+  uint32_t readJSONEscapeChar(uint16_t* out);
 
-  uint32_t readJSONString(std::string &str, bool skipContext = false);
+  uint32_t readJSONString(std::string& str, bool skipContext = false);
 
-  uint32_t readJSONBase64(std::string &str);
+  uint32_t readJSONBase64(std::string& str);
 
-  uint32_t readJSONNumericChars(std::string &str);
+  uint32_t readJSONNumericChars(std::string& str);
 
   template <typename NumberType>
-  uint32_t readJSONInteger(NumberType &num);
+  uint32_t readJSONInteger(NumberType& num);
 
-  uint32_t readJSONDouble(double &num);
+  uint32_t readJSONDouble(double& num);
 
   uint32_t readJSONObjectStart();
 
@@ -144,8 +149,7 @@
 
   uint32_t readJSONArrayEnd();
 
- public:
-
+public:
   /**
    * Writing functions.
    */
@@ -160,27 +164,21 @@
 
   uint32_t writeStructEnd();
 
-  uint32_t writeFieldBegin(const char* name,
-                           const TType fieldType,
-                           const int16_t fieldId);
+  uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId);
 
   uint32_t writeFieldEnd();
 
   uint32_t writeFieldStop();
 
-  uint32_t writeMapBegin(const TType keyType,
-                         const TType valType,
-                         const uint32_t size);
+  uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size);
 
   uint32_t writeMapEnd();
 
-  uint32_t writeListBegin(const TType elemType,
-                          const uint32_t size);
+  uint32_t writeListBegin(const TType elemType, const uint32_t size);
 
   uint32_t writeListEnd();
 
-  uint32_t writeSetBegin(const TType elemType,
-                         const uint32_t size);
+  uint32_t writeSetBegin(const TType elemType, const uint32_t size);
 
   uint32_t writeSetEnd();
 
@@ -204,9 +202,7 @@
    * Reading functions
    */
 
-  uint32_t readMessageBegin(std::string& name,
-                            TMessageType& messageType,
-                            int32_t& seqid);
+  uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid);
 
   uint32_t readMessageEnd();
 
@@ -214,25 +210,19 @@
 
   uint32_t readStructEnd();
 
-  uint32_t readFieldBegin(std::string& name,
-                          TType& fieldType,
-                          int16_t& fieldId);
+  uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId);
 
   uint32_t readFieldEnd();
 
-  uint32_t readMapBegin(TType& keyType,
-                        TType& valType,
-                        uint32_t& size);
+  uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size);
 
   uint32_t readMapEnd();
 
-  uint32_t readListBegin(TType& elemType,
-                         uint32_t& size);
+  uint32_t readListBegin(TType& elemType, uint32_t& size);
 
   uint32_t readListEnd();
 
-  uint32_t readSetBegin(TType& elemType,
-                        uint32_t& size);
+  uint32_t readSetBegin(TType& elemType, uint32_t& size);
 
   uint32_t readSetEnd();
 
@@ -257,18 +247,13 @@
 
   class LookaheadReader {
 
-   public:
-
-    LookaheadReader(TTransport &trans) :
-      trans_(&trans),
-      hasData_(false) {
-    }
+  public:
+    LookaheadReader(TTransport& trans) : trans_(&trans), hasData_(false) {}
 
     uint8_t read() {
       if (hasData_) {
         hasData_ = false;
-      }
-      else {
+      } else {
         trans_->readAll(&data_, 1);
       }
       return data_;
@@ -282,17 +267,17 @@
       return data_;
     }
 
-   private:
-    TTransport *trans_;
+  private:
+    TTransport* trans_;
     bool hasData_;
     uint8_t data_;
   };
 
- private:
+private:
   TTransport* trans_;
 
-  std::stack<boost::shared_ptr<TJSONContext> > contexts_;
-  boost::shared_ptr<TJSONContext> context_;
+  std::stack<std::shared_ptr<TJSONContext> > contexts_;
+  std::shared_ptr<TJSONContext> context_;
   LookaheadReader reader_;
 };
 
@@ -300,30 +285,31 @@
  * Constructs input and output protocol objects given transports.
  */
 class TJSONProtocolFactory : public TProtocolFactory {
- public:
+public:
   TJSONProtocolFactory() {}
 
   virtual ~TJSONProtocolFactory() {}
 
-  boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) {
-    return boost::shared_ptr<TProtocol>(new TJSONProtocol(trans));
+  std::shared_ptr<TProtocol> getProtocol(std::shared_ptr<TTransport> trans) {
+    return std::shared_ptr<TProtocol>(new TJSONProtocol(trans));
   }
 };
-
-}}} // apache::thrift::protocol
-
+}
+}
+} // apache::thrift::protocol
 
 // TODO(dreiss): Move part of ThriftJSONString into a .cpp file and remove this.
 #include <thrift/transport/TBufferTransports.h>
 
-namespace apache { namespace thrift {
+namespace apache {
+namespace thrift {
 
-template<typename ThriftStruct>
-  std::string ThriftJSONString(const ThriftStruct& ts) {
+template <typename ThriftStruct>
+std::string ThriftJSONString(const ThriftStruct& ts) {
   using namespace apache::thrift::transport;
   using namespace apache::thrift::protocol;
   TMemoryBuffer* buffer = new TMemoryBuffer;
-  boost::shared_ptr<TTransport> trans(buffer);
+  std::shared_ptr<TTransport> trans(buffer);
   TJSONProtocol protocol(trans);
 
   ts.write(&protocol);
@@ -333,7 +319,7 @@
   buffer->getBuffer(&buf, &size);
   return std::string((char*)buf, (unsigned int)size);
 }
-
-}} // apache::thrift
+}
+} // apache::thrift
 
 #endif // #define _THRIFT_PROTOCOL_TJSONPROTOCOL_H_ 1
diff --git a/lib/cpp/src/thrift/protocol/TMultiplexedProtocol.cpp b/lib/cpp/src/thrift/protocol/TMultiplexedProtocol.cpp
index a17eacc..f0dc69e 100644
--- a/lib/cpp/src/thrift/protocol/TMultiplexedProtocol.cpp
+++ b/lib/cpp/src/thrift/protocol/TMultiplexedProtocol.cpp
@@ -21,27 +21,20 @@
 #include <thrift/processor/TMultiplexedProcessor.h>
 #include <thrift/protocol/TProtocolDecorator.h>
 
-namespace apache 
-{ 
-    namespace thrift 
-    { 
-        namespace protocol 
-        {
-            uint32_t TMultiplexedProtocol::writeMessageBegin_virt(
-                const std::string& _name,
-                const TMessageType _type,
-                const int32_t _seqid)
-            {
-                if( _type == T_CALL || _type == T_ONEWAY )
-                {
-                    return TProtocolDecorator::writeMessageBegin_virt( serviceName + separator + _name, _type, _seqid );
-                }
-                else
-                {
-                    return TProtocolDecorator::writeMessageBegin_virt(_name, _type, _seqid);
-                }
-            }
-        }
-    }
+namespace apache {
+namespace thrift {
+namespace protocol {
+uint32_t TMultiplexedProtocol::writeMessageBegin_virt(const std::string& _name,
+                                                      const TMessageType _type,
+                                                      const int32_t _seqid) {
+  if (_type == T_CALL || _type == T_ONEWAY) {
+    return TProtocolDecorator::writeMessageBegin_virt(serviceName + separator + _name,
+                                                      _type,
+                                                      _seqid);
+  } else {
+    return TProtocolDecorator::writeMessageBegin_virt(_name, _type, _seqid);
+  }
 }
-
+}
+}
+}
diff --git a/lib/cpp/src/thrift/protocol/TMultiplexedProtocol.h b/lib/cpp/src/thrift/protocol/TMultiplexedProtocol.h
index a59c7b4..94bd82e 100644
--- a/lib/cpp/src/thrift/protocol/TMultiplexedProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TMultiplexedProtocol.h
@@ -22,82 +22,74 @@
 
 #include <thrift/protocol/TProtocolDecorator.h>
 
-namespace apache 
-{ 
-    namespace thrift 
-    { 
-        namespace protocol 
-        {
-            using boost::shared_ptr;
+namespace apache {
+namespace thrift {
+namespace protocol {
+using std::shared_ptr;
 
-            /**
-             * <code>TMultiplexedProtocol</code> is a protocol-independent concrete decorator
-             * that allows a Thrift client to communicate with a multiplexing Thrift server,
-             * by prepending the service name to the function name during function calls.
-             *
-             * \note THIS IS NOT USED BY SERVERS.  On the server, use 
-             * {@link apache::thrift::TMultiplexedProcessor TMultiplexedProcessor} to handle requests
-             * from a multiplexing client.
-             *
-             * This example uses a single socket transport to invoke two services:
-             *
-             * <blockquote><code>
-             *     shared_ptr<TSocket> transport(new TSocket("localhost", 9090));
-             *     transport->open();
-             *
-             *     shared_ptr<TBinaryProtocol> protocol(new TBinaryProtocol(transport));
-             *
-             *     shared_ptr<TMultiplexedProtocol> mp1(new TMultiplexedProtocol(protocol, "Calculator"));
-             *     shared_ptr<CalculatorClient> service1(new CalculatorClient(mp1));
-             *
-             *     shared_ptr<TMultiplexedProtocol> mp2(new TMultiplexedProtocol(protocol, "WeatherReport"));
-             *     shared_ptr<WeatherReportClient> service2(new WeatherReportClient(mp2));
-             *
-             *     service1->add(2,2);
-             *     int temp = service2->getTemperature();
-             * </code></blockquote>
-             *
-             * @see apache::thrift::protocol::TProtocolDecorator
-             */
-             class TMultiplexedProtocol : public TProtocolDecorator
-            {
-            public:
-                /**
-                 * Wrap the specified protocol, allowing it to be used to communicate with a
-                 * multiplexing server.  The <code>serviceName</code> is required as it is
-                 * prepended to the message header so that the multiplexing server can broker
-                 * the function call to the proper service.
-                 *
-                 * \param _protocol    Your communication protocol of choice, e.g. <code>TBinaryProtocol</code>.
-                 * \param _serviceName The service name of the service communicating via this protocol.
-                 */
-                 TMultiplexedProtocol( shared_ptr<TProtocol> _protocol, const std::string& _serviceName ) 
-                    : TProtocolDecorator(_protocol),
-                      serviceName(_serviceName),
-                      separator(":")
-                { }
-                virtual ~TMultiplexedProtocol() {}
+/**
+ * <code>TMultiplexedProtocol</code> is a protocol-independent concrete decorator
+ * that allows a Thrift client to communicate with a multiplexing Thrift server,
+ * by prepending the service name to the function name during function calls.
+ *
+ * \note THIS IS NOT USED BY SERVERS.  On the server, use
+ * {@link apache::thrift::TMultiplexedProcessor TMultiplexedProcessor} to handle requests
+ * from a multiplexing client.
+ *
+ * This example uses a single socket transport to invoke two services:
+ *
+ * <blockquote><code>
+ *     shared_ptr<TSocket> transport(new TSocket("localhost", 9090));
+ *     transport->open();
+ *
+ *     shared_ptr<TBinaryProtocol> protocol(new TBinaryProtocol(transport));
+ *
+ *     shared_ptr<TMultiplexedProtocol> mp1(new TMultiplexedProtocol(protocol, "Calculator"));
+ *     shared_ptr<CalculatorClient> service1(new CalculatorClient(mp1));
+ *
+ *     shared_ptr<TMultiplexedProtocol> mp2(new TMultiplexedProtocol(protocol, "WeatherReport"));
+ *     shared_ptr<WeatherReportClient> service2(new WeatherReportClient(mp2));
+ *
+ *     service1->add(2,2);
+ *     int temp = service2->getTemperature();
+ * </code></blockquote>
+ *
+ * @see apache::thrift::protocol::TProtocolDecorator
+ */
+class TMultiplexedProtocol : public TProtocolDecorator {
+public:
+  /**
+   * Wrap the specified protocol, allowing it to be used to communicate with a
+   * multiplexing server.  The <code>serviceName</code> is required as it is
+   * prepended to the message header so that the multiplexing server can broker
+   * the function call to the proper service.
+   *
+   * \param _protocol    Your communication protocol of choice, e.g. <code>TBinaryProtocol</code>.
+   * \param _serviceName The service name of the service communicating via this protocol.
+   */
+  TMultiplexedProtocol(shared_ptr<TProtocol> _protocol, const std::string& _serviceName)
+    : TProtocolDecorator(_protocol), serviceName(_serviceName), separator(":") {}
+  virtual ~TMultiplexedProtocol() {}
 
-                /**
-                 * Prepends the service name to the function name, separated by TMultiplexedProtocol::SEPARATOR.
-                 *
-                 * \param [in] _name   The name of the method to be called in the service.
-                 * \param [in] _type   The type of message
-                 * \param [in] _name   The sequential id of the message
-                 *
-                 * \throws TException  Passed through from wrapped <code>TProtocol</code> instance.
-                 */
-                uint32_t writeMessageBegin_virt(
-                    const std::string& _name, 
-                    const TMessageType _type, 
-                    const int32_t _seqid);
-            private:
-                const std::string serviceName;
-                const std::string separator;
-            };
+  /**
+   * Prepends the service name to the function name, separated by TMultiplexedProtocol::SEPARATOR.
+   *
+   * \param [in] _name   The name of the method to be called in the service.
+   * \param [in] _type   The type of message
+   * \param [in] _name   The sequential id of the message
+   *
+   * \throws TException  Passed through from wrapped <code>TProtocol</code> instance.
+   */
+  uint32_t writeMessageBegin_virt(const std::string& _name,
+                                  const TMessageType _type,
+                                  const int32_t _seqid);
 
-        }
-    }
+private:
+  const std::string serviceName;
+  const std::string separator;
+};
+}
+}
 }
 
 #endif // THRIFT_TMULTIPLEXEDPROTOCOL_H_
diff --git a/lib/cpp/src/thrift/protocol/TProtocol.cpp b/lib/cpp/src/thrift/protocol/TProtocol.cpp
new file mode 100644
index 0000000..c378aca
--- /dev/null
+++ b/lib/cpp/src/thrift/protocol/TProtocol.cpp
@@ -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.
+ */
+
+#include <thrift/protocol/TProtocol.h>
+
+namespace apache {
+namespace thrift {
+namespace protocol {
+
+TProtocol::~TProtocol() {}
+uint32_t TProtocol::skip_virt(TType type) {
+  return ::apache::thrift::protocol::skip(*this, type);
+}
+
+TProtocolFactory::~TProtocolFactory() {}
+
+}}} // apache::thrift::protocol
diff --git a/lib/cpp/src/thrift/protocol/TProtocol.h b/lib/cpp/src/thrift/protocol/TProtocol.h
index d6ecc0f..bbc6816 100644
--- a/lib/cpp/src/thrift/protocol/TProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TProtocol.h
@@ -20,11 +20,15 @@
 #ifndef _THRIFT_PROTOCOL_TPROTOCOL_H_
 #define _THRIFT_PROTOCOL_TPROTOCOL_H_ 1
 
+#ifdef _WIN32
+// Need to come before any Windows.h includes
+#include <Winsock2.h>
+#endif
+
 #include <thrift/transport/TTransport.h>
 #include <thrift/protocol/TProtocolException.h>
 
-#include <boost/shared_ptr.hpp>
-#include <boost/static_assert.hpp>
+#include <memory>
 
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
@@ -33,18 +37,17 @@
 #include <string>
 #include <map>
 #include <vector>
-
+#include <climits>
 
 // Use this to get around strict aliasing rules.
 // For example, uint64_t i = bitwise_cast<uint64_t>(returns_double());
 // The most obvious implementation is to just cast a pointer,
 // but that doesn't work.
 // For a pretty in-depth explanation of the problem, see
-// http://www.cellperformance.com/mike_acton/2006/06/ (...)
-// understanding_strict_aliasing.html
+// http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html
 template <typename To, typename From>
 static inline To bitwise_cast(From from) {
-  BOOST_STATIC_ASSERT(sizeof(From) == sizeof(To));
+  static_assert(sizeof(From) == sizeof(To), "sizeof(From) == sizeof(To)");
 
   // BAD!!!  These are all broken with -O2.
   //return *reinterpret_cast<To*>(&from);  // BAD!!!
@@ -75,10 +78,6 @@
 }
 
 
-namespace apache { namespace thrift { namespace protocol {
-
-using apache::thrift::transport::TTransport;
-
 #ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
 #endif
@@ -103,12 +102,18 @@
 #endif
 
 #if __THRIFT_BYTE_ORDER == __THRIFT_BIG_ENDIAN
-#  define ntohll(n) (n)
-#  define htonll(n) (n)
+# if !defined(THRIFT_ntohll)
+#  define THRIFT_ntohll(n) (n)
+#  define THRIFT_htonll(n) (n)
+# endif
 # if defined(__GNUC__) && defined(__GLIBC__)
 #  include <byteswap.h>
-#  define htolell(n) bswap_64(n)
-#  define letohll(n) bswap_64(n)
+#  define THRIFT_htolell(n) bswap_64(n)
+#  define THRIFT_letohll(n) bswap_64(n)
+#  define THRIFT_htolel(n) bswap_32(n)
+#  define THRIFT_letohl(n) bswap_32(n)
+#  define THRIFT_htoles(n) bswap_16(n)
+#  define THRIFT_letohs(n) bswap_16(n)
 # else /* GNUC & GLIBC */
 #  define bswap_64(n) \
       ( (((n) & 0xff00000000000000ull) >> 56) \
@@ -119,27 +124,49 @@
       | (((n) & 0x0000000000ff0000ull) << 24) \
       | (((n) & 0x000000000000ff00ull) << 40) \
       | (((n) & 0x00000000000000ffull) << 56) )
-#  define htolell(n) bswap_64(n)
-#  define letohll(n) bswap_64(n)
+#  define bswap_32(n) \
+      ( (((n) & 0xff000000ul) >> 24) \
+      | (((n) & 0x00ff0000ul) >> 8)  \
+      | (((n) & 0x0000ff00ul) << 8)  \
+      | (((n) & 0x000000fful) << 24) )
+#  define bswap_16(n) \
+      ( (((n) & ((unsigned short)0xff00ul)) >> 8)  \
+      | (((n) & ((unsigned short)0x00fful)) << 8)  )
+#  define THRIFT_htolell(n) bswap_64(n)
+#  define THRIFT_letohll(n) bswap_64(n)
+#  define THRIFT_htolel(n) bswap_32(n)
+#  define THRIFT_letohl(n) bswap_32(n)
+#  define THRIFT_htoles(n) bswap_16(n)
+#  define THRIFT_letohs(n) bswap_16(n)
 # endif /* GNUC & GLIBC */
 #elif __THRIFT_BYTE_ORDER == __THRIFT_LITTLE_ENDIAN
-#  define htolell(n) (n)
-#  define letohll(n) (n)
+#  define THRIFT_htolell(n) (n)
+#  define THRIFT_letohll(n) (n)
+#  define THRIFT_htolel(n) (n)
+#  define THRIFT_letohl(n) (n)
+#  define THRIFT_htoles(n) (n)
+#  define THRIFT_letohs(n) (n)
 # if defined(__GNUC__) && defined(__GLIBC__)
 #  include <byteswap.h>
-#  define ntohll(n) bswap_64(n)
-#  define htonll(n) bswap_64(n)
+#  define THRIFT_ntohll(n) bswap_64(n)
+#  define THRIFT_htonll(n) bswap_64(n)
 # elif defined(_MSC_VER) /* Microsoft Visual C++ */
-#  define ntohll(n) ( _byteswap_uint64((uint64_t)n) )
-#  define htonll(n) ( _byteswap_uint64((uint64_t)n) )
-# else /* Not GNUC/GLIBC or MSVC */
-#  define ntohll(n) ( (((uint64_t)ntohl((uint32_t)n)) << 32) + ntohl((uint32_t)(n >> 32)) )
-#  define htonll(n) ( (((uint64_t)htonl((uint32_t)n)) << 32) + htonl((uint32_t)(n >> 32)) )
+#  define THRIFT_ntohll(n) ( _byteswap_uint64((uint64_t)n) )
+#  define THRIFT_htonll(n) ( _byteswap_uint64((uint64_t)n) )
+# elif !defined(THRIFT_ntohll) /* Not GNUC/GLIBC or MSVC */
+#  define THRIFT_ntohll(n) ( (((uint64_t)ntohl((uint32_t)n)) << 32) + ntohl((uint32_t)(n >> 32)) )
+#  define THRIFT_htonll(n) ( (((uint64_t)htonl((uint32_t)n)) << 32) + htonl((uint32_t)(n >> 32)) )
 # endif /* GNUC/GLIBC or MSVC or something else */
 #else /* __THRIFT_BYTE_ORDER */
-# error "Can't define htonll or ntohll!"
+# error "Can't define THRIFT_htonll or THRIFT_ntohll!"
 #endif
 
+namespace apache {
+namespace thrift {
+namespace protocol {
+
+using apache::thrift::transport::TTransport;
+
 /**
  * Enumerated definition of the types that the Thrift protocol supports.
  * Take special note of the T_END type which is used specifically to mark
@@ -177,111 +204,7 @@
   T_ONEWAY     = 4
 };
 
-
-/**
- * Helper template for implementing TProtocol::skip().
- *
- * Templatized to avoid having to make virtual function calls.
- */
-template <class Protocol_>
-uint32_t skip(Protocol_& prot, TType type) {
-  switch (type) {
-  case T_BOOL:
-    {
-      bool boolv;
-      return prot.readBool(boolv);
-    }
-  case T_BYTE:
-    {
-      int8_t bytev;
-      return prot.readByte(bytev);
-    }
-  case T_I16:
-    {
-      int16_t i16;
-      return prot.readI16(i16);
-    }
-  case T_I32:
-    {
-      int32_t i32;
-      return prot.readI32(i32);
-    }
-  case T_I64:
-    {
-      int64_t i64;
-      return prot.readI64(i64);
-    }
-  case T_DOUBLE:
-    {
-      double dub;
-      return prot.readDouble(dub);
-    }
-  case T_STRING:
-    {
-      std::string str;
-      return prot.readBinary(str);
-    }
-  case T_STRUCT:
-    {
-      uint32_t result = 0;
-      std::string name;
-      int16_t fid;
-      TType ftype;
-      result += prot.readStructBegin(name);
-      while (true) {
-        result += prot.readFieldBegin(name, ftype, fid);
-        if (ftype == T_STOP) {
-          break;
-        }
-        result += skip(prot, ftype);
-        result += prot.readFieldEnd();
-      }
-      result += prot.readStructEnd();
-      return result;
-    }
-  case T_MAP:
-    {
-      uint32_t result = 0;
-      TType keyType;
-      TType valType;
-      uint32_t i, size;
-      result += prot.readMapBegin(keyType, valType, size);
-      for (i = 0; i < size; i++) {
-        result += skip(prot, keyType);
-        result += skip(prot, valType);
-      }
-      result += prot.readMapEnd();
-      return result;
-    }
-  case T_SET:
-    {
-      uint32_t result = 0;
-      TType elemType;
-      uint32_t i, size;
-      result += prot.readSetBegin(elemType, size);
-      for (i = 0; i < size; i++) {
-        result += skip(prot, elemType);
-      }
-      result += prot.readSetEnd();
-      return result;
-    }
-  case T_LIST:
-    {
-      uint32_t result = 0;
-      TType elemType;
-      uint32_t i, size;
-      result += prot.readListBegin(elemType, size);
-      for (i = 0; i < size; i++) {
-        result += skip(prot, elemType);
-      }
-      result += prot.readListEnd();
-      return result;
-    }
-  case T_STOP: case T_VOID: case T_U64: case T_UTF8: case T_UTF16:
-    break;
-  }
-  return 0;
-}
+static const uint32_t DEFAULT_RECURSION_LIMIT = 64;
 
 /**
  * Abstract class for a thrift protocol driver. These are all the methods that
@@ -298,8 +221,8 @@
  *
  */
 class TProtocol {
- public:
-  virtual ~TProtocol() {}
+public:
+  virtual ~TProtocol();
 
   /**
    * Writing functions.
@@ -311,7 +234,6 @@
 
   virtual uint32_t writeMessageEnd_virt() = 0;
 
-
   virtual uint32_t writeStructBegin_virt(const char* name) = 0;
 
   virtual uint32_t writeStructEnd_virt() = 0;
@@ -324,19 +246,16 @@
 
   virtual uint32_t writeFieldStop_virt() = 0;
 
-  virtual uint32_t writeMapBegin_virt(const TType keyType,
-                                      const TType valType,
-                                      const uint32_t size) = 0;
+  virtual uint32_t writeMapBegin_virt(const TType keyType, const TType valType, const uint32_t size)
+      = 0;
 
   virtual uint32_t writeMapEnd_virt() = 0;
 
-  virtual uint32_t writeListBegin_virt(const TType elemType,
-                                       const uint32_t size) = 0;
+  virtual uint32_t writeListBegin_virt(const TType elemType, const uint32_t size) = 0;
 
   virtual uint32_t writeListEnd_virt() = 0;
 
-  virtual uint32_t writeSetBegin_virt(const TType elemType,
-                                      const uint32_t size) = 0;
+  virtual uint32_t writeSetBegin_virt(const TType elemType, const uint32_t size) = 0;
 
   virtual uint32_t writeSetEnd_virt() = 0;
 
@@ -368,7 +287,6 @@
     return writeMessageEnd_virt();
   }
 
-
   uint32_t writeStructBegin(const char* name) {
     T_VIRTUAL_CALL();
     return writeStructBegin_virt(name);
@@ -379,9 +297,7 @@
     return writeStructEnd_virt();
   }
 
-  uint32_t writeFieldBegin(const char* name,
-                           const TType fieldType,
-                           const int16_t fieldId) {
+  uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId) {
     T_VIRTUAL_CALL();
     return writeFieldBegin_virt(name, fieldType, fieldId);
   }
@@ -396,9 +312,7 @@
     return writeFieldStop_virt();
   }
 
-  uint32_t writeMapBegin(const TType keyType,
-                         const TType valType,
-                         const uint32_t size) {
+  uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size) {
     T_VIRTUAL_CALL();
     return writeMapBegin_virt(keyType, valType, size);
   }
@@ -482,25 +396,19 @@
 
   virtual uint32_t readStructEnd_virt() = 0;
 
-  virtual uint32_t readFieldBegin_virt(std::string& name,
-                                       TType& fieldType,
-                                       int16_t& fieldId) = 0;
+  virtual uint32_t readFieldBegin_virt(std::string& name, TType& fieldType, int16_t& fieldId) = 0;
 
   virtual uint32_t readFieldEnd_virt() = 0;
 
-  virtual uint32_t readMapBegin_virt(TType& keyType,
-                                     TType& valType,
-                                     uint32_t& size) = 0;
+  virtual uint32_t readMapBegin_virt(TType& keyType, TType& valType, uint32_t& size) = 0;
 
   virtual uint32_t readMapEnd_virt() = 0;
 
-  virtual uint32_t readListBegin_virt(TType& elemType,
-                                      uint32_t& size) = 0;
+  virtual uint32_t readListBegin_virt(TType& elemType, uint32_t& size) = 0;
 
   virtual uint32_t readListEnd_virt() = 0;
 
-  virtual uint32_t readSetBegin_virt(TType& elemType,
-                                     uint32_t& size) = 0;
+  virtual uint32_t readSetBegin_virt(TType& elemType, uint32_t& size) = 0;
 
   virtual uint32_t readSetEnd_virt() = 0;
 
@@ -522,9 +430,7 @@
 
   virtual uint32_t readBinary_virt(std::string& str) = 0;
 
-  uint32_t readMessageBegin(std::string& name,
-                            TMessageType& messageType,
-                            int32_t& seqid) {
+  uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid) {
     T_VIRTUAL_CALL();
     return readMessageBegin_virt(name, messageType, seqid);
   }
@@ -544,9 +450,7 @@
     return readStructEnd_virt();
   }
 
-  uint32_t readFieldBegin(std::string& name,
-                          TType& fieldType,
-                          int16_t& fieldId) {
+  uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) {
     T_VIRTUAL_CALL();
     return readFieldBegin_virt(name, fieldType, fieldId);
   }
@@ -643,44 +547,63 @@
     T_VIRTUAL_CALL();
     return skip_virt(type);
   }
-  virtual uint32_t skip_virt(TType type) {
-    return ::apache::thrift::protocol::skip(*this, type);
-  }
+  virtual uint32_t skip_virt(TType type);
 
-  inline boost::shared_ptr<TTransport> getTransport() {
-    return ptrans_;
-  }
+  inline std::shared_ptr<TTransport> getTransport() { return ptrans_; }
 
   // TODO: remove these two calls, they are for backwards
   // compatibility
-  inline boost::shared_ptr<TTransport> getInputTransport() {
-    return ptrans_;
-  }
-  inline boost::shared_ptr<TTransport> getOutputTransport() {
-    return ptrans_;
-  }
+  inline std::shared_ptr<TTransport> getInputTransport() { return ptrans_; }
+  inline std::shared_ptr<TTransport> getOutputTransport() { return ptrans_; }
 
- protected:
-  TProtocol(boost::shared_ptr<TTransport> ptrans):
-    ptrans_(ptrans) {
+  // input and output recursion depth are kept separate so that one protocol
+  // can be used concurrently for both input and output.
+  void incrementInputRecursionDepth() {
+    if (recursion_limit_ < ++input_recursion_depth_) {
+      throw TProtocolException(TProtocolException::DEPTH_LIMIT);
+    }
   }
+  void decrementInputRecursionDepth() { --input_recursion_depth_; }
 
-  boost::shared_ptr<TTransport> ptrans_;
+  void incrementOutputRecursionDepth() {
+    if (recursion_limit_ < ++output_recursion_depth_) {
+      throw TProtocolException(TProtocolException::DEPTH_LIMIT);
+    }
+  }
+  void decrementOutputRecursionDepth() { --output_recursion_depth_; }
 
- private:
+  uint32_t getRecursionLimit() const {return recursion_limit_;}
+  void setRecurisionLimit(uint32_t depth) {recursion_limit_ = depth;}
+
+protected:
+  TProtocol(std::shared_ptr<TTransport> ptrans)
+    : ptrans_(ptrans), input_recursion_depth_(0), output_recursion_depth_(0), recursion_limit_(DEFAULT_RECURSION_LIMIT)
+  {}
+
+  std::shared_ptr<TTransport> ptrans_;
+
+private:
   TProtocol() {}
+  uint32_t input_recursion_depth_;
+  uint32_t output_recursion_depth_;
+  uint32_t recursion_limit_;
 };
 
 /**
  * Constructs input and output protocol objects given transports.
  */
 class TProtocolFactory {
- public:
+public:
   TProtocolFactory() {}
 
-  virtual ~TProtocolFactory() {}
+  virtual ~TProtocolFactory();
 
-  virtual boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) = 0;
+  virtual std::shared_ptr<TProtocol> getProtocol(std::shared_ptr<TTransport> trans) = 0;
+  virtual std::shared_ptr<TProtocol> getProtocol(std::shared_ptr<TTransport> inTrans,
+               std::shared_ptr<TTransport> outTrans) {
+    (void)outTrans;
+    return getProtocol(inTrans);
+  }
 };
 
 /**
@@ -689,9 +612,152 @@
  * This class does nothing, and should never be instantiated.
  * It is used only by the generator code.
  */
-class TDummyProtocol : public TProtocol {
+class TDummyProtocol : public TProtocol {};
+
+// This is the default / legacy choice
+struct TNetworkBigEndian
+{
+  static uint16_t toWire16(uint16_t x)   {return htons(x);}
+  static uint32_t toWire32(uint32_t x)   {return htonl(x);}
+  static uint64_t toWire64(uint64_t x)   {return THRIFT_htonll(x);}
+  static uint16_t fromWire16(uint16_t x) {return ntohs(x);}
+  static uint32_t fromWire32(uint32_t x) {return ntohl(x);}
+  static uint64_t fromWire64(uint64_t x) {return THRIFT_ntohll(x);}
 };
 
+// On most systems, this will be a bit faster than TNetworkBigEndian
+struct TNetworkLittleEndian
+{
+  static uint16_t toWire16(uint16_t x)   {return THRIFT_htoles(x);}
+  static uint32_t toWire32(uint32_t x)   {return THRIFT_htolel(x);}
+  static uint64_t toWire64(uint64_t x)   {return THRIFT_htolell(x);}
+  static uint16_t fromWire16(uint16_t x) {return THRIFT_letohs(x);}
+  static uint32_t fromWire32(uint32_t x) {return THRIFT_letohl(x);}
+  static uint64_t fromWire64(uint64_t x) {return THRIFT_letohll(x);}
+};
+
+struct TOutputRecursionTracker {
+  TProtocol &prot_;
+  TOutputRecursionTracker(TProtocol &prot) : prot_(prot) {
+    prot_.incrementOutputRecursionDepth();
+  }
+  ~TOutputRecursionTracker() {
+    prot_.decrementOutputRecursionDepth();
+  }
+};
+
+struct TInputRecursionTracker {
+  TProtocol &prot_;
+  TInputRecursionTracker(TProtocol &prot) : prot_(prot) {
+    prot_.incrementInputRecursionDepth();
+  }
+  ~TInputRecursionTracker() {
+    prot_.decrementInputRecursionDepth();
+  }
+};
+
+/**
+ * Helper template for implementing TProtocol::skip().
+ *
+ * Templatized to avoid having to make virtual function calls.
+ */
+template <class Protocol_>
+uint32_t skip(Protocol_& prot, TType type) {
+  TInputRecursionTracker tracker(prot);
+
+  switch (type) {
+  case T_BOOL: {
+    bool boolv;
+    return prot.readBool(boolv);
+  }
+  case T_BYTE: {
+    int8_t bytev = 0;
+    return prot.readByte(bytev);
+  }
+  case T_I16: {
+    int16_t i16;
+    return prot.readI16(i16);
+  }
+  case T_I32: {
+    int32_t i32;
+    return prot.readI32(i32);
+  }
+  case T_I64: {
+    int64_t i64;
+    return prot.readI64(i64);
+  }
+  case T_DOUBLE: {
+    double dub;
+    return prot.readDouble(dub);
+  }
+  case T_STRING: {
+    std::string str;
+    return prot.readBinary(str);
+  }
+  case T_STRUCT: {
+    uint32_t result = 0;
+    std::string name;
+    int16_t fid;
+    TType ftype;
+    result += prot.readStructBegin(name);
+    while (true) {
+      result += prot.readFieldBegin(name, ftype, fid);
+      if (ftype == T_STOP) {
+        break;
+      }
+      result += skip(prot, ftype);
+      result += prot.readFieldEnd();
+    }
+    result += prot.readStructEnd();
+    return result;
+  }
+  case T_MAP: {
+    uint32_t result = 0;
+    TType keyType;
+    TType valType;
+    uint32_t i, size;
+    result += prot.readMapBegin(keyType, valType, size);
+    for (i = 0; i < size; i++) {
+      result += skip(prot, keyType);
+      result += skip(prot, valType);
+    }
+    result += prot.readMapEnd();
+    return result;
+  }
+  case T_SET: {
+    uint32_t result = 0;
+    TType elemType;
+    uint32_t i, size;
+    result += prot.readSetBegin(elemType, size);
+    for (i = 0; i < size; i++) {
+      result += skip(prot, elemType);
+    }
+    result += prot.readSetEnd();
+    return result;
+  }
+  case T_LIST: {
+    uint32_t result = 0;
+    TType elemType;
+    uint32_t i, size;
+    result += prot.readListBegin(elemType, size);
+    for (i = 0; i < size; i++) {
+      result += skip(prot, elemType);
+    }
+    result += prot.readListEnd();
+    return result;
+  }
+  case T_STOP:
+  case T_VOID:
+  case T_U64:
+  case T_UTF8:
+  case T_UTF16:
+    break;
+  default:
+    throw TProtocolException(TProtocolException::INVALID_DATA);
+  }
+  return 0;
+}
+
 }}} // apache::thrift::protocol
 
 #endif // #define _THRIFT_PROTOCOL_TPROTOCOL_H_ 1
diff --git a/lib/cpp/src/thrift/protocol/TProtocolDecorator.h b/lib/cpp/src/thrift/protocol/TProtocolDecorator.h
index 7850bc5..743a0f4 100644
--- a/lib/cpp/src/thrift/protocol/TProtocolDecorator.h
+++ b/lib/cpp/src/thrift/protocol/TProtocolDecorator.h
@@ -21,113 +21,131 @@
 #define THRIFT_TPROTOCOLDECORATOR_H_ 1
 
 #include <thrift/protocol/TProtocol.h>
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
-namespace apache 
-{ 
-    namespace thrift 
-    { 
-        namespace protocol 
-        {
-            using boost::shared_ptr;
+namespace apache {
+namespace thrift {
+namespace protocol {
+using std::shared_ptr;
 
-            /**
-             * <code>TProtocolDecorator</code> forwards all requests to an enclosed
-             * <code>TProtocol</code> instance, providing a way to author concise
-             * concrete decorator subclasses.  
-             *
-             * <p>See p.175 of Design Patterns (by Gamma et al.)</p>
-             * 
-             * @see apache::thrift::protocol::TMultiplexedProtocol
-             */
-            class TProtocolDecorator : public TProtocol
-            {
-            public:
-                virtual ~TProtocolDecorator() {}
-                
-                // Desc: Initializes the protocol decorator object.
-                TProtocolDecorator( shared_ptr<TProtocol> proto ) 
-                    : TProtocol(proto->getTransport()), protocol(proto)
-                {
-                }
+/**
+ * <code>TProtocolDecorator</code> forwards all requests to an enclosed
+ * <code>TProtocol</code> instance, providing a way to author concise
+ * concrete decorator subclasses.
+ *
+ * <p>See p.175 of Design Patterns (by Gamma et al.)</p>
+ *
+ * @see apache::thrift::protocol::TMultiplexedProtocol
+ */
+class TProtocolDecorator : public TProtocol {
+public:
+  virtual ~TProtocolDecorator() {}
 
-                virtual uint32_t writeMessageBegin_virt(
-                    const std::string& name, 
-                    const TMessageType messageType, 
-                    const int32_t seqid)
-                {
-                    return protocol->writeMessageBegin(name, messageType, seqid); 
-                }
-                virtual uint32_t writeMessageEnd_virt() { return protocol->writeMessageEnd(); }
-                virtual uint32_t writeStructBegin_virt(const char* name) { return protocol->writeStructBegin(name); }
-                virtual uint32_t writeStructEnd_virt() { return protocol->writeStructEnd(); }
+  // Desc: Initializes the protocol decorator object.
+  TProtocolDecorator(shared_ptr<TProtocol> proto)
+    : TProtocol(proto->getTransport()), protocol(proto) {}
 
-                virtual uint32_t writeFieldBegin_virt(const char* name,
-                    const TType fieldType,
-                    const int16_t fieldId) { return protocol->writeFieldBegin(name,fieldType,fieldId); }
+  virtual uint32_t writeMessageBegin_virt(const std::string& name,
+                                          const TMessageType messageType,
+                                          const int32_t seqid) {
+    return protocol->writeMessageBegin(name, messageType, seqid);
+  }
+  virtual uint32_t writeMessageEnd_virt() { return protocol->writeMessageEnd(); }
+  virtual uint32_t writeStructBegin_virt(const char* name) {
+    return protocol->writeStructBegin(name);
+  }
+  virtual uint32_t writeStructEnd_virt() { return protocol->writeStructEnd(); }
 
-                virtual uint32_t writeFieldEnd_virt()  { return protocol->writeFieldEnd(); }
-                virtual uint32_t writeFieldStop_virt() { return protocol->writeFieldStop(); }
+  virtual uint32_t writeFieldBegin_virt(const char* name,
+                                        const TType fieldType,
+                                        const int16_t fieldId) {
+    return protocol->writeFieldBegin(name, fieldType, fieldId);
+  }
 
-                virtual uint32_t writeMapBegin_virt(const TType keyType,
-                    const TType valType,
-                    const uint32_t size) { return protocol->writeMapBegin(keyType,valType,size); }
+  virtual uint32_t writeFieldEnd_virt() { return protocol->writeFieldEnd(); }
+  virtual uint32_t writeFieldStop_virt() { return protocol->writeFieldStop(); }
 
-                virtual uint32_t writeMapEnd_virt() { return protocol->writeMapEnd(); }
+  virtual uint32_t writeMapBegin_virt(const TType keyType,
+                                      const TType valType,
+                                      const uint32_t size) {
+    return protocol->writeMapBegin(keyType, valType, size);
+  }
 
-                virtual uint32_t writeListBegin_virt(const TType elemType, const uint32_t size) { return protocol->writeListBegin(elemType,size); }
-                virtual uint32_t writeListEnd_virt() { return protocol->writeListEnd(); }
+  virtual uint32_t writeMapEnd_virt() { return protocol->writeMapEnd(); }
 
-                virtual uint32_t writeSetBegin_virt(const TType elemType, const uint32_t size) { return protocol->writeSetBegin(elemType,size); }
-                virtual uint32_t writeSetEnd_virt() { return protocol->writeSetEnd(); }
+  virtual uint32_t writeListBegin_virt(const TType elemType, const uint32_t size) {
+    return protocol->writeListBegin(elemType, size);
+  }
+  virtual uint32_t writeListEnd_virt() { return protocol->writeListEnd(); }
 
-                virtual uint32_t writeBool_virt(const bool value)  { return protocol->writeBool(value); }
-                virtual uint32_t writeByte_virt(const int8_t byte) { return protocol->writeByte(byte); }
-                virtual uint32_t writeI16_virt(const int16_t i16)  { return protocol->writeI16(i16); }
-                virtual uint32_t writeI32_virt(const int32_t i32)  { return protocol->writeI32(i32); }
-                virtual uint32_t writeI64_virt(const int64_t i64)  { return protocol->writeI64(i64); }
+  virtual uint32_t writeSetBegin_virt(const TType elemType, const uint32_t size) {
+    return protocol->writeSetBegin(elemType, size);
+  }
+  virtual uint32_t writeSetEnd_virt() { return protocol->writeSetEnd(); }
 
-                virtual uint32_t writeDouble_virt(const double dub) { return protocol->writeDouble(dub); }
-                virtual uint32_t writeString_virt(const std::string& str) { return protocol->writeString(str); }
-                virtual uint32_t writeBinary_virt(const std::string& str) { return protocol->writeBinary(str); }
+  virtual uint32_t writeBool_virt(const bool value) { return protocol->writeBool(value); }
+  virtual uint32_t writeByte_virt(const int8_t byte) { return protocol->writeByte(byte); }
+  virtual uint32_t writeI16_virt(const int16_t i16) { return protocol->writeI16(i16); }
+  virtual uint32_t writeI32_virt(const int32_t i32) { return protocol->writeI32(i32); }
+  virtual uint32_t writeI64_virt(const int64_t i64) { return protocol->writeI64(i64); }
 
-                virtual uint32_t readMessageBegin_virt(std::string& name, TMessageType& messageType, int32_t& seqid) { return protocol->readMessageBegin(name,messageType,seqid); }
-                virtual uint32_t readMessageEnd_virt() { return protocol->readMessageEnd(); }
+  virtual uint32_t writeDouble_virt(const double dub) { return protocol->writeDouble(dub); }
+  virtual uint32_t writeString_virt(const std::string& str) { return protocol->writeString(str); }
+  virtual uint32_t writeBinary_virt(const std::string& str) { return protocol->writeBinary(str); }
 
-                virtual uint32_t readStructBegin_virt(std::string& name) { return protocol->readStructBegin(name); }
-                virtual uint32_t readStructEnd_virt() { return protocol->readStructEnd(); }
+  virtual uint32_t readMessageBegin_virt(std::string& name,
+                                         TMessageType& messageType,
+                                         int32_t& seqid) {
+    return protocol->readMessageBegin(name, messageType, seqid);
+  }
+  virtual uint32_t readMessageEnd_virt() { return protocol->readMessageEnd(); }
 
-                virtual uint32_t readFieldBegin_virt(std::string& name, TType& fieldType, int16_t& fieldId) { return protocol->readFieldBegin(name, fieldType, fieldId); }
-                virtual uint32_t readFieldEnd_virt() { return protocol->readFieldEnd(); }
+  virtual uint32_t readStructBegin_virt(std::string& name) {
+    return protocol->readStructBegin(name);
+  }
+  virtual uint32_t readStructEnd_virt() { return protocol->readStructEnd(); }
 
-                virtual uint32_t readMapBegin_virt(TType& keyType, TType& valType, uint32_t& size) { return protocol->readMapBegin(keyType,valType,size); }
-                virtual uint32_t readMapEnd_virt() { return protocol->readMapEnd(); }
+  virtual uint32_t readFieldBegin_virt(std::string& name, TType& fieldType, int16_t& fieldId) {
+    return protocol->readFieldBegin(name, fieldType, fieldId);
+  }
+  virtual uint32_t readFieldEnd_virt() { return protocol->readFieldEnd(); }
 
-                virtual uint32_t readListBegin_virt(TType& elemType, uint32_t& size) { return protocol->readListBegin(elemType,size); }
-                virtual uint32_t readListEnd_virt() { return protocol->readListEnd(); }
+  virtual uint32_t readMapBegin_virt(TType& keyType, TType& valType, uint32_t& size) {
+    return protocol->readMapBegin(keyType, valType, size);
+  }
+  virtual uint32_t readMapEnd_virt() { return protocol->readMapEnd(); }
 
-                virtual uint32_t readSetBegin_virt(TType& elemType, uint32_t& size) { return protocol->readSetBegin(elemType,size); }
-                virtual uint32_t readSetEnd_virt() { return protocol->readSetEnd(); }
+  virtual uint32_t readListBegin_virt(TType& elemType, uint32_t& size) {
+    return protocol->readListBegin(elemType, size);
+  }
+  virtual uint32_t readListEnd_virt() { return protocol->readListEnd(); }
 
-                virtual uint32_t readBool_virt(bool& value) { return protocol->readBool(value); }
-                virtual uint32_t readBool_virt(std::vector<bool>::reference value) { return protocol->readBool(value); }
-                
-                virtual uint32_t readByte_virt(int8_t& byte) { return protocol->readByte(byte); }
+  virtual uint32_t readSetBegin_virt(TType& elemType, uint32_t& size) {
+    return protocol->readSetBegin(elemType, size);
+  }
+  virtual uint32_t readSetEnd_virt() { return protocol->readSetEnd(); }
 
-                virtual uint32_t readI16_virt(int16_t& i16) { return protocol->readI16(i16); }
-                virtual uint32_t readI32_virt(int32_t& i32) { return protocol->readI32(i32); }
-                virtual uint32_t readI64_virt(int64_t& i64) { return protocol->readI64(i64); }
+  virtual uint32_t readBool_virt(bool& value) { return protocol->readBool(value); }
+  virtual uint32_t readBool_virt(std::vector<bool>::reference value) {
+    return protocol->readBool(value);
+  }
 
-                virtual uint32_t readDouble_virt(double& dub) { return protocol->readDouble(dub); }
+  virtual uint32_t readByte_virt(int8_t& byte) { return protocol->readByte(byte); }
 
-                virtual uint32_t readString_virt(std::string& str) { return protocol->readString(str); }
-                virtual uint32_t readBinary_virt(std::string& str) { return protocol->readBinary(str); }
+  virtual uint32_t readI16_virt(int16_t& i16) { return protocol->readI16(i16); }
+  virtual uint32_t readI32_virt(int32_t& i32) { return protocol->readI32(i32); }
+  virtual uint32_t readI64_virt(int64_t& i64) { return protocol->readI64(i64); }
 
-            private:
-                shared_ptr<TProtocol> protocol;    
-            };
-        }
-    }
-} 
+  virtual uint32_t readDouble_virt(double& dub) { return protocol->readDouble(dub); }
+
+  virtual uint32_t readString_virt(std::string& str) { return protocol->readString(str); }
+  virtual uint32_t readBinary_virt(std::string& str) { return protocol->readBinary(str); }
+
+private:
+  shared_ptr<TProtocol> protocol;
+};
+}
+}
+}
 
 #endif // THRIFT_TPROTOCOLDECORATOR_H_
diff --git a/lib/cpp/src/thrift/protocol/TProtocolException.h b/lib/cpp/src/thrift/protocol/TProtocolException.h
index a03d3c8..10178e1 100644
--- a/lib/cpp/src/thrift/protocol/TProtocolException.h
+++ b/lib/cpp/src/thrift/protocol/TProtocolException.h
@@ -22,7 +22,9 @@
 
 #include <string>
 
-namespace apache { namespace thrift { namespace protocol {
+namespace apache {
+namespace thrift {
+namespace protocol {
 
 /**
  * Class to encapsulate all the possible types of protocol errors that may
@@ -33,37 +35,31 @@
  *
  */
 class TProtocolException : public apache::thrift::TException {
- public:
-
+public:
   /**
    * Error codes for the various types of exceptions.
    */
-  enum TProtocolExceptionType
-  { UNKNOWN = 0
-  , INVALID_DATA = 1
-  , NEGATIVE_SIZE = 2
-  , SIZE_LIMIT = 3
-  , BAD_VERSION = 4
-  , NOT_IMPLEMENTED = 5
+  enum TProtocolExceptionType {
+    UNKNOWN = 0,
+    INVALID_DATA = 1,
+    NEGATIVE_SIZE = 2,
+    SIZE_LIMIT = 3,
+    BAD_VERSION = 4,
+    NOT_IMPLEMENTED = 5,
+    DEPTH_LIMIT = 6
   };
 
-  TProtocolException() :
-    apache::thrift::TException(),
-    type_(UNKNOWN) {}
+  TProtocolException() : apache::thrift::TException(), type_(UNKNOWN) {}
 
-  TProtocolException(TProtocolExceptionType type) :
-    apache::thrift::TException(),
-    type_(type) {}
+  TProtocolException(TProtocolExceptionType type) : apache::thrift::TException(), type_(type) {}
 
-  TProtocolException(const std::string& message) :
-    apache::thrift::TException(message),
-    type_(UNKNOWN) {}
+  TProtocolException(const std::string& message)
+    : apache::thrift::TException(message), type_(UNKNOWN) {}
 
-  TProtocolException(TProtocolExceptionType type, const std::string& message) :
-    apache::thrift::TException(message),
-    type_(type) {}
+  TProtocolException(TProtocolExceptionType type, const std::string& message)
+    : apache::thrift::TException(message), type_(type) {}
 
-  virtual ~TProtocolException() throw() {}
+  virtual ~TProtocolException() noexcept {}
 
   /**
    * Returns an error code that provides information about the type of error
@@ -71,34 +67,39 @@
    *
    * @return Error code
    */
-  TProtocolExceptionType getType() {
-    return type_;
-  }
+  TProtocolExceptionType getType() const { return type_; }
 
-  virtual const char* what() const throw() {
+  virtual const char* what() const noexcept {
     if (message_.empty()) {
       switch (type_) {
-        case UNKNOWN         : return "TProtocolException: Unknown protocol exception";
-        case INVALID_DATA    : return "TProtocolException: Invalid data";
-        case NEGATIVE_SIZE   : return "TProtocolException: Negative size";
-        case SIZE_LIMIT      : return "TProtocolException: Exceeded size limit";
-        case BAD_VERSION     : return "TProtocolException: Invalid version";
-        case NOT_IMPLEMENTED : return "TProtocolException: Not implemented";
-        default              : return "TProtocolException: (Invalid exception type)";
+      case UNKNOWN:
+        return "TProtocolException: Unknown protocol exception";
+      case INVALID_DATA:
+        return "TProtocolException: Invalid data";
+      case NEGATIVE_SIZE:
+        return "TProtocolException: Negative size";
+      case SIZE_LIMIT:
+        return "TProtocolException: Exceeded size limit";
+      case BAD_VERSION:
+        return "TProtocolException: Invalid version";
+      case NOT_IMPLEMENTED:
+        return "TProtocolException: Not implemented";
+      default:
+        return "TProtocolException: (Invalid exception type)";
       }
     } else {
       return message_.c_str();
     }
   }
 
- protected:
+protected:
   /**
    * Error code
    */
   TProtocolExceptionType type_;
-
 };
-
-}}} // apache::thrift::protocol
+}
+}
+} // apache::thrift::protocol
 
 #endif // #ifndef _THRIFT_PROTOCOL_TPROTOCOLEXCEPTION_H_
diff --git a/lib/cpp/src/thrift/protocol/TProtocolTap.h b/lib/cpp/src/thrift/protocol/TProtocolTap.h
index f493f88..d000ba6 100644
--- a/lib/cpp/src/thrift/protocol/TProtocolTap.h
+++ b/lib/cpp/src/thrift/protocol/TProtocolTap.h
@@ -22,7 +22,9 @@
 
 #include <thrift/protocol/TVirtualProtocol.h>
 
-namespace apache { namespace thrift { namespace protocol {
+namespace apache {
+namespace thrift {
+namespace protocol {
 
 using apache::thrift::transport::TTransport;
 
@@ -33,17 +35,11 @@
  *
  */
 class TProtocolTap : public TVirtualProtocol<TProtocolTap> {
- public:
-   TProtocolTap(boost::shared_ptr<TProtocol> source,
-                boost::shared_ptr<TProtocol> sink)
-     : TVirtualProtocol<TProtocolTap>(source->getTransport())
-     , source_(source)
-     , sink_(sink)
-  {}
+public:
+  TProtocolTap(std::shared_ptr<TProtocol> source, std::shared_ptr<TProtocol> sink)
+    : TVirtualProtocol<TProtocolTap>(source->getTransport()), source_(source), sink_(sink) {}
 
-  uint32_t readMessageBegin(std::string& name,
-                            TMessageType& messageType,
-                            int32_t& seqid) {
+  uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid) {
     uint32_t rv = source_->readMessageBegin(name, messageType, seqid);
     sink_->writeMessageBegin(name, messageType, seqid);
     return rv;
@@ -67,9 +63,7 @@
     return rv;
   }
 
-  uint32_t readFieldBegin(std::string& name,
-                          TType& fieldType,
-                          int16_t& fieldId) {
+  uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) {
     uint32_t rv = source_->readFieldBegin(name, fieldType, fieldId);
     if (fieldType == T_STOP) {
       sink_->writeFieldStop();
@@ -79,22 +73,18 @@
     return rv;
   }
 
-
   uint32_t readFieldEnd() {
     uint32_t rv = source_->readFieldEnd();
     sink_->writeFieldEnd();
     return rv;
   }
 
-  uint32_t readMapBegin(TType& keyType,
-                        TType& valType,
-                        uint32_t& size) {
+  uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
     uint32_t rv = source_->readMapBegin(keyType, valType, size);
     sink_->writeMapBegin(keyType, valType, size);
     return rv;
   }
 
-
   uint32_t readMapEnd() {
     uint32_t rv = source_->readMapEnd();
     sink_->writeMapEnd();
@@ -107,7 +97,6 @@
     return rv;
   }
 
-
   uint32_t readListEnd() {
     uint32_t rv = source_->readListEnd();
     sink_->writeListEnd();
@@ -120,7 +109,6 @@
     return rv;
   }
 
-
   uint32_t readSetEnd() {
     uint32_t rv = source_->readSetEnd();
     sink_->writeSetEnd();
@@ -178,11 +166,12 @@
     return rv;
   }
 
- private:
-  boost::shared_ptr<TProtocol> source_;
-  boost::shared_ptr<TProtocol> sink_;
+private:
+  std::shared_ptr<TProtocol> source_;
+  std::shared_ptr<TProtocol> sink_;
 };
-
-}}} // apache::thrift::protocol
+}
+}
+} // apache::thrift::protocol
 
 #endif // #define _THRIFT_PROTOCOL_TPROTOCOLTAP_H_ 1
diff --git a/lib/cpp/src/thrift/protocol/TProtocolTypes.h b/lib/cpp/src/thrift/protocol/TProtocolTypes.h
new file mode 100644
index 0000000..6898b24
--- /dev/null
+++ b/lib/cpp/src/thrift/protocol/TProtocolTypes.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#ifndef THRIFT_PROTOCOL_TPROTOCOLTYPES_H_
+#define THRIFT_PROTOCOL_TPROTOCOLTYPES_H_ 1
+
+namespace apache {
+namespace thrift {
+namespace protocol {
+
+enum PROTOCOL_TYPES {
+  T_BINARY_PROTOCOL = 0,
+  T_JSON_PROTOCOL = 1,
+  T_COMPACT_PROTOCOL = 2,
+};
+}
+}
+} // apache::thrift::protocol
+
+#endif // #define _THRIFT_PROTOCOL_TPROTOCOLTYPES_H_ 1
diff --git a/lib/cpp/src/thrift/protocol/TVirtualProtocol.h b/lib/cpp/src/thrift/protocol/TVirtualProtocol.h
index e068725..4eea579 100644
--- a/lib/cpp/src/thrift/protocol/TVirtualProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TVirtualProtocol.h
@@ -22,7 +22,9 @@
 
 #include <thrift/protocol/TProtocol.h>
 
-namespace apache { namespace thrift { namespace protocol {
+namespace apache {
+namespace thrift {
+namespace protocol {
 
 using apache::thrift::transport::TTransport;
 
@@ -38,13 +40,11 @@
  * instead.
  */
 class TProtocolDefaults : public TProtocol {
- public:
-  uint32_t readMessageBegin(std::string& name,
-                            TMessageType& messageType,
-                            int32_t& seqid) {
-    (void) name;
-    (void) messageType;
-    (void) seqid;
+public:
+  uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid) {
+    (void)name;
+    (void)messageType;
+    (void)seqid;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
@@ -55,7 +55,7 @@
   }
 
   uint32_t readStructBegin(std::string& name) {
-    (void) name;
+    (void)name;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
@@ -65,12 +65,10 @@
                              "this protocol does not support reading (yet).");
   }
 
-  uint32_t readFieldBegin(std::string& name,
-                          TType& fieldType,
-                          int16_t& fieldId) {
-    (void) name;
-    (void) fieldType;
-    (void) fieldId;
+  uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) {
+    (void)name;
+    (void)fieldType;
+    (void)fieldId;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
@@ -81,9 +79,9 @@
   }
 
   uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
-    (void) keyType;
-    (void) valType;
-    (void) size;
+    (void)keyType;
+    (void)valType;
+    (void)size;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
@@ -94,8 +92,8 @@
   }
 
   uint32_t readListBegin(TType& elemType, uint32_t& size) {
-    (void) elemType;
-    (void) size;
+    (void)elemType;
+    (void)size;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
@@ -106,8 +104,8 @@
   }
 
   uint32_t readSetBegin(TType& elemType, uint32_t& size) {
-    (void) elemType;
-    (void) size;
+    (void)elemType;
+    (void)size;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
@@ -118,55 +116,55 @@
   }
 
   uint32_t readBool(bool& value) {
-    (void) value;
+    (void)value;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
 
   uint32_t readBool(std::vector<bool>::reference value) {
-    (void) value;
+    (void)value;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
 
   uint32_t readByte(int8_t& byte) {
-    (void) byte;
+    (void)byte;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
 
   uint32_t readI16(int16_t& i16) {
-    (void) i16;
+    (void)i16;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
 
   uint32_t readI32(int32_t& i32) {
-    (void) i32;
+    (void)i32;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
 
   uint32_t readI64(int64_t& i64) {
-    (void) i64;
+    (void)i64;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
 
   uint32_t readDouble(double& dub) {
-    (void) dub;
+    (void)dub;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
 
   uint32_t readString(std::string& str) {
-    (void) str;
+    (void)str;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
 
   uint32_t readBinary(std::string& str) {
-    (void) str;
+    (void)str;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support reading (yet).");
   }
@@ -174,9 +172,9 @@
   uint32_t writeMessageBegin(const std::string& name,
                              const TMessageType messageType,
                              const int32_t seqid) {
-    (void) name;
-    (void) messageType;
-    (void) seqid;
+    (void)name;
+    (void)messageType;
+    (void)seqid;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
@@ -186,9 +184,8 @@
                              "this protocol does not support writing (yet).");
   }
 
-
   uint32_t writeStructBegin(const char* name) {
-    (void) name;
+    (void)name;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
@@ -198,12 +195,10 @@
                              "this protocol does not support writing (yet).");
   }
 
-  uint32_t writeFieldBegin(const char* name,
-                           const TType fieldType,
-                           const int16_t fieldId) {
-    (void) name;
-    (void) fieldType;
-    (void) fieldId;
+  uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId) {
+    (void)name;
+    (void)fieldType;
+    (void)fieldId;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
@@ -218,12 +213,10 @@
                              "this protocol does not support writing (yet).");
   }
 
-  uint32_t writeMapBegin(const TType keyType,
-                         const TType valType,
-                         const uint32_t size) {
-    (void) keyType;
-    (void) valType;
-    (void) size;
+  uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size) {
+    (void)keyType;
+    (void)valType;
+    (void)size;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
@@ -234,8 +227,8 @@
   }
 
   uint32_t writeListBegin(const TType elemType, const uint32_t size) {
-    (void) elemType;
-    (void) size;
+    (void)elemType;
+    (void)size;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
@@ -246,8 +239,8 @@
   }
 
   uint32_t writeSetBegin(const TType elemType, const uint32_t size) {
-    (void) elemType;
-    (void) size;
+    (void)elemType;
+    (void)size;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
@@ -258,70 +251,66 @@
   }
 
   uint32_t writeBool(const bool value) {
-    (void) value;
+    (void)value;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
 
   uint32_t writeByte(const int8_t byte) {
-    (void) byte;
+    (void)byte;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
 
   uint32_t writeI16(const int16_t i16) {
-    (void) i16;
+    (void)i16;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
 
   uint32_t writeI32(const int32_t i32) {
-    (void) i32;
+    (void)i32;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
 
   uint32_t writeI64(const int64_t i64) {
-    (void) i64;
+    (void)i64;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
 
   uint32_t writeDouble(const double dub) {
-    (void) dub;
+    (void)dub;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
 
   uint32_t writeString(const std::string& str) {
-    (void) str;
+    (void)str;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
 
   uint32_t writeBinary(const std::string& str) {
-    (void) str;
+    (void)str;
     throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
                              "this protocol does not support writing (yet).");
   }
 
-  uint32_t skip(TType type) {
-    return ::apache::thrift::protocol::skip(*this, type);
-  }
+  uint32_t skip(TType type) { return ::apache::thrift::protocol::skip(*this, type); }
 
- protected:
-  TProtocolDefaults(boost::shared_ptr<TTransport> ptrans)
-    : TProtocol(ptrans)
-  {}
+protected:
+  TProtocolDefaults(std::shared_ptr<TTransport> ptrans) : TProtocol(ptrans) {}
 };
 
 /**
  * Concrete TProtocol classes should inherit from TVirtualProtocol
  * so they don't have to manually override virtual methods.
  */
-template <class Protocol_, class Super_=TProtocolDefaults>
+template <class Protocol_, class Super_ = TProtocolDefaults>
 class TVirtualProtocol : public Super_ {
- public:
+public:
   /**
    * Writing functions.
    */
@@ -329,37 +318,28 @@
   virtual uint32_t writeMessageBegin_virt(const std::string& name,
                                           const TMessageType messageType,
                                           const int32_t seqid) {
-    return static_cast<Protocol_*>(this)->writeMessageBegin(name, messageType,
-                                                            seqid);
+    return static_cast<Protocol_*>(this)->writeMessageBegin(name, messageType, seqid);
   }
 
   virtual uint32_t writeMessageEnd_virt() {
     return static_cast<Protocol_*>(this)->writeMessageEnd();
   }
 
-
   virtual uint32_t writeStructBegin_virt(const char* name) {
     return static_cast<Protocol_*>(this)->writeStructBegin(name);
   }
 
-  virtual uint32_t writeStructEnd_virt() {
-    return static_cast<Protocol_*>(this)->writeStructEnd();
-  }
+  virtual uint32_t writeStructEnd_virt() { return static_cast<Protocol_*>(this)->writeStructEnd(); }
 
   virtual uint32_t writeFieldBegin_virt(const char* name,
                                         const TType fieldType,
                                         const int16_t fieldId) {
-    return static_cast<Protocol_*>(this)->writeFieldBegin(name, fieldType,
-                                                          fieldId);
+    return static_cast<Protocol_*>(this)->writeFieldBegin(name, fieldType, fieldId);
   }
 
-  virtual uint32_t writeFieldEnd_virt() {
-    return static_cast<Protocol_*>(this)->writeFieldEnd();
-  }
+  virtual uint32_t writeFieldEnd_virt() { return static_cast<Protocol_*>(this)->writeFieldEnd(); }
 
-  virtual uint32_t writeFieldStop_virt() {
-    return static_cast<Protocol_*>(this)->writeFieldStop();
-  }
+  virtual uint32_t writeFieldStop_virt() { return static_cast<Protocol_*>(this)->writeFieldStop(); }
 
   virtual uint32_t writeMapBegin_virt(const TType keyType,
                                       const TType valType,
@@ -367,27 +347,19 @@
     return static_cast<Protocol_*>(this)->writeMapBegin(keyType, valType, size);
   }
 
-  virtual uint32_t writeMapEnd_virt() {
-    return static_cast<Protocol_*>(this)->writeMapEnd();
-  }
+  virtual uint32_t writeMapEnd_virt() { return static_cast<Protocol_*>(this)->writeMapEnd(); }
 
-  virtual uint32_t writeListBegin_virt(const TType elemType,
-                                       const uint32_t size) {
+  virtual uint32_t writeListBegin_virt(const TType elemType, const uint32_t size) {
     return static_cast<Protocol_*>(this)->writeListBegin(elemType, size);
   }
 
-  virtual uint32_t writeListEnd_virt() {
-    return static_cast<Protocol_*>(this)->writeListEnd();
-  }
+  virtual uint32_t writeListEnd_virt() { return static_cast<Protocol_*>(this)->writeListEnd(); }
 
-  virtual uint32_t writeSetBegin_virt(const TType elemType,
-                                      const uint32_t size) {
+  virtual uint32_t writeSetBegin_virt(const TType elemType, const uint32_t size) {
     return static_cast<Protocol_*>(this)->writeSetBegin(elemType, size);
   }
 
-  virtual uint32_t writeSetEnd_virt() {
-    return static_cast<Protocol_*>(this)->writeSetEnd();
-  }
+  virtual uint32_t writeSetEnd_virt() { return static_cast<Protocol_*>(this)->writeSetEnd(); }
 
   virtual uint32_t writeBool_virt(const bool value) {
     return static_cast<Protocol_*>(this)->writeBool(value);
@@ -428,60 +400,40 @@
   virtual uint32_t readMessageBegin_virt(std::string& name,
                                          TMessageType& messageType,
                                          int32_t& seqid) {
-    return static_cast<Protocol_*>(this)->readMessageBegin(name, messageType,
-                                                           seqid);
+    return static_cast<Protocol_*>(this)->readMessageBegin(name, messageType, seqid);
   }
 
-  virtual uint32_t readMessageEnd_virt() {
-    return static_cast<Protocol_*>(this)->readMessageEnd();
-  }
+  virtual uint32_t readMessageEnd_virt() { return static_cast<Protocol_*>(this)->readMessageEnd(); }
 
   virtual uint32_t readStructBegin_virt(std::string& name) {
     return static_cast<Protocol_*>(this)->readStructBegin(name);
   }
 
-  virtual uint32_t readStructEnd_virt() {
-    return static_cast<Protocol_*>(this)->readStructEnd();
+  virtual uint32_t readStructEnd_virt() { return static_cast<Protocol_*>(this)->readStructEnd(); }
+
+  virtual uint32_t readFieldBegin_virt(std::string& name, TType& fieldType, int16_t& fieldId) {
+    return static_cast<Protocol_*>(this)->readFieldBegin(name, fieldType, fieldId);
   }
 
-  virtual uint32_t readFieldBegin_virt(std::string& name,
-                                       TType& fieldType,
-                                       int16_t& fieldId) {
-    return static_cast<Protocol_*>(this)->readFieldBegin(name, fieldType,
-                                                         fieldId);
-  }
+  virtual uint32_t readFieldEnd_virt() { return static_cast<Protocol_*>(this)->readFieldEnd(); }
 
-  virtual uint32_t readFieldEnd_virt() {
-    return static_cast<Protocol_*>(this)->readFieldEnd();
-  }
-
-  virtual uint32_t readMapBegin_virt(TType& keyType,
-                                     TType& valType,
-                                     uint32_t& size) {
+  virtual uint32_t readMapBegin_virt(TType& keyType, TType& valType, uint32_t& size) {
     return static_cast<Protocol_*>(this)->readMapBegin(keyType, valType, size);
   }
 
-  virtual uint32_t readMapEnd_virt() {
-    return static_cast<Protocol_*>(this)->readMapEnd();
-  }
+  virtual uint32_t readMapEnd_virt() { return static_cast<Protocol_*>(this)->readMapEnd(); }
 
-  virtual uint32_t readListBegin_virt(TType& elemType,
-                                      uint32_t& size) {
+  virtual uint32_t readListBegin_virt(TType& elemType, uint32_t& size) {
     return static_cast<Protocol_*>(this)->readListBegin(elemType, size);
   }
 
-  virtual uint32_t readListEnd_virt() {
-    return static_cast<Protocol_*>(this)->readListEnd();
-  }
+  virtual uint32_t readListEnd_virt() { return static_cast<Protocol_*>(this)->readListEnd(); }
 
-  virtual uint32_t readSetBegin_virt(TType& elemType,
-                                     uint32_t& size) {
+  virtual uint32_t readSetBegin_virt(TType& elemType, uint32_t& size) {
     return static_cast<Protocol_*>(this)->readSetBegin(elemType, size);
   }
 
-  virtual uint32_t readSetEnd_virt() {
-    return static_cast<Protocol_*>(this)->readSetEnd();
-  }
+  virtual uint32_t readSetEnd_virt() { return static_cast<Protocol_*>(this)->readSetEnd(); }
 
   virtual uint32_t readBool_virt(bool& value) {
     return static_cast<Protocol_*>(this)->readBool(value);
@@ -519,9 +471,7 @@
     return static_cast<Protocol_*>(this)->readBinary(str);
   }
 
-  virtual uint32_t skip_virt(TType type) {
-    return static_cast<Protocol_*>(this)->skip(type);
-  }
+  virtual uint32_t skip_virt(TType type) { return static_cast<Protocol_*>(this)->skip(type); }
 
   /*
    * Provide a default skip() implementation that uses non-virtual read
@@ -553,12 +503,11 @@
   }
   using Super_::readBool; // so we don't hide readBool(bool&)
 
- protected:
-  TVirtualProtocol(boost::shared_ptr<TTransport> ptrans)
-    : Super_(ptrans)
-  {}
+protected:
+  TVirtualProtocol(std::shared_ptr<TTransport> ptrans) : Super_(ptrans) {}
 };
-
-}}} // apache::thrift::protocol
+}
+}
+} // apache::thrift::protocol
 
 #endif // #define _THRIFT_PROTOCOL_TVIRTUALPROTOCOL_H_ 1
diff --git a/lib/cpp/src/thrift/qt/CMakeLists.txt b/lib/cpp/src/thrift/qt/CMakeLists.txt
new file mode 100644
index 0000000..04a9a31
--- /dev/null
+++ b/lib/cpp/src/thrift/qt/CMakeLists.txt
@@ -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.
+#
+
+set( thriftcppqt5_SOURCES
+    TQIODeviceTransport.cpp
+    TQTcpServer.cpp
+)
+set(CMAKE_AUTOMOC ON)
+find_package(Qt5 REQUIRED COMPONENTS Core Network)
+ADD_LIBRARY_THRIFT(thriftqt5 ${thriftcppqt5_SOURCES})
+TARGET_LINK_LIBRARIES_THRIFT(thriftqt5 Qt5::Core Qt5::Network)
+TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY(thriftqt5 thrift)
diff --git a/lib/cpp/src/thrift/qt/TQIODeviceTransport.cpp b/lib/cpp/src/thrift/qt/TQIODeviceTransport.cpp
index 3a3e222..f77c993 100644
--- a/lib/cpp/src/thrift/qt/TQIODeviceTransport.cpp
+++ b/lib/cpp/src/thrift/qt/TQIODeviceTransport.cpp
@@ -23,46 +23,42 @@
 #include <QIODevice>
 
 #include <thrift/transport/TBufferTransports.h>
+#include <memory>
 
-using boost::shared_ptr;
-  
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
 
-TQIODeviceTransport::TQIODeviceTransport(shared_ptr<QIODevice> dev)
-  : dev_(dev)
-{
+using std::shared_ptr;
+
+namespace transport {
+
+TQIODeviceTransport::TQIODeviceTransport(shared_ptr<QIODevice> dev) : dev_(dev) {
 }
 
-TQIODeviceTransport::~TQIODeviceTransport()
-{
+TQIODeviceTransport::~TQIODeviceTransport() {
   dev_->close();
 }
 
-void TQIODeviceTransport::open()
-{
+void TQIODeviceTransport::open() {
   if (!isOpen()) {
     throw TTransportException(TTransportException::NOT_OPEN,
                               "open(): underlying QIODevice isn't open");
   }
 }
 
-bool TQIODeviceTransport::isOpen()
-{
+bool TQIODeviceTransport::isOpen() {
   return dev_->isOpen();
 }
 
-bool TQIODeviceTransport::peek()
-{
+bool TQIODeviceTransport::peek() {
   return dev_->bytesAvailable() > 0;
 }
 
-void TQIODeviceTransport::close()
-{
+void TQIODeviceTransport::close() {
   dev_->close();
 }
 
-uint32_t TQIODeviceTransport::readAll(uint8_t* buf, uint32_t len)
-{
+uint32_t TQIODeviceTransport::readAll(uint8_t* buf, uint32_t len) {
   uint32_t requestLen = len;
   while (len) {
     uint32_t readSize;
@@ -86,8 +82,7 @@
   return requestLen;
 }
 
-uint32_t TQIODeviceTransport::read(uint8_t* buf, uint32_t len)
-{
+uint32_t TQIODeviceTransport::read(uint8_t* buf, uint32_t len) {
   uint32_t actualSize;
   qint64 readSize;
 
@@ -96,25 +91,23 @@
                               "read(): underlying QIODevice is not open");
   }
 
-  actualSize = (uint32_t)std::min((qint64)len, dev_->bytesAvailable());
-  readSize = dev_->read(reinterpret_cast<char *>(buf), actualSize);
+  actualSize = (uint32_t)(std::min)((qint64)len, dev_->bytesAvailable());
+  readSize = dev_->read(reinterpret_cast<char*>(buf), actualSize);
 
   if (readSize < 0) {
     QAbstractSocket* socket;
-    if ((socket = qobject_cast<QAbstractSocket* >(dev_.get()))) {
+    if ((socket = qobject_cast<QAbstractSocket*>(dev_.get()))) {
       throw TTransportException(TTransportException::UNKNOWN,
                                 "Failed to read() from QAbstractSocket",
                                 socket->error());
     }
-    throw TTransportException(TTransportException::UNKNOWN,
-                              "Failed to read from from QIODevice");
+    throw TTransportException(TTransportException::UNKNOWN, "Failed to read from from QIODevice");
   }
 
   return (uint32_t)readSize;
 }
 
-void TQIODeviceTransport::write(const uint8_t* buf, uint32_t len)
-{
+void TQIODeviceTransport::write(const uint8_t* buf, uint32_t len) {
   while (len) {
     uint32_t written = write_partial(buf, len);
     len -= written;
@@ -122,8 +115,7 @@
   }
 }
 
-uint32_t TQIODeviceTransport::write_partial(const uint8_t* buf, uint32_t len)
-{
+uint32_t TQIODeviceTransport::write_partial(const uint8_t* buf, uint32_t len) {
   qint64 written;
 
   if (!dev_->isOpen()) {
@@ -136,7 +128,8 @@
     QAbstractSocket* socket;
     if ((socket = qobject_cast<QAbstractSocket*>(dev_.get()))) {
       throw TTransportException(TTransportException::UNKNOWN,
-                                "write_partial(): failed to write to QAbstractSocket", socket->error());
+                                "write_partial(): failed to write to QAbstractSocket",
+                                socket->error());
     }
 
     throw TTransportException(TTransportException::UNKNOWN,
@@ -146,8 +139,7 @@
   return (uint32_t)written;
 }
 
-void TQIODeviceTransport::flush()
-{
+void TQIODeviceTransport::flush() {
   if (!dev_->isOpen()) {
     throw TTransportException(TTransportException::NOT_OPEN,
                               "flush(): underlying QIODevice is not open");
@@ -162,18 +154,16 @@
   }
 }
 
-uint8_t* TQIODeviceTransport::borrow(uint8_t* buf, uint32_t* len)
-{
-  (void) buf;
-  (void) len;
+uint8_t* TQIODeviceTransport::borrow(uint8_t* buf, uint32_t* len) {
+  (void)buf;
+  (void)len;
   return NULL;
 }
 
-void TQIODeviceTransport::consume(uint32_t len)
-{
-  (void) len;
+void TQIODeviceTransport::consume(uint32_t len) {
+  (void)len;
   throw TTransportException(TTransportException::UNKNOWN);
 }
-
-}}} // apache::thrift::transport
-
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/qt/TQIODeviceTransport.h b/lib/cpp/src/thrift/qt/TQIODeviceTransport.h
index 64faa12..91ce8d5 100644
--- a/lib/cpp/src/thrift/qt/TQIODeviceTransport.h
+++ b/lib/cpp/src/thrift/qt/TQIODeviceTransport.h
@@ -20,20 +20,23 @@
 #ifndef _THRIFT_ASYNC_TQIODEVICE_TRANSPORT_H_
 #define _THRIFT_ASYNC_TQIODEVICE_TRANSPORT_H_ 1
 
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
 #include <thrift/transport/TVirtualTransport.h>
 
 class QIODevice;
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  *  Transport that operates on a QIODevice (socket, file, etc).
  */
-class TQIODeviceTransport : public apache::thrift::transport::TVirtualTransport<TQIODeviceTransport> {
- public:
-  explicit TQIODeviceTransport(boost::shared_ptr<QIODevice> dev);
+class TQIODeviceTransport
+    : public apache::thrift::transport::TVirtualTransport<TQIODeviceTransport> {
+public:
+  explicit TQIODeviceTransport(std::shared_ptr<QIODevice> dev);
   virtual ~TQIODeviceTransport();
 
   void open();
@@ -41,7 +44,7 @@
   bool peek();
   void close();
 
-  uint32_t readAll(uint8_t *buf, uint32_t len);
+  uint32_t readAll(uint8_t* buf, uint32_t len);
   uint32_t read(uint8_t* buf, uint32_t len);
 
   void write(const uint8_t* buf, uint32_t len);
@@ -52,13 +55,14 @@
   uint8_t* borrow(uint8_t* buf, uint32_t* len);
   void consume(uint32_t len);
 
- private:
-   TQIODeviceTransport(const TQIODeviceTransport&);
-   TQIODeviceTransport& operator=(const TQIODeviceTransport&);
-   
-   boost::shared_ptr<QIODevice> dev_;
+private:
+  TQIODeviceTransport(const TQIODeviceTransport&);
+  TQIODeviceTransport& operator=(const TQIODeviceTransport&);
+
+  std::shared_ptr<QIODevice> dev_;
 };
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_ASYNC_TQIODEVICE_TRANSPORT_H_
-
diff --git a/lib/cpp/src/thrift/qt/TQTcpServer.cpp b/lib/cpp/src/thrift/qt/TQTcpServer.cpp
index 79a8c59..99aad07 100644
--- a/lib/cpp/src/thrift/qt/TQTcpServer.cpp
+++ b/lib/cpp/src/thrift/qt/TQTcpServer.cpp
@@ -17,28 +17,33 @@
  * under the License.
  */
 
+#include <functional>
+#include <memory>
+
 #include <thrift/qt/TQTcpServer.h>
 #include <thrift/qt/TQIODeviceTransport.h>
 
+#include <QMetaType>
 #include <QTcpSocket>
 
-#include <thrift/cxxfunctional.h>
-
 #include <thrift/protocol/TProtocol.h>
 #include <thrift/async/TAsyncProcessor.h>
 
-using boost::shared_ptr;
 using apache::thrift::protocol::TProtocol;
 using apache::thrift::protocol::TProtocolFactory;
 using apache::thrift::transport::TTransport;
 using apache::thrift::transport::TTransportException;
 using apache::thrift::transport::TQIODeviceTransport;
-using apache::thrift::stdcxx::function;
-using apache::thrift::stdcxx::bind;
+using std::bind;
+using std::function;
+using std::placeholders::_1;
+using std::shared_ptr;
 
 QT_USE_NAMESPACE
 
-namespace apache { namespace thrift { namespace async {
+namespace apache {
+namespace thrift {
+namespace async {
 
 struct TQTcpServer::ConnectionContext {
   shared_ptr<QTcpSocket> connection_;
@@ -50,64 +55,51 @@
                              shared_ptr<TTransport> transport,
                              shared_ptr<TProtocol> iprot,
                              shared_ptr<TProtocol> oprot)
-    : connection_(connection)
-    , transport_(transport)
-    , iprot_(iprot)
-    , oprot_(oprot)
-  {}
+    : connection_(connection), transport_(transport), iprot_(iprot), oprot_(oprot) {}
 };
 
 TQTcpServer::TQTcpServer(shared_ptr<QTcpServer> server,
                          shared_ptr<TAsyncProcessor> processor,
                          shared_ptr<TProtocolFactory> pfact,
                          QObject* parent)
-  : QObject(parent)
-  , server_(server)
-  , processor_(processor)
-  , pfact_(pfact)
-{
+  : QObject(parent), server_(server), processor_(processor), pfact_(pfact) {
+  qRegisterMetaType<QTcpSocket*>("QTcpSocket*");
   connect(server.get(), SIGNAL(newConnection()), SLOT(processIncoming()));
 }
 
-TQTcpServer::~TQTcpServer()
-{
+TQTcpServer::~TQTcpServer() {
 }
 
-void TQTcpServer::processIncoming()
-{
+void TQTcpServer::processIncoming() {
   while (server_->hasPendingConnections()) {
     // take ownership of the QTcpSocket; technically it could be deleted
     // when the QTcpServer is destroyed, but any real app should delete this
     // class before deleting the QTcpServer that we are using
     shared_ptr<QTcpSocket> connection(server_->nextPendingConnection());
-    
+
     shared_ptr<TTransport> transport;
     shared_ptr<TProtocol> iprot;
     shared_ptr<TProtocol> oprot;
-    
+
     try {
       transport = shared_ptr<TTransport>(new TQIODeviceTransport(connection));
       iprot = shared_ptr<TProtocol>(pfact_->getProtocol(transport));
       oprot = shared_ptr<TProtocol>(pfact_->getProtocol(transport));
-    } catch(...) {
+    } catch (...) {
       qWarning("[TQTcpServer] Failed to initialize transports/protocols");
       continue;
     }
-    
-    ctxMap_[connection.get()] =
-      shared_ptr<ConnectionContext>(
-         new ConnectionContext(connection, transport, iprot, oprot));
-    
+
+    ctxMap_[connection.get()]
+        = shared_ptr<ConnectionContext>(new ConnectionContext(connection, transport, iprot, oprot));
+
     connect(connection.get(), SIGNAL(readyRead()), SLOT(beginDecode()));
-    
-    // need to use QueuedConnection since we will be deleting the socket in the slot
-    connect(connection.get(), SIGNAL(disconnected()), SLOT(socketClosed()),
-            Qt::QueuedConnection);
+
+    connect(connection.get(), SIGNAL(disconnected()), SLOT(socketClosed()));
   }
 }
 
-void TQTcpServer::beginDecode()
-{
+void TQTcpServer::beginDecode() {
   QTcpSocket* connection(qobject_cast<QTcpSocket*>(sender()));
   Q_ASSERT(connection);
 
@@ -115,43 +107,46 @@
     qWarning("[TQTcpServer] Got data on an unknown QTcpSocket");
     return;
   }
-  
+
   shared_ptr<ConnectionContext> ctx = ctxMap_[connection];
-  
+
   try {
-    processor_->process(
-      bind(&TQTcpServer::finish, this,
-           ctx, apache::thrift::stdcxx::placeholders::_1),
-      ctx->iprot_, ctx->oprot_);
-  } catch(const TTransportException& ex) {
-    qWarning("[TQTcpServer] TTransportException during processing: '%s'",
-             ex.what());
-    ctxMap_.erase(connection);
-  } catch(...) {
+    processor_
+        ->process(bind(&TQTcpServer::finish, this, ctx, _1),
+                  ctx->iprot_,
+                  ctx->oprot_);
+  } catch (const TTransportException& ex) {
+    qWarning("[TQTcpServer] TTransportException during processing: '%s'", ex.what());
+    scheduleDeleteConnectionContext(connection);
+  } catch (...) {
     qWarning("[TQTcpServer] Unknown processor exception");
-    ctxMap_.erase(connection);
+    scheduleDeleteConnectionContext(connection);
   }
 }
 
-void TQTcpServer::socketClosed()
-{
+void TQTcpServer::socketClosed() {
   QTcpSocket* connection(qobject_cast<QTcpSocket*>(sender()));
   Q_ASSERT(connection);
-
-  if (ctxMap_.find(connection) == ctxMap_.end()) {
-    qWarning("[TQTcpServer] Unknown QTcpSocket closed");
-    return;
-  }
-  
-  ctxMap_.erase(connection);
+  scheduleDeleteConnectionContext(connection);
 }
 
-void TQTcpServer::finish(shared_ptr<ConnectionContext> ctx, bool healthy)
-{
+void TQTcpServer::deleteConnectionContext(QTcpSocket* connection) {
+  const ConnectionContextMap::size_type deleted = ctxMap_.erase(connection);
+  if (0 == deleted) {
+      qWarning("[TQTcpServer] Unknown QTcpSocket");
+  }
+}
+
+void TQTcpServer::scheduleDeleteConnectionContext(QTcpSocket* connection) {
+  QMetaObject::invokeMethod(this, "deleteConnectionContext", Qt::QueuedConnection, Q_ARG(QTcpSocket*, connection));
+}
+
+void TQTcpServer::finish(shared_ptr<ConnectionContext> ctx, bool healthy) {
   if (!healthy) {
     qWarning("[TQTcpServer] Processor failed to process data successfully");
-    ctxMap_.erase(ctx->connection_.get());
+    deleteConnectionContext(ctx->connection_.get());
   }
 }
-
-}}} // apache::thrift::async
+}
+}
+} // apache::thrift::async
diff --git a/lib/cpp/src/thrift/qt/TQTcpServer.h b/lib/cpp/src/thrift/qt/TQTcpServer.h
index 12a450f..8e3fe3a 100644
--- a/lib/cpp/src/thrift/qt/TQTcpServer.h
+++ b/lib/cpp/src/thrift/qt/TQTcpServer.h
@@ -23,13 +23,19 @@
 #include <QObject>
 #include <QTcpServer>
 
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
-namespace apache { namespace thrift { namespace protocol {
+namespace apache {
+namespace thrift {
+namespace protocol {
 class TProtocolFactory;
-}}} // apache::thrift::protocol
+}
+}
+} // apache::thrift::protocol
 
-namespace apache { namespace thrift { namespace async {
+namespace apache {
+namespace thrift {
+namespace async {
 
 class TAsyncProcessor;
 
@@ -39,34 +45,37 @@
  *  processor and a protocol factory, and then run the Qt event loop.
  */
 class TQTcpServer : public QObject {
- Q_OBJECT
- public:
-  TQTcpServer(boost::shared_ptr<QTcpServer> server,
-              boost::shared_ptr<TAsyncProcessor> processor,
-              boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> protocolFactory,
-              QT_PREPEND_NAMESPACE(QObject)* parent = NULL);
+  Q_OBJECT
+public:
+  TQTcpServer(std::shared_ptr<QTcpServer> server,
+              std::shared_ptr<TAsyncProcessor> processor,
+              std::shared_ptr<apache::thrift::protocol::TProtocolFactory> protocolFactory,
+              QObject* parent = NULL);
   virtual ~TQTcpServer();
 
- private Q_SLOTS:
+private Q_SLOTS:
   void processIncoming();
   void beginDecode();
   void socketClosed();
+  void deleteConnectionContext(QTcpSocket* connection);
 
- private:
-  TQTcpServer(const TQTcpServer&);
-  TQTcpServer& operator=(const TQTcpServer&);
-  
-  class ConnectionContext;
+private:
+  Q_DISABLE_COPY(TQTcpServer)
 
-  void finish(boost::shared_ptr<ConnectionContext> ctx, bool healthy);
+  struct ConnectionContext;
 
-  boost::shared_ptr<QTcpServer> server_;
-  boost::shared_ptr<TAsyncProcessor> processor_;
-  boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> pfact_;
+  void scheduleDeleteConnectionContext(QTcpSocket* connection);
+  void finish(std::shared_ptr<ConnectionContext> ctx, bool healthy);
 
-  std::map<QT_PREPEND_NAMESPACE(QTcpSocket)*, boost::shared_ptr<ConnectionContext> > ctxMap_;
+  std::shared_ptr<QTcpServer> server_;
+  std::shared_ptr<TAsyncProcessor> processor_;
+  std::shared_ptr<apache::thrift::protocol::TProtocolFactory> pfact_;
+
+  typedef std::map<QTcpSocket*, std::shared_ptr<ConnectionContext> > ConnectionContextMap;
+  ConnectionContextMap ctxMap_;
 };
-
-}}} // apache::thrift::async
+}
+}
+} // apache::thrift::async
 
 #endif // #ifndef _THRIFT_TASYNC_QTCP_SERVER_H_
diff --git a/lib/cpp/src/thrift/server/TConnectedClient.cpp b/lib/cpp/src/thrift/server/TConnectedClient.cpp
new file mode 100644
index 0000000..acdaa77
--- /dev/null
+++ b/lib/cpp/src/thrift/server/TConnectedClient.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#include <thrift/server/TConnectedClient.h>
+
+namespace apache {
+namespace thrift {
+namespace server {
+
+using apache::thrift::TProcessor;
+using apache::thrift::protocol::TProtocol;
+using apache::thrift::server::TServerEventHandler;
+using apache::thrift::transport::TTransport;
+using apache::thrift::transport::TTransportException;
+using std::shared_ptr;
+using std::string;
+
+TConnectedClient::TConnectedClient(const shared_ptr<TProcessor>& processor,
+                                   const shared_ptr<TProtocol>& inputProtocol,
+                                   const shared_ptr<TProtocol>& outputProtocol,
+                                   const shared_ptr<TServerEventHandler>& eventHandler,
+                                   const shared_ptr<TTransport>& client)
+
+  : processor_(processor),
+    inputProtocol_(inputProtocol),
+    outputProtocol_(outputProtocol),
+    eventHandler_(eventHandler),
+    client_(client),
+    opaqueContext_(0) {
+}
+
+TConnectedClient::~TConnectedClient() {
+}
+
+void TConnectedClient::run() {
+  if (eventHandler_) {
+    opaqueContext_ = eventHandler_->createContext(inputProtocol_, outputProtocol_);
+  }
+
+  for (bool done = false; !done;) {
+    if (eventHandler_) {
+      eventHandler_->processContext(opaqueContext_, client_);
+    }
+
+    try {
+      if (!processor_->process(inputProtocol_, outputProtocol_, opaqueContext_)) {
+        break;
+      }
+    } catch (const TTransportException& ttx) {
+      switch (ttx.getType()) {
+        case TTransportException::END_OF_FILE:
+        case TTransportException::INTERRUPTED:
+        case TTransportException::TIMED_OUT:
+          // Client disconnected or was interrupted or did not respond within the receive timeout.
+          // No logging needed.  Done.
+          done = true;
+          break;
+
+        default: {
+          // All other transport exceptions are logged.
+          // State of connection is unknown.  Done.
+          string errStr = string("TConnectedClient died: ") + ttx.what();
+          GlobalOutput(errStr.c_str());
+          done = true;
+          break;
+        }
+      }
+    } catch (const TException& tex) {
+      string errStr = string("TConnectedClient processing exception: ") + tex.what();
+      GlobalOutput(errStr.c_str());
+      // Disconnect from client, because we could not process the message.
+      done = true;
+    }
+  }
+
+  cleanup();
+}
+
+void TConnectedClient::cleanup() {
+  if (eventHandler_) {
+    eventHandler_->deleteContext(opaqueContext_, inputProtocol_, outputProtocol_);
+  }
+
+  try {
+    inputProtocol_->getTransport()->close();
+  } catch (const TTransportException& ttx) {
+    string errStr = string("TConnectedClient input close failed: ") + ttx.what();
+    GlobalOutput(errStr.c_str());
+  }
+
+  try {
+    outputProtocol_->getTransport()->close();
+  } catch (const TTransportException& ttx) {
+    string errStr = string("TConnectedClient output close failed: ") + ttx.what();
+    GlobalOutput(errStr.c_str());
+  }
+
+  try {
+    client_->close();
+  } catch (const TTransportException& ttx) {
+    string errStr = string("TConnectedClient client close failed: ") + ttx.what();
+    GlobalOutput(errStr.c_str());
+  }
+}
+}
+}
+} // apache::thrift::server
diff --git a/lib/cpp/src/thrift/server/TConnectedClient.h b/lib/cpp/src/thrift/server/TConnectedClient.h
new file mode 100644
index 0000000..19e70c1
--- /dev/null
+++ b/lib/cpp/src/thrift/server/TConnectedClient.h
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_SERVER_TCONNECTEDCLIENT_H_
+#define _THRIFT_SERVER_TCONNECTEDCLIENT_H_ 1
+
+#include <memory>
+#include <thrift/TProcessor.h>
+#include <thrift/protocol/TProtocol.h>
+#include <thrift/server/TServer.h>
+#include <thrift/transport/TTransport.h>
+
+namespace apache {
+namespace thrift {
+namespace server {
+
+/**
+ * This represents a client connected to a TServer.  The
+ * processing loop for a client must provide some required
+ * functionality common to all implementations so it is
+ * encapsulated here.
+ */
+
+class TConnectedClient : public apache::thrift::concurrency::Runnable {
+public:
+  /**
+   * Constructor.
+   *
+   * @param[in] processor      the TProcessor
+   * @param[in] inputProtocol  the input TProtocol
+   * @param[in] outputProtocol the output TProtocol
+   * @param[in] eventHandler   the server event handler
+   * @param[in] client         the TTransport representing the client
+   */
+  TConnectedClient(
+      const std::shared_ptr<apache::thrift::TProcessor>& processor,
+      const std::shared_ptr<apache::thrift::protocol::TProtocol>& inputProtocol,
+      const std::shared_ptr<apache::thrift::protocol::TProtocol>& outputProtocol,
+      const std::shared_ptr<apache::thrift::server::TServerEventHandler>& eventHandler,
+      const std::shared_ptr<apache::thrift::transport::TTransport>& client);
+
+  /**
+   * Destructor.
+   */
+  virtual ~TConnectedClient();
+
+  /**
+   * Drive the client until it is done.
+   * The client processing loop is:
+   *
+   * [optional] call eventHandler->createContext once
+   * [optional] call eventHandler->processContext per request
+   *            call processor->process per request
+   *              handle expected transport exceptions:
+   *                END_OF_FILE means the client is gone
+   *                INTERRUPTED means the client was interrupted
+   *                            by TServerTransport::interruptChildren()
+   *              handle unexpected transport exceptions by logging
+   *              handle standard exceptions by logging
+   *              handle unexpected exceptions by logging
+   *            cleanup()
+   */
+  virtual void run() /* override */;
+
+protected:
+  /**
+   * Cleanup after a client.  This happens if the client disconnects,
+   * or if the server is stopped, or if an exception occurs.
+   *
+   * The cleanup processing is:
+   * [optional] call eventHandler->deleteContext once
+   *            close the inputProtocol's TTransport
+   *            close the outputProtocol's TTransport
+   *            close the client
+   */
+  virtual void cleanup();
+
+private:
+  std::shared_ptr<apache::thrift::TProcessor> processor_;
+  std::shared_ptr<apache::thrift::protocol::TProtocol> inputProtocol_;
+  std::shared_ptr<apache::thrift::protocol::TProtocol> outputProtocol_;
+  std::shared_ptr<apache::thrift::server::TServerEventHandler> eventHandler_;
+  std::shared_ptr<apache::thrift::transport::TTransport> client_;
+
+  /**
+   * Context acquired from the eventHandler_ if one exists.
+   */
+  void* opaqueContext_;
+};
+}
+}
+}
+
+#endif // #ifndef _THRIFT_SERVER_TCONNECTEDCLIENT_H_
diff --git a/lib/cpp/src/thrift/server/TNonblockingServer.cpp b/lib/cpp/src/thrift/server/TNonblockingServer.cpp
index b9553c4..f16fce7 100644
--- a/lib/cpp/src/thrift/server/TNonblockingServer.cpp
+++ b/lib/cpp/src/thrift/server/TNonblockingServer.cpp
@@ -17,8 +17,6 @@
  * under the License.
  */
 
-#define __STDC_FORMAT_MACROS
-
 #include <thrift/thrift-config.h>
 
 #include <thrift/server/TNonblockingServer.h>
@@ -27,8 +25,17 @@
 #include <thrift/concurrency/PlatformThreadFactory.h>
 #include <thrift/transport/PlatformSocket.h>
 
+#include <algorithm>
 #include <iostream>
 
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#elif HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#elif HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif
@@ -60,27 +67,27 @@
 #define AF_LOCAL AF_UNIX
 #endif
 
-#if !defined(PRIu32)
-#define PRIu32 "I32u"
-#define PRIu64 "I64u"
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
 #endif
 
-namespace apache { namespace thrift { namespace server {
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+namespace apache {
+namespace thrift {
+namespace server {
 
 using namespace apache::thrift::protocol;
 using namespace apache::thrift::transport;
 using namespace apache::thrift::concurrency;
-using namespace std;
 using apache::thrift::transport::TSocket;
 using apache::thrift::transport::TTransportException;
-using boost::shared_ptr;
+using std::shared_ptr;
 
 /// Three states for sockets: recv frame size, recv data, and send mode
-enum TSocketState {
-  SOCKET_RECV_FRAMING,
-  SOCKET_RECV,
-  SOCKET_SEND
-};
+enum TSocketState { SOCKET_RECV_FRAMING, SOCKET_RECV, SOCKET_SEND };
 
 /**
  * Five states for the nonblocking server:
@@ -104,7 +111,7 @@
  * essentially encapsulates a socket that has some associated libevent state.
  */
 class TNonblockingServer::TConnection {
- private:
+private:
   /// Server IO Thread handling this connection
   TNonblockingIOThread* ioThread_;
 
@@ -112,10 +119,10 @@
   TNonblockingServer* server_;
 
   /// TProcessor
-  boost::shared_ptr<TProcessor> processor_;
+  std::shared_ptr<TProcessor> processor_;
 
   /// Object wrapping network socket
-  boost::shared_ptr<TSocket> tSocket_;
+  std::shared_ptr<TSocket> tSocket_;
 
   /// Libevent object
   struct event event_;
@@ -156,48 +163,36 @@
   /// Count of the number of calls for use with getResizeBufferEveryN().
   int32_t callsForResize_;
 
-  /// Task handle
-  int taskHandle_;
-
-  /// Task event
-  struct event taskEvent_;
-
   /// Transport to read from
-  boost::shared_ptr<TMemoryBuffer> inputTransport_;
+  std::shared_ptr<TMemoryBuffer> inputTransport_;
 
   /// Transport that processor writes to
-  boost::shared_ptr<TMemoryBuffer> outputTransport_;
+  std::shared_ptr<TMemoryBuffer> outputTransport_;
 
   /// extra transport generated by transport factory (e.g. BufferedRouterTransport)
-  boost::shared_ptr<TTransport> factoryInputTransport_;
-  boost::shared_ptr<TTransport> factoryOutputTransport_;
+  std::shared_ptr<TTransport> factoryInputTransport_;
+  std::shared_ptr<TTransport> factoryOutputTransport_;
 
   /// Protocol decoder
-  boost::shared_ptr<TProtocol> inputProtocol_;
+  std::shared_ptr<TProtocol> inputProtocol_;
 
   /// Protocol encoder
-  boost::shared_ptr<TProtocol> outputProtocol_;
+  std::shared_ptr<TProtocol> outputProtocol_;
 
   /// Server event handler, if any
-  boost::shared_ptr<TServerEventHandler> serverEventHandler_;
+  std::shared_ptr<TServerEventHandler> serverEventHandler_;
 
   /// Thrift call context, if any
-  void *connectionContext_;
+  void* connectionContext_;
 
   /// Go into read mode
-  void setRead() {
-    setFlags(EV_READ | EV_PERSIST);
-  }
+  void setRead() { setFlags(EV_READ | EV_PERSIST); }
 
   /// Go into write mode
-  void setWrite() {
-    setFlags(EV_WRITE | EV_PERSIST);
-  }
+  void setWrite() { setFlags(EV_WRITE | EV_PERSIST); }
 
   /// Set socket idle
-  void setIdle() {
-    setFlags(0);
-  }
+  void setIdle() { setFlags(0); }
 
   /**
    * Set event flags for this connection.
@@ -214,13 +209,12 @@
    */
   void workSocket();
 
- public:
-
+public:
   class Task;
 
   /// Constructor
-  TConnection(THRIFT_SOCKET socket, TNonblockingIOThread* ioThread,
-              const sockaddr* addr, socklen_t addrLen) {
+  TConnection(std::shared_ptr<TSocket> socket,
+              TNonblockingIOThread* ioThread) {
     readBuffer_ = NULL;
     readBufferSize_ = 0;
 
@@ -231,29 +225,31 @@
     // once per TConnection (they don't need to be reallocated on init() call)
     inputTransport_.reset(new TMemoryBuffer(readBuffer_, readBufferSize_));
     outputTransport_.reset(
-      new TMemoryBuffer(static_cast<uint32_t>(server_->getWriteBufferDefaultSize())));
-    tSocket_.reset(new TSocket());
-    init(socket, ioThread, addr, addrLen);
+        new TMemoryBuffer(static_cast<uint32_t>(server_->getWriteBufferDefaultSize())));
+
+    tSocket_ =  socket;
+
+    init(ioThread);
   }
 
-  ~TConnection() {
-    std::free(readBuffer_);
-  }
+  ~TConnection() { std::free(readBuffer_); }
 
   /// Close this connection and free or reset its resources.
   void close();
 
- /**
-   * Check buffers against any size limits and shrink it if exceeded.
-   *
-   * @param readLimit we reduce read buffer size to this (if nonzero).
-   * @param writeLimit if nonzero and write buffer is larger, replace it.
-   */
+  /**
+    * Check buffers against any size limits and shrink it if exceeded.
+    *
+    * @param readLimit we reduce read buffer size to this (if nonzero).
+    * @param writeLimit if nonzero and write buffer is larger, replace it.
+    */
   void checkIdleBufferMemLimit(size_t readLimit, size_t writeLimit);
 
   /// Initialize
-  void init(THRIFT_SOCKET socket, TNonblockingIOThread* ioThread,
-            const sockaddr* addr, socklen_t addrLen);
+  void init(TNonblockingIOThread* ioThread);
+
+  /// set socket for connection
+  void setSocket(std::shared_ptr<TSocket> socket);
 
   /**
    * This is called when the application transitions from one state into
@@ -271,7 +267,7 @@
    * @param v void* callback arg where we placed TConnection's "this".
    */
   static void eventHandler(evutil_socket_t fd, short /* which */, void* v) {
-    assert(fd == ((TConnection*)v)->getTSocket()->getSocketFD());
+    assert(fd == static_cast<evutil_socket_t>(((TConnection*)v)->getTSocket()->getSocketFD()));
     ((TConnection*)v)->workSocket();
   }
 
@@ -284,65 +280,52 @@
    *
    * @return true if successful, false if unable to notify (check THRIFT_GET_SOCKET_ERROR).
    */
-  bool notifyIOThread() {
-    return ioThread_->notify(this);
-  }
+  bool notifyIOThread() { return ioThread_->notify(this); }
 
   /*
    * Returns the number of this connection's currently assigned IO
    * thread.
    */
-  int getIOThreadNumber() const {
-    return ioThread_->getThreadNumber();
-  }
+  int getIOThreadNumber() const { return ioThread_->getThreadNumber(); }
 
   /// Force connection shutdown for this connection.
   void forceClose() {
     appState_ = APP_CLOSE_CONNECTION;
     if (!notifyIOThread()) {
+      server_->decrementActiveProcessors();
+      close();
       throw TException("TConnection::forceClose: failed write on notify pipe");
     }
   }
 
   /// return the server this connection was initialized for.
-  TNonblockingServer* getServer() const {
-    return server_;
-  }
+  TNonblockingServer* getServer() const { return server_; }
 
   /// get state of connection.
-  TAppState getState() const {
-    return appState_;
-  }
+  TAppState getState() const { return appState_; }
 
   /// return the TSocket transport wrapping this network connection
-  boost::shared_ptr<TSocket> getTSocket() const {
-    return tSocket_;
-  }
+  std::shared_ptr<TSocket> getTSocket() const { return tSocket_; }
 
   /// return the server event handler if any
-  boost::shared_ptr<TServerEventHandler> getServerEventHandler() {
-    return serverEventHandler_;
-  }
+  std::shared_ptr<TServerEventHandler> getServerEventHandler() { return serverEventHandler_; }
 
   /// return the Thrift connection context if any
-  void* getConnectionContext() {
-    return connectionContext_;
-  }
-
+  void* getConnectionContext() { return connectionContext_; }
 };
 
-class TNonblockingServer::TConnection::Task: public Runnable {
- public:
-  Task(boost::shared_ptr<TProcessor> processor,
-       boost::shared_ptr<TProtocol> input,
-       boost::shared_ptr<TProtocol> output,
-       TConnection* connection) :
-    processor_(processor),
-    input_(input),
-    output_(output),
-    connection_(connection),
-    serverEventHandler_(connection_->getServerEventHandler()),
-    connectionContext_(connection_->getConnectionContext()) {}
+class TNonblockingServer::TConnection::Task : public Runnable {
+public:
+  Task(std::shared_ptr<TProcessor> processor,
+       std::shared_ptr<TProtocol> input,
+       std::shared_ptr<TProtocol> output,
+       TConnection* connection)
+    : processor_(processor),
+      input_(input),
+      output_(output),
+      connection_(connection),
+      serverEventHandler_(connection_->getServerEventHandler()),
+      connectionContext_(connection_->getConnectionContext()) {}
 
   void run() {
     try {
@@ -350,50 +333,45 @@
         if (serverEventHandler_) {
           serverEventHandler_->processContext(connectionContext_, connection_->getTSocket());
         }
-        if (!processor_->process(input_, output_, connectionContext_) ||
-            !input_->getTransport()->peek()) {
+        if (!processor_->process(input_, output_, connectionContext_)
+            || !input_->getTransport()->peek()) {
           break;
         }
       }
     } catch (const TTransportException& ttx) {
       GlobalOutput.printf("TNonblockingServer: client died: %s", ttx.what());
-    } catch (const bad_alloc&) {
+    } catch (const std::bad_alloc&) {
       GlobalOutput("TNonblockingServer: caught bad_alloc exception.");
       exit(1);
     } catch (const std::exception& x) {
       GlobalOutput.printf("TNonblockingServer: process() exception: %s: %s",
-                          typeid(x).name(), x.what());
+                          typeid(x).name(),
+                          x.what());
     } catch (...) {
-      GlobalOutput.printf(
-        "TNonblockingServer: unknown exception while processing.");
+      GlobalOutput.printf("TNonblockingServer: unknown exception while processing.");
     }
 
     // Signal completion back to the libevent thread via a pipe
     if (!connection_->notifyIOThread()) {
+      GlobalOutput.printf("TNonblockingServer: failed to notifyIOThread, closing.");
+      connection_->server_->decrementActiveProcessors();
+      connection_->close();
       throw TException("TNonblockingServer::Task::run: failed write on notify pipe");
     }
   }
 
-  TConnection* getTConnection() {
-    return connection_;
-  }
+  TConnection* getTConnection() { return connection_; }
 
- private:
-  boost::shared_ptr<TProcessor> processor_;
-  boost::shared_ptr<TProtocol> input_;
-  boost::shared_ptr<TProtocol> output_;
+private:
+  std::shared_ptr<TProcessor> processor_;
+  std::shared_ptr<TProtocol> input_;
+  std::shared_ptr<TProtocol> output_;
   TConnection* connection_;
-  boost::shared_ptr<TServerEventHandler> serverEventHandler_;
+  std::shared_ptr<TServerEventHandler> serverEventHandler_;
   void* connectionContext_;
 };
 
-void TNonblockingServer::TConnection::init(THRIFT_SOCKET socket,
-                                           TNonblockingIOThread* ioThread,
-                                           const sockaddr* addr,
-                                           socklen_t addrLen) {
-  tSocket_->setSocketFD(socket);
-  tSocket_->setCachedAddress(addr, addrLen);
-
+void TNonblockingServer::TConnection::init(TNonblockingIOThread* ioThread) {
   ioThread_ = ioThread;
   server_ = ioThread->getServer();
   appState_ = APP_INIT;
@@ -411,22 +389,23 @@
   callsForResize_ = 0;
 
   // get input/transports
-  factoryInputTransport_ = server_->getInputTransportFactory()->getTransport(
-                             inputTransport_);
-  factoryOutputTransport_ = server_->getOutputTransportFactory()->getTransport(
-                             outputTransport_);
+  factoryInputTransport_ = server_->getInputTransportFactory()->getTransport(inputTransport_);
+  factoryOutputTransport_ = server_->getOutputTransportFactory()->getTransport(outputTransport_);
 
   // Create protocol
-  inputProtocol_ = server_->getInputProtocolFactory()->getProtocol(
-                     factoryInputTransport_);
-  outputProtocol_ = server_->getOutputProtocolFactory()->getProtocol(
-                     factoryOutputTransport_);
+  if (server_->getHeaderTransport()) {
+    inputProtocol_ = server_->getInputProtocolFactory()->getProtocol(factoryInputTransport_,
+                                                                     factoryOutputTransport_);
+    outputProtocol_ = inputProtocol_;
+  } else {
+    inputProtocol_ = server_->getInputProtocolFactory()->getProtocol(factoryInputTransport_);
+    outputProtocol_ = server_->getOutputProtocolFactory()->getProtocol(factoryOutputTransport_);
+  }
 
   // Set up for any server event handler
   serverEventHandler_ = server_->getEventHandler();
   if (serverEventHandler_) {
-    connectionContext_ = serverEventHandler_->createContext(inputProtocol_,
-                                                            outputProtocol_);
+    connectionContext_ = serverEventHandler_->createContext(inputProtocol_, outputProtocol_);
   } else {
     connectionContext_ = NULL;
   }
@@ -435,8 +414,12 @@
   processor_ = server_->getProcessor(inputProtocol_, outputProtocol_, tSocket_);
 }
 
+void TNonblockingServer::TConnection::setSocket(std::shared_ptr<TSocket> socket) {
+  tSocket_ = socket;
+}
+
 void TNonblockingServer::TConnection::workSocket() {
-  int got=0, left=0, sent=0;
+  int got = 0, left = 0, sent = 0;
   uint32_t fetch = 0;
 
   switch (socketState_) {
@@ -460,10 +443,14 @@
       }
       readBufferPos_ += fetch;
     } catch (TTransportException& te) {
-      GlobalOutput.printf("TConnection::workSocket(): %s", te.what());
-      close();
+      //In Nonblocking SSLSocket some operations need to be retried again.
+      //Current approach is parsing exception message, but a better solution needs to be investigated.
+      if(!strstr(te.what(), "retry")) {
+        GlobalOutput.printf("TConnection::workSocket(): %s", te.what());
+        close();
 
-      return;
+        return;
+      }
     }
 
     if (readBufferPos_ < sizeof(framing.size)) {
@@ -476,17 +463,31 @@
     if (readWant_ > server_->getMaxFrameSize()) {
       // Don't allow giant frame sizes.  This prevents bad clients from
       // causing us to try and allocate a giant buffer.
-      GlobalOutput.printf("TNonblockingServer: frame size too large "
-                          "(%" PRIu32 " > %" PRIu64 ") from client %s. "
-                          "Remote side not using TFramedTransport?",
-                          readWant_,
-                          (uint64_t)server_->getMaxFrameSize(),
-                          tSocket_->getSocketInfo().c_str());
+      GlobalOutput.printf(
+          "TNonblockingServer: frame size too large "
+          "(%" PRIu32 " > %" PRIu64
+          ") from client %s. "
+          "Remote side not using TFramedTransport?",
+          readWant_,
+          (uint64_t)server_->getMaxFrameSize(),
+          tSocket_->getSocketInfo().c_str());
       close();
       return;
     }
     // size known; now get the rest of the frame
     transition();
+
+    // If the socket has more data than the frame header, continue to work on it. This is not strictly necessary for
+    // regular sockets, because if there is more data, libevent will fire the event handler registered for read
+    // readiness, which will in turn call workSocket(). However, some socket types (such as TSSLSocket) may have the
+    // data sitting in their internal buffers and from libevent's perspective, there is no further data available. In
+    // that case, not having this workSocket() call here would result in a hang as we will never get to work the socket,
+    // despite having more data.
+    if (tSocket_->hasPendingDataToRead())
+    {
+        workSocket();
+    }
+
     return;
 
   case SOCKET_RECV:
@@ -497,10 +498,13 @@
       // Read from the socket
       fetch = readWant_ - readBufferPos_;
       got = tSocket_->read(readBuffer_ + readBufferPos_, fetch);
-    }
-    catch (TTransportException& te) {
-      GlobalOutput.printf("TConnection::workSocket(): %s", te.what());
-      close();
+    } catch (TTransportException& te) {
+      //In Nonblocking SSLSocket some operations need to be retried again.
+      //Current approach is parsing exception message, but a better solution needs to be investigated.
+      if(!strstr(te.what(), "retry")) {
+        GlobalOutput.printf("TConnection::workSocket(): %s", te.what());
+        close();
+      }
 
       return;
     }
@@ -530,7 +534,7 @@
 
     // If there is no data to send, then let us move on
     if (writeBufferPos_ == writeBufferSize_) {
-      GlobalOutput("WARNING: Send state with no data to send\n");
+      GlobalOutput("WARNING: Send state with no data to send");
       transition();
       return;
     }
@@ -538,8 +542,7 @@
     try {
       left = writeBufferSize_ - writeBufferPos_;
       sent = tSocket_->write_partial(writeBuffer_ + writeBufferPos_, left);
-    }
-    catch (TTransportException& te) {
+    } catch (TTransportException& te) {
       GlobalOutput.printf("TConnection::workSocket(): %s ", te.what());
       close();
       return;
@@ -563,6 +566,13 @@
   }
 }
 
+bool TNonblockingServer::getHeaderTransport() {
+  // Currently if there is no output protocol factory,
+  // we assume header transport (without having to create
+  // a new transport and check)
+  return getOutputProtocolFactory() == NULL;
+}
+
 /**
  * This is called when the application transitions from one state into
  * another. This means that it has finished writing the data that it needed
@@ -579,12 +589,20 @@
   case APP_READ_REQUEST:
     // We are done reading the request, package the read buffer into transport
     // and get back some data from the dispatch function
-    inputTransport_->resetBuffer(readBuffer_, readBufferPos_);
-    outputTransport_->resetBuffer();
-    // Prepend four bytes of blank space to the buffer so we can
-    // write the frame size there later.
-    outputTransport_->getWritePtr(4);
-    outputTransport_->wroteBytes(4);
+    if (server_->getHeaderTransport()) {
+      inputTransport_->resetBuffer(readBuffer_, readBufferPos_);
+      outputTransport_->resetBuffer();
+    } else {
+      // We saved room for the framing size in case header transport needed it,
+      // but just skip it for the non-header case
+      inputTransport_->resetBuffer(readBuffer_ + 4, readBufferPos_ - 4);
+      outputTransport_->resetBuffer();
+
+      // Prepend four bytes of blank space to the buffer so we can
+      // write the frame size there later.
+      outputTransport_->getWritePtr(4);
+      outputTransport_->wroteBytes(4);
+    }
 
     server_->incrementActiveProcessors();
 
@@ -592,45 +610,49 @@
       // We are setting up a Task to do this work and we will wait on it
 
       // Create task and dispatch to the thread manager
-      boost::shared_ptr<Runnable> task =
-        boost::shared_ptr<Runnable>(new Task(processor_,
-                                             inputProtocol_,
-                                             outputProtocol_,
-                                             this));
+      std::shared_ptr<Runnable> task = std::shared_ptr<Runnable>(
+          new Task(processor_, inputProtocol_, outputProtocol_, this));
       // The application is now waiting on the task to finish
       appState_ = APP_WAIT_TASK;
 
-        try {
-          server_->addTask(task);
-        } catch (IllegalStateException & ise) {
-          // The ThreadManager is not ready to handle any more tasks (it's probably shutting down).
-          GlobalOutput.printf("IllegalStateException: Server::process() %s", ise.what());
-          close();
-        }
-
       // Set this connection idle so that libevent doesn't process more
       // data on it while we're still waiting for the threadmanager to
       // finish this task
       setIdle();
+
+      try {
+        server_->addTask(task);
+      } catch (IllegalStateException& ise) {
+        // The ThreadManager is not ready to handle any more tasks (it's probably shutting down).
+        GlobalOutput.printf("IllegalStateException: Server::process() %s", ise.what());
+        server_->decrementActiveProcessors();
+        close();
+      } catch (TimedOutException& to) {
+        GlobalOutput.printf("[ERROR] TimedOutException: Server::process() %s", to.what());
+        server_->decrementActiveProcessors();
+        close();
+      }
+
       return;
     } else {
       try {
         if (serverEventHandler_) {
-          serverEventHandler_->processContext(connectionContext_,
-                                              getTSocket());
+          serverEventHandler_->processContext(connectionContext_, getTSocket());
         }
         // Invoke the processor
-        processor_->process(inputProtocol_, outputProtocol_,
-                            connectionContext_);
-      } catch (const TTransportException &ttx) {
-        GlobalOutput.printf("TNonblockingServer transport error in "
-                            "process(): %s", ttx.what());
+        processor_->process(inputProtocol_, outputProtocol_, connectionContext_);
+      } catch (const TTransportException& ttx) {
+        GlobalOutput.printf(
+            "TNonblockingServer transport error in "
+            "process(): %s",
+            ttx.what());
         server_->decrementActiveProcessors();
         close();
         return;
-      } catch (const std::exception &x) {
+      } catch (const std::exception& x) {
         GlobalOutput.printf("Server::process() uncaught exception: %s: %s",
-                            typeid(x).name(), x.what());
+                            typeid(x).name(),
+                            x.what());
         server_->decrementActiveProcessors();
         close();
         return;
@@ -641,9 +663,10 @@
         return;
       }
     }
+    // fallthrough
 
-    // Intentionally fall through here, the call to process has written into
-    // the writeBuffer_
+  // Intentionally fall through here, the call to process has written into
+  // the writeBuffer_
 
   case APP_WAIT_TASK:
     // We have now finished processing a task and the result has been written
@@ -671,9 +694,6 @@
       appState_ = APP_SEND_RESULT;
       setWrite();
 
-      // Try to work the socket immediately
-      // workSocket();
-
       return;
     }
 
@@ -692,8 +712,9 @@
                               server_->getIdleWriteBufferLimit());
       callsForResize_ = 0;
     }
+    // fallthrough
 
-    // N.B.: We also intentionally fall through here into the INIT state!
+  // N.B.: We also intentionally fall through here into the INIT state!
 
   LABEL_APP_INIT:
   case APP_INIT:
@@ -712,12 +733,11 @@
     // Register read event
     setRead();
 
-    // Try to work the socket right away
-    // workSocket();
-
     return;
 
   case APP_READ_FRAME_SIZE:
+    readWant_ += 4;
+
     // We just read the request length
     // Double the buffer size until it is big enough
     if (readWant_ > readBufferSize_) {
@@ -738,15 +758,13 @@
       readBufferSize_ = newSize;
     }
 
-    readBufferPos_= 0;
+    readBufferPos_ = 4;
+    *((uint32_t*)readBuffer_) = htonl(readWant_ - 4);
 
     // Move into read request state
     socketState_ = SOCKET_RECV;
     appState_ = APP_READ_REQUEST;
 
-    // Work the socket right away
-    // workSocket();
-
     return;
 
   case APP_CLOSE_CONNECTION:
@@ -767,11 +785,9 @@
   }
 
   // Delete a previously existing event
-  if (eventFlags_ != 0) {
-    if (event_del(&event_) == -1) {
-      GlobalOutput("TConnection::setFlags event_del");
-      return;
-    }
+  if (eventFlags_ && event_del(&event_) == -1) {
+    GlobalOutput.perror("TConnection::setFlags() event_del", THRIFT_GET_SOCKET_ERROR);
+    return;
   }
 
   // Update in memory structure
@@ -809,13 +825,12 @@
    * ev structure for multiple monitored descriptors; each descriptor needs
    * its own ev.
    */
-  event_set(&event_, tSocket_->getSocketFD(), eventFlags_,
-            TConnection::eventHandler, this);
+  event_set(&event_, tSocket_->getSocketFD(), eventFlags_, TConnection::eventHandler, this);
   event_base_set(ioThread_->getEventBase(), &event_);
 
   // Add the event
   if (event_add(&event_, 0) == -1) {
-    GlobalOutput("TConnection::setFlags(): could not event_add");
+    GlobalOutput.perror("TConnection::setFlags(): could not event_add", THRIFT_GET_SOCKET_ERROR);
   }
 }
 
@@ -823,10 +838,7 @@
  * Closes a connection
  */
 void TNonblockingServer::TConnection::close() {
-  // Delete the registered libevent
-  if (event_del(&event_) == -1) {
-    GlobalOutput.perror("TConnection::close() event_del", THRIFT_GET_SOCKET_ERROR);
-  }
+  setIdle();
 
   if (serverEventHandler_) {
     serverEventHandler_->deleteContext(connectionContext_, inputProtocol_, outputProtocol_);
@@ -840,13 +852,14 @@
   factoryInputTransport_->close();
   factoryOutputTransport_->close();
 
+  // release processor and handler
+  processor_.reset();
+
   // Give this object back to the server that owns it
   server_->returnConnection(this);
 }
 
-void TNonblockingServer::TConnection::checkIdleBufferMemLimit(
-    size_t readLimit,
-    size_t writeLimit) {
+void TNonblockingServer::TConnection::checkIdleBufferMemLimit(size_t readLimit, size_t writeLimit) {
   if (readLimit > 0 && readBufferSize_ > readLimit) {
     free(readBuffer_);
     readBuffer_ = NULL;
@@ -863,7 +876,7 @@
 TNonblockingServer::~TNonblockingServer() {
   // Close any active connections (moves them to the idle connection stack)
   while (activeConnections_.size()) {
-	  activeConnections_.front()->close();
+    activeConnections_.front()->close();
   }
   // Clean up unused TConnection objects in connectionStack_
   while (!connectionStack_.empty()) {
@@ -875,9 +888,9 @@
   // objects and the Thread objects have shared_ptrs to the TNonblockingIOThread
   // objects (as runnable) so these objects will never deallocate without help.
   while (!ioThreads_.empty()) {
-	  boost::shared_ptr<TNonblockingIOThread> iot = ioThreads_.back();
-	  ioThreads_.pop_back();
-	  iot->setThread(boost::shared_ptr<Thread>());
+    std::shared_ptr<TNonblockingIOThread> iot = ioThreads_.back();
+    ioThreads_.pop_back();
+    iot->setThread(std::shared_ptr<Thread>());
   }
 }
 
@@ -885,27 +898,27 @@
  * Creates a new connection either by reusing an object off the stack or
  * by allocating a new one entirely
  */
-TNonblockingServer::TConnection* TNonblockingServer::createConnection(
-    THRIFT_SOCKET socket, const sockaddr* addr, socklen_t addrLen) {
+TNonblockingServer::TConnection* TNonblockingServer::createConnection(std::shared_ptr<TSocket> socket) {
   // Check the stack
   Guard g(connMutex_);
 
   // pick an IO thread to handle this connection -- currently round robin
   assert(nextIOThread_ < ioThreads_.size());
   int selectedThreadIdx = nextIOThread_;
-  nextIOThread_ = (nextIOThread_ + 1) % ioThreads_.size();
+  nextIOThread_ = static_cast<uint32_t>((nextIOThread_ + 1) % ioThreads_.size());
 
   TNonblockingIOThread* ioThread = ioThreads_[selectedThreadIdx].get();
 
   // Check the connection stack to see if we can re-use
   TConnection* result = NULL;
   if (connectionStack_.empty()) {
-    result = new TConnection(socket, ioThread, addr, addrLen);
+    result = new TConnection(socket, ioThread);
     ++numTConnections_;
   } else {
     result = connectionStack_.top();
     connectionStack_.pop();
-    result->init(socket, ioThread, addr, addrLen);
+    result->setSocket(socket);
+    result->init(ioThread);
   }
   activeConnections_.push_back(result);
   return result;
@@ -917,10 +930,12 @@
 void TNonblockingServer::returnConnection(TConnection* connection) {
   Guard g(connMutex_);
 
-  activeConnections_.erase(std::remove(activeConnections_.begin(), activeConnections_.end(), connection), activeConnections_.end());
+  activeConnections_.erase(std::remove(activeConnections_.begin(),
+                                       activeConnections_.end(),
+                                       connection),
+                           activeConnections_.end());
 
-  if (connectionStackLimit_ &&
-      (connectionStack_.size() >= connectionStackLimit_)) {
+  if (connectionStackLimit_ && (connectionStack_.size() >= connectionStackLimit_)) {
     delete connection;
     --numTConnections_;
   } else {
@@ -934,57 +949,39 @@
  * connections on fd and assign TConnection objects to handle those requests.
  */
 void TNonblockingServer::handleEvent(THRIFT_SOCKET fd, short which) {
-  (void) which;
+  (void)which;
   // Make sure that libevent didn't mess up the socket handles
   assert(fd == serverSocket_);
 
-  // Server socket accepted a new connection
-  socklen_t addrLen;
-  sockaddr_storage addrStorage;
-  sockaddr* addrp = (sockaddr*)&addrStorage;
-  addrLen = sizeof(addrStorage);
-
   // Going to accept a new client socket
-  THRIFT_SOCKET clientSocket;
+  std::shared_ptr<TSocket> clientSocket;
 
-  // Accept as many new clients as possible, even though libevent signaled only
-  // one, this helps us to avoid having to go back into the libevent engine so
-  // many times
-  while ((clientSocket = ::accept(fd, addrp, &addrLen)) != -1) {
+  clientSocket = serverTransport_->accept();
+  if (clientSocket) {
     // If we're overloaded, take action here
     if (overloadAction_ != T_OVERLOAD_NO_ACTION && serverOverloaded()) {
       Guard g(connMutex_);
       nConnectionsDropped_++;
       nTotalConnectionsDropped_++;
       if (overloadAction_ == T_OVERLOAD_CLOSE_ON_ACCEPT) {
-        ::THRIFT_CLOSESOCKET(clientSocket);
+        clientSocket->close();
         return;
       } else if (overloadAction_ == T_OVERLOAD_DRAIN_TASK_QUEUE) {
         if (!drainPendingTask()) {
           // Nothing left to discard, so we drop connection instead.
-          ::THRIFT_CLOSESOCKET(clientSocket);
+          clientSocket->close();
           return;
         }
       }
     }
 
-    // Explicitly set this socket to NONBLOCK mode
-    int flags;
-    if ((flags = THRIFT_FCNTL(clientSocket, THRIFT_F_GETFL, 0)) < 0 ||
-        THRIFT_FCNTL(clientSocket, THRIFT_F_SETFL, flags | THRIFT_O_NONBLOCK) < 0) {
-      GlobalOutput.perror("thriftServerEventHandler: set THRIFT_O_NONBLOCK (THRIFT_FCNTL) ", THRIFT_GET_SOCKET_ERROR);
-      ::THRIFT_CLOSESOCKET(clientSocket);
-      return;
-    }
-
     // Create a new TConnection for this client socket.
-    TConnection* clientConnection =
-      createConnection(clientSocket, addrp, addrLen);
+    TConnection* clientConnection = createConnection(clientSocket);
 
     // Fail fast if we could not create a TConnection object
     if (clientConnection == NULL) {
       GlobalOutput.printf("thriftServerEventHandler: failed TConnection factory");
-      ::THRIFT_CLOSESOCKET(clientSocket);
+      clientSocket->close();
       return;
     }
 
@@ -1003,18 +1000,11 @@
     if (clientConnection->getIOThreadNumber() == 0) {
       clientConnection->transition();
     } else {
-      clientConnection->notifyIOThread();
+      if (!clientConnection->notifyIOThread()) {
+        GlobalOutput.perror("[ERROR] notifyIOThread failed on fresh connection, closing", errno);
+        clientConnection->close();
+      }
     }
-
-    // addrLen is written by the accept() call, so needs to be set before the next call.
-    addrLen = sizeof(addrStorage);
-  }
-
-
-  // Done looping accept, now we have to make sure the error is due to
-  // blocking. Any other error is a problem
-  if (THRIFT_GET_SOCKET_ERROR != THRIFT_EAGAIN && THRIFT_GET_SOCKET_ERROR != THRIFT_EWOULDBLOCK) {
-    GlobalOutput.perror("thriftServerEventHandler: accept() ", THRIFT_GET_SOCKET_ERROR);
   }
 }
 
@@ -1022,137 +1012,39 @@
  * Creates a socket to listen on and binds it to the local port.
  */
 void TNonblockingServer::createAndListenOnSocket() {
-  THRIFT_SOCKET s;
-
-  struct addrinfo hints, *res, *res0;
-  int error;
-
-  char port[sizeof("65536") + 1];
-  memset(&hints, 0, sizeof(hints));
-  hints.ai_family = PF_UNSPEC;
-  hints.ai_socktype = SOCK_STREAM;
-  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
-  sprintf(port, "%d", port_);
-
-  // Wildcard address
-  error = getaddrinfo(NULL, port, &hints, &res0);
-  if (error) {
-    throw TException("TNonblockingServer::serve() getaddrinfo " +
-                     string(THRIFT_GAI_STRERROR(error)));
-  }
-
-  // Pick the ipv6 address first since ipv4 addresses can be mapped
-  // into ipv6 space.
-  for (res = res0; res; res = res->ai_next) {
-    if (res->ai_family == AF_INET6 || res->ai_next == NULL)
-      break;
-  }
-
-  // Create the server socket
-  s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
-  if (s == -1) {
-    freeaddrinfo(res0);
-    throw TException("TNonblockingServer::serve() socket() -1");
-  }
-
-  #ifdef IPV6_V6ONLY
-  if (res->ai_family == AF_INET6) {
-    int zero = 0;
-    if (-1 == setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, const_cast_sockopt(&zero), sizeof(zero))) {
-      GlobalOutput("TServerSocket::listen() IPV6_V6ONLY");
-    }
-  }
-  #endif // #ifdef IPV6_V6ONLY
-
-
-  int one = 1;
-
-  // Set THRIFT_NO_SOCKET_CACHING to avoid 2MSL delay on server restart
-  setsockopt(s, SOL_SOCKET, THRIFT_NO_SOCKET_CACHING, const_cast_sockopt(&one), sizeof(one));
-
-  if (::bind(s, res->ai_addr, static_cast<int>(res->ai_addrlen)) == -1) {
-    ::THRIFT_CLOSESOCKET(s);
-    freeaddrinfo(res0);
-    throw TTransportException(TTransportException::NOT_OPEN,
-                              "TNonblockingServer::serve() bind",
-                              THRIFT_GET_SOCKET_ERROR);
-  }
-
-  // Done with the addr info
-  freeaddrinfo(res0);
-
-  // Set up this file descriptor for listening
-  listenSocket(s);
+  serverTransport_->listen();
+  serverSocket_ = serverTransport_->getSocketFD();
 }
 
-/**
- * Takes a socket created by listenSocket() and sets various options on it
- * to prepare for use in the server.
- */
-void TNonblockingServer::listenSocket(THRIFT_SOCKET s) {
-  // Set socket to nonblocking mode
-  int flags;
-  if ((flags = THRIFT_FCNTL(s, THRIFT_F_GETFL, 0)) < 0 ||
-      THRIFT_FCNTL(s, THRIFT_F_SETFL, flags | THRIFT_O_NONBLOCK) < 0) {
-    ::THRIFT_CLOSESOCKET(s);
-    throw TException("TNonblockingServer::serve() THRIFT_O_NONBLOCK");
-  }
 
-  int one = 1;
-  struct linger ling = {0, 0};
-
-  // Keepalive to ensure full result flushing
-  setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, const_cast_sockopt(&one), sizeof(one));
-
-  // Turn linger off to avoid hung sockets
-  setsockopt(s, SOL_SOCKET, SO_LINGER, const_cast_sockopt(&ling), sizeof(ling));
-
-  // Set TCP nodelay if available, MAC OS X Hack
-  // See http://lists.danga.com/pipermail/memcached/2005-March/001240.html
-  #ifndef TCP_NOPUSH
-  setsockopt(s, IPPROTO_TCP, TCP_NODELAY, const_cast_sockopt(&one), sizeof(one));
-  #endif
-
-  #ifdef TCP_LOW_MIN_RTO
-  if (TSocket::getUseLowMinRto()) {
-    setsockopt(s, IPPROTO_TCP, TCP_LOW_MIN_RTO, const_cast_sockopt(&one), sizeof(one));
-  }
-  #endif
-
-  if (listen(s, LISTEN_BACKLOG) == -1) {
-    ::THRIFT_CLOSESOCKET(s);
-    throw TException("TNonblockingServer::serve() listen");
-  }
-
-  // Cool, this socket is good to go, set it as the serverSocket_
-  serverSocket_ = s;
-}
-
-void TNonblockingServer::setThreadManager(boost::shared_ptr<ThreadManager> threadManager) {
+void TNonblockingServer::setThreadManager(std::shared_ptr<ThreadManager> threadManager) {
   threadManager_ = threadManager;
   if (threadManager) {
-    threadManager->setExpireCallback(apache::thrift::stdcxx::bind(&TNonblockingServer::expireClose, this, apache::thrift::stdcxx::placeholders::_1));
+    threadManager->setExpireCallback(
+        std::bind(&TNonblockingServer::expireClose,
+                                     this,
+                                     std::placeholders::_1));
     threadPoolProcessing_ = true;
   } else {
     threadPoolProcessing_ = false;
   }
 }
 
-bool  TNonblockingServer::serverOverloaded() {
+bool TNonblockingServer::serverOverloaded() {
   size_t activeConnections = numTConnections_ - connectionStack_.size();
-  if (numActiveProcessors_ > maxActiveProcessors_ ||
-      activeConnections > maxConnections_) {
+  if (numActiveProcessors_ > maxActiveProcessors_ || activeConnections > maxConnections_) {
     if (!overloaded_) {
-       GlobalOutput.printf("TNonblockingServer: overload condition begun.");
+      GlobalOutput.printf("TNonblockingServer: overload condition begun.");
       overloaded_ = true;
     }
   } else {
-    if (overloaded_ &&
-        (numActiveProcessors_ <= overloadHysteresis_ * maxActiveProcessors_) &&
-        (activeConnections <= overloadHysteresis_ * maxConnections_)) {
-      GlobalOutput.printf("TNonblockingServer: overload ended; "
-                          "%u dropped (%llu total)",
-                          nConnectionsDropped_, nTotalConnectionsDropped_);
+    if (overloaded_ && (numActiveProcessors_ <= overloadHysteresis_ * maxActiveProcessors_)
+        && (activeConnections <= overloadHysteresis_ * maxConnections_)) {
+      GlobalOutput.printf(
+          "TNonblockingServer: overload ended; "
+          "%u dropped (%llu total)",
+          nConnectionsDropped_,
+          nTotalConnectionsDropped_);
       nConnectionsDropped_ = 0;
       overloaded_ = false;
     }
@@ -1163,12 +1055,10 @@
 
 bool TNonblockingServer::drainPendingTask() {
   if (threadManager_) {
-    boost::shared_ptr<Runnable> task = threadManager_->removeNextPending();
+    std::shared_ptr<Runnable> task = threadManager_->removeNextPending();
     if (task) {
-      TConnection* connection =
-        static_cast<TConnection::Task*>(task.get())->getTConnection();
-      assert(connection && connection->getServer()
-             && connection->getState() == APP_WAIT_TASK);
+      TConnection* connection = static_cast<TConnection::Task*>(task.get())->getTConnection();
+      assert(connection && connection->getServer() && connection->getState() == APP_WAIT_TASK);
       connection->forceClose();
       return true;
     }
@@ -1176,11 +1066,9 @@
   return false;
 }
 
-void TNonblockingServer::expireClose(boost::shared_ptr<Runnable> task) {
-  TConnection* connection =
-    static_cast<TConnection::Task*>(task.get())->getTConnection();
-  assert(connection && connection->getServer() &&
-         connection->getState() == APP_WAIT_TASK);
+void TNonblockingServer::expireClose(std::shared_ptr<Runnable> task) {
+  TConnection* connection = static_cast<TConnection::Task*>(task.get())->getTConnection();
+  assert(connection && connection->getServer() && connection->getState() == APP_WAIT_TASK);
   connection->forceClose();
 }
 
@@ -1203,13 +1091,15 @@
   if (!numIOThreads_) {
     numIOThreads_ = DEFAULT_IO_THREADS;
   }
+  // User-provided event-base doesn't works for multi-threaded servers
+  assert(numIOThreads_ == 1 || !userEventBase_);
 
   for (uint32_t id = 0; id < numIOThreads_; ++id) {
     // the first IO thread also does the listening on server socket
     THRIFT_SOCKET listenFd = (id == 0 ? serverSocket_ : THRIFT_INVALID_SOCKET);
 
     shared_ptr<TNonblockingIOThread> thread(
-      new TNonblockingIOThread(this, id, listenFd, useHighPriorityIOThreads_));
+        new TNonblockingIOThread(this, id, listenFd, useHighPriorityIOThreads_));
     ioThreads_.push_back(thread);
   }
 
@@ -1223,19 +1113,19 @@
   assert(ioThreads_.size() == numIOThreads_);
   assert(ioThreads_.size() > 0);
 
-  GlobalOutput.printf("TNonblockingServer: Serving on port %d, %d io threads.",
-               port_, ioThreads_.size());
+  GlobalOutput.printf("TNonblockingServer: Serving with %d io threads.",
+                      ioThreads_.size());
 
   // Launch all the secondary IO threads in separate threads
   if (ioThreads_.size() > 1) {
     ioThreadFactory_.reset(new PlatformThreadFactory(
-#if !defined(USE_BOOST_THREAD) && !defined(USE_STD_THREAD)
-      PlatformThreadFactory::OTHER,  // scheduler
-      PlatformThreadFactory::NORMAL, // priority
-      1,                          // stack size (MB)
+#if !USE_STD_THREAD
+        PlatformThreadFactory::OTHER,  // scheduler
+        PlatformThreadFactory::NORMAL, // priority
+        1,                             // stack size (MB)
 #endif
-      false                       // detached
-    ));
+        false // detached
+        ));
 
     assert(ioThreadFactory_.get());
 
@@ -1257,7 +1147,8 @@
  */
 void TNonblockingServer::serve() {
 
-  registerEvents(NULL);
+  if (ioThreads_.empty())
+    registerEvents(NULL);
 
   // Run the primary (listener) IO thread loop in our main thread; this will
   // only return when the server is shutting down.
@@ -1274,12 +1165,12 @@
                                            int number,
                                            THRIFT_SOCKET listenSocket,
                                            bool useHighPriority)
-      : server_(server)
-      , number_(number)
-      , listenSocket_(listenSocket)
-      , useHighPriority_(useHighPriority)
-      , eventBase_(NULL)
-      , ownEventBase_(false) {
+  : server_(server),
+    number_(number),
+    listenSocket_(listenSocket),
+    useHighPriority_(useHighPriority),
+    eventBase_(NULL),
+    ownEventBase_(false) {
   notificationPipeFDs_[0] = -1;
   notificationPipeFDs_[1] = -1;
 }
@@ -1293,10 +1184,9 @@
     ownEventBase_ = false;
   }
 
-  if (listenSocket_ >= 0) {
+  if (listenSocket_ != THRIFT_INVALID_SOCKET) {
     if (0 != ::THRIFT_CLOSESOCKET(listenSocket_)) {
-      GlobalOutput.perror("TNonblockingIOThread listenSocket_ close(): ",
-                          THRIFT_GET_SOCKET_ERROR);
+      GlobalOutput.perror("TNonblockingIOThread listenSocket_ close(): ", THRIFT_GET_SOCKET_ERROR);
     }
     listenSocket_ = THRIFT_INVALID_SOCKET;
   }
@@ -1313,12 +1203,12 @@
 }
 
 void TNonblockingIOThread::createNotificationPipe() {
-  if(evutil_socketpair(AF_LOCAL, SOCK_STREAM, 0, notificationPipeFDs_) == -1) {
+  if (evutil_socketpair(AF_LOCAL, SOCK_STREAM, 0, notificationPipeFDs_) == -1) {
     GlobalOutput.perror("TNonblockingServer::createNotificationPipe ", EVUTIL_SOCKET_ERROR());
     throw TException("can't create notification pipe");
   }
-  if(evutil_make_socket_nonblocking(notificationPipeFDs_[0])<0 ||
-     evutil_make_socket_nonblocking(notificationPipeFDs_[1])<0) {
+  if (evutil_make_socket_nonblocking(notificationPipeFDs_[0]) < 0
+      || evutil_make_socket_nonblocking(notificationPipeFDs_[1]) < 0) {
     ::THRIFT_CLOSESOCKET(notificationPipeFDs_[0]);
     ::THRIFT_CLOSESOCKET(notificationPipeFDs_[1]);
     throw TException("TNonblockingServer::createNotificationPipe() THRIFT_O_NONBLOCK");
@@ -1326,15 +1216,16 @@
   for (int i = 0; i < 2; ++i) {
 #if LIBEVENT_VERSION_NUMBER < 0x02000000
     int flags;
-    if ((flags = THRIFT_FCNTL(notificationPipeFDs_[i], F_GETFD, 0)) < 0 ||
-        THRIFT_FCNTL(notificationPipeFDs_[i], F_SETFD, flags | FD_CLOEXEC) < 0) {
+    if ((flags = THRIFT_FCNTL(notificationPipeFDs_[i], F_GETFD, 0)) < 0
+        || THRIFT_FCNTL(notificationPipeFDs_[i], F_SETFD, flags | FD_CLOEXEC) < 0) {
 #else
     if (evutil_make_socket_closeonexec(notificationPipeFDs_[i]) < 0) {
 #endif
       ::THRIFT_CLOSESOCKET(notificationPipeFDs_[0]);
       ::THRIFT_CLOSESOCKET(notificationPipeFDs_[1]);
-      throw TException("TNonblockingServer::createNotificationPipe() "
-        "FD_CLOEXEC");
+      throw TException(
+          "TNonblockingServer::createNotificationPipe() "
+          "FD_CLOEXEC");
     }
   }
 }
@@ -1355,11 +1246,11 @@
   // Print some libevent stats
   if (number_ == 0) {
     GlobalOutput.printf("TNonblockingServer: using libevent %s method %s",
-            event_get_version(),
-            event_base_get_method(eventBase_));
+                        event_get_version(),
+                        event_base_get_method(eventBase_));
   }
 
-  if (listenSocket_ >= 0) {
+  if (listenSocket_ != THRIFT_INVALID_SOCKET) {
     // Register the server event
     event_set(&serverEvent_,
               listenSocket_,
@@ -1370,11 +1261,11 @@
 
     // Add the event and start up the server
     if (-1 == event_add(&serverEvent_, 0)) {
-      throw TException("TNonblockingServer::serve(): "
-                       "event_add() failed on server listen event");
+      throw TException(
+          "TNonblockingServer::serve(): "
+          "event_add() failed on server listen event");
     }
-    GlobalOutput.printf("TNonblocking: IO thread #%d registered for listen.",
-                        number_);
+    GlobalOutput.printf("TNonblocking: IO thread #%d registered for listen.", number_);
   }
 
   createNotificationPipe();
@@ -1391,11 +1282,11 @@
 
   // Add the event and start up the server
   if (-1 == event_add(&notificationEvent_, 0)) {
-    throw TException("TNonblockingServer::serve(): "
-                     "event_add() failed on task-done notification event");
+    throw TException(
+        "TNonblockingServer::serve(): "
+        "event_add() failed on task-done notification event");
   }
-  GlobalOutput.printf("TNonblocking: IO thread #%d registered for notify.",
-                      number_);
+  GlobalOutput.printf("TNonblocking: IO thread #%d registered for notify.", number_);
 }
 
 bool TNonblockingIOThread::notify(TNonblockingServer::TConnection* conn) {
@@ -1404,46 +1295,115 @@
     return false;
   }
 
-  const int kSize = sizeof(conn);
-  if (send(fd, const_cast_sockopt(&conn), kSize, 0) != kSize) {
-    return false;
+  int ret = -1;
+  long kSize = sizeof(conn);
+  const char * pos = (const char *)const_cast_sockopt(&conn);
+
+#if defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H)
+  struct pollfd pfd = {fd, POLLOUT, 0};
+
+  while (kSize > 0) {
+    pfd.revents = 0;
+    ret = poll(&pfd, 1, -1);
+    if (ret < 0) {
+      return false;
+    } else if (ret == 0) {
+      continue;
+    }
+
+    if (pfd.revents & POLLHUP || pfd.revents & POLLERR) {
+      ::THRIFT_CLOSESOCKET(fd);
+      return false;
+    }
+
+    if (pfd.revents & POLLOUT) {
+      ret = send(fd, pos, kSize, 0);
+      if (ret < 0) {
+        if (errno == EAGAIN) {
+          continue;
+        }
+
+        ::THRIFT_CLOSESOCKET(fd);
+        return false;
+      }
+
+      kSize -= ret;
+      pos += ret;
+    }
   }
+#else
+  fd_set wfds, efds;
+
+  while (kSize > 0) {
+    FD_ZERO(&wfds);
+    FD_ZERO(&efds);
+    FD_SET(fd, &wfds);
+    FD_SET(fd, &efds);
+    ret = select(static_cast<int>(fd + 1), NULL, &wfds, &efds, NULL);
+    if (ret < 0) {
+      return false;
+    } else if (ret == 0) {
+      continue;
+    }
+
+    if (FD_ISSET(fd, &efds)) {
+      ::THRIFT_CLOSESOCKET(fd);
+      return false;
+    }
+
+    if (FD_ISSET(fd, &wfds)) {
+      ret = send(fd, pos, kSize, 0);
+      if (ret < 0) {
+        if (errno == EAGAIN) {
+          continue;
+        }
+
+        ::THRIFT_CLOSESOCKET(fd);
+        return false;
+      }
+
+      kSize -= ret;
+      pos += ret;
+    }
+  }
+#endif
 
   return true;
 }
 
 /* static */
 void TNonblockingIOThread::notifyHandler(evutil_socket_t fd, short which, void* v) {
-  TNonblockingIOThread* ioThread = (TNonblockingIOThread*) v;
+  TNonblockingIOThread* ioThread = (TNonblockingIOThread*)v;
   assert(ioThread);
   (void)which;
 
   while (true) {
     TNonblockingServer::TConnection* connection = 0;
     const int kSize = sizeof(connection);
-    int nBytes = recv(fd, cast_sockopt(&connection), kSize, 0);
+    long nBytes = recv(fd, cast_sockopt(&connection), kSize, 0);
     if (nBytes == kSize) {
       if (connection == NULL) {
         // this is the command to stop our thread, exit the handler!
+        ioThread->breakLoop(false);
         return;
       }
       connection->transition();
     } else if (nBytes > 0) {
       // throw away these bytes and hope that next time we get a solid read
-      GlobalOutput.printf("notifyHandler: Bad read of %d bytes, wanted %d",
-                          nBytes, kSize);
+      GlobalOutput.printf("notifyHandler: Bad read of %d bytes, wanted %d", nBytes, kSize);
       ioThread->breakLoop(true);
       return;
     } else if (nBytes == 0) {
       GlobalOutput.printf("notifyHandler: Notify socket closed!");
+      ioThread->breakLoop(false);
       // exit the loop
       break;
     } else { // nBytes < 0
-      if (THRIFT_GET_SOCKET_ERROR != THRIFT_EWOULDBLOCK && THRIFT_GET_SOCKET_ERROR != THRIFT_EAGAIN) {
-          GlobalOutput.perror(
-            "TNonblocking: notifyHandler read() failed: ", THRIFT_GET_SOCKET_ERROR);
-          ioThread->breakLoop(true);
-          return;
+      if (THRIFT_GET_SOCKET_ERROR != THRIFT_EWOULDBLOCK
+          && THRIFT_GET_SOCKET_ERROR != THRIFT_EAGAIN) {
+        GlobalOutput.perror("TNonblocking: notifyHandler read() failed: ", THRIFT_GET_SOCKET_ERROR);
+        ioThread->breakLoop(true);
+        return;
       }
       // exit the loop
       break;
@@ -1453,27 +1413,22 @@
 
 void TNonblockingIOThread::breakLoop(bool error) {
   if (error) {
-    GlobalOutput.printf(
-      "TNonblockingServer: IO thread #%d exiting with error.", number_);
+    GlobalOutput.printf("TNonblockingServer: IO thread #%d exiting with error.", number_);
     // TODO: figure out something better to do here, but for now kill the
     // whole process.
     GlobalOutput.printf("TNonblockingServer: aborting process.");
     ::abort();
   }
 
-  // sets a flag so that the loop exits on the next event
-  event_base_loopbreak(eventBase_);
-
-  // event_base_loopbreak() only causes the loop to exit the next time
-  // it wakes up.  We need to force it to wake up, in case there are
-  // no real events it needs to process.
-  //
   // If we're running in the same thread, we can't use the notify(0)
   // mechanism to stop the thread, but happily if we're running in the
   // same thread, this means the thread can't be blocking in the event
   // loop either.
   if (!Thread::is_current(threadId_)) {
     notify(NULL);
+  } else {
+    // cause the loop to stop ASAP - even if it has things to do in it
+    event_base_loopbreak(eventBase_);
   }
 }
 
@@ -1481,7 +1436,7 @@
 #ifdef HAVE_SCHED_H
   // Start out with a standard, low-priority setup for the sched params.
   struct sched_param sp;
-  bzero((void*) &sp, sizeof(sp));
+  bzero((void*)&sp, sizeof(sp));
   int policy = SCHED_OTHER;
 
   // If desired, set up high-priority sched params structure.
@@ -1490,16 +1445,14 @@
     policy = SCHED_FIFO;
     // The priority only compares us to other SCHED_FIFO threads, so we
     // just pick a random priority halfway between min & max.
-    const int priority = (sched_get_priority_max(policy) +
-                          sched_get_priority_min(policy)) / 2;
+    const int priority = (sched_get_priority_max(policy) + sched_get_priority_min(policy)) / 2;
 
     sp.sched_priority = priority;
   }
 
   // Actually set the sched params for the current thread.
   if (0 == pthread_setschedparam(pthread_self(), policy, &sp)) {
-    GlobalOutput.printf(
-      "TNonblocking: IO Thread #%d using high-priority scheduler!", number_);
+    GlobalOutput.printf("TNonblocking: IO Thread #%d using high-priority scheduler!", number_);
   } else {
     GlobalOutput.perror("TNonblocking: pthread_setschedparam(): ", THRIFT_GET_SOCKET_ERROR);
   }
@@ -1509,33 +1462,33 @@
 }
 
 void TNonblockingIOThread::run() {
-  if (eventBase_ == NULL)
+  if (eventBase_ == NULL) {
     registerEvents();
-
-  GlobalOutput.printf("TNonblockingServer: IO thread #%d entering loop...",
-                      number_);
-
+  }
   if (useHighPriority_) {
     setCurrentThreadHighPriority(true);
   }
 
-  // Run libevent engine, never returns, invokes calls to eventHandler
-  event_base_loop(eventBase_, 0);
+  if (eventBase_ != NULL)
+  {
+    GlobalOutput.printf("TNonblockingServer: IO thread #%d entering loop...", number_);
+    // Run libevent engine, never returns, invokes calls to eventHandler
+    event_base_loop(eventBase_, 0);
 
-  if (useHighPriority_) {
-    setCurrentThreadHighPriority(false);
+    if (useHighPriority_) {
+      setCurrentThreadHighPriority(false);
+    }
+
+    // cleans up our registered events
+    cleanupEvents();
   }
 
-  // cleans up our registered events
-  cleanupEvents();
-
-  GlobalOutput.printf("TNonblockingServer: IO thread #%d run() done!",
-    number_);
+  GlobalOutput.printf("TNonblockingServer: IO thread #%d run() done!", number_);
 }
 
 void TNonblockingIOThread::cleanupEvents() {
   // stop the listen socket, if any
-  if (listenSocket_ >= 0) {
+  if (listenSocket_ != THRIFT_INVALID_SOCKET) {
     if (event_del(&serverEvent_) == -1) {
       GlobalOutput.perror("TNonblockingIOThread::stop() event_del: ", THRIFT_GET_SOCKET_ERROR);
     }
@@ -1544,7 +1497,6 @@
   event_del(&notificationEvent_);
 }
 
-
 void TNonblockingIOThread::stop() {
   // This should cause the thread to fall out of its event loop ASAP.
   breakLoop(false);
@@ -1558,10 +1510,11 @@
       // Note that it is safe to both join() ourselves twice, as well as join
       // the current thread as the pthread implementation checks for deadlock.
       thread_->join();
-    } catch(...) {
+    } catch (...) {
       // swallow everything
     }
   }
 }
-
-}}} // apache::thrift::server
+}
+}
+} // apache::thrift::server
diff --git a/lib/cpp/src/thrift/server/TNonblockingServer.h b/lib/cpp/src/thrift/server/TNonblockingServer.h
index 532d4ae..e79c24f 100644
--- a/lib/cpp/src/thrift/server/TNonblockingServer.h
+++ b/lib/cpp/src/thrift/server/TNonblockingServer.h
@@ -21,10 +21,12 @@
 #define _THRIFT_SERVER_TNONBLOCKINGSERVER_H_ 1
 
 #include <thrift/Thrift.h>
+#include <memory>
 #include <thrift/server/TServer.h>
 #include <thrift/transport/PlatformSocket.h>
 #include <thrift/transport/TBufferTransports.h>
 #include <thrift/transport/TSocket.h>
+#include <thrift/transport/TNonblockingServerTransport.h>
 #include <thrift/concurrency/ThreadManager.h>
 #include <climits>
 #include <thrift/concurrency/Thread.h>
@@ -38,13 +40,16 @@
 #include <unistd.h>
 #endif
 #include <event.h>
+#include <event2/event_compat.h>
+#include <event2/event_struct.h>
 
-
-
-namespace apache { namespace thrift { namespace server {
+namespace apache {
+namespace thrift {
+namespace server {
 
 using apache::thrift::transport::TMemoryBuffer;
 using apache::thrift::transport::TSocket;
+using apache::thrift::transport::TNonblockingServerTransport;
 using apache::thrift::protocol::TProtocol;
 using apache::thrift::concurrency::Runnable;
 using apache::thrift::concurrency::ThreadManager;
@@ -63,27 +68,28 @@
 #define LIBEVENT_VERSION_MAJOR 1
 #define LIBEVENT_VERSION_MINOR 14
 #define LIBEVENT_VERSION_REL 13
-#define LIBEVENT_VERSION_NUMBER ((LIBEVENT_VERSION_MAJOR << 24) | (LIBEVENT_VERSION_MINOR << 16) | (LIBEVENT_VERSION_REL << 8))
+#define LIBEVENT_VERSION_NUMBER                                                                    \
+  ((LIBEVENT_VERSION_MAJOR << 24) | (LIBEVENT_VERSION_MINOR << 16) | (LIBEVENT_VERSION_REL << 8))
 #endif
 
 #if LIBEVENT_VERSION_NUMBER < 0x02000000
- typedef THRIFT_SOCKET evutil_socket_t;
+typedef THRIFT_SOCKET evutil_socket_t;
 #endif
 
 #ifndef SOCKOPT_CAST_T
-#   ifndef _WIN32
-#       define SOCKOPT_CAST_T void
-#   else
-#       define SOCKOPT_CAST_T char
-#   endif // _WIN32
+#ifndef _WIN32
+#define SOCKOPT_CAST_T void
+#else
+#define SOCKOPT_CAST_T char
+#endif // _WIN32
 #endif
 
-template<class T>
+template <class T>
 inline const SOCKOPT_CAST_T* const_cast_sockopt(const T* v) {
   return reinterpret_cast<const SOCKOPT_CAST_T*>(v);
 }
 
-template<class T>
+template <class T>
 inline SOCKOPT_CAST_T* cast_sockopt(T* v) {
   return reinterpret_cast<SOCKOPT_CAST_T*>(v);
 }
@@ -93,28 +99,24 @@
  * operates a set of IO threads (by default only one). It assumes that
  * all incoming requests are framed with a 4 byte length indicator and
  * writes out responses using the same framing.
- *
- * It does not use the TServerTransport framework, but rather has socket
- * operations hardcoded for use with select.
- *
  */
 
-
 /// Overload condition actions.
 enum TOverloadAction {
-  T_OVERLOAD_NO_ACTION,        ///< Don't handle overload */
-  T_OVERLOAD_CLOSE_ON_ACCEPT,  ///< Drop new connections immediately */
-  T_OVERLOAD_DRAIN_TASK_QUEUE  ///< Drop some tasks from head of task queue */
+  T_OVERLOAD_NO_ACTION,       ///< Don't handle overload */
+  T_OVERLOAD_CLOSE_ON_ACCEPT, ///< Drop new connections immediately */
+  T_OVERLOAD_DRAIN_TASK_QUEUE ///< Drop some tasks from head of task queue */
 };
 
 class TNonblockingIOThread;
 
 class TNonblockingServer : public TServer {
- private:
+private:
   class TConnection;
 
   friend class TNonblockingIOThread;
- private:
+
+private:
   /// Listen backlog
   static const int LISTEN_BACKLOG = 1024;
 
@@ -154,23 +156,20 @@
   /// Server socket file descriptor
   THRIFT_SOCKET serverSocket_;
 
-  /// Port server runs on
-  int port_;
-
   /// The optional user-provided event-base (for single-thread servers)
   event_base* userEventBase_;
 
   /// For processing via thread pool, may be NULL
-  boost::shared_ptr<ThreadManager> threadManager_;
+  std::shared_ptr<ThreadManager> threadManager_;
 
   /// Is thread pool processing?
   bool threadPoolProcessing_;
 
   // Factory to create the IO threads
-  boost::shared_ptr<PlatformThreadFactory> ioThreadFactory_;
+  std::shared_ptr<PlatformThreadFactory> ioThreadFactory_;
 
   // Vector of IOThread objects that will handle our IO
-  std::vector<boost::shared_ptr<TNonblockingIOThread> > ioThreads_;
+  std::vector<std::shared_ptr<TNonblockingIOThread> > ioThreads_;
 
   // Index of next IO Thread to be used (for round-robin)
   uint32_t nextIOThread_;
@@ -263,22 +262,24 @@
    */
   std::vector<TConnection*> activeConnections_;
 
+  /*
+  */
+  std::shared_ptr<TNonblockingServerTransport> serverTransport_;
+
   /**
    * Called when server socket had something happen.  We accept all waiting
    * client connections on listen socket fd and assign TConnection objects
    * to handle those requests.
    *
-   * @param fd the listen socket.
    * @param which the event flag that triggered the handler.
    */
   void handleEvent(THRIFT_SOCKET fd, short which);
 
-  void init(int port) {
+  void init() {
     serverSocket_ = THRIFT_INVALID_SOCKET;
     numIOThreads_ = DEFAULT_IO_THREADS;
     nextIOThread_ = 0;
     useHighPriorityIOThreads_ = false;
-    port_ = port;
     userEventBase_ = NULL;
     threadPoolProcessing_ = false;
     numTConnections_ = 0;
@@ -299,72 +300,56 @@
     nTotalConnectionsDropped_ = 0;
   }
 
- public:
-  template<typename ProcessorFactory>
-  TNonblockingServer(
-      const boost::shared_ptr<ProcessorFactory>& processorFactory,
-      int port,
-      THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)) :
-    TServer(processorFactory) {
-    init(port);
+public:
+  TNonblockingServer(const std::shared_ptr<TProcessorFactory>& processorFactory,
+                     const std::shared_ptr<apache::thrift::transport::TNonblockingServerTransport>& serverTransport)
+    : TServer(processorFactory), serverTransport_(serverTransport) {
+    init();
   }
 
-  template<typename Processor>
-  TNonblockingServer(const boost::shared_ptr<Processor>& processor,
-                     int port,
-                     THRIFT_OVERLOAD_IF(Processor, TProcessor)) :
-    TServer(processor) {
-    init(port);
+  TNonblockingServer(const std::shared_ptr<TProcessor>& processor,
+                     const std::shared_ptr<apache::thrift::transport::TNonblockingServerTransport>& serverTransport)
+    : TServer(processor), serverTransport_(serverTransport) {
+    init();
   }
 
-  template<typename ProcessorFactory>
-  TNonblockingServer(
-      const boost::shared_ptr<ProcessorFactory>& processorFactory,
-      const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-      int port,
-      const boost::shared_ptr<ThreadManager>& threadManager =
-        boost::shared_ptr<ThreadManager>(),
-      THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)) :
-    TServer(processorFactory) {
 
-    init(port);
+  TNonblockingServer(const std::shared_ptr<TProcessorFactory>& processorFactory,
+                     const std::shared_ptr<TProtocolFactory>& protocolFactory,
+                     const std::shared_ptr<apache::thrift::transport::TNonblockingServerTransport>& serverTransport,
+                     const std::shared_ptr<ThreadManager>& threadManager
+                     = std::shared_ptr<ThreadManager>())
+    : TServer(processorFactory), serverTransport_(serverTransport) {
+    init();
 
     setInputProtocolFactory(protocolFactory);
     setOutputProtocolFactory(protocolFactory);
     setThreadManager(threadManager);
   }
 
-  template<typename Processor>
-  TNonblockingServer(
-      const boost::shared_ptr<Processor>& processor,
-      const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-      int port,
-      const boost::shared_ptr<ThreadManager>& threadManager =
-        boost::shared_ptr<ThreadManager>(),
-      THRIFT_OVERLOAD_IF(Processor, TProcessor)) :
-    TServer(processor) {
-
-    init(port);
+  TNonblockingServer(const std::shared_ptr<TProcessor>& processor,
+                     const std::shared_ptr<TProtocolFactory>& protocolFactory,
+                     const std::shared_ptr<apache::thrift::transport::TNonblockingServerTransport>& serverTransport,
+                     const std::shared_ptr<ThreadManager>& threadManager
+                     = std::shared_ptr<ThreadManager>())
+    : TServer(processor), serverTransport_(serverTransport) {
+    init();
 
     setInputProtocolFactory(protocolFactory);
     setOutputProtocolFactory(protocolFactory);
     setThreadManager(threadManager);
   }
 
-  template<typename ProcessorFactory>
-  TNonblockingServer(
-      const boost::shared_ptr<ProcessorFactory>& processorFactory,
-      const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
-      const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
-      const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
-      const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
-      int port,
-      const boost::shared_ptr<ThreadManager>& threadManager =
-        boost::shared_ptr<ThreadManager>(),
-      THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)) :
-    TServer(processorFactory) {
-
-    init(port);
+  TNonblockingServer(const std::shared_ptr<TProcessorFactory>& processorFactory,
+                     const std::shared_ptr<TTransportFactory>& inputTransportFactory,
+                     const std::shared_ptr<TTransportFactory>& outputTransportFactory,
+                     const std::shared_ptr<TProtocolFactory>& inputProtocolFactory,
+                     const std::shared_ptr<TProtocolFactory>& outputProtocolFactory,
+                     const std::shared_ptr<apache::thrift::transport::TNonblockingServerTransport>& serverTransport,
+                     const std::shared_ptr<ThreadManager>& threadManager
+                     = std::shared_ptr<ThreadManager>())
+    : TServer(processorFactory), serverTransport_(serverTransport) {
+    init();
 
     setInputTransportFactory(inputTransportFactory);
     setOutputTransportFactory(outputTransportFactory);
@@ -373,20 +358,16 @@
     setThreadManager(threadManager);
   }
 
-  template<typename Processor>
-  TNonblockingServer(
-      const boost::shared_ptr<Processor>& processor,
-      const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
-      const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
-      const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
-      const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
-      int port,
-      const boost::shared_ptr<ThreadManager>& threadManager =
-        boost::shared_ptr<ThreadManager>(),
-      THRIFT_OVERLOAD_IF(Processor, TProcessor)) :
-    TServer(processor) {
-
-    init(port);
+  TNonblockingServer(const std::shared_ptr<TProcessor>& processor,
+                     const std::shared_ptr<TTransportFactory>& inputTransportFactory,
+                     const std::shared_ptr<TTransportFactory>& outputTransportFactory,
+                     const std::shared_ptr<TProtocolFactory>& inputProtocolFactory,
+                     const std::shared_ptr<TProtocolFactory>& outputProtocolFactory,
+                     const std::shared_ptr<apache::thrift::transport::TNonblockingServerTransport>& serverTransport,
+                     const std::shared_ptr<ThreadManager>& threadManager
+                     = std::shared_ptr<ThreadManager>())
+    : TServer(processor), serverTransport_(serverTransport) {
+    init();
 
     setInputTransportFactory(inputTransportFactory);
     setOutputTransportFactory(outputTransportFactory);
@@ -397,11 +378,11 @@
 
   ~TNonblockingServer();
 
-  void setThreadManager(boost::shared_ptr<ThreadManager> threadManager);
+  void setThreadManager(std::shared_ptr<ThreadManager> threadManager);
 
-  boost::shared_ptr<ThreadManager> getThreadManager() {
-    return threadManager_;
-  }
+  int getListenPort() { return serverTransport_->getListenPort(); }
+
+  std::shared_ptr<ThreadManager> getThreadManager() { return threadManager_; }
 
   /**
    * Sets the number of IO threads used by this server. Can only be used before
@@ -411,46 +392,36 @@
    */
   void setNumIOThreads(size_t numThreads) {
     numIOThreads_ = numThreads;
+    // User-provided event-base doesn't works for multi-threaded servers
+    assert(numIOThreads_ <= 1 || !userEventBase_);
   }
 
   /** Return whether the IO threads will get high scheduling priority */
-  bool useHighPriorityIOThreads() const {
-    return useHighPriorityIOThreads_;
-  }
+  bool useHighPriorityIOThreads() const { return useHighPriorityIOThreads_; }
 
   /** Set whether the IO threads will get high scheduling priority. */
-  void setUseHighPriorityIOThreads(bool val) {
-    useHighPriorityIOThreads_ = val;
-  }
+  void setUseHighPriorityIOThreads(bool val) { useHighPriorityIOThreads_ = val; }
 
   /** Return the number of IO threads used by this server. */
-  size_t getNumIOThreads() const {
-    return numIOThreads_;
-  }
+  size_t getNumIOThreads() const { return numIOThreads_; }
 
   /**
    * Get the maximum number of unused TConnection we will hold in reserve.
    *
    * @return the current limit on TConnection pool size.
    */
-  size_t getConnectionStackLimit() const {
-    return connectionStackLimit_;
-  }
+  size_t getConnectionStackLimit() const { return connectionStackLimit_; }
 
   /**
    * Set the maximum number of unused TConnection we will hold in reserve.
    *
    * @param sz the new limit for TConnection pool size.
    */
-  void setConnectionStackLimit(size_t sz) {
-    connectionStackLimit_ = sz;
-  }
+  void setConnectionStackLimit(size_t sz) { connectionStackLimit_ = sz; }
 
-  bool isThreadPoolProcessing() const {
-    return threadPoolProcessing_;
-  }
+  bool isThreadPoolProcessing() const { return threadPoolProcessing_; }
 
-  void addTask(boost::shared_ptr<Runnable> task) {
+  void addTask(std::shared_ptr<Runnable> task) {
     threadManager_->add(task, 0LL, taskExpireTime_);
   }
 
@@ -459,27 +430,21 @@
    *
    * @return count of connected sockets.
    */
-  size_t getNumConnections() const {
-    return numTConnections_;
-  }
+  size_t getNumConnections() const { return numTConnections_; }
 
   /**
    * Return the count of sockets currently connected to.
    *
    * @return count of connected sockets.
    */
-  size_t getNumActiveConnections() const {
-    return getNumConnections() - getNumIdleConnections();
-  }
+  size_t getNumActiveConnections() const { return getNumConnections() - getNumIdleConnections(); }
 
   /**
    * Return the count of connection objects allocated but not in use.
    *
    * @return count of idle connection objects.
    */
-  size_t getNumIdleConnections() const {
-    return connectionStack_.size();
-  }
+  size_t getNumIdleConnections() const { return connectionStack_.size(); }
 
   /**
    * Return count of number of connections which are currently processing.
@@ -489,9 +454,7 @@
    *
    * @return # of connections currently processing.
    */
-  size_t getNumActiveProcessors() const {
-    return numActiveProcessors_;
-  }
+  size_t getNumActiveProcessors() const { return numActiveProcessors_; }
 
   /// Increment the count of connections currently processing.
   void incrementActiveProcessors() {
@@ -512,27 +475,21 @@
    *
    * @return current setting.
    */
-  size_t getMaxConnections() const {
-    return maxConnections_;
-  }
+  size_t getMaxConnections() const { return maxConnections_; }
 
   /**
    * Set the maximum # of connections allowed before overload.
    *
    * @param maxConnections new setting for maximum # of connections.
    */
-  void setMaxConnections(size_t maxConnections) {
-    maxConnections_ = maxConnections;
-  }
+  void setMaxConnections(size_t maxConnections) { maxConnections_ = maxConnections; }
 
   /**
    * Get the maximum # of connections waiting in handler/task before overload.
    *
    * @return current setting.
    */
-  size_t getMaxActiveProcessors() const {
-    return maxActiveProcessors_;
-  }
+  size_t getMaxActiveProcessors() const { return maxActiveProcessors_; }
 
   /**
    * Set the maximum # of connections waiting in handler/task before overload.
@@ -551,27 +508,21 @@
    *
    * @return Maxium frame size, in bytes.
    */
-  size_t getMaxFrameSize() const {
-    return maxFrameSize_;
-  }
+  size_t getMaxFrameSize() const { return maxFrameSize_; }
 
   /**
    * Set the maximum allowed frame size.
    *
    * @param maxFrameSize The new maximum frame size.
    */
-  void setMaxFrameSize(size_t maxFrameSize) {
-    maxFrameSize_ = maxFrameSize;
-  }
+  void setMaxFrameSize(size_t maxFrameSize) { maxFrameSize_ = maxFrameSize; }
 
   /**
    * Get fraction of maximum limits before an overload condition is cleared.
    *
    * @return hysteresis fraction
    */
-  double getOverloadHysteresis() const {
-    return overloadHysteresis_;
-  }
+  double getOverloadHysteresis() const { return overloadHysteresis_; }
 
   /**
    * Set fraction of maximum limits before an overload condition is cleared.
@@ -590,36 +541,28 @@
    *
    * @return a TOverloadAction enum value for the currently set action.
    */
-  TOverloadAction getOverloadAction() const {
-    return overloadAction_;
-  }
+  TOverloadAction getOverloadAction() const { return overloadAction_; }
 
   /**
    * Set the action the server is to take on overload.
    *
    * @param overloadAction a TOverloadAction enum value for the action.
    */
-  void setOverloadAction(TOverloadAction overloadAction) {
-    overloadAction_ = overloadAction;
-  }
+  void setOverloadAction(TOverloadAction overloadAction) { overloadAction_ = overloadAction; }
 
   /**
    * Get the time in milliseconds after which a task expires (0 == infinite).
    *
    * @return a 64-bit time in milliseconds.
    */
-  int64_t getTaskExpireTime() const {
-    return taskExpireTime_;
-  }
+  int64_t getTaskExpireTime() const { return taskExpireTime_; }
 
   /**
    * Set the time in milliseconds after which a task expires (0 == infinite).
    *
    * @param taskExpireTime a 64-bit time in milliseconds.
    */
-  void setTaskExpireTime(int64_t taskExpireTime) {
-    taskExpireTime_ = taskExpireTime;
-  }
+  void setTaskExpireTime(int64_t taskExpireTime) { taskExpireTime_ = taskExpireTime; }
 
   /**
    * Determine if the server is currently overloaded.
@@ -643,27 +586,21 @@
    *
    * @return # bytes we initialize a TConnection object's write buffer to.
    */
-  size_t getWriteBufferDefaultSize() const {
-    return writeBufferDefaultSize_;
-  }
+  size_t getWriteBufferDefaultSize() const { return writeBufferDefaultSize_; }
 
   /**
    * Set the starting size of a TConnection object's write buffer.
    *
    * @param size # bytes we initialize a TConnection object's write buffer to.
    */
-  void setWriteBufferDefaultSize(size_t size) {
-    writeBufferDefaultSize_ = size;
-  }
+  void setWriteBufferDefaultSize(size_t size) { writeBufferDefaultSize_ = size; }
 
   /**
    * Get the maximum size of read buffer allocated to idle TConnection objects.
    *
    * @return # bytes beyond which we will dealloc idle buffer.
    */
-  size_t getIdleReadBufferLimit() const {
-    return idleReadBufferLimit_;
-  }
+  size_t getIdleReadBufferLimit() const { return idleReadBufferLimit_; }
 
   /**
    * [NOTE: This is for backwards compatibility, use getIdleReadBufferLimit().]
@@ -671,9 +608,7 @@
    *
    * @return # bytes beyond which we will dealloc idle buffer.
    */
-  size_t getIdleBufferMemLimit() const {
-    return idleReadBufferLimit_;
-  }
+  size_t getIdleBufferMemLimit() const { return idleReadBufferLimit_; }
 
   /**
    * Set the maximum size read buffer allocated to idle TConnection objects.
@@ -684,9 +619,7 @@
    *
    * @param limit of bytes beyond which we will shrink buffers when checked.
    */
-  void setIdleReadBufferLimit(size_t limit) {
-    idleReadBufferLimit_ = limit;
-  }
+  void setIdleReadBufferLimit(size_t limit) { idleReadBufferLimit_ = limit; }
 
   /**
    * [NOTE: This is for backwards compatibility, use setIdleReadBufferLimit().]
@@ -698,20 +631,14 @@
    *
    * @param limit of bytes beyond which we will shrink buffers when checked.
    */
-  void setIdleBufferMemLimit(size_t limit) {
-    idleReadBufferLimit_ = limit;
-  }
-
-
+  void setIdleBufferMemLimit(size_t limit) { idleReadBufferLimit_ = limit; }
 
   /**
    * Get the maximum size of write buffer allocated to idle TConnection objects.
    *
    * @return # bytes beyond which we will reallocate buffers when checked.
    */
-  size_t getIdleWriteBufferLimit() const {
-    return idleWriteBufferLimit_;
-  }
+  size_t getIdleWriteBufferLimit() const { return idleWriteBufferLimit_; }
 
   /**
    * Set the maximum size write buffer allocated to idle TConnection objects.
@@ -722,29 +649,23 @@
    *
    * @param limit of bytes beyond which we will shrink buffers when idle.
    */
-  void setIdleWriteBufferLimit(size_t limit) {
-    idleWriteBufferLimit_ = limit;
-  }
+  void setIdleWriteBufferLimit(size_t limit) { idleWriteBufferLimit_ = limit; }
 
   /**
    * Get # of calls made between buffer size checks.  0 means disabled.
    *
    * @return # of calls between buffer size checks.
    */
-  int32_t getResizeBufferEveryN() const {
-    return resizeBufferEveryN_;
-  }
+  int32_t getResizeBufferEveryN() const { return resizeBufferEveryN_; }
 
   /**
    * Check buffer sizes every "count" calls.  This allows buffer limits
-   * to be enforced for persistant connections with a controllable degree
+   * to be enforced for persistent connections with a controllable degree
    * of overhead. 0 disables checks except at connection close.
    *
    * @param count the number of calls between checks, or 0 to disable
    */
-  void setResizeBufferEveryN(int32_t count) {
-    resizeBufferEveryN_ = count;
-  }
+  void setResizeBufferEveryN(int32_t count) { resizeBufferEveryN_ = count; }
 
   /**
    * Main workhorse function, starts up the server listening on a port and
@@ -761,14 +682,6 @@
   void createAndListenOnSocket();
 
   /**
-   * Takes a socket created by createAndListenOnSocket() and sets various
-   * options on it to prepare for use in the server.
-   *
-   * @param fd descriptor of socket to be initialized/
-   */
-  void listenSocket(THRIFT_SOCKET fd);
-
-  /**
    * Register the optional user-provided event-base (for single-thread servers)
    *
    * This method should be used when the server is running in a single-thread
@@ -784,14 +697,19 @@
    */
   event_base* getUserEventBase() const { return userEventBase_; }
 
- private:
+  /** Some transports, like THeaderTransport, require passing through
+   * the framing size instead of stripping it.
+   */
+  bool getHeaderTransport();
+
+private:
   /**
    * Callback function that the threadmanager calls when a task reaches
    * its expiration time.  It is needed to clean up the expired connection.
    *
    * @param task the runnable associated with the expired task.
    */
-  void expireClose(boost::shared_ptr<Runnable> task);
+  void expireClose(std::shared_ptr<Runnable> task);
 
   /**
    * Return an initialized connection object.  Creates or recovers from
@@ -803,8 +721,7 @@
    * @param addrLen the length of addr
    * @return pointer to initialized TConnection object.
    */
-  TConnection* createConnection(THRIFT_SOCKET socket, const sockaddr* addr,
-                                            socklen_t addrLen);
+  TConnection* createConnection(std::shared_ptr<TSocket> socket);
 
   /**
    * Returns a connection to pool or deletion.  If the connection pool
@@ -817,7 +734,7 @@
 };
 
 class TNonblockingIOThread : public Runnable {
- public:
+public:
   // Creates an IO thread and sets up the event base.  The listenSocket should
   // be a valid FD on which listen() has already been called.  If the
   // listenSocket is < 0, accepting will not be done.
@@ -848,10 +765,10 @@
   evutil_socket_t getNotificationRecvFD() const { return notificationPipeFDs_[0]; }
 
   // Returns the actual thread object associated with this IO thread.
-  boost::shared_ptr<Thread> getThread() const { return thread_; }
+  std::shared_ptr<Thread> getThread() const { return thread_; }
 
   // Sets the actual thread object associated with this IO thread.
-  void setThread(const boost::shared_ptr<Thread>& t) { thread_ = t; }
+  void setThread(const std::shared_ptr<Thread>& t) { thread_ = t; }
 
   // Used by TConnection objects to indicate processing has finished.
   bool notify(TNonblockingServer::TConnection* conn);
@@ -868,7 +785,7 @@
   /// Registers the events for the notification & listen sockets
   void registerEvents();
 
- private:
+private:
   /**
    * C-callable event handler for signaling task completion.  Provides a
    * callback that libevent can understand that will read a connection
@@ -883,7 +800,7 @@
    * C-callable event handler for listener events.  Provides a callback
    * that libevent can understand which invokes server->handleEvent().
    *
-   * @param fd the descriptor the event occured on.
+   * @param fd the descriptor the event occurred on.
    * @param which the flags associated with the event.
    * @param v void* callback arg where we placed TNonblockingServer's "this".
    */
@@ -903,7 +820,7 @@
   /// Sets (or clears) high priority scheduling status for the current thread.
   void setCurrentThreadHighPriority(bool value);
 
- private:
+private:
   /// associated server
   TNonblockingServer* server_;
 
@@ -932,13 +849,14 @@
   /// Used with eventBase_ for task completion notification
   struct event notificationEvent_;
 
- /// File descriptors for pipe used for task completion notification.
+  /// File descriptors for pipe used for task completion notification.
   evutil_socket_t notificationPipeFDs_[2];
 
   /// Actual IO Thread
-  boost::shared_ptr<Thread> thread_;
+  std::shared_ptr<Thread> thread_;
 };
-
-}}} // apache::thrift::server
+}
+}
+} // apache::thrift::server
 
 #endif // #ifndef _THRIFT_SERVER_TNONBLOCKINGSERVER_H_
diff --git a/lib/cpp/src/thrift/server/TServer.cpp b/lib/cpp/src/thrift/server/TServer.cpp
old mode 100755
new mode 100644
index f4ce744..df731c2
--- a/lib/cpp/src/thrift/server/TServer.cpp
+++ b/lib/cpp/src/thrift/server/TServer.cpp
@@ -30,18 +30,23 @@
 #include <unistd.h>
 #endif
 
-namespace apache { namespace thrift { namespace server {
+namespace apache {
+namespace thrift {
+namespace server {
 
-int increase_max_fds(int max_fds=(1<<24))  {
+#ifdef HAVE_SYS_RESOURCE_H
+int increase_max_fds(int max_fds = (1 << 24)) {
   struct rlimit fdmaxrl;
 
-  for(fdmaxrl.rlim_cur = max_fds, fdmaxrl.rlim_max = max_fds;
-      max_fds && (setrlimit(RLIMIT_NOFILE, &fdmaxrl) < 0);
-      fdmaxrl.rlim_cur = max_fds, fdmaxrl.rlim_max = max_fds) {
+  for (fdmaxrl.rlim_cur = max_fds, fdmaxrl.rlim_max = max_fds;
+       max_fds && (setrlimit(RLIMIT_NOFILE, &fdmaxrl) < 0);
+       fdmaxrl.rlim_cur = max_fds, fdmaxrl.rlim_max = max_fds) {
     max_fds /= 2;
   }
 
   return static_cast<int>(fdmaxrl.rlim_cur);
 }
-
-}}} // apache::thrift::server
+#endif
+}
+}
+} // apache::thrift::server
diff --git a/lib/cpp/src/thrift/server/TServer.h b/lib/cpp/src/thrift/server/TServer.h
index c9e88b1..3c6d818 100644
--- a/lib/cpp/src/thrift/server/TServer.h
+++ b/lib/cpp/src/thrift/server/TServer.h
@@ -25,9 +25,11 @@
 #include <thrift/protocol/TBinaryProtocol.h>
 #include <thrift/concurrency/Thread.h>
 
-#include <boost/shared_ptr.hpp>
+#include <memory>
 
-namespace apache { namespace thrift { namespace server {
+namespace apache {
+namespace thrift {
+namespace server {
 
 using apache::thrift::TProcessor;
 using apache::thrift::protocol::TBinaryProtocolFactory;
@@ -45,8 +47,7 @@
  * instance's state).
  */
 class TServerEventHandler {
- public:
-
+public:
   virtual ~TServerEventHandler() {}
 
   /**
@@ -57,8 +58,8 @@
   /**
    * Called when a new client has connected and is about to being processing.
    */
-  virtual void* createContext(boost::shared_ptr<TProtocol> input,
-                              boost::shared_ptr<TProtocol> output) {
+  virtual void* createContext(std::shared_ptr<TProtocol> input,
+                              std::shared_ptr<TProtocol> output) {
     (void)input;
     (void)output;
     return NULL;
@@ -69,8 +70,8 @@
    * context.
    */
   virtual void deleteContext(void* serverContext,
-                             boost::shared_ptr<TProtocol>input,
-                             boost::shared_ptr<TProtocol>output) {
+                             std::shared_ptr<TProtocol> input,
+                             std::shared_ptr<TProtocol> output) {
     (void)serverContext;
     (void)input;
     (void)output;
@@ -79,19 +80,16 @@
   /**
    * Called when a client is about to call the processor.
    */
-  virtual void processContext(void* serverContext,
-                              boost::shared_ptr<TTransport> transport) {
+  virtual void processContext(void* serverContext, std::shared_ptr<TTransport> transport) {
     (void)serverContext;
     (void)transport;
-}
+  }
 
- protected:
-
+protected:
   /**
    * Prevent direct instantiation.
    */
   TServerEventHandler() {}
-
 };
 
 /**
@@ -99,8 +97,7 @@
  *
  */
 class TServer : public concurrency::Runnable {
- public:
-
+public:
   virtual ~TServer() {}
 
   virtual void serve() = 0;
@@ -108,146 +105,107 @@
   virtual void stop() {}
 
   // Allows running the server as a Runnable thread
-  virtual void run() {
-    serve();
-  }
+  virtual void run() { serve(); }
 
-  boost::shared_ptr<TProcessorFactory> getProcessorFactory() {
-    return processorFactory_;
-  }
+  std::shared_ptr<TProcessorFactory> getProcessorFactory() { return processorFactory_; }
 
-  boost::shared_ptr<TServerTransport> getServerTransport() {
-    return serverTransport_;
-  }
+  std::shared_ptr<TServerTransport> getServerTransport() { return serverTransport_; }
 
-  boost::shared_ptr<TTransportFactory> getInputTransportFactory() {
-    return inputTransportFactory_;
-  }
+  std::shared_ptr<TTransportFactory> getInputTransportFactory() { return inputTransportFactory_; }
 
-  boost::shared_ptr<TTransportFactory> getOutputTransportFactory() {
+  std::shared_ptr<TTransportFactory> getOutputTransportFactory() {
     return outputTransportFactory_;
   }
 
-  boost::shared_ptr<TProtocolFactory> getInputProtocolFactory() {
-    return inputProtocolFactory_;
-  }
+  std::shared_ptr<TProtocolFactory> getInputProtocolFactory() { return inputProtocolFactory_; }
 
-  boost::shared_ptr<TProtocolFactory> getOutputProtocolFactory() {
-    return outputProtocolFactory_;
-  }
+  std::shared_ptr<TProtocolFactory> getOutputProtocolFactory() { return outputProtocolFactory_; }
 
-  boost::shared_ptr<TServerEventHandler> getEventHandler() {
-    return eventHandler_;
-  }
+  std::shared_ptr<TServerEventHandler> getEventHandler() { return eventHandler_; }
 
 protected:
-  template<typename ProcessorFactory>
-  TServer(const boost::shared_ptr<ProcessorFactory>& processorFactory,
-          THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)):
-    processorFactory_(processorFactory) {
-    setInputTransportFactory(boost::shared_ptr<TTransportFactory>(
-          new TTransportFactory()));
-    setOutputTransportFactory(boost::shared_ptr<TTransportFactory>(
-          new TTransportFactory()));
-    setInputProtocolFactory(boost::shared_ptr<TProtocolFactory>(
-          new TBinaryProtocolFactory()));
-    setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory>(
-          new TBinaryProtocolFactory()));
+  TServer(const std::shared_ptr<TProcessorFactory>& processorFactory)
+    : processorFactory_(processorFactory) {
+    setInputTransportFactory(std::shared_ptr<TTransportFactory>(new TTransportFactory()));
+    setOutputTransportFactory(std::shared_ptr<TTransportFactory>(new TTransportFactory()));
+    setInputProtocolFactory(std::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
+    setOutputProtocolFactory(std::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
   }
 
-  template<typename Processor>
-  TServer(const boost::shared_ptr<Processor>& processor,
-          THRIFT_OVERLOAD_IF(Processor, TProcessor)):
-    processorFactory_(new TSingletonProcessorFactory(processor)) {
-    setInputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
-    setOutputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
-    setInputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
-    setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
+  TServer(const std::shared_ptr<TProcessor>& processor)
+    : processorFactory_(new TSingletonProcessorFactory(processor)) {
+    setInputTransportFactory(std::shared_ptr<TTransportFactory>(new TTransportFactory()));
+    setOutputTransportFactory(std::shared_ptr<TTransportFactory>(new TTransportFactory()));
+    setInputProtocolFactory(std::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
+    setOutputProtocolFactory(std::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
   }
 
-  template<typename ProcessorFactory>
-  TServer(const boost::shared_ptr<ProcessorFactory>& processorFactory,
-          const boost::shared_ptr<TServerTransport>& serverTransport,
-          THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)):
-    processorFactory_(processorFactory),
-    serverTransport_(serverTransport) {
-    setInputTransportFactory(boost::shared_ptr<TTransportFactory>(
-          new TTransportFactory()));
-    setOutputTransportFactory(boost::shared_ptr<TTransportFactory>(
-          new TTransportFactory()));
-    setInputProtocolFactory(boost::shared_ptr<TProtocolFactory>(
-          new TBinaryProtocolFactory()));
-    setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory>(
-          new TBinaryProtocolFactory()));
+  TServer(const std::shared_ptr<TProcessorFactory>& processorFactory,
+          const std::shared_ptr<TServerTransport>& serverTransport)
+    : processorFactory_(processorFactory), serverTransport_(serverTransport) {
+    setInputTransportFactory(std::shared_ptr<TTransportFactory>(new TTransportFactory()));
+    setOutputTransportFactory(std::shared_ptr<TTransportFactory>(new TTransportFactory()));
+    setInputProtocolFactory(std::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
+    setOutputProtocolFactory(std::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
   }
 
-  template<typename Processor>
-  TServer(const boost::shared_ptr<Processor>& processor,
-          const boost::shared_ptr<TServerTransport>& serverTransport,
-          THRIFT_OVERLOAD_IF(Processor, TProcessor)):
-    processorFactory_(new TSingletonProcessorFactory(processor)),
-    serverTransport_(serverTransport) {
-    setInputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
-    setOutputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
-    setInputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
-    setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
+  TServer(const std::shared_ptr<TProcessor>& processor,
+          const std::shared_ptr<TServerTransport>& serverTransport)
+    : processorFactory_(new TSingletonProcessorFactory(processor)),
+      serverTransport_(serverTransport) {
+    setInputTransportFactory(std::shared_ptr<TTransportFactory>(new TTransportFactory()));
+    setOutputTransportFactory(std::shared_ptr<TTransportFactory>(new TTransportFactory()));
+    setInputProtocolFactory(std::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
+    setOutputProtocolFactory(std::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
   }
 
-  template<typename ProcessorFactory>
-  TServer(const boost::shared_ptr<ProcessorFactory>& processorFactory,
-          const boost::shared_ptr<TServerTransport>& serverTransport,
-          const boost::shared_ptr<TTransportFactory>& transportFactory,
-          const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-          THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)):
-    processorFactory_(processorFactory),
-    serverTransport_(serverTransport),
-    inputTransportFactory_(transportFactory),
-    outputTransportFactory_(transportFactory),
-    inputProtocolFactory_(protocolFactory),
-    outputProtocolFactory_(protocolFactory) {}
+  TServer(const std::shared_ptr<TProcessorFactory>& processorFactory,
+          const std::shared_ptr<TServerTransport>& serverTransport,
+          const std::shared_ptr<TTransportFactory>& transportFactory,
+          const std::shared_ptr<TProtocolFactory>& protocolFactory)
+    : processorFactory_(processorFactory),
+      serverTransport_(serverTransport),
+      inputTransportFactory_(transportFactory),
+      outputTransportFactory_(transportFactory),
+      inputProtocolFactory_(protocolFactory),
+      outputProtocolFactory_(protocolFactory) {}
 
-  template<typename Processor>
-  TServer(const boost::shared_ptr<Processor>& processor,
-          const boost::shared_ptr<TServerTransport>& serverTransport,
-          const boost::shared_ptr<TTransportFactory>& transportFactory,
-          const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-          THRIFT_OVERLOAD_IF(Processor, TProcessor)):
-    processorFactory_(new TSingletonProcessorFactory(processor)),
-    serverTransport_(serverTransport),
-    inputTransportFactory_(transportFactory),
-    outputTransportFactory_(transportFactory),
-    inputProtocolFactory_(protocolFactory),
-    outputProtocolFactory_(protocolFactory) {}
+  TServer(const std::shared_ptr<TProcessor>& processor,
+          const std::shared_ptr<TServerTransport>& serverTransport,
+          const std::shared_ptr<TTransportFactory>& transportFactory,
+          const std::shared_ptr<TProtocolFactory>& protocolFactory)
+    : processorFactory_(new TSingletonProcessorFactory(processor)),
+      serverTransport_(serverTransport),
+      inputTransportFactory_(transportFactory),
+      outputTransportFactory_(transportFactory),
+      inputProtocolFactory_(protocolFactory),
+      outputProtocolFactory_(protocolFactory) {}
 
-  template<typename ProcessorFactory>
-  TServer(const boost::shared_ptr<ProcessorFactory>& processorFactory,
-          const boost::shared_ptr<TServerTransport>& serverTransport,
-          const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
-          const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
-          const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
-          const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
-          THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)):
-    processorFactory_(processorFactory),
-    serverTransport_(serverTransport),
-    inputTransportFactory_(inputTransportFactory),
-    outputTransportFactory_(outputTransportFactory),
-    inputProtocolFactory_(inputProtocolFactory),
-    outputProtocolFactory_(outputProtocolFactory) {}
+  TServer(const std::shared_ptr<TProcessorFactory>& processorFactory,
+          const std::shared_ptr<TServerTransport>& serverTransport,
+          const std::shared_ptr<TTransportFactory>& inputTransportFactory,
+          const std::shared_ptr<TTransportFactory>& outputTransportFactory,
+          const std::shared_ptr<TProtocolFactory>& inputProtocolFactory,
+          const std::shared_ptr<TProtocolFactory>& outputProtocolFactory)
+    : processorFactory_(processorFactory),
+      serverTransport_(serverTransport),
+      inputTransportFactory_(inputTransportFactory),
+      outputTransportFactory_(outputTransportFactory),
+      inputProtocolFactory_(inputProtocolFactory),
+      outputProtocolFactory_(outputProtocolFactory) {}
 
-  template<typename Processor>
-  TServer(const boost::shared_ptr<Processor>& processor,
-          const boost::shared_ptr<TServerTransport>& serverTransport,
-          const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
-          const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
-          const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
-          const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
-          THRIFT_OVERLOAD_IF(Processor, TProcessor)):
-    processorFactory_(new TSingletonProcessorFactory(processor)),
-    serverTransport_(serverTransport),
-    inputTransportFactory_(inputTransportFactory),
-    outputTransportFactory_(outputTransportFactory),
-    inputProtocolFactory_(inputProtocolFactory),
-    outputProtocolFactory_(outputProtocolFactory) {}
+  TServer(const std::shared_ptr<TProcessor>& processor,
+          const std::shared_ptr<TServerTransport>& serverTransport,
+          const std::shared_ptr<TTransportFactory>& inputTransportFactory,
+          const std::shared_ptr<TTransportFactory>& outputTransportFactory,
+          const std::shared_ptr<TProtocolFactory>& inputProtocolFactory,
+          const std::shared_ptr<TProtocolFactory>& outputProtocolFactory)
+    : processorFactory_(new TSingletonProcessorFactory(processor)),
+      serverTransport_(serverTransport),
+      inputTransportFactory_(inputTransportFactory),
+      outputTransportFactory_(outputTransportFactory),
+      inputProtocolFactory_(inputProtocolFactory),
+      outputProtocolFactory_(outputProtocolFactory) {}
 
   /**
    * Get a TProcessor to handle calls on a particular connection.
@@ -256,10 +214,9 @@
    * call).  This allows the TProcessorFactory to return a different processor
    * for each connection if it desires.
    */
-  boost::shared_ptr<TProcessor> getProcessor(
-      boost::shared_ptr<TProtocol> inputProtocol,
-      boost::shared_ptr<TProtocol> outputProtocol,
-      boost::shared_ptr<TTransport> transport) {
+  std::shared_ptr<TProcessor> getProcessor(std::shared_ptr<TProtocol> inputProtocol,
+                                             std::shared_ptr<TProtocol> outputProtocol,
+                                             std::shared_ptr<TTransport> transport) {
     TConnectionInfo connInfo;
     connInfo.input = inputProtocol;
     connInfo.output = outputProtocol;
@@ -268,38 +225,37 @@
   }
 
   // Class variables
-  boost::shared_ptr<TProcessorFactory> processorFactory_;
-  boost::shared_ptr<TServerTransport> serverTransport_;
+  std::shared_ptr<TProcessorFactory> processorFactory_;
+  std::shared_ptr<TServerTransport> serverTransport_;
 
-  boost::shared_ptr<TTransportFactory> inputTransportFactory_;
-  boost::shared_ptr<TTransportFactory> outputTransportFactory_;
+  std::shared_ptr<TTransportFactory> inputTransportFactory_;
+  std::shared_ptr<TTransportFactory> outputTransportFactory_;
 
-  boost::shared_ptr<TProtocolFactory> inputProtocolFactory_;
-  boost::shared_ptr<TProtocolFactory> outputProtocolFactory_;
+  std::shared_ptr<TProtocolFactory> inputProtocolFactory_;
+  std::shared_ptr<TProtocolFactory> outputProtocolFactory_;
 
-  boost::shared_ptr<TServerEventHandler> eventHandler_;
+  std::shared_ptr<TServerEventHandler> eventHandler_;
 
 public:
-  void setInputTransportFactory(boost::shared_ptr<TTransportFactory> inputTransportFactory) {
+  void setInputTransportFactory(std::shared_ptr<TTransportFactory> inputTransportFactory) {
     inputTransportFactory_ = inputTransportFactory;
   }
 
-  void setOutputTransportFactory(boost::shared_ptr<TTransportFactory> outputTransportFactory) {
+  void setOutputTransportFactory(std::shared_ptr<TTransportFactory> outputTransportFactory) {
     outputTransportFactory_ = outputTransportFactory;
   }
 
-  void setInputProtocolFactory(boost::shared_ptr<TProtocolFactory> inputProtocolFactory) {
+  void setInputProtocolFactory(std::shared_ptr<TProtocolFactory> inputProtocolFactory) {
     inputProtocolFactory_ = inputProtocolFactory;
   }
 
-  void setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory> outputProtocolFactory) {
+  void setOutputProtocolFactory(std::shared_ptr<TProtocolFactory> outputProtocolFactory) {
     outputProtocolFactory_ = outputProtocolFactory;
   }
 
-  void setServerEventHandler(boost::shared_ptr<TServerEventHandler> eventHandler) {
+  void setServerEventHandler(std::shared_ptr<TServerEventHandler> eventHandler) {
     eventHandler_ = eventHandler;
   }
-
 };
 
 /**
@@ -307,9 +263,11 @@
  * for the current process and all of its children.
  * By default, tries to increase it to as much as 2^24.
  */
- int increase_max_fds(int max_fds=(1<<24));
-
-
-}}} // apache::thrift::server
+#ifdef HAVE_SYS_RESOURCE_H
+int increase_max_fds(int max_fds = (1 << 24));
+#endif
+}
+}
+} // apache::thrift::server
 
 #endif // #ifndef _THRIFT_SERVER_TSERVER_H_
diff --git a/lib/cpp/src/thrift/server/TServerFramework.cpp b/lib/cpp/src/thrift/server/TServerFramework.cpp
new file mode 100644
index 0000000..cbeaa24
--- /dev/null
+++ b/lib/cpp/src/thrift/server/TServerFramework.cpp
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <stdexcept>
+#include <stdint.h>
+#include <thrift/server/TServerFramework.h>
+
+namespace apache {
+namespace thrift {
+namespace server {
+
+using apache::thrift::concurrency::Synchronized;
+using apache::thrift::protocol::TProtocol;
+using apache::thrift::protocol::TProtocolFactory;
+using std::bind;
+using std::shared_ptr;
+using apache::thrift::transport::TServerTransport;
+using apache::thrift::transport::TTransport;
+using apache::thrift::transport::TTransportException;
+using apache::thrift::transport::TTransportFactory;
+using std::string;
+
+TServerFramework::TServerFramework(const shared_ptr<TProcessorFactory>& processorFactory,
+                                   const shared_ptr<TServerTransport>& serverTransport,
+                                   const shared_ptr<TTransportFactory>& transportFactory,
+                                   const shared_ptr<TProtocolFactory>& protocolFactory)
+  : TServer(processorFactory, serverTransport, transportFactory, protocolFactory),
+    clients_(0),
+    hwm_(0),
+    limit_(INT64_MAX) {
+}
+
+TServerFramework::TServerFramework(const shared_ptr<TProcessor>& processor,
+                                   const shared_ptr<TServerTransport>& serverTransport,
+                                   const shared_ptr<TTransportFactory>& transportFactory,
+                                   const shared_ptr<TProtocolFactory>& protocolFactory)
+  : TServer(processor, serverTransport, transportFactory, protocolFactory),
+    clients_(0),
+    hwm_(0),
+    limit_(INT64_MAX) {
+}
+
+TServerFramework::TServerFramework(const shared_ptr<TProcessorFactory>& processorFactory,
+                                   const shared_ptr<TServerTransport>& serverTransport,
+                                   const shared_ptr<TTransportFactory>& inputTransportFactory,
+                                   const shared_ptr<TTransportFactory>& outputTransportFactory,
+                                   const shared_ptr<TProtocolFactory>& inputProtocolFactory,
+                                   const shared_ptr<TProtocolFactory>& outputProtocolFactory)
+  : TServer(processorFactory,
+            serverTransport,
+            inputTransportFactory,
+            outputTransportFactory,
+            inputProtocolFactory,
+            outputProtocolFactory),
+    clients_(0),
+    hwm_(0),
+    limit_(INT64_MAX) {
+}
+
+TServerFramework::TServerFramework(const shared_ptr<TProcessor>& processor,
+                                   const shared_ptr<TServerTransport>& serverTransport,
+                                   const shared_ptr<TTransportFactory>& inputTransportFactory,
+                                   const shared_ptr<TTransportFactory>& outputTransportFactory,
+                                   const shared_ptr<TProtocolFactory>& inputProtocolFactory,
+                                   const shared_ptr<TProtocolFactory>& outputProtocolFactory)
+  : TServer(processor,
+            serverTransport,
+            inputTransportFactory,
+            outputTransportFactory,
+            inputProtocolFactory,
+            outputProtocolFactory),
+    clients_(0),
+    hwm_(0),
+    limit_(INT64_MAX) {
+}
+
+TServerFramework::~TServerFramework() {
+}
+
+template <typename T>
+static void releaseOneDescriptor(const string& name, T& pTransport) {
+  if (pTransport) {
+    try {
+      pTransport->close();
+    } catch (const TTransportException& ttx) {
+      string errStr = string("TServerFramework " + name + " close failed: ") + ttx.what();
+      GlobalOutput(errStr.c_str());
+    }
+  }
+}
+
+void TServerFramework::serve() {
+  shared_ptr<TTransport> client;
+  shared_ptr<TTransport> inputTransport;
+  shared_ptr<TTransport> outputTransport;
+  shared_ptr<TProtocol> inputProtocol;
+  shared_ptr<TProtocol> outputProtocol;
+
+  // Start the server listening
+  serverTransport_->listen();
+
+  // Run the preServe event to indicate server is now listening
+  // and that it is safe to connect.
+  if (eventHandler_) {
+    eventHandler_->preServe();
+  }
+
+  // Fetch client from server
+  for (;;) {
+    try {
+      // Dereference any resources from any previous client creation
+      // such that a blocking accept does not hold them indefinitely.
+      outputProtocol.reset();
+      inputProtocol.reset();
+      outputTransport.reset();
+      inputTransport.reset();
+      client.reset();
+
+      // If we have reached the limit on the number of concurrent
+      // clients allowed, wait for one or more clients to drain before
+      // accepting another.
+      {
+        Synchronized sync(mon_);
+        while (clients_ >= limit_) {
+          mon_.wait();
+        }
+      }
+
+      client = serverTransport_->accept();
+
+      inputTransport = inputTransportFactory_->getTransport(client);
+      outputTransport = outputTransportFactory_->getTransport(client);
+      if (!outputProtocolFactory_) {
+        inputProtocol = inputProtocolFactory_->getProtocol(inputTransport, outputTransport);
+        outputProtocol = inputProtocol;
+      } else {
+        inputProtocol = inputProtocolFactory_->getProtocol(inputTransport);
+        outputProtocol = outputProtocolFactory_->getProtocol(outputTransport);
+      }
+
+      newlyConnectedClient(shared_ptr<TConnectedClient>(
+          new TConnectedClient(getProcessor(inputProtocol, outputProtocol, client),
+                               inputProtocol,
+                               outputProtocol,
+                               eventHandler_,
+                               client),
+          bind(&TServerFramework::disposeConnectedClient, this, std::placeholders::_1)));
+
+    } catch (TTransportException& ttx) {
+      releaseOneDescriptor("inputTransport", inputTransport);
+      releaseOneDescriptor("outputTransport", outputTransport);
+      releaseOneDescriptor("client", client);
+      if (ttx.getType() == TTransportException::TIMED_OUT) {
+        // Accept timeout - continue processing.
+        continue;
+      } else if (ttx.getType() == TTransportException::END_OF_FILE
+                 || ttx.getType() == TTransportException::INTERRUPTED) {
+        // Server was interrupted.  This only happens when stopping.
+        break;
+      } else {
+        // All other transport exceptions are logged.
+        // State of connection is unknown.  Done.
+        string errStr = string("TServerTransport died: ") + ttx.what();
+        GlobalOutput(errStr.c_str());
+        break;
+      }
+    }
+  }
+
+  releaseOneDescriptor("serverTransport", serverTransport_);
+}
+
+int64_t TServerFramework::getConcurrentClientLimit() const {
+  Synchronized sync(mon_);
+  return limit_;
+}
+
+int64_t TServerFramework::getConcurrentClientCount() const {
+  Synchronized sync(mon_);
+  return clients_;
+}
+
+int64_t TServerFramework::getConcurrentClientCountHWM() const {
+  Synchronized sync(mon_);
+  return hwm_;
+}
+
+void TServerFramework::setConcurrentClientLimit(int64_t newLimit) {
+  if (newLimit < 1) {
+    throw std::invalid_argument("newLimit must be greater than zero");
+  }
+  Synchronized sync(mon_);
+  limit_ = newLimit;
+  if (limit_ - clients_ > 0) {
+    mon_.notify();
+  }
+}
+
+void TServerFramework::stop() {
+  // Order is important because serve() releases serverTransport_ when it is
+  // interrupted, which closes the socket that interruptChildren uses.
+  serverTransport_->interruptChildren();
+  serverTransport_->interrupt();
+}
+
+void TServerFramework::newlyConnectedClient(const shared_ptr<TConnectedClient>& pClient) {
+  {
+    Synchronized sync(mon_);
+    ++clients_;
+    hwm_ = (std::max)(hwm_, clients_);
+  }
+
+  onClientConnected(pClient);
+}
+
+void TServerFramework::disposeConnectedClient(TConnectedClient* pClient) {
+  onClientDisconnected(pClient);
+  delete pClient;
+
+  Synchronized sync(mon_);
+  if (limit_ - --clients_ > 0) {
+    mon_.notify();
+  }
+}
+
+}
+}
+} // apache::thrift::server
diff --git a/lib/cpp/src/thrift/server/TServerFramework.h b/lib/cpp/src/thrift/server/TServerFramework.h
new file mode 100644
index 0000000..eaacce5
--- /dev/null
+++ b/lib/cpp/src/thrift/server/TServerFramework.h
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_SERVER_TSERVERFRAMEWORK_H_
+#define _THRIFT_SERVER_TSERVERFRAMEWORK_H_ 1
+
+#include <memory>
+#include <stdint.h>
+#include <thrift/TProcessor.h>
+#include <thrift/concurrency/Monitor.h>
+#include <thrift/server/TConnectedClient.h>
+#include <thrift/server/TServer.h>
+#include <thrift/transport/TServerTransport.h>
+#include <thrift/transport/TTransport.h>
+
+namespace apache {
+namespace thrift {
+namespace server {
+
+/**
+ * TServerFramework provides a single consolidated processing loop for
+ * servers.  By having a single processing loop, behavior between servers
+ * is more predictable and maintenance cost is lowered.  Implementations
+ * of TServerFramework must provide a method to deal with a client that
+ * connects and one that disconnects.
+ *
+ * While this functionality could be rolled directly into TServer, and
+ * probably should be, it would break the TServer interface contract so
+ * to maintain backwards compatibility for third party servers, no TServers
+ * were harmed in the making of this class.
+ */
+class TServerFramework : public TServer {
+public:
+  TServerFramework(
+      const std::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory);
+
+  TServerFramework(
+      const std::shared_ptr<apache::thrift::TProcessor>& processor,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory);
+
+  TServerFramework(
+      const std::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory);
+
+  TServerFramework(
+      const std::shared_ptr<apache::thrift::TProcessor>& processor,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory);
+
+  virtual ~TServerFramework();
+
+  /**
+   * Accept clients from the TServerTransport and add them for processing.
+   * Call stop() on another thread to interrupt processing
+   * and return control to the caller.
+   * Post-conditions (return guarantees):
+   *   The serverTransport will be closed.
+   */
+  virtual void serve();
+
+  /**
+   * Interrupt serve() so that it meets post-conditions and returns.
+   */
+  virtual void stop();
+
+  /**
+   * Get the concurrent client limit.
+   * \returns the concurrent client limit
+   */
+  virtual int64_t getConcurrentClientLimit() const;
+
+  /**
+   * Get the number of currently connected clients.
+   * \returns the number of currently connected clients
+   */
+  virtual int64_t getConcurrentClientCount() const;
+
+  /**
+   * Get the highest number of concurrent clients.
+   * \returns the highest number of concurrent clients
+   */
+  virtual int64_t getConcurrentClientCountHWM() const;
+
+  /**
+   * Set the concurrent client limit.  This can be changed while
+   * the server is serving however it will not necessarily be
+   * enforced until the next client is accepted and added.  If the
+   * limit is lowered below the number of connected clients, no
+   * action is taken to disconnect the clients.
+   * The default value used if this is not called is INT64_MAX.
+   * \param[in]  newLimit  the new limit of concurrent clients
+   * \throws std::invalid_argument if newLimit is less than 1
+   */
+  virtual void setConcurrentClientLimit(int64_t newLimit);
+
+protected:
+  /**
+   * A client has connected.  The implementation is responsible for managing the
+   * lifetime of the client object.  This is called during the serve() thread,
+   * therefore a failure to return quickly will result in new client connection
+   * delays.
+   *
+   * \param[in]  pClient  the newly connected client
+   */
+  virtual void onClientConnected(const std::shared_ptr<TConnectedClient>& pClient) = 0;
+
+  /**
+   * A client has disconnected.
+   * When called:
+   *   The server no longer tracks the client.
+   *   The client TTransport has already been closed.
+   *   The implementation must not delete the pointer.
+   *
+   * \param[in]  pClient  the disconnected client
+   */
+  virtual void onClientDisconnected(TConnectedClient* pClient) = 0;
+
+private:
+  /**
+   * Common handling for new connected clients.  Implements concurrent
+   * client rate limiting after onClientConnected returns by blocking the
+   * serve() thread if the limit has been reached.
+   */
+  void newlyConnectedClient(const std::shared_ptr<TConnectedClient>& pClient);
+
+  /**
+   * Smart pointer client deletion.
+   * Calls onClientDisconnected and then deletes pClient.
+   */
+  void disposeConnectedClient(TConnectedClient* pClient);
+
+  /**
+   * Monitor for limiting the number of concurrent clients.
+   */
+  apache::thrift::concurrency::Monitor mon_;
+
+  /**
+   * The number of concurrent clients.
+   */
+  int64_t clients_;
+
+  /**
+   * The high water mark of concurrent clients.
+   */
+  int64_t hwm_;
+
+  /**
+   * The limit on the number of concurrent clients.
+   */
+  int64_t limit_;
+};
+}
+}
+} // apache::thrift::server
+
+#endif // #ifndef _THRIFT_SERVER_TSERVERFRAMEWORK_H_
diff --git a/lib/cpp/src/thrift/server/TSimpleServer.cpp b/lib/cpp/src/thrift/server/TSimpleServer.cpp
index 5fc4c97..716234d 100644
--- a/lib/cpp/src/thrift/server/TSimpleServer.cpp
+++ b/lib/cpp/src/thrift/server/TSimpleServer.cpp
@@ -18,136 +18,90 @@
  */
 
 #include <thrift/server/TSimpleServer.h>
-#include <thrift/transport/TTransportException.h>
-#include <string>
-#include <iostream>
 
-namespace apache { namespace thrift { namespace server {
+namespace apache {
+namespace thrift {
+namespace server {
 
-using namespace std;
-using namespace apache::thrift;
-using namespace apache::thrift::protocol;
-using namespace apache::thrift::transport;
-using boost::shared_ptr;
+using apache::thrift::protocol::TProtocol;
+using apache::thrift::protocol::TProtocolFactory;
+using apache::thrift::transport::TServerTransport;
+using apache::thrift::transport::TTransport;
+using apache::thrift::transport::TTransportException;
+using apache::thrift::transport::TTransportFactory;
+using std::shared_ptr;
+using std::string;
 
-/**
- * A simple single-threaded application server. Perfect for unit tests!
- *
- */
-void TSimpleServer::serve() {
-
-  shared_ptr<TTransport> client;
-  shared_ptr<TTransport> inputTransport;
-  shared_ptr<TTransport> outputTransport;
-  shared_ptr<TProtocol> inputProtocol;
-  shared_ptr<TProtocol> outputProtocol;
-
-  // Start the server listening
-  serverTransport_->listen();
-
-  // Run the preServe event
-  if (eventHandler_) {
-    eventHandler_->preServe();
-  }
-
-  // Fetch client from server
-  while (!stop_) {
-    try {
-      client = serverTransport_->accept();
-      inputTransport = inputTransportFactory_->getTransport(client);
-      outputTransport = outputTransportFactory_->getTransport(client);
-      inputProtocol = inputProtocolFactory_->getProtocol(inputTransport);
-      outputProtocol = outputProtocolFactory_->getProtocol(outputTransport);
-    } catch (TTransportException& ttx) {
-      if (inputTransport) { inputTransport->close(); }
-      if (outputTransport) { outputTransport->close(); }
-      if (client) { client->close(); }
-      if (!stop_ || ttx.getType() != TTransportException::INTERRUPTED) {
-          string errStr = string("TServerTransport died on accept: ") + ttx.what();
-          GlobalOutput(errStr.c_str());
-      }
-      continue;
-    } catch (TException& tx) {
-      if (inputTransport) { inputTransport->close(); }
-      if (outputTransport) { outputTransport->close(); }
-      if (client) { client->close(); }
-      string errStr = string("Some kind of accept exception: ") + tx.what();
-      GlobalOutput(errStr.c_str());
-      continue;
-    } catch (string s) {
-      if (inputTransport) { inputTransport->close(); }
-      if (outputTransport) { outputTransport->close(); }
-      if (client) { client->close(); }
-      string errStr = string("Some kind of accept exception: ") + s;
-      GlobalOutput(errStr.c_str());
-      break;
-    }
-
-    // Get the processor
-    shared_ptr<TProcessor> processor = getProcessor(inputProtocol,
-                                                    outputProtocol, client);
-
-    void* connectionContext = NULL;
-    if (eventHandler_) {
-      connectionContext = eventHandler_->createContext(inputProtocol, outputProtocol);
-    }
-    try {
-      for (;;) {
-        if (eventHandler_) {
-          eventHandler_->processContext(connectionContext, client);
-        }
-        if (!processor->process(inputProtocol, outputProtocol,
-                                connectionContext) ||
-          // Peek ahead, is the remote side closed?
-            !inputProtocol->getTransport()->peek()) {
-          break;
-        }
-      }
-    } catch (const TTransportException& ttx) {
-      string errStr = string("TSimpleServer client died: ") + ttx.what();
-      GlobalOutput(errStr.c_str());
-    } catch (const std::exception& x) {
-      GlobalOutput.printf("TSimpleServer exception: %s: %s",
-                          typeid(x).name(), x.what());
-    } catch (...) {
-      GlobalOutput("TSimpleServer uncaught exception.");
-    }
-    if (eventHandler_) {
-      eventHandler_->deleteContext(connectionContext, inputProtocol, outputProtocol);
-    }
-
-    try {
-      inputTransport->close();
-    } catch (const TTransportException& ttx) {
-      string errStr = string("TSimpleServer input close failed: ")
-        + ttx.what();
-      GlobalOutput(errStr.c_str());
-    }
-    try {
-      outputTransport->close();
-    } catch (const TTransportException& ttx) {
-      string errStr = string("TSimpleServer output close failed: ")
-        + ttx.what();
-      GlobalOutput(errStr.c_str());
-    }
-    try {
-      client->close();
-    } catch (const TTransportException& ttx) {
-      string errStr = string("TSimpleServer client close failed: ")
-        + ttx.what();
-      GlobalOutput(errStr.c_str());
-    }
-  }
-
-  if (stop_) {
-    try {
-      serverTransport_->close();
-    } catch (TTransportException &ttx) {
-      string errStr = string("TServerTransport failed on close: ") + ttx.what();
-      GlobalOutput(errStr.c_str());
-    }
-    stop_ = false;
-  }
+TSimpleServer::TSimpleServer(const shared_ptr<TProcessorFactory>& processorFactory,
+                             const shared_ptr<TServerTransport>& serverTransport,
+                             const shared_ptr<TTransportFactory>& transportFactory,
+                             const shared_ptr<TProtocolFactory>& protocolFactory)
+  : TServerFramework(processorFactory, serverTransport, transportFactory, protocolFactory) {
+  TServerFramework::setConcurrentClientLimit(1);
 }
 
-}}} // apache::thrift::server
+TSimpleServer::TSimpleServer(const shared_ptr<TProcessor>& processor,
+                             const shared_ptr<TServerTransport>& serverTransport,
+                             const shared_ptr<TTransportFactory>& transportFactory,
+                             const shared_ptr<TProtocolFactory>& protocolFactory)
+  : TServerFramework(processor, serverTransport, transportFactory, protocolFactory) {
+  TServerFramework::setConcurrentClientLimit(1);
+}
+
+TSimpleServer::TSimpleServer(const shared_ptr<TProcessorFactory>& processorFactory,
+                             const shared_ptr<TServerTransport>& serverTransport,
+                             const shared_ptr<TTransportFactory>& inputTransportFactory,
+                             const shared_ptr<TTransportFactory>& outputTransportFactory,
+                             const shared_ptr<TProtocolFactory>& inputProtocolFactory,
+                             const shared_ptr<TProtocolFactory>& outputProtocolFactory)
+  : TServerFramework(processorFactory,
+                     serverTransport,
+                     inputTransportFactory,
+                     outputTransportFactory,
+                     inputProtocolFactory,
+                     outputProtocolFactory) {
+  TServerFramework::setConcurrentClientLimit(1);
+}
+
+TSimpleServer::TSimpleServer(const shared_ptr<TProcessor>& processor,
+                             const shared_ptr<TServerTransport>& serverTransport,
+                             const shared_ptr<TTransportFactory>& inputTransportFactory,
+                             const shared_ptr<TTransportFactory>& outputTransportFactory,
+                             const shared_ptr<TProtocolFactory>& inputProtocolFactory,
+                             const shared_ptr<TProtocolFactory>& outputProtocolFactory)
+  : TServerFramework(processor,
+                     serverTransport,
+                     inputTransportFactory,
+                     outputTransportFactory,
+                     inputProtocolFactory,
+                     outputProtocolFactory) {
+  TServerFramework::setConcurrentClientLimit(1);
+}
+
+TSimpleServer::~TSimpleServer() {
+}
+
+/**
+ * The main body of customized implementation for TSimpleServer is quite simple:
+ * When a client connects, use the serve() thread to drive it to completion thus
+ * blocking new connections.
+ */
+void TSimpleServer::onClientConnected(const shared_ptr<TConnectedClient>& pClient) {
+  pClient->run();
+}
+
+/**
+ * TSimpleServer does not track clients so there is nothing to do here.
+ */
+void TSimpleServer::onClientDisconnected(TConnectedClient*) {
+}
+
+/**
+ * This makes little sense to the simple server because it is not capable
+ * of having more than one client at a time, so we hide it.
+ */
+void TSimpleServer::setConcurrentClientLimit(int64_t) {
+}
+}
+}
+} // apache::thrift::server
diff --git a/lib/cpp/src/thrift/server/TSimpleServer.h b/lib/cpp/src/thrift/server/TSimpleServer.h
index f9e0e2b..4549225 100644
--- a/lib/cpp/src/thrift/server/TSimpleServer.h
+++ b/lib/cpp/src/thrift/server/TSimpleServer.h
@@ -20,83 +20,58 @@
 #ifndef _THRIFT_SERVER_TSIMPLESERVER_H_
 #define _THRIFT_SERVER_TSIMPLESERVER_H_ 1
 
-#include <thrift/server/TServer.h>
-#include <thrift/transport/TServerTransport.h>
+#include <thrift/server/TServerFramework.h>
 
-namespace apache { namespace thrift { namespace server {
+namespace apache {
+namespace thrift {
+namespace server {
 
 /**
  * This is the most basic simple server. It is single-threaded and runs a
  * continuous loop of accepting a single connection, processing requests on
- * that connection until it closes, and then repeating. It is a good example
- * of how to extend the TServer interface.
- *
+ * that connection until it closes, and then repeating.
  */
-class TSimpleServer : public TServer {
- public:
-  template<typename ProcessorFactory>
+class TSimpleServer : public TServerFramework {
+public:
   TSimpleServer(
-      const boost::shared_ptr<ProcessorFactory>& processorFactory,
-      const boost::shared_ptr<TServerTransport>& serverTransport,
-      const boost::shared_ptr<TTransportFactory>& transportFactory,
-      const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-      THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)) :
-    TServer(processorFactory, serverTransport, transportFactory,
-            protocolFactory),
-    stop_(false) {}
+      const std::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory);
 
-  template<typename Processor>
   TSimpleServer(
-      const boost::shared_ptr<Processor>& processor,
-      const boost::shared_ptr<TServerTransport>& serverTransport,
-      const boost::shared_ptr<TTransportFactory>& transportFactory,
-      const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-      THRIFT_OVERLOAD_IF(Processor, TProcessor)) :
-    TServer(processor, serverTransport, transportFactory, protocolFactory),
-    stop_(false) {}
+      const std::shared_ptr<apache::thrift::TProcessor>& processor,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory);
 
-  template<typename ProcessorFactory>
   TSimpleServer(
-      const boost::shared_ptr<ProcessorFactory>& processorFactory,
-      const boost::shared_ptr<TServerTransport>& serverTransport,
-      const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
-      const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
-      const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
-      const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
-      THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)) :
-    TServer(processorFactory, serverTransport,
-            inputTransportFactory, outputTransportFactory,
-            inputProtocolFactory, outputProtocolFactory),
-    stop_(false) {}
+      const std::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory);
 
-  template<typename Processor>
   TSimpleServer(
-      const boost::shared_ptr<Processor>& processor,
-      const boost::shared_ptr<TServerTransport>& serverTransport,
-      const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
-      const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
-      const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
-      const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
-      THRIFT_OVERLOAD_IF(Processor, TProcessor)) :
-    TServer(processor, serverTransport,
-            inputTransportFactory, outputTransportFactory,
-            inputProtocolFactory, outputProtocolFactory),
-    stop_(false) {}
+      const std::shared_ptr<apache::thrift::TProcessor>& processor,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory);
 
-  ~TSimpleServer() {}
+  virtual ~TSimpleServer();
 
-  void serve();
+protected:
+  virtual void onClientConnected(const std::shared_ptr<TConnectedClient>& pClient) /* override */;
+  virtual void onClientDisconnected(TConnectedClient* pClient) /* override */;
 
-  void stop() {
-    stop_ = true;
-    serverTransport_->interrupt();
-  }
-
- protected:
-  bool stop_;
-
+private:
+  void setConcurrentClientLimit(int64_t newLimit); // hide
 };
-
-}}} // apache::thrift::server
+}
+}
+} // apache::thrift::server
 
 #endif // #ifndef _THRIFT_SERVER_TSIMPLESERVER_H_
diff --git a/lib/cpp/src/thrift/server/TThreadPoolServer.cpp b/lib/cpp/src/thrift/server/TThreadPoolServer.cpp
index da33ec2..ee345a9 100644
--- a/lib/cpp/src/thrift/server/TThreadPoolServer.cpp
+++ b/lib/cpp/src/thrift/server/TThreadPoolServer.cpp
@@ -17,179 +17,86 @@
  * under the License.
  */
 
-#include <thrift/thrift-config.h>
-
 #include <thrift/server/TThreadPoolServer.h>
-#include <thrift/transport/TTransportException.h>
-#include <thrift/concurrency/Thread.h>
-#include <thrift/concurrency/ThreadManager.h>
-#include <string>
-#include <iostream>
 
-namespace apache { namespace thrift { namespace server {
+namespace apache {
+namespace thrift {
+namespace server {
 
-using boost::shared_ptr;
-using namespace std;
-using namespace apache::thrift;
-using namespace apache::thrift::concurrency;
-using namespace apache::thrift::protocol;
-using namespace apache::thrift::transport;
+using apache::thrift::concurrency::ThreadManager;
+using apache::thrift::protocol::TProtocol;
+using apache::thrift::protocol::TProtocolFactory;
+using apache::thrift::transport::TServerTransport;
+using apache::thrift::transport::TTransport;
+using apache::thrift::transport::TTransportException;
+using apache::thrift::transport::TTransportFactory;
+using std::shared_ptr;
+using std::string;
 
-class TThreadPoolServer::Task : public Runnable {
+TThreadPoolServer::TThreadPoolServer(const shared_ptr<TProcessorFactory>& processorFactory,
+                                     const shared_ptr<TServerTransport>& serverTransport,
+                                     const shared_ptr<TTransportFactory>& transportFactory,
+                                     const shared_ptr<TProtocolFactory>& protocolFactory,
+                                     const shared_ptr<ThreadManager>& threadManager)
+  : TServerFramework(processorFactory, serverTransport, transportFactory, protocolFactory),
+    threadManager_(threadManager),
+    timeout_(0),
+    taskExpiration_(0) {
+}
 
-public:
+TThreadPoolServer::TThreadPoolServer(const shared_ptr<TProcessor>& processor,
+                                     const shared_ptr<TServerTransport>& serverTransport,
+                                     const shared_ptr<TTransportFactory>& transportFactory,
+                                     const shared_ptr<TProtocolFactory>& protocolFactory,
+                                     const shared_ptr<ThreadManager>& threadManager)
+  : TServerFramework(processor, serverTransport, transportFactory, protocolFactory),
+    threadManager_(threadManager),
+    timeout_(0),
+    taskExpiration_(0) {
+}
 
-  Task(TThreadPoolServer &server,
-       shared_ptr<TProcessor> processor,
-       shared_ptr<TProtocol> input,
-       shared_ptr<TProtocol> output,
-       shared_ptr<TTransport> transport) :
-    server_(server),
-    processor_(processor),
-    input_(input),
-    output_(output),
-    transport_(transport) {
-  }
+TThreadPoolServer::TThreadPoolServer(const shared_ptr<TProcessorFactory>& processorFactory,
+                                     const shared_ptr<TServerTransport>& serverTransport,
+                                     const shared_ptr<TTransportFactory>& inputTransportFactory,
+                                     const shared_ptr<TTransportFactory>& outputTransportFactory,
+                                     const shared_ptr<TProtocolFactory>& inputProtocolFactory,
+                                     const shared_ptr<TProtocolFactory>& outputProtocolFactory,
+                                     const shared_ptr<ThreadManager>& threadManager)
+  : TServerFramework(processorFactory,
+                     serverTransport,
+                     inputTransportFactory,
+                     outputTransportFactory,
+                     inputProtocolFactory,
+                     outputProtocolFactory),
+    threadManager_(threadManager),
+    timeout_(0),
+    taskExpiration_(0) {
+}
 
-  ~Task() {}
+TThreadPoolServer::TThreadPoolServer(const shared_ptr<TProcessor>& processor,
+                                     const shared_ptr<TServerTransport>& serverTransport,
+                                     const shared_ptr<TTransportFactory>& inputTransportFactory,
+                                     const shared_ptr<TTransportFactory>& outputTransportFactory,
+                                     const shared_ptr<TProtocolFactory>& inputProtocolFactory,
+                                     const shared_ptr<TProtocolFactory>& outputProtocolFactory,
+                                     const shared_ptr<ThreadManager>& threadManager)
+  : TServerFramework(processor,
+                     serverTransport,
+                     inputTransportFactory,
+                     outputTransportFactory,
+                     inputProtocolFactory,
+                     outputProtocolFactory),
+    threadManager_(threadManager),
+    timeout_(0),
+    taskExpiration_(0) {
+}
 
-  void run() {
-    boost::shared_ptr<TServerEventHandler> eventHandler =
-      server_.getEventHandler();
-    void* connectionContext = NULL;
-    if (eventHandler) {
-      connectionContext = eventHandler->createContext(input_, output_);
-    }
-    try {
-      for (;;) {
-        if (eventHandler) {
-          eventHandler->processContext(connectionContext, transport_);
-        }
-        if (!processor_->process(input_, output_, connectionContext) ||
-            !input_->getTransport()->peek()) {
-          break;
-        }
-      }
-    } catch (const TTransportException&) {
-      // This is reasonably expected, client didn't send a full request so just
-      // ignore him
-      // string errStr = string("TThreadPoolServer client died: ") + ttx.what();
-      // GlobalOutput(errStr.c_str());
-    } catch (const std::exception& x) {
-      GlobalOutput.printf("TThreadPoolServer exception %s: %s",
-                          typeid(x).name(), x.what());
-    } catch (...) {
-      GlobalOutput("TThreadPoolServer, unexpected exception in "
-                   "TThreadPoolServer::Task::run()");
-    }
-
-    if (eventHandler) {
-      eventHandler->deleteContext(connectionContext, input_, output_);
-    }
-
-    try {
-      input_->getTransport()->close();
-    } catch (TTransportException& ttx) {
-      string errStr = string("TThreadPoolServer input close failed: ") + ttx.what();
-      GlobalOutput(errStr.c_str());
-    }
-    try {
-      output_->getTransport()->close();
-    } catch (TTransportException& ttx) {
-      string errStr = string("TThreadPoolServer output close failed: ") + ttx.what();
-      GlobalOutput(errStr.c_str());
-    }
-
-  }
-
- private:
-  TServer& server_;
-  shared_ptr<TProcessor> processor_;
-  shared_ptr<TProtocol> input_;
-  shared_ptr<TProtocol> output_;
-  shared_ptr<TTransport> transport_;
-};
-
-TThreadPoolServer::~TThreadPoolServer() {}
+TThreadPoolServer::~TThreadPoolServer() {
+}
 
 void TThreadPoolServer::serve() {
-  shared_ptr<TTransport> client;
-  shared_ptr<TTransport> inputTransport;
-  shared_ptr<TTransport> outputTransport;
-  shared_ptr<TProtocol> inputProtocol;
-  shared_ptr<TProtocol> outputProtocol;
-
-  // Start the server listening
-  serverTransport_->listen();
-
-  // Run the preServe event
-  if (eventHandler_) {
-    eventHandler_->preServe();
-  }
-
-  while (!stop_) {
-    try {
-      client.reset();
-      inputTransport.reset();
-      outputTransport.reset();
-      inputProtocol.reset();
-      outputProtocol.reset();
-
-      // Fetch client from server
-      client = serverTransport_->accept();
-
-      // Make IO transports
-      inputTransport = inputTransportFactory_->getTransport(client);
-      outputTransport = outputTransportFactory_->getTransport(client);
-      inputProtocol = inputProtocolFactory_->getProtocol(inputTransport);
-      outputProtocol = outputProtocolFactory_->getProtocol(outputTransport);
-
-      shared_ptr<TProcessor> processor = getProcessor(inputProtocol,
-                                                      outputProtocol, client);
-
-      // Add to threadmanager pool
-      shared_ptr<TThreadPoolServer::Task> task(new TThreadPoolServer::Task(
-            *this, processor, inputProtocol, outputProtocol, client));
-      threadManager_->add(task, timeout_, taskExpiration_);
-
-    } catch (TTransportException& ttx) {
-      if (inputTransport) { inputTransport->close(); }
-      if (outputTransport) { outputTransport->close(); }
-      if (client) { client->close(); }
-      if (!stop_ || ttx.getType() != TTransportException::INTERRUPTED) {
-        string errStr = string("TThreadPoolServer: TServerTransport died on accept: ") + ttx.what();
-        GlobalOutput(errStr.c_str());
-      }
-      continue;
-    } catch (TException& tx) {
-      if (inputTransport) { inputTransport->close(); }
-      if (outputTransport) { outputTransport->close(); }
-      if (client) { client->close(); }
-      string errStr = string("TThreadPoolServer: Caught TException: ") + tx.what();
-      GlobalOutput(errStr.c_str());
-      continue;
-    } catch (string s) {
-      if (inputTransport) { inputTransport->close(); }
-      if (outputTransport) { outputTransport->close(); }
-      if (client) { client->close(); }
-      string errStr = "TThreadPoolServer: Unknown exception: " + s;
-      GlobalOutput(errStr.c_str());
-      break;
-    }
-  }
-
-  // If stopped manually, join the existing threads
-  if (stop_) {
-    try {
-      serverTransport_->close();
-      threadManager_->join();
-    } catch (TException &tx) {
-      string errStr = string("TThreadPoolServer: Exception shutting down: ") + tx.what();
-      GlobalOutput(errStr.c_str());
-    }
-    stop_ = false;
-  }
-
+  TServerFramework::serve();
+  threadManager_->stop();
 }
 
 int64_t TThreadPoolServer::getTimeout() const {
@@ -208,4 +115,18 @@
   taskExpiration_ = value;
 }
 
-}}} // apache::thrift::server
+std::shared_ptr<apache::thrift::concurrency::ThreadManager>
+TThreadPoolServer::getThreadManager() const {
+  return threadManager_;
+}
+
+void TThreadPoolServer::onClientConnected(const shared_ptr<TConnectedClient>& pClient) {
+  threadManager_->add(pClient, getTimeout(), getTaskExpiration());
+}
+
+void TThreadPoolServer::onClientDisconnected(TConnectedClient*) {
+}
+
+}
+}
+} // apache::thrift::server
diff --git a/lib/cpp/src/thrift/server/TThreadPoolServer.h b/lib/cpp/src/thrift/server/TThreadPoolServer.h
index 8a1fc16..121998c 100644
--- a/lib/cpp/src/thrift/server/TThreadPoolServer.h
+++ b/lib/cpp/src/thrift/server/TThreadPoolServer.h
@@ -20,117 +20,82 @@
 #ifndef _THRIFT_SERVER_TTHREADPOOLSERVER_H_
 #define _THRIFT_SERVER_TTHREADPOOLSERVER_H_ 1
 
+#include <atomic>
 #include <thrift/concurrency/ThreadManager.h>
-#include <thrift/server/TServer.h>
-#include <thrift/transport/TServerTransport.h>
+#include <thrift/server/TServerFramework.h>
 
-#include <boost/shared_ptr.hpp>
+namespace apache {
+namespace thrift {
+namespace server {
 
-namespace apache { namespace thrift { namespace server {
-
-using apache::thrift::concurrency::ThreadManager;
-using apache::thrift::protocol::TProtocolFactory;
-using apache::thrift::transport::TServerTransport;
-using apache::thrift::transport::TTransportFactory;
-
-class TThreadPoolServer : public TServer {
- public:
-  class Task;
-
-  template<typename ProcessorFactory>
+/**
+ * Manage clients using a thread pool.
+ */
+class TThreadPoolServer : public TServerFramework {
+public:
   TThreadPoolServer(
-      const boost::shared_ptr<ProcessorFactory>& processorFactory,
-      const boost::shared_ptr<TServerTransport>& serverTransport,
-      const boost::shared_ptr<TTransportFactory>& transportFactory,
-      const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-      const boost::shared_ptr<ThreadManager>& threadManager,
-      THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)) :
-    TServer(processorFactory, serverTransport, transportFactory,
-            protocolFactory),
-    threadManager_(threadManager),
-    stop_(false),
-    timeout_(0),
-    taskExpiration_(0) {}
+      const std::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory,
+      const std::shared_ptr<apache::thrift::concurrency::ThreadManager>& threadManager
+      = apache::thrift::concurrency::ThreadManager::newSimpleThreadManager());
 
-  template<typename Processor>
   TThreadPoolServer(
-      const boost::shared_ptr<Processor>& processor,
-      const boost::shared_ptr<TServerTransport>& serverTransport,
-      const boost::shared_ptr<TTransportFactory>& transportFactory,
-      const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-      const boost::shared_ptr<ThreadManager>& threadManager,
-      THRIFT_OVERLOAD_IF(Processor, TProcessor)) :
-    TServer(processor, serverTransport, transportFactory, protocolFactory),
-    threadManager_(threadManager),
-    stop_(false),
-    timeout_(0),
-    taskExpiration_(0) {}
+      const std::shared_ptr<apache::thrift::TProcessor>& processor,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory,
+      const std::shared_ptr<apache::thrift::concurrency::ThreadManager>& threadManager
+      = apache::thrift::concurrency::ThreadManager::newSimpleThreadManager());
 
-  template<typename ProcessorFactory>
   TThreadPoolServer(
-      const boost::shared_ptr<ProcessorFactory>& processorFactory,
-      const boost::shared_ptr<TServerTransport>& serverTransport,
-      const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
-      const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
-      const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
-      const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
-      const boost::shared_ptr<ThreadManager>& threadManager,
-      THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory)) :
-    TServer(processorFactory, serverTransport,
-            inputTransportFactory, outputTransportFactory,
-            inputProtocolFactory, outputProtocolFactory),
-    threadManager_(threadManager),
-    stop_(false),
-    timeout_(0),
-    taskExpiration_(0) {}
+      const std::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory,
+      const std::shared_ptr<apache::thrift::concurrency::ThreadManager>& threadManager
+      = apache::thrift::concurrency::ThreadManager::newSimpleThreadManager());
 
-  template<typename Processor>
   TThreadPoolServer(
-      const boost::shared_ptr<Processor>& processor,
-      const boost::shared_ptr<TServerTransport>& serverTransport,
-      const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
-      const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
-      const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
-      const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
-      const boost::shared_ptr<ThreadManager>& threadManager,
-      THRIFT_OVERLOAD_IF(Processor, TProcessor)) :
-    TServer(processor, serverTransport,
-            inputTransportFactory, outputTransportFactory,
-            inputProtocolFactory, outputProtocolFactory),
-    threadManager_(threadManager),
-    stop_(false),
-    timeout_(0),
-    taskExpiration_(0) {}
+      const std::shared_ptr<apache::thrift::TProcessor>& processor,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory,
+      const std::shared_ptr<apache::thrift::concurrency::ThreadManager>& threadManager
+      = apache::thrift::concurrency::ThreadManager::newSimpleThreadManager());
 
   virtual ~TThreadPoolServer();
 
+  /**
+   * Post-conditions (return guarantees):
+   *   There will be no clients connected.
+   */
   virtual void serve();
 
   virtual int64_t getTimeout() const;
-
   virtual void setTimeout(int64_t value);
 
-  virtual void stop() {
-    stop_ = true;
-    serverTransport_->interrupt();
-  }
-
   virtual int64_t getTaskExpiration() const;
-
   virtual void setTaskExpiration(int64_t value);
 
- protected:
+  virtual std::shared_ptr<apache::thrift::concurrency::ThreadManager> getThreadManager() const;
 
-  boost::shared_ptr<ThreadManager> threadManager_;
+protected:
+  virtual void onClientConnected(const std::shared_ptr<TConnectedClient>& pClient) /* override */;
+  virtual void onClientDisconnected(TConnectedClient* pClient) /* override */;
 
-  volatile bool stop_;
-
-  volatile int64_t timeout_;
-
-  volatile int64_t taskExpiration_;
-
+  std::shared_ptr<apache::thrift::concurrency::ThreadManager> threadManager_;
+  std::atomic<int64_t> timeout_;
+  std::atomic<int64_t> taskExpiration_;
 };
 
-}}} // apache::thrift::server
+}
+}
+} // apache::thrift::server
 
 #endif // #ifndef _THRIFT_SERVER_TTHREADPOOLSERVER_H_
diff --git a/lib/cpp/src/thrift/server/TThreadedServer.cpp b/lib/cpp/src/thrift/server/TThreadedServer.cpp
index 909c3ce..2264df7 100644
--- a/lib/cpp/src/thrift/server/TThreadedServer.cpp
+++ b/lib/cpp/src/thrift/server/TThreadedServer.cpp
@@ -17,225 +17,137 @@
  * under the License.
  */
 
-#include <thrift/server/TThreadedServer.h>
-#include <thrift/transport/TTransportException.h>
-#include <thrift/concurrency/PlatformThreadFactory.h>
-
 #include <string>
-#include <iostream>
+#include <memory>
+#include <thrift/concurrency/PlatformThreadFactory.h>
+#include <thrift/server/TThreadedServer.h>
 
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
+namespace apache {
+namespace thrift {
+namespace server {
 
-namespace apache { namespace thrift { namespace server {
+using apache::thrift::concurrency::Runnable;
+using apache::thrift::concurrency::Synchronized;
+using apache::thrift::concurrency::Thread;
+using apache::thrift::concurrency::ThreadFactory;
+using apache::thrift::protocol::TProtocol;
+using apache::thrift::protocol::TProtocolFactory;
+using std::make_shared;
+using std::shared_ptr;
+using apache::thrift::transport::TServerTransport;
+using apache::thrift::transport::TTransport;
+using apache::thrift::transport::TTransportException;
+using apache::thrift::transport::TTransportFactory;
 
-using boost::shared_ptr;
-using namespace std;
-using namespace apache::thrift;
-using namespace apache::thrift::protocol;
-using namespace apache::thrift::transport;
-using namespace apache::thrift::concurrency;
-
-class TThreadedServer::Task: public Runnable {
-
-public:
-
-  Task(TThreadedServer& server,
-       shared_ptr<TProcessor> processor,
-       shared_ptr<TProtocol> input,
-       shared_ptr<TProtocol> output,
-       shared_ptr<TTransport> transport) :
-    server_(server),
-    processor_(processor),
-    input_(input),
-    output_(output),
-    transport_(transport) {
-  }
-
-  ~Task() {}
-
-  void run() {
-    boost::shared_ptr<TServerEventHandler> eventHandler =
-      server_.getEventHandler();
-    void* connectionContext = NULL;
-    if (eventHandler) {
-      connectionContext = eventHandler->createContext(input_, output_);
-    }
-    try {
-      for (;;) {
-        if (eventHandler) {
-          eventHandler->processContext(connectionContext, transport_);
-        }
-        if (!processor_->process(input_, output_, connectionContext) ||
-            !input_->getTransport()->peek()) {
-          break;
-        }
-      }
-    } catch (const TTransportException& ttx) {
-      if (ttx.getType() != TTransportException::END_OF_FILE) {
-        string errStr = string("TThreadedServer client died: ") + ttx.what();
-        GlobalOutput(errStr.c_str());
-      }
-    } catch (const std::exception &x) {
-      GlobalOutput.printf("TThreadedServer exception: %s: %s",
-                          typeid(x).name(), x.what());
-    } catch (...) {
-      GlobalOutput("TThreadedServer uncaught exception.");
-    }
-    if (eventHandler) {
-      eventHandler->deleteContext(connectionContext, input_, output_);
-    }
-
-    try {
-      input_->getTransport()->close();
-    } catch (TTransportException& ttx) {
-      string errStr = string("TThreadedServer input close failed: ") + ttx.what();
-      GlobalOutput(errStr.c_str());
-    }
-    try {
-      output_->getTransport()->close();
-    } catch (TTransportException& ttx) {
-      string errStr = string("TThreadedServer output close failed: ") + ttx.what();
-      GlobalOutput(errStr.c_str());
-    }
-
-    // Remove this task from parent bookkeeping
-    {
-      Synchronized s(server_.tasksMonitor_);
-      server_.tasks_.erase(this);
-      if (server_.tasks_.empty()) {
-        server_.tasksMonitor_.notify();
-      }
-    }
-
-  }
-
- private:
-  TThreadedServer& server_;
-  friend class TThreadedServer;
-
-  shared_ptr<TProcessor> processor_;
-  shared_ptr<TProtocol> input_;
-  shared_ptr<TProtocol> output_;
-  shared_ptr<TTransport> transport_;
-};
-
-void TThreadedServer::init() {
-  stop_ = false;
-
-  if (!threadFactory_) {
-    threadFactory_.reset(new PlatformThreadFactory);
-  }
+TThreadedServer::TThreadedServer(const shared_ptr<TProcessorFactory>& processorFactory,
+                                 const shared_ptr<TServerTransport>& serverTransport,
+                                 const shared_ptr<TTransportFactory>& transportFactory,
+                                 const shared_ptr<TProtocolFactory>& protocolFactory,
+                                 const shared_ptr<ThreadFactory>& threadFactory)
+  : TServerFramework(processorFactory, serverTransport, transportFactory, protocolFactory),
+    threadFactory_(threadFactory) {
 }
 
-TThreadedServer::~TThreadedServer() {}
+TThreadedServer::TThreadedServer(const shared_ptr<TProcessor>& processor,
+                                 const shared_ptr<TServerTransport>& serverTransport,
+                                 const shared_ptr<TTransportFactory>& transportFactory,
+                                 const shared_ptr<TProtocolFactory>& protocolFactory,
+                                 const shared_ptr<ThreadFactory>& threadFactory)
+  : TServerFramework(processor, serverTransport, transportFactory, protocolFactory),
+    threadFactory_(threadFactory) {
+}
+
+TThreadedServer::TThreadedServer(const shared_ptr<TProcessorFactory>& processorFactory,
+                                 const shared_ptr<TServerTransport>& serverTransport,
+                                 const shared_ptr<TTransportFactory>& inputTransportFactory,
+                                 const shared_ptr<TTransportFactory>& outputTransportFactory,
+                                 const shared_ptr<TProtocolFactory>& inputProtocolFactory,
+                                 const shared_ptr<TProtocolFactory>& outputProtocolFactory,
+                                 const shared_ptr<ThreadFactory>& threadFactory)
+  : TServerFramework(processorFactory,
+                     serverTransport,
+                     inputTransportFactory,
+                     outputTransportFactory,
+                     inputProtocolFactory,
+                     outputProtocolFactory),
+    threadFactory_(threadFactory) {
+}
+
+TThreadedServer::TThreadedServer(const shared_ptr<TProcessor>& processor,
+                                 const shared_ptr<TServerTransport>& serverTransport,
+                                 const shared_ptr<TTransportFactory>& inputTransportFactory,
+                                 const shared_ptr<TTransportFactory>& outputTransportFactory,
+                                 const shared_ptr<TProtocolFactory>& inputProtocolFactory,
+                                 const shared_ptr<TProtocolFactory>& outputProtocolFactory,
+                                 const shared_ptr<ThreadFactory>& threadFactory)
+  : TServerFramework(processor,
+                     serverTransport,
+                     inputTransportFactory,
+                     outputTransportFactory,
+                     inputProtocolFactory,
+                     outputProtocolFactory),
+    threadFactory_(threadFactory) {
+}
+
+TThreadedServer::~TThreadedServer() {
+}
 
 void TThreadedServer::serve() {
+  TServerFramework::serve();
 
-  shared_ptr<TTransport> client;
-  shared_ptr<TTransport> inputTransport;
-  shared_ptr<TTransport> outputTransport;
-  shared_ptr<TProtocol> inputProtocol;
-  shared_ptr<TProtocol> outputProtocol;
-
-  // Start the server listening
-  serverTransport_->listen();
-
-  // Run the preServe event
-  if (eventHandler_) {
-    eventHandler_->preServe();
+  // Ensure post-condition of no active clients
+  Synchronized s(clientMonitor_);
+  while (!activeClientMap_.empty()) {
+    clientMonitor_.wait();
   }
 
-  while (!stop_) {
-    try {
-      client.reset();
-      inputTransport.reset();
-      outputTransport.reset();
-      inputProtocol.reset();
-      outputProtocol.reset();
-
-      // Fetch client from server
-      client = serverTransport_->accept();
-
-      // Make IO transports
-      inputTransport = inputTransportFactory_->getTransport(client);
-      outputTransport = outputTransportFactory_->getTransport(client);
-      inputProtocol = inputProtocolFactory_->getProtocol(inputTransport);
-      outputProtocol = outputProtocolFactory_->getProtocol(outputTransport);
-
-      shared_ptr<TProcessor> processor = getProcessor(inputProtocol,
-                                                      outputProtocol, client);
-
-      TThreadedServer::Task* task = new TThreadedServer::Task(*this,
-                                                              processor,
-                                                              inputProtocol,
-                                                              outputProtocol,
-                                                              client);
-
-      // Create a task
-      shared_ptr<Runnable> runnable =
-        shared_ptr<Runnable>(task);
-
-      // Create a thread for this task
-      shared_ptr<Thread> thread =
-        shared_ptr<Thread>(threadFactory_->newThread(runnable));
-
-      // Insert thread into the set of threads
-      {
-        Synchronized s(tasksMonitor_);
-        tasks_.insert(task);
-      }
-
-      // Start the thread!
-      thread->start();
-
-    } catch (TTransportException& ttx) {
-      if (inputTransport) { inputTransport->close(); }
-      if (outputTransport) { outputTransport->close(); }
-      if (client) { client->close(); }
-      if (!stop_ || ttx.getType() != TTransportException::INTERRUPTED) {
-        string errStr = string("TThreadedServer: TServerTransport died on accept: ") + ttx.what();
-        GlobalOutput(errStr.c_str());
-      }
-      continue;
-    } catch (TException& tx) {
-      if (inputTransport) { inputTransport->close(); }
-      if (outputTransport) { outputTransport->close(); }
-      if (client) { client->close(); }
-      string errStr = string("TThreadedServer: Caught TException: ") + tx.what();
-      GlobalOutput(errStr.c_str());
-      continue;
-    } catch (string s) {
-      if (inputTransport) { inputTransport->close(); }
-      if (outputTransport) { outputTransport->close(); }
-      if (client) { client->close(); }
-      string errStr = "TThreadedServer: Unknown exception: " + s;
-      GlobalOutput(errStr.c_str());
-      break;
-    }
-  }
-
-  // If stopped manually, make sure to close server transport
-  if (stop_) {
-    try {
-      serverTransport_->close();
-    } catch (TException &tx) {
-      string errStr = string("TThreadedServer: Exception shutting down: ") + tx.what();
-      GlobalOutput(errStr.c_str());
-    }
-    try {
-      Synchronized s(tasksMonitor_);
-      while (!tasks_.empty()) {
-        tasksMonitor_.wait();
-      }
-    } catch (TException &tx) {
-      string errStr = string("TThreadedServer: Exception joining workers: ") + tx.what();
-      GlobalOutput(errStr.c_str());
-    }
-    stop_ = false;
-  }
-
+  drainDeadClients();
 }
 
-}}} // apache::thrift::server
+void TThreadedServer::drainDeadClients() {
+  // we're in a monitor here
+  while (!deadClientMap_.empty()) {
+    ClientMap::iterator it = deadClientMap_.begin();
+    it->second->join();
+    deadClientMap_.erase(it);
+  }
+}
+
+void TThreadedServer::onClientConnected(const shared_ptr<TConnectedClient>& pClient) {
+  Synchronized sync(clientMonitor_);
+  shared_ptr<TConnectedClientRunner> pRunnable = make_shared<TConnectedClientRunner>(pClient);
+  shared_ptr<Thread> pThread = threadFactory_->newThread(pRunnable);
+  pRunnable->thread(pThread);
+  activeClientMap_.insert(ClientMap::value_type(pClient.get(), pThread));
+  pThread->start();
+}
+
+void TThreadedServer::onClientDisconnected(TConnectedClient* pClient) {
+  Synchronized sync(clientMonitor_);
+  drainDeadClients(); // use the outgoing thread to do some maintenance on our dead client backlog
+  ClientMap::iterator it = activeClientMap_.find(pClient);
+  if (it != activeClientMap_.end()) {
+    ClientMap::iterator end = it;
+    deadClientMap_.insert(it, ++end);
+    activeClientMap_.erase(it);
+  }
+  if (activeClientMap_.empty()) {
+    clientMonitor_.notify();
+  }
+}
+
+TThreadedServer::TConnectedClientRunner::TConnectedClientRunner(const shared_ptr<TConnectedClient>& pClient)
+  : pClient_(pClient) {
+}
+
+TThreadedServer::TConnectedClientRunner::~TConnectedClientRunner() {
+}
+
+void TThreadedServer::TConnectedClientRunner::run() /* override */ {
+  pClient_->run();  // Run the client
+  pClient_.reset(); // The client is done - release it here rather than in the destructor for safety
+}
+
+}
+}
+} // apache::thrift::server
diff --git a/lib/cpp/src/thrift/server/TThreadedServer.h b/lib/cpp/src/thrift/server/TThreadedServer.h
index f965fcd..c5ccd03 100644
--- a/lib/cpp/src/thrift/server/TThreadedServer.h
+++ b/lib/cpp/src/thrift/server/TThreadedServer.h
@@ -20,126 +20,124 @@
 #ifndef _THRIFT_SERVER_TTHREADEDSERVER_H_
 #define _THRIFT_SERVER_TTHREADEDSERVER_H_ 1
 
-#include <thrift/server/TServer.h>
-#include <thrift/transport/TServerTransport.h>
+#include <map>
 #include <thrift/concurrency/Monitor.h>
+#include <thrift/concurrency/PlatformThreadFactory.h>
 #include <thrift/concurrency/Thread.h>
+#include <thrift/server/TServerFramework.h>
 
-#include <boost/shared_ptr.hpp>
+namespace apache {
+namespace thrift {
+namespace server {
 
-namespace apache { namespace thrift { namespace server {
+/**
+ * Manage clients using threads - threads are created one for each client and are
+ * released when the client disconnects.  This server is used to make a dynamically
+ * scalable server up to the concurrent connection limit.
+ */
+class TThreadedServer : public TServerFramework {
+public:
+  TThreadedServer(
+      const std::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory,
+      const std::shared_ptr<apache::thrift::concurrency::ThreadFactory>& threadFactory
+      = std::shared_ptr<apache::thrift::concurrency::ThreadFactory>(
+          new apache::thrift::concurrency::PlatformThreadFactory(false)));
 
-using apache::thrift::TProcessor;
-using apache::thrift::transport::TServerTransport;
-using apache::thrift::transport::TTransportFactory;
-using apache::thrift::concurrency::Monitor;
-using apache::thrift::concurrency::ThreadFactory;
+  TThreadedServer(
+      const std::shared_ptr<apache::thrift::TProcessor>& processor,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory,
+      const std::shared_ptr<apache::thrift::concurrency::ThreadFactory>& threadFactory
+      = std::shared_ptr<apache::thrift::concurrency::ThreadFactory>(
+          new apache::thrift::concurrency::PlatformThreadFactory(false)));
 
-class TThreadedServer : public TServer {
+  TThreadedServer(
+      const std::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory,
+      const std::shared_ptr<apache::thrift::concurrency::ThreadFactory>& threadFactory
+      = std::shared_ptr<apache::thrift::concurrency::ThreadFactory>(
+          new apache::thrift::concurrency::PlatformThreadFactory(false)));
 
- public:
-  class Task;
-
-  template<typename ProcessorFactory>
-  TThreadedServer(const boost::shared_ptr<ProcessorFactory>& processorFactory,
-                  const boost::shared_ptr<TServerTransport>& serverTransport,
-                  const boost::shared_ptr<TTransportFactory>& transportFactory,
-                  const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-                  THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory));
-
-  template<typename ProcessorFactory>
-  TThreadedServer(const boost::shared_ptr<ProcessorFactory>& processorFactory,
-                  const boost::shared_ptr<TServerTransport>& serverTransport,
-                  const boost::shared_ptr<TTransportFactory>& transportFactory,
-                  const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-                  const boost::shared_ptr<ThreadFactory>& threadFactory,
-                  THRIFT_OVERLOAD_IF(ProcessorFactory, TProcessorFactory));
-
-  template<typename Processor>
-  TThreadedServer(const boost::shared_ptr<Processor>& processor,
-                  const boost::shared_ptr<TServerTransport>& serverTransport,
-                  const boost::shared_ptr<TTransportFactory>& transportFactory,
-                  const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-                  THRIFT_OVERLOAD_IF(Processor, TProcessor));
-
-  template<typename Processor>
-  TThreadedServer(const boost::shared_ptr<Processor>& processor,
-                  const boost::shared_ptr<TServerTransport>& serverTransport,
-                  const boost::shared_ptr<TTransportFactory>& transportFactory,
-                  const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-                  const boost::shared_ptr<ThreadFactory>& threadFactory,
-                  THRIFT_OVERLOAD_IF(Processor, TProcessor));
+  TThreadedServer(
+      const std::shared_ptr<apache::thrift::TProcessor>& processor,
+      const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
+      const std::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
+      const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory,
+      const std::shared_ptr<apache::thrift::concurrency::ThreadFactory>& threadFactory
+      = std::shared_ptr<apache::thrift::concurrency::ThreadFactory>(
+          new apache::thrift::concurrency::PlatformThreadFactory(false)));
 
   virtual ~TThreadedServer();
 
+  /**
+   * Post-conditions (return guarantees):
+   *   There will be no clients connected.
+   */
   virtual void serve();
 
-  void stop() {
-    stop_ = true;
-    serverTransport_->interrupt();
-  }
+protected:
+  /**
+   * Drain recently connected clients by joining their threads - this is done lazily because
+   * we cannot do it inside the thread context that is disconnecting.
+   */
+  virtual void drainDeadClients();
 
- protected:
-  void init();
+  /**
+   * Implementation of TServerFramework::onClientConnected
+   */
+  virtual void onClientConnected(const std::shared_ptr<TConnectedClient>& pClient) /* override */;
 
-  boost::shared_ptr<ThreadFactory> threadFactory_;
-  volatile bool stop_;
+  /**
+   * Implementation of TServerFramework::onClientDisconnected
+   */
+  virtual void onClientDisconnected(TConnectedClient *pClient) /* override */;
 
-  Monitor tasksMonitor_;
-  std::set<Task*> tasks_;
+  std::shared_ptr<apache::thrift::concurrency::ThreadFactory> threadFactory_;
 
+  /**
+   * A helper wrapper used to wrap the client in something we can use to maintain
+   * the lifetime of the connected client within a detached thread.  We cannot simply
+   * track the threads because a shared_ptr<Thread> hangs on to the Runnable it is
+   * passed, and TServerFramework requires the runnable (TConnectedClient) to be
+   * destroyed in order to work properly.
+   */
+  class TConnectedClientRunner : public apache::thrift::concurrency::Runnable
+  {
+  public:
+    TConnectedClientRunner(const std::shared_ptr<TConnectedClient>& pClient);
+    virtual ~TConnectedClientRunner();
+    void run() /* override */;
+  private:
+    std::shared_ptr<TConnectedClient> pClient_;
+  };
+
+  apache::thrift::concurrency::Monitor clientMonitor_;
+
+  typedef std::map<TConnectedClient *, std::shared_ptr<apache::thrift::concurrency::Thread> > ClientMap;
+
+  /**
+   * A map of active clients
+   */
+  ClientMap activeClientMap_;
+
+  /**
+   * A map of clients that have disconnected but their threads have not been joined
+   */
+  ClientMap deadClientMap_;
 };
 
-template<typename ProcessorFactory>
-TThreadedServer::TThreadedServer(
-    const boost::shared_ptr<ProcessorFactory>& processorFactory,
-    const boost::shared_ptr<TServerTransport>& serverTransport,
-    const boost::shared_ptr<TTransportFactory>& transportFactory,
-    const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-    THRIFT_OVERLOAD_IF_DEFN(ProcessorFactory, TProcessorFactory)) :
-  TServer(processorFactory, serverTransport, transportFactory,
-          protocolFactory) {
-  init();
 }
-
-template<typename ProcessorFactory>
-TThreadedServer::TThreadedServer(
-    const boost::shared_ptr<ProcessorFactory>& processorFactory,
-    const boost::shared_ptr<TServerTransport>& serverTransport,
-    const boost::shared_ptr<TTransportFactory>& transportFactory,
-    const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-    const boost::shared_ptr<ThreadFactory>& threadFactory,
-    THRIFT_OVERLOAD_IF_DEFN(ProcessorFactory, TProcessorFactory)) :
-  TServer(processorFactory, serverTransport, transportFactory,
-          protocolFactory),
-  threadFactory_(threadFactory) {
-  init();
 }
-
-template<typename Processor>
-TThreadedServer::TThreadedServer(
-    const boost::shared_ptr<Processor>& processor,
-    const boost::shared_ptr<TServerTransport>& serverTransport,
-    const boost::shared_ptr<TTransportFactory>& transportFactory,
-    const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-    THRIFT_OVERLOAD_IF_DEFN(Processor, TProcessor)) :
-  TServer(processor, serverTransport, transportFactory, protocolFactory) {
-  init();
-}
-
-template<typename Processor>
-TThreadedServer::TThreadedServer(
-    const boost::shared_ptr<Processor>& processor,
-    const boost::shared_ptr<TServerTransport>& serverTransport,
-    const boost::shared_ptr<TTransportFactory>& transportFactory,
-    const boost::shared_ptr<TProtocolFactory>& protocolFactory,
-    const boost::shared_ptr<ThreadFactory>& threadFactory,
-    THRIFT_OVERLOAD_IF_DEFN(Processor, TProcessor)) :
-  TServer(processor, serverTransport, transportFactory, protocolFactory),
-  threadFactory_(threadFactory) {
-  init();
-}
-
-}}} // apache::thrift::server
+} // apache::thrift::server
 
 #endif // #ifndef _THRIFT_SERVER_TTHREADEDSERVER_H_
diff --git a/lib/cpp/src/thrift/thrift-config.h b/lib/cpp/src/thrift/thrift-config.h
old mode 100755
new mode 100644
index b1bcccb..d648706
--- a/lib/cpp/src/thrift/thrift-config.h
+++ b/lib/cpp/src/thrift/thrift-config.h
@@ -18,7 +18,7 @@
  */
 
 #ifdef _WIN32
-# include <thrift/windows/config.h>
+#include <thrift/windows/config.h>
 #else
-# include <thrift/config.h>
+#include <thrift/config.h>
 #endif
diff --git a/lib/cpp/src/thrift/transport/PlatformSocket.h b/lib/cpp/src/thrift/transport/PlatformSocket.h
index 58d68a4..9591058 100644
--- a/lib/cpp/src/thrift/transport/PlatformSocket.h
+++ b/lib/cpp/src/thrift/transport/PlatformSocket.h
@@ -17,11 +17,15 @@
  * under the License.
  */
 
+// clang-format off
+
 #ifndef _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_
 #  define _THRIFT_TRANSPORT_PLATFORM_SOCKET_H_
 
 #ifdef _WIN32
+#  include <winsock2.h>
 #  define THRIFT_GET_SOCKET_ERROR ::WSAGetLastError()
+#  define THRIFT_ERRNO (*_errno())
 #  define THRIFT_EINPROGRESS WSAEINPROGRESS
 #  define THRIFT_EAGAIN WSAEWOULDBLOCK
 #  define THRIFT_EINTR WSAEINTR
@@ -40,9 +44,28 @@
 #  define THRIFT_F_SETFL 1
 #  define THRIFT_GETTIMEOFDAY thrift_gettimeofday
 #  define THRIFT_CLOSESOCKET closesocket
-#  define THRIFT_GAI_STRERROR gai_strerrorA
+#  define THRIFT_CLOSE _close
+#  define THRIFT_OPEN _open
+#  define THRIFT_FTRUNCATE _chsize_s
+#  define THRIFT_FSYNC _commit
+#  define THRIFT_LSEEK _lseek
+#  define THRIFT_WRITE _write
+#  define THRIFT_READ _read
+#  define THRIFT_IOCTL_SOCKET ioctlsocket
+#  define THRIFT_IOCTL_SOCKET_NUM_BYTES_TYPE u_long
+#  define THRIFT_FSTAT _fstat
+#  define THRIFT_STAT _stat
+#  ifdef _WIN32_WCE
+#    define THRIFT_GAI_STRERROR(...) thrift_wstr2str(gai_strerrorW(__VA_ARGS__))
+#  else
+#    define THRIFT_GAI_STRERROR gai_strerrorA
+#  endif
 #  define THRIFT_SSIZET ptrdiff_t
-#  define THRIFT_SNPRINTF _snprintf
+#  if (_MSC_VER < 1900)
+#    define THRIFT_SNPRINTF _snprintf
+#  else
+#    define THRIFT_SNPRINTF snprintf
+#  endif
 #  define THRIFT_SLEEP_SEC thrift_sleep
 #  define THRIFT_SLEEP_USEC thrift_usleep
 #  define THRIFT_TIMESPEC thrift_timespec
@@ -58,9 +81,13 @@
 #    define THRIFT_POLLOUT POLLOUT
 #  endif //WINVER
 #  define THRIFT_SHUT_RDWR SD_BOTH
+#  if !defined(AI_ADDRCONFIG)
+#    define AI_ADDRCONFIG 0x00000400
+#  endif
 #else //not _WIN32
 #  include <errno.h>
 #  define THRIFT_GET_SOCKET_ERROR errno
+#  define THRIFT_ERRNO errno
 #  define THRIFT_EINTR       EINTR
 #  define THRIFT_EINPROGRESS EINPROGRESS
 #  define THRIFT_ECONNRESET  ECONNRESET
@@ -79,6 +106,17 @@
 #  define THRIFT_F_SETFL F_SETFL
 #  define THRIFT_GETTIMEOFDAY gettimeofday
 #  define THRIFT_CLOSESOCKET close
+#  define THRIFT_CLOSE close
+#  define THRIFT_OPEN open
+#  define THRIFT_FTRUNCATE ftruncate
+#  define THRIFT_FSYNC fsync
+#  define THRIFT_LSEEK lseek
+#  define THRIFT_WRITE write
+#  define THRIFT_READ read
+#  define THRIFT_IOCTL_SOCKET ioctl
+#  define THRIFT_IOCTL_SOCKET_NUM_BYTES_TYPE int
+#  define THRIFT_STAT stat
+#  define THRIFT_FSTAT fstat
 #  define THRIFT_GAI_STRERROR gai_strerror
 #  define THRIFT_SSIZET ssize_t
 #  define THRIFT_SNPRINTF snprintf
diff --git a/lib/cpp/src/thrift/transport/TBufferTransports.cpp b/lib/cpp/src/thrift/transport/TBufferTransports.cpp
index a307748..9ac2f84 100644
--- a/lib/cpp/src/thrift/transport/TBufferTransports.cpp
+++ b/lib/cpp/src/thrift/transport/TBufferTransports.cpp
@@ -24,8 +24,9 @@
 
 using std::string;
 
-namespace apache { namespace thrift { namespace transport {
-
+namespace apache {
+namespace thrift {
+namespace transport {
 
 uint32_t TBufferedTransport::readSlow(uint8_t* buf, uint32_t len) {
   uint32_t have = static_cast<uint32_t>(rBound_ - rBase_);
@@ -62,7 +63,7 @@
 void TBufferedTransport::writeSlow(const uint8_t* buf, uint32_t len) {
   uint32_t have_bytes = static_cast<uint32_t>(wBase_ - wBuf_.get());
   uint32_t space = static_cast<uint32_t>(wBound_ - wBase_);
-  // We should only take the slow path if we can't accomodate the write
+  // We should only take the slow path if we can't accommodate the write
   // with the free space already in the buffer.
   assert(wBound_ - wBase_ < static_cast<ptrdiff_t>(len));
 
@@ -85,7 +86,7 @@
   // The case where we have to do two syscalls.
   // This case also covers the case where the buffer is empty,
   // but it is clearer (I think) to think of it as two separate cases.
-  if ((have_bytes + len >= 2*wBufSize_) || (have_bytes == 0)) {
+  if ((have_bytes + len >= 2 * wBufSize_) || (have_bytes == 0)) {
     // TODO(dreiss): writev
     if (have_bytes > 0) {
       transport_->write(wBuf_.get(), have_bytes);
@@ -109,14 +110,14 @@
 }
 
 const uint8_t* TBufferedTransport::borrowSlow(uint8_t* buf, uint32_t* len) {
-  (void) buf;
-  (void) len;
+  (void)buf;
+  (void)len;
   // Simply return NULL.  We don't know if there is actually data available on
   // the underlying transport, so calling read() might block.
   return NULL;
 }
 
-void TBufferedTransport::flush()  {
+void TBufferedTransport::flush() {
   // Write out any data waiting in the write buffer.
   uint32_t have_bytes = static_cast<uint32_t>(wBase_ - wBuf_.get());
   if (have_bytes > 0) {
@@ -131,7 +132,6 @@
   transport_->flush();
 }
 
-
 uint32_t TFramedTransport::readSlow(uint8_t* buf, uint32_t len) {
   uint32_t want = len;
   uint32_t have = static_cast<uint32_t>(rBound_ - rBase_);
@@ -175,13 +175,12 @@
   // We can't use readAll(&sz, sizeof(sz)), since that always throws an
   // exception on EOF.  We want to throw an exception only if EOF occurs after
   // partial size data.
-  int32_t sz;
+  int32_t sz = -1;
   uint32_t size_bytes_read = 0;
   while (size_bytes_read < sizeof(sz)) {
     uint8_t* szp = reinterpret_cast<uint8_t*>(&sz) + size_bytes_read;
-    uint32_t bytes_read = transport_->read(
-      szp,
-      static_cast<uint32_t>(sizeof(sz)) - size_bytes_read);
+    uint32_t bytes_read
+        = transport_->read(szp, static_cast<uint32_t>(sizeof(sz)) - size_bytes_read);
     if (bytes_read == 0) {
       if (size_bytes_read == 0) {
         // EOF before any data was read.
@@ -202,6 +201,10 @@
     throw TTransportException("Frame size has negative value");
   }
 
+  // Check for oversized frame
+  if (sz > static_cast<int32_t>(maxFrameSize_))
+    throw TTransportException(TTransportException::CORRUPTED_DATA, "Received an oversized frame");
+
   // Read the frame payload, and reset markers.
   if (sz > static_cast<int32_t>(rBufSize_)) {
     rBuf_.reset(new uint8_t[sz]);
@@ -218,7 +221,7 @@
   uint32_t new_size = wBufSize_;
   if (len + have < have /* overflow */ || len + have > 0x7fffffff) {
     throw TTransportException(TTransportException::BAD_ARGS,
-        "Attempted to write over 2 GB to TFramedTransport.");
+                              "Attempted to write over 2 GB to TFramedTransport.");
   }
   while (new_size < len + have) {
     new_size = new_size > 0 ? new_size * 2 : 1;
@@ -244,7 +247,7 @@
   wBase_ += len;
 }
 
-void TFramedTransport::flush()  {
+void TFramedTransport::flush() {
   int32_t sz_hbo, sz_nbo;
   assert(wBufSize_ > sizeof(sz_nbo));
 
@@ -261,13 +264,22 @@
     wBase_ = wBuf_.get() + sizeof(sz_nbo);
 
     // Write size and frame body.
-    transport_->write(
-      wBuf_.get(),
-      static_cast<uint32_t>(sizeof(sz_nbo))+sz_hbo);
+    transport_->write(wBuf_.get(), static_cast<uint32_t>(sizeof(sz_nbo)) + sz_hbo);
   }
 
   // Flush the underlying transport.
   transport_->flush();
+
+  // reclaim write buffer
+  if (wBufSize_ > bufReclaimThresh_) {
+    wBufSize_ = DEFAULT_BUFFER_SIZE;
+    wBuf_.reset(new uint8_t[wBufSize_]);
+    setWriteBuffer(wBuf_.get(), wBufSize_);
+
+    // reset wBase_ with a pad for the frame size
+    int32_t pad = 0;
+    wBase_ = wBuf_.get() + sizeof(pad);
+  }
 }
 
 uint32_t TFramedTransport::writeEnd() {
@@ -275,8 +287,8 @@
 }
 
 const uint8_t* TFramedTransport::borrowSlow(uint8_t* buf, uint32_t* len) {
-  (void) buf;
-  (void) len;
+  (void)buf;
+  (void)len;
   // Don't try to be clever with shifting buffers.
   // If the fast path failed let the protocol use its slow path.
   // Besides, who is going to try to borrow across messages?
@@ -285,7 +297,15 @@
 
 uint32_t TFramedTransport::readEnd() {
   // include framing bytes
-  return static_cast<uint32_t>(rBound_ - rBuf_.get() + sizeof(uint32_t));
+  uint32_t bytes_read = static_cast<uint32_t>(rBound_ - rBuf_.get() + sizeof(uint32_t));
+
+  if (rBufSize_ > bufReclaimThresh_) {
+    rBufSize_ = 0;
+    rBuf_.reset();
+    setReadBuffer(rBuf_.get(), rBufSize_);
+  }
+
+  return bytes_read;
 }
 
 void TMemoryBuffer::computeRead(uint32_t len, uint8_t** out_start, uint32_t* out_give) {
@@ -341,25 +361,28 @@
   }
 
   // Grow the buffer as necessary.
-  uint32_t new_size = bufferSize_;
+  uint64_t new_size = bufferSize_;
   while (len > avail) {
     new_size = new_size > 0 ? new_size * 2 : 1;
-    avail = available_write() + (new_size - bufferSize_);
+    if (new_size > maxBufferSize_) {
+      throw TTransportException(TTransportException::BAD_ARGS,
+                                "Internal buffer size overflow");
+    }
+    avail = available_write() + (static_cast<uint32_t>(new_size) - bufferSize_);
   }
 
   // Allocate into a new pointer so we don't bork ours if it fails.
-  void* new_buffer = std::realloc(buffer_, new_size);
+  uint8_t* new_buffer = static_cast<uint8_t*>(std::realloc(buffer_, new_size));
   if (new_buffer == NULL) {
     throw std::bad_alloc();
   }
-  bufferSize_ = new_size;
 
-  ptrdiff_t offset = (uint8_t*)new_buffer - buffer_;
-  buffer_ += offset;
-  rBase_ += offset;
-  rBound_ += offset;
-  wBase_ += offset;
-  wBound_ = buffer_ + bufferSize_;
+  rBase_ = new_buffer + (rBase_ - buffer_);
+  rBound_ = new_buffer + (rBound_ - buffer_);
+  wBase_ = new_buffer + (wBase_ - buffer_);
+  wBound_ = new_buffer + new_size;
+  buffer_ = new_buffer;
+  bufferSize_ = static_cast<uint32_t>(new_size);
 }
 
 void TMemoryBuffer::writeSlow(const uint8_t* buf, uint32_t len) {
@@ -379,7 +402,7 @@
 }
 
 const uint8_t* TMemoryBuffer::borrowSlow(uint8_t* buf, uint32_t* len) {
-  (void) buf;
+  (void)buf;
   rBound_ = wBase_;
   if (available_read() >= *len) {
     *len = available_read();
@@ -387,5 +410,6 @@
   }
   return NULL;
 }
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/TBufferTransports.h b/lib/cpp/src/thrift/transport/TBufferTransports.h
index cd6ecea..c423f9c 100644
--- a/lib/cpp/src/thrift/transport/TBufferTransports.h
+++ b/lib/cpp/src/thrift/transport/TBufferTransports.h
@@ -20,7 +20,9 @@
 #ifndef _THRIFT_TRANSPORT_TBUFFERTRANSPORTS_H_
 #define _THRIFT_TRANSPORT_TBUFFERTRANSPORTS_H_ 1
 
+#include <cstdlib>
 #include <cstring>
+#include <limits>
 #include <boost/scoped_array.hpp>
 
 #include <thrift/transport/TTransport.h>
@@ -34,8 +36,9 @@
 #define TDB_UNLIKELY(val) (val)
 #endif
 
-namespace apache { namespace thrift { namespace transport {
-
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * Base class for all transports that use read/write buffers for performance.
@@ -49,8 +52,7 @@
  */
 class TBufferBase : public TVirtualTransport<TBufferBase> {
 
- public:
-
+public:
   /**
    * Fast-path read.
    *
@@ -85,7 +87,7 @@
   /**
    * Fast-path write.
    *
-   * When we have enough empty space in our buffer to accomodate the write, we
+   * When we have enough empty space in our buffer to accommodate the write, we
    * can satisfy it with a single memcpy, then adjust our internal pointers.
    * If the buffer is full, we call out to our slow path, implemented by a
    * subclass.  This method is meant to eventually be nonvirtual and
@@ -121,14 +123,11 @@
     if (TDB_LIKELY(static_cast<ptrdiff_t>(len) <= rBound_ - rBase_)) {
       rBase_ += len;
     } else {
-      throw TTransportException(TTransportException::BAD_ARGS,
-                                "consume did not follow a borrow.");
+      throw TTransportException(TTransportException::BAD_ARGS, "consume did not follow a borrow.");
     }
   }
 
-
- protected:
-
+protected:
   /// Slow path read.
   virtual uint32_t readSlow(uint8_t* buf, uint32_t len) = 0;
 
@@ -149,23 +148,18 @@
    * performance-sensitive operation, so it is okay to just leave it to
    * the concrete class to set up pointers correctly.
    */
-  TBufferBase()
-    : rBase_(NULL)
-    , rBound_(NULL)
-    , wBase_(NULL)
-    , wBound_(NULL)
-  {}
+  TBufferBase() : rBase_(NULL), rBound_(NULL), wBase_(NULL), wBound_(NULL) {}
 
   /// Convenience mutator for setting the read buffer.
   void setReadBuffer(uint8_t* buf, uint32_t len) {
     rBase_ = buf;
-    rBound_ = buf+len;
+    rBound_ = buf + len;
   }
 
   /// Convenience mutator for setting the write buffer.
   void setWriteBuffer(uint8_t* buf, uint32_t len) {
     wBase_ = buf;
-    wBound_ = buf+len;
+    wBound_ = buf + len;
   }
 
   virtual ~TBufferBase() {}
@@ -181,59 +175,49 @@
   uint8_t* wBound_;
 };
 
-
 /**
  * Buffered transport. For reads it will read more data than is requested
  * and will serve future data out of a local buffer. For writes, data is
  * stored to an in memory buffer before being written out.
  *
  */
-class TBufferedTransport
-  : public TVirtualTransport<TBufferedTransport, TBufferBase> {
- public:
-
+class TBufferedTransport : public TVirtualTransport<TBufferedTransport, TBufferBase> {
+public:
   static const int DEFAULT_BUFFER_SIZE = 512;
 
   /// Use default buffer sizes.
-  TBufferedTransport(boost::shared_ptr<TTransport> transport)
-    : transport_(transport)
-    , rBufSize_(DEFAULT_BUFFER_SIZE)
-    , wBufSize_(DEFAULT_BUFFER_SIZE)
-    , rBuf_(new uint8_t[rBufSize_])
-    , wBuf_(new uint8_t[wBufSize_])
-  {
+  TBufferedTransport(std::shared_ptr<TTransport> transport)
+    : transport_(transport),
+      rBufSize_(DEFAULT_BUFFER_SIZE),
+      wBufSize_(DEFAULT_BUFFER_SIZE),
+      rBuf_(new uint8_t[rBufSize_]),
+      wBuf_(new uint8_t[wBufSize_]) {
     initPointers();
   }
 
   /// Use specified buffer sizes.
-  TBufferedTransport(boost::shared_ptr<TTransport> transport, uint32_t sz)
-    : transport_(transport)
-    , rBufSize_(sz)
-    , wBufSize_(sz)
-    , rBuf_(new uint8_t[rBufSize_])
-    , wBuf_(new uint8_t[wBufSize_])
-  {
+  TBufferedTransport(std::shared_ptr<TTransport> transport, uint32_t sz)
+    : transport_(transport),
+      rBufSize_(sz),
+      wBufSize_(sz),
+      rBuf_(new uint8_t[rBufSize_]),
+      wBuf_(new uint8_t[wBufSize_]) {
     initPointers();
   }
 
   /// Use specified read and write buffer sizes.
-  TBufferedTransport(boost::shared_ptr<TTransport> transport, uint32_t rsz, uint32_t wsz)
-    : transport_(transport)
-    , rBufSize_(rsz)
-    , wBufSize_(wsz)
-    , rBuf_(new uint8_t[rBufSize_])
-    , wBuf_(new uint8_t[wBufSize_])
-  {
+  TBufferedTransport(std::shared_ptr<TTransport> transport, uint32_t rsz, uint32_t wsz)
+    : transport_(transport),
+      rBufSize_(rsz),
+      wBufSize_(wsz),
+      rBuf_(new uint8_t[rBufSize_]),
+      wBuf_(new uint8_t[wBufSize_]) {
     initPointers();
   }
 
-  void open() {
-    transport_->open();
-  }
+  void open() { transport_->open(); }
 
-  bool isOpen() {
-    return transport_->isOpen();
-  }
+  bool isOpen() { return transport_->isOpen(); }
 
   bool peek() {
     if (rBase_ == rBound_) {
@@ -253,6 +237,10 @@
 
   void flush();
 
+  /**
+   * Returns the origin of the underlying transport
+   */
+  virtual const std::string getOrigin() { return transport_->getOrigin(); }
 
   /**
    * The following behavior is currently implemented by TBufferedTransport,
@@ -267,26 +255,22 @@
    */
   virtual const uint8_t* borrowSlow(uint8_t* buf, uint32_t* len);
 
-  boost::shared_ptr<TTransport> getUnderlyingTransport() {
-    return transport_;
-  }
+  std::shared_ptr<TTransport> getUnderlyingTransport() { return transport_; }
 
   /*
    * TVirtualTransport provides a default implementation of readAll().
    * We want to use the TBufferBase version instead.
    */
-  uint32_t readAll(uint8_t* buf, uint32_t len) {
-    return TBufferBase::readAll(buf, len);
-  }
+  uint32_t readAll(uint8_t* buf, uint32_t len) { return TBufferBase::readAll(buf, len); }
 
- protected:
+protected:
   void initPointers() {
     setReadBuffer(rBuf_.get(), 0);
     setWriteBuffer(wBuf_.get(), wBufSize_);
     // Write size never changes.
   }
 
-  boost::shared_ptr<TTransport> transport_;
+  std::shared_ptr<TTransport> transport_;
 
   uint32_t rBufSize_;
   uint32_t wBufSize_;
@@ -294,13 +278,12 @@
   boost::scoped_array<uint8_t> wBuf_;
 };
 
-
 /**
  * Wraps a transport into a buffered one.
  *
  */
 class TBufferedTransportFactory : public TTransportFactory {
- public:
+public:
   TBufferedTransportFactory() {}
 
   virtual ~TBufferedTransportFactory() {}
@@ -308,13 +291,11 @@
   /**
    * Wraps the transport into a buffered one.
    */
-  virtual boost::shared_ptr<TTransport> getTransport(boost::shared_ptr<TTransport> trans) {
-    return boost::shared_ptr<TTransport>(new TBufferedTransport(trans));
+  virtual std::shared_ptr<TTransport> getTransport(std::shared_ptr<TTransport> trans) {
+    return std::shared_ptr<TTransport>(new TBufferedTransport(trans));
   }
-
 };
 
-
 /**
  * Framed transport. All writes go into an in-memory buffer until flush is
  * called, at which point the transport writes the length of the entire
@@ -322,44 +303,51 @@
  * other end to always do fixed-length reads.
  *
  */
-class TFramedTransport
-  : public TVirtualTransport<TFramedTransport, TBufferBase> {
- public:
-
+class TFramedTransport : public TVirtualTransport<TFramedTransport, TBufferBase> {
+public:
   static const int DEFAULT_BUFFER_SIZE = 512;
+  static const int DEFAULT_MAX_FRAME_SIZE = 256 * 1024 * 1024;
 
   /// Use default buffer sizes.
-  TFramedTransport(boost::shared_ptr<TTransport> transport)
-    : transport_(transport)
-    , rBufSize_(0)
-    , wBufSize_(DEFAULT_BUFFER_SIZE)
-    , rBuf_()
-    , wBuf_(new uint8_t[wBufSize_])
-  {
+  TFramedTransport()
+    : transport_(),
+      rBufSize_(0),
+      wBufSize_(DEFAULT_BUFFER_SIZE),
+      rBuf_(),
+      wBuf_(new uint8_t[wBufSize_]),
+      bufReclaimThresh_((std::numeric_limits<uint32_t>::max)()) {
     initPointers();
   }
 
-  TFramedTransport(boost::shared_ptr<TTransport> transport, uint32_t sz)
-    : transport_(transport)
-    , rBufSize_(0)
-    , wBufSize_(sz)
-    , rBuf_()
-    , wBuf_(new uint8_t[wBufSize_])
-  {
+  TFramedTransport(std::shared_ptr<TTransport> transport)
+    : transport_(transport),
+      rBufSize_(0),
+      wBufSize_(DEFAULT_BUFFER_SIZE),
+      rBuf_(),
+      wBuf_(new uint8_t[wBufSize_]),
+      bufReclaimThresh_((std::numeric_limits<uint32_t>::max)()),
+      maxFrameSize_(DEFAULT_MAX_FRAME_SIZE) {
     initPointers();
   }
 
-  void open() {
-    transport_->open();
+  TFramedTransport(std::shared_ptr<TTransport> transport,
+                   uint32_t sz,
+                   uint32_t bufReclaimThresh = (std::numeric_limits<uint32_t>::max)())
+    : transport_(transport),
+      rBufSize_(0),
+      wBufSize_(sz),
+      rBuf_(),
+      wBuf_(new uint8_t[wBufSize_]),
+      bufReclaimThresh_(bufReclaimThresh),
+      maxFrameSize_(DEFAULT_MAX_FRAME_SIZE) {
+    initPointers();
   }
 
-  bool isOpen() {
-    return transport_->isOpen();
-  }
+  void open() { transport_->open(); }
 
-  bool peek() {
-    return (rBase_ < rBound_) || transport_->peek();
-  }
+  bool isOpen() { return transport_->isOpen(); }
+
+  bool peek() { return (rBase_ < rBound_) || transport_->peek(); }
 
   void close() {
     flush();
@@ -378,26 +366,37 @@
 
   const uint8_t* borrowSlow(uint8_t* buf, uint32_t* len);
 
-  boost::shared_ptr<TTransport> getUnderlyingTransport() {
-    return transport_;
-  }
+  std::shared_ptr<TTransport> getUnderlyingTransport() { return transport_; }
 
   /*
    * TVirtualTransport provides a default implementation of readAll().
    * We want to use the TBufferBase version instead.
    */
-  uint32_t readAll(uint8_t* buf, uint32_t len) {
-    return TBufferBase::readAll(buf,len);
-  }
+  using TBufferBase::readAll;
 
- protected:
+  /**
+   * Returns the origin of the underlying transport
+   */
+  virtual const std::string getOrigin() { return transport_->getOrigin(); }
+
+  /**
+   * Set the maximum size of the frame at read
+   */
+  void setMaxFrameSize(uint32_t maxFrameSize) { maxFrameSize_ = maxFrameSize; }
+
+  /**
+   * Get the maximum size of the frame at read
+   */
+  uint32_t getMaxFrameSize() { return maxFrameSize_; }
+
+protected:
   /**
    * Reads a frame of input from the underlying stream.
    *
    * Returns true if a frame was read successfully, or false on EOF.
    * (Raises a TTransportException if EOF occurs after a partial frame.)
    */
-  bool readFrame();
+  virtual bool readFrame();
 
   void initPointers() {
     setReadBuffer(NULL, 0);
@@ -408,12 +407,14 @@
     this->write((uint8_t*)&pad, sizeof(pad));
   }
 
-  boost::shared_ptr<TTransport> transport_;
+  std::shared_ptr<TTransport> transport_;
 
   uint32_t rBufSize_;
   uint32_t wBufSize_;
   boost::scoped_array<uint8_t> rBuf_;
   boost::scoped_array<uint8_t> wBuf_;
+  uint32_t bufReclaimThresh_;
+  uint32_t maxFrameSize_;
 };
 
 /**
@@ -421,7 +422,7 @@
  *
  */
 class TFramedTransportFactory : public TTransportFactory {
- public:
+public:
   TFramedTransportFactory() {}
 
   virtual ~TFramedTransportFactory() {}
@@ -429,13 +430,11 @@
   /**
    * Wraps the transport into a framed one.
    */
-  virtual boost::shared_ptr<TTransport> getTransport(boost::shared_ptr<TTransport> trans) {
-    return boost::shared_ptr<TTransport>(new TFramedTransport(trans));
+  virtual std::shared_ptr<TTransport> getTransport(std::shared_ptr<TTransport> trans) {
+    return std::shared_ptr<TTransport>(new TFramedTransport(trans));
   }
-
 };
 
-
 /**
  * A memory buffer is a tranpsort that simply reads from and writes to an
  * in memory buffer. Anytime you call write on it, the data is simply placed
@@ -446,15 +445,17 @@
  *
  */
 class TMemoryBuffer : public TVirtualTransport<TMemoryBuffer, TBufferBase> {
- private:
-
+private:
   // Common initialization done by all constructors.
   void initCommon(uint8_t* buf, uint32_t size, bool owner, uint32_t wPos) {
+
+    maxBufferSize_ = (std::numeric_limits<uint32_t>::max)();
+
     if (buf == NULL && size != 0) {
       assert(owner);
       buf = (uint8_t*)std::malloc(size);
       if (buf == NULL) {
-        throw std::bad_alloc();
+	throw std::bad_alloc();
       }
     }
 
@@ -473,7 +474,7 @@
     // equal to wBase_.  We update it in a few places (computeRead, etc.).
   }
 
- public:
+public:
   static const uint32_t defaultSize = 1024;
 
   /**
@@ -496,19 +497,13 @@
    *   and will be responsible for freeing it.
    *   The membory must have been allocated with malloc.
    */
-  enum MemoryPolicy
-  { OBSERVE = 1
-  , COPY = 2
-  , TAKE_OWNERSHIP = 3
-  };
+  enum MemoryPolicy { OBSERVE = 1, COPY = 2, TAKE_OWNERSHIP = 3 };
 
   /**
    * Construct a TMemoryBuffer with a default-sized buffer,
    * owned by the TMemoryBuffer object.
    */
-  TMemoryBuffer() {
-    initCommon(NULL, defaultSize, true, 0);
-  }
+  TMemoryBuffer() { initCommon(NULL, defaultSize, true, 0); }
 
   /**
    * Construct a TMemoryBuffer with a buffer of a specified size,
@@ -516,9 +511,7 @@
    *
    * @param sz  The initial size of the buffer.
    */
-  TMemoryBuffer(uint32_t sz) {
-    initCommon(NULL, sz, true, 0);
-  }
+  TMemoryBuffer(uint32_t sz) { initCommon(NULL, sz, true, 0); }
 
   /**
    * Construct a TMemoryBuffer with buf as its initial contents.
@@ -537,17 +530,17 @@
     }
 
     switch (policy) {
-      case OBSERVE:
-      case TAKE_OWNERSHIP:
-        initCommon(buf, sz, policy == TAKE_OWNERSHIP, sz);
-        break;
-      case COPY:
-        initCommon(NULL, sz, true, 0);
-        this->write(buf, sz);
-        break;
-      default:
-        throw TTransportException(TTransportException::BAD_ARGS,
-                                  "Invalid MemoryPolicy for TMemoryBuffer");
+    case OBSERVE:
+    case TAKE_OWNERSHIP:
+      initCommon(buf, sz, policy == TAKE_OWNERSHIP, sz);
+      break;
+    case COPY:
+      initCommon(NULL, sz, true, 0);
+      this->write(buf, sz);
+      break;
+    default:
+      throw TTransportException(TTransportException::BAD_ARGS,
+                                "Invalid MemoryPolicy for TMemoryBuffer");
     }
   }
 
@@ -557,13 +550,9 @@
     }
   }
 
-  bool isOpen() {
-    return true;
-  }
+  bool isOpen() { return true; }
 
-  bool peek() {
-    return (rBase_ < wBase_);
-  }
+  bool peek() { return (rBase_ < wBase_); }
 
   void open() {}
 
@@ -646,7 +635,7 @@
 
   // return number of bytes read
   uint32_t readEnd() {
-    //This cast should be safe, because buffer_'s size is a uint32_t
+    // This cast should be safe, because buffer_'s size is a uint32_t
     uint32_t bytes = static_cast<uint32_t>(rBase_ - buffer_);
     if (rBase_ == wBase_) {
       resetBuffer();
@@ -656,7 +645,7 @@
 
   // Return number of bytes written
   uint32_t writeEnd() {
-    //This cast should be safe, because buffer_'s size is a uint32_t
+    // This cast should be safe, because buffer_'s size is a uint32_t
     return static_cast<uint32_t>(wBase_ - buffer_);
   }
 
@@ -665,12 +654,10 @@
     return static_cast<uint32_t>(wBase_ - rBase_);
   }
 
-  uint32_t available_write() const {
-    return static_cast<uint32_t>(wBound_ - wBase_);
-  }
+  uint32_t available_write() const { return static_cast<uint32_t>(wBound_ - wBase_); }
 
   // Returns a pointer to where the client can write data to append to
-  // the TMemoryBuffer, and ensures the buffer is big enough to accomodate a
+  // the TMemoryBuffer, and ensures the buffer is big enough to accommodate a
   // write of the provided length.  The returned pointer is very convenient for
   // passing to read(), recv(), or similar. You must call wroteBytes() as soon
   // as data is written or the buffer will not be aware that data has changed.
@@ -687,22 +674,43 @@
    * TVirtualTransport provides a default implementation of readAll().
    * We want to use the TBufferBase version instead.
    */
-  uint32_t readAll(uint8_t* buf, uint32_t len) {
-    return TBufferBase::readAll(buf,len);
+  uint32_t readAll(uint8_t* buf, uint32_t len) { return TBufferBase::readAll(buf, len); }
+
+  //! \brief Get the current buffer size
+  //! \returns the current buffer size
+  uint32_t getBufferSize() const {
+    return bufferSize_;
   }
 
- protected:
+  //! \brief Get the current maximum buffer size
+  //! \returns the current maximum buffer size
+  uint32_t getMaxBufferSize() const {
+    return maxBufferSize_;
+  }
+
+  //! \brief Change the maximum buffer size
+  //! \param[in]  maxSize  the new maximum buffer size allowed to grow to
+  //! \throws  TTransportException(BAD_ARGS) if maxSize is less than the current buffer size
+  void setMaxBufferSize(uint32_t maxSize) {
+    if (maxSize < bufferSize_) {
+      throw TTransportException(TTransportException::BAD_ARGS,
+                                "Maximum buffer size would be less than current buffer size");
+    }
+    maxBufferSize_ = maxSize;
+  }
+
+protected:
   void swap(TMemoryBuffer& that) {
     using std::swap;
-    swap(buffer_,     that.buffer_);
+    swap(buffer_, that.buffer_);
     swap(bufferSize_, that.bufferSize_);
 
-    swap(rBase_,      that.rBase_);
-    swap(rBound_,     that.rBound_);
-    swap(wBase_,      that.wBase_);
-    swap(wBound_,     that.wBound_);
+    swap(rBase_, that.rBase_);
+    swap(rBound_, that.rBound_);
+    swap(wBase_, that.wBase_);
+    swap(wBound_, that.wBound_);
 
-    swap(owner_,      that.owner_);
+    swap(owner_, that.owner_);
   }
 
   // Make sure there's at least 'len' bytes available for writing.
@@ -723,13 +731,17 @@
   // Allocated buffer size
   uint32_t bufferSize_;
 
+  // Maximum allowed size
+  uint32_t maxBufferSize_;
+
   // Is this object the owner of the buffer?
   bool owner_;
 
   // Don't forget to update constrctors, initCommon, and swap if
   // you add new members.
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_TBUFFERTRANSPORTS_H_
diff --git a/lib/cpp/src/thrift/transport/TFDTransport.cpp b/lib/cpp/src/thrift/transport/TFDTransport.cpp
index 3b72de5..93dd100 100644
--- a/lib/cpp/src/thrift/transport/TFDTransport.cpp
+++ b/lib/cpp/src/thrift/transport/TFDTransport.cpp
@@ -31,23 +31,23 @@
 #include <io.h>
 #endif
 
-using namespace std;
+using std::string;
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 void TFDTransport::close() {
   if (!isOpen()) {
     return;
   }
 
-  int rv = ::THRIFT_CLOSESOCKET(fd_);
-  int errno_copy = THRIFT_GET_SOCKET_ERROR;
+  int rv = ::THRIFT_CLOSE(fd_);
+  int errno_copy = THRIFT_ERRNO;
   fd_ = -1;
   // Have to check uncaught_exception because this is called in the destructor.
   if (rv < 0 && !std::uncaught_exception()) {
-    throw TTransportException(TTransportException::UNKNOWN,
-                              "TFDTransport::close()",
-                              errno_copy);
+    throw TTransportException(TTransportException::UNKNOWN, "TFDTransport::close()", errno_copy);
   }
 }
 
@@ -55,43 +55,39 @@
   unsigned int maxRetries = 5; // same as the TSocket default
   unsigned int retries = 0;
   while (true) {
-    THRIFT_SSIZET rv = ::read(fd_, buf, len);
+    THRIFT_SSIZET rv = ::THRIFT_READ(fd_, buf, len);
     if (rv < 0) {
-      if (THRIFT_GET_SOCKET_ERROR == THRIFT_EINTR && retries < maxRetries) {
+      if (THRIFT_ERRNO == THRIFT_EINTR && retries < maxRetries) {
         // If interrupted, try again
         ++retries;
         continue;
       }
-      int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      throw TTransportException(TTransportException::UNKNOWN,
-                                "TFDTransport::read()",
-                                errno_copy);
+      int errno_copy = THRIFT_ERRNO;
+      throw TTransportException(TTransportException::UNKNOWN, "TFDTransport::read()", errno_copy);
     }
-    //this should be fine, since we already checked for negative values,
-    //and ::read should only return a 32-bit value since len is 32-bit.
+    // this should be fine, since we already checked for negative values,
+    // and ::read should only return a 32-bit value since len is 32-bit.
     return static_cast<uint32_t>(rv);
   }
 }
 
 void TFDTransport::write(const uint8_t* buf, uint32_t len) {
   while (len > 0) {
-    THRIFT_SSIZET rv = ::write(fd_, buf, len);
+    THRIFT_SSIZET rv = ::THRIFT_WRITE(fd_, buf, len);
 
     if (rv < 0) {
-      int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      throw TTransportException(TTransportException::UNKNOWN,
-                                "TFDTransport::write()",
-                                errno_copy);
+      int errno_copy = THRIFT_ERRNO;
+      throw TTransportException(TTransportException::UNKNOWN, "TFDTransport::write()", errno_copy);
     } else if (rv == 0) {
-      throw TTransportException(TTransportException::END_OF_FILE,
-                                "TFDTransport::write()");
+      throw TTransportException(TTransportException::END_OF_FILE, "TFDTransport::write()");
     }
 
     buf += rv;
-    //this should be fine, as we've already checked for negative values, and
+    // this should be fine, as we've already checked for negative values, and
     //::write shouldn't return more than a uint32_t since len is a uint32_t
     len -= static_cast<uint32_t>(rv);
   }
 }
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/TFDTransport.h b/lib/cpp/src/thrift/transport/TFDTransport.h
index cc4f9c1..5593d43 100644
--- a/lib/cpp/src/thrift/transport/TFDTransport.h
+++ b/lib/cpp/src/thrift/transport/TFDTransport.h
@@ -28,27 +28,28 @@
 #include <thrift/transport/TTransport.h>
 #include <thrift/transport/TVirtualTransport.h>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * Dead-simple wrapper around a file descriptor.
  *
  */
 class TFDTransport : public TVirtualTransport<TFDTransport> {
- public:
-  enum ClosePolicy
-  { NO_CLOSE_ON_DESTROY = 0
-  , CLOSE_ON_DESTROY = 1
-  };
+public:
+  enum ClosePolicy { NO_CLOSE_ON_DESTROY = 0, CLOSE_ON_DESTROY = 1 };
 
   TFDTransport(int fd, ClosePolicy close_policy = NO_CLOSE_ON_DESTROY)
-    : fd_(fd)
-    , close_policy_(close_policy)
-  {}
+    : fd_(fd), close_policy_(close_policy) {}
 
   ~TFDTransport() {
     if (close_policy_ == CLOSE_ON_DESTROY) {
-      close();
+      try {
+        close();
+      } catch (TTransportException& ex) {
+        GlobalOutput.printf("~TFDTransport TTransportException: '%s'", ex.what());
+      }
     }
   }
 
@@ -65,11 +66,12 @@
   void setFD(int fd) { fd_ = fd; }
   int getFD() { return fd_; }
 
- protected:
+protected:
   int fd_;
   ClosePolicy close_policy_;
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_TFDTRANSPORT_H_
diff --git a/lib/cpp/src/thrift/transport/TFileTransport.cpp b/lib/cpp/src/thrift/transport/TFileTransport.cpp
index c94ecd2..afb4411 100644
--- a/lib/cpp/src/thrift/transport/TFileTransport.cpp
+++ b/lib/cpp/src/thrift/transport/TFileTransport.cpp
@@ -24,6 +24,8 @@
 #include <thrift/transport/PlatformSocket.h>
 #include <thrift/concurrency/FunctionRunner.h>
 
+#include <boost/version.hpp>
+
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #else
@@ -40,6 +42,7 @@
 #include <cstring>
 #include <iostream>
 #include <limits>
+#include <memory>
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
@@ -48,44 +51,47 @@
 #include <io.h>
 #endif
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
-using boost::scoped_ptr;
-using boost::shared_ptr;
-using namespace std;
+using std::shared_ptr;
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::string;
 using namespace apache::thrift::protocol;
 using namespace apache::thrift::concurrency;
 
 TFileTransport::TFileTransport(string path, bool readOnly)
-  : readState_()
-  , readBuff_(NULL)
-  , currentEvent_(NULL)
-  , readBuffSize_(DEFAULT_READ_BUFF_SIZE)
-  , readTimeout_(NO_TAIL_READ_TIMEOUT)
-  , chunkSize_(DEFAULT_CHUNK_SIZE)
-  , eventBufferSize_(DEFAULT_EVENT_BUFFER_SIZE)
-  , flushMaxUs_(DEFAULT_FLUSH_MAX_US)
-  , flushMaxBytes_(DEFAULT_FLUSH_MAX_BYTES)
-  , maxEventSize_(DEFAULT_MAX_EVENT_SIZE)
-  , maxCorruptedEvents_(DEFAULT_MAX_CORRUPTED_EVENTS)
-  , eofSleepTime_(DEFAULT_EOF_SLEEP_TIME_US)
-  , corruptedEventSleepTime_(DEFAULT_CORRUPTED_SLEEP_TIME_US)
-  , writerThreadIOErrorSleepTime_(DEFAULT_WRITER_THREAD_SLEEP_TIME_US)
-  , dequeueBuffer_(NULL)
-  , enqueueBuffer_(NULL)
-  , notFull_(&mutex_)
-  , notEmpty_(&mutex_)
-  , closing_(false)
-  , flushed_(&mutex_)
-  , forceFlush_(false)
-  , filename_(path)
-  , fd_(0)
-  , bufferAndThreadInitialized_(false)
-  , offset_(0)
-  , lastBadChunk_(0)
-  , numCorruptedEventsInChunk_(0)
-  , readOnly_(readOnly)
-{
+  : readState_(),
+    readBuff_(NULL),
+    currentEvent_(NULL),
+    readBuffSize_(DEFAULT_READ_BUFF_SIZE),
+    readTimeout_(NO_TAIL_READ_TIMEOUT),
+    chunkSize_(DEFAULT_CHUNK_SIZE),
+    eventBufferSize_(DEFAULT_EVENT_BUFFER_SIZE),
+    flushMaxUs_(DEFAULT_FLUSH_MAX_US),
+    flushMaxBytes_(DEFAULT_FLUSH_MAX_BYTES),
+    maxEventSize_(DEFAULT_MAX_EVENT_SIZE),
+    maxCorruptedEvents_(DEFAULT_MAX_CORRUPTED_EVENTS),
+    eofSleepTime_(DEFAULT_EOF_SLEEP_TIME_US),
+    corruptedEventSleepTime_(DEFAULT_CORRUPTED_SLEEP_TIME_US),
+    writerThreadIOErrorSleepTime_(DEFAULT_WRITER_THREAD_SLEEP_TIME_US),
+    dequeueBuffer_(NULL),
+    enqueueBuffer_(NULL),
+    notFull_(&mutex_),
+    notEmpty_(&mutex_),
+    closing_(false),
+    flushed_(&mutex_),
+    forceFlush_(false),
+    filename_(path),
+    fd_(0),
+    bufferAndThreadInitialized_(false),
+    offset_(0),
+    lastBadChunk_(0),
+    numCorruptedEventsInChunk_(0),
+    readOnly_(readOnly) {
   threadFactory_.setDetached(false);
   openLogFile();
 }
@@ -99,12 +105,14 @@
     // flush any events in the queue
     flush();
     GlobalOutput.printf("error, current file (%s) not closed", filename_.c_str());
-    if (-1 == ::THRIFT_CLOSESOCKET(fd_)) {
-      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    if (-1 == ::THRIFT_CLOSE(fd_)) {
+      int errno_copy = THRIFT_ERRNO;
       GlobalOutput.perror("TFileTransport: resetOutputFile() ::close() ", errno_copy);
-      throw TTransportException(TTransportException::UNKNOWN, "TFileTransport: error in file close", errno_copy);
+      throw TTransportException(TTransportException::UNKNOWN,
+                                "TFileTransport: error in file close",
+                                errno_copy);
     } else {
-      //successfully closed fd
+      // successfully closed fd
       fd_ = 0;
     }
   }
@@ -117,10 +125,9 @@
   }
 }
 
-
 TFileTransport::~TFileTransport() {
   // flush the buffer if a writer thread is active
-  if(writerThread_.get()) {
+  if (writerThread_.get()) {
     // set state to closing
     closing_ = true;
 
@@ -154,10 +161,10 @@
 
   // close logfile
   if (fd_ > 0) {
-    if(-1 == ::THRIFT_CLOSESOCKET(fd_)) {
-      GlobalOutput.perror("TFileTransport: ~TFileTransport() ::close() ", THRIFT_GET_SOCKET_ERROR);
+    if (-1 == ::THRIFT_CLOSE(fd_)) {
+      GlobalOutput.perror("TFileTransport: ~TFileTransport() ::close() ", THRIFT_ERRNO);
     } else {
-      //successfully closed fd
+      // successfully closed fd
       fd_ = 0;
     }
   }
@@ -169,9 +176,9 @@
     return false;
   }
 
-  if(!writerThread_.get()) {
+  if (!writerThread_.get()) {
     writerThread_ = threadFactory_.newThread(
-      apache::thrift::concurrency::FunctionRunner::create(startWriterThread, this));
+        apache::thrift::concurrency::FunctionRunner::create(startWriterThread, this));
     writerThread_->start();
   }
 
@@ -190,6 +197,12 @@
   enqueueEvent(buf, len);
 }
 
+template <class _T>
+struct uniqueDeleter
+{
+  void operator()(_T *ptr) const { delete ptr; }
+};
+
 void TFileTransport::enqueueEvent(const uint8_t* buf, uint32_t eventLen) {
   // can't enqueue more events if file is going to close
   if (closing_) {
@@ -197,7 +210,7 @@
   }
 
   // make sure that event size is valid
-  if ( (maxEventSize_ > 0) && (eventLen > maxEventSize_) ) {
+  if ((maxEventSize_ > 0) && (eventLen > maxEventSize_)) {
     T_ERROR("msg size is greater than max event size: %u > %u\n", eventLen, maxEventSize_);
     return;
   }
@@ -207,12 +220,9 @@
     return;
   }
 
-  eventInfo* toEnqueue = new eventInfo();
-  toEnqueue->eventBuff_ = (uint8_t *)std::malloc((sizeof(uint8_t) * eventLen) + 4);
-  if (toEnqueue->eventBuff_ == NULL) {
-    delete toEnqueue;
-    throw std::bad_alloc();
-  }
+  std::unique_ptr<eventInfo, uniqueDeleter<eventInfo> > toEnqueue(new eventInfo());
+  toEnqueue->eventBuff_ = new uint8_t[(sizeof(uint8_t) * eventLen) + 4];
+
   // first 4 bytes is the event length
   memcpy(toEnqueue->eventBuff_, (void*)(&eventLen), 4);
   // actual event contents
@@ -225,14 +235,13 @@
   // make sure that enqueue buffer is initialized and writer thread is running
   if (!bufferAndThreadInitialized_) {
     if (!initBufferAndWriteThread()) {
-      delete toEnqueue;
       return;
     }
   }
 
   // Can't enqueue while buffer is full
   while (enqueueBuffer_->isFull()) {
-	  notFull_.wait();
+    notFull_.wait();
   }
 
   // We shouldn't be trying to enqueue new data while a forced flush is
@@ -241,8 +250,9 @@
   assert(!forceFlush_);
 
   // add to the buffer
-  if (!enqueueBuffer_->addEvent(toEnqueue)) {
-    delete toEnqueue;
+  eventInfo* pEvent = toEnqueue.release();
+  if (!enqueueBuffer_->addEvent(pEvent)) {
+    delete pEvent;
     return;
   }
 
@@ -278,29 +288,27 @@
   }
 
   if (swap) {
-    TFileTransportBuffer *temp = enqueueBuffer_;
+    TFileTransportBuffer* temp = enqueueBuffer_;
     enqueueBuffer_ = dequeueBuffer_;
     dequeueBuffer_ = temp;
   }
 
-
   if (swap) {
-	  notFull_.notify();
+    notFull_.notify();
   }
 
   return swap;
 }
 
-
 void TFileTransport::writerThread() {
   bool hasIOError = false;
 
   // open file if it is not open
-  if(!fd_) {
+  if (!fd_) {
     try {
       openLogFile();
     } catch (...) {
-      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+      int errno_copy = THRIFT_ERRNO;
       GlobalOutput.perror("TFileTransport: writerThread() openLogFile() ", errno_copy);
       fd_ = 0;
       hasIOError = true;
@@ -313,14 +321,15 @@
       seekToEnd();
       // throw away any partial events
       offset_ += readState_.lastDispatchPtr_;
-#ifndef _WIN32
-      ftruncate(fd_, offset_);
-#else
-      _chsize_s(fd_, offset_);
-#endif
-      readState_.resetAllValues();
+      if (0 == THRIFT_FTRUNCATE(fd_, offset_)) {
+        readState_.resetAllValues();
+      } else {
+        int errno_copy = THRIFT_ERRNO;
+        GlobalOutput.perror("TFileTransport: writerThread() truncate ", errno_copy);
+        hasIOError = true;
+      }
     } catch (...) {
-      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+      int errno_copy = THRIFT_ERRNO;
       GlobalOutput.perror("TFileTransport: writerThread() initialization ", errno_copy);
       hasIOError = true;
     }
@@ -340,14 +349,12 @@
 
       // Try to empty buffers before exit
       if (enqueueBuffer_->isEmpty() && dequeueBuffer_->isEmpty()) {
-#ifndef _WIN32
-        fsync(fd_);
-#endif
-        if (-1 == ::THRIFT_CLOSESOCKET(fd_)) {
-          int errno_copy = THRIFT_GET_SOCKET_ERROR;
+        ::THRIFT_FSYNC(fd_);
+        if (-1 == ::THRIFT_CLOSE(fd_)) {
+          int errno_copy = THRIFT_ERRNO;
           GlobalOutput.perror("TFileTransport: writerThread() ::close() ", errno_copy);
         } else {
-          //fd successfully closed
+          // fd successfully closed
           fd_ = 0;
         }
         return;
@@ -357,19 +364,24 @@
     if (swapEventBuffers(&ts_next_flush)) {
       eventInfo* outEvent;
       while (NULL != (outEvent = dequeueBuffer_->getNext())) {
-        // Remove an event from the buffer and write it out to disk. If there is any IO error, for instance,
-        // the output file is unmounted or deleted, then this event is dropped. However, the writer thread
-        // will: (1) sleep for a short while; (2) try to reopen the file; (3) if successful then start writing
+        // Remove an event from the buffer and write it out to disk. If there is any IO error, for
+        // instance,
+        // the output file is unmounted or deleted, then this event is dropped. However, the writer
+        // thread
+        // will: (1) sleep for a short while; (2) try to reopen the file; (3) if successful then
+        // start writing
         // from the end.
 
         while (hasIOError) {
-          T_ERROR("TFileTransport: writer thread going to sleep for %d microseconds due to IO errors", writerThreadIOErrorSleepTime_);
+          T_ERROR(
+              "TFileTransport: writer thread going to sleep for %u microseconds due to IO errors",
+              writerThreadIOErrorSleepTime_);
           THRIFT_SLEEP_USEC(writerThreadIOErrorSleepTime_);
           if (closing_) {
             return;
           }
           if (!fd_) {
-            ::THRIFT_CLOSESOCKET(fd_);
+            ::THRIFT_CLOSE(fd_);
             fd_ = 0;
           }
           try {
@@ -377,15 +389,20 @@
             seekToEnd();
             unflushed = 0;
             hasIOError = false;
-            T_LOG_OPER("TFileTransport: log file %s reopened by writer thread during error recovery", filename_.c_str());
+            T_LOG_OPER(
+                "TFileTransport: log file %s reopened by writer thread during error recovery",
+                filename_.c_str());
           } catch (...) {
-            T_ERROR("TFileTransport: unable to reopen log file %s during error recovery", filename_.c_str());
+            T_ERROR("TFileTransport: unable to reopen log file %s during error recovery",
+                    filename_.c_str());
           }
         }
 
         // sanity check on event
         if ((maxEventSize_ > 0) && (outEvent->eventSize_ > maxEventSize_)) {
-          T_ERROR("msg size is greater than max event size: %u > %u\n", outEvent->eventSize_, maxEventSize_);
+          T_ERROR("msg size is greater than max event size: %u > %u\n",
+                  outEvent->eventSize_,
+                  maxEventSize_);
           continue;
         }
 
@@ -393,25 +410,28 @@
         if ((outEvent->eventSize_ > 0) && (chunkSize_ != 0)) {
           // event size must be less than chunk size
           if (outEvent->eventSize_ > chunkSize_) {
-            T_ERROR("TFileTransport: event size(%u) > chunk size(%u): skipping event", outEvent->eventSize_, chunkSize_);
+            T_ERROR("TFileTransport: event size(%u) > chunk size(%u): skipping event",
+                    outEvent->eventSize_,
+                    chunkSize_);
             continue;
           }
 
-          int64_t chunk1 = offset_/chunkSize_;
-          int64_t chunk2 = (offset_ + outEvent->eventSize_ - 1)/chunkSize_;
+          int64_t chunk1 = offset_ / chunkSize_;
+          int64_t chunk2 = (offset_ + outEvent->eventSize_ - 1) / chunkSize_;
 
           // if adding this event will cross a chunk boundary, pad the chunk with zeros
           if (chunk1 != chunk2) {
             // refetch the offset to keep in sync
-            offset_ = lseek(fd_, 0, SEEK_CUR);
+            offset_ = THRIFT_LSEEK(fd_, 0, SEEK_CUR);
             int32_t padding = (int32_t)((offset_ / chunkSize_ + 1) * chunkSize_ - offset_);
 
             uint8_t* zeros = new uint8_t[padding];
             memset(zeros, '\0', padding);
             boost::scoped_array<uint8_t> array(zeros);
             if (-1 == ::write(fd_, zeros, padding)) {
-              int errno_copy = THRIFT_GET_SOCKET_ERROR;
-              GlobalOutput.perror("TFileTransport: writerThread() error while padding zeros ", errno_copy);
+              int errno_copy = THRIFT_ERRNO;
+              GlobalOutput.perror("TFileTransport: writerThread() error while padding zeros ",
+                                  errno_copy);
               hasIOError = true;
               continue;
             }
@@ -422,8 +442,8 @@
 
         // write the dequeued event to the file
         if (outEvent->eventSize_ > 0) {
-          if (-1 == ::write(fd_, outEvent->eventBuff_, outEvent->eventSize_)) {
-            int errno_copy = THRIFT_GET_SOCKET_ERROR;
+          if (-1 == ::THRIFT_WRITE(fd_, outEvent->eventBuff_, outEvent->eventSize_)) {
+            int errno_copy = THRIFT_ERRNO;
             GlobalOutput.perror("TFileTransport: error while writing event ", errno_copy);
             hasIOError = true;
             continue;
@@ -446,24 +466,24 @@
     // time, it could have changed state in between.  This will result in us
     // making inconsistent decisions.
     bool forced_flush = false;
-	{
-    Guard g(mutex_);
-    if (forceFlush_) {
-      if (!enqueueBuffer_->isEmpty()) {
-        // If forceFlush_ is true, we need to flush all available data.
-        // If enqueueBuffer_ is not empty, go back to the start of the loop to
-        // write it out.
-        //
-        // We know the main thread is waiting on forceFlush_ to be cleared,
-        // so no new events will be added to enqueueBuffer_ until we clear
-        // forceFlush_.  Therefore the next time around the loop enqueueBuffer_
-        // is guaranteed to be empty.  (I.e., we're guaranteed to make progress
-        // and clear forceFlush_ the next time around the loop.)
-        continue;
+    {
+      Guard g(mutex_);
+      if (forceFlush_) {
+        if (!enqueueBuffer_->isEmpty()) {
+          // If forceFlush_ is true, we need to flush all available data.
+          // If enqueueBuffer_ is not empty, go back to the start of the loop to
+          // write it out.
+          //
+          // We know the main thread is waiting on forceFlush_ to be cleared,
+          // so no new events will be added to enqueueBuffer_ until we clear
+          // forceFlush_.  Therefore the next time around the loop enqueueBuffer_
+          // is guaranteed to be empty.  (I.e., we're guaranteed to make progress
+          // and clear forceFlush_ the next time around the loop.)
+          continue;
+        }
+        forced_flush = true;
       }
-      forced_flush = true;
-	}
-	}
+    }
 
     // determine if we need to perform an fsync
     bool flush = false;
@@ -472,9 +492,9 @@
     } else {
       struct timeval current_time;
       THRIFT_GETTIMEOFDAY(&current_time, NULL);
-      if (current_time.tv_sec > ts_next_flush.tv_sec ||
-          (current_time.tv_sec == ts_next_flush.tv_sec &&
-           current_time.tv_usec > ts_next_flush.tv_usec)) {
+      if (current_time.tv_sec > ts_next_flush.tv_sec
+          || (current_time.tv_sec == ts_next_flush.tv_sec
+              && current_time.tv_usec > ts_next_flush.tv_usec)) {
         if (unflushed > 0) {
           flush = true;
         } else {
@@ -487,9 +507,7 @@
 
     if (flush) {
       // sync (force flush) file to disk
-#ifndef _WIN32
-      fsync(fd_);
-#endif
+      THRIFT_FSYNC(fd_);
       unflushed = 0;
       getNextFlushTime(&ts_next_flush);
 
@@ -499,7 +517,7 @@
         forceFlush_ = false;
         assert(enqueueBuffer_->isEmpty());
         assert(dequeueBuffer_->isEmpty());
-		flushed_.notifyAll();
+        flushed_.notifyAll();
       }
     }
   }
@@ -523,13 +541,12 @@
   }
 }
 
-
 uint32_t TFileTransport::readAll(uint8_t* buf, uint32_t len) {
   uint32_t have = 0;
   uint32_t get = 0;
 
   while (have < len) {
-    get = read(buf+have, len-have);
+    get = read(buf + have, len - have);
     if (get <= 0) {
       throw TEOFException();
     }
@@ -572,11 +589,9 @@
   if (remaining <= (int32_t)len) {
     // copy over anything thats remaining
     if (remaining > 0) {
-      memcpy(buf,
-             currentEvent_->eventBuff_ + currentEvent_->eventBuffPos_,
-             remaining);
+      memcpy(buf, currentEvent_->eventBuff_ + currentEvent_->eventBuffPos_, remaining);
     }
-    delete(currentEvent_);
+    delete (currentEvent_);
     currentEvent_ = NULL;
     return remaining;
   }
@@ -600,7 +615,7 @@
     if (readState_.bufferPtr_ == readState_.bufferLen_) {
       // advance the offset pointer
       offset_ += readState_.bufferLen_;
-      readState_.bufferLen_ = static_cast<uint32_t>(::read(fd_, readBuff_, readBuffSize_));
+      readState_.bufferLen_ = static_cast<uint32_t>(::THRIFT_READ(fd_, readBuff_, readBuffSize_));
       //       if (readState_.bufferLen_) {
       //         T_DEBUG_L(1, "Amount read: %u (offset: %lu)", readState_.bufferLen_, offset_);
       //       }
@@ -612,7 +627,7 @@
         readState_.resetAllValues();
         GlobalOutput("TFileTransport: error while reading from file");
         throw TTransportException("TFileTransport: error while reading from file");
-      } else if (readState_.bufferLen_ == 0) {  // EOF
+      } else if (readState_.bufferLen_ == 0) { // EOF
         // wait indefinitely if there is no timeout
         if (readTimeout_ == TAIL_READ_TIMEOUT) {
           THRIFT_SLEEP_USEC(eofSleepTime_);
@@ -638,11 +653,11 @@
     readTries = 0;
 
     // attempt to read an event from the buffer
-    while(readState_.bufferPtr_ < readState_.bufferLen_) {
+    while (readState_.bufferPtr_ < readState_.bufferLen_) {
       if (readState_.readingSize_) {
-        if(readState_.eventSizeBuffPos_ == 0) {
-          if ( (offset_ + readState_.bufferPtr_)/chunkSize_ !=
-               ((offset_ + readState_.bufferPtr_ + 3)/chunkSize_)) {
+        if (readState_.eventSizeBuffPos_ == 0) {
+          if ((offset_ + readState_.bufferPtr_) / chunkSize_
+              != ((offset_ + readState_.bufferPtr_ + 3) / chunkSize_)) {
             // skip one byte towards chunk boundary
             //            T_DEBUG_L(1, "Skipping a byte");
             readState_.bufferPtr_++;
@@ -650,8 +665,8 @@
           }
         }
 
-        readState_.eventSizeBuff_[readState_.eventSizeBuffPos_++] =
-          readBuff_[readState_.bufferPtr_++];
+        readState_.eventSizeBuff_[readState_.eventSizeBuffPos_++]
+            = readBuff_[readState_.bufferPtr_++];
 
         if (readState_.eventSizeBuffPos_ == 4) {
           if (readState_.getEventSize() == 0) {
@@ -663,7 +678,7 @@
           // got a valid event
           readState_.readingSize_ = false;
           if (readState_.event_) {
-            delete(readState_.event_);
+            delete (readState_.event_);
           }
           readState_.event_ = new eventInfo();
           readState_.event_->eventSize_ = readState_.getEventSize();
@@ -681,8 +696,8 @@
           readState_.event_->eventBuffPos_ = 0;
         }
         // take either the entire event or the remaining bytes in the buffer
-        int reclaimBuffer = min((uint32_t)(readState_.bufferLen_ - readState_.bufferPtr_),
-                                readState_.event_->eventSize_ - readState_.event_->eventBuffPos_);
+        int reclaimBuffer = (std::min)((uint32_t)(readState_.bufferLen_ - readState_.bufferPtr_),
+                                       readState_.event_->eventSize_ - readState_.event_->eventBuffPos_);
 
         // copy data from read buffer into event buffer
         memcpy(readState_.event_->eventBuff_ + readState_.event_->eventBuffPos_,
@@ -707,24 +722,26 @@
         }
       }
     }
-
   }
 }
 
 bool TFileTransport::isEventCorrupted() {
   // an error is triggered if:
-  if ( (maxEventSize_ > 0) &&  (readState_.event_->eventSize_ > maxEventSize_)) {
+  if ((maxEventSize_ > 0) && (readState_.event_->eventSize_ > maxEventSize_)) {
     // 1. Event size is larger than user-speficied max-event size
     T_ERROR("Read corrupt event. Event size(%u) greater than max event size (%u)",
-            readState_.event_->eventSize_, maxEventSize_);
+            readState_.event_->eventSize_,
+            maxEventSize_);
     return true;
   } else if (readState_.event_->eventSize_ > chunkSize_) {
     // 2. Event size is larger than chunk size
     T_ERROR("Read corrupt event. Event size(%u) greater than chunk size (%u)",
-               readState_.event_->eventSize_, chunkSize_);
+            readState_.event_->eventSize_,
+            chunkSize_);
     return true;
-  } else if( ((offset_ + readState_.bufferPtr_ - 4)/chunkSize_) !=
-             ((offset_ + readState_.bufferPtr_ + readState_.event_->eventSize_ - 1)/chunkSize_) ) {
+  } else if (((offset_ + readState_.bufferPtr_ - 4) / chunkSize_)
+             != ((offset_ + readState_.bufferPtr_ + readState_.event_->eventSize_ - 1)
+                 / chunkSize_)) {
     // 3. size indicates that event crosses chunk boundary
     T_ERROR("Read corrupt event. Event crosses chunk boundary. Event size:%u  Offset:%lu",
             readState_.event_->eventSize_,
@@ -758,8 +775,8 @@
     } else if (readTimeout_ == TAIL_READ_TIMEOUT) {
       // if tailing the file, wait until there is enough data to start
       // the next chunk
-      while(curChunk == (getNumChunks() - 1)) {
-        THRIFT_SLEEP_USEC(DEFAULT_CORRUPTED_SLEEP_TIME_US);
+      while (curChunk == (getNumChunks() - 1)) {
+        THRIFT_SLEEP_USEC(corruptedEventSleepTime_);
       }
       seekToChunk(curChunk + 1);
     } else {
@@ -768,14 +785,14 @@
       readState_.resetState(readState_.lastDispatchPtr_);
       currentEvent_ = NULL;
       char errorMsg[1024];
-      sprintf(errorMsg, "TFileTransport: log file corrupted at offset: %lu",
+      sprintf(errorMsg,
+              "TFileTransport: log file corrupted at offset: %lu",
               static_cast<unsigned long>(offset_ + readState_.lastDispatchPtr_));
 
       GlobalOutput(errorMsg);
       throw TTransportException(errorMsg);
     }
   }
-
 }
 
 void TFileTransport::seekToChunk(int32_t chunk) {
@@ -809,11 +826,11 @@
     seekToEnd = true;
     chunk = numChunks - 1;
     // this is the min offset to process events till
-    minEndOffset = lseek(fd_, 0, SEEK_END);
+    minEndOffset = ::THRIFT_LSEEK(fd_, 0, SEEK_END);
   }
 
   off_t newOffset = off_t(chunk) * chunkSize_;
-  offset_ = lseek(fd_, newOffset, SEEK_SET);
+  offset_ = ::THRIFT_LSEEK(fd_, newOffset, SEEK_SET);
   readState_.resetAllValues();
   currentEvent_ = NULL;
   if (offset_ == -1) {
@@ -826,7 +843,7 @@
     uint32_t oldReadTimeout = getReadTimeout();
     setReadTimeout(NO_TAIL_READ_TIMEOUT);
     // keep on reading unti the last event at point of seekChunk call
-    boost::scoped_ptr<eventInfo> event;
+    shared_ptr<eventInfo> event;
     while ((offset_ + readState_.bufferPtr_) < minEndOffset) {
       event.reset(readEvent());
       if (event.get() == NULL) {
@@ -835,7 +852,6 @@
     }
     setReadTimeout(oldReadTimeout);
   }
-
 }
 
 void TFileTransport::seekToEnd() {
@@ -847,18 +863,18 @@
     return 0;
   }
 
-  struct stat f_info;
-  int rv = fstat(fd_, &f_info);
+  struct THRIFT_STAT f_info;
+  int rv = ::THRIFT_FSTAT(fd_, &f_info);
 
   if (rv < 0) {
-    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    int errno_copy = THRIFT_ERRNO;
     throw TTransportException(TTransportException::UNKNOWN,
                               "TFileTransport::getNumChunks() (fstat)",
                               errno_copy);
   }
 
   if (f_info.st_size > 0) {
-    size_t numChunks = ((f_info.st_size)/chunkSize_) + 1;
+    size_t numChunks = ((f_info.st_size) / chunkSize_) + 1;
     if (numChunks > (std::numeric_limits<uint32_t>::max)())
       throw TTransportException("Too many chunks");
     return static_cast<uint32_t>(numChunks);
@@ -869,29 +885,27 @@
 }
 
 uint32_t TFileTransport::getCurChunk() {
-  return static_cast<uint32_t>(offset_/chunkSize_);
+  return static_cast<uint32_t>(offset_ / chunkSize_);
 }
 
 // Utility Functions
 void TFileTransport::openLogFile() {
 #ifndef _WIN32
-  mode_t mode = readOnly_ ? S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR| S_IRGRP | S_IROTH;
+  mode_t mode = readOnly_ ? S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
   int flags = readOnly_ ? O_RDONLY : O_RDWR | O_CREAT | O_APPEND;
-  fd_ = ::open(filename_.c_str(), flags, mode);
 #else
   int mode = readOnly_ ? _S_IREAD : _S_IREAD | _S_IWRITE;
   int flags = readOnly_ ? _O_RDONLY : _O_RDWR | _O_CREAT | _O_APPEND;
-  fd_ = ::_open(filename_.c_str(), flags, mode);
 #endif
+  fd_ = ::THRIFT_OPEN(filename_.c_str(), flags, mode);
   offset_ = 0;
 
   // make sure open call was successful
-  if(fd_ == -1) {
-    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+  if (fd_ == -1) {
+    int errno_copy = THRIFT_ERRNO;
     GlobalOutput.perror("TFileTransport: openLogFile() ::open() file: " + filename_, errno_copy);
     throw TTransportException(TTransportException::NOT_OPEN, filename_, errno_copy);
   }
-
 }
 
 void TFileTransport::getNextFlushTime(struct timeval* ts_next_flush) {
@@ -906,12 +920,8 @@
 }
 
 TFileTransportBuffer::TFileTransportBuffer(uint32_t size)
-  : bufferMode_(WRITE)
-  , writePoint_(0)
-  , readPoint_(0)
-  , size_(size)
-{
-  buffer_ = new eventInfo*[size];
+  : bufferMode_(WRITE), writePoint_(0), readPoint_(0), size_(size) {
+  buffer_ = new eventInfo* [size];
 }
 
 TFileTransportBuffer::~TFileTransportBuffer() {
@@ -924,7 +934,7 @@
   }
 }
 
-bool TFileTransportBuffer::addEvent(eventInfo *event) {
+bool TFileTransportBuffer::addEvent(eventInfo* event) {
   if (bufferMode_ == READ) {
     GlobalOutput("Trying to write to a buffer in read mode");
   }
@@ -972,11 +982,11 @@
 
 TFileProcessor::TFileProcessor(shared_ptr<TProcessor> processor,
                                shared_ptr<TProtocolFactory> protocolFactory,
-                               shared_ptr<TFileReaderTransport> inputTransport):
-  processor_(processor),
-  inputProtocolFactory_(protocolFactory),
-  outputProtocolFactory_(protocolFactory),
-  inputTransport_(inputTransport) {
+                               shared_ptr<TFileReaderTransport> inputTransport)
+  : processor_(processor),
+    inputProtocolFactory_(protocolFactory),
+    outputProtocolFactory_(protocolFactory),
+    inputTransport_(inputTransport) {
 
   // default the output transport to a null transport (common case)
   outputTransport_ = shared_ptr<TNullTransport>(new TNullTransport());
@@ -985,11 +995,11 @@
 TFileProcessor::TFileProcessor(shared_ptr<TProcessor> processor,
                                shared_ptr<TProtocolFactory> inputProtocolFactory,
                                shared_ptr<TProtocolFactory> outputProtocolFactory,
-                               shared_ptr<TFileReaderTransport> inputTransport):
-  processor_(processor),
-  inputProtocolFactory_(inputProtocolFactory),
-  outputProtocolFactory_(outputProtocolFactory),
-  inputTransport_(inputTransport) {
+                               shared_ptr<TFileReaderTransport> inputTransport)
+  : processor_(processor),
+    inputProtocolFactory_(inputProtocolFactory),
+    outputProtocolFactory_(outputProtocolFactory),
+    inputTransport_(inputTransport) {
 
   // default the output transport to a null transport (common case)
   outputTransport_ = shared_ptr<TNullTransport>(new TNullTransport());
@@ -998,12 +1008,13 @@
 TFileProcessor::TFileProcessor(shared_ptr<TProcessor> processor,
                                shared_ptr<TProtocolFactory> protocolFactory,
                                shared_ptr<TFileReaderTransport> inputTransport,
-                               shared_ptr<TTransport> outputTransport):
-  processor_(processor),
-  inputProtocolFactory_(protocolFactory),
-  outputProtocolFactory_(protocolFactory),
-  inputTransport_(inputTransport),
-  outputTransport_(outputTransport) {}
+                               shared_ptr<TTransport> outputTransport)
+  : processor_(processor),
+    inputProtocolFactory_(protocolFactory),
+    outputProtocolFactory_(protocolFactory),
+    inputTransport_(inputTransport),
+    outputTransport_(outputTransport) {
+}
 
 void TFileProcessor::process(uint32_t numEvents, bool tail) {
   shared_ptr<TProtocol> inputProtocol = inputProtocolFactory_->getProtocol(inputTransport_);
@@ -1017,20 +1028,20 @@
   }
 
   uint32_t numProcessed = 0;
-  while(1) {
+  while (1) {
     // bad form to use exceptions for flow control but there is really
     // no other way around it
     try {
       processor_->process(inputProtocol, outputProtocol, NULL);
       numProcessed++;
-      if ( (numEvents > 0) && (numProcessed == numEvents)) {
+      if ((numEvents > 0) && (numProcessed == numEvents)) {
         return;
       }
     } catch (TEOFException&) {
       if (!tail) {
         break;
       }
-    } catch (TException &te) {
+    } catch (TException& te) {
       cerr << te.what() << endl;
       break;
     }
@@ -1040,7 +1051,6 @@
   if (tail) {
     inputTransport_->setReadTimeout(oldReadTimeout);
   }
-
 }
 
 void TFileProcessor::processChunk() {
@@ -1049,7 +1059,7 @@
 
   uint32_t curChunk = inputTransport_->getCurChunk();
 
-  while(1) {
+  while (1) {
     // bad form to use exceptions for flow control but there is really
     // no other way around it
     try {
@@ -1059,11 +1069,12 @@
       }
     } catch (TEOFException&) {
       break;
-    } catch (TException &te) {
+    } catch (TException& te) {
       cerr << te.what() << endl;
       break;
     }
   }
 }
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/TFileTransport.h b/lib/cpp/src/thrift/transport/TFileTransport.h
index 75941cf..6cc7bd2 100644
--- a/lib/cpp/src/thrift/transport/TFileTransport.h
+++ b/lib/cpp/src/thrift/transport/TFileTransport.h
@@ -24,18 +24,18 @@
 #include <thrift/Thrift.h>
 #include <thrift/TProcessor.h>
 
+#include <atomic>
 #include <string>
 #include <stdio.h>
 
-#include <boost/scoped_ptr.hpp>
-#include <boost/shared_ptr.hpp>
-
 #include <thrift/concurrency/Mutex.h>
 #include <thrift/concurrency/Monitor.h>
 #include <thrift/concurrency/PlatformThreadFactory.h>
 #include <thrift/concurrency/Thread.h>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 using apache::thrift::TProcessor;
 using apache::thrift::protocol::TProtocolFactory;
@@ -48,7 +48,7 @@
   uint32_t eventSize_;
   uint32_t eventBuffPos_;
 
-  eventInfo():eventBuff_(NULL), eventSize_(0), eventBuffPos_(0){};
+  eventInfo() : eventBuff_(NULL), eventSize_(0), eventBuffPos_(0){};
   ~eventInfo() {
     if (eventBuff_) {
       delete[] eventBuff_;
@@ -61,13 +61,13 @@
   eventInfo* event_;
 
   // keep track of event size
-  uint8_t   eventSizeBuff_[4];
-  uint8_t   eventSizeBuffPos_;
-  bool      readingSize_;
+  uint8_t eventSizeBuff_[4];
+  uint8_t eventSizeBuffPos_;
+  bool readingSize_;
 
   // read buffer variables
-  int32_t  bufferPtr_;
-  int32_t  bufferLen_;
+  int32_t bufferPtr_;
+  int32_t bufferLen_;
 
   // last successful dispatch point
   int32_t lastDispatchPtr_;
@@ -83,24 +83,24 @@
     bufferPtr_ = 0;
     bufferLen_ = 0;
     if (event_) {
-      delete(event_);
+      delete (event_);
     }
     event_ = 0;
   }
 
   inline uint32_t getEventSize() {
-  	  const void *buffer=reinterpret_cast<const void *>(eventSizeBuff_);
-	  return *reinterpret_cast<const uint32_t *>(buffer);
+    const void* buffer = reinterpret_cast<const void*>(eventSizeBuff_);
+    return *reinterpret_cast<const uint32_t*>(buffer);
   }
 
   readState() {
     event_ = 0;
-   resetAllValues();
+    resetAllValues();
   }
 
   ~readState() {
     if (event_) {
-      delete(event_);
+      delete (event_);
     }
   }
 
@@ -121,36 +121,33 @@
  *
  */
 class TFileTransportBuffer {
-  public:
-    TFileTransportBuffer(uint32_t size);
-    ~TFileTransportBuffer();
+public:
+  TFileTransportBuffer(uint32_t size);
+  ~TFileTransportBuffer();
 
-    bool addEvent(eventInfo *event);
-    eventInfo* getNext();
-    void reset();
-    bool isFull();
-    bool isEmpty();
+  bool addEvent(eventInfo* event);
+  eventInfo* getNext();
+  void reset();
+  bool isFull();
+  bool isEmpty();
 
-  private:
-    TFileTransportBuffer(); // should not be used
+private:
+  TFileTransportBuffer(); // should not be used
 
-    enum mode {
-      WRITE,
-      READ
-    };
-    mode bufferMode_;
+  enum mode { WRITE, READ };
+  mode bufferMode_;
 
-    uint32_t writePoint_;
-    uint32_t readPoint_;
-    uint32_t size_;
-    eventInfo** buffer_;
+  uint32_t writePoint_;
+  uint32_t readPoint_;
+  uint32_t size_;
+  eventInfo** buffer_;
 };
 
 /**
  * Abstract interface for transports used to read files
  */
 class TFileReaderTransport : virtual public TTransport {
- public:
+public:
   virtual int32_t getReadTimeout() = 0;
   virtual void setReadTimeout(int32_t readTimeout) = 0;
 
@@ -164,7 +161,7 @@
  * Abstract interface for transports used to write files
  */
 class TFileWriterTransport : virtual public TTransport {
- public:
+public:
   virtual uint32_t getChunkSize() = 0;
   virtual void setChunkSize(uint32_t chunkSize) = 0;
 };
@@ -174,17 +171,14 @@
  * file on disk.
  *
  */
-class TFileTransport : public TFileReaderTransport,
-                       public TFileWriterTransport {
- public:
-  TFileTransport(std::string path, bool readOnly=false);
+class TFileTransport : public TFileReaderTransport, public TFileWriterTransport {
+public:
+  TFileTransport(std::string path, bool readOnly = false);
   ~TFileTransport();
 
   // TODO: what is the correct behaviour for this?
   // the log file is generally always open
-  bool isOpen() {
-    return true;
-  }
+  bool isOpen() { return true; }
 
   void write(const uint8_t* buf, uint32_t len);
   void flush();
@@ -208,27 +202,19 @@
       readBuffSize_ = readBuffSize;
     }
   }
-  uint32_t getReadBuffSize() {
-    return readBuffSize_;
-  }
+  uint32_t getReadBuffSize() { return readBuffSize_; }
 
   static const int32_t TAIL_READ_TIMEOUT = -1;
   static const int32_t NO_TAIL_READ_TIMEOUT = 0;
-  void setReadTimeout(int32_t readTimeout) {
-    readTimeout_ = readTimeout;
-  }
-  int32_t getReadTimeout() {
-    return readTimeout_;
-  }
+  void setReadTimeout(int32_t readTimeout) { readTimeout_ = readTimeout; }
+  int32_t getReadTimeout() { return readTimeout_; }
 
   void setChunkSize(uint32_t chunkSize) {
     if (chunkSize) {
       chunkSize_ = chunkSize;
     }
   }
-  uint32_t getChunkSize() {
-    return chunkSize_;
-  }
+  uint32_t getChunkSize() { return chunkSize_; }
 
   void setEventBufferSize(uint32_t bufferSize) {
     if (bufferAndThreadInitialized_) {
@@ -238,67 +224,47 @@
     eventBufferSize_ = bufferSize;
   }
 
-  uint32_t getEventBufferSize() {
-    return eventBufferSize_;
-  }
+  uint32_t getEventBufferSize() { return eventBufferSize_; }
 
   void setFlushMaxUs(uint32_t flushMaxUs) {
     if (flushMaxUs) {
       flushMaxUs_ = flushMaxUs;
     }
   }
-  uint32_t getFlushMaxUs() {
-    return flushMaxUs_;
-  }
+  uint32_t getFlushMaxUs() { return flushMaxUs_; }
 
   void setFlushMaxBytes(uint32_t flushMaxBytes) {
     if (flushMaxBytes) {
       flushMaxBytes_ = flushMaxBytes;
     }
   }
-  uint32_t getFlushMaxBytes() {
-    return flushMaxBytes_;
-  }
+  uint32_t getFlushMaxBytes() { return flushMaxBytes_; }
 
-  void setMaxEventSize(uint32_t maxEventSize) {
-    maxEventSize_ = maxEventSize;
-  }
-  uint32_t getMaxEventSize() {
-    return maxEventSize_;
-  }
+  void setMaxEventSize(uint32_t maxEventSize) { maxEventSize_ = maxEventSize; }
+  uint32_t getMaxEventSize() { return maxEventSize_; }
 
   void setMaxCorruptedEvents(uint32_t maxCorruptedEvents) {
     maxCorruptedEvents_ = maxCorruptedEvents;
   }
-  uint32_t getMaxCorruptedEvents() {
-    return maxCorruptedEvents_;
-  }
+  uint32_t getMaxCorruptedEvents() { return maxCorruptedEvents_; }
 
   void setEofSleepTimeUs(uint32_t eofSleepTime) {
     if (eofSleepTime) {
       eofSleepTime_ = eofSleepTime;
     }
   }
-  uint32_t getEofSleepTimeUs() {
-    return eofSleepTime_;
-  }
+  uint32_t getEofSleepTimeUs() { return eofSleepTime_; }
 
   /*
    * Override TTransport *_virt() functions to invoke our implementations.
    * We cannot use TVirtualTransport to provide these, since we need to inherit
    * virtually from TTransport.
    */
-  virtual uint32_t read_virt(uint8_t* buf, uint32_t len) {
-    return this->read(buf, len);
-  }
-  virtual uint32_t readAll_virt(uint8_t* buf, uint32_t len) {
-    return this->readAll(buf, len);
-  }
-  virtual void write_virt(const uint8_t* buf, uint32_t len) {
-    this->write(buf, len);
-  }
+  virtual uint32_t read_virt(uint8_t* buf, uint32_t len) { return this->read(buf, len); }
+  virtual uint32_t readAll_virt(uint8_t* buf, uint32_t len) { return this->readAll(buf, len); }
+  virtual void write_virt(const uint8_t* buf, uint32_t len) { this->write(buf, len); }
 
- private:
+private:
   // helper functions for writing to a file
   void enqueueEvent(const uint8_t* buf, uint32_t eventLen);
   bool swapEventBuffers(struct timeval* deadline);
@@ -371,20 +337,20 @@
 
   // writer thread
   apache::thrift::concurrency::PlatformThreadFactory threadFactory_;
-  boost::shared_ptr<apache::thrift::concurrency::Thread> writerThread_;
+  std::shared_ptr<apache::thrift::concurrency::Thread> writerThread_;
 
   // buffers to hold data before it is flushed. Each element of the buffer stores a msg that
   // needs to be written to the file.  The buffers are swapped by the writer thread.
-  TFileTransportBuffer *dequeueBuffer_;
-  TFileTransportBuffer *enqueueBuffer_;
+  TFileTransportBuffer* dequeueBuffer_;
+  TFileTransportBuffer* enqueueBuffer_;
 
   // conditions used to block when the buffer is full or empty
   Monitor notFull_, notEmpty_;
-  volatile bool closing_;
+  std::atomic<bool> closing_;
 
   // To keep track of whether the buffer has been flushed
   Monitor flushed_;
-  volatile bool forceFlush_;
+  std::atomic<bool> forceFlush_;
 
   // Mutex that is grabbed when enqueueing and swapping the read/write buffers
   Mutex mutex_;
@@ -408,15 +374,13 @@
 
 // Exception thrown when EOF is hit
 class TEOFException : public TTransportException {
- public:
-  TEOFException():
-    TTransportException(TTransportException::END_OF_FILE) {};
+public:
+  TEOFException() : TTransportException(TTransportException::END_OF_FILE){};
 };
 
-
 // wrapper class to process events from a file containing thrift events
 class TFileProcessor {
- public:
+public:
   /**
    * Constructor that defaults output transport to null transport
    *
@@ -424,14 +388,14 @@
    * @param protocolFactory protocol factory
    * @param inputTransport file transport
    */
-  TFileProcessor(boost::shared_ptr<TProcessor> processor,
-                 boost::shared_ptr<TProtocolFactory> protocolFactory,
-                 boost::shared_ptr<TFileReaderTransport> inputTransport);
+  TFileProcessor(std::shared_ptr<TProcessor> processor,
+                 std::shared_ptr<TProtocolFactory> protocolFactory,
+                 std::shared_ptr<TFileReaderTransport> inputTransport);
 
-  TFileProcessor(boost::shared_ptr<TProcessor> processor,
-                 boost::shared_ptr<TProtocolFactory> inputProtocolFactory,
-                 boost::shared_ptr<TProtocolFactory> outputProtocolFactory,
-                 boost::shared_ptr<TFileReaderTransport> inputTransport);
+  TFileProcessor(std::shared_ptr<TProcessor> processor,
+                 std::shared_ptr<TProtocolFactory> inputProtocolFactory,
+                 std::shared_ptr<TProtocolFactory> outputProtocolFactory,
+                 std::shared_ptr<TFileReaderTransport> inputTransport);
 
   /**
    * Constructor
@@ -441,10 +405,10 @@
    * @param inputTransport input file transport
    * @param output output transport
    */
-  TFileProcessor(boost::shared_ptr<TProcessor> processor,
-                 boost::shared_ptr<TProtocolFactory> protocolFactory,
-                 boost::shared_ptr<TFileReaderTransport> inputTransport,
-                 boost::shared_ptr<TTransport> outputTransport);
+  TFileProcessor(std::shared_ptr<TProcessor> processor,
+                 std::shared_ptr<TProtocolFactory> protocolFactory,
+                 std::shared_ptr<TFileReaderTransport> inputTransport,
+                 std::shared_ptr<TTransport> outputTransport);
 
   /**
    * processes events from the file
@@ -460,15 +424,16 @@
    */
   void processChunk();
 
- private:
-  boost::shared_ptr<TProcessor> processor_;
-  boost::shared_ptr<TProtocolFactory> inputProtocolFactory_;
-  boost::shared_ptr<TProtocolFactory> outputProtocolFactory_;
-  boost::shared_ptr<TFileReaderTransport> inputTransport_;
-  boost::shared_ptr<TTransport> outputTransport_;
+private:
+  std::shared_ptr<TProcessor> processor_;
+  std::shared_ptr<TProtocolFactory> inputProtocolFactory_;
+  std::shared_ptr<TProtocolFactory> outputProtocolFactory_;
+  std::shared_ptr<TFileReaderTransport> inputTransport_;
+  std::shared_ptr<TTransport> outputTransport_;
 };
-
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // _THRIFT_TRANSPORT_TFILETRANSPORT_H_
+
diff --git a/lib/cpp/src/thrift/transport/THeaderTransport.cpp b/lib/cpp/src/thrift/transport/THeaderTransport.cpp
new file mode 100644
index 0000000..25084ec
--- /dev/null
+++ b/lib/cpp/src/thrift/transport/THeaderTransport.cpp
@@ -0,0 +1,611 @@
+/*
+ * 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.
+ */
+
+#include <thrift/transport/THeaderTransport.h>
+#include <thrift/TApplicationException.h>
+#include <thrift/protocol/TProtocolTypes.h>
+#include <thrift/protocol/TBinaryProtocol.h>
+#include <thrift/protocol/TCompactProtocol.h>
+
+#include <limits>
+#include <utility>
+#include <string>
+#include <string.h>
+#include <zlib.h>
+
+using std::map;
+using std::string;
+using std::vector;
+
+namespace apache {
+namespace thrift {
+
+using std::shared_ptr;
+
+namespace transport {
+
+using namespace apache::thrift::protocol;
+using apache::thrift::protocol::TBinaryProtocol;
+
+uint32_t THeaderTransport::readSlow(uint8_t* buf, uint32_t len) {
+  if (clientType == THRIFT_UNFRAMED_BINARY || clientType == THRIFT_UNFRAMED_COMPACT) {
+    return transport_->read(buf, len);
+  }
+
+  return TFramedTransport::readSlow(buf, len);
+}
+
+uint16_t THeaderTransport::getProtocolId() const {
+  if (clientType == THRIFT_HEADER_CLIENT_TYPE) {
+    return protoId;
+  } else if (clientType == THRIFT_UNFRAMED_COMPACT || clientType == THRIFT_FRAMED_COMPACT) {
+    return T_COMPACT_PROTOCOL;
+  } else {
+    return T_BINARY_PROTOCOL; // Assume other transports use TBinary
+  }
+}
+
+void THeaderTransport::ensureReadBuffer(uint32_t sz) {
+  if (sz > rBufSize_) {
+    rBuf_.reset(new uint8_t[sz]);
+    rBufSize_ = sz;
+  }
+}
+
+bool THeaderTransport::readFrame() {
+  // szN is network byte order of sz
+  uint32_t szN;
+  uint32_t sz;
+
+  // Read the size of the next frame.
+  // We can't use readAll(&sz, sizeof(sz)), since that always throws an
+  // exception on EOF.  We want to throw an exception only if EOF occurs after
+  // partial size data.
+  uint32_t sizeBytesRead = 0;
+  while (sizeBytesRead < sizeof(szN)) {
+    uint8_t* szp = reinterpret_cast<uint8_t*>(&szN) + sizeBytesRead;
+    uint32_t bytesRead = transport_->read(szp, sizeof(szN) - sizeBytesRead);
+    if (bytesRead == 0) {
+      if (sizeBytesRead == 0) {
+        // EOF before any data was read.
+        return false;
+      } else {
+        // EOF after a partial frame header.  Raise an exception.
+        throw TTransportException(TTransportException::END_OF_FILE,
+                                  "No more data to read after "
+                                  "partial frame header.");
+      }
+    }
+    sizeBytesRead += bytesRead;
+  }
+
+  sz = ntohl(szN);
+
+  ensureReadBuffer(4);
+
+  if ((sz & TBinaryProtocol::VERSION_MASK) == (uint32_t)TBinaryProtocol::VERSION_1) {
+    // unframed
+    clientType = THRIFT_UNFRAMED_BINARY;
+    memcpy(rBuf_.get(), &szN, sizeof(szN));
+    setReadBuffer(rBuf_.get(), 4);
+  } else if (static_cast<int8_t>(sz >> 24) == TCompactProtocol::PROTOCOL_ID
+             && (static_cast<int8_t>(sz >> 16) & TCompactProtocol::VERSION_MASK)
+                    == TCompactProtocol::VERSION_N) {
+    clientType = THRIFT_UNFRAMED_COMPACT;
+    memcpy(rBuf_.get(), &szN, sizeof(szN));
+    setReadBuffer(rBuf_.get(), 4);
+  } else {
+    // Could be header format or framed. Check next uint32
+    uint32_t magic_n;
+    uint32_t magic;
+
+    if (sz > MAX_FRAME_SIZE) {
+      throw TTransportException(TTransportException::CORRUPTED_DATA,
+                                "Header transport frame is too large");
+    }
+
+    ensureReadBuffer(sz);
+
+    // We can use readAll here, because it would be an invalid frame otherwise
+    transport_->readAll(reinterpret_cast<uint8_t*>(&magic_n), sizeof(magic_n));
+    memcpy(rBuf_.get(), &magic_n, sizeof(magic_n));
+    magic = ntohl(magic_n);
+
+    if ((magic & TBinaryProtocol::VERSION_MASK) == (uint32_t)TBinaryProtocol::VERSION_1) {
+      // framed
+      clientType = THRIFT_FRAMED_BINARY;
+      transport_->readAll(rBuf_.get() + 4, sz - 4);
+      setReadBuffer(rBuf_.get(), sz);
+    } else if (static_cast<int8_t>(magic >> 24) == TCompactProtocol::PROTOCOL_ID
+               && (static_cast<int8_t>(magic >> 16) & TCompactProtocol::VERSION_MASK)
+                      == TCompactProtocol::VERSION_N) {
+      clientType = THRIFT_FRAMED_COMPACT;
+      transport_->readAll(rBuf_.get() + 4, sz - 4);
+      setReadBuffer(rBuf_.get(), sz);
+    } else if (HEADER_MAGIC == (magic & HEADER_MASK)) {
+      if (sz < 10) {
+        throw TTransportException(TTransportException::CORRUPTED_DATA,
+                                  "Header transport frame is too small");
+      }
+
+      transport_->readAll(rBuf_.get() + 4, sz - 4);
+
+      // header format
+      clientType = THRIFT_HEADER_CLIENT_TYPE;
+      // flags
+      flags = magic & FLAGS_MASK;
+      // seqId
+      uint32_t seqId_n;
+      memcpy(&seqId_n, rBuf_.get() + 4, sizeof(seqId_n));
+      seqId = ntohl(seqId_n);
+      // header size
+      uint16_t headerSize_n;
+      memcpy(&headerSize_n, rBuf_.get() + 8, sizeof(headerSize_n));
+      uint16_t headerSize = ntohs(headerSize_n);
+      setReadBuffer(rBuf_.get(), sz);
+      readHeaderFormat(headerSize, sz);
+    } else {
+      clientType = THRIFT_UNKNOWN_CLIENT_TYPE;
+      throw TTransportException(TTransportException::BAD_ARGS,
+                                "Could not detect client transport type");
+    }
+  }
+
+  return true;
+}
+
+/**
+ * Reads a string from ptr, taking care not to reach headerBoundary
+ * Advances ptr on success
+ *
+ * @param   str             output string
+ * @throws  CORRUPTED_DATA  if size of string exceeds boundary
+ */
+void THeaderTransport::readString(uint8_t*& ptr,
+                                  /* out */ string& str,
+                                  uint8_t const* headerBoundary) {
+  int32_t strLen;
+
+  uint32_t bytes = readVarint32(ptr, &strLen, headerBoundary);
+  if (strLen > headerBoundary - ptr) {
+    throw TTransportException(TTransportException::CORRUPTED_DATA,
+                              "Info header length exceeds header size");
+  }
+  ptr += bytes;
+  str.assign(reinterpret_cast<const char*>(ptr), strLen);
+  ptr += strLen;
+}
+
+void THeaderTransport::readHeaderFormat(uint16_t headerSize, uint32_t sz) {
+  readTrans_.clear();   // Clear out any previous transforms.
+  readHeaders_.clear(); // Clear out any previous headers.
+
+  // skip over already processed magic(4), seqId(4), headerSize(2)
+  uint8_t* ptr = reinterpret_cast<uint8_t*>(rBuf_.get() + 10);
+
+  // Catch integer overflow, check for reasonable header size
+  if (headerSize >= 16384) {
+    throw TTransportException(TTransportException::CORRUPTED_DATA,
+                              "Header size is unreasonable");
+  }
+  headerSize *= 4;
+  const uint8_t* const headerBoundary = ptr + headerSize;
+  if (headerSize > sz) {
+    throw TTransportException(TTransportException::CORRUPTED_DATA,
+                              "Header size is larger than frame");
+  }
+  uint8_t* data = ptr + headerSize;
+  ptr += readVarint16(ptr, &protoId, headerBoundary);
+  int16_t numTransforms;
+  ptr += readVarint16(ptr, &numTransforms, headerBoundary);
+
+  // For now all transforms consist of only the ID, not data.
+  for (int i = 0; i < numTransforms; i++) {
+    int32_t transId;
+    ptr += readVarint32(ptr, &transId, headerBoundary);
+
+    readTrans_.push_back(transId);
+  }
+
+  // Info headers
+  while (ptr < headerBoundary) {
+    int32_t infoId;
+    ptr += readVarint32(ptr, &infoId, headerBoundary);
+
+    if (infoId == 0) {
+      // header padding
+      break;
+    }
+    if (infoId >= infoIdType::END) {
+      // cannot handle infoId
+      break;
+    }
+    switch (infoId) {
+    case infoIdType::KEYVALUE:
+      // Process key-value headers
+      uint32_t numKVHeaders;
+      ptr += readVarint32(ptr, (int32_t*)&numKVHeaders, headerBoundary);
+      // continue until we reach (padded) end of packet
+      while (numKVHeaders-- && ptr < headerBoundary) {
+        // format: key; value
+        // both: length (varint32); value (string)
+        string key, value;
+        readString(ptr, key, headerBoundary);
+        // value
+        readString(ptr, value, headerBoundary);
+        // save to headers
+        readHeaders_[key] = value;
+      }
+      break;
+    }
+  }
+
+  // Untransform the data section.  rBuf will contain result.
+  untransform(data, safe_numeric_cast<uint32_t>(static_cast<ptrdiff_t>(sz) - (data - rBuf_.get())));
+}
+
+void THeaderTransport::untransform(uint8_t* ptr, uint32_t sz) {
+  // Update the transform buffer size if needed
+  resizeTransformBuffer();
+
+  for (vector<uint16_t>::const_iterator it = readTrans_.begin(); it != readTrans_.end(); ++it) {
+    const uint16_t transId = *it;
+
+    if (transId == ZLIB_TRANSFORM) {
+      z_stream stream;
+      int err;
+
+      stream.next_in = ptr;
+      stream.avail_in = sz;
+
+      // Setting these to 0 means use the default free/alloc functions
+      stream.zalloc = (alloc_func)0;
+      stream.zfree = (free_func)0;
+      stream.opaque = (voidpf)0;
+      err = inflateInit(&stream);
+      if (err != Z_OK) {
+        throw TApplicationException(TApplicationException::MISSING_RESULT,
+                                    "Error while zlib deflateInit");
+      }
+      stream.next_out = tBuf_.get();
+      stream.avail_out = tBufSize_;
+      err = inflate(&stream, Z_FINISH);
+      if (err != Z_STREAM_END || stream.avail_out == 0) {
+        throw TApplicationException(TApplicationException::MISSING_RESULT,
+                                    "Error while zlib deflate");
+      }
+      sz = stream.total_out;
+
+      err = inflateEnd(&stream);
+      if (err != Z_OK) {
+        throw TApplicationException(TApplicationException::MISSING_RESULT,
+                                    "Error while zlib deflateEnd");
+      }
+
+      memcpy(ptr, tBuf_.get(), sz);
+    } else {
+      throw TApplicationException(TApplicationException::MISSING_RESULT, "Unknown transform");
+    }
+  }
+
+  setReadBuffer(ptr, sz);
+}
+
+/**
+ * We may have updated the wBuf size, update the tBuf size to match.
+ * Should be called in transform.
+ *
+ * The buffer should be slightly larger than write buffer size due to
+ * compression transforms (that may slightly grow on small frame sizes)
+ */
+void THeaderTransport::resizeTransformBuffer(uint32_t additionalSize) {
+  if (tBufSize_ < wBufSize_ + DEFAULT_BUFFER_SIZE) {
+    uint32_t new_size = wBufSize_ + DEFAULT_BUFFER_SIZE + additionalSize;
+    uint8_t* new_buf = new uint8_t[new_size];
+    tBuf_.reset(new_buf);
+    tBufSize_ = new_size;
+  }
+}
+
+void THeaderTransport::transform(uint8_t* ptr, uint32_t sz) {
+  // Update the transform buffer size if needed
+  resizeTransformBuffer();
+
+  for (vector<uint16_t>::const_iterator it = writeTrans_.begin(); it != writeTrans_.end(); ++it) {
+    const uint16_t transId = *it;
+
+    if (transId == ZLIB_TRANSFORM) {
+      z_stream stream;
+      int err;
+
+      stream.next_in = ptr;
+      stream.avail_in = sz;
+
+      stream.zalloc = (alloc_func)0;
+      stream.zfree = (free_func)0;
+      stream.opaque = (voidpf)0;
+      err = deflateInit(&stream, Z_DEFAULT_COMPRESSION);
+      if (err != Z_OK) {
+        throw TTransportException(TTransportException::CORRUPTED_DATA,
+                                  "Error while zlib deflateInit");
+      }
+      uint32_t tbuf_size = 0;
+      while (err == Z_OK) {
+        resizeTransformBuffer(tbuf_size);
+
+        stream.next_out = tBuf_.get();
+        stream.avail_out = tBufSize_;
+        err = deflate(&stream, Z_FINISH);
+        tbuf_size += DEFAULT_BUFFER_SIZE;
+      }
+      sz = stream.total_out;
+
+      err = deflateEnd(&stream);
+      if (err != Z_OK) {
+        throw TTransportException(TTransportException::CORRUPTED_DATA,
+                                  "Error while zlib deflateEnd");
+      }
+
+      memcpy(ptr, tBuf_.get(), sz);
+    } else {
+      throw TTransportException(TTransportException::CORRUPTED_DATA, "Unknown transform");
+    }
+  }
+
+  wBase_ = wBuf_.get() + sz;
+}
+
+void THeaderTransport::resetProtocol() {
+  // Set to anything except HTTP type so we don't flush again
+  clientType = THRIFT_HEADER_CLIENT_TYPE;
+
+  // Read the header and decide which protocol to go with
+  readFrame();
+}
+
+uint32_t THeaderTransport::getWriteBytes() {
+  return safe_numeric_cast<uint32_t>(wBase_ - wBuf_.get());
+}
+
+/**
+ * Writes a string to a byte buffer, as size (varint32) + string (non-null
+ * terminated)
+ * Automatically advances ptr to after the written portion
+ */
+void THeaderTransport::writeString(uint8_t*& ptr, const string& str) {
+  int32_t strLen = safe_numeric_cast<int32_t>(str.length());
+  ptr += writeVarint32(strLen, ptr);
+  memcpy(ptr, str.c_str(), strLen); // no need to write \0
+  ptr += strLen;
+}
+
+void THeaderTransport::setHeader(const string& key, const string& value) {
+  writeHeaders_[key] = value;
+}
+
+uint32_t THeaderTransport::getMaxWriteHeadersSize() const {
+  size_t maxWriteHeadersSize = 0;
+  THeaderTransport::StringToStringMap::const_iterator it;
+  for (it = writeHeaders_.begin(); it != writeHeaders_.end(); ++it) {
+    // add sizes of key and value to maxWriteHeadersSize
+    // 2 varints32 + the strings themselves
+    maxWriteHeadersSize += 5 + 5 + (it->first).length() + (it->second).length();
+  }
+  return safe_numeric_cast<uint32_t>(maxWriteHeadersSize);
+}
+
+void THeaderTransport::clearHeaders() {
+  writeHeaders_.clear();
+}
+
+void THeaderTransport::flush() {
+  // Write out any data waiting in the write buffer.
+  uint32_t haveBytes = getWriteBytes();
+
+  if (clientType == THRIFT_HEADER_CLIENT_TYPE) {
+    transform(wBuf_.get(), haveBytes);
+    haveBytes = getWriteBytes(); // transform may have changed the size
+  }
+
+  // Note that we reset wBase_ prior to the underlying write
+  // to ensure we're in a sane state (i.e. internal buffer cleaned)
+  // if the underlying write throws up an exception
+  wBase_ = wBuf_.get();
+
+  if (haveBytes > MAX_FRAME_SIZE) {
+    throw TTransportException(TTransportException::CORRUPTED_DATA,
+                              "Attempting to send frame that is too large");
+  }
+
+  if (clientType == THRIFT_HEADER_CLIENT_TYPE) {
+    // header size will need to be updated at the end because of varints.
+    // Make it big enough here for max varint size, plus 4 for padding.
+    uint32_t headerSize = (2 + getNumTransforms()) * THRIFT_MAX_VARINT32_BYTES + 4;
+    // add approximate size of info headers
+    headerSize += getMaxWriteHeadersSize();
+
+    // Pkt size
+    uint32_t maxSzHbo = headerSize + haveBytes // thrift header + payload
+                        + 10;                  // common header section
+    uint8_t* pkt = tBuf_.get();
+    uint8_t* headerStart;
+    uint8_t* headerSizePtr;
+    uint8_t* pktStart = pkt;
+
+    if (maxSzHbo > tBufSize_) {
+      throw TTransportException(TTransportException::CORRUPTED_DATA,
+                                "Attempting to header frame that is too large");
+    }
+
+    uint32_t szHbo;
+    uint32_t szNbo;
+    uint16_t headerSizeN;
+
+    // Fixup szHbo later
+    pkt += sizeof(szNbo);
+    uint16_t headerN = htons(HEADER_MAGIC >> 16);
+    memcpy(pkt, &headerN, sizeof(headerN));
+    pkt += sizeof(headerN);
+    uint16_t flagsN = htons(flags);
+    memcpy(pkt, &flagsN, sizeof(flagsN));
+    pkt += sizeof(flagsN);
+    uint32_t seqIdN = htonl(seqId);
+    memcpy(pkt, &seqIdN, sizeof(seqIdN));
+    pkt += sizeof(seqIdN);
+    headerSizePtr = pkt;
+    // Fixup headerSizeN later
+    pkt += sizeof(headerSizeN);
+    headerStart = pkt;
+
+    pkt += writeVarint32(protoId, pkt);
+    pkt += writeVarint32(getNumTransforms(), pkt);
+
+    // For now, each transform is only the ID, no following data.
+    for (vector<uint16_t>::const_iterator it = writeTrans_.begin(); it != writeTrans_.end(); ++it) {
+      pkt += writeVarint32(*it, pkt);
+    }
+
+    // write info headers
+
+    // for now only write kv-headers
+    int32_t headerCount = safe_numeric_cast<int32_t>(writeHeaders_.size());
+    if (headerCount > 0) {
+      pkt += writeVarint32(infoIdType::KEYVALUE, pkt);
+      // Write key-value headers count
+      pkt += writeVarint32(static_cast<int32_t>(headerCount), pkt);
+      // Write info headers
+      map<string, string>::const_iterator it;
+      for (it = writeHeaders_.begin(); it != writeHeaders_.end(); ++it) {
+        writeString(pkt, it->first);  // key
+        writeString(pkt, it->second); // value
+      }
+      writeHeaders_.clear();
+    }
+
+    // Fixups after varint size calculations
+    headerSize = safe_numeric_cast<uint32_t>(pkt - headerStart);
+    uint8_t padding = 4 - (headerSize % 4);
+    headerSize += padding;
+
+    // Pad out pkt with 0x00
+    for (int i = 0; i < padding; i++) {
+      *(pkt++) = 0x00;
+    }
+
+    // Pkt size
+    ptrdiff_t szHbp = (headerStart - pktStart - 4);
+    if (static_cast<uint64_t>(szHbp) > static_cast<uint64_t>((std::numeric_limits<uint32_t>().max)()) - (headerSize + haveBytes)) {
+      throw TTransportException(TTransportException::CORRUPTED_DATA,
+                                "Header section size is unreasonable");
+    }
+    szHbo = headerSize + haveBytes          // thrift header + payload
+            + static_cast<uint32_t>(szHbp); // common header section
+    headerSizeN = htons(headerSize / 4);
+    memcpy(headerSizePtr, &headerSizeN, sizeof(headerSizeN));
+
+    // Set framing size.
+    szNbo = htonl(szHbo);
+    memcpy(pktStart, &szNbo, sizeof(szNbo));
+
+    outTransport_->write(pktStart, szHbo - haveBytes + 4);
+    outTransport_->write(wBuf_.get(), haveBytes);
+  } else if (clientType == THRIFT_FRAMED_BINARY || clientType == THRIFT_FRAMED_COMPACT) {
+    uint32_t szHbo = (uint32_t)haveBytes;
+    uint32_t szNbo = htonl(szHbo);
+
+    outTransport_->write(reinterpret_cast<uint8_t*>(&szNbo), 4);
+    outTransport_->write(wBuf_.get(), haveBytes);
+  } else if (clientType == THRIFT_UNFRAMED_BINARY || clientType == THRIFT_UNFRAMED_COMPACT) {
+    outTransport_->write(wBuf_.get(), haveBytes);
+  } else {
+    throw TTransportException(TTransportException::BAD_ARGS, "Unknown client type");
+  }
+
+  // Flush the underlying transport.
+  outTransport_->flush();
+}
+
+/**
+ * Read an i16 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 3 bytes.
+ */
+uint32_t THeaderTransport::readVarint16(uint8_t const* ptr, int16_t* i16, uint8_t const* boundary) {
+  int32_t val;
+  uint32_t rsize = readVarint32(ptr, &val, boundary);
+  *i16 = (int16_t)val;
+  return rsize;
+}
+
+/**
+ * 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.
+ */
+uint32_t THeaderTransport::readVarint32(uint8_t const* ptr, int32_t* i32, uint8_t const* boundary) {
+
+  uint32_t rsize = 0;
+  uint32_t val = 0;
+  int shift = 0;
+
+  while (true) {
+    if (ptr == boundary) {
+      throw TApplicationException(TApplicationException::INVALID_MESSAGE_TYPE,
+                                  "Trying to read past header boundary");
+    }
+    uint8_t byte = *(ptr++);
+    rsize++;
+    val |= (uint64_t)(byte & 0x7f) << shift;
+    shift += 7;
+    if (!(byte & 0x80)) {
+      *i32 = val;
+      return rsize;
+    }
+  }
+}
+
+/**
+ * Write an i32 as a varint. Results in 1-5 bytes on the wire.
+ */
+uint32_t THeaderTransport::writeVarint32(int32_t n, uint8_t* pkt) {
+  uint8_t buf[5];
+  uint32_t wsize = 0;
+
+  while (true) {
+    if ((n & ~0x7F) == 0) {
+      buf[wsize++] = (int8_t)n;
+      break;
+    } else {
+      buf[wsize++] = (int8_t)((n & 0x7F) | 0x80);
+      n >>= 7;
+    }
+  }
+
+  // Caller will advance pkt.
+  for (uint32_t i = 0; i < wsize; i++) {
+    pkt[i] = buf[i];
+  }
+
+  return wsize;
+}
+
+uint32_t THeaderTransport::writeVarint16(int16_t n, uint8_t* pkt) {
+  return writeVarint32(n, pkt);
+}
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/THeaderTransport.h b/lib/cpp/src/thrift/transport/THeaderTransport.h
new file mode 100644
index 0000000..e6c57e6
--- /dev/null
+++ b/lib/cpp/src/thrift/transport/THeaderTransport.h
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ */
+
+#ifndef THRIFT_TRANSPORT_THEADERTRANSPORT_H_
+#define THRIFT_TRANSPORT_THEADERTRANSPORT_H_ 1
+
+#include <bitset>
+#include <limits>
+#include <vector>
+#include <stdexcept>
+#include <string>
+#include <map>
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include <boost/scoped_array.hpp>
+
+#include <thrift/protocol/TProtocolTypes.h>
+#include <thrift/transport/TBufferTransports.h>
+#include <thrift/transport/TTransport.h>
+#include <thrift/transport/TVirtualTransport.h>
+
+enum CLIENT_TYPE {
+  THRIFT_HEADER_CLIENT_TYPE = 0,
+  THRIFT_FRAMED_BINARY = 1,
+  THRIFT_UNFRAMED_BINARY = 2,
+  THRIFT_FRAMED_COMPACT = 3,
+  THRIFT_UNFRAMED_COMPACT = 4,
+  THRIFT_UNKNOWN_CLIENT_TYPE = 5,
+};
+
+namespace apache {
+namespace thrift {
+namespace transport {
+
+using apache::thrift::protocol::T_COMPACT_PROTOCOL;
+
+/**
+ * Header transport. All writes go into an in-memory buffer until flush is
+ * called, at which point the transport writes the length of the entire
+ * binary chunk followed by the data payload. This allows the receiver on the
+ * other end to always do fixed-length reads.
+ *
+ * Subclass TFramedTransport because most of the read/write methods are similar
+ * and need similar buffers.  Major changes are readFrame & flush.
+ *
+ * Header Transport *must* be the same transport for both input and
+ * output when used on the server side - client responses should be
+ * the same protocol as those in the request.
+ */
+class THeaderTransport : public TVirtualTransport<THeaderTransport, TFramedTransport> {
+public:
+  static const int DEFAULT_BUFFER_SIZE = 512u;
+  static const int THRIFT_MAX_VARINT32_BYTES = 5;
+
+  /// Use default buffer sizes.
+  explicit THeaderTransport(const std::shared_ptr<TTransport>& transport)
+    : TVirtualTransport(transport),
+      outTransport_(transport),
+      protoId(T_COMPACT_PROTOCOL),
+      clientType(THRIFT_HEADER_CLIENT_TYPE),
+      seqId(0),
+      flags(0),
+      tBufSize_(0),
+      tBuf_(NULL) {
+    if (!transport_) throw std::invalid_argument("transport is empty");
+    initBuffers();
+  }
+
+  THeaderTransport(const std::shared_ptr<TTransport> inTransport,
+                   const std::shared_ptr<TTransport> outTransport)
+    : TVirtualTransport(inTransport),
+      outTransport_(outTransport),
+      protoId(T_COMPACT_PROTOCOL),
+      clientType(THRIFT_HEADER_CLIENT_TYPE),
+      seqId(0),
+      flags(0),
+      tBufSize_(0),
+      tBuf_(NULL) {
+    if (!transport_) throw std::invalid_argument("inTransport is empty");
+    if (!outTransport_) throw std::invalid_argument("outTransport is empty");
+    initBuffers();
+  }
+
+  virtual uint32_t readSlow(uint8_t* buf, uint32_t len);
+  virtual void flush();
+
+  void resizeTransformBuffer(uint32_t additionalSize = 0);
+
+  uint16_t getProtocolId() const;
+  void setProtocolId(uint16_t protoId) { this->protoId = protoId; }
+
+  void resetProtocol();
+
+  /**
+   * We know we got a packet in header format here, try to parse the header
+   *
+   * @param headerSize size of the header portion
+   * @param sz Size of the whole message, including header
+   */
+  void readHeaderFormat(uint16_t headerSize, uint32_t sz);
+
+  /**
+   * Untransform the data based on the received header flags
+   * On conclusion of function, setReadBuffer is called with the
+   * untransformed data.
+   *
+   * @param ptr ptr to data
+   * @param size of data
+   */
+  void untransform(uint8_t* ptr, uint32_t sz);
+
+  /**
+   * Transform the data based on our write transform flags
+   * At conclusion of function the write buffer is set to the
+   * transformed data.
+   *
+   * @param ptr Ptr to data to transform
+   * @param sz Size of data buffer
+   */
+  void transform(uint8_t* ptr, uint32_t sz);
+
+  uint16_t getNumTransforms() const {
+    return safe_numeric_cast<uint16_t>(writeTrans_.size());
+  }
+
+  void setTransform(uint16_t transId) { writeTrans_.push_back(transId); }
+
+  // Info headers
+
+  typedef std::map<std::string, std::string> StringToStringMap;
+
+  // these work with write headers
+  void setHeader(const std::string& key, const std::string& value);
+
+  void clearHeaders();
+
+  StringToStringMap& getWriteHeaders() { return writeHeaders_; }
+
+  // these work with read headers
+  const StringToStringMap& getHeaders() const { return readHeaders_; }
+
+  // accessors for seqId
+  int32_t getSequenceNumber() const { return seqId; }
+  void setSequenceNumber(int32_t seqId) { this->seqId = seqId; }
+
+  enum TRANSFORMS {
+    ZLIB_TRANSFORM = 0x01,
+  };
+
+protected:
+  /**
+   * Reads a frame of input from the underlying stream.
+   *
+   * Returns true if a frame was read successfully, or false on EOF.
+   * (Raises a TTransportException if EOF occurs after a partial frame.)
+   */
+  virtual bool readFrame();
+
+  void ensureReadBuffer(uint32_t sz);
+  uint32_t getWriteBytes();
+
+  void initBuffers() {
+    setReadBuffer(NULL, 0);
+    setWriteBuffer(wBuf_.get(), wBufSize_);
+  }
+
+  std::shared_ptr<TTransport> outTransport_;
+
+  // 0 and 16th bits must be 0 to differentiate from framed & unframed
+  static const uint32_t HEADER_MAGIC = 0x0FFF0000;
+  static const uint32_t HEADER_MASK = 0xFFFF0000;
+  static const uint32_t FLAGS_MASK = 0x0000FFFF;
+
+  static const uint32_t MAX_FRAME_SIZE = 0x3FFFFFFF;
+
+  int16_t protoId;
+  uint16_t clientType;
+  uint32_t seqId;
+  uint16_t flags;
+
+  std::vector<uint16_t> readTrans_;
+  std::vector<uint16_t> writeTrans_;
+
+  // Map to use for headers
+  StringToStringMap readHeaders_;
+  StringToStringMap writeHeaders_;
+
+  /**
+   * Returns the maximum number of bytes that write k/v headers can take
+   */
+  uint32_t getMaxWriteHeadersSize() const;
+
+  struct infoIdType {
+    enum idType {
+      // start at 1 to avoid confusing header padding for an infoId
+      KEYVALUE = 1,
+      END // signal the end of infoIds we can handle
+    };
+  };
+
+  // Buffers to use for transform processing
+  uint32_t tBufSize_;
+  boost::scoped_array<uint8_t> tBuf_;
+
+  void readString(uint8_t*& ptr, /* out */ std::string& str, uint8_t const* headerBoundary);
+
+  void writeString(uint8_t*& ptr, const std::string& str);
+
+  // Varint utils
+  /**
+   * Read an i16 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 3 bytes.
+   */
+  uint32_t readVarint16(uint8_t const* ptr, int16_t* i16, uint8_t const* boundary);
+
+  /**
+   * 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.
+   */
+  uint32_t readVarint32(uint8_t const* ptr, int32_t* i32, uint8_t const* boundary);
+
+  /**
+   * Write an i32 as a varint. Results in 1-5 bytes on the wire.
+   */
+  uint32_t writeVarint32(int32_t n, uint8_t* pkt);
+
+  /**
+   * Write an i16 as a varint. Results in 1-3 bytes on the wire.
+   */
+  uint32_t writeVarint16(int16_t n, uint8_t* pkt);
+};
+
+/**
+ * Wraps a transport into a header one.
+ *
+ */
+class THeaderTransportFactory : public TTransportFactory {
+public:
+  THeaderTransportFactory() {}
+
+  virtual ~THeaderTransportFactory() {}
+
+  /**
+   * Wraps the transport into a header one.
+   */
+  virtual std::shared_ptr<TTransport> getTransport(std::shared_ptr<TTransport> trans) {
+    return std::shared_ptr<TTransport>(new THeaderTransport(trans));
+  }
+};
+}
+}
+} // apache::thrift::transport
+
+#endif // #ifndef THRIFT_TRANSPORT_THEADERTRANSPORT_H_
diff --git a/lib/cpp/src/thrift/transport/THttpClient.cpp b/lib/cpp/src/thrift/transport/THttpClient.cpp
index cb94d5e..d152197 100644
--- a/lib/cpp/src/thrift/transport/THttpClient.cpp
+++ b/lib/cpp/src/thrift/transport/THttpClient.cpp
@@ -22,29 +22,37 @@
 #include <sstream>
 #include <boost/algorithm/string.hpp>
 
+#include <thrift/config.h>
 #include <thrift/transport/THttpClient.h>
 #include <thrift/transport/TSocket.h>
 
-namespace apache { namespace thrift { namespace transport {
+using std::string;
 
-using namespace std;
+namespace apache {
+namespace thrift {
+namespace transport {
 
-THttpClient::THttpClient(boost::shared_ptr<TTransport> transport, std::string host, std::string path) :
-  THttpTransport(transport), host_(host), path_(path) {
+THttpClient::THttpClient(std::shared_ptr<TTransport> transport,
+                         std::string host,
+                         std::string path)
+  : THttpTransport(transport), host_(host), path_(path) {
 }
 
-THttpClient::THttpClient(string host, int port, string path) :
-  THttpTransport(boost::shared_ptr<TTransport>(new TSocket(host, port))), host_(host), path_(path) {
+THttpClient::THttpClient(string host, int port, string path)
+  : THttpTransport(std::shared_ptr<TTransport>(new TSocket(host, port))),
+    host_(host),
+    path_(path) {
 }
 
-THttpClient::~THttpClient() {}
+THttpClient::~THttpClient() {
+}
 
 void THttpClient::parseHeader(char* header) {
   char* colon = strchr(header, ':');
   if (colon == NULL) {
     return;
   }
-  char* value = colon+1;
+  char* value = colon + 1;
 
   if (boost::istarts_with(header, "Transfer-Encoding")) {
     if (boost::iends_with(value, "chunked")) {
@@ -65,7 +73,8 @@
   }
 
   *code = '\0';
-  while (*(code++) == ' ') {};
+  while (*(code++) == ' ') {
+  };
 
   char* msg = strchr(code, ' ');
   if (msg == NULL) {
@@ -92,17 +101,13 @@
 
   // Construct the HTTP header
   std::ostringstream h;
-  h <<
-    "POST " << path_ << " HTTP/1.1" << CRLF <<
-    "Host: " << host_ << CRLF <<
-    "Content-Type: application/x-thrift" << CRLF <<
-    "Content-Length: " << len << CRLF <<
-    "Accept: application/x-thrift" << CRLF <<
-    "User-Agent: Thrift/" << VERSION << " (C++/THttpClient)" << CRLF <<
-    CRLF;
+  h << "POST " << path_ << " HTTP/1.1" << CRLF << "Host: " << host_ << CRLF
+    << "Content-Type: application/x-thrift" << CRLF << "Content-Length: " << len << CRLF
+    << "Accept: application/x-thrift" << CRLF << "User-Agent: Thrift/" << PACKAGE_VERSION
+    << " (C++/THttpClient)" << CRLF << CRLF;
   string header = h.str();
 
-  if(header.size() > (std::numeric_limits<uint32_t>::max)())
+  if (header.size() > (std::numeric_limits<uint32_t>::max)())
     throw TTransportException("Header too big");
   // Write the header, then the data, then flush
   transport_->write((const uint8_t*)header.c_str(), static_cast<uint32_t>(header.size()));
@@ -113,5 +118,6 @@
   writeBuffer_.resetBuffer();
   readHeaders_ = true;
 }
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/THttpClient.h b/lib/cpp/src/thrift/transport/THttpClient.h
index 0898b11..f4fb12a 100644
--- a/lib/cpp/src/thrift/transport/THttpClient.h
+++ b/lib/cpp/src/thrift/transport/THttpClient.h
@@ -22,28 +22,29 @@
 
 #include <thrift/transport/THttpTransport.h>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 class THttpClient : public THttpTransport {
- public:
-  THttpClient(boost::shared_ptr<TTransport> transport, std::string host, std::string path="");
+public:
+  THttpClient(std::shared_ptr<TTransport> transport, std::string host, std::string path = "");
 
-  THttpClient(std::string host, int port, std::string path="");
+  THttpClient(std::string host, int port, std::string path = "");
 
   virtual ~THttpClient();
 
   virtual void flush();
 
- protected:
-
+protected:
   std::string host_;
   std::string path_;
 
   virtual void parseHeader(char* header);
   virtual bool parseStatusLine(char* status);
-
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_THTTPCLIENT_H_
diff --git a/lib/cpp/src/thrift/transport/THttpServer.cpp b/lib/cpp/src/thrift/transport/THttpServer.cpp
index 1135270..96b2480 100644
--- a/lib/cpp/src/thrift/transport/THttpServer.cpp
+++ b/lib/cpp/src/thrift/transport/THttpServer.cpp
@@ -21,18 +21,34 @@
 #include <sstream>
 #include <iostream>
 
+#include <thrift/config.h>
 #include <thrift/transport/THttpServer.h>
 #include <thrift/transport/TSocket.h>
+#if defined(_MSC_VER) || defined(__MINGW32__)
+  #include <Shlwapi.h>
+#endif
 
-namespace apache { namespace thrift { namespace transport {
+using std::string;
 
-using namespace std;
+namespace apache {
+namespace thrift {
+namespace transport {
 
-THttpServer::THttpServer(boost::shared_ptr<TTransport> transport) :
-  THttpTransport(transport) {
+THttpServer::THttpServer(std::shared_ptr<TTransport> transport) : THttpTransport(transport) {
 }
 
-THttpServer::~THttpServer() {}
+THttpServer::~THttpServer() {
+}
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+  #define THRIFT_GMTIME(TM, TIME)             gmtime_s(&TM, &TIME)
+  #define THRIFT_strncasecmp(str1, str2, len) _strnicmp(str1, str2, len)
+  #define THRIFT_strcasestr(haystack, needle) StrStrIA(haystack, needle)
+#else
+  #define THRIFT_GMTIME(TM, TIME)             gmtime_r(&TIME, &TM)
+  #define THRIFT_strncasecmp(str1, str2, len) strncasecmp(str1, str2, len)
+  #define THRIFT_strcasestr(haystack, needle) strcasestr(haystack, needle)
+#endif
 
 void THttpServer::parseHeader(char* header) {
   char* colon = strchr(header, ':');
@@ -40,15 +56,17 @@
     return;
   }
   size_t sz = colon - header;
-  char* value = colon+1;
+  char* value = colon + 1;
 
-  if (strncmp(header, "Transfer-Encoding", sz) == 0) {
-    if (strstr(value, "chunked") != NULL) {
+  if (THRIFT_strncasecmp(header, "Transfer-Encoding", sz) == 0) {
+    if (THRIFT_strcasestr(value, "chunked") != NULL) {
       chunked_ = true;
     }
-  } else if (strncmp(header, "Content-Length", sz) == 0) {
+  } else if (THRIFT_strncasecmp(header, "Content-length", sz) == 0) {
     chunked_ = false;
     contentLength_ = atoi(value);
+  } else if (strncmp(header, "X-Forwarded-For", sz) == 0) {
+    origin_ = value;
   }
 }
 
@@ -61,7 +79,8 @@
   }
 
   *path = '\0';
-  while (*(++path) == ' ') {};
+  while (*(++path) == ' ') {
+  };
 
   char* http = strchr(path, ' ');
   if (http == NULL) {
@@ -72,8 +91,7 @@
   if (strcmp(method, "POST") == 0) {
     // POST method ok, looking for content.
     return true;
-  }
-  else if (strcmp(method, "OPTIONS") == 0) {
+  } else if (strcmp(method, "OPTIONS") == 0) {
     // preflight OPTIONS method, we don't need further content.
     // how to graciously close connection?
     uint8_t* buf;
@@ -82,17 +100,13 @@
 
     // Construct the HTTP header
     std::ostringstream h;
-    h <<
-      "HTTP/1.1 200 OK" << CRLF <<
-      "Date: " << getTimeRFC1123() << CRLF <<
-      "Access-Control-Allow-Origin: *" << CRLF <<
-      "Access-Control-Allow-Methods: POST, OPTIONS" << CRLF <<
-      "Access-Control-Allow-Headers: Content-Type" << CRLF <<
-      CRLF;
+    h << "HTTP/1.1 200 OK" << CRLF << "Date: " << getTimeRFC1123() << CRLF
+      << "Access-Control-Allow-Origin: *" << CRLF << "Access-Control-Allow-Methods: POST, OPTIONS"
+      << CRLF << "Access-Control-Allow-Headers: Content-Type" << CRLF << CRLF;
     string header = h.str();
 
     // Write the header, then the data, then flush
-    transport_->write((const uint8_t*)header.c_str(), header.size());
+    transport_->write((const uint8_t*)header.c_str(), static_cast<uint32_t>(header.size()));
     transport_->write(buf, len);
     transport_->flush();
 
@@ -112,15 +126,10 @@
 
   // Construct the HTTP header
   std::ostringstream h;
-  h <<
-    "HTTP/1.1 200 OK" << CRLF <<
-    "Date: " << getTimeRFC1123() << CRLF <<
-    "Server: Thrift/" << VERSION << CRLF <<
-    "Access-Control-Allow-Origin: *" << CRLF <<
-    "Content-Type: application/x-thrift" << CRLF <<
-    "Content-Length: " << len << CRLF <<
-    "Connection: Keep-Alive" << CRLF <<
-    CRLF;
+  h << "HTTP/1.1 200 OK" << CRLF << "Date: " << getTimeRFC1123() << CRLF << "Server: Thrift/"
+    << PACKAGE_VERSION << CRLF << "Access-Control-Allow-Origin: *" << CRLF
+    << "Content-Type: application/x-thrift" << CRLF << "Content-Length: " << len << CRLF
+    << "Connection: Keep-Alive" << CRLF << CRLF;
   string header = h.str();
 
   // Write the header, then the data, then flush
@@ -134,19 +143,27 @@
   readHeaders_ = true;
 }
 
-std::string THttpServer::getTimeRFC1123()
-{
-  static const char* Days[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
-  static const char* Months[] = {"Jan","Feb","Mar", "Apr", "May", "Jun", "Jul","Aug", "Sep", "Oct","Nov","Dec"};
+std::string THttpServer::getTimeRFC1123() {
+  static const char* Days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+  static const char* Months[]
+      = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
   char buff[128];
-  time_t t = time(NULL);
-  tm* broken_t = gmtime(&t);
 
-  sprintf(buff,"%s, %d %s %d %d:%d:%d GMT",
-          Days[broken_t->tm_wday], broken_t->tm_mday, Months[broken_t->tm_mon],
-          broken_t->tm_year + 1900,
-          broken_t->tm_hour,broken_t->tm_min,broken_t->tm_sec);
+  time_t t = time(NULL);
+  struct tm tmb;
+  THRIFT_GMTIME(tmb, t);
+
+  sprintf(buff,
+          "%s, %d %s %d %d:%d:%d GMT",
+          Days[tmb.tm_wday],
+          tmb.tm_mday,
+          Months[tmb.tm_mon],
+          tmb.tm_year + 1900,
+          tmb.tm_hour,
+          tmb.tm_min,
+          tmb.tm_sec);
   return std::string(buff);
 }
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/THttpServer.h b/lib/cpp/src/thrift/transport/THttpServer.h
index bf69dbe..c38606f 100644
--- a/lib/cpp/src/thrift/transport/THttpServer.h
+++ b/lib/cpp/src/thrift/transport/THttpServer.h
@@ -22,30 +22,30 @@
 
 #include <thrift/transport/THttpTransport.h>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 class THttpServer : public THttpTransport {
- public:
-  THttpServer(boost::shared_ptr<TTransport> transport);
+public:
+  THttpServer(std::shared_ptr<TTransport> transport);
 
   virtual ~THttpServer();
 
   virtual void flush();
 
- protected:
-
+protected:
   void readHeaders();
   virtual void parseHeader(char* header);
   virtual bool parseStatusLine(char* status);
   std::string getTimeRFC1123();
-
 };
 
 /**
  * Wraps a transport into HTTP protocol
  */
 class THttpServerTransportFactory : public TTransportFactory {
- public:
+public:
   THttpServerTransportFactory() {}
 
   virtual ~THttpServerTransportFactory() {}
@@ -53,12 +53,12 @@
   /**
    * Wraps the transport into a buffered one.
    */
-  virtual boost::shared_ptr<TTransport> getTransport(boost::shared_ptr<TTransport> trans) {
-    return boost::shared_ptr<TTransport>(new THttpServer(trans));
+  virtual std::shared_ptr<TTransport> getTransport(std::shared_ptr<TTransport> trans) {
+    return std::shared_ptr<TTransport>(new THttpServer(trans));
   }
-
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_THTTPSERVER_H_
diff --git a/lib/cpp/src/thrift/transport/THttpTransport.cpp b/lib/cpp/src/thrift/transport/THttpTransport.cpp
index c415ddb..6ccc034 100644
--- a/lib/cpp/src/thrift/transport/THttpTransport.cpp
+++ b/lib/cpp/src/thrift/transport/THttpTransport.cpp
@@ -17,32 +17,37 @@
  * under the License.
  */
 
+#include <sstream>
+
 #include <thrift/transport/THttpTransport.h>
 
-namespace apache { namespace thrift { namespace transport {
+using std::string;
 
-using namespace std;
+namespace apache {
+namespace thrift {
+namespace transport {
 
 // Yeah, yeah, hacky to put these here, I know.
 const char* THttpTransport::CRLF = "\r\n";
 const int THttpTransport::CRLF_LEN = 2;
 
-THttpTransport::THttpTransport(boost::shared_ptr<TTransport> transport) :
-  transport_(transport),
-  readHeaders_(true),
-  chunked_(false),
-  chunkedDone_(false),
-  chunkSize_(0),
-  contentLength_(0),
-  httpBuf_(NULL),
-  httpPos_(0),
-  httpBufLen_(0),
-  httpBufSize_(1024) {
+THttpTransport::THttpTransport(std::shared_ptr<TTransport> transport)
+  : transport_(transport),
+    origin_(""),
+    readHeaders_(true),
+    chunked_(false),
+    chunkedDone_(false),
+    chunkSize_(0),
+    contentLength_(0),
+    httpBuf_(NULL),
+    httpPos_(0),
+    httpBufLen_(0),
+    httpBufSize_(1024) {
   init();
 }
 
 void THttpTransport::init() {
-  httpBuf_ = (char*)std::malloc(httpBufSize_+1);
+  httpBuf_ = (char*)std::malloc(httpBufSize_ + 1);
   if (httpBuf_ == NULL) {
     throw std::bad_alloc();
   }
@@ -79,8 +84,10 @@
 uint32_t THttpTransport::readMoreData() {
   uint32_t size;
 
-  // Get more data!
-  refill();
+  if (httpPos_ == httpBufLen_) {
+    // Get more data!
+    refill();
+  }
 
   if (readHeaders_) {
     readHeaders();
@@ -90,8 +97,9 @@
     size = readChunked();
   } else {
     size = readContent(contentLength_);
+    readHeaders_ = true;
   }
-  readHeaders_ = true;
+
   return size;
 }
 
@@ -149,7 +157,7 @@
     if (need < give) {
       give = need;
     }
-    readBuffer_.write((uint8_t*)(httpBuf_+httpPos_), give);
+    readBuffer_.write((uint8_t*)(httpBuf_ + httpPos_), give);
     httpPos_ += give;
     need -= give;
   }
@@ -160,7 +168,7 @@
   while (true) {
     char* eol = NULL;
 
-    eol = strstr(httpBuf_+httpPos_, CRLF);
+    eol = strstr(httpBuf_ + httpPos_, CRLF);
 
     // No CRLF yet?
     if (eol == NULL) {
@@ -170,19 +178,18 @@
     } else {
       // Return pointer to next line
       *eol = '\0';
-      char* line = httpBuf_+httpPos_;
-      httpPos_ = static_cast<uint32_t>((eol-httpBuf_) + CRLF_LEN);
+      char* line = httpBuf_ + httpPos_;
+      httpPos_ = static_cast<uint32_t>((eol - httpBuf_) + CRLF_LEN);
       return line;
     }
   }
-
 }
 
 void THttpTransport::shift() {
   if (httpBufLen_ > httpPos_) {
     // Shift down remaining data and read more
     uint32_t length = httpBufLen_ - httpPos_;
-    memmove(httpBuf_, httpBuf_+httpPos_, length);
+    memmove(httpBuf_, httpBuf_ + httpPos_, length);
     httpBufLen_ = length;
   } else {
     httpBufLen_ = 0;
@@ -195,19 +202,20 @@
   uint32_t avail = httpBufSize_ - httpBufLen_;
   if (avail <= (httpBufSize_ / 4)) {
     httpBufSize_ *= 2;
-    httpBuf_ = (char*)std::realloc(httpBuf_, httpBufSize_+1);
-    if (httpBuf_ == NULL) {
+    char* tmpBuf = (char*)std::realloc(httpBuf_, httpBufSize_ + 1);
+    if (tmpBuf == NULL) {
       throw std::bad_alloc();
     }
+    httpBuf_ = tmpBuf;
   }
 
   // Read more data
-  uint32_t got = transport_->read((uint8_t*)(httpBuf_+httpBufLen_), httpBufSize_-httpBufLen_);
+  uint32_t got = transport_->read((uint8_t*)(httpBuf_ + httpBufLen_), httpBufSize_ - httpBufLen_);
   httpBufLen_ += got;
   httpBuf_[httpBufLen_] = '\0';
 
   if (got == 0) {
-    throw TTransportException("Could not refill buffer");
+    throw TTransportException(TTransportException::END_OF_FILE, "Could not refill buffer");
   }
 }
 
@@ -249,4 +257,14 @@
   writeBuffer_.write(buf, len);
 }
 
-}}}
+const std::string THttpTransport::getOrigin() {
+  std::ostringstream oss;
+  if (!origin_.empty()) {
+    oss << origin_ << ", ";
+  }
+  oss << transport_->getOrigin();
+  return oss.str();
+}
+}
+}
+}
diff --git a/lib/cpp/src/thrift/transport/THttpTransport.h b/lib/cpp/src/thrift/transport/THttpTransport.h
index a2e8834..e46ab7f 100644
--- a/lib/cpp/src/thrift/transport/THttpTransport.h
+++ b/lib/cpp/src/thrift/transport/THttpTransport.h
@@ -23,7 +23,9 @@
 #include <thrift/transport/TBufferTransports.h>
 #include <thrift/transport/TVirtualTransport.h>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * HTTP implementation of the thrift transport. This was irritating
@@ -33,26 +35,18 @@
  * chunked transfer encoding, keepalive, etc. Tested against Apache.
  */
 class THttpTransport : public TVirtualTransport<THttpTransport> {
- public:
-  THttpTransport(boost::shared_ptr<TTransport> transport);
+public:
+  THttpTransport(std::shared_ptr<TTransport> transport);
 
   virtual ~THttpTransport();
 
-  void open() {
-    transport_->open();
-  }
+  void open() { transport_->open(); }
 
-  bool isOpen() {
-    return transport_->isOpen();
-  }
+  bool isOpen() { return transport_->isOpen(); }
 
-  bool peek() {
-    return transport_->peek();
-  }
+  bool peek() { return transport_->peek(); }
 
-  void close() {
-    transport_->close();
-  }
+  void close() { transport_->close(); }
 
   uint32_t read(uint8_t* buf, uint32_t len);
 
@@ -62,9 +56,11 @@
 
   virtual void flush() = 0;
 
- protected:
+  virtual const std::string getOrigin();
 
-  boost::shared_ptr<TTransport> transport_;
+protected:
+  std::shared_ptr<TTransport> transport_;
+  std::string origin_;
 
   TMemoryBuffer writeBuffer_;
   TMemoryBuffer readBuffer_;
@@ -101,7 +97,8 @@
   static const char* CRLF;
   static const int CRLF_LEN;
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_THTTPCLIENT_H_
diff --git a/lib/cpp/src/thrift/transport/TNonblockingSSLServerSocket.cpp b/lib/cpp/src/thrift/transport/TNonblockingSSLServerSocket.cpp
new file mode 100644
index 0000000..adec5d0
--- /dev/null
+++ b/lib/cpp/src/thrift/transport/TNonblockingSSLServerSocket.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include <thrift/transport/TNonblockingSSLServerSocket.h>
+#include <thrift/transport/TSSLSocket.h>
+
+namespace apache {
+namespace thrift {
+namespace transport {
+
+/**
+ * Nonblocking SSL server socket implementation.
+ */
+TNonblockingSSLServerSocket::TNonblockingSSLServerSocket(int port, std::shared_ptr<TSSLSocketFactory> factory)
+  : TNonblockingServerSocket(port), factory_(factory) {
+  factory_->server(true);
+}
+
+TNonblockingSSLServerSocket::TNonblockingSSLServerSocket(const std::string& address,
+                                   int port,
+                                   std::shared_ptr<TSSLSocketFactory> factory)
+  : TNonblockingServerSocket(address, port), factory_(factory) {
+  factory_->server(true);
+}
+
+TNonblockingSSLServerSocket::TNonblockingSSLServerSocket(int port,
+                                   int sendTimeout,
+                                   int recvTimeout,
+                                   std::shared_ptr<TSSLSocketFactory> factory)
+  : TNonblockingServerSocket(port, sendTimeout, recvTimeout), factory_(factory) {
+  factory_->server(true);
+}
+
+std::shared_ptr<TSocket> TNonblockingSSLServerSocket::createSocket(THRIFT_SOCKET client) {
+  std::shared_ptr<TSSLSocket> tSSLSocket;
+  tSSLSocket = factory_->createSocket(client);
+  tSSLSocket->setLibeventSafe();
+  return tSSLSocket;
+}
+}
+}
+}
diff --git a/lib/cpp/src/thrift/transport/TNonblockingSSLServerSocket.h b/lib/cpp/src/thrift/transport/TNonblockingSSLServerSocket.h
new file mode 100644
index 0000000..215c405
--- /dev/null
+++ b/lib/cpp/src/thrift/transport/TNonblockingSSLServerSocket.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_TRANSPORT_TNONBLOCKINGSSLSERVERSOCKET_H_
+#define _THRIFT_TRANSPORT_TNONBLOCKINGSSLSERVERSOCKET_H_ 1
+
+#include <thrift/transport/TNonblockingServerSocket.h>
+
+namespace apache {
+namespace thrift {
+namespace transport {
+
+class TSSLSocketFactory;
+
+/**
+ * Nonblocking Server socket that accepts SSL connections.
+ */
+class TNonblockingSSLServerSocket : public TNonblockingServerSocket {
+public:
+  /**
+   * Constructor.  Binds to all interfaces.
+   *
+   * @param port    Listening port
+   * @param factory SSL socket factory implementation
+   */
+  TNonblockingSSLServerSocket(int port, std::shared_ptr<TSSLSocketFactory> factory);
+
+  /**
+   * Constructor.  Binds to the specified address.
+   *
+   * @param address Address to bind to
+   * @param port    Listening port
+   * @param factory SSL socket factory implementation
+   */
+  TNonblockingSSLServerSocket(const std::string& address,
+                   int port,
+                   std::shared_ptr<TSSLSocketFactory> factory);
+
+  /**
+   * Constructor.  Binds to all interfaces.
+   *
+   * @param port        Listening port
+   * @param sendTimeout Socket send timeout
+   * @param recvTimeout Socket receive timeout
+   * @param factory     SSL socket factory implementation
+   */
+  TNonblockingSSLServerSocket(int port,
+                   int sendTimeout,
+                   int recvTimeout,
+                   std::shared_ptr<TSSLSocketFactory> factory);
+
+protected:
+  std::shared_ptr<TSocket> createSocket(THRIFT_SOCKET socket);
+  std::shared_ptr<TSSLSocketFactory> factory_;
+};
+}
+}
+}
+
+#endif
diff --git a/lib/cpp/src/thrift/transport/TNonblockingServerSocket.cpp b/lib/cpp/src/thrift/transport/TNonblockingServerSocket.cpp
new file mode 100644
index 0000000..3d34cca
--- /dev/null
+++ b/lib/cpp/src/thrift/transport/TNonblockingServerSocket.cpp
@@ -0,0 +1,548 @@
+/*
+ * 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.
+ */
+
+#include <thrift/thrift-config.h>
+
+#include <cstring>
+#include <stdexcept>
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <thrift/transport/TSocket.h>
+#include <thrift/transport/TNonblockingServerSocket.h>
+#include <thrift/transport/PlatformSocket.h>
+
+#ifndef AF_LOCAL
+#define AF_LOCAL AF_UNIX
+#endif
+
+#ifndef SOCKOPT_CAST_T
+#ifndef _WIN32
+#define SOCKOPT_CAST_T void
+#else
+#define SOCKOPT_CAST_T char
+#endif // _WIN32
+#endif
+
+template <class T>
+inline const SOCKOPT_CAST_T* const_cast_sockopt(const T* v) {
+  return reinterpret_cast<const SOCKOPT_CAST_T*>(v);
+}
+
+template <class T>
+inline SOCKOPT_CAST_T* cast_sockopt(T* v) {
+  return reinterpret_cast<SOCKOPT_CAST_T*>(v);
+}
+
+namespace apache {
+namespace thrift {
+namespace transport {
+
+using std::string;
+using std::shared_ptr;
+
+TNonblockingServerSocket::TNonblockingServerSocket(int port)
+  : port_(port),
+    listenPort_(port),
+    serverSocket_(THRIFT_INVALID_SOCKET),
+    acceptBacklog_(DEFAULT_BACKLOG),
+    sendTimeout_(0),
+    recvTimeout_(0),
+    retryLimit_(0),
+    retryDelay_(0),
+    tcpSendBuffer_(0),
+    tcpRecvBuffer_(0),
+    keepAlive_(false),
+    listening_(false) {
+}
+
+TNonblockingServerSocket::TNonblockingServerSocket(int port, int sendTimeout, int recvTimeout)
+  : port_(port),
+    listenPort_(port),
+    serverSocket_(THRIFT_INVALID_SOCKET),
+    acceptBacklog_(DEFAULT_BACKLOG),
+    sendTimeout_(sendTimeout),
+    recvTimeout_(recvTimeout),
+    retryLimit_(0),
+    retryDelay_(0),
+    tcpSendBuffer_(0),
+    tcpRecvBuffer_(0),
+    keepAlive_(false),
+    listening_(false) {
+}
+
+TNonblockingServerSocket::TNonblockingServerSocket(const string& address, int port)
+  : port_(port),
+    listenPort_(port),
+    address_(address),
+    serverSocket_(THRIFT_INVALID_SOCKET),
+    acceptBacklog_(DEFAULT_BACKLOG),
+    sendTimeout_(0),
+    recvTimeout_(0),
+    retryLimit_(0),
+    retryDelay_(0),
+    tcpSendBuffer_(0),
+    tcpRecvBuffer_(0),
+    keepAlive_(false),
+    listening_(false) {
+}
+
+TNonblockingServerSocket::TNonblockingServerSocket(const string& path)
+  : port_(0),
+    listenPort_(0),
+    path_(path),
+    serverSocket_(THRIFT_INVALID_SOCKET),
+    acceptBacklog_(DEFAULT_BACKLOG),
+    sendTimeout_(0),
+    recvTimeout_(0),
+    retryLimit_(0),
+    retryDelay_(0),
+    tcpSendBuffer_(0),
+    tcpRecvBuffer_(0),
+    keepAlive_(false),
+    listening_(false) {
+}
+
+TNonblockingServerSocket::~TNonblockingServerSocket() {
+  close();
+}
+
+void TNonblockingServerSocket::setSendTimeout(int sendTimeout) {
+  sendTimeout_ = sendTimeout;
+}
+
+void TNonblockingServerSocket::setRecvTimeout(int recvTimeout) {
+  recvTimeout_ = recvTimeout;
+}
+
+void TNonblockingServerSocket::setAcceptBacklog(int accBacklog) {
+  acceptBacklog_ = accBacklog;
+}
+
+void TNonblockingServerSocket::setRetryLimit(int retryLimit) {
+  retryLimit_ = retryLimit;
+}
+
+void TNonblockingServerSocket::setRetryDelay(int retryDelay) {
+  retryDelay_ = retryDelay;
+}
+
+void TNonblockingServerSocket::setTcpSendBuffer(int tcpSendBuffer) {
+  tcpSendBuffer_ = tcpSendBuffer;
+}
+
+void TNonblockingServerSocket::setTcpRecvBuffer(int tcpRecvBuffer) {
+  tcpRecvBuffer_ = tcpRecvBuffer;
+}
+
+void TNonblockingServerSocket::listen() {
+  listening_ = true;
+#ifdef _WIN32
+  TWinsockSingleton::create();
+#endif // _WIN32
+  
+  // Validate port number
+  if (port_ < 0 || port_ > 0xFFFF) {
+    throw TTransportException(TTransportException::BAD_ARGS, "Specified port is invalid");
+  }
+
+  const struct addrinfo *res;
+  int error;
+  char port[sizeof("65535")];
+  THRIFT_SNPRINTF(port, sizeof(port), "%d", port_);
+
+  struct addrinfo hints;
+  std::memset(&hints, 0, sizeof(hints));
+  hints.ai_family = PF_UNSPEC;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+
+  // If address is not specified use wildcard address (NULL)
+  TGetAddrInfoWrapper info(address_.empty() ? NULL : &address_[0], port, &hints);
+
+  error = info.init();
+  if (error) {
+    GlobalOutput.printf("getaddrinfo %d: %s", error, THRIFT_GAI_STRERROR(error));
+    close();
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "Could not resolve host for server socket.");
+  }
+
+  // Pick the ipv6 address first since ipv4 addresses can be mapped
+  // into ipv6 space.
+  for (res = info.res(); res; res = res->ai_next) {
+    if (res->ai_family == AF_INET6 || res->ai_next == NULL)
+      break;
+  }
+
+  if (!path_.empty()) {
+    serverSocket_ = socket(PF_UNIX, SOCK_STREAM, IPPROTO_IP);
+  } else if (res != NULL) {
+    serverSocket_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+  }
+
+  if (serverSocket_ == THRIFT_INVALID_SOCKET) {
+    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    GlobalOutput.perror("TNonblockingServerSocket::listen() socket() ", errno_copy);
+    close();
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "Could not create server socket.",
+                              errno_copy);
+  }
+
+  // Set THRIFT_NO_SOCKET_CACHING to prevent 2MSL delay on accept
+  int one = 1;
+  if (-1 == setsockopt(serverSocket_,
+                       SOL_SOCKET,
+                       THRIFT_NO_SOCKET_CACHING,
+                       cast_sockopt(&one),
+                       sizeof(one))) {
+// ignore errors coming out of this setsockopt on Windows.  This is because
+// SO_EXCLUSIVEADDRUSE requires admin privileges on WinXP, but we don't
+// want to force servers to be an admin.
+#ifndef _WIN32
+    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() THRIFT_NO_SOCKET_CACHING ",
+                        errno_copy);
+    close();
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "Could not set THRIFT_NO_SOCKET_CACHING",
+                              errno_copy);
+#endif
+  }
+
+  // Set TCP buffer sizes
+  if (tcpSendBuffer_ > 0) {
+    if (-1 == setsockopt(serverSocket_,
+                         SOL_SOCKET,
+                         SO_SNDBUF,
+                         cast_sockopt(&tcpSendBuffer_),
+                         sizeof(tcpSendBuffer_))) {
+      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+      GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() SO_SNDBUF ", errno_copy);
+      close();
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                "Could not set SO_SNDBUF",
+                                errno_copy);
+    }
+  }
+
+  if (tcpRecvBuffer_ > 0) {
+    if (-1 == setsockopt(serverSocket_,
+                         SOL_SOCKET,
+                         SO_RCVBUF,
+                         cast_sockopt(&tcpRecvBuffer_),
+                         sizeof(tcpRecvBuffer_))) {
+      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+      GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() SO_RCVBUF ", errno_copy);
+      close();
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                "Could not set SO_RCVBUF",
+                                errno_copy);
+    }
+  }
+
+#ifdef IPV6_V6ONLY
+  if (res->ai_family == AF_INET6 && path_.empty()) {
+    int zero = 0;
+    if (-1 == setsockopt(serverSocket_,
+                         IPPROTO_IPV6,
+                         IPV6_V6ONLY,
+                         cast_sockopt(&zero),
+                         sizeof(zero))) {
+      GlobalOutput.perror("TNonblockingServerSocket::listen() IPV6_V6ONLY ", THRIFT_GET_SOCKET_ERROR);
+    }
+  }
+#endif // #ifdef IPV6_V6ONLY
+
+  // Turn linger off, don't want to block on calls to close
+  struct linger ling = {0, 0};
+  if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_LINGER, cast_sockopt(&ling), sizeof(ling))) {
+    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() SO_LINGER ", errno_copy);
+    close();
+    throw TTransportException(TTransportException::NOT_OPEN, "Could not set SO_LINGER", errno_copy);
+  }
+
+  // Keepalive to ensure full result flushing
+  if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_KEEPALIVE, const_cast_sockopt(&one), sizeof(one))) {
+    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() SO_KEEPALIVE ", errno_copy);
+    close();
+    throw TTransportException(TTransportException::NOT_OPEN,
+      "Could not set TCP_NODELAY",
+      errno_copy);
+  }
+
+  // Set TCP nodelay if available, MAC OS X Hack
+  // See http://lists.danga.com/pipermail/memcached/2005-March/001240.html
+#ifndef TCP_NOPUSH
+  // Unix Sockets do not need that
+  if (path_.empty()) {
+    // TCP Nodelay, speed over bandwidth
+    if (-1
+        == setsockopt(serverSocket_, IPPROTO_TCP, TCP_NODELAY, cast_sockopt(&one), sizeof(one))) {
+      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+      GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() TCP_NODELAY ", errno_copy);
+      close();
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                "Could not set TCP_NODELAY",
+                                errno_copy);
+    }
+  }
+#endif
+
+  // Set NONBLOCK on the accept socket
+  int flags = THRIFT_FCNTL(serverSocket_, THRIFT_F_GETFL, 0);
+  if (flags == -1) {
+    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    GlobalOutput.perror("TNonblockingServerSocket::listen() THRIFT_FCNTL() THRIFT_F_GETFL ", errno_copy);
+    close();
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "THRIFT_FCNTL() THRIFT_F_GETFL failed",
+                              errno_copy);
+  }
+
+  if (-1 == THRIFT_FCNTL(serverSocket_, THRIFT_F_SETFL, flags | THRIFT_O_NONBLOCK)) {
+    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    GlobalOutput.perror("TNonblockingServerSocket::listen() THRIFT_FCNTL() THRIFT_O_NONBLOCK ", errno_copy);
+    close();
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "THRIFT_FCNTL() THRIFT_F_SETFL THRIFT_O_NONBLOCK failed",
+                              errno_copy);
+  }
+
+#ifdef TCP_LOW_MIN_RTO
+  if (TSocket::getUseLowMinRto()) {
+    if (-1 == setsockopt(s, IPPROTO_TCP, TCP_LOW_MIN_RTO, const_cast_sockopt(&one), sizeof(one))) {
+      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+      GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() TCP_LOW_MIN_RTO ", errno_copy);
+      close();
+      throw TTransportException(TTransportException::NOT_OPEN,
+        "Could not set TCP_NODELAY",
+        errno_copy);
+    }
+  }
+#endif
+
+  // prepare the port information
+  // we may want to try to bind more than once, since THRIFT_NO_SOCKET_CACHING doesn't
+  // always seem to work. The client can configure the retry variables.
+  int retries = 0;
+  int errno_copy = 0;
+
+  if (!path_.empty()) {
+
+#ifndef _WIN32
+
+    // Unix Domain Socket
+    size_t len = path_.size() + 1;
+    if (len > sizeof(((sockaddr_un*)NULL)->sun_path)) {
+      errno_copy = THRIFT_GET_SOCKET_ERROR;
+      GlobalOutput.perror("TSocket::listen() Unix Domain socket path too long", errno_copy);
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                "Unix Domain socket path too long",
+                                errno_copy);
+    }
+
+    struct sockaddr_un address;
+    address.sun_family = AF_UNIX;
+    memcpy(address.sun_path, path_.c_str(), len);
+
+    socklen_t structlen = static_cast<socklen_t>(sizeof(address));
+
+    if (!address.sun_path[0]) { // abstract namespace socket
+#ifdef __linux__
+      // sun_path is not null-terminated in this case and structlen determines its length
+      structlen -= sizeof(address.sun_path) - len;
+#else
+      GlobalOutput.perror("TSocket::open() Abstract Namespace Domain sockets only supported on linux: ", -99);
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                " Abstract Namespace Domain socket path not supported");
+#endif
+    }
+
+    do {
+      if (0 == ::bind(serverSocket_, (struct sockaddr*)&address, structlen)) {
+        break;
+      }
+      errno_copy = THRIFT_GET_SOCKET_ERROR;
+      // use short circuit evaluation here to only sleep if we need to
+    } while ((retries++ < retryLimit_) && (THRIFT_SLEEP_SEC(retryDelay_) == 0));
+#else
+    GlobalOutput.perror("TSocket::open() Unix Domain socket path not supported on windows", -99);
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              " Unix Domain socket path not supported");
+#endif
+  } else {
+    do {
+      if (0 == ::bind(serverSocket_, res->ai_addr, static_cast<int>(res->ai_addrlen))) {
+        break;
+      }
+      errno_copy = THRIFT_GET_SOCKET_ERROR;
+      // use short circuit evaluation here to only sleep if we need to
+    } while ((retries++ < retryLimit_) && (THRIFT_SLEEP_SEC(retryDelay_) == 0));
+
+    // retrieve bind info
+    if (port_ == 0 && retries <= retryLimit_) {
+      struct sockaddr_storage sa;
+      socklen_t len = sizeof(sa);
+      std::memset(&sa, 0, len);
+      if (::getsockname(serverSocket_, reinterpret_cast<struct sockaddr*>(&sa), &len) < 0) {
+        errno_copy = THRIFT_GET_SOCKET_ERROR;
+        GlobalOutput.perror("TNonblockingServerSocket::getPort() getsockname() ", errno_copy);
+      } else {
+        if (sa.ss_family == AF_INET6) {
+          const struct sockaddr_in6* sin = reinterpret_cast<const struct sockaddr_in6*>(&sa);
+          listenPort_ = ntohs(sin->sin6_port);
+        } else {
+          const struct sockaddr_in* sin = reinterpret_cast<const struct sockaddr_in*>(&sa);
+          listenPort_ = ntohs(sin->sin_port);
+        }
+      }
+    }
+  }
+
+  // throw an error if we failed to bind properly
+  if (retries > retryLimit_) {
+    char errbuf[1024];
+    if (!path_.empty()) {
+      THRIFT_SNPRINTF(errbuf, sizeof(errbuf), "TNonblockingServerSocket::listen() PATH %s", path_.c_str());
+    } else {
+      THRIFT_SNPRINTF(errbuf, sizeof(errbuf), "TNonblockingServerSocket::listen() BIND %d", port_);
+    }
+    GlobalOutput(errbuf);
+    close();
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "Could not bind",
+                              errno_copy);
+  }
+
+  if (listenCallback_)
+    listenCallback_(serverSocket_);
+
+  // Call listen
+  if (-1 == ::listen(serverSocket_, acceptBacklog_)) {
+    errno_copy = THRIFT_GET_SOCKET_ERROR;
+    GlobalOutput.perror("TNonblockingServerSocket::listen() listen() ", errno_copy);
+    close();
+    throw TTransportException(TTransportException::NOT_OPEN, "Could not listen", errno_copy);
+  }
+
+  // The socket is now listening!
+}
+
+int TNonblockingServerSocket::getPort() {
+  return port_;
+}
+
+int TNonblockingServerSocket::getListenPort() {
+  return listenPort_;
+}
+
+shared_ptr<TSocket> TNonblockingServerSocket::acceptImpl() {
+  if (serverSocket_ == THRIFT_INVALID_SOCKET) {
+    throw TTransportException(TTransportException::NOT_OPEN, "TNonblockingServerSocket not listening");
+  }
+  
+  struct sockaddr_storage clientAddress;
+  int size = sizeof(clientAddress);
+  THRIFT_SOCKET clientSocket
+      = ::accept(serverSocket_, (struct sockaddr*)&clientAddress, (socklen_t*)&size);
+
+  if (clientSocket == THRIFT_INVALID_SOCKET) {
+    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    GlobalOutput.perror("TNonblockingServerSocket::acceptImpl() ::accept() ", errno_copy);
+    throw TTransportException(TTransportException::UNKNOWN, "accept()", errno_copy);
+  }
+
+  // Explicitly set this socket to NONBLOCK mode
+  int flags = THRIFT_FCNTL(clientSocket, THRIFT_F_GETFL, 0);
+  if (flags == -1) {
+    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    ::THRIFT_CLOSESOCKET(clientSocket);
+    GlobalOutput.perror("TNonblockingServerSocket::acceptImpl() THRIFT_FCNTL() THRIFT_F_GETFL ", errno_copy);
+    throw TTransportException(TTransportException::UNKNOWN,
+                              "THRIFT_FCNTL(THRIFT_F_GETFL)",
+                              errno_copy);
+  }
+
+  if (-1 == THRIFT_FCNTL(clientSocket, THRIFT_F_SETFL, flags | THRIFT_O_NONBLOCK)) {
+    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    ::THRIFT_CLOSESOCKET(clientSocket);
+    GlobalOutput
+        .perror("TNonblockingServerSocket::acceptImpl() THRIFT_FCNTL() THRIFT_F_SETFL ~THRIFT_O_NONBLOCK ",
+                errno_copy);
+    throw TTransportException(TTransportException::UNKNOWN,
+                              "THRIFT_FCNTL(THRIFT_F_SETFL)",
+                              errno_copy);
+  }
+
+  shared_ptr<TSocket> client = createSocket(clientSocket);
+  if (sendTimeout_ > 0) {
+    client->setSendTimeout(sendTimeout_);
+  }
+  if (recvTimeout_ > 0) {
+    client->setRecvTimeout(recvTimeout_);
+  }
+  if (keepAlive_) {
+    client->setKeepAlive(keepAlive_);
+  }
+  client->setCachedAddress((sockaddr*)&clientAddress, size);
+
+  if (acceptCallback_)
+    acceptCallback_(clientSocket);
+
+  return client;
+}
+
+shared_ptr<TSocket> TNonblockingServerSocket::createSocket(THRIFT_SOCKET clientSocket) {
+  return shared_ptr<TSocket>(new TSocket(clientSocket));
+}
+
+void TNonblockingServerSocket::close() {
+  if (serverSocket_ != THRIFT_INVALID_SOCKET) {
+    shutdown(serverSocket_, THRIFT_SHUT_RDWR);
+    ::THRIFT_CLOSESOCKET(serverSocket_);
+  }
+  serverSocket_ = THRIFT_INVALID_SOCKET;
+  listening_ = false;
+}
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/TNonblockingServerSocket.h b/lib/cpp/src/thrift/transport/TNonblockingServerSocket.h
new file mode 100644
index 0000000..1586ff0
--- /dev/null
+++ b/lib/cpp/src/thrift/transport/TNonblockingServerSocket.h
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_TRANSPORT_TNONBLOCKINGSERVERSOCKET_H_
+#define _THRIFT_TRANSPORT_TNONBLOCKINGSERVERSOCKET_H_ 1
+
+#include <thrift/transport/TNonblockingServerTransport.h>
+#include <thrift/transport/PlatformSocket.h>
+
+namespace apache {
+namespace thrift {
+namespace transport {
+
+class TSocket;
+
+/**
+ * Nonblocking Server socket implementation of TNonblockingServerTransport. Wrapper around a unix
+ * socket listen and accept calls.
+ *
+ */
+class TNonblockingServerSocket : public TNonblockingServerTransport {
+public:
+  typedef std::function<void(THRIFT_SOCKET fd)> socket_func_t;
+
+  const static int DEFAULT_BACKLOG = 1024;
+
+  /**
+   * Constructor.
+   *
+   * @param port    Port number to bind to
+   */
+  TNonblockingServerSocket(int port);
+
+  /**
+   * Constructor.
+   *
+   * @param port        Port number to bind to
+   * @param sendTimeout Socket send timeout
+   * @param recvTimeout Socket receive timeout
+   */
+  TNonblockingServerSocket(int port, int sendTimeout, int recvTimeout);
+
+  /**
+   * Constructor.
+   *
+   * @param address Address to bind to
+   * @param port    Port number to bind to
+   */
+  TNonblockingServerSocket(const std::string& address, int port);
+
+  /**
+   * Constructor used for unix sockets.
+   *
+   * @param path Pathname for unix socket.
+   */
+  TNonblockingServerSocket(const std::string& path);
+
+  virtual ~TNonblockingServerSocket();
+
+  void setSendTimeout(int sendTimeout);
+  void setRecvTimeout(int recvTimeout);
+
+  void setAcceptBacklog(int accBacklog);
+
+  void setRetryLimit(int retryLimit);
+  void setRetryDelay(int retryDelay);
+
+  void setKeepAlive(bool keepAlive) { keepAlive_ = keepAlive; }
+
+  void setTcpSendBuffer(int tcpSendBuffer);
+  void setTcpRecvBuffer(int tcpRecvBuffer);
+
+  // listenCallback gets called just before listen, and after all Thrift
+  // setsockopt calls have been made.  If you have custom setsockopt
+  // things that need to happen on the listening socket, this is the place to do it.
+  void setListenCallback(const socket_func_t& listenCallback) { listenCallback_ = listenCallback; }
+
+  // acceptCallback gets called after each accept call, on the newly created socket.
+  // It is called after all Thrift setsockopt calls have been made.  If you have
+  // custom setsockopt things that need to happen on the accepted
+  // socket, this is the place to do it.
+  void setAcceptCallback(const socket_func_t& acceptCallback) { acceptCallback_ = acceptCallback; }
+
+  THRIFT_SOCKET getSocketFD() { return serverSocket_; }
+
+  int getPort();
+  
+  int getListenPort();
+
+  void listen();
+  void close();
+
+protected:
+  std::shared_ptr<TSocket> acceptImpl();
+  virtual std::shared_ptr<TSocket> createSocket(THRIFT_SOCKET client);
+
+private:
+  int port_;
+  int listenPort_;
+  std::string address_;
+  std::string path_;
+  THRIFT_SOCKET serverSocket_;
+  int acceptBacklog_;
+  int sendTimeout_;
+  int recvTimeout_;
+  int retryLimit_;
+  int retryDelay_;
+  int tcpSendBuffer_;
+  int tcpRecvBuffer_;
+  bool keepAlive_;
+  bool listening_;
+
+  socket_func_t listenCallback_;
+  socket_func_t acceptCallback_;
+};
+}
+}
+} // apache::thrift::transport
+
+#endif // #ifndef _THRIFT_TRANSPORT_TNONBLOCKINGSERVERSOCKET_H_
diff --git a/lib/cpp/src/thrift/transport/TNonblockingServerTransport.h b/lib/cpp/src/thrift/transport/TNonblockingServerTransport.h
new file mode 100644
index 0000000..3142e19
--- /dev/null
+++ b/lib/cpp/src/thrift/transport/TNonblockingServerTransport.h
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef _THRIFT_TRANSPORT_TNONBLOCKINGSERVERTRANSPORT_H_
+#define _THRIFT_TRANSPORT_TNONBLOCKINGSERVERTRANSPORT_H_ 1
+
+#include <thrift/transport/TSocket.h>
+#include <thrift/transport/TTransportException.h>
+
+namespace apache {
+namespace thrift {
+namespace transport {
+
+/**
+ * Server transport framework. A server needs to have some facility for
+ * creating base transports to read/write from.  The server is expected
+ * to keep track of TTransport children that it creates for purposes of
+ * controlling their lifetime.
+ */
+class TNonblockingServerTransport {
+public:
+  virtual ~TNonblockingServerTransport() {}
+
+  /**
+   * Starts the server transport listening for new connections. Prior to this
+   * call most transports will not return anything when accept is called.
+   *
+   * @throws TTransportException if we were unable to listen
+   */
+  virtual void listen() {}
+
+  /**
+   * Gets a new dynamically allocated transport object and passes it to the
+   * caller. Note that it is the explicit duty of the caller to free the
+   * allocated object. The returned TTransport object must always be in the
+   * opened state. NULL should never be returned, instead an Exception should
+   * always be thrown.
+   *
+   * @return A new TTransport object
+   * @throws TTransportException if there is an error
+   */
+  std::shared_ptr<TSocket> accept() {
+    std::shared_ptr<TSocket> result = acceptImpl();
+    if (!result) {
+      throw TTransportException("accept() may not return NULL");
+    }
+    return result;
+  }
+
+  /**
+  * Utility method
+  * 
+  * @return server socket file descriptor 
+  * @throw TTransportException If an error occurs
+  */
+
+  virtual THRIFT_SOCKET getSocketFD() = 0;
+
+  virtual int getPort() = 0;
+
+  virtual int getListenPort() = 0;
+
+  /**
+   * Closes this transport such that future calls to accept will do nothing.
+   */
+  virtual void close() = 0;
+
+protected:
+  TNonblockingServerTransport() {}
+
+  /**
+   * Subclasses should implement this function for accept.
+   *
+   * @return A newly allocated TTransport object
+   * @throw TTransportException If an error occurs
+   */
+  virtual std::shared_ptr<TSocket> acceptImpl() = 0;
+
+};
+}
+}
+} // apache::thrift::transport
+
+#endif // #ifndef _THRIFT_TRANSPORT_TNONBLOCKINGSERVERTRANSPORT_H_
diff --git a/lib/cpp/src/thrift/transport/TPipe.cpp b/lib/cpp/src/thrift/transport/TPipe.cpp
index 92e2912..8a84457 100644
--- a/lib/cpp/src/thrift/transport/TPipe.cpp
+++ b/lib/cpp/src/thrift/transport/TPipe.cpp
@@ -19,139 +19,300 @@
 
 #include <thrift/transport/TTransportException.h>
 #include <thrift/transport/TPipe.h>
+#ifdef _WIN32
+#include <thrift/windows/OverlappedSubmissionThread.h>
+#include <thrift/windows/Sync.h>
+#endif
 
-namespace apache { namespace thrift { namespace transport {
-
-using namespace std;
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
 * TPipe implementation.
 */
 
 #ifdef _WIN32
+
+uint32_t pipe_read(HANDLE pipe, uint8_t* buf, uint32_t len);
+void pipe_write(HANDLE pipe, const uint8_t* buf, uint32_t len);
+
+uint32_t pseudo_sync_read(HANDLE pipe, HANDLE event, uint8_t* buf, uint32_t len);
+void pseudo_sync_write(HANDLE pipe, HANDLE event, const uint8_t* buf, uint32_t len);
+
+class TPipeImpl : boost::noncopyable {
+public:
+  TPipeImpl() {}
+  virtual ~TPipeImpl() {}
+  virtual uint32_t read(uint8_t* buf, uint32_t len) = 0;
+  virtual void write(const uint8_t* buf, uint32_t len) = 0;
+  virtual HANDLE getPipeHandle() = 0; // doubles as the read handle for anon pipe
+  virtual void setPipeHandle(HANDLE pipehandle) = 0;
+  virtual HANDLE getWrtPipeHandle() { return INVALID_HANDLE_VALUE; }
+  virtual void setWrtPipeHandle(HANDLE) {}
+  virtual bool isBufferedDataAvailable() { return false; }
+  virtual HANDLE getNativeWaitHandle() { return INVALID_HANDLE_VALUE; }
+};
+
+class TNamedPipeImpl : public TPipeImpl {
+public:
+  explicit TNamedPipeImpl(TAutoHandle &pipehandle) : Pipe_(pipehandle.release()) {}
+  virtual ~TNamedPipeImpl() {}
+  virtual uint32_t read(uint8_t* buf, uint32_t len) {
+    return pseudo_sync_read(Pipe_.h, read_event_.h, buf, len);
+  }
+  virtual void write(const uint8_t* buf, uint32_t len) {
+    pseudo_sync_write(Pipe_.h, write_event_.h, buf, len);
+  }
+
+  virtual HANDLE getPipeHandle() { return Pipe_.h; }
+  virtual void setPipeHandle(HANDLE pipehandle) { Pipe_.reset(pipehandle); }
+
+private:
+  TManualResetEvent read_event_;
+  TManualResetEvent write_event_;
+  TAutoHandle Pipe_;
+};
+
+class TAnonPipeImpl : public TPipeImpl {
+public:
+  TAnonPipeImpl(HANDLE PipeRd, HANDLE PipeWrt) : PipeRd_(PipeRd), PipeWrt_(PipeWrt) {}
+  virtual ~TAnonPipeImpl() {}
+  virtual uint32_t read(uint8_t* buf, uint32_t len) { return pipe_read(PipeRd_.h, buf, len); }
+  virtual void write(const uint8_t* buf, uint32_t len) { pipe_write(PipeWrt_.h, buf, len); }
+
+  virtual HANDLE getPipeHandle() { return PipeRd_.h; }
+  virtual void setPipeHandle(HANDLE PipeRd) { PipeRd_.reset(PipeRd); }
+  virtual HANDLE getWrtPipeHandle() { return PipeWrt_.h; }
+  virtual void setWrtPipeHandle(HANDLE PipeWrt) { PipeWrt_.reset(PipeWrt); }
+
+private:
+  TAutoHandle PipeRd_;
+  TAutoHandle PipeWrt_;
+};
+
+// If you want a select-like loop to work, use this subclass.  Be warned...
+// the read implementation has several context switches, so this is slower
+// than using the regular named pipe implementation
+class TWaitableNamedPipeImpl : public TPipeImpl {
+public:
+  explicit TWaitableNamedPipeImpl(TAutoHandle &pipehandle)
+    : begin_unread_idx_(0), end_unread_idx_(0) {
+    readOverlap_.action = TOverlappedWorkItem::READ;
+    readOverlap_.h = pipehandle.h;
+    cancelOverlap_.action = TOverlappedWorkItem::CANCELIO;
+    cancelOverlap_.h = pipehandle.h;
+    buffer_.resize(1024 /*arbitrary buffer size*/, '\0');
+    beginAsyncRead(&buffer_[0], static_cast<uint32_t>(buffer_.size()));
+    Pipe_.reset(pipehandle.release());
+  }
+  virtual ~TWaitableNamedPipeImpl() {
+    // see if there is an outstanding read request
+    if (begin_unread_idx_ == end_unread_idx_) {
+      // if so, cancel it, and wait for the dead completion
+      thread_->addWorkItem(&cancelOverlap_);
+      readOverlap_.overlappedResults(false /*ignore errors*/);
+    }
+  }
+  virtual uint32_t read(uint8_t* buf, uint32_t len);
+  virtual void write(const uint8_t* buf, uint32_t len) {
+    pseudo_sync_write(Pipe_.h, write_event_.h, buf, len);
+  }
+
+  virtual HANDLE getPipeHandle() { return Pipe_.h; }
+  virtual void setPipeHandle(HANDLE pipehandle) { Pipe_.reset(pipehandle); }
+  virtual bool isBufferedDataAvailable() { return begin_unread_idx_ < end_unread_idx_; }
+  virtual HANDLE getNativeWaitHandle() { return ready_event_.h; }
+
+private:
+  void beginAsyncRead(uint8_t* buf, uint32_t len);
+  uint32_t endAsyncRead();
+
+  TAutoOverlapThread thread_;
+  TAutoHandle Pipe_;
+  TOverlappedWorkItem readOverlap_;
+  TOverlappedWorkItem cancelOverlap_;
+  TManualResetEvent ready_event_;
+  TManualResetEvent write_event_;
+  std::vector<uint8_t> buffer_;
+  uint32_t begin_unread_idx_;
+  uint32_t end_unread_idx_;
+};
+
+void TWaitableNamedPipeImpl::beginAsyncRead(uint8_t* buf, uint32_t len) {
+  begin_unread_idx_ = end_unread_idx_ = 0;
+  readOverlap_.reset(buf, len, ready_event_.h);
+  thread_->addWorkItem(&readOverlap_);
+  if (readOverlap_.success == FALSE && readOverlap_.last_error != ERROR_IO_PENDING) {
+    GlobalOutput.perror("TPipe ::ReadFile errored GLE=", readOverlap_.last_error);
+    throw TTransportException(TTransportException::UNKNOWN, "TPipe: ReadFile failed");
+  }
+}
+
+uint32_t TWaitableNamedPipeImpl::endAsyncRead() {
+  return readOverlap_.overlappedResults();
+}
+
+uint32_t TWaitableNamedPipeImpl::read(uint8_t* buf, uint32_t len) {
+  if (begin_unread_idx_ == end_unread_idx_) {
+    end_unread_idx_ = endAsyncRead();
+  }
+
+  uint32_t __idxsize = end_unread_idx_ - begin_unread_idx_;
+  uint32_t bytes_to_copy = (len < __idxsize) ? len : __idxsize;
+  memcpy(buf, &buffer_[begin_unread_idx_], bytes_to_copy);
+  begin_unread_idx_ += bytes_to_copy;
+  if (begin_unread_idx_ != end_unread_idx_) {
+    assert(len == bytes_to_copy);
+    // we were able to fulfill the read with just the bytes in our
+    // buffer, and we still have buffer left
+    return bytes_to_copy;
+  }
+  uint32_t bytes_copied = bytes_to_copy;
+
+  // all of the requested data has been read.  Kick off an async read for the next round.
+  beginAsyncRead(&buffer_[0], static_cast<uint32_t>(buffer_.size()));
+
+  return bytes_copied;
+}
+
+void pseudo_sync_write(HANDLE pipe, HANDLE event, const uint8_t* buf, uint32_t len) {
+  OVERLAPPED tempOverlap;
+  memset(&tempOverlap, 0, sizeof(tempOverlap));
+  tempOverlap.hEvent = event;
+
+  uint32_t written = 0;
+  while (written < len) {
+    BOOL result = ::WriteFile(pipe, buf + written, len - written, NULL, &tempOverlap);
+
+    if (result == FALSE && ::GetLastError() != ERROR_IO_PENDING) {
+      GlobalOutput.perror("TPipe ::WriteFile errored GLE=", ::GetLastError());
+      throw TTransportException(TTransportException::UNKNOWN, "TPipe: write failed");
+    }
+
+    DWORD bytes = 0;
+    result = ::GetOverlappedResult(pipe, &tempOverlap, &bytes, TRUE);
+    if (!result) {
+      GlobalOutput.perror("TPipe ::GetOverlappedResult errored GLE=", ::GetLastError());
+      throw TTransportException(TTransportException::UNKNOWN, "TPipe: GetOverlappedResult failed");
+    }
+    written += bytes;
+  }
+}
+
+uint32_t pseudo_sync_read(HANDLE pipe, HANDLE event, uint8_t* buf, uint32_t len) {
+  OVERLAPPED tempOverlap;
+  memset(&tempOverlap, 0, sizeof(tempOverlap));
+  tempOverlap.hEvent = event;
+
+  BOOL result = ::ReadFile(pipe, buf, len, NULL, &tempOverlap);
+
+  if (result == FALSE && ::GetLastError() != ERROR_IO_PENDING) {
+    GlobalOutput.perror("TPipe ::ReadFile errored GLE=", ::GetLastError());
+    throw TTransportException(TTransportException::UNKNOWN, "TPipe: read failed");
+  }
+
+  DWORD bytes = 0;
+  result = ::GetOverlappedResult(pipe, &tempOverlap, &bytes, TRUE);
+  if (!result) {
+    GlobalOutput.perror("TPipe ::GetOverlappedResult errored GLE=", ::GetLastError());
+    throw TTransportException(TTransportException::UNKNOWN, "TPipe: GetOverlappedResult failed");
+  }
+  return bytes;
+}
+
 //---- Constructors ----
-TPipe::TPipe(HANDLE Pipe) :
-  Pipe_(Pipe),
-  TimeoutSeconds_(3),
-  isAnonymous(false)
-{}
+TPipe::TPipe(TAutoHandle &Pipe)
+  : impl_(new TWaitableNamedPipeImpl(Pipe)), TimeoutSeconds_(3), isAnonymous_(false) {
+}
 
-TPipe::TPipe(const char *pipename) :
-  Pipe_(INVALID_HANDLE_VALUE),
-  TimeoutSeconds_(3),
-  isAnonymous(false)
+TPipe::TPipe(HANDLE Pipe)
+  : TimeoutSeconds_(3), isAnonymous_(false)
 {
+  TAutoHandle pipeHandle(Pipe);
+  impl_.reset(new TWaitableNamedPipeImpl(pipeHandle));
+}
+
+TPipe::TPipe(const char* pipename) : TimeoutSeconds_(3), isAnonymous_(false) {
   setPipename(pipename);
 }
 
-TPipe::TPipe(const std::string &pipename) :
-  Pipe_(INVALID_HANDLE_VALUE),
-  TimeoutSeconds_(3),
-  isAnonymous(false)
-{
+TPipe::TPipe(const std::string& pipename) : TimeoutSeconds_(3), isAnonymous_(false) {
   setPipename(pipename);
 }
 
-TPipe::TPipe(HANDLE PipeRd, HANDLE PipeWrt) :
-  Pipe_(PipeRd),
-  PipeWrt_(PipeWrt),
-  TimeoutSeconds_(3),
-  isAnonymous(true)
-{}
+TPipe::TPipe(HANDLE PipeRd, HANDLE PipeWrt)
+  : impl_(new TAnonPipeImpl(PipeRd, PipeWrt)), TimeoutSeconds_(3), isAnonymous_(true) {
+}
 
-TPipe::TPipe() :
-  Pipe_(INVALID_HANDLE_VALUE),
-  TimeoutSeconds_(3)
-{}
+TPipe::TPipe() : TimeoutSeconds_(3), isAnonymous_(false) {
+}
 
-//---- Destructor ----
 TPipe::~TPipe() {
-  close();
 }
 
-
 //---------------------------------------------------------
 // Transport callbacks
 //---------------------------------------------------------
-
 bool TPipe::isOpen() {
-  return (Pipe_ != INVALID_HANDLE_VALUE);
+  return impl_.get() != NULL;
 }
 
 bool TPipe::peek() {
-  if (!isOpen()) {
-    return false;
-  }
-  DWORD bytesavail = 0;
-  int  PeekRet = 0;
-  PeekRet = PeekNamedPipe(Pipe_, NULL, 0, NULL, &bytesavail, NULL);
-  return (PeekRet != 0 && bytesavail > 0);
+  return isOpen();
 }
 
 void TPipe::open() {
-  if (isOpen()) {
+  if (isOpen())
     return;
-  }
 
-  int SleepInterval = 500; //ms
-  int retries = TimeoutSeconds_ * 1000 / SleepInterval;
-  HANDLE hPipe_;
-  for(int i=0; i<retries; i++)
-  {
-    hPipe_ = CreateFile(
-              pipename_.c_str(),
-              GENERIC_READ | GENERIC_WRITE,
-              0,              // no sharing
-              NULL,           // default security attributes
-              OPEN_EXISTING,  // opens existing pipe
-              0,              // default attributes
-              NULL);          // no template file
+  TAutoHandle hPipe;
+  do {
+    DWORD flags = FILE_FLAG_OVERLAPPED; // async mode, so we can do reads at the same time as writes
+    hPipe.reset(CreateFileA(pipename_.c_str(),
+                            GENERIC_READ | GENERIC_WRITE,
+                            0,             // no sharing
+                            NULL,          // default security attributes
+                            OPEN_EXISTING, // opens existing pipe
+                            flags,
+                            NULL)); // no template file
 
-    if (hPipe_ == INVALID_HANDLE_VALUE)
-      ::Sleep(SleepInterval);
-    else
-      break;
-  }
-  if (hPipe_ == INVALID_HANDLE_VALUE)
+    if (hPipe.h != INVALID_HANDLE_VALUE)
+      break; // success!
+
+    if (::GetLastError() != ERROR_PIPE_BUSY) {
+      GlobalOutput.perror("TPipe::open ::CreateFile errored GLE=", ::GetLastError());
+      throw TTransportException(TTransportException::NOT_OPEN, "Unable to open pipe");
+    }
+  } while (::WaitNamedPipeA(pipename_.c_str(), TimeoutSeconds_ * 1000));
+
+  if (hPipe.h == INVALID_HANDLE_VALUE) {
+    GlobalOutput.perror("TPipe::open ::CreateFile errored GLE=", ::GetLastError());
     throw TTransportException(TTransportException::NOT_OPEN, "Unable to open pipe");
-
-  // The pipe connected; change to message-read mode.
-  DWORD dwMode = PIPE_READMODE_MESSAGE;
-  int fSuccess = SetNamedPipeHandleState(
-              hPipe_, // pipe handle
-              &dwMode,  // new pipe mode
-              NULL,     // don't set maximum bytes
-              NULL);    // don't set maximum time
-  if (fSuccess == 0)
-  {
-    throw TTransportException(TTransportException::NOT_OPEN, "SetNamedPipeHandleState failed");
-    close();
   }
-  Pipe_ = hPipe_;
+
+  impl_.reset(new TNamedPipeImpl(hPipe));
 }
 
-
 void TPipe::close() {
-  if (isOpen())
-  {
-    CloseHandle(Pipe_);
-    Pipe_ = INVALID_HANDLE_VALUE;
-  }
+  impl_.reset();
 }
 
 uint32_t TPipe::read(uint8_t* buf, uint32_t len) {
   if (!isOpen())
     throw TTransportException(TTransportException::NOT_OPEN, "Called read on non-open pipe");
+  return impl_->read(buf, len);
+}
 
-  DWORD  cbRead;
-  int fSuccess = ReadFile(
-              Pipe_, // pipe handle
-              buf,      // buffer to receive reply
-              len,      // size of buffer
-              &cbRead,  // number of bytes read
-              NULL);    // not overlapped
+uint32_t pipe_read(HANDLE pipe, uint8_t* buf, uint32_t len) {
+  DWORD cbRead;
+  int fSuccess = ReadFile(pipe,    // pipe handle
+                          buf,     // buffer to receive reply
+                          len,     // size of buffer
+                          &cbRead, // number of bytes read
+                          NULL);   // not overlapped
 
-  if ( !fSuccess && GetLastError() != ERROR_MORE_DATA )
+  if (!fSuccess && GetLastError() != ERROR_MORE_DATA)
     return 0; // No more data, possibly because client disconnected.
 
   return cbRead;
@@ -160,17 +321,18 @@
 void TPipe::write(const uint8_t* buf, uint32_t len) {
   if (!isOpen())
     throw TTransportException(TTransportException::NOT_OPEN, "Called write on non-open pipe");
+  impl_->write(buf, len);
+}
 
-  HANDLE WritePipe = isAnonymous? PipeWrt_: Pipe_;
-  DWORD  cbWritten;
-  int fSuccess = WriteFile(
-              WritePipe, // pipe handle
-              buf,        // message
-              len,        // message length
-              &cbWritten, // bytes written
-              NULL);      // not overlapped
+void pipe_write(HANDLE pipe, const uint8_t* buf, uint32_t len) {
+  DWORD cbWritten;
+  int fSuccess = WriteFile(pipe,       // pipe handle
+                           buf,        // message
+                           len,        // message length
+                           &cbWritten, // bytes written
+                           NULL);      // not overlapped
 
-  if ( !fSuccess)
+  if (!fSuccess)
     throw TTransportException(TTransportException::NOT_OPEN, "Write to pipe failed");
 }
 
@@ -178,40 +340,59 @@
 // Accessors
 //---------------------------------------------------------
 
-string TPipe::getPipename() {
+std::string TPipe::getPipename() {
   return pipename_;
 }
 
-void TPipe::setPipename(const std::string &pipename) {
-  if(pipename.find("\\\\") == -1)
+void TPipe::setPipename(const std::string& pipename) {
+  if (pipename.find("\\\\") == std::string::npos)
     pipename_ = "\\\\.\\pipe\\" + pipename;
   else
     pipename_ = pipename;
 }
 
 HANDLE TPipe::getPipeHandle() {
-  return Pipe_;
+  if (impl_)
+    return impl_->getPipeHandle();
+  return INVALID_HANDLE_VALUE;
 }
 
 void TPipe::setPipeHandle(HANDLE pipehandle) {
-  Pipe_ = pipehandle;
+  if (isAnonymous_)
+    impl_->setPipeHandle(pipehandle);
+  else
+  {
+    TAutoHandle pipe(pipehandle);
+    impl_.reset(new TNamedPipeImpl(pipe));
+  }
 }
 
 HANDLE TPipe::getWrtPipeHandle() {
-  return PipeWrt_;
+  if (impl_)
+    return impl_->getWrtPipeHandle();
+  return INVALID_HANDLE_VALUE;
 }
 
 void TPipe::setWrtPipeHandle(HANDLE pipehandle) {
-  PipeWrt_ = pipehandle;
+  if (impl_)
+    impl_->setWrtPipeHandle(pipehandle);
 }
 
-long TPipe::getConnectTimeout() {
+HANDLE TPipe::getNativeWaitHandle() {
+  if (impl_)
+    return impl_->getNativeWaitHandle();
+  return INVALID_HANDLE_VALUE;
+}
+
+long TPipe::getConnTimeout() {
   return TimeoutSeconds_;
 }
 
-void TPipe::setConnectTimeout(long seconds) {
+void TPipe::setConnTimeout(long seconds) {
   TimeoutSeconds_ = seconds;
 }
-#endif //_WIN32
 
-}}} // apache::thrift::transport
+#endif //_WIN32
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/TPipe.h b/lib/cpp/src/thrift/transport/TPipe.h
index 3c1755b..aa14f95 100644
--- a/lib/cpp/src/thrift/transport/TPipe.h
+++ b/lib/cpp/src/thrift/transport/TPipe.h
@@ -23,26 +23,39 @@
 #include <thrift/transport/TTransport.h>
 #include <thrift/transport/TVirtualTransport.h>
 #ifndef _WIN32
-#  include <thrift/transport/TSocket.h>
+#include <thrift/transport/TSocket.h>
+#endif
+#ifdef _WIN32
+#include <thrift/windows/Sync.h>
+#endif
+#include <boost/noncopyable.hpp>
+#ifdef _WIN32
+#include <thrift/windows/Sync.h>
 #endif
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * Windows Pipes implementation of the TTransport interface.
- *
+ * Don't destroy a TPipe at global scope, as that will cause a thread join
+ * during DLLMain.  That also means that client objects using TPipe shouldn't be at global
+ * scope.
  */
 #ifdef _WIN32
-class TPipe : public TVirtualTransport<TPipe> {
- public:
+class TPipeImpl;
 
+class TPipe : public TVirtualTransport<TPipe> {
+public:
   // Constructs a new pipe object.
   TPipe();
   // Named pipe constructors -
-  explicit TPipe(HANDLE Pipe); //HANDLE is a void*
-  //need a const char * overload so string literals don't go to the HANDLE overload
-  explicit TPipe(const char *pipename);
-  explicit TPipe(const std::string &pipename);
+  explicit TPipe(HANDLE Pipe);       // HANDLE is a void*
+  explicit TPipe(TAutoHandle& Pipe); // this ctor will clear out / move from Pipe
+  // need a const char * overload so string literals don't go to the HANDLE overload
+  explicit TPipe(const char* pipename);
+  explicit TPipe(const std::string& pipename);
   // Anonymous pipe -
   TPipe(HANDLE PipeRd, HANDLE PipeWrt);
 
@@ -67,30 +80,34 @@
   // Writes to the pipe.
   virtual void write(const uint8_t* buf, uint32_t len);
 
-
-  //Accessors
+  // Accessors
   std::string getPipename();
-  void setPipename(const std::string &pipename);
-  HANDLE getPipeHandle(); //doubles as the read handle for anon pipe
+  void setPipename(const std::string& pipename);
+  HANDLE getPipeHandle(); // doubles as the read handle for anon pipe
   void setPipeHandle(HANDLE pipehandle);
   HANDLE getWrtPipeHandle();
   void setWrtPipeHandle(HANDLE pipehandle);
-  long getConnectTimeout();
-  void setConnectTimeout(long seconds);
+  long getConnTimeout();
+  void setConnTimeout(long seconds);
 
- private:
+  // this function is intended to be used in generic / template situations,
+  // so its name needs to be the same as TPipeServer's
+  HANDLE getNativeWaitHandle();
+
+private:
+  std::shared_ptr<TPipeImpl> impl_;
+
   std::string pipename_;
 
-  //Named pipe handles are R/W, while anonymous pipes are one or the other (half duplex).
-  HANDLE Pipe_, PipeWrt_;
   long TimeoutSeconds_;
-  bool isAnonymous;
+  bool isAnonymous_;
 };
+
 #else
 typedef TSocket TPipe;
 #endif
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_TPIPE_H_
-
diff --git a/lib/cpp/src/thrift/transport/TPipeServer.cpp b/lib/cpp/src/thrift/transport/TPipeServer.cpp
index 10fc69b..55c3580 100644
--- a/lib/cpp/src/thrift/transport/TPipeServer.cpp
+++ b/lib/cpp/src/thrift/transport/TPipeServer.cpp
@@ -22,249 +22,303 @@
 
 #include <thrift/transport/TPipe.h>
 #include <thrift/transport/TPipeServer.h>
-#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
 #ifdef _WIN32
-#  include <AccCtrl.h>
-#  include <Aclapi.h>
+#include <thrift/windows/OverlappedSubmissionThread.h>
+#include <AccCtrl.h>
+#include <Aclapi.h>
 #endif //_WIN32
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 #ifdef _WIN32
 
-using namespace std;
-using boost::shared_ptr;
+using std::shared_ptr;
 
-//---- Constructors ----
-TPipeServer::TPipeServer(const std::string &pipename, uint32_t bufsize) :
-  pipename_(pipename),
-  bufsize_(bufsize),
-  Pipe_(INVALID_HANDLE_VALUE),
-  wakeup(INVALID_HANDLE_VALUE),
-  maxconns_(TPIPE_SERVER_MAX_CONNS_DEFAULT),
-  isAnonymous(false),
-  stop_(false)
- {
-    setPipename(pipename);
-    createWakeupEvent();
- }
+class TPipeServerImpl : boost::noncopyable {
+public:
+  TPipeServerImpl() {}
+  virtual ~TPipeServerImpl() {}
+  virtual void interrupt() = 0;
+  virtual std::shared_ptr<TTransport> acceptImpl() = 0;
 
-TPipeServer::TPipeServer(const std::string &pipename, uint32_t bufsize, uint32_t maxconnections) :
-  pipename_(pipename),
-  bufsize_(bufsize),
-  Pipe_(INVALID_HANDLE_VALUE),
-  wakeup(INVALID_HANDLE_VALUE),
-  isAnonymous(false),
-  stop_(false)
- {  //Restrict maxconns_ to 1-PIPE_UNLIMITED_INSTANCES
-    if(maxconnections == 0)
-      maxconns_ = 1;
-    else if (maxconnections > PIPE_UNLIMITED_INSTANCES)
-      maxconns_ = PIPE_UNLIMITED_INSTANCES;
-	else
-      maxconns_ = maxconnections;
+  virtual HANDLE getPipeHandle() = 0;
+  virtual HANDLE getWrtPipeHandle() = 0;
+  virtual HANDLE getClientRdPipeHandle() = 0;
+  virtual HANDLE getClientWrtPipeHandle() = 0;
+  virtual HANDLE getNativeWaitHandle() { return NULL; }
+};
 
-    setPipename(pipename);
-    createWakeupEvent();
- }
-
-TPipeServer::TPipeServer(const std::string &pipename) :
-  pipename_(pipename),
-  bufsize_(1024),
-  Pipe_(INVALID_HANDLE_VALUE),
-  wakeup(INVALID_HANDLE_VALUE),
-  maxconns_(TPIPE_SERVER_MAX_CONNS_DEFAULT),
-  isAnonymous(false),
-  stop_(false)
- {
-    setPipename(pipename);
-    createWakeupEvent();
- }
-
-TPipeServer::TPipeServer(int bufsize) :
-  pipename_(""),
-  bufsize_(bufsize),
-  Pipe_(INVALID_HANDLE_VALUE),
-  wakeup(INVALID_HANDLE_VALUE),
-  maxconns_(1),
-  isAnonymous(true),
-  stop_(false)
- {
-  //The anonymous pipe needs to be created first so that the server can
-  //pass the handles on to the client before the serve (acceptImpl)
-  //blocking call.
-  if (!TCreateAnonPipe()) {
-    GlobalOutput.perror("TPipeServer Create(Anon)Pipe failed, GLE=", GetLastError());
-    throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer Create(Anon)Pipe failed");
+class TAnonPipeServer : public TPipeServerImpl {
+public:
+  TAnonPipeServer() {
+    // The anonymous pipe needs to be created first so that the server can
+    // pass the handles on to the client before the serve (acceptImpl)
+    // blocking call.
+    if (!createAnonPipe()) {
+      GlobalOutput.perror("TPipeServer Create(Anon)Pipe failed, GLE=", GetLastError());
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                " TPipeServer Create(Anon)Pipe failed");
+    }
   }
-  createWakeupEvent();
+
+  virtual ~TAnonPipeServer() {
+    PipeR_.reset();
+    PipeW_.reset();
+    ClientAnonRead_.reset();
+    ClientAnonWrite_.reset();
+  }
+
+  virtual void interrupt() {} // not currently implemented
+
+  virtual std::shared_ptr<TTransport> acceptImpl();
+
+  virtual HANDLE getPipeHandle() { return PipeR_.h; }
+  virtual HANDLE getWrtPipeHandle() { return PipeW_.h; }
+  virtual HANDLE getClientRdPipeHandle() { return ClientAnonRead_.h; }
+  virtual HANDLE getClientWrtPipeHandle() { return ClientAnonWrite_.h; }
+
+private:
+  bool createAnonPipe();
+
+  TAutoHandle PipeR_; // Anonymous Pipe (R)
+  TAutoHandle PipeW_; // Anonymous Pipe (W)
+
+  // Client side anonymous pipe handles
+  //? Do we need duplicates to send to client?
+  TAutoHandle ClientAnonRead_;
+  TAutoHandle ClientAnonWrite_;
+};
+
+class TNamedPipeServer : public TPipeServerImpl {
+public:
+  TNamedPipeServer(const std::string& pipename, uint32_t bufsize, uint32_t maxconnections)
+    : stopping_(false), pipename_(pipename), bufsize_(bufsize), maxconns_(maxconnections)
+  {
+    connectOverlap_.action = TOverlappedWorkItem::CONNECT;
+    cancelOverlap_.action = TOverlappedWorkItem::CANCELIO;
+    TAutoCrit lock(pipe_protect_);
+    initiateNamedConnect(lock);
+  }
+  virtual ~TNamedPipeServer() {}
+
+  virtual void interrupt() {
+    TAutoCrit lock(pipe_protect_);
+    cached_client_.reset();
+    if (Pipe_.h != INVALID_HANDLE_VALUE) {
+      stopping_ = true;
+      cancelOverlap_.h = Pipe_.h;
+      // This should wake up GetOverlappedResult
+      thread_->addWorkItem(&cancelOverlap_);
+    }
+  }
+
+  virtual std::shared_ptr<TTransport> acceptImpl();
+
+  virtual HANDLE getPipeHandle() { return Pipe_.h; }
+  virtual HANDLE getWrtPipeHandle() { return INVALID_HANDLE_VALUE; }
+  virtual HANDLE getClientRdPipeHandle() { return INVALID_HANDLE_VALUE; }
+  virtual HANDLE getClientWrtPipeHandle() { return INVALID_HANDLE_VALUE; }
+  virtual HANDLE getNativeWaitHandle() { return listen_event_.h; }
+
+private:
+  bool createNamedPipe(const TAutoCrit &lockProof);
+  void initiateNamedConnect(const TAutoCrit &lockProof);
+
+  TAutoOverlapThread thread_;
+  TOverlappedWorkItem connectOverlap_;
+  TOverlappedWorkItem cancelOverlap_;
+
+  bool stopping_;
+  std::string pipename_;
+  uint32_t bufsize_;
+  uint32_t maxconns_;
+  TManualResetEvent listen_event_;
+
+  TCriticalSection pipe_protect_;
+  // only read or write these variables underneath a locked pipe_protect_
+  std::shared_ptr<TPipe> cached_client_;
+  TAutoHandle Pipe_;
+};
+
+HANDLE TPipeServer::getNativeWaitHandle() {
+  if (impl_)
+    return impl_->getNativeWaitHandle();
+  return NULL;
 }
 
-TPipeServer::TPipeServer() :
-  pipename_(""),
-  bufsize_(1024),
-  Pipe_(INVALID_HANDLE_VALUE),
-  wakeup(INVALID_HANDLE_VALUE),
-  maxconns_(1),
-  isAnonymous(true),
-  stop_(false)
-{
-  if (!TCreateAnonPipe()) {
-    GlobalOutput.perror("TPipeServer Create(Anon)Pipe failed, GLE=", GetLastError());
-    throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer Create(Anon)Pipe failed");
-  }
-  createWakeupEvent();
+//---- Constructors ----
+TPipeServer::TPipeServer(const std::string& pipename, uint32_t bufsize)
+  : bufsize_(bufsize), isAnonymous_(false) {
+  setMaxConnections(TPIPE_SERVER_MAX_CONNS_DEFAULT);
+  setPipename(pipename);
+}
+
+TPipeServer::TPipeServer(const std::string& pipename, uint32_t bufsize, uint32_t maxconnections)
+  : bufsize_(bufsize), isAnonymous_(false) {
+  setMaxConnections(maxconnections);
+  setPipename(pipename);
+}
+
+TPipeServer::TPipeServer(const std::string& pipename) : bufsize_(1024), isAnonymous_(false) {
+  setMaxConnections(TPIPE_SERVER_MAX_CONNS_DEFAULT);
+  setPipename(pipename);
+}
+
+TPipeServer::TPipeServer(int bufsize) : bufsize_(bufsize), isAnonymous_(true) {
+  setMaxConnections(1);
+  impl_.reset(new TAnonPipeServer);
+}
+
+TPipeServer::TPipeServer() : bufsize_(1024), isAnonymous_(true) {
+  setMaxConnections(1);
+  impl_.reset(new TAnonPipeServer);
 }
 
 //---- Destructor ----
-TPipeServer::~TPipeServer() {
-  close();
-  CloseHandle( wakeup);
-  wakeup = INVALID_HANDLE_VALUE;
-}
+TPipeServer::~TPipeServer() {}
 
 //---------------------------------------------------------
 // Transport callbacks
 //---------------------------------------------------------
+void TPipeServer::listen() {
+  if (isAnonymous_)
+    return;
+  impl_.reset(new TNamedPipeServer(pipename_, bufsize_, maxconns_));
+}
 
 shared_ptr<TTransport> TPipeServer::acceptImpl() {
-  shared_ptr<TPipe> client;
+  return impl_->acceptImpl();
+}
 
-  stop_ = FALSE;
+shared_ptr<TTransport> TAnonPipeServer::acceptImpl() {
+  // This 0-byte read serves merely as a blocking call.
+  byte buf;
+  DWORD br;
+  int fSuccess = ReadFile(PipeR_.h, // pipe handle
+                          &buf,     // buffer to receive reply
+                          0,        // size of buffer
+                          &br,      // number of bytes read
+                          NULL);    // not overlapped
 
-  if(isAnonymous)
-  { //Anonymous Pipe
-    //This 0-byte read serves merely as a blocking call.
-    byte buf;
-    DWORD br;
-    int fSuccess = ReadFile(
-          Pipe_, // pipe handle
-          &buf,   // buffer to receive reply
-          0,      // size of buffer
-          &br,    // number of bytes read
-          NULL);  // not overlapped
-
-    if ( !fSuccess && GetLastError() != ERROR_MORE_DATA ) {
-      GlobalOutput.perror("TPipeServer unable to initiate pipe comms, GLE=", GetLastError());
-      throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer unable to initiate pipe comms");
-    }
-    client.reset(new TPipe(Pipe_, PipeW_));
+  if (!fSuccess && GetLastError() != ERROR_MORE_DATA) {
+    GlobalOutput.perror("TPipeServer unable to initiate pipe comms, GLE=", GetLastError());
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              " TPipeServer unable to initiate pipe comms");
   }
-  else
-  { //Named Pipe
-    if (!TCreateNamedPipe()) {
-      GlobalOutput.perror("TPipeServer CreateNamedPipe failed, GLE=", GetLastError());
-      throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer CreateNamedPipe failed");
-    }
-
-    struct TEventCleaner {
-      HANDLE hEvent;
-      ~TEventCleaner() {CloseHandle(hEvent);}
-    };
-
-    OVERLAPPED overlapped;
-    memset( &overlapped, 0, sizeof(overlapped));
-    overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL);
-    {
-      TEventCleaner cleaner = {overlapped.hEvent};
-      while( ! stop_)
-      {
-        // Wait for the client to connect; if it succeeds, the
-        // function returns a nonzero value. If the function returns
-        // zero, GetLastError should return ERROR_PIPE_CONNECTED.
-        if( ConnectNamedPipe(Pipe_, &overlapped))
-        {
-          GlobalOutput.printf("Client connected.");
-          client.reset(new TPipe(Pipe_));
-          return client;
-        }
-
-        DWORD dwErr = GetLastError();
-        HANDLE events[2] = {overlapped.hEvent, wakeup};
-        switch( dwErr)
-        {
-        case ERROR_PIPE_CONNECTED:
-          GlobalOutput.printf("Client connected.");
-          client.reset(new TPipe(Pipe_));
-          return client;
-
-        case ERROR_IO_PENDING:
-          DWORD dwWait, dwDummy;
-          dwWait = WaitForMultipleObjects( 2, events, FALSE, 3000);
-          switch(dwWait)
-          {
-          case WAIT_OBJECT_0:
-            if(GetOverlappedResult(Pipe_, &overlapped, &dwDummy, TRUE))
-            {
-              GlobalOutput.printf("Client connected.");
-              client.reset(new TPipe(Pipe_));
-              return client;
-            }
-            break;
-          case WAIT_OBJECT_0 + 1:
-            stop_ = TRUE;
-            break;
-          default:
-            break;
-          }
-          break;
-
-        default:
-          break;
-        }
-
-        CancelIo(Pipe_);
-        DisconnectNamedPipe(Pipe_);
-      }
-
-      close();
-      GlobalOutput.perror("TPipeServer ConnectNamedPipe GLE=", GetLastError());
-      throw TTransportException(TTransportException::NOT_OPEN, "TPipeServer: client connection failed");
-    }
-  }
-
+  shared_ptr<TPipe> client(new TPipe(PipeR_.h, PipeW_.h));
   return client;
 }
 
-void TPipeServer::interrupt() {
-  if(Pipe_ != INVALID_HANDLE_VALUE) {
-    stop_ = TRUE;
-    CancelIo(Pipe_);
-    SetEvent(wakeup);
+void TNamedPipeServer::initiateNamedConnect(const TAutoCrit &lockProof) {
+  if (stopping_)
+    return;
+  if (!createNamedPipe(lockProof)) {
+    GlobalOutput.perror("TPipeServer CreateNamedPipe failed, GLE=", GetLastError());
+    throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer CreateNamedPipe failed");
   }
+
+  // The prior connection has been handled, so close the gate
+  ResetEvent(listen_event_.h);
+  connectOverlap_.reset(NULL, 0, listen_event_.h);
+  connectOverlap_.h = Pipe_.h;
+  thread_->addWorkItem(&connectOverlap_);
+
+  // Wait for the client to connect; if it succeeds, the
+  // function returns a nonzero value. If the function returns
+  // zero, GetLastError should return ERROR_PIPE_CONNECTED.
+  if (connectOverlap_.success) {
+    GlobalOutput.printf("Client connected.");
+    cached_client_.reset(new TPipe(Pipe_));
+    // make sure people know that a connection is ready
+    SetEvent(listen_event_.h);
+    return;
+  }
+
+  DWORD dwErr = connectOverlap_.last_error;
+  switch (dwErr) {
+  case ERROR_PIPE_CONNECTED:
+    GlobalOutput.printf("Client connected.");
+    cached_client_.reset(new TPipe(Pipe_));
+    // make sure people know that a connection is ready
+    SetEvent(listen_event_.h);
+    return;
+  case ERROR_IO_PENDING:
+    return; // acceptImpl will do the appropriate WaitForMultipleObjects
+  default:
+    GlobalOutput.perror("TPipeServer ConnectNamedPipe failed, GLE=", dwErr);
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              " TPipeServer ConnectNamedPipe failed");
+  }
+}
+
+shared_ptr<TTransport> TNamedPipeServer::acceptImpl() {
+  {
+    TAutoCrit lock(pipe_protect_);
+    if (cached_client_.get() != NULL) {
+      shared_ptr<TPipe> client;
+      // zero out cached_client, since we are about to return it.
+      client.swap(cached_client_);
+
+      // kick off the next connection before returning
+      initiateNamedConnect(lock);
+      return client; // success!
+    }
+  }
+
+  if (Pipe_.h == INVALID_HANDLE_VALUE) {
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "TNamedPipeServer: someone called accept on a closed pipe server");
+  }
+
+  DWORD dwDummy = 0;
+
+  // For the most part, Pipe_ should be protected with pipe_protect_.  We can't
+  // reasonably do that here though without breaking interruptability.  However,
+  // this should be safe, though I'm not happy about it.  We only need to ensure
+  // that no one writes / modifies Pipe_.h while we are reading it.  Well, the
+  // only two things that should be modifying Pipe_ are acceptImpl, the
+  // functions it calls, and the destructor.  Those things shouldn't be run
+  // concurrently anyway.  So this call is 'really' just a read that may happen
+  // concurrently with interrupt, and that should be fine.
+  if (GetOverlappedResult(Pipe_.h, &connectOverlap_.overlap, &dwDummy, TRUE)) {
+    TAutoCrit lock(pipe_protect_);
+    GlobalOutput.printf("Client connected.");
+    shared_ptr<TPipe> client(new TPipe(Pipe_));
+    // kick off the next connection before returning
+    initiateNamedConnect(lock);
+    return client; // success!
+  }
+  // if we got here, then we are in an error / shutdown case
+  DWORD gle = GetLastError(); // save error before doing cleanup
+  GlobalOutput.perror("TPipeServer ConnectNamedPipe GLE=", gle);
+  if(gle == ERROR_OPERATION_ABORTED) {
+    TAutoCrit lock(pipe_protect_);    	// Needed to insure concurrent thread to be out of interrupt.
+    throw TTransportException(TTransportException::INTERRUPTED, "TPipeServer: server interupted");
+  }
+  throw TTransportException(TTransportException::NOT_OPEN, "TPipeServer: client connection failed");
+}
+
+void TPipeServer::interrupt() {
+  if (impl_)
+    impl_->interrupt();
 }
 
 void TPipeServer::close() {
-  if(!isAnonymous)
-  {
-    if(Pipe_ != INVALID_HANDLE_VALUE) {
-      DisconnectNamedPipe(Pipe_);
-      CloseHandle(Pipe_);
-      Pipe_ = INVALID_HANDLE_VALUE;
-    }
-  }
-  else
-  {
-    try {
-      CloseHandle(Pipe_);
-      CloseHandle(PipeW_);
-      CloseHandle(ClientAnonRead);
-      CloseHandle(ClientAnonWrite);
-    }
-    catch(...) {
-        GlobalOutput.perror("TPipeServer anon close GLE=", GetLastError());
-    }
-  }
+  impl_.reset();
 }
 
+bool TNamedPipeServer::createNamedPipe(const TAutoCrit & /*lockProof*/) {
 
-bool TPipeServer::TCreateNamedPipe() {
-
-  //Windows - set security to allow non-elevated apps
-  //to access pipes created by elevated apps.
+  // Windows - set security to allow non-elevated apps
+  // to access pipes created by elevated apps.
   SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
   PSID everyone_sid = NULL;
-  AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyone_sid);
+  AllocateAndInitializeSid(
+      &SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyone_sid);
 
   EXPLICIT_ACCESS ea;
   ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
@@ -273,12 +327,12 @@
   ea.grfInheritance = NO_INHERITANCE;
   ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
   ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
-  ea.Trustee.ptstrName  = (LPSTR)everyone_sid;
+  ea.Trustee.ptstrName = static_cast<LPTSTR>(everyone_sid);
 
   PACL acl = NULL;
   SetEntriesInAcl(1, &ea, NULL, &acl);
 
-  PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH);
+  PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
   InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
   SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE);
 
@@ -288,115 +342,118 @@
   sa.bInheritHandle = FALSE;
 
   // Create an instance of the named pipe
-  HANDLE hPipe_ = CreateNamedPipe(
-        pipename_.c_str(),        // pipe name
-        PIPE_ACCESS_DUPLEX |      // read/write access
-        FILE_FLAG_OVERLAPPED,     // async mode
-        PIPE_TYPE_MESSAGE |       // message type pipe
-        PIPE_READMODE_MESSAGE,    // message-read mode
-        maxconns_,                // max. instances
-        bufsize_,                 // output buffer size
-        bufsize_,                 // input buffer size
-        0,                        // client time-out
-        &sa);                     // default security attribute
+  TAutoHandle hPipe(CreateNamedPipeA(pipename_.c_str(),    // pipe name
+                                     PIPE_ACCESS_DUPLEX |  // read/write access
+                                     FILE_FLAG_OVERLAPPED, // async mode
+                                     PIPE_TYPE_BYTE |      // byte type pipe
+                                     PIPE_READMODE_BYTE,   // byte read mode
+                                     maxconns_,            // max. instances
+                                     bufsize_,             // output buffer size
+                                     bufsize_,             // input buffer size
+                                     0,                    // client time-out
+                                     &sa));                // security attributes
 
-  if(hPipe_ == INVALID_HANDLE_VALUE)
-  {
-    Pipe_ = INVALID_HANDLE_VALUE;
-    GlobalOutput.perror("TPipeServer::TCreateNamedPipe() GLE=", GetLastError());
-    throw TTransportException(TTransportException::NOT_OPEN, "TCreateNamedPipe() failed", GetLastError());
+  DWORD lastError = GetLastError();
+  LocalFree(sd);
+  LocalFree(acl);
+  FreeSid(everyone_sid);
+
+  if (hPipe.h == INVALID_HANDLE_VALUE) {
+    Pipe_.reset();
+    GlobalOutput.perror("TPipeServer::TCreateNamedPipe() GLE=", lastError);
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "TCreateNamedPipe() failed",
+                lastError);
     return false;
   }
 
-  Pipe_ = hPipe_;
+  Pipe_.reset(hPipe.release());
   return true;
 }
 
-bool TPipeServer::TCreateAnonPipe() {
+bool TAnonPipeServer::createAnonPipe() {
   SECURITY_ATTRIBUTES sa;
-  SECURITY_DESCRIPTOR sd; //security information for pipes
+  SECURITY_DESCRIPTOR sd; // security information for pipes
 
-  InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
+  InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
   SetSecurityDescriptorDacl(&sd, true, NULL, false);
   sa.lpSecurityDescriptor = &sd;
   sa.nLength = sizeof(SECURITY_ATTRIBUTES);
-  sa.bInheritHandle = true; //allow passing handle to child
+  sa.bInheritHandle = true; // allow passing handle to child
 
   HANDLE ClientAnonReadH, PipeW_H, ClientAnonWriteH, Pipe_H;
-  if (!CreatePipe(&ClientAnonReadH,&PipeW_H,&sa,0))   //create stdin pipe
+  if (!CreatePipe(&ClientAnonReadH, &PipeW_H, &sa, 0)) // create stdin pipe
   {
     GlobalOutput.perror("TPipeServer CreatePipe (anon) failed, GLE=", GetLastError());
     return false;
   }
-  if (!CreatePipe(&Pipe_H,&ClientAnonWriteH,&sa,0))  //create stdout pipe
+  if (!CreatePipe(&Pipe_H, &ClientAnonWriteH, &sa, 0)) // create stdout pipe
   {
     GlobalOutput.perror("TPipeServer CreatePipe (anon) failed, GLE=", GetLastError());
     CloseHandle(ClientAnonReadH);
     CloseHandle(PipeW_H);
     return false;
   }
-  ClientAnonRead  = ClientAnonReadH;
-  ClientAnonWrite = ClientAnonWriteH;
-  Pipe_  = Pipe_H;
-  PipeW_ = PipeW_H;
+
+  ClientAnonRead_.reset(ClientAnonReadH);
+  ClientAnonWrite_.reset(ClientAnonWriteH);
+  PipeR_.reset(Pipe_H);
+  PipeW_.reset(PipeW_H);
 
   return true;
 }
 
-void TPipeServer::createWakeupEvent() {
-  wakeup = CreateEvent( NULL, TRUE, FALSE, NULL);
-}
-
-
 //---------------------------------------------------------
 // Accessors
 //---------------------------------------------------------
-
-string TPipeServer::getPipename() {
+std::string TPipeServer::getPipename() {
   return pipename_;
 }
 
-void TPipeServer::setPipename(const std::string &pipename) {
-  if(pipename.find("\\\\") == -1)
+void TPipeServer::setPipename(const std::string& pipename) {
+  if (pipename.find("\\\\") == std::string::npos)
     pipename_ = "\\\\.\\pipe\\" + pipename;
   else
     pipename_ = pipename;
 }
 
-int  TPipeServer::getBufferSize() {
+int TPipeServer::getBufferSize() {
   return bufsize_;
 }
-
 void TPipeServer::setBufferSize(int bufsize) {
   bufsize_ = bufsize;
 }
 
 HANDLE TPipeServer::getPipeHandle() {
-  return Pipe_;
+  return impl_ ? impl_->getPipeHandle() : INVALID_HANDLE_VALUE;
 }
-
-HANDLE TPipeServer::getWrtPipeHandle()
-{
-  return PipeW_;
+HANDLE TPipeServer::getWrtPipeHandle() {
+  return impl_ ? impl_->getWrtPipeHandle() : INVALID_HANDLE_VALUE;
 }
-
-HANDLE TPipeServer::getClientRdPipeHandle()
-{
-  return ClientAnonRead;
+HANDLE TPipeServer::getClientRdPipeHandle() {
+  return impl_ ? impl_->getClientRdPipeHandle() : INVALID_HANDLE_VALUE;
 }
-
-HANDLE TPipeServer::getClientWrtPipeHandle()
-{
-  return ClientAnonWrite;
+HANDLE TPipeServer::getClientWrtPipeHandle() {
+  return impl_ ? impl_->getClientWrtPipeHandle() : INVALID_HANDLE_VALUE;
 }
 
 bool TPipeServer::getAnonymous() {
-  return isAnonymous;
+  return isAnonymous_;
 }
-
 void TPipeServer::setAnonymous(bool anon) {
-  isAnonymous = anon;
+  isAnonymous_ = anon;
 }
-#endif //_WIN32
 
-}}} // apache::thrift::transport
+void TPipeServer::setMaxConnections(uint32_t maxconnections) {
+  if (maxconnections == 0)
+    maxconns_ = 1;
+  else if (maxconnections > PIPE_UNLIMITED_INSTANCES)
+    maxconns_ = PIPE_UNLIMITED_INSTANCES;
+  else
+    maxconns_ = maxconnections;
+}
+
+#endif //_WIN32
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/TPipeServer.h b/lib/cpp/src/thrift/transport/TPipeServer.h
old mode 100755
new mode 100644
index 88a8b6b..c9b13e5
--- a/lib/cpp/src/thrift/transport/TPipeServer.h
+++ b/lib/cpp/src/thrift/transport/TPipeServer.h
@@ -20,74 +20,84 @@
 #ifndef _THRIFT_TRANSPORT_TSERVERWINPIPES_H_
 #define _THRIFT_TRANSPORT_TSERVERWINPIPES_H_ 1
 
+#include <memory>
 #include <thrift/transport/TServerTransport.h>
-#include <boost/shared_ptr.hpp>
 #ifndef _WIN32
-#  include "TServerSocket.h"
+#include <thrift/transport/TServerSocket.h>
+#endif
+#ifdef _WIN32
+#include <thrift/windows/Sync.h>
 #endif
 
-#define TPIPE_SERVER_MAX_CONNS_DEFAULT 10
+#define TPIPE_SERVER_MAX_CONNS_DEFAULT PIPE_UNLIMITED_INSTANCES
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * Windows Pipes implementation of TServerTransport.
+ * Don't destroy a TPipeServer at global scope, as that will cause a thread join
+ * during DLLMain.  That also means that TServer's using TPipeServer shouldn't be at global
+ * scope.
  */
 #ifdef _WIN32
+class TPipeServerImpl;
+class TPipe;
+
 class TPipeServer : public TServerTransport {
- public:
-  //Constructors
+public:
+  // Constructors
   // Named Pipe -
-  TPipeServer(const std::string &pipename, uint32_t bufsize);
-  TPipeServer(const std::string &pipename, uint32_t bufsize, uint32_t maxconnections);
-  TPipeServer(const std::string &pipename);
+  TPipeServer(const std::string& pipename, uint32_t bufsize);
+  TPipeServer(const std::string& pipename, uint32_t bufsize, uint32_t maxconnections);
+  TPipeServer(const std::string& pipename);
   // Anonymous pipe -
   TPipeServer(int bufsize);
   TPipeServer();
 
-  //Destructor
-  ~TPipeServer();
+  // Destructor
+  virtual ~TPipeServer();
 
-  //Standard transport callbacks
-  void interrupt();
-  void close();
- protected:
-  boost::shared_ptr<TTransport> acceptImpl();
+  // Standard transport callbacks
+  virtual void interrupt();
+  virtual void close();
+  virtual void listen();
 
-  bool TCreateNamedPipe();
-  bool TCreateAnonPipe();
-  void createWakeupEvent();
-
- public:
-  //Accessors
+  // Accessors
   std::string getPipename();
-  void setPipename(const std::string &pipename);
-  int  getBufferSize();
+  void setPipename(const std::string& pipename);
+  int getBufferSize();
   void setBufferSize(int bufsize);
-  HANDLE getPipeHandle();  //Named Pipe R/W -or- Anonymous pipe Read handle
+  HANDLE getPipeHandle(); // Named Pipe R/W -or- Anonymous pipe Read handle
   HANDLE getWrtPipeHandle();
   HANDLE getClientRdPipeHandle();
   HANDLE getClientWrtPipeHandle();
   bool getAnonymous();
   void setAnonymous(bool anon);
+  void setMaxConnections(uint32_t maxconnections);
 
- private:
+  // this function is intended to be used in generic / template situations,
+  // so its name needs to be the same as TPipe's
+  HANDLE getNativeWaitHandle();
+
+protected:
+  virtual std::shared_ptr<TTransport> acceptImpl();
+
+private:
+  std::shared_ptr<TPipeServerImpl> impl_;
+
   std::string pipename_;
   uint32_t bufsize_;
-  HANDLE Pipe_;  //Named Pipe (R/W) or Anonymous Pipe (R)
   uint32_t maxconns_;
-  HANDLE PipeW_; //Anonymous Pipe (W)
-  HANDLE ClientAnonRead, ClientAnonWrite; //Client side anonymous pipe handles
-  HANDLE wakeup;  // wake up event
-  //? Do we need duplicates to send to client?
-  bool isAnonymous;
-  bool stop_; // stop flag
+  bool isAnonymous_;
 };
 #else //_WIN32
 //*NIX named pipe implementation uses domain socket
 typedef TServerSocket TPipeServer;
 #endif
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_TSERVERWINPIPES_H_
diff --git a/lib/cpp/src/thrift/transport/TSSLServerSocket.cpp b/lib/cpp/src/thrift/transport/TSSLServerSocket.cpp
index 4689e4a..34605c0 100644
--- a/lib/cpp/src/thrift/transport/TSSLServerSocket.cpp
+++ b/lib/cpp/src/thrift/transport/TSSLServerSocket.cpp
@@ -20,28 +20,41 @@
 #include <thrift/transport/TSSLServerSocket.h>
 #include <thrift/transport/TSSLSocket.h>
 
-namespace apache { namespace thrift { namespace transport {
-
-using namespace boost;
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * SSL server socket implementation.
  */
+TSSLServerSocket::TSSLServerSocket(int port, std::shared_ptr<TSSLSocketFactory> factory)
+  : TServerSocket(port), factory_(factory) {
+  factory_->server(true);
+}
+
+TSSLServerSocket::TSSLServerSocket(const std::string& address,
+                                   int port,
+                                   std::shared_ptr<TSSLSocketFactory> factory)
+  : TServerSocket(address, port), factory_(factory) {
+  factory_->server(true);
+}
+
 TSSLServerSocket::TSSLServerSocket(int port,
-                                   shared_ptr<TSSLSocketFactory> factory):
-                                   TServerSocket(port), factory_(factory) {
+                                   int sendTimeout,
+                                   int recvTimeout,
+                                   std::shared_ptr<TSSLSocketFactory> factory)
+  : TServerSocket(port, sendTimeout, recvTimeout), factory_(factory) {
   factory_->server(true);
 }
 
-TSSLServerSocket::TSSLServerSocket(int port, int sendTimeout, int recvTimeout,
-                                   shared_ptr<TSSLSocketFactory> factory):
-                                   TServerSocket(port, sendTimeout, recvTimeout),
-                                   factory_(factory) {
-  factory_->server(true);
-}
+std::shared_ptr<TSocket> TSSLServerSocket::createSocket(THRIFT_SOCKET client) {
+  if (interruptableChildren_) {
+      return factory_->createSocket(client, pChildInterruptSockReader_);
 
-shared_ptr<TSocket> TSSLServerSocket::createSocket(int client) {
-  return factory_->createSocket(client);
+  } else {
+      return factory_->createSocket(client);
+  }
 }
-
-}}}
+}
+}
+}
diff --git a/lib/cpp/src/thrift/transport/TSSLServerSocket.h b/lib/cpp/src/thrift/transport/TSSLServerSocket.h
index 6d8e657..8b75de8 100644
--- a/lib/cpp/src/thrift/transport/TSSLServerSocket.h
+++ b/lib/cpp/src/thrift/transport/TSSLServerSocket.h
@@ -20,40 +20,57 @@
 #ifndef _THRIFT_TRANSPORT_TSSLSERVERSOCKET_H_
 #define _THRIFT_TRANSPORT_TSSLSERVERSOCKET_H_ 1
 
-#include <boost/shared_ptr.hpp>
 #include <thrift/transport/TServerSocket.h>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 class TSSLSocketFactory;
 
 /**
  * Server socket that accepts SSL connections.
  */
-class TSSLServerSocket: public TServerSocket {
- public:
+class TSSLServerSocket : public TServerSocket {
+public:
   /**
-   * Constructor.
+   * Constructor.  Binds to all interfaces.
    *
    * @param port    Listening port
    * @param factory SSL socket factory implementation
    */
-  TSSLServerSocket(int port, boost::shared_ptr<TSSLSocketFactory> factory);
+  TSSLServerSocket(int port, std::shared_ptr<TSSLSocketFactory> factory);
+
   /**
-   * Constructor.
+   * Constructor.  Binds to the specified address.
+   *
+   * @param address Address to bind to
+   * @param port    Listening port
+   * @param factory SSL socket factory implementation
+   */
+  TSSLServerSocket(const std::string& address,
+                   int port,
+                   std::shared_ptr<TSSLSocketFactory> factory);
+
+  /**
+   * Constructor.  Binds to all interfaces.
    *
    * @param port        Listening port
    * @param sendTimeout Socket send timeout
    * @param recvTimeout Socket receive timeout
    * @param factory     SSL socket factory implementation
    */
-  TSSLServerSocket(int port, int sendTimeout, int recvTimeout,
-                   boost::shared_ptr<TSSLSocketFactory> factory);
- protected:
-  boost::shared_ptr<TSocket> createSocket(int socket);
-  boost::shared_ptr<TSSLSocketFactory> factory_;
-};
+  TSSLServerSocket(int port,
+                   int sendTimeout,
+                   int recvTimeout,
+                   std::shared_ptr<TSSLSocketFactory> factory);
 
-}}}
+protected:
+  std::shared_ptr<TSocket> createSocket(THRIFT_SOCKET socket);
+  std::shared_ptr<TSSLSocketFactory> factory_;
+};
+}
+}
+}
 
 #endif
diff --git a/lib/cpp/src/thrift/transport/TSSLSocket.cpp b/lib/cpp/src/thrift/transport/TSSLSocket.cpp
index 029c541..718e9b1 100644
--- a/lib/cpp/src/thrift/transport/TSSLSocket.cpp
+++ b/lib/cpp/src/thrift/transport/TSSLSocket.cpp
@@ -21,6 +21,7 @@
 
 #include <errno.h>
 #include <string>
+#include <cstring>
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
@@ -28,8 +29,21 @@
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif
-#include <boost/lexical_cast.hpp>
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#define OPENSSL_VERSION_NO_THREAD_ID_BEFORE    0x10000000L
+#define OPENSSL_ENGINE_CLEANUP_REQUIRED_BEFORE 0x10100000L
+
 #include <boost/shared_array.hpp>
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER < OPENSSL_ENGINE_CLEANUP_REQUIRED_BEFORE)
+#include <openssl/engine.h>
+#endif
 #include <openssl/err.h>
 #include <openssl/rand.h>
 #include <openssl/ssl.h>
@@ -37,33 +51,148 @@
 #include <thrift/concurrency/Mutex.h>
 #include <thrift/transport/TSSLSocket.h>
 #include <thrift/transport/PlatformSocket.h>
+#include <thrift/TToString.h>
 
-#define OPENSSL_VERSION_NO_THREAD_ID 0x10000000L
-
-using namespace std;
-using namespace boost;
 using namespace apache::thrift::concurrency;
+using std::string;
 
 struct CRYPTO_dynlock_value {
   Mutex mutex;
 };
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
+// OpenSSL initialization/cleanup
 
-static void buildErrors(string& message, int error = 0);
+static bool openSSLInitialized = false;
+static boost::shared_array<Mutex> mutexes;
+
+static void callbackLocking(int mode, int n, const char*, int) {
+  if (mode & CRYPTO_LOCK) {
+    // assertion of (px != 0) here typically means that a TSSLSocket's lifetime
+    // exceeded the lifetime of the TSSLSocketFactory that created it, and the
+    // TSSLSocketFactory already ran cleanupOpenSSL(), which deleted "mutexes".
+    mutexes[n].lock();
+  } else {
+    mutexes[n].unlock();
+  }
+}
+
+#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_NO_THREAD_ID_BEFORE)
+static unsigned long callbackThreadID() {
+#ifdef _WIN32
+  return (unsigned long)GetCurrentThreadId();
+#else
+  return (unsigned long)pthread_self();
+#endif
+}
+#endif
+
+static CRYPTO_dynlock_value* dyn_create(const char*, int) {
+  return new CRYPTO_dynlock_value;
+}
+
+static void dyn_lock(int mode, struct CRYPTO_dynlock_value* lock, const char*, int) {
+  if (lock != NULL) {
+    if (mode & CRYPTO_LOCK) {
+      lock->mutex.lock();
+    } else {
+      lock->mutex.unlock();
+    }
+  }
+}
+
+static void dyn_destroy(struct CRYPTO_dynlock_value* lock, const char*, int) {
+  delete lock;
+}
+
+void initializeOpenSSL() {
+  if (openSSLInitialized) {
+    return;
+  }
+  openSSLInitialized = true;
+  SSL_library_init();
+  SSL_load_error_strings();
+  ERR_load_crypto_strings();
+
+  // static locking
+  // newer versions of OpenSSL changed CRYPTO_num_locks - see THRIFT-3878
+#ifdef CRYPTO_num_locks
+  mutexes = boost::shared_array<Mutex>(new Mutex[CRYPTO_num_locks()]);
+#else
+  mutexes = boost::shared_array<Mutex>(new Mutex[ ::CRYPTO_num_locks()]);
+#endif
+
+#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_NO_THREAD_ID_BEFORE)
+  CRYPTO_set_id_callback(callbackThreadID);
+#endif
+
+  CRYPTO_set_locking_callback(callbackLocking);
+
+  // dynamic locking
+  CRYPTO_set_dynlock_create_callback(dyn_create);
+  CRYPTO_set_dynlock_lock_callback(dyn_lock);
+  CRYPTO_set_dynlock_destroy_callback(dyn_destroy);
+}
+
+void cleanupOpenSSL() {
+  if (!openSSLInitialized) {
+    return;
+  }
+  openSSLInitialized = false;
+
+  // https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
+  // we purposefully do NOT call FIPS_mode_set(0) and leave it up to the enclosing application to manage FIPS entirely
+#if (OPENSSL_VERSION_NUMBER < OPENSSL_ENGINE_CLEANUP_REQUIRED_BEFORE)
+  ENGINE_cleanup();             // https://www.openssl.org/docs/man1.1.0/crypto/ENGINE_cleanup.html - cleanup call is needed before 1.1.0
+#endif
+  CONF_modules_unload(1);
+  EVP_cleanup();
+  CRYPTO_cleanup_all_ex_data();
+  ERR_remove_state(0);
+  ERR_free_strings();
+
+  mutexes.reset();
+}
+
+static void buildErrors(string& message, int errno_copy = 0, int sslerrno = 0);
 static bool matchName(const char* host, const char* pattern, int size);
 static char uppercase(char c);
 
 // SSLContext implementation
-SSLContext::SSLContext() {
-  ctx_ = SSL_CTX_new(TLSv1_method());
+SSLContext::SSLContext(const SSLProtocol& protocol) {
+  if (protocol == SSLTLS) {
+    ctx_ = SSL_CTX_new(SSLv23_method());
+#ifndef OPENSSL_NO_SSL3
+  } else if (protocol == SSLv3) {
+    ctx_ = SSL_CTX_new(SSLv3_method());
+#endif
+  } else if (protocol == TLSv1_0) {
+    ctx_ = SSL_CTX_new(TLSv1_method());
+  } else if (protocol == TLSv1_1) {
+    ctx_ = SSL_CTX_new(TLSv1_1_method());
+  } else if (protocol == TLSv1_2) {
+    ctx_ = SSL_CTX_new(TLSv1_2_method());
+  } else {
+    /// UNKNOWN PROTOCOL!
+    throw TSSLException("SSL_CTX_new: Unknown protocol");
+  }
+
   if (ctx_ == NULL) {
     string errors;
     buildErrors(errors);
     throw TSSLException("SSL_CTX_new: " + errors);
   }
   SSL_CTX_set_mode(ctx_, SSL_MODE_AUTO_RETRY);
+
+  // Disable horribly insecure SSLv2 and SSLv3 protocols but allow a handshake
+  // with older clients so they get a graceful denial.
+  if (protocol == SSLTLS) {
+      SSL_CTX_set_options(ctx_, SSL_OP_NO_SSLv2);
+      SSL_CTX_set_options(ctx_, SSL_OP_NO_SSLv3);   // THRIFT-3164
+  }
 }
 
 SSLContext::~SSLContext() {
@@ -84,53 +213,113 @@
 }
 
 // TSSLSocket implementation
-TSSLSocket::TSSLSocket(boost::shared_ptr<SSLContext> ctx):
-  TSocket(), server_(false), ssl_(NULL), ctx_(ctx) {
+TSSLSocket::TSSLSocket(std::shared_ptr<SSLContext> ctx)
+  : TSocket(), server_(false), ssl_(NULL), ctx_(ctx) {
+  init();
 }
 
-TSSLSocket::TSSLSocket(boost::shared_ptr<SSLContext> ctx, int socket):
-  TSocket(socket), server_(false), ssl_(NULL), ctx_(ctx) {
+TSSLSocket::TSSLSocket(std::shared_ptr<SSLContext> ctx, std::shared_ptr<THRIFT_SOCKET> interruptListener)
+        : TSocket(), server_(false), ssl_(NULL), ctx_(ctx) {
+  init();
+  interruptListener_ = interruptListener;
 }
 
-TSSLSocket::TSSLSocket(boost::shared_ptr<SSLContext> ctx, string host, int port):
-  TSocket(host, port), server_(false), ssl_(NULL), ctx_(ctx) {
+TSSLSocket::TSSLSocket(std::shared_ptr<SSLContext> ctx, THRIFT_SOCKET socket)
+  : TSocket(socket), server_(false), ssl_(NULL), ctx_(ctx) {
+  init();
+}
+
+TSSLSocket::TSSLSocket(std::shared_ptr<SSLContext> ctx, THRIFT_SOCKET socket, std::shared_ptr<THRIFT_SOCKET> interruptListener)
+        : TSocket(socket, interruptListener), server_(false), ssl_(NULL), ctx_(ctx) {
+  init();
+}
+
+TSSLSocket::TSSLSocket(std::shared_ptr<SSLContext> ctx, string host, int port)
+  : TSocket(host, port), server_(false), ssl_(NULL), ctx_(ctx) {
+  init();
+}
+
+TSSLSocket::TSSLSocket(std::shared_ptr<SSLContext> ctx, string host, int port, std::shared_ptr<THRIFT_SOCKET> interruptListener)
+        : TSocket(host, port), server_(false), ssl_(NULL), ctx_(ctx) {
+  init();
+  interruptListener_ = interruptListener;
 }
 
 TSSLSocket::~TSSLSocket() {
   close();
 }
 
+bool TSSLSocket::hasPendingDataToRead() {
+  if (!isOpen()) {
+    return false;
+  }
+  initializeHandshake();
+  if (!checkHandshake())
+    throw TSSLException("TSSLSocket::hasPendingDataToRead: Handshake is not completed");
+  // data may be available in SSL buffers (note: SSL_pending does not have a failure mode)
+  return SSL_pending(ssl_) > 0 || TSocket::hasPendingDataToRead();
+}
+
+void TSSLSocket::init() {
+  handshakeCompleted_ = false;
+  readRetryCount_ = 0;
+  eventSafe_ = false;
+}
+
 bool TSSLSocket::isOpen() {
   if (ssl_ == NULL || !TSocket::isOpen()) {
     return false;
   }
   int shutdown = SSL_get_shutdown(ssl_);
-  // "!!" is squelching C4800 "forcing bool -> true or false" perfomance warning
+  // "!!" is squelching C4800 "forcing bool -> true or false" performance warning
   bool shutdownReceived = !!(shutdown & SSL_RECEIVED_SHUTDOWN);
-  bool shutdownSent     = !!(shutdown & SSL_SENT_SHUTDOWN);
+  bool shutdownSent = !!(shutdown & SSL_SENT_SHUTDOWN);
   if (shutdownReceived && shutdownSent) {
     return false;
   }
   return true;
 }
 
+/*
+ * Note: This method is not libevent safe.
+*/
 bool TSSLSocket::peek() {
   if (!isOpen()) {
     return false;
   }
-  checkHandshake();
+  initializeHandshake();
+  if (!checkHandshake())
+    throw TSSLException("SSL_peek: Handshake is not completed");
   int rc;
   uint8_t byte;
-  rc = SSL_peek(ssl_, &byte, 1);
-  if (rc < 0) {
-    int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    string errors;
-    buildErrors(errors, errno_copy);
-    throw TSSLException("SSL_peek: " + errors);
-  }
-  if (rc == 0) {
-    ERR_clear_error();
-  }
+  do {
+    rc = SSL_peek(ssl_, &byte, 1);
+    if (rc < 0) {
+
+      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+      int error = SSL_get_error(ssl_, rc);
+      switch (error) {
+        case SSL_ERROR_SYSCALL:
+          if ((errno_copy != THRIFT_EINTR)
+              && (errno_copy != THRIFT_EAGAIN)) {
+            break;
+          }
+        // fallthrough
+        case SSL_ERROR_WANT_READ:
+        case SSL_ERROR_WANT_WRITE:
+          // in the case of SSL_ERROR_SYSCALL we want to wait for an read event again
+          waitForEvent(error != SSL_ERROR_WANT_WRITE);
+          continue;
+        default:;// do nothing
+      }
+      string errors;
+      buildErrors(errors, errno_copy, error);
+      throw TSSLException("SSL_peek: " + errors);
+    } else if (rc == 0) {
+      ERR_clear_error();
+      break;
+    }
+  } while (true);
   return (rc > 0);
 }
 
@@ -141,67 +330,234 @@
   TSocket::open();
 }
 
+/*
+ * Note: This method is not libevent safe.
+*/
 void TSSLSocket::close() {
   if (ssl_ != NULL) {
-    int rc = SSL_shutdown(ssl_);
-    if (rc == 0) {
-      rc = SSL_shutdown(ssl_);
-    }
-    if (rc < 0) {
-      int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      string errors;
-      buildErrors(errors, errno_copy);
-      GlobalOutput(("SSL_shutdown: " + errors).c_str());
+    try {
+      int rc;
+      int errno_copy = 0;
+      int error = 0;
+
+      do {
+        rc = SSL_shutdown(ssl_);
+        if (rc <= 0) {
+          errno_copy = THRIFT_GET_SOCKET_ERROR;
+          error = SSL_get_error(ssl_, rc);
+          switch (error) {
+            case SSL_ERROR_SYSCALL:
+              if ((errno_copy != THRIFT_EINTR)
+                  && (errno_copy != THRIFT_EAGAIN)) {
+                break;
+              }
+            // fallthrough
+            case SSL_ERROR_WANT_READ:
+            case SSL_ERROR_WANT_WRITE:
+              // in the case of SSL_ERROR_SYSCALL we want to wait for an write/read event again
+              waitForEvent(error == SSL_ERROR_WANT_READ);
+              rc = 2;
+            default:;// do nothing
+          }
+        }
+      } while (rc == 2);
+
+      if (rc < 0) {
+        string errors;
+        buildErrors(errors, errno_copy, error);
+        GlobalOutput(("SSL_shutdown: " + errors).c_str());
+      }
+    } catch (TTransportException& te) {
+      // Don't emit an exception because this method is called by the
+      // destructor. There's also not much that a user can do to recover, so
+      // just clean up as much as possible without throwing, similar to the rc
+      // < 0 case above.
+      GlobalOutput.printf("SSL_shutdown: %s", te.what());
     }
     SSL_free(ssl_);
     ssl_ = NULL;
+    handshakeCompleted_ = false;
     ERR_remove_state(0);
   }
   TSocket::close();
 }
 
+/*
+ * Returns number of bytes read in SSL Socket.
+ * If eventSafe is set, and it may returns 0 bytes then read method
+ * needs to be called again until it is successfull or it throws
+ * exception incase of failure.
+*/
 uint32_t TSSLSocket::read(uint8_t* buf, uint32_t len) {
-  checkHandshake();
+  initializeHandshake();
+  if (!checkHandshake())
+    throw TTransportException(TTransportException::UNKNOWN, "retry again");
   int32_t bytes = 0;
-  for (int32_t retries = 0; retries < maxRecvRetries_; retries++){
+  while (readRetryCount_ < maxRecvRetries_) {
     bytes = SSL_read(ssl_, buf, len);
-    if (bytes >= 0)
+    int32_t errno_copy = THRIFT_GET_SOCKET_ERROR;
+    int32_t error = SSL_get_error(ssl_, bytes);
+    readRetryCount_++;
+    if (error == SSL_ERROR_NONE) {
+      readRetryCount_ = 0;
       break;
-    int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    if (SSL_get_error(ssl_, bytes) == SSL_ERROR_SYSCALL) {
-      if (ERR_get_error() == 0 && errno_copy == THRIFT_EINTR) {
-        continue;
-      }
+    }
+    unsigned int waitEventReturn;
+    bool breakout = false;
+    switch (error) {
+      case SSL_ERROR_ZERO_RETURN:
+        throw TTransportException(TTransportException::END_OF_FILE, "client disconnected");
+
+      case SSL_ERROR_SYSCALL:
+        if (errno_copy == 0 && ERR_peek_error() == 0) {
+          breakout = true;
+          break;
+        }
+        if ((errno_copy != THRIFT_EINTR)
+            && (errno_copy != THRIFT_EAGAIN)) {
+              break;
+        }
+        if (readRetryCount_ >= maxRecvRetries_) {
+          // THRIFT_EINTR needs to be handled manually and we can tolerate
+          // a certain number
+          break;
+        }
+      // fallthrough
+
+      case SSL_ERROR_WANT_READ:
+      case SSL_ERROR_WANT_WRITE:
+        if (isLibeventSafe()) {
+          if (readRetryCount_ < maxRecvRetries_) {
+            // THRIFT_EINTR needs to be handled manually and we can tolerate
+            // a certain number
+            throw TTransportException(TTransportException::UNKNOWN, "retry again");
+          }
+          throw TTransportException(TTransportException::INTERNAL_ERROR, "too much recv retries");
+        }
+        // in the case of SSL_ERROR_SYSCALL we want to wait for an read event again
+        else if ((waitEventReturn = waitForEvent(error != SSL_ERROR_WANT_WRITE)) == TSSL_EINTR ) {
+          // repeat operation
+          if (readRetryCount_ < maxRecvRetries_) {
+            // THRIFT_EINTR needs to be handled manually and we can tolerate
+            // a certain number
+            continue;
+          }
+          throw TTransportException(TTransportException::INTERNAL_ERROR, "too much recv retries");
+        }
+        else if (waitEventReturn == TSSL_DATA) {
+            // in case of SSL and huge thrift packets, there may be a number of
+            // socket operations, before any data becomes available by SSL_read().
+            // Therefore the number of retries should not be increased and
+            // the operation should be repeated.
+            readRetryCount_--;
+            continue;
+        }
+        throw TTransportException(TTransportException::INTERNAL_ERROR, "unkown waitForEvent return value");
+      default:;// do nothing
+    }
+    if (breakout) {
+      break;
     }
     string errors;
-    buildErrors(errors, errno_copy);
+    buildErrors(errors, errno_copy, error);
     throw TSSLException("SSL_read: " + errors);
   }
   return bytes;
 }
 
 void TSSLSocket::write(const uint8_t* buf, uint32_t len) {
-  checkHandshake();
+  initializeHandshake();
+  if (!checkHandshake())
+    return;
   // loop in case SSL_MODE_ENABLE_PARTIAL_WRITE is set in SSL_CTX.
   uint32_t written = 0;
   while (written < len) {
+    ERR_clear_error();
     int32_t bytes = SSL_write(ssl_, &buf[written], len - written);
     if (bytes <= 0) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
+      int error = SSL_get_error(ssl_, bytes);
+      switch (error) {
+        case SSL_ERROR_SYSCALL:
+          if ((errno_copy != THRIFT_EINTR)
+              && (errno_copy != THRIFT_EAGAIN)) {
+            break;
+          }
+        // fallthrough        
+        case SSL_ERROR_WANT_READ:
+        case SSL_ERROR_WANT_WRITE:
+          if (isLibeventSafe()) {
+            return;
+          }
+          else {
+            // in the case of SSL_ERROR_SYSCALL we want to wait for an write event again
+            waitForEvent(error == SSL_ERROR_WANT_READ);
+            continue;
+          }
+        default:;// do nothing
+      }
       string errors;
-      buildErrors(errors, errno_copy);
+      buildErrors(errors, errno_copy, error);
       throw TSSLException("SSL_write: " + errors);
     }
     written += bytes;
   }
 }
 
+/*
+ * Returns number of bytes written in SSL Socket.
+ * If eventSafe is set, and it may returns 0 bytes then write method
+ * needs to be called again until it is successfull or it throws
+ * exception incase of failure.
+*/
+uint32_t TSSLSocket::write_partial(const uint8_t* buf, uint32_t len) {
+  initializeHandshake();
+  if (!checkHandshake())
+    return 0;
+  // loop in case SSL_MODE_ENABLE_PARTIAL_WRITE is set in SSL_CTX.
+  uint32_t written = 0;
+  while (written < len) {
+    ERR_clear_error();
+    int32_t bytes = SSL_write(ssl_, &buf[written], len - written);
+    if (bytes <= 0) {
+      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+      int error = SSL_get_error(ssl_, bytes);
+      switch (error) {
+        case SSL_ERROR_SYSCALL:
+          if ((errno_copy != THRIFT_EINTR)
+              && (errno_copy != THRIFT_EAGAIN)) {
+            break;
+          }
+        // fallthrough
+        case SSL_ERROR_WANT_READ:
+        case SSL_ERROR_WANT_WRITE:
+          if (isLibeventSafe()) {
+            return 0;
+          }
+          else {
+            // in the case of SSL_ERROR_SYSCALL we want to wait for an write event again
+            waitForEvent(error == SSL_ERROR_WANT_READ);
+            continue;
+          }
+        default:;// do nothing
+      }
+      string errors;
+      buildErrors(errors, errno_copy, error);
+      throw TSSLException("SSL_write: " + errors);
+    }
+    written += bytes;
+  }
+  return written;
+}
+
 void TSSLSocket::flush() {
   // Don't throw exception if not open. Thrift servers close socket twice.
   if (ssl_ == NULL) {
     return;
   }
-  checkHandshake();
+  initializeHandshake();
+  if (!checkHandshake())
+    throw TSSLException("BIO_flush: Handshake is not completed");
   BIO* bio = SSL_get_wbio(ssl_);
   if (bio == NULL) {
     throw TSSLException("SSL_get_wbio returns NULL");
@@ -214,36 +570,116 @@
   }
 }
 
-void TSSLSocket::checkHandshake() {
-  if (!TSocket::isOpen()) {
-    throw TTransportException(TTransportException::NOT_OPEN);
-  }
-  if (ssl_ != NULL) {
+void TSSLSocket::initializeHandshakeParams() {
+  // set underlying socket to non-blocking
+  int flags;
+  if ((flags = THRIFT_FCNTL(socket_, THRIFT_F_GETFL, 0)) < 0
+      || THRIFT_FCNTL(socket_, THRIFT_F_SETFL, flags | THRIFT_O_NONBLOCK) < 0) {
+    GlobalOutput.perror("thriftServerEventHandler: set THRIFT_O_NONBLOCK (THRIFT_FCNTL) ",
+                        THRIFT_GET_SOCKET_ERROR);
+    ::THRIFT_CLOSESOCKET(socket_);
     return;
   }
   ssl_ = ctx_->createSSL();
-  SSL_set_fd(ssl_, socket_);
+
+  SSL_set_fd(ssl_, static_cast<int>(socket_));
+}
+
+bool TSSLSocket::checkHandshake() {
+  return handshakeCompleted_;
+}
+
+void TSSLSocket::initializeHandshake() {
+  if (!TSocket::isOpen()) {
+    throw TTransportException(TTransportException::NOT_OPEN);
+  }
+  if (checkHandshake()) {
+    return;
+  }
+
+  if (ssl_ == NULL) {
+    initializeHandshakeParams();
+  }
+
   int rc;
+  int errno_copy = 0;
+  int error = 0;
   if (server()) {
-    rc = SSL_accept(ssl_);
+    do {
+      rc = SSL_accept(ssl_);
+      if (rc <= 0) {
+        errno_copy = THRIFT_GET_SOCKET_ERROR;
+        error = SSL_get_error(ssl_, rc);
+        switch (error) {
+          case SSL_ERROR_SYSCALL:
+            if ((errno_copy != THRIFT_EINTR)
+                && (errno_copy != THRIFT_EAGAIN)) {
+              break;
+            }
+          // fallthrough
+          case SSL_ERROR_WANT_READ:
+          case SSL_ERROR_WANT_WRITE:
+            if (isLibeventSafe()) {
+              return;
+            }
+            else {
+              // repeat operation
+              // in the case of SSL_ERROR_SYSCALL we want to wait for an write/read event again
+              waitForEvent(error == SSL_ERROR_WANT_READ);
+              rc = 2;
+            }
+          default:;// do nothing
+        }
+      }
+    } while (rc == 2);
   } else {
-    rc = SSL_connect(ssl_);
+    // OpenSSL < 0.9.8f does not have SSL_set_tlsext_host_name()
+    #if defined(SSL_set_tlsext_host_name)
+      // set the SNI hostname
+      SSL_set_tlsext_host_name(ssl_, getHost().c_str());
+    #endif
+    do {
+      rc = SSL_connect(ssl_);
+      if (rc <= 0) {
+        errno_copy = THRIFT_GET_SOCKET_ERROR;
+        error = SSL_get_error(ssl_, rc);
+        switch (error) {
+          case SSL_ERROR_SYSCALL:
+            if ((errno_copy != THRIFT_EINTR)
+                && (errno_copy != THRIFT_EAGAIN)) {
+              break;
+            }
+          // fallthrough
+          case SSL_ERROR_WANT_READ:
+          case SSL_ERROR_WANT_WRITE:
+            if (isLibeventSafe()) {
+              return;
+            }
+            else {
+              // repeat operation
+              // in the case of SSL_ERROR_SYSCALL we want to wait for an write/read event again
+              waitForEvent(error == SSL_ERROR_WANT_READ);
+              rc = 2;
+            }
+          default:;// do nothing
+        }
+      }
+    } while (rc == 2);
   }
   if (rc <= 0) {
-    int errno_copy = THRIFT_GET_SOCKET_ERROR;
     string fname(server() ? "SSL_accept" : "SSL_connect");
     string errors;
-    buildErrors(errors, errno_copy);
+    buildErrors(errors, errno_copy, error);
     throw TSSLException(fname + ": " + errors);
   }
   authorize();
+  handshakeCompleted_ = true;
 }
 
 void TSSLSocket::authorize() {
   int rc = SSL_get_verify_result(ssl_);
-  if (rc != X509_V_OK) {  // verify authentication result
-    throw TSSLException(string("SSL_get_verify_result(), ") +
-                        X509_verify_cert_error_string(rc));
+  if (rc != X509_V_OK) { // verify authentication result
+    throw TSSLException(string("SSL_get_verify_result(), ") + X509_verify_cert_error_string(rc));
   }
 
   X509* cert = SSL_get_peer_certificate(ssl_);
@@ -284,8 +720,8 @@
   }
 
   // extract subjectAlternativeName
-  STACK_OF(GENERAL_NAME)* alternatives = (STACK_OF(GENERAL_NAME)*)
-                       X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+  STACK_OF(GENERAL_NAME)* alternatives
+      = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
   if (alternatives != NULL) {
     const int count = sk_GENERAL_NAME_num(alternatives);
     for (int i = 0; decision == AccessManager::SKIP && i < count; i++) {
@@ -296,15 +732,15 @@
       char* data = (char*)ASN1_STRING_data(name->d.ia5);
       int length = ASN1_STRING_length(name->d.ia5);
       switch (name->type) {
-        case GEN_DNS:
-          if (host.empty()) {
-            host = (server() ? getPeerHost() : getHost());
-          }
-          decision = access_->verify(host, data, length);
-          break;
-        case GEN_IPADD:
-          decision = access_->verify(sa, data, length);
-          break;
+      case GEN_DNS:
+        if (host.empty()) {
+          host = (server() ? getPeerHost() : getHost());
+        }
+        decision = access_->verify(host, data, length);
+        break;
+      case GEN_IPADD:
+        decision = access_->verify(sa, data, length);
+        break;
       }
     }
     sk_GENERAL_NAME_pop_free(alternatives, GENERAL_NAME_free);
@@ -334,7 +770,7 @@
       ASN1_STRING* common = X509_NAME_ENTRY_get_data(entry);
       int size = ASN1_STRING_to_UTF8(&utf8, common);
       if (host.empty()) {
-        host = (server() ? getHost() : getHost());
+        host = (server() ? getPeerHost() : getHost());
       }
       decision = access_->verify(host, (char*)utf8, size);
       OPENSSL_free(utf8);
@@ -346,52 +782,134 @@
   }
 }
 
-// TSSLSocketFactory implementation
-bool     TSSLSocketFactory::initialized = false;
-uint64_t TSSLSocketFactory::count_ = 0;
-Mutex    TSSLSocketFactory::mutex_;
+/*
+ * Note: This method is not libevent safe.
+*/
+unsigned int TSSLSocket::waitForEvent(bool wantRead) {
+  int fdSocket;
+  BIO* bio;
 
-TSSLSocketFactory::TSSLSocketFactory(): server_(false) {
+  if (wantRead) {
+    bio = SSL_get_rbio(ssl_);
+  } else {
+    bio = SSL_get_wbio(ssl_);
+  }
+
+  if (bio == NULL) {
+    throw TSSLException("SSL_get_?bio returned NULL");
+  }
+
+  if (BIO_get_fd(bio, &fdSocket) <= 0) {
+    throw TSSLException("BIO_get_fd failed");
+  }
+
+  struct THRIFT_POLLFD fds[2];
+  memset(fds, 0, sizeof(fds));
+  fds[0].fd = fdSocket;
+  // use POLLIN also on write operations too, this is needed for operations
+  // which requires read and write on the socket.
+  fds[0].events = wantRead ? THRIFT_POLLIN : THRIFT_POLLIN | THRIFT_POLLOUT;
+
+  if (interruptListener_) {
+    fds[1].fd = *(interruptListener_.get());
+    fds[1].events = THRIFT_POLLIN;
+  }
+
+  int timeout = -1;
+  if (wantRead && recvTimeout_) {
+    timeout = recvTimeout_;
+  }
+  if (!wantRead && sendTimeout_) {
+    timeout = sendTimeout_;
+  }
+
+  int ret = THRIFT_POLL(fds, interruptListener_ ? 2 : 1, timeout);
+
+  if (ret < 0) {
+    // error cases
+    if (THRIFT_GET_SOCKET_ERROR == THRIFT_EINTR) {
+      return TSSL_EINTR; // repeat operation
+    }
+    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    GlobalOutput.perror("TSSLSocket::read THRIFT_POLL() ", errno_copy);
+    throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
+  } else if (ret > 0){
+    if (fds[1].revents & THRIFT_POLLIN) {
+      throw TTransportException(TTransportException::INTERRUPTED, "Interrupted");
+    }
+    return TSSL_DATA;
+  } else {
+    throw TTransportException(TTransportException::TIMED_OUT, "THRIFT_POLL (timed out)");
+  }
+}
+
+// TSSLSocketFactory implementation
+uint64_t TSSLSocketFactory::count_ = 0;
+Mutex TSSLSocketFactory::mutex_;
+bool TSSLSocketFactory::manualOpenSSLInitialization_ = false;
+
+TSSLSocketFactory::TSSLSocketFactory(SSLProtocol protocol) : server_(false) {
   Guard guard(mutex_);
   if (count_ == 0) {
-    initializeOpenSSL();
+    if (!manualOpenSSLInitialization_) {
+      initializeOpenSSL();
+    }
     randomize();
   }
   count_++;
-  ctx_ = boost::shared_ptr<SSLContext>(new SSLContext);
+  ctx_ = std::shared_ptr<SSLContext>(new SSLContext(protocol));
 }
 
 TSSLSocketFactory::~TSSLSocketFactory() {
   Guard guard(mutex_);
+  ctx_.reset();
   count_--;
-  if (count_ == 0) {
+  if (count_ == 0 && !manualOpenSSLInitialization_) {
     cleanupOpenSSL();
   }
 }
 
-boost::shared_ptr<TSSLSocket> TSSLSocketFactory::createSocket() {
-  boost::shared_ptr<TSSLSocket> ssl(new TSSLSocket(ctx_));
+std::shared_ptr<TSSLSocket> TSSLSocketFactory::createSocket() {
+  std::shared_ptr<TSSLSocket> ssl(new TSSLSocket(ctx_));
   setup(ssl);
   return ssl;
 }
 
-boost::shared_ptr<TSSLSocket> TSSLSocketFactory::createSocket(int socket) {
-  boost::shared_ptr<TSSLSocket> ssl(new TSSLSocket(ctx_, socket));
+std::shared_ptr<TSSLSocket> TSSLSocketFactory::createSocket(std::shared_ptr<THRIFT_SOCKET> interruptListener) {
+  std::shared_ptr<TSSLSocket> ssl(new TSSLSocket(ctx_, interruptListener));
   setup(ssl);
   return ssl;
 }
 
-boost::shared_ptr<TSSLSocket> TSSLSocketFactory::createSocket(const string& host,
-                                                       int port) {
-  boost::shared_ptr<TSSLSocket> ssl(new TSSLSocket(ctx_, host, port));
+std::shared_ptr<TSSLSocket> TSSLSocketFactory::createSocket(THRIFT_SOCKET socket) {
+  std::shared_ptr<TSSLSocket> ssl(new TSSLSocket(ctx_, socket));
   setup(ssl);
   return ssl;
 }
 
-void TSSLSocketFactory::setup(boost::shared_ptr<TSSLSocket> ssl) {
+std::shared_ptr<TSSLSocket> TSSLSocketFactory::createSocket(THRIFT_SOCKET socket, std::shared_ptr<THRIFT_SOCKET> interruptListener) {
+  std::shared_ptr<TSSLSocket> ssl(new TSSLSocket(ctx_, socket, interruptListener));
+  setup(ssl);
+  return ssl;
+}
+
+std::shared_ptr<TSSLSocket> TSSLSocketFactory::createSocket(const string& host, int port) {
+  std::shared_ptr<TSSLSocket> ssl(new TSSLSocket(ctx_, host, port));
+  setup(ssl);
+  return ssl;
+}
+
+std::shared_ptr<TSSLSocket> TSSLSocketFactory::createSocket(const string& host, int port, std::shared_ptr<THRIFT_SOCKET> interruptListener) {
+  std::shared_ptr<TSSLSocket> ssl(new TSSLSocket(ctx_, host, port, interruptListener));
+  setup(ssl);
+  return ssl;
+}
+
+
+void TSSLSocketFactory::setup(std::shared_ptr<TSSLSocket> ssl) {
   ssl->server(server());
   if (access_ == NULL && !server()) {
-    access_ = boost::shared_ptr<AccessManager>(new DefaultClientAccessManager);
+    access_ = std::shared_ptr<AccessManager>(new DefaultClientAccessManager);
   }
   if (access_ != NULL) {
     ssl->access(access_);
@@ -413,7 +931,7 @@
 void TSSLSocketFactory::authenticate(bool required) {
   int mode;
   if (required) {
-    mode  = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE;
+    mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE;
   } else {
     mode = SSL_VERIFY_NONE;
   }
@@ -423,7 +941,7 @@
 void TSSLSocketFactory::loadCertificate(const char* path, const char* format) {
   if (path == NULL || format == NULL) {
     throw TTransportException(TTransportException::BAD_ARGS,
-         "loadCertificateChain: either <path> or <format> is NULL");
+                              "loadCertificateChain: either <path> or <format> is NULL");
   }
   if (strcmp(format, "PEM") == 0) {
     if (SSL_CTX_use_certificate_chain_file(ctx_->get(), path) == 0) {
@@ -440,7 +958,7 @@
 void TSSLSocketFactory::loadPrivateKey(const char* path, const char* format) {
   if (path == NULL || format == NULL) {
     throw TTransportException(TTransportException::BAD_ARGS,
-         "loadPrivateKey: either <path> or <format> is NULL");
+                              "loadPrivateKey: either <path> or <format> is NULL");
   }
   if (strcmp(format, "PEM") == 0) {
     if (SSL_CTX_use_PrivateKey_file(ctx_->get(), path, SSL_FILETYPE_PEM) == 0) {
@@ -452,12 +970,12 @@
   }
 }
 
-void TSSLSocketFactory::loadTrustedCertificates(const char* path) {
+void TSSLSocketFactory::loadTrustedCertificates(const char* path, const char* capath) {
   if (path == NULL) {
     throw TTransportException(TTransportException::BAD_ARGS,
-         "loadTrustedCertificates: <path> is NULL");
+                              "loadTrustedCertificates: <path> is NULL");
   }
-  if (SSL_CTX_load_verify_locations(ctx_->get(), path, NULL) == 0) {
+  if (SSL_CTX_load_verify_locations(ctx_->get(), path, capath) == 0) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
     string errors;
     buildErrors(errors, errno_copy);
@@ -474,104 +992,23 @@
   SSL_CTX_set_default_passwd_cb_userdata(ctx_->get(), this);
 }
 
-int TSSLSocketFactory::passwordCallback(char* password,
-                                        int size,
-                                        int,
-                                        void* data) {
+int TSSLSocketFactory::passwordCallback(char* password, int size, int, void* data) {
   TSSLSocketFactory* factory = (TSSLSocketFactory*)data;
   string userPassword;
   factory->getPassword(userPassword, size);
-  int length = userPassword.size();
+  int length = static_cast<int>(userPassword.size());
   if (length > size) {
     length = size;
   }
   strncpy(password, userPassword.c_str(), length);
+  userPassword.assign(userPassword.size(), '*');
   return length;
 }
 
-static shared_array<Mutex> mutexes;
-
-static void callbackLocking(int mode, int n, const char*, int) {
-  if (mode & CRYPTO_LOCK) {
-    mutexes[n].lock();
-  } else {
-    mutexes[n].unlock();
-  }
-}
-
-#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_NO_THREAD_ID)
-static unsigned long callbackThreadID() {
-  return (unsigned long) pthread_self();
-}
-#endif
-
-static CRYPTO_dynlock_value* dyn_create(const char*, int) {
-  return new CRYPTO_dynlock_value;
-}
-
-static void dyn_lock(int mode,
-                     struct CRYPTO_dynlock_value* lock,
-                     const char*, int) {
-  if (lock != NULL) {
-    if (mode & CRYPTO_LOCK) {
-      lock->mutex.lock();
-    } else {
-      lock->mutex.unlock();
-    }
-  }
-}
-
-static void dyn_destroy(struct CRYPTO_dynlock_value* lock, const char*, int) {
-  delete lock;
-}
-
-void TSSLSocketFactory::initializeOpenSSL() {
-  if (initialized) {
-    return;
-  }
-  initialized = true;
-  SSL_library_init();
-  SSL_load_error_strings();
-  // static locking
-  mutexes = shared_array<Mutex>(new Mutex[::CRYPTO_num_locks()]);
-  if (mutexes == NULL) {
-    throw TTransportException(TTransportException::INTERNAL_ERROR,
-          "initializeOpenSSL() failed, "
-          "out of memory while creating mutex array");
-  }
-#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_NO_THREAD_ID)
-  CRYPTO_set_id_callback(callbackThreadID);
-#endif
-  CRYPTO_set_locking_callback(callbackLocking);
-  // dynamic locking
-  CRYPTO_set_dynlock_create_callback(dyn_create);
-  CRYPTO_set_dynlock_lock_callback(dyn_lock);
-  CRYPTO_set_dynlock_destroy_callback(dyn_destroy);
-}
-
-void TSSLSocketFactory::cleanupOpenSSL() {
-  if (!initialized) {
-    return;
-  }
-  initialized = false;
-#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_NO_THREAD_ID)
-  CRYPTO_set_id_callback(NULL);
-#endif
-  CRYPTO_set_locking_callback(NULL);
-  CRYPTO_set_dynlock_create_callback(NULL);
-  CRYPTO_set_dynlock_lock_callback(NULL);
-  CRYPTO_set_dynlock_destroy_callback(NULL);
-  CRYPTO_cleanup_all_ex_data();
-  ERR_free_strings();
-  EVP_cleanup();
-  ERR_remove_state(0);
-  mutexes.reset();
-}
-
 // extract error messages from error queue
-void buildErrors(string& errors, int errno_copy) {
-  unsigned long  errorCode;
-  char   message[256];
+void buildErrors(string& errors, int errno_copy, int sslerrno) {
+  unsigned long errorCode;
+  char message[256];
 
   errors.reserve(512);
   while ((errorCode = ERR_get_error()) != 0) {
@@ -591,22 +1028,32 @@
     }
   }
   if (errors.empty()) {
-    errors = "error code: " + lexical_cast<string>(errno_copy);
+    errors = "error code: " + to_string(errno_copy);
+  }
+  if (sslerrno) {
+    errors += " (SSL_error_code = " + to_string(sslerrno) + ")";
+    if (sslerrno == SSL_ERROR_SYSCALL) {
+      char buf[4096];
+      int err;
+      while ((err = ERR_get_error()) != 0) {
+        errors += " ";
+        errors += ERR_error_string(err, buf);
+      }
+    }
   }
 }
 
 /**
  * Default implementation of AccessManager
  */
-Decision DefaultClientAccessManager::verify(const sockaddr_storage& sa)
-  throw() {
-  (void) sa;
+Decision DefaultClientAccessManager::verify(const sockaddr_storage& sa) noexcept {
+  (void)sa;
   return SKIP;
 }
 
 Decision DefaultClientAccessManager::verify(const string& host,
                                             const char* name,
-                                            int size) throw() {
+                                            int size) noexcept {
   if (host.empty() || name == NULL || size <= 0) {
     return SKIP;
   }
@@ -615,7 +1062,7 @@
 
 Decision DefaultClientAccessManager::verify(const sockaddr_storage& sa,
                                             const char* data,
-                                            int size) throw() {
+                                            int size) noexcept {
   bool match = false;
   if (sa.ss_family == AF_INET && size == sizeof(in_addr)) {
     match = (memcmp(&((sockaddr_in*)&sa)->sin_addr, data, size) == 0);
@@ -656,16 +1103,16 @@
     match = true;
   }
   return match;
-
 }
 
 // This is to work around the Turkish locale issue, i.e.,
 // toupper('i') != toupper('I') if locale is "tr_TR"
-char uppercase (char c) {
+char uppercase(char c) {
   if ('a' <= c && c <= 'z') {
     return c + ('A' - 'a');
   }
   return c;
 }
-
-}}}
+}
+}
+}
diff --git a/lib/cpp/src/thrift/transport/TSSLSocket.h b/lib/cpp/src/thrift/transport/TSSLSocket.h
index 82a2e91..5a87d1e 100644
--- a/lib/cpp/src/thrift/transport/TSSLSocket.h
+++ b/lib/cpp/src/thrift/transport/TSSLSocket.h
@@ -20,38 +20,73 @@
 #ifndef _THRIFT_TRANSPORT_TSSLSOCKET_H_
 #define _THRIFT_TRANSPORT_TSSLSOCKET_H_ 1
 
-#include <string>
-#include <boost/shared_ptr.hpp>
-#include <openssl/ssl.h>
-#include <thrift/concurrency/Mutex.h>
+// Put this first to avoid WIN32 build failure
 #include <thrift/transport/TSocket.h>
 
-namespace apache { namespace thrift { namespace transport {
+#include <openssl/ssl.h>
+#include <string>
+#include <thrift/concurrency/Mutex.h>
+
+namespace apache {
+namespace thrift {
+namespace transport {
 
 class AccessManager;
 class SSLContext;
 
+enum SSLProtocol {
+  SSLTLS  = 0,  // Supports SSLv2 and SSLv3 handshake but only negotiates at TLSv1_0 or later.
+//SSLv2   = 1,  // HORRIBLY INSECURE!
+  SSLv3   = 2,  // Supports SSLv3 only - also horribly insecure!
+  TLSv1_0 = 3,  // Supports TLSv1_0 or later.
+  TLSv1_1 = 4,  // Supports TLSv1_1 or later.
+  TLSv1_2 = 5,  // Supports TLSv1_2 or later.
+  LATEST  = TLSv1_2
+};
+
+#define TSSL_EINTR 0
+#define TSSL_DATA 1
+
+/**
+ * Initialize OpenSSL library.  This function, or some other
+ * equivalent function to initialize OpenSSL, must be called before
+ * TSSLSocket is used.  If you set TSSLSocketFactory to use manual
+ * OpenSSL initialization, you should call this function or otherwise
+ * ensure OpenSSL is initialized yourself.
+ */
+void initializeOpenSSL();
+/**
+ * Cleanup OpenSSL library.  This function should be called to clean
+ * up OpenSSL after use of OpenSSL functionality is finished.  If you
+ * set TSSLSocketFactory to use manual OpenSSL initialization, you
+ * should call this function yourself or ensure that whatever
+ * initialized OpenSSL cleans it up too.
+ */
+void cleanupOpenSSL();
+
 /**
  * OpenSSL implementation for SSL socket interface.
  */
-class TSSLSocket: public TSocket {
- public:
- ~TSSLSocket();
+class TSSLSocket : public TSocket {
+public:
+  ~TSSLSocket();
   /**
    * TTransport interface.
    */
-  bool     isOpen();
-  bool     peek();
-  void     open();
-  void     close();
+  bool isOpen();
+  bool peek();
+  void open();
+  void close();
+  bool hasPendingDataToRead();
   uint32_t read(uint8_t* buf, uint32_t len);
-  void     write(const uint8_t* buf, uint32_t len);
-  void     flush();
-   /**
-   * Set whether to use client or server side SSL handshake protocol.
-   *
-   * @param flag  Use server side handshake protocol if true.
-   */
+  void write(const uint8_t* buf, uint32_t len);
+  uint32_t write_partial(const uint8_t* buf, uint32_t len);
+  void flush();
+  /**
+  * Set whether to use client or server side SSL handshake protocol.
+  *
+  * @param flag  Use server side handshake protocol if true.
+  */
   void server(bool flag) { server_ = flag; }
   /**
    * Determine whether the SSL socket is server or client mode.
@@ -62,29 +97,51 @@
    *
    * @param manager  Instance of AccessManager
    */
-  virtual void access(boost::shared_ptr<AccessManager> manager) {
-    access_ = manager;
-  }
+  virtual void access(std::shared_ptr<AccessManager> manager) { access_ = manager; }
+  /**
+   * Set eventSafe flag if libevent is used.
+   */
+  void setLibeventSafe() { eventSafe_ = true; }
+  /**
+   * Determines whether SSL Socket is libevent safe or not.
+   */
+  bool isLibeventSafe() const { return eventSafe_; }
+
 protected:
   /**
    * Constructor.
    */
-  TSSLSocket(boost::shared_ptr<SSLContext> ctx);
+  TSSLSocket(std::shared_ptr<SSLContext> ctx);
+  /**
+   * Constructor with an interrupt signal.
+   */
+  TSSLSocket(std::shared_ptr<SSLContext> ctx, std::shared_ptr<THRIFT_SOCKET> interruptListener);
   /**
    * Constructor, create an instance of TSSLSocket given an existing socket.
    *
    * @param socket An existing socket
    */
-  TSSLSocket(boost::shared_ptr<SSLContext> ctx, int socket);
+  TSSLSocket(std::shared_ptr<SSLContext> ctx, THRIFT_SOCKET socket);
   /**
+   * Constructor, create an instance of TSSLSocket given an existing socket that can be interrupted.
+   *
+   * @param socket An existing socket
+   */
+  TSSLSocket(std::shared_ptr<SSLContext> ctx, THRIFT_SOCKET socket, std::shared_ptr<THRIFT_SOCKET> interruptListener);
+   /**
    * Constructor.
    *
    * @param host  Remote host name
    * @param port  Remote port number
    */
-  TSSLSocket(boost::shared_ptr<SSLContext> ctx,
-                               std::string host,
-                                       int port);
+  TSSLSocket(std::shared_ptr<SSLContext> ctx, std::string host, int port);
+    /**
+  * Constructor with an interrupt signal.
+  *
+  * @param host  Remote host name
+  * @param port  Remote port number
+  */
+    TSSLSocket(std::shared_ptr<SSLContext> ctx, std::string host, int port, std::shared_ptr<THRIFT_SOCKET> interruptListener);
   /**
    * Authorize peer access after SSL handshake completes.
    */
@@ -92,43 +149,99 @@
   /**
    * Initiate SSL handshake if not already initiated.
    */
-  void checkHandshake();
+  void initializeHandshake();
+  /**
+   * Initiate SSL handshake params.
+   */
+  void initializeHandshakeParams();
+  /**
+   * Check if  SSL handshake is completed or not.
+   */
+  bool checkHandshake();
+  /**
+   * Waits for an socket or shutdown event.
+   *
+   * @throw TTransportException::INTERRUPTED if interrupted is signaled.
+   *
+   * @return TSSL_EINTR if EINTR happened on the underlying socket
+   *         TSSL_DATA  if data is available on the socket.
+   */
+  unsigned int waitForEvent(bool wantRead);
 
   bool server_;
   SSL* ssl_;
-  boost::shared_ptr<SSLContext> ctx_;
-  boost::shared_ptr<AccessManager> access_;
+  std::shared_ptr<SSLContext> ctx_;
+  std::shared_ptr<AccessManager> access_;
   friend class TSSLSocketFactory;
+
+private:
+  bool handshakeCompleted_;
+  int readRetryCount_;
+  bool eventSafe_;
+
+  void init();
 };
 
 /**
  * SSL socket factory. SSL sockets should be created via SSL factory.
+ * The factory will automatically initialize and cleanup openssl as long as
+ * there is a TSSLSocketFactory instantiated, and as long as the static
+ * boolean manualOpenSSLInitialization_ is set to false, the default.
+ *
+ * If you would like to initialize and cleanup openssl yourself, set
+ * manualOpenSSLInitialization_ to true and TSSLSocketFactory will no
+ * longer be responsible for openssl initialization and teardown.
+ *
+ * It is the responsibility of the code using TSSLSocketFactory to
+ * ensure that the factory lifetime exceeds the lifetime of any sockets
+ * it might create.  If this is not guaranteed, a socket may call into
+ * openssl after the socket factory has cleaned up openssl!  This
+ * guarantee is unnecessary if manualOpenSSLInitialization_ is true,
+ * however, since it would be up to the consuming application instead.
  */
 class TSSLSocketFactory {
- public:
+public:
   /**
    * Constructor/Destructor
+   *
+   * @param protocol The SSL/TLS protocol to use.
    */
-  TSSLSocketFactory();
+  TSSLSocketFactory(SSLProtocol protocol = SSLTLS);
   virtual ~TSSLSocketFactory();
   /**
    * Create an instance of TSSLSocket with a fresh new socket.
    */
-  virtual boost::shared_ptr<TSSLSocket> createSocket();
+  virtual std::shared_ptr<TSSLSocket> createSocket();
+  /**
+   * Create an instance of TSSLSocket with a fresh new socket, which is interruptable.
+   */
+  virtual std::shared_ptr<TSSLSocket> createSocket(std::shared_ptr<THRIFT_SOCKET> interruptListener);
   /**
    * Create an instance of TSSLSocket with the given socket.
    *
    * @param socket An existing socket.
    */
-  virtual boost::shared_ptr<TSSLSocket> createSocket(int socket);
-   /**
-   * Create an instance of TSSLSocket.
+  virtual std::shared_ptr<TSSLSocket> createSocket(THRIFT_SOCKET socket);
+  /**
+   * Create an instance of TSSLSocket with the given socket which is interruptable.
    *
-   * @param host  Remote host to be connected to
-   * @param port  Remote port to be connected to
+   * @param socket An existing socket.
    */
-  virtual boost::shared_ptr<TSSLSocket> createSocket(const std::string& host,
-                                                     int port);
+  virtual std::shared_ptr<TSSLSocket> createSocket(THRIFT_SOCKET socket, std::shared_ptr<THRIFT_SOCKET> interruptListener);
+  /**
+  * Create an instance of TSSLSocket.
+  *
+  * @param host  Remote host to be connected to
+  * @param port  Remote port to be connected to
+  */
+  virtual std::shared_ptr<TSSLSocket> createSocket(const std::string& host, int port);
+  /**
+  * Create an instance of TSSLSocket.
+  *
+  * @param host  Remote host to be connected to
+  * @param port  Remote port to be connected to
+  */
+  virtual std::shared_ptr<TSSLSocket> createSocket(const std::string& host, int port, std::shared_ptr<THRIFT_SOCKET> interruptListener);
   /**
    * Set ciphers to be used in SSL handshake process.
    *
@@ -160,7 +273,7 @@
    *
    * @param path Path to trusted certificate file
    */
-  virtual void loadTrustedCertificates(const char* path);
+  virtual void loadTrustedCertificates(const char* path, const char* capath = NULL);
   /**
    * Default randomize method.
    */
@@ -186,14 +299,14 @@
    *
    * @param manager  The AccessManager instance
    */
-  virtual void access(boost::shared_ptr<AccessManager> manager) {
-    access_ = manager;
+  virtual void access(std::shared_ptr<AccessManager> manager) { access_ = manager; }
+  static void setManualOpenSSLInitialization(bool manualOpenSSLInitialization) {
+    manualOpenSSLInitialization_ = manualOpenSSLInitialization;
   }
- protected:
-  boost::shared_ptr<SSLContext> ctx_;
 
-  static void initializeOpenSSL();
-  static void cleanupOpenSSL();
+protected:
+  std::shared_ptr<SSLContext> ctx_;
+
   /**
    * Override this method for custom password callback. It may be called
    * multiple times at any time during a session as necessary.
@@ -202,25 +315,26 @@
    * @param size     Maximum length of password including NULL character
    */
   virtual void getPassword(std::string& /* password */, int /* size */) {}
- private:
+
+private:
   bool server_;
-  boost::shared_ptr<AccessManager> access_;
-  static bool initialized;
+  std::shared_ptr<AccessManager> access_;
   static concurrency::Mutex mutex_;
   static uint64_t count_;
-  void setup(boost::shared_ptr<TSSLSocket> ssl);
+  static bool manualOpenSSLInitialization_;
+  void setup(std::shared_ptr<TSSLSocket> ssl);
   static int passwordCallback(char* password, int size, int, void* data);
 };
 
 /**
  * SSL exception.
  */
-class TSSLException: public TTransportException {
- public:
-  TSSLException(const std::string& message):
-    TTransportException(TTransportException::INTERNAL_ERROR, message) {}
+class TSSLException : public TTransportException {
+public:
+  TSSLException(const std::string& message)
+    : TTransportException(TTransportException::INTERNAL_ERROR, message) {}
 
-  virtual const char* what() const throw() {
+  virtual const char* what() const noexcept {
     if (message_.empty()) {
       return "TSSLException";
     } else {
@@ -233,12 +347,13 @@
  * Wrap OpenSSL SSL_CTX into a class.
  */
 class SSLContext {
- public:
-  SSLContext();
+public:
+  SSLContext(const SSLProtocol& protocol = SSLTLS);
   virtual ~SSLContext();
   SSL* createSSL();
   SSL_CTX* get() { return ctx_; }
- private:
+
+private:
   SSL_CTX* ctx_;
 };
 
@@ -249,67 +364,73 @@
  * object.
  */
 class AccessManager {
- public:
+public:
   enum Decision {
-    DENY   = -1,    // deny access
-    SKIP   =  0,    // cannot make decision, move on to next (if any)
-    ALLOW  =  1     // allow access
+    DENY = -1, // deny access
+    SKIP = 0,  // cannot make decision, move on to next (if any)
+    ALLOW = 1  // allow access
   };
- /**
-  * Destructor
-  */
- virtual ~AccessManager() {}
- /**
-  * Determine whether the peer should be granted access or not. It's called
-  * once after the SSL handshake completes successfully, before peer certificate
-  * is examined.
-  *
-  * If a valid decision (ALLOW or DENY) is returned, the peer certificate is
-  * not to be verified.
-  *
-  * @param  sa Peer IP address
-  * @return True if the peer is trusted, false otherwise
-  */
- virtual Decision verify(const sockaddr_storage& /* sa */ ) throw() { return DENY; }
- /**
-  * Determine whether the peer should be granted access or not. It's called
-  * every time a DNS subjectAltName/common name is extracted from peer's
-  * certificate.
-  *
-  * @param  host Client mode: host name returned by TSocket::getHost()
-  *              Server mode: host name returned by TSocket::getPeerHost()
-  * @param  name SubjectAltName or common name extracted from peer certificate
-  * @param  size Length of name
-  * @return True if the peer is trusted, false otherwise
-  *
-  * Note: The "name" parameter may be UTF8 encoded.
-  */
- virtual Decision verify(const std::string& /* host */, const char* /* name */, int /* size */)
-   throw() { return DENY; }
- /**
-  * Determine whether the peer should be granted access or not. It's called
-  * every time an IP subjectAltName is extracted from peer's certificate.
-  *
-  * @param  sa   Peer IP address retrieved from the underlying socket
-  * @param  data IP address extracted from certificate
-  * @param  size Length of the IP address
-  * @return True if the peer is trusted, false otherwise
-  */
- virtual Decision verify(const sockaddr_storage& /* sa */, const char* /* data */, int /* size */)
-   throw() { return DENY; }
+  /**
+   * Destructor
+   */
+  virtual ~AccessManager() {}
+  /**
+   * Determine whether the peer should be granted access or not. It's called
+   * once after the SSL handshake completes successfully, before peer certificate
+   * is examined.
+   *
+   * If a valid decision (ALLOW or DENY) is returned, the peer certificate is
+   * not to be verified.
+   *
+   * @param  sa Peer IP address
+   * @return True if the peer is trusted, false otherwise
+   */
+  virtual Decision verify(const sockaddr_storage& /* sa */) noexcept { return DENY; }
+  /**
+   * Determine whether the peer should be granted access or not. It's called
+   * every time a DNS subjectAltName/common name is extracted from peer's
+   * certificate.
+   *
+   * @param  host Client mode: host name returned by TSocket::getHost()
+   *              Server mode: host name returned by TSocket::getPeerHost()
+   * @param  name SubjectAltName or common name extracted from peer certificate
+   * @param  size Length of name
+   * @return True if the peer is trusted, false otherwise
+   *
+   * Note: The "name" parameter may be UTF8 encoded.
+   */
+  virtual Decision verify(const std::string& /* host */,
+                          const char* /* name */,
+                          int /* size */) noexcept {
+    return DENY;
+  }
+  /**
+   * Determine whether the peer should be granted access or not. It's called
+   * every time an IP subjectAltName is extracted from peer's certificate.
+   *
+   * @param  sa   Peer IP address retrieved from the underlying socket
+   * @param  data IP address extracted from certificate
+   * @param  size Length of the IP address
+   * @return True if the peer is trusted, false otherwise
+   */
+  virtual Decision verify(const sockaddr_storage& /* sa */,
+                          const char* /* data */,
+                          int /* size */) noexcept {
+    return DENY;
+  }
 };
 
 typedef AccessManager::Decision Decision;
 
-class DefaultClientAccessManager: public AccessManager {
- public:
+class DefaultClientAccessManager : public AccessManager {
+public:
   // AccessManager interface
-  Decision verify(const sockaddr_storage& sa) throw();
-  Decision verify(const std::string& host, const char* name, int size) throw();
-  Decision verify(const sockaddr_storage& sa, const char* data, int size) throw();
+  Decision verify(const sockaddr_storage& sa) noexcept;
+  Decision verify(const std::string& host, const char* name, int size) noexcept;
+  Decision verify(const sockaddr_storage& sa, const char* data, int size) noexcept;
 };
-
-
-}}}
+}
+}
+}
 
 #endif
diff --git a/lib/cpp/src/thrift/transport/TServerSocket.cpp b/lib/cpp/src/thrift/transport/TServerSocket.cpp
index 4cecc3b..118b993 100644
--- a/lib/cpp/src/thrift/transport/TServerSocket.cpp
+++ b/lib/cpp/src/thrift/transport/TServerSocket.cpp
@@ -20,6 +20,7 @@
 #include <thrift/thrift-config.h>
 
 #include <cstring>
+#include <stdexcept>
 #include <sys/types.h>
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
@@ -45,77 +46,139 @@
 #include <thrift/transport/TSocket.h>
 #include <thrift/transport/TServerSocket.h>
 #include <thrift/transport/PlatformSocket.h>
-#include <boost/shared_ptr.hpp>
 
 #ifndef AF_LOCAL
 #define AF_LOCAL AF_UNIX
 #endif
 
 #ifndef SOCKOPT_CAST_T
-#   ifndef _WIN32
-#       define SOCKOPT_CAST_T void
-#   else
-#       define SOCKOPT_CAST_T char
-#   endif // _WIN32
+#ifndef _WIN32
+#define SOCKOPT_CAST_T void
+#else
+#define SOCKOPT_CAST_T char
+#endif // _WIN32
 #endif
 
-template<class T>
+template <class T>
 inline const SOCKOPT_CAST_T* const_cast_sockopt(const T* v) {
-    return reinterpret_cast<const SOCKOPT_CAST_T*>(v);
+  return reinterpret_cast<const SOCKOPT_CAST_T*>(v);
 }
 
-template<class T>
+template <class T>
 inline SOCKOPT_CAST_T* cast_sockopt(T* v) {
-    return reinterpret_cast<SOCKOPT_CAST_T*>(v);
+  return reinterpret_cast<SOCKOPT_CAST_T*>(v);
 }
 
-namespace apache { namespace thrift { namespace transport {
+void destroyer_of_fine_sockets(THRIFT_SOCKET* ssock) {
+  ::THRIFT_CLOSESOCKET(*ssock);
+  delete ssock;
+}
 
-using namespace std;
-using boost::shared_ptr;
+using std::string;
 
-TServerSocket::TServerSocket(int port) :
-  port_(port),
-  serverSocket_(THRIFT_INVALID_SOCKET),
-  acceptBacklog_(DEFAULT_BACKLOG),
-  sendTimeout_(0),
-  recvTimeout_(0),
-  accTimeout_(-1),
-  retryLimit_(0),
-  retryDelay_(0),
-  tcpSendBuffer_(0),
-  tcpRecvBuffer_(0),
-  intSock1_(THRIFT_INVALID_SOCKET),
-  intSock2_(THRIFT_INVALID_SOCKET) {}
+namespace apache {
+namespace thrift {
+namespace transport {
 
-TServerSocket::TServerSocket(int port, int sendTimeout, int recvTimeout) :
-  port_(port),
-  serverSocket_(THRIFT_INVALID_SOCKET),
-  acceptBacklog_(DEFAULT_BACKLOG),
-  sendTimeout_(sendTimeout),
-  recvTimeout_(recvTimeout),
-  accTimeout_(-1),
-  retryLimit_(0),
-  retryDelay_(0),
-  tcpSendBuffer_(0),
-  tcpRecvBuffer_(0),
-  intSock1_(THRIFT_INVALID_SOCKET),
-  intSock2_(THRIFT_INVALID_SOCKET) {}
+using std::shared_ptr;
 
-TServerSocket::TServerSocket(string path) :
-  port_(0),
-  path_(path),
-  serverSocket_(THRIFT_INVALID_SOCKET),
-  acceptBacklog_(DEFAULT_BACKLOG),
-  sendTimeout_(0),
-  recvTimeout_(0),
-  accTimeout_(-1),
-  retryLimit_(0),
-  retryDelay_(0),
-  tcpSendBuffer_(0),
-  tcpRecvBuffer_(0),
-  intSock1_(THRIFT_INVALID_SOCKET),
-  intSock2_(THRIFT_INVALID_SOCKET) {}
+TGetAddrInfoWrapper::TGetAddrInfoWrapper(const char* node,
+                                         const char* service,
+                                         const struct addrinfo* hints)
+  : node_(node), service_(service), hints_(hints), res_(NULL) {}
+
+TGetAddrInfoWrapper::~TGetAddrInfoWrapper() {
+  if (this->res_ != NULL)
+    freeaddrinfo(this->res_);
+}
+
+int TGetAddrInfoWrapper::init() {
+  if (this->res_ == NULL)
+    return getaddrinfo(this->node_, this->service_, this->hints_, &(this->res_));
+  return 0;
+}
+
+const struct addrinfo* TGetAddrInfoWrapper::res() {
+  return this->res_;
+}
+
+TServerSocket::TServerSocket(int port)
+  : interruptableChildren_(true),
+    port_(port),
+    serverSocket_(THRIFT_INVALID_SOCKET),
+    acceptBacklog_(DEFAULT_BACKLOG),
+    sendTimeout_(0),
+    recvTimeout_(0),
+    accTimeout_(-1),
+    retryLimit_(0),
+    retryDelay_(0),
+    tcpSendBuffer_(0),
+    tcpRecvBuffer_(0),
+    keepAlive_(false),
+    listening_(false),
+    interruptSockWriter_(THRIFT_INVALID_SOCKET),
+    interruptSockReader_(THRIFT_INVALID_SOCKET),
+    childInterruptSockWriter_(THRIFT_INVALID_SOCKET) {
+}
+
+TServerSocket::TServerSocket(int port, int sendTimeout, int recvTimeout)
+  : interruptableChildren_(true),
+    port_(port),
+    serverSocket_(THRIFT_INVALID_SOCKET),
+    acceptBacklog_(DEFAULT_BACKLOG),
+    sendTimeout_(sendTimeout),
+    recvTimeout_(recvTimeout),
+    accTimeout_(-1),
+    retryLimit_(0),
+    retryDelay_(0),
+    tcpSendBuffer_(0),
+    tcpRecvBuffer_(0),
+    keepAlive_(false),
+    listening_(false),
+    interruptSockWriter_(THRIFT_INVALID_SOCKET),
+    interruptSockReader_(THRIFT_INVALID_SOCKET),
+    childInterruptSockWriter_(THRIFT_INVALID_SOCKET) {
+}
+
+TServerSocket::TServerSocket(const string& address, int port)
+  : interruptableChildren_(true),
+    port_(port),
+    address_(address),
+    serverSocket_(THRIFT_INVALID_SOCKET),
+    acceptBacklog_(DEFAULT_BACKLOG),
+    sendTimeout_(0),
+    recvTimeout_(0),
+    accTimeout_(-1),
+    retryLimit_(0),
+    retryDelay_(0),
+    tcpSendBuffer_(0),
+    tcpRecvBuffer_(0),
+    keepAlive_(false),
+    listening_(false),
+    interruptSockWriter_(THRIFT_INVALID_SOCKET),
+    interruptSockReader_(THRIFT_INVALID_SOCKET),
+    childInterruptSockWriter_(THRIFT_INVALID_SOCKET) {
+}
+
+TServerSocket::TServerSocket(const string& path)
+  : interruptableChildren_(true),
+    port_(0),
+    path_(path),
+    serverSocket_(THRIFT_INVALID_SOCKET),
+    acceptBacklog_(DEFAULT_BACKLOG),
+    sendTimeout_(0),
+    recvTimeout_(0),
+    accTimeout_(-1),
+    retryLimit_(0),
+    retryDelay_(0),
+    tcpSendBuffer_(0),
+    tcpRecvBuffer_(0),
+    keepAlive_(false),
+    listening_(false),
+    interruptSockWriter_(THRIFT_INVALID_SOCKET),
+    interruptSockReader_(THRIFT_INVALID_SOCKET),
+    childInterruptSockWriter_(THRIFT_INVALID_SOCKET) {
+}
 
 TServerSocket::~TServerSocket() {
   close();
@@ -153,44 +216,78 @@
   tcpRecvBuffer_ = tcpRecvBuffer;
 }
 
+void TServerSocket::setInterruptableChildren(bool enable) {
+  if (listening_) {
+    throw std::logic_error("setInterruptableChildren cannot be called after listen()");
+  }
+  interruptableChildren_ = enable;
+}
+
 void TServerSocket::listen() {
+  listening_ = true;
+#ifdef _WIN32
+  TWinsockSingleton::create();
+#endif // _WIN32
   THRIFT_SOCKET sv[2];
+  // Create the socket pair used to interrupt
   if (-1 == THRIFT_SOCKETPAIR(AF_LOCAL, SOCK_STREAM, 0, sv)) {
-    GlobalOutput.perror("TServerSocket::listen() socketpair() ", THRIFT_GET_SOCKET_ERROR);
-    intSock1_ = THRIFT_INVALID_SOCKET;
-    intSock2_ = THRIFT_INVALID_SOCKET;
+    GlobalOutput.perror("TServerSocket::listen() socketpair() interrupt", THRIFT_GET_SOCKET_ERROR);
+    interruptSockWriter_ = THRIFT_INVALID_SOCKET;
+    interruptSockReader_ = THRIFT_INVALID_SOCKET;
   } else {
-    intSock1_ = sv[1];
-    intSock2_ = sv[0];
+    interruptSockWriter_ = sv[1];
+    interruptSockReader_ = sv[0];
   }
 
-  struct addrinfo hints, *res, *res0;
+  // Create the socket pair used to interrupt all clients
+  if (-1 == THRIFT_SOCKETPAIR(AF_LOCAL, SOCK_STREAM, 0, sv)) {
+    GlobalOutput.perror("TServerSocket::listen() socketpair() childInterrupt",
+                        THRIFT_GET_SOCKET_ERROR);
+    childInterruptSockWriter_ = THRIFT_INVALID_SOCKET;
+    pChildInterruptSockReader_.reset();
+  } else {
+    childInterruptSockWriter_ = sv[1];
+    pChildInterruptSockReader_
+        = std::shared_ptr<THRIFT_SOCKET>(new THRIFT_SOCKET(sv[0]), destroyer_of_fine_sockets);
+  }
+
+  // Validate port number
+  if (port_ < 0 || port_ > 0xFFFF) {
+    throw TTransportException(TTransportException::BAD_ARGS, "Specified port is invalid");
+  }
+
+  const struct addrinfo *res;
   int error;
-  char port[sizeof("65536") + 1];
+  char port[sizeof("65535")];
+  THRIFT_SNPRINTF(port, sizeof(port), "%d", port_);
+
+  struct addrinfo hints;
   std::memset(&hints, 0, sizeof(hints));
   hints.ai_family = PF_UNSPEC;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
-  sprintf(port, "%d", port_);
 
-  // Wildcard address
-  error = getaddrinfo(NULL, port, &hints, &res0);
+  // If address is not specified use wildcard address (NULL)
+  TGetAddrInfoWrapper info(address_.empty() ? NULL : &address_[0], port, &hints);
+
+  error = info.init();
   if (error) {
     GlobalOutput.printf("getaddrinfo %d: %s", error, THRIFT_GAI_STRERROR(error));
     close();
-    throw TTransportException(TTransportException::NOT_OPEN, "Could not resolve host for server socket.");
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "Could not resolve host for server socket.");
   }
 
   // Pick the ipv6 address first since ipv4 addresses can be mapped
   // into ipv6 space.
-  for (res = res0; res; res = res->ai_next) {
+  for (res = info.res(); res; res = res->ai_next) {
     if (res->ai_family == AF_INET6 || res->ai_next == NULL)
       break;
   }
 
-  if (! path_.empty()) {
+  if (!path_.empty()) {
     serverSocket_ = socket(PF_UNIX, SOCK_STREAM, IPPROTO_IP);
-  } else {
+  } else if (res != NULL) {
     serverSocket_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
   }
 
@@ -198,70 +295,93 @@
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
     GlobalOutput.perror("TServerSocket::listen() socket() ", errno_copy);
     close();
-    throw TTransportException(TTransportException::NOT_OPEN, "Could not create server socket.", errno_copy);
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "Could not create server socket.",
+                              errno_copy);
   }
 
   // Set THRIFT_NO_SOCKET_CACHING to prevent 2MSL delay on accept
   int one = 1;
-  if (-1 == setsockopt(serverSocket_, SOL_SOCKET, THRIFT_NO_SOCKET_CACHING,
-                       cast_sockopt(&one), sizeof(one))) {
-    //ignore errors coming out of this setsockopt on Windows.  This is because
-    //SO_EXCLUSIVEADDRUSE requires admin privileges on WinXP, but we don't
-    //want to force servers to be an admin.
+  if (-1 == setsockopt(serverSocket_,
+                       SOL_SOCKET,
+                       THRIFT_NO_SOCKET_CACHING,
+                       cast_sockopt(&one),
+                       sizeof(one))) {
+// ignore errors coming out of this setsockopt on Windows.  This is because
+// SO_EXCLUSIVEADDRUSE requires admin privileges on WinXP, but we don't
+// want to force servers to be an admin.
 #ifndef _WIN32
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TServerSocket::listen() setsockopt() THRIFT_NO_SOCKET_CACHING ", errno_copy);
+    GlobalOutput.perror("TServerSocket::listen() setsockopt() THRIFT_NO_SOCKET_CACHING ",
+                        errno_copy);
     close();
-    throw TTransportException(TTransportException::NOT_OPEN, "Could not set THRIFT_NO_SOCKET_CACHING", errno_copy);
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "Could not set THRIFT_NO_SOCKET_CACHING",
+                              errno_copy);
 #endif
   }
 
   // Set TCP buffer sizes
   if (tcpSendBuffer_ > 0) {
-    if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_SNDBUF,
-                         cast_sockopt(&tcpSendBuffer_), sizeof(tcpSendBuffer_))) {
+    if (-1 == setsockopt(serverSocket_,
+                         SOL_SOCKET,
+                         SO_SNDBUF,
+                         cast_sockopt(&tcpSendBuffer_),
+                         sizeof(tcpSendBuffer_))) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
       GlobalOutput.perror("TServerSocket::listen() setsockopt() SO_SNDBUF ", errno_copy);
       close();
-      throw TTransportException(TTransportException::NOT_OPEN, "Could not set SO_SNDBUF", errno_copy);
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                "Could not set SO_SNDBUF",
+                                errno_copy);
     }
   }
 
   if (tcpRecvBuffer_ > 0) {
-    if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_RCVBUF,
-                         cast_sockopt(&tcpRecvBuffer_), sizeof(tcpRecvBuffer_))) {
+    if (-1 == setsockopt(serverSocket_,
+                         SOL_SOCKET,
+                         SO_RCVBUF,
+                         cast_sockopt(&tcpRecvBuffer_),
+                         sizeof(tcpRecvBuffer_))) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
       GlobalOutput.perror("TServerSocket::listen() setsockopt() SO_RCVBUF ", errno_copy);
       close();
-      throw TTransportException(TTransportException::NOT_OPEN, "Could not set SO_RCVBUF", errno_copy);
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                "Could not set SO_RCVBUF",
+                                errno_copy);
     }
   }
 
-  // Defer accept
-  #ifdef TCP_DEFER_ACCEPT
-  if (-1 == setsockopt(serverSocket_, SOL_SOCKET, TCP_DEFER_ACCEPT,
-                       &one, sizeof(one))) {
-    int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TServerSocket::listen() setsockopt() TCP_DEFER_ACCEPT ", errno_copy);
-    close();
-    throw TTransportException(TTransportException::NOT_OPEN, "Could not set TCP_DEFER_ACCEPT", errno_copy);
+// Defer accept
+#ifdef TCP_DEFER_ACCEPT
+  if (path_.empty()) {
+    if (-1 == setsockopt(serverSocket_, IPPROTO_TCP, TCP_DEFER_ACCEPT, &one, sizeof(one))) {
+      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+      GlobalOutput.perror("TServerSocket::listen() setsockopt() TCP_DEFER_ACCEPT ", errno_copy);
+      close();
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                "Could not set TCP_DEFER_ACCEPT",
+                                errno_copy);
+    }
   }
-  #endif // #ifdef TCP_DEFER_ACCEPT
+#endif // #ifdef TCP_DEFER_ACCEPT
 
-  #ifdef IPV6_V6ONLY
+#ifdef IPV6_V6ONLY
   if (res->ai_family == AF_INET6 && path_.empty()) {
     int zero = 0;
-    if (-1 == setsockopt(serverSocket_, IPPROTO_IPV6, IPV6_V6ONLY,
-          cast_sockopt(&zero), sizeof(zero))) {
+    if (-1 == setsockopt(serverSocket_,
+                         IPPROTO_IPV6,
+                         IPV6_V6ONLY,
+                         cast_sockopt(&zero),
+                         sizeof(zero))) {
       GlobalOutput.perror("TServerSocket::listen() IPV6_V6ONLY ", THRIFT_GET_SOCKET_ERROR);
     }
   }
-  #endif // #ifdef IPV6_V6ONLY
+#endif // #ifdef IPV6_V6ONLY
 
   // Turn linger off, don't want to block on calls to close
   struct linger ling = {0, 0};
-  if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_LINGER,
-                       cast_sockopt(&ling), sizeof(ling))) {
+  if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_LINGER, cast_sockopt(&ling), sizeof(ling))) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
     GlobalOutput.perror("TServerSocket::listen() setsockopt() SO_LINGER ", errno_copy);
     close();
@@ -271,12 +391,14 @@
   // Unix Sockets do not need that
   if (path_.empty()) {
     // TCP Nodelay, speed over bandwidth
-    if (-1 == setsockopt(serverSocket_, IPPROTO_TCP, TCP_NODELAY,
-                         cast_sockopt(&one), sizeof(one))) {
+    if (-1
+        == setsockopt(serverSocket_, IPPROTO_TCP, TCP_NODELAY, cast_sockopt(&one), sizeof(one))) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
       GlobalOutput.perror("TServerSocket::listen() setsockopt() TCP_NODELAY ", errno_copy);
       close();
-      throw TTransportException(TTransportException::NOT_OPEN, "Could not set TCP_NODELAY", errno_copy);
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                "Could not set TCP_NODELAY",
+                                errno_copy);
     }
   }
 
@@ -285,78 +407,120 @@
   if (flags == -1) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
     GlobalOutput.perror("TServerSocket::listen() THRIFT_FCNTL() THRIFT_F_GETFL ", errno_copy);
-    throw TTransportException(TTransportException::NOT_OPEN, "THRIFT_FCNTL() failed", errno_copy);
+    close();
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "THRIFT_FCNTL() THRIFT_F_GETFL failed",
+                              errno_copy);
   }
 
   if (-1 == THRIFT_FCNTL(serverSocket_, THRIFT_F_SETFL, flags | THRIFT_O_NONBLOCK)) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
     GlobalOutput.perror("TServerSocket::listen() THRIFT_FCNTL() THRIFT_O_NONBLOCK ", errno_copy);
-    throw TTransportException(TTransportException::NOT_OPEN, "THRIFT_FCNTL() failed", errno_copy);
+    close();
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "THRIFT_FCNTL() THRIFT_F_SETFL THRIFT_O_NONBLOCK failed",
+                              errno_copy);
   }
 
   // prepare the port information
   // we may want to try to bind more than once, since THRIFT_NO_SOCKET_CACHING doesn't
   // always seem to work. The client can configure the retry variables.
   int retries = 0;
+  int errno_copy = 0;
 
-  if (! path_.empty()) {
+  if (!path_.empty()) {
 
 #ifndef _WIN32
 
     // Unix Domain Socket
-    struct sockaddr_un address;
-    socklen_t len;
-
-    if (path_.length() > sizeof(address.sun_path)) {
-      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    size_t len = path_.size() + 1;
+    if (len > sizeof(((sockaddr_un*)NULL)->sun_path)) {
+      errno_copy = THRIFT_GET_SOCKET_ERROR;
       GlobalOutput.perror("TSocket::listen() Unix Domain socket path too long", errno_copy);
-      throw TTransportException(TTransportException::NOT_OPEN, " Unix Domain socket path too long");
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                "Unix Domain socket path too long",
+                                errno_copy);
     }
 
+    struct sockaddr_un address;
     address.sun_family = AF_UNIX;
-    THRIFT_SNPRINTF(address.sun_path, sizeof(address.sun_path), "%s", path_.c_str());
-    len = sizeof(address);
+    memcpy(address.sun_path, path_.c_str(), len);
+
+    socklen_t structlen = static_cast<socklen_t>(sizeof(address));
+
+    if (!address.sun_path[0]) { // abstract namespace socket
+#ifdef __linux__
+      // sun_path is not null-terminated in this case and structlen determines its length
+      structlen -= sizeof(address.sun_path) - len;
+#else
+      GlobalOutput.perror("TSocket::open() Abstract Namespace Domain sockets only supported on linux: ", -99);
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                " Abstract Namespace Domain socket path not supported");
+#endif
+    }
 
     do {
-      if (0 == ::bind(serverSocket_, (struct sockaddr *) &address, len)) {
+      if (0 == ::bind(serverSocket_, (struct sockaddr*)&address, structlen)) {
         break;
       }
+      errno_copy = THRIFT_GET_SOCKET_ERROR;
       // use short circuit evaluation here to only sleep if we need to
     } while ((retries++ < retryLimit_) && (THRIFT_SLEEP_SEC(retryDelay_) == 0));
 #else
     GlobalOutput.perror("TSocket::open() Unix Domain socket path not supported on windows", -99);
-    throw TTransportException(TTransportException::NOT_OPEN, " Unix Domain socket path not supported");
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              " Unix Domain socket path not supported");
 #endif
   } else {
     do {
       if (0 == ::bind(serverSocket_, res->ai_addr, static_cast<int>(res->ai_addrlen))) {
         break;
       }
+      errno_copy = THRIFT_GET_SOCKET_ERROR;
       // use short circuit evaluation here to only sleep if we need to
     } while ((retries++ < retryLimit_) && (THRIFT_SLEEP_SEC(retryDelay_) == 0));
 
-    // free addrinfo
-    freeaddrinfo(res0);
+    // retrieve bind info
+    if (port_ == 0 && retries <= retryLimit_) {
+      struct sockaddr_storage sa;
+      socklen_t len = sizeof(sa);
+      std::memset(&sa, 0, len);
+      if (::getsockname(serverSocket_, reinterpret_cast<struct sockaddr*>(&sa), &len) < 0) {
+        errno_copy = THRIFT_GET_SOCKET_ERROR;
+        GlobalOutput.perror("TServerSocket::getPort() getsockname() ", errno_copy);
+      } else {
+        if (sa.ss_family == AF_INET6) {
+          const struct sockaddr_in6* sin = reinterpret_cast<const struct sockaddr_in6*>(&sa);
+          port_ = ntohs(sin->sin6_port);
+        } else {
+          const struct sockaddr_in* sin = reinterpret_cast<const struct sockaddr_in*>(&sa);
+          port_ = ntohs(sin->sin_port);
+        }
+      }
+    }
   }
 
   // throw an error if we failed to bind properly
   if (retries > retryLimit_) {
     char errbuf[1024];
-    if (! path_.empty()) {
-      sprintf(errbuf, "TServerSocket::listen() PATH %s", path_.c_str());
-    }
-    else {
-      sprintf(errbuf, "TServerSocket::listen() BIND %d", port_);
+    if (!path_.empty()) {
+      THRIFT_SNPRINTF(errbuf, sizeof(errbuf), "TServerSocket::listen() PATH %s", path_.c_str());
+    } else {
+      THRIFT_SNPRINTF(errbuf, sizeof(errbuf), "TServerSocket::listen() BIND %d", port_);
     }
     GlobalOutput(errbuf);
     close();
-    throw TTransportException(TTransportException::NOT_OPEN, "Could not bind",
-                              THRIFT_GET_SOCKET_ERROR);
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "Could not bind",
+                              errno_copy);
   }
 
+  if (listenCallback_)
+    listenCallback_(serverSocket_);
+
   // Call listen
   if (-1 == ::listen(serverSocket_, acceptBacklog_)) {
-    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    errno_copy = THRIFT_GET_SOCKET_ERROR;
     GlobalOutput.perror("TServerSocket::listen() listen() ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN, "Could not listen", errno_copy);
@@ -365,6 +529,10 @@
   // The socket is now listening!
 }
 
+int TServerSocket::getPort() {
+  return port_;
+}
+
 shared_ptr<TTransport> TServerSocket::acceptImpl() {
   if (serverSocket_ == THRIFT_INVALID_SOCKET) {
     throw TTransportException(TTransportException::NOT_OPEN, "TServerSocket not listening");
@@ -376,11 +544,11 @@
   int numEintrs = 0;
 
   while (true) {
-    std::memset(fds, 0 , sizeof(fds));
+    std::memset(fds, 0, sizeof(fds));
     fds[0].fd = serverSocket_;
     fds[0].events = THRIFT_POLLIN;
-    if (intSock2_ != THRIFT_INVALID_SOCKET) {
-      fds[1].fd = intSock2_;
+    if (interruptSockReader_ != THRIFT_INVALID_SOCKET) {
+      fds[1].fd = interruptSockReader_;
       fds[1].events = THRIFT_POLLIN;
     }
     /*
@@ -401,11 +569,11 @@
       throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
     } else if (ret > 0) {
       // Check for an interrupt signal
-      if (intSock2_ != THRIFT_INVALID_SOCKET
-          && (fds[1].revents & THRIFT_POLLIN)) {
+      if (interruptSockReader_ != THRIFT_INVALID_SOCKET && (fds[1].revents & THRIFT_POLLIN)) {
         int8_t buf;
-        if (-1 == recv(intSock2_, cast_sockopt(&buf), sizeof(int8_t), 0)) {
-          GlobalOutput.perror("TServerSocket::acceptImpl() recv() interrupt ", THRIFT_GET_SOCKET_ERROR);
+        if (-1 == recv(interruptSockReader_, cast_sockopt(&buf), sizeof(int8_t), 0)) {
+          GlobalOutput.perror("TServerSocket::acceptImpl() recv() interrupt ",
+                              THRIFT_GET_SOCKET_ERROR);
         }
         throw TTransportException(TTransportException::INTERRUPTED);
       }
@@ -422,11 +590,10 @@
 
   struct sockaddr_storage clientAddress;
   int size = sizeof(clientAddress);
-  THRIFT_SOCKET clientSocket = ::accept(serverSocket_,
-                              (struct sockaddr *) &clientAddress,
-                              (socklen_t *) &size);
+  THRIFT_SOCKET clientSocket
+      = ::accept(serverSocket_, (struct sockaddr*)&clientAddress, (socklen_t*)&size);
 
-  if (clientSocket == -1) {
+  if (clientSocket == THRIFT_INVALID_SOCKET) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
     GlobalOutput.perror("TServerSocket::acceptImpl() ::accept() ", errno_copy);
     throw TTransportException(TTransportException::UNKNOWN, "accept()", errno_copy);
@@ -436,14 +603,22 @@
   int flags = THRIFT_FCNTL(clientSocket, THRIFT_F_GETFL, 0);
   if (flags == -1) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    ::THRIFT_CLOSESOCKET(clientSocket);
     GlobalOutput.perror("TServerSocket::acceptImpl() THRIFT_FCNTL() THRIFT_F_GETFL ", errno_copy);
-    throw TTransportException(TTransportException::UNKNOWN, "THRIFT_FCNTL(THRIFT_F_GETFL)", errno_copy);
+    throw TTransportException(TTransportException::UNKNOWN,
+                              "THRIFT_FCNTL(THRIFT_F_GETFL)",
+                              errno_copy);
   }
 
   if (-1 == THRIFT_FCNTL(clientSocket, THRIFT_F_SETFL, flags & ~THRIFT_O_NONBLOCK)) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TServerSocket::acceptImpl() THRIFT_FCNTL() THRIFT_F_SETFL ~THRIFT_O_NONBLOCK ", errno_copy);
-    throw TTransportException(TTransportException::UNKNOWN, "THRIFT_FCNTL(THRIFT_F_SETFL)", errno_copy);
+    ::THRIFT_CLOSESOCKET(clientSocket);
+    GlobalOutput
+        .perror("TServerSocket::acceptImpl() THRIFT_FCNTL() THRIFT_F_SETFL ~THRIFT_O_NONBLOCK ",
+                errno_copy);
+    throw TTransportException(TTransportException::UNKNOWN,
+                              "THRIFT_FCNTL(THRIFT_F_SETFL)",
+                              errno_copy);
   }
 
   shared_ptr<TSocket> client = createSocket(clientSocket);
@@ -453,38 +628,70 @@
   if (recvTimeout_ > 0) {
     client->setRecvTimeout(recvTimeout_);
   }
-  client->setCachedAddress((sockaddr*) &clientAddress, size);
+  if (keepAlive_) {
+    client->setKeepAlive(keepAlive_);
+  }
+  client->setCachedAddress((sockaddr*)&clientAddress, size);
+
+  if (acceptCallback_)
+    acceptCallback_(clientSocket);
 
   return client;
 }
 
 shared_ptr<TSocket> TServerSocket::createSocket(THRIFT_SOCKET clientSocket) {
-  return shared_ptr<TSocket>(new TSocket(clientSocket));
+  if (interruptableChildren_) {
+    return shared_ptr<TSocket>(new TSocket(clientSocket, pChildInterruptSockReader_));
+  } else {
+    return shared_ptr<TSocket>(new TSocket(clientSocket));
+  }
 }
 
-void TServerSocket::interrupt() {
-  if (intSock1_ != THRIFT_INVALID_SOCKET) {
+void TServerSocket::notify(THRIFT_SOCKET notifySocket) {
+  if (notifySocket != THRIFT_INVALID_SOCKET) {
     int8_t byte = 0;
-    if (-1 == send(intSock1_, cast_sockopt(&byte), sizeof(int8_t), 0)) {
-      GlobalOutput.perror("TServerSocket::interrupt() send() ", THRIFT_GET_SOCKET_ERROR);
+    if (-1 == send(notifySocket, cast_sockopt(&byte), sizeof(int8_t), 0)) {
+      GlobalOutput.perror("TServerSocket::notify() send() ", THRIFT_GET_SOCKET_ERROR);
     }
   }
 }
 
+void TServerSocket::interrupt() {
+  concurrency::Guard g(rwMutex_);
+  if (interruptSockWriter_ != THRIFT_INVALID_SOCKET) {
+    notify(interruptSockWriter_);
+  }
+}
+
+void TServerSocket::interruptChildren() {
+  concurrency::Guard g(rwMutex_);
+  if (childInterruptSockWriter_ != THRIFT_INVALID_SOCKET) {
+    notify(childInterruptSockWriter_);
+  }
+}
+
 void TServerSocket::close() {
+  concurrency::Guard g(rwMutex_);
   if (serverSocket_ != THRIFT_INVALID_SOCKET) {
     shutdown(serverSocket_, THRIFT_SHUT_RDWR);
     ::THRIFT_CLOSESOCKET(serverSocket_);
   }
-  if (intSock1_ != THRIFT_INVALID_SOCKET) {
-      ::THRIFT_CLOSESOCKET(intSock1_);
+  if (interruptSockWriter_ != THRIFT_INVALID_SOCKET) {
+    ::THRIFT_CLOSESOCKET(interruptSockWriter_);
   }
-  if (intSock2_ != THRIFT_INVALID_SOCKET) {
-    ::THRIFT_CLOSESOCKET(intSock2_);
+  if (interruptSockReader_ != THRIFT_INVALID_SOCKET) {
+    ::THRIFT_CLOSESOCKET(interruptSockReader_);
+  }
+  if (childInterruptSockWriter_ != THRIFT_INVALID_SOCKET) {
+    ::THRIFT_CLOSESOCKET(childInterruptSockWriter_);
   }
   serverSocket_ = THRIFT_INVALID_SOCKET;
-  intSock1_ = THRIFT_INVALID_SOCKET;
-  intSock2_ = THRIFT_INVALID_SOCKET;
+  interruptSockWriter_ = THRIFT_INVALID_SOCKET;
+  interruptSockReader_ = THRIFT_INVALID_SOCKET;
+  childInterruptSockWriter_ = THRIFT_INVALID_SOCKET;
+  pChildInterruptSockReader_.reset();
+  listening_ = false;
 }
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/TServerSocket.h b/lib/cpp/src/thrift/transport/TServerSocket.h
index 4a8c029..b23d2c1 100644
--- a/lib/cpp/src/thrift/transport/TServerSocket.h
+++ b/lib/cpp/src/thrift/transport/TServerSocket.h
@@ -20,28 +20,83 @@
 #ifndef _THRIFT_TRANSPORT_TSERVERSOCKET_H_
 #define _THRIFT_TRANSPORT_TSERVERSOCKET_H_ 1
 
-#include <thrift/transport/TServerTransport.h>
+#include <thrift/concurrency/Mutex.h>
 #include <thrift/transport/PlatformSocket.h>
-#include <boost/shared_ptr.hpp>
+#include <thrift/transport/TServerTransport.h>
 
-namespace apache { namespace thrift { namespace transport {
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+namespace apache {
+namespace thrift {
+namespace transport {
 
 class TSocket;
 
+class TGetAddrInfoWrapper {
+public:
+  TGetAddrInfoWrapper(const char* node, const char* service, const struct addrinfo* hints);
+
+  virtual ~TGetAddrInfoWrapper();
+
+  int init();
+  const struct addrinfo* res();
+
+private:
+  const char* node_;
+  const char* service_;
+  const struct addrinfo* hints_;
+  struct addrinfo* res_;
+};
+
 /**
  * Server socket implementation of TServerTransport. Wrapper around a unix
  * socket listen and accept calls.
  *
  */
 class TServerSocket : public TServerTransport {
- public:
+public:
+  typedef std::function<void(THRIFT_SOCKET fd)> socket_func_t;
+
   const static int DEFAULT_BACKLOG = 1024;
 
+  /**
+   * Constructor.
+   *
+   * @param port    Port number to bind to
+   */
   TServerSocket(int port);
-  TServerSocket(int port, int sendTimeout, int recvTimeout);
-  TServerSocket(std::string path);
 
-  ~TServerSocket();
+  /**
+   * Constructor.
+   *
+   * @param port        Port number to bind to
+   * @param sendTimeout Socket send timeout
+   * @param recvTimeout Socket receive timeout
+   */
+  TServerSocket(int port, int sendTimeout, int recvTimeout);
+
+  /**
+   * Constructor.
+   *
+   * @param address Address to bind to
+   * @param port    Port number to bind to
+   */
+  TServerSocket(const std::string& address, int port);
+
+  /**
+   * Constructor used for unix sockets.
+   *
+   * @param path Pathname for unix socket.
+   */
+  TServerSocket(const std::string& path);
+
+  virtual ~TServerSocket();
 
   void setSendTimeout(int sendTimeout);
   void setRecvTimeout(int recvTimeout);
@@ -52,20 +107,55 @@
   void setRetryLimit(int retryLimit);
   void setRetryDelay(int retryDelay);
 
+  void setKeepAlive(bool keepAlive) { keepAlive_ = keepAlive; }
+
   void setTcpSendBuffer(int tcpSendBuffer);
   void setTcpRecvBuffer(int tcpRecvBuffer);
 
+  // listenCallback gets called just before listen, and after all Thrift
+  // setsockopt calls have been made.  If you have custom setsockopt
+  // things that need to happen on the listening socket, this is the place to do it.
+  void setListenCallback(const socket_func_t& listenCallback) { listenCallback_ = listenCallback; }
+
+  // acceptCallback gets called after each accept call, on the newly created socket.
+  // It is called after all Thrift setsockopt calls have been made.  If you have
+  // custom setsockopt things that need to happen on the accepted
+  // socket, this is the place to do it.
+  void setAcceptCallback(const socket_func_t& acceptCallback) { acceptCallback_ = acceptCallback; }
+
+  // When enabled (the default), new children TSockets will be constructed so
+  // they can be interrupted by TServerTransport::interruptChildren().
+  // This is more expensive in terms of system calls (poll + recv) however
+  // ensures a connected client cannot interfere with TServer::stop().
+  //
+  // When disabled, TSocket children do not incur an additional poll() call.
+  // Server-side reads are more efficient, however a client can interfere with
+  // the server's ability to shutdown properly by staying connected.
+  //
+  // Must be called before listen(); mode cannot be switched after that.
+  // \throws std::logic_error if listen() has been called
+  void setInterruptableChildren(bool enable);
+
+  THRIFT_SOCKET getSocketFD() { return serverSocket_; }
+
+  int getPort();
+
   void listen();
+  void interrupt();
+  void interruptChildren();
   void close();
 
-  void interrupt();
+protected:
+  std::shared_ptr<TTransport> acceptImpl();
+  virtual std::shared_ptr<TSocket> createSocket(THRIFT_SOCKET client);
+  bool interruptableChildren_;
+  std::shared_ptr<THRIFT_SOCKET> pChildInterruptSockReader_; // if interruptableChildren_ this is shared with child TSockets
 
- protected:
-  boost::shared_ptr<TTransport> acceptImpl();
-  virtual boost::shared_ptr<TSocket> createSocket(THRIFT_SOCKET client);
+private:
+  void notify(THRIFT_SOCKET notifySock);
 
- private:
   int port_;
+  std::string address_;
   std::string path_;
   THRIFT_SOCKET serverSocket_;
   int acceptBacklog_;
@@ -76,11 +166,19 @@
   int retryDelay_;
   int tcpSendBuffer_;
   int tcpRecvBuffer_;
+  bool keepAlive_;
+  bool listening_;
 
-  THRIFT_SOCKET intSock1_;
-  THRIFT_SOCKET intSock2_;
+  concurrency::Mutex rwMutex_;                                 // thread-safe interrupt
+  THRIFT_SOCKET interruptSockWriter_;                          // is notified on interrupt()
+  THRIFT_SOCKET interruptSockReader_;                          // is used in select/poll with serverSocket_ for interruptability
+  THRIFT_SOCKET childInterruptSockWriter_;                     // is notified on interruptChildren()
+
+  socket_func_t listenCallback_;
+  socket_func_t acceptCallback_;
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_TSERVERSOCKET_H_
diff --git a/lib/cpp/src/thrift/transport/TServerTransport.h b/lib/cpp/src/thrift/transport/TServerTransport.h
index 2ddee0d..db7632a 100644
--- a/lib/cpp/src/thrift/transport/TServerTransport.h
+++ b/lib/cpp/src/thrift/transport/TServerTransport.h
@@ -22,17 +22,19 @@
 
 #include <thrift/transport/TTransport.h>
 #include <thrift/transport/TTransportException.h>
-#include <boost/shared_ptr.hpp>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * Server transport framework. A server needs to have some facility for
- * creating base transports to read/write from.
- *
+ * creating base transports to read/write from.  The server is expected
+ * to keep track of TTransport children that it creates for purposes of
+ * controlling their lifetime.
  */
 class TServerTransport {
- public:
+public:
   virtual ~TServerTransport() {}
 
   /**
@@ -53,8 +55,8 @@
    * @return A new TTransport object
    * @throws TTransportException if there is an error
    */
-  boost::shared_ptr<TTransport> accept() {
-    boost::shared_ptr<TTransport> result = acceptImpl();
+  std::shared_ptr<TTransport> accept() {
+    std::shared_ptr<TTransport> result = acceptImpl();
     if (!result) {
       throw TTransportException("accept() may not return NULL");
     }
@@ -65,16 +67,35 @@
    * For "smart" TServerTransport implementations that work in a multi
    * threaded context this can be used to break out of an accept() call.
    * It is expected that the transport will throw a TTransportException
-   * with the interrupted error code.
+   * with the INTERRUPTED error code.
+   *
+   * This will not make an attempt to interrupt any TTransport children.
    */
   virtual void interrupt() {}
 
   /**
+   * This will interrupt the children created by the server transport.
+   * allowing them to break out of any blocking data reception call.
+   * It is expected that the children will throw a TTransportException
+   * with the INTERRUPTED error code.
+   */
+  virtual void interruptChildren() {}
+
+  /**
+  * Utility method
+  *
+  * @return server socket file descriptor
+  * @throw TTransportException If an error occurs
+  */
+
+  virtual THRIFT_SOCKET getSocketFD() { return -1; }
+
+  /**
    * Closes this transport such that future calls to accept will do nothing.
    */
   virtual void close() = 0;
 
- protected:
+protected:
   TServerTransport() {}
 
   /**
@@ -83,10 +104,10 @@
    * @return A newly allocated TTransport object
    * @throw TTransportException If an error occurs
    */
-  virtual boost::shared_ptr<TTransport> acceptImpl() = 0;
-
+  virtual std::shared_ptr<TTransport> acceptImpl() = 0;
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_TSERVERTRANSPORT_H_
diff --git a/lib/cpp/src/thrift/transport/TShortReadTransport.h b/lib/cpp/src/thrift/transport/TShortReadTransport.h
index 8def354..118252d 100644
--- a/lib/cpp/src/thrift/transport/TShortReadTransport.h
+++ b/lib/cpp/src/thrift/transport/TShortReadTransport.h
@@ -25,7 +25,10 @@
 #include <thrift/transport/TTransport.h>
 #include <thrift/transport/TVirtualTransport.h>
 
-namespace apache { namespace thrift { namespace transport { namespace test {
+namespace apache {
+namespace thrift {
+namespace transport {
+namespace test {
 
 /**
  * This class is only meant for testing.  It wraps another transport.
@@ -34,64 +37,46 @@
  *
  */
 class TShortReadTransport : public TVirtualTransport<TShortReadTransport> {
- public:
-  TShortReadTransport(boost::shared_ptr<TTransport> transport, double full_prob)
-    : transport_(transport)
-    , fullProb_(full_prob)
-  {}
+public:
+  TShortReadTransport(std::shared_ptr<TTransport> transport, double full_prob)
+    : transport_(transport), fullProb_(full_prob) {}
 
-  bool isOpen() {
-    return transport_->isOpen();
-  }
+  bool isOpen() { return transport_->isOpen(); }
 
-  bool peek() {
-    return transport_->peek();
-  }
+  bool peek() { return transport_->peek(); }
 
-  void open() {
-    transport_->open();
-  }
+  void open() { transport_->open(); }
 
-  void close() {
-    transport_->close();
-  }
+  void close() { transport_->close(); }
 
   uint32_t read(uint8_t* buf, uint32_t len) {
     if (len == 0) {
       return 0;
     }
 
-    if (rand()/(double)RAND_MAX >= fullProb_) {
-      len = 1 + rand()%len;
+    if (rand() / (double)RAND_MAX >= fullProb_) {
+      len = 1 + rand() % len;
     }
     return transport_->read(buf, len);
   }
 
-  void write(const uint8_t* buf, uint32_t len) {
-    transport_->write(buf, len);
-  }
+  void write(const uint8_t* buf, uint32_t len) { transport_->write(buf, len); }
 
-  void flush() {
-    transport_->flush();
-  }
+  void flush() { transport_->flush(); }
 
-  const uint8_t* borrow(uint8_t* buf, uint32_t* len) {
-    return transport_->borrow(buf, len);
-  }
+  const uint8_t* borrow(uint8_t* buf, uint32_t* len) { return transport_->borrow(buf, len); }
 
-  void consume(uint32_t len) {
-    return transport_->consume(len);
-  }
+  void consume(uint32_t len) { return transport_->consume(len); }
 
-  boost::shared_ptr<TTransport> getUnderlyingTransport() {
-    return transport_;
-  }
+  std::shared_ptr<TTransport> getUnderlyingTransport() { return transport_; }
 
- protected:
-  boost::shared_ptr<TTransport> transport_;
+protected:
+  std::shared_ptr<TTransport> transport_;
   double fullProb_;
 };
-
-}}}} // apache::thrift::transport::test
+}
+}
+}
+} // apache::thrift::transport::test
 
 #endif // #ifndef _THRIFT_TRANSPORT_TSHORTREADTRANSPORT_H_
diff --git a/lib/cpp/src/thrift/transport/TSimpleFileTransport.cpp b/lib/cpp/src/thrift/transport/TSimpleFileTransport.cpp
index 9af1445..4b1399e 100644
--- a/lib/cpp/src/thrift/transport/TSimpleFileTransport.cpp
+++ b/lib/cpp/src/thrift/transport/TSimpleFileTransport.cpp
@@ -31,11 +31,12 @@
 #include <io.h>
 #endif
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
-TSimpleFileTransport::
-TSimpleFileTransport(const std::string& path, bool read, bool write)
-    : TFDTransport(-1, TFDTransport::CLOSE_ON_DESTROY) {
+TSimpleFileTransport::TSimpleFileTransport(const std::string& path, bool read, bool write)
+  : TFDTransport(-1, TFDTransport::CLOSE_ON_DESTROY) {
   int flags = 0;
   if (read && write) {
     flags = O_RDWR;
@@ -50,18 +51,17 @@
     flags |= O_CREAT | O_APPEND;
   }
 #ifndef _WIN32
-  mode_t mode = S_IRUSR | S_IWUSR| S_IRGRP | S_IROTH;
+  mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
 #else
   int mode = _S_IREAD | _S_IWRITE;
 #endif
-  int fd = ::open(path.c_str(),
-                  flags,
-                  mode);
+  int fd = ::THRIFT_OPEN(path.c_str(), flags, mode);
   if (fd < 0) {
     throw TTransportException("failed to open file for writing: " + path);
   }
   setFD(fd);
   open();
 }
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/TSimpleFileTransport.h b/lib/cpp/src/thrift/transport/TSimpleFileTransport.h
index 985a1d3..32e1897 100644
--- a/lib/cpp/src/thrift/transport/TSimpleFileTransport.h
+++ b/lib/cpp/src/thrift/transport/TSimpleFileTransport.h
@@ -22,7 +22,9 @@
 
 #include <thrift/transport/TFDTransport.h>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * Dead-simple wrapper around a file.
@@ -30,12 +32,11 @@
  * Writeable files are opened with O_CREAT and O_APPEND
  */
 class TSimpleFileTransport : public TFDTransport {
- public:
-  TSimpleFileTransport(const std::string& path,
-                       bool read =  true,
-                       bool write = false);
+public:
+  TSimpleFileTransport(const std::string& path, bool read = true, bool write = false);
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif //  _THRIFT_TRANSPORT_TSIMPLEFILETRANSPORT_H_
diff --git a/lib/cpp/src/thrift/transport/TSocket.cpp b/lib/cpp/src/thrift/transport/TSocket.cpp
index d521bb5..c6c2bfa 100644
--- a/lib/cpp/src/thrift/transport/TSocket.cpp
+++ b/lib/cpp/src/thrift/transport/TSocket.cpp
@@ -21,6 +21,9 @@
 
 #include <cstring>
 #include <sstream>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif
@@ -46,106 +49,147 @@
 #include <thrift/transport/PlatformSocket.h>
 
 #ifndef SOCKOPT_CAST_T
-#   ifndef _WIN32
-#       define SOCKOPT_CAST_T void
-#   else
-#       define SOCKOPT_CAST_T char
-#   endif // _WIN32
+#ifndef _WIN32
+#define SOCKOPT_CAST_T void
+#else
+#define SOCKOPT_CAST_T char
+#endif // _WIN32
 #endif
 
-template<class T>
+template <class T>
 inline const SOCKOPT_CAST_T* const_cast_sockopt(const T* v) {
-    return reinterpret_cast<const SOCKOPT_CAST_T*>(v);
+  return reinterpret_cast<const SOCKOPT_CAST_T*>(v);
 }
 
-template<class T>
+template <class T>
 inline SOCKOPT_CAST_T* cast_sockopt(T* v) {
-    return reinterpret_cast<SOCKOPT_CAST_T*>(v);
+  return reinterpret_cast<SOCKOPT_CAST_T*>(v);
 }
 
-namespace apache { namespace thrift { namespace transport {
+using std::string;
 
-using namespace std;
-
-// Global var to track total socket sys calls
-uint32_t g_socket_syscalls = 0;
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * TSocket implementation.
  *
  */
 
-TSocket::TSocket(string host, int port) :
-  host_(host),
-  port_(port),
-  path_(""),
-  socket_(THRIFT_INVALID_SOCKET),
-  connTimeout_(0),
-  sendTimeout_(0),
-  recvTimeout_(0),
-  lingerOn_(1),
-  lingerVal_(0),
-  noDelay_(1),
-  maxRecvRetries_(5) {
-  recvTimeval_.tv_sec = (int)(recvTimeout_/1000);
-  recvTimeval_.tv_usec = (int)((recvTimeout_%1000)*1000);
+TSocket::TSocket(const string& host, int port)
+  : host_(host),
+    port_(port),
+    socket_(THRIFT_INVALID_SOCKET),
+    peerPort_(0),
+    connTimeout_(0),
+    sendTimeout_(0),
+    recvTimeout_(0),
+    keepAlive_(false),
+    lingerOn_(1),
+    lingerVal_(0),
+    noDelay_(1),
+    maxRecvRetries_(5) {
 }
 
-TSocket::TSocket(string path) :
-  host_(""),
-  port_(0),
-  path_(path),
-  socket_(THRIFT_INVALID_SOCKET),
-  connTimeout_(0),
-  sendTimeout_(0),
-  recvTimeout_(0),
-  lingerOn_(1),
-  lingerVal_(0),
-  noDelay_(1),
-  maxRecvRetries_(5) {
-  recvTimeval_.tv_sec = (int)(recvTimeout_/1000);
-  recvTimeval_.tv_usec = (int)((recvTimeout_%1000)*1000);
+TSocket::TSocket(const string& path)
+  : port_(0),
+    path_(path),
+    socket_(THRIFT_INVALID_SOCKET),
+    peerPort_(0),
+    connTimeout_(0),
+    sendTimeout_(0),
+    recvTimeout_(0),
+    keepAlive_(false),
+    lingerOn_(1),
+    lingerVal_(0),
+    noDelay_(1),
+    maxRecvRetries_(5) {
   cachedPeerAddr_.ipv4.sin_family = AF_UNSPEC;
 }
 
-TSocket::TSocket() :
-  host_(""),
-  port_(0),
-  path_(""),
-  socket_(THRIFT_INVALID_SOCKET),
-  connTimeout_(0),
-  sendTimeout_(0),
-  recvTimeout_(0),
-  lingerOn_(1),
-  lingerVal_(0),
-  noDelay_(1),
-  maxRecvRetries_(5) {
-  recvTimeval_.tv_sec = (int)(recvTimeout_/1000);
-  recvTimeval_.tv_usec = (int)((recvTimeout_%1000)*1000);
+TSocket::TSocket()
+  : port_(0),
+    socket_(THRIFT_INVALID_SOCKET),
+    peerPort_(0),
+    connTimeout_(0),
+    sendTimeout_(0),
+    recvTimeout_(0),
+    keepAlive_(false),
+    lingerOn_(1),
+    lingerVal_(0),
+    noDelay_(1),
+    maxRecvRetries_(5) {
   cachedPeerAddr_.ipv4.sin_family = AF_UNSPEC;
 }
 
-TSocket::TSocket(THRIFT_SOCKET socket) :
-  host_(""),
-  port_(0),
-  path_(""),
-  socket_(socket),
-  connTimeout_(0),
-  sendTimeout_(0),
-  recvTimeout_(0),
-  lingerOn_(1),
-  lingerVal_(0),
-  noDelay_(1),
-  maxRecvRetries_(5) {
-  recvTimeval_.tv_sec = (int)(recvTimeout_/1000);
-  recvTimeval_.tv_usec = (int)((recvTimeout_%1000)*1000);
+TSocket::TSocket(THRIFT_SOCKET socket)
+  : port_(0),
+    socket_(socket),
+    peerPort_(0),
+    connTimeout_(0),
+    sendTimeout_(0),
+    recvTimeout_(0),
+    keepAlive_(false),
+    lingerOn_(1),
+    lingerVal_(0),
+    noDelay_(1),
+    maxRecvRetries_(5) {
   cachedPeerAddr_.ipv4.sin_family = AF_UNSPEC;
+#ifdef SO_NOSIGPIPE
+  {
+    int one = 1;
+    setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
+  }
+#endif
+}
+
+TSocket::TSocket(THRIFT_SOCKET socket, std::shared_ptr<THRIFT_SOCKET> interruptListener)
+  : port_(0),
+    socket_(socket),
+    peerPort_(0),
+    interruptListener_(interruptListener),
+    connTimeout_(0),
+    sendTimeout_(0),
+    recvTimeout_(0),
+    keepAlive_(false),
+    lingerOn_(1),
+    lingerVal_(0),
+    noDelay_(1),
+    maxRecvRetries_(5) {
+  cachedPeerAddr_.ipv4.sin_family = AF_UNSPEC;
+#ifdef SO_NOSIGPIPE
+  {
+    int one = 1;
+    setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
+  }
+#endif
 }
 
 TSocket::~TSocket() {
   close();
 }
 
+bool TSocket::hasPendingDataToRead() {
+  if (!isOpen()) {
+    return false;
+  }
+
+  int32_t retries = 0;
+  THRIFT_IOCTL_SOCKET_NUM_BYTES_TYPE numBytesAvailable;
+try_again:
+  int r = THRIFT_IOCTL_SOCKET(socket_, FIONREAD, &numBytesAvailable);
+  if (r == -1) {
+    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    if (errno_copy == THRIFT_EINTR && (retries++ < maxRecvRetries_)) {
+      goto try_again;
+    }
+    GlobalOutput.perror("TSocket::hasPendingDataToRead() THRIFT_IOCTL_SOCKET() " + getSocketInfo(), errno_copy);
+    throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
+  }
+  return numBytesAvailable > 0;
+}
+
 bool TSocket::isOpen() {
   return (socket_ != THRIFT_INVALID_SOCKET);
 }
@@ -154,34 +198,64 @@
   if (!isOpen()) {
     return false;
   }
+  if (interruptListener_) {
+    for (int retries = 0;;) {
+      struct THRIFT_POLLFD fds[2];
+      std::memset(fds, 0, sizeof(fds));
+      fds[0].fd = socket_;
+      fds[0].events = THRIFT_POLLIN;
+      fds[1].fd = *(interruptListener_.get());
+      fds[1].events = THRIFT_POLLIN;
+      int ret = THRIFT_POLL(fds, 2, (recvTimeout_ == 0) ? -1 : recvTimeout_);
+      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+      if (ret < 0) {
+        // error cases
+        if (errno_copy == THRIFT_EINTR && (retries++ < maxRecvRetries_)) {
+          continue;
+        }
+        GlobalOutput.perror("TSocket::peek() THRIFT_POLL() ", errno_copy);
+        throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
+      } else if (ret > 0) {
+        // Check the interruptListener
+        if (fds[1].revents & THRIFT_POLLIN) {
+          return false;
+        }
+        // There must be data or a disconnection, fall through to the PEEK
+        break;
+      } else {
+        // timeout
+        return false;
+      }
+    }
+  }
+
+  // Check to see if data is available or if the remote side closed
   uint8_t buf;
   int r = static_cast<int>(recv(socket_, cast_sockopt(&buf), 1, MSG_PEEK));
   if (r == -1) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    #if defined __FreeBSD__ || defined __MACH__
+#if defined __FreeBSD__ || defined __MACH__
     /* shigin:
      * freebsd returns -1 and THRIFT_ECONNRESET if socket was closed by
      * the other side
      */
-    if (errno_copy == THRIFT_ECONNRESET)
-    {
-      close();
+    if (errno_copy == THRIFT_ECONNRESET) {
       return false;
     }
-    #endif
+#endif
     GlobalOutput.perror("TSocket::peek() recv() " + getSocketInfo(), errno_copy);
     throw TTransportException(TTransportException::UNKNOWN, "recv()", errno_copy);
   }
   return (r > 0);
 }
 
-void TSocket::openConnection(struct addrinfo *res) {
+void TSocket::openConnection(struct addrinfo* res) {
 
   if (isOpen()) {
     return;
   }
 
-  if (! path_.empty()) {
+  if (!path_.empty()) {
     socket_ = socket(PF_UNIX, SOCK_STREAM, IPPROTO_IP);
   } else {
     socket_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
@@ -203,13 +277,24 @@
     setRecvTimeout(recvTimeout_);
   }
 
+  if (keepAlive_) {
+    setKeepAlive(keepAlive_);
+  }
+
   // Linger
   setLinger(lingerOn_, lingerVal_);
 
   // No delay
   setNoDelay(noDelay_);
 
-  // Uses a low min RTO if asked to.
+#ifdef SO_NOSIGPIPE
+  {
+    int one = 1;
+    setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
+  }
+#endif
+
+// Uses a low min RTO if asked to.
 #ifdef TCP_LOW_MIN_RTO
   if (getUseLowMinRto()) {
     int one = 1;
@@ -217,7 +302,6 @@
   }
 #endif
 
-
   // Set the socket to be non blocking for connect if a timeout exists
   int flags = THRIFT_FCNTL(socket_, THRIFT_F_GETFL, 0);
   if (connTimeout_ > 0) {
@@ -236,27 +320,38 @@
 
   // Connect the socket
   int ret;
-  if (! path_.empty()) {
+  if (!path_.empty()) {
 
 #ifndef _WIN32
-
-    struct sockaddr_un address;
-    socklen_t len;
-
-    if (path_.length() > sizeof(address.sun_path)) {
+    size_t len = path_.size() + 1;
+    if (len > sizeof(((sockaddr_un*)NULL)->sun_path)) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
       GlobalOutput.perror("TSocket::open() Unix Domain socket path too long", errno_copy);
       throw TTransportException(TTransportException::NOT_OPEN, " Unix Domain socket path too long");
     }
 
+    struct sockaddr_un address;
     address.sun_family = AF_UNIX;
-    THRIFT_SNPRINTF(address.sun_path, sizeof(address.sun_path), "%s", path_.c_str());
-    len = sizeof(address);
-    ret = connect(socket_, (struct sockaddr *) &address, len);
+    memcpy(address.sun_path, path_.c_str(), len);
 
+    socklen_t structlen = static_cast<socklen_t>(sizeof(address));
+
+    if (!address.sun_path[0]) { // abstract namespace socket
+#ifdef __linux__
+      // sun_path is not null-terminated in this case and structlen determines its length
+      structlen -= sizeof(address.sun_path) - len;
 #else
-      GlobalOutput.perror("TSocket::open() Unix Domain socket path not supported on windows", -99);
-      throw TTransportException(TTransportException::NOT_OPEN, " Unix Domain socket path not supported");
+      GlobalOutput.perror("TSocket::open() Abstract Namespace Domain sockets only supported on linux: ", -99);
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                " Abstract Namespace Domain socket path not supported");
+#endif
+    }
+
+    ret = connect(socket_, (struct sockaddr*)&address, structlen);
+#else
+    GlobalOutput.perror("TSocket::open() Unix Domain socket path not supported on windows", -99);
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              " Unix Domain socket path not supported");
 #endif
 
   } else {
@@ -268,15 +363,15 @@
     goto done;
   }
 
-  if ((THRIFT_GET_SOCKET_ERROR != THRIFT_EINPROGRESS) && (THRIFT_GET_SOCKET_ERROR != THRIFT_EWOULDBLOCK)) {
+  if ((THRIFT_GET_SOCKET_ERROR != THRIFT_EINPROGRESS)
+      && (THRIFT_GET_SOCKET_ERROR != THRIFT_EWOULDBLOCK)) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
     GlobalOutput.perror("TSocket::open() connect() " + getSocketInfo(), errno_copy);
     throw TTransportException(TTransportException::NOT_OPEN, "connect() failed", errno_copy);
   }
 
-
   struct THRIFT_POLLFD fds[1];
-  std::memset(fds, 0 , sizeof(fds));
+  std::memset(fds, 0, sizeof(fds));
   fds[0].fd = socket_;
   fds[0].events = THRIFT_POLLOUT;
   ret = THRIFT_POLL(fds, 1, connTimeout_);
@@ -296,7 +391,8 @@
     if (val == 0) {
       goto done;
     }
-    GlobalOutput.perror("TSocket::open() error on socket (after THRIFT_POLL) " + getSocketInfo(), val);
+    GlobalOutput.perror("TSocket::open() error on socket (after THRIFT_POLL) " + getSocketInfo(),
+                        val);
     throw TTransportException(TTransportException::NOT_OPEN, "socket open() error", val);
   } else if (ret == 0) {
     // socket timed out
@@ -310,9 +406,13 @@
     throw TTransportException(TTransportException::NOT_OPEN, "THRIFT_POLL() failed", errno_copy);
   }
 
- done:
+done:
   // Set socket back to normal mode (blocking)
-  THRIFT_FCNTL(socket_, THRIFT_F_SETFL, flags);
+  if (-1 == THRIFT_FCNTL(socket_, THRIFT_F_SETFL, flags)) {
+    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    GlobalOutput.perror("TSocket::open() THRIFT_FCNTL " + getSocketInfo(), errno_copy);
+    throw TTransportException(TTransportException::NOT_OPEN, "THRIFT_FCNTL() failed", errno_copy);
+  }
 
   if (path_.empty()) {
     setCachedAddress(res->ai_addr, static_cast<socklen_t>(res->ai_addrlen));
@@ -323,24 +423,24 @@
   if (isOpen()) {
     return;
   }
-  if (! path_.empty()) {
+  if (!path_.empty()) {
     unix_open();
   } else {
     local_open();
   }
 }
 
-void TSocket::unix_open(){
-  if (! path_.empty()) {
+void TSocket::unix_open() {
+  if (!path_.empty()) {
     // Unix Domain SOcket does not need addrinfo struct, so we pass NULL
     openConnection(NULL);
   }
 }
 
-void TSocket::local_open(){
+void TSocket::local_open() {
 
 #ifdef _WIN32
-    TWinsockSingleton::create();
+  TWinsockSingleton::create();
 #endif // _WIN32
 
   if (isOpen()) {
@@ -349,7 +449,7 @@
 
   // Validate port number
   if (port_ < 0 || port_ > 0xFFFF) {
-    throw TTransportException(TTransportException::NOT_OPEN, "Specified port is invalid");
+    throw TTransportException(TTransportException::BAD_ARGS, "Specified port is invalid");
   }
 
   struct addrinfo hints, *res, *res0;
@@ -365,11 +465,20 @@
 
   error = getaddrinfo(host_.c_str(), port, &hints, &res0);
 
+#ifdef _WIN32
+  if (error == WSANO_DATA) {
+    hints.ai_flags &= ~AI_ADDRCONFIG;
+    error = getaddrinfo(host_.c_str(), port, &hints, &res0);
+  }
+#endif
+
   if (error) {
-    string errStr = "TSocket::open() getaddrinfo() " + getSocketInfo() + string(THRIFT_GAI_STRERROR(error));
+    string errStr = "TSocket::open() getaddrinfo() " + getSocketInfo()
+                    + string(THRIFT_GAI_STRERROR(error));
     GlobalOutput(errStr.c_str());
     close();
-    throw TTransportException(TTransportException::NOT_OPEN, "Could not resolve host for client socket.");
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              "Could not resolve host for client socket.");
   }
 
   // Cycle through all the returned addresses until one
@@ -424,10 +533,10 @@
     // if a readTimeout is specified along with a max number of recv retries, then
     // the threshold will ensure that the read timeout is not exceeded even in the
     // case of resource errors
-    eagainThresholdMicros = (recvTimeout_*1000)/ ((maxRecvRetries_>0) ? maxRecvRetries_ : 2);
+    eagainThresholdMicros = (recvTimeout_ * 1000) / ((maxRecvRetries_ > 0) ? maxRecvRetries_ : 2);
   }
 
- try_again:
+try_again:
   // Read from the socket
   struct timeval begin;
   if (recvTimeout_ > 0) {
@@ -437,9 +546,41 @@
     // an THRIFT_EAGAIN is due to a timeout or an out-of-resource condition.
     begin.tv_sec = begin.tv_usec = 0;
   }
-  int got = static_cast<int>(recv(socket_, cast_sockopt(buf), len, 0));
-  int errno_copy = THRIFT_GET_SOCKET_ERROR; //THRIFT_GETTIMEOFDAY can change THRIFT_GET_SOCKET_ERROR
-  ++g_socket_syscalls;
+
+  int got = 0;
+
+  if (interruptListener_) {
+    struct THRIFT_POLLFD fds[2];
+    std::memset(fds, 0, sizeof(fds));
+    fds[0].fd = socket_;
+    fds[0].events = THRIFT_POLLIN;
+    fds[1].fd = *(interruptListener_.get());
+    fds[1].events = THRIFT_POLLIN;
+
+    int ret = THRIFT_POLL(fds, 2, (recvTimeout_ == 0) ? -1 : recvTimeout_);
+    int errno_copy = THRIFT_GET_SOCKET_ERROR;
+    if (ret < 0) {
+      // error cases
+      if (errno_copy == THRIFT_EINTR && (retries++ < maxRecvRetries_)) {
+        goto try_again;
+      }
+      GlobalOutput.perror("TSocket::read() THRIFT_POLL() ", errno_copy);
+      throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
+    } else if (ret > 0) {
+      // Check the interruptListener
+      if (fds[1].revents & THRIFT_POLLIN) {
+        throw TTransportException(TTransportException::INTERRUPTED, "Interrupted");
+      }
+    } else /* ret == 0 */ {
+      throw TTransportException(TTransportException::TIMED_OUT, "THRIFT_EAGAIN (timed out)");
+    }
+
+    // falling through means there is something to recv and it cannot block
+  }
+
+  got = static_cast<int>(recv(socket_, cast_sockopt(buf), len, 0));
+  // THRIFT_GETTIMEOFDAY can change THRIFT_GET_SOCKET_ERROR
+  int errno_copy = THRIFT_GET_SOCKET_ERROR;
 
   // Check for error on read
   if (got < 0) {
@@ -447,14 +588,13 @@
       // if no timeout we can assume that resource exhaustion has occurred.
       if (recvTimeout_ == 0) {
         throw TTransportException(TTransportException::TIMED_OUT,
-                                    "THRIFT_EAGAIN (unavailable resources)");
+                                  "THRIFT_EAGAIN (unavailable resources)");
       }
       // check if this is the lack of resources or timeout case
       struct timeval end;
       THRIFT_GETTIMEOFDAY(&end, NULL);
-      uint32_t readElapsedMicros =  static_cast<uint32_t>(
-         ((end.tv_sec - begin.tv_sec) * 1000 * 1000)
-         + (((uint64_t)(end.tv_usec - begin.tv_usec))));
+      uint32_t readElapsedMicros = static_cast<uint32_t>(((end.tv_sec - begin.tv_sec) * 1000 * 1000)
+                                                         + (end.tv_usec - begin.tv_usec));
 
       if (!eagainThresholdMicros || (readElapsedMicros < eagainThresholdMicros)) {
         if (retries++ < maxRecvRetries_) {
@@ -466,8 +606,7 @@
         }
       } else {
         // infer that timeout has been hit
-        throw TTransportException(TTransportException::TIMED_OUT,
-                                  "THRIFT_EAGAIN (timed out)");
+        throw TTransportException(TTransportException::TIMED_OUT, "THRIFT_EAGAIN (timed out)");
       }
     }
 
@@ -476,29 +615,9 @@
       goto try_again;
     }
 
-    #if defined __FreeBSD__ || defined __MACH__
     if (errno_copy == THRIFT_ECONNRESET) {
-      /* shigin: freebsd doesn't follow POSIX semantic of recv and fails with
-       * THRIFT_ECONNRESET if peer performed shutdown
-       * edhall: eliminated close() since we do that in the destructor.
-       */
       return 0;
     }
-    #endif
-
-#ifdef _WIN32
-    if(errno_copy == WSAECONNRESET) {
-      return 0; // EOF
-    }
-#endif
-
-    // Now it's not a try again case, but a real probblez
-    GlobalOutput.perror("TSocket::read() recv() " + getSocketInfo(), errno_copy);
-
-    // If we disconnect with no linger time
-    if (errno_copy == THRIFT_ECONNRESET) {
-      throw TTransportException(TTransportException::NOT_OPEN, "THRIFT_ECONNRESET");
-    }
 
     // This ish isn't open
     if (errno_copy == THRIFT_ENOTCONN) {
@@ -510,18 +629,13 @@
       throw TTransportException(TTransportException::TIMED_OUT, "THRIFT_ETIMEDOUT");
     }
 
+    // Now it's not a try again case, but a real probblez
+    GlobalOutput.perror("TSocket::read() recv() " + getSocketInfo(), errno_copy);
+
     // Some other error, whatevz
     throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
   }
 
-  // The remote host has closed the socket
-  if (got == 0) {
-    // edhall: we used to call close() here, but our caller may want to deal
-    // with the socket fd and we'll close() in our destructor in any case.
-    return 0;
-  }
-
-  // Pack data into string
   return got;
 }
 
@@ -533,8 +647,7 @@
     if (b == 0) {
       // This should only happen if the timeout set with SO_SNDTIMEO expired.
       // Raise an exception.
-      throw TTransportException(TTransportException::TIMED_OUT,
-                                "send timeout expired");
+      throw TTransportException(TTransportException::TIMED_OUT, "send timeout expired");
     }
     sent += b;
   }
@@ -555,7 +668,6 @@
 #endif // ifdef MSG_NOSIGNAL
 
   int b = static_cast<int>(send(socket_, const_cast_sockopt(buf + sent), len - sent, flags));
-  ++g_socket_syscalls;
 
   if (b < 0) {
     if (THRIFT_GET_SOCKET_ERROR == THRIFT_EWOULDBLOCK || THRIFT_GET_SOCKET_ERROR == THRIFT_EAGAIN) {
@@ -565,8 +677,8 @@
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
     GlobalOutput.perror("TSocket::write_partial() send() " + getSocketInfo(), errno_copy);
 
-    if (errno_copy == THRIFT_EPIPE || errno_copy == THRIFT_ECONNRESET || errno_copy == THRIFT_ENOTCONN) {
-      close();
+    if (errno_copy == THRIFT_EPIPE || errno_copy == THRIFT_ECONNRESET
+        || errno_copy == THRIFT_ENOTCONN) {
       throw TTransportException(TTransportException::NOT_OPEN, "write() send()", errno_copy);
     }
 
@@ -603,10 +715,16 @@
     return;
   }
 
+#ifndef _WIN32
   struct linger l = {(lingerOn_ ? 1 : 0), lingerVal_};
+#else
+  struct linger l = {static_cast<u_short>(lingerOn_ ? 1 : 0), static_cast<u_short>(lingerVal_)};
+#endif
+
   int ret = setsockopt(socket_, SOL_SOCKET, SO_LINGER, cast_sockopt(&l), sizeof(l));
   if (ret == -1) {
-    int errno_copy = THRIFT_GET_SOCKET_ERROR;  // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
+    int errno_copy
+        = THRIFT_GET_SOCKET_ERROR; // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
     GlobalOutput.perror("TSocket::setLinger() setsockopt() " + getSocketInfo(), errno_copy);
   }
 }
@@ -621,7 +739,8 @@
   int v = noDelay_ ? 1 : 0;
   int ret = setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, cast_sockopt(&v), sizeof(v));
   if (ret == -1) {
-    int errno_copy = THRIFT_GET_SOCKET_ERROR;  // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
+    int errno_copy
+        = THRIFT_GET_SOCKET_ERROR; // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
     GlobalOutput.perror("TSocket::setNoDelay() setsockopt() " + getSocketInfo(), errno_copy);
   }
 }
@@ -630,50 +749,57 @@
   connTimeout_ = ms;
 }
 
-void TSocket::setRecvTimeout(int ms) {
-  if (ms < 0) {
+void setGenericTimeout(THRIFT_SOCKET s, int timeout_ms, int optname) {
+  if (timeout_ms < 0) {
     char errBuf[512];
-    sprintf(errBuf, "TSocket::setRecvTimeout with negative input: %d\n", ms);
+    sprintf(errBuf, "TSocket::setGenericTimeout with negative input: %d\n", timeout_ms);
     GlobalOutput(errBuf);
     return;
   }
-  recvTimeout_ = ms;
 
-  if (socket_ == THRIFT_INVALID_SOCKET) {
+  if (s == THRIFT_INVALID_SOCKET) {
     return;
   }
 
-  recvTimeval_.tv_sec = (int)(recvTimeout_/1000);
-  recvTimeval_.tv_usec = (int)((recvTimeout_%1000)*1000);
+#ifdef _WIN32
+  DWORD platform_time = static_cast<DWORD>(timeout_ms);
+#else
+  struct timeval platform_time = {(int)(timeout_ms / 1000), (int)((timeout_ms % 1000) * 1000)};
+#endif
 
-  // Copy because THRIFT_POLL may modify
-  struct timeval r = recvTimeval_;
-  int ret = setsockopt(socket_, SOL_SOCKET, SO_RCVTIMEO, cast_sockopt(&r), sizeof(r));
+  int ret = setsockopt(s, SOL_SOCKET, optname, cast_sockopt(&platform_time), sizeof(platform_time));
   if (ret == -1) {
-    int errno_copy = THRIFT_GET_SOCKET_ERROR;  // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
-    GlobalOutput.perror("TSocket::setRecvTimeout() setsockopt() " + getSocketInfo(), errno_copy);
+    int errno_copy
+        = THRIFT_GET_SOCKET_ERROR; // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
+    GlobalOutput.perror("TSocket::setGenericTimeout() setsockopt() ", errno_copy);
   }
 }
 
+void TSocket::setRecvTimeout(int ms) {
+  setGenericTimeout(socket_, ms, SO_RCVTIMEO);
+  recvTimeout_ = ms;
+}
+
 void TSocket::setSendTimeout(int ms) {
-  if (ms < 0) {
-    char errBuf[512];
-    sprintf(errBuf, "TSocket::setSendTimeout with negative input: %d\n", ms);
-    GlobalOutput(errBuf);
-    return;
-  }
+  setGenericTimeout(socket_, ms, SO_SNDTIMEO);
   sendTimeout_ = ms;
+}
+
+void TSocket::setKeepAlive(bool keepAlive) {
+  keepAlive_ = keepAlive;
 
   if (socket_ == THRIFT_INVALID_SOCKET) {
     return;
   }
 
-  struct timeval s = {(int)(sendTimeout_/1000),
-                      (int)((sendTimeout_%1000)*1000)};
-  int ret = setsockopt(socket_, SOL_SOCKET, SO_SNDTIMEO, cast_sockopt(&s), sizeof(s));
+  int value = keepAlive_;
+  int ret
+      = setsockopt(socket_, SOL_SOCKET, SO_KEEPALIVE, const_cast_sockopt(&value), sizeof(value));
+
   if (ret == -1) {
-    int errno_copy = THRIFT_GET_SOCKET_ERROR;  // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
-    GlobalOutput.perror("TSocket::setSendTimeout() setsockopt() " + getSocketInfo(), errno_copy);
+    int errno_copy
+        = THRIFT_GET_SOCKET_ERROR; // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
+    GlobalOutput.perror("TSocket::setKeepAlive() setsockopt() " + getSocketInfo(), errno_copy);
   }
 }
 
@@ -683,11 +809,15 @@
 
 string TSocket::getSocketInfo() {
   std::ostringstream oss;
-  if (host_.empty() || port_ == 0) {
-    oss << "<Host: " << getPeerAddress();
-    oss << " Port: " << getPeerPort() << ">";
+  if (path_.empty()) {
+    if (host_.empty() || port_ == 0) {
+      oss << "<Host: " << getPeerAddress();
+      oss << " Port: " << getPeerPort() << ">";
+    } else {
+      oss << "<Host: " << host_ << " Port: " << port_ << ">";
+    }
   } else {
-    oss << "<Host: " << host_ << " Port: " << port_ << ">";
+    oss << "<Path: " << path_ << ">";
   }
   return oss.str();
 }
@@ -706,7 +836,7 @@
 
     if (addrPtr == NULL) {
       addrLen = sizeof(addr);
-      if (getpeername(socket_, (sockaddr*) &addr, &addrLen) != 0) {
+      if (getpeername(socket_, (sockaddr*)&addr, &addrLen) != 0) {
         return peerHost_;
       }
       addrPtr = (sockaddr*)&addr;
@@ -717,9 +847,13 @@
     char clienthost[NI_MAXHOST];
     char clientservice[NI_MAXSERV];
 
-    getnameinfo((sockaddr*) addrPtr, addrLen,
-                clienthost, sizeof(clienthost),
-                clientservice, sizeof(clientservice), 0);
+    getnameinfo((sockaddr*)addrPtr,
+                addrLen,
+                clienthost,
+                sizeof(clienthost),
+                clientservice,
+                sizeof(clientservice),
+                0);
 
     peerHost_ = clienthost;
   }
@@ -740,7 +874,7 @@
 
     if (addrPtr == NULL) {
       addrLen = sizeof(addr);
-      if (getpeername(socket_, (sockaddr*) &addr, &addrLen) != 0) {
+      if (getpeername(socket_, (sockaddr*)&addr, &addrLen) != 0) {
         return peerAddress_;
       }
       addrPtr = (sockaddr*)&addr;
@@ -751,10 +885,13 @@
     char clienthost[NI_MAXHOST];
     char clientservice[NI_MAXSERV];
 
-    getnameinfo(addrPtr, addrLen,
-                clienthost, sizeof(clienthost),
-                clientservice, sizeof(clientservice),
-                NI_NUMERICHOST|NI_NUMERICSERV);
+    getnameinfo(addrPtr,
+                addrLen,
+                clienthost,
+                sizeof(clienthost),
+                clientservice,
+                sizeof(clientservice),
+                NI_NUMERICHOST | NI_NUMERICSERV);
 
     peerAddress_ = clienthost;
     peerPort_ = std::atoi(clientservice);
@@ -785,17 +922,19 @@
     }
     break;
   }
+  peerAddress_.clear();
+  peerHost_.clear();
 }
 
 sockaddr* TSocket::getCachedAddress(socklen_t* len) const {
   switch (cachedPeerAddr_.ipv4.sin_family) {
   case AF_INET:
     *len = sizeof(sockaddr_in);
-    return (sockaddr*) &cachedPeerAddr_.ipv4;
+    return (sockaddr*)&cachedPeerAddr_.ipv4;
 
   case AF_INET6:
     *len = sizeof(sockaddr_in6);
-    return (sockaddr*) &cachedPeerAddr_.ipv6;
+    return (sockaddr*)&cachedPeerAddr_.ipv6;
 
   default:
     return NULL;
@@ -810,4 +949,11 @@
   return useLowMinRto_;
 }
 
-}}} // apache::thrift::transport
+const std::string TSocket::getOrigin() {
+  std::ostringstream oss;
+  oss << getPeerHost() << ":" << getPeerPort();
+  return oss.str();
+}
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/TSocket.h b/lib/cpp/src/thrift/transport/TSocket.h
index fd5b961..4030d46 100644
--- a/lib/cpp/src/thrift/transport/TSocket.h
+++ b/lib/cpp/src/thrift/transport/TSocket.h
@@ -37,14 +37,16 @@
 #include <netdb.h>
 #endif
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * TCP Socket implementation of the TTransport interface.
  *
  */
 class TSocket : public TVirtualTransport<TSocket> {
- public:
+public:
   /**
    * Constructs a new socket. Note that this does NOT actually connect the
    * socket.
@@ -59,7 +61,7 @@
    * @param host An IP address or hostname to connect to
    * @param port The port to connect on
    */
-  TSocket(std::string host, int port);
+  TSocket(const std::string& host, int port);
 
   /**
    * Constructs a new Unix domain socket.
@@ -67,7 +69,7 @@
    *
    * @param path The Unix domain socket e.g. "/tmp/ThriftTest.binary.thrift"
    */
-  TSocket(std::string path);
+  TSocket(const std::string& path);
 
   /**
    * Destroyes the socket object, closing it if necessary.
@@ -82,7 +84,9 @@
   virtual bool isOpen();
 
   /**
-   * Calls select on the socket to see if there is more data available.
+   * Checks whether there is more data available in the socket to read.
+   *
+   * This call blocks until at least one byte is available or the socket is closed.
    */
   virtual bool peek();
 
@@ -99,7 +103,25 @@
   virtual void close();
 
   /**
+   * Determines whether there is pending data to read or not.
+   *
+   * This call does not block.
+   * \throws TTransportException of types:
+   *           NOT_OPEN means the socket has been closed
+   *           UNKNOWN means something unexpected happened
+   * \returns true if there is pending data to read, false otherwise
+   */
+  virtual bool hasPendingDataToRead();
+
+  /**
    * Reads from the underlying socket.
+   * \returns the number of bytes read or 0 indicates EOF
+   * \throws TTransportException of types:
+   *           INTERRUPTED means the socket was interrupted
+   *                       out of a blocking call
+   *           NOT_OPEN means the socket has been closed
+   *           TIMED_OUT means the receive timeout expired
+   *           UNKNOWN means something unexpected happened
    */
   virtual uint32_t read(uint8_t* buf, uint32_t len);
 
@@ -111,7 +133,7 @@
   /**
    * Writes to the underlying socket.  Does single send() and returns result.
    */
-  uint32_t write_partial(const uint8_t* buf, uint32_t len);
+  virtual uint32_t write_partial(const uint8_t* buf, uint32_t len);
 
   /**
    * Get the host that the socket is connected to
@@ -179,7 +201,12 @@
   void setMaxRecvRetries(int maxRecvRetries);
 
   /**
-   * Get socket information formated as a string <Host: x Port: x>
+   * Set SO_KEEPALIVE
+   */
+  void setKeepAlive(bool keepAlive);
+
+  /**
+   * Get socket information formatted as a string <Host: x Port: x>
    */
   std::string getSocketInfo();
 
@@ -201,9 +228,7 @@
   /**
    * Returns the underlying socket file descriptor.
    */
-  THRIFT_SOCKET getSocketFD() {
-    return socket_;
-  }
+  THRIFT_SOCKET getSocketFD() { return socket_; }
 
   /**
    * (Re-)initialize a TSocket for the supplied descriptor.  This is only
@@ -230,23 +255,45 @@
   static bool getUseLowMinRto();
 
   /**
-   * Constructor to create socket from raw UNIX handle.
+   * Get the origin the socket is connected to
+   *
+   * @return string peer host identifier and port
+   */
+  virtual const std::string getOrigin();
+
+  /**
+   * Constructor to create socket from file descriptor.
    */
   TSocket(THRIFT_SOCKET socket);
 
   /**
+   * Constructor to create socket from file descriptor that
+   * can be interrupted safely.
+   */
+  TSocket(THRIFT_SOCKET socket, std::shared_ptr<THRIFT_SOCKET> interruptListener);
+
+  /**
    * Set a cache of the peer address (used when trivially available: e.g.
    * accept() or connect()). Only caches IPV4 and IPV6; unset for others.
    */
   void setCachedAddress(const sockaddr* addr, socklen_t len);
 
- protected:
+protected:
   /** connect, called by open */
-  void openConnection(struct addrinfo *res);
+  void openConnection(struct addrinfo* res);
 
   /** Host to connect to */
   std::string host_;
 
+  /** Port number to connect on */
+  int port_;
+
+  /** UNIX domain socket path */
+  std::string path_;
+
+  /** Underlying socket handle */
+  THRIFT_SOCKET socket_;
+
   /** Peer hostname */
   std::string peerHost_;
 
@@ -256,14 +303,11 @@
   /** Peer port */
   int peerPort_;
 
-  /** Port number to connect on */
-  int port_;
-
-  /** UNIX domain socket path */
-  std::string path_;
-
-  /** Underlying UNIX socket handle */
-  THRIFT_SOCKET socket_;
+  /**
+   * A shared socket pointer that will interrupt a blocking read if data
+   * becomes available on it
+   */
+  std::shared_ptr<THRIFT_SOCKET> interruptListener_;
 
   /** Connect timeout in ms */
   int connTimeout_;
@@ -274,6 +318,9 @@
   /** Recv timeout in ms */
   int recvTimeout_;
 
+  /** Keep alive on */
+  bool keepAlive_;
+
   /** Linger on */
   bool lingerOn_;
 
@@ -286,9 +333,6 @@
   /** Recv EGAIN retries */
   int maxRecvRetries_;
 
-  /** Recv timeout timeval */
-  struct timeval recvTimeval_;
-
   /** Cached peer address */
   union {
     sockaddr_in ipv4;
@@ -298,12 +342,12 @@
   /** Whether to use low minimum TCP retransmission timeout */
   static bool useLowMinRto_;
 
- private:
+private:
   void unix_open();
   void local_open();
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_TSOCKET_H_
-
diff --git a/lib/cpp/src/thrift/transport/TSocketPool.cpp b/lib/cpp/src/thrift/transport/TSocketPool.cpp
index e0b286a..5477bbb 100644
--- a/lib/cpp/src/thrift/transport/TSocketPool.cpp
+++ b/lib/cpp/src/thrift/transport/TSocketPool.cpp
@@ -21,57 +21,62 @@
 
 #include <algorithm>
 #include <iostream>
+#if __cplusplus >= 201703L
+#include <random>
+#endif
 
 #include <thrift/transport/TSocketPool.h>
 
-namespace apache { namespace thrift { namespace transport {
+using std::pair;
+using std::string;
+using std::vector;
 
-using namespace std;
+namespace apache {
+namespace thrift {
+namespace transport {
 
-using boost::shared_ptr;
+using std::shared_ptr;
 
 /**
  * TSocketPoolServer implementation
  *
  */
 TSocketPoolServer::TSocketPoolServer()
-  : host_(""),
-    port_(0),
-    socket_(THRIFT_INVALID_SOCKET),
-    lastFailTime_(0),
-    consecutiveFailures_(0) {}
+  : host_(""), port_(0), socket_(THRIFT_INVALID_SOCKET), lastFailTime_(0), consecutiveFailures_(0) {
+}
 
 /**
  * Constructor for TSocketPool server
  */
-TSocketPoolServer::TSocketPoolServer(const string &host, int port)
+TSocketPoolServer::TSocketPoolServer(const string& host, int port)
   : host_(host),
     port_(port),
     socket_(THRIFT_INVALID_SOCKET),
     lastFailTime_(0),
-    consecutiveFailures_(0) {}
+    consecutiveFailures_(0) {
+}
 
 /**
  * TSocketPool implementation.
  *
  */
 
-TSocketPool::TSocketPool() : TSocket(),
-  numRetries_(1),
-  retryInterval_(60),
-  maxConsecutiveFailures_(1),
-  randomize_(true),
-  alwaysTryLast_(true) {
+TSocketPool::TSocketPool()
+  : TSocket(),
+    numRetries_(1),
+    retryInterval_(60),
+    maxConsecutiveFailures_(1),
+    randomize_(true),
+    alwaysTryLast_(true) {
 }
 
-TSocketPool::TSocketPool(const vector<string> &hosts,
-                         const vector<int> &ports) : TSocket(),
-  numRetries_(1),
-  retryInterval_(60),
-  maxConsecutiveFailures_(1),
-  randomize_(true),
-  alwaysTryLast_(true)
-{
+TSocketPool::TSocketPool(const vector<string>& hosts, const vector<int>& ports)
+  : TSocket(),
+    numRetries_(1),
+    retryInterval_(60),
+    maxConsecutiveFailures_(1),
+    randomize_(true),
+    alwaysTryLast_(true) {
   if (hosts.size() != ports.size()) {
     GlobalOutput("TSocketPool::TSocketPool: hosts.size != ports.size");
     throw TTransportException(TTransportException::BAD_ARGS);
@@ -82,41 +87,41 @@
   }
 }
 
-TSocketPool::TSocketPool(const vector<pair<string, int> >& servers) : TSocket(),
-  numRetries_(1),
-  retryInterval_(60),
-  maxConsecutiveFailures_(1),
-  randomize_(true),
-  alwaysTryLast_(true)
-{
+TSocketPool::TSocketPool(const vector<pair<string, int> >& servers)
+  : TSocket(),
+    numRetries_(1),
+    retryInterval_(60),
+    maxConsecutiveFailures_(1),
+    randomize_(true),
+    alwaysTryLast_(true) {
   for (unsigned i = 0; i < servers.size(); ++i) {
     addServer(servers[i].first, servers[i].second);
   }
 }
 
-TSocketPool::TSocketPool(const vector< shared_ptr<TSocketPoolServer> >& servers) : TSocket(),
-  servers_(servers),
-  numRetries_(1),
-  retryInterval_(60),
-  maxConsecutiveFailures_(1),
-  randomize_(true),
-  alwaysTryLast_(true)
-{
+TSocketPool::TSocketPool(const vector<shared_ptr<TSocketPoolServer> >& servers)
+  : TSocket(),
+    servers_(servers),
+    numRetries_(1),
+    retryInterval_(60),
+    maxConsecutiveFailures_(1),
+    randomize_(true),
+    alwaysTryLast_(true) {
 }
 
-TSocketPool::TSocketPool(const string& host, int port) : TSocket(),
-  numRetries_(1),
-  retryInterval_(60),
-  maxConsecutiveFailures_(1),
-  randomize_(true),
-  alwaysTryLast_(true)
-{
+TSocketPool::TSocketPool(const string& host, int port)
+  : TSocket(),
+    numRetries_(1),
+    retryInterval_(60),
+    maxConsecutiveFailures_(1),
+    randomize_(true),
+    alwaysTryLast_(true) {
   addServer(host, port);
 }
 
 TSocketPool::~TSocketPool() {
-  vector< shared_ptr<TSocketPoolServer> >::const_iterator iter = servers_.begin();
-  vector< shared_ptr<TSocketPoolServer> >::const_iterator iterEnd = servers_.end();
+  vector<shared_ptr<TSocketPoolServer> >::const_iterator iter = servers_.begin();
+  vector<shared_ptr<TSocketPoolServer> >::const_iterator iterEnd = servers_.end();
   for (; iter != iterEnd; ++iter) {
     setCurrentServer(*iter);
     TSocketPool::close();
@@ -127,17 +132,17 @@
   servers_.push_back(shared_ptr<TSocketPoolServer>(new TSocketPoolServer(host, port)));
 }
 
-void TSocketPool::addServer(shared_ptr<TSocketPoolServer> &server) {
+void TSocketPool::addServer(shared_ptr<TSocketPoolServer>& server) {
   if (server) {
     servers_.push_back(server);
   }
 }
 
-void TSocketPool::setServers(const vector< shared_ptr<TSocketPoolServer> >& servers) {
+void TSocketPool::setServers(const vector<shared_ptr<TSocketPoolServer> >& servers) {
   servers_ = servers;
 }
 
-void TSocketPool::getServers(vector< shared_ptr<TSocketPoolServer> >& servers) {
+void TSocketPool::getServers(vector<shared_ptr<TSocketPoolServer> >& servers) {
   servers = servers_;
 }
 
@@ -149,7 +154,6 @@
   retryInterval_ = retryInterval;
 }
 
-
 void TSocketPool::setMaxConsecutiveFailures(int maxConsecutiveFailures) {
   maxConsecutiveFailures_ = maxConsecutiveFailures;
 }
@@ -162,7 +166,7 @@
   alwaysTryLast_ = alwaysTryLast;
 }
 
-void TSocketPool::setCurrentServer(const shared_ptr<TSocketPoolServer> &server) {
+void TSocketPool::setCurrentServer(const shared_ptr<TSocketPoolServer>& server) {
   currentServer_ = server;
   host_ = server->host_;
   port_ = server->port_;
@@ -187,12 +191,18 @@
   }
 
   if (randomize_ && numServers > 1) {
-    random_shuffle(servers_.begin(), servers_.end());
+#if __cplusplus >= 201703L
+    std::random_device rng;
+    std::mt19937 urng(rng());
+    std::shuffle(servers_.begin(), servers_.end(), urng);
+#else
+    std::random_shuffle(servers_.begin(), servers_.end());
+#endif
   }
 
   for (size_t i = 0; i < numServers; ++i) {
 
-    shared_ptr<TSocketPoolServer> &server = servers_[i];
+    shared_ptr<TSocketPoolServer>& server = servers_[i];
     // Impersonate the server socket
     setCurrentServer(server);
 
@@ -216,8 +226,8 @@
       for (int j = 0; j < numRetries_; ++j) {
         try {
           TSocket::open();
-        } catch (TException e) {
-          string errStr = "TSocketPool::open failed "+getSocketInfo()+": "+e.what();
+        } catch (const TException &e) {
+          string errStr = "TSocketPool::open failed " + getSocketInfo() + ": " + e.what();
           GlobalOutput(errStr.c_str());
           socket_ = THRIFT_INVALID_SOCKET;
           continue;
@@ -250,5 +260,6 @@
     currentServer_->socket_ = THRIFT_INVALID_SOCKET;
   }
 }
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/TSocketPool.h b/lib/cpp/src/thrift/transport/TSocketPool.h
index 7728257..18f101c 100644
--- a/lib/cpp/src/thrift/transport/TSocketPool.h
+++ b/lib/cpp/src/thrift/transport/TSocketPool.h
@@ -23,15 +23,17 @@
 #include <vector>
 #include <thrift/transport/TSocket.h>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
- /**
-  * Class to hold server information for TSocketPool
-  *
-  */
+/**
+ * Class to hold server information for TSocketPool
+ *
+ */
 class TSocketPoolServer {
 
-  public:
+public:
   /**
    * Default constructor for server info
    */
@@ -40,7 +42,7 @@
   /**
    * Constructor for TSocketPool server
    */
-  TSocketPoolServer(const std::string &host, int port);
+  TSocketPoolServer(const std::string& host, int port);
 
   // Host name
   std::string host_;
@@ -64,133 +66,130 @@
  */
 class TSocketPool : public TSocket {
 
- public:
+public:
+  /**
+   * Socket pool constructor
+   */
+  TSocketPool();
 
-   /**
-    * Socket pool constructor
-    */
-   TSocketPool();
+  /**
+   * Socket pool constructor
+   *
+   * @param hosts list of host names
+   * @param ports list of port names
+   */
+  TSocketPool(const std::vector<std::string>& hosts, const std::vector<int>& ports);
 
-   /**
-    * Socket pool constructor
-    *
-    * @param hosts list of host names
-    * @param ports list of port names
-    */
-   TSocketPool(const std::vector<std::string> &hosts,
-               const std::vector<int> &ports);
+  /**
+   * Socket pool constructor
+   *
+   * @param servers list of pairs of host name and port
+   */
+  TSocketPool(const std::vector<std::pair<std::string, int> >& servers);
 
-   /**
-    * Socket pool constructor
-    *
-    * @param servers list of pairs of host name and port
-    */
-   TSocketPool(const std::vector<std::pair<std::string, int> >& servers);
+  /**
+   * Socket pool constructor
+   *
+   * @param servers list of TSocketPoolServers
+   */
+  TSocketPool(const std::vector<std::shared_ptr<TSocketPoolServer> >& servers);
 
-   /**
-    * Socket pool constructor
-    *
-    * @param servers list of TSocketPoolServers
-    */
-  TSocketPool(const std::vector< boost::shared_ptr<TSocketPoolServer> >& servers);
+  /**
+   * Socket pool constructor
+   *
+   * @param host single host
+   * @param port single port
+   */
+  TSocketPool(const std::string& host, int port);
 
-   /**
-    * Socket pool constructor
-    *
-    * @param host single host
-    * @param port single port
-    */
-   TSocketPool(const std::string& host, int port);
+  /**
+   * Destroyes the socket object, closing it if necessary.
+   */
+  virtual ~TSocketPool();
 
-   /**
-    * Destroyes the socket object, closing it if necessary.
-    */
-   virtual ~TSocketPool();
+  /**
+   * Add a server to the pool
+   */
+  void addServer(const std::string& host, int port);
 
-   /**
-    * Add a server to the pool
-    */
-   void addServer(const std::string& host, int port);
+  /**
+   * Add a server to the pool
+   */
+  void addServer(std::shared_ptr<TSocketPoolServer>& server);
 
-   /**
-    * Add a server to the pool
-    */
-  void addServer(boost::shared_ptr<TSocketPoolServer> &server);
+  /**
+   * Set list of servers in this pool
+   */
+  void setServers(const std::vector<std::shared_ptr<TSocketPoolServer> >& servers);
 
-   /**
-    * Set list of servers in this pool
-    */
-  void setServers(const std::vector< boost::shared_ptr<TSocketPoolServer> >& servers);
+  /**
+   * Get list of servers in this pool
+   */
+  void getServers(std::vector<std::shared_ptr<TSocketPoolServer> >& servers);
 
-   /**
-    * Get list of servers in this pool
-    */
-  void getServers(std::vector< boost::shared_ptr<TSocketPoolServer> >& servers);
+  /**
+   * Sets how many times to keep retrying a host in the connect function.
+   */
+  void setNumRetries(int numRetries);
 
-   /**
-    * Sets how many times to keep retrying a host in the connect function.
-    */
-   void setNumRetries(int numRetries);
+  /**
+   * Sets how long to wait until retrying a host if it was marked down
+   */
+  void setRetryInterval(int retryInterval);
 
-   /**
-    * Sets how long to wait until retrying a host if it was marked down
-    */
-   void setRetryInterval(int retryInterval);
+  /**
+   * Sets how many times to keep retrying a host before marking it as down.
+   */
+  void setMaxConsecutiveFailures(int maxConsecutiveFailures);
 
-   /**
-    * Sets how many times to keep retrying a host before marking it as down.
-    */
-   void setMaxConsecutiveFailures(int maxConsecutiveFailures);
+  /**
+   * Turns randomization in connect order on or off.
+   */
+  void setRandomize(bool randomize);
 
-   /**
-    * Turns randomization in connect order on or off.
-    */
-   void setRandomize(bool randomize);
+  /**
+   * Whether to always try the last server.
+   */
+  void setAlwaysTryLast(bool alwaysTryLast);
 
-   /**
-    * Whether to always try the last server.
-    */
-   void setAlwaysTryLast(bool alwaysTryLast);
+  /**
+   * Creates and opens the UNIX socket.
+   */
+  void open();
 
-   /**
-    * Creates and opens the UNIX socket.
-    */
-   void open();
+  /*
+   * Closes the UNIX socket
+   */
+  void close();
 
-   /*
-    * Closes the UNIX socket
-    */
-   void close();
+protected:
+  void setCurrentServer(const std::shared_ptr<TSocketPoolServer>& server);
 
- protected:
-
-  void setCurrentServer(const boost::shared_ptr<TSocketPoolServer> &server);
-
-   /** List of servers to connect to */
-  std::vector< boost::shared_ptr<TSocketPoolServer> > servers_;
+  /** List of servers to connect to */
+  std::vector<std::shared_ptr<TSocketPoolServer> > servers_;
 
   /** Current server */
-  boost::shared_ptr<TSocketPoolServer> currentServer_;
+  std::shared_ptr<TSocketPoolServer> currentServer_;
 
-   /** How many times to retry each host in connect */
-   int numRetries_;
+  /** How many times to retry each host in connect */
+  int numRetries_;
 
-   /** Retry interval in seconds, how long to not try a host if it has been
-    * marked as down.
-    */
-   time_t retryInterval_;
+  /** Retry interval in seconds, how long to not try a host if it has been
+   * marked as down.
+   */
+  time_t retryInterval_;
 
-   /** Max consecutive failures before marking a host down. */
-   int maxConsecutiveFailures_;
+  /** Max consecutive failures before marking a host down. */
+  int maxConsecutiveFailures_;
 
-   /** Try hosts in order? or Randomized? */
-   bool randomize_;
+  /** Try hosts in order? or Randomized? */
+  bool randomize_;
 
-   /** Always try last host, even if marked down? */
-   bool alwaysTryLast_;
+  /** Always try last host, even if marked down? */
+  bool alwaysTryLast_;
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_TSOCKETPOOL_H_
-
diff --git a/lib/cpp/src/thrift/transport/TTransport.h b/lib/cpp/src/thrift/transport/TTransport.h
index 3b552c4..d844239 100644
--- a/lib/cpp/src/thrift/transport/TTransport.h
+++ b/lib/cpp/src/thrift/transport/TTransport.h
@@ -21,25 +21,26 @@
 #define _THRIFT_TRANSPORT_TTRANSPORT_H_ 1
 
 #include <thrift/Thrift.h>
-#include <boost/shared_ptr.hpp>
 #include <thrift/transport/TTransportException.h>
+#include <memory>
 #include <string>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * Helper template to hoist readAll implementation out of TTransport
  */
 template <class Transport_>
-uint32_t readAll(Transport_ &trans, uint8_t* buf, uint32_t len) {
+uint32_t readAll(Transport_& trans, uint8_t* buf, uint32_t len) {
   uint32_t have = 0;
   uint32_t get = 0;
 
   while (have < len) {
-    get = trans.read(buf+have, len-have);
+    get = trans.read(buf + have, len - have);
     if (get <= 0) {
-      throw TTransportException(TTransportException::END_OF_FILE,
-                                "No more data to read.");
+      throw TTransportException(TTransportException::END_OF_FILE, "No more data to read.");
     }
     have += get;
   }
@@ -47,14 +48,13 @@
   return have;
 }
 
-
 /**
  * Generic interface for a method of transporting data. A TTransport may be
  * capable of either reading or writing, but not necessarily both.
  *
  */
 class TTransport {
- public:
+public:
   /**
    * Virtual deconstructor.
    */
@@ -63,9 +63,7 @@
   /**
    * Whether this transport is open.
    */
-  virtual bool isOpen() {
-    return false;
-  }
+  virtual bool isOpen() { return false; }
 
   /**
    * Tests whether there is more data to read or if the remote side is
@@ -75,9 +73,7 @@
    * This is used by a server to check if it should listen for another
    * request.
    */
-  virtual bool peek() {
-    return isOpen();
-  }
+  virtual bool peek() { return isOpen(); }
 
   /**
    * Opens the transport for communications.
@@ -109,8 +105,7 @@
     return read_virt(buf, len);
   }
   virtual uint32_t read_virt(uint8_t* /* buf */, uint32_t /* len */) {
-    throw TTransportException(TTransportException::NOT_OPEN,
-                              "Base TTransport cannot read.");
+    throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot read.");
   }
 
   /**
@@ -158,8 +153,7 @@
     write_virt(buf, len);
   }
   virtual void write_virt(const uint8_t* /* buf */, uint32_t /* len */) {
-    throw TTransportException(TTransportException::NOT_OPEN,
-                              "Base TTransport cannot write.");
+    throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot write.");
   }
 
   /**
@@ -215,9 +209,7 @@
     T_VIRTUAL_CALL();
     return borrow_virt(buf, len);
   }
-  virtual const uint8_t* borrow_virt(uint8_t* /* buf */, uint32_t* /* len */) {
-    return NULL;
-  }
+  virtual const uint8_t* borrow_virt(uint8_t* /* buf */, uint32_t* /* len */) { return NULL; }
 
   /**
    * Remove len bytes from the transport.  This should always follow a borrow
@@ -233,11 +225,20 @@
     consume_virt(len);
   }
   virtual void consume_virt(uint32_t /* len */) {
-    throw TTransportException(TTransportException::NOT_OPEN,
-                              "Base TTransport cannot consume.");
+    throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot consume.");
   }
 
- protected:
+  /**
+   * Returns the origin of the transports call. The value depends on the
+   * transport used. An IP based transport for example will return the
+   * IP address of the client making the request.
+   * If the transport doesn't know the origin Unknown is returned.
+   *
+   * The returned value can be used in a log message for example
+   */
+  virtual const std::string getOrigin() { return "Unknown"; }
+
+protected:
   /**
    * Simple constructor.
    */
@@ -251,7 +252,7 @@
  *
  */
 class TTransportFactory {
- public:
+public:
   TTransportFactory() {}
 
   virtual ~TTransportFactory() {}
@@ -259,12 +260,12 @@
   /**
    * Default implementation does nothing, just returns the transport given.
    */
-  virtual boost::shared_ptr<TTransport> getTransport(boost::shared_ptr<TTransport> trans) {
+  virtual std::shared_ptr<TTransport> getTransport(std::shared_ptr<TTransport> trans) {
     return trans;
   }
-
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_TTRANSPORT_H_
diff --git a/lib/cpp/src/thrift/transport/TTransportException.cpp b/lib/cpp/src/thrift/transport/TTransportException.cpp
index 2c1f303..a527317 100644
--- a/lib/cpp/src/thrift/transport/TTransportException.cpp
+++ b/lib/cpp/src/thrift/transport/TTransportException.cpp
@@ -18,14 +18,42 @@
  */
 
 #include <thrift/transport/TTransportException.h>
-#include <boost/lexical_cast.hpp>
 #include <cstring>
 
 #include <thrift/thrift-config.h>
 
 using std::string;
-using boost::lexical_cast;
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
-}}} // apache::thrift::transport
+const char* TTransportException::what() const noexcept {
+  if (message_.empty()) {
+    switch (type_) {
+    case UNKNOWN:
+      return "TTransportException: Unknown transport exception";
+    case NOT_OPEN:
+      return "TTransportException: Transport not open";
+    case TIMED_OUT:
+      return "TTransportException: Timed out";
+    case END_OF_FILE:
+      return "TTransportException: End of file";
+    case INTERRUPTED:
+      return "TTransportException: Interrupted";
+    case BAD_ARGS:
+      return "TTransportException: Invalid arguments";
+    case CORRUPTED_DATA:
+      return "TTransportException: Corrupted Data";
+    case INTERNAL_ERROR:
+      return "TTransportException: Internal error";
+    default:
+      return "TTransportException: (Invalid exception type)";
+    }
+  } else {
+    return message_.c_str();
+  }
+}
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/TTransportException.h b/lib/cpp/src/thrift/transport/TTransportException.h
index 028dbb8..fb5f00c 100644
--- a/lib/cpp/src/thrift/transport/TTransportException.h
+++ b/lib/cpp/src/thrift/transport/TTransportException.h
@@ -20,10 +20,13 @@
 #ifndef _THRIFT_TRANSPORT_TTRANSPORTEXCEPTION_H_
 #define _THRIFT_TRANSPORT_TTRANSPORTEXCEPTION_H_ 1
 
+#include <boost/numeric/conversion/cast.hpp>
 #include <string>
 #include <thrift/Thrift.h>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * Class to encapsulate all the possible types of transport errors that may
@@ -34,44 +37,35 @@
  *
  */
 class TTransportException : public apache::thrift::TException {
- public:
+public:
   /**
    * Error codes for the various types of exceptions.
    */
-  enum TTransportExceptionType
-  { UNKNOWN = 0
-  , NOT_OPEN = 1
-  , TIMED_OUT = 2
-  , END_OF_FILE = 3
-  , INTERRUPTED = 4
-  , BAD_ARGS = 5
-  , CORRUPTED_DATA = 6
-  , INTERNAL_ERROR = 7
+  enum TTransportExceptionType {
+    UNKNOWN = 0,
+    NOT_OPEN = 1,
+    TIMED_OUT = 2,
+    END_OF_FILE = 3,
+    INTERRUPTED = 4,
+    BAD_ARGS = 5,
+    CORRUPTED_DATA = 6,
+    INTERNAL_ERROR = 7
   };
 
-  TTransportException() :
-    apache::thrift::TException(),
-    type_(UNKNOWN) {}
+  TTransportException() : apache::thrift::TException(), type_(UNKNOWN) {}
 
-  TTransportException(TTransportExceptionType type) :
-    apache::thrift::TException(),
-    type_(type) {}
+  TTransportException(TTransportExceptionType type) : apache::thrift::TException(), type_(type) {}
 
-  TTransportException(const std::string& message) :
-    apache::thrift::TException(message),
-    type_(UNKNOWN) {}
+  TTransportException(const std::string& message)
+    : apache::thrift::TException(message), type_(UNKNOWN) {}
 
-  TTransportException(TTransportExceptionType type, const std::string& message) :
-    apache::thrift::TException(message),
-    type_(type) {}
+  TTransportException(TTransportExceptionType type, const std::string& message)
+    : apache::thrift::TException(message), type_(type) {}
 
-  TTransportException(TTransportExceptionType type,
-                      const std::string& message,
-                      int errno_copy) :
-    apache::thrift::TException(message + ": " + TOutput::strerror_s(errno_copy)),
-    type_(type) {}
+  TTransportException(TTransportExceptionType type, const std::string& message, int errno_copy)
+    : apache::thrift::TException(message + ": " + TOutput::strerror_s(errno_copy)), type_(type) {}
 
-  virtual ~TTransportException() throw() {}
+  virtual ~TTransportException() noexcept {}
 
   /**
    * Returns an error code that provides information about the type of error
@@ -79,37 +73,34 @@
    *
    * @return Error code
    */
-  TTransportExceptionType getType() const throw() {
-    return type_;
-  }
+  TTransportExceptionType getType() const noexcept { return type_; }
 
-  virtual const char* what() const throw() {
-    if (message_.empty()) {
-      switch (type_) {
-        case UNKNOWN        : return "TTransportException: Unknown transport exception";
-        case NOT_OPEN       : return "TTransportException: Transport not open";
-        case TIMED_OUT      : return "TTransportException: Timed out";
-        case END_OF_FILE    : return "TTransportException: End of file";
-        case INTERRUPTED    : return "TTransportException: Interrupted";
-        case BAD_ARGS       : return "TTransportException: Invalid arguments";
-        case CORRUPTED_DATA : return "TTransportException: Corrupted Data";
-        case INTERNAL_ERROR : return "TTransportException: Internal error";
-        default             : return "TTransportException: (Invalid exception type)";
-      }
-    } else {
-      return message_.c_str();
-    }
-  }
+  virtual const char* what() const noexcept;
 
- protected:
+protected:
   /** Just like strerror_r but returns a C++ string object. */
   std::string strerror_s(int errno_copy);
 
   /** Error code */
   TTransportExceptionType type_;
-
 };
 
-}}} // apache::thrift::transport
+/**
+ * Legacy code in transport implementations have overflow issues
+ * that need to be enforced.
+ */
+template <typename To, typename From> To safe_numeric_cast(From i) {
+  try {
+    return boost::numeric_cast<To>(i);
+  }
+  catch (const std::bad_cast& bc) {
+    throw TTransportException(TTransportException::CORRUPTED_DATA,
+                              bc.what());
+  }
+}
+
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_TTRANSPORTEXCEPTION_H_
diff --git a/lib/cpp/src/thrift/transport/TTransportUtils.cpp b/lib/cpp/src/thrift/transport/TTransportUtils.cpp
index 44f6101..6f47c79 100644
--- a/lib/cpp/src/thrift/transport/TTransportUtils.cpp
+++ b/lib/cpp/src/thrift/transport/TTransportUtils.cpp
@@ -21,39 +21,44 @@
 
 using std::string;
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 uint32_t TPipedTransport::read(uint8_t* buf, uint32_t len) {
   uint32_t need = len;
 
   // We don't have enough data yet
-  if (rLen_-rPos_ < need) {
+  if (rLen_ - rPos_ < need) {
     // Copy out whatever we have
-    if (rLen_-rPos_ > 0) {
-      memcpy(buf, rBuf_+rPos_, rLen_-rPos_);
-      need -= rLen_-rPos_;
-      buf += rLen_-rPos_;
+    if (rLen_ - rPos_ > 0) {
+      memcpy(buf, rBuf_ + rPos_, rLen_ - rPos_);
+      need -= rLen_ - rPos_;
+      buf += rLen_ - rPos_;
       rPos_ = rLen_;
     }
 
     // Double the size of the underlying buffer if it is full
     if (rLen_ == rBufSize_) {
-      rBufSize_ *=2;
-      rBuf_ = (uint8_t *)std::realloc(rBuf_, sizeof(uint8_t) * rBufSize_);
+      rBufSize_ *= 2;
+      uint8_t *tmpBuf = (uint8_t*)std::realloc(rBuf_, sizeof(uint8_t) * rBufSize_);
+      if (tmpBuf == NULL) {
+       throw std::bad_alloc();
+      }
+      rBuf_ = tmpBuf;
     }
 
     // try to fill up the buffer
-    rLen_ += srcTrans_->read(rBuf_+rPos_, rBufSize_ - rPos_);
+    rLen_ += srcTrans_->read(rBuf_ + rPos_, rBufSize_ - rPos_);
   }
 
-
   // Hand over whatever we have
   uint32_t give = need;
-  if (rLen_-rPos_ < give) {
-    give = rLen_-rPos_;
+  if (rLen_ - rPos_ < give) {
+    give = rLen_ - rPos_;
   }
   if (give > 0) {
-    memcpy(buf, rBuf_+rPos_, give);
+    memcpy(buf, rBuf_ + rPos_, give);
     rPos_ += give;
     need -= give;
   }
@@ -68,11 +73,16 @@
 
   // Make the buffer as big as it needs to be
   if ((len + wLen_) >= wBufSize_) {
-    uint32_t newBufSize = wBufSize_*2;
+    uint32_t newBufSize = wBufSize_ * 2;
     while ((len + wLen_) >= newBufSize) {
       newBufSize *= 2;
     }
-    wBuf_ = (uint8_t *)std::realloc(wBuf_, sizeof(uint8_t) * newBufSize);
+    uint8_t *tmpBuf= (uint8_t*)std::realloc(wBuf_, sizeof(uint8_t) * newBufSize);
+    if (tmpBuf == NULL) {
+      throw std::bad_alloc();
+    }
+    wBuf_ = tmpBuf;
+
     wBufSize_ = newBufSize;
   }
 
@@ -81,7 +91,7 @@
   wLen_ += len;
 }
 
-void TPipedTransport::flush()  {
+void TPipedTransport::flush() {
   // Write out any data waiting in the write buffer
   if (wLen_ > 0) {
     srcTrans_->write(wBuf_, wLen_);
@@ -92,9 +102,10 @@
   srcTrans_->flush();
 }
 
-TPipedFileReaderTransport::TPipedFileReaderTransport(boost::shared_ptr<TFileReaderTransport> srcTrans, boost::shared_ptr<TTransport> dstTrans)
-  : TPipedTransport(srcTrans, dstTrans),
-    srcTrans_(srcTrans) {
+TPipedFileReaderTransport::TPipedFileReaderTransport(
+    std::shared_ptr<TFileReaderTransport> srcTrans,
+    std::shared_ptr<TTransport> dstTrans)
+  : TPipedTransport(srcTrans, dstTrans), srcTrans_(srcTrans) {
 }
 
 TPipedFileReaderTransport::~TPipedFileReaderTransport() {
@@ -125,7 +136,7 @@
   uint32_t get = 0;
 
   while (have < len) {
-    get = read(buf+have, len-have);
+    get = read(buf + have, len - have);
     if (get <= 0) {
       throw TEOFException();
     }
@@ -174,5 +185,6 @@
 void TPipedFileReaderTransport::seekToEnd() {
   srcTrans_->seekToEnd();
 }
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/TTransportUtils.h b/lib/cpp/src/thrift/transport/TTransportUtils.h
index aa294b4..4c82dd3 100644
--- a/lib/cpp/src/thrift/transport/TTransportUtils.h
+++ b/lib/cpp/src/thrift/transport/TTransportUtils.h
@@ -29,7 +29,9 @@
 #include <thrift/transport/TBufferTransports.h>
 #include <thrift/transport/TFileTransport.h>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * The null transport is a dummy transport that doesn't actually do anything.
@@ -39,24 +41,18 @@
  *
  */
 class TNullTransport : public TVirtualTransport<TNullTransport> {
- public:
+public:
   TNullTransport() {}
 
   ~TNullTransport() {}
 
-  bool isOpen() {
-    return true;
-  }
+  bool isOpen() { return true; }
 
   void open() {}
 
-  void write(const uint8_t* /* buf */, uint32_t /* len */) {
-    return;
-  }
-
+  void write(const uint8_t* /* buf */, uint32_t /* len */) { return; }
 };
 
-
 /**
  * TPipedTransport. This transport allows piping of a request from one
  * transport to another either when readEnd() or writeEnd(). The typical
@@ -66,41 +62,46 @@
  *
  */
 class TPipedTransport : virtual public TTransport {
- public:
-  TPipedTransport(boost::shared_ptr<TTransport> srcTrans,
-                  boost::shared_ptr<TTransport> dstTrans) :
-    srcTrans_(srcTrans),
-    dstTrans_(dstTrans),
-    rBufSize_(512), rPos_(0), rLen_(0),
-    wBufSize_(512), wLen_(0) {
+public:
+  TPipedTransport(std::shared_ptr<TTransport> srcTrans, std::shared_ptr<TTransport> dstTrans)
+    : srcTrans_(srcTrans),
+      dstTrans_(dstTrans),
+      rBufSize_(512),
+      rPos_(0),
+      rLen_(0),
+      wBufSize_(512),
+      wLen_(0) {
 
     // default is to to pipe the request when readEnd() is called
     pipeOnRead_ = true;
     pipeOnWrite_ = false;
 
-    rBuf_ = (uint8_t*) std::malloc(sizeof(uint8_t) * rBufSize_);
+    rBuf_ = (uint8_t*)std::malloc(sizeof(uint8_t) * rBufSize_);
     if (rBuf_ == NULL) {
       throw std::bad_alloc();
     }
-    wBuf_ = (uint8_t*) std::malloc(sizeof(uint8_t) * wBufSize_);
+    wBuf_ = (uint8_t*)std::malloc(sizeof(uint8_t) * wBufSize_);
     if (wBuf_ == NULL) {
       throw std::bad_alloc();
     }
   }
 
-  TPipedTransport(boost::shared_ptr<TTransport> srcTrans,
-                  boost::shared_ptr<TTransport> dstTrans,
-                  uint32_t sz) :
-    srcTrans_(srcTrans),
-    dstTrans_(dstTrans),
-    rBufSize_(512), rPos_(0), rLen_(0),
-    wBufSize_(sz), wLen_(0) {
+  TPipedTransport(std::shared_ptr<TTransport> srcTrans,
+                  std::shared_ptr<TTransport> dstTrans,
+                  uint32_t sz)
+    : srcTrans_(srcTrans),
+      dstTrans_(dstTrans),
+      rBufSize_(512),
+      rPos_(0),
+      rLen_(0),
+      wBufSize_(sz),
+      wLen_(0) {
 
-    rBuf_ = (uint8_t*) std::malloc(sizeof(uint8_t) * rBufSize_);
+    rBuf_ = (uint8_t*)std::malloc(sizeof(uint8_t) * rBufSize_);
     if (rBuf_ == NULL) {
       throw std::bad_alloc();
     }
-    wBuf_ = (uint8_t*) std::malloc(sizeof(uint8_t) * wBufSize_);
+    wBuf_ = (uint8_t*)std::malloc(sizeof(uint8_t) * wBufSize_);
     if (wBuf_ == NULL) {
       throw std::bad_alloc();
     }
@@ -111,40 +112,33 @@
     std::free(wBuf_);
   }
 
-  bool isOpen() {
-    return srcTrans_->isOpen();
-  }
+  bool isOpen() { return srcTrans_->isOpen(); }
 
   bool peek() {
     if (rPos_ >= rLen_) {
       // Double the size of the underlying buffer if it is full
       if (rLen_ == rBufSize_) {
-        rBufSize_ *=2;
-        rBuf_ = (uint8_t *)std::realloc(rBuf_, sizeof(uint8_t) * rBufSize_);
+        rBufSize_ *= 2;
+        uint8_t * tmpBuf = (uint8_t*)std::realloc(rBuf_, sizeof(uint8_t) * rBufSize_);
+	if (tmpBuf == NULL) {
+	  throw std::bad_alloc();
+	}
+	rBuf_ = tmpBuf;
       }
 
       // try to fill up the buffer
-      rLen_ += srcTrans_->read(rBuf_+rPos_, rBufSize_ - rPos_);
+      rLen_ += srcTrans_->read(rBuf_ + rPos_, rBufSize_ - rPos_);
     }
     return (rLen_ > rPos_);
   }
 
+  void open() { srcTrans_->open(); }
 
-  void open() {
-    srcTrans_->open();
-  }
+  void close() { srcTrans_->close(); }
 
-  void close() {
-    srcTrans_->close();
-  }
+  void setPipeOnRead(bool pipeVal) { pipeOnRead_ = pipeVal; }
 
-  void setPipeOnRead(bool pipeVal) {
-    pipeOnRead_ = pipeVal;
-  }
-
-  void setPipeOnWrite(bool pipeVal) {
-    pipeOnWrite_ = pipeVal;
-  }
+  void setPipeOnWrite(bool pipeVal) { pipeOnWrite_ = pipeVal; }
 
   uint32_t read(uint8_t* buf, uint32_t len);
 
@@ -180,25 +174,19 @@
 
   void flush();
 
-  boost::shared_ptr<TTransport> getTargetTransport() {
-    return dstTrans_;
-  }
+  std::shared_ptr<TTransport> getTargetTransport() { return dstTrans_; }
 
   /*
    * Override TTransport *_virt() functions to invoke our implementations.
    * We cannot use TVirtualTransport to provide these, since we need to inherit
    * virtually from TTransport.
    */
-  virtual uint32_t read_virt(uint8_t* buf, uint32_t len) {
-    return this->read(buf, len);
-  }
-  virtual void write_virt(const uint8_t* buf, uint32_t len) {
-    this->write(buf, len);
-  }
+  virtual uint32_t read_virt(uint8_t* buf, uint32_t len) { return this->read(buf, len); }
+  virtual void write_virt(const uint8_t* buf, uint32_t len) { this->write(buf, len); }
 
- protected:
-  boost::shared_ptr<TTransport> srcTrans_;
-  boost::shared_ptr<TTransport> dstTrans_;
+protected:
+  std::shared_ptr<TTransport> srcTrans_;
+  std::shared_ptr<TTransport> dstTrans_;
 
   uint8_t* rBuf_;
   uint32_t rBufSize_;
@@ -213,15 +201,14 @@
   bool pipeOnWrite_;
 };
 
-
 /**
  * Wraps a transport into a pipedTransport instance.
  *
  */
 class TPipedTransportFactory : public TTransportFactory {
- public:
+public:
   TPipedTransportFactory() {}
-  TPipedTransportFactory(boost::shared_ptr<TTransport> dstTrans) {
+  TPipedTransportFactory(std::shared_ptr<TTransport> dstTrans) {
     initializeTargetTransport(dstTrans);
   }
   virtual ~TPipedTransportFactory() {}
@@ -229,11 +216,11 @@
   /**
    * Wraps the base transport into a piped transport.
    */
-  virtual boost::shared_ptr<TTransport> getTransport(boost::shared_ptr<TTransport> srcTrans) {
-    return boost::shared_ptr<TTransport>(new TPipedTransport(srcTrans, dstTrans_));
+  virtual std::shared_ptr<TTransport> getTransport(std::shared_ptr<TTransport> srcTrans) {
+    return std::shared_ptr<TTransport>(new TPipedTransport(srcTrans, dstTrans_));
   }
 
-  virtual void initializeTargetTransport(boost::shared_ptr<TTransport> dstTrans) {
+  virtual void initializeTargetTransport(std::shared_ptr<TTransport> dstTrans) {
     if (dstTrans_.get() == NULL) {
       dstTrans_ = dstTrans;
     } else {
@@ -241,8 +228,8 @@
     }
   }
 
- protected:
-  boost::shared_ptr<TTransport> dstTrans_;
+protected:
+  std::shared_ptr<TTransport> dstTrans_;
 };
 
 /**
@@ -251,10 +238,10 @@
  * TTransport can still access the original transport.
  *
  */
-class TPipedFileReaderTransport : public TPipedTransport,
-                                  public TFileReaderTransport {
- public:
-  TPipedFileReaderTransport(boost::shared_ptr<TFileReaderTransport> srcTrans, boost::shared_ptr<TTransport> dstTrans);
+class TPipedFileReaderTransport : public TPipedTransport, public TFileReaderTransport {
+public:
+  TPipedFileReaderTransport(std::shared_ptr<TFileReaderTransport> srcTrans,
+                            std::shared_ptr<TTransport> dstTrans);
 
   ~TPipedFileReaderTransport();
 
@@ -283,20 +270,14 @@
    * We cannot use TVirtualTransport to provide these, since we need to inherit
    * virtually from TTransport.
    */
-  virtual uint32_t read_virt(uint8_t* buf, uint32_t len) {
-    return this->read(buf, len);
-  }
-  virtual uint32_t readAll_virt(uint8_t* buf, uint32_t len) {
-    return this->readAll(buf, len);
-  }
-  virtual void write_virt(const uint8_t* buf, uint32_t len) {
-    this->write(buf, len);
-  }
+  virtual uint32_t read_virt(uint8_t* buf, uint32_t len) { return this->read(buf, len); }
+  virtual uint32_t readAll_virt(uint8_t* buf, uint32_t len) { return this->readAll(buf, len); }
+  virtual void write_virt(const uint8_t* buf, uint32_t len) { this->write(buf, len); }
 
- protected:
+protected:
   // shouldn't be used
   TPipedFileReaderTransport();
-  boost::shared_ptr<TFileReaderTransport> srcTrans_;
+  std::shared_ptr<TFileReaderTransport> srcTrans_;
 };
 
 /**
@@ -304,27 +285,30 @@
  *
  */
 class TPipedFileReaderTransportFactory : public TPipedTransportFactory {
- public:
+public:
   TPipedFileReaderTransportFactory() {}
-  TPipedFileReaderTransportFactory(boost::shared_ptr<TTransport> dstTrans)
-    : TPipedTransportFactory(dstTrans)
-  {}
+  TPipedFileReaderTransportFactory(std::shared_ptr<TTransport> dstTrans)
+    : TPipedTransportFactory(dstTrans) {}
   virtual ~TPipedFileReaderTransportFactory() {}
 
-  boost::shared_ptr<TTransport> getTransport(boost::shared_ptr<TTransport> srcTrans) {
-    boost::shared_ptr<TFileReaderTransport> pFileReaderTransport = boost::dynamic_pointer_cast<TFileReaderTransport>(srcTrans);
+  std::shared_ptr<TTransport> getTransport(std::shared_ptr<TTransport> srcTrans) {
+    std::shared_ptr<TFileReaderTransport> pFileReaderTransport
+        = std::dynamic_pointer_cast<TFileReaderTransport>(srcTrans);
     if (pFileReaderTransport.get() != NULL) {
       return getFileReaderTransport(pFileReaderTransport);
     } else {
-      return boost::shared_ptr<TTransport>();
+      return std::shared_ptr<TTransport>();
     }
   }
 
-  boost::shared_ptr<TFileReaderTransport> getFileReaderTransport(boost::shared_ptr<TFileReaderTransport> srcTrans) {
-    return boost::shared_ptr<TFileReaderTransport>(new TPipedFileReaderTransport(srcTrans, dstTrans_));
+  std::shared_ptr<TFileReaderTransport> getFileReaderTransport(
+      std::shared_ptr<TFileReaderTransport> srcTrans) {
+    return std::shared_ptr<TFileReaderTransport>(
+        new TPipedFileReaderTransport(srcTrans, dstTrans_));
   }
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_TTRANSPORTUTILS_H_
diff --git a/lib/cpp/src/thrift/transport/TVirtualTransport.h b/lib/cpp/src/thrift/transport/TVirtualTransport.h
index 575f547..0cacf61 100644
--- a/lib/cpp/src/thrift/transport/TVirtualTransport.h
+++ b/lib/cpp/src/thrift/transport/TVirtualTransport.h
@@ -22,8 +22,9 @@
 
 #include <thrift/transport/TTransport.h>
 
-namespace apache { namespace thrift { namespace transport {
-
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * Helper class that provides default implementations of TTransport methods.
@@ -42,28 +43,20 @@
  * read_virt().)
  */
 class TTransportDefaults : public TTransport {
- public:
+public:
   /*
    * TTransport *_virt() methods provide reasonable default implementations.
    * Invoke them non-virtually.
    */
-  uint32_t read(uint8_t* buf, uint32_t len) {
-    return this->TTransport::read_virt(buf, len);
-  }
-  uint32_t readAll(uint8_t* buf, uint32_t len) {
-    return this->TTransport::readAll_virt(buf, len);
-  }
-  void write(const uint8_t* buf, uint32_t len) {
-    this->TTransport::write_virt(buf, len);
-  }
+  uint32_t read(uint8_t* buf, uint32_t len) { return this->TTransport::read_virt(buf, len); }
+  uint32_t readAll(uint8_t* buf, uint32_t len) { return this->TTransport::readAll_virt(buf, len); }
+  void write(const uint8_t* buf, uint32_t len) { this->TTransport::write_virt(buf, len); }
   const uint8_t* borrow(uint8_t* buf, uint32_t* len) {
     return this->TTransport::borrow_virt(buf, len);
   }
-  void consume(uint32_t len) {
-    this->TTransport::consume_virt(len);
-  }
+  void consume(uint32_t len) { this->TTransport::consume_virt(len); }
 
- protected:
+protected:
   TTransportDefaults() {}
 };
 
@@ -84,9 +77,9 @@
  *
  * @author Chad Walters <chad@powerset.com>
  */
-template <class Transport_, class Super_=TTransportDefaults>
+template <class Transport_, class Super_ = TTransportDefaults>
 class TVirtualTransport : public Super_ {
- public:
+public:
   /*
    * Implementations of the *_virt() functions, to call the subclass's
    * non-virtual implementation function.
@@ -107,9 +100,7 @@
     return static_cast<Transport_*>(this)->borrow(buf, len);
   }
 
-  virtual void consume_virt(uint32_t len) {
-    static_cast<Transport_*>(this)->consume(len);
-  }
+  virtual void consume_virt(uint32_t len) { static_cast<Transport_*>(this)->consume(len); }
 
   /*
    * Provide a default readAll() implementation that invokes
@@ -126,7 +117,7 @@
     return ::apache::thrift::transport::readAll(*trans, buf, len);
   }
 
- protected:
+protected:
   TVirtualTransport() {}
 
   /*
@@ -135,12 +126,15 @@
    * additional versions can be added as needed.
    */
   template <typename Arg_>
-  TVirtualTransport(Arg_ const& arg) : Super_(arg) { }
+  TVirtualTransport(Arg_ const& arg)
+    : Super_(arg) {}
 
   template <typename Arg1_, typename Arg2_>
-  TVirtualTransport(Arg1_ const& a1, Arg2_ const& a2) : Super_(a1, a2) { }
+  TVirtualTransport(Arg1_ const& a1, Arg2_ const& a2)
+    : Super_(a1, a2) {}
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_TVIRTUALTRANSPORT_H_
diff --git a/lib/cpp/src/thrift/transport/TZlibTransport.cpp b/lib/cpp/src/thrift/transport/TZlibTransport.cpp
index d77eedd..e426dc3 100644
--- a/lib/cpp/src/thrift/transport/TZlibTransport.cpp
+++ b/lib/cpp/src/thrift/transport/TZlibTransport.cpp
@@ -24,7 +24,9 @@
 
 using std::string;
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 // Don't call this outside of the constructor.
 void TZlibTransport::initZlib() {
@@ -36,17 +38,17 @@
 
     rstream_->zalloc = Z_NULL;
     wstream_->zalloc = Z_NULL;
-    rstream_->zfree  = Z_NULL;
-    wstream_->zfree  = Z_NULL;
+    rstream_->zfree = Z_NULL;
+    wstream_->zfree = Z_NULL;
     rstream_->opaque = Z_NULL;
     wstream_->opaque = Z_NULL;
 
-    rstream_->next_in   = crbuf_;
-    wstream_->next_in   = uwbuf_;
-    rstream_->next_out  = urbuf_;
-    wstream_->next_out  = cwbuf_;
-    rstream_->avail_in  = 0;
-    wstream_->avail_in  = 0;
+    rstream_->next_in = crbuf_;
+    wstream_->next_in = uwbuf_;
+    rstream_->next_out = urbuf_;
+    wstream_->next_out = cwbuf_;
+    rstream_->avail_in = 0;
+    wstream_->avail_in = 0;
     rstream_->avail_out = urbuf_size_;
     wstream_->avail_out = cwbuf_size_;
 
@@ -79,8 +81,8 @@
 
 inline void TZlibTransport::checkZlibRvNothrow(int status, const char* message) {
   if (status != Z_OK) {
-    string output = "TZlibTransport: zlib failure in destructor: " +
-      TZlibTransportException::errorMessage(status, message);
+    string output = "TZlibTransport: zlib failure in destructor: "
+                    + TZlibTransportException::errorMessage(status, message);
     GlobalOutput(output.c_str());
   }
 }
@@ -116,8 +118,6 @@
   return (readAvail() > 0) || (rstream_->avail_in > 0) || transport_->peek();
 }
 
-
-
 // READING STRATEGY
 //
 // We have two buffers for reading: one containing the compressed data (crbuf_)
@@ -143,7 +143,7 @@
   while (true) {
     // Copy out whatever we have available, then give them the min of
     // what we have and what they want, then advance indices.
-    int give = std::min((uint32_t) readAvail(), need);
+    int give = (std::min)((uint32_t)readAvail(), need);
     memcpy(buf, urbuf_ + urpos_, give);
     need -= give;
     buf += give;
@@ -170,7 +170,7 @@
     }
 
     // The uncompressed read buffer is empty, so reset the stream fields.
-    rstream_->next_out  = urbuf_;
+    rstream_->next_out = urbuf_;
     rstream_->avail_out = urbuf_size_;
     urpos_ = 0;
 
@@ -195,7 +195,7 @@
     if (got == 0) {
       return false;
     }
-    rstream_->next_in  = crbuf_;
+    rstream_->next_in = crbuf_;
     rstream_->avail_in = got;
   }
 
@@ -211,7 +211,6 @@
   return true;
 }
 
-
 // WRITING STRATEGY
 //
 // We buffer up small writes before sending them to zlib, so our logic is:
@@ -232,8 +231,7 @@
 
 void TZlibTransport::write(const uint8_t* buf, uint32_t len) {
   if (output_finished_) {
-    throw TTransportException(TTransportException::BAD_ARGS,
-                              "write() called after finish()");
+    throw TTransportException(TTransportException::BAD_ARGS, "write() called after finish()");
   }
 
   // zlib's "deflate" function has enough logic in it that I think
@@ -252,25 +250,32 @@
   }
 }
 
-void TZlibTransport::flush()  {
+void TZlibTransport::flush() {
   if (output_finished_) {
-    throw TTransportException(TTransportException::BAD_ARGS,
-                              "flush() called after finish()");
+    throw TTransportException(TTransportException::BAD_ARGS, "flush() called after finish()");
+  }
+
+  flushToZlib(uwbuf_, uwpos_, Z_BLOCK);
+  uwpos_ = 0;
+
+  if(wstream_->avail_out < 6){
+    transport_->write(cwbuf_, cwbuf_size_ - wstream_->avail_out);
+    wstream_->next_out = cwbuf_;
+    wstream_->avail_out = cwbuf_size_;
   }
 
   flushToTransport(Z_FULL_FLUSH);
 }
 
-void TZlibTransport::finish()  {
+void TZlibTransport::finish() {
   if (output_finished_) {
-    throw TTransportException(TTransportException::BAD_ARGS,
-                              "finish() called more than once");
+    throw TTransportException(TTransportException::BAD_ARGS, "finish() called more than once");
   }
 
   flushToTransport(Z_FINISH);
 }
 
-void TZlibTransport::flushToTransport(int flush)  {
+void TZlibTransport::flushToTransport(int flush) {
   // write pending data in uwbuf_ to zlib
   flushToZlib(uwbuf_, uwpos_, flush);
   uwpos_ = 0;
@@ -285,18 +290,18 @@
 }
 
 void TZlibTransport::flushToZlib(const uint8_t* buf, int len, int flush) {
-  wstream_->next_in  = const_cast<uint8_t*>(buf);
+  wstream_->next_in = const_cast<uint8_t*>(buf);
   wstream_->avail_in = len;
 
   while (true) {
-    if (flush == Z_NO_FLUSH && wstream_->avail_in == 0) {
+    if ((flush == Z_NO_FLUSH || flush == Z_BLOCK) && wstream_->avail_in == 0) {
       break;
     }
 
     // If our ouput buffer is full, flush to the underlying transport.
     if (wstream_->avail_out == 0) {
       transport_->write(cwbuf_, cwbuf_size_);
-      wstream_->next_out  = cwbuf_;
+      wstream_->next_out = cwbuf_;
       wstream_->avail_out = cwbuf_size_;
     }
 
@@ -310,15 +315,15 @@
 
     checkZlibRv(zlib_rv, wstream_->msg);
 
-    if ((flush == Z_SYNC_FLUSH || flush == Z_FULL_FLUSH) &&
-        wstream_->avail_in == 0 && wstream_->avail_out != 0) {
+    if ((flush == Z_SYNC_FLUSH || flush == Z_FULL_FLUSH) && wstream_->avail_in == 0
+        && wstream_->avail_out != 0) {
       break;
     }
   }
 }
 
 const uint8_t* TZlibTransport::borrow(uint8_t* buf, uint32_t* len) {
-  (void) buf;
+  (void)buf;
   // Don't try to be clever with shifting buffers.
   // If we have enough data, give a pointer to it,
   // otherwise let the protcol use its slow path.
@@ -333,8 +338,7 @@
   if (readAvail() >= (int)len) {
     urpos_ += len;
   } else {
-    throw TTransportException(TTransportException::BAD_ARGS,
-                              "consume did not follow a borrow.");
+    throw TTransportException(TTransportException::BAD_ARGS, "consume did not follow a borrow.");
   }
 }
 
@@ -348,14 +352,13 @@
   // This should only be called when reading is complete.
   // If the caller still has unread data, throw an exception.
   if (readAvail() > 0) {
-    throw TTransportException(
-        TTransportException::CORRUPTED_DATA,
-        "verifyChecksum() called before end of zlib stream");
+    throw TTransportException(TTransportException::CORRUPTED_DATA,
+                              "verifyChecksum() called before end of zlib stream");
   }
 
   // Reset the rstream fields, in case avail_out is 0.
   // (Since readAvail() is 0, we know there is no unread data in urbuf_)
-  rstream_->next_out  = urbuf_;
+  rstream_->next_out = urbuf_;
   rstream_->avail_out = urbuf_size_;
   urpos_ = 0;
 
@@ -394,6 +397,6 @@
                             "verifyChecksum() called before end of "
                             "zlib stream");
 }
-
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/transport/TZlibTransport.h b/lib/cpp/src/thrift/transport/TZlibTransport.h
index dd9dd14..b45ec43 100644
--- a/lib/cpp/src/thrift/transport/TZlibTransport.h
+++ b/lib/cpp/src/thrift/transport/TZlibTransport.h
@@ -20,24 +20,25 @@
 #ifndef _THRIFT_TRANSPORT_TZLIBTRANSPORT_H_
 #define _THRIFT_TRANSPORT_TZLIBTRANSPORT_H_ 1
 
-#include <boost/lexical_cast.hpp>
 #include <thrift/transport/TTransport.h>
 #include <thrift/transport/TVirtualTransport.h>
+#include <thrift/TToString.h>
 #include <zlib.h>
 
 struct z_stream_s;
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 class TZlibTransportException : public TTransportException {
- public:
-  TZlibTransportException(int status, const char* msg) :
-    TTransportException(TTransportException::INTERNAL_ERROR,
-                        errorMessage(status, msg)),
-    zlib_status_(status),
-    zlib_msg_(msg == NULL ? "(null)" : msg) {}
+public:
+  TZlibTransportException(int status, const char* msg)
+    : TTransportException(TTransportException::INTERNAL_ERROR, errorMessage(status, msg)),
+      zlib_status_(status),
+      zlib_msg_(msg == NULL ? "(null)" : msg) {}
 
-  virtual ~TZlibTransportException() throw() {}
+  virtual ~TZlibTransportException() noexcept {}
 
   int getZlibStatus() { return zlib_status_; }
   std::string getZlibMessage() { return zlib_msg_; }
@@ -50,7 +51,7 @@
       rv += "(no message)";
     }
     rv += " (status = ";
-    rv += boost::lexical_cast<std::string>(status);
+    rv += to_string(status);
     rv += ")";
     return rv;
   }
@@ -60,15 +61,14 @@
 };
 
 /**
- * This transport uses zlib to compress on write and decompress on read 
+ * This transport uses zlib to compress on write and decompress on read
  *
  * TODO(dreiss): Don't do an extra copy of the compressed data if
  *               the underlying transport is TBuffered or TMemory.
  *
  */
 class TZlibTransport : public TVirtualTransport<TZlibTransport> {
- public:
- 
+public:
   /**
    * @param transport    The transport to read compressed data from
    *                     and write compressed data to.
@@ -78,36 +78,34 @@
    * @param cwbuf_size   Compressed buffer size for writing.
    * @param comp_level   Compression level (0=none[fast], 6=default, 9=max[slow]).
    */
-  TZlibTransport(boost::shared_ptr<TTransport> transport,
+  TZlibTransport(std::shared_ptr<TTransport> transport,
                  int urbuf_size = DEFAULT_URBUF_SIZE,
                  int crbuf_size = DEFAULT_CRBUF_SIZE,
                  int uwbuf_size = DEFAULT_UWBUF_SIZE,
                  int cwbuf_size = DEFAULT_CWBUF_SIZE,
-                 int16_t comp_level = Z_DEFAULT_COMPRESSION) :
-    transport_(transport),
-    urpos_(0),
-    uwpos_(0),
-    input_ended_(false),
-    output_finished_(false),
-    urbuf_size_(urbuf_size),
-    crbuf_size_(crbuf_size),
-    uwbuf_size_(uwbuf_size),
-    cwbuf_size_(cwbuf_size),
-    urbuf_(NULL),
-    crbuf_(NULL),
-    uwbuf_(NULL),
-    cwbuf_(NULL),
-    rstream_(NULL),
-    wstream_(NULL),
-    comp_level_(comp_level)
-  {
+                 int16_t comp_level = Z_DEFAULT_COMPRESSION)
+    : transport_(transport),
+      urpos_(0),
+      uwpos_(0),
+      input_ended_(false),
+      output_finished_(false),
+      urbuf_size_(urbuf_size),
+      crbuf_size_(crbuf_size),
+      uwbuf_size_(uwbuf_size),
+      cwbuf_size_(cwbuf_size),
+      urbuf_(NULL),
+      crbuf_(NULL),
+      uwbuf_(NULL),
+      cwbuf_(NULL),
+      rstream_(NULL),
+      wstream_(NULL),
+      comp_level_(comp_level) {
     if (uwbuf_size_ < MIN_DIRECT_DEFLATE_SIZE) {
       // Have to copy this into a local because of a linking issue.
       int minimum = MIN_DIRECT_DEFLATE_SIZE;
-      throw TTransportException(
-          TTransportException::BAD_ARGS,
-          "TZLibTransport: uncompressed write buffer must be at least"
-          + boost::lexical_cast<std::string>(minimum) + ".");
+      throw TTransportException(TTransportException::BAD_ARGS,
+                                "TZLibTransport: uncompressed write buffer must be at least"
+                                + to_string(minimum) + ".");
     }
 
     try {
@@ -143,13 +141,9 @@
   bool isOpen();
   bool peek();
 
-  void open() {
-    transport_->open();
-  }
+  void open() { transport_->open(); }
 
-  void close() {
-    transport_->close();
-  }
+  void close() { transport_->close(); }
 
   uint32_t read(uint8_t* buf, uint32_t len);
 
@@ -178,16 +172,17 @@
    */
   void verifyChecksum();
 
-   /**
-    * TODO(someone_smart): Choose smart defaults.
-    */
+  /**
+   * TODO(someone_smart): Choose smart defaults.
+   */
   static const int DEFAULT_URBUF_SIZE = 128;
   static const int DEFAULT_CRBUF_SIZE = 1024;
   static const int DEFAULT_UWBUF_SIZE = 128;
   static const int DEFAULT_CWBUF_SIZE = 1024;
 
- protected:
+  std::shared_ptr<TTransport> getUnderlyingTransport() const { return transport_; }
 
+protected:
   inline void checkZlibRv(int status, const char* msg);
   inline void checkZlibRvNothrow(int status, const char* msg);
   inline int readAvail();
@@ -195,12 +190,12 @@
   void flushToZlib(const uint8_t* buf, int len, int flush);
   bool readFromZlib();
 
- protected:
+protected:
   // Writes smaller than this are buffered up.
   // Larger (or equal) writes are dumped straight to zlib.
   static const uint32_t MIN_DIRECT_DEFLATE_SIZE = 32;
 
-  boost::shared_ptr<TTransport> transport_;
+  std::shared_ptr<TTransport> transport_;
 
   int urpos_;
   int uwpos_;
@@ -226,24 +221,22 @@
   const int comp_level_;
 };
 
-
 /**
  * Wraps a transport into a zlibbed one.
  *
  */
 class TZlibTransportFactory : public TTransportFactory {
- public:
+public:
   TZlibTransportFactory() {}
 
   virtual ~TZlibTransportFactory() {}
 
-  virtual boost::shared_ptr<TTransport> getTransport(
-                                         boost::shared_ptr<TTransport> trans) {
-    return boost::shared_ptr<TTransport>(new TZlibTransport(trans));
+  virtual std::shared_ptr<TTransport> getTransport(std::shared_ptr<TTransport> trans) {
+    return std::shared_ptr<TTransport>(new TZlibTransport(trans));
   }
 };
-
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // #ifndef _THRIFT_TRANSPORT_TZLIBTRANSPORT_H_
diff --git a/lib/cpp/src/thrift/windows/GetTimeOfDay.cpp b/lib/cpp/src/thrift/windows/GetTimeOfDay.cpp
index 1906302..820828f 100644
--- a/lib/cpp/src/thrift/windows/GetTimeOfDay.cpp
+++ b/lib/cpp/src/thrift/windows/GetTimeOfDay.cpp
@@ -21,92 +21,86 @@
 #include <thrift/thrift-config.h>
 
 // win32
-#include <time.h>
-
-#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
-#   define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
-#else
-#   define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL
+#if defined(__MINGW32__)
+  #include <sys/time.h>
 #endif
 
-struct timezone
-{
-    int  tz_minuteswest; /* minutes W of Greenwich */
-    int  tz_dsttime;     /* type of dst correction */
+#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
+#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
+#else
+#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
+#endif
+
+#if !defined(__MINGW32__)
+struct timezone {
+  int tz_minuteswest; /* minutes W of Greenwich */
+  int tz_dsttime;     /* type of dst correction */
 };
+#endif
 
-int thrift_gettimeofday(struct timeval * tv, struct timezone * tz)
-{
-    FILETIME         ft;
-    unsigned __int64 tmpres(0);
-    static int       tzflag;
-
-    if (NULL != tv)
-    {
-        GetSystemTimeAsFileTime(&ft);
-
-        tmpres |= ft.dwHighDateTime;
-        tmpres <<= 32;
-        tmpres |= ft.dwLowDateTime;
-
-        /*converting file time to unix epoch*/
-        tmpres -= DELTA_EPOCH_IN_MICROSECS;
-        tmpres /= 10;  /*convert into microseconds*/
-        tv->tv_sec = (long)(tmpres / 1000000UL);
-        tv->tv_usec = (long)(tmpres % 1000000UL);
-    }
-
-    if (NULL != tz)
-    {
-        if (!tzflag)
-        {
-            _tzset();
-            tzflag++;
-        }
-
-        long time_zone(0);
-        errno_t err(_get_timezone(&time_zone));
-        if (err == NO_ERROR)
-        {
-            tz->tz_minuteswest = time_zone / 60;
-        }
-        else
-        {
-            return -1;
-        }
-
-        int day_light(0);
-        err = (_get_daylight(&day_light));
-        if (err == NO_ERROR)
-        {
-            tz->tz_dsttime = day_light;
-            return 0;
-        }
-        else
-        {
-            return -1;
-        }
-    }
-
-    return -1;
+#if defined(__MINGW32__)
+int thrift_gettimeofday(struct timeval* tv, struct timezone* tz) {
+  return gettimeofday(tv,tz);
 }
+#else
+int thrift_gettimeofday(struct timeval* tv, struct timezone* tz) {
+  FILETIME ft;
+  unsigned __int64 tmpres(0);
+  static int tzflag;
 
-int thrift_sleep(unsigned int seconds)
-{
+  if (NULL != tv) {
+    GetSystemTimeAsFileTime(&ft);
+
+    tmpres |= ft.dwHighDateTime;
+    tmpres <<= 32;
+    tmpres |= ft.dwLowDateTime;
+
+    /*converting file time to unix epoch*/
+    tmpres -= DELTA_EPOCH_IN_MICROSECS;
+    tmpres /= 10; /*convert into microseconds*/
+    tv->tv_sec = (long)(tmpres / 1000000UL);
+    tv->tv_usec = (long)(tmpres % 1000000UL);
+  }
+
+  if (NULL != tz) {
+    if (!tzflag) {
+      _tzset();
+      tzflag++;
+    }
+
+    long time_zone(0);
+    errno_t err(_get_timezone(&time_zone));
+    if (err == NO_ERROR) {
+      tz->tz_minuteswest = time_zone / 60;
+    } else {
+      return -1;
+    }
+
+    int day_light(0);
+    err = (_get_daylight(&day_light));
+    if (err == NO_ERROR) {
+      tz->tz_dsttime = day_light;
+      return 0;
+    } else {
+      return -1;
+    }
+  }
+
+  return 0;
+}
+#endif
+
+int thrift_sleep(unsigned int seconds) {
   ::Sleep(seconds * 1000);
   return 0;
 }
-int thrift_usleep(unsigned int microseconds)
-{
-  unsigned int milliseconds = (microseconds + 999)/ 1000;
+int thrift_usleep(unsigned int microseconds) {
+  unsigned int milliseconds = (microseconds + 999) / 1000;
   ::Sleep(milliseconds);
   return 0;
 }
 
-char *thrift_ctime_r(const time_t *_clock, char *_buf)
-{
-   strcpy(_buf, ctime(_clock));
-   return _buf;
+char* thrift_ctime_r(const time_t* _clock, char* _buf) {
+  strcpy(_buf, ctime(_clock));
+  return _buf;
 }
-
-
diff --git a/lib/cpp/src/thrift/windows/GetTimeOfDay.h b/lib/cpp/src/thrift/windows/GetTimeOfDay.h
index 27b8a84..762ac5e 100644
--- a/lib/cpp/src/thrift/windows/GetTimeOfDay.h
+++ b/lib/cpp/src/thrift/windows/GetTimeOfDay.h
@@ -29,15 +29,16 @@
 #endif
 
 #include <thrift/thrift-config.h>
+#include <time.h>
 
 struct thrift_timespec {
   int64_t tv_sec;
   int64_t tv_nsec;
 };
 
-int thrift_gettimeofday(struct timeval * tv, struct timezone * tz);
+int thrift_gettimeofday(struct timeval* tv, struct timezone* tz);
 int thrift_sleep(unsigned int seconds);
 int thrift_usleep(unsigned int micro_seconds);
-char *thrift_ctime_r(const time_t *_clock, char *_buf);
+char* thrift_ctime_r(const time_t* _clock, char* _buf);
 
 #endif // _THRIFT_WINDOWS_GETTIMEOFDAY_H_
diff --git a/lib/cpp/src/thrift/windows/Operators.h b/lib/cpp/src/thrift/windows/Operators.h
index 95d8e3e..9b86096 100644
--- a/lib/cpp/src/thrift/windows/Operators.h
+++ b/lib/cpp/src/thrift/windows/Operators.h
@@ -24,17 +24,17 @@
 #pragma once
 #endif // _MSC_VER
 
-namespace apache { namespace thrift {
+namespace apache {
+namespace thrift {
 
 class TEnumIterator;
 
-inline bool operator == (const TEnumIterator&, const TEnumIterator&)
-{
-    // Not entirely sure what the test should be here. It is only to enable
-    // iterator debugging and is not used in release mode.
-    return true;
+inline bool operator==(const TEnumIterator&, const TEnumIterator&) {
+  // Not entirely sure what the test should be here. It is only to enable
+  // iterator debugging and is not used in release mode.
+  return true;
 }
-
-}} // apache::thrift
+}
+} // apache::thrift
 
 #endif // _THRIFT_WINDOWS_OPERATORS_H_
diff --git a/lib/cpp/src/thrift/windows/OverlappedSubmissionThread.cpp b/lib/cpp/src/thrift/windows/OverlappedSubmissionThread.cpp
new file mode 100644
index 0000000..5ac6fe0
--- /dev/null
+++ b/lib/cpp/src/thrift/windows/OverlappedSubmissionThread.cpp
@@ -0,0 +1,151 @@
+/*
+* 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.
+*/
+
+#include <thrift/windows/OverlappedSubmissionThread.h>
+#include <thrift/transport/TTransportException.h>
+#include <boost/noncopyable.hpp>
+#include <boost/scope_exit.hpp>
+#include <process.h>
+
+namespace apache {
+namespace thrift {
+namespace transport {
+
+TOverlappedWorkItem::TOverlappedWorkItem()
+  : SLIST_ENTRY(),
+    action(UNKNOWN),
+    h(INVALID_HANDLE_VALUE),
+    buffer(NULL),
+    buffer_len(0),
+    overlap(),
+    last_error(0),
+    success(TRUE) {
+}
+
+void TOverlappedWorkItem::reset(uint8_t* buf, uint32_t len, HANDLE event) {
+  memset(&overlap, 0, sizeof(overlap));
+  overlap.hEvent = event;
+  buffer = buf;
+  buffer_len = len;
+  last_error = 0;
+  success = FALSE;
+}
+
+uint32_t TOverlappedWorkItem::overlappedResults(bool signal_failure) {
+  DWORD bytes = 0;
+  BOOL result = ::GetOverlappedResult(h, &overlap, &bytes, TRUE);
+  if (signal_failure && !result) // get overlapped error case
+  {
+    GlobalOutput.perror("TPipe ::GetOverlappedResult errored GLE=", ::GetLastError());
+    throw TTransportException(TTransportException::UNKNOWN, "TPipe: GetOverlappedResult failed");
+  }
+  return bytes;
+}
+
+bool TOverlappedWorkItem::process() {
+  BOOST_SCOPE_EXIT((&doneSubmittingEvent)) { SetEvent(doneSubmittingEvent.h); }
+  BOOST_SCOPE_EXIT_END
+
+  switch (action) {
+  case (CONNECT):
+    success = ::ConnectNamedPipe(h, &overlap);
+    if (success == FALSE)
+      last_error = ::GetLastError();
+    return true;
+  case (READ):
+    success = ::ReadFile(h, buffer, buffer_len, NULL, &overlap);
+    if (success == FALSE)
+      last_error = ::GetLastError();
+    return true;
+  case (CANCELIO):
+    success = ::CancelIo(h);
+    if (success == FALSE)
+      last_error = ::GetLastError();
+    return true;
+  case (STOP):
+  default:
+    return false;
+  }
+}
+
+void TOverlappedSubmissionThread::addWorkItem(TOverlappedWorkItem* item) {
+  InterlockedPushEntrySList(&workList_, item);
+  SetEvent(workAvailableEvent_.h);
+  WaitForSingleObject(item->doneSubmittingEvent.h, INFINITE);
+}
+
+TOverlappedSubmissionThread* TOverlappedSubmissionThread::acquire_instance() {
+  TAutoCrit lock(instanceGuard_);
+  if (instance_ == NULL) {
+    assert(instanceRefCount_ == 0);
+    instance_ = new TOverlappedSubmissionThread;
+  }
+  ++instanceRefCount_;
+  return instance_;
+}
+void TOverlappedSubmissionThread::release_instance() {
+  TAutoCrit lock(instanceGuard_);
+  if (--instanceRefCount_ == 0) {
+    delete instance_;
+    instance_ = NULL;
+  }
+}
+
+TOverlappedSubmissionThread::TOverlappedSubmissionThread() {
+  stopItem_.action = TOverlappedWorkItem::STOP;
+
+  InitializeSListHead(&workList_);
+  thread_ = (HANDLE)_beginthreadex(NULL, 0, thread_proc, this, 0, NULL);
+  if (thread_ == 0) {
+    GlobalOutput.perror("TOverlappedSubmissionThread unable to create thread, errno=", errno);
+    throw TTransportException(TTransportException::NOT_OPEN,
+                              " TOverlappedSubmissionThread unable to create thread");
+  }
+}
+
+TOverlappedSubmissionThread::~TOverlappedSubmissionThread() {
+  addWorkItem(&stopItem_);
+  ::WaitForSingleObject(thread_, INFINITE);
+  CloseHandle(thread_);
+}
+
+void TOverlappedSubmissionThread::run() {
+  for (;;) {
+    WaitForSingleObject(workAvailableEvent_.h, INFINITE);
+    // todo check result
+    SLIST_ENTRY* entry = NULL;
+    while ((entry = InterlockedPopEntrySList(&workList_)) != NULL) {
+      TOverlappedWorkItem& item = *static_cast<TOverlappedWorkItem*>(entry);
+      if (!item.process())
+        return;
+    }
+  }
+}
+
+unsigned __stdcall TOverlappedSubmissionThread::thread_proc(void* addr) {
+  static_cast<TOverlappedSubmissionThread*>(addr)->run();
+  return 0;
+}
+
+TCriticalSection TOverlappedSubmissionThread::instanceGuard_;
+TOverlappedSubmissionThread* TOverlappedSubmissionThread::instance_;
+uint32_t TOverlappedSubmissionThread::instanceRefCount_ = 0;
+}
+}
+} // apach::thrift::transport
diff --git a/lib/cpp/src/thrift/windows/OverlappedSubmissionThread.h b/lib/cpp/src/thrift/windows/OverlappedSubmissionThread.h
new file mode 100644
index 0000000..dd0c5c9
--- /dev/null
+++ b/lib/cpp/src/thrift/windows/OverlappedSubmissionThread.h
@@ -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.
+ */
+
+#ifndef _THRIFT_WINDOWS_OverlappedSubmissionThread_H_
+#define _THRIFT_WINDOWS_OverlappedSubmissionThread_H_ 1
+
+#ifndef _WIN32
+#error "OverlappedSubmissionThread.h is only usable on Windows"
+#endif
+
+#include <thrift/windows/Sync.h>
+#include <boost/noncopyable.hpp>
+#include <Windows.h>
+
+/*
+  *** Why does this class exist?
+  In short, because we want to enable something similar to a "select" loop, on Windows, with
+  named pipes.  The core of the "select" loop is a call to WaitForMultipleObjects.  So that means
+  we need a signalable object that indicates when data is available.
+
+  A pipe handle doesn't do that.  A pipe handle is signaled when a read or write completes, and if
+  no one has called read or write, then the pipe handle is useless in WaitForMultipleObjects.  So
+  instead, we use overlapped I/O.  With overlapped I/O, you call read, and associate an event with
+  the read.  When the read finishes, the event is signaled.  This means that when you create a pipe,
+  you start a read.  When the customer calls read on your transport object, you wait for the last
+  read to finish, and then kick off another.
+
+  There is one big caveat to this though.  The thread that initiated the read must stay alive.  If
+  the thread that initiated the read exits, then the read completes in an error state.  To ensure
+  that the initiating thread stays alive, we create a singleton thread whose sole responsibility is
+  to manage this overlapped I/O requests.  This introduces some overhead, but it is overhead that
+  is necessary for correct behavior.
+
+  This thread currently supports connect, read, and cancel io.  So far, I haven't needed to put any
+  writes on this thread, but if needed, it could be done.  The client write buffer would need to be
+  copied to ensure that it doesn't get invalidated.
+
+  *** How does one use this class?
+  Create a TOverlappedWorkItem, and fill in the action and "h", then call reset().  Your work item
+  is now ready to be submitted to the overlapped submission thread.  Create a TAutoOverlapThread,
+  and call thread->addWorkItem with your work item.  After addWorkItem completes, you may inspect
+  last_error and success.  At some point in the future, call workItem.overlappedResults to wait
+  until the operation has completed.
+*/
+
+namespace apache {
+namespace thrift {
+namespace transport {
+
+struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) TOverlappedWorkItem : public SLIST_ENTRY {
+  TOverlappedWorkItem();
+
+  enum action_t {
+    UNKNOWN = 3000,
+    CONNECT,
+    READ,
+    CANCELIO,
+    STOP,
+  };
+
+  TAutoResetEvent doneSubmittingEvent;
+  action_t action;
+  HANDLE h;
+  uint8_t* buffer;
+  uint32_t buffer_len;
+  OVERLAPPED overlap;
+
+  DWORD last_error;
+  BOOL success;
+
+  void reset(uint8_t* buf, uint32_t len, HANDLE event);
+  uint32_t overlappedResults(bool signal_failure = true);
+  bool process();
+};
+
+class TOverlappedSubmissionThread : boost::noncopyable {
+public:
+  void addWorkItem(TOverlappedWorkItem* item);
+
+  // singleton stuff
+public:
+  static TOverlappedSubmissionThread* acquire_instance();
+  static void release_instance();
+
+private:
+  static TCriticalSection instanceGuard_;
+  static TOverlappedSubmissionThread* instance_;
+  static uint32_t instanceRefCount_;
+
+  // thread details
+private:
+  TOverlappedSubmissionThread();
+  ~TOverlappedSubmissionThread();
+  void run();
+  static unsigned __stdcall thread_proc(void* addr);
+
+private:
+  DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) SLIST_HEADER workList_;
+  TOverlappedWorkItem stopItem_;
+  TAutoResetEvent workAvailableEvent_;
+  HANDLE thread_;
+};
+
+class TAutoOverlapThread : boost::noncopyable {
+private:
+  TOverlappedSubmissionThread* p;
+
+public:
+  TAutoOverlapThread() : p(TOverlappedSubmissionThread::acquire_instance()) {}
+  ~TAutoOverlapThread() { TOverlappedSubmissionThread::release_instance(); }
+  TOverlappedSubmissionThread* operator->() { return p; }
+};
+}
+}
+} // apache::thrift::transport
+
+#endif
diff --git a/lib/cpp/src/thrift/windows/SocketPair.cpp b/lib/cpp/src/thrift/windows/SocketPair.cpp
index 4b65e6b..7228832 100644
--- a/lib/cpp/src/thrift/windows/SocketPair.cpp
+++ b/lib/cpp/src/thrift/windows/SocketPair.cpp
@@ -36,67 +36,65 @@
 // Win32
 #include <WS2tcpip.h>
 
-int thrift_socketpair(int d, int type, int protocol, THRIFT_SOCKET sv[2])
-{
-    THRIFT_UNUSED_VARIABLE(protocol);
-    THRIFT_UNUSED_VARIABLE(type);
-    THRIFT_UNUSED_VARIABLE(d);
+int thrift_socketpair(int d, int type, int protocol, THRIFT_SOCKET sv[2]) {
+  THRIFT_UNUSED_VARIABLE(protocol);
+  THRIFT_UNUSED_VARIABLE(type);
+  THRIFT_UNUSED_VARIABLE(d);
 
-    union {
-       struct sockaddr_in inaddr;
-       struct sockaddr addr;
-    } a;
-    THRIFT_SOCKET listener;
-    int e;
-    socklen_t addrlen = sizeof(a.inaddr);
-    DWORD flags = 0;
-    int reuse = 1;
+  union {
+    struct sockaddr_in inaddr;
+    struct sockaddr addr;
+  } a;
+  THRIFT_SOCKET listener;
+  int e;
+  socklen_t addrlen = sizeof(a.inaddr);
+  DWORD flags = 0;
+  int reuse = 1;
 
-    if (sv == 0) {
-      WSASetLastError(WSAEINVAL);
-      return SOCKET_ERROR;
-    }
-
-    listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-    if (listener == INVALID_SOCKET)
-        return SOCKET_ERROR;
-
-    memset(&a, 0, sizeof(a));
-    a.inaddr.sin_family = AF_INET;
-    a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-    a.inaddr.sin_port = 0;
-
-    sv[0] = sv[1] = INVALID_SOCKET;
-    do {
-        //ignore errors coming out of this setsockopt.  This is because
-        //SO_EXCLUSIVEADDRUSE requires admin privileges on WinXP, but we don't
-        //want to force socket pairs to be an admin.
-        setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
-               (char*) &reuse, (socklen_t) sizeof(reuse));
-        if  (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
-            break;
-        if  (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR)
-            break;
-        if (listen(listener, 1) == SOCKET_ERROR)
-            break;
-        sv[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags);
-        if (sv[0] == INVALID_SOCKET)
-            break;
-        if (connect(sv[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
-            break;
-        sv[1] = accept(listener, NULL, NULL);
-        if (sv[1] == INVALID_SOCKET)
-            break;
-
-        closesocket(listener);
-        return 0;
-
-    } while (0);
-
-    e = WSAGetLastError();
-    closesocket(listener);
-    closesocket(sv[0]);
-    closesocket(sv[1]);
-    WSASetLastError(e);
+  if (sv == 0) {
+    WSASetLastError(WSAEINVAL);
     return SOCKET_ERROR;
+  }
+
+  listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (listener == INVALID_SOCKET)
+    return SOCKET_ERROR;
+
+  memset(&a, 0, sizeof(a));
+  a.inaddr.sin_family = AF_INET;
+  a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  a.inaddr.sin_port = 0;
+
+  sv[0] = sv[1] = INVALID_SOCKET;
+  do {
+    // ignore errors coming out of this setsockopt.  This is because
+    // SO_EXCLUSIVEADDRUSE requires admin privileges on WinXP, but we don't
+    // want to force socket pairs to be an admin.
+    setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char*)&reuse, (socklen_t)sizeof(reuse));
+    if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
+      break;
+    if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR)
+      break;
+    if (listen(listener, 1) == SOCKET_ERROR)
+      break;
+    sv[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags);
+    if (sv[0] == INVALID_SOCKET)
+      break;
+    if (connect(sv[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
+      break;
+    sv[1] = accept(listener, NULL, NULL);
+    if (sv[1] == INVALID_SOCKET)
+      break;
+
+    closesocket(listener);
+    return 0;
+
+  } while (0);
+
+  e = WSAGetLastError();
+  closesocket(listener);
+  closesocket(sv[0]);
+  closesocket(sv[1]);
+  WSASetLastError(e);
+  return SOCKET_ERROR;
 }
diff --git a/lib/cpp/src/thrift/windows/StdAfx.cpp b/lib/cpp/src/thrift/windows/StdAfx.cpp
deleted file mode 100644
index e69de29..0000000
--- a/lib/cpp/src/thrift/windows/StdAfx.cpp
+++ /dev/null
diff --git a/lib/cpp/src/thrift/windows/StdAfx.h b/lib/cpp/src/thrift/windows/StdAfx.h
deleted file mode 100644
index e69de29..0000000
--- a/lib/cpp/src/thrift/windows/StdAfx.h
+++ /dev/null
diff --git a/lib/cpp/src/thrift/windows/Sync.h b/lib/cpp/src/thrift/windows/Sync.h
new file mode 100644
index 0000000..5d32199
--- /dev/null
+++ b/lib/cpp/src/thrift/windows/Sync.h
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_WINDOWS_Sync_H_
+#define _THRIFT_WINDOWS_Sync_H_ 1
+
+#ifndef _WIN32
+#error "windows/Sync.h is only usable on Windows"
+#endif
+
+#include <thrift/concurrency/Exception.h>
+#include <boost/noncopyable.hpp>
+#include <Windows.h>
+
+/*
+  Lightweight synchronization objects that only make sense on Windows.  For cross-platform
+  code, use the classes found in the concurrency namespace
+*/
+
+namespace apache {
+namespace thrift {
+
+struct TCriticalSection : boost::noncopyable {
+  CRITICAL_SECTION cs;
+  TCriticalSection() { InitializeCriticalSection(&cs); }
+  ~TCriticalSection() { DeleteCriticalSection(&cs); }
+};
+
+class TAutoCrit : boost::noncopyable {
+private:
+  CRITICAL_SECTION* cs_;
+
+public:
+  explicit TAutoCrit(TCriticalSection& cs) : cs_(&cs.cs) { EnterCriticalSection(cs_); }
+  ~TAutoCrit() { LeaveCriticalSection(cs_); }
+};
+
+struct TAutoResetEvent : boost::noncopyable {
+  HANDLE h;
+
+  TAutoResetEvent() {
+    h = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (h == NULL) {
+      GlobalOutput.perror("TAutoResetEvent unable to create event, GLE=", GetLastError());
+      throw apache::thrift::concurrency::SystemResourceException("CreateEvent failed");
+    }
+  }
+  ~TAutoResetEvent() { CloseHandle(h); }
+};
+
+struct TManualResetEvent : boost::noncopyable {
+  HANDLE h;
+
+  TManualResetEvent() {
+    h = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (h == NULL) {
+      GlobalOutput.perror("TManualResetEvent unable to create event, GLE=", GetLastError());
+      throw apache::thrift::concurrency::SystemResourceException("CreateEvent failed");
+    }
+  }
+  ~TManualResetEvent() { CloseHandle(h); }
+};
+
+struct TAutoHandle : boost::noncopyable {
+  HANDLE h;
+  explicit TAutoHandle(HANDLE h_ = INVALID_HANDLE_VALUE) : h(h_) {}
+  ~TAutoHandle() {
+    if (h != INVALID_HANDLE_VALUE)
+      CloseHandle(h);
+  }
+
+  HANDLE release() {
+    HANDLE retval = h;
+    h = INVALID_HANDLE_VALUE;
+    return retval;
+  }
+  void reset(HANDLE h_ = INVALID_HANDLE_VALUE) {
+    if (h_ == h)
+      return;
+    if (h != INVALID_HANDLE_VALUE)
+      CloseHandle(h);
+    h = h_;
+  }
+};
+}
+} // apache::thrift
+
+#endif
diff --git a/lib/cpp/src/thrift/windows/TWinsockSingleton.cpp b/lib/cpp/src/thrift/windows/TWinsockSingleton.cpp
index 2e306c6..d2683b0 100644
--- a/lib/cpp/src/thrift/windows/TWinsockSingleton.cpp
+++ b/lib/cpp/src/thrift/windows/TWinsockSingleton.cpp
@@ -23,51 +23,39 @@
 #include <boost/assert.hpp>
 #include <stdexcept>
 
-namespace apache { namespace thrift { namespace transport {
+namespace apache {
+namespace thrift {
+namespace transport {
 
 TWinsockSingleton::instance_ptr TWinsockSingleton::instance_ptr_(NULL);
-#if USE_BOOST_THREAD
-boost::once_flag                TWinsockSingleton::flags_ = BOOST_ONCE_INIT;
-#elif USE_STD_THREAD
-std::once_flag                  TWinsockSingleton::flags_;
-#else
-#error For windows you must choose USE_BOOST_THREAD or USE_STD_THREAD
-#endif
+std::once_flag TWinsockSingleton::flags_;
 
 //------------------------------------------------------------------------------
-TWinsockSingleton::TWinsockSingleton(void)
-{
-    WORD    version(MAKEWORD(2, 2));
-    WSAData data = {0};
+TWinsockSingleton::TWinsockSingleton(void) {
+  WORD version(MAKEWORD(2, 2));
+  WSAData data = {0};
 
-    int error(WSAStartup(version, &data));
-    if (error != 0)
-    {
-        BOOST_ASSERT(false);
-        throw std::runtime_error("Failed to initialise Winsock.");
-    }
+  int error(WSAStartup(version, &data));
+  if (error != 0) {
+    BOOST_ASSERT(false);
+    throw std::runtime_error("Failed to initialise Winsock.");
+  }
 }
 
 //------------------------------------------------------------------------------
-TWinsockSingleton::~TWinsockSingleton(void)
-{
-    WSACleanup();
+TWinsockSingleton::~TWinsockSingleton(void) {
+  WSACleanup();
 }
 
 //------------------------------------------------------------------------------
-void TWinsockSingleton::create(void)
-{
-#if USE_BOOST_THREAD
-    boost::call_once(init, flags_);
-#elif USE_STD_THREAD
-    std::call_once(flags_, init);
-#endif
+void TWinsockSingleton::create(void) {
+  std::call_once(flags_, init);
 }
 
 //------------------------------------------------------------------------------
-void TWinsockSingleton::init(void)
-{
-    instance_ptr_.reset(new TWinsockSingleton);
+void TWinsockSingleton::init(void) {
+  instance_ptr_.reset(new TWinsockSingleton);
 }
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
diff --git a/lib/cpp/src/thrift/windows/TWinsockSingleton.h b/lib/cpp/src/thrift/windows/TWinsockSingleton.h
index ab12c22..a30806b 100644
--- a/lib/cpp/src/thrift/windows/TWinsockSingleton.h
+++ b/lib/cpp/src/thrift/windows/TWinsockSingleton.h
@@ -32,57 +32,42 @@
 
 // boost
 #include <boost/noncopyable.hpp>
-#include <boost/scoped_ptr.hpp>
 
-#if USE_BOOST_THREAD
-#include <boost/thread/once.hpp>
-#elif USE_STD_THREAD
+#include <memory>
 #include <mutex>
-#else
-#error For windows you must choose USE_BOOST_THREAD or USE_STD_THREAD
-#endif
 
-namespace apache { namespace thrift { namespace transport {
+
+namespace apache {
+namespace thrift {
+namespace transport {
 
 /**
  * Winsock2 must be intialised once only in order to create sockets. This class
  * performs a one time initialisation when create is called.
  */
-class TWinsockSingleton : private boost::noncopyable
-{
+class TWinsockSingleton : private boost::noncopyable {
 
 public:
-
-    typedef boost::scoped_ptr<TWinsockSingleton> instance_ptr;
+  typedef std::shared_ptr<TWinsockSingleton> instance_ptr;
 
 private:
-
-    TWinsockSingleton(void);
+  TWinsockSingleton(void);
 
 public:
-
-    ~TWinsockSingleton(void);
+  ~TWinsockSingleton(void);
 
 public:
-
-    static void create(void);
+  static void create(void);
 
 private:
-
-    static void init(void);
+  static void init(void);
 
 private:
-
-    static instance_ptr     instance_ptr_;
-#if USE_BOOST_THREAD
-    static boost::once_flag flags_;
-#elif USE_STD_THREAD
-    static std::once_flag flags_;
-#else
-#error Need a non-Boost non-C++11 way to track single initialization here.
-#endif
+  static instance_ptr instance_ptr_;
+  static std::once_flag flags_;
 };
-
-}}} // apache::thrift::transport
+}
+}
+} // apache::thrift::transport
 
 #endif // _THRIFT_TRANSPORT_WINDOWS_TWINSOCKSINGLETON_H_
diff --git a/lib/cpp/src/thrift/windows/TargetVersion.h b/lib/cpp/src/thrift/windows/TargetVersion.h
deleted file mode 100644
index e69de29..0000000
--- a/lib/cpp/src/thrift/windows/TargetVersion.h
+++ /dev/null
diff --git a/lib/cpp/src/thrift/windows/WinFcntl.cpp b/lib/cpp/src/thrift/windows/WinFcntl.cpp
index 2466400..c907e92 100644
--- a/lib/cpp/src/thrift/windows/WinFcntl.cpp
+++ b/lib/cpp/src/thrift/windows/WinFcntl.cpp
@@ -19,54 +19,46 @@
 
 #include <thrift/windows/WinFcntl.h>
 
-int thrift_fcntl(THRIFT_SOCKET fd, int cmd, int flags)
-{
-    if(cmd != THRIFT_F_GETFL && cmd != THRIFT_F_SETFL)
-    {
-        return -1;
-    }
+int thrift_fcntl(THRIFT_SOCKET fd, int cmd, int flags) {
+  if (cmd != THRIFT_F_GETFL && cmd != THRIFT_F_SETFL) {
+    return -1;
+  }
 
-    if(flags != THRIFT_O_NONBLOCK && flags != 0)
-    {
-        return -1;
-    }
+  if (flags != THRIFT_O_NONBLOCK && flags != 0) {
+    return -1;
+  }
 
-    if(cmd == THRIFT_F_GETFL)
-    {
-        return 0;
-    }
+  if (cmd == THRIFT_F_GETFL) {
+    return 0;
+  }
 
-    int res;
-    if(flags)
-    {
-        res = ioctlsocket(fd, FIONBIO, reinterpret_cast<u_long *>(&(flags = 1)));
-    }
-    else
-    {
-        res = ioctlsocket(fd, FIONBIO, reinterpret_cast<u_long *>(&(flags = 0)));
-    }
+  int res;
+  if (flags) {
+    res = ioctlsocket(fd, FIONBIO, reinterpret_cast<u_long*>(&(flags = 1)));
+  } else {
+    res = ioctlsocket(fd, FIONBIO, reinterpret_cast<u_long*>(&(flags = 0)));
+  }
 
-    return res;
+  return res;
 }
 
-#if WINVER <= 0x0502 //XP, Server2003
-int thrift_poll(THRIFT_POLLFD *fdArray, ULONG nfds, INT timeout)
-{
+#if WINVER <= 0x0502 // XP, Server2003
+int thrift_poll(THRIFT_POLLFD* fdArray, ULONG nfds, INT timeout) {
   fd_set read_fds, write_fds;
-  fd_set* read_fds_ptr  = NULL;
+  fd_set* read_fds_ptr = NULL;
   fd_set* write_fds_ptr = NULL;
 
   FD_ZERO(&read_fds);
   FD_ZERO(&write_fds);
 
-  for(ULONG i=0; i<nfds; i++) {
-    //Read (in) socket
-    if((fdArray[i].events & THRIFT_POLLIN) == THRIFT_POLLIN) {
+  for (ULONG i = 0; i < nfds; i++) {
+    // Read (in) socket
+    if ((fdArray[i].events & THRIFT_POLLIN) == THRIFT_POLLIN) {
       read_fds_ptr = &read_fds;
       FD_SET(fdArray[i].fd, &read_fds);
     }
-    //Write (out) socket
-    else if((fdArray[i].events & THRIFT_POLLOUT) == THRIFT_POLLOUT) {
+    // Write (out) socket
+    else if ((fdArray[i].events & THRIFT_POLLOUT) == THRIFT_POLLOUT) {
       write_fds_ptr = &write_fds;
       FD_SET(fdArray[i].fd, &write_fds);
     }
@@ -74,31 +66,36 @@
 
   timeval time_out;
   timeval* time_out_ptr = NULL;
-  if(timeout >= 0) {
-    timeval time_out = {timeout / 1000, timeout * 1000};
+  if (timeout >= 0) {
+    time_out.tv_sec = timeout / 1000;
+    time_out.tv_usec = (timeout % 1000) * 1000;
     time_out_ptr = &time_out;
-  }
-  else { //to avoid compiler warnings
+  } else { // to avoid compiler warnings
     (void)time_out;
     (void)timeout;
   }
 
   int sktready = select(1, read_fds_ptr, write_fds_ptr, NULL, time_out_ptr);
-  if(sktready > 0) {
-    for(ULONG i=0; i<nfds; i++) {
+  if (sktready > 0) {
+    for (ULONG i = 0; i < nfds; i++) {
       fdArray[i].revents = 0;
-      if(FD_ISSET(fdArray[i].fd, &read_fds))
+      if (FD_ISSET(fdArray[i].fd, &read_fds))
         fdArray[i].revents |= THRIFT_POLLIN;
-      if(FD_ISSET(fdArray[i].fd, &write_fds))
+      if (FD_ISSET(fdArray[i].fd, &write_fds))
         fdArray[i].revents |= THRIFT_POLLOUT;
     }
   }
   return sktready;
 }
-#else //Vista, Win7...
-int thrift_poll(THRIFT_POLLFD *fdArray, ULONG nfds, INT timeout)
-{
+#else  // Vista, Win7...
+int thrift_poll(THRIFT_POLLFD* fdArray, ULONG nfds, INT timeout) {
   return WSAPoll(fdArray, nfds, timeout);
 }
 #endif // WINVER
 
+#ifdef _WIN32_WCE
+std::string thrift_wstr2str(std::wstring ws) {
+  std::string s(ws.begin(), ws.end());
+  return s;
+}
+#endif
diff --git a/lib/cpp/src/thrift/windows/WinFcntl.h b/lib/cpp/src/thrift/windows/WinFcntl.h
index f30c0de..6c6be97 100644
--- a/lib/cpp/src/thrift/windows/WinFcntl.h
+++ b/lib/cpp/src/thrift/windows/WinFcntl.h
@@ -28,21 +28,29 @@
 #error This is a MSVC header only.
 #endif
 
+#ifdef _WIN32_WCE
+#include <string>
+#endif
+
 // Win32
 #include <Winsock2.h>
 #include <thrift/transport/PlatformSocket.h>
 
-#if WINVER <= 0x0502 //XP, Server2003
+#if WINVER <= 0x0502 // XP, Server2003
 struct thrift_pollfd {
-  THRIFT_SOCKET  fd;
-  SHORT   events;
-  SHORT   revents;
+  THRIFT_SOCKET fd;
+  SHORT events;
+  SHORT revents;
 };
 #endif
 
 extern "C" {
 int thrift_fcntl(THRIFT_SOCKET fd, int cmd, int flags);
-int thrift_poll(THRIFT_POLLFD *fdArray, ULONG nfds, INT timeout);
+int thrift_poll(THRIFT_POLLFD* fdArray, ULONG nfds, INT timeout);
 }
 
+#ifdef _WIN32_WCE
+std::string thrift_wstr2str(std::wstring ws);
+#endif
+
 #endif // _THRIFT_WINDOWS_FCNTL_H_
diff --git a/lib/cpp/src/thrift/windows/config.h b/lib/cpp/src/thrift/windows/config.h
index 0555e07..a5f4457 100644
--- a/lib/cpp/src/thrift/windows/config.h
+++ b/lib/cpp/src/thrift/windows/config.h
@@ -25,53 +25,65 @@
 #endif // _MSC_VER
 
 #ifndef _WIN32
-#error This is a MSVC header only.
+#error "This is a Windows header only"
 #endif
 
-// use std::thread in MSVC11 (2012) or newer
-#if _MSC_VER >= 1700
-#  define USE_STD_THREAD 1
-// otherwise use boost threads
-#else
-#  define USE_BOOST_THREAD 1
+// use std::thread in MSVC11 (2012) or newer and in MinGW
+#if (_MSC_VER >= 1700) || defined(__MINGW32__)
+#define USE_STD_THREAD 1
+#endif
+
+// Something that defines PRId64 is required to build
+#define HAVE_INTTYPES_H 1
+
+// VS2010 or later has stdint.h as does MinGW
+#if (_MSC_VER >= 1600) || defined(__MINGW32__)
+#define HAVE_STDINT_H 1
 #endif
 
 #ifndef TARGET_WIN_XP
-#  define TARGET_WIN_XP 1
+#define TARGET_WIN_XP 1
 #endif
 
 #if TARGET_WIN_XP
-#  ifndef WINVER
-#    define WINVER 0x0501
-#  endif
-#  ifndef _WIN32_WINNT
-#    define _WIN32_WINNT 0x0501
-#  endif
+#ifndef WINVER
+#define WINVER 0x0501
+#endif
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
 #endif
 
 #ifndef _WIN32_WINNT
-#  define _WIN32_WINNT 0x0601
+#define _WIN32_WINNT 0x0601
 #endif
 
-#pragma warning(disable: 4996) // Deprecated posix name.
+#if defined(_M_IX86) || defined(_M_X64)
+#define ARITHMETIC_RIGHT_SHIFT 1
+#define SIGNED_RIGHT_SHIFT_IS 1
+#endif
 
-#define VERSION "1.0.0-dev"
+#ifndef __MINGW32__
+#pragma warning(disable : 4996) // Deprecated posix name.
+#endif
+
 #define HAVE_GETTIMEOFDAY 1
 #define HAVE_SYS_STAT_H 1
 
+// Must be using VS2010 or later, or boost, so that C99 types are defined in the global namespace
 #ifdef HAVE_STDINT_H
-#  include <stdint.h>
+#include <stdint.h>
 #else
-#  include <boost/cstdint.hpp>
+#include <boost/cstdint.hpp>
 
-typedef boost::int64_t    int64_t;
-typedef boost::uint64_t  uint64_t;
-typedef boost::int32_t    int32_t;
-typedef boost::uint32_t  uint32_t;
-typedef boost::int16_t    int16_t;
-typedef boost::uint16_t  uint16_t;
-typedef boost::int8_t      int8_t;
-typedef boost::uint8_t    uint8_t;
+typedef boost::int64_t int64_t;
+typedef boost::uint64_t uint64_t;
+typedef boost::int32_t int32_t;
+typedef boost::uint32_t uint32_t;
+typedef boost::int16_t int16_t;
+typedef boost::uint16_t uint16_t;
+typedef boost::int8_t int8_t;
+typedef boost::uint8_t uint8_t;
 #endif
 
 #include <thrift/transport/PlatformSocket.h>
@@ -84,7 +96,14 @@
 // windows
 #include <Winsock2.h>
 #include <ws2tcpip.h>
-#pragma comment(lib, "Ws2_32.lib")
-#pragma comment(lib, "advapi32.lib") //For security APIs in TPipeServer
+#ifndef __MINGW32__
+  #ifdef _WIN32_WCE
+  #pragma comment(lib, "Ws2.lib")
+  #else
+  #pragma comment(lib, "Ws2_32.lib")
+  #pragma comment(lib, "advapi32.lib") // For security APIs in TPipeServer
+  #pragma comment(lib, "Shlwapi.lib")  // For StrStrIA in TPipeServer
+  #endif
+#endif // __MINGW32__
 
 #endif // _THRIFT_WINDOWS_CONFIG_H_
diff --git a/lib/cpp/src/thrift/windows/force_inc.h b/lib/cpp/src/thrift/windows/force_inc.h
deleted file mode 100644
index e69de29..0000000
--- a/lib/cpp/src/thrift/windows/force_inc.h
+++ /dev/null
diff --git a/lib/cpp/src/thrift/windows/tr1/functional b/lib/cpp/src/thrift/windows/tr1/functional
deleted file mode 100644
index e69de29..0000000
--- a/lib/cpp/src/thrift/windows/tr1/functional
+++ /dev/null
diff --git a/lib/cpp/test/AllProtocolTests.cpp b/lib/cpp/test/AllProtocolTests.cpp
index 65d1927..6b5c7c4 100644
--- a/lib/cpp/test/AllProtocolTests.cpp
+++ b/lib/cpp/test/AllProtocolTests.cpp
@@ -22,6 +22,10 @@
 #include <thrift/protocol/TBinaryProtocol.h>
 #include <thrift/protocol/TCompactProtocol.h>
 #include <thrift/transport/TBufferTransports.h>
+
+#define BOOST_TEST_MODULE AllProtocolTests
+#include <boost/test/unit_test.hpp>
+
 #include "AllProtocolTests.tcc"
 
 using namespace apache::thrift;
@@ -30,15 +34,14 @@
 
 char errorMessage[ERR_LEN];
 
-int main(int argc, char** argv) {
-  (void) argc;
-  (void) argv;
-  try {
-    testProtocol<TBinaryProtocol>("TBinaryProtocol");
-    testProtocol<TCompactProtocol>("TCompactProtocol");
-  } catch (TException e) {
-    printf("%s\n", e.what());
-    return 1;
-  }
-  return 0;
+BOOST_AUTO_TEST_CASE(test_binary_protocol) {
+  testProtocol<TBinaryProtocol>("TBinaryProtocol");
+}
+
+BOOST_AUTO_TEST_CASE(test_little_binary_protocol) {
+  testProtocol<TLEBinaryProtocol>("TLEBinaryProtocol");
+}
+
+BOOST_AUTO_TEST_CASE(test_compact_protocol) {
+  testProtocol<TCompactProtocol>("TCompactProtocol");
 }
diff --git a/lib/cpp/test/AllProtocolTests.tcc b/lib/cpp/test/AllProtocolTests.tcc
index 9155da8..a7eab07 100644
--- a/lib/cpp/test/AllProtocolTests.tcc
+++ b/lib/cpp/test/AllProtocolTests.tcc
@@ -28,7 +28,7 @@
 
 #include "GenericHelpers.h"
 
-using boost::shared_ptr;
+using std::shared_ptr;
 using namespace apache::thrift;
 using namespace apache::thrift::protocol;
 using namespace apache::thrift::transport;
@@ -45,7 +45,10 @@
   Val out;
   GenericIO::read(protocol, out);
   if (out != val) {
-    snprintf(errorMessage, ERR_LEN, "Invalid naked test (type: %s)", ClassNames::getName<Val>());
+    THRIFT_SNPRINTF(errorMessage,
+                    ERR_LEN,
+                    "Invalid naked test (type: %s)",
+                    ClassNames::getName<Val>());
     throw TException(errorMessage);
   }
 }
@@ -71,11 +74,11 @@
   protocol->readFieldBegin(name, fieldType, fieldId);
 
   if (fieldId != 15) {
-    snprintf(errorMessage, ERR_LEN, "Invalid ID (type: %s)", typeid(val).name());
+    THRIFT_SNPRINTF(errorMessage, ERR_LEN, "Invalid ID (type: %s)", typeid(val).name());
     throw TException(errorMessage);
   }
   if (fieldType != type) {
-    snprintf(errorMessage, ERR_LEN, "Invalid Field Type (type: %s)", typeid(val).name());
+    THRIFT_SNPRINTF(errorMessage, ERR_LEN, "Invalid Field Type (type: %s)", typeid(val).name());
     throw TException(errorMessage);
   }
 
@@ -83,7 +86,7 @@
   GenericIO::read(protocol, out);
 
   if (out != val) {
-    snprintf(errorMessage, ERR_LEN, "Invalid value read (type: %s)", typeid(val).name());
+    THRIFT_SNPRINTF(errorMessage, ERR_LEN, "Invalid value read (type: %s)", typeid(val).name());
     throw TException(errorMessage);
   }
 
@@ -97,20 +100,18 @@
     const char* name;
     TMessageType type;
     int32_t seqid;
-  } messages[4] = {
-    {"short message name", T_CALL, 0},
-    {"1", T_REPLY, 12345},
-    {"loooooooooooooooooooooooooooooooooong", T_EXCEPTION, 1 << 16},
-    {"Janky", T_CALL, 0}
-  };
+  } messages[] = {{"short message name", T_CALL, 0},
+                  {"1", T_REPLY, 12345},
+                  {"loooooooooooooooooooooooooooooooooong", T_EXCEPTION, 1 << 16},
+                  {"one way push", T_ONEWAY, 12},
+                  {"Janky", T_CALL, 0}};
+  const int messages_count = sizeof(messages) / sizeof(TMessage);
 
-  for (int i = 0; i < 4; i++) {
+  for (int i = 0; i < messages_count; i++) {
     shared_ptr<TTransport> transport(new TMemoryBuffer());
     shared_ptr<TProtocol> protocol(new TProto(transport));
 
-    protocol->writeMessageBegin(messages[i].name,
-                                messages[i].type,
-                                messages[i].seqid);
+    protocol->writeMessageBegin(messages[i].name, messages[i].type, messages[i].seqid);
     protocol->writeMessageEnd();
 
     std::string name;
@@ -118,9 +119,7 @@
     int32_t seqid;
 
     protocol->readMessageBegin(name, type, seqid);
-    if (name != messages[i].name ||
-        type != messages[i].type ||
-        seqid != messages[i].seqid) {
+    if (name != messages[i].name || type != messages[i].type || seqid != messages[i].seqid) {
       throw TException("readMessageBegin failed.");
     }
   }
@@ -143,8 +142,8 @@
     testNaked<TProto, int16_t>((int16_t)-1);
     testNaked<TProto, int16_t>((int16_t)-15000);
     testNaked<TProto, int16_t>((int16_t)-0x7fff);
-    testNaked<TProto, int16_t>(std::numeric_limits<int16_t>::min());
-    testNaked<TProto, int16_t>(std::numeric_limits<int16_t>::max());
+    testNaked<TProto, int16_t>((std::numeric_limits<int16_t>::min)());
+    testNaked<TProto, int16_t>((std::numeric_limits<int16_t>::max)());
 
     testField<TProto, T_I16, int16_t>((int16_t)0);
     testField<TProto, T_I16, int16_t>((int16_t)1);
@@ -165,8 +164,8 @@
     testNaked<TProto, int32_t>(-1);
     testNaked<TProto, int32_t>(-15000);
     testNaked<TProto, int32_t>(-0xffff);
-    testNaked<TProto, int32_t>(std::numeric_limits<int32_t>::min());
-    testNaked<TProto, int32_t>(std::numeric_limits<int32_t>::max());
+    testNaked<TProto, int32_t>((std::numeric_limits<int32_t>::min)());
+    testNaked<TProto, int32_t>((std::numeric_limits<int32_t>::max)());
 
     testField<TProto, T_I32, int32_t>(0);
     testField<TProto, T_I32, int32_t>(1);
@@ -182,24 +181,23 @@
     testField<TProto, T_I32, int32_t>(-15000);
     testField<TProto, T_I32, int32_t>(-0xffff);
     testField<TProto, T_I32, int32_t>(-0xffffff);
-    testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::min());
-    testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::max());
-    testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::min() + 10);
-    testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::max() - 16);
-    testNaked<TProto, int64_t>(std::numeric_limits<int64_t>::min());
-    testNaked<TProto, int64_t>(std::numeric_limits<int64_t>::max());
-
+    testNaked<TProto, int64_t>((std::numeric_limits<int32_t>::min)());
+    testNaked<TProto, int64_t>((std::numeric_limits<int32_t>::max)());
+    testNaked<TProto, int64_t>((std::numeric_limits<int32_t>::min)() + 10);
+    testNaked<TProto, int64_t>((std::numeric_limits<int32_t>::max)() - 16);
+    testNaked<TProto, int64_t>((std::numeric_limits<int64_t>::min)());
+    testNaked<TProto, int64_t>((std::numeric_limits<int64_t>::max)());
 
     testNaked<TProto, int64_t>(0);
     for (int64_t i = 0; i < 62; i++) {
-      testNaked<TProto, int64_t>(1L << i);
-      testNaked<TProto, int64_t>(-(1L << i));
+      testNaked<TProto, int64_t>(1LL << i);
+      testNaked<TProto, int64_t>(-(1LL << i));
     }
 
     testField<TProto, T_I64, int64_t>(0);
     for (int i = 0; i < 62; i++) {
-      testField<TProto, T_I64, int64_t>(1L << i);
-      testField<TProto, T_I64, int64_t>(-(1L << i));
+      testField<TProto, T_I64, int64_t>(1LL << i);
+      testField<TProto, T_I64, int64_t>(-(1LL << i));
     }
 
     testNaked<TProto, double>(123.456);
@@ -208,7 +206,7 @@
     testNaked<TProto, std::string>("short");
     testNaked<TProto, std::string>("borderlinetiny");
     testNaked<TProto, std::string>("a bit longer than the smallest possible");
-    testNaked<TProto, std::string>("\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA"); //kinda binary test
+    testNaked<TProto, std::string>("\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA"); // kinda binary test
 
     testField<TProto, T_STRING, std::string>("");
     testField<TProto, T_STRING, std::string>("short");
@@ -219,7 +217,7 @@
 
     printf("%s => OK\n", protoname);
   } catch (TException e) {
-    snprintf(errorMessage, ERR_LEN, "%s => Test FAILED: %s", protoname, e.what());
+    THRIFT_SNPRINTF(errorMessage, ERR_LEN, "%s => Test FAILED: %s", protoname, e.what());
     throw TException(errorMessage);
   }
 }
diff --git a/lib/cpp/test/AnnotationTest.cpp b/lib/cpp/test/AnnotationTest.cpp
new file mode 100644
index 0000000..2e18840
--- /dev/null
+++ b/lib/cpp/test/AnnotationTest.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+#define BOOST_TEST_MODULE AnnotationTest
+#include <boost/test/unit_test.hpp>
+#include "gen-cpp/AnnotationTest_types.h"
+#include <ostream>
+#include <sstream>
+
+// Normally thrift generates ostream operators, however
+// with the annotation "cpp.customostream" one can tell the
+// compiler they are going to provide their own, and not
+// emit operator << or printTo().
+
+std::ostream& operator<<(std::ostream& os, const ostr_custom& osc)
+{
+  os << "{ bar = " << osc.bar << "; }";
+  return os;
+}
+
+BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE)
+
+BOOST_AUTO_TEST_CASE(test_cpp_compiler_generated_ostream_operator)
+{
+  ostr_default def;
+  def.__set_bar(10);
+
+  std::stringstream ssd;
+  ssd << def;
+  BOOST_CHECK_EQUAL(ssd.str(), "ostr_default(bar=10)");
+}
+
+BOOST_AUTO_TEST_CASE(test_cpp_customostream_uses_consuming_application_definition)
+{
+  ostr_custom cus;
+  cus.__set_bar(10);
+
+  std::stringstream csd;
+  csd << cus;
+  BOOST_CHECK_EQUAL(csd.str(), "{ bar = 10; }");
+}
+
+/**
+ * Disabled; see THRIFT-1567 - not sure what it is supposed to do
+BOOST_AUTO_TEST_CASE(test_cpp_type) {
+  // Check that the "cpp.type" annotation changes "struct foo" to "DenseFoo"
+  // This won't compile if the annotation is mishandled
+  DenseFoo foo;
+  foo.__set_bar(5);
+}
+ */
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/Base64Test.cpp b/lib/cpp/test/Base64Test.cpp
index 5caaae8..7686e4e 100644
--- a/lib/cpp/test/Base64Test.cpp
+++ b/lib/cpp/test/Base64Test.cpp
@@ -23,7 +23,7 @@
 using apache::thrift::protocol::base64_encode;
 using apache::thrift::protocol::base64_decode;
 
-BOOST_AUTO_TEST_SUITE( Base64Test )
+BOOST_AUTO_TEST_SUITE(Base64Test)
 
 void setupTestData(int i, uint8_t* data, int& len) {
   len = 0;
@@ -37,12 +37,16 @@
 }
 
 void checkEncoding(uint8_t* data, int len) {
+#ifdef NDEBUG
+  ((void)data);
+#endif
+
   for (int i = 0; i < len; i++) {
     BOOST_ASSERT(isalnum(data[i]) || data[i] == '/' || data[i] == '+');
   }
 }
 
-BOOST_AUTO_TEST_CASE( test_Base64_Encode_Decode ) {
+BOOST_AUTO_TEST_CASE(test_Base64_Encode_Decode) {
   int len;
   uint8_t testInput[3];
   uint8_t testOutput[4];
@@ -64,7 +68,6 @@
     // decode output and check that it matches input
     base64_decode(testOutput, len + 1);
     BOOST_ASSERT(0 == memcmp(testInput, testOutput, len));
-
   }
 }
 
diff --git a/lib/cpp/test/Benchmark.cpp b/lib/cpp/test/Benchmark.cpp
index 9ee2586..5ff77aa 100644
--- a/lib/cpp/test/Benchmark.cpp
+++ b/lib/cpp/test/Benchmark.cpp
@@ -21,11 +21,13 @@
 #include <config.h>
 #endif
 #include <iostream>
-#include <cmath>
-#include "thrift/transport/TBufferTransports.h"
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include <memory>
 #include "thrift/protocol/TBinaryProtocol.h"
+#include "thrift/transport/TBufferTransports.h"
 #include "gen-cpp/DebugProtoTest_types.h"
-#include <time.h>
+
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
@@ -34,76 +36,207 @@
 public:
   timeval vStart;
 
-  Timer() {
-    gettimeofday(&vStart, 0);
-  }
-  void start() {
-    gettimeofday(&vStart, 0);
-  }
+  Timer() { THRIFT_GETTIMEOFDAY(&vStart, 0); }
+  void start() { THRIFT_GETTIMEOFDAY(&vStart, 0); }
 
   double frame() {
     timeval vEnd;
-    gettimeofday(&vEnd, 0);
+    THRIFT_GETTIMEOFDAY(&vEnd, 0);
     double dstart = vStart.tv_sec + ((double)vStart.tv_usec / 1000000.0);
     double dend = vEnd.tv_sec + ((double)vEnd.tv_usec / 1000000.0);
     return dend - dstart;
   }
-
 };
 
 int main() {
-  using namespace std;
   using namespace thrift::test::debug;
   using namespace apache::thrift::transport;
   using namespace apache::thrift::protocol;
-  using namespace boost;
+  using std::cout;
+  using std::endl;
 
   OneOfEach ooe;
-  ooe.im_true   = true;
-  ooe.im_false  = false;
-  ooe.a_bite    = 0x7f;
+  ooe.im_true = true;
+  ooe.im_false = false;
+  ooe.a_bite = 0x7f;
   ooe.integer16 = 27000;
-  ooe.integer32 = 1<<24;
+  ooe.integer32 = 1 << 24;
   ooe.integer64 = (uint64_t)6000 * 1000 * 1000;
   ooe.double_precision = M_PI;
-  ooe.some_characters  = "JSON THIS! \"\1";
-  ooe.zomg_unicode     = "\xd7\n\a\t";
+  ooe.some_characters = "JSON THIS! \"\1";
+  ooe.zomg_unicode = "\xd7\n\a\t";
   ooe.base64 = "\1\2\3\255";
 
-  boost::shared_ptr<TMemoryBuffer> buf(new TMemoryBuffer());
+  int num = 100000;
+  std::shared_ptr<TMemoryBuffer> buf(new TMemoryBuffer(num*1000));
 
-  int num = 1000000;
+  uint8_t* data = NULL;
+  uint32_t datasize = 0;
 
   {
+    buf->resetBuffer();
+    TBinaryProtocolT<TMemoryBuffer> prot(buf);
+    double elapsed = 0.0;
     Timer timer;
 
-    for (int i = 0; i < num; i ++) {
-      buf->resetBuffer();
-      TBinaryProtocolT<TBufferBase> prot(buf);
+    for (int i = 0; i < num; i++) {
       ooe.write(&prot);
     }
-    cout << "Write: " << num / (1000 * timer.frame()) << " kHz" << endl;
+    elapsed = timer.frame();
+    cout << "Write big endian: " << num / (1000 * elapsed) << " kHz" << endl;
   }
 
-  uint8_t* data;
-  uint32_t datasize;
-
   buf->getBuffer(&data, &datasize);
 
   {
-
+    std::shared_ptr<TMemoryBuffer> buf2(new TMemoryBuffer(data, datasize));
+    TBinaryProtocolT<TMemoryBuffer> prot(buf2);
+    OneOfEach ooe2;
+    double elapsed = 0.0;
     Timer timer;
 
-    for (int i = 0; i < num; i ++) {
-      OneOfEach ooe2;
-      boost::shared_ptr<TMemoryBuffer> buf2(new TMemoryBuffer(data, datasize));
-      //buf2->resetBuffer(data, datasize);
-      TBinaryProtocolT<TBufferBase> prot(buf2);
+    for (int i = 0; i < num; i++) {
       ooe2.read(&prot);
-
-      //cout << apache::thrift::ThriftDebugString(ooe2) << endl << endl;
     }
-    cout << " Read: " << num / (1000 * timer.frame()) << " kHz" << endl;
+    elapsed = timer.frame();
+    cout << " Read big endian: " << num / (1000 * elapsed) << " kHz" << endl;
+  }
+
+  {
+    buf->resetBuffer();
+    TBinaryProtocolT<TMemoryBuffer, TNetworkLittleEndian> prot(buf);
+    double elapsed = 0.0;
+    Timer timer;
+
+    for (int i = 0; i < num; i++) {
+      ooe.write(&prot);
+    }
+    elapsed = timer.frame();
+    cout << "Write little endian: " << num / (1000 * elapsed) << " kHz" << endl;
+  }
+
+  {
+    OneOfEach ooe2;
+    std::shared_ptr<TMemoryBuffer> buf2(new TMemoryBuffer(data, datasize));
+    TBinaryProtocolT<TMemoryBuffer, TNetworkLittleEndian> prot(buf2);
+    double elapsed = 0.0;
+    Timer timer;
+
+    for (int i = 0; i < num; i++) {
+      ooe2.read(&prot);
+    }
+    elapsed = timer.frame();
+    cout << " Read little endian: " << num / (1000 * elapsed) << " kHz" << endl;
+  }
+
+  {
+    buf->resetBuffer();
+    TBinaryProtocolT<TMemoryBuffer> prot(buf);
+    double elapsed = 0.0;
+    Timer timer;
+
+    for (int i = 0; i < num; i++) {
+      ooe.write(&prot);
+    }
+    elapsed = timer.frame();
+    cout << "Write big endian: " << num / (1000 * elapsed) << " kHz" << endl;
+  }
+
+  {
+    std::shared_ptr<TMemoryBuffer> buf2(new TMemoryBuffer(data, datasize));
+    TBinaryProtocolT<TMemoryBuffer> prot(buf2);
+    OneOfEach ooe2;
+    double elapsed = 0.0;
+    Timer timer;
+
+    for (int i = 0; i < num; i++) {
+      ooe2.read(&prot);
+    }
+    elapsed = timer.frame();
+    cout << " Read big endian: " << num / (1000 * elapsed) << " kHz" << endl;
+  }
+
+
+  data = NULL;
+  datasize = 0;
+  num = 10000000;
+
+  ListDoublePerf listDoublePerf;
+  listDoublePerf.field.reserve(num);
+  for (int x = 0; x < num; ++x)
+    listDoublePerf.field.push_back(double(x));
+
+  buf.reset(new TMemoryBuffer(num * 100));
+
+  {
+    buf->resetBuffer();
+    TBinaryProtocolT<TMemoryBuffer> prot(buf);
+    double elapsed = 0.0;
+    Timer timer;
+
+    listDoublePerf.write(&prot);
+    elapsed = timer.frame();
+    cout << "Double write big endian: " << num / (1000 * elapsed) << " kHz" << endl;
+  }
+
+  buf->getBuffer(&data, &datasize);
+
+  {
+    std::shared_ptr<TMemoryBuffer> buf2(new TMemoryBuffer(data, datasize));
+    TBinaryProtocolT<TMemoryBuffer> prot(buf2);
+    ListDoublePerf listDoublePerf2;
+    double elapsed = 0.0;
+    Timer timer;
+
+    listDoublePerf2.read(&prot);
+    elapsed = timer.frame();
+    cout << " Double read big endian: " << num / (1000 * elapsed) << " kHz" << endl;
+  }
+
+  {
+    buf->resetBuffer();
+    TBinaryProtocolT<TMemoryBuffer, TNetworkLittleEndian> prot(buf);
+    double elapsed = 0.0;
+    Timer timer;
+
+    listDoublePerf.write(&prot);
+    elapsed = timer.frame();
+    cout << "Double write little endian: " << num / (1000 * elapsed) << " kHz" << endl;
+  }
+
+  {
+    ListDoublePerf listDoublePerf2;
+    std::shared_ptr<TMemoryBuffer> buf2(new TMemoryBuffer(data, datasize));
+    TBinaryProtocolT<TMemoryBuffer, TNetworkLittleEndian> prot(buf2);
+    double elapsed = 0.0;
+    Timer timer;
+
+    listDoublePerf2.read(&prot);
+    elapsed = timer.frame();
+    cout << " Double read little endian: " << num / (1000 * elapsed) << " kHz" << endl;
+  }
+
+  {
+    buf->resetBuffer();
+    TBinaryProtocolT<TMemoryBuffer> prot(buf);
+    double elapsed = 0.0;
+    Timer timer;
+
+    listDoublePerf.write(&prot);
+    elapsed = timer.frame();
+    cout << "Double write big endian: " << num / (1000 * elapsed) << " kHz" << endl;
+  }
+
+  {
+    std::shared_ptr<TMemoryBuffer> buf2(new TMemoryBuffer(data, datasize));
+    TBinaryProtocolT<TMemoryBuffer> prot(buf2);
+    ListDoublePerf listDoublePerf2;
+    double elapsed = 0.0;
+    Timer timer;
+
+    listDoublePerf2.read(&prot);
+    elapsed = timer.frame();
+    cout << " Double read big endian: " << num / (1000 * elapsed) << " kHz" << endl;
   }
 
 
diff --git a/lib/cpp/test/CMakeLists.txt b/lib/cpp/test/CMakeLists.txt
new file mode 100644
index 0000000..82d47a6
--- /dev/null
+++ b/lib/cpp/test/CMakeLists.txt
@@ -0,0 +1,405 @@
+#
+# 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.
+#
+
+include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
+
+if (WITH_DYN_LINK_TEST)
+    add_definitions( -DBOOST_TEST_DYN_LINK )
+endif()
+
+# Make sure gen-cpp files can be included
+include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+
+# Create the thrift C++ test library
+set(testgencpp_SOURCES
+    gen-cpp/AnnotationTest_types.cpp
+    gen-cpp/AnnotationTest_types.h
+    gen-cpp/DebugProtoTest_types.cpp
+    gen-cpp/DebugProtoTest_types.h
+    gen-cpp/EnumTest_types.cpp
+    gen-cpp/EnumTest_types.h
+    gen-cpp/OptionalRequiredTest_types.cpp
+    gen-cpp/OptionalRequiredTest_types.h
+    gen-cpp/Recursive_types.cpp
+    gen-cpp/Recursive_types.h
+    gen-cpp/ThriftTest_types.cpp
+    gen-cpp/ThriftTest_types.h
+    gen-cpp/OneWayTest_types.cpp
+    gen-cpp/OneWayTest_types.h
+    gen-cpp/OneWayService.cpp
+    gen-cpp/OneWayService.h
+    gen-cpp/TypedefTest_types.cpp
+    gen-cpp/TypedefTest_types.h
+    ThriftTest_extras.cpp
+    DebugProtoTest_extras.cpp
+)
+
+add_library(testgencpp STATIC ${testgencpp_SOURCES})
+
+set(testgencpp_cob_SOURCES
+    gen-cpp/ChildService.cpp
+    gen-cpp/ChildService.h
+    gen-cpp/EmptyService.cpp
+    gen-cpp/EmptyService.h
+    gen-cpp/ParentService.cpp
+    gen-cpp/ParentService.h
+    gen-cpp/proc_types.cpp
+    gen-cpp/proc_types.h
+)
+add_library(testgencpp_cob STATIC ${testgencpp_cob_SOURCES})
+
+add_executable(Benchmark Benchmark.cpp)
+target_link_libraries(Benchmark testgencpp)
+LINK_AGAINST_THRIFT_LIBRARY(Benchmark thrift)
+add_test(NAME Benchmark COMMAND Benchmark)
+target_link_libraries(Benchmark testgencpp)
+
+set(UnitTest_SOURCES
+    UnitTestMain.cpp
+    OneWayHTTPTest.cpp
+    TMemoryBufferTest.cpp
+    TBufferBaseTest.cpp
+    Base64Test.cpp
+    ToStringTest.cpp
+    TypedefTest.cpp
+    TServerSocketTest.cpp
+    TServerTransportTest.cpp
+)
+
+if(NOT WITH_STDTHREADS AND NOT MSVC AND NOT MINGW)
+    list(APPEND UnitTest_SOURCES concurrency/MutexTest.cpp)
+    list(APPEND UnitTest_SOURCES concurrency/RWMutexStarveTest.cpp)
+endif()
+
+add_executable(UnitTests ${UnitTest_SOURCES})
+target_link_libraries(UnitTests testgencpp ${Boost_LIBRARIES})
+LINK_AGAINST_THRIFT_LIBRARY(UnitTests thrift)
+add_test(NAME UnitTests COMMAND UnitTests)
+if ( MSVC )
+    # Disable C4503: decorated name length exceeded, name was truncated
+    # 'insanity' results in very long decorated names
+    set_property( TARGET UnitTests APPEND_STRING PROPERTY COMPILE_FLAGS /wd4503 )
+endif ( MSVC )
+
+
+set( TInterruptTest_SOURCES
+     TSocketInterruptTest.cpp
+     TSSLSocketInterruptTest.cpp
+)
+if (WIN32)
+    list(APPEND TInterruptTest_SOURCES
+        TPipeInterruptTest.cpp
+    )
+endif()
+add_executable(TInterruptTest ${TInterruptTest_SOURCES})
+target_link_libraries(TInterruptTest
+    testgencpp
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(TInterruptTest thrift)
+if (NOT MSVC AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT MINGW)
+target_link_libraries(TInterruptTest -lrt)
+endif ()
+add_test(NAME TInterruptTest COMMAND TInterruptTest -- "${CMAKE_CURRENT_SOURCE_DIR}/../../../test/keys")
+
+add_executable(TServerIntegrationTest TServerIntegrationTest.cpp)
+target_link_libraries(TServerIntegrationTest
+    testgencpp_cob
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(TServerIntegrationTest thrift)
+if (NOT MSVC AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT MINGW)
+target_link_libraries(TServerIntegrationTest -lrt)
+endif ()
+add_test(NAME TServerIntegrationTest COMMAND TServerIntegrationTest)
+
+if(WITH_ZLIB)
+include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}")
+add_executable(TransportTest TransportTest.cpp)
+target_link_libraries(TransportTest
+    testgencpp
+    ${Boost_LIBRARIES}
+    ${ZLIB_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(TransportTest thrift)
+LINK_AGAINST_THRIFT_LIBRARY(TransportTest thriftz)
+add_test(NAME TransportTest COMMAND TransportTest)
+
+add_executable(ZlibTest ZlibTest.cpp)
+target_link_libraries(ZlibTest
+    testgencpp
+    ${Boost_LIBRARIES}
+    ${ZLIB_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(ZlibTest thrift)
+LINK_AGAINST_THRIFT_LIBRARY(ZlibTest thriftz)
+add_test(NAME ZlibTest COMMAND ZlibTest)
+endif(WITH_ZLIB)
+
+add_executable(AnnotationTest AnnotationTest.cpp)
+target_link_libraries(AnnotationTest
+    testgencpp
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(AnnotationTest thrift)
+add_test(NAME AnnotationTest COMMAND AnnotationTest)
+
+add_executable(EnumTest EnumTest.cpp)
+target_link_libraries(EnumTest
+    testgencpp
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(EnumTest thrift)
+add_test(NAME EnumTest COMMAND EnumTest)
+
+if(HAVE_GETOPT_H)
+add_executable(TFileTransportTest TFileTransportTest.cpp)
+target_link_libraries(TFileTransportTest
+    testgencpp
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(TFileTransportTest thrift)
+add_test(NAME TFileTransportTest COMMAND TFileTransportTest)
+endif()
+
+add_executable(TFDTransportTest TFDTransportTest.cpp)
+target_link_libraries(TFDTransportTest
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(TFDTransportTest thrift)
+add_test(NAME TFDTransportTest COMMAND TFDTransportTest)
+
+add_executable(TPipedTransportTest TPipedTransportTest.cpp)
+target_link_libraries(TPipedTransportTest
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(TPipedTransportTest thrift)
+add_test(NAME TPipedTransportTest COMMAND TPipedTransportTest)
+
+set(AllProtocolsTest_SOURCES
+    AllProtocolTests.cpp
+    AllProtocolTests.tcc
+    GenericHelpers
+    )
+
+add_executable(AllProtocolsTest ${AllProtocolsTest_SOURCES})
+target_link_libraries(AllProtocolsTest
+    testgencpp
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(AllProtocolsTest thrift)
+add_test(NAME AllProtocolsTest COMMAND AllProtocolsTest)
+
+# The debug run-time in Windows asserts on isprint() with negative inputs
+if (NOT MSVC OR (MSVC AND CMAKE_BUILD_TYPE EQUAL "DEBUG"))
+add_executable(DebugProtoTest DebugProtoTest.cpp)
+target_link_libraries(DebugProtoTest
+    testgencpp
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(DebugProtoTest thrift)
+add_test(NAME DebugProtoTest COMMAND DebugProtoTest)
+endif()
+
+add_executable(JSONProtoTest JSONProtoTest.cpp)
+target_link_libraries(JSONProtoTest
+    testgencpp
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(JSONProtoTest thrift)
+add_test(NAME JSONProtoTest COMMAND JSONProtoTest)
+
+add_executable(OptionalRequiredTest OptionalRequiredTest.cpp)
+target_link_libraries(OptionalRequiredTest
+    testgencpp
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(OptionalRequiredTest thrift)
+add_test(NAME OptionalRequiredTest COMMAND OptionalRequiredTest)
+
+add_executable(RecursiveTest RecursiveTest.cpp)
+target_link_libraries(RecursiveTest
+    testgencpp
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(RecursiveTest thrift)
+add_test(NAME RecursiveTest COMMAND RecursiveTest)
+
+add_executable(SpecializationTest SpecializationTest.cpp)
+target_link_libraries(SpecializationTest
+    testgencpp
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(SpecializationTest thrift)
+add_test(NAME SpecializationTest COMMAND SpecializationTest)
+
+set(concurrency_test_SOURCES
+    concurrency/Tests.cpp
+    concurrency/ThreadFactoryTests.h
+    concurrency/ThreadManagerTests.h
+    concurrency/TimerManagerTests.h
+)
+add_executable(concurrency_test ${concurrency_test_SOURCES})
+LINK_AGAINST_THRIFT_LIBRARY(concurrency_test thrift)
+add_test(NAME concurrency_test COMMAND concurrency_test)
+
+set(link_test_SOURCES
+    link/LinkTest.cpp
+    gen-cpp/ParentService.h
+    link/TemplatedService1.cpp
+    link/TemplatedService2.cpp
+)
+
+add_executable(link_test ${link_test_SOURCES})
+target_link_libraries(link_test testgencpp_cob)
+LINK_AGAINST_THRIFT_LIBRARY(link_test thrift)
+target_link_libraries(link_test testgencpp)
+add_test(NAME link_test COMMAND link_test)
+
+if(WITH_LIBEVENT)
+set(processor_test_SOURCES
+    processor/ProcessorTest.cpp
+    processor/EventLog.cpp
+    processor/ServerThread.cpp
+    processor/EventLog.h
+    processor/Handlers.h
+    processor/ServerThread.h
+)
+add_executable(processor_test ${processor_test_SOURCES})
+target_link_libraries(processor_test
+    testgencpp_cob
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(processor_test thrift)
+LINK_AGAINST_THRIFT_LIBRARY(processor_test thriftnb)
+add_test(NAME processor_test COMMAND processor_test)
+
+set(TNonblockingServerTest_SOURCES TNonblockingServerTest.cpp)
+add_executable(TNonblockingServerTest ${TNonblockingServerTest_SOURCES})
+include_directories(${LIBEVENT_INCLUDE_DIRS})
+target_link_libraries(TNonblockingServerTest
+    testgencpp_cob
+    ${LIBEVENT_LIBRARIES}
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(TNonblockingServerTest thrift)
+LINK_AGAINST_THRIFT_LIBRARY(TNonblockingServerTest thriftnb)
+add_test(NAME TNonblockingServerTest COMMAND TNonblockingServerTest)
+
+if(OPENSSL_FOUND AND WITH_OPENSSL)
+  set(TNonblockingSSLServerTest_SOURCES TNonblockingSSLServerTest.cpp)
+  add_executable(TNonblockingSSLServerTest ${TNonblockingSSLServerTest_SOURCES})
+  include_directories(${LIBEVENT_INCLUDE_DIRS})
+  target_link_libraries(TNonblockingSSLServerTest
+    testgencpp_cob
+    ${LIBEVENT_LIBRARIES}
+    ${Boost_LIBRARIES}
+  )
+  LINK_AGAINST_THRIFT_LIBRARY(TNonblockingSSLServerTest thrift)
+  LINK_AGAINST_THRIFT_LIBRARY(TNonblockingSSLServerTest thriftnb)
+  add_test(NAME TNonblockingSSLServerTest COMMAND TNonblockingSSLServerTest -- "${CMAKE_CURRENT_SOURCE_DIR}/../../../test/keys")
+endif(OPENSSL_FOUND AND WITH_OPENSSL)
+endif(WITH_LIBEVENT)
+
+if(OPENSSL_FOUND AND WITH_OPENSSL)
+add_executable(OpenSSLManualInitTest OpenSSLManualInitTest.cpp)
+target_link_libraries(OpenSSLManualInitTest
+    ${OPENSSL_LIBRARIES}
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(OpenSSLManualInitTest thrift)
+add_test(NAME OpenSSLManualInitTest COMMAND OpenSSLManualInitTest)
+
+add_executable(SecurityTest SecurityTest.cpp)
+target_link_libraries(SecurityTest
+    testgencpp
+    ${Boost_LIBRARIES}
+)
+LINK_AGAINST_THRIFT_LIBRARY(SecurityTest thrift)
+if (NOT MSVC AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT MINGW)
+target_link_libraries(SecurityTest -lrt)
+endif ()
+add_test(NAME SecurityTest COMMAND SecurityTest -- "${CMAKE_CURRENT_SOURCE_DIR}/../../../test/keys")
+
+endif()
+
+if(WITH_QT4)
+set(CMAKE_AUTOMOC ON)
+find_package(Qt4 REQUIRED COMPONENTS QtTest)
+set(TQTcpServerTest_SOURCES
+    qt/TQTcpServerTest.cpp
+)
+add_executable(TQTcpServerTest ${TQTcpServerTest_SOURCES})
+target_link_libraries(TQTcpServerTest testgencpp_cob thriftqt Qt4::QtTest)
+LINK_AGAINST_THRIFT_LIBRARY(TQTcpServerTest thrift)
+add_test(NAME TQTcpServerTest COMMAND TQTcpServerTest)
+endif()
+
+if(WITH_QT5)
+add_subdirectory(qt)
+endif()
+
+#
+# Common thrift code generation rules
+#
+
+add_custom_command(OUTPUT gen-cpp/AnnotationTest_constants.cpp
+                          gen-cpp/AnnotationTest_constants.h
+                          gen-cpp/AnnotationTest_types.cpp
+                          gen-cpp/AnnotationTest_types.h
+                          gen-cpp/foo_service.cpp
+                          gen-cpp/foo_service.h
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/AnnotationTest.thrift
+)
+
+add_custom_command(OUTPUT gen-cpp/DebugProtoTest_types.cpp gen-cpp/DebugProtoTest_types.h gen-cpp/EmptyService.cpp gen-cpp/EmptyService.h
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/DebugProtoTest.thrift
+)
+
+add_custom_command(OUTPUT gen-cpp/EnumTest_types.cpp gen-cpp/EnumTest_types.h
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/EnumTest.thrift
+)
+
+add_custom_command(OUTPUT gen-cpp/TypedefTest_types.cpp gen-cpp/TypedefTest_types.h
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/TypedefTest.thrift
+)
+
+add_custom_command(OUTPUT gen-cpp/OptionalRequiredTest_types.cpp gen-cpp/OptionalRequiredTest_types.h
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/OptionalRequiredTest.thrift
+)
+
+add_custom_command(OUTPUT gen-cpp/Recursive_types.cpp gen-cpp/Recursive_types.h
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/Recursive.thrift
+)
+
+add_custom_command(OUTPUT gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/StressTest.thrift
+)
+
+add_custom_command(OUTPUT gen-cpp/SecondService.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_types.h
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
+)
+
+add_custom_command(OUTPUT gen-cpp/OneWayService.cpp gen-cpp/OneWayTest_constants.cpp gen-cpp/OneWayTest_types.h gen-cpp/OneWayService.h gen-cpp/OneWayTest_constants.h gen-cpp/OneWayTest_types.cpp
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${CMAKE_CURRENT_SOURCE_DIR}/OneWayTest.thrift
+)
+
+add_custom_command(OUTPUT gen-cpp/ChildService.cpp gen-cpp/ChildService.h gen-cpp/ParentService.cpp gen-cpp/ParentService.h gen-cpp/proc_types.cpp gen-cpp/proc_types.h
+    COMMAND ${THRIFT_COMPILER} --gen cpp:templates,cob_style ${CMAKE_CURRENT_SOURCE_DIR}/processor/proc.thrift
+)
diff --git a/lib/cpp/test/DebugProtoTest.cpp b/lib/cpp/test/DebugProtoTest.cpp
index 26cc1ea..060f354 100644
--- a/lib/cpp/test/DebugProtoTest.cpp
+++ b/lib/cpp/test/DebugProtoTest.cpp
@@ -17,89 +17,294 @@
  * under the License.
  */
 
-#include <iostream>
+#define _USE_MATH_DEFINES
 #include <cmath>
 #include "gen-cpp/DebugProtoTest_types.h"
 #include <thrift/protocol/TDebugProtocol.h>
+#include <memory>
 
-int main() {
-  using std::cout;
-  using std::endl;
-  using namespace thrift::test::debug;
+#define BOOST_TEST_MODULE DebugProtoTest
+#include <boost/test/unit_test.hpp>
 
+using namespace thrift::test::debug;
 
-  OneOfEach ooe;
-  ooe.im_true   = true;
-  ooe.im_false  = false;
-  ooe.a_bite    = 0x7f;
-  ooe.integer16 = 27000;
-  ooe.integer32 = 1<<24;
-  ooe.integer64 = (uint64_t)6000 * 1000 * 1000;
-  ooe.double_precision = M_PI;
-  ooe.some_characters  = "Debug THIS!";
-  ooe.zomg_unicode     = "\xd7\n\a\t";
+static ::std::shared_ptr<OneOfEach> ooe;
 
-  cout << apache::thrift::ThriftDebugString(ooe) << endl << endl;
+void testCaseSetup_1() {
+  ooe.reset(new OneOfEach);
+  ooe->im_true = true;
+  ooe->im_false = false;
+  ooe->a_bite = 0x7f;
+  ooe->integer16 = 27000;
+  ooe->integer32 = 1 << 24;
+  ooe->integer64 = (uint64_t)6000 * 1000 * 1000;
+  ooe->double_precision = M_PI;
+  ooe->some_characters = "Debug THIS!";
+  ooe->zomg_unicode = "\xd7\n\a\t";
+}
 
+BOOST_AUTO_TEST_CASE(test_debug_proto_1) {
+  testCaseSetup_1();
 
-  Nesting n;
-  n.my_ooe = ooe;
-  n.my_ooe.integer16 = 16;
-  n.my_ooe.integer32 = 32;
-  n.my_ooe.integer64 = 64;
-  n.my_ooe.double_precision = (std::sqrt(5.0)+1)/2;
-  n.my_ooe.some_characters  = ":R (me going \"rrrr\")";
-  n.my_ooe.zomg_unicode     = "\xd3\x80\xe2\x85\xae\xce\x9d\x20"
-                              "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"
-                              "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80\xbc";
-  n.my_bonk.type    = 31337;
-  n.my_bonk.message = "I am a bonk... xor!";
+  const std::string expected_result(
+    "OneOfEach {\n"
+    "  01: im_true (bool) = true,\n"
+    "  02: im_false (bool) = false,\n"
+    "  03: a_bite (byte) = 0x7f,\n"
+    "  04: integer16 (i16) = 27000,\n"
+    "  05: integer32 (i32) = 16777216,\n"
+    "  06: integer64 (i64) = 6000000000,\n"
+    "  07: double_precision (double) = 3.1415926535897931,\n"
+    "  08: some_characters (string) = \"Debug THIS!\",\n"
+    "  09: zomg_unicode (string) = \"\\xd7\\n\\a\\t\",\n"
+    "  10: what_who (bool) = false,\n"
+    "  11: base64 (string) = \"\",\n"
+    "  12: byte_list (list) = list<byte>[3] {\n"
+    "    [0] = 0x01,\n"
+    "    [1] = 0x02,\n"
+    "    [2] = 0x03,\n"
+    "  },\n"
+    "  13: i16_list (list) = list<i16>[3] {\n"
+    "    [0] = 1,\n"
+    "    [1] = 2,\n"
+    "    [2] = 3,\n"
+    "  },\n"
+    "  14: i64_list (list) = list<i64>[3] {\n"
+    "    [0] = 1,\n"
+    "    [1] = 2,\n"
+    "    [2] = 3,\n"
+    "  },\n"
+    "}");
+  const std::string result(apache::thrift::ThriftDebugString(*ooe));
 
-  cout << apache::thrift::ThriftDebugString(n) << endl << endl;
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
 
+static ::std::shared_ptr<Nesting> n;
 
-  HolyMoley hm;
+void testCaseSetup_2() {
+  testCaseSetup_1();
 
-  hm.big.push_back(ooe);
-  hm.big.push_back(n.my_ooe);
-  hm.big[0].a_bite = 0x22;
-  hm.big[1].a_bite = 0x33;
+  n.reset(new Nesting);
+  n->my_ooe = *ooe;
+  n->my_ooe.integer16 = 16;
+  n->my_ooe.integer32 = 32;
+  n->my_ooe.integer64 = 64;
+  n->my_ooe.double_precision = (std::sqrt(5.0) + 1) / 2;
+  n->my_ooe.some_characters = ":R (me going \"rrrr\")";
+  n->my_ooe.zomg_unicode     = "\xd3\x80\xe2\x85\xae\xce\x9d\x20\xd0\x9d\xce"
+                               "\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0"
+                               "\xb0\xcf\x81\xe2\x84\x8e\x20\xce\x91\x74\x74"
+                               "\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80"
+                               "\xbc";
+  n->my_bonk.type = 31337;
+  n->my_bonk.message = "I am a bonk... xor!";
+}
+
+BOOST_AUTO_TEST_CASE(test_debug_proto_2) {
+  testCaseSetup_2();
+
+  const std::string expected_result(
+    "Nesting {\n"
+    "  01: my_bonk (struct) = Bonk {\n"
+    "    01: type (i32) = 31337,\n"
+    "    02: message (string) = \"I am a bonk... xor!\",\n"
+    "  },\n"
+    "  02: my_ooe (struct) = OneOfEach {\n"
+    "    01: im_true (bool) = true,\n"
+    "    02: im_false (bool) = false,\n"
+    "    03: a_bite (byte) = 0x7f,\n"
+    "    04: integer16 (i16) = 16,\n"
+    "    05: integer32 (i32) = 32,\n"
+    "    06: integer64 (i64) = 64,\n"
+    "    07: double_precision (double) = 1.6180339887498949,\n"
+    "    08: some_characters (string) = \":R (me going \\\"rrrr\\\")\",\n"
+    "    09: zomg_unicode (string) = \"\\xd3\\x80\\xe2\\x85\\xae\\xce\\x9d \\xd"
+      "0\\x9d\\xce\\xbf\\xe2\\x85\\xbf\\xd0\\xbe\\xc9\\xa1\\xd0\\xb3\\xd0\\xb0"
+      "\\xcf\\x81\\xe2\\x84\\x8e \\xce\\x91tt\\xce\\xb1\\xe2\\x85\\xbd\\xce\\xb"
+      "a\\xc7\\x83\\xe2\\x80\\xbc\",\n"
+    "    10: what_who (bool) = false,\n"
+    "    11: base64 (string) = \"\",\n"
+    "    12: byte_list (list) = list<byte>[3] {\n"
+    "      [0] = 0x01,\n"
+    "      [1] = 0x02,\n"
+    "      [2] = 0x03,\n"
+    "    },\n"
+    "    13: i16_list (list) = list<i16>[3] {\n"
+    "      [0] = 1,\n"
+    "      [1] = 2,\n"
+    "      [2] = 3,\n"
+    "    },\n"
+    "    14: i64_list (list) = list<i64>[3] {\n"
+    "      [0] = 1,\n"
+    "      [1] = 2,\n"
+    "      [2] = 3,\n"
+    "    },\n"
+    "  },\n"
+    "}");
+  const std::string result(apache::thrift::ThriftDebugString(*n));
+
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
+
+static ::std::shared_ptr<HolyMoley> hm;
+
+void testCaseSetup_3() {
+  testCaseSetup_2();
+
+  hm.reset(new HolyMoley);
+
+  hm->big.push_back(*ooe);
+  hm->big.push_back(n->my_ooe);
+  hm->big[0].a_bite = 0x22;
+  hm->big[1].a_bite = 0x33;
 
   std::vector<std::string> stage1;
   stage1.push_back("and a one");
   stage1.push_back("and a two");
-  hm.contain.insert(stage1);
+  hm->contain.insert(stage1);
   stage1.clear();
   stage1.push_back("then a one, two");
   stage1.push_back("three!");
   stage1.push_back("FOUR!!");
-  hm.contain.insert(stage1);
+  hm->contain.insert(stage1);
   stage1.clear();
-  hm.contain.insert(stage1);
+  hm->contain.insert(stage1);
 
   std::vector<Bonk> stage2;
-  hm.bonks["nothing"] = stage2;
-  stage2.resize(stage2.size()+1);
+  hm->bonks["nothing"] = stage2;
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 1;
   stage2.back().message = "Wait.";
-  stage2.resize(stage2.size()+1);
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 2;
   stage2.back().message = "What?";
-  hm.bonks["something"] = stage2;
+  hm->bonks["something"] = stage2;
   stage2.clear();
-  stage2.resize(stage2.size()+1);
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 3;
   stage2.back().message = "quoth";
-  stage2.resize(stage2.size()+1);
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 4;
   stage2.back().message = "the raven";
-  stage2.resize(stage2.size()+1);
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 5;
   stage2.back().message = "nevermore";
-  hm.bonks["poe"] = stage2;
+  hm->bonks["poe"] = stage2;
+}
 
-  cout << apache::thrift::ThriftDebugString(hm) << endl << endl;
+BOOST_AUTO_TEST_CASE(test_debug_proto_3) {
+  testCaseSetup_3();
 
+  const std::string expected_result(
+    "HolyMoley {\n"
+    "  01: big (list) = list<struct>[2] {\n"
+    "    [0] = OneOfEach {\n"
+    "      01: im_true (bool) = true,\n"
+    "      02: im_false (bool) = false,\n"
+    "      03: a_bite (byte) = 0x22,\n"
+    "      04: integer16 (i16) = 27000,\n"
+    "      05: integer32 (i32) = 16777216,\n"
+    "      06: integer64 (i64) = 6000000000,\n"
+    "      07: double_precision (double) = 3.1415926535897931,\n"
+    "      08: some_characters (string) = \"Debug THIS!\",\n"
+    "      09: zomg_unicode (string) = \"\\xd7\\n\\a\\t\",\n"
+    "      10: what_who (bool) = false,\n"
+    "      11: base64 (string) = \"\",\n"
+    "      12: byte_list (list) = list<byte>[3] {\n"
+    "        [0] = 0x01,\n"
+    "        [1] = 0x02,\n"
+    "        [2] = 0x03,\n"
+    "      },\n"
+    "      13: i16_list (list) = list<i16>[3] {\n"
+    "        [0] = 1,\n"
+    "        [1] = 2,\n"
+    "        [2] = 3,\n"
+    "      },\n"
+    "      14: i64_list (list) = list<i64>[3] {\n"
+    "        [0] = 1,\n"
+    "        [1] = 2,\n"
+    "        [2] = 3,\n"
+    "      },\n"
+    "    },\n"
+    "    [1] = OneOfEach {\n"
+    "      01: im_true (bool) = true,\n"
+    "      02: im_false (bool) = false,\n"
+    "      03: a_bite (byte) = 0x33,\n"
+    "      04: integer16 (i16) = 16,\n"
+    "      05: integer32 (i32) = 32,\n"
+    "      06: integer64 (i64) = 64,\n"
+    "      07: double_precision (double) = 1.6180339887498949,\n"
+    "      08: some_characters (string) = \":R (me going \\\"rrrr\\\")\",\n"
+    "      09: zomg_unicode (string) = \"\\xd3\\x80\\xe2\\x85\\xae\\xce\\x9d \\"
+      "xd0\\x9d\\xce\\xbf\\xe2\\x85\\xbf\\xd0\\xbe\\xc9\\xa1\\xd0\\xb3\\xd0\\xb"
+      "0\\xcf\\x81\\xe2\\x84\\x8e \\xce\\x91tt\\xce\\xb1\\xe2\\x85\\xbd\\xce\\x"
+      "ba\\xc7\\x83\\xe2\\x80\\xbc\",\n"
+    "      10: what_who (bool) = false,\n"
+    "      11: base64 (string) = \"\",\n"
+    "      12: byte_list (list) = list<byte>[3] {\n"
+    "        [0] = 0x01,\n"
+    "        [1] = 0x02,\n"
+    "        [2] = 0x03,\n"
+    "      },\n"
+    "      13: i16_list (list) = list<i16>[3] {\n"
+    "        [0] = 1,\n"
+    "        [1] = 2,\n"
+    "        [2] = 3,\n"
+    "      },\n"
+    "      14: i64_list (list) = list<i64>[3] {\n"
+    "        [0] = 1,\n"
+    "        [1] = 2,\n"
+    "        [2] = 3,\n"
+    "      },\n"
+    "    },\n"
+    "  },\n"
+    "  02: contain (set) = set<list>[3] {\n"
+    "    list<string>[0] {\n"
+    "    },\n"
+    "    list<string>[2] {\n"
+    "      [0] = \"and a one\",\n"
+    "      [1] = \"and a two\",\n"
+    "    },\n"
+    "    list<string>[3] {\n"
+    "      [0] = \"then a one, two\",\n"
+    "      [1] = \"three!\",\n"
+    "      [2] = \"FOUR!!\",\n"
+    "    },\n"
+    "  },\n"
+    "  03: bonks (map) = map<string,list>[3] {\n"
+    "    \"nothing\" -> list<struct>[0] {\n"
+    "    },\n"
+    "    \"poe\" -> list<struct>[3] {\n"
+    "      [0] = Bonk {\n"
+    "        01: type (i32) = 3,\n"
+    "        02: message (string) = \"quoth\",\n"
+    "      },\n"
+    "      [1] = Bonk {\n"
+    "        01: type (i32) = 4,\n"
+    "        02: message (string) = \"the raven\",\n"
+    "      },\n"
+    "      [2] = Bonk {\n"
+    "        01: type (i32) = 5,\n"
+    "        02: message (string) = \"nevermore\",\n"
+    "      },\n"
+    "    },\n"
+    "    \"something\" -> list<struct>[2] {\n"
+    "      [0] = Bonk {\n"
+    "        01: type (i32) = 1,\n"
+    "        02: message (string) = \"Wait.\",\n"
+    "      },\n"
+    "      [1] = Bonk {\n"
+    "        01: type (i32) = 2,\n"
+    "        02: message (string) = \"What?\",\n"
+    "      },\n"
+    "    },\n"
+    "  },\n"
+    "}");
+  const std::string result(apache::thrift::ThriftDebugString(*hm));
 
-  return 0;
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
 }
diff --git a/lib/cpp/test/DebugProtoTest_extras.cpp b/lib/cpp/test/DebugProtoTest_extras.cpp
index c89db74..5c4fd35 100644
--- a/lib/cpp/test/DebugProtoTest_extras.cpp
+++ b/lib/cpp/test/DebugProtoTest_extras.cpp
@@ -21,13 +21,15 @@
 
 #include "gen-cpp/DebugProtoTest_types.h"
 
-
-namespace thrift { namespace test { namespace debug {
+namespace thrift {
+namespace test {
+namespace debug {
 
 bool Empty::operator<(Empty const& other) const {
-  (void) other;
+  (void)other;
   // It is empty, so all are equal.
   return false;
 }
-
-}}}
+}
+}
+}
diff --git a/lib/cpp/test/DenseProtoTest.cpp b/lib/cpp/test/DenseProtoTest.cpp
deleted file mode 100644
index f73579f..0000000
--- a/lib/cpp/test/DenseProtoTest.cpp
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*
-../compiler/cpp/thrift --gen cpp:dense DebugProtoTest.thrift
-../compiler/cpp/thrift --gen cpp:dense OptionalRequiredTest.thrift
-g++ -Wall -g -I../lib/cpp/src -I/usr/local/include/boost-1_33_1 \
-  gen-cpp/OptionalRequiredTest_types.cpp \
-  gen-cpp/DebugProtoTest_types.cpp \
-  DenseProtoTest.cpp ../lib/cpp/.libs/libthrift.a -o DenseProtoTest
-./DenseProtoTest
-*/
-
-// I do this to reach into the guts of TDenseProtocol.  Sorry.
-#define private public
-#define inline
-
-#undef NDEBUG
-#include <cstdlib>
-#include <cassert>
-#include <iostream>
-#include <cmath>
-#include <string>
-#include "gen-cpp/DebugProtoTest_types.h"
-#include "gen-cpp/OptionalRequiredTest_types.h"
-#include <thrift/protocol/TDenseProtocol.h>
-#include <thrift/transport/TBufferTransports.h>
-
-
-// Can't use memcmp here.  GCC is too smart.
-bool my_memeq(const char* str1, const char* str2, int len) {
-  for (int i = 0; i < len; i++) {
-    if (str1[i] != str2[i]) {
-      return false;
-    }
-  }
-  return true;
-}
-
-
-int main() {
-  using std::string;
-  using std::cout;
-  using std::endl;
-  using boost::shared_ptr;
-  using namespace thrift::test::debug;
-  using namespace apache::thrift::transport;
-  using namespace apache::thrift::protocol;
-
-
-  OneOfEach ooe;
-  ooe.im_true   = true;
-  ooe.im_false  = false;
-  ooe.a_bite    = 0xd6;
-  ooe.integer16 = 27000;
-  ooe.integer32 = 1<<24;
-  ooe.integer64 = (uint64_t)6000 * 1000 * 1000;
-  ooe.double_precision = M_PI;
-  ooe.some_characters  = "Debug THIS!";
-  ooe.zomg_unicode     = "\xd7\n\a\t";
-
-  //cout << apache::thrift::ThriftDebugString(ooe) << endl << endl;
-
-
-  Nesting n;
-  n.my_ooe = ooe;
-  n.my_ooe.integer16 = 16;
-  n.my_ooe.integer32 = 32;
-  n.my_ooe.integer64 = 64;
-  n.my_ooe.double_precision = (std::sqrt(5)+1)/2;
-  n.my_ooe.some_characters  = ":R (me going \"rrrr\")";
-  n.my_ooe.zomg_unicode     = "\xd3\x80\xe2\x85\xae\xce\x9d\x20"
-                              "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"
-                              "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80\xbc";
-  n.my_bonk.type    = 31337;
-  n.my_bonk.message = "I am a bonk... xor!";
-
-  //cout << apache::thrift::ThriftDebugString(n) << endl << endl;
-
-
-  HolyMoley hm;
-
-  hm.big.push_back(ooe);
-  hm.big.push_back(n.my_ooe);
-  hm.big[0].a_bite = 0x22;
-  hm.big[1].a_bite = 0x33;
-
-  std::vector<std::string> stage1;
-  stage1.push_back("and a one");
-  stage1.push_back("and a two");
-  hm.contain.insert(stage1);
-  stage1.clear();
-  stage1.push_back("then a one, two");
-  stage1.push_back("three!");
-  stage1.push_back("FOUR!!");
-  hm.contain.insert(stage1);
-  stage1.clear();
-  hm.contain.insert(stage1);
-
-  std::vector<Bonk> stage2;
-  hm.bonks["nothing"] = stage2;
-  stage2.resize(stage2.size()+1);
-  stage2.back().type = 1;
-  stage2.back().message = "Wait.";
-  stage2.resize(stage2.size()+1);
-  stage2.back().type = 2;
-  stage2.back().message = "What?";
-  hm.bonks["something"] = stage2;
-  stage2.clear();
-  stage2.resize(stage2.size()+1);
-  stage2.back().type = 3;
-  stage2.back().message = "quoth";
-  stage2.resize(stage2.size()+1);
-  stage2.back().type = 4;
-  stage2.back().message = "the raven";
-  stage2.resize(stage2.size()+1);
-  stage2.back().type = 5;
-  stage2.back().message = "nevermore";
-  hm.bonks["poe"] = stage2;
-
-  //cout << apache::thrift::ThriftDebugString(hm) << endl << endl;
-
-  shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer());
-  shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer));
-  proto->setTypeSpec(HolyMoley::local_reflection);
-
-  hm.write(proto.get());
-  HolyMoley hm2;
-  hm2.read(proto.get());
-
-  assert(hm == hm2);
-
-
-  // Let's test out the variable-length ints, shall we?
-  uint64_t vlq;
-  #define checkout(i, c) { \
-    buffer->resetBuffer(); \
-    proto->vlqWrite(i); \
-    proto->getTransport()->flush(); \
-    assert(my_memeq(buffer->getBufferAsString().data(), c, sizeof(c)-1)); \
-    proto->vlqRead(vlq); \
-    assert(vlq == i); \
-  }
-
-  checkout(0x00000000, "\x00");
-  checkout(0x00000040, "\x40");
-  checkout(0x0000007F, "\x7F");
-  checkout(0x00000080, "\x81\x00");
-  checkout(0x00002000, "\xC0\x00");
-  checkout(0x00003FFF, "\xFF\x7F");
-  checkout(0x00004000, "\x81\x80\x00");
-  checkout(0x00100000, "\xC0\x80\x00");
-  checkout(0x001FFFFF, "\xFF\xFF\x7F");
-  checkout(0x00200000, "\x81\x80\x80\x00");
-  checkout(0x08000000, "\xC0\x80\x80\x00");
-  checkout(0x0FFFFFFF, "\xFF\xFF\xFF\x7F");
-  checkout(0x10000000, "\x81\x80\x80\x80\x00");
-  checkout(0x20000000, "\x82\x80\x80\x80\x00");
-  checkout(0x1FFFFFFF, "\x81\xFF\xFF\xFF\x7F");
-  checkout(0xFFFFFFFF, "\x8F\xFF\xFF\xFF\x7F");
-
-  checkout(0x0000000100000000ull, "\x90\x80\x80\x80\x00");
-  checkout(0x0000000200000000ull, "\xA0\x80\x80\x80\x00");
-  checkout(0x0000000300000000ull, "\xB0\x80\x80\x80\x00");
-  checkout(0x0000000700000000ull, "\xF0\x80\x80\x80\x00");
-  checkout(0x00000007F0000000ull, "\xFF\x80\x80\x80\x00");
-  checkout(0x00000007FFFFFFFFull, "\xFF\xFF\xFF\xFF\x7F");
-  checkout(0x0000000800000000ull, "\x81\x80\x80\x80\x80\x00");
-  checkout(0x1FFFFFFFFFFFFFFFull, "\x9F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F");
-  checkout(0x7FFFFFFFFFFFFFFFull, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F");
-  checkout(0xFFFFFFFFFFFFFFFFull, "\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F");
-
-  // Test out the slow path with a TBufferedTransport.
-  shared_ptr<TBufferedTransport> buff_trans(new TBufferedTransport(buffer, 3));
-  proto.reset(new TDenseProtocol(buff_trans));
-  checkout(0x0000000100000000ull, "\x90\x80\x80\x80\x00");
-  checkout(0x0000000200000000ull, "\xA0\x80\x80\x80\x00");
-  checkout(0x0000000300000000ull, "\xB0\x80\x80\x80\x00");
-  checkout(0x0000000700000000ull, "\xF0\x80\x80\x80\x00");
-  checkout(0x00000007F0000000ull, "\xFF\x80\x80\x80\x00");
-  checkout(0x00000007FFFFFFFFull, "\xFF\xFF\xFF\xFF\x7F");
-  checkout(0x0000000800000000ull, "\x81\x80\x80\x80\x80\x00");
-  checkout(0x1FFFFFFFFFFFFFFFull, "\x9F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F");
-  checkout(0x7FFFFFFFFFFFFFFFull, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F");
-  checkout(0xFFFFFFFFFFFFFFFFull, "\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F");
-
-  // Test optional stuff.
-  proto.reset(new TDenseProtocol(buffer));
-  proto->setTypeSpec(ManyOpt::local_reflection);
-  ManyOpt mo1, mo2, mo3, mo4, mo5, mo6;
-  mo1.opt1 = 923759347;
-  mo1.opt2 = 392749274;
-  mo1.opt3 = 395739402;
-  mo1.def4 = 294730928;
-  mo1.opt5 = 394309218;
-  mo1.opt6 = 832194723;
-  mo1.__isset.opt1 = true;
-  mo1.__isset.opt2 = true;
-  mo1.__isset.opt3 = true;
-  mo1.__isset.def4 = true;
-  mo1.__isset.opt5 = true;
-  mo1.__isset.opt6 = true;
-
-  mo1.write(proto.get());
-  mo2.read(proto.get());
-
-  assert(mo2.__isset.opt1 == true);
-  assert(mo2.__isset.opt2 == true);
-  assert(mo2.__isset.opt3 == true);
-  assert(mo2.__isset.def4 == true);
-  assert(mo2.__isset.opt5 == true);
-  assert(mo2.__isset.opt6 == true);
-
-  assert(mo1 == mo2);
-
-  mo1.__isset.opt1 = false;
-  mo1.__isset.opt3 = false;
-  mo1.__isset.opt5 = false;
-
-  mo1.write(proto.get());
-  mo3.read(proto.get());
-
-  assert(mo3.__isset.opt1 == false);
-  assert(mo3.__isset.opt2 == true);
-  assert(mo3.__isset.opt3 == false);
-  assert(mo3.__isset.def4 == true);
-  assert(mo3.__isset.opt5 == false);
-  assert(mo3.__isset.opt6 == true);
-
-  assert(mo1 == mo3);
-
-  mo1.__isset.opt1 = true;
-  mo1.__isset.opt3 = true;
-  mo1.__isset.opt5 = true;
-  mo1.__isset.opt2 = false;
-  mo1.__isset.opt6 = false;
-
-  mo1.write(proto.get());
-  mo4.read(proto.get());
-
-  assert(mo4.__isset.opt1 == true);
-  assert(mo4.__isset.opt2 == false);
-  assert(mo4.__isset.opt3 == true);
-  assert(mo4.__isset.def4 == true);
-  assert(mo4.__isset.opt5 == true);
-  assert(mo4.__isset.opt6 == false);
-
-  assert(mo1 == mo4);
-
-  mo1.__isset.opt1 = false;
-  mo1.__isset.opt5 = false;
-
-  mo1.write(proto.get());
-  mo5.read(proto.get());
-
-  assert(mo5.__isset.opt1 == false);
-  assert(mo5.__isset.opt2 == false);
-  assert(mo5.__isset.opt3 == true);
-  assert(mo5.__isset.def4 == true);
-  assert(mo5.__isset.opt5 == false);
-  assert(mo5.__isset.opt6 == false);
-
-  assert(mo1 == mo5);
-
-  mo1.__isset.opt3 = false;
-
-  mo1.write(proto.get());
-  mo6.read(proto.get());
-
-  assert(mo6.__isset.opt1 == false);
-  assert(mo6.__isset.opt2 == false);
-  assert(mo6.__isset.opt3 == false);
-  assert(mo6.__isset.def4 == true);
-  assert(mo6.__isset.opt5 == false);
-  assert(mo6.__isset.opt6 == false);
-
-  assert(mo1 == mo6);
-
-
-  // Test fingerprint checking stuff.
-
-  {
-    // Default and required have the same fingerprint.
-    Tricky1 t1;
-    Tricky3 t3;
-    assert(string(Tricky1::ascii_fingerprint) == Tricky3::ascii_fingerprint);
-    proto->setTypeSpec(Tricky1::local_reflection);
-    t1.im_default = 227;
-    t1.write(proto.get());
-    proto->setTypeSpec(Tricky3::local_reflection);
-    t3.read(proto.get());
-    assert(t3.im_required == 227);
-  }
-
-  {
-    // Optional changes things.
-    Tricky1 t1;
-    Tricky2 t2;
-    assert(string(Tricky1::ascii_fingerprint) != Tricky2::ascii_fingerprint);
-    proto->setTypeSpec(Tricky1::local_reflection);
-    t1.im_default = 227;
-    t1.write(proto.get());
-    try {
-      proto->setTypeSpec(Tricky2::local_reflection);
-      t2.read(proto.get());
-      assert(false);
-    } catch (TProtocolException& ex) {
-      buffer->resetBuffer();
-    }
-  }
-
-  {
-    // Holy cow.  We can use the Tricky1 typespec with the Tricky2 structure.
-    Tricky1 t1;
-    Tricky2 t2;
-    proto->setTypeSpec(Tricky1::local_reflection);
-    t1.im_default = 227;
-    t1.write(proto.get());
-    t2.read(proto.get());
-    assert(t2.__isset.im_optional == true);
-    assert(t2.im_optional == 227);
-  }
-
-  {
-    // And totally off the wall.
-    Tricky1 t1;
-    OneOfEach ooe2;
-    assert(string(Tricky1::ascii_fingerprint) != OneOfEach::ascii_fingerprint);
-    proto->setTypeSpec(Tricky1::local_reflection);
-    t1.im_default = 227;
-    t1.write(proto.get());
-    try {
-      proto->setTypeSpec(OneOfEach::local_reflection);
-      ooe2.read(proto.get());
-      assert(false);
-    } catch (TProtocolException& ex) {
-      buffer->resetBuffer();
-    }
-  }
-
-  // Okay, this is really off the wall.
-  // Just don't crash.
-  cout << "Starting fuzz test.  This takes a while.  (20 dots.)" << endl;
-  std::srand(12345);
-  for (int i = 0; i < 2000; i++) {
-    if (i % 100 == 0) {
-      cout << ".";
-      cout.flush();
-    }
-    buffer->resetBuffer();
-    // Make sure the fingerprint prefix is right.
-    buffer->write(Nesting::binary_fingerprint, 4);
-    for (int j = 0; j < 1024*1024; j++) {
-      uint8_t r = std::rand();
-      buffer->write(&r, 1);
-    }
-    Nesting n;
-    proto->setTypeSpec(OneOfEach::local_reflection);
-    try {
-      n.read(proto.get());
-    } catch (TProtocolException& ex) {
-    } catch (TTransportException& ex) {
-    }
-  }
-  cout << endl;
-
-  return 0;
-}
diff --git a/lib/cpp/test/EnumTest.cpp b/lib/cpp/test/EnumTest.cpp
new file mode 100644
index 0000000..c935bc4
--- /dev/null
+++ b/lib/cpp/test/EnumTest.cpp
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#define BOOST_TEST_MODULE EnumTest
+#include <boost/test/unit_test.hpp>
+#include "gen-cpp/EnumTest_types.h"
+
+std::ostream& operator <<(std::ostream& os, const MyEnumWithCustomOstream::type& val)
+{
+  os << "{" << (int)val << ":CUSTOM!" << "}";
+  return os;
+}
+
+BOOST_AUTO_TEST_SUITE(EnumTest)
+
+BOOST_AUTO_TEST_CASE(test_enum_value) {
+  // Check that all the enum values match what we expect
+  BOOST_CHECK_EQUAL(MyEnum1::ME1_0, 0);
+  BOOST_CHECK_EQUAL(MyEnum1::ME1_1, 1);
+  BOOST_CHECK_EQUAL(MyEnum1::ME1_2, 2);
+  BOOST_CHECK_EQUAL(MyEnum1::ME1_3, 3);
+  BOOST_CHECK_EQUAL(MyEnum1::ME1_5, 5);
+  BOOST_CHECK_EQUAL(MyEnum1::ME1_6, 6);
+
+  BOOST_CHECK_EQUAL(MyEnum2::ME2_0, 0);
+  BOOST_CHECK_EQUAL(MyEnum2::ME2_1, 1);
+  BOOST_CHECK_EQUAL(MyEnum2::ME2_2, 2);
+
+  BOOST_CHECK_EQUAL(MyEnum3::ME3_0, 0);
+  BOOST_CHECK_EQUAL(MyEnum3::ME3_1, 1);
+  BOOST_CHECK_EQUAL(MyEnum3::ME3_N2, -2);
+  BOOST_CHECK_EQUAL(MyEnum3::ME3_N1, -1);
+  BOOST_CHECK_EQUAL(MyEnum3::ME3_D0, 0);
+  BOOST_CHECK_EQUAL(MyEnum3::ME3_D1, 1);
+  BOOST_CHECK_EQUAL(MyEnum3::ME3_9, 9);
+  BOOST_CHECK_EQUAL(MyEnum3::ME3_10, 10);
+
+  BOOST_CHECK_EQUAL(MyEnum4::ME4_A, 0x7ffffffd);
+  BOOST_CHECK_EQUAL(MyEnum4::ME4_B, 0x7ffffffe);
+  BOOST_CHECK_EQUAL(MyEnum4::ME4_C, 0x7fffffff);
+
+  BOOST_CHECK_EQUAL(MyEnum5::e1, 0);
+  BOOST_CHECK_EQUAL(MyEnum5::e2, 42);
+}
+
+template <class _T>
+std::string EnumToString(_T e)
+{
+  std::stringstream ss;
+  ss << e;
+  return ss.str();
+}
+
+
+BOOST_AUTO_TEST_CASE(test_enum_ostream)
+{
+  BOOST_CHECK_EQUAL(EnumToString(MyEnum1::ME1_0), "ME1_0");
+  BOOST_CHECK_EQUAL(EnumToString(MyEnum5::e2), "e2");
+  BOOST_CHECK_EQUAL(EnumToString(MyEnum3::ME3_N1), "ME3_N1");
+  BOOST_CHECK_EQUAL(EnumToString(MyEnumWithCustomOstream::CustoM2), "{2:CUSTOM!}");
+
+  // some invalid or unknown value
+  MyEnum5::type uut = (MyEnum5::type)44;
+  BOOST_CHECK_EQUAL(EnumToString(uut), "44");
+}
+
+BOOST_AUTO_TEST_CASE(test_enum_constant)
+{
+  MyStruct ms;
+  BOOST_CHECK_EQUAL(ms.me2_2, 2);
+  BOOST_CHECK_EQUAL(ms.me3_n2, -2);
+  BOOST_CHECK_EQUAL(ms.me3_d1, 1);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/GenericHelpers.h b/lib/cpp/test/GenericHelpers.h
index 1853a37..bcef9f2 100644
--- a/lib/cpp/test/GenericHelpers.h
+++ b/lib/cpp/test/GenericHelpers.h
@@ -20,83 +20,88 @@
 #ifndef _THRIFT_TEST_GENERICHELPERS_H_
 #define _THRIFT_TEST_GENERICHELPERS_H_ 1
 
-#include <thrift/protocol/TBinaryProtocol.h>
-#include <thrift/transport/TBufferTransports.h>
+#include <thrift/protocol/TProtocol.h>
+#include <memory>
 #include <thrift/Thrift.h>
 
-using boost::shared_ptr;
-using namespace apache::thrift::protocol;
-
 /* ClassName Helper for cleaner exceptions */
 class ClassNames {
- public:
+public:
   template <typename T>
-  static const char* getName() { return "Unknown type"; }
+  static const char* getName() {
+    return "Unknown type";
+  }
 };
 
-template <> const char* ClassNames::getName<int8_t>() { return "byte"; }
-template <> const char* ClassNames::getName<int16_t>() { return "short"; }
-template <> const char* ClassNames::getName<int32_t>() { return "int"; }
-template <> const char* ClassNames::getName<int64_t>() { return "long"; }
-template <> const char* ClassNames::getName<double>() { return "double"; }
-template <> const char* ClassNames::getName<std::string>() { return "string"; }
+template <>
+const char* ClassNames::getName<int8_t>() {
+  return "byte";
+}
+template <>
+const char* ClassNames::getName<int16_t>() {
+  return "short";
+}
+template <>
+const char* ClassNames::getName<int32_t>() {
+  return "int";
+}
+template <>
+const char* ClassNames::getName<int64_t>() {
+  return "long";
+}
+template <>
+const char* ClassNames::getName<double>() {
+  return "double";
+}
+template <>
+const char* ClassNames::getName<std::string>() {
+  return "string";
+}
 
 /* Generic Protocol I/O function for tests */
 class GenericIO {
- public:
-
+public:
   /* Write functions */
 
-  static uint32_t write(shared_ptr<TProtocol> proto, const int8_t& val) {
+  static uint32_t write(std::shared_ptr<apache::thrift::protocol::TProtocol> proto, const int8_t& val) {
     return proto->writeByte(val);
   }
 
-  static uint32_t write(shared_ptr<TProtocol> proto, const int16_t& val) {
+  static uint32_t write(std::shared_ptr<apache::thrift::protocol::TProtocol> proto, const int16_t& val) {
     return proto->writeI16(val);
   }
 
-  static uint32_t write(shared_ptr<TProtocol> proto, const int32_t& val) {
+  static uint32_t write(std::shared_ptr<apache::thrift::protocol::TProtocol> proto, const int32_t& val) {
     return proto->writeI32(val);
   }
 
-  static uint32_t write(shared_ptr<TProtocol> proto, const double& val) {
+  static uint32_t write(std::shared_ptr<apache::thrift::protocol::TProtocol> proto, const double& val) {
     return proto->writeDouble(val);
   }
 
-  static uint32_t write(shared_ptr<TProtocol> proto, const int64_t& val) {
+  static uint32_t write(std::shared_ptr<apache::thrift::protocol::TProtocol> proto, const int64_t& val) {
     return proto->writeI64(val);
   }
 
-  static uint32_t write(shared_ptr<TProtocol> proto, const std::string& val) {
+  static uint32_t write(std::shared_ptr<apache::thrift::protocol::TProtocol> proto, const std::string& val) {
     return proto->writeString(val);
   }
 
   /* Read functions */
 
-  static uint32_t read(shared_ptr<TProtocol> proto, int8_t& val) {
-    return proto->readByte(val);
-  }
+  static uint32_t read(std::shared_ptr<apache::thrift::protocol::TProtocol> proto, int8_t& val) { return proto->readByte(val); }
 
-  static uint32_t read(shared_ptr<TProtocol> proto, int16_t& val) {
-    return proto->readI16(val);
-  }
+  static uint32_t read(std::shared_ptr<apache::thrift::protocol::TProtocol> proto, int16_t& val) { return proto->readI16(val); }
 
-  static uint32_t read(shared_ptr<TProtocol> proto, int32_t& val) {
-    return proto->readI32(val);
-  }
+  static uint32_t read(std::shared_ptr<apache::thrift::protocol::TProtocol> proto, int32_t& val) { return proto->readI32(val); }
 
-  static uint32_t read(shared_ptr<TProtocol> proto, int64_t& val) {
-    return proto->readI64(val);
-  }
+  static uint32_t read(std::shared_ptr<apache::thrift::protocol::TProtocol> proto, int64_t& val) { return proto->readI64(val); }
 
-  static uint32_t read(shared_ptr<TProtocol> proto, double& val) {
-    return proto->readDouble(val);
-  }
+  static uint32_t read(std::shared_ptr<apache::thrift::protocol::TProtocol> proto, double& val) { return proto->readDouble(val); }
 
-  static uint32_t read(shared_ptr<TProtocol> proto, std::string& val) {
+  static uint32_t read(std::shared_ptr<apache::thrift::protocol::TProtocol> proto, std::string& val) {
     return proto->readString(val);
   }
-
 };
 
 #endif
diff --git a/lib/cpp/test/JSONProtoTest.cpp b/lib/cpp/test/JSONProtoTest.cpp
index dcb34d1..c2ad73e 100644
--- a/lib/cpp/test/JSONProtoTest.cpp
+++ b/lib/cpp/test/JSONProtoTest.cpp
@@ -17,128 +17,227 @@
  * under the License.
  */
 
-#include <iostream>
+#define _USE_MATH_DEFINES
 #include <cmath>
-#include <thrift/transport/TBufferTransports.h>
+#include <iomanip>
+#include <sstream>
 #include <thrift/protocol/TJSONProtocol.h>
+#include <memory>
+#include <thrift/transport/TBufferTransports.h>
 #include "gen-cpp/DebugProtoTest_types.h"
 
-int main() {
-  using std::cout;
-  using std::endl;
-  using namespace thrift::test::debug;
-  using apache::thrift::transport::TMemoryBuffer;
-  using apache::thrift::protocol::TJSONProtocol;
+#define BOOST_TEST_MODULE JSONProtoTest
+#include <boost/test/unit_test.hpp>
 
-  OneOfEach ooe;
-  ooe.im_true   = true;
-  ooe.im_false  = false;
-  ooe.a_bite    = 0x7f;
-  ooe.integer16 = 27000;
-  ooe.integer32 = 1<<24;
-  ooe.integer64 = (uint64_t)6000 * 1000 * 1000;
-  ooe.double_precision = M_PI;
-  ooe.some_characters  = "JSON THIS! \"\1";
-  ooe.zomg_unicode     = "\xd7\n\a\t";
-  ooe.base64 = "\1\2\3\255";
-  cout << apache::thrift::ThriftJSONString(ooe) << endl << endl;
+using namespace thrift::test::debug;
+using namespace apache::thrift;
+using apache::thrift::transport::TMemoryBuffer;
+using apache::thrift::protocol::TJSONProtocol;
 
+static std::shared_ptr<OneOfEach> ooe;
 
-  Nesting n;
-  n.my_ooe = ooe;
-  n.my_ooe.integer16 = 16;
-  n.my_ooe.integer32 = 32;
-  n.my_ooe.integer64 = 64;
-  n.my_ooe.double_precision = (std::sqrt(5.0)+1)/2;
-  n.my_ooe.some_characters  = ":R (me going \"rrrr\")";
-  n.my_ooe.zomg_unicode     = "\xd3\x80\xe2\x85\xae\xce\x9d\x20"
-                              "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"
-                              "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80\xbc";
-  n.my_bonk.type    = 31337;
-  n.my_bonk.message = "I am a bonk... xor!";
+void testCaseSetup_1() {
+  ooe.reset(new OneOfEach);
+  ooe->im_true = true;
+  ooe->im_false = false;
+  ooe->a_bite = 0x7f;
+  ooe->integer16 = 27000;
+  ooe->integer32 = 1 << 24;
+  ooe->integer64 = (uint64_t)6000 * 1000 * 1000;
+  ooe->double_precision = M_PI;
+  ooe->some_characters = "JSON THIS! \"\1";
+  ooe->zomg_unicode = "\xd7\n\a\t";
+  ooe->base64 = "\1\2\3\255";
+}
 
-  cout << apache::thrift::ThriftJSONString(n) << endl << endl;
+BOOST_AUTO_TEST_CASE(test_json_proto_1) {
+  testCaseSetup_1();
 
+  const std::string expected_result(
+  "{\"1\":{\"tf\":1},\"2\":{\"tf\":0},\"3\":{\"i8\":127},\"4\":{\"i16\":27000},"
+  "\"5\":{\"i32\":16777216},\"6\":{\"i64\":6000000000},\"7\":{\"dbl\":3.1415926"
+  "535897931},\"8\":{\"str\":\"JSON THIS! \\\"\\u0001\"},\"9\":{\"str\":\"\xd7\\"
+  "n\\u0007\\t\"},\"10\":{\"tf\":0},\"11\":{\"str\":\"AQIDrQ\"},\"12\":{\"lst\""
+  ":[\"i8\",3,1,2,3]},\"13\":{\"lst\":[\"i16\",3,1,2,3]},\"14\":{\"lst\":[\"i64"
+  "\",3,1,2,3]}}");
 
-  HolyMoley hm;
+  const std::string result(apache::thrift::ThriftJSONString(*ooe));
 
-  hm.big.push_back(ooe);
-  hm.big.push_back(n.my_ooe);
-  hm.big[0].a_bite = 0x22;
-  hm.big[1].a_bite = 0x33;
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
+
+static std::shared_ptr<Nesting> n;
+
+void testCaseSetup_2() {
+  testCaseSetup_1();
+
+  n.reset(new Nesting);
+  n->my_ooe = *ooe;
+  n->my_ooe.integer16 = 16;
+  n->my_ooe.integer32 = 32;
+  n->my_ooe.integer64 = 64;
+  n->my_ooe.double_precision = (std::sqrt(5.0) + 1) / 2;
+  n->my_ooe.some_characters = ":R (me going \"rrrr\")";
+  n->my_ooe.zomg_unicode     = "\xd3\x80\xe2\x85\xae\xce\x9d\x20\xd0\x9d\xce"
+                               "\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0"
+                               "\xb0\xcf\x81\xe2\x84\x8e\x20\xce\x91\x74\x74"
+                               "\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80"
+                               "\xbc";
+  n->my_bonk.type = 31337;
+  n->my_bonk.message = "I am a bonk... xor!";
+}
+
+BOOST_AUTO_TEST_CASE(test_json_proto_2) {
+  testCaseSetup_2();
+
+  const std::string expected_result(
+    "{\"1\":{\"rec\":{\"1\":{\"i32\":31337},\"2\":{\"str\":\"I am a bonk... xor"
+    "!\"}}},\"2\":{\"rec\":{\"1\":{\"tf\":1},\"2\":{\"tf\":0},\"3\":{\"i8\":127"
+    "},\"4\":{\"i16\":16},\"5\":{\"i32\":32},\"6\":{\"i64\":64},\"7\":{\"dbl\":"
+    "1.6180339887498949},\"8\":{\"str\":\":R (me going \\\"rrrr\\\")\"},\"9\":{"
+    "\"str\":\"ӀⅮΝ Нοⅿоɡгаρℎ Αttαⅽκǃ‼\"},\"10\":{\"tf\":0},\"11\":{\"str\":\""
+    "AQIDrQ\"},\"12\":{\"lst\":[\"i8\",3,1,2,3]},\"13\":{\"lst\":[\"i16\",3,1,2"
+    ",3]},\"14\":{\"lst\":[\"i64\",3,1,2,3]}}}}"
+  );
+
+  const std::string result(apache::thrift::ThriftJSONString(*n));
+
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
+
+static std::shared_ptr<HolyMoley> hm;
+
+void testCaseSetup_3() {
+  testCaseSetup_2();
+
+  hm.reset(new HolyMoley);
+
+  hm->big.push_back(*ooe);
+  hm->big.push_back(n->my_ooe);
+  hm->big[0].a_bite = 0x22;
+  hm->big[1].a_bite = 0x33;
 
   std::vector<std::string> stage1;
   stage1.push_back("and a one");
   stage1.push_back("and a two");
-  hm.contain.insert(stage1);
+  hm->contain.insert(stage1);
   stage1.clear();
   stage1.push_back("then a one, two");
   stage1.push_back("three!");
   stage1.push_back("FOUR!!");
-  hm.contain.insert(stage1);
+  hm->contain.insert(stage1);
   stage1.clear();
-  hm.contain.insert(stage1);
+  hm->contain.insert(stage1);
 
   std::vector<Bonk> stage2;
-  hm.bonks["nothing"] = stage2;
-  stage2.resize(stage2.size()+1);
+  hm->bonks["nothing"] = stage2;
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 1;
   stage2.back().message = "Wait.";
-  stage2.resize(stage2.size()+1);
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 2;
   stage2.back().message = "What?";
-  hm.bonks["something"] = stage2;
+  hm->bonks["something"] = stage2;
   stage2.clear();
-  stage2.resize(stage2.size()+1);
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 3;
   stage2.back().message = "quoth";
-  stage2.resize(stage2.size()+1);
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 4;
   stage2.back().message = "the raven";
-  stage2.resize(stage2.size()+1);
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 5;
   stage2.back().message = "nevermore";
-  hm.bonks["poe"] = stage2;
+  hm->bonks["poe"] = stage2;
+}
 
-  cout << apache::thrift::ThriftJSONString(hm) << endl << endl;
+BOOST_AUTO_TEST_CASE(test_json_proto_3) {
+  testCaseSetup_3();
 
-  boost::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer());
-  boost::shared_ptr<TJSONProtocol> proto(new TJSONProtocol(buffer));
+  const std::string expected_result(
+  "{\"1\":{\"lst\":[\"rec\",2,{\"1\":{\"tf\":1},\"2\":{\"tf\":0},\"3\":{\"i8\":"
+  "34},\"4\":{\"i16\":27000},\"5\":{\"i32\":16777216},\"6\":{\"i64\":6000000000"
+  "},\"7\":{\"dbl\":3.1415926535897931},\"8\":{\"str\":\"JSON THIS! \\\"\\u0001"
+  "\"},\"9\":{\"str\":\"\xd7\\n\\u0007\\t\"},\"10\":{\"tf\":0},\"11\":{\"str\":"
+  "\"AQIDrQ\"},\"12\":{\"lst\":[\"i8\",3,1,2,3]},\"13\":{\"lst\":[\"i16\",3,1,2"
+  ",3]},\"14\":{\"lst\":[\"i64\",3,1,2,3]}},{\"1\":{\"tf\":1},\"2\":{\"tf\":0},"
+  "\"3\":{\"i8\":51},\"4\":{\"i16\":16},\"5\":{\"i32\":32},\"6\":{\"i64\":64},"
+  "\"7\":{\"dbl\":1.6180339887498949},\"8\":{\"str\":\":R (me going \\\"rrrr\\\""
+  ")\"},\"9\":{\"str\":\"ӀⅮΝ Нοⅿоɡгаρℎ Αttαⅽκǃ‼\"},\"10\":{\"tf\":0},\"11\":{"
+  "\"str\":\"AQIDrQ\"},\"12\":{\"lst\":[\"i8\",3,1,2,3]},\"13\":{\"lst\":[\"i16"
+  "\",3,1,2,3]},\"14\":{\"lst\":[\"i64\",3,1,2,3]}}]},\"2\":{\"set\":[\"lst\",3"
+  ",[\"str\",0],[\"str\",2,\"and a one\",\"and a two\"],[\"str\",3,\"then a one"
+  ", two\",\"three!\",\"FOUR!!\"]]},\"3\":{\"map\":[\"str\",\"lst\",3,{\"nothin"
+  "g\":[\"rec\",0],\"poe\":[\"rec\",3,{\"1\":{\"i32\":3},\"2\":{\"str\":\"quoth"
+  "\"}},{\"1\":{\"i32\":4},\"2\":{\"str\":\"the raven\"}},{\"1\":{\"i32\":5},\""
+  "2\":{\"str\":\"nevermore\"}}],\"something\":[\"rec\",2,{\"1\":{\"i32\":1},\""
+  "2\":{\"str\":\"Wait.\"}},{\"1\":{\"i32\":2},\"2\":{\"str\":\"What?\"}}]}]}}"
+  );
 
+  const std::string result(apache::thrift::ThriftJSONString(*hm));
 
-  cout << "Testing ooe" << endl;
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
 
-  ooe.write(proto.get());
+BOOST_AUTO_TEST_CASE(test_json_proto_4) {
+  testCaseSetup_1();
+
+  std::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer());
+  std::shared_ptr<TJSONProtocol> proto(new TJSONProtocol(buffer));
+
+  ooe->write(proto.get());
   OneOfEach ooe2;
   ooe2.read(proto.get());
 
-  assert(ooe == ooe2);
+  BOOST_CHECK(*ooe == ooe2);
+}
 
+BOOST_AUTO_TEST_CASE(test_json_proto_5) {
+  testCaseSetup_3();
 
-  cout << "Testing hm" << endl;
+  std::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer());
+  std::shared_ptr<TJSONProtocol> proto(new TJSONProtocol(buffer));
 
-  hm.write(proto.get());
+  hm->write(proto.get());
   HolyMoley hm2;
   hm2.read(proto.get());
 
-  assert(hm == hm2);
+  BOOST_CHECK(*hm == hm2);
 
   hm2.big[0].a_bite = 0x00;
 
-  assert(hm != hm2);
+  BOOST_CHECK(*hm != hm2);
+}
 
+BOOST_AUTO_TEST_CASE(test_json_proto_6) {
   Doubles dub;
-  dub.nan = HUGE_VAL/HUGE_VAL;
+  dub.nan = HUGE_VAL / HUGE_VAL;
   dub.inf = HUGE_VAL;
   dub.neginf = -HUGE_VAL;
-  dub.repeating = 10.0/3.0;
+  dub.repeating = 10.0 / 3.0;
   dub.big = 1E+305;
-  dub.small = 1E-305;
+  dub.tiny = 1E-305;
   dub.zero = 0.0;
   dub.negzero = -0.0;
-  cout << apache::thrift::ThriftJSONString(dub) << endl << endl;
 
-  cout << "Testing base" << endl;
+  const std::string expected_result(
+  "{\"1\":{\"dbl\":\"NaN\"},\"2\":{\"dbl\":\"Infinity\"},\"3\":{\"dbl\":\"-Infi"
+  "nity\"},\"4\":{\"dbl\":3.3333333333333335},\"5\":{\"dbl\":9.9999999999999994e+"
+  "304},\"6\":{\"dbl\":1e-305},\"7\":{\"dbl\":0},\"8\":{\"dbl\":-0}}"
+  );
+
+  const std::string result(apache::thrift::ThriftJSONString(dub));
+
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
+
+BOOST_AUTO_TEST_CASE(test_json_proto_7) {
+  std::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer());
+  std::shared_ptr<TJSONProtocol> proto(new TJSONProtocol(buffer));
 
   Base64 base;
   base.a = 123;
@@ -153,7 +252,92 @@
   Base64 base2;
   base2.read(proto.get());
 
-  assert(base == base2);
+  BOOST_CHECK(base == base2);
+}
 
-  return 0;
+BOOST_AUTO_TEST_CASE(test_json_proto_8) {
+  const char* json_string =
+  "{\"1\":{\"tf\":1},\"2\":{\"tf\":0},\"3\":{\"i8\":127},\"4\":{\"i16\":27000},"
+  "\"5\":{\"i32\":16.77216},\"6\":{\"i64\":6000000000},\"7\":{\"dbl\":3.1415926"
+  "535897931},\"8\":{\"str\":\"JSON THIS! \\\"\\u0001\"},\"9\":{\"str\":\"\xd7\\"
+  "n\\u0007\\t\"},\"10\":{\"tf\":0},\"11\":{\"str\":\"AQIDrQ\"},\"12\":{\"lst\""
+  ":[\"i8\",3,1,2,3]},\"13\":{\"lst\":[\"i16\",3,1,2,3]},\"14\":{\"lst\":[\"i64"
+  "\",3,1,2,3]}}";
+
+  const std::size_t bufSiz = strlen(json_string) * sizeof(char);
+  std::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(
+    (uint8_t*)(json_string), static_cast<uint32_t>(bufSiz)));
+  std::shared_ptr<TJSONProtocol> proto(new TJSONProtocol(buffer));
+
+  OneOfEach ooe2;
+
+  BOOST_CHECK_THROW(ooe2.read(proto.get()),
+    apache::thrift::protocol::TProtocolException);
+}
+
+static std::string toHexSequence(const std::string& str) {
+  std::stringstream ss;
+  ss << std::hex << std::setfill('0');
+  for (std::size_t i = 0; i < str.size(); i++) {
+    ss << "\\x" << int(uint8_t(str[i]));
+  }
+  return ss.str();
+}
+
+BOOST_AUTO_TEST_CASE(test_json_unicode_escaped) {
+  const char json_string[] =
+  "{\"1\":{\"tf\":1},\"2\":{\"tf\":0},\"3\":{\"i8\":127},\"4\":{\"i16\":27000},"
+  "\"5\":{\"i32\":16},\"6\":{\"i64\":6000000000},\"7\":{\"dbl\":3.1415926"
+  "535897931},\"8\":{\"str\":\"JSON THIS!\"},\"9\":{\"str\":\"\\u0e01 \\ud835\\udd3e\"},"
+  "\"10\":{\"tf\":0},\"11\":{\"str\":\"000000\"},\"12\":{\"lst\""
+  ":[\"i8\",3,1,2,3]},\"13\":{\"lst\":[\"i16\",3,1,2,3]},\"14\":{\"lst\":[\"i64"
+  "\",3,1,2,3]}}";
+  const char* expected_zomg_unicode = "\xe0\xb8\x81 \xf0\x9d\x94\xbe";
+
+  std::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(
+    (uint8_t*)(json_string), sizeof(json_string)));
+  std::shared_ptr<TJSONProtocol> proto(new TJSONProtocol(buffer));
+
+  OneOfEach ooe2;
+  ooe2.read(proto.get());
+  BOOST_CHECK_MESSAGE(!ooe2.zomg_unicode.compare(expected_zomg_unicode),
+    "Expected:\n" << toHexSequence(expected_zomg_unicode) << "\nGotten:\n"
+                  << toHexSequence(ooe2.zomg_unicode));
+
+}
+
+BOOST_AUTO_TEST_CASE(test_json_unicode_escaped_missing_low_surrogate) {
+  const char json_string[] =
+  "{\"1\":{\"tf\":1},\"2\":{\"tf\":0},\"3\":{\"i8\":127},\"4\":{\"i16\":27000},"
+  "\"5\":{\"i32\":16},\"6\":{\"i64\":6000000000},\"7\":{\"dbl\":3.1415926"
+  "535897931},\"8\":{\"str\":\"JSON THIS!\"},\"9\":{\"str\":\"\\ud835\"},"
+  "\"10\":{\"tf\":0},\"11\":{\"str\":\"000000\"},\"12\":{\"lst\""
+  ":[\"i8\",3,1,2,3]},\"13\":{\"lst\":[\"i16\",3,1,2,3]},\"14\":{\"lst\":[\"i64"
+  "\",3,1,2,3]}}";
+
+  std::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(
+    (uint8_t*)(json_string), sizeof(json_string)));
+  std::shared_ptr<TJSONProtocol> proto(new TJSONProtocol(buffer));
+
+  OneOfEach ooe2;
+  BOOST_CHECK_THROW(ooe2.read(proto.get()),
+    apache::thrift::protocol::TProtocolException);
+}
+
+BOOST_AUTO_TEST_CASE(test_json_unicode_escaped_missing_hi_surrogate) {
+  const char json_string[] =
+  "{\"1\":{\"tf\":1},\"2\":{\"tf\":0},\"3\":{\"i8\":127},\"4\":{\"i16\":27000},"
+  "\"5\":{\"i32\":16},\"6\":{\"i64\":6000000000},\"7\":{\"dbl\":3.1415926"
+  "535897931},\"8\":{\"str\":\"JSON THIS!\"},\"9\":{\"str\":\"\\udd3e\"},"
+  "\"10\":{\"tf\":0},\"11\":{\"str\":\"000000\"},\"12\":{\"lst\""
+  ":[\"i8\",3,1,2,3]},\"13\":{\"lst\":[\"i16\",3,1,2,3]},\"14\":{\"lst\":[\"i64"
+  "\",3,1,2,3]}}";
+
+  std::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(
+    (uint8_t*)(json_string), sizeof(json_string)));
+  std::shared_ptr<TJSONProtocol> proto(new TJSONProtocol(buffer));
+
+  OneOfEach ooe2;
+  BOOST_CHECK_THROW(ooe2.read(proto.get()),
+    apache::thrift::protocol::TProtocolException);
 }
diff --git a/lib/cpp/test/Makefile.am b/lib/cpp/test/Makefile.am
index d04cfb5..d645a65 100755
--- a/lib/cpp/test/Makefile.am
+++ b/lib/cpp/test/Makefile.am
@@ -16,22 +16,57 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-.NOTPARALLEL:
+AUTOMAKE_OPTIONS = subdir-objects serial-tests
+
+BUILT_SOURCES = gen-cpp/AnnotationTest_types.h \
+                gen-cpp/DebugProtoTest_types.h \
+                gen-cpp/EnumTest_types.h \
+                gen-cpp/OptionalRequiredTest_types.h \
+                gen-cpp/Recursive_types.h \
+                gen-cpp/ThriftTest_types.h \
+                gen-cpp/TypedefTest_types.h \
+                gen-cpp/ChildService.h \
+                gen-cpp/EmptyService.h \
+                gen-cpp/ParentService.h \
+		gen-cpp/OneWayTest_types.h \
+		gen-cpp/OneWayService.h \
+		gen-cpp/OneWayTest_constants.h \
+                gen-cpp/proc_types.h
+
 noinst_LTLIBRARIES = libtestgencpp.la libprocessortest.la
 nodist_libtestgencpp_la_SOURCES = \
+	gen-cpp/AnnotationTest_types.cpp \
+	gen-cpp/AnnotationTest_types.h \
 	gen-cpp/DebugProtoTest_types.cpp \
-	gen-cpp/OptionalRequiredTest_types.cpp \
-	gen-cpp/DebugProtoTest_types.cpp \
-	gen-cpp/ThriftTest_types.cpp \
 	gen-cpp/DebugProtoTest_types.h \
+	gen-cpp/DoubleConstantsTest_constants.cpp \
+	gen-cpp/DoubleConstantsTest_constants.h \
+	gen-cpp/EnumTest_types.cpp \
+	gen-cpp/EnumTest_types.h \
+	gen-cpp/OptionalRequiredTest_types.cpp \
 	gen-cpp/OptionalRequiredTest_types.h \
+	gen-cpp/Recursive_types.cpp \
+	gen-cpp/Recursive_types.h \
+	gen-cpp/ThriftTest_types.cpp \
 	gen-cpp/ThriftTest_types.h \
+	gen-cpp/ThriftTest_constants.cpp \
+	gen-cpp/ThriftTest_constants.h \
+	gen-cpp/TypedefTest_types.cpp \
+	gen-cpp/TypedefTest_types.h \
+	gen-cpp/OneWayService.cpp \
+	gen-cpp/OneWayTest_constants.cpp \
+	gen-cpp/OneWayTest_types.h \
+	gen-cpp/OneWayService.h \
+	gen-cpp/OneWayTest_constants.h \
+	gen-cpp/OneWayTest_types.cpp \
 	ThriftTest_extras.cpp \
 	DebugProtoTest_extras.cpp
 
 nodist_libprocessortest_la_SOURCES = \
 	gen-cpp/ChildService.cpp \
 	gen-cpp/ChildService.h \
+	gen-cpp/EmptyService.cpp \
+	gen-cpp/EmptyService.h \
 	gen-cpp/ParentService.cpp \
 	gen-cpp/ParentService.h \
 	gen-cpp/proc_types.cpp \
@@ -42,7 +77,8 @@
 
 libtestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la
 
-noinst_PROGRAMS = Benchmark
+noinst_PROGRAMS = Benchmark \
+	concurrency_test
 
 Benchmark_SOURCES = \
 	Benchmark.cpp
@@ -50,43 +86,97 @@
 Benchmark_LDADD = libtestgencpp.la
 
 check_PROGRAMS = \
+	UnitTests \
 	TFDTransportTest \
 	TPipedTransportTest \
 	DebugProtoTest \
 	JSONProtoTest \
 	OptionalRequiredTest \
+	RecursiveTest \
 	SpecializationTest \
 	AllProtocolsTest \
 	TransportTest \
+	TInterruptTest \
+	TServerIntegrationTest \
+	SecurityTest \
 	ZlibTest \
 	TFileTransportTest \
-	UnitTests
-# disable these test ... too strong
-#       processor_test
-#	concurrency_test
+	link_test \
+	OpenSSLManualInitTest \
+	EnumTest \
+	RenderedDoubleConstantsTest \
+        AnnotationTest
+
+if AMX_HAVE_LIBEVENT
+noinst_PROGRAMS += \
+	processor_test
+check_PROGRAMS += \
+	TNonblockingServerTest \
+	TNonblockingSSLServerTest
+endif
 
 TESTS_ENVIRONMENT= \
 	BOOST_TEST_LOG_SINK=tests.xml \
 	BOOST_TEST_LOG_LEVEL=test_suite \
-	BOOST_TEST_LOG_FORMAT=xml
+	BOOST_TEST_LOG_FORMAT=XML
 
 TESTS = \
 	$(check_PROGRAMS)
 
 UnitTests_SOURCES = \
 	UnitTestMain.cpp \
+	OneWayHTTPTest.cpp \
 	TMemoryBufferTest.cpp \
 	TBufferBaseTest.cpp \
-	Base64Test.cpp
+	Base64Test.cpp \
+	ToStringTest.cpp \
+	TypedefTest.cpp \
+	TServerSocketTest.cpp \
+	TServerTransportTest.cpp \
+	TTransportCheckThrow.h
 
-if !WITH_BOOSTTHREADS
 UnitTests_SOURCES += \
-        RWMutexStarveTest.cpp
-endif
+  concurrency/MutexTest.cpp \
+  concurrency/RWMutexStarveTest.cpp
 
 UnitTests_LDADD = \
   libtestgencpp.la \
-  $(BOOST_ROOT_PATH)/lib/libboost_unit_test_framework.a
+  $(BOOST_TEST_LDADD) \
+  $(BOOST_SYSTEM_LDADD) \
+  $(BOOST_THREAD_LDADD)
+
+TInterruptTest_SOURCES = \
+	TSocketInterruptTest.cpp \
+	TSSLSocketInterruptTest.cpp
+
+TInterruptTest_LDADD = \
+  libtestgencpp.la \
+  $(BOOST_TEST_LDADD) \
+  $(BOOST_FILESYSTEM_LDADD) \
+  $(BOOST_CHRONO_LDADD) \
+  $(BOOST_SYSTEM_LDADD) \
+  $(BOOST_THREAD_LDADD)
+
+TServerIntegrationTest_SOURCES = \
+	TServerIntegrationTest.cpp
+
+TServerIntegrationTest_LDADD = \
+  libtestgencpp.la \
+  libprocessortest.la \
+  $(BOOST_TEST_LDADD) \
+  $(BOOST_SYSTEM_LDADD) \
+  $(BOOST_THREAD_LDADD)
+
+SecurityTest_SOURCES = \
+	SecurityTest.cpp
+
+SecurityTest_LDADD = \
+  libtestgencpp.la \
+  libprocessortest.la \
+  $(BOOST_TEST_LDADD) \
+  $(BOOST_FILESYSTEM_LDADD) \
+  $(BOOST_SYSTEM_LDADD) \
+  $(BOOST_THREAD_LDADD)
 
 TransportTest_SOURCES = \
 	TransportTest.cpp
@@ -94,7 +184,7 @@
 TransportTest_LDADD = \
   libtestgencpp.la \
   $(top_builddir)/lib/cpp/libthriftz.la \
-  $(BOOST_ROOT_PATH)/lib/libboost_unit_test_framework.a \
+  $(BOOST_TEST_LDADD) \
   -lz
 
 ZlibTest_SOURCES = \
@@ -103,15 +193,33 @@
 ZlibTest_LDADD = \
   libtestgencpp.la \
   $(top_builddir)/lib/cpp/libthriftz.la \
-  $(BOOST_ROOT_PATH)/lib/libboost_unit_test_framework.a \
+  $(BOOST_TEST_LDADD) \
   -lz
 
+EnumTest_SOURCES = \
+	EnumTest.cpp
+
+EnumTest_LDADD = \
+  libtestgencpp.la \
+  $(BOOST_TEST_LDADD)
+
+RenderedDoubleConstantsTest_SOURCES = RenderedDoubleConstantsTest.cpp
+
+RenderedDoubleConstantsTest_LDADD = libtestgencpp.la $(BOOST_TEST_LDADD)
+
+AnnotationTest_SOURCES = \
+	AnnotationTest.cpp
+
+AnnotationTest_LDADD = \
+  libtestgencpp.la \
+  $(BOOST_TEST_LDADD)
+
 TFileTransportTest_SOURCES = \
 	TFileTransportTest.cpp
 
 TFileTransportTest_LDADD = \
   libtestgencpp.la \
-  $(BOOST_ROOT_PATH)/lib/libboost_unit_test_framework.a
+  $(BOOST_TEST_LDADD)
 
 #
 # TFDTransportTest
@@ -119,18 +227,24 @@
 TFDTransportTest_SOURCES = \
 	TFDTransportTest.cpp
 
-TFDTransportTest_LDADD = \
-	$(top_builddir)/lib/cpp/libthrift.la
+TFDTransportTest_LDADD =  \
+	$(top_builddir)/lib/cpp/libthrift.la \
+	$(BOOST_TEST_LDADD)
 
 
 #
 # TPipedTransportTest
 #
 TPipedTransportTest_SOURCES = \
-	TPipedTransportTest.cpp
+	TPipedTransportTest.cpp \
+	TPipeInterruptTest.cpp
 
 TPipedTransportTest_LDADD = \
-	$(top_builddir)/lib/cpp/libthrift.la
+	libtestgencpp.la \
+	$(top_builddir)/lib/cpp/libthrift.la \
+	$(BOOST_TEST_LDADD) \
+	$(BOOST_SYSTEM_LDADD) \
+	$(BOOST_THREAD_LDADD)
 
 #
 # AllProtocolsTest
@@ -140,7 +254,9 @@
 	AllProtocolTests.tcc \
 	GenericHelpers.h
 
-AllProtocolsTest_LDADD = libtestgencpp.la
+AllProtocolsTest_LDADD = \
+  libtestgencpp.la \
+  $(BOOST_TEST_LDADD)
 
 #
 # DebugProtoTest
@@ -148,7 +264,9 @@
 DebugProtoTest_SOURCES = \
 	DebugProtoTest.cpp
 
-DebugProtoTest_LDADD = libtestgencpp.la
+DebugProtoTest_LDADD = \
+	libtestgencpp.la \
+	$(BOOST_TEST_LDADD)
 
 
 #
@@ -157,7 +275,36 @@
 JSONProtoTest_SOURCES = \
 	JSONProtoTest.cpp
 
-JSONProtoTest_LDADD = libtestgencpp.la
+JSONProtoTest_LDADD = \
+	libtestgencpp.la \
+	$(BOOST_TEST_LDADD)
+
+#
+# TNonblockingServerTest
+#
+TNonblockingServerTest_SOURCES = TNonblockingServerTest.cpp
+
+TNonblockingServerTest_LDADD = libprocessortest.la \
+                               $(top_builddir)/lib/cpp/libthrift.la \
+                               $(top_builddir)/lib/cpp/libthriftnb.la \
+                               $(BOOST_TEST_LDADD) \
+                               $(BOOST_LDFLAGS) \
+                               $(LIBEVENT_LIBS)
+#
+# TNonblockingSSLServerTest
+#
+TNonblockingSSLServerTest_SOURCES = TNonblockingSSLServerTest.cpp
+
+TNonblockingSSLServerTest_LDADD = libprocessortest.la \
+                               $(top_builddir)/lib/cpp/libthrift.la \
+                               $(top_builddir)/lib/cpp/libthriftnb.la \
+                               $(BOOST_TEST_LDADD) \
+                               $(BOOST_LDFLAGS) \
+                               $(BOOST_FILESYSTEM_LDADD) \
+                               $(BOOST_CHRONO_LDADD) \
+                               $(BOOST_SYSTEM_LDADD) \
+                               $(BOOST_THREAD_LDADD) \
+                               $(LIBEVENT_LIBS)
 
 #
 # OptionalRequiredTest
@@ -165,7 +312,19 @@
 OptionalRequiredTest_SOURCES = \
 	OptionalRequiredTest.cpp
 
-OptionalRequiredTest_LDADD = libtestgencpp.la
+OptionalRequiredTest_LDADD = \
+	libtestgencpp.la \
+	$(BOOST_TEST_LDADD)
+
+#
+# OptionalRequiredTest
+#
+RecursiveTest_SOURCES = \
+	RecursiveTest.cpp
+
+RecursiveTest_LDADD = \
+	libtestgencpp.la \
+	$(BOOST_TEST_LDADD)
 
 #
 # SpecializationTest
@@ -173,7 +332,9 @@
 SpecializationTest_SOURCES = \
 	SpecializationTest.cpp
 
-SpecializationTest_LDADD = libtestgencpp.la
+SpecializationTest_LDADD = \
+	libtestgencpp.la \
+	$(BOOST_TEST_LDADD)
 
 concurrency_test_SOURCES = \
 	concurrency/Tests.cpp \
@@ -184,6 +345,11 @@
 concurrency_test_LDADD = \
   $(top_builddir)/lib/cpp/libthrift.la
 
+link_test_SOURCES = \
+  link/LinkTest.cpp \
+  link/TemplatedService1.cpp \
+  link/TemplatedService2.cpp
+
 processor_test_SOURCES = \
 	processor/ProcessorTest.cpp \
 	processor/EventLog.cpp \
@@ -195,42 +361,69 @@
 processor_test_LDADD = libprocessortest.la \
                        $(top_builddir)/lib/cpp/libthrift.la \
                        $(top_builddir)/lib/cpp/libthriftnb.la \
+                       $(BOOST_TEST_LDADD) \
                        $(BOOST_LDFLAGS) \
-                       -levent \
-                       $(BOOST_ROOT_PATH)/lib/libboost_unit_test_framework.a
+                       $(LIBEVENT_LIBS)
+
+OpenSSLManualInitTest_SOURCES = \
+	OpenSSLManualInitTest.cpp
+
+OpenSSLManualInitTest_LDADD = \
+	$(top_builddir)/lib/cpp/libthrift.la \
+	$(BOOST_TEST_LDADD) \
+	$(OPENSSL_LDFLAGS) \
+	$(OPENSSL_LIBS)
+
 #
 # Common thrift code generation rules
 #
-THRIFT = $(top_builddir)/compiler/cpp/thrift
 
-gen-cpp/DebugProtoTest_types.cpp gen-cpp/DebugProtoTest_types.h: $(top_srcdir)/test/DebugProtoTest.thrift
-	$(THRIFT) --gen cpp:dense $<
+gen-cpp/AnnotationTest_constants.cpp gen-cpp/AnnotationTest_constants.h gen-cpp/AnnotationTest_types.cpp gen-cpp/AnnotationTest_types.h: $(top_srcdir)/test/AnnotationTest.thrift
+	$(THRIFT) --gen cpp $<
+
+gen-cpp/DebugProtoTest_types.cpp gen-cpp/DebugProtoTest_types.h gen-cpp/EmptyService.cpp gen-cpp/EmptyService.h: $(top_srcdir)/test/DebugProtoTest.thrift
+	$(THRIFT) --gen cpp $<
+
+gen-cpp/DoubleConstantsTest_constants.cpp gen-cpp/DoubleConstantsTest_constants.h: $(top_srcdir)/test/DoubleConstantsTest.thrift
+	$(THRIFT) --gen cpp $<
+
+
+gen-cpp/EnumTest_types.cpp gen-cpp/EnumTest_types.h: $(top_srcdir)/test/EnumTest.thrift
+	$(THRIFT) --gen cpp $<
+
+gen-cpp/TypedefTest_types.cpp gen-cpp/TypedefTest_types.h: $(top_srcdir)/test/TypedefTest.thrift
+	$(THRIFT) --gen cpp $<
 
 gen-cpp/OptionalRequiredTest_types.cpp gen-cpp/OptionalRequiredTest_types.h: $(top_srcdir)/test/OptionalRequiredTest.thrift
-	$(THRIFT) --gen cpp:dense $<
+	$(THRIFT) --gen cpp $<
+
+gen-cpp/Recursive_types.cpp gen-cpp/Recursive_types.h: $(top_srcdir)/test/Recursive.thrift
+	$(THRIFT) --gen cpp $<
 
 gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp: $(top_srcdir)/test/StressTest.thrift
-	$(THRIFT) --gen cpp:dense $<
+	$(THRIFT) --gen cpp $<
 
 gen-cpp/SecondService.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_types.h: $(top_srcdir)/test/ThriftTest.thrift
-	$(THRIFT) --gen cpp:dense $<
+	$(THRIFT) --gen cpp $<
 
-gen-cpp/ChildService.cpp: processor/proc.thrift
+gen-cpp/OneWayService.cpp gen-cpp/OneWayTest_constants.cpp gen-cpp/OneWayTest_types.h gen-cpp/OneWayService.h gen-cpp/OneWayTest_constants.h gen-cpp/OneWayTest_types.cpp: OneWayTest.thrift
+	$(THRIFT) --gen cpp $<
+
+gen-cpp/ChildService.cpp gen-cpp/ChildService.h gen-cpp/ParentService.cpp gen-cpp/ParentService.h gen-cpp/proc_types.cpp gen-cpp/proc_types.h: processor/proc.thrift
 	$(THRIFT) --gen cpp:templates,cob_style $<
 
-INCLUDES = \
-	-I$(top_srcdir)/lib/cpp/src
-
-AM_CPPFLAGS = $(BOOST_CPPFLAGS)
+AM_CPPFLAGS = $(BOOST_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I.
 AM_LDFLAGS = $(BOOST_LDFLAGS)
-AM_CXXFLAGS = -Wall
+AM_CXXFLAGS = -Wall -Wextra -pedantic
 
 clean-local:
-	$(RM) -r gen-cpp
+	$(RM) gen-cpp/*
 
 EXTRA_DIST = \
-	DenseProtoTest.cpp \
-	ThriftTest_extras.cpp \
-	DebugProtoTest_extras.cpp \
 	concurrency \
-	processor
+	processor \
+	qt \
+	CMakeLists.txt \
+	DebugProtoTest_extras.cpp \
+	ThriftTest_extras.cpp \
+	OneWayTest.thrift
diff --git a/lib/cpp/test/OneWayHTTPTest.cpp b/lib/cpp/test/OneWayHTTPTest.cpp
new file mode 100644
index 0000000..89fa164
--- /dev/null
+++ b/lib/cpp/test/OneWayHTTPTest.cpp
@@ -0,0 +1,242 @@
+/*
+ * 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.
+ */
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/thread.hpp>
+#include <iostream>
+#include <climits>
+#include <vector>
+#include <thrift/concurrency/Monitor.h>
+#include <thrift/protocol/TBinaryProtocol.h>
+#include <thrift/protocol/TJSONProtocol.h>
+#include <thrift/server/TThreadedServer.h>
+#include <thrift/transport/THttpServer.h>
+#include <thrift/transport/THttpClient.h>
+#include <thrift/transport/TServerSocket.h>
+#include <thrift/transport/TSocket.h>
+#include <memory>
+#include <thrift/transport/TBufferTransports.h>
+#include "gen-cpp/OneWayService.h"
+
+BOOST_AUTO_TEST_SUITE(OneWayHTTPTest)
+
+using namespace apache::thrift;
+using apache::thrift::protocol::TProtocol;
+using apache::thrift::protocol::TBinaryProtocol;
+using apache::thrift::protocol::TBinaryProtocolFactory;
+using apache::thrift::protocol::TJSONProtocol;
+using apache::thrift::protocol::TJSONProtocolFactory;
+using apache::thrift::server::TThreadedServer;
+using apache::thrift::server::TServerEventHandler;
+using apache::thrift::transport::TTransport;
+using apache::thrift::transport::THttpServer;
+using apache::thrift::transport::THttpServerTransportFactory;
+using apache::thrift::transport::THttpClient;
+using apache::thrift::transport::TBufferedTransport;
+using apache::thrift::transport::TBufferedTransportFactory;
+using apache::thrift::transport::TMemoryBuffer;
+using apache::thrift::transport::TServerSocket;
+using apache::thrift::transport::TSocket;
+using apache::thrift::transport::TTransportException;
+using std::shared_ptr;
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::string;
+namespace utf = boost::unit_test;
+
+// Define this env var to enable some logging (in case you need to debug)
+#undef ENABLE_STDERR_LOGGING
+
+class OneWayServiceHandler : public onewaytest::OneWayServiceIf {
+public:
+  OneWayServiceHandler() {}
+
+  void roundTripRPC() override {
+#ifdef ENABLE_STDERR_LOGGING
+    cerr << "roundTripRPC()" << endl;
+#endif
+  }
+  void oneWayRPC() {
+#ifdef ENABLE_STDERR_LOGGING
+    cerr << "oneWayRPC()" << std::endl ;
+#endif
+ }
+};
+
+class OneWayServiceCloneFactory : virtual public onewaytest::OneWayServiceIfFactory {
+ public:
+  virtual ~OneWayServiceCloneFactory() {}
+  virtual onewaytest::OneWayServiceIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo)
+  {
+    (void)connInfo ;
+    return new OneWayServiceHandler;
+  }
+  virtual void releaseHandler( onewaytest::OneWayServiceIf* handler) {
+    delete handler;
+  }
+};
+
+class RPC0ThreadClass {
+public:
+  RPC0ThreadClass(TThreadedServer& server) : server_(server) { } // Constructor
+~RPC0ThreadClass() { } // Destructor
+
+void Run() {
+  server_.serve() ;
+}
+ TThreadedServer& server_ ;
+} ;
+
+using apache::thrift::concurrency::Monitor;
+using apache::thrift::concurrency::Mutex;
+using apache::thrift::concurrency::Synchronized;
+
+// copied from IntegrationTest
+class TServerReadyEventHandler : public TServerEventHandler, public Monitor {
+public:
+  TServerReadyEventHandler() : isListening_(false), accepted_(0) {}
+  virtual ~TServerReadyEventHandler() {}
+  virtual void preServe() {
+    Synchronized sync(*this);
+    isListening_ = true;
+    notify();
+  }
+  virtual void* createContext(shared_ptr<TProtocol> input,
+                              shared_ptr<TProtocol> output) {
+    Synchronized sync(*this);
+    ++accepted_;
+    notify();
+
+    (void)input;
+    (void)output;
+    return NULL;
+  }
+  bool isListening() const { return isListening_; }
+  uint64_t acceptedCount() const { return accepted_; }
+
+private:
+  bool isListening_;
+  uint64_t accepted_;
+};
+
+class TBlockableBufferedTransport : public TBufferedTransport {
+ public:
+  TBlockableBufferedTransport(std::shared_ptr<TTransport> transport)
+    : TBufferedTransport(transport, 10240),
+    blocked_(false) {
+  }
+
+  uint32_t write_buffer_length() {
+    uint32_t have_bytes = static_cast<uint32_t>(wBase_ - wBuf_.get());
+    return have_bytes ;
+  }
+
+  void block() {
+    blocked_ = true ;
+#ifdef ENABLE_STDERR_LOGGING
+    cerr << "block flushing\n" ;
+#endif
+ }
+  void unblock() {
+    blocked_ = false ;
+#ifdef ENABLE_STDERR_LOGGING
+    cerr << "unblock flushing, buffer is\n<<" << std::string((char *)wBuf_.get(), write_buffer_length()) << ">>\n" ;
+#endif
+ }
+
+  void flush() override {
+    if (blocked_) {
+#ifdef ENABLE_STDERR_LOGGING
+      cerr << "flush was blocked\n" ;
+#endif
+      return ;
+    }
+    TBufferedTransport::flush() ;
+  }
+
+  bool blocked_ ;
+} ;
+
+BOOST_AUTO_TEST_CASE( JSON_BufferedHTTP )
+{
+  std::shared_ptr<TServerSocket> ss = std::make_shared<TServerSocket>(0) ;
+  TThreadedServer server(
+    std::make_shared<onewaytest::OneWayServiceProcessorFactory>(std::make_shared<OneWayServiceCloneFactory>()),
+    ss, //port
+    std::make_shared<THttpServerTransportFactory>(),
+    std::make_shared<TJSONProtocolFactory>());
+
+  std::shared_ptr<TServerReadyEventHandler> pEventHandler(new TServerReadyEventHandler) ;
+  server.setServerEventHandler(pEventHandler);
+
+#ifdef ENABLE_STDERR_LOGGING
+  cerr << "Starting the server...\n";
+#endif
+  RPC0ThreadClass t(server) ;
+  boost::thread thread(&RPC0ThreadClass::Run, &t);
+
+  {
+    Synchronized sync(*(pEventHandler.get()));
+    while (!pEventHandler->isListening()) {
+      pEventHandler->wait();
+    }
+  }
+
+  int port = ss->getPort() ;
+#ifdef ENABLE_STDERR_LOGGING
+  cerr << "port " << port << endl ;
+#endif
+
+  {
+    std::shared_ptr<TSocket> socket(new TSocket("localhost", port));
+    socket->setRecvTimeout(10000) ; // 1000msec should be enough
+    std::shared_ptr<TBlockableBufferedTransport> blockable_transport(new TBlockableBufferedTransport(socket));
+    std::shared_ptr<TTransport> transport(new THttpClient(blockable_transport, "localhost", "/service"));
+    std::shared_ptr<TProtocol> protocol(new TJSONProtocol(transport));
+    onewaytest::OneWayServiceClient client(protocol);
+
+
+    transport->open();
+    client.roundTripRPC();
+    blockable_transport->block() ;
+    uint32_t size0 = blockable_transport->write_buffer_length() ;
+    client.send_oneWayRPC() ;
+    uint32_t size1 = blockable_transport->write_buffer_length() ;
+    client.send_oneWayRPC() ;
+    uint32_t size2 = blockable_transport->write_buffer_length() ;
+    BOOST_CHECK((size1 - size0) == (size2 - size1)) ;
+    blockable_transport->unblock() ;
+    client.send_roundTripRPC() ;
+    blockable_transport->flush() ;
+    try {
+      client.recv_roundTripRPC() ;
+    } catch (TTransportException e) {
+      BOOST_ERROR( "we should not get a transport exception -- this means we failed: " + std::string(e.what()) ) ;
+    }
+    transport->close();
+  }
+  server.stop();
+  thread.join() ;
+#ifdef ENABLE_STDERR_LOGGING
+  cerr << "finished.\n";
+#endif
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/OneWayTest.thrift b/lib/cpp/test/OneWayTest.thrift
new file mode 100644
index 0000000..127e9ff
--- /dev/null
+++ b/lib/cpp/test/OneWayTest.thrift
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+namespace c_glib OneWayTest
+namespace java onewaytest
+namespace cpp onewaytest
+namespace rb Onewaytest
+namespace perl OneWayTest
+namespace csharp Onewaytest
+namespace js OneWayTest
+namespace st OneWayTest
+namespace py OneWayTest
+namespace py.twisted OneWayTest
+namespace go onewaytest
+namespace php OneWayTest
+namespace delphi Onewaytest
+namespace cocoa OneWayTest
+namespace lua OneWayTest
+namespace xsd test (uri = 'http://thrift.apache.org/ns/OneWayTest')
+namespace netcore ThriftAsync.OneWayTest
+
+// a minimal Thrift service, for use in OneWayHTTPTtest.cpp
+service OneWayService {
+  void roundTripRPC(),
+  oneway void oneWayRPC()
+}
diff --git a/lib/cpp/test/OpenSSLManualInitTest.cpp b/lib/cpp/test/OpenSSLManualInitTest.cpp
new file mode 100644
index 0000000..a30b303
--- /dev/null
+++ b/lib/cpp/test/OpenSSLManualInitTest.cpp
@@ -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.
+ */
+// To show that this test actually tests something, you can change
+// MANUAL_OPENSSL_INIT to 0 to cause automatic OpenSSL init/cleanup,
+// which will cause the test to fail
+#define MANUAL_OPENSSL_INIT 1
+#ifdef _WIN32
+#include <WinSock2.h>
+#endif
+
+#include <boost/test/unit_test.hpp>
+#include <openssl/evp.h>
+#include <thrift/transport/TSSLSocket.h>
+
+using namespace apache::thrift::transport;
+
+void make_isolated_sslsocketfactory() {
+  // Here we create an isolated TSSLSocketFactory to ensure the
+  // constructor and destructor of TSSLSocketFactory get run.  Thus
+  // without manual initialization normally OpenSSL would be
+  // uninitialized after this function.
+  TSSLSocketFactory factory;
+}
+
+void openssl_init() {
+#if MANUAL_OPENSSL_INIT
+  TSSLSocketFactory::setManualOpenSSLInitialization(true);
+  initializeOpenSSL();
+#endif
+}
+
+void openssl_cleanup() {
+#if MANUAL_OPENSSL_INIT
+  cleanupOpenSSL();
+#endif
+}
+
+void test_openssl_availability() {
+  // Check whether Thrift leaves OpenSSL functionality available after
+  // the last TSSLSocketFactory is destroyed when manual
+  // initialization is set
+  openssl_init();
+  make_isolated_sslsocketfactory();
+
+  // The following function is one that will fail if OpenSSL is
+  // uninitialized.  It might also fail on very old versions of
+  // OpenSSL...
+  const EVP_MD* md = EVP_get_digestbyname("SHA256");
+  BOOST_CHECK(md != NULL);
+  openssl_cleanup();
+}
+
+#ifdef BOOST_TEST_DYN_LINK
+bool init_unit_test_suite() {
+  boost::unit_test::test_suite* suite = &boost::unit_test::framework::master_test_suite();
+  suite->p_name.value = "OpenSSLManualInit";
+
+  suite->add(BOOST_TEST_CASE(test_openssl_availability));
+
+  return true;
+}
+ 
+int main( int argc, char* argv[] ) {
+  return ::boost::unit_test::unit_test_main(&init_unit_test_suite,argc,argv);
+}
+#else
+boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
+  THRIFT_UNUSED_VARIABLE(argc);
+  THRIFT_UNUSED_VARIABLE(argv);
+  boost::unit_test::test_suite* suite = &boost::unit_test::framework::master_test_suite();
+  suite->p_name.value = "OpenSSLManualInit";
+
+  suite->add(BOOST_TEST_CASE(test_openssl_availability));
+
+  return NULL;
+}
+#endif
\ No newline at end of file
diff --git a/lib/cpp/test/OptionalRequiredTest.cpp b/lib/cpp/test/OptionalRequiredTest.cpp
index ddafa81..4c43546 100644
--- a/lib/cpp/test/OptionalRequiredTest.cpp
+++ b/lib/cpp/test/OptionalRequiredTest.cpp
@@ -21,242 +21,366 @@
  * details.
  */
 
-#include <cassert>
 #include <map>
-#include <iostream>
 #include <thrift/protocol/TDebugProtocol.h>
 #include <thrift/protocol/TBinaryProtocol.h>
 #include <thrift/transport/TBufferTransports.h>
 #include "gen-cpp/OptionalRequiredTest_types.h"
 
-using std::cout;
-using std::endl;
-using std::map;
-using std::string;
+#define BOOST_TEST_MODULE OptionalRequiredTest
+#include <boost/test/unit_test.hpp>
+
 using namespace thrift::test;
 using namespace apache::thrift;
 using namespace apache::thrift::transport;
 using namespace apache::thrift::protocol;
 
-
 /*
 template<typename Struct>
 void trywrite(const Struct& s, bool should_work) {
   bool worked;
   try {
-    TBinaryProtocol protocol(boost::shared_ptr<TTransport>(new TMemoryBuffer));
+    TBinaryProtocol protocol(std::shared_ptr<TTransport>(new TMemoryBuffer));
     s.write(&protocol);
     worked = true;
   } catch (TProtocolException & ex) {
     worked = false;
   }
-  assert(worked == should_work);
+  BOOST_CHECK(worked == should_work);
 }
 */
 
 template <typename Struct1, typename Struct2>
-void write_to_read(const Struct1 & w, Struct2 & r) {
-  TBinaryProtocol protocol(boost::shared_ptr<TTransport>(new TMemoryBuffer));
+void write_to_read(const Struct1& w, Struct2& r) {
+  TBinaryProtocol protocol(std::shared_ptr<TTransport>(new TMemoryBuffer));
   w.write(&protocol);
   r.read(&protocol);
 }
 
+BOOST_AUTO_TEST_CASE(test_optional_required_1) {
+  OldSchool o;
 
-int main() {
+  const std::string expected_result(
+    "OldSchool {\n"
+    "  01: im_int (i16) = 0,\n"
+    "  02: im_str (string) = \"\",\n"
+    "  03: im_big (list) = list<map>[0] {\n"
+    "  },\n"
+    "}");
+  const std::string result(apache::thrift::ThriftDebugString(o));
 
-  cout << "This old school struct should have three fields." << endl;
-  {
-    OldSchool o;
-    cout << ThriftDebugString(o) << endl;
-  }
-  cout << endl;
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
 
-  cout << "Setting a value before setting isset." << endl;
-  {
-    Simple s;
-    cout << ThriftDebugString(s) << endl;
-    s.im_optional = 10;
-    cout << ThriftDebugString(s) << endl;
-    s.__isset.im_optional = true;
-    cout << ThriftDebugString(s) << endl;
-  }
-  cout << endl;
+BOOST_AUTO_TEST_CASE(test_optional_required_2_1) {
+  Simple s;
 
-  cout << "Setting isset before setting a value." << endl;
-  {
-    Simple s;
-    cout << ThriftDebugString(s) << endl;
-    s.__isset.im_optional = true;
-    cout << ThriftDebugString(s) << endl;
-    s.im_optional = 10;
-    cout << ThriftDebugString(s) << endl;
-  }
-  cout << endl;
+  const std::string expected_result(
+    "Simple {\n"
+    "  01: im_default (i16) = 0,\n"
+    "  02: im_required (i16) = 0,\n"
+    "}");
+  const std::string result(apache::thrift::ThriftDebugString(s));
 
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
+
+BOOST_AUTO_TEST_CASE(test_optional_required_2_2) {
+  Simple s;
+  s.im_optional = 10;
+
+  const std::string expected_result(
+    "Simple {\n"
+    "  01: im_default (i16) = 0,\n"
+    "  02: im_required (i16) = 0,\n"
+    "}");
+  const std::string result(apache::thrift::ThriftDebugString(s));
+
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
+
+BOOST_AUTO_TEST_CASE(test_optional_required_2_3) {
+  Simple s;
+  s.im_optional = 10;
+  s.__isset.im_optional = true;
+
+  const std::string expected_result(
+    "Simple {\n"
+    "  01: im_default (i16) = 0,\n"
+    "  02: im_required (i16) = 0,\n"
+    "  03: im_optional (i16) = 10,\n"
+    "}");
+  const std::string result(apache::thrift::ThriftDebugString(s));
+
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
+
+BOOST_AUTO_TEST_CASE(test_optional_required_2_4) {
+  Simple s;
+  s.__isset.im_optional = true;
+
+  const std::string expected_result(
+    "Simple {\n"
+    "  01: im_default (i16) = 0,\n"
+    "  02: im_required (i16) = 0,\n"
+    "  03: im_optional (i16) = 0,\n"
+    "}");
+  const std::string result(apache::thrift::ThriftDebugString(s));
+
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
+
+BOOST_AUTO_TEST_CASE(test_optional_required_2_5) {
+  Simple s;
+  s.__isset.im_optional = true;
+  s.im_optional = 10;
+
+  const std::string expected_result(
+    "Simple {\n"
+    "  01: im_default (i16) = 0,\n"
+    "  02: im_required (i16) = 0,\n"
+    "  03: im_optional (i16) = 10,\n"
+    "}");
+  const std::string result(apache::thrift::ThriftDebugString(s));
+
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
+
+BOOST_AUTO_TEST_CASE(test_optional_required_3) {
+  // assign/copy-construct with non-required fields
+
+  Simple s1, s2;
+  s1.__isset.im_default = true;
+  s1.__set_im_optional(10);
+  BOOST_CHECK(s1.__isset.im_default);
+  BOOST_CHECK(s1.__isset.im_optional);
+
+  s2 = s1;
+
+  BOOST_CHECK(s2.__isset.im_default);
+  BOOST_CHECK(s2.__isset.im_optional);
+
+  Simple s3(s1);
+
+  BOOST_CHECK(s3.__isset.im_default);
+  BOOST_CHECK(s3.__isset.im_optional);
+}
+
+BOOST_AUTO_TEST_CASE(test_optional_required_4) {
   // Write-to-read with optional fields.
-  {
-    Simple s1, s2, s3;
-    s1.im_optional = 10;
-    assert(!s1.__isset.im_default);
-  //assert(!s1.__isset.im_required);  // Compile error.
-    assert(!s1.__isset.im_optional);
 
-    write_to_read(s1, s2);
+  Simple s1, s2, s3;
+  s1.im_optional = 10;
+  BOOST_CHECK(!s1.__isset.im_default);
+  // BOOST_CHECK(!s1.__isset.im_required);  // Compile error.
+  BOOST_CHECK(!s1.__isset.im_optional);
 
-    assert( s2.__isset.im_default);
-  //assert( s2.__isset.im_required);  // Compile error.
-    assert(!s2.__isset.im_optional);
-    assert(s3.im_optional == 0);
+  write_to_read(s1, s2);
 
-    s1.__isset.im_optional = true;
-    write_to_read(s1, s3);
+  BOOST_CHECK(s2.__isset.im_default);
+  // BOOST_CHECK( s2.__isset.im_required);  // Compile error.
+  BOOST_CHECK(!s2.__isset.im_optional);
+  BOOST_CHECK(s3.im_optional == 0);
 
-    assert( s3.__isset.im_default);
-  //assert( s3.__isset.im_required);  // Compile error.
-    assert( s3.__isset.im_optional);
-    assert(s3.im_optional == 10);
-  }
+  s1.__isset.im_optional = true;
+  write_to_read(s1, s3);
 
+  BOOST_CHECK(s3.__isset.im_default);
+  // BOOST_CHECK( s3.__isset.im_required);  // Compile error.
+  BOOST_CHECK(s3.__isset.im_optional);
+  BOOST_CHECK(s3.im_optional == 10);
+}
+
+BOOST_AUTO_TEST_CASE(test_optional_required_5) {
   // Writing between optional and default.
-  {
-    Tricky1 t1;
-    Tricky2 t2;
 
-    t2.im_optional = 10;
-    write_to_read(t2, t1);
-    write_to_read(t1, t2);
-    assert(!t1.__isset.im_default);
-    assert( t2.__isset.im_optional);
-    assert(t1.im_default == t2.im_optional);
-    assert(t1.im_default == 0);
-  }
+  Tricky1 t1;
+  Tricky2 t2;
 
+  t2.im_optional = 10;
+  write_to_read(t2, t1);
+  write_to_read(t1, t2);
+  BOOST_CHECK(!t1.__isset.im_default);
+  BOOST_CHECK(t2.__isset.im_optional);
+  BOOST_CHECK(t1.im_default == t2.im_optional);
+  BOOST_CHECK(t1.im_default == 0);
+}
+
+BOOST_AUTO_TEST_CASE(test_optional_required_6) {
   // Writing between default and required.
-  {
-    Tricky1 t1;
-    Tricky3 t3;
-    write_to_read(t1, t3);
-    write_to_read(t3, t1);
-    assert(t1.__isset.im_default);
-  }
 
+  Tricky1 t1;
+  Tricky3 t3;
+  write_to_read(t1, t3);
+  write_to_read(t3, t1);
+  BOOST_CHECK(t1.__isset.im_default);
+}
+
+BOOST_AUTO_TEST_CASE(test_optional_required_7) {
   // Writing between optional and required.
-  {
-    Tricky2 t2;
-    Tricky3 t3;
-    t2.__isset.im_optional = true;
-    write_to_read(t2, t3);
-    write_to_read(t3, t2);
-  }
 
+  Tricky2 t2;
+  Tricky3 t3;
+  t2.__isset.im_optional = true;
+  write_to_read(t2, t3);
+  write_to_read(t3, t2);
+}
+
+BOOST_AUTO_TEST_CASE(test_optional_required_8) {
   // Mu-hu-ha-ha-ha!
-  {
-    Tricky2 t2;
-    Tricky3 t3;
-    try {
-      write_to_read(t2, t3);
-      abort();
-    }
-    catch (TProtocolException& ex) {}
 
-    write_to_read(t3, t2);
-    assert(t2.__isset.im_optional);
+  Tricky2 t2;
+  Tricky3 t3;
+  try {
+    write_to_read(t2, t3);
+    abort();
+  } catch (const TProtocolException&) {
   }
 
-  cout << "Complex struct, simple test." << endl;
-  {
-    Complex c;
-    cout << ThriftDebugString(c) << endl;
-  }
+  write_to_read(t3, t2);
+  BOOST_CHECK(t2.__isset.im_optional);
+}
 
+BOOST_AUTO_TEST_CASE(test_optional_required_9) {
+  Complex c;
 
-  {
-    Tricky1 t1;
-    Tricky2 t2;
-    // Compile error.
-    //(void)(t1 == t2);
-  }
+  const std::string expected_result(
+    "Complex {\n"
+    "  01: cp_default (i16) = 0,\n"
+    "  02: cp_required (i16) = 0,\n"
+    "  04: the_map (map) = map<i16,struct>[0] {\n"
+    "  },\n"
+    "  05: req_simp (struct) = Simple {\n"
+    "    01: im_default (i16) = 0,\n"
+    "    02: im_required (i16) = 0,\n"
+    "  },\n"
+    "}");
+  const std::string result(apache::thrift::ThriftDebugString(c));
 
-  {
-    OldSchool o1, o2, o3;
-    assert(o1 == o2);
-    o1.im_int = o2.im_int = 10;
-    assert(o1 == o2);
-    o1.__isset.im_int = true;
-    o2.__isset.im_int = false;
-    assert(o1 == o2);
-    o1.im_int = 20;
-    o1.__isset.im_int = false;
-    assert(o1 != o2);
-    o1.im_int = 10;
-    assert(o1 == o2);
-    o1.im_str = o2.im_str = "foo";
-    assert(o1 == o2);
-    o1.__isset.im_str = o2.__isset.im_str = true;
-    assert(o1 == o2);
-    map<int32_t,string> mymap;
-    mymap[1] = "bar";
-    mymap[2] = "baz";
-    o1.im_big.push_back(map<int32_t,string>());
-    assert(o1 != o2);
-    o2.im_big.push_back(map<int32_t,string>());
-    assert(o1 == o2);
-    o2.im_big.push_back(mymap);
-    assert(o1 != o2);
-    o1.im_big.push_back(mymap);
-    assert(o1 == o2);
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
 
-    TBinaryProtocol protocol(boost::shared_ptr<TTransport>(new TMemoryBuffer));
-    o1.write(&protocol);
+BOOST_AUTO_TEST_CASE(test_optional_required_10) {
+  Tricky1 t1;
+  Tricky2 t2;
+  // Compile error.
+  //(void)(t1 == t2);
+}
 
-    o1.im_big.push_back(mymap);
-    mymap[3] = "qux";
-    o2.im_big.push_back(mymap);
-    assert(o1 != o2);
-    o1.im_big.back()[3] = "qux";
-    assert(o1 == o2);
+BOOST_AUTO_TEST_CASE(test_optional_required_11) {
+  OldSchool o1, o2, o3;
+  BOOST_CHECK(o1 == o2);
+  o1.im_int = o2.im_int = 10;
+  BOOST_CHECK(o1 == o2);
+  o1.__isset.im_int = true;
+  o2.__isset.im_int = false;
+  BOOST_CHECK(o1 == o2);
+  o1.im_int = 20;
+  o1.__isset.im_int = false;
+  BOOST_CHECK(o1 != o2);
+  o1.im_int = 10;
+  BOOST_CHECK(o1 == o2);
+  o1.im_str = o2.im_str = "foo";
+  BOOST_CHECK(o1 == o2);
+  o1.__isset.im_str = o2.__isset.im_str = true;
+  BOOST_CHECK(o1 == o2);
+  std::map<int32_t, std::string> mymap;
+  mymap[1] = "bar";
+  mymap[2] = "baz";
+  o1.im_big.push_back(std::map<int32_t, std::string>());
+  BOOST_CHECK(o1 != o2);
+  o2.im_big.push_back(std::map<int32_t, std::string>());
+  BOOST_CHECK(o1 == o2);
+  o2.im_big.push_back(mymap);
+  BOOST_CHECK(o1 != o2);
+  o1.im_big.push_back(mymap);
+  BOOST_CHECK(o1 == o2);
 
-    o3.read(&protocol);
-    o3.im_big.push_back(mymap);
-    assert(o1 == o3);
+  TBinaryProtocol protocol(std::shared_ptr<TTransport>(new TMemoryBuffer));
+  o1.write(&protocol);
 
-    //cout << ThriftDebugString(o3) << endl;
-  }
+  o1.im_big.push_back(mymap);
+  mymap[3] = "qux";
+  o2.im_big.push_back(mymap);
+  BOOST_CHECK(o1 != o2);
+  o1.im_big.back()[3] = "qux";
+  BOOST_CHECK(o1 == o2);
+  
+  o3.read(&protocol);
+  o3.im_big.push_back(mymap);
+  BOOST_CHECK(o1 == o3);
 
-  {
-    Tricky2 t1, t2;
-    assert(t1.__isset.im_optional == false);
-    assert(t2.__isset.im_optional == false);
-    assert(t1 == t2);
-    t1.im_optional = 5;
-    assert(t1 == t2);
-    t2.im_optional = 5;
-    assert(t1 == t2);
-    t1.__isset.im_optional = true;
-    assert(t1 != t2);
-    t2.__isset.im_optional = true;
-    assert(t1 == t2);
-    t1.im_optional = 10;
-    assert(t1 != t2);
-    t2.__isset.im_optional = false;
-    assert(t1 != t2);
-  }
+  const std::string expected_result(
+    "OldSchool {\n"
+    "  01: im_int (i16) = 10,\n"
+    "  02: im_str (string) = \"foo\",\n"
+    "  03: im_big (list) = list<map>[3] {\n"
+    "    [0] = map<i32,string>[0] {\n"
+    "    },\n"
+    "    [1] = map<i32,string>[2] {\n"
+    "      1 -> \"bar\",\n"
+    "      2 -> \"baz\",\n"
+    "    },\n"
+    "    [2] = map<i32,string>[3] {\n"
+    "      1 -> \"bar\",\n"
+    "      2 -> \"baz\",\n"
+    "      3 -> \"qux\",\n"
+    "    },\n"
+    "  },\n"
+    "}");
+  const std::string result(apache::thrift::ThriftDebugString(o3));
 
-  {
-    OptionalDefault t1, t2;
-    cout << ThriftDebugString(t1) << endl;
-    assert(t1.__isset.opt_int == true);
-    assert(t1.__isset.opt_str == true);
-    assert(t1.opt_int == t2.opt_int);
-    assert(t1.opt_str == t2.opt_str);
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
+}
 
-    write_to_read(t1, t2);
-    cout << ThriftDebugString(t2) << endl;
-    assert(t2.__isset.opt_int == true);
-    assert(t2.__isset.opt_str == true);
-    assert(t1.opt_int == t2.opt_int);
-    assert(t1.opt_str == t2.opt_str);
-  }
+BOOST_AUTO_TEST_CASE(test_optional_required_12) {
+  Tricky2 t1, t2;
+  BOOST_CHECK(t1.__isset.im_optional == false);
+  BOOST_CHECK(t2.__isset.im_optional == false);
+  BOOST_CHECK(t1 == t2);
+  t1.im_optional = 5;
+  BOOST_CHECK(t1 == t2);
+  t2.im_optional = 5;
+  BOOST_CHECK(t1 == t2);
+  t1.__isset.im_optional = true;
+  BOOST_CHECK(t1 != t2);
+  t2.__isset.im_optional = true;
+  BOOST_CHECK(t1 == t2);
+  t1.im_optional = 10;
+  BOOST_CHECK(t1 != t2);
+  t2.__isset.im_optional = false;
+  BOOST_CHECK(t1 != t2);
+}
 
-  return 0;
+BOOST_AUTO_TEST_CASE(test_optional_required_13) {
+  OptionalDefault t1, t2;
+
+  BOOST_CHECK(t1.__isset.opt_int == true);
+  BOOST_CHECK(t1.__isset.opt_str == true);
+  BOOST_CHECK(t1.opt_int == t2.opt_int);
+  BOOST_CHECK(t1.opt_str == t2.opt_str);
+
+  write_to_read(t1, t2);
+  BOOST_CHECK(t2.__isset.opt_int == true);
+  BOOST_CHECK(t2.__isset.opt_str == true);
+  BOOST_CHECK(t1.opt_int == t2.opt_int);
+  BOOST_CHECK(t1.opt_str == t2.opt_str);
+
+  const std::string expected_result(
+    "OptionalDefault {\n"
+    "  01: opt_int (i16) = 1234,\n"
+    "  02: opt_str (string) = \"default\",\n"
+    "}");
+  const std::string result(apache::thrift::ThriftDebugString(t2));
+
+  BOOST_CHECK_MESSAGE(!expected_result.compare(result),
+    "Expected:\n" << expected_result << "\nGotten:\n" << result);
 }
diff --git a/lib/cpp/test/RWMutexStarveTest.cpp b/lib/cpp/test/RWMutexStarveTest.cpp
deleted file mode 100644
index e6cccf2..0000000
--- a/lib/cpp/test/RWMutexStarveTest.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <iostream>
-#include <unistd.h>
-
-#include <boost/shared_ptr.hpp>
-#include <boost/test/unit_test.hpp>
-
-#include "thrift/concurrency/Mutex.h"
-#include "thrift/concurrency/PosixThreadFactory.h"
-
-using boost::shared_ptr;
-using boost::unit_test::test_suite;
-using boost::unit_test::framework::master_test_suite;
-
-using namespace apache::thrift::concurrency;
-using namespace std;
-
-class Locker : public Runnable
-{
-protected:
-  Locker(boost::shared_ptr<ReadWriteMutex> rwlock, bool writer) :
-    rwlock_(rwlock), writer_(writer),
-    started_(false), gotLock_(false), signaled_(false) { }
-
-public:
-  virtual void run()
-  {
-    started_ = true;
-    if (writer_) {
-      rwlock_->acquireWrite();
-    } else {
-      rwlock_->acquireRead();
-    }
-    gotLock_ = true;
-    while (!signaled_) {
-      usleep(5000);
-    }
-    rwlock_->release();
-  }
-
-  bool started() const { return started_; }
-  bool gotLock() const { return gotLock_; }
-  void signal() { signaled_ = true; }
-
-protected:
-  boost::shared_ptr<ReadWriteMutex> rwlock_;
-  bool writer_;
-  volatile bool started_;
-  volatile bool gotLock_;
-  volatile bool signaled_;
-};
-
-class Reader : public Locker
-{
-public:
-  Reader(boost::shared_ptr<ReadWriteMutex> rwlock) : Locker(rwlock, false) { }
-};
-
-class Writer : public Locker
-{
-public:
-  Writer(boost::shared_ptr<ReadWriteMutex> rwlock) : Locker(rwlock, true) { }
-};
-
-void test_starve(PosixThreadFactory::POLICY policy)
-{
-  // the man pages for pthread_wrlock_rdlock suggest that any OS guarantee about
-  // writer starvation may be influenced by the scheduling policy, so let's try
-  // all 3 policies to see if any of them work.
-  PosixThreadFactory factory(policy);
-  factory.setDetached(false);
-
-  boost::shared_ptr<ReadWriteMutex> rwlock(new NoStarveReadWriteMutex());
-
-  boost::shared_ptr<Reader> reader1(new Reader(rwlock));
-  boost::shared_ptr<Reader> reader2(new Reader(rwlock));
-  boost::shared_ptr<Writer> writer(new Writer(rwlock));
-
-  boost::shared_ptr<Thread> treader1 = factory.newThread(reader1);
-  boost::shared_ptr<Thread> treader2 = factory.newThread(reader2);
-  boost::shared_ptr<Thread> twriter = factory.newThread(writer);
-
-  // launch a reader and make sure he has the lock
-  treader1->start();
-  while (!reader1->gotLock()) {
-    usleep(2000);
-  }
-
-  // launch a writer and make sure he's blocked on the lock
-  twriter->start();
-  while (!writer->started()) {
-    usleep(2000);
-  }
-  // tricky part... we can never be 100% sure that the writer is actually
-  // blocked on the lock, but we can pretty reasonably sure because we know
-  // he just executed the line immediately before getting the lock, and
-  // we'll wait a full second for him to get on it.
-  sleep(1);
-
-  // launch a second reader... if the RWMutex guarantees that writers won't
-  // starve, this reader should not be able to acquire the lock until the writer
-  // has acquired and released it.
-  treader2->start();
-  while (!reader2->started()) {
-    usleep(2000);
-  }
-  // again... can't be 100% sure the reader is waiting on (or has) the lock
-  // but we can be close.
-  sleep(1);
-
-  // tell reader 1 to let go of the lock
-  reader1->signal();
-
-  // wait for someone to get the lock
-  while (!reader2->gotLock() && !writer->gotLock()) {
-    usleep(2000);
-  }
-
-  // the test succeeded if the WRITER got the lock.
-  bool success = writer->gotLock();
-
-  // tell everyone we're done and wait for them to finish
-  reader2->signal();
-  writer->signal();
-  treader1->join();
-  treader2->join();
-  twriter->join();
-
-  // make sure it worked.
-  BOOST_CHECK_MESSAGE(success, "writer is starving");
-}
-
-BOOST_AUTO_TEST_SUITE( RWMutexStarveTest )
-
-BOOST_AUTO_TEST_CASE( test_starve_other )
-{
-  test_starve(PosixThreadFactory::OTHER);
-}
-
-BOOST_AUTO_TEST_CASE( test_starve_rr )
-{
-  test_starve(PosixThreadFactory::ROUND_ROBIN);
-}
-
-BOOST_AUTO_TEST_CASE( test_starve_fifo )
-{
-  test_starve(PosixThreadFactory::FIFO);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/RecursiveTest.cpp b/lib/cpp/test/RecursiveTest.cpp
new file mode 100644
index 0000000..15f234c
--- /dev/null
+++ b/lib/cpp/test/RecursiveTest.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+#include "gen-cpp/Recursive_types.h"
+#include <thrift/protocol/TBinaryProtocol.h>
+#include <memory>
+#include <thrift/transport/TBufferTransports.h>
+
+#define BOOST_TEST_MODULE RecursiveTest
+#include <boost/test/unit_test.hpp>
+
+using apache::thrift::transport::TMemoryBuffer;
+using apache::thrift::protocol::TBinaryProtocol;
+using std::shared_ptr;
+
+BOOST_AUTO_TEST_CASE(test_recursive_1) {
+  shared_ptr<TMemoryBuffer> buf(new TMemoryBuffer());
+  shared_ptr<TBinaryProtocol> prot(new TBinaryProtocol(buf));
+
+  RecTree tree;
+  RecTree child;
+  tree.children.push_back(child);
+
+  tree.write(prot.get());
+
+  RecTree result;
+  result.read(prot.get());
+  BOOST_CHECK(tree == result);
+}
+
+BOOST_AUTO_TEST_CASE(test_recursive_2) {
+  shared_ptr<TMemoryBuffer> buf(new TMemoryBuffer());
+  shared_ptr<TBinaryProtocol> prot(new TBinaryProtocol(buf));
+
+  RecList l;
+  shared_ptr<RecList> l2(new RecList);
+  l.nextitem = l2;
+
+  l.write(prot.get());
+
+  RecList resultlist;
+  resultlist.read(prot.get());
+  BOOST_CHECK(resultlist.nextitem != NULL);
+  BOOST_CHECK(resultlist.nextitem->nextitem == NULL);
+}
+
+BOOST_AUTO_TEST_CASE(test_recursive_3) {
+  shared_ptr<TMemoryBuffer> buf(new TMemoryBuffer());
+  shared_ptr<TBinaryProtocol> prot(new TBinaryProtocol(buf));
+
+  CoRec c;
+  shared_ptr<CoRec2> r(new CoRec2);
+  c.other = r;
+
+  c.write(prot.get());
+
+  c.read(prot.get());
+  BOOST_CHECK(c.other != NULL);
+  BOOST_CHECK(c.other->other.other == NULL);
+}
+
+BOOST_AUTO_TEST_CASE(test_recursive_4) {
+  shared_ptr<TMemoryBuffer> buf(new TMemoryBuffer());
+  shared_ptr<TBinaryProtocol> prot(new TBinaryProtocol(buf));
+
+  shared_ptr<RecList> depthLimit(new RecList);
+  depthLimit->nextitem = depthLimit;
+  BOOST_CHECK_THROW(depthLimit->write(prot.get()),
+    apache::thrift::protocol::TProtocolException);
+
+  depthLimit->nextitem.reset();
+}
diff --git a/lib/cpp/test/RenderedDoubleConstantsTest.cpp b/lib/cpp/test/RenderedDoubleConstantsTest.cpp
new file mode 100644
index 0000000..0ca042b
--- /dev/null
+++ b/lib/cpp/test/RenderedDoubleConstantsTest.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+#define EPSILON 0.0000001
+#include <typeindex>
+#include <typeinfo>
+#include <vector>
+
+#include "gen-cpp/DoubleConstantsTest_constants.h"
+using namespace thrift::test;
+
+#define BOOST_TEST_MODULE RenderedDoubleConstantsTest
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(RenderedDoubleConstantsTest)
+
+BOOST_AUTO_TEST_CASE(test_rendered_double_constants) {
+    const double EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT = 1.0;
+    const double EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT = -100.0;
+    const double EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT = 9223372036854775807.0;
+    const double EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT = -9223372036854775807.0;
+    const double EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS = 3.14159265359;
+    const double EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE = 1000000.1;
+    const double EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE = -1000000.1;
+    const double EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE = 1.7e+308;
+    const double EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE = 9223372036854775816.43;
+    const double EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE = -1.7e+308;
+    const double EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE = -9223372036854775816.43;
+    BOOST_CHECK_CLOSE(
+        g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST,
+        EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT, EPSILON);
+    BOOST_CHECK_CLOSE(
+        g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST,
+        EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT, EPSILON);
+    BOOST_CHECK_CLOSE(
+        g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST,
+        EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT, EPSILON);
+    BOOST_CHECK_CLOSE(
+        g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST,
+        EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT, EPSILON);
+    BOOST_CHECK_CLOSE(
+        g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST,
+        EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS, EPSILON);
+    BOOST_CHECK_CLOSE(
+        g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST,
+        EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE, EPSILON);
+    BOOST_CHECK_CLOSE(
+        g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST,
+        EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE, EPSILON);
+    BOOST_CHECK_CLOSE(
+        g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST,
+        EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE, EPSILON);
+    BOOST_CHECK_CLOSE(
+        g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST,
+        EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE, EPSILON);
+    BOOST_CHECK_CLOSE(
+        g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST,
+        EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE, EPSILON);
+    BOOST_CHECK_CLOSE(
+        g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST,
+        EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE, EPSILON);
+    BOOST_CHECK(
+        typeid(g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST).hash_code() ==
+        typeid(EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT).hash_code());
+    BOOST_CHECK(
+        typeid(g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST).hash_code() ==
+        typeid(EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT).hash_code());
+    BOOST_CHECK(
+        typeid(g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST).hash_code() ==
+        typeid(EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT).hash_code());
+    BOOST_CHECK(
+        typeid(g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST).hash_code() ==
+        typeid(EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT).hash_code());
+    BOOST_CHECK(
+        typeid(g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST).hash_code() ==
+        typeid(EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS).hash_code());
+    BOOST_CHECK(
+        typeid(g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST).hash_code() ==
+        typeid(EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE).hash_code());
+    BOOST_CHECK(
+        typeid(g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST).hash_code() ==
+        typeid(EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE).hash_code());
+    BOOST_CHECK(
+        typeid(g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST).hash_code() ==
+        typeid(EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE).hash_code());
+    BOOST_CHECK(
+        typeid(g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST).hash_code() ==
+        typeid(EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE).hash_code());
+    BOOST_CHECK(
+        typeid(g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST).hash_code() ==
+        typeid(EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE).hash_code());
+    BOOST_CHECK(
+        typeid(g_DoubleConstantsTest_constants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST)
+            .hash_code() ==
+        typeid(EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE).hash_code());
+}
+
+BOOST_AUTO_TEST_CASE(test_rendered_double_list) {
+    const std::vector<double> EXPECTED_DOUBLE_LIST{1.0,-100.0,100.0,9223372036854775807.0,-9223372036854775807.0,
+        3.14159265359,1000000.1,-1000000.1,1.7e+308,-1.7e+308,9223372036854775816.43,-9223372036854775816.43};
+    BOOST_CHECK_EQUAL(g_DoubleConstantsTest_constants.DOUBLE_LIST_TEST.size(), EXPECTED_DOUBLE_LIST.size());
+    for (unsigned int i = 0; i < EXPECTED_DOUBLE_LIST.size(); ++i) {
+        BOOST_CHECK_CLOSE(g_DoubleConstantsTest_constants.DOUBLE_LIST_TEST[i], EXPECTED_DOUBLE_LIST[i], EPSILON);
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/SecurityTest.cpp b/lib/cpp/test/SecurityTest.cpp
new file mode 100644
index 0000000..982a4f3
--- /dev/null
+++ b/lib/cpp/test/SecurityTest.cpp
@@ -0,0 +1,278 @@
+/*
+ * 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.
+ */
+
+#define BOOST_TEST_MODULE SecurityTest
+#include <boost/test/unit_test.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <boost/thread.hpp>
+#include <memory>
+#include <thrift/transport/TSSLServerSocket.h>
+#include <thrift/transport/TSSLSocket.h>
+#include <thrift/transport/TTransport.h>
+#include <vector>
+#ifdef __linux__
+#include <signal.h>
+#endif
+
+using apache::thrift::transport::TSSLServerSocket;
+using apache::thrift::transport::TServerTransport;
+using apache::thrift::transport::TSSLSocket;
+using apache::thrift::transport::TSSLSocketFactory;
+using apache::thrift::transport::TTransport;
+using apache::thrift::transport::TTransportException;
+using apache::thrift::transport::TTransportFactory;
+
+using std::bind;
+using std::shared_ptr;
+
+boost::filesystem::path keyDir;
+boost::filesystem::path certFile(const std::string& filename)
+{
+    return keyDir / filename;
+}
+boost::mutex gMutex;
+
+struct GlobalFixture
+{
+    GlobalFixture()
+    {
+        using namespace boost::unit_test::framework;
+    for (int i = 0; i < master_test_suite().argc; ++i)
+    {
+      BOOST_TEST_MESSAGE(boost::format("argv[%1%] = \"%2%\"") % i % master_test_suite().argv[i]);
+    }
+
+    #ifdef __linux__
+    // OpenSSL calls send() without MSG_NOSIGPIPE so writing to a socket that has
+    // disconnected can cause a SIGPIPE signal...
+    signal(SIGPIPE, SIG_IGN);
+    #endif
+
+    TSSLSocketFactory::setManualOpenSSLInitialization(true);
+    apache::thrift::transport::initializeOpenSSL();
+
+    keyDir = boost::filesystem::current_path().parent_path().parent_path().parent_path() / "test" / "keys";
+    if (!boost::filesystem::exists(certFile("server.crt")))
+    {
+      keyDir = boost::filesystem::path(master_test_suite().argv[master_test_suite().argc - 1]);
+      if (!boost::filesystem::exists(certFile("server.crt")))
+      {
+        throw std::invalid_argument("The last argument to this test must be the directory containing the test certificate(s).");
+      }
+    }
+    }
+
+    virtual ~GlobalFixture()
+    {
+    apache::thrift::transport::cleanupOpenSSL();
+#ifdef __linux__
+    signal(SIGPIPE, SIG_DFL);
+#endif
+    }
+};
+
+#if (BOOST_VERSION >= 105900)
+BOOST_GLOBAL_FIXTURE(GlobalFixture);
+#else
+BOOST_GLOBAL_FIXTURE(GlobalFixture)
+#endif
+
+struct SecurityFixture
+{
+    void server(apache::thrift::transport::SSLProtocol protocol)
+    {
+        try
+        {
+            boost::mutex::scoped_lock lock(mMutex);
+
+            shared_ptr<TSSLSocketFactory> pServerSocketFactory;
+            shared_ptr<TSSLServerSocket> pServerSocket;
+
+            pServerSocketFactory.reset(new TSSLSocketFactory(static_cast<apache::thrift::transport::SSLProtocol>(protocol)));
+            pServerSocketFactory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
+            pServerSocketFactory->loadCertificate(certFile("server.crt").string().c_str());
+            pServerSocketFactory->loadPrivateKey(certFile("server.key").string().c_str());
+            pServerSocketFactory->server(true);
+            pServerSocket.reset(new TSSLServerSocket("localhost", 0, pServerSocketFactory));
+            shared_ptr<TTransport> connectedClient;
+
+            try
+            {
+                pServerSocket->listen();
+                mPort = pServerSocket->getPort();
+                mCVar.notify_one();
+                lock.unlock();
+
+                connectedClient = pServerSocket->accept();
+                uint8_t buf[2];
+                buf[0] = 'O';
+                buf[1] = 'K';
+                connectedClient->write(&buf[0], 2);
+                connectedClient->flush();
+            }
+
+            catch (apache::thrift::transport::TTransportException& ex)
+            {
+                boost::mutex::scoped_lock lock(gMutex);
+                BOOST_TEST_MESSAGE(boost::format("SRV %1% Exception: %2%") % boost::this_thread::get_id() % ex.what());
+            }
+
+            if (connectedClient)
+            {
+                connectedClient->close();
+                connectedClient.reset();
+            }
+
+            pServerSocket->close();
+            pServerSocket.reset();
+        }
+        catch (std::exception& ex)
+        {
+            BOOST_FAIL(boost::format("%1%: %2%") % typeid(ex).name() % ex.what());
+        }
+    }
+
+    void client(apache::thrift::transport::SSLProtocol protocol)
+    {
+        try
+        {
+            shared_ptr<TSSLSocketFactory> pClientSocketFactory;
+            shared_ptr<TSSLSocket> pClientSocket;
+
+            try
+            {
+                pClientSocketFactory.reset(new TSSLSocketFactory(static_cast<apache::thrift::transport::SSLProtocol>(protocol)));
+                pClientSocketFactory->authenticate(true);
+                pClientSocketFactory->loadCertificate(certFile("client.crt").string().c_str());
+                pClientSocketFactory->loadPrivateKey(certFile("client.key").string().c_str());
+                pClientSocketFactory->loadTrustedCertificates(certFile("CA.pem").string().c_str());
+                pClientSocket = pClientSocketFactory->createSocket("localhost", mPort);
+                pClientSocket->open();
+
+                uint8_t buf[3];
+                buf[0] = 0;
+                buf[1] = 0;
+                BOOST_CHECK_EQUAL(2, pClientSocket->read(&buf[0], 2));
+                BOOST_CHECK_EQUAL(0, memcmp(&buf[0], "OK", 2));
+                mConnected = true;
+            }
+            catch (apache::thrift::transport::TTransportException& ex)
+            {
+                boost::mutex::scoped_lock lock(gMutex);
+                BOOST_TEST_MESSAGE(boost::format("CLI %1% Exception: %2%") % boost::this_thread::get_id() % ex.what());
+            }
+
+            if (pClientSocket)
+            {
+                pClientSocket->close();
+                pClientSocket.reset();
+            }
+        }
+        catch (std::exception& ex)
+        {
+            BOOST_FAIL(boost::format("%1%: %2%") % typeid(ex).name() % ex.what());
+        }
+    }
+
+    static const char *protocol2str(size_t protocol)
+    {
+        static const char *strings[apache::thrift::transport::LATEST + 1] =
+        {
+                "SSLTLS",
+                "SSLv2",
+                "SSLv3",
+                "TLSv1_0",
+                "TLSv1_1",
+                "TLSv1_2"
+        };
+        return strings[protocol];
+    }
+
+    boost::mutex mMutex;
+    boost::condition_variable mCVar;
+    int mPort;
+    bool mConnected;
+};
+
+BOOST_FIXTURE_TEST_SUITE(BOOST_TEST_MODULE, SecurityFixture)
+
+BOOST_AUTO_TEST_CASE(ssl_security_matrix)
+{
+    try
+    {
+        // matrix of connection success between client and server with different SSLProtocol selections
+        bool matrix[apache::thrift::transport::LATEST + 1][apache::thrift::transport::LATEST + 1] =
+        {
+    //   server    = SSLTLS   SSLv2    SSLv3    TLSv1_0  TLSv1_1  TLSv1_2
+    // client
+    /* SSLTLS  */  { true,    false,   false,   true,    true,    true    },
+    /* SSLv2   */  { false,   false,   false,   false,   false,   false   },
+    /* SSLv3   */  { false,   false,   true,    false,   false,   false   },
+    /* TLSv1_0 */  { true,    false,   false,   true,    false,   false   },
+    /* TLSv1_1 */  { true,    false,   false,   false,   true,    false   },
+    /* TLSv1_2 */  { true,    false,   false,   false,   false,   true    }
+        };
+
+        for (size_t si = 0; si <= apache::thrift::transport::LATEST; ++si)
+        {
+            for (size_t ci = 0; ci <= apache::thrift::transport::LATEST; ++ci)
+            {
+                if (si == 1 || ci == 1)
+                {
+                    // Skip all SSLv2 cases - protocol not supported
+                    continue;
+                }
+
+#ifdef OPENSSL_NO_SSL3
+                if (si == 2 || ci == 2)
+                {
+                    // Skip all SSLv3 cases - protocol not supported
+                    continue;
+                }
+#endif
+
+                boost::mutex::scoped_lock lock(mMutex);
+
+                BOOST_TEST_MESSAGE(boost::format("TEST: Server = %1%, Client = %2%")
+                    % protocol2str(si) % protocol2str(ci));
+
+                mConnected = false;
+                // thread_group manages the thread lifetime - ignore the return value of create_thread
+                boost::thread_group threads;
+                (void)threads.create_thread(bind(&SecurityFixture::server, this, static_cast<apache::thrift::transport::SSLProtocol>(si)));
+                mCVar.wait(lock);           // wait for listen() to succeed
+                lock.unlock();
+                (void)threads.create_thread(bind(&SecurityFixture::client, this, static_cast<apache::thrift::transport::SSLProtocol>(ci)));
+                threads.join_all();
+
+                BOOST_CHECK_MESSAGE(mConnected == matrix[ci][si],
+                        boost::format("      Server = %1%, Client = %2% expected mConnected == %3% but was %4%")
+                            % protocol2str(si) % protocol2str(ci) % matrix[ci][si] % mConnected);
+            }
+        }
+    }
+    catch (std::exception& ex)
+    {
+        BOOST_FAIL(boost::format("%1%: %2%") % typeid(ex).name() % ex.what());
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/SpecializationTest.cpp b/lib/cpp/test/SpecializationTest.cpp
index 7a3d347..008837d 100644
--- a/lib/cpp/test/SpecializationTest.cpp
+++ b/lib/cpp/test/SpecializationTest.cpp
@@ -1,30 +1,30 @@
-#include <iostream>
+#define _USE_MATH_DEFINES
 #include <cmath>
 #include <thrift/transport/TTransportUtils.h>
 #include <thrift/protocol/TBinaryProtocol.h>
 #include <gen-cpp/DebugProtoTest_types.h>
 
-using std::cout;
-using std::endl;
 using namespace thrift::test::debug;
 using namespace apache::thrift::transport;
 using namespace apache::thrift::protocol;
 
+#define BOOST_TEST_MODULE SpecializationTest
+#include <boost/test/unit_test.hpp>
+
 typedef TBinaryProtocolT<TMemoryBuffer> MyProtocol;
-//typedef TBinaryProtocolT<TTransport> MyProtocol;
+// typedef TBinaryProtocolT<TTransport> MyProtocol;
 
-int main() {
-
+BOOST_AUTO_TEST_CASE(test_specialization_1) {
   OneOfEach ooe;
-  ooe.im_true   = true;
-  ooe.im_false  = false;
-  ooe.a_bite    = 0x7f;
+  ooe.im_true = true;
+  ooe.im_false = false;
+  ooe.a_bite = 0x7f;
   ooe.integer16 = 27000;
-  ooe.integer32 = 1<<24;
+  ooe.integer32 = 1 << 24;
   ooe.integer64 = (uint64_t)6000 * 1000 * 1000;
   ooe.double_precision = M_PI;
-  ooe.some_characters  = "JSON THIS! \"\1";
-  ooe.zomg_unicode     = "\xd7\n\a\t";
+  ooe.some_characters = "JSON THIS! \"\1";
+  ooe.zomg_unicode = "\xd7\n\a\t";
   ooe.base64 = "\1\2\3\255";
 
   Nesting n;
@@ -32,12 +32,14 @@
   n.my_ooe.integer16 = 16;
   n.my_ooe.integer32 = 32;
   n.my_ooe.integer64 = 64;
-  n.my_ooe.double_precision = (std::sqrt(5)+1)/2;
-  n.my_ooe.some_characters  = ":R (me going \"rrrr\")";
-  n.my_ooe.zomg_unicode     = "\xd3\x80\xe2\x85\xae\xce\x9d\x20"
-                              "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"
-                              "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80\xbc";
-  n.my_bonk.type    = 31337;
+  n.my_ooe.double_precision = (std::sqrt(5.0) + 1) / 2;
+  n.my_ooe.some_characters = ":R (me going \"rrrr\")";
+  n.my_ooe.zomg_unicode     = "\xd3\x80\xe2\x85\xae\xce\x9d\x20\xd0\x9d\xce"
+                              "\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0"
+                              "\xb0\xcf\x81\xe2\x84\x8e\x20\xce\x91\x74\x74"
+                              "\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80"
+                              "\xbc";
+  n.my_bonk.type = 31337;
   n.my_bonk.message = "I am a bonk... xor!";
 
   HolyMoley hm;
@@ -61,48 +63,41 @@
 
   std::vector<Bonk> stage2;
   hm.bonks["nothing"] = stage2;
-  stage2.resize(stage2.size()+1);
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 1;
   stage2.back().message = "Wait.";
-  stage2.resize(stage2.size()+1);
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 2;
   stage2.back().message = "What?";
   hm.bonks["something"] = stage2;
   stage2.clear();
-  stage2.resize(stage2.size()+1);
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 3;
   stage2.back().message = "quoth";
-  stage2.resize(stage2.size()+1);
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 4;
   stage2.back().message = "the raven";
-  stage2.resize(stage2.size()+1);
+  stage2.resize(stage2.size() + 1);
   stage2.back().type = 5;
   stage2.back().message = "nevermore";
   hm.bonks["poe"] = stage2;
 
-  boost::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer());
-  boost::shared_ptr<TProtocol> proto(new MyProtocol(buffer));
-
-  cout << "Testing ooe" << endl;
+  std::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer());
+  std::shared_ptr<TProtocol> proto(new MyProtocol(buffer));
 
   ooe.write(proto.get());
   OneOfEach ooe2;
   ooe2.read(proto.get());
 
-  assert(ooe == ooe2);
-
-
-  cout << "Testing hm" << endl;
+  BOOST_CHECK(ooe == ooe2);
 
   hm.write(proto.get());
   HolyMoley hm2;
   hm2.read(proto.get());
 
-  assert(hm == hm2);
+  BOOST_CHECK(hm == hm2);
 
   hm2.big[0].a_bite = 0x00;
 
-  assert(hm != hm2);
-
-  return 0;
+  BOOST_CHECK(hm != hm2);
 }
diff --git a/lib/cpp/test/TBufferBaseTest.cpp b/lib/cpp/test/TBufferBaseTest.cpp
index f88a019..430302c 100644
--- a/lib/cpp/test/TBufferBaseTest.cpp
+++ b/lib/cpp/test/TBufferBaseTest.cpp
@@ -21,13 +21,14 @@
 #include <boost/test/auto_unit_test.hpp>
 #include <thrift/transport/TBufferTransports.h>
 #include <thrift/transport/TShortReadTransport.h>
+#include <memory>
 
-using std::string;
-using boost::shared_ptr;
+using std::shared_ptr;
 using apache::thrift::transport::TMemoryBuffer;
 using apache::thrift::transport::TBufferedTransport;
 using apache::thrift::transport::TFramedTransport;
 using apache::thrift::transport::test::TShortReadTransport;
+using std::string;
 
 // Shamelessly copied from ZlibTransport.  TODO: refactor.
 unsigned int dist[][5000] = {
@@ -349,7 +350,7 @@
       int write_index = 0;
       unsigned int to_write = (1<<14)-42;
       while (to_write > 0) {
-        int write_amt = std::min(dist[d1][write_index], to_write);
+        int write_amt = (std::min)(dist[d1][write_index], to_write);
         buffer.write(&data[write_offset], write_amt);
         write_offset += write_amt;
         write_index++;
@@ -360,7 +361,7 @@
       int read_index = 0;
       unsigned int to_read = (1<<13)-42;
       while (to_read > 0) {
-        int read_amt = std::min(dist[d2][read_index], to_read);
+        int read_amt = (std::min)(dist[d2][read_index], to_read);
         int got = buffer.read(&data_out[read_offset], read_amt);
         BOOST_CHECK_EQUAL(got, read_amt);
         read_offset += read_amt;
@@ -374,7 +375,7 @@
       int second_index = write_index-1;
       unsigned int to_second = (1<<14)+42;
       while (to_second > 0) {
-        int second_amt = std::min(dist[d1][second_index], to_second);
+        int second_amt = (std::min)(dist[d1][second_index], to_second);
         //printf("%d\n", second_amt);
         buffer.write(&data[second_offset], second_amt);
         second_offset += second_amt;
@@ -566,7 +567,7 @@
       for (int d1 = 0; d1 < 3; d1++) {
         shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(16));
         TFramedTransport trans(buffer, size);
-        uint8_t data_out[1<<15];
+        std::vector<uint8_t> data_out(1<<17, 0);
         std::vector<int> flush_sizes;
 
         int write_offset = 0;
@@ -604,7 +605,7 @@
         }
 
         BOOST_CHECK_EQUAL((unsigned int)read_offset, sizeof(data));
-        BOOST_CHECK(!memcmp(data, data_out, sizeof(data)));
+        BOOST_CHECK(!memcmp(data, &data_out[0], sizeof(data)));
       }
     }
   }
diff --git a/lib/cpp/test/TFDTransportTest.cpp b/lib/cpp/test/TFDTransportTest.cpp
index 7ffca71..0ba035a 100644
--- a/lib/cpp/test/TFDTransportTest.cpp
+++ b/lib/cpp/test/TFDTransportTest.cpp
@@ -21,36 +21,30 @@
 #include <stdexcept>
 #include <thrift/Thrift.h>
 #include <thrift/transport/TFDTransport.h>
+
+#define BOOST_TEST_MODULE TFDTransportTest
+#include <boost/test/unit_test.hpp>
+
+// Disabled on MSVC because the RTL asserts on an invalid file descriptor
+// in both debug and release mode; at least in MSVCR100 (Visual Studio 2010)
+#if !defined(WIN32)
+
 using apache::thrift::transport::TTransportException;
 using apache::thrift::transport::TFDTransport;
 
-class DummyException : std::exception {
-};
-
-int main() {
-  {
-    TFDTransport t(256, TFDTransport::NO_CLOSE_ON_DESTROY);
-  }
-
-  try {
-    {
-      TFDTransport t(256, TFDTransport::CLOSE_ON_DESTROY);
-    }
-    std::abort();
-  } catch (TTransportException) {
-  }
-
-  try {
-    {
-      TFDTransport t(256, TFDTransport::CLOSE_ON_DESTROY);
-      throw DummyException();
-    }
-    std::abort();
-  } catch (TTransportException&) {
-    abort();
-  } catch (DummyException&) {
-  }
-
-  return 0;
-
+BOOST_AUTO_TEST_CASE(test_tfdtransport_1) {
+  BOOST_CHECK_NO_THROW(TFDTransport t(256, TFDTransport::CLOSE_ON_DESTROY));
 }
+
+BOOST_AUTO_TEST_CASE(test_tfdtransport_2) {
+  TFDTransport t(256, TFDTransport::CLOSE_ON_DESTROY);
+  BOOST_CHECK_THROW(t.close(), TTransportException);
+}
+
+#else
+
+BOOST_AUTO_TEST_CASE(test_tfdtransport_dummy) {
+  BOOST_CHECK(true);
+}
+
+#endif
diff --git a/lib/cpp/test/TFileTransportTest.cpp b/lib/cpp/test/TFileTransportTest.cpp
old mode 100755
new mode 100644
index 20c3b5c..d0c26b3
--- a/lib/cpp/test/TFileTransportTest.cpp
+++ b/lib/cpp/test/TFileTransportTest.cpp
@@ -30,6 +30,14 @@
 
 #include <thrift/transport/TFileTransport.h>
 
+#ifdef __MINGW32__
+  #include <io.h>
+  #include <unistd.h>
+  #include <sys/types.h>
+  #include <fcntl.h>
+  #include <sys\stat.h>
+#endif
+
 using namespace apache::thrift::transport;
 
 /**************************************************************************
@@ -41,30 +49,15 @@
 class FsyncLog;
 FsyncLog* fsync_log;
 
-
 /**************************************************************************
  * Helper code
  **************************************************************************/
 
-// Provide BOOST_CHECK_LT() and BOOST_CHECK_GT(), in case we're compiled
-// with an older version of boost
-#ifndef BOOST_CHECK_LT
-#define BOOST_CHECK_CMP(a, b, op, check_fn) \
-  check_fn((a) op (b), \
-           "check " BOOST_STRINGIZE(a) " " BOOST_STRINGIZE(op) " " \
-           BOOST_STRINGIZE(b) " failed: " BOOST_STRINGIZE(a) "=" << (a) << \
-           " " BOOST_STRINGIZE(b) "=" << (b))
-
-#define BOOST_CHECK_LT(a, b) BOOST_CHECK_CMP(a, b, <, BOOST_CHECK_MESSAGE)
-#define BOOST_CHECK_GT(a, b) BOOST_CHECK_CMP(a, b, >, BOOST_CHECK_MESSAGE)
-#define BOOST_REQUIRE_LT(a, b) BOOST_CHECK_CMP(a, b, <, BOOST_REQUIRE_MESSAGE)
-#endif // BOOST_CHECK_LT
-
 /**
  * Class to record calls to fsync
  */
 class FsyncLog {
- public:
+public:
   struct FsyncCall {
     struct timeval time;
     int fd;
@@ -74,17 +67,15 @@
   FsyncLog() {}
 
   void fsync(int fd) {
-    (void) fd;
+    (void)fd;
     FsyncCall call;
-    gettimeofday(&call.time, NULL);
+    THRIFT_GETTIMEOFDAY(&call.time, NULL);
     calls_.push_back(call);
   }
 
-  const CallList* getCalls() const {
-    return &calls_;
-  }
+  const CallList* getCalls() const { return &calls_; }
 
- private:
+private:
   CallList calls_;
 };
 
@@ -92,8 +83,22 @@
  * Helper class to clean up temporary files
  */
 class TempFile {
- public:
+public:
   TempFile(const char* directory, const char* prefix) {
+  #ifdef __MINGW32__
+    ((void)directory);
+    size_t path_len = strlen(prefix) + 8;
+    path_ = new char[path_len];
+    snprintf(path_, path_len, "%sXXXXXX", prefix);
+    if (_mktemp_s(path_,path_len) == 0) {
+      fd_ = open(path_,O_CREAT | O_RDWR | O_BINARY,S_IREAD | S_IWRITE);
+      if (fd_ < 0) {
+        throw apache::thrift::TException("_mktemp_s() failed");
+      }
+    } else {
+      throw apache::thrift::TException("_mktemp_s() failed");
+    }
+  #else
     size_t path_len = strlen(directory) + strlen(prefix) + 8;
     path_ = new char[path_len];
     snprintf(path_, path_len, "%s/%sXXXXXX", directory, prefix);
@@ -102,6 +107,7 @@
     if (fd_ < 0) {
       throw apache::thrift::TException("mkstemp() failed");
     }
+  #endif
   }
 
   ~TempFile() {
@@ -109,13 +115,9 @@
     close();
   }
 
-  const char* getPath() const {
-    return path_;
-  }
+  const char* getPath() const { return path_; }
 
-  int getFD() const {
-    return fd_;
-  }
+  int getFD() const { return fd_; }
 
   void unlink() {
     if (path_) {
@@ -134,7 +136,7 @@
     fd_ = -1;
   }
 
- private:
+private:
   char* path_;
   int fd_;
 };
@@ -142,8 +144,7 @@
 // Use our own version of fsync() for testing.
 // This returns immediately, so timing in test_destructor() isn't affected by
 // waiting on the actual filesystem.
-extern "C"
-int fsync(int fd) {
+extern "C" int fsync(int fd) {
   if (fsync_log) {
     fsync_log->fsync(fd);
   }
@@ -154,7 +155,6 @@
   return (t2->tv_usec - t1->tv_usec) + (t2->tv_sec - t1->tv_sec) * 1000000;
 }
 
-
 /**************************************************************************
  * Test cases
  **************************************************************************/
@@ -176,7 +176,7 @@
 
   unsigned int num_over = 0;
   for (unsigned int n = 0; n < NUM_ITERATIONS; ++n) {
-    ftruncate(f.getFD(), 0);
+    BOOST_CHECK_EQUAL(0, ftruncate(f.getFD(), 0));
 
     TFileTransport* transport = new TFileTransport(f.getPath());
 
@@ -195,16 +195,16 @@
     struct timeval start;
     struct timeval end;
 
-    gettimeofday(&start, NULL);
+    THRIFT_GETTIMEOFDAY(&start, NULL);
     delete transport;
-    gettimeofday(&end, NULL);
+    THRIFT_GETTIMEOFDAY(&end, NULL);
 
     int delta = time_diff(&start, &end);
 
     // If any attempt takes more than 500ms, treat that as a failure.
     // Treat this as a fatal failure, so we'll return now instead of
     // looping over a very slow operation.
-    BOOST_REQUIRE_LT(delta, 500000);
+    BOOST_WARN( delta < 500000 );
 
     // Normally, it takes less than 100ms on my dev box.
     // However, if the box is heavily loaded, some of the test runs
@@ -215,17 +215,16 @@
   }
 
   // Make sure fewer than 10% of the runs took longer than 1000us
-  BOOST_CHECK(num_over < (NUM_ITERATIONS / 10));
+  BOOST_WARN(num_over < (NUM_ITERATIONS / 10));
 }
 
 /**
  * Make sure setFlushMaxUs() is honored.
  */
-void test_flush_max_us_impl(uint32_t flush_us, uint32_t write_us,
-                            uint32_t test_us) {
+void test_flush_max_us_impl(uint32_t flush_us, uint32_t write_us, uint32_t test_us) {
   // TFileTransport only calls fsync() if data has been written,
   // so make sure the write interval is smaller than the flush interval.
-  BOOST_REQUIRE(write_us < flush_us);
+  BOOST_WARN(write_us < flush_us);
 
   TempFile f(tmp_dir, "thrift.TFileTransportTest.");
 
@@ -277,16 +276,13 @@
   const FsyncLog::CallList* calls = log.getCalls();
   // We added 1 fsync call above.
   // Make sure TFileTransport called fsync at least once
-  BOOST_CHECK_GE(calls->size(),
-                 static_cast<FsyncLog::CallList::size_type>(1));
+  BOOST_WARN_GE(calls->size(), static_cast<FsyncLog::CallList::size_type>(1));
 
   const struct timeval* prev_time = NULL;
-  for (FsyncLog::CallList::const_iterator it = calls->begin();
-       it != calls->end();
-       ++it) {
+  for (FsyncLog::CallList::const_iterator it = calls->begin(); it != calls->end(); ++it) {
     if (prev_time) {
       int delta = time_diff(prev_time, &it->time);
-      BOOST_CHECK_LT(delta, max_allowed_delta);
+      BOOST_WARN( delta < max_allowed_delta );
     }
     prev_time = &it->time;
   }
@@ -322,13 +318,13 @@
   transport.write(buf, 1);
 
   struct timeval start;
-  gettimeofday(&start, NULL);
+  THRIFT_GETTIMEOFDAY(&start, NULL);
 
   for (unsigned int n = 0; n < 10; ++n) {
     transport.flush();
 
     struct timeval now;
-    gettimeofday(&now, NULL);
+    THRIFT_GETTIMEOFDAY(&now, NULL);
 
     // Fail if at any point we've been running for longer than half a second.
     // (With the buggy code, TFileTransport used to take 3 seconds per flush())
@@ -336,7 +332,7 @@
     // Use a fatal fail so we break out early, rather than continuing to make
     // many more slow flush() calls.
     int delta = time_diff(&start, &now);
-    BOOST_REQUIRE_LT(delta, 2000000);
+    BOOST_WARN( delta < 2000000 );
   }
 }
 
@@ -352,11 +348,8 @@
 }
 
 void parse_args(int argc, char* argv[]) {
-  struct option long_opts[] = {
-    { "help", false, NULL, 'h' },
-    { "tmp-dir", true, NULL, 't' },
-    { NULL, 0, NULL, 0 }
-  };
+  struct option long_opts[]
+      = {{"help", false, NULL, 'h'}, {"tmp-dir", true, NULL, 't'}, {NULL, 0, NULL, 0}};
 
   while (true) {
     optopt = 1;
@@ -366,28 +359,46 @@
     }
 
     switch (optchar) {
-      case 't':
-        tmp_dir = optarg;
-        break;
-      case 'h':
-        print_usage(stdout, argv[0]);
-        exit(0);
-      case '?':
-        exit(1);
-      default:
-        // Only happens if someone adds another option to the optarg string,
-        // but doesn't update the switch statement to handle it.
-        fprintf(stderr, "unknown option \"-%c\"\n", optchar);
-        exit(1);
+    case 't':
+      tmp_dir = optarg;
+      break;
+    case 'h':
+      print_usage(stdout, argv[0]);
+      exit(0);
+    case '?':
+      exit(1);
+    default:
+      // Only happens if someone adds another option to the optarg string,
+      // but doesn't update the switch statement to handle it.
+      fprintf(stderr, "unknown option \"-%c\"\n", optchar);
+      exit(1);
     }
   }
 }
 
+#ifdef BOOST_TEST_DYN_LINK
+static int myArgc = 0;
+static char **myArgv = NULL;
+
+bool init_unit_test_suite() {
+  boost::unit_test::framework::master_test_suite().p_name.value = "TFileTransportTest";
+
+  // Parse arguments
+  parse_args(myArgc,myArgv);
+  return true;
+}
+
+int main( int argc, char* argv[] ) {
+  myArgc = argc;
+  myArgv = argv;
+  return ::boost::unit_test::unit_test_main(&init_unit_test_suite,argc,argv);
+}
+#else
 boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
-  boost::unit_test::framework::master_test_suite().p_name.value =
-    "TFileTransportTest";
+  boost::unit_test::framework::master_test_suite().p_name.value = "TFileTransportTest";
 
   // Parse arguments
   parse_args(argc, argv);
   return NULL;
 }
+#endif
diff --git a/lib/cpp/test/TMemoryBufferTest.cpp b/lib/cpp/test/TMemoryBufferTest.cpp
index 10b53f4..9206872 100644
--- a/lib/cpp/test/TMemoryBufferTest.cpp
+++ b/lib/cpp/test/TMemoryBufferTest.cpp
@@ -20,89 +20,141 @@
 #include <boost/test/auto_unit_test.hpp>
 #include <iostream>
 #include <climits>
-#include <cassert>
-#include <thrift/transport/TBufferTransports.h>
+#include <vector>
 #include <thrift/protocol/TBinaryProtocol.h>
+#include <memory>
+#include <thrift/transport/TBufferTransports.h>
 #include "gen-cpp/ThriftTest_types.h"
 
-BOOST_AUTO_TEST_SUITE( TMemoryBufferTest )
+BOOST_AUTO_TEST_SUITE(TMemoryBufferTest)
 
-BOOST_AUTO_TEST_CASE( test_roundtrip ) {
-    using apache::thrift::transport::TMemoryBuffer;
-    using apache::thrift::protocol::TBinaryProtocol;
-    using boost::shared_ptr;
+using apache::thrift::protocol::TBinaryProtocol;
+using apache::thrift::transport::TMemoryBuffer;
+using apache::thrift::transport::TTransportException;
+using std::shared_ptr;
+using std::cout;
+using std::endl;
+using std::string;
 
-    shared_ptr<TMemoryBuffer> strBuffer(new TMemoryBuffer());
-    shared_ptr<TBinaryProtocol> binaryProtcol(new TBinaryProtocol(strBuffer));
+BOOST_AUTO_TEST_CASE(test_read_write_grow) {
+  // Added to test the fix for THRIFT-1248
+  TMemoryBuffer uut;
+  const int maxSize = 65536;
+  uint8_t verify[maxSize];
+  std::vector<uint8_t> buf;
+  buf.resize(maxSize);
 
-    thrift::test::Xtruct a;
-    a.i32_thing = 10;
-    a.i64_thing = 30;
-    a.string_thing ="holla back a";
-
-    a.write(binaryProtcol.get());
-    std::string serialized = strBuffer->getBufferAsString();
-
-    shared_ptr<TMemoryBuffer> strBuffer2(new TMemoryBuffer());
-    shared_ptr<TBinaryProtocol> binaryProtcol2(new TBinaryProtocol(strBuffer2));
-
-    strBuffer2->resetBuffer((uint8_t*)serialized.data(), serialized.length());
-    thrift::test::Xtruct a2;
-    a2.read(binaryProtcol2.get());
-
-    assert(a == a2);
+  for (uint32_t i = 0; i < maxSize; ++i) {
+    buf[i] = static_cast<uint8_t>(i);
   }
 
-BOOST_AUTO_TEST_CASE( test_copy )
+  for (uint32_t i = 1; i < maxSize; i *= 2) {
+    uut.write(&buf[0], i);
+  }
+
+  for (uint32_t i = 1; i < maxSize; i *= 2) {
+    uut.read(verify, i);
+    BOOST_CHECK_EQUAL(0, ::memcmp(verify, &buf[0], i));
+  }
+}
+
+BOOST_AUTO_TEST_CASE(test_roundtrip) {
+  shared_ptr<TMemoryBuffer> strBuffer(new TMemoryBuffer());
+  shared_ptr<TBinaryProtocol> binaryProtcol(new TBinaryProtocol(strBuffer));
+
+  thrift::test::Xtruct a;
+  a.i32_thing = 10;
+  a.i64_thing = 30;
+  a.string_thing = "holla back a";
+
+  a.write(binaryProtcol.get());
+  std::string serialized = strBuffer->getBufferAsString();
+
+  shared_ptr<TMemoryBuffer> strBuffer2(new TMemoryBuffer());
+  shared_ptr<TBinaryProtocol> binaryProtcol2(new TBinaryProtocol(strBuffer2));
+
+  strBuffer2->resetBuffer((uint8_t*)serialized.data(), static_cast<uint32_t>(serialized.length()));
+  thrift::test::Xtruct a2;
+  a2.read(binaryProtcol2.get());
+
+  BOOST_CHECK(a == a2);
+}
+
+BOOST_AUTO_TEST_CASE(test_readAppendToString) {
+  string* str1 = new string("abcd1234");
+  TMemoryBuffer buf((uint8_t*)str1->data(),
+                    static_cast<uint32_t>(str1->length()),
+                    TMemoryBuffer::COPY);
+
+  string str3 = "wxyz", str4 = "6789";
+  buf.readAppendToString(str3, 4);
+  buf.readAppendToString(str4, INT_MAX);
+
+  BOOST_CHECK(str3 == "wxyzabcd");
+  BOOST_CHECK(str4 == "67891234");
+}
+
+BOOST_AUTO_TEST_CASE(test_exceptions) {
+  char data[] = "foo\0bar";
+
+  TMemoryBuffer buf1((uint8_t*)data, 7, TMemoryBuffer::OBSERVE);
+  string str = buf1.getBufferAsString();
+  BOOST_CHECK(str.length() == 7);
+
+  buf1.resetBuffer();
+
+  BOOST_CHECK_THROW(buf1.write((const uint8_t*)"foo", 3), TTransportException);
+
+  TMemoryBuffer buf2((uint8_t*)data, 7, TMemoryBuffer::COPY);
+  BOOST_CHECK_NO_THROW(buf2.write((const uint8_t*)"bar", 3));
+}
+
+BOOST_AUTO_TEST_CASE(test_default_maximum_buffer_size)
+{
+  BOOST_CHECK_EQUAL((std::numeric_limits<uint32_t>::max)(), TMemoryBuffer().getMaxBufferSize());
+}
+
+BOOST_AUTO_TEST_CASE(test_default_buffer_size)
+{
+  BOOST_CHECK_EQUAL(1024, TMemoryBuffer().getBufferSize());
+}
+
+BOOST_AUTO_TEST_CASE(test_error_set_max_buffer_size_too_small)
+{
+  TMemoryBuffer buf;
+  BOOST_CHECK_THROW(buf.setMaxBufferSize(buf.getBufferSize() - 1), TTransportException);
+}
+
+BOOST_AUTO_TEST_CASE(test_maximum_buffer_size)
+{
+  TMemoryBuffer buf;
+  buf.setMaxBufferSize(8192);
+  std::vector<uint8_t> small_buff(1);
+
+  for (size_t i = 0; i < 8192; ++i)
   {
-    using apache::thrift::transport::TMemoryBuffer;
-    using std::string;
-    using std::cout;
-    using std::endl;
-
-    string* str1 = new string("abcd1234");
-    const char* data1 = str1->data();
-    TMemoryBuffer buf((uint8_t*)str1->data(), str1->length(), TMemoryBuffer::COPY);
-    delete str1;
-    string* str2 = new string("plsreuse");
-    bool obj_reuse = (str1 == str2);
-    bool dat_reuse = (data1 == str2->data());
-    cout << "Object reuse: " << obj_reuse << "   Data reuse: " << dat_reuse
-      << ((obj_reuse && dat_reuse) ? "   YAY!" : "") << endl;
-    delete str2;
-
-    string str3 = "wxyz", str4 = "6789";
-    buf.readAppendToString(str3, 4);
-    buf.readAppendToString(str4, INT_MAX);
-
-    assert(str3 == "wxyzabcd");
-    assert(str4 == "67891234");
+    buf.write(&small_buff[0], 1);
   }
 
-BOOST_AUTO_TEST_CASE( test_exceptions )
-  {
-    using apache::thrift::transport::TTransportException;
-    using apache::thrift::transport::TMemoryBuffer;
-    using std::string;
+  BOOST_CHECK_THROW(buf.write(&small_buff[0], 1), TTransportException);
+}
 
-    char data[] = "foo\0bar";
+BOOST_AUTO_TEST_CASE(test_memory_buffer_to_get_sizeof_objects)
+{
+  // This is a demonstration of how to use TMemoryBuffer to determine
+  // the serialized size of a thrift object in the Binary protocol.
+  // See THRIFT-3480
 
-    TMemoryBuffer buf1((uint8_t*)data, 7, TMemoryBuffer::OBSERVE);
-    string str = buf1.getBufferAsString();
-    assert(str.length() == 7);
-    buf1.resetBuffer();
-    try {
-      buf1.write((const uint8_t*)"foo", 3);
-      assert(false);
-    } catch (TTransportException& ex) {}
+  shared_ptr<TMemoryBuffer> memBuffer(new TMemoryBuffer());
+  shared_ptr<TBinaryProtocol> binaryProtcol(new TBinaryProtocol(memBuffer));
 
-    TMemoryBuffer buf2((uint8_t*)data, 7, TMemoryBuffer::COPY);
-    try {
-      buf2.write((const uint8_t*)"bar", 3);
-    } catch (TTransportException& ex) {
-      assert(false);
-    }
-  }
+  thrift::test::Xtruct object;
+  object.i32_thing = 10;
+  object.i64_thing = 30;
+  object.string_thing = "who's your daddy?";
+
+  uint32_t size = object.write(binaryProtcol.get());
+  BOOST_CHECK_EQUAL(47, size);
+}
 
 BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/lib/cpp/test/TNonblockingSSLServerTest.cpp b/lib/cpp/test/TNonblockingSSLServerTest.cpp
new file mode 100644
index 0000000..330380b
--- /dev/null
+++ b/lib/cpp/test/TNonblockingSSLServerTest.cpp
@@ -0,0 +1,291 @@
+/*
+ * 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.
+ */
+
+#define BOOST_TEST_MODULE TNonblockingSSLServerTest
+#include <boost/test/unit_test.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/format.hpp>
+
+#include "thrift/server/TNonblockingServer.h"
+#include "thrift/transport/TSSLSocket.h"
+#include "thrift/transport/TNonblockingSSLServerSocket.h"
+
+#include "gen-cpp/ParentService.h"
+
+#include <event.h>
+
+using namespace apache::thrift;
+using apache::thrift::concurrency::Guard;
+using apache::thrift::concurrency::Monitor;
+using apache::thrift::concurrency::Mutex;
+using apache::thrift::server::TServerEventHandler;
+using apache::thrift::transport::TSSLSocketFactory;
+using apache::thrift::transport::TSSLSocket;
+
+struct Handler : public test::ParentServiceIf {
+  void addString(const std::string& s) { strings_.push_back(s); }
+  void getStrings(std::vector<std::string>& _return) { _return = strings_; }
+  std::vector<std::string> strings_;
+
+  // dummy overrides not used in this test
+  int32_t incrementGeneration() { return 0; }
+  int32_t getGeneration() { return 0; }
+  void getDataWait(std::string&, const int32_t) {}
+  void onewayWait() {}
+  void exceptionWait(const std::string&) {}
+  void unexpectedExceptionWait(const std::string&) {}
+};
+
+boost::filesystem::path keyDir;
+boost::filesystem::path certFile(const std::string& filename)
+{
+  return keyDir / filename;
+}
+
+struct GlobalFixtureSSL
+{
+    GlobalFixtureSSL()
+    {
+      using namespace boost::unit_test::framework;
+      for (int i = 0; i < master_test_suite().argc; ++i)
+      {
+        BOOST_TEST_MESSAGE(boost::format("argv[%1%] = \"%2%\"") % i % master_test_suite().argv[i]);
+      }
+
+#ifdef __linux__
+      // OpenSSL calls send() without MSG_NOSIGPIPE so writing to a socket that has
+      // disconnected can cause a SIGPIPE signal...
+      signal(SIGPIPE, SIG_IGN);
+#endif
+
+      TSSLSocketFactory::setManualOpenSSLInitialization(true);
+      apache::thrift::transport::initializeOpenSSL();
+
+      keyDir = boost::filesystem::current_path().parent_path().parent_path().parent_path() / "test" / "keys";
+      if (!boost::filesystem::exists(certFile("server.crt")))
+      {
+        keyDir = boost::filesystem::path(master_test_suite().argv[master_test_suite().argc - 1]);
+        if (!boost::filesystem::exists(certFile("server.crt")))
+        {
+          throw std::invalid_argument("The last argument to this test must be the directory containing the test certificate(s).");
+        }
+      }
+    }
+
+    virtual ~GlobalFixtureSSL()
+    {
+      apache::thrift::transport::cleanupOpenSSL();
+#ifdef __linux__
+      signal(SIGPIPE, SIG_DFL);
+#endif
+    }
+};
+
+#if (BOOST_VERSION >= 105900)
+BOOST_GLOBAL_FIXTURE(GlobalFixtureSSL);
+#else
+BOOST_GLOBAL_FIXTURE(GlobalFixtureSSL)
+#endif
+
+std::shared_ptr<TSSLSocketFactory> createServerSocketFactory() {
+  std::shared_ptr<TSSLSocketFactory> pServerSocketFactory;
+
+  pServerSocketFactory.reset(new TSSLSocketFactory());
+  pServerSocketFactory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
+  pServerSocketFactory->loadCertificate(certFile("server.crt").string().c_str());
+  pServerSocketFactory->loadPrivateKey(certFile("server.key").string().c_str());
+  pServerSocketFactory->server(true);
+  return pServerSocketFactory;
+}
+
+std::shared_ptr<TSSLSocketFactory> createClientSocketFactory() {
+  std::shared_ptr<TSSLSocketFactory> pClientSocketFactory;
+
+  pClientSocketFactory.reset(new TSSLSocketFactory());
+  pClientSocketFactory->authenticate(true);
+  pClientSocketFactory->loadCertificate(certFile("client.crt").string().c_str());
+  pClientSocketFactory->loadPrivateKey(certFile("client.key").string().c_str());
+  pClientSocketFactory->loadTrustedCertificates(certFile("CA.pem").string().c_str());
+  return pClientSocketFactory;
+}
+
+class Fixture {
+private:
+  struct ListenEventHandler : public TServerEventHandler {
+    public:
+      ListenEventHandler(Mutex* mutex) : listenMonitor_(mutex), ready_(false) {}
+
+      void preServe() /* override */ {
+        Guard g(listenMonitor_.mutex());
+        ready_ = true;
+        listenMonitor_.notify();
+      }
+
+      Monitor listenMonitor_;
+      bool ready_;
+  };
+
+  struct Runner : public apache::thrift::concurrency::Runnable {
+    int port;
+    std::shared_ptr<event_base> userEventBase;
+    std::shared_ptr<TProcessor> processor;
+    std::shared_ptr<server::TNonblockingServer> server;
+    std::shared_ptr<ListenEventHandler> listenHandler;
+    std::shared_ptr<TSSLSocketFactory> pServerSocketFactory;
+    std::shared_ptr<transport::TNonblockingSSLServerSocket> socket;
+    Mutex mutex_;
+
+    Runner() {
+      listenHandler.reset(new ListenEventHandler(&mutex_));
+    }
+
+    virtual void run() {
+      // When binding to explicit port, allow retrying to workaround bind failures on ports in use
+      int retryCount = port ? 10 : 0;
+      pServerSocketFactory = createServerSocketFactory();  
+      startServer(retryCount);
+    }
+
+    void readyBarrier() {
+      // block until server is listening and ready to accept connections
+      Guard g(mutex_);
+      while (!listenHandler->ready_) {
+        listenHandler->listenMonitor_.wait();
+      }
+    }
+  private:
+    void startServer(int retry_count) {
+      try {
+        socket.reset(new transport::TNonblockingSSLServerSocket(port, pServerSocketFactory));
+        server.reset(new server::TNonblockingServer(processor, socket));
+	      server->setServerEventHandler(listenHandler);
+        server->setNumIOThreads(1);
+        if (userEventBase) {
+          server->registerEvents(userEventBase.get());
+        }
+        server->serve();
+      } catch (const transport::TTransportException&) {
+        if (retry_count > 0) {
+          ++port;
+          startServer(retry_count - 1);
+        } else {
+          throw;
+        }
+      }
+    }
+  };
+
+  struct EventDeleter {
+    void operator()(event_base* p) { event_base_free(p); }
+  };
+
+protected:
+  Fixture() : processor(new test::ParentServiceProcessor(std::make_shared<Handler>())) {}
+
+  ~Fixture() {
+    if (server) {
+      server->stop();
+    }
+    if (thread) {
+      thread->join();
+    }
+  }
+
+  void setEventBase(event_base* user_event_base) {
+    userEventBase_.reset(user_event_base, EventDeleter());
+  }
+
+  int startServer(int port) {
+    std::shared_ptr<Runner> runner(new Runner);
+    runner->port = port;
+    runner->processor = processor;
+    runner->userEventBase = userEventBase_;
+
+    std::unique_ptr<apache::thrift::concurrency::ThreadFactory> threadFactory(
+        new apache::thrift::concurrency::PlatformThreadFactory(
+#if !USE_STD_THREAD
+            concurrency::PlatformThreadFactory::OTHER, concurrency::PlatformThreadFactory::NORMAL,
+            1,
+#endif
+            false));
+    thread = threadFactory->newThread(runner);
+    thread->start();
+    runner->readyBarrier();
+
+    server = runner->server;
+    return runner->port;
+  }
+
+  bool canCommunicate(int serverPort) {
+    std::shared_ptr<TSSLSocketFactory> pClientSocketFactory = createClientSocketFactory();
+    std::shared_ptr<TSSLSocket> socket = pClientSocketFactory->createSocket("localhost", serverPort);
+    socket->open();
+    test::ParentServiceClient client(std::make_shared<protocol::TBinaryProtocol>(
+        std::make_shared<transport::TFramedTransport>(socket)));
+    client.addString("foo");
+    std::vector<std::string> strings;
+    client.getStrings(strings);
+    return strings.size() == 1 && !(strings[0].compare("foo"));
+  }
+
+private:
+  std::shared_ptr<event_base> userEventBase_;
+  std::shared_ptr<test::ParentServiceProcessor> processor;
+protected:
+  std::shared_ptr<server::TNonblockingServer> server;
+private:
+  std::shared_ptr<apache::thrift::concurrency::Thread> thread;
+
+};
+
+BOOST_AUTO_TEST_SUITE(TNonblockingSSLServerTest)
+
+BOOST_FIXTURE_TEST_CASE(get_specified_port, Fixture) {
+  int specified_port = startServer(12345);
+  BOOST_REQUIRE_GE(specified_port, 12345);
+  BOOST_REQUIRE_EQUAL(server->getListenPort(), specified_port);
+  BOOST_CHECK(canCommunicate(specified_port));
+
+  server->stop();
+}
+
+BOOST_FIXTURE_TEST_CASE(get_assigned_port, Fixture) {
+  int specified_port = startServer(0);
+  BOOST_REQUIRE_EQUAL(specified_port, 0);
+  int assigned_port = server->getListenPort();
+  BOOST_REQUIRE_NE(assigned_port, 0);
+  BOOST_CHECK(canCommunicate(assigned_port));
+
+  server->stop();
+}
+
+BOOST_FIXTURE_TEST_CASE(provide_event_base, Fixture) {
+  event_base* eb = event_base_new();
+  setEventBase(eb);
+  startServer(0);
+
+  // assert that the server works
+  BOOST_CHECK(canCommunicate(server->getListenPort()));
+#if LIBEVENT_VERSION_NUMBER > 0x02010400
+  // also assert that the event_base is actually used when it's easy
+  BOOST_CHECK_GT(event_base_get_num_events(eb, EVENT_BASE_COUNT_ADDED), 0);
+#endif
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/TNonblockingServerTest.cpp b/lib/cpp/test/TNonblockingServerTest.cpp
new file mode 100644
index 0000000..f0bb283
--- /dev/null
+++ b/lib/cpp/test/TNonblockingServerTest.cpp
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ */
+
+#define BOOST_TEST_MODULE TNonblockingServerTest
+#include <boost/test/unit_test.hpp>
+#include <memory>
+
+#include "thrift/concurrency/Monitor.h"
+#include "thrift/concurrency/Thread.h"
+#include "thrift/server/TNonblockingServer.h"
+#include "thrift/transport/TNonblockingServerSocket.h"
+
+#include "gen-cpp/ParentService.h"
+
+#include <event.h>
+
+using apache::thrift::concurrency::Guard;
+using apache::thrift::concurrency::Monitor;
+using apache::thrift::concurrency::Mutex;
+using apache::thrift::concurrency::PlatformThreadFactory;
+using apache::thrift::concurrency::Runnable;
+using apache::thrift::concurrency::Thread;
+using apache::thrift::concurrency::ThreadFactory;
+using apache::thrift::server::TServerEventHandler;
+using std::make_shared;
+using std::shared_ptr;
+
+using namespace apache::thrift;
+
+struct Handler : public test::ParentServiceIf {
+  void addString(const std::string& s) { strings_.push_back(s); }
+  void getStrings(std::vector<std::string>& _return) { _return = strings_; }
+  std::vector<std::string> strings_;
+
+  // dummy overrides not used in this test
+  int32_t incrementGeneration() { return 0; }
+  int32_t getGeneration() { return 0; }
+  void getDataWait(std::string&, const int32_t) {}
+  void onewayWait() {}
+  void exceptionWait(const std::string&) {}
+  void unexpectedExceptionWait(const std::string&) {}
+};
+
+class Fixture {
+private:
+  struct ListenEventHandler : public TServerEventHandler {
+    public:
+      ListenEventHandler(Mutex* mutex) : listenMonitor_(mutex), ready_(false) {}
+
+      void preServe() /* override */ {
+        Guard g(listenMonitor_.mutex());
+        ready_ = true;
+        listenMonitor_.notify();
+      }
+
+      Monitor listenMonitor_;
+      bool ready_;
+  };
+
+  struct Runner : public Runnable {
+    int port;
+    shared_ptr<event_base> userEventBase;
+    shared_ptr<TProcessor> processor;
+    shared_ptr<server::TNonblockingServer> server;
+    shared_ptr<ListenEventHandler> listenHandler;
+    shared_ptr<transport::TNonblockingServerSocket> socket;
+    Mutex mutex_;
+
+    Runner() {
+      listenHandler.reset(new ListenEventHandler(&mutex_));
+    }
+
+    virtual void run() {
+      // When binding to explicit port, allow retrying to workaround bind failures on ports in use
+      int retryCount = port ? 10 : 0;
+      startServer(retryCount);
+    }
+
+    void readyBarrier() {
+      // block until server is listening and ready to accept connections
+      Guard g(mutex_);
+      while (!listenHandler->ready_) {
+        listenHandler->listenMonitor_.wait();
+      }
+    }
+  private:
+    void startServer(int retry_count) {
+      try {
+        socket.reset(new transport::TNonblockingServerSocket(port));
+        server.reset(new server::TNonblockingServer(processor, socket));
+        server->setServerEventHandler(listenHandler);
+        if (userEventBase) {
+          server->registerEvents(userEventBase.get());
+        }
+        server->serve();
+      } catch (const transport::TTransportException&) {
+        if (retry_count > 0) {
+          ++port;
+          startServer(retry_count - 1);
+        } else {
+          throw;
+        }
+      }
+    }
+  };
+
+  struct EventDeleter {
+    void operator()(event_base* p) { event_base_free(p); }
+  };
+
+protected:
+  Fixture() : processor(new test::ParentServiceProcessor(make_shared<Handler>())) {}
+
+  ~Fixture() {
+    if (server) {
+      server->stop();
+    }
+    if (thread) {
+      thread->join();
+    }
+  }
+
+  void setEventBase(event_base* user_event_base) {
+    userEventBase_.reset(user_event_base, EventDeleter());
+  }
+
+  int startServer(int port) {
+    shared_ptr<Runner> runner(new Runner);
+    runner->port = port;
+    runner->processor = processor;
+    runner->userEventBase = userEventBase_;
+
+    shared_ptr<ThreadFactory> threadFactory(
+        new PlatformThreadFactory(
+#if !USE_STD_THREAD
+            PlatformThreadFactory::OTHER, PlatformThreadFactory::NORMAL,
+            1,
+#endif
+            false));
+    thread = threadFactory->newThread(runner);
+    thread->start();
+    runner->readyBarrier();
+
+    server = runner->server;
+    return runner->port;
+  }
+
+  bool canCommunicate(int serverPort) {
+    shared_ptr<transport::TSocket> socket(new transport::TSocket("localhost", serverPort));
+    socket->open();
+    test::ParentServiceClient client(make_shared<protocol::TBinaryProtocol>(
+        make_shared<transport::TFramedTransport>(socket)));
+    client.addString("foo");
+    std::vector<std::string> strings;
+    client.getStrings(strings);
+    return strings.size() == 1 && !(strings[0].compare("foo"));
+  }
+
+private:
+  shared_ptr<event_base> userEventBase_;
+  shared_ptr<test::ParentServiceProcessor> processor;
+protected:
+  shared_ptr<server::TNonblockingServer> server;
+private:
+  shared_ptr<apache::thrift::concurrency::Thread> thread;
+
+};
+
+BOOST_AUTO_TEST_SUITE(TNonblockingServerTest)
+
+BOOST_FIXTURE_TEST_CASE(get_specified_port, Fixture) {
+  int specified_port = startServer(12345);
+  BOOST_REQUIRE_GE(specified_port, 12345);
+  BOOST_REQUIRE_EQUAL(server->getListenPort(), specified_port);
+  BOOST_CHECK(canCommunicate(specified_port));
+
+  server->stop();
+}
+
+BOOST_FIXTURE_TEST_CASE(get_assigned_port, Fixture) {
+  int specified_port = startServer(0);
+  BOOST_REQUIRE_EQUAL(specified_port, 0);
+  int assigned_port = server->getListenPort();
+  BOOST_REQUIRE_NE(assigned_port, 0);
+  BOOST_CHECK(canCommunicate(assigned_port));
+
+  server->stop();
+}
+
+BOOST_FIXTURE_TEST_CASE(provide_event_base, Fixture) {
+  event_base* eb = event_base_new();
+  setEventBase(eb);
+  startServer(0);
+
+  // assert that the server works
+  BOOST_CHECK(canCommunicate(server->getListenPort()));
+#if LIBEVENT_VERSION_NUMBER > 0x02010400
+  // also assert that the event_base is actually used when it's easy
+  BOOST_CHECK_GT(event_base_get_num_events(eb, EVENT_BASE_COUNT_ADDED), 0);
+#endif
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/TPipeInterruptTest.cpp b/lib/cpp/test/TPipeInterruptTest.cpp
new file mode 100644
index 0000000..2423f56
--- /dev/null
+++ b/lib/cpp/test/TPipeInterruptTest.cpp
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifdef _WIN32
+
+#include <boost/test/test_tools.hpp>
+#include <boost/test/unit_test_suite.hpp>
+
+#include <boost/chrono/duration.hpp>
+#include <boost/date_time/posix_time/posix_time_duration.hpp>
+#include <boost/thread/thread.hpp>
+#include <thrift/transport/TPipe.h>
+#include <thrift/transport/TPipeServer.h>
+#include <memory>
+
+using apache::thrift::transport::TPipeServer;
+using apache::thrift::transport::TPipe;
+using apache::thrift::transport::TTransport;
+using apache::thrift::transport::TTransportException;
+using namespace apache::thrift;
+
+BOOST_AUTO_TEST_SUITE(TPipeInterruptTest)
+
+// TODO: duplicate the test cases in TSocketInterruptTest for pipes,
+// once pipes implement interruptChildren
+
+BOOST_AUTO_TEST_CASE(test_interrupt_before_accept) {
+  TPipeServer pipe1("TPipeInterruptTest");
+  pipe1.listen();
+  pipe1.interrupt();
+  BOOST_CHECK_THROW(pipe1.accept(), TTransportException);
+}
+
+static void acceptWorker(TPipeServer *pipe) {
+  try
+  {
+    for (;;)
+    {
+      std::shared_ptr<TTransport> temp = pipe->accept();
+    }
+  }
+  catch (...) {/*just want to make sure nothing crashes*/ }
+}
+
+static void interruptWorker(TPipeServer *pipe) {
+  boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+  pipe->interrupt();
+}
+
+BOOST_AUTO_TEST_CASE(stress_pipe_accept_interruption) {
+  int interruptIters = 10;
+
+  for (int i = 0; i < interruptIters; ++i)
+  {
+    TPipeServer pipeServer("TPipeInterruptTest");
+    pipeServer.listen();
+    boost::thread acceptThread(std::bind(acceptWorker, &pipeServer));
+    boost::thread interruptThread(std::bind(interruptWorker, &pipeServer));
+    try
+    {
+      for (;;)
+      {
+        TPipe client("TPipeInterruptTest");
+        client.setConnTimeout(1);
+        client.open();
+      }
+    } catch (...) { /*just testing for crashes*/ }
+    interruptThread.join();
+    acceptThread.join();
+  }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+#endif
diff --git a/lib/cpp/test/TPipedTransportTest.cpp b/lib/cpp/test/TPipedTransportTest.cpp
index 7762f05..f3091a4 100644
--- a/lib/cpp/test/TPipedTransportTest.cpp
+++ b/lib/cpp/test/TPipedTransportTest.cpp
@@ -17,37 +17,37 @@
  * under the License.
  */
 
-#include <cstdlib>
-#include <stdexcept>
 #include <thrift/Thrift.h>
+#include <memory>
 #include <thrift/transport/TTransportUtils.h>
 #include <thrift/transport/TBufferTransports.h>
-using namespace std;
+
+#define BOOST_TEST_MODULE TPipedTransportTest
+#include <boost/test/unit_test.hpp>
+
 using apache::thrift::transport::TTransportException;
 using apache::thrift::transport::TPipedTransport;
 using apache::thrift::transport::TMemoryBuffer;
+using namespace apache::thrift;
 
-int main() {
-  boost::shared_ptr<TMemoryBuffer> underlying(new TMemoryBuffer);
-  boost::shared_ptr<TMemoryBuffer> pipe(new TMemoryBuffer);
-  boost::shared_ptr<TPipedTransport> trans(new TPipedTransport(underlying, pipe));
+BOOST_AUTO_TEST_CASE(test_read_write) {
+  std::shared_ptr<TMemoryBuffer> underlying(new TMemoryBuffer);
+  std::shared_ptr<TMemoryBuffer> pipe(new TMemoryBuffer);
+  std::shared_ptr<TPipedTransport> trans(new TPipedTransport(underlying, pipe));
 
   uint8_t buffer[4];
 
   underlying->write((uint8_t*)"abcd", 4);
   trans->readAll(buffer, 2);
-  assert( string((char*)buffer, 2) == "ab" );
+  BOOST_CHECK(std::string((char*)buffer, 2) == "ab");
   trans->readEnd();
-  assert( pipe->getBufferAsString() == "ab" );
+  BOOST_CHECK(pipe->getBufferAsString() == "ab");
   pipe->resetBuffer();
   underlying->write((uint8_t*)"ef", 2);
   trans->readAll(buffer, 2);
-  assert( string((char*)buffer, 2) == "cd" );
+  BOOST_CHECK(std::string((char*)buffer, 2) == "cd");
   trans->readAll(buffer, 2);
-  assert( string((char*)buffer, 2) == "ef" );
+  BOOST_CHECK(std::string((char*)buffer, 2) == "ef");
   trans->readEnd();
-  assert( pipe->getBufferAsString() == "cdef" );
-
-  return 0;
-
+  BOOST_CHECK(pipe->getBufferAsString() == "cdef");
 }
diff --git a/lib/cpp/test/TSSLSocketInterruptTest.cpp b/lib/cpp/test/TSSLSocketInterruptTest.cpp
new file mode 100644
index 0000000..33f686c
--- /dev/null
+++ b/lib/cpp/test/TSSLSocketInterruptTest.cpp
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ */
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/unit_test_suite.hpp>
+#include <boost/chrono/duration.hpp>
+#include <boost/date_time/posix_time/posix_time_duration.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/format.hpp>
+#include <memory>
+#include <thrift/transport/TSSLSocket.h>
+#include <thrift/transport/TSSLServerSocket.h>
+#ifdef __linux__
+#include <signal.h>
+#endif
+
+using apache::thrift::transport::TSSLServerSocket;
+using apache::thrift::transport::TSSLSocket;
+using apache::thrift::transport::TTransport;
+using apache::thrift::transport::TTransportException;
+using apache::thrift::transport::TSSLSocketFactory;
+
+using std::static_pointer_cast;
+using std::shared_ptr;
+
+BOOST_AUTO_TEST_SUITE(TSSLSocketInterruptTest)
+
+boost::filesystem::path keyDir;
+boost::filesystem::path certFile(const std::string& filename)
+{
+  return keyDir / filename;
+}
+boost::mutex gMutex;
+
+struct GlobalFixtureSSL
+{
+    GlobalFixtureSSL()
+    {
+      using namespace boost::unit_test::framework;
+      for (int i = 0; i < master_test_suite().argc; ++i)
+      {
+        BOOST_TEST_MESSAGE(boost::format("argv[%1%] = \"%2%\"") % i % master_test_suite().argv[i]);
+      }
+
+#ifdef __linux__
+      // OpenSSL calls send() without MSG_NOSIGPIPE so writing to a socket that has
+      // disconnected can cause a SIGPIPE signal...
+      signal(SIGPIPE, SIG_IGN);
+#endif
+
+      TSSLSocketFactory::setManualOpenSSLInitialization(true);
+      apache::thrift::transport::initializeOpenSSL();
+
+      keyDir = boost::filesystem::current_path().parent_path().parent_path().parent_path() / "test" / "keys";
+      if (!boost::filesystem::exists(certFile("server.crt")))
+      {
+        keyDir = boost::filesystem::path(master_test_suite().argv[master_test_suite().argc - 1]);
+        if (!boost::filesystem::exists(certFile("server.crt")))
+        {
+          throw std::invalid_argument("The last argument to this test must be the directory containing the test certificate(s).");
+        }
+      }
+    }
+
+    virtual ~GlobalFixtureSSL()
+    {
+      apache::thrift::transport::cleanupOpenSSL();
+#ifdef __linux__
+      signal(SIGPIPE, SIG_DFL);
+#endif
+    }
+};
+
+#if (BOOST_VERSION >= 105900)
+BOOST_GLOBAL_FIXTURE(GlobalFixtureSSL);
+#else
+BOOST_GLOBAL_FIXTURE(GlobalFixtureSSL)
+#endif
+
+void readerWorker(shared_ptr<TTransport> tt, uint32_t expectedResult) {
+  uint8_t buf[4];
+  try {
+    tt->read(buf, 1);
+    BOOST_CHECK_EQUAL(expectedResult, tt->read(buf, 4));
+  } catch (const TTransportException& tx) {
+    BOOST_CHECK_EQUAL(TTransportException::TIMED_OUT, tx.getType());
+  }
+}
+
+void readerWorkerMustThrow(shared_ptr<TTransport> tt) {
+  try {
+    uint8_t buf[400];
+    tt->read(buf, 1);
+    tt->read(buf, 400);
+    BOOST_ERROR("should not have gotten here");
+  } catch (const TTransportException& tx) {
+    BOOST_CHECK_EQUAL(TTransportException::INTERRUPTED, tx.getType());
+  }
+}
+
+shared_ptr<TSSLSocketFactory> createServerSocketFactory() {
+  shared_ptr<TSSLSocketFactory> pServerSocketFactory;
+
+  pServerSocketFactory.reset(new TSSLSocketFactory());
+  pServerSocketFactory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
+  pServerSocketFactory->loadCertificate(certFile("server.crt").string().c_str());
+  pServerSocketFactory->loadPrivateKey(certFile("server.key").string().c_str());
+  pServerSocketFactory->server(true);
+  return pServerSocketFactory;
+}
+
+shared_ptr<TSSLSocketFactory> createClientSocketFactory() {
+  shared_ptr<TSSLSocketFactory> pClientSocketFactory;
+
+  pClientSocketFactory.reset(new TSSLSocketFactory());
+  pClientSocketFactory->authenticate(true);
+  pClientSocketFactory->loadCertificate(certFile("client.crt").string().c_str());
+  pClientSocketFactory->loadPrivateKey(certFile("client.key").string().c_str());
+  pClientSocketFactory->loadTrustedCertificates(certFile("CA.pem").string().c_str());
+  return pClientSocketFactory;
+}
+
+BOOST_AUTO_TEST_CASE(test_ssl_interruptable_child_read_while_handshaking) {
+  shared_ptr<TSSLSocketFactory> pServerSocketFactory = createServerSocketFactory();
+  TSSLServerSocket sock1("localhost", 0, pServerSocketFactory);
+  sock1.listen();
+  int port = sock1.getPort();
+  shared_ptr<TSSLSocketFactory> pClientSocketFactory = createClientSocketFactory();
+  shared_ptr<TSSLSocket> clientSock = pClientSocketFactory->createSocket("localhost", port);
+  clientSock->open();
+  shared_ptr<TTransport> accepted = sock1.accept();
+  boost::thread readThread(std::bind(readerWorkerMustThrow, accepted));
+  boost::this_thread::sleep(boost::posix_time::milliseconds(50));
+  // readThread is practically guaranteed to be blocking now
+  sock1.interruptChildren();
+  BOOST_CHECK_MESSAGE(readThread.try_join_for(boost::chrono::milliseconds(20)),
+  "server socket interruptChildren did not interrupt child read");
+  clientSock->close();
+  accepted->close();
+  sock1.close();
+}
+
+BOOST_AUTO_TEST_CASE(test_ssl_interruptable_child_read) {
+  shared_ptr<TSSLSocketFactory> pServerSocketFactory = createServerSocketFactory();
+  TSSLServerSocket sock1("localhost", 0, pServerSocketFactory);
+  sock1.listen();
+  int port = sock1.getPort();
+  shared_ptr<TSSLSocketFactory> pClientSocketFactory = createClientSocketFactory();
+  shared_ptr<TSSLSocket> clientSock = pClientSocketFactory->createSocket("localhost", port);
+  clientSock->open();
+  shared_ptr<TTransport> accepted = sock1.accept();
+  boost::thread readThread(std::bind(readerWorkerMustThrow, accepted));
+  clientSock->write((const uint8_t*)"0", 1);
+  boost::this_thread::sleep(boost::posix_time::milliseconds(50));
+  // readThread is practically guaranteed to be blocking now
+  sock1.interruptChildren();
+  BOOST_CHECK_MESSAGE(readThread.try_join_for(boost::chrono::milliseconds(20)),
+                      "server socket interruptChildren did not interrupt child read");
+  accepted->close();
+  clientSock->close();
+  sock1.close();
+}
+
+BOOST_AUTO_TEST_CASE(test_ssl_non_interruptable_child_read) {
+  shared_ptr<TSSLSocketFactory> pServerSocketFactory = createServerSocketFactory();
+  TSSLServerSocket sock1("localhost", 0, pServerSocketFactory);
+  sock1.setInterruptableChildren(false); // returns to pre-THRIFT-2441 behavior
+  sock1.listen();
+  int port = sock1.getPort();
+  shared_ptr<TSSLSocketFactory> pClientSocketFactory = createClientSocketFactory();
+  shared_ptr<TSSLSocket> clientSock = pClientSocketFactory->createSocket("localhost", port);
+  clientSock->open();
+  shared_ptr<TTransport> accepted = sock1.accept();
+  static_pointer_cast<TSSLSocket>(accepted)->setRecvTimeout(1000);
+  boost::thread readThread(std::bind(readerWorker, accepted, 0));
+  clientSock->write((const uint8_t*)"0", 1);
+  boost::this_thread::sleep(boost::posix_time::milliseconds(50));
+  // readThread is practically guaranteed to be blocking here
+  sock1.interruptChildren();
+  BOOST_CHECK_MESSAGE(!readThread.try_join_for(boost::chrono::milliseconds(200)),
+                      "server socket interruptChildren interrupted child read");
+
+  // wait for receive timeout to kick in
+  readThread.join();
+  accepted->close();
+  clientSock->close();
+  sock1.close();
+}
+
+BOOST_AUTO_TEST_CASE(test_ssl_cannot_change_after_listen) {
+  shared_ptr<TSSLSocketFactory> pServerSocketFactory = createServerSocketFactory();
+  TSSLServerSocket sock1("localhost", 0, pServerSocketFactory);
+  sock1.listen();
+  BOOST_CHECK_THROW(sock1.setInterruptableChildren(false), std::logic_error);
+  sock1.close();
+}
+
+void peekerWorker(shared_ptr<TTransport> tt, bool expectedResult) {
+  uint8_t buf[400];
+  try {
+    tt->read(buf, 1);
+    BOOST_CHECK_EQUAL(expectedResult, tt->peek());
+  } catch (const TTransportException& tx) {
+    BOOST_CHECK_EQUAL(TTransportException::TIMED_OUT, tx.getType());
+  }
+}
+
+void peekerWorkerInterrupt(shared_ptr<TTransport> tt) {
+  uint8_t buf[400];
+  try {
+    tt->read(buf, 1);
+    tt->peek();
+  } catch (const TTransportException& tx) {
+    BOOST_CHECK_EQUAL(TTransportException::INTERRUPTED, tx.getType());
+  }
+}
+
+BOOST_AUTO_TEST_CASE(test_ssl_interruptable_child_peek) {
+  shared_ptr<TSSLSocketFactory> pServerSocketFactory = createServerSocketFactory();
+  TSSLServerSocket sock1("localhost", 0, pServerSocketFactory);
+  sock1.listen();
+  int port = sock1.getPort();
+  shared_ptr<TSSLSocketFactory> pClientSocketFactory = createClientSocketFactory();
+  shared_ptr<TSSLSocket> clientSock = pClientSocketFactory->createSocket("localhost", port);
+  clientSock->open();
+  shared_ptr<TTransport> accepted = sock1.accept();
+  boost::thread peekThread(std::bind(peekerWorkerInterrupt, accepted));
+  clientSock->write((const uint8_t*)"0", 1);
+  boost::this_thread::sleep(boost::posix_time::milliseconds(50));
+  // peekThread is practically guaranteed to be blocking now
+  sock1.interruptChildren();
+  BOOST_CHECK_MESSAGE(peekThread.try_join_for(boost::chrono::milliseconds(200)),
+                      "server socket interruptChildren did not interrupt child peek");
+  accepted->close();
+  clientSock->close();
+  sock1.close();
+}
+
+BOOST_AUTO_TEST_CASE(test_ssl_non_interruptable_child_peek) {
+  shared_ptr<TSSLSocketFactory> pServerSocketFactory = createServerSocketFactory();
+  TSSLServerSocket sock1("localhost", 0, pServerSocketFactory);
+  sock1.setInterruptableChildren(false); // returns to pre-THRIFT-2441 behavior
+  sock1.listen();
+  int port = sock1.getPort();
+  shared_ptr<TSSLSocketFactory> pClientSocketFactory = createClientSocketFactory();
+  shared_ptr<TSSLSocket> clientSock = pClientSocketFactory->createSocket("localhost", port);
+  clientSock->open();
+  shared_ptr<TTransport> accepted = sock1.accept();
+  static_pointer_cast<TSSLSocket>(accepted)->setRecvTimeout(1000);
+  boost::thread peekThread(std::bind(peekerWorker, accepted, false));
+  clientSock->write((const uint8_t*)"0", 1);
+  boost::this_thread::sleep(boost::posix_time::milliseconds(50));
+  // peekThread is practically guaranteed to be blocking now
+  sock1.interruptChildren();
+  BOOST_CHECK_MESSAGE(!peekThread.try_join_for(boost::chrono::milliseconds(200)),
+                      "server socket interruptChildren interrupted child peek");
+
+  // wait for the receive timeout to kick in
+  peekThread.join();
+  accepted->close();
+  clientSock->close();
+  sock1.close();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/TServerIntegrationTest.cpp b/lib/cpp/test/TServerIntegrationTest.cpp
new file mode 100644
index 0000000..7976c8b
--- /dev/null
+++ b/lib/cpp/test/TServerIntegrationTest.cpp
@@ -0,0 +1,536 @@
+/*
+ * 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.
+ */
+
+#define BOOST_TEST_MODULE TServerIntegrationTest
+#include <atomic>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/date_time/posix_time/ptime.hpp>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <boost/thread.hpp>
+#include <thrift/server/TSimpleServer.h>
+#include <thrift/server/TThreadPoolServer.h>
+#include <thrift/server/TThreadedServer.h>
+#include <memory>
+#include <thrift/protocol/TBinaryProtocol.h>
+#include <thrift/transport/TServerSocket.h>
+#include <thrift/transport/TSocket.h>
+#include <thrift/transport/TTransport.h>
+#include "gen-cpp/ParentService.h"
+#include <string>
+#include <vector>
+
+using apache::thrift::concurrency::Guard;
+using apache::thrift::concurrency::Monitor;
+using apache::thrift::concurrency::Mutex;
+using apache::thrift::concurrency::Synchronized;
+using apache::thrift::protocol::TBinaryProtocol;
+using apache::thrift::protocol::TBinaryProtocolFactory;
+using apache::thrift::protocol::TProtocol;
+using apache::thrift::protocol::TProtocolFactory;
+using apache::thrift::transport::TServerSocket;
+using apache::thrift::transport::TServerTransport;
+using apache::thrift::transport::TSocket;
+using apache::thrift::transport::TTransport;
+using apache::thrift::transport::TTransportException;
+using apache::thrift::transport::TTransportFactory;
+using apache::thrift::server::TServer;
+using apache::thrift::server::TServerEventHandler;
+using apache::thrift::server::TSimpleServer;
+using apache::thrift::server::TThreadPoolServer;
+using apache::thrift::server::TThreadedServer;
+using std::dynamic_pointer_cast;
+using std::make_shared;
+using std::shared_ptr;
+using apache::thrift::test::ParentServiceClient;
+using apache::thrift::test::ParentServiceIf;
+using apache::thrift::test::ParentServiceIfFactory;
+using apache::thrift::test::ParentServiceIfSingletonFactory;
+using apache::thrift::test::ParentServiceProcessor;
+using apache::thrift::test::ParentServiceProcessorFactory;
+using apache::thrift::TProcessor;
+using apache::thrift::TProcessorFactory;
+using boost::posix_time::milliseconds;
+
+/**
+ * preServe runs after listen() is successful, when we can connect
+ */
+class TServerReadyEventHandler : public TServerEventHandler, public Monitor {
+public:
+  TServerReadyEventHandler() : isListening_(false), accepted_(0) {}
+  virtual ~TServerReadyEventHandler() {}
+  virtual void preServe() {
+    Synchronized sync(*this);
+    isListening_ = true;
+    notify();
+  }
+  virtual void* createContext(shared_ptr<TProtocol> input,
+                              shared_ptr<TProtocol> output) {
+    Synchronized sync(*this);
+    ++accepted_;
+    notify();
+
+    (void)input;
+    (void)output;
+    return NULL;
+  }
+  bool isListening() const { return isListening_; }
+  uint64_t acceptedCount() const { return accepted_; }
+
+private:
+  bool isListening_;
+  uint64_t accepted_;
+};
+
+/**
+ * Reusing another generated test, just something to serve up
+ */
+class ParentHandler : public ParentServiceIf {
+public:
+  ParentHandler() : generation_(0) {}
+
+  int32_t incrementGeneration() {
+    Guard g(mutex_);
+    return ++generation_;
+  }
+
+  int32_t getGeneration() {
+    Guard g(mutex_);
+    return generation_;
+  }
+
+  void addString(const std::string& s) {
+    Guard g(mutex_);
+    strings_.push_back(s);
+  }
+
+  void getStrings(std::vector<std::string>& _return) {
+    Guard g(mutex_);
+    _return = strings_;
+  }
+
+  void getDataWait(std::string& _return, const int32_t length) {
+    THRIFT_UNUSED_VARIABLE(_return);
+    THRIFT_UNUSED_VARIABLE(length);
+  }
+
+  void onewayWait() {}
+
+  void exceptionWait(const std::string& message) { THRIFT_UNUSED_VARIABLE(message); }
+
+  void unexpectedExceptionWait(const std::string& message) { THRIFT_UNUSED_VARIABLE(message); }
+
+protected:
+  Mutex mutex_;
+  int32_t generation_;
+  std::vector<std::string> strings_;
+};
+
+void autoSocketCloser(TSocket* pSock) {
+  pSock->close();
+  delete pSock;
+}
+
+template <class TServerType>
+class TServerIntegrationTestFixture {
+public:
+  TServerIntegrationTestFixture(const shared_ptr<TProcessorFactory>& _processorFactory)
+    : pServer(new TServerType(_processorFactory,
+                              shared_ptr<TServerTransport>(
+                                  new TServerSocket("localhost", 0)),
+                              shared_ptr<TTransportFactory>(new TTransportFactory),
+                              shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory))),
+      pEventHandler(shared_ptr<TServerReadyEventHandler>(new TServerReadyEventHandler)),
+    bStressDone(false),
+    bStressConnectionCount(0),
+    bStressRequestCount(0) {
+    pServer->setServerEventHandler(pEventHandler);
+  }
+
+  TServerIntegrationTestFixture(const shared_ptr<TProcessor>& _processor)
+    : pServer(
+          new TServerType(_processor,
+                          shared_ptr<TServerTransport>(new TServerSocket("localhost", 0)),
+                          shared_ptr<TTransportFactory>(new TTransportFactory),
+                          shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory))),
+      pEventHandler(shared_ptr<TServerReadyEventHandler>(new TServerReadyEventHandler)),
+      bStressDone(false),
+    bStressConnectionCount(0),
+    bStressRequestCount(0) {
+    pServer->setServerEventHandler(pEventHandler);
+  }
+
+  void startServer() {
+    pServerThread.reset(new boost::thread(std::bind(&TServerType::serve, pServer.get())));
+
+    // block until listen() completes so clients will be able to connect
+    Synchronized sync(*(pEventHandler.get()));
+    while (!pEventHandler->isListening()) {
+      pEventHandler->wait();
+    }
+
+    BOOST_TEST_MESSAGE("  server is listening");
+  }
+
+  void blockUntilAccepted(uint64_t numAccepted) {
+    Synchronized sync(*(pEventHandler.get()));
+    while (pEventHandler->acceptedCount() < numAccepted) {
+      pEventHandler->wait();
+    }
+
+    BOOST_TEST_MESSAGE(boost::format("  server has accepted %1%") % numAccepted);
+  }
+
+  void stopServer() {
+    if (pServerThread) {
+      pServer->stop();
+      BOOST_TEST_MESSAGE("  server stop completed");
+
+      pServerThread->join();
+      BOOST_TEST_MESSAGE("  server thread joined");
+      pServerThread.reset();
+    }
+  }
+
+  ~TServerIntegrationTestFixture() { stopServer(); }
+
+  /**
+   * Performs a baseline test where some clients are opened and issue a single operation
+   * and then disconnect at different intervals.
+   * \param[in]  numToMake  the number of concurrent clients
+   * \param[in]  expectedHWM  the high water mark we expect of concurrency
+   * \param[in]  purpose  a description of the test for logging purposes
+   */
+  void baseline(int64_t numToMake, int64_t expectedHWM, const std::string& purpose) {
+    BOOST_TEST_MESSAGE(boost::format("Testing %1%: %2% with %3% clients, expect %4% HWM")
+            % typeid(TServerType).name() % purpose % numToMake % expectedHWM);
+
+    startServer();
+
+    std::vector<shared_ptr<TSocket> > holdSockets;
+    std::vector<shared_ptr<boost::thread> > holdThreads;
+
+    for (int64_t i = 0; i < numToMake; ++i) {
+      shared_ptr<TSocket> pClientSock(new TSocket("localhost", getServerPort()),
+                                             autoSocketCloser);
+      holdSockets.push_back(pClientSock);
+      shared_ptr<TProtocol> pClientProtocol(new TBinaryProtocol(pClientSock));
+      ParentServiceClient client(pClientProtocol);
+      pClientSock->open();
+      client.incrementGeneration();
+      holdThreads.push_back(shared_ptr<boost::thread>(
+          new boost::thread(std::bind(&TServerIntegrationTestFixture::delayClose,
+                                        this,
+                                        pClientSock,
+                                        milliseconds(10 * numToMake)))));
+    }
+
+    BOOST_CHECK_EQUAL(expectedHWM, pServer->getConcurrentClientCountHWM());
+
+    BOOST_FOREACH (shared_ptr<boost::thread> pThread, holdThreads) { pThread->join(); }
+    holdThreads.clear();
+    holdSockets.clear();
+
+    stopServer();
+  }
+
+  /**
+   * Helper method used to close a connection after a delay.
+   * \param[in]  toClose  the connection to close
+   * \param[in]  after  the delay to impose
+   */
+  void delayClose(shared_ptr<TTransport> toClose, boost::posix_time::time_duration after) {
+    boost::this_thread::sleep(after);
+    toClose->close();
+  }
+
+  /**
+   * \returns  the server port number
+   */
+  int getServerPort() {
+    TServerSocket* pSock = dynamic_cast<TServerSocket*>(pServer->getServerTransport().get());
+    if (!pSock) { throw std::logic_error("how come?"); }
+    return pSock->getPort();
+  }
+
+  /**
+   * Performs a stress test by spawning threads that connect, do a number of operations
+   * and disconnect, then a random delay, then do it over again.  This is done for a fixed
+   * period of time to test for concurrency correctness.
+   * \param[in]  numToMake  the number of concurrent clients
+   */
+  void stress(int64_t numToMake, const boost::posix_time::time_duration& duration) {
+    BOOST_TEST_MESSAGE(boost::format("Stress testing %1% with %2% clients for %3% seconds")
+        % typeid(TServerType).name() % numToMake % duration.total_seconds());
+
+    startServer();
+
+    std::vector<shared_ptr<boost::thread> > holdThreads;
+    for (int64_t i = 0; i < numToMake; ++i) {
+      holdThreads.push_back(shared_ptr<boost::thread>(
+        new boost::thread(std::bind(&TServerIntegrationTestFixture::stressor, this))));
+    }
+
+    boost::this_thread::sleep(duration);
+    bStressDone = true;
+
+    BOOST_TEST_MESSAGE(boost::format("  serviced %1% connections (HWM %2%) totaling %3% requests")
+        % bStressConnectionCount % pServer->getConcurrentClientCountHWM() % bStressRequestCount);
+
+    BOOST_FOREACH (shared_ptr<boost::thread> pThread, holdThreads) { pThread->join(); }
+    holdThreads.clear();
+
+    BOOST_CHECK(bStressRequestCount > 0);
+
+    stopServer();
+  }
+
+  /**
+   * Helper method to stress the system
+   */
+  void stressor() {
+  while (!bStressDone) {
+      shared_ptr<TSocket> pSocket(new TSocket("localhost", getServerPort()), autoSocketCloser);
+      shared_ptr<TProtocol> pProtocol(new TBinaryProtocol(pSocket));
+      ParentServiceClient client(pProtocol);
+      pSocket->open();
+      bStressConnectionCount.fetch_add(1, std::memory_order_relaxed);
+      for (int i = 0; i < rand() % 1000; ++i) {
+      client.incrementGeneration();
+        bStressRequestCount.fetch_add(1, std::memory_order_relaxed);
+      }
+    }
+  }
+
+  shared_ptr<TServerType> pServer;
+  shared_ptr<TServerReadyEventHandler> pEventHandler;
+  shared_ptr<boost::thread> pServerThread;
+  std::atomic<bool> bStressDone;
+  std::atomic<int64_t> bStressConnectionCount;
+  std::atomic<int64_t> bStressRequestCount;
+};
+
+template <class TServerType>
+class TServerIntegrationProcessorFactoryTestFixture
+    : public TServerIntegrationTestFixture<TServerType> {
+public:
+  TServerIntegrationProcessorFactoryTestFixture()
+    : TServerIntegrationTestFixture<TServerType>(make_shared<ParentServiceProcessorFactory>(
+          make_shared<ParentServiceIfSingletonFactory>(
+              make_shared<ParentHandler>()))) {}
+};
+
+template <class TServerType>
+class TServerIntegrationProcessorTestFixture : public TServerIntegrationTestFixture<TServerType> {
+public:
+  TServerIntegrationProcessorTestFixture()
+    : TServerIntegrationTestFixture<TServerType>(
+          make_shared<ParentServiceProcessor>(make_shared<ParentHandler>())) {}
+};
+
+BOOST_AUTO_TEST_SUITE(constructors)
+
+BOOST_FIXTURE_TEST_CASE(test_simple_factory,
+                        TServerIntegrationProcessorFactoryTestFixture<TSimpleServer>) {
+  baseline(3, 1, "factory");
+}
+
+BOOST_FIXTURE_TEST_CASE(test_simple, TServerIntegrationProcessorTestFixture<TSimpleServer>) {
+  baseline(3, 1, "processor");
+}
+
+BOOST_FIXTURE_TEST_CASE(test_threaded_factory,
+                        TServerIntegrationProcessorFactoryTestFixture<TThreadedServer>) {
+  baseline(10, 10, "factory");
+}
+
+BOOST_FIXTURE_TEST_CASE(test_threaded, TServerIntegrationProcessorTestFixture<TThreadedServer>) {
+  baseline(10, 10, "processor");
+}
+
+BOOST_FIXTURE_TEST_CASE(test_threaded_bound,
+                        TServerIntegrationProcessorTestFixture<TThreadedServer>) {
+  pServer->setConcurrentClientLimit(4);
+  baseline(10, 4, "limit by server framework");
+}
+
+BOOST_FIXTURE_TEST_CASE(test_threaded_stress,
+                        TServerIntegrationProcessorFactoryTestFixture<TThreadedServer>) {
+  stress(10, boost::posix_time::seconds(3));
+}
+
+BOOST_FIXTURE_TEST_CASE(test_threadpool_factory,
+                        TServerIntegrationProcessorFactoryTestFixture<TThreadPoolServer>) {
+  pServer->getThreadManager()->threadFactory(
+      shared_ptr<apache::thrift::concurrency::ThreadFactory>(
+          new apache::thrift::concurrency::PlatformThreadFactory));
+  pServer->getThreadManager()->start();
+
+  // thread factory has 4 threads as a default
+  // thread factory however is a bad way to limit concurrent clients
+  // as accept() will be called to grab a 5th client socket, in this case
+  // and then the thread factory will block adding the thread to manage
+  // that client.
+  baseline(10, 5, "limit by thread manager");
+}
+
+BOOST_FIXTURE_TEST_CASE(test_threadpool,
+                        TServerIntegrationProcessorTestFixture<TThreadPoolServer>) {
+  pServer->getThreadManager()->threadFactory(
+      shared_ptr<apache::thrift::concurrency::ThreadFactory>(
+          new apache::thrift::concurrency::PlatformThreadFactory));
+  pServer->getThreadManager()->start();
+
+  // thread factory has 4 threads as a default
+  // thread factory however is a bad way to limit concurrent clients
+  // as accept() will be called to grab a 5th client socket, in this case
+  // and then the thread factory will block adding the thread to manage
+  // that client.
+  baseline(10, 5, "limit by thread manager");
+}
+
+BOOST_FIXTURE_TEST_CASE(test_threadpool_bound,
+                        TServerIntegrationProcessorTestFixture<TThreadPoolServer>) {
+  pServer->getThreadManager()->threadFactory(
+      shared_ptr<apache::thrift::concurrency::ThreadFactory>(
+          new apache::thrift::concurrency::PlatformThreadFactory));
+  pServer->getThreadManager()->start();
+  pServer->setConcurrentClientLimit(4);
+
+  baseline(10, 4, "server framework connection limit");
+}
+
+BOOST_FIXTURE_TEST_CASE(test_threadpool_stress,
+                        TServerIntegrationProcessorTestFixture<TThreadPoolServer>) {
+  pServer->getThreadManager()->threadFactory(
+      shared_ptr<apache::thrift::concurrency::ThreadFactory>(
+          new apache::thrift::concurrency::PlatformThreadFactory));
+  pServer->getThreadManager()->start();
+
+  stress(10, boost::posix_time::seconds(3));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_FIXTURE_TEST_SUITE(TServerIntegrationTest,
+                         TServerIntegrationProcessorTestFixture<TThreadedServer>)
+
+BOOST_AUTO_TEST_CASE(test_stop_with_interruptable_clients_connected) {
+  // This tests THRIFT-2441 new behavior: stopping the server disconnects clients
+  BOOST_TEST_MESSAGE("Testing stop with interruptable clients");
+
+  startServer();
+
+  shared_ptr<TSocket> pClientSock1(new TSocket("localhost", getServerPort()),
+                                          autoSocketCloser);
+  pClientSock1->open();
+
+  shared_ptr<TSocket> pClientSock2(new TSocket("localhost", getServerPort()),
+                                          autoSocketCloser);
+  pClientSock2->open();
+
+  // Ensure they have been accepted
+  blockUntilAccepted(2);
+
+  // The test fixture destructor will force the sockets to disconnect
+  // Prior to THRIFT-2441, pServer->stop() would hang until clients disconnected
+  stopServer();
+
+  // extra proof the server end disconnected the clients
+  uint8_t buf[1];
+  BOOST_CHECK_EQUAL(0, pClientSock1->read(&buf[0], 1)); // 0 = disconnected
+  BOOST_CHECK_EQUAL(0, pClientSock2->read(&buf[0], 1)); // 0 = disconnected
+}
+
+BOOST_AUTO_TEST_CASE(test_stop_with_uninterruptable_clients_connected) {
+  // This tests pre-THRIFT-2441 behavior: stopping the server blocks until clients
+  // disconnect.
+    BOOST_TEST_MESSAGE("Testing stop with uninterruptable clients");
+
+  dynamic_pointer_cast<TServerSocket>(pServer->getServerTransport())
+      ->setInterruptableChildren(false); // returns to pre-THRIFT-2441 behavior
+
+  startServer();
+
+  shared_ptr<TSocket> pClientSock1(new TSocket("localhost", getServerPort()),
+                                          autoSocketCloser);
+  pClientSock1->open();
+
+  shared_ptr<TSocket> pClientSock2(new TSocket("localhost", getServerPort()),
+                                          autoSocketCloser);
+  pClientSock2->open();
+
+  // Ensure they have been accepted
+  blockUntilAccepted(2);
+
+  boost::thread t1(std::bind(&TServerIntegrationTestFixture::delayClose,
+                               this,
+                               pClientSock1,
+                               milliseconds(250)));
+  boost::thread t2(std::bind(&TServerIntegrationTestFixture::delayClose,
+                               this,
+                               pClientSock2,
+                               milliseconds(250)));
+
+  // Once the clients disconnect the server will stop
+  stopServer();
+  BOOST_CHECK(pServer->getConcurrentClientCountHWM() > 0);
+  t1.join();
+  t2.join();
+}
+
+BOOST_AUTO_TEST_CASE(test_concurrent_client_limit) {
+  startServer();
+  BOOST_TEST_MESSAGE("Testing the concurrent client limit");
+
+  BOOST_CHECK_EQUAL(INT64_MAX, pServer->getConcurrentClientLimit());
+  pServer->setConcurrentClientLimit(2);
+  BOOST_CHECK_EQUAL(0, pServer->getConcurrentClientCount());
+  BOOST_CHECK_EQUAL(2, pServer->getConcurrentClientLimit());
+
+  shared_ptr<TSocket> pClientSock1(new TSocket("localhost", getServerPort()),
+                                          autoSocketCloser);
+  pClientSock1->open();
+  blockUntilAccepted(1);
+  BOOST_CHECK_EQUAL(1, pServer->getConcurrentClientCount());
+
+  shared_ptr<TSocket> pClientSock2(new TSocket("localhost", getServerPort()),
+                                          autoSocketCloser);
+  pClientSock2->open();
+  blockUntilAccepted(2);
+  BOOST_CHECK_EQUAL(2, pServer->getConcurrentClientCount());
+
+  // a third client cannot connect until one of the other two closes
+  boost::thread t2(std::bind(&TServerIntegrationTestFixture::delayClose,
+                               this,
+                               pClientSock2,
+                               milliseconds(250)));
+  shared_ptr<TSocket> pClientSock3(new TSocket("localhost", getServerPort()),
+                                          autoSocketCloser);
+  pClientSock2->open();
+  blockUntilAccepted(2);
+  BOOST_CHECK_EQUAL(2, pServer->getConcurrentClientCount());
+  BOOST_CHECK_EQUAL(2, pServer->getConcurrentClientCountHWM());
+
+  stopServer();
+  BOOST_CHECK(pServer->getConcurrentClientCountHWM() > 0);
+  t2.join();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/TServerSocketTest.cpp b/lib/cpp/test/TServerSocketTest.cpp
new file mode 100644
index 0000000..bec6d47
--- /dev/null
+++ b/lib/cpp/test/TServerSocketTest.cpp
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <boost/test/auto_unit_test.hpp>
+#include <thrift/transport/TSocket.h>
+#include <thrift/transport/TServerSocket.h>
+#include <memory>
+#include "TTransportCheckThrow.h"
+#include <iostream>
+
+using apache::thrift::transport::TServerSocket;
+using apache::thrift::transport::TSocket;
+using apache::thrift::transport::TTransport;
+using apache::thrift::transport::TTransportException;
+using std::shared_ptr;
+
+BOOST_AUTO_TEST_SUITE(TServerSocketTest)
+
+BOOST_AUTO_TEST_CASE(test_bind_to_address) {
+  TServerSocket sock1("localhost", 0);
+  sock1.listen();
+  int port = sock1.getPort();
+  TSocket clientSock("localhost", port);
+  clientSock.open();
+  shared_ptr<TTransport> accepted = sock1.accept();
+  accepted->close();
+  sock1.close();
+
+  std::cout << "An error message from getaddrinfo on the console is expected:" << std::endl;
+  TServerSocket sock2("257.258.259.260", 0);
+  BOOST_CHECK_THROW(sock2.listen(), TTransportException);
+  sock2.close();
+}
+
+BOOST_AUTO_TEST_CASE(test_listen_valid_port) {
+  TServerSocket sock1(-1);
+  TTRANSPORT_CHECK_THROW(sock1.listen(), TTransportException::BAD_ARGS);
+
+  TServerSocket sock2(65536);
+  TTRANSPORT_CHECK_THROW(sock2.listen(), TTransportException::BAD_ARGS);
+}
+
+BOOST_AUTO_TEST_CASE(test_close_before_listen) {
+  TServerSocket sock1("localhost", 0);
+  sock1.close();
+}
+
+BOOST_AUTO_TEST_CASE(test_get_port) {
+  TServerSocket sock1("localHost", 888);
+  BOOST_CHECK_EQUAL(888, sock1.getPort());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/TServerTransportTest.cpp b/lib/cpp/test/TServerTransportTest.cpp
new file mode 100644
index 0000000..539bd28
--- /dev/null
+++ b/lib/cpp/test/TServerTransportTest.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include <boost/test/auto_unit_test.hpp>
+#include <thrift/transport/TSocket.h>
+#include <thrift/transport/TServerTransport.h>
+#include <memory>
+
+using apache::thrift::transport::TServerTransport;
+using apache::thrift::transport::TTransport;
+using apache::thrift::transport::TTransportException;
+using std::shared_ptr;
+
+BOOST_AUTO_TEST_SUITE(TServerTransportTest)
+
+class TestTTransport : public TTransport {};
+
+class TestTServerTransport : public TServerTransport {
+public:
+  TestTServerTransport() : valid_(true) {}
+  void close() {}
+  bool valid_;
+
+protected:
+  shared_ptr<TTransport> acceptImpl() {
+    return valid_ ? shared_ptr<TestTTransport>(new TestTTransport)
+                  : shared_ptr<TestTTransport>();
+  }
+};
+
+BOOST_AUTO_TEST_CASE(test_positive_accept) {
+  TestTServerTransport uut;
+  BOOST_CHECK(uut.accept());
+}
+
+BOOST_AUTO_TEST_CASE(test_negative_accept) {
+  TestTServerTransport uut;
+  uut.valid_ = false;
+  BOOST_CHECK_THROW(uut.accept(), TTransportException);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/TSocketInterruptTest.cpp b/lib/cpp/test/TSocketInterruptTest.cpp
new file mode 100644
index 0000000..366242f
--- /dev/null
+++ b/lib/cpp/test/TSocketInterruptTest.cpp
@@ -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.
+ */
+
+#define BOOST_TEST_MODULE TSocketInterruptTest
+#include <boost/test/auto_unit_test.hpp>
+
+#include <boost/chrono/duration.hpp>
+#include <boost/date_time/posix_time/posix_time_duration.hpp>
+#include <boost/thread/thread.hpp>
+#include <thrift/transport/TSocket.h>
+#include <thrift/transport/TServerSocket.h>
+#include <memory>
+
+using apache::thrift::transport::TServerSocket;
+using apache::thrift::transport::TSocket;
+using apache::thrift::transport::TTransport;
+using apache::thrift::transport::TTransportException;
+using namespace apache::thrift;
+
+BOOST_AUTO_TEST_SUITE(TSocketInterruptTest)
+
+void readerWorker(std::shared_ptr<TTransport> tt, uint32_t expectedResult) {
+  uint8_t buf[4];
+  BOOST_CHECK_EQUAL(expectedResult, tt->read(buf, 4));
+}
+
+void readerWorkerMustThrow(std::shared_ptr<TTransport> tt) {
+  try {
+    uint8_t buf[4];
+    tt->read(buf, 4);
+    BOOST_ERROR("should not have gotten here");
+  } catch (const TTransportException& tx) {
+    BOOST_CHECK_EQUAL(TTransportException::INTERRUPTED, tx.getType());
+  }
+}
+
+BOOST_AUTO_TEST_CASE(test_interruptable_child_read) {
+  TServerSocket sock1("localhost", 0);
+  sock1.listen();
+  int port = sock1.getPort();
+  TSocket clientSock("localhost", port);
+  clientSock.open();
+  std::shared_ptr<TTransport> accepted = sock1.accept();
+  boost::thread readThread(std::bind(readerWorkerMustThrow, accepted));
+  boost::this_thread::sleep(boost::posix_time::milliseconds(50));
+  // readThread is practically guaranteed to be blocking now
+  sock1.interruptChildren();
+  BOOST_CHECK_MESSAGE(readThread.try_join_for(boost::chrono::milliseconds(200)),
+                      "server socket interruptChildren did not interrupt child read");
+  clientSock.close();
+  accepted->close();
+  sock1.close();
+}
+
+BOOST_AUTO_TEST_CASE(test_non_interruptable_child_read) {
+  TServerSocket sock1("localhost", 0);
+  sock1.setInterruptableChildren(false); // returns to pre-THRIFT-2441 behavior
+  sock1.listen();
+  int port = sock1.getPort();
+  TSocket clientSock("localhost", port);
+  clientSock.open();
+  std::shared_ptr<TTransport> accepted = sock1.accept();
+  boost::thread readThread(std::bind(readerWorker, accepted, 0));
+  boost::this_thread::sleep(boost::posix_time::milliseconds(50));
+  // readThread is practically guaranteed to be blocking here
+  sock1.interruptChildren();
+  BOOST_CHECK_MESSAGE(!readThread.try_join_for(boost::chrono::milliseconds(200)),
+                      "server socket interruptChildren interrupted child read");
+
+  // only way to proceed is to have the client disconnect
+  clientSock.close();
+  readThread.join();
+  accepted->close();
+  sock1.close();
+}
+
+BOOST_AUTO_TEST_CASE(test_cannot_change_after_listen) {
+  TServerSocket sock1("localhost", 0);
+  sock1.listen();
+  BOOST_CHECK_THROW(sock1.setInterruptableChildren(false), std::logic_error);
+  sock1.close();
+}
+
+void peekerWorker(std::shared_ptr<TTransport> tt, bool expectedResult) {
+  BOOST_CHECK_EQUAL(expectedResult, tt->peek());
+}
+
+BOOST_AUTO_TEST_CASE(test_interruptable_child_peek) {
+  TServerSocket sock1("localhost", 0);
+  sock1.listen();
+  int port = sock1.getPort();
+  TSocket clientSock("localhost", port);
+  clientSock.open();
+  std::shared_ptr<TTransport> accepted = sock1.accept();
+  // peek() will return false if child is interrupted
+  boost::thread peekThread(std::bind(peekerWorker, accepted, false));
+  boost::this_thread::sleep(boost::posix_time::milliseconds(50));
+  // peekThread is practically guaranteed to be blocking now
+  sock1.interruptChildren();
+  BOOST_CHECK_MESSAGE(peekThread.try_join_for(boost::chrono::milliseconds(200)),
+                      "server socket interruptChildren did not interrupt child peek");
+  clientSock.close();
+  accepted->close();
+  sock1.close();
+}
+
+BOOST_AUTO_TEST_CASE(test_non_interruptable_child_peek) {
+  TServerSocket sock1("localhost", 0);
+  sock1.setInterruptableChildren(false); // returns to pre-THRIFT-2441 behavior
+  sock1.listen();
+  int port = sock1.getPort();
+  TSocket clientSock("localhost", port);
+  clientSock.open();
+  std::shared_ptr<TTransport> accepted = sock1.accept();
+  // peek() will return false when remote side is closed
+  boost::thread peekThread(std::bind(peekerWorker, accepted, false));
+  boost::this_thread::sleep(boost::posix_time::milliseconds(50));
+  // peekThread is practically guaranteed to be blocking now
+  sock1.interruptChildren();
+  BOOST_CHECK_MESSAGE(!peekThread.try_join_for(boost::chrono::milliseconds(200)),
+                      "server socket interruptChildren interrupted child peek");
+
+  // only way to proceed is to have the client disconnect
+  clientSock.close();
+  peekThread.join();
+  accepted->close();
+  sock1.close();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/TTransportCheckThrow.h b/lib/cpp/test/TTransportCheckThrow.h
new file mode 100644
index 0000000..92277b4
--- /dev/null
+++ b/lib/cpp/test/TTransportCheckThrow.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#define TTRANSPORT_CHECK_THROW(_CALL, _TYPE)                                                       \
+  {                                                                                                \
+    bool caught = false;                                                                           \
+    try {                                                                                          \
+      (_CALL);                                                                                     \
+    } catch (TTransportException & ex) {                                                           \
+      BOOST_CHECK_EQUAL(ex.getType(), _TYPE);                                                      \
+      caught = true;                                                                               \
+    }                                                                                              \
+    BOOST_CHECK_MESSAGE(caught, "expected TTransportException but nothing was thrown");            \
+  }
+
+#define TTRANSPORT_REQUIRE_THROW(_CALL, _TYPE)                                                     \
+  {                                                                                                \
+    bool caught = false;                                                                           \
+    try {                                                                                          \
+      (_CALL);                                                                                     \
+    } catch (TTransportException & ex) {                                                           \
+      BOOST_REQUIRE_EQUAL(ex.getType(), _TYPE);                                                    \
+      caught = true;                                                                               \
+    }                                                                                              \
+    BOOST_REQUIRE_MESSAGE(caught, "expected TTransportException but nothing was thrown");          \
+  }
diff --git a/lib/cpp/test/ThriftTest_extras.cpp b/lib/cpp/test/ThriftTest_extras.cpp
index 33f681f..af5606e 100644
--- a/lib/cpp/test/ThriftTest_extras.cpp
+++ b/lib/cpp/test/ThriftTest_extras.cpp
@@ -22,12 +22,12 @@
 #include <thrift/protocol/TDebugProtocol.h>
 #include "gen-cpp/ThriftTest_types.h"
 
-
-namespace thrift { namespace test {
+namespace thrift {
+namespace test {
 
 bool Insanity::operator<(thrift::test::Insanity const& other) const {
   using apache::thrift::ThriftDebugString;
   return ThriftDebugString(*this) < ThriftDebugString(other);
 }
-
-}}
+}
+}
diff --git a/lib/cpp/test/ToStringTest.cpp b/lib/cpp/test/ToStringTest.cpp
new file mode 100644
index 0000000..d204cb3
--- /dev/null
+++ b/lib/cpp/test/ToStringTest.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#include <vector>
+#include <map>
+
+#include <boost/test/auto_unit_test.hpp>
+
+#include <thrift/TToString.h>
+
+#include "gen-cpp/ThriftTest_types.h"
+#include "gen-cpp/OptionalRequiredTest_types.h"
+#include "gen-cpp/DebugProtoTest_types.h"
+
+using apache::thrift::to_string;
+
+BOOST_AUTO_TEST_SUITE(ToStringTest)
+
+BOOST_AUTO_TEST_CASE(base_types_to_string) {
+  BOOST_CHECK_EQUAL(to_string(10), "10");
+  BOOST_CHECK_EQUAL(to_string(true), "1");
+  BOOST_CHECK_EQUAL(to_string('a'), "a");
+  BOOST_CHECK_EQUAL(to_string(1.2), "1.2");
+  BOOST_CHECK_EQUAL(to_string("abc"), "abc");
+}
+
+BOOST_AUTO_TEST_CASE(empty_vector_to_string) {
+  std::vector<int> l;
+  BOOST_CHECK_EQUAL(to_string(l), "[]");
+}
+
+BOOST_AUTO_TEST_CASE(single_item_vector_to_string) {
+  std::vector<int> l;
+  l.push_back(100);
+  BOOST_CHECK_EQUAL(to_string(l), "[100]");
+}
+
+BOOST_AUTO_TEST_CASE(multiple_item_vector_to_string) {
+  std::vector<int> l;
+  l.push_back(100);
+  l.push_back(150);
+  BOOST_CHECK_EQUAL(to_string(l), "[100, 150]");
+}
+
+BOOST_AUTO_TEST_CASE(empty_map_to_string) {
+  std::map<int, std::string> m;
+  BOOST_CHECK_EQUAL(to_string(m), "{}");
+}
+
+BOOST_AUTO_TEST_CASE(single_item_map_to_string) {
+  std::map<int, std::string> m;
+  m[12] = "abc";
+  BOOST_CHECK_EQUAL(to_string(m), "{12: abc}");
+}
+
+BOOST_AUTO_TEST_CASE(multi_item_map_to_string) {
+  std::map<int, std::string> m;
+  m[12] = "abc";
+  m[31] = "xyz";
+  BOOST_CHECK_EQUAL(to_string(m), "{12: abc, 31: xyz}");
+}
+
+BOOST_AUTO_TEST_CASE(empty_set_to_string) {
+  std::set<char> s;
+  BOOST_CHECK_EQUAL(to_string(s), "{}");
+}
+
+BOOST_AUTO_TEST_CASE(single_item_set_to_string) {
+  std::set<char> s;
+  s.insert('c');
+  BOOST_CHECK_EQUAL(to_string(s), "{c}");
+}
+
+BOOST_AUTO_TEST_CASE(multi_item_set_to_string) {
+  std::set<char> s;
+  s.insert('a');
+  s.insert('z');
+  BOOST_CHECK_EQUAL(to_string(s), "{a, z}");
+}
+
+BOOST_AUTO_TEST_CASE(generated_empty_object_to_string) {
+  thrift::test::EmptyStruct e;
+  BOOST_CHECK_EQUAL(to_string(e), "EmptyStruct()");
+}
+
+BOOST_AUTO_TEST_CASE(generated_single_basic_field_object_to_string) {
+  thrift::test::StructA a;
+  a.__set_s("abcd");
+  BOOST_CHECK_EQUAL(to_string(a), "StructA(s=abcd)");
+}
+
+BOOST_AUTO_TEST_CASE(generated_two_basic_fields_object_to_string) {
+  thrift::test::Bonk a;
+  a.__set_message("abcd");
+  a.__set_type(1234);
+  BOOST_CHECK_EQUAL(to_string(a), "Bonk(message=abcd, type=1234)");
+}
+
+BOOST_AUTO_TEST_CASE(generated_optional_fields_object_to_string) {
+  thrift::test::Tricky2 a;
+  BOOST_CHECK_EQUAL(to_string(a), "Tricky2(im_optional=<null>)");
+  a.__set_im_optional(123);
+  BOOST_CHECK_EQUAL(to_string(a), "Tricky2(im_optional=123)");
+}
+
+BOOST_AUTO_TEST_CASE(generated_nested_object_to_string) {
+  thrift::test::OneField a;
+  BOOST_CHECK_EQUAL(to_string(a), "OneField(field=EmptyStruct())");
+}
+
+BOOST_AUTO_TEST_CASE(generated_nested_list_object_to_string) {
+  thrift::test::ListBonks l;
+  l.bonk.assign(2, thrift::test::Bonk());
+  l.bonk[0].__set_message("a");
+  l.bonk[1].__set_message("b");
+
+  BOOST_CHECK_EQUAL(to_string(l),
+                    "ListBonks(bonk=[Bonk(message=a, type=0), Bonk(message=b, type=0)])");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/TransportTest.cpp b/lib/cpp/test/TransportTest.cpp
old mode 100755
new mode 100644
index 4233e6e..ce19544
--- a/lib/cpp/test/TransportTest.cpp
+++ b/lib/cpp/test/TransportTest.cpp
@@ -16,23 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE // needed for getopt_long
-#endif
+
+#include <thrift/thrift-config.h>
 
 #include <stdlib.h>
 #include <time.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <signal.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
 #include <sstream>
-#include <tr1/functional>
+#include <fstream>
 
 #include <boost/mpl/list.hpp>
 #include <boost/shared_array.hpp>
 #include <boost/random.hpp>
 #include <boost/type_traits.hpp>
 #include <boost/test/unit_test.hpp>
+#include <boost/version.hpp>
 
 #include <thrift/transport/TBufferTransports.h>
 #include <thrift/transport/TFDTransport.h>
@@ -40,24 +40,30 @@
 #include <thrift/transport/TZlibTransport.h>
 #include <thrift/transport/TSocket.h>
 
+#include <thrift/concurrency/FunctionRunner.h>
+#if _WIN32
+#include <thrift/transport/TPipe.h>
+#include <thrift/windows/TWinsockSingleton.h>
+#endif
+
 using namespace apache::thrift::transport;
+using namespace apache::thrift;
 
 static boost::mt19937 rng;
-static const char* tmp_dir = "/tmp";
 
 void initrand(unsigned int seed) {
   rng.seed(seed);
 }
 
 class SizeGenerator {
- public:
+public:
   virtual ~SizeGenerator() {}
   virtual uint32_t nextSize() = 0;
   virtual std::string describe() const = 0;
 };
 
 class ConstantSizeGenerator : public SizeGenerator {
- public:
+public:
   ConstantSizeGenerator(uint32_t value) : value_(value) {}
   uint32_t nextSize() { return value_; }
   std::string describe() const {
@@ -66,14 +72,14 @@
     return desc.str();
   }
 
- private:
+private:
   uint32_t value_;
 };
 
 class RandomSizeGenerator : public SizeGenerator {
- public:
-  RandomSizeGenerator(uint32_t min, uint32_t max) :
-    generator_(rng, boost::uniform_int<int>(min, max)) {}
+public:
+  RandomSizeGenerator(uint32_t min, uint32_t max)
+    : generator_(rng, boost::uniform_int<int>(min, max)) {}
 
   uint32_t nextSize() { return generator_(); }
 
@@ -83,12 +89,11 @@
     return desc.str();
   }
 
-  uint32_t getMin() const { return generator_.distribution().min(); }
-  uint32_t getMax() const { return generator_.distribution().max(); }
+  uint32_t getMin() const { return (generator_.distribution().min)(); }
+  uint32_t getMax() const { return (generator_.distribution().max)(); }
 
- private:
-  boost::variate_generator< boost::mt19937&, boost::uniform_int<int> >
-    generator_;
+private:
+  boost::variate_generator<boost::mt19937&, boost::uniform_int<int> > generator_;
 };
 
 /**
@@ -99,17 +104,16 @@
  *   to make a copy of the generator to bind it to the test function.)
  */
 class GenericSizeGenerator : public SizeGenerator {
- public:
-  GenericSizeGenerator(uint32_t value) :
-    generator_(new ConstantSizeGenerator(value)) {}
-  GenericSizeGenerator(uint32_t min, uint32_t max) :
-    generator_(new RandomSizeGenerator(min, max)) {}
+public:
+  GenericSizeGenerator(uint32_t value) : generator_(new ConstantSizeGenerator(value)) {}
+  GenericSizeGenerator(uint32_t min, uint32_t max)
+    : generator_(new RandomSizeGenerator(min, max)) {}
 
   uint32_t nextSize() { return generator_->nextSize(); }
   std::string describe() const { return generator_->describe(); }
 
- private:
-  boost::shared_ptr<SizeGenerator> generator_;
+private:
+  std::shared_ptr<SizeGenerator> generator_;
 };
 
 /**************************************************************************
@@ -126,32 +130,31 @@
  */
 template <class Transport_>
 class CoupledTransports {
- public:
+public:
   virtual ~CoupledTransports() {}
   typedef Transport_ TransportType;
 
   CoupledTransports() : in(), out() {}
 
-  boost::shared_ptr<Transport_> in;
-  boost::shared_ptr<Transport_> out;
+  std::shared_ptr<Transport_> in;
+  std::shared_ptr<Transport_> out;
 
- private:
+private:
   CoupledTransports(const CoupledTransports&);
-  CoupledTransports &operator=(const CoupledTransports&);
+  CoupledTransports& operator=(const CoupledTransports&);
 };
 
 /**
  * Coupled TMemoryBuffers
  */
 class CoupledMemoryBuffers : public CoupledTransports<TMemoryBuffer> {
- public:
-  CoupledMemoryBuffers() :
-    buf(new TMemoryBuffer) {
+public:
+  CoupledMemoryBuffers() : buf(new TMemoryBuffer) {
     in = buf;
     out = buf;
   }
 
-  boost::shared_ptr<TMemoryBuffer> buf;
+  std::shared_ptr<TMemoryBuffer> buf;
 };
 
 /**
@@ -160,7 +163,7 @@
  */
 template <class WrapperTransport_, class InnerCoupledTransports_>
 class CoupledWrapperTransportsT : public CoupledTransports<WrapperTransport_> {
- public:
+public:
   CoupledWrapperTransportsT() {
     if (inner_.in) {
       this->in.reset(new WrapperTransport_(inner_.in));
@@ -177,40 +180,35 @@
  * Coupled TBufferedTransports.
  */
 template <class InnerTransport_>
-class CoupledBufferedTransportsT :
-  public CoupledWrapperTransportsT<TBufferedTransport, InnerTransport_> {
-};
+class CoupledBufferedTransportsT
+    : public CoupledWrapperTransportsT<TBufferedTransport, InnerTransport_> {};
 
-typedef CoupledBufferedTransportsT<CoupledMemoryBuffers>
-  CoupledBufferedTransports;
+typedef CoupledBufferedTransportsT<CoupledMemoryBuffers> CoupledBufferedTransports;
 
 /**
  * Coupled TFramedTransports.
  */
 template <class InnerTransport_>
-class CoupledFramedTransportsT :
-  public CoupledWrapperTransportsT<TFramedTransport, InnerTransport_> {
-};
+class CoupledFramedTransportsT
+    : public CoupledWrapperTransportsT<TFramedTransport, InnerTransport_> {};
 
-typedef CoupledFramedTransportsT<CoupledMemoryBuffers>
-  CoupledFramedTransports;
+typedef CoupledFramedTransportsT<CoupledMemoryBuffers> CoupledFramedTransports;
 
 /**
  * Coupled TZlibTransports.
  */
 template <class InnerTransport_>
-class CoupledZlibTransportsT :
-  public CoupledWrapperTransportsT<TZlibTransport, InnerTransport_> {
-};
+class CoupledZlibTransportsT : public CoupledWrapperTransportsT<TZlibTransport, InnerTransport_> {};
 
-typedef CoupledZlibTransportsT<CoupledMemoryBuffers>
-  CoupledZlibTransports;
+typedef CoupledZlibTransportsT<CoupledMemoryBuffers> CoupledZlibTransports;
 
+#ifndef _WIN32
+// FD transport doesn't make much sense on Windows.
 /**
  * Coupled TFDTransports.
  */
 class CoupledFDTransports : public CoupledTransports<TFDTransport> {
- public:
+public:
   CoupledFDTransports() {
     int pipes[2];
 
@@ -222,15 +220,32 @@
     out.reset(new TFDTransport(pipes[1], TFDTransport::CLOSE_ON_DESTROY));
   }
 };
+#else
+/**
+ * Coupled pipe transports
+ */
+class CoupledPipeTransports : public CoupledTransports<TPipe> {
+public:
+  HANDLE hRead;
+  HANDLE hWrite;
+
+  CoupledPipeTransports() {
+    BOOST_REQUIRE(CreatePipe(&hRead, &hWrite, NULL, 1048576 * 2));
+    in.reset(new TPipe(hRead, hWrite));
+    in->open();
+    out = in;
+  }
+};
+#endif
 
 /**
  * Coupled TSockets
  */
 class CoupledSocketTransports : public CoupledTransports<TSocket> {
- public:
+public:
   CoupledSocketTransports() {
-    int sockets[2];
-    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sockets) != 0) {
+    THRIFT_SOCKET sockets[2] = {0};
+    if (THRIFT_SOCKETPAIR(PF_UNIX, SOCK_STREAM, 0, sockets) != 0) {
       return;
     }
 
@@ -240,37 +255,38 @@
   }
 };
 
+// These could be made to work on Windows, but I don't care enough to make it happen
+#ifndef _WIN32
 /**
  * Coupled TFileTransports
  */
 class CoupledFileTransports : public CoupledTransports<TFileTransport> {
- public:
+public:
   CoupledFileTransports() {
+#ifndef _WIN32
+    const char* tmp_dir = "/tmp";
+#define FILENAME_SUFFIX "/thrift.transport_test"
+#else
+    const char* tmp_dir = getenv("TMP");
+#define FILENAME_SUFFIX "\\thrift.transport_test"
+#endif
+
     // Create a temporary file to use
-    size_t filename_len = strlen(tmp_dir) + 32;
-    filename = new char[filename_len];
-    snprintf(filename, filename_len,
-             "%s/thrift.transport_test.XXXXXX", tmp_dir);
-    fd = mkstemp(filename);
-    if (fd < 0) {
-      return;
-    }
+    filename.resize(strlen(tmp_dir) + strlen(FILENAME_SUFFIX));
+    THRIFT_SNPRINTF(&filename[0], filename.size(), "%s" FILENAME_SUFFIX, tmp_dir);
+#undef FILENAME_SUFFIX
+
+    { std::ofstream dummy_creation(filename.c_str(), std::ofstream::trunc); }
 
     in.reset(new TFileTransport(filename, true));
     out.reset(new TFileTransport(filename));
   }
 
-  ~CoupledFileTransports() {
-    if (fd >= 0) {
-      close(fd);
-      unlink(filename);
-    }
-    delete[] filename;
-  }
+  ~CoupledFileTransports() { remove(filename.c_str()); }
 
-  char* filename;
-  int fd;
+  std::string filename;
 };
+#endif
 
 /**
  * Wrapper around another CoupledTransports implementation that exposes the
@@ -282,7 +298,7 @@
  */
 template <class CoupledTransports_>
 class CoupledTTransports : public CoupledTransports<TTransport> {
- public:
+public:
   CoupledTTransports() : transports() {
     in = transports.in;
     out = transports.out;
@@ -300,7 +316,7 @@
  */
 template <class CoupledTransports_>
 class CoupledBufferBases : public CoupledTransports<TBufferBase> {
- public:
+public:
   CoupledBufferBases() : transports() {
     in = transports.in;
     out = transports.out;
@@ -324,44 +340,42 @@
  **************************************************************************/
 
 struct TriggerInfo {
-  TriggerInfo(int seconds, const boost::shared_ptr<TTransport>& transport,
-              uint32_t writeLength) :
-    timeoutSeconds(seconds),
-    transport(transport),
-    writeLength(writeLength),
-    next(NULL) {}
+  TriggerInfo(int seconds, const std::shared_ptr<TTransport>& transport, uint32_t writeLength)
+    : timeoutSeconds(seconds), transport(transport), writeLength(writeLength), next(NULL) {}
 
   int timeoutSeconds;
-  boost::shared_ptr<TTransport> transport;
+  std::shared_ptr<TTransport> transport;
   uint32_t writeLength;
   TriggerInfo* next;
 };
 
-TriggerInfo* triggerInfo;
-unsigned int numTriggersFired;
+apache::thrift::concurrency::Monitor g_alarm_monitor;
+TriggerInfo* g_triggerInfo;
+unsigned int g_numTriggersFired;
+bool g_teardown = false;
 
-void set_alarm();
+void alarm_handler() {
+  TriggerInfo* info = NULL;
+  {
+    apache::thrift::concurrency::Synchronized s(g_alarm_monitor);
+    // The alarm timed out, which almost certainly means we're stuck
+    // on a transport that is incorrectly blocked.
+    ++g_numTriggersFired;
 
-void alarm_handler(int signum) {
-  (void) signum;
-  // The alarm timed out, which almost certainly means we're stuck
-  // on a transport that is incorrectly blocked.
-  ++numTriggersFired;
+    // Note: we print messages to stdout instead of stderr, since
+    // tools/test/runner only records stdout messages in the failure messages for
+    // boost tests.  (boost prints its test info to stdout.)
+    printf("Timeout alarm expired; attempting to unblock transport\n");
+    if (g_triggerInfo == NULL) {
+      printf("  trigger stack is empty!\n");
+    }
 
-  // Note: we print messages to stdout instead of stderr, since
-  // tools/test/runner only records stdout messages in the failure messages for
-  // boost tests.  (boost prints its test info to stdout.)
-  printf("Timeout alarm expired; attempting to unblock transport\n");
-  if (triggerInfo == NULL) {
-    printf("  trigger stack is empty!\n");
+    // Pop off the first TriggerInfo.
+    // If there is another one, schedule an alarm for it.
+    info = g_triggerInfo;
+    g_triggerInfo = info->next;
   }
 
-  // Pop off the first TriggerInfo.
-  // If there is another one, schedule an alarm for it.
-  TriggerInfo* info = triggerInfo;
-  triggerInfo = info->next;
-  set_alarm();
-
   // Write some data to the transport to hopefully unblock it.
   uint8_t* buf = new uint8_t[info->writeLength];
   memset(buf, 'b', info->writeLength);
@@ -372,21 +386,28 @@
   delete info;
 }
 
-void set_alarm() {
-  if (triggerInfo == NULL) {
-    // clear any alarm
-    alarm(0);
-    return;
+void alarm_handler_wrapper() {
+  int64_t timeout = 0; // timeout of 0 means wait forever
+  while (true) {
+    bool fireHandler = false;
+    {
+      apache::thrift::concurrency::Synchronized s(g_alarm_monitor);
+      if (g_teardown)
+        return;
+      // calculate timeout
+      if (g_triggerInfo == NULL) {
+        timeout = 0;
+      } else {
+        timeout = g_triggerInfo->timeoutSeconds * 1000;
+      }
+
+      int waitResult = g_alarm_monitor.waitForTimeRelative(timeout);
+      if (waitResult == THRIFT_ETIMEDOUT)
+        fireHandler = true;
+    }
+    if (fireHandler)
+      alarm_handler(); // calling outside the lock
   }
-
-  struct sigaction action;
-  memset(&action, 0, sizeof(action));
-  action.sa_handler = alarm_handler;
-  action.sa_flags = SA_RESETHAND;
-  sigemptyset(&action.sa_mask);
-  sigaction(SIGALRM, &action, NULL);
-
-  alarm(triggerInfo->timeoutSeconds);
 }
 
 /**
@@ -398,31 +419,37 @@
  * to the end.)
  */
 void add_trigger(unsigned int seconds,
-                 const boost::shared_ptr<TTransport> &transport,
+                 const std::shared_ptr<TTransport>& transport,
                  uint32_t write_len) {
   TriggerInfo* info = new TriggerInfo(seconds, transport, write_len);
-
-  if (triggerInfo == NULL) {
-    // This is the first trigger.
-    // Set triggerInfo, and schedule the alarm
-    triggerInfo = info;
-    set_alarm();
-  } else {
-    // Add this trigger to the end of the list
-    TriggerInfo* prev = triggerInfo;
-    while (prev->next) {
-      prev = prev->next;
+  {
+    apache::thrift::concurrency::Synchronized s(g_alarm_monitor);
+    if (g_triggerInfo == NULL) {
+      // This is the first trigger.
+      // Set g_triggerInfo, and schedule the alarm
+      g_triggerInfo = info;
+      g_alarm_monitor.notify();
+    } else {
+      // Add this trigger to the end of the list
+      TriggerInfo* prev = g_triggerInfo;
+      while (prev->next) {
+        prev = prev->next;
+      }
+      prev->next = info;
     }
-
-    prev->next = info;
   }
 }
 
 void clear_triggers() {
-  TriggerInfo *info = triggerInfo;
-  alarm(0);
-  triggerInfo = NULL;
-  numTriggersFired = 0;
+  TriggerInfo* info = NULL;
+
+  {
+    apache::thrift::concurrency::Synchronized s(g_alarm_monitor);
+    info = g_triggerInfo;
+    g_triggerInfo = NULL;
+    g_numTriggersFired = 0;
+    g_alarm_monitor.notify();
+  }
 
   while (info != NULL) {
     TriggerInfo* next = info->next;
@@ -432,7 +459,7 @@
 }
 
 void set_trigger(unsigned int seconds,
-                 const boost::shared_ptr<TTransport> &transport,
+                 const std::shared_ptr<TTransport>& transport,
                  uint32_t write_len) {
   clear_triggers();
   add_trigger(seconds, transport, write_len);
@@ -476,10 +503,8 @@
   BOOST_REQUIRE(transports.in != NULL);
   BOOST_REQUIRE(transports.out != NULL);
 
-  boost::shared_array<uint8_t> wbuf =
-    boost::shared_array<uint8_t>(new uint8_t[totalSize]);
-  boost::shared_array<uint8_t> rbuf =
-    boost::shared_array<uint8_t>(new uint8_t[totalSize]);
+  boost::shared_array<uint8_t> wbuf = boost::shared_array<uint8_t>(new uint8_t[totalSize]);
+  boost::shared_array<uint8_t> rbuf = boost::shared_array<uint8_t>(new uint8_t[totalSize]);
 
   // store some data in wbuf
   for (uint32_t n = 0; n < totalSize; ++n) {
@@ -499,8 +524,7 @@
 
     // Make sure (total_written - total_read) + wchunk_size
     // is less than maxOutstanding
-    if (maxOutstanding > 0 &&
-        wchunk_size > maxOutstanding - (total_written - total_read)) {
+    if (maxOutstanding > 0 && wchunk_size > maxOutstanding - (total_written - total_read)) {
       wchunk_size = maxOutstanding - (total_written - total_read);
     }
 
@@ -514,8 +538,7 @@
 
       try {
         transports.out->write(wbuf.get() + total_written, write_size);
-      }
-      catch (TTransportException & te) {
+      } catch (TTransportException& te) {
         if (te.getType() == TTransportException::TIMED_OUT)
           break;
         throw te;
@@ -549,17 +572,15 @@
       try {
         bytes_read = transports.in->read(rbuf.get() + total_read, read_size);
       } catch (TTransportException& e) {
-        BOOST_FAIL("read(pos=" << total_read << ", size=" << read_size <<
-                   ") threw exception \"" << e.what() <<
-                   "\"; written so far: " << total_written << " / " <<
-                   totalSize << " bytes");
+        BOOST_FAIL("read(pos=" << total_read << ", size=" << read_size << ") threw exception \""
+                               << e.what() << "\"; written so far: " << total_written << " / "
+                               << totalSize << " bytes");
       }
 
       BOOST_REQUIRE_MESSAGE(bytes_read > 0,
-                            "read(pos=" << total_read << ", size=" <<
-                            read_size << ") returned " << bytes_read <<
-                            "; written so far: " << total_written << " / " <<
-                            totalSize << " bytes");
+                            "read(pos=" << total_read << ", size=" << read_size << ") returned "
+                                        << bytes_read << "; written so far: " << total_written
+                                        << " / " << totalSize << " bytes");
       chunk_read += bytes_read;
       total_read += bytes_read;
     }
@@ -569,7 +590,6 @@
   BOOST_CHECK_EQUAL(memcmp(rbuf.get(), wbuf.get(), totalSize), 0);
 }
 
-
 template <class CoupledTransports>
 void test_read_part_available() {
   CoupledTransports transports;
@@ -586,8 +606,8 @@
   transports.out->flush();
   set_trigger(3, transports.out, 1);
   uint32_t bytes_read = transports.in->read(read_buf, 10);
-  BOOST_CHECK_EQUAL(numTriggersFired, (unsigned int) 0);
-  BOOST_CHECK_EQUAL(bytes_read, (uint32_t) 9);
+  BOOST_CHECK_EQUAL(g_numTriggersFired, (unsigned int)0);
+  BOOST_CHECK_EQUAL(bytes_read, (uint32_t)9);
 
   clear_triggers();
 }
@@ -608,13 +628,13 @@
 
   // Read 1 byte, to force the transport to read the frame
   uint32_t bytes_read = transports.in->read(read_buf, 1);
-  BOOST_CHECK_EQUAL(bytes_read, 1);
+  BOOST_CHECK_EQUAL(bytes_read, 1u);
 
   // Read more than what is remaining and verify the transport does not block
   set_trigger(3, transports.out, 1);
   bytes_read = transports.in->read(read_buf, 10);
-  BOOST_CHECK_EQUAL(numTriggersFired, 0);
-  BOOST_CHECK_EQUAL(bytes_read, 9);
+  BOOST_CHECK_EQUAL(g_numTriggersFired, 0u);
+  BOOST_CHECK_EQUAL(bytes_read, 9u);
 
   clear_triggers();
 }
@@ -653,7 +673,7 @@
 
   // Now read 4 bytes, so that we are partway through the written data.
   uint32_t bytes_read = transports.in->read(read_buf, 4);
-  BOOST_CHECK_EQUAL(bytes_read, (uint32_t) 4);
+  BOOST_CHECK_EQUAL(bytes_read, (uint32_t)4);
 
   // Now attempt to read 10 bytes.  Only 9 more are available.
   //
@@ -666,13 +686,13 @@
   while (total_read < 9) {
     set_trigger(3, transports.out, 1);
     bytes_read = transports.in->read(read_buf, 10);
-    BOOST_REQUIRE_EQUAL(numTriggersFired, (unsigned int) 0);
-    BOOST_REQUIRE_GT(bytes_read, (uint32_t) 0);
+    BOOST_REQUIRE_EQUAL(g_numTriggersFired, (unsigned int)0);
+    BOOST_REQUIRE_GT(bytes_read, (uint32_t)0);
     total_read += bytes_read;
-    BOOST_REQUIRE_LE(total_read, (uint32_t) 9);
+    BOOST_REQUIRE_LE(total_read, (uint32_t)9);
   }
 
-  BOOST_CHECK_EQUAL(total_read, (uint32_t) 9);
+  BOOST_CHECK_EQUAL(total_read, (uint32_t)9);
 
   clear_triggers();
 }
@@ -694,7 +714,7 @@
   set_trigger(3, transports.out, 1);
   uint32_t borrow_len = 10;
   const uint8_t* borrowed_buf = transports.in->borrow(read_buf, &borrow_len);
-  BOOST_CHECK_EQUAL(numTriggersFired, (unsigned int) 0);
+  BOOST_CHECK_EQUAL(g_numTriggersFired, (unsigned int)0);
   BOOST_CHECK(borrowed_buf == NULL);
 
   clear_triggers();
@@ -720,11 +740,11 @@
   add_trigger(1, transports.out, 8);
   uint32_t bytes_read = transports.in->read(read_buf, 10);
   if (bytes_read == 0) {
-    BOOST_CHECK_EQUAL(numTriggersFired, (unsigned int) 0);
+    BOOST_CHECK_EQUAL(g_numTriggersFired, (unsigned int)0);
     clear_triggers();
   } else {
-    BOOST_CHECK_EQUAL(numTriggersFired, (unsigned int) 1);
-    BOOST_CHECK_EQUAL(bytes_read, (uint32_t) 2);
+    BOOST_CHECK_EQUAL(g_numTriggersFired, (unsigned int)1);
+    BOOST_CHECK_EQUAL(bytes_read, (uint32_t)2);
   }
 
   clear_triggers();
@@ -744,7 +764,7 @@
   uint32_t borrow_len = 10;
   const uint8_t* borrowed_buf = transports.in->borrow(NULL, &borrow_len);
   BOOST_CHECK(borrowed_buf == NULL);
-  BOOST_CHECK_EQUAL(numTriggersFired, (unsigned int) 0);
+  BOOST_CHECK_EQUAL(g_numTriggersFired, (unsigned int)0);
 
   clear_triggers();
 }
@@ -759,53 +779,46 @@
  * - Combining many tests into a single function makes it more difficult to
  *   tell precisely which tests failed.  It also means you can't get a progress
  *   update after each test, and the tests are already fairly slow.
- * - Similar registration could be acheived with BOOST_TEST_CASE_TEMPLATE,
+ * - Similar registration could be achieved with BOOST_TEST_CASE_TEMPLATE,
  *   but it requires a lot of awkward MPL code, and results in useless test
  *   case names.  (The names are generated from std::type_info::name(), which
  *   is compiler-dependent.  gcc returns mangled names.)
  **************************************************************************/
 
-#define ADD_TEST_RW(CoupledTransports, totalSize, ...) \
-    addTestRW< CoupledTransports >(BOOST_STRINGIZE(CoupledTransports), \
-                                   totalSize, ## __VA_ARGS__);
+#define ADD_TEST_RW(CoupledTransports, totalSize, ...)                                             \
+  addTestRW<CoupledTransports>(BOOST_STRINGIZE(CoupledTransports), totalSize, ##__VA_ARGS__);
 
-#define TEST_RW(CoupledTransports, totalSize, ...) \
-  do { \
-    /* Add the test as specified, to test the non-virtual function calls */ \
-    ADD_TEST_RW(CoupledTransports, totalSize, ## __VA_ARGS__); \
-    /* \
-     * Also test using the transport as a TTransport*, to test \
-     * the read_virt()/write_virt() calls \
-     */ \
-    ADD_TEST_RW(CoupledTTransports<CoupledTransports>, \
-                totalSize, ## __VA_ARGS__); \
-    /* Test wrapping the transport with TBufferedTransport */ \
-    ADD_TEST_RW(CoupledBufferedTransportsT<CoupledTransports>, \
-                totalSize, ## __VA_ARGS__); \
-    /* Test wrapping the transport with TFramedTransports */ \
-    ADD_TEST_RW(CoupledFramedTransportsT<CoupledTransports>, \
-                totalSize, ## __VA_ARGS__); \
-    /* Test wrapping the transport with TZlibTransport */ \
-    ADD_TEST_RW(CoupledZlibTransportsT<CoupledTransports>, \
-                totalSize, ## __VA_ARGS__); \
+#define TEST_RW(CoupledTransports, totalSize, ...)                                                 \
+  do {                                                                                             \
+    /* Add the test as specified, to test the non-virtual function calls */                        \
+    ADD_TEST_RW(CoupledTransports, totalSize, ##__VA_ARGS__);                                      \
+    /*                                                                                             \
+     * Also test using the transport as a TTransport*, to test                                     \
+     * the read_virt()/write_virt() calls                                                          \
+     */                                                                                            \
+    ADD_TEST_RW(CoupledTTransports<CoupledTransports>, totalSize, ##__VA_ARGS__);                  \
+    /* Test wrapping the transport with TBufferedTransport */                                      \
+    ADD_TEST_RW(CoupledBufferedTransportsT<CoupledTransports>, totalSize, ##__VA_ARGS__);          \
+    /* Test wrapping the transport with TFramedTransports */                                       \
+    ADD_TEST_RW(CoupledFramedTransportsT<CoupledTransports>, totalSize, ##__VA_ARGS__);            \
+    /* Test wrapping the transport with TZlibTransport */                                          \
+    ADD_TEST_RW(CoupledZlibTransportsT<CoupledTransports>, totalSize, ##__VA_ARGS__);              \
   } while (0)
 
-#define ADD_TEST_BLOCKING(CoupledTransports) \
-    addTestBlocking< CoupledTransports >(BOOST_STRINGIZE(CoupledTransports));
+#define ADD_TEST_BLOCKING(CoupledTransports)                                                       \
+  addTestBlocking<CoupledTransports>(BOOST_STRINGIZE(CoupledTransports));
 
-#define TEST_BLOCKING_BEHAVIOR(CoupledTransports) \
-  ADD_TEST_BLOCKING(CoupledTransports); \
-  ADD_TEST_BLOCKING(CoupledTTransports<CoupledTransports>); \
-  ADD_TEST_BLOCKING(CoupledBufferedTransportsT<CoupledTransports>); \
-  ADD_TEST_BLOCKING(CoupledFramedTransportsT<CoupledTransports>); \
+#define TEST_BLOCKING_BEHAVIOR(CoupledTransports)                                                  \
+  ADD_TEST_BLOCKING(CoupledTransports);                                                            \
+  ADD_TEST_BLOCKING(CoupledTTransports<CoupledTransports>);                                        \
+  ADD_TEST_BLOCKING(CoupledBufferedTransportsT<CoupledTransports>);                                \
+  ADD_TEST_BLOCKING(CoupledFramedTransportsT<CoupledTransports>);                                  \
   ADD_TEST_BLOCKING(CoupledZlibTransportsT<CoupledTransports>);
 
 class TransportTestGen {
- public:
-  TransportTestGen(boost::unit_test::test_suite* suite,
-                   float sizeMultiplier) :
-      suite_(suite),
-      sizeMultiplier_(sizeMultiplier) {}
+public:
+  TransportTestGen(boost::unit_test::test_suite* suite, float sizeMultiplier)
+    : suite_(suite), sizeMultiplier_(sizeMultiplier) {}
 
   void generate() {
     GenericSizeGenerator rand4k(1, 4096);
@@ -816,104 +829,139 @@
      */
 
     // TMemoryBuffer tests
-    TEST_RW(CoupledMemoryBuffers, 1024*1024, 0, 0);
-    TEST_RW(CoupledMemoryBuffers, 1024*256, rand4k, rand4k);
-    TEST_RW(CoupledMemoryBuffers, 1024*256, 167, 163);
-    TEST_RW(CoupledMemoryBuffers, 1024*16, 1, 1);
+    TEST_RW(CoupledMemoryBuffers, 1024 * 1024, 0, 0);
+    TEST_RW(CoupledMemoryBuffers, 1024 * 256, rand4k, rand4k);
+    TEST_RW(CoupledMemoryBuffers, 1024 * 256, 167, 163);
+    TEST_RW(CoupledMemoryBuffers, 1024 * 16, 1, 1);
 
-    TEST_RW(CoupledMemoryBuffers, 1024*256, 0, 0, rand4k, rand4k);
-    TEST_RW(CoupledMemoryBuffers, 1024*256, rand4k, rand4k, rand4k, rand4k);
-    TEST_RW(CoupledMemoryBuffers, 1024*256, 167, 163, rand4k, rand4k);
-    TEST_RW(CoupledMemoryBuffers, 1024*16, 1, 1, rand4k, rand4k);
+    TEST_RW(CoupledMemoryBuffers, 1024 * 256, 0, 0, rand4k, rand4k);
+    TEST_RW(CoupledMemoryBuffers, 1024 * 256, rand4k, rand4k, rand4k, rand4k);
+    TEST_RW(CoupledMemoryBuffers, 1024 * 256, 167, 163, rand4k, rand4k);
+    TEST_RW(CoupledMemoryBuffers, 1024 * 16, 1, 1, rand4k, rand4k);
 
     TEST_BLOCKING_BEHAVIOR(CoupledMemoryBuffers);
 
+#ifndef _WIN32
     // TFDTransport tests
     // Since CoupledFDTransports tests with a pipe, writes will block
     // if there is too much outstanding unread data in the pipe.
     uint32_t fd_max_outstanding = 4096;
-    TEST_RW(CoupledFDTransports, 1024*1024, 0, 0,
-            0, 0, fd_max_outstanding);
-    TEST_RW(CoupledFDTransports, 1024*256, rand4k, rand4k,
-            0, 0, fd_max_outstanding);
-    TEST_RW(CoupledFDTransports, 1024*256, 167, 163,
-            0, 0, fd_max_outstanding);
-    TEST_RW(CoupledFDTransports, 1024*16, 1, 1,
-            0, 0, fd_max_outstanding);
+    TEST_RW(CoupledFDTransports, 1024 * 1024, 0, 0, 0, 0, fd_max_outstanding);
+    TEST_RW(CoupledFDTransports, 1024 * 256, rand4k, rand4k, 0, 0, fd_max_outstanding);
+    TEST_RW(CoupledFDTransports, 1024 * 256, 167, 163, 0, 0, fd_max_outstanding);
+    TEST_RW(CoupledFDTransports, 1024 * 16, 1, 1, 0, 0, fd_max_outstanding);
 
-    TEST_RW(CoupledFDTransports, 1024*256, 0, 0,
-            rand4k, rand4k, fd_max_outstanding);
-    TEST_RW(CoupledFDTransports, 1024*256, rand4k, rand4k,
-            rand4k, rand4k, fd_max_outstanding);
-    TEST_RW(CoupledFDTransports, 1024*256, 167, 163,
-            rand4k, rand4k, fd_max_outstanding);
-    TEST_RW(CoupledFDTransports, 1024*16, 1, 1,
-            rand4k, rand4k, fd_max_outstanding);
+    TEST_RW(CoupledFDTransports, 1024 * 256, 0, 0, rand4k, rand4k, fd_max_outstanding);
+    TEST_RW(CoupledFDTransports, 1024 * 256, rand4k, rand4k, rand4k, rand4k, fd_max_outstanding);
+    TEST_RW(CoupledFDTransports, 1024 * 256, 167, 163, rand4k, rand4k, fd_max_outstanding);
+    TEST_RW(CoupledFDTransports, 1024 * 16, 1, 1, rand4k, rand4k, fd_max_outstanding);
 
     TEST_BLOCKING_BEHAVIOR(CoupledFDTransports);
+#else
+    // TPipe tests (WIN32 only)
+    TEST_RW(CoupledPipeTransports, 1024 * 1024, 0, 0);
+    TEST_RW(CoupledPipeTransports, 1024 * 256, rand4k, rand4k);
+    TEST_RW(CoupledPipeTransports, 1024 * 256, 167, 163);
+    TEST_RW(CoupledPipeTransports, 1024 * 16, 1, 1);
+
+    TEST_RW(CoupledPipeTransports, 1024 * 256, 0, 0, rand4k, rand4k);
+    TEST_RW(CoupledPipeTransports, 1024 * 256, rand4k, rand4k, rand4k, rand4k);
+    TEST_RW(CoupledPipeTransports, 1024 * 256, 167, 163, rand4k, rand4k);
+    TEST_RW(CoupledPipeTransports, 1024 * 16, 1, 1, rand4k, rand4k);
+
+    TEST_BLOCKING_BEHAVIOR(CoupledPipeTransports);
+#endif //_WIN32
 
     // TSocket tests
     uint32_t socket_max_outstanding = 4096;
-    TEST_RW(CoupledSocketTransports, 1024*1024, 0, 0,
-            0, 0, socket_max_outstanding);
-    TEST_RW(CoupledSocketTransports, 1024*256, rand4k, rand4k,
-            0, 0, socket_max_outstanding);
-    TEST_RW(CoupledSocketTransports, 1024*256, 167, 163,
-            0, 0, socket_max_outstanding);
+    TEST_RW(CoupledSocketTransports, 1024 * 1024, 0, 0, 0, 0, socket_max_outstanding);
+    TEST_RW(CoupledSocketTransports, 1024 * 256, rand4k, rand4k, 0, 0, socket_max_outstanding);
+    TEST_RW(CoupledSocketTransports, 1024 * 256, 167, 163, 0, 0, socket_max_outstanding);
     // Doh.  Apparently writing to a socket has some additional overhead for
     // each send() call.  If we have more than ~400 outstanding 1-byte write
     // requests, additional send() calls start blocking.
-    TEST_RW(CoupledSocketTransports, 1024*16, 1, 1,
-            0, 0, socket_max_outstanding);
-    TEST_RW(CoupledSocketTransports, 1024*256, 0, 0,
-            rand4k, rand4k, socket_max_outstanding);
-    TEST_RW(CoupledSocketTransports, 1024*256, rand4k, rand4k,
-            rand4k, rand4k, socket_max_outstanding);
-    TEST_RW(CoupledSocketTransports, 1024*256, 167, 163,
-            rand4k, rand4k, socket_max_outstanding);
-    TEST_RW(CoupledSocketTransports, 1024*16, 1, 1,
-            rand4k, rand4k, socket_max_outstanding);
+    TEST_RW(CoupledSocketTransports, 1024 * 16, 1, 1, 0, 0, socket_max_outstanding);
+    TEST_RW(CoupledSocketTransports, 1024 * 256, 0, 0, rand4k, rand4k, socket_max_outstanding);
+    TEST_RW(CoupledSocketTransports,
+            1024 * 256,
+            rand4k,
+            rand4k,
+            rand4k,
+            rand4k,
+            socket_max_outstanding);
+    TEST_RW(CoupledSocketTransports, 1024 * 256, 167, 163, rand4k, rand4k, socket_max_outstanding);
+    TEST_RW(CoupledSocketTransports, 1024 * 16, 1, 1, rand4k, rand4k, socket_max_outstanding);
 
     TEST_BLOCKING_BEHAVIOR(CoupledSocketTransports);
 
+// These could be made to work on Windows, but I don't care enough to make it happen
+#ifndef _WIN32
     // TFileTransport tests
     // We use smaller buffer sizes here, since TFileTransport is fairly slow.
     //
     // TFileTransport can't write more than 16MB at once
-    uint32_t max_write_at_once = 1024*1024*16 - 4;
-    TEST_RW(CoupledFileTransports, 1024*1024, max_write_at_once, 0);
-    TEST_RW(CoupledFileTransports, 1024*128, rand4k, rand4k);
-    TEST_RW(CoupledFileTransports, 1024*128, 167, 163);
-    TEST_RW(CoupledFileTransports, 1024*2, 1, 1);
+    uint32_t max_write_at_once = 1024 * 1024 * 16 - 4;
+    TEST_RW(CoupledFileTransports, 1024 * 1024, max_write_at_once, 0);
+    TEST_RW(CoupledFileTransports, 1024 * 128, rand4k, rand4k);
+    TEST_RW(CoupledFileTransports, 1024 * 128, 167, 163);
+    TEST_RW(CoupledFileTransports, 1024 * 2, 1, 1);
 
-    TEST_RW(CoupledFileTransports, 1024*64, 0, 0, rand4k, rand4k);
-    TEST_RW(CoupledFileTransports, 1024*64,
-            rand4k, rand4k, rand4k, rand4k);
-    TEST_RW(CoupledFileTransports, 1024*64, 167, 163, rand4k, rand4k);
-    TEST_RW(CoupledFileTransports, 1024*2, 1, 1, rand4k, rand4k);
+    TEST_RW(CoupledFileTransports, 1024 * 64, 0, 0, rand4k, rand4k);
+    TEST_RW(CoupledFileTransports, 1024 * 64, rand4k, rand4k, rand4k, rand4k);
+    TEST_RW(CoupledFileTransports, 1024 * 64, 167, 163, rand4k, rand4k);
+    TEST_RW(CoupledFileTransports, 1024 * 2, 1, 1, rand4k, rand4k);
 
     TEST_BLOCKING_BEHAVIOR(CoupledFileTransports);
+#endif
 
     // Add some tests that access TBufferedTransport and TFramedTransport
     // via TTransport pointers and TBufferBase pointers.
     ADD_TEST_RW(CoupledTTransports<CoupledBufferedTransports>,
-                1024*1024, rand4k, rand4k, rand4k, rand4k);
+                1024 * 1024,
+                rand4k,
+                rand4k,
+                rand4k,
+                rand4k);
     ADD_TEST_RW(CoupledBufferBases<CoupledBufferedTransports>,
-                1024*1024, rand4k, rand4k, rand4k, rand4k);
+                1024 * 1024,
+                rand4k,
+                rand4k,
+                rand4k,
+                rand4k);
     ADD_TEST_RW(CoupledTTransports<CoupledFramedTransports>,
-                1024*1024, rand4k, rand4k, rand4k, rand4k);
+                1024 * 1024,
+                rand4k,
+                rand4k,
+                rand4k,
+                rand4k);
     ADD_TEST_RW(CoupledBufferBases<CoupledFramedTransports>,
-                1024*1024, rand4k, rand4k, rand4k, rand4k);
+                1024 * 1024,
+                rand4k,
+                rand4k,
+                rand4k,
+                rand4k);
 
     // Test using TZlibTransport via a TTransport pointer
     ADD_TEST_RW(CoupledTTransports<CoupledZlibTransports>,
-                1024*1024, rand4k, rand4k, rand4k, rand4k);
+                1024 * 1024,
+                rand4k,
+                rand4k,
+                rand4k,
+                rand4k);
   }
 
- private:
+#if (BOOST_VERSION >= 105900)
+#define MAKE_TEST_CASE(_FUNC, _NAME) boost::unit_test::make_test_case(_FUNC, _NAME, __FILE__, __LINE__)
+#else
+#define MAKE_TEST_CASE(_FUNC, _NAME) boost::unit_test::make_test_case(_FUNC, _NAME)
+#endif
+
+private:
   template <class CoupledTransports>
-  void addTestRW(const char* transport_name, uint32_t totalSize,
-                 GenericSizeGenerator wSizeGen, GenericSizeGenerator rSizeGen,
+  void addTestRW(const char* transport_name,
+                 uint32_t totalSize,
+                 GenericSizeGenerator wSizeGen,
+                 GenericSizeGenerator rSizeGen,
                  GenericSizeGenerator wChunkSizeGen = 0,
                  GenericSizeGenerator rChunkSizeGen = 0,
                  uint32_t maxOutstanding = 0,
@@ -922,61 +970,46 @@
     totalSize = static_cast<uint32_t>(totalSize * sizeMultiplier_);
 
     std::ostringstream name;
-    name << transport_name << "::test_rw(" << totalSize << ", " <<
-      wSizeGen.describe() << ", " << rSizeGen.describe() << ", " <<
-      wChunkSizeGen.describe() << ", " << rChunkSizeGen.describe() << ", " <<
-      maxOutstanding << ")";
+    name << transport_name << "::test_rw(" << totalSize << ", " << wSizeGen.describe() << ", "
+         << rSizeGen.describe() << ", " << wChunkSizeGen.describe() << ", "
+         << rChunkSizeGen.describe() << ", " << maxOutstanding << ")";
 
-    boost::unit_test::callback0<> test_func =
-      std::tr1::bind(test_rw<CoupledTransports>, totalSize,
-                     wSizeGen, rSizeGen, wChunkSizeGen, rChunkSizeGen,
-                     maxOutstanding);
-    boost::unit_test::test_case* tc =
-      boost::unit_test::make_test_case(test_func, name.str());
-    suite_->add(tc, expectedFailures);
+#if (BOOST_VERSION >= 105900)
+    std::function<void ()> test_func
+#else
+    boost::unit_test::callback0<> test_func
+#endif
+        = std::bind(test_rw<CoupledTransports>,
+                                       totalSize,
+                                       wSizeGen,
+                                       rSizeGen,
+                                       wChunkSizeGen,
+                                       rChunkSizeGen,
+                                       maxOutstanding);
+    suite_->add(MAKE_TEST_CASE(test_func, name.str()), expectedFailures);
   }
 
   template <class CoupledTransports>
-  void addTestBlocking(const char* transportName,
-                       uint32_t expectedFailures = 0) {
+  void addTestBlocking(const char* transportName, uint32_t expectedFailures = 0) {
     char name[1024];
-    boost::unit_test::test_case* tc;
 
-    snprintf(name, sizeof(name), "%s::test_read_part_available()",
-             transportName);
-    tc = boost::unit_test::make_test_case(
-          test_read_part_available<CoupledTransports>, name);
-    suite_->add(tc, expectedFailures);
+    THRIFT_SNPRINTF(name, sizeof(name), "%s::test_read_part_available()", transportName);
+    suite_->add(MAKE_TEST_CASE(test_read_part_available<CoupledTransports>, name), expectedFailures);
 
-    snprintf(name, sizeof(name), "%s::test_read_part_available_in_chunks()",
-             transportName);
-    tc = boost::unit_test::make_test_case(
-          test_read_part_available_in_chunks<CoupledTransports>, name);
-    suite_->add(tc, expectedFailures);
+    THRIFT_SNPRINTF(name, sizeof(name), "%s::test_read_part_available_in_chunks()", transportName);
+    suite_->add(MAKE_TEST_CASE(test_read_part_available_in_chunks<CoupledTransports>, name), expectedFailures);
 
-    snprintf(name, sizeof(name), "%s::test_read_partial_midframe()",
-             transportName);
-    tc = boost::unit_test::make_test_case(
-          test_read_partial_midframe<CoupledTransports>, name);
-    suite_->add(tc, expectedFailures);
+    THRIFT_SNPRINTF(name, sizeof(name), "%s::test_read_partial_midframe()", transportName);
+    suite_->add(MAKE_TEST_CASE(test_read_partial_midframe<CoupledTransports>, name), expectedFailures);
 
-    snprintf(name, sizeof(name), "%s::test_read_none_available()",
-             transportName);
-    tc = boost::unit_test::make_test_case(
-          test_read_none_available<CoupledTransports>, name);
-    suite_->add(tc, expectedFailures);
+    THRIFT_SNPRINTF(name, sizeof(name), "%s::test_read_none_available()", transportName);
+    suite_->add(MAKE_TEST_CASE(test_read_none_available<CoupledTransports>, name), expectedFailures);
 
-    snprintf(name, sizeof(name), "%s::test_borrow_part_available()",
-             transportName);
-    tc = boost::unit_test::make_test_case(
-          test_borrow_part_available<CoupledTransports>, name);
-    suite_->add(tc, expectedFailures);
+    THRIFT_SNPRINTF(name, sizeof(name), "%s::test_borrow_part_available()", transportName);
+    suite_->add(MAKE_TEST_CASE(test_borrow_part_available<CoupledTransports>, name), expectedFailures);
 
-    snprintf(name, sizeof(name), "%s::test_borrow_none_available()",
-             transportName);
-    tc = boost::unit_test::make_test_case(
-          test_borrow_none_available<CoupledTransports>, name);
-    suite_->add(tc, expectedFailures);
+    THRIFT_SNPRINTF(name, sizeof(name), "%s::test_borrow_none_available()", transportName);
+    suite_->add(MAKE_TEST_CASE(test_borrow_none_available<CoupledTransports>, name), expectedFailures);
   }
 
   boost::unit_test::test_suite* suite_;
@@ -991,103 +1024,68 @@
  * General Initialization
  **************************************************************************/
 
-void print_usage(FILE* f, const char* argv0) {
-  fprintf(f, "Usage: %s [boost_options] [options]\n", argv0);
-  fprintf(f, "Options:\n");
-  fprintf(f, "  --seed=<N>, -s <N>\n");
-  fprintf(f, "  --tmp-dir=DIR, -t DIR\n");
-  fprintf(f, "  --help\n");
-}
+struct global_fixture {
+  std::shared_ptr<apache::thrift::concurrency::Thread> alarmThread_;
+  global_fixture() {
+#if _WIN32
+    apache::thrift::transport::TWinsockSingleton::create();
+#endif
 
-struct Options {
-  int seed;
-  bool haveSeed;
-  float sizeMultiplier;
+    apache::thrift::concurrency::PlatformThreadFactory factory;
+    factory.setDetached(false);
+
+    alarmThread_ = factory.newThread(
+        apache::thrift::concurrency::FunctionRunner::create(alarm_handler_wrapper));
+    alarmThread_->start();
+  }
+  ~global_fixture() {
+    {
+      apache::thrift::concurrency::Synchronized s(g_alarm_monitor);
+      g_teardown = true;
+      g_alarm_monitor.notify();
+    }
+    alarmThread_->join();
+  }
 };
 
-void parse_args(int argc, char* argv[], Options* options) {
-  bool have_seed = false;
-  options->sizeMultiplier = 1;
+#if (BOOST_VERSION >= 105900)
+BOOST_GLOBAL_FIXTURE(global_fixture);
+#else
+BOOST_GLOBAL_FIXTURE(global_fixture)
+#endif
 
-  struct option long_opts[] = {
-    { "help", false, NULL, 'h' },
-    { "seed", true, NULL, 's' },
-    { "tmp-dir", true, NULL, 't' },
-    { "size-multiplier", true, NULL, 'x' },
-    { NULL, 0, NULL, 0 }
-  };
+#ifdef BOOST_TEST_DYN_LINK
+bool init_unit_test_suite() {
+  struct timeval tv;
+  THRIFT_GETTIMEOFDAY(&tv, NULL);
+  int seed = tv.tv_sec ^ tv.tv_usec;
 
-  while (true) {
-    optopt = 1;
-    int optchar = getopt_long(argc, argv, "hs:t:x:", long_opts, NULL);
-    if (optchar == -1) {
-      break;
-    }
+  initrand(seed);
 
-    switch (optchar) {
-      case 't':
-        tmp_dir = optarg;
-        break;
-      case 's': {
-        char *endptr;
-        options->seed = strtol(optarg, &endptr, 0);
-        if (endptr == optarg || *endptr != '\0') {
-          fprintf(stderr, "invalid seed value \"%s\": must be an integer\n",
-                  optarg);
-          exit(1);
-        }
-        have_seed = true;
-        break;
-      }
-      case 'h':
-        print_usage(stdout, argv[0]);
-        exit(0);
-      case 'x': {
-        char *endptr;
-        options->sizeMultiplier = strtof(optarg, &endptr);
-        if (endptr == optarg || *endptr != '\0') {
-          fprintf(stderr, "invalid size multiplier \"%s\": must be a number\n",
-                  optarg);
-          exit(1);
-        }
-        if (options->sizeMultiplier < 0) {
-          fprintf(stderr, "invalid size multiplier \"%s\": "
-                  "must be non-negative\n", optarg);
-          exit(1);
-        }
-        break;
-      }
-      case '?':
-        exit(1);
-      default:
-        // Only happens if someone adds another option to the optarg string,
-        // but doesn't update the switch statement to handle it.
-        fprintf(stderr, "unknown option \"-%c\"\n", optchar);
-        exit(1);
-    }
-  }
-
-  if (!have_seed) {
-    // choose a seed now if the user didn't specify one
-    struct timeval tv;
-    struct timezone tz;
-    gettimeofday(&tv, &tz);
-    options->seed = tv.tv_sec ^ tv.tv_usec;
-  }
+  boost::unit_test::test_suite* suite = &boost::unit_test::framework::master_test_suite();
+  suite->p_name.value = "TransportTest";
+  TransportTestGen transport_test_generator(suite, 1);
+  transport_test_generator.generate();
+  return true;
 }
 
+int main( int argc, char* argv[] ) {
+  return ::boost::unit_test::unit_test_main(&init_unit_test_suite,argc,argv);
+}
+#else
 boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
-  // Parse arguments
-  Options options;
-  parse_args(argc, argv, &options);
+  THRIFT_UNUSED_VARIABLE(argc);
+  THRIFT_UNUSED_VARIABLE(argv);
+  struct timeval tv;
+  THRIFT_GETTIMEOFDAY(&tv, NULL);
+  int seed = tv.tv_sec ^ tv.tv_usec;
 
-  initrand(options.seed);
+  initrand(seed);
 
-  boost::unit_test::test_suite* suite =
-    &boost::unit_test::framework::master_test_suite();
+  boost::unit_test::test_suite* suite = &boost::unit_test::framework::master_test_suite();
   suite->p_name.value = "TransportTest";
-  TransportTestGen transport_test_generator(suite, options.sizeMultiplier);
+  TransportTestGen transport_test_generator(suite, 1);
   transport_test_generator.generate();
-
   return NULL;
 }
+#endif
diff --git a/lib/cpp/test/TypedefTest.cpp b/lib/cpp/test/TypedefTest.cpp
new file mode 100644
index 0000000..24e9265
--- /dev/null
+++ b/lib/cpp/test/TypedefTest.cpp
@@ -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.
+ */
+
+#include <boost/type_traits/is_same.hpp>
+#include <boost/static_assert.hpp>
+
+#include "gen-cpp/TypedefTest_types.h"
+
+BOOST_STATIC_ASSERT((boost::is_same<int32_t, thrift::test::MyInt32>::value));
+BOOST_STATIC_ASSERT((boost::is_same<std::string, thrift::test::MyString>::value));
+BOOST_STATIC_ASSERT(
+    (boost::is_same<thrift::test::TypedefTestStruct, thrift::test::MyStruct>::value));
diff --git a/lib/cpp/test/ZlibTest.cpp b/lib/cpp/test/ZlibTest.cpp
index 4d7966e..c826814 100644
--- a/lib/cpp/test/ZlibTest.cpp
+++ b/lib/cpp/test/ZlibTest.cpp
@@ -17,31 +17,38 @@
  * under the License.
  */
 
-#define __STDC_LIMIT_MACROS
-#define __STDC_FORMAT_MACROS
-
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE // needed for getopt_long
 #endif
 
+#if defined(_MSC_VER) && (_MSC_VER <= 1700)
+// polynomial and std::fill_t warning happens in MSVC 2010, 2013, maybe others
+// https://svn.boost.org/trac/boost/ticket/11426
+#pragma warning(disable:4996)
+#endif
+
+#ifdef HAVE_STDINT_H
 #include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
 #include <inttypes.h>
-#include <getopt.h>
+#endif
 #include <cstddef>
 #include <fstream>
 #include <iostream>
-#include <tr1/functional>
+#include <memory>
 
 #include <boost/random.hpp>
 #include <boost/shared_array.hpp>
 #include <boost/test/unit_test.hpp>
+#include <boost/version.hpp>
 
 #include <thrift/transport/TBufferTransports.h>
 #include <thrift/transport/TZlibTransport.h>
 
-using namespace std;
-using namespace boost;
 using namespace apache::thrift::transport;
+using std::shared_ptr;
+using std::string;
 
 boost::mt19937 rng;
 
@@ -50,26 +57,24 @@
  */
 
 class SizeGenerator {
- public:
+public:
   virtual ~SizeGenerator() {}
   virtual unsigned int getSize() = 0;
 };
 
 class ConstantSizeGenerator : public SizeGenerator {
- public:
+public:
   ConstantSizeGenerator(unsigned int value) : value_(value) {}
-  virtual unsigned int getSize() {
-    return value_;
-  }
+  virtual unsigned int getSize() { return value_; }
 
- private:
+private:
   unsigned int value_;
 };
 
 class LogNormalSizeGenerator : public SizeGenerator {
- public:
-  LogNormalSizeGenerator(double mean, double std_dev) :
-      gen_(rng, lognormal_distribution<double>(mean, std_dev)) {}
+public:
+  LogNormalSizeGenerator(double mean, double std_dev)
+    : gen_(rng, boost::lognormal_distribution<double>(mean, std_dev)) {}
 
   virtual unsigned int getSize() {
     // Loop until we get a size of 1 or more
@@ -81,26 +86,26 @@
     }
   }
 
- private:
-  variate_generator< mt19937, lognormal_distribution<double> > gen_;
+private:
+  boost::variate_generator<boost::mt19937, boost::lognormal_distribution<double> > gen_;
 };
 
-uint8_t* gen_uniform_buffer(uint32_t buf_len, uint8_t c) {
+boost::shared_array<uint8_t> gen_uniform_buffer(uint32_t buf_len, uint8_t c) {
   uint8_t* buf = new uint8_t[buf_len];
   memset(buf, c, buf_len);
-  return buf;
+  return boost::shared_array<uint8_t>(buf);
 }
 
-uint8_t* gen_compressible_buffer(uint32_t buf_len) {
+boost::shared_array<uint8_t> gen_compressible_buffer(uint32_t buf_len) {
   uint8_t* buf = new uint8_t[buf_len];
 
   // Generate small runs of alternately increasing and decreasing bytes
   boost::uniform_smallint<uint32_t> run_length_distribution(1, 64);
   boost::uniform_smallint<uint8_t> byte_distribution(0, UINT8_MAX);
-  boost::variate_generator< boost::mt19937, boost::uniform_smallint<uint8_t> >
-    byte_generator(rng, byte_distribution);
-  boost::variate_generator< boost::mt19937, boost::uniform_smallint<uint32_t> >
-    run_len_generator(rng, run_length_distribution);
+  boost::variate_generator<boost::mt19937, boost::uniform_smallint<uint8_t> >
+      byte_generator(rng, byte_distribution);
+  boost::variate_generator<boost::mt19937, boost::uniform_smallint<uint32_t> >
+      run_len_generator(rng, run_length_distribution);
 
   uint32_t idx = 0;
   int8_t step = 1;
@@ -120,82 +125,81 @@
     step *= -1;
   }
 
-  return buf;
+  return boost::shared_array<uint8_t>(buf);
 }
 
-uint8_t* gen_random_buffer(uint32_t buf_len) {
+boost::shared_array<uint8_t> gen_random_buffer(uint32_t buf_len) {
   uint8_t* buf = new uint8_t[buf_len];
 
   boost::uniform_smallint<uint8_t> distribution(0, UINT8_MAX);
-  boost::variate_generator< boost::mt19937, boost::uniform_smallint<uint8_t> >
-    generator(rng, distribution);
+  boost::variate_generator<boost::mt19937, boost::uniform_smallint<uint8_t> >
+      generator(rng, distribution);
 
   for (uint32_t n = 0; n < buf_len; ++n) {
     buf[n] = generator();
   }
 
-  return buf;
+  return boost::shared_array<uint8_t>(buf);
 }
 
 /*
  * Test functions
  */
 
-void test_write_then_read(const uint8_t* buf, uint32_t buf_len) {
-  boost::shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
-  boost::shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf));
-  zlib_trans->write(buf, buf_len);
+void test_write_then_read(const boost::shared_array<uint8_t> buf, uint32_t buf_len) {
+  shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
+  shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf));
+  zlib_trans->write(buf.get(), buf_len);
   zlib_trans->finish();
 
   boost::shared_array<uint8_t> mirror(new uint8_t[buf_len]);
   uint32_t got = zlib_trans->readAll(mirror.get(), buf_len);
   BOOST_REQUIRE_EQUAL(got, buf_len);
-  BOOST_CHECK_EQUAL(memcmp(mirror.get(), buf, buf_len), 0);
+  BOOST_CHECK_EQUAL(memcmp(mirror.get(), buf.get(), buf_len), 0);
   zlib_trans->verifyChecksum();
 }
 
-void test_separate_checksum(const uint8_t* buf, uint32_t buf_len) {
+void test_separate_checksum(const boost::shared_array<uint8_t> buf, uint32_t buf_len) {
   // This one is tricky.  I separate the last byte of the stream out
   // into a separate crbuf_.  The last byte is part of the checksum,
   // so the entire read goes fine, but when I go to verify the checksum
   // it isn't there.  The original implementation complained that
   // the stream was not complete.  I'm about to go fix that.
   // It worked.  Awesome.
-  boost::shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
-  boost::shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf));
-  zlib_trans->write(buf, buf_len);
+  shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
+  shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf));
+  zlib_trans->write(buf.get(), buf_len);
   zlib_trans->finish();
   string tmp_buf;
   membuf->appendBufferToString(tmp_buf);
   zlib_trans.reset(new TZlibTransport(membuf,
                                       TZlibTransport::DEFAULT_URBUF_SIZE,
-                                      tmp_buf.length()-1));
+                                      static_cast<uint32_t>(tmp_buf.length() - 1)));
 
   boost::shared_array<uint8_t> mirror(new uint8_t[buf_len]);
   uint32_t got = zlib_trans->readAll(mirror.get(), buf_len);
   BOOST_REQUIRE_EQUAL(got, buf_len);
-  BOOST_CHECK_EQUAL(memcmp(mirror.get(), buf, buf_len), 0);
+  BOOST_CHECK_EQUAL(memcmp(mirror.get(), buf.get(), buf_len), 0);
   zlib_trans->verifyChecksum();
 }
 
-void test_incomplete_checksum(const uint8_t* buf, uint32_t buf_len) {
+void test_incomplete_checksum(const boost::shared_array<uint8_t> buf, uint32_t buf_len) {
   // Make sure we still get that "not complete" error if
   // it really isn't complete.
-  boost::shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
-  boost::shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf));
-  zlib_trans->write(buf, buf_len);
+  shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
+  shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf));
+  zlib_trans->write(buf.get(), buf_len);
   zlib_trans->finish();
   string tmp_buf;
   membuf->appendBufferToString(tmp_buf);
   tmp_buf.erase(tmp_buf.length() - 1);
-  membuf->resetBuffer(const_cast<uint8_t*>(
-                        reinterpret_cast<const uint8_t*>(tmp_buf.data())),
-                      tmp_buf.length());
+  membuf->resetBuffer(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(tmp_buf.data())),
+                      static_cast<uint32_t>(tmp_buf.length()));
 
   boost::shared_array<uint8_t> mirror(new uint8_t[buf_len]);
   uint32_t got = zlib_trans->readAll(mirror.get(), buf_len);
   BOOST_REQUIRE_EQUAL(got, buf_len);
-  BOOST_CHECK_EQUAL(memcmp(mirror.get(), buf, buf_len), 0);
+  BOOST_CHECK_EQUAL(memcmp(mirror.get(), buf.get(), buf_len), 0);
   try {
     zlib_trans->verifyChecksum();
     BOOST_ERROR("verifyChecksum() did not report an error");
@@ -204,12 +208,13 @@
   }
 }
 
-void test_read_write_mix(const uint8_t* buf, uint32_t buf_len,
-                         const boost::shared_ptr<SizeGenerator>& write_gen,
-                         const boost::shared_ptr<SizeGenerator>& read_gen) {
+void test_read_write_mix(const boost::shared_array<uint8_t> buf,
+                         uint32_t buf_len,
+                         const shared_ptr<SizeGenerator>& write_gen,
+                         const shared_ptr<SizeGenerator>& read_gen) {
   // Try it with a mix of read/write sizes.
-  boost::shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
-  boost::shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf));
+  shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
+  shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf));
   unsigned int tot;
 
   tot = 0;
@@ -218,7 +223,7 @@
     if (tot + write_len > buf_len) {
       write_len = buf_len - tot;
     }
-    zlib_trans->write(buf + tot, write_len);
+    zlib_trans->write(buf.get() + tot, write_len);
     tot += write_len;
   }
 
@@ -234,19 +239,19 @@
     }
     uint32_t got = zlib_trans->read(mirror.get() + tot, read_len);
     BOOST_REQUIRE_LE(got, expected_read_len);
-    BOOST_REQUIRE_NE(got, (uint32_t) 0);
+    BOOST_REQUIRE_NE(got, (uint32_t)0);
     tot += got;
   }
 
-  BOOST_CHECK_EQUAL(memcmp(mirror.get(), buf, buf_len), 0);
+  BOOST_CHECK_EQUAL(memcmp(mirror.get(), buf.get(), buf_len), 0);
   zlib_trans->verifyChecksum();
 }
 
-void test_invalid_checksum(const uint8_t* buf, uint32_t buf_len) {
+void test_invalid_checksum(const boost::shared_array<uint8_t> buf, uint32_t buf_len) {
   // Verify checksum checking.
-  boost::shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
-  boost::shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf));
-  zlib_trans->write(buf, buf_len);
+  shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
+  shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf));
+  zlib_trans->write(buf.get(), buf_len);
   zlib_trans->finish();
   string tmp_buf;
   membuf->appendBufferToString(tmp_buf);
@@ -264,11 +269,10 @@
   // (When this occurs, verifyChecksum() throws an exception indicating
   // that the end of the data hasn't been reached.)  I haven't seen this
   // error when only modifying checksum bytes.
-  int index = tmp_buf.size() - 1;
+  int index = static_cast<int>(tmp_buf.size() - 1);
   tmp_buf[index]++;
-  membuf->resetBuffer(const_cast<uint8_t*>(
-                        reinterpret_cast<const uint8_t*>(tmp_buf.data())),
-                      tmp_buf.length());
+  membuf->resetBuffer(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(tmp_buf.data())),
+                      static_cast<uint32_t>(tmp_buf.length()));
 
   boost::shared_array<uint8_t> mirror(new uint8_t[buf_len]);
   try {
@@ -280,11 +284,11 @@
   }
 }
 
-void test_write_after_flush(const uint8_t* buf, uint32_t buf_len) {
+void test_write_after_flush(const boost::shared_array<uint8_t> buf, uint32_t buf_len) {
   // write some data
-  boost::shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
-  boost::shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf));
-  zlib_trans->write(buf, buf_len);
+  shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
+  shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf));
+  zlib_trans->write(buf.get(), buf_len);
 
   // call finish()
   zlib_trans->finish();
@@ -318,32 +322,52 @@
 void test_no_write() {
   // Verify that no data is written to the underlying transport if we
   // never write data to the TZlibTransport.
-  boost::shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
+  shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
   {
     // Create a TZlibTransport object, and immediately destroy it
     // when it goes out of scope.
     TZlibTransport w_zlib_trans(membuf);
   }
 
-  BOOST_CHECK_EQUAL(membuf->available_read(), (uint32_t) 0);
+  BOOST_CHECK_EQUAL(membuf->available_read(), (uint32_t)0);
+}
+
+void test_get_underlying_transport() {
+  shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
+  shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf));
+  BOOST_CHECK_EQUAL(membuf.get(), zlib_trans->getUnderlyingTransport().get());
 }
 
 /*
  * Initialization
  */
 
-#define ADD_TEST_CASE(suite, name, function, ...) \
-  do { \
-    ::std::ostringstream name_ss; \
-    name_ss << name << "-" << BOOST_STRINGIZE(function); \
-    ::boost::unit_test::test_case* tc = ::boost::unit_test::make_test_case( \
-        ::std::tr1::bind(function, ## __VA_ARGS__), \
-        name_ss.str()); \
-    (suite)->add(tc); \
+#if (BOOST_VERSION >= 105900)
+#define ADD_TEST_CASE(suite, name, _FUNC, ...)                                                     \
+  do {                                                                                             \
+    ::std::ostringstream name_ss;                                                                  \
+    name_ss << name << "-" << BOOST_STRINGIZE(_FUNC);                                              \
+    ::std::function<void ()> test_func =                                        \
+        ::std::bind(_FUNC, ##__VA_ARGS__);                                      \
+    ::boost::unit_test::test_case* tc                                                              \
+        = ::boost::unit_test::make_test_case(test_func, name_ss.str(), __FILE__, __LINE__);        \
+    (suite)->add(tc);                                                                              \
   } while (0)
+#else
+#define ADD_TEST_CASE(suite, name, _FUNC, ...)                                                     \
+  do {                                                                                             \
+    ::std::ostringstream name_ss;                                                                  \
+    name_ss << name << "-" << BOOST_STRINGIZE(_FUNC);                                              \
+    ::boost::unit_test::test_case* tc                                                              \
+        = ::boost::unit_test::make_test_case(::std::bind(_FUNC,                 \
+                                                                            ##__VA_ARGS__),        \
+                                             name_ss.str());                                       \
+    (suite)->add(tc);                                                                              \
+  } while (0)
+#endif
 
-void add_tests(unit_test::test_suite* suite,
-               const uint8_t* buf,
+void add_tests(boost::unit_test::test_suite* suite,
+               const boost::shared_array<uint8_t>& buf,
                uint32_t buf_len,
                const char* name) {
   ADD_TEST_CASE(suite, name, test_write_then_read, buf, buf_len);
@@ -352,20 +376,30 @@
   ADD_TEST_CASE(suite, name, test_invalid_checksum, buf, buf_len);
   ADD_TEST_CASE(suite, name, test_write_after_flush, buf, buf_len);
 
-  boost::shared_ptr<SizeGenerator> size_32k(new ConstantSizeGenerator(1<<15));
-  boost::shared_ptr<SizeGenerator> size_lognormal(new LogNormalSizeGenerator(20, 30));
-  ADD_TEST_CASE(suite, name << "-constant",
-                test_read_write_mix, buf, buf_len,
-                size_32k, size_32k);
-  ADD_TEST_CASE(suite, name << "-lognormal-write",
-                test_read_write_mix, buf, buf_len,
-                size_lognormal, size_32k);
-  ADD_TEST_CASE(suite, name << "-lognormal-read",
-                test_read_write_mix, buf, buf_len,
-                size_32k, size_lognormal);
-  ADD_TEST_CASE(suite, name << "-lognormal-both",
-                test_read_write_mix, buf, buf_len,
-                size_lognormal, size_lognormal);
+  shared_ptr<SizeGenerator> size_32k(new ConstantSizeGenerator(1 << 15));
+  shared_ptr<SizeGenerator> size_lognormal(new LogNormalSizeGenerator(20, 30));
+  ADD_TEST_CASE(suite, name << "-constant", test_read_write_mix, buf, buf_len, size_32k, size_32k);
+  ADD_TEST_CASE(suite,
+                name << "-lognormal-write",
+                test_read_write_mix,
+                buf,
+                buf_len,
+                size_lognormal,
+                size_32k);
+  ADD_TEST_CASE(suite,
+                name << "-lognormal-read",
+                test_read_write_mix,
+                buf,
+                buf_len,
+                size_32k,
+                size_lognormal);
+  ADD_TEST_CASE(suite,
+                name << "-lognormal-both",
+                test_read_write_mix,
+                buf,
+                buf_len,
+                size_lognormal,
+                size_lognormal);
 
   // Test with a random size distribution,
   // but use the exact same distribution for reading as for writing.
@@ -373,11 +407,15 @@
   // Because the SizeGenerator makes a copy of the random number generator,
   // both SizeGenerators should return the exact same set of values, since they
   // both start with random number generators in the same state.
-  boost::shared_ptr<SizeGenerator> write_size_gen(new LogNormalSizeGenerator(20, 30));
-  boost::shared_ptr<SizeGenerator> read_size_gen(new LogNormalSizeGenerator(20, 30));
-  ADD_TEST_CASE(suite, name << "-lognormal-same-distribution",
-                test_read_write_mix, buf, buf_len,
-                write_size_gen, read_size_gen);
+  shared_ptr<SizeGenerator> write_size_gen(new LogNormalSizeGenerator(20, 30));
+  shared_ptr<SizeGenerator> read_size_gen(new LogNormalSizeGenerator(20, 30));
+  ADD_TEST_CASE(suite,
+                name << "-lognormal-same-distribution",
+                test_read_write_mix,
+                buf,
+                buf_len,
+                write_size_gen,
+                read_size_gen);
 }
 
 void print_usage(FILE* f, const char* argv0) {
@@ -387,64 +425,45 @@
   fprintf(f, "  --help\n");
 }
 
-void parse_args(int argc, char* argv[]) {
-  uint32_t seed = 0;
-  bool has_seed = false;
-
-  struct option long_opts[] = {
-    { "help", false, NULL, 'h' },
-    { "seed", true, NULL, 's' },
-    { NULL, 0, NULL, 0 }
-  };
-
-  while (true) {
-    optopt = 1;
-    int optchar = getopt_long(argc, argv, "hs:", long_opts, NULL);
-    if (optchar == -1) {
-      break;
-    }
-
-    switch (optchar) {
-      case 's': {
-        char *endptr;
-        seed = strtol(optarg, &endptr, 0);
-        if (endptr == optarg || *endptr != '\0') {
-          fprintf(stderr, "invalid seed value \"%s\": must be a positive "
-                  "integer\n", optarg);
-          exit(1);
-        }
-        has_seed = true;
-        break;
-      }
-      case 'h':
-        print_usage(stdout, argv[0]);
-        exit(0);
-      case '?':
-        exit(1);
-      default:
-        // Only happens if someone adds another option to the optarg string,
-        // but doesn't update the switch statement to handle it.
-        fprintf(stderr, "unknown option \"-%c\"\n", optchar);
-        exit(1);
-    }
-  }
-
-  if (!has_seed) {
-    seed = time(NULL);
-  }
-
+#ifdef BOOST_TEST_DYN_LINK
+bool init_unit_test_suite() {
+  uint32_t seed = static_cast<uint32_t>(time(NULL));
+#ifdef HAVE_INTTYPES_H
   printf("seed: %" PRIu32 "\n", seed);
+#endif
   rng.seed(seed);
-}
 
-unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
-  parse_args(argc, argv);
-
-  unit_test::test_suite* suite =
-    &boost::unit_test::framework::master_test_suite();
+  boost::unit_test::test_suite* suite = &boost::unit_test::framework::master_test_suite();
   suite->p_name.value = "ZlibTest";
 
-  uint32_t buf_len = 1024*32;
+  uint32_t buf_len = 1024 * 32;
+  add_tests(suite, gen_uniform_buffer(buf_len, 'a'), buf_len, "uniform");
+  add_tests(suite, gen_compressible_buffer(buf_len), buf_len, "compressible");
+  add_tests(suite, gen_random_buffer(buf_len), buf_len, "random");
+
+  suite->add(BOOST_TEST_CASE(test_no_write));
+  suite->add(BOOST_TEST_CASE(test_get_underlying_transport));
+
+  return true;
+}
+
+int main( int argc, char* argv[] ) {
+  return ::boost::unit_test::unit_test_main(&init_unit_test_suite,argc,argv);
+}
+#else
+boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
+  THRIFT_UNUSED_VARIABLE(argc);
+  THRIFT_UNUSED_VARIABLE(argv);
+  uint32_t seed = static_cast<uint32_t>(time(NULL));
+#ifdef HAVE_INTTYPES_H
+  printf("seed: %" PRIu32 "\n", seed);
+#endif
+  rng.seed(seed);
+
+  boost::unit_test::test_suite* suite = &boost::unit_test::framework::master_test_suite();
+  suite->p_name.value = "ZlibTest";
+
+  uint32_t buf_len = 1024 * 32;
   add_tests(suite, gen_uniform_buffer(buf_len, 'a'), buf_len, "uniform");
   add_tests(suite, gen_compressible_buffer(buf_len), buf_len, "compressible");
   add_tests(suite, gen_random_buffer(buf_len), buf_len, "random");
@@ -453,3 +472,4 @@
 
   return NULL;
 }
+#endif
diff --git a/lib/cpp/test/concurrency/MutexTest.cpp b/lib/cpp/test/concurrency/MutexTest.cpp
new file mode 100644
index 0000000..781ec1a
--- /dev/null
+++ b/lib/cpp/test/concurrency/MutexTest.cpp
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// This is linked into the UnitTests test executable
+
+#include <boost/test/unit_test.hpp>
+
+#include "thrift/concurrency/Exception.h"
+#include "thrift/concurrency/Mutex.h"
+
+using boost::unit_test::test_suite;
+using boost::unit_test::framework::master_test_suite;
+
+using namespace apache::thrift::concurrency;
+
+struct LFAT
+{
+  LFAT()
+    : uut(Mutex::ERRORCHECK_INITIALIZER)
+  {
+    BOOST_CHECK_EQUAL(0, pthread_mutex_init(&mx, 0));
+    BOOST_CHECK_EQUAL(0, pthread_cond_init(&cv, 0));
+  }
+
+  Mutex uut;
+  pthread_mutex_t mx;
+  pthread_cond_t cv;
+};
+
+// Helper for testing mutex behavior when locked by another thread
+void * lockFromAnotherThread(void *ptr)
+{
+  struct LFAT *lfat = (LFAT *)ptr;
+  BOOST_CHECK_EQUAL   (0, pthread_mutex_lock(&lfat->mx));           // synchronize with testing thread
+  BOOST_CHECK_NO_THROW( lfat->uut.lock());
+  BOOST_CHECK_EQUAL   (0, pthread_cond_signal(&lfat->cv));          // tell testing thread we have locked the mutex
+  BOOST_CHECK_EQUAL   (0, pthread_cond_wait(&lfat->cv, &lfat->mx)); // wait for testing thread to signal condition variable telling us to unlock
+  BOOST_CHECK_NO_THROW( lfat->uut.unlock());
+  return ptr;                                                       // testing thread should join to ensure completeness
+}
+
+BOOST_AUTO_TEST_SUITE(MutexTest)
+
+BOOST_AUTO_TEST_CASE(happy_path)
+{
+  Mutex uut(Mutex::ERRORCHECK_INITIALIZER);                         // needed to test unlocking twice without undefined behavior
+
+  BOOST_CHECK_NO_THROW( uut.lock());
+  BOOST_CHECK_THROW   ( uut.lock(), SystemResourceException);       // EDEADLK (this thread owns it)
+  BOOST_CHECK_NO_THROW( uut.unlock());
+}
+
+BOOST_AUTO_TEST_CASE(recursive_happy_path)
+{
+  Mutex uut(Mutex::RECURSIVE_INITIALIZER);
+
+  BOOST_CHECK_NO_THROW( uut.lock());
+  BOOST_CHECK_NO_THROW( uut.lock());
+  BOOST_CHECK_NO_THROW( uut.unlock());
+  BOOST_CHECK_NO_THROW( uut.lock());
+  BOOST_CHECK_NO_THROW( uut.lock());
+  BOOST_CHECK_NO_THROW( uut.unlock());
+  BOOST_CHECK_NO_THROW( uut.lock());
+  BOOST_CHECK_NO_THROW( uut.unlock());
+  BOOST_CHECK_NO_THROW( uut.unlock());
+  BOOST_CHECK_NO_THROW( uut.unlock());
+}
+
+BOOST_AUTO_TEST_CASE(trylock)
+{
+  Mutex uut(Mutex::ADAPTIVE_INITIALIZER);   // just using another initializer for coverage
+
+  BOOST_CHECK         ( uut.trylock());
+  BOOST_CHECK         (!uut.trylock());
+  BOOST_CHECK_NO_THROW( uut.unlock());
+}
+
+BOOST_AUTO_TEST_CASE(timedlock)
+{
+  pthread_t th;
+  struct LFAT lfat;
+
+  BOOST_CHECK         ( lfat.uut.timedlock(100));
+  BOOST_CHECK_THROW   ( lfat.uut.timedlock(100),
+                        SystemResourceException);                   // EDEADLK (current thread owns mutex - logic error)
+  BOOST_CHECK_NO_THROW( lfat.uut.unlock());
+
+  BOOST_CHECK_EQUAL   (0, pthread_mutex_lock(&lfat.mx));            // synchronize with helper thread
+  BOOST_CHECK_EQUAL   (0, pthread_create(&th, NULL,
+                            lockFromAnotherThread, &lfat));         // create helper thread
+  BOOST_CHECK_EQUAL   (0, pthread_cond_wait(&lfat.cv, &lfat.mx));   // wait for helper thread to lock mutex
+
+  BOOST_CHECK         (!lfat.uut.timedlock(100));                   // false: another thread owns the lock
+
+  BOOST_CHECK_EQUAL   (0, pthread_cond_signal(&lfat.cv));           // tell helper thread we are done
+  BOOST_CHECK_EQUAL   (0, pthread_mutex_unlock(&lfat.mx));          // let helper thread clean up
+  BOOST_CHECK_EQUAL   (0, pthread_join(th, 0));                     // wait for testing thread to unlock and be done
+}
+
+BOOST_AUTO_TEST_CASE(underlying)
+{
+  Mutex uut;
+
+  BOOST_CHECK         ( uut.getUnderlyingImpl());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/concurrency/RWMutexStarveTest.cpp b/lib/cpp/test/concurrency/RWMutexStarveTest.cpp
new file mode 100644
index 0000000..985a230
--- /dev/null
+++ b/lib/cpp/test/concurrency/RWMutexStarveTest.cpp
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// This is linked into the UnitTests test executable
+
+#include <boost/test/unit_test.hpp>
+
+#include "thrift/concurrency/Mutex.h"
+#include "thrift/concurrency/PosixThreadFactory.h"
+#include <memory>
+
+using std::shared_ptr;
+using boost::unit_test::test_suite;
+using boost::unit_test::framework::master_test_suite;
+
+using namespace apache::thrift::concurrency;
+
+class Locker : public Runnable {
+protected:
+  Locker(shared_ptr<ReadWriteMutex> rwlock, bool writer)
+    : rwlock_(rwlock), writer_(writer), started_(false), gotLock_(false), signaled_(false) {}
+
+public:
+  virtual void run() {
+    started_ = true;
+    if (writer_) {
+      rwlock_->acquireWrite();
+    } else {
+      rwlock_->acquireRead();
+    }
+    gotLock_ = true;
+    while (!signaled_) {
+      usleep(5000);
+    }
+    rwlock_->release();
+  }
+
+  bool started() const { return started_; }
+  bool gotLock() const { return gotLock_; }
+  void signal() { signaled_ = true; }
+
+protected:
+  shared_ptr<ReadWriteMutex> rwlock_;
+  bool writer_;
+  volatile bool started_;
+  volatile bool gotLock_;
+  volatile bool signaled_;
+};
+
+class Reader : public Locker {
+public:
+  Reader(shared_ptr<ReadWriteMutex> rwlock) : Locker(rwlock, false) {}
+};
+
+class Writer : public Locker {
+public:
+  Writer(shared_ptr<ReadWriteMutex> rwlock) : Locker(rwlock, true) {}
+};
+
+void test_starve(PosixThreadFactory::POLICY policy) {
+  // the man pages for pthread_wrlock_rdlock suggest that any OS guarantee about
+  // writer starvation may be influenced by the scheduling policy, so let's try
+  // all 3 policies to see if any of them work.
+  PosixThreadFactory factory(policy);
+  factory.setDetached(false);
+
+  shared_ptr<ReadWriteMutex> rwlock(new NoStarveReadWriteMutex());
+
+  shared_ptr<Reader> reader1(new Reader(rwlock));
+  shared_ptr<Reader> reader2(new Reader(rwlock));
+  shared_ptr<Writer> writer(new Writer(rwlock));
+
+  shared_ptr<Thread> treader1 = factory.newThread(reader1);
+  shared_ptr<Thread> treader2 = factory.newThread(reader2);
+  shared_ptr<Thread> twriter = factory.newThread(writer);
+
+  // launch a reader and make sure he has the lock
+  treader1->start();
+  while (!reader1->gotLock()) {
+    usleep(2000);
+  }
+
+  // launch a writer and make sure he's blocked on the lock
+  twriter->start();
+  while (!writer->started()) {
+    usleep(2000);
+  }
+  // tricky part... we can never be 100% sure that the writer is actually
+  // blocked on the lock, but we can pretty reasonably sure because we know
+  // he just executed the line immediately before getting the lock, and
+  // we'll wait a full second for him to get on it.
+  sleep(1);
+
+  // launch a second reader... if the RWMutex guarantees that writers won't
+  // starve, this reader should not be able to acquire the lock until the writer
+  // has acquired and released it.
+  treader2->start();
+  while (!reader2->started()) {
+    usleep(2000);
+  }
+  // again... can't be 100% sure the reader is waiting on (or has) the lock
+  // but we can be close.
+  sleep(1);
+
+  // tell reader 1 to let go of the lock
+  reader1->signal();
+
+  // wait for someone to get the lock
+  while (!reader2->gotLock() && !writer->gotLock()) {
+    usleep(2000);
+  }
+
+  // the test succeeded if the WRITER got the lock.
+  bool success = writer->gotLock();
+
+  // tell everyone we're done and wait for them to finish
+  reader2->signal();
+  writer->signal();
+  treader1->join();
+  treader2->join();
+  twriter->join();
+
+  // make sure it worked.
+  BOOST_CHECK_MESSAGE(success, "writer is starving");
+}
+
+BOOST_AUTO_TEST_SUITE(RWMutexStarveTest)
+
+BOOST_AUTO_TEST_CASE(test_starve_other) {
+  test_starve(PosixThreadFactory::OTHER);
+}
+
+BOOST_AUTO_TEST_CASE(test_starve_rr) {
+  test_starve(PosixThreadFactory::ROUND_ROBIN);
+}
+
+BOOST_AUTO_TEST_CASE(test_starve_fifo) {
+  test_starve(PosixThreadFactory::FIFO);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/lib/cpp/test/concurrency/Tests.cpp b/lib/cpp/test/concurrency/Tests.cpp
index c80bb88..fc0ba7f 100644
--- a/lib/cpp/test/concurrency/Tests.cpp
+++ b/lib/cpp/test/concurrency/Tests.cpp
@@ -25,11 +25,15 @@
 #include "TimerManagerTests.h"
 #include "ThreadManagerTests.h"
 
+// The test weight, where 10 is 10 times more threads than baseline
+// and the baseline is optimized for running in valgrind
+static int WEIGHT = 10;
+
 int main(int argc, char** argv) {
 
   std::string arg;
 
-  std::vector<std::string>  args(argc - 1 > 1 ? argc - 1 : 1);
+  std::vector<std::string> args(argc - 1 > 1 ? argc - 1 : 1);
 
   args[0] = "all";
 
@@ -37,6 +41,11 @@
     args[ix - 1] = std::string(argv[ix]);
   }
 
+  if (getenv("VALGRIND") != 0) {
+	  // lower the scale of every test
+	  WEIGHT = 1;
+  }
+
   bool runAll = args[0].compare("all") == 0;
 
   if (runAll || args[0].compare("thread-factory") == 0) {
@@ -45,25 +54,38 @@
 
     std::cout << "ThreadFactory tests..." << std::endl;
 
-    size_t count =  1000;
-    size_t floodLoops =  1;
-    size_t floodCount =  100000;
+    int reapLoops = 2 * WEIGHT;
+    int reapCount = 100 * WEIGHT;
+    size_t floodLoops = 3;
+    size_t floodCount = 500 * WEIGHT;
 
-    std::cout << "\t\tThreadFactory reap N threads test: N = " << count << std::endl;
+    std::cout << "\t\tThreadFactory reap N threads test: N = " << reapLoops << "x" << reapCount << std::endl;
 
-    assert(threadFactoryTests.reapNThreads(count));
+    if (!threadFactoryTests.reapNThreads(reapLoops, reapCount)) {
+      std::cerr << "\t\ttThreadFactory reap N threads FAILED" << std::endl;
+      return 1;
+    }
 
-    std::cout << "\t\tThreadFactory floodN threads test: N = " << floodCount << std::endl;
+    std::cout << "\t\tThreadFactory flood N threads test: N = " << floodLoops << "x" << floodCount << std::endl;
 
-    assert(threadFactoryTests.floodNTest(floodLoops, floodCount));
+    if (!threadFactoryTests.floodNTest(floodLoops, floodCount)) {
+      std::cerr << "\t\ttThreadFactory flood N threads FAILED" << std::endl;
+      return 1;
+    }
 
     std::cout << "\t\tThreadFactory synchronous start test" << std::endl;
 
-    assert(threadFactoryTests.synchStartTest());
+    if (!threadFactoryTests.synchStartTest()) {
+      std::cerr << "\t\ttThreadFactory synchronous start FAILED" << std::endl;
+      return 1;
+    }
 
     std::cout << "\t\tThreadFactory monitor timeout test" << std::endl;
 
-    assert(threadFactoryTests.monitorTimeoutTest());
+    if (!threadFactoryTests.monitorTimeoutTest()) {
+      std::cerr << "\t\ttThreadFactory monitor timeout FAILED" << std::endl;
+      return 1;
+    }
   }
 
   if (runAll || args[0].compare("util") == 0) {
@@ -89,7 +111,6 @@
     std::cout << "\t\t\tscall per ms: " << count / (time01 - time00) << std::endl;
   }
 
-
   if (runAll || args[0].compare("timer-manager") == 0) {
 
     std::cout << "TimerManager tests..." << std::endl;
@@ -98,7 +119,38 @@
 
     TimerManagerTests timerManagerTests;
 
-    assert(timerManagerTests.test00());
+    if (!timerManagerTests.test00()) {
+      std::cerr << "\t\tTimerManager tests FAILED" << std::endl;
+      return 1;
+    }
+
+    std::cout << "\t\tTimerManager test01" << std::endl;
+
+    if (!timerManagerTests.test01()) {
+      std::cerr << "\t\tTimerManager tests FAILED" << std::endl;
+      return 1;
+    }
+
+    std::cout << "\t\tTimerManager test02" << std::endl;
+
+    if (!timerManagerTests.test02()) {
+      std::cerr << "\t\tTimerManager tests FAILED" << std::endl;
+      return 1;
+    }
+
+    std::cout << "\t\tTimerManager test03" << std::endl;
+
+    if (!timerManagerTests.test03()) {
+      std::cerr << "\t\tTimerManager tests FAILED" << std::endl;
+      return 1;
+    }
+
+    std::cout << "\t\tTimerManager test04" << std::endl;
+
+    if (!timerManagerTests.test04()) {
+      std::cerr << "\t\tTimerManager tests FAILED" << std::endl;
+      return 1;
+    }
   }
 
   if (runAll || args[0].compare("thread-manager") == 0) {
@@ -106,23 +158,34 @@
     std::cout << "ThreadManager tests..." << std::endl;
 
     {
-
-      size_t workerCount = 100;
-
-      size_t taskCount = 100000;
-
+      size_t workerCount = 10 * WEIGHT;
+      size_t taskCount = 500 * WEIGHT;
       int64_t delay = 10LL;
 
-      std::cout << "\t\tThreadManager load test: worker count: " << workerCount << " task count: " << taskCount << " delay: " << delay << std::endl;
-
       ThreadManagerTests threadManagerTests;
 
-      assert(threadManagerTests.loadTest(taskCount, delay, workerCount));
+      std::cout << "\t\tThreadManager api test:" << std::endl;
 
-      std::cout << "\t\tThreadManager block test: worker count: " << workerCount << " delay: " << delay << std::endl;
+      if (!threadManagerTests.apiTest()) {
+        std::cerr << "\t\tThreadManager apiTest FAILED" << std::endl;
+        return 1;
+      }
 
-      assert(threadManagerTests.blockTest(delay, workerCount));
+      std::cout << "\t\tThreadManager load test: worker count: " << workerCount
+                << " task count: " << taskCount << " delay: " << delay << std::endl;
 
+      if (!threadManagerTests.loadTest(taskCount, delay, workerCount)) {
+        std::cerr << "\t\tThreadManager loadTest FAILED" << std::endl;
+        return 1;
+      }
+
+      std::cout << "\t\tThreadManager block test: worker count: " << workerCount
+                << " delay: " << delay << std::endl;
+
+      if (!threadManagerTests.blockTest(delay, workerCount)) {
+        std::cerr << "\t\tThreadManager blockTest FAILED" << std::endl;
+        return 1;
+      }
     }
   }
 
@@ -134,22 +197,30 @@
 
       size_t minWorkerCount = 2;
 
-      size_t maxWorkerCount = 512;
+      size_t maxWorkerCount = 8;
 
-      size_t tasksPerWorker = 1000;
+      size_t tasksPerWorker = 100 * WEIGHT;
 
-      int64_t delay = 10LL;
+      int64_t delay = 5LL;
 
-      for (size_t workerCount = minWorkerCount; workerCount < maxWorkerCount; workerCount*= 2) {
+      for (size_t workerCount = minWorkerCount; workerCount <= maxWorkerCount; workerCount *= 4) {
 
         size_t taskCount = workerCount * tasksPerWorker;
 
-        std::cout << "\t\tThreadManager load test: worker count: " << workerCount << " task count: " << taskCount << " delay: " << delay << std::endl;
+        std::cout << "\t\tThreadManager load test: worker count: " << workerCount
+                  << " task count: " << taskCount << " delay: " << delay << std::endl;
 
         ThreadManagerTests threadManagerTests;
 
-        threadManagerTests.loadTest(taskCount, delay, workerCount);
+        if (!threadManagerTests.loadTest(taskCount, delay, workerCount))
+        {
+          std::cerr << "\t\tThreadManager loadTest FAILED" << std::endl;
+          return 1;
+        }
       }
     }
   }
+
+  std::cout << "ALL TESTS PASSED" << std::endl;
+  return 0;
 }
diff --git a/lib/cpp/test/concurrency/ThreadFactoryTests.h b/lib/cpp/test/concurrency/ThreadFactoryTests.h
old mode 100755
new mode 100644
index fda6c9e..ba98502
--- a/lib/cpp/test/concurrency/ThreadFactoryTests.h
+++ b/lib/cpp/test/concurrency/ThreadFactoryTests.h
@@ -21,16 +21,19 @@
 #include <thrift/concurrency/Thread.h>
 #include <thrift/concurrency/PlatformThreadFactory.h>
 #include <thrift/concurrency/Monitor.h>
+#include <thrift/concurrency/Mutex.h>
 #include <thrift/concurrency/Util.h>
 
 #include <assert.h>
-#include <unistd.h>
 #include <iostream>
-#include <set>
+#include <vector>
 
-namespace apache { namespace thrift { namespace concurrency { namespace test {
+namespace apache {
+namespace thrift {
+namespace concurrency {
+namespace test {
 
-using boost::shared_ptr;
+using std::shared_ptr;
 using namespace apache::thrift::concurrency;
 
 /**
@@ -41,132 +44,84 @@
 class ThreadFactoryTests {
 
 public:
-
-  static const double ERROR;
-
-  class Task: public Runnable {
-
-  public:
-
-    Task() {}
-
-    void run() {
-      std::cout << "\t\t\tHello World" << std::endl;
-    }
-  };
-
-  /**
-   * Hello world test
-   */
-  bool helloWorldTest() {
-
-    PlatformThreadFactory threadFactory = PlatformThreadFactory();
-
-    shared_ptr<Task> task = shared_ptr<Task>(new ThreadFactoryTests::Task());
-
-    shared_ptr<Thread> thread = threadFactory.newThread(task);
-
-    thread->start();
-
-    thread->join();
-
-    std::cout << "\t\t\tSuccess!" << std::endl;
-
-    return true;
-  }
-
   /**
    * Reap N threads
    */
-  class ReapNTask: public Runnable {
+  class ReapNTask : public Runnable {
 
-   public:
-
-    ReapNTask(Monitor& monitor, int& activeCount) :
-      _monitor(monitor),
-      _count(activeCount) {}
+  public:
+    ReapNTask(Monitor& monitor, int& activeCount) : _monitor(monitor), _count(activeCount) {}
 
     void run() {
       Synchronized s(_monitor);
-
-      _count--;
-
-      //std::cout << "\t\t\tthread count: " << _count << std::endl;
-
-      if (_count == 0) {
+      
+      if (--_count == 0) {
         _monitor.notify();
       }
     }
 
     Monitor& _monitor;
-
     int& _count;
   };
 
-  bool reapNThreads(int loop=1, int count=10) {
+  bool reapNThreads(int loop = 1, int count = 10) {
 
-    PlatformThreadFactory threadFactory =  PlatformThreadFactory();
+    PlatformThreadFactory threadFactory = PlatformThreadFactory();
+    shared_ptr<Monitor> monitor(new Monitor);
 
-    Monitor* monitor = new Monitor();
+    for (int lix = 0; lix < loop; lix++) {
 
-    for(int lix = 0; lix < loop; lix++) {
+      int activeCount = 0;
 
-      int* activeCount  = new int(count);
-
-      std::set<shared_ptr<Thread> > threads;
-
+      std::vector<shared_ptr<Thread> > threads;
       int tix;
 
       for (tix = 0; tix < count; tix++) {
         try {
-          threads.insert(threadFactory.newThread(shared_ptr<Runnable>(new ReapNTask(*monitor, *activeCount))));
-        } catch(SystemResourceException& e) {
-          std::cout << "\t\t\tfailed to create " << lix * count + tix << " thread " << e.what() << std::endl;
+          ++activeCount;
+          threads.push_back(
+              threadFactory.newThread(shared_ptr<Runnable>(new ReapNTask(*monitor, activeCount))));
+        } catch (SystemResourceException& e) {
+          std::cout << "\t\t\tfailed to create " << lix* count + tix << " thread " << e.what()
+                    << std::endl;
           throw e;
         }
       }
 
       tix = 0;
-      for (std::set<shared_ptr<Thread> >::const_iterator thread = threads.begin(); thread != threads.end(); tix++, ++thread) {
+      for (std::vector<shared_ptr<Thread> >::const_iterator thread = threads.begin();
+           thread != threads.end();
+           tix++, ++thread) {
 
         try {
           (*thread)->start();
-        } catch(SystemResourceException& e) {
-          std::cout << "\t\t\tfailed to start  " << lix * count + tix << " thread " << e.what() << std::endl;
+        } catch (SystemResourceException& e) {
+          std::cout << "\t\t\tfailed to start  " << lix* count + tix << " thread " << e.what()
+                    << std::endl;
           throw e;
         }
       }
 
       {
         Synchronized s(*monitor);
-        while (*activeCount > 0) {
+        while (activeCount > 0) {
           monitor->wait(1000);
         }
       }
-      delete activeCount;
-      std::cout << "\t\t\treaped " << lix * count << " threads" << std::endl;
+      
+      std::cout << "\t\t\treaped " << lix* count << " threads" << std::endl;
     }
 
     std::cout << "\t\t\tSuccess!" << std::endl;
-
     return true;
   }
 
-  class SynchStartTask: public Runnable {
+  class SynchStartTask : public Runnable {
 
-   public:
+  public:
+    enum STATE { UNINITIALIZED, STARTING, STARTED, STOPPING, STOPPED };
 
-    enum STATE {
-      UNINITIALIZED,
-      STARTING,
-      STARTED,
-      STOPPING,
-      STOPPED
-    };
-
-    SynchStartTask(Monitor& monitor, volatile  STATE& state) :
-      _monitor(monitor),
-      _state(state) {}
+    SynchStartTask(Monitor& monitor, volatile STATE& state) : _monitor(monitor), _state(state) {}
 
     void run() {
       {
@@ -190,9 +145,9 @@
       }
     }
 
-   private:
+  private:
     Monitor& _monitor;
-    volatile  STATE& _state;
+    volatile STATE& _state;
   };
 
   bool synchStartTest() {
@@ -201,9 +156,10 @@
 
     SynchStartTask::STATE state = SynchStartTask::UNINITIALIZED;
 
-    shared_ptr<SynchStartTask> task = shared_ptr<SynchStartTask>(new SynchStartTask(monitor, state));
+    shared_ptr<SynchStartTask> task
+        = shared_ptr<SynchStartTask>(new SynchStartTask(monitor, state));
 
-    PlatformThreadFactory threadFactory =  PlatformThreadFactory();
+    PlatformThreadFactory threadFactory = PlatformThreadFactory();
 
     shared_ptr<Thread> thread = threadFactory.newThread(task);
 
@@ -227,8 +183,8 @@
       Synchronized s(monitor);
 
       try {
-          monitor.wait(100);
-      } catch(TimedOutException& e) {
+        monitor.wait(100);
+      } catch (TimedOutException&) {
       }
 
       if (state == SynchStartTask::STARTED) {
@@ -252,104 +208,102 @@
     return true;
   }
 
-  /** See how accurate monitor timeout is. */
+  /**
+   * The only guarantee a monitor timeout can give you is that
+   * it will take "at least" as long as the timeout, no less.
+   * There is absolutely no guarantee around regaining execution
+   * near the timeout.  On a busy system (like inside a third party
+   * CI environment) it could take quite a bit longer than the
+   * requested timeout, and that's ok.
+   */
 
-  bool monitorTimeoutTest(size_t count=1000, int64_t timeout=10) {
+  bool monitorTimeoutTest(int64_t count = 1000, int64_t timeout = 2) {
 
     Monitor monitor;
 
     int64_t startTime = Util::currentTime();
 
-    for (size_t ix = 0; ix < count; ix++) {
+    for (int64_t ix = 0; ix < count; ix++) {
       {
         Synchronized s(monitor);
         try {
-            monitor.wait(timeout);
-        } catch(TimedOutException& e) {
+          monitor.wait(timeout);
+        } catch (TimedOutException&) {
         }
       }
     }
 
     int64_t endTime = Util::currentTime();
 
-    double error = ((endTime - startTime) - (count * timeout)) / (double)(count * timeout);
+  bool success = (endTime - startTime) >= (count * timeout);
 
-    if (error < 0.0)  {
-
-      error *= 1.0;
-    }
-
-    bool success = error < ThreadFactoryTests::ERROR;
-
-    std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "! expected time: " << count * timeout << "ms elapsed time: "<< endTime - startTime << "ms error%: " << error * 100.0 << std::endl;
+    std::cout << "\t\t\t" << (success ? "Success" : "Failure")
+              << ": minimum required time to elapse " << count * timeout
+              << "ms; actual elapsed time " << endTime - startTime << "ms"
+              << std::endl;
 
     return success;
   }
 
-
   class FloodTask : public Runnable {
   public:
-
-    FloodTask(const size_t id) :_id(id) {}
-    ~FloodTask(){
-      if(_id % 1000 == 0) {
+    FloodTask(const size_t id, Monitor& mon) : _id(id), _mon(mon) {}
+    ~FloodTask() {
+      if (_id % 10000 == 0) {
+		Synchronized sync(_mon);
         std::cout << "\t\tthread " << _id << " done" << std::endl;
       }
     }
 
-    void run(){
-      if(_id % 1000 == 0) {
+    void run() {
+      if (_id % 10000 == 0) {
+		Synchronized sync(_mon);
         std::cout << "\t\tthread " << _id << " started" << std::endl;
       }
-
-      usleep(1);
     }
     const size_t _id;
+    Monitor& _mon;
   };
 
-  void foo(PlatformThreadFactory *tf) {
-    (void) tf;
-  }
+  void foo(PlatformThreadFactory* tf) { (void)tf; }
 
-  bool floodNTest(size_t loop=1, size_t count=100000) {
+  bool floodNTest(size_t loop = 1, size_t count = 100000) {
 
     bool success = false;
-
-    for(size_t lix = 0; lix < loop; lix++) {
+    Monitor mon;
+	
+    for (size_t lix = 0; lix < loop; lix++) {
 
       PlatformThreadFactory threadFactory = PlatformThreadFactory();
       threadFactory.setDetached(true);
 
-        for(size_t tix = 0; tix < count; tix++) {
+      for (size_t tix = 0; tix < count; tix++) {
 
-          try {
+        try {
 
-            shared_ptr<FloodTask> task(new FloodTask(lix * count + tix ));
+          shared_ptr<FloodTask> task(new FloodTask(lix * count + tix, mon));
+          shared_ptr<Thread> thread = threadFactory.newThread(task);
+          thread->start();
 
-            shared_ptr<Thread> thread = threadFactory.newThread(task);
+        } catch (TException& e) {
 
-            thread->start();
+          std::cout << "\t\t\tfailed to start  " << lix* count + tix << " thread " << e.what()
+                    << std::endl;
 
-            usleep(1);
-
-          } catch (TException& e) {
-
-            std::cout << "\t\t\tfailed to start  " << lix * count + tix << " thread " << e.what() << std::endl;
-
-            return success;
-          }
+          return success;
         }
+      }
 
-        std::cout << "\t\t\tflooded " << (lix + 1) * count << " threads" << std::endl;
-
-        success = true;
+      Synchronized sync(mon);
+      std::cout << "\t\t\tflooded " << (lix + 1) * count << " threads" << std::endl;
+      success = true;
     }
 
     return success;
   }
 };
 
-const double ThreadFactoryTests::ERROR = .20;
-
-}}}} // apache::thrift::concurrency::test
-
+}
+}
+}
+} // apache::thrift::concurrency::test
diff --git a/lib/cpp/test/concurrency/ThreadManagerTests.h b/lib/cpp/test/concurrency/ThreadManagerTests.h
old mode 100755
new mode 100644
index 4e53a2d..d6c092d
--- a/lib/cpp/test/concurrency/ThreadManagerTests.h
+++ b/lib/cpp/test/concurrency/ThreadManagerTests.h
@@ -24,51 +24,51 @@
 #include <thrift/concurrency/Util.h>
 
 #include <assert.h>
+#include <deque>
 #include <set>
 #include <iostream>
-#include <set>
 #include <stdint.h>
 
-namespace apache { namespace thrift { namespace concurrency { namespace test {
+namespace apache {
+namespace thrift {
+namespace concurrency {
+namespace test {
 
 using namespace apache::thrift::concurrency;
 
-/**
- * ThreadManagerTests class
- *
- * @version $Id:$
- */
+static std::deque<std::shared_ptr<Runnable> > m_expired;
+static void expiredNotifier(std::shared_ptr<Runnable> runnable)
+{
+  m_expired.push_back(runnable);
+}
+
+static void sleep_(int64_t millisec) {
+  Monitor _sleep;
+  Synchronized s(_sleep);
+
+  try {
+    _sleep.wait(millisec);
+  } catch (TimedOutException&) {
+    ;
+  } catch (...) {
+    assert(0);
+  }
+}
+
 class ThreadManagerTests {
 
 public:
-
-  static const double ERROR;
-
-  class Task: public Runnable {
+  class Task : public Runnable {
 
   public:
-
-    Task(Monitor& monitor, size_t& count, int64_t timeout) :
-      _monitor(monitor),
-      _count(count),
-      _timeout(timeout),
-      _done(false) {}
+    Task(Monitor& monitor, size_t& count, int64_t timeout)
+      : _monitor(monitor), _count(count), _timeout(timeout), _startTime(0), _endTime(0), _done(false) {}
 
     void run() {
 
       _startTime = Util::currentTime();
 
-      {
-        Synchronized s(_sleep);
-
-        try {
-          _sleep.wait(_timeout);
-        } catch(TimedOutException& e) {
-          ;
-        }catch(...) {
-          assert(0);
-        }
-      }
+      sleep_(_timeout);
 
       _endTime = Util::currentTime();
 
@@ -80,9 +80,7 @@
         // std::cout << "Thread " << _count << " completed " << std::endl;
 
         _count--;
-
-        if (_count == 0) {
-
+        if (_count % 10000 == 0) {
           _monitor.notify();
         }
       }
@@ -102,7 +100,7 @@
    * completes. Verify that all tasks completed and that thread manager cleans
    * up properly on delete.
    */
-  bool loadTest(size_t count=100, int64_t timeout=100LL, size_t workerCount=4) {
+  bool loadTest(size_t count = 100, int64_t timeout = 100LL, size_t workerCount = 4) {
 
     Monitor monitor;
 
@@ -110,9 +108,10 @@
 
     shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(workerCount);
 
-    shared_ptr<PlatformThreadFactory> threadFactory = shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory());
+    shared_ptr<PlatformThreadFactory> threadFactory
+        = shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory(false));
 
-#ifndef USE_BOOST_THREAD
+#if !USE_STD_THREAD
     threadFactory->setPriority(PosixThreadFactory::HIGHEST);
 #endif
     threadManager->threadFactory(threadFactory);
@@ -123,21 +122,26 @@
 
     for (size_t ix = 0; ix < count; ix++) {
 
-      tasks.insert(shared_ptr<ThreadManagerTests::Task>(new ThreadManagerTests::Task(monitor, activeCount, timeout)));
+      tasks.insert(shared_ptr<ThreadManagerTests::Task>(
+          new ThreadManagerTests::Task(monitor, activeCount, timeout)));
     }
 
     int64_t time00 = Util::currentTime();
 
-    for (std::set<shared_ptr<ThreadManagerTests::Task> >::iterator ix = tasks.begin(); ix != tasks.end(); ix++) {
+    for (std::set<shared_ptr<ThreadManagerTests::Task> >::iterator ix = tasks.begin();
+         ix != tasks.end();
+         ix++) {
 
-        threadManager->add(*ix);
+      threadManager->add(*ix);
     }
 
+    std::cout << "\t\t\t\tloaded " << count << " tasks to execute" << std::endl;
+
     {
       Synchronized s(monitor);
 
-      while(activeCount > 0) {
-
+      while (activeCount > 0) {
+        std::cout << "\t\t\t\tactiveCount = " << activeCount << std::endl;
         monitor.wait();
       }
     }
@@ -151,7 +155,9 @@
     int64_t minTime = 9223372036854775807LL;
     int64_t maxTime = 0;
 
-    for (std::set<shared_ptr<ThreadManagerTests::Task> >::iterator ix = tasks.begin(); ix != tasks.end(); ix++) {
+    for (std::set<shared_ptr<ThreadManagerTests::Task> >::iterator ix = tasks.begin();
+         ix != tasks.end();
+         ix++) {
 
       shared_ptr<ThreadManagerTests::Task> task = *ix;
 
@@ -175,59 +181,57 @@
         maxTime = delta;
       }
 
-      averageTime+= delta;
+      averageTime += delta;
     }
 
     averageTime /= count;
 
-    std::cout << "\t\t\tfirst start: " << firstTime << "ms Last end: " << lastTime << "ms min: " << minTime << "ms max: " << maxTime << "ms average: " << averageTime << "ms" << std::endl;
+    std::cout << "\t\t\tfirst start: " << firstTime << " Last end: " << lastTime
+              << " min: " << minTime << "ms max: " << maxTime << "ms average: " << averageTime
+              << "ms" << std::endl;
 
-    double expectedTime = ((count + (workerCount - 1)) / workerCount) * timeout;
+    bool success = (time01 - time00) >= ((int64_t)count * timeout) / (int64_t)workerCount;
 
-    double error = ((time01 - time00) - expectedTime) / expectedTime;
-
-    if (error < 0) {
-      error*= -1.0;
-    }
-
-    bool success = error < ERROR;
-
-    std::cout << "\t\t\t" << (success ? "Success" : "Failure") << "! expected time: " << expectedTime << "ms elapsed time: "<< time01 - time00 << "ms error%: " << error * 100.0 << std::endl;
+    std::cout << "\t\t\t" << (success ? "Success" : "Failure")
+              << "! expected time: " << ((int64_t)count * timeout) / (int64_t)workerCount << "ms elapsed time: " << time01 - time00
+              << "ms" << std::endl;
 
     return success;
   }
 
-  class BlockTask: public Runnable {
+  class BlockTask : public Runnable {
 
   public:
-
-    BlockTask(Monitor& monitor, Monitor& bmonitor, size_t& count) :
-      _monitor(monitor),
-      _bmonitor(bmonitor),
-      _count(count) {}
+    BlockTask(Monitor& entryMonitor, Monitor& blockMonitor, bool& blocked, Monitor& doneMonitor, size_t& count)
+      : _entryMonitor(entryMonitor), _entered(false), _blockMonitor(blockMonitor), _blocked(blocked), _doneMonitor(doneMonitor), _count(count) {}
 
     void run() {
       {
-        Synchronized s(_bmonitor);
-
-        _bmonitor.wait();
-
+        Synchronized s(_entryMonitor);
+        _entered = true;
+        _entryMonitor.notify();
       }
 
       {
-        Synchronized s(_monitor);
+        Synchronized s(_blockMonitor);
+        while (_blocked) {
+          _blockMonitor.wait();
+        }
+      }
 
-        _count--;
-
-        if (_count == 0) {
-
-          _monitor.notify();
+      {
+        Synchronized s(_doneMonitor);
+        if (--_count == 0) {
+          _doneMonitor.notify();
         }
       }
     }
 
-    Monitor& _monitor;
-    Monitor& _bmonitor;
+    Monitor& _entryMonitor;
+    bool _entered;
+    Monitor& _blockMonitor;
+    bool& _blocked;
+    Monitor& _doneMonitor;
     size_t& _count;
   };
 
@@ -235,147 +239,447 @@
    * Block test.  Create pendingTaskCountMax tasks.  Verify that we block adding the
    * pendingTaskCountMax + 1th task.  Verify that we unblock when a task completes */
 
-  bool blockTest(int64_t timeout=100LL, size_t workerCount=2) {
-    (void) timeout;
+  bool blockTest(int64_t timeout = 100LL, size_t workerCount = 2) {
+    (void)timeout;
     bool success = false;
 
     try {
 
-      Monitor bmonitor;
-      Monitor monitor;
+      Monitor entryMonitor;   // not used by this test
+      Monitor blockMonitor;
+      bool blocked[] = {true, true, true};
+      Monitor doneMonitor;
 
       size_t pendingTaskMaxCount = workerCount;
 
       size_t activeCounts[] = {workerCount, pendingTaskMaxCount, 1};
 
-      shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(workerCount, pendingTaskMaxCount);
+      shared_ptr<ThreadManager> threadManager
+          = ThreadManager::newSimpleThreadManager(workerCount, pendingTaskMaxCount);
 
-      shared_ptr<PlatformThreadFactory> threadFactory = shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory());
+      shared_ptr<PlatformThreadFactory> threadFactory
+          = shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory());
 
-#ifndef USE_BOOST_THREAD
+#if !USE_STD_THREAD
       threadFactory->setPriority(PosixThreadFactory::HIGHEST);
 #endif
       threadManager->threadFactory(threadFactory);
 
       threadManager->start();
 
-      std::set<shared_ptr<ThreadManagerTests::BlockTask> > tasks;
+      std::vector<shared_ptr<ThreadManagerTests::BlockTask> > tasks;
+      tasks.reserve(workerCount + pendingTaskMaxCount);
 
       for (size_t ix = 0; ix < workerCount; ix++) {
 
-        tasks.insert(shared_ptr<ThreadManagerTests::BlockTask>(new ThreadManagerTests::BlockTask(monitor, bmonitor,activeCounts[0])));
+        tasks.push_back(shared_ptr<ThreadManagerTests::BlockTask>(
+            new ThreadManagerTests::BlockTask(entryMonitor, blockMonitor, blocked[0], doneMonitor, activeCounts[0])));
       }
 
       for (size_t ix = 0; ix < pendingTaskMaxCount; ix++) {
 
-        tasks.insert(shared_ptr<ThreadManagerTests::BlockTask>(new ThreadManagerTests::BlockTask(monitor, bmonitor,activeCounts[1])));
+        tasks.push_back(shared_ptr<ThreadManagerTests::BlockTask>(
+            new ThreadManagerTests::BlockTask(entryMonitor, blockMonitor, blocked[1], doneMonitor, activeCounts[1])));
       }
 
-      for (std::set<shared_ptr<ThreadManagerTests::BlockTask> >::iterator ix = tasks.begin(); ix != tasks.end(); ix++) {
+      for (std::vector<shared_ptr<ThreadManagerTests::BlockTask> >::iterator ix = tasks.begin();
+           ix != tasks.end();
+           ix++) {
         threadManager->add(*ix);
       }
 
-      if(!(success = (threadManager->totalTaskCount() == pendingTaskMaxCount + workerCount))) {
+      if (!(success = (threadManager->totalTaskCount() == pendingTaskMaxCount + workerCount))) {
         throw TException("Unexpected pending task count");
       }
 
-      shared_ptr<ThreadManagerTests::BlockTask> extraTask(new ThreadManagerTests::BlockTask(monitor, bmonitor, activeCounts[2]));
+      shared_ptr<ThreadManagerTests::BlockTask> extraTask(
+          new ThreadManagerTests::BlockTask(entryMonitor, blockMonitor, blocked[2], doneMonitor, activeCounts[2]));
 
       try {
         threadManager->add(extraTask, 1);
         throw TException("Unexpected success adding task in excess of pending task count");
-      } catch(TooManyPendingTasksException& e) {
+      } catch (TooManyPendingTasksException&) {
         throw TException("Should have timed out adding task in excess of pending task count");
-      } catch(TimedOutException& e) {
+      } catch (TimedOutException&) {
         // Expected result
       }
 
       try {
         threadManager->add(extraTask, -1);
         throw TException("Unexpected success adding task in excess of pending task count");
-      } catch(TimedOutException& e) {
+      } catch (TimedOutException&) {
         throw TException("Unexpected timeout adding task in excess of pending task count");
-      } catch(TooManyPendingTasksException& e) {
+      } catch (TooManyPendingTasksException&) {
         // Expected result
       }
 
-      std::cout << "\t\t\t" << "Pending tasks " << threadManager->pendingTaskCount()  << std::endl;
+      std::cout << "\t\t\t"
+                << "Pending tasks " << threadManager->pendingTaskCount() << std::endl;
 
       {
-        Synchronized s(bmonitor);
-
-        bmonitor.notifyAll();
+        Synchronized s(blockMonitor);
+        blocked[0] = false;
+        blockMonitor.notifyAll();
       }
 
       {
-        Synchronized s(monitor);
-
-        while(activeCounts[0] != 0) {
-          monitor.wait();
+        Synchronized s(doneMonitor);
+        while (activeCounts[0] != 0) {
+          doneMonitor.wait();
         }
       }
 
-      std::cout << "\t\t\t" << "Pending tasks " << threadManager->pendingTaskCount() << std::endl;
+      std::cout << "\t\t\t"
+                << "Pending tasks " << threadManager->pendingTaskCount() << std::endl;
 
       try {
         threadManager->add(extraTask, 1);
-      } catch(TimedOutException& e) {
-        std::cout << "\t\t\t" << "add timed out unexpectedly"  << std::endl;
+      } catch (TimedOutException&) {
+        std::cout << "\t\t\t"
+                  << "add timed out unexpectedly" << std::endl;
         throw TException("Unexpected timeout adding task");
 
-      } catch(TooManyPendingTasksException& e) {
-        std::cout << "\t\t\t" << "add encountered too many pending exepctions" << std::endl;
+      } catch (TooManyPendingTasksException&) {
+        std::cout << "\t\t\t"
+                  << "add encountered too many pending exepctions" << std::endl;
         throw TException("Unexpected timeout adding task");
       }
 
       // Wake up tasks that were pending before and wait for them to complete
 
       {
-        Synchronized s(bmonitor);
-
-        bmonitor.notifyAll();
+        Synchronized s(blockMonitor);
+        blocked[1] = false;
+        blockMonitor.notifyAll();
       }
 
       {
-        Synchronized s(monitor);
-
-        while(activeCounts[1] != 0) {
-          monitor.wait();
+        Synchronized s(doneMonitor);
+        while (activeCounts[1] != 0) {
+          doneMonitor.wait();
         }
       }
 
       // Wake up the extra task and wait for it to complete
 
       {
-        Synchronized s(bmonitor);
-
-        bmonitor.notifyAll();
+        Synchronized s(blockMonitor);
+        blocked[2] = false;
+        blockMonitor.notifyAll();
       }
 
       {
-        Synchronized s(monitor);
-
-        while(activeCounts[2] != 0) {
-          monitor.wait();
+        Synchronized s(doneMonitor);
+        while (activeCounts[2] != 0) {
+          doneMonitor.wait();
         }
       }
 
-      if(!(success = (threadManager->totalTaskCount() == 0))) {
-        throw TException("Unexpected pending task count");
+      threadManager->stop();
+
+      if (!(success = (threadManager->totalTaskCount() == 0))) {
+        throw TException("Unexpected total task count");
       }
 
-    } catch(TException& e) {
+    } catch (TException& e) {
       std::cout << "ERROR: " << e.what() << std::endl;
     }
 
     std::cout << "\t\t\t" << (success ? "Success" : "Failure") << std::endl;
     return success;
- }
+  }
+
+
+  bool apiTest() {
+
+    // prove currentTime has milliseconds granularity since many other things depend on it
+    int64_t a = Util::currentTime();
+    sleep_(100);
+    int64_t b = Util::currentTime();
+    if (b - a < 50 || b - a > 150) {
+      std::cerr << "\t\t\texpected 100ms gap, found " << (b-a) << "ms gap instead." << std::endl;
+      return false;
+    }
+
+#if !USE_STD_THREAD
+    // test once with a detached thread factory and once with a joinable thread factory
+
+    shared_ptr<PosixThreadFactory> threadFactory
+        = shared_ptr<PosixThreadFactory>(new PosixThreadFactory(false));
+
+    std::cout << "\t\t\tapiTest with joinable thread factory" << std::endl;
+    if (!apiTestWithThreadFactory(threadFactory)) {
+      return false;
+    }
+
+    threadFactory.reset(new PosixThreadFactory(true));
+    std::cout << "\t\t\tapiTest with detached thread factory" << std::endl;
+    return apiTestWithThreadFactory(threadFactory);
+#else
+    return apiTestWithThreadFactory(shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory()));
+#endif
+
+  }
+
+  bool apiTestWithThreadFactory(shared_ptr<PlatformThreadFactory> threadFactory)
+  {
+    shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(1);
+    threadManager->threadFactory(threadFactory);
+
+#if !USE_STD_THREAD
+    threadFactory->setPriority(PosixThreadFactory::HIGHEST);
+
+    // verify we cannot change the thread factory to one with the opposite detached setting
+    shared_ptr<PlatformThreadFactory> threadFactory2
+        = shared_ptr<PosixThreadFactory>(new PlatformThreadFactory(
+          PosixThreadFactory::ROUND_ROBIN,
+          PosixThreadFactory::NORMAL,
+          1,
+          !threadFactory->isDetached()));
+    try {
+      threadManager->threadFactory(threadFactory2);
+      // if the call succeeded we changed the thread factory to one that had the opposite setting for "isDetached()".
+      // this is bad, because the thread manager checks with the thread factory to see if it should join threads
+      // as they are leaving - so the detached status of new threads cannot change while there are existing threads.
+      std::cerr << "\t\t\tShould not be able to change thread factory detached disposition" << std::endl;
+      return false;
+    }
+    catch (InvalidArgumentException& ex) {
+      /* expected */
+    }
+#endif
+
+    std::cout << "\t\t\t\tstarting.. " << std::endl;
+
+    threadManager->start();
+    threadManager->setExpireCallback(expiredNotifier); // std::bind(&ThreadManagerTests::expiredNotifier, this));
+
+#define EXPECT(FUNC, COUNT) { size_t c = FUNC; if (c != COUNT) { std::cerr << "expected " #FUNC" to be " #COUNT ", but was " << c << std::endl; return false; } }
+
+    EXPECT(threadManager->workerCount(), 1);
+    EXPECT(threadManager->idleWorkerCount(), 1);
+    EXPECT(threadManager->pendingTaskCount(), 0);
+
+    std::cout << "\t\t\t\tadd 2nd worker.. " << std::endl;
+
+    threadManager->addWorker();
+
+    EXPECT(threadManager->workerCount(), 2);
+    EXPECT(threadManager->idleWorkerCount(), 2);
+    EXPECT(threadManager->pendingTaskCount(), 0);
+
+    std::cout << "\t\t\t\tremove 2nd worker.. " << std::endl;
+
+    threadManager->removeWorker();
+
+    EXPECT(threadManager->workerCount(), 1);
+    EXPECT(threadManager->idleWorkerCount(), 1);
+    EXPECT(threadManager->pendingTaskCount(), 0);
+
+    std::cout << "\t\t\t\tremove 1st worker.. " << std::endl;
+
+    threadManager->removeWorker();
+
+    EXPECT(threadManager->workerCount(), 0);
+    EXPECT(threadManager->idleWorkerCount(), 0);
+    EXPECT(threadManager->pendingTaskCount(), 0);
+
+    std::cout << "\t\t\t\tadd blocking task.. " << std::endl;
+
+    // We're going to throw a blocking task into the mix
+    Monitor entryMonitor;   // signaled when task is running
+    Monitor blockMonitor;   // to be signaled to unblock the task
+    bool blocked(true);     // set to false before notifying
+    Monitor doneMonitor;    // signaled when count reaches zero
+    size_t activeCount = 1;
+    shared_ptr<ThreadManagerTests::BlockTask> blockingTask(
+      new ThreadManagerTests::BlockTask(entryMonitor, blockMonitor, blocked, doneMonitor, activeCount));
+    threadManager->add(blockingTask);
+
+    EXPECT(threadManager->workerCount(), 0);
+    EXPECT(threadManager->idleWorkerCount(), 0);
+    EXPECT(threadManager->pendingTaskCount(), 1);
+
+    std::cout << "\t\t\t\tadd other task.. " << std::endl;
+
+    shared_ptr<ThreadManagerTests::Task> otherTask(
+      new ThreadManagerTests::Task(doneMonitor, activeCount, 0));
+
+    threadManager->add(otherTask);
+
+    EXPECT(threadManager->workerCount(), 0);
+    EXPECT(threadManager->idleWorkerCount(), 0);
+    EXPECT(threadManager->pendingTaskCount(), 2);
+
+    std::cout << "\t\t\t\tremove blocking task specifically.. " << std::endl;
+
+    threadManager->remove(blockingTask);
+
+    EXPECT(threadManager->workerCount(), 0);
+    EXPECT(threadManager->idleWorkerCount(), 0);
+    EXPECT(threadManager->pendingTaskCount(), 1);
+
+    std::cout << "\t\t\t\tremove next pending task.." << std::endl;
+
+    shared_ptr<Runnable> nextTask = threadManager->removeNextPending();
+    if (nextTask != otherTask) {
+      std::cerr << "\t\t\t\t\texpected removeNextPending to return otherTask" << std::endl;
+      return false;
+    }
+
+    EXPECT(threadManager->workerCount(), 0);
+    EXPECT(threadManager->idleWorkerCount(), 0);
+    EXPECT(threadManager->pendingTaskCount(), 0);
+
+    std::cout << "\t\t\t\tremove next pending task (none left).." << std::endl;
+
+    nextTask = threadManager->removeNextPending();
+    if (nextTask) {
+      std::cerr << "\t\t\t\t\texpected removeNextPending to return an empty Runnable" << std::endl;
+      return false;
+    }
+
+    std::cout << "\t\t\t\tadd 2 expired tasks and 1 not.." << std::endl;
+
+    shared_ptr<ThreadManagerTests::Task> expiredTask(
+      new ThreadManagerTests::Task(doneMonitor, activeCount, 0));
+
+    threadManager->add(expiredTask, 0, 1);
+    threadManager->add(blockingTask);       // add one that hasn't expired to make sure it gets skipped
+    threadManager->add(expiredTask, 0, 1);  // add a second expired to ensure removeExpiredTasks removes both
+
+    sleep_(50);  // make sure enough time elapses for it to expire - the shortest expiration time is 1 millisecond
+
+    EXPECT(threadManager->workerCount(), 0);
+    EXPECT(threadManager->idleWorkerCount(), 0);
+    EXPECT(threadManager->pendingTaskCount(), 3);
+    EXPECT(threadManager->expiredTaskCount(), 0);
+
+    std::cout << "\t\t\t\tremove expired tasks.." << std::endl;
+
+    if (!m_expired.empty()) {
+      std::cerr << "\t\t\t\t\texpected m_expired to be empty" << std::endl;
+      return false;
+    }
+
+    threadManager->removeExpiredTasks();
+
+    if (m_expired.size() != 2) {
+      std::cerr << "\t\t\t\t\texpected m_expired to be set" << std::endl;
+      return false;
+    }
+
+    if (m_expired.front() != expiredTask) {
+      std::cerr << "\t\t\t\t\texpected m_expired[0] to be the expired task" << std::endl;
+      return false;
+    }
+    m_expired.pop_front();
+
+    if (m_expired.front() != expiredTask) {
+      std::cerr << "\t\t\t\t\texpected m_expired[1] to be the expired task" << std::endl;
+      return false;
+    }
+
+    m_expired.clear();
+
+    threadManager->remove(blockingTask);
+
+    EXPECT(threadManager->workerCount(), 0);
+    EXPECT(threadManager->idleWorkerCount(), 0);
+    EXPECT(threadManager->pendingTaskCount(), 0);
+    EXPECT(threadManager->expiredTaskCount(), 2);
+
+    std::cout << "\t\t\t\tadd expired task (again).." << std::endl;
+
+    threadManager->add(expiredTask, 0, 1);  // expires in 1ms
+    sleep_(50);  // make sure enough time elapses for it to expire - the shortest expiration time is 1ms
+
+    std::cout << "\t\t\t\tadd worker to consume expired task.." << std::endl;
+
+    threadManager->addWorker();
+    sleep_(100);  // make sure it has time to spin up and expire the task
+
+    if (m_expired.empty()) {
+      std::cerr << "\t\t\t\t\texpected m_expired to be set" << std::endl;
+      return false;
+    }
+
+    if (m_expired.front() != expiredTask) {
+      std::cerr << "\t\t\t\t\texpected m_expired to be the expired task" << std::endl;
+      return false;
+    }
+
+    m_expired.clear();
+
+    EXPECT(threadManager->workerCount(), 1);
+    EXPECT(threadManager->idleWorkerCount(), 1);
+    EXPECT(threadManager->pendingTaskCount(), 0);
+    EXPECT(threadManager->expiredTaskCount(), 3);
+
+    std::cout << "\t\t\t\ttry to remove too many workers" << std::endl;
+    try {
+      threadManager->removeWorker(2);
+      std::cerr << "\t\t\t\t\texpected InvalidArgumentException" << std::endl;
+      return false;
+    } catch (const InvalidArgumentException&) {
+      /* expected */
+    }
+
+    std::cout << "\t\t\t\tremove worker.. " << std::endl;
+
+    threadManager->removeWorker();
+
+    EXPECT(threadManager->workerCount(), 0);
+    EXPECT(threadManager->idleWorkerCount(), 0);
+    EXPECT(threadManager->pendingTaskCount(), 0);
+    EXPECT(threadManager->expiredTaskCount(), 3);
+
+    std::cout << "\t\t\t\tadd blocking task.. " << std::endl;
+
+    threadManager->add(blockingTask);
+
+    EXPECT(threadManager->workerCount(), 0);
+    EXPECT(threadManager->idleWorkerCount(), 0);
+    EXPECT(threadManager->pendingTaskCount(), 1);
+
+    std::cout << "\t\t\t\tadd worker.. " << std::endl;
+
+    threadManager->addWorker();
+    {
+      Synchronized s(entryMonitor);
+      while (!blockingTask->_entered) {
+        entryMonitor.wait();
+      }
+    }
+
+    EXPECT(threadManager->workerCount(), 1);
+    EXPECT(threadManager->idleWorkerCount(), 0);
+    EXPECT(threadManager->pendingTaskCount(), 0);
+
+    std::cout << "\t\t\t\tunblock task and remove worker.. " << std::endl;
+
+    {
+      Synchronized s(blockMonitor);
+      blocked = false;
+      blockMonitor.notifyAll();
+    }
+    threadManager->removeWorker();
+
+    EXPECT(threadManager->workerCount(), 0);
+    EXPECT(threadManager->idleWorkerCount(), 0);
+    EXPECT(threadManager->pendingTaskCount(), 0);
+
+    std::cout << "\t\t\t\tcleanup.. " << std::endl;
+
+    blockingTask.reset();
+    threadManager.reset();
+    return true;
+  }
 };
 
-const double ThreadManagerTests::ERROR = .20;
-
-}}}} // apache::thrift::concurrency
+}
+}
+}
+} // apache::thrift::concurrency
 
 using namespace apache::thrift::concurrency::test;
-
diff --git a/lib/cpp/test/concurrency/TimerManagerTests.h b/lib/cpp/test/concurrency/TimerManagerTests.h
index 4fe9667..1c52c47 100644
--- a/lib/cpp/test/concurrency/TimerManagerTests.h
+++ b/lib/cpp/test/concurrency/TimerManagerTests.h
@@ -25,55 +25,36 @@
 #include <assert.h>
 #include <iostream>
 
-namespace apache { namespace thrift { namespace concurrency { namespace test {
+namespace apache {
+namespace thrift {
+namespace concurrency {
+namespace test {
 
 using namespace apache::thrift::concurrency;
 
-/**
- * ThreadManagerTests class
- *
- * @version $Id:$
- */
 class TimerManagerTests {
 
- public:
-
-  static const double ERROR;
-
-  class Task: public Runnable {
-   public:
-
-    Task(Monitor& monitor, int64_t timeout) :
-      _timeout(timeout),
-      _startTime(Util::currentTime()),
-      _monitor(monitor),
-      _success(false),
-      _done(false) {}
+public:
+  class Task : public Runnable {
+  public:
+    Task(Monitor& monitor, int64_t timeout)
+      : _timeout(timeout),
+        _startTime(Util::currentTime()),
+        _endTime(0),
+        _monitor(monitor),
+        _success(false),
+        _done(false) {}
 
     ~Task() { std::cerr << this << std::endl; }
 
     void run() {
 
       _endTime = Util::currentTime();
+      _success = (_endTime - _startTime) >= _timeout;
 
-      // Figure out error percentage
-
-      int64_t delta = _endTime - _startTime;
-
-
-      delta = delta > _timeout ?  delta - _timeout : _timeout - delta;
-
-      float error = delta / _timeout;
-
-      if(error < ERROR) {
-        _success = true;
-      }
-
-      _done = true;
-
-      std::cout << "\t\t\tTimerManagerTests::Task[" << this << "] done" << std::endl; //debug
-
-      {Synchronized s(_monitor);
+      {
+        Synchronized s(_monitor);
+        _done = true;
         _monitor.notifyAll();
       }
     }
@@ -92,19 +73,19 @@
    * properly clean up itself and the remaining orphaned timeout task when the
    * manager goes out of scope and its destructor is called.
    */
-  bool test00(int64_t timeout=1000LL) {
+  bool test00(int64_t timeout = 1000LL) {
 
-    shared_ptr<TimerManagerTests::Task> orphanTask = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, 10 * timeout));
+    shared_ptr<TimerManagerTests::Task> orphanTask
+        = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, 10 * timeout));
 
     {
-
       TimerManager timerManager;
-
       timerManager.threadFactory(shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory()));
-
       timerManager.start();
-
-      assert(timerManager.state() == TimerManager::STARTED);
+      if (timerManager.state() != TimerManager::STARTED) {
+        std::cerr << "timerManager is not in the STARTED state, but should be" << std::endl;
+        return false;
+      }
 
       // Don't create task yet, because its constructor sets the expected completion time, and we
       // need to delay between inserting the two tasks into the run queue.
@@ -112,34 +93,161 @@
 
       {
         Synchronized s(_monitor);
-
         timerManager.add(orphanTask, 10 * timeout);
 
-        try {
-          // Wait for 1 second in order to give timerManager a chance to start sleeping in response
-          // to adding orphanTask. We need to do this so we can verify that adding the second task
-          // kicks the dispatcher out of the current wait and starts the new 1 second wait.
-          _monitor.wait (1000);
-          assert (0 == "ERROR: This wait should time out. TimerManager dispatcher may have a problem.");
-        } catch (TimedOutException &ex) {
-        }
+        THRIFT_SLEEP_USEC(timeout * 1000);
 
-        task.reset (new TimerManagerTests::Task(_monitor, timeout));
-
+        task.reset(new TimerManagerTests::Task(_monitor, timeout));
         timerManager.add(task, timeout);
-
         _monitor.wait();
       }
 
-      assert(task->_done);
-
+      if (!task->_done) {
+        std::cerr << "task is not done, but it should have executed" << std::endl;
+        return false;
+      }
 
       std::cout << "\t\t\t" << (task->_success ? "Success" : "Failure") << "!" << std::endl;
     }
 
-    // timerManager.stop(); This is where it happens via destructor
+    if (orphanTask->_done) {
+      std::cerr << "orphan task is done, but it should not have executed" << std::endl;
+      return false;
+    }
 
-    assert(!orphanTask->_done);
+    return true;
+  }
+
+  /**
+   * This test creates two tasks, removes the first one then waits for the second one. It then
+   * verifies that the timer manager properly clean up itself and the remaining orphaned timeout
+   * task when the manager goes out of scope and its destructor is called.
+   */
+  bool test01(int64_t timeout = 1000LL) {
+    TimerManager timerManager;
+    timerManager.threadFactory(shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory()));
+    timerManager.start();
+    assert(timerManager.state() == TimerManager::STARTED);
+
+    Synchronized s(_monitor);
+
+    // Setup the two tasks
+    shared_ptr<TimerManagerTests::Task> taskToRemove
+      = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout / 2));
+    timerManager.add(taskToRemove, taskToRemove->_timeout);
+
+    shared_ptr<TimerManagerTests::Task> task
+      = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout));
+    timerManager.add(task, task->_timeout);
+
+    // Remove one task and wait until the other has completed
+    timerManager.remove(taskToRemove);
+    _monitor.wait(timeout * 2);
+
+    assert(!taskToRemove->_done);
+    assert(task->_done);
+
+    return true;
+  }
+
+  /**
+   * This test creates two tasks with the same callback and another one, then removes the two
+   * duplicated then waits for the last one. It then verifies that the timer manager properly
+   * clean up itself and the remaining orphaned timeout task when the manager goes out of scope
+   * and its destructor is called.
+   */
+  bool test02(int64_t timeout = 1000LL) {
+    TimerManager timerManager;
+    timerManager.threadFactory(shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory()));
+    timerManager.start();
+    assert(timerManager.state() == TimerManager::STARTED);
+
+    Synchronized s(_monitor);
+
+    // Setup the one tasks and add it twice
+    shared_ptr<TimerManagerTests::Task> taskToRemove
+      = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout / 3));
+    timerManager.add(taskToRemove, taskToRemove->_timeout);
+    timerManager.add(taskToRemove, taskToRemove->_timeout * 2);
+
+    shared_ptr<TimerManagerTests::Task> task
+      = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout));
+    timerManager.add(task, task->_timeout);
+
+    // Remove the first task (e.g. two timers) and wait until the other has completed
+    timerManager.remove(taskToRemove);
+    _monitor.wait(timeout * 2);
+
+    assert(!taskToRemove->_done);
+    assert(task->_done);
+
+    return true;
+  }
+
+  /**
+   * This test creates two tasks, removes the first one then waits for the second one. It then
+   * verifies that the timer manager properly clean up itself and the remaining orphaned timeout
+   * task when the manager goes out of scope and its destructor is called.
+   */
+  bool test03(int64_t timeout = 1000LL) {
+    TimerManager timerManager;
+    timerManager.threadFactory(shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory()));
+    timerManager.start();
+    assert(timerManager.state() == TimerManager::STARTED);
+
+    Synchronized s(_monitor);
+
+    // Setup the two tasks
+    shared_ptr<TimerManagerTests::Task> taskToRemove
+        = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout / 2));
+    TimerManager::Timer timer = timerManager.add(taskToRemove, taskToRemove->_timeout);
+
+    shared_ptr<TimerManagerTests::Task> task
+      = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout));
+    timerManager.add(task, task->_timeout);
+
+    // Remove one task and wait until the other has completed
+    timerManager.remove(timer);
+    _monitor.wait(timeout * 2);
+
+    assert(!taskToRemove->_done);
+    assert(task->_done);
+
+    // Verify behavior when removing the removed task
+    try {
+      timerManager.remove(timer);
+      assert(0 == "ERROR: This remove should send a NoSuchTaskException exception.");
+    } catch (NoSuchTaskException&) {
+    }
+
+    return true;
+  }
+
+  /**
+   * This test creates one tasks, and tries to remove it after it has expired.
+   */
+  bool test04(int64_t timeout = 1000LL) {
+    TimerManager timerManager;
+    timerManager.threadFactory(shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory()));
+    timerManager.start();
+    assert(timerManager.state() == TimerManager::STARTED);
+
+    Synchronized s(_monitor);
+
+    // Setup the task
+    shared_ptr<TimerManagerTests::Task> task
+      = shared_ptr<TimerManagerTests::Task>(new TimerManagerTests::Task(_monitor, timeout / 10));
+    TimerManager::Timer timer = timerManager.add(task, task->_timeout);
+
+    // Wait until the task has completed
+    _monitor.wait(timeout);
+
+    // Verify behavior when removing the expired task
+    try {
+      timerManager.remove(timer);
+      assert(0 == "ERROR: This remove should send a NoSuchTaskException exception.");
+    } catch (NoSuchTaskException&) {
+    }
 
     return true;
   }
@@ -149,7 +257,7 @@
   Monitor _monitor;
 };
 
-const double TimerManagerTests::ERROR = .20;
-
-}}}} // apache::thrift::concurrency
-
+}
+}
+}
+} // apache::thrift::concurrency
diff --git a/lib/cpp/test/link/LinkTest.cpp b/lib/cpp/test/link/LinkTest.cpp
new file mode 100644
index 0000000..18e14d1
--- /dev/null
+++ b/lib/cpp/test/link/LinkTest.cpp
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+int main(int, char**) {
+  return 0;
+}
diff --git a/lib/cpp/test/link/TemplatedService1.cpp b/lib/cpp/test/link/TemplatedService1.cpp
new file mode 100644
index 0000000..da1790b
--- /dev/null
+++ b/lib/cpp/test/link/TemplatedService1.cpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * This file is a part of a link test that makes sure generated
+ * templated service headers can be included from multiple
+ * implementation files.
+ */
+
+#include "gen-cpp/ParentService.h"
diff --git a/lib/cpp/test/link/TemplatedService2.cpp b/lib/cpp/test/link/TemplatedService2.cpp
new file mode 100644
index 0000000..da1790b
--- /dev/null
+++ b/lib/cpp/test/link/TemplatedService2.cpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * This file is a part of a link test that makes sure generated
+ * templated service headers can be included from multiple
+ * implementation files.
+ */
+
+#include "gen-cpp/ParentService.h"
diff --git a/lib/cpp/test/processor/EventLog.cpp b/lib/cpp/test/processor/EventLog.cpp
index 0ac3028..e3ddbcc 100644
--- a/lib/cpp/test/processor/EventLog.cpp
+++ b/lib/cpp/test/processor/EventLog.cpp
@@ -19,27 +19,31 @@
 #include "EventLog.h"
 
 #include <stdarg.h>
+#include <stdlib.h>
 
-using namespace std;
 using namespace apache::thrift::concurrency;
 
 namespace {
 
+// Define environment variable DEBUG_EVENTLOG to enable debug logging
+// ex: $ DEBUG_EVENTLOG=1 processor_test
+static const char * DEBUG_EVENTLOG = getenv("DEBUG_EVENTLOG");
+
 void debug(const char* fmt, ...) {
-  // Comment out this return to enable debug logs from the test code.
-  return;
+  if (DEBUG_EVENTLOG) {
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
 
-  va_list ap;
-  va_start(ap, fmt);
-  vfprintf(stderr, fmt, ap);
-  va_end(ap);
-
-  fprintf(stderr, "\n");
+    fprintf(stderr, "\n");
+  }
+}
 }
 
-}
-
-namespace apache { namespace thrift { namespace test {
+namespace apache {
+namespace thrift {
+namespace test {
 
 uint32_t EventLog::nextId_ = 0;
 
@@ -74,11 +78,12 @@
   debug("New log: %d", id_);
 }
 
-void EventLog::append(EventType type, uint32_t connectionId, uint32_t callId,
-                      const string& message) {
+void EventLog::append(EventType type,
+                      uint32_t connectionId,
+                      uint32_t callId,
+                      const std::string& message) {
   Synchronized s(monitor_);
-  debug("%d <-- %u, %u, %s \"%s\"", id_, connectionId, callId, type,
-        message.c_str());
+  debug("%d <-- %u, %u, %s \"%s\"", id_, connectionId, callId, type, message.c_str());
 
   Event e(type, connectionId, callId, message);
   events_.push_back(e);
@@ -125,5 +130,6 @@
     }
   }
 }
-
-}}} // apache::thrift::test
+}
+}
+} // apache::thrift::test
diff --git a/lib/cpp/test/processor/EventLog.h b/lib/cpp/test/processor/EventLog.h
index d731cec..4f8275d 100644
--- a/lib/cpp/test/processor/EventLog.h
+++ b/lib/cpp/test/processor/EventLog.h
@@ -21,7 +21,9 @@
 
 #include <thrift/concurrency/Monitor.h>
 
-namespace apache { namespace thrift { namespace test {
+namespace apache {
+namespace thrift {
+namespace test {
 
 // Initially I made EventType an enum, but using char* results
 // in much more readable error messages when there is a mismatch.
@@ -31,21 +33,17 @@
 typedef const char* EventType;
 
 struct Event {
-  Event(EventType type, uint32_t connectionId, uint32_t callId,
-        const std::string& message) :
-      type(type),
-      connectionId(connectionId),
-      callId(callId),
-      message(message) {}
+  Event(EventType type, uint32_t connectionId, uint32_t callId, const std::string& message)
+    : type(type), connectionId(connectionId), callId(callId), message(message) {}
 
   EventType type;
-  uint32_t  connectionId;
-  uint32_t  callId;
-  std::string    message;
+  uint32_t connectionId;
+  uint32_t callId;
+  std::string message;
 };
 
 class EventLog {
- public:
+public:
   static EventType ET_LOG_END;
   static EventType ET_CONN_CREATED;
   static EventType ET_CONN_DESTROYED;
@@ -73,13 +71,15 @@
 
   EventLog();
 
-  void append(EventType type, uint32_t connectionId, uint32_t callId,
+  void append(EventType type,
+              uint32_t connectionId,
+              uint32_t callId,
               const std::string& message = "");
 
   Event waitForEvent(int64_t timeout = 500);
   Event waitForConnEvent(uint32_t connId, int64_t timeout = 500);
 
- protected:
+protected:
   typedef std::list<Event> EventList;
 
   concurrency::Monitor monitor_;
@@ -88,7 +88,8 @@
 
   static uint32_t nextId_;
 };
-
-}}} // apache::thrift::test
+}
+}
+} // apache::thrift::test
 
 #endif // _THRIFT_TEST_EVENTLOG_H_
diff --git a/lib/cpp/test/processor/Handlers.h b/lib/cpp/test/processor/Handlers.h
index 2be262a..29784d8 100644
--- a/lib/cpp/test/processor/Handlers.h
+++ b/lib/cpp/test/processor/Handlers.h
@@ -23,15 +23,14 @@
 #include "gen-cpp/ParentService.h"
 #include "gen-cpp/ChildService.h"
 
-namespace apache { namespace thrift { namespace test {
+namespace apache {
+namespace thrift {
+namespace test {
 
 class ParentHandler : virtual public ParentServiceIf {
- public:
-  ParentHandler(const boost::shared_ptr<EventLog>& log) :
-      triggerMonitor(&mutex_),
-      generation_(0),
-      wait_(false),
-      log_(log) { }
+public:
+  ParentHandler(const std::shared_ptr<EventLog>& log)
+    : triggerMonitor(&mutex_), generation_(0), wait_(false), log_(log) {}
 
   int32_t incrementGeneration() {
     concurrency::Guard g(mutex_);
@@ -57,7 +56,7 @@
     _return = strings_;
   }
 
-  void getDataWait(std::string& _return, int32_t length) {
+  void getDataWait(std::string& _return, const int32_t length) {
     concurrency::Guard g(mutex_);
     log_->append(EventLog::ET_CALL_GET_DATA_WAIT, 0, 0);
 
@@ -116,7 +115,7 @@
     triggerMonitor.notifyAll();
   }
 
- protected:
+protected:
   /**
    * blockUntilTriggered() won't return until triggerPendingCalls() is invoked
    * in another thread.
@@ -137,16 +136,19 @@
   int32_t generation_;
   bool wait_;
   std::vector<std::string> strings_;
-  boost::shared_ptr<EventLog> log_;
+  std::shared_ptr<EventLog> log_;
 };
 
-class ChildHandler : public ParentHandler, virtual public ChildServiceIf {
- public:
-  ChildHandler(const boost::shared_ptr<EventLog>& log) :
-      ParentHandler(log),
-      value_(0) {}
+#ifdef _WIN32
+  #pragma warning( push )
+  #pragma warning (disable : 4250 ) //inheriting methods via dominance
+#endif
 
-  int32_t setValue(int32_t value) {
+class ChildHandler : public ParentHandler, virtual public ChildServiceIf {
+public:
+  ChildHandler(const std::shared_ptr<EventLog>& log) : ParentHandler(log), value_(0) {}
+
+  int32_t setValue(const int32_t value) {
     concurrency::Guard g(mutex_);
     log_->append(EventLog::ET_CALL_SET_VALUE, 0, 0);
 
@@ -162,46 +164,44 @@
     return value_;
   }
 
- protected:
+protected:
   int32_t value_;
 };
 
-struct ConnContext {
- public:
-  ConnContext(boost::shared_ptr<protocol::TProtocol> in,
-              boost::shared_ptr<protocol::TProtocol> out,
-              uint32_t id) :
-      input(in),
-      output(out),
-      id(id) {}
+#ifdef _WIN32
+  #pragma warning( pop )
+#endif
 
-  boost::shared_ptr<protocol::TProtocol> input;
-  boost::shared_ptr<protocol::TProtocol> output;
+struct ConnContext {
+public:
+  ConnContext(std::shared_ptr<protocol::TProtocol> in,
+              std::shared_ptr<protocol::TProtocol> out,
+              uint32_t id)
+    : input(in), output(out), id(id) {}
+
+  std::shared_ptr<protocol::TProtocol> input;
+  std::shared_ptr<protocol::TProtocol> output;
   uint32_t id;
 };
 
 struct CallContext {
- public:
-  CallContext(ConnContext *context, uint32_t id, const std::string& name) :
-      connContext(context),
-      name(name),
-      id(id) {}
+public:
+  CallContext(ConnContext* context, uint32_t id, const std::string& name)
+    : connContext(context), name(name), id(id) {}
 
-  ConnContext *connContext;
+  ConnContext* connContext;
   std::string name;
   uint32_t id;
 };
 
 class ServerEventHandler : public server::TServerEventHandler {
- public:
-  ServerEventHandler(const boost::shared_ptr<EventLog>& log) :
-      nextId_(1),
-      log_(log) {}
+public:
+  ServerEventHandler(const std::shared_ptr<EventLog>& log) : nextId_(1), log_(log) {}
 
   virtual void preServe() {}
 
-  virtual void* createContext(boost::shared_ptr<protocol::TProtocol> input,
-                              boost::shared_ptr<protocol::TProtocol> output) {
+  virtual void* createContext(std::shared_ptr<protocol::TProtocol> input,
+                              std::shared_ptr<protocol::TProtocol> output) {
     ConnContext* context = new ConnContext(input, output, nextId_);
     ++nextId_;
     log_->append(EventLog::ET_CONN_CREATED, context->id, 0);
@@ -209,8 +209,8 @@
   }
 
   virtual void deleteContext(void* serverContext,
-                             boost::shared_ptr<protocol::TProtocol>input,
-                             boost::shared_ptr<protocol::TProtocol>output) {
+                             std::shared_ptr<protocol::TProtocol> input,
+                             std::shared_ptr<protocol::TProtocol> output) {
     ConnContext* context = reinterpret_cast<ConnContext*>(serverContext);
 
     if (input != context->input) {
@@ -225,38 +225,38 @@
     delete context;
   }
 
-  virtual void processContext(
-      void* serverContext,
-      boost::shared_ptr<transport::TTransport> transport) {
-    // TODO: We currently don't test the behavior of the processContext()
-    // calls.  The various server implementations call processContext() at
-    // slightly different times, and it is too annoying to try and account for
-    // their various differences.
-    //
-    // TThreadedServer, TThreadPoolServer, and TSimpleServer usually wait until
-    // they see the first byte of a request before calling processContext().
-    // However, they don't wait for the first byte of the very first request,
-    // and instead immediately call processContext() before any data is
-    // received.
-    //
-    // TNonblockingServer always waits until receiving the full request before
-    // calling processContext().
+  virtual void processContext(void* serverContext,
+                              std::shared_ptr<transport::TTransport> transport) {
+// TODO: We currently don't test the behavior of the processContext()
+// calls.  The various server implementations call processContext() at
+// slightly different times, and it is too annoying to try and account for
+// their various differences.
+//
+// TThreadedServer, TThreadPoolServer, and TSimpleServer usually wait until
+// they see the first byte of a request before calling processContext().
+// However, they don't wait for the first byte of the very first request,
+// and instead immediately call processContext() before any data is
+// received.
+//
+// TNonblockingServer always waits until receiving the full request before
+// calling processContext().
 #if 0
     ConnContext* context = reinterpret_cast<ConnContext*>(serverContext);
     log_->append(EventLog::ET_PROCESS, context->id, 0);
+#else
+    THRIFT_UNUSED_VARIABLE(serverContext);
+    THRIFT_UNUSED_VARIABLE(transport);
 #endif
   }
 
- protected:
+protected:
   uint32_t nextId_;
-  boost::shared_ptr<EventLog> log_;
+  std::shared_ptr<EventLog> log_;
 };
 
 class ProcessorEventHandler : public TProcessorEventHandler {
- public:
-  ProcessorEventHandler(const boost::shared_ptr<EventLog>& log) :
-      nextId_(1),
-      log_(log) {}
+public:
+  ProcessorEventHandler(const std::shared_ptr<EventLog>& log) : nextId_(1), log_(log) {}
 
   void* getContext(const char* fnName, void* serverContext) {
     ConnContext* connContext = reinterpret_cast<ConnContext*>(serverContext);
@@ -264,78 +264,75 @@
     CallContext* context = new CallContext(connContext, nextId_, fnName);
     ++nextId_;
 
-    log_->append(EventLog::ET_CALL_STARTED, connContext->id, context->id,
-                 fnName);
+    log_->append(EventLog::ET_CALL_STARTED, connContext->id, context->id, fnName);
     return context;
   }
 
   void freeContext(void* ctx, const char* fnName) {
     CallContext* context = reinterpret_cast<CallContext*>(ctx);
     checkName(context, fnName);
-    log_->append(EventLog::ET_CALL_FINISHED, context->connContext->id,
-                 context->id, fnName);
+    log_->append(EventLog::ET_CALL_FINISHED, context->connContext->id, context->id, fnName);
     delete context;
   }
 
   void preRead(void* ctx, const char* fnName) {
     CallContext* context = reinterpret_cast<CallContext*>(ctx);
     checkName(context, fnName);
-    log_->append(EventLog::ET_PRE_READ, context->connContext->id, context->id,
-                 fnName);
+    log_->append(EventLog::ET_PRE_READ, context->connContext->id, context->id, fnName);
   }
 
   void postRead(void* ctx, const char* fnName, uint32_t bytes) {
+    THRIFT_UNUSED_VARIABLE(bytes);
     CallContext* context = reinterpret_cast<CallContext*>(ctx);
     checkName(context, fnName);
-    log_->append(EventLog::ET_POST_READ, context->connContext->id, context->id,
-                 fnName);
+    log_->append(EventLog::ET_POST_READ, context->connContext->id, context->id, fnName);
   }
 
   void preWrite(void* ctx, const char* fnName) {
     CallContext* context = reinterpret_cast<CallContext*>(ctx);
     checkName(context, fnName);
-    log_->append(EventLog::ET_PRE_WRITE, context->connContext->id, context->id,
-                 fnName);
+    log_->append(EventLog::ET_PRE_WRITE, context->connContext->id, context->id, fnName);
   }
 
   void postWrite(void* ctx, const char* fnName, uint32_t bytes) {
+    THRIFT_UNUSED_VARIABLE(bytes);
     CallContext* context = reinterpret_cast<CallContext*>(ctx);
     checkName(context, fnName);
-    log_->append(EventLog::ET_POST_WRITE, context->connContext->id,
-                 context->id, fnName);
+    log_->append(EventLog::ET_POST_WRITE, context->connContext->id, context->id, fnName);
   }
 
   void asyncComplete(void* ctx, const char* fnName) {
     CallContext* context = reinterpret_cast<CallContext*>(ctx);
     checkName(context, fnName);
-    log_->append(EventLog::ET_ASYNC_COMPLETE, context->connContext->id,
-                 context->id, fnName);
+    log_->append(EventLog::ET_ASYNC_COMPLETE, context->connContext->id, context->id, fnName);
   }
 
   void handlerError(void* ctx, const char* fnName) {
     CallContext* context = reinterpret_cast<CallContext*>(ctx);
     checkName(context, fnName);
-    log_->append(EventLog::ET_HANDLER_ERROR, context->connContext->id,
-                 context->id, fnName);
+    log_->append(EventLog::ET_HANDLER_ERROR, context->connContext->id, context->id, fnName);
   }
 
- protected:
+protected:
   void checkName(const CallContext* context, const char* fnName) {
     // Note: we can't use BOOST_CHECK_EQUAL here, since the handler runs in a
     // different thread from the test functions.  Just abort if the names are
     // different
     if (context->name != fnName) {
-      fprintf(stderr, "call context name mismatch: \"%s\" != \"%s\"\n",
-              context->name.c_str(), fnName);
+      fprintf(stderr,
+              "call context name mismatch: \"%s\" != \"%s\"\n",
+              context->name.c_str(),
+              fnName);
       fflush(stderr);
       abort();
     }
   }
 
   uint32_t nextId_;
-  boost::shared_ptr<EventLog> log_;
+  std::shared_ptr<EventLog> log_;
 };
-
-}}} // apache::thrift::test
+}
+}
+} // apache::thrift::test
 
 #endif // _THRIFT_PROCESSOR_TEST_HANDLERS_H_
diff --git a/lib/cpp/test/processor/ProcessorTest.cpp b/lib/cpp/test/processor/ProcessorTest.cpp
index 58b82fb..36ce013 100644
--- a/lib/cpp/test/processor/ProcessorTest.cpp
+++ b/lib/cpp/test/processor/ProcessorTest.cpp
@@ -23,10 +23,9 @@
  * implementations.
  */
 
-#include <tr1/functional>
 #include <boost/test/unit_test.hpp>
 
-#include <thrift/concurrency/PosixThreadFactory.h>
+#include <thrift/concurrency/PlatformThreadFactory.h>
 #include <thrift/concurrency/Monitor.h>
 #include <thrift/protocol/TBinaryProtocol.h>
 #include <thrift/server/TThreadedServer.h>
@@ -34,130 +33,129 @@
 #include <thrift/server/TNonblockingServer.h>
 #include <thrift/server/TSimpleServer.h>
 #include <thrift/transport/TSocket.h>
+#include <thrift/transport/TNonblockingServerSocket.h>
 
 #include "EventLog.h"
 #include "ServerThread.h"
 #include "Handlers.h"
 #include "gen-cpp/ChildService.h"
 
-using namespace std;
-using namespace boost;
 using namespace apache::thrift;
 using namespace apache::thrift::concurrency;
 using namespace apache::thrift::protocol;
 using namespace apache::thrift::server;
-using namespace apache::thrift::transport;
-
 using namespace apache::thrift::test;
+using namespace apache::thrift::transport;
+using std::string;
+using std::vector;
 
 /*
  * Traits classes that encapsulate how to create various types of servers.
  */
 
 class TSimpleServerTraits {
- public:
+public:
   typedef TSimpleServer ServerType;
 
-  shared_ptr<TSimpleServer> createServer(
-      const shared_ptr<TProcessor>& processor,
+  std::shared_ptr<TSimpleServer> createServer(
+      const std::shared_ptr<TProcessor>& processor,
       uint16_t port,
-      const shared_ptr<TTransportFactory>& transportFactory,
-      const shared_ptr<TProtocolFactory>& protocolFactory) {
-    shared_ptr<TServerSocket> socket(new TServerSocket(port));
-    return shared_ptr<TSimpleServer>(new TSimpleServer(
-          processor, socket, transportFactory, protocolFactory));
+      const std::shared_ptr<TTransportFactory>& transportFactory,
+      const std::shared_ptr<TProtocolFactory>& protocolFactory) {
+    std::shared_ptr<TServerSocket> socket(new TServerSocket(port));
+    return std::shared_ptr<TSimpleServer>(
+        new TSimpleServer(processor, socket, transportFactory, protocolFactory));
   }
 };
 
 class TThreadedServerTraits {
- public:
+public:
   typedef TThreadedServer ServerType;
 
-  shared_ptr<TThreadedServer> createServer(
-      const shared_ptr<TProcessor>& processor,
+  std::shared_ptr<TThreadedServer> createServer(
+      const std::shared_ptr<TProcessor>& processor,
       uint16_t port,
-      const shared_ptr<TTransportFactory>& transportFactory,
-      const shared_ptr<TProtocolFactory>& protocolFactory) {
-    shared_ptr<TServerSocket> socket(new TServerSocket(port));
-    return shared_ptr<TThreadedServer>(new TThreadedServer(
-          processor, socket, transportFactory, protocolFactory));
+      const std::shared_ptr<TTransportFactory>& transportFactory,
+      const std::shared_ptr<TProtocolFactory>& protocolFactory) {
+    std::shared_ptr<TServerSocket> socket(new TServerSocket(port));
+    return std::shared_ptr<TThreadedServer>(
+        new TThreadedServer(processor, socket, transportFactory, protocolFactory));
   }
 };
 
 class TThreadPoolServerTraits {
- public:
+public:
   typedef TThreadPoolServer ServerType;
 
-  shared_ptr<TThreadPoolServer> createServer(
-      const shared_ptr<TProcessor>& processor,
+  std::shared_ptr<TThreadPoolServer> createServer(
+      const std::shared_ptr<TProcessor>& processor,
       uint16_t port,
-      const shared_ptr<TTransportFactory>& transportFactory,
-      const shared_ptr<TProtocolFactory>& protocolFactory) {
-    shared_ptr<TServerSocket> socket(new TServerSocket(port));
+      const std::shared_ptr<TTransportFactory>& transportFactory,
+      const std::shared_ptr<TProtocolFactory>& protocolFactory) {
+    std::shared_ptr<TServerSocket> socket(new TServerSocket(port));
 
-    shared_ptr<PosixThreadFactory> threadFactory(new PosixThreadFactory);
-    shared_ptr<ThreadManager> threadManager =
-      ThreadManager::newSimpleThreadManager(8);
+    std::shared_ptr<PlatformThreadFactory> threadFactory(new PlatformThreadFactory);
+    std::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(8);
     threadManager->threadFactory(threadFactory);
     threadManager->start();
 
-    return shared_ptr<TThreadPoolServer>(new TThreadPoolServer(
-          processor, socket, transportFactory, protocolFactory,
-          threadManager));
+    return std::shared_ptr<TThreadPoolServer>(
+        new TThreadPoolServer(processor, socket, transportFactory, protocolFactory, threadManager));
   }
 };
 
 class TNonblockingServerTraits {
- public:
+public:
   typedef TNonblockingServer ServerType;
 
-  shared_ptr<TNonblockingServer> createServer(
-      const shared_ptr<TProcessor>& processor,
+  std::shared_ptr<TNonblockingServer> createServer(
+      const std::shared_ptr<TProcessor>& processor,
       uint16_t port,
-      const shared_ptr<TTransportFactory>& transportFactory,
-      const shared_ptr<TProtocolFactory>& protocolFactory) {
+      const std::shared_ptr<TTransportFactory>& transportFactory,
+      const std::shared_ptr<TProtocolFactory>& protocolFactory) {
     // TNonblockingServer automatically uses TFramedTransport.
     // Raise an exception if the supplied transport factory is not a
     // TFramedTransportFactory
-    TFramedTransportFactory* framedFactory =
-      dynamic_cast<TFramedTransportFactory*>(transportFactory.get());
+    TFramedTransportFactory* framedFactory
+        = dynamic_cast<TFramedTransportFactory*>(transportFactory.get());
     if (framedFactory == NULL) {
       throw TException("TNonblockingServer must use TFramedTransport");
     }
 
-    shared_ptr<PosixThreadFactory> threadFactory(new PosixThreadFactory);
-    shared_ptr<ThreadManager> threadManager =
-      ThreadManager::newSimpleThreadManager(8);
+    std::shared_ptr<TNonblockingServerSocket> socket(new TNonblockingServerSocket(port));
+    std::shared_ptr<PlatformThreadFactory> threadFactory(new PlatformThreadFactory);
+    std::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(8);
     threadManager->threadFactory(threadFactory);
     threadManager->start();
 
-    return shared_ptr<TNonblockingServer>(new TNonblockingServer(
-          processor, protocolFactory, port, threadManager));
+    return std::shared_ptr<TNonblockingServer>(
+        new TNonblockingServer(processor, protocolFactory, socket, threadManager));
   }
 };
 
 class TNonblockingServerNoThreadsTraits {
- public:
+public:
   typedef TNonblockingServer ServerType;
 
-  shared_ptr<TNonblockingServer> createServer(
-      const shared_ptr<TProcessor>& processor,
+  std::shared_ptr<TNonblockingServer> createServer(
+      const std::shared_ptr<TProcessor>& processor,
       uint16_t port,
-      const shared_ptr<TTransportFactory>& transportFactory,
-      const shared_ptr<TProtocolFactory>& protocolFactory) {
+      const std::shared_ptr<TTransportFactory>& transportFactory,
+      const std::shared_ptr<TProtocolFactory>& protocolFactory) {
     // TNonblockingServer automatically uses TFramedTransport.
     // Raise an exception if the supplied transport factory is not a
     // TFramedTransportFactory
-    TFramedTransportFactory* framedFactory =
-      dynamic_cast<TFramedTransportFactory*>(transportFactory.get());
+    TFramedTransportFactory* framedFactory
+        = dynamic_cast<TFramedTransportFactory*>(transportFactory.get());
     if (framedFactory == NULL) {
       throw TException("TNonblockingServer must use TFramedTransport");
     }
 
+    std::shared_ptr<TNonblockingServerSocket> socket(new TNonblockingServerSocket(port));
     // Use a NULL ThreadManager
-    shared_ptr<ThreadManager> threadManager;
-    return shared_ptr<TNonblockingServer>(new TNonblockingServer(
-          processor, protocolFactory, port, threadManager));
+    std::shared_ptr<ThreadManager> threadManager;
+    return std::shared_ptr<TNonblockingServer>(
+        new TNonblockingServer(processor, protocolFactory, socket, threadManager));
   }
 };
 
@@ -174,7 +172,7 @@
  */
 
 class UntemplatedTraits {
- public:
+public:
   typedef TBinaryProtocolFactory ProtocolFactory;
   typedef TBinaryProtocol Protocol;
 
@@ -185,7 +183,7 @@
 };
 
 class TemplatedTraits {
- public:
+public:
   typedef TBinaryProtocolFactoryT<TBufferBase> ProtocolFactory;
   typedef TBinaryProtocolT<TBufferBase> Protocol;
 
@@ -195,10 +193,9 @@
   typedef ChildServiceClientT<Protocol> ChildClient;
 };
 
-
-template<typename TemplateTraits_>
+template <typename TemplateTraits_>
 class ParentServiceTraits {
- public:
+public:
   typedef typename TemplateTraits_::ParentProcessor Processor;
   typedef typename TemplateTraits_::ParentClient Client;
   typedef ParentHandler Handler;
@@ -207,9 +204,9 @@
   typedef typename TemplateTraits_::Protocol Protocol;
 };
 
-template<typename TemplateTraits_>
+template <typename TemplateTraits_>
 class ChildServiceTraits {
- public:
+public:
   typedef typename TemplateTraits_::ChildProcessor Processor;
   typedef typename TemplateTraits_::ChildClient Client;
   typedef ChildHandler Handler;
@@ -225,17 +222,18 @@
 // It would also be niec if they used covariant return types.  Unfortunately,
 // since they return shared_ptr instead of raw pointers, covariant return types
 // won't work.
-template<typename ServerTraits_, typename ServiceTraits_,
-         typename TransportFactory_ = TFramedTransportFactory,
-         typename Transport_ = TFramedTransport>
+template <typename ServerTraits_,
+          typename ServiceTraits_,
+          typename TransportFactory_ = TFramedTransportFactory,
+          typename Transport_ = TFramedTransport>
 class ServiceState : public ServerState {
- public:
+public:
   typedef typename ServiceTraits_::Processor Processor;
   typedef typename ServiceTraits_::Client Client;
   typedef typename ServiceTraits_::Handler Handler;
 
-  ServiceState() :
-      port_(0),
+  ServiceState()
+    : port_(0),
       log_(new EventLog),
       handler_(new Handler(log_)),
       processor_(new Processor(handler_)),
@@ -246,60 +244,48 @@
     processor_->setEventHandler(processorEventHandler_);
   }
 
-  shared_ptr<TServer> createServer(uint16_t port) {
+  std::shared_ptr<TServer> createServer(uint16_t port) {
     ServerTraits_ serverTraits;
-    return serverTraits.createServer(processor_, port, transportFactory_,
-                                     protocolFactory_);
+    return serverTraits.createServer(processor_, port, transportFactory_, protocolFactory_);
   }
 
-  shared_ptr<TServerEventHandler> getServerEventHandler() {
-    return serverEventHandler_;
-  }
+  std::shared_ptr<TServerEventHandler> getServerEventHandler() { return serverEventHandler_; }
 
-  void bindSuccessful(uint16_t port) {
-    port_ = port;
-  }
+  void bindSuccessful(uint16_t port) { port_ = port; }
 
-  uint16_t getPort() const {
-    return port_;
-  }
+  uint16_t getPort() const { return port_; }
 
-  const shared_ptr<EventLog>& getLog() const {
-    return log_;
-  }
+  const std::shared_ptr<EventLog>& getLog() const { return log_; }
 
-  const shared_ptr<Handler>& getHandler() const {
-    return handler_;
-  }
+  const std::shared_ptr<Handler>& getHandler() const { return handler_; }
 
-  shared_ptr<Client> createClient() {
+  std::shared_ptr<Client> createClient() {
     typedef typename ServiceTraits_::Protocol Protocol;
 
-    shared_ptr<TSocket> socket(new TSocket("127.0.0.1", port_));
-    shared_ptr<Transport_> transport(new Transport_(socket));
-    shared_ptr<Protocol> protocol(new Protocol(transport));
+    std::shared_ptr<TSocket> socket(new TSocket("127.0.0.1", port_));
+    std::shared_ptr<Transport_> transport(new Transport_(socket));
+    std::shared_ptr<Protocol> protocol(new Protocol(transport));
     transport->open();
 
-    shared_ptr<Client> client(new Client(protocol));
+    std::shared_ptr<Client> client(new Client(protocol));
     return client;
   }
 
- private:
+private:
   uint16_t port_;
-  shared_ptr<EventLog> log_;
-  shared_ptr<Handler> handler_;
-  shared_ptr<Processor> processor_;
-  shared_ptr<TTransportFactory> transportFactory_;
-  shared_ptr<TProtocolFactory> protocolFactory_;
-  shared_ptr<TServerEventHandler> serverEventHandler_;
-  shared_ptr<TProcessorEventHandler> processorEventHandler_;
+  std::shared_ptr<EventLog> log_;
+  std::shared_ptr<Handler> handler_;
+  std::shared_ptr<Processor> processor_;
+  std::shared_ptr<TTransportFactory> transportFactory_;
+  std::shared_ptr<TProtocolFactory> protocolFactory_;
+  std::shared_ptr<TServerEventHandler> serverEventHandler_;
+  std::shared_ptr<TProcessorEventHandler> processorEventHandler_;
 };
 
-
 /**
  * Check that there are no more events in the log
  */
-void checkNoEvents(const shared_ptr<EventLog>& log) {
+void checkNoEvents(const std::shared_ptr<EventLog>& log) {
   // Wait for an event with a very short timeout period.  We don't expect
   // anything to be present, so we will normally wait for the full timeout.
   // On the other hand, a non-zero timeout is nice since it does give a short
@@ -313,9 +299,9 @@
  *
  * Returns the connection ID allocated by the server.
  */
-uint32_t checkNewConnEvents(const shared_ptr<EventLog>& log) {
+uint32_t checkNewConnEvents(const std::shared_ptr<EventLog>& log) {
   // Check for an ET_CONN_CREATED event
-  Event event = log->waitForEvent();
+  Event event = log->waitForEvent(2500);
   BOOST_CHECK_EQUAL(EventLog::ET_CONN_CREATED, event.type);
 
   // Some servers call the processContext() hook immediately.
@@ -328,7 +314,7 @@
 /**
  * Check for the events that should be logged when a connection is closed.
  */
-void checkCloseEvents(const shared_ptr<EventLog>& log, uint32_t connId) {
+void checkCloseEvents(const std::shared_ptr<EventLog>& log, uint32_t connId) {
   // Check for an ET_CONN_DESTROYED event
   Event event = log->waitForEvent();
   BOOST_CHECK_EQUAL(EventLog::ET_CONN_DESTROYED, event.type);
@@ -346,7 +332,7 @@
  *
  * Returns the call ID allocated by the server.
  */
-uint32_t checkCallHandlerEvents(const shared_ptr<EventLog>& log,
+uint32_t checkCallHandlerEvents(const std::shared_ptr<EventLog>& log,
                                 uint32_t connId,
                                 EventType callType,
                                 const string& callName) {
@@ -383,7 +369,7 @@
 /**
  * Check for the events that should be after a handler returns.
  */
-void checkCallPostHandlerEvents(const shared_ptr<EventLog>& log,
+void checkCallPostHandlerEvents(const std::shared_ptr<EventLog>& log,
                                 uint32_t connId,
                                 uint32_t callId,
                                 const string& callName) {
@@ -423,7 +409,7 @@
  *
  * Returns the call ID allocated by the server.
  */
-uint32_t checkCallEvents(const shared_ptr<EventLog>& log,
+uint32_t checkCallEvents(const std::shared_ptr<EventLog>& log,
                          uint32_t connId,
                          EventType callType,
                          const string& callName) {
@@ -437,9 +423,9 @@
  * Test functions
  */
 
-template<typename State_>
-void testParentService(const shared_ptr<State_>& state) {
-  shared_ptr<typename State_::Client> client = state->createClient();
+template <typename State_>
+void testParentService(const std::shared_ptr<State_>& state) {
+  std::shared_ptr<typename State_::Client> client = state->createClient();
 
   int32_t gen = client->getGeneration();
   int32_t newGen = client->incrementGeneration();
@@ -459,9 +445,9 @@
   BOOST_REQUIRE_EQUAL("asdf", strings[2]);
 }
 
-template<typename State_>
-void testChildService(const shared_ptr<State_>& state) {
-  shared_ptr<typename State_::Client> client = state->createClient();
+template <typename State_>
+void testChildService(const std::shared_ptr<State_>& state) {
+  std::shared_ptr<typename State_::Client> client = state->createClient();
 
   // Test calling some of the parent methids via the a child client
   int32_t gen = client->getGeneration();
@@ -477,25 +463,23 @@
   BOOST_CHECK_EQUAL(99, client->getValue());
 }
 
-template<typename ServerTraits, typename TemplateTraits>
+template <typename ServerTraits, typename TemplateTraits>
 void testBasicService() {
-  typedef ServiceState< ServerTraits, ParentServiceTraits<TemplateTraits> >
-    State;
+  typedef ServiceState<ServerTraits, ParentServiceTraits<TemplateTraits> > State;
 
   // Start the server
-  shared_ptr<State> state(new State);
+  std::shared_ptr<State> state(new State);
   ServerThread serverThread(state, true);
 
   testParentService(state);
 }
 
-template<typename ServerTraits, typename TemplateTraits>
+template <typename ServerTraits, typename TemplateTraits>
 void testInheritedService() {
-  typedef ServiceState< ServerTraits, ChildServiceTraits<TemplateTraits> >
-    State;
+  typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
 
   // Start the server
-  shared_ptr<State> state(new State);
+  std::shared_ptr<State> state(new State);
   ServerThread serverThread(state, true);
 
   testParentService(state);
@@ -506,21 +490,22 @@
  * Test to make sure that the TServerEventHandler and TProcessorEventHandler
  * methods are invoked in the correct order with the actual events.
  */
-template<typename ServerTraits, typename TemplateTraits>
+template <typename ServerTraits, typename TemplateTraits>
 void testEventSequencing() {
   // We use TBufferedTransport for this test, instead of TFramedTransport.
   // This way the server will start processing data as soon as it is received,
   // instead of waiting for the full request.  This is necessary so we can
   // separate the preRead() and postRead() events.
-  typedef ServiceState< ServerTraits, ChildServiceTraits<TemplateTraits>,
-                        TBufferedTransportFactory, TBufferedTransport>
-    State;
+  typedef ServiceState<ServerTraits,
+                       ChildServiceTraits<TemplateTraits>,
+                       TBufferedTransportFactory,
+                       TBufferedTransport> State;
 
   // Start the server
-  shared_ptr<State> state(new State);
+  std::shared_ptr<State> state(new State);
   ServerThread serverThread(state, true);
 
-  const shared_ptr<EventLog>& log = state->getLog();
+  const std::shared_ptr<EventLog>& log = state->getLog();
 
   // Make sure we're at the end of the log
   checkNoEvents(log);
@@ -529,7 +514,7 @@
 
   // Make sure createContext() is called after a connection has been
   // established.  We open a plain socket instead of creating a client.
-  shared_ptr<TSocket> socket(new TSocket("127.0.0.1", state->getPort()));
+  std::shared_ptr<TSocket> socket(new TSocket("127.0.0.1", state->getPort()));
   socket->open();
 
   // Make sure the proper events occurred after a new connection
@@ -539,7 +524,7 @@
   // can test the timing for the preRead() call.
   string requestName = "getDataWait";
   string eventName = "ParentService.getDataWait";
-  int32_t seqid = time(NULL);
+  int32_t seqid = int32_t(time(NULL));
   TBinaryProtocol protocol(socket);
   protocol.writeMessageBegin(requestName, T_CALL, seqid);
   socket->flush();
@@ -563,7 +548,7 @@
   // Send the rest of the request
   protocol.writeStructBegin("ParentService_getDataNotified_pargs");
   protocol.writeFieldBegin("length", apache::thrift::protocol::T_I32, 1);
-  protocol.writeI32(8*1024*1024);
+  protocol.writeI32(8 * 1024 * 1024);
   protocol.writeFieldEnd();
   protocol.writeFieldStop();
   protocol.writeStructEnd();
@@ -607,7 +592,7 @@
   checkNoEvents(log);
 
   // Read the response header
-  std::string responseName;
+  string responseName;
   int32_t responseSeqid = 0;
   apache::thrift::protocol::TMessageType responseType;
   protocol.readMessageBegin(responseName, responseType, responseSeqid);
@@ -645,25 +630,24 @@
   checkNoEvents(log);
 }
 
-template<typename ServerTraits, typename TemplateTraits>
+template <typename ServerTraits, typename TemplateTraits>
 void testSeparateConnections() {
-  typedef ServiceState< ServerTraits, ChildServiceTraits<TemplateTraits> >
-    State;
+  typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
 
   // Start the server
-  shared_ptr<State> state(new State);
+  std::shared_ptr<State> state(new State);
   ServerThread serverThread(state, true);
 
-  const shared_ptr<EventLog>& log = state->getLog();
+  const std::shared_ptr<EventLog>& log = state->getLog();
 
   // Create a client
-  shared_ptr<typename State::Client> client1 = state->createClient();
+  std::shared_ptr<typename State::Client> client1 = state->createClient();
 
   // Make sure the expected events were logged
   uint32_t client1Id = checkNewConnEvents(log);
 
   // Create a second client
-  shared_ptr<typename State::Client> client2 = state->createClient();
+  std::shared_ptr<typename State::Client> client2 = state->createClient();
 
   // Make sure the expected events were logged
   uint32_t client2Id = checkNewConnEvents(log);
@@ -674,20 +658,19 @@
   // Make a call, and check for the proper events
   int32_t value = 5;
   client1->setValue(value);
-  uint32_t call1 = checkCallEvents(log, client1Id, EventLog::ET_CALL_SET_VALUE,
-                                     "ChildService.setValue");
+  uint32_t call1
+      = checkCallEvents(log, client1Id, EventLog::ET_CALL_SET_VALUE, "ChildService.setValue");
 
   // Make a call with client2
   int32_t v = client2->getValue();
   BOOST_CHECK_EQUAL(value, v);
-  checkCallEvents(log, client2Id, EventLog::ET_CALL_GET_VALUE,
-                  "ChildService.getValue");
+  checkCallEvents(log, client2Id, EventLog::ET_CALL_GET_VALUE, "ChildService.getValue");
 
   // Make another call with client1
   v = client1->getValue();
   BOOST_CHECK_EQUAL(value, v);
-  uint32_t call2 = checkCallEvents(log, client1Id, EventLog::ET_CALL_GET_VALUE,
-                                     "ChildService.getValue");
+  uint32_t call2
+      = checkCallEvents(log, client1Id, EventLog::ET_CALL_GET_VALUE, "ChildService.getValue");
   BOOST_CHECK_NE(call1, call2);
 
   // Close the second client, and check for the appropriate events
@@ -695,19 +678,18 @@
   checkCloseEvents(log, client2Id);
 }
 
-template<typename ServerTraits, typename TemplateTraits>
+template <typename ServerTraits, typename TemplateTraits>
 void testOnewayCall() {
-  typedef ServiceState< ServerTraits, ChildServiceTraits<TemplateTraits> >
-    State;
+  typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
 
   // Start the server
-  shared_ptr<State> state(new State);
+  std::shared_ptr<State> state(new State);
   ServerThread serverThread(state, true);
 
-  const shared_ptr<EventLog>& log = state->getLog();
+  const std::shared_ptr<EventLog>& log = state->getLog();
 
   // Create a client
-  shared_ptr<typename State::Client> client = state->createClient();
+  std::shared_ptr<typename State::Client> client = state->createClient();
   uint32_t connId = checkNewConnEvents(log);
 
   // Make a oneway call
@@ -716,9 +698,7 @@
   state->getHandler()->prepareTriggeredCall();
   client->onewayWait();
   string callName = "ParentService.onewayWait";
-  uint32_t callId = checkCallHandlerEvents(log, connId,
-                                           EventLog::ET_CALL_ONEWAY_WAIT,
-                                           callName);
+  uint32_t callId = checkCallHandlerEvents(log, connId, EventLog::ET_CALL_ONEWAY_WAIT, callName);
 
   // There shouldn't be any more events
   checkNoEvents(log);
@@ -750,19 +730,18 @@
   checkNoEvents(log);
 }
 
-template<typename ServerTraits, typename TemplateTraits>
+template <typename ServerTraits, typename TemplateTraits>
 void testExpectedError() {
-  typedef ServiceState< ServerTraits, ChildServiceTraits<TemplateTraits> >
-    State;
+  typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
 
   // Start the server
-  shared_ptr<State> state(new State);
+  std::shared_ptr<State> state(new State);
   ServerThread serverThread(state, true);
 
-  const shared_ptr<EventLog>& log = state->getLog();
+  const std::shared_ptr<EventLog>& log = state->getLog();
 
   // Create a client
-  shared_ptr<typename State::Client> client = state->createClient();
+  std::shared_ptr<typename State::Client> client = state->createClient();
   uint32_t connId = checkNewConnEvents(log);
 
   // Send the exceptionWait() call
@@ -770,9 +749,7 @@
   string message = "test 1234 test";
   client->send_exceptionWait(message);
   string callName = "ParentService.exceptionWait";
-  uint32_t callId = checkCallHandlerEvents(log, connId,
-                                           EventLog::ET_CALL_EXCEPTION_WAIT,
-                                           callName);
+  uint32_t callId = checkCallHandlerEvents(log, connId, EventLog::ET_CALL_EXCEPTION_WAIT, callName);
 
   // There shouldn't be any more events
   checkNoEvents(log);
@@ -790,6 +767,9 @@
     BOOST_FAIL("expected MyError to be thrown");
   } catch (const MyError& e) {
     BOOST_CHECK_EQUAL(message, e.message);
+    // Check if std::exception::what() is handled properly
+    size_t message_pos = string(e.what()).find("TException - service has thrown: MyError");
+    BOOST_CHECK_NE(message_pos, string::npos);
   }
 
   // Now we should see the events for a normal call finish
@@ -805,19 +785,18 @@
   checkNoEvents(log);
 }
 
-template<typename ServerTraits, typename TemplateTraits>
+template <typename ServerTraits, typename TemplateTraits>
 void testUnexpectedError() {
-  typedef ServiceState< ServerTraits, ChildServiceTraits<TemplateTraits> >
-    State;
+  typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
 
   // Start the server
-  shared_ptr<State> state(new State);
+  std::shared_ptr<State> state(new State);
   ServerThread serverThread(state, true);
 
-  const shared_ptr<EventLog>& log = state->getLog();
+  const std::shared_ptr<EventLog>& log = state->getLog();
 
   // Create a client
-  shared_ptr<typename State::Client> client = state->createClient();
+  std::shared_ptr<typename State::Client> client = state->createClient();
   uint32_t connId = checkNewConnEvents(log);
 
   // Send the unexpectedExceptionWait() call
@@ -825,8 +804,8 @@
   string message = "1234 test 5678";
   client->send_unexpectedExceptionWait(message);
   string callName = "ParentService.unexpectedExceptionWait";
-  uint32_t callId = checkCallHandlerEvents(
-      log, connId, EventLog::ET_CALL_UNEXPECTED_EXCEPTION_WAIT, callName);
+  uint32_t callId
+      = checkCallHandlerEvents(log, connId, EventLog::ET_CALL_UNEXPECTED_EXCEPTION_WAIT, callName);
 
   // There shouldn't be any more events
   checkNoEvents(log);
@@ -842,7 +821,7 @@
   try {
     client->recv_unexpectedExceptionWait();
     BOOST_FAIL("expected TApplicationError to be thrown");
-  } catch (const TApplicationException& e) {
+  } catch (const TApplicationException&) {
   }
 
   // Now we should see a handler error event
@@ -872,47 +851,46 @@
   checkNoEvents(log);
 }
 
-
 // Macro to define simple tests that can be used with all server types
-#define DEFINE_SIMPLE_TESTS(Server, Template) \
-  BOOST_AUTO_TEST_CASE(Server##_##Template##_basicService) { \
-    testBasicService<Server##Traits, Template##Traits>(); \
-  } \
-  BOOST_AUTO_TEST_CASE(Server##_##Template##_inheritedService) { \
-    testInheritedService<Server##Traits, Template##Traits>(); \
-  } \
-  BOOST_AUTO_TEST_CASE(Server##_##Template##_oneway) { \
-    testOnewayCall<Server##Traits, Template##Traits>(); \
-  } \
-  BOOST_AUTO_TEST_CASE(Server##_##Template##_exception) { \
-    testExpectedError<Server##Traits, Template##Traits>(); \
-  } \
-  BOOST_AUTO_TEST_CASE(Server##_##Template##_unexpectedException) { \
-    testUnexpectedError<Server##Traits, Template##Traits>(); \
+#define DEFINE_SIMPLE_TESTS(Server, Template)                                                      \
+  BOOST_AUTO_TEST_CASE(Server##_##Template##_basicService) {                                       \
+    testBasicService<Server##Traits, Template##Traits>();                                          \
+  }                                                                                                \
+  BOOST_AUTO_TEST_CASE(Server##_##Template##_inheritedService) {                                   \
+    testInheritedService<Server##Traits, Template##Traits>();                                      \
+  }                                                                                                \
+  BOOST_AUTO_TEST_CASE(Server##_##Template##_oneway) {                                             \
+    testOnewayCall<Server##Traits, Template##Traits>();                                            \
+  }                                                                                                \
+  BOOST_AUTO_TEST_CASE(Server##_##Template##_exception) {                                          \
+    testExpectedError<Server##Traits, Template##Traits>();                                         \
+  }                                                                                                \
+  BOOST_AUTO_TEST_CASE(Server##_##Template##_unexpectedException) {                                \
+    testUnexpectedError<Server##Traits, Template##Traits>();                                       \
   }
 
 // Tests that require the server to process multiple connections concurrently
 // (i.e., not TSimpleServer)
-#define DEFINE_CONCURRENT_SERVER_TESTS(Server, Template) \
-  BOOST_AUTO_TEST_CASE(Server##_##Template##_separateConnections) { \
-    testSeparateConnections<Server##Traits, Template##Traits>(); \
+#define DEFINE_CONCURRENT_SERVER_TESTS(Server, Template)                                           \
+  BOOST_AUTO_TEST_CASE(Server##_##Template##_separateConnections) {                                \
+    testSeparateConnections<Server##Traits, Template##Traits>();                                   \
   }
 
 // The testEventSequencing() test manually generates a request for the server,
 // and doesn't work with TFramedTransport.  Therefore we can't test it with
 // TNonblockingServer.
-#define DEFINE_NOFRAME_TESTS(Server, Template) \
-  BOOST_AUTO_TEST_CASE(Server##_##Template##_eventSequencing) { \
-    testEventSequencing<Server##Traits, Template##Traits>(); \
+#define DEFINE_NOFRAME_TESTS(Server, Template)                                                     \
+  BOOST_AUTO_TEST_CASE(Server##_##Template##_eventSequencing) {                                    \
+    testEventSequencing<Server##Traits, Template##Traits>();                                       \
   }
 
-#define DEFINE_TNONBLOCKINGSERVER_TESTS(Server, Template) \
-  DEFINE_SIMPLE_TESTS(Server, Template) \
+#define DEFINE_TNONBLOCKINGSERVER_TESTS(Server, Template)                                          \
+  DEFINE_SIMPLE_TESTS(Server, Template)                                                            \
   DEFINE_CONCURRENT_SERVER_TESTS(Server, Template)
 
-#define DEFINE_ALL_SERVER_TESTS(Server, Template) \
-  DEFINE_SIMPLE_TESTS(Server, Template) \
-  DEFINE_CONCURRENT_SERVER_TESTS(Server, Template) \
+#define DEFINE_ALL_SERVER_TESTS(Server, Template)                                                  \
+  DEFINE_SIMPLE_TESTS(Server, Template)                                                            \
+  DEFINE_CONCURRENT_SERVER_TESTS(Server, Template)                                                 \
   DEFINE_NOFRAME_TESTS(Server, Template)
 
 DEFINE_ALL_SERVER_TESTS(TThreadedServer, Templated)
@@ -925,17 +903,27 @@
 DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServerNoThreads, Templated)
 DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServerNoThreads, Untemplated)
 
-DEFINE_SIMPLE_TESTS(TSimpleServer, Templated);
-DEFINE_SIMPLE_TESTS(TSimpleServer, Untemplated);
-DEFINE_NOFRAME_TESTS(TSimpleServer, Templated);
-DEFINE_NOFRAME_TESTS(TSimpleServer, Untemplated);
+DEFINE_SIMPLE_TESTS(TSimpleServer, Templated)
+DEFINE_SIMPLE_TESTS(TSimpleServer, Untemplated)
+DEFINE_NOFRAME_TESTS(TSimpleServer, Templated)
+DEFINE_NOFRAME_TESTS(TSimpleServer, Untemplated)
 
 // TODO: We should test TEventServer in the future.
 // For now, it is known not to work correctly with TProcessorEventHandler.
+#ifdef BOOST_TEST_DYN_LINK
+bool init_unit_test_suite() {
+  ::boost::unit_test::framework::master_test_suite().p_name.value = "ProcessorTest";
+  return true;
+}
 
-unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
-  unit_test::framework::master_test_suite().p_name.value =
-    "ProcessorTest";
-
+int main( int argc, char* argv[] ) {
+  return ::boost::unit_test::unit_test_main(&init_unit_test_suite,argc,argv);
+}
+#else
+::boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
+  THRIFT_UNUSED_VARIABLE(argc);
+  THRIFT_UNUSED_VARIABLE(argv);
+  ::boost::unit_test::framework::master_test_suite().p_name.value = "ProcessorTest";
   return NULL;
 }
+#endif
diff --git a/lib/cpp/test/processor/ServerThread.cpp b/lib/cpp/test/processor/ServerThread.cpp
index 9f2087c..4d1ec4c 100644
--- a/lib/cpp/test/processor/ServerThread.cpp
+++ b/lib/cpp/test/processor/ServerThread.cpp
@@ -21,20 +21,24 @@
 
 #include "ServerThread.h"
 
-#include <thrift/concurrency/PosixThreadFactory.h>
+#include <thrift/concurrency/PlatformThreadFactory.h>
 #include <thrift/concurrency/ThreadManager.h>
 #include <thrift/server/TThreadPoolServer.h>
 #include <thrift/transport/TBufferTransports.h>
 #include <thrift/transport/TServerSocket.h>
 
-namespace apache { namespace thrift { namespace test {
+namespace apache {
+namespace thrift {
+namespace test {
 
 void ServerThread::start() {
   assert(!running_);
   running_ = true;
 
+  helper_.reset(new Helper(this));
+
   // Start the other thread
-  concurrency::PosixThreadFactory threadFactory;
+  concurrency::PlatformThreadFactory threadFactory;
   threadFactory.setDetached(false);
   thread_ = threadFactory.newThread(helper_);
 
@@ -48,9 +52,8 @@
   }
 
   if (error_) {
-    throw transport::TTransportException(
-        transport::TTransportException::NOT_OPEN,
-        "failed to bind on server socket");
+    throw transport::TTransportException(transport::TTransportException::NOT_OPEN,
+                                         "failed to bind on server socket");
   }
 }
 
@@ -89,7 +92,7 @@
     try {
       // Try to serve requests
       server_->serve();
-    } catch (const TException& x) {
+    } catch (const TException&) {
       // TNonblockingServer throws a generic TException if it fails to bind.
       // If we get a TException, we'll optimistically assume the bind failed.
       ++port_;
@@ -127,8 +130,8 @@
   serverState_->bindSuccessful(port_);
 
   // Set the real server event handler (replacing ourself)
-  boost::shared_ptr<server::TServerEventHandler> serverEventHandler =
-    serverState_->getServerEventHandler();
+  std::shared_ptr<server::TServerEventHandler> serverEventHandler
+      = serverState_->getServerEventHandler();
   server_->setServerEventHandler(serverEventHandler);
 
   // Notify the main thread that we have successfully started serving requests
@@ -142,7 +145,8 @@
     serverEventHandler->preServe();
   }
 }
-
-}}} // apache::thrift::test
+}
+}
+} // apache::thrift::test
 
 #endif // _THRIFT_TEST_SERVERTHREAD_TCC_
diff --git a/lib/cpp/test/processor/ServerThread.h b/lib/cpp/test/processor/ServerThread.h
index 0dd5127..61e31a3 100644
--- a/lib/cpp/test/processor/ServerThread.h
+++ b/lib/cpp/test/processor/ServerThread.h
@@ -26,13 +26,15 @@
 
 #include "EventLog.h"
 
-namespace apache { namespace thrift { namespace test {
+namespace apache {
+namespace thrift {
+namespace test {
 
 /**
  * A helper class to tell ServerThread how to create the server
  */
 class ServerState {
- public:
+public:
   virtual ~ServerState() {}
 
   /**
@@ -41,7 +43,7 @@
    * If the server returned fails to bind to the specified port when serve() is
    * called on it, createServer() may be called again on a different port.
    */
-  virtual boost::shared_ptr<server::TServer> createServer(uint16_t port) = 0;
+  virtual std::shared_ptr<server::TServer> createServer(uint16_t port) = 0;
 
   /**
    * Get the TServerEventHandler to set on the server.
@@ -50,9 +52,8 @@
    * start serving traffic.  It is invoked from the server thread, rather than
    * the main thread.
    */
-  virtual boost::shared_ptr<server::TServerEventHandler>
-      getServerEventHandler() {
-    return boost::shared_ptr<server::TServerEventHandler>();
+  virtual std::shared_ptr<server::TServerEventHandler> getServerEventHandler() {
+    return std::shared_ptr<server::TServerEventHandler>();
   }
 
   /**
@@ -61,18 +62,16 @@
    * Subclasses may override this method if they wish to record the final
    * port that was used for the server.
    */
-  virtual void bindSuccessful(uint16_t port) {
-  }
+  virtual void bindSuccessful(uint16_t /*port*/) {}
 };
 
 /**
  * ServerThread starts a thrift server running in a separate thread.
  */
 class ServerThread {
- public:
-  ServerThread(const boost::shared_ptr<ServerState>& state, bool autoStart) :
-      helper_(new Helper(this)),
-      port_(0),
+public:
+  ServerThread(const std::shared_ptr<ServerState>& state, bool autoStart)
+    : port_(0),
       running_(false),
       serving_(false),
       error_(false),
@@ -85,9 +84,7 @@
   void start();
   void stop();
 
-  uint16_t getPort() const {
-    return port_;
-  }
+  uint16_t getPort() const { return port_; }
 
   ~ServerThread() {
     if (running_) {
@@ -99,33 +96,27 @@
     }
   }
 
- protected:
+protected:
   // Annoying.  thrift forces us to use shared_ptr, so we have to use
   // a helper class that we can allocate on the heap and give to thrift.
   // It would be simpler if we could just make Runnable and TServerEventHandler
   // private base classes of ServerThread.
-  class Helper : public concurrency::Runnable,
-                 public server::TServerEventHandler {
-   public:
-    Helper(ServerThread* serverThread)
-      : serverThread_(serverThread) {}
+  class Helper : public concurrency::Runnable, public server::TServerEventHandler {
+  public:
+    Helper(ServerThread* serverThread) : serverThread_(serverThread) {}
 
-    void run() {
-      serverThread_->run();
-    }
+    void run() { serverThread_->run(); }
 
-    void preServe() {
-      serverThread_->preServe();
-    }
+    void preServe() { serverThread_->preServe(); }
 
-   private:
+  private:
     ServerThread* serverThread_;
   };
 
   void run();
   void preServe();
 
-  boost::shared_ptr<Helper> helper_;
+  std::shared_ptr<Helper> helper_;
 
   uint16_t port_;
   bool running_;
@@ -133,11 +124,12 @@
   bool error_;
   concurrency::Monitor serverMonitor_;
 
-  boost::shared_ptr<ServerState> serverState_;
-  boost::shared_ptr<server::TServer> server_;
-  boost::shared_ptr<concurrency::Thread> thread_;
+  std::shared_ptr<ServerState> serverState_;
+  std::shared_ptr<server::TServer> server_;
+  std::shared_ptr<concurrency::Thread> thread_;
 };
-
-}}} // apache::thrift::test
+}
+}
+} // apache::thrift::test
 
 #endif // _THRIFT_TEST_SERVERTHREAD_H_
diff --git a/lib/cpp/test/qt/CMakeLists.txt b/lib/cpp/test/qt/CMakeLists.txt
new file mode 100644
index 0000000..7f341cc
--- /dev/null
+++ b/lib/cpp/test/qt/CMakeLists.txt
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+
+set(CMAKE_AUTOMOC ON)
+find_package(Qt5 REQUIRED COMPONENTS Test Network)
+set(TQTcpServerTest_Qt5_SOURCES
+    TQTcpServerTest.cpp
+)
+add_executable(TQTcpServerTest_Qt5 ${TQTcpServerTest_Qt5_SOURCES})
+target_link_libraries(TQTcpServerTest_Qt5 testgencpp_cob)
+LINK_AGAINST_THRIFT_LIBRARY(TQTcpServerTest_Qt5 thriftqt5)
+LINK_AGAINST_THRIFT_LIBRARY(TQTcpServerTest_Qt5 thrift)
+target_link_libraries(TQTcpServerTest_Qt5 Qt5::Test Qt5::Network)
+
+add_test(NAME TQTcpServerTest_Qt5 COMMAND TQTcpServerTest_Qt5)
+
diff --git a/lib/cpp/test/qt/TQTcpServerTest.cpp b/lib/cpp/test/qt/TQTcpServerTest.cpp
new file mode 100644
index 0000000..58d0c6d
--- /dev/null
+++ b/lib/cpp/test/qt/TQTcpServerTest.cpp
@@ -0,0 +1,113 @@
+#define BOOST_TEST_MODULE TQTcpServerTest
+#include <QTest>
+#include <iostream>
+
+#include <QTcpServer>
+#include <QTcpSocket>
+#include <QHostAddress>
+#include <QThread>
+
+#ifndef Q_MOC_RUN
+  #include "thrift/protocol/TBinaryProtocol.h"
+  #include "thrift/async/TAsyncProcessor.h"
+  #include "thrift/qt/TQTcpServer.h"
+  #include "thrift/qt/TQIODeviceTransport.h"
+
+  #include "gen-cpp/ParentService.h"
+#endif
+
+using namespace apache::thrift;
+
+struct AsyncHandler : public test::ParentServiceCobSvIf {
+  std::vector<std::string> strings;
+  virtual void addString(std::function<void()> cob, const std::string& s) {
+    strings.push_back(s);
+    cob();
+  }
+  virtual void getStrings(std::function<void(std::vector<std::string> const& _return)> cob) {
+    cob(strings);
+  }
+
+  // Overrides not used in this test
+  virtual void incrementGeneration(std::function<void(int32_t const& _return)> cob) {}
+  virtual void getGeneration(std::function<void(int32_t const& _return)> cob) {}
+  virtual void getDataWait(std::function<void(std::string const& _return)> cob,
+                           const int32_t length) {}
+  virtual void onewayWait(std::function<void()> cob) {}
+  virtual void exceptionWait(
+      std::function<void()> cob,
+      std::function<void(::apache::thrift::TDelayedException* _throw)> /* exn_cob */,
+      const std::string& message) {}
+  virtual void unexpectedExceptionWait(std::function<void()> cob, const std::string& message) {}
+};
+
+class TQTcpServerTest : public QObject {
+  Q_OBJECT
+
+private slots:
+  void initTestCase();
+  void cleanupTestCase();
+  void test_communicate();
+
+private:
+  std::shared_ptr<QThread> serverThread;
+  std::shared_ptr<async::TQTcpServer> server;
+  std::shared_ptr<test::ParentServiceClient> client;
+};
+
+void TQTcpServerTest::initTestCase() {
+  // setup server
+  std::shared_ptr<QTcpServer> serverSocket = std::make_shared<QTcpServer>();
+  server.reset(new async::TQTcpServer(serverSocket,
+                                      std::make_shared<test::ParentServiceAsyncProcessor>(
+                                      std::make_shared<AsyncHandler>()),
+                                      std::make_shared<protocol::TBinaryProtocolFactory>()));
+  QVERIFY(serverSocket->listen(QHostAddress::LocalHost));
+  int port = serverSocket->serverPort();
+  QVERIFY(port > 0);
+
+  //setup server thread and move server to it
+  serverThread.reset(new QThread());
+  serverSocket->moveToThread(serverThread.get());
+  server->moveToThread(serverThread.get());
+  serverThread->start();
+
+  // setup client
+  std::shared_ptr<QTcpSocket> socket = std::make_shared<QTcpSocket>();
+  client.reset(new test::ParentServiceClient(std::make_shared<protocol::TBinaryProtocol>(
+      std::make_shared<transport::TQIODeviceTransport>(socket))));
+  socket->connectToHost(QHostAddress::LocalHost, port);
+  QVERIFY(socket->waitForConnected());
+}
+
+void TQTcpServerTest::cleanupTestCase() {
+  //first, stop the thread which holds the server
+  serverThread->quit();
+  serverThread->wait();
+  // now, it is safe to delete the server
+  server.reset();
+  // delete thread now
+  serverThread.reset();
+
+  // cleanup client
+  client.reset();
+}
+
+void TQTcpServerTest::test_communicate() {
+  client->addString("foo");
+  client->addString("bar");
+
+  std::vector<std::string> reply;
+  client->getStrings(reply);
+  QCOMPARE(QString::fromStdString(reply[0]), QString("foo"));
+  QCOMPARE(QString::fromStdString(reply[1]), QString("bar"));
+}
+
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+QTEST_GUILESS_MAIN(TQTcpServerTest);
+#else
+#undef QT_GUI_LIB
+QTEST_MAIN(TQTcpServerTest);
+#endif
+#include "TQTcpServerTest.moc"
diff --git a/lib/cpp/thrift-qt5.pc.in b/lib/cpp/thrift-qt5.pc.in
new file mode 100755
index 0000000..a8b1666
--- /dev/null
+++ b/lib/cpp/thrift-qt5.pc.in
@@ -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.
+#
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Thrift
+Description: Thrift Qt5 API
+Version: @VERSION@
+Requires: thrift = @VERSION@
+Libs: -L${libdir} -lthriftqt5
+Cflags: -I${includedir}
diff --git a/lib/cpp/thrift.sln b/lib/cpp/thrift.sln
index 88d7968..cb0f455 100644
--- a/lib/cpp/thrift.sln
+++ b/lib/cpp/thrift.sln
@@ -7,7 +7,7 @@
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{006984E0-7CC1-47E2-ACD2-A40FE4D38693}"
 	ProjectSection(SolutionItems) = preProject
-		README_WINDOWS = README_WINDOWS
+		README.md = README.md
 	EndProjectSection
 EndProject
 Global
diff --git a/lib/csharp/Makefile.am b/lib/csharp/Makefile.am
index 71cc83b..56a8b0f 100644
--- a/lib/csharp/Makefile.am
+++ b/lib/csharp/Makefile.am
@@ -17,7 +17,9 @@
 # under the License.
 #
 
-THRIFTCODE= \
+SUBDIRS = . test/Multiplex
+
+THRIFTCODE = \
             src/Collections/THashSet.cs \
             src/Collections/TCollections.cs \
             src/Properties/AssemblyInfo.cs \
@@ -46,9 +48,11 @@
             src/Server/TThreadPoolServer.cs \
             src/Server/TSimpleServer.cs \
             src/Server/TServer.cs \
+            src/Server/TServerEventHandler.cs \
             src/Transport/TBufferedTransport.cs \
             src/Transport/TTransport.cs \
             src/Transport/TSocket.cs \
+            src/Transport/TSocketVersionizer.cs \
             src/Transport/TTransportException.cs \
             src/Transport/TStreamTransport.cs \
             src/Transport/TFramedTransport.cs \
@@ -58,34 +62,54 @@
             src/Transport/THttpClient.cs \
             src/Transport/THttpHandler.cs \
             src/Transport/TMemoryBuffer.cs \
+            src/Transport/TNamedPipeClientTransport.cs \
+            src/Transport/TNamedPipeServerTransport.cs \
+            src/Transport/TTLSSocket.cs \
+            src/Transport/TTLSServerSocket.cs \
             src/TProcessor.cs \
+            src/TProcessorFactory.cs \
+            src/TSingletonProcessorFactory.cs \
+            src/TPrototypeProcessorFactory.cs \
+            src/TControllingHandler.cs \
             src/TException.cs \
             src/TApplicationException.cs
 
-CSC=gmcs
-
-if NET_2_0
-MONO_DEFINES=/d:NET_2_0
+if MONO_MCS
+export CSC = mcs
+else
+export CSC = gmcs
 endif
 
-all-local: Thrift.dll
+if NET_2_0
+export CSC_DEFINES = -d:NET_2_0
+endif
+
+all-local: Thrift.dll Thrift.45.dll
 
 Thrift.dll: $(THRIFTCODE)
-	$(CSC) $(THRIFTCODE) /out:Thrift.dll /target:library /reference:System.Web $(MONO_DEFINES)
+	$(CSC) $(CSC_DEFINES) -out:$@ -target:library -reference:System.Web $(THRIFTCODE)
+
+Thrift.45.dll: $(THRIFTCODE)
+	$(CSC) $(CSC_DEFINES) -out:$@ -target:library -reference:System.Web $(THRIFTCODE)
 
 clean-local:
-	$(RM) Thrift.dll
+	$(RM) Thrift.dll  \
+	$(RM) Thrift.45.dll
 
-# run csharp tests?
-# check:
-# 	cd test/ThriftTest && ./maketest.sh 
-# 	cd test/Multiplex && ./maketest.sh
-    
 EXTRA_DIST = \
-             $(THRIFTCODE) \
-             ThriftMSBuildTask \
-             src/Thrift.csproj \
-             src/Thrift.sln \
-             src/Thrift.WP7.csproj \
-             src/Properties/AssemblyInfo.WP7.cs \
-             test
+	$(THRIFTCODE) \
+	ThriftMSBuildTask \
+	src/Thrift.csproj \
+	src/Thrift.45.csproj \
+	src/Thrift.sln \
+	src/Net35/ExtensionsNet35.cs \
+	src/Transport/TSilverlightSocket.cs \
+	src/Transport/THttpTaskAsyncHandler.cs \
+	src/TAsyncProcessor.cs \
+	test \
+	coding_standards.md \
+	README.md
+
+MAINTAINERCLEANFILES = \
+	Makefile \
+	Makefile.in
diff --git a/lib/csharp/README b/lib/csharp/README.md
similarity index 100%
rename from lib/csharp/README
rename to lib/csharp/README.md
diff --git a/lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs b/lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs
index e0a5702..c741b72 100644
--- a/lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs
+++ b/lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs
@@ -56,5 +56,5 @@
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("0.9.1.*")]
-[assembly: AssemblyFileVersion("0.9.1.*")]
+[assembly: AssemblyVersion("1.0.0.*")]
+[assembly: AssemblyFileVersion("1.0.0.*")]
diff --git a/lib/csharp/ThriftMSBuildTask/ThriftBuild.cs b/lib/csharp/ThriftMSBuildTask/ThriftBuild.cs
index 75bb339..4e6d301 100644
--- a/lib/csharp/ThriftMSBuildTask/ThriftBuild.cs
+++ b/lib/csharp/ThriftMSBuildTask/ThriftBuild.cs
@@ -33,214 +33,214 @@
 
 namespace ThriftMSBuildTask
 {
-	/// <summary>
-	/// MSBuild Task to generate csharp from .thrift files, and compile the code into a library: ThriftImpl.dll
-	/// </summary>
-	public class ThriftBuild : Task
-	{
-		/// <summary>
-		/// The full path to the thrift.exe compiler
-		/// </summary>
-		[Required]
-		public ITaskItem ThriftExecutable
-		{
-			get;
-			set;
-		}
+    /// <summary>
+    /// MSBuild Task to generate csharp from .thrift files, and compile the code into a library: ThriftImpl.dll
+    /// </summary>
+    public class ThriftBuild : Task
+    {
+        /// <summary>
+        /// The full path to the thrift.exe compiler
+        /// </summary>
+        [Required]
+        public ITaskItem ThriftExecutable
+        {
+            get;
+            set;
+        }
 
-		/// <summary>
-		/// The full path to a thrift.dll C# library
-		/// </summary>
-		[Required]
-		public ITaskItem ThriftLibrary
-		{
-			get;
-			set;
-		}
+        /// <summary>
+        /// The full path to a thrift.dll C# library
+        /// </summary>
+        [Required]
+        public ITaskItem ThriftLibrary
+        {
+            get;
+            set;
+        }
 
-		/// <summary>
-		/// A direcotry containing .thrift files
-		/// </summary>
-		[Required]
-		public ITaskItem ThriftDefinitionDir
-		{
-			get;
-			set;
-		}
+        /// <summary>
+        /// A direcotry containing .thrift files
+        /// </summary>
+        [Required]
+        public ITaskItem ThriftDefinitionDir
+        {
+            get;
+            set;
+        }
 
-		/// <summary>
-		/// The name of the auto-gen and compiled thrift library. It will placed in
-		/// the same directory as ThriftLibrary
-		/// </summary>
-		[Required]
-		public ITaskItem OutputName
-		{
-			get;
-			set;
-		}
+        /// <summary>
+        /// The name of the auto-gen and compiled thrift library. It will placed in
+        /// the same directory as ThriftLibrary
+        /// </summary>
+        [Required]
+        public ITaskItem OutputName
+        {
+            get;
+            set;
+        }
 
-		/// <summary>
-		/// The full path to the compiled ThriftLibrary. This allows msbuild tasks to use this
-		/// output as a variable for use elsewhere.
-		/// </summary>
-		[Output]
-		public ITaskItem ThriftImplementation
-		{
-			get { return thriftImpl; }
-		}
+        /// <summary>
+        /// The full path to the compiled ThriftLibrary. This allows msbuild tasks to use this
+        /// output as a variable for use elsewhere.
+        /// </summary>
+        [Output]
+        public ITaskItem ThriftImplementation
+        {
+            get { return thriftImpl; }
+        }
 
-		private ITaskItem thriftImpl;
-		private const string lastCompilationName = "LAST_COMP_TIMESTAMP";
+        private ITaskItem thriftImpl;
+        private const string lastCompilationName = "LAST_COMP_TIMESTAMP";
 
-		//use the Message Build Task to write something to build log
-		private void LogMessage(string text, MessageImportance importance)
-		{
-			Message m = new Message();
-			m.Text = text;
-			m.Importance = importance.ToString();
-			m.BuildEngine = this.BuildEngine;
-			m.Execute();
-		}
+        //use the Message Build Task to write something to build log
+        private void LogMessage(string text, MessageImportance importance)
+        {
+            Message m = new Message();
+            m.Text = text;
+            m.Importance = importance.ToString();
+            m.BuildEngine = this.BuildEngine;
+            m.Execute();
+        }
 
-		//recursively find .cs files in srcDir, paths should initially be non-null and empty
-		private void FindSourcesHelper(string srcDir, List<string> paths)
-		{
-			string[] files = Directory.GetFiles(srcDir, "*.cs");
-			foreach (string f in files)
-			{
-				paths.Add(f);
-			}
-			string[] dirs = Directory.GetDirectories(srcDir);
-			foreach (string dir in dirs)
-			{
-				FindSourcesHelper(dir, paths);
-			}
-		}
+        //recursively find .cs files in srcDir, paths should initially be non-null and empty
+        private void FindSourcesHelper(string srcDir, List<string> paths)
+        {
+            string[] files = Directory.GetFiles(srcDir, "*.cs");
+            foreach (string f in files)
+            {
+                paths.Add(f);
+            }
+            string[] dirs = Directory.GetDirectories(srcDir);
+            foreach (string dir in dirs)
+            {
+                FindSourcesHelper(dir, paths);
+            }
+        }
 
-		/// <summary>
-		/// Quote paths with spaces
-		/// </summary>
-		private string SafePath(string path)
-		{
-			if (path.Contains(' ') && !path.StartsWith("\""))
-			{
-				return "\"" + path + "\"";
-			}
-			return path;
-		}
+        /// <summary>
+        /// Quote paths with spaces
+        /// </summary>
+        private string SafePath(string path)
+        {
+            if (path.Contains(' ') && !path.StartsWith("\""))
+            {
+                return "\"" + path + "\"";
+            }
+            return path;
+        }
 
-		private ITaskItem[] FindSources(string srcDir)
-		{
-			List<string> files = new List<string>();
-			FindSourcesHelper(srcDir, files);
-			ITaskItem[] items = new ITaskItem[files.Count];
-			for (int i = 0; i < items.Length; i++)
-			{
-				items[i] = new TaskItem(files[i]);
-			}
-			return items;
-		}
+        private ITaskItem[] FindSources(string srcDir)
+        {
+            List<string> files = new List<string>();
+            FindSourcesHelper(srcDir, files);
+            ITaskItem[] items = new ITaskItem[files.Count];
+            for (int i = 0; i < items.Length; i++)
+            {
+                items[i] = new TaskItem(files[i]);
+            }
+            return items;
+        }
 
-		private string LastWriteTime(string defDir)
-		{
-			string[] files = Directory.GetFiles(defDir, "*.thrift");
-			DateTime d = (new DirectoryInfo(defDir)).LastWriteTime;
-			foreach(string file in files)
-			{
-				FileInfo f = new FileInfo(file);
-				DateTime curr = f.LastWriteTime;
-				if (DateTime.Compare(curr, d) > 0)
-				{
-					d = curr;
-				}
-			}
-			return d.ToFileTimeUtc().ToString();
-		}
+        private string LastWriteTime(string defDir)
+        {
+            string[] files = Directory.GetFiles(defDir, "*.thrift");
+            DateTime d = (new DirectoryInfo(defDir)).LastWriteTime;
+            foreach(string file in files)
+            {
+                FileInfo f = new FileInfo(file);
+                DateTime curr = f.LastWriteTime;
+                if (DateTime.Compare(curr, d) > 0)
+                {
+                    d = curr;
+                }
+            }
+            return d.ToFileTimeUtc().ToString();
+        }
 
-		public override bool Execute()
-		{
-			string defDir = SafePath(ThriftDefinitionDir.ItemSpec);
-			//look for last compilation timestamp
-			string lastBuildPath = Path.Combine(defDir, lastCompilationName);
-			DirectoryInfo defDirInfo = new DirectoryInfo(defDir);
-			string lastWrite = LastWriteTime(defDir);
-			if (File.Exists(lastBuildPath))
-			{
-				string lastComp = File.ReadAllText(lastBuildPath);
-				//don't recompile if the thrift library has been updated since lastComp
-				FileInfo f = new FileInfo(ThriftLibrary.ItemSpec);
-				string thriftLibTime = f.LastWriteTimeUtc.ToFileTimeUtc().ToString();
-				if (lastComp.CompareTo(thriftLibTime) < 0)
-				{
-					//new thrift library, do a compile
-					lastWrite = thriftLibTime;
-				}
-				else if (lastComp == lastWrite || (lastComp == thriftLibTime && lastComp.CompareTo(lastWrite) > 0))
-				{
-					//the .thrift dir hasn't been written to since last compilation, don't need to do anything
-					LogMessage("ThriftImpl up-to-date", MessageImportance.High);
-					return true;
-				}
-			}
+        public override bool Execute()
+        {
+            string defDir = SafePath(ThriftDefinitionDir.ItemSpec);
+            //look for last compilation timestamp
+            string lastBuildPath = Path.Combine(defDir, lastCompilationName);
+            DirectoryInfo defDirInfo = new DirectoryInfo(defDir);
+            string lastWrite = LastWriteTime(defDir);
+            if (File.Exists(lastBuildPath))
+            {
+                string lastComp = File.ReadAllText(lastBuildPath);
+                //don't recompile if the thrift library has been updated since lastComp
+                FileInfo f = new FileInfo(ThriftLibrary.ItemSpec);
+                string thriftLibTime = f.LastWriteTimeUtc.ToFileTimeUtc().ToString();
+                if (lastComp.CompareTo(thriftLibTime) < 0)
+                {
+                    //new thrift library, do a compile
+                    lastWrite = thriftLibTime;
+                }
+                else if (lastComp == lastWrite || (lastComp == thriftLibTime && lastComp.CompareTo(lastWrite) > 0))
+                {
+                    //the .thrift dir hasn't been written to since last compilation, don't need to do anything
+                    LogMessage("ThriftImpl up-to-date", MessageImportance.High);
+                    return true;
+                }
+            }
 
-			//find the directory of the thriftlibrary (that's where output will go)
-			FileInfo thriftLibInfo = new FileInfo(SafePath(ThriftLibrary.ItemSpec));
-			string thriftDir = thriftLibInfo.Directory.FullName;
+            //find the directory of the thriftlibrary (that's where output will go)
+            FileInfo thriftLibInfo = new FileInfo(SafePath(ThriftLibrary.ItemSpec));
+            string thriftDir = thriftLibInfo.Directory.FullName;
 
-			string genDir = Path.Combine(thriftDir, "gen-csharp");
-			if (Directory.Exists(genDir))
-			{
-				try
-				{
-					Directory.Delete(genDir, true);
-				}
-				catch { /*eh i tried, just over-write now*/}
-			}
+            string genDir = Path.Combine(thriftDir, "gen-csharp");
+            if (Directory.Exists(genDir))
+            {
+                try
+                {
+                    Directory.Delete(genDir, true);
+                }
+                catch { /*eh i tried, just over-write now*/}
+            }
 
-			//run the thrift executable to generate C#
-			foreach (string thriftFile in Directory.GetFiles(defDir, "*.thrift"))
-			{
-				LogMessage("Generating code for: " + thriftFile, MessageImportance.Normal);
-				Process p = new Process();
-				p.StartInfo.FileName = SafePath(ThriftExecutable.ItemSpec);
-				p.StartInfo.Arguments = "--gen csharp -o " + SafePath(thriftDir) + " -r " + thriftFile;
-				p.StartInfo.UseShellExecute = false;
-				p.StartInfo.CreateNoWindow = true;
-				p.StartInfo.RedirectStandardOutput = false;
-				p.Start();
-				p.WaitForExit();
-				if (p.ExitCode != 0)
-				{
-					LogMessage("thrift.exe failed to compile " + thriftFile, MessageImportance.High);
-					return false;
-				}
-				if (p.ExitCode != 0)
-				{
-					LogMessage("thrift.exe failed to compile " + thriftFile, MessageImportance.High);
-					return false;
-				}
-			}
+            //run the thrift executable to generate C#
+            foreach (string thriftFile in Directory.GetFiles(defDir, "*.thrift"))
+            {
+                LogMessage("Generating code for: " + thriftFile, MessageImportance.Normal);
+                Process p = new Process();
+                p.StartInfo.FileName = SafePath(ThriftExecutable.ItemSpec);
+                p.StartInfo.Arguments = "--gen csharp -o " + SafePath(thriftDir) + " -r " + thriftFile;
+                p.StartInfo.UseShellExecute = false;
+                p.StartInfo.CreateNoWindow = true;
+                p.StartInfo.RedirectStandardOutput = false;
+                p.Start();
+                p.WaitForExit();
+                if (p.ExitCode != 0)
+                {
+                    LogMessage("thrift.exe failed to compile " + thriftFile, MessageImportance.High);
+                    return false;
+                }
+                if (p.ExitCode != 0)
+                {
+                    LogMessage("thrift.exe failed to compile " + thriftFile, MessageImportance.High);
+                    return false;
+                }
+            }
 
-			Csc csc = new Csc();
-			csc.TargetType = "library";
-			csc.References = new ITaskItem[] { new TaskItem(ThriftLibrary.ItemSpec) };
-			csc.EmitDebugInformation = true;
-			string outputPath = Path.Combine(thriftDir, OutputName.ItemSpec);
-			csc.OutputAssembly = new TaskItem(outputPath);
-			csc.Sources = FindSources(Path.Combine(thriftDir, "gen-csharp"));
-			csc.BuildEngine = this.BuildEngine;
-			LogMessage("Compiling generated cs...", MessageImportance.Normal);
-			if (!csc.Execute())
-			{
-				return false;
-			}
+            Csc csc = new Csc();
+            csc.TargetType = "library";
+            csc.References = new ITaskItem[] { new TaskItem(ThriftLibrary.ItemSpec) };
+            csc.EmitDebugInformation = true;
+            string outputPath = Path.Combine(thriftDir, OutputName.ItemSpec);
+            csc.OutputAssembly = new TaskItem(outputPath);
+            csc.Sources = FindSources(Path.Combine(thriftDir, "gen-csharp"));
+            csc.BuildEngine = this.BuildEngine;
+            LogMessage("Compiling generated cs...", MessageImportance.Normal);
+            if (!csc.Execute())
+            {
+                return false;
+            }
 
-			//write file to defDir to indicate a build was successfully completed
-			File.WriteAllText(lastBuildPath, lastWrite);
+            //write file to defDir to indicate a build was successfully completed
+            File.WriteAllText(lastBuildPath, lastWrite);
 
-			thriftImpl = new TaskItem(outputPath);
+            thriftImpl = new TaskItem(outputPath);
 
-			return true;
-		}
-	}
+            return true;
+        }
+    }
 }
diff --git a/lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj b/lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj
index fc377a4..a319df2 100644
--- a/lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj
+++ b/lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>

+<?xml version="1.0" encoding="utf-8"?>
 <!--
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements. See the NOTICE file
@@ -16,103 +16,103 @@
   KIND, either express or implied. See the License for the
   specific language governing permissions and limitations
   under the License.
--->

-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

-  <PropertyGroup>

-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

-    <ProductVersion>9.0.21022</ProductVersion>

-    <SchemaVersion>2.0</SchemaVersion>

-    <ProjectGuid>{EC0A0231-66EA-4593-A792-C6CA3BB8668E}</ProjectGuid>

-    <OutputType>Library</OutputType>

-    <AppDesignerFolder>Properties</AppDesignerFolder>

-    <RootNamespace>ThriftMSBuildTask</RootNamespace>

-    <AssemblyName>ThriftMSBuildTask</AssemblyName>

-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>

-    <FileAlignment>512</FileAlignment>

-    <FileUpgradeFlags>

-    </FileUpgradeFlags>

-    <OldToolsVersion>3.5</OldToolsVersion>

-    <UpgradeBackupLocation />

-    <PublishUrl>publish\</PublishUrl>

-    <Install>true</Install>

-    <InstallFrom>Disk</InstallFrom>

-    <UpdateEnabled>false</UpdateEnabled>

-    <UpdateMode>Foreground</UpdateMode>

-    <UpdateInterval>7</UpdateInterval>

-    <UpdateIntervalUnits>Days</UpdateIntervalUnits>

-    <UpdatePeriodically>false</UpdatePeriodically>

-    <UpdateRequired>false</UpdateRequired>

-    <MapFileExtensions>true</MapFileExtensions>

-    <ApplicationRevision>0</ApplicationRevision>

-    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>

-    <IsWebBootstrapper>false</IsWebBootstrapper>

-    <UseApplicationTrust>false</UseApplicationTrust>

-    <BootstrapperEnabled>true</BootstrapperEnabled>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

-    <DebugSymbols>true</DebugSymbols>

-    <DebugType>full</DebugType>

-    <Optimize>false</Optimize>

-    <OutputPath>bin\Debug\</OutputPath>

-    <DefineConstants>DEBUG;TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

-    <DebugType>pdbonly</DebugType>

-    <Optimize>true</Optimize>

-    <OutputPath>bin\Release\</OutputPath>

-    <DefineConstants>TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>

-  </PropertyGroup>

-  <ItemGroup>

-    <Reference Include="Microsoft.Build.Framework" />

-    <Reference Include="Microsoft.Build.Tasks" />

-    <Reference Include="Microsoft.Build.Utilities" />

-    <Reference Include="System" />

-    <Reference Include="System.Core">

-      <RequiredTargetFramework>3.5</RequiredTargetFramework>

-    </Reference>

-    <Reference Include="System.Xml.Linq">

-      <RequiredTargetFramework>3.5</RequiredTargetFramework>

-    </Reference>

-    <Reference Include="System.Data.DataSetExtensions">

-      <RequiredTargetFramework>3.5</RequiredTargetFramework>

-    </Reference>

-    <Reference Include="System.Data" />

-    <Reference Include="System.Xml" />

-  </ItemGroup>

-  <ItemGroup>

-    <Compile Include="ThriftBuild.cs" />

-    <Compile Include="Properties\AssemblyInfo.cs" />

-  </ItemGroup>

-  <ItemGroup>

-    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">

-      <Visible>False</Visible>

-      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>

-      <Install>false</Install>

-    </BootstrapperPackage>

-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">

-      <Visible>False</Visible>

-      <ProductName>.NET Framework 3.5 SP1</ProductName>

-      <Install>true</Install>

-    </BootstrapperPackage>

-    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">

-      <Visible>False</Visible>

-      <ProductName>Windows Installer 3.1</ProductName>

-      <Install>true</Install>

-    </BootstrapperPackage>

-  </ItemGroup>

-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{EC0A0231-66EA-4593-A792-C6CA3BB8668E}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ThriftMSBuildTask</RootNamespace>
+    <AssemblyName>ThriftMSBuildTask</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.0</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.Build.Framework" />
+    <Reference Include="Microsoft.Build.Tasks" />
+    <Reference Include="Microsoft.Build.Utilities" />
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ThriftBuild.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">
   </Target>
   <Target Name="AfterBuild">
   </Target>
-  -->

-</Project>
\ No newline at end of file
+  -->
+</Project>
diff --git a/lib/csharp/coding_standards.md b/lib/csharp/coding_standards.md
new file mode 100644
index 0000000..dc87190
--- /dev/null
+++ b/lib/csharp/coding_standards.md
@@ -0,0 +1,6 @@
+## C# Coding Standards
+
+Please follow:
+ * [Thrift General Coding Standards](/doc/coding_standards.md)
+ * [MSDN C# Coding Conventions](http://msdn.microsoft.com/en-us/library/ff926074.aspx)
+ * [C# Coding Guidelines](http://csharpguidelines.codeplex.com/)
diff --git a/lib/csharp/src/Collections/TCollections.cs b/lib/csharp/src/Collections/TCollections.cs
index 23fd8da..84afb6a 100644
--- a/lib/csharp/src/Collections/TCollections.cs
+++ b/lib/csharp/src/Collections/TCollections.cs
@@ -21,74 +21,74 @@
 
 namespace Thrift.Collections
 {
-	public class TCollections
-	{
-		/// <summary>
-		/// This will return true if the two collections are value-wise the same.
-		/// If the collection contains a collection, the collections will be compared using this method.
-		/// </summary>
-		public static bool Equals (IEnumerable first, IEnumerable second)
-		{
-			if (first == null && second == null)
-			{
-				return true;
-			}
-			if (first == null || second == null)
-			{
-				return false;
-			}
-			IEnumerator fiter = first.GetEnumerator ();
-			IEnumerator siter = second.GetEnumerator ();
+    public class TCollections
+    {
+        /// <summary>
+        /// This will return true if the two collections are value-wise the same.
+        /// If the collection contains a collection, the collections will be compared using this method.
+        /// </summary>
+        public static bool Equals (IEnumerable first, IEnumerable second)
+        {
+            if (first == null && second == null)
+            {
+                return true;
+            }
+            if (first == null || second == null)
+            {
+                return false;
+            }
+            IEnumerator fiter = first.GetEnumerator ();
+            IEnumerator siter = second.GetEnumerator ();
 
-			bool fnext = fiter.MoveNext ();
-			bool snext = siter.MoveNext ();
-			while (fnext && snext)
-			{
-				IEnumerable fenum = fiter.Current as IEnumerable;
-				IEnumerable senum = siter.Current as IEnumerable;
-				if (fenum != null && senum != null)
-				{
-					if (!Equals(fenum, senum))
-					{
-						return false;
-					}
-				}
-				else if (fenum == null ^ senum == null)
-				{
-					return false;
-				}
-				else if (!Equals(fiter.Current, siter.Current))
-				{
-					return false;
-				}
-				fnext = fiter.MoveNext();
-				snext = siter.MoveNext();
-			}
+            bool fnext = fiter.MoveNext ();
+            bool snext = siter.MoveNext ();
+            while (fnext && snext)
+            {
+                IEnumerable fenum = fiter.Current as IEnumerable;
+                IEnumerable senum = siter.Current as IEnumerable;
+                if (fenum != null && senum != null)
+                {
+                    if (!Equals(fenum, senum))
+                    {
+                        return false;
+                    }
+                }
+                else if (fenum == null ^ senum == null)
+                {
+                    return false;
+                }
+                else if (!Equals(fiter.Current, siter.Current))
+                {
+                    return false;
+                }
+                fnext = fiter.MoveNext();
+                snext = siter.MoveNext();
+            }
 
-			return fnext == snext;
-		}
+            return fnext == snext;
+        }
 
-		/// <summary>
-		/// This returns a hashcode based on the value of the enumerable.
-		/// </summary>
-		public static int GetHashCode (IEnumerable enumerable)
-		{
-			if (enumerable == null)
-			{
-				return 0;
-			}
+        /// <summary>
+        /// This returns a hashcode based on the value of the enumerable.
+        /// </summary>
+        public static int GetHashCode (IEnumerable enumerable)
+        {
+            if (enumerable == null)
+            {
+                return 0;
+            }
 
-			int hashcode = 0;
-			foreach (Object obj in enumerable)
-			{
-				IEnumerable enum2 = obj as IEnumerable;
-				int objHash = enum2 == null ? obj.GetHashCode () : GetHashCode (enum2);
-				unchecked
-				{
-					hashcode = (hashcode * 397) ^ (objHash);
-				}
-			}
-			return hashcode;
-		}
-	}
-}
\ No newline at end of file
+            int hashcode = 0;
+            foreach (object obj in enumerable)
+            {
+                IEnumerable enum2 = obj as IEnumerable;
+                int objHash = enum2 == null ? obj.GetHashCode () : GetHashCode (enum2);
+                unchecked
+                {
+                    hashcode = (hashcode * 397) ^ (objHash);
+                }
+            }
+            return hashcode;
+        }
+    }
+}
diff --git a/lib/csharp/src/Collections/THashSet.cs b/lib/csharp/src/Collections/THashSet.cs
index b71a8d2..e29271a 100644
--- a/lib/csharp/src/Collections/THashSet.cs
+++ b/lib/csharp/src/Collections/THashSet.cs
@@ -30,131 +30,131 @@
 #if SILVERLIGHT
     [DataContract]
 #else
-	[Serializable]
+    [Serializable]
 #endif
-	public class THashSet<T> : ICollection<T>
-	{
+    public class THashSet<T> : ICollection<T>
+    {
 #if NET_2_0 || SILVERLIGHT
 #if SILVERLIGHT
         [DataMember]
 #endif
         TDictSet<T> set = new TDictSet<T>();
 #else
-		HashSet<T> set = new HashSet<T>();
+        HashSet<T> set = new HashSet<T>();
 #endif
-		public int Count
-		{
-			get { return set.Count; }
-		}
+        public int Count
+        {
+            get { return set.Count; }
+        }
 
-		public bool IsReadOnly
-		{
-			get { return false; }
-		}
+        public bool IsReadOnly
+        {
+            get { return false; }
+        }
 
-		public void Add(T item)
-		{
-			set.Add(item);
-		}
+        public void Add(T item)
+        {
+            set.Add(item);
+        }
 
-		public void Clear()
-		{
-			set.Clear();
-		}
+        public void Clear()
+        {
+            set.Clear();
+        }
 
-		public bool Contains(T item)
-		{
-			return set.Contains(item);
-		}
+        public bool Contains(T item)
+        {
+            return set.Contains(item);
+        }
 
-		public void CopyTo(T[] array, int arrayIndex)
-		{
-			set.CopyTo(array, arrayIndex);
-		}
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            set.CopyTo(array, arrayIndex);
+        }
 
-		public IEnumerator GetEnumerator()
-		{
-			return set.GetEnumerator();
-		}
+        public IEnumerator GetEnumerator()
+        {
+            return set.GetEnumerator();
+        }
 
-		IEnumerator<T> IEnumerable<T>.GetEnumerator()
-		{
-			return ((IEnumerable<T>)set).GetEnumerator();
-		}
+        IEnumerator<T> IEnumerable<T>.GetEnumerator()
+        {
+            return ((IEnumerable<T>)set).GetEnumerator();
+        }
 
-		public bool Remove(T item)
-		{
-			return set.Remove(item);
-		}
+        public bool Remove(T item)
+        {
+            return set.Remove(item);
+        }
 
 #if NET_2_0 || SILVERLIGHT
 #if SILVERLIGHT
         [DataContract]
 #endif
         private class TDictSet<V> : ICollection<V>
-		{
+        {
 #if SILVERLIGHT
             [DataMember]
 #endif
-			Dictionary<V, TDictSet<V>> dict = new Dictionary<V, TDictSet<V>>();
+            Dictionary<V, TDictSet<V>> dict = new Dictionary<V, TDictSet<V>>();
 
-			public int Count
-			{
-				get { return dict.Count; }
-			}
+            public int Count
+            {
+                get { return dict.Count; }
+            }
 
-			public bool IsReadOnly
-			{
-				get { return false; }
-			}
+            public bool IsReadOnly
+            {
+                get { return false; }
+            }
 
-			public IEnumerator GetEnumerator()
-			{
-				return ((IEnumerable)dict.Keys).GetEnumerator();
-			}
+            public IEnumerator GetEnumerator()
+            {
+                return ((IEnumerable)dict.Keys).GetEnumerator();
+            }
 
-			IEnumerator<V> IEnumerable<V>.GetEnumerator()
-			{
-				return dict.Keys.GetEnumerator();
-			}
+            IEnumerator<V> IEnumerable<V>.GetEnumerator()
+            {
+                return dict.Keys.GetEnumerator();
+            }
 
-			public bool Add(V item)
-			{
-				if (!dict.ContainsKey(item))
-				{
-					dict[item] = this;
-					return true;
-				}
+            public bool Add(V item)
+            {
+                if (!dict.ContainsKey(item))
+                {
+                    dict[item] = this;
+                    return true;
+                }
 
-				return false;
-			}
+                return false;
+            }
 
-			void ICollection<V>.Add(V item)
-			{
-				Add(item);
-			}
+            void ICollection<V>.Add(V item)
+            {
+                Add(item);
+            }
 
-			public void Clear()
-			{
-				dict.Clear();
-			}
+            public void Clear()
+            {
+                dict.Clear();
+            }
 
-			public bool Contains(V item)
-			{
-				return dict.ContainsKey(item);
-			}
+            public bool Contains(V item)
+            {
+                return dict.ContainsKey(item);
+            }
 
-			public void CopyTo(V[] array, int arrayIndex)
-			{
-				dict.Keys.CopyTo(array, arrayIndex);
-			}
+            public void CopyTo(V[] array, int arrayIndex)
+            {
+                dict.Keys.CopyTo(array, arrayIndex);
+            }
 
-			public bool Remove(V item)
-			{
-				return dict.Remove(item);
-			}
-		}
+            public bool Remove(V item)
+            {
+                return dict.Remove(item);
+            }
+        }
 #endif
-	}
+    }
 
 }
diff --git a/lib/csharp/src/Net35/ExtensionsNet35.cs b/lib/csharp/src/Net35/ExtensionsNet35.cs
new file mode 100644
index 0000000..73a4232
--- /dev/null
+++ b/lib/csharp/src/Net35/ExtensionsNet35.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+#if (!NET45)
+namespace Thrift
+{
+    static class StreamExtensionsNet35
+    {
+        // CopyTo() has been added in 4.0
+        public static long CopyTo(this Stream source, Stream target)
+        {
+            byte[] buffer = new byte[8192];  // multiple of 4096
+            long nTotal = 0;
+            while (true)
+            {
+                int nRead = source.Read(buffer, 0, buffer.Length);
+                if (nRead <= 0)  // done?
+                    return nTotal;
+
+                target.Write(buffer, 0, nRead);
+                nTotal += nRead;
+            }
+        }
+    }
+
+}
+#endif
+
diff --git a/lib/csharp/src/Properties/AssemblyInfo.WP7.cs b/lib/csharp/src/Properties/AssemblyInfo.WP7.cs
deleted file mode 100644
index cbe1763..0000000
--- a/lib/csharp/src/Properties/AssemblyInfo.WP7.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Thrift.WP7")]
-[assembly: AssemblyDescription("C# bindings for the Apache Thrift RPC system")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("The Apache Software Foundation")]
-[assembly: AssemblyProduct("Thrift")]
-[assembly: AssemblyCopyright("The Apache Software Foundation")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-//@TODO where to put License information?
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components.  If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("a343f89c-57dd-4fa8-a9c6-35391cd5f655")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-[assembly: AssemblyVersion("1.0.0.1")]
-[assembly: AssemblyFileVersion("1.0.0.1")]
diff --git a/lib/csharp/src/Properties/AssemblyInfo.cs b/lib/csharp/src/Properties/AssemblyInfo.cs
index 101e6bf..7e86781 100644
--- a/lib/csharp/src/Properties/AssemblyInfo.cs
+++ b/lib/csharp/src/Properties/AssemblyInfo.cs
@@ -51,5 +51,5 @@
 //
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
-[assembly: AssemblyVersion("0.9.1.1")]
-[assembly: AssemblyFileVersion("0.9.1.1")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/lib/csharp/src/Protocol/TAbstractBase.cs b/lib/csharp/src/Protocol/TAbstractBase.cs
index de2e3db..f5a61cd 100644
--- a/lib/csharp/src/Protocol/TAbstractBase.cs
+++ b/lib/csharp/src/Protocol/TAbstractBase.cs
@@ -19,11 +19,11 @@
 
 namespace Thrift.Protocol
 {
-	public interface TAbstractBase
-	{
-		///
-		/// Writes the objects out to the protocol
-		///
-		void Write(TProtocol tProtocol);
-	}
+    public interface TAbstractBase
+    {
+        /// <summary>
+        /// Writes the objects out to the protocol.
+        /// </summary>
+        void Write(TProtocol tProtocol);
+    }
 }
diff --git a/lib/csharp/src/Protocol/TBase.cs b/lib/csharp/src/Protocol/TBase.cs
index b8b36fb..411e4d9 100644
--- a/lib/csharp/src/Protocol/TBase.cs
+++ b/lib/csharp/src/Protocol/TBase.cs
@@ -19,11 +19,11 @@
 
 namespace Thrift.Protocol
 {
-	public interface TBase : TAbstractBase
-	{
-		///
-		/// Reads the TObject from the given input protocol.
-		///
-		void Read(TProtocol tProtocol);
-	}
+    public interface TBase : TAbstractBase
+    {
+        /// <summary>
+        /// Reads the TObject from the given input protocol.
+        /// </summary>
+        void Read(TProtocol tProtocol);
+    }
 }
diff --git a/lib/csharp/src/Protocol/TBase64Utils.cs b/lib/csharp/src/Protocol/TBase64Utils.cs
index 78c3767..9eaaebd 100644
--- a/lib/csharp/src/Protocol/TBase64Utils.cs
+++ b/lib/csharp/src/Protocol/TBase64Utils.cs
@@ -21,80 +21,80 @@
 
 namespace Thrift.Protocol
 {
-	internal static class TBase64Utils
-	{
-		internal const string ENCODE_TABLE =
-			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+    internal static class TBase64Utils
+    {
+        internal const string ENCODE_TABLE =
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
-		internal static void encode(byte[] src, int srcOff, int len, byte[] dst,
-								int dstOff)
-		{
-			dst[dstOff] = (byte)ENCODE_TABLE[(src[srcOff] >> 2) & 0x3F];
-			if (len == 3)
-			{
-				dst[dstOff + 1] =
-					(byte)ENCODE_TABLE[
-						((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
-				dst[dstOff + 2] =
-					(byte)ENCODE_TABLE[
-						((src[srcOff + 1] << 2) & 0x3C) | ((src[srcOff + 2] >> 6) & 0x03)];
-				dst[dstOff + 3] =
-					(byte)ENCODE_TABLE[src[srcOff + 2] & 0x3F];
-			}
-			else if (len == 2)
-			{
-				dst[dstOff + 1] =
-					(byte)ENCODE_TABLE[
-						((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
-				dst[dstOff + 2] =
-					(byte)ENCODE_TABLE[(src[srcOff + 1] << 2) & 0x3C];
+        internal static void encode(byte[] src, int srcOff, int len, byte[] dst,
+                                int dstOff)
+        {
+            dst[dstOff] = (byte)ENCODE_TABLE[(src[srcOff] >> 2) & 0x3F];
+            if (len == 3)
+            {
+                dst[dstOff + 1] =
+                    (byte)ENCODE_TABLE[
+                        ((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+                dst[dstOff + 2] =
+                    (byte)ENCODE_TABLE[
+                        ((src[srcOff + 1] << 2) & 0x3C) | ((src[srcOff + 2] >> 6) & 0x03)];
+                dst[dstOff + 3] =
+                    (byte)ENCODE_TABLE[src[srcOff + 2] & 0x3F];
+            }
+            else if (len == 2)
+            {
+                dst[dstOff + 1] =
+                    (byte)ENCODE_TABLE[
+                        ((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+                dst[dstOff + 2] =
+                    (byte)ENCODE_TABLE[(src[srcOff + 1] << 2) & 0x3C];
 
-			}
-			else
-			{ // len == 1) {
-				dst[dstOff + 1] =
-					(byte)ENCODE_TABLE[(src[srcOff] << 4) & 0x30];
-			}
-		}
+            }
+            else
+            { // len == 1) {
+                dst[dstOff + 1] =
+                    (byte)ENCODE_TABLE[(src[srcOff] << 4) & 0x30];
+            }
+        }
 
-		private static int[] DECODE_TABLE = {
-			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
-			52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
-			-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
-			15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
-			-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
-			41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
-			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-			-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-		};
+        private static int[] DECODE_TABLE = {
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
+            52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
+            -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
+            15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
+            -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
+            41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+        };
 
-		internal static void decode(byte[] src, int srcOff, int len, byte[] dst,
-								 int dstOff)
-		{
-			dst[dstOff] = (byte)
-				((DECODE_TABLE[src[srcOff] & 0x0FF] << 2) |
-				(DECODE_TABLE[src[srcOff + 1] & 0x0FF] >> 4));
-			if (len > 2)
-			{
-				dst[dstOff + 1] = (byte)
-					(((DECODE_TABLE[src[srcOff + 1] & 0x0FF] << 4) & 0xF0) |
-					(DECODE_TABLE[src[srcOff + 2] & 0x0FF] >> 2));
-				if (len > 3)
-				{
-					dst[dstOff + 2] = (byte)
-						(((DECODE_TABLE[src[srcOff + 2] & 0x0FF] << 6) & 0xC0) |
-						DECODE_TABLE[src[srcOff + 3] & 0x0FF]);
-				}
-			}
-		}
+        internal static void decode(byte[] src, int srcOff, int len, byte[] dst,
+                                 int dstOff)
+        {
+            dst[dstOff] = (byte)
+                ((DECODE_TABLE[src[srcOff] & 0x0FF] << 2) |
+                (DECODE_TABLE[src[srcOff + 1] & 0x0FF] >> 4));
+            if (len > 2)
+            {
+                dst[dstOff + 1] = (byte)
+                    (((DECODE_TABLE[src[srcOff + 1] & 0x0FF] << 4) & 0xF0) |
+                    (DECODE_TABLE[src[srcOff + 2] & 0x0FF] >> 2));
+                if (len > 3)
+                {
+                    dst[dstOff + 2] = (byte)
+                        (((DECODE_TABLE[src[srcOff + 2] & 0x0FF] << 6) & 0xC0) |
+                        DECODE_TABLE[src[srcOff + 3] & 0x0FF]);
+                }
+            }
+        }
 
-	}
+    }
 }
diff --git a/lib/csharp/src/Protocol/TBinaryProtocol.cs b/lib/csharp/src/Protocol/TBinaryProtocol.cs
index 4bbd9ad..a4faa94 100644
--- a/lib/csharp/src/Protocol/TBinaryProtocol.cs
+++ b/lib/csharp/src/Protocol/TBinaryProtocol.cs
@@ -27,369 +27,369 @@
 
 namespace Thrift.Protocol
 {
-	public class TBinaryProtocol : TProtocol
-	{
-		protected const uint VERSION_MASK = 0xffff0000;
-		protected const uint VERSION_1 = 0x80010000;
+    public class TBinaryProtocol : TProtocol
+    {
+        protected const uint VERSION_MASK = 0xffff0000;
+        protected const uint VERSION_1 = 0x80010000;
 
-		protected bool strictRead_ = false;
-		protected bool strictWrite_ = true;
+        protected bool strictRead_ = false;
+        protected bool strictWrite_ = true;
 
-		#region BinaryProtocol Factory
-		 /**
-		  * Factory
-		  */
-		  public class Factory : TProtocolFactory {
+        #region BinaryProtocol Factory
 
-			  protected bool strictRead_ = false;
-			  protected bool strictWrite_ = true;
+        public class Factory : TProtocolFactory
+        {
+            protected bool strictRead_ = false;
+            protected bool strictWrite_ = true;
 
-			  public Factory()
-				  :this(false, true)
-			  {
-			  }
+            public Factory()
+                : this(false, true)
+            {
+            }
 
-			  public Factory(bool strictRead, bool strictWrite)
-			  {
-				  strictRead_ = strictRead;
-				  strictWrite_ = strictWrite;
-			  }
+            public Factory(bool strictRead, bool strictWrite)
+            {
+                strictRead_ = strictRead;
+                strictWrite_ = strictWrite;
+            }
 
-			public TProtocol GetProtocol(TTransport trans) {
-			  return new TBinaryProtocol(trans, strictRead_, strictWrite_);
-			}
-		  }
+            public TProtocol GetProtocol(TTransport trans)
+            {
+                return new TBinaryProtocol(trans, strictRead_, strictWrite_);
+            }
+        }
 
-		#endregion
+        #endregion
 
-		public TBinaryProtocol(TTransport trans)
-			: this(trans, false, true)
-		{
-		}
+        public TBinaryProtocol(TTransport trans)
+            : this(trans, false, true)
+        {
+        }
 
-		public TBinaryProtocol(TTransport trans, bool strictRead, bool strictWrite)
-			:base(trans)
-		{
-			strictRead_ = strictRead;
-			strictWrite_ = strictWrite;
-		}
+        public TBinaryProtocol(TTransport trans, bool strictRead, bool strictWrite)
+            : base(trans)
+        {
+            strictRead_ = strictRead;
+            strictWrite_ = strictWrite;
+        }
 
-		#region Write Methods
+        #region Write Methods
 
-		public override void WriteMessageBegin(TMessage message)
-		{
-			if (strictWrite_)
-			{
-				uint version = VERSION_1 | (uint)(message.Type);
-				WriteI32((int)version);
-				WriteString(message.Name);
-				WriteI32(message.SeqID);
-			}
-			else
-			{
-				WriteString(message.Name);
-				WriteByte((sbyte)message.Type);
-				WriteI32(message.SeqID);
-			}
-		}
+        public override void WriteMessageBegin(TMessage message)
+        {
+            if (strictWrite_)
+            {
+                uint version = VERSION_1 | (uint)(message.Type);
+                WriteI32((int)version);
+                WriteString(message.Name);
+                WriteI32(message.SeqID);
+            }
+            else
+            {
+                WriteString(message.Name);
+                WriteByte((sbyte)message.Type);
+                WriteI32(message.SeqID);
+            }
+        }
 
-		public override void WriteMessageEnd()
-		{
-		}
+        public override void WriteMessageEnd()
+        {
+        }
 
-		public override void WriteStructBegin(TStruct struc)
-		{
-		}
+        public override void WriteStructBegin(TStruct struc)
+        {
+        }
 
-		public override void WriteStructEnd()
-		{
-		}
+        public override void WriteStructEnd()
+        {
+        }
 
-		public override void WriteFieldBegin(TField field)
-		{
-			WriteByte((sbyte)field.Type);
-			WriteI16(field.ID);
-		}
+        public override void WriteFieldBegin(TField field)
+        {
+            WriteByte((sbyte)field.Type);
+            WriteI16(field.ID);
+        }
 
-		public override void WriteFieldEnd()
-		{
-		}
+        public override void WriteFieldEnd()
+        {
+        }
 
-		public override void WriteFieldStop()
-		{
-			WriteByte((sbyte)TType.Stop);
-		}
+        public override void WriteFieldStop()
+        {
+            WriteByte((sbyte)TType.Stop);
+        }
 
-		public override void WriteMapBegin(TMap map)
-		{
-			WriteByte((sbyte)map.KeyType);
-			WriteByte((sbyte)map.ValueType);
-			WriteI32(map.Count);
-		}
+        public override void WriteMapBegin(TMap map)
+        {
+            WriteByte((sbyte)map.KeyType);
+            WriteByte((sbyte)map.ValueType);
+            WriteI32(map.Count);
+        }
 
-		public override void WriteMapEnd()
-		{
-		}
+        public override void WriteMapEnd()
+        {
+        }
 
-		public override void WriteListBegin(TList list)
-		{
-			WriteByte((sbyte)list.ElementType);
-			WriteI32(list.Count);
-		}
+        public override void WriteListBegin(TList list)
+        {
+            WriteByte((sbyte)list.ElementType);
+            WriteI32(list.Count);
+        }
 
-		public override void WriteListEnd()
-		{
-		}
+        public override void WriteListEnd()
+        {
+        }
 
-		public override void WriteSetBegin(TSet set)
-		{
-			WriteByte((sbyte)set.ElementType);
-			WriteI32(set.Count);
-		}
+        public override void WriteSetBegin(TSet set)
+        {
+            WriteByte((sbyte)set.ElementType);
+            WriteI32(set.Count);
+        }
 
-		public override void WriteSetEnd()
-		{
-		}
+        public override void WriteSetEnd()
+        {
+        }
 
-		public override void WriteBool(bool b)
-		{
-			WriteByte(b ? (sbyte)1 : (sbyte)0);
-		}
+        public override void WriteBool(bool b)
+        {
+            WriteByte(b ? (sbyte)1 : (sbyte)0);
+        }
 
-		private byte[] bout = new byte[1];
-		public override void WriteByte(sbyte b)
-		{
-			bout[0] = (byte)b;
-			trans.Write(bout, 0, 1);
-		}
+        private byte[] bout = new byte[1];
+        public override void WriteByte(sbyte b)
+        {
+            bout[0] = (byte)b;
+            trans.Write(bout, 0, 1);
+        }
 
-		private byte[] i16out = new byte[2];
-		public override void WriteI16(short s)
-		{
-			i16out[0] = (byte)(0xff & (s >> 8));
-			i16out[1] = (byte)(0xff & s);
-			trans.Write(i16out, 0, 2);
-		}
+        private byte[] i16out = new byte[2];
+        public override void WriteI16(short s)
+        {
+            i16out[0] = (byte)(0xff & (s >> 8));
+            i16out[1] = (byte)(0xff & s);
+            trans.Write(i16out, 0, 2);
+        }
 
-		private byte[] i32out = new byte[4];
-		public override void WriteI32(int i32)
-		{
-			i32out[0] = (byte)(0xff & (i32 >> 24));
-			i32out[1] = (byte)(0xff & (i32 >> 16));
-			i32out[2] = (byte)(0xff & (i32 >> 8));
-			i32out[3] = (byte)(0xff & i32);
-			trans.Write(i32out, 0, 4);
-		}
+        private byte[] i32out = new byte[4];
+        public override void WriteI32(int i32)
+        {
+            i32out[0] = (byte)(0xff & (i32 >> 24));
+            i32out[1] = (byte)(0xff & (i32 >> 16));
+            i32out[2] = (byte)(0xff & (i32 >> 8));
+            i32out[3] = (byte)(0xff & i32);
+            trans.Write(i32out, 0, 4);
+        }
 
-		private byte[] i64out = new byte[8];
-		public override void WriteI64(long i64)
-		{
-			i64out[0] = (byte)(0xff & (i64 >> 56));
-			i64out[1] = (byte)(0xff & (i64 >> 48));
-			i64out[2] = (byte)(0xff & (i64 >> 40));
-			i64out[3] = (byte)(0xff & (i64 >> 32));
-			i64out[4] = (byte)(0xff & (i64 >> 24));
-			i64out[5] = (byte)(0xff & (i64 >> 16));
-			i64out[6] = (byte)(0xff & (i64 >> 8));
-			i64out[7] = (byte)(0xff & i64);
-			trans.Write(i64out, 0, 8);
-		}
+        private byte[] i64out = new byte[8];
+        public override void WriteI64(long i64)
+        {
+            i64out[0] = (byte)(0xff & (i64 >> 56));
+            i64out[1] = (byte)(0xff & (i64 >> 48));
+            i64out[2] = (byte)(0xff & (i64 >> 40));
+            i64out[3] = (byte)(0xff & (i64 >> 32));
+            i64out[4] = (byte)(0xff & (i64 >> 24));
+            i64out[5] = (byte)(0xff & (i64 >> 16));
+            i64out[6] = (byte)(0xff & (i64 >> 8));
+            i64out[7] = (byte)(0xff & i64);
+            trans.Write(i64out, 0, 8);
+        }
 
-		public override void WriteDouble(double d)
-		{
+        public override void WriteDouble(double d)
+        {
 #if !SILVERLIGHT
-			WriteI64(BitConverter.DoubleToInt64Bits(d));
+            WriteI64(BitConverter.DoubleToInt64Bits(d));
 #else
             var bytes = BitConverter.GetBytes(d);
             WriteI64(BitConverter.ToInt64(bytes, 0));
 #endif
-		}
+        }
 
-		public override void WriteBinary(byte[] b)
-		{
-			WriteI32(b.Length);
-			trans.Write(b, 0, b.Length);
-		}
+        public override void WriteBinary(byte[] b)
+        {
+            WriteI32(b.Length);
+            trans.Write(b, 0, b.Length);
+        }
 
-		#endregion
+        #endregion
 
-		#region ReadMethods
+        #region ReadMethods
 
-		public override TMessage ReadMessageBegin()
-		{
-			TMessage message = new TMessage();
-			int size = ReadI32();
-			if (size < 0)
-			{
-				uint version = (uint)size & VERSION_MASK;
-				if (version != VERSION_1)
-				{
-					throw new TProtocolException(TProtocolException.BAD_VERSION, "Bad version in ReadMessageBegin: " + version);
-				}
-				message.Type = (TMessageType)(size & 0x000000ff);
-				message.Name = ReadString();
-				message.SeqID = ReadI32();
-			}
-			else
-			{
-				if (strictRead_)
-				{
-					throw new TProtocolException(TProtocolException.BAD_VERSION, "Missing version in readMessageBegin, old client?");
-				}
-				message.Name = ReadStringBody(size);
-				message.Type = (TMessageType)ReadByte();
-				message.SeqID = ReadI32();
-			}
-			return message;
-		}
-
-		public override void ReadMessageEnd()
-		{
-		}
-
-		public override TStruct ReadStructBegin()
-		{
-			return new TStruct();
-		}
-
-		public override void ReadStructEnd()
-		{
-		}
-
-		public override TField ReadFieldBegin()
-		{
-			TField field = new TField();
-			field.Type = (TType)ReadByte();
-
-			if (field.Type != TType.Stop)
-			{
-				field.ID = ReadI16();
-			}
-
-			return field;
-		}
-
-		public override void ReadFieldEnd()
-		{
-		}
-
-		public override TMap ReadMapBegin()
-		{
-			TMap map = new TMap();
-			map.KeyType = (TType)ReadByte();
-			map.ValueType = (TType)ReadByte();
-			map.Count = ReadI32();
-
-			return map;
-		}
-
-		public override void ReadMapEnd()
-		{
-		}
-
-		public override TList ReadListBegin()
-		{
-			TList list = new TList();
-			list.ElementType = (TType)ReadByte();
-			list.Count = ReadI32();
-
-			return list;
-		}
-
-		public override void ReadListEnd()
-		{
-		}
-
-		public override TSet ReadSetBegin()
-		{
-			TSet set = new TSet();
-			set.ElementType = (TType)ReadByte();
-			set.Count = ReadI32();
-
-			return set;
-		}
-
-		public override void ReadSetEnd()
-		{
-		}
-
-		public override bool ReadBool()
-		{
-			return ReadByte() == 1;
-		}
-
-		private byte[] bin = new byte[1];
-		public override sbyte ReadByte()
-		{
-			ReadAll(bin, 0, 1);
-			return (sbyte)bin[0];
-		}
-
-		private byte[] i16in = new byte[2];
-		public override short ReadI16()
-		{
-			ReadAll(i16in, 0, 2);
-			return (short)(((i16in[0] & 0xff) << 8) | ((i16in[1] & 0xff)));
-		}
-
-		private byte[] i32in = new byte[4];
-		public override int ReadI32()
-		{
-			ReadAll(i32in, 0, 4);
-			return (int)(((i32in[0] & 0xff) << 24) | ((i32in[1] & 0xff) << 16) | ((i32in[2] & 0xff) << 8) | ((i32in[3] & 0xff)));
-		}

-

-#pragma warning disable 675

-

-        private byte[] i64in = new byte[8];
-		public override long ReadI64()
-		{
-			ReadAll(i64in, 0, 8);

-            unchecked {
-              return (long)(
-                  ((long)(i64in[0] & 0xff) << 56) |
-                  ((long)(i64in[1] & 0xff) << 48) |
-                  ((long)(i64in[2] & 0xff) << 40) |
-                  ((long)(i64in[3] & 0xff) << 32) |
-                  ((long)(i64in[4] & 0xff) << 24) |
-                  ((long)(i64in[5] & 0xff) << 16) |
-                  ((long)(i64in[6] & 0xff) << 8) |
-                  ((long)(i64in[7] & 0xff)));
+        public override TMessage ReadMessageBegin()
+        {
+            TMessage message = new TMessage();
+            int size = ReadI32();
+            if (size < 0)
+            {
+                uint version = (uint)size & VERSION_MASK;
+                if (version != VERSION_1)
+                {
+                    throw new TProtocolException(TProtocolException.BAD_VERSION, "Bad version in ReadMessageBegin: " + version);
+                }
+                message.Type = (TMessageType)(size & 0x000000ff);
+                message.Name = ReadString();
+                message.SeqID = ReadI32();
             }
-        }

-

-#pragma warning restore 675

-

+            else
+            {
+                if (strictRead_)
+                {
+                    throw new TProtocolException(TProtocolException.BAD_VERSION, "Missing version in readMessageBegin, old client?");
+                }
+                message.Name = ReadStringBody(size);
+                message.Type = (TMessageType)ReadByte();
+                message.SeqID = ReadI32();
+            }
+            return message;
+        }
+
+        public override void ReadMessageEnd()
+        {
+        }
+
+        public override TStruct ReadStructBegin()
+        {
+            return new TStruct();
+        }
+
+        public override void ReadStructEnd()
+        {
+        }
+
+        public override TField ReadFieldBegin()
+        {
+            TField field = new TField();
+            field.Type = (TType)ReadByte();
+
+            if (field.Type != TType.Stop)
+            {
+                field.ID = ReadI16();
+            }
+
+            return field;
+        }
+
+        public override void ReadFieldEnd()
+        {
+        }
+
+        public override TMap ReadMapBegin()
+        {
+            TMap map = new TMap();
+            map.KeyType = (TType)ReadByte();
+            map.ValueType = (TType)ReadByte();
+            map.Count = ReadI32();
+
+            return map;
+        }
+
+        public override void ReadMapEnd()
+        {
+        }
+
+        public override TList ReadListBegin()
+        {
+            TList list = new TList();
+            list.ElementType = (TType)ReadByte();
+            list.Count = ReadI32();
+
+            return list;
+        }
+
+        public override void ReadListEnd()
+        {
+        }
+
+        public override TSet ReadSetBegin()
+        {
+            TSet set = new TSet();
+            set.ElementType = (TType)ReadByte();
+            set.Count = ReadI32();
+
+            return set;
+        }
+
+        public override void ReadSetEnd()
+        {
+        }
+
+        public override bool ReadBool()
+        {
+            return ReadByte() == 1;
+        }
+
+        private byte[] bin = new byte[1];
+        public override sbyte ReadByte()
+        {
+            ReadAll(bin, 0, 1);
+            return (sbyte)bin[0];
+        }
+
+        private byte[] i16in = new byte[2];
+        public override short ReadI16()
+        {
+            ReadAll(i16in, 0, 2);
+            return (short)(((i16in[0] & 0xff) << 8) | ((i16in[1] & 0xff)));
+        }
+
+        private byte[] i32in = new byte[4];
+        public override int ReadI32()
+        {
+            ReadAll(i32in, 0, 4);
+            return (int)(((i32in[0] & 0xff) << 24) | ((i32in[1] & 0xff) << 16) | ((i32in[2] & 0xff) << 8) | ((i32in[3] & 0xff)));
+        }
+
+#pragma warning disable 675
+
+        private byte[] i64in = new byte[8];
+        public override long ReadI64()
+        {
+            ReadAll(i64in, 0, 8);
+            unchecked
+            {
+                return (long)(
+                    ((long)(i64in[0] & 0xff) << 56) |
+                    ((long)(i64in[1] & 0xff) << 48) |
+                    ((long)(i64in[2] & 0xff) << 40) |
+                    ((long)(i64in[3] & 0xff) << 32) |
+                    ((long)(i64in[4] & 0xff) << 24) |
+                    ((long)(i64in[5] & 0xff) << 16) |
+                    ((long)(i64in[6] & 0xff) << 8) |
+                    ((long)(i64in[7] & 0xff)));
+            }
+        }
+
+#pragma warning restore 675
+
         public override double ReadDouble()
-		{
+        {
 #if !SILVERLIGHT
-			return BitConverter.Int64BitsToDouble(ReadI64());
+            return BitConverter.Int64BitsToDouble(ReadI64());
 #else
             var value = ReadI64();
             var bytes = BitConverter.GetBytes(value);
             return BitConverter.ToDouble(bytes, 0);
 #endif
-		}
+        }
 
-		public override byte[] ReadBinary()
-		{
-			int size = ReadI32();
-			byte[] buf = new byte[size];
-			trans.ReadAll(buf, 0, size);
-			return buf;
-		}
-		private  string ReadStringBody(int size)
-		{
-			byte[] buf = new byte[size];
-			trans.ReadAll(buf, 0, size);
-			return Encoding.UTF8.GetString(buf, 0, buf.Length);
-		}
+        public override byte[] ReadBinary()
+        {
+            int size = ReadI32();
+            byte[] buf = new byte[size];
+            trans.ReadAll(buf, 0, size);
+            return buf;
+        }
+        private string ReadStringBody(int size)
+        {
+            byte[] buf = new byte[size];
+            trans.ReadAll(buf, 0, size);
+            return Encoding.UTF8.GetString(buf, 0, buf.Length);
+        }
 
-		private int ReadAll(byte[] buf, int off, int len)
-		{
-			return trans.ReadAll(buf, off, len);
-		}
+        private int ReadAll(byte[] buf, int off, int len)
+        {
+            return trans.ReadAll(buf, off, len);
+        }
 
-		#endregion
-	}
+        #endregion
+    }
 }
diff --git a/lib/csharp/src/Protocol/TCompactProtocol.cs b/lib/csharp/src/Protocol/TCompactProtocol.cs
index a498577..ff67397 100644
--- a/lib/csharp/src/Protocol/TCompactProtocol.cs
+++ b/lib/csharp/src/Protocol/TCompactProtocol.cs
@@ -41,11 +41,12 @@
         private const byte VERSION = 1;
         private const byte VERSION_MASK = 0x1f; // 0001 1111
         private const byte TYPE_MASK = 0xE0; // 1110 0000
+        private const byte TYPE_BITS = 0x07; // 0000 0111
         private const int TYPE_SHIFT_AMOUNT = 5;
 
-        /**
-         * All of the on-wire type codes.
-         */
+        /// <summary>
+        /// All of the on-wire type codes.
+        /// </summary>
         private static class Types
         {
             public const byte STOP = 0x00;
@@ -63,32 +64,29 @@
             public const byte STRUCT = 0x0C;
         }
 
-        /** 
-         * Used to keep track of the last field for the current and previous structs,
-         * so we can do the delta stuff.
-         */
+        /// <summary>
+        /// Used to keep track of the last field for the current and previous structs,
+        /// so we can do the delta stuff.
+        /// </summary>
         private Stack<short> lastField_ = new Stack<short>(15);
 
         private short lastFieldId_ = 0;
 
-        /**
-         * If we encounter a boolean field begin, save the TField here so it can 
-         * have the value incorporated.
-         */
+        /// <summary>
+        /// If we encounter a boolean field begin, save the TField here so it can
+        /// have the value incorporated.
+        /// </summary>
         private Nullable<TField> booleanField_;
 
-        /**
-         * If we Read a field header, and it's a boolean field, save the boolean 
-         * value here so that ReadBool can use it.
-         */
-        private  Nullable<Boolean> boolValue_;
+        /// <summary>
+        /// If we Read a field header, and it's a boolean field, save the boolean
+        /// value here so that ReadBool can use it.
+        /// </summary>
+        private Nullable<Boolean> boolValue_;
 
 
         #region CompactProtocol Factory
 
-        /**
-		  * Factory
-		  */
         public class Factory : TProtocolFactory
         {
             public Factory() { }
@@ -126,31 +124,32 @@
 
         #region Write Methods
 
-
-        /** 
-         * Writes a byte without any possibility of all that field header nonsense. 
-         * Used internally by other writing methods that know they need to Write a byte.
-         */
+        /// <summary>
+        /// Writes a byte without any possibility of all that field header nonsense.
+        /// Used internally by other writing methods that know they need to Write a byte.
+        /// </summary>
         private byte[] byteDirectBuffer = new byte[1];
+
         private void WriteByteDirect(byte b)
         {
             byteDirectBuffer[0] = b;
             trans.Write(byteDirectBuffer);
         }
 
-        /** 
-         * Writes a byte without any possibility of all that field header nonsense.
-         */
+        /// <summary>
+        /// Writes a byte without any possibility of all that field header nonsense.
+        /// </summary>
         private void WriteByteDirect(int n)
         {
             WriteByteDirect((byte)n);
         }
 
-        /**
-         * Write an i32 as a varint. Results in 1-5 bytes on the wire.
-         * TODO: make a permanent buffer like WriteVarint64?
-         */
+        /// <summary>
+        /// Write an i32 as a varint. Results in 1-5 bytes on the wire.
+        /// TODO: make a permanent buffer like WriteVarint64?
+        /// </summary>
         byte[] i32buf = new byte[5];
+
         private void WriteVarint32(uint n)
         {
             int idx = 0;
@@ -173,10 +172,10 @@
             trans.Write(i32buf, 0, idx);
         }
 
-        /**
-        * 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.
-        */
+        /// <summary>
+        /// 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.
+        /// </summary>
         public override void WriteMessageBegin(TMessage message)
         {
             WriteByteDirect(PROTOCOL_ID);
@@ -185,33 +184,33 @@
             WriteString(message.Name);
         }
 
-        /**
-         * 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.
-         */
+        /// <summary>
+        /// 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.
+        /// </summary>
         public override void WriteStructBegin(TStruct strct)
         {
             lastField_.Push(lastFieldId_);
             lastFieldId_ = 0;
         }
 
-        /**
-         * 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.
-         */
+        /// <summary>
+        /// 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.
+        /// </summary>
         public override void WriteStructEnd()
         {
             lastFieldId_ = lastField_.Pop();
         }
 
-        /**
-         * Write a field header containing the field id and field type. If the
-         * difference between the current field id and the last one is small (< 15),
-         * then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
-         * field id will follow the type header as a zigzag varint.
-         */
+        /// <summary>
+        /// Write a field header containing the field id and field type. If the
+        /// difference between the current field id and the last one is small (&lt; 15),
+        /// then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
+        /// field id will follow the type header as a zigzag varint.
+        /// </summary>
         public override void WriteFieldBegin(TField field)
         {
             if (field.Type == TType.Bool)
@@ -225,11 +224,11 @@
             }
         }
 
-        /**
-         * 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.
-         */
+        /// <summary>
+        /// 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.
+        /// </summary>
         private void WriteFieldBeginInternal(TField field, byte typeOverride)
         {
             // short lastField = lastField_.Pop();
@@ -254,18 +253,18 @@
             // lastField_.push(field.id);
         }
 
-        /**
-         * Write the STOP symbol so we know there are no more fields in this struct.
-         */
+        /// <summary>
+        /// Write the STOP symbol so we know there are no more fields in this struct.
+        /// </summary>
         public override void WriteFieldStop()
         {
             WriteByteDirect(Types.STOP);
         }
 
-        /**
-         * Write a map header. If the map is empty, omit the key and value type 
-         * headers, as we don't need any additional information to skip it.
-         */
+        /// <summary>
+        /// Write a map header. If the map is empty, omit the key and value type
+        /// headers, as we don't need any additional information to skip it.
+        /// </summary>
         public override void WriteMapBegin(TMap map)
         {
             if (map.Count == 0)
@@ -279,28 +278,28 @@
             }
         }
 
-        /** 
-         * Write a list header.
-         */
+        /// <summary>
+        /// Write a list header.
+        /// </summary>
         public override void WriteListBegin(TList list)
         {
             WriteCollectionBegin(list.ElementType, list.Count);
         }
 
-        /**
-         * Write a set header.
-         */
+        /// <summary>
+        /// Write a set header.
+        /// </summary>
         public override void WriteSetBegin(TSet set)
         {
             WriteCollectionBegin(set.ElementType, set.Count);
         }
 
-        /**
-         * Write a boolean value. Potentially, this could be a boolean field, in 
-         * which case the field header info isn't written yet. If so, decide what the
-         * right type header is for the value and then Write the field header. 
-         * Otherwise, Write a single byte.
-         */
+        /// <summary>
+        /// Write a boolean value. Potentially, this could be a boolean field, in
+        /// which case the field header info isn't written yet. If so, decide what the
+        /// right type header is for the value and then Write the field header.
+        /// Otherwise, Write a single byte.
+        /// </summary>
         public override void WriteBool(Boolean b)
         {
             if (booleanField_ != null)
@@ -316,41 +315,41 @@
             }
         }
 
-        /** 
-         * Write a byte. Nothing to see here!
-         */
+        /// <summary>
+        /// Write a byte. Nothing to see here!
+        /// </summary>
         public override void WriteByte(sbyte b)
         {
             WriteByteDirect((byte)b);
         }
 
-        /**
-         * Write an I16 as a zigzag varint.
-         */
+        /// <summary>
+        /// Write an I16 as a zigzag varint.
+        /// </summary>
         public override void WriteI16(short i16)
         {
             WriteVarint32(intToZigZag(i16));
         }
 
-        /**
-         * Write an i32 as a zigzag varint.
-         */
+        /// <summary>
+        /// Write an i32 as a zigzag varint.
+        /// </summary>
         public override void WriteI32(int i32)
         {
             WriteVarint32(intToZigZag(i32));
         }
 
-        /**
-         * Write an i64 as a zigzag varint.
-         */
+        /// <summary>
+        /// Write an i64 as a zigzag varint.
+        /// </summary>
         public override void WriteI64(long i64)
         {
             WriteVarint64(longToZigzag(i64));
         }
 
-        /**
-         * Write a double to the wire as 8 bytes.
-         */
+        /// <summary>
+        /// Write a double to the wire as 8 bytes.
+        /// </summary>
         public override void WriteDouble(double dub)
         {
             byte[] data = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -358,18 +357,18 @@
             trans.Write(data);
         }
 
-        /**
-         * Write a string to the wire with a varint size preceding.
-         */
-        public override void WriteString(String str)
+        /// <summary>
+        /// Write a string to the wire with a varint size preceding.
+        /// </summary>
+        public override void WriteString(string str)
         {
             byte[] bytes = UTF8Encoding.UTF8.GetBytes(str);
             WriteBinary(bytes, 0, bytes.Length);
         }
 
-        /**
-         * Write a byte array, using a varint for the size. 
-         */
+        /// <summary>
+        /// Write a byte array, using a varint for the size.
+        /// </summary>
         public override void WriteBinary(byte[] bin)
         {
             WriteBinary(bin, 0, bin.Length);
@@ -382,9 +381,9 @@
         }
 
         //
-        // These methods are called by structs, but don't actually have any wire 
+        // These methods are called by structs, but don't actually have any wire
         // output or purpose.
-        // 
+        //
 
         public override void WriteMessageEnd() { }
         public override void WriteMapEnd() { }
@@ -396,10 +395,10 @@
         // 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.
-         */
+        /// <summary>
+        /// Abstract method for writing the start of lists and sets. List and sets on
+        /// the wire differ only by the type indicator.
+        /// </summary>
         protected void WriteCollectionBegin(TType elemType, int size)
         {
             if (size <= 14)
@@ -413,9 +412,9 @@
             }
         }
 
-        /**
-         * Write an i64 as a varint. Results in 1-10 bytes on the wire.
-         */
+        /// <summary>
+        /// Write an i64 as a varint. Results in 1-10 bytes on the wire.
+        /// </summary>
         byte[] varint64out = new byte[10];
         private void WriteVarint64(ulong n)
         {
@@ -436,28 +435,28 @@
             trans.Write(varint64out, 0, idx);
         }
 
-        /**
-         * Convert l into a zigzag long. This allows negative numbers to be 
-         * represented compactly as a varint.
-         */
+        /// <summary>
+        /// Convert l into a zigzag long. This allows negative numbers to be
+        /// represented compactly as a varint.
+        /// </summary>
         private ulong longToZigzag(long n)
         {
             return (ulong)(n << 1) ^ (ulong)(n >> 63);
         }
 
-        /**
-         * Convert n into a zigzag int. This allows negative numbers to be 
-         * represented compactly as a varint.
-         */
+        /// <summary>
+        /// Convert n into a zigzag int. This allows negative numbers to be
+        /// represented compactly as a varint.
+        /// </summary>
         private uint intToZigZag(int n)
         {
             return (uint)(n << 1) ^ (uint)(n >> 31);
         }
 
-        /**
-         * Convert a long into little-endian bytes in buf starting at off and going 
-         * until off+7.
-         */
+        /// <summary>
+        /// Convert a long into little-endian bytes in buf starting at off and going
+        /// until off+7.
+        /// </summary>
         private void fixedLongToBytes(long n, byte[] buf, int off)
         {
             buf[off + 0] = (byte)(n & 0xff);
@@ -474,32 +473,32 @@
 
         #region ReadMethods
 
-        /**
-   * Read a message header. 
-   */
+        /// <summary>
+        /// Read a message header.
+        /// </summary>
         public override TMessage ReadMessageBegin()
-        {

+        {
             byte protocolId = (byte)ReadByte();
             if (protocolId != PROTOCOL_ID)
             {
                 throw new TProtocolException("Expected protocol id " + PROTOCOL_ID.ToString("X") + " but got " + protocolId.ToString("X"));
-            }

+            }
             byte versionAndType = (byte)ReadByte();
             byte version = (byte)(versionAndType & VERSION_MASK);
             if (version != VERSION)
             {
                 throw new TProtocolException("Expected version " + VERSION + " but got " + version);
             }
-            byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & 0x03);
+            byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
             int seqid = (int)ReadVarint32();
-            String messageName = ReadString();
+            string messageName = ReadString();
             return new TMessage(messageName, (TMessageType)type, seqid);
         }
 
-        /**
-         * 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.
-         */
+        /// <summary>
+        /// 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.
+        /// </summary>
         public override TStruct ReadStructBegin()
         {
             lastField_.Push(lastFieldId_);
@@ -507,21 +506,21 @@
             return ANONYMOUS_STRUCT;
         }
 
-        /**
-         * Doesn't actually consume any wire data, just removes the last field for 
-         * this struct from the field stack.
-         */
+        /// <summary>
+        /// Doesn't actually consume any wire data, just removes the last field for
+        /// this struct from the field stack.
+        /// </summary>
         public override void ReadStructEnd()
         {
             // consume the last field we Read off the wire.
             lastFieldId_ = lastField_.Pop();
         }
 
-        /**
-         * Read a field header off the wire. 
-         */
+        /// <summary>
+        /// Read a field header off the wire.
+        /// </summary>
         public override TField ReadFieldBegin()
-        {

+        {
             byte type = (byte)ReadByte();
 
             // if it's a stop, then we can return immediately, as the struct is over.
@@ -559,26 +558,26 @@
             return field;
         }
 
-        /** 
-         * 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.
-         */
+        /// <summary>
+        /// 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.
+        /// </summary>
         public override TMap ReadMapBegin()
         {
-            int size = (int)ReadVarint32();

+            int size = (int)ReadVarint32();
             byte keyAndValueType = size == 0 ? (byte)0 : (byte)ReadByte();
             return new TMap(getTType((byte)(keyAndValueType >> 4)), getTType((byte)(keyAndValueType & 0xf)), size);
         }
 
-        /**
-         * 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.
-         */
+        /// <summary>
+        /// 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.
+        /// </summary>
         public override TList ReadListBegin()
-        {

+        {
             byte size_and_type = (byte)ReadByte();
             int size = (size_and_type >> 4) & 0x0f;
             if (size == 15)
@@ -589,22 +588,22 @@
             return new TList(type, size);
         }
 
-        /**
-         * 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.
-         */
+        /// <summary>
+        /// 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.
+        /// </summary>
         public override TSet ReadSetBegin()
         {
             return new TSet(ReadListBegin());
         }
 
-        /**
-         * 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.
-         */
+        /// <summary>
+        /// 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.
+        /// </summary>
         public override Boolean ReadBool()
         {
             if (boolValue_ != null)
@@ -617,42 +616,42 @@
         }
 
         byte[] byteRawBuf = new byte[1];
-        /**
-         * Read a single byte off the wire. Nothing interesting here.
-         */
+        /// <summary>
+        /// Read a single byte off the wire. Nothing interesting here.
+        /// </summary>
         public override sbyte ReadByte()
         {
             trans.ReadAll(byteRawBuf, 0, 1);
             return (sbyte)byteRawBuf[0];
         }
 
-        /**
-         * Read an i16 from the wire as a zigzag varint.
-         */
+        /// <summary>
+        /// Read an i16 from the wire as a zigzag varint.
+        /// </summary>
         public override short ReadI16()
         {
             return (short)zigzagToInt(ReadVarint32());
         }
 
-        /**
-         * Read an i32 from the wire as a zigzag varint.
-         */
+        /// <summary>
+        /// Read an i32 from the wire as a zigzag varint.
+        /// </summary>
         public override int ReadI32()
         {
             return zigzagToInt(ReadVarint32());
         }
 
-        /**
-         * Read an i64 from the wire as a zigzag varint.
-         */
+        /// <summary>
+        /// Read an i64 from the wire as a zigzag varint.
+        /// </summary>
         public override long ReadI64()
         {
             return zigzagToLong(ReadVarint64());
         }
 
-        /**
-         * No magic here - just Read a double off the wire.
-         */
+        /// <summary>
+        /// No magic here - just Read a double off the wire.
+        /// </summary>
         public override double ReadDouble()
         {
             byte[] longBits = new byte[8];
@@ -660,10 +659,10 @@
             return BitConverter.Int64BitsToDouble(bytesToLong(longBits));
         }
 
-        /**
-         * Reads a byte[] (via ReadBinary), and then UTF-8 decodes it.
-         */
-        public override String ReadString()
+        /// <summary>
+        /// Reads a byte[] (via ReadBinary), and then UTF-8 decodes it.
+        /// </summary>
+        public override string ReadString()
         {
             int length = (int)ReadVarint32();
 
@@ -675,9 +674,9 @@
             return Encoding.UTF8.GetString(ReadBinary(length));
         }
 
-        /**
-         * Read a byte[] from the wire. 
-         */
+        /// <summary>
+        /// Read a byte[] from the wire.
+        /// </summary>
         public override byte[] ReadBinary()
         {
             int length = (int)ReadVarint32();
@@ -688,9 +687,9 @@
             return buf;
         }
 
-        /**
-         * Read a byte[] of a known length from the wire. 
-         */
+        /// <summary>
+        /// Read a byte[] of a known length from the wire.
+        /// </summary>
         private byte[] ReadBinary(int length)
         {
             if (length == 0) return new byte[0];
@@ -701,7 +700,7 @@
         }
 
         //
-        // These methods are here for the struct to call, but don't have any wire 
+        // These methods are here for the struct to call, but don't have any wire
         // encoding.
         //
         public override void ReadMessageEnd() { }
@@ -714,16 +713,16 @@
         // 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.
-         */
+        /// <summary>
+        /// 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.
+        /// </summary>
         private uint ReadVarint32()
         {
             uint result = 0;
             int shift = 0;
             while (true)
-            {

+            {
                 byte b = (byte)ReadByte();
                 result |= (uint)(b & 0x7f) << shift;
                 if ((b & 0x80) != 0x80) break;
@@ -732,22 +731,22 @@
             return result;
         }
 
-        /**
-         * 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.
-         */
+        /// <summary>
+        /// 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.
+        /// </summary>
         private ulong ReadVarint64()
         {
             int shift = 0;
             ulong result = 0;
             while (true)
-            {

+            {
                 byte b = (byte)ReadByte();
                 result |= (ulong)(b & 0x7f) << shift;
                 if ((b & 0x80) != 0x80) break;
                 shift += 7;
             }
-			
+
             return result;
         }
 
@@ -757,27 +756,27 @@
         // encoding helpers
         //
 
-        /**
-         * Convert from zigzag int to int.
-         */
+        /// <summary>
+        /// Convert from zigzag int to int.
+        /// </summary>
         private int zigzagToInt(uint n)
         {
             return (int)(n >> 1) ^ (-(int)(n & 1));
         }
 
-        /** 
-         * Convert from zigzag long to long.
-         */
+        /// <summary>
+        /// Convert from zigzag long to long.
+        /// </summary>
         private long zigzagToLong(ulong n)
         {
             return (long)(n >> 1) ^ (-(long)(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.
-         */
+        /// <summary>
+        /// 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.
+        /// </summary>
         private long bytesToLong(byte[] bytes)
         {
             return
@@ -801,10 +800,10 @@
             return lowerNibble == Types.BOOLEAN_TRUE || lowerNibble == Types.BOOLEAN_FALSE;
         }
 
-        /**
-         * Given a TCompactProtocol.Types constant, convert it to its corresponding 
-         * TType value.
-         */
+        /// <summary>
+        /// Given a TCompactProtocol.Types constant, convert it to its corresponding
+        /// TType value.
+        /// </summary>
         private TType getTType(byte type)
         {
             switch ((byte)(type & 0x0f))
@@ -839,9 +838,9 @@
             }
         }
 
-        /**
-         * Given a TType value, find the appropriate TCompactProtocol.Types constant.
-         */
+        /// <summary>
+        /// Given a TType value, find the appropriate TCompactProtocol.Types constant.
+        /// </summary>
         private byte getCompactType(TType ttype)
         {
             return ttypeToCompactType[(int)ttype];
diff --git a/lib/csharp/src/Protocol/TField.cs b/lib/csharp/src/Protocol/TField.cs
index fa10584..8179557 100644
--- a/lib/csharp/src/Protocol/TField.cs
+++ b/lib/csharp/src/Protocol/TField.cs
@@ -27,36 +27,36 @@
 
 namespace Thrift.Protocol
 {
-	public struct TField
-	{
-		private string name;
-		private TType type;
-		private short id;
+    public struct TField
+    {
+        private string name;
+        private TType type;
+        private short id;
 
-		public TField(string name, TType type, short id)
-			:this()
-		{
-			this.name = name;
-			this.type = type;
-			this.id = id;
-		}
+        public TField(string name, TType type, short id)
+            :this()
+        {
+            this.name = name;
+            this.type = type;
+            this.id = id;
+        }
 
-		public string Name
-		{
-			get { return name; }
-			set { name = value; }
-		}
+        public string Name
+        {
+            get { return name; }
+            set { name = value; }
+        }
 
-		public TType Type
-		{
-			get { return type; }
-			set { type = value; }
-		}
+        public TType Type
+        {
+            get { return type; }
+            set { type = value; }
+        }
 
-		public short ID
-		{
-			get { return id; }
-			set { id = value; }
-		}
-	}
+        public short ID
+        {
+            get { return id; }
+            set { id = value; }
+        }
+    }
 }
diff --git a/lib/csharp/src/Protocol/TJSONProtocol.cs b/lib/csharp/src/Protocol/TJSONProtocol.cs
index 3b27d30..9dbdea9 100644
--- a/lib/csharp/src/Protocol/TJSONProtocol.cs
+++ b/lib/csharp/src/Protocol/TJSONProtocol.cs
@@ -27,1049 +27,1098 @@
 
 namespace Thrift.Protocol
 {
-	/// <summary>
-	/// JSON protocol implementation for thrift.
-	///
-	/// This is a full-featured protocol supporting Write and Read.
-	///
-	/// Please see the C++ class header for a detailed description of the
-	/// protocol's wire format.
-	///
-	/// Adapted from the Java version.
-	/// </summary>
-	public class TJSONProtocol : TProtocol
-	{
-		/// <summary>
-		/// Factory for JSON protocol objects
-		/// </summary>
-		public class Factory : TProtocolFactory
-		{
-			public TProtocol GetProtocol(TTransport trans)
-			{
-				return new TJSONProtocol(trans);
-			}
-		}
+    /// <summary>
+    /// JSON protocol implementation for thrift.
+    /// <para/>
+    /// This is a full-featured protocol supporting Write and Read.
+    /// <para/>
+    /// Please see the C++ class header for a detailed description of the
+    /// protocol's wire format.
+    /// <para/>
+    /// Adapted from the Java version.
+    /// </summary>
+    public class TJSONProtocol : TProtocol
+    {
+        /// <summary>
+        /// Factory for JSON protocol objects.
+        /// </summary>
+        public class Factory : TProtocolFactory
+        {
+            public TProtocol GetProtocol(TTransport trans)
+            {
+                return new TJSONProtocol(trans);
+            }
+        }
 
-		private static byte[] COMMA = new byte[] { (byte)',' };
-		private static byte[] COLON = new byte[] { (byte)':' };
-		private static byte[] LBRACE = new byte[] { (byte)'{' };
-		private static byte[] RBRACE = new byte[] { (byte)'}' };
-		private static byte[] LBRACKET = new byte[] { (byte)'[' };
-		private static byte[] RBRACKET = new byte[] { (byte)']' };
-		private static byte[] QUOTE = new byte[] { (byte)'"' };
-		private static byte[] BACKSLASH = new byte[] { (byte)'\\' };
-		private static byte[] ZERO = new byte[] { (byte)'0' };
+        private static byte[] COMMA = new byte[] { (byte)',' };
+        private static byte[] COLON = new byte[] { (byte)':' };
+        private static byte[] LBRACE = new byte[] { (byte)'{' };
+        private static byte[] RBRACE = new byte[] { (byte)'}' };
+        private static byte[] LBRACKET = new byte[] { (byte)'[' };
+        private static byte[] RBRACKET = new byte[] { (byte)']' };
+        private static byte[] QUOTE = new byte[] { (byte)'"' };
+        private static byte[] BACKSLASH = new byte[] { (byte)'\\' };
 
-		private byte[] ESCSEQ = new byte[] { (byte)'\\', (byte)'u', (byte)'0', (byte)'0' };
+        private byte[] ESCSEQ = new byte[] { (byte)'\\', (byte)'u', (byte)'0', (byte)'0' };
 
-		private const long VERSION = 1;
-		private byte[] JSON_CHAR_TABLE = {
-	0,  0,  0,  0,  0,  0,  0,  0,(byte)'b',(byte)'t',(byte)'n',  0,(byte)'f',(byte)'r',  0,  0, 
-	0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 
-	1,  1,(byte)'"',  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+        private const long VERSION = 1;
+        private byte[] JSON_CHAR_TABLE = {
+    0,  0,  0,  0,  0,  0,  0,  0,(byte)'b',(byte)'t',(byte)'n',  0,(byte)'f',(byte)'r',  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    1,  1,(byte)'"',  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
   };
 
-		private char[] ESCAPE_CHARS = "\"\\bfnrt".ToCharArray();
+        private char[] ESCAPE_CHARS = "\"\\/bfnrt".ToCharArray();
 
-		private byte[] ESCAPE_CHAR_VALS = {
-	(byte)'"', (byte)'\\', (byte)'\b', (byte)'\f', (byte)'\n', (byte)'\r', (byte)'\t',
+        private byte[] ESCAPE_CHAR_VALS = {
+    (byte)'"', (byte)'\\', (byte)'/', (byte)'\b', (byte)'\f', (byte)'\n', (byte)'\r', (byte)'\t',
   };
 
-		private const int DEF_STRING_SIZE = 16;
+        private const int DEF_STRING_SIZE = 16;
 
-		private static byte[] NAME_BOOL = new byte[] { (byte)'t', (byte)'f' };
-		private static byte[] NAME_BYTE = new byte[] { (byte)'i', (byte)'8' };
-		private static byte[] NAME_I16 = new byte[] { (byte)'i', (byte)'1', (byte)'6' };
-		private static byte[] NAME_I32 = new byte[] { (byte)'i', (byte)'3', (byte)'2' };
-		private static byte[] NAME_I64 = new byte[] { (byte)'i', (byte)'6', (byte)'4' };
-		private static byte[] NAME_DOUBLE = new byte[] { (byte)'d', (byte)'b', (byte)'l' };
-		private static byte[] NAME_STRUCT = new byte[] { (byte)'r', (byte)'e', (byte)'c' };
-		private static byte[] NAME_STRING = new byte[] { (byte)'s', (byte)'t', (byte)'r' };
-		private static byte[] NAME_MAP = new byte[] { (byte)'m', (byte)'a', (byte)'p' };
-		private static byte[] NAME_LIST = new byte[] { (byte)'l', (byte)'s', (byte)'t' };
-		private static byte[] NAME_SET = new byte[] { (byte)'s', (byte)'e', (byte)'t' };
+        private static byte[] NAME_BOOL = new byte[] { (byte)'t', (byte)'f' };
+        private static byte[] NAME_BYTE = new byte[] { (byte)'i', (byte)'8' };
+        private static byte[] NAME_I16 = new byte[] { (byte)'i', (byte)'1', (byte)'6' };
+        private static byte[] NAME_I32 = new byte[] { (byte)'i', (byte)'3', (byte)'2' };
+        private static byte[] NAME_I64 = new byte[] { (byte)'i', (byte)'6', (byte)'4' };
+        private static byte[] NAME_DOUBLE = new byte[] { (byte)'d', (byte)'b', (byte)'l' };
+        private static byte[] NAME_STRUCT = new byte[] { (byte)'r', (byte)'e', (byte)'c' };
+        private static byte[] NAME_STRING = new byte[] { (byte)'s', (byte)'t', (byte)'r' };
+        private static byte[] NAME_MAP = new byte[] { (byte)'m', (byte)'a', (byte)'p' };
+        private static byte[] NAME_LIST = new byte[] { (byte)'l', (byte)'s', (byte)'t' };
+        private static byte[] NAME_SET = new byte[] { (byte)'s', (byte)'e', (byte)'t' };
 
-		private static byte[] GetTypeNameForTypeID(TType typeID)
-		{
-			switch (typeID)
-			{
-				case TType.Bool:
-					return NAME_BOOL;
-				case TType.Byte:
-					return NAME_BYTE;
-				case TType.I16:
-					return NAME_I16;
-				case TType.I32:
-					return NAME_I32;
-				case TType.I64:
-					return NAME_I64;
-				case TType.Double:
-					return NAME_DOUBLE;
-				case TType.String:
-					return NAME_STRING;
-				case TType.Struct:
-					return NAME_STRUCT;
-				case TType.Map:
-					return NAME_MAP;
-				case TType.Set:
-					return NAME_SET;
-				case TType.List:
-					return NAME_LIST;
-				default:
-					throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
-												 "Unrecognized type");
-			}
-		}
+        private static byte[] GetTypeNameForTypeID(TType typeID)
+        {
+            switch (typeID)
+            {
+                case TType.Bool:
+                    return NAME_BOOL;
+                case TType.Byte:
+                    return NAME_BYTE;
+                case TType.I16:
+                    return NAME_I16;
+                case TType.I32:
+                    return NAME_I32;
+                case TType.I64:
+                    return NAME_I64;
+                case TType.Double:
+                    return NAME_DOUBLE;
+                case TType.String:
+                    return NAME_STRING;
+                case TType.Struct:
+                    return NAME_STRUCT;
+                case TType.Map:
+                    return NAME_MAP;
+                case TType.Set:
+                    return NAME_SET;
+                case TType.List:
+                    return NAME_LIST;
+                default:
+                    throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+                                                 "Unrecognized type");
+            }
+        }
 
-		private static TType GetTypeIDForTypeName(byte[] name)
-		{
-			TType result = TType.Stop;
-			if (name.Length > 1)
-			{
-				switch (name[0])
-				{
-					case (byte)'d':
-						result = TType.Double;
-						break;
-					case (byte)'i':
-						switch (name[1])
-						{
-							case (byte)'8':
-								result = TType.Byte;
-								break;
-							case (byte)'1':
-								result = TType.I16;
-								break;
-							case (byte)'3':
-								result = TType.I32;
-								break;
-							case (byte)'6':
-								result = TType.I64;
-								break;
-						}
-						break;
-					case (byte)'l':
-						result = TType.List;
-						break;
-					case (byte)'m':
-						result = TType.Map;
-						break;
-					case (byte)'r':
-						result = TType.Struct;
-						break;
-					case (byte)'s':
-						if (name[1] == (byte)'t')
-						{
-							result = TType.String;
-						}
-						else if (name[1] == (byte)'e')
-						{
-							result = TType.Set;
-						}
-						break;
-					case (byte)'t':
-						result = TType.Bool;
-						break;
-				}
-			}
-			if (result == TType.Stop)
-			{
-				throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
-											 "Unrecognized type");
-			}
-			return result;
-		}
+        private static TType GetTypeIDForTypeName(byte[] name)
+        {
+            TType result = TType.Stop;
+            if (name.Length > 1)
+            {
+                switch (name[0])
+                {
+                    case (byte)'d':
+                        result = TType.Double;
+                        break;
+                    case (byte)'i':
+                        switch (name[1])
+                        {
+                            case (byte)'8':
+                                result = TType.Byte;
+                                break;
+                            case (byte)'1':
+                                result = TType.I16;
+                                break;
+                            case (byte)'3':
+                                result = TType.I32;
+                                break;
+                            case (byte)'6':
+                                result = TType.I64;
+                                break;
+                        }
+                        break;
+                    case (byte)'l':
+                        result = TType.List;
+                        break;
+                    case (byte)'m':
+                        result = TType.Map;
+                        break;
+                    case (byte)'r':
+                        result = TType.Struct;
+                        break;
+                    case (byte)'s':
+                        if (name[1] == (byte)'t')
+                        {
+                            result = TType.String;
+                        }
+                        else if (name[1] == (byte)'e')
+                        {
+                            result = TType.Set;
+                        }
+                        break;
+                    case (byte)'t':
+                        result = TType.Bool;
+                        break;
+                }
+            }
+            if (result == TType.Stop)
+            {
+                throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+                                             "Unrecognized type");
+            }
+            return result;
+        }
 
-		///<summary>
-		/// Base class for tracking JSON contexts that may require
-		/// inserting/Reading additional JSON syntax characters
-		/// This base context does nothing.
-		///</summary>
-		protected class JSONBaseContext
-		{
-			protected TJSONProtocol proto;
+        /// <summary>
+        /// Base class for tracking JSON contexts that may require
+        /// inserting/Reading additional JSON syntax characters
+        /// This base context does nothing.
+        /// </summary>
+        protected class JSONBaseContext
+        {
+            protected TJSONProtocol proto;
 
-			public JSONBaseContext(TJSONProtocol proto)
-			{
-				this.proto = proto;
-			}
+            public JSONBaseContext(TJSONProtocol proto)
+            {
+                this.proto = proto;
+            }
 
-			public virtual void Write() { }
+            public virtual void Write() { }
 
-			public virtual void Read() { }
+            public virtual void Read() { }
 
-			public virtual bool EscapeNumbers() { return false; }
-		}
+            public virtual bool EscapeNumbers() { return false; }
+        }
 
-		///<summary>
-		/// Context for JSON lists. Will insert/Read commas before each item except
-		/// for the first one
-		///</summary>
-		protected class JSONListContext : JSONBaseContext
-		{
-			public JSONListContext(TJSONProtocol protocol)
-				: base(protocol)
-			{
+        /// <summary>
+        /// Context for JSON lists. Will insert/Read commas before each item except
+        /// for the first one
+        /// </summary>
+        protected class JSONListContext : JSONBaseContext
+        {
+            public JSONListContext(TJSONProtocol protocol)
+                : base(protocol)
+            {
 
-			}
+            }
 
-			private bool first = true;
+            private bool first = true;
 
-			public override void Write()
-			{
-				if (first)
-				{
-					first = false;
-				}
-				else
-				{
-					proto.trans.Write(COMMA);
-				}
-			}
+            public override void Write()
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    proto.trans.Write(COMMA);
+                }
+            }
 
-			public override void Read()
-			{
-				if (first)
-				{
-					first = false;
-				}
-				else
-				{
-					proto.ReadJSONSyntaxChar(COMMA);
-				}
-			}
-		}
+            public override void Read()
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    proto.ReadJSONSyntaxChar(COMMA);
+                }
+            }
+        }
 
-		///<summary>
-		/// Context for JSON records. Will insert/Read colons before the value portion
-		/// of each record pair, and commas before each key except the first. In
-		/// addition, will indicate that numbers in the key position need to be
-		/// escaped in quotes (since JSON keys must be strings).
-		///</summary>
-		protected class JSONPairContext : JSONBaseContext
-		{
-			public JSONPairContext(TJSONProtocol proto)
-				: base(proto)
-			{
+        /// <summary>
+        /// Context for JSON records. Will insert/Read colons before the value portion
+        /// of each record pair, and commas before each key except the first. In
+        /// addition, will indicate that numbers in the key position need to be
+        /// escaped in quotes (since JSON keys must be strings).
+        /// </summary>
+        protected class JSONPairContext : JSONBaseContext
+        {
+            public JSONPairContext(TJSONProtocol proto)
+                : base(proto)
+            {
 
-			}
+            }
 
-			private bool first = true;
-			private bool colon = true;
+            private bool first = true;
+            private bool colon = true;
 
-			public override void Write()
-			{
-				if (first)
-				{
-					first = false;
-					colon = true;
-				}
-				else
-				{
-					proto.trans.Write(colon ? COLON : COMMA);
-					colon = !colon;
-				}
-			}
+            public override void Write()
+            {
+                if (first)
+                {
+                    first = false;
+                    colon = true;
+                }
+                else
+                {
+                    proto.trans.Write(colon ? COLON : COMMA);
+                    colon = !colon;
+                }
+            }
 
-			public override void Read()
-			{
-				if (first)
-				{
-					first = false;
-					colon = true;
-				}
-				else
-				{
-					proto.ReadJSONSyntaxChar(colon ? COLON : COMMA);
-					colon = !colon;
-				}
-			}
+            public override void Read()
+            {
+                if (first)
+                {
+                    first = false;
+                    colon = true;
+                }
+                else
+                {
+                    proto.ReadJSONSyntaxChar(colon ? COLON : COMMA);
+                    colon = !colon;
+                }
+            }
 
-			public override bool EscapeNumbers()
-			{
-				return colon;
-			}
-		}
+            public override bool EscapeNumbers()
+            {
+                return colon;
+            }
+        }
 
-		///<summary>
-		/// Holds up to one byte from the transport
-		///</summary>
-		protected class LookaheadReader
-		{
-			protected TJSONProtocol proto;
+        /// <summary>
+        /// Holds up to one byte from the transport
+        /// </summary>
+        protected class LookaheadReader
+        {
+            protected TJSONProtocol proto;
 
-			public LookaheadReader(TJSONProtocol proto)
-			{
-				this.proto = proto;
-			}
+            public LookaheadReader(TJSONProtocol proto)
+            {
+                this.proto = proto;
+            }
 
-			private bool hasData;
-			private byte[] data = new byte[1];
+            private bool hasData;
+            private byte[] data = new byte[1];
 
-			///<summary>
-			/// Return and consume the next byte to be Read, either taking it from the
-			/// data buffer if present or getting it from the transport otherwise.
-			///</summary>
-			public byte Read()
-			{
-				if (hasData)
-				{
-					hasData = false;
-				}
-				else
-				{
-					proto.trans.ReadAll(data, 0, 1);
-				}
-				return data[0];
-			}
+            /// <summary>
+            /// Return and consume the next byte to be Read, either taking it from the
+            /// data buffer if present or getting it from the transport otherwise.
+            /// </summary>
+            public byte Read()
+            {
+                if (hasData)
+                {
+                    hasData = false;
+                }
+                else
+                {
+                    proto.trans.ReadAll(data, 0, 1);
+                }
+                return data[0];
+            }
 
-			///<summary>
-			/// Return the next byte to be Read without consuming, filling the data
-			/// buffer if it has not been filled alReady.
-			///</summary>
-			public byte Peek()
-			{
-				if (!hasData)
-				{
-					proto.trans.ReadAll(data, 0, 1);
-				}
-				hasData = true;
-				return data[0];
-			}
-		}
+            /// <summary>
+            /// Return the next byte to be Read without consuming, filling the data
+            /// buffer if it has not been filled alReady.
+            /// </summary>
+            public byte Peek()
+            {
+                if (!hasData)
+                {
+                    proto.trans.ReadAll(data, 0, 1);
+                }
+                hasData = true;
+                return data[0];
+            }
+        }
 
-		// Default encoding
-		protected Encoding utf8Encoding = UTF8Encoding.UTF8;
+        // Default encoding
+        protected Encoding utf8Encoding = UTF8Encoding.UTF8;
 
-		// Stack of nested contexts that we may be in
-		protected Stack<JSONBaseContext> contextStack = new Stack<JSONBaseContext>();
+        // Stack of nested contexts that we may be in
+        protected Stack<JSONBaseContext> contextStack = new Stack<JSONBaseContext>();
 
-		// Current context that we are in
-		protected JSONBaseContext context;
+        // Current context that we are in
+        protected JSONBaseContext context;
 
-		// Reader that manages a 1-byte buffer
-		protected LookaheadReader reader;
+        // Reader that manages a 1-byte buffer
+        protected LookaheadReader reader;
 
-		///<summary>
-		/// Push a new JSON context onto the stack.
-		///</summary>
-		protected void PushContext(JSONBaseContext c)
-		{
-			contextStack.Push(context);
-			context = c;
-		}
+        /// <summary>
+        /// Push a new JSON context onto the stack.
+        /// </summary>
+        protected void PushContext(JSONBaseContext c)
+        {
+            contextStack.Push(context);
+            context = c;
+        }
 
-		///<summary>
-		/// Pop the last JSON context off the stack
-		///</summary>
-		protected void PopContext()
-		{
-			context = contextStack.Pop();
-		}
+        /// <summary>
+        /// Pop the last JSON context off the stack
+        /// </summary>
+        protected void PopContext()
+        {
+            context = contextStack.Pop();
+        }
 
-		///<summary>
-		/// TJSONProtocol Constructor
-		///</summary>
-		public TJSONProtocol(TTransport trans)
-			: base(trans)
-		{
-			context = new JSONBaseContext(this);
-			reader = new LookaheadReader(this);
-		}
+        /// <summary>
+        /// TJSONProtocol Constructor
+        /// </summary>
+        public TJSONProtocol(TTransport trans)
+            : base(trans)
+        {
+            context = new JSONBaseContext(this);
+            reader = new LookaheadReader(this);
+        }
 
-		// Temporary buffer used by several methods
-		private byte[] tempBuffer = new byte[4];
+        // Temporary buffer used by several methods
+        private byte[] tempBuffer = new byte[4];
 
-		///<summary>
-		/// Read a byte that must match b[0]; otherwise an exception is thrown.
-		/// Marked protected to avoid synthetic accessor in JSONListContext.Read
-		/// and JSONPairContext.Read
-		///</summary>
-		protected void ReadJSONSyntaxChar(byte[] b)
-		{
-			byte ch = reader.Read();
-			if (ch != b[0])
-			{
-				throw new TProtocolException(TProtocolException.INVALID_DATA,
-											 "Unexpected character:" + (char)ch);
-			}
-		}
+        /// <summary>
+        /// Read a byte that must match b[0]; otherwise an exception is thrown.
+        /// Marked protected to avoid synthetic accessor in JSONListContext.Read
+        /// and JSONPairContext.Read
+        /// </summary>
+        protected void ReadJSONSyntaxChar(byte[] b)
+        {
+            byte ch = reader.Read();
+            if (ch != b[0])
+            {
+                throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                             "Unexpected character:" + (char)ch);
+            }
+        }
 
-		///<summary>
-		/// Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its
-		/// corresponding hex value
-		///</summary>
-		private static byte HexVal(byte ch)
-		{
-			if ((ch >= '0') && (ch <= '9'))
-			{
-				return (byte)((char)ch - '0');
-			}
-			else if ((ch >= 'a') && (ch <= 'f'))
-			{
-				ch += 10;
-				return (byte)((char)ch - 'a');
-			}
-			else
-			{
-				throw new TProtocolException(TProtocolException.INVALID_DATA,
-											 "Expected hex character");
-			}
-		}
+        /// <summary>
+        /// Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its
+        /// corresponding hex value
+        /// </summary>
+        private static byte HexVal(byte ch)
+        {
+            if ((ch >= '0') && (ch <= '9'))
+            {
+                return (byte)((char)ch - '0');
+            }
+            else if ((ch >= 'a') && (ch <= 'f'))
+            {
+                ch += 10;
+                return (byte)((char)ch - 'a');
+            }
+            else
+            {
+                throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                             "Expected hex character");
+            }
+        }
 
-		///<summary>
-		/// Convert a byte containing a hex value to its corresponding hex character
-		///</summary>
-		private static byte HexChar(byte val)
-		{
-			val &= 0x0F;
-			if (val < 10)
-			{
-				return (byte)((char)val + '0');
-			}
-			else
-			{
-				val -= 10;
-				return (byte)((char)val + 'a');
-			}
-		}
+        /// <summary>
+        /// Convert a byte containing a hex value to its corresponding hex character
+        /// </summary>
+        private static byte HexChar(byte val)
+        {
+            val &= 0x0F;
+            if (val < 10)
+            {
+                return (byte)((char)val + '0');
+            }
+            else
+            {
+                val -= 10;
+                return (byte)((char)val + 'a');
+            }
+        }
 
-		///<summary>
-		/// Write the bytes in array buf as a JSON characters, escaping as needed
-		///</summary>
-		private void WriteJSONString(byte[] b)
-		{
-			context.Write();
-			trans.Write(QUOTE);
-			int len = b.Length;
-			for (int i = 0; i < len; i++)
-			{
-				if ((b[i] & 0x00FF) >= 0x30)
-				{
-					if (b[i] == BACKSLASH[0])
-					{
-						trans.Write(BACKSLASH);
-						trans.Write(BACKSLASH);
-					}
-					else
-					{
-						trans.Write(b, i, 1);
-					}
-				}
-				else
-				{
-					tempBuffer[0] = JSON_CHAR_TABLE[b[i]];
-					if (tempBuffer[0] == 1)
-					{
-						trans.Write(b, i, 1);
-					}
-					else if (tempBuffer[0] > 1)
-					{
-						trans.Write(BACKSLASH);
-						trans.Write(tempBuffer, 0, 1);
-					}
-					else
-					{
-						trans.Write(ESCSEQ);
-						tempBuffer[0] = HexChar((byte)(b[i] >> 4));
-						tempBuffer[1] = HexChar(b[i]);
-						trans.Write(tempBuffer, 0, 2);
-					}
-				}
-			}
-			trans.Write(QUOTE);
-		}
+        /// <summary>
+        /// Write the bytes in array buf as a JSON characters, escaping as needed
+        /// </summary>
+        private void WriteJSONString(byte[] b)
+        {
+            context.Write();
+            trans.Write(QUOTE);
+            int len = b.Length;
+            for (int i = 0; i < len; i++)
+            {
+                if ((b[i] & 0x00FF) >= 0x30)
+                {
+                    if (b[i] == BACKSLASH[0])
+                    {
+                        trans.Write(BACKSLASH);
+                        trans.Write(BACKSLASH);
+                    }
+                    else
+                    {
+                        trans.Write(b, i, 1);
+                    }
+                }
+                else
+                {
+                    tempBuffer[0] = JSON_CHAR_TABLE[b[i]];
+                    if (tempBuffer[0] == 1)
+                    {
+                        trans.Write(b, i, 1);
+                    }
+                    else if (tempBuffer[0] > 1)
+                    {
+                        trans.Write(BACKSLASH);
+                        trans.Write(tempBuffer, 0, 1);
+                    }
+                    else
+                    {
+                        trans.Write(ESCSEQ);
+                        tempBuffer[0] = HexChar((byte)(b[i] >> 4));
+                        tempBuffer[1] = HexChar(b[i]);
+                        trans.Write(tempBuffer, 0, 2);
+                    }
+                }
+            }
+            trans.Write(QUOTE);
+        }
 
-		///<summary>
-		/// Write out number as a JSON value. If the context dictates so, it will be
-		/// wrapped in quotes to output as a JSON string.
-		///</summary>
-		private void WriteJSONInteger(long num)
-		{
-			context.Write();
-			String str = num.ToString();
+        /// <summary>
+        /// Write out number as a JSON value. If the context dictates so, it will be
+        /// wrapped in quotes to output as a JSON string.
+        /// </summary>
+        private void WriteJSONInteger(long num)
+        {
+            context.Write();
+            string str = num.ToString();
+
+            bool escapeNum = context.EscapeNumbers();
+            if (escapeNum)
+                trans.Write(QUOTE);
+
+            trans.Write(utf8Encoding.GetBytes(str));
+
+            if (escapeNum)
+                trans.Write(QUOTE);
+        }
+
+        /// <summary>
+        /// Write out a double as a JSON value. If it is NaN or infinity or if the
+        /// context dictates escaping, Write out as JSON string.
+        /// </summary>
+        private void WriteJSONDouble(double num)
+        {
+            context.Write();
+            string str = num.ToString("G17", CultureInfo.InvariantCulture);
+            bool special = false;
+
+            switch (str[0])
+            {
+                case 'N': // NaN
+                case 'I': // Infinity
+                    special = true;
+                    break;
+                case '-':
+                    if (str[1] == 'I')
+                    { // -Infinity
+                        special = true;
+                    }
+                    break;
+            }
+
+            bool escapeNum = special || context.EscapeNumbers();
+
+            if (escapeNum)
+                trans.Write(QUOTE);
+
+            trans.Write(utf8Encoding.GetBytes(str));
+
+            if (escapeNum)
+                trans.Write(QUOTE);
+        }
+        /// <summary>
+        /// Write out contents of byte array b as a JSON string with base-64 encoded
+        /// data
+        /// </summary>
+        private void WriteJSONBase64(byte[] b)
+        {
+            context.Write();
+            trans.Write(QUOTE);
 
-			bool escapeNum = context.EscapeNumbers();
-			if (escapeNum)
-				trans.Write(QUOTE);
+            int len = b.Length;
+            int off = 0;
 
-			trans.Write(utf8Encoding.GetBytes(str));
+            while (len >= 3)
+            {
+                // Encode 3 bytes at a time
+                TBase64Utils.encode(b, off, 3, tempBuffer, 0);
+                trans.Write(tempBuffer, 0, 4);
+                off += 3;
+                len -= 3;
+            }
+            if (len > 0)
+            {
+                // Encode remainder
+                TBase64Utils.encode(b, off, len, tempBuffer, 0);
+                trans.Write(tempBuffer, 0, len + 1);
+            }
 
-			if (escapeNum)
-				trans.Write(QUOTE);
-		}
+            trans.Write(QUOTE);
+        }
 
-		///<summary>
-		/// Write out a double as a JSON value. If it is NaN or infinity or if the
-		/// context dictates escaping, Write out as JSON string.
-		///</summary>
-		private void WriteJSONDouble(double num)
-		{
-			context.Write();
-			String str = num.ToString(CultureInfo.InvariantCulture);
-			bool special = false;
+        private void WriteJSONObjectStart()
+        {
+            context.Write();
+            trans.Write(LBRACE);
+            PushContext(new JSONPairContext(this));
+        }
 
-			switch (str[0])
-			{
-				case 'N': // NaN
-				case 'I': // Infinity
-					special = true;
-					break;
-				case '-':
-					if (str[1] == 'I')
-					{ // -Infinity
-						special = true;
-					}
-					break;
-			}
+        private void WriteJSONObjectEnd()
+        {
+            PopContext();
+            trans.Write(RBRACE);
+        }
 
-			bool escapeNum = special || context.EscapeNumbers();
+        private void WriteJSONArrayStart()
+        {
+            context.Write();
+            trans.Write(LBRACKET);
+            PushContext(new JSONListContext(this));
+        }
 
-			if (escapeNum)
-				trans.Write(QUOTE);
+        private void WriteJSONArrayEnd()
+        {
+            PopContext();
+            trans.Write(RBRACKET);
+        }
 
-			trans.Write(utf8Encoding.GetBytes(str));
+        public override void WriteMessageBegin(TMessage message)
+        {
+            WriteJSONArrayStart();
+            WriteJSONInteger(VERSION);
 
-			if (escapeNum)
-				trans.Write(QUOTE);
-		}
-		///<summary>
-		/// Write out contents of byte array b as a JSON string with base-64 encoded
-		/// data
-		///</summary>
-		private void WriteJSONBase64(byte[] b)
-		{
-			context.Write();
-			trans.Write(QUOTE);
+            byte[] b = utf8Encoding.GetBytes(message.Name);
+            WriteJSONString(b);
 
-			int len = b.Length;
-			int off = 0;
+            WriteJSONInteger((long)message.Type);
+            WriteJSONInteger(message.SeqID);
+        }
 
-			while (len >= 3)
-			{
-				// Encode 3 bytes at a time
-				TBase64Utils.encode(b, off, 3, tempBuffer, 0);
-				trans.Write(tempBuffer, 0, 4);
-				off += 3;
-				len -= 3;
-			}
-			if (len > 0)
-			{
-				// Encode remainder
-				TBase64Utils.encode(b, off, len, tempBuffer, 0);
-				trans.Write(tempBuffer, 0, len + 1);
-			}
+        public override void WriteMessageEnd()
+        {
+            WriteJSONArrayEnd();
+        }
 
-			trans.Write(QUOTE);
-		}
+        public override void WriteStructBegin(TStruct str)
+        {
+            WriteJSONObjectStart();
+        }
 
-		private void WriteJSONObjectStart()
-		{
-			context.Write();
-			trans.Write(LBRACE);
-			PushContext(new JSONPairContext(this));
-		}
+        public override void WriteStructEnd()
+        {
+            WriteJSONObjectEnd();
+        }
 
-		private void WriteJSONObjectEnd()
-		{
-			PopContext();
-			trans.Write(RBRACE);
-		}
+        public override void WriteFieldBegin(TField field)
+        {
+            WriteJSONInteger(field.ID);
+            WriteJSONObjectStart();
+            WriteJSONString(GetTypeNameForTypeID(field.Type));
+        }
 
-		private void WriteJSONArrayStart()
-		{
-			context.Write();
-			trans.Write(LBRACKET);
-			PushContext(new JSONListContext(this));
-		}
+        public override void WriteFieldEnd()
+        {
+            WriteJSONObjectEnd();
+        }
 
-		private void WriteJSONArrayEnd()
-		{
-			PopContext();
-			trans.Write(RBRACKET);
-		}
+        public override void WriteFieldStop() { }
 
-		public override void WriteMessageBegin(TMessage message)
-		{
-			WriteJSONArrayStart();
-			WriteJSONInteger(VERSION);
+        public override void WriteMapBegin(TMap map)
+        {
+            WriteJSONArrayStart();
+            WriteJSONString(GetTypeNameForTypeID(map.KeyType));
+            WriteJSONString(GetTypeNameForTypeID(map.ValueType));
+            WriteJSONInteger(map.Count);
+            WriteJSONObjectStart();
+        }
 
-			byte[] b = utf8Encoding.GetBytes(message.Name);
-			WriteJSONString(b);
+        public override void WriteMapEnd()
+        {
+            WriteJSONObjectEnd();
+            WriteJSONArrayEnd();
+        }
 
-			WriteJSONInteger((long)message.Type);
-			WriteJSONInteger(message.SeqID);
-		}
+        public override void WriteListBegin(TList list)
+        {
+            WriteJSONArrayStart();
+            WriteJSONString(GetTypeNameForTypeID(list.ElementType));
+            WriteJSONInteger(list.Count);
+        }
 
-		public override void WriteMessageEnd()
-		{
-			WriteJSONArrayEnd();
-		}
+        public override void WriteListEnd()
+        {
+            WriteJSONArrayEnd();
+        }
 
-		public override void WriteStructBegin(TStruct str)
-		{
-			WriteJSONObjectStart();
-		}
+        public override void WriteSetBegin(TSet set)
+        {
+            WriteJSONArrayStart();
+            WriteJSONString(GetTypeNameForTypeID(set.ElementType));
+            WriteJSONInteger(set.Count);
+        }
 
-		public override void WriteStructEnd()
-		{
-			WriteJSONObjectEnd();
-		}
+        public override void WriteSetEnd()
+        {
+            WriteJSONArrayEnd();
+        }
 
-		public override void WriteFieldBegin(TField field)
-		{
-			WriteJSONInteger(field.ID);
-			WriteJSONObjectStart();
-			WriteJSONString(GetTypeNameForTypeID(field.Type));
-		}
+        public override void WriteBool(bool b)
+        {
+            WriteJSONInteger(b ? (long)1 : (long)0);
+        }
 
-		public override void WriteFieldEnd()
-		{
-			WriteJSONObjectEnd();
-		}
+        public override void WriteByte(sbyte b)
+        {
+            WriteJSONInteger((long)b);
+        }
 
-		public override void WriteFieldStop() { }
+        public override void WriteI16(short i16)
+        {
+            WriteJSONInteger((long)i16);
+        }
 
-		public override void WriteMapBegin(TMap map)
-		{
-			WriteJSONArrayStart();
-			WriteJSONString(GetTypeNameForTypeID(map.KeyType));
-			WriteJSONString(GetTypeNameForTypeID(map.ValueType));
-			WriteJSONInteger(map.Count);
-			WriteJSONObjectStart();
-		}
+        public override void WriteI32(int i32)
+        {
+            WriteJSONInteger((long)i32);
+        }
 
-		public override void WriteMapEnd()
-		{
-			WriteJSONObjectEnd();
-			WriteJSONArrayEnd();
-		}
+        public override void WriteI64(long i64)
+        {
+            WriteJSONInteger(i64);
+        }
 
-		public override void WriteListBegin(TList list)
-		{
-			WriteJSONArrayStart();
-			WriteJSONString(GetTypeNameForTypeID(list.ElementType));
-			WriteJSONInteger(list.Count);
-		}
+        public override void WriteDouble(double dub)
+        {
+            WriteJSONDouble(dub);
+        }
 
-		public override void WriteListEnd()
-		{
-			WriteJSONArrayEnd();
-		}
+        public override void WriteString(string str)
+        {
+            byte[] b = utf8Encoding.GetBytes(str);
+            WriteJSONString(b);
+        }
 
-		public override void WriteSetBegin(TSet set)
-		{
-			WriteJSONArrayStart();
-			WriteJSONString(GetTypeNameForTypeID(set.ElementType));
-			WriteJSONInteger(set.Count);
-		}
+        public override void WriteBinary(byte[] bin)
+        {
+            WriteJSONBase64(bin);
+        }
 
-		public override void WriteSetEnd()
-		{
-			WriteJSONArrayEnd();
-		}
+        /**
+         * Reading methods.
+         */
 
-		public override void WriteBool(bool b)
-		{
-			WriteJSONInteger(b ? (long)1 : (long)0);
-		}
+        /// <summary>
+        /// Read in a JSON string, unescaping as appropriate.. Skip Reading from the
+        /// context if skipContext is true.
+        /// </summary>
+        private byte[] ReadJSONString(bool skipContext)
+        {
+            MemoryStream buffer = new MemoryStream();
+            List<char> codeunits = new List<char>();
 
-		public override void WriteByte(sbyte b)
-		{
-			WriteJSONInteger((long)b);
-		}
 
-		public override void WriteI16(short i16)
-		{
-			WriteJSONInteger((long)i16);
-		}
+            if (!skipContext)
+            {
+                context.Read();
+            }
+            ReadJSONSyntaxChar(QUOTE);
+            while (true)
+            {
+                byte ch = reader.Read();
+                if (ch == QUOTE[0])
+                {
+                    break;
+                }
 
-		public override void WriteI32(int i32)
-		{
-			WriteJSONInteger((long)i32);
-		}
+                // escaped?
+                if (ch != ESCSEQ[0])
+                {
+                    buffer.Write(new byte[] { (byte)ch }, 0, 1);
+                    continue;
+                }
 
-		public override void WriteI64(long i64)
-		{
-			WriteJSONInteger(i64);
-		}
+                // distinguish between \uXXXX and \?
+                ch = reader.Read();
+                if (ch != ESCSEQ[1])  // control chars like \n
+                {
+                    int off = Array.IndexOf(ESCAPE_CHARS, (char)ch);
+                    if (off == -1)
+                    {
+                        throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                                        "Expected control char");
+                    }
+                    ch = ESCAPE_CHAR_VALS[off];
+                    buffer.Write(new byte[] { (byte)ch }, 0, 1);
+                    continue;
+                }
 
-		public override void WriteDouble(double dub)
-		{
-			WriteJSONDouble(dub);
-		}
 
-		public override void WriteString(String str)
-		{
-			byte[] b = utf8Encoding.GetBytes(str);
-			WriteJSONString(b);
-		}
+                // it's \uXXXX
+                trans.ReadAll(tempBuffer, 0, 4);
+                var wch = (short)((HexVal((byte)tempBuffer[0]) << 12) +
+                                  (HexVal((byte)tempBuffer[1]) << 8) +
+                                  (HexVal((byte)tempBuffer[2]) << 4) +
+                                   HexVal(tempBuffer[3]));
+                if (Char.IsHighSurrogate((char)wch))
+                {
+                    if (codeunits.Count > 0)
+                    {
+                        throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                                        "Expected low surrogate char");
+                    }
+                    codeunits.Add((char)wch);
+                }
+                else if (Char.IsLowSurrogate((char)wch))
+                {
+                    if (codeunits.Count == 0)
+                    {
+                        throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                                        "Expected high surrogate char");
+                    }
+                    codeunits.Add((char)wch);
+                    var tmp = utf8Encoding.GetBytes(codeunits.ToArray());
+                    buffer.Write(tmp, 0, tmp.Length);
+                    codeunits.Clear();
+                }
+                else
+                {
+                    var tmp = utf8Encoding.GetBytes(new char[] { (char)wch });
+                    buffer.Write(tmp, 0, tmp.Length);
+                }
+            }
 
-		public override void WriteBinary(byte[] bin)
-		{
-			WriteJSONBase64(bin);
-		}
 
-		/**
-		 * Reading methods.
-		 */
+            if (codeunits.Count > 0)
+            {
+                throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                                "Expected low surrogate char");
+            }
 
-		///<summary>
-		/// Read in a JSON string, unescaping as appropriate.. Skip Reading from the
-		/// context if skipContext is true.
-		///</summary>
-		private byte[] ReadJSONString(bool skipContext)
-		{
-			MemoryStream buffer = new MemoryStream();
+            return buffer.ToArray();
+        }
 
+        /// <summary>
+        /// Return true if the given byte could be a valid part of a JSON number.
+        /// </summary>
+        private bool IsJSONNumeric(byte b)
+        {
+            switch (b)
+            {
+                case (byte)'+':
+                case (byte)'-':
+                case (byte)'.':
+                case (byte)'0':
+                case (byte)'1':
+                case (byte)'2':
+                case (byte)'3':
+                case (byte)'4':
+                case (byte)'5':
+                case (byte)'6':
+                case (byte)'7':
+                case (byte)'8':
+                case (byte)'9':
+                case (byte)'E':
+                case (byte)'e':
+                    return true;
+            }
+            return false;
+        }
 
-			if (!skipContext)
-			{
-				context.Read();
-			}
-			ReadJSONSyntaxChar(QUOTE);
-			while (true)
-			{
-				byte ch = reader.Read();
-				if (ch == QUOTE[0])
-				{
-					break;
-				}
-				if (ch == ESCSEQ[0])
-				{
-					ch = reader.Read();
-					if (ch == ESCSEQ[1])
-					{
-						ReadJSONSyntaxChar(ZERO);
-						ReadJSONSyntaxChar(ZERO);
-						trans.ReadAll(tempBuffer, 0, 2);
-						ch = (byte)((HexVal((byte)tempBuffer[0]) << 4) + HexVal(tempBuffer[1]));
-					}
-					else
-					{
-						int off = Array.IndexOf(ESCAPE_CHARS, (char)ch);
-						if (off == -1)
-						{
-							throw new TProtocolException(TProtocolException.INVALID_DATA,
-														 "Expected control char");
-						}
-						ch = ESCAPE_CHAR_VALS[off];
-					}
-				}
-				buffer.Write(new byte[] { (byte)ch }, 0, 1);
-			}
-			return buffer.ToArray();
-		}
+        /// <summary>
+        /// Read in a sequence of characters that are all valid in JSON numbers. Does
+        /// not do a complete regex check to validate that this is actually a number.
+        /// </summary>
+        private string ReadJSONNumericChars()
+        {
+            StringBuilder strbld = new StringBuilder();
+            while (true)
+            {
+                byte ch = reader.Peek();
+                if (!IsJSONNumeric(ch))
+                {
+                    break;
+                }
+                strbld.Append((char)reader.Read());
+            }
+            return strbld.ToString();
+        }
 
-		///<summary>
-		/// Return true if the given byte could be a valid part of a JSON number.
-		///</summary>
-		private bool IsJSONNumeric(byte b)
-		{
-			switch (b)
-			{
-				case (byte)'+':
-				case (byte)'-':
-				case (byte)'.':
-				case (byte)'0':
-				case (byte)'1':
-				case (byte)'2':
-				case (byte)'3':
-				case (byte)'4':
-				case (byte)'5':
-				case (byte)'6':
-				case (byte)'7':
-				case (byte)'8':
-				case (byte)'9':
-				case (byte)'E':
-				case (byte)'e':
-					return true;
-			}
-			return false;
-		}
+        /// <summary>
+        /// Read in a JSON number. If the context dictates, Read in enclosing quotes.
+        /// </summary>
+        private long ReadJSONInteger()
+        {
+            context.Read();
+            if (context.EscapeNumbers())
+            {
+                ReadJSONSyntaxChar(QUOTE);
+            }
 
-		///<summary>
-		/// Read in a sequence of characters that are all valid in JSON numbers. Does
-		/// not do a complete regex check to validate that this is actually a number.
-		////</summary>
-		private String ReadJSONNumericChars()
-		{
-			StringBuilder strbld = new StringBuilder();
-			while (true)
-			{
-				byte ch = reader.Peek();
-				if (!IsJSONNumeric(ch))
-				{
-					break;
-				}
-				strbld.Append((char)reader.Read());
-			}
-			return strbld.ToString();
-		}
+            string str = ReadJSONNumericChars();
+            if (context.EscapeNumbers())
+            {
+                ReadJSONSyntaxChar(QUOTE);
+            }
 
-		///<summary>
-		/// Read in a JSON number. If the context dictates, Read in enclosing quotes.
-		///</summary>
-		private long ReadJSONInteger()
-		{
-			context.Read();
-			if (context.EscapeNumbers())
-			{
-				ReadJSONSyntaxChar(QUOTE);
-			}
-			String str = ReadJSONNumericChars();
-			if (context.EscapeNumbers())
-			{
-				ReadJSONSyntaxChar(QUOTE);
-			}
-			try
-			{
-				return Int64.Parse(str);
-			}
-			catch (FormatException)
-			{
-				throw new TProtocolException(TProtocolException.INVALID_DATA,
-											 "Bad data encounted in numeric data");
-			}
-		}
+            try
+            {
+                return Int64.Parse(str);
+            }
+            catch (FormatException fex)
+            {
+                throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                             "Bad data encounted in numeric data", fex);
+            }
+        }
 
-		///<summary>
-		/// Read in a JSON double value. Throw if the value is not wrapped in quotes
-		/// when expected or if wrapped in quotes when not expected.
-		///</summary>
-		private double ReadJSONDouble()
-		{
-			context.Read();
-			if (reader.Peek() == QUOTE[0])
-			{
-				byte[] arr = ReadJSONString(true);
-				double dub = Double.Parse(utf8Encoding.GetString(arr,0,arr.Length), CultureInfo.InvariantCulture);
+        /// <summary>
+        /// Read in a JSON double value. Throw if the value is not wrapped in quotes
+        /// when expected or if wrapped in quotes when not expected.
+        /// </summary>
+        private double ReadJSONDouble()
+        {
+            context.Read();
+            if (reader.Peek() == QUOTE[0])
+            {
+                byte[] arr = ReadJSONString(true);
+                double dub = Double.Parse(utf8Encoding.GetString(arr, 0, arr.Length), CultureInfo.InvariantCulture);
 
-				if (!context.EscapeNumbers() && !Double.IsNaN(dub) &&
-					!Double.IsInfinity(dub))
-				{
-					// Throw exception -- we should not be in a string in this case
-					throw new TProtocolException(TProtocolException.INVALID_DATA,
-												 "Numeric data unexpectedly quoted");
-				}
-				return dub;
-			}
-			else
-			{
-				if (context.EscapeNumbers())
-				{
-					// This will throw - we should have had a quote if escapeNum == true
-					ReadJSONSyntaxChar(QUOTE);
-				}
-				try
-				{
-					return Double.Parse(ReadJSONNumericChars());
-				}
-				catch (FormatException)
-				{
-					throw new TProtocolException(TProtocolException.INVALID_DATA,
-												 "Bad data encounted in numeric data");
-				}
-			}
-		}
+                if (!context.EscapeNumbers() && !Double.IsNaN(dub) && !Double.IsInfinity(dub))
+                {
+                    // Throw exception -- we should not be in a string in this case
+                    throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                                 "Numeric data unexpectedly quoted");
+                }
+                return dub;
+            }
+            else
+            {
+                if (context.EscapeNumbers())
+                {
+                    // This will throw - we should have had a quote if escapeNum == true
+                    ReadJSONSyntaxChar(QUOTE);
+                }
+                try
+                {
+                    return Double.Parse(ReadJSONNumericChars(), CultureInfo.InvariantCulture);
+                }
+                catch (FormatException fex)
+                {
+                    throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                                 "Bad data encounted in numeric data", fex);
+                }
+            }
+        }
 
-		//<summary>
-		/// Read in a JSON string containing base-64 encoded data and decode it.
-		///</summary>
-		private byte[] ReadJSONBase64()
-		{
-			byte[] b = ReadJSONString(false);
-			int len = b.Length;
-			int off = 0;
-			int size = 0;
-			while (len >= 4)
-			{
-				// Decode 4 bytes at a time
-				TBase64Utils.decode(b, off, 4, b, size); // NB: decoded in place
-				off += 4;
-				len -= 4;
-				size += 3;
-			}
-			// Don't decode if we hit the end or got a single leftover byte (invalid
-			// base64 but legal for skip of regular string type)
-			if (len > 1)
-			{
-				// Decode remainder
-				TBase64Utils.decode(b, off, len, b, size); // NB: decoded in place
-				size += len - 1;
-			}
-			// Sadly we must copy the byte[] (any way around this?)
-			byte[] result = new byte[size];
-			Array.Copy(b, 0, result, 0, size);
-			return result;
-		}
+        /// <summary>
+        /// Read in a JSON string containing base-64 encoded data and decode it.
+        /// </summary>
+        private byte[] ReadJSONBase64()
+        {
+            byte[] b = ReadJSONString(false);
+            int len = b.Length;
+            int off = 0;
+            int size = 0;
+            // reduce len to ignore fill bytes
+            while ((len > 0) && (b[len - 1] == '='))
+            {
+                --len;
+            }
+            // read & decode full byte triplets = 4 source bytes
+            while (len > 4)
+            {
+                // Decode 4 bytes at a time
+                TBase64Utils.decode(b, off, 4, b, size); // NB: decoded in place
+                off += 4;
+                len -= 4;
+                size += 3;
+            }
+            // Don't decode if we hit the end or got a single leftover byte (invalid
+            // base64 but legal for skip of regular string type)
+            if (len > 1)
+            {
+                // Decode remainder
+                TBase64Utils.decode(b, off, len, b, size); // NB: decoded in place
+                size += len - 1;
+            }
+            // Sadly we must copy the byte[] (any way around this?)
+            byte[] result = new byte[size];
+            Array.Copy(b, 0, result, 0, size);
+            return result;
+        }
 
-		private void ReadJSONObjectStart()
-		{
-			context.Read();
-			ReadJSONSyntaxChar(LBRACE);
-			PushContext(new JSONPairContext(this));
-		}
+        private void ReadJSONObjectStart()
+        {
+            context.Read();
+            ReadJSONSyntaxChar(LBRACE);
+            PushContext(new JSONPairContext(this));
+        }
 
-		private void ReadJSONObjectEnd()
-		{
-			ReadJSONSyntaxChar(RBRACE);
-			PopContext();
-		}
+        private void ReadJSONObjectEnd()
+        {
+            ReadJSONSyntaxChar(RBRACE);
+            PopContext();
+        }
 
-		private void ReadJSONArrayStart()
-		{
-			context.Read();
-			ReadJSONSyntaxChar(LBRACKET);
-			PushContext(new JSONListContext(this));
-		}
+        private void ReadJSONArrayStart()
+        {
+            context.Read();
+            ReadJSONSyntaxChar(LBRACKET);
+            PushContext(new JSONListContext(this));
+        }
 
-		private void ReadJSONArrayEnd()
-		{
-			ReadJSONSyntaxChar(RBRACKET);
-			PopContext();
-		}
+        private void ReadJSONArrayEnd()
+        {
+            ReadJSONSyntaxChar(RBRACKET);
+            PopContext();
+        }
 
-		public override TMessage ReadMessageBegin()
-		{
-			TMessage message = new TMessage();
-			ReadJSONArrayStart();
-			if (ReadJSONInteger() != VERSION)
-			{
-				throw new TProtocolException(TProtocolException.BAD_VERSION,
-											 "Message contained bad version.");
-			}
+        public override TMessage ReadMessageBegin()
+        {
+            TMessage message = new TMessage();
+            ReadJSONArrayStart();
+            if (ReadJSONInteger() != VERSION)
+            {
+                throw new TProtocolException(TProtocolException.BAD_VERSION,
+                                             "Message contained bad version.");
+            }
 
             var buf = ReadJSONString(false);
-			message.Name = utf8Encoding.GetString(buf,0,buf.Length);
-			message.Type = (TMessageType)ReadJSONInteger();
-			message.SeqID = (int)ReadJSONInteger();
-			return message;
-		}
+            message.Name = utf8Encoding.GetString(buf, 0, buf.Length);
+            message.Type = (TMessageType)ReadJSONInteger();
+            message.SeqID = (int)ReadJSONInteger();
+            return message;
+        }
 
-		public override void ReadMessageEnd()
-		{
-			ReadJSONArrayEnd();
-		}
+        public override void ReadMessageEnd()
+        {
+            ReadJSONArrayEnd();
+        }
 
-		public override TStruct ReadStructBegin()
-		{
-			ReadJSONObjectStart();
-			return new TStruct();
-		}
+        public override TStruct ReadStructBegin()
+        {
+            ReadJSONObjectStart();
+            return new TStruct();
+        }
 
-		public override void ReadStructEnd()
-		{
-			ReadJSONObjectEnd();
-		}
+        public override void ReadStructEnd()
+        {
+            ReadJSONObjectEnd();
+        }
 
-		public override TField ReadFieldBegin()
-		{
-			TField field = new TField();
-			byte ch = reader.Peek();
-			if (ch == RBRACE[0])
-			{
-				field.Type = TType.Stop;
-			}
-			else
-			{
-				field.ID = (short)ReadJSONInteger();
-				ReadJSONObjectStart();
-				field.Type = GetTypeIDForTypeName(ReadJSONString(false));
-			}
-			return field;
-		}
+        public override TField ReadFieldBegin()
+        {
+            TField field = new TField();
+            byte ch = reader.Peek();
+            if (ch == RBRACE[0])
+            {
+                field.Type = TType.Stop;
+            }
+            else
+            {
+                field.ID = (short)ReadJSONInteger();
+                ReadJSONObjectStart();
+                field.Type = GetTypeIDForTypeName(ReadJSONString(false));
+            }
+            return field;
+        }
 
-		public override void ReadFieldEnd()
-		{
-			ReadJSONObjectEnd();
-		}
+        public override void ReadFieldEnd()
+        {
+            ReadJSONObjectEnd();
+        }
 
-		public override TMap ReadMapBegin()
-		{
-			TMap map = new TMap();
-			ReadJSONArrayStart();
-			map.KeyType = GetTypeIDForTypeName(ReadJSONString(false));
-			map.ValueType = GetTypeIDForTypeName(ReadJSONString(false));
-			map.Count = (int)ReadJSONInteger();
-			ReadJSONObjectStart();
-			return map;
-		}
+        public override TMap ReadMapBegin()
+        {
+            TMap map = new TMap();
+            ReadJSONArrayStart();
+            map.KeyType = GetTypeIDForTypeName(ReadJSONString(false));
+            map.ValueType = GetTypeIDForTypeName(ReadJSONString(false));
+            map.Count = (int)ReadJSONInteger();
+            ReadJSONObjectStart();
+            return map;
+        }
 
-		public override void ReadMapEnd()
-		{
-			ReadJSONObjectEnd();
-			ReadJSONArrayEnd();
-		}
+        public override void ReadMapEnd()
+        {
+            ReadJSONObjectEnd();
+            ReadJSONArrayEnd();
+        }
 
-		public override TList ReadListBegin()
-		{
-			TList list = new TList();
-			ReadJSONArrayStart();
-			list.ElementType = GetTypeIDForTypeName(ReadJSONString(false));
-			list.Count = (int)ReadJSONInteger();
-			return list;
-		}
+        public override TList ReadListBegin()
+        {
+            TList list = new TList();
+            ReadJSONArrayStart();
+            list.ElementType = GetTypeIDForTypeName(ReadJSONString(false));
+            list.Count = (int)ReadJSONInteger();
+            return list;
+        }
 
-		public override void ReadListEnd()
-		{
-			ReadJSONArrayEnd();
-		}
+        public override void ReadListEnd()
+        {
+            ReadJSONArrayEnd();
+        }
 
-		public override TSet ReadSetBegin()
-		{
-			TSet set = new TSet();
-			ReadJSONArrayStart();
-			set.ElementType = GetTypeIDForTypeName(ReadJSONString(false));
-			set.Count = (int)ReadJSONInteger();
-			return set;
-		}
+        public override TSet ReadSetBegin()
+        {
+            TSet set = new TSet();
+            ReadJSONArrayStart();
+            set.ElementType = GetTypeIDForTypeName(ReadJSONString(false));
+            set.Count = (int)ReadJSONInteger();
+            return set;
+        }
 
-		public override void ReadSetEnd()
-		{
-			ReadJSONArrayEnd();
-		}
+        public override void ReadSetEnd()
+        {
+            ReadJSONArrayEnd();
+        }
 
-		public override bool ReadBool()
-		{
-			return (ReadJSONInteger() == 0 ? false : true);
-		}
+        public override bool ReadBool()
+        {
+            return (ReadJSONInteger() == 0 ? false : true);
+        }
 
-		public override sbyte ReadByte()
-		{
-			return (sbyte)ReadJSONInteger();
-		}
+        public override sbyte ReadByte()
+        {
+            return (sbyte)ReadJSONInteger();
+        }
 
-		public override short ReadI16()
-		{
-			return (short)ReadJSONInteger();
-		}
+        public override short ReadI16()
+        {
+            return (short)ReadJSONInteger();
+        }
 
-		public override int ReadI32()
-		{
-			return (int)ReadJSONInteger();
-		}
+        public override int ReadI32()
+        {
+            return (int)ReadJSONInteger();
+        }
 
-		public override long ReadI64()
-		{
-			return (long)ReadJSONInteger();
-		}
+        public override long ReadI64()
+        {
+            return (long)ReadJSONInteger();
+        }
 
-		public override double ReadDouble()
-		{
-			return ReadJSONDouble();
-		}
+        public override double ReadDouble()
+        {
+            return ReadJSONDouble();
+        }
 
-		public override String ReadString()
-		{
+        public override string ReadString()
+        {
             var buf = ReadJSONString(false);
-			return utf8Encoding.GetString(buf,0,buf.Length);
-		}
+            return utf8Encoding.GetString(buf, 0, buf.Length);
+        }
 
-		public override byte[] ReadBinary()
-		{
-			return ReadJSONBase64();
-		}
+        public override byte[] ReadBinary()
+        {
+            return ReadJSONBase64();
+        }
 
-	}
+    }
 }
diff --git a/lib/csharp/src/Protocol/TList.cs b/lib/csharp/src/Protocol/TList.cs
index a651eb1..0c8f214 100644
--- a/lib/csharp/src/Protocol/TList.cs
+++ b/lib/csharp/src/Protocol/TList.cs
@@ -27,28 +27,28 @@
 
 namespace Thrift.Protocol
 {
-	public struct TList
-	{
-		private TType elementType;
-		private int count;
+    public struct TList
+    {
+        private TType elementType;
+        private int count;
 
-		public TList(TType elementType, int count)
-			:this()
-		{
-			this.elementType = elementType;
-			this.count = count;
-		}
+        public TList(TType elementType, int count)
+            :this()
+        {
+            this.elementType = elementType;
+            this.count = count;
+        }
 
-		public TType ElementType
-		{
-			get { return elementType; }
-			set { elementType = value; }
-		}
+        public TType ElementType
+        {
+            get { return elementType; }
+            set { elementType = value; }
+        }
 
-		public int Count
-		{
-			get { return count; }
-			set { count = value; }
-		}
-	}
+        public int Count
+        {
+            get { return count; }
+            set { count = value; }
+        }
+    }
 }
diff --git a/lib/csharp/src/Protocol/TMap.cs b/lib/csharp/src/Protocol/TMap.cs
index 5c8d650..aba9d3a 100644
--- a/lib/csharp/src/Protocol/TMap.cs
+++ b/lib/csharp/src/Protocol/TMap.cs
@@ -27,36 +27,36 @@
 
 namespace Thrift.Protocol
 {
-	public struct TMap
-	{
-		private TType keyType;
-		private TType valueType;
-		private int count;
+    public struct TMap
+    {
+        private TType keyType;
+        private TType valueType;
+        private int count;
 
-		public TMap(TType keyType, TType valueType, int count)
-			:this()
-		{
-			this.keyType = keyType;
-			this.valueType = valueType;
-			this.count = count;
-		}
+        public TMap(TType keyType, TType valueType, int count)
+            :this()
+        {
+            this.keyType = keyType;
+            this.valueType = valueType;
+            this.count = count;
+        }
 
-		public TType KeyType
-		{
-			get { return keyType; }
-			set { keyType = value; }
-		}
+        public TType KeyType
+        {
+            get { return keyType; }
+            set { keyType = value; }
+        }
 
-		public TType ValueType
-		{
-			get { return valueType; }
-			set { valueType = value; }
-		}
+        public TType ValueType
+        {
+            get { return valueType; }
+            set { valueType = value; }
+        }
 
-		public int Count
-		{
-			get { return count; }
-			set { count = value; }
-		}
-	}
+        public int Count
+        {
+            get { return count; }
+            set { count = value; }
+        }
+    }
 }
diff --git a/lib/csharp/src/Protocol/TMessage.cs b/lib/csharp/src/Protocol/TMessage.cs
index 8e96da5..348263c 100644
--- a/lib/csharp/src/Protocol/TMessage.cs
+++ b/lib/csharp/src/Protocol/TMessage.cs
@@ -27,36 +27,36 @@
 
 namespace Thrift.Protocol
 {
-	public struct TMessage
-	{
-		private string name;
-		private TMessageType type;
-		private int seqID;
+    public struct TMessage
+    {
+        private string name;
+        private TMessageType type;
+        private int seqID;
 
-		public TMessage(string name, TMessageType type, int seqid)
-			:this()
-		{
-			this.name = name;
-			this.type = type;
-			this.seqID = seqid;
-		}
+        public TMessage(string name, TMessageType type, int seqid)
+            :this()
+        {
+            this.name = name;
+            this.type = type;
+            this.seqID = seqid;
+        }
 
-		public string Name
-		{
-			get { return name; }
-			set { name = value; }
-		}
+        public string Name
+        {
+            get { return name; }
+            set { name = value; }
+        }
 
-		public TMessageType Type
-		{
-			get { return type; }
-			set { type = value; }
-		}
+        public TMessageType Type
+        {
+            get { return type; }
+            set { type = value; }
+        }
 
-		public int SeqID
-		{
-			get { return seqID; }
-			set { seqID = value; }
-		}
-	}
+        public int SeqID
+        {
+            get { return seqID; }
+            set { seqID = value; }
+        }
+    }
 }
diff --git a/lib/csharp/src/Protocol/TMessageType.cs b/lib/csharp/src/Protocol/TMessageType.cs
index ab07cf6..c7091fe 100644
--- a/lib/csharp/src/Protocol/TMessageType.cs
+++ b/lib/csharp/src/Protocol/TMessageType.cs
@@ -21,11 +21,11 @@
 
 namespace Thrift.Protocol
 {
-	public enum TMessageType
-	{
-		Call = 1,
-		Reply = 2,
-		Exception = 3,
-		Oneway = 4
-	}
+    public enum TMessageType
+    {
+        Call = 1,
+        Reply = 2,
+        Exception = 3,
+        Oneway = 4
+    }
 }
diff --git a/lib/csharp/src/Protocol/TMultiplexedProcessor.cs b/lib/csharp/src/Protocol/TMultiplexedProcessor.cs
index 4ce8d62..aa91c52 100644
--- a/lib/csharp/src/Protocol/TMultiplexedProcessor.cs
+++ b/lib/csharp/src/Protocol/TMultiplexedProcessor.cs
@@ -27,76 +27,79 @@
 using System.Collections.Generic;
 using System.IO;
 
-namespace Thrift.Protocol 
+namespace Thrift.Protocol
 {
-
-    /**
-     * TMultiplexedProcessor is a TProcessor allowing a single TServer to provide multiple services.
-     * To do so, you instantiate the processor and then register additional processors with it, 
-     * as shown in the following example:
-     *
-     *     TMultiplexedProcessor processor = new TMultiplexedProcessor();
-     *
-     *     processor.registerProcessor(
-     *         "Calculator",
-     *         new Calculator.Processor(new CalculatorHandler()));
-     *
-     *     processor.registerProcessor(
-     *         "WeatherReport",
-     *         new WeatherReport.Processor(new WeatherReportHandler()));
-     *
-     *     TServerTransport t = new TServerSocket(9090);
-     *     TSimpleServer server = new TSimpleServer(processor, t);
-     *
-     *     server.serve();
-     */
-    public class TMultiplexedProcessor : TProcessor 
+    /// <summary>
+    /// <see cref="TMultiplexedProcessor"/> is a <see cref="TProcessor"/> allowing a single <see cref="Thrift.Server.TServer"/>
+    /// to provide multiple services.
+    /// <para/>
+    /// To do so, you instantiate the processor and then register additional processors with it,
+    /// as shown in the following example:
+    /// <para/>
+    /// <code>
+    ///     TMultiplexedProcessor processor = new TMultiplexedProcessor();
+    ///
+    ///     processor.registerProcessor(
+    ///         "Calculator",
+    ///         new Calculator.Processor(new CalculatorHandler()));
+    ///
+    ///     processor.registerProcessor(
+    ///         "WeatherReport",
+    ///         new WeatherReport.Processor(new WeatherReportHandler()));
+    ///
+    ///     TServerTransport t = new TServerSocket(9090);
+    ///     TSimpleServer server = new TSimpleServer(processor, t);
+    ///
+    ///     server.serve();
+    /// </code>
+    /// </summary>
+    public class TMultiplexedProcessor : TProcessor
     {
-        private Dictionary<String,TProcessor> ServiceProcessorMap = new Dictionary<String,TProcessor>();
+        private Dictionary<string, TProcessor> ServiceProcessorMap = new Dictionary<string, TProcessor>();
 
-        /**
-         * 'Register' a service with this TMultiplexedProcessor. This allows us to broker 
-         * requests to individual services by using the service name to select them at request time.
-         *
-         * Args: 
-         * - serviceName    Name of a service, has to be identical to the name
-         *                  declared in the Thrift IDL, e.g. "WeatherReport".
-         * - processor      Implementation of a service, ususally referred to as "handlers", 
-         *                  e.g. WeatherReportHandler implementing WeatherReport.Iface.
-         */
-        public void RegisterProcessor(String serviceName, TProcessor processor) 
+        /// <summary>
+        /// 'Register' a service with this TMultiplexedProcessor. This allows us to broker
+        /// requests to individual services by using the service name to select them at request time.
+        ///
+        /// Args:
+        /// - serviceName    Name of a service, has to be identical to the name
+        ///                  declared in the Thrift IDL, e.g. "WeatherReport".
+        /// - processor      Implementation of a service, usually referred to as "handlers",
+        ///                  e.g. WeatherReportHandler implementing WeatherReport.Iface.
+        /// </summary>
+        public void RegisterProcessor(string serviceName, TProcessor processor)
         {
             ServiceProcessorMap.Add(serviceName, processor);
         }
 
-        
-        private void Fail( TProtocol oprot, TMessage message, TApplicationException.ExceptionType extype, string etxt)
+
+        private void Fail(TProtocol oprot, TMessage message, TApplicationException.ExceptionType extype, string etxt)
         {
-            TApplicationException appex = new TApplicationException( extype, etxt);
+            TApplicationException appex = new TApplicationException(extype, etxt);
 
             TMessage newMessage = new TMessage(message.Name, TMessageType.Exception, message.SeqID);
 
             oprot.WriteMessageBegin(newMessage);
-            appex.Write( oprot);
+            appex.Write(oprot);
             oprot.WriteMessageEnd();
             oprot.Transport.Flush();
         }
-            
-        
-        /**
-         * This implementation of process performs the following steps:
-         *
-         * - Read the beginning of the message.
-         * - Extract the service name from the message.
-         * - Using the service name to locate the appropriate processor.
-         * - Dispatch to the processor, with a decorated instance of TProtocol
-         *    that allows readMessageBegin() to return the original TMessage.
-         *  
-         * Throws an exception if 
-         * - the message type is not CALL or ONEWAY, 
-         * - the service name was not found in the message, or 
-         * - the service name has not been RegisterProcessor()ed.  
-         */
+
+
+        /// <summary>
+        /// This implementation of process performs the following steps:
+        ///
+        /// - Read the beginning of the message.
+        /// - Extract the service name from the message.
+        /// - Using the service name to locate the appropriate processor.
+        /// - Dispatch to the processor, with a decorated instance of TProtocol
+        ///    that allows readMessageBegin() to return the original TMessage.
+        /// <para/>
+        /// Throws an exception if
+        /// - the message type is not CALL or ONEWAY,
+        /// - the service name was not found in the message, or
+        /// - the service name has not been RegisterProcessor()ed.
+        /// </summary>
         public bool Process(TProtocol iprot, TProtocol oprot)
         {
             /*  Use the actual underlying protocol (e.g. TBinaryProtocol) to read the
@@ -155,22 +158,22 @@
 
         }
 
-        /**
-         *  Our goal was to work with any protocol.  In order to do that, we needed
-         *  to allow them to call readMessageBegin() and get a TMessage in exactly
-         *  the standard format, without the service name prepended to TMessage.name.
-         */
-        private class StoredMessageProtocol : TProtocolDecorator 
+        /// <summary>
+        ///  Our goal was to work with any protocol.  In order to do that, we needed
+        ///  to allow them to call readMessageBegin() and get a TMessage in exactly
+        ///  the standard format, without the service name prepended to TMessage.name.
+        /// </summary>
+        private class StoredMessageProtocol : TProtocolDecorator
         {
             TMessage MsgBegin;
 
-            public StoredMessageProtocol(TProtocol protocol, TMessage messageBegin) 
-                :base(protocol)
+            public StoredMessageProtocol(TProtocol protocol, TMessage messageBegin)
+                : base(protocol)
             {
                 this.MsgBegin = messageBegin;
             }
 
-            public override TMessage ReadMessageBegin()  
+            public override TMessage ReadMessageBegin()
             {
                 return MsgBegin;
             }
diff --git a/lib/csharp/src/Protocol/TMultiplexedProtocol.cs b/lib/csharp/src/Protocol/TMultiplexedProtocol.cs
index ccd7fcf..1bd420f 100644
--- a/lib/csharp/src/Protocol/TMultiplexedProtocol.cs
+++ b/lib/csharp/src/Protocol/TMultiplexedProtocol.cs
@@ -26,66 +26,65 @@
 using Thrift.Transport;
 using System.Collections.Generic;
 
-namespace Thrift.Protocol 
+namespace Thrift.Protocol
 {
 
-    /**
-     * TMultiplexedProtocol is a protocol-independent concrete decorator that allows a Thrift 
-     * client to communicate with a multiplexing Thrift server, by prepending the service name 
-     * to the function name during function calls.
-     *
-     * NOTE: THIS IS NOT TO BE USED BY SERVERS.  
-     * On the server, use TMultiplexedProcessor to handle requests from a multiplexing client.
-     *
-     * This example uses a single socket transport to invoke two services:
-     *
-     *     TSocket transport = new TSocket("localhost", 9090);
-     *     transport.open();
-     *     
-     *     TBinaryProtocol protocol = new TBinaryProtocol(transport);
-     *
-     *     TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "Calculator");
-     *     Calculator.Client service = new Calculator.Client(mp);
-     *
-     *     TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, "WeatherReport");
-     *     WeatherReport.Client service2 = new WeatherReport.Client(mp2);
-     *
-     *     System.out.println(service.add(2,2));
-     *     System.out.println(service2.getTemperature());
-     *
-     */
-    public class TMultiplexedProtocol : TProtocolDecorator 
+    /// <summary>
+    /// TMultiplexedProtocol is a protocol-independent concrete decorator that allows a Thrift
+    /// client to communicate with a multiplexing Thrift server, by prepending the service name
+    /// to the function name during function calls.
+    /// <para/>
+    /// NOTE: THIS IS NOT TO BE USED BY SERVERS.
+    /// On the server, use TMultiplexedProcessor to handle requests from a multiplexing client.
+    /// <para/>
+    /// This example uses a single socket transport to invoke two services:
+    /// <code>
+    ///     TSocket transport = new TSocket("localhost", 9090);
+    ///     transport.open();
+    ///
+    ///     TBinaryProtocol protocol = new TBinaryProtocol(transport);
+    ///
+    ///     TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "Calculator");
+    ///     Calculator.Client service = new Calculator.Client(mp);
+    ///
+    ///     TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, "WeatherReport");
+    ///     WeatherReport.Client service2 = new WeatherReport.Client(mp2);
+    ///
+    ///     System.out.println(service.add(2,2));
+    ///     System.out.println(service2.getTemperature());
+    /// </code>
+    /// </summary>
+    public class TMultiplexedProtocol : TProtocolDecorator
     {
 
-        /** Used to delimit the service name from the function name */
-        public static String SEPARATOR = ":";
+        /// <summary>
+        /// Used to delimit the service name from the function name.
+        /// </summary>
+        public static string SEPARATOR = ":";
 
-        private String ServiceName;
+        private string ServiceName;
 
-        /**
-         * Wrap the specified protocol, allowing it to be used to communicate with a
-         * multiplexing server.  The <code>serviceName</code> is required as it is
-         * prepended to the message header so that the multiplexing server can broker
-         * the function call to the proper service.
-         *
-         * Args:
-         *  protocol        Your communication protocol of choice, e.g. TBinaryProtocol
-         *  serviceName     The service name of the service communicating via this protocol.
-         */
-        public TMultiplexedProtocol(TProtocol protocol, String serviceName) 
+        /// <summary>
+        /// Wrap the specified protocol, allowing it to be used to communicate with a
+        /// multiplexing server.  The <paramref name="serviceName"/> is required as it is
+        /// prepended to the message header so that the multiplexing server can broker
+        /// the function call to the proper service.
+        /// </summary>
+        /// <param name="protocol">Your communication protocol of choice, e.g. <see cref="TBinaryProtocol"/>.</param>
+        /// <param name="serviceName">The service name of the service communicating via this protocol.</param>
+        public TMultiplexedProtocol(TProtocol protocol, string serviceName)
             : base(protocol)
         {
             ServiceName = serviceName;
         }
 
-        /**
-         * Prepends the service name to the function name, separated by TMultiplexedProtocol.SEPARATOR.
-         * Args:
-         *   tMessage     The original message.
-         */
-        public override void WriteMessageBegin(TMessage tMessage) 
+        /// <summary>
+        /// Prepends the service name to the function name, separated by TMultiplexedProtocol.SEPARATOR.
+        /// </summary>
+        /// <param name="tMessage">The original message.</param>
+        public override void WriteMessageBegin(TMessage tMessage)
         {
-            switch(tMessage.Type)
+            switch (tMessage.Type)
             {
                 case TMessageType.Call:
                 case TMessageType.Oneway:
@@ -101,5 +100,4 @@
             }
         }
     }
-
 }
diff --git a/lib/csharp/src/Protocol/TProtocol.cs b/lib/csharp/src/Protocol/TProtocol.cs
index 70920d4..dd7a6e0 100644
--- a/lib/csharp/src/Protocol/TProtocol.cs
+++ b/lib/csharp/src/Protocol/TProtocol.cs
@@ -27,19 +27,44 @@
 
 namespace Thrift.Protocol
 {
-	public abstract class TProtocol : IDisposable
-	{
-		protected TTransport trans;
+    public abstract class TProtocol : IDisposable
+    {
+        private const int DEFAULT_RECURSION_DEPTH = 64;
 
-		protected TProtocol(TTransport trans)
-		{
-			this.trans = trans;
-		}
+        protected TTransport trans;
+        protected int recursionLimit;
+        protected int recursionDepth;
 
-		public TTransport Transport
-		{
-			get { return trans; }
-		}
+        protected TProtocol(TTransport trans)
+        {
+            this.trans = trans;
+            this.recursionLimit = DEFAULT_RECURSION_DEPTH;
+            this.recursionDepth = 0;
+        }
+
+        public TTransport Transport
+        {
+            get { return trans; }
+        }
+
+        public int RecursionLimit
+        {
+            get { return recursionLimit; }
+            set { recursionLimit = value; }
+        }
+
+        public void IncrementRecursionDepth()
+        {
+            if (recursionDepth < recursionLimit)
+                ++recursionDepth;
+            else
+                throw new TProtocolException(TProtocolException.DEPTH_LIMIT, "Depth limit exceeded");
+        }
+
+        public void DecrementRecursionDepth()
+        {
+            --recursionDepth;
+        }
 
         #region " IDisposable Support "
         private bool _IsDisposed;
@@ -64,52 +89,54 @@
         }
         #endregion
 
-		public abstract void WriteMessageBegin(TMessage message);
-		public abstract void WriteMessageEnd();
-		public abstract void WriteStructBegin(TStruct struc);
-		public abstract void WriteStructEnd();
-		public abstract void WriteFieldBegin(TField field);
-		public abstract void WriteFieldEnd();
-		public abstract void WriteFieldStop();
-		public abstract void WriteMapBegin(TMap map);
-		public abstract void WriteMapEnd();
-		public abstract void WriteListBegin(TList list);
-		public abstract void WriteListEnd();
-		public abstract void WriteSetBegin(TSet set);
-		public abstract void WriteSetEnd();
-		public abstract void WriteBool(bool b);
-		public abstract void WriteByte(sbyte b);
-		public abstract void WriteI16(short i16);
-		public abstract void WriteI32(int i32);
-		public abstract void WriteI64(long i64);
-		public abstract void WriteDouble(double d);
-		public virtual void WriteString(string s) {
-			WriteBinary(Encoding.UTF8.GetBytes(s));
-		}
-		public abstract void WriteBinary(byte[] b);
+        public abstract void WriteMessageBegin(TMessage message);
+        public abstract void WriteMessageEnd();
+        public abstract void WriteStructBegin(TStruct struc);
+        public abstract void WriteStructEnd();
+        public abstract void WriteFieldBegin(TField field);
+        public abstract void WriteFieldEnd();
+        public abstract void WriteFieldStop();
+        public abstract void WriteMapBegin(TMap map);
+        public abstract void WriteMapEnd();
+        public abstract void WriteListBegin(TList list);
+        public abstract void WriteListEnd();
+        public abstract void WriteSetBegin(TSet set);
+        public abstract void WriteSetEnd();
+        public abstract void WriteBool(bool b);
+        public abstract void WriteByte(sbyte b);
+        public abstract void WriteI16(short i16);
+        public abstract void WriteI32(int i32);
+        public abstract void WriteI64(long i64);
+        public abstract void WriteDouble(double d);
+        public virtual void WriteString(string s)
+        {
+            WriteBinary(Encoding.UTF8.GetBytes(s));
+        }
+        public abstract void WriteBinary(byte[] b);
 
-		public abstract TMessage ReadMessageBegin();
-		public abstract void ReadMessageEnd();
-		public abstract TStruct ReadStructBegin();
-		public abstract void ReadStructEnd();
-		public abstract TField ReadFieldBegin();
-		public abstract void ReadFieldEnd();
-		public abstract TMap ReadMapBegin();
-		public abstract void ReadMapEnd();
-		public abstract TList ReadListBegin();
-		public abstract void ReadListEnd();
-		public abstract TSet ReadSetBegin();
-		public abstract void ReadSetEnd();
-		public abstract bool ReadBool();
-		public abstract sbyte ReadByte();
-		public abstract short ReadI16();
-		public abstract int ReadI32();
-		public abstract long ReadI64();
-		public abstract double ReadDouble();
-		public virtual string ReadString() {
+        public abstract TMessage ReadMessageBegin();
+        public abstract void ReadMessageEnd();
+        public abstract TStruct ReadStructBegin();
+        public abstract void ReadStructEnd();
+        public abstract TField ReadFieldBegin();
+        public abstract void ReadFieldEnd();
+        public abstract TMap ReadMapBegin();
+        public abstract void ReadMapEnd();
+        public abstract TList ReadListBegin();
+        public abstract void ReadListEnd();
+        public abstract TSet ReadSetBegin();
+        public abstract void ReadSetEnd();
+        public abstract bool ReadBool();
+        public abstract sbyte ReadByte();
+        public abstract short ReadI16();
+        public abstract int ReadI32();
+        public abstract long ReadI64();
+        public abstract double ReadDouble();
+        public virtual string ReadString()
+        {
             var buf = ReadBinary();
             return Encoding.UTF8.GetString(buf, 0, buf.Length);
         }
-		public abstract byte[] ReadBinary();
-	}
+        public abstract byte[] ReadBinary();
+    }
 }
diff --git a/lib/csharp/src/Protocol/TProtocolDecorator.cs b/lib/csharp/src/Protocol/TProtocolDecorator.cs
index e1977f5..8600002 100644
--- a/lib/csharp/src/Protocol/TProtocolDecorator.cs
+++ b/lib/csharp/src/Protocol/TProtocolDecorator.cs
@@ -1,262 +1,261 @@
-/**

- * 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.

- *

- * Contains some contributions under the Thrift Software License.

- * Please see doc/old-thrift-license.txt in the Thrift distribution for

- * details.

- */

-

-using System;

-using System.Text;

-using Thrift.Transport;

-using System.Collections.Generic;

-

-namespace Thrift.Protocol 

-{

-

-    /**

-     * TProtocolDecorator forwards all requests to an enclosed TProtocol instance, 

-     * providing a way to author concise concrete decorator subclasses.  While it has 

-     * no abstract methods, it is marked abstract as a reminder that by itself, 

-     * it does not modify the behaviour of the enclosed TProtocol.

-     *

-     * See p.175 of Design Patterns (by Gamma et al.)

-     * See TMultiplexedProtocol

-     */

-    public abstract class TProtocolDecorator : TProtocol 

-    {

-        private TProtocol WrappedProtocol;

-

-        /**

-         * Encloses the specified protocol.

-         * @param protocol All operations will be forward to this protocol.  Must be non-null.

-         */

-        public TProtocolDecorator(TProtocol protocol) 

-            : base( protocol.Transport)

-        {

-            

-            WrappedProtocol = protocol;

-        }

-

-        public override void WriteMessageBegin(TMessage tMessage) 

-        {

-            WrappedProtocol.WriteMessageBegin(tMessage);

-        }

-

-        public override void WriteMessageEnd()

-        {

-            WrappedProtocol.WriteMessageEnd();

-        }

-

-        public override void WriteStructBegin(TStruct tStruct)

-        {

-            WrappedProtocol.WriteStructBegin(tStruct);

-        }

-

-        public override void WriteStructEnd()

-        {

-            WrappedProtocol.WriteStructEnd();

-        }

-

-        public override void WriteFieldBegin(TField tField)

-        {

-            WrappedProtocol.WriteFieldBegin(tField);

-        }

-

-        public override void WriteFieldEnd()

-        {

-            WrappedProtocol.WriteFieldEnd();

-        }

-

-        public override void WriteFieldStop()

-        {

-            WrappedProtocol.WriteFieldStop();

-        }

-

-        public override void WriteMapBegin(TMap tMap) 

-        {

-            WrappedProtocol.WriteMapBegin(tMap);

-        }

-

-        public override void WriteMapEnd()

-        {

-            WrappedProtocol.WriteMapEnd();

-        }

-

-        public override void WriteListBegin(TList tList)  

-        {

-            WrappedProtocol.WriteListBegin(tList);

-        }

-

-        public override void WriteListEnd()

-{

-            WrappedProtocol.WriteListEnd();

-        }

-

-        public override void WriteSetBegin(TSet tSet)  

-        {

-            WrappedProtocol.WriteSetBegin(tSet);

-        }

-

-        public override void WriteSetEnd()

-        {

-            WrappedProtocol.WriteSetEnd();

-        }

-

-        public override void WriteBool(bool b)  

-        {

-            WrappedProtocol.WriteBool(b);

-        }

-

-        public override void WriteByte(sbyte b)

-        {

-            WrappedProtocol.WriteByte(b);

-        }

-

-        public override void WriteI16(short i)

-        {

-            WrappedProtocol.WriteI16(i);

-        }

-

-        public override void WriteI32(int i)

-        {

-            WrappedProtocol.WriteI32(i);

-        }

-

-        public override void WriteI64(long l)

-        {

-            WrappedProtocol.WriteI64(l);

-        }

-

-        public override void WriteDouble(double v)

-        {

-            WrappedProtocol.WriteDouble(v);

-        }

-

-        public override void WriteString(String s)

-        {

-            WrappedProtocol.WriteString(s);

-        }

-

-        public override void WriteBinary(byte[] bytes)

-        {

-            WrappedProtocol.WriteBinary(bytes);

-        }

-

-        public override TMessage ReadMessageBegin()

-        {

-            return WrappedProtocol.ReadMessageBegin();

-        }

-

-        public override void ReadMessageEnd()

-        {

-            WrappedProtocol.ReadMessageEnd();

-        }

-

-        public override TStruct ReadStructBegin()

-        {

-            return WrappedProtocol.ReadStructBegin();

-        }

-

-        public override void ReadStructEnd()

-        {

-            WrappedProtocol.ReadStructEnd();

-        }

-

-        public override TField ReadFieldBegin()

-        {

-            return WrappedProtocol.ReadFieldBegin();

-        }

-

-        public override void ReadFieldEnd()

-        {

-            WrappedProtocol.ReadFieldEnd();

-        }

-

-        public override TMap ReadMapBegin()

-        {

-            return WrappedProtocol.ReadMapBegin();

-        }

-

-        public override void ReadMapEnd()

-        {

-            WrappedProtocol.ReadMapEnd();

-        }

-

-        public override TList ReadListBegin()

-        {

-            return WrappedProtocol.ReadListBegin();

-        }

-

-        public override void ReadListEnd()

-        {

-            WrappedProtocol.ReadListEnd();

-        }

-

-        public override TSet ReadSetBegin()

-        {

-            return WrappedProtocol.ReadSetBegin();

-        }

-

-        public override void ReadSetEnd()

-        {

-            WrappedProtocol.ReadSetEnd();

-        }

-

-        public override bool ReadBool()

-        {

-            return WrappedProtocol.ReadBool();

-        }

-

-        public override sbyte ReadByte()

-        {

-            return WrappedProtocol.ReadByte();

-        }

-

-        public override short ReadI16()

-        {

-            return WrappedProtocol.ReadI16();

-        }

-

-        public override int ReadI32()

-        {

-            return WrappedProtocol.ReadI32();

-        }

-

-        public override long ReadI64()

-        {

-            return WrappedProtocol.ReadI64();

-        }

-

-        public override double ReadDouble()

-        {

-            return WrappedProtocol.ReadDouble();

-        }

-

-        public override String ReadString()

-        {

-            return WrappedProtocol.ReadString();

-        }

-

-        public override byte[] ReadBinary()

-        {

-            return WrappedProtocol.ReadBinary();

-        }

-    }

-

-}

+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Text;
+using Thrift.Transport;
+using System.Collections.Generic;
+
+namespace Thrift.Protocol
+{
+    /// <summary>
+    /// <see cref="TProtocolDecorator"/> forwards all requests to an enclosed <see cref="TProtocol"/> instance,
+    /// providing a way to author concise concrete decorator subclasses. While it has
+    /// no abstract methods, it is marked abstract as a reminder that by itself,
+    /// it does not modify the behaviour of the enclosed <see cref="TProtocol"/>.
+    /// <para/>
+    /// See p.175 of Design Patterns (by Gamma et al.)
+    /// </summary>
+    /// <seealso cref="TMultiplexedProtocol"/>
+    public abstract class TProtocolDecorator : TProtocol
+    {
+        private TProtocol WrappedProtocol;
+
+        /// <summary>
+        /// Encloses the specified protocol.
+        /// </summary>
+        /// <param name="protocol">All operations will be forward to this protocol.  Must be non-null.</param>
+        public TProtocolDecorator(TProtocol protocol)
+            : base(protocol.Transport)
+        {
+
+            WrappedProtocol = protocol;
+        }
+
+        public override void WriteMessageBegin(TMessage tMessage)
+        {
+            WrappedProtocol.WriteMessageBegin(tMessage);
+        }
+
+        public override void WriteMessageEnd()
+        {
+            WrappedProtocol.WriteMessageEnd();
+        }
+
+        public override void WriteStructBegin(TStruct tStruct)
+        {
+            WrappedProtocol.WriteStructBegin(tStruct);
+        }
+
+        public override void WriteStructEnd()
+        {
+            WrappedProtocol.WriteStructEnd();
+        }
+
+        public override void WriteFieldBegin(TField tField)
+        {
+            WrappedProtocol.WriteFieldBegin(tField);
+        }
+
+        public override void WriteFieldEnd()
+        {
+            WrappedProtocol.WriteFieldEnd();
+        }
+
+        public override void WriteFieldStop()
+        {
+            WrappedProtocol.WriteFieldStop();
+        }
+
+        public override void WriteMapBegin(TMap tMap)
+        {
+            WrappedProtocol.WriteMapBegin(tMap);
+        }
+
+        public override void WriteMapEnd()
+        {
+            WrappedProtocol.WriteMapEnd();
+        }
+
+        public override void WriteListBegin(TList tList)
+        {
+            WrappedProtocol.WriteListBegin(tList);
+        }
+
+        public override void WriteListEnd()
+        {
+            WrappedProtocol.WriteListEnd();
+        }
+
+        public override void WriteSetBegin(TSet tSet)
+        {
+            WrappedProtocol.WriteSetBegin(tSet);
+        }
+
+        public override void WriteSetEnd()
+        {
+            WrappedProtocol.WriteSetEnd();
+        }
+
+        public override void WriteBool(bool b)
+        {
+            WrappedProtocol.WriteBool(b);
+        }
+
+        public override void WriteByte(sbyte b)
+        {
+            WrappedProtocol.WriteByte(b);
+        }
+
+        public override void WriteI16(short i)
+        {
+            WrappedProtocol.WriteI16(i);
+        }
+
+        public override void WriteI32(int i)
+        {
+            WrappedProtocol.WriteI32(i);
+        }
+
+        public override void WriteI64(long l)
+        {
+            WrappedProtocol.WriteI64(l);
+        }
+
+        public override void WriteDouble(double v)
+        {
+            WrappedProtocol.WriteDouble(v);
+        }
+
+        public override void WriteString(string s)
+        {
+            WrappedProtocol.WriteString(s);
+        }
+
+        public override void WriteBinary(byte[] bytes)
+        {
+            WrappedProtocol.WriteBinary(bytes);
+        }
+
+        public override TMessage ReadMessageBegin()
+        {
+            return WrappedProtocol.ReadMessageBegin();
+        }
+
+        public override void ReadMessageEnd()
+        {
+            WrappedProtocol.ReadMessageEnd();
+        }
+
+        public override TStruct ReadStructBegin()
+        {
+            return WrappedProtocol.ReadStructBegin();
+        }
+
+        public override void ReadStructEnd()
+        {
+            WrappedProtocol.ReadStructEnd();
+        }
+
+        public override TField ReadFieldBegin()
+        {
+            return WrappedProtocol.ReadFieldBegin();
+        }
+
+        public override void ReadFieldEnd()
+        {
+            WrappedProtocol.ReadFieldEnd();
+        }
+
+        public override TMap ReadMapBegin()
+        {
+            return WrappedProtocol.ReadMapBegin();
+        }
+
+        public override void ReadMapEnd()
+        {
+            WrappedProtocol.ReadMapEnd();
+        }
+
+        public override TList ReadListBegin()
+        {
+            return WrappedProtocol.ReadListBegin();
+        }
+
+        public override void ReadListEnd()
+        {
+            WrappedProtocol.ReadListEnd();
+        }
+
+        public override TSet ReadSetBegin()
+        {
+            return WrappedProtocol.ReadSetBegin();
+        }
+
+        public override void ReadSetEnd()
+        {
+            WrappedProtocol.ReadSetEnd();
+        }
+
+        public override bool ReadBool()
+        {
+            return WrappedProtocol.ReadBool();
+        }
+
+        public override sbyte ReadByte()
+        {
+            return WrappedProtocol.ReadByte();
+        }
+
+        public override short ReadI16()
+        {
+            return WrappedProtocol.ReadI16();
+        }
+
+        public override int ReadI32()
+        {
+            return WrappedProtocol.ReadI32();
+        }
+
+        public override long ReadI64()
+        {
+            return WrappedProtocol.ReadI64();
+        }
+
+        public override double ReadDouble()
+        {
+            return WrappedProtocol.ReadDouble();
+        }
+
+        public override string ReadString()
+        {
+            return WrappedProtocol.ReadString();
+        }
+
+        public override byte[] ReadBinary()
+        {
+            return WrappedProtocol.ReadBinary();
+        }
+    }
+
+}
diff --git a/lib/csharp/src/Protocol/TProtocolException.cs b/lib/csharp/src/Protocol/TProtocolException.cs
index bc002d3..c0f007e 100644
--- a/lib/csharp/src/Protocol/TProtocolException.cs
+++ b/lib/csharp/src/Protocol/TProtocolException.cs
@@ -25,42 +25,43 @@
 
 namespace Thrift.Protocol
 {
-	public class TProtocolException : TException
-	{
-		public const int UNKNOWN = 0;
-		public const int INVALID_DATA = 1;
-		public const int NEGATIVE_SIZE = 2;
-		public const int SIZE_LIMIT = 3;
-		public const int BAD_VERSION = 4;
-		public const int NOT_IMPLEMENTED= 5;
+    public class TProtocolException : TException
+    {
+        public const int UNKNOWN = 0;
+        public const int INVALID_DATA = 1;
+        public const int NEGATIVE_SIZE = 2;
+        public const int SIZE_LIMIT = 3;
+        public const int BAD_VERSION = 4;
+        public const int NOT_IMPLEMENTED = 5;
+        public const int DEPTH_LIMIT = 6;
 
-		protected int type_ = UNKNOWN;
+        protected int type_ = UNKNOWN;
 
-		public TProtocolException()
-			: base()
-		{
-		}
+        public TProtocolException()
+            : base()
+        {
+        }
 
-		public TProtocolException(int type)
-			: base()
-		{
-			type_ = type;
-		}
+        public TProtocolException(int type)
+            : base()
+        {
+            type_ = type;
+        }
 
-		public TProtocolException(int type, String message)
-			: base(message)
-		{
-			type_ = type;
-		}
+        public TProtocolException(int type, string message, Exception inner = null)
+            : base(message, inner)
+        {
+            type_ = type;
+        }
 
-		public TProtocolException(String message)
-			: base(message)
-		{
-		}
+        public TProtocolException(string message, Exception inner = null)
+            : base(message, inner)
+        {
+        }
 
-		public int getType()
-		{
-			return type_;
-		}
-	}
+        public int getType()
+        {
+            return type_;
+        }
+    }
 }
diff --git a/lib/csharp/src/Protocol/TProtocolFactory.cs b/lib/csharp/src/Protocol/TProtocolFactory.cs
index ebc7367..71360a1 100644
--- a/lib/csharp/src/Protocol/TProtocolFactory.cs
+++ b/lib/csharp/src/Protocol/TProtocolFactory.cs
@@ -26,8 +26,8 @@
 
 namespace Thrift.Protocol
 {
-	public interface TProtocolFactory
-	{
-		TProtocol GetProtocol(TTransport trans);
-	}
+    public interface TProtocolFactory
+    {
+        TProtocol GetProtocol(TTransport trans);
+    }
 }
diff --git a/lib/csharp/src/Protocol/TProtocolUtil.cs b/lib/csharp/src/Protocol/TProtocolUtil.cs
index 82cd3e3..d995c6c 100644
--- a/lib/csharp/src/Protocol/TProtocolUtil.cs
+++ b/lib/csharp/src/Protocol/TProtocolUtil.cs
@@ -25,74 +25,84 @@
 
 namespace Thrift.Protocol
 {
-	public static class TProtocolUtil
-	{
-		public static void Skip(TProtocol prot, TType type)
-		{
-			switch (type)
-			{
-				case TType.Bool:
-					prot.ReadBool();
-					break;
-				case TType.Byte:
-					prot.ReadByte();
-					break;
-				case TType.I16:
-					prot.ReadI16();
-					break;
-				case TType.I32:
-					prot.ReadI32();
-					break;
-				case TType.I64:
-					prot.ReadI64();
-					break;
-				case TType.Double:
-					prot.ReadDouble();
-					break;
-				case TType.String:
-					// Don't try to decode the string, just skip it.
-					prot.ReadBinary();
-					break;
-				case TType.Struct:
-					prot.ReadStructBegin();
-					while (true)
-					{
-						TField field = prot.ReadFieldBegin();
-						if (field.Type == TType.Stop)
-						{
-							break;
-						}
-						Skip(prot, field.Type);
-						prot.ReadFieldEnd();
-					}
-					prot.ReadStructEnd();
-					break;
-				case TType.Map:
-					TMap map = prot.ReadMapBegin();
-					for (int i = 0; i < map.Count; i++)
-					{
-						Skip(prot, map.KeyType);
-						Skip(prot, map.ValueType);
-					}
-					prot.ReadMapEnd();
-					break;
-				case TType.Set:
-					TSet set = prot.ReadSetBegin();
-					for (int i = 0; i < set.Count; i++)
-					{
-						Skip(prot, set.ElementType);
-					}
-					prot.ReadSetEnd();
-					break;
-				case TType.List:
-					TList list = prot.ReadListBegin();
-					for (int i = 0; i < list.Count; i++)
-					{
-						Skip(prot, list.ElementType);
-					}
-					prot.ReadListEnd();
-					break;
-			}
-		}
-	}
+    public static class TProtocolUtil
+    {
+        public static void Skip(TProtocol prot, TType type)
+        {
+            prot.IncrementRecursionDepth();
+            try
+            {
+                switch (type)
+                {
+                    case TType.Bool:
+                        prot.ReadBool();
+                        break;
+                    case TType.Byte:
+                        prot.ReadByte();
+                        break;
+                    case TType.I16:
+                        prot.ReadI16();
+                        break;
+                    case TType.I32:
+                        prot.ReadI32();
+                        break;
+                    case TType.I64:
+                        prot.ReadI64();
+                        break;
+                    case TType.Double:
+                        prot.ReadDouble();
+                        break;
+                    case TType.String:
+                        // Don't try to decode the string, just skip it.
+                        prot.ReadBinary();
+                        break;
+                    case TType.Struct:
+                        prot.ReadStructBegin();
+                        while (true)
+                        {
+                            TField field = prot.ReadFieldBegin();
+                            if (field.Type == TType.Stop)
+                            {
+                                break;
+                            }
+                            Skip(prot, field.Type);
+                            prot.ReadFieldEnd();
+                        }
+                        prot.ReadStructEnd();
+                        break;
+                    case TType.Map:
+                        TMap map = prot.ReadMapBegin();
+                        for (int i = 0; i < map.Count; i++)
+                        {
+                            Skip(prot, map.KeyType);
+                            Skip(prot, map.ValueType);
+                        }
+                        prot.ReadMapEnd();
+                        break;
+                    case TType.Set:
+                        TSet set = prot.ReadSetBegin();
+                        for (int i = 0; i < set.Count; i++)
+                        {
+                            Skip(prot, set.ElementType);
+                        }
+                        prot.ReadSetEnd();
+                        break;
+                    case TType.List:
+                        TList list = prot.ReadListBegin();
+                        for (int i = 0; i < list.Count; i++)
+                        {
+                            Skip(prot, list.ElementType);
+                        }
+                        prot.ReadListEnd();
+                        break;
+                    default:
+                        throw new TProtocolException(TProtocolException.INVALID_DATA, "Unknown data type " + type.ToString("d"));
+                }
+            }
+            finally
+            {
+                prot.DecrementRecursionDepth();
+            }
+        }
+    }
 }
diff --git a/lib/csharp/src/Protocol/TSet.cs b/lib/csharp/src/Protocol/TSet.cs
index 68e5286..a918ab5 100644
--- a/lib/csharp/src/Protocol/TSet.cs
+++ b/lib/csharp/src/Protocol/TSet.cs
@@ -27,33 +27,33 @@
 
 namespace Thrift.Protocol
 {
-	public struct TSet
-	{
-		private TType elementType;
-		private int count;
+    public struct TSet
+    {
+        private TType elementType;
+        private int count;
 
-		public TSet(TType elementType, int count)
-			:this()
-		{
-			this.elementType = elementType;
-			this.count = count;
-		}
+        public TSet(TType elementType, int count)
+            :this()
+        {
+            this.elementType = elementType;
+            this.count = count;
+        }
 
-		public TSet(TList list)
-			: this(list.ElementType, list.Count)
-		{
-		}
+        public TSet(TList list)
+            : this(list.ElementType, list.Count)
+        {
+        }
 
-		public TType ElementType
-		{
-			get { return elementType; }
-			set { elementType = value; }
-		}
+        public TType ElementType
+        {
+            get { return elementType; }
+            set { elementType = value; }
+        }
 
-		public int Count
-		{
-			get { return count; }
-			set { count = value; }
-		}
-	}
+        public int Count
+        {
+            get { return count; }
+            set { count = value; }
+        }
+    }
 }
diff --git a/lib/csharp/src/Protocol/TStruct.cs b/lib/csharp/src/Protocol/TStruct.cs
index 37d1106..f4844a4 100644
--- a/lib/csharp/src/Protocol/TStruct.cs
+++ b/lib/csharp/src/Protocol/TStruct.cs
@@ -27,20 +27,20 @@
 
 namespace Thrift.Protocol
 {
-	public struct TStruct
-	{
-		private string name;
+    public struct TStruct
+    {
+        private string name;
 
-		public TStruct(string name)
-			:this()
-		{
-			this.name = name;
-		}
+        public TStruct(string name)
+            :this()
+        {
+            this.name = name;
+        }
 
-		public string Name
-		{
-			get { return name; }
-			set { name = value; }
-		}
-	}
+        public string Name
+        {
+            get { return name; }
+            set { name = value; }
+        }
+    }
 }
diff --git a/lib/csharp/src/Protocol/TType.cs b/lib/csharp/src/Protocol/TType.cs
index efc7bef..9ce915e 100644
--- a/lib/csharp/src/Protocol/TType.cs
+++ b/lib/csharp/src/Protocol/TType.cs
@@ -25,20 +25,20 @@
 
 namespace Thrift.Protocol
 {
-	public enum TType : byte
-	{
-		Stop = 0,
-		Void = 1,
-		Bool = 2,
-		Byte = 3,
-		Double = 4,
-		I16 = 6,
-		I32 = 8,
-		I64 = 10,
-		String = 11,
-		Struct = 12,
-		Map = 13,
-		Set = 14,
-		List = 15
-	}
+    public enum TType : byte
+    {
+        Stop = 0,
+        Void = 1,
+        Bool = 2,
+        Byte = 3,
+        Double = 4,
+        I16 = 6,
+        I32 = 8,
+        I64 = 10,
+        String = 11,
+        Struct = 12,
+        Map = 13,
+        Set = 14,
+        List = 15
+    }
 }
diff --git a/lib/csharp/src/Server/TServer.cs b/lib/csharp/src/Server/TServer.cs
index 7bf2747..2bc04f3 100644
--- a/lib/csharp/src/Server/TServer.cs
+++ b/lib/csharp/src/Server/TServer.cs
@@ -28,112 +28,128 @@
 
 namespace Thrift.Server
 {
-	public abstract class TServer
-	{
-		/**
-		 * Core processor
-		 */
-		protected TProcessor processor;
+    public abstract class TServer
+    {
+        //Attributes
+        protected TProcessorFactory processorFactory;
+        protected TServerTransport serverTransport;
+        protected TTransportFactory inputTransportFactory;
+        protected TTransportFactory outputTransportFactory;
+        protected TProtocolFactory inputProtocolFactory;
+        protected TProtocolFactory outputProtocolFactory;
+        protected TServerEventHandler serverEventHandler = null;
 
-		/**
-		 * Server transport
-		 */
-		protected TServerTransport serverTransport;
+        //Methods
+        public void setEventHandler(TServerEventHandler seh)
+        {
+            serverEventHandler = seh;
+        }
+        public TServerEventHandler getEventHandler()
+        {
+            return serverEventHandler;
+        }
 
-		/**
-		 * Input Transport Factory
-		 */
-		protected TTransportFactory inputTransportFactory;
+        //Log delegation
+        public delegate void LogDelegate(string str);
+        private LogDelegate _logDelegate;
+        protected LogDelegate logDelegate
+        {
+            get { return _logDelegate; }
+            set { _logDelegate = (value != null) ? value : DefaultLogDelegate; }
+        }
+        protected static void DefaultLogDelegate(string s)
+        {
+            Console.Error.WriteLine(s);
+        }
 
-		/**
-		 * Output Transport Factory
-		 */
-		protected TTransportFactory outputTransportFactory;
+        //Construction
+        public TServer(TProcessor processor,
+                  TServerTransport serverTransport)
+          : this(processor, serverTransport,
+             new TTransportFactory(),
+             new TTransportFactory(),
+             new TBinaryProtocol.Factory(),
+             new TBinaryProtocol.Factory(),
+             DefaultLogDelegate)
+        {
+        }
 
-		/**
-		 * Input Protocol Factory
-		 */
-		protected TProtocolFactory inputProtocolFactory;
+        public TServer(TProcessor processor,
+                TServerTransport serverTransport,
+                LogDelegate logDelegate)
+          : this(processor,
+             serverTransport,
+             new TTransportFactory(),
+             new TTransportFactory(),
+             new TBinaryProtocol.Factory(),
+             new TBinaryProtocol.Factory(),
+             logDelegate)
+        {
+        }
 
-		/**
-		 * Output Protocol Factory
-		 */
-		protected TProtocolFactory outputProtocolFactory;
-		public delegate void LogDelegate(string str);
-		protected LogDelegate logDelegate;
+        public TServer(TProcessor processor,
+                  TServerTransport serverTransport,
+                  TTransportFactory transportFactory)
+          : this(processor,
+             serverTransport,
+             transportFactory,
+             transportFactory,
+             new TBinaryProtocol.Factory(),
+             new TBinaryProtocol.Factory(),
+             DefaultLogDelegate)
+        {
+        }
 
-		/**
-		 * Default constructors.
-		 */
+        public TServer(TProcessor processor,
+                  TServerTransport serverTransport,
+                  TTransportFactory transportFactory,
+                  TProtocolFactory protocolFactory)
+          : this(processor,
+             serverTransport,
+             transportFactory,
+             transportFactory,
+             protocolFactory,
+             protocolFactory,
+               DefaultLogDelegate)
+        {
+        }
 
-		public TServer(TProcessor processor,
-						  TServerTransport serverTransport)
-			:this(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(), DefaultLogDelegate)
-		{
-		}
+        public TServer(TProcessor processor,
+            TServerTransport serverTransport,
+            TTransportFactory inputTransportFactory,
+            TTransportFactory outputTransportFactory,
+            TProtocolFactory inputProtocolFactory,
+            TProtocolFactory outputProtocolFactory,
+            LogDelegate logDelegate)
+        {
+            this.processorFactory = new TSingletonProcessorFactory(processor);
+            this.serverTransport = serverTransport;
+            this.inputTransportFactory = inputTransportFactory;
+            this.outputTransportFactory = outputTransportFactory;
+            this.inputProtocolFactory = inputProtocolFactory;
+            this.outputProtocolFactory = outputProtocolFactory;
+            this.logDelegate = (logDelegate != null) ? logDelegate : DefaultLogDelegate;
+        }
 
-		public TServer(TProcessor processor,
-						TServerTransport serverTransport,
-						LogDelegate logDelegate)
-			: this(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(), DefaultLogDelegate)
-		{
-		}
+        public TServer(TProcessorFactory processorFactory,
+                  TServerTransport serverTransport,
+                  TTransportFactory inputTransportFactory,
+                  TTransportFactory outputTransportFactory,
+                  TProtocolFactory inputProtocolFactory,
+                  TProtocolFactory outputProtocolFactory,
+                  LogDelegate logDelegate)
+        {
+            this.processorFactory = processorFactory;
+            this.serverTransport = serverTransport;
+            this.inputTransportFactory = inputTransportFactory;
+            this.outputTransportFactory = outputTransportFactory;
+            this.inputProtocolFactory = inputProtocolFactory;
+            this.outputProtocolFactory = outputProtocolFactory;
+            this.logDelegate = (logDelegate != null) ? logDelegate : DefaultLogDelegate;
+        }
 
-		public TServer(TProcessor processor,
-						  TServerTransport serverTransport,
-						  TTransportFactory transportFactory)
-			:this(processor,
-				 serverTransport,
-				 transportFactory,
-				 transportFactory,
-				 new TBinaryProtocol.Factory(),
-				 new TBinaryProtocol.Factory(),
-				 DefaultLogDelegate)
-		{
-		}
-
-		public TServer(TProcessor processor,
-						  TServerTransport serverTransport,
-						  TTransportFactory transportFactory,
-						  TProtocolFactory protocolFactory)
-			:this(processor,
-				 serverTransport,
-				 transportFactory,
-				 transportFactory,
-				 protocolFactory,
-				 protocolFactory,
-			     DefaultLogDelegate)
-		{
-		}
-
-		public TServer(TProcessor processor,
-						  TServerTransport serverTransport,
-						  TTransportFactory inputTransportFactory,
-						  TTransportFactory outputTransportFactory,
-						  TProtocolFactory inputProtocolFactory,
-						  TProtocolFactory outputProtocolFactory,
-						  LogDelegate logDelegate)
-		{
-			this.processor = processor;
-			this.serverTransport = serverTransport;
-			this.inputTransportFactory = inputTransportFactory;
-			this.outputTransportFactory = outputTransportFactory;
-			this.inputProtocolFactory = inputProtocolFactory;
-			this.outputProtocolFactory = outputProtocolFactory;
-			this.logDelegate = logDelegate;
-		}
-
-		/**
-		 * The run method fires up the server and gets things going.
-		 */
-		public abstract void Serve();
-
-		public abstract void Stop();
-
-		protected static void DefaultLogDelegate(string s)
-		{
-			Console.Error.WriteLine(s);
-		}
-	}
+        //Abstract Interface
+        public abstract void Serve();
+        public abstract void Stop();
+    }
 }
-
diff --git a/lib/csharp/src/Server/TServerEventHandler.cs b/lib/csharp/src/Server/TServerEventHandler.cs
new file mode 100644
index 0000000..e81efc6
--- /dev/null
+++ b/lib/csharp/src/Server/TServerEventHandler.cs
@@ -0,0 +1,53 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+
+namespace Thrift.Server
+{
+    /// <summary>
+    /// Interface implemented by server users to handle events from the server.
+    /// </summary>
+    public interface TServerEventHandler
+    {
+        /// <summary>
+        /// Called before the server begins.
+        /// </summary>
+        void preServe();
+
+        /// <summary>
+        /// Called when a new client has connected and is about to being processing.
+        /// </summary>
+        object createContext(Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output);
+
+        /// <summary>
+        /// Called when a client has finished request-handling to delete server context.
+        /// </summary>
+        void deleteContext(object serverContext, Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output);
+
+        /// <summary>
+        /// Called when a client is about to call the processor.
+        /// </summary>
+        void processContext(object serverContext, Thrift.Transport.TTransport transport);
+    };
+}
diff --git a/lib/csharp/src/Server/TSimpleServer.cs b/lib/csharp/src/Server/TSimpleServer.cs
index 1099fc1..4e7ea96 100644
--- a/lib/csharp/src/Server/TSimpleServer.cs
+++ b/lib/csharp/src/Server/TSimpleServer.cs
@@ -27,122 +27,154 @@
 
 namespace Thrift.Server
 {
-	/// <summary>
-	/// Simple single-threaded server for testing
-	/// </summary>
-	public class TSimpleServer : TServer
-	{
-		private bool stop = false;
+    /// <summary>
+    /// Simple single-threaded server for testing.
+    /// </summary>
+    public class TSimpleServer : TServer
+    {
+        private bool stop = false;
 
-		public TSimpleServer(TProcessor processor,
-						  TServerTransport serverTransport)
-			:base(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(), DefaultLogDelegate)
-		{
-		}
+        public TSimpleServer(TProcessor processor,
+                  TServerTransport serverTransport)
+          : base(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(), DefaultLogDelegate)
+        {
+        }
 
-		public TSimpleServer(TProcessor processor,
-							TServerTransport serverTransport,
-							LogDelegate logDel)
-			: base(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(), logDel)
-		{
-		}
+        public TSimpleServer(TProcessor processor,
+                  TServerTransport serverTransport,
+                  LogDelegate logDel)
+          : base(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(), logDel)
+        {
+        }
 
-		public TSimpleServer(TProcessor processor,
-						  TServerTransport serverTransport,
-						  TTransportFactory transportFactory)
-			:base(processor,
-				 serverTransport,
-				 transportFactory,
-				 transportFactory,
-				 new TBinaryProtocol.Factory(),
-				 new TBinaryProtocol.Factory(),
-			     DefaultLogDelegate)
-		{
-		}
+        public TSimpleServer(TProcessor processor,
+                  TServerTransport serverTransport,
+                  TTransportFactory transportFactory)
+          : base(processor,
+             serverTransport,
+             transportFactory,
+             transportFactory,
+             new TBinaryProtocol.Factory(),
+             new TBinaryProtocol.Factory(),
+               DefaultLogDelegate)
+        {
+        }
 
-		public TSimpleServer(TProcessor processor,
-						  TServerTransport serverTransport,
-						  TTransportFactory transportFactory,
-						  TProtocolFactory protocolFactory)
-			:base(processor,
-				 serverTransport,
-				 transportFactory,
-				 transportFactory,
-				 protocolFactory,
-				 protocolFactory,
-				 DefaultLogDelegate)
-		{
-		}
+        public TSimpleServer(TProcessor processor,
+            TServerTransport serverTransport,
+            TTransportFactory transportFactory,
+            TProtocolFactory protocolFactory)
+            : base(processor,
+               serverTransport,
+               transportFactory,
+               transportFactory,
+               protocolFactory,
+               protocolFactory,
+               DefaultLogDelegate)
+        {
+        }
 
-		public override void Serve()
-		{
-			try
-			{
-				serverTransport.Listen();
-			}
-			catch (TTransportException ttx)
-			{
-				logDelegate(ttx.ToString());
-				return;
-			}
+        public TSimpleServer(TProcessorFactory processorFactory,
+                  TServerTransport serverTransport,
+                  TTransportFactory transportFactory,
+                  TProtocolFactory protocolFactory)
+          : base(processorFactory,
+             serverTransport,
+             transportFactory,
+             transportFactory,
+             protocolFactory,
+             protocolFactory,
+             DefaultLogDelegate)
+        {
+        }
 
-			while (!stop)
-			{
-				TTransport client = null;
-				TTransport inputTransport = null;
-				TTransport outputTransport = null;
-				TProtocol inputProtocol = null;
-				TProtocol outputProtocol = null;
-				try
-				{
-          using(client = serverTransport.Accept())
-          {
-            if (client != null)
+        public override void Serve()
+        {
+            try
             {
-              using(inputTransport = inputTransportFactory.GetTransport(client))
-              {
-                using (outputTransport = outputTransportFactory.GetTransport(client))
-                {
-                  inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
-                  outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
-                  while (processor.Process(inputProtocol, outputProtocol)) { }
-                }
-              }
+                serverTransport.Listen();
             }
-          }
-        }
-        catch (TTransportException ttx)
-        {
-          // Client died, just move on
-          if (stop)
-          {
-            logDelegate("TSimpleServer was shutting down, caught " + ttx.GetType().Name);
-          }
-        }
-        catch (Exception x)
-        {
-          logDelegate(x.ToString());
-        }
-      }
+            catch (TTransportException ttx)
+            {
+                logDelegate(ttx.ToString());
+                return;
+            }
 
-			if (stop)
-			{
-				try
-				{
-					serverTransport.Close();
-				}
-				catch (TTransportException ttx)
-				{
-					logDelegate("TServerTranport failed on close: " + ttx.Message);
-				}
-				stop = false;
-			}
-		}
+            //Fire the preServe server event when server is up but before any client connections
+            if (serverEventHandler != null)
+                serverEventHandler.preServe();
 
-		public override void Stop()
-		{
-			stop = true;
-			serverTransport.Close();
-		}
-	}
+            while (!stop)
+            {
+                TProcessor processor = null;
+                TTransport client = null;
+                TTransport inputTransport = null;
+                TTransport outputTransport = null;
+                TProtocol inputProtocol = null;
+                TProtocol outputProtocol = null;
+                object connectionContext = null;
+                try
+                {
+                    using (client = serverTransport.Accept())
+                    {
+                        processor = processorFactory.GetProcessor(client);
+                        if (client != null)
+                        {
+                            using (inputTransport = inputTransportFactory.GetTransport(client))
+                            {
+                                using (outputTransport = outputTransportFactory.GetTransport(client))
+                                {
+                                    inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
+                                    outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
+
+                                    //Recover event handler (if any) and fire createContext server event when a client connects
+                                    if (serverEventHandler != null)
+                                        connectionContext = serverEventHandler.createContext(inputProtocol, outputProtocol);
+
+                                    //Process client requests until client disconnects
+                                    while (!stop)
+                                    {
+                                        if (!inputTransport.Peek())
+                                            break;
+
+                                        //Fire processContext server event
+                                        //N.B. This is the pattern implemented in C++ and the event fires provisionally.
+                                        //That is to say it may be many minutes between the event firing and the client request
+                                        //actually arriving or the client may hang up without ever makeing a request.
+                                        if (serverEventHandler != null)
+                                            serverEventHandler.processContext(connectionContext, inputTransport);
+                                        //Process client request (blocks until transport is readable)
+                                        if (!processor.Process(inputProtocol, outputProtocol))
+                                            break;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                catch (TTransportException ttx)
+                {
+                    if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted)
+                    {
+                        logDelegate(ttx.ToString());
+                    }
+                }
+                catch (Exception x)
+                {
+                    //Unexpected
+                    logDelegate(x.ToString());
+                }
+
+                //Fire deleteContext server event after client disconnects
+                if (serverEventHandler != null)
+                    serverEventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
+            }
+        }
+
+        public override void Stop()
+        {
+            stop = true;
+            serverTransport.Close();
+        }
+    }
 }
diff --git a/lib/csharp/src/Server/TThreadPoolServer.cs b/lib/csharp/src/Server/TThreadPoolServer.cs
index b257fd8..a494ce7 100644
--- a/lib/csharp/src/Server/TThreadPoolServer.cs
+++ b/lib/csharp/src/Server/TThreadPoolServer.cs
@@ -28,167 +28,268 @@
 
 namespace Thrift.Server
 {
-	/// <summary>
-	/// Server that uses C# built-in ThreadPool to spawn threads when handling requests
-	/// </summary>
-	public class TThreadPoolServer : TServer
-	{
-		private const int DEFAULT_MIN_THREADS = 10;
-		private const int DEFAULT_MAX_THREADS = 100;
-		private volatile bool stop = false;
+    /// <summary>
+    /// Server that uses C# built-in ThreadPool to spawn threads when handling requests.
+    /// </summary>
+    public class TThreadPoolServer : TServer
+    {
+        private const int DEFAULT_MIN_THREADS = -1;  // use .NET ThreadPool defaults
+        private const int DEFAULT_MAX_THREADS = -1;  // use .NET ThreadPool defaults
+        private volatile bool stop = false;
 
-		public TThreadPoolServer(TProcessor processor, TServerTransport serverTransport)
-			:this(processor, serverTransport,
-				 new TTransportFactory(), new TTransportFactory(),
-				 new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
-				 DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS, DefaultLogDelegate)
-		{
-		}
-
-		public TThreadPoolServer(TProcessor processor, TServerTransport serverTransport, LogDelegate logDelegate)
-			: this(processor, serverTransport,
-				 new TTransportFactory(), new TTransportFactory(),
-				 new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
-				 DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS, logDelegate)
-		{
-		}
-
-
-		public TThreadPoolServer(TProcessor processor,
-								 TServerTransport serverTransport,
-								 TTransportFactory transportFactory,
-								 TProtocolFactory protocolFactory)
-			:this(processor, serverTransport,
-				 transportFactory, transportFactory,
-				 protocolFactory, protocolFactory,
-				 DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS, DefaultLogDelegate)
-		{
-		}
-
-		public TThreadPoolServer(TProcessor processor,
-								 TServerTransport serverTransport,
-								 TTransportFactory inputTransportFactory,
-								 TTransportFactory outputTransportFactory,
-								 TProtocolFactory inputProtocolFactory,
-								 TProtocolFactory outputProtocolFactory,
-								 int minThreadPoolThreads, int maxThreadPoolThreads, LogDelegate logDel)
-			:base(processor, serverTransport, inputTransportFactory, outputTransportFactory,
-				  inputProtocolFactory, outputProtocolFactory, logDel)
-		{
-      lock (typeof(TThreadPoolServer))
-      {
-        if (!ThreadPool.SetMinThreads(minThreadPoolThreads, minThreadPoolThreads))
+        public struct Configuration
         {
-          throw new Exception("Error: could not SetMinThreads in ThreadPool");
+            public int MinWorkerThreads;
+            public int MaxWorkerThreads;
+            public int MinIOThreads;
+            public int MaxIOThreads;
+
+            public Configuration(int min = DEFAULT_MIN_THREADS, int max = DEFAULT_MAX_THREADS)
+            {
+                MinWorkerThreads = min;
+                MaxWorkerThreads = max;
+                MinIOThreads = min;
+                MaxIOThreads = max;
+            }
+
+            public Configuration(int minWork, int maxWork, int minIO, int maxIO)
+            {
+                MinWorkerThreads = minWork;
+                MaxWorkerThreads = maxWork;
+                MinIOThreads = minIO;
+                MaxIOThreads = maxIO;
+            }
         }
-        if (!ThreadPool.SetMaxThreads(maxThreadPoolThreads, maxThreadPoolThreads))
+
+        public TThreadPoolServer(TProcessor processor, TServerTransport serverTransport)
+            : this(new TSingletonProcessorFactory(processor), serverTransport,
+             new TTransportFactory(), new TTransportFactory(),
+             new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
+             new Configuration(), DefaultLogDelegate)
         {
-          throw new Exception("Error: could not SetMaxThreads in ThreadPool");
         }
-			}
-		}
+
+        public TThreadPoolServer(TProcessor processor, TServerTransport serverTransport, LogDelegate logDelegate)
+            : this(new TSingletonProcessorFactory(processor), serverTransport,
+             new TTransportFactory(), new TTransportFactory(),
+             new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
+             new Configuration(), logDelegate)
+        {
+        }
+
+        public TThreadPoolServer(TProcessor processor,
+         TServerTransport serverTransport,
+         TTransportFactory transportFactory,
+         TProtocolFactory protocolFactory)
+            : this(new TSingletonProcessorFactory(processor), serverTransport,
+               transportFactory, transportFactory,
+               protocolFactory, protocolFactory,
+               new Configuration(), DefaultLogDelegate)
+        {
+        }
+
+        public TThreadPoolServer(TProcessorFactory processorFactory,
+                     TServerTransport serverTransport,
+                     TTransportFactory transportFactory,
+                     TProtocolFactory protocolFactory)
+            : this(processorFactory, serverTransport,
+             transportFactory, transportFactory,
+             protocolFactory, protocolFactory,
+             new Configuration(), DefaultLogDelegate)
+        {
+        }
+
+        public TThreadPoolServer(TProcessorFactory processorFactory,
+                     TServerTransport serverTransport,
+                     TTransportFactory inputTransportFactory,
+                     TTransportFactory outputTransportFactory,
+                     TProtocolFactory inputProtocolFactory,
+                     TProtocolFactory outputProtocolFactory,
+                     int minThreadPoolThreads, int maxThreadPoolThreads, LogDelegate logDel)
+            : this(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory,
+             inputProtocolFactory, outputProtocolFactory,
+             new Configuration(minThreadPoolThreads, maxThreadPoolThreads),
+             logDel)
+        {
+        }
+
+        public TThreadPoolServer(TProcessorFactory processorFactory,
+                     TServerTransport serverTransport,
+                     TTransportFactory inputTransportFactory,
+                     TTransportFactory outputTransportFactory,
+                     TProtocolFactory inputProtocolFactory,
+                     TProtocolFactory outputProtocolFactory,
+                     Configuration threadConfig,
+                     LogDelegate logDel)
+            : base(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory,
+            inputProtocolFactory, outputProtocolFactory, logDel)
+        {
+            lock (typeof(TThreadPoolServer))
+            {
+                if ((threadConfig.MaxWorkerThreads > 0) || (threadConfig.MaxIOThreads > 0))
+                {
+                    int work, comm;
+                    ThreadPool.GetMaxThreads(out work, out comm);
+                    if (threadConfig.MaxWorkerThreads > 0)
+                        work = threadConfig.MaxWorkerThreads;
+                    if (threadConfig.MaxIOThreads > 0)
+                        comm = threadConfig.MaxIOThreads;
+                    if (!ThreadPool.SetMaxThreads(work, comm))
+                        throw new Exception("Error: could not SetMaxThreads in ThreadPool");
+                }
+
+                if ((threadConfig.MinWorkerThreads > 0) || (threadConfig.MinIOThreads > 0))
+                {
+                    int work, comm;
+                    ThreadPool.GetMinThreads(out work, out comm);
+                    if (threadConfig.MinWorkerThreads > 0)
+                        work = threadConfig.MinWorkerThreads;
+                    if (threadConfig.MinIOThreads > 0)
+                        comm = threadConfig.MinIOThreads;
+                    if (!ThreadPool.SetMinThreads(work, comm))
+                        throw new Exception("Error: could not SetMinThreads in ThreadPool");
+                }
+            }
+        }
 
 
-		/// <summary>
-		/// Use new ThreadPool thread for each new client connection
-		/// </summary>
-		public override void Serve()
-		{
-			try
-			{
-				serverTransport.Listen();
-			}
-			catch (TTransportException ttx)
-			{
-				logDelegate("Error, could not listen on ServerTransport: " + ttx);
-				return;
-			}
+        /// <summary>
+        /// Use new ThreadPool thread for each new client connection.
+        /// </summary>
+        public override void Serve()
+        {
+            try
+            {
+                serverTransport.Listen();
+            }
+            catch (TTransportException ttx)
+            {
+                logDelegate("Error, could not listen on ServerTransport: " + ttx);
+                return;
+            }
 
-			while (!stop)
-			{
-				int failureCount = 0;
-				try
-				{
-					TTransport client = serverTransport.Accept();
-					ThreadPool.QueueUserWorkItem(this.Execute, client);
-				}
-				catch (TTransportException ttx)
-				{
-					if (stop)
-					{
-						logDelegate("TThreadPoolServer was shutting down, caught " + ttx.GetType().Name);
-					}
-					else
-					{
-						++failureCount;
-						logDelegate(ttx.ToString());
-					}
+            //Fire the preServe server event when server is up but before any client connections
+            if (serverEventHandler != null)
+                serverEventHandler.preServe();
 
-				}
-			}
+            while (!stop)
+            {
+                int failureCount = 0;
+                try
+                {
+                    TTransport client = serverTransport.Accept();
+                    ThreadPool.QueueUserWorkItem(this.Execute, client);
+                }
+                catch (TTransportException ttx)
+                {
+                    if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted)
+                    {
+                        ++failureCount;
+                        logDelegate(ttx.ToString());
+                    }
 
-			if (stop)
-			{
-				try
-				{
-					serverTransport.Close();
-				}
-				catch (TTransportException ttx)
-				{
-					logDelegate("TServerTransport failed on close: " + ttx.Message);
-				}
-				stop = false;
-			}
-		}
+                }
+            }
 
-		/// <summary>
-		/// Loops on processing a client forever
-		/// threadContext will be a TTransport instance
-		/// </summary>
-		/// <param name="threadContext"></param>
-		private void Execute(Object threadContext)
-		{
-			TTransport client = (TTransport)threadContext;
-			TTransport inputTransport = null;
-			TTransport outputTransport = null;
-			TProtocol inputProtocol = null;
-			TProtocol outputProtocol = null;
-			try
-			{
-				inputTransport = inputTransportFactory.GetTransport(client);
-				outputTransport = outputTransportFactory.GetTransport(client);
-				inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
-				outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
-				while (processor.Process(inputProtocol, outputProtocol))
-				{
-					//keep processing requests until client disconnects
-				}
-			}
-			catch (TTransportException)
-			{
-				// Assume the client died and continue silently
-				//Console.WriteLine(ttx);
-			}
-			
-			catch (Exception x)
-			{
-				logDelegate("Error: " + x);
-			}
+            if (stop)
+            {
+                try
+                {
+                    serverTransport.Close();
+                }
+                catch (TTransportException ttx)
+                {
+                    logDelegate("TServerTransport failed on close: " + ttx.Message);
+                }
+                stop = false;
+            }
+        }
 
-			if (inputTransport != null)
-			{
-				inputTransport.Close();
-			}
-			if (outputTransport != null)
-			{
-				outputTransport.Close();
-			}
-		}
+        /// <summary>
+        /// Loops on processing a client forever
+        /// threadContext will be a TTransport instance
+        /// </summary>
+        /// <param name="threadContext"></param>
+        private void Execute(object threadContext)
+        {
+            using (TTransport client = (TTransport)threadContext)
+            {
+                TProcessor processor = processorFactory.GetProcessor(client, this);
+                TTransport inputTransport = null;
+                TTransport outputTransport = null;
+                TProtocol inputProtocol = null;
+                TProtocol outputProtocol = null;
+                object connectionContext = null;
+                try
+                {
+                    try
+                    {
+                        inputTransport = inputTransportFactory.GetTransport(client);
+                        outputTransport = outputTransportFactory.GetTransport(client);
+                        inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
+                        outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
 
-		public override void Stop()
-		{
-			stop = true;
-			serverTransport.Close();
-		}
-	}
+                        //Recover event handler (if any) and fire createContext server event when a client connects
+                        if (serverEventHandler != null)
+                            connectionContext = serverEventHandler.createContext(inputProtocol, outputProtocol);
+
+                        //Process client requests until client disconnects
+                        while (!stop)
+                        {
+                            if (!inputTransport.Peek())
+                                break;
+
+                            //Fire processContext server event
+                            //N.B. This is the pattern implemented in C++ and the event fires provisionally.
+                            //That is to say it may be many minutes between the event firing and the client request
+                            //actually arriving or the client may hang up without ever makeing a request.
+                            if (serverEventHandler != null)
+                                serverEventHandler.processContext(connectionContext, inputTransport);
+                            //Process client request (blocks until transport is readable)
+                            if (!processor.Process(inputProtocol, outputProtocol))
+                                break;
+                        }
+                    }
+                    catch (TTransportException)
+                    {
+                        //Usually a client disconnect, expected
+                    }
+                    catch (Exception x)
+                    {
+                        //Unexpected
+                        logDelegate("Error: " + x);
+                    }
+
+                    //Fire deleteContext server event after client disconnects
+                    if (serverEventHandler != null)
+                        serverEventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
+
+                }
+                finally
+                {
+                    //Close transports
+                    if (inputTransport != null)
+                        inputTransport.Close();
+                    if (outputTransport != null)
+                        outputTransport.Close();
+
+                    // disposable stuff should be disposed
+                    if (inputProtocol != null)
+                        inputProtocol.Dispose();
+                    if (outputProtocol != null)
+                        outputProtocol.Dispose();
+                    if (inputTransport != null)
+                        inputTransport.Dispose();
+                    if (outputTransport != null)
+                        outputTransport.Dispose();
+                }
+            }
+        }
+
+        public override void Stop()
+        {
+            stop = true;
+            serverTransport.Close();
+        }
+    }
 }
diff --git a/lib/csharp/src/Server/TThreadedServer.cs b/lib/csharp/src/Server/TThreadedServer.cs
index 8e73bb7..cc051a3 100644
--- a/lib/csharp/src/Server/TThreadedServer.cs
+++ b/lib/csharp/src/Server/TThreadedServer.cs
@@ -26,204 +26,257 @@
 
 namespace Thrift.Server
 {
-	/// <summary>
-	/// Server that uses C# threads (as opposed to the ThreadPool) when handling requests
-	/// </summary>
-	public class TThreadedServer : TServer
-	{
-		private const int DEFAULT_MAX_THREADS = 100;
-		private volatile bool stop = false;
-		private readonly int maxThreads;
+    /// <summary>
+    /// Server that uses C# threads (as opposed to the ThreadPool) when handling requests.
+    /// </summary>
+    public class TThreadedServer : TServer
+    {
+        private const int DEFAULT_MAX_THREADS = 100;
+        private volatile bool stop = false;
+        private readonly int maxThreads;
 
-		private Queue<TTransport> clientQueue;
-		private THashSet<Thread> clientThreads;
-		private object clientLock;
-		private Thread workerThread;
+        private Queue<TTransport> clientQueue;
+        private THashSet<Thread> clientThreads;
+        private object clientLock;
+        private Thread workerThread;
 
-		public TThreadedServer(TProcessor processor, TServerTransport serverTransport)
-			: this(processor, serverTransport,
-				 new TTransportFactory(), new TTransportFactory(),
-				 new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
-				 DEFAULT_MAX_THREADS, DefaultLogDelegate)
-		{
-		}
-
-		public TThreadedServer(TProcessor processor, TServerTransport serverTransport, LogDelegate logDelegate)
-			: this(processor, serverTransport,
-				 new TTransportFactory(), new TTransportFactory(),
-				 new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
-				 DEFAULT_MAX_THREADS, logDelegate)
-		{
-		}
-
-
-		public TThreadedServer(TProcessor processor,
-								 TServerTransport serverTransport,
-								 TTransportFactory transportFactory,
-								 TProtocolFactory protocolFactory)
-			: this(processor, serverTransport,
-				 transportFactory, transportFactory,
-				 protocolFactory, protocolFactory,
-				 DEFAULT_MAX_THREADS, DefaultLogDelegate)
-		{
-		}
-
-		public TThreadedServer(TProcessor processor,
-								 TServerTransport serverTransport,
-								 TTransportFactory inputTransportFactory,
-								 TTransportFactory outputTransportFactory,
-								 TProtocolFactory inputProtocolFactory,
-								 TProtocolFactory outputProtocolFactory,
-								 int maxThreads, LogDelegate logDel)
-			: base(processor, serverTransport, inputTransportFactory, outputTransportFactory,
-				  inputProtocolFactory, outputProtocolFactory, logDel)
-		{
-			this.maxThreads = maxThreads;
-			clientQueue = new Queue<TTransport>();
-			clientLock = new object();
-			clientThreads = new THashSet<Thread>();
-		}
-
-		/// <summary>
-		/// Use new Thread for each new client connection. block until numConnections < maxThreads
-		/// </summary>
-		public override void Serve()
-		{
-			try
-			{
-				//start worker thread
-				workerThread = new Thread(new ThreadStart(Execute));
-				workerThread.Start();
-				serverTransport.Listen();
-			}
-			catch (TTransportException ttx)
-			{
-				logDelegate("Error, could not listen on ServerTransport: " + ttx);
-				return;
-			}
-
-			while (!stop)
-			{
-				int failureCount = 0;
-				try
-				{
-					TTransport client = serverTransport.Accept();
-					lock (clientLock)
-					{
-						clientQueue.Enqueue(client);
-						Monitor.Pulse(clientLock);
-					}
-				}
-				catch (TTransportException ttx)
-				{
-					if (stop)
-					{
-						logDelegate("TThreadPoolServer was shutting down, caught " + ttx);
-					}
-					else
-					{
-						++failureCount;
-						logDelegate(ttx.ToString());
-					}
-
-				}
-			}
-
-			if (stop)
-			{
-				try
-				{
-					serverTransport.Close();
-				}
-				catch (TTransportException ttx)
-				{
-					logDelegate("TServeTransport failed on close: " + ttx.Message);
-				}
-				stop = false;
-			}
-		}
-
-		/// <summary>
-		/// Loops on processing a client forever
-		/// threadContext will be a TTransport instance
-		/// </summary>
-		/// <param name="threadContext"></param>
-		private void Execute()
-		{
-			while (!stop)
-			{
-				TTransport client;
-				Thread t;
-				lock (clientLock)
-				{
-					//don't dequeue if too many connections
-					while (clientThreads.Count >= maxThreads)
-					{
-						Monitor.Wait(clientLock);
-					}
-
-					while (clientQueue.Count == 0)
-					{
-						Monitor.Wait(clientLock);
-					}
-
-					client = clientQueue.Dequeue();
-					t = new Thread(new ParameterizedThreadStart(ClientWorker));
-					clientThreads.Add(t);
-				}
-				//start processing requests from client on new thread
-				t.Start(client);
-			}
-		}
-
-		private void ClientWorker(Object context)
-		{
-			TTransport client = (TTransport)context;
-			TTransport inputTransport = null;
-			TTransport outputTransport = null;
-			TProtocol inputProtocol = null;
-			TProtocol outputProtocol = null;
-			try
-			{
-        using (inputTransport = inputTransportFactory.GetTransport(client))
+        public int ClientThreadsCount
         {
-          using (outputTransport = outputTransportFactory.GetTransport(client))
-          {
-            inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
-            outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
-            while (processor.Process(inputProtocol, outputProtocol))
-            {
-              //keep processing requests until client disconnects
-            }
-          }
+            get { return clientThreads.Count; }
         }
-			}
-			catch (TTransportException)
-			{
-			}
-			catch (Exception x)
-			{
-				logDelegate("Error: " + x);
-			}
 
-			lock (clientLock)
-			{
-				clientThreads.Remove(Thread.CurrentThread);
-				Monitor.Pulse(clientLock);
-			}
-			return;
-		}
+        public TThreadedServer(TProcessor processor, TServerTransport serverTransport)
+            : this(new TSingletonProcessorFactory(processor), serverTransport,
+             new TTransportFactory(), new TTransportFactory(),
+             new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
+             DEFAULT_MAX_THREADS, DefaultLogDelegate)
+        {
+        }
 
-		public override void Stop()
-		{
-			stop = true;
-			serverTransport.Close();
-			//clean up all the threads myself
-			workerThread.Abort();
-			foreach (Thread t in clientThreads)
-			{
-				t.Abort();
-			}
-		}
-	}
+        public TThreadedServer(TProcessor processor, TServerTransport serverTransport, LogDelegate logDelegate)
+            : this(new TSingletonProcessorFactory(processor), serverTransport,
+             new TTransportFactory(), new TTransportFactory(),
+             new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
+             DEFAULT_MAX_THREADS, logDelegate)
+        {
+        }
+
+
+        public TThreadedServer(TProcessor processor,
+                     TServerTransport serverTransport,
+                     TTransportFactory transportFactory,
+                     TProtocolFactory protocolFactory)
+            : this(new TSingletonProcessorFactory(processor), serverTransport,
+             transportFactory, transportFactory,
+             protocolFactory, protocolFactory,
+             DEFAULT_MAX_THREADS, DefaultLogDelegate)
+        {
+        }
+
+        public TThreadedServer(TProcessorFactory processorFactory,
+               TServerTransport serverTransport,
+               TTransportFactory transportFactory,
+               TProtocolFactory protocolFactory)
+            : this(processorFactory, serverTransport,
+             transportFactory, transportFactory,
+             protocolFactory, protocolFactory,
+             DEFAULT_MAX_THREADS, DefaultLogDelegate)
+        {
+        }
+        public TThreadedServer(TProcessorFactory processorFactory,
+                     TServerTransport serverTransport,
+                     TTransportFactory inputTransportFactory,
+                     TTransportFactory outputTransportFactory,
+                     TProtocolFactory inputProtocolFactory,
+                     TProtocolFactory outputProtocolFactory,
+                     int maxThreads, LogDelegate logDel)
+          : base(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory,
+              inputProtocolFactory, outputProtocolFactory, logDel)
+        {
+            this.maxThreads = maxThreads;
+            clientQueue = new Queue<TTransport>();
+            clientLock = new object();
+            clientThreads = new THashSet<Thread>();
+        }
+
+        /// <summary>
+        /// Use new Thread for each new client connection. block until numConnections &lt; maxThreads.
+        /// </summary>
+        public override void Serve()
+        {
+            try
+            {
+                //start worker thread
+                workerThread = new Thread(new ThreadStart(Execute));
+                workerThread.Start();
+                serverTransport.Listen();
+            }
+            catch (TTransportException ttx)
+            {
+                logDelegate("Error, could not listen on ServerTransport: " + ttx);
+                return;
+            }
+
+            //Fire the preServe server event when server is up but before any client connections
+            if (serverEventHandler != null)
+                serverEventHandler.preServe();
+
+            while (!stop)
+            {
+                int failureCount = 0;
+                try
+                {
+                    TTransport client = serverTransport.Accept();
+                    lock (clientLock)
+                    {
+                        clientQueue.Enqueue(client);
+                        Monitor.Pulse(clientLock);
+                    }
+                }
+                catch (TTransportException ttx)
+                {
+                    if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted)
+                    {
+                        ++failureCount;
+                        logDelegate(ttx.ToString());
+                    }
+
+                }
+            }
+
+            if (stop)
+            {
+                try
+                {
+                    serverTransport.Close();
+                }
+                catch (TTransportException ttx)
+                {
+                    logDelegate("TServeTransport failed on close: " + ttx.Message);
+                }
+                stop = false;
+            }
+        }
+
+        /// <summary>
+        /// Loops on processing a client forever
+        /// </summary>
+        private void Execute()
+        {
+            while (!stop)
+            {
+                TTransport client;
+                Thread t;
+                lock (clientLock)
+                {
+                    //don't dequeue if too many connections
+                    while (clientThreads.Count >= maxThreads)
+                    {
+                        Monitor.Wait(clientLock);
+                    }
+
+                    while (clientQueue.Count == 0)
+                    {
+                        Monitor.Wait(clientLock);
+                    }
+
+                    client = clientQueue.Dequeue();
+                    t = new Thread(new ParameterizedThreadStart(ClientWorker));
+                    clientThreads.Add(t);
+                }
+                //start processing requests from client on new thread
+                t.Start(client);
+            }
+        }
+
+        private void ClientWorker(object context)
+        {
+            using (TTransport client = (TTransport)context)
+            {
+                TProcessor processor = processorFactory.GetProcessor(client);
+                TTransport inputTransport = null;
+                TTransport outputTransport = null;
+                TProtocol inputProtocol = null;
+                TProtocol outputProtocol = null;
+                object connectionContext = null;
+                try
+                {
+                    try
+                    {
+                        inputTransport = inputTransportFactory.GetTransport(client);
+                        outputTransport = outputTransportFactory.GetTransport(client);
+                        inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
+                        outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
+
+                        //Recover event handler (if any) and fire createContext server event when a client connects
+                        if (serverEventHandler != null)
+                            connectionContext = serverEventHandler.createContext(inputProtocol, outputProtocol);
+
+                        //Process client requests until client disconnects
+                        while (!stop)
+                        {
+                            if (!inputTransport.Peek())
+                                break;
+
+                            //Fire processContext server event
+                            //N.B. This is the pattern implemented in C++ and the event fires provisionally.
+                            //That is to say it may be many minutes between the event firing and the client request
+                            //actually arriving or the client may hang up without ever makeing a request.
+                            if (serverEventHandler != null)
+                                serverEventHandler.processContext(connectionContext, inputTransport);
+                            //Process client request (blocks until transport is readable)
+                            if (!processor.Process(inputProtocol, outputProtocol))
+                                break;
+                        }
+                    }
+                    catch (TTransportException)
+                    {
+                        //Usually a client disconnect, expected
+                    }
+                    catch (Exception x)
+                    {
+                        //Unexpected
+                        logDelegate("Error: " + x);
+                    }
+
+                    //Fire deleteContext server event after client disconnects
+                    if (serverEventHandler != null)
+                        serverEventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
+
+                    lock (clientLock)
+                    {
+                        clientThreads.Remove(Thread.CurrentThread);
+                        Monitor.Pulse(clientLock);
+                    }
+
+                }
+                finally
+                {
+                    //Close transports
+                    if (inputTransport != null)
+                        inputTransport.Close();
+                    if (outputTransport != null)
+                        outputTransport.Close();
+
+                    // disposable stuff should be disposed
+                    if (inputProtocol != null)
+                        inputProtocol.Dispose();
+                    if (outputProtocol != null)
+                        outputProtocol.Dispose();
+                }
+            }
+        }
+
+        public override void Stop()
+        {
+            stop = true;
+            serverTransport.Close();
+            //clean up all the threads myself
+            workerThread.Abort();
+            foreach (Thread t in clientThreads)
+            {
+                t.Abort();
+            }
+        }
+    }
 }
diff --git a/lib/csharp/src/TApplicationException.cs b/lib/csharp/src/TApplicationException.cs
index 4a1b2d2..8dd7ae5 100644
--- a/lib/csharp/src/TApplicationException.cs
+++ b/lib/csharp/src/TApplicationException.cs
@@ -26,116 +26,121 @@
 
 namespace Thrift
 {
-	public class TApplicationException : TException
-	{
-		protected ExceptionType type;
+    public class TApplicationException : TException
+    {
+        protected ExceptionType type;
 
-		public TApplicationException()
-		{
-		}
+        public TApplicationException()
+        {
+        }
 
-		public TApplicationException(ExceptionType type)
-		{
-			this.type = type;
-		}
+        public TApplicationException(ExceptionType type)
+        {
+            this.type = type;
+        }
 
-		public TApplicationException(ExceptionType type, string message)
-			: base(message)
-		{
-			this.type = type;
-		}
+        public TApplicationException(ExceptionType type, string message)
+            : base(message, null) // TApplicationException is serializable, but we never serialize InnerException
+        {
+            this.type = type;
+        }
 
-		public static TApplicationException Read(TProtocol iprot)
-		{
-			TField field;
+        public static TApplicationException Read(TProtocol iprot)
+        {
+            TField field;
 
-			string message = null;
-			ExceptionType type = ExceptionType.Unknown;
+            string message = null;
+            ExceptionType type = ExceptionType.Unknown;
 
-			iprot.ReadStructBegin();
-			while (true)
-			{
-				field = iprot.ReadFieldBegin();
-				if (field.Type == TType.Stop)
-				{
-					break;
-				}
+            iprot.ReadStructBegin();
+            while (true)
+            {
+                field = iprot.ReadFieldBegin();
+                if (field.Type == TType.Stop)
+                {
+                    break;
+                }
 
-				switch (field.ID)
-				{
-					case 1:
-						if (field.Type == TType.String)
-						{
-							message = iprot.ReadString();
-						}
-						else
-						{
-							TProtocolUtil.Skip(iprot, field.Type);
-						}
-						break;
-					case 2:
-						if (field.Type == TType.I32)
-						{
-							type = (ExceptionType)iprot.ReadI32();
-						}
-						else
-						{
-							TProtocolUtil.Skip(iprot, field.Type);
-						}
-						break;
-					default:
-						TProtocolUtil.Skip(iprot, field.Type);
-						break;
-				}
+                switch (field.ID)
+                {
+                    case 1:
+                        if (field.Type == TType.String)
+                        {
+                            message = iprot.ReadString();
+                        }
+                        else
+                        {
+                            TProtocolUtil.Skip(iprot, field.Type);
+                        }
+                        break;
+                    case 2:
+                        if (field.Type == TType.I32)
+                        {
+                            type = (ExceptionType)iprot.ReadI32();
+                        }
+                        else
+                        {
+                            TProtocolUtil.Skip(iprot, field.Type);
+                        }
+                        break;
+                    default:
+                        TProtocolUtil.Skip(iprot, field.Type);
+                        break;
+                }
 
-				iprot.ReadFieldEnd();
-			}
+                iprot.ReadFieldEnd();
+            }
 
-			iprot.ReadStructEnd();
+            iprot.ReadStructEnd();
 
-			return new TApplicationException(type, message);
-		}
+            return new TApplicationException(type, message);
+        }
 
-		public void Write(TProtocol oprot)
-		{
-			TStruct struc = new TStruct("TApplicationException");
-			TField field = new TField();
+        public void Write(TProtocol oprot)
+        {
+            TStruct struc = new TStruct("TApplicationException");
+            TField field = new TField();
 
-			oprot.WriteStructBegin(struc);
+            oprot.WriteStructBegin(struc);
 
-			if (!String.IsNullOrEmpty(Message))
-			{
-				field.Name = "message";
-				field.Type = TType.String;
-				field.ID = 1;
-				oprot.WriteFieldBegin(field);
-				oprot.WriteString(Message);
-				oprot.WriteFieldEnd();
-			}
+            if (!string.IsNullOrEmpty(Message))
+            {
+                field.Name = "message";
+                field.Type = TType.String;
+                field.ID = 1;
+                oprot.WriteFieldBegin(field);
+                oprot.WriteString(Message);
+                oprot.WriteFieldEnd();
+            }
 
-			field.Name = "type";
-			field.Type = TType.I32;
-			field.ID = 2;
-			oprot.WriteFieldBegin(field);
-			oprot.WriteI32((int)type);
-			oprot.WriteFieldEnd();
-			oprot.WriteFieldStop();
-			oprot.WriteStructEnd();
-		}
+            field.Name = "type";
+            field.Type = TType.I32;
+            field.ID = 2;
+            oprot.WriteFieldBegin(field);
+            oprot.WriteI32((int)type);
+            oprot.WriteFieldEnd();
+            oprot.WriteFieldStop();
+            oprot.WriteStructEnd();
+        }
 
-		public enum ExceptionType
-		{
-			Unknown,
-			UnknownMethod,
-			InvalidMessageType,
-			WrongMethodName,
-			BadSequenceID,
-			MissingResult,
-			InternalError,
-			ProtocolError,
-			InvalidTransform,
-			InvalidProtocol,
-			UnsupportedClientType
-		}
-	}
+        public enum ExceptionType
+        {
+            Unknown,
+            UnknownMethod,
+            InvalidMessageType,
+            WrongMethodName,
+            BadSequenceID,
+            MissingResult,
+            InternalError,
+            ProtocolError,
+            InvalidTransform,
+            InvalidProtocol,
+            UnsupportedClientType
+        }
+
+        public ExceptionType Type
+        {
+            get { return type; }
+        }
+    }
 }
diff --git a/lib/csharp/src/TAsyncProcessor.cs b/lib/csharp/src/TAsyncProcessor.cs
new file mode 100644
index 0000000..ab43225
--- /dev/null
+++ b/lib/csharp/src/TAsyncProcessor.cs
@@ -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.
+ */
+
+using System.Threading.Tasks;
+using Thrift.Protocol;
+
+namespace Thrift
+{
+    /// <summary>
+    /// Processes a message asynchronously.
+    /// </summary>
+    public interface TAsyncProcessor
+    {
+        /// <summary>
+        /// Processes the next part of the message.
+        /// </summary>
+        /// <param name="iprot">The input protocol.</param>
+        /// <param name="oprot">The output protocol.</param>
+        /// <returns>true if there's more to process, false otherwise.</returns>
+        Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot);
+    }
+}
diff --git a/lib/csharp/src/TControllingHandler.cs b/lib/csharp/src/TControllingHandler.cs
new file mode 100644
index 0000000..7b5203a
--- /dev/null
+++ b/lib/csharp/src/TControllingHandler.cs
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+using System;
+using Thrift.Server;
+
+namespace Thrift
+{
+    public interface TControllingHandler
+    {
+        TServer server { get; set; }
+    }
+}
diff --git a/lib/csharp/src/TException.cs b/lib/csharp/src/TException.cs
index a99bfa8..aa9a210 100644
--- a/lib/csharp/src/TException.cs
+++ b/lib/csharp/src/TException.cs
@@ -25,16 +25,16 @@
 
 namespace Thrift
 {
-	public class TException : Exception
-	{
-		public TException()
-		{
-		}
+    public class TException : Exception
+    {
+        public TException()
+        {
+        }
 
-		public TException( string message)
-			: base(message)
-		{
-		}
+        public TException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
 
-	}
+    }
 }
diff --git a/lib/csharp/src/TProcessor.cs b/lib/csharp/src/TProcessor.cs
index dc1b795..71ce755 100644
--- a/lib/csharp/src/TProcessor.cs
+++ b/lib/csharp/src/TProcessor.cs
@@ -26,8 +26,8 @@
 
 namespace Thrift
 {
-	public interface TProcessor
-	{
-		bool Process(TProtocol iprot, TProtocol oprot);
-	}
+    public interface TProcessor
+    {
+        bool Process(TProtocol iprot, TProtocol oprot);
+    }
 }
diff --git a/lib/csharp/src/TProcessorFactory.cs b/lib/csharp/src/TProcessorFactory.cs
new file mode 100644
index 0000000..fdf631b
--- /dev/null
+++ b/lib/csharp/src/TProcessorFactory.cs
@@ -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.
+ */
+
+using System;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace Thrift
+{
+    public interface TProcessorFactory
+    {
+        TProcessor GetProcessor(TTransport trans, TServer server = null);
+    }
+}
diff --git a/lib/csharp/src/TPrototypeProcessorFactory.cs b/lib/csharp/src/TPrototypeProcessorFactory.cs
new file mode 100644
index 0000000..0b47261
--- /dev/null
+++ b/lib/csharp/src/TPrototypeProcessorFactory.cs
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace Thrift
+{
+    public class TPrototypeProcessorFactory<P, H> : TProcessorFactory where P : TProcessor
+    {
+        object[] handlerArgs = null;
+
+        public TPrototypeProcessorFactory()
+        {
+            handlerArgs = new object[0];
+        }
+
+        public TPrototypeProcessorFactory(params object[] handlerArgs)
+        {
+            this.handlerArgs = handlerArgs;
+        }
+
+        public TProcessor GetProcessor(TTransport trans, TServer server = null)
+        {
+            H handler = (H)Activator.CreateInstance(typeof(H), handlerArgs);
+
+            TControllingHandler handlerServerRef = handler as TControllingHandler;
+            if (handlerServerRef != null)
+            {
+                handlerServerRef.server = server;
+            }
+            return Activator.CreateInstance(typeof(P), new object[] { handler }) as TProcessor;
+        }
+    }
+}
diff --git a/lib/csharp/src/TSingletonProcessorFactory.cs b/lib/csharp/src/TSingletonProcessorFactory.cs
new file mode 100644
index 0000000..ed2897b
--- /dev/null
+++ b/lib/csharp/src/TSingletonProcessorFactory.cs
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace Thrift
+{
+    public class TSingletonProcessorFactory : TProcessorFactory
+    {
+        private readonly TProcessor processor_;
+
+        public TSingletonProcessorFactory(TProcessor processor)
+        {
+            processor_ = processor;
+        }
+
+        public TProcessor GetProcessor(TTransport trans, TServer server = null)
+        {
+            return processor_;
+        }
+    }
+}
diff --git a/lib/csharp/src/Thrift.45.csproj b/lib/csharp/src/Thrift.45.csproj
new file mode 100644
index 0000000..4e28b25
--- /dev/null
+++ b/lib/csharp/src/Thrift.45.csproj
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{EBCE35DA-CF6A-42BC-A357-A9C09B534299}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Thrift</RootNamespace>
+    <AssemblyName>Thrift45</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>portable</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;NET45</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>portable</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE;NET45</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Web" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Collections\TCollections.cs" />
+    <Compile Include="Collections\THashSet.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Protocol\TAbstractBase.cs" />
+    <Compile Include="Protocol\TBase.cs" />
+    <Compile Include="Protocol\TBase64Utils.cs" />
+    <Compile Include="Protocol\TBinaryProtocol.cs" />
+    <Compile Include="Protocol\TCompactProtocol.cs" />
+    <Compile Include="Protocol\TField.cs" />
+    <Compile Include="Protocol\TJSONProtocol.cs" />
+    <Compile Include="Protocol\TList.cs" />
+    <Compile Include="Protocol\TMap.cs" />
+    <Compile Include="Protocol\TMessage.cs" />
+    <Compile Include="Protocol\TMessageType.cs" />
+    <Compile Include="Protocol\TMultiplexedProcessor.cs" />
+    <Compile Include="Protocol\TMultiplexedProtocol.cs" />
+    <Compile Include="Protocol\TProtocol.cs" />
+    <Compile Include="Protocol\TProtocolDecorator.cs" />
+    <Compile Include="Protocol\TProtocolException.cs" />
+    <Compile Include="Protocol\TProtocolFactory.cs" />
+    <Compile Include="Protocol\TProtocolUtil.cs" />
+    <Compile Include="Protocol\TSet.cs" />
+    <Compile Include="Protocol\TStruct.cs" />
+    <Compile Include="Protocol\TType.cs" />
+    <Compile Include="Server\TServer.cs" />
+    <Compile Include="Server\TServerEventHandler.cs" />
+    <Compile Include="Server\TSimpleServer.cs" />
+    <Compile Include="Server\TThreadedServer.cs" />
+    <Compile Include="Server\TThreadPoolServer.cs" />
+    <Compile Include="TApplicationException.cs" />
+    <Compile Include="TAsyncProcessor.cs" />
+    <Compile Include="TControllingHandler.cs" />
+    <Compile Include="TException.cs" />
+    <Compile Include="TProcessor.cs" />
+    <Compile Include="TProcessorFactory.cs" />
+    <Compile Include="TPrototypeProcessorFactory.cs" />
+    <Compile Include="Transport\TBufferedTransport.cs" />
+    <Compile Include="Transport\TFramedTransport.cs" />
+    <Compile Include="Transport\THttpClient.cs" />
+    <Compile Include="Transport\THttpHandler.cs" />
+    <Compile Include="Transport\THttpTaskAsyncHandler.cs" />
+    <Compile Include="Transport\TMemoryBuffer.cs" />
+    <Compile Include="Transport\TNamedPipeClientTransport.cs" />
+    <Compile Include="Transport\TNamedPipeServerTransport.cs" />
+    <Compile Include="Transport\TServerSocket.cs" />
+    <Compile Include="Transport\TServerTransport.cs" />
+    <Compile Include="Transport\TSilverlightSocket.cs" />
+    <Compile Include="Transport\TSocket.cs" />
+    <Compile Include="Transport\TSocketVersionizer.cs" />
+    <Compile Include="Transport\TStreamTransport.cs" />
+    <Compile Include="Transport\TTLSServerSocket.cs" />
+    <Compile Include="Transport\TTLSSocket.cs" />
+    <Compile Include="Transport\TTransport.cs" />
+    <Compile Include="Transport\TTransportException.cs" />
+    <Compile Include="Transport\TTransportFactory.cs" />
+    <Compile Include="TSingletonProcessorFactory.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Server\Collections\" />
+    <Folder Include="Server\Protocol\" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/lib/csharp/src/Thrift.WP7.csproj b/lib/csharp/src/Thrift.WP7.csproj
deleted file mode 100644
index 2b2147e..0000000
--- a/lib/csharp/src/Thrift.WP7.csproj
+++ /dev/null
@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
--->
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>10.0.20506</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{DF58BDB0-2457-4A52-9981-65A0E8B50833}</ProjectGuid>
-    <ProjectTypeGuids>{C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>Thrift.WP7</RootNamespace>
-    <AssemblyName>Thrift.WP7</AssemblyName>
-    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
-    <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
-    <TargetFrameworkProfile>WindowsPhone</TargetFrameworkProfile>
-    <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
-    <SilverlightApplication>false</SilverlightApplication>
-    <ValidateXaml>true</ValidateXaml>
-    <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>Bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
-    <NoStdLib>true</NoStdLib>
-    <NoConfig>true</NoConfig>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>Bin\Release</OutputPath>
-    <DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
-    <NoStdLib>true</NoStdLib>
-    <NoConfig>true</NoConfig>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="Microsoft.Phone" />
-    <Reference Include="Microsoft.Phone.Interop" />
-    <Reference Include="System.Runtime.Serialization" />
-    <Reference Include="System.Servicemodel.Web" />
-    <Reference Include="System.Windows" />
-    <Reference Include="system" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml" />
-    <Reference Include="System.Net" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Collections\TCollections.cs" />
-    <Compile Include="Collections\THashSet.cs" />
-    <Compile Include="Properties\AssemblyInfo.WP7.cs" />
-    <Compile Include="Protocol\TAbstractBase.cs" />
-    <Compile Include="Protocol\TBase.cs" />
-    <Compile Include="Protocol\TBase64Utils.cs" />
-    <Compile Include="Protocol\TBinaryProtocol.cs" />
-    <Compile Include="Protocol\TField.cs" />
-    <Compile Include="Protocol\TJSONProtocol.cs" />
-    <Compile Include="Protocol\TList.cs" />
-    <Compile Include="Protocol\TMap.cs" />
-    <Compile Include="Protocol\TMessage.cs" />
-    <Compile Include="Protocol\TMessageType.cs" />
-    <Compile Include="Protocol\TMultiplexedProcessor.cs" />
-    <Compile Include="Protocol\TMultiplexedProtocol.cs" />
-    <Compile Include="Protocol\TProtocol.cs" />
-    <Compile Include="Protocol\TProtocolDecorator.cs" />
-    <Compile Include="Protocol\TProtocolException.cs" />
-    <Compile Include="Protocol\TProtocolFactory.cs" />
-    <Compile Include="Protocol\TProtocolUtil.cs" />
-    <Compile Include="Protocol\TSet.cs" />
-    <Compile Include="Protocol\TStruct.cs" />
-    <Compile Include="Protocol\TType.cs" />
-    <Compile Include="TException.cs" />
-    <Compile Include="TApplicationException.cs" />
-    <Compile Include="TProcessor.cs" />
-    <Compile Include="Transport\TFramedTransport.cs" />
-    <Compile Include="Transport\THttpClient.cs" />
-    <Compile Include="Transport\TStreamTransport.cs" />
-    <Compile Include="Transport\TTransport.cs" />
-    <Compile Include="Transport\TTransportException.cs" />
-    <Compile Include="Transport\TTransportFactory.cs" />
-    <Compile Include="Transport\TMemoryBuffer.cs" />
-  </ItemGroup>
-  <Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.$(TargetFrameworkProfile).Overrides.targets" />
-  <Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.CSharp.targets" />
-  <ProjectExtensions />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>
\ No newline at end of file
diff --git a/lib/csharp/src/Thrift.csproj b/lib/csharp/src/Thrift.csproj
index 439b960..bf65569 100644
--- a/lib/csharp/src/Thrift.csproj
+++ b/lib/csharp/src/Thrift.csproj
@@ -1,145 +1,157 @@
-<?xml version="1.0" encoding="utf-8"?>

-<!--

-  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.

--->

-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

-  <PropertyGroup>

-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

-    <ProjectGuid>{499EB63C-D74C-47E8-AE48-A2FC94538E9D}</ProjectGuid>

-    <ProductVersion>9.0.21022</ProductVersion>

-    <SchemaVersion>2.0</SchemaVersion>

-    <OutputType>Library</OutputType>

-    <NoStandardLibraries>false</NoStandardLibraries>

-    <AssemblyName>Thrift</AssemblyName>

-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>

-    <FileAlignment>512</FileAlignment>

-    <RootNamespace>Thrift</RootNamespace>

-    <FileUpgradeFlags>

-    </FileUpgradeFlags>

-    <OldToolsVersion>3.5</OldToolsVersion>

-    <UpgradeBackupLocation />

-    <PublishUrl>publish\</PublishUrl>

-    <Install>true</Install>

-    <InstallFrom>Disk</InstallFrom>

-    <UpdateEnabled>false</UpdateEnabled>

-    <UpdateMode>Foreground</UpdateMode>

-    <UpdateInterval>7</UpdateInterval>

-    <UpdateIntervalUnits>Days</UpdateIntervalUnits>

-    <UpdatePeriodically>false</UpdatePeriodically>

-    <UpdateRequired>false</UpdateRequired>

-    <MapFileExtensions>true</MapFileExtensions>

-    <ApplicationRevision>0</ApplicationRevision>

-    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>

-    <IsWebBootstrapper>false</IsWebBootstrapper>

-    <UseApplicationTrust>false</UseApplicationTrust>

-    <BootstrapperEnabled>true</BootstrapperEnabled>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

-    <DebugSymbols>true</DebugSymbols>

-    <DebugType>full</DebugType>

-    <Optimize>false</Optimize>

-    <OutputPath>bin\Debug\</OutputPath>

-    <DefineConstants>DEBUG;TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

-    <DebugType>pdbonly</DebugType>

-    <Optimize>true</Optimize>

-    <OutputPath>bin\Release\</OutputPath>

-    <DefineConstants>TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>

-  </PropertyGroup>

-  <ItemGroup>

-    <Reference Include="System" />

-    <Reference Include="System.Core">

-      <RequiredTargetFramework>3.5</RequiredTargetFramework>

-    </Reference>

-    <Reference Include="System.Web" />

-  </ItemGroup>

-  <ItemGroup>

-    <Compile Include="Collections\TCollections.cs" />

-    <Compile Include="Collections\THashSet.cs" />

-    <Compile Include="Properties\AssemblyInfo.cs" />

-    <Compile Include="Protocol\TAbstractBase.cs" />

-    <Compile Include="Protocol\TBase.cs" />

-    <Compile Include="Protocol\TBase64Utils.cs" />

-    <Compile Include="Protocol\TBinaryProtocol.cs" />

-    <Compile Include="Protocol\TCompactProtocol.cs" />

-    <Compile Include="Protocol\TField.cs" />

-    <Compile Include="Protocol\TJSONProtocol.cs" />

-    <Compile Include="Protocol\TList.cs" />

-    <Compile Include="Protocol\TMap.cs" />

-    <Compile Include="Protocol\TMessage.cs" />

-    <Compile Include="Protocol\TMessageType.cs" />

-    <Compile Include="Protocol\TMultiplexedProcessor.cs" />

-    <Compile Include="Protocol\TMultiplexedProtocol.cs" />

-    <Compile Include="Protocol\TProtocol.cs" />

-    <Compile Include="Protocol\TProtocolDecorator.cs" />

-    <Compile Include="Protocol\TProtocolException.cs" />

-    <Compile Include="Protocol\TProtocolFactory.cs" />

-    <Compile Include="Protocol\TProtocolUtil.cs" />

-    <Compile Include="Protocol\TSet.cs" />

-    <Compile Include="Protocol\TStruct.cs" />

-    <Compile Include="Protocol\TType.cs" />

-    <Compile Include="Server\TThreadedServer.cs" />

-    <Compile Include="Server\TServer.cs" />

-    <Compile Include="Server\TSimpleServer.cs" />

-    <Compile Include="Server\TThreadPoolServer.cs" />

-    <Compile Include="TException.cs" />

-    <Compile Include="TApplicationException.cs" />

-    <Compile Include="TProcessor.cs" />

-    <Compile Include="Transport\TBufferedTransport.cs" />

-    <Compile Include="Transport\TFramedTransport.cs" />

-    <Compile Include="Transport\THttpClient.cs" />

-    <Compile Include="Transport\THttpHandler.cs" />

-    <Compile Include="Transport\TServerSocket.cs" />

-    <Compile Include="Transport\TServerTransport.cs" />

-    <Compile Include="Transport\TSocket.cs" />

-    <Compile Include="Transport\TStreamTransport.cs" />

-    <Compile Include="Transport\TTransport.cs" />

-    <Compile Include="Transport\TTransportException.cs" />

-    <Compile Include="Transport\TTransportFactory.cs" />

-    <Compile Include="Transport\TMemoryBuffer.cs" />

-  </ItemGroup>

-  <ItemGroup>

-    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">

-      <Visible>False</Visible>

-      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>

-      <Install>false</Install>

-    </BootstrapperPackage>

-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">

-      <Visible>False</Visible>

-      <ProductName>.NET Framework 3.5 SP1</ProductName>

-      <Install>true</Install>

-    </BootstrapperPackage>

-    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">

-      <Visible>False</Visible>

-      <ProductName>Windows Installer 3.1</ProductName>

-      <Install>true</Install>

-    </BootstrapperPackage>

-  </ItemGroup>

-  <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />

-  <ProjectExtensions>

-    <VisualStudio AllowExistingFolder="true" />

-  </ProjectExtensions>

-</Project>

+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{499EB63C-D74C-47E8-AE48-A2FC94538E9D}</ProjectGuid>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <OutputType>Library</OutputType>
+    <NoStandardLibraries>false</NoStandardLibraries>
+    <AssemblyName>Thrift</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <RootNamespace>Thrift</RootNamespace>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.0</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>portable</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>portable</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>
+    </DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Web" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Collections\TCollections.cs" />
+    <Compile Include="Collections\THashSet.cs" />
+    <Compile Include="Net35\ExtensionsNet35.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Protocol\TAbstractBase.cs" />
+    <Compile Include="Protocol\TBase.cs" />
+    <Compile Include="Protocol\TBase64Utils.cs" />
+    <Compile Include="Protocol\TBinaryProtocol.cs" />
+    <Compile Include="Protocol\TCompactProtocol.cs" />
+    <Compile Include="Protocol\TField.cs" />
+    <Compile Include="Protocol\TJSONProtocol.cs" />
+    <Compile Include="Protocol\TList.cs" />
+    <Compile Include="Protocol\TMap.cs" />
+    <Compile Include="Protocol\TMessage.cs" />
+    <Compile Include="Protocol\TMessageType.cs" />
+    <Compile Include="Protocol\TMultiplexedProcessor.cs" />
+    <Compile Include="Protocol\TMultiplexedProtocol.cs" />
+    <Compile Include="Protocol\TProtocol.cs" />
+    <Compile Include="Protocol\TProtocolDecorator.cs" />
+    <Compile Include="Protocol\TProtocolException.cs" />
+    <Compile Include="Protocol\TProtocolFactory.cs" />
+    <Compile Include="Protocol\TProtocolUtil.cs" />
+    <Compile Include="Protocol\TSet.cs" />
+    <Compile Include="Protocol\TStruct.cs" />
+    <Compile Include="Protocol\TType.cs" />
+    <Compile Include="Server\TServer.cs" />
+    <Compile Include="Server\TServerEventHandler.cs" />
+    <Compile Include="Server\TSimpleServer.cs" />
+    <Compile Include="Server\TThreadedServer.cs" />
+    <Compile Include="Server\TThreadPoolServer.cs" />
+    <Compile Include="TApplicationException.cs" />
+    <Compile Include="TControllingHandler.cs" />
+    <Compile Include="TException.cs" />
+    <Compile Include="TProcessor.cs" />
+    <Compile Include="TProcessorFactory.cs" />
+    <Compile Include="TPrototypeProcessorFactory.cs" />
+    <Compile Include="Transport\TBufferedTransport.cs" />
+    <Compile Include="Transport\TFramedTransport.cs" />
+    <Compile Include="Transport\THttpClient.cs" />
+    <Compile Include="Transport\THttpHandler.cs" />
+    <Compile Include="Transport\TMemoryBuffer.cs" />
+    <Compile Include="Transport\TNamedPipeClientTransport.cs" />
+    <Compile Include="Transport\TNamedPipeServerTransport.cs" />
+    <Compile Include="Transport\TServerSocket.cs" />
+    <Compile Include="Transport\TServerTransport.cs" />
+    <Compile Include="Transport\TSocket.cs" />
+    <Compile Include="Transport\TSocketVersionizer.cs" />
+    <Compile Include="Transport\TStreamTransport.cs" />
+    <Compile Include="Transport\TTLSServerSocket.cs" />
+    <Compile Include="Transport\TTLSSocket.cs" />
+    <Compile Include="Transport\TTransport.cs" />
+    <Compile Include="Transport\TTransportException.cs" />
+    <Compile Include="Transport\TTransportFactory.cs" />
+    <Compile Include="TSingletonProcessorFactory.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
+  <ProjectExtensions>
+    <VisualStudio AllowExistingFolder="true" />
+  </ProjectExtensions>
+</Project>
\ No newline at end of file
diff --git a/lib/csharp/src/Thrift.sln b/lib/csharp/src/Thrift.sln
index ee0a3e7..a29e468 100644
--- a/lib/csharp/src/Thrift.sln
+++ b/lib/csharp/src/Thrift.sln
@@ -4,12 +4,13 @@
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftTest", "..\test\ThriftTest\ThriftTest.csproj", "{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}"
-	ProjectSection(ProjectDependencies) = postProject
-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D} = {499EB63C-D74C-47E8-AE48-A2FC94538E9D}
-	EndProjectSection
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftMSBuildTask", "..\ThriftMSBuildTask\ThriftMSBuildTask.csproj", "{EC0A0231-66EA-4593-A792-C6CA3BB8668E}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift.45", "Thrift.45.csproj", "{EBCE35DA-CF6A-42BC-A357-A9C09B534299}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftMVCTest", "..\test\ThriftMVCTest\ThriftMVCTest.csproj", "{891B4487-C7BA-427E-BBC8-4C596C229A10}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -28,11 +29,19 @@
 		{EC0A0231-66EA-4593-A792-C6CA3BB8668E}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{EC0A0231-66EA-4593-A792-C6CA3BB8668E}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{EC0A0231-66EA-4593-A792-C6CA3BB8668E}.Release|Any CPU.Build.0 = Release|Any CPU
-	EndGlobalSection
-	GlobalSection(MonoDevelopProperties) = preSolution
-		StartupItem = Thrift.csproj
+		{EBCE35DA-CF6A-42BC-A357-A9C09B534299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EBCE35DA-CF6A-42BC-A357-A9C09B534299}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EBCE35DA-CF6A-42BC-A357-A9C09B534299}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EBCE35DA-CF6A-42BC-A357-A9C09B534299}.Release|Any CPU.Build.0 = Release|Any CPU
+		{891B4487-C7BA-427E-BBC8-4C596C229A10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{891B4487-C7BA-427E-BBC8-4C596C229A10}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{891B4487-C7BA-427E-BBC8-4C596C229A10}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{891B4487-C7BA-427E-BBC8-4C596C229A10}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
+	GlobalSection(MonoDevelopProperties) = preSolution
+		        StartupItem = Thrift.csproj
+	EndGlobalSection
 EndGlobal
diff --git a/lib/csharp/src/Transport/TBufferedTransport.cs b/lib/csharp/src/Transport/TBufferedTransport.cs
index 14b5db0..8870988 100644
--- a/lib/csharp/src/Transport/TBufferedTransport.cs
+++ b/lib/csharp/src/Transport/TBufferedTransport.cs
@@ -22,99 +22,173 @@
 
 namespace Thrift.Transport
 {
-  public class TBufferedTransport : TTransport, IDisposable
-	{
-		private BufferedStream inputBuffer;
-		private BufferedStream outputBuffer;
-		private int bufSize;
-		private TStreamTransport transport;
-
-		public TBufferedTransport(TStreamTransport transport)
-			:this(transport, 1024)
-		{
-
-		}
-
-		public TBufferedTransport(TStreamTransport transport, int bufSize)
-		{
-			this.bufSize = bufSize;
-			this.transport = transport;
-			InitBuffers();
-		}
-
-		private void InitBuffers()
-		{
-			if (transport.InputStream != null)
-			{
-				inputBuffer = new BufferedStream(transport.InputStream, bufSize);
-			}
-			if (transport.OutputStream != null)
-			{
-				outputBuffer = new BufferedStream(transport.OutputStream, bufSize);
-			}
-		}
-
-		public TTransport UnderlyingTransport
-		{
-			get { return transport; }
-		}
-
-		public override bool IsOpen
-		{
-			get { return transport.IsOpen; }
-		}
-
-		public override void Open()
-		{
-			transport.Open();
-			InitBuffers();
-		}
-
-		public override void Close()
-		{
-			if (inputBuffer != null && inputBuffer.CanRead)
-			{
-				inputBuffer.Close();
-			}
-			if (outputBuffer != null && outputBuffer.CanWrite)
-			{
-				outputBuffer.Close();
-			}
-		}
-
-		public override int Read(byte[] buf, int off, int len)
-		{
-			return inputBuffer.Read(buf, off, len);
-		}
-
-		public override void Write(byte[] buf, int off, int len)
-		{
-			outputBuffer.Write(buf, off, len);
-		}
-
-		public override void Flush()
-		{
-			outputBuffer.Flush();
-		}
-
-    #region " IDisposable Support "
-    private bool _IsDisposed;
-
-    // IDisposable
-    protected override void Dispose(bool disposing)
+    public class TBufferedTransport : TTransport, IDisposable
     {
-      if (!_IsDisposed)
-      {
-        if (disposing)
+        private readonly int bufSize;
+        private readonly MemoryStream inputBuffer = new MemoryStream(0);
+        private readonly MemoryStream outputBuffer = new MemoryStream(0);
+        private readonly TTransport transport;
+
+        public TBufferedTransport(TTransport transport, int bufSize = 1024)
         {
-          if (inputBuffer != null)
-            inputBuffer.Dispose();
-          if (outputBuffer != null)
-            outputBuffer.Dispose();
+            if (transport == null)
+                throw new ArgumentNullException("transport");
+            if (bufSize <= 0)
+                throw new ArgumentException("bufSize", "Buffer size must be a positive number.");
+            this.transport = transport;
+            this.bufSize = bufSize;
         }
-      }
-      _IsDisposed = true;
+
+        public TTransport UnderlyingTransport
+        {
+            get
+            {
+                CheckNotDisposed();
+                return transport;
+            }
+        }
+
+        public override bool IsOpen
+        {
+            get
+            {
+                // We can legitimately throw here but be nice a bit.
+                // CheckNotDisposed();
+                return !_IsDisposed && transport.IsOpen;
+            }
+        }
+
+        public override void Open()
+        {
+            CheckNotDisposed();
+            transport.Open();
+        }
+
+        public override void Close()
+        {
+            CheckNotDisposed();
+            transport.Close();
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            CheckNotDisposed();
+            ValidateBufferArgs(buf, off, len);
+            if (!IsOpen)
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+
+            if (inputBuffer.Capacity < bufSize)
+                inputBuffer.Capacity = bufSize;
+
+            while (true)
+            {
+                int got = inputBuffer.Read(buf, off, len);
+                if (got > 0)
+                    return got;
+
+                inputBuffer.Seek(0, SeekOrigin.Begin);
+                inputBuffer.SetLength(inputBuffer.Capacity);
+                int filled = transport.Read(inputBuffer.GetBuffer(), 0, (int)inputBuffer.Length);
+                inputBuffer.SetLength(filled);
+                if (filled == 0)
+                    return 0;
+            }
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            CheckNotDisposed();
+            ValidateBufferArgs(buf, off, len);
+            if (!IsOpen)
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            // Relative offset from "off" argument
+            int offset = 0;
+            if (outputBuffer.Length > 0)
+            {
+                int capa = (int)(outputBuffer.Capacity - outputBuffer.Length);
+                int writeSize = capa <= len ? capa : len;
+                outputBuffer.Write(buf, off, writeSize);
+                offset += writeSize;
+                if (writeSize == capa)
+                {
+                    transport.Write(outputBuffer.GetBuffer(), 0, (int)outputBuffer.Length);
+                    outputBuffer.SetLength(0);
+                }
+            }
+            while (len - offset >= bufSize)
+            {
+                transport.Write(buf, off + offset, bufSize);
+                offset += bufSize;
+            }
+            int remain = len - offset;
+            if (remain > 0)
+            {
+                if (outputBuffer.Capacity < bufSize)
+                    outputBuffer.Capacity = bufSize;
+                outputBuffer.Write(buf, off + offset, remain);
+            }
+        }
+
+        private void InternalFlush()
+        {
+            if (!IsOpen)
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            if (outputBuffer.Length > 0)
+            {
+                transport.Write(outputBuffer.GetBuffer(), 0, (int)outputBuffer.Length);
+                outputBuffer.SetLength(0);
+            }
+        }
+
+        public override void Flush()
+        {
+            CheckNotDisposed();
+            InternalFlush();
+
+            transport.Flush();
+        }
+
+        public override IAsyncResult BeginFlush(AsyncCallback callback, object state)
+        {
+            CheckNotDisposed();
+            InternalFlush();
+
+            return transport.BeginFlush( callback, state);
+        }
+
+        public override void EndFlush(IAsyncResult asyncResult)
+        {
+            transport.EndFlush( asyncResult);
+        }
+
+
+
+        protected void CheckNotDisposed()
+        {
+            if (_IsDisposed)
+                throw new ObjectDisposedException("TBufferedTransport");
+        }
+
+        #region " IDisposable Support "
+        protected bool _IsDisposed { get; private set; }
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (inputBuffer != null)
+                        inputBuffer.Dispose();
+                    if (outputBuffer != null)
+                        outputBuffer.Dispose();
+                    if (transport != null)
+                        transport.Dispose();
+                }
+            }
+            _IsDisposed = true;
+        }
+        #endregion
     }
-    #endregion
-  }
 }
diff --git a/lib/csharp/src/Transport/TFramedTransport.cs b/lib/csharp/src/Transport/TFramedTransport.cs
index 3d43112..a746a32 100644
--- a/lib/csharp/src/Transport/TFramedTransport.cs
+++ b/lib/csharp/src/Transport/TFramedTransport.cs
@@ -21,135 +21,185 @@
 
 namespace Thrift.Transport
 {
-  public class TFramedTransport : TTransport, IDisposable
-	{
-		protected TTransport transport = null;
-		protected MemoryStream writeBuffer;
-		protected MemoryStream readBuffer = null;
-
-		private const int header_size = 4;
-		private static byte[] header_dummy = new byte[header_size]; // used as header placeholder while initilizing new write buffer
-
-		public class Factory : TTransportFactory
-		{
-			public override TTransport GetTransport(TTransport trans)
-			{
-				return new TFramedTransport(trans);
-			}
-		}
-
-		public TFramedTransport()
-		{
-			InitWriteBuffer();
-		}
-
-		public TFramedTransport(TTransport transport) : this()
-		{
-			this.transport = transport;
-		}
-
-		public override void Open()
-		{
-			transport.Open();
-		}
-
-		public override bool IsOpen
-		{
-			get
-			{
-				return transport.IsOpen;
-			}
-		}
-
-		public override void Close()
-		{
-			transport.Close();
-		}
-
-		public override int Read(byte[] buf, int off, int len)
-		{
-			if (readBuffer != null)
-			{
-				int got = readBuffer.Read(buf, off, len);
-				if (got > 0)
-				{
-					return got;
-				}
-			}
-
-			// Read another frame of data
-			ReadFrame();
-
-			return readBuffer.Read(buf, off, len);
-		}
-
-		private void ReadFrame()
-		{
-			byte[] i32rd = new byte[header_size];
-			transport.ReadAll(i32rd, 0, header_size);
-			int size =
-				((i32rd[0] & 0xff) << 24) |
-				((i32rd[1] & 0xff) << 16) |
-				((i32rd[2] & 0xff) <<  8) |
-				((i32rd[3] & 0xff));
-
-
-			byte[] buff = new byte[size];
-			transport.ReadAll(buff, 0, size);
-			readBuffer = new MemoryStream(buff);
-		}
-
-		public override void Write(byte[] buf, int off, int len)
-		{
-			writeBuffer.Write(buf, off, len);
-		}
-
-		public override void Flush()
-		{
-			byte[] buf = writeBuffer.GetBuffer();
-			int len = (int)writeBuffer.Length;
-			int data_len = len - header_size;
-			if ( data_len < 0 )
-				throw new System.InvalidOperationException (); // logic error actually
-
-			InitWriteBuffer();
-
-			// Inject message header into the reserved buffer space
-			buf[0] = (byte)(0xff & (data_len >> 24));
-			buf[1] = (byte)(0xff & (data_len >> 16));
-			buf[2] = (byte)(0xff & (data_len >> 8));
-			buf[3] = (byte)(0xff & (data_len));
-
-			// Send the entire message at once
-			transport.Write(buf, 0, len);
-
-			transport.Flush();
-		}
-
-		private void InitWriteBuffer ()
-		{
-			// Create new buffer instance
-			writeBuffer = new MemoryStream(1024);
-
-			// Reserve space for message header to be put right before sending it out
-			writeBuffer.Write ( header_dummy, 0, header_size );
-		}
-    #region " IDisposable Support "
-    private bool _IsDisposed;
-
-    // IDisposable
-    protected override void Dispose(bool disposing)
+    public class TFramedTransport : TTransport, IDisposable
     {
-      if (!_IsDisposed)
-      {
-        if (disposing)
+        private readonly TTransport transport;
+        private readonly MemoryStream writeBuffer = new MemoryStream(1024);
+        private readonly MemoryStream readBuffer = new MemoryStream(1024);
+
+        private const int HeaderSize = 4;
+        private readonly byte[] headerBuf = new byte[HeaderSize];
+
+        public class Factory : TTransportFactory
         {
-          if (readBuffer != null)
-            readBuffer.Dispose();
+            public override TTransport GetTransport(TTransport trans)
+            {
+                return new TFramedTransport(trans);
+            }
         }
-      }
-      _IsDisposed = true;
+
+        public TFramedTransport(TTransport transport)
+        {
+            if (transport == null)
+                throw new ArgumentNullException("transport");
+            this.transport = transport;
+            InitWriteBuffer();
+        }
+
+        public override void Open()
+        {
+            CheckNotDisposed();
+            transport.Open();
+        }
+
+        public override bool IsOpen
+        {
+            get
+            {
+                // We can legitimately throw here but be nice a bit.
+                // CheckNotDisposed();
+                return !_IsDisposed && transport.IsOpen;
+            }
+        }
+
+        public override void Close()
+        {
+            CheckNotDisposed();
+            transport.Close();
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            CheckNotDisposed();
+            ValidateBufferArgs(buf, off, len);
+            if (!IsOpen)
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            int got = readBuffer.Read(buf, off, len);
+            if (got > 0)
+            {
+                return got;
+            }
+
+            // Read another frame of data
+            ReadFrame();
+
+            return readBuffer.Read(buf, off, len);
+        }
+
+        private void ReadFrame()
+        {
+            transport.ReadAll(headerBuf, 0, HeaderSize);
+            int size = DecodeFrameSize(headerBuf);
+
+            readBuffer.SetLength(size);
+            readBuffer.Seek(0, SeekOrigin.Begin);
+            byte[] buff = readBuffer.GetBuffer();
+            transport.ReadAll(buff, 0, size);
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            CheckNotDisposed();
+            ValidateBufferArgs(buf, off, len);
+            if (!IsOpen)
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            if (writeBuffer.Length + (long)len > (long)int.MaxValue)
+                Flush();
+            writeBuffer.Write(buf, off, len);
+        }
+
+        private void InternalFlush()
+        {
+            CheckNotDisposed();
+            if (!IsOpen)
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            byte[] buf = writeBuffer.GetBuffer();
+            int len = (int)writeBuffer.Length;
+            int data_len = len - HeaderSize;
+            if (data_len < 0)
+                throw new System.InvalidOperationException(); // logic error actually
+
+            // Inject message header into the reserved buffer space
+            EncodeFrameSize(data_len, buf);
+
+            // Send the entire message at once
+            transport.Write(buf, 0, len);
+
+            InitWriteBuffer();
+        }
+
+        public override void Flush()
+        {
+            CheckNotDisposed();
+            InternalFlush();
+
+            transport.Flush();
+        }
+
+        public override IAsyncResult BeginFlush(AsyncCallback callback, object state)
+        {
+            CheckNotDisposed();
+            InternalFlush();
+
+            return transport.BeginFlush( callback, state);
+        }
+
+        public override void EndFlush(IAsyncResult asyncResult)
+        {
+            transport.EndFlush( asyncResult);
+        }
+
+        private void InitWriteBuffer()
+        {
+            // Reserve space for message header to be put right before sending it out
+            writeBuffer.SetLength(HeaderSize);
+            writeBuffer.Seek(0, SeekOrigin.End);
+        }
+
+        private static void EncodeFrameSize(int frameSize, byte[] buf)
+        {
+            buf[0] = (byte)(0xff & (frameSize >> 24));
+            buf[1] = (byte)(0xff & (frameSize >> 16));
+            buf[2] = (byte)(0xff & (frameSize >> 8));
+            buf[3] = (byte)(0xff & (frameSize));
+        }
+
+        private static int DecodeFrameSize(byte[] buf)
+        {
+            return
+                ((buf[0] & 0xff) << 24) |
+                ((buf[1] & 0xff) << 16) |
+                ((buf[2] & 0xff) << 8) |
+                ((buf[3] & 0xff));
+        }
+
+
+        private void CheckNotDisposed()
+        {
+            if (_IsDisposed)
+                throw new ObjectDisposedException("TFramedTransport");
+        }
+
+        #region " IDisposable Support "
+        private bool _IsDisposed;
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (readBuffer != null)
+                        readBuffer.Dispose();
+                    if (writeBuffer != null)
+                        writeBuffer.Dispose();
+                    if (transport != null)
+                        transport.Dispose();
+                }
+            }
+            _IsDisposed = true;
+        }
+        #endregion
     }
-    #endregion
-  }
 }
diff --git a/lib/csharp/src/Transport/THttpClient.cs b/lib/csharp/src/Transport/THttpClient.cs
index 7f04be7..667fc25 100644
--- a/lib/csharp/src/Transport/THttpClient.cs
+++ b/lib/csharp/src/Transport/THttpClient.cs
@@ -7,7 +7,7 @@
  * "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
+ *     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
@@ -15,8 +15,8 @@
  * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations
  * under the License.
- * 
- * 
+ *
+ *
  */
 
 using System;
@@ -24,56 +24,64 @@
 using System.IO;
 using System.Net;
 using System.Threading;
+using System.Linq;
+using System.Security.Cryptography.X509Certificates;
+using System.IO.Compression;
 
 namespace Thrift.Transport
 {
-	public class THttpClient : TTransport, IDisposable
-	{
-		private readonly Uri uri;
-		private Stream inputStream;
-		private MemoryStream outputStream = new MemoryStream();
+    public class THttpClient : TTransport, IDisposable
+    {
+        private readonly Uri uri;
+        private readonly X509Certificate[] certificates;
+        private Stream inputStream;
+        private MemoryStream outputStream = new MemoryStream();
 
         // Timeouts in milliseconds
         private int connectTimeout = 30000;
 
         private int readTimeout = 30000;
 
-		private IDictionary<String, String> customHeaders = new Dictionary<string, string>();
+        private IDictionary<string, string> customHeaders = new Dictionary<string, string>();
 
-        private HttpWebRequest connection = null;

 #if !SILVERLIGHT
         private IWebProxy proxy = WebRequest.DefaultWebProxy;
-#endif

-

+#endif
+
         public THttpClient(Uri u)
-		{
-			uri = u;
-            connection = CreateRequest();
-		}
+            : this(u, Enumerable.Empty<X509Certificate>())
+        {
+        }
 
-		public int ConnectTimeout
-		{
-			set
-			{
-			   connectTimeout = value;
-			}
-		}
+        public THttpClient(Uri u, IEnumerable<X509Certificate> certificates)
+        {
+            uri = u;
+            this.certificates = (certificates ?? Enumerable.Empty<X509Certificate>()).ToArray();
+        }
 
-		public int ReadTimeout
-		{
-			set
-			{
-				readTimeout = value;
-			}
-		}
+        public int ConnectTimeout
+        {
+            set
+            {
+                connectTimeout = value;
+            }
+        }
 
-		public IDictionary<String, String> CustomHeaders
-		{
-			get
-			{
-				return customHeaders;
-			}
-		}
+        public int ReadTimeout
+        {
+            set
+            {
+                readTimeout = value;
+            }
+        }
+
+        public IDictionary<string, string> CustomHeaders
+        {
+            get
+            {
+                return customHeaders;
+            }
+        }
 
 #if !SILVERLIGHT
         public IWebProxy Proxy
@@ -85,140 +93,207 @@
         }
 #endif
 
-		public override bool IsOpen
-		{
-			get
-			{
-				return true;
-			}
-		}
+        public override bool IsOpen
+        {
+            get
+            {
+                return true;
+            }
+        }
 
-		public override void Open()
-		{
-		}
+        public override void Open()
+        {
+        }
 
-		public override void Close()
-		{
-			if (inputStream != null)
-			{
-				inputStream.Close();
-				inputStream = null;
-			}
-			if (outputStream != null)
-			{
-				outputStream.Close();
-				outputStream = null;
-			}
-		}
+        public override void Close()
+        {
+            if (inputStream != null)
+            {
+                inputStream.Close();
+                inputStream = null;
+            }
+            if (outputStream != null)
+            {
+                outputStream.Close();
+                outputStream = null;
+            }
+        }
 
-		public override int Read(byte[] buf, int off, int len)
-		{
-			if (inputStream == null)
-			{
-				throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No request has been sent");
-			}
+        public override int Read(byte[] buf, int off, int len)
+        {
+            if (inputStream == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No request has been sent");
+            }
 
-			try
-			{
-				int ret = inputStream.Read(buf, off, len);
+            try
+            {
+                int ret = inputStream.Read(buf, off, len);
 
-				if (ret == -1)
-				{
-					throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "No more data available");
-				}
+                if (ret == -1)
+                {
+                    throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "No more data available");
+                }
 
-				return ret;
-			}
-			catch (IOException iox)
-			{ 
-				throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString());
-			}
-		}
+                return ret;
+            }
+            catch (IOException iox)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString(), iox);
+            }
+        }
 
-		public override void Write(byte[] buf, int off, int len)
-		{
-			outputStream.Write(buf, off, len);
-		}
+        public override void Write(byte[] buf, int off, int len)
+        {
+            outputStream.Write(buf, off, len);
+        }
 
 #if !SILVERLIGHT
-		public override void Flush()
-		{
-			try 
-			{
-				SendRequest();
-			}
-			finally
-			{
-				outputStream = new MemoryStream();
-			}
-		}
+        public override void Flush()
+        {
+            try
+            {
+                SendRequest();
+            }
+            finally
+            {
+                outputStream = new MemoryStream();
+            }
+        }
 
-		private void SendRequest()
-		{
-			try
-			{
-				HttpWebRequest connection = CreateRequest();
+        private void SendRequest()
+        {
+            try
+            {
+                HttpWebRequest connection = CreateRequest();
+                connection.Headers.Add("Accept-Encoding", "gzip, deflate");
 
-				byte[] data = outputStream.ToArray();
-				connection.ContentLength = data.Length;
+                byte[] data = outputStream.ToArray();
+                connection.ContentLength = data.Length;
 
-				using (Stream requestStream = connection.GetRequestStream())
-				{
-					requestStream.Write(data, 0, data.Length);
-					inputStream = connection.GetResponse().GetResponseStream();
-				}
-			}
-			catch (IOException iox)
-			{
-				throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString());
-			}
-			catch (WebException wx)
-			{
-				throw new TTransportException(TTransportException.ExceptionType.Unknown, "Couldn't connect to server: " + wx);
-			}
-		}
+                using (Stream requestStream = connection.GetRequestStream())
+                {
+                    requestStream.Write(data, 0, data.Length);
+
+                    // Resolve HTTP hang that can happens after successive calls by making sure
+                    // that we release the response and response stream. To support this, we copy
+                    // the response to a memory stream.
+                    using (var response = connection.GetResponse())
+                    {
+                        using (var responseStream = response.GetResponseStream())
+                        {
+                            // Copy the response to a memory stream so that we can
+                            // cleanly close the response and response stream.
+                            inputStream = new MemoryStream();
+                            byte[] buffer = new byte[8192];  // multiple of 4096
+                            int bytesRead;
+                            while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
+                            {
+                                inputStream.Write(buffer, 0, bytesRead);
+                            }
+                            inputStream.Seek(0, 0);
+                        }
+
+                        var encodings = response.Headers.GetValues("Content-Encoding");
+                        if (encodings != null)
+                        {
+                            foreach (var encoding in encodings)
+                            {
+                                switch (encoding)
+                                {
+                                    case "gzip":
+                                        DecompressGZipped(ref inputStream);
+                                        break;
+                                    case "deflate":
+                                        DecompressDeflated(ref inputStream);
+                                        break;
+                                    default:
+                                        break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            catch (IOException iox)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString(), iox);
+            }
+            catch (WebException wx)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, "Couldn't connect to server: " + wx, wx);
+            }
+        }
+
+        private void DecompressDeflated(ref Stream inputStream)
+        {
+            var tmp = new MemoryStream();
+            using (var decomp = new DeflateStream(inputStream, CompressionMode.Decompress))
+            {
+                decomp.CopyTo(tmp);
+            }
+            inputStream.Dispose();
+            inputStream = tmp;
+            inputStream.Seek(0, 0);
+        }
+
+        private void DecompressGZipped(ref Stream inputStream)
+        {
+            var tmp = new MemoryStream();
+            using (var decomp = new GZipStream(inputStream, CompressionMode.Decompress))
+            {
+                decomp.CopyTo(tmp);
+            }
+            inputStream.Dispose();
+            inputStream = tmp;
+            inputStream.Seek(0, 0);
+        }
 #endif
-				private HttpWebRequest CreateRequest()
-		{
-			HttpWebRequest connection = (HttpWebRequest)WebRequest.Create(uri);
+        private HttpWebRequest CreateRequest()
+        {
+            HttpWebRequest connection = (HttpWebRequest)WebRequest.Create(uri);
+
 
 #if !SILVERLIGHT
-			if (connectTimeout > 0)
-			{
-				connection.Timeout = connectTimeout;
-			}
-			if (readTimeout > 0)
-			{
-				connection.ReadWriteTimeout = readTimeout;
-			}
+            // Adding certificates through code is not supported with WP7 Silverlight
+            // see "Windows Phone 7 and Certificates_FINAL_121610.pdf"
+            connection.ClientCertificates.AddRange(certificates);
+
+            if (connectTimeout > 0)
+            {
+                connection.Timeout = connectTimeout;
+            }
+            if (readTimeout > 0)
+            {
+                connection.ReadWriteTimeout = readTimeout;
+            }
 #endif
-			// Make the request
-			connection.ContentType = "application/x-thrift";
-			connection.Accept = "application/x-thrift";
-			connection.UserAgent = "C#/THttpClient";
-			connection.Method = "POST";
+            // Make the request
+            connection.ContentType = "application/x-thrift";
+            connection.Accept = "application/x-thrift";
+            connection.UserAgent = "C#/THttpClient";
+            connection.Method = "POST";
 #if !SILVERLIGHT
-			connection.ProtocolVersion = HttpVersion.Version10;
+            connection.ProtocolVersion = HttpVersion.Version10;
 #endif
 
             //add custom headers here
-			foreach (KeyValuePair<string, string> item in customHeaders)
-			{
+            foreach (KeyValuePair<string, string> item in customHeaders)
+            {
 #if !SILVERLIGHT
-				connection.Headers.Add(item.Key, item.Value);
+                connection.Headers.Add(item.Key, item.Value);
 #else
                 connection.Headers[item.Key] = item.Value;
 #endif
-			}
+            }
 
 #if !SILVERLIGHT
             connection.Proxy = proxy;
 #endif
 
             return connection;
-		}
+        }
 
-#if SILVERLIGHT
         public override IAsyncResult BeginFlush(AsyncCallback callback, object state)
         {
             // Extract request and reset buffer
@@ -241,7 +316,7 @@
             }
             catch (IOException iox)
             {
-                throw new TTransportException(iox.ToString());
+                throw new TTransportException(iox.ToString(), iox);
             }
         }
 
@@ -249,7 +324,7 @@
         {
             try
             {
-                var flushAsyncResult = (FlushAsyncResult) asyncResult;
+                var flushAsyncResult = (FlushAsyncResult)asyncResult;
 
                 if (!flushAsyncResult.IsCompleted)
                 {
@@ -262,14 +337,14 @@
                 {
                     throw flushAsyncResult.AsyncException;
                 }
-            } finally
+            }
+            finally
             {
                 outputStream = new MemoryStream();
             }
 
         }
 
-
         private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
         {
             var flushAsyncResult = (FlushAsyncResult)asynchronousResult.AsyncState;
@@ -285,7 +360,7 @@
             }
             catch (Exception exception)
             {
-                flushAsyncResult.AsyncException = new TTransportException(exception.ToString());
+                flushAsyncResult.AsyncException = new TTransportException(exception.ToString(), exception);
                 flushAsyncResult.UpdateStatusToComplete();
                 flushAsyncResult.NotifyCallbackWhenAvailable();
             }
@@ -300,7 +375,7 @@
             }
             catch (Exception exception)
             {
-                flushAsyncResult.AsyncException = new TTransportException(exception.ToString());
+                flushAsyncResult.AsyncException = new TTransportException(exception.ToString(), exception);
             }
             flushAsyncResult.UpdateStatusToComplete();
             flushAsyncResult.NotifyCallbackWhenAvailable();
@@ -312,9 +387,9 @@
             private volatile Boolean _isCompleted;
             private ManualResetEvent _evt;
             private readonly AsyncCallback _cbMethod;
-            private readonly Object _state;
+            private readonly object _state;
 
-            public FlushAsyncResult(AsyncCallback cbMethod, Object state)
+            public FlushAsyncResult(AsyncCallback cbMethod, object state)
             {
                 _cbMethod = cbMethod;
                 _state = state;
@@ -340,7 +415,7 @@
             {
                 get { return _isCompleted; }
             }
-            private readonly Object _locker = new Object();
+            private readonly object _locker = new object();
             private ManualResetEvent GetEvtHandle()
             {
                 lock (_locker)
@@ -358,12 +433,12 @@
             }
             internal void UpdateStatusToComplete()
             {
-                _isCompleted = true; //1. set _iscompleted to true 
+                _isCompleted = true; //1. set _iscompleted to true
                 lock (_locker)
                 {
                     if (_evt != null)
                     {
-                        _evt.Set(); //2. set the event, when it exists 
+                        _evt.Set(); //2. set the event, when it exists
                     }
                 }
             }
@@ -377,25 +452,24 @@
             }
         }
 
-#endif
-#region " IDisposable Support "
-		private bool _IsDisposed;
+        #region " IDisposable Support "
+        private bool _IsDisposed;
 
-		// IDisposable
-		protected override void Dispose(bool disposing)
-		{
-			if (!_IsDisposed)
-			{
-				if (disposing)
-				{
-					if (inputStream != null)
-						inputStream.Dispose();
-					if (outputStream != null)
-						outputStream.Dispose();
-				}
-			}
-			_IsDisposed = true;
-		}
-#endregion
-	}
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (inputStream != null)
+                        inputStream.Dispose();
+                    if (outputStream != null)
+                        outputStream.Dispose();
+                }
+            }
+            _IsDisposed = true;
+        }
+        #endregion
+    }
 }
diff --git a/lib/csharp/src/Transport/THttpHandler.cs b/lib/csharp/src/Transport/THttpHandler.cs
index 0a10d79..4115ef9 100644
--- a/lib/csharp/src/Transport/THttpHandler.cs
+++ b/lib/csharp/src/Transport/THttpHandler.cs
@@ -1,11 +1,23 @@
-//
-//  THttpHandler.cs
-//
-//  Authors:
-//		Fredrik Hedberg <fhedberg@availo.com>
-//
-//  Distributed under the Apache Public License
-//
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * 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.
+ *
+ *
+ */
 
 using System;
 using System.Web;
@@ -31,7 +43,7 @@
         {
 
         }
-        
+
         public THttpHandler(TProcessor processor, TProtocolFactory protocolFactory)
             : this(processor, protocolFactory, protocolFactory)
         {
@@ -63,30 +75,23 @@
         {
             TTransport transport = new TStreamTransport(input,output);
 
-            TProtocol inputProtocol = null;
-            TProtocol outputProtocol = null;
-
             try
             {
-                inputProtocol = inputProtocolFactory.GetProtocol(transport);
-                outputProtocol = outputProtocolFactory.GetProtocol(transport);
+                var inputProtocol = inputProtocolFactory.GetProtocol(transport);
+                var outputProtocol = outputProtocolFactory.GetProtocol(transport);
 
-                while (processor.Process(inputProtocol, outputProtocol)) { }
+                while (processor.Process(inputProtocol, outputProtocol))
+                {
+                }
             }
             catch (TTransportException)
             {
                 // Client died, just move on
             }
-            catch (TApplicationException tx)
+            finally
             {
-                Console.Error.Write(tx);
+                transport.Close();
             }
-            catch (Exception x)
-            {
-                Console.Error.Write(x);
-            }
-
-            transport.Close();
         }
 
         public bool IsReusable
diff --git a/lib/csharp/src/Transport/THttpTaskAsyncHandler.cs b/lib/csharp/src/Transport/THttpTaskAsyncHandler.cs
new file mode 100644
index 0000000..e491f32
--- /dev/null
+++ b/lib/csharp/src/Transport/THttpTaskAsyncHandler.cs
@@ -0,0 +1,97 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System.Threading.Tasks;
+using System.Web;
+using Thrift.Protocol;
+
+namespace Thrift.Transport
+{
+    /// <summary>
+    /// An async task based HTTP handler for processing thrift services.
+    /// </summary>
+    public class THttpTaskAsyncHandler : HttpTaskAsyncHandler
+    {
+        private readonly TAsyncProcessor _processor;
+        private readonly TProtocolFactory _inputProtocolFactory;
+        private readonly TProtocolFactory _outputProtocolFactory;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="THttpTaskAsyncHandler"/> class
+        /// using the <see cref="TBinaryProtocol.Factory"/> for both input and output streams.
+        /// </summary>
+        /// <param name="processor">The async processor implementation.</param>
+        public THttpTaskAsyncHandler(TAsyncProcessor processor)
+            : this(processor, new TBinaryProtocol.Factory())
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="THttpTaskAsyncHandler"/> class
+        /// using <paramref name="protocolFactory"/> for both input and output streams.
+        /// </summary>
+        /// <param name="processor">The async processor implementation.</param>
+        /// <param name="protocolFactory">The protocol factory.</param>
+        public THttpTaskAsyncHandler(TAsyncProcessor processor, TProtocolFactory protocolFactory)
+            : this(processor, protocolFactory, protocolFactory)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="THttpTaskAsyncHandler"/> class.
+        /// </summary>
+        /// <param name="processor">The async processor implementation.</param>
+        /// <param name="inputProtocolFactory">The input protocol factory.</param>
+        /// <param name="outputProtocolFactory">The output protocol factory.</param>
+        public THttpTaskAsyncHandler(TAsyncProcessor processor, TProtocolFactory inputProtocolFactory,
+            TProtocolFactory outputProtocolFactory)
+        {
+            _processor = processor;
+            _inputProtocolFactory = inputProtocolFactory;
+            _outputProtocolFactory = outputProtocolFactory;
+        }
+
+        public override async Task ProcessRequestAsync(HttpContext context)
+        {
+            var transport = new TStreamTransport(context.Request.InputStream, context.Response.OutputStream);
+
+            try
+            {
+                var input = _inputProtocolFactory.GetProtocol(transport);
+                var output = _outputProtocolFactory.GetProtocol(transport);
+
+                while (await _processor.ProcessAsync(input, output))
+                {
+                }
+            }
+            catch (TTransportException)
+            {
+                // Client died, just move on
+            }
+            finally
+            {
+                transport.Close();
+            }
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TMemoryBuffer.cs b/lib/csharp/src/Transport/TMemoryBuffer.cs
index ca31fee..303d083 100644
--- a/lib/csharp/src/Transport/TMemoryBuffer.cs
+++ b/lib/csharp/src/Transport/TMemoryBuffer.cs
@@ -22,78 +22,96 @@
 using System.Reflection;
 using Thrift.Protocol;
 
-namespace Thrift.Transport {
-	public class TMemoryBuffer : TTransport {
+namespace Thrift.Transport
+{
+    public class TMemoryBuffer : TTransport
+    {
 
-		private readonly MemoryStream byteStream;
+        private readonly MemoryStream byteStream;
 
-		public TMemoryBuffer() {
-			byteStream = new MemoryStream();
-		}
+        public TMemoryBuffer()
+        {
+            byteStream = new MemoryStream();
+        }
 
-		public TMemoryBuffer(byte[] buf) {
-			byteStream = new MemoryStream(buf);
-		}
+        public TMemoryBuffer(byte[] buf)
+        {
+            byteStream = new MemoryStream(buf);
+        }
 
-		public override void Open() {
-			/** do nothing **/
-		}
+        public override void Open()
+        {
+            /** do nothing **/
+        }
 
-		public override void Close() {
-			/** do nothing **/
-		}
+        public override void Close()
+        {
+            /** do nothing **/
+        }
 
-		public override int Read(byte[] buf, int off, int len) {
-			return byteStream.Read(buf, off, len);
-		}
+        public override int Read(byte[] buf, int off, int len)
+        {
+            return byteStream.Read(buf, off, len);
+        }
 
-		public override void Write(byte[] buf, int off, int len) {
-			byteStream.Write(buf, off, len);
-		}
+        public override void Write(byte[] buf, int off, int len)
+        {
+            byteStream.Write(buf, off, len);
+        }
 
-		public byte[] GetBuffer() {
-			return byteStream.ToArray();
-		}
+        public byte[] GetBuffer()
+        {
+            return byteStream.ToArray();
+        }
 
 
-		public override bool IsOpen {
-			get { return true; }
-		}
+        public override bool IsOpen
+        {
+            get { return true; }
+        }
 
-		public static byte[] Serialize(TAbstractBase s) {
-			var t = new TMemoryBuffer();
-			var p = new TBinaryProtocol(t);
+        public static byte[] Serialize(TAbstractBase s)
+        {
+            var t = new TMemoryBuffer();
+            var p = new TBinaryProtocol(t);
 
-			s.Write(p);
+            s.Write(p);
 
-			return t.GetBuffer();
-		}
+            return t.GetBuffer();
+        }
 
-		public static T DeSerialize<T>(byte[] buf) where T : TAbstractBase {
-			var trans = new TMemoryBuffer(buf);
-			var p = new TBinaryProtocol(trans);
-			if (typeof (TBase).IsAssignableFrom(typeof (T))) {
-				var method = typeof (T).GetMethod("Read", BindingFlags.Instance | BindingFlags.Public);
-				var t = Activator.CreateInstance<T>();
-				method.Invoke(t, new object[] {p});
-				return t;
-			 } else {
-			       var method = typeof (T).GetMethod("Read", BindingFlags.Static | BindingFlags.Public);
-				return (T) method.Invoke(null, new object[] {p});
-			}
-		}
+        public static T DeSerialize<T>(byte[] buf) where T : TAbstractBase
+        {
+            var trans = new TMemoryBuffer(buf);
+            var p = new TBinaryProtocol(trans);
+            if (typeof(TBase).IsAssignableFrom(typeof(T)))
+            {
+                var method = typeof(T).GetMethod("Read", BindingFlags.Instance | BindingFlags.Public);
+                var t = Activator.CreateInstance<T>();
+                method.Invoke(t, new object[] { p });
+                return t;
+            }
+            else
+            {
+                var method = typeof(T).GetMethod("Read", BindingFlags.Static | BindingFlags.Public);
+                return (T)method.Invoke(null, new object[] { p });
+            }
+        }
 
-		private bool _IsDisposed;
+        private bool _IsDisposed;
 
-		// IDisposable
-		protected override void Dispose(bool disposing) {
-			if (!_IsDisposed) {
-				if (disposing) {
-					if (byteStream != null)
-						byteStream.Dispose();
-				}
-			}
-			_IsDisposed = true;
-		}
-	}
-}
\ No newline at end of file
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (byteStream != null)
+                        byteStream.Dispose();
+                }
+            }
+            _IsDisposed = true;
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TNamedPipeClientTransport.cs b/lib/csharp/src/Transport/TNamedPipeClientTransport.cs
new file mode 100644
index 0000000..49a50aa
--- /dev/null
+++ b/lib/csharp/src/Transport/TNamedPipeClientTransport.cs
@@ -0,0 +1,111 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.IO.Pipes;
+using System.Threading;
+
+namespace Thrift.Transport
+{
+    public class TNamedPipeClientTransport : TTransport
+    {
+        private NamedPipeClientStream client;
+        private string ServerName;
+        private string PipeName;
+        private int ConnectTimeout;
+
+        public TNamedPipeClientTransport(string pipe, int timeout = Timeout.Infinite)
+        {
+            ServerName = ".";
+            PipeName = pipe;
+            ConnectTimeout = timeout;
+        }
+
+        public TNamedPipeClientTransport(string server, string pipe, int timeout = Timeout.Infinite)
+        {
+            ServerName = (server != "") ? server : ".";
+            PipeName = pipe;
+            ConnectTimeout = timeout;
+        }
+
+        public override bool IsOpen
+        {
+            get { return client != null && client.IsConnected; }
+        }
+
+        public override void Open()
+        {
+            if (IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen);
+            }
+            client = new NamedPipeClientStream(ServerName, PipeName, PipeDirection.InOut, PipeOptions.None);
+            client.Connect(ConnectTimeout);
+        }
+
+        public override void Close()
+        {
+            if (client != null)
+            {
+                client.Close();
+                client = null;
+            }
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            if (client == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            }
+
+            return client.Read(buf, off, len);
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            if (client == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            }
+
+            // if necessary, send the data in chunks
+            // there's a system limit around 0x10000 bytes that we hit otherwise
+            // MSDN: "Pipe write operations across a network are limited to 65,535 bytes per write. For more information regarding pipes, see the Remarks section."
+            var nBytes = Math.Min(len, 15 * 4096);  // 16 would exceed the limit
+            while (nBytes > 0)
+            {
+                client.Write(buf, off, nBytes);
+
+                off += nBytes;
+                len -= nBytes;
+                nBytes = Math.Min(len, nBytes);
+            }
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            client.Dispose();
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TNamedPipeServerTransport.cs b/lib/csharp/src/Transport/TNamedPipeServerTransport.cs
new file mode 100644
index 0000000..32215cf
--- /dev/null
+++ b/lib/csharp/src/Transport/TNamedPipeServerTransport.cs
@@ -0,0 +1,296 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.IO.Pipes;
+using System.Threading;
+using System.Security.Principal;
+
+namespace Thrift.Transport
+{
+    public class TNamedPipeServerTransport : TServerTransport
+    {
+        /// <summary>
+        /// This is the address of the Pipe on the localhost.
+        /// </summary>
+        private readonly string pipeAddress;
+        private NamedPipeServerStream stream = null;
+        private bool asyncMode = true;
+
+        public TNamedPipeServerTransport(string pipeAddress)
+        {
+            this.pipeAddress = pipeAddress;
+        }
+
+        public override void Listen()
+        {
+            // nothing to do here
+        }
+
+        public override void Close()
+        {
+            if (stream != null)
+            {
+                try
+                {
+                    stream.Close();
+                    stream.Dispose();
+                }
+                finally
+                {
+                    stream = null;
+                }
+            }
+        }
+
+        private void EnsurePipeInstance()
+        {
+            if (stream == null)
+            {
+                var direction = PipeDirection.InOut;
+                var maxconn = NamedPipeServerStream.MaxAllowedServerInstances;
+                var mode = PipeTransmissionMode.Byte;
+                var options = asyncMode ? PipeOptions.Asynchronous : PipeOptions.None;
+                const int INBUF_SIZE = 4096;
+                const int OUTBUF_SIZE = 4096;
+
+                // security
+                var security = new PipeSecurity();
+                security.AddAccessRule(
+                    new PipeAccessRule(
+                        new SecurityIdentifier(WellKnownSidType.WorldSid, null),
+                        PipeAccessRights.Read | PipeAccessRights.Write | PipeAccessRights.Synchronize | PipeAccessRights.CreateNewInstance,
+                        System.Security.AccessControl.AccessControlType.Allow
+                    )
+                );
+
+                try
+                {
+                    stream = new NamedPipeServerStream(pipeAddress, direction, maxconn, mode, options, INBUF_SIZE, OUTBUF_SIZE, security);
+                }
+                catch (NotImplementedException)  // Mono still does not support async, fallback to sync
+                {
+                    if (asyncMode)
+                    {
+                        options &= (~PipeOptions.Asynchronous);
+                        stream = new NamedPipeServerStream(pipeAddress, direction, maxconn, mode, options, INBUF_SIZE, OUTBUF_SIZE, security);
+                        asyncMode = false;
+                    }
+                    else
+                    {
+                        throw;
+                    }
+                }
+
+            }
+        }
+
+        protected override TTransport AcceptImpl()
+        {
+            try
+            {
+                EnsurePipeInstance();
+
+                if (asyncMode)
+                {
+                    var evt = new ManualResetEvent(false);
+                    Exception eOuter = null;
+
+                    stream.BeginWaitForConnection(asyncResult =>
+                    {
+                        try
+                        {
+                            if (stream != null)
+                                stream.EndWaitForConnection(asyncResult);
+                            else
+                                eOuter = new TTransportException(TTransportException.ExceptionType.Interrupted);
+                        }
+                        catch (Exception e)
+                        {
+                            if (stream != null)
+                                eOuter = e;
+                            else
+                                eOuter = new TTransportException(TTransportException.ExceptionType.Interrupted, e.Message, e);
+                        }
+                        evt.Set();
+                    }, null);
+
+                    evt.WaitOne();
+
+                    if (eOuter != null)
+                        throw eOuter; // rethrow exception
+                }
+                else
+                {
+                    stream.WaitForConnection();
+                }
+
+                var trans = new ServerTransport(stream,asyncMode);
+                stream = null;  // pass ownership to ServerTransport
+                return trans;
+            }
+            catch (TTransportException)
+            {
+                Close();
+                throw;
+            }
+            catch (Exception e)
+            {
+                Close();
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, e.Message, e);
+            }
+        }
+
+        private class ServerTransport : TTransport
+        {
+            private NamedPipeServerStream stream;
+            private bool asyncMode;
+
+            public ServerTransport(NamedPipeServerStream stream, bool asyncMode)
+            {
+                this.stream = stream;
+                this.asyncMode = asyncMode;
+            }
+
+            public override bool IsOpen
+            {
+                get { return stream != null && stream.IsConnected; }
+            }
+
+            public override void Open()
+            {
+            }
+
+            public override void Close()
+            {
+                if (stream != null)
+                    stream.Close();
+            }
+
+            public override int Read(byte[] buf, int off, int len)
+            {
+                if (stream == null)
+                {
+                    throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+                }
+
+                if (asyncMode)
+                {
+                    Exception eOuter = null;
+                    var evt = new ManualResetEvent(false);
+                    int retval = 0;
+
+                    stream.BeginRead(buf, off, len, asyncResult =>
+                    {
+                        try
+                        {
+                            if (stream != null)
+                                retval = stream.EndRead(asyncResult);
+                            else
+                                eOuter = new TTransportException(TTransportException.ExceptionType.Interrupted);
+                        }
+                        catch (Exception e)
+                        {
+                            if (stream != null)
+                                eOuter = e;
+                            else
+                                eOuter = new TTransportException(TTransportException.ExceptionType.Interrupted, e.Message, e);
+                        }
+                        evt.Set();
+                    }, null);
+
+                    evt.WaitOne();
+
+                    if (eOuter != null)
+                        throw eOuter; // rethrow exception
+                    else
+                        return retval;
+                }
+                else
+                {
+                    return stream.Read(buf, off, len);
+                }
+            }
+
+            public override void Write(byte[] buf, int off, int len)
+            {
+                if (stream == null)
+                {
+                    throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+                }
+
+                // if necessary, send the data in chunks
+                // there's a system limit around 0x10000 bytes that we hit otherwise
+                // MSDN: "Pipe write operations across a network are limited to 65,535 bytes per write. For more information regarding pipes, see the Remarks section."
+                var nBytes = Math.Min(len, 15 * 4096);  // 16 would exceed the limit
+                while (nBytes > 0)
+                {
+
+                    if (asyncMode)
+                    {
+                        Exception eOuter = null;
+                        var evt = new ManualResetEvent(false);
+
+                        stream.BeginWrite(buf, off, nBytes, asyncResult =>
+                        {
+                            try
+                            {
+                                if (stream != null)
+                                    stream.EndWrite(asyncResult);
+                                else
+                                    eOuter = new TTransportException(TTransportException.ExceptionType.Interrupted);
+                            }
+                            catch (Exception e)
+                            {
+                                if (stream != null)
+                                    eOuter = e;
+                                else
+                                    eOuter = new TTransportException(TTransportException.ExceptionType.Interrupted, e.Message, e);
+                            }
+                            evt.Set();
+                        }, null);
+
+                        evt.WaitOne();
+
+                        if (eOuter != null)
+                            throw eOuter; // rethrow exception
+                    }
+                    else
+                    {
+                        stream.Write(buf, off, nBytes);
+                    }
+
+                    off += nBytes;
+                    len -= nBytes;
+                    nBytes = Math.Min(len, nBytes);
+                }
+            }
+
+            protected override void Dispose(bool disposing)
+            {
+                if (stream != null)
+                    stream.Dispose();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/csharp/src/Transport/TServerSocket.cs b/lib/csharp/src/Transport/TServerSocket.cs
index eefa4f9..d8ec62a 100644
--- a/lib/csharp/src/Transport/TServerSocket.cs
+++ b/lib/csharp/src/Transport/TServerSocket.cs
@@ -27,94 +27,94 @@
 
 namespace Thrift.Transport
 {
-	public class TServerSocket : TServerTransport
-	{
-		/**
-		* Underlying server with socket
-		*/
-		private TcpListener server = null;
+    public class TServerSocket : TServerTransport
+    {
+        /// <summary>
+        /// Underlying server with socket.
+        /// </summary>
+        private TcpListener server = null;
 
-		/**
-		 * Port to listen on
-		 */
-		private int port = 0;
+        /// <summary>
+        /// Port to listen on.
+        /// </summary>
+        private int port = 0;
 
-		/**
-		 * Timeout for client sockets from accept
-		 */
-		private int clientTimeout = 0;
+        /// <summary>
+        /// Timeout for client sockets from accept.
+        /// </summary>
+        private int clientTimeout = 0;
 
-		/**
-		 * Whether or not to wrap new TSocket connections in buffers
-		 */
-		private bool useBufferedSockets = false;
+        /// <summary>
+        /// Whether or not to wrap new TSocket connections in buffers.
+        /// </summary>
+        private bool useBufferedSockets = false;
 
-		/**
-		 * Creates a server socket from underlying socket object
-		 */
-		public TServerSocket(TcpListener listener)
-			:this(listener, 0)
-		{
-		}
+        /// <summary>
+        /// Creates a server socket from underlying socket object.
+        /// </summary>
+        public TServerSocket(TcpListener listener)
+            : this(listener, 0)
+        {
+        }
 
-		/**
-		 * Creates a server socket from underlying socket object
-		 */
-		public TServerSocket(TcpListener listener, int clientTimeout)
-		{
-			this.server = listener;
-			this.clientTimeout = clientTimeout;
-		}
+        /// <summary>
+        /// Creates a server socket from underlying socket object.
+        /// </summary>
+        public TServerSocket(TcpListener listener, int clientTimeout)
+        {
+            this.server = listener;
+            this.clientTimeout = clientTimeout;
+        }
 
-		/**
-		 * Creates just a port listening server socket
-		 */
-		public TServerSocket(int port)
-			: this(port, 0)
-		{
-		}
+        /// <summary>
+        /// Creates just a port listening server socket.
+        /// </summary>
+        public TServerSocket(int port)
+            : this(port, 0)
+        {
+        }
 
-		/**
-		 * Creates just a port listening server socket
-		 */
-		public TServerSocket(int port, int clientTimeout)
-			:this(port, clientTimeout, false)
-		{
-		}
+        /// <summary>
+        /// Creates just a port listening server socket.
+        /// </summary>
+        public TServerSocket(int port, int clientTimeout)
+            : this(port, clientTimeout, false)
+        {
+        }
 
-		public TServerSocket(int port, int clientTimeout, bool useBufferedSockets)
-		{
-			this.port = port;
-			this.clientTimeout = clientTimeout;
-			this.useBufferedSockets = useBufferedSockets;
-			try
-			{
-				// Make server socket
-				server = new TcpListener(System.Net.IPAddress.Any, this.port);
-				server.Server.NoDelay = true;
-			}
-			catch (Exception)
-			{
-				server = null;
-				throw new TTransportException("Could not create ServerSocket on port " + port + ".");
-			}
-		}
+        public TServerSocket(int port, int clientTimeout, bool useBufferedSockets)
+        {
+            this.port = port;
+            this.clientTimeout = clientTimeout;
+            this.useBufferedSockets = useBufferedSockets;
+            try
+            {
+                // Make server socket
+                this.server = TSocketVersionizer.CreateTcpListener(this.port);
+                this.server.Server.NoDelay = true;
+            }
+            catch (Exception ex)
+            {
+                server = null;
+                throw new TTransportException("Could not create ServerSocket on port " + this.port + ".", ex);
+            }
+        }
 
-		public override void Listen()
-		{
-			// Make sure not to block on accept
-			if (server != null)
-			{
-				try
-				{
-					server.Start();
-				}
-				catch (SocketException sx)
-				{
-					throw new TTransportException("Could not accept on listening socket: " + sx.Message);
-				}
-			}
-		}
+        public override void Listen()
+        {
+            // Make sure not to block on accept
+            if (server != null)
+            {
+                try
+                {
+                    server.Start();
+                }
+                catch (SocketException sx)
+                {
+                    throw new TTransportException("Could not accept on listening socket: " + sx.Message, sx);
+                }
+            }
+        }
 
         protected override TTransport AcceptImpl()
         {
@@ -142,7 +142,7 @@
                 }
                 catch (System.Exception)
                 {
-                    // If a TSocket was successfully created, then let 
+                    // If a TSocket was successfully created, then let
                     // it do proper cleanup of the TcpClient object.
                     if (result2 != null)
                         result2.Dispose();
@@ -153,24 +153,24 @@
             }
             catch (Exception ex)
             {
-                throw new TTransportException(ex.ToString());
+                throw new TTransportException(ex.ToString(), ex);
             }
         }
 
         public override void Close()
-		{
-			if (server != null)
-			{
-				try
-				{
-					server.Stop();
-				}
-				catch (Exception ex)
-				{
-					throw new TTransportException("WARNING: Could not close server socket: " + ex);
-				}
-				server = null;
-			}
-		}
-	}
+        {
+            if (server != null)
+            {
+                try
+                {
+                    server.Stop();
+                }
+                catch (Exception ex)
+                {
+                    throw new TTransportException("WARNING: Could not close server socket: " + ex, ex);
+                }
+                server = null;
+            }
+        }
+    }
 }
diff --git a/lib/csharp/src/Transport/TServerTransport.cs b/lib/csharp/src/Transport/TServerTransport.cs
index c99d07f..e63880b 100644
--- a/lib/csharp/src/Transport/TServerTransport.cs
+++ b/lib/csharp/src/Transport/TServerTransport.cs
@@ -25,19 +25,20 @@
 
 namespace Thrift.Transport
 {
-	public abstract class TServerTransport
-	{
-		public abstract void Listen();
-		public abstract void Close();
-		protected abstract TTransport AcceptImpl();
+    public abstract class TServerTransport
+    {
+        public abstract void Listen();
+        public abstract void Close();
+        protected abstract TTransport AcceptImpl();
 
-		public TTransport Accept()
-		{
-			TTransport transport = AcceptImpl();
-			if (transport == null) {
-			  throw new TTransportException("accept() may not return NULL");
-			}
-			return transport;
-		 }
-	}
+        public TTransport Accept()
+        {
+            TTransport transport = AcceptImpl();
+            if (transport == null)
+            {
+                throw new TTransportException("accept() may not return NULL");
+            }
+            return transport;
+        }
+    }
 }
diff --git a/lib/csharp/src/Transport/TSilverlightSocket.cs b/lib/csharp/src/Transport/TSilverlightSocket.cs
new file mode 100644
index 0000000..40469ab
--- /dev/null
+++ b/lib/csharp/src/Transport/TSilverlightSocket.cs
@@ -0,0 +1,393 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+/* only for silverlight */
+#if SILVERLIGHT
+
+using System;
+using System.Net.Sockets;
+using System.IO;
+using System.Net;
+using System.Threading;
+
+namespace Thrift.Transport
+{
+    public class TSilverlightSocket : TTransport
+    {
+        Socket socket = null;
+        static ManualResetEvent readAsyncComplete = new ManualResetEvent(false);
+        public event EventHandler<SocketAsyncEventArgs> connectHandler = null;
+
+        // memory stream for write cache.
+        private MemoryStream outputStream = new MemoryStream();
+
+        private string host = null;
+        private int port = 0;
+        private int timeout = 0;
+
+        // constructor
+        public TSilverlightSocket(string host, int port)
+            : this(host, port, 0)
+        {
+        }
+
+        // constructor
+        public TSilverlightSocket(string host, int port, int timeout)
+        {
+            this.host = host;
+            this.port = port;
+            this.timeout = timeout;
+
+            InitSocket();
+        }
+
+        private void InitSocket()
+        {
+            // Create a stream-based, TCP socket using the InterNetwork Address Family.
+            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+            socket.NoDelay = true;
+        }
+
+        public int Timeout
+        {
+            set
+            {
+                timeout = value;
+            }
+        }
+
+        public string Host
+        {
+            get
+            {
+                return host;
+            }
+        }
+
+        public int Port
+        {
+            get
+            {
+                return port;
+            }
+        }
+
+        public override bool IsOpen
+        {
+            get
+            {
+                if (socket == null)
+                {
+                    return false;
+                }
+
+                return socket.Connected;
+            }
+        }
+
+        public override void Open()
+        {
+            if (IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
+            }
+
+            if (string.IsNullOrEmpty(host))
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host");
+            }
+
+            if (port <= 0)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
+            }
+
+            if (socket == null)
+            {
+                InitSocket();
+            }
+
+            if (timeout == 0)     // no timeout -> infinite
+            {
+                timeout = 10000;  // set a default timeout for WP.
+            }
+
+            {
+                // Create DnsEndPoint. The hostName and port are passed in to this method.
+                DnsEndPoint hostEntry = new DnsEndPoint(this.host, this.port);
+
+                // Create a SocketAsyncEventArgs object to be used in the connection request
+                SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
+                socketEventArg.RemoteEndPoint = hostEntry;
+
+                // Inline event handler for the Completed event.
+                // Note: This event handler was implemented inline in order to make this method self-contained.
+                socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
+                {
+                    if (connectHandler != null)
+                    {
+                        connectHandler(this, e);
+                    }
+                });
+
+                // Make an asynchronous Connect request over the socket
+                socket.ConnectAsync(socketEventArg);
+            }
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            bool _timeout = true;
+            string _error = null;
+            int _recvBytes = -1;
+
+            if (socket == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Socket is not open");
+            }
+
+            // Create SocketAsyncEventArgs context object
+            SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
+            socketEventArg.RemoteEndPoint = socket.RemoteEndPoint;
+
+            // Setup the buffer to receive the data
+            socketEventArg.SetBuffer(buf, off, len);
+
+            // Inline event handler for the Completed event.
+            // Note: This even handler was implemented inline in order to make
+            // this method self-contained.
+            socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
+            {
+                _timeout = false;
+
+                if (e.SocketError == SocketError.Success)
+                {
+                    _recvBytes = e.BytesTransferred;
+                }
+                else
+                {
+                    _error = e.SocketError.ToString();
+                }
+
+                readAsyncComplete.Set();
+            });
+
+            // Sets the state of the event to nonsignaled, causing threads to block
+            readAsyncComplete.Reset();
+
+            // Make an asynchronous Receive request over the socket
+            socket.ReceiveAsync(socketEventArg);
+
+            // Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
+            // If no response comes back within this time then proceed
+            readAsyncComplete.WaitOne(this.timeout);
+
+            if (_timeout)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.TimedOut, "Socket recv timeout");
+            }
+
+            if (_error != null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, _error);
+            }
+
+            return _recvBytes;
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            outputStream.Write(buf, off, len);
+        }
+
+        private void beginFlush_Completed(object sender, SocketAsyncEventArgs e)
+        {
+            FlushAsyncResult flushAsyncResult = e.UserToken as FlushAsyncResult;
+            flushAsyncResult.UpdateStatusToComplete();
+            flushAsyncResult.NotifyCallbackWhenAvailable();
+
+            if (e.SocketError != SocketError.Success)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, e.SocketError.ToString());
+            }
+        }
+
+        public override IAsyncResult BeginFlush(AsyncCallback callback, object state)
+        {
+            // Extract request and reset buffer
+            byte[] data = outputStream.ToArray();
+
+            FlushAsyncResult flushAsyncResult = new FlushAsyncResult(callback, state);
+
+            SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
+            socketEventArg.RemoteEndPoint = socket.RemoteEndPoint;
+            socketEventArg.UserToken = flushAsyncResult;
+
+            socketEventArg.Completed += beginFlush_Completed;
+            socketEventArg.SetBuffer(data, 0, data.Length);
+
+            socket.SendAsync(socketEventArg);
+
+            return flushAsyncResult;
+        }
+
+        public override void EndFlush(IAsyncResult asyncResult)
+        {
+            try
+            {
+                var flushAsyncResult = (FlushAsyncResult)asyncResult;
+
+                if (!flushAsyncResult.IsCompleted)
+                {
+                    var waitHandle = flushAsyncResult.AsyncWaitHandle;
+                    waitHandle.WaitOne();
+                    waitHandle.Close();
+                }
+
+                if (flushAsyncResult.AsyncException != null)
+                {
+                    throw flushAsyncResult.AsyncException;
+                }
+            }
+            finally
+            {
+                outputStream = new MemoryStream();
+            }
+        }
+
+        // Copy from impl from THttpClient.cs
+        // Based on http://msmvps.com/blogs/luisabreu/archive/2009/06/15/multithreading-implementing-the-iasyncresult-interface.aspx
+        class FlushAsyncResult : IAsyncResult
+        {
+            private volatile Boolean _isCompleted;
+            private ManualResetEvent _evt;
+            private readonly AsyncCallback _cbMethod;
+            private readonly object _state;
+
+            public FlushAsyncResult(AsyncCallback cbMethod, object state)
+            {
+                _cbMethod = cbMethod;
+                _state = state;
+            }
+
+            internal byte[] Data { get; set; }
+            internal Socket Connection { get; set; }
+            internal TTransportException AsyncException { get; set; }
+
+            public object AsyncState
+            {
+                get { return _state; }
+            }
+
+            public WaitHandle AsyncWaitHandle
+            {
+                get { return GetEvtHandle(); }
+            }
+
+            public bool CompletedSynchronously
+            {
+                get { return false; }
+            }
+
+            public bool IsCompleted
+            {
+                get { return _isCompleted; }
+            }
+
+            private readonly object _locker = new object();
+
+            private ManualResetEvent GetEvtHandle()
+            {
+                lock (_locker)
+                {
+                    if (_evt == null)
+                    {
+                        _evt = new ManualResetEvent(false);
+                    }
+                    if (_isCompleted)
+                    {
+                        _evt.Set();
+                    }
+                }
+                return _evt;
+            }
+
+            internal void UpdateStatusToComplete()
+            {
+                _isCompleted = true; //1. set _iscompleted to true
+                lock (_locker)
+                {
+                    if (_evt != null)
+                    {
+                        _evt.Set(); //2. set the event, when it exists
+                    }
+                }
+            }
+
+            internal void NotifyCallbackWhenAvailable()
+            {
+                if (_cbMethod != null)
+                {
+                    _cbMethod(this);
+                }
+            }
+        }
+
+        public override void Close()
+        {
+            if (socket != null)
+            {
+                socket.Close();
+                socket = null;
+            }
+        }
+
+#region " IDisposable Support "
+        private bool _IsDisposed;
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (outputStream != null)
+                    {
+                        outputStream.Dispose();
+                    }
+                    outputStream = null;
+                    if (socket != null)
+                    {
+                        ((IDisposable)socket).Dispose();
+                    }
+                }
+            }
+            _IsDisposed = true;
+        }
+#endregion
+    }
+}
+
+
+#endif
diff --git a/lib/csharp/src/Transport/TSocket.cs b/lib/csharp/src/Transport/TSocket.cs
index 1d50968..d8fa335 100644
--- a/lib/csharp/src/Transport/TSocket.cs
+++ b/lib/csharp/src/Transport/TSocket.cs
@@ -26,117 +26,118 @@
 
 namespace Thrift.Transport
 {
-	public class TSocket : TStreamTransport
-	{
-		private TcpClient client = null;
-		private string host = null;
-		private int port = 0;
-		private int timeout = 0;
+    public class TSocket : TStreamTransport
+    {
+        private TcpClient client = null;
+        private string host = null;
+        private int port = 0;
+        private int timeout = 0;
 
-		public TSocket(TcpClient client)
-		{
-			this.client = client;
+        public TSocket(TcpClient client)
+        {
+            this.client = client;
 
-			if (IsOpen)
-			{
-				inputStream = client.GetStream();
-				outputStream = client.GetStream();
-			}
-		}
+            if (IsOpen)
+            {
+                inputStream = client.GetStream();
+                outputStream = client.GetStream();
+            }
+        }
 
-		public TSocket(string host, int port) : this(host, port, 0)
-		{
-		}
+        public TSocket(string host, int port)
+            : this(host, port, 0)
+        {
+        }
 
-		public TSocket(string host, int port, int timeout)
-		{
-			this.host = host;
-			this.port = port;
-			this.timeout = timeout;
+        public TSocket(string host, int port, int timeout)
+        {
+            this.host = host;
+            this.port = port;
+            this.timeout = timeout;
 
-			InitSocket();
-		}
+            InitSocket();
+        }
 
-		private void InitSocket()
-		{
-			client = new TcpClient();
-			client.ReceiveTimeout = client.SendTimeout = timeout;
-			client.Client.NoDelay = true;
-		}
+        private void InitSocket()
+        {
+            this.client = TSocketVersionizer.CreateTcpClient();
+            this.client.ReceiveTimeout = client.SendTimeout = timeout;
+            this.client.Client.NoDelay = true;
+        }
 
-		public int Timeout
-		{
-			set
-			{
-				client.ReceiveTimeout = client.SendTimeout = timeout = value;
-			}
-		}
+        public int Timeout
+        {
+            set
+            {
+                client.ReceiveTimeout = client.SendTimeout = timeout = value;
+            }
+        }
 
-		public TcpClient TcpClient
-		{
-			get
-			{
-				return client;
-			}
-		}
+        public TcpClient TcpClient
+        {
+            get
+            {
+                return client;
+            }
+        }
 
-		public string Host
-		{
-			get
-			{
-				return host;
-			}
-		}
+        public string Host
+        {
+            get
+            {
+                return host;
+            }
+        }
 
-		public int Port
-		{
-			get
-			{
-				return port;
-			}
-		}
+        public int Port
+        {
+            get
+            {
+                return port;
+            }
+        }
 
-		public override bool IsOpen
-		{
-			get
-			{
-				if (client == null)
-				{
-					return false;
-				}
+        public override bool IsOpen
+        {
+            get
+            {
+                if (client == null)
+                {
+                    return false;
+                }
 
-				return client.Connected;
-			}
-		}
+                return client.Connected;
+            }
+        }
 
-		public override void Open()
-		{
-			if (IsOpen)
-			{
-				throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
-			}
+        public override void Open()
+        {
+            if (IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
+            }
 
-			if (String.IsNullOrEmpty(host))
-			{
-				throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host");
-			}
+            if (string.IsNullOrEmpty(host))
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host");
+            }
 
-			if (port <= 0)
-			{
-				throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
-			}
+            if (port <= 0)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
+            }
 
-			if (client == null)
-			{
-				InitSocket();
-			}
+            if (client == null)
+            {
+                InitSocket();
+            }
 
-			if( timeout == 0)			// no timeout -> infinite
-			{
-				client.Connect(host, port);
-			}
-			else                        // we have a timeout -> use it
-			{
+            if (timeout == 0)            // no timeout -> infinite
+            {
+                client.Connect(host, port);
+            }
+            else                        // we have a timeout -> use it
+            {
                 ConnectHelper hlp = new ConnectHelper(client);
                 IAsyncResult asyncres = client.BeginConnect(host, port, new AsyncCallback(ConnectCallback), hlp);
                 bool bConnected = asyncres.AsyncWaitHandle.WaitOne(timeout) && client.Connected;
@@ -144,7 +145,7 @@
                 {
                     lock (hlp.Mutex)
                     {
-                        if( hlp.CallbackDone)
+                        if (hlp.CallbackDone)
                         {
                             asyncres.AsyncWaitHandle.Close();
                             client.Close();
@@ -157,11 +158,11 @@
                     }
                     throw new TTransportException(TTransportException.ExceptionType.TimedOut, "Connect timed out");
                 }
-			}
+            }
 
-			inputStream = client.GetStream();
-			outputStream = client.GetStream();
-		}
+            inputStream = client.GetStream();
+            outputStream = client.GetStream();
+        }
 
 
         static void ConnectCallback(IAsyncResult asyncres)
@@ -170,22 +171,31 @@
             lock (hlp.Mutex)
             {
                 hlp.CallbackDone = true;
-                    
+
                 try
                 {
-                    if( hlp.Client.Client != null)
+                    if (hlp.Client.Client != null)
                         hlp.Client.EndConnect(asyncres);
                 }
-                catch (SocketException)
+                catch (Exception)
                 {
                     // catch that away
                 }
 
-                if (hlp.DoCleanup) 
+                if (hlp.DoCleanup)
                 {
-                    asyncres.AsyncWaitHandle.Close();
-                    if (hlp.Client is IDisposable)
-                        ((IDisposable)hlp.Client).Dispose();
+                    try
+                    {
+                        asyncres.AsyncWaitHandle.Close();
+                    }
+                    catch (Exception) { }
+
+                    try
+                    {
+                        if (hlp.Client is IDisposable)
+                            ((IDisposable)hlp.Client).Dispose();
+                    }
+                    catch (Exception) { }
                     hlp.Client = null;
                 }
             }
@@ -203,33 +213,33 @@
             }
         }
 
-		public override void Close()
-		{
-			base.Close();
-			if (client != null)
-			{
-				client.Close();
-				client = null;
-			}
-		}
-
-    #region " IDisposable Support "
-    private bool _IsDisposed;
-
-    // IDisposable
-    protected override void Dispose(bool disposing)
-    {
-      if (!_IsDisposed)
-      {
-        if (disposing)
+        public override void Close()
         {
-          if (client != null)
-            ((IDisposable)client).Dispose();
-          base.Dispose(disposing);
+            base.Close();
+            if (client != null)
+            {
+                client.Close();
+                client = null;
+            }
         }
-      }
-      _IsDisposed = true;
+
+        #region " IDisposable Support "
+        private bool _IsDisposed;
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (client != null)
+                        ((IDisposable)client).Dispose();
+                    base.Dispose(disposing);
+                }
+            }
+            _IsDisposed = true;
+        }
+        #endregion
     }
-    #endregion
-  }
 }
diff --git a/lib/csharp/src/Transport/TSocketVersionizer.cs b/lib/csharp/src/Transport/TSocketVersionizer.cs
new file mode 100644
index 0000000..bf4c0e4
--- /dev/null
+++ b/lib/csharp/src/Transport/TSocketVersionizer.cs
@@ -0,0 +1,78 @@
+/**
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Sockets;
+using System.Reflection;
+using System.Text;
+#if NET45
+using System.Threading.Tasks;
+#endif
+
+namespace Thrift.Transport
+{
+    /// <summary>
+    /// PropertyInfo for the DualMode property of the System.Net.Sockets.Socket class. Used to determine if the sockets are capable of
+    /// automatic IPv4 and IPv6 handling. If DualMode is present the sockets automatically handle IPv4 and IPv6 connections.
+    /// If the DualMode is not available the system configuration determines whether IPv4 or IPv6 is used.
+    /// </summary>
+    internal static class TSocketVersionizer
+    {
+        /// <summary>
+        /// Creates a TcpClient according to the capabilitites of the used framework
+        /// </summary>
+        internal static TcpClient CreateTcpClient()
+        {
+            TcpClient client = null;
+
+#if NET45
+            client = new TcpClient(AddressFamily.InterNetworkV6);
+            client.Client.DualMode = true;
+#else
+            client = new TcpClient(AddressFamily.InterNetwork);
+#endif
+
+            return client;
+        }
+
+        /// <summary>
+        /// Creates a TcpListener according to the capabilitites of the used framework.
+        /// </summary>
+        internal static TcpListener CreateTcpListener(Int32 port)
+        {
+            TcpListener listener = null;
+
+#if NET45
+            listener = new TcpListener(System.Net.IPAddress.IPv6Any, port);
+            listener.Server.DualMode = true;
+#else
+
+            listener = new TcpListener(System.Net.IPAddress.Any, port);
+#endif
+
+            return listener;
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TStreamTransport.cs b/lib/csharp/src/Transport/TStreamTransport.cs
index 901b609..304599f 100644
--- a/lib/csharp/src/Transport/TStreamTransport.cs
+++ b/lib/csharp/src/Transport/TStreamTransport.cs
@@ -26,103 +26,103 @@
 
 namespace Thrift.Transport
 {
-	public class TStreamTransport : TTransport
-	{
-		protected Stream inputStream;
-		protected Stream outputStream;
-
-		public TStreamTransport()
-		{
-		}
-
-		public TStreamTransport(Stream inputStream, Stream outputStream)
-		{
-			this.inputStream = inputStream;
-			this.outputStream = outputStream;
-		}
-
-		public Stream OutputStream
-		{
-			get { return outputStream; }
-		}
-
-		public Stream InputStream
-		{
-			get { return inputStream; }
-		}
-
-		public override bool IsOpen
-		{
-			get { return true; }
-		}
-
-		public override void Open()
-		{
-		}
-
-		public override void Close()
-		{
-			if (inputStream != null)
-			{
-				inputStream.Close();
-				inputStream = null;
-			}
-			if (outputStream != null)
-			{
-				outputStream.Close();
-				outputStream = null;
-			}
-		}
-
-		public override int Read(byte[] buf, int off, int len)
-		{
-			if (inputStream == null)
-			{
-				throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot read from null inputstream");
-			}
-
-			return inputStream.Read(buf, off, len);
-		}
-
-		public override void Write(byte[] buf, int off, int len)
-		{
-			if (outputStream == null)
-			{
-				throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot write to null outputstream");
-			}
-
-			outputStream.Write(buf, off, len);
-		}
-
-		public override void Flush()
-		{
-			if (outputStream == null)
-			{
-				throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot flush null outputstream");
-			}
-
-			outputStream.Flush();
-		}
-
-
-    #region " IDisposable Support "
-    private bool _IsDisposed;
-
-    // IDisposable
-    protected override void Dispose(bool disposing)
+    public class TStreamTransport : TTransport
     {
-      if (!_IsDisposed)
-      {
-        if (disposing)
+        protected Stream inputStream;
+        protected Stream outputStream;
+
+        protected TStreamTransport()
         {
-          if (InputStream != null)
-            InputStream.Dispose();
-          if (OutputStream != null)
-            OutputStream.Dispose();
         }
-      }
-      _IsDisposed = true;
+
+        public TStreamTransport(Stream inputStream, Stream outputStream)
+        {
+            this.inputStream = inputStream;
+            this.outputStream = outputStream;
+        }
+
+        public Stream OutputStream
+        {
+            get { return outputStream; }
+        }
+
+        public Stream InputStream
+        {
+            get { return inputStream; }
+        }
+
+        public override bool IsOpen
+        {
+            get { return true; }
+        }
+
+        public override void Open()
+        {
+        }
+
+        public override void Close()
+        {
+            if (inputStream != null)
+            {
+                inputStream.Close();
+                inputStream = null;
+            }
+            if (outputStream != null)
+            {
+                outputStream.Close();
+                outputStream = null;
+            }
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            if (inputStream == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot read from null inputstream");
+            }
+
+            return inputStream.Read(buf, off, len);
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            if (outputStream == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot write to null outputstream");
+            }
+
+            outputStream.Write(buf, off, len);
+        }
+
+        public override void Flush()
+        {
+            if (outputStream == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot flush null outputstream");
+            }
+
+            outputStream.Flush();
+        }
+
+
+        #region " IDisposable Support "
+        private bool _IsDisposed;
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_IsDisposed)
+            {
+                if (disposing)
+                {
+                    if (InputStream != null)
+                        InputStream.Dispose();
+                    if (OutputStream != null)
+                        OutputStream.Dispose();
+                }
+            }
+            _IsDisposed = true;
+        }
+        #endregion
     }
-    #endregion
-  }
 }
diff --git a/lib/csharp/src/Transport/TTLSServerSocket.cs b/lib/csharp/src/Transport/TTLSServerSocket.cs
new file mode 100644
index 0000000..716a97c
--- /dev/null
+++ b/lib/csharp/src/Transport/TTLSServerSocket.cs
@@ -0,0 +1,223 @@
+/**
+ * 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.
+ */
+
+using System;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Thrift.Transport
+{
+    /// <summary>
+    /// SSL Server Socket Wrapper Class
+    /// </summary>
+    public class TTLSServerSocket : TServerTransport
+    {
+        /// <summary>
+        /// Underlying tcp server
+        /// </summary>
+        private TcpListener server = null;
+
+        /// <summary>
+        /// The port where the socket listen
+        /// </summary>
+        private int port = 0;
+
+        /// <summary>
+        /// Timeout for the created server socket
+        /// </summary>
+        private readonly int clientTimeout;
+
+        /// <summary>
+        /// Whether or not to wrap new TSocket connections in buffers
+        /// </summary>
+        private bool useBufferedSockets = false;
+
+        /// <summary>
+        /// The servercertificate with the private- and public-key
+        /// </summary>
+        private X509Certificate serverCertificate;
+
+        /// <summary>
+        /// The function to validate the client certificate.
+        /// </summary>
+        private RemoteCertificateValidationCallback clientCertValidator;
+
+        /// <summary>
+        /// The function to determine which certificate to use.
+        /// </summary>
+        private LocalCertificateSelectionCallback localCertificateSelectionCallback;
+
+        /// <summary>
+        /// The SslProtocols value that represents the protocol used for authentication.
+        /// </summary>
+        private readonly SslProtocols sslProtocols;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSServerSocket" /> class.
+        /// </summary>
+        /// <param name="port">The port where the server runs.</param>
+        /// <param name="certificate">The certificate object.</param>
+        public TTLSServerSocket(int port, X509Certificate2 certificate)
+            : this(port, 0, certificate)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSServerSocket" /> class.
+        /// </summary>
+        /// <param name="port">The port where the server runs.</param>
+        /// <param name="clientTimeout">Send/receive timeout.</param>
+        /// <param name="certificate">The certificate object.</param>
+        public TTLSServerSocket(int port, int clientTimeout, X509Certificate2 certificate)
+            : this(port, clientTimeout, false, certificate)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSServerSocket" /> class.
+        /// </summary>
+        /// <param name="port">The port where the server runs.</param>
+        /// <param name="clientTimeout">Send/receive timeout.</param>
+        /// <param name="useBufferedSockets">If set to <c>true</c> [use buffered sockets].</param>
+        /// <param name="certificate">The certificate object.</param>
+        /// <param name="clientCertValidator">The certificate validator.</param>
+        /// <param name="localCertificateSelectionCallback">The callback to select which certificate to use.</param>
+        /// <param name="sslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
+        public TTLSServerSocket(
+            int port,
+            int clientTimeout,
+            bool useBufferedSockets,
+            X509Certificate2 certificate,
+            RemoteCertificateValidationCallback clientCertValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            // TODO: Enable Tls11 and Tls12 (TLS 1.1 and 1.2) by default once we start using .NET 4.5+.
+            SslProtocols sslProtocols = SslProtocols.Tls)
+        {
+            if (!certificate.HasPrivateKey)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, "Your server-certificate needs to have a private key");
+            }
+
+            this.port = port;
+            this.clientTimeout = clientTimeout;
+            this.serverCertificate = certificate;
+            this.useBufferedSockets = useBufferedSockets;
+            this.clientCertValidator = clientCertValidator;
+            this.localCertificateSelectionCallback = localCertificateSelectionCallback;
+            this.sslProtocols = sslProtocols;
+            try
+            {
+                // Create server socket
+                this.server = TSocketVersionizer.CreateTcpListener(this.port);
+                this.server.Server.NoDelay = true;
+            }
+            catch (Exception ex)
+            {
+                server = null;
+                throw new TTransportException("Could not create ServerSocket on port " + this.port + ".", ex);
+            }
+        }
+
+        /// <summary>
+        /// Starts the server.
+        /// </summary>
+        public override void Listen()
+        {
+            // Make sure accept is not blocking
+            if (this.server != null)
+            {
+                try
+                {
+                    this.server.Start();
+                }
+                catch (SocketException sx)
+                {
+                    throw new TTransportException("Could not accept on listening socket: " + sx.Message, sx);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Callback for Accept Implementation
+        /// </summary>
+        /// <returns>
+        /// TTransport-object.
+        /// </returns>
+        protected override TTransport AcceptImpl()
+        {
+            if (this.server == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket.");
+            }
+
+            try
+            {
+                TcpClient client = this.server.AcceptTcpClient();
+                client.SendTimeout = client.ReceiveTimeout = this.clientTimeout;
+
+                //wrap the client in an SSL Socket passing in the SSL cert
+                TTLSSocket socket = new TTLSSocket(
+                    client,
+                    this.serverCertificate,
+                    true,
+                    this.clientCertValidator,
+                    this.localCertificateSelectionCallback,
+                    this.sslProtocols);
+
+                socket.setupTLS();
+
+                if (useBufferedSockets)
+                {
+                    TBufferedTransport trans = new TBufferedTransport(socket);
+                    return trans;
+                }
+                else
+                {
+                    return socket;
+                }
+
+            }
+            catch (Exception ex)
+            {
+                throw new TTransportException(ex.ToString(), ex);
+            }
+        }
+
+        /// <summary>
+        /// Stops the Server
+        /// </summary>
+        public override void Close()
+        {
+            if (this.server != null)
+            {
+                try
+                {
+                    this.server.Stop();
+                }
+                catch (Exception ex)
+                {
+                    throw new TTransportException("WARNING: Could not close server socket: " + ex, ex);
+                }
+                this.server = null;
+            }
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TTLSSocket.cs b/lib/csharp/src/Transport/TTLSSocket.cs
new file mode 100644
index 0000000..fd019c3
--- /dev/null
+++ b/lib/csharp/src/Transport/TTLSSocket.cs
@@ -0,0 +1,371 @@
+/**
+ * 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.
+ */
+
+using System;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Thrift.Transport
+{
+    /// <summary>
+    /// SSL Socket Wrapper class
+    /// </summary>
+    public class TTLSSocket : TStreamTransport
+    {
+        /// <summary>
+        /// Internal TCP Client
+        /// </summary>
+        private TcpClient client;
+
+        /// <summary>
+        /// The host
+        /// </summary>
+        private string host;
+
+        /// <summary>
+        /// The port
+        /// </summary>
+        private int port;
+
+        /// <summary>
+        /// The timeout for the connection
+        /// </summary>
+        private int timeout;
+
+        /// <summary>
+        /// Internal SSL Stream for IO
+        /// </summary>
+        private SslStream secureStream;
+
+        /// <summary>
+        /// Defines wheter or not this socket is a server socket<br/>
+        /// This is used for the TLS-authentication
+        /// </summary>
+        private bool isServer;
+
+        /// <summary>
+        /// The certificate
+        /// </summary>
+        private X509Certificate certificate;
+
+        /// <summary>
+        /// User defined certificate validator.
+        /// </summary>
+        private RemoteCertificateValidationCallback certValidator;
+
+        /// <summary>
+        /// The function to determine which certificate to use.
+        /// </summary>
+        private LocalCertificateSelectionCallback localCertificateSelectionCallback;
+
+        /// <summary>
+        /// The SslProtocols value that represents the protocol used for authentication.SSL protocols to be used.
+        /// </summary>
+        private readonly SslProtocols sslProtocols;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSSocket"/> class.
+        /// </summary>
+        /// <param name="client">An already created TCP-client</param>
+        /// <param name="certificate">The certificate.</param>
+        /// <param name="isServer">if set to <c>true</c> [is server].</param>
+        /// <param name="certValidator">User defined cert validator.</param>
+        /// <param name="localCertificateSelectionCallback">The callback to select which certificate to use.</param>
+        /// <param name="sslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
+        public TTLSSocket(
+            TcpClient client,
+            X509Certificate certificate,
+            bool isServer = false,
+            RemoteCertificateValidationCallback certValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            // TODO: Enable Tls11 and Tls12 (TLS 1.1 and 1.2) by default once we start using .NET 4.5+.
+            SslProtocols sslProtocols = SslProtocols.Tls)
+        {
+            this.client = client;
+            this.certificate = certificate;
+            this.certValidator = certValidator;
+            this.localCertificateSelectionCallback = localCertificateSelectionCallback;
+            this.sslProtocols = sslProtocols;
+            this.isServer = isServer;
+            if (isServer && certificate == null)
+            {
+                throw new ArgumentException("TTLSSocket needs certificate to be used for server", "certificate");
+            }
+
+            if (IsOpen)
+            {
+                base.inputStream = client.GetStream();
+                base.outputStream = client.GetStream();
+            }
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSSocket"/> class.
+        /// </summary>
+        /// <param name="host">The host, where the socket should connect to.</param>
+        /// <param name="port">The port.</param>
+        /// <param name="certificatePath">The certificate path.</param>
+        /// <param name="certValidator">User defined cert validator.</param>
+        /// <param name="localCertificateSelectionCallback">The callback to select which certificate to use.</param>
+        /// <param name="sslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
+        public TTLSSocket(
+            string host,
+            int port,
+            string certificatePath,
+            RemoteCertificateValidationCallback certValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            SslProtocols sslProtocols = SslProtocols.Tls)
+            : this(host, port, 0, X509Certificate.CreateFromCertFile(certificatePath), certValidator, localCertificateSelectionCallback, sslProtocols)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSSocket"/> class.
+        /// </summary>
+        /// <param name="host">The host, where the socket should connect to.</param>
+        /// <param name="port">The port.</param>
+        /// <param name="certificate">The certificate.</param>
+        /// <param name="certValidator">User defined cert validator.</param>
+        /// <param name="localCertificateSelectionCallback">The callback to select which certificate to use.</param>
+        /// <param name="sslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
+        public TTLSSocket(
+            string host,
+            int port,
+            X509Certificate certificate = null,
+            RemoteCertificateValidationCallback certValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            SslProtocols sslProtocols = SslProtocols.Tls)
+            : this(host, port, 0, certificate, certValidator, localCertificateSelectionCallback, sslProtocols)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TTLSSocket"/> class.
+        /// </summary>
+        /// <param name="host">The host, where the socket should connect to.</param>
+        /// <param name="port">The port.</param>
+        /// <param name="timeout">The timeout.</param>
+        /// <param name="certificate">The certificate.</param>
+        /// <param name="certValidator">User defined cert validator.</param>
+        /// <param name="localCertificateSelectionCallback">The callback to select which certificate to use.</param>
+        /// <param name="sslProtocols">The SslProtocols value that represents the protocol used for authentication.</param>
+        public TTLSSocket(
+            string host,
+            int port,
+            int timeout,
+            X509Certificate certificate,
+            RemoteCertificateValidationCallback certValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            SslProtocols sslProtocols = SslProtocols.Tls)
+        {
+            this.host = host;
+            this.port = port;
+            this.timeout = timeout;
+            this.certificate = certificate;
+            this.certValidator = certValidator;
+            this.localCertificateSelectionCallback = localCertificateSelectionCallback;
+            this.sslProtocols = sslProtocols;
+
+            InitSocket();
+        }
+
+        /// <summary>
+        /// Creates the TcpClient and sets the timeouts
+        /// </summary>
+        private void InitSocket()
+        {
+            client = TSocketVersionizer.CreateTcpClient();
+            client.ReceiveTimeout = client.SendTimeout = timeout;
+            client.Client.NoDelay = true;
+        }
+
+        /// <summary>
+        /// Sets Send / Recv Timeout for IO
+        /// </summary>
+        public int Timeout
+        {
+            set
+            {
+                this.client.ReceiveTimeout = this.client.SendTimeout = this.timeout = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets the TCP client.
+        /// </summary>
+        public TcpClient TcpClient
+        {
+            get
+            {
+                return client;
+            }
+        }
+
+        /// <summary>
+        /// Gets the host.
+        /// </summary>
+        public string Host
+        {
+            get
+            {
+                return host;
+            }
+        }
+
+        /// <summary>
+        /// Gets the port.
+        /// </summary>
+        public int Port
+        {
+            get
+            {
+                return port;
+            }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether TCP Client is Cpen
+        /// </summary>
+        public override bool IsOpen
+        {
+            get
+            {
+                if (this.client == null)
+                {
+                    return false;
+                }
+
+                return this.client.Connected;
+            }
+        }
+
+        /// <summary>
+        /// Validates the certificates!<br/>
+        /// </summary>
+        /// <param name="sender">The sender-object.</param>
+        /// <param name="certificate">The used certificate.</param>
+        /// <param name="chain">The certificate chain.</param>
+        /// <param name="sslValidationErrors">An enum, which lists all the errors from the .NET certificate check.</param>
+        /// <returns></returns>
+        private bool DefaultCertificateValidator(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslValidationErrors)
+        {
+            return (sslValidationErrors == SslPolicyErrors.None);
+        }
+
+        /// <summary>
+        /// Connects to the host and starts the routine, which sets up the TLS
+        /// </summary>
+        public override void Open()
+        {
+            if (IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
+            }
+
+            if (string.IsNullOrEmpty(host))
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host");
+            }
+
+            if (port <= 0)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
+            }
+
+            if (client == null)
+            {
+                InitSocket();
+            }
+
+            client.Connect(host, port);
+
+            setupTLS();
+        }
+
+        /// <summary>
+        /// Creates a TLS-stream and lays it over the existing socket
+        /// </summary>
+        public void setupTLS()
+        {
+            RemoteCertificateValidationCallback validator = this.certValidator ?? DefaultCertificateValidator;
+
+            if (this.localCertificateSelectionCallback != null)
+            {
+                this.secureStream = new SslStream(
+                    this.client.GetStream(),
+                    false,
+                    validator,
+                    this.localCertificateSelectionCallback
+                );
+            }
+            else
+            {
+                this.secureStream = new SslStream(
+                    this.client.GetStream(),
+                    false,
+                    validator
+                );
+            }
+
+            try
+            {
+                if (isServer)
+                {
+                    // Server authentication
+                    this.secureStream.AuthenticateAsServer(this.certificate, this.certValidator != null, sslProtocols, true);
+                }
+                else
+                {
+                    // Client authentication
+                    X509CertificateCollection certs = certificate != null ? new X509CertificateCollection { certificate } : new X509CertificateCollection();
+                    this.secureStream.AuthenticateAsClient(host, certs, sslProtocols, true);
+                }
+            }
+            catch (Exception)
+            {
+                this.Close();
+                throw;
+            }
+
+            inputStream = this.secureStream;
+            outputStream = this.secureStream;
+        }
+
+        /// <summary>
+        /// Closes the SSL Socket
+        /// </summary>
+        public override void Close()
+        {
+            base.Close();
+            if (this.client != null)
+            {
+                this.client.Close();
+                this.client = null;
+            }
+
+            if (this.secureStream != null)
+            {
+                this.secureStream.Close();
+                this.secureStream = null;
+            }
+        }
+    }
+}
diff --git a/lib/csharp/src/Transport/TTransport.cs b/lib/csharp/src/Transport/TTransport.cs
index c03e9c2..5e4ac22 100644
--- a/lib/csharp/src/Transport/TTransport.cs
+++ b/lib/csharp/src/Transport/TTransport.cs
@@ -22,77 +22,125 @@
  */
 
 using System;
+using System.IO;
 
 namespace Thrift.Transport
 {
-	public abstract class TTransport : IDisposable
-	{
-		public abstract bool IsOpen
-		{
-			get;
-		}
+    public abstract class TTransport : IDisposable
+    {
+        public abstract bool IsOpen
+        {
+            get;
+        }
 
-		public bool Peek()
-		{
-			return IsOpen;
-		}
+        private byte[] _peekBuffer = new byte[1];
+        private bool _hasPeekByte;
 
-		public abstract void Open();
+        public bool Peek()
+        {
+            //If we already have a byte read but not consumed, do nothing.
+            if (_hasPeekByte)
+                return true;
 
-		public abstract void Close();
+            //If transport closed we can't peek.
+            if (!IsOpen)
+                return false;
 
-		public abstract int Read(byte[] buf, int off, int len);
+            //Try to read one byte. If succeeds we will need to store it for the next read.
+            try
+            {
+                int bytes = Read(_peekBuffer, 0, 1);
+                if (bytes == 0)
+                    return false;
+            }
+            catch (IOException)
+            {
+                return false;
+            }
 
-		public int ReadAll(byte[] buf, int off, int len)
-		{
-			int got = 0;
-			int ret = 0;
+            _hasPeekByte = true;
+            return true;
+        }
 
-			while (got < len)
-			{
-				ret = Read(buf, off + got, len - got);
-				if (ret <= 0)
-				{
-					throw new TTransportException(
-						TTransportException.ExceptionType.EndOfFile,
-						"Cannot read, Remote side has closed");
-				}
-				got += ret;
-			}
+        public abstract void Open();
 
-			return got;
-		}
+        public abstract void Close();
 
-		public virtual void Write(byte[] buf) 
-		{
-			Write (buf, 0, buf.Length);
-		}
+        protected static void ValidateBufferArgs(byte[] buf, int off, int len)
+        {
+            if (buf == null)
+                throw new ArgumentNullException("buf");
+            if (off < 0)
+                throw new ArgumentOutOfRangeException("Buffer offset is smaller than zero.");
+            if (len < 0)
+                throw new ArgumentOutOfRangeException("Buffer length is smaller than zero.");
+            if (off + len > buf.Length)
+                throw new ArgumentOutOfRangeException("Not enough data.");
+        }
 
-		public abstract void Write(byte[] buf, int off, int len);
+        public abstract int Read(byte[] buf, int off, int len);
 
-		public virtual void Flush()
-		{
-		}
-        
+        public int ReadAll(byte[] buf, int off, int len)
+        {
+            ValidateBufferArgs(buf, off, len);
+            int got = 0;
+
+            //If we previously peeked a byte, we need to use that first.
+            if (_hasPeekByte)
+            {
+                buf[off + got++] = _peekBuffer[0];
+                _hasPeekByte = false;
+            }
+
+            while (got < len)
+            {
+                int ret = Read(buf, off + got, len - got);
+                if (ret <= 0)
+                {
+                    throw new TTransportException(
+                        TTransportException.ExceptionType.EndOfFile,
+                        "Cannot read, Remote side has closed");
+                }
+                got += ret;
+            }
+            return got;
+        }
+
+        public virtual void Write(byte[] buf)
+        {
+            Write(buf, 0, buf.Length);
+        }
+
+        public abstract void Write(byte[] buf, int off, int len);
+
+        public virtual void Flush()
+        {
+        }
+
         public virtual IAsyncResult BeginFlush(AsyncCallback callback, object state)
         {
-            return null;
+            throw new TTransportException(
+                TTransportException.ExceptionType.Unknown,
+                "Asynchronous operations are not supported by this transport.");
         }
 
         public virtual void EndFlush(IAsyncResult asyncResult)
         {
+            throw new TTransportException(
+                TTransportException.ExceptionType.Unknown,
+                "Asynchronous operations are not supported by this transport.");
         }
 
-		#region " IDisposable Support "
-		// IDisposable
-		protected abstract void Dispose(bool disposing);
+        #region " IDisposable Support "
+        // IDisposable
+        protected abstract void Dispose(bool disposing);
 
-		public void Dispose()
-		{
-			// Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
-			Dispose(true);
-			GC.SuppressFinalize(this);
-		}
-		#endregion
-	}
+        public void Dispose()
+        {
+            // Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+        #endregion
+    }
 }
diff --git a/lib/csharp/src/Transport/TTransportException.cs b/lib/csharp/src/Transport/TTransportException.cs
index fda0138..7f6cc18 100644
--- a/lib/csharp/src/Transport/TTransportException.cs
+++ b/lib/csharp/src/Transport/TTransportException.cs
@@ -25,44 +25,45 @@
 
 namespace Thrift.Transport
 {
-	public class TTransportException : TException
-	{
-		protected ExceptionType type;
+    public class TTransportException : TException
+    {
+        protected ExceptionType type;
 
-		public TTransportException()
-			: base()
-		{
-		}
+        public TTransportException()
+            : base()
+        {
+        }
 
-		public TTransportException(ExceptionType type)
-			: this()
-		{
-			this.type = type;
-		}
+        public TTransportException(ExceptionType type)
+            : this()
+        {
+            this.type = type;
+        }
 
-		public TTransportException(ExceptionType type, string message)
-			: base(message)
-		{
-			this.type = type;
-		}
+        public TTransportException(ExceptionType type, string message, Exception inner = null)
+            : base(message, inner)
+        {
+            this.type = type;
+        }
 
-		public TTransportException(string message)
-			: base(message)
-		{
-		}
+        public TTransportException(string message, Exception inner = null)
+            : base(message, inner)
+        {
+        }
 
-		public ExceptionType Type
-		{
-			get { return type; }
-		}
+        public ExceptionType Type
+        {
+            get { return type; }
+        }
 
-		public enum ExceptionType
-		{
-			Unknown,
-			NotOpen,
-			AlreadyOpen,
-			TimedOut,
-			EndOfFile
-		}
-	}
+        public enum ExceptionType
+        {
+            Unknown,
+            NotOpen,
+            AlreadyOpen,
+            TimedOut,
+            EndOfFile,
+            Interrupted
+        }
+    }
 }
diff --git a/lib/csharp/src/Transport/TTransportFactory.cs b/lib/csharp/src/Transport/TTransportFactory.cs
index 8f4f15d..47a0c62 100644
--- a/lib/csharp/src/Transport/TTransportFactory.cs
+++ b/lib/csharp/src/Transport/TTransportFactory.cs
@@ -25,18 +25,18 @@
 
 namespace Thrift.Transport
 {
-	/// <summary>
-	/// From Mark Slee & Aditya Agarwal of Facebook:
-	/// 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)
-	/// </summary>
-	public class TTransportFactory
-	{
-		public virtual TTransport GetTransport(TTransport trans)
-		{
-			return trans;
-		}
-	}
+    /// <summary>
+    /// From Mark Slee &amp; Aditya Agarwal of Facebook:
+    /// 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)
+    /// </summary>
+    public class TTransportFactory
+    {
+        public virtual TTransport GetTransport(TTransport trans)
+        {
+            return trans;
+        }
+    }
 }
diff --git a/lib/csharp/test/JSON/JSONTest.csproj b/lib/csharp/test/JSON/JSONTest.csproj
new file mode 100644
index 0000000..f07d43e
--- /dev/null
+++ b/lib/csharp/test/JSON/JSONTest.csproj
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{E37A0034-DCBF-4886-A0DA-25A03D12D975}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>JSONTest</RootNamespace>
+    <AssemblyName>JSONTest</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <TargetFrameworkProfile>
+    </TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Thrift.csproj">
+      <Project>{499EB63C-D74C-47E8-AE48-A2FC94538E9D}</Project>
+      <Name>Thrift</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/lib/csharp/test/JSON/Program.cs b/lib/csharp/test/JSON/Program.cs
new file mode 100644
index 0000000..f61388a
--- /dev/null
+++ b/lib/csharp/test/JSON/Program.cs
@@ -0,0 +1,95 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Thrift.Protocol;
+using Thrift.Transport;
+
+namespace JSONTest
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            TestThrift2365();  // JSON binary decodes too much data
+            TestThrift2336();  // hex encoding using \uXXXX where 0xXXXX > 0xFF
+            TestThrift3403(); // JSON escaped unicode surrogate pair support.
+        }
+
+
+        public static void TestThrift2365()
+        {
+            var rnd = new Random();
+            for (var len = 0; len < 10; ++len)
+            {
+                byte[] dataWritten = new byte[len];
+                rnd.NextBytes(dataWritten);
+
+                Stream stm = new MemoryStream();
+                TTransport trans = new TStreamTransport(null, stm);
+                TProtocol prot = new TJSONProtocol(trans);
+                prot.WriteBinary(dataWritten);
+
+                stm.Position = 0;
+                trans = new TStreamTransport(stm, null);
+                prot = new TJSONProtocol(trans);
+                byte[] dataRead = prot.ReadBinary();
+
+                Debug.Assert(dataRead.Length == dataWritten.Length);
+                for (var i = 0; i < dataRead.Length; ++i)
+                    Debug.Assert(dataRead[i] == dataWritten[i]);
+            }
+        }
+
+
+        public static void TestThrift2336()
+        {
+            const string RUSSIAN_TEXT = "\u0420\u0443\u0441\u0441\u043a\u043e\u0435 \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435";
+            const string RUSSIAN_JSON = "\"\\u0420\\u0443\\u0441\\u0441\\u043a\\u043e\\u0435 \\u041d\\u0430\\u0437\\u0432\\u0430\\u043d\\u0438\\u0435\"";
+
+            // prepare buffer with JSON data
+            byte[] rawBytes = new byte[RUSSIAN_JSON.Length];
+            for (var i = 0; i < RUSSIAN_JSON.Length; ++i)
+                rawBytes[i] = (byte)(RUSSIAN_JSON[i] & (char)0xFF);  // only low bytes
+
+            // parse and check
+            var stm = new MemoryStream(rawBytes);
+            var trans = new TStreamTransport(stm, null);
+            var prot = new TJSONProtocol(trans);
+            Debug.Assert(prot.ReadString() == RUSSIAN_TEXT, "reading JSON with hex-encoded chars > 8 bit");
+        }
+
+        public static void TestThrift3403()
+        {
+            string GCLEF_TEXT = "\ud834\udd1e";
+            const string GCLEF_JSON = "\"\\ud834\\udd1e\"";
+
+            // parse and check
+            var stm = new MemoryStream(Encoding.UTF8.GetBytes(GCLEF_JSON));
+            var trans = new TStreamTransport(stm, null);
+            var prot = new TJSONProtocol(trans);
+            Debug.Assert(prot.ReadString() == GCLEF_TEXT, "reading JSON with surrogate pair hex-encoded chars");
+        }
+    }
+}
diff --git a/lib/csharp/test/JSON/Properties/AssemblyInfo.cs b/lib/csharp/test/JSON/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..fdff4a1
--- /dev/null
+++ b/lib/csharp/test/JSON/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Allgemeine Informationen über eine Assembly werden über die folgenden
+// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+// die mit einer Assembly verknüpft sind.
+[assembly: AssemblyTitle("JSONTest")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
+// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
+// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
+[assembly: ComVisible(false)]
+
+// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
+[assembly: Guid("2b2e7d56-3e65-4368-92d7-e34d56b7105e")]
+
+// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+//
+//      Hauptversion
+//      Nebenversion
+//      Buildnummer
+//      Revision
+//
+// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
+// übernehmen, indem Sie "*" eingeben:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/lib/csharp/test/JSON/app.config b/lib/csharp/test/JSON/app.config
new file mode 100644
index 0000000..9c1919d
--- /dev/null
+++ b/lib/csharp/test/JSON/app.config
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<configuration>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
diff --git a/lib/csharp/test/Multiplex/Client/Multiplex.Test.Client.cs b/lib/csharp/test/Multiplex/Client/Multiplex.Test.Client.cs
index 95ba5a4..c810a08 100644
--- a/lib/csharp/test/Multiplex/Client/Multiplex.Test.Client.cs
+++ b/lib/csharp/test/Multiplex/Client/Multiplex.Test.Client.cs
@@ -26,17 +26,16 @@
 using Thrift;
 using Test.Multiplex;
 
-
 namespace Test.Multiplex.Client
 {
-	public class TestClient
-	{
-        private void Run()
+    public class TestClient
+    {
+        static void Execute(int port)
         {
             try
             {
                 TTransport trans;
-                trans = new TSocket("localhost", 9090);
+                trans = new TSocket("localhost", port);
                 trans = new TFramedTransport(trans);
                 trans.Open();
 
@@ -44,44 +43,40 @@
 
                 TMultiplexedProtocol multiplex;
 
-                multiplex = new TMultiplexedProtocol( Protocol, Constants.NAME_BENCHMARKSERVICE);
-                BenchmarkService.Iface bench = new BenchmarkService.Client( multiplex);
+                multiplex = new TMultiplexedProtocol(Protocol, Constants.NAME_BENCHMARKSERVICE);
+                BenchmarkService.Iface bench = new BenchmarkService.Client(multiplex);
 
-                multiplex = new TMultiplexedProtocol( Protocol, Constants.NAME_AGGR);
-                Aggr.Iface aggr = new Aggr.Client( multiplex);
-                
-                sbyte i;
-                for( i = 1; 10 >= i; ++i)
+                multiplex = new TMultiplexedProtocol(Protocol, Constants.NAME_AGGR);
+                Aggr.Iface aggr = new Aggr.Client(multiplex);
+
+                for (sbyte i = 1; 10 >= i; ++i)
                 {
-                    aggr.addValue( bench.fibonacci(i));
+                    aggr.addValue(bench.fibonacci(i));
                 }
 
-                foreach( int k in aggr.getValues())
+                foreach (int k in aggr.getValues())
                 {
-                    Console.Write(k.ToString()+" ");
+                    Console.Write(k.ToString() + " ");
                     Console.WriteLine("");
                 }
+                trans.Close();
             }
-            catch( Exception e)
+            catch (Exception e)
             {
-                Console.WriteLine( e.Message);
+                Console.WriteLine(e.Message);
             }
         }
 
-
-        public static void Execute()
-        {
-            TestClient client = new TestClient();
-            client.Run();
-        }
-
         static void Main(string[] args)
         {
-            Execute();
+            int port = 9090;
+            if (args.Length > 0)
+            {
+                port = ushort.Parse(args[0]);
+            }
+            Execute(port);
             Console.WriteLine("done.");
-            Console.ReadLine();
         }
-
     }
 }
 
diff --git a/lib/csharp/test/Multiplex/Client/MultiplexClient.csproj b/lib/csharp/test/Multiplex/Client/MultiplexClient.csproj
index 6221e14..21e1ce1 100644
--- a/lib/csharp/test/Multiplex/Client/MultiplexClient.csproj
+++ b/lib/csharp/test/Multiplex/Client/MultiplexClient.csproj
@@ -46,7 +46,7 @@
     <UpdateRequired>false</UpdateRequired>
     <MapFileExtensions>true</MapFileExtensions>
     <ApplicationRevision>0</ApplicationRevision>
-    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <ApplicationVersion>1.0.0.0</ApplicationVersion>
     <UseApplicationTrust>false</UseApplicationTrust>
     <BootstrapperEnabled>true</BootstrapperEnabled>
   </PropertyGroup>
@@ -145,4 +145,4 @@
 
 </PreBuildEvent>
   </PropertyGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/lib/csharp/test/Multiplex/Client/Properties/AssemblyInfo.cs b/lib/csharp/test/Multiplex/Client/Properties/AssemblyInfo.cs
index ee234bf..f686ded 100644
--- a/lib/csharp/test/Multiplex/Client/Properties/AssemblyInfo.cs
+++ b/lib/csharp/test/Multiplex/Client/Properties/AssemblyInfo.cs
@@ -27,9 +27,9 @@
 [assembly: AssemblyTitle("MultiplexClient")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("MultiplexClient")]
-[assembly: AssemblyCopyright("Copyright © 2013 The Apache Software Foundation")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
diff --git a/lib/csharp/test/Multiplex/Makefile.am b/lib/csharp/test/Multiplex/Makefile.am
new file mode 100644
index 0000000..57253d6
--- /dev/null
+++ b/lib/csharp/test/Multiplex/Makefile.am
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+
+GENERATED = \
+	gen-csharp/Aggr.cs \
+	gen-csharp/BenchmarkService.cs \
+	gen-csharp/Error.cs
+
+BUILT_SOURCES = $(GENERATED)
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+gen-csharp/Aggr.cs: $(top_srcdir)/contrib/async-test/aggr.thrift
+	$(THRIFT) --gen csharp $<
+
+gen-csharp/BenchmarkService.cs gen-csharp/Error.cs: $(top_srcdir)/lib/rb/benchmark/Benchmark.thrift
+	$(THRIFT) --gen csharp $<
+
+ThriftImpl.dll: Multiplex.Test.Common.cs $(GENERATED) ../../Thrift.dll
+	$(CSC) $(CSC_DEFINES) -t:library -out:./ThriftImpl.dll -reference:../../Thrift.dll $(GENERATED) $<
+
+MultiplexClient.exe: Client/Multiplex.Test.Client.cs ThriftImpl.dll
+	$(CSC) $(CSC_DEFINES) -out:$@ -reference:../../Thrift.dll -reference:ThriftImpl.dll $<
+
+MultiplexServer.exe: Server/Multiplex.Test.Server.cs ThriftImpl.dll
+	$(CSC) $(CSC_DEFINES) -out:$@ -reference:../../Thrift.dll -reference:ThriftImpl.dll $<
+
+clean-local:
+	$(RM) -rf gen-csharp *.exe *.dll
+
+TESTPORT = 9501
+check-local: MultiplexServer.exe MultiplexClient.exe
+	echo $(TESTPORT)
+	MONO_PATH=../../ timeout 10 mono MultiplexServer.exe $(TESTPORT) &
+	sleep 1
+	MONO_PATH=../../ mono MultiplexClient.exe $(TESTPORT)
diff --git a/lib/csharp/test/Multiplex/Multiplex.Test.Common.cs b/lib/csharp/test/Multiplex/Multiplex.Test.Common.cs
index 5296b68..a687852 100644
--- a/lib/csharp/test/Multiplex/Multiplex.Test.Common.cs
+++ b/lib/csharp/test/Multiplex/Multiplex.Test.Common.cs
@@ -30,8 +30,8 @@
 
 namespace Test.Multiplex
 {
-	public class Constants
-	{
+    public class Constants
+    {
         public const string NAME_BENCHMARKSERVICE = "BenchmarkService";
         public const string NAME_AGGR             = "Aggr";
     }
diff --git a/lib/csharp/test/Multiplex/Server/Multiplex.Test.Server.cs b/lib/csharp/test/Multiplex/Server/Multiplex.Test.Server.cs
index fbec1b7..9786189 100644
--- a/lib/csharp/test/Multiplex/Server/Multiplex.Test.Server.cs
+++ b/lib/csharp/test/Multiplex/Server/Multiplex.Test.Server.cs
@@ -28,32 +28,16 @@
 
 namespace Test.Multiplex.Server
 {
-	public class TestServer
-	{
-        public interface ITestHandler
-        {
-            void SetServer( TServer aServer);
-        }
-
-        protected class TestHandlerImpl : ITestHandler
-        {
-            private TServer Server;
-    
-            public void SetServer( TServer aServer)
-            {
-                Server = aServer;
-            }
-        }
-
-
-        protected class BenchmarkServiceImpl : TestHandlerImpl, BenchmarkService.Iface
+    public class TestServer
+    {
+        class BenchmarkServiceImpl : BenchmarkService.Iface
         {
             public int fibonacci(sbyte n)
             {
                 int prev, next, result;
                 prev   = 0;
                 result = 1;
-                while( n > 0) 
+                while (n > 0)
                 {
                     next   = result + prev;
                     prev   = result;
@@ -64,14 +48,13 @@
             }
         }
 
-
-        protected class AggrServiceImpl : TestHandlerImpl,  Aggr.Iface
+        class AggrServiceImpl : Aggr.Iface
         {
             List<int> values = new List<int>();
 
             public void addValue(int value)
             {
-                values.Add( value);
+                values.Add(value);
             }
 
             public List<int> getValues()
@@ -80,52 +63,45 @@
             }
         }
 
-       static void Execute()
-       {
-           try
-           {
-               // create protocol factory, default to BinaryProtocol
-               TProtocolFactory ProtocolFactory = new TBinaryProtocol.Factory(true,true);
-               TServerTransport servertrans     = new TServerSocket( 9090, 0, false);
-               TTransportFactory TransportFactory = new TFramedTransport.Factory();
+        static void Execute(int port)
+        {
+            try
+            {
+                // create protocol factory, default to BinaryProtocol
+                TProtocolFactory ProtocolFactory = new TBinaryProtocol.Factory(true,true);
+                TServerTransport servertrans = new TServerSocket(port, 0, false);
+                TTransportFactory TransportFactory = new TFramedTransport.Factory();
 
-               BenchmarkService.Iface benchHandler = new BenchmarkServiceImpl();
-               TProcessor benchProcessor = new BenchmarkService.Processor( benchHandler);
+                BenchmarkService.Iface benchHandler = new BenchmarkServiceImpl();
+                TProcessor benchProcessor = new BenchmarkService.Processor(benchHandler);
 
-               Aggr.Iface aggrHandler = new AggrServiceImpl();
-               TProcessor aggrProcessor = new Aggr.Processor( aggrHandler);
+                Aggr.Iface aggrHandler = new AggrServiceImpl();
+                TProcessor aggrProcessor = new Aggr.Processor(aggrHandler);
 
-               TMultiplexedProcessor multiplex = new TMultiplexedProcessor();
-               multiplex.RegisterProcessor(Constants.NAME_BENCHMARKSERVICE, benchProcessor);
-               multiplex.RegisterProcessor(Constants.NAME_AGGR, aggrProcessor);
+                TMultiplexedProcessor multiplex = new TMultiplexedProcessor();
+                multiplex.RegisterProcessor(Constants.NAME_BENCHMARKSERVICE, benchProcessor);
+                multiplex.RegisterProcessor(Constants.NAME_AGGR, aggrProcessor);
 
-               TServer ServerEngine = new TSimpleServer( multiplex, servertrans, TransportFactory, ProtocolFactory);
+                TServer ServerEngine = new TSimpleServer(multiplex, servertrans, TransportFactory, ProtocolFactory);
 
-               (benchHandler as ITestHandler).SetServer( ServerEngine);
-               (aggrHandler as ITestHandler).SetServer( ServerEngine);
+                Console.WriteLine("Starting the server ...");
+                ServerEngine.Serve();
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine(e.Message);
+            }
+        }
 
-               Console.WriteLine("Starting the server ...");
-               ServerEngine.Serve();
-
-               (benchHandler as ITestHandler).SetServer(null);
-               (aggrHandler as ITestHandler).SetServer(null);
-
-           } 
-           catch( Exception e)
-           {
-               Console.WriteLine( e.Message);
-           }
-           Console.WriteLine( "done.");
-       }
-
-        
-       static void Main(string[] args)
-       {
-           Execute();
-       }
+        static void Main(string[] args)
+        {
+            int port = 9090;
+            if (args.Length > 0)
+            {
+                port = ushort.Parse(args[0]);
+            }
+            Execute(port);
+        }
     }
-
-
-
 }
 
diff --git a/lib/csharp/test/Multiplex/Server/MultiplexServer.csproj b/lib/csharp/test/Multiplex/Server/MultiplexServer.csproj
index dc1d123..c4a4394 100644
--- a/lib/csharp/test/Multiplex/Server/MultiplexServer.csproj
+++ b/lib/csharp/test/Multiplex/Server/MultiplexServer.csproj
@@ -46,7 +46,7 @@
     <UpdateRequired>false</UpdateRequired>
     <MapFileExtensions>true</MapFileExtensions>
     <ApplicationRevision>0</ApplicationRevision>
-    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <ApplicationVersion>1.0.0.0</ApplicationVersion>
     <UseApplicationTrust>false</UseApplicationTrust>
     <BootstrapperEnabled>true</BootstrapperEnabled>
   </PropertyGroup>
@@ -145,4 +145,4 @@
 
 </PreBuildEvent>
   </PropertyGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/lib/csharp/test/Multiplex/Server/Properties/AssemblyInfo.cs b/lib/csharp/test/Multiplex/Server/Properties/AssemblyInfo.cs
index 9b9dd6f..5d40546 100644
--- a/lib/csharp/test/Multiplex/Server/Properties/AssemblyInfo.cs
+++ b/lib/csharp/test/Multiplex/Server/Properties/AssemblyInfo.cs
@@ -27,9 +27,9 @@
 [assembly: AssemblyTitle("MultiplexServer")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("MultiplexServer")]
-[assembly: AssemblyCopyright("Copyright © 2013 The Apache Software Foundation")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
diff --git a/lib/csharp/test/Multiplex/maketest.sh b/lib/csharp/test/Multiplex/maketest.sh
deleted file mode 100644
index a2bcde4..0000000
--- a/lib/csharp/test/Multiplex/maketest.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/sh
-
-#
-# 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.
-#
-
-../../../../compiler/cpp/thrift --gen csharp  ../../../../contrib/async-test/aggr.thrift
-../../../../compiler/cpp/thrift --gen csharp  ../../../rb/benchmark/Benchmark.thrift
-gmcs /t:library /out:./ThriftImpl.dll /recurse:./gen-csharp/* /reference:../../Thrift.dll Multiplex.Test.Common.cs
-gmcs  /out:MultiplexClient.exe /reference:../../Thrift.dll /reference:ThriftImpl.dll Client/Multiplex.Test.Client.cs  
-gmcs  /out:MultiplexServer.exe /reference:../../Thrift.dll /reference:ThriftImpl.dll Server/Multiplex.Test.Server.cs  
-
-
-
-export MONO_PATH=../../
-
-timeout 120 ./MultiplexServer.exe & 
-sleep 3;
-./MultiplexClient.exe
diff --git a/lib/csharp/test/ThriftMVCTest/App_Start/FilterConfig.cs b/lib/csharp/test/ThriftMVCTest/App_Start/FilterConfig.cs
new file mode 100644
index 0000000..855184f
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/App_Start/FilterConfig.cs
@@ -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.
+ */
+
+using System.Web.Mvc;
+
+namespace ThriftMVCTest
+{
+    public static class FilterConfig
+    {
+        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
+        {
+            filters.Add(new HandleErrorAttribute());
+        }
+    }
+}
diff --git a/lib/csharp/test/ThriftMVCTest/App_Start/RouteConfig.cs b/lib/csharp/test/ThriftMVCTest/App_Start/RouteConfig.cs
new file mode 100644
index 0000000..b4b6023
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/App_Start/RouteConfig.cs
@@ -0,0 +1,39 @@
+/**
+ * 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.
+ */
+
+using System.Web.Mvc;
+using System.Web.Routing;
+
+namespace ThriftMVCTest
+{
+    public static class RouteConfig
+    {
+        public static void RegisterRoutes(RouteCollection routes)
+        {
+            routes.IgnoreRoute("{resource}.thrift");
+            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
+
+            routes.MapRoute(
+                name: "Default",
+                url: "{controller}/{action}/{id}",
+                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
+            );
+        }
+    }
+}
diff --git a/lib/csharp/test/ThriftMVCTest/AsyncHttpHandler.cs b/lib/csharp/test/ThriftMVCTest/AsyncHttpHandler.cs
new file mode 100644
index 0000000..7f26184
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/AsyncHttpHandler.cs
@@ -0,0 +1,32 @@
+/**
+ * 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.
+ */
+
+using Thrift.Transport;
+
+namespace ThriftMVCTest
+{
+    public class AsyncHttpHandler : THttpTaskAsyncHandler
+    {
+        public AsyncHttpHandler()
+            : base(
+                new Thrift.Test.SecondService.AsyncProcessor(new SecondServiceImpl()))
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/csharp/test/ThriftMVCTest/Controllers/HomeController.cs b/lib/csharp/test/ThriftMVCTest/Controllers/HomeController.cs
new file mode 100644
index 0000000..c9a1ec4
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Controllers/HomeController.cs
@@ -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.
+ */
+
+using System;
+using System.Threading.Tasks;
+using System.Web.Mvc;
+using Thrift.Protocol;
+using Thrift.Test;
+using Thrift.Transport;
+
+namespace ThriftMVCTest.Controllers
+{
+    public class HomeController : Controller
+    {
+        public ActionResult Index()
+        {
+            return View();
+        }
+
+        public async Task<ActionResult> TestThriftAsync()
+        {
+            var baseUri = new Uri(string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority,
+                Url.Content("~")));
+
+            SecondService.IAsync asyncService =
+                new SecondService.Client(new TBinaryProtocol(new THttpClient(new Uri(baseUri, "Async.thrift"))));
+
+            var result = await asyncService.secondtestStringAsync("TestString");
+            if (result != "testString(\"TestString\")")
+            {
+                throw new Exception("The wrong result was returned");
+            }
+
+            return RedirectToAction("Index");
+        }
+
+        public ActionResult TestThriftSync()
+        {
+            var baseUri = new Uri(string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority,
+                Url.Content("~")));
+
+            SecondService.ISync service =
+                new SecondService.Client(new TBinaryProtocol(new THttpClient(new Uri(baseUri, "Sync.thrift"))));
+
+            var result = service.secondtestString("TestString");
+            if (result != "testString(\"TestString\")")
+            {
+                throw new Exception("The wrong result was returned");
+            }
+
+            return RedirectToAction("Index");
+        }
+    }
+}
diff --git a/lib/csharp/test/ThriftMVCTest/Global.asax b/lib/csharp/test/ThriftMVCTest/Global.asax
new file mode 100644
index 0000000..7bb688c
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Global.asax
@@ -0,0 +1,19 @@
+<%@ Application Codebehind="Global.asax.cs" Inherits="ThriftMVCTest.MvcApplication" Language="C#" %>
+<!--
+  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.
+-->
diff --git a/lib/csharp/test/ThriftMVCTest/Global.asax.cs b/lib/csharp/test/ThriftMVCTest/Global.asax.cs
new file mode 100644
index 0000000..59731ef
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Global.asax.cs
@@ -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.
+ */
+
+using System.Web.Mvc;
+using System.Web.Routing;
+
+namespace ThriftMVCTest
+{
+    public class MvcApplication : System.Web.HttpApplication
+    {
+        protected void Application_Start()
+        {
+            AreaRegistration.RegisterAllAreas();
+            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
+            RouteConfig.RegisterRoutes(RouteTable.Routes);
+        }
+    }
+}
diff --git a/lib/csharp/test/ThriftMVCTest/Properties/AssemblyInfo.cs b/lib/csharp/test/ThriftMVCTest/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..cfe8894
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Properties/AssemblyInfo.cs
@@ -0,0 +1,53 @@
+/**
+ * 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.
+ */
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ThriftMVCTest")]
+[assembly: AssemblyDescription("A web project for testing the thrift ASP.NET features.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("366f9bd0-3c0e-48aa-b2ca-61fd4a93e427")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs b/lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs
new file mode 100644
index 0000000..fad301a
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs
@@ -0,0 +1,37 @@
+/**
+ * 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.
+ */
+
+using System.Threading.Tasks;
+using Thrift.Test;
+
+namespace ThriftMVCTest
+{
+    public class SecondServiceImpl : SecondService.IAsync, SecondService.ISync
+    {
+        public Task<string> secondtestStringAsync(string thing)
+        {
+            return Task.FromResult(thing);
+        }
+
+        public string secondtestString(string thing)
+        {
+            return "testString(\"" + thing + "\")";
+        }
+    }
+}
diff --git a/lib/csharp/test/ThriftMVCTest/SyncHttpHandler.cs b/lib/csharp/test/ThriftMVCTest/SyncHttpHandler.cs
new file mode 100644
index 0000000..4fe2662
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/SyncHttpHandler.cs
@@ -0,0 +1,32 @@
+/**
+ * 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.
+ */
+
+using Thrift.Transport;
+
+namespace ThriftMVCTest
+{
+    public class SyncHttpHandler : THttpHandler
+    {
+        public SyncHttpHandler()
+            : base(
+                new Thrift.Test.SecondService.Processor(new SecondServiceImpl()))
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/csharp/test/ThriftMVCTest/ThriftMVCTest.csproj b/lib/csharp/test/ThriftMVCTest/ThriftMVCTest.csproj
new file mode 100644
index 0000000..0eb969a
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/ThriftMVCTest.csproj
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>
+    </ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{891B4487-C7BA-427E-BBC8-4C596C229A10}</ProjectGuid>
+    <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ThriftMVCTest</RootNamespace>
+    <AssemblyName>ThriftMVCTest</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <MvcBuildViews>false</MvcBuildViews>
+    <UseIISExpress>true</UseIISExpress>
+    <IISExpressSSLPort />
+    <IISExpressAnonymousAuthentication />
+    <IISExpressWindowsAuthentication />
+    <IISExpressUseClassicPipelineMode />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Web.DynamicData" />
+    <Reference Include="System.Web.Entity" />
+    <Reference Include="System.Web.ApplicationServices" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Web" />
+    <Reference Include="System.Web.Extensions" />
+    <Reference Include="System.Web.Abstractions" />
+    <Reference Include="System.Web.Routing" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Web.Services" />
+    <Reference Include="System.EnterpriseServices" />
+    <Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Net.Http">
+    </Reference>
+    <Reference Include="System.Net.Http.WebRequest">
+    </Reference>
+    <Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <Private>True</Private>
+      <HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
+    </Reference>
+    <Reference Include="ThriftImpl">
+      <HintPath>.\ThriftImpl.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="App_Start\FilterConfig.cs" />
+    <Compile Include="App_Start\RouteConfig.cs" />
+    <Compile Include="SyncHttpHandler.cs" />
+    <Compile Include="AsyncHttpHandler.cs" />
+    <Compile Include="Controllers\HomeController.cs" />
+    <Compile Include="Global.asax.cs">
+      <DependentUpon>Global.asax</DependentUpon>
+    </Compile>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SecondServiceImpl.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="favicon.ico" />
+    <Content Include="Global.asax" />
+    <Content Include="Web.config" />
+    <Content Include="Web.Debug.config">
+      <DependentUpon>Web.config</DependentUpon>
+    </Content>
+    <Content Include="Web.Release.config">
+      <DependentUpon>Web.config</DependentUpon>
+    </Content>
+    <Content Include="Views\Web.config" />
+    <Content Include="Views\_ViewStart.cshtml" />
+    <Content Include="Views\Shared\_Layout.cshtml" />
+    <Content Include="Views\Home\Index.cshtml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="App_Data\" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="packages.config">
+      <SubType>Designer</SubType>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Thrift.45.csproj">
+      <Project>{ebce35da-cf6a-42bc-a357-a9c09b534299}</Project>
+      <Name>Thrift.45</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
+  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
+  <Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
+    <AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
+  </Target>
+  <ProjectExtensions>
+    <VisualStudio>
+      <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
+        <WebProjectProperties>
+          <UseIIS>True</UseIIS>
+          <AutoAssignPort>True</AutoAssignPort>
+          <DevelopmentServerPort>57482</DevelopmentServerPort>
+          <DevelopmentServerVPath>/</DevelopmentServerVPath>
+          <IISUrl>http://localhost:57482/</IISUrl>
+          <NTLMAuthentication>False</NTLMAuthentication>
+          <UseCustomServer>False</UseCustomServer>
+          <CustomServerUrl>
+          </CustomServerUrl>
+          <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
+        </WebProjectProperties>
+      </FlavorProperties>
+    </VisualStudio>
+  </ProjectExtensions>
+  <PropertyGroup>
+    <PreBuildEvent>rmdir /s /q "$(ProjectDir)gen-csharp"
+del /f /q "$(ProjectDir)ThriftImpl.dll"
+SET OUTPUT_DIR=$(ProjectDir)
+SET THRIFT_FILE=$(ProjectDir)\..\..\..\..\test\ThriftTest.thrift
+for %25%25I in ("%25OUTPUT_DIR%25") do set SHORT_DIR=%25%25~fsI
+for %25%25I in ("%25THRIFT_FILE%25") do set THRIFT_SHORT=%25%25~fsI
+"$(ProjectDir)\..\..\..\..\compiler\cpp\Debug\thrift.exe" --gen csharp:async=true -o %25SHORT_DIR%25 %25THRIFT_SHORT%25
+"$(MSBuildToolsPath)\Csc.exe" /t:library /out:"$(ProjectDir)ThriftImpl.dll" /recurse:"$(ProjectDir)gen-csharp"\* /reference:"$(ProjectDir)..\..\src\bin\Debug\Thrift45.dll"</PreBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target> -->
+</Project>
\ No newline at end of file
diff --git a/lib/csharp/test/ThriftMVCTest/Views/Home/Index.cshtml b/lib/csharp/test/ThriftMVCTest/Views/Home/Index.cshtml
new file mode 100644
index 0000000..f0ca7da
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Views/Home/Index.cshtml
@@ -0,0 +1,25 @@
+@*
+    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.
+*@
+
+@{
+    ViewBag.Title = "Home Page";
+}
+
+<p>@Html.ActionLink("Test Thrift Async Service", "TestThriftAsync")</p>
+<p>@Html.ActionLink("Test Thrift Sync Service", "TestThriftSync")</p>
diff --git a/lib/csharp/test/ThriftMVCTest/Views/Shared/_Layout.cshtml b/lib/csharp/test/ThriftMVCTest/Views/Shared/_Layout.cshtml
new file mode 100644
index 0000000..b41c99a
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Views/Shared/_Layout.cshtml
@@ -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.
+*@
+
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Thrift ASP.NET Test</title>
+</head>
+<body>
+    @RenderBody()
+</body>
+</html>
diff --git a/lib/csharp/test/ThriftMVCTest/Views/Web.config b/lib/csharp/test/ThriftMVCTest/Views/Web.config
new file mode 100644
index 0000000..3c21138
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Views/Web.config
@@ -0,0 +1,60 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<configuration>
+  <configSections>
+    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
+      <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
+      <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
+    </sectionGroup>
+  </configSections>
+
+  <system.web.webPages.razor>
+    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
+    <pages pageBaseType="System.Web.Mvc.WebViewPage">
+      <namespaces>
+        <add namespace="System.Web.Mvc" />
+        <add namespace="System.Web.Mvc.Ajax" />
+        <add namespace="System.Web.Mvc.Html" />
+        <add namespace="System.Web.Optimization"/>
+        <add namespace="System.Web.Routing" />
+        <add namespace="ThriftMVCTest" />
+      </namespaces>
+    </pages>
+  </system.web.webPages.razor>
+
+  <appSettings>
+    <add key="webpages:Enabled" value="false" />
+  </appSettings>
+
+  <system.webServer>
+    <handlers>
+      <remove name="BlockViewHandler"/>
+      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
+    </handlers>
+  </system.webServer>
+
+  <system.web>
+    <compilation>
+      <assemblies>
+        <add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
+      </assemblies>
+    </compilation>
+  </system.web>
+</configuration>
diff --git a/lib/csharp/test/ThriftMVCTest/Views/_ViewStart.cshtml b/lib/csharp/test/ThriftMVCTest/Views/_ViewStart.cshtml
new file mode 100644
index 0000000..8cde2ee
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Views/_ViewStart.cshtml
@@ -0,0 +1,22 @@
+@*
+    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.
+*@
+
+@{
+    Layout = "~/Views/Shared/_Layout.cshtml";
+}
diff --git a/lib/csharp/test/ThriftMVCTest/Web.Debug.config b/lib/csharp/test/ThriftMVCTest/Web.Debug.config
new file mode 100644
index 0000000..45d56d8
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Web.Debug.config
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
+  <!--
+    In the example below, the "SetAttributes" transform will change the value of
+    "connectionString" to use "ReleaseSQLServer" only when the "Match" locator
+    finds an attribute "name" that has a value of "MyDB".
+
+    <connectionStrings>
+      <add name="MyDB"
+        connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
+        xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
+    </connectionStrings>
+  -->
+  <system.web>
+    <!--
+      In the example below, the "Replace" transform will replace the entire
+      <customErrors> section of your Web.config file.
+      Note that because there is only one customErrors section under the
+      <system.web> node, there is no need to use the "xdt:Locator" attribute.
+
+      <customErrors defaultRedirect="GenericError.htm"
+        mode="RemoteOnly" xdt:Transform="Replace">
+        <error statusCode="500" redirect="InternalError.htm"/>
+      </customErrors>
+    -->
+  </system.web>
+</configuration>
diff --git a/lib/csharp/test/ThriftMVCTest/Web.Release.config b/lib/csharp/test/ThriftMVCTest/Web.Release.config
new file mode 100644
index 0000000..157c340
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Web.Release.config
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
+  <!--
+    In the example below, the "SetAttributes" transform will change the value of
+    "connectionString" to use "ReleaseSQLServer" only when the "Match" locator
+    finds an attribute "name" that has a value of "MyDB".
+
+    <connectionStrings>
+      <add name="MyDB"
+        connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
+        xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
+    </connectionStrings>
+  -->
+  <system.web>
+    <compilation xdt:Transform="RemoveAttributes(debug)" />
+    <!--
+      In the example below, the "Replace" transform will replace the entire
+      <customErrors> section of your Web.config file.
+      Note that because there is only one customErrors section under the
+      <system.web> node, there is no need to use the "xdt:Locator" attribute.
+
+      <customErrors defaultRedirect="GenericError.htm"
+        mode="RemoteOnly" xdt:Transform="Replace">
+        <error statusCode="500" redirect="InternalError.htm"/>
+      </customErrors>
+    -->
+  </system.web>
+</configuration>
diff --git a/lib/csharp/test/ThriftMVCTest/Web.config b/lib/csharp/test/ThriftMVCTest/Web.config
new file mode 100644
index 0000000..9c57d11
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/Web.config
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  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.
+-->
+
+<!--
+  For more information on how to configure your ASP.NET application, please visit
+  http://go.microsoft.com/fwlink/?LinkId=301880
+  -->
+<configuration>
+  <appSettings>
+    <add key="webpages:Version" value="3.0.0.0" />
+    <add key="webpages:Enabled" value="false" />
+    <add key="ClientValidationEnabled" value="true" />
+    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
+    <add key="owin:AutomaticAppStartup" value="false" />
+  </appSettings>
+  <system.web>
+    <authentication mode="None" />
+    <compilation debug="true" targetFramework="4.5" />
+    <httpRuntime targetFramework="4.5" />
+  </system.web>
+  <system.webServer>
+    <modules>
+      <remove name="FormsAuthentication" />
+    </modules>
+    <handlers>
+      <add name="AsyncHttpHandler" verb="*" path="Async.thrift" type="ThriftMVCTest.AsyncHttpHandler, ThriftMVCTest" />
+      <add name="SyncHttpHandler" verb="*" path="Sync.thrift" type="ThriftMVCTest.SyncHttpHandler, ThriftMVCTest" />
+    </handlers>
+  </system.webServer>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
+        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
+        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+</configuration>
\ No newline at end of file
diff --git a/lib/csharp/test/ThriftMVCTest/favicon.ico b/lib/csharp/test/ThriftMVCTest/favicon.ico
new file mode 100644
index 0000000..a3a7999
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/favicon.ico
Binary files differ
diff --git a/lib/csharp/test/ThriftMVCTest/packages.config b/lib/csharp/test/ThriftMVCTest/packages.config
new file mode 100644
index 0000000..98c8416
--- /dev/null
+++ b/lib/csharp/test/ThriftMVCTest/packages.config
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<packages>
+  <package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
+  <package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net45" />
+  <package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net45" />
+  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/lib/csharp/test/ThriftTest/Program.cs b/lib/csharp/test/ThriftTest/Program.cs
deleted file mode 100644
index 4c63ca4..0000000
--- a/lib/csharp/test/ThriftTest/Program.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-// Distributed under the Thrift Software License
-//
-// See accompanying file LICENSE or visit the Thrift site at:
-// http://developers.facebook.com/thrift/
-
-using System;
-using Thrift.Transport;
-using Thrift.Protocol;
-using Thrift.Test; //generated code
-
-namespace Test
-{
-	class Program
-	{
-		static void Main(string[] args)
-		{
-			if (args.Length == 0)
-			{
-				Console.WriteLine("must provide 'server' or 'client' arg");
-				return;
-			}
-
-			string[] subArgs = new string[args.Length - 1];
-			for(int i = 1; i < args.Length; i++)
-			{
-				subArgs[i-1] = args[i];
-			}
-			if (args[0] == "client")
-			{
-				TestClient.Execute(subArgs);
-			}
-			else if (args[0] == "server")
-			{
-				TestServer.Execute(subArgs);
-			}
-			else
-			{
-				Console.WriteLine("first argument must be 'server' or 'client'");
-			}
-		}
-	}
-}
diff --git a/lib/csharp/test/ThriftTest/Properties/AssemblyInfo.cs b/lib/csharp/test/ThriftTest/Properties/AssemblyInfo.cs
deleted file mode 100644
index 504ca8d..0000000
--- a/lib/csharp/test/ThriftTest/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("ThriftTest")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("ThriftTest")]
-[assembly: AssemblyCopyright("Copyright © 2009 The Apache Software Foundation")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components.  If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("f41b193b-f1ab-48ee-8843-f88e43084e26")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/lib/csharp/test/ThriftTest/TestClient.cs b/lib/csharp/test/ThriftTest/TestClient.cs
deleted file mode 100644
index fe21f41..0000000
--- a/lib/csharp/test/ThriftTest/TestClient.cs
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using Thrift.Collections;
-using Thrift.Protocol;
-using Thrift.Transport;
-using Thrift.Test;
-
-namespace Test
-{
-	public class TestClient
-	{
-		private static int numIterations = 1;
-
-		public static void Execute(string[] args)
-		{
-			try
-			{
-				string host = "localhost";
-				int port = 9090;
-				string url = null;
-				int numThreads = 1;
-				bool buffered = false, framed = false;
-
-				try
-				{
-					for (int i = 0; i < args.Length; i++)
-					{
-						if (args[i] == "-h")
-						{
-							string[] hostport = args[++i].Split(':');
-							host = hostport[0];
-							if (hostport.Length > 1)
-							{
-								port = Convert.ToInt32(hostport[1]);
-							}
-						}
-						else if (args[i] == "-u")
-						{
-							url = args[++i];
-						}
-						else if (args[i] == "-n")
-						{
-							numIterations = Convert.ToInt32(args[++i]);
-						}
-						else if (args[i] == "-b" || args[i] == "-buffered")
-						{
-							buffered = true;
-							Console.WriteLine("Using buffered sockets");
-						}
-						else if (args[i] == "-f" || args[i] == "-framed")
-						{
-							framed = true;
-							Console.WriteLine("Using framed transport");
-						}
-						else if (args[i] == "-t")
-						{
-							numThreads = Convert.ToInt32(args[++i]);
-						}
-					}
-				}
-				catch (Exception e)
-				{
-					Console.WriteLine(e.StackTrace);
-				}
-
-
-
-				//issue tests on separate threads simultaneously
-				Thread[] threads = new Thread[numThreads];
-				DateTime start = DateTime.Now;
-				for (int test = 0; test < numThreads; test++)
-				{
-					Thread t = new Thread(new ParameterizedThreadStart(ClientThread));
-					threads[test] = t;
-					if (url == null)
-					{
-						TTransport trans = new TSocket(host, port);
-						if (buffered)
-							trans = new TBufferedTransport(trans as TStreamTransport);
-						if (framed)
-							trans = new TFramedTransport(trans);
-							
-						t.Start(trans);
-					}
-					else
-					{
-						THttpClient http = new THttpClient(new Uri(url));
-						t.Start(http);
-					}
-				}
-
-				for (int test = 0; test < numThreads; test++)
-				{
-					threads[test].Join();
-				}
-				Console.Write("Total time: " + (DateTime.Now - start));
-			}
-			catch (Exception outerEx)
-			{
-				Console.WriteLine(outerEx.Message + " ST: " + outerEx.StackTrace);
-			}
-
-			Console.WriteLine();
-			Console.WriteLine();
-		}
-
-		public static void ClientThread(object obj)
-		{
-			TTransport transport = (TTransport)obj;
-			for (int i = 0; i < numIterations; i++)
-			{
-				ClientTest(transport);
-			}
-			transport.Close();
-		}
-
-		public static void ClientTest(TTransport transport)
-		{
-			TBinaryProtocol binaryProtocol = new TBinaryProtocol(transport);
-
-			ThriftTest.Client client = new ThriftTest.Client(binaryProtocol);
-			try
-			{
-				if (!transport.IsOpen)
-				{
-					transport.Open();
-				}
-			}
-			catch (TTransportException ttx)
-			{
-				Console.WriteLine("Connect failed: " + ttx.Message);
-				return;
-			}
-
-			long start = DateTime.Now.ToFileTime();
-
-			Console.Write("testVoid()");
-			client.testVoid();
-			Console.WriteLine(" = void");
-
-			Console.Write("testString(\"Test\")");
-			string s = client.testString("Test");
-			Console.WriteLine(" = \"" + s + "\"");
-
-			Console.Write("testByte(1)");
-			sbyte i8 = client.testByte((sbyte)1);
-			Console.WriteLine(" = " + i8);
-
-			Console.Write("testI32(-1)");
-			int i32 = client.testI32(-1);
-			Console.WriteLine(" = " + i32);
-
-			Console.Write("testI64(-34359738368)");
-			long i64 = client.testI64(-34359738368);
-			Console.WriteLine(" = " + i64);
-
-			Console.Write("testDouble(5.325098235)");
-			double dub = client.testDouble(5.325098235);
-			Console.WriteLine(" = " + dub);
-
-			Console.Write("testStruct({\"Zero\", 1, -3, -5})");
-			Xtruct o = new Xtruct();
-			o.String_thing = "Zero";
-			o.Byte_thing = (sbyte)1;
-			o.I32_thing = -3;
-			o.I64_thing = -5;
-			Xtruct i = client.testStruct(o);
-			Console.WriteLine(" = {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}");
-
-			Console.Write("testNest({1, {\"Zero\", 1, -3, -5}, 5})");
-			Xtruct2 o2 = new Xtruct2();
-			o2.Byte_thing = (sbyte)1;
-			o2.Struct_thing = o;
-			o2.I32_thing = 5;
-			Xtruct2 i2 = client.testNest(o2);
-			i = i2.Struct_thing;
-			Console.WriteLine(" = {" + i2.Byte_thing + ", {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}, " + i2.I32_thing + "}");
-
-			Dictionary<int, int> mapout = new Dictionary<int, int>();
-			for (int j = 0; j < 5; j++)
-			{
-				mapout[j] = j - 10;
-			}
-			Console.Write("testMap({");
-			bool first = true;
-			foreach (int key in mapout.Keys)
-			{
-				if (first)
-				{
-					first = false;
-				}
-				else
-				{
-					Console.Write(", ");
-				}
-				Console.Write(key + " => " + mapout[key]);
-			}
-			Console.Write("})");
-
-			Dictionary<int, int> mapin = client.testMap(mapout);
-
-			Console.Write(" = {");
-			first = true;
-			foreach (int key in mapin.Keys)
-			{
-				if (first)
-				{
-					first = false;
-				}
-				else
-				{
-					Console.Write(", ");
-				}
-				Console.Write(key + " => " + mapin[key]);
-			}
-			Console.WriteLine("}");
-
-			List<int> listout = new List<int>();
-			for (int j = -2; j < 3; j++)
-			{
-				listout.Add(j);
-			}
-			Console.Write("testList({");
-			first = true;
-			foreach (int j in listout)
-			{
-				if (first)
-				{
-					first = false;
-				}
-				else
-				{
-					Console.Write(", ");
-				}
-				Console.Write(j);
-			}
-			Console.Write("})");
-
-			List<int> listin = client.testList(listout);
-
-			Console.Write(" = {");
-			first = true;
-			foreach (int j in listin)
-			{
-				if (first)
-				{
-					first = false;
-				}
-				else
-				{
-					Console.Write(", ");
-				}
-				Console.Write(j);
-			}
-			Console.WriteLine("}");
-
-			//set
-			THashSet<int> setout = new THashSet<int>();
-			for (int j = -2; j < 3; j++)
-			{
-				setout.Add(j);
-			}
-			Console.Write("testSet({");
-			first = true;
-			foreach (int j in setout)
-			{
-				if (first)
-				{
-					first = false;
-				}
-				else
-				{
-					Console.Write(", ");
-				}
-				Console.Write(j);
-			}
-			Console.Write("})");
-
-			THashSet<int> setin = client.testSet(setout);
-
-			Console.Write(" = {");
-			first = true;
-			foreach (int j in setin)
-			{
-				if (first)
-				{
-					first = false;
-				}
-				else
-				{
-					Console.Write(", ");
-				}
-				Console.Write(j);
-			}
-			Console.WriteLine("}");
-
-
-			Console.Write("testEnum(ONE)");
-			Numberz ret = client.testEnum(Numberz.ONE);
-			Console.WriteLine(" = " + ret);
-
-			Console.Write("testEnum(TWO)");
-			ret = client.testEnum(Numberz.TWO);
-			Console.WriteLine(" = " + ret);
-
-			Console.Write("testEnum(THREE)");
-			ret = client.testEnum(Numberz.THREE);
-			Console.WriteLine(" = " + ret);
-
-			Console.Write("testEnum(FIVE)");
-			ret = client.testEnum(Numberz.FIVE);
-			Console.WriteLine(" = " + ret);
-
-			Console.Write("testEnum(EIGHT)");
-			ret = client.testEnum(Numberz.EIGHT);
-			Console.WriteLine(" = " + ret);
-
-			Console.Write("testTypedef(309858235082523)");
-			long uid = client.testTypedef(309858235082523L);
-			Console.WriteLine(" = " + uid);
-
-			Console.Write("testMapMap(1)");
-			Dictionary<int, Dictionary<int, int>> mm = client.testMapMap(1);
-			Console.Write(" = {");
-			foreach (int key in mm.Keys)
-			{
-				Console.Write(key + " => {");
-				Dictionary<int, int> m2 = mm[key];
-				foreach (int k2 in m2.Keys)
-				{
-					Console.Write(k2 + " => " + m2[k2] + ", ");
-				}
-				Console.Write("}, ");
-			}
-			Console.WriteLine("}");
-
-			Insanity insane = new Insanity();
-			insane.UserMap = new Dictionary<Numberz, long>();
-			insane.UserMap[Numberz.FIVE] = 5000L;
-			Xtruct truck = new Xtruct();
-			truck.String_thing = "Truck";
-			truck.Byte_thing = (sbyte)8;
-			truck.I32_thing = 8;
-			truck.I64_thing = 8;
-			insane.Xtructs = new List<Xtruct>();
-			insane.Xtructs.Add(truck);
-			Console.Write("testInsanity()");
-			Dictionary<long, Dictionary<Numberz, Insanity>> whoa = client.testInsanity(insane);
-			Console.Write(" = {");
-			foreach (long key in whoa.Keys)
-			{
-				Dictionary<Numberz, Insanity> val = whoa[key];
-				Console.Write(key + " => {");
-
-				foreach (Numberz k2 in val.Keys)
-				{
-					Insanity v2 = val[k2];
-
-					Console.Write(k2 + " => {");
-					Dictionary<Numberz, long> userMap = v2.UserMap;
-
-					Console.Write("{");
-					if (userMap != null)
-					{
-						foreach (Numberz k3 in userMap.Keys)
-						{
-							Console.Write(k3 + " => " + userMap[k3] + ", ");
-						}
-					}
-					else
-					{
-						Console.Write("null");
-					}
-					Console.Write("}, ");
-
-					List<Xtruct> xtructs = v2.Xtructs;
-
-					Console.Write("{");
-					if (xtructs != null)
-					{
-						foreach (Xtruct x in xtructs)
-						{
-							Console.Write("{\"" + x.String_thing + "\", " + x.Byte_thing + ", " + x.I32_thing + ", " + x.I32_thing + "}, ");
-						}
-					}
-					else
-					{
-						Console.Write("null");
-					}
-					Console.Write("}");
-
-					Console.Write("}, ");
-				}
-				Console.Write("}, ");
-			}
-			Console.WriteLine("}");
-
-
-			sbyte arg0 = 1;
-			int arg1 = 2;
-			long arg2 = long.MaxValue;
-			Dictionary<short, string> multiDict = new Dictionary<short, string>();
-			multiDict[1] = "one";
-			Numberz arg4 = Numberz.FIVE;
-			long arg5 = 5000000;
-			Console.Write("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")");
-			Xtruct multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5);
-			Console.Write(" = Xtruct(byte_thing:" + multiResponse.Byte_thing + ",String_thing:" + multiResponse.String_thing
-						+ ",i32_thing:" + multiResponse.I32_thing + ",i64_thing:" + multiResponse.I64_thing + ")\n");
-
-			Console.WriteLine("Test Oneway(1)");
-			client.testOneway(1);
-
-			Console.Write("Test Calltime()");
-			var startt = DateTime.UtcNow;
-			for ( int k=0; k<1000; ++k )
-				client.testVoid();
-			Console.WriteLine(" = " + (DateTime.UtcNow - startt).TotalSeconds.ToString() + " ms a testVoid() call" );
-		}
-	}
-}
diff --git a/lib/csharp/test/ThriftTest/TestServer.cs b/lib/csharp/test/ThriftTest/TestServer.cs
deleted file mode 100644
index ceb4368..0000000
--- a/lib/csharp/test/ThriftTest/TestServer.cs
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-// Distributed under the Thrift Software License
-//
-// See accompanying file LICENSE or visit the Thrift site at:
-// http://developers.facebook.com/thrift/
-using System;
-using System.Collections.Generic;
-using Thrift.Collections;
-using Thrift.Test; //generated code
-using Thrift.Transport;
-using Thrift.Protocol;
-using Thrift.Server;
-
-namespace Test
-{
-	public class TestServer
-	{
-		public class TestHandler : ThriftTest.Iface
-		{
-			public TServer server;
-
-			public TestHandler() { }
-
-			public void testVoid()
-			{
-				Console.WriteLine("testVoid()");
-			}
-
-			public string testString(string thing)
-			{
-				Console.WriteLine("teststring(\"" + thing + "\")");
-				return thing;
-			}
-
-			public sbyte testByte(sbyte thing)
-			{
-				Console.WriteLine("testByte(" + thing + ")");
-				return thing;
-			}
-
-			public int testI32(int thing)
-			{
-				Console.WriteLine("testI32(" + thing + ")");
-				return thing;
-			}
-
-			public long testI64(long thing)
-			{
-				Console.WriteLine("testI64(" + thing + ")");
-				return thing;
-			}
-
-			public double testDouble(double thing)
-			{
-				Console.WriteLine("testDouble(" + thing + ")");
-				return thing;
-			}
-
-			public Xtruct testStruct(Xtruct thing)
-			{
-				Console.WriteLine("testStruct({" +
-								 "\"" + thing.String_thing + "\", " +
-								 thing.Byte_thing + ", " +
-								 thing.I32_thing + ", " +
-								 thing.I64_thing + "})");
-				return thing;
-			}
-
-			public Xtruct2 testNest(Xtruct2 nest)
-			{
-				Xtruct thing = nest.Struct_thing;
-				Console.WriteLine("testNest({" +
-								 nest.Byte_thing + ", {" +
-								 "\"" + thing.String_thing + "\", " +
-								 thing.Byte_thing + ", " +
-								 thing.I32_thing + ", " +
-								 thing.I64_thing + "}, " +
-								 nest.I32_thing + "})");
-				return nest;
-			}
-
-			public Dictionary<int, int> testMap(Dictionary<int, int> thing)
-			{
-				Console.WriteLine("testMap({");
-				bool first = true;
-				foreach (int key in thing.Keys)
-				{
-					if (first)
-					{
-						first = false;
-					}
-					else
-					{
-						Console.WriteLine(", ");
-					}
-					Console.WriteLine(key + " => " + thing[key]);
-				}
-				Console.WriteLine("})");
-				return thing;
-			}

-

-            public Dictionary<string, string> testStringMap(Dictionary<string, string> thing)

-            {

-                Console.WriteLine("testStringMap({");

-                bool first = true;

-                foreach (string key in thing.Keys)

-                {

-                    if (first)

-                    {

-                        first = false;

-                    }

-                    else

-                    {

-                        Console.WriteLine(", ");

-                    }

-                    Console.WriteLine(key + " => " + thing[key]);

-                }

-                Console.WriteLine("})");

-                return thing;

-            }
-
-			public THashSet<int> testSet(THashSet<int> thing)
-			{
-				Console.WriteLine("testSet({");
-				bool first = true;
-				foreach (int elem in thing)
-				{
-					if (first)
-					{
-						first = false;
-					}
-					else
-					{
-						Console.WriteLine(", ");
-					}
-					Console.WriteLine(elem);
-				}
-				Console.WriteLine("})");
-				return thing;
-			}
-
-			public List<int> testList(List<int> thing)
-			{
-				Console.WriteLine("testList({");
-				bool first = true;
-				foreach (int elem in thing)
-				{
-					if (first)
-					{
-						first = false;
-					}
-					else
-					{
-						Console.WriteLine(", ");
-					}
-					Console.WriteLine(elem);
-				}
-				Console.WriteLine("})");
-				return thing;
-			}
-
-			public Numberz testEnum(Numberz thing)
-			{
-				Console.WriteLine("testEnum(" + thing + ")");
-				return thing;
-			}
-
-			public long testTypedef(long thing)
-			{
-				Console.WriteLine("testTypedef(" + thing + ")");
-				return thing;
-			}
-
-			public Dictionary<int, Dictionary<int, int>> testMapMap(int hello)
-			{
-				Console.WriteLine("testMapMap(" + hello + ")");
-				Dictionary<int, Dictionary<int, int>> mapmap =
-				  new Dictionary<int, Dictionary<int, int>>();
-
-				Dictionary<int, int> pos = new Dictionary<int, int>();
-				Dictionary<int, int> neg = new Dictionary<int, int>();
-				for (int i = 1; i < 5; i++)
-				{
-					pos[i] = i;
-					neg[-i] = -i;
-				}
-
-				mapmap[4] = pos;
-				mapmap[-4] = neg;
-
-				return mapmap;
-			}
-
-			public Dictionary<long, Dictionary<Numberz, Insanity>> testInsanity(Insanity argument)
-			{
-				Console.WriteLine("testInsanity()");
-
-				Xtruct hello = new Xtruct();
-				hello.String_thing = "Hello2";
-				hello.Byte_thing = 2;
-				hello.I32_thing = 2;
-				hello.I64_thing = 2;
-
-				Xtruct goodbye = new Xtruct();
-				goodbye.String_thing = "Goodbye4";
-				goodbye.Byte_thing = (sbyte)4;
-				goodbye.I32_thing = 4;
-				goodbye.I64_thing = (long)4;
-
-				Insanity crazy = new Insanity();
-				crazy.UserMap = new Dictionary<Numberz, long>();
-				crazy.UserMap[Numberz.EIGHT] = (long)8;
-				crazy.Xtructs = new List<Xtruct>();
-				crazy.Xtructs.Add(goodbye);
-
-				Insanity looney = new Insanity();
-				crazy.UserMap[Numberz.FIVE] = (long)5;
-				crazy.Xtructs.Add(hello);
-
-				Dictionary<Numberz, Insanity> first_map = new Dictionary<Numberz, Insanity>();
-				Dictionary<Numberz, Insanity> second_map = new Dictionary<Numberz, Insanity>(); ;
-
-				first_map[Numberz.TWO] = crazy;
-				first_map[Numberz.THREE] = crazy;
-
-				second_map[Numberz.SIX] = looney;
-
-				Dictionary<long, Dictionary<Numberz, Insanity>> insane =
-				  new Dictionary<long, Dictionary<Numberz, Insanity>>();
-				insane[(long)1] = first_map;
-				insane[(long)2] = second_map;
-
-				return insane;
-			}
-
-			public Xtruct testMulti(sbyte arg0, int arg1, long arg2, Dictionary<short, string> arg3, Numberz arg4, long arg5)
-			{
-				Console.WriteLine("testMulti()");
-
-				Xtruct hello = new Xtruct(); ;
-				hello.String_thing = "Hello2";
-				hello.Byte_thing = arg0;
-				hello.I32_thing = arg1;
-				hello.I64_thing = arg2;
-				return hello;
-			}
-
-			public void testException(string arg)
-			{
-				Console.WriteLine("testException(" + arg + ")");
-				if (arg == "Xception")
-				{
-					Xception x = new Xception();
-					x.ErrorCode = 1001;
-					x.Message = "This is an Xception";
-					throw x;
-				}
-				return;
-			}
-
-			public Xtruct testMultiException(string arg0, string arg1)
-			{
-				Console.WriteLine("testMultiException(" + arg0 + ", " + arg1 + ")");
-				if (arg0 == "Xception")
-				{
-					Xception x = new Xception();
-					x.ErrorCode = 1001;
-					x.Message = "This is an Xception";
-					throw x;
-				}
-				else if (arg0 == "Xception2")
-				{
-					Xception2 x = new Xception2();
-					x.ErrorCode = 2002;
-					x.Struct_thing = new Xtruct();
-					x.Struct_thing.String_thing = "This is an Xception2";
-					throw x;
-				}
-
-				Xtruct result = new Xtruct();
-				result.String_thing = arg1;
-				return result;
-			}
-
-			public void testStop()
-			{
-				if (server != null)
-				{
-					server.Stop();
-				}
-			}
-
-			public void testOneway(int arg)
-			{
-				Console.WriteLine("testOneway(" + arg + "), sleeping...");
-				System.Threading.Thread.Sleep(arg * 1000);
-				Console.WriteLine("testOneway finished");
-			}
-
-		} // class TestHandler
-
-		public static void Execute(string[] args)
-		{
-			try
-			{
-				bool useBufferedSockets = false, useFramed = false;
-				int port = 9090;
-				if (args.Length > 0)
-				{
-					port = int.Parse(args[0]);
-
-					if (args.Length > 1)
-					{
-						if ( args[1] == "raw" )
-						{
-							// as default
-						}
-						else if ( args[1] == "buffered" )
-						{
-							useBufferedSockets = true;
-						}
-						else if ( args[1] == "framed" )
-						{
-							useFramed = true;
-						}
-						else
-						{
-							// Fall back to the older boolean syntax
-							bool.TryParse(args[1], out useBufferedSockets);
-						}
-					}
-				}
-
-				// Processor
-				TestHandler testHandler = new TestHandler();
-				ThriftTest.Processor testProcessor = new ThriftTest.Processor(testHandler);
-
-				// Transport
-				TServerSocket tServerSocket = new TServerSocket(port, 0, useBufferedSockets);
-
-				// Simple Server
-				TServer serverEngine;
-				if ( useFramed )
-					serverEngine = new TSimpleServer(testProcessor, tServerSocket, new TFramedTransport.Factory());
-				else
-					serverEngine = new TSimpleServer(testProcessor, tServerSocket);
-
-				// ThreadPool Server
-				// serverEngine = new TThreadPoolServer(testProcessor, tServerSocket);
-
-				// Threaded Server
-				// serverEngine = new TThreadedServer(testProcessor, tServerSocket);
-
-				testHandler.server = serverEngine;
-
-				// Run it
-				Console.WriteLine("Starting the server on port " + port + 
-					(useBufferedSockets ? " with buffered socket" : "") + 
-					(useFramed ? " with framed transport" : "") + 
-					"...");
-				serverEngine.Serve();
-
-			}
-			catch (Exception x)
-			{
-				Console.Error.Write(x);
-			}
-			Console.WriteLine("done.");
-		}
-	}
-}
diff --git a/lib/csharp/test/ThriftTest/ThriftTest.csproj b/lib/csharp/test/ThriftTest/ThriftTest.csproj
deleted file mode 100644
index 8717876..0000000
--- a/lib/csharp/test/ThriftTest/ThriftTest.csproj
+++ /dev/null
@@ -1,141 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>

-<!--

-  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.

--->

-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

-  <PropertyGroup>

-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

-    <ProductVersion>9.0.21022</ProductVersion>

-    <SchemaVersion>2.0</SchemaVersion>

-    <ProjectGuid>{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}</ProjectGuid>

-    <OutputType>Exe</OutputType>

-    <AppDesignerFolder>Properties</AppDesignerFolder>

-    <RootNamespace>ThriftTest</RootNamespace>

-    <AssemblyName>ThriftTest</AssemblyName>

-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>

-    <FileAlignment>512</FileAlignment>

-    <IsWebBootstrapper>false</IsWebBootstrapper>

-    <FileUpgradeFlags>

-    </FileUpgradeFlags>

-    <OldToolsVersion>3.5</OldToolsVersion>

-    <UpgradeBackupLocation />

-    <PublishUrl>publish\</PublishUrl>

-    <Install>true</Install>

-    <InstallFrom>Disk</InstallFrom>

-    <UpdateEnabled>false</UpdateEnabled>

-    <UpdateMode>Foreground</UpdateMode>

-    <UpdateInterval>7</UpdateInterval>

-    <UpdateIntervalUnits>Days</UpdateIntervalUnits>

-    <UpdatePeriodically>false</UpdatePeriodically>

-    <UpdateRequired>false</UpdateRequired>

-    <MapFileExtensions>true</MapFileExtensions>

-    <ApplicationRevision>0</ApplicationRevision>

-    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>

-    <UseApplicationTrust>false</UseApplicationTrust>

-    <BootstrapperEnabled>true</BootstrapperEnabled>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

-    <DebugSymbols>true</DebugSymbols>

-    <DebugType>full</DebugType>

-    <Optimize>false</Optimize>

-    <OutputPath>bin\Debug\</OutputPath>

-    <DefineConstants>DEBUG;TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

-    <DebugType>pdbonly</DebugType>

-    <Optimize>true</Optimize>

-    <OutputPath>bin\Release\</OutputPath>

-    <DefineConstants>TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>

-  </PropertyGroup>

-  <ItemGroup>

-    <Reference Include="System" />

-    <Reference Include="ThriftImpl, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">

-      <SpecificVersion>False</SpecificVersion>

-      <HintPath>.\ThriftImpl.dll</HintPath>

-    </Reference>

-  </ItemGroup>

-  <ItemGroup>

-    <Compile Include="Program.cs" />

-    <Compile Include="Properties\AssemblyInfo.cs" />

-    <Compile Include="TestClient.cs" />

-    <Compile Include="TestServer.cs" />

-  </ItemGroup>

-  <ItemGroup>

-    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">

-      <Visible>False</Visible>

-      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>

-      <Install>false</Install>

-    </BootstrapperPackage>

-    <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">

-      <Visible>False</Visible>

-      <ProductName>.NET Framework 2.0 %28x86%29</ProductName>

-      <Install>false</Install>

-    </BootstrapperPackage>

-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">

-      <Visible>False</Visible>

-      <ProductName>.NET Framework 3.0 %28x86%29</ProductName>

-      <Install>false</Install>

-    </BootstrapperPackage>

-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">

-      <Visible>False</Visible>

-      <ProductName>.NET Framework 3.5</ProductName>

-      <Install>true</Install>

-    </BootstrapperPackage>

-    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">

-      <Visible>False</Visible>

-      <ProductName>.NET Framework 3.5 SP1</ProductName>

-      <Install>false</Install>

-    </BootstrapperPackage>

-    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">

-      <Visible>False</Visible>

-      <ProductName>Windows Installer 3.1</ProductName>

-      <Install>true</Install>

-    </BootstrapperPackage>

-  </ItemGroup>

-  <ItemGroup>

-    <ProjectReference Include="..\..\src\Thrift.csproj">

-      <Project>{499EB63C-D74C-47E8-AE48-A2FC94538E9D}</Project>

-      <Name>Thrift</Name>

-    </ProjectReference>

-  </ItemGroup>

-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

-       Other similar extension points exist, see Microsoft.Common.targets.

-  <Target Name="BeforeBuild">

-  </Target>

-  <Target Name="AfterBuild">

-  </Target>

-  -->

-  <PropertyGroup>

-    <PreBuildEvent>rmdir /s /q "$(ProjectDir)gen-csharp"

-del /f /q "$(ProjectDir)ThriftImpl.dll"

-SET OUTPUT_DIR=$(ProjectDir)

-SET THRIFT_FILE=$(ProjectDir)\..\..\..\..\test\ThriftTest.thrift

-for %25%25I in ("%25OUTPUT_DIR%25") do set SHORT_DIR=%25%25~fsI

-for %25%25I in ("%25THRIFT_FILE%25") do set THRIFT_SHORT=%25%25~fsI

-"$(ProjectDir)\..\..\..\..\compiler\cpp\thrift.exe" --gen csharp -o %25SHORT_DIR%25 %25THRIFT_SHORT%25

-$(MSBuildToolsPath)\Csc.exe /t:library /out:"$(ProjectDir)ThriftImpl.dll" /recurse:"$(ProjectDir)gen-csharp"\* /reference:"$(ProjectDir)..\..\src\bin\Debug\Thrift.dll"</PreBuildEvent>

-  </PropertyGroup>

-</Project>
\ No newline at end of file
diff --git a/lib/csharp/test/ThriftTest/maketest.sh b/lib/csharp/test/ThriftTest/maketest.sh
deleted file mode 100644
index 86c1a11..0000000
--- a/lib/csharp/test/ThriftTest/maketest.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-
-#
-# 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.
-#
-
-../../../../compiler/cpp/thrift --gen csharp -o . ../../../../test/ThriftTest.thrift
-gmcs /t:library /out:./ThriftImpl.dll /recurse:./gen-csharp/* /reference:../../Thrift.dll
-gmcs  /out:TestClientServer.exe /reference:../../Thrift.dll /reference:ThriftImpl.dll TestClient.cs TestServer.cs Program.cs
-
-export MONO_PATH=../../
-
-timeout 120 ./TestClientServer.exe server &
-./TestClientServer.exe client
diff --git a/lib/d/Makefile.am b/lib/d/Makefile.am
index a4e3188..2a81218 100644
--- a/lib/d/Makefile.am
+++ b/lib/d/Makefile.am
@@ -17,7 +17,13 @@
 # under the License.
 #
 
-SUBDIRS = . test
+AUTOMAKE_OPTIONS = serial-tests
+
+SUBDIRS = .
+
+if WITH_TESTS
+SUBDIRS += test
+endif
 
 #
 # Enumeration of all the public and private modules.
@@ -35,7 +41,10 @@
 d_async_DATA = $(addprefix src/, $(addsuffix .d, $(d_asyncmodules)))
 
 d_codegenmodules = $(addprefix thrift/codegen/, async_client \
-	async_client_pool base client client_pool idlgen processor)
+	async_client_pool base client client_pool processor)
+#d_codegenmodules = $(addprefix thrift/codegen/, async_client \
+#	async_client_pool base client client_pool idlgen processor)
+
 d_codegendir = $(d_thriftdir)/codegen
 d_codegen_DATA = $(addprefix src/, $(addsuffix .d, $(d_codegenmodules)))
 
@@ -168,7 +177,7 @@
 	touch $@
 
 unittest/debug/%: src/%.d $(all_targets) unittest/emptymain.d
-	$(DMD) -gc -of$(subst /,$(DMD_OF_DIRSEP),$@) $(d_test_flags) $^
+	$(DMD) -g -of$(subst /,$(DMD_OF_DIRSEP),$@) $(d_test_flags) $^
 
 unittest/release/%: src/%.d $(all_targets) unittest/emptymain.d
 	$(DMD) -O -release -of$(subst /,$(DMD_OF_DIRSEP),$@) $(d_test_flags) $^
@@ -176,8 +185,10 @@
 TESTS = $(addprefix unittest/debug/, $(d_test_modules)) \
 	$(addprefix unittest/release/, $(d_test_modules))
 
+precross: all-local
+	$(MAKE) -C test precross
 
 EXTRA_DIST = \
 	src \
 	test \
-	README
+	README.md
diff --git a/lib/d/README b/lib/d/README.md
similarity index 100%
rename from lib/d/README
rename to lib/d/README.md
diff --git a/lib/d/coding_standards.md b/lib/d/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/d/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/d/src/thrift/async/libevent.d b/lib/d/src/thrift/async/libevent.d
index 3358bef..812e4a7 100644
--- a/lib/d/src/thrift/async/libevent.d
+++ b/lib/d/src/thrift/async/libevent.d
@@ -392,7 +392,7 @@
       TAsyncEventReason.NORMAL;
     (*(cast(TSocketEventListener*)arg))(reason);
     GC.removeRange(arg);
-    clear(arg);
+    destroy(arg);
     free(arg);
   }
 
@@ -402,7 +402,7 @@
     assert(flags & EV_TIMEOUT);
     (*(cast(void delegate()*)arg))();
     GC.removeRange(arg);
-    clear(arg);
+    destroy(arg);
     free(arg);
   }
 
@@ -430,7 +430,7 @@
   Work[][TAsyncTransport] workQueues_;
 
   /// The total number of work items not yet finished (queued and currently
-  /// excecuted) and delays not yet executed.
+  /// executed) and delays not yet executed.
   uint queuedCount_;
 
   /// Protects queuedCount_.
@@ -442,8 +442,8 @@
 
 private {
   timeval toTimeval(const(Duration) dur) {
-    timeval tv = {tv_sec: cast(int)dur.total!"seconds"(),
-      tv_usec: dur.fracSec.usecs};
+    timeval tv;
+    dur.split!("seconds", "usecs")(tv.tv_sec, tv.tv_usec);
     return tv;
   }
 
diff --git a/lib/d/src/thrift/async/socket.d b/lib/d/src/thrift/async/socket.d
index 6de13d9..a08f51d 100644
--- a/lib/d/src/thrift/async/socket.d
+++ b/lib/d/src/thrift/async/socket.d
@@ -18,6 +18,7 @@
  */
 module thrift.async.socket;
 
+import core.stdc.errno: ECONNRESET;
 import core.thread : Fiber;
 import core.time : dur, Duration;
 import std.array : empty;
diff --git a/lib/d/src/thrift/base.d b/lib/d/src/thrift/base.d
index 3b265cb..d5ece73 100644
--- a/lib/d/src/thrift/base.d
+++ b/lib/d/src/thrift/base.d
@@ -43,14 +43,14 @@
   }
 
   /// The exceptions thrown by the children of the operation. If applicable,
-  /// the list is ordered in the same way the exceptions occured.
+  /// the list is ordered in the same way the exceptions occurred.
   Exception[] exceptions;
 }
 
 /// The Thrift version string, used for informative purposes.
 // Note: This is currently hardcoded, but will likely be filled in by the build
 // system in future versions.
-enum VERSION = "0.9.1";
+enum VERSION = "1.0.0";
 
 /**
  * Functions used for logging inside Thrift.
@@ -62,7 +62,7 @@
  * Examples:
  * ---
  * logInfo("An informative message.");
- * logError("Some error occured: %s", e);
+ * logError("Some error occurred: %s", e);
  * ---
  */
 alias logFormatted!g_infoLogSink logInfo;
@@ -93,7 +93,7 @@
 // This should be private, if it could still be used through the aliases then.
 template logFormatted(alias target) {
   void logFormatted(string file = __FILE__, int line = __LINE__,
-    T...)(string format, T args) if (
+    T...)(string fmt, T args) if (
     __traits(compiles, { target(""); })
   ) {
     import std.format, std.stdio;
@@ -107,9 +107,9 @@
       formattedWrite(g_formatBuffer, "%s:%s: ", file, line);
 
       static if (T.length == 0) {
-        g_formatBuffer.put(format);
+        g_formatBuffer.put(fmt);
       } else {
-        formattedWrite(g_formatBuffer, format, args);
+        formattedWrite(g_formatBuffer, fmt, args);
       }
       target(g_formatBuffer.data);
     }
diff --git a/lib/d/src/thrift/codegen/base.d b/lib/d/src/thrift/codegen/base.d
index 95e09ff..db54992 100644
--- a/lib/d/src/thrift/codegen/base.d
+++ b/lib/d/src/thrift/codegen/base.d
@@ -43,11 +43,12 @@
 import std.array : empty, front;
 import std.conv : to;
 import std.exception : enforce;
-import std.traits : BaseTypeTuple, isPointer, isSomeFunction, pointerTarget,
+import std.traits : BaseTypeTuple, isPointer, isSomeFunction, PointerTarget,
   ReturnType;
 import thrift.base;
 import thrift.internal.codegen;
 import thrift.protocol.base;
+import thrift.util.hashset;
 
 /*
  * Thrift struct/service meta data, which is used to store information from
@@ -358,7 +359,7 @@
 mixin template TStructHelpers(alias fieldMetaData = cast(TFieldMeta[])null) if (
   is(typeof(fieldMetaData) : TFieldMeta[])
 ) {
-  import std.algorithm : canFind;
+  import std.algorithm : any;
   import thrift.codegen.base;
   import thrift.internal.codegen : isNullable, MemberType, mergeFieldMeta,
     FieldNames;
@@ -419,6 +420,10 @@
 
       return (cast()super).opEquals(other);
     }
+
+    override size_t toHash() const {
+      return thriftToHashImpl();
+    }
   } else {
     string toString() const {
       return thriftToStringImpl();
@@ -427,6 +432,10 @@
     bool opEquals(ref const This other) const {
       return thriftOpEqualsImpl(other);
     }
+
+    size_t toHash() const @safe nothrow {
+      return thriftToHashImpl();
+    }
   }
 
   private string thriftToStringImpl() const {
@@ -459,7 +468,16 @@
     return true;
   }
 
-  static if (canFind!`!a.defaultValue.empty`(mergeFieldMeta!(This, fieldMetaData))) {
+  private size_t thriftToHashImpl() const @trusted nothrow {
+    size_t hash = 0;
+    foreach (i, _; this.tupleof) {
+      auto val = this.tupleof[i];
+      hash += typeid(val).getHash(&val);
+    }
+    return hash;
+  }
+
+  static if (any!`!a.defaultValue.empty`(mergeFieldMeta!(This, fieldMetaData))) {
     static if (is(This _ == class)) {
       this() {
         mixin(thriftFieldInitCode!(mergeFieldMeta!(This, fieldMetaData))("this"));
@@ -500,10 +518,10 @@
   return code;
 }
 
-version (unittest) {
+unittest {
   // Cannot make this nested in the unittest block due to a »no size yet for
   // forward reference« error.
-  struct Foo {
+  static struct Foo {
     string a;
     int b;
     int c;
@@ -514,8 +532,7 @@
       TFieldMeta("c", 3, TReq.REQUIRED, "4")
     ]);
   }
-}
-unittest {
+
   auto f = Foo();
 
   f.set!"b"(12345);
@@ -575,7 +592,7 @@
  * the wire without altering their definitions.
  */
 void readStruct(T, Protocol, alias fieldMetaData = cast(TFieldMeta[])null,
-  bool pointerStruct = false)(ref T s, Protocol p) if (isTProtocol!Protocol)
+  bool pointerStruct = false)(auto ref T s, Protocol p) if (isTProtocol!Protocol)
 {
   mixin({
     string code;
@@ -674,7 +691,7 @@
     string readFieldCode(FieldType)(string name, short id, TReq req) {
       static if (pointerStruct && isPointer!FieldType) {
         immutable v = "(*s." ~ name ~ ")";
-        alias pointerTarget!FieldType F;
+        alias PointerTarget!FieldType F;
       } else {
         immutable v = "s." ~ name;
         alias FieldType F;
@@ -862,7 +879,7 @@
 
       static if (pointerStruct && isPointer!FieldType) {
         immutable v = "(*s." ~ name ~ ")";
-        alias pointerTarget!FieldType F;
+        alias PointerTarget!FieldType F;
       } else {
         immutable v = "s." ~ name;
         alias FieldType F;
@@ -942,6 +959,29 @@
   static assert(__traits(compiles, { Test t; t.write(cast(TProtocol)null); }));
 }
 
+// Ensure opEquals and toHash consistency.
+unittest {
+  struct TestEquals {
+    int a1;
+
+    mixin TStructHelpers!([
+      TFieldMeta("a1", 1, TReq.OPT_IN_REQ_OUT),
+    ]);
+  }
+
+  TestEquals a, b;
+  assert(a == b);
+  assert(a.toHash() == b.toHash());
+
+  a.a1 = 42;
+  assert(a != b);
+  assert(a.toHash() != b.toHash());
+
+  b.a1 = 42;
+  assert(a == b);
+  assert(a.toHash() == b.toHash());
+}
+
 private {
   /*
    * Returns a D code string containing the matching TType value for a passed
diff --git a/lib/d/src/thrift/codegen/client.d b/lib/d/src/thrift/codegen/client.d
index 9755ea8..117b076 100644
--- a/lib/d/src/thrift/codegen/client.d
+++ b/lib/d/src/thrift/codegen/client.d
@@ -184,13 +184,15 @@
           "TPargsStruct!(Interface, `" ~ methodName ~ "`)";
         code ~= paramStructType ~ " args = " ~ paramStructType ~ "();\n";
         code ~= paramAssignCode;
-        code ~= "oprot_.writeMessageBegin(TMessage(`" ~ methodName ~
-          "`, TMessageType.CALL, ++seqid_));\n";
+        code ~= "oprot_.writeMessageBegin(TMessage(`" ~ methodName ~ "`, ";
+        code ~= ((methodMetaFound && methodMeta.type == TMethodType.ONEWAY)
+                 ? "TMessageType.ONEWAY" : "TMessageType.CALL");
+        code ~= ", ++seqid_));\n";
         code ~= "args.write(oprot_);\n";
         code ~= "oprot_.writeMessageEnd();\n";
         code ~= "oprot_.transport.flush();\n";
 
-        // If this is not a oneway method, generate the recieving code.
+        // If this is not a oneway method, generate the receiving code.
         if (!methodMetaFound || methodMeta.type != TMethodType.ONEWAY) {
           code ~= "TPresultStruct!(Interface, `" ~ methodName ~ "`) result;\n";
 
diff --git a/lib/d/src/thrift/codegen/client_pool.d b/lib/d/src/thrift/codegen/client_pool.d
index ebf5b60..c46b743 100644
--- a/lib/d/src/thrift/codegen/client_pool.d
+++ b/lib/d/src/thrift/codegen/client_pool.d
@@ -205,7 +205,7 @@
           } else {
             // We are dealing with a normal exception thrown by the
             // server-side method, just pass it on. As far as we are
-            // concerned, the method call succeded.
+            // concerned, the method call succeeded.
             pool_.recordSuccess(c);
             throw e;
           }
diff --git a/lib/d/src/thrift/codegen/idlgen.d b/lib/d/src/thrift/codegen/idlgen.d
index 03e9b90..9f88936 100644
--- a/lib/d/src/thrift/codegen/idlgen.d
+++ b/lib/d/src/thrift/codegen/idlgen.d
@@ -155,10 +155,10 @@
       // the front. Because with the Thrift compiler types can only depend on
       // other types that have already been defined, we collect all the
       // dependencies, prepend them to the list, and then prune the duplicates
-      // (keeping the first occurences). If this requirement should ever be
+      // (keeping the first occurrences). If this requirement should ever be
       // dropped from Thrift, this could be easily adapted to handle circular
       // dependencies by passing TypeTuple!(T, List) to ForAllWithList instead
-      // of appending List afterwards, and removing the now unneccesary
+      // of appending List afterwards, and removing the now unnecessary
       // NoDuplicates.
       alias NoDuplicates!(
         ForAllWithList!(
@@ -641,13 +641,16 @@
 }
 `);
 
-  static assert(structIdlString!WithDefaults ==
+import std.algorithm;
+  static assert(structIdlString!WithDefaults.startsWith(
 `struct WithDefaults {
   -1: string a = "asdf",
-  -2: double b = 3.1415,
-  1: WithoutMeta c = {a: "foo", b: 3, },
+  -2: double b = 3.141`));
+
+  static assert(structIdlString!WithDefaults.endsWith(
+`1: WithoutMeta c = {a: "foo", b: 3, },
 }
-`);
+`));
 
   static assert(structIdlString!OneOfEach ==
 `struct OneOfEach {
diff --git a/lib/d/src/thrift/codegen/processor.d b/lib/d/src/thrift/codegen/processor.d
index e6b77fa..5ce7ac6 100644
--- a/lib/d/src/thrift/codegen/processor.d
+++ b/lib/d/src/thrift/codegen/processor.d
@@ -254,7 +254,7 @@
         code ~= "result.set!`success`(" ~ call ~ ");\n";
       }
 
-      // If this is not a oneway method, generate the recieving code.
+      // If this is not a oneway method, generate the receiving code.
       if (!methodMetaFound || methodMeta.type != TMethodType.ONEWAY) {
         if (methodMetaFound) {
           foreach (e; methodMeta.exceptions) {
diff --git a/lib/d/src/thrift/internal/codegen.d b/lib/d/src/thrift/internal/codegen.d
index aae65bb..85f9d18 100644
--- a/lib/d/src/thrift/internal/codegen.d
+++ b/lib/d/src/thrift/internal/codegen.d
@@ -19,6 +19,7 @@
 
 module thrift.internal.codegen;
 
+import std.algorithm : canFind;
 import std.traits : InterfacesTuple, isSomeFunction, isSomeString;
 import std.typetuple : staticIndexOf, staticMap, NoDuplicates, TypeTuple;
 import thrift.codegen.base;
@@ -178,6 +179,7 @@
 template FieldNames(T, alias fieldMetaData = cast(TFieldMeta[])null) {
   alias StaticFilter!(
     All!(
+      doesNotReadMembers,
       PApply!(isValueMember, T),
       PApply!(notIgnored, T, PApplySkip, fieldMetaData)
     ),
@@ -185,6 +187,17 @@
   ) FieldNames;
 }
 
+/*
+ * true if the passed member name is not a method generated by the
+ * TStructHelpers template that in its implementations queries the struct
+ * members.
+ *
+ * Kludge used internally to break a cycle caused a DMD forward reference
+ * regression, see THRIFT-2130.
+ */
+enum doesNotReadMembers(string name) = !["opEquals", "thriftOpEqualsImpl",
+  "toString", "thriftToStringImpl"].canFind(name);
+
 template derivedMembers(T) {
   alias TypeTuple!(__traits(derivedMembers, T)) derivedMembers;
 }
diff --git a/lib/d/src/thrift/internal/ctfe.d b/lib/d/src/thrift/internal/ctfe.d
index 3b10a78..974db01 100644
--- a/lib/d/src/thrift/internal/ctfe.d
+++ b/lib/d/src/thrift/internal/ctfe.d
@@ -86,11 +86,13 @@
 }
 
 unittest {
+  import std.algorithm;
   static assert(ctfeToString(double.infinity) == "inf");
   static assert(ctfeToString(-double.infinity) == "-inf");
   static assert(ctfeToString(double.nan) == "nan");
   static assert(ctfeToString(0.0) == "0");
   static assert(ctfeToString(-0.0) == "-0");
-  static assert(ctfeToString(3.1415) == "3.1415");
+  static assert(ctfeToString(2.5) == "2.5");
+  static assert(ctfeToString(3.1415).startsWith("3.141"));
   static assert(ctfeToString(2e-200) == "2e-200");
 }
diff --git a/lib/d/src/thrift/internal/resource_pool.d b/lib/d/src/thrift/internal/resource_pool.d
index 8bd6ac5..c0820a3 100644
--- a/lib/d/src/thrift/internal/resource_pool.d
+++ b/lib/d/src/thrift/internal/resource_pool.d
@@ -65,7 +65,7 @@
   /**
    * Returns an »enriched« input range to iterate over the pool members.
    */
-  struct Range {
+  static struct Range {
     /**
      * Whether the range is empty.
      *
@@ -98,9 +98,7 @@
         auto fi = r in parent_.faultInfos_;
 
         if (fi && fi.resetTime != fi.resetTime.init) {
-          // The argument to < needs to be an lvalue…
-          auto currentTick = TickDuration.currSystemTick;
-          if (fi.resetTime < currentTick) {
+          if (fi.resetTime < parent_.getCurrentTick_()) {
             // The timeout expired, remove the resource from the list and go
             // ahead trying it.
             parent_.faultInfos_.remove(r);
@@ -154,7 +152,7 @@
      */
     bool willBecomeNonempty(out Resource next, out Duration waitTime) {
       // If no resources are in the pool, the range will never become non-empty.
-      if (resources_.empty) return true;
+      if (resources_.empty) return false;
 
       // If cycle mode is not enabled, a range never becomes non-empty after
       // being empty once, because all the elements have already been
@@ -167,7 +165,7 @@
       ).front;
 
       next = nextPair[0];
-      waitTime = to!Duration(nextPair[1].resetTime - TickDuration.currSystemTick);
+      waitTime = to!Duration(nextPair[1].resetTime - parent_.getCurrentTick_());
 
       return true;
     }
@@ -232,8 +230,7 @@
     if (fi.count >= faultDisableCount) {
       // If the resource has hit the fault count limit, disable it for
       // specified duration.
-      fi.resetTime = TickDuration.currSystemTick +
-        TickDuration.from!"hnsecs"(faultDisableDuration.total!"hnsecs");
+      fi.resetTime = getCurrentTick_() + cast(TickDuration)faultDisableDuration;
     }
   }
 
@@ -270,6 +267,15 @@
 private:
   Resource[] resources_;
   FaultInfo[Resource] faultInfos_;
+
+  /// Function to get the current timestamp from some monotonic system clock.
+  ///
+  /// This is overridable to be able to write timing-insensitive unit tests.
+  /// The extra indirection should not matter much performance-wise compared to
+  /// the actual system call, and by its very nature thisshould not be on a hot
+  /// path anyway.
+  typeof(&TickDuration.currSystemTick) getCurrentTick_ =
+    &TickDuration.currSystemTick;
 }
 
 private {
@@ -279,11 +285,17 @@
   }
 }
 
-import std.datetime;
-import thrift.base;
+unittest {
+  auto pool = new TResourcePool!Object([]);
+  enforce(pool[].empty);
+  Object dummyRes;
+  Duration dummyDur;
+  enforce(!pool[].willBecomeNonempty(dummyRes, dummyDur));
+}
 
 unittest {
-  import core.thread;
+  import std.datetime;
+  import thrift.base;
 
   auto a = new Object;
   auto b = new Object;
@@ -291,7 +303,10 @@
   auto objs = [a, b, c];
   auto pool = new TResourcePool!Object(objs);
   pool.permute = false;
-  pool.faultDisableDuration = dur!"msecs"(5);
+
+  static Duration fakeClock;
+  pool.getCurrentTick_ = () => cast(TickDuration)fakeClock;
+
   Object dummyRes = void;
   Duration dummyDur = void;
 
@@ -328,7 +343,7 @@
     enforce(r.empty);
     enforce(!r.willBecomeNonempty(dummyRes, dummyDur));
 
-    Thread.sleep(dur!"msecs"(5));
+    fakeClock += 2.seconds;
     // Not in cycle mode, has to be still empty after the timeouts expired.
     enforce(r.empty);
     enforce(!r.willBecomeNonempty(dummyRes, dummyDur));
@@ -340,9 +355,7 @@
     pool.faultDisableCount = 1;
 
     pool.recordFault(a);
-    Thread.sleep(dur!"usecs"(1));
     pool.recordFault(b);
-    Thread.sleep(dur!"usecs"(1));
     pool.recordFault(c);
 
     auto r = pool[];
@@ -383,7 +396,7 @@
     r.popFront();
     enforce(r.front == b);
 
-    Thread.sleep(dur!"msecs"(5));
+    fakeClock += 2.seconds;
 
     r.popFront();
     enforce(r.front == c);
@@ -400,19 +413,18 @@
     pool.faultDisableCount = 1;
 
     pool.recordFault(a);
-    Thread.sleep(dur!"usecs"(1));
+    fakeClock += 1.msecs;
     pool.recordFault(b);
-    Thread.sleep(dur!"usecs"(1));
+    fakeClock += 1.msecs;
     pool.recordFault(c);
 
     auto r = pool[];
     enforce(r.empty);
 
-    Object nextRes;
-    Duration nextWait;
-    enforce(r.willBecomeNonempty(nextRes, nextWait));
-    enforce(nextRes == a);
-    enforce(nextWait > dur!"hnsecs"(0));
+    // Make sure willBecomeNonempty gets the order right.
+    enforce(r.willBecomeNonempty(dummyRes, dummyDur));
+    enforce(dummyRes == a);
+    enforce(dummyDur > Duration.zero);
 
     foreach (o; objs) pool.recordSuccess(o);
   }
diff --git a/lib/d/src/thrift/internal/ssl.d b/lib/d/src/thrift/internal/ssl.d
index 63a0a2b..3af54b5 100644
--- a/lib/d/src/thrift/internal/ssl.d
+++ b/lib/d/src/thrift/internal/ssl.d
@@ -179,7 +179,7 @@
   Exception exception;
 
   void initMessage() {
-    message.clear();
+    message.destroy();
     hadMessage = false;
     if (!location.empty) {
       message ~= location;
diff --git a/lib/d/src/thrift/internal/ssl_bio.d b/lib/d/src/thrift/internal/ssl_bio.d
index 796be91..ae85027 100644
--- a/lib/d/src/thrift/internal/ssl_bio.d
+++ b/lib/d/src/thrift/internal/ssl_bio.d
@@ -73,7 +73,7 @@
   void setError(Exception e) nothrow {
     ERR_put_error(ERR_LIB_D_EXCEPTION, ERR_F_D_EXCEPTION, ERR_R_D_EXCEPTION,
       ERR_FILE_D_EXCEPTION, ERR_LINE_D_EXCEPTION);
-    try { GC.addRoot(cast(void*)e); } catch {}
+    try { GC.addRoot(cast(void*)e); } catch (Throwable) {}
     ERR_set_error_data(cast(char*)e, ERR_FLAGS_D_EXCEPTION);
   }
 
diff --git a/lib/d/src/thrift/internal/test/server.d b/lib/d/src/thrift/internal/test/server.d
index b5393f0..fc5e86b 100644
--- a/lib/d/src/thrift/internal/test/server.d
+++ b/lib/d/src/thrift/internal/test/server.d
@@ -102,7 +102,7 @@
         servingCondition.wait();
 
         cancel.trigger();
-        enforce(doneCondition.wait(dur!"msecs"(100)));
+        enforce(doneCondition.wait(dur!"msecs"(3*1000)));
         serverThread.join();
       }
     }
diff --git a/lib/d/src/thrift/internal/traits.d b/lib/d/src/thrift/internal/traits.d
index 11e98c5..8ce1089 100644
--- a/lib/d/src/thrift/internal/traits.d
+++ b/lib/d/src/thrift/internal/traits.d
@@ -21,115 +21,6 @@
 import std.traits;
 
 /**
- * Adds or removes attributes from the given function (pointer) or delegate
- * type.
- *
- * Besides the base type, two std.traits.FunctionAttribute bitfields are
- * accepted, representing the attributes to add to the function signature
- * resp. to remove from it. If an attribute appears in both fields, an error
- * is raised.
- *
- * Params:
- *   T = The base type.
- *   setAttrs = The attributes to add to the type, if not already present.
- *   clearAttrs = The attributes to remove from the type, if present.
- */
-template ChangeFuncAttrs(
-  T,
-  FunctionAttribute setAttrs = FunctionAttribute.none,
-  FunctionAttribute clearAttrs = FunctionAttribute.none
-) if (isFunctionPointer!T || isDelegate!T) {
-  static assert(!(setAttrs & clearAttrs),
-    "Cannot set and clear attributes at the same time.");
-  mixin({
-    enum newAttrs = (functionAttributes!T | setAttrs) & ~clearAttrs;
-    static assert(!(newAttrs & FunctionAttribute.trusted) ||
-      !(newAttrs & FunctionAttribute.safe),
-      "Cannot have a function/delegate that is both trusted and safe.");
-
-    string result = "alias ";
-
-    static if (functionLinkage!T != "D") {
-      result ~= "extern(" ~ functionLinkage!T ~ ") ";
-    }
-
-    static if (newAttrs & FunctionAttribute.ref_) {
-      result ~= "ref ";
-    }
-
-    result ~= "ReturnType!T";
-
-    static if (isDelegate!T) {
-      result ~= " delegate";
-    } else {
-      result ~= " function";
-    }
-
-    result ~= "(ParameterTypeTuple!T)";
-
-    static if (newAttrs & FunctionAttribute.pure_) {
-      result ~= " pure";
-    }
-    static if (newAttrs & FunctionAttribute.nothrow_) {
-      result ~= " nothrow";
-    }
-    static if (newAttrs & FunctionAttribute.property) {
-      result ~= " @property";
-    }
-    static if (newAttrs & FunctionAttribute.trusted) {
-      result ~= " @trusted";
-    }
-    static if (newAttrs & FunctionAttribute.safe) {
-      result ~= " @safe";
-    }
-
-    result ~= " ChangeFuncAttrs;";
-    return result;
-  }());
-}
-
-/// Ditto
-template ChangeFuncAttrs(
-  T,
-  FunctionAttribute setAttrs = FunctionAttribute.none,
-  FunctionAttribute clearAttrs = FunctionAttribute.none
-) if (is(T == function)) {
-  // To avoid a lot of syntactic headaches, we just use the above version to
-  // operate on the corresponding function pointer type and then remove the
-  // pointer again.
-  alias FunctionTypeOf!(ChangeFuncAttrs!(T*, setAttrs, clearAttrs))
-    ChangeFuncAttrs;
-}
-
-version (unittest) {
-  import std.algorithm;
-  import std.metastrings;
-  import std.typetuple;
-}
-unittest {
-  alias FunctionAttribute FA;
-  foreach (T0; TypeTuple!(
-    int function(int),
-    int delegate(int),
-    FunctionTypeOf!(int function(int))
-  )) {
-    alias ChangeFuncAttrs!(T0, FA.safe) T1;
-    static assert(functionAttributes!T1 == FA.safe);
-
-    alias ChangeFuncAttrs!(T1, FA.nothrow_ | FA.ref_, FA.safe) T2;
-    static assert(functionAttributes!T2 == (FA.nothrow_ | FA.ref_));
-
-    enum allAttrs = reduce!"a | b"([EnumMembers!FA]) & ~FA.safe;
-
-    alias ChangeFuncAttrs!(T2, allAttrs) T3;
-    static assert(functionAttributes!T3 == allAttrs);
-
-    alias ChangeFuncAttrs!(T3, FA.none, allAttrs) T4;
-    static assert(is(T4 == T0));
-  }
-}
-
-/**
  * Adds »nothrow« to the type of the passed function pointer/delegate, if it
  * is not already present.
  *
@@ -137,5 +28,6 @@
  * advantage of being explicitly about the operation that is performed.
  */
 auto assumeNothrow(T)(T t) if (isFunctionPointer!T || isDelegate!T) {
-  return cast(ChangeFuncAttrs!(T, FunctionAttribute.nothrow_))t;
+  enum attrs = functionAttributes!T | FunctionAttribute.nothrow_;
+  return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
 }
diff --git a/lib/d/src/thrift/protocol/base.d b/lib/d/src/thrift/protocol/base.d
index bd65b71..70648b3 100644
--- a/lib/d/src/thrift/protocol/base.d
+++ b/lib/d/src/thrift/protocol/base.d
@@ -207,7 +207,8 @@
     NEGATIVE_SIZE, ///
     SIZE_LIMIT, ///
     BAD_VERSION, ///
-    NOT_IMPLEMENTED ///
+    NOT_IMPLEMENTED, ///
+    DEPTH_LIMIT ///
   }
 
   ///
@@ -220,6 +221,7 @@
         case Type.SIZE_LIMIT: return "Exceeded size limit";
         case Type.BAD_VERSION: return "Invalid version";
         case Type.NOT_IMPLEMENTED: return "Not implemented";
+        case Type.DEPTH_LIMIT: return "Exceeded size limit";
         default: return "(Invalid exception type)";
       }
     }
diff --git a/lib/d/src/thrift/protocol/compact.d b/lib/d/src/thrift/protocol/compact.d
index e970fd1..9155c81 100644
--- a/lib/d/src/thrift/protocol/compact.d
+++ b/lib/d/src/thrift/protocol/compact.d
@@ -133,8 +133,8 @@
 
   void writeMessageBegin(TMessage msg) {
     writeByte(cast(byte)PROTOCOL_ID);
-    writeByte((VERSION_N & VERSION_MASK) |
-      ((cast(int)msg.type << TYPE_SHIFT_AMOUNT) & TYPE_MASK));
+    writeByte(cast(byte)((VERSION_N & VERSION_MASK) |
+                         ((cast(int)msg.type << TYPE_SHIFT_AMOUNT) & TYPE_MASK)));
     writeVarint32(msg.seqid);
     writeString(msg.name);
   }
@@ -259,7 +259,7 @@
         TProtocolException.Type.BAD_VERSION);
     }
 
-    msg.type = cast(TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & 0x03);
+    msg.type = cast(TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
     msg.seqid = readVarint32();
     msg.name = readString();
 
@@ -391,7 +391,7 @@
       writeByte(cast(byte)(size << 4 | toCType(elemType)));
     } else {
       assert(size <= int.max);
-      writeByte(0xf0 | toCType(elemType));
+      writeByte(cast(byte)(0xf0 | toCType(elemType)));
       writeVarint32(cast(int)size);
     }
   }
@@ -589,6 +589,7 @@
   enum VERSION_N = 1;
   enum VERSION_MASK = 0b0001_1111;
   enum TYPE_MASK = 0b1110_0000;
+  enum TYPE_BITS = 0b0000_0111;
   enum TYPE_SHIFT_AMOUNT = 5;
 
   // Probably need to implement a better stack at some point.
diff --git a/lib/d/src/thrift/protocol/json.d b/lib/d/src/thrift/protocol/json.d
index e89aee1..56a71da 100644
--- a/lib/d/src/thrift/protocol/json.d
+++ b/lib/d/src/thrift/protocol/json.d
@@ -26,6 +26,7 @@
 import std.string : format;
 import std.traits : isIntegral;
 import std.typetuple : allSatisfy, TypeTuple;
+import std.utf : toUTF8;
 import thrift.protocol.base;
 import thrift.transport.base;
 
@@ -61,7 +62,7 @@
   }
 
   void reset() {
-    contextStack_.clear();
+    destroy(contextStack_);
     context_ = new Context();
     reader_ = new LookaheadReader(trans_);
   }
@@ -132,7 +133,8 @@
     bool escapeNum = value !is null || context_.escapeNum;
 
     if (value is null) {
-      value = format("%.16g", dub);
+      /* precision is 17 */
+      value = format("%.17g", dub);
     }
 
     if (escapeNum) trans_.write(STRING_DELIMITER);
@@ -492,12 +494,15 @@
     return readSyntaxChar(reader_, ch);
   }
 
-  ubyte readJsonEscapeChar() {
-    readJsonSyntaxChar(ZERO_CHAR);
-    readJsonSyntaxChar(ZERO_CHAR);
+  wchar readJsonEscapeChar() {
     auto a = reader_.read();
     auto b = reader_.read();
-    return cast(ubyte)((hexVal(a[0]) << 4) + hexVal(b[0]));
+    auto c = reader_.read();
+    auto d = reader_.read();
+    return cast(ushort)(
+          (hexVal(a[0]) << 12) + (hexVal(b[0]) << 8) +
+          (hexVal(c[0]) << 4) + hexVal(d[0])
+        );
   }
 
   string readJsonString(bool skipContext = false) {
@@ -506,6 +511,7 @@
     readJsonSyntaxChar(STRING_DELIMITER);
     auto buffer = appender!string();
 
+    wchar[] wchs;
     int bytesRead;
     while (true) {
       auto ch = reader_.read();
@@ -521,7 +527,18 @@
       if (ch == BACKSLASH) {
         ch = reader_.read();
         if (ch == ESCAPE_CHAR) {
-          ch = readJsonEscapeChar();
+          auto wch = readJsonEscapeChar();
+          if (wch >= 0xD800 && wch <= 0xDBFF) {
+            wchs ~= wch;
+          } else if (wch >= 0xDC00 && wch <= 0xDFFF && wchs.length == 0) {
+            throw new TProtocolException("Missing UTF-16 high surrogate.",
+                                         TProtocolException.Type.INVALID_DATA);
+          } else {
+            wchs ~= wch;
+            buffer.put(wchs.toUTF8);
+            wchs = [];
+          }
+          continue;
         } else {
           auto pos = countUntil(kEscapeChars[], ch[0]);
           if (pos == -1) {
@@ -531,9 +548,17 @@
           ch = kEscapeCharVals[pos];
         }
       }
+      if (wchs.length != 0) {
+        throw new TProtocolException("Missing UTF-16 low surrogate.",
+                                     TProtocolException.Type.INVALID_DATA);
+      }
       buffer.put(ch[0]);
     }
 
+    if (wchs.length != 0) {
+      throw new TProtocolException("Missing UTF-16 low surrogate.",
+                                   TProtocolException.Type.INVALID_DATA);
+    }
     return buffer.data;
   }
 
@@ -772,6 +797,36 @@
 }
 
 unittest {
+  import std.exception;
+  import thrift.transport.memory;
+
+  auto buf = new TMemoryBuffer(cast(ubyte[])"\"\\u0e01 \\ud835\\udd3e\"");
+  auto json = tJsonProtocol(buf);
+  auto str = json.readString();
+  enforce(str == "ก 𝔾");
+}
+
+unittest {
+  // Thrown if low surrogate is missing.
+  import std.exception;
+  import thrift.transport.memory;
+
+  auto buf = new TMemoryBuffer(cast(ubyte[])"\"\\u0e01 \\ud835\"");
+  auto json = tJsonProtocol(buf);
+  assertThrown!TProtocolException(json.readString());
+}
+
+unittest {
+  // Thrown if high surrogate is missing.
+  import std.exception;
+  import thrift.transport.memory;
+
+  auto buf = new TMemoryBuffer(cast(ubyte[])"\"\\u0e01 \\udd3e\"");
+  auto json = tJsonProtocol(buf);
+  assertThrown!TProtocolException(json.readString());
+}
+
+unittest {
   import thrift.internal.test.protocol;
   testContainerSizeLimit!(TJsonProtocol!())();
   testStringSizeLimit!(TJsonProtocol!())();
diff --git a/lib/d/src/thrift/server/base.d b/lib/d/src/thrift/server/base.d
index b56ae66..a23b1c7 100644
--- a/lib/d/src/thrift/server/base.d
+++ b/lib/d/src/thrift/server/base.d
@@ -37,7 +37,7 @@
   /**
    * Starts serving.
    *
-   * Blocks until the server finishes, i.e. a serious problem occured or the
+   * Blocks until the server finishes, i.e. a serious problem occurred or the
    * cancellation request has been triggered.
    *
    * Server implementations are expected to implement cancellation in a best-
@@ -118,6 +118,38 @@
   TTransportFactory outputTransportFactory_;
   TProtocolFactory inputProtocolFactory_;
   TProtocolFactory outputProtocolFactory_;
+
+public:
+
+  @property TProcessorFactory processorFactory()
+  {
+    return processorFactory_;
+  }
+
+  @property TServerTransport serverTransport()
+  {
+    return serverTransport_;
+  }
+
+  @property TTransportFactory inputTransportFactory()
+  {
+    return inputTransportFactory_;
+  }
+
+  @property TTransportFactory outputTransportFactory()
+  {
+    return outputTransportFactory_;
+  }
+
+  @property TProtocolFactory inputProtocolFactory()
+  {
+    return inputProtocolFactory_;
+  }
+
+  @property TProtocolFactory outputProtocolFactory()
+  {
+    return outputProtocolFactory_;
+  }
 }
 
 /**
diff --git a/lib/d/src/thrift/server/nonblocking.d b/lib/d/src/thrift/server/nonblocking.d
index 0216799..5860c0c 100644
--- a/lib/d/src/thrift/server/nonblocking.d
+++ b/lib/d/src/thrift/server/nonblocking.d
@@ -893,14 +893,14 @@
       callsSinceResize_ = 0;
 
       factoryInputTransport_ =
-        server_.inputTransportFactory_.getTransport(inputTransport_);
+        server_.inputTransportFactory.getTransport(inputTransport_);
       factoryOutputTransport_ =
-        server_.outputTransportFactory_.getTransport(outputTransport_);
+        server_.outputTransportFactory.getTransport(outputTransport_);
 
       inputProtocol_ =
-        server_.inputProtocolFactory_.getProtocol(factoryInputTransport_);
+        server_.inputProtocolFactory.getProtocol(factoryInputTransport_);
       outputProtocol_ =
-        server_.outputProtocolFactory_.getProtocol(factoryOutputTransport_);
+        server_.outputProtocolFactory.getProtocol(factoryOutputTransport_);
 
       if (server_.eventHandler) {
         connectionContext_ =
@@ -908,7 +908,7 @@
       }
 
       auto info = TConnectionInfo(inputProtocol_, outputProtocol_, socket_);
-      processor_ = server_.processorFactory_.getProcessor(info);
+      processor_ = server_.processorFactory.getProcessor(info);
     }
 
     ~this() {
diff --git a/lib/d/src/thrift/server/simple.d b/lib/d/src/thrift/server/simple.d
index f7183a7..5aba4c1 100644
--- a/lib/d/src/thrift/server/simple.d
+++ b/lib/d/src/thrift/server/simple.d
@@ -140,7 +140,9 @@
           }
         }
       } catch (TTransportException ttx) {
-        logError("Client died: %s", ttx);
+        if (ttx.type() != TTransportException.Type.END_OF_FILE) {
+          logError("Client died unexpectedly: %s", ttx);
+        }
       } catch (Exception e) {
         logError("Uncaught exception: %s", e);
       }
diff --git a/lib/d/src/thrift/server/taskpool.d b/lib/d/src/thrift/server/taskpool.d
index b4720a4..670e720 100644
--- a/lib/d/src/thrift/server/taskpool.d
+++ b/lib/d/src/thrift/server/taskpool.d
@@ -268,7 +268,9 @@
         }
       }
     } catch (TTransportException ttx) {
-      logError("Client died: %s", ttx);
+      if (ttx.type() != TTransportException.Type.END_OF_FILE) {
+        logError("Client died unexpectedly: %s", ttx);
+      }
     } catch (Exception e) {
       logError("Uncaught exception: %s", e);
     }
diff --git a/lib/d/src/thrift/server/threaded.d b/lib/d/src/thrift/server/threaded.d
index 1cde983..300cc84 100644
--- a/lib/d/src/thrift/server/threaded.d
+++ b/lib/d/src/thrift/server/threaded.d
@@ -173,7 +173,9 @@
         }
       }
     } catch (TTransportException ttx) {
-      logError("Client died: %s", ttx);
+      if (ttx.type() != TTransportException.Type.END_OF_FILE) {
+        logError("Client died unexpectedly: %s", ttx);
+      }
     } catch (Exception e) {
       logError("Uncaught exception: %s", e);
     }
diff --git a/lib/d/src/thrift/server/transport/base.d b/lib/d/src/thrift/server/transport/base.d
index da165d3..704e16d 100644
--- a/lib/d/src/thrift/server/transport/base.d
+++ b/lib/d/src/thrift/server/transport/base.d
@@ -95,16 +95,7 @@
 
   ///
   this(Type type, string file = __FILE__, size_t line = __LINE__, Throwable next = null) {
-    string msg = "TTransportException: ";
-    switch (type) {
-      case Type.UNKNOWN: msg ~= "Unknown server transport exception"; break;
-      case Type.NOT_LISTENING: msg ~= "Server transport not listening"; break;
-      case Type.ALREADY_LISTENING: msg ~= "Server transport already listening"; break;
-      case Type.RESOURCE_FAILED: msg ~= "An underlying resource failed"; break;
-      default: msg ~= "(Invalid exception type)"; break;
-    }
-
-    this(msg, type, file, line, next);
+    this(errorMsg(type), type, file, line, next);
   }
 
   ///
@@ -129,5 +120,18 @@
 
 protected:
   Type type_;
+
+private:
+  string errorMsg(Type type) {
+    string msg = "TTransportException: ";
+    switch (type) {
+      case Type.UNKNOWN: msg ~= "Unknown server transport exception"; break;
+      case Type.NOT_LISTENING: msg ~= "Server transport not listening"; break;
+      case Type.ALREADY_LISTENING: msg ~= "Server transport already listening"; break;
+      case Type.RESOURCE_FAILED: msg ~= "An underlying resource failed"; break;
+      default: msg ~= "(Invalid exception type)"; break;
+    }
+    return msg;
+  }
 }
 
diff --git a/lib/d/src/thrift/transport/file.d b/lib/d/src/thrift/transport/file.d
index 7c6705a..fe88e73 100644
--- a/lib/d/src/thrift/transport/file.d
+++ b/lib/d/src/thrift/transport/file.d
@@ -37,7 +37,8 @@
 import std.algorithm : min, max;
 import std.concurrency;
 import std.conv : to;
-import std.datetime : AutoStart, dur, Duration, StopWatch;
+import std.datetime : dur, Duration;
+import std.datetime.stopwatch : AutoStart, StopWatch;
 import std.exception;
 import std.stdio : File;
 import thrift.base;
@@ -246,7 +247,7 @@
     enforce(!isOpen, new TTransportException(
       "Cannot set chunk size after TFileReaderTransport has been opened."));
     enforce(value > EventSize.sizeof, new TTransportException("Chunks must " ~
-      "be large enough to accomodate at least a single byte of payload data."));
+      "be large enough to accommodate at least a single byte of payload data."));
     chunkSize_ = value;
   }
 
@@ -637,7 +638,7 @@
   override void close() {
     if (!isOpen) return;
 
-    prioritySend(writerThread_, ShutdownMessage(), thisTid); // FIXME: Should use normal send here.
+    send(writerThread_, ShutdownMessage(), thisTid);
     receive((ShutdownMessage msg, Tid tid){});
     isOpen_ = false;
   }
@@ -847,7 +848,7 @@
         (immutable(ubyte)[] data) {
           while (errorOpening) {
             logError("Writer thread going to sleep for %s µs due to IO errors",
-              ioErrorSleepDuration.fracSec.usecs);
+              ioErrorSleepDuration.total!"usecs");
 
             // Sleep for ioErrorSleepDuration, being ready to be interrupted
             // by shutdown requests.
@@ -1076,15 +1077,15 @@
 
       // If any attempt takes more than 500ms, treat that as a fatal failure to
       // avoid looping over a potentially very slow operation.
-      enforce(sw.peek().msecs < 500,
-        text("close() took ", sw.peek().msecs, "ms."));
+      enforce(sw.peek().total!"msecs" < 1500,
+        text("close() took ", sw.peek().total!"msecs", "ms."));
 
       // Normally, it takes less than 5ms on my dev box.
       // However, if the box is heavily loaded, some of the test runs can take
       // longer. Additionally, on a Windows Server 2008 instance running in
       // a VirtualBox VM, it has been observed that about a quarter of the runs
       // takes (217 ± 1) ms, for reasons not yet known.
-      if (sw.peek().msecs > 5) {
+      if (sw.peek().total!"msecs" > 50) {
         ++numOver;
       }
 
diff --git a/lib/d/src/thrift/transport/http.d b/lib/d/src/thrift/transport/http.d
index 5186f3d..0e58dee 100644
--- a/lib/d/src/thrift/transport/http.d
+++ b/lib/d/src/thrift/transport/http.d
@@ -134,7 +134,7 @@
     }
 
     static bool compToLower(ubyte a, ubyte b) {
-      return a == toLower(cast(char)b);
+      return toLower(cast(char)a) == toLower(cast(char)b);
     }
 
     if (startsWith!compToLower(split[0], cast(ubyte[])"transfer-encoding")) {
@@ -330,7 +330,7 @@
       "Host: " ~ host_ ~ "\r\n" ~
       "Content-Type: application/x-thrift\r\n" ~
       "Content-Length: " ~ to!string(dataLength) ~ "\r\n" ~
-      "Accept: application/x-thrift\r\n"
+      "Accept: application/x-thrift\r\n" ~
       "User-Agent: Thrift/" ~ VERSION ~ " (D/TClientHttpTransport)\r\n" ~
       "\r\n";
   }
diff --git a/lib/d/src/thrift/transport/socket.d b/lib/d/src/thrift/transport/socket.d
index 38b567a..fcb38da 100644
--- a/lib/d/src/thrift/transport/socket.d
+++ b/lib/d/src/thrift/transport/socket.d
@@ -18,6 +18,7 @@
  */
 module thrift.transport.socket;
 
+import core.stdc.errno: ECONNRESET;
 import core.thread : Thread;
 import core.time : dur, Duration;
 import std.array : empty;
@@ -79,8 +80,8 @@
     version (none) assert(written <= buf.length, text("Implementation wrote " ~
       "more data than requested to?! (", written, " vs. ", buf.length, ")"));
   } body {
-    assert(0, "DMD bug? – Why would contracts work for interfaces, but not "
-      "for abstract methods? "
+    assert(0, "DMD bug? – Why would contracts work for interfaces, but not " ~
+      "for abstract methods? " ~
       "(Error: function […] in and out contracts require function body");
   }
 
@@ -256,7 +257,7 @@
         new TCompoundOperationException(
           text(
             "All addresses tried failed (",
-            joiner(map!q{text(a._0, `: "`, a._1.msg, `"`)}(zip(addrs, errors)), ", "),
+            joiner(map!q{text(a[0], `: "`, a[1].msg, `"`)}(zip(addrs, errors)), ", "),
             ")."
           ),
           errors
diff --git a/lib/d/src/thrift/transport/ssl.d b/lib/d/src/thrift/transport/ssl.d
index c1eab25..f8ce40e 100644
--- a/lib/d/src/thrift/transport/ssl.d
+++ b/lib/d/src/thrift/transport/ssl.d
@@ -249,7 +249,13 @@
     }
     count_++;
 
-    ctx_ = SSL_CTX_new(TLSv1_method());
+    static if (OPENSSL_VERSION_NUMBER >= 0x1010000f) { // OPENSSL_VERSION_AT_LEAST(1, 1)) {
+        ctx_ = SSL_CTX_new(TLS_method());
+    } else {
+        ctx_ = SSL_CTX_new(SSLv23_method());
+        SSL_CTX_set_options(ctx_, SSL_OP_NO_SSLv2);
+    }
+    SSL_CTX_set_options(ctx_, SSL_OP_NO_SSLv3);   // THRIFT-3164
     enforce(ctx_, getSSLException("SSL_CTX_new"));
     SSL_CTX_set_mode(ctx_, SSL_MODE_AUTO_RETRY);
   }
@@ -446,6 +452,7 @@
     }
     initialized_ = true;
 
+   static if (OPENSSL_VERSION_NUMBER < 0x1010000f) { // OPENSSL_VERSION_BEFORE(1, 1)) {
     SSL_library_init();
     SSL_load_error_strings();
 
@@ -463,12 +470,14 @@
     CRYPTO_set_dynlock_create_callback(assumeNothrow(&dynlockCreateCallback));
     CRYPTO_set_dynlock_lock_callback(assumeNothrow(&dynlockLockCallback));
     CRYPTO_set_dynlock_destroy_callback(assumeNothrow(&dynlockDestroyCallback));
+   }
   }
 
   static void cleanupOpenSSL() {
     if (!initialized_) return;
 
     initialized_ = false;
+   static if (OPENSSL_VERSION_NUMBER < 0x1010000f) { // OPENSSL_VERSION_BEFORE(1, 1)) {
     CRYPTO_set_locking_callback(null);
     CRYPTO_set_dynlock_create_callback(null);
     CRYPTO_set_dynlock_lock_callback(null);
@@ -476,6 +485,7 @@
     CRYPTO_cleanup_all_ex_data();
     ERR_free_strings();
     ERR_remove_state(0);
+   }
   }
 
   static extern(C) {
@@ -518,7 +528,7 @@
       const(char)* file, int line)
     {
       GC.removeRange(l);
-      clear(cast(Mutex)l);
+      destroy(cast(Mutex)l);
       free(l);
     }
 
diff --git a/lib/d/src/thrift/util/future.d b/lib/d/src/thrift/util/future.d
index 7c127c4..2b32a01 100644
--- a/lib/d/src/thrift/util/future.d
+++ b/lib/d/src/thrift/util/future.d
@@ -316,7 +316,7 @@
 }
 
 /**
- * Creates an interface that is similiar to a given one, but accepts an
+ * Creates an interface that is similar to a given one, but accepts an
  * additional, optional TCancellation parameter each method, and returns
  * TFutures instead of plain return values.
  *
@@ -454,7 +454,7 @@
 
       ++completedCount_;
       if (completedCount_ == futures_.length) {
-        // This was the last future in the list, there is no possiblity
+        // This was the last future in the list, there is no possibility
         // another result could ever become available.
         finished_ = true;
       }
diff --git a/lib/d/src/thrift/util/hashset.d b/lib/d/src/thrift/util/hashset.d
index 5ef97f9..ede122e 100644
--- a/lib/d/src/thrift/util/hashset.d
+++ b/lib/d/src/thrift/util/hashset.d
@@ -23,13 +23,15 @@
 import std.traits : isImplicitlyConvertible, ParameterTypeTuple;
 import std.range : ElementType, isInputRange;
 
+struct Void {}
+
 /**
  * A quickly hacked together hash set implementation backed by built-in
  * associative arrays to have something to compile Thrift's set<> to until
  * std.container gains something suitable.
  */
 // Note: The funky pointer casts (i.e. *(cast(immutable(E)*)&e) instead of
-// just cast(immutable(E))e) are a workaround for LDC 2 compatibilty.
+// just cast(immutable(E))e) are a workaround for LDC 2 compatibility.
 final class HashSet(E) {
   ///
   this() {}
@@ -41,7 +43,7 @@
 
   ///
   void insert(Stuff)(Stuff stuff) if (isImplicitlyConvertible!(Stuff, E)) {
-    aa_[*(cast(immutable(E)*)&stuff)] = [];
+    aa_[*(cast(immutable(E)*)&stuff)] = Void.init;
   }
 
   ///
@@ -49,7 +51,7 @@
     isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, E)
   ) {
     foreach (e; stuff) {
-      aa_[*(cast(immutable(E)*)&e)] = [];
+      aa_[*(cast(immutable(E)*)&e)] = Void.init;
     }
   }
 
@@ -86,7 +88,7 @@
 
   ///
   auto opSlice() const {
-    // TODO: Implement using AA key range once availabe in release DMD/druntime
+    // TODO: Implement using AA key range once available in release DMD/druntime
     // to avoid allocation.
     return cast(E[])(aa_.keys);
   }
@@ -115,7 +117,6 @@
   }
 
 private:
-  alias void[0] Void;
   Void[immutable(E)] aa_;
 }
 
diff --git a/lib/d/test/Makefile.am b/lib/d/test/Makefile.am
old mode 100644
new mode 100755
index ff4bd46..3b6a6f1
--- a/lib/d/test/Makefile.am
+++ b/lib/d/test/Makefile.am
@@ -17,11 +17,13 @@
 # under the License.
 #
 
+AUTOMAKE_OPTIONS = serial-tests
+
+BUILT_SOURCES = trusted-ca-certificate.pem server-certificate.pem
+
 
 # Thrift compiler rules
 
-THRIFT = $(top_builddir)/compiler/cpp/thrift
-
 debug_proto_gen = $(addprefix gen-d/, DebugProtoTest_types.d)
 
 $(debug_proto_gen): $(top_srcdir)/test/DebugProtoTest.thrift
@@ -52,7 +54,7 @@
 
 libevent_dependent_targets = async_test_client client_pool_test \
 	stress_test_server thrift_test_server
-libevent_dependent_ran_tests = async_test_runner.sh thrift_test_runner.sh
+libevent_dependent_ran_tests = client_pool_test async_test_runner.sh thrift_test_runner.sh
 
 openssl_dependent_targets = async_test thrift_test_client thrift_test_server
 openssl_dependent_ran_tests = async_test_runner.sh thrift_test_runner.sh
@@ -70,7 +72,7 @@
 
 if WITH_D_SSL_TESTS
 d_test_flags += $(DMD_OPENSSL_FLAGS) ../$(D_SSL_LIB_NAME)
-targets = trusted-ca-certificate.pem server-certificate.pem $(targets_)
+targets = $(targets_)
 ran_tests = $(ran_tests_)
 else
 targets = $(filter-out $(openssl_dependent_targets), $(targets_))
@@ -121,3 +123,5 @@
 	trusted-ca-certificate.pem server-certificate.pem
 
 TESTS = $(ran_tests)
+
+precross: $(targets)
diff --git a/lib/d/test/async_test.d b/lib/d/test/async_test.d
index 16db51b..fb765ad 100644
--- a/lib/d/test/async_test.d
+++ b/lib/d/test/async_test.d
@@ -130,7 +130,7 @@
   }
 
   auto managers = new TLibeventAsyncManager[managerCount];
-  scope (exit) foreach (ref m; managers) clear(m);
+  scope (exit) foreach (ref m; managers) destroy(m);
 
   auto clientsThreads = new ThreadGroup;
   foreach (managerIndex, ref manager; managers) {
@@ -340,9 +340,9 @@
           if (trace_) writefln(`Calling delayedEcho("%s", 100 ms)...`, id);
           auto a = client.delayedEcho(id, 100);
           enforce(!a.completion.wait(dur!"usecs"(1)),
-            text("wait() succeded early (", a.get(), ", ", id, ")."));
+            text("wait() succeeded early (", a.get(), ", ", id, ")."));
           enforce(!a.completion.wait(dur!"usecs"(1)),
-            text("wait() succeded early (", a.get(), ", ", id, ")."));
+            text("wait() succeeded early (", a.get(), ", ", id, ")."));
           enforce(a.completion.wait(dur!"msecs"(200)),
             text("wait() didn't succeed as expected (", id, ")."));
           enforce(a.get() == id);
@@ -353,9 +353,9 @@
           if (trace_) writefln(`Calling delayedFail("%s", 100 ms)... `, id);
           auto a = client.delayedFail(id, 100);
           enforce(!a.completion.wait(dur!"usecs"(1)),
-            text("wait() succeded early (", id, ", ", collectException(a.get()), ")."));
+            text("wait() succeeded early (", id, ", ", collectException(a.get()), ")."));
           enforce(!a.completion.wait(dur!"usecs"(1)),
-            text("wait() succeded early (", id, ", ", collectException(a.get()), ")."));
+            text("wait() succeeded early (", id, ", ", collectException(a.get()), ")."));
           enforce(a.completion.wait(dur!"msecs"(200)),
             text("wait() didn't succeed as expected (", id, ")."));
           auto e = cast(AsyncTestException)collectException(a.get());
diff --git a/lib/d/test/async_test_runner.sh b/lib/d/test/async_test_runner.sh
old mode 100644
new mode 100755
index 4b9b7c0..7d507ee
--- a/lib/d/test/async_test_runner.sh
+++ b/lib/d/test/async_test_runner.sh
@@ -1,6 +1,28 @@
 #!/bin/bash
+
+#
+# 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.
+#
+
+CUR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
 # Runs the async test in both SSL and non-SSL mode.
-./async_test > /dev/null || exit 1
+${CUR}/async_test > /dev/null || exit 1
 echo "Non-SSL tests done."
-./async_test --ssl > /dev/null || exit 1
+${CUR}/async_test --ssl > /dev/null || exit 1
 echo "SSL tests done."
diff --git a/lib/d/test/client_pool_test.d b/lib/d/test/client_pool_test.d
index 85bcb29..b24c97a 100644
--- a/lib/d/test/client_pool_test.d
+++ b/lib/d/test/client_pool_test.d
@@ -18,6 +18,7 @@
  */
 module client_pool_test;
 
+import core.sync.semaphore : Semaphore;
 import core.time : Duration, dur;
 import core.thread : Thread;
 import std.algorithm;
@@ -28,6 +29,7 @@
 import std.range;
 import std.stdio;
 import std.typecons;
+import std.variant : Variant;
 import thrift.base;
 import thrift.async.libevent;
 import thrift.async.socket;
@@ -37,9 +39,12 @@
 import thrift.codegen.client;
 import thrift.codegen.client_pool;
 import thrift.codegen.processor;
+import thrift.protocol.base;
 import thrift.protocol.binary;
+import thrift.server.base;
 import thrift.server.simple;
 import thrift.server.transport.socket;
+import thrift.transport.base;
 import thrift.transport.buffered;
 import thrift.transport.socket;
 import thrift.util.cancellation;
@@ -108,11 +113,29 @@
   }
 }
 
+class ServerPreServeHandler : TServerEventHandler {
+  this(Semaphore sem) {
+    sem_ = sem;
+  }
+
+  override void preServe() {
+    sem_.notify();
+  }
+
+  Variant createContext(TProtocol input, TProtocol output) { return Variant.init; }
+  void deleteContext(Variant serverContext, TProtocol input, TProtocol output) {}
+  void preProcess(Variant serverContext, TTransport transport) {}
+
+private:
+  Semaphore sem_;
+}
+
 class ServerThread : Thread {
-  this(ExTestHandler handler, TCancellation cancellation) {
+  this(ExTestHandler handler, ServerPreServeHandler serverHandler, TCancellation cancellation) {
     super(&run);
     handler_ = handler;
     cancellation_ = cancellation;
+    serverHandler_ = serverHandler;
   }
 private:
   void run() {
@@ -123,16 +146,17 @@
       serverTransport.recvTimeout = dur!"seconds"(3);
       auto transportFactory = new TBufferedTransportFactory;
 
-      auto server = new TSimpleServer(
-        processor, serverTransport, transportFactory, protocolFactory);
+      auto server = new TSimpleServer(processor, serverTransport, transportFactory, protocolFactory);
+      server.eventHandler = serverHandler_;
       server.serve(cancellation_);
     } catch (Exception e) {
       writefln("Server thread on port %s failed: %s", handler_.port, e);
     }
   }
 
-  TCancellation cancellation_;
   ExTestHandler handler_;
+  ServerPreServeHandler serverHandler_;
+  TCancellation cancellation_;
 }
 
 void main(string[] args) {
@@ -145,6 +169,9 @@
 
   immutable ports = cast(immutable)array(map!"cast(ushort)a"(iota(port, port + 6)));
 
+  // semaphore that will be incremented whenever each server thread has bound and started listening
+  Semaphore sem = new Semaphore(0);
+
 version (none) {
   // Cannot use this due to multiple DMD @@BUG@@s:
   // 1. »function D main is a nested function and cannot be accessed from array«
@@ -174,11 +201,10 @@
 }
 
   // Fire up the server threads.
-  foreach (h; handlers) (new ServerThread(h, serverCancellation)).start();
+  foreach (h; handlers) (new ServerThread(h, new ServerPreServeHandler(sem), serverCancellation)).start();
 
-  // Give the servers some time to get up. This should really be accomplished
-  // via a barrier here and in the preServe() hook.
-  Thread.sleep(dur!"msecs"(10));
+  // wait until all the handlers signal that they're ready to serve
+  foreach (h; handlers) (sem.wait(dur!`seconds`(1)));
 
   syncClientPoolTest(ports, handlers);
   asyncClientPoolTest(ports, handlers);
@@ -409,8 +435,8 @@
     )();
     Thread.sleep(dur!"msecs"(20));
     auto resultTuple = partialResult.finishGet();
-    enforce(resultTuple._0 == ports[0 .. 2]);
-    enforce(equal(map!"a.port"(cast(TestServiceException[])resultTuple._1),
+    enforce(resultTuple[0] == ports[0 .. 2]);
+    enforce(equal(map!"a.port"(cast(TestServiceException[])resultTuple[1]),
       ports[3 .. $ - 1]));
   }
 }
diff --git a/lib/d/test/serialization_benchmark.d b/lib/d/test/serialization_benchmark.d
index 35515c8..40d0480 100644
--- a/lib/d/test/serialization_benchmark.d
+++ b/lib/d/test/serialization_benchmark.d
@@ -13,7 +13,7 @@
  */
 module serialization_benchmark;
 
-import std.datetime : AutoStart, StopWatch;
+import std.datetime.stopwatch : AutoStart, StopWatch;
 import std.math : PI;
 import std.stdio;
 import thrift.protocol.binary;
@@ -46,7 +46,7 @@
     }
     sw.stop();
 
-    auto msecs = sw.peek().msecs;
+    auto msecs = sw.peek().total!"msecs";
     writefln("Write: %s ms (%s kHz)", msecs, ITERATIONS / msecs);
   }
 
@@ -64,7 +64,7 @@
     }
     sw.stop();
 
-    auto msecs = sw.peek().msecs;
+    auto msecs = sw.peek().total!"msecs";
     writefln(" Read: %s ms (%s kHz)", msecs, ITERATIONS / msecs);
   }
 }
diff --git a/lib/d/test/thrift_test_client.d b/lib/d/test/thrift_test_client.d
index a258b64..49419f7 100644
--- a/lib/d/test/thrift_test_client.d
+++ b/lib/d/test/thrift_test_client.d
@@ -25,6 +25,7 @@
 import std.stdio;
 import std.string;
 import std.traits;
+import thrift.base;
 import thrift.codegen.client;
 import thrift.protocol.base;
 import thrift.protocol.binary;
@@ -75,6 +76,7 @@
     "ssl", &ssl,
     "transport", &transportType,
     "trace", &trace,
+    "port", &port,
     "host", (string _, string value) {
       auto parts = split(value, ":");
       if (parts.length > 1) {
@@ -87,13 +89,14 @@
       }
     }
   );
+  port = to!ushort(port);
 
   TSocket socket;
   if (ssl) {
     auto sslContext = new TSSLContext();
     sslContext.ciphers = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
     sslContext.authenticate = true;
-    sslContext.loadTrustedCertificates("./trusted-ca-certificate.pem");
+    sslContext.loadTrustedCertificates("../../../test/keys/CA.pem");
     socket = new TSSLSocket(sslContext, host, port);
   } else {
     socket = new TSocket(host, port);
@@ -159,6 +162,8 @@
     if (trace) writefln(" = %s", dub);
     enforce(dub == -5.2098523);
 
+	// TODO: add testBinary() call
+	
     Xtruct out1;
     out1.string_thing = "Zero";
     out1.byte_thing = 1;
@@ -278,6 +283,15 @@
       }
 
       try {
+        if (trace) write("client.testException(\"TException\") =>");
+        client.testException("Xception");
+        if (trace) writeln("  void\nFAILURE");
+        throw new Exception("testException failed.");
+      } catch (TException e) {
+        if (trace) writefln("  {%s}", e.msg);
+      }
+
+      try {
         if (trace) write("client.testException(\"success\") =>");
         client.testException("success");
         if (trace) writeln("  void");
diff --git a/lib/d/test/thrift_test_runner.sh b/lib/d/test/thrift_test_runner.sh
old mode 100644
new mode 100755
index fbe75f0..51bfe99
--- a/lib/d/test/thrift_test_runner.sh
+++ b/lib/d/test/thrift_test_runner.sh
@@ -1,10 +1,34 @@
 #!/bin/bash
+
+#
+# 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.
+#
+
 # Runs the D ThriftTest client and servers for all combinations of transport,
 # protocol, SSL-mode and server type.
 # Pass -k to keep going after failed tests.
 
+CUR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
 protocols="binary compact json"
-transports="buffered framed http raw"
+# TODO: fix and enable http
+# transports="buffered framed raw http"
+transports="buffered framed raw"
 servers="simple taskpool threaded"
 framed_only_servers="nonblocking pooledNonblocking"
 
@@ -21,16 +45,20 @@
         esac
 
         args="--transport=$transport --protocol=$protocol$ssl"
-        ./thrift_test_server $args --server-type=$server > /dev/null &
+        ${CUR}/thrift_test_server $args --server-type=$server > /dev/null &
         server_pid=$!
 
         # Give the server some time to get up and check if it runs (yes, this
         # is a huge kludge, should add a connect timeout to test client).
         client_rc=-1
-        sleep 0.01
+        if [ "$server" = "taskpool" ]; then
+          sleep 0.5
+        else
+          sleep 0.02
+        fi
         kill -0 $server_pid 2>/dev/null
         if [ $? -eq 0 ]; then
-          ./thrift_test_client $args --numTests=10 > /dev/null
+          ${CUR}/thrift_test_client $args --numTests=10 > /dev/null
           client_rc=$?
 
           # Temporarily redirect stderr to null to avoid job control messages,
diff --git a/lib/d/test/thrift_test_server.d b/lib/d/test/thrift_test_server.d
index 993c063..b582253 100644
--- a/lib/d/test/thrift_test_server.d
+++ b/lib/d/test/thrift_test_server.d
@@ -16,8 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
 module thrift_test_server;
 
+import core.stdc.errno : errno;
+import core.stdc.signal : signal, sigfn_t, SIGINT, SIG_DFL, SIG_ERR;
 import core.thread : dur, Thread;
 import std.algorithm;
 import std.exception : enforce;
@@ -40,6 +43,7 @@
 import thrift.transport.framed;
 import thrift.transport.http;
 import thrift.transport.ssl;
+import thrift.util.cancellation;
 import thrift.util.hashset;
 import test_utils;
 
@@ -81,6 +85,16 @@
     return thing;
   }
 
+  override string testBinary(string thing) {
+    if (trace_) writefln("testBinary(\"%s\")", thing);
+    return thing;
+  }
+
+  override bool testBool(bool thing) {
+    if (trace_) writefln("testBool(\"%s\")", thing);
+    return thing;
+  }
+
   override Xtruct testStruct(ref const(Xtruct) thing) {
     if (trace_) writefln("testStruct({\"%s\", %s, %s, %s})",
       thing.string_thing, thing.byte_thing, thing.i32_thing, thing.i64_thing);
@@ -133,7 +147,17 @@
 
   override Insanity[Numberz][UserId] testInsanity(ref const(Insanity) argument) {
     if (trace_) writeln("testInsanity()");
-    return testInsanityReturn;
+    Insanity[Numberz][UserId] ret;
+    Insanity[Numberz] m1;
+    Insanity[Numberz] m2;
+    Insanity tmp;
+    tmp = cast(Insanity)argument;
+    m1[Numberz.TWO] = tmp;
+    m1[Numberz.THREE] = tmp;
+    m2[Numberz.SIX] = Insanity();
+    ret[1] = m1;
+    ret[2] = m2;
+    return ret;
   }
 
   override Xtruct testMulti(byte arg0, int arg1, long arg2, string[short] arg3,
@@ -150,6 +174,8 @@
       e.errorCode = 1001;
       e.message = arg;
       throw e;
+    } else if (arg == "TException") {
+      throw new TException();
     } else if (arg == "ApplicationException") {
       throw new TException();
     }
@@ -183,14 +209,44 @@
   bool trace_;
 }
 
+shared(bool) gShutdown = false;
+
+nothrow @nogc extern(C) void handleSignal(int sig) {
+  gShutdown = true;
+}
+
+// Runs a thread that waits for shutdown to be
+// signaled and then triggers cancellation,
+// causing the server to stop.  While we could
+// use a signalfd for this purpose, we are instead
+// opting for a busy waiting scheme for maximum
+// portability since signalfd is a linux thing.
+
+class ShutdownThread : Thread {
+  this(TCancellationOrigin cancellation) {
+    cancellation_ = cancellation;
+    super(&run);
+  }
+  
+private:
+  void run() {
+    while (!gShutdown) {
+      Thread.sleep(dur!("msecs")(25));
+    }
+    cancellation_.trigger();
+  }
+  
+  TCancellationOrigin cancellation_;
+}
+
 void main(string[] args) {
   ushort port = 9090;
   ServerType serverType;
   ProtocolType protocolType;
   size_t numIOThreads = 1;
   TransportType transportType;
-  bool ssl;
-  bool trace;
+  bool ssl = false;
+  bool trace = true;
   size_t taskPoolSize = totalCPUs;
 
   getopt(args, "port", &port, "protocol", &protocolType, "server-type",
@@ -244,8 +300,8 @@
   if (ssl) {
     auto sslContext = new TSSLContext();
     sslContext.serverSide = true;
-    sslContext.loadCertificate("./server-certificate.pem");
-    sslContext.loadPrivateKey("./server-private-key.pem");
+    sslContext.loadCertificate("../../../test/keys/server.crt");
+    sslContext.loadPrivateKey("../../../test/keys/server.key");
     sslContext.ciphers = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
     serverSocket = new TSSLServerSocket(port, sslContext);
   } else {
@@ -257,8 +313,26 @@
   auto server = createServer(serverType, numIOThreads, taskPoolSize,
     processor, serverSocket, transportFactory, protocolFactory);
 
+  // Set up SIGINT signal handling
+  sigfn_t oldHandler = signal(SIGINT, &handleSignal);
+  enforce(oldHandler != SIG_ERR,
+    "Could not replace the SIGINT signal handler: errno {0}".format(errno()));
+  
+  // Set up a server cancellation trigger
+  auto cancel = new TCancellationOrigin();
+
+  // Set up a listener for the shutdown condition - this will
+  // wake up when the signal occurs and trigger cancellation.
+  auto shutdown = new ShutdownThread(cancel);
+  shutdown.start();
+  
+  // Serve from this thread; the signal will stop the server
+  // and control will return here
   writefln("Starting %s/%s %s ThriftTest server %son port %s...", protocolType,
     transportType, serverType, ssl ? "(using SSL) ": "", port);
-  server.serve();
+  server.serve(cancel);
+  shutdown.join();
+  signal(SIGINT, SIG_DFL);
+    
   writeln("done.");
 }
diff --git a/lib/d/test/transport_test.d b/lib/d/test/transport_test.d
index 09bf6fd..623e03f 100644
--- a/lib/d/test/transport_test.d
+++ b/lib/d/test/transport_test.d
@@ -144,7 +144,7 @@
   }
 
   ~this() {
-    clear(inner_);
+    destroy(inner_);
   }
 
 private:
diff --git a/lib/dart/.analysis_options b/lib/dart/.analysis_options
new file mode 100644
index 0000000..a10d4c5
--- /dev/null
+++ b/lib/dart/.analysis_options
@@ -0,0 +1,2 @@
+analyzer:
+  strong-mode: true
diff --git a/lib/dart/LICENSE b/lib/dart/LICENSE
new file mode 100644
index 0000000..4eacb64
--- /dev/null
+++ b/lib/dart/LICENSE
@@ -0,0 +1,16 @@
+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.
diff --git a/lib/dart/Makefile.am b/lib/dart/Makefile.am
new file mode 100644
index 0000000..ab6ddc0
--- /dev/null
+++ b/lib/dart/Makefile.am
@@ -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.
+#
+
+all-local:
+	$(DARTPUB) get
+
+clean-local:
+	$(RM) -r .pub
+	find . -type d -name "packages" | xargs $(RM) -r
+	find . -type f -name ".packages" | xargs $(RM)
+	find . -type f -name "pubspec.lock" | xargs $(RM)
+
+check-local: all
+
+EXTRA_DIST = \
+	.analysis_options
+
diff --git a/lib/dart/README.md b/lib/dart/README.md
new file mode 100644
index 0000000..2be168b
--- /dev/null
+++ b/lib/dart/README.md
@@ -0,0 +1,26 @@
+Thrift Dart Library
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+Using Thrift with Dart
+====================
+
+Dart 1.12.0 or newer is required
diff --git a/lib/dart/coding_standards.md b/lib/dart/coding_standards.md
new file mode 100644
index 0000000..62f6003
--- /dev/null
+++ b/lib/dart/coding_standards.md
@@ -0,0 +1,6 @@
+# Dart Coding Standards
+
+### Please follow:
+ * [Thrift General Coding Standards](/doc/coding_standards.md)
+ * [Use dartfmt](https://www.dartlang.org/tools/dartfmt/) and follow the 
+   [Dart Style Guide](https://www.dartlang.org/articles/style-guide/)
diff --git a/lib/dart/lib/src/browser/t_web_socket.dart b/lib/dart/lib/src/browser/t_web_socket.dart
new file mode 100644
index 0000000..17693b3
--- /dev/null
+++ b/lib/dart/lib/src/browser/t_web_socket.dart
@@ -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.
+
+library thrift.src.browser;
+
+import 'dart:async';
+import 'dart:convert' show BASE64;
+import 'dart:html' show CloseEvent;
+import 'dart:html' show Event;
+import 'dart:html' show MessageEvent;
+import 'dart:html' show WebSocket;
+import 'dart:typed_data' show Uint8List;
+
+import 'package:thrift/thrift.dart';
+
+/// A [TSocket] backed by a [WebSocket] from dart:html
+class TWebSocket implements TSocket {
+  final Uri url;
+
+  final StreamController<TSocketState> _onStateController;
+  Stream<TSocketState> get onState => _onStateController.stream;
+
+  final StreamController<Object> _onErrorController;
+  Stream<Object> get onError => _onErrorController.stream;
+
+  final StreamController<Uint8List> _onMessageController;
+  Stream<Uint8List> get onMessage => _onMessageController.stream;
+
+  final List<Uint8List> _requests = [];
+
+  TWebSocket(this.url)
+      : _onStateController = new StreamController.broadcast(),
+        _onErrorController = new StreamController.broadcast(),
+        _onMessageController = new StreamController.broadcast() {
+    if (url == null || !url.hasAuthority || !url.hasPort) {
+      throw new ArgumentError('Invalid url');
+    }
+  }
+
+  WebSocket _socket;
+
+  bool get isOpen => _socket != null && _socket.readyState == WebSocket.OPEN;
+
+  bool get isClosed =>
+      _socket == null || _socket.readyState == WebSocket.CLOSED;
+
+  Future open() {
+    if (!isClosed) {
+      throw new TTransportError(
+          TTransportErrorType.ALREADY_OPEN, 'Socket already connected');
+    }
+
+    _socket = new WebSocket(url.toString());
+    _socket.onError.listen(_onError);
+    _socket.onOpen.listen(_onOpen);
+    _socket.onClose.listen(_onClose);
+    _socket.onMessage.listen(_onMessage);
+
+    return _socket.onOpen.first;
+  }
+
+  Future close() {
+    if (_socket != null) {
+      _socket.close();
+      return _socket.onClose.first;
+    } else {
+      return new Future.value();
+    }
+  }
+
+  void send(Uint8List data) {
+    _requests.add(data);
+    _sendRequests();
+  }
+
+  void _sendRequests() {
+    while (isOpen && _requests.isNotEmpty) {
+      Uint8List data = _requests.removeAt(0);
+      _socket.sendString(BASE64.encode(data));
+    }
+  }
+
+  void _onOpen(Event event) {
+    _onStateController.add(TSocketState.OPEN);
+    _sendRequests();
+  }
+
+  void _onClose(CloseEvent event) {
+    _socket = null;
+
+    if (_requests.isNotEmpty) {
+      _onErrorController
+          .add(new StateError('Socket was closed with pending requests'));
+    }
+    _requests.clear();
+
+    _onStateController.add(TSocketState.CLOSED);
+  }
+
+  void _onMessage(MessageEvent message) {
+    try {
+      Uint8List data =
+          new Uint8List.fromList(BASE64.decode(message.data));
+      _onMessageController.add(data);
+    } on FormatException catch (_) {
+      var error = new TProtocolError(TProtocolErrorType.INVALID_DATA,
+          "Expected a Base 64 encoded string.");
+      _onErrorController.add(error);
+    }
+  }
+
+  void _onError(Event event) {
+    close();
+    _onErrorController.add(event.toString());
+  }
+}
diff --git a/lib/dart/lib/src/console/t_tcp_socket.dart b/lib/dart/lib/src/console/t_tcp_socket.dart
new file mode 100644
index 0000000..b714803
--- /dev/null
+++ b/lib/dart/lib/src/console/t_tcp_socket.dart
@@ -0,0 +1,81 @@
+/// Licensed to the Apache Software Foundation (ASF) under one
+/// or more contributor license agreements. See the NOTICE file
+/// distributed with this work for additional information
+/// regarding copyright ownership. The ASF licenses this file
+/// to you under the Apache License, Version 2.0 (the
+/// "License"); you may not use this file except in compliance
+/// with the License. You may obtain a copy of the License at
+///
+/// http://www.apache.org/licenses/LICENSE-2.0
+///
+/// Unless required by applicable law or agreed to in writing,
+/// software distributed under the License is distributed on an
+/// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+/// KIND, either express or implied. See the License for the
+/// specific language governing permissions and limitations
+/// under the License.
+
+library thrift.src.console.t_tcp_socket;
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:typed_data' show Uint8List;
+
+import 'package:thrift/thrift.dart';
+
+/// A [TSocket] backed by a [Socket] from dart:io
+class TTcpSocket implements TSocket {
+  final StreamController<TSocketState> _onStateController;
+  Stream<TSocketState> get onState => _onStateController.stream;
+
+  final StreamController<Object> _onErrorController;
+  Stream<Object> get onError => _onErrorController.stream;
+
+  final StreamController<Uint8List> _onMessageController;
+  Stream<Uint8List> get onMessage => _onMessageController.stream;
+
+  TTcpSocket(Socket socket)
+      : _onStateController = new StreamController.broadcast(),
+        _onErrorController = new StreamController.broadcast(),
+        _onMessageController = new StreamController.broadcast() {
+    if (socket == null) {
+      throw new ArgumentError.notNull('socket');
+    }
+
+    _socket = socket;
+    _socket.listen(_onMessage, onError: _onError, onDone: close);
+  }
+
+  Socket _socket;
+
+  bool get isOpen => _socket != null;
+
+  bool get isClosed => _socket == null;
+
+  Future open() async {
+    _onStateController.add(TSocketState.OPEN);
+  }
+
+  Future close() async {
+    if (_socket != null) {
+      await _socket.close();
+      _socket = null;
+    }
+
+    _onStateController.add(TSocketState.CLOSED);
+  }
+
+  void send(Uint8List data) {
+    _socket.add(data);
+  }
+
+  void _onMessage(List<int> message) {
+    Uint8List data = new Uint8List.fromList(message);
+    _onMessageController.add(data);
+  }
+
+  void _onError(Object error) {
+    close();
+    _onErrorController.add('$error');
+  }
+}
diff --git a/lib/dart/lib/src/console/t_web_socket.dart b/lib/dart/lib/src/console/t_web_socket.dart
new file mode 100644
index 0000000..4ed7284
--- /dev/null
+++ b/lib/dart/lib/src/console/t_web_socket.dart
@@ -0,0 +1,89 @@
+/// 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.
+
+library thrift.src.console.t_web_socket;
+
+import 'dart:async';
+import 'dart:convert' show BASE64;
+import 'dart:io';
+import 'dart:typed_data' show Uint8List;
+
+import 'package:thrift/thrift.dart';
+
+/// A [TSocket] backed by a [WebSocket] from dart:io
+class TWebSocket implements TSocket {
+  final StreamController<TSocketState> _onStateController;
+  Stream<TSocketState> get onState => _onStateController.stream;
+
+  final StreamController<Object> _onErrorController;
+  Stream<Object> get onError => _onErrorController.stream;
+
+  final StreamController<Uint8List> _onMessageController;
+  Stream<Uint8List> get onMessage => _onMessageController.stream;
+
+  TWebSocket(WebSocket socket)
+      : _onStateController = new StreamController.broadcast(),
+        _onErrorController = new StreamController.broadcast(),
+        _onMessageController = new StreamController.broadcast() {
+    if (socket == null) {
+      throw new ArgumentError.notNull('socket');
+    }
+
+    _socket = socket;
+    _socket.listen(_onMessage, onError: _onError, onDone: close);
+  }
+
+  WebSocket _socket;
+
+  bool get isOpen => _socket != null;
+
+  bool get isClosed => _socket == null;
+
+  Future open() async {
+    _onStateController.add(TSocketState.OPEN);
+  }
+
+  Future close() async {
+    if (_socket != null) {
+      await _socket.close();
+      _socket = null;
+    }
+
+    _onStateController.add(TSocketState.CLOSED);
+  }
+
+  void send(Uint8List data) {
+    _socket.add(BASE64.encode(data));
+  }
+
+  void _onMessage(String message) {
+    try {
+      Uint8List data =
+          new Uint8List.fromList(BASE64.decode(message));
+      _onMessageController.add(data);
+    } on FormatException catch (_) {
+      var error = new TProtocolError(TProtocolErrorType.INVALID_DATA,
+          "Expected a Base 64 encoded string.");
+      _onErrorController.add(error);
+    }
+  }
+
+  void _onError(Object error) {
+    close();
+    _onErrorController.add('$error');
+  }
+}
diff --git a/lib/dart/lib/src/protocol/t_binary_protocol.dart b/lib/dart/lib/src/protocol/t_binary_protocol.dart
new file mode 100644
index 0000000..a785d81
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_binary_protocol.dart
@@ -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.
+
+part of thrift;
+
+class TBinaryProtocolFactory implements TProtocolFactory<TBinaryProtocol> {
+  TBinaryProtocolFactory({this.strictRead: false, this.strictWrite: true});
+
+  final bool strictRead;
+  final bool strictWrite;
+
+  TBinaryProtocol getProtocol(TTransport transport) {
+    return new TBinaryProtocol(transport,
+        strictRead: strictRead, strictWrite: strictWrite);
+  }
+}
+
+/// Binary protocol implementation for Thrift.
+///
+/// Adapted from the C# version.
+class TBinaryProtocol extends TProtocol {
+  static const int VERSION_MASK = 0xffff0000;
+  static const int VERSION_1 = 0x80010000;
+
+  static const Utf8Codec _utf8Codec = const Utf8Codec();
+
+  final bool strictRead;
+  final bool strictWrite;
+
+  TBinaryProtocol(TTransport transport,
+      {this.strictRead: false, this.strictWrite: true})
+      : super(transport);
+
+  /// write
+  void writeMessageBegin(TMessage message) {
+    if (strictWrite) {
+      int version = VERSION_1 | message.type;
+      writeI32(version);
+      writeString(message.name);
+      writeI32(message.seqid);
+    } else {
+      writeString(message.name);
+      writeByte(message.type);
+      writeI32(message.seqid);
+    }
+  }
+
+  void writeMessageEnd() {}
+
+  void writeStructBegin(TStruct struct) {}
+
+  void writeStructEnd() {}
+
+  void writeFieldBegin(TField field) {
+    writeByte(field.type);
+    writeI16(field.id);
+  }
+
+  void writeFieldEnd() {}
+
+  void writeFieldStop() {
+    writeByte(TType.STOP);
+  }
+
+  void writeMapBegin(TMap map) {
+    writeByte(map.keyType);
+    writeByte(map.valueType);
+    writeI32(map.length);
+  }
+
+  void writeMapEnd() {}
+
+  void writeListBegin(TList list) {
+    writeByte(list.elementType);
+    writeI32(list.length);
+  }
+
+  void writeListEnd() {}
+
+  void writeSetBegin(TSet set) {
+    writeByte(set.elementType);
+    writeI32(set.length);
+  }
+
+  void writeSetEnd() {}
+
+  void writeBool(bool b) {
+    if (b == null) b = false;
+    writeByte(b ? 1 : 0);
+  }
+
+  final ByteData _byteOut = new ByteData(1);
+  void writeByte(int byte) {
+    if (byte == null) byte = 0;
+    _byteOut.setUint8(0, byte);
+    transport.write(_byteOut.buffer.asUint8List(), 0, 1);
+  }
+
+  final ByteData _i16Out = new ByteData(2);
+  void writeI16(int i16) {
+    if (i16 == null) i16 = 0;
+    _i16Out.setInt16(0, i16);
+    transport.write(_i16Out.buffer.asUint8List(), 0, 2);
+  }
+
+  final ByteData _i32Out = new ByteData(4);
+  void writeI32(int i32) {
+    if (i32 == null) i32 = 0;
+    _i32Out.setInt32(0, i32);
+    transport.write(_i32Out.buffer.asUint8List(), 0, 4);
+  }
+
+  final Uint8List _i64Out = new Uint8List(8);
+  void writeI64(int i64) {
+    if (i64 == null) i64 = 0;
+    var i = new Int64(i64);
+    var bts = i.toBytes();
+    for (var j = 0; j < 8; j++) {
+      _i64Out[j] = bts[8 - j - 1];
+    }
+    transport.write(_i64Out, 0, 8);
+  }
+
+  void writeString(String s) {
+    var bytes = s != null ? _utf8Codec.encode(s) : new Uint8List.fromList([]);
+    writeI32(bytes.length);
+    transport.write(bytes, 0, bytes.length);
+  }
+
+  final ByteData _doubleOut = new ByteData(8);
+  void writeDouble(double d) {
+    if (d == null) d = 0.0;
+    _doubleOut.setFloat64(0, d);
+    transport.write(_doubleOut.buffer.asUint8List(), 0, 8);
+  }
+
+  void writeBinary(Uint8List bytes) {
+    var length = bytes.length;
+    writeI32(length);
+    transport.write(bytes, 0, length);
+  }
+
+  /// read
+  TMessage readMessageBegin() {
+    String name;
+    int type;
+    int seqid;
+
+    int size = readI32();
+    if (size < 0) {
+      int version = size & VERSION_MASK;
+      if (version != VERSION_1) {
+        throw new TProtocolError(TProtocolErrorType.BAD_VERSION,
+            "Bad version in readMessageBegin: $version");
+      }
+      type = size & 0x000000ff;
+      name = readString();
+      seqid = readI32();
+    } else {
+      if (strictRead) {
+        throw new TProtocolError(TProtocolErrorType.BAD_VERSION,
+            "Missing version in readMessageBegin");
+      }
+      name = _readString(size);
+      type = readByte();
+      seqid = readI32();
+    }
+    return new TMessage(name, type, seqid);
+  }
+
+  void readMessageEnd() {}
+
+  TStruct readStructBegin() {
+    return new TStruct();
+  }
+
+  void readStructEnd() {}
+
+  TField readFieldBegin() {
+    String name = "";
+    int type = readByte();
+    int id = type != TType.STOP ? readI16() : 0;
+
+    return new TField(name, type, id);
+  }
+
+  void readFieldEnd() {}
+
+  TMap readMapBegin() {
+    int keyType = readByte();
+    int valueType = readByte();
+    int length = readI32();
+
+    return new TMap(keyType, valueType, length);
+  }
+
+  void readMapEnd() {}
+
+  TList readListBegin() {
+    int elementType = readByte();
+    int length = readI32();
+
+    return new TList(elementType, length);
+  }
+
+  void readListEnd() {}
+
+  TSet readSetBegin() {
+    int elementType = readByte();
+    int length = readI32();
+
+    return new TSet(elementType, length);
+  }
+
+  void readSetEnd() {}
+
+  bool readBool() => readByte() == 1;
+
+  final Uint8List _byteIn = new Uint8List(1);
+  int readByte() {
+    transport.readAll(_byteIn, 0, 1);
+    return _byteIn.buffer.asByteData().getUint8(0);
+  }
+
+  final Uint8List _i16In = new Uint8List(2);
+  int readI16() {
+    transport.readAll(_i16In, 0, 2);
+    return _i16In.buffer.asByteData().getInt16(0);
+  }
+
+  final Uint8List _i32In = new Uint8List(4);
+  int readI32() {
+    transport.readAll(_i32In, 0, 4);
+    return _i32In.buffer.asByteData().getInt32(0);
+  }
+
+  final Uint8List _i64In = new Uint8List(8);
+  int readI64() {
+    transport.readAll(_i64In, 0, 8);
+    var i = new Int64.fromBytesBigEndian(_i64In);
+    return i.toInt();
+  }
+
+  final Uint8List _doubleIn = new Uint8List(8);
+  double readDouble() {
+    transport.readAll(_doubleIn, 0, 8);
+    return _doubleIn.buffer.asByteData().getFloat64(0);
+  }
+
+  String readString() {
+    int size = readI32();
+    return _readString(size);
+  }
+
+  String _readString(int size) {
+    Uint8List stringIn = new Uint8List(size);
+    transport.readAll(stringIn, 0, size);
+    return _utf8Codec.decode(stringIn);
+  }
+
+  Uint8List readBinary() {
+    int length = readI32();
+    Uint8List binaryIn = new Uint8List(length);
+    transport.readAll(binaryIn, 0, length);
+    return binaryIn;
+  }
+}
diff --git a/lib/dart/lib/src/protocol/t_compact_protocol.dart b/lib/dart/lib/src/protocol/t_compact_protocol.dart
new file mode 100644
index 0000000..72d7641
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_compact_protocol.dart
@@ -0,0 +1,470 @@
+/// 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.
+
+part of thrift;
+
+class TCompactProtocolFactory implements TProtocolFactory<TCompactProtocol> {
+  TCompactProtocolFactory();
+
+  TCompactProtocol getProtocol(TTransport transport) {
+    return new TCompactProtocol(transport);
+  }
+}
+
+/// Compact protocol implementation for Thrift.
+///
+/// Use of fixnum library is required due to bugs like
+/// https://github.com/dart-lang/sdk/issues/15361
+///
+/// Adapted from the Java version.
+class TCompactProtocol extends TProtocol {
+  static const int PROTOCOL_ID = 0x82;
+  static const int VERSION = 1;
+  static const int VERSION_MASK = 0x1f;
+  static const int TYPE_MASK = 0xE0;
+  static const int TYPE_BITS = 0x07;
+  static const int TYPE_SHIFT_AMOUNT = 5;
+  static final TField TSTOP = new TField("", TType.STOP, 0);
+
+  static const int TYPE_BOOLEAN_TRUE = 0x01;
+  static const int TYPE_BOOLEAN_FALSE = 0x02;
+  static const int TYPE_BYTE = 0x03;
+  static const int TYPE_I16 = 0x04;
+  static const int TYPE_I32 = 0x05;
+  static const int TYPE_I64 = 0x06;
+  static const int TYPE_DOUBLE = 0x07;
+  static const int TYPE_BINARY = 0x08;
+  static const int TYPE_LIST = 0x09;
+  static const int TYPE_SET = 0x0A;
+  static const int TYPE_MAP = 0x0B;
+  static const int TYPE_STRUCT = 0x0C;
+
+  static final List<int> _typeMap = new List.unmodifiable(new List(16)
+    ..[TType.STOP] = TType.STOP
+    ..[TType.BOOL] = TYPE_BOOLEAN_TRUE
+    ..[TType.BYTE] = TYPE_BYTE
+    ..[TType.I16] = TYPE_I16
+    ..[TType.I32] = TYPE_I32
+    ..[TType.I64] = TYPE_I64
+    ..[TType.DOUBLE] = TYPE_DOUBLE
+    ..[TType.STRING] = TYPE_BINARY
+    ..[TType.LIST] = TYPE_LIST
+    ..[TType.SET] = TYPE_SET
+    ..[TType.MAP] = TYPE_MAP
+    ..[TType.STRUCT] = TYPE_STRUCT);
+
+  static const Utf8Codec _utf8Codec = const Utf8Codec();
+
+  // Pretend this is a stack
+  DoubleLinkedQueue<int> _lastField = new DoubleLinkedQueue<int>();
+  int _lastFieldId = 0;
+
+  TField _booleanField = null;
+  bool _boolValue = null;
+
+  final Uint8List tempList = new Uint8List(10);
+  final ByteData tempBD = new ByteData(10);
+
+  TCompactProtocol(TTransport transport) : super(transport);
+
+  /// Write
+  void writeMessageBegin(TMessage message) {
+    writeByte(PROTOCOL_ID);
+    writeByte((VERSION & VERSION_MASK) |
+        ((message.type << TYPE_SHIFT_AMOUNT) & TYPE_MASK));
+    _writeVarInt32(new Int32(message.seqid));
+    writeString(message.name);
+  }
+
+  void writeMessageEnd() {}
+
+  void writeStructBegin(TStruct struct) {
+    _lastField.addLast(_lastFieldId);
+    _lastFieldId = 0;
+  }
+
+  void writeStructEnd() {
+    _lastFieldId = _lastField.removeLast();
+  }
+
+  void writeFieldBegin(TField field) {
+    if (field.type == TType.BOOL) {
+      _booleanField = field;
+    } else {
+      _writeFieldBegin(field, -1);
+    }
+  }
+
+  void _writeFieldBegin(TField field, int typeOverride) {
+    int typeToWrite =
+        typeOverride == -1 ? _getCompactType(field.type) : typeOverride;
+
+    if (field.id > _lastFieldId && field.id - _lastFieldId <= 15) {
+      writeByte((field.id - _lastFieldId) << 4 | typeToWrite);
+    } else {
+      writeByte(typeToWrite);
+      writeI16(field.id);
+    }
+
+    _lastFieldId = field.id;
+  }
+
+  void writeFieldEnd() {}
+
+  void writeFieldStop() {
+    writeByte(TType.STOP);
+  }
+
+  void writeMapBegin(TMap map) {
+    if (map.length == 0) {
+      writeByte(0);
+    } else {
+      _writeVarInt32(new Int32(map.length));
+      writeByte(
+          _getCompactType(map.keyType) << 4 | _getCompactType(map.valueType));
+    }
+  }
+
+  void writeMapEnd() {}
+
+  void writeListBegin(TList list) {
+    _writeCollectionBegin(list.elementType, list.length);
+  }
+
+  void writeListEnd() {}
+
+  void writeSetBegin(TSet set) {
+    _writeCollectionBegin(set.elementType, set.length);
+  }
+
+  void writeSetEnd() {}
+
+  void writeBool(bool b) {
+    if (b == null) b = false;
+    if (_booleanField != null) {
+      _writeFieldBegin(
+          _booleanField, b ? TYPE_BOOLEAN_TRUE : TYPE_BOOLEAN_FALSE);
+      _booleanField = null;
+    } else {
+      writeByte(b ? TYPE_BOOLEAN_TRUE : TYPE_BOOLEAN_FALSE);
+    }
+  }
+
+  void writeByte(int b) {
+    if (b == null) b = 0;
+    tempList[0] = b;
+    transport.write(tempList, 0, 1);
+  }
+
+  void writeI16(int i16) {
+    if (i16 == null) i16 = 0;
+    _writeVarInt32(_int32ToZigZag(new Int32(i16)));
+  }
+
+  void writeI32(int i32) {
+    if (i32 == null) i32 = 0;
+    _writeVarInt32(_int32ToZigZag(new Int32(i32)));
+  }
+
+  void writeI64(int i64) {
+    if (i64 == null) i64 = 0;
+    _writeVarInt64(_int64ToZigZag(new Int64(i64)));
+  }
+
+  void writeDouble(double d) {
+    if (d == null) d = 0.0;
+    tempBD.setFloat64(0, d, Endianness.LITTLE_ENDIAN);
+    transport.write(tempBD.buffer.asUint8List(), 0, 8);
+  }
+
+  void writeString(String str) {
+    Uint8List bytes =
+        str != null ? _utf8Codec.encode(str) : new Uint8List.fromList([]);
+    writeBinary(bytes);
+  }
+
+  void writeBinary(Uint8List bytes) {
+    _writeVarInt32(new Int32(bytes.length));
+    transport.write(bytes, 0, bytes.length);
+  }
+
+  void _writeVarInt32(Int32 n) {
+    int idx = 0;
+    while (true) {
+      if ((n & ~0x7F) == 0) {
+        tempList[idx++] = (n & 0xFF).toInt();
+        break;
+      } else {
+        tempList[idx++] = (((n & 0x7F) | 0x80) & 0xFF).toInt();
+        n = n.shiftRightUnsigned(7);
+      }
+    }
+    transport.write(tempList, 0, idx);
+  }
+
+  void _writeVarInt64(Int64 n) {
+    int idx = 0;
+    while (true) {
+      if ((n & ~0x7F) == 0) {
+        tempList[idx++] = (n & 0xFF).toInt();
+        break;
+      } else {
+        tempList[idx++] = (((n & 0x7F) | 0x80) & 0xFF).toInt();
+        n = n.shiftRightUnsigned(7);
+      }
+    }
+    transport.write(tempList, 0, idx);
+  }
+
+  void _writeCollectionBegin(int elemType, int length) {
+    if (length <= 14) {
+      writeByte(length << 4 | _getCompactType(elemType));
+    } else {
+      writeByte(0xF0 | _getCompactType(elemType));
+      _writeVarInt32(new Int32(length));
+    }
+  }
+
+  Int32 _int32ToZigZag(Int32 n) {
+    return (n << 1) ^ (n >> 31);
+  }
+
+  Int64 _int64ToZigZag(Int64 n) {
+    return (n << 1) ^ (n >> 63);
+  }
+
+  /// Read
+  TMessage readMessageBegin() {
+    int protocolId = readByte();
+    if (protocolId != PROTOCOL_ID) {
+      throw new TProtocolError(TProtocolErrorType.BAD_VERSION,
+          'Expected protocol id $PROTOCOL_ID but got $protocolId');
+    }
+    int versionAndType = readByte();
+    int version = versionAndType & VERSION_MASK;
+    if (version != VERSION) {
+      throw new TProtocolError(TProtocolErrorType.BAD_VERSION,
+          'Expected version $VERSION but got $version');
+    }
+    int type = (versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS;
+    int seqId = _readVarInt32().toInt();
+    String messageName = readString();
+    return new TMessage(messageName, type, seqId);
+  }
+
+  void readMessageEnd() {}
+
+  TStruct readStructBegin() {
+    _lastField.addLast(_lastFieldId);
+    _lastFieldId = 0;
+    // TODO make this a constant?
+    return new TStruct();
+  }
+
+  void readStructEnd() {
+    _lastFieldId = _lastField.removeLast();
+  }
+
+  TField readFieldBegin() {
+    int type = readByte();
+    if (type == TType.STOP) {
+      return TSTOP;
+    }
+
+    int fieldId;
+    int modifier = (type & 0xF0) >> 4;
+    if (modifier == 0) {
+      fieldId = readI16();
+    } else {
+      fieldId = _lastFieldId + modifier;
+    }
+
+    TField field = new TField('', _getTType(type & 0x0F), fieldId);
+    if (_isBoolType(type)) {
+      _boolValue = (type & 0x0F) == TYPE_BOOLEAN_TRUE;
+    }
+
+    _lastFieldId = field.id;
+    return field;
+  }
+
+  void readFieldEnd() {}
+
+  TMap readMapBegin() {
+    int length = _readVarInt32().toInt();
+    _checkNegReadLength(length);
+
+    int keyAndValueType = length == 0 ? 0 : readByte();
+    int keyType = _getTType(keyAndValueType >> 4);
+    int valueType = _getTType(keyAndValueType & 0x0F);
+    return new TMap(keyType, valueType, length);
+  }
+
+  void readMapEnd() {}
+
+  TList readListBegin() {
+    int lengthAndType = readByte();
+    int length = (lengthAndType >> 4) & 0x0F;
+    if (length == 15) {
+      length = _readVarInt32().toInt();
+    }
+    _checkNegReadLength(length);
+    int type = _getTType(lengthAndType);
+    return new TList(type, length);
+  }
+
+  void readListEnd() {}
+
+  TSet readSetBegin() {
+    TList tlist = readListBegin();
+    return new TSet(tlist.elementType, tlist.length);
+  }
+
+  void readSetEnd() {}
+
+  bool readBool() {
+    if (_boolValue != null) {
+      bool result = _boolValue;
+      _boolValue = null;
+      return result;
+    }
+    return readByte() == TYPE_BOOLEAN_TRUE;
+  }
+
+  int readByte() {
+    transport.readAll(tempList, 0, 1);
+    return tempList.buffer.asByteData().getUint8(0);
+  }
+
+  int readI16() {
+    return _zigzagToInt32(_readVarInt32()).toInt();
+  }
+
+  int readI32() {
+    return _zigzagToInt32(_readVarInt32()).toInt();
+  }
+
+  int readI64() {
+    return _zigzagToInt64(_readVarInt64()).toInt();
+  }
+
+  double readDouble() {
+    transport.readAll(tempList, 0, 8);
+    return tempList.buffer.asByteData().getFloat64(0, Endianness.LITTLE_ENDIAN);
+  }
+
+  String readString() {
+    int length = _readVarInt32().toInt();
+    _checkNegReadLength(length);
+
+    // TODO look at using temp for small strings?
+    Uint8List buff = new Uint8List(length);
+    transport.readAll(buff, 0, length);
+    return _utf8Codec.decode(buff);
+  }
+
+  Uint8List readBinary() {
+    int length = _readVarInt32().toInt();
+    _checkNegReadLength(length);
+
+    Uint8List buff = new Uint8List(length);
+    transport.readAll(buff, 0, length);
+    return buff;
+  }
+
+  Int32 _readVarInt32() {
+    Int32 result = Int32.ZERO;
+    int shift = 0;
+    while (true) {
+      Int32 b = new Int32(readByte());
+      result |= (b & 0x7f) << shift;
+      if ((b & 0x80) != 0x80) break;
+      shift += 7;
+    }
+    return result;
+  }
+
+  Int64 _readVarInt64() {
+    Int64 result = Int64.ZERO;
+    int shift = 0;
+    while (true) {
+      Int64 b = new Int64(readByte());
+      result |= (b & 0x7f) << shift;
+      if ((b & 0x80) != 0x80) break;
+      shift += 7;
+    }
+    return result;
+  }
+
+  Int32 _zigzagToInt32(Int32 n) {
+    return (n.shiftRightUnsigned(1)) ^ -(n & 1);
+  }
+
+  Int64 _zigzagToInt64(Int64 n) {
+    return (n.shiftRightUnsigned(1)) ^ -(n & 1);
+  }
+
+  void _checkNegReadLength(int length) {
+    if (length < 0) {
+      throw new TProtocolError(
+          TProtocolErrorType.NEGATIVE_SIZE, 'Negative length: $length');
+    }
+  }
+
+  int _getCompactType(int ttype) {
+    return _typeMap[ttype];
+  }
+
+  int _getTType(int type) {
+    switch (type & 0x0F) {
+      case TType.STOP:
+        return TType.STOP;
+      case TYPE_BOOLEAN_FALSE:
+      case TYPE_BOOLEAN_TRUE:
+        return TType.BOOL;
+      case TYPE_BYTE:
+        return TType.BYTE;
+      case TYPE_I16:
+        return TType.I16;
+      case TYPE_I32:
+        return TType.I32;
+      case TYPE_I64:
+        return TType.I64;
+      case TYPE_DOUBLE:
+        return TType.DOUBLE;
+      case TYPE_BINARY:
+        return TType.STRING;
+      case TYPE_LIST:
+        return TType.LIST;
+      case TYPE_SET:
+        return TType.SET;
+      case TYPE_MAP:
+        return TType.MAP;
+      case TYPE_STRUCT:
+        return TType.STRUCT;
+      default:
+        throw new TProtocolError(
+            TProtocolErrorType.INVALID_DATA, "Unknown type: ${type & 0x0F}");
+    }
+  }
+
+  bool _isBoolType(int b) {
+    int lowerNibble = b & 0x0F;
+    return lowerNibble == TYPE_BOOLEAN_TRUE ||
+        lowerNibble == TYPE_BOOLEAN_FALSE;
+  }
+}
diff --git a/lib/dart/lib/src/protocol/t_field.dart b/lib/dart/lib/src/protocol/t_field.dart
new file mode 100644
index 0000000..444b4e5
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_field.dart
@@ -0,0 +1,26 @@
+/// 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.
+
+part of thrift;
+
+class TField {
+  final String name;
+  final int type;
+  final int id;
+
+  TField(this.name, this.type, this.id);
+}
diff --git a/lib/dart/lib/src/protocol/t_json_protocol.dart b/lib/dart/lib/src/protocol/t_json_protocol.dart
new file mode 100644
index 0000000..7fbb7c4
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_json_protocol.dart
@@ -0,0 +1,784 @@
+/// 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.
+
+part of thrift;
+
+class TJsonProtocolFactory implements TProtocolFactory<TJsonProtocol> {
+  TJsonProtocol getProtocol(TTransport transport) {
+    return new TJsonProtocol(transport);
+  }
+}
+
+/// JSON protocol implementation for Thrift.
+///
+/// Adapted from the C# version.
+class TJsonProtocol extends TProtocol {
+  static const int VERSION_1 = 1;
+
+  static const Utf8Codec utf8Codec = const Utf8Codec();
+
+  _BaseContext _context;
+  _BaseContext _rootContext;
+  _LookaheadReader _reader;
+
+  final List<_BaseContext> _contextStack = [];
+  final Uint8List _tempBuffer = new Uint8List(4);
+
+  TJsonProtocol(TTransport transport) : super(transport) {
+    _rootContext = new _BaseContext(this);
+    _reader = new _LookaheadReader(this);
+    _resetContext();
+  }
+
+  void _pushContext(_BaseContext c) {
+    _contextStack.add(c);
+    _context = c;
+  }
+
+  void _popContext() {
+    _contextStack.removeLast();
+    _context = _contextStack.isEmpty ? _rootContext : _contextStack.last;
+  }
+
+  void _resetContext() {
+    _contextStack.clear();
+    _context = _rootContext;
+  }
+
+  /// Read a byte that must match [char]; otherwise throw a [TProtocolError].
+  void _readJsonSyntaxChar(int charByte) {
+    int byte = _reader.read();
+    if (byte != charByte) {
+      throw new TProtocolError(TProtocolErrorType.INVALID_DATA,
+          "Expected character ${new String.fromCharCode(charByte)} but found: ${new String.fromCharCode(byte)}");
+    }
+  }
+
+  int _hexVal(int byte) {
+    if (byte >= _Constants.HEX_0_BYTES[0] &&
+        byte <= _Constants.HEX_9_BYTES[0]) {
+      return byte - _Constants.HEX_0_BYTES[0];
+    } else if (byte >= _Constants.HEX_A_BYTES[0] &&
+        byte <= _Constants.HEX_F_BYTES[0]) {
+      byte += 10;
+      return byte - _Constants.HEX_A_BYTES[0];
+    } else {
+      throw new TProtocolError(
+          TProtocolErrorType.INVALID_DATA, "Expected hex character");
+    }
+  }
+
+  int _hexChar(int byte) => byte.toRadixString(16).codeUnitAt(0);
+
+  /// write
+
+  /// Write the [bytes] as JSON characters, escaping as needed.
+  void _writeJsonString(Uint8List bytes) {
+    _context.write();
+    transport.writeAll(_Constants.QUOTE_BYTES);
+
+    int length = bytes.length;
+    for (int i = 0; i < length; i++) {
+      int byte = bytes[i];
+      if ((byte & 0x00FF) >= 0x30) {
+        if (byte == _Constants.BACKSLASH_BYTES[0]) {
+          transport.writeAll(_Constants.BACKSLASH_BYTES);
+          transport.writeAll(_Constants.BACKSLASH_BYTES);
+        } else {
+          transport.write(bytes, i, 1);
+        }
+      } else {
+        _tempBuffer[0] = _Constants.JSON_CHAR_TABLE[byte];
+        if (_tempBuffer[0] == 1) {
+          transport.write(bytes, i, 1);
+        } else if (_tempBuffer[0] > 1) {
+          transport.writeAll(_Constants.BACKSLASH_BYTES);
+          transport.write(_tempBuffer, 0, 1);
+        } else {
+          transport.writeAll(_Constants.ESCSEQ_BYTES);
+          _tempBuffer[0] = _hexChar(byte >> 4);
+          _tempBuffer[1] = _hexChar(byte);
+          transport.write(_tempBuffer, 0, 2);
+        }
+      }
+    }
+
+    transport.writeAll(_Constants.QUOTE_BYTES);
+  }
+
+  void _writeJsonInteger(int i) {
+    if (i == null) i = 0;
+
+    _context.write();
+    String str = i.toString();
+
+    if (_context.escapeNumbers) {
+      transport.writeAll(_Constants.QUOTE_BYTES);
+    }
+    transport.writeAll(utf8Codec.encode(str));
+    if (_context.escapeNumbers) {
+      transport.writeAll(_Constants.QUOTE_BYTES);
+    }
+  }
+
+  void _writeJsonDouble(double d) {
+    if (d == null) d = 0.0;
+
+    _context.write();
+    String str = d.toString();
+    bool escapeNumbers = d.isNaN || d.isInfinite || _context.escapeNumbers;
+
+    if (escapeNumbers) {
+      transport.writeAll(_Constants.QUOTE_BYTES);
+    }
+    transport.writeAll(utf8Codec.encode(str));
+    if (escapeNumbers) {
+      transport.writeAll(_Constants.QUOTE_BYTES);
+    }
+  }
+
+  void _writeJsonBase64(Uint8List bytes) {
+    _context.write();
+    transport.writeAll(_Constants.QUOTE_BYTES);
+
+    String base64 = BASE64.encode(bytes);
+    transport.writeAll(utf8Codec.encode(base64));
+
+    transport.writeAll(_Constants.QUOTE_BYTES);
+  }
+
+  void _writeJsonObjectStart() {
+    _context.write();
+    transport.writeAll(_Constants.LBRACE_BYTES);
+    _pushContext(new _PairContext(this));
+  }
+
+  void _writeJsonObjectEnd() {
+    _popContext();
+    transport.writeAll(_Constants.RBRACE_BYTES);
+  }
+
+  void _writeJsonArrayStart() {
+    _context.write();
+    transport.writeAll(_Constants.LBRACKET_BYTES);
+    _pushContext(new _ListContext(this));
+  }
+
+  void _writeJsonArrayEnd() {
+    _popContext();
+    transport.writeAll(_Constants.RBRACKET_BYTES);
+  }
+
+  void writeMessageBegin(TMessage message) {
+    _resetContext();
+
+    _writeJsonArrayStart();
+    _writeJsonInteger(VERSION_1);
+
+    _writeJsonString(utf8Codec.encode(message.name));
+    _writeJsonInteger(message.type);
+    _writeJsonInteger(message.seqid);
+  }
+
+  void writeMessageEnd() {
+    _writeJsonArrayEnd();
+  }
+
+  void writeStructBegin(TStruct struct) {
+    _writeJsonObjectStart();
+  }
+
+  void writeStructEnd() {
+    _writeJsonObjectEnd();
+  }
+
+  void writeFieldBegin(TField field) {
+    _writeJsonInteger(field.id);
+    _writeJsonObjectStart();
+    _writeJsonString(_Constants.getTypeNameBytesForTypeId(field.type));
+  }
+
+  void writeFieldEnd() {
+    _writeJsonObjectEnd();
+  }
+
+  void writeFieldStop() {}
+
+  void writeMapBegin(TMap map) {
+    _writeJsonArrayStart();
+    _writeJsonString(_Constants.getTypeNameBytesForTypeId(map.keyType));
+    _writeJsonString(_Constants.getTypeNameBytesForTypeId(map.valueType));
+    _writeJsonInteger(map.length);
+    _writeJsonObjectStart();
+  }
+
+  void writeMapEnd() {
+    _writeJsonObjectEnd();
+    _writeJsonArrayEnd();
+  }
+
+  void writeListBegin(TList list) {
+    _writeJsonArrayStart();
+    _writeJsonString(_Constants.getTypeNameBytesForTypeId(list.elementType));
+    _writeJsonInteger(list.length);
+  }
+
+  void writeListEnd() {
+    _writeJsonArrayEnd();
+  }
+
+  void writeSetBegin(TSet set) {
+    _writeJsonArrayStart();
+    _writeJsonString(_Constants.getTypeNameBytesForTypeId(set.elementType));
+    _writeJsonInteger(set.length);
+  }
+
+  void writeSetEnd() {
+    _writeJsonArrayEnd();
+  }
+
+  void writeBool(bool b) {
+    if (b == null) b = false;
+    _writeJsonInteger(b ? 1 : 0);
+  }
+
+  void writeByte(int b) {
+    _writeJsonInteger(b);
+  }
+
+  void writeI16(int i16) {
+    _writeJsonInteger(i16);
+  }
+
+  void writeI32(int i32) {
+    _writeJsonInteger(i32);
+  }
+
+  void writeI64(int i64) {
+    _writeJsonInteger(i64);
+  }
+
+  void writeDouble(double d) {
+    _writeJsonDouble(d);
+  }
+
+  void writeString(String s) {
+    var bytes = s != null ? utf8Codec.encode(s) : new Uint8List.fromList([]);
+    _writeJsonString(bytes);
+  }
+
+  void writeBinary(Uint8List bytes) {
+    _writeJsonBase64(bytes);
+  }
+
+  bool _isHighSurrogate(int b) => b >= 0xD800 && b <= 0xDBFF;
+
+  bool _isLowSurrogate(int b) => b >= 0xDC00 && b <= 0xDFFF;
+
+  /// read
+
+  Uint8List _readJsonString({bool skipContext: false}) {
+    List<int> bytes = [];
+    List<int> codeunits = [];
+
+    if (!skipContext) {
+      _context.read();
+    }
+
+    _readJsonSyntaxChar(_Constants.QUOTE_BYTES[0]);
+    while (true) {
+      int byte = _reader.read();
+      if (byte == _Constants.QUOTE_BYTES[0]) {
+        break;
+      }
+
+      // escaped?
+      if (byte != _Constants.ESCSEQ_BYTES[0]) {
+        bytes.add(byte);
+        continue;
+      }
+
+      byte = _reader.read();
+
+      // distinguish between \uXXXX and control chars like \n
+      if (byte != _Constants.ESCSEQ_BYTES[1]) {
+        String char = new String.fromCharCode(byte);
+        int offset = _Constants.ESCAPE_CHARS.indexOf(char);
+        if (offset == -1) {
+          throw new TProtocolError(
+              TProtocolErrorType.INVALID_DATA, "Expected control char");
+        }
+        byte = _Constants.ESCAPE_CHAR_VALS.codeUnitAt(offset);
+        bytes.add(byte);
+        continue;
+      }
+
+      // it's \uXXXX
+      transport.readAll(_tempBuffer, 0, 4);
+      byte = (_hexVal(_tempBuffer[0]) << 12)
+        + (_hexVal(_tempBuffer[1]) << 8)
+        + (_hexVal(_tempBuffer[2]) << 4)
+        + _hexVal(_tempBuffer[3]);
+      if (_isHighSurrogate(byte)) {
+        if (codeunits.isNotEmpty) {
+          throw new TProtocolError(
+              TProtocolErrorType.INVALID_DATA, "Expected low surrogate");
+        }
+        codeunits.add(byte);
+      }
+      else if (_isLowSurrogate(byte)) {
+        if (codeunits.isEmpty) {
+          throw new TProtocolError(
+              TProtocolErrorType.INVALID_DATA, "Expected high surrogate");
+        }
+        codeunits.add(byte);
+        bytes.addAll(utf8Codec.encode(new String.fromCharCodes(codeunits)));
+        codeunits.clear();
+      }
+      else {
+        bytes.addAll(utf8Codec.encode(new String.fromCharCode(byte)));
+      }
+    }
+
+    if (codeunits.isNotEmpty) {
+      throw new TProtocolError(
+          TProtocolErrorType.INVALID_DATA, "Expected low surrogate");
+    }
+
+    return new Uint8List.fromList(bytes);
+  }
+
+  String _readJsonNumericChars() {
+    StringBuffer buffer = new StringBuffer();
+    while (true) {
+      if (!_Constants.isJsonNumeric(_reader.peek())) {
+        break;
+      }
+      buffer.write(new String.fromCharCode(_reader.read()));
+    }
+    return buffer.toString();
+  }
+
+  int _readJsonInteger() {
+    _context.read();
+
+    if (_context.escapeNumbers) {
+      _readJsonSyntaxChar(_Constants.QUOTE_BYTES[0]);
+    }
+    String str = _readJsonNumericChars();
+    if (_context.escapeNumbers) {
+      _readJsonSyntaxChar(_Constants.QUOTE_BYTES[0]);
+    }
+
+    try {
+      return int.parse(str);
+    } on FormatException catch (_) {
+      throw new TProtocolError(TProtocolErrorType.INVALID_DATA,
+          "Bad data encounted in numeric data");
+    }
+  }
+
+  double _readJsonDouble() {
+    _context.read();
+
+    if (_reader.peek() == _Constants.QUOTE_BYTES[0]) {
+      Uint8List bytes = _readJsonString(skipContext: true);
+      double d = double.parse(utf8Codec.decode(bytes), (_) {
+        throw new TProtocolError(TProtocolErrorType.INVALID_DATA,
+            "Bad data encounted in numeric data");
+      });
+      if (!_context.escapeNumbers && !d.isNaN && !d.isInfinite) {
+        throw new TProtocolError(TProtocolErrorType.INVALID_DATA,
+            "Numeric data unexpectedly quoted");
+      }
+      return d;
+    } else {
+      if (_context.escapeNumbers) {
+        // This will throw - we should have had a quote if escapeNumbers == true
+        _readJsonSyntaxChar(_Constants.QUOTE_BYTES[0]);
+      }
+      return double.parse(_readJsonNumericChars(), (_) {
+        throw new TProtocolError(TProtocolErrorType.INVALID_DATA,
+            "Bad data encounted in numeric data");
+      });
+    }
+  }
+
+  Uint8List _readJsonBase64() {
+    // convert UTF-8 bytes of a Base 64 encoded string to binary bytes
+    Uint8List base64Bytes = _readJsonString();
+    String base64 = utf8Codec.decode(base64Bytes);
+
+    return new Uint8List.fromList(BASE64.decode(base64));
+  }
+
+  void _readJsonObjectStart() {
+    _context.read();
+    _readJsonSyntaxChar(_Constants.LBRACE_BYTES[0]);
+    _pushContext(new _PairContext(this));
+  }
+
+  void _readJsonObjectEnd() {
+    _readJsonSyntaxChar(_Constants.RBRACE_BYTES[0]);
+    _popContext();
+  }
+
+  void _readJsonArrayStart() {
+    _context.read();
+    _readJsonSyntaxChar(_Constants.LBRACKET_BYTES[0]);
+    _pushContext(new _ListContext(this));
+  }
+
+  void _readJsonArrayEnd() {
+    _readJsonSyntaxChar(_Constants.RBRACKET_BYTES[0]);
+    _popContext();
+  }
+
+  TMessage readMessageBegin() {
+    _resetContext();
+
+    _readJsonArrayStart();
+    if (_readJsonInteger() != VERSION_1) {
+      throw new TProtocolError(
+          TProtocolErrorType.BAD_VERSION, "Message contained bad version.");
+    }
+
+    Uint8List buffer = _readJsonString();
+    String name = utf8Codec.decode(buffer);
+    int type = _readJsonInteger();
+    int seqid = _readJsonInteger();
+
+    return new TMessage(name, type, seqid);
+  }
+
+  void readMessageEnd() {
+    _readJsonArrayEnd();
+  }
+
+  TStruct readStructBegin() {
+    _readJsonObjectStart();
+    return new TStruct();
+  }
+
+  void readStructEnd() {
+    _readJsonObjectEnd();
+  }
+
+  TField readFieldBegin() {
+    String name = "";
+    int type = TType.STOP;
+    int id = 0;
+
+    if (_reader.peek() != _Constants.RBRACE_BYTES[0]) {
+      id = _readJsonInteger();
+      _readJsonObjectStart();
+      type = _Constants.getTypeIdForTypeName(_readJsonString());
+    }
+
+    return new TField(name, type, id);
+  }
+
+  void readFieldEnd() {
+    _readJsonObjectEnd();
+  }
+
+  TMap readMapBegin() {
+    _readJsonArrayStart();
+    int keyType = _Constants.getTypeIdForTypeName(_readJsonString());
+    int valueType = _Constants.getTypeIdForTypeName(_readJsonString());
+    int length = _readJsonInteger();
+    _readJsonObjectStart();
+
+    return new TMap(keyType, valueType, length);
+  }
+
+  void readMapEnd() {
+    _readJsonObjectEnd();
+    _readJsonArrayEnd();
+  }
+
+  TList readListBegin() {
+    _readJsonArrayStart();
+    int elementType = _Constants.getTypeIdForTypeName(_readJsonString());
+    int length = _readJsonInteger();
+
+    return new TList(elementType, length);
+  }
+
+  void readListEnd() {
+    _readJsonArrayEnd();
+  }
+
+  TSet readSetBegin() {
+    _readJsonArrayStart();
+    int elementType = _Constants.getTypeIdForTypeName(_readJsonString());
+    int length = _readJsonInteger();
+
+    return new TSet(elementType, length);
+  }
+
+  void readSetEnd() {
+    _readJsonArrayEnd();
+  }
+
+  bool readBool() {
+    return _readJsonInteger() == 0 ? false : true;
+  }
+
+  int readByte() {
+    return _readJsonInteger();
+  }
+
+  int readI16() {
+    return _readJsonInteger();
+  }
+
+  int readI32() {
+    return _readJsonInteger();
+  }
+
+  int readI64() {
+    return _readJsonInteger();
+  }
+
+  double readDouble() {
+    return _readJsonDouble();
+  }
+
+  String readString() {
+    return utf8Codec.decode(_readJsonString());
+  }
+
+  Uint8List readBinary() {
+    return new Uint8List.fromList(_readJsonBase64());
+  }
+}
+
+class _Constants {
+  static const utf8codec = const Utf8Codec();
+
+  static final Uint8List HEX_0_BYTES = new Uint8List.fromList('0'.codeUnits);
+  static final Uint8List HEX_9_BYTES = new Uint8List.fromList('9'.codeUnits);
+  static final Uint8List HEX_A_BYTES = new Uint8List.fromList('a'.codeUnits);
+  static final Uint8List HEX_F_BYTES = new Uint8List.fromList('f'.codeUnits);
+  static final Uint8List COMMA_BYTES = new Uint8List.fromList(','.codeUnits);
+  static final Uint8List COLON_BYTES = new Uint8List.fromList(':'.codeUnits);
+  static final Uint8List LBRACE_BYTES = new Uint8List.fromList('{'.codeUnits);
+  static final Uint8List RBRACE_BYTES = new Uint8List.fromList('}'.codeUnits);
+  static final Uint8List LBRACKET_BYTES = new Uint8List.fromList('['.codeUnits);
+  static final Uint8List RBRACKET_BYTES = new Uint8List.fromList(']'.codeUnits);
+  static final Uint8List QUOTE_BYTES = new Uint8List.fromList('"'.codeUnits);
+  static final Uint8List BACKSLASH_BYTES =
+      new Uint8List.fromList(r'\'.codeUnits);
+
+  static final ESCSEQ_BYTES = new Uint8List.fromList(r'\u00'.codeUnits);
+
+  static final Uint8List JSON_CHAR_TABLE = new Uint8List.fromList([
+    0, 0, 0, 0, 0, 0, 0, 0, // 8 bytes
+    'b'.codeUnitAt(0), 't'.codeUnitAt(0), 'n'.codeUnitAt(0), 0, // 4 bytes
+    'f'.codeUnitAt(0), 'r'.codeUnitAt(0), 0, 0, // 4 bytes
+    0, 0, 0, 0, 0, 0, 0, 0, // 8 bytes
+    0, 0, 0, 0, 0, 0, 0, 0, // 8 bytes
+    1, 1, '"'.codeUnitAt(0), 1, 1, 1, 1, 1, // 8 bytes
+    1, 1, 1, 1, 1, 1, 1, 1 // 8 bytes
+  ]);
+
+  static const String ESCAPE_CHARS = r'"\/bfnrt';
+  static const String ESCAPE_CHAR_VALS = '"\\/\b\f\n\r\t';
+
+  static const String NAME_BOOL = 'tf';
+  static const String NAME_BYTE = 'i8';
+  static const String NAME_I16 = 'i16';
+  static const String NAME_I32 = 'i32';
+  static const String NAME_I64 = 'i64';
+  static const String NAME_DOUBLE = 'dbl';
+  static const String NAME_STRUCT = 'rec';
+  static const String NAME_STRING = 'str';
+  static const String NAME_MAP = 'map';
+  static const String NAME_LIST = 'lst';
+  static const String NAME_SET = 'set';
+
+  static final Map<int, Uint8List> _TYPE_ID_TO_NAME_BYTES =
+      new Map.unmodifiable({
+    TType.BOOL: new Uint8List.fromList(NAME_BOOL.codeUnits),
+    TType.BYTE: new Uint8List.fromList(NAME_BYTE.codeUnits),
+    TType.I16: new Uint8List.fromList(NAME_I16.codeUnits),
+    TType.I32: new Uint8List.fromList(NAME_I32.codeUnits),
+    TType.I64: new Uint8List.fromList(NAME_I64.codeUnits),
+    TType.DOUBLE: new Uint8List.fromList(NAME_DOUBLE.codeUnits),
+    TType.STRING: new Uint8List.fromList(NAME_STRING.codeUnits),
+    TType.STRUCT: new Uint8List.fromList(NAME_STRUCT.codeUnits),
+    TType.MAP: new Uint8List.fromList(NAME_MAP.codeUnits),
+    TType.SET: new Uint8List.fromList(NAME_SET.codeUnits),
+    TType.LIST: new Uint8List.fromList(NAME_LIST.codeUnits)
+  });
+
+  static Uint8List getTypeNameBytesForTypeId(int typeId) {
+    if (!_TYPE_ID_TO_NAME_BYTES.containsKey(typeId)) {
+      throw new TProtocolError(
+          TProtocolErrorType.NOT_IMPLEMENTED, "Unrecognized type");
+    }
+
+    return _TYPE_ID_TO_NAME_BYTES[typeId];
+  }
+
+  static final Map<String, int> _NAME_TO_TYPE_ID = new Map.unmodifiable({
+    NAME_BOOL: TType.BOOL,
+    NAME_BYTE: TType.BYTE,
+    NAME_I16: TType.I16,
+    NAME_I32: TType.I32,
+    NAME_I64: TType.I64,
+    NAME_DOUBLE: TType.DOUBLE,
+    NAME_STRING: TType.STRING,
+    NAME_STRUCT: TType.STRUCT,
+    NAME_MAP: TType.MAP,
+    NAME_SET: TType.SET,
+    NAME_LIST: TType.LIST
+  });
+
+  static int getTypeIdForTypeName(Uint8List bytes) {
+    String name = utf8codec.decode(bytes);
+    if (!_NAME_TO_TYPE_ID.containsKey(name)) {
+      throw new TProtocolError(
+          TProtocolErrorType.NOT_IMPLEMENTED, "Unrecognized type");
+    }
+
+    return _NAME_TO_TYPE_ID[name];
+  }
+
+  static final Set<int> _JSON_NUMERICS = new Set.from([
+    '+'.codeUnitAt(0),
+    '-'.codeUnitAt(0),
+    '.'.codeUnitAt(0),
+    '0'.codeUnitAt(0),
+    '1'.codeUnitAt(0),
+    '2'.codeUnitAt(0),
+    '3'.codeUnitAt(0),
+    '4'.codeUnitAt(0),
+    '5'.codeUnitAt(0),
+    '6'.codeUnitAt(0),
+    '7'.codeUnitAt(0),
+    '8'.codeUnitAt(0),
+    '9'.codeUnitAt(0),
+    'E'.codeUnitAt(0),
+    'e'.codeUnitAt(0)
+  ]);
+
+  static bool isJsonNumeric(int byte) {
+    return _JSON_NUMERICS.contains(byte);
+  }
+}
+
+class _LookaheadReader {
+  final TJsonProtocol protocol;
+
+  _LookaheadReader(this.protocol);
+
+  bool _hasData = false;
+  final Uint8List _data = new Uint8List(1);
+
+  int read() {
+    if (_hasData) {
+      _hasData = false;
+    } else {
+      protocol.transport.readAll(_data, 0, 1);
+    }
+
+    return _data[0];
+  }
+
+  int peek() {
+    if (!_hasData) {
+      protocol.transport.readAll(_data, 0, 1);
+    }
+    _hasData = true;
+
+    return _data[0];
+  }
+}
+
+class _BaseContext {
+  final TJsonProtocol protocol;
+
+  _BaseContext(this.protocol);
+
+  void write() {}
+
+  void read() {}
+
+  bool get escapeNumbers => false;
+
+  String toString() => 'BaseContext';
+}
+
+class _ListContext extends _BaseContext {
+  _ListContext(TJsonProtocol protocol) : super(protocol);
+
+  bool _first = true;
+
+  void write() {
+    if (_first) {
+      _first = false;
+    } else {
+      protocol.transport.writeAll(_Constants.COMMA_BYTES);
+    }
+  }
+
+  void read() {
+    if (_first) {
+      _first = false;
+    } else {
+      protocol._readJsonSyntaxChar(_Constants.COMMA_BYTES[0]);
+    }
+  }
+
+  String toString() => 'ListContext';
+}
+
+class _PairContext extends _BaseContext {
+  _PairContext(TJsonProtocol protocol) : super(protocol);
+
+  bool _first = true;
+  bool _colon = true;
+
+  Uint8List get symbolBytes =>
+      _colon ? _Constants.COLON_BYTES : _Constants.COMMA_BYTES;
+
+  void write() {
+    if (_first) {
+      _first = false;
+      _colon = true;
+    } else {
+      protocol.transport.writeAll(symbolBytes);
+      _colon = !_colon;
+    }
+  }
+
+  void read() {
+    if (_first) {
+      _first = false;
+      _colon = true;
+    } else {
+      protocol._readJsonSyntaxChar(symbolBytes[0]);
+      _colon = !_colon;
+    }
+  }
+
+  bool get escapeNumbers => _colon;
+
+  String toString() => 'PairContext';
+}
diff --git a/lib/dart/lib/src/protocol/t_list.dart b/lib/dart/lib/src/protocol/t_list.dart
new file mode 100644
index 0000000..49f4673
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_list.dart
@@ -0,0 +1,25 @@
+/// 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.
+
+part of thrift;
+
+class TList {
+  final int elementType;
+  final int length;
+
+  TList(this.elementType, this.length);
+}
diff --git a/lib/dart/lib/src/protocol/t_map.dart b/lib/dart/lib/src/protocol/t_map.dart
new file mode 100644
index 0000000..efdf681
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_map.dart
@@ -0,0 +1,26 @@
+/// 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.
+
+part of thrift;
+
+class TMap {
+  final int keyType;
+  final int valueType;
+  final int length;
+
+  TMap(this.keyType, this.valueType, this.length);
+}
diff --git a/lib/dart/lib/src/protocol/t_message.dart b/lib/dart/lib/src/protocol/t_message.dart
new file mode 100644
index 0000000..cc7b886
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_message.dart
@@ -0,0 +1,35 @@
+/// 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.
+
+part of thrift;
+
+class TMessageType {
+  static const int CALL = 1;
+  static const int REPLY = 2;
+  static const int EXCEPTION = 3;
+  static const int ONEWAY = 4;
+}
+
+class TMessage {
+  final String name;
+  final int type;
+  final int seqid;
+
+  TMessage(this.name, this.type, this.seqid);
+
+  String toString() => "<TMessage name: '$name' type: $type seqid: $seqid>";
+}
diff --git a/lib/dart/lib/src/protocol/t_multiplexed_protocol.dart b/lib/dart/lib/src/protocol/t_multiplexed_protocol.dart
new file mode 100644
index 0000000..078a6d7
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_multiplexed_protocol.dart
@@ -0,0 +1,43 @@
+/// 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.
+
+part of thrift;
+
+/// Adapted from the C# version.
+class TMultiplexedProtocol extends TProtocolDecorator {
+  static const SEPARATOR = ':';
+
+  final String _serviceName;
+
+  TMultiplexedProtocol(TProtocol protocol, String serviceName)
+      : _serviceName = serviceName,
+        super(protocol) {
+    if (serviceName == null) {
+      throw new ArgumentError.notNull("serviceName");
+    }
+  }
+
+  void writeMessageBegin(TMessage message) {
+    if (message.type == TMessageType.CALL ||
+        message.type == TMessageType.ONEWAY) {
+      String name = _serviceName + SEPARATOR + message.name;
+      message = new TMessage(name, message.type, message.seqid);
+    }
+
+    super.writeMessageBegin(message);
+  }
+}
diff --git a/lib/dart/lib/src/protocol/t_protocol.dart b/lib/dart/lib/src/protocol/t_protocol.dart
new file mode 100644
index 0000000..f49c032
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_protocol.dart
@@ -0,0 +1,95 @@
+/// Licensed to the Apache Software Foundation (ASF) under one
+/// or more contributor license agreements. See the NOTICE file
+/// distributed with this work for additional information
+/// regarding copyright ownership. The ASF licenses this file
+/// to you under the Apache License, Version 2.0 (the
+/// "License"); you may not use this file except in compliance
+/// with the License. You may obtain a copy of the License at
+///
+/// http://www.apache.org/licenses/LICENSE-2.0
+///
+/// Unless required by applicable law or agreed to in writing,
+/// software distributed under the License is distributed on an
+/// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+/// KIND, either express or implied. See the License for the
+/// specific language governing permissions and limitations
+/// under the License.
+
+part of thrift;
+
+abstract class TProtocol {
+  final TTransport transport;
+
+  TProtocol(this.transport);
+
+  /// Write
+  void writeMessageBegin(TMessage message);
+  void writeMessageEnd();
+
+  void writeStructBegin(TStruct struct);
+  void writeStructEnd();
+
+  void writeFieldBegin(TField field);
+  void writeFieldEnd();
+  void writeFieldStop();
+
+  void writeMapBegin(TMap map);
+  void writeMapEnd();
+
+  void writeListBegin(TList list);
+  void writeListEnd();
+
+  void writeSetBegin(TSet set);
+  void writeSetEnd();
+
+  void writeBool(bool b);
+
+  void writeByte(int b);
+
+  void writeI16(int i16);
+
+  void writeI32(int i32);
+
+  void writeI64(int i64);
+
+  void writeDouble(double d);
+
+  void writeString(String str);
+
+  void writeBinary(Uint8List bytes);
+
+  /// Read
+  TMessage readMessageBegin();
+  void readMessageEnd();
+
+  TStruct readStructBegin();
+  void readStructEnd();
+
+  TField readFieldBegin();
+  void readFieldEnd();
+
+  TMap readMapBegin();
+  void readMapEnd();
+
+  TList readListBegin();
+  void readListEnd();
+
+  TSet readSetBegin();
+  void readSetEnd();
+
+  bool readBool();
+
+  int readByte();
+
+  int readI16();
+
+  int readI32();
+
+  int readI64();
+
+  double readDouble();
+
+  String readString();
+
+  Uint8List readBinary();
+}
diff --git a/lib/dart/lib/src/protocol/t_protocol_decorator.dart b/lib/dart/lib/src/protocol/t_protocol_decorator.dart
new file mode 100644
index 0000000..9cd02f6
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_protocol_decorator.dart
@@ -0,0 +1,150 @@
+/// 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.
+
+part of thrift;
+
+/// Forward all operations to the wrapped protocol.  Used as a base class.
+///
+/// Adapted from the C# version.
+class TProtocolDecorator extends TProtocol {
+  final TProtocol _protocol;
+
+  TProtocolDecorator(TProtocol protocol)
+      : _protocol = protocol,
+        super(protocol.transport);
+
+  /// Write
+
+  void writeMessageBegin(TMessage message) {
+    _protocol.writeMessageBegin(message);
+  }
+
+  void writeMessageEnd() {
+    _protocol.writeMessageEnd();
+  }
+
+  void writeStructBegin(TStruct struct) {
+    _protocol.writeStructBegin(struct);
+  }
+
+  void writeStructEnd() {
+    _protocol.writeStructEnd();
+  }
+
+  void writeFieldBegin(TField field) {
+    _protocol.writeFieldBegin(field);
+  }
+
+  void writeFieldEnd() {
+    _protocol.writeFieldEnd();
+  }
+
+  void writeFieldStop() {
+    _protocol.writeFieldStop();
+  }
+
+  void writeMapBegin(TMap map) {
+    _protocol.writeMapBegin(map);
+  }
+
+  void writeMapEnd() {
+    _protocol.writeMapEnd();
+  }
+
+  void writeListBegin(TList list) {
+    _protocol.writeListBegin(list);
+  }
+
+  void writeListEnd() {
+    _protocol.writeListEnd();
+  }
+
+  void writeSetBegin(TSet set) {
+    _protocol.writeSetBegin(set);
+  }
+
+  void writeSetEnd() {
+    _protocol.writeSetEnd();
+  }
+
+  void writeBool(bool b) {
+    _protocol.writeBool(b);
+  }
+
+  void writeByte(int b) {
+    _protocol.writeByte(b);
+  }
+
+  void writeI16(int i16) {
+    _protocol.writeI16(i16);
+  }
+
+  void writeI32(int i32) {
+    _protocol.writeI32(i32);
+  }
+
+  void writeI64(int i64) {
+    _protocol.writeI64(i64);
+  }
+
+  void writeDouble(double d) {
+    _protocol.writeDouble(d);
+  }
+
+  void writeString(String str) {
+    _protocol.writeString(str);
+  }
+
+  void writeBinary(Uint8List bytes) {
+    _protocol.writeBinary(bytes);
+  }
+
+  /// Read
+  TMessage readMessageBegin() => _protocol.readMessageBegin();
+  void readMessageEnd() => _protocol.readMessageEnd();
+
+  TStruct readStructBegin() => _protocol.readStructBegin();
+  void readStructEnd() => _protocol.readStructEnd();
+
+  TField readFieldBegin() => _protocol.readFieldBegin();
+  void readFieldEnd() => _protocol.readFieldEnd();
+
+  TMap readMapBegin() => _protocol.readMapBegin();
+  void readMapEnd() => _protocol.readMapEnd();
+
+  TList readListBegin() => _protocol.readListBegin();
+  void readListEnd() => _protocol.readListEnd();
+
+  TSet readSetBegin() => _protocol.readSetBegin();
+  void readSetEnd() => _protocol.readSetEnd();
+
+  bool readBool() => _protocol.readBool();
+
+  int readByte() => _protocol.readByte();
+
+  int readI16() => _protocol.readI16();
+
+  int readI32() => _protocol.readI32();
+
+  int readI64() => _protocol.readI64();
+
+  double readDouble() => _protocol.readDouble();
+
+  String readString() => _protocol.readString();
+
+  Uint8List readBinary() => _protocol.readBinary();
+}
diff --git a/lib/dart/lib/src/protocol/t_protocol_error.dart b/lib/dart/lib/src/protocol/t_protocol_error.dart
new file mode 100644
index 0000000..456baeb
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_protocol_error.dart
@@ -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.
+
+part of thrift;
+
+class TProtocolErrorType {
+  static const int UNKNOWN = 0;
+  static const int INVALID_DATA = 1;
+  static const int NEGATIVE_SIZE = 2;
+  static const int SIZE_LIMIT = 3;
+  static const int BAD_VERSION = 4;
+  static const int NOT_IMPLEMENTED = 5;
+  static const int DEPTH_LIMIT = 6;
+}
+
+class TProtocolError extends TError {
+  TProtocolError([int type = TProtocolErrorType.UNKNOWN, String message = ""])
+      : super(type, message);
+}
diff --git a/lib/dart/lib/src/protocol/t_protocol_factory.dart b/lib/dart/lib/src/protocol/t_protocol_factory.dart
new file mode 100644
index 0000000..922c6cb
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_protocol_factory.dart
@@ -0,0 +1,22 @@
+/// 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.
+
+part of thrift;
+
+abstract class TProtocolFactory<T extends TProtocol> {
+  T getProtocol(TTransport transport);
+}
diff --git a/lib/dart/lib/src/protocol/t_protocol_util.dart b/lib/dart/lib/src/protocol/t_protocol_util.dart
new file mode 100644
index 0000000..ad20068
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_protocol_util.dart
@@ -0,0 +1,107 @@
+/// Licensed to the Apache Software Foundation (ASF) under one
+/// or more contributor license agreements. See the NOTICE file
+/// distributed with this work for additional information
+/// regarding copyright ownership. The ASF licenses this file
+/// to you under the Apache License, Version 2.0 (the
+/// "License"); you may not use this file except in compliance
+/// with the License. You may obtain a copy of the License at
+///
+/// http://www.apache.org/licenses/LICENSE-2.0
+///
+/// Unless required by applicable law or agreed to in writing,
+/// software distributed under the License is distributed on an
+/// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+/// KIND, either express or implied. See the License for the
+/// specific language governing permissions and limitations
+/// under the License.
+
+part of thrift;
+
+class TProtocolUtil {
+  // equal to JavaScript Number.MAX_SAFE_INTEGER, 2^53 - 1
+  static const int defaultRecursionLimit = 9007199254740991;
+
+  static int maxRecursionLimit = defaultRecursionLimit;
+
+  static skip(TProtocol prot, int type) {
+    _skip(prot, type, maxRecursionLimit);
+  }
+
+  static _skip(TProtocol prot, int type, int recursionLimit) {
+    if (recursionLimit <= 0) {
+      throw new TProtocolError(
+          TProtocolErrorType.DEPTH_LIMIT, "Depth limit exceeded");
+    }
+
+    switch (type) {
+      case TType.BOOL:
+        prot.readBool();
+        break;
+
+      case TType.BYTE:
+        prot.readByte();
+        break;
+
+      case TType.I16:
+        prot.readI16();
+        break;
+
+      case TType.I32:
+        prot.readI32();
+        break;
+
+      case TType.I64:
+        prot.readI64();
+        break;
+
+      case TType.DOUBLE:
+        prot.readDouble();
+        break;
+
+      case TType.STRING:
+        prot.readBinary();
+        break;
+
+      case TType.STRUCT:
+        prot.readStructBegin();
+        while (true) {
+          TField field = prot.readFieldBegin();
+          if (field.type == TType.STOP) {
+            break;
+          }
+          _skip(prot, field.type, recursionLimit - 1);
+          prot.readFieldEnd();
+        }
+        prot.readStructEnd();
+        break;
+
+      case TType.MAP:
+        TMap map = prot.readMapBegin();
+        for (int i = 0; i < map.length; i++) {
+          _skip(prot, map.keyType, recursionLimit - 1);
+          _skip(prot, map.valueType, recursionLimit - 1);
+        }
+        prot.readMapEnd();
+        break;
+
+      case TType.SET:
+        TSet set = prot.readSetBegin();
+        for (int i = 0; i < set.length; i++) {
+          _skip(prot, set.elementType, recursionLimit - 1);
+        }
+        prot.readSetEnd();
+        break;
+
+      case TType.LIST:
+        TList list = prot.readListBegin();
+        for (int i = 0; i < list.length; i++) {
+          _skip(prot, list.elementType, recursionLimit - 1);
+        }
+        prot.readListEnd();
+        break;
+
+      default:
+        break;
+    }
+  }
+}
diff --git a/lib/dart/lib/src/protocol/t_set.dart b/lib/dart/lib/src/protocol/t_set.dart
new file mode 100644
index 0000000..b342537
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_set.dart
@@ -0,0 +1,25 @@
+/// 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.
+
+part of thrift;
+
+class TSet {
+  final int elementType;
+  final int length;
+
+  TSet(this.elementType, this.length);
+}
diff --git a/lib/dart/lib/src/protocol/t_struct.dart b/lib/dart/lib/src/protocol/t_struct.dart
new file mode 100644
index 0000000..0303f63
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_struct.dart
@@ -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.
+
+part of thrift;
+
+class TStruct {
+  final String name;
+
+  TStruct([this.name = ""]);
+}
diff --git a/lib/dart/lib/src/protocol/t_type.dart b/lib/dart/lib/src/protocol/t_type.dart
new file mode 100644
index 0000000..3919d96
--- /dev/null
+++ b/lib/dart/lib/src/protocol/t_type.dart
@@ -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.
+
+part of thrift;
+
+class TType {
+  static const int STOP = 0;
+  static const int VOID = 1;
+  static const int BOOL = 2;
+  static const int BYTE = 3;
+  static const int DOUBLE = 4;
+  static const int I16 = 6;
+  static const int I32 = 8;
+  static const int I64 = 10;
+  static const int STRING = 11;
+  static const int STRUCT = 12;
+  static const int MAP = 13;
+  static const int SET = 14;
+  static const int LIST = 15;
+}
diff --git a/lib/dart/lib/src/serializer/t_deserializer.dart b/lib/dart/lib/src/serializer/t_deserializer.dart
new file mode 100644
index 0000000..ed1d139
--- /dev/null
+++ b/lib/dart/lib/src/serializer/t_deserializer.dart
@@ -0,0 +1,50 @@
+/// 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.
+
+part of thrift;
+
+class TDeserializer {
+  final message = new TMessage('Deserializer', TMessageType.ONEWAY, 1);
+  TBufferedTransport transport;
+  TProtocol protocol;
+
+  TDeserializer({TProtocolFactory protocolFactory}) {
+    this.transport = new TBufferedTransport();
+    
+    if (protocolFactory == null) {
+        protocolFactory = new TBinaryProtocolFactory();
+    }
+    
+    this.protocol = protocolFactory.getProtocol(this.transport);
+  }
+
+  void read(TBase base, Uint8List data) {
+    transport.writeAll(data);
+    
+    transport.flush();
+    
+    base.read(protocol);
+  }
+
+  void readString(TBase base, String data) {
+    transport.writeAll(BASE64.decode(data));
+    
+    transport.flush();
+
+    base.read(protocol);
+  }
+}
diff --git a/lib/dart/lib/src/serializer/t_serializer.dart b/lib/dart/lib/src/serializer/t_serializer.dart
new file mode 100644
index 0000000..20ddb6d
--- /dev/null
+++ b/lib/dart/lib/src/serializer/t_serializer.dart
@@ -0,0 +1,48 @@
+/// 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.
+
+part of thrift;
+
+class TSerializer {
+  final message = new TMessage('Serializer', TMessageType.ONEWAY, 1);
+  TBufferedTransport transport;
+  TProtocol protocol;
+
+  TSerializer({TProtocolFactory protocolFactory}) {
+    this.transport = new TBufferedTransport();
+    
+    if (protocolFactory == null) {
+      protocolFactory = new TBinaryProtocolFactory();
+    }
+
+    this.protocol = protocolFactory.getProtocol(this.transport);
+  }
+
+  Uint8List write(TBase base) {
+    base.write(protocol);
+    
+    return transport.consumeWriteBuffer();
+  }
+
+  String writeString(TBase base) {
+    base.write(protocol);
+    
+    Uint8List bytes = transport.consumeWriteBuffer();
+    
+    return BASE64.encode(bytes);
+  }
+}
diff --git a/lib/dart/lib/src/t_application_error.dart b/lib/dart/lib/src/t_application_error.dart
new file mode 100644
index 0000000..6f8abd4
--- /dev/null
+++ b/lib/dart/lib/src/t_application_error.dart
@@ -0,0 +1,104 @@
+/// 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.
+
+part of thrift;
+
+class TApplicationErrorType {
+  static const int UNKNOWN = 0;
+  static const int UNKNOWN_METHOD = 1;
+  static const int INVALID_MESSAGE_TYPE = 2;
+  static const int WRONG_METHOD_NAME = 3;
+  static const int BAD_SEQUENCE_ID = 4;
+  static const int MISSING_RESULT = 5;
+  static const int INTERNAL_ERROR = 6;
+  static const int PROTOCOL_ERROR = 7;
+  static const int INVALID_TRANSFORM = 8;
+  static const int INVALID_PROTOCOL = 9;
+  static const int UNSUPPORTED_CLIENT_TYPE = 10;
+}
+
+class TApplicationError extends TError {
+  static final TStruct _struct = new TStruct("TApplicationError");
+  static const int MESSAGE = 1;
+  static final TField _messageField =
+      new TField("message", TType.STRING, MESSAGE);
+  static const int TYPE = 2;
+  static final TField _typeField = new TField("type", TType.I32, TYPE);
+
+  TApplicationError(
+      [int type = TApplicationErrorType.UNKNOWN, String message = ""])
+      : super(type, message);
+
+  static TApplicationError read(TProtocol iprot) {
+    TField field;
+
+    String message = null;
+    int type = TApplicationErrorType.UNKNOWN;
+
+    iprot.readStructBegin();
+    while (true) {
+      field = iprot.readFieldBegin();
+
+      if (field.type == TType.STOP) {
+        break;
+      }
+
+      switch (field.id) {
+        case MESSAGE:
+          if (field.type == TType.STRING) {
+            message = iprot.readString();
+          } else {
+            TProtocolUtil.skip(iprot, field.type);
+          }
+          break;
+
+        case TYPE:
+          if (field.type == TType.I32) {
+            type = iprot.readI32();
+          } else {
+            TProtocolUtil.skip(iprot, field.type);
+          }
+          break;
+
+        default:
+          TProtocolUtil.skip(iprot, field.type);
+          break;
+      }
+      iprot.readFieldEnd();
+    }
+    iprot.readStructEnd();
+
+    return new TApplicationError(type, message);
+  }
+
+  write(TProtocol oprot) {
+    oprot.writeStructBegin(_struct);
+
+    if (message != null && !message.isEmpty) {
+      oprot.writeFieldBegin(_messageField);
+      oprot.writeString(message);
+      oprot.writeFieldEnd();
+    }
+
+    oprot.writeFieldBegin(_typeField);
+    oprot.writeI32(type);
+    oprot.writeFieldEnd();
+
+    oprot.writeFieldStop();
+    oprot.writeStructEnd();
+  }
+}
diff --git a/lib/dart/lib/src/t_base.dart b/lib/dart/lib/src/t_base.dart
new file mode 100644
index 0000000..d5571b6
--- /dev/null
+++ b/lib/dart/lib/src/t_base.dart
@@ -0,0 +1,37 @@
+/// 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.
+
+part of thrift;
+
+abstract class TBase {
+  /// Reads the TObject from the given input protocol.
+  void read(TProtocol iprot);
+
+  /// Writes the objects out to the [oprot] protocol.
+  void write(TProtocol oprot);
+
+  /// Check if a field is currently set or unset, using the [fieldId].
+  bool isSet(int fieldId);
+
+  /// Get a field's value by [fieldId]. Primitive types will be wrapped in the
+  /// appropriate "boxed" types.
+  getFieldValue(int fieldId);
+
+  /// Set a field's value by [fieldId]. Primitive types must be "boxed" in the
+  /// appropriate object wrapper type.
+  setFieldValue(int fieldId, Object value);
+}
diff --git a/lib/dart/lib/src/t_error.dart b/lib/dart/lib/src/t_error.dart
new file mode 100644
index 0000000..93ab732
--- /dev/null
+++ b/lib/dart/lib/src/t_error.dart
@@ -0,0 +1,27 @@
+/// 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.
+
+part of thrift;
+
+class TError extends Error {
+  final String message;
+  final int type;
+
+  TError(this.type, this.message);
+
+  String toString() => "<TError type: $type message: '$message'>";
+}
diff --git a/lib/dart/lib/src/t_processor.dart b/lib/dart/lib/src/t_processor.dart
new file mode 100644
index 0000000..dcf20fb
--- /dev/null
+++ b/lib/dart/lib/src/t_processor.dart
@@ -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.
+
+part of thrift;
+
+/// A processor is a generic object which operates upon an input stream and
+/// writes to some output stream.
+abstract class TProcessor {
+  bool process(TProtocol input, TProtocol output);
+}
diff --git a/lib/dart/lib/src/transport/t_buffered_transport.dart b/lib/dart/lib/src/transport/t_buffered_transport.dart
new file mode 100644
index 0000000..b73a30c
--- /dev/null
+++ b/lib/dart/lib/src/transport/t_buffered_transport.dart
@@ -0,0 +1,98 @@
+/// 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.
+
+part of thrift;
+
+/// Buffered implementation of [TTransport].
+class TBufferedTransport extends TTransport {
+  final List<int> _writeBuffer = [];
+  Iterator<int> _readIterator;
+
+  Uint8List consumeWriteBuffer() {
+    Uint8List buffer = new Uint8List.fromList(_writeBuffer);
+    _writeBuffer.clear();
+    return buffer;
+  }
+
+  void _setReadBuffer(Uint8List readBuffer) {
+    _readIterator = readBuffer != null ? readBuffer.iterator : null;
+  }
+
+  void _reset({bool isOpen: false}) {
+    _isOpen = isOpen;
+    _writeBuffer.clear();
+    _readIterator = null;
+  }
+
+  bool get hasReadData => _readIterator != null;
+
+  bool _isOpen;
+  bool get isOpen => _isOpen;
+
+  Future open() async {
+    _reset(isOpen: true);
+  }
+
+  Future close() async {
+    _reset(isOpen: false);
+  }
+
+  int read(Uint8List buffer, int offset, int length) {
+    if (buffer == null) {
+      throw new ArgumentError.notNull("buffer");
+    }
+
+    if (offset + length > buffer.length) {
+      throw new ArgumentError("The range exceeds the buffer length");
+    }
+
+    if (_readIterator == null || length <= 0) {
+      return 0;
+    }
+
+    int i = 0;
+    while (i < length && _readIterator.moveNext()) {
+      buffer[offset + i] = _readIterator.current;
+      i++;
+    }
+
+    // cleanup iterator when we've reached the end
+    if (_readIterator.current == null) {
+      _readIterator = null;
+    }
+
+    return i;
+  }
+
+  void write(Uint8List buffer, int offset, int length) {
+    if (buffer == null) {
+      throw new ArgumentError.notNull("buffer");
+    }
+
+    if (offset + length > buffer.length) {
+      throw new ArgumentError("The range exceeds the buffer length");
+    }
+
+    _writeBuffer.addAll(buffer.sublist(offset, offset + length));
+  }
+
+  Future flush() {
+    _readIterator = consumeWriteBuffer().iterator;
+
+    return new Future.value();
+  }
+}
diff --git a/lib/dart/lib/src/transport/t_framed_transport.dart b/lib/dart/lib/src/transport/t_framed_transport.dart
new file mode 100644
index 0000000..2ef03f7
--- /dev/null
+++ b/lib/dart/lib/src/transport/t_framed_transport.dart
@@ -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.
+
+part of thrift;
+
+/// Framed [TTransport].
+///
+/// Adapted from the Java Framed transport.
+class TFramedTransport extends TBufferedTransport {
+  static const int headerByteCount = 4;
+
+  final TTransport _transport;
+
+  final Uint8List _headerBytes = new Uint8List(headerByteCount);
+  int _receivedHeaderBytes = 0;
+
+  int _bodySize = 0;
+  Uint8List _body = null;
+  int _receivedBodyBytes = 0;
+
+  Completer<Uint8List> _frameCompleter = null;
+
+  TFramedTransport(TTransport transport) : _transport = transport {
+    if (transport == null) {
+      throw new ArgumentError.notNull("transport");
+    }
+  }
+
+  bool get isOpen => _transport.isOpen;
+
+  Future open() {
+    _reset(isOpen: true);
+    return _transport.open();
+  }
+
+  Future close() {
+    _reset(isOpen: false);
+    return _transport.close();
+  }
+
+  int read(Uint8List buffer, int offset, int length) {
+    if (hasReadData) {
+      int got = super.read(buffer, offset, length);
+      if (got > 0) return got;
+    }
+
+    // IMPORTANT: by the time you've got here,
+    // an entire frame is available for reading
+
+    return super.read(buffer, offset, length);
+  }
+
+  void _readFrame() {
+    if (_body == null) {
+      bool gotFullHeader = _readFrameHeader();
+      if (!gotFullHeader) {
+        return;
+      }
+    }
+
+    _readFrameBody();
+  }
+
+  bool _readFrameHeader() {
+    var remainingHeaderBytes = headerByteCount - _receivedHeaderBytes;
+
+    int got = _transport.read(_headerBytes, _receivedHeaderBytes, remainingHeaderBytes);
+    if (got < 0) {
+      throw new TTransportError(
+          TTransportErrorType.UNKNOWN, "Socket closed during frame header read");
+    }
+
+    _receivedHeaderBytes += got;
+
+    if (_receivedHeaderBytes == headerByteCount) {
+      int size = _headerBytes.buffer.asByteData().getUint32(0);
+
+      _receivedHeaderBytes = 0;
+
+      if (size < 0) {
+        throw new TTransportError(
+            TTransportErrorType.UNKNOWN, "Read a negative frame size: $size");
+      }
+
+      _bodySize = size;
+      _body = new Uint8List(_bodySize);
+      _receivedBodyBytes = 0;
+
+      return true;
+    } else {
+      _registerForReadableBytes();
+      return false;
+    }
+  }
+
+  void _readFrameBody() {
+    var remainingBodyBytes = _bodySize - _receivedBodyBytes;
+
+    int got = _transport.read(_body, _receivedBodyBytes, remainingBodyBytes);
+    if (got < 0) {
+      throw new TTransportError(
+          TTransportErrorType.UNKNOWN, "Socket closed during frame body read");
+    }
+
+    _receivedBodyBytes += got;
+
+    if (_receivedBodyBytes == _bodySize) {
+      var body = _body;
+
+      _bodySize = 0;
+      _body = null;
+      _receivedBodyBytes = 0;
+
+      _setReadBuffer(body);
+
+      var completer = _frameCompleter;
+      _frameCompleter = null;
+      completer.complete(new Uint8List(0));
+    } else {
+      _registerForReadableBytes();
+    }
+  }
+
+  Future flush() {
+    if (_frameCompleter == null) {
+      Uint8List buffer = consumeWriteBuffer();
+      int length = buffer.length;
+
+      _headerBytes.buffer.asByteData().setUint32(0, length);
+      _transport.write(_headerBytes, 0, headerByteCount);
+      _transport.write(buffer, 0, length);
+
+      _frameCompleter  = new Completer<Uint8List>();
+      _registerForReadableBytes();
+    }
+
+    return _frameCompleter.future;
+  }
+
+  void _registerForReadableBytes() {
+    _transport.flush().then((_) {
+      _readFrame();
+    }).catchError((e) {
+      var completer = _frameCompleter;
+
+      _receivedHeaderBytes = 0;
+      _bodySize = 0;
+      _body = null;
+      _receivedBodyBytes = 0;
+      _frameCompleter = null;
+
+      completer.completeError(e);
+    });
+  }
+}
diff --git a/lib/dart/lib/src/transport/t_http_transport.dart b/lib/dart/lib/src/transport/t_http_transport.dart
new file mode 100644
index 0000000..aa78e9c
--- /dev/null
+++ b/lib/dart/lib/src/transport/t_http_transport.dart
@@ -0,0 +1,100 @@
+/// Licensed to the Apache Software Foundation (ASF) under one
+/// or more contributor license agreements. See the NOTICE file
+/// distributed with this work for additional information
+/// regarding copyright ownership. The ASF licenses this file
+/// to you under the Apache License, Version 2.0 (the
+/// "License"); you may not use this file except in compliance
+/// with the License. You may obtain a copy of the License at
+///
+/// http://www.apache.org/licenses/LICENSE-2.0
+///
+/// Unless required by applicable law or agreed to in writing,
+/// software distributed under the License is distributed on an
+/// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+/// KIND, either express or implied. See the License for the
+/// specific language governing permissions and limitations
+/// under the License.
+
+part of thrift;
+
+/// HTTP implementation of [TTransport].
+///
+/// For example:
+///
+///     var transport = new THttpClientTransport(new BrowserClient(),
+///         new THttpConfig(url, {'X-My-Custom-Header': 'my value'}));
+///     var protocol = new TJsonProtocol(transport);
+///     var client = new MyThriftServiceClient(protocol);
+///     var result = client.myMethod();
+///
+/// Adapted from the JS XHR HTTP transport.
+class THttpClientTransport extends TBufferedTransport {
+  final Client httpClient;
+  final THttpConfig config;
+
+  THttpClientTransport(this.httpClient, this.config) {
+    if (httpClient == null) {
+      throw new ArgumentError.notNull("httpClient");
+    }
+  }
+
+  Future close() async {
+    _reset(isOpen: false);
+    httpClient.close();
+  }
+
+  Future flush() {
+    var requestBody = BASE64.encode(consumeWriteBuffer());
+
+    // Use a sync completer to ensure that the buffer can be read immediately
+    // after the read buffer is set, and avoid a race condition where another
+    // response could overwrite the read buffer.
+    var completer = new Completer.sync();
+
+    httpClient
+        .post(config.url, headers: config.headers, body: requestBody)
+        .then((response) {
+      Uint8List data;
+      try {
+        data = new Uint8List.fromList(
+            BASE64.decode(response.body));
+      } on FormatException catch (_) {
+        throw new TProtocolError(TProtocolErrorType.INVALID_DATA,
+            "Expected a Base 64 encoded string.");
+      }
+
+      _setReadBuffer(data);
+      completer.complete();
+    });
+
+    return completer.future;
+  }
+}
+
+class THttpConfig {
+  final Uri url;
+
+  Map<String, String> _headers;
+  Map<String, String> get headers => _headers;
+
+  THttpConfig(this.url, Map<String, String> headers) {
+    if (url == null || !url.hasAuthority) {
+      throw new ArgumentError("Invalid url");
+    }
+
+    _initHeaders(headers);
+  }
+
+  void _initHeaders(Map<String, String> initial) {
+    var h = {};
+
+    if (initial != null) {
+      h.addAll(initial);
+    }
+
+    h['Content-Type'] = 'application/x-thrift';
+    h['Accept'] = 'application/x-thrift';
+
+    _headers = new Map.unmodifiable(h);
+  }
+}
diff --git a/lib/dart/lib/src/transport/t_message_reader.dart b/lib/dart/lib/src/transport/t_message_reader.dart
new file mode 100644
index 0000000..8ca0708
--- /dev/null
+++ b/lib/dart/lib/src/transport/t_message_reader.dart
@@ -0,0 +1,99 @@
+/// 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.
+
+part of thrift;
+
+/// [TMessageReader] extracts a [TMessage] from bytes.  This is used to allow a
+/// transport to inspect the message seqid and map responses to requests.
+class TMessageReader {
+  final TProtocolFactory protocolFactory;
+
+  final int byteOffset;
+  final _TMessageReaderTransport _transport;
+
+  /// Construct a [MessageReader].  The optional [byteOffset] specifies the
+  /// number of bytes to skip before reading the [TMessage].
+  TMessageReader(this.protocolFactory, {int byteOffset: 0})
+      : _transport = new _TMessageReaderTransport(),
+        this.byteOffset = byteOffset;
+
+  TMessage readMessage(Uint8List bytes) {
+    _transport.reset(bytes, byteOffset);
+    TProtocol protocol = protocolFactory.getProtocol(_transport);
+    TMessage message = protocol.readMessageBegin();
+    _transport.reset(null);
+
+    return message;
+  }
+}
+
+/// An internal class used to support [TMessageReader].
+class _TMessageReaderTransport extends TTransport {
+  _TMessageReaderTransport();
+
+  Iterator<int> _readIterator;
+
+  void reset(Uint8List bytes, [int offset = 0]) {
+    if (bytes == null) {
+      _readIterator = null;
+      return;
+    }
+
+    if (offset > bytes.length) {
+      throw new ArgumentError("The offset exceeds the bytes length");
+    }
+
+    _readIterator = bytes.iterator;
+
+    for (var i = 0; i < offset; i++) {
+      _readIterator.moveNext();
+    }
+  }
+
+  get isOpen => true;
+
+  Future open() => throw new UnsupportedError("Unsupported in MessageReader");
+
+  Future close() => throw new UnsupportedError("Unsupported in MessageReader");
+
+  int read(Uint8List buffer, int offset, int length) {
+    if (buffer == null) {
+      throw new ArgumentError.notNull("buffer");
+    }
+
+    if (offset + length > buffer.length) {
+      throw new ArgumentError("The range exceeds the buffer length");
+    }
+
+    if (_readIterator == null || length <= 0) {
+      return 0;
+    }
+
+    int i = 0;
+    while (i < length && _readIterator.moveNext()) {
+      buffer[offset + i] = _readIterator.current;
+      i++;
+    }
+
+    return i;
+  }
+
+  void write(Uint8List buffer, int offset, int length) =>
+      throw new UnsupportedError("Unsupported in MessageReader");
+
+  Future flush() => throw new UnsupportedError("Unsupported in MessageReader");
+}
diff --git a/lib/dart/lib/src/transport/t_socket.dart b/lib/dart/lib/src/transport/t_socket.dart
new file mode 100644
index 0000000..b2eb6b6
--- /dev/null
+++ b/lib/dart/lib/src/transport/t_socket.dart
@@ -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.
+
+part of thrift;
+
+enum TSocketState { CLOSED, OPEN }
+
+abstract class TSocket {
+  Stream<TSocketState> get onState;
+
+  Stream<Object> get onError;
+
+  Stream<Uint8List> get onMessage;
+
+  bool get isOpen;
+
+  bool get isClosed;
+
+  Future open();
+
+  Future close();
+
+  void send(Uint8List data);
+}
diff --git a/lib/dart/lib/src/transport/t_socket_transport.dart b/lib/dart/lib/src/transport/t_socket_transport.dart
new file mode 100644
index 0000000..c41374a
--- /dev/null
+++ b/lib/dart/lib/src/transport/t_socket_transport.dart
@@ -0,0 +1,177 @@
+/// 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.
+
+part of thrift;
+
+/// Socket implementation of [TTransport].
+///
+/// For example:
+///
+///     var transport = new TClientSocketTransport(new TWebSocket(url));
+///     var protocol = new TBinaryProtocol(transport);
+///     var client = new MyThriftServiceClient(protocol);
+///     var result = client.myMethod();
+///
+/// Adapted from the JS WebSocket transport.
+abstract class TSocketTransport extends TBufferedTransport {
+  final Logger logger = new Logger('thrift.TSocketTransport');
+
+  final TSocket socket;
+
+  /// A transport using the provided [socket].
+  TSocketTransport(this.socket) {
+    if (socket == null) {
+      throw new ArgumentError.notNull('socket');
+    }
+
+    socket.onError.listen((e) => logger.warning(e));
+    socket.onMessage.listen(handleIncomingMessage);
+  }
+
+  bool get isOpen => socket.isOpen;
+
+  Future open() {
+    _reset(isOpen: true);
+    return socket.open();
+  }
+
+  Future close() {
+    _reset(isOpen: false);
+    return socket.close();
+  }
+
+  /// Make an incoming message available to read from the transport.
+  void handleIncomingMessage(Uint8List messageBytes) {
+    _setReadBuffer(messageBytes);
+  }
+}
+
+/// [TClientSocketTransport] is a basic client socket transport.  It sends
+/// outgoing messages and expects a response.
+///
+/// NOTE: This transport expects a single threaded server, as it will process
+/// responses in FIFO order.
+class TClientSocketTransport extends TSocketTransport {
+  final List<Completer<Uint8List>> _completers = [];
+
+  TClientSocketTransport(TSocket socket) : super(socket);
+
+  Future flush() {
+    Uint8List bytes = consumeWriteBuffer();
+
+    // Use a sync completer to ensure that the buffer can be read immediately
+    // after the read buffer is set, and avoid a race condition where another
+    // response could overwrite the read buffer.
+    var completer = new Completer<Uint8List>.sync();
+    _completers.add(completer);
+
+    if (bytes.lengthInBytes > 0) {
+      socket.send(bytes);
+    }
+
+    return completer.future;
+  }
+
+  void handleIncomingMessage(Uint8List messageBytes) {
+    super.handleIncomingMessage(messageBytes);
+
+    if (_completers.isNotEmpty) {
+      var completer = _completers.removeAt(0);
+      completer.complete();
+    }
+  }
+}
+
+/// [TAsyncClientSocketTransport] sends outgoing messages and expects an
+/// asynchronous response.
+///
+/// NOTE: This transport uses a [MessageReader] to read a [TMessage] when an
+/// incoming message arrives to correlate a response to a request, using the
+/// seqid.
+class TAsyncClientSocketTransport extends TSocketTransport {
+  static const defaultTimeout = const Duration(seconds: 30);
+
+  final Map<int, Completer<Uint8List>> _completers = {};
+
+  final TMessageReader messageReader;
+
+  final Duration responseTimeout;
+
+  TAsyncClientSocketTransport(TSocket socket, TMessageReader messageReader,
+      {Duration responseTimeout: defaultTimeout})
+      : this.messageReader = messageReader,
+        this.responseTimeout = responseTimeout,
+        super(socket);
+
+  Future flush() {
+    Uint8List bytes = consumeWriteBuffer();
+    TMessage message = messageReader.readMessage(bytes);
+    int seqid = message.seqid;
+
+    // Use a sync completer to ensure that the buffer can be read immediately
+    // after the read buffer is set, and avoid a race condition where another
+    // response could overwrite the read buffer.
+    var completer = new Completer<Uint8List>.sync();
+    _completers[seqid] = completer;
+
+    if (responseTimeout != null) {
+      new Future.delayed(responseTimeout, () {
+        var completer = _completers.remove(seqid);
+        if (completer != null) {
+          completer.completeError(
+              new TimeoutException("Response timed out.", responseTimeout));
+        }
+      });
+    }
+
+    socket.send(bytes);
+
+    return completer.future;
+  }
+
+  void handleIncomingMessage(Uint8List messageBytes) {
+    super.handleIncomingMessage(messageBytes);
+
+    TMessage message = messageReader.readMessage(messageBytes);
+    var completer = _completers.remove(message.seqid);
+    if (completer != null) {
+      completer.complete();
+    }
+  }
+}
+
+/// [TServerSocketTransport] listens for incoming messages.  When it sends a
+/// response, it does not expect an acknowledgement.
+class TServerSocketTransport extends TSocketTransport {
+  final StreamController _onIncomingMessageController;
+  Stream get onIncomingMessage => _onIncomingMessageController.stream;
+
+  TServerSocketTransport(TSocket socket)
+      : _onIncomingMessageController = new StreamController.broadcast(),
+        super(socket);
+
+  Future flush() async {
+    Uint8List message = consumeWriteBuffer();
+    socket.send(message);
+  }
+
+  void handleIncomingMessage(Uint8List messageBytes) {
+    super.handleIncomingMessage(messageBytes);
+
+    _onIncomingMessageController.add(null);
+  }
+}
diff --git a/lib/dart/lib/src/transport/t_transport.dart b/lib/dart/lib/src/transport/t_transport.dart
new file mode 100644
index 0000000..563d5eb
--- /dev/null
+++ b/lib/dart/lib/src/transport/t_transport.dart
@@ -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.
+
+part of thrift;
+
+abstract class TTransport {
+  /// Queries whether the transport is open.
+  /// Returns [true] if the transport is open.
+  bool get isOpen;
+
+  /// Opens the transport for reading/writing.
+  /// Throws [TTransportError] if the transport could not be opened.
+  Future open();
+
+  /// Closes the transport.
+  Future close();
+
+  /// Reads up to [length] bytes into [buffer], starting at [offset].
+  /// Returns the number of bytes actually read.
+  /// Throws [TTransportError] if there was an error reading data
+  int read(Uint8List buffer, int offset, int length);
+
+  /// Guarantees that all of [length] bytes are actually read off the transport.
+  /// Returns the number of bytes actually read, which must be equal to
+  /// [length].
+  /// Throws [TTransportError] if there was an error reading data
+  int readAll(Uint8List buffer, int offset, int length) {
+    int got = 0;
+    int ret = 0;
+    while (got < length) {
+      ret = read(buffer, offset + got, length - got);
+      if (ret <= 0) {
+        throw new TTransportError(
+            TTransportErrorType.UNKNOWN,
+            "Cannot read. Remote side has closed. Tried to read $length "
+            "bytes, but only got $got bytes.");
+      }
+      got += ret;
+    }
+    return got;
+  }
+
+  /// Writes up to [len] bytes from the buffer.
+  /// Throws [TTransportError] if there was an error writing data
+  void write(Uint8List buffer, int offset, int length);
+
+  /// Writes the [bytes] to the output.
+  /// Throws [TTransportError] if there was an error writing data
+  void writeAll(Uint8List buffer) {
+    write(buffer, 0, buffer.length);
+  }
+
+  /// Flush any pending data out of a transport buffer.
+  /// Throws [TTransportError] if there was an error writing out data.
+  Future flush();
+}
diff --git a/lib/dart/lib/src/transport/t_transport_error.dart b/lib/dart/lib/src/transport/t_transport_error.dart
new file mode 100644
index 0000000..d3508e0
--- /dev/null
+++ b/lib/dart/lib/src/transport/t_transport_error.dart
@@ -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.
+
+part of thrift;
+
+class TTransportErrorType {
+  static const int UNKNOWN = 0;
+  static const int NOT_OPEN = 1;
+  static const int ALREADY_OPEN = 2;
+  static const int TIMED_OUT = 3;
+  static const int END_OF_FILE = 4;
+}
+
+class TTransportError extends TError {
+  TTransportError([int type = TTransportErrorType.UNKNOWN, String message = ""])
+      : super(type, message);
+}
diff --git a/lib/dart/lib/src/transport/t_transport_factory.dart b/lib/dart/lib/src/transport/t_transport_factory.dart
new file mode 100644
index 0000000..7a10461
--- /dev/null
+++ b/lib/dart/lib/src/transport/t_transport_factory.dart
@@ -0,0 +1,27 @@
+/// 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.
+
+part of thrift;
+
+/// Factory class used to create wrapped instance of a [TTransport]. This is
+/// used primarily in servers.
+///
+/// Adapted from the Java version.
+class TTransportFactory {
+  Future<TTransport> getTransport(TTransport transport) =>
+      new Future.value(transport);
+}
diff --git a/lib/dart/lib/thrift.dart b/lib/dart/lib/thrift.dart
new file mode 100644
index 0000000..3d9bb01
--- /dev/null
+++ b/lib/dart/lib/thrift.dart
@@ -0,0 +1,64 @@
+/// 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.
+
+library thrift;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:convert' show Utf8Codec, BASE64;
+import 'dart:typed_data' show ByteData;
+import 'dart:typed_data' show Endianness;
+import 'dart:typed_data' show Uint8List;
+
+import 'package:fixnum/fixnum.dart';
+import 'package:http/http.dart' show Client;
+import 'package:logging/logging.dart';
+
+part 'src/t_application_error.dart';
+part 'src/t_base.dart';
+part 'src/t_error.dart';
+part 'src/t_processor.dart';
+
+part 'src/protocol/t_binary_protocol.dart';
+part 'src/protocol/t_compact_protocol.dart';
+part 'src/protocol/t_field.dart';
+part 'src/protocol/t_json_protocol.dart';
+part 'src/protocol/t_list.dart';
+part 'src/protocol/t_map.dart';
+part 'src/protocol/t_message.dart';
+part 'src/protocol/t_multiplexed_protocol.dart';
+part 'src/protocol/t_protocol.dart';
+part 'src/protocol/t_protocol_decorator.dart';
+part 'src/protocol/t_protocol_error.dart';
+part 'src/protocol/t_protocol_factory.dart';
+part 'src/protocol/t_protocol_util.dart';
+part 'src/protocol/t_set.dart';
+part 'src/protocol/t_struct.dart';
+part 'src/protocol/t_type.dart';
+
+part 'src/serializer/t_deserializer.dart';
+part 'src/serializer/t_serializer.dart';
+
+part 'src/transport/t_buffered_transport.dart';
+part 'src/transport/t_framed_transport.dart';
+part 'src/transport/t_http_transport.dart';
+part 'src/transport/t_message_reader.dart';
+part 'src/transport/t_socket.dart';
+part 'src/transport/t_transport.dart';
+part 'src/transport/t_transport_error.dart';
+part 'src/transport/t_transport_factory.dart';
+part 'src/transport/t_socket_transport.dart';
diff --git a/lib/dart/lib/thrift_browser.dart b/lib/dart/lib/thrift_browser.dart
new file mode 100644
index 0000000..2ebc257
--- /dev/null
+++ b/lib/dart/lib/thrift_browser.dart
@@ -0,0 +1,22 @@
+/// 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.
+
+library thrift_browser;
+
+/// Classes that are only supported in browser applications go here
+
+export 'src/browser/t_web_socket.dart' show TWebSocket;
diff --git a/lib/dart/lib/thrift_console.dart b/lib/dart/lib/thrift_console.dart
new file mode 100644
index 0000000..48a83d1
--- /dev/null
+++ b/lib/dart/lib/thrift_console.dart
@@ -0,0 +1,23 @@
+/// 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.
+
+library thrift_console;
+
+/// Classes that are only supported in console applications go here
+
+export 'src/console/t_tcp_socket.dart' show TTcpSocket;
+export 'src/console/t_web_socket.dart' show TWebSocket;
diff --git a/lib/dart/pubspec.yaml b/lib/dart/pubspec.yaml
new file mode 100644
index 0000000..fdc4a0d
--- /dev/null
+++ b/lib/dart/pubspec.yaml
@@ -0,0 +1,43 @@
+# 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.
+
+name: thrift
+version: 1.0.0
+description: >
+  A Dart library for Apache Thrift
+author: Apache Thrift Developers <dev@thrift.apache.org>
+homepage: http://thrift.apache.org
+documentation: http://thrift.apache.org
+
+environment:
+  sdk: ">=1.13.0 <2.0.0"
+
+dependencies:
+  fixnum: ^0.10.2
+  http: ^0.11.3
+  logging: ^0.11.0
+
+dev_dependencies:
+  # test
+  mockito: ^1.0.0
+  test: ^0.12.0
+
+  # dart_dev - https://github.com/Workiva/dart_dev
+  dart_dev: ^1.5.0
+  coverage: ^0.7.3
+  dart_style: ">=0.2.4 <0.3.0"
+  dartdoc: ^0.9.0
diff --git a/lib/dart/test/protocol/t_protocol_test.dart b/lib/dart/test/protocol/t_protocol_test.dart
new file mode 100644
index 0000000..0e6cde5
--- /dev/null
+++ b/lib/dart/test/protocol/t_protocol_test.dart
@@ -0,0 +1,406 @@
+// 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.
+
+library thrift.test.transport.t_json_protocol_test;
+
+import 'dart:async';
+import 'dart:convert' show UTF8;
+import 'dart:typed_data' show Uint8List;
+
+import 'package:test/test.dart';
+import 'package:thrift/thrift.dart';
+
+void main() {
+  final message = new TMessage('my message', TMessageType.ONEWAY, 123);
+
+  TProtocol protocol;
+
+  Primitive getPrimitive(int tType) {
+    switch (tType) {
+      case TType.BOOL:
+        return new Primitive(protocol.readBool, protocol.writeBool, false);
+
+      case TType.BYTE:
+        return new Primitive(protocol.readByte, protocol.writeByte, 0);
+
+      case TType.I16:
+        return new Primitive(protocol.readI16, protocol.writeI16, 0);
+
+      case TType.I32:
+        return new Primitive(protocol.readI32, protocol.writeI32, 0);
+
+      case TType.I64:
+        return new Primitive(protocol.readI64, protocol.writeI64, 0);
+
+      case TType.DOUBLE:
+        return new Primitive(protocol.readDouble, protocol.writeDouble, 0);
+
+      case TType.STRING:
+        return new Primitive(protocol.readString, protocol.writeString, '');
+
+      default:
+        throw new UnsupportedError("Unsupported TType $tType");
+    }
+  }
+
+  Future primitiveTest(Primitive primitive, input) async {
+    primitive.write(input);
+    protocol.writeMessageEnd();
+
+    await protocol.transport.flush();
+
+    protocol.readMessageBegin();
+    var output = primitive.read();
+
+    expect(output, input);
+  }
+
+  Future primitiveNullTest(Primitive primitive) async {
+    primitive.write(null);
+    protocol.writeMessageEnd();
+
+    await protocol.transport.flush();
+
+    protocol.readMessageBegin();
+    var output = primitive.read();
+
+    expect(output, primitive.defaultValue);
+  }
+
+  var sharedTests = () {
+    test('Test message', () async {
+      protocol.writeMessageEnd();
+
+      await protocol.transport.flush();
+
+      var subject = protocol.readMessageBegin();
+
+      expect(subject.name, message.name);
+      expect(subject.type, message.type);
+      expect(subject.seqid, message.seqid);
+    });
+
+    test('Test struct', () async {
+      var input = new TStruct();
+
+      protocol.writeStructBegin(input);
+      protocol.writeStructEnd();
+      protocol.writeMessageEnd();
+
+      await protocol.transport.flush();
+
+      protocol.readMessageBegin();
+      var output = protocol.readStructBegin();
+
+      // name is not serialized, see C# version for reference
+      expect(output, isNotNull);
+    });
+
+    test('Test field', () async {
+      var input = new TField('my field', TType.MAP, 123);
+
+      protocol.writeFieldBegin(input);
+      protocol.writeFieldEnd();
+      protocol.writeMessageEnd();
+
+      await protocol.transport.flush();
+
+      protocol.readMessageBegin();
+      var output = protocol.readFieldBegin();
+
+      // name is not serialized, see C# version for reference
+      expect(output.type, input.type);
+      expect(output.id, input.id);
+    });
+
+    test('Test map', () async {
+      var input = new TMap(TType.STRING, TType.STRUCT, 123);
+
+      protocol.writeMapBegin(input);
+      protocol.writeMapEnd();
+      protocol.writeMessageEnd();
+
+      await protocol.transport.flush();
+
+      protocol.readMessageBegin();
+      var output = protocol.readMapBegin();
+
+      expect(output.keyType, input.keyType);
+      expect(output.valueType, input.valueType);
+      expect(output.length, input.length);
+    });
+
+    test('Test list', () async {
+      var input = new TList(TType.STRING, 123);
+
+      protocol.writeListBegin(input);
+      protocol.writeListEnd();
+      protocol.writeMessageEnd();
+
+      await protocol.transport.flush();
+
+      protocol.readMessageBegin();
+      var output = protocol.readListBegin();
+
+      expect(output.elementType, input.elementType);
+      expect(output.length, input.length);
+    });
+
+    test('Test set', () async {
+      var input = new TSet(TType.STRING, 123);
+
+      protocol.writeSetBegin(input);
+      protocol.writeSetEnd();
+      protocol.writeMessageEnd();
+
+      await protocol.transport.flush();
+
+      protocol.readMessageBegin();
+      var output = protocol.readListBegin();
+
+      expect(output.elementType, input.elementType);
+      expect(output.length, input.length);
+    });
+
+    test('Test bool', () async {
+      await primitiveTest(getPrimitive(TType.BOOL), true);
+    });
+
+    test('Test bool null', () async {
+      await primitiveNullTest(getPrimitive(TType.BOOL));
+    });
+
+    test('Test byte', () async {
+      await primitiveTest(getPrimitive(TType.BYTE), 64);
+    });
+
+    test('Test byte null', () async {
+      await primitiveNullTest(getPrimitive(TType.BYTE));
+    });
+
+    test('Test I16', () async {
+      await primitiveTest(getPrimitive(TType.I16), 32767);
+    });
+
+    test('Test I16 null', () async {
+      await primitiveNullTest(getPrimitive(TType.I16));
+    });
+
+    test('Test I32', () async {
+      await primitiveTest(getPrimitive(TType.I32), 2147483647);
+    });
+
+    test('Test I32 null', () async {
+      await primitiveNullTest(getPrimitive(TType.I32));
+    });
+
+    test('Test I64', () async {
+      await primitiveTest(getPrimitive(TType.I64), 9223372036854775807);
+    });
+
+    test('Test I64 null', () async {
+      await primitiveNullTest(getPrimitive(TType.I64));
+    });
+
+    test('Test double', () async {
+      await primitiveTest(getPrimitive(TType.DOUBLE), 3.1415926);
+    });
+
+    test('Test double null', () async {
+      await primitiveNullTest(getPrimitive(TType.DOUBLE));
+    });
+
+    test('Test string', () async {
+      var input = 'There are only two hard things in computer science: '
+          'cache invalidation, naming things, and off-by-one errors.';
+      await primitiveTest(getPrimitive(TType.STRING), input);
+    });
+
+    test('Test string null', () async {
+      await primitiveNullTest(getPrimitive(TType.STRING));
+    });
+
+    test('Test binary', () async {
+      var input = new Uint8List.fromList(new List.filled(100, 123));
+
+      protocol.writeBinary(input);
+      protocol.writeMessageEnd();
+
+      await protocol.transport.flush();
+
+      protocol.readMessageBegin();
+      var output = protocol.readBinary();
+
+      expect(output.length, input.length);
+      expect(output.every((i) => i == 123), isTrue);
+    });
+
+    test('Test complex struct', () async {
+      // {1: {10: 20}, 2: {30: 40}}
+      protocol.writeStructBegin(new TStruct());
+      protocol.writeFieldBegin(new TField('success', TType.MAP, 0));
+      protocol.writeMapBegin(new TMap(TType.I32, TType.MAP, 2));
+
+      protocol.writeI32(1); // key
+      protocol.writeMapBegin(new TMap(TType.I32, TType.I32, 1));
+      protocol.writeI32(10); // key
+      protocol.writeI32(20); // value
+      protocol.writeMapEnd();
+
+      protocol.writeI32(2); // key
+      protocol.writeMapBegin(new TMap(TType.I32, TType.I32, 1));
+      protocol.writeI32(30); // key
+      protocol.writeI32(40); // value
+      protocol.writeMapEnd();
+
+      protocol.writeMapEnd();
+      protocol.writeFieldEnd();
+      protocol.writeFieldStop();
+      protocol.writeStructEnd();
+      protocol.writeMessageEnd();
+
+      await protocol.transport.flush();
+
+      protocol.readMessageBegin();
+      protocol.readStructBegin();
+      expect(protocol.readFieldBegin().type, TType.MAP);
+      expect(protocol.readMapBegin().length, 2);
+
+      expect(protocol.readI32(), 1); // key
+      expect(protocol.readMapBegin().length, 1);
+      expect(protocol.readI32(), 10); // key
+      expect(protocol.readI32(), 20); // value
+      protocol.readMapEnd();
+
+      expect(protocol.readI32(), 2); // key
+      expect(protocol.readMapBegin().length, 1);
+      expect(protocol.readI32(), 30); // key
+      expect(protocol.readI32(), 40); // value
+      protocol.readMapEnd();
+
+      protocol.readMapEnd();
+      protocol.readFieldEnd();
+      protocol.readStructEnd();
+      protocol.readMessageEnd();
+    });
+
+    test('Test nested maps and lists', () async {
+      // {1: [{10: 20}], 2: [{30: 40}]}
+      protocol.writeMapBegin(new TMap(TType.I32, TType.LIST, 2));
+
+      protocol.writeI32(1); // key
+      protocol.writeListBegin(new TList(TType.MAP, 1));
+      protocol.writeMapBegin(new TMap(TType.I32, TType.I32, 1));
+      protocol.writeI32(10); // key
+      protocol.writeI32(20); // value
+      protocol.writeMapEnd();
+      protocol.writeListEnd();
+
+      protocol.writeI32(2); // key
+      protocol.writeListBegin(new TList(TType.MAP, 1));
+      protocol.writeMapBegin(new TMap(TType.I32, TType.I32, 1));
+      protocol.writeI32(30); // key
+      protocol.writeI32(40); // value
+      protocol.writeMapEnd();
+      protocol.writeListEnd();
+
+      protocol.writeMapEnd();
+      protocol.writeMessageEnd();
+
+      await protocol.transport.flush();
+
+      protocol.readMessageBegin();
+      expect(protocol.readMapBegin().length, 2);
+
+      expect(protocol.readI32(), 1); // key
+      expect(protocol.readListBegin().length, 1);
+      expect(protocol.readMapBegin().length, 1);
+      expect(protocol.readI32(), 10); // key
+      expect(protocol.readI32(), 20); // value
+      protocol.readMapEnd();
+      protocol.readListEnd();
+
+      expect(protocol.readI32(), 2); // key
+      expect(protocol.readListBegin().length, 1);
+      expect(protocol.readMapBegin().length, 1);
+      expect(protocol.readI32(), 30); // key
+      expect(protocol.readI32(), 40); // value
+      protocol.readMapEnd();
+      protocol.readListEnd();
+
+      protocol.readMapEnd();
+      protocol.readMessageEnd();
+    });
+  };
+
+  group('JSON', () {
+    setUp(() {
+      protocol = new TJsonProtocol(new TBufferedTransport());
+      protocol.writeMessageBegin(message);
+    });
+
+    test('Test escaped unicode', () async {
+      /*
+         KOR_KAI
+           UTF-8:  0xE0 0xB8 0x81
+           UTF-16: 0x0E01
+         G clef:
+           UTF-8:  0xF0 0x9D 0x84 0x9E
+           UTF-16: 0xD834 0xDD1E
+       */
+      var buffer = UTF8.encode(r'"\u0001\u0e01 \ud834\udd1e"');
+      var transport = new TBufferedTransport();
+      transport.writeAll(buffer);
+
+      var protocol = new TJsonProtocol(transport);
+
+      await protocol.transport.flush();
+
+      var subject = protocol.readString();
+      expect(subject,
+          UTF8.decode([0x01, 0xE0, 0xB8, 0x81, 0x20, 0xF0, 0x9D, 0x84, 0x9E]));
+    });
+
+    group('shared tests', sharedTests);
+  });
+
+  group('binary', () {
+    setUp(() {
+      protocol = new TBinaryProtocol(new TBufferedTransport());
+      protocol.writeMessageBegin(message);
+    });
+
+    group('shared tests', sharedTests);
+  });
+
+  group('compact', () {
+    setUp(() {
+      protocol = new TCompactProtocol(new TBufferedTransport());
+      protocol.writeMessageBegin(message);
+    });
+
+    group('shared tests', sharedTests);
+  });
+}
+
+class Primitive {
+  final Function read;
+  final Function write;
+  final defaultValue;
+
+  Primitive(this.read, this.write, this.defaultValue);
+}
diff --git a/lib/dart/test/serializer/serializer_test.dart b/lib/dart/test/serializer/serializer_test.dart
new file mode 100644
index 0000000..2f76503
--- /dev/null
+++ b/lib/dart/test/serializer/serializer_test.dart
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+library thrift.test.serializer.serializer_test;
+
+import 'package:test/test.dart';
+import 'package:thrift/thrift.dart';
+import 'serializer_test_data.dart';
+
+void main() {
+  var serializer = () {
+    TDeserializer deserializer;
+    TSerializer serializer;
+    TestTObject testTObject;
+
+    setUp(() {
+      serializer = new TSerializer();
+      deserializer = new TDeserializer();
+      
+      testTObject = new TestTObject();
+      testTObject.b = true;
+      testTObject.s = "TEST";
+      testTObject.d = 15.25;
+      testTObject.i = 10;
+      
+      var testList = new List<String>();
+      testList.add("TEST 1");
+      testList.add("TEST 2");
+      
+      testTObject.l = testList;
+    });
+    
+    assertNewObjectEqualsTObject(TestTObject newObject) {
+      expect(newObject.l, equals(testTObject.l));
+      expect(newObject.b, equals(testTObject.b));
+      expect(newObject.i, equals(testTObject.i));
+      expect(newObject.d, equals(testTObject.d));
+      expect(newObject.s, equals(testTObject.s));
+    }
+    
+    runWriteStringTest() {
+      var s = serializer.writeString(testTObject);
+
+      var newObject = new TestTObject();
+      deserializer.readString(newObject, s);
+
+      assertNewObjectEqualsTObject(newObject);
+    };
+
+    runWriteTest() {
+      var s = serializer.write(testTObject);
+
+      var newObject = new TestTObject();
+      deserializer.read(newObject, s);
+
+      assertNewObjectEqualsTObject(newObject);
+    };
+
+    test('JSON Protocol String', () {
+      serializer.protocol = new TJsonProtocol(serializer.transport);
+      deserializer.protocol = new TJsonProtocol(deserializer.transport);
+      
+      runWriteStringTest();
+    });
+
+    test('JSON Protocol', () {
+      serializer.protocol = new TJsonProtocol(serializer.transport);
+      deserializer.protocol = new TJsonProtocol(deserializer.transport);
+
+      runWriteTest();
+    });
+
+    test('Binary Protocol String', () {
+      serializer.protocol = new TBinaryProtocol(serializer.transport);
+      deserializer.protocol = new TBinaryProtocol(deserializer.transport);
+
+      runWriteStringTest();
+    });
+
+    test('Binary Protocol', () {
+      serializer.protocol = new TBinaryProtocol(serializer.transport);
+      deserializer.protocol = new TBinaryProtocol(deserializer.transport);
+
+      runWriteTest();
+    });
+
+    test('Compact Protocol String', () {
+      serializer.protocol = new TCompactProtocol(serializer.transport);
+      deserializer.protocol = new TCompactProtocol(deserializer.transport);
+
+      runWriteStringTest();
+    });
+
+    test('Compact Protocol', () {
+      serializer.protocol = new TCompactProtocol(serializer.transport);
+      deserializer.protocol = new TCompactProtocol(deserializer.transport);
+
+      runWriteTest();
+    });
+  };
+
+  group('Serializer', serializer);
+}
diff --git a/lib/dart/test/serializer/serializer_test_data.dart b/lib/dart/test/serializer/serializer_test_data.dart
new file mode 100644
index 0000000..3586f08
--- /dev/null
+++ b/lib/dart/test/serializer/serializer_test_data.dart
@@ -0,0 +1,342 @@
+/*
+ * 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.
+ */
+
+library thrift.test.serializer.serializer_test;
+
+import 'package:thrift/thrift.dart';
+
+/// TestTObject is a simple test struct
+class TestTObject implements TBase {
+  static final TStruct _STRUCT_DESC = new TStruct("TestTObject");
+  static final TField _I_FIELD_DESC = new TField("i", TType.I32, 1);
+  static final TField _D_FIELD_DESC = new TField("d", TType.DOUBLE, 2);
+  static final TField _S_FIELD_DESC = new TField("s", TType.STRING, 3);
+  static final TField _L_FIELD_DESC = new TField("l", TType.LIST, 4);
+  static final TField _B_FIELD_DESC = new TField("b", TType.BOOL, 5);
+
+  int _i;
+  static const int I = 1;
+  double _d;
+  static const int D = 2;
+  String _s;
+  static const int S = 3;
+  List<String> _l;
+  static const int L = 4;
+  bool _b;
+  static const int B = 5;
+
+  bool __isset_i = false;
+  bool __isset_d = false;
+  bool __isset_b = false;
+
+  TestTObject() {
+  }
+
+  // i
+  int get i => this._i;
+
+  set i(int i) {
+    this._i = i;
+    this.__isset_i = true;
+  }
+
+  bool isSetI() => this.__isset_i;
+
+  unsetI() {
+    this.__isset_i = false;
+  }
+
+  // d
+  double get d => this._d;
+
+  set d(double d) {
+    this._d = d;
+    this.__isset_d = true;
+  }
+
+  bool isSetD() => this.__isset_d;
+
+  unsetD() {
+    this.__isset_d = false;
+  }
+
+  // s
+  String get s => this._s;
+
+  set s(String s) {
+    this._s = s;
+  }
+
+  bool isSetS() => this.s != null;
+
+  unsetS() {
+    this.s = null;
+  }
+
+  // l
+  List<String> get l => this._l;
+
+  set l(List<String> l) {
+    this._l = l;
+  }
+
+  bool isSetL() => this.l != null;
+
+  unsetL() {
+    this.l = null;
+  }
+
+  // b
+  bool get b => this._b;
+
+  set b(bool b) {
+    this._b = b;
+    this.__isset_b = true;
+  }
+
+  bool isSetB() => this.__isset_b;
+
+  unsetB() {
+    this.__isset_b = false;
+  }
+
+  getFieldValue(int fieldID) {
+    switch (fieldID) {
+      case I:
+        return this.i;
+      case D:
+        return this.d;
+      case S:
+        return this.s;
+      case L:
+        return this.l;
+      case B:
+        return this.b;
+      default:
+        throw new ArgumentError("Field $fieldID doesn't exist!");
+    }
+  }
+
+  setFieldValue(int fieldID, Object value) {
+    switch (fieldID) {
+      case I:
+        if (value == null) {
+          unsetI();
+        } else {
+          this.i = value;
+        }
+        break;
+
+      case D:
+        if (value == null) {
+          unsetD();
+        } else {
+          this.d = value;
+        }
+        break;
+
+      case S:
+        if (value == null) {
+          unsetS();
+        } else {
+          this.s = value;
+        }
+        break;
+
+      case L:
+        if (value == null) {
+          unsetL();
+        } else {
+          this.l = value as List<String>;
+        }
+        break;
+
+      case B:
+        if (value == null) {
+          unsetB();
+        } else {
+          this.b = value;
+        }
+        break;
+
+      default:
+        throw new ArgumentError("Field $fieldID doesn't exist!");
+    }
+  }
+
+  // Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise
+  bool isSet(int fieldID) {
+    switch (fieldID) {
+      case I:
+        return isSetI();
+      case D:
+        return isSetD();
+      case S:
+        return isSetS();
+      case L:
+        return isSetL();
+      case B:
+        return isSetB();
+      default:
+        throw new ArgumentError("Field $fieldID doesn't exist!");
+    }
+  }
+
+  read(TProtocol iprot) {
+    TField field;
+    iprot.readStructBegin();
+    while (true) {
+      field = iprot.readFieldBegin();
+      if (field.type == TType.STOP) {
+        break;
+      }
+      switch (field.id) {
+        case I:
+          if (field.type == TType.I32) {
+            this.i = iprot.readI32();
+            this.__isset_i = true;
+          } else {
+            TProtocolUtil.skip(iprot, field.type);
+          }
+          break;
+        case D:
+          if (field.type == TType.DOUBLE) {
+            this.d = iprot.readDouble();
+            this.__isset_d = true;
+          } else {
+            TProtocolUtil.skip(iprot, field.type);
+          }
+          break;
+        case S:
+          if (field.type == TType.STRING) {
+            this.s = iprot.readString();
+          } else {
+            TProtocolUtil.skip(iprot, field.type);
+          }
+          break;
+        case L:
+          if (field.type == TType.LIST) {
+            {
+              TList _list74 = iprot.readListBegin();
+              this.l = new List<String>();
+              for (int _i75 = 0; _i75 < _list74.length; ++_i75) {
+                String _elem76;
+                _elem76 = iprot.readString();
+                this.l.add(_elem76);
+              }
+              iprot.readListEnd();
+            }
+          } else {
+            TProtocolUtil.skip(iprot, field.type);
+          }
+          break;
+        case B:
+          if (field.type == TType.BOOL) {
+            this.b = iprot.readBool();
+            this.__isset_b = true;
+          } else {
+            TProtocolUtil.skip(iprot, field.type);
+          }
+          break;
+        default:
+          TProtocolUtil.skip(iprot, field.type);
+          break;
+      }
+      iprot.readFieldEnd();
+    }
+    iprot.readStructEnd();
+
+    // check for required fields of primitive type, which can't be checked in the validate method
+    validate();
+  }
+
+  write(TProtocol oprot) {
+    validate();
+
+    oprot.writeStructBegin(_STRUCT_DESC);
+    oprot.writeFieldBegin(_I_FIELD_DESC);
+    oprot.writeI32(this.i);
+    oprot.writeFieldEnd();
+    oprot.writeFieldBegin(_D_FIELD_DESC);
+    oprot.writeDouble(this.d);
+    oprot.writeFieldEnd();
+    if (this.s != null) {
+      oprot.writeFieldBegin(_S_FIELD_DESC);
+      oprot.writeString(this.s);
+      oprot.writeFieldEnd();
+    }
+    if (this.l != null) {
+      oprot.writeFieldBegin(_L_FIELD_DESC);
+      {
+        oprot.writeListBegin(new TList(TType.STRING, this.l.length));
+        for (var elem77 in this.l) {
+          oprot.writeString(elem77);
+        }
+        oprot.writeListEnd();
+      }
+      oprot.writeFieldEnd();
+    }
+    oprot.writeFieldBegin(_B_FIELD_DESC);
+    oprot.writeBool(this.b);
+    oprot.writeFieldEnd();
+    oprot.writeFieldStop();
+    oprot.writeStructEnd();
+  }
+
+  String toString() {
+    StringBuffer ret = new StringBuffer("TestTObject(");
+
+    ret.write("i:");
+    ret.write(this.i);
+
+    ret.write(", ");
+    ret.write("d:");
+    ret.write(this.d);
+
+    ret.write(", ");
+    ret.write("s:");
+    if (this.s == null) {
+      ret.write("null");
+    } else {
+      ret.write(this.s);
+    }
+
+    ret.write(", ");
+    ret.write("l:");
+    if (this.l == null) {
+      ret.write("null");
+    } else {
+      ret.write(this.l);
+    }
+
+    ret.write(", ");
+    ret.write("b:");
+    ret.write(this.b);
+
+    ret.write(")");
+
+    return ret.toString();
+  }
+
+  validate() {
+    // check for required fields
+    // check that fields of type enum have valid values
+  }
+
+}
diff --git a/lib/dart/test/t_application_error_test.dart b/lib/dart/test/t_application_error_test.dart
new file mode 100644
index 0000000..511d8d6
--- /dev/null
+++ b/lib/dart/test/t_application_error_test.dart
@@ -0,0 +1,46 @@
+// 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.
+
+library thrift.test.t_application_error_test;
+
+import 'package:test/test.dart';
+import 'package:thrift/thrift.dart';
+
+void main() {
+  TProtocol protocol;
+
+  setUp(() {
+    protocol = new TBinaryProtocol(new TBufferedTransport());
+  });
+
+  test('Write and read an application error', () {
+    var expectedType = TApplicationErrorType.INTERNAL_ERROR;
+    var expectedMessage = 'test error message';
+
+    TApplicationError error =
+        new TApplicationError(expectedType, expectedMessage);
+    error.write(protocol);
+
+    protocol.transport.flush();
+
+    TApplicationError subject = TApplicationError.read(protocol);
+
+    expect(subject, isNotNull);
+    expect(subject.type, expectedType);
+    expect(subject.message, expectedMessage);
+  });
+}
diff --git a/lib/dart/test/transport/t_framed_transport_test.dart b/lib/dart/test/transport/t_framed_transport_test.dart
new file mode 100644
index 0000000..e072e68
--- /dev/null
+++ b/lib/dart/test/transport/t_framed_transport_test.dart
@@ -0,0 +1,175 @@
+// 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.
+
+library thrift.test.transport.t_framed_transport_test;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:typed_data' show Uint8List;
+
+import 'package:test/test.dart';
+import 'package:thrift/thrift.dart';
+
+void main() {
+  group('TFramedTransport partial reads', () {
+    final flushAwaitDuration = new Duration(seconds: 10);
+
+    FakeReadOnlySocket socket;
+    TSocketTransport socketTransport;
+    TFramedTransport transport;
+    var messageAvailable;
+
+    setUp(() {
+      socket = new FakeReadOnlySocket();
+      socketTransport = new TClientSocketTransport(socket);
+      transport = new TFramedTransport(socketTransport);
+      messageAvailable = false;
+    });
+
+    expectNoReadableBytes() {
+      var readBuffer = new Uint8List(128);
+      var readBytes = transport.read(readBuffer, 0, readBuffer.lengthInBytes);
+      expect(readBytes, 0);
+      expect(messageAvailable, false);
+    }
+
+    test('Test transport reads messages where header and body are sent separately', () async {
+      // buffer into which we'll read
+      var readBuffer = new Uint8List(10);
+      var readBytes;
+
+      // registers for readable bytes
+      var flushFuture = transport.flush().timeout(flushAwaitDuration);
+      flushFuture.then((_) {
+        messageAvailable = true;
+      });
+
+      // write header bytes
+      socket.messageController.add(new Uint8List.fromList([0x00, 0x00, 0x00, 0x06]));
+
+      // you shouldn't be able to get any bytes from the read,
+      // because the header has been consumed internally
+      expectNoReadableBytes();
+
+      // write first batch of body
+      socket.messageController.add(new Uint8List.fromList(UTF8.encode("He")));
+
+      // you shouldn't be able to get any bytes from the read,
+      // because the frame has been consumed internally
+      expectNoReadableBytes();
+
+      // write second batch of body
+      socket.messageController.add(new Uint8List.fromList(UTF8.encode("llo!")));
+
+      // have to wait for the flush to complete,
+      // because it's only then that the frame is available for reading
+      await flushFuture;
+      expect(messageAvailable, true);
+
+      // at this point the frame is complete, so we expect the read to complete
+      readBytes = transport.read(readBuffer, 0, readBuffer.lengthInBytes);
+      expect(readBytes, 6);
+      expect(readBuffer.sublist(0, 6), UTF8.encode("Hello!"));
+    });
+
+    test('Test transport reads messages where header is sent in pieces '
+         'and body is also sent in pieces', () async {
+      // buffer into which we'll read
+      var readBuffer = new Uint8List(10);
+      var readBytes;
+
+      // registers for readable bytes
+      var flushFuture = transport.flush().timeout(flushAwaitDuration);
+      flushFuture.then((_) {
+        messageAvailable = true;
+      });
+
+      // write first part of header bytes
+      socket.messageController.add(new Uint8List.fromList([0x00, 0x00]));
+
+      // you shouldn't be able to get any bytes from the read
+      expectNoReadableBytes();
+
+      // write second part of header bytes
+      socket.messageController.add(new Uint8List.fromList([0x00, 0x03]));
+
+      // you shouldn't be able to get any bytes from the read again
+      // because only the header was read, and there's no frame body
+      readBytes = expectNoReadableBytes();
+
+      // write first batch of body
+      socket.messageController.add(new Uint8List.fromList(UTF8.encode("H")));
+
+      // you shouldn't be able to get any bytes from the read,
+      // because the frame has been consumed internally
+      expectNoReadableBytes();
+
+      // write second batch of body
+      socket.messageController.add(new Uint8List.fromList(UTF8.encode("i!")));
+
+      // have to wait for the flush to complete,
+      // because it's only then that the frame is available for reading
+      await flushFuture;
+      expect(messageAvailable, true);
+
+      // at this point the frame is complete, so we expect the read to complete
+      readBytes = transport.read(readBuffer, 0, readBuffer.lengthInBytes);
+      expect(readBytes, 3);
+      expect(readBuffer.sublist(0, 3), UTF8.encode("Hi!"));
+    });
+  });
+}
+
+
+
+class FakeReadOnlySocket extends TSocket {
+
+  StreamController<Uint8List> messageController = new StreamController<Uint8List>(sync: true);
+  StreamController<Object> errorController = new StreamController<Object>();
+  StreamController<TSocketState> stateController = new StreamController<TSocketState>();
+
+  @override
+  Future close() {
+    // noop
+  }
+
+  @override
+  bool get isClosed => false;
+
+  @override
+  bool get isOpen => true;
+
+  @override
+  Stream<Object> get onError => errorController.stream;
+
+  @override
+  Stream<Uint8List> get onMessage => messageController.stream;
+
+  @override
+  Stream<TSocketState> get onState => stateController.stream;
+
+  @override
+  Future open() {
+    // noop
+  }
+
+  @override
+  void send(Uint8List data) {
+    // noop
+  }
+}
+
diff --git a/lib/dart/test/transport/t_http_transport_test.dart b/lib/dart/test/transport/t_http_transport_test.dart
new file mode 100644
index 0000000..66f3d05
--- /dev/null
+++ b/lib/dart/test/transport/t_http_transport_test.dart
@@ -0,0 +1,164 @@
+// 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.
+
+library thrift.test.transport.t_socket_transport_test;
+
+import 'dart:async';
+import 'dart:convert' show Encoding;
+import 'dart:convert' show Utf8Codec, BASE64;
+import 'dart:typed_data' show Uint8List;
+
+import 'package:http/http.dart' show BaseRequest;
+import 'package:http/http.dart' show Client;
+import 'package:http/http.dart' show Response;
+import 'package:http/http.dart' show StreamedResponse;
+import 'package:test/test.dart';
+import 'package:thrift/thrift.dart';
+
+void main() {
+  const utf8Codec = const Utf8Codec();
+
+  group('THttpClientTransport', () {
+    FakeHttpClient client;
+    THttpClientTransport transport;
+
+    setUp(() {
+      client = new FakeHttpClient(sync: false);
+      var config = new THttpConfig(Uri.parse('http://localhost'), {});
+      transport = new THttpClientTransport(client, config);
+    });
+
+    test('Test transport sends body', () async {
+      var expectedText = 'my request';
+      transport.writeAll(utf8Codec.encode(expectedText));
+
+      expect(client.postRequest, isEmpty);
+
+      await transport.flush();
+
+      expect(client.postRequest, isNotEmpty);
+
+      var requestText =
+          utf8Codec.decode(BASE64.decode(client.postRequest));
+      expect(requestText, expectedText);
+    });
+
+    test('Test transport receives response', () async {
+      var expectedText = 'my response';
+      var expectedBytes = utf8Codec.encode(expectedText);
+      client.postResponse = BASE64.encode(expectedBytes);
+
+      transport.writeAll(utf8Codec.encode('my request'));
+      expect(transport.hasReadData, isFalse);
+
+      await transport.flush();
+
+      expect(transport.hasReadData, isTrue);
+
+      var buffer = new Uint8List(expectedBytes.length);
+      transport.readAll(buffer, 0, expectedBytes.length);
+
+      var bufferText = utf8Codec.decode(buffer);
+      expect(bufferText, expectedText);
+    });
+  });
+
+  group('THttpClientTransport with multiple messages', () {
+    FakeHttpClient client;
+    THttpClientTransport transport;
+
+    setUp(() {
+      client = new FakeHttpClient(sync: true);
+      var config = new THttpConfig(Uri.parse('http://localhost'), {});
+      transport = new THttpClientTransport(client, config);
+    });
+
+    test('Test read correct buffer after flush', () async {
+      String bufferText;
+      var expectedText = 'response 1';
+      var expectedBytes = utf8Codec.encode(expectedText);
+
+      // prepare a response
+      transport.writeAll(utf8Codec.encode('request 1'));
+      client.postResponse = BASE64.encode(expectedBytes);
+
+      Future responseReady = transport.flush().then((_) {
+        var buffer = new Uint8List(expectedBytes.length);
+        transport.readAll(buffer, 0, expectedBytes.length);
+        bufferText = utf8Codec.decode(buffer);
+      });
+
+      // prepare a second response
+      transport.writeAll(utf8Codec.encode('request 2'));
+      var response2Bytes = utf8Codec.encode('response 2');
+      client.postResponse = BASE64.encode(response2Bytes);
+      await transport.flush();
+
+      await responseReady;
+      expect(bufferText, expectedText);
+    });
+  });
+}
+
+class FakeHttpClient implements Client {
+  String postResponse = '';
+  String postRequest = '';
+
+  final bool sync;
+
+  FakeHttpClient({this.sync: false});
+
+  Future<Response> post(url,
+      {Map<String, String> headers, body, Encoding encoding}) {
+    postRequest = body;
+    var response = new Response(postResponse, 200);
+
+    if (sync) {
+      return new Future.sync(() => response);
+    } else {
+      return new Future.value(response);
+    }
+  }
+
+  Future<Response> head(url, {Map<String, String> headers}) =>
+      throw new UnimplementedError();
+
+  Future<Response> get(url, {Map<String, String> headers}) =>
+      throw new UnimplementedError();
+
+  Future<Response> put(url,
+          {Map<String, String> headers, body, Encoding encoding}) =>
+      throw new UnimplementedError();
+
+  Future<Response> patch(url,
+          {Map<String, String> headers, body, Encoding encoding}) =>
+      throw new UnimplementedError();
+
+  Future<Response> delete(url, {Map<String, String> headers}) =>
+      throw new UnimplementedError();
+
+  Future<String> read(url, {Map<String, String> headers}) =>
+      throw new UnimplementedError();
+
+  Future<Uint8List> readBytes(url, {Map<String, String> headers}) =>
+      throw new UnimplementedError();
+
+  Future<StreamedResponse> send(BaseRequest request) =>
+      throw new UnimplementedError();
+
+  void close() => throw new UnimplementedError();
+}
diff --git a/lib/dart/test/transport/t_socket_transport_test.dart b/lib/dart/test/transport/t_socket_transport_test.dart
new file mode 100644
index 0000000..929ab17
--- /dev/null
+++ b/lib/dart/test/transport/t_socket_transport_test.dart
@@ -0,0 +1,311 @@
+// 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.
+
+library thrift.test.transport.t_socket_transport_test;
+
+import 'dart:async';
+import 'dart:convert' show Utf8Codec, BASE64;
+import 'dart:typed_data' show Uint8List;
+
+import 'package:mockito/mockito.dart';
+import 'package:test/test.dart';
+import 'package:thrift/thrift.dart';
+
+void main() {
+  const utf8Codec = const Utf8Codec();
+
+  final requestText = 'my test request';
+  final requestBytes = new Uint8List.fromList(utf8Codec.encode(requestText));
+  final requestBase64 = BASE64.encode(requestBytes);
+
+  final responseText = 'response 1';
+  final responseBytes = new Uint8List.fromList(utf8Codec.encode(responseText));
+  final responseBase64 = BASE64.encode(responseBytes);
+
+  final framedResponseBase64 =
+      BASE64.encode(_getFramedResponse(responseBytes));
+
+  group('TClientSocketTransport', () {
+    FakeSocket socket;
+    TTransport transport;
+
+    setUp(() async {
+      socket = new FakeSocket(sync: false);
+      await socket.open();
+      transport = new TClientSocketTransport(socket);
+      await transport.open();
+      transport.writeAll(requestBytes);
+    });
+
+    test('Test client sending data over transport', () async {
+      expect(socket.sendPayload, isNull);
+
+      Future responseReady = transport.flush();
+
+      // allow microtask events to finish
+      await new Future.value();
+
+      expect(socket.sendPayload, isNotNull);
+      expect(socket.sendPayload, requestBytes);
+
+      // simulate a response
+      socket.receiveFakeMessage(responseBase64);
+
+      await responseReady;
+      var buffer = new Uint8List(responseBytes.length);
+      transport.readAll(buffer, 0, responseBytes.length);
+      var bufferText = utf8Codec.decode(buffer);
+
+      expect(bufferText, responseText);
+    });
+  }, timeout: new Timeout(new Duration(seconds: 1)));
+
+  group('TClientSocketTransport with FramedTransport', () {
+    FakeSocket socket;
+    TTransport transport;
+
+    setUp(() async {
+      socket = new FakeSocket(sync: true);
+      await socket.open();
+
+      transport = new TFramedTransport(new TClientSocketTransport(socket));
+      await transport.open();
+      transport.writeAll(requestBytes);
+    });
+
+    test('Test client sending data over framed transport', () async {
+      String bufferText;
+
+      Future responseReady = transport.flush().then((_) {
+        var buffer = new Uint8List(responseBytes.length);
+        transport.readAll(buffer, 0, responseBytes.length);
+        bufferText = utf8Codec.decode(buffer);
+      });
+
+      // simulate a response
+      socket.receiveFakeMessage(framedResponseBase64);
+
+      await responseReady;
+      expect(bufferText, responseText);
+    });
+  }, timeout: new Timeout(new Duration(seconds: 1)));
+
+  group('TAsyncClientSocketTransport', () {
+    FakeSocket socket;
+    FakeProtocolFactory protocolFactory;
+    TTransport transport;
+
+    setUp(() async {
+      socket = new FakeSocket(sync: true);
+      await socket.open();
+
+      protocolFactory = new FakeProtocolFactory();
+      protocolFactory.message = new TMessage('foo', TMessageType.CALL, 123);
+      transport = new TAsyncClientSocketTransport(
+          socket, new TMessageReader(protocolFactory),
+          responseTimeout: Duration.ZERO);
+      await transport.open();
+      transport.writeAll(requestBytes);
+    });
+
+    test('Test response correlates to correct request', () async {
+      String bufferText;
+
+      Future responseReady = transport.flush().then((_) {
+        var buffer = new Uint8List(responseBytes.length);
+        transport.readAll(buffer, 0, responseBytes.length);
+        bufferText = utf8Codec.decode(buffer);
+      });
+
+      // simulate a response
+      protocolFactory.message = new TMessage('foo', TMessageType.REPLY, 123);
+      socket.receiveFakeMessage(responseBase64);
+
+      // simulate a second response
+      var response2Text = 'response 2';
+      var response2Bytes =
+          new Uint8List.fromList(utf8Codec.encode(response2Text));
+      var response2Base64 = BASE64.encode(response2Bytes);
+      protocolFactory.message = new TMessage('foo2', TMessageType.REPLY, 124);
+      socket.receiveFakeMessage(response2Base64);
+
+      await responseReady;
+      expect(bufferText, responseText);
+    });
+
+    test('Test response timeout', () async {
+      Future responseReady = transport.flush();
+      expect(responseReady, throwsA(new isInstanceOf<TimeoutException>()));
+    });
+  }, timeout: new Timeout(new Duration(seconds: 1)));
+
+  group('TAsyncClientSocketTransport with TFramedTransport', () {
+    FakeSocket socket;
+    FakeProtocolFactory protocolFactory;
+    TTransport transport;
+
+    setUp(() async {
+      socket = new FakeSocket(sync: true);
+      await socket.open();
+
+      protocolFactory = new FakeProtocolFactory();
+      protocolFactory.message = new TMessage('foo', TMessageType.CALL, 123);
+      var messageReader = new TMessageReader(protocolFactory,
+          byteOffset: TFramedTransport.headerByteCount);
+
+      transport = new TFramedTransport(new TAsyncClientSocketTransport(
+          socket, messageReader,
+          responseTimeout: Duration.ZERO));
+      await transport.open();
+      transport.writeAll(requestBytes);
+    });
+
+    test('Test async client sending data over framed transport', () async {
+      String bufferText;
+
+      Future responseReady = transport.flush().then((_) {
+        var buffer = new Uint8List(responseBytes.length);
+        transport.readAll(buffer, 0, responseBytes.length);
+        bufferText = utf8Codec.decode(buffer);
+      });
+
+      // simulate a response
+      protocolFactory.message = new TMessage('foo', TMessageType.REPLY, 123);
+      socket.receiveFakeMessage(framedResponseBase64);
+
+      await responseReady;
+      expect(bufferText, responseText);
+    });
+  }, timeout: new Timeout(new Duration(seconds: 1)));
+
+  group('TServerTransport', () {
+    test('Test server transport listens to socket', () async {
+      var socket = new FakeSocket();
+      await socket.open();
+      expect(socket.isOpen, isTrue);
+
+      var transport = new TServerSocketTransport(socket);
+      expect(transport.hasReadData, isFalse);
+
+      socket.receiveFakeMessage(requestBase64);
+
+      // allow microtask events to finish
+      await new Future.value();
+
+      expect(transport.hasReadData, isTrue);
+
+      var buffer = new Uint8List(requestBytes.length);
+      transport.readAll(buffer, 0, requestBytes.length);
+
+      var bufferText = utf8Codec.decode(buffer);
+      expect(bufferText, requestText);
+    });
+
+    test('Test server sending data over transport', () async {
+      var socket = new FakeSocket();
+      await socket.open();
+
+      var transport = new TServerSocketTransport(socket);
+
+      transport.writeAll(responseBytes);
+      expect(socket.sendPayload, isNull);
+
+      transport.flush();
+
+      // allow microtask events to finish
+      await new Future.value();
+
+      expect(socket.sendPayload, isNotNull);
+      expect(socket.sendPayload, responseBytes);
+    });
+  }, timeout: new Timeout(new Duration(seconds: 1)));
+}
+
+class FakeSocket extends TSocket {
+  final StreamController<TSocketState> _onStateController;
+  Stream<TSocketState> get onState => _onStateController.stream;
+
+  final StreamController<Object> _onErrorController;
+  Stream<Object> get onError => _onErrorController.stream;
+
+  final StreamController<Uint8List> _onMessageController;
+  Stream<Uint8List> get onMessage => _onMessageController.stream;
+
+  FakeSocket({bool sync: false})
+      : _onStateController = new StreamController.broadcast(sync: sync),
+        _onErrorController = new StreamController.broadcast(sync: sync),
+        _onMessageController = new StreamController.broadcast(sync: sync);
+
+  bool _isOpen;
+
+  bool get isOpen => _isOpen;
+
+  bool get isClosed => !isOpen;
+
+  Future open() async {
+    _isOpen = true;
+    _onStateController.add(TSocketState.OPEN);
+  }
+
+  Future close() async {
+    _isOpen = false;
+    _onStateController.add(TSocketState.CLOSED);
+  }
+
+  Uint8List _sendPayload;
+  Uint8List get sendPayload => _sendPayload;
+
+  void send(Uint8List data) {
+    if (!isOpen) throw new StateError('The socket is not open');
+
+    _sendPayload = data;
+  }
+
+  void receiveFakeMessage(String base64) {
+    if (!isOpen) throw new StateError('The socket is not open');
+
+    var message =
+        new Uint8List.fromList(BASE64.decode(base64));
+    _onMessageController.add(message);
+  }
+}
+
+class FakeProtocolFactory implements TProtocolFactory {
+  FakeProtocolFactory();
+
+  TMessage message;
+
+  getProtocol(TTransport transport) => new FakeProtocol(message);
+}
+
+class FakeProtocol extends Mock implements TProtocol {
+  FakeProtocol(this._message);
+
+  TMessage _message;
+
+  readMessageBegin() => _message;
+}
+
+Uint8List _getFramedResponse(Uint8List responseBytes) {
+  var byteOffset = TFramedTransport.headerByteCount;
+  var response = new Uint8List(byteOffset + responseBytes.length);
+
+  response.buffer.asByteData().setInt32(0, responseBytes.length);
+  response.setAll(byteOffset, responseBytes);
+
+  return response;
+}
diff --git a/lib/dart/test/transport/t_transport_test.dart b/lib/dart/test/transport/t_transport_test.dart
new file mode 100644
index 0000000..0bb381a
--- /dev/null
+++ b/lib/dart/test/transport/t_transport_test.dart
@@ -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.
+
+library thrift.test.transport.t_socket_transport_test;
+
+import 'package:test/test.dart';
+import 'package:thrift/thrift.dart';
+
+/// Common transport tests
+void main() {
+  group('TTransportFactory', () {
+    test('transport is returned from base factory', () async {
+      TTransport result;
+      TTransport transport = null;
+
+      var factory = new TTransportFactory();
+
+      result = await factory.getTransport(transport);
+      expect(result, isNull);
+
+      transport = new TBufferedTransport();
+      result = await factory.getTransport(transport);
+
+      expect(result, transport);
+    });
+  });
+}
diff --git a/lib/dart/tool/dev.dart b/lib/dart/tool/dev.dart
new file mode 100644
index 0000000..27f8b8f
--- /dev/null
+++ b/lib/dart/tool/dev.dart
@@ -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.
+
+library tool.dev;
+
+import 'package:dart_dev/dart_dev.dart' show dev, config;
+
+main(List<String> args) async {
+  // https://github.com/Workiva/dart_dev
+
+  var directories = ['lib/', 'test/', 'tool/'];
+  config.analyze.entryPoints = directories;
+  config.format.directories = directories;
+  config.copyLicense
+    ..licensePath = 'LICENSE_HEADER'
+    ..directories = directories;
+
+  await dev(args);
+}
diff --git a/lib/delphi/DelphiThrift.groupproj b/lib/delphi/DelphiThrift.groupproj
new file mode 100644
index 0000000..a172e49
--- /dev/null
+++ b/lib/delphi/DelphiThrift.groupproj
@@ -0,0 +1,156 @@
+	<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+		<PropertyGroup>
+			<ProjectGuid>{6BD327A5-7688-4263-B6A8-B15207CF4EC5}</ProjectGuid>
+		</PropertyGroup>
+		<ItemGroup>
+			<Projects Include="test\client.dproj">
+				<Dependencies/>
+			</Projects>
+			<Projects Include="test\server.dproj">
+				<Dependencies/>
+			</Projects>
+			<Projects Include="test\multiplexed\Multiplex.Test.Client.dproj">
+				<Dependencies/>
+			</Projects>
+			<Projects Include="test\multiplexed\Multiplex.Test.Server.dproj">
+				<Dependencies/>
+			</Projects>
+			<Projects Include="test\serializer\TestSerializer.dproj">
+				<Dependencies/>
+			</Projects>
+			<Projects Include="test\skip\skiptest_version1.dproj">
+				<Dependencies/>
+			</Projects>
+			<Projects Include="test\skip\skiptest_version2.dproj">
+				<Dependencies/>
+			</Projects>
+			<Projects Include="test\typeregistry\TestTypeRegistry.dproj">
+				<Dependencies/>
+			</Projects>
+			<Projects Include="..\..\tutorial\delphi\DelphiServer\DelphiServer.dproj">
+				<Dependencies/>
+			</Projects>
+			<Projects Include="..\..\tutorial\delphi\DelphiClient\DelphiClient.dproj">
+				<Dependencies/>
+			</Projects>
+			<Projects Include="test\keywords\ReservedKeywords.dproj">
+				<Dependencies/>
+			</Projects>
+		</ItemGroup>
+		<ProjectExtensions>
+			<Borland.Personality>Default.Personality.12</Borland.Personality>
+			<Borland.ProjectType/>
+			<BorlandProject>
+				<Default.Personality/>
+			</BorlandProject>
+		</ProjectExtensions>
+		<Target Name="client">
+			<MSBuild Projects="test\client.dproj"/>
+		</Target>
+		<Target Name="client:Clean">
+			<MSBuild Projects="test\client.dproj" Targets="Clean"/>
+		</Target>
+		<Target Name="client:Make">
+			<MSBuild Projects="test\client.dproj" Targets="Make"/>
+		</Target>
+		<Target Name="server">
+			<MSBuild Projects="test\server.dproj"/>
+		</Target>
+		<Target Name="server:Clean">
+			<MSBuild Projects="test\server.dproj" Targets="Clean"/>
+		</Target>
+		<Target Name="server:Make">
+			<MSBuild Projects="test\server.dproj" Targets="Make"/>
+		</Target>
+		<Target Name="Multiplex_Test_Client">
+			<MSBuild Projects="test\multiplexed\Multiplex.Test.Client.dproj"/>
+		</Target>
+		<Target Name="Multiplex_Test_Client:Clean">
+			<MSBuild Projects="test\multiplexed\Multiplex.Test.Client.dproj" Targets="Clean"/>
+		</Target>
+		<Target Name="Multiplex_Test_Client:Make">
+			<MSBuild Projects="test\multiplexed\Multiplex.Test.Client.dproj" Targets="Make"/>
+		</Target>
+		<Target Name="Multiplex_Test_Server">
+			<MSBuild Projects="test\multiplexed\Multiplex.Test.Server.dproj"/>
+		</Target>
+		<Target Name="Multiplex_Test_Server:Clean">
+			<MSBuild Projects="test\multiplexed\Multiplex.Test.Server.dproj" Targets="Clean"/>
+		</Target>
+		<Target Name="Multiplex_Test_Server:Make">
+			<MSBuild Projects="test\multiplexed\Multiplex.Test.Server.dproj" Targets="Make"/>
+		</Target>
+		<Target Name="TestSerializer">
+			<MSBuild Projects="test\serializer\TestSerializer.dproj"/>
+		</Target>
+		<Target Name="TestSerializer:Clean">
+			<MSBuild Projects="test\serializer\TestSerializer.dproj" Targets="Clean"/>
+		</Target>
+		<Target Name="TestSerializer:Make">
+			<MSBuild Projects="test\serializer\TestSerializer.dproj" Targets="Make"/>
+		</Target>
+		<Target Name="skiptest_version1">
+			<MSBuild Projects="test\skip\skiptest_version1.dproj"/>
+		</Target>
+		<Target Name="skiptest_version1:Clean">
+			<MSBuild Projects="test\skip\skiptest_version1.dproj" Targets="Clean"/>
+		</Target>
+		<Target Name="skiptest_version1:Make">
+			<MSBuild Projects="test\skip\skiptest_version1.dproj" Targets="Make"/>
+		</Target>
+		<Target Name="skiptest_version2">
+			<MSBuild Projects="test\skip\skiptest_version2.dproj"/>
+		</Target>
+		<Target Name="skiptest_version2:Clean">
+			<MSBuild Projects="test\skip\skiptest_version2.dproj" Targets="Clean"/>
+		</Target>
+		<Target Name="skiptest_version2:Make">
+			<MSBuild Projects="test\skip\skiptest_version2.dproj" Targets="Make"/>
+		</Target>
+		<Target Name="TestTypeRegistry">
+			<MSBuild Projects="test\typeregistry\TestTypeRegistry.dproj"/>
+		</Target>
+		<Target Name="TestTypeRegistry:Clean">
+			<MSBuild Projects="test\typeregistry\TestTypeRegistry.dproj" Targets="Clean"/>
+		</Target>
+		<Target Name="TestTypeRegistry:Make">
+			<MSBuild Projects="test\typeregistry\TestTypeRegistry.dproj" Targets="Make"/>
+		</Target>
+		<Target Name="DelphiServer">
+			<MSBuild Projects="..\..\tutorial\delphi\DelphiServer\DelphiServer.dproj"/>
+		</Target>
+		<Target Name="DelphiServer:Clean">
+			<MSBuild Projects="..\..\tutorial\delphi\DelphiServer\DelphiServer.dproj" Targets="Clean"/>
+		</Target>
+		<Target Name="DelphiServer:Make">
+			<MSBuild Projects="..\..\tutorial\delphi\DelphiServer\DelphiServer.dproj" Targets="Make"/>
+		</Target>
+		<Target Name="DelphiClient">
+			<MSBuild Projects="..\..\tutorial\delphi\DelphiClient\DelphiClient.dproj"/>
+		</Target>
+		<Target Name="DelphiClient:Clean">
+			<MSBuild Projects="..\..\tutorial\delphi\DelphiClient\DelphiClient.dproj" Targets="Clean"/>
+		</Target>
+		<Target Name="DelphiClient:Make">
+			<MSBuild Projects="..\..\tutorial\delphi\DelphiClient\DelphiClient.dproj" Targets="Make"/>
+		</Target>
+		<Target Name="ReservedKeywords">
+			<MSBuild Projects="test\keywords\ReservedKeywords.dproj"/>
+		</Target>
+		<Target Name="ReservedKeywords:Clean">
+			<MSBuild Projects="test\keywords\ReservedKeywords.dproj" Targets="Clean"/>
+		</Target>
+		<Target Name="ReservedKeywords:Make">
+			<MSBuild Projects="test\keywords\ReservedKeywords.dproj" Targets="Make"/>
+		</Target>
+		<Target Name="Build">
+			<CallTarget Targets="client;server;Multiplex_Test_Client;Multiplex_Test_Server;TestSerializer;skiptest_version1;skiptest_version2;TestTypeRegistry;DelphiServer;DelphiClient;ReservedKeywords"/>
+		</Target>
+		<Target Name="Clean">
+			<CallTarget Targets="client:Clean;server:Clean;Multiplex_Test_Client:Clean;Multiplex_Test_Server:Clean;TestSerializer:Clean;skiptest_version1:Clean;skiptest_version2:Clean;TestTypeRegistry:Clean;DelphiServer:Clean;DelphiClient:Clean;ReservedKeywords:Clean"/>
+		</Target>
+		<Target Name="Make">
+			<CallTarget Targets="client:Make;server:Make;Multiplex_Test_Client:Make;Multiplex_Test_Server:Make;TestSerializer:Make;skiptest_version1:Make;skiptest_version2:Make;TestTypeRegistry:Make;DelphiServer:Make;DelphiClient:Make;ReservedKeywords:Make"/>
+		</Target>
+		<Import Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')" Project="$(BDS)\Bin\CodeGear.Group.Targets"/>
+	</Project>
diff --git a/lib/delphi/README.md b/lib/delphi/README.md
new file mode 100644
index 0000000..91799d0
--- /dev/null
+++ b/lib/delphi/README.md
@@ -0,0 +1,30 @@
+Thrift Delphi Software Library
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+Using Thrift with Delphi
+====================
+
+The Thrift Delphi Library requires at least Delphi 2010.
+
+Because the Library heavily relies on generics, using it
+with earlier versions (such as Delphi 7) will *not* work.
+
diff --git a/lib/delphi/coding_standards.md b/lib/delphi/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/delphi/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/delphi/src/Thrift.Collections.pas b/lib/delphi/src/Thrift.Collections.pas
index 66ff1c0..b2206cb 100644
--- a/lib/delphi/src/Thrift.Collections.pas
+++ b/lib/delphi/src/Thrift.Collections.pas
@@ -1,617 +1,619 @@
-(*

- * 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.

- *)

-

-unit Thrift.Collections;

-

-interface

-

-uses

-  Generics.Collections, Generics.Defaults, Thrift.Utils;

-

-type

-

-{$IF CompilerVersion < 21.0}

-  TArray<T> = array of T;

-{$IFEND}

-

-  IThriftContainer = interface

-    ['{93DEF5A0-D162-461A-AB22-5B4EE0734050}']

-    function ToString: string;

-  end;

-

-  IThriftDictionary<TKey,TValue> = interface(IThriftContainer)

-    ['{25EDD506-F9D1-4008-A40F-5940364B7E46}']

-    function GetEnumerator: TEnumerator<TPair<TKey,TValue>>;

-

-    function GetKeys: TDictionary<TKey,TValue>.TKeyCollection;

-    function GetValues: TDictionary<TKey,TValue>.TValueCollection;

-    function GetItem(const Key: TKey): TValue;

-    procedure SetItem(const Key: TKey; const Value: TValue);

-    function GetCount: Integer;

-

-    procedure Add(const Key: TKey; const Value: TValue);

-    procedure Remove(const Key: TKey);

-{$IF CompilerVersion >= 21.0}

-    function ExtractPair(const Key: TKey): TPair<TKey,TValue>;

-{$IFEND}

-    procedure Clear;

-    procedure TrimExcess;

-    function TryGetValue(const Key: TKey; out Value: TValue): Boolean;

-    procedure AddOrSetValue(const Key: TKey; const Value: TValue);

-    function ContainsKey(const Key: TKey): Boolean;

-    function ContainsValue(const Value: TValue): Boolean;

-    function ToArray: TArray<TPair<TKey,TValue>>;

-

-    property Items[const Key: TKey]: TValue read GetItem write SetItem; default;

-    property Count: Integer read GetCount;

-    property Keys: TDictionary<TKey,TValue>.TKeyCollection read GetKeys;

-    property Values: TDictionary<TKey,TValue>.TValueCollection read GetValues;

-  end;

-

-  TThriftDictionaryImpl<TKey,TValue> = class( TInterfacedObject, IThriftDictionary<TKey,TValue>)

-  private

-    FDictionaly : TDictionary<TKey,TValue>;

-  protected

-    function GetEnumerator: TEnumerator<TPair<TKey,TValue>>;

-

-    function GetKeys: TDictionary<TKey,TValue>.TKeyCollection;

-    function GetValues: TDictionary<TKey,TValue>.TValueCollection;

-    function GetItem(const Key: TKey): TValue;

-    procedure SetItem(const Key: TKey; const Value: TValue);

-    function GetCount: Integer;

-

-    procedure Add(const Key: TKey; const Value: TValue);

-    procedure Remove(const Key: TKey);

-{$IF CompilerVersion >= 21.0}

-    function ExtractPair(const Key: TKey): TPair<TKey,TValue>;

-{$IFEND}

-    procedure Clear;

-    procedure TrimExcess;

-    function TryGetValue(const Key: TKey; out Value: TValue): Boolean;

-    procedure AddOrSetValue(const Key: TKey; const Value: TValue);

-    function ContainsKey(const Key: TKey): Boolean;

-    function ContainsValue(const Value: TValue): Boolean;

-    function ToArray: TArray<TPair<TKey,TValue>>;

-    property Items[const Key: TKey]: TValue read GetItem write SetItem; default;

-    property Count: Integer read GetCount;

-    property Keys: TDictionary<TKey,TValue>.TKeyCollection read GetKeys;

-    property Values: TDictionary<TKey,TValue>.TValueCollection read GetValues;

-  public

-    constructor Create(ACapacity: Integer = 0);

-    destructor Destroy; override;

-  end;

-

-  IThriftList<T> = interface(IThriftContainer)

-    ['{29BEEE31-9CB4-401B-AA04-5148A75F473B}']

-    function GetEnumerator: TEnumerator<T>;

-    function GetCapacity: Integer;

-    procedure SetCapacity(Value: Integer);

-    function GetCount: Integer;

-    procedure SetCount(Value: Integer);

-    function GetItem(Index: Integer): T;

-    procedure SetItem(Index: Integer; const Value: T);

-    function Add(const Value: T): Integer;

-    procedure AddRange(const Values: array of T); overload;

-    procedure AddRange(const Collection: IEnumerable<T>); overload;

-    procedure AddRange(Collection: TEnumerable<T>); overload;

-    procedure Insert(Index: Integer; const Value: T);

-    procedure InsertRange(Index: Integer; const Values: array of T); overload;

-    procedure InsertRange(Index: Integer; const Collection: IEnumerable<T>); overload;

-    procedure InsertRange(Index: Integer; const Collection: TEnumerable<T>); overload;

-    function Remove(const Value: T): Integer;

-    procedure Delete(Index: Integer);

-    procedure DeleteRange(AIndex, ACount: Integer);

-    function Extract(const Value: T): T;

-{$IF CompilerVersion >= 21.0}

-    procedure Exchange(Index1, Index2: Integer);

-    procedure Move(CurIndex, NewIndex: Integer);

-    function First: T;

-    function Last: T;

-{$IFEND}

-    procedure Clear;

-    function Contains(const Value: T): Boolean;

-    function IndexOf(const Value: T): Integer;

-    function LastIndexOf(const Value: T): Integer;

-    procedure Reverse;

-    procedure Sort; overload;

-    procedure Sort(const AComparer: IComparer<T>); overload;

-    function BinarySearch(const Item: T; out Index: Integer): Boolean; overload;

-    function BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean; overload;

-    procedure TrimExcess;

-    function ToArray: TArray<T>;

-    property Capacity: Integer read GetCapacity write SetCapacity;

-    property Count: Integer read GetCount write SetCount;

-    property Items[Index: Integer]: T read GetItem write SetItem; default;

-  end;

-

-  TThriftListImpl<T> = class( TInterfacedObject, IThriftList<T>)

-  private

-    FList : TList<T>;

-  protected

-    function GetEnumerator: TEnumerator<T>;

-    function GetCapacity: Integer;

-    procedure SetCapacity(Value: Integer);

-    function GetCount: Integer;

-    procedure SetCount(Value: Integer);

-    function GetItem(Index: Integer): T;

-    procedure SetItem(Index: Integer; const Value: T);

-    function Add(const Value: T): Integer;

-    procedure AddRange(const Values: array of T); overload;

-    procedure AddRange(const Collection: IEnumerable<T>); overload;

-    procedure AddRange(Collection: TEnumerable<T>); overload;

-    procedure Insert(Index: Integer; const Value: T);

-    procedure InsertRange(Index: Integer; const Values: array of T); overload;

-    procedure InsertRange(Index: Integer; const Collection: IEnumerable<T>); overload;

-    procedure InsertRange(Index: Integer; const Collection: TEnumerable<T>); overload;

-    function Remove(const Value: T): Integer;

-    procedure Delete(Index: Integer);

-    procedure DeleteRange(AIndex, ACount: Integer);

-    function Extract(const Value: T): T;

-{$IF CompilerVersion >= 21.0}

-    procedure Exchange(Index1, Index2: Integer);

-    procedure Move(CurIndex, NewIndex: Integer);

-    function First: T;

-    function Last: T;

-{$IFEND}

-    procedure Clear;

-    function Contains(const Value: T): Boolean;

-    function IndexOf(const Value: T): Integer;

-    function LastIndexOf(const Value: T): Integer;

-    procedure Reverse;

-    procedure Sort; overload;

-    procedure Sort(const AComparer: IComparer<T>); overload;

-    function BinarySearch(const Item: T; out Index: Integer): Boolean; overload;

-    function BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean; overload;

-    procedure TrimExcess;

-    function ToArray: TArray<T>;

-    property Capacity: Integer read GetCapacity write SetCapacity;

-    property Count: Integer read GetCount write SetCount;

-    property Items[Index: Integer]: T read GetItem write SetItem; default;

-  public

-    constructor Create;

-    destructor Destroy; override;

-  end;

-

-  IHashSet<TValue> = interface(IThriftContainer)

-    ['{0923A3B5-D4D4-48A8-91AD-40238E2EAD66}']

-    function GetEnumerator: TEnumerator<TValue>;

-    function GetIsReadOnly: Boolean;

-    function GetCount: Integer;

-    property Count: Integer read GetCount;

-    property IsReadOnly: Boolean read GetIsReadOnly;

-    procedure Add( const item: TValue);

-    procedure Clear;

-    function Contains( const item: TValue): Boolean;

-    procedure CopyTo(var A: TArray<TValue>; arrayIndex: Integer);

-    function Remove( const item: TValue ): Boolean;

-  end;

-

-  THashSetImpl<TValue> = class( TInterfacedObject, IHashSet<TValue>)

-  private

-    FDictionary : IThriftDictionary<TValue,Integer>;

-    FIsReadOnly: Boolean;

-  protected

-    function GetEnumerator: TEnumerator<TValue>;

-    function GetIsReadOnly: Boolean;

-    function GetCount: Integer;

-    property Count: Integer read GetCount;

-    property IsReadOnly: Boolean read FIsReadOnly;

-    procedure Add( const item: TValue);

-    procedure Clear;

-    function Contains( const item: TValue): Boolean;

-    procedure CopyTo(var A: TArray<TValue>; arrayIndex: Integer);

-    function Remove( const item: TValue ): Boolean;

-  public

-    constructor Create;

-  end;

-

-implementation

-

-{ THashSetImpl<TValue> }

-

-procedure THashSetImpl<TValue>.Add( const item: TValue);

-begin

-  if not FDictionary.ContainsKey(item) then

-  begin

-    FDictionary.Add( item, 0);

-  end;

-end;

-

-procedure THashSetImpl<TValue>.Clear;

-begin

-  FDictionary.Clear;

-end;

-

-function THashSetImpl<TValue>.Contains( const item: TValue): Boolean;

-begin

-  Result := FDictionary.ContainsKey(item);

-end;

-

-procedure THashSetImpl<TValue>.CopyTo(var A: TArray<TValue>; arrayIndex: Integer);

-var

-  i : Integer;

-  Enumlator : TEnumerator<TValue>;

-begin

-  Enumlator := GetEnumerator;

-  while Enumlator.MoveNext do

-  begin

-    A[arrayIndex] := Enumlator.Current;

-    Inc(arrayIndex);

-  end;

-end;

-

-constructor THashSetImpl<TValue>.Create;

-begin

-  inherited;

-  FDictionary := TThriftDictionaryImpl<TValue,Integer>.Create;

-end;

-

-function THashSetImpl<TValue>.GetCount: Integer;

-begin

-  Result := FDictionary.Count;

-end;

-

-function THashSetImpl<TValue>.GetEnumerator: TEnumerator<TValue>;

-begin

-  Result := FDictionary.Keys.GetEnumerator;

-end;

-

-function THashSetImpl<TValue>.GetIsReadOnly: Boolean;

-begin

-  Result := FIsReadOnly;

-end;

-

-function THashSetImpl<TValue>.Remove( const item: TValue): Boolean;

-begin

-  Result := False;

-  if FDictionary.ContainsKey( item ) then

-  begin

-    FDictionary.Remove( item );

-    Result := not FDictionary.ContainsKey( item );

-  end;

-end;

-

-{ TThriftDictionaryImpl<TKey, TValue> }

-

-procedure TThriftDictionaryImpl<TKey, TValue>.Add(const Key: TKey;

-  const Value: TValue);

-begin

-  FDictionaly.Add( Key, Value);

-end;

-

-procedure TThriftDictionaryImpl<TKey, TValue>.AddOrSetValue(const Key: TKey;

-  const Value: TValue);

-begin

-  FDictionaly.AddOrSetValue( Key, Value);

-end;

-

-procedure TThriftDictionaryImpl<TKey, TValue>.Clear;

-begin

-  FDictionaly.Clear;

-end;

-

-function TThriftDictionaryImpl<TKey, TValue>.ContainsKey(

-  const Key: TKey): Boolean;

-begin

-  Result := FDictionaly.ContainsKey( Key );

-end;

-

-function TThriftDictionaryImpl<TKey, TValue>.ContainsValue(

-  const Value: TValue): Boolean;

-begin

-  Result := FDictionaly.ContainsValue( Value );

-end;

-

-constructor TThriftDictionaryImpl<TKey, TValue>.Create(ACapacity: Integer);

-begin

-  FDictionaly := TDictionary<TKey,TValue>.Create( ACapacity );

-end;

-

-destructor TThriftDictionaryImpl<TKey, TValue>.Destroy;

-begin

-  FDictionaly.Free;

-  inherited;

-end;

-

-{$IF CompilerVersion >= 21.0}

-function TThriftDictionaryImpl<TKey, TValue>.ExtractPair( const Key: TKey): TPair<TKey, TValue>;

-begin

-  Result := FDictionaly.ExtractPair( Key);

-end;

-{$IFEND}

-

-function TThriftDictionaryImpl<TKey, TValue>.GetCount: Integer;

-begin

-  Result := FDictionaly.Count;

-end;

-

-function TThriftDictionaryImpl<TKey, TValue>.GetEnumerator: TEnumerator<TPair<TKey, TValue>>;

-begin

-  Result := FDictionaly.GetEnumerator;

-end;

-

-function TThriftDictionaryImpl<TKey, TValue>.GetItem(const Key: TKey): TValue;

-begin

-  Result := FDictionaly.Items[Key];

-end;

-

-function TThriftDictionaryImpl<TKey, TValue>.GetKeys: TDictionary<TKey, TValue>.TKeyCollection;

-begin

-  Result := FDictionaly.Keys;

-end;

-

-function TThriftDictionaryImpl<TKey, TValue>.GetValues: TDictionary<TKey, TValue>.TValueCollection;

-begin

-  Result := FDictionaly.Values;

-end;

-

-procedure TThriftDictionaryImpl<TKey, TValue>.Remove(const Key: TKey);

-begin

-  FDictionaly.Remove( Key );

-end;

-

-procedure TThriftDictionaryImpl<TKey, TValue>.SetItem(const Key: TKey;

-  const Value: TValue);

-begin

-  FDictionaly.AddOrSetValue( Key, Value);

-end;

-

-function TThriftDictionaryImpl<TKey, TValue>.ToArray: TArray<TPair<TKey, TValue>>;

-{$IF CompilerVersion < 22.0}

-var

-  x : TPair<TKey, TValue>;

-  i : Integer;

-{$IFEND}

-begin

-{$IF CompilerVersion < 22.0}

-  SetLength(Result, Count);

-  i := 0;

-  for x in FDictionaly do

-  begin

-    Result[i] := x;

-    Inc( i );

-  end;

-{$ELSE}

-  Result := FDictionaly.ToArray;

-{$IFEND}

-end;

-

-procedure TThriftDictionaryImpl<TKey, TValue>.TrimExcess;

-begin

-  FDictionaly.TrimExcess;

-end;

-

-function TThriftDictionaryImpl<TKey, TValue>.TryGetValue(const Key: TKey;

-  out Value: TValue): Boolean;

-begin

-  Result := FDictionaly.TryGetValue( Key, Value);

-end;

-

-{ TThriftListImpl<T> }

-

-function TThriftListImpl<T>.Add(const Value: T): Integer;

-begin

-  Result := FList.Add( Value );

-end;

-

-procedure TThriftListImpl<T>.AddRange(Collection: TEnumerable<T>);

-begin

-  FList.AddRange( Collection );

-end;

-

-procedure TThriftListImpl<T>.AddRange(const Collection: IEnumerable<T>);

-begin

-  FList.AddRange( Collection );

-end;

-

-procedure TThriftListImpl<T>.AddRange(const Values: array of T);

-begin

-  FList.AddRange( Values );

-end;

-

-function TThriftListImpl<T>.BinarySearch(const Item: T;

-  out Index: Integer): Boolean;

-begin

-  Result := FList.BinarySearch( Item, Index);

-end;

-

-function TThriftListImpl<T>.BinarySearch(const Item: T; out Index: Integer;

-  const AComparer: IComparer<T>): Boolean;

-begin

-  Result := FList.BinarySearch( Item, Index, AComparer);

-end;

-

-procedure TThriftListImpl<T>.Clear;

-begin

-  FList.Clear;

-end;

-

-function TThriftListImpl<T>.Contains(const Value: T): Boolean;

-begin

-  Result := FList.Contains( Value );

-end;

-

-constructor TThriftListImpl<T>.Create;

-begin

-  FList := TList<T>.Create;

-end;

-

-procedure TThriftListImpl<T>.Delete(Index: Integer);

-begin

-  FList.Delete( Index )

-end;

-

-procedure TThriftListImpl<T>.DeleteRange(AIndex, ACount: Integer);

-begin

-  FList.DeleteRange( AIndex, ACount)

-end;

-

-destructor TThriftListImpl<T>.Destroy;

-begin

-  FList.Free;

-  inherited;

-end;

-

-{$IF CompilerVersion >= 21.0}

-procedure TThriftListImpl<T>.Exchange(Index1, Index2: Integer);

-begin

-  FList.Exchange( Index1, Index2 )

-end;

-{$IFEND}

-

-function TThriftListImpl<T>.Extract(const Value: T): T;

-begin

-  Result := FList.Extract( Value )

-end;

-

-{$IF CompilerVersion >= 21.0}

-function TThriftListImpl<T>.First: T;

-begin

-  Result := FList.First;

-end;

-{$IFEND}

-

-function TThriftListImpl<T>.GetCapacity: Integer;

-begin

-  Result := FList.Capacity;

-end;

-

-function TThriftListImpl<T>.GetCount: Integer;

-begin

-  Result := FList.Count;

-end;

-

-function TThriftListImpl<T>.GetEnumerator: TEnumerator<T>;

-begin

-  Result := FList.GetEnumerator;

-end;

-

-function TThriftListImpl<T>.GetItem(Index: Integer): T;

-begin

-  Result := FList[Index];

-end;

-

-function TThriftListImpl<T>.IndexOf(const Value: T): Integer;

-begin

-  Result := FList.IndexOf( Value );

-end;

-

-procedure TThriftListImpl<T>.Insert(Index: Integer; const Value: T);

-begin

-  FList.Insert( Index, Value);

-end;

-

-procedure TThriftListImpl<T>.InsertRange(Index: Integer;

-  const Collection: TEnumerable<T>);

-begin

-  FList.InsertRange( Index, Collection );

-end;

-

-procedure TThriftListImpl<T>.InsertRange(Index: Integer;

-  const Values: array of T);

-begin

-  FList.InsertRange( Index, Values);

-end;

-

-procedure TThriftListImpl<T>.InsertRange(Index: Integer;

-  const Collection: IEnumerable<T>);

-begin

-  FList.InsertRange( Index, Collection );

-end;

-

-{$IF CompilerVersion >= 21.0}

-function TThriftListImpl<T>.Last: T;

-begin

-  Result := FList.Last;

-end;

-{$IFEND}

-

-function TThriftListImpl<T>.LastIndexOf(const Value: T): Integer;

-begin

-  Result := FList.LastIndexOf( Value );

-end;

-

-{$IF CompilerVersion >= 21.0}

-procedure TThriftListImpl<T>.Move(CurIndex, NewIndex: Integer);

-begin

-  FList.Move( CurIndex,  NewIndex);

-end;

-{$IFEND}

-

-function TThriftListImpl<T>.Remove(const Value: T): Integer;

-begin

-  Result := FList.Remove( Value );

-end;

-

-procedure TThriftListImpl<T>.Reverse;

-begin

-  FList.Reverse;

-end;

-

-procedure TThriftListImpl<T>.SetCapacity(Value: Integer);

-begin

-  FList.Capacity := Value;

-end;

-

-procedure TThriftListImpl<T>.SetCount(Value: Integer);

-begin

-  FList.Count := Value;

-end;

-

-procedure TThriftListImpl<T>.SetItem(Index: Integer; const Value: T);

-begin

-  FList[Index] := Value;

-end;

-

-procedure TThriftListImpl<T>.Sort;

-begin

-  FList.Sort;

-end;

-

-procedure TThriftListImpl<T>.Sort(const AComparer: IComparer<T>);

-begin

-  FList.Sort;

-end;

-

-function TThriftListImpl<T>.ToArray: TArray<T>;

-{$IF CompilerVersion < 22.0}

-var

-  x : T;

-  i : Integer;

-{$IFEND}

-begin

-{$IF CompilerVersion < 22.0}

-  SetLength(Result, Count);

-  i := 0;

-  for x in FList do

-  begin

-    Result[i] := x;

-    Inc( i );

-  end;

-{$ELSE}

-  Result := FList.ToArray;

-{$IFEND}

-end;

-

-procedure TThriftListImpl<T>.TrimExcess;

-begin

-  FList.TrimExcess;

-end;

-

-end.

+(*
+ * 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.
+ *)
+
+unit Thrift.Collections;
+
+interface
+
+uses
+  Generics.Collections, Generics.Defaults, Thrift.Utils;
+
+type
+
+{$IF CompilerVersion < 21.0}
+  TArray<T> = array of T;
+{$IFEND}
+
+  IThriftContainer = interface
+    ['{93DEF5A0-D162-461A-AB22-5B4EE0734050}']
+    function ToString: string;
+  end;
+
+  IThriftDictionary<TKey,TValue> = interface(IThriftContainer)
+    ['{25EDD506-F9D1-4008-A40F-5940364B7E46}']
+    function GetEnumerator: TEnumerator<TPair<TKey,TValue>>;
+
+    function GetKeys: TDictionary<TKey,TValue>.TKeyCollection;
+    function GetValues: TDictionary<TKey,TValue>.TValueCollection;
+    function GetItem(const Key: TKey): TValue;
+    procedure SetItem(const Key: TKey; const Value: TValue);
+    function GetCount: Integer;
+
+    procedure Add(const Key: TKey; const Value: TValue);
+    procedure Remove(const Key: TKey);
+{$IF CompilerVersion >= 21.0}
+    function ExtractPair(const Key: TKey): TPair<TKey,TValue>;
+{$IFEND}
+    procedure Clear;
+    procedure TrimExcess;
+    function TryGetValue(const Key: TKey; out Value: TValue): Boolean;
+    procedure AddOrSetValue(const Key: TKey; const Value: TValue);
+    function ContainsKey(const Key: TKey): Boolean;
+    function ContainsValue(const Value: TValue): Boolean;
+    function ToArray: TArray<TPair<TKey,TValue>>;
+
+    property Items[const Key: TKey]: TValue read GetItem write SetItem; default;
+    property Count: Integer read GetCount;
+    property Keys: TDictionary<TKey,TValue>.TKeyCollection read GetKeys;
+    property Values: TDictionary<TKey,TValue>.TValueCollection read GetValues;
+  end;
+
+  TThriftDictionaryImpl<TKey,TValue> = class( TInterfacedObject, IThriftDictionary<TKey,TValue>)
+  private
+    FDictionaly : TDictionary<TKey,TValue>;
+  protected
+    function GetEnumerator: TEnumerator<TPair<TKey,TValue>>;
+
+    function GetKeys: TDictionary<TKey,TValue>.TKeyCollection;
+    function GetValues: TDictionary<TKey,TValue>.TValueCollection;
+    function GetItem(const Key: TKey): TValue;
+    procedure SetItem(const Key: TKey; const Value: TValue);
+    function GetCount: Integer;
+
+    procedure Add(const Key: TKey; const Value: TValue);
+    procedure Remove(const Key: TKey);
+{$IF CompilerVersion >= 21.0}
+    function ExtractPair(const Key: TKey): TPair<TKey,TValue>;
+{$IFEND}
+    procedure Clear;
+    procedure TrimExcess;
+    function TryGetValue(const Key: TKey; out Value: TValue): Boolean;
+    procedure AddOrSetValue(const Key: TKey; const Value: TValue);
+    function ContainsKey(const Key: TKey): Boolean;
+    function ContainsValue(const Value: TValue): Boolean;
+    function ToArray: TArray<TPair<TKey,TValue>>;
+    property Items[const Key: TKey]: TValue read GetItem write SetItem; default;
+    property Count: Integer read GetCount;
+    property Keys: TDictionary<TKey,TValue>.TKeyCollection read GetKeys;
+    property Values: TDictionary<TKey,TValue>.TValueCollection read GetValues;
+  public
+    constructor Create(ACapacity: Integer = 0);
+    destructor Destroy; override;
+  end;
+
+  IThriftList<T> = interface(IThriftContainer)
+    ['{29BEEE31-9CB4-401B-AA04-5148A75F473B}']
+    function GetEnumerator: TEnumerator<T>;
+    function GetCapacity: Integer;
+    procedure SetCapacity(Value: Integer);
+    function GetCount: Integer;
+    procedure SetCount(Value: Integer);
+    function GetItem(Index: Integer): T;
+    procedure SetItem(Index: Integer; const Value: T);
+    function Add(const Value: T): Integer;
+    procedure AddRange(const Values: array of T); overload;
+    procedure AddRange(const Collection: IEnumerable<T>); overload;
+    procedure AddRange(Collection: TEnumerable<T>); overload;
+    procedure Insert(Index: Integer; const Value: T);
+    procedure InsertRange(Index: Integer; const Values: array of T); overload;
+    procedure InsertRange(Index: Integer; const Collection: IEnumerable<T>); overload;
+    procedure InsertRange(Index: Integer; const Collection: TEnumerable<T>); overload;
+    function Remove(const Value: T): Integer;
+    procedure Delete(Index: Integer);
+    procedure DeleteRange(AIndex, ACount: Integer);
+    function Extract(const Value: T): T;
+{$IF CompilerVersion >= 21.0}
+    procedure Exchange(Index1, Index2: Integer);
+    procedure Move(CurIndex, NewIndex: Integer);
+    function First: T;
+    function Last: T;
+{$IFEND}
+    procedure Clear;
+    function Contains(const Value: T): Boolean;
+    function IndexOf(const Value: T): Integer;
+    function LastIndexOf(const Value: T): Integer;
+    procedure Reverse;
+    procedure Sort; overload;
+    procedure Sort(const AComparer: IComparer<T>); overload;
+    function BinarySearch(const Item: T; out Index: Integer): Boolean; overload;
+    function BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean; overload;
+    procedure TrimExcess;
+    function ToArray: TArray<T>;
+    property Capacity: Integer read GetCapacity write SetCapacity;
+    property Count: Integer read GetCount write SetCount;
+    property Items[Index: Integer]: T read GetItem write SetItem; default;
+  end;
+
+  TThriftListImpl<T> = class( TInterfacedObject, IThriftList<T>)
+  private
+    FList : TList<T>;
+  protected
+    function GetEnumerator: TEnumerator<T>;
+    function GetCapacity: Integer;
+    procedure SetCapacity(Value: Integer);
+    function GetCount: Integer;
+    procedure SetCount(Value: Integer);
+    function GetItem(Index: Integer): T;
+    procedure SetItem(Index: Integer; const Value: T);
+    function Add(const Value: T): Integer;
+    procedure AddRange(const Values: array of T); overload;
+    procedure AddRange(const Collection: IEnumerable<T>); overload;
+    procedure AddRange(Collection: TEnumerable<T>); overload;
+    procedure Insert(Index: Integer; const Value: T);
+    procedure InsertRange(Index: Integer; const Values: array of T); overload;
+    procedure InsertRange(Index: Integer; const Collection: IEnumerable<T>); overload;
+    procedure InsertRange(Index: Integer; const Collection: TEnumerable<T>); overload;
+    function Remove(const Value: T): Integer;
+    procedure Delete(Index: Integer);
+    procedure DeleteRange(AIndex, ACount: Integer);
+    function Extract(const Value: T): T;
+{$IF CompilerVersion >= 21.0}
+    procedure Exchange(Index1, Index2: Integer);
+    procedure Move(CurIndex, NewIndex: Integer);
+    function First: T;
+    function Last: T;
+{$IFEND}
+    procedure Clear;
+    function Contains(const Value: T): Boolean;
+    function IndexOf(const Value: T): Integer;
+    function LastIndexOf(const Value: T): Integer;
+    procedure Reverse;
+    procedure Sort; overload;
+    procedure Sort(const AComparer: IComparer<T>); overload;
+    function BinarySearch(const Item: T; out Index: Integer): Boolean; overload;
+    function BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean; overload;
+    procedure TrimExcess;
+    function ToArray: TArray<T>;
+    property Capacity: Integer read GetCapacity write SetCapacity;
+    property Count: Integer read GetCount write SetCount;
+    property Items[Index: Integer]: T read GetItem write SetItem; default;
+  public
+    constructor Create;
+    destructor Destroy; override;
+  end;
+
+  IHashSet<TValue> = interface(IThriftContainer)
+    ['{0923A3B5-D4D4-48A8-91AD-40238E2EAD66}']
+    function GetEnumerator: TEnumerator<TValue>;
+    function GetIsReadOnly: Boolean;
+    function GetCount: Integer;
+    property Count: Integer read GetCount;
+    property IsReadOnly: Boolean read GetIsReadOnly;
+    procedure Add( const item: TValue);
+    procedure Clear;
+    function Contains( const item: TValue): Boolean;
+    procedure CopyTo(var A: TArray<TValue>; arrayIndex: Integer);
+    function Remove( const item: TValue ): Boolean;
+  end;
+
+  THashSetImpl<TValue> = class( TInterfacedObject, IHashSet<TValue>)
+  private
+    FDictionary : IThriftDictionary<TValue,Integer>;
+    FIsReadOnly: Boolean;
+  protected
+    function GetEnumerator: TEnumerator<TValue>;
+    function GetIsReadOnly: Boolean;
+    function GetCount: Integer;
+    property Count: Integer read GetCount;
+    property IsReadOnly: Boolean read FIsReadOnly;
+    procedure Add( const item: TValue);
+    procedure Clear;
+    function Contains( const item: TValue): Boolean;
+    procedure CopyTo(var A: TArray<TValue>; arrayIndex: Integer);
+    function Remove( const item: TValue ): Boolean;
+  public
+    constructor Create;
+  end;
+
+implementation
+
+{ THashSetImpl<TValue> }
+
+procedure THashSetImpl<TValue>.Add( const item: TValue);
+begin
+  if not FDictionary.ContainsKey(item) then
+  begin
+    FDictionary.Add( item, 0);
+  end;
+end;
+
+procedure THashSetImpl<TValue>.Clear;
+begin
+  FDictionary.Clear;
+end;
+
+function THashSetImpl<TValue>.Contains( const item: TValue): Boolean;
+begin
+  Result := FDictionary.ContainsKey(item);
+end;
+
+procedure THashSetImpl<TValue>.CopyTo(var A: TArray<TValue>; arrayIndex: Integer);
+var
+  i : Integer;
+  Enumlator : TEnumerator<TValue>;
+begin
+  Enumlator := GetEnumerator;
+  while Enumlator.MoveNext do
+  begin
+    A[arrayIndex] := Enumlator.Current;
+    Inc(arrayIndex);
+  end;
+end;
+
+constructor THashSetImpl<TValue>.Create;
+begin
+  inherited;
+  FDictionary := TThriftDictionaryImpl<TValue,Integer>.Create;
+end;
+
+function THashSetImpl<TValue>.GetCount: Integer;
+begin
+  Result := FDictionary.Count;
+end;
+
+function THashSetImpl<TValue>.GetEnumerator: TEnumerator<TValue>;
+begin
+  Result := FDictionary.Keys.GetEnumerator;
+end;
+
+function THashSetImpl<TValue>.GetIsReadOnly: Boolean;
+begin
+  Result := FIsReadOnly;
+end;
+
+function THashSetImpl<TValue>.Remove( const item: TValue): Boolean;
+begin
+  Result := False;
+  if FDictionary.ContainsKey( item ) then
+  begin
+    FDictionary.Remove( item );
+    Result := not FDictionary.ContainsKey( item );
+  end;
+end;
+
+{ TThriftDictionaryImpl<TKey, TValue> }
+
+procedure TThriftDictionaryImpl<TKey, TValue>.Add(const Key: TKey;
+  const Value: TValue);
+begin
+  FDictionaly.Add( Key, Value);
+end;
+
+procedure TThriftDictionaryImpl<TKey, TValue>.AddOrSetValue(const Key: TKey;
+  const Value: TValue);
+begin
+  FDictionaly.AddOrSetValue( Key, Value);
+end;
+
+procedure TThriftDictionaryImpl<TKey, TValue>.Clear;
+begin
+  FDictionaly.Clear;
+end;
+
+function TThriftDictionaryImpl<TKey, TValue>.ContainsKey(
+  const Key: TKey): Boolean;
+begin
+  Result := FDictionaly.ContainsKey( Key );
+end;
+
+function TThriftDictionaryImpl<TKey, TValue>.ContainsValue(
+  const Value: TValue): Boolean;
+begin
+  Result := FDictionaly.ContainsValue( Value );
+end;
+
+constructor TThriftDictionaryImpl<TKey, TValue>.Create(ACapacity: Integer);
+begin
+  inherited Create;
+  FDictionaly := TDictionary<TKey,TValue>.Create( ACapacity );
+end;
+
+destructor TThriftDictionaryImpl<TKey, TValue>.Destroy;
+begin
+  FDictionaly.Free;
+  inherited;
+end;
+
+{$IF CompilerVersion >= 21.0}
+function TThriftDictionaryImpl<TKey, TValue>.ExtractPair( const Key: TKey): TPair<TKey, TValue>;
+begin
+  Result := FDictionaly.ExtractPair( Key);
+end;
+{$IFEND}
+
+function TThriftDictionaryImpl<TKey, TValue>.GetCount: Integer;
+begin
+  Result := FDictionaly.Count;
+end;
+
+function TThriftDictionaryImpl<TKey, TValue>.GetEnumerator: TEnumerator<TPair<TKey, TValue>>;
+begin
+  Result := FDictionaly.GetEnumerator;
+end;
+
+function TThriftDictionaryImpl<TKey, TValue>.GetItem(const Key: TKey): TValue;
+begin
+  Result := FDictionaly.Items[Key];
+end;
+
+function TThriftDictionaryImpl<TKey, TValue>.GetKeys: TDictionary<TKey, TValue>.TKeyCollection;
+begin
+  Result := FDictionaly.Keys;
+end;
+
+function TThriftDictionaryImpl<TKey, TValue>.GetValues: TDictionary<TKey, TValue>.TValueCollection;
+begin
+  Result := FDictionaly.Values;
+end;
+
+procedure TThriftDictionaryImpl<TKey, TValue>.Remove(const Key: TKey);
+begin
+  FDictionaly.Remove( Key );
+end;
+
+procedure TThriftDictionaryImpl<TKey, TValue>.SetItem(const Key: TKey;
+  const Value: TValue);
+begin
+  FDictionaly.AddOrSetValue( Key, Value);
+end;
+
+function TThriftDictionaryImpl<TKey, TValue>.ToArray: TArray<TPair<TKey, TValue>>;
+{$IF CompilerVersion < 22.0}
+var
+  x : TPair<TKey, TValue>;
+  i : Integer;
+{$IFEND}
+begin
+{$IF CompilerVersion < 22.0}
+  SetLength(Result, Count);
+  i := 0;
+  for x in FDictionaly do
+  begin
+    Result[i] := x;
+    Inc( i );
+  end;
+{$ELSE}
+  Result := FDictionaly.ToArray;
+{$IFEND}
+end;
+
+procedure TThriftDictionaryImpl<TKey, TValue>.TrimExcess;
+begin
+  FDictionaly.TrimExcess;
+end;
+
+function TThriftDictionaryImpl<TKey, TValue>.TryGetValue(const Key: TKey;
+  out Value: TValue): Boolean;
+begin
+  Result := FDictionaly.TryGetValue( Key, Value);
+end;
+
+{ TThriftListImpl<T> }
+
+function TThriftListImpl<T>.Add(const Value: T): Integer;
+begin
+  Result := FList.Add( Value );
+end;
+
+procedure TThriftListImpl<T>.AddRange(Collection: TEnumerable<T>);
+begin
+  FList.AddRange( Collection );
+end;
+
+procedure TThriftListImpl<T>.AddRange(const Collection: IEnumerable<T>);
+begin
+  FList.AddRange( Collection );
+end;
+
+procedure TThriftListImpl<T>.AddRange(const Values: array of T);
+begin
+  FList.AddRange( Values );
+end;
+
+function TThriftListImpl<T>.BinarySearch(const Item: T;
+  out Index: Integer): Boolean;
+begin
+  Result := FList.BinarySearch( Item, Index);
+end;
+
+function TThriftListImpl<T>.BinarySearch(const Item: T; out Index: Integer;
+  const AComparer: IComparer<T>): Boolean;
+begin
+  Result := FList.BinarySearch( Item, Index, AComparer);
+end;
+
+procedure TThriftListImpl<T>.Clear;
+begin
+  FList.Clear;
+end;
+
+function TThriftListImpl<T>.Contains(const Value: T): Boolean;
+begin
+  Result := FList.Contains( Value );
+end;
+
+constructor TThriftListImpl<T>.Create;
+begin
+  inherited;
+  FList := TList<T>.Create;
+end;
+
+procedure TThriftListImpl<T>.Delete(Index: Integer);
+begin
+  FList.Delete( Index )
+end;
+
+procedure TThriftListImpl<T>.DeleteRange(AIndex, ACount: Integer);
+begin
+  FList.DeleteRange( AIndex, ACount)
+end;
+
+destructor TThriftListImpl<T>.Destroy;
+begin
+  FList.Free;
+  inherited;
+end;
+
+{$IF CompilerVersion >= 21.0}
+procedure TThriftListImpl<T>.Exchange(Index1, Index2: Integer);
+begin
+  FList.Exchange( Index1, Index2 )
+end;
+{$IFEND}
+
+function TThriftListImpl<T>.Extract(const Value: T): T;
+begin
+  Result := FList.Extract( Value )
+end;
+
+{$IF CompilerVersion >= 21.0}
+function TThriftListImpl<T>.First: T;
+begin
+  Result := FList.First;
+end;
+{$IFEND}
+
+function TThriftListImpl<T>.GetCapacity: Integer;
+begin
+  Result := FList.Capacity;
+end;
+
+function TThriftListImpl<T>.GetCount: Integer;
+begin
+  Result := FList.Count;
+end;
+
+function TThriftListImpl<T>.GetEnumerator: TEnumerator<T>;
+begin
+  Result := FList.GetEnumerator;
+end;
+
+function TThriftListImpl<T>.GetItem(Index: Integer): T;
+begin
+  Result := FList[Index];
+end;
+
+function TThriftListImpl<T>.IndexOf(const Value: T): Integer;
+begin
+  Result := FList.IndexOf( Value );
+end;
+
+procedure TThriftListImpl<T>.Insert(Index: Integer; const Value: T);
+begin
+  FList.Insert( Index, Value);
+end;
+
+procedure TThriftListImpl<T>.InsertRange(Index: Integer;
+  const Collection: TEnumerable<T>);
+begin
+  FList.InsertRange( Index, Collection );
+end;
+
+procedure TThriftListImpl<T>.InsertRange(Index: Integer;
+  const Values: array of T);
+begin
+  FList.InsertRange( Index, Values);
+end;
+
+procedure TThriftListImpl<T>.InsertRange(Index: Integer;
+  const Collection: IEnumerable<T>);
+begin
+  FList.InsertRange( Index, Collection );
+end;
+
+{$IF CompilerVersion >= 21.0}
+function TThriftListImpl<T>.Last: T;
+begin
+  Result := FList.Last;
+end;
+{$IFEND}
+
+function TThriftListImpl<T>.LastIndexOf(const Value: T): Integer;
+begin
+  Result := FList.LastIndexOf( Value );
+end;
+
+{$IF CompilerVersion >= 21.0}
+procedure TThriftListImpl<T>.Move(CurIndex, NewIndex: Integer);
+begin
+  FList.Move( CurIndex,  NewIndex);
+end;
+{$IFEND}
+
+function TThriftListImpl<T>.Remove(const Value: T): Integer;
+begin
+  Result := FList.Remove( Value );
+end;
+
+procedure TThriftListImpl<T>.Reverse;
+begin
+  FList.Reverse;
+end;
+
+procedure TThriftListImpl<T>.SetCapacity(Value: Integer);
+begin
+  FList.Capacity := Value;
+end;
+
+procedure TThriftListImpl<T>.SetCount(Value: Integer);
+begin
+  FList.Count := Value;
+end;
+
+procedure TThriftListImpl<T>.SetItem(Index: Integer; const Value: T);
+begin
+  FList[Index] := Value;
+end;
+
+procedure TThriftListImpl<T>.Sort;
+begin
+  FList.Sort;
+end;
+
+procedure TThriftListImpl<T>.Sort(const AComparer: IComparer<T>);
+begin
+  FList.Sort;
+end;
+
+function TThriftListImpl<T>.ToArray: TArray<T>;
+{$IF CompilerVersion < 22.0}
+var
+  x : T;
+  i : Integer;
+{$IFEND}
+begin
+{$IF CompilerVersion < 22.0}
+  SetLength(Result, Count);
+  i := 0;
+  for x in FList do
+  begin
+    Result[i] := x;
+    Inc( i );
+  end;
+{$ELSE}
+  Result := FList.ToArray;
+{$IFEND}
+end;
+
+procedure TThriftListImpl<T>.TrimExcess;
+begin
+  FList.TrimExcess;
+end;
+
+end.
diff --git a/lib/delphi/src/Thrift.Console.pas b/lib/delphi/src/Thrift.Console.pas
deleted file mode 100644
index 324efc3..0000000
--- a/lib/delphi/src/Thrift.Console.pas
+++ /dev/null
@@ -1,132 +0,0 @@
-(*

- * Licensed to the Apache Software Foundation (ASF) under one

- * or more contributor license agreements. See the NOTICE file

- * distributed with this work for additional information

- * regarding copyright ownership. The ASF licenses this file

- * to you under the Apache License, Version 2.0 (the

- * "License"); you may not use this file except in compliance

- * with the License. You may obtain a copy of the License at

- *

- *   http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing,

- * software distributed under the License is distributed on an

- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

- * KIND, either express or implied. See the License for the

- * specific language governing permissions and limitations

- * under the License.

- *)

-

-unit Thrift.Console;

-

-interface

-

-uses

-  StdCtrls;

-

-type

-  TThriftConsole = class

-  public

-    procedure Write( const S: string); virtual;

-    procedure WriteLine( const S: string); virtual;

-  end;

-

-  TGUIConsole = class( TThriftConsole )

-  private

-    FLineBreak : Boolean;

-    FMemo : TMemo;

-

-    procedure InternalWrite( const S: string; bWriteLine: Boolean);

-  public

-    procedure Write( const S: string); override;

-    procedure WriteLine( const S: string); override;

-    constructor Create( AMemo: TMemo);

-  end;

-

-function Console: TThriftConsole;

-procedure ChangeConsole( AConsole: TThriftConsole );

-procedure RestoreConsoleToDefault;

-

-implementation

-

-var

-  FDefaultConsole : TThriftConsole;

-  FConsole : TThriftConsole;

-

-function Console: TThriftConsole;

-begin

-  Result := FConsole;

-end;

-

-{ TThriftConsole }

-

-procedure TThriftConsole.Write(const S: string);

-begin

-  System.Write( S );

-end;

-

-procedure TThriftConsole.WriteLine(const S: string);

-begin

-  System.Writeln( S );

-end;

-

-procedure ChangeConsole( AConsole: TThriftConsole );

-begin

-  FConsole := AConsole;

-end;

-

-procedure RestoreConsoleToDefault;

-begin

-  FConsole := FDefaultConsole;

-end;

-

-{ TGUIConsole }

-

-constructor TGUIConsole.Create( AMemo: TMemo);

-begin

-  FMemo := AMemo;

-  FLineBreak := True;

-end;

-

-procedure TGUIConsole.InternalWrite(const S: string; bWriteLine: Boolean);

-var

-  idx : Integer;

-begin

-  if FLineBreak then

-  begin

-    FMemo.Lines.Add( S );

-  end else

-  begin

-    idx := FMemo.Lines.Count - 1;

-    if idx < 0 then

-    begin

-      FMemo.Lines.Add( S );

-    end;

-    FMemo.Lines[idx] := FMemo.Lines[idx] + S;

-  end;

-  FLineBreak := bWriteLine;

-end;

-

-procedure TGUIConsole.Write(const S: string);

-begin

-  InternalWrite( S, False);

-end;

-

-procedure TGUIConsole.WriteLine(const S: string);

-begin

-  InternalWrite( S, True);

-end;

-

-initialization

-begin

-  FDefaultConsole := TThriftConsole.Create;

-  FConsole := FDefaultConsole;

-end;

-

-finalization

-begin

-  FDefaultConsole.Free;

-end;

-

-end.

-

diff --git a/lib/delphi/src/Thrift.Defines.inc b/lib/delphi/src/Thrift.Defines.inc
new file mode 100644
index 0000000..499ccae
--- /dev/null
+++ b/lib/delphi/src/Thrift.Defines.inc
@@ -0,0 +1,50 @@
+(*
+ * 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.
+ *)
+
+
+// Good lists of Delphi version numbers
+// https://github.com/project-jedi/jedi/blob/master/jedi.inc
+// http://docwiki.embarcadero.com/RADStudio/Seattle/en/Compiler_Versions
+
+
+// start with most backwards compatible defaults
+
+{$DEFINE OLD_UNIT_NAMES}
+{$DEFINE OLD_SOCKETS}      // TODO: add socket support for CompilerVersion >= 28.0
+{$UNDEF HAVE_CLASS_CTOR}
+
+
+// enable features as they are available
+
+{$IF CompilerVersion >= 21.0}   // Delphi 2010
+  {$DEFINE HAVE_CLASS_CTOR}
+{$IFEND}
+
+{$IF CompilerVersion >= 23.0}   // Delphi XE2
+  {$UNDEF OLD_UNIT_NAMES}
+{$IFEND}
+
+{$IF CompilerVersion >= 28.0}   // Delphi XE7
+  {$UNDEF OLD_SOCKETS}
+{$IFEND}
+
+
+// EOF
+
+
diff --git a/lib/delphi/src/Thrift.Exception.pas b/lib/delphi/src/Thrift.Exception.pas
new file mode 100644
index 0000000..5d15c36
--- /dev/null
+++ b/lib/delphi/src/Thrift.Exception.pas
@@ -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.
+ *)
+
+{$SCOPEDENUMS ON}
+
+unit Thrift.Exception;
+
+interface
+
+uses
+  Classes, SysUtils;
+
+type
+  // base class for all Thrift exceptions
+  TException = class( SysUtils.Exception)
+  public
+    function Message : string;        // hide inherited property: allow read, but prevent accidental writes
+    procedure UpdateMessageProperty;  // update inherited message property with toString()
+  end;
+
+
+
+
+implementation
+
+{ TException }
+
+function TException.Message;
+// allow read (exception summary), but prevent accidental writes
+// read will return the exception summary
+begin
+  result := Self.ToString;
+end;
+
+procedure TException.UpdateMessageProperty;
+// Update the inherited Message property to better conform to standard behaviour.
+// Nice benefit: The IDE is now able to show the exception message again.
+begin
+  inherited Message := Self.ToString;  // produces a summary text
+end;
+
+
+
+
+end.
+
diff --git a/lib/delphi/src/Thrift.Processor.Multiplex.pas b/lib/delphi/src/Thrift.Processor.Multiplex.pas
index 8d6d8b0..8cf23db 100644
--- a/lib/delphi/src/Thrift.Processor.Multiplex.pas
+++ b/lib/delphi/src/Thrift.Processor.Multiplex.pas
@@ -1,22 +1,22 @@
 (*
- * 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.

- *)

-

+ * 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.
+ *)
+
 unit Thrift.Processor.Multiplex;
 
 
@@ -53,11 +53,11 @@
 
 type
   IMultiplexedProcessor = interface( IProcessor)
-    ['{810FF32D-22A2-4D58-B129-B0590703ECEC}']

+    ['{807F9D19-6CF4-4789-840E-93E87A12EB63}']
     // Register a service with this TMultiplexedProcessor.  This allows us
     // to broker requests to individual services by using the service name
     // to select them at request time.
-    procedure RegisterProcessor( const serviceName : String; const processor : IProcessor);
+    procedure RegisterProcessor( const serviceName : String; const processor : IProcessor; const asDefault : Boolean = FALSE);
   end;
 
 
@@ -68,17 +68,18 @@
     // the standard format, without the service name prepended to TMessage.name.
     TStoredMessageProtocol = class( TProtocolDecorator)
     private
-      FMessageBegin : IMessage;
+      FMessageBegin : TThriftMessage;
     public
-      constructor Create( const protocol : IProtocol; const aMsgBegin : IMessage);
-      function ReadMessageBegin: IMessage; override;
+      constructor Create( const protocol : IProtocol; const aMsgBegin : TThriftMessage);
+      function ReadMessageBegin: TThriftMessage; override;
     end;
 
   private
     FServiceProcessorMap : TDictionary<String, IProcessor>;
+    FDefaultProcessor : IProcessor;
 
-    procedure Error( const oprot : IProtocol; const msg : IMessage;
-                     extype : TApplicationException.TExceptionType; const etxt : string);
+    procedure Error( const oprot : IProtocol; const msg : TThriftMessage;
+                     extype : TApplicationExceptionSpecializedClass; const etxt : string);
 
   public
     constructor Create;
@@ -87,7 +88,7 @@
     // Register a service with this TMultiplexedProcessorImpl.  This allows us
     // to broker requests to individual services by using the service name
     // to select them at request time.
-    procedure RegisterProcessor( const serviceName : String; const processor : IProcessor);
+    procedure RegisterProcessor( const serviceName : String; const processor : IProcessor; const asDefault : Boolean = FALSE);
 
     { This implementation of process performs the following steps:
       - Read the beginning of the message.
@@ -99,20 +100,20 @@
       An exception is thrown if the message type is not CALL or ONEWAY
       or if the service is unknown (or not properly registered).
     }
-    function Process(const iprot, oprot : IProtocol) : Boolean;
+    function Process( const iprot, oprot: IProtocol; const events : IProcessorEvents = nil): Boolean;
   end;
 
 
 implementation
 
-constructor TMultiplexedProcessorImpl.TStoredMessageProtocol.Create( const protocol : IProtocol; const aMsgBegin : IMessage);
+constructor TMultiplexedProcessorImpl.TStoredMessageProtocol.Create( const protocol : IProtocol; const aMsgBegin : TThriftMessage);
 begin
   inherited Create( protocol);
   FMessageBegin := aMsgBegin;
 end;
 
 
-function TMultiplexedProcessorImpl.TStoredMessageProtocol.ReadMessageBegin: IMessage;
+function TMultiplexedProcessorImpl.TStoredMessageProtocol.ReadMessageBegin: TThriftMessage;
 begin
   result := FMessageBegin;
 end;
@@ -135,35 +136,41 @@
 end;
 
 
-procedure TMultiplexedProcessorImpl.RegisterProcessor( const serviceName : String; const processor : IProcessor);
+procedure TMultiplexedProcessorImpl.RegisterProcessor( const serviceName : String; const processor : IProcessor; const asDefault : Boolean);
 begin
   FServiceProcessorMap.Add( serviceName, processor);
+
+  if asDefault then begin
+    if FDefaultProcessor = nil
+    then FDefaultProcessor := processor
+    else raise TApplicationExceptionInternalError.Create('Only one default service allowed');
+  end;
 end;
 
 
-procedure TMultiplexedProcessorImpl.Error( const oprot : IProtocol; const msg : IMessage;
-                                           extype : TApplicationException.TExceptionType;
+procedure TMultiplexedProcessorImpl.Error( const oprot : IProtocol; const msg : TThriftMessage;
+                                           extype : TApplicationExceptionSpecializedClass;
                                            const etxt : string);
 var appex  : TApplicationException;
-    newMsg : IMessage;
+    newMsg : TThriftMessage;
 begin
-  appex := TApplicationException.Create( extype, etxt);
+  appex := extype.Create(etxt);
   try
-    newMsg := TMessageImpl.Create( msg.Name, TMessageType.Exception, msg.SeqID);
-

+    Init( newMsg, msg.Name, TMessageType.Exception, msg.SeqID);
+
     oprot.WriteMessageBegin(newMsg);
     appex.Write(oprot);
     oprot.WriteMessageEnd();
     oprot.Transport.Flush();
 
   finally
-    appex.Free;

+    appex.Free;
   end;
 end;
 
 
-function TMultiplexedProcessorImpl.Process(const iprot, oprot : IProtocol) : Boolean;
-var msg, newMsg : IMessage;
+function TMultiplexedProcessorImpl.Process(const iprot, oprot : IProtocol; const events : IProcessorEvents = nil): Boolean;
+var msg, newMsg : TThriftMessage;
     idx         : Integer;
     sService    : string;
     processor   : IProcessor;
@@ -178,39 +185,47 @@
   msg := iprot.readMessageBegin();
   if not (msg.Type_ in [TMessageType.Call, TMessageType.Oneway]) then begin
     Error( oprot, msg,
-           TApplicationException.TExceptionType.InvalidMessageType,
+           TApplicationExceptionInvalidMessageType,
            ERROR_INVALID_MSGTYPE);
-    Exit( FALSE);

-  end;

-

+    Exit( FALSE);
+  end;
+
   // Extract the service name
+  // use FDefaultProcessor as fallback if there is no separator
   idx := Pos( TMultiplexedProtocol.SEPARATOR, msg.Name);
-  if idx < 1 then begin
+  if idx > 0 then begin
+
+    // Create a new TMessage, something that can be consumed by any TProtocol
+    sService := Copy( msg.Name, 1, idx-1);
+    if not FServiceProcessorMap.TryGetValue( sService, processor)
+    then begin
+      Error( oprot, msg,
+             TApplicationExceptionInternalError,
+             Format(ERROR_UNKNOWN_SERVICE,[sService]));
+      Exit( FALSE);
+    end;
+
+    // Create a new TMessage, removing the service name
+    Inc( idx, Length(TMultiplexedProtocol.SEPARATOR));
+    Init( newMsg, Copy( msg.Name, idx, MAXINT), msg.Type_, msg.SeqID);
+
+  end
+  else if FDefaultProcessor <> nil then begin
+    processor := FDefaultProcessor;
+    newMsg    := msg;  // no need to change
+
+  end
+  else begin
     Error( oprot, msg,
-           TApplicationException.TExceptionType.InvalidProtocol,
+           TApplicationExceptionInvalidProtocol,
            Format(ERROR_INCOMPATIBLE_PROT,[msg.Name]));
     Exit( FALSE);
-  end;

-
-  // Create a new TMessage, something that can be consumed by any TProtocol
-  sService := Copy( msg.Name, 1, idx-1);
-  if not FServiceProcessorMap.TryGetValue( sService, processor)
-  then begin
-    Error( oprot, msg,
-           TApplicationException.TExceptionType.InternalError,
-           Format(ERROR_UNKNOWN_SERVICE,[sService]));
-    Exit( FALSE);
-  end;

-
-  // Create a new TMessage, removing the service name
-  Inc( idx, Length(TMultiplexedProtocol.SEPARATOR));
-  newMsg := TMessageImpl.Create( Copy( msg.Name, idx, MAXINT), msg.Type_, msg.SeqID);
+  end;
 
   // Dispatch processing to the stored processor
   protocol := TStoredMessageProtocol.Create( iprot, newMsg);
-  result   := processor.process( protocol, oprot);
+  result   := processor.process( protocol, oprot, events);
 end;
 
 
 end.
-
diff --git a/lib/delphi/src/Thrift.Protocol.Compact.pas b/lib/delphi/src/Thrift.Protocol.Compact.pas
new file mode 100644
index 0000000..1c1b3da
--- /dev/null
+++ b/lib/delphi/src/Thrift.Protocol.Compact.pas
@@ -0,0 +1,1117 @@
+(*
+ * 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.
+ *)
+
+{$SCOPEDENUMS ON}
+
+unit Thrift.Protocol.Compact;
+
+interface
+
+uses
+  Classes,
+  SysUtils,
+  Math,
+  Generics.Collections,
+  Thrift.Transport,
+  Thrift.Protocol,
+  Thrift.Utils;
+
+type
+  ICompactProtocol = interface( IProtocol)
+    ['{C01927EC-021A-45F7-93B1-23D6A5420EDD}']
+  end;
+
+  // Compact protocol implementation for thrift.
+  // Adapted from the C# version.
+  TCompactProtocolImpl = class( TProtocolImpl, ICompactProtocol)
+  public
+    type
+      TFactory = class( TInterfacedObject, IProtocolFactory)
+      public
+        function GetProtocol( const trans: ITransport): IProtocol;
+      end;
+
+  private const
+
+    { TODO
+    static TStruct ANONYMOUS_STRUCT = new TStruct("");
+    static TField TSTOP = new TField("", TType.Stop, (short)0);
+    }
+
+    PROTOCOL_ID       = Byte( $82);
+    VERSION           = Byte( 1);
+    VERSION_MASK      = Byte( $1F); // 0001 1111
+    TYPE_MASK         = Byte( $E0); // 1110 0000
+    TYPE_BITS         = Byte( $07); // 0000 0111
+    TYPE_SHIFT_AMOUNT = Byte( 5);
+
+  private type
+    // All of the on-wire type codes.
+    Types = (
+      STOP          = $00,
+      BOOLEAN_TRUE  = $01,
+      BOOLEAN_FALSE = $02,
+      BYTE_         = $03,
+      I16           = $04,
+      I32           = $05,
+      I64           = $06,
+      DOUBLE_       = $07,
+      BINARY        = $08,
+      LIST          = $09,
+      SET_          = $0A,
+      MAP           = $0B,
+      STRUCT        = $0C
+    );
+
+  private const
+    ttypeToCompactType : array[TType] of Types = (
+      Types.STOP,           // Stop    = 0,
+      Types(-1),            // Void    = 1,
+      Types.BOOLEAN_TRUE,   // Bool_   = 2,
+      Types.BYTE_,          // Byte_   = 3,
+      Types.DOUBLE_,        // Double_ = 4,
+      Types(-5),            // unused
+      Types.I16,            // I16     = 6,
+      Types(-7),            // unused
+      Types.I32,            // I32     = 8,
+      Types(-9),            // unused
+      Types.I64,            // I64     = 10,
+      Types.BINARY,         // String_ = 11,
+      Types.STRUCT,         // Struct  = 12,
+      Types.MAP,            // Map     = 13,
+      Types.SET_,           // Set_    = 14,
+      Types.LIST            // List    = 15,
+    );
+
+    tcompactTypeToType : array[Types] of TType = (
+      TType.Stop,       // STOP
+      TType.Bool_,      // BOOLEAN_TRUE
+      TType.Bool_,      // BOOLEAN_FALSE
+      TType.Byte_,      // BYTE_
+      TType.I16,        // I16
+      TType.I32,        // I32
+      TType.I64,        // I64
+      TType.Double_,    // DOUBLE_
+      TType.String_,    // BINARY
+      TType.List,       // LIST
+      TType.Set_,       // SET_
+      TType.Map,        // MAP
+      TType.Struct      // STRUCT
+    );
+
+  private
+    // Used to keep track of the last field for the current and previous structs,
+    // so we can do the delta stuff.
+    lastField_ : TStack<Integer>;
+    lastFieldId_ : Integer;
+
+    // If we encounter a boolean field begin, save the TField here so it can
+    // have the value incorporated.
+    private booleanField_ : TThriftField;
+
+    // If we Read a field header, and it's a boolean field, save the boolean
+    // value here so that ReadBool can use it.
+    private  boolValue_  : ( unused, bool_true, bool_false);
+
+  public
+    constructor Create(const trans : ITransport);
+    destructor Destroy;  override;
+
+    procedure Reset;
+
+  private
+    procedure WriteByteDirect( const b : Byte);  overload;
+
+    // Writes a byte without any possibility of all that field header nonsense.
+    procedure WriteByteDirect( const n : Integer);  overload;
+
+    // Write an i32 as a varint. Results in 1-5 bytes on the wire.
+    // TODO: make a permanent buffer like WriteVarint64?
+    procedure WriteVarint32( n : Cardinal);
+
+  private
+    // 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.
+    procedure WriteFieldBeginInternal( const field : TThriftField; typeOverride : Byte);
+
+  public
+    procedure WriteMessageBegin( const msg: TThriftMessage); override;
+    procedure WriteMessageEnd; override;
+    procedure WriteStructBegin( const struc: TThriftStruct); override;
+    procedure WriteStructEnd; override;
+    procedure WriteFieldBegin( const field: TThriftField); override;
+    procedure WriteFieldEnd; override;
+    procedure WriteFieldStop; override;
+    procedure WriteMapBegin( const map: TThriftMap); override;
+    procedure WriteMapEnd; override;
+    procedure WriteListBegin( const list: TThriftList); override;
+    procedure WriteListEnd(); override;
+    procedure WriteSetBegin( const set_: TThriftSet ); override;
+    procedure WriteSetEnd(); override;
+    procedure WriteBool( b: Boolean); override;
+    procedure WriteByte( b: ShortInt); override;
+    procedure WriteI16( i16: SmallInt); override;
+    procedure WriteI32( i32: Integer); override;
+    procedure WriteI64( const i64: Int64); override;
+    procedure WriteDouble( const dub: Double); override;
+    procedure WriteBinary( const b: TBytes); overload; override;
+
+  private
+    class function  DoubleToInt64Bits( const db : Double) : Int64;
+    class function  Int64BitsToDouble( const i64 : Int64) : Double;
+
+    // Abstract method for writing the start of lists and sets. List and sets on
+    // the wire differ only by the type indicator.
+    procedure WriteCollectionBegin( const elemType : TType; size : Integer);
+
+    procedure WriteVarint64( n : UInt64);
+
+    // Convert l into a zigzag long. This allows negative numbers to be
+    // represented compactly as a varint.
+    class function  longToZigzag( const n : Int64) : UInt64;
+
+    // Convert n into a zigzag int. This allows negative numbers to be
+    // represented compactly as a varint.
+    class function intToZigZag( const n : Integer) : Cardinal;
+
+    //Convert a Int64 into little-endian bytes in buf starting at off and going until off+7.
+    class procedure fixedLongToBytes( const n : Int64; var buf : TBytes);
+
+  public
+    function  ReadMessageBegin: TThriftMessage; override;
+    procedure ReadMessageEnd(); override;
+    function  ReadStructBegin: TThriftStruct; override;
+    procedure ReadStructEnd; override;
+    function  ReadFieldBegin: TThriftField; override;
+    procedure ReadFieldEnd(); override;
+    function  ReadMapBegin: TThriftMap; override;
+    procedure ReadMapEnd(); override;
+    function  ReadListBegin: TThriftList; override;
+    procedure ReadListEnd(); override;
+    function  ReadSetBegin: TThriftSet; override;
+    procedure ReadSetEnd(); override;
+    function  ReadBool: Boolean; override;
+    function  ReadByte: ShortInt; override;
+    function  ReadI16: SmallInt; override;
+    function  ReadI32: Integer; override;
+    function  ReadI64: Int64; override;
+    function  ReadDouble:Double; override;
+    function  ReadBinary: TBytes; overload; override;
+
+  private
+    // 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.
+    function ReadVarint32 : Cardinal;
+
+    // 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.
+    function ReadVarint64 : UInt64;
+
+
+    // encoding helpers
+
+    // Convert from zigzag Integer to Integer.
+    class function zigzagToInt( const n : Cardinal ) : Integer;
+
+    // Convert from zigzag Int64 to Int64.
+    class function zigzagToLong( const n : UInt64) : Int64;
+
+    // Note that it's important that the mask bytes are Int64 literals,
+    // otherwise they'll default to ints, and when you shift an Integer left 56 bits,
+    // you just get a messed up Integer.
+    class function bytesToLong( const bytes : TBytes) : Int64;
+
+    // type testing and converting
+    class function isBoolType( const b : byte) : Boolean;
+
+    // Given a TCompactProtocol.Types constant, convert it to its corresponding TType value.
+    class function getTType( const type_ : byte) : TType;
+
+    // Given a TType value, find the appropriate TCompactProtocol.Types constant.
+    class function getCompactType( const ttype : TType) : Byte;
+  end;
+
+
+implementation
+
+
+
+//--- TCompactProtocolImpl.TFactory ----------------------------------------
+
+
+function TCompactProtocolImpl.TFactory.GetProtocol( const trans: ITransport): IProtocol;
+begin
+  result := TCompactProtocolImpl.Create( trans);
+end;
+
+
+//--- TCompactProtocolImpl -------------------------------------------------
+
+
+constructor TCompactProtocolImpl.Create(const trans: ITransport);
+begin
+  inherited Create( trans);
+
+  lastFieldId_ := 0;
+  lastField_ := TStack<Integer>.Create;
+
+  Init( booleanField_, '', TType.Stop, 0);
+  boolValue_ := unused;
+end;
+
+
+destructor TCompactProtocolImpl.Destroy;
+begin
+  try
+    FreeAndNil( lastField_);
+  finally
+    inherited Destroy;
+  end;
+end;
+
+
+
+procedure TCompactProtocolImpl.Reset;
+begin
+  lastField_.Clear();
+  lastFieldId_ := 0;
+  Init( booleanField_, '', TType.Stop, 0);
+  boolValue_ := unused;
+end;
+
+
+// Writes a byte without any possibility of all that field header nonsense.
+// Used internally by other writing methods that know they need to Write a byte.
+procedure TCompactProtocolImpl.WriteByteDirect( const b : Byte);
+begin
+  Transport.Write( @b, SizeOf(b));
+end;
+
+
+// Writes a byte without any possibility of all that field header nonsense.
+procedure TCompactProtocolImpl.WriteByteDirect( const n : Integer);
+begin
+  WriteByteDirect( Byte(n));
+end;
+
+
+// Write an i32 as a varint. Results in 1-5 bytes on the wire.
+procedure TCompactProtocolImpl.WriteVarint32( n : Cardinal);
+var i32buf : TBytes;
+    idx : Integer;
+begin
+  SetLength( i32buf, 5);
+  idx := 0;
+  while TRUE do begin
+    ASSERT( idx < Length(i32buf));
+
+    // last part?
+    if ((n and not $7F) = 0) then begin
+      i32buf[idx] := Byte(n);
+      Inc(idx);
+      Break;
+    end;
+
+    i32buf[idx] := Byte((n and $7F) or $80);
+    Inc(idx);
+    n := n shr 7;
+  end;
+
+  Transport.Write( i32buf, 0, idx);
+end;
+
+
+// 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.
+procedure TCompactProtocolImpl.WriteMessageBegin( const msg: TThriftMessage);
+var versionAndType : Byte;
+begin
+  Reset;
+
+  versionAndType := Byte( VERSION and VERSION_MASK)
+                 or Byte( (Cardinal(msg.Type_) shl TYPE_SHIFT_AMOUNT) and TYPE_MASK);
+
+  WriteByteDirect( PROTOCOL_ID);
+  WriteByteDirect( versionAndType);
+  WriteVarint32( Cardinal(msg.SeqID));
+  WriteString( msg.Name);
+end;
+
+
+// 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.
+procedure TCompactProtocolImpl.WriteStructBegin( const struc: TThriftStruct);
+begin
+  lastField_.Push(lastFieldId_);
+  lastFieldId_ := 0;
+end;
+
+
+// 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.
+procedure TCompactProtocolImpl.WriteStructEnd;
+begin
+  lastFieldId_ := lastField_.Pop();
+end;
+
+
+// Write a field header containing the field id and field type. If the difference between the
+// current field id and the last one is small (< 15), then the field id will be encoded in
+// the 4 MSB as a delta. Otherwise, the field id will follow the type header as a zigzag varint.
+procedure TCompactProtocolImpl.WriteFieldBegin( const field: TThriftField);
+begin
+  case field.Type_ of
+    TType.Bool_ : booleanField_ := field; // we want to possibly include the value, so we'll wait.
+  else
+    WriteFieldBeginInternal(field, $FF);
+  end;
+end;
+
+
+// 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.
+procedure TCompactProtocolImpl.WriteFieldBeginInternal( const field : TThriftField; typeOverride : Byte);
+var typeToWrite : Byte;
+begin
+  // if there's a type override, use that.
+  if typeOverride = $FF
+  then typeToWrite := getCompactType( field.Type_)
+  else typeToWrite := typeOverride;
+
+  // check if we can use delta encoding for the field id
+  if (field.ID > lastFieldId_) and ((field.ID - lastFieldId_) <= 15)
+  then begin
+    // Write them together
+    WriteByteDirect( ((field.ID - lastFieldId_) shl 4) or typeToWrite);
+  end
+  else begin
+    // Write them separate
+    WriteByteDirect( typeToWrite);
+    WriteI16( field.ID);
+  end;
+
+  lastFieldId_ := field.ID;
+end;
+
+
+// Write the STOP symbol so we know there are no more fields in this struct.
+procedure TCompactProtocolImpl.WriteFieldStop;
+begin
+  WriteByteDirect( Byte( Types.STOP));
+end;
+
+
+// Write a map header. If the map is empty, omit the key and value type
+// headers, as we don't need any additional information to skip it.
+procedure TCompactProtocolImpl.WriteMapBegin( const map: TThriftMap);
+var key, val : Byte;
+begin
+  if (map.Count = 0)
+  then WriteByteDirect( 0)
+  else begin
+    WriteVarint32( Cardinal( map.Count));
+    key := getCompactType(map.KeyType);
+    val := getCompactType(map.ValueType);
+    WriteByteDirect( (key shl 4) or val);
+  end;
+end;
+
+
+// Write a list header.
+procedure TCompactProtocolImpl.WriteListBegin( const list: TThriftList);
+begin
+  WriteCollectionBegin( list.ElementType, list.Count);
+end;
+
+
+// Write a set header.
+procedure TCompactProtocolImpl.WriteSetBegin( const set_: TThriftSet );
+begin
+  WriteCollectionBegin( set_.ElementType, set_.Count);
+end;
+
+
+// Write a boolean value. Potentially, this could be a boolean field, in
+// which case the field header info isn't written yet. If so, decide what the
+// right type header is for the value and then Write the field header.
+// Otherwise, Write a single byte.
+procedure TCompactProtocolImpl.WriteBool( b: Boolean);
+var bt : Types;
+begin
+  if b
+  then bt := Types.BOOLEAN_TRUE
+  else bt := Types.BOOLEAN_FALSE;
+
+  if booleanField_.Type_ = TType.Bool_ then begin
+    // we haven't written the field header yet
+    WriteFieldBeginInternal( booleanField_, Byte(bt));
+    booleanField_.Type_ := TType.Stop;
+  end
+  else begin
+    // we're not part of a field, so just Write the value.
+    WriteByteDirect( Byte(bt));
+  end;
+end;
+
+
+// Write a byte. Nothing to see here!
+procedure TCompactProtocolImpl.WriteByte( b: ShortInt);
+begin
+  WriteByteDirect( Byte(b));
+end;
+
+
+// Write an I16 as a zigzag varint.
+procedure TCompactProtocolImpl.WriteI16( i16: SmallInt);
+begin
+  WriteVarint32( intToZigZag( i16));
+end;
+
+
+// Write an i32 as a zigzag varint.
+procedure TCompactProtocolImpl.WriteI32( i32: Integer);
+begin
+  WriteVarint32( intToZigZag( i32));
+end;
+
+
+// Write an i64 as a zigzag varint.
+procedure TCompactProtocolImpl.WriteI64( const i64: Int64);
+begin
+  WriteVarint64( longToZigzag( i64));
+end;
+
+
+class function TCompactProtocolImpl.DoubleToInt64Bits( const db : Double) : Int64;
+begin
+  ASSERT( SizeOf(db) = SizeOf(result));
+  Move( db, result, SizeOf(result));
+end;
+
+
+class function TCompactProtocolImpl.Int64BitsToDouble( const i64 : Int64) : Double;
+begin
+  ASSERT( SizeOf(i64) = SizeOf(result));
+  Move( i64, result, SizeOf(result));
+end;
+
+
+// Write a double to the wire as 8 bytes.
+procedure TCompactProtocolImpl.WriteDouble( const dub: Double);
+var data : TBytes;
+begin
+  fixedLongToBytes( DoubleToInt64Bits(dub), data);
+  Transport.Write( data);
+end;
+
+
+// Write a byte array, using a varint for the size.
+procedure TCompactProtocolImpl.WriteBinary( const b: TBytes);
+begin
+  WriteVarint32( Cardinal(Length(b)));
+  Transport.Write( b);
+end;
+
+procedure TCompactProtocolImpl.WriteMessageEnd;
+begin
+  // nothing to do
+end;
+
+
+procedure TCompactProtocolImpl.WriteMapEnd;
+begin
+  // nothing to do
+end;
+
+
+procedure TCompactProtocolImpl.WriteListEnd;
+begin
+  // nothing to do
+end;
+
+
+procedure TCompactProtocolImpl.WriteSetEnd;
+begin
+  // nothing to do
+end;
+
+
+procedure TCompactProtocolImpl.WriteFieldEnd;
+begin
+  // nothing to do
+end;
+
+
+// Abstract method for writing the start of lists and sets. List and sets on
+// the wire differ only by the type indicator.
+procedure TCompactProtocolImpl.WriteCollectionBegin( const elemType : TType; size : Integer);
+begin
+  if size <= 14
+  then WriteByteDirect( (size shl 4) or getCompactType(elemType))
+  else begin
+    WriteByteDirect( $F0 or getCompactType(elemType));
+    WriteVarint32( Cardinal(size));
+  end;
+end;
+
+
+// Write an i64 as a varint. Results in 1-10 bytes on the wire.
+procedure TCompactProtocolImpl.WriteVarint64( n : UInt64);
+var varint64out : TBytes;
+    idx : Integer;
+begin
+  SetLength( varint64out, 10);
+  idx := 0;
+  while TRUE do begin
+    ASSERT( idx < Length(varint64out));
+
+    // last one?
+    if (n and not UInt64($7F)) = 0 then begin
+      varint64out[idx] := Byte(n);
+      Inc(idx);
+      Break;
+    end;
+
+    varint64out[idx] := Byte((n and $7F) or $80);
+    Inc(idx);
+    n := n shr 7;
+  end;
+
+  Transport.Write( varint64out, 0, idx);
+end;
+
+
+// Convert l into a zigzag Int64. This allows negative numbers to be
+// represented compactly as a varint.
+class function TCompactProtocolImpl.longToZigzag( const n : Int64) : UInt64;
+begin
+  // there is no arithmetic right shift in Delphi
+  if n >= 0
+  then result := UInt64(n shl 1)
+  else result := UInt64(n shl 1) xor $FFFFFFFFFFFFFFFF;
+end;
+
+
+// Convert n into a zigzag Integer. This allows negative numbers to be
+// represented compactly as a varint.
+class function TCompactProtocolImpl.intToZigZag( const n : Integer) : Cardinal;
+begin
+  // there is no arithmetic right shift in Delphi
+  if n >= 0
+  then result := Cardinal(n shl 1)
+  else result := Cardinal(n shl 1) xor $FFFFFFFF;
+end;
+
+
+// Convert a Int64 into 8 little-endian bytes in buf
+class procedure TCompactProtocolImpl.fixedLongToBytes( const n : Int64; var buf : TBytes);
+begin
+  SetLength( buf, 8);
+  buf[0] := Byte( n         and $FF);
+  buf[1] := Byte((n shr 8)  and $FF);
+  buf[2] := Byte((n shr 16) and $FF);
+  buf[3] := Byte((n shr 24) and $FF);
+  buf[4] := Byte((n shr 32) and $FF);
+  buf[5] := Byte((n shr 40) and $FF);
+  buf[6] := Byte((n shr 48) and $FF);
+  buf[7] := Byte((n shr 56) and $FF);
+end;
+
+
+
+// Read a message header.
+function TCompactProtocolImpl.ReadMessageBegin : TThriftMessage;
+var protocolId, versionAndType, version, type_ : Byte;
+    seqid : Integer;
+    msgNm : String;
+begin
+  Reset;
+
+  protocolId := Byte( ReadByte);
+  if (protocolId <> PROTOCOL_ID)
+  then raise TProtocolExceptionBadVersion.Create( 'Expected protocol id ' + IntToHex(PROTOCOL_ID,2)
+                                                + ' but got ' + IntToHex(protocolId,2));
+
+  versionAndType := Byte( ReadByte);
+  version        := Byte( versionAndType and VERSION_MASK);
+  if (version <> VERSION)
+  then raise TProtocolExceptionBadVersion.Create( 'Expected version ' +IntToStr(VERSION)
+                                                + ' but got ' + IntToStr(version));
+
+  type_ := Byte( (versionAndType shr TYPE_SHIFT_AMOUNT) and TYPE_BITS);
+  seqid := Integer( ReadVarint32);
+  msgNm := ReadString;
+  Init( result, msgNm, TMessageType(type_), seqid);
+end;
+
+
+// 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.
+function TCompactProtocolImpl.ReadStructBegin: TThriftStruct;
+begin
+  lastField_.Push( lastFieldId_);
+  lastFieldId_ := 0;
+  Init( result);
+end;
+
+
+// Doesn't actually consume any wire data, just removes the last field for
+// this struct from the field stack.
+procedure TCompactProtocolImpl.ReadStructEnd;
+begin
+  // consume the last field we Read off the wire.
+  lastFieldId_ := lastField_.Pop();
+end;
+
+
+// Read a field header off the wire.
+function TCompactProtocolImpl.ReadFieldBegin: TThriftField;
+var type_ : Byte;
+    fieldId, modifier : ShortInt;
+begin
+  type_ := Byte( ReadByte);
+
+  // if it's a stop, then we can return immediately, as the struct is over.
+  if type_ = Byte(Types.STOP) then begin
+    Init( result, '', TType.Stop, 0);
+    Exit;
+  end;
+
+  // mask off the 4 MSB of the type header. it could contain a field id delta.
+  modifier := ShortInt( (type_ and $F0) shr 4);
+  if (modifier = 0)
+  then fieldId := ReadI16    // not a delta. look ahead for the zigzag varint field id.
+  else fieldId := ShortInt( lastFieldId_ + modifier); // add the delta to the last Read field id.
+
+  Init( result, '', getTType(Byte(type_ and $0F)), fieldId);
+
+  // if this happens to be a boolean field, the value is encoded in the type
+   // save the boolean value in a special instance variable.
+  if isBoolType(type_) then begin
+    if Byte(type_ and $0F) = Byte(Types.BOOLEAN_TRUE)
+    then boolValue_ := bool_true
+    else boolValue_ := bool_false;
+  end;
+
+  // push the new field onto the field stack so we can keep the deltas going.
+  lastFieldId_ := result.ID;
+end;
+
+
+// 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.
+function TCompactProtocolImpl.ReadMapBegin: TThriftMap;
+var size : Integer;
+    keyAndValueType : Byte;
+    key, val : TType;
+begin
+  size := Integer( ReadVarint32);
+  if size = 0
+  then keyAndValueType := 0
+  else keyAndValueType := Byte( ReadByte);
+
+  key := getTType( Byte( keyAndValueType shr 4));
+  val := getTType( Byte( keyAndValueType and $F));
+  Init( result, key, val, size);
+  ASSERT( (result.KeyType = key) and (result.ValueType = val));
+end;
+
+
+// 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 $F, and a varint will follow with the
+// true size.
+function TCompactProtocolImpl.ReadListBegin: TThriftList;
+var size_and_type : Byte;
+    size : Integer;
+    type_ : TType;
+begin
+  size_and_type := Byte( ReadByte);
+
+  size := (size_and_type shr 4) and $0F;
+  if (size = 15)
+  then size := Integer( ReadVarint32);
+
+  type_ := getTType( size_and_type);
+  Init( result, type_, size);
+end;
+
+
+// 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 $F, and a varint will follow with the
+// true size.
+function TCompactProtocolImpl.ReadSetBegin: TThriftSet;
+var size_and_type : Byte;
+    size : Integer;
+    type_ : TType;
+begin
+  size_and_type := Byte( ReadByte);
+
+  size := (size_and_type shr 4) and $0F;
+  if (size = 15)
+  then size := Integer( ReadVarint32);
+
+  type_ := getTType( size_and_type);
+  Init( result, type_, size);
+end;
+
+
+// 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.
+function TCompactProtocolImpl.ReadBool: Boolean;
+begin
+  if boolValue_ <> unused then begin
+    result := (boolValue_ = bool_true);
+    boolValue_ := unused;
+    Exit;
+  end;
+
+  result := (Byte(ReadByte) = Byte(Types.BOOLEAN_TRUE));
+end;
+
+
+// Read a single byte off the wire. Nothing interesting here.
+function TCompactProtocolImpl.ReadByte: ShortInt;
+begin
+  Transport.ReadAll( @result, SizeOf(result), 0, 1);
+end;
+
+
+// Read an i16 from the wire as a zigzag varint.
+function TCompactProtocolImpl.ReadI16: SmallInt;
+begin
+  result := SmallInt( zigzagToInt( ReadVarint32));
+end;
+
+
+// Read an i32 from the wire as a zigzag varint.
+function TCompactProtocolImpl.ReadI32: Integer;
+begin
+  result := zigzagToInt( ReadVarint32);
+end;
+
+
+// Read an i64 from the wire as a zigzag varint.
+function TCompactProtocolImpl.ReadI64: Int64;
+begin
+  result := zigzagToLong( ReadVarint64);
+end;
+
+
+// No magic here - just Read a double off the wire.
+function TCompactProtocolImpl.ReadDouble:Double;
+var longBits : TBytes;
+begin
+  SetLength( longBits, 8);
+  Transport.ReadAll( longBits, 0, 8);
+  result := Int64BitsToDouble( bytesToLong( longBits));
+end;
+
+
+// Read a byte[] from the wire.
+function TCompactProtocolImpl.ReadBinary: TBytes;
+var length : Integer;
+begin
+  length := Integer( ReadVarint32);
+  SetLength( result, length);
+  if (length > 0)
+  then Transport.ReadAll( result, 0, length);
+end;
+
+
+procedure TCompactProtocolImpl.ReadMessageEnd;
+begin
+  // nothing to do
+end;
+
+
+procedure TCompactProtocolImpl.ReadFieldEnd;
+begin
+  // nothing to do
+end;
+
+
+procedure TCompactProtocolImpl.ReadMapEnd;
+begin
+  // nothing to do
+end;
+
+
+procedure TCompactProtocolImpl.ReadListEnd;
+begin
+  // nothing to do
+end;
+
+
+procedure TCompactProtocolImpl.ReadSetEnd;
+begin
+  // nothing to do
+end;
+
+
+
+// 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.
+function TCompactProtocolImpl.ReadVarint32 : Cardinal;
+var shift : Integer;
+    b : Byte;
+begin
+  result := 0;
+  shift  := 0;
+  while TRUE do begin
+    b := Byte( ReadByte);
+    result := result or (Cardinal(b and $7F) shl shift);
+    if ((b and $80) <> $80)
+    then Break;
+    Inc( shift, 7);
+  end;
+end;
+
+
+// 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.
+function TCompactProtocolImpl.ReadVarint64 : UInt64;
+var shift : Integer;
+    b : Byte;
+begin
+  result := 0;
+  shift  := 0;
+  while TRUE do begin
+    b := Byte( ReadByte);
+    result := result or (UInt64(b and $7F) shl shift);
+    if ((b and $80) <> $80)
+    then Break;
+    Inc( shift, 7);
+  end;
+end;
+
+
+// Convert from zigzag Integer to Integer.
+class function TCompactProtocolImpl.zigzagToInt( const n : Cardinal ) : Integer;
+begin
+  result := Integer(n shr 1) xor (-Integer(n and 1));
+end;
+
+
+// Convert from zigzag Int64 to Int64.
+class function TCompactProtocolImpl.zigzagToLong( const n : UInt64) : Int64;
+begin
+  result := Int64(n shr 1) xor (-Int64(n and 1));
+end;
+
+
+// Note that it's important that the mask bytes are Int64 literals,
+// otherwise they'll default to ints, and when you shift an Integer left 56 bits,
+// you just get a messed up Integer.
+class function TCompactProtocolImpl.bytesToLong( const bytes : TBytes) : Int64;
+begin
+  ASSERT( Length(bytes) >= 8);
+  result := (Int64(bytes[7] and $FF) shl 56) or
+            (Int64(bytes[6] and $FF) shl 48) or
+            (Int64(bytes[5] and $FF) shl 40) or
+            (Int64(bytes[4] and $FF) shl 32) or
+            (Int64(bytes[3] and $FF) shl 24) or
+            (Int64(bytes[2] and $FF) shl 16) or
+            (Int64(bytes[1] and $FF) shl  8) or
+            (Int64(bytes[0] and $FF));
+end;
+
+
+class function TCompactProtocolImpl.isBoolType( const b : byte) : Boolean;
+var lowerNibble : Byte;
+begin
+  lowerNibble := b and $0f;
+  result := (Types(lowerNibble) in [Types.BOOLEAN_TRUE, Types.BOOLEAN_FALSE]);
+end;
+
+
+// Given a TCompactProtocol.Types constant, convert it to its corresponding TType value.
+class function TCompactProtocolImpl.getTType( const type_ : byte) : TType;
+var tct : Types;
+begin
+  tct := Types( type_ and $0F);
+  if tct in [Low(Types)..High(Types)]
+  then result := tcompactTypeToType[tct]
+  else raise TProtocolExceptionInvalidData.Create('don''t know what type: '+IntToStr(Ord(tct)));
+end;
+
+
+// Given a TType value, find the appropriate TCompactProtocol.Types constant.
+class function TCompactProtocolImpl.getCompactType( const ttype : TType) : Byte;
+begin
+  if ttype in VALID_TTYPES
+  then result := Byte( ttypeToCompactType[ttype])
+  else raise TProtocolExceptionInvalidData.Create('don''t know what type: '+IntToStr(Ord(ttype)));
+end;
+
+
+//--- unit tests -------------------------------------------
+
+{$IFDEF Debug}
+procedure TestDoubleToInt64Bits;
+
+  procedure TestPair( const a : Double; const b : Int64);
+  begin
+    ASSERT( TCompactProtocolImpl.DoubleToInt64Bits(a) = b);
+    ASSERT( TCompactProtocolImpl.Int64BitsToDouble(b) = a);
+  end;
+
+begin
+  TestPair( 1.0000000000000000E+000,  Int64($3FF0000000000000));
+  TestPair( 1.5000000000000000E+001,  Int64($402E000000000000));
+  TestPair( 2.5500000000000000E+002,  Int64($406FE00000000000));
+  TestPair( 4.2949672950000000E+009,  Int64($41EFFFFFFFE00000));
+  TestPair( 3.9062500000000000E-003,  Int64($3F70000000000000));
+  TestPair( 2.3283064365386963E-010,  Int64($3DF0000000000000));
+  TestPair( 1.2345678901230000E-300,  Int64($01AA74FE1C1E7E45));
+  TestPair( 1.2345678901234500E-150,  Int64($20D02A36586DB4BB));
+  TestPair( 1.2345678901234565E+000,  Int64($3FF3C0CA428C59FA));
+  TestPair( 1.2345678901234567E+000,  Int64($3FF3C0CA428C59FB));
+  TestPair( 1.2345678901234569E+000,  Int64($3FF3C0CA428C59FC));
+  TestPair( 1.2345678901234569E+150,  Int64($5F182344CD3CDF9F));
+  TestPair( 1.2345678901234569E+300,  Int64($7E3D7EE8BCBBD352));
+  TestPair( -1.7976931348623157E+308, Int64($FFEFFFFFFFFFFFFF));
+  TestPair( 1.7976931348623157E+308,  Int64($7FEFFFFFFFFFFFFF));
+  TestPair( 4.9406564584124654E-324,  Int64($0000000000000001));
+  TestPair( 0.0000000000000000E+000,  Int64($0000000000000000));
+  TestPair( 4.94065645841247E-324,    Int64($0000000000000001));
+  TestPair( 3.2378592100206092E-319,  Int64($000000000000FFFF));
+  TestPair( 1.3906711615669959E-309,  Int64($0000FFFFFFFFFFFF));
+  TestPair( NegInfinity,              Int64($FFF0000000000000));
+  TestPair( Infinity,                 Int64($7FF0000000000000));
+
+  // NaN is special
+  ASSERT( TCompactProtocolImpl.DoubleToInt64Bits( NaN) = Int64($FFF8000000000000));
+  ASSERT( IsNan( TCompactProtocolImpl.Int64BitsToDouble( Int64($FFF8000000000000))));
+end;
+{$ENDIF}
+
+
+{$IFDEF Debug}
+procedure TestZigZag;
+
+  procedure Test32( const test : Integer);
+  var zz : Cardinal;
+  begin
+    zz := TCompactProtocolImpl.intToZigZag(test);
+    ASSERT( TCompactProtocolImpl.zigzagToInt(zz) = test, IntToStr(test));
+  end;
+
+  procedure Test64( const test : Int64);
+  var zz : UInt64;
+  begin
+    zz := TCompactProtocolImpl.longToZigzag(test);
+    ASSERT( TCompactProtocolImpl.zigzagToLong(zz) = test, IntToStr(test));
+  end;
+
+var i : Integer;
+begin
+  // protobuf testcases
+  ASSERT( TCompactProtocolImpl.intToZigZag(0)  = 0, 'pb #1 to ZigZag');
+  ASSERT( TCompactProtocolImpl.intToZigZag(-1) = 1, 'pb #2 to ZigZag');
+  ASSERT( TCompactProtocolImpl.intToZigZag(1)  = 2, 'pb #3 to ZigZag');
+  ASSERT( TCompactProtocolImpl.intToZigZag(-2) = 3, 'pb #4 to ZigZag');
+  ASSERT( TCompactProtocolImpl.intToZigZag(+2147483647) = 4294967294, 'pb #5 to ZigZag');
+  ASSERT( TCompactProtocolImpl.intToZigZag(-2147483648) = 4294967295, 'pb #6 to ZigZag');
+
+  // protobuf testcases
+  ASSERT( TCompactProtocolImpl.zigzagToInt(0)  = 0, 'pb #1 from ZigZag');
+  ASSERT( TCompactProtocolImpl.zigzagToInt(1) = -1, 'pb #2 from ZigZag');
+  ASSERT( TCompactProtocolImpl.zigzagToInt(2)  = 1, 'pb #3 from ZigZag');
+  ASSERT( TCompactProtocolImpl.zigzagToInt(3) = -2, 'pb #4 from ZigZag');
+  ASSERT( TCompactProtocolImpl.zigzagToInt(4294967294) = +2147483647, 'pb #5 from ZigZag');
+  ASSERT( TCompactProtocolImpl.zigzagToInt(4294967295) = -2147483648, 'pb #6 from ZigZag');
+
+  // back and forth 32
+  Test32( 0);
+  for i := 0 to 30 do begin
+    Test32( +(Integer(1) shl i));
+    Test32( -(Integer(1) shl i));
+  end;
+  Test32( Integer($7FFFFFFF));
+  Test32( Integer($80000000));
+
+  // back and forth 64
+  Test64( 0);
+  for i := 0 to 62 do begin
+    Test64( +(Int64(1) shl i));
+    Test64( -(Int64(1) shl i));
+  end;
+  Test64( Int64($7FFFFFFFFFFFFFFF));
+  Test64( Int64($8000000000000000));
+end;
+{$ENDIF}
+
+
+{$IFDEF Debug}
+procedure TestLongBytes;
+
+  procedure Test( const test : Int64);
+  var buf : TBytes;
+  begin
+    TCompactProtocolImpl.fixedLongToBytes( test, buf);
+    ASSERT( TCompactProtocolImpl.bytesToLong( buf) = test, IntToStr(test));
+  end;
+
+var i : Integer;
+begin
+  Test( 0);
+  for i := 0 to 62 do begin
+    Test( +(Int64(1) shl i));
+    Test( -(Int64(1) shl i));
+  end;
+  Test( Int64($7FFFFFFFFFFFFFFF));
+  Test( Int64($8000000000000000));
+end;
+{$ENDIF}
+
+
+{$IFDEF Debug}
+procedure UnitTest;
+var w : WORD;
+const FPU_CW_DENORMALIZED = $0002;
+begin
+  w := Get8087CW;
+  try
+    Set8087CW( w or FPU_CW_DENORMALIZED);
+
+    TestDoubleToInt64Bits;
+    TestZigZag;
+    TestLongBytes;
+
+  finally
+    Set8087CW( w);
+  end;
+end;
+{$ENDIF}
+
+
+initialization
+  {$IFDEF Debug}
+  UnitTest;
+  {$ENDIF}
+
+end.
+
diff --git a/lib/delphi/src/Thrift.Protocol.JSON.pas b/lib/delphi/src/Thrift.Protocol.JSON.pas
index 2cc4bbd..30600aa 100644
--- a/lib/delphi/src/Thrift.Protocol.JSON.pas
+++ b/lib/delphi/src/Thrift.Protocol.JSON.pas
@@ -24,13 +24,14 @@
 interface
 
 uses
+  Character,
   Classes,
   SysUtils,
   Math,
-  IdCoderMIME,
   Generics.Collections,
   Thrift.Transport,
-  Thrift.Protocol;
+  Thrift.Protocol,
+  Thrift.Utils;
 
 type
   IJSONProtocol = interface( IProtocol)
@@ -102,7 +103,7 @@
 
       private
         FHasData : Boolean;
-        FData    : TBytes;
+        FData    : Byte;
 
       public
         // Return and consume the next byte to be Read, either taking it from the
@@ -168,18 +169,18 @@
 
   public
     // IProtocol
-    procedure WriteMessageBegin( const aMsg : IMessage); override;
+    procedure WriteMessageBegin( const aMsg : TThriftMessage); override;
     procedure WriteMessageEnd; override;
-    procedure WriteStructBegin( const struc: IStruct); override;
+    procedure WriteStructBegin( const struc: TThriftStruct); override;
     procedure WriteStructEnd; override;
-    procedure WriteFieldBegin( const field: IField); override;
+    procedure WriteFieldBegin( const field: TThriftField); override;
     procedure WriteFieldEnd; override;
     procedure WriteFieldStop; override;
-    procedure WriteMapBegin( const map: IMap); override;
+    procedure WriteMapBegin( const map: TThriftMap); override;
     procedure WriteMapEnd; override;
-    procedure WriteListBegin( const list: IList); override;
+    procedure WriteListBegin( const list: TThriftList); override;
     procedure WriteListEnd(); override;
-    procedure WriteSetBegin( const set_: ISet ); override;
+    procedure WriteSetBegin( const set_: TThriftSet ); override;
     procedure WriteSetEnd(); override;
     procedure WriteBool( b: Boolean); override;
     procedure WriteByte( b: ShortInt); override;
@@ -190,17 +191,17 @@
     procedure WriteString( const s: string );   override;
     procedure WriteBinary( const b: TBytes); override;
     //
-    function ReadMessageBegin: IMessage; override;
+    function ReadMessageBegin: TThriftMessage; override;
     procedure ReadMessageEnd(); override;
-    function ReadStructBegin: IStruct; override;
+    function ReadStructBegin: TThriftStruct; override;
     procedure ReadStructEnd; override;
-    function ReadFieldBegin: IField; override;
+    function ReadFieldBegin: TThriftField; override;
     procedure ReadFieldEnd(); override;
-    function ReadMapBegin: IMap; override;
+    function ReadMapBegin: TThriftMap; override;
     procedure ReadMapEnd(); override;
-    function ReadListBegin: IList; override;
+    function ReadListBegin: TThriftList; override;
     procedure ReadListEnd(); override;
-    function ReadSetBegin: ISet; override;
+    function ReadSetBegin: TThriftSet; override;
     procedure ReadSetEnd(); override;
     function ReadBool: Boolean; override;
     function ReadByte: ShortInt; override;
@@ -254,7 +255,6 @@
   RBRACKET  : TBytes;
   QUOTE     : TBytes;
   BACKSLASH : TBytes;
-  ZERO      : TBytes;
   ESCSEQ    : TBytes;
 
 const
@@ -264,8 +264,8 @@
                      0,0,0,0, 0,0,0,0, 0,0,0,0,  0,0,0,0,
                      1,1,Byte('"'),1,  1,1,1,1, 1,1,1,1, 1,1,1,1);
 
-  ESCAPE_CHARS     = '"\btnfr';
-  ESCAPE_CHAR_VALS = '"\'#8#9#10#12#13;
+  ESCAPE_CHARS     = '"\/btnfr';
+  ESCAPE_CHAR_VALS = '"\/'#8#9#10#12#13;
 
   DEF_STRING_SIZE = 16;
 
@@ -310,7 +310,7 @@
     TType.Set_:     result := NAME_SET;
     TType.List:     result := NAME_LIST;
   else
-    raise TProtocolException.Create( TProtocolException.NOT_IMPLEMENTED, 'Unrecognized type ('+IntToStr(Ord(typeID))+')');
+    raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+IntToStr(Ord(typeID))+')');
   end;
 end;
 
@@ -328,7 +328,7 @@
   else if name = NAME_MAP    then result := TType.Map
   else if name = NAME_LIST   then result := TType.List
   else if name = NAME_SET    then result := TType.Set_
-  else raise TProtocolException.Create( TProtocolException.NOT_IMPLEMENTED, 'Unrecognized type ('+name+')');
+  else raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+name+')');
 end;
 
 
@@ -437,21 +437,19 @@
   if FHasData
   then FHasData := FALSE
   else begin
-    SetLength( FData, 1);
-    IJSONProtocol(FProto).Transport.ReadAll( FData, 0, 1);
+    IJSONProtocol(FProto).Transport.ReadAll( @FData, SizeOf(FData), 0, 1);
   end;
-  result := FData[0];
+  result := FData;
 end;
 
 
 function TJSONProtocolImpl.TLookaheadReader.Peek : Byte;
 begin
   if not FHasData then begin
-    SetLength( FData, 1);
-    IJSONProtocol(FProto).Transport.ReadAll( FData, 0, 1);
+    IJSONProtocol(FProto).Transport.ReadAll( @FData, SizeOf(FData), 0, 1);
     FHasData := TRUE;
   end;
-  result := FData[0];
+  result := FData;
 end;
 
 
@@ -506,7 +504,7 @@
 begin
   ch := FReader.Read;
   if (ch <> b)
-  then raise TProtocolException.Create( TProtocolException.INVALID_DATA, 'Unexpected character ('+Char(ch)+')');
+  then raise TProtocolExceptionInvalidData.Create('Unexpected character ('+Char(ch)+')');
 end;
 
 
@@ -516,7 +514,7 @@
   i := StrToIntDef( '$0'+Char(ch), -1);
   if (0 <= i) and (i < $10)
   then result := i
-  else raise TProtocolException.Create( TProtocolException.INVALID_DATA, 'Expected hex character ('+Char(ch)+')');
+  else raise TProtocolExceptionInvalidData.Create('Expected hex character ('+Char(ch)+')');
 end;
 
 
@@ -623,24 +621,29 @@
 
 
 procedure TJSONProtocolImpl.WriteJSONBase64( const b : TBytes);
-var str : string;
-    tmp : TBytes;
-    i   : Integer;
+var len, off, cnt : Integer;
+    tmpBuf : TBytes;
 begin
   FContext.Write;
   Transport.Write( QUOTE);
 
-  // First base64-encode b, then write the resulting 8-bit chars
-  // Unfortunately, EncodeBytes() returns a string of 16-bit (wide) chars
-  // And for the sake of efficiency, we want to write everything at once
-  str := TIdEncoderMIME.EncodeBytes(b);
-  ASSERT( SizeOf(str[1]) = SizeOf(Word));
-  SetLength( tmp, Length(str));
-  for i := 1 to Length(str) do begin
-    ASSERT( Hi(Word(str[i])) = 0);   // base64 consists of a well-defined set of 8-bit chars only
-    tmp[i-1] := Lo(Word(str[i]));    // extract the lower byte
+  len := Length(b);
+  off := 0;
+  SetLength( tmpBuf, 4);
+
+  while len >= 3 do begin
+    // Encode 3 bytes at a time
+    Base64Utils.Encode( b, off, 3, tmpBuf, 0);
+    Transport.Write( tmpBuf, 0, 4);
+    Inc( off, 3);
+    Dec( len, 3);
   end;
-  Transport.Write( tmp);  // now write all the data
+
+  // Encode remainder, if any
+  if len > 0 then begin
+    cnt := Base64Utils.Encode( b, off, len, tmpBuf, 0);
+    Transport.Write( tmpBuf, 0, cnt);
+  end;
 
   Transport.Write( QUOTE);
 end;
@@ -676,7 +679,7 @@
 end;
 
 
-procedure TJSONProtocolImpl.WriteMessageBegin( const aMsg : IMessage);
+procedure TJSONProtocolImpl.WriteMessageBegin( const aMsg : TThriftMessage);
 begin
   ResetContextStack;  // THRIFT-1473
 
@@ -695,7 +698,7 @@
 end;
 
 
-procedure TJSONProtocolImpl.WriteStructBegin( const struc: IStruct);
+procedure TJSONProtocolImpl.WriteStructBegin( const struc: TThriftStruct);
 begin
   WriteJSONObjectStart;
 end;
@@ -707,7 +710,7 @@
 end;
 
 
-procedure TJSONProtocolImpl.WriteFieldBegin( const field : IField);
+procedure TJSONProtocolImpl.WriteFieldBegin( const field : TThriftField);
 begin
   WriteJSONInteger(field.ID);
   WriteJSONObjectStart;
@@ -726,7 +729,7 @@
   // nothing to do
 end;
 
-procedure TJSONProtocolImpl.WriteMapBegin( const map: IMap);
+procedure TJSONProtocolImpl.WriteMapBegin( const map: TThriftMap);
 begin
   WriteJSONArrayStart;
   WriteJSONString( GetTypeNameForTypeID( map.KeyType));
@@ -743,7 +746,7 @@
 end;
 
 
-procedure TJSONProtocolImpl.WriteListBegin( const list: IList);
+procedure TJSONProtocolImpl.WriteListBegin( const list: TThriftList);
 begin
   WriteJSONArrayStart;
   WriteJSONString( GetTypeNameForTypeID( list.ElementType));
@@ -757,7 +760,7 @@
 end;
 
 
-procedure TJSONProtocolImpl.WriteSetBegin( const set_: ISet);
+procedure TJSONProtocolImpl.WriteSetBegin( const set_: TThriftSet);
 begin
   WriteJSONArrayStart;
   WriteJSONString( GetTypeNameForTypeID( set_.ElementType));
@@ -815,10 +818,14 @@
 
 function TJSONProtocolImpl.ReadJSONString( skipContext : Boolean) : TBytes;
 var buffer : TMemoryStream;
-    ch : Byte;
+    ch  : Byte;
+    wch : Word;
+    highSurogate: Char;
+    surrogatePairs: Array[0..1] of Char;
     off : Integer;
     tmp : TBytes;
 begin
+  highSurogate := #0;
   buffer := TMemoryStream.Create;
   try
     if not skipContext
@@ -832,27 +839,56 @@
       if (ch = QUOTE[0])
       then Break;
 
-      if (ch = ESCSEQ[0])
-      then begin
-        ch := FReader.Read;
-        if (ch = ESCSEQ[1])
-        then begin
-          ReadJSONSyntaxChar( ZERO[0]);
-          ReadJSONSyntaxChar( ZERO[0]);
-          SetLength( tmp, 2);
-          Transport.ReadAll( tmp, 0, 2);
-          ch := (HexVal(tmp[0]) shl 4) + HexVal(tmp[1]);
-        end
-        else begin
-          off := Pos( Char(ch), ESCAPE_CHARS);
-          if off < 1
-          then raise TProtocolException.Create( TProtocolException.INVALID_DATA, 'Expected control char');
-          ch := Byte( ESCAPE_CHAR_VALS[off]);
-        end;
+      // check for escapes
+      if (ch <> ESCSEQ[0]) then begin
+        buffer.Write( ch, 1);
+        Continue;
       end;
-      buffer.Write( ch, 1);
+
+      // distuinguish between \uNNNN and \?
+      ch := FReader.Read;
+      if (ch <> ESCSEQ[1])
+      then begin
+        off := Pos( Char(ch), ESCAPE_CHARS);
+        if off < 1
+        then raise TProtocolExceptionInvalidData.Create('Expected control char');
+        ch := Byte( ESCAPE_CHAR_VALS[off]);
+        buffer.Write( ch, 1);
+        Continue;
+      end;
+
+      // it is \uXXXX
+      SetLength( tmp, 4);
+      Transport.ReadAll( tmp, 0, 4);
+      wch := (HexVal(tmp[0]) shl 12)
+           + (HexVal(tmp[1]) shl 8)
+           + (HexVal(tmp[2]) shl 4)
+           +  HexVal(tmp[3]);
+
+      // we need to make UTF8 bytes from it, to be decoded later
+      if CharUtils.IsHighSurrogate(char(wch)) then begin
+        if highSurogate <> #0
+        then raise TProtocolExceptionInvalidData.Create('Expected low surrogate char');
+        highSurogate := char(wch);
+      end
+      else if CharUtils.IsLowSurrogate(char(wch)) then begin
+        if highSurogate = #0
+        then TProtocolExceptionInvalidData.Create('Expected high surrogate char');
+        surrogatePairs[0] := highSurogate;
+        surrogatePairs[1] := char(wch);
+        tmp := TEncoding.UTF8.GetBytes(surrogatePairs);
+        buffer.Write( tmp[0], Length(tmp));
+        highSurogate := #0;
+      end
+      else begin
+        tmp := SysUtils.TEncoding.UTF8.GetBytes(Char(wch));
+        buffer.Write( tmp[0], Length(tmp));
+      end;
     end;
 
+    if highSurogate <> #0
+    then raise TProtocolExceptionInvalidData.Create('Expected low surrogate char');
+
     SetLength( result, buffer.Size);
     if buffer.Size > 0 then Move( buffer.Memory^, result[0], Length(result));
 
@@ -905,8 +941,7 @@
     result := StrToInt64(str);
   except
     on e:Exception do begin
-      raise TProtocolException.Create( TProtocolException.INVALID_DATA,
-                                       'Bad data encounted in numeric data ('+str+') ('+e.Message+')');
+      raise TProtocolExceptionInvalidData.Create('Bad data encounted in numeric data ('+str+') ('+e.Message+')');
     end;
   end;
 end;
@@ -928,7 +963,7 @@
     and not Math.IsInfinite(dub)
     then begin
       // Throw exception -- we should not be in a string in  Self case
-      raise TProtocolException.Create( TProtocolException.INVALID_DATA, 'Numeric data unexpectedly quoted');
+      raise TProtocolExceptionInvalidData.Create('Numeric data unexpectedly quoted');
     end;
     result := dub;
     Exit;
@@ -943,20 +978,44 @@
     result := StrToFloat( str, INVARIANT_CULTURE);
   except
     on e:Exception
-    do raise TProtocolException.Create( TProtocolException.INVALID_DATA,
-                                       'Bad data encounted in numeric data ('+str+') ('+e.Message+')');
+    do raise TProtocolExceptionInvalidData.Create('Bad data encounted in numeric data ('+str+') ('+e.Message+')');
   end;
 end;
 
 
 function TJSONProtocolImpl.ReadJSONBase64 : TBytes;
 var b : TBytes;
-    str : string;
+    len, off, size : Integer;
 begin
   b := ReadJSONString(false);
 
-  SetString( str, PAnsiChar(b), Length(b));
-  result := TIdDecoderMIME.DecodeBytes( str);
+  len := Length(b);
+  off := 0;
+  size := 0;
+
+  // reduce len to ignore fill bytes
+  Dec(len);
+  while (len >= 0) and (b[len] = Byte('=')) do Dec(len);
+  Inc(len);
+
+  // read & decode full byte triplets = 4 source bytes
+  while (len >= 4) do begin
+    // Decode 4 bytes at a time
+    Inc( size, Base64Utils.Decode( b, off, 4, b, size)); // decoded in place
+    Inc( off, 4);
+    Dec( len, 4);
+  end;
+
+  // Don't decode if we hit the end or got a single leftover byte (invalid
+  // base64 but legal for skip of regular string type)
+  if len > 1 then begin
+    // Decode remainder
+    Inc( size, Base64Utils.Decode( b, off, len, b, size)); // decoded in place
+  end;
+
+  // resize to final size and return the data
+  SetLength( b, size);
+  result := b;
 end;
 
 
@@ -990,15 +1049,15 @@
 end;
 
 
-function TJSONProtocolImpl.ReadMessageBegin: IMessage;
+function TJSONProtocolImpl.ReadMessageBegin: TThriftMessage;
 begin
   ResetContextStack;  // THRIFT-1473
 
-  result := TMessageImpl.Create;
+  Init( result);
   ReadJSONArrayStart;
 
   if ReadJSONInteger <> VERSION
-  then raise TProtocolException.Create( TProtocolException.BAD_VERSION, 'Message contained bad version.');
+  then raise TProtocolExceptionBadVersion.Create('Message contained bad version.');
 
   result.Name  := SysUtils.TEncoding.UTF8.GetString( ReadJSONString( FALSE));
   result.Type_ := TMessageType( ReadJSONInteger);
@@ -1012,10 +1071,10 @@
 end;
 
 
-function TJSONProtocolImpl.ReadStructBegin : IStruct ;
+function TJSONProtocolImpl.ReadStructBegin : TThriftStruct ;
 begin
   ReadJSONObjectStart;
-  result := TStructImpl.Create('');
+  Init( result);
 end;
 
 
@@ -1025,11 +1084,11 @@
 end;
 
 
-function TJSONProtocolImpl.ReadFieldBegin : IField;
+function TJSONProtocolImpl.ReadFieldBegin : TThriftField;
 var ch : Byte;
     str : string;
 begin
-  result := TFieldImpl.Create;
+  Init( result);
   ch := FReader.Peek;
   if ch = RBRACE[0]
   then result.Type_ := TType.Stop
@@ -1049,10 +1108,10 @@
 end;
 
 
-function TJSONProtocolImpl.ReadMapBegin : IMap;
+function TJSONProtocolImpl.ReadMapBegin : TThriftMap;
 var str : string;
 begin
-  result := TMapImpl.Create;
+  Init( result);
   ReadJSONArrayStart;
 
   str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
@@ -1073,10 +1132,10 @@
 end;
 
 
-function TJSONProtocolImpl.ReadListBegin : IList;
+function TJSONProtocolImpl.ReadListBegin : TThriftList;
 var str : string;
 begin
-  result := TListImpl.Create;
+  Init( result);
   ReadJSONArrayStart;
 
   str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
@@ -1091,10 +1150,10 @@
 end;
 
 
-function TJSONProtocolImpl.ReadSetBegin : ISet;
+function TJSONProtocolImpl.ReadSetBegin : TThriftSet;
 var str : string;
 begin
-  result := TSetImpl.Create;
+  Init( result);
   ReadJSONArrayStart;
 
   str := SysUtils.TEncoding.UTF8.GetString( ReadJSONString(FALSE));
@@ -1174,6 +1233,5 @@
   InitBytes( RBRACKET,  [Byte(']')]);
   InitBytes( QUOTE,     [Byte('"')]);
   InitBytes( BACKSLASH, [Byte('\')]);
-  InitBytes( ZERO,      [Byte('0')]);
   InitBytes( ESCSEQ,    [Byte('\'),Byte('u'),Byte('0'),Byte('0')]);
 end.
diff --git a/lib/delphi/src/Thrift.Protocol.Multiplex.pas b/lib/delphi/src/Thrift.Protocol.Multiplex.pas
index 2cd2401..93a3838 100644
--- a/lib/delphi/src/Thrift.Protocol.Multiplex.pas
+++ b/lib/delphi/src/Thrift.Protocol.Multiplex.pas
@@ -1,22 +1,22 @@
 (*
- * 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.

- *)

-

+ * 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.
+ *)
+
 unit Thrift.Protocol.Multiplex;
 
 interface
@@ -71,7 +71,7 @@
     { Prepends the service name to the function name, separated by SEPARATOR.
       Args: The original message.
     }
-    procedure WriteMessageBegin( const msg: IMessage); override;
+    procedure WriteMessageBegin( const msg: TThriftMessage); override;
   end;
 
 
@@ -86,14 +86,14 @@
 end;
 
 
-procedure TMultiplexedProtocol.WriteMessageBegin( const msg: IMessage);
+procedure TMultiplexedProtocol.WriteMessageBegin( const msg: TThriftMessage);
 // Prepends the service name to the function name, separated by TMultiplexedProtocol.SEPARATOR.
-var newMsg : IMessage;
+var newMsg : TThriftMessage;
 begin
   case msg.Type_ of
     TMessageType.Call,
     TMessageType.Oneway : begin
-      newMsg := TMessageImpl.Create( FServiceName + SEPARATOR + msg.Name, msg.Type_, msg.SeqID);
+      Init( newMsg, FServiceName + SEPARATOR + msg.Name, msg.Type_, msg.SeqID);
       inherited WriteMessageBegin( newMsg);
     end;
 
diff --git a/lib/delphi/src/Thrift.Protocol.pas b/lib/delphi/src/Thrift.Protocol.pas
index 1f27203..36509ca 100644
--- a/lib/delphi/src/Thrift.Protocol.pas
+++ b/lib/delphi/src/Thrift.Protocol.pas
@@ -1,1541 +1,1389 @@
-(*

- * 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.

- *)

-

-{$SCOPEDENUMS ON}

-

-unit Thrift.Protocol;

-

-interface

-

-uses

-  Classes,

-  SysUtils,

-  Contnrs,

-  Thrift.Stream,

-  Thrift.Collections,

-  Thrift.Transport;

-

-type

-

-  TType = (

-    Stop = 0,

-    Void = 1,

-    Bool_ = 2,

-    Byte_ = 3,

-    Double_ = 4,

-    I16 = 6,

-    I32 = 8,

-    I64 = 10,

-    String_ = 11,

-    Struct = 12,

-    Map = 13,

-    Set_ = 14,

-    List = 15

-  );

-

-  TMessageType = (

-    Call = 1,

-    Reply = 2,

-    Exception = 3,

-    Oneway = 4

-  );

-

-  IProtocol = interface;

-  IStruct = interface;

-

-  IProtocolFactory = interface

-    ['{7CD64A10-4E9F-4E99-93BF-708A31F4A67B}']

-    function GetProtocol( const trans: ITransport): IProtocol;

-  end;

-

-  TThriftStringBuilder = class( TStringBuilder)

-  public

-    function Append(const Value: TBytes): TStringBuilder; overload;

-    function Append(const Value: IThriftContainer): TStringBuilder; overload;

-  end;

-

-  TProtocolException = class( Exception )

-  public

-    const

-      UNKNOWN : Integer = 0;

-      INVALID_DATA : Integer = 1;

-      NEGATIVE_SIZE : Integer = 2;

-      SIZE_LIMIT : Integer = 3;

-      BAD_VERSION : Integer = 4;

-      NOT_IMPLEMENTED : Integer = 5;

-  protected

-    FType : Integer;

-  public

-    constructor Create; overload;

-    constructor Create( type_: Integer ); overload;

-    constructor Create( type_: Integer; const msg: string); overload;

-  end;

-

-  IMap = interface

-    ['{30531D97-7E06-4233-B800-C3F53CCD23E7}']

-    function GetKeyType: TType;

-    procedure SetKeyType( Value: TType);

-    function GetValueType: TType;

-    procedure SetValueType( Value: TType);

-    function GetCount: Integer;

-    procedure SetCount( Value: Integer);

-    property KeyType: TType read GetKeyType write SetKeyType;

-    property ValueType: TType read GetValueType write SetValueType;

-    property Count: Integer read GetCount write SetCount;

-  end;

-

-  TMapImpl = class( TInterfacedObject, IMap)

-  private

-    FValueType: TType;

-    FKeyType: TType;

-    FCount: Integer;

-  protected

-    function GetKeyType: TType;

-    procedure SetKeyType( Value: TType);

-    function GetValueType: TType;

-    procedure SetValueType( Value: TType);

-    function GetCount: Integer;

-    procedure SetCount( Value: Integer);

-  public

-    constructor Create( AValueType: TType; AKeyType: TType; ACount: Integer); overload;

-    constructor Create; overload;

-  end;

-

-  IList = interface

-    ['{6763E1EA-A934-4472-904F-0083980B9B87}']

-    function GetElementType: TType;

-    procedure SetElementType( Value: TType);

-    function GetCount: Integer;

-    procedure SetCount( Value: Integer);

-    property ElementType: TType read GetElementType write SetElementType;

-    property Count: Integer read GetCount write SetCount;

-  end;

-

-  TListImpl = class( TInterfacedObject, IList)

-  private

-    FElementType: TType;

-    FCount : Integer;

-  protected

-    function GetElementType: TType;

-    procedure SetElementType( Value: TType);

-    function GetCount: Integer;

-    procedure SetCount( Value: Integer);

-  public

-    constructor Create( AElementType: TType; ACount: Integer); overload;

-    constructor Create; overload;

-  end;

-

-  ISet = interface

-    ['{A8671700-7514-4C1E-8A05-62786872005F}']

-    function GetElementType: TType;

-    procedure SetElementType( Value: TType);

-    function GetCount: Integer;

-    procedure SetCount( Value: Integer);

-    property ElementType: TType read GetElementType write SetElementType;

-    property Count: Integer read GetCount write SetCount;

-  end;

-

-  TSetImpl = class( TInterfacedObject, ISet)

-  private

-    FCount: Integer;

-    FElementType: TType;

-  protected

-    function GetElementType: TType;

-    procedure SetElementType( Value: TType);

-    function GetCount: Integer;

-    procedure SetCount( Value: Integer);

-  public

-    constructor Create( AElementType: TType; ACount: Integer); overload;

-    constructor Create; overload;

-  end;

-

-  IMessage = interface

-    ['{9E368B4A-B1FA-43E7-8CF5-56C66D256CA7}']

-    function GetName: string;

-    procedure SetName( const Value: string);

-    function GetType: TMessageType;

-    procedure SetType( Value: TMessageType);

-    function GetSeqID: Integer;

-    procedure SetSeqID( Value: Integer);

-    property Name: string read GetName write SetName;

-    property Type_: TMessageType read GetType write SetType;

-    property SeqID: Integer read GetSeqID write SetSeqID;

-  end;

-

-  TMessageImpl = class( TInterfacedObject, IMessage )

-  private

-    FName: string;

-    FMessageType: TMessageType;

-    FSeqID: Integer;

-  protected

-    function GetName: string;

-    procedure SetName( const Value: string);

-    function GetType: TMessageType;

-    procedure SetType( Value: TMessageType);

-    function GetSeqID: Integer;

-    procedure SetSeqID( Value: Integer);

-  public

-    property Name: string read FName write FName;

-    property Type_: TMessageType read FMessageType write FMessageType;

-    property SeqID: Integer read FSeqID write FSeqID;

-    constructor Create( AName: string; AMessageType: TMessageType; ASeqID: Integer); overload;

-    constructor Create; overload;

-  end;

-

-  IField = interface

-    ['{F0D43BE5-7883-442E-83FF-0580CC632B72}']

-    function GetName: string;

-    procedure SetName( const Value: string);

-    function GetType: TType;

-    procedure SetType( Value: TType);

-    function GetId: SmallInt;

-    procedure SetId( Value: SmallInt);

-    property Name: string read GetName write SetName;

-    property Type_: TType read GetType write SetType;

-    property Id: SmallInt read GetId write SetId;

-  end;

-

-  TFieldImpl = class( TInterfacedObject, IField)

-  private

-    FName : string;

-    FType : TType;

-    FId   : SmallInt;

-  protected

-    function GetName: string;

-    procedure SetName( const Value: string);

-    function GetType: TType;

-    procedure SetType( Value: TType);

-    function GetId: SmallInt;

-    procedure SetId( Value: SmallInt);

-  public

-    constructor Create( const AName: string; const AType: TType; AId: SmallInt); overload;

-    constructor Create; overload;

-  end;

-

-  TProtocolUtil = class

-  public

-    class procedure Skip( prot: IProtocol; type_: TType);

-  end;

-

-  IProtocol = interface

-    ['{FD95C151-1527-4C96-8134-B902BFC4B4FC}']

-    function GetTransport: ITransport;

-    procedure WriteMessageBegin( const msg: IMessage);

-    procedure WriteMessageEnd;

-    procedure WriteStructBegin( const struc: IStruct);

-    procedure WriteStructEnd;

-    procedure WriteFieldBegin( const field: IField);

-    procedure WriteFieldEnd;

-    procedure WriteFieldStop;

-    procedure WriteMapBegin( const map: IMap);

-    procedure WriteMapEnd;

-    procedure WriteListBegin( const list: IList);

-    procedure WriteListEnd();

-    procedure WriteSetBegin( const set_: ISet );

-    procedure WriteSetEnd();

-    procedure WriteBool( b: Boolean);

-    procedure WriteByte( b: ShortInt);

-    procedure WriteI16( i16: SmallInt);

-    procedure WriteI32( i32: Integer);

-    procedure WriteI64( const i64: Int64);

-    procedure WriteDouble( const d: Double);

-    procedure WriteString( const s: string );

-    procedure WriteAnsiString( const s: AnsiString);

-    procedure WriteBinary( const b: TBytes);

-

-    function ReadMessageBegin: IMessage;

-    procedure ReadMessageEnd();

-    function ReadStructBegin: IStruct;

-    procedure ReadStructEnd;

-    function ReadFieldBegin: IField;

-    procedure ReadFieldEnd();

-    function ReadMapBegin: IMap;

-    procedure ReadMapEnd();

-    function ReadListBegin: IList;

-    procedure ReadListEnd();

-    function ReadSetBegin: ISet;

-    procedure ReadSetEnd();

-    function ReadBool: Boolean;

-    function ReadByte: ShortInt;

-    function ReadI16: SmallInt;

-    function ReadI32: Integer;

-    function ReadI64: Int64;

-    function ReadDouble:Double;

-    function ReadBinary: TBytes;

-    function ReadString: string;

-    function ReadAnsiString: AnsiString;

-    property Transport: ITransport read GetTransport;

-  end;

-

-  TProtocolImpl = class abstract( TInterfacedObject, IProtocol)

-  protected

-    FTrans : ITransport;

-    function GetTransport: ITransport;

-  public

-    procedure WriteMessageBegin( const msg: IMessage); virtual; abstract;

-    procedure WriteMessageEnd; virtual; abstract;

-    procedure WriteStructBegin( const struc: IStruct); virtual; abstract;

-    procedure WriteStructEnd; virtual; abstract;

-    procedure WriteFieldBegin( const field: IField); virtual; abstract;

-    procedure WriteFieldEnd; virtual; abstract;

-    procedure WriteFieldStop; virtual; abstract;

-    procedure WriteMapBegin( const map: IMap); virtual; abstract;

-    procedure WriteMapEnd; virtual; abstract;

-    procedure WriteListBegin( const list: IList); virtual; abstract;

-    procedure WriteListEnd(); virtual; abstract;

-    procedure WriteSetBegin( const set_: ISet ); virtual; abstract;

-    procedure WriteSetEnd(); virtual; abstract;

-    procedure WriteBool( b: Boolean); virtual; abstract;

-    procedure WriteByte( b: ShortInt); virtual; abstract;

-    procedure WriteI16( i16: SmallInt); virtual; abstract;

-    procedure WriteI32( i32: Integer); virtual; abstract;

-    procedure WriteI64( const i64: Int64); virtual; abstract;

-    procedure WriteDouble( const d: Double); virtual; abstract;

-    procedure WriteString( const s: string ); virtual;

-    procedure WriteAnsiString( const s: AnsiString); virtual;

-    procedure WriteBinary( const b: TBytes); virtual; abstract;

-

-    function ReadMessageBegin: IMessage; virtual; abstract;

-    procedure ReadMessageEnd(); virtual; abstract;

-    function ReadStructBegin: IStruct; virtual; abstract;

-    procedure ReadStructEnd; virtual; abstract;

-    function ReadFieldBegin: IField; virtual; abstract;

-    procedure ReadFieldEnd(); virtual; abstract;

-    function ReadMapBegin: IMap; virtual; abstract;

-    procedure ReadMapEnd(); virtual; abstract;

-    function ReadListBegin: IList; virtual; abstract;

-    procedure ReadListEnd(); virtual; abstract;

-    function ReadSetBegin: ISet; virtual; abstract;

-    procedure ReadSetEnd(); virtual; abstract;

-    function ReadBool: Boolean; virtual; abstract;

-    function ReadByte: ShortInt; virtual; abstract;

-    function ReadI16: SmallInt; virtual; abstract;

-    function ReadI32: Integer; virtual; abstract;

-    function ReadI64: Int64; virtual; abstract;

-    function ReadDouble:Double; virtual; abstract;

-    function ReadBinary: TBytes; virtual; abstract;

-    function ReadString: string; virtual;

-    function ReadAnsiString: AnsiString; virtual;

-

-    property Transport: ITransport read GetTransport;

-

-    constructor Create( trans: ITransport );

-  end;

-

-  IBase = interface

-    ['{08D9BAA8-5EAA-410F-B50B-AC2E6E5E4155}']

-    function ToString: string;

-    procedure Read( const iprot: IProtocol);

-    procedure Write( const iprot: IProtocol);

-  end;

-

-  IStruct = interface

-    ['{5DCE39AA-C916-4BC7-A79B-96A0C36B2220}']

-    procedure SetName(const Value: string);

-    function GetName: string;

-    property Name: string read GetName write SetName;

-  end;

-

-  TStructImpl = class( TInterfacedObject, IStruct )

-  private

-    FName: string;

-  protected

-    function GetName: string;

-    procedure SetName(const Value: string);

-  public

-    constructor Create( const AName: string);

-  end;

-

-  TBinaryProtocolImpl = class( TProtocolImpl )

-  protected

-    const

-      VERSION_MASK : Cardinal = $ffff0000;

-      VERSION_1 : Cardinal = $80010000;

-  protected

-    FStrictRead : Boolean;

-    FStrictWrite : Boolean;

-

-  private

-    function ReadAll( var buf: TBytes; off: Integer; len: Integer ): Integer;

-    function ReadStringBody( size: Integer): string;

-

-  public

-

-    type

-      TFactory = class( TInterfacedObject, IProtocolFactory)

-      protected

-        FStrictRead : Boolean;

-        FStrictWrite : Boolean;

-      public

-        function GetProtocol( const trans: ITransport): IProtocol;

-        constructor Create( AStrictRead, AStrictWrite: Boolean ); overload;

-        constructor Create; overload;

-      end;

-

-    constructor Create( const trans: ITransport); overload;

-    constructor Create( const trans: ITransport; strictRead: Boolean; strictWrite: Boolean); overload;

-

-    procedure WriteMessageBegin( const msg: IMessage); override;

-    procedure WriteMessageEnd; override;

-    procedure WriteStructBegin( const struc: IStruct); override;

-    procedure WriteStructEnd; override;

-    procedure WriteFieldBegin( const field: IField); override;

-    procedure WriteFieldEnd; override;

-    procedure WriteFieldStop; override;

-    procedure WriteMapBegin( const map: IMap); override;

-    procedure WriteMapEnd; override;

-    procedure WriteListBegin( const list: IList); override;

-    procedure WriteListEnd(); override;

-    procedure WriteSetBegin( const set_: ISet ); override;

-    procedure WriteSetEnd(); override;

-    procedure WriteBool( b: Boolean); override;

-    procedure WriteByte( b: ShortInt); override;

-    procedure WriteI16( i16: SmallInt); override;

-    procedure WriteI32( i32: Integer); override;

-    procedure WriteI64( const i64: Int64); override;

-    procedure WriteDouble( const d: Double); override;

-    procedure WriteBinary( const b: TBytes); override;

-

-    function ReadMessageBegin: IMessage; override;

-    procedure ReadMessageEnd(); override;

-    function ReadStructBegin: IStruct; override;

-    procedure ReadStructEnd; override;

-    function ReadFieldBegin: IField; override;

-    procedure ReadFieldEnd(); override;

-    function ReadMapBegin: IMap; override;

-    procedure ReadMapEnd(); override;

-    function ReadListBegin: IList; override;

-    procedure ReadListEnd(); override;

-    function ReadSetBegin: ISet; override;

-    procedure ReadSetEnd(); override;

-    function ReadBool: Boolean; override;

-    function ReadByte: ShortInt; override;

-    function ReadI16: SmallInt; override;

-    function ReadI32: Integer; override;

-    function ReadI64: Int64; override;

-    function ReadDouble:Double; override;

-    function ReadBinary: TBytes; override;

-

-  end;

-

-

-  { TProtocolDecorator forwards all requests to an enclosed TProtocol instance,

-    providing a way to author concise concrete decorator subclasses. The decorator

-    does not (and should not) modify the behaviour of the enclosed TProtocol

-

-    See p.175 of Design Patterns (by Gamma et al.)

-  }

-  TProtocolDecorator = class( TProtocolImpl)

-  private

-    FWrappedProtocol : IProtocol;

-

-  public

-    // Encloses the specified protocol.

-    // All operations will be forward to the given protocol.  Must be non-null.

-    constructor Create( const aProtocol : IProtocol);

-

-    procedure WriteMessageBegin( const msg: IMessage); override;

-    procedure WriteMessageEnd; override;

-    procedure WriteStructBegin( const struc: IStruct); override;

-    procedure WriteStructEnd; override;

-    procedure WriteFieldBegin( const field: IField); override;

-    procedure WriteFieldEnd; override;

-    procedure WriteFieldStop; override;

-    procedure WriteMapBegin( const map: IMap); override;

-    procedure WriteMapEnd; override;

-    procedure WriteListBegin( const list: IList); override;

-    procedure WriteListEnd(); override;

-    procedure WriteSetBegin( const set_: ISet ); override;

-    procedure WriteSetEnd(); override;

-    procedure WriteBool( b: Boolean); override;

-    procedure WriteByte( b: ShortInt); override;

-    procedure WriteI16( i16: SmallInt); override;

-    procedure WriteI32( i32: Integer); override;

-    procedure WriteI64( const i64: Int64); override;

-    procedure WriteDouble( const d: Double); override;

-    procedure WriteString( const s: string ); override;

-    procedure WriteAnsiString( const s: AnsiString); override;

-    procedure WriteBinary( const b: TBytes); override;

-

-    function ReadMessageBegin: IMessage; override;

-    procedure ReadMessageEnd(); override;

-    function ReadStructBegin: IStruct; override;

-    procedure ReadStructEnd; override;

-    function ReadFieldBegin: IField; override;

-    procedure ReadFieldEnd(); override;

-    function ReadMapBegin: IMap; override;

-    procedure ReadMapEnd(); override;

-    function ReadListBegin: IList; override;

-    procedure ReadListEnd(); override;

-    function ReadSetBegin: ISet; override;

-    procedure ReadSetEnd(); override;

-    function ReadBool: Boolean; override;

-    function ReadByte: ShortInt; override;

-    function ReadI16: SmallInt; override;

-    function ReadI32: Integer; override;

-    function ReadI64: Int64; override;

-    function ReadDouble:Double; override;

-    function ReadBinary: TBytes; override;

-    function ReadString: string; override;

-    function ReadAnsiString: AnsiString; override;

-  end;

-

-

-implementation

-

-function ConvertInt64ToDouble( const n: Int64): Double;

-begin

-  ASSERT( SizeOf(n) = SizeOf(Result));

-  System.Move( n, Result, SizeOf(Result));

-end;

-

-function ConvertDoubleToInt64( const d: Double): Int64;

-begin

-  ASSERT( SizeOf(d) = SizeOf(Result));

-  System.Move( d, Result, SizeOf(Result));

-end;

-

-{ TFieldImpl }

-

-constructor TFieldImpl.Create(const AName: string; const AType: TType;

-  AId: SmallInt);

-begin

-  FName := AName;

-  FType := AType;

-  FId := AId;

-end;

-

-constructor TFieldImpl.Create;

-begin

-  FName := '';

-  FType := Low(TType);

-  FId   := 0;

-end;

-

-function TFieldImpl.GetId: SmallInt;

-begin

-  Result := FId;

-end;

-

-function TFieldImpl.GetName: string;

-begin

-  Result := FName;

-end;

-

-function TFieldImpl.GetType: TType;

-begin

-  Result := FType;

-end;

-

-procedure TFieldImpl.SetId(Value: SmallInt);

-begin

-  FId := Value;

-end;

-

-procedure TFieldImpl.SetName(const Value: string);

-begin

-  FName := Value;

-end;

-

-procedure TFieldImpl.SetType(Value: TType);

-begin

-  FType := Value;

-end;

-

-{ TProtocolImpl }

-

-constructor TProtocolImpl.Create(trans: ITransport);

-begin

-  inherited Create;

-  FTrans := trans;

-end;

-

-function TProtocolImpl.GetTransport: ITransport;

-begin

-  Result := FTrans;

-end;

-

-function TProtocolImpl.ReadAnsiString: AnsiString;

-var

-  b : TBytes;

-  len : Integer;

-begin

-  Result := '';

-  b := ReadBinary;

-  len := Length( b );

-  if len > 0 then

-  begin

-    SetLength( Result, len);

-    System.Move( b[0], Pointer(Result)^, len );

-  end;

-end;

-

-function TProtocolImpl.ReadString: string;

-begin

-  Result := TEncoding.UTF8.GetString( ReadBinary );

-end;

-

-procedure TProtocolImpl.WriteAnsiString(const s: AnsiString);

-var

-  b : TBytes;

-  len : Integer;

-begin

-  len := Length(s);

-  SetLength( b, len);

-  if len > 0 then

-  begin

-    System.Move( Pointer(s)^, b[0], len );

-  end;

-  WriteBinary( b );

-end;

-

-procedure TProtocolImpl.WriteString(const s: string);

-var

-  b : TBytes;

-begin

-  b := TEncoding.UTF8.GetBytes(s);

-  WriteBinary( b );

-end;

-

-{ TProtocolUtil }

-

-class procedure TProtocolUtil.Skip( prot: IProtocol; type_: TType);

-var field : IField;

-    map   : IMap;

-    set_  : ISet;

-    list  : IList;

-    i     : Integer;

-begin

-  case type_ of

-    // simple types

-    TType.Bool_   :  prot.ReadBool();

-    TType.Byte_   :  prot.ReadByte();

-    TType.I16     :  prot.ReadI16();

-    TType.I32     :  prot.ReadI32();

-    TType.I64     :  prot.ReadI64();

-    TType.Double_ :  prot.ReadDouble();

-    TType.String_ :  prot.ReadBinary();// Don't try to decode the string, just skip it.

-

-    // structured types

-    TType.Struct :  begin

-      prot.ReadStructBegin();

-      while TRUE do begin

-        field := prot.ReadFieldBegin();

-        if (field.Type_ = TType.Stop) then Break;

-        Skip(prot, field.Type_);

-        prot.ReadFieldEnd();

-      end;

-      prot.ReadStructEnd();

-    end;

-

-    TType.Map :  begin

-      map := prot.ReadMapBegin();

-      for i := 0 to map.Count-1 do begin

-        Skip(prot, map.KeyType);

-        Skip(prot, map.ValueType);

-      end;

-      prot.ReadMapEnd();

-    end;

-

-    TType.Set_ :  begin

-      set_ := prot.ReadSetBegin();

-      for i := 0 to set_.Count-1

-      do Skip( prot, set_.ElementType);

-      prot.ReadSetEnd();

-    end;

-

-    TType.List :  begin

-      list := prot.ReadListBegin();

-      for i := 0 to list.Count-1

-      do Skip( prot, list.ElementType);

-      prot.ReadListEnd();

-    end;

-

-  else

-    ASSERT( FALSE); // any new types?

-  end;

-end;

-

-{ TStructImpl }

-

-constructor TStructImpl.Create(const AName: string);

-begin

-  inherited Create;

-  FName := AName;

-end;

-

-function TStructImpl.GetName: string;

-begin

-  Result := FName;

-end;

-

-procedure TStructImpl.SetName(const Value: string);

-begin

-  FName := Value;

-end;

-

-{ TMapImpl }

-

-constructor TMapImpl.Create(AValueType, AKeyType: TType; ACount: Integer);

-begin

-  inherited Create;

-  FValueType := AValueType;

-  FKeyType := AKeyType;

-  FCount := ACount;

-end;

-

-constructor TMapImpl.Create;

-begin

-

-end;

-

-function TMapImpl.GetCount: Integer;

-begin

-  Result := FCount;

-end;

-

-function TMapImpl.GetKeyType: TType;

-begin

-  Result := FKeyType;

-end;

-

-function TMapImpl.GetValueType: TType;

-begin

-  Result := FValueType;

-end;

-

-procedure TMapImpl.SetCount(Value: Integer);

-begin

-  FCount := Value;

-end;

-

-procedure TMapImpl.SetKeyType(Value: TType);

-begin

-  FKeyType := Value;

-end;

-

-procedure TMapImpl.SetValueType(Value: TType);

-begin

-  FValueType := Value;

-end;

-

-{ IMessage }

-

-constructor TMessageImpl.Create(AName: string; AMessageType: TMessageType;

-  ASeqID: Integer);

-begin

-  inherited Create;

-  FName := AName;

-  FMessageType := AMessageType;

-  FSeqID := ASeqID;

-end;

-

-constructor TMessageImpl.Create;

-begin

-  inherited;

-end;

-

-function TMessageImpl.GetName: string;

-begin

-  Result := FName;

-end;

-

-function TMessageImpl.GetSeqID: Integer;

-begin

-  Result := FSeqID;

-end;

-

-function TMessageImpl.GetType: TMessageType;

-begin

-  Result := FMessageType;

-end;

-

-procedure TMessageImpl.SetName(const Value: string);

-begin

-  FName := Value;

-end;

-

-procedure TMessageImpl.SetSeqID(Value: Integer);

-begin

-  FSeqID := Value;

-end;

-

-procedure TMessageImpl.SetType(Value: TMessageType);

-begin

-  FMessageType := Value;

-end;

-

-{ ISet }

-

-constructor TSetImpl.Create( AElementType: TType; ACount: Integer);

-begin

-  inherited Create;

-  FCount := ACount;

-  FElementType := AElementType;

-end;

-

-constructor TSetImpl.Create;

-begin

-

-end;

-

-function TSetImpl.GetCount: Integer;

-begin

-  Result := FCount;

-end;

-

-function TSetImpl.GetElementType: TType;

-begin

-  Result := FElementType;

-end;

-

-procedure TSetImpl.SetCount(Value: Integer);

-begin

-  FCount := Value;

-end;

-

-procedure TSetImpl.SetElementType(Value: TType);

-begin

-  FElementType := Value;

-end;

-

-{ IList }

-

-constructor TListImpl.Create( AElementType: TType; ACount: Integer);

-begin

-  inherited Create;

-  FCount := ACount;

-  FElementType := AElementType;

-end;

-

-constructor TListImpl.Create;

-begin

-

-end;

-

-function TListImpl.GetCount: Integer;

-begin

-  Result := FCount;

-end;

-

-function TListImpl.GetElementType: TType;

-begin

-  Result := FElementType;

-end;

-

-procedure TListImpl.SetCount(Value: Integer);

-begin

-  FCount := Value;

-end;

-

-procedure TListImpl.SetElementType(Value: TType);

-begin

-  FElementType := Value;

-end;

-

-{ TBinaryProtocolImpl }

-

-constructor TBinaryProtocolImpl.Create( const trans: ITransport);

-begin

-  Create( trans, False, True);

-end;

-

-constructor TBinaryProtocolImpl.Create( const trans: ITransport; strictRead,

-  strictWrite: Boolean);

-begin

-  inherited Create( trans );

-  FStrictRead := strictRead;

-  FStrictWrite := strictWrite;

-end;

-

-function TBinaryProtocolImpl.ReadAll( var buf: TBytes; off,

-  len: Integer): Integer;

-begin

-  Result := FTrans.ReadAll( buf, off, len );

-end;

-

-function TBinaryProtocolImpl.ReadBinary: TBytes;

-var

-  size : Integer;

-  buf : TBytes;

-begin

-  size := ReadI32;

-  SetLength( buf, size );

-  FTrans.ReadAll( buf, 0, size);

-  Result := buf;

-end;

-

-function TBinaryProtocolImpl.ReadBool: Boolean;

-begin

-  Result := ReadByte = 1;

-end;

-

-function TBinaryProtocolImpl.ReadByte: ShortInt;

-var

-  bin : TBytes;

-begin

-  SetLength( bin, 1);

-  ReadAll( bin, 0, 1 );

-  Result := ShortInt( bin[0]);

-end;

-

-function TBinaryProtocolImpl.ReadDouble: Double;

-begin

-  Result := ConvertInt64ToDouble( ReadI64 )

-end;

-

-function TBinaryProtocolImpl.ReadFieldBegin: IField;

-var

-  field : IField;

-begin

-  field := TFieldImpl.Create;

-  field.Type_ := TType( ReadByte);

-  if ( field.Type_ <> TType.Stop ) then

-  begin

-    field.Id := ReadI16;

-  end;

-  Result := field;

-end;

-

-procedure TBinaryProtocolImpl.ReadFieldEnd;

-begin

-

-end;

-

-function TBinaryProtocolImpl.ReadI16: SmallInt;

-var

-  i16in : TBytes;

-begin

-  SetLength( i16in, 2 );

-  ReadAll( i16in, 0, 2);

-  Result := SmallInt(((i16in[0] and $FF) shl 8) or (i16in[1] and $FF));

-end;

-

-function TBinaryProtocolImpl.ReadI32: Integer;

-var

-  i32in : TBytes;

-begin

-  SetLength( i32in, 4 );

-  ReadAll( i32in, 0, 4);

-

-  Result := Integer(

-    ((i32in[0] and $FF) shl 24) or

-    ((i32in[1] and $FF) shl 16) or

-    ((i32in[2] and $FF) shl 8) or

-     (i32in[3] and $FF));

-

-end;

-

-function TBinaryProtocolImpl.ReadI64: Int64;

-var

-  i64in : TBytes;

-begin

-  SetLength( i64in, 8);

-  ReadAll( i64in, 0, 8);

-  Result :=

-    (Int64( i64in[0] and $FF) shl 56) or

-    (Int64( i64in[1] and $FF) shl 48) or

-    (Int64( i64in[2] and $FF) shl 40) or

-    (Int64( i64in[3] and $FF) shl 32) or

-    (Int64( i64in[4] and $FF) shl 24) or

-    (Int64( i64in[5] and $FF) shl 16) or

-    (Int64( i64in[6] and $FF) shl 8) or

-    (Int64( i64in[7] and $FF));

-end;

-

-function TBinaryProtocolImpl.ReadListBegin: IList;

-var

-  list : IList;

-begin

-  list := TListImpl.Create;

-  list.ElementType := TType( ReadByte );

-  list.Count := ReadI32;

-  Result := list;

-end;

-

-procedure TBinaryProtocolImpl.ReadListEnd;

-begin

-

-end;

-

-function TBinaryProtocolImpl.ReadMapBegin: IMap;

-var

-  map : IMap;

-begin

-  map := TMapImpl.Create;

-  map.KeyType := TType( ReadByte );

-  map.ValueType := TType( ReadByte );

-  map.Count := ReadI32;

-  Result := map;

-end;

-

-procedure TBinaryProtocolImpl.ReadMapEnd;

-begin

-

-end;

-

-function TBinaryProtocolImpl.ReadMessageBegin: IMessage;

-var

-  size : Integer;

-  version : Integer;

-  message : IMessage;

-begin

-  message := TMessageImpl.Create;

-  size := ReadI32;

-  if (size < 0) then

-  begin

-    version := size and Integer( VERSION_MASK);

-    if ( version <> Integer( VERSION_1)) then

-    begin

-      raise TProtocolException.Create(TProtocolException.BAD_VERSION, 'Bad version in ReadMessageBegin: ' + IntToStr(version) );

-    end;

-    message.Type_ := TMessageType( size and $000000ff);

-    message.Name := ReadString;

-    message.SeqID := ReadI32;

-  end else

-  begin

-    if FStrictRead then

-    begin

-      raise TProtocolException.Create( TProtocolException.BAD_VERSION, 'Missing version in readMessageBegin, old client?' );

-    end;

-    message.Name := ReadStringBody( size );

-    message.Type_ := TMessageType( ReadByte );

-    message.SeqID := ReadI32;

-  end;

-  Result := message;

-end;

-

-procedure TBinaryProtocolImpl.ReadMessageEnd;

-begin

-  inherited;

-

-end;

-

-function TBinaryProtocolImpl.ReadSetBegin: ISet;

-var

-  set_ : ISet;

-begin

-  set_ := TSetImpl.Create;

-  set_.ElementType := TType( ReadByte );

-  set_.Count := ReadI32;

-  Result := set_;

-end;

-

-procedure TBinaryProtocolImpl.ReadSetEnd;

-begin

-

-end;

-

-function TBinaryProtocolImpl.ReadStringBody( size: Integer): string;

-var

-  buf : TBytes;

-begin

-  SetLength( buf, size );

-  FTrans.ReadAll( buf, 0, size );

-  Result := TEncoding.UTF8.GetString( buf);

-end;

-

-function TBinaryProtocolImpl.ReadStructBegin: IStruct;

-begin

-  Result := TStructImpl.Create('');

-end;

-

-procedure TBinaryProtocolImpl.ReadStructEnd;

-begin

-  inherited;

-

-end;

-

-procedure TBinaryProtocolImpl.WriteBinary( const b: TBytes);

-var iLen : Integer;

-begin

-  iLen := Length(b);

-  WriteI32( iLen);

-  if iLen > 0 then FTrans.Write(b, 0, iLen);

-end;

-

-procedure TBinaryProtocolImpl.WriteBool(b: Boolean);

-begin

-  if b then

-  begin

-    WriteByte( 1 );

-  end else

-  begin

-    WriteByte( 0 );

-  end;

-end;

-

-procedure TBinaryProtocolImpl.WriteByte(b: ShortInt);

-var

-  a : TBytes;

-begin

-  SetLength( a, 1);

-  a[0] := Byte( b );

-  FTrans.Write( a, 0, 1 );

-end;

-

-procedure TBinaryProtocolImpl.WriteDouble( const d: Double);

-begin

-  WriteI64(ConvertDoubleToInt64(d));

-end;

-

-procedure TBinaryProtocolImpl.WriteFieldBegin( const field: IField);

-begin

-  WriteByte(ShortInt(field.Type_));

-  WriteI16(field.ID);

-end;

-

-procedure TBinaryProtocolImpl.WriteFieldEnd;

-begin

-

-end;

-

-procedure TBinaryProtocolImpl.WriteFieldStop;

-begin

-  WriteByte(ShortInt(TType.Stop));

-end;

-

-procedure TBinaryProtocolImpl.WriteI16(i16: SmallInt);

-var

-  i16out : TBytes;

-begin

-  SetLength( i16out, 2);

-  i16out[0] := Byte($FF and (i16 shr 8));

-  i16out[1] := Byte($FF and i16);

-  FTrans.Write( i16out );

-end;

-

-procedure TBinaryProtocolImpl.WriteI32(i32: Integer);

-var

-  i32out : TBytes;

-begin

-  SetLength( i32out, 4);

-  i32out[0] := Byte($FF and (i32 shr 24));

-  i32out[1] := Byte($FF and (i32 shr 16));

-  i32out[2] := Byte($FF and (i32 shr 8));

-  i32out[3] := Byte($FF and i32);

-  FTrans.Write( i32out, 0, 4);

-end;

-

-procedure TBinaryProtocolImpl.WriteI64( const i64: Int64);

-var

-  i64out : TBytes;

-begin

-  SetLength( i64out, 8);

-  i64out[0] := Byte($FF and (i64 shr 56));

-  i64out[1] := Byte($FF and (i64 shr 48));

-  i64out[2] := Byte($FF and (i64 shr 40));

-  i64out[3] := Byte($FF and (i64 shr 32));

-  i64out[4] := Byte($FF and (i64 shr 24));

-  i64out[5] := Byte($FF and (i64 shr 16));

-  i64out[6] := Byte($FF and (i64 shr 8));

-  i64out[7] := Byte($FF and i64);

-  FTrans.Write( i64out, 0, 8);

-end;

-

-procedure TBinaryProtocolImpl.WriteListBegin( const list: IList);

-begin

-  WriteByte(ShortInt(list.ElementType));

-  WriteI32(list.Count);

-end;

-

-procedure TBinaryProtocolImpl.WriteListEnd;

-begin

-

-end;

-

-procedure TBinaryProtocolImpl.WriteMapBegin( const map: IMap);

-begin

-  WriteByte(ShortInt(map.KeyType));

-  WriteByte(ShortInt(map.ValueType));

-  WriteI32(map.Count);

-end;

-

-procedure TBinaryProtocolImpl.WriteMapEnd;

-begin

-

-end;

-

-procedure TBinaryProtocolImpl.WriteMessageBegin( const msg: IMessage);

-var

-  version : Cardinal;

-begin

-  if FStrictWrite then

-  begin

-    version := VERSION_1 or Cardinal( msg.Type_);

-    WriteI32( Integer( version) );

-    WriteString( msg.Name);

-    WriteI32( msg.SeqID);

-  end else

-  begin

-    WriteString( msg.Name);

-    WriteByte(ShortInt( msg.Type_));

-    WriteI32( msg.SeqID);

-  end;

-end;

-

-procedure TBinaryProtocolImpl.WriteMessageEnd;

-begin

-

-end;

-

-procedure TBinaryProtocolImpl.WriteSetBegin( const set_: ISet);

-begin

-  WriteByte(ShortInt(set_.ElementType));

-  WriteI32(set_.Count);

-end;

-

-procedure TBinaryProtocolImpl.WriteSetEnd;

-begin

-

-end;

-

-procedure TBinaryProtocolImpl.WriteStructBegin( const struc: IStruct);

-begin

-

-end;

-

-procedure TBinaryProtocolImpl.WriteStructEnd;

-begin

-

-end;

-

-{ TProtocolException }

-

-constructor TProtocolException.Create;

-begin

-  inherited Create('');

-  FType := UNKNOWN;

-end;

-

-constructor TProtocolException.Create(type_: Integer);

-begin

-  inherited Create('');

-  FType := type_;

-end;

-

-constructor TProtocolException.Create(type_: Integer; const msg: string);

-begin

-  inherited Create( msg );

-  FType := type_;

-end;

-

-{ TThriftStringBuilder }

-

-function TThriftStringBuilder.Append(const Value: TBytes): TStringBuilder;

-begin

-  Result := Append( string( RawByteString(Value)) );

-end;

-

-function TThriftStringBuilder.Append(

-  const Value: IThriftContainer): TStringBuilder;

-begin

-  Result := Append( Value.ToString );

-end;

-

-{ TBinaryProtocolImpl.TFactory }

-

-constructor TBinaryProtocolImpl.TFactory.Create(AStrictRead, AStrictWrite: Boolean);

-begin

-  FStrictRead := AStrictRead;

-  FStrictWrite := AStrictWrite;

-end;

-

-constructor TBinaryProtocolImpl.TFactory.Create;

-begin

-  Create( False, True )

-end;

-

-function TBinaryProtocolImpl.TFactory.GetProtocol( const trans: ITransport): IProtocol;

-begin

-  Result := TBinaryProtocolImpl.Create( trans, FStrictRead, FStrictWrite);

-end;

-

-

-{ TProtocolDecorator }

-

-constructor TProtocolDecorator.Create( const aProtocol : IProtocol);

-begin

-  ASSERT( aProtocol <> nil);

-  inherited Create( aProtocol.Transport);

-  FWrappedProtocol := aProtocol;

-end;

-

-

-procedure TProtocolDecorator.WriteMessageBegin( const msg: IMessage);

-begin

-  FWrappedProtocol.WriteMessageBegin( msg);

-end;

-

-

-procedure TProtocolDecorator.WriteMessageEnd;

-begin

-  FWrappedProtocol.WriteMessageEnd;

-end;

-

-

-procedure TProtocolDecorator.WriteStructBegin( const struc: IStruct);

-begin

-  FWrappedProtocol.WriteStructBegin( struc);

-end;

-

-

-procedure TProtocolDecorator.WriteStructEnd;

-begin

-  FWrappedProtocol.WriteStructEnd;

-end;

-

-

-procedure TProtocolDecorator.WriteFieldBegin( const field: IField);

-begin

-  FWrappedProtocol.WriteFieldBegin( field);

-end;

-

-

-procedure TProtocolDecorator.WriteFieldEnd;

-begin

-  FWrappedProtocol.WriteFieldEnd;

-end;

-

-

-procedure TProtocolDecorator.WriteFieldStop;

-begin

-  FWrappedProtocol.WriteFieldStop;

-end;

-

-

-procedure TProtocolDecorator.WriteMapBegin( const map: IMap);

-begin

-  FWrappedProtocol.WriteMapBegin( map);

-end;

-

-

-procedure TProtocolDecorator.WriteMapEnd;

-begin

-  FWrappedProtocol.WriteMapEnd;

-end;

-

-

-procedure TProtocolDecorator.WriteListBegin( const list: IList);

-begin

-  FWrappedProtocol.WriteListBegin( list);

-end;

-

-

-procedure TProtocolDecorator.WriteListEnd();

-begin

-  FWrappedProtocol.WriteListEnd();

-end;

-

-

-procedure TProtocolDecorator.WriteSetBegin( const set_: ISet );

-begin

-  FWrappedProtocol.WriteSetBegin( set_);

-end;

-

-

-procedure TProtocolDecorator.WriteSetEnd();

-begin

-  FWrappedProtocol.WriteSetEnd();

-end;

-

-

-procedure TProtocolDecorator.WriteBool( b: Boolean);

-begin

-  FWrappedProtocol.WriteBool( b);

-end;

-

-

-procedure TProtocolDecorator.WriteByte( b: ShortInt);

-begin

-  FWrappedProtocol.WriteByte( b);

-end;

-

-

-procedure TProtocolDecorator.WriteI16( i16: SmallInt);

-begin

-  FWrappedProtocol.WriteI16( i16);

-end;

-

-

-procedure TProtocolDecorator.WriteI32( i32: Integer);

-begin

-  FWrappedProtocol.WriteI32( i32);

-end;

-

-

-procedure TProtocolDecorator.WriteI64( const i64: Int64);

-begin

-  FWrappedProtocol.WriteI64( i64);

-end;

-

-

-procedure TProtocolDecorator.WriteDouble( const d: Double);

-begin

-  FWrappedProtocol.WriteDouble( d);

-end;

-

-

-procedure TProtocolDecorator.WriteString( const s: string );

-begin

-  FWrappedProtocol.WriteString( s);

-end;

-

-

-procedure TProtocolDecorator.WriteAnsiString( const s: AnsiString);

-begin

-  FWrappedProtocol.WriteAnsiString( s);

-end;

-

-

-procedure TProtocolDecorator.WriteBinary( const b: TBytes);

-begin

-  FWrappedProtocol.WriteBinary( b);

-end;

-

-

-function TProtocolDecorator.ReadMessageBegin: IMessage;

-begin

-  result := FWrappedProtocol.ReadMessageBegin;

-end;

-

-

-procedure TProtocolDecorator.ReadMessageEnd();

-begin

-  FWrappedProtocol.ReadMessageEnd();

-end;

-

-

-function TProtocolDecorator.ReadStructBegin: IStruct;

-begin

-  result := FWrappedProtocol.ReadStructBegin;

-end;

-

-

-procedure TProtocolDecorator.ReadStructEnd;

-begin

-  FWrappedProtocol.ReadStructEnd;

-end;

-

-

-function TProtocolDecorator.ReadFieldBegin: IField;

-begin

-  result := FWrappedProtocol.ReadFieldBegin;

-end;

-

-

-procedure TProtocolDecorator.ReadFieldEnd();

-begin

-  FWrappedProtocol.ReadFieldEnd();

-end;

-

-

-function TProtocolDecorator.ReadMapBegin: IMap;

-begin

-  result := FWrappedProtocol.ReadMapBegin;

-end;

-

-

-procedure TProtocolDecorator.ReadMapEnd();

-begin

-  FWrappedProtocol.ReadMapEnd();

-end;

-

-

-function TProtocolDecorator.ReadListBegin: IList;

-begin

-  result := FWrappedProtocol.ReadListBegin;

-end;

-

-

-procedure TProtocolDecorator.ReadListEnd();

-begin

-  FWrappedProtocol.ReadListEnd();

-end;

-

-

-function TProtocolDecorator.ReadSetBegin: ISet;

-begin

-  result := FWrappedProtocol.ReadSetBegin;

-end;

-

-

-procedure TProtocolDecorator.ReadSetEnd();

-begin

-  FWrappedProtocol.ReadSetEnd();

-end;

-

-

-function TProtocolDecorator.ReadBool: Boolean;

-begin

-  result := FWrappedProtocol.ReadBool;

-end;

-

-

-function TProtocolDecorator.ReadByte: ShortInt;

-begin

-  result := FWrappedProtocol.ReadByte;

-end;

-

-

-function TProtocolDecorator.ReadI16: SmallInt;

-begin

-  result := FWrappedProtocol.ReadI16;

-end;

-

-

-function TProtocolDecorator.ReadI32: Integer;

-begin

-  result := FWrappedProtocol.ReadI32;

-end;

-

-

-function TProtocolDecorator.ReadI64: Int64;

-begin

-  result := FWrappedProtocol.ReadI64;

-end;

-

-

-function TProtocolDecorator.ReadDouble:Double;

-begin

-  result := FWrappedProtocol.ReadDouble;

-end;

-

-

-function TProtocolDecorator.ReadBinary: TBytes;

-begin

-  result := FWrappedProtocol.ReadBinary;

-end;

-

-

-function TProtocolDecorator.ReadString: string;

-begin

-  result := FWrappedProtocol.ReadString;

-end;

-

-

-function TProtocolDecorator.ReadAnsiString: AnsiString;

-begin

-  result := FWrappedProtocol.ReadAnsiString;

-end;

-

-

-

-end.

-

+(*
+ * 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.
+ *)
+
+{$SCOPEDENUMS ON}
+
+unit Thrift.Protocol;
+
+interface
+
+uses
+  Classes,
+  SysUtils,
+  Contnrs,
+  Thrift.Exception,
+  Thrift.Stream,
+  Thrift.Collections,
+  Thrift.Transport;
+
+type
+
+  TType = (
+    Stop = 0,
+    Void = 1,
+    Bool_ = 2,
+    Byte_ = 3,
+    Double_ = 4,
+    I16 = 6,
+    I32 = 8,
+    I64 = 10,
+    String_ = 11,
+    Struct = 12,
+    Map = 13,
+    Set_ = 14,
+    List = 15
+  );
+
+  TMessageType = (
+    Call = 1,
+    Reply = 2,
+    Exception = 3,
+    Oneway = 4
+  );
+
+const
+  VALID_TTYPES = [
+    TType.Stop, TType.Void,
+    TType.Bool_, TType.Byte_, TType.Double_, TType.I16, TType.I32, TType.I64, TType.String_,
+    TType.Struct, TType.Map, TType.Set_, TType.List
+  ];
+
+  VALID_MESSAGETYPES = [Low(TMessageType)..High(TMessageType)];
+
+const
+  DEFAULT_RECURSION_LIMIT = 64;
+
+type
+  IProtocol = interface;
+
+  TThriftMessage = record
+    Name: string;
+    Type_: TMessageType;
+    SeqID: Integer;
+  end;
+
+  TThriftStruct = record
+    Name: string;
+  end;
+
+  TThriftField = record
+    Name: string;
+    Type_: TType;
+    Id: SmallInt;
+  end;
+
+  TThriftList = record
+    ElementType: TType;
+    Count: Integer;
+  end;
+
+  TThriftMap = record
+    KeyType: TType;
+    ValueType: TType;
+    Count: Integer;
+  end;
+
+  TThriftSet = record
+    ElementType: TType;
+    Count: Integer;
+  end;
+
+
+
+  IProtocolFactory = interface
+    ['{7CD64A10-4E9F-4E99-93BF-708A31F4A67B}']
+    function GetProtocol( const trans: ITransport): IProtocol;
+  end;
+
+  TThriftStringBuilder = class( TStringBuilder)
+  public
+    function Append(const Value: TBytes): TStringBuilder; overload;
+    function Append(const Value: IThriftContainer): TStringBuilder; overload;
+  end;
+
+  TProtocolException = class( TException)
+  public
+    const // TODO(jensg): change into enum
+      UNKNOWN = 0;
+      INVALID_DATA = 1;
+      NEGATIVE_SIZE = 2;
+      SIZE_LIMIT = 3;
+      BAD_VERSION = 4;
+      NOT_IMPLEMENTED = 5;
+      DEPTH_LIMIT = 6;
+  protected
+    constructor HiddenCreate(const Msg: string);
+  public
+    // purposefully hide inherited constructor
+    class function Create(const Msg: string): TProtocolException; overload; deprecated 'Use specialized TProtocolException types (or regenerate from IDL)';
+    class function Create: TProtocolException; overload; deprecated 'Use specialized TProtocolException types (or regenerate from IDL)';
+    class function Create( type_: Integer): TProtocolException; overload; deprecated 'Use specialized TProtocolException types (or regenerate from IDL)';
+    class function Create( type_: Integer; const msg: string): TProtocolException; overload; deprecated 'Use specialized TProtocolException types (or regenerate from IDL)';
+  end;
+
+  // Needed to remove deprecation warning
+  TProtocolExceptionSpecialized = class abstract (TProtocolException)
+  public
+    constructor Create(const Msg: string);
+  end;
+
+  TProtocolExceptionUnknown = class (TProtocolExceptionSpecialized);
+  TProtocolExceptionInvalidData = class (TProtocolExceptionSpecialized);
+  TProtocolExceptionNegativeSize = class (TProtocolExceptionSpecialized);
+  TProtocolExceptionSizeLimit = class (TProtocolExceptionSpecialized);
+  TProtocolExceptionBadVersion = class (TProtocolExceptionSpecialized);
+  TProtocolExceptionNotImplemented = class (TProtocolExceptionSpecialized);
+  TProtocolExceptionDepthLimit = class (TProtocolExceptionSpecialized);
+
+
+  TProtocolUtil = class
+  public
+    class procedure Skip( prot: IProtocol; type_: TType);
+  end;
+
+  IProtocolRecursionTracker = interface
+    ['{29CA033F-BB56-49B1-9EE3-31B1E82FC7A5}']
+    // no members yet
+  end;
+
+  TProtocolRecursionTrackerImpl = class abstract( TInterfacedObject, IProtocolRecursionTracker)
+  protected
+    FProtocol : IProtocol;
+  public
+    constructor Create( prot : IProtocol);
+    destructor Destroy; override;
+  end;
+
+  IProtocol = interface
+    ['{602A7FFB-0D9E-4CD8-8D7F-E5076660588A}']
+    function GetTransport: ITransport;
+    procedure WriteMessageBegin( const msg: TThriftMessage);
+    procedure WriteMessageEnd;
+    procedure WriteStructBegin( const struc: TThriftStruct);
+    procedure WriteStructEnd;
+    procedure WriteFieldBegin( const field: TThriftField);
+    procedure WriteFieldEnd;
+    procedure WriteFieldStop;
+    procedure WriteMapBegin( const map: TThriftMap);
+    procedure WriteMapEnd;
+    procedure WriteListBegin( const list: TThriftList);
+    procedure WriteListEnd();
+    procedure WriteSetBegin( const set_: TThriftSet );
+    procedure WriteSetEnd();
+    procedure WriteBool( b: Boolean);
+    procedure WriteByte( b: ShortInt);
+    procedure WriteI16( i16: SmallInt);
+    procedure WriteI32( i32: Integer);
+    procedure WriteI64( const i64: Int64);
+    procedure WriteDouble( const d: Double);
+    procedure WriteString( const s: string );
+    procedure WriteAnsiString( const s: AnsiString);
+    procedure WriteBinary( const b: TBytes);
+
+    function ReadMessageBegin: TThriftMessage;
+    procedure ReadMessageEnd();
+    function ReadStructBegin: TThriftStruct;
+    procedure ReadStructEnd;
+    function ReadFieldBegin: TThriftField;
+    procedure ReadFieldEnd();
+    function ReadMapBegin: TThriftMap;
+    procedure ReadMapEnd();
+    function ReadListBegin: TThriftList;
+    procedure ReadListEnd();
+    function ReadSetBegin: TThriftSet;
+    procedure ReadSetEnd();
+    function ReadBool: Boolean;
+    function ReadByte: ShortInt;
+    function ReadI16: SmallInt;
+    function ReadI32: Integer;
+    function ReadI64: Int64;
+    function ReadDouble:Double;
+    function ReadBinary: TBytes;
+    function ReadString: string;
+    function ReadAnsiString: AnsiString;
+
+    procedure SetRecursionLimit( value : Integer);
+    function  GetRecursionLimit : Integer;
+    function  NextRecursionLevel : IProtocolRecursionTracker;
+    procedure IncrementRecursionDepth;
+    procedure DecrementRecursionDepth;
+
+    property Transport: ITransport read GetTransport;
+    property RecursionLimit : Integer read GetRecursionLimit write SetRecursionLimit;
+  end;
+
+  TProtocolImpl = class abstract( TInterfacedObject, IProtocol)
+  protected
+    FTrans : ITransport;
+    FRecursionLimit : Integer;
+    FRecursionDepth : Integer;
+
+    procedure SetRecursionLimit( value : Integer);
+    function  GetRecursionLimit : Integer;
+    function  NextRecursionLevel : IProtocolRecursionTracker;
+    procedure IncrementRecursionDepth;
+    procedure DecrementRecursionDepth;
+
+    function GetTransport: ITransport;
+  public
+    procedure WriteMessageBegin( const msg: TThriftMessage); virtual; abstract;
+    procedure WriteMessageEnd; virtual; abstract;
+    procedure WriteStructBegin( const struc: TThriftStruct); virtual; abstract;
+    procedure WriteStructEnd; virtual; abstract;
+    procedure WriteFieldBegin( const field: TThriftField); virtual; abstract;
+    procedure WriteFieldEnd; virtual; abstract;
+    procedure WriteFieldStop; virtual; abstract;
+    procedure WriteMapBegin( const map: TThriftMap); virtual; abstract;
+    procedure WriteMapEnd; virtual; abstract;
+    procedure WriteListBegin( const list: TThriftList); virtual; abstract;
+    procedure WriteListEnd(); virtual; abstract;
+    procedure WriteSetBegin( const set_: TThriftSet ); virtual; abstract;
+    procedure WriteSetEnd(); virtual; abstract;
+    procedure WriteBool( b: Boolean); virtual; abstract;
+    procedure WriteByte( b: ShortInt); virtual; abstract;
+    procedure WriteI16( i16: SmallInt); virtual; abstract;
+    procedure WriteI32( i32: Integer); virtual; abstract;
+    procedure WriteI64( const i64: Int64); virtual; abstract;
+    procedure WriteDouble( const d: Double); virtual; abstract;
+    procedure WriteString( const s: string ); virtual;
+    procedure WriteAnsiString( const s: AnsiString); virtual;
+    procedure WriteBinary( const b: TBytes); virtual; abstract;
+
+    function ReadMessageBegin: TThriftMessage; virtual; abstract;
+    procedure ReadMessageEnd(); virtual; abstract;
+    function ReadStructBegin: TThriftStruct; virtual; abstract;
+    procedure ReadStructEnd; virtual; abstract;
+    function ReadFieldBegin: TThriftField; virtual; abstract;
+    procedure ReadFieldEnd(); virtual; abstract;
+    function ReadMapBegin: TThriftMap; virtual; abstract;
+    procedure ReadMapEnd(); virtual; abstract;
+    function ReadListBegin: TThriftList; virtual; abstract;
+    procedure ReadListEnd(); virtual; abstract;
+    function ReadSetBegin: TThriftSet; virtual; abstract;
+    procedure ReadSetEnd(); virtual; abstract;
+    function ReadBool: Boolean; virtual; abstract;
+    function ReadByte: ShortInt; virtual; abstract;
+    function ReadI16: SmallInt; virtual; abstract;
+    function ReadI32: Integer; virtual; abstract;
+    function ReadI64: Int64; virtual; abstract;
+    function ReadDouble:Double; virtual; abstract;
+    function ReadBinary: TBytes; virtual; abstract;
+    function ReadString: string; virtual;
+    function ReadAnsiString: AnsiString; virtual;
+
+    property Transport: ITransport read GetTransport;
+
+    constructor Create( trans: ITransport );
+  end;
+
+  IBase = interface
+    ['{08D9BAA8-5EAA-410F-B50B-AC2E6E5E4155}']
+    function ToString: string;
+    procedure Read( const iprot: IProtocol);
+    procedure Write( const iprot: IProtocol);
+  end;
+
+
+  TBinaryProtocolImpl = class( TProtocolImpl )
+  protected
+    const
+      VERSION_MASK : Cardinal = $ffff0000;
+      VERSION_1 : Cardinal = $80010000;
+  protected
+    FStrictRead : Boolean;
+    FStrictWrite : Boolean;
+
+  private
+    function ReadAll( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer ): Integer;  inline;
+    function ReadStringBody( size: Integer): string;
+
+  public
+
+    type
+      TFactory = class( TInterfacedObject, IProtocolFactory)
+      protected
+        FStrictRead : Boolean;
+        FStrictWrite : Boolean;
+      public
+        function GetProtocol( const trans: ITransport): IProtocol;
+        constructor Create( AStrictRead, AStrictWrite: Boolean ); overload;
+        constructor Create; overload;
+      end;
+
+    constructor Create( const trans: ITransport); overload;
+    constructor Create( const trans: ITransport; strictRead: Boolean; strictWrite: Boolean); overload;
+
+    procedure WriteMessageBegin( const msg: TThriftMessage); override;
+    procedure WriteMessageEnd; override;
+    procedure WriteStructBegin( const struc: TThriftStruct); override;
+    procedure WriteStructEnd; override;
+    procedure WriteFieldBegin( const field: TThriftField); override;
+    procedure WriteFieldEnd; override;
+    procedure WriteFieldStop; override;
+    procedure WriteMapBegin( const map: TThriftMap); override;
+    procedure WriteMapEnd; override;
+    procedure WriteListBegin( const list: TThriftList); override;
+    procedure WriteListEnd(); override;
+    procedure WriteSetBegin( const set_: TThriftSet ); override;
+    procedure WriteSetEnd(); override;
+    procedure WriteBool( b: Boolean); override;
+    procedure WriteByte( b: ShortInt); override;
+    procedure WriteI16( i16: SmallInt); override;
+    procedure WriteI32( i32: Integer); override;
+    procedure WriteI64( const i64: Int64); override;
+    procedure WriteDouble( const d: Double); override;
+    procedure WriteBinary( const b: TBytes); override;
+
+    function ReadMessageBegin: TThriftMessage; override;
+    procedure ReadMessageEnd(); override;
+    function ReadStructBegin: TThriftStruct; override;
+    procedure ReadStructEnd; override;
+    function ReadFieldBegin: TThriftField; override;
+    procedure ReadFieldEnd(); override;
+    function ReadMapBegin: TThriftMap; override;
+    procedure ReadMapEnd(); override;
+    function ReadListBegin: TThriftList; override;
+    procedure ReadListEnd(); override;
+    function ReadSetBegin: TThriftSet; override;
+    procedure ReadSetEnd(); override;
+    function ReadBool: Boolean; override;
+    function ReadByte: ShortInt; override;
+    function ReadI16: SmallInt; override;
+    function ReadI32: Integer; override;
+    function ReadI64: Int64; override;
+    function ReadDouble:Double; override;
+    function ReadBinary: TBytes; override;
+
+  end;
+
+
+  { TProtocolDecorator forwards all requests to an enclosed TProtocol instance,
+    providing a way to author concise concrete decorator subclasses. The decorator
+    does not (and should not) modify the behaviour of the enclosed TProtocol
+
+    See p.175 of Design Patterns (by Gamma et al.)
+  }
+  TProtocolDecorator = class( TProtocolImpl)
+  private
+    FWrappedProtocol : IProtocol;
+
+  public
+    // Encloses the specified protocol.
+    // All operations will be forward to the given protocol.  Must be non-null.
+    constructor Create( const aProtocol : IProtocol);
+
+    procedure WriteMessageBegin( const msg: TThriftMessage); override;
+    procedure WriteMessageEnd; override;
+    procedure WriteStructBegin( const struc: TThriftStruct); override;
+    procedure WriteStructEnd; override;
+    procedure WriteFieldBegin( const field: TThriftField); override;
+    procedure WriteFieldEnd; override;
+    procedure WriteFieldStop; override;
+    procedure WriteMapBegin( const map: TThriftMap); override;
+    procedure WriteMapEnd; override;
+    procedure WriteListBegin( const list: TThriftList); override;
+    procedure WriteListEnd(); override;
+    procedure WriteSetBegin( const set_: TThriftSet ); override;
+    procedure WriteSetEnd(); override;
+    procedure WriteBool( b: Boolean); override;
+    procedure WriteByte( b: ShortInt); override;
+    procedure WriteI16( i16: SmallInt); override;
+    procedure WriteI32( i32: Integer); override;
+    procedure WriteI64( const i64: Int64); override;
+    procedure WriteDouble( const d: Double); override;
+    procedure WriteString( const s: string ); override;
+    procedure WriteAnsiString( const s: AnsiString); override;
+    procedure WriteBinary( const b: TBytes); override;
+
+    function ReadMessageBegin: TThriftMessage; override;
+    procedure ReadMessageEnd(); override;
+    function ReadStructBegin: TThriftStruct; override;
+    procedure ReadStructEnd; override;
+    function ReadFieldBegin: TThriftField; override;
+    procedure ReadFieldEnd(); override;
+    function ReadMapBegin: TThriftMap; override;
+    procedure ReadMapEnd(); override;
+    function ReadListBegin: TThriftList; override;
+    procedure ReadListEnd(); override;
+    function ReadSetBegin: TThriftSet; override;
+    procedure ReadSetEnd(); override;
+    function ReadBool: Boolean; override;
+    function ReadByte: ShortInt; override;
+    function ReadI16: SmallInt; override;
+    function ReadI32: Integer; override;
+    function ReadI64: Int64; override;
+    function ReadDouble:Double; override;
+    function ReadBinary: TBytes; override;
+    function ReadString: string; override;
+    function ReadAnsiString: AnsiString; override;
+  end;
+
+
+type
+  IRequestEvents = interface
+    ['{F926A26A-5B00-4560-86FA-2CAE3BA73DAF}']
+    // Called before reading arguments.
+    procedure PreRead;
+    // Called between reading arguments and calling the handler.
+    procedure PostRead;
+    // Called between calling the handler and writing the response.
+    procedure PreWrite;
+    // Called after writing the response.
+    procedure PostWrite;
+    // Called when an oneway (async) function call completes successfully.
+    procedure OnewayComplete;
+    // Called if the handler throws an undeclared exception.
+    procedure UnhandledError( const e : Exception);
+    // Called when a client has finished request-handling to clean up
+    procedure CleanupContext;
+  end;
+
+
+  IProcessorEvents = interface
+    ['{A8661119-657C-447D-93C5-512E36162A45}']
+    // Called when a client is about to call the processor.
+    procedure Processing( const transport : ITransport);
+    // Called on any service function invocation
+    function  CreateRequestContext( const aFunctionName : string) : IRequestEvents;
+    // Called when a client has finished request-handling to clean up
+    procedure CleanupContext;
+  end;
+
+
+  IProcessor = interface
+    ['{7BAE92A5-46DA-4F13-B6EA-0EABE233EE5F}']
+    function Process( const iprot :IProtocol; const oprot: IProtocol; const events : IProcessorEvents = nil): Boolean;
+  end;
+
+
+procedure Init( var rec : TThriftMessage; const AName: string = ''; const AMessageType: TMessageType = Low(TMessageType); const ASeqID: Integer = 0);  overload;  inline;
+procedure Init( var rec : TThriftStruct;  const AName: string = '');  overload;  inline;
+procedure Init( var rec : TThriftField;   const AName: string = ''; const AType: TType = Low(TType); const AID: SmallInt = 0);  overload;  inline;
+procedure Init( var rec : TThriftMap;     const AKeyType: TType = Low(TType); const AValueType: TType = Low(TType); const ACount: Integer = 0); overload;  inline;
+procedure Init( var rec : TThriftSet;     const AElementType: TType = Low(TType); const ACount: Integer = 0); overload;  inline;
+procedure Init( var rec : TThriftList;    const AElementType: TType = Low(TType); const ACount: Integer = 0); overload;  inline;
+
+
+implementation
+
+function ConvertInt64ToDouble( const n: Int64): Double;
+begin
+  ASSERT( SizeOf(n) = SizeOf(Result));
+  System.Move( n, Result, SizeOf(Result));
+end;
+
+function ConvertDoubleToInt64( const d: Double): Int64;
+begin
+  ASSERT( SizeOf(d) = SizeOf(Result));
+  System.Move( d, Result, SizeOf(Result));
+end;
+
+
+
+{ TProtocolRecursionTrackerImpl }
+
+constructor TProtocolRecursionTrackerImpl.Create( prot : IProtocol);
+begin
+  inherited Create;
+
+  // storing the pointer *after* the (successful) increment is important here
+  prot.IncrementRecursionDepth;
+  FProtocol := prot;
+end;
+
+destructor TProtocolRecursionTrackerImpl.Destroy;
+begin
+  try
+    // we have to release the reference iff the pointer has been stored
+    if FProtocol <> nil then begin
+      FProtocol.DecrementRecursionDepth;
+      FProtocol := nil;
+    end;
+  finally
+    inherited Destroy;
+  end;
+end;
+
+{ TProtocolImpl }
+
+constructor TProtocolImpl.Create(trans: ITransport);
+begin
+  inherited Create;
+  FTrans := trans;
+  FRecursionLimit := DEFAULT_RECURSION_LIMIT;
+  FRecursionDepth := 0;
+end;
+
+procedure TProtocolImpl.SetRecursionLimit( value : Integer);
+begin
+  FRecursionLimit := value;
+end;
+
+function TProtocolImpl.GetRecursionLimit : Integer;
+begin
+  result := FRecursionLimit;
+end;
+
+function TProtocolImpl.NextRecursionLevel : IProtocolRecursionTracker;
+begin
+  result := TProtocolRecursionTrackerImpl.Create(Self);
+end;
+
+procedure TProtocolImpl.IncrementRecursionDepth;
+begin
+  if FRecursionDepth < FRecursionLimit
+  then Inc(FRecursionDepth)
+  else raise TProtocolExceptionDepthLimit.Create('Depth limit exceeded');
+end;
+
+procedure TProtocolImpl.DecrementRecursionDepth;
+begin
+  Dec(FRecursionDepth)
+end;
+
+function TProtocolImpl.GetTransport: ITransport;
+begin
+  Result := FTrans;
+end;
+
+function TProtocolImpl.ReadAnsiString: AnsiString;
+var
+  b : TBytes;
+  len : Integer;
+begin
+  Result := '';
+  b := ReadBinary;
+  len := Length( b );
+  if len > 0 then
+  begin
+    SetLength( Result, len);
+    System.Move( b[0], Pointer(Result)^, len );
+  end;
+end;
+
+function TProtocolImpl.ReadString: string;
+begin
+  Result := TEncoding.UTF8.GetString( ReadBinary );
+end;
+
+procedure TProtocolImpl.WriteAnsiString(const s: AnsiString);
+var
+  b : TBytes;
+  len : Integer;
+begin
+  len := Length(s);
+  SetLength( b, len);
+  if len > 0 then
+  begin
+    System.Move( Pointer(s)^, b[0], len );
+  end;
+  WriteBinary( b );
+end;
+
+procedure TProtocolImpl.WriteString(const s: string);
+var
+  b : TBytes;
+begin
+  b := TEncoding.UTF8.GetBytes(s);
+  WriteBinary( b );
+end;
+
+{ TProtocolUtil }
+
+class procedure TProtocolUtil.Skip( prot: IProtocol; type_: TType);
+var field : TThriftField;
+    map   : TThriftMap;
+    set_  : TThriftSet;
+    list  : TThriftList;
+    i     : Integer;
+    tracker : IProtocolRecursionTracker;
+begin
+  tracker := prot.NextRecursionLevel;
+  case type_ of
+    // simple types
+    TType.Bool_   :  prot.ReadBool();
+    TType.Byte_   :  prot.ReadByte();
+    TType.I16     :  prot.ReadI16();
+    TType.I32     :  prot.ReadI32();
+    TType.I64     :  prot.ReadI64();
+    TType.Double_ :  prot.ReadDouble();
+    TType.String_ :  prot.ReadBinary();// Don't try to decode the string, just skip it.
+
+    // structured types
+    TType.Struct :  begin
+      prot.ReadStructBegin();
+      while TRUE do begin
+        field := prot.ReadFieldBegin();
+        if (field.Type_ = TType.Stop) then Break;
+        Skip(prot, field.Type_);
+        prot.ReadFieldEnd();
+      end;
+      prot.ReadStructEnd();
+    end;
+
+    TType.Map :  begin
+      map := prot.ReadMapBegin();
+      for i := 0 to map.Count-1 do begin
+        Skip(prot, map.KeyType);
+        Skip(prot, map.ValueType);
+      end;
+      prot.ReadMapEnd();
+    end;
+
+    TType.Set_ :  begin
+      set_ := prot.ReadSetBegin();
+      for i := 0 to set_.Count-1
+      do Skip( prot, set_.ElementType);
+      prot.ReadSetEnd();
+    end;
+
+    TType.List :  begin
+      list := prot.ReadListBegin();
+      for i := 0 to list.Count-1
+      do Skip( prot, list.ElementType);
+      prot.ReadListEnd();
+    end;
+
+  else
+    raise TProtocolExceptionInvalidData.Create('Unexpected type '+IntToStr(Ord(type_)));
+  end;
+end;
+
+
+{ TBinaryProtocolImpl }
+
+constructor TBinaryProtocolImpl.Create( const trans: ITransport);
+begin
+  //no inherited
+  Create( trans, False, True);
+end;
+
+constructor TBinaryProtocolImpl.Create( const trans: ITransport; strictRead,
+  strictWrite: Boolean);
+begin
+  inherited Create( trans );
+  FStrictRead := strictRead;
+  FStrictWrite := strictWrite;
+end;
+
+function TBinaryProtocolImpl.ReadAll( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer ): Integer;
+begin
+  Result := FTrans.ReadAll( pBuf, buflen, off, len );
+end;
+
+function TBinaryProtocolImpl.ReadBinary: TBytes;
+var
+  size : Integer;
+  buf : TBytes;
+begin
+  size := ReadI32;
+  SetLength( buf, size );
+  FTrans.ReadAll( buf, 0, size);
+  Result := buf;
+end;
+
+function TBinaryProtocolImpl.ReadBool: Boolean;
+begin
+  Result := (ReadByte = 1);
+end;
+
+function TBinaryProtocolImpl.ReadByte: ShortInt;
+begin
+  ReadAll( @result, SizeOf(result), 0, 1);
+end;
+
+function TBinaryProtocolImpl.ReadDouble: Double;
+begin
+  Result := ConvertInt64ToDouble( ReadI64 )
+end;
+
+function TBinaryProtocolImpl.ReadFieldBegin: TThriftField;
+begin
+  Init( result, '', TType( ReadByte), 0);
+  if ( result.Type_ <> TType.Stop ) then begin
+    result.Id := ReadI16;
+  end;
+end;
+
+procedure TBinaryProtocolImpl.ReadFieldEnd;
+begin
+
+end;
+
+function TBinaryProtocolImpl.ReadI16: SmallInt;
+var i16in : packed array[0..1] of Byte;
+begin
+  ReadAll( @i16in, Sizeof(i16in), 0, 2);
+  Result := SmallInt(((i16in[0] and $FF) shl 8) or (i16in[1] and $FF));
+end;
+
+function TBinaryProtocolImpl.ReadI32: Integer;
+var i32in : packed array[0..3] of Byte;
+begin
+  ReadAll( @i32in, SizeOf(i32in), 0, 4);
+
+  Result := Integer(
+    ((i32in[0] and $FF) shl 24) or
+    ((i32in[1] and $FF) shl 16) or
+    ((i32in[2] and $FF) shl 8) or
+     (i32in[3] and $FF));
+
+end;
+
+function TBinaryProtocolImpl.ReadI64: Int64;
+var i64in : packed array[0..7] of Byte;
+begin
+  ReadAll( @i64in, SizeOf(i64in), 0, 8);
+  Result :=
+    (Int64( i64in[0] and $FF) shl 56) or
+    (Int64( i64in[1] and $FF) shl 48) or
+    (Int64( i64in[2] and $FF) shl 40) or
+    (Int64( i64in[3] and $FF) shl 32) or
+    (Int64( i64in[4] and $FF) shl 24) or
+    (Int64( i64in[5] and $FF) shl 16) or
+    (Int64( i64in[6] and $FF) shl 8) or
+    (Int64( i64in[7] and $FF));
+end;
+
+function TBinaryProtocolImpl.ReadListBegin: TThriftList;
+begin
+  result.ElementType := TType(ReadByte);
+  result.Count       := ReadI32;
+end;
+
+procedure TBinaryProtocolImpl.ReadListEnd;
+begin
+
+end;
+
+function TBinaryProtocolImpl.ReadMapBegin: TThriftMap;
+begin
+  result.KeyType   := TType(ReadByte);
+  result.ValueType := TType(ReadByte);
+  result.Count     := ReadI32;
+end;
+
+procedure TBinaryProtocolImpl.ReadMapEnd;
+begin
+
+end;
+
+function TBinaryProtocolImpl.ReadMessageBegin: TThriftMessage;
+var
+  size : Integer;
+  version : Integer;
+begin
+  Init( result);
+  size := ReadI32;
+  if (size < 0) then begin
+    version := size and Integer( VERSION_MASK);
+    if ( version <> Integer( VERSION_1)) then begin
+      raise TProtocolExceptionBadVersion.Create('Bad version in ReadMessageBegin: ' + IntToStr(version) );
+    end;
+    result.Type_ := TMessageType( size and $000000ff);
+    result.Name := ReadString;
+    result.SeqID := ReadI32;
+  end
+  else begin
+    if FStrictRead then begin
+      raise TProtocolExceptionBadVersion.Create('Missing version in readMessageBegin, old client?' );
+    end;
+    result.Name := ReadStringBody( size );
+    result.Type_ := TMessageType( ReadByte );
+    result.SeqID := ReadI32;
+  end;
+end;
+
+procedure TBinaryProtocolImpl.ReadMessageEnd;
+begin
+  inherited;
+
+end;
+
+function TBinaryProtocolImpl.ReadSetBegin: TThriftSet;
+begin
+  result.ElementType := TType(ReadByte);
+  result.Count       := ReadI32;
+end;
+
+procedure TBinaryProtocolImpl.ReadSetEnd;
+begin
+
+end;
+
+function TBinaryProtocolImpl.ReadStringBody( size: Integer): string;
+var
+  buf : TBytes;
+begin
+  SetLength( buf, size );
+  FTrans.ReadAll( buf, 0, size );
+  Result := TEncoding.UTF8.GetString( buf);
+end;
+
+function TBinaryProtocolImpl.ReadStructBegin: TThriftStruct;
+begin
+  Init( Result);
+end;
+
+procedure TBinaryProtocolImpl.ReadStructEnd;
+begin
+  inherited;
+
+end;
+
+procedure TBinaryProtocolImpl.WriteBinary( const b: TBytes);
+var iLen : Integer;
+begin
+  iLen := Length(b);
+  WriteI32( iLen);
+  if iLen > 0 then FTrans.Write(b, 0, iLen);
+end;
+
+procedure TBinaryProtocolImpl.WriteBool(b: Boolean);
+begin
+  if b then begin
+    WriteByte( 1 );
+  end else begin
+    WriteByte( 0 );
+  end;
+end;
+
+procedure TBinaryProtocolImpl.WriteByte(b: ShortInt);
+begin
+  FTrans.Write( @b, 0, 1);
+end;
+
+procedure TBinaryProtocolImpl.WriteDouble( const d: Double);
+begin
+  WriteI64(ConvertDoubleToInt64(d));
+end;
+
+procedure TBinaryProtocolImpl.WriteFieldBegin( const field: TThriftField);
+begin
+  WriteByte(ShortInt(field.Type_));
+  WriteI16(field.ID);
+end;
+
+procedure TBinaryProtocolImpl.WriteFieldEnd;
+begin
+
+end;
+
+procedure TBinaryProtocolImpl.WriteFieldStop;
+begin
+  WriteByte(ShortInt(TType.Stop));
+end;
+
+procedure TBinaryProtocolImpl.WriteI16(i16: SmallInt);
+var i16out : packed array[0..1] of Byte;
+begin
+  i16out[0] := Byte($FF and (i16 shr 8));
+  i16out[1] := Byte($FF and i16);
+  FTrans.Write( @i16out, 0, 2);
+end;
+
+procedure TBinaryProtocolImpl.WriteI32(i32: Integer);
+var i32out : packed array[0..3] of Byte;
+begin
+  i32out[0] := Byte($FF and (i32 shr 24));
+  i32out[1] := Byte($FF and (i32 shr 16));
+  i32out[2] := Byte($FF and (i32 shr 8));
+  i32out[3] := Byte($FF and i32);
+  FTrans.Write( @i32out, 0, 4);
+end;
+
+procedure TBinaryProtocolImpl.WriteI64( const i64: Int64);
+var i64out : packed array[0..7] of Byte;
+begin
+  i64out[0] := Byte($FF and (i64 shr 56));
+  i64out[1] := Byte($FF and (i64 shr 48));
+  i64out[2] := Byte($FF and (i64 shr 40));
+  i64out[3] := Byte($FF and (i64 shr 32));
+  i64out[4] := Byte($FF and (i64 shr 24));
+  i64out[5] := Byte($FF and (i64 shr 16));
+  i64out[6] := Byte($FF and (i64 shr 8));
+  i64out[7] := Byte($FF and i64);
+  FTrans.Write( @i64out, 0, 8);
+end;
+
+procedure TBinaryProtocolImpl.WriteListBegin( const list: TThriftList);
+begin
+  WriteByte(ShortInt(list.ElementType));
+  WriteI32(list.Count);
+end;
+
+procedure TBinaryProtocolImpl.WriteListEnd;
+begin
+
+end;
+
+procedure TBinaryProtocolImpl.WriteMapBegin( const map: TThriftMap);
+begin
+  WriteByte(ShortInt(map.KeyType));
+  WriteByte(ShortInt(map.ValueType));
+  WriteI32(map.Count);
+end;
+
+procedure TBinaryProtocolImpl.WriteMapEnd;
+begin
+
+end;
+
+procedure TBinaryProtocolImpl.WriteMessageBegin( const msg: TThriftMessage);
+var
+  version : Cardinal;
+begin
+  if FStrictWrite then
+  begin
+    version := VERSION_1 or Cardinal( msg.Type_);
+    WriteI32( Integer( version) );
+    WriteString( msg.Name);
+    WriteI32( msg.SeqID);
+  end else
+  begin
+    WriteString( msg.Name);
+    WriteByte(ShortInt( msg.Type_));
+    WriteI32( msg.SeqID);
+  end;
+end;
+
+procedure TBinaryProtocolImpl.WriteMessageEnd;
+begin
+
+end;
+
+procedure TBinaryProtocolImpl.WriteSetBegin( const set_: TThriftSet);
+begin
+  WriteByte(ShortInt(set_.ElementType));
+  WriteI32(set_.Count);
+end;
+
+procedure TBinaryProtocolImpl.WriteSetEnd;
+begin
+
+end;
+
+procedure TBinaryProtocolImpl.WriteStructBegin( const struc: TThriftStruct);
+begin
+
+end;
+
+procedure TBinaryProtocolImpl.WriteStructEnd;
+begin
+
+end;
+
+{ TProtocolException }
+
+constructor TProtocolException.HiddenCreate(const Msg: string);
+begin
+  inherited Create(Msg);
+end;
+
+class function TProtocolException.Create(const Msg: string): TProtocolException;
+begin
+  Result := TProtocolExceptionUnknown.Create(Msg);
+end;
+
+class function TProtocolException.Create: TProtocolException;
+begin
+  Result := TProtocolExceptionUnknown.Create('');
+end;
+
+class function TProtocolException.Create(type_: Integer): TProtocolException;
+begin
+{$WARN SYMBOL_DEPRECATED OFF}
+  Result := Create(type_, '');
+{$WARN SYMBOL_DEPRECATED DEFAULT}
+end;
+
+class function TProtocolException.Create(type_: Integer; const msg: string): TProtocolException;
+begin
+  case type_ of
+    INVALID_DATA:    Result := TProtocolExceptionInvalidData.Create(msg);
+    NEGATIVE_SIZE:   Result := TProtocolExceptionNegativeSize.Create(msg);
+    SIZE_LIMIT:      Result := TProtocolExceptionSizeLimit.Create(msg);
+    BAD_VERSION:     Result := TProtocolExceptionBadVersion.Create(msg);
+    NOT_IMPLEMENTED: Result := TProtocolExceptionNotImplemented.Create(msg);
+    DEPTH_LIMIT:     Result := TProtocolExceptionDepthLimit.Create(msg);
+  else
+    Result := TProtocolExceptionUnknown.Create(msg);
+  end;
+end;
+
+{ TProtocolExceptionSpecialized }
+
+constructor TProtocolExceptionSpecialized.Create(const Msg: string);
+begin
+  inherited HiddenCreate(Msg);
+end;
+
+{ TThriftStringBuilder }
+
+function TThriftStringBuilder.Append(const Value: TBytes): TStringBuilder;
+begin
+  Result := Append( string( RawByteString(Value)) );
+end;
+
+function TThriftStringBuilder.Append(
+  const Value: IThriftContainer): TStringBuilder;
+begin
+  Result := Append( Value.ToString );
+end;
+
+{ TBinaryProtocolImpl.TFactory }
+
+constructor TBinaryProtocolImpl.TFactory.Create(AStrictRead, AStrictWrite: Boolean);
+begin
+  inherited Create;
+  FStrictRead := AStrictRead;
+  FStrictWrite := AStrictWrite;
+end;
+
+constructor TBinaryProtocolImpl.TFactory.Create;
+begin
+  //no inherited;
+  Create( False, True )
+end;
+
+function TBinaryProtocolImpl.TFactory.GetProtocol( const trans: ITransport): IProtocol;
+begin
+  Result := TBinaryProtocolImpl.Create( trans, FStrictRead, FStrictWrite);
+end;
+
+
+{ TProtocolDecorator }
+
+constructor TProtocolDecorator.Create( const aProtocol : IProtocol);
+begin
+  ASSERT( aProtocol <> nil);
+  inherited Create( aProtocol.Transport);
+  FWrappedProtocol := aProtocol;
+end;
+
+
+procedure TProtocolDecorator.WriteMessageBegin( const msg: TThriftMessage);
+begin
+  FWrappedProtocol.WriteMessageBegin( msg);
+end;
+
+
+procedure TProtocolDecorator.WriteMessageEnd;
+begin
+  FWrappedProtocol.WriteMessageEnd;
+end;
+
+
+procedure TProtocolDecorator.WriteStructBegin( const struc: TThriftStruct);
+begin
+  FWrappedProtocol.WriteStructBegin( struc);
+end;
+
+
+procedure TProtocolDecorator.WriteStructEnd;
+begin
+  FWrappedProtocol.WriteStructEnd;
+end;
+
+
+procedure TProtocolDecorator.WriteFieldBegin( const field: TThriftField);
+begin
+  FWrappedProtocol.WriteFieldBegin( field);
+end;
+
+
+procedure TProtocolDecorator.WriteFieldEnd;
+begin
+  FWrappedProtocol.WriteFieldEnd;
+end;
+
+
+procedure TProtocolDecorator.WriteFieldStop;
+begin
+  FWrappedProtocol.WriteFieldStop;
+end;
+
+
+procedure TProtocolDecorator.WriteMapBegin( const map: TThriftMap);
+begin
+  FWrappedProtocol.WriteMapBegin( map);
+end;
+
+
+procedure TProtocolDecorator.WriteMapEnd;
+begin
+  FWrappedProtocol.WriteMapEnd;
+end;
+
+
+procedure TProtocolDecorator.WriteListBegin( const list: TThriftList);
+begin
+  FWrappedProtocol.WriteListBegin( list);
+end;
+
+
+procedure TProtocolDecorator.WriteListEnd();
+begin
+  FWrappedProtocol.WriteListEnd();
+end;
+
+
+procedure TProtocolDecorator.WriteSetBegin( const set_: TThriftSet );
+begin
+  FWrappedProtocol.WriteSetBegin( set_);
+end;
+
+
+procedure TProtocolDecorator.WriteSetEnd();
+begin
+  FWrappedProtocol.WriteSetEnd();
+end;
+
+
+procedure TProtocolDecorator.WriteBool( b: Boolean);
+begin
+  FWrappedProtocol.WriteBool( b);
+end;
+
+
+procedure TProtocolDecorator.WriteByte( b: ShortInt);
+begin
+  FWrappedProtocol.WriteByte( b);
+end;
+
+
+procedure TProtocolDecorator.WriteI16( i16: SmallInt);
+begin
+  FWrappedProtocol.WriteI16( i16);
+end;
+
+
+procedure TProtocolDecorator.WriteI32( i32: Integer);
+begin
+  FWrappedProtocol.WriteI32( i32);
+end;
+
+
+procedure TProtocolDecorator.WriteI64( const i64: Int64);
+begin
+  FWrappedProtocol.WriteI64( i64);
+end;
+
+
+procedure TProtocolDecorator.WriteDouble( const d: Double);
+begin
+  FWrappedProtocol.WriteDouble( d);
+end;
+
+
+procedure TProtocolDecorator.WriteString( const s: string );
+begin
+  FWrappedProtocol.WriteString( s);
+end;
+
+
+procedure TProtocolDecorator.WriteAnsiString( const s: AnsiString);
+begin
+  FWrappedProtocol.WriteAnsiString( s);
+end;
+
+
+procedure TProtocolDecorator.WriteBinary( const b: TBytes);
+begin
+  FWrappedProtocol.WriteBinary( b);
+end;
+
+
+function TProtocolDecorator.ReadMessageBegin: TThriftMessage;
+begin
+  result := FWrappedProtocol.ReadMessageBegin;
+end;
+
+
+procedure TProtocolDecorator.ReadMessageEnd();
+begin
+  FWrappedProtocol.ReadMessageEnd();
+end;
+
+
+function TProtocolDecorator.ReadStructBegin: TThriftStruct;
+begin
+  result := FWrappedProtocol.ReadStructBegin;
+end;
+
+
+procedure TProtocolDecorator.ReadStructEnd;
+begin
+  FWrappedProtocol.ReadStructEnd;
+end;
+
+
+function TProtocolDecorator.ReadFieldBegin: TThriftField;
+begin
+  result := FWrappedProtocol.ReadFieldBegin;
+end;
+
+
+procedure TProtocolDecorator.ReadFieldEnd();
+begin
+  FWrappedProtocol.ReadFieldEnd();
+end;
+
+
+function TProtocolDecorator.ReadMapBegin: TThriftMap;
+begin
+  result := FWrappedProtocol.ReadMapBegin;
+end;
+
+
+procedure TProtocolDecorator.ReadMapEnd();
+begin
+  FWrappedProtocol.ReadMapEnd();
+end;
+
+
+function TProtocolDecorator.ReadListBegin: TThriftList;
+begin
+  result := FWrappedProtocol.ReadListBegin;
+end;
+
+
+procedure TProtocolDecorator.ReadListEnd();
+begin
+  FWrappedProtocol.ReadListEnd();
+end;
+
+
+function TProtocolDecorator.ReadSetBegin: TThriftSet;
+begin
+  result := FWrappedProtocol.ReadSetBegin;
+end;
+
+
+procedure TProtocolDecorator.ReadSetEnd();
+begin
+  FWrappedProtocol.ReadSetEnd();
+end;
+
+
+function TProtocolDecorator.ReadBool: Boolean;
+begin
+  result := FWrappedProtocol.ReadBool;
+end;
+
+
+function TProtocolDecorator.ReadByte: ShortInt;
+begin
+  result := FWrappedProtocol.ReadByte;
+end;
+
+
+function TProtocolDecorator.ReadI16: SmallInt;
+begin
+  result := FWrappedProtocol.ReadI16;
+end;
+
+
+function TProtocolDecorator.ReadI32: Integer;
+begin
+  result := FWrappedProtocol.ReadI32;
+end;
+
+
+function TProtocolDecorator.ReadI64: Int64;
+begin
+  result := FWrappedProtocol.ReadI64;
+end;
+
+
+function TProtocolDecorator.ReadDouble:Double;
+begin
+  result := FWrappedProtocol.ReadDouble;
+end;
+
+
+function TProtocolDecorator.ReadBinary: TBytes;
+begin
+  result := FWrappedProtocol.ReadBinary;
+end;
+
+
+function TProtocolDecorator.ReadString: string;
+begin
+  result := FWrappedProtocol.ReadString;
+end;
+
+
+function TProtocolDecorator.ReadAnsiString: AnsiString;
+begin
+  result := FWrappedProtocol.ReadAnsiString;
+end;
+
+
+{ Init helper functions }
+
+procedure Init( var rec : TThriftMessage; const AName: string; const AMessageType: TMessageType; const ASeqID: Integer);
+begin
+  rec.Name := AName;
+  rec.Type_ := AMessageType;
+  rec.SeqID := ASeqID;
+end;
+
+
+procedure Init( var rec : TThriftStruct; const AName: string = '');
+begin
+  rec.Name := AName;
+end;
+
+
+procedure Init( var rec : TThriftField; const AName: string; const AType: TType; const AID: SmallInt);
+begin
+  rec.Name := AName;
+  rec.Type_ := AType;
+  rec.Id := AId;
+end;
+
+
+procedure Init( var rec : TThriftMap; const AKeyType, AValueType: TType; const ACount: Integer);
+begin
+  rec.ValueType := AValueType;
+  rec.KeyType := AKeyType;
+  rec.Count := ACount;
+end;
+
+
+procedure Init( var rec : TThriftSet; const AElementType: TType; const ACount: Integer);
+begin
+  rec.Count := ACount;
+  rec.ElementType := AElementType;
+end;
+
+
+procedure Init( var rec : TThriftList; const AElementType: TType; const ACount: Integer);
+begin
+  rec.Count := ACount;
+  rec.ElementType := AElementType;
+end;
+
+
+
+
+
+end.
+
diff --git a/lib/delphi/src/Thrift.Serializer.pas b/lib/delphi/src/Thrift.Serializer.pas
index dce6863..5f2905a 100644
--- a/lib/delphi/src/Thrift.Serializer.pas
+++ b/lib/delphi/src/Thrift.Serializer.pas
@@ -18,10 +18,16 @@
  *)
 unit Thrift.Serializer;
 
+{$I Thrift.Defines.inc}
+
 interface
 
 uses
+  {$IFDEF OLD_UNIT_NAMES}
   Classes, Windows, SysUtils,
+  {$ELSE}
+  System.Classes, Winapi.Windows, System.SysUtils,
+  {$ENDIF}
   Thrift.Protocol,
   Thrift.Transport,
   Thrift.Stream;
@@ -86,6 +92,7 @@
 constructor TSerializer.Create();
 // Create a new TSerializer that uses the TBinaryProtocol by default.
 begin
+  //no inherited;
   Create( TBinaryProtocolImpl.TFactory.Create);
 end;
 
@@ -137,7 +144,7 @@
 procedure TSerializer.Serialize( const input : IBase; const aStm : TStream);
 // Serialize the Thrift object into a byte array. The process is simple,
 // just clear the byte array output, write the object into it, and grab the
-// raw bytes. 
+// raw bytes.
 const COPY_ENTIRE_STREAM = 0;
 begin
   try
@@ -156,6 +163,7 @@
 constructor TDeserializer.Create();
 // Create a new TDeserializer that uses the TBinaryProtocol by default.
 begin
+  //no inherited;
   Create( TBinaryProtocolImpl.TFactory.Create);
 end;
 
diff --git a/lib/delphi/src/Thrift.Server.pas b/lib/delphi/src/Thrift.Server.pas
index e6ab7ac..13c5762 100644
--- a/lib/delphi/src/Thrift.Server.pas
+++ b/lib/delphi/src/Thrift.Server.pas
@@ -19,19 +19,42 @@
 
  unit Thrift.Server;
 
+{$I Thrift.Defines.inc}
+{$I-}  // prevent annoying errors with default log delegate and no console
+
 interface
 
 uses
-  SysUtils,
+  {$IFDEF OLD_UNIT_NAMES}
+  Windows, SysUtils,
+  {$ELSE}
+  Winapi.Windows, System.SysUtils,
+  {$ENDIF}
   Thrift,
   Thrift.Protocol,
   Thrift.Transport;
 
 type
+  IServerEvents = interface
+    ['{9E2A99C5-EE85-40B2-9A52-2D1722B18176}']
+    // Called before the server begins.
+    procedure PreServe;
+    // Called when the server transport is ready to accept requests
+    procedure PreAccept;
+    // Called when a new client has connected and the server is about to being processing.
+    function  CreateProcessingContext( const input, output : IProtocol) : IProcessorEvents;
+  end;
+
+
   IServer = interface
-    ['{CF9F56C6-BB39-4C7D-877B-43B416572CE6}']
+    ['{ADC46F2D-8199-4D1C-96D2-87FD54351723}']
     procedure Serve;
     procedure Stop;
+
+    function GetServerEvents : IServerEvents;
+    procedure SetServerEvents( const value : IServerEvents);
+
+    property ServerEvents : IServerEvents read GetServerEvents write SetServerEvents;
   end;
 
   TServerImpl = class abstract( TInterfacedObject, IServer )
@@ -46,9 +69,13 @@
     FInputProtocolFactory : IProtocolFactory;
     FOutputProtocolFactory : IProtocolFactory;
     FLogDelegate : TLogDelegate;
+    FServerEvents : IServerEvents;
 
     class procedure DefaultLogDelegate( const str: string);
 
+    function GetServerEvents : IServerEvents;
+    procedure SetServerEvents( const value : IServerEvents);
+
     procedure Serve; virtual; abstract;
     procedure Stop; virtual; abstract;
   public
@@ -62,10 +89,10 @@
       const ALogDelegate : TLogDelegate
       ); overload;
 
-    constructor Create( 
+    constructor Create(
       const AProcessor :IProcessor;
       const AServerTransport: IServerTransport
-	  ); overload;
+      ); overload;
 
     constructor Create(
       const AProcessor :IProcessor;
@@ -120,6 +147,7 @@
   InputTransFactory := TTransportFactoryImpl.Create;
   OutputTransFactory := TTransportFactoryImpl.Create;
 
+  //no inherited;
   Create(
     AProcessor,
     AServerTransport,
@@ -143,6 +171,7 @@
   InputTransFactory := TTransportFactoryImpl.Create;
   OutputTransFactory := TTransportFactoryImpl.Create;
 
+  //no inherited;
   Create(
     AProcessor,
     AServerTransport,
@@ -163,6 +192,7 @@
   InputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
   OutputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
 
+  //no inherited;
   Create( AProcessor, AServerTransport, ATransportFactory, ATransportFactory,
     InputProtocolFactory, OutputProtocolFactory, DefaultLogDelegate);
 end;
@@ -173,6 +203,7 @@
   const AInputProtocolFactory, AOutputProtocolFactory: IProtocolFactory;
   const ALogDelegate : TLogDelegate);
 begin
+  inherited Create;
   FProcessor := AProcessor;
   FServerTransport := AServerTransport;
   FInputTransportFactory := AInputTransportFactory;
@@ -184,19 +215,39 @@
 
 class procedure TServerImpl.DefaultLogDelegate( const str: string);
 begin
-  Writeln( str );
+  try
+    Writeln( str);
+    if IoResult <> 0 then OutputDebugString(PChar(str));
+  except
+    OutputDebugString(PChar(str));
+  end;
 end;
 
 constructor TServerImpl.Create( const AProcessor: IProcessor;
   const AServerTransport: IServerTransport; const ATransportFactory: ITransportFactory;
   const AProtocolFactory: IProtocolFactory);
 begin
+  //no inherited;
   Create( AProcessor, AServerTransport,
           ATransportFactory, ATransportFactory,
           AProtocolFactory, AProtocolFactory,
           DefaultLogDelegate);
 end;
 
+
+function TServerImpl.GetServerEvents : IServerEvents;
+begin
+  result := FServerEvents;
+end;
+
+
+procedure TServerImpl.SetServerEvents( const value : IServerEvents);
+begin
+  // if you need more than one, provide a specialized IServerEvents implementation
+  FServerEvents := value;
+end;
+
+
 { TSimpleServer }
 
 constructor TSimpleServer.Create( const AProcessor: IProcessor;
@@ -255,6 +306,7 @@
   OutputTransport : ITransport;
   InputProtocol : IProtocol;
   OutputProtocol : IProtocol;
+  context : IProcessorEvents;
 begin
   try
     FServerTransport.Listen;
@@ -265,6 +317,9 @@
     end;
   end;
 
+  if FServerEvents <> nil
+  then FServerEvents.PreServe;
+
   client := nil;
   while (not FStop) do
   begin
@@ -275,16 +330,45 @@
       InputProtocol := nil;
       OutputProtocol := nil;
 
-      client := FServerTransport.Accept;
+      // close any old connections before before waiting for new clients
+      if client <> nil then try
+        try
+          client.Close;
+        finally
+          client := nil;
+        end;
+      except
+        // catch all, we can't do much about it at this point
+      end;
+
+      client := FServerTransport.Accept( procedure
+                                         begin
+                                           if FServerEvents <> nil
+                                           then FServerEvents.PreAccept;
+                                         end);
+
+      if client = nil then begin
+        if FStop
+        then Abort  // silent exception
+        else raise TTransportExceptionUnknown.Create('ServerTransport.Accept() may not return NULL');
+      end;
+
       FLogDelegate( 'Client Connected!');
 
       InputTransport := FInputTransportFactory.GetTransport( client );
       OutputTransport := FOutputTransportFactory.GetTransport( client );
       InputProtocol := FInputProtocolFactory.GetProtocol( InputTransport );
       OutputProtocol := FOutputProtocolFactory.GetProtocol( OutputTransport );
-      while ( FProcessor.Process( InputProtocol, OutputProtocol )) do
-      begin
-        if FStop then Break;
+
+      if FServerEvents <> nil
+      then context := FServerEvents.CreateProcessingContext( InputProtocol, OutputProtocol)
+      else context := nil;
+
+      while not FStop do begin
+        if context <> nil
+        then context.Processing( client);
+        if not FProcessor.Process( InputProtocol, OutputProtocol, context)
+        then Break;
       end;
 
     except
@@ -299,6 +383,13 @@
         FLogDelegate( E.ToString);
       end;
     end;
+
+    if context <> nil
+    then begin
+      context.CleanupContext;
+      context := nil;
+    end;
+
     if InputTransport <> nil then
     begin
       InputTransport.Close;
diff --git a/lib/delphi/src/Thrift.Socket.pas b/lib/delphi/src/Thrift.Socket.pas
new file mode 100644
index 0000000..f0cab79
--- /dev/null
+++ b/lib/delphi/src/Thrift.Socket.pas
@@ -0,0 +1,1617 @@
+(*
+ * 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.
+ *)
+
+unit Thrift.Socket;
+
+{$I Thrift.Defines.inc}
+{$I-}  // prevent annoying errors with default log delegate and no console
+
+interface
+{$IFNDEF OLD_SOCKETS} // not for OLD_SOCKETS
+
+uses
+  Winapi.Windows, Winapi.Winsock2;
+
+const
+  AI_PASSIVE                = $00000001;  // Socket address will be used in bind() call
+  AI_CANONNAME              = $00000002;  // Return canonical name in first ai_canonname
+  AI_NUMERICHOST            = $00000004;  // Nodename must be a numeric address string
+  AI_NUMERICSERV            = $00000008;  // Servicename must be a numeric port number
+
+  AI_ALL                    = $00000100;  // Query both IP6 and IP4 with AI_V4MAPPED
+  AI_ADDRCONFIG             = $00000400;  // Resolution only if global address configured
+  AI_V4MAPPED               = $00000800;  // On v6 failure, query v4 and convert to V4MAPPED format
+
+  AI_NON_AUTHORITATIVE      = $00004000;  // LUP_NON_AUTHORITATIVE
+  AI_SECURE                 = $00008000;  // LUP_SECURE
+  AI_RETURN_PREFERRED_NAMES = $00010000;  // LUP_RETURN_PREFERRED_NAMES
+
+  AI_FQDN                   = $00020000;  // Return the FQDN in ai_canonname
+  AI_FILESERVER             = $00040000;  // Resolving fileserver name resolution
+
+type
+  PAddrInfoA = ^TAddrInfoA;
+  TAddrInfoA = record
+    ai_flags: Integer;
+    ai_family: Integer;
+    ai_socktype: Integer;
+    ai_protocol: Integer;
+    ai_addrlen: NativeUInt;
+    ai_canonname: PAnsiChar;
+    ai_addr: PSockAddr;
+    ai_next: PAddrInfoA;
+  end;
+
+  PAddrInfoW = ^TAddrInfoW;
+  TAddrInfoW = record
+    ai_flags: Integer;
+    ai_family: Integer;
+    ai_socktype: Integer;
+    ai_protocol: Integer;
+    ai_addrlen: NativeUInt;
+    ai_canonname: PChar;
+    ai_addr: PSockAddr;
+    ai_next: PAddrInfoW;
+  end;
+
+  TAddressFamily = USHORT;
+
+  TIn6Addr = record
+  case Integer of
+    0: (_Byte: array[0..15] of UCHAR);
+    1: (_Word: array[0..7] of USHORT);
+  end;
+
+  TScopeId = record
+  public
+    Value: ULONG;
+  private
+    function GetBitField(Loc: Integer): Integer; inline;
+    procedure SetBitField(Loc: Integer; const aValue: Integer); inline;
+  public
+    property Zone: Integer index $0028 read GetBitField write SetBitField;
+    property Level: Integer index $2804 read GetBitField write SetBitField;
+  end;
+
+  TSockAddrIn6 = record
+    sin6_family: TAddressFamily;
+    sin6_port: USHORT;
+    sin6_flowinfo: ULONG;
+    sin6_addr: TIn6Addr;
+  case Integer of
+    0: (sin6_scope_id: ULONG);
+    1: (sin6_scope_struct: TScopeId);
+  end;
+  PSockAddrIn6 = ^TSockAddrIn6;
+
+const
+  NI_NOFQDN      = $01;  // Only return nodename portion for local hosts
+  NI_NUMERICHOST = $02;  // Return numeric form of the host's address
+  NI_NAMEREQD    = $04;  // Error if the host's name not in DNS
+  NI_NUMERICSERV = $08;  // Return numeric form of the service (port #)
+  NI_DGRAM       = $10;  // Service is a datagram service
+
+  NI_MAXHOST     = 1025;  // Max size of a fully-qualified domain name
+  NI_MAXSERV     = 32;    // Max size of a service name
+
+function getaddrinfo(pNodeName, pServiceName: PAnsiChar; const pHints: TAddrInfoA; var ppResult: PAddrInfoA): Integer; stdcall;
+function GetAddrInfoW(pNodeName, pServiceName: PWideChar; const pHints: TAddrInfoW; var ppResult: PAddrInfoW): Integer; stdcall;
+procedure freeaddrinfo(pAddrInfo: PAddrInfoA); stdcall;
+procedure FreeAddrInfoW(pAddrInfo: PAddrInfoW); stdcall;
+function getnameinfo(const pSockaddr: TSockAddr; SockaddrLength: Integer; pNodeBuffer: PAnsiChar; NodeBufferSize: DWORD; pServiceBuffer: PAnsiChar;
+  ServiceBufferSize: DWORD; Flags: Integer): Integer; stdcall;
+function GetNameInfoW(const pSockaddr: TSockAddr; SockaddrLength: Integer; pNodeBuffer: PWideChar; NodeBufferSize: DWORD; pServiceBuffer: PWideChar;
+  ServiceBufferSize: DWORD; Flags: Integer): Integer; stdcall;
+
+type
+  TSmartPointerDestroyer<T> = reference to procedure(Value: T);
+
+  ISmartPointer<T> = reference to function: T;
+
+  TSmartPointer<T> = class(TInterfacedObject, ISmartPointer<T>)
+  private
+    FValue: T;
+    FDestroyer: TSmartPointerDestroyer<T>;
+  public
+    constructor Create(AValue: T; ADestroyer: TSmartPointerDestroyer<T>);
+    destructor Destroy; override;
+    function Invoke: T;
+  end;
+
+  TBaseSocket = class abstract
+  public type
+    TLogDelegate = reference to procedure( const str: string);
+  strict private
+    FPort: Integer;
+    FSocket: Winapi.Winsock2.TSocket;
+    FSendTimeout,
+    FRecvTimeout: Longword;
+    FKeepAlive: Boolean;
+    FLogDelegate: TLogDelegate;
+    class constructor Create;
+    class destructor Destroy;
+    class procedure DefaultLogDelegate(const Str: string);
+  protected type
+    IGetAddrInfoWrapper = interface
+      function Init: Integer;
+      function GetRes: PAddrInfoW;
+      property Res: PAddrInfoW read GetRes;
+    end;
+    TGetAddrInfoWrapper = class(TInterfacedObject, IGetAddrInfoWrapper)
+    strict private
+      FNode: string;
+      FService: string;
+      FHints,
+      FRes: PAddrInfoW;
+    public
+      constructor Create(ANode, AService: string; AHints: PAddrInfoW);
+      destructor Destroy; override;
+      function Init: Integer;
+      function GetRes: PAddrInfoW;
+      property Res: PAddrInfoW read GetRes;
+    end;
+  strict protected
+    procedure CommonInit; virtual;
+    function CreateSocket(AAddress: string; APort: Integer): IGetAddrInfoWrapper;
+    procedure SetRecvTimeout(ARecvTimeout: Longword); virtual;
+    procedure SetSendTimeout(ASendTimeout: Longword); virtual;
+    procedure SetKeepAlive(AKeepAlive: Boolean); virtual;
+    procedure SetSocket(ASocket: Winapi.Winsock2.TSocket);
+    property LogDelegate: TLogDelegate read FLogDelegate;
+  public
+    //
+    // Constructs a new socket. Note that this does NOT actually connect the
+    // socket.
+    //
+    constructor Create(ALogDelegate: TLogDelegate = nil); overload;
+    constructor Create(APort: Integer; ALogDelegate: TLogDelegate = nil); overload;
+
+    //
+    // Destroys the socket object, closing it if necessary.
+    //
+    destructor Destroy; override;
+
+    //
+    // Shuts down communications on the socket
+    //
+    procedure Close; virtual;
+
+    // The port that the socket is connected to
+    property Port: Integer read FPort write FPort;
+
+    // The receive timeout
+    property RecvTimeout: Longword read FRecvTimeout write SetRecvTimeout;
+
+    // The send timeout
+    property SendTimeout: Longword read FSendTimeout write SetSendTimeout;
+
+    // Set SO_KEEPALIVE
+    property KeepAlive: Boolean read FKeepAlive write SetKeepAlive;
+
+    // The underlying socket descriptor
+    property Socket: Winapi.Winsock2.TSocket read FSocket write SetSocket;
+  end;
+
+  TSocket = class(TBaseSocket)
+  strict private type
+    TCachedPeerAddr = record
+    case Integer of
+      0: (ipv4: TSockAddrIn);
+      1: (ipv6: TSockAddrIn6);
+    end;
+  strict private
+    FHost: string;
+    FPeerHost: string;
+    FPeerAddress: string;
+    FPeerPort: Integer;
+    FInterruptListener: ISmartPointer<Winapi.Winsock2.TSocket>;
+    FConnTimeout: Longword;
+    FLingerOn: Boolean;
+    FLingerVal: Integer;
+    FNoDelay: Boolean;
+    FMaxRecvRetries: Longword;
+    FCachedPeerAddr: TCachedPeerAddr;
+    procedure InitPeerInfo;
+    procedure OpenConnection(Res: TBaseSocket.IGetAddrInfoWrapper);
+    procedure LocalOpen;
+    procedure SetGenericTimeout(S: Winapi.Winsock2.TSocket; Timeout: Longword; OptName: Integer);
+    function GetIsOpen: Boolean;
+    procedure SetNoDelay(ANoDelay: Boolean);
+    function GetSocketInfo: string;
+    function GetPeerHost: string;
+    function GetPeerAddress: string;
+    function GetPeerPort: Integer;
+    function GetOrigin: string;
+  strict protected
+    procedure CommonInit; override;
+    procedure SetRecvTimeout(ARecvTimeout: Longword); override;
+    procedure SetSendTimeout(ASendTimeout: Longword); override;
+    procedure SetKeepAlive(AKeepAlive: Boolean); override;
+  public
+    //
+    // Constructs a new socket. Note that this does NOT actually connect the
+    // socket.
+    //
+    constructor Create(ALogDelegate: TBaseSocket.TLogDelegate = nil); overload;
+
+    //
+    // Constructs a new socket. Note that this does NOT actually connect the
+    // socket.
+    //
+    // @param host An IP address or hostname to connect to
+    // @param port The port to connect on
+    //
+    constructor Create(AHost: string; APort: Integer; ALogDelegate: TBaseSocket.TLogDelegate = nil); overload;
+
+    //
+    // Constructor to create socket from socket descriptor.
+    //
+    constructor Create(ASocket: Winapi.Winsock2.TSocket; ALogDelegate: TBaseSocket.TLogDelegate = nil); overload;
+
+    //
+    // Constructor to create socket from socket descriptor that
+    // can be interrupted safely.
+    //
+    constructor Create(ASocket: Winapi.Winsock2.TSocket; AInterruptListener: ISmartPointer<Winapi.Winsock2.TSocket>;
+      ALogDelegate: TBaseSocket.TLogDelegate = nil); overload;
+
+    //
+    // Creates and opens the socket
+    //
+    // @throws ETransportationException If the socket could not connect
+    //
+    procedure Open;
+
+    //
+    // Shuts down communications on the socket
+    //
+    procedure Close; override;
+
+    //
+    // Reads from the underlying socket.
+    // \returns the number of bytes read or 0 indicates EOF
+    // \throws TTransportException of types:
+    //          Interrupted means the socket was interrupted
+    //                      out of a blocking call
+    //          NotOpen means the socket has been closed
+    //          TimedOut means the receive timeout expired
+    //          Unknown means something unexpected happened
+    //
+    function Read(var Buf; Len: Integer): Integer;
+
+    //
+    // Writes to the underlying socket.  Loops until done or fail.
+    //
+    procedure Write(const Buf; Len: Integer);
+
+    //
+    // Writes to the underlying socket.  Does single send() and returns result.
+    //
+    function WritePartial(const Buf; Len: Integer): Integer;
+
+    //
+    // Returns a cached copy of the peer address.
+    //
+    function GetCachedAddress(out Len: Integer): PSockAddr;
+
+    //
+    // Set a cache of the peer address (used when trivially available: e.g.
+    // accept() or connect()). Only caches IPV4 and IPV6; unset for others.
+    //
+    procedure SetCachedAddress(const Addr: TSockAddr; Len: Integer);
+
+    //
+    // Controls whether the linger option is set on the socket.
+    //
+    // @param on      Whether SO_LINGER is on
+    // @param linger  If linger is active, the number of seconds to linger for
+    //
+    procedure SetLinger(LingerOn: Boolean; LingerVal: Integer);
+
+    //
+    // Calls select() on the socket to see if there is more data available.
+    //
+    function Peek: Boolean;
+
+    // Whether the socket is alive
+    property IsOpen: Boolean read GetIsOpen;
+
+    // The host that the socket is connected to
+    property Host: string read FHost write FHost;
+
+    // Whether to enable or disable Nagle's algorithm
+    property NoDelay: Boolean read FNoDelay write SetNoDelay;
+
+    // Connect timeout
+    property ConnTimeout: Longword read FConnTimeout write FConnTimeout;
+
+    // The max number of recv retries in the case of a WSAEWOULDBLOCK
+    property MaxRecvRetries: Longword read FMaxRecvRetries write FMaxRecvRetries;
+
+    // Socket information formatted as a string <Host: x Port: x>
+    property SocketInfo: string read GetSocketInfo;
+
+    // The DNS name of the host to which the socket is connected
+    property PeerHost: string read GetPeerHost;
+
+    // The address of the host to which the socket is connected
+    property PeerAddress: string read GetPeerAddress;
+
+    // The port of the host to which the socket is connected
+    property PeerPort: Integer read GetPeerPort;
+
+    // The origin the socket is connected to
+    property Origin: string read GetOrigin;
+  end;
+
+  TServerSocketFunc = reference to procedure(sock: Winapi.Winsock2.TSocket);
+
+  TServerSocket = class(TBaseSocket)
+  strict private
+    FAddress: string;
+    FAcceptBacklog,
+    FRetryLimit,
+    FRetryDelay,
+    FTcpSendBuffer,
+    FTcpRecvBuffer: Integer;
+    FAcceptTimeout: Longword;
+    FListening,
+    FInterruptableChildren: Boolean;
+    FInterruptSockWriter,                                               // is notified on Interrupt()
+    FInterruptSockReader,                                               // is used in select with FSocket for interruptability
+    FChildInterruptSockWriter: Winapi.Winsock2.TSocket;                 // is notified on InterruptChildren()
+    FChildInterruptSockReader: ISmartPointer<Winapi.Winsock2.TSocket>;  // if FnterruptableChildren this is shared with child TSockets
+    FListenCallback,
+    FAcceptCallback: TServerSocketFunc;
+    function CreateSocketObj(Client: Winapi.Winsock2.TSocket): TSocket;
+    procedure Notify(NotifySocket: Winapi.Winsock2.TSocket);
+    procedure SetInterruptableChildren(AValue: Boolean);
+  strict protected
+    procedure CommonInit; override;
+  public const
+    DEFAULT_BACKLOG = 1024;
+  public
+    //
+    // Constructor.
+    //
+    // @param port    Port number to bind to
+    //
+    constructor Create(APort: Integer; ALogDelegate: TBaseSocket.TLogDelegate = nil); overload;
+
+    //
+    // Constructor.
+    //
+    // @param port        Port number to bind to
+    // @param sendTimeout Socket send timeout
+    // @param recvTimeout Socket receive timeout
+    //
+    constructor Create(APort: Integer; ASendTimeout, ARecvTimeout: Longword; ALogDelegate: TBaseSocket.TLogDelegate = nil); overload;
+
+    //
+    // Constructor.
+    //
+    // @param address Address to bind to
+    // @param port    Port number to bind to
+    //
+    constructor Create(AAddress: string; APort: Integer; ALogDelegate: TBaseSocket.TLogDelegate = nil); overload;
+
+    procedure Listen;
+    function Accept: TSocket;
+    procedure Interrupt;
+    procedure InterruptChildren;
+    procedure Close; override;
+
+    property AcceptBacklog: Integer read FAcceptBacklog write FAcceptBacklog;
+    property AcceptTimeout: Longword read FAcceptTimeout write FAcceptTimeout;
+    property RetryLimit: Integer read FRetryLimit write FRetryLimit;
+    property RetryDelay: Integer read FRetryDelay write FRetryDelay;
+    property TcpSendBuffer: Integer read FTcpSendBuffer write FTcpSendBuffer;
+    property TcpRecvBuffer: Integer read FTcpRecvBuffer write FTcpRecvBuffer;
+
+    // When enabled (the default), new children TSockets will be constructed so
+    // they can be interrupted by TServerTransport.InterruptChildren().
+    // This is more expensive in terms of system calls (poll + recv) however
+    // ensures a connected client cannot interfere with TServer.Stop().
+    //
+    // When disabled, TSocket children do not incur an additional poll() call.
+    // Server-side reads are more efficient, however a client can interfere with
+    // the server's ability to shutdown properly by staying connected.
+    //
+    // Must be called before listen(); mode cannot be switched after that.
+    // \throws EPropertyError if listen() has been called
+    property InterruptableChildren: Boolean read FInterruptableChildren write SetInterruptableChildren;
+
+    // listenCallback gets called just before listen, and after all Thrift
+    // setsockopt calls have been made.  If you have custom setsockopt
+    // things that need to happen on the listening socket, this is the place to do it.
+    property ListenCallback: TServerSocketFunc read FListenCallback write FListenCallback;
+
+    // acceptCallback gets called after each accept call, on the newly created socket.
+    // It is called after all Thrift setsockopt calls have been made.  If you have
+    // custom setsockopt things that need to happen on the accepted
+    // socket, this is the place to do it.
+    property AcceptCallback: TServerSocketFunc read FAcceptCallback write FAcceptCallback;
+  end;
+
+{$ENDIF} // not for OLD_SOCKETS
+implementation
+{$IFNDEF OLD_SOCKETS} // not for OLD_SOCKETS
+
+uses
+  System.SysUtils, System.Math, System.DateUtils, Thrift.Transport;
+
+constructor TBaseSocket.TGetAddrInfoWrapper.Create(ANode, AService: string; AHints: PAddrInfoW);
+begin
+  inherited Create;
+  FNode := ANode;
+  FService := AService;
+  FHints := AHints;
+  FRes := nil;
+end;
+
+destructor TBaseSocket.TGetAddrInfoWrapper.Destroy;
+begin
+  if Assigned(FRes) then
+    FreeAddrInfoW(FRes);
+  inherited Destroy;
+end;
+
+function TBaseSocket.TGetAddrInfoWrapper.Init: Integer;
+begin
+  if FRes = nil then
+    Exit(GetAddrInfoW(@FNode[1], @FService[1], FHints^, FRes));
+  Result := 0;
+end;
+
+function TBaseSocket.TGetAddrInfoWrapper.GetRes: PAddrInfoW;
+begin
+  Result := FRes;
+end;
+
+procedure DestroyerOfFineSockets(ssock: Winapi.Winsock2.TSocket);
+begin
+  closesocket(ssock);
+end;
+
+function TScopeId.GetBitField(Loc: Integer): Integer;
+begin
+  Result := (Value shr (Loc shr 8)) and ((1 shl (Loc and $FF)) - 1);
+end;
+
+procedure TScopeId.SetBitField(Loc: Integer; const aValue: Integer);
+begin
+  Value := (Value and ULONG((not ((1 shl (Loc and $FF)) - 1)))) or ULONG(aValue shl (Loc shr 8));
+end;
+
+function getaddrinfo; external 'ws2_32.dll' name 'getaddrinfo';
+function GetAddrInfoW; external 'ws2_32.dll' name 'GetAddrInfoW';
+procedure freeaddrinfo; external 'ws2_32.dll' name 'freeaddrinfo';
+procedure FreeAddrInfoW; external 'ws2_32.dll' name 'FreeAddrInfoW';
+function getnameinfo; external 'ws2_32.dll' name 'getnameinfo';
+function GetNameInfoW; external 'ws2_32.dll' name 'GetNameInfoW';
+
+constructor TSmartPointer<T>.Create(AValue: T; ADestroyer: TSmartPointerDestroyer<T>);
+begin
+  inherited Create;
+  FValue := AValue;
+  FDestroyer := ADestroyer;
+end;
+
+destructor TSmartPointer<T>.Destroy;
+begin
+  if Assigned(FDestroyer) then FDestroyer(FValue);
+  inherited Destroy;
+end;
+
+function TSmartPointer<T>.Invoke: T;
+begin
+  Result := FValue;
+end;
+
+class constructor TBaseSocket.Create;
+var
+  Version: WORD;
+  Data: WSAData;
+  Error: Integer;
+begin
+  Version := $0202;
+  FillChar(Data, SizeOf(Data), 0);
+  Error := WSAStartup(Version, Data);
+  if Error <> 0 then
+    raise Exception.Create('Failed to initialize Winsock.');
+end;
+
+class destructor TBaseSocket.Destroy;
+begin
+  WSACleanup;
+end;
+
+class procedure TBaseSocket.DefaultLogDelegate(const Str: string);
+var
+  OutStr: string;
+begin
+  OutStr := Format('Thrift: %s %s', [DateTimeToStr(Now, TFormatSettings.Create), Str]);
+  try
+    Writeln(OutStr);
+    if IoResult <> 0 then OutputDebugString(PChar(OutStr));
+  except
+    OutputDebugString(PChar(OutStr));
+  end;
+end;
+
+procedure TBaseSocket.CommonInit;
+begin
+  FSocket := INVALID_SOCKET;
+  FPort := 0;
+  FSendTimeout := 0;
+  FRecvTimeout := 0;
+  FKeepAlive := False;
+  FLogDelegate := DefaultLogDelegate;
+end;
+
+function TBaseSocket.CreateSocket(AAddress: string; APort: Integer): IGetAddrInfoWrapper;
+var
+  Hints: TAddrInfoW;
+  Res: PAddrInfoW;
+  ThePort: array[0..5] of Char;
+  Error: Integer;
+begin
+  FillChar(Hints, SizeOf(Hints), 0);
+  Hints.ai_family := PF_UNSPEC;
+  Hints.ai_socktype := SOCK_STREAM;
+  Hints.ai_flags := AI_PASSIVE or AI_ADDRCONFIG;
+  StrFmt(ThePort, '%d', [FPort]);
+
+  Result := TGetAddrInfoWrapper.Create(AAddress, ThePort, @Hints);
+  Error := Result.Init;
+  if Error <> 0 then begin
+    LogDelegate(Format('GetAddrInfoW %d: %s', [Error, SysErrorMessage(Error)]));
+    Close;
+    raise TTransportExceptionNotOpen.Create('Could not resolve host for server socket.');
+  end;
+
+  // Pick the ipv6 address first since ipv4 addresses can be mapped
+  // into ipv6 space.
+  Res := Result.Res;
+  while Assigned(Res) do begin
+    if (Res^.ai_family = AF_INET6) or (not Assigned(Res^.ai_next)) then
+      Break;
+    Res := Res^.ai_next;
+  end;
+
+  FSocket := Winapi.Winsock2.socket(Res^.ai_family, Res^.ai_socktype, Res^.ai_protocol);
+  if FSocket = INVALID_SOCKET then begin
+    Error := WSAGetLastError;
+    LogDelegate(Format('TBaseSocket.CreateSocket() socket() %s', [SysErrorMessage(Error)]));
+    Close;
+    raise TTransportExceptionNotOpen.Create(Format('socket(): %s', [SysErrorMessage(Error)]));
+  end;
+end;
+
+procedure TBaseSocket.SetRecvTimeout(ARecvTimeout: Longword);
+begin
+  FRecvTimeout := ARecvTimeout;
+end;
+
+procedure TBaseSocket.SetSendTimeout(ASendTimeout: Longword);
+begin
+  FSendTimeout := ASendTimeout;
+end;
+
+procedure TBaseSocket.SetKeepAlive(AKeepAlive: Boolean);
+begin
+  FKeepAlive := AKeepAlive;
+end;
+
+procedure TBaseSocket.SetSocket(ASocket: Winapi.Winsock2.TSocket);
+begin
+  if FSocket <> INVALID_SOCKET then
+    Close;
+  FSocket := ASocket;
+end;
+
+constructor TBaseSocket.Create(ALogDelegate: TLogDelegate);
+begin
+  inherited Create;
+  CommonInit;
+  if Assigned(ALogDelegate) then FLogDelegate := ALogDelegate;
+end;
+
+constructor TBaseSocket.Create(APort: Integer; ALogDelegate: TLogDelegate);
+begin
+  inherited Create;
+  CommonInit;
+  FPort := APort;
+  if Assigned(ALogDelegate) then FLogDelegate := ALogDelegate;
+end;
+
+destructor TBaseSocket.Destroy;
+begin
+  Close;
+  inherited Destroy;
+end;
+
+procedure TBaseSocket.Close;
+begin
+  if FSocket <> INVALID_SOCKET then begin
+    shutdown(FSocket, SD_BOTH);
+    closesocket(FSocket);
+  end;
+  FSocket := INVALID_SOCKET;
+end;
+
+procedure TSocket.InitPeerInfo;
+begin
+  FCachedPeerAddr.ipv4.sin_family := AF_UNSPEC;
+  FPeerHost := '';
+  FPeerAddress := '';
+  FPeerPort := 0;
+end;
+
+procedure TSocket.CommonInit;
+begin
+  inherited CommonInit;
+  FHost := '';
+  FInterruptListener := nil;
+  FConnTimeout := 0;
+  FLingerOn := True;
+  FLingerVal := 0;
+  FNoDelay := True;
+  FMaxRecvRetries := 5;
+  InitPeerInfo;
+end;
+
+procedure TSocket.OpenConnection(Res: TBaseSocket.IGetAddrInfoWrapper);
+label
+  Done;
+var
+  ErrnoCopy: Integer;
+  Ret,
+  Ret2: Integer;
+  Fds: TFdSet;
+  TVal: TTimeVal;
+  PTVal: PTimeVal;
+  Val,
+  Lon: Integer;
+  One,
+  Zero: Cardinal;
+begin
+  if SendTimeout > 0 then SetSendTimeout(SendTimeout);
+  if RecvTimeout > 0 then SetRecvTimeout(RecvTimeout);
+  if KeepAlive then SetKeepAlive(KeepAlive);
+  SetLinger(FLingerOn, FLingerVal);
+  SetNoDelay(FNoDelay);
+
+  // Set the socket to be non blocking for connect if a timeout exists
+  Zero := 0;
+  if FConnTimeout > 0 then begin
+    One := 1;
+    if ioctlsocket(Socket, Integer(FIONBIO), One) = SOCKET_ERROR then begin
+      ErrnoCopy := WSAGetLastError;
+      LogDelegate(Format('TSocket.OpenConnection() ioctlsocket() %s %s', [SocketInfo, SysErrorMessage(ErrnoCopy)]));
+      raise TTransportExceptionNotOpen.Create(Format('ioctlsocket() failed: %s', [SysErrorMessage(ErrnoCopy)]));
+    end;
+  end
+  else begin
+    if ioctlsocket(Socket, Integer(FIONBIO), Zero) = SOCKET_ERROR then begin
+      ErrnoCopy := WSAGetLastError;
+      LogDelegate(Format('TSocket.OpenConnection() ioctlsocket() %s %s', [SocketInfo, SysErrorMessage(ErrnoCopy)]));
+      raise TTransportExceptionNotOpen.Create(Format('ioctlsocket() failed: %s', [SysErrorMessage(ErrnoCopy)]));
+    end;
+  end;
+
+  Ret := connect(Socket, Res.Res^.ai_addr^, Res.Res^.ai_addrlen);
+  if Ret = 0 then goto Done;
+
+  ErrnoCopy := WSAGetLastError;
+  if (ErrnoCopy <> WSAEINPROGRESS) and (ErrnoCopy <> WSAEWOULDBLOCK) then begin
+    LogDelegate(Format('TSocket.OpenConnection() connect() ', [SocketInfo, SysErrorMessage(ErrnoCopy)]));
+    raise TTransportExceptionNotOpen.Create(Format('connect() failed: %s', [SysErrorMessage(ErrnoCopy)]));
+  end;
+
+  FD_ZERO(Fds);
+  _FD_SET(Socket, Fds);
+  if FConnTimeout > 0 then begin
+    TVal.tv_sec := FConnTimeout div 1000;
+    TVal.tv_usec := (FConnTimeout mod 1000) * 1000;
+    PTVal := @TVal;
+  end
+  else
+    PTVal := nil;
+  Ret := select(1, nil, @Fds, nil, PTVal);
+
+  if Ret > 0 then begin
+    // Ensure the socket is connected and that there are no errors set
+    Lon := SizeOf(Val);
+    Ret2 := getsockopt(Socket, SOL_SOCKET, SO_ERROR, @Val, Lon);
+    if Ret2 = SOCKET_ERROR then begin
+      ErrnoCopy := WSAGetLastError;
+      LogDelegate(Format('TSocket.OpenConnection() getsockopt() ', [SocketInfo, SysErrorMessage(ErrnoCopy)]));
+      raise TTransportExceptionNotOpen.Create(Format('getsockopt(): %s', [SysErrorMessage(ErrnoCopy)]));
+    end;
+    // no errors on socket, go to town
+    if Val = 0 then goto Done;
+    LogDelegate(Format('TSocket.OpenConnection() error on socket (after select()) ', [SocketInfo, SysErrorMessage(ErrnoCopy)]));
+    raise TTransportExceptionNotOpen.Create(Format('socket OpenConnection() error: %s', [SysErrorMessage(Val)]));
+  end
+  else if Ret = 0 then begin
+    // socket timed out
+    LogDelegate(Format('TSocket.OpenConnection() timed out ', [SocketInfo, SysErrorMessage(ErrnoCopy)]));
+    raise TTransportExceptionNotOpen.Create('OpenConnection() timed out');
+  end
+  else begin
+    // error on select()
+    ErrnoCopy := WSAGetLastError;
+    LogDelegate(Format('TSocket.OpenConnection() select() ', [SocketInfo, SysErrorMessage(ErrnoCopy)]));
+    raise TTransportExceptionNotOpen.Create(Format('select() failed: %s', [SysErrorMessage(ErrnoCopy)]));
+  end;
+
+Done:
+  // Set socket back to normal mode (blocking)
+  ioctlsocket(Socket, Integer(FIONBIO), Zero);
+  SetCachedAddress(Res.Res^.ai_addr^, Res.Res^.ai_addrlen);
+end;
+
+procedure TSocket.LocalOpen;
+var
+  Res: TBaseSocket.IGetAddrInfoWrapper;
+begin
+  if IsOpen then Exit;
+
+  // Validate port number
+  if (Port < 0) or (Port > $FFFF) then
+    raise TTransportExceptionBadArgs.Create('Specified port is invalid');
+
+  Res := CreateSocket(Host, Port);
+
+  OpenConnection(Res);
+end;
+
+procedure TSocket.SetGenericTimeout(S: Winapi.Winsock2.TSocket; Timeout: Longword; OptName: Integer);
+var
+  Time: DWORD;
+begin
+  if S = INVALID_SOCKET then
+    Exit;
+
+  Time := Timeout;
+
+  if setsockopt(S, SOL_SOCKET, OptName, @Time, SizeOf(Time)) = SOCKET_ERROR then
+    LogDelegate(Format('SetGenericTimeout() setsockopt() %s', [SysErrorMessage(WSAGetLastError)]));
+end;
+
+function TSocket.GetIsOpen: Boolean;
+begin
+  Result := Socket <> INVALID_SOCKET;
+end;
+
+procedure TSocket.SetNoDelay(ANoDelay: Boolean);
+var
+  V: Integer;
+begin
+  FNoDelay := ANoDelay;
+  if Socket = INVALID_SOCKET then
+    Exit;
+
+  V := IfThen(FNoDelay, 1, 0);
+  if setsockopt(Socket, IPPROTO_TCP, TCP_NODELAY, @V, SizeOf(V)) = SOCKET_ERROR then
+    LogDelegate(Format('TSocket.SetNoDelay() setsockopt() %s %s', [SocketInfo, SysErrorMessage(WSAGetLastError)]));
+end;
+
+function TSocket.GetSocketInfo: string;
+begin
+  if (FHost = '') or (Port = 0) then
+    Result := '<Host: ' + GetPeerAddress + ' Port: ' + GetPeerPort.ToString + '>'
+  else
+    Result := '<Host: ' + FHost + ' Port: ' + Port.ToString + '>';
+end;
+
+function TSocket.GetPeerHost: string;
+var
+  Addr: TSockAddrStorage;
+  AddrPtr: PSockAddr;
+  AddrLen: Integer;
+  ClientHost: array[0..NI_MAXHOST-1] of Char;
+  ClientService: array[0..NI_MAXSERV-1] of Char;
+begin
+  if FPeerHost = '' then begin
+    if Socket = INVALID_SOCKET then
+      Exit(FPeerHost);
+
+    AddrPtr := GetCachedAddress(AddrLen);
+    if AddrPtr = nil then begin
+      AddrLen := SizeOf(Addr);
+      if getpeername(Socket, PSockAddr(@Addr)^, AddrLen) <> 0 then
+        Exit(FPeerHost);
+      AddrPtr := PSockAddr(@Addr);
+      SetCachedAddress(AddrPtr^, AddrLen);
+    end;
+
+    GetNameInfoW(AddrPtr^, AddrLen, ClientHost, NI_MAXHOST, ClientService, NI_MAXSERV, 0);
+    FPeerHost := ClientHost;
+  end;
+  Result := FPeerHost;
+end;
+
+function TSocket.GetPeerAddress: string;
+var
+  Addr: TSockAddrStorage;
+  AddrPtr: PSockAddr;
+  AddrLen: Integer;
+  ClientHost: array[0..NI_MAXHOST-1] of Char;
+  ClientService: array[0..NI_MAXSERV-1] of Char;
+begin
+  if FPeerAddress = '' then begin
+    if Socket = INVALID_SOCKET then
+      Exit(FPeerAddress);
+
+    AddrPtr := GetCachedAddress(AddrLen);
+    if AddrPtr = nil then begin
+      AddrLen := SizeOf(Addr);
+      if getpeername(Socket, PSockAddr(@Addr)^, AddrLen) <> 0 then
+        Exit(FPeerHost);
+      AddrPtr := PSockAddr(@Addr);
+      SetCachedAddress(AddrPtr^, AddrLen);
+    end;
+
+    GetNameInfoW(AddrPtr^, AddrLen, ClientHost, NI_MAXHOST, ClientService, NI_MAXSERV, NI_NUMERICHOST or NI_NUMERICSERV);
+    FPeerAddress := ClientHost;
+    TryStrToInt(ClientService, FPeerPort);
+  end;
+  Result := FPeerAddress
+end;
+
+function TSocket.GetPeerPort: Integer;
+begin
+  GetPeerAddress;
+  Result := FPeerPort;
+end;
+
+function TSocket.GetOrigin: string;
+begin
+  Result := GetPeerHost + ':' + GetPeerPort.ToString;
+end;
+
+procedure TSocket.SetRecvTimeout(ARecvTimeout: Longword);
+begin
+  inherited SetRecvTimeout(ARecvTimeout);
+  SetGenericTimeout(Socket, ARecvTimeout, SO_RCVTIMEO);
+end;
+
+procedure TSocket.SetSendTimeout(ASendTimeout: Longword);
+begin
+  inherited SetSendTimeout(ASendTimeout);
+  SetGenericTimeout(Socket, ASendTimeout, SO_SNDTIMEO);
+end;
+
+procedure TSocket.SetKeepAlive(AKeepAlive: Boolean);
+var
+  Value: Integer;
+begin
+  inherited SetKeepAlive(AKeepAlive);
+
+  Value := IfThen(KeepAlive, 1, 0);
+  if setsockopt(Socket, SOL_SOCKET, SO_KEEPALIVE, @Value, SizeOf(Value)) = SOCKET_ERROR then
+    LogDelegate(Format('TSocket.SetKeepAlive() setsockopt() %s %s', [SocketInfo, SysErrorMessage(WSAGetLastError)]));
+end;
+
+constructor TSocket.Create(ALogDelegate: TBaseSocket.TLogDelegate = nil);
+begin
+  // Not needed, but just a placeholder
+  inherited Create(ALogDelegate);
+end;
+
+constructor TSocket.Create(AHost: string; APort: Integer; ALogDelegate: TBaseSocket.TLogDelegate);
+begin
+  inherited Create(APort, ALogDelegate);
+  FHost := AHost;
+end;
+
+constructor TSocket.Create(ASocket: Winapi.Winsock2.TSocket; ALogDelegate: TBaseSocket.TLogDelegate);
+begin
+  inherited Create(ALogDelegate);
+  Socket := ASocket;
+end;
+
+constructor TSocket.Create(ASocket: Winapi.Winsock2.TSocket; AInterruptListener: ISmartPointer<Winapi.Winsock2.TSocket>;
+  ALogDelegate: TBaseSocket.TLogDelegate);
+begin
+  inherited Create(ALogDelegate);
+  Socket := ASocket;
+  FInterruptListener := AInterruptListener;
+end;
+
+procedure TSocket.Open;
+begin
+  if IsOpen then Exit;
+  LocalOpen;
+end;
+
+procedure TSocket.Close;
+begin
+  inherited Close;
+  InitPeerInfo;
+end;
+
+function TSocket.Read(var Buf; Len: Integer): Integer;
+label
+  TryAgain;
+var
+  Retries: Longword;
+  EAgainThreshold,
+  ReadElapsed: UInt64;
+  Start: TDateTime;
+  Got: Integer;
+  Fds: TFdSet;
+  ErrnoCopy: Integer;
+  TVal: TTimeVal;
+  PTVal: PTimeVal;
+  Ret: Integer;
+begin
+  if Socket = INVALID_SOCKET then
+    raise TTransportExceptionNotOpen.Create('Called read on non-open socket');
+
+  Retries := 0;
+
+  // THRIFT_EAGAIN can be signalled both when a timeout has occurred and when
+  // the system is out of resources (an awesome undocumented feature).
+  // The following is an approximation of the time interval under which
+  // THRIFT_EAGAIN is taken to indicate an out of resources error.
+  EAgainThreshold := 0;
+  if RecvTimeout <> 0 then
+    // if a readTimeout is specified along with a max number of recv retries, then
+    // the threshold will ensure that the read timeout is not exceeded even in the
+    // case of resource errors
+    EAgainThreshold := RecvTimeout div IfThen(FMaxRecvRetries > 0, FMaxRecvRetries, 2);
+
+TryAgain:
+  // Read from the socket
+  if RecvTimeout > 0 then
+    Start := Now
+  else
+    // if there is no read timeout we don't need the TOD to determine whether
+    // an THRIFT_EAGAIN is due to a timeout or an out-of-resource condition.
+    Start := 0;
+
+  if Assigned(FInterruptListener) then begin
+    FD_ZERO(Fds);
+    _FD_SET(Socket, Fds);
+    _FD_SET(FInterruptListener, Fds);
+    if RecvTimeout > 0 then begin
+      TVal.tv_sec := RecvTimeout div 1000;
+      TVal.tv_usec := (RecvTimeout mod 1000) * 1000;
+      PTVal := @TVal;
+    end
+    else
+      PTVal := nil;
+
+    Ret := select(2, @Fds, nil, nil, PTVal);
+    ErrnoCopy := WSAGetLastError;
+    if Ret < 0 then begin
+      // error cases
+      if (ErrnoCopy = WSAEINTR) and (Retries < FMaxRecvRetries) then begin
+        Inc(Retries);
+        goto TryAgain;
+      end;
+      LogDelegate(Format('TSocket.Read() select() %s', [SysErrorMessage(ErrnoCopy)]));
+      raise TTransportExceptionUnknown.Create(Format('Unknown: %s', [SysErrorMessage(ErrnoCopy)]));
+    end
+    else if Ret > 0 then begin
+      // Check the interruptListener
+      if FD_ISSET(FInterruptListener, Fds) then
+        raise TTransportExceptionInterrupted.Create('Interrupted');
+    end
+    else // Ret = 0
+      raise TTransportExceptionTimedOut.Create('WSAEWOULDBLOCK (timed out)');
+
+    // falling through means there is something to recv and it cannot block
+  end;
+
+  Got := recv(Socket, Buf, Len, 0);
+  ErrnoCopy := WSAGetLastError;
+  // Check for error on read
+  if Got < 0 then begin
+    if ErrnoCopy = WSAEWOULDBLOCK then begin
+      // if no timeout we can assume that resource exhaustion has occurred.
+      if RecvTimeout = 0 then
+        raise TTransportExceptionTimedOut.Create('WSAEWOULDBLOCK (unavailable resources)');
+      // check if this is the lack of resources or timeout case
+      ReadElapsed := MilliSecondsBetween(Now, Start);
+      if (EAgainThreshold = 0) or (ReadElapsed < EAgainThreshold) then begin
+        if Retries < FMaxRecvRetries then begin
+          Inc(Retries);
+          Sleep(1);
+          goto TryAgain;
+        end
+        else
+          raise TTransportExceptionTimedOut.Create('WSAEWOULDBLOCK (unavailable resources)');
+      end
+      else
+        // infer that timeout has been hit
+        raise TTransportExceptionTimedOut.Create('WSAEWOULDBLOCK (timed out)');
+    end;
+
+    // If interrupted, try again
+    if (ErrnoCopy = WSAEINTR) and (Retries < FMaxRecvRetries) then begin
+      Inc(Retries);
+      goto TryAgain;
+    end;
+
+    if ErrnoCopy = WSAECONNRESET then
+      Exit(0);
+
+    // This ish isn't open
+    if ErrnoCopy = WSAENOTCONN then
+      raise TTransportExceptionNotOpen.Create('WSAENOTCONN');
+
+    // Timed out!
+    if ErrnoCopy = WSAETIMEDOUT then
+      raise TTransportExceptionNotOpen.Create('WSAETIMEDOUT');
+
+    // Now it's not a try again case, but a real probblez
+    LogDelegate(Format('TSocket.Read() recv() %s %s', [SocketInfo, SysErrorMessage(ErrnoCopy)]));
+
+    // Some other error, whatevz
+    raise TTransportExceptionUnknown.Create(Format('Unknown: %s', [SysErrorMessage(ErrnoCopy)]));
+  end;
+
+  Result := Got;
+end;
+
+procedure TSocket.Write(const Buf; Len: Integer);
+var
+  Sent, B: Integer;
+begin
+  Sent := 0;
+  while Sent < Len do begin
+    B := WritePartial((PByte(@Buf) + Sent)^, Len - Sent);
+    if B = 0 then
+      // This should only happen if the timeout set with SO_SNDTIMEO expired.
+      // Raise an exception.
+      raise TTransportExceptionTimedOut.Create('send timeout expired');
+    Inc(Sent, B);
+  end;
+end;
+
+function TSocket.WritePartial(const Buf; Len: Integer): Integer;
+var
+  B: Integer;
+  ErrnoCopy: Integer;
+begin
+  if Socket = INVALID_SOCKET then
+    raise TTransportExceptionNotOpen.Create('Called write on non-open socket');
+
+  B := send(Socket, Buf, Len, 0);
+
+  if B < 0 then begin
+    // Fail on a send error
+    ErrnoCopy := WSAGetLastError;
+    if ErrnoCopy = WSAEWOULDBLOCK then
+      Exit(0);
+
+    LogDelegate(Format('TSocket.WritePartial() send() %s %s', [SocketInfo, SysErrorMessage(ErrnoCopy)]));
+
+    if (ErrnoCopy = WSAECONNRESET) or (ErrnoCopy = WSAENOTCONN) then begin
+      Close;
+      raise TTransportExceptionNotOpen.Create(Format('write() send(): %s', [SysErrorMessage(ErrnoCopy)]));
+    end;
+
+    raise TTransportExceptionUnknown.Create(Format('write() send(): %s', [SysErrorMessage(ErrnoCopy)]));
+  end;
+
+  // Fail on blocked send
+  if B = 0 then
+    raise TTransportExceptionNotOpen.Create('Socket send returned 0.');
+
+  Result := B;
+end;
+
+function TSocket.GetCachedAddress(out Len: Integer): PSockAddr;
+begin
+  case FCachedPeerAddr.ipv4.sin_family of
+    AF_INET: begin
+      Len := SizeOf(TSockAddrIn);
+      Result := PSockAddr(@FCachedPeerAddr.ipv4);
+    end;
+    AF_INET6: begin
+      Len := SizeOf(TSockAddrIn6);
+      Result := PSockAddr(@FCachedPeerAddr.ipv6);
+    end;
+  else
+    Len := 0;
+    Result := nil;
+  end;
+end;
+
+procedure TSocket.SetCachedAddress(const Addr: TSockAddr; Len: Integer);
+begin
+  case Addr.sa_family of
+    AF_INET: if Len = SizeOf(TSockAddrIn) then FCachedPeerAddr.ipv4 := PSockAddrIn(@Addr)^;
+    AF_INET6: if Len = SizeOf(TSockAddrIn6) then FCachedPeerAddr.ipv6 := PSockAddrIn6(@Addr)^;
+  end;
+  FPeerAddress := '';
+  FPeerHost := '';
+  FPeerPort := 0;
+end;
+
+procedure TSocket.SetLinger(LingerOn: Boolean; LingerVal: Integer);
+var
+  L: TLinger;
+begin
+  FLingerOn := LingerOn;
+  FLingerVal := LingerVal;
+  if Socket = INVALID_SOCKET then
+    Exit;
+
+  L.l_onoff := IfThen(FLingerOn, 1, 0);
+  L.l_linger := LingerVal;
+
+  if setsockopt(Socket, SOL_SOCKET, SO_LINGER, @L, SizeOf(L)) = SOCKET_ERROR then
+    LogDelegate(Format('TSocket.SetLinger() setsockopt() %s %s', [SocketInfo, SysErrorMessage(WSAGetLastError)]));
+end;
+
+function TSocket.Peek: Boolean;
+var
+  Retries: Longword;
+  Fds: TFdSet;
+  TVal: TTimeVal;
+  PTVal: PTimeVal;
+  Ret: Integer;
+  ErrnoCopy: Integer;
+  Buf: Byte;
+begin
+  if not IsOpen then Exit(False);
+
+  if Assigned(FInterruptListener) then begin
+    Retries := 0;
+    while true do begin
+      FD_ZERO(Fds);
+      _FD_SET(Socket, Fds);
+      _FD_SET(FInterruptListener, Fds);
+      if RecvTimeout > 0 then begin
+        TVal.tv_sec := RecvTimeout div 1000;
+        TVal.tv_usec := (RecvTimeout mod 1000) * 1000;
+        PTVal := @TVal;
+      end
+      else
+        PTVal := nil;
+
+      Ret := select(2, @Fds, nil, nil, PTVal);
+      ErrnoCopy := WSAGetLastError;
+      if Ret < 0 then begin
+        // error cases
+        if (ErrnoCopy = WSAEINTR) and (Retries < FMaxRecvRetries) then begin
+          Inc(Retries);
+          Continue;
+        end;
+        LogDelegate(Format('TSocket.Peek() select() %s', [SysErrorMessage(ErrnoCopy)]));
+        raise TTransportExceptionUnknown.Create(Format('Unknown: %s', [SysErrorMessage(ErrnoCopy)]));
+      end
+      else if Ret > 0 then begin
+        // Check the interruptListener
+        if FD_ISSET(FInterruptListener, Fds) then
+          Exit(False);
+        // There must be data or a disconnection, fall through to the PEEK
+        Break;
+      end
+      else
+        // timeout
+        Exit(False);
+    end;
+  end;
+
+  // Check to see if data is available or if the remote side closed
+  Ret := recv(Socket, Buf, 1, MSG_PEEK);
+  if Ret = SOCKET_ERROR then begin
+    ErrnoCopy := WSAGetLastError;
+    if ErrnoCopy = WSAECONNRESET then begin
+      Close;
+      Exit(False);
+    end;
+    LogDelegate(Format('TSocket.Peek() recv() %s %s', [SocketInfo, SysErrorMessage(ErrnoCopy)]));
+    raise TTransportExceptionUnknown.Create(Format('recv(): %s', [SysErrorMessage(ErrnoCopy)]));
+  end;
+  Result := Ret > 0;
+end;
+
+function TServerSocket.CreateSocketObj(Client: Winapi.Winsock2.TSocket): TSocket;
+begin
+  if FInterruptableChildren then
+    Result := TSocket.Create(Client, FChildInterruptSockReader)
+  else
+    Result := TSocket.Create(Client);
+end;
+
+procedure TServerSocket.Notify(NotifySocket: Winapi.Winsock2.TSocket);
+var
+  Byt: Byte;
+begin
+  if NotifySocket <> INVALID_SOCKET then begin
+    Byt := 0;
+    if send(NotifySocket, Byt, SizeOf(Byt), 0) = SOCKET_ERROR then
+      LogDelegate(Format('TServerSocket.Notify() send() %s', [SysErrorMessage(WSAGetLastError)]));
+  end;
+end;
+
+procedure TServerSocket.SetInterruptableChildren(AValue: Boolean);
+begin
+  if FListening then
+    raise Exception.Create('InterruptableChildren cannot be set after listen()');
+  FInterruptableChildren := AValue;
+end;
+
+procedure TServerSocket.CommonInit;
+begin
+  inherited CommonInit;
+  FInterruptableChildren := True;
+  FAcceptBacklog := DEFAULT_BACKLOG;
+  FAcceptTimeout := 0;
+  FRetryLimit := 0;
+  FRetryDelay := 0;
+  FTcpSendBuffer := 0;
+  FTcpRecvBuffer := 0;
+  FListening := False;
+  FInterruptSockWriter := INVALID_SOCKET;
+  FInterruptSockReader := INVALID_SOCKET;
+  FChildInterruptSockWriter := INVALID_SOCKET;
+end;
+
+constructor TServerSocket.Create(APort: Integer; ALogDelegate: TBaseSocket.TLogDelegate = nil);
+begin
+  // Unnecessary, but here for documentation purposes
+  inherited Create(APort, ALogDelegate);
+end;
+
+constructor TServerSocket.Create(APort: Integer; ASendTimeout, ARecvTimeout: Longword; ALogDelegate: TBaseSocket.TLogDelegate);
+begin
+  inherited Create(APort, ALogDelegate);
+  SendTimeout := ASendTimeout;
+  RecvTimeout := ARecvTimeout;
+end;
+
+constructor TServerSocket.Create(AAddress: string; APort: Integer; ALogDelegate: TBaseSocket.TLogDelegate);
+begin
+  inherited Create(APort, ALogDelegate);
+  FAddress := AAddress;
+end;
+
+procedure TServerSocket.Listen;
+
+  function CreateSocketPair(var Reader, Writer: Winapi.Winsock2.TSocket): Integer;
+  label
+    Error;
+  type
+    TSAUnion = record
+    case Integer of
+      0: (inaddr: TSockAddrIn);
+      1: (addr: TSockAddr);
+    end;
+  var
+    a: TSAUnion;
+    listener: Winapi.Winsock2.TSocket;
+    e: Integer;
+    addrlen: Integer;
+    flags: DWORD;
+    reuse: Integer;
+  begin
+    addrlen := SizeOf(a.inaddr);
+    flags := 0;
+    reuse := 1;
+
+    listener := Winapi.Winsock2.socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if listener = INVALID_SOCKET then
+      Exit(SOCKET_ERROR);
+
+    FillChar(a, SizeOf(a), 0);
+    a.inaddr.sin_family := AF_INET;
+    a.inaddr.sin_addr.s_addr := htonl(INADDR_LOOPBACK);
+    a.inaddr.sin_port := 0;
+    Reader := INVALID_SOCKET;
+    Writer := INVALID_SOCKET;
+
+    // ignore errors coming out of this setsockopt.  This is because
+    // SO_EXCLUSIVEADDRUSE requires admin privileges on WinXP, but we don't
+    // want to force socket pairs to be an admin.
+    setsockopt(listener, SOL_SOCKET, Integer(SO_EXCLUSIVEADDRUSE), @reuse, SizeOf(reuse));
+    if bind(listener, a.addr, SizeOf(a.inaddr)) = SOCKET_ERROR then
+      goto Error;
+
+    if getsockname(listener, a.addr, addrlen) = SOCKET_ERROR then
+      goto Error;
+
+    if Winapi.Winsock2.listen(listener, 1) = SOCKET_ERROR then
+      goto Error;
+
+    Reader := WSASocket(AF_INET, SOCK_STREAM, 0, nil, 0, flags);
+    if Reader = INVALID_SOCKET then
+      goto Error;
+
+    if connect(Reader, a.addr, SizeOf(a.inaddr)) = SOCKET_ERROR then
+      goto Error;
+
+    Writer := Winapi.Winsock2.accept(listener, nil, nil);
+    if Writer = INVALID_SOCKET then
+      goto Error;
+
+    closesocket(listener);
+    Exit(0);
+
+  Error:
+    e := WSAGetLastError;
+    closesocket(listener);
+    closesocket(Reader);
+    closesocket(Writer);
+    WSASetLastError(e);
+    Result := SOCKET_ERROR;
+  end;
+
+var
+  TempIntReader,
+  TempIntWriter: Winapi.Winsock2.TSocket;
+  One: Cardinal;
+  ErrnoCopy: Integer;
+  Ling: TLinger;
+  Retries: Integer;
+  AddrInfo: IGetAddrInfoWrapper;
+  SA: TSockAddrStorage;
+  Len: Integer;
+begin
+  // Create the socket pair used to interrupt
+  if CreateSocketPair(TempIntReader, TempIntWriter) = SOCKET_ERROR then begin
+    LogDelegate(Format('TServerSocket.Listen() CreateSocketPair() Interrupt %s', [SysErrorMessage(WSAGetLastError)]));
+    FInterruptSockReader := INVALID_SOCKET;
+    FInterruptSockWriter := INVALID_SOCKET;
+  end
+  else begin
+    FInterruptSockReader := TempIntReader;
+    FInterruptSockWriter := TempIntWriter;
+  end;
+
+  // Create the socket pair used to interrupt all clients
+  if CreateSocketPair(TempIntReader, TempIntWriter) = SOCKET_ERROR then begin
+    LogDelegate(Format('TServerSocket.Listen() CreateSocketPair() ChildInterrupt %s', [SysErrorMessage(WSAGetLastError)]));
+    FChildInterruptSockReader := TSmartPointer<Winapi.Winsock2.TSocket>.Create(INVALID_SOCKET, nil);
+    FChildInterruptSockWriter := INVALID_SOCKET;
+  end
+  else begin
+    FChildInterruptSockReader := TSmartPointer<Winapi.Winsock2.TSocket>.Create(TempIntReader, DestroyerOfFineSockets);
+    FChildInterruptSockWriter := TempIntWriter;
+  end;
+
+  if (Port < 0) or (Port > $FFFF) then
+    raise TTransportExceptionBadArgs.Create('Specified port is invalid');
+
+  AddrInfo := CreateSocket(FAddress, Port);
+
+  // Set SO_EXCLUSIVEADDRUSE to prevent 2MSL delay on accept
+  One := 1;
+  setsockopt(Socket, SOL_SOCKET, Integer(SO_EXCLUSIVEADDRUSE), @one, SizeOf(One));
+  // ignore errors coming out of this setsockopt on Windows.  This is because
+  // SO_EXCLUSIVEADDRUSE requires admin privileges on WinXP, but we don't
+  // want to force servers to be an admin.
+
+  // Set TCP buffer sizes
+  if FTcpSendBuffer > 0 then begin
+    if setsockopt(Socket, SOL_SOCKET, SO_SNDBUF, @FTcpSendBuffer, SizeOf(FTcpSendBuffer)) = SOCKET_ERROR then begin
+      ErrnoCopy := WSAGetLastError;
+      LogDelegate(Format('TServerSocket.Listen() setsockopt() SO_SNDBUF %s', [SysErrorMessage(ErrnoCopy)]));
+      raise TTransportExceptionNotOpen.Create(Format('Could not set SO_SNDBUF: %s', [SysErrorMessage(ErrnoCopy)]));
+    end;
+  end;
+
+  if FTcpRecvBuffer > 0 then begin
+    if setsockopt(Socket, SOL_SOCKET, SO_RCVBUF, @FTcpRecvBuffer, SizeOf(FTcpRecvBuffer)) = SOCKET_ERROR then begin
+      ErrnoCopy := WSAGetLastError;
+      LogDelegate(Format('TServerSocket.Listen() setsockopt() SO_RCVBUF %s', [SysErrorMessage(ErrnoCopy)]));
+      raise TTransportExceptionNotOpen.Create(Format('Could not set SO_RCVBUF: %s', [SysErrorMessage(ErrnoCopy)]));
+    end;
+  end;
+
+  // Turn linger off, don't want to block on calls to close
+  Ling.l_onoff := 0;
+  Ling.l_linger := 0;
+  if setsockopt(Socket, SOL_SOCKET, SO_LINGER, @Ling, SizeOf(Ling)) = SOCKET_ERROR then begin
+    ErrnoCopy := WSAGetLastError;
+    LogDelegate(Format('TServerSocket.Listen() setsockopt() SO_LINGER %s', [SysErrorMessage(ErrnoCopy)]));
+    raise TTransportExceptionNotOpen.Create(Format('Could not set SO_LINGER: %s', [SysErrorMessage(ErrnoCopy)]));
+  end;
+
+  // TCP Nodelay, speed over bandwidth
+  if setsockopt(Socket, IPPROTO_TCP, TCP_NODELAY, @One, SizeOf(One)) = SOCKET_ERROR then begin
+    ErrnoCopy := WSAGetLastError;
+    LogDelegate(Format('TServerSocket.Listen() setsockopt() TCP_NODELAY %s', [SysErrorMessage(ErrnoCopy)]));
+    raise TTransportExceptionNotOpen.Create(Format('Could not set TCP_NODELAY: %s', [SysErrorMessage(ErrnoCopy)]));
+  end;
+
+  // Set NONBLOCK on the accept socket
+  if ioctlsocket(Socket, Integer(FIONBIO), One) = SOCKET_ERROR then begin
+    ErrnoCopy := WSAGetLastError;
+    LogDelegate(Format('TServerSocket.Listen() ioctlsocket() FIONBIO %s', [SysErrorMessage(ErrnoCopy)]));
+    raise TTransportExceptionNotOpen.Create(Format('ioctlsocket() FIONBIO: %s', [SysErrorMessage(ErrnoCopy)]));
+  end;
+
+  // prepare the port information
+  // we may want to try to bind more than once, since THRIFT_NO_SOCKET_CACHING doesn't
+  // always seem to work. The client can configure the retry variables.
+  Retries := 0;
+  while True do begin
+    if bind(Socket, AddrInfo.Res^.ai_addr^, AddrInfo.Res^.ai_addrlen) = 0 then
+      Break;
+    Inc(Retries);
+    if Retries > FRetryLimit then
+      Break;
+    Sleep(FRetryDelay * 1000);
+  end;
+
+  // retrieve bind info
+  if (Port = 0) and (Retries < FRetryLimit) then begin
+    Len := SizeOf(SA);
+    FillChar(SA, Len, 0);
+    if getsockname(Socket, PSockAddr(@SA)^, Len) = SOCKET_ERROR then
+      LogDelegate(Format('TServerSocket.Listen() getsockname() %s', [SysErrorMessage(WSAGetLastError)]))
+    else begin
+      if SA.ss_family = AF_INET6 then
+        Port := ntohs(PSockAddrIn6(@SA)^.sin6_port)
+      else
+        Port := ntohs(PSockAddrIn(@SA)^.sin_port);
+    end;
+  end;
+
+  // throw an error if we failed to bind properly
+  if (Retries > FRetryLimit) then begin
+    LogDelegate(Format('TServerSocket.Listen() BIND %d', [Port]));
+    Close;
+    raise TTransportExceptionNotOpen.Create(Format('Could not bind: %s', [SysErrorMessage(WSAGetLastError)]));
+  end;
+
+  if Assigned(FListenCallback) then
+    FListenCallback(Socket);
+
+  // Call listen
+  if Winapi.Winsock2.listen(Socket, FAcceptBacklog) = SOCKET_ERROR then begin
+    ErrnoCopy := WSAGetLastError;
+    LogDelegate(Format('TServerSocket.Listen() listen() %s', [SysErrorMessage(ErrnoCopy)]));
+    raise TTransportExceptionNotOpen.Create(Format('Could not listen: %s', [SysErrorMessage(ErrnoCopy)]));
+  end;
+
+  // The socket is now listening!
+end;
+
+function TServerSocket.Accept: TSocket;
+var
+  Fds: TFdSet;
+  MaxEInters,
+  NumEInters: Integer;
+  TVal: TTimeVal;
+  PTVal: PTimeVal;
+  ErrnoCopy: Integer;
+  Buf: Byte;
+  ClientAddress: TSockAddrStorage;
+  Size: Integer;
+  ClientSocket: Winapi.Winsock2.TSocket;
+  Zero: Cardinal;
+  Client: TSocket;
+  Ret: Integer;
+begin
+  MaxEInters := 5;
+  NumEInters := 0;
+
+  while True do begin
+    FD_ZERO(Fds);
+    _FD_SET(Socket, Fds);
+    _FD_SET(FInterruptSockReader, Fds);
+    if FAcceptTimeout > 0 then begin
+      TVal.tv_sec := FAcceptTimeout div 1000;
+      TVal.tv_usec := (FAcceptTimeout mod 1000) * 1000;
+      PTVal := @TVal;
+    end
+    else
+      PTVal := nil;
+
+    // TODO: if WSAEINTR is received, we'll restart the timeout.
+    // To be accurate, we need to fix this in the future.
+    Ret := select(2, @Fds, nil, nil, PTVal);
+
+    if Ret < 0 then begin
+      // error cases
+      if (WSAGetLastError = WSAEINTR) and (NumEInters < MaxEInters) then begin
+        // THRIFT_EINTR needs to be handled manually and we can tolerate
+        // a certain number
+        Inc(NumEInters);
+        Continue;
+      end;
+      ErrnoCopy := WSAGetLastError;
+      LogDelegate(Format('TServerSocket.Accept() select() %s', [SysErrorMessage(ErrnoCopy)]));
+      raise TTransportExceptionUnknown.Create(Format('Unknown: %s', [SysErrorMessage(ErrnoCopy)]));
+    end
+    else if Ret > 0 then begin
+      // Check for an interrupt signal
+      if (FInterruptSockReader <> INVALID_SOCKET) and FD_ISSET(FInterruptSockReader, Fds) then begin
+        if recv(FInterruptSockReader, Buf, SizeOf(Buf), 0) = SOCKET_ERROR then
+          LogDelegate(Format('TServerSocket.Accept() recv() interrupt %s', [SysErrorMessage(WSAGetLastError)]));
+        raise TTransportExceptionInterrupted.Create('interrupted');
+      end;
+
+      // Check for the actual server socket being ready
+      if FD_ISSET(Socket, Fds) then
+        Break;
+    end
+    else begin
+      LogDelegate('TServerSocket.Accept() select() 0');
+      raise TTransportExceptionUnknown.Create('unknown error');
+    end;
+  end;
+
+  Size := SizeOf(ClientAddress);
+  ClientSocket := Winapi.Winsock2.accept(Socket, @ClientAddress, @Size);
+  if ClientSocket = INVALID_SOCKET then begin
+    ErrnoCopy := WSAGetLastError;
+    LogDelegate(Format('TServerSocket.Accept() accept() %s', [SysErrorMessage(ErrnoCopy)]));
+    raise TTransportExceptionUnknown.Create(Format('accept(): %s', [SysErrorMessage(ErrnoCopy)]));
+  end;
+
+  // Make sure client socket is blocking
+  Zero := 0;
+  if ioctlsocket(ClientSocket, Integer(FIONBIO), Zero) = SOCKET_ERROR then begin
+    ErrnoCopy := WSAGetLastError;
+    closesocket(ClientSocket);
+    LogDelegate(Format('TServerSocket.Accept() ioctlsocket() FIONBIO %s', [SysErrorMessage(ErrnoCopy)]));
+    raise TTransportExceptionUnknown.Create(Format('ioctlsocket(): %s', [SysErrorMessage(ErrnoCopy)]));
+  end;
+
+  Client := CreateSocketObj(ClientSocket);
+  if SendTimeout > 0 then
+    Client.SendTimeout := SendTimeout;
+  if RecvTimeout > 0 then
+    Client.RecvTimeout := RecvTimeout;
+  if KeepAlive then
+    Client.KeepAlive := KeepAlive;
+  Client.SetCachedAddress(PSockAddr(@ClientAddress)^, Size);
+
+  if Assigned(FAcceptCallback) then
+    FAcceptCallback(ClientSocket);
+
+  Result := Client;
+end;
+
+procedure TServerSocket.Interrupt;
+begin
+  Notify(FInterruptSockWriter);
+end;
+
+procedure TServerSocket.InterruptChildren;
+begin
+  Notify(FChildInterruptSockWriter);
+end;
+
+procedure TServerSocket.Close;
+begin
+  inherited Close;
+  if FInterruptSockWriter <> INVALID_SOCKET then
+    closesocket(FInterruptSockWriter);
+  if FInterruptSockReader <> INVALID_SOCKET then
+    closesocket(FInterruptSockReader);
+  if FChildInterruptSockWriter <> INVALID_SOCKET then
+    closesocket(FChildInterruptSockWriter);
+  FChildInterruptSockReader := TSmartPointer<Winapi.Winsock2.TSocket>.Create(INVALID_SOCKET, nil);
+  FListening := False;
+end;
+
+{$ENDIF} // not for OLD_SOCKETS
+end.
diff --git a/lib/delphi/src/Thrift.Stream.pas b/lib/delphi/src/Thrift.Stream.pas
index 81d5d2a..3308c53 100644
--- a/lib/delphi/src/Thrift.Stream.pas
+++ b/lib/delphi/src/Thrift.Stream.pas
@@ -1,298 +1,319 @@
-(*

- * 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.

- *)

-

-unit Thrift.Stream;

-

-interface

-

-uses

-  Classes,

-  SysUtils,

-  SysConst,

-  RTLConsts,

-  Thrift.Utils,

-  ActiveX;

-

-type

-

-  IThriftStream = interface

-    ['{732621B3-F697-4D76-A1B0-B4DD5A8E4018}']

-    procedure Write( const buffer: TBytes; offset: Integer; count: Integer);

-    function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer;

-    procedure Open;

-    procedure Close;

-    procedure Flush;

-    function IsOpen: Boolean;

-    function ToArray: TBytes;

-  end;

-

-  TThriftStreamImpl = class( TInterfacedObject, IThriftStream)

-  private

-    procedure CheckSizeAndOffset( const buffer: TBytes; offset: Integer; count: Integer);

-  protected

-    procedure Write( const buffer: TBytes; offset: Integer; count: Integer); virtual;

-    function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; virtual;

-    procedure Open; virtual; abstract;

-    procedure Close; virtual; abstract;

-    procedure Flush; virtual; abstract;

-    function IsOpen: Boolean; virtual; abstract;

-    function ToArray: TBytes; virtual; abstract;

-  end;

-

-  TThriftStreamAdapterDelphi = class( TThriftStreamImpl )

-  private

-    FStream : TStream;

-    FOwnsStream : Boolean;

-  protected

-    procedure Write( const buffer: TBytes; offset: Integer; count: Integer); override;

-    function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; override;

-    procedure Open; override;

-    procedure Close; override;

-    procedure Flush; override;

-    function IsOpen: Boolean; override;

-    function ToArray: TBytes; override;

-  public

-    constructor Create( const AStream: TStream; AOwnsStream : Boolean);

-    destructor Destroy; override;

-  end;

-

-  TThriftStreamAdapterCOM = class( TThriftStreamImpl)

-  private

-    FStream : IStream;

-  protected

-    procedure Write( const buffer: TBytes; offset: Integer; count: Integer); override;

-    function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; override;

-    procedure Open; override;

-    procedure Close; override;

-    procedure Flush; override;

-    function IsOpen: Boolean; override;

-    function ToArray: TBytes; override;

-  public

-    constructor Create( const AStream: IStream);

-  end;

-

-implementation

-

-{ TThriftStreamAdapterCOM }

-

-procedure TThriftStreamAdapterCOM.Close;

-begin

-  FStream := nil;

-end;

-

-constructor TThriftStreamAdapterCOM.Create( const AStream: IStream);

-begin

-  FStream := AStream;

-end;

-

-procedure TThriftStreamAdapterCOM.Flush;

-begin

-  if IsOpen then

-  begin

-    if FStream <> nil then

-    begin

-      FStream.Commit( STGC_DEFAULT );

-    end;

-  end;

-end;

-

-function TThriftStreamAdapterCOM.IsOpen: Boolean;

-begin

-  Result := FStream <> nil;

-end;

-

-procedure TThriftStreamAdapterCOM.Open;

-begin

-

-end;

-

-function TThriftStreamAdapterCOM.Read( var buffer: TBytes; offset: Integer; count: Integer): Integer;

-begin

-  inherited;

-  Result := 0;

-  if FStream <> nil then

-  begin

-    if count > 0 then

-    begin

-      FStream.Read( @buffer[offset], count, @Result);

-    end;

-  end;

-end;

-

-function TThriftStreamAdapterCOM.ToArray: TBytes;

-var

-  statstg: TStatStg;

-  len : Integer;

-  NewPos : Int64;

-  cbRead : Integer;

-begin

-  FillChar( statstg, SizeOf( statstg), 0);

-  len := 0;

-  if IsOpen then

-  begin

-    if Succeeded( FStream.Stat( statstg, STATFLAG_NONAME )) then

-    begin

-      len := statstg.cbSize;

-    end;

-  end;

-

-  SetLength( Result, len );

-

-  if len > 0 then

-  begin

-    if Succeeded( FStream.Seek( 0, STREAM_SEEK_SET, NewPos) ) then

-    begin

-      FStream.Read( @Result[0], len, @cbRead);

-    end;

-  end;

-end;

-

-procedure TThriftStreamAdapterCOM.Write( const buffer: TBytes; offset: Integer; count: Integer);

-var

-  nWritten : Integer;

-begin

-  inherited;

-  if IsOpen then

-  begin

-    if count > 0 then

-    begin

-      FStream.Write( @buffer[0], count, @nWritten);

-    end;

-  end;

-end;

-

-{ TThriftStreamImpl }

-

-procedure TThriftStreamImpl.CheckSizeAndOffset(const buffer: TBytes; offset,

-  count: Integer);

-var

-  len : Integer;

-begin

-  if count > 0 then

-  begin

-    len := Length( buffer );

-    if (offset < 0) or ( offset >= len) then

-    begin

-      raise ERangeError.Create( SBitsIndexError );

-    end;

-    if count > len then

-    begin

-      raise ERangeError.Create( SBitsIndexError );

-    end;

-  end;

-end;

-

-function TThriftStreamImpl.Read(var buffer: TBytes; offset,

-  count: Integer): Integer;

-begin

-  Result := 0;

-  CheckSizeAndOffset( buffer, offset, count );

-end;

-

-procedure TThriftStreamImpl.Write(const buffer: TBytes; offset, count: Integer);

-begin

-  CheckSizeAndOffset( buffer, offset, count );

-end;

-

-{ TThriftStreamAdapterDelphi }

-

-procedure TThriftStreamAdapterDelphi.Close;

-begin

-  FStream.Free;

-  FStream := nil;

-  FOwnsStream := False;

-end;

-

-constructor TThriftStreamAdapterDelphi.Create( const AStream: TStream; AOwnsStream: Boolean);

-begin

-  FStream := AStream;

-  FOwnsStream := AOwnsStream;

-end;

-

-destructor TThriftStreamAdapterDelphi.Destroy;

-begin

-  if FOwnsStream then

-  begin

-    FStream.Free;

-  end;

-  inherited;

-end;

-

-procedure TThriftStreamAdapterDelphi.Flush;

-begin

-

-end;

-

-function TThriftStreamAdapterDelphi.IsOpen: Boolean;

-begin

-  Result := FStream <> nil;

-end;

-

-procedure TThriftStreamAdapterDelphi.Open;

-begin

-

-end;

-

-function TThriftStreamAdapterDelphi.Read(var buffer: TBytes; offset,

-  count: Integer): Integer;

-begin

-  inherited;

-  Result := 0;

-  if count > 0 then

-  begin

-    Result := FStream.Read( Pointer(@buffer[offset])^, count)

-  end;

-end;

-

-function TThriftStreamAdapterDelphi.ToArray: TBytes;

-var

-  OrgPos : Integer;

-  len : Integer;

-begin

-  len := 0;

-  if FStream <> nil then

-  begin

-    len := FStream.Size;

-  end;

-

-  SetLength( Result, len );

-

-  if len > 0 then

-  begin

-    OrgPos := FStream.Position;

-    try

-      FStream.Position := 0;

-      FStream.ReadBuffer( Pointer(@Result[0])^, len );

-    finally

-      FStream.Position := OrgPos;

-    end;

-  end

-end;

-

-procedure TThriftStreamAdapterDelphi.Write(const buffer: TBytes; offset,

-  count: Integer);

-begin

-  inherited;

-  if count > 0 then

-  begin

-    FStream.Write( Pointer(@buffer[offset])^, count)

-  end;

-end;

-

-end.

+(*
+ * 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.
+ *)
+
+unit Thrift.Stream;
+
+{$I Thrift.Defines.inc}
+
+interface
+
+uses
+  Classes,
+  SysUtils,
+  SysConst,
+  RTLConsts,
+  {$IFDEF OLD_UNIT_NAMES}
+  ActiveX,
+  {$ELSE}
+  Winapi.ActiveX,
+  {$ENDIF}
+  Thrift.Utils;
+
+type
+
+  IThriftStream = interface
+    ['{2A77D916-7446-46C1-8545-0AEC0008DBCA}']
+    procedure Write( const buffer: TBytes; offset: Integer; count: Integer);  overload;
+    procedure Write( const pBuf : Pointer; offset: Integer; count: Integer);  overload;
+    function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer;  overload;
+    function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;  overload;
+    procedure Open;
+    procedure Close;
+    procedure Flush;
+    function IsOpen: Boolean;
+    function ToArray: TBytes;
+  end;
+
+  TThriftStreamImpl = class( TInterfacedObject, IThriftStream)
+  private
+    procedure CheckSizeAndOffset( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer);  overload;
+  protected
+    procedure Write( const buffer: TBytes; offset: Integer; count: Integer); overload; inline;
+    procedure Write( const pBuf : Pointer; offset: Integer; count: Integer);  overload; virtual;
+    function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; overload; inline;
+    function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; overload; virtual;
+    procedure Open; virtual; abstract;
+    procedure Close; virtual; abstract;
+    procedure Flush; virtual; abstract;
+    function IsOpen: Boolean; virtual; abstract;
+    function ToArray: TBytes; virtual; abstract;
+  end;
+
+  TThriftStreamAdapterDelphi = class( TThriftStreamImpl )
+  private
+    FStream : TStream;
+    FOwnsStream : Boolean;
+  protected
+    procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
+    function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
+    procedure Open; override;
+    procedure Close; override;
+    procedure Flush; override;
+    function IsOpen: Boolean; override;
+    function ToArray: TBytes; override;
+  public
+    constructor Create( const AStream: TStream; AOwnsStream : Boolean);
+    destructor Destroy; override;
+  end;
+
+  TThriftStreamAdapterCOM = class( TThriftStreamImpl)
+  private
+    FStream : IStream;
+  protected
+    procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
+    function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
+    procedure Open; override;
+    procedure Close; override;
+    procedure Flush; override;
+    function IsOpen: Boolean; override;
+    function ToArray: TBytes; override;
+  public
+    constructor Create( const AStream: IStream);
+  end;
+
+implementation
+
+{ TThriftStreamAdapterCOM }
+
+procedure TThriftStreamAdapterCOM.Close;
+begin
+  FStream := nil;
+end;
+
+constructor TThriftStreamAdapterCOM.Create( const AStream: IStream);
+begin
+  inherited Create;
+  FStream := AStream;
+end;
+
+procedure TThriftStreamAdapterCOM.Flush;
+begin
+  if IsOpen then begin
+    if FStream <> nil then begin
+      FStream.Commit( STGC_DEFAULT );
+    end;
+  end;
+end;
+
+function TThriftStreamAdapterCOM.IsOpen: Boolean;
+begin
+  Result := FStream <> nil;
+end;
+
+procedure TThriftStreamAdapterCOM.Open;
+begin
+  // nothing to do
+end;
+
+function TThriftStreamAdapterCOM.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
+var pTmp : PByte;
+begin
+  inherited;
+
+  if count >= buflen-offset
+  then count := buflen-offset;
+
+  Result := 0;
+  if FStream <> nil then begin
+    if count > 0 then begin
+      pTmp := pBuf;
+      Inc( pTmp, offset);
+      FStream.Read( pTmp, count, @Result);
+    end;
+  end;
+end;
+
+function TThriftStreamAdapterCOM.ToArray: TBytes;
+var
+  statstg: TStatStg;
+  len : Integer;
+  NewPos : {$IF CompilerVersion >= 29.0} UInt64 {$ELSE} Int64  {$IFEND};
+  cbRead : Integer;
+begin
+  FillChar( statstg, SizeOf( statstg), 0);
+  len := 0;
+  if IsOpen then begin
+    if Succeeded( FStream.Stat( statstg, STATFLAG_NONAME )) then begin
+      len := statstg.cbSize;
+    end;
+  end;
+
+  SetLength( Result, len );
+
+  if len > 0 then begin
+    if Succeeded( FStream.Seek( 0, STREAM_SEEK_SET, NewPos) ) then begin
+      FStream.Read( @Result[0], len, @cbRead);
+    end;
+  end;
+end;
+
+procedure TThriftStreamAdapterCOM.Write( const pBuf: Pointer; offset: Integer; count: Integer);
+var nWritten : Integer;
+    pTmp : PByte;
+begin
+  inherited;
+  if IsOpen then begin
+    if count > 0 then begin
+      pTmp := pBuf;
+      Inc( pTmp, offset);
+      FStream.Write( pTmp, count, @nWritten);
+    end;
+  end;
+end;
+
+{ TThriftStreamImpl }
+
+procedure TThriftStreamImpl.CheckSizeAndOffset( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer);
+begin
+  if count > 0 then begin
+    if (offset < 0) or ( offset >= buflen) then begin
+      raise ERangeError.Create( SBitsIndexError );
+    end;
+    if count > buflen then begin
+      raise ERangeError.Create( SBitsIndexError );
+    end;
+  end;
+end;
+
+function TThriftStreamImpl.Read(var buffer: TBytes; offset, count: Integer): Integer;
+begin
+  if Length(buffer) > 0
+  then Result := Read( @buffer[0], Length(buffer), offset, count)
+  else Result := 0;
+end;
+
+function TThriftStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
+begin
+  Result := 0;
+  CheckSizeAndOffset( pBuf, buflen, offset, count );
+end;
+
+procedure TThriftStreamImpl.Write(const buffer: TBytes; offset, count: Integer);
+begin
+  if Length(buffer) > 0
+  then Write( @buffer[0], offset, count);
+end;
+
+procedure TThriftStreamImpl.Write( const pBuf : Pointer; offset: Integer; count: Integer);
+begin
+  CheckSizeAndOffset( pBuf, offset+count, offset, count);
+end;
+
+{ TThriftStreamAdapterDelphi }
+
+procedure TThriftStreamAdapterDelphi.Close;
+begin
+  FStream.Free;
+  FStream := nil;
+  FOwnsStream := False;
+end;
+
+constructor TThriftStreamAdapterDelphi.Create( const AStream: TStream; AOwnsStream: Boolean);
+begin
+  inherited Create;
+  FStream := AStream;
+  FOwnsStream := AOwnsStream;
+end;
+
+destructor TThriftStreamAdapterDelphi.Destroy;
+begin
+  if FOwnsStream 
+  then Close;
+  
+  inherited;
+end;
+
+procedure TThriftStreamAdapterDelphi.Flush;
+begin
+  // nothing to do
+end;
+
+function TThriftStreamAdapterDelphi.IsOpen: Boolean;
+begin
+  Result := FStream <> nil;
+end;
+
+procedure TThriftStreamAdapterDelphi.Open;
+begin
+  // nothing to do
+end;
+
+function TThriftStreamAdapterDelphi.Read(const pBuf : Pointer; const buflen : Integer; offset, count: Integer): Integer;
+var pTmp : PByte;
+begin
+  inherited;
+
+  if count >= buflen-offset
+  then count := buflen-offset;
+
+  if count > 0 then begin
+    pTmp := pBuf;
+    Inc( pTmp, offset);
+    Result := FStream.Read( pTmp^, count)
+  end
+  else Result := 0;
+end;
+
+function TThriftStreamAdapterDelphi.ToArray: TBytes;
+var
+  OrgPos : Integer;
+  len : Integer;
+begin
+  len := 0;
+  if FStream <> nil then
+  begin
+    len := FStream.Size;
+  end;
+
+  SetLength( Result, len );
+
+  if len > 0 then
+  begin
+    OrgPos := FStream.Position;
+    try
+      FStream.Position := 0;
+      FStream.ReadBuffer( Pointer(@Result[0])^, len );
+    finally
+      FStream.Position := OrgPos;
+    end;
+  end
+end;
+
+procedure TThriftStreamAdapterDelphi.Write(const pBuf : Pointer; offset, count: Integer);
+var pTmp : PByte;
+begin
+  inherited;
+  if count > 0 then begin
+    pTmp := pBuf;
+    Inc( pTmp, offset);
+    FStream.Write( pTmp^, count)
+  end;
+end;
+
+end.
diff --git a/lib/delphi/src/Thrift.Transport.Pipes.pas b/lib/delphi/src/Thrift.Transport.Pipes.pas
index bf07e1e..77a343b 100644
--- a/lib/delphi/src/Thrift.Transport.Pipes.pas
+++ b/lib/delphi/src/Thrift.Transport.Pipes.pas
Binary files differ
diff --git a/lib/delphi/src/Thrift.Transport.pas b/lib/delphi/src/Thrift.Transport.pas
index 8668e5a..dad9ab7 100644
--- a/lib/delphi/src/Thrift.Transport.pas
+++ b/lib/delphi/src/Thrift.Transport.pas
@@ -1,1266 +1,1715 @@
-(*

- * 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.

- *)

-

- {$SCOPEDENUMS ON}

-

-unit Thrift.Transport;

-

-interface

-

-uses

-  Classes,

-  SysUtils,

-  Math,

-  Sockets,

-  Generics.Collections,

-  Thrift.Collections,

-  Thrift.Utils,

-  Thrift.Stream,

-  ActiveX,

-  msxml;

-

-type

-  ITransport = interface

-    ['{A4A9FC37-D620-44DC-AD21-662D16364CE4}']

-    function GetIsOpen: Boolean;

-    property IsOpen: Boolean read GetIsOpen;

-    function Peek: Boolean;

-    procedure Open;

-    procedure Close;

-    function Read(var buf: TBytes; off: Integer; len: Integer): Integer;

-    function ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer;

-    procedure Write( const buf: TBytes); overload;

-    procedure Write( const buf: TBytes; off: Integer; len: Integer); overload;

-    procedure Flush;

-  end;

-

-  TTransportImpl = class( TInterfacedObject, ITransport)

-  protected

-    function GetIsOpen: Boolean; virtual; abstract;

-    property IsOpen: Boolean read GetIsOpen;

-    function Peek: Boolean; virtual;

-    procedure Open(); virtual; abstract;

-    procedure Close(); virtual; abstract;

-    function Read(var buf: TBytes; off: Integer; len: Integer): Integer; virtual; abstract;

-    function ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer; virtual;

-    procedure Write( const buf: TBytes); overload; virtual;

-    procedure Write( const buf: TBytes; off: Integer; len: Integer); overload; virtual; abstract;

-    procedure Flush; virtual;

-  end;

-

-  TTransportException = class( Exception )

-  public

-    type

-      TExceptionType = (

-        Unknown,

-        NotOpen,

-        AlreadyOpen,

-        TimedOut,

-        EndOfFile

-      );

-  private

-    FType : TExceptionType;

-  public

-    constructor Create( AType: TExceptionType); overload;

-    constructor Create( const msg: string); overload;

-    constructor Create( AType: TExceptionType; const msg: string); overload;

-    property Type_: TExceptionType read FType;

-  end;

-

-  IHTTPClient = interface( ITransport )

-    ['{0F5DB8AB-710D-4338-AAC9-46B5734C5057}']

-    procedure SetConnectionTimeout(const Value: Integer);

-    function GetConnectionTimeout: Integer;

-    procedure SetReadTimeout(const Value: Integer);

-    function GetReadTimeout: Integer;

-    function GetCustomHeaders: IThriftDictionary<string,string>;

-    procedure SendRequest;

-    property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout;

-    property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;

-    property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;

-  end;

-

-  THTTPClientImpl = class( TTransportImpl, IHTTPClient)

-  private

-    FUri : string;

-    FInputStream : IThriftStream;

-    FOutputStream : IThriftStream;

-    FConnectionTimeout : Integer;

-    FReadTimeout : Integer;

-    FCustomHeaders : IThriftDictionary<string,string>;

-

-    function CreateRequest: IXMLHTTPRequest;

-  protected

-    function GetIsOpen: Boolean; override;

-    procedure Open(); override;

-    procedure Close(); override;

-    function Read( var buf: TBytes; off: Integer; len: Integer): Integer; override;

-    procedure Write( const buf: TBytes; off: Integer; len: Integer); override;

-    procedure Flush; override;

-

-    procedure SetConnectionTimeout(const Value: Integer);

-    function GetConnectionTimeout: Integer;

-    procedure SetReadTimeout(const Value: Integer);

-    function GetReadTimeout: Integer;

-    function GetCustomHeaders: IThriftDictionary<string,string>;

-    procedure SendRequest;

-    property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout;

-    property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;

-    property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;

-  public

-    constructor Create( const AUri: string);

-    destructor Destroy; override;

-  end;

-

-  IServerTransport = interface

-    ['{BF6B7043-DA22-47BF-8B11-2B88EC55FE12}']

-    procedure Listen;

-    procedure Close;

-    function Accept: ITransport;

-  end;

-

-  TServerTransportImpl = class( TInterfacedObject, IServerTransport)

-  protected

-    function AcceptImpl: ITransport; virtual; abstract;

-  public

-    procedure Listen; virtual; abstract;

-    procedure Close; virtual; abstract;

-    function Accept: ITransport;

-  end;

-

-  ITransportFactory = interface

-    ['{DD809446-000F-49E1-9BFF-E0D0DC76A9D7}']

-    function GetTransport( const ATrans: ITransport): ITransport;

-  end;

-

-  TTransportFactoryImpl = class( TInterfacedObject, ITransportFactory)

-    function GetTransport( const ATrans: ITransport): ITransport; virtual;

-  end;

-

-  TTcpSocketStreamImpl = class( TThriftStreamImpl )

-  private

-    FTcpClient : TCustomIpClient;

-  protected

-    procedure Write( const buffer: TBytes; offset: Integer; count: Integer); override;

-    function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; override;

-    procedure Open; override;

-    procedure Close; override;

-    procedure Flush; override;

-

-    function IsOpen: Boolean; override;

-    function ToArray: TBytes; override;

-  public

-    constructor Create( const ATcpClient: TCustomIpClient);

-  end;

-

-  IStreamTransport = interface( ITransport )

-    ['{A8479B47-2A3E-4421-A9A0-D5A9EDCC634A}']

-    function GetInputStream: IThriftStream;

-    function GetOutputStream: IThriftStream;

-    property InputStream : IThriftStream read GetInputStream;

-    property OutputStream : IThriftStream read GetOutputStream;

-  end;

-

-  TStreamTransportImpl = class( TTransportImpl, IStreamTransport)

-  protected

-    FInputStream : IThriftStream;

-    FOutputStream : IThriftStream;

-  protected

-    function GetIsOpen: Boolean; override;

-

-    function GetInputStream: IThriftStream;

-    function GetOutputStream: IThriftStream;

-  public

-    property InputStream : IThriftStream read GetInputStream;

-    property OutputStream : IThriftStream read GetOutputStream;

-

-    procedure Open; override;

-    procedure Close; override;

-    procedure Flush; override;

-    function Read(var buf: TBytes; off: Integer; len: Integer): Integer; override;

-    procedure Write( const buf: TBytes; off: Integer; len: Integer); override;

-    constructor Create( const AInputStream : IThriftStream; const AOutputStream : IThriftStream);

-    destructor Destroy; override;

-  end;

-

-  TBufferedStreamImpl = class( TThriftStreamImpl)

-  private

-    FStream : IThriftStream;

-    FBufSize : Integer;

-    FReadBuffer : TMemoryStream;

-    FWriteBuffer : TMemoryStream;

-  protected

-    procedure Write( const buffer: TBytes; offset: Integer; count: Integer); override;

-    function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; override;

-    procedure Open;  override;

-    procedure Close; override;

-    procedure Flush; override;

-    function IsOpen: Boolean; override;

-    function ToArray: TBytes; override;

-  public

-    constructor Create( const AStream: IThriftStream; ABufSize: Integer);

-    destructor Destroy; override;

-  end;

-

-  TServerSocketImpl = class( TServerTransportImpl)

-  private

-    FServer : TTcpServer;

-    FPort : Integer;

-    FClientTimeout : Integer;

-    FUseBufferedSocket : Boolean;

-    FOwnsServer : Boolean;

-  protected

-    function AcceptImpl: ITransport; override;

-  public

-    constructor Create( const AServer: TTcpServer ); overload;

-    constructor Create( const AServer: TTcpServer; AClientTimeout: Integer); overload;

-    constructor Create( APort: Integer); overload;

-    constructor Create( APort: Integer; AClientTimeout: Integer); overload;

-    constructor Create( APort: Integer; AClientTimeout: Integer;

-      AUseBufferedSockets: Boolean); overload;

-    destructor Destroy; override;

-    procedure Listen; override;

-    procedure Close; override;

-  end;

-

-  TBufferedTransportImpl = class( TTransportImpl )

-  private

-    FInputBuffer : IThriftStream;

-    FOutputBuffer : IThriftStream;

-    FTransport : IStreamTransport;

-    FBufSize : Integer;

-

-    procedure InitBuffers;

-    function GetUnderlyingTransport: ITransport;

-  protected

-    function GetIsOpen: Boolean; override;

-    procedure Flush; override;

-  public

-    procedure Open(); override;

-    procedure Close(); override;

-    function Read(var buf: TBytes; off: Integer; len: Integer): Integer; override;

-    procedure Write( const buf: TBytes; off: Integer; len: Integer); override;

-    constructor Create( const ATransport : IStreamTransport ); overload;

-    constructor Create( const ATransport : IStreamTransport; ABufSize: Integer); overload;

-    property UnderlyingTransport: ITransport read GetUnderlyingTransport;

-    property IsOpen: Boolean read GetIsOpen;

-  end;

-

-  TSocketImpl = class(TStreamTransportImpl)

-  private

-    FClient : TCustomIpClient;

-    FOwnsClient : Boolean;

-    FHost : string;

-    FPort : Integer;

-    FTimeout : Integer;

-

-    procedure InitSocket;

-  protected

-    function GetIsOpen: Boolean; override;

-  public

-    procedure Open; override;

-    constructor Create( const AClient : TCustomIpClient); overload;

-    constructor Create( const AHost: string; APort: Integer); overload;

-    constructor Create( const AHost: string; APort: Integer; ATimeout: Integer); overload;

-    destructor Destroy; override;

-    procedure Close; override;

-    property TcpClient: TCustomIpClient read FClient;

-    property Host : string read FHost;

-    property Port: Integer read FPort;

-  end;

-

-  TFramedTransportImpl = class( TTransportImpl)

-  private const

-    FHeaderSize : Integer = 4;

-  private class var

-    FHeader_Dummy : array of Byte;

-  protected

-    FTransport : ITransport;

-    FWriteBuffer : TMemoryStream;

-    FReadBuffer : TMemoryStream;

-

-    procedure InitWriteBuffer;

-    procedure ReadFrame;

-  public

-    type

-      TFactory = class( TTransportFactoryImpl )

-      public

-        function GetTransport( const ATrans: ITransport): ITransport; override;

-      end;

-

-{$IF CompilerVersion >= 21.0}

-    class constructor Create;

-{$IFEND}

-    constructor Create; overload;

-    constructor Create( const ATrans: ITransport); overload;

-    destructor Destroy; override;

-

-    procedure Open(); override;

-    function GetIsOpen: Boolean; override;

-

-    procedure Close(); override;

-    function Read(var buf: TBytes; off: Integer; len: Integer): Integer; override;

-    procedure Write( const buf: TBytes; off: Integer; len: Integer); override;

-    procedure Flush; override;

-  end;

-

-{$IF CompilerVersion < 21.0}

-procedure TFramedTransportImpl_Initialize;

-{$IFEND}

-

-implementation

-

-{ TTransportImpl }

-

-procedure TTransportImpl.Flush;

-begin

-

-end;

-

-function TTransportImpl.Peek: Boolean;

-begin

-  Result := IsOpen;

-end;

-

-function TTransportImpl.ReadAll( var buf: TBytes; off, len: Integer): Integer;

-var

-  got : Integer;

-  ret : Integer;

-begin

-  got := 0;

-  while ( got < len) do

-  begin

-    ret := Read( buf, off + got, len - got);

-    if ( ret <= 0 ) then

-    begin

-      raise TTransportException.Create( 'Cannot read, Remote side has closed' );

-    end;

-    got := got + ret;

-  end;

-  Result := got;

-end;

-

-procedure TTransportImpl.Write( const buf: TBytes);

-begin

-  Self.Write( buf, 0, Length(buf) );

-end;

-

-{ THTTPClientImpl }

-

-procedure THTTPClientImpl.Close;

-begin

-  FInputStream := nil;

-  FOutputStream := nil;

-end;

-

-constructor THTTPClientImpl.Create(const AUri: string);

-begin

-  inherited Create;

-  FUri := AUri;

-  FCustomHeaders := TThriftDictionaryImpl<string,string>.Create;

-  FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);

-end;

-

-function THTTPClientImpl.CreateRequest: IXMLHTTPRequest;

-var

-  pair : TPair<string,string>;

-begin

-{$IF CompilerVersion >= 21.0}

-  Result := CoXMLHTTP.Create;

-{$ELSE}

-  Result := CoXMLHTTPRequest.Create;

-{$IFEND}

-

-  Result.open('POST', FUri, False, '', '');

-  Result.setRequestHeader( 'Content-Type', 'application/x-thrift');

-  Result.setRequestHeader( 'Accept', 'application/x-thrift');

-  Result.setRequestHeader( 'User-Agent', 'Delphi/IHTTPClient');

-

-  for pair in FCustomHeaders do

-  begin

-    Result.setRequestHeader( pair.Key, pair.Value );

-  end;

-end;

-

-destructor THTTPClientImpl.Destroy;

-begin

-  Close;

-  inherited;

-end;

-

-procedure THTTPClientImpl.Flush;

-begin

-  try

-    SendRequest;

-  finally

-    FOutputStream := nil;

-    FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);

-  end;

-end;

-

-function THTTPClientImpl.GetConnectionTimeout: Integer;

-begin

-  Result := FConnectionTimeout;

-end;

-

-function THTTPClientImpl.GetCustomHeaders: IThriftDictionary<string,string>;

-begin

-  Result := FCustomHeaders;

-end;

-

-function THTTPClientImpl.GetIsOpen: Boolean;

-begin

-  Result := True;

-end;

-

-function THTTPClientImpl.GetReadTimeout: Integer;

-begin

-  Result := FReadTimeout;

-end;

-

-procedure THTTPClientImpl.Open;

-begin

-

-end;

-

-function THTTPClientImpl.Read( var buf: TBytes; off, len: Integer): Integer;

-begin

-  if FInputStream = nil then

-  begin

-    raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,

-      'No request has been sent');

-  end;

-  try

-    Result := FInputStream.Read( buf, off, len )

-  except

-    on E: Exception do

-    begin

-      raise TTransportException.Create( TTransportException.TExceptionType.Unknown,

-        E.Message);

-    end;

-  end;

-end;

-

-procedure THTTPClientImpl.SendRequest;

-var

-  xmlhttp : IXMLHTTPRequest;

-  ms : TMemoryStream;

-  a : TBytes;

-  len : Integer;

-begin

-  xmlhttp := CreateRequest;

-

-  ms := TMemoryStream.Create;

-  try

-    a := FOutputStream.ToArray;

-    len := Length(a);

-    if len > 0 then

-    begin

-      ms.WriteBuffer( Pointer(@a[0])^, len);

-    end;

-    ms.Position := 0;

-    xmlhttp.send( IUnknown( TStreamAdapter.Create( ms, soReference )));

-    FInputStream := nil;

-    FInputStream := TThriftStreamAdapterCOM.Create( IUnknown( xmlhttp.responseStream) as IStream);

-  finally

-    ms.Free;

-  end;

-end;

-

-procedure THTTPClientImpl.SetConnectionTimeout(const Value: Integer);

-begin

-  FConnectionTimeout := Value;

-end;

-

-procedure THTTPClientImpl.SetReadTimeout(const Value: Integer);

-begin

-  FReadTimeout := Value

-end;

-

-procedure THTTPClientImpl.Write( const buf: TBytes; off, len: Integer);

-begin

-  FOutputStream.Write( buf, off, len);

-end;

-

-{ TTransportException }

-

-constructor TTransportException.Create(AType: TExceptionType);

-begin

-  Create( AType, '' )

-end;

-

-constructor TTransportException.Create(AType: TExceptionType;

-  const msg: string);

-begin

-  inherited Create(msg);

-  FType := AType;

-end;

-

-constructor TTransportException.Create(const msg: string);

-begin

-  inherited Create(msg);

-end;

-

-{ TServerTransportImpl }

-

-function TServerTransportImpl.Accept: ITransport;

-begin

-  Result := AcceptImpl;

-  if Result = nil then

-  begin

-    raise TTransportException.Create( 'accept() may not return NULL' );

-  end;

-end;

-

-{ TTransportFactoryImpl }

-

-function TTransportFactoryImpl.GetTransport( const ATrans: ITransport): ITransport;

-begin

-  Result := ATrans;

-end;

-

-{ TServerSocket }

-

-constructor TServerSocketImpl.Create( const AServer: TTcpServer; AClientTimeout: Integer);

-begin

-  FServer := AServer;

-  FClientTimeout := AClientTimeout;

-end;

-

-constructor TServerSocketImpl.Create( const AServer: TTcpServer);

-begin

-  Create( AServer, 0 );

-end;

-

-constructor TServerSocketImpl.Create(APort: Integer);

-begin

-  Create( APort, 0 );

-end;

-

-function TServerSocketImpl.AcceptImpl: ITransport;

-var

-  ret : TCustomIpClient;

-  ret2 : IStreamTransport;

-  ret3 : ITransport;

-begin

-  if FServer = nil then

-  begin

-    raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,

-      'No underlying server socket.');

-  end;

-

-  try

-    ret := TCustomIpClient.Create(nil);

-    if ( not FServer.Accept( ret )) then

-    begin

-      ret.Free;

-      Result := nil;

-      Exit;

-    end;

-

-    if ret = nil then

-    begin

-      Result := nil;

-      Exit;

-    end;

-

-    ret2 := TSocketImpl.Create( ret );

-    if FUseBufferedSocket then

-    begin

-      ret3 := TBufferedTransportImpl.Create(ret2);

-      Result := ret3;

-    end else

-    begin

-      Result := ret2;

-    end;

-

-  except

-    on E: Exception do

-    begin

-      raise TTransportException.Create( E.ToString );

-    end;

-  end;

-end;

-

-procedure TServerSocketImpl.Close;

-begin

-  if FServer <> nil then

-  begin

-    try

-      FServer.Active := False;

-    except

-      on E: Exception do

-      begin

-        raise TTransportException.Create('Error on closing socket : ' + E.Message);

-      end;

-    end;

-  end;

-end;

-

-constructor TServerSocketImpl.Create(APort, AClientTimeout: Integer;

-  AUseBufferedSockets: Boolean);

-begin

-  FPort := APort;

-  FClientTimeout := AClientTimeout;

-  FUseBufferedSocket := AUseBufferedSockets;

-  FOwnsServer := True;

-  FServer := TTcpServer.Create( nil );

-  FServer.BlockMode := bmBlocking;

-{$IF CompilerVersion >= 21.0}

-  FServer.LocalPort := AnsiString( IntToStr( FPort));

-{$ELSE}

-  FServer.LocalPort := IntToStr( FPort);

-{$IFEND}

-end;

-

-destructor TServerSocketImpl.Destroy;

-begin

-  if FOwnsServer then

-  begin

-    FServer.Free;

-  end;

-  inherited;

-end;

-

-procedure TServerSocketImpl.Listen;

-begin

-  if FServer <> nil then

-  begin

-    try

-      FServer.Active := True;

-    except

-      on E: Exception do

-      begin

-        raise TTransportException.Create('Could not accept on listening socket: ' + E.Message);

-      end;

-    end;

-  end;

-end;

-

-constructor TServerSocketImpl.Create(APort, AClientTimeout: Integer);

-begin

-  Create( APort, AClientTimeout, False );

-end;

-

-{ TSocket }

-

-constructor TSocketImpl.Create( const AClient : TCustomIpClient);

-var

-  stream : IThriftStream;

-begin

-  FClient := AClient;

-  stream := TTcpSocketStreamImpl.Create( FClient);

-  FInputStream := stream;

-  FOutputStream := stream;

-end;

-

-constructor TSocketImpl.Create(const AHost: string; APort: Integer);

-begin

-  Create( AHost, APort, 0);

-end;

-

-procedure TSocketImpl.Close;

-begin

-  inherited Close;

-  if FClient <> nil then

-  begin

-    FClient.Free;

-    FClient := nil;

-  end;

-end;

-

-constructor TSocketImpl.Create(const AHost: string; APort, ATimeout: Integer);

-begin

-  FHost := AHost;

-  FPort := APort;

-  FTimeout := ATimeout;

-  InitSocket;

-end;

-

-destructor TSocketImpl.Destroy;

-begin

-  if FOwnsClient then

-  begin

-    FClient.Free;

-  end;

-  inherited;

-end;

-

-function TSocketImpl.GetIsOpen: Boolean;

-begin

-  Result := False;

-  if FClient <> nil then

-  begin

-    Result := FClient.Connected;

-  end;

-end;

-

-procedure TSocketImpl.InitSocket;

-var

-  stream : IThriftStream;

-begin

-  if FClient <> nil then

-  begin

-    if FOwnsClient then

-    begin

-      FClient.Free;

-      FClient := nil;

-    end;

-  end;

-  FClient := TTcpClient.Create( nil );

-  FOwnsClient := True;

-

-  stream := TTcpSocketStreamImpl.Create( FClient);

-  FInputStream := stream;

-  FOutputStream := stream;

-

-end;

-

-procedure TSocketImpl.Open;

-begin

-  if IsOpen then

-  begin

-    raise TTransportException.Create( TTransportException.TExceptionType.AlreadyOpen,

-      'Socket already connected');

-  end;

-

-  if FHost =  '' then

-  begin

-    raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,

-      'Cannot open null host');

-  end;

-

-  if Port <= 0 then

-  begin

-    raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,

-      'Cannot open without port');

-  end;

-

-  if FClient = nil then

-  begin

-    InitSocket;

-  end;

-

-  FClient.RemoteHost := TSocketHost( Host);

-  FClient.RemotePort := TSocketPort( IntToStr( Port));

-  FClient.Connect;

-

-  FInputStream := TTcpSocketStreamImpl.Create( FClient);

-  FOutputStream := FInputStream;

-end;

-

-{ TBufferedStream }

-

-procedure TBufferedStreamImpl.Close;

-begin

-  Flush;

-  FStream := nil;

-

-  FReadBuffer.Free;

-  FReadBuffer := nil;

-

-  FWriteBuffer.Free;

-  FWriteBuffer := nil;

-end;

-

-constructor TBufferedStreamImpl.Create( const AStream: IThriftStream; ABufSize: Integer);

-begin

-  FStream := AStream;

-  FBufSize := ABufSize;

-  FReadBuffer := TMemoryStream.Create;

-  FWriteBuffer := TMemoryStream.Create;

-end;

-

-destructor TBufferedStreamImpl.Destroy;

-begin

-  Close;

-  inherited;

-end;

-

-procedure TBufferedStreamImpl.Flush;

-var

-  buf : TBytes;

-  len : Integer;

-begin

-  if IsOpen then

-  begin

-    len := FWriteBuffer.Size;

-    if len > 0 then

-    begin

-      SetLength( buf, len );

-      FWriteBuffer.Position := 0;

-      FWriteBuffer.Read( Pointer(@buf[0])^, len );

-      FStream.Write( buf, 0, len );

-    end;

-    FWriteBuffer.Clear;

-  end;

-end;

-

-function TBufferedStreamImpl.IsOpen: Boolean;

-begin

-  Result := (FWriteBuffer <> nil)

-        and (FReadBuffer <> nil)

-        and (FStream <> nil);

-end;

-

-procedure TBufferedStreamImpl.Open;

-begin

-

-end;

-

-function TBufferedStreamImpl.Read( var buffer: TBytes; offset: Integer; count: Integer): Integer;

-var

-  nRead : Integer;

-  tempbuf : TBytes;

-begin

-  inherited;

-  Result := 0;

-  if IsOpen then

-  begin

-    while count > 0 do begin

-

-      if FReadBuffer.Position >= FReadBuffer.Size then

-      begin

-        FReadBuffer.Clear;

-        SetLength( tempbuf, FBufSize);

-        nRead := FStream.Read( tempbuf, 0, FBufSize );

-        if nRead = 0 then Break; // avoid infinite loop

-

-        FReadBuffer.WriteBuffer( Pointer(@tempbuf[0])^, nRead );

-        FReadBuffer.Position := 0;

-      end;

-

-      if FReadBuffer.Position < FReadBuffer.Size then

-      begin

-        nRead  := Min( FReadBuffer.Size - FReadBuffer.Position, count);

-        Inc( Result, FReadBuffer.Read( Pointer(@buffer[offset])^, nRead));

-        Dec( count, nRead);

-        Inc( offset, nRead);

-      end;

-    end;

-  end;

-end;

-

-function TBufferedStreamImpl.ToArray: TBytes;

-var

-  len : Integer;

-begin

-  len := 0;

-

-  if IsOpen then

-  begin

-    len := FReadBuffer.Size;

-  end;

-

-  SetLength( Result, len);

-

-  if len > 0 then

-  begin

-    FReadBuffer.Position := 0;

-    FReadBuffer.Read( Pointer(@Result[0])^, len );

-  end;

-end;

-

-procedure TBufferedStreamImpl.Write( const buffer: TBytes; offset: Integer; count: Integer);

-begin

-  inherited;

-  if count > 0 then

-  begin

-    if IsOpen then

-    begin

-      FWriteBuffer.Write( Pointer(@buffer[offset])^, count );

-      if FWriteBuffer.Size > FBufSize then

-      begin

-        Flush;

-      end;

-    end;

-  end;

-end;

-

-{ TStreamTransportImpl }

-

-procedure TStreamTransportImpl.Close;

-begin

-  if FInputStream <> FOutputStream then

-  begin

-    if FInputStream <> nil then

-    begin

-      FInputStream := nil;

-    end;

-    if FOutputStream <> nil then

-    begin

-      FOutputStream := nil;

-    end;

-  end else

-  begin

-    FInputStream := nil;

-    FOutputStream := nil;

-  end;

-end;

-

-constructor TStreamTransportImpl.Create( const AInputStream : IThriftStream; const AOutputStream : IThriftStream);

-begin

-  FInputStream := AInputStream;

-  FOutputStream := AOutputStream;

-end;

-

-destructor TStreamTransportImpl.Destroy;

-begin

-  FInputStream := nil;

-  FOutputStream := nil;

-  inherited;

-end;

-

-procedure TStreamTransportImpl.Flush;

-begin

-  if FOutputStream = nil then

-  begin

-    raise TTransportException.Create( TTransportException.TExceptionType.NotOpen, 'Cannot flush null outputstream' );

-  end;

-

-  FOutputStream.Flush;

-end;

-

-function TStreamTransportImpl.GetInputStream: IThriftStream;

-begin

-  Result := FInputStream;

-end;

-

-function TStreamTransportImpl.GetIsOpen: Boolean;

-begin

-  Result := True;

-end;

-

-function TStreamTransportImpl.GetOutputStream: IThriftStream;

-begin

-  Result := FInputStream;

-end;

-

-procedure TStreamTransportImpl.Open;

-begin

-

-end;

-

-function TStreamTransportImpl.Read(var buf: TBytes; off, len: Integer): Integer;

-begin

-  if FInputStream = nil then

-  begin

-    raise TTransportException.Create( TTransportException.TExceptionType.NotOpen, 'Cannot read from null inputstream' );

-  end;

-  Result := FInputStream.Read( buf, off, len );

-end;

-

-procedure TStreamTransportImpl.Write(const buf: TBytes; off, len: Integer);

-begin

-  if FOutputStream = nil then

-  begin

-    raise TTransportException.Create( TTransportException.TExceptionType.NotOpen, 'Cannot write to null outputstream' );

-  end;

-

-  FOutputStream.Write( buf, off, len );

-end;

-

-{ TBufferedTransportImpl }

-

-constructor TBufferedTransportImpl.Create( const ATransport: IStreamTransport);

-begin

-  Create( ATransport, 1024 );

-end;

-

-procedure TBufferedTransportImpl.Close;

-begin

-  FTransport.Close;

-end;

-

-constructor TBufferedTransportImpl.Create( const ATransport: IStreamTransport;

-  ABufSize: Integer);

-begin

-  FTransport := ATransport;

-  FBufSize := ABufSize;

-  InitBuffers;

-end;

-

-procedure TBufferedTransportImpl.Flush;

-begin

-  if FOutputBuffer <> nil then

-  begin

-    FOutputBuffer.Flush;

-  end;

-end;

-

-function TBufferedTransportImpl.GetIsOpen: Boolean;

-begin

-  Result := FTransport.IsOpen;

-end;

-

-function TBufferedTransportImpl.GetUnderlyingTransport: ITransport;

-begin

-  Result := FTransport;

-end;

-

-procedure TBufferedTransportImpl.InitBuffers;

-begin

-  if FTransport.InputStream <> nil then

-  begin

-    FInputBuffer := TBufferedStreamImpl.Create( FTransport.InputStream, FBufSize );

-  end;

-  if FTransport.OutputStream <> nil then

-  begin

-    FOutputBuffer := TBufferedStreamImpl.Create( FTransport.OutputStream, FBufSize );

-  end;

-end;

-

-procedure TBufferedTransportImpl.Open;

-begin

-  FTransport.Open

-end;

-

-function TBufferedTransportImpl.Read(var buf: TBytes; off, len: Integer): Integer;

-begin

-  Result := 0;

-  if FInputBuffer <> nil then

-  begin

-    Result := FInputBuffer.Read( buf, off, len );

-  end;

-end;

-

-procedure TBufferedTransportImpl.Write(const buf: TBytes; off, len: Integer);

-begin

-  if FOutputBuffer <> nil then

-  begin

-    FOutputBuffer.Write( buf, off, len );

-  end;

-end;

-

-{ TFramedTransportImpl }

-

-{$IF CompilerVersion < 21.0}

-procedure TFramedTransportImpl_Initialize;

-begin

-  SetLength( TFramedTransportImpl.FHeader_Dummy, TFramedTransportImpl.FHeaderSize);

-  FillChar( TFramedTransportImpl.FHeader_Dummy[0],

-    Length( TFramedTransportImpl.FHeader_Dummy) * SizeOf( Byte ), 0);

-end;

-{$ELSE}

-class constructor TFramedTransportImpl.Create;

-begin

-  SetLength( FHeader_Dummy, FHeaderSize);

-  FillChar( FHeader_Dummy[0], Length( FHeader_Dummy) * SizeOf( Byte ), 0);

-end;

-{$IFEND}

-

-constructor TFramedTransportImpl.Create;

-begin

-  InitWriteBuffer;

-end;

-

-procedure TFramedTransportImpl.Close;

-begin

-  FTransport.Close;

-end;

-

-constructor TFramedTransportImpl.Create( const ATrans: ITransport);

-begin

-  InitWriteBuffer;

-  FTransport := ATrans;

-end;

-

-destructor TFramedTransportImpl.Destroy;

-begin

-  FWriteBuffer.Free;

-  FReadBuffer.Free;

-  inherited;

-end;

-

-procedure TFramedTransportImpl.Flush;

-var

-  buf : TBytes;

-  len : Integer;

-  data_len : Integer;

-

-begin

-  len := FWriteBuffer.Size;

-  SetLength( buf, len);

-  if len > 0 then

-  begin

-    System.Move( FWriteBuffer.Memory^, buf[0], len );

-  end;

-

-  data_len := len - FHeaderSize;

-  if (data_len < 0) then

-  begin

-    raise Exception.Create( 'TFramedTransport.Flush: data_len < 0' );

-  end;

-

-  InitWriteBuffer;

-

-  buf[0] := Byte($FF and (data_len shr 24));

-  buf[1] := Byte($FF and (data_len shr 16));

-  buf[2] := Byte($FF and (data_len shr 8));

-  buf[3] := Byte($FF and data_len);

-

-  FTransport.Write( buf, 0, len );

-  FTransport.Flush;

-end;

-

-function TFramedTransportImpl.GetIsOpen: Boolean;

-begin

-  Result := FTransport.IsOpen;

-end;

-

-type

-  TAccessMemoryStream = class(TMemoryStream)

-  end;

-

-procedure TFramedTransportImpl.InitWriteBuffer;

-begin

-  FWriteBuffer.Free;

-  FWriteBuffer := TMemoryStream.Create;

-  TAccessMemoryStream(FWriteBuffer).Capacity := 1024;

-  FWriteBuffer.Write( Pointer(@FHeader_Dummy[0])^, FHeaderSize);

-end;

-

-procedure TFramedTransportImpl.Open;

-begin

-  FTransport.Open;

-end;

-

-function TFramedTransportImpl.Read(var buf: TBytes; off, len: Integer): Integer;

-var

-  got : Integer;

-begin

-  if FReadBuffer <> nil then

-  begin

-    if len > 0

-    then got := FReadBuffer.Read( Pointer(@buf[off])^, len )

-    else got := 0;

-    if got > 0 then

-    begin

-      Result := got;

-      Exit;

-    end;

-  end;

-

-  ReadFrame;

-  if len > 0

-  then Result := FReadBuffer.Read( Pointer(@buf[off])^, len)

-  else Result := 0;

-end;

-

-procedure TFramedTransportImpl.ReadFrame;

-var

-  i32rd : TBytes;

-  size : Integer;

-  buff : TBytes;

-begin

-  SetLength( i32rd, FHeaderSize );

-  FTransport.ReadAll( i32rd, 0, FHeaderSize);

-  size :=

-    ((i32rd[0] and $FF) shl 24) or

-    ((i32rd[1] and $FF) shl 16) or

-    ((i32rd[2] and $FF) shl 8) or

-     (i32rd[3] and $FF);

-  SetLength( buff, size );

-  FTransport.ReadAll( buff, 0, size );

-  FReadBuffer.Free;

-  FReadBuffer := TMemoryStream.Create;

-  FReadBuffer.Write( Pointer(@buff[0])^, size );

-  FReadBuffer.Position := 0;

-end;

-

-procedure TFramedTransportImpl.Write(const buf: TBytes; off, len: Integer);

-begin

-  if len > 0

-  then FWriteBuffer.Write( Pointer(@buf[off])^, len );

-end;

-

-{ TFramedTransport.TFactory }

-

-function TFramedTransportImpl.TFactory.GetTransport( const ATrans: ITransport): ITransport;

-begin

-  Result := TFramedTransportImpl.Create( ATrans );

-end;

-

-{ TTcpSocketStreamImpl }

-

-procedure TTcpSocketStreamImpl.Close;

-begin

-  FTcpClient.Close;

-end;

-

-constructor TTcpSocketStreamImpl.Create( const ATcpClient: TCustomIpClient);

-begin

-  FTcpClient := ATcpClient;

-end;

-

-procedure TTcpSocketStreamImpl.Flush;

-begin

-

-end;

-

-function TTcpSocketStreamImpl.IsOpen: Boolean;

-begin

-  Result := FTcpClient.Active;

-end;

-

-procedure TTcpSocketStreamImpl.Open;

-begin

-  FTcpClient.Open;

-end;

-

-function TTcpSocketStreamImpl.Read(var buffer: TBytes; offset,

-  count: Integer): Integer;

-begin

-  inherited;

-  Result := FTcpClient.ReceiveBuf( Pointer(@buffer[offset])^, count);

-end;

-

-function TTcpSocketStreamImpl.ToArray: TBytes;

-var

-  len : Integer;

-begin

-  len := 0;

-  if IsOpen then

-  begin

-    len := FTcpClient.BytesReceived;

-  end;

-

-  SetLength( Result, len );

-

-  if len > 0 then

-  begin

-    FTcpClient.ReceiveBuf( Pointer(@Result[0])^, len);

-  end;

-end;

-

-procedure TTcpSocketStreamImpl.Write(const buffer: TBytes; offset, count: Integer);

-begin

-  inherited;

-  FTcpClient.SendBuf( Pointer(@buffer[offset])^, count);

-end;

-

-{$IF CompilerVersion < 21.0}

-initialization

-begin

-  TFramedTransportImpl_Initialize;

-end;

-{$IFEND}

-

-

-end.

+(*
+ * 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.
+ *)
+unit Thrift.Transport;
+
+{$I Thrift.Defines.inc}
+{$SCOPEDENUMS ON}
+
+interface
+
+uses
+  Classes,
+  SysUtils,
+  Math,
+  Generics.Collections,
+  {$IFDEF OLD_UNIT_NAMES}
+    ActiveX, msxml, WinSock, Sockets,
+  {$ELSE}
+    Winapi.ActiveX, Winapi.msxml, Winapi.WinSock,
+    {$IFDEF OLD_SOCKETS}
+      Web.Win.Sockets,
+    {$ELSE}
+      Thrift.Socket,
+    {$ENDIF}
+  {$ENDIF}
+  Thrift.Collections,
+  Thrift.Exception,
+  Thrift.Utils,
+  Thrift.Stream;
+
+type
+  ITransport = interface
+    ['{DB84961E-8BB3-4532-99E1-A8C7AC2300F7}']
+    function GetIsOpen: Boolean;
+    property IsOpen: Boolean read GetIsOpen;
+    function Peek: Boolean;
+    procedure Open;
+    procedure Close;
+    function Read(var buf: TBytes; off: Integer; len: Integer): Integer; overload;
+    function Read(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload;
+    function ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer; overload;
+    function ReadAll(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload;
+    procedure Write( const buf: TBytes); overload;
+    procedure Write( const buf: TBytes; off: Integer; len: Integer); overload;
+    procedure Write( const pBuf : Pointer; off, len : Integer); overload;
+    procedure Write( const pBuf : Pointer; len : Integer); overload;
+    procedure Flush;
+  end;
+
+  TTransportImpl = class( TInterfacedObject, ITransport)
+  protected
+    function GetIsOpen: Boolean; virtual; abstract;
+    property IsOpen: Boolean read GetIsOpen;
+    function Peek: Boolean; virtual;
+    procedure Open(); virtual; abstract;
+    procedure Close(); virtual; abstract;
+    function Read(var buf: TBytes; off: Integer; len: Integer): Integer; overload; inline;
+    function Read(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload; virtual; abstract;
+    function ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer;  overload; inline;
+    function ReadAll(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload; virtual;
+    procedure Write( const buf: TBytes); overload; inline;
+    procedure Write( const buf: TBytes; off: Integer; len: Integer); overload; inline;
+    procedure Write( const pBuf : Pointer; len : Integer); overload; inline;
+    procedure Write( const pBuf : Pointer; off, len : Integer); overload; virtual; abstract;
+    procedure Flush; virtual;
+  end;
+
+  TTransportException = class( TException)
+  public
+    type
+      TExceptionType = (
+        Unknown,
+        NotOpen,
+        AlreadyOpen,
+        TimedOut,
+        EndOfFile,
+        BadArgs,
+        Interrupted
+      );
+  private
+    function GetType: TExceptionType;
+  protected
+    constructor HiddenCreate(const Msg: string);
+  public
+    class function Create( AType: TExceptionType): TTransportException; overload; deprecated 'Use specialized TTransportException types (or regenerate from IDL)';
+    class function Create( const msg: string): TTransportException; reintroduce; overload; deprecated 'Use specialized TTransportException types (or regenerate from IDL)';
+    class function Create( AType: TExceptionType; const msg: string): TTransportException; overload; deprecated 'Use specialized TTransportException types (or regenerate from IDL)';
+    property Type_: TExceptionType read GetType;
+  end;
+
+  // Needed to remove deprecation warning
+  TTransportExceptionSpecialized = class abstract (TTransportException)
+  public
+    constructor Create(const Msg: string);
+  end;
+
+  TTransportExceptionUnknown = class (TTransportExceptionSpecialized);
+  TTransportExceptionNotOpen = class (TTransportExceptionSpecialized);
+  TTransportExceptionAlreadyOpen = class (TTransportExceptionSpecialized);
+  TTransportExceptionTimedOut = class (TTransportExceptionSpecialized);
+  TTransportExceptionEndOfFile = class (TTransportExceptionSpecialized);
+  TTransportExceptionBadArgs = class (TTransportExceptionSpecialized);
+  TTransportExceptionInterrupted = class (TTransportExceptionSpecialized);
+
+  IHTTPClient = interface( ITransport )
+    ['{BA142D12-8AE6-4B50-9E33-6B7843B21D73}']
+    procedure SetDnsResolveTimeout(const Value: Integer);
+    function GetDnsResolveTimeout: Integer;
+    procedure SetConnectionTimeout(const Value: Integer);
+    function GetConnectionTimeout: Integer;
+    procedure SetSendTimeout(const Value: Integer);
+    function GetSendTimeout: Integer;
+    procedure SetReadTimeout(const Value: Integer);
+    function GetReadTimeout: Integer;
+    function GetCustomHeaders: IThriftDictionary<string,string>;
+    procedure SendRequest;
+
+    property DnsResolveTimeout: Integer read GetDnsResolveTimeout write SetDnsResolveTimeout;
+    property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout;
+    property SendTimeout: Integer read GetSendTimeout write SetSendTimeout;
+    property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;
+    property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;
+  end;
+
+  THTTPClientImpl = class( TTransportImpl, IHTTPClient)
+  private
+    FUri : string;
+    FInputStream : IThriftStream;
+    FOutputStream : IThriftStream;
+    FDnsResolveTimeout : Integer;
+    FConnectionTimeout : Integer;
+    FSendTimeout : Integer;
+    FReadTimeout : Integer;
+    FCustomHeaders : IThriftDictionary<string,string>;
+
+    function CreateRequest: IXMLHTTPRequest;
+  protected
+    function GetIsOpen: Boolean; override;
+    procedure Open(); override;
+    procedure Close(); override;
+    function  Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
+    procedure Write( const pBuf : Pointer; off, len : Integer); override;
+    procedure Flush; override;
+
+    procedure SetDnsResolveTimeout(const Value: Integer);
+    function GetDnsResolveTimeout: Integer;
+    procedure SetConnectionTimeout(const Value: Integer);
+    function GetConnectionTimeout: Integer;
+    procedure SetSendTimeout(const Value: Integer);
+    function GetSendTimeout: Integer;
+    procedure SetReadTimeout(const Value: Integer);
+    function GetReadTimeout: Integer;
+
+    function GetCustomHeaders: IThriftDictionary<string,string>;
+    procedure SendRequest;
+    property DnsResolveTimeout: Integer read GetDnsResolveTimeout write SetDnsResolveTimeout;
+    property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout;
+    property SendTimeout: Integer read GetSendTimeout write SetSendTimeout;
+    property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;
+    property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;
+  public
+    constructor Create( const AUri: string);
+    destructor Destroy; override;
+  end;
+
+  IServerTransport = interface
+    ['{C43B87ED-69EA-47C4-B77C-15E288252900}']
+    procedure Listen;
+    procedure Close;
+    function Accept( const fnAccepting: TProc): ITransport;
+  end;
+
+  TServerTransportImpl = class( TInterfacedObject, IServerTransport)
+  protected
+    procedure Listen; virtual; abstract;
+    procedure Close; virtual; abstract;
+    function Accept( const fnAccepting: TProc): ITransport;  virtual; abstract;
+  end;
+
+  ITransportFactory = interface
+    ['{DD809446-000F-49E1-9BFF-E0D0DC76A9D7}']
+    function GetTransport( const ATrans: ITransport): ITransport;
+  end;
+
+  TTransportFactoryImpl = class( TInterfacedObject, ITransportFactory)
+    function GetTransport( const ATrans: ITransport): ITransport; virtual;
+  end;
+
+  TTcpSocketStreamImpl = class( TThriftStreamImpl )
+{$IFDEF OLD_SOCKETS}
+  private type
+    TWaitForData = ( wfd_HaveData, wfd_Timeout, wfd_Error);
+  private
+    FTcpClient : TCustomIpClient;
+    FTimeout : Integer;
+    function Select( ReadReady, WriteReady, ExceptFlag: PBoolean;
+                     TimeOut: Integer; var wsaError : Integer): Integer;
+    function WaitForData( TimeOut : Integer; pBuf : Pointer; DesiredBytes: Integer;
+                          var wsaError, bytesReady : Integer): TWaitForData;
+{$ELSE}
+    FTcpClient: TSocket;
+  protected const
+    SLEEP_TIME = 200;
+{$ENDIF}
+  protected
+    procedure Write( const pBuf : Pointer; offset, count: Integer); override;
+    function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
+    procedure Open; override;
+    procedure Close; override;
+    procedure Flush; override;
+
+    function IsOpen: Boolean; override;
+    function ToArray: TBytes; override;
+  public
+{$IFDEF OLD_SOCKETS}
+    constructor Create( const ATcpClient: TCustomIpClient; const aTimeout : Integer = 0);
+{$ELSE}
+    constructor Create( const ATcpClient: TSocket; const aTimeout : Longword = 0);
+{$ENDIF}
+  end;
+
+  IStreamTransport = interface( ITransport )
+    ['{A8479B47-2A3E-4421-A9A0-D5A9EDCC634A}']
+    function GetInputStream: IThriftStream;
+    function GetOutputStream: IThriftStream;
+    property InputStream : IThriftStream read GetInputStream;
+    property OutputStream : IThriftStream read GetOutputStream;
+  end;
+
+  TStreamTransportImpl = class( TTransportImpl, IStreamTransport)
+  protected
+    FInputStream : IThriftStream;
+    FOutputStream : IThriftStream;
+  protected
+    function GetIsOpen: Boolean; override;
+
+    function GetInputStream: IThriftStream;
+    function GetOutputStream: IThriftStream;
+  public
+    property InputStream : IThriftStream read GetInputStream;
+    property OutputStream : IThriftStream read GetOutputStream;
+
+    procedure Open; override;
+    procedure Close; override;
+    procedure Flush; override;
+    function  Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
+    procedure Write( const pBuf : Pointer; off, len : Integer); override;
+    constructor Create( const AInputStream : IThriftStream; const AOutputStream : IThriftStream);
+    destructor Destroy; override;
+  end;
+
+  TBufferedStreamImpl = class( TThriftStreamImpl)
+  private
+    FStream : IThriftStream;
+    FBufSize : Integer;
+    FReadBuffer : TMemoryStream;
+    FWriteBuffer : TMemoryStream;
+  protected
+    procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
+    function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
+    procedure Open;  override;
+    procedure Close; override;
+    procedure Flush; override;
+    function IsOpen: Boolean; override;
+    function ToArray: TBytes; override;
+  public
+    constructor Create( const AStream: IThriftStream; ABufSize: Integer);
+    destructor Destroy; override;
+  end;
+
+  TServerSocketImpl = class( TServerTransportImpl)
+  private
+{$IFDEF OLD_SOCKETS}
+    FServer : TTcpServer;
+    FPort : Integer;
+    FClientTimeout : Integer;
+{$ELSE}
+    FServer: TServerSocket;
+{$ENDIF}
+    FUseBufferedSocket : Boolean;
+    FOwnsServer : Boolean;
+  protected
+    function Accept( const fnAccepting: TProc) : ITransport; override;
+  public
+{$IFDEF OLD_SOCKETS}
+    constructor Create( const AServer: TTcpServer; AClientTimeout: Integer = 0); overload;
+    constructor Create( APort: Integer; AClientTimeout: Integer = 0; AUseBufferedSockets: Boolean = FALSE); overload;
+{$ELSE}
+    constructor Create( const AServer: TServerSocket; AClientTimeout: Longword = 0); overload;
+    constructor Create( APort: Integer; AClientTimeout: Longword = 0; AUseBufferedSockets: Boolean = FALSE); overload;
+{$ENDIF}
+    destructor Destroy; override;
+    procedure Listen; override;
+    procedure Close; override;
+  end;
+
+  TBufferedTransportImpl = class( TTransportImpl )
+  private
+    FInputBuffer : IThriftStream;
+    FOutputBuffer : IThriftStream;
+    FTransport : IStreamTransport;
+    FBufSize : Integer;
+
+    procedure InitBuffers;
+    function GetUnderlyingTransport: ITransport;
+  protected
+    function GetIsOpen: Boolean; override;
+    procedure Flush; override;
+  public
+    procedure Open(); override;
+    procedure Close(); override;
+    function  Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
+    procedure Write( const pBuf : Pointer; off, len : Integer); override;
+    constructor Create( const ATransport : IStreamTransport ); overload;
+    constructor Create( const ATransport : IStreamTransport; ABufSize: Integer); overload;
+    property UnderlyingTransport: ITransport read GetUnderlyingTransport;
+    property IsOpen: Boolean read GetIsOpen;
+  end;
+
+  TSocketImpl = class(TStreamTransportImpl)
+  private
+{$IFDEF OLD_SOCKETS}
+    FClient : TCustomIpClient;
+{$ELSE}
+    FClient: TSocket;
+{$ENDIF}
+    FOwnsClient : Boolean;
+    FHost : string;
+    FPort : Integer;
+{$IFDEF OLD_SOCKETS}
+    FTimeout : Integer;
+{$ELSE}
+    FTimeout : Longword;
+{$ENDIF}
+
+    procedure InitSocket;
+  protected
+    function GetIsOpen: Boolean; override;
+  public
+    procedure Open; override;
+{$IFDEF OLD_SOCKETS}
+    constructor Create( const AClient : TCustomIpClient; aOwnsClient : Boolean; ATimeout: Integer = 0); overload;
+    constructor Create( const AHost: string; APort: Integer; ATimeout: Integer = 0); overload;
+{$ELSE}
+    constructor Create(const AClient: TSocket; aOwnsClient: Boolean); overload;
+    constructor Create( const AHost: string; APort: Integer; ATimeout: Longword = 0); overload;
+{$ENDIF}
+    destructor Destroy; override;
+    procedure Close; override;
+{$IFDEF OLD_SOCKETS}
+    property TcpClient: TCustomIpClient read FClient;
+{$ELSE}
+    property TcpClient: TSocket read FClient;
+{$ENDIF}
+    property Host : string read FHost;
+    property Port: Integer read FPort;
+  end;
+
+  TFramedTransportImpl = class( TTransportImpl)
+  private const
+    FHeaderSize : Integer = 4;
+  private class var
+    FHeader_Dummy : array of Byte;
+  protected
+    FTransport : ITransport;
+    FWriteBuffer : TMemoryStream;
+    FReadBuffer : TMemoryStream;
+
+    procedure InitWriteBuffer;
+    procedure ReadFrame;
+  public
+    type
+      TFactory = class( TTransportFactoryImpl )
+      public
+        function GetTransport( const ATrans: ITransport): ITransport; override;
+      end;
+
+    {$IFDEF HAVE_CLASS_CTOR}
+    class constructor Create;
+    {$ENDIF}
+
+    constructor Create; overload;
+    constructor Create( const ATrans: ITransport); overload;
+    destructor Destroy; override;
+
+    procedure Open(); override;
+    function GetIsOpen: Boolean; override;
+
+    procedure Close(); override;
+    function  Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
+    procedure Write( const pBuf : Pointer; off, len : Integer); override;
+    procedure Flush; override;
+  end;
+
+{$IFNDEF HAVE_CLASS_CTOR}
+procedure TFramedTransportImpl_Initialize;
+{$ENDIF}
+
+const
+  DEFAULT_THRIFT_TIMEOUT = 5 * 1000; // ms
+
+
+implementation
+
+{ TTransportImpl }
+
+procedure TTransportImpl.Flush;
+begin
+  // nothing to do
+end;
+
+function TTransportImpl.Peek: Boolean;
+begin
+  Result := IsOpen;
+end;
+
+function TTransportImpl.Read(var buf: TBytes; off: Integer; len: Integer): Integer;
+begin
+  if Length(buf) > 0
+  then result := Read( @buf[0], Length(buf), off, len)
+  else result := 0;
+end;
+
+function TTransportImpl.ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer;
+begin
+  if Length(buf) > 0
+  then result := ReadAll( @buf[0], Length(buf), off, len)
+  else result := 0;
+end;
+
+procedure TTransportImpl.Write( const buf: TBytes);
+begin
+  if Length(buf) > 0
+  then Write( @buf[0], 0, Length(buf));
+end;
+
+procedure TTransportImpl.Write( const buf: TBytes; off: Integer; len: Integer);
+begin
+  if Length(buf) > 0
+  then Write( @buf[0], off, len);
+end;
+
+function TTransportImpl.ReadAll(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
+var ret : Integer;
+begin
+  result := 0;
+  while result < len do begin
+    ret := Read( pBuf, buflen, off + result, len - result);
+    if ret > 0
+    then Inc( result, ret)
+    else raise TTransportExceptionNotOpen.Create( 'Cannot read, Remote side has closed' );
+  end;
+end;
+
+procedure TTransportImpl.Write( const pBuf : Pointer; len : Integer);
+begin
+  Self.Write( pBuf, 0, len);
+end;
+
+{ THTTPClientImpl }
+
+constructor THTTPClientImpl.Create(const AUri: string);
+begin
+  inherited Create;
+  FUri := AUri;
+
+  // defaults according to MSDN
+  FDnsResolveTimeout := 0; // no timeout
+  FConnectionTimeout := 60 * 1000;
+  FSendTimeout       := 30 * 1000;
+  FReadTimeout       := 30 * 1000;
+
+  FCustomHeaders := TThriftDictionaryImpl<string,string>.Create;
+  FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
+end;
+
+function THTTPClientImpl.CreateRequest: IXMLHTTPRequest;
+var
+  pair : TPair<string,string>;
+  srvHttp : IServerXMLHTTPRequest;
+begin
+  {$IF CompilerVersion >= 21.0}
+  Result := CoServerXMLHTTP.Create;
+  {$ELSE}
+  Result := CoXMLHTTPRequest.Create;
+  {$IFEND}
+
+  // setting a timeout value to 0 (zero) means "no timeout" for that setting
+  if Supports( result, IServerXMLHTTPRequest, srvHttp)
+  then srvHttp.setTimeouts( DnsResolveTimeout, ConnectionTimeout, SendTimeout, ReadTimeout);
+
+  Result.open('POST', FUri, False, '', '');
+  Result.setRequestHeader( 'Content-Type', 'application/x-thrift');
+  Result.setRequestHeader( 'Accept', 'application/x-thrift');
+  Result.setRequestHeader( 'User-Agent', 'Delphi/IHTTPClient');
+
+  for pair in FCustomHeaders do begin
+    Result.setRequestHeader( pair.Key, pair.Value );
+  end;
+end;
+
+destructor THTTPClientImpl.Destroy;
+begin
+  Close;
+  inherited;
+end;
+
+function THTTPClientImpl.GetDnsResolveTimeout: Integer;
+begin
+  Result := FDnsResolveTimeout;
+end;
+
+procedure THTTPClientImpl.SetDnsResolveTimeout(const Value: Integer);
+begin
+  FDnsResolveTimeout := Value;
+end;
+
+function THTTPClientImpl.GetConnectionTimeout: Integer;
+begin
+  Result := FConnectionTimeout;
+end;
+
+procedure THTTPClientImpl.SetConnectionTimeout(const Value: Integer);
+begin
+  FConnectionTimeout := Value;
+end;
+
+function THTTPClientImpl.GetSendTimeout: Integer;
+begin
+  Result := FSendTimeout;
+end;
+
+procedure THTTPClientImpl.SetSendTimeout(const Value: Integer);
+begin
+  FSendTimeout := Value;
+end;
+
+function THTTPClientImpl.GetReadTimeout: Integer;
+begin
+  Result := FReadTimeout;
+end;
+
+procedure THTTPClientImpl.SetReadTimeout(const Value: Integer);
+begin
+  FReadTimeout := Value;
+end;
+
+function THTTPClientImpl.GetCustomHeaders: IThriftDictionary<string,string>;
+begin
+  Result := FCustomHeaders;
+end;
+
+function THTTPClientImpl.GetIsOpen: Boolean;
+begin
+  Result := True;
+end;
+
+procedure THTTPClientImpl.Open;
+begin
+  FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
+end;
+
+procedure THTTPClientImpl.Close;
+begin
+  FInputStream := nil;
+  FOutputStream := nil;
+end;
+
+procedure THTTPClientImpl.Flush;
+begin
+  try
+    SendRequest;
+  finally
+    FOutputStream := nil;
+    FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
+    ASSERT( FOutputStream <> nil);
+  end;
+end;
+
+function THTTPClientImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
+begin
+  if FInputStream = nil then begin
+    raise TTransportExceptionNotOpen.Create('No request has been sent');
+  end;
+
+  try
+    Result := FInputStream.Read( pBuf, buflen, off, len)
+  except
+    on E: Exception
+    do raise TTransportExceptionUnknown.Create(E.Message);
+  end;
+end;
+
+procedure THTTPClientImpl.SendRequest;
+var
+  xmlhttp : IXMLHTTPRequest;
+  ms : TMemoryStream;
+  a : TBytes;
+  len : Integer;
+begin
+  xmlhttp := CreateRequest;
+
+  ms := TMemoryStream.Create;
+  try
+    a := FOutputStream.ToArray;
+    len := Length(a);
+    if len > 0 then begin
+      ms.WriteBuffer( Pointer(@a[0])^, len);
+    end;
+    ms.Position := 0;
+    xmlhttp.send( IUnknown( TStreamAdapter.Create( ms, soReference )));
+    FInputStream := nil;
+    FInputStream := TThriftStreamAdapterCOM.Create( IUnknown( xmlhttp.responseStream) as IStream);
+  finally
+    ms.Free;
+  end;
+end;
+
+procedure THTTPClientImpl.Write( const pBuf : Pointer; off, len : Integer);
+begin
+  FOutputStream.Write( pBuf, off, len);
+end;
+
+{ TTransportException }
+
+function TTransportException.GetType: TExceptionType;
+begin
+  if Self is TTransportExceptionNotOpen then Result := TExceptionType.NotOpen
+  else if Self is TTransportExceptionAlreadyOpen then Result := TExceptionType.AlreadyOpen
+  else if Self is TTransportExceptionTimedOut then Result := TExceptionType.TimedOut
+  else if Self is TTransportExceptionEndOfFile then Result := TExceptionType.EndOfFile
+  else if Self is TTransportExceptionBadArgs then Result := TExceptionType.BadArgs
+  else if Self is TTransportExceptionInterrupted then Result := TExceptionType.Interrupted
+  else Result := TExceptionType.Unknown;
+end;
+
+constructor TTransportException.HiddenCreate(const Msg: string);
+begin
+  inherited Create(Msg);
+end;
+
+class function TTransportException.Create(AType: TExceptionType): TTransportException;
+begin
+  //no inherited;
+{$WARN SYMBOL_DEPRECATED OFF}
+  Result := Create(AType, '')
+{$WARN SYMBOL_DEPRECATED DEFAULT}
+end;
+
+class function TTransportException.Create(AType: TExceptionType;
+  const msg: string): TTransportException;
+begin
+  case AType of
+    TExceptionType.NotOpen:     Result := TTransportExceptionNotOpen.Create(msg);
+    TExceptionType.AlreadyOpen: Result := TTransportExceptionAlreadyOpen.Create(msg);
+    TExceptionType.TimedOut:    Result := TTransportExceptionTimedOut.Create(msg);
+    TExceptionType.EndOfFile:   Result := TTransportExceptionEndOfFile.Create(msg);
+    TExceptionType.BadArgs:     Result := TTransportExceptionBadArgs.Create(msg);
+    TExceptionType.Interrupted: Result := TTransportExceptionInterrupted.Create(msg);
+  else
+    Result := TTransportExceptionUnknown.Create(msg);
+  end;
+end;
+
+class function TTransportException.Create(const msg: string): TTransportException;
+begin
+  Result := TTransportExceptionUnknown.Create(Msg);
+end;
+
+{ TTransportExceptionSpecialized }
+
+constructor TTransportExceptionSpecialized.Create(const Msg: string);
+begin
+  inherited HiddenCreate(Msg);
+end;
+
+{ TTransportFactoryImpl }
+
+function TTransportFactoryImpl.GetTransport( const ATrans: ITransport): ITransport;
+begin
+  Result := ATrans;
+end;
+
+{ TServerSocket }
+
+{$IFDEF OLD_SOCKETS}
+constructor TServerSocketImpl.Create( const AServer: TTcpServer; AClientTimeout: Integer);
+begin
+  inherited Create;
+  FServer := AServer;
+  FClientTimeout := AClientTimeout;
+end;
+{$ELSE}
+constructor TServerSocketImpl.Create( const AServer: TServerSocket; AClientTimeout: Longword);
+begin
+  inherited Create;
+  FServer := AServer;
+  FServer.RecvTimeout := AClientTimeout;
+  FServer.SendTimeout := AClientTimeout;
+end;
+{$ENDIF}
+
+{$IFDEF OLD_SOCKETS}
+constructor TServerSocketImpl.Create(APort, AClientTimeout: Integer; AUseBufferedSockets: Boolean);
+{$ELSE}
+constructor TServerSocketImpl.Create(APort: Integer; AClientTimeout: Longword; AUseBufferedSockets: Boolean);
+{$ENDIF}
+begin
+  inherited Create;
+{$IFDEF OLD_SOCKETS}
+  FPort := APort;
+  FClientTimeout := AClientTimeout;
+  FServer := TTcpServer.Create( nil );
+  FServer.BlockMode := bmBlocking;
+  {$IF CompilerVersion >= 21.0}
+  FServer.LocalPort := AnsiString( IntToStr( FPort));
+  {$ELSE}
+  FServer.LocalPort := IntToStr( FPort);
+  {$IFEND}
+{$ELSE}
+  FServer := TServerSocket.Create(APort, AClientTimeout, AClientTimeout);
+{$ENDIF}
+  FUseBufferedSocket := AUseBufferedSockets;
+  FOwnsServer := True;
+end;
+
+destructor TServerSocketImpl.Destroy;
+begin
+  if FOwnsServer then begin
+    FServer.Free;
+    FServer := nil;
+  end;
+  inherited;
+end;
+
+function TServerSocketImpl.Accept( const fnAccepting: TProc): ITransport;
+var
+{$IFDEF OLD_SOCKETS}
+  client : TCustomIpClient;
+{$ELSE}
+  client: TSocket;
+{$ENDIF}
+  trans  : IStreamTransport;
+begin
+  if FServer = nil then begin
+    raise TTransportExceptionNotOpen.Create('No underlying server socket.');
+  end;
+
+{$IFDEF OLD_SOCKETS}
+  client := nil;
+  try
+    client := TCustomIpClient.Create(nil);
+
+    if Assigned(fnAccepting)
+    then fnAccepting();
+
+    if not FServer.Accept( client) then begin
+      client.Free;
+      Result := nil;
+      Exit;
+    end;
+
+    if client = nil then begin
+      Result := nil;
+      Exit;
+    end;
+
+    trans := TSocketImpl.Create( client, TRUE, FClientTimeout);
+    client := nil;  // trans owns it now
+
+    if FUseBufferedSocket
+    then result := TBufferedTransportImpl.Create( trans)
+    else result := trans;
+
+  except
+    on E: Exception do begin
+      client.Free;
+      raise TTransportExceptionUnknown.Create(E.ToString);
+    end;
+  end;
+{$ELSE}
+  if Assigned(fnAccepting) then
+    fnAccepting();
+
+  client := FServer.Accept;
+  try
+    trans := TSocketImpl.Create(client, True);
+    client := nil;
+
+    if FUseBufferedSocket then
+      Result := TBufferedTransportImpl.Create(trans)
+    else
+      Result := trans;
+  except
+    client.Free;
+    raise;
+  end;
+{$ENDIF}
+end;
+
+procedure TServerSocketImpl.Listen;
+begin
+  if FServer <> nil then
+  begin
+{$IFDEF OLD_SOCKETS}
+    try
+      FServer.Active := True;
+    except
+      on E: Exception
+      do raise TTransportExceptionUnknown.Create('Could not accept on listening socket: ' + E.Message);
+    end;
+{$ELSE}
+    FServer.Listen;
+{$ENDIF}
+  end;
+end;
+
+procedure TServerSocketImpl.Close;
+begin
+  if FServer <> nil then
+{$IFDEF OLD_SOCKETS}
+    try
+      FServer.Active := False;
+    except
+      on E: Exception
+      do raise TTransportExceptionUnknown.Create('Error on closing socket : ' + E.Message);
+    end;
+{$ELSE}
+    FServer.Close;
+{$ENDIF}
+end;
+
+{ TSocket }
+
+{$IFDEF OLD_SOCKETS}
+constructor TSocketImpl.Create( const AClient : TCustomIpClient; aOwnsClient : Boolean; ATimeout: Integer = 0);
+var stream : IThriftStream;
+begin
+  FClient := AClient;
+  FTimeout := ATimeout;
+  FOwnsClient := aOwnsClient;
+  stream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
+  inherited Create( stream, stream);
+end;
+{$ELSE}
+constructor TSocketImpl.Create(const AClient: TSocket; aOwnsClient: Boolean);
+var stream : IThriftStream;
+begin
+  FClient := AClient;
+  FTimeout := AClient.RecvTimeout;
+  FOwnsClient := aOwnsClient;
+  stream := TTcpSocketStreamImpl.Create(FClient, FTimeout);
+  inherited Create(stream, stream);
+end;
+{$ENDIF}
+
+{$IFDEF OLD_SOCKETS}
+constructor TSocketImpl.Create(const AHost: string; APort, ATimeout: Integer);
+{$ELSE}
+constructor TSocketImpl.Create(const AHost: string; APort: Integer; ATimeout: Longword);
+{$ENDIF}
+begin
+  inherited Create(nil,nil);
+  FHost := AHost;
+  FPort := APort;
+  FTimeout := ATimeout;
+  InitSocket;
+end;
+
+destructor TSocketImpl.Destroy;
+begin
+  if FOwnsClient
+  then FreeAndNil( FClient);
+  inherited;
+end;
+
+procedure TSocketImpl.Close;
+begin
+  inherited Close;
+
+  FInputStream := nil;
+  FOutputStream := nil;
+
+  if FOwnsClient
+  then FreeAndNil( FClient)
+  else FClient := nil;
+end;
+
+function TSocketImpl.GetIsOpen: Boolean;
+begin
+{$IFDEF OLD_SOCKETS}
+  Result := (FClient <> nil) and FClient.Connected;
+{$ELSE}
+  Result := (FClient <> nil) and FClient.IsOpen
+{$ENDIF}
+end;
+
+procedure TSocketImpl.InitSocket;
+var
+  stream : IThriftStream;
+begin
+  if FOwnsClient
+  then FreeAndNil( FClient)
+  else FClient := nil;
+
+{$IFDEF OLD_SOCKETS}
+  FClient := TTcpClient.Create( nil);
+{$ELSE}
+  FClient := TSocket.Create(FHost, FPort);
+{$ENDIF}
+  FOwnsClient := True;
+
+  stream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
+  FInputStream := stream;
+  FOutputStream := stream;
+end;
+
+procedure TSocketImpl.Open;
+begin
+  if IsOpen then begin
+    raise TTransportExceptionAlreadyOpen.Create('Socket already connected');
+  end;
+
+  if FHost = '' then begin
+    raise TTransportExceptionNotOpen.Create('Cannot open null host');
+  end;
+
+  if Port <= 0 then begin
+    raise TTransportExceptionNotOpen.Create('Cannot open without port');
+  end;
+
+  if FClient = nil
+  then InitSocket;
+
+{$IFDEF OLD_SOCKETS}
+  FClient.RemoteHost := TSocketHost( Host);
+  FClient.RemotePort := TSocketPort( IntToStr( Port));
+  FClient.Connect;
+{$ELSE}
+  FClient.Open;
+{$ENDIF}
+
+  FInputStream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
+  FOutputStream := FInputStream;
+end;
+
+{ TBufferedStream }
+
+procedure TBufferedStreamImpl.Close;
+begin
+  Flush;
+  FStream := nil;
+
+  FReadBuffer.Free;
+  FReadBuffer := nil;
+
+  FWriteBuffer.Free;
+  FWriteBuffer := nil;
+end;
+
+constructor TBufferedStreamImpl.Create( const AStream: IThriftStream; ABufSize: Integer);
+begin
+  inherited Create;
+  FStream := AStream;
+  FBufSize := ABufSize;
+  FReadBuffer := TMemoryStream.Create;
+  FWriteBuffer := TMemoryStream.Create;
+end;
+
+destructor TBufferedStreamImpl.Destroy;
+begin
+  Close;
+  inherited;
+end;
+
+procedure TBufferedStreamImpl.Flush;
+var
+  buf : TBytes;
+  len : Integer;
+begin
+  if IsOpen then begin
+    len := FWriteBuffer.Size;
+    if len > 0 then begin
+      SetLength( buf, len );
+      FWriteBuffer.Position := 0;
+      FWriteBuffer.Read( Pointer(@buf[0])^, len );
+      FStream.Write( buf, 0, len );
+    end;
+    FWriteBuffer.Clear;
+  end;
+end;
+
+function TBufferedStreamImpl.IsOpen: Boolean;
+begin
+  Result := (FWriteBuffer <> nil)
+        and (FReadBuffer <> nil)
+        and (FStream <> nil)
+        and FStream.IsOpen;
+end;
+
+procedure TBufferedStreamImpl.Open;
+begin
+  FStream.Open;
+end;
+
+function TBufferedStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
+var
+  nRead : Integer;
+  tempbuf : TBytes;
+  pTmp : PByte;
+begin
+  inherited;
+  Result := 0;
+
+  if IsOpen then begin
+    while count > 0 do begin
+
+      if FReadBuffer.Position >= FReadBuffer.Size then begin
+        FReadBuffer.Clear;
+        SetLength( tempbuf, FBufSize);
+        nRead := FStream.Read( tempbuf, 0, FBufSize );
+        if nRead = 0 then Break; // avoid infinite loop
+
+        FReadBuffer.WriteBuffer( Pointer(@tempbuf[0])^, nRead );
+        FReadBuffer.Position := 0;
+      end;
+
+      if FReadBuffer.Position < FReadBuffer.Size then begin
+        nRead := Min( FReadBuffer.Size - FReadBuffer.Position, count);
+        pTmp  := pBuf;
+        Inc( pTmp, offset);
+        Inc( Result, FReadBuffer.Read( pTmp^, nRead));
+        Dec( count, nRead);
+        Inc( offset, nRead);
+      end;
+    end;
+  end;
+end;
+
+function TBufferedStreamImpl.ToArray: TBytes;
+var len : Integer;
+begin
+  len := 0;
+
+  if IsOpen then begin
+    len := FReadBuffer.Size;
+  end;
+
+  SetLength( Result, len);
+
+  if len > 0 then begin
+    FReadBuffer.Position := 0;
+    FReadBuffer.Read( Pointer(@Result[0])^, len );
+  end;
+end;
+
+procedure TBufferedStreamImpl.Write( const pBuf : Pointer; offset: Integer; count: Integer);
+var pTmp : PByte;
+begin
+  inherited;
+  if count > 0 then begin
+    if IsOpen then begin
+      pTmp := pBuf;
+      Inc( pTmp, offset);
+      FWriteBuffer.Write( pTmp^, count );
+      if FWriteBuffer.Size > FBufSize then begin
+        Flush;
+      end;
+    end;
+  end;
+end;
+
+{ TStreamTransportImpl }
+
+constructor TStreamTransportImpl.Create( const AInputStream : IThriftStream; const AOutputStream : IThriftStream);
+begin
+  inherited Create;
+  FInputStream := AInputStream;
+  FOutputStream := AOutputStream;
+end;
+
+destructor TStreamTransportImpl.Destroy;
+begin
+  FInputStream := nil;
+  FOutputStream := nil;
+  inherited;
+end;
+
+procedure TStreamTransportImpl.Close;
+begin
+  FInputStream := nil;
+  FOutputStream := nil;
+end;
+
+procedure TStreamTransportImpl.Flush;
+begin
+  if FOutputStream = nil then begin
+    raise TTransportExceptionNotOpen.Create('Cannot flush null outputstream' );
+  end;
+
+  FOutputStream.Flush;
+end;
+
+function TStreamTransportImpl.GetInputStream: IThriftStream;
+begin
+  Result := FInputStream;
+end;
+
+function TStreamTransportImpl.GetIsOpen: Boolean;
+begin
+  Result := True;
+end;
+
+function TStreamTransportImpl.GetOutputStream: IThriftStream;
+begin
+  Result := FOutputStream;
+end;
+
+procedure TStreamTransportImpl.Open;
+begin
+
+end;
+
+function TStreamTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
+begin
+  if FInputStream = nil then begin
+    raise TTransportExceptionNotOpen.Create('Cannot read from null inputstream' );
+  end;
+
+  Result := FInputStream.Read( pBuf,buflen, off, len );
+end;
+
+procedure TStreamTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
+begin
+  if FOutputStream = nil then begin
+    raise TTransportExceptionNotOpen.Create('Cannot write to null outputstream' );
+  end;
+
+  FOutputStream.Write( pBuf, off, len );
+end;
+
+{ TBufferedTransportImpl }
+
+constructor TBufferedTransportImpl.Create( const ATransport: IStreamTransport);
+begin
+  //no inherited;
+  Create( ATransport, 1024 );
+end;
+
+constructor TBufferedTransportImpl.Create( const ATransport: IStreamTransport;  ABufSize: Integer);
+begin
+  inherited Create;
+  FTransport := ATransport;
+  FBufSize := ABufSize;
+  InitBuffers;
+end;
+
+procedure TBufferedTransportImpl.Close;
+begin
+  FTransport.Close;
+  FInputBuffer := nil;
+  FOutputBuffer := nil;  
+end;
+
+procedure TBufferedTransportImpl.Flush;
+begin
+  if FOutputBuffer <> nil then begin
+    FOutputBuffer.Flush;
+  end;
+end;
+
+function TBufferedTransportImpl.GetIsOpen: Boolean;
+begin
+  Result := FTransport.IsOpen;
+end;
+
+function TBufferedTransportImpl.GetUnderlyingTransport: ITransport;
+begin
+  Result := FTransport;
+end;
+
+procedure TBufferedTransportImpl.InitBuffers;
+begin
+  if FTransport.InputStream <> nil then begin
+    FInputBuffer := TBufferedStreamImpl.Create( FTransport.InputStream, FBufSize );
+  end;
+  if FTransport.OutputStream <> nil then begin
+    FOutputBuffer := TBufferedStreamImpl.Create( FTransport.OutputStream, FBufSize );
+  end;
+end;
+
+procedure TBufferedTransportImpl.Open;
+begin
+  FTransport.Open;
+  InitBuffers;  // we need to get the buffers to match FTransport substreams again
+end;
+
+function TBufferedTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
+begin
+  Result := 0;
+  if FInputBuffer <> nil then begin
+    Result := FInputBuffer.Read( pBuf,buflen, off, len );
+  end;
+end;
+
+procedure TBufferedTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
+begin
+  if FOutputBuffer <> nil then begin
+    FOutputBuffer.Write( pBuf, off, len );
+  end;
+end;
+
+{ TFramedTransportImpl }
+
+{$IFDEF HAVE_CLASS_CTOR}
+class constructor TFramedTransportImpl.Create;
+begin
+  SetLength( FHeader_Dummy, FHeaderSize);
+  FillChar( FHeader_Dummy[0], Length( FHeader_Dummy) * SizeOf( Byte ), 0);
+end;
+{$ELSE}
+procedure TFramedTransportImpl_Initialize;
+begin
+  SetLength( TFramedTransportImpl.FHeader_Dummy, TFramedTransportImpl.FHeaderSize);
+  FillChar( TFramedTransportImpl.FHeader_Dummy[0],
+    Length( TFramedTransportImpl.FHeader_Dummy) * SizeOf( Byte ), 0);
+end;
+{$ENDIF}
+
+constructor TFramedTransportImpl.Create;
+begin
+  inherited Create;
+  InitWriteBuffer;
+end;
+
+procedure TFramedTransportImpl.Close;
+begin
+  FTransport.Close;
+end;
+
+constructor TFramedTransportImpl.Create( const ATrans: ITransport);
+begin
+  inherited Create;
+  InitWriteBuffer;
+  FTransport := ATrans;
+end;
+
+destructor TFramedTransportImpl.Destroy;
+begin
+  FWriteBuffer.Free;
+  FReadBuffer.Free;
+  inherited;
+end;
+
+procedure TFramedTransportImpl.Flush;
+var
+  buf : TBytes;
+  len : Integer;
+  data_len : Integer;
+
+begin
+  len := FWriteBuffer.Size;
+  SetLength( buf, len);
+  if len > 0 then begin
+    System.Move( FWriteBuffer.Memory^, buf[0], len );
+  end;
+
+  data_len := len - FHeaderSize;
+  if (data_len < 0) then begin
+    raise TTransportExceptionUnknown.Create('TFramedTransport.Flush: data_len < 0' );
+  end;
+
+  InitWriteBuffer;
+
+  buf[0] := Byte($FF and (data_len shr 24));
+  buf[1] := Byte($FF and (data_len shr 16));
+  buf[2] := Byte($FF and (data_len shr 8));
+  buf[3] := Byte($FF and data_len);
+
+  FTransport.Write( buf, 0, len );
+  FTransport.Flush;
+end;
+
+function TFramedTransportImpl.GetIsOpen: Boolean;
+begin
+  Result := FTransport.IsOpen;
+end;
+
+type
+  TAccessMemoryStream = class(TMemoryStream)
+  end;
+
+procedure TFramedTransportImpl.InitWriteBuffer;
+begin
+  FWriteBuffer.Free;
+  FWriteBuffer := TMemoryStream.Create;
+  TAccessMemoryStream(FWriteBuffer).Capacity := 1024;
+  FWriteBuffer.Write( Pointer(@FHeader_Dummy[0])^, FHeaderSize);
+end;
+
+procedure TFramedTransportImpl.Open;
+begin
+  FTransport.Open;
+end;
+
+function TFramedTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
+var pTmp : PByte;
+begin
+  if len > (buflen-off)
+  then len := buflen-off;
+
+  pTmp := pBuf;
+  Inc( pTmp, off);
+
+  if (FReadBuffer <> nil) and (len > 0) then begin
+    result := FReadBuffer.Read( pTmp^, len);
+    if result > 0 then begin
+      Exit;
+    end;
+  end;
+
+  ReadFrame;
+  if len > 0
+  then Result := FReadBuffer.Read( pTmp^, len)
+  else Result := 0;
+end;
+
+procedure TFramedTransportImpl.ReadFrame;
+var
+  i32rd : TBytes;
+  size : Integer;
+  buff : TBytes;
+begin
+  SetLength( i32rd, FHeaderSize );
+  FTransport.ReadAll( i32rd, 0, FHeaderSize);
+  size :=
+    ((i32rd[0] and $FF) shl 24) or
+    ((i32rd[1] and $FF) shl 16) or
+    ((i32rd[2] and $FF) shl 8) or
+     (i32rd[3] and $FF);
+  SetLength( buff, size );
+  FTransport.ReadAll( buff, 0, size );
+  FReadBuffer.Free;
+  FReadBuffer := TMemoryStream.Create;
+  if Length(buff) > 0
+  then FReadBuffer.Write( Pointer(@buff[0])^, size );
+  FReadBuffer.Position := 0;
+end;
+
+procedure TFramedTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
+var pTmp : PByte;
+begin
+  if len > 0 then begin
+    pTmp := pBuf;
+    Inc( pTmp, off);
+
+    FWriteBuffer.Write( pTmp^, len );
+  end;
+end;
+
+{ TFramedTransport.TFactory }
+
+function TFramedTransportImpl.TFactory.GetTransport( const ATrans: ITransport): ITransport;
+begin
+  Result := TFramedTransportImpl.Create( ATrans );
+end;
+
+{ TTcpSocketStreamImpl }
+
+procedure TTcpSocketStreamImpl.Close;
+begin
+  FTcpClient.Close;
+end;
+
+{$IFDEF OLD_SOCKETS}
+constructor TTcpSocketStreamImpl.Create( const ATcpClient: TCustomIpClient; const aTimeout : Integer);
+begin
+  inherited Create;
+  FTcpClient := ATcpClient;
+  FTimeout := aTimeout;
+end;
+{$ELSE}
+constructor TTcpSocketStreamImpl.Create( const ATcpClient: TSocket; const aTimeout : Longword);
+begin
+  inherited Create;
+  FTcpClient := ATcpClient;
+  if aTimeout = 0 then
+    FTcpClient.RecvTimeout := SLEEP_TIME
+  else
+    FTcpClient.RecvTimeout := aTimeout;
+  FTcpClient.SendTimeout := aTimeout;
+end;
+{$ENDIF}
+
+procedure TTcpSocketStreamImpl.Flush;
+begin
+
+end;
+
+function TTcpSocketStreamImpl.IsOpen: Boolean;
+begin
+{$IFDEF OLD_SOCKETS}
+  Result := FTcpClient.Active;
+{$ELSE}
+  Result := FTcpClient.IsOpen;
+{$ENDIF}
+end;
+
+procedure TTcpSocketStreamImpl.Open;
+begin
+  FTcpClient.Open;
+end;
+
+
+{$IFDEF OLD_SOCKETS}
+function TTcpSocketStreamImpl.Select( ReadReady, WriteReady, ExceptFlag: PBoolean;
+                                      TimeOut: Integer; var wsaError : Integer): Integer;
+var
+  ReadFds: TFDset;
+  ReadFdsptr: PFDset;
+  WriteFds: TFDset;
+  WriteFdsptr: PFDset;
+  ExceptFds: TFDset;
+  ExceptFdsptr: PFDset;
+  tv: timeval;
+  Timeptr: PTimeval;
+  socket : TSocket;
+begin
+  if not FTcpClient.Active then begin
+    wsaError := WSAEINVAL;
+    Exit( SOCKET_ERROR);
+  end;
+
+  socket := FTcpClient.Handle;
+
+  if Assigned(ReadReady) then begin
+    ReadFdsptr := @ReadFds;
+    FD_ZERO(ReadFds);
+    FD_SET(socket, ReadFds);
+  end
+  else begin
+    ReadFdsptr := nil;
+  end;
+
+  if Assigned(WriteReady) then begin
+    WriteFdsptr := @WriteFds;
+    FD_ZERO(WriteFds);
+    FD_SET(socket, WriteFds);
+  end
+  else begin
+    WriteFdsptr := nil;
+  end;
+
+  if Assigned(ExceptFlag) then begin
+    ExceptFdsptr := @ExceptFds;
+    FD_ZERO(ExceptFds);
+    FD_SET(socket, ExceptFds);
+  end
+  else begin
+    ExceptFdsptr := nil;
+  end;
+
+  if TimeOut >= 0 then begin
+    tv.tv_sec := TimeOut div 1000;
+    tv.tv_usec :=  1000 * (TimeOut mod 1000);
+    Timeptr := @tv;
+  end
+  else begin
+    Timeptr := nil;  // wait forever
+  end;
+
+  wsaError := 0;
+  try
+    {$IFDEF MSWINDOWS}
+      {$IFDEF OLD_UNIT_NAMES}
+      result := WinSock.select(        socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
+      {$ELSE}
+      result := Winapi.WinSock.select( socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
+      {$ENDIF}
+    {$ENDIF}
+    {$IFDEF LINUX}
+      result := Libc.select(           socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
+    {$ENDIF}
+	
+    if result = SOCKET_ERROR
+    then wsaError := WSAGetLastError;
+
+  except
+    result := SOCKET_ERROR;
+  end;
+
+  if Assigned(ReadReady) then
+   ReadReady^ := FD_ISSET(socket, ReadFds);
+   
+  if Assigned(WriteReady) then
+    WriteReady^ := FD_ISSET(socket, WriteFds);
+  
+  if Assigned(ExceptFlag) then
+    ExceptFlag^ := FD_ISSET(socket, ExceptFds);
+end;
+{$ENDIF}
+
+{$IFDEF OLD_SOCKETS}
+function TTcpSocketStreamImpl.WaitForData( TimeOut : Integer; pBuf : Pointer;
+                                           DesiredBytes : Integer;
+                                           var wsaError, bytesReady : Integer): TWaitForData;
+var bCanRead, bError : Boolean;
+    retval : Integer;
+const 
+  MSG_PEEK = {$IFDEF OLD_UNIT_NAMES} WinSock.MSG_PEEK  {$ELSE} Winapi.WinSock.MSG_PEEK  {$ENDIF};
+begin
+  bytesReady := 0;
+
+  // The select function returns the total number of socket handles that are ready
+  // and contained in the fd_set structures, zero if the time limit expired,
+  // or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR,
+  // WSAGetLastError can be used to retrieve a specific error code.
+  retval := Self.Select( @bCanRead, nil, @bError, TimeOut, wsaError);
+  if retval = SOCKET_ERROR
+  then Exit( TWaitForData.wfd_Error);
+  if (retval = 0) or not bCanRead
+  then Exit( TWaitForData.wfd_Timeout);
+
+  // recv() returns the number of bytes received, or -1 if an error occurred.
+  // The return value will be 0 when the peer has performed an orderly shutdown.
+  
+  retval := recv( FTcpClient.Handle, pBuf^, DesiredBytes, MSG_PEEK);
+  if retval <= 0
+  then Exit( TWaitForData.wfd_Error);
+
+  // at least we have some data
+  bytesReady := Min( retval, DesiredBytes);
+  result := TWaitForData.wfd_HaveData;
+end;
+{$ENDIF}
+
+{$IFDEF OLD_SOCKETS}
+function TTcpSocketStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
+// old sockets version
+var wfd : TWaitForData;
+    wsaError,
+    msecs : Integer;
+    nBytes : Integer;
+    pTmp : PByte;
+begin
+  inherited;
+
+  if FTimeout > 0
+  then msecs := FTimeout
+  else msecs := DEFAULT_THRIFT_TIMEOUT;
+
+  result := 0;
+  pTmp   := pBuf;
+  Inc( pTmp, offset);
+  while count > 0 do begin
+
+    while TRUE do begin
+      wfd := WaitForData( msecs, pTmp, count, wsaError, nBytes);
+      case wfd of
+        TWaitForData.wfd_Error    :  Exit;
+        TWaitForData.wfd_HaveData :  Break;
+        TWaitForData.wfd_Timeout  :  begin
+          if (FTimeout = 0)
+          then Exit
+          else begin
+            raise TTransportExceptionTimedOut.Create(SysErrorMessage(Cardinal(wsaError)));
+
+          end;
+        end;
+      else
+        ASSERT( FALSE);
+      end;
+    end;
+
+    // reduce the timeout once we got data
+    if FTimeout > 0
+    then msecs := FTimeout div 10
+    else msecs := DEFAULT_THRIFT_TIMEOUT div 10;
+    msecs := Max( msecs, 200);
+
+    ASSERT( nBytes <= count);
+    nBytes := FTcpClient.ReceiveBuf( pTmp^, nBytes);
+    Inc( pTmp, nBytes);
+    Dec( count, nBytes);
+    Inc( result, nBytes);
+  end;
+end;
+
+function TTcpSocketStreamImpl.ToArray: TBytes;
+// old sockets version
+var len : Integer;
+begin
+  len := 0;
+  if IsOpen then begin
+    len := FTcpClient.BytesReceived;
+  end;
+
+  SetLength( Result, len );
+
+  if len > 0 then begin
+    FTcpClient.ReceiveBuf( Pointer(@Result[0])^, len);
+  end;
+end;
+
+procedure TTcpSocketStreamImpl.Write( const pBuf : Pointer; offset, count: Integer);
+// old sockets version
+var bCanWrite, bError : Boolean;
+    retval, wsaError : Integer;
+    pTmp : PByte;
+begin
+  inherited;
+
+  if not FTcpClient.Active
+  then raise TTransportExceptionNotOpen.Create('not open');
+
+  // The select function returns the total number of socket handles that are ready
+  // and contained in the fd_set structures, zero if the time limit expired,
+  // or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR,
+  // WSAGetLastError can be used to retrieve a specific error code.
+  retval := Self.Select( nil, @bCanWrite, @bError, FTimeOut, wsaError);
+  if retval = SOCKET_ERROR
+  then raise TTransportExceptionUnknown.Create(SysErrorMessage(Cardinal(wsaError)));
+
+  if (retval = 0)
+  then raise TTransportExceptionTimedOut.Create('timed out');
+
+  if bError or not bCanWrite
+  then raise TTransportExceptionUnknown.Create('unknown error');
+
+  pTmp := pBuf;
+  Inc( pTmp, offset);
+  FTcpClient.SendBuf( pTmp^, count);
+end;
+
+{$ELSE}
+
+function TTcpSocketStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
+// new sockets version
+var nBytes : Integer;
+    pTmp : PByte;
+begin
+  inherited;
+
+  result := 0;
+  pTmp   := pBuf;
+  Inc( pTmp, offset);
+  while count > 0 do begin
+    nBytes := FTcpClient.Read( pTmp^, count);
+    if nBytes = 0 then Exit;
+    Inc( pTmp, nBytes);
+    Dec( count, nBytes);
+    Inc( result, nBytes);
+  end;
+end;
+
+function TTcpSocketStreamImpl.ToArray: TBytes;
+// new sockets version
+var len : Integer;
+begin
+  len := 0;
+  try
+    if FTcpClient.Peek then
+      repeat
+        SetLength(Result, Length(Result) + 1024);
+        len := FTcpClient.Read(Result[Length(Result) - 1024], 1024);
+      until len < 1024;
+  except
+    on TTransportException do begin { don't allow default exceptions } end;
+    else raise;
+  end;
+  if len > 0 then
+    SetLength(Result, Length(Result) - 1024 + len);
+end;
+
+procedure TTcpSocketStreamImpl.Write( const pBuf : Pointer; offset, count: Integer);
+// new sockets version
+var pTmp : PByte;
+begin
+  inherited;
+
+  if not FTcpClient.IsOpen
+  then raise TTransportExceptionNotOpen.Create('not open');
+
+  pTmp := pBuf;
+  Inc( pTmp, offset);
+  FTcpClient.Write( pTmp^, count);
+end;
+
+{$ENDIF}
+
+
+{$IF CompilerVersion < 21.0}
+initialization
+begin
+  TFramedTransportImpl_Initialize;
+end;
+{$IFEND}
+
+
+end.
diff --git a/lib/delphi/src/Thrift.TypeRegistry.pas b/lib/delphi/src/Thrift.TypeRegistry.pas
index cc22952..c18e97f 100644
--- a/lib/delphi/src/Thrift.TypeRegistry.pas
+++ b/lib/delphi/src/Thrift.TypeRegistry.pas
@@ -1,95 +1,95 @@
-(*

- * Licensed to the Apache Software Foundation (ASF) under one

- * or more contributor license agreements. See the NOTICE file

- * distributed with this work for additional information

- * regarding copyright ownership. The ASF licenses this file

- * to you under the Apache License, Version 2.0 (the

- * "License"); you may not use this file except in compliance

- * with the License. You may obtain a copy of the License at

- *

- *   http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing,

- * software distributed under the License is distributed on an

- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

- * KIND, either express or implied. See the License for the

- * specific language governing permissions and limitations

- * under the License.

- *)

-

-unit Thrift.TypeRegistry;

-

-interface

-

-uses

-  Generics.Collections, TypInfo,

-  Thrift.Protocol;

-

-type

-  TFactoryMethod<T> = function:T;

-

-  TypeRegistry = class

-  private

-    class var FTypeInfoToFactoryLookup : TDictionary<Pointer, Pointer>;

-  public

-    class constructor Create;

-    class destructor Destroy;

-    class procedure RegisterTypeFactory<F>(const aFactoryMethod: TFactoryMethod<F>);

-    class function  Construct<F>: F;

-    class function  ConstructFromTypeInfo(const aTypeInfo: PTypeInfo): IBase;

-  end;

-

-implementation

-

-

-{ TypeRegistration }

-

-class constructor TypeRegistry.Create;

-begin

-  FTypeInfoToFactoryLookup := TDictionary<Pointer, Pointer>.Create;

-end;

-

-class destructor TypeRegistry.Destroy;

-begin

-  FTypeInfoToFactoryLookup.Free;

-end;

-

-class procedure TypeRegistry.RegisterTypeFactory<F>(const aFactoryMethod: TFactoryMethod<F>);

-var

-  TypeInfo     : Pointer;

-begin

-  TypeInfo := System.TypeInfo(F);

-

-  if (TypeInfo <> nil) and (PTypeInfo(TypeInfo).Kind = tkInterface)

-  then FTypeInfoToFactoryLookup.AddOrSetValue(TypeInfo, @aFactoryMethod);

-end;

-

-class function TypeRegistry.Construct<F>: F;

-var

-  TypeInfo     : PTypeInfo;

-  Factory      : Pointer;

-begin

-  Result := default(F);

-

-  TypeInfo := System.TypeInfo(F);

-

-  if Assigned(TypeInfo) and (TypeInfo.Kind = tkInterface)

-  then begin

-    if FTypeInfoToFactoryLookup.TryGetValue(TypeInfo, Factory)

-    then Result := TFactoryMethod<F>(Factory)();

-  end;

-end;

-

-class function TypeRegistry.ConstructFromTypeInfo(const aTypeInfo: PTypeInfo): IBase;

-var

-  Factory      : Pointer;

-begin

-  Result := nil;

-  if FTypeInfoToFactoryLookup.TryGetValue(aTypeInfo, Factory)

-  then Result := IBase(TFactoryMethod<IBase>(Factory)());

-end;

-

-

-

-

-end.

+(*
+ * 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.
+ *)
+
+unit Thrift.TypeRegistry;
+
+interface
+
+uses
+  Generics.Collections, TypInfo,
+  Thrift.Protocol;
+
+type
+  TFactoryMethod<T> = function:T;
+
+  TypeRegistry = class
+  private
+    class var FTypeInfoToFactoryLookup : TDictionary<Pointer, Pointer>;
+  public
+    class constructor Create;
+    class destructor Destroy;
+    class procedure RegisterTypeFactory<F>(const aFactoryMethod: TFactoryMethod<F>);
+    class function  Construct<F>: F;
+    class function  ConstructFromTypeInfo(const aTypeInfo: PTypeInfo): IBase;
+  end;
+
+implementation
+
+
+{ TypeRegistration }
+
+class constructor TypeRegistry.Create;
+begin
+  FTypeInfoToFactoryLookup := TDictionary<Pointer, Pointer>.Create;
+end;
+
+class destructor TypeRegistry.Destroy;
+begin
+  FTypeInfoToFactoryLookup.Free;
+end;
+
+class procedure TypeRegistry.RegisterTypeFactory<F>(const aFactoryMethod: TFactoryMethod<F>);
+var
+  TypeInfo     : Pointer;
+begin
+  TypeInfo := System.TypeInfo(F);
+
+  if (TypeInfo <> nil) and (PTypeInfo(TypeInfo).Kind = tkInterface)
+  then FTypeInfoToFactoryLookup.AddOrSetValue(TypeInfo, @aFactoryMethod);
+end;
+
+class function TypeRegistry.Construct<F>: F;
+var
+  TypeInfo     : PTypeInfo;
+  Factory      : Pointer;
+begin
+  Result := default(F);
+
+  TypeInfo := System.TypeInfo(F);
+
+  if Assigned(TypeInfo) and (TypeInfo.Kind = tkInterface)
+  then begin
+    if FTypeInfoToFactoryLookup.TryGetValue(TypeInfo, Factory)
+    then Result := TFactoryMethod<F>(Factory)();
+  end;
+end;
+
+class function TypeRegistry.ConstructFromTypeInfo(const aTypeInfo: PTypeInfo): IBase;
+var
+  Factory      : Pointer;
+begin
+  Result := nil;
+  if FTypeInfoToFactoryLookup.TryGetValue(aTypeInfo, Factory)
+  then Result := IBase(TFactoryMethod<IBase>(Factory)());
+end;
+
+
+
+
+end.
diff --git a/lib/delphi/src/Thrift.Utils.pas b/lib/delphi/src/Thrift.Utils.pas
index 72c0dc1..7e57863 100644
--- a/lib/delphi/src/Thrift.Utils.pas
+++ b/lib/delphi/src/Thrift.Utils.pas
@@ -1,36 +1,259 @@
-(*

- * 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.

- *)

-

-unit Thrift.Utils;

-

-interface

-

-function IfValue(B: Boolean; const TrueValue, FalseValue: WideString): string;

-

-implementation

-

-function IfValue(B: Boolean; const TrueValue, FalseValue: WideString): string;

-begin

-  if B then

-    Result := TrueValue

-  else

-    Result := FalseValue;

-end;

-

-end.

+(*
+ * 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.
+ *)
+
+unit Thrift.Utils;
+
+interface
+
+{$I Thrift.Defines.inc}
+
+uses
+  {$IFDEF OLD_UNIT_NAMES}
+  Classes, Windows, SysUtils, Character, SyncObjs;
+  {$ELSE}
+  System.Classes, Winapi.Windows, System.SysUtils, System.Character, System.SyncObjs;
+  {$ENDIF}
+
+type
+  IOverlappedHelper = interface
+    ['{A1832EFA-2E02-4884-8F09-F0A0277157FA}']
+    function Overlapped : TOverlapped;
+    function OverlappedPtr : POverlapped;
+    function WaitHandle : THandle;
+    function WaitFor(dwTimeout: DWORD) : DWORD;
+  end;
+
+  TOverlappedHelperImpl = class( TInterfacedObject, IOverlappedHelper)
+  strict protected
+    FOverlapped : TOverlapped;
+    FEvent      : TEvent;
+
+    // IOverlappedHelper
+    function Overlapped : TOverlapped;
+    function OverlappedPtr : POverlapped;
+    function WaitHandle : THandle;
+    function WaitFor(dwTimeout: DWORD) : DWORD;
+  public
+    constructor Create;
+    destructor Destroy;  override;
+  end;
+
+
+  Base64Utils = class sealed
+  public
+    class function Encode( const src : TBytes; srcOff, len : Integer; dst : TBytes; dstOff : Integer) : Integer; static;
+    class function Decode( const src : TBytes; srcOff, len : Integer; dst : TBytes; dstOff : Integer) : Integer; static;
+  end;
+
+
+  CharUtils = class sealed
+  public
+    class function IsHighSurrogate( const c : Char) : Boolean; static; inline;
+    class function IsLowSurrogate( const c : Char) : Boolean; static; inline;
+  end;
+
+
+{$IFDEF Win64}
+function InterlockedExchangeAdd64( var Addend : Int64; Value : Int64) : Int64;  
+{$ENDIF}
+
+
+implementation
+
+{ TOverlappedHelperImpl }
+
+constructor TOverlappedHelperImpl.Create;
+begin
+  inherited Create;
+  FillChar( FOverlapped, SizeOf(FOverlapped), 0);
+  FEvent := TEvent.Create( nil, TRUE, FALSE, '');  // always ManualReset, see MSDN
+  FOverlapped.hEvent := FEvent.Handle;
+end;
+
+
+
+destructor TOverlappedHelperImpl.Destroy;
+begin
+  try
+    FOverlapped.hEvent := 0;
+    FreeAndNil( FEvent);
+
+  finally
+    inherited Destroy;
+  end;
+
+end;
+
+
+function TOverlappedHelperImpl.Overlapped : TOverlapped;
+begin
+  result := FOverlapped;
+end;
+
+
+function TOverlappedHelperImpl.OverlappedPtr : POverlapped;
+begin
+  result := @FOverlapped;
+end;
+
+
+function TOverlappedHelperImpl.WaitHandle : THandle;
+begin
+  result := FOverlapped.hEvent;
+end;
+
+
+function TOverlappedHelperImpl.WaitFor( dwTimeout : DWORD) : DWORD;
+begin
+  result := WaitForSingleObject( FOverlapped.hEvent, dwTimeout);
+end;
+
+
+{ Base64Utils }
+
+class function Base64Utils.Encode( const src : TBytes; srcOff, len : Integer; dst : TBytes; dstOff : Integer) : Integer;
+const ENCODE_TABLE : PAnsiChar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+begin
+  ASSERT( len in [1..3]);
+  dst[dstOff] := Byte( ENCODE_TABLE[ (src[srcOff] shr 2) and $3F]);
+  case len of
+    3 : begin
+      Inc(dstOff);
+      dst[dstOff] := Byte( ENCODE_TABLE[ ((src[srcOff] shl 4) and $30) or ((src[srcOff + 1] shr 4) and $0F)]);
+      Inc(dstOff);
+      dst[dstOff] := Byte( ENCODE_TABLE[ ((src[srcOff + 1] shl 2) and $3C) or ((src[srcOff + 2] shr 6) and $03)]);
+      Inc(dstOff);
+      dst[dstOff] := Byte( ENCODE_TABLE[ src[srcOff + 2] and $3F]);
+      result := 4;
+    end;
+
+    2 : begin
+      Inc(dstOff);
+      dst[dstOff] := Byte( ENCODE_TABLE[ ((src[srcOff] shl 4) and $30) or ((src[srcOff + 1] shr 4) and $0F)]);
+      Inc(dstOff);
+      dst[dstOff] := Byte( ENCODE_TABLE[ (src[srcOff + 1] shl 2) and $3C]);
+      result := 3;
+    end;
+
+    1 : begin
+      Inc(dstOff);
+      dst[dstOff] := Byte( ENCODE_TABLE[ (src[srcOff] shl 4) and $30]);
+      result := 2;
+    end;
+
+  else
+    ASSERT( FALSE);
+    result := 0;  // because invalid call
+  end;
+end;
+
+
+class function Base64Utils.Decode( const src : TBytes; srcOff, len : Integer; dst : TBytes; dstOff : Integer) : Integer;
+const DECODE_TABLE : array[0..$FF] of Integer
+                   = ( -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+                       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+                       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
+                       52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
+                       -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
+                       15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
+                       -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
+                       41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
+                       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+                       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+                       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+                       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+                       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+                       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+                       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+                       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1  );
+begin
+  ASSERT( len in [1..4]);
+  result := 1;
+  dst[dstOff] := ((DECODE_TABLE[src[srcOff]     and $0FF] shl 2)
+              or  (DECODE_TABLE[src[srcOff + 1] and $0FF] shr 4));
+
+  if (len > 2) then begin
+    Inc( result);
+    Inc( dstOff);
+    dst[dstOff] := (((DECODE_TABLE[src[srcOff + 1] and $0FF] shl 4) and $F0)
+                or   (DECODE_TABLE[src[srcOff + 2] and $0FF] shr 2));
+
+    if (len > 3) then begin
+      Inc( result);
+      Inc( dstOff);
+      dst[dstOff] := (((DECODE_TABLE[src[srcOff + 2] and $0FF] shl 6) and $C0)
+                  or    DECODE_TABLE[src[srcOff + 3] and $0FF]);
+    end;
+  end;
+end;
+
+
+class function CharUtils.IsHighSurrogate( const c : Char) : Boolean;
+begin
+  {$IF CompilerVersion < 25.0}
+    {$IFDEF OLD_UNIT_NAMES}
+    result := Character.IsHighSurrogate(c);
+    {$ELSE}
+    result := System.Character.IsHighSurrogate(c);
+    {$ENDIF}
+  {$ELSE}
+  result := c.IsHighSurrogate();
+  {$IFEND}
+end;
+
+
+class function CharUtils.IsLowSurrogate( const c : Char) : Boolean;
+begin
+  {$IF CompilerVersion < 25.0}
+    {$IFDEF OLD_UNIT_NAMES}
+    result := Character.IsLowSurrogate(c);
+    {$ELSE}
+    result := System.Character.IsLowSurrogate(c);
+    {$ENDIF}
+  {$ELSE}
+  result := c.IsLowSurrogate();
+  {$IFEND}
+end;
+
+
+{$IFDEF Win64}
+
+function InterlockedCompareExchange64( var Target : Int64; Exchange, Comparand : Int64) : Int64;  inline;
+begin
+  {$IFDEF OLD_UNIT_NAMES}
+  result := Windows.InterlockedCompareExchange64( Target, Exchange, Comparand);
+  {$ELSE}
+  result := WinApi.Windows.InterlockedCompareExchange64( Target, Exchange, Comparand);
+  {$ENDIF}
+end;
+
+
+function InterlockedExchangeAdd64( var Addend : Int64; Value : Int64) : Int64;
+var old : Int64;
+begin
+  repeat
+    Old := Addend;
+  until (InterlockedCompareExchange64( Addend, Old + Value, Old) = Old);
+  result := Old;
+end;
+
+{$ENDIF}
+
+
+end.
diff --git a/lib/delphi/src/Thrift.pas b/lib/delphi/src/Thrift.pas
index d5a961b..62481e7 100644
--- a/lib/delphi/src/Thrift.pas
+++ b/lib/delphi/src/Thrift.pas
@@ -22,18 +22,19 @@
 interface
 
 uses
-  SysUtils, Thrift.Protocol;
+  SysUtils,
+  Thrift.Exception,
+  Thrift.Protocol;
 
 const
-  Version = '0.9.1';
+  Version = '1.0.0';
 
 type
-  IProcessor = interface
-    ['{B1538A07-6CAC-4406-8A4C-AFED07C70A89}']
-    function Process( const iprot :IProtocol; const oprot: IProtocol): Boolean;
-  end;
+  TException = Thrift.Exception.TException; // compatibility alias
 
-  TApplicationException = class( SysUtils.Exception )
+  TApplicationExceptionSpecializedClass = class of TApplicationExceptionSpecialized;
+
+  TApplicationException = class( TException)
   public
     type
 {$SCOPEDENUMS ON}
@@ -52,69 +53,115 @@
       );
 {$SCOPEDENUMS OFF}
   private
-    FType : TExceptionType;
+    function GetType: TExceptionType;
+  protected
+    constructor HiddenCreate(const Msg: string);
   public
-    constructor Create; overload;
-    constructor Create( AType: TExceptionType); overload;
-    constructor Create( AType: TExceptionType; const msg: string); overload;
+    // purposefully hide inherited constructor
+    class function Create(const Msg: string): TApplicationException; overload; deprecated 'Use specialized TApplicationException types (or regenerate from IDL)';
+    class function Create: TApplicationException; overload; deprecated 'Use specialized TApplicationException types (or regenerate from IDL)';
+    class function Create( AType: TExceptionType): TApplicationException; overload; deprecated 'Use specialized TApplicationException types (or regenerate from IDL)';
+    class function Create( AType: TExceptionType; const msg: string): TApplicationException; overload; deprecated 'Use specialized TApplicationException types (or regenerate from IDL)';
+
+    class function GetSpecializedExceptionType(AType: TExceptionType): TApplicationExceptionSpecializedClass;
 
     class function Read( const iprot: IProtocol): TApplicationException;
     procedure Write( const oprot: IProtocol );
   end;
 
-  // base class for IDL-generated exceptions
-  TException = class( SysUtils.Exception)
+  // Needed to remove deprecation warning
+  TApplicationExceptionSpecialized = class abstract (TApplicationException)
   public
-    function Message : string;        // hide inherited property: allow read, but prevent accidental writes
-    procedure UpdateMessageProperty;  // update inherited message property with toString()
+    constructor Create(const Msg: string);
   end;
 
+  TApplicationExceptionUnknown = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionUnknownMethod = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionInvalidMessageType = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionWrongMethodName = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionBadSequenceID = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionMissingResult = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionInternalError = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionProtocolError = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionInvalidTransform = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionInvalidProtocol = class (TApplicationExceptionSpecialized);
+  TApplicationExceptionUnsupportedClientType = class (TApplicationExceptionSpecialized);
+
+
 implementation
 
-{ TException }
-
-function TException.Message;
-// allow read (exception summary), but prevent accidental writes
-// read will return the exception summary
-begin
-  result := Self.ToString;
-end;
-
-procedure TException.UpdateMessageProperty;
-// Update the inherited Message property to better conform to standard behaviour.
-// Nice benefit: The IDE is now able to show the exception message again.
-begin
-  inherited Message := Self.ToString;  // produces a summary text
-end;
-
 { TApplicationException }
 
-constructor TApplicationException.Create;
+function TApplicationException.GetType: TExceptionType;
 begin
-  inherited Create( '' );
+  if Self is TApplicationExceptionUnknownMethod then Result := TExceptionType.UnknownMethod
+  else if Self is TApplicationExceptionInvalidMessageType then Result := TExceptionType.InvalidMessageType
+  else if Self is TApplicationExceptionWrongMethodName then Result := TExceptionType.WrongMethodName
+  else if Self is TApplicationExceptionBadSequenceID then Result := TExceptionType.BadSequenceID
+  else if Self is TApplicationExceptionMissingResult then Result := TExceptionType.MissingResult
+  else if Self is TApplicationExceptionInternalError then Result := TExceptionType.InternalError
+  else if Self is TApplicationExceptionProtocolError then Result := TExceptionType.ProtocolError
+  else if Self is TApplicationExceptionInvalidTransform then Result := TExceptionType.InvalidTransform
+  else if Self is TApplicationExceptionInvalidProtocol then Result := TExceptionType.InvalidProtocol
+  else if Self is TApplicationExceptionUnsupportedClientType then Result := TExceptionType.UnsupportedClientType
+  else Result := TExceptionType.Unknown;
 end;
 
-constructor TApplicationException.Create(AType: TExceptionType;
-  const msg: string);
+constructor TApplicationException.HiddenCreate(const Msg: string);
 begin
-  inherited Create( msg );
-  FType := AType;
+  inherited Create(Msg);
 end;
 
-constructor TApplicationException.Create(AType: TExceptionType);
+class function TApplicationException.Create(const Msg: string): TApplicationException;
 begin
-  inherited Create('');
-  FType := AType;
+  Result := TApplicationExceptionUnknown.Create(Msg);
+end;
+
+class function TApplicationException.Create: TApplicationException;
+begin
+  Result := TApplicationExceptionUnknown.Create('');
+end;
+
+class function TApplicationException.Create( AType: TExceptionType): TApplicationException;
+begin
+{$WARN SYMBOL_DEPRECATED OFF}
+  Result := Create(AType, '');
+{$WARN SYMBOL_DEPRECATED DEFAULT}
+end;
+
+class function TApplicationException.Create( AType: TExceptionType; const msg: string): TApplicationException;
+begin
+  Result := GetSpecializedExceptionType(AType).Create(msg);
+end;
+
+class function TApplicationException.GetSpecializedExceptionType(AType: TExceptionType): TApplicationExceptionSpecializedClass;
+begin
+  case AType of
+    TExceptionType.UnknownMethod:         Result := TApplicationExceptionUnknownMethod;
+    TExceptionType.InvalidMessageType:    Result := TApplicationExceptionInvalidMessageType;
+    TExceptionType.WrongMethodName:       Result := TApplicationExceptionWrongMethodName;
+    TExceptionType.BadSequenceID:         Result := TApplicationExceptionBadSequenceID;
+    TExceptionType.MissingResult:         Result := TApplicationExceptionMissingResult;
+    TExceptionType.InternalError:         Result := TApplicationExceptionInternalError;
+    TExceptionType.ProtocolError:         Result := TApplicationExceptionProtocolError;
+    TExceptionType.InvalidTransform:      Result := TApplicationExceptionInvalidTransform;
+    TExceptionType.InvalidProtocol:       Result := TApplicationExceptionInvalidProtocol;
+    TExceptionType.UnsupportedClientType: Result := TApplicationExceptionUnsupportedClientType;
+  else
+    Result := TApplicationExceptionUnknown;
+  end;
 end;
 
 class function TApplicationException.Read( const iprot: IProtocol): TApplicationException;
 var
-  field : IField;
+  field : TThriftField;
   msg : string;
   typ : TExceptionType;
+  struc : TThriftStruct;
 begin
   msg := '';
   typ := TExceptionType.Unknown;
+  struc := iprot.ReadStructBegin;
   while ( True ) do
   begin
     field := iprot.ReadFieldBegin;
@@ -150,17 +197,16 @@
     iprot.ReadFieldEnd;
   end;
   iprot.ReadStructEnd;
-  Result := TApplicationException.Create( typ, msg );
+  Result := GetSpecializedExceptionType(typ).Create(msg);
 end;
 
 procedure TApplicationException.Write( const oprot: IProtocol);
 var
-  struc : IStruct;
-  field : IField;
-
+  struc : TThriftStruct;
+  field : TThriftField;
 begin
-  struc := TStructImpl.Create( 'TApplicationException' );
-  field := TFieldImpl.Create;
+  Init(struc, 'TApplicationException');
+  Init(field);
 
   oprot.WriteStructBegin( struc );
   if Message <> '' then
@@ -177,10 +223,17 @@
   field.Type_ := TType.I32;
   field.Id := 2;
   oprot.WriteFieldBegin(field);
-  oprot.WriteI32(Integer(FType));
+  oprot.WriteI32(Integer(GetType));
   oprot.WriteFieldEnd();
   oprot.WriteFieldStop();
   oprot.WriteStructEnd();
 end;
 
+{ TApplicationExceptionSpecialized }
+
+constructor TApplicationExceptionSpecialized.Create(const Msg: string);
+begin
+  inherited HiddenCreate(Msg);
+end;
+
 end.
diff --git a/lib/delphi/test/ConsoleHelper.pas b/lib/delphi/test/ConsoleHelper.pas
new file mode 100644
index 0000000..0a8ddcf
--- /dev/null
+++ b/lib/delphi/test/ConsoleHelper.pas
@@ -0,0 +1,132 @@
+(*
+ * 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.
+ *)
+
+unit ConsoleHelper;
+
+interface
+
+uses Classes;
+
+type
+  TThriftConsole = class
+  public
+    procedure Write( const S: string); virtual;
+    procedure WriteLine( const S: string); virtual;
+  end;
+
+  TGUIConsole = class( TThriftConsole )
+  private
+    FLineBreak : Boolean;
+    FMemo : TStrings;
+
+    procedure InternalWrite( const S: string; bWriteLine: Boolean);
+  public
+    procedure Write( const S: string); override;
+    procedure WriteLine( const S: string); override;
+    constructor Create( AMemo: TStrings);
+  end;
+
+function Console: TThriftConsole;
+procedure ChangeConsole( AConsole: TThriftConsole );
+procedure RestoreConsoleToDefault;
+
+implementation
+
+var
+  FDefaultConsole : TThriftConsole;
+  FConsole : TThriftConsole;
+
+function Console: TThriftConsole;
+begin
+  Result := FConsole;
+end;
+
+{ TThriftConsole }
+
+procedure TThriftConsole.Write(const S: string);
+begin
+  System.Write( S );
+end;
+
+procedure TThriftConsole.WriteLine(const S: string);
+begin
+  System.Writeln( S );
+end;
+
+procedure ChangeConsole( AConsole: TThriftConsole );
+begin
+  FConsole := AConsole;
+end;
+
+procedure RestoreConsoleToDefault;
+begin
+  FConsole := FDefaultConsole;
+end;
+
+{ TGUIConsole }
+
+constructor TGUIConsole.Create( AMemo: TStrings);
+begin
+  inherited Create;
+  FMemo := AMemo;
+  FLineBreak := True;
+end;
+
+procedure TGUIConsole.InternalWrite(const S: string; bWriteLine: Boolean);
+var
+  idx : Integer;
+begin
+  if FLineBreak then
+  begin
+    FMemo.Add( S );
+  end else
+  begin
+    idx := FMemo.Count - 1;
+    if idx < 0 then
+      FMemo.Add( S )
+    else
+      FMemo[idx] := FMemo[idx] + S;
+  end;
+  FLineBreak := bWriteLine;
+end;
+
+procedure TGUIConsole.Write(const S: string);
+begin
+  InternalWrite( S, False);
+end;
+
+procedure TGUIConsole.WriteLine(const S: string);
+begin
+  InternalWrite( S, True);
+end;
+
+initialization
+begin
+  FDefaultConsole := TThriftConsole.Create;
+  FConsole := FDefaultConsole;
+end;
+
+finalization
+begin
+  FDefaultConsole.Free;
+end;
+
+end.
+
+
diff --git a/lib/delphi/test/TestClient.pas b/lib/delphi/test/TestClient.pas
index 37fe7d7..0fa43b0 100644
--- a/lib/delphi/test/TestClient.pas
+++ b/lib/delphi/test/TestClient.pas
@@ -1,4 +1,4 @@
-(*
+(*
  * 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
@@ -19,25 +19,35 @@
 
 unit TestClient;
 
+{$I ../src/Thrift.Defines.inc}
+
 {.$DEFINE StressTest}   // activate to stress-test the server with frequent connects/disconnects
-{.$DEFINE PerfTest}     // activate to activate the performance test
+{.$DEFINE PerfTest}     // activate the performance test
+{$DEFINE Exceptions}    // activate the exceptions test (or disable while debugging)
+
+{$if CompilerVersion >= 28}
+{$DEFINE SupportsAsync}
+{$ifend}
 
 interface
 
 uses
-  Windows, SysUtils, Classes,
+  Windows, SysUtils, Classes, Math, ComObj, ActiveX,
+  {$IFDEF SupportsAsync} System.Threading, {$ENDIF}
   DateUtils,
   Generics.Collections,
   TestConstants,
+  ConsoleHelper,
   Thrift,
+  Thrift.Protocol.Compact,
   Thrift.Protocol.JSON,
   Thrift.Protocol,
   Thrift.Transport.Pipes,
   Thrift.Transport,
   Thrift.Stream,
   Thrift.Test,
-  Thrift.Collections,
-  Thrift.Console;
+  Thrift.Utils,
+  Thrift.Collections;
 
 type
   TThreadConsole = class
@@ -49,8 +59,38 @@
     constructor Create( AThread: TThread);
   end;
 
+  TTestSetup = record
+    protType  : TKnownProtocol;
+    endpoint  : TEndpointTransport;
+    layered   : TLayeredTransports;
+    useSSL    : Boolean; // include where appropriate (TLayeredTransport?)
+    host      : string;
+    port      : Integer;
+    sPipeName : string;
+    hAnonRead, hAnonWrite : THandle;
+  end;
+
   TClientThread = class( TThread )
+  private type
+    TTestGroup = (
+      test_Unknown,
+      test_BaseTypes,
+      test_Structs,
+      test_Containers,
+      test_Exceptions
+      // new values here
+    );
+    TTestGroups = set of TTestGroup;
+
+    TTestSize = (
+      Empty,           // Edge case: the zero-length empty binary
+      Normal,          // Fairly small array of usual size (256 bytes)
+      ByteArrayTest,   // THRIFT-4454 Large writes/reads may cause range check errors in debug mode
+      PipeWriteLimit   // THRIFT-4372 Pipe write operations across a network are limited to 65,535 bytes per write.
+    );
+
   private
+    FSetup : TTestSetup;
     FTransport : ITransport;
     FProtocol : IProtocol;
     FNumIteration : Integer;
@@ -58,19 +98,36 @@
 
     // test reporting, will be refactored out into separate class later
     FTestGroup : string;
+    FCurrentTest : TTestGroup;
     FSuccesses : Integer;
     FErrors : TStringList;
-    procedure StartTestGroup( const aGroup : string);
+    FFailed : TTestGroups;
+    FExecuted : TTestGroups;
+    procedure StartTestGroup( const aGroup : string; const aTest : TTestGroup);
     procedure Expect( aTestResult : Boolean; const aTestInfo : string);
     procedure ReportResults;
+    function  CalculateExitCode : Byte;
 
     procedure ClientTest;
+    {$IFDEF SupportsAsync}
+    procedure ClientAsyncTest;
+    {$ENDIF}
+
+    procedure InitializeProtocolTransportStack;
+    procedure ShutdownProtocolTransportStack;
+
     procedure JSONProtocolReadWriteTest;
+    function  PrepareBinaryData( aRandomDist : Boolean; aSize : TTestSize) : TBytes;
+    {$IFDEF StressTest}
     procedure StressTest(const client : TThriftTest.Iface);
+    {$ENDIF}
+    {$IFDEF Win64}
+    procedure UseInterlockedExchangeAdd64;
+    {$ENDIF}
   protected
     procedure Execute; override;
   public
-    constructor Create( const ATransport: ITransport; const AProtocol : IProtocol; ANumIteration: Integer);
+    constructor Create( const aSetup : TTestSetup; const aNumIteration: Integer);
     destructor Destroy; override;
   end;
 
@@ -79,12 +136,34 @@
     class var
       FNumIteration : Integer;
       FNumThread : Integer;
+
+    class procedure PrintCmdLineHelp;
+    class procedure InvalidArgs;
   public
-    class procedure Execute( const args: array of string);
+    class function Execute( const args: array of string) : Byte;
   end;
 
+
 implementation
 
+const
+   EXITCODE_SUCCESS           = $00;  // no errors bits set
+   //
+   EXITCODE_FAILBIT_BASETYPES  = $01;
+   EXITCODE_FAILBIT_STRUCTS    = $02;
+   EXITCODE_FAILBIT_CONTAINERS = $04;
+   EXITCODE_FAILBIT_EXCEPTIONS = $08;
+
+   MAP_FAILURES_TO_EXITCODE_BITS : array[TClientThread.TTestGroup] of Byte = (
+     EXITCODE_SUCCESS,  // no bits here
+     EXITCODE_FAILBIT_BASETYPES,
+     EXITCODE_FAILBIT_STRUCTS,
+     EXITCODE_FAILBIT_CONTAINERS,
+     EXITCODE_FAILBIT_EXCEPTIONS
+   );
+
+
+
 function BoolToString( b : Boolean) : string;
 // overrides global BoolToString()
 begin
@@ -98,137 +177,152 @@
 
 { TTestClient }
 
-class procedure TTestClient.Execute(const args: array of string);
+class procedure TTestClient.PrintCmdLineHelp;
+const HELPTEXT = ' [options]'#10
+               + #10
+               + 'Allowed options:'#10
+               + '  -h [ --help ]               produce help message'#10
+               + '  --host arg (=localhost)     Host to connect'#10
+               + '  --port arg (=9090)          Port number to connect'#10
+               + '  --domain-socket arg         Domain Socket (e.g. /tmp/ThriftTest.thrift),'#10
+               + '                              instead of host and port'#10
+               + '  --named-pipe arg            Windows Named Pipe (e.g. MyThriftPipe)'#10
+               + '  --anon-pipes hRead hWrite   Windows Anonymous Pipes pair (handles)'#10
+               + '  --transport arg (=sockets)  Transport: buffered, framed, http, evhttp'#10
+               + '  --protocol arg (=binary)    Protocol: binary, compact, json'#10
+               + '  --ssl                       Encrypted Transport using SSL'#10
+               + '  -n [ --testloops ] arg (=1) Number of Tests'#10
+               + '  -t [ --threads ] arg (=1)   Number of Test threads'#10
+               ;
+begin
+  Writeln( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + HELPTEXT);
+end;
+
+class procedure TTestClient.InvalidArgs;
+begin
+  Console.WriteLine( 'Invalid args.');
+  Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + ' -h for more information');
+  Abort;
+end;
+
+class function TTestClient.Execute(const args: array of string) : Byte;
 var
   i : Integer;
-  host : string;
-  port : Integer;
-  url : string;
-  bBuffered : Boolean;
-  bAnonPipe : Boolean;
-  bFramed : Boolean;
-  sPipeName : string;
-  hAnonRead, hAnonWrite : THandle;
+  threadExitCode : Byte;
   s : string;
-  n : Integer;
   threads : array of TThread;
   dtStart : TDateTime;
   test : Integer;
   thread : TThread;
-  trans : ITransport;
-  prot : IProtocol;
-  streamtrans : IStreamTransport;
-  http : IHTTPClient;
-  protType, p : TKnownProtocol;
-const
-  // pipe timeouts to be used
-  DEBUG_TIMEOUT   = 30 * 1000;
-  RELEASE_TIMEOUT = DEFAULT_THRIFT_PIPE_TIMEOUT;
-  TIMEOUT         = RELEASE_TIMEOUT;
+  setup : TTestSetup;
 begin
-  bBuffered := False;;
-  bFramed := False;
-  protType := prot_Binary;
-  try
-    host := 'localhost';
-    port := 9090;
-    url := '';
-    sPipeName := '';
-    bAnonPipe := FALSE;
-    hAnonRead := INVALID_HANDLE_VALUE;
+  // init record
+  with setup do begin
+    protType   := prot_Binary;
+    endpoint   := trns_Sockets;
+    layered    := [];
+    useSSL     := FALSE;
+    host       := 'localhost';
+    port       := 9090;
+    sPipeName  := '';
+    hAnonRead  := INVALID_HANDLE_VALUE;
     hAnonWrite := INVALID_HANDLE_VALUE;
+  end;
+
+  try
     i := 0;
-    try
-      while ( i < Length(args) ) do
-      begin
+    while ( i < Length(args) ) do begin
+      s := args[i];
+      Inc( i);
 
-        try
-          if ( args[i] = '-h') then
-          begin
-            Inc( i );
-            s := args[i];
-            n := Pos( ':', s);
-            if ( n > 0 ) then
-            begin
-              host := Copy( s, 1, n - 1);
-              port := StrToInt( Copy( s, n + 1, MaxInt));
-            end else
-            begin
-              host := s;
-            end;
-          end
-          else if (args[i] = '-u') then
-          begin
-            Inc( i );
-            url := args[i];
-          end
-          else if (args[i] = '-n') then
-          begin
-            Inc( i );
-            FNumIteration := StrToInt( args[i] );
-          end
-          else if (args[i] = '-b') then
-          begin
-            bBuffered := True;
-            Console.WriteLine('Buffered transport');
-          end
-          else if (args[i] = '-f' ) or ( args[i] = '-framed') then
-          begin
-            bFramed := True;
-            Console.WriteLine('Framed transport');
-          end
-          else if (args[i] = '-pipe') then  // -pipe <name>
-          begin
-            Console.WriteLine('Named pipes transport');
-            Inc( i );
-            sPipeName := args[i];
-          end
-          else if (args[i] = '-anon') then  // -anon <hReadPipe> <hWritePipe>
-          begin
-            if Length(args) <= (i+2) then begin
-              Console.WriteLine('Invalid args: -anon <hRead> <hWrite> or use "server.exe -anon"');
-              Halt(1);
-            end;
-            Console.WriteLine('Anonymous pipes transport');
-            Inc( i);
-            hAnonRead := THandle( StrToIntDef( args[i], Integer(INVALID_HANDLE_VALUE)));
-            Inc( i);
-            hAnonWrite := THandle( StrToIntDef( args[i], Integer(INVALID_HANDLE_VALUE)));
-            bAnonPipe := TRUE;
-          end
-          else if (args[i] = '-t') then
-          begin
-            Inc( i );
-            FNumThread := StrToInt( args[i] );
-          end
-          else if (args[i] = '-prot') then  // -prot JSON|binary
-          begin
-            Inc( i );
-            s := args[i];
-            for p:= Low(TKnownProtocol) to High(TKnownProtocol) do begin
-              if SameText( s, KNOWN_PROTOCOLS[p]) then begin
-                protType := p;
-                Console.WriteLine('Using '+KNOWN_PROTOCOLS[protType]+' protocol');
-                Break;
-              end;
-            end;
-          end;
-        finally
-          Inc( i );
-        end;
+      if (s = '-h') or (s = '--help') then begin
+        // -h [ --help ]               produce help message
+        PrintCmdLineHelp;
+        result := $FF;   // all tests failed
+        Exit;
+      end
+      else if s = '--host' then begin
+        // --host arg (=localhost)     Host to connect
+        setup.host := args[i];
+        Inc( i);
+      end
+      else if s = '--port' then begin
+        // --port arg (=9090)          Port number to connect
+        s := args[i];
+        Inc( i);
+        setup.port := StrToIntDef(s,0);
+        if setup.port <= 0 then InvalidArgs;
+      end
+      else if s = '--domain-socket' then begin
+        // --domain-socket arg         Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port
+        raise Exception.Create('domain-socket not supported');
+      end
+      else if s = '--named-pipe' then begin
+        // --named-pipe arg            Windows Named Pipe (e.g. MyThriftPipe)
+        setup.endpoint := trns_NamedPipes;
+        setup.sPipeName := args[i];
+        Inc( i);
+        Console.WriteLine('Using named pipe ('+setup.sPipeName+')');
+      end
+      else if s = '--anon-pipes' then begin
+        // --anon-pipes hRead hWrite   Windows Anonymous Pipes pair (handles)
+        setup.endpoint := trns_AnonPipes;
+        setup.hAnonRead := THandle( StrToIntDef( args[i], Integer(INVALID_HANDLE_VALUE)));
+        Inc( i);
+        setup.hAnonWrite := THandle( StrToIntDef( args[i], Integer(INVALID_HANDLE_VALUE)));
+        Inc( i);
+        Console.WriteLine('Using anonymous pipes ('+IntToStr(Integer(setup.hAnonRead))+' and '+IntToStr(Integer(setup.hAnonWrite))+')');
+      end
+      else if s = '--transport' then begin
+        // --transport arg (=sockets)  Transport: buffered, framed, http, evhttp
+        s := args[i];
+        Inc( i);
 
-      end;
+        if      s = 'buffered' then Include( setup.layered, trns_Buffered)
+        else if s = 'framed'   then Include( setup.layered, trns_Framed)
+        else if s = 'http'     then setup.endpoint := trns_Http
+        else if s = 'evhttp'   then setup.endpoint := trns_EvHttp
+        else InvalidArgs;
+      end
+      else if s = '--protocol' then begin
+        // --protocol arg (=binary)    Protocol: binary, compact, json
+        s := args[i];
+        Inc( i);
 
-    except
-      on E: Exception do
-      begin
-        Console.WriteLine( E.Message );
+        if      s = 'binary'   then setup.protType := prot_Binary
+        else if s = 'compact'  then setup.protType := prot_Compact
+        else if s = 'json'     then setup.protType := prot_JSON
+        else InvalidArgs;
+      end
+      else if s = '--ssl' then begin
+        // --ssl                       Encrypted Transport using SSL
+        setup.useSSL := TRUE;
+
+      end
+      else if (s = '-n') or (s = '--testloops') then begin
+        // -n [ --testloops ] arg (=1) Number of Tests
+        FNumIteration := StrToIntDef( args[i], 0);
+        Inc( i);
+        if FNumIteration <= 0
+        then InvalidArgs;
+
+      end
+      else if (s = '-t') or (s = '--threads') then begin
+        // -t [ --threads ] arg (=1)   Number of Test threads
+        FNumThread := StrToIntDef( args[i], 0);
+        Inc( i);
+        if FNumThread <= 0
+        then InvalidArgs;
+      end
+      else begin
+        InvalidArgs;
       end;
     end;
 
+
     // In the anonymous pipes mode the client is launched by the test server
     // -> behave nicely and allow for attaching a debugger to this process
-    if bAnonPipe and not IsDebuggerPresent
+    if (setup.endpoint = trns_AnonPipes) and not IsDebuggerPresent
     then MessageBox( 0, 'Attach Debugger and/or click OK to continue.',
                         'Thrift TestClient (Delphi)',
                         MB_OK or MB_ICONEXCLAMATION);
@@ -236,74 +330,37 @@
     SetLength( threads, FNumThread);
     dtStart := Now;
 
-    for test := 0 to FNumThread - 1 do
-    begin
-      if url = '' then
-      begin
-        if sPipeName <> '' then begin
-          Console.WriteLine('Using named pipe ('+sPipeName+')');
-          streamtrans := TNamedPipeTransportClientEndImpl.Create( sPipeName, 0, nil, TIMEOUT);
-        end
-        else if bAnonPipe then begin
-          Console.WriteLine('Using anonymous pipes ('+IntToStr(Integer(hAnonRead))+' and '+IntToStr(Integer(hAnonWrite))+')');
-          streamtrans := TAnonymousPipeTransportImpl.Create( hAnonRead, hAnonWrite, FALSE);
-        end
-        else begin
-          Console.WriteLine('Using sockets ('+host+' port '+IntToStr(port)+')');
-          streamtrans := TSocketImpl.Create( host, port );
-        end;
+    // layered transports are not really meant to be stacked upon each other
+    if (trns_Framed in setup.layered) then begin
+      Console.WriteLine('Using framed transport');
+    end
+    else if (trns_Buffered in setup.layered) then begin
+      Console.WriteLine('Using buffered transport');
+    end;
 
-        trans := streamtrans;
+    Console.WriteLine(THRIFT_PROTOCOLS[setup.protType]+' protocol');
 
-        if bBuffered then begin
-          trans := TBufferedTransportImpl.Create( streamtrans, 32);  // small buffer to test read()
-          Console.WriteLine('Using buffered transport');
-        end;
-
-        if bFramed then begin
-          trans := TFramedTransportImpl.Create( trans );
-          Console.WriteLine('Using framed transport');
-        end;
-
-      end
-      else begin
-        Console.WriteLine('Using HTTPClient');
-        http := THTTPClientImpl.Create( url );
-        trans := http;
-      end;
-
-      // create protocol instance, default to BinaryProtocol
-      case protType of
-        prot_Binary:  prot := TBinaryProtocolImpl.Create( trans, BINARY_STRICT_READ, BINARY_STRICT_WRITE);
-        prot_JSON  :  prot := TJSONProtocolImpl.Create( trans);
-      else
-        ASSERT( FALSE);  // unhandled case!
-        prot := TBinaryProtocolImpl.Create( trans, BINARY_STRICT_READ, BINARY_STRICT_WRITE);  // use default
-      end;
-
-      thread := TClientThread.Create( trans, prot, FNumIteration);
+    for test := 0 to FNumThread - 1 do begin
+      thread := TClientThread.Create( setup, FNumIteration);
       threads[test] := thread;
-{$WARN SYMBOL_DEPRECATED OFF}
-      thread.Resume;
-{$WARN SYMBOL_DEPRECATED ON}
+      thread.Start;
     end;
 
-    for test := 0 to FNumThread - 1 do
-    begin
-      threads[test].WaitFor;
-    end;
-
-    for test := 0 to FNumThread - 1 do
-    begin
+    result := 0;
+    for test := 0 to FNumThread - 1 do begin
+      threadExitCode := threads[test].WaitFor;
+      result := result or threadExitCode;
       threads[test].Free;
+      threads[test] := nil;
     end;
 
     Console.Write('Total time: ' + IntToStr( MilliSecondsBetween(Now, dtStart)));
 
   except
-    on E: Exception do
-    begin
-      Console.WriteLine( E.Message + ' ST: ' + E.StackTrace );
+    on E: EAbort do raise;
+    on E: Exception do begin
+      Console.WriteLine( E.Message + #10 + E.StackTrace);
+      raise;
     end;
   end;
 
@@ -320,6 +377,7 @@
   i8 : ShortInt;
   i32 : Integer;
   i64 : Int64;
+  binOut,binIn : TBytes;
   dub : Double;
   o : IXtruct;
   o2 : IXtruct2;
@@ -361,15 +419,17 @@
   arg3 : IThriftDictionary<SmallInt, string>;
   arg4 : TNumberz;
   arg5 : Int64;
+  {$IFDEF PerfTest}
   StartTick : Cardinal;
   k : Integer;
-  proc : TThreadProcedure;
+  {$ENDIF}
   hello, goodbye : IXtruct;
   crazy : IInsanity;
   looney : IInsanity;
   first_map : IThriftDictionary<TNumberz, IInsanity>;
   second_map : IThriftDictionary<TNumberz, IInsanity>;
-
+  pair : TPair<TNumberz, TUserId>;
+  testsize : TTestSize;
 begin
   client := TThriftTest.TClient.Create( FProtocol);
   FTransport.Open;
@@ -378,11 +438,12 @@
   StressTest( client);
   {$ENDIF StressTest}
 
+  {$IFDEF Exceptions}
   // in-depth exception test
   // (1) do we get an exception at all?
   // (2) do we get the right exception?
   // (3) does the exception contain the expected data?
-  StartTestGroup( 'testException');
+  StartTestGroup( 'testException', test_Exceptions);
   // case 1: exception type declared in IDL at the function call
   try
     client.testException('Xception');
@@ -394,7 +455,7 @@
       Console.WriteLine( ' = ' + IntToStr(e.ErrorCode) + ', ' + e.Message_ );
     end;
     on e:TTransportException do Expect( FALSE, 'Unexpected : "'+e.ToString+'"');
-    on e:Exception do Expect( FALSE, 'Unexpected exception type "'+e.ClassName+'"');
+    on e:Exception do Expect( FALSE, 'Unexpected exception "'+e.ClassName+'": '+e.Message);
   end;
 
   // case 2: exception type NOT declared in IDL at the function call
@@ -405,34 +466,49 @@
   except
     on e:TTransportException do begin
       Console.WriteLine( e.ClassName+' = '+e.Message); // this is what we get
-      if FTransport.IsOpen then FTransport.Close;
-      FTransport.Open;   // re-open connection, server has already closed
     end;
-    on e:TException do Expect( FALSE, 'Unexpected exception type "'+e.ClassName+'"');
-    on e:Exception do Expect( FALSE, 'Unexpected exception type "'+e.ClassName+'"');
+    on e:TApplicationException do begin
+      Console.WriteLine( e.ClassName+' = '+e.Message); // this is what we get
+    end;
+    on e:TException do Expect( FALSE, 'Unexpected exception "'+e.ClassName+'": '+e.Message);
+    on e:Exception do Expect( FALSE, 'Unexpected exception "'+e.ClassName+'": '+e.Message);
   end;
 
+
+  if FTransport.IsOpen then FTransport.Close;
+  FTransport.Open;   // re-open connection, server has already closed
+
+
   // case 3: no exception
   try
     client.testException('something');
     Expect( TRUE, 'testException(''something''): must not trow an exception');
   except
     on e:TTransportException do Expect( FALSE, 'Unexpected : "'+e.ToString+'"');
-    on e:Exception do Expect( FALSE, 'Unexpected exception "'+e.ClassName+'"');
+    on e:Exception do Expect( FALSE, 'Unexpected exception "'+e.ClassName+'": '+e.Message);
   end;
+  {$ENDIF Exceptions}
 
 
   // simple things
-  StartTestGroup( 'simple Thrift calls');
+  StartTestGroup( 'simple Thrift calls', test_BaseTypes);
   client.testVoid();
   Expect( TRUE, 'testVoid()');  // success := no exception
 
+  s := BoolToString( client.testBool(TRUE));
+  Expect( s = BoolToString(TRUE),  'testBool(TRUE) = '+s);
+  s := BoolToString( client.testBool(FALSE));
+  Expect( s = BoolToString(FALSE),  'testBool(FALSE) = '+s);
+
   s := client.testString('Test');
   Expect( s = 'Test', 'testString(''Test'') = "'+s+'"');
 
+  s := client.testString('');  // empty string
+  Expect( s = '', 'testString('''') = "'+s+'"');
+
   s := client.testString(HUGE_TEST_STRING);
   Expect( length(s) = length(HUGE_TEST_STRING),
-          'testString( lenght(HUGE_TEST_STRING) = '+IntToStr(Length(HUGE_TEST_STRING))+') '
+          'testString( length(HUGE_TEST_STRING) = '+IntToStr(Length(HUGE_TEST_STRING))+') '
          +'=> length(result) = '+IntToStr(Length(s)));
 
   i8 := client.testByte(1);
@@ -445,12 +521,27 @@
   i64 := client.testI64(-34359738368);
   Expect( i64 = -34359738368, 'testI64(-34359738368) = ' + IntToStr( i64));
 
+  // random binary small
+  for testsize := Low(TTestSize) to High(TTestSize) do begin
+    binOut := PrepareBinaryData( TRUE, testsize);
+    Console.WriteLine('testBinary('+BytesToHex(binOut)+')');
+    try
+      binIn := client.testBinary(binOut);
+      Expect( Length(binOut) = Length(binIn), 'testBinary(): length '+IntToStr(Length(binOut))+' = '+IntToStr(Length(binIn)));
+      i32 := Min( Length(binOut), Length(binIn));
+      Expect( CompareMem( binOut, binIn, i32), 'testBinary('+BytesToHex(binOut)+') = '+BytesToHex(binIn));
+    except
+      on e:TApplicationException do Console.WriteLine('testBinary(): '+e.Message);
+      on e:Exception do Expect( FALSE, 'testBinary(): Unexpected exception "'+e.ClassName+'": '+e.Message);
+    end;
+  end;
+
   Console.WriteLine('testDouble(5.325098235)');
   dub := client.testDouble(5.325098235);
   Expect( abs(dub-5.325098235) < 1e-14, 'testDouble(5.325098235) = ' + FloatToStr( dub));
 
   // structs
-  StartTestGroup( 'testStruct');
+  StartTestGroup( 'testStruct', test_Structs);
   Console.WriteLine('testStruct({''Zero'', 1, -3, -5})');
   o := TXtructImpl.Create;
   o.String_thing := 'Zero';
@@ -468,7 +559,7 @@
   Expect( i.__isset_I64_thing, 'i.__isset_I64_thing = '+BoolToString(i.__isset_I64_thing));
 
   // nested structs
-  StartTestGroup( 'testNest');
+  StartTestGroup( 'testNest', test_Structs);
   Console.WriteLine('testNest({1, {''Zero'', 1, -3, -5}, 5})');
   o2 := TXtruct2Impl.Create;
   o2.Byte_thing := 1;
@@ -491,7 +582,7 @@
 
   // map<type1,type2>: A map of strictly unique keys to values.
   // Translates to an STL map, Java HashMap, PHP associative array, Python/Ruby dictionary, etc.
-  StartTestGroup( 'testMap');
+  StartTestGroup( 'testMap', test_Containers);
   mapout := TThriftDictionaryImpl<Integer,Integer>.Create;
   for j := 0 to 4 do
   begin
@@ -523,7 +614,7 @@
 
   // map<type1,type2>: A map of strictly unique keys to values.
   // Translates to an STL map, Java HashMap, PHP associative array, Python/Ruby dictionary, etc.
-  StartTestGroup( 'testStringMap');
+  StartTestGroup( 'testStringMap', test_Containers);
   strmapout := TThriftDictionaryImpl<string,string>.Create;
   for j := 0 to 4 do
   begin
@@ -558,7 +649,7 @@
   // set<type>: An unordered set of unique elements.
   // Translates to an STL set, Java HashSet, set in Python, etc.
   // Note: PHP does not support sets, so it is treated similar to a List
-  StartTestGroup( 'testSet');
+  StartTestGroup( 'testSet', test_Containers);
   setout := THashSetImpl<Integer>.Create;
   for j := -2 to 2 do
   begin
@@ -585,7 +676,7 @@
 
   // list<type>: An ordered list of elements.
   // Translates to an STL vector, Java ArrayList, native arrays in scripting languages, etc.
-  StartTestGroup( 'testList');
+  StartTestGroup( 'testList', test_Containers);
   listout := TThriftListImpl<Integer>.Create;
   listout.Add( +1);
   listout.Add( -2);
@@ -635,7 +726,7 @@
 
 
   // maps of maps
-  StartTestGroup( 'testMapMap(1)');
+  StartTestGroup( 'testMapMap(1)', test_Containers);
   mm := client.testMapMap(1);
   Console.Write(' = {');
   for key in mm.Keys do
@@ -663,15 +754,15 @@
 
 
   // insanity
-  StartTestGroup( 'testInsanity');
+  StartTestGroup( 'testInsanity', test_Structs);
   insane := TInsanityImpl.Create;
   insane.UserMap := TThriftDictionaryImpl<TNumberz, Int64>.Create;
   insane.UserMap.AddOrSetValue( TNumberz.FIVE, 5000);
   truck := TXtructImpl.Create;
   truck.String_thing := 'Truck';
-  truck.Byte_thing := 8;
-  truck.I32_thing := 8;
-  truck.I64_thing := 8;
+  truck.Byte_thing := -8;  // byte is signed
+  truck.I32_thing := 32;
+  truck.I64_thing := 64;
   insane.Xtructs := TThriftListImpl<IXtruct>.Create;
   insane.Xtructs.Add( truck );
   whoa := client.testInsanity( insane );
@@ -720,6 +811,18 @@
   end;
   Console.WriteLine('}');
 
+  (**
+   * So you think you've got this all worked, out eh?
+   *
+   * Creates a the returned map with these values and prints it out:
+   *   { 1 => { 2 => argument,
+   *            3 => argument,
+   *          },
+   *     2 => { 6 => <empty Insanity struct>, },
+   *   }
+   * @return map<UserId, map<Numberz,Insanity>> - a map with the above values
+   *)
+
   // verify result data
   Expect( whoa.Count = 2, 'whoa.Count = '+IntToStr(whoa.Count));
   //
@@ -740,36 +843,25 @@
     Expect( crazy.__isset_UserMap, 'crazy.__isset_UserMap = '+BoolToString(crazy.__isset_UserMap));
     Expect( crazy.__isset_Xtructs, 'crazy.__isset_Xtructs = '+BoolToString(crazy.__isset_Xtructs));
 
-    Expect( crazy.UserMap.Count = 2, 'crazy.UserMap.Count = '+IntToStr(crazy.UserMap.Count));
-    Expect( crazy.UserMap[TNumberz.FIVE] = 5, 'crazy.UserMap[TNumberz.FIVE] = '+IntToStr(crazy.UserMap[TNumberz.FIVE]));
-    Expect( crazy.UserMap[TNumberz.EIGHT] = 8, 'crazy.UserMap[TNumberz.EIGHT] = '+IntToStr(crazy.UserMap[TNumberz.EIGHT]));
+    Expect( crazy.UserMap.Count = insane.UserMap.Count, 'crazy.UserMap.Count = '+IntToStr(crazy.UserMap.Count));
+    for pair in insane.UserMap do begin
+      Expect( crazy.UserMap[pair.Key] = pair.Value, 'crazy.UserMap['+IntToStr(Ord(pair.key))+'] = '+IntToStr(crazy.UserMap[pair.Key]));
+    end;
 
-    Expect( crazy.Xtructs.Count = 2, 'crazy.Xtructs.Count = '+IntToStr(crazy.Xtructs.Count));
-    goodbye := crazy.Xtructs[0];  // lists are ordered, so we are allowed to assume this order
-	  hello   := crazy.Xtructs[1];
-
-    Expect( goodbye.String_thing = 'Goodbye4', 'goodbye.String_thing = "'+goodbye.String_thing+'"');
-    Expect( goodbye.Byte_thing = 4, 'goodbye.Byte_thing = '+IntToStr(goodbye.Byte_thing));
-    Expect( goodbye.I32_thing = 4, 'goodbye.I32_thing = '+IntToStr(goodbye.I32_thing));
-    Expect( goodbye.I64_thing = 4, 'goodbye.I64_thing = '+IntToStr(goodbye.I64_thing));
-    Expect( goodbye.__isset_String_thing, 'goodbye.__isset_String_thing = '+BoolToString(goodbye.__isset_String_thing));
-    Expect( goodbye.__isset_Byte_thing, 'goodbye.__isset_Byte_thing = '+BoolToString(goodbye.__isset_Byte_thing));
-    Expect( goodbye.__isset_I32_thing, 'goodbye.__isset_I32_thing = '+BoolToString(goodbye.__isset_I32_thing));
-    Expect( goodbye.__isset_I64_thing, 'goodbye.__isset_I64_thing = '+BoolToString(goodbye.__isset_I64_thing));
-
-    Expect( hello.String_thing = 'Hello2', 'hello.String_thing = "'+hello.String_thing+'"');
-    Expect( hello.Byte_thing = 2, 'hello.Byte_thing = '+IntToStr(hello.Byte_thing));
-    Expect( hello.I32_thing = 2, 'hello.I32_thing = '+IntToStr(hello.I32_thing));
-    Expect( hello.I64_thing = 2, 'hello.I64_thing = '+IntToStr(hello.I64_thing));
-    Expect( hello.__isset_String_thing, 'hello.__isset_String_thing = '+BoolToString(hello.__isset_String_thing));
-    Expect( hello.__isset_Byte_thing, 'hello.__isset_Byte_thing = '+BoolToString(hello.__isset_Byte_thing));
-    Expect( hello.__isset_I32_thing, 'hello.__isset_I32_thing = '+BoolToString(hello.__isset_I32_thing));
-    Expect( hello.__isset_I64_thing, 'hello.__isset_I64_thing = '+BoolToString(hello.__isset_I64_thing));
+    Expect( crazy.Xtructs.Count = insane.Xtructs.Count, 'crazy.Xtructs.Count = '+IntToStr(crazy.Xtructs.Count));
+    for arg0 := 0 to insane.Xtructs.Count-1 do begin
+      hello   := insane.Xtructs[arg0];
+      goodbye := crazy.Xtructs[arg0];
+      Expect( goodbye.String_thing = hello.String_thing, 'goodbye.String_thing = '+goodbye.String_thing);
+      Expect( goodbye.Byte_thing = hello.Byte_thing, 'goodbye.Byte_thing = '+IntToStr(goodbye.Byte_thing));
+      Expect( goodbye.I32_thing = hello.I32_thing, 'goodbye.I32_thing = '+IntToStr(goodbye.I32_thing));
+      Expect( goodbye.I64_thing = hello.I64_thing, 'goodbye.I64_thing = '+IntToStr(goodbye.I64_thing));
+    end;
   end;
 
 
   // multi args
-  StartTestGroup( 'testMulti');
+  StartTestGroup( 'testMulti', test_BaseTypes);
   arg0 := 1;
   arg1 := 2;
   arg2 := High(Int64);
@@ -793,19 +885,21 @@
   Expect( i.__isset_I64_thing, 'testMulti: i.__isset_I64_thing = '+BoolToString(i.__isset_I64_thing));
 
   // multi exception
-  StartTestGroup( 'testMultiException(1)');
+  StartTestGroup( 'testMultiException(1)', test_Exceptions);
   try
     i := client.testMultiException( 'need more pizza', 'run out of beer');
     Expect( i.String_thing = 'run out of beer', 'i.String_thing = "' +i.String_thing+ '"');
     Expect( i.__isset_String_thing, 'i.__isset_String_thing = '+BoolToString(i.__isset_String_thing));
+    { this is not necessarily true, these fields are default-serialized
     Expect( not i.__isset_Byte_thing, 'i.__isset_Byte_thing = '+BoolToString(i.__isset_Byte_thing));
     Expect( not i.__isset_I32_thing, 'i.__isset_I32_thing = '+BoolToString(i.__isset_I32_thing));
     Expect( not i.__isset_I64_thing, 'i.__isset_I64_thing = '+BoolToString(i.__isset_I64_thing));
+    }
   except
-    on e:Exception do Expect( FALSE, 'Unexpected exception "'+e.ClassName+'"');
+    on e:Exception do Expect( FALSE, 'Unexpected exception "'+e.ClassName+'": '+e.Message);
   end;
 
-  StartTestGroup( 'testMultiException(Xception)');
+  StartTestGroup( 'testMultiException(Xception)', test_Exceptions);
   try
     i := client.testMultiException( 'Xception', 'second test');
     Expect( FALSE, 'testMultiException(''Xception''): must trow an exception');
@@ -816,10 +910,10 @@
       Expect( x.ErrorCode = 1001, 'x.ErrorCode = '+IntToStr(x.ErrorCode));
       Expect( x.Message_ = 'This is an Xception', 'x.Message = "'+x.Message_+'"');
     end;
-    on e:Exception do Expect( FALSE, 'Unexpected exception "'+e.ClassName+'"');
+    on e:Exception do Expect( FALSE, 'Unexpected exception "'+e.ClassName+'": '+e.Message);
   end;
 
-  StartTestGroup( 'testMultiException(Xception2)');
+  StartTestGroup( 'testMultiException(Xception2)', test_Exceptions);
   try
     i := client.testMultiException( 'Xception2', 'third test');
     Expect( FALSE, 'testMultiException(''Xception2''): must trow an exception');
@@ -830,23 +924,25 @@
       Expect( x.ErrorCode = 2002, 'x.ErrorCode = '+IntToStr(x.ErrorCode));
       Expect( x.Struct_thing.String_thing = 'This is an Xception2', 'x.Struct_thing.String_thing = "'+x.Struct_thing.String_thing+'"');
       Expect( x.Struct_thing.__isset_String_thing, 'x.Struct_thing.__isset_String_thing = '+BoolToString(x.Struct_thing.__isset_String_thing));
+      { this is not necessarily true, these fields are default-serialized
       Expect( not x.Struct_thing.__isset_Byte_thing, 'x.Struct_thing.__isset_Byte_thing = '+BoolToString(x.Struct_thing.__isset_Byte_thing));
       Expect( not x.Struct_thing.__isset_I32_thing, 'x.Struct_thing.__isset_I32_thing = '+BoolToString(x.Struct_thing.__isset_I32_thing));
       Expect( not x.Struct_thing.__isset_I64_thing, 'x.Struct_thing.__isset_I64_thing = '+BoolToString(x.Struct_thing.__isset_I64_thing));
+      }
     end;
-    on e:Exception do Expect( FALSE, 'Unexpected exception "'+e.ClassName+'"');
+    on e:Exception do Expect( FALSE, 'Unexpected exception "'+e.ClassName+'": '+e.Message);
   end;
 
 
   // oneway functions
-  StartTestGroup( 'Test Oneway(1)');
+  StartTestGroup( 'Test Oneway(1)', test_Unknown);
   client.testOneway(1);
   Expect( TRUE, 'Test Oneway(1)');  // success := no exception
 
   // call time
   {$IFDEF PerfTest}
   StartTestGroup( 'Test Calltime()');
-  StartTick := GetTIckCount;
+  StartTick := GetTickCount;
   for k := 0 to 1000 - 1 do
   begin
     client.testVoid();
@@ -855,10 +951,38 @@
   {$ENDIF PerfTest}
 
   // no more tests here
-  StartTestGroup( '');
+  StartTestGroup( '', test_Unknown);
 end;
 
 
+{$IFDEF SupportsAsync}
+procedure TClientThread.ClientAsyncTest;
+var
+  client : TThriftTest.IAsync;
+  s : string;
+  i8 : ShortInt;
+begin
+  StartTestGroup( 'Async Tests', test_Unknown);
+  client := TThriftTest.TClient.Create( FProtocol);
+  FTransport.Open;
+
+  // oneway void functions
+  client.testOnewayAsync(1).Wait;
+  Expect( TRUE, 'Test Oneway(1)');  // success := no exception
+
+  // normal functions
+  s := client.testStringAsync(HUGE_TEST_STRING).Value;
+  Expect( length(s) = length(HUGE_TEST_STRING),
+          'testString( length(HUGE_TEST_STRING) = '+IntToStr(Length(HUGE_TEST_STRING))+') '
+         +'=> length(result) = '+IntToStr(Length(s)));
+
+  i8 := client.testByte(1).Value;
+  Expect( i8 = 1, 'testByte(1) = ' + IntToStr( i8 ));
+end;
+{$ENDIF}
+
+
+{$IFDEF StressTest}
 procedure TClientThread.StressTest(const client : TThriftTest.Iface);
 begin
   while TRUE do begin
@@ -875,6 +999,50 @@
     end;
   end;
 end;
+{$ENDIF}
+
+
+function TClientThread.PrepareBinaryData( aRandomDist : Boolean; aSize : TTestSize) : TBytes;
+var i : Integer;
+begin
+  case aSize of
+    Empty          : SetLength( result, 0);
+    Normal         : SetLength( result, $100);
+    ByteArrayTest  : SetLength( result, SizeOf(TByteArray) + 128);
+    PipeWriteLimit : SetLength( result, 65535 + 128);
+  else
+    raise EArgumentException.Create('aSize');
+  end;
+
+  ASSERT( Low(result) = 0);
+  if Length(result) = 0 then Exit;
+
+  // linear distribution, unless random is requested
+  if not aRandomDist then begin
+    for i := Low(result) to High(result) do begin
+      result[i] := i mod $100;
+    end;
+    Exit;
+  end;
+
+  // random distribution of all 256 values
+  FillChar( result[0], Length(result) * SizeOf(result[0]), $0);
+  for i := Low(result) to High(result) do begin
+    result[i] := Byte( Random($100));
+  end;
+end;
+
+
+{$IFDEF Win64}
+procedure TClientThread.UseInterlockedExchangeAdd64;
+var a,b : Int64;
+begin
+  a := 1;
+  b := 2;
+  Thrift.Utils.InterlockedExchangeAdd64( a,b);
+  Expect( a = 3, 'InterlockedExchangeAdd64');
+end;
+{$ENDIF}
 
 
 procedure TClientThread.JSONProtocolReadWriteTest;
@@ -884,8 +1052,8 @@
 // other clients or servers expect as the real JSON. This is beyond the scope of this test.
 var prot   : IProtocol;
     stm    : TStringStream;
-    list   : IList;
-    binary, binRead : TBytes;
+    list   : TThriftList;
+    binary, binRead, emptyBinary : TBytes;
     i,iErr : Integer;
 const
   TEST_SHORT   = ShortInt( $FE);
@@ -895,14 +1063,20 @@
   TEST_DOUBLE  = -1.234e-56;
   DELTA_DOUBLE = TEST_DOUBLE * 1e-14;
   TEST_STRING  = 'abc-'#$00E4#$00f6#$00fc; // german umlauts (en-us: "funny chars")
+  // Test THRIFT-2336 and THRIFT-3404 with U+1D11E (G Clef symbol) and 'Русское Название';
+  G_CLEF_AND_CYRILLIC_TEXT = #$1d11e' '#$0420#$0443#$0441#$0441#$043a#$043e#$0435' '#$041d#$0430#$0437#$0432#$0430#$043d#$0438#$0435;
+  G_CLEF_AND_CYRILLIC_JSON = '"\ud834\udd1e \u0420\u0443\u0441\u0441\u043a\u043e\u0435 \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435"';
+  // test both possible solidus encodings
+  SOLIDUS_JSON_DATA = '"one/two\/three"';
+  SOLIDUS_EXCPECTED = 'one/two/three';
 begin
   stm  := TStringStream.Create;
   try
-    StartTestGroup( 'JsonProtocolTest');  // no more tests here
+    StartTestGroup( 'JsonProtocolTest', test_Unknown);
 
     // prepare binary data
-    SetLength( binary, $100);
-    for i := Low(binary) to High(binary) do binary[i] := i;
+    binary := PrepareBinaryData( FALSE, Normal);
+    SetLength( emptyBinary, 0); // empty binary data block
 
     // output setup
     prot := TJSONProtocolImpl.Create(
@@ -910,7 +1084,8 @@
                 nil, TThriftStreamAdapterDelphi.Create( stm, FALSE)));
 
     // write
-    prot.WriteListBegin( TListImpl.Create( TType.String_, 9));
+    Init( list, TType.String_, 9);
+    prot.WriteListBegin( list);
     prot.WriteBool( TRUE);
     prot.WriteBool( FALSE);
     prot.WriteByte( TEST_SHORT);
@@ -920,6 +1095,8 @@
     prot.WriteDouble( TEST_DOUBLE);
     prot.WriteString( TEST_STRING);
     prot.WriteBinary( binary);
+    prot.WriteString( '');  // empty string
+    prot.WriteBinary( emptyBinary); // empty binary data block
     prot.WriteListEnd;
 
     // input setup
@@ -942,6 +1119,8 @@
     Expect( abs(prot.ReadDouble-TEST_DOUBLE) < abs(DELTA_DOUBLE), 'WriteDouble/ReadDouble');
     Expect( prot.ReadString = TEST_STRING, 'WriteString/ReadString');
     binRead := prot.ReadBinary;
+    Expect( Length(prot.ReadString) = 0, 'WriteString/ReadString (empty string)');
+    Expect( Length(prot.ReadBinary) = 0, 'empty WriteBinary/ReadBinary (empty data block)');
     prot.ReadListEnd;
 
     // test binary data
@@ -959,17 +1138,59 @@
 
     Expect( stm.Position = stm.Size, 'Stream position after read');
 
+
+    // Solidus can be encoded in two ways. Make sure we can read both
+    stm.Position := 0;
+    stm.Size     := 0;
+    stm.WriteString(SOLIDUS_JSON_DATA);
+    stm.Position := 0;
+    prot := TJSONProtocolImpl.Create(
+              TStreamTransportImpl.Create(
+                TThriftStreamAdapterDelphi.Create( stm, FALSE), nil));
+    Expect( prot.ReadString = SOLIDUS_EXCPECTED, 'Solidus encoding');
+
+
+    // Widechars should work too. Do they?
+    // After writing, we ensure that we are able to read it back
+    // We can't assume hex-encoding, since (nearly) any Unicode char is valid JSON
+    stm.Position := 0;
+    stm.Size     := 0;
+    prot := TJSONProtocolImpl.Create(
+              TStreamTransportImpl.Create(
+                nil, TThriftStreamAdapterDelphi.Create( stm, FALSE)));
+    prot.WriteString( G_CLEF_AND_CYRILLIC_TEXT);
+    stm.Position := 0;
+    prot := TJSONProtocolImpl.Create(
+              TStreamTransportImpl.Create(
+                TThriftStreamAdapterDelphi.Create( stm, FALSE), nil));
+    Expect( prot.ReadString = G_CLEF_AND_CYRILLIC_TEXT, 'Writing JSON with chars > 8 bit');
+
+    // Widechars should work with hex-encoding too. Do they?
+    stm.Position := 0;
+    stm.Size     := 0;
+    stm.WriteString( G_CLEF_AND_CYRILLIC_JSON);
+    stm.Position := 0;
+    prot := TJSONProtocolImpl.Create(
+              TStreamTransportImpl.Create(
+                TThriftStreamAdapterDelphi.Create( stm, FALSE), nil));
+    Expect( prot.ReadString = G_CLEF_AND_CYRILLIC_TEXT, 'Reading JSON with chars > 8 bit');
+
+
   finally
     stm.Free;
     prot := nil;  //-> Release
-    StartTestGroup( '');  // no more tests here
+    StartTestGroup( '', test_Unknown);  // no more tests here
   end;
 end;
 
 
-procedure TClientThread.StartTestGroup( const aGroup : string);
+procedure TClientThread.StartTestGroup( const aGroup : string; const aTest : TTestGroup);
 begin
   FTestGroup := aGroup;
+  FCurrentTest := aTest;
+
+  Include( FExecuted, aTest);
+
   if FTestGroup <> '' then begin
     Console.WriteLine('');
     Console.WriteLine( aGroup+' tests');
@@ -986,12 +1207,14 @@
   end
   else begin
     FErrors.Add( FTestGroup+': '+aTestInfo);
+    Include( FFailed, FCurrentTest);
     Console.WriteLine( aTestInfo+': *** FAILED ***');
 
     // We have a failed test!
     // -> issue DebugBreak ONLY if a debugger is attached,
     // -> unhandled DebugBreaks would cause Windows to terminate the app otherwise
-    if IsDebuggerPresent then asm int 3 end;
+    if IsDebuggerPresent
+    then {$IFDEF CPUX64} DebugBreak {$ELSE} asm int 3 end {$ENDIF};
   end;
 end;
 
@@ -1023,18 +1246,31 @@
 end;
 
 
-constructor TClientThread.Create( const ATransport: ITransport; const AProtocol : IProtocol; ANumIteration: Integer);
+function TClientThread.CalculateExitCode : Byte;
+var test : TTestGroup;
 begin
-  inherited Create( True );
+  result := EXITCODE_SUCCESS;
+  for test := Low(TTestGroup) to High(TTestGroup) do begin
+    if (test in FFailed) or not (test in FExecuted)
+    then result := result or MAP_FAILURES_TO_EXITCODE_BITS[test];
+  end;
+end;
+
+
+constructor TClientThread.Create( const aSetup : TTestSetup; const aNumIteration: Integer);
+begin
+  FSetup := aSetup;
   FNumIteration := ANumIteration;
-  FTransport := ATransport;
-  FProtocol := AProtocol;
+
   FConsole := TThreadConsole.Create( Self );
+  FCurrentTest := test_Unknown;
 
   // error list: keep correct order, allow for duplicates
   FErrors := TStringList.Create;
   FErrors.Sorted := FALSE;
   FErrors.Duplicates := dupAccept;
+
+  inherited Create( TRUE);
 end;
 
 destructor TClientThread.Destroy;
@@ -1047,39 +1283,144 @@
 procedure TClientThread.Execute;
 var
   i : Integer;
-  proc : TThreadProcedure;
 begin
   // perform all tests
   try
-    for i := 0 to FNumIteration - 1 do
-    begin
-      ClientTest;
-      JSONProtocolReadWriteTest;
+    {$IFDEF Win64}
+    UseInterlockedExchangeAdd64;
+    {$ENDIF}
+    JSONProtocolReadWriteTest;
+
+    // must be run in the context of the thread
+    InitializeProtocolTransportStack;
+    try
+      for i := 0 to FNumIteration - 1 do begin
+        ClientTest;
+        {$IFDEF SupportsAsync}
+        ClientAsyncTest;
+        {$ENDIF}
+      end;
+
+      // report the outcome
+      ReportResults;
+      SetReturnValue( CalculateExitCode);
+
+    finally
+      ShutdownProtocolTransportStack;
     end;
+
   except
     on e:Exception do Expect( FALSE, 'unexpected exception: "'+e.message+'"');
   end;
+end;
 
-  // report the outcome
-  ReportResults;
 
-  // shutdown
-  proc := procedure
-  begin
-    if FTransport <> nil then
-    begin
+procedure TClientThread.InitializeProtocolTransportStack;
+var
+  streamtrans : IStreamTransport;
+  http : IHTTPClient;
+  sUrl : string;
+const
+  DEBUG_TIMEOUT   = 30 * 1000;
+  RELEASE_TIMEOUT = DEFAULT_THRIFT_TIMEOUT;
+  PIPE_TIMEOUT    = RELEASE_TIMEOUT;
+  HTTP_TIMEOUTS   = 10 * 1000;
+begin
+  // needed for HTTP clients as they utilize the MSXML COM components
+  OleCheck( CoInitialize( nil));
+
+  case FSetup.endpoint of
+    trns_Sockets: begin
+      Console.WriteLine('Using sockets ('+FSetup.host+' port '+IntToStr(FSetup.port)+')');
+      streamtrans := TSocketImpl.Create( FSetup.host, FSetup.port );
+      FTransport := streamtrans;
+    end;
+
+    trns_Http: begin
+      Console.WriteLine('Using HTTPClient');
+      if FSetup.useSSL
+      then sUrl := 'http://'
+      else sUrl := 'https://';
+      sUrl := sUrl + FSetup.host;
+      case FSetup.port of
+        80  : if FSetup.useSSL then sUrl := sUrl + ':'+ IntToStr(FSetup.port);
+        443 : if not FSetup.useSSL then sUrl := sUrl + ':'+ IntToStr(FSetup.port);
+      else
+        if FSetup.port > 0 then sUrl := sUrl + ':'+ IntToStr(FSetup.port);
+      end;
+      http := THTTPClientImpl.Create( sUrl);
+      http.DnsResolveTimeout := HTTP_TIMEOUTS;
+      http.ConnectionTimeout := HTTP_TIMEOUTS;
+      http.SendTimeout       := HTTP_TIMEOUTS;
+      http.ReadTimeout       := HTTP_TIMEOUTS;
+      FTransport := http;
+    end;
+
+    trns_EvHttp: begin
+      raise Exception.Create(ENDPOINT_TRANSPORTS[FSetup.endpoint]+' transport not implemented');
+    end;
+
+    trns_NamedPipes: begin
+      streamtrans := TNamedPipeTransportClientEndImpl.Create( FSetup.sPipeName, 0, nil, PIPE_TIMEOUT, PIPE_TIMEOUT);
+      FTransport := streamtrans;
+    end;
+
+    trns_AnonPipes: begin
+      streamtrans := TAnonymousPipeTransportImpl.Create( FSetup.hAnonRead, FSetup.hAnonWrite, FALSE);
+      FTransport := streamtrans;
+    end;
+
+  else
+    raise Exception.Create('Unhandled endpoint transport');
+  end;
+  ASSERT( FTransport <> nil);
+
+  // layered transports are not really meant to be stacked upon each other
+  if (trns_Framed in FSetup.layered) then begin
+    FTransport := TFramedTransportImpl.Create( FTransport);
+  end
+  else if (trns_Buffered in FSetup.layered) and (streamtrans <> nil) then begin
+    FTransport := TBufferedTransportImpl.Create( streamtrans, 32);  // small buffer to test read()
+  end;
+
+  if FSetup.useSSL then begin
+    raise Exception.Create('SSL/TLS not implemented');
+  end;
+
+  // create protocol instance, default to BinaryProtocol
+  case FSetup.protType of
+    prot_Binary  :  FProtocol := TBinaryProtocolImpl.Create( FTransport, BINARY_STRICT_READ, BINARY_STRICT_WRITE);
+    prot_JSON    :  FProtocol := TJSONProtocolImpl.Create( FTransport);
+    prot_Compact :  FProtocol := TCompactProtocolImpl.Create( FTransport);
+  else
+    raise Exception.Create('Unhandled protocol');
+  end;
+
+  ASSERT( (FTransport <> nil) and (FProtocol <> nil));
+end;
+
+
+procedure TClientThread.ShutdownProtocolTransportStack;
+begin
+  try
+    FProtocol := nil;
+
+    if FTransport <> nil then begin
       FTransport.Close;
       FTransport := nil;
     end;
-  end;
 
-  Synchronize( proc );
+  finally
+    CoUninitialize;
+  end;
 end;
 
+
 { TThreadConsole }
 
 constructor TThreadConsole.Create(AThread: TThread);
 begin
+  inherited Create;
   FThread := AThread;
 end;
 
diff --git a/lib/delphi/test/TestConstants.pas b/lib/delphi/test/TestConstants.pas
index f21a4bb..37969dc 100644
--- a/lib/delphi/test/TestConstants.pas
+++ b/lib/delphi/test/TestConstants.pas
@@ -21,13 +21,49 @@
 
 interface
 
+uses SysUtils;
+
 type
-  TKnownProtocol = ( prot_Binary,  // default binary protocol
-                     prot_JSON     // JSON protocol
-                   );
+  TKnownProtocol = (
+    prot_Binary,  // default binary protocol
+    prot_JSON,    // JSON protocol
+    prot_Compact
+  );
+
+  TServerType = (
+    srv_Simple,
+    srv_Nonblocking,
+    srv_Threadpool,
+    srv_Threaded
+  );
+
+  TEndpointTransport = (
+    trns_Sockets,
+    trns_Http,
+    trns_NamedPipes,
+    trns_AnonPipes,
+    trns_EvHttp  // as listed on http://thrift.apache.org/test
+  );
+
+  TLayeredTransport = (
+    trns_Buffered,
+    trns_Framed
+  );
+
+  TLayeredTransports = set of TLayeredTransport;
+
 const
-  KNOWN_PROTOCOLS : array[TKnownProtocol] of string
-                  = ('binary', 'JSON');
+  SERVER_TYPES : array[TServerType] of string
+                  = ('Simple', 'Nonblocking', 'Threadpool', 'Threaded');
+
+  THRIFT_PROTOCOLS : array[TKnownProtocol] of string
+                  = ('Binary', 'JSON', 'Compact');
+
+  LAYERED_TRANSPORTS : array[TLayeredTransport] of string
+                  = ('Buffered', 'Framed');
+
+  ENDPOINT_TRANSPORTS : array[TEndpointTransport] of string
+                  = ('Sockets', 'Http', 'Named Pipes','Anon Pipes', 'EvHttp');
 
   // defaults are: read=false, write=true
   BINARY_STRICT_READ  = FALSE;
@@ -106,8 +142,21 @@
                    + 'diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet '
                    + 'clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ';
 
+
+function BytesToHex( const bytes : TBytes) : string;
+
+
 implementation
 
-// nothing
+
+function BytesToHex( const bytes : TBytes) : string;
+var i : Integer;
+begin
+  result := '';
+  for i := Low(bytes) to High(bytes) do begin
+    result := result + IntToHex(bytes[i],2);
+  end;
+end;
+
 
 end.
diff --git a/lib/delphi/test/TestServer.pas b/lib/delphi/test/TestServer.pas
index 7b74e58..69cb175 100644
--- a/lib/delphi/test/TestServer.pas
+++ b/lib/delphi/test/TestServer.pas
@@ -19,6 +19,7 @@
 
 unit TestServer;
 
+{$I ../src/Thrift.Defines.inc}
 {$WARN SYMBOL_PLATFORM OFF}
 
 {.$DEFINE RunEndless}   // activate to interactively stress-test the server stop routines via Ctrl+C
@@ -28,17 +29,19 @@
 uses
   Windows, SysUtils,
   Generics.Collections,
-  Thrift.Console,
   Thrift.Server,
   Thrift.Transport,
   Thrift.Transport.Pipes,
   Thrift.Protocol,
   Thrift.Protocol.JSON,
+  Thrift.Protocol.Compact,
   Thrift.Collections,
   Thrift.Utils,
   Thrift.Test,
   Thrift,
   TestConstants,
+  TestServerEvents,
+  ConsoleHelper,
   Contnrs;
 
 type
@@ -56,11 +59,13 @@
         FServer : IServer;
       protected
         procedure testVoid();
+        function testBool(thing: Boolean): Boolean;
         function testString(const thing: string): string;
         function testByte(thing: ShortInt): ShortInt;
         function testI32(thing: Integer): Integer;
         function testI64(const thing: Int64): Int64;
         function testDouble(const thing: Double): Double;
+        function testBinary(const thing: TBytes): TBytes;
         function testStruct(const thing: IXtruct): IXtruct;
         function testNest(const thing: IXtruct2): IXtruct2;
         function testMap(const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
@@ -80,6 +85,9 @@
         procedure SetServer( const AServer : IServer );
       end;
 
+      class procedure PrintCmdLineHelp;
+      class procedure InvalidArgs;
+
       class procedure LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
       class procedure Execute( const args: array of string);
   end;
@@ -134,6 +142,12 @@
   Result := thing;
 end;
 
+function TTestServer.TTestHandlerImpl.testBinary(const thing: TBytes): TBytes;
+begin
+  Console.WriteLine('testBinary("' + BytesToHex( thing ) + '")');
+  Result := thing;
+end;
+
 function TTestServer.TTestHandlerImpl.testEnum(thing: TNumberz): TNumberz;
 begin
   Console.WriteLine('testEnum(' + IntToStr( Integer( thing)) + ')');
@@ -150,7 +164,7 @@
 
   if (arg = 'TException') then
   begin
-    raise TException.Create('');
+    raise TException.Create('TException');
   end;
 
   // else do not throw anything
@@ -171,44 +185,33 @@
 function TTestServer.TTestHandlerImpl.testInsanity(
   const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
 var
-  hello, goodbye : IXtruct;
-  crazy : IInsanity;
   looney : IInsanity;
   first_map : IThriftDictionary<TNumberz, IInsanity>;
   second_map : IThriftDictionary<TNumberz, IInsanity>;
   insane : IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
 
 begin
-
   Console.WriteLine('testInsanity()');
-  hello := TXtructImpl.Create;
-  hello.String_thing := 'Hello2';
-  hello.Byte_thing := 2;
-  hello.I32_thing := 2;
-  hello.I64_thing := 2;
 
-  goodbye := TXtructImpl.Create;
-  goodbye.String_thing := 'Goodbye4';
-  goodbye.Byte_thing := 4;
-  goodbye.I32_thing := 4;
-  goodbye.I64_thing := 4;
-
-  crazy := TInsanityImpl.Create;
-  crazy.UserMap := TThriftDictionaryImpl<TNumberz, Int64>.Create;
-  crazy.UserMap.AddOrSetValue( TNumberz.EIGHT, 8);
-  crazy.Xtructs := TThriftListImpl<IXtruct>.Create;
-  crazy.Xtructs.Add(goodbye);
-
-  looney := TInsanityImpl.Create;
-  crazy.UserMap.AddOrSetValue( TNumberz.FIVE, 5);
-  crazy.Xtructs.Add(hello);
+  (**
+   * So you think you've got this all worked, out eh?
+   *
+   * Creates a the returned map with these values and prints it out:
+   *   { 1 => { 2 => argument,
+   *            3 => argument,
+   *          },
+   *     2 => { 6 => <empty Insanity struct>, },
+   *   }
+   * @return map<UserId, map<Numberz,Insanity>> - a map with the above values
+   *)
 
   first_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
   second_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
 
-  first_map.AddOrSetValue( TNumberz.TWO, crazy);
-  first_map.AddOrSetValue( TNumberz.THREE, crazy);
+  first_map.AddOrSetValue( TNumberz.TWO, argument);
+  first_map.AddOrSetValue( TNumberz.THREE, argument);
 
+  looney := TInsanityImpl.Create;
   second_map.AddOrSetValue( TNumberz.SIX, looney);
 
   insane := TThriftDictionaryImpl<Int64, IThriftDictionary<TNumberz, IInsanity>>.Create;
@@ -312,7 +315,7 @@
   Console.WriteLine('testMultiException(' + arg0 + ', ' + arg1 + ')');
   if ( arg0 = 'Xception') then
   begin
-    raise TXception.Create( 1001, 'This is an Xception');  // test the new rich CTOR 
+    raise TXception.Create( 1001, 'This is an Xception');  // test the new rich CTOR
   end else
   if ( arg0 = 'Xception2') then
   begin
@@ -382,6 +385,12 @@
   end;
 end;
 
+function TTestServer.TTestHandlerImpl.testBool(thing: Boolean): Boolean;
+begin
+  Console.WriteLine('testBool(' + BoolToStr(thing,true) + ')');
+  Result := thing;
+end;
+
 function TTestServer.TTestHandlerImpl.testString( const thing: string): string;
 begin
   Console.WriteLine('teststring("' + thing + '")');
@@ -436,13 +445,41 @@
 { TTestServer }
 
 
+class procedure TTestServer.PrintCmdLineHelp;
+const HELPTEXT = ' [options]'#10
+               + #10
+               + 'Allowed options:'#10
+               + '  -h [ --help ]               produce help message'#10
+               + '  --port arg (=9090)          Port number to listen'#10
+               + '  --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)'#10
+               + '  --named-pipe arg            Windows Named Pipe (e.g. MyThriftPipe)'#10
+               + '  --server-type arg (=simple) type of server, "simple", "thread-pool",'#10
+               + '                              "threaded", or "nonblocking"'#10
+               + '  --transport arg (=socket)   transport: buffered, framed, http, anonpipe'#10
+               + '  --protocol arg (=binary)    protocol: binary, compact, json'#10
+               + '  --ssl                       Encrypted Transport using SSL'#10
+               + '  --processor-events          processor-events'#10
+               + '  -n [ --workers ] arg (=4)   Number of thread pools workers. Only valid for'#10
+               + '                              thread-pool server type'#10
+               ;
+begin
+  Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + HELPTEXT);
+end;
+
+class procedure TTestServer.InvalidArgs;
+begin
+  Console.WriteLine( 'Invalid args.');
+  Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + ' -h for more information');
+  Abort;
+end;
+
 class procedure TTestServer.LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
 //Launch child process and pass R/W anonymous pipe handles on cmd line.
 //This is a simple example and does not include elevation or other
 //advanced features.
 var pi : PROCESS_INFORMATION;
-		si : STARTUPINFO;
-		sArg, sHandles, sCmdLine : string;
+        si : STARTUPINFO;
+        sArg, sHandles, sCmdLine : string;
     i : Integer;
 begin
   GetStartupInfo( si);  //set startupinfo for the spawned process
@@ -473,16 +510,14 @@
   Win32Check( CreateProcess( nil, PChar(sCmdLine), nil,nil,TRUE,0,nil,nil,si,pi));
 
   CloseHandle( pi.hThread);
-	CloseHandle( pi.hProcess);
+    CloseHandle( pi.hProcess);
 end;
 
 
 class procedure TTestServer.Execute( const args: array of string);
 var
-  UseBufferedSockets : Boolean;
-  UseFramed : Boolean;
   Port : Integer;
-  AnonPipe : Boolean;
+  ServerEvents : Boolean;
   sPipeName : string;
   testHandler : ITestHandler;
   testProcessor : IProcessor;
@@ -492,68 +527,105 @@
   namedpipe : INamedPipeServerTransport;
   TransportFactory : ITransportFactory;
   ProtocolFactory : IProtocolFactory;
-  i : Integer;
+  i, numWorker : Integer;
   s : string;
-  protType, p : TKnownProtocol;
-const
-  // pipe timeouts to be used
-  DEBUG_TIMEOUT   = 30 * 1000;
-  RELEASE_TIMEOUT = 0;  // server-side default
-  TIMEOUT         = RELEASE_TIMEOUT;
+  protType : TKnownProtocol;
+  servertype : TServerType;
+  endpoint : TEndpointTransport;
+  layered : TLayeredTransports;
+  UseSSL : Boolean; // include where appropriate (TLayeredTransport?)
 begin
   try
-    UseBufferedSockets := False;
-    UseFramed := False;
-    AnonPipe := FALSE;
+    ServerEvents := FALSE;
     protType := prot_Binary;
+    servertype := srv_Simple;
+    endpoint := trns_Sockets;
+    layered := [];
+    UseSSL := FALSE;
     Port := 9090;
     sPipeName := '';
+    numWorker := 4;
 
     i := 0;
     while ( i < Length(args) ) do begin
       s := args[i];
       Inc(i);
 
-      if StrToIntDef( s, -1) > 0 then
-      begin
-        Port :=  StrToIntDef( s, Port);
+      // Allowed options:
+      if (s = '-h') or (s = '--help') then begin
+        // -h [ --help ]               produce help message
+        PrintCmdLineHelp;
+        Exit;
       end
-      else if ( s = 'raw' ) then
-      begin
-        // as default
+      else if (s = '--port') then begin
+        // --port arg (=9090)          Port number to listen
+        s := args[i];
+        Inc(i);
+        Port := StrToIntDef( s, Port);
       end
-      else if ( s = 'buffered' ) then
-      begin
-        UseBufferedSockets := True;
+      else if (s = '--domain-socket') then begin
+        // --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)
+        raise Exception.Create('domain-socket not supported');
       end
-      else if ( s = 'framed' ) then
-      begin
-        UseFramed := True;
-      end
-      else if (s = '-pipe') then
-      begin
+      else if (s = '--named-pipe') then begin
+        // --named-pipe arg            Windows Named Pipe (e.g. MyThriftPipe)
+        endpoint := trns_NamedPipes;
         sPipeName := args[i];  // -pipe <name>
         Inc( i );
       end
-      else if (s = '-anon') then
-      begin
-        AnonPipe := TRUE;
-      end
-      else if (s = '-prot') then  // -prot JSON|binary
-      begin
+      else if (s = '--server-type') then begin
+        // --server-type arg (=simple) type of server,
+        // arg = "simple", "thread-pool", "threaded", or "nonblocking"
         s := args[i];
-        Inc( i );
-        for p:= Low(TKnownProtocol) to High(TKnownProtocol) do begin
-          if SameText( s, KNOWN_PROTOCOLS[p]) then begin
-            protType := p;
-            Break;
-          end;
-        end;
-      end else
-      begin
-        // Fall back to the older boolean syntax
-        UseBufferedSockets := StrToBoolDef( args[1], UseBufferedSockets);
+        Inc(i);
+
+        if      s = 'simple'      then servertype := srv_Simple
+        else if s = 'thread-pool' then servertype := srv_Threadpool
+        else if s = 'threaded'    then servertype := srv_Threaded
+        else if s = 'nonblocking' then servertype := srv_Nonblocking
+        else InvalidArgs;
       end
+      else if (s = '--transport') then begin
+        // --transport arg (=buffered) transport: buffered, framed, http
+        s := args[i];
+        Inc(i);
+
+        if      s = 'buffered' then Include( layered, trns_Buffered)
+        else if s = 'framed'   then Include( layered, trns_Framed)
+        else if s = 'http'     then endpoint := trns_Http
+        else if s = 'anonpipe' then endpoint := trns_AnonPipes
+        else InvalidArgs;
+      end
+      else if (s = '--protocol') then begin
+        // --protocol arg (=binary)    protocol: binary, compact, json
+        s := args[i];
+        Inc(i);
+
+        if      s = 'binary'   then protType := prot_Binary
+        else if s = 'compact'  then protType := prot_Compact
+        else if s = 'json'     then protType := prot_JSON
+        else InvalidArgs;
+      end
+      else if (s = '--ssl') then begin
+        // --ssl     Encrypted Transport using SSL
+        UseSSL := TRUE;
+      end
+      else if (s = '--processor-events') then begin
+         // --processor-events          processor-events
+        ServerEvents := TRUE;
+      end
+      else if (s = '-n') or (s = '--workers') then begin
+        // -n [ --workers ] arg (=4)   Number of thread pools workers.
+        // Only valid for thread-pool server type
+        s := args[i];
+        numWorker := StrToIntDef(s,0);
+        if numWorker > 0
+        then Inc(i)
+        else numWorker := 4;
+      end
+      else begin
+        InvalidArgs;
+      end;
     end;
 
 
@@ -561,34 +633,49 @@
 
     // create protocol factory, default to BinaryProtocol
     case protType of
-      prot_Binary:  ProtocolFactory := TBinaryProtocolImpl.TFactory.Create( BINARY_STRICT_READ, BINARY_STRICT_WRITE);
-      prot_JSON  :  ProtocolFactory := TJSONProtocolImpl.TFactory.Create;
+      prot_Binary  :  ProtocolFactory := TBinaryProtocolImpl.TFactory.Create( BINARY_STRICT_READ, BINARY_STRICT_WRITE);
+      prot_JSON    :  ProtocolFactory := TJSONProtocolImpl.TFactory.Create;
+      prot_Compact :  ProtocolFactory := TCompactProtocolImpl.TFactory.Create;
     else
-      ASSERT( FALSE);  // unhandled case!
-      ProtocolFactory := TBinaryProtocolImpl.TFactory.Create( BINARY_STRICT_READ, BINARY_STRICT_WRITE);
+      raise Exception.Create('Unhandled protocol');
     end;
     ASSERT( ProtocolFactory <> nil);
-    Console.WriteLine('- '+KNOWN_PROTOCOLS[protType]+' protocol');
+    Console.WriteLine('- '+THRIFT_PROTOCOLS[protType]+' protocol');
 
+    case endpoint of
 
-    if sPipeName <> '' then begin
-      Console.WriteLine('- named pipe ('+sPipeName+')');
-      namedpipe   := TNamedPipeServerTransportImpl.Create( sPipeName, 4096, PIPE_UNLIMITED_INSTANCES, TIMEOUT);
-      servertrans := namedpipe;
-    end
-    else if AnonPipe then begin
-      Console.WriteLine('- anonymous pipes');
-      anonymouspipe := TAnonymousPipeServerTransportImpl.Create;
-      servertrans   := anonymouspipe;
-    end
-    else begin
-      Console.WriteLine('- sockets (port '+IntToStr(port)+')');
-      if UseBufferedSockets then Console.WriteLine('- buffered sockets');
-      servertrans := TServerSocketImpl.Create( Port, 0, UseBufferedSockets);
+      trns_Sockets : begin
+        Console.WriteLine('- sockets (port '+IntToStr(port)+')');
+        if (trns_Buffered in layered) then Console.WriteLine('- buffered');
+        servertrans := TServerSocketImpl.Create( Port, 0, (trns_Buffered in layered));
+      end;
+
+      trns_Http : begin
+        raise Exception.Create(ENDPOINT_TRANSPORTS[endpoint]+' server transport not implemented');
+      end;
+
+      trns_NamedPipes : begin
+        Console.WriteLine('- named pipe ('+sPipeName+')');
+        namedpipe   := TNamedPipeServerTransportImpl.Create( sPipeName, 4096, PIPE_UNLIMITED_INSTANCES);
+        servertrans := namedpipe;
+      end;
+
+      trns_AnonPipes : begin
+        Console.WriteLine('- anonymous pipes');
+        anonymouspipe := TAnonymousPipeServerTransportImpl.Create;
+        servertrans   := anonymouspipe;
+      end
+
+    else
+      raise Exception.Create('Unhandled endpoint transport');
     end;
     ASSERT( servertrans <> nil);
 
-    if UseFramed then begin
+    if UseSSL then begin
+      raise Exception.Create('SSL not implemented');
+    end;
+
+    if (trns_Framed in layered) then begin
       Console.WriteLine('- framed transport');
       TransportFactory := TFramedTransportImpl.TFactory.Create
     end
@@ -600,15 +687,36 @@
     testHandler   := TTestHandlerImpl.Create;
     testProcessor := TThriftTest.TProcessorImpl.Create( testHandler );
 
-    ServerEngine := TSimpleServer.Create( testProcessor,
-                                          ServerTrans,
-                                          TransportFactory,
-                                          ProtocolFactory);
+    case servertype of
+      srv_Simple      : begin
+        ServerEngine := TSimpleServer.Create( testProcessor, ServerTrans, TransportFactory, ProtocolFactory);
+      end;
+
+      srv_Nonblocking : begin
+        raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
+      end;
+
+      srv_Threadpool,
+      srv_Threaded: begin
+        if numWorker > 1 then {use here};
+        raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
+      end;
+
+    else
+      raise Exception.Create('Unhandled server type');
+    end;
+    ASSERT( ServerEngine <> nil);
 
     testHandler.SetServer( ServerEngine);
 
+    // test events?
+    if ServerEvents then begin
+      Console.WriteLine('- server events test enabled');
+      ServerEngine.ServerEvents := TServerEventsImpl.Create;
+    end;
+
     // start the client now when we have the anon handles, but before the server starts
-    if AnonPipe
+    if endpoint = trns_AnonPipes
     then LaunchAnonPipeChild( ExtractFilePath(ParamStr(0))+'client.exe', anonymouspipe);
 
     // install Ctrl+C handler before the server starts
@@ -625,9 +733,9 @@
     g_Handler := nil;
 
   except
-    on E: Exception do
-    begin
-      Console.Write( E.Message);
+    on E: EAbort do raise;
+    on E: Exception do begin
+      Console.WriteLine( E.Message + #10 + E.StackTrace );
     end;
   end;
   Console.WriteLine( 'done.');
diff --git a/lib/delphi/test/TestServerEvents.pas b/lib/delphi/test/TestServerEvents.pas
new file mode 100644
index 0000000..2208cd4
--- /dev/null
+++ b/lib/delphi/test/TestServerEvents.pas
@@ -0,0 +1,174 @@
+(*
+ * 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.
+ *)
+
+unit TestServerEvents;
+
+interface
+
+uses
+  SysUtils,
+  Thrift,
+  Thrift.Protocol,
+  Thrift.Transport,
+  Thrift.Server,
+  ConsoleHelper;
+
+type
+  TRequestEventsImpl = class( TInterfacedObject, IRequestEvents)
+  protected
+    FStart : TDateTime;
+    // IRequestProcessingEvents
+    procedure PreRead;
+    procedure PostRead;
+    procedure PreWrite;
+    procedure PostWrite;
+    procedure OnewayComplete;
+    procedure UnhandledError( const e : Exception);
+    procedure CleanupContext;
+  public
+    constructor Create;
+  end;
+
+
+  TProcessorEventsImpl = class( TInterfacedObject, IProcessorEvents)
+  protected
+    FReqs : Integer;
+    // IProcessorEvents
+    procedure Processing( const transport : ITransport);
+    function  CreateRequestContext( const aFunctionName : string) : IRequestEvents;
+    procedure CleanupContext;
+  public
+    constructor Create;
+  end;
+
+
+  TServerEventsImpl = class( TInterfacedObject, IServerEvents)
+  protected
+    // IServerEvents
+    procedure PreServe;
+    procedure PreAccept;
+    function  CreateProcessingContext( const input, output : IProtocol) : IProcessorEvents;
+  end;
+
+
+implementation
+
+{ TServerEventsImpl }
+
+procedure TServerEventsImpl.PreServe;
+begin
+  Console.WriteLine('ServerEvents: Server starting to serve requests');
+end;
+
+
+procedure TServerEventsImpl.PreAccept;
+begin
+  Console.WriteLine('ServerEvents: Server transport is ready to accept incoming calls');
+end;
+
+
+function TServerEventsImpl.CreateProcessingContext(const input, output: IProtocol): IProcessorEvents;
+begin
+  result := TProcessorEventsImpl.Create;
+end;
+
+
+{ TProcessorEventsImpl }
+
+constructor TProcessorEventsImpl.Create;
+begin
+  inherited Create;
+  FReqs := 0;
+  Console.WriteLine('ProcessorEvents: Client connected, processing begins');
+end;
+
+procedure TProcessorEventsImpl.Processing(const transport: ITransport);
+begin
+  Console.WriteLine('ProcessorEvents: Processing of incoming request begins');
+end;
+
+
+function TProcessorEventsImpl.CreateRequestContext( const aFunctionName: string): IRequestEvents;
+begin
+  result := TRequestEventsImpl.Create;
+  Inc( FReqs);
+end;
+
+
+procedure TProcessorEventsImpl.CleanupContext;
+begin
+  Console.WriteLine( 'ProcessorEvents: completed after handling '+IntToStr(FReqs)+' requests.');
+end;
+
+
+{ TRequestEventsImpl }
+
+
+constructor TRequestEventsImpl.Create;
+begin
+  inherited Create;
+  FStart := Now;
+  Console.WriteLine('RequestEvents: New request');
+end;
+
+
+procedure TRequestEventsImpl.PreRead;
+begin
+  Console.WriteLine('RequestEvents: Reading request message ...');
+end;
+
+
+procedure TRequestEventsImpl.PostRead;
+begin
+  Console.WriteLine('RequestEvents: Reading request message completed');
+end;
+
+procedure TRequestEventsImpl.PreWrite;
+begin
+  Console.WriteLine('RequestEvents: Writing response message ...');
+end;
+
+
+procedure TRequestEventsImpl.PostWrite;
+begin
+  Console.WriteLine('RequestEvents: Writing response message completed');
+end;
+
+
+procedure TRequestEventsImpl.OnewayComplete;
+begin
+  Console.WriteLine('RequestEvents: Oneway message processed');
+end;
+
+
+procedure TRequestEventsImpl.UnhandledError(const e: Exception);
+begin
+  Console.WriteLine('RequestEvents: Unhandled exception of type '+e.classname);
+end;
+
+
+procedure TRequestEventsImpl.CleanupContext;
+var millis : Double;
+begin
+  millis := (Now - FStart) * (24*60*60*1000);
+  Console.WriteLine( 'Request processing completed in '+IntToStr(Round(millis))+' ms');
+end;
+
+
+end.
diff --git a/lib/delphi/test/client.dpr b/lib/delphi/test/client.dpr
index 209e29d..06dbd3d 100644
--- a/lib/delphi/test/client.dpr
+++ b/lib/delphi/test/client.dpr
@@ -28,13 +28,17 @@
   Thrift.Test, // in 'gen-delphi\Thrift.Test.pas',
   Thrift in '..\src\Thrift.pas',
   Thrift.Transport in '..\src\Thrift.Transport.pas',
+  Thrift.Socket in '..\src\Thrift.Socket.pas',
+  Thrift.Exception in '..\src\Thrift.Exception.pas',
   Thrift.Transport.Pipes in '..\src\Thrift.Transport.Pipes.pas',
   Thrift.Protocol in '..\src\Thrift.Protocol.pas',
   Thrift.Protocol.JSON in '..\src\Thrift.Protocol.JSON.pas',
+  Thrift.Protocol.Compact in '..\src\Thrift.Protocol.Compact.pas',
+  Thrift.Protocol.Multiplex in '..\src\Thrift.Protocol.Multiplex.pas',
   Thrift.Collections in '..\src\Thrift.Collections.pas',
   Thrift.Server in '..\src\Thrift.Server.pas',
   Thrift.Stream in '..\src\Thrift.Stream.pas',
-  Thrift.Console in '..\src\Thrift.Console.pas',
+  Thrift.TypeRegistry in '..\src\Thrift.TypeRegistry.pas',
   Thrift.Utils in '..\src\Thrift.Utils.pas';
 
 var
@@ -42,24 +46,26 @@
   args : array of string;
   i : Integer;
   arg : string;
-  s : string;
 
 begin
   try
     Writeln( 'Delphi TestClient '+Thrift.Version);
     nParamCount := ParamCount;
     SetLength( args, nParamCount);
-    for i := 1 to nParamCount do
-    begin
+    for i := 1 to nParamCount do begin
       arg := ParamStr( i );
       args[i-1] := arg;
     end;
-    TTestClient.Execute( args );
-    Readln;
+
+    ExitCode := TTestClient.Execute( args);
+
   except
+    on E: EAbort do begin
+      ExitCode := $FF;
+    end;
     on E: Exception do begin
       Writeln(E.ClassName, ': ', E.Message);
-      ExitCode := $FFFF;
+      ExitCode := $FF;
     end;
   end;
 end.
diff --git a/lib/delphi/test/codegen/README.md b/lib/delphi/test/codegen/README.md
new file mode 100644
index 0000000..a014589
--- /dev/null
+++ b/lib/delphi/test/codegen/README.md
@@ -0,0 +1,28 @@
+How to use the test case:
+----------------------------------------------
+- copy and the template batch file
+- open the batch file and adjust configuration as necessary
+- run the batch
+
+
+Configuration:
+----------------------------------------------
+SVNWORKDIR
+should point to the Thrift working copy root
+
+MY_THRIFT_FILES
+can be set to point to a folder with more thrift IDL files.
+If you don't have any such files, just leave the setting blank.
+
+BIN
+Local MSYS binary folder. Your THRIFT.EXE is installed here.
+
+MINGW_BIN
+Local MinGW bin folder. Contains DLL files required by THRIFT.EXE
+
+DCC
+Identifies the Delphi Command Line compiler (dcc32.exe)
+To be configuired only, if the default is not suitable.
+
+----------------------------------------------
+*EOF*
\ No newline at end of file
diff --git a/lib/delphi/test/codegen/README.txt b/lib/delphi/test/codegen/README.txt
deleted file mode 100644
index d1447a1..0000000
--- a/lib/delphi/test/codegen/README.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-How to use the test case:
-----------------------------------------------
-- copy and the template batch file 
-- open the batch file and adjust configuration as necessary
-- run the batch
-
-
-Configuration:
-----------------------------------------------
-SVNWORKDIR 
-should point to the Thrift working copy root
-
-MY_THRIFT_FILES 
-can be set to point to a folder with more thrift IDL files. 
-If you don't have any such files, just leave the setting blank.
-
-BIN
-Local MSYS binary folder. Your THRIFT.EXE is installed here.
-
-MINGW_BIN
-Local MinGW bin folder. Contains DLL files required by THRIFT.EXE
-
-DCC
-Identifies the Delphi Command Line compiler (dcc32.exe)
-To be configuired only, if the default is not suitable.
-
-----------------------------------------------
-*EOF*
\ No newline at end of file
diff --git a/lib/delphi/test/codegen/ReservedKeywords.thrift b/lib/delphi/test/codegen/ReservedKeywords.thrift
deleted file mode 100644
index 83c1836..0000000
--- a/lib/delphi/test/codegen/ReservedKeywords.thrift
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-// make sure generated code does not produce name collisions with predefined keywords 
-
-
-
-typedef i32 Cardinal
-typedef string message
-typedef list< map< Cardinal, message>> program
-
-struct unit {
-  1: Cardinal downto;
-  2: program procedure;
-}
-
-typedef set< unit> units
-
-exception exception1 {
-  1: program message;
-  2: unit array;
-}
-
-service constructor {
-  unit Create(1: Cardinal asm; 2: message inherited) throws (1: exception1 label);
-  units Destroy();
-}
-
-const Cardinal downto = +1
-const Cardinal published = -1
-
-enum keywords {
-  record = 1,
-  repeat = 2,
-  deprecated = 3
-}
-
-
-
diff --git a/lib/delphi/test/codegen/run-Pascal-Codegen-Tests.bat.tmpl b/lib/delphi/test/codegen/run-Pascal-Codegen-Tests.bat.tmpl
index 6ccd260..dbab0ae 100644
--- a/lib/delphi/test/codegen/run-Pascal-Codegen-Tests.bat.tmpl
+++ b/lib/delphi/test/codegen/run-Pascal-Codegen-Tests.bat.tmpl
@@ -1,3 +1,21 @@
+REM /*
+REM * Licensed to the Apache Software Foundation (ASF) under one
+REM * or more contributor license agreements. See the NOTICE file
+REM * distributed with this work for additional information
+REM * regarding copyright ownership. The ASF licenses this file
+REM * to you under the Apache License, Version 2.0 (the
+REM * "License"); you may not use this file except in compliance
+REM * with the License. You may obtain a copy of the License at
+REM *
+REM *   http://www.apache.org/licenses/LICENSE-2.0
+REM *
+REM * Unless required by applicable law or agreed to in writing,
+REM * software distributed under the License is distributed on an
+REM * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+REM * KIND, either express or implied. See the License for the
+REM * specific language governing permissions and limitations
+REM * under the License.
+REM */
 @echo off
 if ""=="%1" goto CONFIG
 goto HANDLEDIR
@@ -44,7 +62,7 @@
 rem * create and/or empty target dirs
 if not exist "%TARGET%"           md "%TARGET%"
 if not exist "%TARGET%\%SUBDIR%"  md "%TARGET%\%SUBDIR%"
-if not exist "%OUTDCU%" 	      md "%OUTDCU%"
+if not exist "%OUTDCU%"           md "%OUTDCU%"
 if exist "%TARGET%\*.thrift"      del "%TARGET%\*.thrift"       /Q
 if exist "%TARGET%\%SUBDIR%\*.*"  del "%TARGET%\%SUBDIR%\*.*"   /Q
 if exist "%OUTDCU%\*.*"           del "%OUTDCU%\*.*"            /Q
@@ -58,7 +76,7 @@
 echo.
 echo Generating code, please wait ...
 cd "%TARGET%"
-for %%a in (*.thrift) do "%BIN%\thrift.exe" -v --gen delphi:ansistr_binary,register_types "%%a" 2>> "%LOGFILE%"
+for %%a in (*.thrift) do "%BIN%\thrift.exe" -v --gen delphi:register_types,constprefix,events,xmldoc "%%a" 2>> "%LOGFILE%"
 REM * for %%a in (*.thrift) do "%BIN%\thrift.exe" -v --gen cpp "%%a" >> NUL:
 cmd /c start notepad "%LOGFILE%"
 cd ..
@@ -70,31 +88,31 @@
 rem * generate a minimal DPR file that uses all generated pascal units
 cd "%TARGET%\%SUBDIR%\"
 if exist inherited.*  ren inherited.*  _inherited.*
-echo program %TESTAPP%;    					> %TESTAPP%.dpr
-echo {$APPTYPE CONSOLE}   					>> %TESTAPP%.dpr
-echo.    									>> %TESTAPP%.dpr
-echo uses 									>> %TESTAPP%.dpr
-for %%a in (*.pas) do echo   %%~na,			>> %TESTAPP%.dpr
-echo   Windows, Classes, SysUtils;			>> %TESTAPP%.dpr
-echo.    									>> %TESTAPP%.dpr
-echo begin 									>> %TESTAPP%.dpr
-echo   Writeln('Successfully compiled!');	>> %TESTAPP%.dpr
-echo   Writeln('List of units:');	>> %TESTAPP%.dpr
-for %%a in (*.pas) do echo   Write('%%~na':30,'':10);  >> %TESTAPP%.dpr
-echo   Writeln;	>> %TESTAPP%.dpr
-echo end. 									>> %TESTAPP%.dpr
-echo.    									>> %TESTAPP%.dpr
+echo program %TESTAPP%;                                           > %TESTAPP%.dpr
+echo {$APPTYPE CONSOLE}                                          >> %TESTAPP%.dpr
+echo.                                                            >> %TESTAPP%.dpr
+echo uses                                                        >> %TESTAPP%.dpr
+for %%a in (*.pas) do echo   %%~na,                              >> %TESTAPP%.dpr
+echo   Windows, Classes, SysUtils;                               >> %TESTAPP%.dpr
+echo.                                                            >> %TESTAPP%.dpr
+echo begin                                                       >> %TESTAPP%.dpr
+echo   Writeln('Successfully compiled!');                        >> %TESTAPP%.dpr
+echo   Writeln('List of units:');                                >> %TESTAPP%.dpr
+for %%a in (*.pas) do echo   Write('%%~na':30,'':10);            >> %TESTAPP%.dpr
+echo   Writeln;                                                  >> %TESTAPP%.dpr
+echo end.                                                        >> %TESTAPP%.dpr
+echo.                                                            >> %TESTAPP%.dpr
 cd ..\..
 
 rem * try to compile the DPR
 rem * this should not throw any errors, warnings or hints
-"%DCC%"  -B "%TARGET%\%SUBDIR%\%TESTAPP%" -U"%UNITSEARCH%" -I"%UNITSEARCH%" -N"%OUTDCU%" -E"%TARGET%\%SUBDIR%" 
+"%DCC%"  -B "%TARGET%\%SUBDIR%\%TESTAPP%" -U"%UNITSEARCH%" -I"%UNITSEARCH%" -N"%OUTDCU%" -E"%TARGET%\%SUBDIR%"
 dir "%TARGET%\%SUBDIR%\%TESTAPP%.exe"
 if not exist "%TARGET%\%SUBDIR%\%TESTAPP%.exe"  goto CODEGEN_FAILED
 echo.
 echo -----------------------------------------------------------------
 echo The compiled program is now executed. If it hangs or crashes, we
-echo have a serious problem with the generated code. Expected output 
+echo have a serious problem with the generated code. Expected output
 echo is "Successfully compiled:" followed by a list of generated units.
 echo -----------------------------------------------------------------
 "%TARGET%\%SUBDIR%\%TESTAPP%.exe"
@@ -106,10 +124,10 @@
 REM -----------------------------------------------------
 :DXE_NOT_FOUND
 REM -----------------------------------------------------
-echo Delphi Compiler (dcc32.exe) not found. 
+echo Delphi Compiler (dcc32.exe) not found.
 echo Please check the "DCC" setting in this batch.
 echo.
-cmd /c start notepad README.TXT
+cmd /c start notepad README.MD
 cmd /c start notepad %0
 pause
 GOTO EOF
@@ -119,7 +137,7 @@
 :CONFIG_ERROR
 REM -----------------------------------------------------
 echo Missing, incomplete or wrong configuration settings!
-cmd /c start notepad README.TXT
+cmd /c start notepad README.MD
 cmd /c start notepad %0
 pause
 GOTO EOF
diff --git a/lib/delphi/test/keywords/ReservedIncluded.thrift b/lib/delphi/test/keywords/ReservedIncluded.thrift
new file mode 100644
index 0000000..8b47a50
--- /dev/null
+++ b/lib/delphi/test/keywords/ReservedIncluded.thrift
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+// make sure generated code does not produce name collisions with predefined keywords
+namespace delphi SysUtils
+
+const i32 integer = 42
+
+// EOF
diff --git a/lib/delphi/test/keywords/ReservedKeywords.dpr b/lib/delphi/test/keywords/ReservedKeywords.dpr
new file mode 100644
index 0000000..1fbc8c1
--- /dev/null
+++ b/lib/delphi/test/keywords/ReservedKeywords.dpr
@@ -0,0 +1,15 @@
+program ReservedKeywords;
+
+{$APPTYPE CONSOLE}
+
+uses
+  SysUtils, System_;
+
+begin
+  try
+    { TODO -oUser -cConsole Main : Code hier einfügen }
+  except
+    on E: Exception do
+      Writeln(E.ClassName, ': ', E.Message);
+  end;
+end.
diff --git a/lib/delphi/test/keywords/ReservedKeywords.dproj b/lib/delphi/test/keywords/ReservedKeywords.dproj
new file mode 100644
index 0000000..6bd9544
--- /dev/null
+++ b/lib/delphi/test/keywords/ReservedKeywords.dproj
@@ -0,0 +1,112 @@
+	<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+		<PropertyGroup>
+			<ProjectGuid>{F2E9B6FC-A931-4271-8E30-5A4E402481B4}</ProjectGuid>
+			<MainSource>ReservedKeywords.dpr</MainSource>
+			<ProjectVersion>12.3</ProjectVersion>
+			<Basis>True</Basis>
+			<Config Condition="'$(Config)'==''">Debug</Config>
+			<Platform>Win32</Platform>
+			<AppType>Console</AppType>
+			<FrameworkType>None</FrameworkType>
+			<DCC_DCCCompiler>DCC32</DCC_DCCCompiler>
+		</PropertyGroup>
+		<PropertyGroup Condition="'$(Config)'=='Basis' or '$(Base)'!=''">
+			<Base>true</Base>
+		</PropertyGroup>
+		<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+			<Cfg_1>true</Cfg_1>
+			<CfgParent>Base</CfgParent>
+			<Base>true</Base>
+		</PropertyGroup>
+		<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+			<Cfg_2>true</Cfg_2>
+			<CfgParent>Base</CfgParent>
+			<Base>true</Base>
+		</PropertyGroup>
+		<PropertyGroup Condition="'$(Base)'!=''">
+			<DCC_ImageBase>00400000</DCC_ImageBase>
+			<DCC_DcuOutput>.\$(Config)\$(Platform)</DCC_DcuOutput>
+			<DCC_UnitSearchPath>gen-delphi;..\..\src;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+			<DCC_UnitAlias>WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;$(DCC_UnitAlias)</DCC_UnitAlias>
+			<DCC_ExeOutput>.\$(Config)\$(Platform)</DCC_ExeOutput>
+			<DCC_N>false</DCC_N>
+			<DCC_S>false</DCC_S>
+			<DCC_K>false</DCC_K>
+			<DCC_E>false</DCC_E>
+			<DCC_F>false</DCC_F>
+		</PropertyGroup>
+		<PropertyGroup Condition="'$(Cfg_1)'!=''">
+			<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+			<DCC_Optimize>false</DCC_Optimize>
+			<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+		</PropertyGroup>
+		<PropertyGroup Condition="'$(Cfg_2)'!=''">
+			<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+			<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+			<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+			<DCC_DebugInformation>false</DCC_DebugInformation>
+		</PropertyGroup>
+		<ItemGroup>
+			<DelphiCompile Include="ReservedKeywords.dpr">
+				<MainSource>MainSource</MainSource>
+			</DelphiCompile>
+			<BuildConfiguration Include="Release">
+				<Key>Cfg_2</Key>
+				<CfgParent>Base</CfgParent>
+			</BuildConfiguration>
+			<BuildConfiguration Include="Basis">
+				<Key>Base</Key>
+			</BuildConfiguration>
+			<BuildConfiguration Include="Debug">
+				<Key>Cfg_1</Key>
+				<CfgParent>Base</CfgParent>
+			</BuildConfiguration>
+		</ItemGroup>
+		<Import Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')" Project="$(BDS)\Bin\CodeGear.Delphi.Targets"/>
+		<Import Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')" Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj"/>
+		<PropertyGroup>
+			<PreBuildEvent><![CDATA[thrift -r  -gen delphi ReservedKeywords.thrift]]></PreBuildEvent>
+		</PropertyGroup>
+		<ProjectExtensions>
+			<Borland.Personality>Delphi.Personality.12</Borland.Personality>
+			<Borland.ProjectType/>
+			<BorlandProject>
+				<Delphi.Personality>
+					<VersionInfo>
+						<VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+						<VersionInfo Name="AutoIncBuild">False</VersionInfo>
+						<VersionInfo Name="MajorVer">1</VersionInfo>
+						<VersionInfo Name="MinorVer">0</VersionInfo>
+						<VersionInfo Name="Release">0</VersionInfo>
+						<VersionInfo Name="Build">0</VersionInfo>
+						<VersionInfo Name="Debug">False</VersionInfo>
+						<VersionInfo Name="PreRelease">False</VersionInfo>
+						<VersionInfo Name="Special">False</VersionInfo>
+						<VersionInfo Name="Private">False</VersionInfo>
+						<VersionInfo Name="DLL">False</VersionInfo>
+						<VersionInfo Name="Locale">1031</VersionInfo>
+						<VersionInfo Name="CodePage">1252</VersionInfo>
+					</VersionInfo>
+					<VersionInfoKeys>
+						<VersionInfoKeys Name="CompanyName"/>
+						<VersionInfoKeys Name="FileDescription"/>
+						<VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+						<VersionInfoKeys Name="InternalName"/>
+						<VersionInfoKeys Name="LegalCopyright"/>
+						<VersionInfoKeys Name="LegalTrademarks"/>
+						<VersionInfoKeys Name="OriginalFilename"/>
+						<VersionInfoKeys Name="ProductName"/>
+						<VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+						<VersionInfoKeys Name="Comments"/>
+					</VersionInfoKeys>
+					<Source>
+						<Source Name="MainSource">ReservedKeywords.dpr</Source>
+					</Source>
+				</Delphi.Personality>
+				<Platforms>
+					<Platform value="Win32">True</Platform>
+				</Platforms>
+			</BorlandProject>
+			<ProjectFileVersion>12</ProjectFileVersion>
+		</ProjectExtensions>
+	</Project>
diff --git a/lib/delphi/test/keywords/ReservedKeywords.thrift b/lib/delphi/test/keywords/ReservedKeywords.thrift
new file mode 100644
index 0000000..2f49d74
--- /dev/null
+++ b/lib/delphi/test/keywords/ReservedKeywords.thrift
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+// make sure generated code does not produce name collisions with predefined keywords
+namespace delphi System
+
+include "ReservedIncluded.thrift"
+
+
+typedef i32 Cardinal
+typedef string message
+typedef list< map< Cardinal, message>> program
+
+struct unit {
+  1: Cardinal downto;
+  2: program procedure;
+}
+
+typedef set< unit> units
+
+exception exception1 {
+  1: program message;
+  2: unit array;
+}
+
+service constructor {
+  unit Create(1: Cardinal asm; 2: message inherited) throws (1: exception1 label);
+  units Destroy();
+}
+
+const Cardinal downto = +1
+const Cardinal published = -1
+
+enum keywords {
+  record = 1,
+  repeat = 2,
+  deprecated = 3
+}
+
+
+struct Struct_lists {
+  1: list<Struct_simple> init;
+  2: list<Struct_simple> struc;
+  3: list<Struct_simple> field;
+  4: list<Struct_simple> field_;
+  5: list<Struct_simple> tracker;
+  6: list<Struct_simple> Self;
+}
+
+struct Struct_structs {
+  1: Struct_simple init;
+  2: Struct_simple struc;
+  3: Struct_simple field;
+  4: Struct_simple field_;
+  5: Struct_simple tracker;
+  6: Struct_simple Self;
+}
+
+struct Struct_simple {
+  1: bool init;
+  2: bool struc;
+  3: bool field;
+  4: bool field_;
+  5: bool tracker;
+  6: bool Self;
+}
+
+struct Struct_strings {
+  1: string init;
+  2: string struc;
+  3: string field;
+  4: string field_;
+  5: string tracker;
+  6: string Self;
+}
+
+struct Struct_binary {
+  1: binary init;
+  2: binary struc;
+  3: binary field;
+  4: binary field_;
+  5: binary tracker;
+  6: binary Self;
+}
+
+
+typedef i32 IProtocol 
+typedef i32 ITransport
+typedef i32 IFace
+typedef i32 IAsync
+typedef i32 System
+typedef i32 SysUtils
+typedef i32 Generics
+typedef i32 Thrift
+
+struct Struct_Thrift_Names {
+  1: IProtocol   IProtocol
+  2: ITransport  ITransport
+  3: IFace       IFace
+  4: IAsync      IAsync
+  5: System      System
+  6: SysUtils    SysUtils
+  7: Generics    Generics
+  8: Thrift      Thrift
+}
+
+
+enum Thrift4554_Enum {
+  Foo = 0,
+  Bar = 1,
+  Baz = 2,
+}
+
+struct Thrift4554_Struct {
+  1 : optional double MinValue
+  2 : optional double MaxValue
+  3 : optional bool Integer  // causes issue
+  4 : optional Thrift4554_Enum Foo
+}
+
+
+// EOF
diff --git a/lib/delphi/test/maketest.sh b/lib/delphi/test/maketest.sh
old mode 100644
new mode 100755
diff --git a/lib/delphi/test/multiplexed/Multiplex.Client.Main.pas b/lib/delphi/test/multiplexed/Multiplex.Client.Main.pas
index 2cc7ab0..35fdf6f 100644
--- a/lib/delphi/test/multiplexed/Multiplex.Client.Main.pas
+++ b/lib/delphi/test/multiplexed/Multiplex.Client.Main.pas
@@ -57,8 +57,8 @@
 
 type
   IServiceClient = interface
-    ['{7745C1C2-AB20-43BA-B6F0-08BF92DE0BAC}']

-    procedure Test;

+    ['{7745C1C2-AB20-43BA-B6F0-08BF92DE0BAC}']
+    procedure Test;
   end;
 
 //--- TTestClient -------------------------------------
@@ -70,14 +70,15 @@
   client := TTestClient.Create(args);
   try
     client.Run;
-  finally

-    client.Free;

+  finally
+    client.Free;
   end;
 end;
 
 
 constructor TTestClient.Create( const args: array of string);
 begin
+  inherited Create;
   ParseArgs(args);
   Setup;
 end;
@@ -120,8 +121,8 @@
     do Write(IntToStr(i)+' ');
     WriteLn;
   except
-    on e:Exception do Writeln(#10+e.Message);

-  end;

+    on e:Exception do Writeln(#10+e.Message);
+  end;
 end;
 
 
diff --git a/lib/delphi/test/multiplexed/Multiplex.Server.Main.pas b/lib/delphi/test/multiplexed/Multiplex.Server.Main.pas
index 4f5cd13..3860f5a 100644
--- a/lib/delphi/test/multiplexed/Multiplex.Server.Main.pas
+++ b/lib/delphi/test/multiplexed/Multiplex.Server.Main.pas
@@ -28,7 +28,6 @@
 uses
   Windows, SysUtils,
   Generics.Collections,
-  Thrift.Console,
   Thrift.Server,
   Thrift.Transport,
   Thrift.Transport.Pipes,
@@ -41,6 +40,7 @@
   Benchmark,  // in gen-delphi folder
   Aggr,       // in gen-delphi folder
   Multiplex.Test.Common,
+  ConsoleHelper,
   Contnrs;
 
 type
@@ -72,20 +72,20 @@
     TAggrImpl = class( TTestHandlerImpl, TAggr.Iface)
     protected
       FList : IThriftList<Integer>;
-    
+
       // TAggr.Iface
       procedure addValue(value: Integer);
-      function getValues(): IThriftList<Integer>;

-    public

-      constructor Create;

-      destructor Destroy;  override;

-    end;

+      function getValues(): IThriftList<Integer>;
+    public
+      constructor Create;
+      destructor Destroy;  override;
+    end;
 
   public
     class procedure Execute( const args: array of string);
   end;
 
-  
+
 implementation
 
 
@@ -105,45 +105,45 @@
   prev   := 0;
   result := 1;
   while n > 0 do begin
-    next   := result + prev;

-    prev   := result;

-    result := next;

-    Dec(n);

+    next   := result + prev;
+    prev   := result;
+    result := next;
+    Dec(n);
   end;
 end;
 
 { TTestServer.TAggrImpl }
 
 constructor TTestServer.TAggrImpl.Create;
-begin

+begin
   inherited Create;
   FList := TThriftListImpl<Integer>.Create;
 end;
 
-

-destructor TTestServer.TAggrImpl.Destroy;  

+
+destructor TTestServer.TAggrImpl.Destroy;
 begin
   try
-    FreeAndNil( FList);

-  finally

-    inherited Destroy;

-  end;                  
+    FreeAndNil( FList);
+  finally
+    inherited Destroy;
+  end;
 end;
 
-

+
 procedure TTestServer.TAggrImpl.addValue(value: Integer);
 begin
   FList.Add( value);
 end;
 
-

+
 function TTestServer.TAggrImpl.getValues(): IThriftList<Integer>;
 begin
   result := FList;
 end;
 
-

-{ TTestServer }    
+
+{ TTestServer }
 
 class procedure TTestServer.Execute( const args: array of string);
 var
diff --git a/lib/delphi/test/multiplexed/Multiplex.Test.Client.dpr b/lib/delphi/test/multiplexed/Multiplex.Test.Client.dpr
index 23e296a..4278d8f 100644
--- a/lib/delphi/test/multiplexed/Multiplex.Test.Client.dpr
+++ b/lib/delphi/test/multiplexed/Multiplex.Test.Client.dpr
@@ -23,19 +23,21 @@
 {$APPTYPE CONSOLE}
 
 uses
-  SysUtils,

-  Multiplex.Client.Main in 'Multiplex.Client.Main.pas',

-  Thrift in '..\..\src\Thrift.pas',

-  Thrift.Transport in '..\..\src\Thrift.Transport.pas',

-  Thrift.Transport.Pipes in '..\..\src\Thrift.Transport.Pipes.pas',

-  Thrift.Protocol in '..\..\src\Thrift.Protocol.pas',

-  Thrift.Protocol.Multiplex in '..\..\src\Thrift.Protocol.Multiplex.pas',

-  Thrift.Collections in '..\..\src\Thrift.Collections.pas',

-  Thrift.Server in '..\..\src\Thrift.Server.pas',

-  Thrift.Stream in '..\..\src\Thrift.Stream.pas',

-  Thrift.Console in '..\..\src\Thrift.Console.pas',

-  Thrift.Utils in '..\..\src\Thrift.Utils.pas';

-

+  SysUtils,
+  Multiplex.Client.Main in 'Multiplex.Client.Main.pas',
+  Thrift in '..\..\src\Thrift.pas',
+  Thrift.Socket in '..\..\src\Thrift.Socket.pas',
+  Thrift.Exception in '..\..\src\Thrift.Exception.pas',
+  Thrift.Transport in '..\..\src\Thrift.Transport.pas',
+  Thrift.Transport.Pipes in '..\..\src\Thrift.Transport.Pipes.pas',
+  Thrift.Protocol in '..\..\src\Thrift.Protocol.pas',
+  Thrift.Protocol.Multiplex in '..\..\src\Thrift.Protocol.Multiplex.pas',
+  Thrift.Collections in '..\..\src\Thrift.Collections.pas',
+  Thrift.Server in '..\..\src\Thrift.Server.pas',
+  Thrift.Stream in '..\..\src\Thrift.Stream.pas',
+  Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
+  Thrift.Utils in '..\..\src\Thrift.Utils.pas';
+
 var
   nParamCount : Integer;
   args : array of string;
diff --git a/lib/delphi/test/multiplexed/Multiplex.Test.Common.pas b/lib/delphi/test/multiplexed/Multiplex.Test.Common.pas
index 231c3ad..2caf081 100644
--- a/lib/delphi/test/multiplexed/Multiplex.Test.Common.pas
+++ b/lib/delphi/test/multiplexed/Multiplex.Test.Common.pas
@@ -1,35 +1,35 @@
-(*

- * 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.

- *)

-

-unit Multiplex.Test.Common;

-

-interface

-

-const

-  NAME_BENCHMARKSERVICE = 'BenchmarkService';

-  NAME_AGGR             = 'Aggr';

-

-

-implementation

-

-// nix

-

-end.

-

-

+(*
+ * 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.
+ *)
+
+unit Multiplex.Test.Common;
+
+interface
+
+const
+  NAME_BENCHMARKSERVICE = 'BenchmarkService';
+  NAME_AGGR             = 'Aggr';
+
+
+implementation
+
+// nix
+
+end.
+
+
diff --git a/lib/delphi/test/multiplexed/Multiplex.Test.Server.dpr b/lib/delphi/test/multiplexed/Multiplex.Test.Server.dpr
index 9da1cdc..120462b 100644
--- a/lib/delphi/test/multiplexed/Multiplex.Test.Server.dpr
+++ b/lib/delphi/test/multiplexed/Multiplex.Test.Server.dpr
@@ -22,20 +22,23 @@
 {$APPTYPE CONSOLE}
 
 uses
-  SysUtils,

-  Multiplex.Server.Main in 'Multiplex.Server.Main.pas',

-  Thrift in '..\..\src\Thrift.pas',

-  Thrift.Transport in '..\..\src\Thrift.Transport.pas',

-  Thrift.Transport.Pipes in '..\..\src\Thrift.Transport.Pipes.pas',

-  Thrift.Protocol in '..\..\src\Thrift.Protocol.pas',

-  Thrift.Protocol.Multiplex in '..\..\src\Thrift.Protocol.Multiplex.pas',

-  Thrift.Processor.Multiplex in '..\..\src\Thrift.Processor.Multiplex.pas',

-  Thrift.Collections in '..\..\src\Thrift.Collections.pas',

-  Thrift.Server in '..\..\src\Thrift.Server.pas',

-  Thrift.Console in '..\..\src\Thrift.Console.pas',

-  Thrift.Utils in '..\..\src\Thrift.Utils.pas',

-  Thrift.Stream in '..\..\src\Thrift.Stream.pas';

-

+  SysUtils,
+  Multiplex.Server.Main in 'Multiplex.Server.Main.pas',
+  ConsoleHelper in '..\ConsoleHelper.pas',
+  Thrift in '..\..\src\Thrift.pas',
+  Thrift.Exception in '..\..\src\Thrift.Exception.pas',
+  Thrift.Socket in '..\..\src\Thrift.Socket.pas',
+  Thrift.Transport in '..\..\src\Thrift.Transport.pas',
+  Thrift.Transport.Pipes in '..\..\src\Thrift.Transport.Pipes.pas',
+  Thrift.Protocol in '..\..\src\Thrift.Protocol.pas',
+  Thrift.Protocol.Multiplex in '..\..\src\Thrift.Protocol.Multiplex.pas',
+  Thrift.Processor.Multiplex in '..\..\src\Thrift.Processor.Multiplex.pas',
+  Thrift.Collections in '..\..\src\Thrift.Collections.pas',
+  Thrift.Server in '..\..\src\Thrift.Server.pas',
+  Thrift.Utils in '..\..\src\Thrift.Utils.pas',
+  Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
+  Thrift.Stream in '..\..\src\Thrift.Stream.pas';
+
 var
   nParamCount : Integer;
   args : array of string;
diff --git a/lib/delphi/test/serializer/TestSerializer.Data.pas b/lib/delphi/test/serializer/TestSerializer.Data.pas
index 34ad4f6..5fc0070 100644
--- a/lib/delphi/test/serializer/TestSerializer.Data.pas
+++ b/lib/delphi/test/serializer/TestSerializer.Data.pas
@@ -22,6 +22,7 @@
 interface
 
 uses
+  SysUtils,
   Thrift.Collections,
   DebugProtoTest;
 
@@ -194,7 +195,7 @@
   {$IF cDebugProtoTest_Option_AnsiStr_Binary}
   result.SetBase64('base64');
   {$ELSE}
-  not yet impl
+  result.SetBase64( TEncoding.UTF8.GetBytes('base64'));
   {$IFEND}
 
   // byte, i16, and i64 lists are populated by default constructor
@@ -283,65 +284,67 @@
 // superhuge compact proto test struct
 begin
   result := TCompactProtoTestStructImpl.Create;
-  result.A_byte := TConstants.COMPACT_TEST.A_byte;
-  result.A_i16 := TConstants.COMPACT_TEST.A_i16;
-  result.A_i32 := TConstants.COMPACT_TEST.A_i32;
-  result.A_i64 := TConstants.COMPACT_TEST.A_i64;
-  result.A_double := TConstants.COMPACT_TEST.A_double;
-  result.A_string := TConstants.COMPACT_TEST.A_string;
-  result.A_binary := TConstants.COMPACT_TEST.A_binary;
-  result.True_field := TConstants.COMPACT_TEST.True_field;
-  result.False_field := TConstants.COMPACT_TEST.False_field;
-  result.Empty_struct_field := TConstants.COMPACT_TEST.Empty_struct_field;
-  result.Byte_list := TConstants.COMPACT_TEST.Byte_list;
-  result.I16_list := TConstants.COMPACT_TEST.I16_list;
-  result.I32_list := TConstants.COMPACT_TEST.I32_list;
-  result.I64_list := TConstants.COMPACT_TEST.I64_list;
-  result.Double_list := TConstants.COMPACT_TEST.Double_list;
-  result.String_list := TConstants.COMPACT_TEST.String_list;
-  result.Binary_list := TConstants.COMPACT_TEST.Binary_list;
-  result.Boolean_list := TConstants.COMPACT_TEST.Boolean_list;
-  result.Struct_list := TConstants.COMPACT_TEST.Struct_list;
-  result.Byte_set := TConstants.COMPACT_TEST.Byte_set;
-  result.I16_set := TConstants.COMPACT_TEST.I16_set;
-  result.I32_set := TConstants.COMPACT_TEST.I32_set;
-  result.I64_set := TConstants.COMPACT_TEST.I64_set;
-  result.Double_set := TConstants.COMPACT_TEST.Double_set;
-  result.String_set := TConstants.COMPACT_TEST.String_set;
-  result.String_set := TConstants.COMPACT_TEST.String_set;
-  result.String_set := TConstants.COMPACT_TEST.String_set;
-  result.Binary_set := TConstants.COMPACT_TEST.Binary_set;
-  result.Boolean_set := TConstants.COMPACT_TEST.Boolean_set;
-  result.Struct_set := TConstants.COMPACT_TEST.Struct_set;
-  result.Byte_byte_map := TConstants.COMPACT_TEST.Byte_byte_map;
-  result.I16_byte_map := TConstants.COMPACT_TEST.I16_byte_map;
-  result.I32_byte_map := TConstants.COMPACT_TEST.I32_byte_map;
-  result.I64_byte_map := TConstants.COMPACT_TEST.I64_byte_map;
-  result.Double_byte_map := TConstants.COMPACT_TEST.Double_byte_map;
-  result.String_byte_map := TConstants.COMPACT_TEST.String_byte_map;
-  result.Binary_byte_map := TConstants.COMPACT_TEST.Binary_byte_map;
-  result.Boolean_byte_map := TConstants.COMPACT_TEST.Boolean_byte_map;
-  result.Byte_i16_map := TConstants.COMPACT_TEST.Byte_i16_map;
-  result.Byte_i32_map := TConstants.COMPACT_TEST.Byte_i32_map;
-  result.Byte_i64_map := TConstants.COMPACT_TEST.Byte_i64_map;
-  result.Byte_double_map := TConstants.COMPACT_TEST.Byte_double_map;
-  result.Byte_string_map := TConstants.COMPACT_TEST.Byte_string_map;
-  result.Byte_binary_map := TConstants.COMPACT_TEST.Byte_binary_map;
-  result.Byte_boolean_map := TConstants.COMPACT_TEST.Byte_boolean_map;
-  result.List_byte_map := TConstants.COMPACT_TEST.List_byte_map;
-  result.Set_byte_map := TConstants.COMPACT_TEST.Set_byte_map;
-  result.Map_byte_map := TConstants.COMPACT_TEST.Map_byte_map;
-  result.Byte_map_map := TConstants.COMPACT_TEST.Byte_map_map;
-  result.Byte_set_map := TConstants.COMPACT_TEST.Byte_set_map;
-  result.Byte_list_map := TConstants.COMPACT_TEST.Byte_list_map;
+  result.A_byte := TDebugProtoTestConstants.COMPACT_TEST.A_byte;
+  result.A_i16 := TDebugProtoTestConstants.COMPACT_TEST.A_i16;
+  result.A_i32 := TDebugProtoTestConstants.COMPACT_TEST.A_i32;
+  result.A_i64 := TDebugProtoTestConstants.COMPACT_TEST.A_i64;
+  result.A_double := TDebugProtoTestConstants.COMPACT_TEST.A_double;
+  result.A_string := TDebugProtoTestConstants.COMPACT_TEST.A_string;
+  result.A_binary := TDebugProtoTestConstants.COMPACT_TEST.A_binary;
+  result.True_field := TDebugProtoTestConstants.COMPACT_TEST.True_field;
+  result.False_field := TDebugProtoTestConstants.COMPACT_TEST.False_field;
+  result.Empty_struct_field := TDebugProtoTestConstants.COMPACT_TEST.Empty_struct_field;
+  result.Byte_list := TDebugProtoTestConstants.COMPACT_TEST.Byte_list;
+  result.I16_list := TDebugProtoTestConstants.COMPACT_TEST.I16_list;
+  result.I32_list := TDebugProtoTestConstants.COMPACT_TEST.I32_list;
+  result.I64_list := TDebugProtoTestConstants.COMPACT_TEST.I64_list;
+  result.Double_list := TDebugProtoTestConstants.COMPACT_TEST.Double_list;
+  result.String_list := TDebugProtoTestConstants.COMPACT_TEST.String_list;
+  result.Binary_list := TDebugProtoTestConstants.COMPACT_TEST.Binary_list;
+  result.Boolean_list := TDebugProtoTestConstants.COMPACT_TEST.Boolean_list;
+  result.Struct_list := TDebugProtoTestConstants.COMPACT_TEST.Struct_list;
+  result.Byte_set := TDebugProtoTestConstants.COMPACT_TEST.Byte_set;
+  result.I16_set := TDebugProtoTestConstants.COMPACT_TEST.I16_set;
+  result.I32_set := TDebugProtoTestConstants.COMPACT_TEST.I32_set;
+  result.I64_set := TDebugProtoTestConstants.COMPACT_TEST.I64_set;
+  result.Double_set := TDebugProtoTestConstants.COMPACT_TEST.Double_set;
+  result.String_set := TDebugProtoTestConstants.COMPACT_TEST.String_set;
+  result.String_set := TDebugProtoTestConstants.COMPACT_TEST.String_set;
+  result.String_set := TDebugProtoTestConstants.COMPACT_TEST.String_set;
+  result.Binary_set := TDebugProtoTestConstants.COMPACT_TEST.Binary_set;
+  result.Boolean_set := TDebugProtoTestConstants.COMPACT_TEST.Boolean_set;
+  result.Struct_set := TDebugProtoTestConstants.COMPACT_TEST.Struct_set;
+  result.Byte_byte_map := TDebugProtoTestConstants.COMPACT_TEST.Byte_byte_map;
+  result.I16_byte_map := TDebugProtoTestConstants.COMPACT_TEST.I16_byte_map;
+  result.I32_byte_map := TDebugProtoTestConstants.COMPACT_TEST.I32_byte_map;
+  result.I64_byte_map := TDebugProtoTestConstants.COMPACT_TEST.I64_byte_map;
+  result.Double_byte_map := TDebugProtoTestConstants.COMPACT_TEST.Double_byte_map;
+  result.String_byte_map := TDebugProtoTestConstants.COMPACT_TEST.String_byte_map;
+  result.Binary_byte_map := TDebugProtoTestConstants.COMPACT_TEST.Binary_byte_map;
+  result.Boolean_byte_map := TDebugProtoTestConstants.COMPACT_TEST.Boolean_byte_map;
+  result.Byte_i16_map := TDebugProtoTestConstants.COMPACT_TEST.Byte_i16_map;
+  result.Byte_i32_map := TDebugProtoTestConstants.COMPACT_TEST.Byte_i32_map;
+  result.Byte_i64_map := TDebugProtoTestConstants.COMPACT_TEST.Byte_i64_map;
+  result.Byte_double_map := TDebugProtoTestConstants.COMPACT_TEST.Byte_double_map;
+  result.Byte_string_map := TDebugProtoTestConstants.COMPACT_TEST.Byte_string_map;
+  result.Byte_binary_map := TDebugProtoTestConstants.COMPACT_TEST.Byte_binary_map;
+  result.Byte_boolean_map := TDebugProtoTestConstants.COMPACT_TEST.Byte_boolean_map;
+  result.List_byte_map := TDebugProtoTestConstants.COMPACT_TEST.List_byte_map;
+  result.Set_byte_map := TDebugProtoTestConstants.COMPACT_TEST.Set_byte_map;
+  result.Map_byte_map := TDebugProtoTestConstants.COMPACT_TEST.Map_byte_map;
+  result.Byte_map_map := TDebugProtoTestConstants.COMPACT_TEST.Byte_map_map;
+  result.Byte_set_map := TDebugProtoTestConstants.COMPACT_TEST.Byte_set_map;
+  result.Byte_list_map := TDebugProtoTestConstants.COMPACT_TEST.Byte_list_map;
 
   {$IF cDebugProtoTest_Option_AnsiStr_Binary}
   result.A_binary := AnsiString( #0#1#2#3#4#5#6#7#8);
   {$ELSE}
-  not yet impl
+  result.A_binary := TEncoding.UTF8.GetBytes( #0#1#2#3#4#5#6#7#8);
   {$IFEND}
 end;
 
 
+
+
 end.
 
diff --git a/lib/delphi/test/serializer/TestSerializer.dpr b/lib/delphi/test/serializer/TestSerializer.dpr
index 60e55c1..51e22a4 100644
--- a/lib/delphi/test/serializer/TestSerializer.dpr
+++ b/lib/delphi/test/serializer/TestSerializer.dpr
@@ -17,22 +17,25 @@
  * under the License.
  *)
 
-program skiptest_version1;
+program TestSerializer;
 
 {$APPTYPE CONSOLE}
 
 uses
   Classes, Windows, SysUtils, Generics.Collections,
   Thrift in '..\..\src\Thrift.pas',
+  Thrift.Exception in '..\..\src\Thrift.Exception.pas',
+  Thrift.Socket in '..\..\src\Thrift.Socket.pas',
   Thrift.Transport in '..\..\src\Thrift.Transport.pas',
   Thrift.Protocol in '..\..\src\Thrift.Protocol.pas',
   Thrift.Protocol.JSON in '..\..\src\Thrift.Protocol.JSON.pas',
   Thrift.Collections in '..\..\src\Thrift.Collections.pas',
   Thrift.Server in '..\..\src\Thrift.Server.pas',
-  Thrift.Console in '..\..\src\Thrift.Console.pas',
   Thrift.Utils in '..\..\src\Thrift.Utils.pas',
   Thrift.Serializer in '..\..\src\Thrift.Serializer.pas',
   Thrift.Stream in '..\..\src\Thrift.Stream.pas',
+  Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
+  System_,
   DebugProtoTest,
   TestSerializer.Data;
 
@@ -48,11 +51,13 @@
     class procedure Deserialize( const input : TBytes; const target : IBase; const factory : IProtocolFactory);  overload;
     class procedure Deserialize( const input : TStream; const target : IBase; const factory : IProtocolFactory);  overload;
 
+    procedure Test_Serializer_Deserializer;
+
   public
     constructor Create;
     destructor Destroy;  override;
 
-    procedure TestDeserialize;
+    procedure RunTests;
   end;
 
 
@@ -78,9 +83,10 @@
   end;
 end;
 
-
-procedure TTestSerializer.TestDeserialize;
 type TMethod = (mt_Bytes, mt_Stream);
+
+
+procedure TTestSerializer.Test_Serializer_Deserializer;
 var level3ooe, correct : IOneOfEach;
     factory : IProtocolFactory;
     bytes   : TBytes;
@@ -153,6 +159,19 @@
 end;
 
 
+procedure TTestSerializer.RunTests;
+begin
+  try
+    Test_Serializer_Deserializer;
+  except
+    on e:Exception do begin
+      Writeln( e.Message);
+      Write('Hit ENTER to close ... '); Readln;
+    end;
+  end;
+end;
+
+
 class function TTestSerializer.Serialize(const input : IBase; const factory : IProtocolFactory) : TBytes;
 var serial : TSerializer;
 begin
@@ -204,7 +223,7 @@
 begin
   test := TTestSerializer.Create;
   try
-    test.TestDeserialize;
+    test.RunTests;
   finally
     test.Free;
   end;
diff --git a/lib/delphi/test/server.dpr b/lib/delphi/test/server.dpr
index ca485af..b5e48a6 100644
--- a/lib/delphi/test/server.dpr
+++ b/lib/delphi/test/server.dpr
@@ -24,15 +24,21 @@
 uses
   SysUtils,
   TestServer in 'TestServer.pas',
+  TestServerEvents in 'TestServerEvents.pas',
   Thrift.Test,  // in gen-delphi folder
   Thrift in '..\src\Thrift.pas',
+  Thrift.Exception in '..\src\Thrift.Exception.pas',
   Thrift.Transport in '..\src\Thrift.Transport.pas',
+  Thrift.Socket in '..\src\Thrift.Socket.pas',
   Thrift.Transport.Pipes in '..\src\Thrift.Transport.Pipes.pas',
   Thrift.Protocol in '..\src\Thrift.Protocol.pas',
   Thrift.Protocol.JSON in '..\src\Thrift.Protocol.JSON.pas',
+  Thrift.Protocol.Compact in '..\src\Thrift.Protocol.Compact.pas',
+  Thrift.Protocol.Multiplex in '..\src\Thrift.Protocol.Multiplex.pas',
+  Thrift.Processor.Multiplex in '..\src\Thrift.Processor.Multiplex.pas',
   Thrift.Collections in '..\src\Thrift.Collections.pas',
   Thrift.Server in '..\src\Thrift.Server.pas',
-  Thrift.Console in '..\src\Thrift.Console.pas',
+  Thrift.TypeRegistry in '..\src\Thrift.TypeRegistry.pas',
   Thrift.Utils in '..\src\Thrift.Utils.pas',
   Thrift.Stream in '..\src\Thrift.Stream.pas';
 
@@ -41,23 +47,27 @@
   args : array of string;
   i : Integer;
   arg : string;
-  s : string;
 
 begin
   try
     Writeln( 'Delphi TestServer '+Thrift.Version);
     nParamCount := ParamCount;
     SetLength( args, nParamCount);
-    for i := 1 to nParamCount do
-    begin
+    for i := 1 to nParamCount do begin
       arg := ParamStr( i );
       args[i-1] := arg;
     end;
+
     TTestServer.Execute( args );
-    Writeln('Press ENTER to close ... '); Readln;
+
   except
-    on E: Exception do
+    on E: EAbort do begin
+      ExitCode := $FF;
+    end;
+    on E: Exception do begin
       Writeln(E.ClassName, ': ', E.Message);
+      ExitCode := $FF;
+    end;
   end;
 end.
 
diff --git a/lib/delphi/test/skip/README.md b/lib/delphi/test/skip/README.md
new file mode 100644
index 0000000..f349368
--- /dev/null
+++ b/lib/delphi/test/skip/README.md
@@ -0,0 +1,11 @@
+These two projects belong together. Both programs
+simulate server and client for different versions
+of the same protocol.
+
+The intention of this test is to ensure fully
+working compatibility features of the Delphi Thrift
+implementation.
+
+The expected test result is, that no errors occur
+with both programs, regardless in which order they
+might be started.
diff --git a/lib/delphi/test/skip/README.txt b/lib/delphi/test/skip/README.txt
deleted file mode 100644
index 90d5ff5..0000000
--- a/lib/delphi/test/skip/README.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-These two projects belong together. Both programs 
-simulate server and client for different versions 
-of the same protocol.
-
-The intention of this test is to ensure fully
-working compatibilty features of the Delphi Thrift 
-implementation.
-
-The expected test result is, that no errors occur 
-with both programs, regardless in which order they 
-might be started.
diff --git a/lib/delphi/test/skip/skiptest_version1.dpr b/lib/delphi/test/skip/skiptest_version1.dpr
index e873f29..803d6bd 100644
--- a/lib/delphi/test/skip/skiptest_version1.dpr
+++ b/lib/delphi/test/skip/skiptest_version1.dpr
@@ -25,13 +25,15 @@
   Classes, Windows, SysUtils,
   Skiptest.One,
   Thrift in '..\..\src\Thrift.pas',
+  Thrift.Exception in '..\..\src\Thrift.Exception.pas',
+  Thrift.Socket in '..\..\src\Thrift.Socket.pas',
   Thrift.Transport in '..\..\src\Thrift.Transport.pas',
   Thrift.Protocol in '..\..\src\Thrift.Protocol.pas',
   Thrift.Protocol.JSON in '..\..\src\Thrift.Protocol.JSON.pas',
   Thrift.Collections in '..\..\src\Thrift.Collections.pas',
   Thrift.Server in '..\..\src\Thrift.Server.pas',
-  Thrift.Console in '..\..\src\Thrift.Console.pas',
   Thrift.Utils in '..\..\src\Thrift.Utils.pas',
+  Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
   Thrift.Stream in '..\..\src\Thrift.Stream.pas';
 
 const
@@ -42,7 +44,7 @@
 function CreatePing : IPing;
 begin
   result := TPingImpl.Create;
-  result.Version1  := Skiptest.One.TConstants.SKIPTESTSERVICE_VERSION;
+  result.Version1  := Tskiptest_version_1Constants.SKIPTESTSERVICE_VERSION;
 end;
 
 
@@ -95,7 +97,7 @@
     client := nil;  // not Free!
     cliRef := nil;
     stm.Free;
-    if client = nil then {warning supressed};
+    if client = nil then {warning suppressed};
   end;
 
   DeleteFile( fname+REQUEST_EXT);
@@ -122,7 +124,7 @@
     client := nil;  // not Free!
     cliRef := nil;
     stm.Free;
-    if client = nil then {warning supressed};
+    if client = nil then {warning suppressed};
   end;
 end;
 
@@ -149,7 +151,7 @@
     server := nil;  // not Free!
     stmIn.Free;
     stmOut.Free;
-    if server = nil then {warning supressed};
+    if server = nil then {warning suppressed};
   end;
 
   DeleteFile( fname+RESPONSE_EXT);
@@ -177,7 +179,7 @@
   FILE_JSON   = 'pingpong.json';
 begin
   try
-    Writeln( 'Delphi SkipTest '+IntToStr(TConstants.SKIPTESTSERVICE_VERSION)+' using '+Thrift.Version);
+    Writeln( 'Delphi SkipTest '+IntToStr(Tskiptest_version_1Constants.SKIPTESTSERVICE_VERSION)+' using '+Thrift.Version);
 
     Writeln;
     Writeln('Binary protocol');
diff --git a/lib/delphi/test/skip/skiptest_version2.dpr b/lib/delphi/test/skip/skiptest_version2.dpr
index 7615251..633b247 100644
--- a/lib/delphi/test/skip/skiptest_version2.dpr
+++ b/lib/delphi/test/skip/skiptest_version2.dpr
@@ -25,13 +25,15 @@
   Classes, Windows, SysUtils,
   Skiptest.Two,
   Thrift in '..\..\src\Thrift.pas',
+  Thrift.Exception in '..\..\src\Thrift.Exception.pas',
+  Thrift.Socket in '..\..\src\Thrift.Socket.pas',
   Thrift.Transport in '..\..\src\Thrift.Transport.pas',
   Thrift.Protocol in '..\..\src\Thrift.Protocol.pas',
   Thrift.Protocol.JSON in '..\..\src\Thrift.Protocol.JSON.pas',
   Thrift.Collections in '..\..\src\Thrift.Collections.pas',
   Thrift.Server in '..\..\src\Thrift.Server.pas',
-  Thrift.Console in '..\..\src\Thrift.Console.pas',
   Thrift.Utils in '..\..\src\Thrift.Utils.pas',
+  Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
   Thrift.Stream in '..\..\src\Thrift.Stream.pas';
 
 const
@@ -43,7 +45,7 @@
     set_ : IHashSet<string>;
 begin
   result := TPingImpl.Create;
-  result.Version1  := Skiptest.Two.TConstants.SKIPTESTSERVICE_VERSION;
+  result.Version1  := Tskiptest_version_2Constants.SKIPTESTSERVICE_VERSION;
   result.BoolVal   := TRUE;
   result.ByteVal   := 2;
   result.DbVal     := 3;
@@ -121,7 +123,7 @@
     client := nil;  // not Free!
     cliRef := nil;
     stm.Free;
-    if client = nil then {warning supressed};
+    if client = nil then {warning suppressed};
   end;
 
   DeleteFile( fname+REQUEST_EXT);
@@ -149,7 +151,7 @@
     client := nil;  // not Free!
     cliRef := nil;
     stm.Free;
-    if client = nil then {warning supressed};
+    if client = nil then {warning suppressed};
   end;
 end;
 
@@ -176,7 +178,7 @@
     server := nil;  // not Free!
     stmIn.Free;
     stmOut.Free;
-    if server = nil then {warning supressed};
+    if server = nil then {warning suppressed};
   end;
 
   DeleteFile( fname+RESPONSE_EXT);
@@ -204,7 +206,7 @@
   FILE_JSON   = 'pingpong.json';
 begin
   try
-    Writeln( 'Delphi SkipTest '+IntToStr(TConstants.SKIPTESTSERVICE_VERSION)+' using '+Thrift.Version);
+    Writeln( 'Delphi SkipTest '+IntToStr(Tskiptest_version_2Constants.SKIPTESTSERVICE_VERSION)+' using '+Thrift.Version);
 
     Writeln;
     Writeln('Binary protocol');
diff --git a/lib/delphi/test/typeregistry/TestTypeRegistry.dpr b/lib/delphi/test/typeregistry/TestTypeRegistry.dpr
index 64d5771..18a7c7d 100644
--- a/lib/delphi/test/typeregistry/TestTypeRegistry.dpr
+++ b/lib/delphi/test/typeregistry/TestTypeRegistry.dpr
@@ -25,11 +25,12 @@
   Classes, Windows, SysUtils, Generics.Collections, TypInfo,
   Thrift in '..\..\src\Thrift.pas',
   Thrift.Transport in '..\..\src\Thrift.Transport.pas',
+  Thrift.Exception in '..\..\src\Thrift.Exception.pas',
+  Thrift.Socket in '..\..\src\Thrift.Socket.pas',
   Thrift.Protocol in '..\..\src\Thrift.Protocol.pas',
   Thrift.Protocol.JSON in '..\..\src\Thrift.Protocol.JSON.pas',
   Thrift.Collections in '..\..\src\Thrift.Collections.pas',
   Thrift.Server in '..\..\src\Thrift.Server.pas',
-  Thrift.Console in '..\..\src\Thrift.Console.pas',
   Thrift.Utils in '..\..\src\Thrift.Utils.pas',
   Thrift.Serializer in '..\..\src\Thrift.Serializer.pas',
   Thrift.Stream in '..\..\src\Thrift.Stream.pas',
@@ -48,42 +49,42 @@
 begin
   instance := TypeRegistry.Construct<T>;
   name := GetTypeName(TypeInfo(T));
-  if instance <> nil

-  then Writeln( name, ' = ok')

-  else begin

-    Writeln( name, ' = failed');

-    raise Exception.Create( 'Test with '+name+' failed!');

-  end;

+  if instance <> nil
+  then Writeln( name, ' = ok')
+  else begin
+    Writeln( name, ' = failed');
+    raise Exception.Create( 'Test with '+name+' failed!');
+  end;
 end;
 
 begin
   Writeln('Testing ...');
   Tester<IDoubles>.Test;
-  Tester<IOneOfEach>.Test;

-  Tester<IBonk>.Test;

-  Tester<INesting>.Test;

-  Tester<IHolyMoley>.Test;

-  Tester<IBackwards>.Test;

-  Tester<IEmpty>.Test;

-  Tester<IWrapper>.Test;

-  Tester<IRandomStuff>.Test;

-  Tester<IBase64>.Test;

-  Tester<ICompactProtoTestStruct>.Test;

-  Tester<ISingleMapTestStruct>.Test;

-  Tester<IBlowUp>.Test;

-  Tester<IReverseOrderStruct>.Test;

-  Tester<IStructWithSomeEnum>.Test;

-  Tester<ITestUnion>.Test;

-  Tester<ITestUnionMinusStringField>.Test;

-  Tester<IComparableUnion>.Test;

-  Tester<IStructWithAUnion>.Test;

-  Tester<IPrimitiveThenStruct>.Test;

-  Tester<IStructWithASomemap>.Test;

-  Tester<IBigFieldIdStruct>.Test;

-  Tester<IBreaksRubyCompactProtocol>.Test;

-  Tester<ITupleProtocolTestStruct>.Test;

-  Writeln('Completed.');

-

-

-end.

+  Tester<IOneOfEach>.Test;
+  Tester<IBonk>.Test;
+  Tester<INesting>.Test;
+  Tester<IHolyMoley>.Test;
+  Tester<IBackwards>.Test;
+  Tester<IEmpty>.Test;
+  Tester<IWrapper>.Test;
+  Tester<IRandomStuff>.Test;
+  Tester<IBase64>.Test;
+  Tester<ICompactProtoTestStruct>.Test;
+  Tester<ISingleMapTestStruct>.Test;
+  Tester<IBlowUp>.Test;
+  Tester<IReverseOrderStruct>.Test;
+  Tester<IStructWithSomeEnum>.Test;
+  Tester<ITestUnion>.Test;
+  Tester<ITestUnionMinusStringField>.Test;
+  Tester<IComparableUnion>.Test;
+  Tester<IStructWithAUnion>.Test;
+  Tester<IPrimitiveThenStruct>.Test;
+  Tester<IStructWithASomemap>.Test;
+  Tester<IBigFieldIdStruct>.Test;
+  Tester<IBreaksRubyCompactProtocol>.Test;
+  Tester<ITupleProtocolTestStruct>.Test;
+  Writeln('Completed.');
+
+
+end.
 
diff --git a/lib/erl/Makefile.am b/lib/erl/Makefile.am
index 6550b52..06323b4 100644
--- a/lib/erl/Makefile.am
+++ b/lib/erl/Makefile.am
@@ -18,21 +18,44 @@
 #
 
 THRIFT = ../../compiler/cpp/thrift
-THRIFT_FILES = $(wildcard ../../test/*.thrift) \
-			   $(wildcard test/*.thrift)
+THRIFT_OMIT_FILE = test/Thrift_omit_without.thrift
+THRIFT_FILES = $(wildcard test/*.thrift) \
+		  $(THRIFT_OMIT_FILE) \
+		  ../../test/ConstantsDemo.thrift \
+		  ../../test/NameConflictTest.thrift \
+		  ../../test/DoubleConstantsTest.thrift \
+		  ../../test/ThriftTest.thrift
 
-.generated: $(THRIFT_FILES)
+if ERLANG_OTP16
+ERL_FLAG = erl:otp16
+ERL_FLAG_LEGACY = erl:otp16,legacynames
+# otp16 + maps does not make sense. We need to generate it anyway to avoid include error.
+ERL_FLAG_MAPS = erl:otp16
+else
+ERL_FLAG = erl
+ERL_FLAG_LEGACY = erl:legacynames
+ERL_FLAG_MAPS = erl:maps
+endif
+
+$(THRIFT_OMIT_FILE): test/Thrift_omit_with.thrift
+	grep -v omit $< >$@
+
+.generated: $(THRIFT) $(THRIFT_FILES)
 	for f in $(THRIFT_FILES) ; do \
-	  $(THRIFT) --gen erl -out test $$f ; \
-	done ; \
+		$(THRIFT) --gen $(ERL_FLAG) -o test $$f ; \
+	done
+	$(THRIFT) --gen $(ERL_FLAG_LEGACY) -o test test/flags/LegacyNames.thrift
+	$(THRIFT) --gen $(ERL_FLAG_MAPS) -o test test/flags/Thrift3214.thrift
 	touch .generated
 
 all: .generated
-	./rebar get-deps
-	./rebar compile
+	$(REBAR) get-deps
+	$(REBAR) compile
 
 check: .generated
-	./rebar skip_deps=true eunit
+	$(REBAR) -C rebar.test.config get-deps
+	$(REBAR) -C rebar.test.config compile
+	$(REBAR) -C rebar.test.config skip_deps=true eunit
 
 install: all
 	mkdir -p $(DESTDIR)$(ERLANG_INSTALL_LIB_DIR_thrift) ; \
@@ -47,37 +70,22 @@
 	rm -rf $(DESTDIR)$(ERLANG_INSTALL_LIB_DIR_thrift)
 
 clean:
-	./rebar clean
 	rm -f .generated
-	rm -f test/secondService_* \
-		  test/aService_* \
-		  test/serviceForExceptionWithAMap_* \
-		  test/annotationTest_* \
-		  test/service_* \
-		  test/constantsDemo_* \
-		  test/smallService_* \
-		  test/smallTest_* \
-		  test/debugProtoTest_* \
-		  test/srv_* \
-		  test/denseLinkingTest_* \
-		  test/stressTest_* \
-		  test/docTest_* \
-		  test/emptyService_* \
-		  test/inherited_* \
-		  test/javaBeansTest_* \
-		  test/thrift1151_* \
-		  test/javaBeansTest_* \
-		  test/manyTypedefs_* \
-		  test/thriftTest_* \
-		  test/optionalRequiredTest_* \
-		  test/yowza_* \
-		  test/reverseOrderService_* \
-		  test/manyOptionals_*
-	./rebar clean
+	rm -rf test/gen-erl/
+	rm -f $(THRIFT_OMIT_FILE)
+	$(REBAR) clean
 
 maintainer-clean-local:
 	rm -rf ebin
 
-EXTRA_DIST = include src rebar rebar.config test
+EXTRA_DIST = \
+	include \
+	src \
+	coding_standards.md \
+	rebar.config \
+	rebar.config.script \
+	rebar.test.config \
+	test \
+	README.md
 
 MAINTAINERCLEANFILES = Makefile.in
diff --git a/lib/erl/README b/lib/erl/README
deleted file mode 100644
index d7080da..0000000
--- a/lib/erl/README
+++ /dev/null
@@ -1,48 +0,0 @@
-Thrift Erlang Software Library
-
-License
-=======
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-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.
-
-Example
-=======
-
-Example session using thrift_client:
-
-1> {ok, C0} = thrift_client_util:new("localhost", 9090, thriftTest_thrift, []), ok.
-ok
-2> {C1, R1} = thrift_client:call(C0, testVoid, []), R1.
-{ok,ok}
-3> {C2, R2} = thrift_client:call(C1, testVoid, [asdf]), R2.
-{error,{bad_args,testVoid,[asdf]}}
-4> {C3, R3} = thrift_client:call(C2, testI32, [123]), R3.
-{ok,123}
-5> {C4, R4} = thrift_client:call(C3, testOneway, [1]), R4.
-{ok,ok}
-6> {C5, R5} = thrift_client:call(C4, testXception, ["foo"]), R5.
-{error,{no_function,testXception}}
-7> {C6, R6} = thrift_client:call(C5, testException, ["foo"]), R6.
-{ok,ok}
-8> {C7, R7} = (catch thrift_client:call(C6, testException, ["Xception"])), R7.
-{exception,{xception,1001,<<"Xception">>}}
-
-Notes
-=====
-To use the JSON protocol client, you will need jsx.  This will be pulled in
-via rebar for building but not automatically installed by make install.
diff --git a/lib/erl/README.md b/lib/erl/README.md
new file mode 100644
index 0000000..433d05c
--- /dev/null
+++ b/lib/erl/README.md
@@ -0,0 +1,51 @@
+# Thrift Erlang Software Library #
+
+## License ##
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+## Release Notes ##
+
+### 0.9.2 ###
+
+as of 0.9.2 struct and function naming conventions have changed. to retain the
+old naming conventions (for backwards compatibility) use the compiler option
+`legacynames`
+
+## Example ##
+
+Example session using thrift_client:
+
+```erl
+1> {ok, C0} = thrift_client_util:new("localhost", 9090, thrift_test_thrift, []), ok.
+ok
+2> {C1, R1} = thrift_client:call(C0, testVoid, []), R1.
+{ok,ok}
+3> {C2, R2} = thrift_client:call(C1, testVoid, [asdf]), R2.
+{error,{bad_args,testVoid,[asdf]}}
+4> {C3, R3} = thrift_client:call(C2, testI32, [123]), R3.
+{ok,123}
+5> {C4, R4} = thrift_client:call(C3, testOneway, [1]), R4.
+{ok,ok}
+6> {C5, R5} = thrift_client:call(C4, testXception, ["foo"]), R5.
+{error,{no_function,testXception}}
+7> {C6, R6} = thrift_client:call(C5, testException, ["foo"]), R6.
+{ok,ok}
+8> {C7, R7} = (catch thrift_client:call(C6, testException, ["Xception"])), R7.
+{exception,{xception,1001,<<"Xception">>}}
+```
diff --git a/lib/erl/coding_standards.md b/lib/erl/coding_standards.md
new file mode 100644
index 0000000..4d37dbc
--- /dev/null
+++ b/lib/erl/coding_standards.md
@@ -0,0 +1,3 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
+
+Particularly for Erlang please follow the Erlang [Programming Rules and Conventions](http://www.erlang.se/doc/programming_rules.shtml). 
diff --git a/lib/erl/include/thrift_constants.hrl b/lib/erl/include/thrift_constants.hrl
index dbfaaf6..7cb29eb 100644
--- a/lib/erl/include/thrift_constants.hrl
+++ b/lib/erl/include/thrift_constants.hrl
@@ -22,6 +22,7 @@
 -define(tType_VOID, 1).
 -define(tType_BOOL, 2).
 -define(tType_BYTE, 3).
+-define(tType_I8, 3).
 -define(tType_DOUBLE, 4).
 -define(tType_I16, 6).
 -define(tType_I32, 8).
@@ -56,3 +57,6 @@
 -define(TApplicationException_INVALID_TRANSFORM, 8).
 -define(TApplicationException_INVALID_PROTOCOL, 9).
 -define(TApplicationException_UNSUPPORTED_CLIENT_TYPE, 10).
+
+-define (MULTIPLEXED_SERVICE_SEPARATOR, ":").
+-define (MULTIPLEXED_ERROR_HANDLER_KEY, "error_handler").
diff --git a/lib/erl/include/thrift_protocol.hrl b/lib/erl/include/thrift_protocol.hrl
index f85f455..bc0acc8 100644
--- a/lib/erl/include/thrift_protocol.hrl
+++ b/lib/erl/include/thrift_protocol.hrl
@@ -20,12 +20,12 @@
 -ifndef(THRIFT_PROTOCOL_INCLUDED).
 -define(THRIFT_PROTOCOL_INCLUDED, true).
 
--record(protocol_message_begin, {name, type, seqid}).
--record(protocol_struct_begin, {name}).
--record(protocol_field_begin, {name, type, id}).
--record(protocol_map_begin, {ktype, vtype, size}).
--record(protocol_list_begin, {etype, size}).
--record(protocol_set_begin, {etype, size}).
+-record(protocol_message_begin, {name :: string(), type :: integer(), seqid :: integer()}).
+-record(protocol_struct_begin, {name :: string()}).
+-record(protocol_field_begin, {name :: string(), type :: integer(), id :: integer()}).
+-record(protocol_map_begin, {ktype :: integer(), vtype :: integer(), size :: integer()}).
+-record(protocol_list_begin, {etype :: integer(), size :: integer()}).
+-record(protocol_set_begin, {etype :: integer(), size :: integer()}).
 
 -type tprot_header_val() :: #protocol_message_begin{}
                           | #protocol_struct_begin{}
diff --git a/lib/erl/rebar b/lib/erl/rebar
deleted file mode 100755
index 53419ea..0000000
--- a/lib/erl/rebar
+++ /dev/null
Binary files differ
diff --git a/lib/erl/rebar.config b/lib/erl/rebar.config
index 2728cb3..1ea18a4 100644
--- a/lib/erl/rebar.config
+++ b/lib/erl/rebar.config
@@ -1,5 +1 @@
-{erl_opts, [debug_info]}.
-{lib_dirs, ["deps"]}.
-{deps, [
-         { jsx, "1.2.1", {git, "git://github.com/talentdeficit/jsx.git", {tag, "v1.2.1"}}}
-       ]}.
+{erl_opts, [{platform_define, "^R.*", otp16_or_less}, debug_info]}.
diff --git a/lib/erl/rebar.config.script b/lib/erl/rebar.config.script
new file mode 100644
index 0000000..c733823
--- /dev/null
+++ b/lib/erl/rebar.config.script
@@ -0,0 +1,7 @@
+Def0 = case not erlang:is_builtin(erlang, monotonic_time, 0) of
+           true -> [];
+           false -> [{d, time_correction}]
+       end,
+Defs = Def0,
+lists:keystore(erl_opts, 1, CONFIG,
+               {erl_opts, proplists:get_value(erl_opts, CONFIG, []) ++ Defs}).
diff --git a/lib/erl/rebar.test.config b/lib/erl/rebar.test.config
new file mode 100644
index 0000000..2ff2afb
--- /dev/null
+++ b/lib/erl/rebar.test.config
@@ -0,0 +1,5 @@
+{erl_opts, [{platform_define, "^R.*", otp16_or_less}, debug_info]}.
+
+{deps, [
+  {meck, "", {git, "https://github.com/eproxus/meck.git", {tag, "0.8.9"}}}
+]}.
diff --git a/lib/erl/src/thrift.app.src b/lib/erl/src/thrift.app.src
index db19897..b3b225f 100644
--- a/lib/erl/src/thrift.app.src
+++ b/lib/erl/src/thrift.app.src
@@ -17,17 +17,38 @@
 %% under the License.
 %%
 %%% -*- mode:erlang -*-
-{application, thrift,
- [
+{application, thrift, [
   % A quick description of the application.
   {description, "Thrift bindings"},
 
   % The version of the applicaton
-  {vsn, "0.9.1"},
+  {vsn, "1.0.0"},
 
   % All modules used by the application.
   {modules, [
-   ]},
+    thrift_base64_transport,
+    thrift_binary_protocol,
+    thrift_buffered_transport,
+    thrift_client_util,
+    thrift_client,
+    thrift_disk_log_transport,
+    thrift_file_transport,
+    thrift_framed_transport,
+    thrift_http_transport,
+    thrift_json_parser,
+    thrift_json_protocol,
+    thrift_membuffer_transport,
+    thrift_memory_buffer,
+    thrift_processor,
+    thrift_protocol,
+    thrift_reconnecting_client,
+    thrift_server,
+    thrift_service,
+    thrift_socket_server,
+    thrift_socket_transport,
+    thrift_transport_state_test,
+    thrift_transport
+  ]},
 
   % All of the registered names the application uses. This can be ignored.
   {registered, []},
@@ -35,11 +56,7 @@
   % Applications that are to be started prior to this one. This can be ignored
   % leave it alone unless you understand it well and let the .rel files in
   % your release handle this.
-  {applications,
-   [
-    kernel,
-    stdlib
-   ]},
+  {applications, [kernel, stdlib]},
 
   % OTP application loader will load, but not start, included apps. Again
   % this can be ignored as well.  To load but not start an application it
@@ -49,10 +66,9 @@
   % configuration parameters similar to those in the config file specified
   % on the command line. can be fetched with gas:get_env
   {env, [
-         % If an error/crash occurs during processing of a function,
-         % should the TApplicationException serialized back to the client
-         % include the erlang backtrace?
-         {exceptions_include_traces, true}
+    % If an error/crash occurs during processing of a function,
+    % should the TApplicationException serialized back to the client
+    % include the erlang backtrace?
+    {exceptions_include_traces, true}
   ]}
- ]
-}.
+]}.
diff --git a/lib/erl/src/thrift_binary_protocol.erl b/lib/erl/src/thrift_binary_protocol.erl
index 800fd8e..85abb62 100644
--- a/lib/erl/src/thrift_binary_protocol.erl
+++ b/lib/erl/src/thrift_binary_protocol.erl
@@ -333,11 +333,15 @@
 new_protocol_factory(TransportFactory, Options) ->
     ParsedOpts = parse_factory_options(Options, #tbp_opts{}),
     F = fun() ->
-                {ok, Transport} = TransportFactory(),
-                thrift_binary_protocol:new(
-                  Transport,
-                  [{strict_read,  ParsedOpts#tbp_opts.strict_read},
-                   {strict_write, ParsedOpts#tbp_opts.strict_write}])
+               case TransportFactory() of
+                    {ok, Transport} ->
+                        thrift_binary_protocol:new(
+                            Transport,
+                            [{strict_read,  ParsedOpts#tbp_opts.strict_read},
+                             {strict_write, ParsedOpts#tbp_opts.strict_write}]);
+                    {error, Error} ->
+                        {error, Error}
+                end
         end,
     {ok, F}.
 
diff --git a/lib/erl/src/thrift_buffered_transport.erl b/lib/erl/src/thrift_buffered_transport.erl
index d4d614e..e9d3fff 100644
--- a/lib/erl/src/thrift_buffered_transport.erl
+++ b/lib/erl/src/thrift_buffered_transport.erl
@@ -21,57 +21,78 @@
 
 -behaviour(thrift_transport).
 
-%% API
--export([new/1, new_transport_factory/1]).
+%% constructor
+-export([new/1]).
+%% protocol callbacks
+-export([read/2, read_exact/2, write/2, flush/1, close/1]).
+%% legacy api
+-export([new_transport_factory/1]).
 
-%% thrift_transport callbacks
--export([write/2, read/2, flush/1, close/1]).
 
--record(buffered_transport, {wrapped, % a thrift_transport
-                             write_buffer % iolist()
-                            }).
--type state() :: #buffered_transport{}.
+-record(t_buffered, {
+  wrapped,
+  write_buffer
+}).
+
+-type state() :: #t_buffered{}.
+
+
+-spec new(Transport::thrift_transport:t_transport()) ->
+  thrift_transport:t_transport().
+
+new(Wrapped) ->
+  State = #t_buffered{
+    wrapped = Wrapped,
+    write_buffer = []
+  },
+  thrift_transport:new(?MODULE, State).
+
+
 -include("thrift_transport_behaviour.hrl").
 
 
-new(WrappedTransport) ->
-    State = #buffered_transport{wrapped = WrappedTransport,
-                                write_buffer = []},
-    thrift_transport:new(?MODULE, State).
+%% reads data through from the wrapped transport
+read(State = #t_buffered{wrapped = Wrapped}, Len)
+when is_integer(Len), Len >= 0 ->
+  {NewState, Response} = thrift_transport:read(Wrapped, Len),
+  {State#t_buffered{wrapped = NewState}, Response}.
 
 
-%% Writes data into the buffer
-write(State = #buffered_transport{write_buffer = WBuf}, Data) ->
-    {State#buffered_transport{write_buffer = [WBuf, Data]}, ok}.
+%% reads data through from the wrapped transport
+read_exact(State = #t_buffered{wrapped = Wrapped}, Len)
+when is_integer(Len), Len >= 0 ->
+  {NewState, Response} = thrift_transport:read_exact(Wrapped, Len),
+  {State#t_buffered{wrapped = NewState}, Response}.
 
-%% Flushes the buffer through to the wrapped transport
-flush(State = #buffered_transport{write_buffer = WBuf,
-                                  wrapped = Wrapped0}) ->
-    {Wrapped1, Response} = thrift_transport:write(Wrapped0, WBuf),
-    {Wrapped2, _} = thrift_transport:flush(Wrapped1),
-    NewState = State#buffered_transport{write_buffer = [],
-                                        wrapped = Wrapped2},
-    {NewState, Response}.
 
-%% Closes the transport and the wrapped transport
-close(State = #buffered_transport{wrapped = Wrapped0}) ->
-    {Wrapped1, Result} = thrift_transport:close(Wrapped0),
-    NewState = State#buffered_transport{wrapped = Wrapped1},
-    {NewState, Result}.
+write(State = #t_buffered{write_buffer = Buffer}, Data) ->
+  {State#t_buffered{write_buffer = [Buffer, Data]}, ok}.
 
-%% Reads data through from the wrapped transport
-read(State = #buffered_transport{wrapped = Wrapped0}, Len) when is_integer(Len) ->
-    {Wrapped1, Response} = thrift_transport:read(Wrapped0, Len),
-    NewState = State#buffered_transport{wrapped = Wrapped1},
-    {NewState, Response}.
+
+flush(State = #t_buffered{wrapped = Wrapped, write_buffer = Buffer}) ->
+  case iolist_size(Buffer) of
+    %% if write buffer is empty, do nothing
+    0 -> {State, ok};
+    _ ->
+      {Written, Response} = thrift_transport:write(Wrapped, Buffer),
+      {Flushed, ok} = thrift_transport:flush(Written),
+      {State#t_buffered{wrapped = Flushed, write_buffer = []}, Response}
+  end.
+
+
+close(State = #t_buffered{wrapped = Wrapped}) ->
+  {Closed, Result} = thrift_transport:close(Wrapped),
+  {State#t_buffered{wrapped = Closed}, Result}.
+
 
 %%--------------------------------------------------------------------
 %%% Internal functions
 %%--------------------------------------------------------------------
 %%%% FACTORY GENERATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 new_transport_factory(WrapFactory) ->
-    F = fun() ->
-                {ok, Wrapped} = WrapFactory(),
-                new(Wrapped)
-        end,
-    {ok, F}.
+  F = fun() ->
+    {ok, Wrapped} = WrapFactory(),
+    new(Wrapped)
+  end,
+  {ok, F}.
+
diff --git a/lib/erl/src/thrift_client.erl b/lib/erl/src/thrift_client.erl
index 5c74adc..1a9cb50 100644
--- a/lib/erl/src/thrift_client.erl
+++ b/lib/erl/src/thrift_client.erl
@@ -36,13 +36,12 @@
 
 -spec call(#tclient{}, atom(), list()) -> {#tclient{}, {ok, any()} | {error, any()}}.
 call(Client = #tclient{}, Function, Args)
-  when is_atom(Function), is_list(Args) ->
-    case send_function_call(Client, Function, Args) of
-        {Client1, ok} ->
-            receive_function_result(Client1, Function);
-        Else ->
-            Else
-    end.
+when is_atom(Function), is_list(Args) ->
+  case send_function_call(Client, Function, Args) of
+    {ok, Client1} -> receive_function_result(Client1, Function);
+    {{error, X}, Client1} -> {Client1, {error, X}};
+    Else -> Else
+  end.
 
 
 %% Sends a function call but does not read the result. This is useful
@@ -51,7 +50,10 @@
 -spec send_call(#tclient{}, atom(), list()) -> {#tclient{}, ok}.
 send_call(Client = #tclient{}, Function, Args)
   when is_atom(Function), is_list(Args) ->
-    send_function_call(Client, Function, Args).
+    case send_function_call(Client, Function, Args) of
+      {ok, Client1} -> {Client1, ok};
+      Else -> Else
+    end.
 
 -spec close(#tclient{}) -> ok.
 close(#tclient{protocol=Protocol}) ->
@@ -61,28 +63,40 @@
 %%--------------------------------------------------------------------
 %%% Internal functions
 %%--------------------------------------------------------------------
--spec send_function_call(#tclient{}, atom(), list()) -> {#tclient{}, ok | {error, any()}}.
-send_function_call(Client = #tclient{protocol = Proto0,
-                                     service  = Service,
-                                     seqid    = SeqId},
-                   Function,
-                   Args) ->
-    Params = Service:function_info(Function, params_type),
-    case Params of
-        no_function ->
-            {Client, {error, {no_function, Function}}};
-        {struct, PList} when length(PList) =/= length(Args) ->
-            {Client, {error, {bad_args, Function, Args}}};
-        {struct, _PList} ->
-            Begin = #protocol_message_begin{name = atom_to_list(Function),
-                                            type = ?tMessageType_CALL,
-                                            seqid = SeqId},
-            {Proto1, ok} = thrift_protocol:write(Proto0, Begin),
-            {Proto2, ok} = thrift_protocol:write(Proto1, {Params, list_to_tuple([Function | Args])}),
-            {Proto3, ok} = thrift_protocol:write(Proto2, message_end),
-            {Proto4, ok} = thrift_protocol:flush_transport(Proto3),
-            {Client#tclient{protocol = Proto4}, ok}
-    end.
+-spec send_function_call(#tclient{}, atom(), list()) -> {ok | {error, any()}, #tclient{}}.
+send_function_call(Client = #tclient{service = Service}, Function, Args) ->
+  {Params, Reply} = try
+    {Service:function_info(Function, params_type), Service:function_info(Function, reply_type)}
+  catch error:function_clause -> {no_function, 0}
+  end,
+  MsgType = case Reply of
+    oneway_void -> ?tMessageType_ONEWAY;
+    _ -> ?tMessageType_CALL
+  end,
+  case Params of
+    no_function ->
+      {{error, {no_function, Function}}, Client};
+    {struct, PList} when length(PList) =/= length(Args) ->
+      {{error, {bad_args, Function, Args}}, Client};
+    {struct, _PList} -> write_message(Client, Function, Args, Params, MsgType)
+  end.
+
+-spec write_message(#tclient{}, atom(), list(), {struct, list()}, integer()) ->
+  {ok | {error, any()}, #tclient{}}.
+write_message(Client = #tclient{protocol = P0, seqid = Seq}, Function, Args, Params, MsgType) ->
+  try
+    {P1, ok} = thrift_protocol:write(P0, #protocol_message_begin{
+      name = atom_to_list(Function),
+      type = MsgType,
+      seqid = Seq
+    }),
+    {P2, ok} = thrift_protocol:write(P1, {Params, list_to_tuple([Function|Args])}),
+    {P3, ok} = thrift_protocol:write(P2, message_end),
+    {P4, ok} = thrift_protocol:flush_transport(P3),
+    {ok, Client#tclient{protocol = P4}}
+  catch
+    error:{badmatch, {_, {error, _} = Error}} -> {Error, Client}
+  end.
 
 -spec receive_function_result(#tclient{}, atom()) -> {#tclient{}, {ok, any()} | {error, any()}}.
 receive_function_result(Client = #tclient{service = Service}, Function) ->
@@ -96,17 +110,20 @@
                               seqid    = SeqId},
             Function,
             ReplyType) ->
-    {Proto1, MessageBegin} = thrift_protocol:read(Proto0, message_begin),
-    NewClient = Client#tclient{protocol = Proto1},
-    case MessageBegin of
-        #protocol_message_begin{seqid = RetSeqId} when RetSeqId =/= SeqId ->
-            {NewClient, {error, {bad_seq_id, SeqId}}};
-
-        #protocol_message_begin{type = ?tMessageType_EXCEPTION} ->
-            handle_application_exception(NewClient);
-
-        #protocol_message_begin{type = ?tMessageType_REPLY} ->
-            handle_reply(NewClient, Function, ReplyType)
+    case thrift_protocol:read(Proto0, message_begin) of
+         {Proto1, {error, Reason}} ->
+             NewClient = Client#tclient{protocol = Proto1},
+             {NewClient, {error, Reason}};
+         {Proto1, MessageBegin} ->
+             NewClient = Client#tclient{protocol = Proto1},
+             case MessageBegin of
+                 #protocol_message_begin{seqid = RetSeqId} when RetSeqId =/= SeqId ->
+                     {NewClient, {error, {bad_seq_id, SeqId}}};
+                 #protocol_message_begin{type = ?tMessageType_EXCEPTION} ->
+                     handle_application_exception(NewClient);
+                 #protocol_message_begin{type = ?tMessageType_REPLY} ->
+                     handle_reply(NewClient, Function, ReplyType)
+             end
     end.
 
 
diff --git a/lib/erl/src/thrift_client_util.erl b/lib/erl/src/thrift_client_util.erl
index c52bb8b..1dbe51e 100644
--- a/lib/erl/src/thrift_client_util.erl
+++ b/lib/erl/src/thrift_client_util.erl
@@ -20,6 +20,11 @@
 -module(thrift_client_util).
 
 -export([new/4]).
+-export([new_multiplexed/3, new_multiplexed/4]).
+
+-type service_name()            :: nonempty_string().
+-type service_module()          :: atom().
+-type multiplexed_service_map() :: [{ServiceName::service_name(), ServiceModule::service_module()}].
 
 %%
 %% Splits client options into client, protocol, and transport options
@@ -34,28 +39,74 @@
 
 split_options([Opt = {OptKey, _} | Rest], ProtoIn, TransIn)
   when OptKey =:= strict_read;
-       OptKey =:= strict_write ->
+       OptKey =:= strict_write;
+       OptKey =:= protocol ->
     split_options(Rest, [Opt | ProtoIn], TransIn);
 
 split_options([Opt = {OptKey, _} | Rest], ProtoIn, TransIn)
   when OptKey =:= framed;
        OptKey =:= connect_timeout;
-       OptKey =:= sockopts ->
+       OptKey =:= recv_timeout;
+       OptKey =:= sockopts;
+       OptKey =:= ssltransport;
+       OptKey =:= ssloptions->
     split_options(Rest, ProtoIn, [Opt | TransIn]).
 
 
 %% Client constructor for the common-case of socket transports
-%% with the binary protocol
 new(Host, Port, Service, Options)
   when is_integer(Port), is_atom(Service), is_list(Options) ->
-    {ProtoOpts, TransOpts} = split_options(Options),
+    {ProtoOpts, TransOpts0} = split_options(Options),
 
+    {TransportModule, TransOpts2} = case lists:keytake(ssltransport, 1, TransOpts0) of
+                                        {value, {_, true}, TransOpts1} -> {thrift_sslsocket_transport, TransOpts1};
+                                        false -> {thrift_socket_transport, TransOpts0}
+                                    end,
+
+    {ProtocolModule, ProtoOpts1} = case lists:keytake(protocol, 1, ProtoOpts) of
+                                     {value, {_, compact}, Opts} -> {thrift_compact_protocol, Opts};
+                                     {value, {_, json}, Opts} -> {thrift_json_protocol, Opts};
+                                     {value, {_, binary}, Opts} -> {thrift_binary_protocol, Opts};
+                                     false -> {thrift_binary_protocol, ProtoOpts}
+                                   end,
     {ok, TransportFactory} =
-        thrift_socket_transport:new_transport_factory(Host, Port, TransOpts),
+        TransportModule:new_transport_factory(Host, Port, TransOpts2),
 
-    {ok, ProtocolFactory} = thrift_binary_protocol:new_protocol_factory(
-                              TransportFactory, ProtoOpts),
+    {ok, ProtocolFactory} = ProtocolModule:new_protocol_factory(
+                              TransportFactory, ProtoOpts1),
+
+    case ProtocolFactory() of
+        {ok, Protocol} ->
+            thrift_client:new(Protocol, Service);
+        {error, Error} ->
+            {error, Error}
+    end.
+
+-spec new_multiplexed(Host, Port, Services, Options) -> {ok, ServiceThriftClientList} when
+    Host        :: nonempty_string(),
+    Port        :: non_neg_integer(),
+    Services    :: multiplexed_service_map(),
+    Options     :: list(),
+    ServiceThriftClientList :: [{ServiceName::list(), ThriftClient::term()}].
+new_multiplexed(Host, Port, Services, Options) when is_integer(Port),
+                                                    is_list(Services),
+                                                    is_list(Options) ->
+    new_multiplexed(thrift_socket_transport:new_transport_factory(Host, Port, Options), Services, Options).
+
+-spec new_multiplexed(TransportFactoryTuple, Services, Options) -> {ok, ServiceThriftClientList} when
+    TransportFactoryTuple   :: {ok, TransportFactory::term()},
+    Services                :: multiplexed_service_map(),
+    Options                 :: list(),
+    ServiceThriftClientList :: [{ServiceName::service_name(), ThriftClient::term()}].
+new_multiplexed(TransportFactoryTuple, Services, Options) when is_list(Services),
+                                                               is_list(Options),
+                                                               is_tuple(TransportFactoryTuple) ->
+    {ProtoOpts, _} = split_options(Options),
+
+    {ok, TransportFactory} = TransportFactoryTuple,
+
+    {ok, ProtocolFactory} = thrift_binary_protocol:new_protocol_factory(TransportFactory, ProtoOpts),
 
     {ok, Protocol} = ProtocolFactory(),
 
-    thrift_client:new(Protocol, Service).
+    {ok, [{ServiceName, element(2, thrift_client:new(element(2, thrift_multiplexed_protocol:new(Protocol, ServiceName)), Service))} || {ServiceName, Service} <- Services]}.
diff --git a/lib/erl/src/thrift_compact_protocol.erl b/lib/erl/src/thrift_compact_protocol.erl
new file mode 100644
index 0000000..0f14221
--- /dev/null
+++ b/lib/erl/src/thrift_compact_protocol.erl
@@ -0,0 +1,390 @@
+%%
+%% 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.
+%%
+
+-module(thrift_compact_protocol).
+
+-behaviour(thrift_protocol).
+
+-include("thrift_constants.hrl").
+-include("thrift_protocol.hrl").
+
+-export([new/1, new/2,
+         read/2,
+         write/2,
+         flush_transport/1,
+         close_transport/1,
+         new_protocol_factory/2
+        ]).
+
+-define(ID_NONE, 16#10000).
+-define(CBOOL_NONE, 0).
+-define(CBOOL_TRUE, 1).
+-define(CBOOL_FALSE, 2).
+
+-record(t_compact, {transport,
+                           % state for pending boolean fields
+                           read_stack=[],
+                           read_value=?CBOOL_NONE,
+                           write_stack=[],
+                           write_id=?ID_NONE
+                          }).
+-type state() :: #t_compact{}.
+-include("thrift_protocol_behaviour.hrl").
+
+-define(PROTOCOL_ID, 16#82).
+-define(VERSION_MASK, 16#1f).
+-define(VERSION_1, 16#01).
+-define(TYPE_MASK, 16#E0).
+-define(TYPE_BITS, 16#07).
+-define(TYPE_SHIFT_AMOUNT, 5).
+
+typeid_to_compact(?tType_STOP) -> 16#0;
+typeid_to_compact(?tType_BOOL) -> 16#2;
+typeid_to_compact(?tType_I8) -> 16#3;
+typeid_to_compact(?tType_I16) -> 16#4;
+typeid_to_compact(?tType_I32) -> 16#5;
+typeid_to_compact(?tType_I64) -> 16#6;
+typeid_to_compact(?tType_DOUBLE) -> 16#7;
+typeid_to_compact(?tType_STRING) -> 16#8;
+typeid_to_compact(?tType_STRUCT) -> 16#C;
+typeid_to_compact(?tType_MAP) -> 16#B;
+typeid_to_compact(?tType_SET) -> 16#A;
+typeid_to_compact(?tType_LIST) -> 16#9.
+
+compact_to_typeid(16#0) ->  ?tType_STOP;
+compact_to_typeid(?CBOOL_FALSE) ->  ?tType_BOOL;
+compact_to_typeid(?CBOOL_TRUE) ->  ?tType_BOOL;
+compact_to_typeid(16#7) ->  ?tType_DOUBLE;
+compact_to_typeid(16#3) ->  ?tType_I8;
+compact_to_typeid(16#4) ->  ?tType_I16;
+compact_to_typeid(16#5) ->  ?tType_I32;
+compact_to_typeid(16#6) ->  ?tType_I64;
+compact_to_typeid(16#8) ->  ?tType_STRING;
+compact_to_typeid(16#C) ->  ?tType_STRUCT;
+compact_to_typeid(16#B) ->  ?tType_MAP;
+compact_to_typeid(16#A) ->  ?tType_SET;
+compact_to_typeid(16#9) ->  ?tType_LIST.
+
+bool_to_cbool(Value) when Value -> ?CBOOL_TRUE;
+bool_to_cbool(_) -> ?CBOOL_FALSE.
+cbool_to_bool(Value) -> Value =:= ?CBOOL_TRUE.
+
+new(Transport) -> new(Transport, _Options = []).
+
+new(Transport, _Options) ->
+  State  = #t_compact{transport = Transport},
+  thrift_protocol:new(?MODULE, State).
+
+flush_transport(This = #t_compact{transport = Transport}) ->
+  {NewTransport, Result} = thrift_transport:flush(Transport),
+  {This#t_compact{transport = NewTransport}, Result}.
+
+close_transport(This = #t_compact{transport = Transport}) ->
+  {NewTransport, Result} = thrift_transport:close(Transport),
+  {This#t_compact{transport = NewTransport}, Result}.
+
+%%%
+%%% instance methods
+%%%
+
+write_field_begin(This0 = #t_compact{write_stack=[LastId|T]}, CompactType, Id) ->
+  IdDiff = Id - LastId,
+  This1 = This0#t_compact{write_stack=[Id|T]},
+  case (IdDiff > 0) and (IdDiff < 16) of
+    true -> write(This1, {byte, (IdDiff bsl 4) bor CompactType});
+    false ->
+      {This2, ok} = write(This1, {byte, CompactType}),
+      write(This2, {i16, Id})
+  end.
+
+-spec to_zigzag(integer()) -> non_neg_integer().
+to_zigzag(Value) -> 16#FFFFFFFFFFFFFFFF band ((Value bsl 1) bxor (Value bsr 63)).
+
+-spec from_zigzag(non_neg_integer()) -> integer().
+from_zigzag(Value) -> (Value bsr 1) bxor -(Value band 1).
+
+-spec to_varint(non_neg_integer(), iolist()) -> iolist().
+to_varint(Value, Acc) when (Value < 16#80) -> [Acc, Value];
+to_varint(Value, Acc) ->
+  to_varint(Value bsr 7, [Acc, ((Value band 16#7F) bor 16#80)]).
+
+-spec read_varint(#t_compact{}, non_neg_integer(), non_neg_integer()) -> non_neg_integer().
+read_varint(This0, Acc, Count) ->
+  {This1, {ok, Byte}} = read(This0, byte),
+  case (Byte band 16#80) of
+    0 -> {This1, {ok, (Byte bsl (7 * Count)) + Acc}};
+    _ -> read_varint(This1, ((Byte band 16#7f) bsl (7 * Count)) + Acc, Count + 1)
+  end.
+
+write(This0, #protocol_message_begin{
+        name = Name,
+        type = Type,
+        seqid = Seqid}) ->
+  {This1, ok} = write(This0, {byte, ?PROTOCOL_ID}),
+  {This2, ok} = write(This1, {byte, (?VERSION_1 band ?VERSION_MASK) bor (Type bsl ?TYPE_SHIFT_AMOUNT)}),
+  {This3, ok} = write(This2, {ui32, Seqid}),
+  {This4, ok} = write(This3, {string, Name}),
+  {This4, ok};
+
+write(This, message_end) -> {This, ok};
+
+write(This0, #protocol_field_begin{
+       name = _Name,
+       type = Type,
+       id = Id})
+when (Type =:= ?tType_BOOL) -> {This0#t_compact{write_id = Id}, ok};
+
+write(This0, #protocol_field_begin{
+       name = _Name,
+       type = Type,
+       id = Id}) ->
+  write_field_begin(This0, typeid_to_compact(Type), Id);
+
+write(This, field_stop) -> write(This, {byte, ?tType_STOP});
+
+write(This, field_end) -> {This, ok};
+
+write(This0, #protocol_map_begin{
+      ktype = _Ktype,
+      vtype = _Vtype,
+      size = Size})
+when Size =:= 0 ->
+  write(This0, {byte, 0});
+
+write(This0, #protocol_map_begin{
+       ktype = Ktype,
+       vtype = Vtype,
+       size = Size}) ->
+  {This1, ok} = write(This0, {ui32, Size}),
+  write(This1, {byte, (typeid_to_compact(Ktype) bsl 4) bor typeid_to_compact(Vtype)});
+
+write(This, map_end) -> {This, ok};
+
+write(This0, #protocol_list_begin{
+        etype = Etype,
+        size = Size})
+when Size < 16#f ->
+  write(This0, {byte, (Size bsl 4) bor typeid_to_compact(Etype)});
+
+write(This0, #protocol_list_begin{
+        etype = Etype,
+        size = Size}) ->
+  {This1, ok} = write(This0, {byte, 16#f0 bor typeid_to_compact(Etype)}),
+  write(This1, {ui32, Size});
+
+write(This, list_end) -> {This, ok};
+
+write(This0, #protocol_set_begin{
+        etype = Etype,
+        size = Size}) ->
+  write(This0, #protocol_list_begin{etype = Etype, size =  Size});
+
+write(This, set_end) -> {This, ok};
+
+write(This = #t_compact{write_stack = Stack}, #protocol_struct_begin{}) ->
+  {This#t_compact{write_stack = [0|Stack]}, ok};
+write(This = #t_compact{write_stack = [_|T]}, struct_end) ->
+  {This#t_compact{write_stack = T}, ok};
+
+write(This = #t_compact{write_id = ?ID_NONE}, {bool, Value}) ->
+  write(This, {byte, bool_to_cbool(Value)});
+
+write(This0 = #t_compact{write_id = Id}, {bool, Value}) ->
+  {This1, ok} = write_field_begin(This0, bool_to_cbool(Value), Id),
+  {This1#t_compact{write_id = ?ID_NONE}, ok};
+
+write(This, {byte, Value}) when is_integer(Value) ->
+  write(This, <<Value:8/big-signed>>);
+
+write(This, {i16, Value}) when is_integer(Value) -> write(This, to_varint(to_zigzag(Value), []));
+write(This, {ui32, Value}) when is_integer(Value) -> write(This, to_varint(Value, []));
+write(This, {i32, Value}) when is_integer(Value) ->
+  write(This, to_varint(to_zigzag(Value), []));
+write(This, {i64, Value}) when is_integer(Value) -> write(This, to_varint(to_zigzag(Value), []));
+
+write(This, {double, Double}) ->
+  write(This, <<Double:64/float-signed-little>>);
+
+write(This0, {string, Str}) when is_list(Str) ->
+  % TODO: limit length
+  {This1, ok} = write(This0, {ui32, length(Str)}),
+  {This2, ok} = write(This1, list_to_binary(Str)),
+  {This2, ok};
+
+write(This0, {string, Bin}) when is_binary(Bin) ->
+  % TODO: limit length
+  {This1, ok} = write(This0, {ui32, size(Bin)}),
+  {This2, ok} = write(This1, Bin),
+  {This2, ok};
+
+%% Data :: iolist()
+write(This = #t_compact{transport = Trans}, Data) ->
+  {NewTransport, Result} = thrift_transport:write(Trans, Data),
+  {This#t_compact{transport = NewTransport}, Result}.
+
+%%
+%%
+
+read(This0, message_begin) ->
+  {This1, {ok, ?PROTOCOL_ID}} = read(This0, ubyte),
+  {This2, {ok, VerAndType}} = read(This1, ubyte),
+  ?VERSION_1 = VerAndType band ?VERSION_MASK,
+  {This3, {ok, SeqId}} = read(This2, ui32),
+  {This4, {ok, Name}} = read(This3, string),
+  {This4, #protocol_message_begin{
+             name  = binary_to_list(Name),
+             type  = (VerAndType bsr ?TYPE_SHIFT_AMOUNT) band ?TYPE_BITS,
+             seqid = SeqId}};
+
+read(This, message_end) -> {This, ok};
+
+read(This = #t_compact{read_stack = Stack}, struct_begin) ->
+  {This#t_compact{read_stack = [0|Stack]}, ok};
+read(This = #t_compact{read_stack = [_H|T]}, struct_end) ->
+  {This#t_compact{read_stack = T}, ok};
+
+read(This0 = #t_compact{read_stack = [LastId|T]}, field_begin) ->
+  {This1, {ok, Byte}} = read(This0, ubyte),
+  case Byte band 16#f of
+    CompactType = ?tType_STOP ->
+      {This1, #protocol_field_begin{type = CompactType}};
+    CompactType ->
+      {This2, {ok, Id}} = case Byte bsr 4 of
+                            0 -> read(This1, i16);
+                            IdDiff ->
+                              {This1, {ok, LastId + IdDiff}}
+                          end,
+      case compact_to_typeid(CompactType) of
+        ?tType_BOOL ->
+          {This2#t_compact{read_stack = [Id|T], read_value = cbool_to_bool(CompactType)},
+           #protocol_field_begin{type = ?tType_BOOL, id = Id}};
+        Type ->
+          {This2#t_compact{read_stack = [Id|T]},
+           #protocol_field_begin{type = Type, id = Id}}
+      end
+  end;
+
+read(This, field_end) -> {This, ok};
+
+read(This0, map_begin) ->
+  {This1, {ok, Size}}  = read(This0, ui32),
+  {This2, {ok, KV}} = case Size of
+                        0 -> {This1, {ok, 0}};
+                        _ -> read(This1, ubyte)
+                      end,
+  {This2, #protocol_map_begin{ktype = compact_to_typeid(KV bsr 4),
+                              vtype = compact_to_typeid(KV band 16#f),
+                              size = Size}};
+read(This, map_end) -> {This, ok};
+
+read(This0, list_begin) ->
+  {This1, {ok, SizeAndType}} = read(This0, ubyte),
+  {This2, {ok, Size}} = case (SizeAndType bsr 4) band 16#f of
+                          16#f -> read(This1, ui32);
+                          Else -> {This1, {ok, Else}}
+                        end,
+  {This2, #protocol_list_begin{etype = compact_to_typeid(SizeAndType band 16#f),
+                               size = Size}};
+
+read(This, list_end) -> {This, ok};
+
+read(This0, set_begin) ->
+  {This1, {ok, SizeAndType}} = read(This0, ubyte),
+  {This2, {ok, Size}} = case (SizeAndType bsr 4) band 16#f of
+                          16#f -> read(This1, ui32);
+                          Else -> {This1, {ok, Else}}
+                        end,
+  {This2, #protocol_set_begin{etype = compact_to_typeid(SizeAndType band 16#f),
+                               size = Size}};
+
+read(This, set_end) -> {This, ok};
+
+read(This0, field_stop) ->
+  {This1, {ok, ?tType_STOP}} = read(This0, ubyte),
+  {This1, ok};
+
+%%
+
+read(This0 = #t_compact{read_value = ?CBOOL_NONE}, bool) ->
+  {This1, {ok, Byte}} = read(This0, ubyte),
+  {This1, {ok, cbool_to_bool(Byte)}};
+
+read(This0 = #t_compact{read_value = Bool}, bool) ->
+  {This0#t_compact{read_value = ?CBOOL_NONE}, {ok, Bool}};
+
+read(This0, ubyte) ->
+  {This1, {ok, <<Val:8/integer-unsigned-big, _/binary>>}} = read_data(This0, 1),
+  {This1, {ok, Val}};
+
+read(This0, byte) ->
+  {This1, Bytes} = read_data(This0, 1),
+  case Bytes of
+    {ok, <<Val:8/integer-signed-big, _/binary>>} -> {This1, {ok, Val}};
+    Else -> {This1, Else}
+  end;
+
+read(This0, i16) ->
+  {This1, {ok, Zigzag}} = read_varint(This0, 0, 0),
+  {This1, {ok, from_zigzag(Zigzag)}};
+
+read(This0, ui32) -> read_varint(This0, 0, 0);
+
+read(This0, i32) ->
+  {This1, {ok, Zigzag}} = read_varint(This0, 0, 0),
+  {This1, {ok, from_zigzag(Zigzag)}};
+
+read(This0, i64) ->
+  {This1, {ok, Zigzag}} = read_varint(This0, 0, 0),
+  {This1, {ok, from_zigzag(Zigzag)}};
+
+read(This0, double) ->
+  {This1, Bytes} = read_data(This0, 8),
+  case Bytes of
+    {ok, <<Val:64/float-signed-little, _/binary>>} -> {This1, {ok, Val}};
+    Else -> {This1, Else}
+  end;
+
+% returns a binary directly, call binary_to_list if necessary
+read(This0, string) ->
+  {This1, {ok, Sz}}  = read(This0, ui32),
+  read_data(This1, Sz).
+
+-spec read_data(#t_compact{}, non_neg_integer()) ->
+    {#t_compact{}, {ok, binary()} | {error, _Reason}}.
+read_data(This, 0) -> {This, {ok, <<>>}};
+read_data(This = #t_compact{transport = Trans}, Len) when is_integer(Len) andalso Len > 0 ->
+    {NewTransport, Result} = thrift_transport:read(Trans, Len),
+    {This#t_compact{transport = NewTransport}, Result}.
+
+
+%%%% FACTORY GENERATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% returns a (fun() -> thrift_protocol())
+new_protocol_factory(TransportFactory, _Options) ->
+  F = fun() ->
+          case TransportFactory() of
+            {ok, Transport} ->
+              thrift_compact_protocol:new(
+                Transport,
+                []);
+            {error, Error} ->
+              {error, Error}
+          end
+      end,
+  {ok, F}.
diff --git a/lib/erl/src/thrift_file_transport.erl b/lib/erl/src/thrift_file_transport.erl
index ba3aa89..071152b 100644
--- a/lib/erl/src/thrift_file_transport.erl
+++ b/lib/erl/src/thrift_file_transport.erl
@@ -21,69 +21,95 @@
 
 -behaviour(thrift_transport).
 
--export([new_reader/1,
-         new/1,
-         new/2,
-         write/2, read/2, flush/1, close/1]).
+%% constructors
+-export([new/1, new/2]).
+%% protocol callbacks
+-export([read/2, read_exact/2, write/2, flush/1, close/1]).
+%% legacy api
+-export([new_reader/1]).
 
--record(t_file_transport, {device,
-                           should_close = true,
-                           mode = write}).
--type state() :: #t_file_transport{}.
--include("thrift_transport_behaviour.hrl").
 
-%%%% CONSTRUCTION   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-record(t_file, {
+  device,
+  should_close = true,
+  mode = write
+}).
 
-new_reader(Filename) ->
-    case file:open(Filename, [read, binary, {read_ahead, 1024*1024}]) of
-        {ok, IODevice} ->
-            new(IODevice, [{should_close, true}, {mode, read}]);
-        Error -> Error
-    end.
+-type state() :: #t_file{}.
 
-new(Device) ->
-    new(Device, []).
 
-%% Device :: io_device()
-%%
+-spec new(Device::file:io_device()) ->
+  thrift_transport:t_transport().
+
+new(Device) -> new(Device, []).
+
+-spec new(Device::file:io_device(), Opts::list()) ->
+  thrift_transport:t_transport().
+
 %% Device should be opened in raw and binary mode.
 new(Device, Opts) when is_list(Opts) ->
-    State = parse_opts(Opts, #t_file_transport{device = Device}),
-    thrift_transport:new(?MODULE, State).
+  State = parse_opts(Opts, #t_file{device = Device}),
+  thrift_transport:new(?MODULE, State).
 
 
-%% Parse options
-parse_opts([{should_close, Bool} | Rest], State) when is_boolean(Bool) ->
-    parse_opts(Rest, State#t_file_transport{should_close = Bool});
-parse_opts([{mode, Mode} | Rest], State)
-  when Mode =:= write;
-       Mode =:= read ->
-    parse_opts(Rest, State#t_file_transport{mode = Mode});
+parse_opts([{should_close, Bool}|Rest], State)
+when is_boolean(Bool) ->
+  parse_opts(Rest, State#t_file{should_close = Bool});
+parse_opts([{mode, Mode}|Rest], State)
+when Mode =:= write; Mode =:= read ->
+  parse_opts(Rest, State#t_file{mode = Mode});
 parse_opts([], State) ->
-     State.
+  State.
 
 
-%%%% TRANSPORT IMPL %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-write(This = #t_file_transport{device = Device, mode = write}, Data) ->
-    {This, file:write(Device, Data)};
-write(This, _D) ->
-    {This, {error, read_mode}}.
+-include("thrift_transport_behaviour.hrl").
 
 
-read(This = #t_file_transport{device = Device, mode = read}, Len)
-  when is_integer(Len), Len >= 0 ->
-    {This, file:read(Device, Len)};
-read(This, _D) ->
-    {This, {error, read_mode}}.
+read(State = #t_file{device = Device, mode = read}, Len)
+when is_integer(Len), Len >= 0 ->
+  case file:read(Device, Len) of
+    eof -> {State, {error, eof}};
+    {ok, Result} -> {State, {ok, iolist_to_binary(Result)}}
+  end;
+read(State, _) ->
+  {State, {error, write_mode}}.
 
-flush(This = #t_file_transport{device = Device, mode = write}) ->
-    {This, file:sync(Device)}.
 
-close(This = #t_file_transport{device = Device, should_close = SC}) ->
-    case SC of
-        true ->
-            {This, file:close(Device)};
-        false ->
-            {This, ok}
-    end.
+read_exact(State = #t_file{device = Device, mode = read}, Len)
+when is_integer(Len), Len >= 0 ->
+  case file:read(Device, Len) of
+    eof -> {State, {error, eof}};
+    {ok, Result} ->
+      case iolist_size(Result) of
+        X when X < Len -> {State, {error, eof}};
+        _ -> {State, {ok, iolist_to_binary(Result)}}
+      end
+  end;
+read_exact(State, _) ->
+  {State, {error, write_mode}}.
+
+
+write(State = #t_file{device = Device, mode = write}, Data) ->
+  {State, file:write(Device, Data)};
+write(State, _) ->
+  {State, {error, read_mode}}.
+
+
+flush(State = #t_file{device = Device, mode = write}) ->
+  {State, file:sync(Device)}.
+
+
+close(State = #t_file{device = Device, should_close = SC}) ->
+  case SC of
+    true -> {State, file:close(Device)};
+    false -> {State, ok}
+  end.
+
+
+%% legacy api. left for compatibility
+new_reader(Filename) ->
+  case file:open(Filename, [read, binary, {read_ahead, 1024*1024}]) of
+    {ok, IODevice} -> new(IODevice, [{should_close, true}, {mode, read}]);
+    Error -> Error
+  end.
+
diff --git a/lib/erl/src/thrift_framed_transport.erl b/lib/erl/src/thrift_framed_transport.erl
index eca3cbe..9a5d6af 100644
--- a/lib/erl/src/thrift_framed_transport.erl
+++ b/lib/erl/src/thrift_framed_transport.erl
@@ -21,83 +21,106 @@
 
 -behaviour(thrift_transport).
 
-%% API
+%% constructor
 -export([new/1]).
+%% protocol callbacks
+-export([read/2, read_exact/2, write/2, flush/1, close/1]).
 
-%% thrift_transport callbacks
--export([write/2, read/2, flush/1, close/1]).
 
--record(framed_transport, {wrapped, % a thrift_transport
-                           read_buffer, % iolist()
-                           write_buffer % iolist()
-                          }).
--type state() :: #framed_transport{}.
+-record(t_framed, {
+  wrapped,
+  read_buffer,
+  write_buffer
+}).
+
+-type state() :: #t_framed{}.
+
+
+-spec new(Transport::thrift_transport:t_transport()) ->
+  thrift_transport:t_transport().
+
+new(Wrapped) ->
+  State = #t_framed{
+    wrapped = Wrapped,
+    read_buffer = [],
+    write_buffer = []
+  },
+  thrift_transport:new(?MODULE, State).
+
+
 -include("thrift_transport_behaviour.hrl").
 
-new(WrappedTransport) ->
-    State = #framed_transport{wrapped = WrappedTransport,
-                              read_buffer = [],
-                              write_buffer = []},
-    thrift_transport:new(?MODULE, State).
 
-%% Writes data into the buffer
-write(State = #framed_transport{write_buffer = WBuf}, Data) ->
-    {State#framed_transport{write_buffer = [WBuf, Data]}, ok}.
+read(State = #t_framed{wrapped = Wrapped, read_buffer = Buffer}, Len)
+when is_integer(Len), Len >= 0 ->
+  Binary = iolist_to_binary(Buffer),
+  case Binary of
+    <<>> when Len > 0 ->
+      case next_frame(Wrapped) of
+        {NewState, {ok, Frame}} ->
+          NewBinary = iolist_to_binary([Binary, Frame]),
+          Give = min(iolist_size(NewBinary), Len),
+          {Result, Remaining} = split_binary(NewBinary, Give),
+          {State#t_framed{wrapped = NewState, read_buffer = Remaining}, {ok, Result}};
+        {NewState, Error} ->
+          {State#t_framed{wrapped = NewState}, Error}
+      end;
+    %% read of zero bytes
+    <<>> -> {State, {ok, <<>>}};
+    %% read buffer is nonempty
+    _ ->
+      Give = min(iolist_size(Binary), Len),
+      {Result, Remaining} = split_binary(Binary, Give),
+      {State#t_framed{read_buffer = Remaining}, {ok, Result}}
+  end.
 
-%% Flushes the buffer through to the wrapped transport
-flush(State0 = #framed_transport{write_buffer = Buffer,
-                                   wrapped = Wrapped0}) ->
-    FrameLen = iolist_size(Buffer),
-    Data     = [<<FrameLen:32/integer-signed-big>>, Buffer],
 
-    {Wrapped1, Response} = thrift_transport:write(Wrapped0, Data),
+read_exact(State = #t_framed{wrapped = Wrapped, read_buffer = Buffer}, Len)
+when is_integer(Len), Len >= 0 ->
+  Binary = iolist_to_binary(Buffer),
+  case iolist_size(Binary) of
+    %% read buffer is larger than requested read size
+    X when X >= Len ->
+      {Result, Remaining} = split_binary(Binary, Len),
+      {State#t_framed{read_buffer = Remaining}, {ok, Result}};
+    %% read buffer is insufficient for requested read size
+    _ ->
+      case next_frame(Wrapped) of
+        {NewState, {ok, Frame}} ->
+          read_exact(
+            State#t_framed{wrapped = NewState, read_buffer = [Buffer, Frame]},
+            Len
+          );
+        {NewState, Error} ->
+          {State#t_framed{wrapped = NewState}, Error}
+      end
+  end.
 
-    {Wrapped2, _} = thrift_transport:flush(Wrapped1),
+next_frame(Transport) ->
+  case thrift_transport:read_exact(Transport, 4) of
+    {NewState, {ok, <<FrameLength:32/integer-signed-big>>}} ->
+      thrift_transport:read_exact(NewState, FrameLength);
+    Error -> Error
+  end.
 
-    State1 = State0#framed_transport{wrapped = Wrapped2, write_buffer = []},
-    {State1, Response}.
 
-%% Closes the transport and the wrapped transport
-close(State = #framed_transport{wrapped = Wrapped0}) ->
-    {Wrapped1, Result} = thrift_transport:close(Wrapped0),
-    NewState = State#framed_transport{wrapped = Wrapped1},
-    {NewState, Result}.
+write(State = #t_framed{write_buffer = Buffer}, Data) ->
+  {State#t_framed{write_buffer = [Buffer, Data]}, ok}.
 
-%% Reads data through from the wrapped transport
-read(State0 = #framed_transport{wrapped = Wrapped0, read_buffer = RBuf},
-     Len) when is_integer(Len) ->
-    {Wrapped1, {RBuf1, RBuf1Size}} =
-        %% if the read buffer is empty, read another frame
-        %% otherwise, just read from what's left in the buffer
-        case iolist_size(RBuf) of
-            0 ->
-                %% read the frame length
-                case thrift_transport:read(Wrapped0, 4) of
-                  {WrappedS1,
-                    {ok, <<FrameLen:32/integer-signed-big, _/binary>>}} ->
-                    %% then read the data
-                    case thrift_transport:read(WrappedS1, FrameLen) of
-                      {WrappedS2, {ok, Bin}} ->
-                        {WrappedS2, {Bin, erlang:byte_size(Bin)}};
-                      {WrappedS2, {error, Reason1}} ->
-                        {WrappedS2, {error, Reason1}}
-                    end;
-                  {WrappedS1, {error, Reason2}} ->
-                    {WrappedS1, {error, Reason2}}
-                end;
-            Sz ->
-                {Wrapped0, {RBuf, Sz}}
-        end,
 
-    %% pull off Give bytes, return them to the user, leave the rest in the buffer
-    case RBuf1 of
-      error ->
-        { State0#framed_transport {wrapped = Wrapped1, read_buffer = [] },
-          {RBuf1, RBuf1Size} };
-      _ ->
-        Give = min(RBuf1Size, Len),
-        <<Data:Give/binary, RBuf2/binary>> = iolist_to_binary(RBuf1),
+flush(State = #t_framed{write_buffer = Buffer, wrapped = Wrapped}) ->
+  case iolist_size(Buffer) of
+    %% if write buffer is empty, do nothing
+    0 -> {State, ok};
+    FrameLen ->
+      Data = [<<FrameLen:32/integer-signed-big>>, Buffer],
+      {Written, Response} = thrift_transport:write(Wrapped, Data),
+      {Flushed, ok} = thrift_transport:flush(Written),
+      {State#t_framed{wrapped = Flushed, write_buffer = []}, Response}
+  end.
 
-        { State0#framed_transport{wrapped = Wrapped1, read_buffer=RBuf2},
-          {ok, Data} }
-    end.
+
+close(State = #t_framed{wrapped = Wrapped}) ->
+  {Closed, Result} = thrift_transport:close(Wrapped),
+  {State#t_framed{wrapped = Closed}, Result}.
+
diff --git a/lib/erl/src/thrift_json_parser.erl b/lib/erl/src/thrift_json_parser.erl
new file mode 100644
index 0000000..4e47f10
--- /dev/null
+++ b/lib/erl/src/thrift_json_parser.erl
@@ -0,0 +1,419 @@
+%% Licensed to the Apache Software Foundation (ASF) under one
+%% or more contributor license agreements. See the NOTICE file
+%% distributed with this work for additional information
+%% regarding copyright ownership. The ASF licenses this file
+%% to you under the Apache License, Version 2.0 (the
+%% "License"); you may not use this file except in compliance
+%% with the License. You may obtain a copy of the License at
+%%
+%%   http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing,
+%% software distributed under the License is distributed on an
+%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+%% KIND, either express or implied. See the License for the
+%% specific language governing permissions and limitations
+%% under the License.
+%%
+%% The json parser implementation was created by
+%% alisdair sullivan <alisdair@hartbrake.com> based on
+%% the jsx json library
+
+-module(thrift_json_parser).
+-export([parser/0, handle_event/2]).
+
+
+-record(config, {strict_utf8 = false :: boolean()}).
+
+
+parser() -> fun(JSON) -> start(JSON, {?MODULE, []}, [], #config{}) end.
+
+
+handle_event(Event, {Handler, State}, _Config) -> {Handler, Handler:handle_event(Event, State)}.
+
+handle_event(end_json, State) -> lists:reverse([end_json] ++ State);
+handle_event(Event, State) -> [Event] ++ State.
+
+
+%% whitespace
+-define(space, 16#20).
+-define(tab, 16#09).
+-define(cr, 16#0D).
+-define(newline, 16#0A).
+
+%% object delimiters
+-define(start_object, 16#7B).
+-define(end_object, 16#7D).
+
+%% array delimiters
+-define(start_array, 16#5B).
+-define(end_array, 16#5D).
+
+%% kv seperator
+-define(comma, 16#2C).
+-define(doublequote, 16#22).
+-define(singlequote, 16#27).
+-define(colon, 16#3A).
+
+%% string escape sequences
+-define(rsolidus, 16#5C).
+-define(solidus, 16#2F).
+
+%% math
+-define(zero, 16#30).
+-define(decimalpoint, 16#2E).
+-define(negative, 16#2D).
+-define(positive, 16#2B).
+
+%% comments
+-define(star, 16#2A).
+
+
+%% some useful guards
+-define(is_hex(Symbol),
+    (Symbol >= $a andalso Symbol =< $f) orelse
+    (Symbol >= $A andalso Symbol =< $F) orelse
+    (Symbol >= $0 andalso Symbol =< $9)
+).
+
+-define(is_nonzero(Symbol),
+    Symbol >= $1 andalso Symbol =< $9
+).
+
+-define(is_whitespace(Symbol),
+    Symbol =:= ?space; Symbol =:= ?tab; Symbol =:= ?cr; Symbol =:= ?newline
+).
+
+
+%% lists are benchmarked to be faster (tho higher in memory usage) than binaries
+new_seq() -> [].
+new_seq(C) -> [C].
+
+acc_seq(Seq, C) when is_list(C) -> lists:reverse(C) ++ Seq;
+acc_seq(Seq, C) -> [C] ++ Seq.
+
+end_seq(Seq) -> unicode:characters_to_binary(lists:reverse(Seq)).
+
+end_seq(Seq, _) -> end_seq(Seq).
+
+
+start(<<16#ef, 16#bb, 16#bf, Rest/binary>>, Handler, Stack, Config) ->
+    value(Rest, Handler, Stack, Config);
+start(Bin, Handler, Stack, Config) ->
+    value(Bin, Handler, Stack, Config).
+
+
+value(<<?doublequote, Rest/binary>>, Handler, Stack, Config) ->
+    string(Rest, Handler, new_seq(), Stack, Config);
+value(<<$t, Rest/binary>>, Handler, Stack, Config) ->
+    true(Rest, Handler, Stack, Config);
+value(<<$f, Rest/binary>>, Handler, Stack, Config) ->
+    false(Rest, Handler, Stack, Config);
+value(<<$n, Rest/binary>>, Handler, Stack, Config) ->
+    null(Rest, Handler, Stack, Config);
+value(<<?negative, Rest/binary>>, Handler, Stack, Config) ->
+    negative(Rest, Handler, new_seq($-), Stack, Config);
+value(<<?zero, Rest/binary>>, Handler, Stack, Config) ->
+    zero(Rest, Handler, new_seq($0), Stack, Config);
+value(<<S, Rest/binary>>, Handler, Stack, Config) when ?is_nonzero(S) ->
+    integer(Rest, Handler, new_seq(S), Stack, Config);
+value(<<?start_object, Rest/binary>>, Handler, Stack, Config) ->
+    object(Rest, handle_event(start_object, Handler, Config), [key|Stack], Config);
+value(<<?start_array, Rest/binary>>, Handler, Stack, Config) ->
+    array(Rest, handle_event(start_array, Handler, Config), [array|Stack], Config);
+value(<<S, Rest/binary>>, Handler, Stack, Config) when ?is_whitespace(S) ->
+    value(Rest, Handler, Stack, Config);
+value(_Bin, _Handler, _Stack, _Config) ->
+    erlang:error(badarg).
+
+
+object(<<?doublequote, Rest/binary>>, Handler, Stack, Config) ->
+    string(Rest, Handler, new_seq(), Stack, Config);
+object(<<?end_object, Rest/binary>>, Handler, [key|Stack], Config) ->
+    maybe_done(Rest, handle_event(end_object, Handler, Config), Stack, Config);
+object(<<S, Rest/binary>>, Handler, Stack, Config) when ?is_whitespace(S) ->
+    object(Rest, Handler, Stack, Config);
+object(_Bin, _Handler, _Stack, _Config) ->
+    erlang:error(badarg).
+
+
+array(<<?end_array, Rest/binary>>, Handler, [array|Stack], Config) ->
+    maybe_done(Rest, handle_event(end_array, Handler, Config), Stack, Config);
+array(<<S, Rest/binary>>, Handler, Stack, Config) when ?is_whitespace(S) ->
+    array(Rest, Handler, Stack, Config);
+array(Bin, Handler, Stack, Config) ->
+    value(Bin, Handler, Stack, Config).
+
+
+colon(<<?colon, Rest/binary>>, Handler, [key|Stack], Config) ->
+    value(Rest, Handler, [object|Stack], Config);
+colon(<<S, Rest/binary>>, Handler, Stack, Config) when ?is_whitespace(S) ->
+    colon(Rest, Handler, Stack, Config);
+colon(_Bin, _Handler, _Stack, _Config) ->
+    erlang:error(badarg).
+
+
+key(<<?doublequote, Rest/binary>>, Handler, Stack, Config) ->
+    string(Rest, Handler, new_seq(), Stack, Config);
+key(<<S, Rest/binary>>, Handler, Stack, Config) when ?is_whitespace(S) ->
+    key(Rest, Handler, Stack, Config);
+key(_Bin, _Handler, _Stack, _Config) ->
+    erlang:error(badarg).
+
+
+%% note that if you encounter an error from string and you can't find the clause that
+%%  caused it here, it might be in unescape below
+string(<<?doublequote, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    doublequote(Rest, Handler, Acc, Stack, Config);
+string(<<?solidus, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    string(Rest, Handler, acc_seq(Acc, ?solidus), Stack, Config);
+string(<<?rsolidus/utf8, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    unescape(Rest, Handler, Acc, Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#20, X < 16#2028 ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X == 16#2028; X == 16#2029 ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X > 16#2029, X < 16#d800 ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X > 16#dfff, X < 16#fdd0 ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X > 16#fdef, X < 16#fffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#10000, X < 16#1fffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#20000, X < 16#2fffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#30000, X < 16#3fffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#40000, X < 16#4fffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#50000, X < 16#5fffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#60000, X < 16#6fffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#70000, X < 16#7fffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#80000, X < 16#8fffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#90000, X < 16#9fffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#a0000, X < 16#afffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#b0000, X < 16#bfffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#c0000, X < 16#cfffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#d0000, X < 16#dfffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#e0000, X < 16#efffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#f0000, X < 16#ffffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+string(<<X/utf8, Rest/binary>>, Handler, Acc, Stack, Config) when X >= 16#100000, X < 16#10fffe ->
+    string(Rest, Handler, acc_seq(Acc, X), Stack, Config);
+%% surrogates
+string(<<237, X, _, Rest/binary>>, Handler, Acc, Stack, Config=#config{strict_utf8=false})
+        when X >= 160 ->
+    string(Rest, Handler, acc_seq(Acc, 16#fffd), Stack, Config);
+%% u+xfffe, u+xffff, control codes and other noncharacters
+string(<<_/utf8, Rest/binary>>, Handler, Acc, Stack, Config=#config{strict_utf8=false}) ->
+    string(Rest, Handler, acc_seq(Acc, 16#fffd), Stack, Config);
+%% u+fffe and u+ffff for R14BXX (subsequent runtimes will happily match the
+%%  preceding clause
+string(<<239, 191, X, Rest/binary>>, Handler, Acc, Stack, Config=#config{strict_utf8=false})
+        when X == 190; X == 191 ->
+    string(Rest, Handler, acc_seq(Acc, 16#fffd), Stack, Config);
+%% overlong encodings and missing continuations of a 2 byte sequence
+string(<<X, Rest/binary>>, Handler, Acc, Stack, Config=#config{strict_utf8=false})
+        when X >= 192, X =< 223 ->
+    strip_continuations(Rest, Handler, Acc, Stack, Config, 1);
+%% overlong encodings and missing continuations of a 3 byte sequence
+string(<<X, Rest/binary>>, Handler, Acc, Stack, Config=#config{strict_utf8=false})
+        when X >= 224, X =< 239 ->
+    strip_continuations(Rest, Handler, Acc, Stack, Config, 2);
+%% overlong encodings and missing continuations of a 4 byte sequence
+string(<<X, Rest/binary>>, Handler, Acc, Stack, Config=#config{strict_utf8=false})
+        when X >= 240, X =< 247 ->
+    strip_continuations(Rest, Handler, Acc, Stack, Config, 3);
+%% incompletes and unexpected bytes, including orphan continuations
+string(<<_, Rest/binary>>, Handler, Acc, Stack, Config=#config{strict_utf8=false}) ->
+    string(Rest, Handler, acc_seq(Acc, 16#fffd), Stack, Config);
+string(_Bin, _Handler, _Acc, _Stack, _Config) ->
+  erlang:error(badarg).
+
+
+doublequote(Rest, Handler, Acc, [key|_] = Stack, Config) ->
+    colon(Rest, handle_event({key, end_seq(Acc, Config)}, Handler, Config), Stack, Config);
+doublequote(Rest, Handler, Acc, Stack, Config) ->
+    maybe_done(Rest, handle_event({string, end_seq(Acc, Config)}, Handler, Config), Stack, Config).
+
+
+%% strips continuation bytes after bad utf bytes, guards against both too short
+%%  and overlong sequences. N is the maximum number of bytes to strip
+strip_continuations(<<Rest/binary>>, Handler, Acc, Stack, Config, 0) ->
+    string(Rest, Handler, acc_seq(Acc, 16#fffd), Stack, Config);
+strip_continuations(<<X, Rest/binary>>, Handler, Acc, Stack, Config, N) when X >= 128, X =< 191 ->
+    strip_continuations(Rest, Handler, Acc, Stack, Config, N - 1);
+%% not a continuation byte, insert a replacement character for sequence thus
+%%  far and dispatch back to string
+strip_continuations(<<Rest/binary>>, Handler, Acc, Stack, Config, _) ->
+    string(Rest, Handler, acc_seq(Acc, 16#fffd), Stack, Config).
+
+
+%% this all gets really gross and should probably eventually be folded into
+%%  but for now it fakes being part of string on incompletes and errors
+unescape(<<$b, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    string(Rest, Handler, acc_seq(Acc, $\b), Stack, Config);
+unescape(<<$f, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    string(Rest, Handler, acc_seq(Acc, $\f), Stack, Config);
+unescape(<<$n, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    string(Rest, Handler, acc_seq(Acc, $\n), Stack, Config);
+unescape(<<$r, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    string(Rest, Handler, acc_seq(Acc, $\r), Stack, Config);
+unescape(<<$t, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    string(Rest, Handler, acc_seq(Acc, $\t), Stack, Config);
+unescape(<<?doublequote, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    string(Rest, Handler, acc_seq(Acc, $\"), Stack, Config);
+unescape(<<?rsolidus, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    string(Rest, Handler, acc_seq(Acc, $\\), Stack, Config);
+unescape(<<?solidus, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    string(Rest, Handler, acc_seq(Acc, $/), Stack, Config);
+unescape(<<$u, $d, A, B, C, ?rsolidus, $u, $d, X, Y, Z, Rest/binary>>, Handler, Acc, Stack, Config)
+        when (A == $8 orelse A == $9 orelse A == $a orelse A == $b),
+             (X == $c orelse X == $d orelse X == $e orelse X == $f),
+             ?is_hex(B), ?is_hex(C), ?is_hex(Y), ?is_hex(Z)
+        ->
+    High = erlang:list_to_integer([$d, A, B, C], 16),
+    Low = erlang:list_to_integer([$d, X, Y, Z], 16),
+    Codepoint = (High - 16#d800) * 16#400 + (Low - 16#dc00) + 16#10000,
+    string(Rest, Handler, acc_seq(Acc, Codepoint), Stack, Config);
+unescape(<<$u, $d, A, B, C, ?rsolidus, $u, W, X, Y, Z, Rest/binary>>, Handler, Acc, Stack, Config)
+        when (A == $8 orelse A == $9 orelse A == $a orelse A == $b),
+             ?is_hex(B), ?is_hex(C), ?is_hex(W), ?is_hex(X), ?is_hex(Y), ?is_hex(Z)
+        ->
+    string(Rest, Handler, acc_seq(Acc, [16#fffd, 16#fffd]), Stack, Config);
+unescape(<<$u, A, B, C, D, Rest/binary>>, Handler, Acc, Stack, Config)
+        when ?is_hex(A), ?is_hex(B), ?is_hex(C), ?is_hex(D) ->
+    case erlang:list_to_integer([A, B, C, D], 16) of
+        Codepoint when Codepoint < 16#d800; Codepoint > 16#dfff ->
+            string(Rest, Handler, acc_seq(Acc, Codepoint), Stack, Config);
+        _ ->
+            string(Rest, Handler, acc_seq(Acc, 16#fffd), Stack, Config)
+    end;
+unescape(_Bin, _Handler, _Acc, _Stack, _Config) ->
+    erlang:error(badarg).
+
+
+%% like in strings, there's some pseudo states in here that will never
+%%  show up in errors or incompletes. some show up in value, some show
+%%  up in integer, decimal or exp
+negative(<<$0, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    zero(Rest, Handler, acc_seq(Acc, $0), Stack, Config);
+negative(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when ?is_nonzero(S) ->
+    integer(Rest, Handler, acc_seq(Acc, S), Stack, Config);
+negative(_Bin, _Handler, _Acc, _Stack, _Config) ->
+    erlang:error(badarg).
+
+
+zero(<<?decimalpoint, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    decimal(Rest, Handler, acc_seq(Acc, ?decimalpoint), Stack, Config);
+zero(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= $e; S =:= $E ->
+    e(Rest, Handler, acc_seq(Acc, ".0e"), Stack, Config);
+zero(Bin, Handler, Acc, Stack, Config) ->
+    finish_number(Bin, Handler, {zero, Acc}, Stack, Config).
+
+
+integer(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= ?zero; ?is_nonzero(S) ->
+    integer(Rest, Handler, acc_seq(Acc, S), Stack, Config);
+integer(<<?decimalpoint, Rest/binary>>, Handler, Acc, Stack, Config) ->
+    initialdecimal(Rest, Handler, acc_seq(Acc, ?decimalpoint), Stack, Config);
+integer(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= $e; S =:= $E ->
+    e(Rest, Handler, acc_seq(Acc, ".0e"), Stack, Config);
+integer(Bin, Handler, Acc, Stack, Config) ->
+    finish_number(Bin, Handler, {integer, Acc}, Stack, Config).
+
+
+initialdecimal(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= ?zero; ?is_nonzero(S) ->
+    decimal(Rest, Handler, acc_seq(Acc, S), Stack, Config);
+initialdecimal(_Bin, _Handler, _Acc, _Stack, _Config) ->
+    erlang:error(badarg).
+
+
+decimal(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= ?zero; ?is_nonzero(S) ->
+    decimal(Rest, Handler, acc_seq(Acc, S), Stack, Config);
+decimal(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= $e; S =:= $E ->
+    e(Rest, Handler, acc_seq(Acc, $e), Stack, Config);
+decimal(Bin, Handler, Acc, Stack, Config) ->
+    finish_number(Bin, Handler, {decimal, Acc}, Stack, Config).
+
+
+e(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= ?zero; ?is_nonzero(S) ->
+    exp(Rest, Handler, acc_seq(Acc, S), Stack, Config);
+e(<<Sign, Rest/binary>>, Handler, Acc, Stack, Config) when Sign =:= ?positive; Sign =:= ?negative ->
+    ex(Rest, Handler, acc_seq(Acc, Sign), Stack, Config);
+e(_Bin, _Handler, _Acc, _Stack, _Config) ->
+    erlang:error(badarg).
+
+
+ex(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= ?zero; ?is_nonzero(S) ->
+    exp(Rest, Handler, acc_seq(Acc, S), Stack, Config);
+ex(_Bin, _Handler, _Acc, _Stack, _Config) ->
+    erlang:error(badarg).
+
+
+exp(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= ?zero; ?is_nonzero(S) ->
+    exp(Rest, Handler, acc_seq(Acc, S), Stack, Config);
+exp(Bin, Handler, Acc, Stack, Config) ->
+    finish_number(Bin, Handler, {exp, Acc}, Stack, Config).
+
+
+finish_number(Rest, Handler, Acc, [], Config) ->
+    maybe_done(Rest, handle_event(format_number(Acc), Handler, Config), [], Config);
+finish_number(Rest, Handler, Acc, Stack, Config) ->
+    maybe_done(Rest, handle_event(format_number(Acc), Handler, Config), Stack, Config).
+
+
+format_number({zero, Acc}) -> {integer, list_to_integer(lists:reverse(Acc))};
+format_number({integer, Acc}) -> {integer, list_to_integer(lists:reverse(Acc))};
+format_number({decimal, Acc}) -> {float, list_to_float(lists:reverse(Acc))};
+format_number({exp, Acc}) -> {float, list_to_float(lists:reverse(Acc))}.
+
+
+true(<<$r, $u, $e, Rest/binary>>, Handler, Stack, Config) ->
+    maybe_done(Rest, handle_event({literal, true}, Handler, Config), Stack, Config);
+true(_Bin, _Handler, _Stack, _Config) ->
+    erlang:error(badarg).
+
+
+false(<<$a, $l, $s, $e, Rest/binary>>, Handler, Stack, Config) ->
+    maybe_done(Rest, handle_event({literal, false}, Handler, Config), Stack, Config);
+false(_Bin, _Handler, _Stack, _Config) ->
+    erlang:error(badarg).
+
+
+null(<<$u, $l, $l, Rest/binary>>, Handler, Stack, Config) ->
+    maybe_done(Rest, handle_event({literal, null}, Handler, Config), Stack, Config);
+null(_Bin, _Handler, _Stack, _Config) ->
+    erlang:error(badarg).
+
+
+maybe_done(<<Rest/binary>>, Handler, [], Config) ->
+    done(Rest, handle_event(end_json, Handler, Config), [], Config);
+maybe_done(<<?end_object, Rest/binary>>, Handler, [object|Stack], Config) ->
+    maybe_done(Rest, handle_event(end_object, Handler, Config), Stack, Config);
+maybe_done(<<?end_array, Rest/binary>>, Handler, [array|Stack], Config) ->
+    maybe_done(Rest, handle_event(end_array, Handler, Config), Stack, Config);
+maybe_done(<<?comma, Rest/binary>>, Handler, [object|Stack], Config) ->
+    key(Rest, Handler, [key|Stack], Config);
+maybe_done(<<?comma, Rest/binary>>, Handler, [array|_] = Stack, Config) ->
+    value(Rest, Handler, Stack, Config);
+maybe_done(<<S, Rest/binary>>, Handler, Stack, Config) when ?is_whitespace(S) ->
+    maybe_done(Rest, Handler, Stack, Config);
+maybe_done(_Bin, _Handler, _Stack, _Config) ->
+    erlang:error(badarg).
+
+
+done(<<S, Rest/binary>>, Handler, [], Config) when ?is_whitespace(S) ->
+    done(Rest, Handler, [], Config);
+done(<<>>, {_Handler, State}, [], _Config) -> State;
+done(_Bin, _Handler, _Stack, _Config) -> erlang:error(badarg).
diff --git a/lib/erl/src/thrift_json_protocol.erl b/lib/erl/src/thrift_json_protocol.erl
index aa4aed8..c5f3da8 100644
--- a/lib/erl/src/thrift_json_protocol.erl
+++ b/lib/erl/src/thrift_json_protocol.erl
@@ -56,6 +56,7 @@
 typeid_to_json(?tType_BOOL) -> "tf";
 typeid_to_json(?tType_BYTE) -> "i8";
 typeid_to_json(?tType_DOUBLE) -> "dbl";
+typeid_to_json(?tType_I8) -> "i8";
 typeid_to_json(?tType_I16) -> "i16";
 typeid_to_json(?tType_I32) -> "i32";
 typeid_to_json(?tType_I64) -> "i64";
@@ -66,8 +67,8 @@
 typeid_to_json(?tType_LIST) -> "lst".
 
 json_to_typeid("tf") -> ?tType_BOOL;
-json_to_typeid("i8") -> ?tType_BYTE;
 json_to_typeid("dbl") -> ?tType_DOUBLE;
+json_to_typeid("i8") -> ?tType_I8;
 json_to_typeid("i16") -> ?tType_I16;
 json_to_typeid("i32") -> ?tType_I32;
 json_to_typeid("i64") -> ?tType_I64;
@@ -294,7 +295,7 @@
         {context_pre_item, false},
         case is_binary(Str) of
             true -> Str;
-            false -> jsx:term_to_json(list_to_binary(Str), [{strict, false}])
+            false -> <<"\"", (list_to_binary(Str))/binary, "\"">>
         end,
         {context_post_item, false}
     ]);
@@ -325,10 +326,11 @@
 %% Subsequent calls to read actually operate on the events returned by JSX.
 read_all(#json_protocol{transport = Transport0} = State) ->
     {Transport1, Bin} = read_all_1(Transport0, []),
-    P = jsx:parser(),
+    P = thrift_json_parser:parser(),
+    [First|Rest] = P(Bin),
     State#json_protocol{
         transport = Transport1,
-        jsx = P(Bin)
+        jsx = {event, First, Rest}
     }.
 
 read_all_1(Transport0, IoList) ->
@@ -346,8 +348,8 @@
 % type as input. Comparing the read event from the one is was passed, it
 % returns an error if something other than the expected value is encountered.
 % Expect also maintains the context stack in #json_protocol.
-expect(#json_protocol{jsx={event, {Type, Data}=Ev, Next}}=State, ExpectedType) ->
-    NextState = State#json_protocol{jsx=Next()},
+expect(#json_protocol{jsx={event, {Type, Data}=Ev, [Next|Rest]}}=State, ExpectedType) ->
+    NextState = State#json_protocol{jsx={event, Next, Rest}},
     case Type == ExpectedType of
         true -> 
             {NextState, {ok, convert_data(Type, Data)}};
@@ -385,8 +387,8 @@
             Error
     end.
 
-read_field(#json_protocol{jsx={event, Field, Next}} = State) ->
-    NewState = State#json_protocol{jsx=Next()},
+read_field(#json_protocol{jsx={event, Field, [Next|Rest]}} = State) ->
+    NewState = State#json_protocol{jsx={event, Next, Rest}},
     {NewState, Field}.
 
 read(This0, message_begin) ->
@@ -563,4 +565,3 @@
                 thrift_json_protocol:new(Transport, [])
         end,
     {ok, F}.
-
diff --git a/lib/erl/src/thrift_membuffer_transport.erl b/lib/erl/src/thrift_membuffer_transport.erl
new file mode 100644
index 0000000..be9acb2
--- /dev/null
+++ b/lib/erl/src/thrift_membuffer_transport.erl
@@ -0,0 +1,83 @@
+%%
+%% 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.
+%%
+
+-module(thrift_membuffer_transport).
+
+-behaviour(thrift_transport).
+
+%% constructors
+-export([new/0, new/1]).
+%% protocol callbacks
+-export([read/2, read_exact/2, write/2, flush/1, close/1]).
+
+
+-record(t_membuffer, {
+  buffer = []
+}).
+
+-type state() :: #t_membuffer{}.
+
+
+-spec new() -> thrift_transport:t_transport().
+
+new() -> new([]).
+
+-spec new(Buf::iodata()) -> thrift_transport:t_transport().
+
+new(Buf) when is_list(Buf) ->
+  State = #t_membuffer{buffer = Buf},
+  thrift_transport:new(?MODULE, State);
+new(Buf) when is_binary(Buf) ->
+  State = #t_membuffer{buffer = [Buf]},
+  thrift_transport:new(?MODULE, State).
+
+
+-include("thrift_transport_behaviour.hrl").
+
+
+read(State = #t_membuffer{buffer = Buf}, Len)
+when is_integer(Len), Len >= 0 ->
+  Binary = iolist_to_binary(Buf),
+  Give = min(iolist_size(Binary), Len),
+  {Result, Remaining} = split_binary(Binary, Give),
+  {State#t_membuffer{buffer = Remaining}, {ok, Result}}.
+
+
+read_exact(State = #t_membuffer{buffer = Buf}, Len)
+when is_integer(Len), Len >= 0 ->
+  Binary = iolist_to_binary(Buf),
+  case iolist_size(Binary) of
+    X when X >= Len ->
+      {Result, Remaining} = split_binary(Binary, Len),
+      {State#t_membuffer{buffer = Remaining}, {ok, Result}};
+    _ ->
+      {State, {error, eof}}
+  end.
+
+
+write(State = #t_membuffer{buffer = Buf}, Data)
+when is_list(Data); is_binary(Data) ->
+  {State#t_membuffer{buffer = [Buf, Data]}, ok}.
+
+
+flush(State) -> {State, ok}.
+
+
+close(State) -> {State, ok}.
+
diff --git a/lib/erl/src/thrift_memory_buffer.erl b/lib/erl/src/thrift_memory_buffer.erl
index 53abbc4..6a59ea5 100644
--- a/lib/erl/src/thrift_memory_buffer.erl
+++ b/lib/erl/src/thrift_memory_buffer.erl
@@ -21,42 +21,27 @@
 
 -behaviour(thrift_transport).
 
-%% API
--export([new/0, new/1, new_transport_factory/0]).
+%% constructors
+-export([new/0, new/1]).
+%% protocol callbacks
+-export([read/2, write/2, flush/1, close/1]).
+%% legacy api
+-export([new_transport_factory/0]).
 
-%% thrift_transport callbacks
--export([write/2, read/2, flush/1, close/1]).
 
--record(memory_buffer, {buffer}).
--type state() :: #memory_buffer{}.
--include("thrift_transport_behaviour.hrl").
+%% wrapper around thrift_membuffer_transport for legacy reasons
 
-new() ->
-    State = #memory_buffer{buffer = []},
-    thrift_transport:new(?MODULE, State).
+new() -> thrift_membuffer_transport:new().
 
-new (Buf) when is_list (Buf) ->
-  State = #memory_buffer{buffer = Buf},
-  thrift_transport:new(?MODULE, State);
-new (Buf) ->
-  State = #memory_buffer{buffer = [Buf]},
-  thrift_transport:new(?MODULE, State).
+new(State) -> thrift_membuffer_transport:new(State).
 
-new_transport_factory() ->
-    {ok, fun() -> new() end}.
+new_transport_factory() -> {ok, fun() -> new() end}.
 
-%% Writes data into the buffer
-write(State = #memory_buffer{buffer = Buf}, Data) ->
-    {State#memory_buffer{buffer = [Buf, Data]}, ok}.
+write(State, Data) -> thrift_membuffer_transport:write(State, Data).
 
-flush(State = #memory_buffer {buffer = Buf}) ->
-    {State#memory_buffer{buffer = []}, Buf}.
+read(State, Data) -> thrift_membuffer_transport:read(State, Data).
 
-close(State) ->
-    {State, ok}.
+flush(State) -> thrift_membuffer_transport:flush(State).
 
-read(State = #memory_buffer{buffer = Buf}, Len) when is_integer(Len) ->
-    Binary = iolist_to_binary(Buf),
-    Give = min(iolist_size(Binary), Len),
-    {Result, Remaining} = split_binary(Binary, Give),
-    {State#memory_buffer{buffer = Remaining}, {ok, Result}}.
+close(State) -> thrift_membuffer_transport:close(State).
+
diff --git a/lib/erl/src/thrift_multiplexed_map_wrapper.erl b/lib/erl/src/thrift_multiplexed_map_wrapper.erl
new file mode 100644
index 0000000..34c5e95
--- /dev/null
+++ b/lib/erl/src/thrift_multiplexed_map_wrapper.erl
@@ -0,0 +1,57 @@
+%%
+%% 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.
+%%
+
+-module(thrift_multiplexed_map_wrapper).
+
+-export([
+          new/0
+         ,store/3
+         ,find/2
+         ,fetch/2
+        ]).
+
+-type service_handler()     :: nonempty_string().
+-type module_()             :: atom().
+-type service_handler_map() :: [{ServiceHandler::service_handler(), Module::module_()}].
+
+-spec new() -> service_handler_map().
+new() ->
+    orddict:new().
+
+-spec store(ServiceHandler, Module, Map) -> NewMap when
+    ServiceHandler :: service_handler(),
+    Module         :: module_(),
+    Map            :: service_handler_map(),
+    NewMap         :: service_handler_map().
+store(ServiceHandler, Module, Map) ->
+    orddict:store(ServiceHandler, Module, Map).
+
+-spec find(ServiceHandler, Map) -> {ok, Module} | error when
+    ServiceHandler :: service_handler(),
+    Module         :: module_(),
+    Map            :: service_handler_map().
+find(ServiceHandler, Map) ->
+    orddict:find(ServiceHandler, Map).
+
+-spec fetch(ServiceHandler, Map) -> Module when
+    ServiceHandler :: service_handler(),
+    Module         :: module_(),
+    Map            :: service_handler_map().
+fetch(ServiceHandler, Map) ->
+    orddict:fetch(ServiceHandler, Map).
diff --git a/lib/erl/src/thrift_multiplexed_protocol.erl b/lib/erl/src/thrift_multiplexed_protocol.erl
new file mode 100644
index 0000000..5f7b70c
--- /dev/null
+++ b/lib/erl/src/thrift_multiplexed_protocol.erl
@@ -0,0 +1,83 @@
+%%
+%% 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.
+%%
+
+-module(thrift_multiplexed_protocol).
+
+-behaviour(thrift_protocol).
+
+-include("thrift_constants.hrl").
+-include("thrift_protocol.hrl").
+
+-include("thrift_protocol_behaviour.hrl").
+
+-export([new/2,
+         read/2,
+         write/2,
+         flush_transport/1,
+         close_transport/1
+        ]).
+
+-record(protocol, {module, data}).
+-type protocol() :: #protocol{}.
+
+-record (multiplexed_protocol, {protocol_module_to_decorate::atom(),
+								protocol_data_to_decorate::term(),
+								service_name::nonempty_string()}).
+
+-type state() :: #multiplexed_protocol{}.
+
+-spec new(ProtocolToDecorate::protocol(), ServiceName::nonempty_string()) -> {ok, Protocol::protocol()}.
+new(ProtocolToDecorate, ServiceName) when is_record(ProtocolToDecorate, protocol),
+                                          is_list(ServiceName) ->
+    State = #multiplexed_protocol{protocol_module_to_decorate = ProtocolToDecorate#protocol.module,
+                                    protocol_data_to_decorate = ProtocolToDecorate#protocol.data,
+                                                 service_name = ServiceName},
+    thrift_protocol:new(?MODULE, State).
+
+flush_transport(State = #multiplexed_protocol{protocol_module_to_decorate = ProtocolModuleToDecorate,
+                                                protocol_data_to_decorate = State0}) ->
+    {State1, ok} = ProtocolModuleToDecorate:flush_transport(State0),
+    {State#multiplexed_protocol{protocol_data_to_decorate = State1}, ok}.
+
+close_transport(State = #multiplexed_protocol{protocol_module_to_decorate = ProtocolModuleToDecorate,
+                                                protocol_data_to_decorate = State0}) ->
+    {State1, ok} = ProtocolModuleToDecorate:close_transport(State0),
+    {State#multiplexed_protocol{protocol_data_to_decorate = State1}, ok}.
+
+write(State = #multiplexed_protocol{protocol_module_to_decorate = ProtocolModuleToDecorate,
+                                      protocol_data_to_decorate = State0,
+                                                   service_name = ServiceName},
+      Message = #protocol_message_begin{name = Name}) ->
+    {State1, ok} = ProtocolModuleToDecorate:write(State0,
+                                                  Message#protocol_message_begin{name=ServiceName ++
+                                                                                      ?MULTIPLEXED_SERVICE_SEPARATOR ++
+                                                                                      Name}),
+    {State#multiplexed_protocol{protocol_data_to_decorate = State1}, ok};
+
+write(State = #multiplexed_protocol{protocol_module_to_decorate = ProtocolModuleToDecorate,
+                                      protocol_data_to_decorate = State0},
+      Message) ->
+    {State1, ok} = ProtocolModuleToDecorate:write(State0, Message),
+    {State#multiplexed_protocol{protocol_data_to_decorate = State1}, ok}.
+
+read(State = #multiplexed_protocol{protocol_module_to_decorate = ProtocolModuleToDecorate,
+                                     protocol_data_to_decorate = State0},
+     Message) ->
+    {State1, Result} = ProtocolModuleToDecorate:read(State0, Message),
+    {State#multiplexed_protocol{protocol_data_to_decorate = State1}, Result}.
diff --git a/lib/erl/src/thrift_processor.erl b/lib/erl/src/thrift_processor.erl
index d474294..5c9f26f 100644
--- a/lib/erl/src/thrift_processor.erl
+++ b/lib/erl/src/thrift_processor.erl
@@ -33,41 +33,53 @@
                            handler = Handler}).
 
 loop(State0 = #thrift_processor{protocol  = Proto0,
-                                handler = Handler}) ->
+                                handler = Handler,
+                                service = Service}) ->
+
     {Proto1, MessageBegin} = thrift_protocol:read(Proto0, message_begin),
     State1 = State0#thrift_processor{protocol = Proto1},
+
+    ErrorHandler = fun
+        (HandlerModules) when is_list(HandlerModules) -> thrift_multiplexed_map_wrapper:fetch(?MULTIPLEXED_ERROR_HANDLER_KEY, HandlerModules);
+        (HandlerModule) -> HandlerModule
+    end,
+
     case MessageBegin of
+
         #protocol_message_begin{name = Function,
-                                type = ?tMessageType_CALL,
-                                seqid = Seqid} ->
-            case handle_function(State1, list_to_atom(Function), Seqid) of
-                {State2, ok} -> loop(State2);
-                {_State2, {error, Reason}} ->
-                    Handler:handle_error(list_to_atom(Function), Reason),
-                    thrift_protocol:close_transport(Proto1),
-                    ok
-            end;
-        #protocol_message_begin{name = Function,
-                                type = ?tMessageType_ONEWAY, 
-                                seqid = Seqid} ->
-            case handle_function(State1, list_to_atom(Function), Seqid) of
-                {State2, ok} -> loop(State2);
-                {_State2, {error, Reason}} ->
-                    Handler:handle_error(list_to_atom(Function), Reason),
-                    thrift_protocol:close_transport(Proto1),
-                    ok
+                                type = Type,
+                                seqid = Seqid} when Type =:= ?tMessageType_CALL; Type =:= ?tMessageType_ONEWAY ->
+            case string:tokens(Function, ?MULTIPLEXED_SERVICE_SEPARATOR) of
+                [ServiceName, FunctionName] ->
+                    ServiceModule  = thrift_multiplexed_map_wrapper:fetch(ServiceName, Service),
+                    ServiceHandler = thrift_multiplexed_map_wrapper:fetch(ServiceName, Handler),
+                    case handle_function(State1#thrift_processor{service=ServiceModule, handler=ServiceHandler}, list_to_atom(FunctionName), Seqid) of
+                        {State2, ok} -> loop(State2#thrift_processor{service=Service, handler=Handler});
+                        {_State2, {error, Reason}} ->
+							apply(ErrorHandler(Handler), handle_error, [list_to_atom(Function), Reason]),
+                            thrift_protocol:close_transport(Proto1),
+                            ok
+                    end;
+                _ ->
+                    case handle_function(State1, list_to_atom(Function), Seqid) of
+                        {State2, ok} -> loop(State2);
+                        {_State2, {error, Reason}} ->
+							apply(ErrorHandler(Handler), handle_error, [list_to_atom(Function), Reason]),
+                            thrift_protocol:close_transport(Proto1),
+                            ok
+                    end
             end;
         {error, timeout = Reason} ->
-            Handler:handle_error(undefined, Reason),
+			apply(ErrorHandler(Handler), handle_error, [undefined, Reason]),
             thrift_protocol:close_transport(Proto1),
             ok;
         {error, closed = Reason} ->
             %% error_logger:info_msg("Client disconnected~n"),
-            Handler:handle_error(undefined, Reason),
+			apply(ErrorHandler(Handler), handle_error, [undefined, Reason]),
             thrift_protocol:close_transport(Proto1),
             exit(shutdown);
         {error, Reason} ->
-            Handler:handle_error(undefined, Reason),
+			apply(ErrorHandler(Handler), handle_error, [undefined, Reason]),
             thrift_protocol:close_transport(Proto1),
             exit(shutdown)
     end.
diff --git a/lib/erl/src/thrift_protocol.erl b/lib/erl/src/thrift_protocol.erl
index 193b07a..2fe10d6 100644
--- a/lib/erl/src/thrift_protocol.erl
+++ b/lib/erl/src/thrift_protocol.erl
@@ -63,8 +63,8 @@
 typeid_to_atom(?tType_STOP) -> field_stop;
 typeid_to_atom(?tType_VOID) -> void;
 typeid_to_atom(?tType_BOOL) -> bool;
-typeid_to_atom(?tType_BYTE) -> byte;
 typeid_to_atom(?tType_DOUBLE) -> double;
+typeid_to_atom(?tType_I8) -> byte;
 typeid_to_atom(?tType_I16) -> i16;
 typeid_to_atom(?tType_I32) -> i32;
 typeid_to_atom(?tType_I64) -> i64;
@@ -76,8 +76,9 @@
 
 term_to_typeid(void) -> ?tType_VOID;
 term_to_typeid(bool) -> ?tType_BOOL;
-term_to_typeid(byte) -> ?tType_BYTE;
+term_to_typeid(byte) -> ?tType_I8;
 term_to_typeid(double) -> ?tType_DOUBLE;
+term_to_typeid(i8) -> ?tType_I8;
 term_to_typeid(i16) -> ?tType_I16;
 term_to_typeid(i32) -> ?tType_I32;
 term_to_typeid(i64) -> ?tType_I64;
@@ -148,8 +149,12 @@
 read(IProto0, {map, KeyType, ValType}) ->
     {IProto1, #protocol_map_begin{size = Size, ktype = KType, vtype = VType}} =
         read(IProto0, map_begin),
-    {KType, KType} = {term_to_typeid(KeyType), KType},
-    {VType, VType} = {term_to_typeid(ValType), VType},
+    _ = case Size of
+      0 -> 0;
+      _ ->
+        {KType, KType} = {term_to_typeid(KeyType), KType},
+        {VType, VType} = {term_to_typeid(ValType), VType}
+    end,
     {List, IProto2} = lists:mapfoldl(fun(_, ProtoS0) ->
                                              {ProtoS1, {ok, Key}} = read(ProtoS0, KeyType),
                                              {ProtoS2, {ok, Val}} = read(ProtoS1, ValType),
@@ -191,7 +196,8 @@
         thrift_protocol:read(IProto0, field_begin),
     case {FType, Fid} of
         {?tType_STOP, _} ->
-            {IProto1, RTuple};
+            {IProto2, ok} = read(IProto1, struct_end),
+            {IProto2, RTuple};
         _Else ->
             case dict:find(Fid, SDict) of
                 {ok, {Type, Index}} ->
@@ -208,18 +214,16 @@
                             skip_field(FType, IProto1, SDict, RTuple)
                     end;
                 _Else2 ->
-                    error_logger:info_msg("Skipping field ~p with unknown fid~n", [Fid]),
                     skip_field(FType, IProto1, SDict, RTuple)
             end
     end.
 
 skip_field(FType, IProto0, SDict, RTuple) ->
-    FTypeAtom = thrift_protocol:typeid_to_atom(FType),
-    {IProto1, ok} = thrift_protocol:skip(IProto0, FTypeAtom),
+    {IProto1, ok} = skip(IProto0, typeid_to_atom(FType)),
     {IProto2, ok} = read(IProto1, field_end),
     read_struct_loop(IProto2, SDict, RTuple).
 
--spec skip(#protocol{}, any()) -> {#protocol{}, ok}.
+-spec skip(#protocol{}, atom()) -> {#protocol{}, ok}.
 
 skip(Proto0, struct) ->
     {Proto1, ok} = read(Proto0, struct_begin),
@@ -256,7 +260,7 @@
         ?tType_STOP ->
             {Proto1, ok};
         _Else ->
-            {Proto2, ok} = skip(Proto1, Type),
+            {Proto2, ok} = skip(Proto1, typeid_to_atom(Type)),
             {Proto3, ok} = read(Proto2, field_end),
             skip_struct_loop(Proto3)
     end.
@@ -266,8 +270,8 @@
                                                 size = Size}) ->
     case Size of
         N when N > 0 ->
-            {Proto1, ok} = skip(Proto0, Ktype),
-            {Proto2, ok} = skip(Proto1, Vtype),
+            {Proto1, ok} = skip(Proto0, typeid_to_atom(Ktype)),
+            {Proto2, ok} = skip(Proto1, typeid_to_atom(Vtype)),
             skip_map_loop(Proto2,
                           Map#protocol_map_begin{size = Size - 1});
         0 -> {Proto0, ok}
@@ -277,7 +281,7 @@
                                                 size = Size}) ->
     case Size of
         N when N > 0 ->
-            {Proto1, ok} = skip(Proto0, Etype),
+            {Proto1, ok} = skip(Proto0, typeid_to_atom(Etype)),
             skip_set_loop(Proto1,
                           Map#protocol_set_begin{size = Size - 1});
         0 -> {Proto0, ok}
@@ -287,7 +291,7 @@
                                                   size = Size}) ->
     case Size of
         N when N > 0 ->
-            {Proto1, ok} = skip(Proto0, Etype),
+            {Proto1, ok} = skip(Proto0, typeid_to_atom(Etype)),
             skip_list_loop(Proto1,
                            Map#protocol_list_begin{size = Size - 1});
         0 -> {Proto0, ok}
diff --git a/lib/erl/src/thrift_reconnecting_client.erl b/lib/erl/src/thrift_reconnecting_client.erl
index 8ff1941..538fd3a 100644
--- a/lib/erl/src/thrift_reconnecting_client.erl
+++ b/lib/erl/src/thrift_reconnecting_client.erl
@@ -36,14 +36,14 @@
           terminate/2,
           code_change/3 ]).
 
--record( state, { client = nil, 
+-record( state, { client = nil,
                   host,
                   port,
                   thrift_svc,
                   thrift_opts,
                   reconn_min,
                   reconn_max,
-                  reconn_time,
+                  reconn_time = 0,
                   op_cnt_dict,
                   op_time_dict } ).
 
@@ -115,9 +115,9 @@
              _From,
              State=#state{ client = Client } ) ->
 
-  Start = now(),
+  Timer = timer_fun(),
   Result = ( catch thrift_client:call( Client, Op, Args) ),
-  Time = timer:now_diff( now(), Start ),
+  Time = Timer(),
 
   case Result of
     { C, { ok, Reply } } ->
@@ -156,6 +156,9 @@
 %%                                       {stop, Reason, State}
 %% Description: Handling all non call/cast messages
 %%--------------------------------------------------------------------
+handle_info( try_connect, State ) ->
+  { noreply, try_connect( State ) };
+
 handle_info( _Info, State ) ->
   { noreply, State }.
 
@@ -214,6 +217,21 @@
     false -> Backoff
   end.
 
+-ifdef(time_correction).
+timer_fun() ->
+  T1 = erlang:monotonic_time(),
+  fun() ->
+    T2 = erlang:monotonic_time(),
+    erlang:convert_time_unit(T2 - T1, native, micro_seconds)
+  end.
+-else.
+timer_fun() ->
+  T1 = erlang:timestamp(),
+  fun() ->
+    T2 = erlang:timestamp(),
+    timer:now_diff(T2, T1)
+  end.
+-endif.
 
 incr_stats( Op, Result, Time,
             State = #state{ op_cnt_dict  = OpCntDict,
diff --git a/lib/erl/src/thrift_socket_server.erl b/lib/erl/src/thrift_socket_server.erl
index f7c7a02..4e3c052 100644
--- a/lib/erl/src/thrift_socket_server.erl
+++ b/lib/erl/src/thrift_socket_server.erl
@@ -21,12 +21,19 @@
 
 -behaviour(gen_server).
 
--export([start/1, stop/1]).
+-include ("thrift_constants.hrl").
 
--export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3,
-         handle_info/2]).
+-ifdef(TEST).
+    -compile(export_all).
+    -export_records([thrift_socket_server]).
+-else.
+    -export([start/1, stop/1]).
 
--export([acceptor_loop/1]).
+    -export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3,
+             handle_info/2]).
+
+    -export([acceptor_loop/1]).
+-endif.
 
 -record(thrift_socket_server,
         {port,
@@ -38,7 +45,10 @@
          listen=null,
          acceptor=null,
          socket_opts=[{recv_timeout, 500}],
-         framed=false
+         protocol=binary,
+         framed=false,
+         ssltransport=false,
+         ssloptions=[]
         }).
 
 start(State=#thrift_socket_server{}) ->
@@ -91,10 +101,46 @@
     parse_options(Rest, State#thrift_socket_server{ip=ParsedIp});
 parse_options([{socket_opts, L} | Rest], State) when is_list(L), length(L) > 0 ->
     parse_options(Rest, State#thrift_socket_server{socket_opts=L});
-parse_options([{handler, Handler} | Rest], State) ->
+
+parse_options([{handler, []} | _Rest], _State) ->
+    throw("At least an error handler must be defined.");
+parse_options([{handler, ServiceHandlerPropertyList} | Rest], State) when is_list(ServiceHandlerPropertyList) ->
+    ServiceHandlerMap =
+    case State#thrift_socket_server.handler of
+        undefined ->
+            lists:foldl(
+                fun ({ServiceName, ServiceHandler}, Acc) when is_list(ServiceName), is_atom(ServiceHandler) ->
+                        thrift_multiplexed_map_wrapper:store(ServiceName, ServiceHandler, Acc);
+                    (_, _Acc) ->
+                        throw("The handler option is not properly configured for multiplexed services. It should be a kind of [{\"error_handler\", Module::atom()}, {SericeName::list(), Module::atom()}, ...]")
+                end, thrift_multiplexed_map_wrapper:new(), ServiceHandlerPropertyList);
+        _ -> throw("Error while parsing the handler option.")
+    end,
+    case thrift_multiplexed_map_wrapper:find(?MULTIPLEXED_ERROR_HANDLER_KEY, ServiceHandlerMap) of
+        {ok, _ErrorHandler} -> parse_options(Rest, State#thrift_socket_server{handler=ServiceHandlerMap});
+        error -> throw("The handler option is not properly configured for multiplexed services. It should be a kind of [{\"error_handler\", Module::atom()}, {SericeName::list(), Module::atom()}, ...]")
+    end;
+parse_options([{handler, Handler} | Rest], State) when State#thrift_socket_server.handler == undefined, is_atom(Handler) ->
     parse_options(Rest, State#thrift_socket_server{handler=Handler});
-parse_options([{service, Service} | Rest], State) ->
+
+parse_options([{service, []} | _Rest], _State) ->
+    throw("At least one service module must be defined.");
+parse_options([{service, ServiceModulePropertyList} | Rest], State) when is_list(ServiceModulePropertyList) ->
+    ServiceModuleMap =
+    case State#thrift_socket_server.service of
+        undefined ->
+            lists:foldl(
+                fun ({ServiceName, ServiceModule}, Acc) when is_list(ServiceName), is_atom(ServiceModule) ->
+                        thrift_multiplexed_map_wrapper:store(ServiceName, ServiceModule, Acc);
+                    (_, _Acc) ->
+                        throw("The service option is not properly configured for multiplexed services. It should be a kind of [{SericeName::list(), ServiceModule::atom()}, ...]")
+                end, thrift_multiplexed_map_wrapper:new(), ServiceModulePropertyList);
+        _ -> throw("Error while parsing the service option.")
+    end,
+    parse_options(Rest, State#thrift_socket_server{service=ServiceModuleMap});
+parse_options([{service, Service} | Rest], State) when State#thrift_socket_server.service == undefined, is_atom(Service) ->
     parse_options(Rest, State#thrift_socket_server{service=Service});
+
 parse_options([{max, Max} | Rest], State) ->
     MaxInt = case Max of
                  Max when is_list(Max) ->
@@ -103,8 +149,17 @@
                      Max
              end,
     parse_options(Rest, State#thrift_socket_server{max=MaxInt});
+
+parse_options([{protocol, Proto} | Rest], State) when is_atom(Proto) ->
+    parse_options(Rest, State#thrift_socket_server{protocol=Proto});
+
 parse_options([{framed, Framed} | Rest], State) when is_boolean(Framed) ->
-    parse_options(Rest, State#thrift_socket_server{framed=Framed}).
+    parse_options(Rest, State#thrift_socket_server{framed=Framed});
+
+parse_options([{ssltransport, SSLTransport} | Rest], State) when is_boolean(SSLTransport) ->
+    parse_options(Rest, State#thrift_socket_server{ssltransport=SSLTransport});
+parse_options([{ssloptions, SSLOptions} | Rest], State) when is_list(SSLOptions) ->
+    parse_options(Rest, State#thrift_socket_server{ssloptions=SSLOptions}).
 
 start_server(State=#thrift_socket_server{name=Name}) ->
     case Name of
@@ -168,25 +223,32 @@
     State#thrift_socket_server{acceptor=null};
 new_acceptor(State=#thrift_socket_server{listen=Listen,
                                          service=Service, handler=Handler,
-                                         socket_opts=Opts, framed=Framed
+                                         socket_opts=Opts, framed=Framed, protocol=Proto,
+                                         ssltransport=SslTransport, ssloptions=SslOptions
                                         }) ->
     Pid = proc_lib:spawn_link(?MODULE, acceptor_loop,
-                              [{self(), Listen, Service, Handler, Opts, Framed}]),
+                              [{self(), Listen, Service, Handler, Opts, Framed, SslTransport, SslOptions, Proto}]),
     State#thrift_socket_server{acceptor=Pid}.
 
-acceptor_loop({Server, Listen, Service, Handler, SocketOpts, Framed})
+acceptor_loop({Server, Listen, Service, Handler, SocketOpts, Framed, SslTransport, SslOptions, Proto})
   when is_pid(Server), is_list(SocketOpts) ->
     case catch gen_tcp:accept(Listen) of % infinite timeout
         {ok, Socket} ->
             gen_server:cast(Server, {accepted, self()}),
             ProtoGen = fun() ->
-                               {ok, SocketTransport}   = thrift_socket_transport:new(Socket, SocketOpts),
-                               {ok, Transport}         =
-                                   case Framed of
-                                       true  -> thrift_framed_transport:new(SocketTransport);
-                                       false -> thrift_buffered_transport:new(SocketTransport)
-                                   end,
-                               {ok, Protocol}          = thrift_binary_protocol:new(Transport),
+                               {ok, SocketTransport} = case SslTransport of
+                                                           true  -> thrift_sslsocket_transport:new(Socket, SocketOpts, SslOptions);
+                                                           false -> thrift_socket_transport:new(Socket, SocketOpts)
+                                                       end,
+                               {ok, Transport}       = case Framed of
+                                                           true  -> thrift_framed_transport:new(SocketTransport);
+                                                           false -> thrift_buffered_transport:new(SocketTransport)
+                                                       end,
+                               {ok, Protocol}        = case Proto of
+                                                         compact -> thrift_compact_protocol:new(Transport);
+                                                         json -> thrift_json_protocol:new(Transport);
+                                                         _ -> thrift_binary_protocol:new(Transport)
+                                                       end,
                                {ok, Protocol}
                        end,
             thrift_processor:init({Server, ProtoGen, Service, Handler});
@@ -214,8 +276,11 @@
 handle_cast(stop, State) ->
     {stop, normal, State}.
 
-terminate(_Reason, #thrift_socket_server{listen=Listen, port=Port}) ->
+terminate(Reason, #thrift_socket_server{listen=Listen, port=Port}) ->
     gen_tcp:close(Listen),
+    {backtrace, Bt} = erlang:process_info(self(), backtrace),
+    error_logger:error_report({?MODULE, ?LINE,
+                               {child_error, Reason, Bt}}),
     case Port < 1024 of
         true ->
             catch fdsrv:stop(),
diff --git a/lib/erl/src/thrift_socket_transport.erl b/lib/erl/src/thrift_socket_transport.erl
index 5e1ef02..fa10ed0 100644
--- a/lib/erl/src/thrift_socket_transport.erl
+++ b/lib/erl/src/thrift_socket_transport.erl
@@ -21,102 +21,156 @@
 
 -behaviour(thrift_transport).
 
--export([new/1,
-         new/2,
-         write/2, read/2, flush/1, close/1,
+%% constructors
+-export([new/1, new/2]).
+%% transport callbacks
+-export([read/2, read_exact/2, write/2, flush/1, close/1]).
+%% legacy api
+-export([new_transport_factory/3]).
 
-         new_transport_factory/3]).
 
--record(data, {socket,
-               recv_timeout=infinity}).
--type state() :: #data{}.
--include("thrift_transport_behaviour.hrl").
+-record(t_socket, {
+  socket,
+  recv_timeout=60000,
+  buffer = []
+}).
 
-new(Socket) ->
-    new(Socket, []).
+-type state() :: #t_socket{}.
+
+
+-spec new(Socket::any()) ->
+  thrift_transport:t_transport().
+
+new(Socket) -> new(Socket, []).
+
+-spec new(Socket::any(), Opts::list()) ->
+  thrift_transport:t_transport().
 
 new(Socket, Opts) when is_list(Opts) ->
-    State =
-        case lists:keysearch(recv_timeout, 1, Opts) of
-            {value, {recv_timeout, Timeout}}
-            when is_integer(Timeout), Timeout > 0 ->
-                #data{socket=Socket, recv_timeout=Timeout};
-            _ ->
-                #data{socket=Socket}
-        end,
-    thrift_transport:new(?MODULE, State).
-
-%% Data :: iolist()
-write(This = #data{socket = Socket}, Data) ->
-    {This, gen_tcp:send(Socket, Data)}.
-
-read(This = #data{socket=Socket, recv_timeout=Timeout}, Len)
-  when is_integer(Len), Len >= 0 ->
-    case gen_tcp:recv(Socket, Len, Timeout) of
-        Err = {error, timeout} ->
-            error_logger:info_msg("read timeout: peer conn ~p", [inet:peername(Socket)]),
-            gen_tcp:close(Socket),
-            {This, Err};
-        Data ->
-            {This, Data}
-    end.
-
-%% We can't really flush - everything is flushed when we write
-flush(This) ->
-    {This, ok}.
-
-close(This = #data{socket = Socket}) ->
-    {This, gen_tcp:close(Socket)}.
+  State = parse_opts(Opts, #t_socket{socket = Socket}),
+  thrift_transport:new(?MODULE, State).
 
 
-%%%% FACTORY GENERATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+parse_opts([{recv_timeout, Timeout}|Rest], State)
+when is_integer(Timeout), Timeout > 0 ->
+  parse_opts(Rest, State#t_socket{recv_timeout = Timeout});
+parse_opts([{recv_timeout, infinity}|Rest], State) ->
+  parse_opts(Rest, State#t_socket{recv_timeout = infinity});
+parse_opts([], State) ->
+  State.
 
 
+-include("thrift_transport_behaviour.hrl").
+
+
+read(State = #t_socket{buffer = Buf}, Len)
+when is_integer(Len), Len >= 0 ->
+  Binary = iolist_to_binary(Buf),
+  case iolist_size(Binary) of
+    X when X >= Len ->
+      {Result, Remaining} = split_binary(Binary, Len),
+      {State#t_socket{buffer = Remaining}, {ok, Result}};
+    _ -> recv(State, Len)
+  end.
+
+recv(State = #t_socket{socket = Socket, buffer = Buf}, Len) ->
+  case gen_tcp:recv(Socket, 0, State#t_socket.recv_timeout) of
+    {error, Error} ->
+      gen_tcp:close(Socket),
+      {State, {error, Error}};
+    {ok, Data} ->
+      Binary = iolist_to_binary([Buf, Data]),
+      Give = min(iolist_size(Binary), Len),
+      {Result, Remaining} = split_binary(Binary, Give),
+      {State#t_socket{buffer = Remaining}, {ok, Result}}
+  end.
+
+
+read_exact(State = #t_socket{buffer = Buf}, Len)
+when is_integer(Len), Len >= 0 ->
+  Binary = iolist_to_binary(Buf),
+  case iolist_size(Binary) of
+    X when X >= Len -> read(State, Len);
+    X ->
+      case gen_tcp:recv(State#t_socket.socket, Len - X, State#t_socket.recv_timeout) of
+        {error, Error} ->
+          gen_tcp:close(State#t_socket.socket),
+          {State, {error, Error}};
+        {ok, Data} ->
+          {State#t_socket{buffer = []}, {ok, <<Binary/binary, Data/binary>>}}
+      end
+  end.
+
+
+write(State = #t_socket{socket = Socket}, Data) ->
+  case gen_tcp:send(Socket, Data) of
+    {error, Error} ->
+      gen_tcp:close(Socket),
+      {State, {error, Error}};
+    ok -> {State, ok}
+  end.
+
+
+flush(State) ->
+  {State#t_socket{buffer = []}, ok}.
+
+
+close(State = #t_socket{socket = Socket}) ->
+  {State, gen_tcp:close(Socket)}.
+
+
+%% legacy api. left for compatibility
+
 %% The following "local" record is filled in by parse_factory_options/2
 %% below. These options can be passed to new_protocol_factory/3 in a
 %% proplists-style option list. They're parsed like this so it is an O(n)
 %% operation instead of O(n^2)
--record(factory_opts, {connect_timeout = infinity,
-                       sockopts = [],
-                       framed = false}).
+-record(factory_opts, {
+  connect_timeout = infinity,
+  sockopts = [],
+  framed = false
+}).
 
-parse_factory_options([], Opts) ->
-    Opts;
-parse_factory_options([{framed, Bool} | Rest], Opts) when is_boolean(Bool) ->
-    parse_factory_options(Rest, Opts#factory_opts{framed=Bool});
-parse_factory_options([{sockopts, OptList} | Rest], Opts) when is_list(OptList) ->
-    parse_factory_options(Rest, Opts#factory_opts{sockopts=OptList});
-parse_factory_options([{connect_timeout, TO} | Rest], Opts) when TO =:= infinity; is_integer(TO) ->
-    parse_factory_options(Rest, Opts#factory_opts{connect_timeout=TO}).
+parse_factory_options([], FactoryOpts, TransOpts) -> {FactoryOpts, TransOpts};
+parse_factory_options([{framed, Bool}|Rest], FactoryOpts, TransOpts)
+when is_boolean(Bool) ->
+  parse_factory_options(Rest, FactoryOpts#factory_opts{framed = Bool}, TransOpts);
+parse_factory_options([{sockopts, OptList}|Rest], FactoryOpts, TransOpts)
+when is_list(OptList) ->
+  parse_factory_options(Rest, FactoryOpts#factory_opts{sockopts = OptList}, TransOpts);
+parse_factory_options([{connect_timeout, TO}|Rest], FactoryOpts, TransOpts)
+when TO =:= infinity; is_integer(TO) ->
+  parse_factory_options(Rest, FactoryOpts#factory_opts{connect_timeout = TO}, TransOpts);
+parse_factory_options([{recv_timeout, TO}|Rest], FactoryOpts, TransOpts)
+when TO =:= infinity; is_integer(TO) ->
+  parse_factory_options(Rest, FactoryOpts, [{recv_timeout, TO}] ++ TransOpts).
 
 
-%%
 %% Generates a "transport factory" function - a fun which returns a thrift_transport()
 %% instance.
-%% This can be passed into a protocol factory to generate a connection to a
+%% State can be passed into a protocol factory to generate a connection to a
 %% thrift server over a socket.
-%%
 new_transport_factory(Host, Port, Options) ->
-    ParsedOpts = parse_factory_options(Options, #factory_opts{}),
-
-    F = fun() ->
-                SockOpts = [binary,
-                            {packet, 0},
-                            {active, false},
-                            {nodelay, true} |
-                            ParsedOpts#factory_opts.sockopts],
-                case catch gen_tcp:connect(Host, Port, SockOpts,
-                                           ParsedOpts#factory_opts.connect_timeout) of
-                    {ok, Sock} ->
-                        {ok, Transport} = thrift_socket_transport:new(Sock),
-                        {ok, BufTransport} =
-                            case ParsedOpts#factory_opts.framed of
-                                true  -> thrift_framed_transport:new(Transport);
-                                false -> thrift_buffered_transport:new(Transport)
-                            end,
-                        {ok, BufTransport};
-                    Error  ->
-                        Error
-                end
+  {FactoryOpts, TransOpts} = parse_factory_options(Options, #factory_opts{}, []),
+  {ok, fun() -> SockOpts = [binary,
+      {packet, 0},
+      {active, false},
+      {nodelay, true}|FactoryOpts#factory_opts.sockopts
+    ],
+    case catch gen_tcp:connect(
+      Host,
+      Port,
+      SockOpts,
+      FactoryOpts#factory_opts.connect_timeout
+    ) of
+      {ok, Sock} ->
+        {ok, Transport} = thrift_socket_transport:new(Sock, TransOpts),
+        {ok, BufTransport} = case FactoryOpts#factory_opts.framed of
+          true  -> thrift_framed_transport:new(Transport);
+          false -> thrift_buffered_transport:new(Transport)
         end,
-    {ok, F}.
+        {ok, BufTransport};
+      Error  -> Error
+    end
+  end}.
+
diff --git a/lib/erl/src/thrift_sslsocket_transport.erl b/lib/erl/src/thrift_sslsocket_transport.erl
new file mode 100644
index 0000000..211153f
--- /dev/null
+++ b/lib/erl/src/thrift_sslsocket_transport.erl
@@ -0,0 +1,147 @@
+%%
+%% 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.
+%%
+-module(thrift_sslsocket_transport).
+
+-include("thrift_transport_behaviour.hrl").
+
+-behaviour(thrift_transport).
+
+-export([new/3,
+         write/2, read/2, flush/1, close/1,
+
+         new_transport_factory/3]).
+
+%% Export only for the transport factory
+-export([new/2]).
+
+-record(data, {socket,
+               recv_timeout=infinity}).
+-type state() :: #data{}.
+
+%% The following "local" record is filled in by parse_factory_options/2
+%% below. These options can be passed to new_protocol_factory/3 in a
+%% proplists-style option list. They're parsed like this so it is an O(n)
+%% operation instead of O(n^2)
+-record(factory_opts, {connect_timeout = infinity,
+                       sockopts = [],
+                       framed = false,
+                       ssloptions = []}).
+
+parse_factory_options([], Opts) ->
+    Opts;
+parse_factory_options([{framed, Bool} | Rest], Opts) when is_boolean(Bool) ->
+    parse_factory_options(Rest, Opts#factory_opts{framed=Bool});
+parse_factory_options([{sockopts, OptList} | Rest], Opts) when is_list(OptList) ->
+    parse_factory_options(Rest, Opts#factory_opts{sockopts=OptList});
+parse_factory_options([{connect_timeout, TO} | Rest], Opts) when TO =:= infinity; is_integer(TO) ->
+    parse_factory_options(Rest, Opts#factory_opts{connect_timeout=TO});
+parse_factory_options([{ssloptions, SslOptions} | Rest], Opts) when is_list(SslOptions) ->
+    parse_factory_options(Rest, Opts#factory_opts{ssloptions=SslOptions}).
+
+new(Socket, SockOpts, SslOptions) when is_list(SockOpts), is_list(SslOptions) ->
+    inet:setopts(Socket, [{active, false}]), %% => prevent the ssl handshake messages get lost
+
+    %% upgrade to an ssl socket
+    case catch ssl:ssl_accept(Socket, SslOptions) of % infinite timeout
+        {ok, SslSocket} ->
+            new(SslSocket, SockOpts);
+        {error, Reason} ->
+            exit({error, Reason});
+        Other ->
+            error_logger:error_report(
+              [{application, thrift},
+               "SSL accept failed error",
+               lists:flatten(io_lib:format("~p", [Other]))]),
+            exit({error, ssl_accept_failed})
+    end.
+
+new(SslSocket, SockOpts) ->
+    State =
+        case lists:keysearch(recv_timeout, 1, SockOpts) of
+            {value, {recv_timeout, Timeout}}
+              when is_integer(Timeout), Timeout > 0 ->
+                #data{socket=SslSocket, recv_timeout=Timeout};
+            _ ->
+                #data{socket=SslSocket}
+        end,
+    thrift_transport:new(?MODULE, State).
+
+%% Data :: iolist()
+write(This = #data{socket = Socket}, Data) ->
+    {This, ssl:send(Socket, Data)}.
+
+read(This = #data{socket=Socket, recv_timeout=Timeout}, Len)
+  when is_integer(Len), Len >= 0 ->
+    case ssl:recv(Socket, Len, Timeout) of
+        Err = {error, timeout} ->
+            error_logger:info_msg("read timeout: peer conn ~p", [inet:peername(Socket)]),
+            ssl:close(Socket),
+            {This, Err};
+        Data ->
+            {This, Data}
+    end.
+
+%% We can't really flush - everything is flushed when we write
+flush(This) ->
+    {This, ok}.
+
+close(This = #data{socket = Socket}) ->
+    {This, ssl:close(Socket)}.
+
+%%%% FACTORY GENERATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%
+%% Generates a "transport factory" function - a fun which returns a thrift_transport()
+%% instance.
+%% This can be passed into a protocol factory to generate a connection to a
+%% thrift server over a socket.
+%%
+new_transport_factory(Host, Port, Options) ->
+    ParsedOpts = parse_factory_options(Options, #factory_opts{}),
+
+    F = fun() ->
+                SockOpts = [binary,
+                            {packet, 0},
+                            {active, false},
+                            {nodelay, true} |
+                            ParsedOpts#factory_opts.sockopts],
+                case catch gen_tcp:connect(Host, Port, SockOpts,
+                                           ParsedOpts#factory_opts.connect_timeout) of
+                    {ok, Sock} ->
+                        SslSock = case catch ssl:connect(Sock, ParsedOpts#factory_opts.ssloptions,
+                                                         ParsedOpts#factory_opts.connect_timeout) of
+                                      {ok, SslSocket} ->
+                                          SslSocket;
+                                      Other ->
+                                          error_logger:info_msg("error while connecting over ssl - reason: ~p~n", [Other]),
+                                          catch gen_tcp:close(Sock),
+                                          exit(error)
+                                  end,
+                        {ok, Transport} = thrift_sslsocket_transport:new(SslSock, SockOpts),
+                        {ok, BufTransport} =
+                            case ParsedOpts#factory_opts.framed of
+                                true  -> thrift_framed_transport:new(Transport);
+                                false -> thrift_buffered_transport:new(Transport)
+                            end,
+                        {ok, BufTransport};
+                    Error  ->
+                        Error
+                end
+        end,
+    {ok, F}.
\ No newline at end of file
diff --git a/lib/erl/src/thrift_transport.erl b/lib/erl/src/thrift_transport.erl
index 39f8c05..2414bde 100644
--- a/lib/erl/src/thrift_transport.erl
+++ b/lib/erl/src/thrift_transport.erl
@@ -20,59 +20,107 @@
 -module(thrift_transport).
 
 -export([behaviour_info/1]).
+%% constructors
+-export([new/1, new/2]).
+%% transport callbacks
+-export([read/2, read_exact/2, write/2, flush/1, close/1]).
 
--export([new/2,
-         write/2,
-         read/2,
-         flush/1,
-         close/1
-        ]).
+-export_type([t_transport/0]).
+
 
 behaviour_info(callbacks) ->
-    [{read, 2},
-     {write, 2},
-     {flush, 1},
-     {close, 1}
-    ].
+  [{read, 2}, {write, 2}, {flush, 1}, {close, 1}].
 
--record(transport, {module, data}).
+
+-record(t_transport, {
+  module,
+  state
+}).
+
+-type state() :: #t_transport{}.
+-type t_transport() :: #t_transport{}.
+
 
 -ifdef(transport_wrapper_module).
 -define(debug_wrap(Transport),
-        case Transport#transport.module of
-            ?transport_wrapper_module ->
-                Transport;
-            _Else ->
-                {ok, Result} = ?transport_wrapper_module:new(Transport),
-                Result
-        end).
+  case Transport#t_transport.module of
+    ?transport_wrapper_module -> Transport;
+    _Else ->
+      {ok, Result} = ?transport_wrapper_module:new(Transport),
+      Result
+  end
+).
 -else.
 -define(debug_wrap(Transport), Transport).
 -endif.
 
-new(Module, Data) when is_atom(Module) ->
-    Transport0 = #transport{module = Module, data = Data},
-    Transport1 = ?debug_wrap(Transport0),
-    {ok, Transport1}.
 
--spec write(#transport{}, iolist() | binary()) -> {#transport{}, ok | {error, _Reason}}.
-write(Transport, Data) ->
-    Module = Transport#transport.module,
-    {NewTransData, Result} = Module:write(Transport#transport.data, Data),
-    {Transport#transport{data = NewTransData}, Result}.
+-type wrappable() ::
+  binary() |
+  list() |
+  {membuffer, binary() | list()} |
+  {tcp, port()} |
+  {tcp, port(), list()} |
+  {file, file:io_device()} |
+  {file, file:io_device(), list()} |
+  {file, file:filename()} |
+  {file, file:filename(), list()}.
 
--spec read(#transport{}, non_neg_integer()) -> {#transport{}, {ok, binary()} | {error, _Reason}}.
-read(Transport, Len) when is_integer(Len) ->
-    Module = Transport#transport.module,
-    {NewTransData, Result} = Module:read(Transport#transport.data, Len),
-    {Transport#transport{data = NewTransData}, Result}.
+-spec new(wrappable()) -> {ok, #t_transport{}}.
 
--spec flush(#transport{}) -> {#transport{}, ok | {error, _Reason}}.
-flush(Transport = #transport{module = Module, data = Data}) ->
-    {NewTransData, Result} = Module:flush(Data),
-    {Transport#transport{data = NewTransData}, Result}.
+new({membuffer, Membuffer}) when is_binary(Membuffer); is_list(Membuffer) ->
+  thrift_membuffer_transport:new(Membuffer);
+new({membuffer, Membuffer, []}) when is_binary(Membuffer); is_list(Membuffer) ->
+  thrift_membuffer_transport:new(Membuffer);
+new({tcp, Socket}) when is_port(Socket) ->
+  new({tcp, Socket, []});
+new({tcp, Socket, Opts}) when is_port(Socket) ->
+  thrift_socket_transport:new(Socket, Opts);
+new({file, Filename}) when is_list(Filename); is_binary(Filename) ->
+  new({file, Filename, []});
+new({file, Filename, Opts}) when is_list(Filename); is_binary(Filename) ->
+  {ok, File} = file:open(Filename, [raw, binary]),
+  new({file, File, Opts});
+new({file, File, Opts}) ->
+  thrift_file_transport:new(File, Opts).
 
--spec close(#transport{}) -> {#transport{}, ok | {error, _Reason}}.
-close(Transport = #transport{module = Module, data = Data}) ->
-    {NewTransData, Result} = Module:close(Data),
-    {Transport#transport{data = NewTransData}, Result}.
+-spec new(Module::module(), State::any()) -> {ok, #t_transport{}}.
+
+new(Module, State) when is_atom(Module) ->
+  {ok, ?debug_wrap(#t_transport{module = Module, state = State})}.
+
+
+-include("thrift_transport_behaviour.hrl").
+
+
+read(Transport = #t_transport{module = Module}, Len)
+when is_integer(Len), Len >= 0 ->
+  {NewState, Result} = Module:read(Transport#t_transport.state, Len),
+  {Transport#t_transport{state = NewState}, Result}.
+
+
+read_exact(Transport = #t_transport{module = Module}, Len)
+when is_integer(Len), Len >= 0 ->
+  case lists:keyfind(read_exact, 1, Module:module_info(exports)) of
+    {read_exact, 2} ->
+      {NewState, Result} = Module:read_exact(Transport#t_transport.state, Len),
+      {Transport#t_transport{state = NewState}, Result};
+    _ ->
+      read(Transport, Len)
+  end.
+
+
+write(Transport = #t_transport{module = Module}, Data) ->
+  {NewState, Result} = Module:write(Transport#t_transport.state, Data),
+  {Transport#t_transport{state = NewState}, Result}.
+
+
+flush(Transport = #t_transport{module = Module}) ->
+  {NewState, Result} = Module:flush(Transport#t_transport.state),
+  {Transport#t_transport{state = NewState}, Result}.
+
+
+close(Transport = #t_transport{module = Module}) ->
+  {NewState, Result} = Module:close(Transport#t_transport.state),
+  {Transport#t_transport{state = NewState}, Result}.
+
diff --git a/lib/erl/test/Thrift_omit_with.thrift b/lib/erl/test/Thrift_omit_with.thrift
new file mode 100644
index 0000000..8bffc7c
--- /dev/null
+++ b/lib/erl/test/Thrift_omit_with.thrift
@@ -0,0 +1,22 @@
+struct test1 {
+  1: i32 one
+  2: i32 two                    // omit
+  3: i32 three
+}
+
+struct test2 {
+  1: i32 one
+  2: test2 two                  // omit
+  3: i32 three
+}
+
+struct test3 {
+  1: i32 one
+  2: list<test1> two            // omit
+}
+
+struct test4 {
+  1: i32 one
+  2: map<i32,test1> two         // omit
+}
+
diff --git a/lib/erl/test/flags/LegacyNames.thrift b/lib/erl/test/flags/LegacyNames.thrift
new file mode 100644
index 0000000..38f2729
--- /dev/null
+++ b/lib/erl/test/flags/LegacyNames.thrift
@@ -0,0 +1,33 @@
+enum Numberz
+{
+  ONE = 1,
+  TWO,
+  THREE,
+  FIVE = 5,
+  SIX,
+  EIGHT = 8
+}
+
+const Numberz myNumberz = Numberz.ONE;
+
+struct CapitalizedStruct
+{
+  1: i32 Id,
+  2: binary message
+}
+
+struct ListCapitalizedStructs
+{
+  1: list<CapitalizedStruct> structs
+}
+
+exception Xception {
+  1: i32 errorCode,
+  2: binary message
+}
+
+service LegacyNames
+{
+  ListCapitalizedStructs Names(1: CapitalizedStruct foo, 2: CapitalizedStruct bar)
+    throws(1: Xception err)
+}
\ No newline at end of file
diff --git a/lib/erl/test/flags/Thrift3214.thrift b/lib/erl/test/flags/Thrift3214.thrift
new file mode 100644
index 0000000..a9110ce
--- /dev/null
+++ b/lib/erl/test/flags/Thrift3214.thrift
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+struct StringMap
+{
+  1: map<i32, string> data = {1: "a", 2: "b"};
+}
diff --git a/lib/erl/test/legacy_names_test.erl b/lib/erl/test/legacy_names_test.erl
new file mode 100644
index 0000000..c16aa3e
--- /dev/null
+++ b/lib/erl/test/legacy_names_test.erl
@@ -0,0 +1,69 @@
+%%
+%% Licensed to the Apache Software Foundation (ASF) under one
+%% or more contributor license agreements. See the NOTICE file
+%% distributed with this work for additional information
+%% regarding copyright ownership. The ASF licenses this file
+%% to you under the Apache License, Version 2.0 (the
+%% "License"); you may not use this file except in compliance
+%% with the License. You may obtain a copy of the License at
+%%
+%%   http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing,
+%% software distributed under the License is distributed on an
+%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+%% KIND, either express or implied. See the License for the
+%% specific language governing permissions and limitations
+%% under the License.
+%%
+
+-module(legacy_names_test).
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-include("gen-erl/legacyNames_constants.hrl").
+
+record_generation_test_() ->
+  [
+    {"capitalizedStruct record", ?_assertMatch(
+      {capitalizedStruct, _, _},
+      #capitalizedStruct{id=null,message=null}
+    )}
+  ].
+
+struct_info_test_() ->
+  [
+    {"capitalizedStruct extended definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, i32, 'id', undefined},
+        {2, undefined, string, 'message', undefined}
+      ]},
+      legacyNames_types:struct_info_ext(capitalizedStruct)
+    )},
+    {"listCapitalizedStructs extended definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {list, {struct, {'legacyNames_types', 'capitalizedStruct'}}}, 'structs', []}
+      ]},
+      legacyNames_types:struct_info_ext(listCapitalizedStructs)
+    )}
+  ].
+
+service_info_test_() ->
+  [
+    {"names params", ?_assertEqual(
+      {struct, [
+        {1, {struct, {'legacyNames_types', 'capitalizedStruct'}}},
+        {2, {struct, {'legacyNames_types', 'capitalizedStruct'}}}
+      ]},
+      legacyNames_thrift:function_info(names, params_type)
+    )},
+    {"names reply", ?_assertEqual(
+      {struct, {'legacyNames_types', 'listCapitalizedStructs'}},
+      legacyNames_thrift:function_info(names, reply_type)
+    )},
+    {"names exceptions", ?_assertEqual(
+      {struct, [{1, {struct, {'legacyNames_types', 'xception'}}}]},
+      legacyNames_thrift:function_info(names, exceptions)
+    )}
+  ].
diff --git a/lib/erl/test/multiplexing.thrift b/lib/erl/test/multiplexing.thrift
new file mode 100644
index 0000000..7c7994b
--- /dev/null
+++ b/lib/erl/test/multiplexing.thrift
@@ -0,0 +1,7 @@
+service Multiplexing_Calculator {
+    i32 add(1: i32 x, 2: i32 y)
+}
+
+service Multiplexing_WeatherReport {
+    double getTemperature()
+}
diff --git a/lib/erl/test/multiplexing_test.erl b/lib/erl/test/multiplexing_test.erl
new file mode 100644
index 0000000..0f2d616
--- /dev/null
+++ b/lib/erl/test/multiplexing_test.erl
@@ -0,0 +1,57 @@
+-module(multiplexing_test).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-export([
+     handle_function/2
+    ,handle_error/2
+]).
+
+start_multiplexed_server_test() ->
+
+    Port = 9090,
+    Services = [
+                {"Multiplexing_Calculator",    multiplexing__calculator_thrift},
+                {"Multiplexing_WeatherReport", multiplexing__weather_report_thrift}
+               ],
+
+    {ok, Pid} = thrift_socket_server:start([
+        {ip, "127.0.0.1"},
+        {port, Port},
+        {name, ?MODULE},
+        {service, Services},
+        {handler, [
+            {"error_handler",              ?MODULE},
+            {"Multiplexing_Calculator",    ?MODULE},
+            {"Multiplexing_WeatherReport", ?MODULE}
+        ]}
+     ]),
+
+    {ok, [{"Multiplexing_Calculator", CalculatorClient0},
+          {"Multiplexing_WeatherReport", WeatherReportClient0}]} = thrift_client_util:new_multiplexed("127.0.0.1", Port, Services, []),
+
+    ?assertMatch({_, {error, {bad_args, _, _}}}, thrift_client:call(WeatherReportClient0, getTemperature, [1])),
+    ?assertMatch({_, {error, {bad_args, _, _}}}, thrift_client:call(CalculatorClient0, add, [1])),
+    ?assertMatch({_, {error, {bad_args, _, _}}}, thrift_client:call(CalculatorClient0, add, [1,1,1])),
+
+    ?assertMatch({_, {error, {no_function, _}}}, thrift_client:call(CalculatorClient0, getTemperature, [])),
+    ?assertMatch({_, {error, {no_function, _}}}, thrift_client:call(WeatherReportClient0, add, [41, 1])),
+
+    ?assertMatch({_, {ok, 42}}, thrift_client:call(CalculatorClient0, add, [41, 1])),
+    ?assertMatch({_, {ok, 42.0}}, thrift_client:call(WeatherReportClient0, getTemperature, [])),
+
+    thrift_socket_server:stop(Pid).
+
+%% HANDLE FUNCTIONS
+
+%% Calculator handles
+handle_function(add, {X, Y}) ->
+    {reply, X + Y};
+
+%% WeatherReport handles
+handle_function(getTemperature, {}) ->
+    {reply, 42.0}.
+
+handle_error(_F, _Reason) ->
+%%     ?debugHere, ?debugVal({_F, _Reason}),
+    ok.
\ No newline at end of file
diff --git a/lib/erl/test/name_conflict_test.erl b/lib/erl/test/name_conflict_test.erl
new file mode 100644
index 0000000..b01df57
--- /dev/null
+++ b/lib/erl/test/name_conflict_test.erl
@@ -0,0 +1,299 @@
+%%
+%% 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.
+%%
+
+-module(name_conflict_test).
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-include("gen-erl/name_conflict_test_constants.hrl").
+
+record_generation_test_() ->
+  [
+    {"using record", ?_assertMatch(
+      {using, _, _},
+      #using{single=null,integer=null}
+    )},
+    {"delegate record", ?_assertMatch(
+      {delegate, _, _},
+      #delegate{partial=null,delegate=null}
+    )},
+    {"get record", ?_assertMatch(
+      {get, _},
+      #get{sbyte=null}
+    )},
+    {"partial record", ?_assertMatch(
+      {partial, _, _, _},
+      #partial{using=null}
+    )},
+    {"ClassAndProp record", ?_assertMatch(
+      {'ClassAndProp', _, _, _, _},
+      #'ClassAndProp'{
+        'ClassAndProp'=null,
+        'ClassAndProp_'=null,
+        'ClassAndProp__'=null,
+        'ClassAndProper'=null
+      }
+    )},
+    {"second_chance record", ?_assertMatch(
+      {second_chance, _, _, _, _},
+      #second_chance{
+        'SECOND_CHANCE'=null,
+        'SECOND_CHANCE_'=null,
+        'SECOND_CHANCE__'=null,
+        'SECOND_CHANCES'=null
+      }
+    )},
+    {"NOW_EAT_THIS record", ?_assertMatch(
+      {'NOW_EAT_THIS', _, _, _, _},
+      #'NOW_EAT_THIS'{
+        now_eat_this=null,
+        now_eat_this_=null,
+        now_eat_this__=null,
+        now_eat_this_and_this=null
+      }
+    )},
+    {"TheEdgeCase record", ?_assertMatch(
+      {'TheEdgeCase', _, _, _, _, _, _},
+      #'TheEdgeCase'{
+        theEdgeCase=null,
+        theEdgeCase_=null,
+        theEdgeCase__=null,
+        'TheEdgeCase'=null,
+        'TheEdgeCase_'=null,
+        'TheEdgeCase__'=null
+      }
+    )},
+    {"Tricky_ record", ?_assertMatch(
+      {'Tricky_', _, _},
+      #'Tricky_'{tricky=null,'Tricky'=null}
+    )},
+    {"Nested record", ?_assertMatch(
+      {'Nested', _, _, _, _, _, _},
+      #'Nested'{
+        'ClassAndProp'=null,
+        second_chance=null,
+        'NOW_EAT_THIS'=null,
+        'TheEdgeCase'=null,
+        'Tricky_'=null,
+        'Nested'=null
+      }
+    )},
+    {"Problem_ record", ?_assertMatch(
+      {'Problem_', _, _},
+      #'Problem_'{problem=null,'Problem'=null}
+    )}
+  ].
+
+struct_info_test_() ->
+  [
+    {"using definition", ?_assertEqual(
+      {struct, [{1, double},{2, double}]},
+      name_conflict_test_types:struct_info(using)
+    )},
+    {"delegate definition", ?_assertEqual(
+      {struct, [
+        {1, string},
+        {2, {struct, {name_conflict_test_types, delegate}}}
+      ]},
+      name_conflict_test_types:struct_info(delegate)
+    )},
+    {"get definition", ?_assertEqual(
+      {struct, [{1, bool}]},
+      name_conflict_test_types:struct_info(get)
+    )},
+    {"partial definition", ?_assertEqual(
+      {struct, [
+        {1, {struct, {name_conflict_test_types, using}}},
+        {2, bool},
+        {3, bool}
+      ]},
+      name_conflict_test_types:struct_info(partial)
+    )},
+    {"ClassAndProp definition", ?_assertEqual(
+      {struct, [{1, bool},{2, bool},{3, bool},{4, bool}]},
+      name_conflict_test_types:struct_info('ClassAndProp')
+    )},
+    {"second_chance definition", ?_assertEqual(
+      {struct, [{1, bool},{2, bool},{3, bool},{4, bool}]},
+      name_conflict_test_types:struct_info(second_chance)
+    )},
+    {"NOW_EAT_THIS definition", ?_assertEqual(
+      {struct, [{1, bool},{2, bool},{3, bool},{4, bool}]},
+      name_conflict_test_types:struct_info('NOW_EAT_THIS')
+    )},
+    {"TheEdgeCase definition", ?_assertEqual(
+      {struct, [{1, bool},{2, bool},{3, bool},{4, bool},{5, bool},{6, bool}]},
+      name_conflict_test_types:struct_info('TheEdgeCase')
+    )},
+    {"Tricky_ definition", ?_assertEqual(
+      {struct, [{1, bool},{2, bool}]},
+      name_conflict_test_types:struct_info('Tricky_')
+    )},
+    {"Nested definition", ?_assertEqual(
+      {struct, [
+        {1, {struct, {name_conflict_test_types, 'ClassAndProp'}}},
+        {2, {struct, {name_conflict_test_types, second_chance}}},
+        {3, {struct, {name_conflict_test_types, 'NOW_EAT_THIS'}}},
+        {4, {struct, {name_conflict_test_types, 'TheEdgeCase'}}},
+        {5, {struct, {name_conflict_test_types, 'Tricky_'}}},
+        {6, {struct, {name_conflict_test_types, 'Nested'}}}
+      ]},
+      name_conflict_test_types:struct_info('Nested')
+    )},
+    {"Problem_ definition", ?_assertEqual(
+      {struct, [{1, bool},{2, bool}]},
+      name_conflict_test_types:struct_info('Problem_')
+    )},
+    {"using extended definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, double, single, undefined},
+        {2, undefined, double, integer, undefined}
+      ]},
+      name_conflict_test_types:struct_info_ext(using)
+    )},
+    {"delegate extended definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, string, partial, undefined},
+        {2, undefined, {struct, {name_conflict_test_types, delegate}}, delegate, undefined}
+      ]},
+      name_conflict_test_types:struct_info_ext(delegate)
+    )},
+    {"get extended definition", ?_assertEqual(
+      {struct, [{1, undefined, bool, sbyte, undefined}]},
+      name_conflict_test_types:struct_info_ext(get)
+    )},
+    {"partial extended definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {struct, {name_conflict_test_types, using}}, using, #using{}},
+        {2, undefined, bool, read, undefined},
+        {3, undefined, bool, write, undefined}
+      ]},
+      name_conflict_test_types:struct_info_ext(partial)
+    )},
+    {"ClassAndProp extended definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, bool, 'ClassAndProp', undefined},
+        {2, undefined, bool, 'ClassAndProp_', undefined},
+        {3, undefined, bool, 'ClassAndProp__', undefined},
+        {4, undefined, bool, 'ClassAndProper', undefined}
+      ]},
+      name_conflict_test_types:struct_info_ext('ClassAndProp')
+    )},
+    {"second_chance extended definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, bool, 'SECOND_CHANCE', undefined},
+        {2, undefined, bool, 'SECOND_CHANCE_', undefined},
+        {3, undefined, bool, 'SECOND_CHANCE__', undefined},
+        {4, undefined, bool, 'SECOND_CHANCES', undefined}
+      ]},
+      name_conflict_test_types:struct_info_ext(second_chance)
+    )},
+    {"NOW_EAT_THIS extended definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, bool, now_eat_this, undefined},
+        {2, undefined, bool, now_eat_this_, undefined},
+        {3, undefined, bool, now_eat_this__, undefined},
+        {4, undefined, bool, now_eat_this_and_this, undefined}
+      ]},
+      name_conflict_test_types:struct_info_ext('NOW_EAT_THIS')
+    )},
+    {"TheEdgeCase extended definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, bool, theEdgeCase, undefined},
+        {2, undefined, bool, theEdgeCase_, undefined},
+        {3, undefined, bool, theEdgeCase__, undefined},
+        {4, undefined, bool, 'TheEdgeCase', undefined},
+        {5, undefined, bool, 'TheEdgeCase_', undefined},
+        {6, undefined, bool, 'TheEdgeCase__', undefined}
+      ]},
+      name_conflict_test_types:struct_info_ext('TheEdgeCase')
+    )},
+    {"Tricky_ extended definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, bool, tricky, undefined},
+        {2, undefined, bool, 'Tricky', undefined}
+      ]},
+      name_conflict_test_types:struct_info_ext('Tricky_')
+    )},
+    {"Nested extended definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {struct, {
+          name_conflict_test_types,
+          'ClassAndProp'
+        }}, 'ClassAndProp', #'ClassAndProp'{}},
+        {2, undefined, {struct, {
+          name_conflict_test_types,
+          second_chance
+        }}, second_chance, #second_chance{}},
+        {3, undefined, {struct, {
+          name_conflict_test_types,
+          'NOW_EAT_THIS'
+        }}, 'NOW_EAT_THIS', #'NOW_EAT_THIS'{}},
+        {4, undefined, {struct, {
+          name_conflict_test_types,
+          'TheEdgeCase'
+        }}, 'TheEdgeCase', #'TheEdgeCase'{}},
+        {5, undefined, {struct, {
+          name_conflict_test_types,
+          'Tricky_'
+        }}, 'Tricky_', #'Tricky_'{}},
+        {6, undefined, {struct, {
+          name_conflict_test_types,
+          'Nested'
+        }}, 'Nested', undefined}
+      ]},
+      name_conflict_test_types:struct_info_ext('Nested')
+    )},
+    {"Problem_ extended definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, bool, problem, undefined},
+        {2, undefined, bool, 'Problem', undefined}
+      ]},
+      name_conflict_test_types:struct_info_ext('Problem_')
+    )}
+  ].
+
+service_info_test_() ->
+  [
+    {"event params", ?_assertEqual(
+      {struct, [{1, {struct, {name_conflict_test_types, partial}}}]},
+      extern_thrift:function_info(event, params_type)
+    )},
+    {"event reply", ?_assertEqual(
+      {struct, {name_conflict_test_types, delegate}},
+      extern_thrift:function_info(event, reply_type)
+    )},
+    {"event exceptions", ?_assertEqual(
+      {struct, []},
+      extern_thrift:function_info(event, exceptions)
+    )},
+    {"Foo params", ?_assertEqual(
+      {struct, [{1, {struct, {name_conflict_test_types, 'Nested'}}}]},
+      extern_thrift:function_info('Foo', params_type)
+    )},
+    {"Foo reply", ?_assertEqual(
+      {struct, []},
+      extern_thrift:function_info('Foo', reply_type)
+    )},
+    {"Foo exceptions", ?_assertEqual(
+      {struct, [{1, {struct, {name_conflict_test_types, 'Problem_'}}}]},
+      extern_thrift:function_info('Foo', exceptions)
+    )}
+  ].
diff --git a/lib/erl/test/test_client.erl b/lib/erl/test/test_client.erl
deleted file mode 100644
index 59f596d..0000000
--- a/lib/erl/test/test_client.erl
+++ /dev/null
@@ -1,132 +0,0 @@
-%%
-%% Licensed to the Apache Software Foundation (ASF) under one
-%% or more contributor license agreements. See the NOTICE file
-%% distributed with this work for additional information
-%% regarding copyright ownership. The ASF licenses this file
-%% to you under the Apache License, Version 2.0 (the
-%% "License"); you may not use this file except in compliance
-%% with the License. You may obtain a copy of the License at
-%%
-%%   http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing,
-%% software distributed under the License is distributed on an
-%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-%% KIND, either express or implied. See the License for the
-%% specific language governing permissions and limitations
-%% under the License.
-%%
-
--module(test_client).
-
--export([start/0, start/1]).
-
--include("thriftTest_types.hrl").
-
--record(options, {port = 9090,
-                  client_opts = []}).
-
-parse_args(Args) -> parse_args(Args, #options{}).
-parse_args([], Opts) -> Opts;
-parse_args([Head | Rest], Opts) ->
-    NewOpts =
-        case catch list_to_integer(Head) of
-            Port when is_integer(Port) ->
-                Opts#options{port = Port};
-            _Else ->
-                case Head of
-                    "framed" ->
-                        Opts#options{client_opts = [{framed, true} | Opts#options.client_opts]};
-                    "" ->
-                        Opts;
-                    _Else ->
-                        erlang:error({bad_arg, Head})
-                end
-        end,
-    parse_args(Rest, NewOpts).
-
-
-start() -> start([]).
-start(Args) ->
-  #options{port = Port, client_opts = ClientOpts} = parse_args(Args),
-  {ok, Client0} = thrift_client_util:new(
-    "127.0.0.1", Port, thriftTest_thrift, ClientOpts),
-
-  DemoXtruct = #xtruct{
-    string_thing = <<"Zero">>,
-    byte_thing = 1,
-    i32_thing = 9128361,
-    i64_thing = 9223372036854775807},
-
-  DemoNest = #xtruct2{
-    byte_thing = 7,
-    struct_thing = DemoXtruct,
-    % Note that we don't set i32_thing, it will come back as undefined
-    % from the Python server, but 0 from the C++ server, since it is not
-    % optional
-    i32_thing = 2},
-
-  % Is it safe to match these things?
-  DemoDict = dict:from_list([ {Key, Key-10} || Key <- lists:seq(0,10) ]),
-  DemoSet = sets:from_list([ Key || Key <- lists:seq(-3,3) ]),
-
-  %DemoInsane = #insanity{
-  %  userMap = dict:from_list([{?thriftTest_FIVE, 5000}]),
-  %  xtructs = [#xtruct{ string_thing = <<"Truck">>, byte_thing = 8, i32_thing = 8, i64_thing = 8}]},
-
-  {Client01, {ok, ok}} = thrift_client:call(Client0, testVoid, []),
-
-  {Client02, {ok, <<"Test">>}}      = thrift_client:call(Client01, testString, ["Test"]),
-  {Client03, {ok, <<"Test">>}}      = thrift_client:call(Client02, testString, [<<"Test">>]),
-  {Client04, {ok, 63}}              = thrift_client:call(Client03, testByte, [63]),
-  {Client05, {ok, -1}}              = thrift_client:call(Client04, testI32, [-1]),
-  {Client06, {ok, 0}}               = thrift_client:call(Client05, testI32, [0]),
-  {Client07, {ok, -34359738368}}    = thrift_client:call(Client06, testI64, [-34359738368]),
-  {Client08, {ok, -5.2098523}}      = thrift_client:call(Client07, testDouble, [-5.2098523]),
-  {Client09, {ok, DemoXtruct}}      = thrift_client:call(Client08, testStruct, [DemoXtruct]),
-  {Client10, {ok, DemoNest}}        = thrift_client:call(Client09, testNest, [DemoNest]),
-  {Client11, {ok, DemoDict}}        = thrift_client:call(Client10, testMap, [DemoDict]),
-  {Client12, {ok, DemoSet}}         = thrift_client:call(Client11, testSet, [DemoSet]),
-  {Client13, {ok, [-1,2,3]}}        = thrift_client:call(Client12, testList, [[-1,2,3]]),
-  {Client14, {ok, 1}}               = thrift_client:call(Client13, testEnum, [?thriftTest_Numberz_ONE]),
-  {Client15, {ok, 309858235082523}} = thrift_client:call(Client14, testTypedef, [309858235082523]),
-
-  % No python implementation, but works with C++ and Erlang.
-  %{Client16, {ok, InsaneResult}}    = thrift_client:call(Client15, testInsanity, [DemoInsane]),
-  %io:format("~p~n", [InsaneResult]),
-  Client16 = Client15,
-
-  {Client17, {ok, #xtruct{string_thing = <<"Message">>}}} =
-    thrift_client:call(Client16, testMultiException, ["Safe", "Message"]),
-
-  Client18 =
-    try
-      {ClientS1, Result1} = thrift_client:call(Client17, testMultiException, ["Xception", "Message"]),
-      io:format("Unexpected return! ~p~n", [Result1]),
-      ClientS1
-    catch
-      throw:{ClientS2, {exception, ExnS1 = #xception{}}} ->
-        #xception{errorCode = 1001, message = <<"This is an Xception">>} = ExnS1,
-        ClientS2;
-      throw:{ClientS2, {exception, _ExnS1 = #xception2{}}} ->
-        io:format("Wrong exception type!~n", []),
-        ClientS2
-    end,
-
-  Client19 =
-    try
-      {ClientS3, Result2} = thrift_client:call(Client18, testMultiException, ["Xception2", "Message"]),
-      io:format("Unexpected return! ~p~n", [Result2]),
-      ClientS3
-    catch
-      throw:{ClientS4, {exception, _ExnS2 = #xception{}}} ->
-        io:format("Wrong exception type!~n", []),
-        ClientS4;
-      throw:{ClientS4, {exception, ExnS2 = #xception2{}}} ->
-        #xception2{errorCode = 2002,
-                   struct_thing = #xtruct{
-                     string_thing = <<"This is an Xception2">>}} = ExnS2,
-        ClientS4
-    end,
-
-  thrift_client:close(Client19).
diff --git a/lib/erl/test/test_const.erl b/lib/erl/test/test_const.erl
new file mode 100644
index 0000000..627777b
--- /dev/null
+++ b/lib/erl/test/test_const.erl
@@ -0,0 +1,54 @@
+%%
+%% 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.
+%%
+
+-module(test_const).
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+-include("gen-erl/constants_demo_types.hrl").
+
+namespace_test() ->
+  %% Verify that records produced by ConstantsDemo.thrift have the right namespace.
+  io:format(user, "in namespace_test()\n", []),
+  {struct, _} = constants_demo_types:struct_info('consts_thing'),
+  {struct, _} = constants_demo_types:struct_info('consts_Blah'),
+  ok.
+
+const_map_test() ->
+  ?assertEqual(233, constants_demo_constants:gen_map(35532)),
+  ?assertError(function_clause, constants_demo_constants:gen_map(0)),
+
+  ?assertEqual(853, constants_demo_constants:gen_map(43523, default)),
+  ?assertEqual(default, constants_demo_constants:gen_map(10110, default)),
+
+  ?assertEqual(98325, constants_demo_constants:gen_map2("lkjsdf")),
+  ?assertError(function_clause, constants_demo_constants:gen_map2("nonexist")),
+
+  ?assertEqual(233, constants_demo_constants:gen_map2("hello", 321)),
+  ?assertEqual(321, constants_demo_constants:gen_map2("goodbye", 321)).
+
+const_list_test() ->
+  ?assertEqual(23598352, constants_demo_constants:gen_list(2)),
+  ?assertError(function_clause, constants_demo_constants:gen_list(0)),
+
+  ?assertEqual(3253523, constants_demo_constants:gen_list(3, default)),
+  ?assertEqual(default, constants_demo_constants:gen_list(10, default)).
+
+-endif. %% TEST
diff --git a/lib/erl/test/test_disklog.erl b/lib/erl/test/test_disklog.erl
index 17a27b0..dcb6fc1 100644
--- a/lib/erl/test/test_disklog.erl
+++ b/lib/erl/test/test_disklog.erl
@@ -26,12 +26,12 @@
   {ok, TransportFactory} =
     thrift_disk_log_transport:new_transport_factory(
       test_disklog,
-      [{file, "/tmp/test_log"},
+      [{file, "./test_log"},
        {size, {1024*1024, 10}}]),
   {ok, ProtocolFactory} =
     thrift_binary_protocol:new_protocol_factory( TransportFactory, []),
   {ok, Proto} = ProtocolFactory(),
-  {ok, Client0} = thrift_client:new(Proto, thriftTest_thrift),
+  {ok, Client0} = thrift_client:new(Proto, thrift_test_thrift),
 
   io:format("Client started~n"),
 
@@ -47,6 +47,13 @@
 
   {_Client3, ok} = thrift_client:close(Client2),
   io:format("Client closed~n"),
+  
+  lists:foreach(fun(File) -> file:delete(File) end, [
+    "./test_log.1",
+    "./test_log.idx",
+    "./test_log.siz"
+  ]),
+  io:format("Cleaning up test files~n"),
 
   ok.
 
@@ -54,7 +61,7 @@
   {ok, TransportFactory} =
     thrift_disk_log_transport:new_transport_factory(
       test_disklog,
-      [{file, "/tmp/test_b64_log"},
+      [{file, "./test_b64_log"},
        {size, {1024*1024, 10}}]),
   {ok, B64Factory} =
     thrift_base64_transport:new_transport_factory(TransportFactory),
@@ -63,7 +70,7 @@
   {ok, ProtocolFactory} =
     thrift_binary_protocol:new_protocol_factory(BufFactory, []),
   {ok, Proto} = ProtocolFactory(),
-  {ok, Client0} = thrift_client:new(Proto, thriftTest_thrift),
+  {ok, Client0} = thrift_client:new(Proto, thrift_test_thrift),
 
   io:format("Client started~n"),
 
@@ -80,6 +87,13 @@
   {_Client3, ok} = thrift_client:close(Client2),
   io:format("Client closed~n"),
 
+  lists:foreach(fun(File) -> file:delete(File) end, [
+    "./test_b64_log.1",
+    "./test_b64_log.idx",
+    "./test_b64_log.siz"
+  ]),
+  io:format("Cleaning up test files~n"),
+
   ok.
 
 -endif.
diff --git a/lib/erl/test/test_membuffer.erl b/lib/erl/test/test_membuffer.erl
deleted file mode 100644
index 7a01143..0000000
--- a/lib/erl/test/test_membuffer.erl
+++ /dev/null
@@ -1,115 +0,0 @@
-%%
-%% Licensed to the Apache Software Foundation (ASF) under one
-%% or more contributor license agreements. See the NOTICE file
-%% distributed with this work for additional information
-%% regarding copyright ownership. The ASF licenses this file
-%% to you under the Apache License, Version 2.0 (the
-%% "License"); you may not use this file except in compliance
-%% with the License. You may obtain a copy of the License at
-%%
-%%   http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing,
-%% software distributed under the License is distributed on an
-%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-%% KIND, either express or implied. See the License for the
-%% specific language governing permissions and limitations
-%% under the License.
-%%
-
--module(test_membuffer).
-
--ifdef(TEST).
--include_lib("eunit/include/eunit.hrl").
-
--include("thriftTest_types.hrl").
-
-test_data() ->
-  #xtruct {
-    string_thing = <<"foobar">>,
-    byte_thing = 123,
-    i32_thing = 1234567,
-    i64_thing = 12345678900
-  }.
-
-encode_decode_1_test() ->
-  {ok, Transport} = thrift_memory_buffer:new(),
-  {ok, Protocol0} = thrift_binary_protocol:new(Transport),
-  TestData = test_data(),
-  {Protocol1, ok} = thrift_protocol:write(Protocol0,
-    {{struct, element(2, thriftTest_types:struct_info('xtruct'))},
-      TestData}),
-  {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
-    {struct, element(2, thriftTest_types:struct_info('xtruct'))},
-    'xtruct'),
-  Result = TestData.
-
-encode_decode_2_test() ->
-  {ok, Transport} = thrift_memory_buffer:new(),
-  {ok, Protocol0} = thrift_binary_protocol:new(Transport),
-  TestData = test_data(),
-  {Protocol1, ok} = thrift_protocol:write(Protocol0,
-    {{struct, element(2, thriftTest_types:struct_info('xtruct'))},
-      TestData}),
-  {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
-    {struct, element(2, thriftTest_types:struct_info('xtruct3'))},
-    'xtruct3'),
-
-  Result = #xtruct3{string_thing = TestData#xtruct.string_thing,
-    changed = undefined,
-    i32_thing = TestData#xtruct.i32_thing,
-    i64_thing = TestData#xtruct.i64_thing}.
-
-
-encode_decode_3_test() ->
-  {ok, Transport} = thrift_memory_buffer:new(),
-  {ok, Protocol0} = thrift_binary_protocol:new(Transport),
-  TestData = #bools{im_true = true, im_false = false},
-  {Protocol1, ok} = thrift_protocol:write(Protocol0,
-    {{struct, element(2, thriftTest_types:struct_info('bools'))},
-      TestData}),
-  {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
-    {struct, element(2, thriftTest_types:struct_info('bools'))},
-    'bools'),
-
-  true = TestData#bools.im_true  =:= Result#bools.im_true,
-  true = TestData#bools.im_false =:= Result#bools.im_false.
-
-
-encode_decode_4_test() ->
-  {ok, Transport} = thrift_memory_buffer:new(),
-  {ok, Protocol0} = thrift_binary_protocol:new(Transport),
-  TestData = #insanity{xtructs=[]},
-  {Protocol1, ok} = thrift_protocol:write(Protocol0,
-    {{struct, element(2, thriftTest_types:struct_info('insanity'))},
-      TestData}),
-  {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1,
-    {struct, element(2, thriftTest_types:struct_info('insanity'))},
-    'insanity'),
-
-  TestData = Result.
-
-encode_decode_5_test() ->
-  % test writing to a buffer, getting the bytes out, putting them
-  % in a new buffer and reading them
-
-  % here's the writing part
-  {ok, Transport0} = thrift_memory_buffer:new(),
-  {ok, Protocol0} = thrift_binary_protocol:new(Transport0),
-  TestData = test_data(),
-  {Protocol1, ok} = thrift_protocol:write(Protocol0,
-    {{struct, element(2, thriftTest_types:struct_info('xtruct'))},
-      TestData}),
-  % flush now returns the buffer
-  {_Protocol2, Buf} = thrift_protocol:flush_transport (Protocol1),
-
-  % now the reading part
-  {ok, T2} = thrift_memory_buffer:new (Buf),
-  {ok, P2} = thrift_binary_protocol:new(T2),
-  {_, {ok, Result}} = thrift_protocol:read(P2,
-    {struct, element(2, thriftTest_types:struct_info('xtruct'))},
-    'xtruct'),
-
-  Result = TestData.
-
--endif.
diff --git a/lib/erl/test/test_omit.erl b/lib/erl/test/test_omit.erl
new file mode 100644
index 0000000..80841e2
--- /dev/null
+++ b/lib/erl/test/test_omit.erl
@@ -0,0 +1,79 @@
+-module(test_omit).
+
+-include("gen-erl/thrift_omit_with_types.hrl").
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+omit_struct1_test() ->
+  %% In this test, the field that is deleted is a basic type (an i32).
+  A = #test1{one = 1, three = 3},
+  B = #test1{one = 1, two = 2, three = 3},
+  {ok, Transport} = thrift_membuffer_transport:new(),
+  {ok, P0} = thrift_binary_protocol:new(Transport),
+
+  {P1, ok} = thrift_protocol:write(P0, {{struct, {thrift_omit_with_types, element(1, A)}}, A}),
+  {P2, {ok, O0}} = thrift_protocol:read(P1, {struct, {thrift_omit_without_types, element(1, A)}}),
+  ?assertEqual(element(1, A), element(1, O0)),
+  ?assertEqual(element(2, A), element(2, O0)),
+  ?assertEqual(element(4, A), element(3, O0)),
+
+  {P3, ok} = thrift_protocol:write(P2, {{struct, {thrift_omit_with_types, element(1, B)}}, B}),
+  {_P4, {ok, O1}} = thrift_protocol:read(P3, {struct, {thrift_omit_without_types, element(1, A)}}),
+  ?assertEqual(element(1, A), element(1, O1)),
+  ?assertEqual(element(2, A), element(2, O1)),
+  ?assertEqual(element(4, A), element(3, O1)),
+
+  ok.
+
+omit_struct2_test() ->
+  %% In this test, the field that is deleted is a struct.
+  A = #test2{one = 1, two = #test2{one = 10, three = 30}, three = 3},
+  B = #test2{one = 1, two = #test2{one = 10, two = #test2{one = 100}, three = 30}, three = 3},
+
+  {ok, Transport} = thrift_membuffer_transport:new(),
+  {ok, P0} = thrift_binary_protocol:new(Transport),
+
+  {P1, ok} = thrift_protocol:write(P0, {{struct, {thrift_omit_with_types, element(1, A)}}, A}),
+  {P2, {ok, O0}} = thrift_protocol:read(P1, {struct, {thrift_omit_without_types, element(1, A)}}),
+  ?assertEqual(element(1, A), element(1, O0)),
+  ?assertEqual(element(2, A), element(2, O0)),
+  ?assertEqual(element(4, A), element(3, O0)),
+
+  {P3, ok} = thrift_protocol:write(P2, {{struct, {thrift_omit_with_types, element(1, B)}}, B}),
+  {_P4, {ok, O1}} = thrift_protocol:read(P3, {struct, {thrift_omit_without_types, element(1, A)}}),
+  ?assertEqual(element(1, A), element(1, O1)),
+  ?assertEqual(element(2, A), element(2, O1)),
+  ?assertEqual(element(4, A), element(3, O1)),
+
+  ok.
+
+omit_list_test() ->
+  %% In this test, the field that is deleted is a list.
+  A = #test1{one = 1, two = 2, three = 3},
+  B = #test3{one = 1, two = [ A ]},
+
+  {ok, Transport} = thrift_membuffer_transport:new(),
+  {ok, P0} = thrift_binary_protocol:new(Transport),
+
+  {P1, ok} = thrift_protocol:write(P0, {{struct, {thrift_omit_with_types, element(1, B)}}, B}),
+  {_P2, {ok, O0}} = thrift_protocol:read(P1, {struct, {thrift_omit_without_types, element(1, B)}}),
+  ?assertEqual(element(2, B), element(2, O0)),
+
+  ok.
+
+omit_map_test() ->
+  %% In this test, the field that is deleted is a map.
+  A = #test1{one = 1, two = 2, three = 3},
+  B = #test4{one = 1, two = dict:from_list([ {2, A} ])},
+
+  {ok, Transport} = thrift_membuffer_transport:new(),
+  {ok, P0} = thrift_binary_protocol:new(Transport),
+
+  {P1, ok} = thrift_protocol:write(P0, {{struct, {thrift_omit_with_types, element(1, B)}}, B}),
+  {_P2, {ok, O0}} = thrift_protocol:read(P1, {struct, {thrift_omit_without_types, element(1, B)}}),
+  ?assertEqual(element(2, B), element(2, O0)),
+
+  ok.
+
+-endif. %% TEST
diff --git a/lib/erl/test/test_rendered_double_constants.erl b/lib/erl/test/test_rendered_double_constants.erl
new file mode 100644
index 0000000..87fce81
--- /dev/null
+++ b/lib/erl/test/test_rendered_double_constants.erl
@@ -0,0 +1,68 @@
+%%
+%% 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.
+%%
+
+-module(test_rendered_double_constants).
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+-include("gen-erl/double_constants_test_constants.hrl").
+
+-define(EPSILON, 0.0000001).
+
+rendered_double_constants_test() ->
+  ?assert(abs(1.0 - ?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST) =< ?EPSILON),
+  ?assert(abs(-100.0 - ?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST) =< ?EPSILON),
+  ?assert(abs(9223372036854775807.0 - ?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST) =< ?EPSILON),
+  ?assert(abs(-9223372036854775807.0 - ?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST) =< ?EPSILON),
+  ?assert(abs(3.14159265359 - ?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST) =< ?EPSILON),
+  ?assert(abs(1000000.1 - ?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST) =< ?EPSILON),
+  ?assert(abs(-1000000.1 - ?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST) =< ?EPSILON),
+  ?assert(abs(1.7e+308 - ?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST) =< ?EPSILON),
+  ?assert(abs(9223372036854775816.43 - ?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST) =< ?EPSILON),
+  ?assert(abs(-1.7e+308 - ?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST) =< ?EPSILON),
+  ?assert(abs(-9223372036854775816.43 - ?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST) =< ?EPSILON),
+  ?assert(is_float(?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST)),
+  ?assert(is_float(?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST)),
+  ?assert(is_float(?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST)),
+  ?assert(is_float(?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST)),
+  ?assert(is_float(?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST)),
+  ?assert(is_float(?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST)),
+  ?assert(is_float(?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST)),
+  ?assert(is_float(?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST)),
+  ?assert(is_float(?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST)),
+  ?assert(is_float(?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST)),
+  ?assert(is_float(?DOUBLE_CONSTANTS_TEST_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST)).
+
+rendered_double_list_test() ->
+  ?assertEqual(12, length(?DOUBLE_CONSTANTS_TEST_DOUBLE_LIST_TEST)),
+  ?assert(abs(1.0 - lists:nth(1, ?DOUBLE_CONSTANTS_TEST_DOUBLE_LIST_TEST)) =< ?EPSILON),
+  ?assert(abs(-100.0 - lists:nth(2, ?DOUBLE_CONSTANTS_TEST_DOUBLE_LIST_TEST)) =< ?EPSILON),
+  ?assert(abs(100.0 - lists:nth(3, ?DOUBLE_CONSTANTS_TEST_DOUBLE_LIST_TEST)) =< ?EPSILON),
+  ?assert(abs(9223372036854775807.0 - lists:nth(4, ?DOUBLE_CONSTANTS_TEST_DOUBLE_LIST_TEST)) =< ?EPSILON),
+  ?assert(abs(-9223372036854775807.0 - lists:nth(5, ?DOUBLE_CONSTANTS_TEST_DOUBLE_LIST_TEST)) =< ?EPSILON),
+  ?assert(abs(3.14159265359 - lists:nth(6, ?DOUBLE_CONSTANTS_TEST_DOUBLE_LIST_TEST)) =< ?EPSILON),
+  ?assert(abs(1000000.1 - lists:nth(7, ?DOUBLE_CONSTANTS_TEST_DOUBLE_LIST_TEST)) =< ?EPSILON),
+  ?assert(abs(-1000000.1 - lists:nth(8, ?DOUBLE_CONSTANTS_TEST_DOUBLE_LIST_TEST)) =< ?EPSILON),
+  ?assert(abs(1.7e+308 - lists:nth(9, ?DOUBLE_CONSTANTS_TEST_DOUBLE_LIST_TEST)) =< ?EPSILON),
+  ?assert(abs(-1.7e+308 - lists:nth(10, ?DOUBLE_CONSTANTS_TEST_DOUBLE_LIST_TEST)) =< ?EPSILON),
+  ?assert(abs(9223372036854775816.43 - lists:nth(11, ?DOUBLE_CONSTANTS_TEST_DOUBLE_LIST_TEST)) =< ?EPSILON),
+  ?assert(abs(-9223372036854775816.43 - lists:nth(12, ?DOUBLE_CONSTANTS_TEST_DOUBLE_LIST_TEST)) =< ?EPSILON).
+
+-endif. %% TEST
\ No newline at end of file
diff --git a/lib/erl/test/test_server.erl b/lib/erl/test/test_server.erl
deleted file mode 100644
index 63f7b08..0000000
--- a/lib/erl/test/test_server.erl
+++ /dev/null
@@ -1,204 +0,0 @@
-%%
-%% Licensed to the Apache Software Foundation (ASF) under one
-%% or more contributor license agreements. See the NOTICE file
-%% distributed with this work for additional information
-%% regarding copyright ownership. The ASF licenses this file
-%% to you under the Apache License, Version 2.0 (the
-%% "License"); you may not use this file except in compliance
-%% with the License. You may obtain a copy of the License at
-%%
-%%   http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing,
-%% software distributed under the License is distributed on an
-%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-%% KIND, either express or implied. See the License for the
-%% specific language governing permissions and limitations
-%% under the License.
-%%
-
--module(test_server).
-
--export([go/0, go/1, start_link/2, handle_function/2]).
-
--include("thriftTest_types.hrl").
-
--record(options, {port = 9090,
-                  server_opts = []}).
-
-parse_args(Args) -> parse_args(Args, #options{}).
-parse_args([], Opts) -> Opts;
-parse_args([Head | Rest], Opts) ->
-    NewOpts =
-        case catch list_to_integer(Head) of
-            Port when is_integer(Port) ->
-                Opts#options{port = Port};
-            _Else ->
-                case Head of
-                    "framed" ->
-                        Opts#options{server_opts = [{framed, true} | Opts#options.server_opts]};
-                    "" ->
-                        Opts;
-                    _Else ->
-                        erlang:error({bad_arg, Head})
-                end
-        end,
-    parse_args(Rest, NewOpts).
-
-go() -> go([]).
-go(Args) ->
-    #options{port = Port, server_opts = ServerOpts} = parse_args(Args),
-    spawn(fun() -> start_link(Port, ServerOpts), receive after infinity -> ok end end).
-
-start_link(Port, ServerOpts) ->
-    thrift_socket_server:start([{handler, ?MODULE},
-                                {service, thriftTest_thrift},
-                                {port, Port}] ++
-                               ServerOpts).
-
-
-handle_function(testVoid, {}) ->
-    io:format("testVoid~n"),
-    ok;
-
-handle_function(testString, {S}) when is_binary(S) ->
-    io:format("testString: ~p~n", [S]),
-    {reply, S};
-
-handle_function(testByte, {I8}) when is_integer(I8) ->
-    io:format("testByte: ~p~n", [I8]),
-    {reply, I8};
-
-handle_function(testI32, {I32}) when is_integer(I32) ->
-    io:format("testI32: ~p~n", [I32]),
-    {reply, I32};
-
-handle_function(testI64, {I64}) when is_integer(I64) ->
-    io:format("testI64: ~p~n", [I64]),
-    {reply, I64};
-
-handle_function(testDouble, {Double}) when is_float(Double) ->
-    io:format("testDouble: ~p~n", [Double]),
-    {reply, Double};
-
-handle_function(testStruct,
-                {Struct = #xtruct{string_thing = String,
-                                 byte_thing = Byte,
-                                 i32_thing = I32,
-                                 i64_thing = I64}})
-when is_binary(String),
-     is_integer(Byte),
-     is_integer(I32),
-     is_integer(I64) ->
-    io:format("testStruct: ~p~n", [Struct]),
-    {reply, Struct};
-
-handle_function(testNest,
-                {Nest}) when is_record(Nest, xtruct2),
-                             is_record(Nest#xtruct2.struct_thing, xtruct) ->
-    io:format("testNest: ~p~n", [Nest]),
-    {reply, Nest};
-
-handle_function(testMap, {Map}) ->
-    io:format("testMap: ~p~n", [dict:to_list(Map)]),
-    {reply, Map};
-
-handle_function(testSet, {Set}) ->
-    true = sets:is_set(Set),
-    io:format("testSet: ~p~n", [sets:to_list(Set)]),
-    {reply, Set};
-
-handle_function(testList, {List}) when is_list(List) ->
-    io:format("testList: ~p~n", [List]),
-    {reply, List};
-
-handle_function(testEnum, {Enum}) when is_integer(Enum) ->
-    io:format("testEnum: ~p~n", [Enum]),
-    {reply, Enum};
-
-handle_function(testTypedef, {UserID}) when is_integer(UserID) ->
-    io:format("testTypedef: ~p~n", [UserID]),
-    {reply, UserID};
-
-handle_function(testMapMap, {Hello}) ->
-    io:format("testMapMap: ~p~n", [Hello]),
-
-    PosList = [{I, I}   || I <- lists:seq(1, 5)],
-    NegList = [{-I, -I} || I <- lists:seq(1, 5)],
-
-    MapMap = dict:from_list([{4,  dict:from_list(PosList)},
-                             {-4, dict:from_list(NegList)}]),
-    {reply, MapMap};
-
-handle_function(testInsanity, {Insanity}) when is_record(Insanity, insanity) ->
-    Hello = #xtruct{string_thing = <<"Hello2">>,
-                    byte_thing = 2,
-                    i32_thing = 2,
-                    i64_thing = 2},
-
-    Goodbye = #xtruct{string_thing = <<"Goodbye4">>,
-                      byte_thing = 4,
-                      i32_thing = 4,
-                      i64_thing = 4},
-    Crazy = #insanity{
-      userMap = dict:from_list([{?thriftTest_Numberz_EIGHT, 8}]),
-      xtructs = [Goodbye]
-      },
-
-    Looney = #insanity{
-      userMap = dict:from_list([{?thriftTest_Numberz_FIVE, 5}]),
-      xtructs = [Hello]
-      },
-
-    FirstMap = dict:from_list([{?thriftTest_Numberz_TWO, Crazy},
-                               {?thriftTest_Numberz_THREE, Crazy}]),
-
-    SecondMap = dict:from_list([{?thriftTest_Numberz_SIX, Looney}]),
-
-    Insane = dict:from_list([{1, FirstMap},
-                             {2, SecondMap}]),
-
-    io:format("Return = ~p~n", [Insane]),
-
-    {reply, Insane};
-
-handle_function(testMulti, Args = {Arg0, Arg1, Arg2, _Arg3, Arg4, Arg5})
-  when is_integer(Arg0),
-       is_integer(Arg1),
-       is_integer(Arg2),
-       is_integer(Arg4),
-       is_integer(Arg5) ->
-
-    io:format("testMulti(~p)~n", [Args]),
-    {reply, #xtruct{string_thing = <<"Hello2">>,
-                    byte_thing = Arg0,
-                    i32_thing = Arg1,
-                    i64_thing = Arg2}};
-
-handle_function(testException, {String}) when is_binary(String) ->
-    io:format("testException(~p)~n", [String]),
-    case String of
-        <<"Xception">> ->
-            throw(#xception{errorCode = 1001,
-                            message = String});
-        _ ->
-            ok
-    end;
-
-handle_function(testMultiException, {Arg0, Arg1}) ->
-    io:format("testMultiException(~p, ~p)~n", [Arg0, Arg1]),
-    case Arg0 of
-        <<"Xception">> ->
-            throw(#xception{errorCode = 1001,
-                                   message = <<"This is an Xception">>});
-        <<"Xception2">> ->
-            throw(#xception2{errorCode = 2002,
-                                    struct_thing =
-                                    #xtruct{string_thing = <<"This is an Xception2">>}});
-        _ ->
-            {reply, #xtruct{string_thing = Arg1}}
-    end;
-
-handle_function(testOneway, {Seconds}) ->
-    timer:sleep(1000 * Seconds),
-    ok.
diff --git a/lib/erl/test/test_thrift_1151.erl b/lib/erl/test/test_thrift_1151.erl
index 9cee486..f4a910e 100644
--- a/lib/erl/test/test_thrift_1151.erl
+++ b/lib/erl/test/test_thrift_1151.erl
@@ -1,24 +1,34 @@
 -module(test_thrift_1151).
 
--include("thrift1151_types.hrl").
+-include("gen-erl/thrift1151_types.hrl").
 
 -ifdef(TEST).
 -include_lib("eunit/include/eunit.hrl").
 
 unmatched_struct_test() ->
-  S1 = #structC{x=#structB{x=1}},
+  S1 = #'StructC'{x=#'StructB'{x=1}},
   {ok, Transport} = thrift_memory_buffer:new(),
   {ok, Protocol} = thrift_binary_protocol:new(Transport),
-  ?assertException (error, struct_unmatched,
-    thrift_protocol:write(Protocol,
-      {{struct, element(2, thrift1151_types:struct_info('structC'))}, S1})).
+  ?assertException(
+    error,
+    struct_unmatched,
+    thrift_protocol:write(
+      Protocol,
+      {{struct, element(2, thrift1151_types:struct_info('StructC'))}, S1}
+    )
+  ).
 
 badarg_test() ->
-  S2 = #structC{x=#structA{x="1"}},
+  S2 = #'StructC'{x=#'StructA'{x="1"}},
   {ok, Transport} = thrift_memory_buffer:new(),
   {ok, Protocol} = thrift_binary_protocol:new(Transport),
-  ?assertException (error, badarg,
-    thrift_protocol:write(Protocol,
-      {{struct, element(2, thrift1151_types:struct_info('structC'))}, S2})).
+  ?assertException(
+    error,
+    badarg,
+    thrift_protocol:write(
+      Protocol,
+      {{struct, element(2, thrift1151_types:struct_info('StructC'))}, S2}
+    )
+  ).
 
 -endif.
diff --git a/lib/erl/test/test_thrift_3214.erl b/lib/erl/test/test_thrift_3214.erl
new file mode 100644
index 0000000..0f9544b
--- /dev/null
+++ b/lib/erl/test/test_thrift_3214.erl
@@ -0,0 +1,60 @@
+%%
+%% 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.
+%%
+
+-module(test_thrift_3214).
+-compile(export_all).
+
+-include("gen-erl/thrift3214_types.hrl").
+
+-ifdef(TEST).
+-ifndef(otp16_or_less).
+-include_lib("eunit/include/eunit.hrl").
+
+record_generation_test_() ->
+  [
+    {"StringMap record", ?_assertMatch(
+      {'StringMap', _},
+      #'StringMap'{data=#{50 => "foo"}}
+    )},
+    {"StringMap record defaults", ?_assertEqual(
+      {'StringMap', #{1 => "a", 2 => "b"}},
+      #'StringMap'{}
+    )},
+    {"StringMap record dict from list", ?_assertNotEqual(
+      {'StringMap', dict:from_list([{1, "a"}, {2, "b"}])},
+      #'StringMap'{}
+    )},
+    {"StringMap record map from list", ?_assertEqual(
+      {'StringMap', maps:from_list([{1, "a"}, {2, "b"}])},
+      #'StringMap'{}
+    )}
+  ].
+
+struct_info_test_() ->
+  [
+    {"StringMap extended definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {map, i32, string}, 'data', #{1 => "a", 2 => "b"}}
+      ]},
+      thrift3214_types:struct_info_ext('StringMap')
+    )}
+  ].
+
+-endif.
+-endif.
diff --git a/lib/erl/test/test_thrift_buffered_transport.erl b/lib/erl/test/test_thrift_buffered_transport.erl
new file mode 100644
index 0000000..8519e82
--- /dev/null
+++ b/lib/erl/test/test_thrift_buffered_transport.erl
@@ -0,0 +1,359 @@
+%%
+%% 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.
+%%
+
+-module(test_thrift_buffered_transport).
+-include_lib("eunit/include/eunit.hrl").
+
+
+new(Transport) -> thrift_buffered_transport:new(Transport).
+
+new_test_() ->
+  [
+    {"new buffered membuffer", ?_assertMatch(
+      {ok, {t_transport, thrift_buffered_transport, {t_buffered,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, []}},
+        []
+      }}},
+      new({t_transport, thrift_membuffer_transport, {t_membuffer, []}})
+    )}
+  ].
+
+
+read(Frame, Bytes) -> thrift_buffered_transport:read(Frame, Bytes).
+
+read_test_() ->
+  [
+    {"read zero bytes from an empty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        {ok, <<>>}
+      },
+      read(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        0
+      )
+    )},
+    {"read 1 byte from an empty buffered membuffer", ?_assertMatch(
+      {_, {ok, <<>>}},
+      read(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        1
+      )
+    )},
+    {"read zero bytes from nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<"hallo world">>
+          }},
+          []
+        },
+        {ok, <<>>}
+      },
+      read(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<"hallo world">>
+          }},
+          []
+        },
+        0
+      )
+    )},
+    {"read 1 byte from nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"allo world">>}},
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        1
+      )
+    )},
+    {"read 1 byte from nonempty buffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"allo world">>}},
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        1
+      )
+    )},
+    {"read a zillion bytes from nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        {ok, <<"hallo world">>}
+      },
+      read(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        65536
+      )
+    )}
+  ].
+
+
+read_exact(Frame, Bytes) -> thrift_buffered_transport:read_exact(Frame, Bytes).
+
+read_exact_test_() ->
+  [
+    {"read exactly zero bytes from an empty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        {ok, <<>>}
+      },
+      read_exact(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        0
+      )
+    )},
+    {"read exactly 1 byte from an empty buffered membuffer", ?_assertMatch(
+      {_, {error, eof}},
+      read_exact(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        1
+      )
+    )},
+    {"read exactly zero bytes from nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        {ok, <<>>}
+      },
+      read_exact(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        0
+      )
+    )},
+    {"read exactly 1 byte from nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"allo world">>}},
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read_exact(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<"hallo world">>
+          }},
+          []
+        },
+        1
+      )
+    )},
+    {"read exactly 1 byte from nonempty buffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"allo world">>}},
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read_exact(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        1
+      )
+    )},
+    {"read exactly a zillion bytes from nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<"hallo world">>}},
+          []
+        },
+        {error, eof}
+      },
+      read_exact(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<"hallo world">>
+          }},
+          []
+        },
+        65536
+      )
+    )}
+  ].
+
+
+write(Framed, Data) -> thrift_buffered_transport:write(Framed, Data).
+
+write_test_() ->
+  [
+    {"write empty list to empty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [[], []]
+        },
+        ok
+      },
+      write(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        []
+      )
+    )},
+    {"write empty list to nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [["hallo world"], []]
+        },
+        ok
+      },
+      write(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          ["hallo world"]
+        },
+        []
+      )
+    )},
+    {"write empty binary to empty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [[], <<>>]
+        },
+        ok
+      },
+      write(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        <<>>
+      )
+    )},
+    {"write empty binary to nonempty buffered membuffer", ?_assertMatch(
+      {
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [["hallo world"], <<>>]
+        },
+        ok
+      },
+      write(
+        {t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          ["hallo world"]
+        },
+        <<>>
+      )
+    )}
+  ].
+
+
+flush(Transport) -> thrift_buffered_transport:flush(Transport).
+
+flush_test_() ->
+  [
+    {"flush empty buffered membuffer", ?_assertMatch(
+      {{t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          []
+        },
+        ok
+      },
+      flush({t_buffered,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+        []
+      })
+    )},
+    {"flush nonempty buffered membuffer", ?_assertMatch(
+      {{t_buffered,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            [<<>>, <<"hallo world">>]
+          }},
+          []
+        },
+        ok
+      },
+      flush({t_buffered,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+        <<"hallo world">>
+      })
+    )}
+  ].
+
+
+close(Transport) -> thrift_buffered_transport:close(Transport).
+
+close_test_() ->
+  {"close buffered membuffer", ?_assertMatch(
+    {{t_buffered,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+        []
+      },
+      ok
+    },
+    close({t_buffered,
+      {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+      []
+    })
+  )}.
+
diff --git a/lib/erl/test/test_thrift_compact_protocol.erl b/lib/erl/test/test_thrift_compact_protocol.erl
new file mode 100644
index 0000000..5da78c6
--- /dev/null
+++ b/lib/erl/test/test_thrift_compact_protocol.erl
@@ -0,0 +1,219 @@
+%%
+%% 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.
+%%
+
+-module(test_thrift_compact_protocol).
+-include_lib("eunit/include/eunit.hrl").
+-include("thrift_constants.hrl").
+-include("thrift_protocol.hrl").
+
+
+new(Transport) -> thrift_compact_protocol:new(Transport).
+new() ->
+  {ok, Transport} = thrift_membuffer_transport:new(),
+  thrift_compact_protocol:new(Transport).
+
+new_test() ->
+  new(thrift_membuffer_transport:new()).
+
+write(This, Value) -> thrift_protocol:write(This, Value).
+read(This, Type) -> thrift_protocol:read(This, Type).
+
+str(This0, Value0) ->
+  {This1, ok} = write(This0, {string, Value0}),
+  {This2, {ok, Value1}} = read(This1, string),
+  ?assertEqual(Value0, binary_to_list(Value1)),
+  {This2, ok}.
+string_test() ->
+  {ok, This0} = new(),
+  {This1, ok} = str(This0, "aaa"),
+  {This2, ok} = str(This1, ""),
+  {This2, ok}.
+
+round_trip(This0, Type, Value0) ->
+  {This1, ok} = write(This0, {Type, Value0}),
+  {This2, {ok, Value1}} = read(This1, Type),
+  ?assertEqual(Value0, Value1),
+  {This2, ok}.
+
+bool_test() ->
+  {ok, This0} = new(),
+  {This1, ok} = round_trip(This0, bool, true),
+  {This2, ok} = round_trip(This1, bool, false),
+  {This2, ok}.
+
+byte(This0, Value0) -> round_trip(This0, byte, Value0).
+byte_test() ->
+  {ok, This0} = new(),
+  {This1, ok} = byte(This0, 0),
+  {This2, ok} = byte(This1, 42),
+  {This3, ok} = byte(This2, -1),
+  {This4, ok} = byte(This3, -128),
+  {This4, ok}.
+
+i16(This0, Value0) -> round_trip(This0, i16, Value0).
+i16_test() ->
+  {ok, This0} = new(),
+  {This1, ok} = i16(This0, 0),
+  {This2, ok} = i16(This1, 42),
+  {This3, ok} = i16(This2, 30000),
+  {This4, ok} = i16(This3, -1),
+  {This5, ok} = i16(This4, -128),
+  {This6, ok} = i16(This5, -30000),
+  {This6, ok}.
+
+i32(This0, Value0) -> round_trip(This0, i32, Value0).
+i32_test() ->
+  {ok, This0} = new(),
+  {This1, ok} = i32(This0, 0),
+  {This2, ok} = i32(This1, 42),
+  {This3, ok} = i32(This2, 30000),
+  {This4, ok} = i32(This3, 2000000002),
+  {This5, ok} = i32(This4, -1),
+  {This6, ok} = i32(This5, -128),
+  {This7, ok} = i32(This6, -30000),
+  {This8, ok} = i32(This7, -2000000002),
+  {This8, ok}.
+
+i64(This0, Value0) -> round_trip(This0, i64, Value0).
+i64_test() ->
+  {ok, This0} = new(),
+  {This1, ok} = i64(This0, 0),
+  {This2, ok} = i64(This1, 42),
+  {This3, ok} = i64(This2, 30000),
+  {This4, ok} = i64(This3, 2000000002),
+  {This5, ok} = i64(This4, 100000000000000064),
+  {This6, ok} = i64(This5, -1),
+  {This7, ok} = i64(This6, -128),
+  {This8, ok} = i64(This7, -30000),
+  {This9, ok} = i64(This8, -2000000002),
+  {This10, ok} = i64(This9, -100000000000000064),
+  {This10, ok}.
+
+struct_test() ->
+  {ok, P0} = new(),
+  {P1, ok} = write(P0, #protocol_message_begin{ name = "Message1", type = ?tType_I8, seqid = 3}),
+  {P2, ok} = write(P1, #protocol_struct_begin{}),
+  {P3, ok} = write(P2, #protocol_field_begin{ name = "field1", type = ?tType_I8, id = 1}),
+  {P4, ok} = write(P3, {byte, 42}),
+  {P5, ok} = write(P4, field_end),
+  {P6, ok} = write(P5, #protocol_field_begin{ name = "field2", type = ?tType_I8, id = 14}),
+  {P7, ok} = write(P6, {byte, 3}),
+  {P8, ok} = write(P7, field_end),
+  {P9, ok} = write(P8, #protocol_field_begin{ name = "field3", type = ?tType_I8, id = 42}),
+  {P10, ok} = write(P9, {byte, 8}),
+  {P11, ok} = write(P10, field_end),
+  {P12, ok} = write(P11, field_stop),
+  {P13, ok} = write(P12, struct_end),
+  {P14, ok} = write(P13, message_end),
+
+  {P15, #protocol_message_begin{ name = "Message1", type = ?tType_I8, seqid = 3}} = read(P14, message_begin),
+  {P16, ok} = read(P15, struct_begin),
+  {P17, #protocol_field_begin{ type = ?tType_I8, id = 1 }} = read(P16, field_begin),
+  {P18, {ok, 42}} = read(P17, byte),
+  {P19, ok} = read(P18, field_end),
+  {P20, #protocol_field_begin{ type = ?tType_I8, id = 14 }} = read(P19, field_begin),
+  {P21, {ok, 3}} = read(P20, byte),
+  {P22, ok} = read(P21, field_end),
+  {P23, #protocol_field_begin{ type = ?tType_I8, id = 42 }} = read(P22, field_begin),
+  {P24, {ok, 8}} = read(P23, byte),
+  {P25, ok} = read(P24, field_end),
+  {P26, #protocol_field_begin{ type = ?tType_STOP}} = read(P25, field_begin),
+  {P27, ok} = read(P26, struct_end),
+  {P28, ok} = read(P27, message_end),
+  {P28, ok}.
+
+bool_field_test() ->
+  {ok, P0} = new(),
+  {P1, ok} = write(P0, #protocol_message_begin{ name = "Message1", type = ?tType_I8, seqid = 3}),
+  {P2, ok} = write(P1, #protocol_struct_begin{}),
+  {P3, ok} = write(P2, #protocol_field_begin{ name = "field1", type = ?tType_BOOL, id = 1}),
+  {P4, ok} = write(P3, {bool, true}),
+  {P5, ok} = write(P4, field_end),
+  {P6, ok} = write(P5, #protocol_field_begin{ name = "field2", type = ?tType_BOOL, id = 14}),
+  {P7, ok} = write(P6, {bool, false}),
+  {P8, ok} = write(P7, field_end),
+  {P9, ok} = write(P8, #protocol_field_begin{ name = "field3", type = ?tType_BOOL, id = 42}),
+  {P10, ok} = write(P9, {bool, true}),
+  {P11, ok} = write(P10, field_end),
+  {P12, ok} = write(P11, field_stop),
+  {P13, ok} = write(P12, struct_end),
+  {P14, ok} = write(P13, message_end),
+
+  {P15, #protocol_message_begin{ name = "Message1", type = ?tType_I8, seqid = 3}} = read(P14, message_begin),
+  {P16, ok} = read(P15, struct_begin),
+  {P17, #protocol_field_begin{ type = ?tType_BOOL, id = 1 }} = read(P16, field_begin),
+  {P18, {ok, true}} = read(P17, bool),
+  {P19, ok} = read(P18, field_end),
+  {P20, #protocol_field_begin{ type = ?tType_BOOL, id = 14 }} = read(P19, field_begin),
+  {P21, {ok, false}} = read(P20, bool),
+  {P22, ok} = read(P21, field_end),
+  {P23, #protocol_field_begin{ type = ?tType_BOOL, id = 42 }} = read(P22, field_begin),
+  {P24, {ok, true}} = read(P23, bool),
+  {P25, ok} = read(P24, field_end),
+  {P26, #protocol_field_begin{ type = ?tType_STOP}} = read(P25, field_begin),
+  {P27, ok} = read(P26, struct_end),
+  {P28, ok} = read(P27, message_end),
+  {P28, ok}.
+
+nesting_test() ->
+  {ok, P0} = new(),
+  {P1, ok} = write(P0, #protocol_message_begin{ name = "Message1", type = ?tType_I8, seqid = 3}),
+  {P2, ok} = write(P1, #protocol_struct_begin{}),
+  {P3, ok} = write(P2, #protocol_field_begin{ name = "field1", type = ?tType_BOOL, id = 14}),
+  {P4, ok} = write(P3, {bool, true}),
+  {P5, ok} = write(P4, field_end),
+
+  {P6, ok} = write(P5, #protocol_field_begin{ name = "field2", type = ?tType_STRUCT, id = 28}),
+  {P7, ok} = write(P6, #protocol_struct_begin{}),
+  {P8, ok} = write(P7, #protocol_field_begin{ name = "field2_1", type = ?tType_BOOL, id = 30000}),
+  {P9, ok} = write(P8, {bool, false}),
+  {P10, ok} = write(P9, field_end),
+  {P11, ok} = write(P10, field_stop),
+  {P12, ok} = write(P11, struct_end),
+  {P13, ok} = write(P12, field_end),
+
+  {P14, ok} = write(P13, #protocol_field_begin{ name = "field3", type = ?tType_BOOL, id = 42}),
+  {P15, ok} = write(P14, {bool, true}),
+  {P16, ok} = write(P15, field_end),
+  {P17, ok} = write(P16, field_stop),
+  {P18, ok} = write(P17, struct_end),
+  {P19, ok} = write(P18, message_end),
+
+  {P20, #protocol_message_begin{ name = "Message1", type = ?tType_I8, seqid = 3}} = read(P19, message_begin),
+  {P21, ok} = read(P20, struct_begin),
+  {P22, #protocol_field_begin{ type = ?tType_BOOL, id = 14 }} = read(P21, field_begin),
+  {P23, {ok, true}} = read(P22, bool),
+  {P24, ok} = read(P23, field_end),
+
+  {P25, #protocol_field_begin{ type = ?tType_STRUCT, id = 28 }} = read(P24, field_begin),
+  {P26, ok} = read(P25, struct_begin),
+  {P27, #protocol_field_begin{ type = ?tType_BOOL, id = 30000 }} = read(P26, field_begin),
+  {P28, {ok, false}} = read(P27, bool),
+  {P29, ok} = read(P28, field_end),
+  {P30, #protocol_field_begin{ type = ?tType_STOP }} = read(P29, field_begin),
+  {P31, ok} = read(P30, struct_end),
+  {P32, ok} = read(P31, field_end),
+
+  {P33, #protocol_field_begin{ type = ?tType_BOOL, id = 42 }} = read(P32, field_begin),
+  {P34, {ok, true}} = read(P33, bool),
+  {P35, ok} = read(P34, field_end),
+  {P36, #protocol_field_begin{ type = ?tType_STOP }} = read(P35, field_begin),
+  {P37, ok} = read(P36, struct_end),
+  {P38, ok} = read(P37, message_end),
+  {P38, ok}.
diff --git a/lib/erl/test/test_thrift_file_transport.erl b/lib/erl/test/test_thrift_file_transport.erl
new file mode 100644
index 0000000..3e5c1d1
--- /dev/null
+++ b/lib/erl/test/test_thrift_file_transport.erl
@@ -0,0 +1,213 @@
+%%
+%% 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.
+%%
+
+-module(test_thrift_file_transport).
+-include_lib("eunit/include/eunit.hrl").
+
+
+new(File) -> thrift_file_transport:new(File).
+new(File, Opts) -> thrift_file_transport:new(File, Opts).
+
+new_test_() ->
+  [
+    {"new file", ?_assertMatch(
+      {ok, {_, thrift_file_transport, {t_file, a_fake_file, true, write}}},
+      new(a_fake_file)
+    )},
+    {"new file in read mode", ?_assertMatch(
+      {ok, {_, thrift_file_transport, {t_file, a_fake_file, true, read}}},
+      new(a_fake_file, [{mode, read}])
+    )},
+    {"new file in write mode", ?_assertMatch(
+      {ok, {_, thrift_file_transport, {t_file, a_fake_file, true, write}}},
+      new(a_fake_file, [{mode, write}])
+    )},
+    {"new file in should_close true mode", ?_assertMatch(
+      {ok, {_, thrift_file_transport, {t_file, a_fake_file, true, write}}},
+      new(a_fake_file, [{should_close, true}])
+    )},
+    {"new file in should_close false mode", ?_assertMatch(
+      {ok, {_, thrift_file_transport, {t_file, a_fake_file, false, write}}},
+      new(a_fake_file, [{should_close, false}])
+    )}
+  ].
+
+
+read(File, Bytes) -> thrift_file_transport:read(File, Bytes).
+
+read_test_() ->
+  {setup,
+    fun() ->
+      meck:new(file, [unstick, passthrough]),
+      meck:expect(file, read, fun(Bin, N) ->
+        {Result, _} = split_binary(Bin, min(iolist_size(Bin), N)),
+        {ok, Result}
+      end)
+    end,
+    fun(_) -> meck:unload(file) end,
+    [
+      {"read zero bytes from empty file", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read({t_file, <<>>, true, read}, 0)
+      )},
+      {"read 1 byte from empty file", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read({t_file, <<>>, true, read}, 1)
+      )},
+      {"read zero bytes from nonempty file", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read({t_file, <<"hallo world">>, true, read}, 0)
+      )},
+      {"read 1 byte from nonempty file", ?_assertMatch(
+        {_, {ok, <<"h">>}},
+        read({t_file, <<"hallo world">>, true, read}, 1)
+      )},
+      {"read a zillion bytes from nonempty file", ?_assertMatch(
+        {_, {ok, <<"hallo world">>}},
+        read({t_file, <<"hallo world">>, true, read}, 65536)
+      )},
+      {"read 0 byte from file in write mode", ?_assertMatch(
+        {_, {error, write_mode}},
+        read({t_file, <<>>, true, write}, 0)
+      )},
+      {"read 1 byte from file in write mode", ?_assertMatch(
+        {_, {error, write_mode}},
+        read({t_file, <<>>, true, write}, 1)
+      )}
+    ]
+  }.
+
+
+read_exact(File, Bytes) -> thrift_file_transport:read_exact(File, Bytes).
+
+read_exact_test_() ->
+  {setup,
+    fun() ->
+      meck:new(file, [unstick, passthrough]),
+      meck:expect(file, read, fun(Bin, N) ->
+        {Result, _} = split_binary(Bin, min(iolist_size(Bin), N)),
+        {ok, Result}
+      end)
+    end,
+    fun(_) -> meck:unload(file) end,
+    [
+      {"read exactly zero bytes from empty file", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read_exact({t_file, <<>>, true, read}, 0)
+      )},
+      {"read exactly 1 byte from empty file", ?_assertMatch(
+        {_, {error, eof}},
+        read_exact({t_file, <<>>, true, read}, 1)
+      )},
+      {"read exactly zero bytes from nonempty file", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read_exact({t_file, <<"hallo world">>, true, read}, 0)
+      )},
+      {"read exactly 1 byte from nonempty file", ?_assertMatch(
+        {_, {ok, <<"h">>}},
+        read_exact({t_file, <<"hallo world">>, true, read}, 1)
+      )},
+      {"read exactly a zillion bytes from nonempty file", ?_assertMatch(
+        {_, {error, eof}},
+        read_exact({t_file, <<"hallo world">>, true, read}, 65536)
+      )},
+      {"read exactly 0 byte from file in write mode", ?_assertMatch(
+        {_, {error, write_mode}},
+        read_exact({t_file, <<>>, true, write}, 0)
+      )},
+      {"read exactly 1 byte from file in write mode", ?_assertMatch(
+        {_, {error, write_mode}},
+        read_exact({t_file, <<>>, true, write}, 1)
+      )}
+    ]
+  }.
+
+
+write(File, Data) -> thrift_file_transport:write(File, Data).
+
+write_test_() ->
+  {setup,
+    fun() ->
+      meck:new(file, [unstick, passthrough]),
+      meck:expect(file, write, fun(_, _) -> ok end)
+    end,
+    fun(_) -> meck:unload(file) end,
+    [
+      {"write empty list to file", ?_assertMatch(
+        {{t_file, a_fake_file, true, write}, ok},
+        write({t_file, a_fake_file, true, write}, [])
+      )},
+      {"write empty binary to file", ?_assertMatch(
+        {{t_file, a_fake_file, true, write}, ok},
+        write({t_file, a_fake_file, true, write}, <<>>)
+      )},
+      {"write a list to file", ?_assertMatch(
+        {{t_file, a_fake_file, true, write}, ok},
+        write({t_file, a_fake_file, true, write}, "hallo world")
+      )},
+      {"write a binary to file", ?_assertMatch(
+        {{t_file, a_fake_file, true, write}, ok},
+        write({t_file, a_fake_file, true, write}, <<"hallo world">>)
+      )},
+      {"write a binary to file in read mode", ?_assertMatch(
+        {_, {error, read_mode}},
+        write({t_file, a_fake_file, true, read}, <<"hallo world">>)
+      )},
+      {"write a list to file in read mode", ?_assertMatch(
+        {_, {error, read_mode}},
+        write({t_file, a_fake_file, true, read}, "hallo world")
+      )}
+    ]
+  }.
+
+
+flush(Transport) -> thrift_file_transport:flush(Transport).
+
+flush_test_() ->
+  {setup,
+    fun() ->
+      meck:new(file, [unstick, passthrough]),
+      meck:expect(file, sync, fun(_File) -> ok end)
+    end,
+    fun(_) -> meck:unload(file) end,
+    [
+      {"flush file", ?_assertMatch(
+        {{t_file, a_fake_file, true, write}, ok},
+        flush({t_file, a_fake_file, true, write})
+      )}
+    ]
+  }.
+
+
+close(Transport) -> thrift_file_transport:close(Transport).
+
+close_test_() ->
+  {setup,
+    fun() ->
+      meck:new(file, [unstick, passthrough]),
+      meck:expect(file, close, fun(_) -> ok end)
+    end,
+    fun(_) -> meck:unload(file) end,
+    [
+      {"close file", ?_assertMatch(
+        {{t_file, a_fake_file, true, write}, ok},
+        close({t_file, a_fake_file, true, write})
+      )}
+    ]
+  }.
\ No newline at end of file
diff --git a/lib/erl/test/test_thrift_framed_transport.erl b/lib/erl/test/test_thrift_framed_transport.erl
new file mode 100644
index 0000000..8a538a5
--- /dev/null
+++ b/lib/erl/test/test_thrift_framed_transport.erl
@@ -0,0 +1,404 @@
+%%
+%% 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.
+%%
+
+-module(test_thrift_framed_transport).
+-include_lib("eunit/include/eunit.hrl").
+
+
+new(Transport) -> thrift_framed_transport:new(Transport).
+
+new_test_() ->
+  [
+    {"new framed membuffer", ?_assertMatch(
+      {ok, {t_transport, thrift_framed_transport, {t_framed,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, []}},
+        [],
+        []
+      }}},
+      new({t_transport, thrift_membuffer_transport, {t_membuffer, []}})
+    )}
+  ].
+
+
+read(Frame, Bytes) -> thrift_framed_transport:read(Frame, Bytes).
+
+read_test_() ->
+  [
+    {"read zero bytes from an empty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        {ok, <<>>}
+      },
+      read(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        0
+      )
+    )},
+    {"read 1 byte from an empty framed membuffer", ?_assertMatch(
+      {_, {error, eof}},
+      read(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        1
+      )
+    )},
+    {"read zero bytes from nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        {ok, <<>>}
+      },
+      read(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        0
+      )
+    )},
+    {"read 1 byte from nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<"allo world">>,
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        1
+      )
+    )},
+    {"read 1 byte from nonempty buffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<"allo world">>,
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<"hallo world">>,
+          []
+        },
+        1
+      )
+    )},
+    {"read a zillion bytes from nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<>>,
+          []
+        },
+        {ok, <<"hallo world">>}
+      },
+      read(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        65536
+      )
+    )}
+  ].
+
+
+read_exact(Frame, Bytes) -> thrift_framed_transport:read_exact(Frame, Bytes).
+
+read_exact_test_() ->
+  [
+    {"read exactly zero bytes from an empty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<>>,
+          []
+        },
+        {ok, <<>>}
+      },
+      read_exact(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        0
+      )
+    )},
+    {"read exactly 1 byte from an empty framed membuffer", ?_assertMatch(
+      {_, {error, eof}},
+      read_exact(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        1
+      )
+    )},
+    {"read exactly zero bytes from nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          <<>>,
+          []
+        },
+        {ok, <<>>}
+      },
+      read_exact(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        0
+      )
+    )},
+    {"read exactly 1 byte from nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<"allo world">>,
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read_exact(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        1
+      )
+    )},
+    {"read exactly 1 byte from nonempty buffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<"allo world">>,
+          []
+        },
+        {ok, <<"h">>}
+      },
+      read_exact(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          <<"hallo world">>,
+          []
+        },
+        1
+      )
+    )},
+    {"read exactly a zillion bytes from nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [[],<<"hallo world">>],
+          []
+        },
+        {error, eof}
+      },
+      read_exact(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            <<0, 0, 0, 11, "hallo world">>
+          }},
+          [],
+          []
+        },
+        65536
+      )
+    )}
+  ].
+
+
+write(Framed, Data) -> thrift_framed_transport:write(Framed, Data).
+
+write_test_() ->
+  [
+    {"write empty list to empty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          [[], []]
+        },
+        ok
+      },
+      write(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        []
+      )
+    )},
+    {"write empty list to nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          [["hallo world"], []]
+        },
+        ok
+      },
+      write(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          ["hallo world"]
+        },
+        []
+      )
+    )},
+    {"write empty binary to empty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          [[], <<>>]
+        },
+        ok
+      },
+      write(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        <<>>
+      )
+    )},
+    {"write empty binary to nonempty framed membuffer", ?_assertMatch(
+      {
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          [["hallo world"], <<>>]
+        },
+        ok
+      },
+      write(
+        {t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          ["hallo world"]
+        },
+        <<>>
+      )
+    )}
+  ].
+
+
+flush(Transport) -> thrift_framed_transport:flush(Transport).
+
+flush_test_() ->
+  [
+    {"flush empty framed membuffer", ?_assertMatch(
+      {{t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+          [],
+          []
+        },
+        ok
+      },
+      flush({t_framed,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+        [],
+        []
+      })
+    )},
+    {"flush nonempty framed membuffer", ?_assertMatch(
+      {{t_framed,
+          {t_transport, thrift_membuffer_transport, {t_membuffer,
+            [<<>>, [<<0, 0, 0, 11>>, <<"hallo world">>]]
+          }},
+          [],
+          []
+        },
+        ok
+      },
+      flush({t_framed,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+        [],
+        <<"hallo world">>
+      })
+    )}
+  ].
+
+
+close(Transport) -> thrift_framed_transport:close(Transport).
+
+close_test_() ->
+  {"close framed membuffer", ?_assertMatch(
+    {{t_framed,
+        {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+        [],
+        []
+      },
+      ok
+    },
+    close({t_framed,
+      {t_transport, thrift_membuffer_transport, {t_membuffer, <<>>}},
+      [],
+      []
+    })
+  )}.
+
diff --git a/lib/erl/test/test_thrift_membuffer_transport.erl b/lib/erl/test/test_thrift_membuffer_transport.erl
new file mode 100644
index 0000000..9689c79
--- /dev/null
+++ b/lib/erl/test/test_thrift_membuffer_transport.erl
@@ -0,0 +1,167 @@
+%%
+%% Licensed to the Apache Software Foundation (ASF) under one
+%% or more contributor license agreements. See the NOTICE file
+%% distributed with this work for additional information
+%% regarding copyright ownership. The ASF licenses this file
+%% to you under the Apache License, Version 2.0 (the
+%% "License"); you may not use this file except in compliance
+%% with the License. You may obtain a copy of the License at
+%%
+%%   http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing,
+%% software distributed under the License is distributed on an
+%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+%% KIND, either express or implied. See the License for the
+%% specific language governing permissions and limitations
+%% under the License.
+%%
+
+-module(test_thrift_membuffer_transport).
+-include_lib("eunit/include/eunit.hrl").
+
+
+new() -> thrift_membuffer_transport:new().
+new(Data) -> thrift_membuffer_transport:new(Data).
+
+new_test_() ->
+  [
+    {"new empty membuffer", ?_assertMatch(
+      {ok, {_, _, {t_membuffer, []}}},
+      new()
+    )},
+    {"new membuffer with <<>>", ?_assertMatch(
+      {ok, {_, _, {t_membuffer, [<<>>]}}},
+      new(<<>>)
+    )},
+    {"new membuffer with []", ?_assertMatch(
+      {ok, {_, _, {t_membuffer, []}}},
+      new([])
+    )},
+    {"new membuffer with <<\"hallo world\">>", ?_assertMatch(
+      {ok, {_, _, {t_membuffer, [<<"hallo world">>]}}},
+      new(<<"hallo world">>)
+    )},
+    {"new membuffer with \"hallo world\"", ?_assertMatch(
+      {ok, {_, _, {t_membuffer, "hallo world"}}},
+      new("hallo world")
+    )}
+  ].
+
+
+read(Membuffer, Bytes) -> thrift_membuffer_transport:read(Membuffer, Bytes).
+
+read_test_() ->
+  [
+    {"read zero bytes from an empty membuffer", ?_assertMatch(
+      {_, {ok, <<>>}},
+      read({t_membuffer, []}, 0)
+    )},
+    {"read 1 byte from an empty membuffer", ?_assertMatch(
+      {_, {ok, <<>>}},
+      read({t_membuffer, []}, 1)
+    )},
+    {"read zero bytes from nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, <<"hallo world">>}, {ok, <<>>}},
+      read({t_membuffer, [["hallo", " "], "world"]}, 0)
+    )},
+    {"read 1 byte from nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, <<"allo world">>}, {ok, <<"h">>}},
+      read({t_membuffer, [["hallo", " "], "world"]}, 1)
+    )},
+    {"read a zillion bytes from nonempty buffer", ?_assertMatch(
+      {{t_membuffer, <<>>}, {ok, <<"hallo world">>}},
+      read({t_membuffer, [["hallo", " "], "world"]}, 65536)
+    )}
+  ].
+
+
+read_exact(Membuffer, Bytes) ->
+  thrift_membuffer_transport:read_exact(Membuffer, Bytes).
+
+read_exact_test_() ->
+  [
+    {"read exactly zero bytes from an empty membuffer", ?_assertMatch(
+      {_, {ok, <<>>}},
+      read_exact({t_membuffer, []}, 0)
+    )},
+    {"read exactly 1 byte from an empty membuffer", ?_assertMatch(
+      {_, {error, eof}},
+      read_exact({t_membuffer, []}, 1)
+    )},
+    {"read exactly zero bytes from nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, <<"hallo world">>}, {ok, <<>>}},
+      read_exact({t_membuffer, [["hallo", " "], "world"]}, 0)
+    )},
+    {"read exactly 1 byte from nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, <<"allo world">>}, {ok, <<"h">>}},
+      read_exact({t_membuffer, [["hallo", " "], "world"]}, 1)
+    )},
+    {"read exactly a zillion bytes from nonempty buffer", ?_assertMatch(
+      {{t_membuffer, [["hallo", " "], "world"]}, {error, eof}},
+      read_exact({t_membuffer, [["hallo", " "], "world"]}, 65536)
+    )}
+  ].
+
+
+write(Membuffer, Data) -> thrift_membuffer_transport:write(Membuffer, Data).
+
+write_test_() ->
+  [
+    {"write empty list to empty membuffer", ?_assertMatch(
+      {{t_membuffer, [[], []]}, ok},
+      write({t_membuffer, []}, [])
+    )},
+    {"write empty list to nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, ["hallo world", []]}, ok},
+      write({t_membuffer, "hallo world"}, [])
+    )},
+    {"write empty binary to empty membuffer", ?_assertMatch(
+      {{t_membuffer, [[], <<>>]}, ok},
+      write({t_membuffer, []}, <<>>)
+    )},
+    {"write empty binary to nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, ["hallo world", <<>>]}, ok},
+      write({t_membuffer, "hallo world"}, <<>>)
+    )},
+    {"write a list to empty membuffer", ?_assertMatch(
+      {{t_membuffer, [[], "hallo world"]}, ok},
+      write({t_membuffer, []}, "hallo world")
+    )},
+    {"write a list to nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, [["hallo", " "], "world"]}, ok},
+      write({t_membuffer, ["hallo", " "]}, "world")
+    )},
+    {"write a binary to empty membuffer", ?_assertMatch(
+      {{t_membuffer, [[], <<"hallo world">>]}, ok},
+      write({t_membuffer, []}, <<"hallo world">>)
+    )},
+    {"write a binary to nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, [["hallo", " "], <<"world">>]}, ok},
+      write({t_membuffer, ["hallo", " "]}, <<"world">>)
+    )}
+  ].
+
+
+flush(Transport) -> thrift_membuffer_transport:flush(Transport).
+
+flush_test_() ->
+  [
+    {"flush empty membuffer", ?_assertMatch(
+      {{t_membuffer, []}, ok},
+      flush({t_membuffer, []})
+    )},
+    {"flush nonempty membuffer", ?_assertMatch(
+      {{t_membuffer, [<<"hallo world">>]}, ok},
+      flush({t_membuffer, [<<"hallo world">>]})
+    )}
+  ].
+
+
+close(Transport) -> thrift_membuffer_transport:close(Transport).
+
+close_test_() ->
+  {"close membuffer", ?_assertMatch(
+    {{t_membuffer, _}, ok},
+    close({t_membuffer, []})
+  )}.
\ No newline at end of file
diff --git a/lib/erl/test/test_thrift_socket_transport.erl b/lib/erl/test/test_thrift_socket_transport.erl
new file mode 100644
index 0000000..5bc0f24
--- /dev/null
+++ b/lib/erl/test/test_thrift_socket_transport.erl
@@ -0,0 +1,199 @@
+%%
+%% 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.
+%%
+
+-module(test_thrift_socket_transport).
+-include_lib("eunit/include/eunit.hrl").
+
+
+new(Socket) -> thrift_socket_transport:new(Socket).
+new(Socket, Opts) -> thrift_socket_transport:new(Socket, Opts).
+
+new_test_() ->
+  [
+    {"new socket", ?_assertMatch(
+      {ok, {_, thrift_socket_transport, {t_socket, a_fake_socket, 60000, []}}},
+      new(a_fake_socket)
+    )},
+    {"new socket with no options", ?_assertMatch(
+      {ok, {_, thrift_socket_transport, {t_socket, a_fake_socket, 60000, []}}},
+      new(a_fake_socket, [])
+    )},
+    {"new socket with integer timeout", ?_assertMatch(
+      {ok, {_, thrift_socket_transport, {t_socket, a_fake_socket, 5000, []}}},
+      new(a_fake_socket, [{recv_timeout, 5000}])
+    )},
+    {"new socket with infinity timeout", ?_assertMatch(
+      {ok, {_, thrift_socket_transport, {t_socket, a_fake_socket, infinity, []}}},
+      new(a_fake_socket, [{recv_timeout, infinity}])
+    )}
+  ].
+
+
+read(Socket, Bytes) -> thrift_socket_transport:read(Socket, Bytes).
+
+read_test_() ->
+  {setup,
+    fun() ->
+      meck:new(gen_tcp, [unstick, passthrough]),
+      meck:expect(gen_tcp, recv, fun(Bin, 0, _) -> {ok, Bin} end)
+    end,
+    fun(_) -> meck:unload(gen_tcp) end,
+    [
+      {"read zero bytes from empty socket", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read({t_socket, <<>>, 60000, []}, 0)
+      )},
+      {"read 1 byte from empty socket", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read({t_socket, <<>>, 60000, []}, 1)
+      )},
+      {"read zero bytes from nonempty socket", ?_assertMatch(
+        {{t_socket, _, _, _}, {ok, <<>>}},
+        read({t_socket, <<"hallo world">>, 60000, []}, 0)
+      )},
+      {"read 1 byte from nonempty socket", ?_assertMatch(
+        {{t_socket, _, _, <<"allo world">>}, {ok, <<"h">>}},
+        read({t_socket, <<"hallo world">>, 60000, []}, 1)
+      )},
+      {"read a zillion bytes from nonempty socket", ?_assertMatch(
+        {{t_socket, _, _, <<>>}, {ok, <<"hallo world">>}},
+        read({t_socket, <<"hallo world">>, 60000, []}, 65536)
+      )},
+      {"read 1 byte from previously buffered socket", ?_assertMatch(
+        {{t_socket, _, _, <<"allo">>}, {ok, <<"h">>}},
+        read({t_socket, <<" world">>, 60000, <<"hallo">>}, 1)
+      )},
+      {"read 6 byte from previously buffered socket", ?_assertMatch(
+        {{t_socket, _, _, <<"world">>}, {ok, <<"hallo ">>}},
+        read({t_socket, <<" world">>, 60000, <<"hallo">>}, 6)
+      )},
+      {"read a zillion bytes from previously buffered socket", ?_assertMatch(
+        {{t_socket, _, _, <<>>}, {ok, <<"hallo world">>}},
+        read({t_socket, <<" world">>, 60000, <<"hallo">>}, 65536)
+      )}
+    ]
+  }.
+
+
+read_exact(Socket, Bytes) -> thrift_socket_transport:read_exact(Socket, Bytes).
+
+read_exact_test_() ->
+  {setup,
+    fun() ->
+      meck:new(gen_tcp, [unstick, passthrough]),
+      meck:expect(gen_tcp, recv, fun(Bin, N, _) ->
+        case N of
+          0 -> {ok, Bin};
+          1 -> {ok, <<"h">>};
+          N when N > 2 -> {error, timeout}
+        end
+      end),
+      meck:expect(gen_tcp, close, fun(_) -> ok end)
+    end,
+    fun(_) -> meck:unload(gen_tcp) end,
+    [
+      {"read_exact zero bytes from empty socket", ?_assertMatch(
+        {_, {ok, <<>>}},
+        read_exact({t_socket, <<>>, 60000, []}, 0)
+      )},
+      {"read_exact zero bytes from nonempty socket", ?_assertMatch(
+        {{t_socket, _, _, _}, {ok, <<>>}},
+        read_exact({t_socket, <<"hallo world">>, 60000, []}, 0)
+      )},
+      {"read_exact 1 byte from nonempty socket", ?_assertMatch(
+        {{t_socket, _, _, []}, {ok, <<"h">>}},
+        read_exact({t_socket, <<"hallo world">>, 60000, []}, 1)
+      )},
+      {"read_exact a zillion bytes from nonempty socket", ?_assertMatch(
+        {{t_socket, _, _, []}, {error, timeout}},
+        read_exact({t_socket, <<"hallo world">>, 60000, []}, 65536)
+      )},
+      {"read_exact 1 byte from previously buffered socket", ?_assertMatch(
+        {{t_socket, _, _, <<"allo">>}, {ok, <<"h">>}},
+        read_exact({t_socket, <<" world">>, 60000, <<"hallo">>}, 1)
+      )},
+      {"read_exact 6 byte from previously buffered socket", ?_assertMatch(
+        {{t_socket, _, _, []}, {ok, <<"more h">>}},
+        read_exact({t_socket, <<"hallo">>, 60000, <<"more ">>}, 6)
+      )},
+      {"read_exact a zillion bytes from previously buffered socket", ?_assertMatch(
+        {{t_socket, _, _, <<"hallo">>}, {error, timeout}},
+        read_exact({t_socket, <<" world">>, 60000, <<"hallo">>}, 65536)
+      )}
+    ]
+  }.
+
+
+write(Socket, Data) -> thrift_socket_transport:write(Socket, Data).
+
+write_test_() ->
+  {setup,
+    fun() ->
+      meck:new(gen_tcp, [unstick, passthrough]),
+      meck:expect(gen_tcp, send, fun(_, _) -> ok end)
+    end,
+    fun(_) -> meck:unload(gen_tcp) end,
+    [
+      {"write empty list to socket", ?_assertMatch(
+        {{t_socket, a_fake_socket, 60000, []}, ok},
+        write({t_socket, a_fake_socket, 60000, []}, [])
+      )},
+      {"write empty binary to socket", ?_assertMatch(
+        {{t_socket, a_fake_socket, 60000, []}, ok},
+        write({t_socket, a_fake_socket, 60000, []}, <<>>)
+      )},
+      {"write a list to socket", ?_assertMatch(
+        {{t_socket, a_fake_socket, 60000, []}, ok},
+        write({t_socket, a_fake_socket, 60000, []}, "hallo world")
+      )},
+      {"write a binary to socket", ?_assertMatch(
+        {{t_socket, a_fake_socket, 60000, []}, ok},
+        write({t_socket, a_fake_socket, 60000, []}, <<"hallo world">>)
+      )}
+    ]
+  }.
+
+
+flush(Transport) -> thrift_socket_transport:flush(Transport).
+
+flush_test_() ->
+  [
+    {"flush socket", ?_assertMatch(
+      {{t_socket, a_fake_socket, 60000, []}, ok},
+      flush({t_socket, a_fake_socket, 60000, []})
+    )}
+  ].
+
+
+close(Transport) -> thrift_socket_transport:close(Transport).
+
+close_test_() ->
+  {setup,
+    fun() ->
+      meck:new(gen_tcp, [unstick, passthrough]),
+      meck:expect(gen_tcp, close, fun(_) -> ok end)
+    end,
+    fun(_) -> meck:unload(gen_tcp) end,
+    [
+      {"close membuffer", ?_assertMatch(
+        {{t_socket, a_fake_socket, 60000, []}, ok},
+        close({t_socket, a_fake_socket, 60000, []})
+      )}
+    ]
+  }.
\ No newline at end of file
diff --git a/lib/erl/test/thrift_socket_server_test.erl b/lib/erl/test/thrift_socket_server_test.erl
new file mode 100644
index 0000000..0818b84
--- /dev/null
+++ b/lib/erl/test/thrift_socket_server_test.erl
@@ -0,0 +1,49 @@
+-module (thrift_socket_server_test).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-include ("thrift_constants.hrl").
+
+parse_handler_options_test_() ->
+    CorrectServiceHandlerOptionList = [{?MULTIPLEXED_ERROR_HANDLER_KEY, ?MODULE}, {"Service1", ?MODULE}, {"Service2", ?MODULE}],
+    MissingErrorHandlerOptionList   = [{"Service1", ?MODULE}, {"Service2", ?MODULE}],
+    WrongService2HandlerOptionList  = [{?MULTIPLEXED_ERROR_HANDLER_KEY, ?MODULE}, {"Service1", ?MODULE}, {"Service2", "Module"}],
+    WrongServiceKeyOptionList       = [{?MULTIPLEXED_ERROR_HANDLER_KEY, ?MODULE}, {'service1', ?MODULE}, {"Service2", ?MODULE}],
+    CorrectHandlerTestFunction = fun() ->
+        ?assertMatch({thrift_socket_server,_,_,_,_,_,_,_,_,_,_,_,_,_}, thrift_socket_server:parse_options([{handler, CorrectServiceHandlerOptionList}])),
+        {thrift_socket_server,_,_, HandlerList,_,_,_,_,_,_,_,_,_,_} = thrift_socket_server:parse_options([{handler, CorrectServiceHandlerOptionList}]),
+        lists:foreach(fun
+            ({ServiceName, HandlerModule}) ->
+                ?assertMatch({ok, HandlerModule} when is_atom(HandlerModule), thrift_multiplexed_map_wrapper:find(ServiceName, HandlerList))
+        end, CorrectServiceHandlerOptionList)
+    end,
+    [
+     {"Bad argument for the handler option", ?_assertThrow(_, thrift_socket_server:parse_options([{handler, []}]))},
+     {"Try to parse the handler option twice", ?_assertThrow(_, thrift_socket_server:parse_options([{handler, ?MODULE}, {handler, CorrectServiceHandlerOptionList}]))},
+     {"Parse the handler option as a non multiplexed service handler", ?_assertMatch({thrift_socket_server,_,_,?MODULE,_,_,_,_,_,_,_,_,_,_}, thrift_socket_server:parse_options([{handler, ?MODULE}]))},
+     {"No error handler was defined", ?_assertThrow(_, thrift_socket_server:parse_options([{handler, MissingErrorHandlerOptionList}]))},
+     {"Bad handler module for Service2", ?_assertThrow(_, thrift_socket_server:parse_options([{handler, WrongService2HandlerOptionList}]))},
+     {"Bad service key for Service1", ?_assertThrow(_, thrift_socket_server:parse_options([{handler, WrongServiceKeyOptionList}]))},
+     {"Try to parse a correct handler option list", CorrectHandlerTestFunction}
+    ].
+
+parse_service_options_test_() ->
+    CorrectServiceModuleOptionList = [{"Service1", ?MODULE}, {"Service2", ?MODULE}],
+    WrongService2ModuleOptionList  = [{"Service1", ?MODULE}, {"Service2", "thrift_service_module"}],
+    WrongServiceKeyOptionList       = [{'service1', ?MODULE}, {"Service2", ?MODULE}],
+    CorrectServiceModuleTestFunction = fun() ->
+        ?assertMatch({thrift_socket_server,_,_,_,_,_,_,_,_,_,_,_,_,_}, thrift_socket_server:parse_options([{service, CorrectServiceModuleOptionList}])),
+        {thrift_socket_server,_, ServiceModuleList,_,_,_,_,_,_,_,_,_,_,_} = thrift_socket_server:parse_options([{service, CorrectServiceModuleOptionList}]),
+        lists:foreach(fun
+            ({ServiceName, ServiceModule}) ->
+                ?assertMatch({ok, ServiceModule} when is_atom(ServiceModule), thrift_multiplexed_map_wrapper:find(ServiceName, ServiceModuleList))
+        end, CorrectServiceModuleOptionList)
+    end,
+    [
+     {"Bad argument for the service option", ?_assertThrow(_, thrift_socket_server:parse_options([{service, []}]))},
+     {"Try to parse the service option twice", ?_assertThrow(_, thrift_socket_server:parse_options([{service, ?MODULE}, {service, CorrectServiceModuleOptionList}]))},
+     {"Parse a service module for a non multiplexed service", ?_assertMatch({thrift_socket_server,_,?MODULE,_,_,_,_,_,_,_,_,_,_,_}, thrift_socket_server:parse_options([{service, ?MODULE}]))},
+     {"Bad service module for Service2", ?_assertThrow(_, thrift_socket_server:parse_options([{service, WrongService2ModuleOptionList}]))},
+     {"Bad service key for Service1", ?_assertThrow(_, thrift_socket_server:parse_options([{service, WrongServiceKeyOptionList}]))},
+     {"Try to parse a correct service option list", CorrectServiceModuleTestFunction}
+    ].
diff --git a/lib/erl/test/thrift_test_test.erl b/lib/erl/test/thrift_test_test.erl
new file mode 100644
index 0000000..77df61d
--- /dev/null
+++ b/lib/erl/test/thrift_test_test.erl
@@ -0,0 +1,643 @@
+%%
+%% 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.
+%%
+
+% don't rename this thrift_test, it clobbers generated files
+-module(thrift_test_test).
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-include("gen-erl/thrift_test_constants.hrl").
+
+constant_test_() ->
+  [
+    {"myNumberz equals 1", ?_assertEqual(1, ?THRIFT_TEST_MYNUMBERZ)}
+  ].
+
+record_generation_test_() ->
+  [
+    {"Bonk record", ?_assertMatch(
+      {'thrift.test.Bonk', _, _},
+      #'thrift.test.Bonk'{message=null,type=null}
+    )},
+    {"Bools record", ?_assertMatch(
+      {'thrift.test.Bools', _, _},
+      #'thrift.test.Bools'{im_true=null,im_false=null}
+    )},
+    {"Xtruct record", ?_assertMatch(
+      {'thrift.test.Xtruct', _, _, _, _},
+      #'thrift.test.Xtruct'{string_thing=null,byte_thing=null,i32_thing=null,i64_thing=null}
+    )},
+    {"Xtruct2 record", ?_assertMatch(
+      {'thrift.test.Xtruct2', _, _, _},
+      #'thrift.test.Xtruct2'{byte_thing=null,struct_thing=null,i32_thing=null}
+    )},
+    {"Xtruct3 record", ?_assertMatch(
+      {'thrift.test.Xtruct3', _, _, _, _},
+      #'thrift.test.Xtruct3'{string_thing=null,changed=null,i32_thing=null,i64_thing=null}
+    )},
+    {"Insanity record", ?_assertMatch(
+      {'thrift.test.Insanity', _, _},
+      #'thrift.test.Insanity'{userMap=null,xtructs=null}
+    )},
+    {"CrazyNesting record", ?_assertMatch(
+      {'thrift.test.CrazyNesting', _, _, _, _},
+      #'thrift.test.CrazyNesting'{
+        string_field=null,
+        set_field=null,
+        list_field=null,
+        binary_field=null
+      }
+    )},
+    {"Xception record", ?_assertMatch(
+      {'thrift.test.Xception', _, _},
+      #'thrift.test.Xception'{errorCode=null,message=null}
+    )},
+    {"Xception2 record", ?_assertMatch(
+      {'thrift.test.Xception2', _, _},
+      #'thrift.test.Xception2'{errorCode=null,struct_thing=null}
+    )},
+    {"EmptyStruct record", ?_assertMatch({'thrift.test.EmptyStruct'}, #'thrift.test.EmptyStruct'{})},
+    {"OneField record", ?_assertMatch({'thrift.test.OneField', _}, #'thrift.test.OneField'{field=null})},
+    {"VersioningTestV1 record", ?_assertMatch(
+      {'thrift.test.VersioningTestV1', _, _, _},
+      #'thrift.test.VersioningTestV1'{begin_in_both=null,old_string=null,end_in_both=null}
+    )},
+    {"VersioningTestV2 record", ?_assertMatch(
+      {'thrift.test.VersioningTestV2', _, _, _, _, _, _, _, _, _, _, _, _},
+      #'thrift.test.VersioningTestV2'{
+        begin_in_both=null,
+        newint=null,
+        newbyte=null,
+        newshort=null,
+        newlong=null,
+        newdouble=null,
+        newstruct=null,
+        newlist=null,
+        newset=null,
+        newmap=null,
+        newstring=null,
+        end_in_both=null
+      }
+    )},
+    {"ListTypeVersioningV1 record", ?_assertMatch(
+      {'thrift.test.ListTypeVersioningV1', _, _},
+      #'thrift.test.ListTypeVersioningV1'{myints=null,hello=null}
+    )},
+    {"ListTypeVersioningV2 record", ?_assertMatch(
+      {'thrift.test.ListTypeVersioningV2', _, _},
+      #'thrift.test.ListTypeVersioningV2'{strings=null,hello=null}
+    )},
+    {"GuessProtocolStruct record", ?_assertMatch(
+      {'thrift.test.GuessProtocolStruct', _},
+      #'thrift.test.GuessProtocolStruct'{map_field=null}
+    )},
+    {"LargeDeltas record", ?_assertMatch(
+      {'thrift.test.LargeDeltas', _, _, _, _, _, _, _, _, _, _},
+      #'thrift.test.LargeDeltas'{
+        b1=null,
+        b10=null,
+        b100=null,
+        check_true=null,
+        b1000=null,
+        check_false=null,
+        vertwo2000=null,
+        a_set2500=null,
+        vertwo3000=null,
+        big_numbers=null
+      }
+    )},
+    {"NestedListsI32x2 record", ?_assertMatch(
+      {'thrift.test.NestedListsI32x2', _},
+      #'thrift.test.NestedListsI32x2'{integerlist=null}
+    )},
+    {"NestedListsI32x3 record", ?_assertMatch(
+      {'thrift.test.NestedListsI32x3', _},
+      #'thrift.test.NestedListsI32x3'{integerlist=null}
+    )},
+    {"NestedMixedx2 record", ?_assertMatch(
+      {'thrift.test.NestedMixedx2', _, _, _},
+      #'thrift.test.NestedMixedx2'{
+        int_set_list=null,
+        map_int_strset=null,
+        map_int_strset_list=null
+      }
+    )},
+    {"ListBonks record", ?_assertMatch({'thrift.test.ListBonks', _}, #'thrift.test.ListBonks'{bonk=null})},
+    {"NestedListsBonk record", ?_assertMatch(
+      {'thrift.test.NestedListsBonk', _},
+      #'thrift.test.NestedListsBonk'{bonk=null}
+    )},
+    {"BoolTest record", ?_assertMatch(
+      {'thrift.test.BoolTest', _, _},
+      #'thrift.test.BoolTest'{b=null,s=null}
+    )},
+    {"StructA record", ?_assertMatch({'thrift.test.StructA', _}, #'thrift.test.StructA'{s=null})},
+    {"StructB record", ?_assertMatch(
+      {'thrift.test.StructB', _, _},
+      #'thrift.test.StructB'{aa=null,ab=null}
+    )}
+  ].
+
+struct_info_test_() ->
+  [
+    {"Bonk definition (short version)", ?_assertEqual(
+      {struct, [{1, string}, {2, i32}]},
+      thrift_test_types:struct_info('thrift.test.Bonk')
+    )},
+    {"Bonk definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, string, message, undefined},
+        {2, undefined, i32, type, undefined}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.Bonk')
+    )},
+    {"Bools definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, bool, im_true, undefined},
+        {2, undefined, bool, im_false, undefined}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.Bools')
+    )},
+    {"Xtruct definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, string, string_thing, undefined},
+        {4, undefined, byte, byte_thing, undefined},
+        {9, undefined, i32, i32_thing, undefined},
+        {11, undefined, i64, i64_thing, undefined}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.Xtruct')
+    )},
+    {"Xtruct2 definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, byte, byte_thing, undefined},
+        {2, undefined, {struct, {'thrift_test_types', 'thrift.test.Xtruct'}}, struct_thing, #'thrift.test.Xtruct'{}},
+        {3, undefined, i32, i32_thing, undefined}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.Xtruct2')
+    )},
+    {"Xtruct3 definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, string, string_thing, undefined},
+        {4, undefined, i32, changed, undefined},
+        {9, undefined, i32, i32_thing, undefined},
+        {11, undefined, i64, i64_thing, undefined}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.Xtruct3')
+    )},
+    {"Insanity definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {map, i32, i64}, userMap, dict:new()},
+        {2, undefined, {list, {struct, {'thrift_test_types', 'thrift.test.Xtruct'}}}, xtructs, []}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.Insanity')
+    )},
+    {"CrazyNesting definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, string, string_field, undefined},
+        {2, optional, {set, {struct, {'thrift_test_types', 'thrift.test.Insanity'}}}, set_field, sets:new()},
+        {3, required, {list, {map,
+          {set, i32},
+          {map, i32, {set, {list, {map, {struct, {'thrift_test_types', 'thrift.test.Insanity'}}, string}}}}
+        }}, list_field, []},
+        {4, undefined, string, binary_field, undefined}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.CrazyNesting')
+    )},
+    {"Xception definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, i32, errorCode, undefined},
+        {2, undefined, string, message, undefined}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.Xception')
+    )},
+    {"Xception2 definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, i32, errorCode, undefined},
+        {2, undefined, {struct, {'thrift_test_types', 'thrift.test.Xtruct'}}, struct_thing, #'thrift.test.Xtruct'{}}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.Xception2')
+    )},
+    {"EmptyStruct definition", ?_assertEqual(
+      {struct, []},
+      thrift_test_types:struct_info_ext('thrift.test.EmptyStruct')
+    )},
+    {"OneField definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {struct, {'thrift_test_types', 'thrift.test.EmptyStruct'}}, field, #'thrift.test.EmptyStruct'{}}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.OneField')
+    )},
+    {"VersioningTestV1 definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, i32, begin_in_both, undefined},
+        {3, undefined, string, old_string, undefined},
+        {12, undefined, i32, end_in_both, undefined}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.VersioningTestV1')
+    )},
+    {"VersioningTestV2 definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, i32, begin_in_both, undefined},
+        {2, undefined, i32, newint, undefined},
+        {3, undefined, byte, newbyte, undefined},
+        {4, undefined, i16, newshort, undefined},
+        {5, undefined, i64, newlong, undefined},
+        {6, undefined, double, newdouble, undefined},
+        {7, undefined, {struct, {thrift_test_types, 'thrift.test.Bonk'}}, newstruct, #'thrift.test.Bonk'{}},
+        {8, undefined, {list, i32}, newlist, []},
+        {9, undefined, {set, i32}, newset, sets:new()},
+        {10, undefined, {map, i32, i32}, newmap, dict:new()},
+        {11, undefined, string, newstring, undefined},
+        {12, undefined, i32, end_in_both, undefined}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.VersioningTestV2')
+    )},
+    {"ListTypeVersioningV1 definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {list, i32}, myints, []},
+        {2, undefined, string, hello, undefined}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.ListTypeVersioningV1')
+    )},
+    {"ListTypeVersioningV2 definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {list, string}, strings, []},
+        {2, undefined, string, hello, undefined}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.ListTypeVersioningV2')
+    )},
+    {"GuessProtocolStruct definition", ?_assertEqual(
+      {struct, [
+        {7, undefined, {map, string, string}, map_field, dict:new()}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.GuessProtocolStruct')
+    )},
+    {"LargeDeltas definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {struct, {thrift_test_types, 'thrift.test.Bools'}}, b1, #'thrift.test.Bools'{}},
+        {10, undefined, {struct, {thrift_test_types, 'thrift.test.Bools'}}, b10, #'thrift.test.Bools'{}},
+        {100, undefined, {struct, {thrift_test_types, 'thrift.test.Bools'}}, b100, #'thrift.test.Bools'{}},
+        {500, undefined, bool, check_true, undefined},
+        {1000, undefined, {struct, {thrift_test_types, 'thrift.test.Bools'}}, b1000, #'thrift.test.Bools'{}},
+        {1500, undefined, bool, check_false, undefined},
+        {2000, undefined, {struct, {thrift_test_types, 'thrift.test.VersioningTestV2'}}, vertwo2000, #'thrift.test.VersioningTestV2'{}},
+        {2500, undefined, {set, string}, a_set2500, sets:new()},
+        {3000, undefined, {struct, {thrift_test_types, 'thrift.test.VersioningTestV2'}}, vertwo3000, #'thrift.test.VersioningTestV2'{}},
+        {4000, undefined, {list, i32}, big_numbers, []}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.LargeDeltas')
+    )},
+    {"NestedListsI32x2 definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {list, {list, i32}}, integerlist, []}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.NestedListsI32x2')
+    )},
+    {"NestedListsI32x3 definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {list, {list, {list, i32}}}, integerlist, []}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.NestedListsI32x3')
+    )},
+    {"NestedMixedx2 definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {list, {set, i32}}, int_set_list, []},
+        {2, undefined, {map, i32, {set, string}}, map_int_strset, dict:new()},
+        {3, undefined, {list, {map, i32, {set, string}}}, map_int_strset_list, []}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.NestedMixedx2')
+    )},
+    {"ListBonks definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {list, {struct, {thrift_test_types, 'thrift.test.Bonk'}}}, bonk, []}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.ListBonks')
+    )},
+    {"NestedListsBonk definition", ?_assertEqual(
+      {struct, [
+        {1, undefined, {list, {list, {list, {struct, {thrift_test_types, 'thrift.test.Bonk'}}}}}, bonk, []}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.NestedListsBonk')
+    )},
+    {"BoolTest definition", ?_assertEqual(
+      {struct, [
+        {1, optional, bool, b, true},
+        {2, optional, string, s, "true"}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.BoolTest')
+    )},
+    {"StructA definition", ?_assertEqual(
+      {struct, [{1, required, string, s, undefined}]},
+      thrift_test_types:struct_info_ext('thrift.test.StructA')
+    )},
+    {"StructB definition", ?_assertEqual(
+      {struct, [
+        {1, optional, {struct, {thrift_test_types, 'thrift.test.StructA'}}, aa, #'thrift.test.StructA'{}},
+        {2, required, {struct, {thrift_test_types, 'thrift.test.StructA'}}, ab, #'thrift.test.StructA'{}}
+      ]},
+      thrift_test_types:struct_info_ext('thrift.test.StructB')
+    )}
+  ].
+
+service_info_test_() ->
+  [
+    {"testVoid params", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testVoid, params_type)
+    )},
+    {"testVoid reply", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testVoid, reply_type)
+    )},
+    {"testVoid exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testVoid, exceptions)
+    )},
+    {"testString params", ?_assertEqual(
+      {struct, [{1, string}]},
+      thrift_test_thrift:function_info(testString, params_type)
+    )},
+    {"testString reply", ?_assertEqual(
+      string,
+      thrift_test_thrift:function_info(testString, reply_type)
+    )},
+    {"testString exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testString, exceptions)
+    )},
+    {"testByte params", ?_assertEqual(
+      {struct, [{1, byte}]},
+      thrift_test_thrift:function_info(testByte, params_type)
+    )},
+    {"testByte reply", ?_assertEqual(
+      byte,
+      thrift_test_thrift:function_info(testByte, reply_type)
+    )},
+    {"testByte exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testByte, exceptions)
+    )},
+    {"testI32 params", ?_assertEqual(
+      {struct, [{1, i32}]},
+      thrift_test_thrift:function_info(testI32, params_type)
+    )},
+    {"testI32 reply", ?_assertEqual(
+      i32,
+      thrift_test_thrift:function_info(testI32, reply_type)
+    )},
+    {"testI32 exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testI32, exceptions)
+    )},
+    {"testI64 params", ?_assertEqual(
+      {struct, [{1, i64}]},
+      thrift_test_thrift:function_info(testI64, params_type)
+    )},
+    {"testI64 reply", ?_assertEqual(
+      i64,
+      thrift_test_thrift:function_info(testI64, reply_type)
+    )},
+    {"testI64 exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testI64, exceptions)
+    )},
+    {"testDouble params", ?_assertEqual(
+      {struct, [{1, double}]},
+      thrift_test_thrift:function_info(testDouble, params_type)
+    )},
+    {"testDouble reply", ?_assertEqual(
+      double,
+      thrift_test_thrift:function_info(testDouble, reply_type)
+    )},
+    {"testDouble exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testDouble, exceptions)
+    )},
+    {"testStruct params", ?_assertEqual(
+      {struct, [
+        {1, {struct, {thrift_test_types, 'thrift.test.Xtruct'}}}
+      ]},
+      thrift_test_thrift:function_info(testStruct, params_type)
+    )},
+    {"testStruct reply", ?_assertEqual(
+      {struct, {thrift_test_types, 'thrift.test.Xtruct'}},
+      thrift_test_thrift:function_info(testStruct, reply_type)
+    )},
+    {"testStruct exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testStruct, exceptions)
+    )},
+    {"testNest params", ?_assertEqual(
+      {struct, [
+        {1, {struct, {thrift_test_types, 'thrift.test.Xtruct2'}}}
+      ]},
+      thrift_test_thrift:function_info(testNest, params_type)
+    )},
+    {"testNest reply", ?_assertEqual(
+      {struct, {thrift_test_types, 'thrift.test.Xtruct2'}},
+      thrift_test_thrift:function_info(testNest, reply_type)
+    )},
+    {"testNest exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testNest, exceptions)
+    )},
+    {"testMap params", ?_assertEqual(
+      {struct, [
+        {1, {map, i32, i32}}
+      ]},
+      thrift_test_thrift:function_info(testMap, params_type)
+    )},
+    {"testMap reply", ?_assertEqual(
+      {map, i32, i32},
+      thrift_test_thrift:function_info(testMap, reply_type)
+    )},
+    {"testMap exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testMap, exceptions)
+    )},
+    {"testStringMap params", ?_assertEqual(
+      {struct, [
+        {1, {map, string, string}}
+      ]},
+      thrift_test_thrift:function_info(testStringMap, params_type)
+    )},
+    {"testStringMap reply", ?_assertEqual(
+      {map, string, string},
+      thrift_test_thrift:function_info(testStringMap, reply_type)
+    )},
+    {"testStringMap exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testStringMap, exceptions)
+    )},
+    {"testSet params", ?_assertEqual(
+      {struct, [
+        {1, {set, i32}}
+      ]},
+      thrift_test_thrift:function_info(testSet, params_type)
+    )},
+    {"testSet reply", ?_assertEqual(
+      {set, i32},
+      thrift_test_thrift:function_info(testSet, reply_type)
+    )},
+    {"testSet exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testSet, exceptions)
+    )},
+    {"testList params", ?_assertEqual(
+      {struct, [
+        {1, {list, i32}}
+      ]},
+      thrift_test_thrift:function_info(testList, params_type)
+    )},
+    {"testList reply", ?_assertEqual(
+      {list, i32},
+      thrift_test_thrift:function_info(testList, reply_type)
+    )},
+    {"testList exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testList, exceptions)
+    )},
+    {"testEnum params", ?_assertEqual(
+      {struct, [
+        {1, i32}
+      ]},
+      thrift_test_thrift:function_info(testEnum, params_type)
+    )},
+    {"testEnum reply", ?_assertEqual(
+      i32,
+      thrift_test_thrift:function_info(testEnum, reply_type)
+    )},
+    {"testEnum exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testEnum, exceptions)
+    )},
+    {"testTypedef params", ?_assertEqual(
+      {struct, [{1, i64}]},
+      thrift_test_thrift:function_info(testTypedef, params_type)
+    )},
+    {"testTypedef reply", ?_assertEqual(
+      i64,
+      thrift_test_thrift:function_info(testTypedef, reply_type)
+    )},
+    {"testTypedef exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testTypedef, exceptions)
+    )},
+    {"testMapMap params", ?_assertEqual(
+      {struct, [
+        {1, i32}
+      ]},
+      thrift_test_thrift:function_info(testMapMap, params_type)
+    )},
+    {"testMapMap reply", ?_assertEqual(
+      {map, i32, {map, i32,i32}},
+      thrift_test_thrift:function_info(testMapMap, reply_type)
+    )},
+    {"testMapMap exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testMapMap, exceptions)
+    )},
+    {"testInsanity params", ?_assertEqual(
+      {struct, [
+        {1, {struct, {thrift_test_types, 'thrift.test.Insanity'}}}
+      ]},
+      thrift_test_thrift:function_info(testInsanity, params_type)
+    )},
+    {"testInsanity reply", ?_assertEqual(
+      {map, i64, {map, i32, {struct, {'thrift_test_types', 'thrift.test.Insanity'}}}},
+      thrift_test_thrift:function_info(testInsanity, reply_type)
+    )},
+    {"testInsanity exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testInsanity, exceptions)
+    )},
+    {"testMulti params", ?_assertEqual(
+      {struct, [
+        {1, byte},
+        {2, i32},
+        {3, i64},
+        {4, {map, i16, string}},
+        {5, i32},
+        {6, i64}
+      ]},
+      thrift_test_thrift:function_info(testMulti, params_type)
+    )},
+    {"testMulti reply", ?_assertEqual(
+      {struct, {thrift_test_types, 'thrift.test.Xtruct'}},
+      thrift_test_thrift:function_info(testMulti, reply_type)
+    )},
+    {"testMulti exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testMulti, exceptions)
+    )},
+    {"testException params", ?_assertEqual(
+      {struct, [{1, string}]},
+      thrift_test_thrift:function_info(testException, params_type)
+    )},
+    {"testException reply", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testException, reply_type)
+    )},
+    {"testException exceptions", ?_assertEqual(
+      {struct, [
+        {1, {struct, {thrift_test_types, 'thrift.test.Xception'}}}
+      ]},
+      thrift_test_thrift:function_info(testException, exceptions)
+    )},
+    {"testMultiException params", ?_assertEqual(
+      {struct, [{1, string}, {2, string}]},
+      thrift_test_thrift:function_info(testMultiException, params_type)
+    )},
+    {"testMultiException reply", ?_assertEqual(
+      {struct, {thrift_test_types, 'thrift.test.Xtruct'}},
+      thrift_test_thrift:function_info(testMultiException, reply_type)
+    )},
+    {"testMultiException exceptions", ?_assertEqual(
+      {struct, [
+        {1, {struct, {thrift_test_types, 'thrift.test.Xception'}}},
+        {2, {struct, {thrift_test_types, 'thrift.test.Xception2'}}}
+      ]},
+      thrift_test_thrift:function_info(testMultiException, exceptions)
+    )},
+    {"testOneway params", ?_assertEqual(
+      {struct, [{1, i32}]},
+      thrift_test_thrift:function_info(testOneway, params_type)
+    )},
+    {"testOneway reply", ?_assertEqual(
+      oneway_void,
+      thrift_test_thrift:function_info(testOneway, reply_type)
+    )},
+    {"testOneway exceptions", ?_assertEqual(
+      {struct, []},
+      thrift_test_thrift:function_info(testOneway, exceptions)
+    )},
+    {"secondtestString params", ?_assertEqual(
+      {struct, [{1, string}]},
+      second_service_thrift:function_info(secondtestString, params_type)
+    )},
+    {"secondtestString reply", ?_assertEqual(
+      string,
+      second_service_thrift:function_info(secondtestString, reply_type)
+    )},
+    {"secondtestString exceptions", ?_assertEqual(
+      {struct, []},
+      second_service_thrift:function_info(secondtestString, exceptions)
+    )}
+  ].
diff --git a/lib/go/Makefile.am b/lib/go/Makefile.am
index efb58be..0dfa5fa 100644
--- a/lib/go/Makefile.am
+++ b/lib/go/Makefile.am
@@ -17,21 +17,29 @@
 # under the License.
 #
 
+SUBDIRS = .
+
 if WITH_TESTS
-SUBDIRS = test
+SUBDIRS += test
 endif
 
 install:
 	@echo '##############################################################'
 	@echo '##############################################################'
-	@echo 'The Go client library should be installed via "go get", please see /lib/go/README'
+	@echo 'The Go client library should be installed via "go get", please see /lib/go/README.md'
 	@echo '##############################################################'
 	@echo '##############################################################'
 
 check-local:
-	$(GO) test ./thrift
+	GOPATH=`pwd` $(GO) test -race ./thrift
 
-all-local: check-local
+clean-local:
+	$(RM) -rf pkg
+
+all-local:
+	GOPATH=`pwd` $(GO) build ./thrift
 
 EXTRA_DIST = \
-	thrift
\ No newline at end of file
+	thrift \
+	coding_standards.md \
+	README.md
diff --git a/lib/go/README b/lib/go/README
deleted file mode 100644
index 94628d9..0000000
--- a/lib/go/README
+++ /dev/null
@@ -1,31 +0,0 @@
-Thrift Python Software Library
-
-License
-=======
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-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.
-
-Using Thrift with Go
-====================
-
-In following Go conventions, we reccomend you use the 'go' tool to install
-Thrift for go.
-
-$ go get git.apache.org/thrift.git/lib/go/thrift
-
-Will install the last stable release.
diff --git a/lib/go/README.md b/lib/go/README.md
new file mode 100644
index 0000000..ce6d5ed
--- /dev/null
+++ b/lib/go/README.md
@@ -0,0 +1,83 @@
+Thrift Go Software Library
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+
+Using Thrift with Go
+====================
+
+Thrift supports Go 1.7+
+
+In following Go conventions, we recommend you use the 'go' tool to install
+Thrift for go.
+
+    $ go get github.com/apache/thrift/lib/go/thrift/...
+
+Will retrieve and install the most recent version of the package.
+
+
+A note about optional fields
+============================
+
+The thrift-to-Go compiler tries to represent thrift IDL structs as Go structs.
+We must be able to distinguish between optional fields that are set to their
+default value and optional values which are actually unset, so the generated
+code represents optional fields via pointers.
+
+This is generally intuitive and works well much of the time, but Go does not
+have a syntax for creating a pointer to a constant in a single expression. That
+is, given a struct like
+
+    struct SomeIDLType {
+    	OptionalField *int32
+    }
+
+, the following will not compile:
+
+    x := &SomeIDLType{
+    	OptionalField: &(3),
+    }
+
+(Nor is there any other syntax that's built in to the language)
+
+As such, we provide some helpers that do just this under lib/go/thrift/. E.g.,
+
+    x := &SomeIDLType{
+    	OptionalField: thrift.Int32Ptr(3),
+    }
+
+And so on. The code generator also creates analogous helpers for user-defined
+typedefs and enums.
+
+Adding custom tags to generated Thrift structs
+==============================================
+
+You can add tags to the auto-generated thrift structs using the following format:
+
+    struct foo {
+      1: required string Bar (go.tag = "some_tag:\"some_tag_value\"")
+    }
+    
+which will generate:
+
+    type Foo struct {
+      Bar string `thrift:"bar,1,required" some_tag:"some_tag_value"`
+    }
diff --git a/lib/go/coding_standards.md b/lib/go/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/go/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/go/test/BinaryKeyTest.thrift b/lib/go/test/BinaryKeyTest.thrift
new file mode 100644
index 0000000..71cb614
--- /dev/null
+++ b/lib/go/test/BinaryKeyTest.thrift
@@ -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.
+#
+
+# Make sure that thrift produce compilable code for binary key
+struct testStruct {
+  1: required map<binary,string> bin_to_string
+}
+
diff --git a/lib/go/test/DontExportRWTest.thrift b/lib/go/test/DontExportRWTest.thrift
new file mode 100644
index 0000000..39e5a6f
--- /dev/null
+++ b/lib/go/test/DontExportRWTest.thrift
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+struct InnerStruct {
+  1: required string id
+}
+
+struct TestStruct {
+  1: required string id
+  2: required InnerStruct inner
+}
diff --git a/lib/go/test/ErrorTest.thrift b/lib/go/test/ErrorTest.thrift
new file mode 100644
index 0000000..33b6644
--- /dev/null
+++ b/lib/go/test/ErrorTest.thrift
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+struct TestStruct 
+{
+  1: map<string, string> m,
+  2: list<string> l,
+  3: set<string> s,
+  4: i32 i
+}
+
+service ErrorTest 
+{
+  TestStruct         testStruct(1: TestStruct thing)
+  string             testString(1: string s)
+}
diff --git a/lib/go/test/GoTagTest.thrift b/lib/go/test/GoTagTest.thrift
new file mode 100644
index 0000000..508b3b6
--- /dev/null
+++ b/lib/go/test/GoTagTest.thrift
@@ -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.
+#
+
+struct tagged {
+    1: string string_thing,
+    2: i64 int_thing (go.tag = "json:\"int_thing,string\""),
+    3: optional i64 optional_int_thing
+}
diff --git a/lib/go/test/IgnoreInitialismsTest.thrift b/lib/go/test/IgnoreInitialismsTest.thrift
new file mode 100644
index 0000000..0b30e9e
--- /dev/null
+++ b/lib/go/test/IgnoreInitialismsTest.thrift
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+struct IgnoreInitialismsTest {
+    1: i64 id,
+    2: i64 my_id,
+    3: i64 num_cpu,
+    4: i64 num_gpu,
+    5: i64 my_ID,
+}
diff --git a/lib/go/test/InitialismsTest.thrift b/lib/go/test/InitialismsTest.thrift
new file mode 100644
index 0000000..ad86ac1
--- /dev/null
+++ b/lib/go/test/InitialismsTest.thrift
@@ -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.
+#
+
+struct InitialismsTest {
+    1: string user_id,
+    2: string server_url,
+    3: string id, 
+}
diff --git a/lib/go/test/Makefile.am b/lib/go/test/Makefile.am
index 4e71cd0..78d4681 100644
--- a/lib/go/test/Makefile.am
+++ b/lib/go/test/Makefile.am
@@ -17,29 +17,95 @@
 # under the License.
 #
 
-THRIFT = $(top_srcdir)/compiler/cpp/thrift
+THRIFTARGS = -out gopath/src/ --gen go:thrift_import=thrift$(COMPILER_EXTRAFLAG)
 THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift
 
 # Thrift for GO has problems with complex map keys: THRIFT-2063
-gopath: $(THRIFT) $(THRIFTTEST) IncludesTest.thrift NamespacedTest.thrift
+gopath: $(THRIFT) $(THRIFTTEST) \
+				IncludesTest.thrift \
+				NamespacedTest.thrift \
+				MultiplexedProtocolTest.thrift \
+				OnewayTest.thrift \
+				OptionalFieldsTest.thrift \
+				RequiredFieldTest.thrift \
+				ServicesTest.thrift \
+				GoTagTest.thrift \
+				TypedefFieldTest.thrift \
+				RefAnnotationFieldsTest.thrift \
+				UnionDefaultValueTest.thrift \
+				UnionBinaryTest.thrift \
+				ErrorTest.thrift \
+				NamesTest.thrift \
+				InitialismsTest.thrift \
+				DontExportRWTest.thrift \
+				dontexportrwtest/compile_test.go \
+				IgnoreInitialismsTest.thrift
 	mkdir -p gopath/src
-	grep -v list.*map.*list.*map $(THRIFTTEST) > ThriftTest.thrift
-	$(THRIFT) --gen go:thrift_import=thrift -r IncludesTest.thrift
-	ln -nfs ../../gen-go/ThriftTest gopath/src/ThriftTest
-	ln -nfs ../../gen-go/IncludesTest gopath/src/IncludesTest
-	ln -nfs ../../gen-go/lib gopath/src/lib
+	grep -v list.*map.*list.*map $(THRIFTTEST) | grep -v 'set<Insanity>' > ThriftTest.thrift
+	$(THRIFT) $(THRIFTARGS) -r IncludesTest.thrift
+	$(THRIFT) $(THRIFTARGS) BinaryKeyTest.thrift
+	$(THRIFT) $(THRIFTARGS) MultiplexedProtocolTest.thrift
+	$(THRIFT) $(THRIFTARGS) OnewayTest.thrift
+	$(THRIFT) $(THRIFTARGS) OptionalFieldsTest.thrift
+	$(THRIFT) $(THRIFTARGS) RequiredFieldTest.thrift
+	$(THRIFT) $(THRIFTARGS) ServicesTest.thrift
+	$(THRIFT) $(THRIFTARGS) GoTagTest.thrift
+	$(THRIFT) $(THRIFTARGS) TypedefFieldTest.thrift
+	$(THRIFT) $(THRIFTARGS) RefAnnotationFieldsTest.thrift
+	$(THRIFT) $(THRIFTARGS) UnionDefaultValueTest.thrift
+	$(THRIFT) $(THRIFTARGS) UnionBinaryTest.thrift
+	$(THRIFT) $(THRIFTARGS) ErrorTest.thrift
+	$(THRIFT) $(THRIFTARGS) NamesTest.thrift
+	$(THRIFT) $(THRIFTARGS) InitialismsTest.thrift
+	$(THRIFT) $(THRIFTARGS),read_write_private DontExportRWTest.thrift
+	$(THRIFT) $(THRIFTARGS),ignore_initialisms IgnoreInitialismsTest.thrift
+	GOPATH=`pwd`/gopath $(GO) get github.com/golang/mock/gomock || true
+	sed -i 's/\"context\"/\"golang.org\/x\/net\/context\"/g' gopath/src/github.com/golang/mock/gomock/controller.go || true
+	GOPATH=`pwd`/gopath $(GO) get github.com/golang/mock/gomock
 	ln -nfs ../../../thrift gopath/src/thrift
+	ln -nfs ../../tests gopath/src/tests
+	cp -r ./dontexportrwtest gopath/src
 	touch gopath
 
 check: gopath
-	GOPATH=`pwd`/gopath $(GO) build IncludesTest
+	GOPATH=`pwd`/gopath $(GO) build \
+				includestest \
+				binarykeytest \
+				servicestest \
+				typedeffieldtest \
+				refannotationfieldstest \
+				errortest	\
+				namestest \
+				initialismstest \
+				dontexportrwtest \
+				ignoreinitialismstest \
+				unionbinarytest
+	GOPATH=`pwd`/gopath $(GO) test thrift tests dontexportrwtest
 
 clean-local:
-	$(RM) -r gen-go gopath ThriftTest.thrift
+	$(RM) -r gopath ThriftTest.thrift gen-go
 
 client: stubs
 	$(GO) run TestClient.go
 
 EXTRA_DIST = \
+	dontexportrwtest \
+	tests \
+	BinaryKeyTest.thrift \
+	GoTagTest.thrift \
 	IncludesTest.thrift \
-	NamespacedTest.thrift
+	MultiplexedProtocolTest.thrift \
+	NamespacedTest.thrift \
+	OnewayTest.thrift \
+	OptionalFieldsTest.thrift \
+	RequiredFieldTest.thrift \
+	RefAnnotationFieldsTest.thrift \
+	UnionDefaultValueTest.thrift \
+	UnionBinaryTest.thrift \
+	ServicesTest.thrift \
+	TypedefFieldTest.thrift \
+	ErrorTest.thrift \
+	NamesTest.thrift \
+	InitialismsTest.thrift \
+	DontExportRWTest.thrift \
+	IgnoreInitialismsTest.thrift
diff --git a/lib/go/test/MultiplexedProtocolTest.thrift b/lib/go/test/MultiplexedProtocolTest.thrift
new file mode 100644
index 0000000..b263f59
--- /dev/null
+++ b/lib/go/test/MultiplexedProtocolTest.thrift
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+service First {
+    i64 returnOne();
+}
+
+service Second {
+    i64 returnTwo();
+}
+
diff --git a/lib/go/test/NamesTest.thrift b/lib/go/test/NamesTest.thrift
new file mode 100644
index 0000000..e7e9563
--- /dev/null
+++ b/lib/go/test/NamesTest.thrift
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+
+struct NamesTest {
+    1: required string type
+}
+
+service NameCollisionOne
+{
+    void blahBlah()
+}
+
+service NameCollisionTwo
+{
+    void blahBlah()
+}
diff --git a/lib/go/test/NamespacedTest.thrift b/lib/go/test/NamespacedTest.thrift
index 1bb2fc4..a910350 100644
--- a/lib/go/test/NamespacedTest.thrift
+++ b/lib/go/test/NamespacedTest.thrift
@@ -19,7 +19,7 @@
 
 include "ThriftTest.thrift"
 
-namespace go lib.go.test.NamespacedTest
+namespace go lib.go.test.namespacedtest
 
 enum Stuff {
   ONE = 1,
diff --git a/lib/go/test/OnewayTest.thrift b/lib/go/test/OnewayTest.thrift
new file mode 100644
index 0000000..3242f80
--- /dev/null
+++ b/lib/go/test/OnewayTest.thrift
@@ -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.
+#
+
+service OneWay {
+    oneway void hi(1: i64 i, 2: string s)
+    void emptyfunc()
+    i64 echo_int(1: i64 param)
+}
diff --git a/lib/go/test/OptionalFieldsTest.thrift b/lib/go/test/OptionalFieldsTest.thrift
new file mode 100644
index 0000000..2afc157
--- /dev/null
+++ b/lib/go/test/OptionalFieldsTest.thrift
@@ -0,0 +1,50 @@
+#
+# 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.
+#
+
+struct structA {
+ 1: required i64 sa_i
+}
+
+struct all_optional {
+ 1: optional string s = "DEFAULT",
+ 2: optional i64 i = 42,
+ 3: optional bool b = false,
+ 4: optional string s2,
+ 5: optional i64 i2,
+ 6: optional bool b2,
+ 7: optional structA aa,
+ 9: optional list<i64> l,
+ 10: optional list<i64> l2 = [1, 2],
+ 11: optional map<i64, i64> m,
+ 12: optional map<i64, i64> m2 = {1:2, 3:4},
+ 13: optional binary bin,
+ 14: optional binary bin2 = "asdf",
+}
+
+struct structB {
+ 1: required structA required_struct_thing
+ 2: optional structA optional_struct_thing
+}
+
+struct structC {
+ 1: string s,
+ 2: required i32 i,
+ 3: optional bool b,
+ 4: required string s2,
+}
diff --git a/lib/go/test/RefAnnotationFieldsTest.thrift b/lib/go/test/RefAnnotationFieldsTest.thrift
new file mode 100644
index 0000000..b7f28c2
--- /dev/null
+++ b/lib/go/test/RefAnnotationFieldsTest.thrift
@@ -0,0 +1,58 @@
+#
+# 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.
+#
+
+struct structA {
+ 1: required i64 sa_i
+}
+
+struct all_referenced {
+ 1: optional string s = "DEFAULT" (cpp.ref = ""),
+ 2: optional i64 i = 42 (cpp.ref = ""),
+ 3: optional bool b = false (cpp.ref = ""),
+ 4: optional string s2 (cpp.ref = ""),
+ 5: optional i64 i2 (cpp.ref = ""),
+ 6: optional bool b2 (cpp.ref = ""),
+ 7: optional structA aa (cpp.ref = ""),
+ 9: optional list<i64> l (cpp.ref = ""),
+ 10: optional list<i64> l2 = [1, 2] (cpp.ref = ""),
+ 11: optional map<i64, i64> m (cpp.ref = ""),
+ 12: optional map<i64, i64> m2 = {1:2, 3:4} (cpp.ref = ""),
+ 13: optional binary bin (cpp.ref = ""),
+ 14: optional binary bin2 = "asdf" (cpp.ref = ""),
+
+ 15: required string ref_s = "DEFAULT" (cpp.ref = ""),
+ 16: required i64 ref_i = 42 (cpp.ref = ""),
+ 17: required bool ref_b = false (cpp.ref = ""),
+ 18: required string ref_s2 (cpp.ref = ""),
+ 19: required i64 ref_i2 (cpp.ref = ""),
+ 20: required bool ref_b2 (cpp.ref = ""),
+ 21: required structA ref_aa (cpp.ref = ""),
+ 22: required list<i64> ref_l (cpp.ref = ""),
+ 23: required list<i64> ref_l2 = [1, 2] (cpp.ref = ""),
+ 24: required map<i64, i64> ref_m (cpp.ref = ""),
+ 25: required map<i64, i64> ref_m2 = {1:2, 3:4} (cpp.ref = ""),
+ 26: required binary ref_bin (cpp.ref = ""),
+ 27: required binary ref_bin2 = "asdf" (cpp.ref = ""),
+
+}
+
+struct structB {
+ 1: required structA required_struct_thing
+ 2: optional structA optional_struct_thing
+}
diff --git a/lib/go/test/RequiredFieldTest.thrift b/lib/go/test/RequiredFieldTest.thrift
new file mode 100644
index 0000000..4a2dcae
--- /dev/null
+++ b/lib/go/test/RequiredFieldTest.thrift
@@ -0,0 +1,7 @@
+struct RequiredField {
+  1: required string name
+}
+
+struct OtherThing {
+  1: required i16 value
+}
diff --git a/lib/go/test/ServicesTest.thrift b/lib/go/test/ServicesTest.thrift
new file mode 100644
index 0000000..882b03a
--- /dev/null
+++ b/lib/go/test/ServicesTest.thrift
@@ -0,0 +1,111 @@
+#
+# 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.
+#
+
+# We are only testing that generated code compiles, no correctness checking is done
+
+exception moderate_disaster {
+  1: i32 errorCode,
+  2: string message
+}
+
+exception total_disaster {
+  1: string message
+  2: optional bool president_was_woken_up = false
+}
+
+struct struct_a {
+  1: required i64 whatever
+}
+
+service a_serv {
+    void voidfunc(),
+    void void_with_1ex() throws(1: moderate_disaster err1)
+    void void_with_2ex() throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    string stringfunc()
+    string stringfunc_1ex() throws(1: moderate_disaster err1)
+    string stringfunc_2ex() throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    i64 i64func()
+    i64 i64func_1ex() throws(1: moderate_disaster err1)
+    i64 i64func_2ex() throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    list<string> list_of_strings_func()
+    list<string> list_of_strings_func_1ex() throws(1: moderate_disaster err1)
+    list<string> list_of_strings_func_2ex() throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    map<i64,string> map_func()
+    map<i64,string> map_func_1ex() throws(1: moderate_disaster err1)
+    map<i64,string> map_func_2ex() throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    struct_a struct_a_func()
+    struct_a struct_a_func_1ex() throws(1: moderate_disaster err1)
+    struct_a struct_a_func_2ex() throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    void voidfunc_1int(1: i64 i),
+    void void_with_1ex_1int(1: i64 i) throws(1: moderate_disaster err1)
+    void void_with_2ex_1int(1: i64 i) throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    string stringfunc_1int(1: i64 i)
+    string stringfunc_1ex_1int(1: i64 i) throws(1: moderate_disaster err1)
+    string stringfunc_2ex_1int(1: i64 i) throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    i64 i64func_1int(1: i64 i)
+    i64 i64func_1ex_1int(1: i64 i) throws(1: moderate_disaster err1)
+    i64 i64func_2ex_1int(1: i64 i) throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    list<string> list_of_strings_func_1int(1: i64 i)
+    list<string> list_of_strings_func_1ex_1int(1: i64 i) throws(1: moderate_disaster err1)
+    list<string> list_of_strings_func_2ex_1int(1: i64 i) throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    map<i64,string> map_func_1int(1: i64 i)
+    map<i64,string> map_func_1ex_1int(1: i64 i) throws(1: moderate_disaster err1)
+    map<i64,string> map_func_2ex_1int(1: i64 i) throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    struct_a struct_a_func_1int(1: i64 i)
+    struct_a struct_a_func_1ex_1int(1: i64 i) throws(1: moderate_disaster err1)
+    struct_a struct_a_func_2ex_1int(1: i64 i) throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    void voidfunc_1int_1s(1: i64 i, 2: string s),
+    void void_with_1ex_1int_1s(1: i64 i, 2: string s) throws(1: moderate_disaster err1)
+    void void_with_2ex_1int_1s(1: i64 i, 2: string s) throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    string stringfunc_1int_1s(1: i64 i, 2: string s)
+    string stringfunc_1ex_1int_1s(1: i64 i, 2: string s) throws(1: moderate_disaster err1)
+    string stringfunc_2ex_1int_1s(1: i64 i, 2: string s) throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    i64 i64func_1int_1s(1: i64 i, 2: string s)
+    i64 i64func_1ex_1int_1s(1: i64 i, 2: string s) throws(1: moderate_disaster err1)
+    i64 i64func_2ex_1int_1s(1: i64 i, 2: string s) throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    list<string> list_of_strings_func_1int_1s(1: i64 i, 2: string s)
+    list<string> list_of_strings_func_1ex_1int_1s(1: i64 i, 2: string s) throws(1: moderate_disaster err1)
+    list<string> list_of_strings_func_2ex_1int_1s(1: i64 i, 2: string s) throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    map<i64,string> map_func_1int_1s(1: i64 i, 2: string s)
+    map<i64,string> map_func_1ex_1int_1s(1: i64 i, 2: string s) throws(1: moderate_disaster err1)
+    map<i64,string> map_func_2ex_1int_1s(1: i64 i, 2: string s) throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    struct_a struct_a_func_1int_1s(1: i64 i, 2: string s)
+    struct_a struct_a_func_1ex_1int_1s(1: i64 i, 2: string s) throws(1: moderate_disaster err1)
+    struct_a struct_a_func_2ex_1int_1s(1: i64 i, 2: string s) throws(1: moderate_disaster err1, 2:total_disaster err2)
+
+    struct_a struct_a_func_1struct_a(1: struct_a st)
+
+}
diff --git a/lib/go/test/TypedefFieldTest.thrift b/lib/go/test/TypedefFieldTest.thrift
new file mode 100644
index 0000000..390e8c8
--- /dev/null
+++ b/lib/go/test/TypedefFieldTest.thrift
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+
+# We are only testing that generated code compiles, no correctness checking is done
+
+enum Details {
+  Everything = 0
+  StateOnly = 1
+  StateAndOptions = 2
+  SomethingElse = 3
+}
+
+typedef list< Details>  DetailsWanted
+
+struct BaseRequest {
+  1 : optional string RequestID
+}
+
+struct GetMyDetails {
+  1 : required BaseRequest base_
+  2 : required string ObjectID
+  3 : optional DetailsWanted DetailsWanted
+}
diff --git a/lib/go/test/UnionBinaryTest.thrift b/lib/go/test/UnionBinaryTest.thrift
new file mode 100644
index 0000000..f77112b
--- /dev/null
+++ b/lib/go/test/UnionBinaryTest.thrift
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+# See https://issues.apache.org/jira/browse/THRIFT-4573
+union Sample {
+  1: map<string, string> u1,
+  2: binary u2,
+  3: list<string> u3
+}
diff --git a/lib/go/test/UnionDefaultValueTest.thrift b/lib/go/test/UnionDefaultValueTest.thrift
new file mode 100644
index 0000000..4c93480
--- /dev/null
+++ b/lib/go/test/UnionDefaultValueTest.thrift
@@ -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.
+#
+
+struct Option1 {
+}
+
+struct Option2 {
+  1: optional string name
+}
+
+union Descendant {
+  1: Option1 option1
+  2: Option2 option2
+}
+
+struct TestStruct {
+  1: optional Descendant descendant = { "option1": {}}
+}
diff --git a/lib/go/test/dontexportrwtest/compile_test.go b/lib/go/test/dontexportrwtest/compile_test.go
new file mode 100644
index 0000000..cf6763e
--- /dev/null
+++ b/lib/go/test/dontexportrwtest/compile_test.go
@@ -0,0 +1,37 @@
+/*
+ * 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 dontexportrwtest
+
+import (
+	"testing"
+)
+
+// Make sure that thrift generates non-exported read/write methods if
+// read_write_private option is specified
+func TestReadWriteMethodsArePrivate(t *testing.T) {
+	// This will only compile if read/write methods exist
+	s := NewTestStruct()
+	_ = s.read
+	_ = s.write
+
+	is := NewInnerStruct()
+	_ = is.read
+	_ = is.write
+}
diff --git a/lib/go/test/tests/binary_key_test.go b/lib/go/test/tests/binary_key_test.go
new file mode 100644
index 0000000..aa96193
--- /dev/null
+++ b/lib/go/test/tests/binary_key_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 tests
+
+import (
+	"binarykeytest"
+	"testing"
+)
+
+func TestBinaryMapKeyGeneratesString(t *testing.T) {
+	s := binarykeytest.NewTestStruct()
+	//This will only compile if BinToString has type of map[string]string
+	s.BinToString = make(map[string]string)
+}
diff --git a/lib/go/test/tests/client_error_test.go b/lib/go/test/tests/client_error_test.go
new file mode 100644
index 0000000..fdec4ea
--- /dev/null
+++ b/lib/go/test/tests/client_error_test.go
@@ -0,0 +1,873 @@
+/*
+ * 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 tests
+
+import (
+	"context"
+	"errors"
+	"errortest"
+	"testing"
+	"thrift"
+
+	"github.com/golang/mock/gomock"
+)
+
+// TestCase: Comprehensive call and reply workflow in the client.
+// Setup mock to fail at a certain position. Return true if position exists otherwise false.
+func prepareClientCallReply(protocol *MockTProtocol, failAt int, failWith error) bool {
+	var err error = nil
+
+	if failAt == 0 {
+		err = failWith
+	}
+	last := protocol.EXPECT().WriteMessageBegin("testStruct", thrift.CALL, int32(1)).Return(err)
+	if failAt == 0 {
+		return true
+	}
+	if failAt == 1 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteStructBegin("testStruct_args").Return(err).After(last)
+	if failAt == 1 {
+		return true
+	}
+	if failAt == 2 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteFieldBegin("thing", thrift.TType(thrift.STRUCT), int16(1)).Return(err).After(last)
+	if failAt == 2 {
+		return true
+	}
+	if failAt == 3 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteStructBegin("TestStruct").Return(err).After(last)
+	if failAt == 3 {
+		return true
+	}
+	if failAt == 4 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteFieldBegin("m", thrift.TType(thrift.MAP), int16(1)).Return(err).After(last)
+	if failAt == 4 {
+		return true
+	}
+	if failAt == 5 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteMapBegin(thrift.TType(thrift.STRING), thrift.TType(thrift.STRING), 0).Return(err).After(last)
+	if failAt == 5 {
+		return true
+	}
+	if failAt == 6 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteMapEnd().Return(err).After(last)
+	if failAt == 6 {
+		return true
+	}
+	if failAt == 7 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteFieldEnd().Return(err).After(last)
+	if failAt == 7 {
+		return true
+	}
+	if failAt == 8 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteFieldBegin("l", thrift.TType(thrift.LIST), int16(2)).Return(err).After(last)
+	if failAt == 8 {
+		return true
+	}
+	if failAt == 9 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteListBegin(thrift.TType(thrift.STRING), 0).Return(err).After(last)
+	if failAt == 9 {
+		return true
+	}
+	if failAt == 10 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteListEnd().Return(err).After(last)
+	if failAt == 10 {
+		return true
+	}
+	if failAt == 11 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteFieldEnd().Return(err).After(last)
+	if failAt == 11 {
+		return true
+	}
+	if failAt == 12 {
+		err = failWith
+	}
+
+	last = protocol.EXPECT().WriteFieldBegin("s", thrift.TType(thrift.SET), int16(3)).Return(err).After(last)
+	if failAt == 12 {
+		return true
+	}
+	if failAt == 13 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteSetBegin(thrift.TType(thrift.STRING), 0).Return(err).After(last)
+	if failAt == 13 {
+		return true
+	}
+	if failAt == 14 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteSetEnd().Return(err).After(last)
+	if failAt == 14 {
+		return true
+	}
+	if failAt == 15 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteFieldEnd().Return(err).After(last)
+	if failAt == 15 {
+		return true
+	}
+	if failAt == 16 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteFieldBegin("i", thrift.TType(thrift.I32), int16(4)).Return(err).After(last)
+	if failAt == 16 {
+		return true
+	}
+	if failAt == 17 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteI32(int32(3)).Return(err).After(last)
+	if failAt == 17 {
+		return true
+	}
+	if failAt == 18 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteFieldEnd().Return(err).After(last)
+	if failAt == 18 {
+		return true
+	}
+	if failAt == 19 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteFieldStop().Return(err).After(last)
+	if failAt == 19 {
+		return true
+	}
+	if failAt == 20 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteStructEnd().Return(err).After(last)
+	if failAt == 20 {
+		return true
+	}
+	if failAt == 21 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteFieldEnd().Return(err).After(last)
+	if failAt == 21 {
+		return true
+	}
+	if failAt == 22 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteFieldStop().Return(err).After(last)
+	if failAt == 22 {
+		return true
+	}
+	if failAt == 23 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteStructEnd().Return(err).After(last)
+	if failAt == 23 {
+		return true
+	}
+	if failAt == 24 {
+		err = failWith
+	}
+	last = protocol.EXPECT().WriteMessageEnd().Return(err).After(last)
+	if failAt == 24 {
+		return true
+	}
+	if failAt == 25 {
+		err = failWith
+	}
+	last = protocol.EXPECT().Flush(context.Background()).Return(err).After(last)
+	if failAt == 25 {
+		return true
+	}
+	if failAt == 26 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadMessageBegin().Return("testStruct", thrift.REPLY, int32(1), err).After(last)
+	if failAt == 26 {
+		return true
+	}
+	if failAt == 27 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadStructBegin().Return("testStruct_args", err).After(last)
+	if failAt == 27 {
+		return true
+	}
+	if failAt == 28 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldBegin().Return("_", thrift.TType(thrift.STRUCT), int16(0), err).After(last)
+	if failAt == 28 {
+		return true
+	}
+	if failAt == 29 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadStructBegin().Return("TestStruct", err).After(last)
+	if failAt == 29 {
+		return true
+	}
+	if failAt == 30 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldBegin().Return("m", thrift.TType(thrift.MAP), int16(1), err).After(last)
+	if failAt == 30 {
+		return true
+	}
+	if failAt == 31 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadMapBegin().Return(thrift.TType(thrift.STRING), thrift.TType(thrift.STRING), 0, err).After(last)
+	if failAt == 31 {
+		return true
+	}
+	if failAt == 32 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadMapEnd().Return(err).After(last)
+	if failAt == 32 {
+		return true
+	}
+	if failAt == 33 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldEnd().Return(err).After(last)
+	if failAt == 33 {
+		return true
+	}
+	if failAt == 34 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldBegin().Return("l", thrift.TType(thrift.LIST), int16(2), err).After(last)
+	if failAt == 34 {
+		return true
+	}
+	if failAt == 35 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadListBegin().Return(thrift.TType(thrift.STRING), 0, err).After(last)
+	if failAt == 35 {
+		return true
+	}
+	if failAt == 36 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadListEnd().Return(err).After(last)
+	if failAt == 36 {
+		return true
+	}
+	if failAt == 37 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldEnd().Return(err).After(last)
+	if failAt == 37 {
+		return true
+	}
+	if failAt == 38 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldBegin().Return("s", thrift.TType(thrift.SET), int16(3), err).After(last)
+	if failAt == 38 {
+		return true
+	}
+	if failAt == 39 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadSetBegin().Return(thrift.TType(thrift.STRING), 0, err).After(last)
+	if failAt == 39 {
+		return true
+	}
+	if failAt == 40 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadSetEnd().Return(err).After(last)
+	if failAt == 40 {
+		return true
+	}
+	if failAt == 41 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldEnd().Return(err).After(last)
+	if failAt == 41 {
+		return true
+	}
+	if failAt == 42 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldBegin().Return("i", thrift.TType(thrift.I32), int16(4), err).After(last)
+	if failAt == 42 {
+		return true
+	}
+	if failAt == 43 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadI32().Return(int32(3), err).After(last)
+	if failAt == 43 {
+		return true
+	}
+	if failAt == 44 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldEnd().Return(err).After(last)
+	if failAt == 44 {
+		return true
+	}
+	if failAt == 45 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldBegin().Return("_", thrift.TType(thrift.STOP), int16(5), err).After(last)
+	if failAt == 45 {
+		return true
+	}
+	if failAt == 46 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadStructEnd().Return(err).After(last)
+	if failAt == 46 {
+		return true
+	}
+	if failAt == 47 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldEnd().Return(err).After(last)
+	if failAt == 47 {
+		return true
+	}
+	if failAt == 48 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldBegin().Return("_", thrift.TType(thrift.STOP), int16(1), err).After(last)
+	if failAt == 48 {
+		return true
+	}
+	if failAt == 49 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadStructEnd().Return(err).After(last)
+	if failAt == 49 {
+		return true
+	}
+	if failAt == 50 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadMessageEnd().Return(err).After(last)
+	if failAt == 50 {
+		return true
+	}
+	return false
+}
+
+// TestCase: Comprehensive call and reply workflow in the client.
+// Expecting TTransportError on fail.
+func TestClientReportTTransportErrors(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+
+	thing := errortest.NewTestStruct()
+	thing.M = make(map[string]string)
+	thing.L = make([]string, 0)
+	thing.S = make([]string, 0)
+	thing.I = 3
+
+	err := thrift.NewTTransportException(thrift.TIMED_OUT, "test")
+	for i := 0; ; i++ {
+		protocol := NewMockTProtocol(mockCtrl)
+		if !prepareClientCallReply(protocol, i, err) {
+			return
+		}
+		client := errortest.NewErrorTestClient(thrift.NewTStandardClient(protocol, protocol))
+		_, retErr := client.TestStruct(defaultCtx, thing)
+		mockCtrl.Finish()
+		mockCtrl = gomock.NewController(t)
+		err2, ok := retErr.(thrift.TTransportException)
+		if !ok {
+			t.Fatal("Expected a TTrasportException")
+		}
+
+		if err2.TypeId() != thrift.TIMED_OUT {
+			t.Fatal("Expected TIMED_OUT error")
+		}
+	}
+}
+
+// TestCase: Comprehensive call and reply workflow in the client.
+// Expecting TTransportError on fail.
+// Similar to TestClientReportTTransportErrors, but using legacy client constructor.
+func TestClientReportTTransportErrorsLegacy(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	transport := thrift.NewTMemoryBuffer()
+	thing := errortest.NewTestStruct()
+	thing.M = make(map[string]string)
+	thing.L = make([]string, 0)
+	thing.S = make([]string, 0)
+	thing.I = 3
+
+	err := thrift.NewTTransportException(thrift.TIMED_OUT, "test")
+	for i := 0; ; i++ {
+		protocol := NewMockTProtocol(mockCtrl)
+		if !prepareClientCallReply(protocol, i, err) {
+			return
+		}
+		client := errortest.NewErrorTestClientProtocol(transport, protocol, protocol)
+		_, retErr := client.TestStruct(defaultCtx, thing)
+		mockCtrl.Finish()
+		mockCtrl = gomock.NewController(t)
+		err2, ok := retErr.(thrift.TTransportException)
+		if !ok {
+			t.Fatal("Expected a TTrasportException")
+		}
+
+		if err2.TypeId() != thrift.TIMED_OUT {
+			t.Fatal("Expected TIMED_OUT error")
+		}
+	}
+}
+
+// TestCase: Comprehensive call and reply workflow in the client.
+// Expecting TTProtocolErrors on fail.
+func TestClientReportTProtocolErrors(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+
+	thing := errortest.NewTestStruct()
+	thing.M = make(map[string]string)
+	thing.L = make([]string, 0)
+	thing.S = make([]string, 0)
+	thing.I = 3
+
+	err := thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, errors.New("test"))
+	for i := 0; ; i++ {
+		protocol := NewMockTProtocol(mockCtrl)
+		if !prepareClientCallReply(protocol, i, err) {
+			return
+		}
+		client := errortest.NewErrorTestClient(thrift.NewTStandardClient(protocol, protocol))
+		_, retErr := client.TestStruct(defaultCtx, thing)
+		mockCtrl.Finish()
+		mockCtrl = gomock.NewController(t)
+		err2, ok := retErr.(thrift.TProtocolException)
+		if !ok {
+			t.Fatal("Expected a TProtocolException")
+		}
+		if err2.TypeId() != thrift.INVALID_DATA {
+			t.Fatal("Expected INVALID_DATA error")
+		}
+	}
+}
+
+// TestCase: Comprehensive call and reply workflow in the client.
+// Expecting TTProtocolErrors on fail.
+// Similar to TestClientReportTProtocolErrors, but using legacy client constructor.
+func TestClientReportTProtocolErrorsLegacy(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	transport := thrift.NewTMemoryBuffer()
+	thing := errortest.NewTestStruct()
+	thing.M = make(map[string]string)
+	thing.L = make([]string, 0)
+	thing.S = make([]string, 0)
+	thing.I = 3
+
+	err := thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, errors.New("test"))
+	for i := 0; ; i++ {
+		protocol := NewMockTProtocol(mockCtrl)
+		if !prepareClientCallReply(protocol, i, err) {
+			return
+		}
+		client := errortest.NewErrorTestClientProtocol(transport, protocol, protocol)
+		_, retErr := client.TestStruct(defaultCtx, thing)
+		mockCtrl.Finish()
+		mockCtrl = gomock.NewController(t)
+		err2, ok := retErr.(thrift.TProtocolException)
+		if !ok {
+			t.Fatal("Expected a TProtocolException")
+		}
+		if err2.TypeId() != thrift.INVALID_DATA {
+			t.Fatal("Expected INVALID_DATA error")
+		}
+	}
+}
+
+// TestCase: call and reply with exception workflow in the client.
+// Setup mock to fail at a certain position. Return true if position exists otherwise false.
+func prepareClientCallException(protocol *MockTProtocol, failAt int, failWith error) bool {
+	var err error = nil
+
+	// No need to test failure in this block, because it is covered in other test cases
+	last := protocol.EXPECT().WriteMessageBegin("testString", thrift.CALL, int32(1))
+	last = protocol.EXPECT().WriteStructBegin("testString_args").After(last)
+	last = protocol.EXPECT().WriteFieldBegin("s", thrift.TType(thrift.STRING), int16(1)).After(last)
+	last = protocol.EXPECT().WriteString("test").After(last)
+	last = protocol.EXPECT().WriteFieldEnd().After(last)
+	last = protocol.EXPECT().WriteFieldStop().After(last)
+	last = protocol.EXPECT().WriteStructEnd().After(last)
+	last = protocol.EXPECT().WriteMessageEnd().After(last)
+	last = protocol.EXPECT().Flush(context.Background()).After(last)
+
+	// Reading the exception, might fail.
+	if failAt == 0 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadMessageBegin().Return("testString", thrift.EXCEPTION, int32(1), err).After(last)
+	if failAt == 0 {
+		return true
+	}
+	if failAt == 1 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadStructBegin().Return("TApplicationException", err).After(last)
+	if failAt == 1 {
+		return true
+	}
+	if failAt == 2 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldBegin().Return("message", thrift.TType(thrift.STRING), int16(1), err).After(last)
+	if failAt == 2 {
+		return true
+	}
+	if failAt == 3 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadString().Return("test", err).After(last)
+	if failAt == 3 {
+		return true
+	}
+	if failAt == 4 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldEnd().Return(err).After(last)
+	if failAt == 4 {
+		return true
+	}
+	if failAt == 5 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldBegin().Return("type", thrift.TType(thrift.I32), int16(2), err).After(last)
+	if failAt == 5 {
+		return true
+	}
+	if failAt == 6 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadI32().Return(int32(thrift.PROTOCOL_ERROR), err).After(last)
+	if failAt == 6 {
+		return true
+	}
+	if failAt == 7 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldEnd().Return(err).After(last)
+	if failAt == 7 {
+		return true
+	}
+	if failAt == 8 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadFieldBegin().Return("_", thrift.TType(thrift.STOP), int16(2), err).After(last)
+	if failAt == 8 {
+		return true
+	}
+	if failAt == 9 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadStructEnd().Return(err).After(last)
+	if failAt == 9 {
+		return true
+	}
+	if failAt == 10 {
+		err = failWith
+	}
+	last = protocol.EXPECT().ReadMessageEnd().Return(err).After(last)
+	if failAt == 10 {
+		return true
+	}
+
+	return false
+}
+
+// TestCase: call and reply with exception workflow in the client.
+func TestClientCallException(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+
+	err := thrift.NewTTransportException(thrift.TIMED_OUT, "test")
+	for i := 0; ; i++ {
+		protocol := NewMockTProtocol(mockCtrl)
+		willComplete := !prepareClientCallException(protocol, i, err)
+
+		client := errortest.NewErrorTestClient(thrift.NewTStandardClient(protocol, protocol))
+		_, retErr := client.TestString(defaultCtx, "test")
+		mockCtrl.Finish()
+		mockCtrl = gomock.NewController(t)
+
+		if !willComplete {
+			err2, ok := retErr.(thrift.TTransportException)
+			if !ok {
+				t.Fatal("Expected a TTransportException")
+			}
+			if err2.TypeId() != thrift.TIMED_OUT {
+				t.Fatal("Expected TIMED_OUT error")
+			}
+		} else {
+			err2, ok := retErr.(thrift.TApplicationException)
+			if !ok {
+				t.Fatal("Expected a TApplicationException")
+			}
+			if err2.TypeId() != thrift.PROTOCOL_ERROR {
+				t.Fatal("Expected PROTOCOL_ERROR error")
+			}
+			break
+		}
+	}
+}
+
+// TestCase: call and reply with exception workflow in the client.
+// Similar to TestClientCallException, but using legacy client constructor.
+func TestClientCallExceptionLegacy(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	transport := thrift.NewTMemoryBuffer()
+	err := thrift.NewTTransportException(thrift.TIMED_OUT, "test")
+	for i := 0; ; i++ {
+		protocol := NewMockTProtocol(mockCtrl)
+		willComplete := !prepareClientCallException(protocol, i, err)
+
+		client := errortest.NewErrorTestClientProtocol(transport, protocol, protocol)
+		_, retErr := client.TestString(defaultCtx, "test")
+		mockCtrl.Finish()
+		mockCtrl = gomock.NewController(t)
+
+		if !willComplete {
+			err2, ok := retErr.(thrift.TTransportException)
+			if !ok {
+				t.Fatal("Expected a TTransportException")
+			}
+			if err2.TypeId() != thrift.TIMED_OUT {
+				t.Fatal("Expected TIMED_OUT error")
+			}
+		} else {
+			err2, ok := retErr.(thrift.TApplicationException)
+			if !ok {
+				t.Fatal("Expected a TApplicationException")
+			}
+			if err2.TypeId() != thrift.PROTOCOL_ERROR {
+				t.Fatal("Expected PROTOCOL_ERROR error")
+			}
+			break
+		}
+	}
+}
+
+// TestCase: Mismatching sequence id has been received in the client.
+func TestClientSeqIdMismatch(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	protocol := NewMockTProtocol(mockCtrl)
+	gomock.InOrder(
+		protocol.EXPECT().WriteMessageBegin("testString", thrift.CALL, int32(1)),
+		protocol.EXPECT().WriteStructBegin("testString_args"),
+		protocol.EXPECT().WriteFieldBegin("s", thrift.TType(thrift.STRING), int16(1)),
+		protocol.EXPECT().WriteString("test"),
+		protocol.EXPECT().WriteFieldEnd(),
+		protocol.EXPECT().WriteFieldStop(),
+		protocol.EXPECT().WriteStructEnd(),
+		protocol.EXPECT().WriteMessageEnd(),
+		protocol.EXPECT().Flush(context.Background()),
+		protocol.EXPECT().ReadMessageBegin().Return("testString", thrift.REPLY, int32(2), nil),
+	)
+
+	client := errortest.NewErrorTestClient(thrift.NewTStandardClient(protocol, protocol))
+	_, err := client.TestString(defaultCtx, "test")
+	mockCtrl.Finish()
+	appErr, ok := err.(thrift.TApplicationException)
+	if !ok {
+		t.Fatal("Expected TApplicationException")
+	}
+	if appErr.TypeId() != thrift.BAD_SEQUENCE_ID {
+		t.Fatal("Expected BAD_SEQUENCE_ID error")
+	}
+}
+
+// TestCase: Mismatching sequence id has been received in the client.
+// Similar to TestClientSeqIdMismatch, but using legacy client constructor.
+func TestClientSeqIdMismatchLegeacy(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	transport := thrift.NewTMemoryBuffer()
+	protocol := NewMockTProtocol(mockCtrl)
+	gomock.InOrder(
+		protocol.EXPECT().WriteMessageBegin("testString", thrift.CALL, int32(1)),
+		protocol.EXPECT().WriteStructBegin("testString_args"),
+		protocol.EXPECT().WriteFieldBegin("s", thrift.TType(thrift.STRING), int16(1)),
+		protocol.EXPECT().WriteString("test"),
+		protocol.EXPECT().WriteFieldEnd(),
+		protocol.EXPECT().WriteFieldStop(),
+		protocol.EXPECT().WriteStructEnd(),
+		protocol.EXPECT().WriteMessageEnd(),
+		protocol.EXPECT().Flush(context.Background()),
+		protocol.EXPECT().ReadMessageBegin().Return("testString", thrift.REPLY, int32(2), nil),
+	)
+
+	client := errortest.NewErrorTestClientProtocol(transport, protocol, protocol)
+	_, err := client.TestString(defaultCtx, "test")
+	mockCtrl.Finish()
+	appErr, ok := err.(thrift.TApplicationException)
+	if !ok {
+		t.Fatal("Expected TApplicationException")
+	}
+	if appErr.TypeId() != thrift.BAD_SEQUENCE_ID {
+		t.Fatal("Expected BAD_SEQUENCE_ID error")
+	}
+}
+
+// TestCase: Wrong method name has been received in the client.
+func TestClientWrongMethodName(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	protocol := NewMockTProtocol(mockCtrl)
+	gomock.InOrder(
+		protocol.EXPECT().WriteMessageBegin("testString", thrift.CALL, int32(1)),
+		protocol.EXPECT().WriteStructBegin("testString_args"),
+		protocol.EXPECT().WriteFieldBegin("s", thrift.TType(thrift.STRING), int16(1)),
+		protocol.EXPECT().WriteString("test"),
+		protocol.EXPECT().WriteFieldEnd(),
+		protocol.EXPECT().WriteFieldStop(),
+		protocol.EXPECT().WriteStructEnd(),
+		protocol.EXPECT().WriteMessageEnd(),
+		protocol.EXPECT().Flush(context.Background()),
+		protocol.EXPECT().ReadMessageBegin().Return("unknown", thrift.REPLY, int32(1), nil),
+	)
+
+	client := errortest.NewErrorTestClient(thrift.NewTStandardClient(protocol, protocol))
+	_, err := client.TestString(defaultCtx, "test")
+	mockCtrl.Finish()
+	appErr, ok := err.(thrift.TApplicationException)
+	if !ok {
+		t.Fatal("Expected TApplicationException")
+	}
+	if appErr.TypeId() != thrift.WRONG_METHOD_NAME {
+		t.Fatal("Expected WRONG_METHOD_NAME error")
+	}
+}
+
+// TestCase: Wrong method name has been received in the client.
+// Similar to TestClientWrongMethodName, but using legacy client constructor.
+func TestClientWrongMethodNameLegacy(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	transport := thrift.NewTMemoryBuffer()
+	protocol := NewMockTProtocol(mockCtrl)
+	gomock.InOrder(
+		protocol.EXPECT().WriteMessageBegin("testString", thrift.CALL, int32(1)),
+		protocol.EXPECT().WriteStructBegin("testString_args"),
+		protocol.EXPECT().WriteFieldBegin("s", thrift.TType(thrift.STRING), int16(1)),
+		protocol.EXPECT().WriteString("test"),
+		protocol.EXPECT().WriteFieldEnd(),
+		protocol.EXPECT().WriteFieldStop(),
+		protocol.EXPECT().WriteStructEnd(),
+		protocol.EXPECT().WriteMessageEnd(),
+		protocol.EXPECT().Flush(context.Background()),
+		protocol.EXPECT().ReadMessageBegin().Return("unknown", thrift.REPLY, int32(1), nil),
+	)
+
+	client := errortest.NewErrorTestClientProtocol(transport, protocol, protocol)
+	_, err := client.TestString(defaultCtx, "test")
+	mockCtrl.Finish()
+	appErr, ok := err.(thrift.TApplicationException)
+	if !ok {
+		t.Fatal("Expected TApplicationException")
+	}
+	if appErr.TypeId() != thrift.WRONG_METHOD_NAME {
+		t.Fatal("Expected WRONG_METHOD_NAME error")
+	}
+}
+
+// TestCase: Wrong message type has been received in the client.
+func TestClientWrongMessageType(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	protocol := NewMockTProtocol(mockCtrl)
+	gomock.InOrder(
+		protocol.EXPECT().WriteMessageBegin("testString", thrift.CALL, int32(1)),
+		protocol.EXPECT().WriteStructBegin("testString_args"),
+		protocol.EXPECT().WriteFieldBegin("s", thrift.TType(thrift.STRING), int16(1)),
+		protocol.EXPECT().WriteString("test"),
+		protocol.EXPECT().WriteFieldEnd(),
+		protocol.EXPECT().WriteFieldStop(),
+		protocol.EXPECT().WriteStructEnd(),
+		protocol.EXPECT().WriteMessageEnd(),
+		protocol.EXPECT().Flush(context.Background()),
+		protocol.EXPECT().ReadMessageBegin().Return("testString", thrift.INVALID_TMESSAGE_TYPE, int32(1), nil),
+	)
+
+	client := errortest.NewErrorTestClient(thrift.NewTStandardClient(protocol, protocol))
+	_, err := client.TestString(defaultCtx, "test")
+	mockCtrl.Finish()
+	appErr, ok := err.(thrift.TApplicationException)
+	if !ok {
+		t.Fatal("Expected TApplicationException")
+	}
+	if appErr.TypeId() != thrift.INVALID_MESSAGE_TYPE_EXCEPTION {
+		t.Fatal("Expected INVALID_MESSAGE_TYPE_EXCEPTION error")
+	}
+}
+
+// TestCase: Wrong message type has been received in the client.
+// Similar to TestClientWrongMessageType, but using legacy client constructor.
+func TestClientWrongMessageTypeLegacy(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	transport := thrift.NewTMemoryBuffer()
+	protocol := NewMockTProtocol(mockCtrl)
+	gomock.InOrder(
+		protocol.EXPECT().WriteMessageBegin("testString", thrift.CALL, int32(1)),
+		protocol.EXPECT().WriteStructBegin("testString_args"),
+		protocol.EXPECT().WriteFieldBegin("s", thrift.TType(thrift.STRING), int16(1)),
+		protocol.EXPECT().WriteString("test"),
+		protocol.EXPECT().WriteFieldEnd(),
+		protocol.EXPECT().WriteFieldStop(),
+		protocol.EXPECT().WriteStructEnd(),
+		protocol.EXPECT().WriteMessageEnd(),
+		protocol.EXPECT().Flush(context.Background()),
+		protocol.EXPECT().ReadMessageBegin().Return("testString", thrift.INVALID_TMESSAGE_TYPE, int32(1), nil),
+	)
+
+	client := errortest.NewErrorTestClientProtocol(transport, protocol, protocol)
+	_, err := client.TestString(defaultCtx, "test")
+	mockCtrl.Finish()
+	appErr, ok := err.(thrift.TApplicationException)
+	if !ok {
+		t.Fatal("Expected TApplicationException")
+	}
+	if appErr.TypeId() != thrift.INVALID_MESSAGE_TYPE_EXCEPTION {
+		t.Fatal("Expected INVALID_MESSAGE_TYPE_EXCEPTION error")
+	}
+}
diff --git a/lib/go/test/tests/context.go b/lib/go/test/tests/context.go
new file mode 100644
index 0000000..a93a82b
--- /dev/null
+++ b/lib/go/test/tests/context.go
@@ -0,0 +1,26 @@
+/*
+ * 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 tests
+
+import (
+	"context"
+)
+
+var defaultCtx = context.Background()
diff --git a/lib/go/test/tests/encoding_json_test.go b/lib/go/test/tests/encoding_json_test.go
new file mode 100644
index 0000000..12d4566
--- /dev/null
+++ b/lib/go/test/tests/encoding_json_test.go
@@ -0,0 +1,79 @@
+/*
+ * 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 tests
+
+import (
+	"encoding"
+	"encoding/json"
+	"testing"
+	"thrifttest"
+)
+
+func TestEnumIsTextMarshaller(t *testing.T) {
+	one := thrifttest.Numberz_ONE
+	var tm encoding.TextMarshaler = one
+	b, err := tm.MarshalText()
+	if err != nil {
+		t.Fatalf("Unexpected error from MarshalText: %s", err)
+	}
+	if string(b) != one.String() {
+		t.Errorf("MarshalText(%s) = %s, expected = %s", one, b, one)
+	}
+}
+
+func TestEnumIsTextUnmarshaller(t *testing.T) {
+	var tm encoding.TextUnmarshaler = thrifttest.NumberzPtr(thrifttest.Numberz_TWO)
+	err := tm.UnmarshalText([]byte("TWO"))
+	if err != nil {
+		t.Fatalf("Unexpected error from UnmarshalText(TWO): %s", err)
+	}
+	if *(tm.(*thrifttest.Numberz)) != thrifttest.Numberz_TWO {
+		t.Errorf("UnmarshalText(TWO) = %s", tm)
+	}
+
+	err = tm.UnmarshalText([]byte("NAN"))
+	if err == nil {
+		t.Errorf("Error from UnmarshalText(NAN)")
+	}
+}
+
+func TestJSONMarshalUnmarshal(t *testing.T) {
+	s1 := thrifttest.StructB{
+		Aa: &thrifttest.StructA{S: "Aa"},
+		Ab: &thrifttest.StructA{S: "Ab"},
+	}
+
+	b, err := json.Marshal(s1)
+	if err != nil {
+		t.Fatalf("Unexpected error from json.Marshal: %s", err)
+	}
+
+	s2 := thrifttest.StructB{}
+	err = json.Unmarshal(b, &s2)
+	if err != nil {
+		t.Fatalf("Unexpected error from json.Unmarshal: %s", err)
+	}
+
+	if *s1.Aa != *s2.Aa || *s1.Ab != *s2.Ab {
+		t.Logf("s1 = %+v", s1)
+		t.Logf("s2 = %+v", s2)
+		t.Errorf("json: Unmarshal(Marshal(s)) != s")
+	}
+}
diff --git a/lib/go/test/tests/gotag_test.go b/lib/go/test/tests/gotag_test.go
new file mode 100644
index 0000000..32f056f
--- /dev/null
+++ b/lib/go/test/tests/gotag_test.go
@@ -0,0 +1,53 @@
+/*
+ * 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 tests
+
+import (
+	"gotagtest"
+	"reflect"
+	"testing"
+)
+
+func TestDefaultTag(t *testing.T) {
+	s := gotagtest.Tagged{}
+	st := reflect.TypeOf(s)
+	field, ok := st.FieldByName("StringThing")
+	if !ok || field.Tag.Get("json") != "string_thing" {
+		t.Error("Unexpected default tag value")
+	}
+}
+
+func TestCustomTag(t *testing.T) {
+	s := gotagtest.Tagged{}
+	st := reflect.TypeOf(s)
+	field, ok := st.FieldByName("IntThing")
+	if !ok || field.Tag.Get("json") != "int_thing,string" {
+		t.Error("Unexpected custom tag value")
+	}
+}
+
+func TestOptionalTag(t *testing.T) {
+	s := gotagtest.Tagged{}
+	st := reflect.TypeOf(s)
+	field, ok := st.FieldByName("OptionalIntThing")
+	if !ok || field.Tag.Get("json") != "optional_int_thing,omitempty" {
+		t.Error("Unexpected default tag value for optional field")
+	}
+}
diff --git a/lib/go/test/tests/ignoreinitialisms_test.go b/lib/go/test/tests/ignoreinitialisms_test.go
new file mode 100644
index 0000000..3cd5f65
--- /dev/null
+++ b/lib/go/test/tests/ignoreinitialisms_test.go
@@ -0,0 +1,51 @@
+/*
+ * 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 tests
+
+import (
+	"ignoreinitialismstest"
+	"reflect"
+	"testing"
+)
+
+func TestIgnoreInitialismsFlagIsHonoured(t *testing.T) {
+	s := ignoreinitialismstest.IgnoreInitialismsTest{}
+	st := reflect.TypeOf(s)
+	_, ok := st.FieldByName("Id")
+	if !ok {
+		t.Error("Id attribute is missing!")
+	}
+	_, ok = st.FieldByName("MyId")
+	if !ok {
+		t.Error("MyId attribute is missing!")
+	}
+	_, ok = st.FieldByName("NumCpu")
+	if !ok {
+		t.Error("NumCpu attribute is missing!")
+	}
+	_, ok = st.FieldByName("NumGpu")
+	if !ok {
+		t.Error("NumGpu attribute is missing!")
+	}
+	_, ok = st.FieldByName("My_ID")
+	if !ok {
+		t.Error("My_ID attribute is missing!")
+	}
+}
diff --git a/lib/go/test/tests/initialisms_test.go b/lib/go/test/tests/initialisms_test.go
new file mode 100644
index 0000000..40923d2
--- /dev/null
+++ b/lib/go/test/tests/initialisms_test.go
@@ -0,0 +1,43 @@
+/*
+ * 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 tests
+
+import (
+	"initialismstest"
+	"reflect"
+	"testing"
+)
+
+func TestThatCommonInitialismsAreFixed(t *testing.T) {
+	s := initialismstest.InitialismsTest{}
+	st := reflect.TypeOf(s)
+	_, ok := st.FieldByName("UserID")
+	if !ok {
+		t.Error("UserID attribute is missing!")
+	}
+	_, ok = st.FieldByName("ServerURL")
+	if !ok {
+		t.Error("ServerURL attribute is missing!")
+	}
+	_, ok = st.FieldByName("ID")
+	if !ok {
+		t.Error("ID attribute is missing!")
+	}
+}
diff --git a/lib/go/test/tests/multiplexed_protocol_test.go b/lib/go/test/tests/multiplexed_protocol_test.go
new file mode 100644
index 0000000..61ac628
--- /dev/null
+++ b/lib/go/test/tests/multiplexed_protocol_test.go
@@ -0,0 +1,197 @@
+/*
+ * 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 tests
+
+import (
+	"context"
+	"multiplexedprotocoltest"
+	"net"
+	"testing"
+	"thrift"
+	"time"
+)
+
+func FindAvailableTCPServerPort() net.Addr {
+	if l, err := net.Listen("tcp", "127.0.0.1:0"); err != nil {
+		panic("Could not find available server port")
+	} else {
+		defer l.Close()
+		return l.Addr()
+	}
+}
+
+type FirstImpl struct{}
+
+func (f *FirstImpl) ReturnOne(ctx context.Context) (r int64, err error) {
+	return 1, nil
+}
+
+type SecondImpl struct{}
+
+func (s *SecondImpl) ReturnTwo(ctx context.Context) (r int64, err error) {
+	return 2, nil
+}
+
+func createTransport(addr net.Addr) (thrift.TTransport, error) {
+	socket := thrift.NewTSocketFromAddrTimeout(addr, TIMEOUT)
+	transport := thrift.NewTFramedTransport(socket)
+	err := transport.Open()
+	if err != nil {
+		return nil, err
+	}
+	return transport, nil
+}
+
+func TestMultiplexedProtocolFirst(t *testing.T) {
+	processor := thrift.NewTMultiplexedProcessor()
+	protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
+	transportFactory := thrift.NewTTransportFactory()
+	transportFactory = thrift.NewTFramedTransportFactory(transportFactory)
+	addr := FindAvailableTCPServerPort()
+	serverTransport, err := thrift.NewTServerSocketTimeout(addr.String(), TIMEOUT)
+	if err != nil {
+		t.Fatal("Unable to create server socket", err)
+	}
+	server = thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
+
+	firstProcessor := multiplexedprotocoltest.NewFirstProcessor(&FirstImpl{})
+	processor.RegisterProcessor("FirstService", firstProcessor)
+
+	secondProcessor := multiplexedprotocoltest.NewSecondProcessor(&SecondImpl{})
+	processor.RegisterProcessor("SecondService", secondProcessor)
+
+	defer server.Stop()
+	go server.Serve()
+	time.Sleep(10 * time.Millisecond)
+
+	transport, err := createTransport(addr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer transport.Close()
+	protocol := thrift.NewTMultiplexedProtocol(thrift.NewTBinaryProtocolTransport(transport), "FirstService")
+
+	client := multiplexedprotocoltest.NewFirstClient(thrift.NewTStandardClient(protocol, protocol))
+
+	ret, err := client.ReturnOne(defaultCtx)
+	if err != nil {
+		t.Fatal("Unable to call first server:", err)
+	} else if ret != 1 {
+		t.Fatal("Unexpected result from server: ", ret)
+	}
+}
+
+func TestMultiplexedProtocolSecond(t *testing.T) {
+	processor := thrift.NewTMultiplexedProcessor()
+	protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
+	transportFactory := thrift.NewTTransportFactory()
+	transportFactory = thrift.NewTFramedTransportFactory(transportFactory)
+	addr := FindAvailableTCPServerPort()
+	serverTransport, err := thrift.NewTServerSocketTimeout(addr.String(), TIMEOUT)
+	if err != nil {
+		t.Fatal("Unable to create server socket", err)
+	}
+	server = thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
+
+	firstProcessor := multiplexedprotocoltest.NewFirstProcessor(&FirstImpl{})
+	processor.RegisterProcessor("FirstService", firstProcessor)
+
+	secondProcessor := multiplexedprotocoltest.NewSecondProcessor(&SecondImpl{})
+	processor.RegisterProcessor("SecondService", secondProcessor)
+
+	defer server.Stop()
+	go server.Serve()
+	time.Sleep(10 * time.Millisecond)
+
+	transport, err := createTransport(addr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer transport.Close()
+	protocol := thrift.NewTMultiplexedProtocol(thrift.NewTBinaryProtocolTransport(transport), "SecondService")
+
+	client := multiplexedprotocoltest.NewSecondClient(thrift.NewTStandardClient(protocol, protocol))
+
+	ret, err := client.ReturnTwo(defaultCtx)
+	if err != nil {
+		t.Fatal("Unable to call second server:", err)
+	} else if ret != 2 {
+		t.Fatal("Unexpected result from server: ", ret)
+	}
+}
+
+func TestMultiplexedProtocolLegacy(t *testing.T) {
+	processor := thrift.NewTMultiplexedProcessor()
+	protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
+	transportFactory := thrift.NewTTransportFactory()
+	transportFactory = thrift.NewTFramedTransportFactory(transportFactory)
+	addr := FindAvailableTCPServerPort()
+	serverTransport, err := thrift.NewTServerSocketTimeout(addr.String(), TIMEOUT)
+	if err != nil {
+		t.Fatal("Unable to create server socket", err)
+	}
+	server = thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
+
+	firstProcessor := multiplexedprotocoltest.NewFirstProcessor(&FirstImpl{})
+	processor.RegisterProcessor("FirstService", firstProcessor)
+
+	secondProcessor := multiplexedprotocoltest.NewSecondProcessor(&SecondImpl{})
+	processor.RegisterProcessor("SecondService", secondProcessor)
+
+	defer server.Stop()
+	go server.Serve()
+	time.Sleep(10 * time.Millisecond)
+
+	transport, err := createTransport(addr)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	defer transport.Close()
+
+	protocol := thrift.NewTBinaryProtocolTransport(transport)
+	client := multiplexedprotocoltest.NewSecondClient(thrift.NewTStandardClient(protocol, protocol))
+
+	ret, err := client.ReturnTwo(defaultCtx)
+	//expect error since default processor is not registered
+	if err == nil {
+		t.Fatal("Expecting error")
+	}
+
+	//register default processor and call again
+	processor.RegisterDefault(multiplexedprotocoltest.NewSecondProcessor(&SecondImpl{}))
+	transport, err = createTransport(addr)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	defer transport.Close()
+
+	protocol = thrift.NewTBinaryProtocolTransport(transport)
+	client = multiplexedprotocoltest.NewSecondClient(thrift.NewTStandardClient(protocol, protocol))
+
+	ret, err = client.ReturnTwo(defaultCtx)
+	if err != nil {
+		t.Fatal("Unable to call legacy server:", err)
+	}
+	if ret != 2 {
+		t.Fatal("Unexpected result from server: ", ret)
+	}
+}
diff --git a/lib/go/test/tests/names_test.go b/lib/go/test/tests/names_test.go
new file mode 100644
index 0000000..90b63a3
--- /dev/null
+++ b/lib/go/test/tests/names_test.go
@@ -0,0 +1,35 @@
+/*
+ * 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 tests
+
+import (
+	"namestest"
+	"reflect"
+	"testing"
+)
+
+func TestThatAttributeNameSubstituionDoesNotOccur(t *testing.T) {
+	s := namestest.NamesTest{}
+	st := reflect.TypeOf(s)
+	_, ok := st.FieldByName("Type")
+	if !ok {
+		t.Error("Type attribute is missing!")
+	}
+}
diff --git a/lib/go/test/tests/one_way_test.go b/lib/go/test/tests/one_way_test.go
new file mode 100644
index 0000000..48d0bbe
--- /dev/null
+++ b/lib/go/test/tests/one_way_test.go
@@ -0,0 +1,91 @@
+/*
+ * 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 tests
+
+import (
+	"context"
+	"fmt"
+	"net"
+	"onewaytest"
+	"testing"
+	"thrift"
+	"time"
+)
+
+func findPort() net.Addr {
+	if l, err := net.Listen("tcp", "127.0.0.1:0"); err != nil {
+		panic("Could not find available server port")
+	} else {
+		defer l.Close()
+		return l.Addr()
+	}
+}
+
+type impl struct{}
+
+func (i *impl) Hi(ctx context.Context, in int64, s string) (err error)        { fmt.Println("Hi!"); return }
+func (i *impl) Emptyfunc(ctx context.Context) (err error)                     { return }
+func (i *impl) EchoInt(ctx context.Context, param int64) (r int64, err error) { return param, nil }
+
+const TIMEOUT = time.Second
+
+var addr net.Addr
+var server *thrift.TSimpleServer
+var client *onewaytest.OneWayClient
+
+func TestInitOneway(t *testing.T) {
+	var err error
+	addr = findPort()
+	serverTransport, err := thrift.NewTServerSocketTimeout(addr.String(), TIMEOUT)
+	if err != nil {
+		t.Fatal("Unable to create server socket", err)
+	}
+	processor := onewaytest.NewOneWayProcessor(&impl{})
+	server = thrift.NewTSimpleServer2(processor, serverTransport)
+
+	go server.Serve()
+	time.Sleep(10 * time.Millisecond)
+}
+
+func TestInitOnewayClient(t *testing.T) {
+	transport := thrift.NewTSocketFromAddrTimeout(addr, TIMEOUT)
+	protocol := thrift.NewTBinaryProtocolTransport(transport)
+	client = onewaytest.NewOneWayClient(thrift.NewTStandardClient(protocol, protocol))
+	err := transport.Open()
+	if err != nil {
+		t.Fatal("Unable to open client socket", err)
+	}
+}
+
+func TestCallOnewayServer(t *testing.T) {
+	//call oneway function
+	err := client.Hi(defaultCtx, 1, "")
+	if err != nil {
+		t.Fatal("Unexpected error: ", err)
+	}
+	//There is no way to detect protocol problems with single oneway call so we call it second time
+	i, err := client.EchoInt(defaultCtx, 42)
+	if err != nil {
+		t.Fatal("Unexpected error: ", err)
+	}
+	if i != 42 {
+		t.Fatal("Unexpected returned value: ", i)
+	}
+}
diff --git a/lib/go/test/tests/optional_fields_test.go b/lib/go/test/tests/optional_fields_test.go
new file mode 100644
index 0000000..34ad660
--- /dev/null
+++ b/lib/go/test/tests/optional_fields_test.go
@@ -0,0 +1,280 @@
+/*
+ * 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 tests
+
+import (
+	"bytes"
+	gomock "github.com/golang/mock/gomock"
+	"optionalfieldstest"
+	"testing"
+	"thrift"
+)
+
+func TestIsSetReturnFalseOnCreation(t *testing.T) {
+	ao := optionalfieldstest.NewAllOptional()
+	if ao.IsSetS() {
+		t.Errorf("Optional field S is set on initialization")
+	}
+	if ao.IsSetI() {
+		t.Errorf("Optional field I is set on initialization")
+	}
+	if ao.IsSetB() {
+		t.Errorf("Optional field B is set on initialization")
+	}
+	if ao.IsSetS2() {
+		t.Errorf("Optional field S2 is set on initialization")
+	}
+	if ao.IsSetI2() {
+		t.Errorf("Optional field I2 is set on initialization")
+	}
+	if ao.IsSetB2() {
+		t.Errorf("Optional field B2 is set on initialization")
+	}
+	if ao.IsSetAa() {
+		t.Errorf("Optional field Aa is set on initialization")
+	}
+	if ao.IsSetL() {
+		t.Errorf("Optional field L is set on initialization")
+	}
+	if ao.IsSetL2() {
+		t.Errorf("Optional field L2 is set on initialization")
+	}
+	if ao.IsSetM() {
+		t.Errorf("Optional field M is set on initialization")
+	}
+	if ao.IsSetM2() {
+		t.Errorf("Optional field M2 is set on initialization")
+	}
+	if ao.IsSetBin() {
+		t.Errorf("Optional field Bin is set on initialization")
+	}
+	if ao.IsSetBin2() {
+		t.Errorf("Optional field Bin2 is set on initialization")
+	}
+}
+
+func TestDefaultValuesOnCreation(t *testing.T) {
+	ao := optionalfieldstest.NewAllOptional()
+	if ao.GetS() != "DEFAULT" {
+		t.Errorf("Unexpected default value %#v for field S", ao.GetS())
+	}
+	if ao.GetI() != 42 {
+		t.Errorf("Unexpected default value %#v for field I", ao.GetI())
+	}
+	if ao.GetB() != false {
+		t.Errorf("Unexpected default value %#v for field B", ao.GetB())
+	}
+	if ao.GetS2() != "" {
+		t.Errorf("Unexpected default value %#v for field S2", ao.GetS2())
+	}
+	if ao.GetI2() != 0 {
+		t.Errorf("Unexpected default value %#v for field I2", ao.GetI2())
+	}
+	if ao.GetB2() != false {
+		t.Errorf("Unexpected default value %#v for field B2", ao.GetB2())
+	}
+	if l := ao.GetL(); len(l) != 0 {
+		t.Errorf("Unexpected default value %#v for field L", l)
+	}
+	if l := ao.GetL2(); len(l) != 2 || l[0] != 1 || l[1] != 2 {
+		t.Errorf("Unexpected default value %#v for field L2", l)
+	}
+	//FIXME: should we return empty map here?
+	if m := ao.GetM(); m != nil {
+		t.Errorf("Unexpected default value %#v for field M", m)
+	}
+	if m := ao.GetM2(); len(m) != 2 || m[1] != 2 || m[3] != 4 {
+		t.Errorf("Unexpected default value %#v for field M2", m)
+	}
+	if bv := ao.GetBin(); bv != nil {
+		t.Errorf("Unexpected default value %#v for field Bin", bv)
+	}
+	if bv := ao.GetBin2(); !bytes.Equal(bv, []byte("asdf")) {
+		t.Errorf("Unexpected default value %#v for field Bin2", bv)
+	}
+}
+
+func TestInitialValuesOnCreation(t *testing.T) {
+	ao := optionalfieldstest.NewAllOptional()
+	if ao.S != "DEFAULT" {
+		t.Errorf("Unexpected initial value %#v for field S", ao.S)
+	}
+	if ao.I != 42 {
+		t.Errorf("Unexpected initial value %#v for field I", ao.I)
+	}
+	if ao.B != false {
+		t.Errorf("Unexpected initial value %#v for field B", ao.B)
+	}
+	if ao.S2 != nil {
+		t.Errorf("Unexpected initial value %#v for field S2", ao.S2)
+	}
+	if ao.I2 != nil {
+		t.Errorf("Unexpected initial value %#v for field I2", ao.I2)
+	}
+	if ao.B2 != nil {
+		t.Errorf("Unexpected initial value %#v for field B2", ao.B2)
+	}
+	if ao.L != nil || len(ao.L) != 0 {
+		t.Errorf("Unexpected initial value %#v for field L", ao.L)
+	}
+	if ao.L2 != nil {
+		t.Errorf("Unexpected initial value %#v for field L2", ao.L2)
+	}
+	if ao.M != nil {
+		t.Errorf("Unexpected initial value %#v for field M", ao.M)
+	}
+	if ao.M2 != nil {
+		t.Errorf("Unexpected initial value %#v for field M2", ao.M2)
+	}
+	if ao.Bin != nil || len(ao.Bin) != 0 {
+		t.Errorf("Unexpected initial value %#v for field Bin", ao.Bin)
+	}
+	if !bytes.Equal(ao.Bin2, []byte("asdf")) {
+		t.Errorf("Unexpected initial value %#v for field Bin2", ao.Bin2)
+	}
+}
+
+func TestIsSetReturnTrueAfterUpdate(t *testing.T) {
+	ao := optionalfieldstest.NewAllOptional()
+	ao.S = "somevalue"
+	ao.I = 123
+	ao.B = true
+	ao.Aa = optionalfieldstest.NewStructA()
+	if !ao.IsSetS() {
+		t.Errorf("Field S should be set")
+	}
+	if !ao.IsSetI() {
+		t.Errorf("Field I should be set")
+	}
+	if !ao.IsSetB() {
+		t.Errorf("Field B should be set")
+	}
+	if !ao.IsSetAa() {
+		t.Errorf("Field aa should be set")
+	}
+}
+
+func TestListNotEmpty(t *testing.T) {
+	ao := optionalfieldstest.NewAllOptional()
+	ao.L = []int64{1, 2, 3}
+	if !ao.IsSetL() {
+		t.Errorf("Field L should be set")
+	}
+}
+
+//Make sure that optional fields are not being serialized
+func TestNoOptionalUnsetFieldsOnWire(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	defer mockCtrl.Finish()
+	proto := NewMockTProtocol(mockCtrl)
+	gomock.InOrder(
+		proto.EXPECT().WriteStructBegin("all_optional").Return(nil),
+		proto.EXPECT().WriteFieldStop().Return(nil),
+		proto.EXPECT().WriteStructEnd().Return(nil),
+	)
+	ao := optionalfieldstest.NewAllOptional()
+	ao.Write(proto)
+}
+
+func TestNoSetToDefaultFieldsOnWire(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	defer mockCtrl.Finish()
+	proto := NewMockTProtocol(mockCtrl)
+	gomock.InOrder(
+		proto.EXPECT().WriteStructBegin("all_optional").Return(nil),
+		proto.EXPECT().WriteFieldStop().Return(nil),
+		proto.EXPECT().WriteStructEnd().Return(nil),
+	)
+	ao := optionalfieldstest.NewAllOptional()
+	ao.I = 42
+	ao.Write(proto)
+}
+
+//Make sure that only one field is being serialized when set to non-default
+func TestOneISetFieldOnWire(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	defer mockCtrl.Finish()
+	proto := NewMockTProtocol(mockCtrl)
+	gomock.InOrder(
+		proto.EXPECT().WriteStructBegin("all_optional").Return(nil),
+		proto.EXPECT().WriteFieldBegin("i", thrift.TType(thrift.I64), int16(2)).Return(nil),
+		proto.EXPECT().WriteI64(int64(123)).Return(nil),
+		proto.EXPECT().WriteFieldEnd().Return(nil),
+		proto.EXPECT().WriteFieldStop().Return(nil),
+		proto.EXPECT().WriteStructEnd().Return(nil),
+	)
+	ao := optionalfieldstest.NewAllOptional()
+	ao.I = 123
+	ao.Write(proto)
+}
+
+func TestOneLSetFieldOnWire(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	defer mockCtrl.Finish()
+	proto := NewMockTProtocol(mockCtrl)
+	gomock.InOrder(
+		proto.EXPECT().WriteStructBegin("all_optional").Return(nil),
+		proto.EXPECT().WriteFieldBegin("l", thrift.TType(thrift.LIST), int16(9)).Return(nil),
+		proto.EXPECT().WriteListBegin(thrift.TType(thrift.I64), 2).Return(nil),
+		proto.EXPECT().WriteI64(int64(1)).Return(nil),
+		proto.EXPECT().WriteI64(int64(2)).Return(nil),
+		proto.EXPECT().WriteListEnd().Return(nil),
+		proto.EXPECT().WriteFieldEnd().Return(nil),
+		proto.EXPECT().WriteFieldStop().Return(nil),
+		proto.EXPECT().WriteStructEnd().Return(nil),
+	)
+	ao := optionalfieldstest.NewAllOptional()
+	ao.L = []int64{1, 2}
+	ao.Write(proto)
+}
+
+func TestOneBinSetFieldOnWire(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	defer mockCtrl.Finish()
+	proto := NewMockTProtocol(mockCtrl)
+	gomock.InOrder(
+		proto.EXPECT().WriteStructBegin("all_optional").Return(nil),
+		proto.EXPECT().WriteFieldBegin("bin", thrift.TType(thrift.STRING), int16(13)).Return(nil),
+		proto.EXPECT().WriteBinary([]byte("somebytestring")).Return(nil),
+		proto.EXPECT().WriteFieldEnd().Return(nil),
+		proto.EXPECT().WriteFieldStop().Return(nil),
+		proto.EXPECT().WriteStructEnd().Return(nil),
+	)
+	ao := optionalfieldstest.NewAllOptional()
+	ao.Bin = []byte("somebytestring")
+	ao.Write(proto)
+}
+
+func TestOneEmptyBinSetFieldOnWire(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	defer mockCtrl.Finish()
+	proto := NewMockTProtocol(mockCtrl)
+	gomock.InOrder(
+		proto.EXPECT().WriteStructBegin("all_optional").Return(nil),
+		proto.EXPECT().WriteFieldBegin("bin", thrift.TType(thrift.STRING), int16(13)).Return(nil),
+		proto.EXPECT().WriteBinary([]byte{}).Return(nil),
+		proto.EXPECT().WriteFieldEnd().Return(nil),
+		proto.EXPECT().WriteFieldStop().Return(nil),
+		proto.EXPECT().WriteStructEnd().Return(nil),
+	)
+	ao := optionalfieldstest.NewAllOptional()
+	ao.Bin = []byte{}
+	ao.Write(proto)
+}
diff --git a/lib/go/test/tests/protocol_mock.go b/lib/go/test/tests/protocol_mock.go
new file mode 100644
index 0000000..51d7a02
--- /dev/null
+++ b/lib/go/test/tests/protocol_mock.go
@@ -0,0 +1,513 @@
+/*
+ * 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.
+ */
+
+// Automatically generated by MockGen. DO NOT EDIT!
+// Source: thrift (interfaces: TProtocol)
+
+package tests
+
+import (
+	"context"
+	thrift "thrift"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// Mock of TProtocol interface
+type MockTProtocol struct {
+	ctrl     *gomock.Controller
+	recorder *_MockTProtocolRecorder
+}
+
+// Recorder for MockTProtocol (not exported)
+type _MockTProtocolRecorder struct {
+	mock *MockTProtocol
+}
+
+func NewMockTProtocol(ctrl *gomock.Controller) *MockTProtocol {
+	mock := &MockTProtocol{ctrl: ctrl}
+	mock.recorder = &_MockTProtocolRecorder{mock}
+	return mock
+}
+
+func (_m *MockTProtocol) EXPECT() *_MockTProtocolRecorder {
+	return _m.recorder
+}
+
+func (_m *MockTProtocol) Flush(ctx context.Context) error {
+	ret := _m.ctrl.Call(_m, "Flush")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) Flush(ctx context.Context) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "Flush")
+}
+
+func (_m *MockTProtocol) ReadBinary() ([]byte, error) {
+	ret := _m.ctrl.Call(_m, "ReadBinary")
+	ret0, _ := ret[0].([]byte)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockTProtocolRecorder) ReadBinary() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadBinary")
+}
+
+func (_m *MockTProtocol) ReadBool() (bool, error) {
+	ret := _m.ctrl.Call(_m, "ReadBool")
+	ret0, _ := ret[0].(bool)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockTProtocolRecorder) ReadBool() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadBool")
+}
+
+func (_m *MockTProtocol) ReadByte() (int8, error) {
+	ret := _m.ctrl.Call(_m, "ReadByte")
+	ret0, _ := ret[0].(int8)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockTProtocolRecorder) ReadByte() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadByte")
+}
+
+func (_m *MockTProtocol) ReadDouble() (float64, error) {
+	ret := _m.ctrl.Call(_m, "ReadDouble")
+	ret0, _ := ret[0].(float64)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockTProtocolRecorder) ReadDouble() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadDouble")
+}
+
+func (_m *MockTProtocol) ReadFieldBegin() (string, thrift.TType, int16, error) {
+	ret := _m.ctrl.Call(_m, "ReadFieldBegin")
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(thrift.TType)
+	ret2, _ := ret[2].(int16)
+	ret3, _ := ret[3].(error)
+	return ret0, ret1, ret2, ret3
+}
+
+func (_mr *_MockTProtocolRecorder) ReadFieldBegin() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadFieldBegin")
+}
+
+func (_m *MockTProtocol) ReadFieldEnd() error {
+	ret := _m.ctrl.Call(_m, "ReadFieldEnd")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) ReadFieldEnd() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadFieldEnd")
+}
+
+func (_m *MockTProtocol) ReadI16() (int16, error) {
+	ret := _m.ctrl.Call(_m, "ReadI16")
+	ret0, _ := ret[0].(int16)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockTProtocolRecorder) ReadI16() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadI16")
+}
+
+func (_m *MockTProtocol) ReadI32() (int32, error) {
+	ret := _m.ctrl.Call(_m, "ReadI32")
+	ret0, _ := ret[0].(int32)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockTProtocolRecorder) ReadI32() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadI32")
+}
+
+func (_m *MockTProtocol) ReadI64() (int64, error) {
+	ret := _m.ctrl.Call(_m, "ReadI64")
+	ret0, _ := ret[0].(int64)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockTProtocolRecorder) ReadI64() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadI64")
+}
+
+func (_m *MockTProtocol) ReadListBegin() (thrift.TType, int, error) {
+	ret := _m.ctrl.Call(_m, "ReadListBegin")
+	ret0, _ := ret[0].(thrift.TType)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+func (_mr *_MockTProtocolRecorder) ReadListBegin() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadListBegin")
+}
+
+func (_m *MockTProtocol) ReadListEnd() error {
+	ret := _m.ctrl.Call(_m, "ReadListEnd")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) ReadListEnd() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadListEnd")
+}
+
+func (_m *MockTProtocol) ReadMapBegin() (thrift.TType, thrift.TType, int, error) {
+	ret := _m.ctrl.Call(_m, "ReadMapBegin")
+	ret0, _ := ret[0].(thrift.TType)
+	ret1, _ := ret[1].(thrift.TType)
+	ret2, _ := ret[2].(int)
+	ret3, _ := ret[3].(error)
+	return ret0, ret1, ret2, ret3
+}
+
+func (_mr *_MockTProtocolRecorder) ReadMapBegin() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadMapBegin")
+}
+
+func (_m *MockTProtocol) ReadMapEnd() error {
+	ret := _m.ctrl.Call(_m, "ReadMapEnd")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) ReadMapEnd() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadMapEnd")
+}
+
+func (_m *MockTProtocol) ReadMessageBegin() (string, thrift.TMessageType, int32, error) {
+	ret := _m.ctrl.Call(_m, "ReadMessageBegin")
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(thrift.TMessageType)
+	ret2, _ := ret[2].(int32)
+	ret3, _ := ret[3].(error)
+	return ret0, ret1, ret2, ret3
+}
+
+func (_mr *_MockTProtocolRecorder) ReadMessageBegin() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadMessageBegin")
+}
+
+func (_m *MockTProtocol) ReadMessageEnd() error {
+	ret := _m.ctrl.Call(_m, "ReadMessageEnd")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) ReadMessageEnd() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadMessageEnd")
+}
+
+func (_m *MockTProtocol) ReadSetBegin() (thrift.TType, int, error) {
+	ret := _m.ctrl.Call(_m, "ReadSetBegin")
+	ret0, _ := ret[0].(thrift.TType)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+func (_mr *_MockTProtocolRecorder) ReadSetBegin() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadSetBegin")
+}
+
+func (_m *MockTProtocol) ReadSetEnd() error {
+	ret := _m.ctrl.Call(_m, "ReadSetEnd")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) ReadSetEnd() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadSetEnd")
+}
+
+func (_m *MockTProtocol) ReadString() (string, error) {
+	ret := _m.ctrl.Call(_m, "ReadString")
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockTProtocolRecorder) ReadString() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadString")
+}
+
+func (_m *MockTProtocol) ReadStructBegin() (string, error) {
+	ret := _m.ctrl.Call(_m, "ReadStructBegin")
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+func (_mr *_MockTProtocolRecorder) ReadStructBegin() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadStructBegin")
+}
+
+func (_m *MockTProtocol) ReadStructEnd() error {
+	ret := _m.ctrl.Call(_m, "ReadStructEnd")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) ReadStructEnd() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "ReadStructEnd")
+}
+
+func (_m *MockTProtocol) Skip(_param0 thrift.TType) error {
+	ret := _m.ctrl.Call(_m, "Skip", _param0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) Skip(arg0 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "Skip", arg0)
+}
+
+func (_m *MockTProtocol) Transport() thrift.TTransport {
+	ret := _m.ctrl.Call(_m, "Transport")
+	ret0, _ := ret[0].(thrift.TTransport)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) Transport() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "Transport")
+}
+
+func (_m *MockTProtocol) WriteBinary(_param0 []byte) error {
+	ret := _m.ctrl.Call(_m, "WriteBinary", _param0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteBinary(arg0 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteBinary", arg0)
+}
+
+func (_m *MockTProtocol) WriteBool(_param0 bool) error {
+	ret := _m.ctrl.Call(_m, "WriteBool", _param0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteBool(arg0 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteBool", arg0)
+}
+
+func (_m *MockTProtocol) WriteByte(_param0 int8) error {
+	ret := _m.ctrl.Call(_m, "WriteByte", _param0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteByte(arg0 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteByte", arg0)
+}
+
+func (_m *MockTProtocol) WriteDouble(_param0 float64) error {
+	ret := _m.ctrl.Call(_m, "WriteDouble", _param0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteDouble(arg0 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteDouble", arg0)
+}
+
+func (_m *MockTProtocol) WriteFieldBegin(_param0 string, _param1 thrift.TType, _param2 int16) error {
+	ret := _m.ctrl.Call(_m, "WriteFieldBegin", _param0, _param1, _param2)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteFieldBegin(arg0, arg1, arg2 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteFieldBegin", arg0, arg1, arg2)
+}
+
+func (_m *MockTProtocol) WriteFieldEnd() error {
+	ret := _m.ctrl.Call(_m, "WriteFieldEnd")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteFieldEnd() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteFieldEnd")
+}
+
+func (_m *MockTProtocol) WriteFieldStop() error {
+	ret := _m.ctrl.Call(_m, "WriteFieldStop")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteFieldStop() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteFieldStop")
+}
+
+func (_m *MockTProtocol) WriteI16(_param0 int16) error {
+	ret := _m.ctrl.Call(_m, "WriteI16", _param0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteI16(arg0 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteI16", arg0)
+}
+
+func (_m *MockTProtocol) WriteI32(_param0 int32) error {
+	ret := _m.ctrl.Call(_m, "WriteI32", _param0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteI32(arg0 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteI32", arg0)
+}
+
+func (_m *MockTProtocol) WriteI64(_param0 int64) error {
+	ret := _m.ctrl.Call(_m, "WriteI64", _param0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteI64(arg0 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteI64", arg0)
+}
+
+func (_m *MockTProtocol) WriteListBegin(_param0 thrift.TType, _param1 int) error {
+	ret := _m.ctrl.Call(_m, "WriteListBegin", _param0, _param1)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteListBegin(arg0, arg1 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteListBegin", arg0, arg1)
+}
+
+func (_m *MockTProtocol) WriteListEnd() error {
+	ret := _m.ctrl.Call(_m, "WriteListEnd")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteListEnd() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteListEnd")
+}
+
+func (_m *MockTProtocol) WriteMapBegin(_param0 thrift.TType, _param1 thrift.TType, _param2 int) error {
+	ret := _m.ctrl.Call(_m, "WriteMapBegin", _param0, _param1, _param2)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteMapBegin(arg0, arg1, arg2 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteMapBegin", arg0, arg1, arg2)
+}
+
+func (_m *MockTProtocol) WriteMapEnd() error {
+	ret := _m.ctrl.Call(_m, "WriteMapEnd")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteMapEnd() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteMapEnd")
+}
+
+func (_m *MockTProtocol) WriteMessageBegin(_param0 string, _param1 thrift.TMessageType, _param2 int32) error {
+	ret := _m.ctrl.Call(_m, "WriteMessageBegin", _param0, _param1, _param2)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteMessageBegin(arg0, arg1, arg2 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteMessageBegin", arg0, arg1, arg2)
+}
+
+func (_m *MockTProtocol) WriteMessageEnd() error {
+	ret := _m.ctrl.Call(_m, "WriteMessageEnd")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteMessageEnd() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteMessageEnd")
+}
+
+func (_m *MockTProtocol) WriteSetBegin(_param0 thrift.TType, _param1 int) error {
+	ret := _m.ctrl.Call(_m, "WriteSetBegin", _param0, _param1)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteSetBegin(arg0, arg1 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteSetBegin", arg0, arg1)
+}
+
+func (_m *MockTProtocol) WriteSetEnd() error {
+	ret := _m.ctrl.Call(_m, "WriteSetEnd")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteSetEnd() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteSetEnd")
+}
+
+func (_m *MockTProtocol) WriteString(_param0 string) error {
+	ret := _m.ctrl.Call(_m, "WriteString", _param0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteString(arg0 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteString", arg0)
+}
+
+func (_m *MockTProtocol) WriteStructBegin(_param0 string) error {
+	ret := _m.ctrl.Call(_m, "WriteStructBegin", _param0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteStructBegin(arg0 interface{}) *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteStructBegin", arg0)
+}
+
+func (_m *MockTProtocol) WriteStructEnd() error {
+	ret := _m.ctrl.Call(_m, "WriteStructEnd")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+func (_mr *_MockTProtocolRecorder) WriteStructEnd() *gomock.Call {
+	return _mr.mock.ctrl.RecordCall(_mr.mock, "WriteStructEnd")
+}
diff --git a/lib/go/test/tests/protocols_test.go b/lib/go/test/tests/protocols_test.go
new file mode 100644
index 0000000..cffd9c3
--- /dev/null
+++ b/lib/go/test/tests/protocols_test.go
@@ -0,0 +1,97 @@
+/*
+ * 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 tests
+
+import (
+	"testing"
+	"thrift"
+	"thrifttest"
+)
+
+func RunSocketTestSuite(t *testing.T, protocolFactory thrift.TProtocolFactory,
+	transportFactory thrift.TTransportFactory) {
+	// server
+	var err error
+	addr = FindAvailableTCPServerPort()
+	serverTransport, err := thrift.NewTServerSocketTimeout(addr.String(), TIMEOUT)
+	if err != nil {
+		t.Fatal("Unable to create server socket", err)
+	}
+	processor := thrifttest.NewThriftTestProcessor(NewThriftTestHandler())
+	server = thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
+	server.Listen()
+
+	go server.Serve()
+
+	// client
+	var transport thrift.TTransport = thrift.NewTSocketFromAddrTimeout(addr, TIMEOUT)
+	transport, err = transportFactory.GetTransport(transport)
+	if err != nil {
+		t.Fatal(err)
+	}
+	var protocol thrift.TProtocol = protocolFactory.GetProtocol(transport)
+	thriftTestClient := thrifttest.NewThriftTestClient(thrift.NewTStandardClient(protocol, protocol))
+	err = transport.Open()
+	if err != nil {
+		t.Fatal("Unable to open client socket", err)
+	}
+
+	driver := NewThriftTestDriver(t, thriftTestClient)
+	driver.Start()
+}
+
+// Run test suite using TJSONProtocol
+func TestTJSONProtocol(t *testing.T) {
+	RunSocketTestSuite(t,
+		thrift.NewTJSONProtocolFactory(),
+		thrift.NewTTransportFactory())
+	RunSocketTestSuite(t,
+		thrift.NewTJSONProtocolFactory(),
+		thrift.NewTBufferedTransportFactory(8912))
+	RunSocketTestSuite(t,
+		thrift.NewTJSONProtocolFactory(),
+		thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory()))
+}
+
+// Run test suite using TBinaryProtocol
+func TestTBinaryProtocol(t *testing.T) {
+	RunSocketTestSuite(t,
+		thrift.NewTBinaryProtocolFactoryDefault(),
+		thrift.NewTTransportFactory())
+	RunSocketTestSuite(t,
+		thrift.NewTBinaryProtocolFactoryDefault(),
+		thrift.NewTBufferedTransportFactory(8912))
+	RunSocketTestSuite(t,
+		thrift.NewTBinaryProtocolFactoryDefault(),
+		thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory()))
+}
+
+// Run test suite using TCompactBinaryProtocol
+func TestTCompactProtocol(t *testing.T) {
+	RunSocketTestSuite(t,
+		thrift.NewTCompactProtocolFactory(),
+		thrift.NewTTransportFactory())
+	RunSocketTestSuite(t,
+		thrift.NewTCompactProtocolFactory(),
+		thrift.NewTBufferedTransportFactory(8912))
+	RunSocketTestSuite(t,
+		thrift.NewTCompactProtocolFactory(),
+		thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory()))
+}
diff --git a/lib/go/test/tests/required_fields_test.go b/lib/go/test/tests/required_fields_test.go
new file mode 100644
index 0000000..3fa414a
--- /dev/null
+++ b/lib/go/test/tests/required_fields_test.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 tests
+
+import (
+	"context"
+	"github.com/golang/mock/gomock"
+	"optionalfieldstest"
+	"requiredfieldtest"
+	"testing"
+	"thrift"
+)
+
+func TestRequiredField_SucecssWhenSet(t *testing.T) {
+	// create a new RequiredField instance with the required field set
+	source := &requiredfieldtest.RequiredField{Name: "this is a test"}
+	sourceData, err := thrift.NewTSerializer().Write(context.Background(), source)
+	if err != nil {
+		t.Fatalf("failed to serialize %T: %v", source, err)
+	}
+
+	d := thrift.NewTDeserializer()
+	err = d.Read(&requiredfieldtest.RequiredField{}, sourceData)
+	if err != nil {
+		t.Fatalf("Did not expect an error when trying to deserialize the requiredfieldtest.RequiredField: %v", err)
+	}
+}
+
+func TestRequiredField_ErrorWhenMissing(t *testing.T) {
+	// create a new OtherThing instance, without setting the required field
+	source := &requiredfieldtest.OtherThing{}
+	sourceData, err := thrift.NewTSerializer().Write(context.Background(), source)
+	if err != nil {
+		t.Fatalf("failed to serialize %T: %v", source, err)
+	}
+
+	// attempt to deserialize into a different type (which should fail)
+	d := thrift.NewTDeserializer()
+	err = d.Read(&requiredfieldtest.RequiredField{}, sourceData)
+	if err == nil {
+		t.Fatal("Expected an error when trying to deserialize an object which is missing a required field")
+	}
+}
+
+func TestStructReadRequiredFields(t *testing.T) {
+	mockCtrl := gomock.NewController(t)
+	protocol := NewMockTProtocol(mockCtrl)
+	testStruct := optionalfieldstest.NewStructC()
+
+	// None of required fields are set
+	gomock.InOrder(
+		protocol.EXPECT().ReadStructBegin().Return("StructC", nil),
+		protocol.EXPECT().ReadFieldBegin().Return("_", thrift.TType(thrift.STOP), int16(1), nil),
+		protocol.EXPECT().ReadStructEnd().Return(nil),
+	)
+
+	err := testStruct.Read(protocol)
+	mockCtrl.Finish()
+	mockCtrl = gomock.NewController(t)
+	if err == nil {
+		t.Fatal("Expected read to fail")
+	}
+	err2, ok := err.(thrift.TProtocolException)
+	if !ok {
+		t.Fatal("Expected a TProtocolException")
+	}
+	if err2.TypeId() != thrift.INVALID_DATA {
+		t.Fatal("Expected INVALID_DATA TProtocolException")
+	}
+
+	// One of the required fields is set
+	gomock.InOrder(
+		protocol.EXPECT().ReadStructBegin().Return("StructC", nil),
+		protocol.EXPECT().ReadFieldBegin().Return("I", thrift.TType(thrift.I32), int16(2), nil),
+		protocol.EXPECT().ReadI32().Return(int32(1), nil),
+		protocol.EXPECT().ReadFieldEnd().Return(nil),
+		protocol.EXPECT().ReadFieldBegin().Return("_", thrift.TType(thrift.STOP), int16(1), nil),
+		protocol.EXPECT().ReadStructEnd().Return(nil),
+	)
+
+	err = testStruct.Read(protocol)
+	mockCtrl.Finish()
+	mockCtrl = gomock.NewController(t)
+	if err == nil {
+		t.Fatal("Expected read to fail")
+	}
+	err2, ok = err.(thrift.TProtocolException)
+	if !ok {
+		t.Fatal("Expected a TProtocolException")
+	}
+	if err2.TypeId() != thrift.INVALID_DATA {
+		t.Fatal("Expected INVALID_DATA TProtocolException")
+	}
+
+	// Both of the required fields are set
+	gomock.InOrder(
+		protocol.EXPECT().ReadStructBegin().Return("StructC", nil),
+		protocol.EXPECT().ReadFieldBegin().Return("i", thrift.TType(thrift.I32), int16(2), nil),
+		protocol.EXPECT().ReadI32().Return(int32(1), nil),
+		protocol.EXPECT().ReadFieldEnd().Return(nil),
+		protocol.EXPECT().ReadFieldBegin().Return("s2", thrift.TType(thrift.STRING), int16(4), nil),
+		protocol.EXPECT().ReadString().Return("test", nil),
+		protocol.EXPECT().ReadFieldEnd().Return(nil),
+		protocol.EXPECT().ReadFieldBegin().Return("_", thrift.TType(thrift.STOP), int16(1), nil),
+		protocol.EXPECT().ReadStructEnd().Return(nil),
+	)
+
+	err = testStruct.Read(protocol)
+	mockCtrl.Finish()
+	if err != nil {
+		t.Fatal("Expected read to succeed")
+	}
+}
diff --git a/lib/go/test/tests/struct_args_rets_test.go b/lib/go/test/tests/struct_args_rets_test.go
new file mode 100644
index 0000000..81e9b26
--- /dev/null
+++ b/lib/go/test/tests/struct_args_rets_test.go
@@ -0,0 +1,36 @@
+/*
+ * 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 tests
+
+import (
+	st "servicestest"
+)
+
+//this function is never called, it will fail to compile if check is failed
+func staticCheckStructArgsResults() {
+	//Check that struct args and results are passed by reference
+	var sa *st.StructA = &st.StructA{}
+	var iface st.AServ
+	var err error
+
+	sa, err = iface.StructAFunc_1structA(defaultCtx, sa)
+	_ = err
+	_ = sa
+}
diff --git a/lib/go/test/tests/thrifttest_driver.go b/lib/go/test/tests/thrifttest_driver.go
new file mode 100644
index 0000000..de54cbc
--- /dev/null
+++ b/lib/go/test/tests/thrifttest_driver.go
@@ -0,0 +1,236 @@
+/*
+ * 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 tests
+
+import (
+	"reflect"
+	"testing"
+	"thrifttest"
+)
+
+type ThriftTestDriver struct {
+	client thrifttest.ThriftTest
+	t      *testing.T
+}
+
+func NewThriftTestDriver(t *testing.T, client thrifttest.ThriftTest) *ThriftTestDriver {
+	return &ThriftTestDriver{client, t}
+}
+
+func (p *ThriftTestDriver) Start() {
+	client := p.client
+	t := p.t
+
+	if client.TestVoid(defaultCtx) != nil {
+		t.Fatal("TestVoid failed")
+	}
+
+	if r, err := client.TestString(defaultCtx, "Test"); r != "Test" || err != nil {
+		t.Fatal("TestString with simple text failed")
+	}
+
+	if r, err := client.TestString(defaultCtx, ""); r != "" || err != nil {
+		t.Fatal("TestString with empty text failed")
+	}
+
+	stringTest := "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " +
+		"Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " +
+		"Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, " +
+		"বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, " +
+		"Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, " +
+		"Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, " +
+		"Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, " +
+		"Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, " +
+		"Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, " +
+		"Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, " +
+		"Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, " +
+		"ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, " +
+		"Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, " +
+		"Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa " +
+		"Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa " +
+		"Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪" +
+		"Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, " +
+		"Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, " +
+		"Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, " +
+		"Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple " +
+		"English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, " +
+		"Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, " +
+		"Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, " +
+		"Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, " +
+		"Bân-lâm-gú, 粵語"
+
+	if r, err := client.TestString(defaultCtx, stringTest); r != stringTest || err != nil {
+		t.Fatal("TestString with all languages failed")
+	}
+
+	specialCharacters := "quote: \" backslash:" +
+		" backspace: \b formfeed: \f newline: \n return: \r tab: " +
+		" now-all-of-them-together: '\\\b\n\r\t'" +
+		" now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><" +
+		" char-to-test-json-parsing: ]] \"]] \\\" }}}{ [[[ "
+
+	if r, err := client.TestString(defaultCtx, specialCharacters); r != specialCharacters || err != nil {
+		t.Fatal("TestString with specialCharacters failed")
+	}
+
+	if r, err := client.TestByte(defaultCtx, 1); r != 1 || err != nil {
+		t.Fatal("TestByte(1) failed")
+	}
+	if r, err := client.TestByte(defaultCtx, 0); r != 0 || err != nil {
+		t.Fatal("TestByte(0) failed")
+	}
+	if r, err := client.TestByte(defaultCtx, -1); r != -1 || err != nil {
+		t.Fatal("TestByte(-1) failed")
+	}
+	if r, err := client.TestByte(defaultCtx, -127); r != -127 || err != nil {
+		t.Fatal("TestByte(-127) failed")
+	}
+
+	if r, err := client.TestI32(defaultCtx, -1); r != -1 || err != nil {
+		t.Fatal("TestI32(-1) failed")
+	}
+	if r, err := client.TestI32(defaultCtx, 1); r != 1 || err != nil {
+		t.Fatal("TestI32(1) failed")
+	}
+
+	if r, err := client.TestI64(defaultCtx, -5); r != -5 || err != nil {
+		t.Fatal("TestI64(-5) failed")
+	}
+	if r, err := client.TestI64(defaultCtx, 5); r != 5 || err != nil {
+		t.Fatal("TestI64(5) failed")
+	}
+	if r, err := client.TestI64(defaultCtx, -34359738368); r != -34359738368 || err != nil {
+		t.Fatal("TestI64(-34359738368) failed")
+	}
+
+	if r, err := client.TestDouble(defaultCtx, -5.2098523); r != -5.2098523 || err != nil {
+		t.Fatal("TestDouble(-5.2098523) failed")
+	}
+	if r, err := client.TestDouble(defaultCtx, -7.012052175215044); r != -7.012052175215044 || err != nil {
+		t.Fatal("TestDouble(-7.012052175215044) failed")
+	}
+
+	// TODO: add testBinary() call
+
+	out := thrifttest.NewXtruct()
+	out.StringThing = "Zero"
+	out.ByteThing = 1
+	out.I32Thing = -3
+	out.I64Thing = 1000000
+	if r, err := client.TestStruct(defaultCtx, out); !reflect.DeepEqual(r, out) || err != nil {
+		t.Fatal("TestStruct failed")
+	}
+
+	out2 := thrifttest.NewXtruct2()
+	out2.ByteThing = 1
+	out2.StructThing = out
+	out2.I32Thing = 5
+	if r, err := client.TestNest(defaultCtx, out2); !reflect.DeepEqual(r, out2) || err != nil {
+		t.Fatal("TestNest failed")
+	}
+
+	mapout := make(map[int32]int32)
+	for i := int32(0); i < 5; i++ {
+		mapout[i] = i - 10
+	}
+	if r, err := client.TestMap(defaultCtx, mapout); !reflect.DeepEqual(r, mapout) || err != nil {
+		t.Fatal("TestMap failed")
+	}
+
+	mapTestInput := map[string]string{
+		"a": "123", "a b": "with spaces ", "same": "same", "0": "numeric key",
+		"longValue": stringTest, stringTest: "long key",
+	}
+	if r, err := client.TestStringMap(defaultCtx, mapTestInput); !reflect.DeepEqual(r, mapTestInput) || err != nil {
+		t.Fatal("TestStringMap failed")
+	}
+
+	setTestInput := []int32{1, 2, 3}
+	if r, err := client.TestSet(defaultCtx, setTestInput); !reflect.DeepEqual(r, setTestInput) || err != nil {
+		t.Fatal("TestSet failed")
+	}
+
+	listTest := []int32{1, 2, 3}
+	if r, err := client.TestList(defaultCtx, listTest); !reflect.DeepEqual(r, listTest) || err != nil {
+		t.Fatal("TestList failed")
+	}
+
+	if r, err := client.TestEnum(defaultCtx, thrifttest.Numberz_ONE); r != thrifttest.Numberz_ONE || err != nil {
+		t.Fatal("TestEnum failed")
+	}
+
+	if r, err := client.TestTypedef(defaultCtx, 69); r != 69 || err != nil {
+		t.Fatal("TestTypedef failed")
+	}
+
+	mapMapTest := map[int32]map[int32]int32{
+		4:  {1: 1, 2: 2, 3: 3, 4: 4},
+		-4: {-4: -4, -3: -3, -2: -2, -1: -1},
+	}
+	if r, err := client.TestMapMap(defaultCtx, 1); !reflect.DeepEqual(r, mapMapTest) || err != nil {
+		t.Fatal("TestMapMap failed")
+	}
+
+	crazyX1 := thrifttest.NewXtruct()
+	crazyX1.StringThing = "Goodbye4"
+	crazyX1.ByteThing = 4
+	crazyX1.I32Thing = 4
+	crazyX1.I64Thing = 4
+
+	crazyX2 := thrifttest.NewXtruct()
+	crazyX2.StringThing = "Hello2"
+	crazyX2.ByteThing = 2
+	crazyX2.I32Thing = 2
+	crazyX2.I64Thing = 2
+
+	crazy := thrifttest.NewInsanity()
+	crazy.UserMap = map[thrifttest.Numberz]thrifttest.UserId{5: 5, 8: 8}
+	crazy.Xtructs = []*thrifttest.Xtruct{crazyX1, crazyX2}
+
+	crazyEmpty := thrifttest.NewInsanity()
+	crazyEmpty.UserMap = map[thrifttest.Numberz]thrifttest.UserId{}
+	crazyEmpty.Xtructs = []*thrifttest.Xtruct{}
+
+	insanity := map[thrifttest.UserId]map[thrifttest.Numberz]*thrifttest.Insanity{
+		1: {thrifttest.Numberz_TWO: crazy, thrifttest.Numberz_THREE: crazy},
+		2: {thrifttest.Numberz_SIX: crazyEmpty},
+	}
+	if r, err := client.TestInsanity(defaultCtx, crazy); !reflect.DeepEqual(r, insanity) || err != nil {
+		t.Fatal("TestInsanity failed")
+	}
+
+	if err := client.TestException(defaultCtx, "TException"); err == nil {
+		t.Fatal("TestException TException failed")
+	}
+
+	if err, ok := client.TestException(defaultCtx, "Xception").(*thrifttest.Xception); ok == false || err == nil {
+		t.Fatal("TestException Xception failed")
+	} else if err.ErrorCode != 1001 || err.Message != "Xception" {
+		t.Fatal("TestException Xception failed")
+	}
+
+	if err := client.TestException(defaultCtx, "no Exception"); err != nil {
+		t.Fatal("TestException no Exception failed")
+	}
+
+	if err := client.TestOneway(defaultCtx, 0); err != nil {
+		t.Fatal("TestOneway failed")
+	}
+}
diff --git a/lib/go/test/tests/thrifttest_handler.go b/lib/go/test/tests/thrifttest_handler.go
new file mode 100644
index 0000000..31b9ee2
--- /dev/null
+++ b/lib/go/test/tests/thrifttest_handler.go
@@ -0,0 +1,210 @@
+/*
+ * 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 tests
+
+import (
+	"context"
+	"errors"
+	"thrift"
+	"thrifttest"
+	"time"
+)
+
+type SecondServiceHandler struct {
+}
+
+func NewSecondServiceHandler() *SecondServiceHandler {
+	return &SecondServiceHandler{}
+}
+
+func (p *SecondServiceHandler) BlahBlah(ctx context.Context) (err error) {
+	return nil
+}
+
+func (p *SecondServiceHandler) SecondtestString(ctx context.Context, thing string) (r string, err error) {
+	return thing, nil
+}
+
+type ThriftTestHandler struct {
+}
+
+func NewThriftTestHandler() *ThriftTestHandler {
+	return &ThriftTestHandler{}
+}
+
+func (p *ThriftTestHandler) TestVoid(ctx context.Context) (err error) {
+	return nil
+}
+
+func (p *ThriftTestHandler) TestString(ctx context.Context, thing string) (r string, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestBool(ctx context.Context, thing bool) (r bool, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestByte(ctx context.Context, thing int8) (r int8, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestI32(ctx context.Context, thing int32) (r int32, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestI64(ctx context.Context, thing int64) (r int64, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestDouble(ctx context.Context, thing float64) (r float64, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestBinary(ctx context.Context, thing []byte) (r []byte, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestStruct(ctx context.Context, thing *thrifttest.Xtruct) (r *thrifttest.Xtruct, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestNest(ctx context.Context, thing *thrifttest.Xtruct2) (r *thrifttest.Xtruct2, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestMap(ctx context.Context, thing map[int32]int32) (r map[int32]int32, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestStringMap(ctx context.Context, thing map[string]string) (r map[string]string, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestSet(ctx context.Context, thing []int32) (r []int32, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestList(ctx context.Context, thing []int32) (r []int32, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestEnum(ctx context.Context, thing thrifttest.Numberz) (r thrifttest.Numberz, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestTypedef(ctx context.Context, thing thrifttest.UserId) (r thrifttest.UserId, err error) {
+	return thing, nil
+}
+
+func (p *ThriftTestHandler) TestMapMap(ctx context.Context, hello int32) (r map[int32]map[int32]int32, err error) {
+	r = make(map[int32]map[int32]int32)
+	pos := make(map[int32]int32)
+	neg := make(map[int32]int32)
+
+	for i := int32(1); i < 5; i++ {
+		pos[i] = i
+		neg[-i] = -i
+	}
+	r[4] = pos
+	r[-4] = neg
+
+	return r, nil
+}
+
+func (p *ThriftTestHandler) TestInsanity(ctx context.Context, argument *thrifttest.Insanity) (r map[thrifttest.UserId]map[thrifttest.Numberz]*thrifttest.Insanity, err error) {
+	hello := thrifttest.NewXtruct()
+	hello.StringThing = "Hello2"
+	hello.ByteThing = 2
+	hello.I32Thing = 2
+	hello.I64Thing = 2
+
+	goodbye := thrifttest.NewXtruct()
+	goodbye.StringThing = "Goodbye4"
+	goodbye.ByteThing = 4
+	goodbye.I32Thing = 4
+	goodbye.I64Thing = 4
+
+	crazy := thrifttest.NewInsanity()
+	crazy.UserMap = make(map[thrifttest.Numberz]thrifttest.UserId)
+	crazy.UserMap[thrifttest.Numberz_EIGHT] = 8
+	crazy.UserMap[thrifttest.Numberz_FIVE] = 5
+	crazy.Xtructs = []*thrifttest.Xtruct{goodbye, hello}
+
+	first_map := make(map[thrifttest.Numberz]*thrifttest.Insanity)
+	second_map := make(map[thrifttest.Numberz]*thrifttest.Insanity)
+
+	first_map[thrifttest.Numberz_TWO] = crazy
+	first_map[thrifttest.Numberz_THREE] = crazy
+
+	looney := thrifttest.NewInsanity()
+	second_map[thrifttest.Numberz_SIX] = looney
+
+	var insane = make(map[thrifttest.UserId]map[thrifttest.Numberz]*thrifttest.Insanity)
+	insane[1] = first_map
+	insane[2] = second_map
+
+	return insane, nil
+}
+
+func (p *ThriftTestHandler) TestMulti(ctx context.Context, arg0 int8, arg1 int32, arg2 int64, arg3 map[int16]string, arg4 thrifttest.Numberz, arg5 thrifttest.UserId) (r *thrifttest.Xtruct, err error) {
+	r = thrifttest.NewXtruct()
+	r.StringThing = "Hello2"
+	r.ByteThing = arg0
+	r.I32Thing = arg1
+	r.I64Thing = arg2
+	return r, nil
+}
+
+func (p *ThriftTestHandler) TestException(ctx context.Context, arg string) (err error) {
+	if arg == "Xception" {
+		x := thrifttest.NewXception()
+		x.ErrorCode = 1001
+		x.Message = arg
+		return x
+	} else if arg == "TException" {
+		return thrift.TException(errors.New(arg))
+	} else {
+		return nil
+	}
+}
+
+func (p *ThriftTestHandler) TestMultiException(ctx context.Context, arg0 string, arg1 string) (r *thrifttest.Xtruct, err error) {
+	if arg0 == "Xception" {
+		x := thrifttest.NewXception()
+		x.ErrorCode = 1001
+		x.Message = "This is an Xception"
+		return nil, x
+	} else if arg0 == "Xception2" {
+		x2 := thrifttest.NewXception2()
+		x2.ErrorCode = 2002
+		x2.StructThing = thrifttest.NewXtruct()
+		x2.StructThing.StringThing = "This is an Xception2"
+		return nil, x2
+	}
+
+	res := thrifttest.NewXtruct()
+	res.StringThing = arg1
+	return res, nil
+}
+
+func (p *ThriftTestHandler) TestOneway(ctx context.Context, secondsToSleep int32) (err error) {
+	time.Sleep(time.Second * time.Duration(secondsToSleep))
+	return nil
+}
diff --git a/lib/go/test/tests/union_binary_test.go b/lib/go/test/tests/union_binary_test.go
new file mode 100644
index 0000000..bdae2cb
--- /dev/null
+++ b/lib/go/test/tests/union_binary_test.go
@@ -0,0 +1,36 @@
+/*
+ * 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 tests
+
+import (
+	"testing"
+	"unionbinarytest"
+)
+
+
+// See https://issues.apache.org/jira/browse/THRIFT-4573
+func TestUnionBinary(t *testing.T) {
+	s := unionbinarytest.NewSample()
+	s.U1 = map[string]string{}
+	s.U2 = []byte{}
+	if n := s.CountSetFieldsSample(); n != 2 {
+		t.Errorf("Expected 2 set fields, got %d!", n)
+	}
+}
diff --git a/lib/go/test/tests/union_default_value_test.go b/lib/go/test/tests/union_default_value_test.go
new file mode 100644
index 0000000..2dcbf4e
--- /dev/null
+++ b/lib/go/test/tests/union_default_value_test.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 tests
+
+import (
+	"testing"
+	"uniondefaultvaluetest"
+)
+
+func TestUnionDefaultValue(t *testing.T) {
+	s := uniondefaultvaluetest.NewTestStruct()
+	d := s.GetDescendant()
+	if d == nil {
+		t.Error("Default Union value not set!")
+	}
+}
diff --git a/lib/go/thrift/application_exception.go b/lib/go/thrift/application_exception.go
index 6655cc5..b9d7eed 100644
--- a/lib/go/thrift/application_exception.go
+++ b/lib/go/thrift/application_exception.go
@@ -30,11 +30,22 @@
 	PROTOCOL_ERROR                 = 7
 )
 
+var defaultApplicationExceptionMessage = map[int32]string{
+	UNKNOWN_APPLICATION_EXCEPTION:  "unknown application exception",
+	UNKNOWN_METHOD:                 "unknown method",
+	INVALID_MESSAGE_TYPE_EXCEPTION: "invalid message type",
+	WRONG_METHOD_NAME:              "wrong method name",
+	BAD_SEQUENCE_ID:                "bad sequence ID",
+	MISSING_RESULT:                 "missing result",
+	INTERNAL_ERROR:                 "unknown internal error",
+	PROTOCOL_ERROR:                 "unknown protocol error",
+}
+
 // Application level Thrift exception
 type TApplicationException interface {
 	TException
 	TypeId() int32
-	Read(iprot TProtocol) (TApplicationException, error)
+	Read(iprot TProtocol) error
 	Write(oprot TProtocol) error
 }
 
@@ -44,7 +55,10 @@
 }
 
 func (e tApplicationException) Error() string {
-	return e.message
+	if e.message != "" {
+		return e.message
+	}
+	return defaultApplicationExceptionMessage[e.type_]
 }
 
 func NewTApplicationException(type_ int32, message string) TApplicationException {
@@ -55,10 +69,11 @@
 	return p.type_
 }
 
-func (p *tApplicationException) Read(iprot TProtocol) (TApplicationException, error) {
+func (p *tApplicationException) Read(iprot TProtocol) error {
+	// TODO: this should really be generated by the compiler
 	_, err := iprot.ReadStructBegin()
 	if err != nil {
-		return nil, err
+		return err
 	}
 
 	message := ""
@@ -67,7 +82,7 @@
 	for {
 		_, ttype, id, err := iprot.ReadFieldBegin()
 		if err != nil {
-			return nil, err
+			return err
 		}
 		if ttype == STOP {
 			break
@@ -76,33 +91,40 @@
 		case 1:
 			if ttype == STRING {
 				if message, err = iprot.ReadString(); err != nil {
-					return nil, err
+					return err
 				}
 			} else {
 				if err = SkipDefaultDepth(iprot, ttype); err != nil {
-					return nil, err
+					return err
 				}
 			}
 		case 2:
 			if ttype == I32 {
 				if type_, err = iprot.ReadI32(); err != nil {
-					return nil, err
+					return err
 				}
 			} else {
 				if err = SkipDefaultDepth(iprot, ttype); err != nil {
-					return nil, err
+					return err
 				}
 			}
 		default:
 			if err = SkipDefaultDepth(iprot, ttype); err != nil {
-				return nil, err
+				return err
 			}
 		}
 		if err = iprot.ReadFieldEnd(); err != nil {
-			return nil, err
+			return err
 		}
 	}
-	return NewTApplicationException(type_, message), iprot.ReadStructEnd()
+	if err := iprot.ReadStructEnd(); err != nil {
+		return err
+	}
+
+	p.message = message
+	p.type_ = type_
+
+	return nil
 }
 
 func (p *tApplicationException) Write(oprot TProtocol) (err error) {
diff --git a/lib/go/thrift/application_exception_test.go b/lib/go/thrift/application_exception_test.go
index 7010f86..7743357 100644
--- a/lib/go/thrift/application_exception_test.go
+++ b/lib/go/thrift/application_exception_test.go
@@ -25,17 +25,17 @@
 
 func TestTApplicationException(t *testing.T) {
 	exc := NewTApplicationException(UNKNOWN_APPLICATION_EXCEPTION, "")
-	if exc.Error() != "" {
+	if exc.Error() != defaultApplicationExceptionMessage[UNKNOWN_APPLICATION_EXCEPTION] {
 		t.Fatalf("Expected empty string for exception but found '%s'", exc.Error())
 	}
 	if exc.TypeId() != UNKNOWN_APPLICATION_EXCEPTION {
-		t.Fatalf("Expected type UNKNOWN for exception but found '%s'", exc.TypeId())
+		t.Fatalf("Expected type UNKNOWN for exception but found '%v'", exc.TypeId())
 	}
 	exc = NewTApplicationException(WRONG_METHOD_NAME, "junk_method")
 	if exc.Error() != "junk_method" {
 		t.Fatalf("Expected 'junk_method' for exception but found '%s'", exc.Error())
 	}
 	if exc.TypeId() != WRONG_METHOD_NAME {
-		t.Fatalf("Expected type WRONG_METHOD_NAME for exception but found '%s'", exc.TypeId())
+		t.Fatalf("Expected type WRONG_METHOD_NAME for exception but found '%v'", exc.TypeId())
 	}
 }
diff --git a/lib/go/thrift/binary_protocol.go b/lib/go/thrift/binary_protocol.go
index b57b528..1f90bf4 100644
--- a/lib/go/thrift/binary_protocol.go
+++ b/lib/go/thrift/binary_protocol.go
@@ -20,17 +20,23 @@
 package thrift
 
 import (
+	"bytes"
+	"context"
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"io"
 	"math"
 )
 
 type TBinaryProtocol struct {
-	trans           TTransport
-	strictRead      bool
-	strictWrite     bool
-	buffer          [8]byte
+	trans         TRichTransport
+	origTransport TTransport
+	reader        io.Reader
+	writer        io.Writer
+	strictRead    bool
+	strictWrite   bool
+	buffer        [64]byte
 }
 
 type TBinaryProtocolFactory struct {
@@ -43,7 +49,15 @@
 }
 
 func NewTBinaryProtocol(t TTransport, strictRead, strictWrite bool) *TBinaryProtocol {
-	return &TBinaryProtocol{trans: t, strictRead: strictRead, strictWrite: strictWrite}
+	p := &TBinaryProtocol{origTransport: t, strictRead: strictRead, strictWrite: strictWrite}
+	if et, ok := t.(TRichTransport); ok {
+		p.trans = et
+	} else {
+		p.trans = NewTRichTransport(t)
+	}
+	p.reader = p.trans
+	p.writer = p.trans
+	return p
 }
 
 func NewTBinaryProtocolFactoryDefault() *TBinaryProtocolFactory {
@@ -80,7 +94,7 @@
 		if e != nil {
 			return e
 		}
-		e = p.WriteByte(byte(typeId))
+		e = p.WriteByte(int8(typeId))
 		if e != nil {
 			return e
 		}
@@ -103,7 +117,7 @@
 }
 
 func (p *TBinaryProtocol) WriteFieldBegin(name string, typeId TType, id int16) error {
-	e := p.WriteByte(byte(typeId))
+	e := p.WriteByte(int8(typeId))
 	if e != nil {
 		return e
 	}
@@ -121,11 +135,11 @@
 }
 
 func (p *TBinaryProtocol) WriteMapBegin(keyType TType, valueType TType, size int) error {
-	e := p.WriteByte(byte(keyType))
+	e := p.WriteByte(int8(keyType))
 	if e != nil {
 		return e
 	}
-	e = p.WriteByte(byte(valueType))
+	e = p.WriteByte(int8(valueType))
 	if e != nil {
 		return e
 	}
@@ -138,7 +152,7 @@
 }
 
 func (p *TBinaryProtocol) WriteListBegin(elemType TType, size int) error {
-	e := p.WriteByte(byte(elemType))
+	e := p.WriteByte(int8(elemType))
 	if e != nil {
 		return e
 	}
@@ -151,7 +165,7 @@
 }
 
 func (p *TBinaryProtocol) WriteSetBegin(elemType TType, size int) error {
-	e := p.WriteByte(byte(elemType))
+	e := p.WriteByte(int8(elemType))
 	if e != nil {
 		return e
 	}
@@ -170,30 +184,29 @@
 	return p.WriteByte(0)
 }
 
-func (p *TBinaryProtocol) WriteByte(value byte) error {
-	v := []byte{value}
-	_, e := p.trans.Write(v)
+func (p *TBinaryProtocol) WriteByte(value int8) error {
+	e := p.trans.WriteByte(byte(value))
 	return NewTProtocolException(e)
 }
 
 func (p *TBinaryProtocol) WriteI16(value int16) error {
 	v := p.buffer[0:2]
 	binary.BigEndian.PutUint16(v, uint16(value))
-	_, e := p.trans.Write(v)
+	_, e := p.writer.Write(v)
 	return NewTProtocolException(e)
 }
 
 func (p *TBinaryProtocol) WriteI32(value int32) error {
 	v := p.buffer[0:4]
 	binary.BigEndian.PutUint32(v, uint32(value))
-	_, e := p.trans.Write(v)
+	_, e := p.writer.Write(v)
 	return NewTProtocolException(e)
 }
 
 func (p *TBinaryProtocol) WriteI64(value int64) error {
-	v := p.buffer[:]
+	v := p.buffer[0:8]
 	binary.BigEndian.PutUint64(v, uint64(value))
-	_, err := p.trans.Write(v)
+	_, err := p.writer.Write(v)
 	return NewTProtocolException(err)
 }
 
@@ -202,7 +215,12 @@
 }
 
 func (p *TBinaryProtocol) WriteString(value string) error {
-	return p.WriteBinary([]byte(value))
+	e := p.WriteI32(int32(len(value)))
+	if e != nil {
+		return e
+	}
+	_, err := p.trans.WriteString(value)
+	return NewTProtocolException(err)
 }
 
 func (p *TBinaryProtocol) WriteBinary(value []byte) error {
@@ -210,7 +228,7 @@
 	if e != nil {
 		return e
 	}
-	_, err := p.trans.Write(value)
+	_, err := p.writer.Write(value)
 	return NewTProtocolException(err)
 }
 
@@ -242,7 +260,7 @@
 	if p.strictRead {
 		return name, typeId, seqId, NewTProtocolExceptionWithType(BAD_VERSION, fmt.Errorf("Missing version in ReadMessageBegin"))
 	}
-	name, e2 := p.readStringBody(int(size))
+	name, e2 := p.readStringBody(size)
 	if e2 != nil {
 		return name, typeId, seqId, e2
 	}
@@ -286,6 +304,8 @@
 	return nil
 }
 
+var invalidDataLength = NewTProtocolExceptionWithType(INVALID_DATA, errors.New("Invalid data length"))
+
 func (p *TBinaryProtocol) ReadMapBegin() (kType, vType TType, size int, err error) {
 	k, e := p.ReadByte()
 	if e != nil {
@@ -300,11 +320,15 @@
 	}
 	vType = TType(v)
 	size32, e := p.ReadI32()
-	size = int(size32)
 	if e != nil {
 		err = NewTProtocolException(e)
 		return
 	}
+	if size32 < 0 {
+		err = invalidDataLength
+		return
+	}
+	size = int(size32)
 	return kType, vType, size, nil
 }
 
@@ -320,12 +344,17 @@
 	}
 	elemType = TType(b)
 	size32, e := p.ReadI32()
-	size = int(size32)
 	if e != nil {
 		err = NewTProtocolException(e)
 		return
 	}
-	return elemType, size, nil
+	if size32 < 0 {
+		err = invalidDataLength
+		return
+	}
+	size = int(size32)
+
+	return
 }
 
 func (p *TBinaryProtocol) ReadListEnd() error {
@@ -340,11 +369,15 @@
 	}
 	elemType = TType(b)
 	size32, e := p.ReadI32()
-	size = int(size32)
 	if e != nil {
 		err = NewTProtocolException(e)
 		return
 	}
+	if size32 < 0 {
+		err = invalidDataLength
+		return
+	}
+	size = int(size32)
 	return elemType, size, nil
 }
 
@@ -361,10 +394,9 @@
 	return v, e
 }
 
-func (p *TBinaryProtocol) ReadByte() (value byte, err error) {
-	buf := p.buffer[0:1]
-	err = p.readAll(buf)
-	return buf[0], err
+func (p *TBinaryProtocol) ReadByte() (int8, error) {
+	v, err := p.trans.ReadByte()
+	return int8(v), err
 }
 
 func (p *TBinaryProtocol) ReadI16() (value int16, err error) {
@@ -400,7 +432,12 @@
 	if e != nil {
 		return "", e
 	}
-	return p.readStringBody(int(size))
+	if size < 0 {
+		err = invalidDataLength
+		return
+	}
+
+	return p.readStringBody(size)
 }
 
 func (p *TBinaryProtocol) ReadBinary() ([]byte, error) {
@@ -408,14 +445,18 @@
 	if e != nil {
 		return nil, e
 	}
+	if size < 0 {
+		return nil, invalidDataLength
+	}
+
 	isize := int(size)
 	buf := make([]byte, isize)
 	_, err := io.ReadFull(p.trans, buf)
 	return buf, NewTProtocolException(err)
 }
 
-func (p *TBinaryProtocol) Flush() (err error) {
-	return NewTProtocolException(p.trans.Flush())
+func (p *TBinaryProtocol) Flush(ctx context.Context) (err error) {
+	return NewTProtocolException(p.trans.Flush(ctx))
 }
 
 func (p *TBinaryProtocol) Skip(fieldType TType) (err error) {
@@ -423,20 +464,46 @@
 }
 
 func (p *TBinaryProtocol) Transport() TTransport {
-	return p.trans
+	return p.origTransport
 }
 
 func (p *TBinaryProtocol) readAll(buf []byte) error {
-	_, err := io.ReadFull(p.trans, buf)
+	_, err := io.ReadFull(p.reader, buf)
 	return NewTProtocolException(err)
 }
 
-func (p *TBinaryProtocol) readStringBody(size int) (value string, err error) {
+const readLimit = 32768
+
+func (p *TBinaryProtocol) readStringBody(size int32) (value string, err error) {
 	if size < 0 {
 		return "", nil
 	}
-	isize := int(size)
-	buf := make([]byte, isize)
-	_, e := io.ReadFull(p.trans, buf)
-	return string(buf), NewTProtocolException(e)
+
+	var (
+		buf bytes.Buffer
+		e   error
+		b   []byte
+	)
+
+	switch {
+	case int(size) <= len(p.buffer):
+		b = p.buffer[:size] // avoids allocation for small reads
+	case int(size) < readLimit:
+		b = make([]byte, size)
+	default:
+		b = make([]byte, readLimit)
+	}
+
+	for size > 0 {
+		_, e = io.ReadFull(p.trans, b)
+		buf.Write(b)
+		if e != nil {
+			break
+		}
+		size -= readLimit
+		if size < readLimit && size > 0 {
+			b = b[:size]
+		}
+	}
+	return buf.String(), NewTProtocolException(e)
 }
diff --git a/lib/go/thrift/buffered_transport.go b/lib/go/thrift/buffered_transport.go
index e3546a5..9670206 100644
--- a/lib/go/thrift/buffered_transport.go
+++ b/lib/go/thrift/buffered_transport.go
@@ -19,23 +19,22 @@
 
 package thrift
 
+import (
+	"bufio"
+	"context"
+)
+
 type TBufferedTransportFactory struct {
 	size int
 }
 
-type TBuffer struct {
-	buffer     []byte
-	pos, limit int
-}
-
 type TBufferedTransport struct {
-	tp   TTransport
-	rbuf *TBuffer
-	wbuf *TBuffer
+	bufio.ReadWriter
+	tp TTransport
 }
 
-func (p *TBufferedTransportFactory) GetTransport(trans TTransport) TTransport {
-	return NewTBufferedTransport(trans, p.size)
+func (p *TBufferedTransportFactory) GetTransport(trans TTransport) (TTransport, error) {
+	return NewTBufferedTransport(trans, p.size), nil
 }
 
 func NewTBufferedTransportFactory(bufferSize int) *TBufferedTransportFactory {
@@ -43,9 +42,13 @@
 }
 
 func NewTBufferedTransport(trans TTransport, bufferSize int) *TBufferedTransport {
-	rb := &TBuffer{buffer: make([]byte, bufferSize)}
-	wb := &TBuffer{buffer: make([]byte, bufferSize), limit: bufferSize}
-	return &TBufferedTransport{tp: trans, rbuf: rb, wbuf: wb}
+	return &TBufferedTransport{
+		ReadWriter: bufio.ReadWriter{
+			Reader: bufio.NewReaderSize(trans, bufferSize),
+			Writer: bufio.NewWriterSize(trans, bufferSize),
+		},
+		tp: trans,
+	}
 }
 
 func (p *TBufferedTransport) IsOpen() bool {
@@ -60,47 +63,30 @@
 	return p.tp.Close()
 }
 
-func (p *TBufferedTransport) Read(buf []byte) (n int, err error) {
-	rbuf := p.rbuf
-	if rbuf.pos == rbuf.limit { // no more data to read from buffer
-		rbuf.pos = 0
-		// read data, fill buffer
-		rbuf.limit, err = p.tp.Read(rbuf.buffer)
-		if err != nil {
-			return 0, err
-		}
+func (p *TBufferedTransport) Read(b []byte) (int, error) {
+	n, err := p.ReadWriter.Read(b)
+	if err != nil {
+		p.ReadWriter.Reader.Reset(p.tp)
 	}
-	n = copy(buf, rbuf.buffer[rbuf.pos:rbuf.limit])
-	rbuf.pos += n
-	return n, nil
+	return n, err
 }
 
-func (p *TBufferedTransport) Write(buf []byte) (n int, err error) {
-	wbuf := p.wbuf
-	size := len(buf)
-	if wbuf.pos+size > wbuf.limit { // buffer is full, flush buffer
-		p.Flush()
+func (p *TBufferedTransport) Write(b []byte) (int, error) {
+	n, err := p.ReadWriter.Write(b)
+	if err != nil {
+		p.ReadWriter.Writer.Reset(p.tp)
 	}
-	n = copy(wbuf.buffer[wbuf.pos:], buf)
-	wbuf.pos += n
-	return n, nil
+	return n, err
 }
 
-func (p *TBufferedTransport) Flush() error {
-	start := 0
-	wbuf := p.wbuf
-	for start < wbuf.pos {
-		n, err := p.tp.Write(wbuf.buffer[start:wbuf.pos])
-		if err != nil {
-			return err
-		}
-		start += n
+func (p *TBufferedTransport) Flush(ctx context.Context) error {
+	if err := p.ReadWriter.Flush(); err != nil {
+		p.ReadWriter.Writer.Reset(p.tp)
+		return err
 	}
-
-	wbuf.pos = 0
-	return p.tp.Flush()
+	return p.tp.Flush(ctx)
 }
 
-func (p *TBufferedTransport) Peek() bool {
-	return p.rbuf.pos < p.rbuf.limit || p.tp.Peek()
+func (p *TBufferedTransport) RemainingBytes() (num_bytes uint64) {
+	return p.tp.RemainingBytes()
 }
diff --git a/lib/go/thrift/client.go b/lib/go/thrift/client.go
new file mode 100644
index 0000000..28791cc
--- /dev/null
+++ b/lib/go/thrift/client.go
@@ -0,0 +1,85 @@
+package thrift
+
+import (
+	"context"
+	"fmt"
+)
+
+type TClient interface {
+	Call(ctx context.Context, method string, args, result TStruct) error
+}
+
+type TStandardClient struct {
+	seqId        int32
+	iprot, oprot TProtocol
+}
+
+// TStandardClient implements TClient, and uses the standard message format for Thrift.
+// It is not safe for concurrent use.
+func NewTStandardClient(inputProtocol, outputProtocol TProtocol) *TStandardClient {
+	return &TStandardClient{
+		iprot: inputProtocol,
+		oprot: outputProtocol,
+	}
+}
+
+func (p *TStandardClient) Send(ctx context.Context, oprot TProtocol, seqId int32, method string, args TStruct) error {
+	if err := oprot.WriteMessageBegin(method, CALL, seqId); err != nil {
+		return err
+	}
+	if err := args.Write(oprot); err != nil {
+		return err
+	}
+	if err := oprot.WriteMessageEnd(); err != nil {
+		return err
+	}
+	return oprot.Flush(ctx)
+}
+
+func (p *TStandardClient) Recv(iprot TProtocol, seqId int32, method string, result TStruct) error {
+	rMethod, rTypeId, rSeqId, err := iprot.ReadMessageBegin()
+	if err != nil {
+		return err
+	}
+
+	if method != rMethod {
+		return NewTApplicationException(WRONG_METHOD_NAME, fmt.Sprintf("%s: wrong method name", method))
+	} else if seqId != rSeqId {
+		return NewTApplicationException(BAD_SEQUENCE_ID, fmt.Sprintf("%s: out of order sequence response", method))
+	} else if rTypeId == EXCEPTION {
+		var exception tApplicationException
+		if err := exception.Read(iprot); err != nil {
+			return err
+		}
+
+		if err := iprot.ReadMessageEnd(); err != nil {
+			return err
+		}
+
+		return &exception
+	} else if rTypeId != REPLY {
+		return NewTApplicationException(INVALID_MESSAGE_TYPE_EXCEPTION, fmt.Sprintf("%s: invalid message type", method))
+	}
+
+	if err := result.Read(iprot); err != nil {
+		return err
+	}
+
+	return iprot.ReadMessageEnd()
+}
+
+func (p *TStandardClient) Call(ctx context.Context, method string, args, result TStruct) error {
+	p.seqId++
+	seqId := p.seqId
+
+	if err := p.Send(ctx, p.oprot, seqId, method, args); err != nil {
+		return err
+	}
+
+	// method is oneway
+	if result == nil {
+		return nil
+	}
+
+	return p.Recv(p.iprot, seqId, method, result)
+}
diff --git a/lib/go/thrift/common_test.go b/lib/go/thrift/common_test.go
new file mode 100644
index 0000000..93597ff
--- /dev/null
+++ b/lib/go/thrift/common_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
+
+import "context"
+
+type mockProcessor struct {
+	ProcessFunc func(in, out TProtocol) (bool, TException)
+}
+
+func (m *mockProcessor) Process(ctx context.Context, in, out TProtocol) (bool, TException) {
+	return m.ProcessFunc(in, out)
+}
diff --git a/lib/go/thrift/compact_protocol.go b/lib/go/thrift/compact_protocol.go
index ba5f722..1900d50 100644
--- a/lib/go/thrift/compact_protocol.go
+++ b/lib/go/thrift/compact_protocol.go
@@ -20,11 +20,11 @@
 package thrift
 
 import (
+	"context"
 	"encoding/binary"
 	"fmt"
 	"io"
 	"math"
-	"strings"
 )
 
 const (
@@ -32,6 +32,7 @@
 	COMPACT_VERSION           = 1
 	COMPACT_VERSION_MASK      = 0x1f
 	COMPACT_TYPE_MASK         = 0x0E0
+	COMPACT_TYPE_BITS         = 0x07
 	COMPACT_TYPE_SHIFT_AMOUNT = 5
 )
 
@@ -84,7 +85,8 @@
 }
 
 type TCompactProtocol struct {
-	trans TTransport
+	trans         TRichTransport
+	origTransport TTransport
 
 	// Used to keep track of the last field for the current and previous structs,
 	// so we can do the delta stuff.
@@ -93,17 +95,28 @@
 
 	// If we encounter a boolean field begin, save the TField here so it can
 	// have the value incorporated.
-	booleanField *field
+	booleanFieldName    string
+	booleanFieldId      int16
+	booleanFieldPending bool
 
 	// 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
+	buffer             [64]byte
 }
 
 // Create a TCompactProtocol given a TTransport
 func NewTCompactProtocol(trans TTransport) *TCompactProtocol {
-	return &TCompactProtocol{trans: trans, lastField: []int{}}
+	p := &TCompactProtocol{origTransport: trans, lastField: []int{}}
+	if et, ok := trans.(TRichTransport); ok {
+		p.trans = et
+	} else {
+		p.trans = NewTRichTransport(trans)
+	}
+
+	return p
+
 }
 
 //
@@ -113,11 +126,11 @@
 // 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) error {
-	_, err := p.writeByteDirect(COMPACT_PROTOCOL_ID)
+	err := p.writeByteDirect(COMPACT_PROTOCOL_ID)
 	if err != nil {
 		return NewTProtocolException(err)
 	}
-	_, err = p.writeByteDirect((COMPACT_VERSION & COMPACT_VERSION_MASK) | ((byte(typeId) << COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_MASK))
+	err = p.writeByteDirect((COMPACT_VERSION & COMPACT_VERSION_MASK) | ((byte(typeId) << COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_MASK))
 	if err != nil {
 		return NewTProtocolException(err)
 	}
@@ -153,7 +166,7 @@
 func (p *TCompactProtocol) WriteFieldBegin(name string, typeId TType, id int16) error {
 	if typeId == BOOL {
 		// we want to possibly include the value, so we'll wait.
-		p.booleanField = newField(name, typeId, int(id))
+		p.booleanFieldName, p.booleanFieldId, p.booleanFieldPending = name, id, true
 		return nil
 	}
 	_, err := p.writeFieldBeginInternal(name, typeId, id, 0xFF)
@@ -178,20 +191,20 @@
 	written := 0
 	if fieldId > p.lastFieldId && fieldId-p.lastFieldId <= 15 {
 		// write them together
-		written, err := p.writeByteDirect(byte((fieldId-p.lastFieldId)<<4) | typeToWrite)
+		err := p.writeByteDirect(byte((fieldId-p.lastFieldId)<<4) | typeToWrite)
 		if err != nil {
-			return written, err
+			return 0, err
 		}
 	} else {
 		// write them separate
-		n, err := p.writeByteDirect(typeToWrite)
+		err := p.writeByteDirect(typeToWrite)
 		if err != nil {
-			return n, err
+			return 0, err
 		}
 		err = p.WriteI16(id)
-		written = n + 2
+		written = 1 + 2
 		if err != nil {
-			return written, err
+			return 0, err
 		}
 	}
 
@@ -203,20 +216,20 @@
 func (p *TCompactProtocol) WriteFieldEnd() error { return nil }
 
 func (p *TCompactProtocol) WriteFieldStop() error {
-	_, err := p.writeByteDirect(STOP)
+	err := p.writeByteDirect(STOP)
 	return NewTProtocolException(err)
 }
 
 func (p *TCompactProtocol) WriteMapBegin(keyType TType, valueType TType, size int) error {
 	if size == 0 {
-		_, err := p.writeByteDirect(0)
+		err := p.writeByteDirect(0)
 		return NewTProtocolException(err)
 	}
 	_, err := p.writeVarint32(int32(size))
 	if err != nil {
 		return NewTProtocolException(err)
 	}
-	_, err = p.writeByteDirect(byte(p.getCompactType(keyType))<<4 | byte(p.getCompactType(valueType)))
+	err = p.writeByteDirect(byte(p.getCompactType(keyType))<<4 | byte(p.getCompactType(valueType)))
 	return NewTProtocolException(err)
 }
 
@@ -243,20 +256,20 @@
 	if value {
 		v = byte(COMPACT_BOOLEAN_TRUE)
 	}
-	if p.booleanField != nil {
+	if p.booleanFieldPending {
 		// 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
+		_, err := p.writeFieldBeginInternal(p.booleanFieldName, BOOL, p.booleanFieldId, v)
+		p.booleanFieldPending = false
 		return NewTProtocolException(err)
 	}
 	// we're not part of a field, so just write the value.
-	_, err := p.writeByteDirect(v)
+	err := p.writeByteDirect(v)
 	return NewTProtocolException(err)
 }
 
 // Write a byte. Nothing to see here!
-func (p *TCompactProtocol) WriteByte(value byte) error {
-	_, err := p.writeByteDirect(value)
+func (p *TCompactProtocol) WriteByte(value int8) error {
+	err := p.writeByteDirect(byte(value))
 	return NewTProtocolException(err)
 }
 
@@ -280,17 +293,22 @@
 
 // Write a double to the wire as 8 bytes.
 func (p *TCompactProtocol) WriteDouble(value float64) error {
-	buf := make([]byte, 8)
+	buf := p.buffer[0:8]
 	binary.LittleEndian.PutUint64(buf, math.Float64bits(value))
 	_, err := p.trans.Write(buf)
 	return NewTProtocolException(err)
 }
 
-// Write a string to the wire with a varint size preceeding.
+// Write a string to the wire with a varint size preceding.
 func (p *TCompactProtocol) WriteString(value string) error {
-	buf := make([]byte, len(value))
-	strings.NewReader(value).Read(buf)
-	return p.WriteBinary(buf)
+	_, e := p.writeVarint32(int32(len(value)))
+	if e != nil {
+		return NewTProtocolException(e)
+	}
+	if len(value) > 0 {
+	}
+	_, e = p.trans.WriteString(value)
+	return e
 }
 
 // Write a byte array, using a varint for the size.
@@ -312,17 +330,24 @@
 
 // Read a message header.
 func (p *TCompactProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err error) {
-	protocolId, err := p.ReadByte()
+
+	protocolId, err := p.readByteDirect()
+	if err != nil {
+		return
+	}
+
 	if protocolId != COMPACT_PROTOCOL_ID {
 		e := fmt.Errorf("Expected protocol id %02x but got %02x", COMPACT_PROTOCOL_ID, protocolId)
 		return "", typeId, seqId, NewTProtocolExceptionWithType(BAD_VERSION, e)
 	}
-	versionAndType, err := p.ReadByte()
-	version := versionAndType & COMPACT_VERSION_MASK
-	typeId = TMessageType((versionAndType >> COMPACT_TYPE_SHIFT_AMOUNT) & 0x03)
+
+	versionAndType, err := p.readByteDirect()
 	if err != nil {
 		return
 	}
+
+	version := versionAndType & COMPACT_VERSION_MASK
+	typeId = TMessageType((versionAndType >> COMPACT_TYPE_SHIFT_AMOUNT) & COMPACT_TYPE_BITS)
 	if version != COMPACT_VERSION {
 		e := fmt.Errorf("Expected version %02x but got %02x", COMPACT_VERSION, version)
 		err = NewTProtocolExceptionWithType(BAD_VERSION, e)
@@ -352,19 +377,20 @@
 func (p *TCompactProtocol) ReadStructEnd() error {
 	// consume the last field we read off the wire.
 	p.lastFieldId = p.lastField[len(p.lastField)-1]
+	p.lastField = p.lastField[:len(p.lastField)-1]
 	return nil
 }
 
 // Read a field header off the wire.
 func (p *TCompactProtocol) ReadFieldBegin() (name string, typeId TType, id int16, err error) {
-	t, err := p.ReadByte()
+	t, err := p.readByteDirect()
 	if err != nil {
 		return
 	}
 
 	// if it's a stop, then we can return immediately, as the struct is over.
 	if (t & 0x0f) == STOP {
-		return "", STOP, 0,nil
+		return "", STOP, 0, nil
 	}
 
 	// mask off the 4 MSB of the type header. it could contain a field id delta.
@@ -404,14 +430,19 @@
 // "correct" types.
 func (p *TCompactProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, err error) {
 	size32, e := p.readVarint32()
-	size = int(size32)
 	if e != nil {
 		err = NewTProtocolException(e)
 		return
 	}
+	if size32 < 0 {
+		err = invalidDataLength
+		return
+	}
+	size = int(size32)
+
 	keyAndValueType := byte(STOP)
 	if size != 0 {
-		keyAndValueType, err = p.ReadByte()
+		keyAndValueType, err = p.readByteDirect()
 		if err != nil {
 			return
 		}
@@ -428,7 +459,7 @@
 // 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 error) {
-	size_and_type, err := p.ReadByte()
+	size_and_type, err := p.readByteDirect()
 	if err != nil {
 		return
 	}
@@ -439,6 +470,10 @@
 			err = NewTProtocolException(e)
 			return
 		}
+		if size2 < 0 {
+			err = invalidDataLength
+			return
+		}
 		size = int(size2)
 	}
 	elemType, e := p.getTType(tCompactType(size_and_type))
@@ -469,18 +504,17 @@
 		p.boolValueIsNotNull = false
 		return p.boolValue, nil
 	}
-	v, err := p.ReadByte()
+	v, err := p.readByteDirect()
 	return v == COMPACT_BOOLEAN_TRUE, err
 }
 
 // Read a single byte off the wire. Nothing interesting here.
-func (p *TCompactProtocol) ReadByte() (value byte, err error) {
-	buf := []byte{0}
-	_, e := io.ReadFull(p.trans, buf)
-	if e != nil {
-		return 0, NewTProtocolException(e)
+func (p *TCompactProtocol) ReadByte() (int8, error) {
+	v, err := p.readByteDirect()
+	if err != nil {
+		return 0, NewTProtocolException(err)
 	}
-	return buf[0], nil
+	return int8(v), err
 }
 
 // Read an i16 from the wire as a zigzag varint.
@@ -511,7 +545,7 @@
 
 // No magic here - just read a double off the wire.
 func (p *TCompactProtocol) ReadDouble() (value float64, err error) {
-	longBits := make([]byte, 8)
+	longBits := p.buffer[0:8]
 	_, e := io.ReadFull(p.trans, longBits)
 	if e != nil {
 		return 0.0, NewTProtocolException(e)
@@ -521,27 +555,47 @@
 
 // Reads a []byte (via readBinary), and then UTF-8 decodes it.
 func (p *TCompactProtocol) ReadString() (value string, err error) {
-	v, e := p.ReadBinary()
-	return string(v), NewTProtocolException(e)
+	length, e := p.readVarint32()
+	if e != nil {
+		return "", NewTProtocolException(e)
+	}
+	if length < 0 {
+		return "", invalidDataLength
+	}
+
+	if length == 0 {
+		return "", nil
+	}
+	var buf []byte
+	if length <= int32(len(p.buffer)) {
+		buf = p.buffer[0:length]
+	} else {
+		buf = make([]byte, length)
+	}
+	_, e = io.ReadFull(p.trans, buf)
+	return string(buf), NewTProtocolException(e)
 }
 
 // Read a []byte from the wire.
 func (p *TCompactProtocol) ReadBinary() (value []byte, err error) {
 	length, e := p.readVarint32()
 	if e != nil {
-		return []byte{}, NewTProtocolException(e)
+		return nil, NewTProtocolException(e)
 	}
 	if length == 0 {
 		return []byte{}, nil
 	}
+	if length < 0 {
+		return nil, invalidDataLength
+	}
 
 	buf := make([]byte, length)
 	_, e = io.ReadFull(p.trans, buf)
 	return buf, NewTProtocolException(e)
 }
 
-func (p *TCompactProtocol) Flush() (err error) {
-	return NewTProtocolException(p.trans.Flush())
+func (p *TCompactProtocol) Flush(ctx context.Context) (err error) {
+	return NewTProtocolException(p.trans.Flush(ctx))
 }
 
 func (p *TCompactProtocol) Skip(fieldType TType) (err error) {
@@ -549,7 +603,7 @@
 }
 
 func (p *TCompactProtocol) Transport() TTransport {
-	return p.trans
+	return p.origTransport
 }
 
 //
@@ -560,20 +614,20 @@
 // the wire differ only by the type indicator.
 func (p *TCompactProtocol) writeCollectionBegin(elemType TType, size int) (int, error) {
 	if size <= 14 {
-		return p.writeByteDirect(byte(int32(size<<4) | int32(p.getCompactType(elemType))))
+		return 1, p.writeByteDirect(byte(int32(size<<4) | int32(p.getCompactType(elemType))))
 	}
-	n, err := p.writeByteDirect(0xf0 | byte(p.getCompactType(elemType)))
+	err := p.writeByteDirect(0xf0 | byte(p.getCompactType(elemType)))
 	if err != nil {
-		return n, err
+		return 0, err
 	}
 	m, err := p.writeVarint32(int32(size))
-	return n + m, err
+	return 1 + 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, error) {
-	i32buf := make([]byte, 5)
+	i32buf := p.buffer[0:5]
 	idx := 0
 	for {
 		if (n & ^0x7F) == 0 {
@@ -595,7 +649,7 @@
 
 // Write an i64 as a varint. Results in 1-10 bytes on the wire.
 func (p *TCompactProtocol) writeVarint64(n int64) (int, error) {
-	varint64out := make([]byte, 10)
+	varint64out := p.buffer[0:10]
 	idx := 0
 	for {
 		if (n & ^0x7F) == 0 {
@@ -632,15 +686,15 @@
 	binary.LittleEndian.PutUint64(buf, uint64(n))
 }
 
-// Writes a byte without any possiblity of all that field header nonsense.
+// Writes a byte without any possibility 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, error) {
-	return p.trans.Write([]byte{b})
+func (p *TCompactProtocol) writeByteDirect(b byte) error {
+	return p.trans.WriteByte(b)
 }
 
-// Writes a byte without any possiblity of all that field header nonsense.
+// Writes a byte without any possibility of all that field header nonsense.
 func (p *TCompactProtocol) writeIntAsByteDirect(n int) (int, error) {
-	return p.writeByteDirect(byte(n))
+	return 1, p.writeByteDirect(byte(n))
 }
 
 //
@@ -662,7 +716,7 @@
 	shift := uint(0)
 	result := int64(0)
 	for {
-		b, err := p.ReadByte()
+		b, err := p.readByteDirect()
 		if err != nil {
 			return 0, err
 		}
@@ -675,6 +729,11 @@
 	return result, nil
 }
 
+// Read a byte, unlike ReadByte that reads Thrift-byte that is i8.
+func (p *TCompactProtocol) readByteDirect() (byte, error) {
+	return p.trans.ReadByte()
+}
+
 //
 // encoding helpers
 //
@@ -719,8 +778,7 @@
 	switch byte(t) & 0x0f {
 	case STOP:
 		return STOP, nil
-	case COMPACT_BOOLEAN_FALSE:
-	case COMPACT_BOOLEAN_TRUE:
+	case COMPACT_BOOLEAN_FALSE, COMPACT_BOOLEAN_TRUE:
 		return BOOL, nil
 	case COMPACT_BYTE:
 		return BYTE, nil
@@ -743,7 +801,7 @@
 	case COMPACT_STRUCT:
 		return STRUCT, nil
 	}
-	return STOP, TException(fmt.Errorf("don't know what type: %s", t&0x0f))
+	return STOP, TException(fmt.Errorf("don't know what type: %v", t&0x0f))
 }
 
 // Given a TType value, find the appropriate TCompactProtocol.Types constant.
diff --git a/lib/go/thrift/compact_protocol_test.go b/lib/go/thrift/compact_protocol_test.go
index c874379..65f77f2 100644
--- a/lib/go/thrift/compact_protocol_test.go
+++ b/lib/go/thrift/compact_protocol_test.go
@@ -20,35 +20,41 @@
 package thrift
 
 import (
+	"bytes"
 	"testing"
 )
 
 func TestReadWriteCompactProtocol(t *testing.T) {
 	ReadWriteProtocolTest(t, NewTCompactProtocolFactory())
-	/*
-	   transports := []TTransport{
-	     NewTMemoryBuffer(),
-	     NewStreamTransportRW(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();
-	   }
-	*/
+
+	transports := []TTransport{
+		NewTMemoryBuffer(),
+		NewStreamTransportRW(bytes.NewBuffer(make([]byte, 0, 16384))),
+		NewTFramedTransport(NewTMemoryBuffer()),
+	}
+
+	zlib0, _ := NewTZlibTransport(NewTMemoryBuffer(), 0)
+	zlib6, _ := NewTZlibTransport(NewTMemoryBuffer(), 6)
+	zlib9, _ := NewTZlibTransport(NewTFramedTransport(NewTMemoryBuffer()), 9)
+	transports = append(transports, zlib0, zlib6, zlib9)
+
+	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/context.go b/lib/go/thrift/context.go
new file mode 100644
index 0000000..d15c1bc
--- /dev/null
+++ b/lib/go/thrift/context.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
+
+import "context"
+
+var defaultCtx = context.Background()
diff --git a/lib/go/thrift/debug_protocol.go b/lib/go/thrift/debug_protocol.go
new file mode 100644
index 0000000..57943e0
--- /dev/null
+++ b/lib/go/thrift/debug_protocol.go
@@ -0,0 +1,270 @@
+/*
+ * 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 (
+	"context"
+	"log"
+)
+
+type TDebugProtocol struct {
+	Delegate  TProtocol
+	LogPrefix string
+}
+
+type TDebugProtocolFactory struct {
+	Underlying TProtocolFactory
+	LogPrefix  string
+}
+
+func NewTDebugProtocolFactory(underlying TProtocolFactory, logPrefix string) *TDebugProtocolFactory {
+	return &TDebugProtocolFactory{
+		Underlying: underlying,
+		LogPrefix:  logPrefix,
+	}
+}
+
+func (t *TDebugProtocolFactory) GetProtocol(trans TTransport) TProtocol {
+	return &TDebugProtocol{
+		Delegate:  t.Underlying.GetProtocol(trans),
+		LogPrefix: t.LogPrefix,
+	}
+}
+
+func (tdp *TDebugProtocol) WriteMessageBegin(name string, typeId TMessageType, seqid int32) error {
+	err := tdp.Delegate.WriteMessageBegin(name, typeId, seqid)
+	log.Printf("%sWriteMessageBegin(name=%#v, typeId=%#v, seqid=%#v) => %#v", tdp.LogPrefix, name, typeId, seqid, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteMessageEnd() error {
+	err := tdp.Delegate.WriteMessageEnd()
+	log.Printf("%sWriteMessageEnd() => %#v", tdp.LogPrefix, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteStructBegin(name string) error {
+	err := tdp.Delegate.WriteStructBegin(name)
+	log.Printf("%sWriteStructBegin(name=%#v) => %#v", tdp.LogPrefix, name, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteStructEnd() error {
+	err := tdp.Delegate.WriteStructEnd()
+	log.Printf("%sWriteStructEnd() => %#v", tdp.LogPrefix, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteFieldBegin(name string, typeId TType, id int16) error {
+	err := tdp.Delegate.WriteFieldBegin(name, typeId, id)
+	log.Printf("%sWriteFieldBegin(name=%#v, typeId=%#v, id%#v) => %#v", tdp.LogPrefix, name, typeId, id, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteFieldEnd() error {
+	err := tdp.Delegate.WriteFieldEnd()
+	log.Printf("%sWriteFieldEnd() => %#v", tdp.LogPrefix, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteFieldStop() error {
+	err := tdp.Delegate.WriteFieldStop()
+	log.Printf("%sWriteFieldStop() => %#v", tdp.LogPrefix, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteMapBegin(keyType TType, valueType TType, size int) error {
+	err := tdp.Delegate.WriteMapBegin(keyType, valueType, size)
+	log.Printf("%sWriteMapBegin(keyType=%#v, valueType=%#v, size=%#v) => %#v", tdp.LogPrefix, keyType, valueType, size, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteMapEnd() error {
+	err := tdp.Delegate.WriteMapEnd()
+	log.Printf("%sWriteMapEnd() => %#v", tdp.LogPrefix, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteListBegin(elemType TType, size int) error {
+	err := tdp.Delegate.WriteListBegin(elemType, size)
+	log.Printf("%sWriteListBegin(elemType=%#v, size=%#v) => %#v", tdp.LogPrefix, elemType, size, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteListEnd() error {
+	err := tdp.Delegate.WriteListEnd()
+	log.Printf("%sWriteListEnd() => %#v", tdp.LogPrefix, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteSetBegin(elemType TType, size int) error {
+	err := tdp.Delegate.WriteSetBegin(elemType, size)
+	log.Printf("%sWriteSetBegin(elemType=%#v, size=%#v) => %#v", tdp.LogPrefix, elemType, size, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteSetEnd() error {
+	err := tdp.Delegate.WriteSetEnd()
+	log.Printf("%sWriteSetEnd() => %#v", tdp.LogPrefix, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteBool(value bool) error {
+	err := tdp.Delegate.WriteBool(value)
+	log.Printf("%sWriteBool(value=%#v) => %#v", tdp.LogPrefix, value, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteByte(value int8) error {
+	err := tdp.Delegate.WriteByte(value)
+	log.Printf("%sWriteByte(value=%#v) => %#v", tdp.LogPrefix, value, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteI16(value int16) error {
+	err := tdp.Delegate.WriteI16(value)
+	log.Printf("%sWriteI16(value=%#v) => %#v", tdp.LogPrefix, value, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteI32(value int32) error {
+	err := tdp.Delegate.WriteI32(value)
+	log.Printf("%sWriteI32(value=%#v) => %#v", tdp.LogPrefix, value, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteI64(value int64) error {
+	err := tdp.Delegate.WriteI64(value)
+	log.Printf("%sWriteI64(value=%#v) => %#v", tdp.LogPrefix, value, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteDouble(value float64) error {
+	err := tdp.Delegate.WriteDouble(value)
+	log.Printf("%sWriteDouble(value=%#v) => %#v", tdp.LogPrefix, value, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteString(value string) error {
+	err := tdp.Delegate.WriteString(value)
+	log.Printf("%sWriteString(value=%#v) => %#v", tdp.LogPrefix, value, err)
+	return err
+}
+func (tdp *TDebugProtocol) WriteBinary(value []byte) error {
+	err := tdp.Delegate.WriteBinary(value)
+	log.Printf("%sWriteBinary(value=%#v) => %#v", tdp.LogPrefix, value, err)
+	return err
+}
+
+func (tdp *TDebugProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqid int32, err error) {
+	name, typeId, seqid, err = tdp.Delegate.ReadMessageBegin()
+	log.Printf("%sReadMessageBegin() (name=%#v, typeId=%#v, seqid=%#v, err=%#v)", tdp.LogPrefix, name, typeId, seqid, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadMessageEnd() (err error) {
+	err = tdp.Delegate.ReadMessageEnd()
+	log.Printf("%sReadMessageEnd() err=%#v", tdp.LogPrefix, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadStructBegin() (name string, err error) {
+	name, err = tdp.Delegate.ReadStructBegin()
+	log.Printf("%sReadStructBegin() (name%#v, err=%#v)", tdp.LogPrefix, name, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadStructEnd() (err error) {
+	err = tdp.Delegate.ReadStructEnd()
+	log.Printf("%sReadStructEnd() err=%#v", tdp.LogPrefix, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadFieldBegin() (name string, typeId TType, id int16, err error) {
+	name, typeId, id, err = tdp.Delegate.ReadFieldBegin()
+	log.Printf("%sReadFieldBegin() (name=%#v, typeId=%#v, id=%#v, err=%#v)", tdp.LogPrefix, name, typeId, id, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadFieldEnd() (err error) {
+	err = tdp.Delegate.ReadFieldEnd()
+	log.Printf("%sReadFieldEnd() err=%#v", tdp.LogPrefix, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, err error) {
+	keyType, valueType, size, err = tdp.Delegate.ReadMapBegin()
+	log.Printf("%sReadMapBegin() (keyType=%#v, valueType=%#v, size=%#v, err=%#v)", tdp.LogPrefix, keyType, valueType, size, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadMapEnd() (err error) {
+	err = tdp.Delegate.ReadMapEnd()
+	log.Printf("%sReadMapEnd() err=%#v", tdp.LogPrefix, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadListBegin() (elemType TType, size int, err error) {
+	elemType, size, err = tdp.Delegate.ReadListBegin()
+	log.Printf("%sReadListBegin() (elemType=%#v, size=%#v, err=%#v)", tdp.LogPrefix, elemType, size, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadListEnd() (err error) {
+	err = tdp.Delegate.ReadListEnd()
+	log.Printf("%sReadListEnd() err=%#v", tdp.LogPrefix, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadSetBegin() (elemType TType, size int, err error) {
+	elemType, size, err = tdp.Delegate.ReadSetBegin()
+	log.Printf("%sReadSetBegin() (elemType=%#v, size=%#v, err=%#v)", tdp.LogPrefix, elemType, size, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadSetEnd() (err error) {
+	err = tdp.Delegate.ReadSetEnd()
+	log.Printf("%sReadSetEnd() err=%#v", tdp.LogPrefix, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadBool() (value bool, err error) {
+	value, err = tdp.Delegate.ReadBool()
+	log.Printf("%sReadBool() (value=%#v, err=%#v)", tdp.LogPrefix, value, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadByte() (value int8, err error) {
+	value, err = tdp.Delegate.ReadByte()
+	log.Printf("%sReadByte() (value=%#v, err=%#v)", tdp.LogPrefix, value, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadI16() (value int16, err error) {
+	value, err = tdp.Delegate.ReadI16()
+	log.Printf("%sReadI16() (value=%#v, err=%#v)", tdp.LogPrefix, value, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadI32() (value int32, err error) {
+	value, err = tdp.Delegate.ReadI32()
+	log.Printf("%sReadI32() (value=%#v, err=%#v)", tdp.LogPrefix, value, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadI64() (value int64, err error) {
+	value, err = tdp.Delegate.ReadI64()
+	log.Printf("%sReadI64() (value=%#v, err=%#v)", tdp.LogPrefix, value, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadDouble() (value float64, err error) {
+	value, err = tdp.Delegate.ReadDouble()
+	log.Printf("%sReadDouble() (value=%#v, err=%#v)", tdp.LogPrefix, value, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadString() (value string, err error) {
+	value, err = tdp.Delegate.ReadString()
+	log.Printf("%sReadString() (value=%#v, err=%#v)", tdp.LogPrefix, value, err)
+	return
+}
+func (tdp *TDebugProtocol) ReadBinary() (value []byte, err error) {
+	value, err = tdp.Delegate.ReadBinary()
+	log.Printf("%sReadBinary() (value=%#v, err=%#v)", tdp.LogPrefix, value, err)
+	return
+}
+func (tdp *TDebugProtocol) Skip(fieldType TType) (err error) {
+	err = tdp.Delegate.Skip(fieldType)
+	log.Printf("%sSkip(fieldType=%#v) (err=%#v)", tdp.LogPrefix, fieldType, err)
+	return
+}
+func (tdp *TDebugProtocol) Flush(ctx context.Context) (err error) {
+	err = tdp.Delegate.Flush(ctx)
+	log.Printf("%sFlush() (err=%#v)", tdp.LogPrefix, err)
+	return
+}
+
+func (tdp *TDebugProtocol) Transport() TTransport {
+	return tdp.Delegate.Transport()
+}
diff --git a/lib/go/thrift/deserializer.go b/lib/go/thrift/deserializer.go
new file mode 100644
index 0000000..91a0983
--- /dev/null
+++ b/lib/go/thrift/deserializer.go
@@ -0,0 +1,58 @@
+/*
+ * 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 TDeserializer struct {
+	Transport TTransport
+	Protocol  TProtocol
+}
+
+func NewTDeserializer() *TDeserializer {
+	var transport TTransport
+	transport = NewTMemoryBufferLen(1024)
+
+	protocol := NewTBinaryProtocolFactoryDefault().GetProtocol(transport)
+
+	return &TDeserializer{
+		transport,
+		protocol}
+}
+
+func (t *TDeserializer) ReadString(msg TStruct, s string) (err error) {
+	err = nil
+	if _, err = t.Transport.Write([]byte(s)); err != nil {
+		return
+	}
+	if err = msg.Read(t.Protocol); err != nil {
+		return
+	}
+	return
+}
+
+func (t *TDeserializer) Read(msg TStruct, b []byte) (err error) {
+	err = nil
+	if _, err = t.Transport.Write(b); err != nil {
+		return
+	}
+	if err = msg.Read(t.Protocol); err != nil {
+		return
+	}
+	return
+}
diff --git a/lib/go/thrift/exception.go b/lib/go/thrift/exception.go
index e08ffc0..ea8d6f6 100644
--- a/lib/go/thrift/exception.go
+++ b/lib/go/thrift/exception.go
@@ -19,7 +19,26 @@
 
 package thrift
 
+import (
+	"errors"
+)
+
 // Generic Thrift exception
 type TException interface {
 	error
 }
+
+// Prepends additional information to an error without losing the Thrift exception interface
+func PrependError(prepend string, err error) error {
+	if t, ok := err.(TTransportException); ok {
+		return NewTTransportException(t.TypeId(), prepend+t.Error())
+	}
+	if t, ok := err.(TProtocolException); ok {
+		return NewTProtocolExceptionWithType(t.TypeId(), errors.New(prepend+err.Error()))
+	}
+	if t, ok := err.(TApplicationException); ok {
+		return NewTApplicationException(t.TypeId(), prepend+t.Error())
+	}
+
+	return errors.New(prepend + err.Error())
+}
diff --git a/lib/go/thrift/exception_test.go b/lib/go/thrift/exception_test.go
new file mode 100644
index 0000000..71f5e2c
--- /dev/null
+++ b/lib/go/thrift/exception_test.go
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift
+
+import (
+	"errors"
+	"testing"
+)
+
+func TestPrependError(t *testing.T) {
+	err := NewTApplicationException(INTERNAL_ERROR, "original error")
+	err2, ok := PrependError("Prepend: ", err).(TApplicationException)
+	if !ok {
+		t.Fatal("Couldn't cast error TApplicationException")
+	}
+	if err2.Error() != "Prepend: original error" {
+		t.Fatal("Unexpected error string")
+	}
+	if err2.TypeId() != INTERNAL_ERROR {
+		t.Fatal("Unexpected type error")
+	}
+
+	err3 := NewTProtocolExceptionWithType(INVALID_DATA, errors.New("original error"))
+	err4, ok := PrependError("Prepend: ", err3).(TProtocolException)
+	if !ok {
+		t.Fatal("Couldn't cast error TProtocolException")
+	}
+	if err4.Error() != "Prepend: original error" {
+		t.Fatal("Unexpected error string")
+	}
+	if err4.TypeId() != INVALID_DATA {
+		t.Fatal("Unexpected type error")
+	}
+
+	err5 := NewTTransportException(TIMED_OUT, "original error")
+	err6, ok := PrependError("Prepend: ", err5).(TTransportException)
+	if !ok {
+		t.Fatal("Couldn't cast error TTransportException")
+	}
+	if err6.Error() != "Prepend: original error" {
+		t.Fatal("Unexpected error string")
+	}
+	if err6.TypeId() != TIMED_OUT {
+		t.Fatal("Unexpected type error")
+	}
+
+	err7 := errors.New("original error")
+	err8 := PrependError("Prepend: ", err7)
+	if err8.Error() != "Prepend: original error" {
+		t.Fatal("Unexpected error string")
+	}
+}
diff --git a/lib/go/thrift/framed_transport.go b/lib/go/thrift/framed_transport.go
index 3a59e7b..81fa65a 100644
--- a/lib/go/thrift/framed_transport.go
+++ b/lib/go/thrift/framed_transport.go
@@ -20,33 +20,52 @@
 package thrift
 
 import (
+	"bufio"
 	"bytes"
+	"context"
 	"encoding/binary"
+	"fmt"
 	"io"
 )
 
+const DEFAULT_MAX_LENGTH = 16384000
+
 type TFramedTransport struct {
-	transport   TTransport
-	writeBuffer *bytes.Buffer
-	readBuffer  *bytes.Buffer
+	transport TTransport
+	buf       bytes.Buffer
+	reader    *bufio.Reader
+	frameSize uint32 //Current remaining size of the frame. if ==0 read next frame header
+	buffer    [4]byte
+	maxLength uint32
 }
 
 type tFramedTransportFactory struct {
-	factory TTransportFactory
+	factory   TTransportFactory
+	maxLength uint32
 }
 
 func NewTFramedTransportFactory(factory TTransportFactory) TTransportFactory {
-	return &tFramedTransportFactory{factory: factory}
+	return &tFramedTransportFactory{factory: factory, maxLength: DEFAULT_MAX_LENGTH}
 }
 
-func (p *tFramedTransportFactory) GetTransport(base TTransport) TTransport {
-	return NewTFramedTransport(p.factory.GetTransport(base))
+func NewTFramedTransportFactoryMaxLength(factory TTransportFactory, maxLength uint32) TTransportFactory {
+	return &tFramedTransportFactory{factory: factory, maxLength: maxLength}
+}
+
+func (p *tFramedTransportFactory) GetTransport(base TTransport) (TTransport, error) {
+	tt, err := p.factory.GetTransport(base)
+	if err != nil {
+		return nil, err
+	}
+	return NewTFramedTransportMaxLength(tt, p.maxLength), nil
 }
 
 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)}
+	return &TFramedTransport{transport: transport, reader: bufio.NewReader(transport), maxLength: DEFAULT_MAX_LENGTH}
+}
+
+func NewTFramedTransportMaxLength(transport TTransport, maxLength uint32) *TFramedTransport {
+	return &TFramedTransport{transport: transport, reader: bufio.NewReader(transport), maxLength: maxLength}
 }
 
 func (p *TFramedTransport) Open() error {
@@ -57,68 +76,98 @@
 	return p.transport.IsOpen()
 }
 
-func (p *TFramedTransport) Peek() bool {
-	return p.transport.Peek()
-}
-
 func (p *TFramedTransport) Close() error {
 	return p.transport.Close()
 }
 
-func (p *TFramedTransport) Read(buf []byte) (int, error) {
-	if p.readBuffer.Len() > 0 {
-		got, err := p.readBuffer.Read(buf)
-		if got > 0 {
-			return got, NewTTransportExceptionFromError(err)
+func (p *TFramedTransport) Read(buf []byte) (l int, err error) {
+	if p.frameSize == 0 {
+		p.frameSize, err = p.readFrameHeader()
+		if err != nil {
+			return
 		}
 	}
-
-	// Read another frame of data
-	p.readFrame()
-
-	got, err := p.readBuffer.Read(buf)
+	if p.frameSize < uint32(len(buf)) {
+		frameSize := p.frameSize
+		tmp := make([]byte, p.frameSize)
+		l, err = p.Read(tmp)
+		copy(buf, tmp)
+		if err == nil {
+			err = NewTTransportExceptionFromError(fmt.Errorf("Not enough frame size %d to read %d bytes", frameSize, len(buf)))
+			return
+		}
+	}
+	got, err := p.reader.Read(buf)
+	p.frameSize = p.frameSize - uint32(got)
+	//sanity check
+	if p.frameSize < 0 {
+		return 0, NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "Negative frame size")
+	}
 	return got, NewTTransportExceptionFromError(err)
 }
 
+func (p *TFramedTransport) ReadByte() (c byte, err error) {
+	if p.frameSize == 0 {
+		p.frameSize, err = p.readFrameHeader()
+		if err != nil {
+			return
+		}
+	}
+	if p.frameSize < 1 {
+		return 0, NewTTransportExceptionFromError(fmt.Errorf("Not enough frame size %d to read %d bytes", p.frameSize, 1))
+	}
+	c, err = p.reader.ReadByte()
+	if err == nil {
+		p.frameSize--
+	}
+	return
+}
+
 func (p *TFramedTransport) Write(buf []byte) (int, error) {
-	n, err := p.writeBuffer.Write(buf)
+	n, err := p.buf.Write(buf)
 	return n, NewTTransportExceptionFromError(err)
 }
 
-func (p *TFramedTransport) Flush() error {
-	size := p.writeBuffer.Len()
-	buf := []byte{0, 0, 0, 0}
+func (p *TFramedTransport) WriteByte(c byte) error {
+	return p.buf.WriteByte(c)
+}
+
+func (p *TFramedTransport) WriteString(s string) (n int, err error) {
+	return p.buf.WriteString(s)
+}
+
+func (p *TFramedTransport) Flush(ctx context.Context) error {
+	size := p.buf.Len()
+	buf := p.buffer[:4]
 	binary.BigEndian.PutUint32(buf, uint32(size))
 	_, err := p.transport.Write(buf)
 	if err != nil {
+		p.buf.Truncate(0)
 		return NewTTransportExceptionFromError(err)
 	}
 	if size > 0 {
-		if n, err := p.writeBuffer.WriteTo(p.transport); err != nil {
-			print("Error while flushing write buffer of size ", size, " to transport, only wrote ", n, " bytes: ", err, "\n")
+		if n, err := p.buf.WriteTo(p.transport); err != nil {
+			print("Error while flushing write buffer of size ", size, " to transport, only wrote ", n, " bytes: ", err.Error(), "\n")
+			p.buf.Truncate(0)
 			return NewTTransportExceptionFromError(err)
 		}
 	}
-	err = p.transport.Flush()
+	err = p.transport.Flush(ctx)
 	return NewTTransportExceptionFromError(err)
 }
 
-func (p *TFramedTransport) readFrame() (int, error) {
-	buf := []byte{0, 0, 0, 0}
-	if _, err := io.ReadFull(p.transport, buf); err != nil {
+func (p *TFramedTransport) readFrameHeader() (uint32, error) {
+	buf := p.buffer[:4]
+	if _, err := io.ReadFull(p.reader, buf); err != nil {
 		return 0, err
 	}
-	size := int(binary.BigEndian.Uint32(buf))
-	if size < 0 {
-		return 0, NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "Read a negative frame size ("+string(size)+")")
+	size := binary.BigEndian.Uint32(buf)
+	if size < 0 || size > p.maxLength {
+		return 0, NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, fmt.Sprintf("Incorrect frame size (%d)", size))
 	}
-	if size == 0 {
-		return 0, nil
-	}
-	buf2 := make([]byte, size)
-	if n, err := io.ReadFull(p.transport, buf2); err != nil {
-		return n, err
-	}
-	p.readBuffer = bytes.NewBuffer(buf2)
 	return size, nil
 }
+
+func (p *TFramedTransport) RemainingBytes() (num_bytes uint64) {
+	return uint64(p.frameSize)
+}
diff --git a/lib/go/thrift/http_client.go b/lib/go/thrift/http_client.go
index 18b1671..5c82bf5 100644
--- a/lib/go/thrift/http_client.go
+++ b/lib/go/thrift/http_client.go
@@ -21,71 +21,103 @@
 
 import (
 	"bytes"
+	"context"
+	"io"
+	"io/ioutil"
 	"net/http"
 	"net/url"
 	"strconv"
 )
 
+// Default to using the shared http client. Library users are
+// free to change this global client or specify one through
+// THttpClientOptions.
+var DefaultHttpClient *http.Client = http.DefaultClient
+
 type THttpClient struct {
+	client             *http.Client
 	response           *http.Response
 	url                *url.URL
 	requestBuffer      *bytes.Buffer
+	header             http.Header
 	nsecConnectTimeout int64
 	nsecReadTimeout    int64
 }
 
 type THttpClientTransportFactory struct {
-	url    string
-	isPost bool
+	options THttpClientOptions
+	url     string
 }
 
-func (p *THttpClientTransportFactory) GetTransport(trans TTransport) TTransport {
+func (p *THttpClientTransportFactory) GetTransport(trans TTransport) (TTransport, error) {
 	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
+			return NewTHttpClientWithOptions(t.url.String(), p.options)
 		}
 	}
-	if p.isPost {
-		s, _ := NewTHttpPostClient(p.url)
-		return s
-	}
-	s, _ := NewTHttpClient(p.url)
-	return s
+	return NewTHttpClientWithOptions(p.url, p.options)
+}
+
+type THttpClientOptions struct {
+	// If nil, DefaultHttpClient is used
+	Client *http.Client
 }
 
 func NewTHttpClientTransportFactory(url string) *THttpClientTransportFactory {
-	return &THttpClientTransportFactory{url: url, isPost: false}
+	return NewTHttpClientTransportFactoryWithOptions(url, THttpClientOptions{})
 }
 
-func NewTHttpPostClientTransportFactory(url string) *THttpClientTransportFactory {
-	return &THttpClientTransportFactory{url: url, isPost: true}
+func NewTHttpClientTransportFactoryWithOptions(url string, options THttpClientOptions) *THttpClientTransportFactory {
+	return &THttpClientTransportFactory{url: url, options: options}
 }
 
-func NewTHttpClient(urlstr string) (TTransport, error) {
-	parsedURL, err := url.Parse(urlstr)
-	if err != nil {
-		return nil, err
-	}
-	response, err := http.Get(urlstr)
-	if err != nil {
-		return nil, err
-	}
-	return &THttpClient{response: response, url: parsedURL}, nil
-}
-
-func NewTHttpPostClient(urlstr string) (TTransport, error) {
+func NewTHttpClientWithOptions(urlstr string, options THttpClientOptions) (TTransport, error) {
 	parsedURL, err := url.Parse(urlstr)
 	if err != nil {
 		return nil, err
 	}
 	buf := make([]byte, 0, 1024)
-	return &THttpClient{url: parsedURL, requestBuffer: bytes.NewBuffer(buf)}, nil
+	client := options.Client
+	if client == nil {
+		client = DefaultHttpClient
+	}
+	httpHeader := map[string][]string{"Content-Type": {"application/x-thrift"}}
+	return &THttpClient{client: client, url: parsedURL, requestBuffer: bytes.NewBuffer(buf), header: httpHeader}, nil
+}
+
+func NewTHttpClient(urlstr string) (TTransport, error) {
+	return NewTHttpClientWithOptions(urlstr, THttpClientOptions{})
+}
+
+// Set the HTTP Header for this specific Thrift Transport
+// It is important that you first assert the TTransport as a THttpClient type
+// like so:
+//
+// httpTrans := trans.(THttpClient)
+// httpTrans.SetHeader("User-Agent","Thrift Client 1.0")
+func (p *THttpClient) SetHeader(key string, value string) {
+	p.header.Add(key, value)
+}
+
+// Get the HTTP Header represented by the supplied Header Key for this specific Thrift Transport
+// It is important that you first assert the TTransport as a THttpClient type
+// like so:
+//
+// httpTrans := trans.(THttpClient)
+// hdrValue := httpTrans.GetHeader("User-Agent")
+func (p *THttpClient) GetHeader(key string) string {
+	return p.header.Get(key)
+}
+
+// Deletes the HTTP Header given a Header Key for this specific Thrift Transport
+// It is important that you first assert the TTransport as a THttpClient type
+// like so:
+//
+// httpTrans := trans.(THttpClient)
+// httpTrans.DelHeader("User-Agent")
+func (p *THttpClient) DelHeader(key string) {
+	p.header.Del(key)
 }
 
 func (p *THttpClient) Open() error {
@@ -97,21 +129,29 @@
 	return p.response != nil || p.requestBuffer != nil
 }
 
-func (p *THttpClient) Peek() bool {
-	return p.IsOpen()
+func (p *THttpClient) closeResponse() error {
+	var err error
+	if p.response != nil && p.response.Body != nil {
+		// The docs specify that if keepalive is enabled and the response body is not
+		// read to completion the connection will never be returned to the pool and
+		// reused. Errors are being ignored here because if the connection is invalid
+		// and this fails for some reason, the Close() method will do any remaining
+		// cleanup.
+		io.Copy(ioutil.Discard, p.response.Body)
+
+		err = p.response.Body.Close()
+	}
+
+	p.response = nil
+	return err
 }
 
 func (p *THttpClient) Close() 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
+	return p.closeResponse()
 }
 
 func (p *THttpClient) Read(buf []byte) (int, error) {
@@ -119,23 +159,84 @@
 		return 0, NewTTransportException(NOT_OPEN, "Response buffer is empty, no request.")
 	}
 	n, err := p.response.Body.Read(buf)
+	if n > 0 && (err == nil || err == io.EOF) {
+		return n, nil
+	}
 	return n, NewTTransportExceptionFromError(err)
 }
 
+func (p *THttpClient) ReadByte() (c byte, err error) {
+	return readByte(p.response.Body)
+}
+
 func (p *THttpClient) Write(buf []byte) (int, error) {
 	n, err := p.requestBuffer.Write(buf)
 	return n, err
 }
 
-func (p *THttpClient) Flush() error {
-	response, err := http.Post(p.url.String(), "application/x-thrift", p.requestBuffer)
+func (p *THttpClient) WriteByte(c byte) error {
+	return p.requestBuffer.WriteByte(c)
+}
+
+func (p *THttpClient) WriteString(s string) (n int, err error) {
+	return p.requestBuffer.WriteString(s)
+}
+
+func (p *THttpClient) Flush(ctx context.Context) error {
+	// Close any previous response body to avoid leaking connections.
+	p.closeResponse()
+
+	req, err := http.NewRequest("POST", p.url.String(), p.requestBuffer)
+	if err != nil {
+		return NewTTransportExceptionFromError(err)
+	}
+	req.Header = p.header
+	if ctx != nil {
+		req = req.WithContext(ctx)
+	}
+	response, err := p.client.Do(req)
 	if err != nil {
 		return NewTTransportExceptionFromError(err)
 	}
 	if response.StatusCode != http.StatusOK {
+		// Close the response to avoid leaking file descriptors. closeResponse does
+		// more than just call Close(), so temporarily assign it and reuse the logic.
+		p.response = response
+		p.closeResponse()
+
 		// TODO(pomack) log bad response
 		return NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "HTTP Response code: "+strconv.Itoa(response.StatusCode))
 	}
 	p.response = response
 	return nil
 }
+
+func (p *THttpClient) RemainingBytes() (num_bytes uint64) {
+	len := p.response.ContentLength
+	if len >= 0 {
+		return uint64(len)
+	}
+
+	const maxSize = ^uint64(0)
+	return maxSize // the thruth is, we just don't know unless framed is used
+}
+
+// Deprecated: Use NewTHttpClientTransportFactory instead.
+func NewTHttpPostClientTransportFactory(url string) *THttpClientTransportFactory {
+	return NewTHttpClientTransportFactoryWithOptions(url, THttpClientOptions{})
+}
+
+// Deprecated: Use NewTHttpClientTransportFactoryWithOptions instead.
+func NewTHttpPostClientTransportFactoryWithOptions(url string, options THttpClientOptions) *THttpClientTransportFactory {
+	return NewTHttpClientTransportFactoryWithOptions(url, options)
+}
+
+// Deprecated: Use NewTHttpClientWithOptions instead.
+func NewTHttpPostClientWithOptions(urlstr string, options THttpClientOptions) (TTransport, error) {
+	return NewTHttpClientWithOptions(urlstr, options)
+}
+
+// Deprecated: Use NewTHttpClient instead.
+func NewTHttpPostClient(urlstr string) (TTransport, error) {
+	return NewTHttpClientWithOptions(urlstr, THttpClientOptions{})
+}
diff --git a/lib/go/thrift/http_client_test.go b/lib/go/thrift/http_client_test.go
index 041faec..453680a 100644
--- a/lib/go/thrift/http_client_test.go
+++ b/lib/go/thrift/http_client_test.go
@@ -20,6 +20,7 @@
 package thrift
 
 import (
+	"net/http"
 	"testing"
 )
 
@@ -35,3 +36,71 @@
 	}
 	TransportTest(t, trans, trans)
 }
+
+func TestHttpClientHeaders(t *testing.T) {
+	l, addr := HttpClientSetupForTest(t)
+	if l != nil {
+		defer l.Close()
+	}
+	trans, err := NewTHttpPostClient("http://" + addr.String())
+	if err != nil {
+		l.Close()
+		t.Fatalf("Unable to connect to %s: %s", addr.String(), err)
+	}
+	TransportHeaderTest(t, trans, trans)
+}
+
+func TestHttpCustomClient(t *testing.T) {
+	l, addr := HttpClientSetupForTest(t)
+	if l != nil {
+		defer l.Close()
+	}
+
+	httpTransport := &customHttpTransport{}
+
+	trans, err := NewTHttpPostClientWithOptions("http://"+addr.String(), THttpClientOptions{
+		Client: &http.Client{
+			Transport: httpTransport,
+		},
+	})
+	if err != nil {
+		l.Close()
+		t.Fatalf("Unable to connect to %s: %s", addr.String(), err)
+	}
+	TransportHeaderTest(t, trans, trans)
+
+	if !httpTransport.hit {
+		t.Fatalf("Custom client was not used")
+	}
+}
+
+func TestHttpCustomClientPackageScope(t *testing.T) {
+	l, addr := HttpClientSetupForTest(t)
+	if l != nil {
+		defer l.Close()
+	}
+	httpTransport := &customHttpTransport{}
+	DefaultHttpClient = &http.Client{
+		Transport: httpTransport,
+	}
+
+	trans, err := NewTHttpPostClient("http://" + addr.String())
+	if err != nil {
+		l.Close()
+		t.Fatalf("Unable to connect to %s: %s", addr.String(), err)
+	}
+	TransportHeaderTest(t, trans, trans)
+
+	if !httpTransport.hit {
+		t.Fatalf("Custom client was not used")
+	}
+}
+
+type customHttpTransport struct {
+	hit bool
+}
+
+func (c *customHttpTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+	c.hit = true
+	return http.DefaultTransport.RoundTrip(req)
+}
diff --git a/lib/go/thrift/http_transport.go b/lib/go/thrift/http_transport.go
new file mode 100644
index 0000000..66f0f38
--- /dev/null
+++ b/lib/go/thrift/http_transport.go
@@ -0,0 +1,63 @@
+/*
+ * 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 (
+	"compress/gzip"
+	"io"
+	"net/http"
+	"strings"
+)
+
+// NewThriftHandlerFunc is a function that create a ready to use Apache Thrift Handler function
+func NewThriftHandlerFunc(processor TProcessor,
+	inPfactory, outPfactory TProtocolFactory) func(w http.ResponseWriter, r *http.Request) {
+
+	return gz(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Add("Content-Type", "application/x-thrift")
+
+		transport := NewStreamTransport(r.Body, w)
+		processor.Process(r.Context(), inPfactory.GetProtocol(transport), outPfactory.GetProtocol(transport))
+	})
+}
+
+// gz transparently compresses the HTTP response if the client supports it.
+func gz(handler http.HandlerFunc) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
+			handler(w, r)
+			return
+		}
+		w.Header().Set("Content-Encoding", "gzip")
+		gz := gzip.NewWriter(w)
+		defer gz.Close()
+		gzw := gzipResponseWriter{Writer: gz, ResponseWriter: w}
+		handler(gzw, r)
+	}
+}
+
+type gzipResponseWriter struct {
+	io.Writer
+	http.ResponseWriter
+}
+
+func (w gzipResponseWriter) Write(b []byte) (int, error) {
+	return w.Writer.Write(b)
+}
diff --git a/lib/go/thrift/iostream_transport.go b/lib/go/thrift/iostream_transport.go
index 64b2958..fea93bc 100644
--- a/lib/go/thrift/iostream_transport.go
+++ b/lib/go/thrift/iostream_transport.go
@@ -21,14 +21,16 @@
 
 import (
 	"bufio"
+	"context"
 	"io"
 )
 
 // StreamTransport is a Transport made of an io.Reader and/or an io.Writer
 type StreamTransport struct {
-	Reader       io.Reader
-	Writer       io.Writer
+	io.Reader
+	io.Writer
 	isReadWriter bool
+	closed       bool
 }
 
 type StreamTransportFactory struct {
@@ -37,38 +39,38 @@
 	isReadWriter bool
 }
 
-func (p *StreamTransportFactory) GetTransport(trans TTransport) TTransport {
+func (p *StreamTransportFactory) GetTransport(trans TTransport) (TTransport, error) {
 	if trans != nil {
 		t, ok := trans.(*StreamTransport)
 		if ok {
 			if t.isReadWriter {
-				return NewStreamTransportRW(t.Reader.(io.ReadWriter))
+				return NewStreamTransportRW(t.Reader.(io.ReadWriter)), nil
 			}
 			if t.Reader != nil && t.Writer != nil {
-				return NewStreamTransport(t.Reader, t.Writer)
+				return NewStreamTransport(t.Reader, t.Writer), nil
 			}
 			if t.Reader != nil && t.Writer == nil {
-				return NewStreamTransportR(t.Reader)
+				return NewStreamTransportR(t.Reader), nil
 			}
 			if t.Reader == nil && t.Writer != nil {
-				return NewStreamTransportW(t.Writer)
+				return NewStreamTransportW(t.Writer), nil
 			}
-			return &StreamTransport{}
+			return &StreamTransport{}, nil
 		}
 	}
 	if p.isReadWriter {
-		return NewStreamTransportRW(p.Reader.(io.ReadWriter))
+		return NewStreamTransportRW(p.Reader.(io.ReadWriter)), nil
 	}
 	if p.Reader != nil && p.Writer != nil {
-		return NewStreamTransport(p.Reader, p.Writer)
+		return NewStreamTransport(p.Reader, p.Writer), nil
 	}
 	if p.Reader != nil && p.Writer == nil {
-		return NewStreamTransportR(p.Reader)
+		return NewStreamTransportR(p.Reader), nil
 	}
 	if p.Reader == nil && p.Writer != nil {
-		return NewStreamTransportW(p.Writer)
+		return NewStreamTransportW(p.Writer), nil
 	}
-	return &StreamTransport{}
+	return &StreamTransport{}, nil
 }
 
 func NewStreamTransportFactory(reader io.Reader, writer io.Writer, isReadWriter bool) *StreamTransportFactory {
@@ -92,23 +94,25 @@
 	return &StreamTransport{Reader: bufrw, Writer: bufrw, isReadWriter: true}
 }
 
-// (The streams must already be open at construction time, so this should
-// always return true.)
 func (p *StreamTransport) IsOpen() bool {
-	return true
+	return !p.closed
 }
 
-// (The streams must already be open. This method does nothing.)
+// implicitly opened on creation, can't be reopened once closed
 func (p *StreamTransport) Open() error {
-	return nil
-}
-
-func (p *StreamTransport) Peek() bool {
-	return p.IsOpen()
+	if !p.closed {
+		return NewTTransportException(ALREADY_OPEN, "StreamTransport already open.")
+	} else {
+		return NewTTransportException(NOT_OPEN, "cannot reopen StreamTransport.")
+	}
 }
 
 // Closes both the input and output streams.
 func (p *StreamTransport) Close() error {
+	if p.closed {
+		return NewTTransportException(NOT_OPEN, "StreamTransport already closed.")
+	}
+	p.closed = true
 	closedReader := false
 	if p.Reader != nil {
 		c, ok := p.Reader.(io.Closer)
@@ -134,26 +138,8 @@
 	return nil
 }
 
-// Reads from the underlying input stream if not null.
-func (p *StreamTransport) Read(buf []byte) (int, error) {
-	if p.Reader == nil {
-		return 0, NewTTransportException(NOT_OPEN, "Cannot read from null inputStream")
-	}
-	n, err := p.Reader.Read(buf)
-	return n, NewTTransportExceptionFromError(err)
-}
-
-// Writes to the underlying output stream if not null.
-func (p *StreamTransport) Write(buf []byte) (int, error) {
-	if p.Writer == nil {
-		return 0, NewTTransportException(NOT_OPEN, "Cannot write to null outputStream")
-	}
-	n, err := p.Writer.Write(buf)
-	return n, NewTTransportExceptionFromError(err)
-}
-
 // Flushes the underlying output stream if not null.
-func (p *StreamTransport) Flush() error {
+func (p *StreamTransport) Flush(ctx context.Context) error {
 	if p.Writer == nil {
 		return NewTTransportException(NOT_OPEN, "Cannot flush null outputStream")
 	}
@@ -166,3 +152,63 @@
 	}
 	return nil
 }
+
+func (p *StreamTransport) Read(c []byte) (n int, err error) {
+	n, err = p.Reader.Read(c)
+	if err != nil {
+		err = NewTTransportExceptionFromError(err)
+	}
+	return
+}
+
+func (p *StreamTransport) ReadByte() (c byte, err error) {
+	f, ok := p.Reader.(io.ByteReader)
+	if ok {
+		c, err = f.ReadByte()
+	} else {
+		c, err = readByte(p.Reader)
+	}
+	if err != nil {
+		err = NewTTransportExceptionFromError(err)
+	}
+	return
+}
+
+func (p *StreamTransport) Write(c []byte) (n int, err error) {
+	n, err = p.Writer.Write(c)
+	if err != nil {
+		err = NewTTransportExceptionFromError(err)
+	}
+	return
+}
+
+func (p *StreamTransport) WriteByte(c byte) (err error) {
+	f, ok := p.Writer.(io.ByteWriter)
+	if ok {
+		err = f.WriteByte(c)
+	} else {
+		err = writeByte(p.Writer, c)
+	}
+	if err != nil {
+		err = NewTTransportExceptionFromError(err)
+	}
+	return
+}
+
+func (p *StreamTransport) WriteString(s string) (n int, err error) {
+	f, ok := p.Writer.(stringWriter)
+	if ok {
+		n, err = f.WriteString(s)
+	} else {
+		n, err = p.Writer.Write([]byte(s))
+	}
+	if err != nil {
+		err = NewTTransportExceptionFromError(err)
+	}
+	return
+}
+
+func (p *StreamTransport) RemainingBytes() (num_bytes uint64) {
+	const maxSize = ^uint64(0)
+	return maxSize // the thruth is, we just don't know unless framed is used
+}
diff --git a/lib/go/thrift/iostream_transport_test.go b/lib/go/thrift/iostream_transport_test.go
index 15ea2d4..15a6116 100644
--- a/lib/go/thrift/iostream_transport_test.go
+++ b/lib/go/thrift/iostream_transport_test.go
@@ -28,3 +28,25 @@
 	trans := NewStreamTransportRW(bytes.NewBuffer(make([]byte, 0, 1024)))
 	TransportTest(t, trans, trans)
 }
+
+func TestStreamTransportOpenClose(t *testing.T) {
+	trans := NewStreamTransportRW(bytes.NewBuffer(make([]byte, 0, 1024)))
+	if !trans.IsOpen() {
+		t.Fatal("StreamTransport should be already open")
+	}
+	if trans.Open() == nil {
+		t.Fatal("StreamTransport should return error when open twice")
+	}
+	if trans.Close() != nil {
+		t.Fatal("StreamTransport should not return error when closing open transport")
+	}
+	if trans.IsOpen() {
+		t.Fatal("StreamTransport should not be open after close")
+	}
+	if trans.Close() == nil {
+		t.Fatal("StreamTransport should return error when closing a non open transport")
+	}
+	if trans.Open() == nil {
+		t.Fatal("StreamTransport should not be able to reopen")
+	}
+}
diff --git a/lib/go/thrift/json_protocol.go b/lib/go/thrift/json_protocol.go
index 5e8453a..7be685d 100644
--- a/lib/go/thrift/json_protocol.go
+++ b/lib/go/thrift/json_protocol.go
@@ -20,6 +20,7 @@
 package thrift
 
 import (
+	"context"
 	"encoding/base64"
 	"fmt"
 )
@@ -60,6 +61,7 @@
 }
 
 func (p *TJSONProtocol) WriteMessageBegin(name string, typeId TMessageType, seqId int32) error {
+	p.resetContextStack() // THRIFT-3735
 	if e := p.OutputListBegin(); e != nil {
 		return e
 	}
@@ -69,7 +71,7 @@
 	if e := p.WriteString(name); e != nil {
 		return e
 	}
-	if e := p.WriteByte(byte(typeId)); e != nil {
+	if e := p.WriteByte(int8(typeId)); e != nil {
 		return e
 	}
 	if e := p.WriteI32(seqId); e != nil {
@@ -100,7 +102,11 @@
 	if e := p.OutputObjectBegin(); e != nil {
 		return e
 	}
-	if e := p.WriteString(p.TypeIdToString(typeId)); e != nil {
+	s, e1 := p.TypeIdToString(typeId)
+	if e1 != nil {
+		return e1
+	}
+	if e := p.WriteString(s); e != nil {
 		return e
 	}
 	return nil
@@ -116,16 +122,30 @@
 	if e := p.OutputListBegin(); e != nil {
 		return e
 	}
-	if e := p.WriteString(p.TypeIdToString(keyType)); e != nil {
+	s, e1 := p.TypeIdToString(keyType)
+	if e1 != nil {
+		return e1
+	}
+	if e := p.WriteString(s); e != nil {
 		return e
 	}
-	if e := p.WriteString(p.TypeIdToString(valueType)); e != nil {
+	s, e1 = p.TypeIdToString(valueType)
+	if e1 != nil {
+		return e1
+	}
+	if e := p.WriteString(s); e != nil {
 		return e
 	}
-	return p.WriteI64(int64(size))
+	if e := p.WriteI64(int64(size)); e != nil {
+		return e
+	}
+	return p.OutputObjectBegin()
 }
 
 func (p *TJSONProtocol) WriteMapEnd() error {
+	if e := p.OutputObjectEnd(); e != nil {
+		return e
+	}
 	return p.OutputListEnd()
 }
 
@@ -146,10 +166,13 @@
 }
 
 func (p *TJSONProtocol) WriteBool(b bool) error {
-	return p.OutputBool(b)
+	if b {
+		return p.WriteI32(1)
+	}
+	return p.WriteI32(0)
 }
 
-func (p *TJSONProtocol) WriteByte(b byte) error {
+func (p *TJSONProtocol) WriteByte(b int8) error {
 	return p.WriteI32(int32(b))
 }
 
@@ -181,19 +204,26 @@
 	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 {
+	if _, e := p.write(JSON_QUOTE_BYTES); e != nil {
 		return NewTProtocolException(e)
 	}
-	writer.Close()
-	p.writer.Write(JSON_QUOTE_BYTES)
+	writer := base64.NewEncoder(base64.StdEncoding, p.writer)
+	if _, e := writer.Write(v); e != nil {
+		p.writer.Reset(p.trans) // THRIFT-3735
+		return NewTProtocolException(e)
+	}
+	if e := writer.Close(); e != nil {
+		return NewTProtocolException(e)
+	}
+	if _, e := p.write(JSON_QUOTE_BYTES); e != nil {
+		return NewTProtocolException(e)
+	}
 	return p.OutputPostValue()
 }
 
 // Reading methods.
-
 func (p *TJSONProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err error) {
+	p.resetContextStack() // THRIFT-3735
 	if isNull, err := p.ParseListBegin(); isNull || err != nil {
 		return name, typeId, seqId, err
 	}
@@ -235,9 +265,6 @@
 }
 
 func (p *TJSONProtocol) ReadFieldBegin() (string, TType, int16, error) {
-	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
@@ -250,7 +277,10 @@
 		return "", STOP, fieldId, err
 	}
 	sType, err := p.ReadString()
-	fType := p.StringToTypeId(sType)
+	if err != nil {
+		return "", STOP, fieldId, err
+	}
+	fType, err := p.StringToTypeId(sType)
 	return "", fType, fieldId, err
 }
 
@@ -265,25 +295,40 @@
 
 	// read keyType
 	sKeyType, e := p.ReadString()
-	keyType = p.StringToTypeId(sKeyType)
+	if e != nil {
+		return keyType, valueType, size, e
+	}
+	keyType, e = 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
+	}
+	valueType, e = p.StringToTypeId(sValueType)
 	if e != nil {
 		return keyType, valueType, size, e
 	}
 
 	// read size
-	iSize, err := p.ReadI64()
+	iSize, e := p.ReadI64()
+	if e != nil {
+		return keyType, valueType, size, e
+	}
 	size = int(iSize)
-	return keyType, valueType, size, err
+
+	_, e = p.ParseObjectStart()
+	return keyType, valueType, size, e
 }
 
 func (p *TJSONProtocol) ReadMapEnd() error {
+	e := p.ParseObjectEnd()
+	if e != nil {
+		return e
+	}
 	return p.ParseListEnd()
 }
 
@@ -304,50 +349,13 @@
 }
 
 func (p *TJSONProtocol) ReadBool() (bool, error) {
-	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 {
-				e := fmt.Errorf("Expected \"true\" but found: %s", string(b))
-				return value, NewTProtocolExceptionWithType(INVALID_DATA, e)
-			}
-			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 {
-				e := fmt.Errorf("Expected \"false\" but found: %s", string(b))
-				return value, NewTProtocolExceptionWithType(INVALID_DATA, e)
-			}
-			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 {
-				e := fmt.Errorf("Expected \"null\" but found: %s", string(b))
-				return value, NewTProtocolExceptionWithType(INVALID_DATA, e)
-			}
-		default:
-			e := fmt.Errorf("Expected \"true\", \"false\", or \"null\" but found: %s", string(b))
-			return value, NewTProtocolExceptionWithType(INVALID_DATA, e)
-		}
-	}
-	return value, p.ParsePostValue()
+	value, err := p.ReadI32()
+	return (value != 0), err
 }
 
-func (p *TJSONProtocol) ReadByte() (byte, error) {
+func (p *TJSONProtocol) ReadByte() (int8, error) {
 	v, err := p.ReadI64()
-	return byte(v), err
+	return int8(v), err
 }
 
 func (p *TJSONProtocol) ReadI16() (int16, error) {
@@ -375,21 +383,26 @@
 	if err := p.ParsePreValue(); err != nil {
 		return v, err
 	}
-	b, _ := p.reader.Peek(len(JSON_NULL))
-	if len(b) > 0 && b[0] == JSON_QUOTE {
+	f, _ := p.reader.Peek(1)
+	if len(f) > 0 && f[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)])
+	} else if len(f) > 0 && f[0] == JSON_NULL[0] {
+		b := make([]byte, len(JSON_NULL))
+		_, err := p.reader.Read(b)
 		if err != nil {
 			return v, NewTProtocolException(err)
 		}
+		if string(b) != string(JSON_NULL) {
+			e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(b))
+			return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
+		}
 	} else {
-		e := fmt.Errorf("Expected a JSON string, found %s", string(b))
+		e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(f))
 		return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
 	}
 	return v, p.ParsePostValue()
@@ -400,28 +413,38 @@
 	if err := p.ParsePreValue(); err != nil {
 		return nil, err
 	}
-	b, _ := p.reader.Peek(len(JSON_NULL))
-	if len(b) > 0 && b[0] == JSON_QUOTE {
+	f, _ := p.reader.Peek(1)
+	if len(f) > 0 && f[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)])
+	} else if len(f) > 0 && f[0] == JSON_NULL[0] {
+		b := make([]byte, len(JSON_NULL))
+		_, err := p.reader.Read(b)
 		if err != nil {
 			return v, NewTProtocolException(err)
 		}
+		if string(b) != string(JSON_NULL) {
+			e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(b))
+			return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
+		}
 	} else {
-		e := fmt.Errorf("Expected a JSON string, found %s", string(b))
+		e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(f))
 		return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
 	}
+
 	return v, p.ParsePostValue()
 }
 
-func (p *TJSONProtocol) Flush() (err error) {
-	return NewTProtocolException(p.writer.Flush())
+func (p *TJSONProtocol) Flush(ctx context.Context) (err error) {
+	err = p.writer.Flush()
+	if err == nil {
+		err = p.trans.Flush(ctx)
+	}
+	return NewTProtocolException(err)
 }
 
 func (p *TJSONProtocol) Skip(fieldType TType) (err error) {
@@ -436,7 +459,11 @@
 	if e := p.OutputListBegin(); e != nil {
 		return e
 	}
-	if e := p.WriteString(p.TypeIdToString(elemType)); e != nil {
+	s, e1 := p.TypeIdToString(elemType)
+	if e1 != nil {
+		return e1
+	}
+	if e := p.WriteString(s); e != nil {
 		return e
 	}
 	if e := p.WriteI64(int64(size)); e != nil {
@@ -445,13 +472,15 @@
 	return nil
 }
 
-
 func (p *TJSONProtocol) ParseElemListBegin() (elemType TType, size int, e error) {
 	if isNull, e := p.ParseListBegin(); isNull || e != nil {
 		return VOID, 0, e
 	}
 	sElemType, err := p.ReadString()
-	elemType = p.StringToTypeId(sElemType)
+	if err != nil {
+		return VOID, size, err
+	}
+	elemType, err = p.StringToTypeId(sElemType)
 	if err != nil {
 		return elemType, size, err
 	}
@@ -465,7 +494,10 @@
 		return VOID, 0, e
 	}
 	sElemType, err := p.ReadString()
-	elemType = p.StringToTypeId(sElemType)
+	if err != nil {
+		return VOID, size, err
+	}
+	elemType, err = p.StringToTypeId(sElemType)
 	if err != nil {
 		return elemType, size, err
 	}
@@ -478,7 +510,11 @@
 	if e := p.OutputListBegin(); e != nil {
 		return e
 	}
-	if e := p.OutputString(p.TypeIdToString(elemType)); e != nil {
+	s, e1 := p.TypeIdToString(elemType)
+	if e1 != nil {
+		return e1
+	}
+	if e := p.OutputString(s); e != nil {
 		return e
 	}
 	if e := p.OutputI64(int64(size)); e != nil {
@@ -487,70 +523,62 @@
 	return nil
 }
 
-func (p *TJSONProtocol) TypeIdToString(fieldType TType) string {
+func (p *TJSONProtocol) TypeIdToString(fieldType TType) (string, error) {
 	switch byte(fieldType) {
-	case STOP:
-		return "stp"
-	case VOID:
-		return "v"
 	case BOOL:
-		return "tf"
+		return "tf", nil
 	case BYTE:
-		return "i8"
-	case DOUBLE:
-		return "dbl"
+		return "i8", nil
 	case I16:
-		return "i16"
+		return "i16", nil
 	case I32:
-		return "i32"
+		return "i32", nil
 	case I64:
-		return "i64"
+		return "i64", nil
+	case DOUBLE:
+		return "dbl", nil
 	case STRING:
-		return "str"
+		return "str", nil
 	case STRUCT:
-		return "rec"
+		return "rec", nil
 	case MAP:
-		return "map"
+		return "map", nil
 	case SET:
-		return "set"
+		return "set", nil
 	case LIST:
-		return "lst"
-	case UTF16:
-		return "str"
+		return "lst", nil
 	}
-	return ""
+
+	e := fmt.Errorf("Unknown fieldType: %d", int(fieldType))
+	return "", NewTProtocolExceptionWithType(INVALID_DATA, e)
 }
 
-func (p *TJSONProtocol) StringToTypeId(fieldType string) TType {
+func (p *TJSONProtocol) StringToTypeId(fieldType string) (TType, error) {
 	switch fieldType {
-	case "stp":
-		return TType(STOP)
-	case "v":
-		return TType(VOID)
 	case "tf":
-		return TType(BOOL)
+		return TType(BOOL), nil
 	case "i8":
-		return TType(BYTE)
-	case "dbl":
-		return TType(DOUBLE)
-	case "16":
-		return TType(I16)
+		return TType(BYTE), nil
+	case "i16":
+		return TType(I16), nil
 	case "i32":
-		return TType(I32)
+		return TType(I32), nil
 	case "i64":
-		return TType(I64)
+		return TType(I64), nil
+	case "dbl":
+		return TType(DOUBLE), nil
 	case "str":
-		return TType(STRING)
+		return TType(STRING), nil
 	case "rec":
-		return TType(STRUCT)
+		return TType(STRUCT), nil
 	case "map":
-		return TType(MAP)
+		return TType(MAP), nil
 	case "set":
-		return TType(SET)
+		return TType(SET), nil
 	case "lst":
-		return TType(LIST)
-	case "u16":
-		return TType(UTF16)
+		return TType(LIST), nil
 	}
-	return TType(STOP)
+
+	e := fmt.Errorf("Unknown type identifier: %s", fieldType)
+	return TType(STOP), NewTProtocolExceptionWithType(INVALID_DATA, e)
 }
diff --git a/lib/go/thrift/json_protocol_test.go b/lib/go/thrift/json_protocol_test.go
index cb626cc..59c4d64 100644
--- a/lib/go/thrift/json_protocol_test.go
+++ b/lib/go/thrift/json_protocol_test.go
@@ -20,6 +20,7 @@
 package thrift
 
 import (
+	"context"
 	"encoding/base64"
 	"encoding/json"
 	"fmt"
@@ -36,15 +37,21 @@
 		if e := p.WriteBool(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
-		if s != fmt.Sprint(value) {
-			t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+		expected := ""
+		if value {
+			expected = "1"
+		} else {
+			expected = "0"
 		}
-		v := false
-		if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+		if s != expected {
+			t.Fatalf("Bad value for %s %v: %s expected", thetype, value, s)
+		}
+		v := -1
+		if err := json.Unmarshal([]byte(s), &v); err != nil || (v != 0) != value {
 			t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
 		}
 		trans.Reset()
@@ -58,11 +65,11 @@
 		trans := NewTMemoryBuffer()
 		p := NewTJSONProtocol(trans)
 		if value {
-			trans.Write(JSON_TRUE)
+			trans.Write([]byte{'1'}) // not JSON_TRUE
 		} else {
-			trans.Write(JSON_FALSE)
+			trans.Write([]byte{'0'}) // not JSON_FALSE
 		}
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadBool()
 		if e != nil {
@@ -71,8 +78,9 @@
 		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)
+		vv := -1
+		if err := json.Unmarshal([]byte(s), &vv); err != nil || (vv != 0) != value {
+			t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, vv)
 		}
 		trans.Reset()
 		trans.Close()
@@ -87,14 +95,14 @@
 		if e := p.WriteByte(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
 		if s != fmt.Sprint(value) {
 			t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
 		}
-		v := byte(0)
+		v := int8(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)
 		}
@@ -109,7 +117,7 @@
 		trans := NewTMemoryBuffer()
 		p := NewTJSONProtocol(trans)
 		trans.WriteString(strconv.Itoa(int(value)))
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadByte()
 		if e != nil {
@@ -134,7 +142,7 @@
 		if e := p.WriteI16(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
@@ -156,7 +164,7 @@
 		trans := NewTMemoryBuffer()
 		p := NewTJSONProtocol(trans)
 		trans.WriteString(strconv.Itoa(int(value)))
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadI16()
 		if e != nil {
@@ -181,7 +189,7 @@
 		if e := p.WriteI32(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
@@ -203,7 +211,7 @@
 		trans := NewTMemoryBuffer()
 		p := NewTJSONProtocol(trans)
 		trans.WriteString(strconv.Itoa(int(value)))
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadI32()
 		if e != nil {
@@ -228,7 +236,7 @@
 		if e := p.WriteI64(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
@@ -250,7 +258,7 @@
 		trans := NewTMemoryBuffer()
 		p := NewTJSONProtocol(trans)
 		trans.WriteString(strconv.FormatInt(value, 10))
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadI64()
 		if e != nil {
@@ -275,7 +283,7 @@
 		if e := p.WriteDouble(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
@@ -312,7 +320,7 @@
 		p := NewTJSONProtocol(trans)
 		n := NewNumericFromDouble(value)
 		trans.WriteString(n.String())
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadDouble()
 		if e != nil {
@@ -351,7 +359,7 @@
 		if e := p.WriteString(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
@@ -373,7 +381,7 @@
 		trans := NewTMemoryBuffer()
 		p := NewTJSONProtocol(trans)
 		trans.WriteString(jsonQuote(value))
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadString()
 		if e != nil {
@@ -402,7 +410,7 @@
 	if e := p.WriteBinary(value); e != nil {
 		t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 	}
-	if e := p.Flush(); e != nil {
+	if e := p.Flush(context.Background()); e != nil {
 		t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 	}
 	s := trans.String()
@@ -434,7 +442,7 @@
 	trans := NewTMemoryBuffer()
 	p := NewTJSONProtocol(trans)
 	trans.WriteString(jsonQuote(b64String))
-	trans.Flush()
+	trans.Flush(context.Background())
 	s := trans.String()
 	v, e := p.ReadBinary()
 	if e != nil {
@@ -467,7 +475,7 @@
 		}
 	}
 	p.WriteListEnd()
-	if e := p.Flush(); e != nil {
+	if e := p.Flush(context.Background()); e != nil {
 		t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.Error())
 	}
 	str := trans.String()
@@ -521,7 +529,7 @@
 		}
 	}
 	p.WriteSetEnd()
-	if e := p.Flush(); e != nil {
+	if e := p.Flush(context.Background()); e != nil {
 		t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.Error())
 	}
 	str := trans.String()
@@ -578,12 +586,12 @@
 		}
 	}
 	p.WriteMapEnd()
-	if e := p.Flush(); e != nil {
+	if e := p.Flush(context.Background()); e != nil {
 		t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.Error())
 	}
 	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)
+		t.Fatalf("Bad value for %s, wrote: %v, in go: %v", thetype, str, DOUBLE_VALUES)
 	}
 	expectedKeyType, expectedValueType, expectedSize, err := p.ReadMapBegin()
 	if err != nil {
@@ -633,7 +641,10 @@
 				t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
 			}
 		}
-		trans.Reset()
+	}
+	err = p.ReadMapEnd()
+	if err != nil {
+		t.Fatalf("Error while reading map end: %s", err.Error())
 	}
 	trans.Close()
 }
diff --git a/lib/go/thrift/lowlevel_benchmarks_test.go b/lib/go/thrift/lowlevel_benchmarks_test.go
new file mode 100644
index 0000000..e173655
--- /dev/null
+++ b/lib/go/thrift/lowlevel_benchmarks_test.go
@@ -0,0 +1,540 @@
+/*
+ * 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"
+	"testing"
+)
+
+var binaryProtoF = NewTBinaryProtocolFactoryDefault()
+var compactProtoF = NewTCompactProtocolFactory()
+
+var buf = bytes.NewBuffer(make([]byte, 0, 1024))
+
+var tfv = []TTransportFactory{
+	NewTMemoryBufferTransportFactory(1024),
+	NewStreamTransportFactory(buf, buf, true),
+	NewTFramedTransportFactory(NewTMemoryBufferTransportFactory(1024)),
+}
+
+func BenchmarkBinaryBool_0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteBool(b, p, trans)
+	}
+}
+
+func BenchmarkBinaryByte_0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteByte(b, p, trans)
+	}
+}
+
+func BenchmarkBinaryI16_0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI16(b, p, trans)
+	}
+}
+
+func BenchmarkBinaryI32_0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI32(b, p, trans)
+	}
+}
+func BenchmarkBinaryI64_0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI64(b, p, trans)
+	}
+}
+func BenchmarkBinaryDouble_0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteDouble(b, p, trans)
+	}
+}
+func BenchmarkBinaryString_0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteString(b, p, trans)
+	}
+}
+func BenchmarkBinaryBinary_0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteBinary(b, p, trans)
+	}
+}
+
+func BenchmarkBinaryBool_1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteBool(b, p, trans)
+	}
+}
+
+func BenchmarkBinaryByte_1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteByte(b, p, trans)
+	}
+}
+
+func BenchmarkBinaryI16_1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI16(b, p, trans)
+	}
+}
+
+func BenchmarkBinaryI32_1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI32(b, p, trans)
+	}
+}
+func BenchmarkBinaryI64_1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI64(b, p, trans)
+	}
+}
+func BenchmarkBinaryDouble_1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteDouble(b, p, trans)
+	}
+}
+func BenchmarkBinaryString_1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteString(b, p, trans)
+	}
+}
+func BenchmarkBinaryBinary_1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteBinary(b, p, trans)
+	}
+}
+
+func BenchmarkBinaryBool_2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteBool(b, p, trans)
+	}
+}
+
+func BenchmarkBinaryByte_2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteByte(b, p, trans)
+	}
+}
+
+func BenchmarkBinaryI16_2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI16(b, p, trans)
+	}
+}
+
+func BenchmarkBinaryI32_2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI32(b, p, trans)
+	}
+}
+func BenchmarkBinaryI64_2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI64(b, p, trans)
+	}
+}
+func BenchmarkBinaryDouble_2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteDouble(b, p, trans)
+	}
+}
+func BenchmarkBinaryString_2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteString(b, p, trans)
+	}
+}
+func BenchmarkBinaryBinary_2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := binaryProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteBinary(b, p, trans)
+	}
+}
+
+func BenchmarkCompactBool_0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteBool(b, p, trans)
+	}
+}
+
+func BenchmarkCompactByte_0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteByte(b, p, trans)
+	}
+}
+
+func BenchmarkCompactI16_0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI16(b, p, trans)
+	}
+}
+
+func BenchmarkCompactI32_0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI32(b, p, trans)
+	}
+}
+func BenchmarkCompactI64_0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI64(b, p, trans)
+	}
+}
+func BenchmarkCompactDouble0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteDouble(b, p, trans)
+	}
+}
+func BenchmarkCompactString0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteString(b, p, trans)
+	}
+}
+func BenchmarkCompactBinary0(b *testing.B) {
+	trans, err := tfv[0].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteBinary(b, p, trans)
+	}
+}
+
+func BenchmarkCompactBool_1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteBool(b, p, trans)
+	}
+}
+
+func BenchmarkCompactByte_1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteByte(b, p, trans)
+	}
+}
+
+func BenchmarkCompactI16_1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI16(b, p, trans)
+	}
+}
+
+func BenchmarkCompactI32_1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI32(b, p, trans)
+	}
+}
+func BenchmarkCompactI64_1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI64(b, p, trans)
+	}
+}
+func BenchmarkCompactDouble1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteDouble(b, p, trans)
+	}
+}
+func BenchmarkCompactString1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteString(b, p, trans)
+	}
+}
+func BenchmarkCompactBinary1(b *testing.B) {
+	trans, err := tfv[1].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteBinary(b, p, trans)
+	}
+}
+
+func BenchmarkCompactBool_2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteBool(b, p, trans)
+	}
+}
+
+func BenchmarkCompactByte_2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteByte(b, p, trans)
+	}
+}
+
+func BenchmarkCompactI16_2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI16(b, p, trans)
+	}
+}
+
+func BenchmarkCompactI32_2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI32(b, p, trans)
+	}
+}
+func BenchmarkCompactI64_2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteI64(b, p, trans)
+	}
+}
+func BenchmarkCompactDouble2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteDouble(b, p, trans)
+	}
+}
+func BenchmarkCompactString2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteString(b, p, trans)
+	}
+}
+func BenchmarkCompactBinary2(b *testing.B) {
+	trans, err := tfv[2].GetTransport(nil)
+	if err != nil {
+		b.Fatal(err)
+	}
+	p := compactProtoF.GetProtocol(trans)
+	for i := 0; i < b.N; i++ {
+		ReadWriteBinary(b, p, trans)
+	}
+}
diff --git a/lib/go/thrift/memory_buffer.go b/lib/go/thrift/memory_buffer.go
index c48e089..5936d27 100644
--- a/lib/go/thrift/memory_buffer.go
+++ b/lib/go/thrift/memory_buffer.go
@@ -21,6 +21,7 @@
 
 import (
 	"bytes"
+	"context"
 )
 
 // Memory buffer-based implementation of the TTransport interface.
@@ -33,14 +34,14 @@
 	size int
 }
 
-func (p *TMemoryBufferTransportFactory) GetTransport(trans TTransport) TTransport {
+func (p *TMemoryBufferTransportFactory) GetTransport(trans TTransport) (TTransport, error) {
 	if trans != nil {
 		t, ok := trans.(*TMemoryBuffer)
 		if ok && t.size > 0 {
-			return NewTMemoryBufferLen(t.size)
+			return NewTMemoryBufferLen(t.size), nil
 		}
 	}
-	return NewTMemoryBufferLen(p.size)
+	return NewTMemoryBufferLen(p.size), nil
 }
 
 func NewTMemoryBufferTransportFactory(size int) *TMemoryBufferTransportFactory {
@@ -64,16 +65,16 @@
 	return nil
 }
 
-func (p *TMemoryBuffer) Peek() bool {
-	return p.IsOpen()
-}
-
 func (p *TMemoryBuffer) Close() error {
 	p.Buffer.Reset()
 	return nil
 }
 
 // Flushing a memory buffer is a no-op
-func (p *TMemoryBuffer) Flush() error {
+func (p *TMemoryBuffer) Flush(ctx context.Context) error {
 	return nil
 }
+
+func (p *TMemoryBuffer) RemainingBytes() (num_bytes uint64) {
+	return uint64(p.Buffer.Len())
+}
diff --git a/lib/go/thrift/multiplexed_protocol.go b/lib/go/thrift/multiplexed_protocol.go
new file mode 100644
index 0000000..d028a30
--- /dev/null
+++ b/lib/go/thrift/multiplexed_protocol.go
@@ -0,0 +1,170 @@
+/*
+ * 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 (
+	"context"
+	"fmt"
+	"strings"
+)
+
+/*
+TMultiplexedProtocol is a protocol-independent concrete decorator
+that allows a Thrift client to communicate with a multiplexing Thrift server,
+by prepending the service name to the function name during function calls.
+
+NOTE: THIS IS NOT USED BY SERVERS.  On the server, use TMultiplexedProcessor to handle request
+from a multiplexing client.
+
+This example uses a single socket transport to invoke two services:
+
+socket := thrift.NewTSocketFromAddrTimeout(addr, TIMEOUT)
+transport := thrift.NewTFramedTransport(socket)
+protocol := thrift.NewTBinaryProtocolTransport(transport)
+
+mp := thrift.NewTMultiplexedProtocol(protocol, "Calculator")
+service := Calculator.NewCalculatorClient(mp)
+
+mp2 := thrift.NewTMultiplexedProtocol(protocol, "WeatherReport")
+service2 := WeatherReport.NewWeatherReportClient(mp2)
+
+err := transport.Open()
+if err != nil {
+	t.Fatal("Unable to open client socket", err)
+}
+
+fmt.Println(service.Add(2,2))
+fmt.Println(service2.GetTemperature())
+*/
+
+type TMultiplexedProtocol struct {
+	TProtocol
+	serviceName string
+}
+
+const MULTIPLEXED_SEPARATOR = ":"
+
+func NewTMultiplexedProtocol(protocol TProtocol, serviceName string) *TMultiplexedProtocol {
+	return &TMultiplexedProtocol{
+		TProtocol:   protocol,
+		serviceName: serviceName,
+	}
+}
+
+func (t *TMultiplexedProtocol) WriteMessageBegin(name string, typeId TMessageType, seqid int32) error {
+	if typeId == CALL || typeId == ONEWAY {
+		return t.TProtocol.WriteMessageBegin(t.serviceName+MULTIPLEXED_SEPARATOR+name, typeId, seqid)
+	} else {
+		return t.TProtocol.WriteMessageBegin(name, typeId, seqid)
+	}
+}
+
+/*
+TMultiplexedProcessor is a TProcessor allowing
+a single TServer to provide multiple services.
+
+To do so, you instantiate the processor and then register additional
+processors with it, as shown in the following example:
+
+var processor = thrift.NewTMultiplexedProcessor()
+
+firstProcessor :=
+processor.RegisterProcessor("FirstService", firstProcessor)
+
+processor.registerProcessor(
+  "Calculator",
+  Calculator.NewCalculatorProcessor(&CalculatorHandler{}),
+)
+
+processor.registerProcessor(
+  "WeatherReport",
+  WeatherReport.NewWeatherReportProcessor(&WeatherReportHandler{}),
+)
+
+serverTransport, err := thrift.NewTServerSocketTimeout(addr, TIMEOUT)
+if err != nil {
+  t.Fatal("Unable to create server socket", err)
+}
+server := thrift.NewTSimpleServer2(processor, serverTransport)
+server.Serve();
+*/
+
+type TMultiplexedProcessor struct {
+	serviceProcessorMap map[string]TProcessor
+	DefaultProcessor    TProcessor
+}
+
+func NewTMultiplexedProcessor() *TMultiplexedProcessor {
+	return &TMultiplexedProcessor{
+		serviceProcessorMap: make(map[string]TProcessor),
+	}
+}
+
+func (t *TMultiplexedProcessor) RegisterDefault(processor TProcessor) {
+	t.DefaultProcessor = processor
+}
+
+func (t *TMultiplexedProcessor) RegisterProcessor(name string, processor TProcessor) {
+	if t.serviceProcessorMap == nil {
+		t.serviceProcessorMap = make(map[string]TProcessor)
+	}
+	t.serviceProcessorMap[name] = processor
+}
+
+func (t *TMultiplexedProcessor) Process(ctx context.Context, in, out TProtocol) (bool, TException) {
+	name, typeId, seqid, err := in.ReadMessageBegin()
+	if err != nil {
+		return false, err
+	}
+	if typeId != CALL && typeId != ONEWAY {
+		return false, fmt.Errorf("Unexpected message type %v", typeId)
+	}
+	//extract the service name
+	v := strings.SplitN(name, MULTIPLEXED_SEPARATOR, 2)
+	if len(v) != 2 {
+		if t.DefaultProcessor != nil {
+			smb := NewStoredMessageProtocol(in, name, typeId, seqid)
+			return t.DefaultProcessor.Process(ctx, smb, out)
+		}
+		return false, fmt.Errorf("Service name not found in message name: %s.  Did you forget to use a TMultiplexProtocol in your client?", name)
+	}
+	actualProcessor, ok := t.serviceProcessorMap[v[0]]
+	if !ok {
+		return false, fmt.Errorf("Service name not found: %s.  Did you forget to call registerProcessor()?", v[0])
+	}
+	smb := NewStoredMessageProtocol(in, v[1], typeId, seqid)
+	return actualProcessor.Process(ctx, smb, out)
+}
+
+//Protocol that use stored message for ReadMessageBegin
+type storedMessageProtocol struct {
+	TProtocol
+	name   string
+	typeId TMessageType
+	seqid  int32
+}
+
+func NewStoredMessageProtocol(protocol TProtocol, name string, typeId TMessageType, seqid int32) *storedMessageProtocol {
+	return &storedMessageProtocol{protocol, name, typeId, seqid}
+}
+
+func (s *storedMessageProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqid int32, err error) {
+	return s.name, s.typeId, s.seqid, nil
+}
diff --git a/lib/go/thrift/pointerize.go b/lib/go/thrift/pointerize.go
new file mode 100644
index 0000000..8d6b2c2
--- /dev/null
+++ b/lib/go/thrift/pointerize.go
@@ -0,0 +1,50 @@
+/*
+ * 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
+
+///////////////////////////////////////////////////////////////////////////////
+// This file is home to helpers that convert from various base types to
+// respective pointer types. This is necessary because Go does not permit
+// references to constants, nor can a pointer type to base type be allocated
+// and initialized in a single expression.
+//
+// E.g., this is not allowed:
+//
+//    var ip *int = &5
+//
+// But this *is* allowed:
+//
+//    func IntPtr(i int) *int { return &i }
+//    var ip *int = IntPtr(5)
+//
+// Since pointers to base types are commonplace as [optional] fields in
+// exported thrift structs, we factor such helpers here.
+///////////////////////////////////////////////////////////////////////////////
+
+func Float32Ptr(v float32) *float32 { return &v }
+func Float64Ptr(v float64) *float64 { return &v }
+func IntPtr(v int) *int             { return &v }
+func Int32Ptr(v int32) *int32       { return &v }
+func Int64Ptr(v int64) *int64       { return &v }
+func StringPtr(v string) *string    { return &v }
+func Uint32Ptr(v uint32) *uint32    { return &v }
+func Uint64Ptr(v uint64) *uint64    { return &v }
+func BoolPtr(v bool) *bool          { return &v }
+func ByteSlicePtr(v []byte) *[]byte { return &v }
diff --git a/lib/go/thrift/processor.go b/lib/go/thrift/processor.go
deleted file mode 100644
index ca0d3fa..0000000
--- a/lib/go/thrift/processor.go
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-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/processor_factory.go b/lib/go/thrift/processor_factory.go
index 9d645df..e4b132b 100644
--- a/lib/go/thrift/processor_factory.go
+++ b/lib/go/thrift/processor_factory.go
@@ -19,6 +19,18 @@
 
 package thrift
 
+import "context"
+
+// A processor is a generic object which operates upon an input stream and
+// writes to some output stream.
+type TProcessor interface {
+	Process(ctx context.Context, in, out TProtocol) (bool, TException)
+}
+
+type TProcessorFunction interface {
+	Process(ctx context.Context, seqId int32, in, out TProtocol) (bool, TException)
+}
+
 // The default processor factory just returns a singleton
 // instance.
 type TProcessorFactory interface {
diff --git a/lib/go/thrift/protocol.go b/lib/go/thrift/protocol.go
index 87ceaad..615b7a4 100644
--- a/lib/go/thrift/protocol.go
+++ b/lib/go/thrift/protocol.go
@@ -19,6 +19,12 @@
 
 package thrift
 
+import (
+	"context"
+	"errors"
+	"fmt"
+)
+
 const (
 	VERSION_MASK = 0xffff0000
 	VERSION_1    = 0x80010000
@@ -39,7 +45,7 @@
 	WriteSetBegin(elemType TType, size int) error
 	WriteSetEnd() error
 	WriteBool(value bool) error
-	WriteByte(value byte) error
+	WriteByte(value int8) error
 	WriteI16(value int16) error
 	WriteI32(value int32) error
 	WriteI64(value int64) error
@@ -60,7 +66,7 @@
 	ReadSetBegin() (elemType TType, size int, err error)
 	ReadSetEnd() error
 	ReadBool() (value bool, err error)
-	ReadByte() (value byte, err error)
+	ReadByte() (value int8, err error)
 	ReadI16() (value int16, err error)
 	ReadI32() (value int32, err error)
 	ReadI64() (value int64, err error)
@@ -69,21 +75,26 @@
 	ReadBinary() (value []byte, err error)
 
 	Skip(fieldType TType) (err error)
-	Flush() (err error)
+	Flush(ctx context.Context) (err error)
 
 	Transport() TTransport
 }
 
 // The maximum recursive depth the skip() function will traverse
-var MaxSkipDepth = 1<<31 - 1
+const DEFAULT_RECURSION_DEPTH = 64
 
 // Skips over the next data element from the provided input TProtocol object.
 func SkipDefaultDepth(prot TProtocol, typeId TType) (err error) {
-	return Skip(prot, typeId, MaxSkipDepth)
+	return Skip(prot, typeId, DEFAULT_RECURSION_DEPTH)
 }
 
 // Skips over the next data element from the provided input TProtocol object.
 func Skip(self TProtocol, fieldType TType, maxDepth int) (err error) {
+
+	if maxDepth <= 0 {
+		return NewTProtocolExceptionWithType(DEPTH_LIMIT, errors.New("Depth limit exceeded"))
+	}
+
 	switch fieldType {
 	case STOP:
 		return
@@ -117,7 +128,10 @@
 			if typeId == STOP {
 				break
 			}
-			Skip(self, typeId, maxDepth-1)
+			err := Skip(self, typeId, maxDepth-1)
+			if err != nil {
+				return err
+			}
 			self.ReadFieldEnd()
 		}
 		return self.ReadStructEnd()
@@ -127,7 +141,10 @@
 			return err
 		}
 		for i := 0; i < size; i++ {
-			Skip(self, keyType, maxDepth-1)
+			err := Skip(self, keyType, maxDepth-1)
+			if err != nil {
+				return err
+			}
 			self.Skip(valueType)
 		}
 		return self.ReadMapEnd()
@@ -137,7 +154,10 @@
 			return err
 		}
 		for i := 0; i < size; i++ {
-			Skip(self, elemType, maxDepth-1)
+			err := Skip(self, elemType, maxDepth-1)
+			if err != nil {
+				return err
+			}
 		}
 		return self.ReadSetEnd()
 	case LIST:
@@ -146,9 +166,14 @@
 			return err
 		}
 		for i := 0; i < size; i++ {
-			Skip(self, elemType, maxDepth-1)
+			err := Skip(self, elemType, maxDepth-1)
+			if err != nil {
+				return err
+			}
 		}
 		return self.ReadListEnd()
+	default:
+		return NewTProtocolExceptionWithType(INVALID_DATA, errors.New(fmt.Sprintf("Unknown data type %d", fieldType)))
 	}
 	return nil
 }
diff --git a/lib/go/thrift/protocol_exception.go b/lib/go/thrift/protocol_exception.go
index f1a164a..29ab75d 100644
--- a/lib/go/thrift/protocol_exception.go
+++ b/lib/go/thrift/protocol_exception.go
@@ -36,6 +36,7 @@
 	SIZE_LIMIT                 = 3
 	BAD_VERSION                = 4
 	NOT_IMPLEMENTED            = 5
+	DEPTH_LIMIT                = 6
 )
 
 type tProtocolException struct {
@@ -59,7 +60,7 @@
 	if err == nil {
 		return nil
 	}
-	if e,ok := err.(TProtocolException); ok {
+	if e, ok := err.(TProtocolException); ok {
 		return e
 	}
 	if _, ok := err.(base64.CorruptInputError); ok {
@@ -74,4 +75,3 @@
 	}
 	return &tProtocolException{errType, err.Error()}
 }
-
diff --git a/lib/go/thrift/protocol_test.go b/lib/go/thrift/protocol_test.go
index 632098c..944055c 100644
--- a/lib/go/thrift/protocol_test.go
+++ b/lib/go/thrift/protocol_test.go
@@ -21,6 +21,7 @@
 
 import (
 	"bytes"
+	"context"
 	"io/ioutil"
 	"math"
 	"net"
@@ -31,10 +32,9 @@
 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
+	BYTE_VALUES    []int8
 	INT16_VALUES   []int16
 	INT32_VALUES   []int32
 	INT64_VALUES   []int64
@@ -47,9 +47,8 @@
 	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}
+	BYTE_VALUES = []int8{117, 0, 1, 32, 127, -128, -1}
 	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}
@@ -58,6 +57,7 @@
 }
 
 type HTTPEchoServer struct{}
+type HTTPHeaderEchoServer struct{}
 
 func (p *HTTPEchoServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 	buf, err := ioutil.ReadAll(req.Body)
@@ -70,6 +70,17 @@
 	}
 }
 
+func (p *HTTPHeaderEchoServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+	buf, err := ioutil.ReadAll(req.Body)
+	if err != nil {
+		w.WriteHeader(http.StatusBadRequest)
+		w.Write(buf)
+	} else {
+		w.WriteHeader(http.StatusOK)
+		w.Write(buf)
+	}
+}
+
 func HttpClientSetupForTest(t *testing.T) (net.Listener, net.Addr) {
 	addr, err := FindAvailableTCPServerPort(40000)
 	if err != nil {
@@ -85,6 +96,21 @@
 	return l, addr
 }
 
+func HttpClientSetupForHeaderTest(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)
+		return nil, addr
+	}
+	l, err := net.Listen(addr.Network(), addr.String())
+	if err != nil {
+		t.Fatalf("Unable to setup tcp listener on %s: %s", addr.String(), err)
+		return l, addr
+	}
+	go http.Serve(l, &HTTPHeaderEchoServer{})
+	return l, addr
+}
+
 func ReadWriteProtocolTest(t *testing.T, protocolFactory TProtocolFactory) {
 	buf := bytes.NewBuffer(make([]byte, 0, 1024))
 	l, addr := HttpClientSetupForTest(t)
@@ -93,70 +119,107 @@
 		NewTMemoryBufferTransportFactory(1024),
 		NewStreamTransportFactory(buf, buf, true),
 		NewTFramedTransportFactory(NewTMemoryBufferTransportFactory(1024)),
+		NewTZlibTransportFactoryWithFactory(0, NewTMemoryBufferTransportFactory(1024)),
+		NewTZlibTransportFactoryWithFactory(6, NewTMemoryBufferTransportFactory(1024)),
+		NewTZlibTransportFactoryWithFactory(9, NewTFramedTransportFactory(NewTMemoryBufferTransportFactory(1024))),
 		NewTHttpPostClientTransportFactory("http://" + addr.String()),
 	}
 	for _, tf := range transports {
-		trans := tf.GetTransport(nil)
+		trans, err := tf.GetTransport(nil)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
 		p := protocolFactory.GetProtocol(trans)
 		ReadWriteBool(t, p, trans)
 		trans.Close()
 	}
 	for _, tf := range transports {
-		trans := tf.GetTransport(nil)
+		trans, err := tf.GetTransport(nil)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
 		p := protocolFactory.GetProtocol(trans)
 		ReadWriteByte(t, p, trans)
 		trans.Close()
 	}
 	for _, tf := range transports {
-		trans := tf.GetTransport(nil)
+		trans, err := tf.GetTransport(nil)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
 		p := protocolFactory.GetProtocol(trans)
 		ReadWriteI16(t, p, trans)
 		trans.Close()
 	}
 	for _, tf := range transports {
-		trans := tf.GetTransport(nil)
+		trans, err := tf.GetTransport(nil)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
 		p := protocolFactory.GetProtocol(trans)
 		ReadWriteI32(t, p, trans)
 		trans.Close()
 	}
 	for _, tf := range transports {
-		trans := tf.GetTransport(nil)
+		trans, err := tf.GetTransport(nil)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
 		p := protocolFactory.GetProtocol(trans)
 		ReadWriteI64(t, p, trans)
 		trans.Close()
 	}
 	for _, tf := range transports {
-		trans := tf.GetTransport(nil)
+		trans, err := tf.GetTransport(nil)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
 		p := protocolFactory.GetProtocol(trans)
 		ReadWriteDouble(t, p, trans)
 		trans.Close()
 	}
 	for _, tf := range transports {
-		trans := tf.GetTransport(nil)
+		trans, err := tf.GetTransport(nil)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
 		p := protocolFactory.GetProtocol(trans)
 		ReadWriteString(t, p, trans)
 		trans.Close()
 	}
 	for _, tf := range transports {
-		trans := tf.GetTransport(nil)
+		trans, err := tf.GetTransport(nil)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
 		p := protocolFactory.GetProtocol(trans)
 		ReadWriteBinary(t, p, trans)
 		trans.Close()
 	}
-
 	for _, tf := range transports {
-	  trans := tf.GetTransport(nil)
-	  p := protocolFactory.GetProtocol(trans);
-	  ReadWriteI64(t, p, trans);
-	  ReadWriteDouble(t, p, trans);
-	  ReadWriteBinary(t, p, trans);
-	  ReadWriteByte(t, p, trans);
-	  trans.Close()
+		trans, err := tf.GetTransport(nil)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+		p := protocolFactory.GetProtocol(trans)
+		ReadWriteI64(t, p, trans)
+		ReadWriteDouble(t, p, trans)
+		ReadWriteBinary(t, p, trans)
+		ReadWriteByte(t, p, trans)
+		trans.Close()
 	}
-
 }
 
-func ReadWriteBool(t *testing.T, p TProtocol, trans TTransport) {
+func ReadWriteBool(t testing.TB, p TProtocol, trans TTransport) {
 	thetype := TType(BOOL)
 	thelen := len(BOOL_VALUES)
 	err := p.WriteListBegin(thetype, thelen)
@@ -166,17 +229,17 @@
 	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)
+			t.Errorf("%s: %T %T %v Error writing bool in list at index %v: %v", "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)
+		t.Errorf("%s: %T %T %v Error writing list end: %v", "ReadWriteBool", p, trans, err, BOOL_VALUES)
 	}
-	p.Flush()
+	p.Flush(context.Background())
 	thetype2, thelen2, err := p.ReadListBegin()
 	if err != nil {
-		t.Errorf("%s: %T %T %q Error reading list: %q", "ReadWriteBool", p, trans, err, BOOL_VALUES)
+		t.Errorf("%s: %T %T %v Error reading list: %v", "ReadWriteBool", p, trans, err, BOOL_VALUES)
 	}
 	_, ok := p.(*TSimpleJSONProtocol)
 	if !ok {
@@ -184,16 +247,16 @@
 			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)
+			t.Errorf("%s: %T %T len %v != len %v", "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)
+			t.Errorf("%s: %T %T %v Error reading bool at index %v: %v", "ReadWriteBool", p, trans, err, k, v)
 		}
 		if v != value {
-			t.Errorf("%s: index %d %q %q %q != %q", "ReadWriteBool", k, p, trans, v, value)
+			t.Errorf("%s: index %v %v %v %v != %v", "ReadWriteBool", k, p, trans, v, value)
 		}
 	}
 	err = p.ReadListEnd()
@@ -202,7 +265,7 @@
 	}
 }
 
-func ReadWriteByte(t *testing.T, p TProtocol, trans TTransport) {
+func ReadWriteByte(t testing.TB, p TProtocol, trans TTransport) {
 	thetype := TType(BYTE)
 	thelen := len(BYTE_VALUES)
 	err := p.WriteListBegin(thetype, thelen)
@@ -219,7 +282,7 @@
 	if err != nil {
 		t.Errorf("%s: %T %T %q Error writing list end: %q", "ReadWriteByte", p, trans, err, BYTE_VALUES)
 	}
-	err = p.Flush()
+	err = p.Flush(context.Background())
 	if err != nil {
 		t.Errorf("%s: %T %T %q Error flushing list of bytes: %q", "ReadWriteByte", p, trans, err, BYTE_VALUES)
 	}
@@ -233,7 +296,7 @@
 			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)
+			t.Errorf("%s: %T %T len %v != len %v", "ReadWriteByte", p, trans, thelen, thelen2)
 		}
 	}
 	for k, v := range BYTE_VALUES {
@@ -251,7 +314,7 @@
 	}
 }
 
-func ReadWriteI16(t *testing.T, p TProtocol, trans TTransport) {
+func ReadWriteI16(t testing.TB, p TProtocol, trans TTransport) {
 	thetype := TType(I16)
 	thelen := len(INT16_VALUES)
 	p.WriteListBegin(thetype, thelen)
@@ -259,7 +322,7 @@
 		p.WriteI16(v)
 	}
 	p.WriteListEnd()
-	p.Flush()
+	p.Flush(context.Background())
 	thetype2, thelen2, err := p.ReadListBegin()
 	if err != nil {
 		t.Errorf("%s: %T %T %q Error reading list: %q", "ReadWriteI16", p, trans, err, INT16_VALUES)
@@ -270,7 +333,7 @@
 			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)
+			t.Errorf("%s: %T %T len %v != len %v", "ReadWriteI16", p, trans, thelen, thelen2)
 		}
 	}
 	for k, v := range INT16_VALUES {
@@ -288,7 +351,7 @@
 	}
 }
 
-func ReadWriteI32(t *testing.T, p TProtocol, trans TTransport) {
+func ReadWriteI32(t testing.TB, p TProtocol, trans TTransport) {
 	thetype := TType(I32)
 	thelen := len(INT32_VALUES)
 	p.WriteListBegin(thetype, thelen)
@@ -296,7 +359,7 @@
 		p.WriteI32(v)
 	}
 	p.WriteListEnd()
-	p.Flush()
+	p.Flush(context.Background())
 	thetype2, thelen2, err := p.ReadListBegin()
 	if err != nil {
 		t.Errorf("%s: %T %T %q Error reading list: %q", "ReadWriteI32", p, trans, err, INT32_VALUES)
@@ -307,7 +370,7 @@
 			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)
+			t.Errorf("%s: %T %T len %v != len %v", "ReadWriteI32", p, trans, thelen, thelen2)
 		}
 	}
 	for k, v := range INT32_VALUES {
@@ -324,7 +387,7 @@
 	}
 }
 
-func ReadWriteI64(t *testing.T, p TProtocol, trans TTransport) {
+func ReadWriteI64(t testing.TB, p TProtocol, trans TTransport) {
 	thetype := TType(I64)
 	thelen := len(INT64_VALUES)
 	p.WriteListBegin(thetype, thelen)
@@ -332,7 +395,7 @@
 		p.WriteI64(v)
 	}
 	p.WriteListEnd()
-	p.Flush()
+	p.Flush(context.Background())
 	thetype2, thelen2, err := p.ReadListBegin()
 	if err != nil {
 		t.Errorf("%s: %T %T %q Error reading list: %q", "ReadWriteI64", p, trans, err, INT64_VALUES)
@@ -343,7 +406,7 @@
 			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)
+			t.Errorf("%s: %T %T len %v != len %v", "ReadWriteI64", p, trans, thelen, thelen2)
 		}
 	}
 	for k, v := range INT64_VALUES {
@@ -360,7 +423,7 @@
 	}
 }
 
-func ReadWriteDouble(t *testing.T, p TProtocol, trans TTransport) {
+func ReadWriteDouble(t testing.TB, p TProtocol, trans TTransport) {
 	thetype := TType(DOUBLE)
 	thelen := len(DOUBLE_VALUES)
 	p.WriteListBegin(thetype, thelen)
@@ -368,32 +431,28 @@
 		p.WriteDouble(v)
 	}
 	p.WriteListEnd()
-	p.Flush()
-	wrotebuffer := ""
-	if memtrans, ok := trans.(*TMemoryBuffer); ok {
-		wrotebuffer = memtrans.String()
-	}
+	p.Flush(context.Background())
 	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)
+		t.Errorf("%s: %T %T %v Error reading list: %v", "ReadWriteDouble", p, trans, err, DOUBLE_VALUES)
 	}
 	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)
+		t.Errorf("%s: %T %T len %v != len %v", "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)
+			t.Errorf("%s: %T %T %q Error reading double at index %d: %v", "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)
+				t.Errorf("%s: %T %T math.IsNaN(%v) != math.IsNaN(%v)", "ReadWriteDouble", p, trans, v, value)
 			}
 		} else if v != value {
-			t.Errorf("%s: %T %T %v != %q", "ReadWriteDouble", p, trans, v, value)
+			t.Errorf("%s: %T %T %v != %v", "ReadWriteDouble", p, trans, v, value)
 		}
 	}
 	err = p.ReadListEnd()
@@ -402,7 +461,7 @@
 	}
 }
 
-func ReadWriteString(t *testing.T, p TProtocol, trans TTransport) {
+func ReadWriteString(t testing.TB, p TProtocol, trans TTransport) {
 	thetype := TType(STRING)
 	thelen := len(STRING_VALUES)
 	p.WriteListBegin(thetype, thelen)
@@ -410,7 +469,7 @@
 		p.WriteString(v)
 	}
 	p.WriteListEnd()
-	p.Flush()
+	p.Flush(context.Background())
 	thetype2, thelen2, err := p.ReadListBegin()
 	if err != nil {
 		t.Errorf("%s: %T %T %q Error reading list: %q", "ReadWriteString", p, trans, err, STRING_VALUES)
@@ -421,7 +480,7 @@
 			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)
+			t.Errorf("%s: %T %T len %v != len %v", "ReadWriteString", p, trans, thelen, thelen2)
 		}
 	}
 	for k, v := range STRING_VALUES {
@@ -430,7 +489,7 @@
 			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)
+			t.Errorf("%s: %T %T %v != %v", "ReadWriteString", p, trans, v, value)
 		}
 	}
 	if err != nil {
@@ -438,10 +497,10 @@
 	}
 }
 
-func ReadWriteBinary(t *testing.T, p TProtocol, trans TTransport) {
+func ReadWriteBinary(t testing.TB, p TProtocol, trans TTransport) {
 	v := protocol_bdata
 	p.WriteBinary(v)
-	p.Flush()
+	p.Flush(context.Background())
 	value, err := p.ReadBinary()
 	if err != nil {
 		t.Errorf("%s: %T %T Unable to read binary: %s", "ReadWriteBinary", p, trans, err.Error())
diff --git a/lib/go/thrift/rich_transport.go b/lib/go/thrift/rich_transport.go
new file mode 100644
index 0000000..4025beb
--- /dev/null
+++ b/lib/go/thrift/rich_transport.go
@@ -0,0 +1,68 @@
+/*
+ * 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 "io"
+
+type RichTransport struct {
+	TTransport
+}
+
+// Wraps Transport to provide TRichTransport interface
+func NewTRichTransport(trans TTransport) *RichTransport {
+	return &RichTransport{trans}
+}
+
+func (r *RichTransport) ReadByte() (c byte, err error) {
+	return readByte(r.TTransport)
+}
+
+func (r *RichTransport) WriteByte(c byte) error {
+	return writeByte(r.TTransport, c)
+}
+
+func (r *RichTransport) WriteString(s string) (n int, err error) {
+	return r.Write([]byte(s))
+}
+
+func (r *RichTransport) RemainingBytes() (num_bytes uint64) {
+	return r.TTransport.RemainingBytes()
+}
+
+func readByte(r io.Reader) (c byte, err error) {
+	v := [1]byte{0}
+	n, err := r.Read(v[0:1])
+	if n > 0 && (err == nil || err == io.EOF) {
+		return v[0], nil
+	}
+	if n > 0 && err != nil {
+		return v[0], err
+	}
+	if err != nil {
+		return 0, err
+	}
+	return v[0], nil
+}
+
+func writeByte(w io.Writer, c byte) error {
+	v := [1]byte{c}
+	_, err := w.Write(v[0:1])
+	return err
+}
diff --git a/lib/go/thrift/rich_transport_test.go b/lib/go/thrift/rich_transport_test.go
new file mode 100644
index 0000000..25c3fd5
--- /dev/null
+++ b/lib/go/thrift/rich_transport_test.go
@@ -0,0 +1,89 @@
+/*
+ * 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"
+	"errors"
+	"io"
+	"reflect"
+	"testing"
+)
+
+func TestEnsureTransportsAreRich(t *testing.T) {
+	buf := bytes.NewBuffer(make([]byte, 0, 1024))
+
+	transports := []TTransportFactory{
+		NewTMemoryBufferTransportFactory(1024),
+		NewStreamTransportFactory(buf, buf, true),
+		NewTFramedTransportFactory(NewTMemoryBufferTransportFactory(1024)),
+		NewTHttpPostClientTransportFactory("http://127.0.0.1"),
+	}
+	for _, tf := range transports {
+		trans, err := tf.GetTransport(nil)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+		_, ok := trans.(TRichTransport)
+		if !ok {
+			t.Errorf("Transport %s does not implement TRichTransport interface", reflect.ValueOf(trans))
+		}
+	}
+}
+
+// TestReadByte tests whether readByte handles error cases correctly.
+func TestReadByte(t *testing.T) {
+	for i, test := range readByteTests {
+		v, err := readByte(test.r)
+		if v != test.v {
+			t.Fatalf("TestReadByte %d: value differs. Expected %d, got %d", i, test.v, test.r.v)
+		}
+		if err != test.err {
+			t.Fatalf("TestReadByte %d: error differs. Expected %s, got %s", i, test.err, test.r.err)
+		}
+	}
+}
+
+var someError = errors.New("Some error")
+var readByteTests = []struct {
+	r   *mockReader
+	v   byte
+	err error
+}{
+	{&mockReader{0, 55, io.EOF}, 0, io.EOF},        // reader sends EOF w/o data
+	{&mockReader{0, 55, someError}, 0, someError},  // reader sends some other error
+	{&mockReader{1, 55, nil}, 55, nil},             // reader sends data w/o error
+	{&mockReader{1, 55, io.EOF}, 55, nil},          // reader sends data with EOF
+	{&mockReader{1, 55, someError}, 55, someError}, // reader sends data withsome error
+}
+
+type mockReader struct {
+	n   int
+	v   byte
+	err error
+}
+
+func (r *mockReader) Read(p []byte) (n int, err error) {
+	if r.n > 0 {
+		p[0] = r.v
+	}
+	return r.n, r.err
+}
diff --git a/lib/go/thrift/serializer.go b/lib/go/thrift/serializer.go
new file mode 100644
index 0000000..1ff4d37
--- /dev/null
+++ b/lib/go/thrift/serializer.go
@@ -0,0 +1,79 @@
+/*
+ * 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 (
+	"context"
+)
+
+type TSerializer struct {
+	Transport *TMemoryBuffer
+	Protocol  TProtocol
+}
+
+type TStruct interface {
+	Write(p TProtocol) error
+	Read(p TProtocol) error
+}
+
+func NewTSerializer() *TSerializer {
+	transport := NewTMemoryBufferLen(1024)
+	protocol := NewTBinaryProtocolFactoryDefault().GetProtocol(transport)
+
+	return &TSerializer{
+		transport,
+		protocol}
+}
+
+func (t *TSerializer) WriteString(ctx context.Context, msg TStruct) (s string, err error) {
+	t.Transport.Reset()
+
+	if err = msg.Write(t.Protocol); err != nil {
+		return
+	}
+
+	if err = t.Protocol.Flush(ctx); err != nil {
+		return
+	}
+	if err = t.Transport.Flush(ctx); err != nil {
+		return
+	}
+
+	return t.Transport.String(), nil
+}
+
+func (t *TSerializer) Write(ctx context.Context, msg TStruct) (b []byte, err error) {
+	t.Transport.Reset()
+
+	if err = msg.Write(t.Protocol); err != nil {
+		return
+	}
+
+	if err = t.Protocol.Flush(ctx); err != nil {
+		return
+	}
+
+	if err = t.Transport.Flush(ctx); err != nil {
+		return
+	}
+
+	b = append(b, t.Transport.Bytes()...)
+	return
+}
diff --git a/lib/go/thrift/serializer_test.go b/lib/go/thrift/serializer_test.go
new file mode 100644
index 0000000..32227ef
--- /dev/null
+++ b/lib/go/thrift/serializer_test.go
@@ -0,0 +1,170 @@
+/*
+ * 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 (
+	"context"
+	"errors"
+	"fmt"
+	"testing"
+)
+
+type ProtocolFactory interface {
+	GetProtocol(t TTransport) TProtocol
+}
+
+func compareStructs(m, m1 MyTestStruct) (bool, error) {
+	switch {
+	case m.On != m1.On:
+		return false, errors.New("Boolean not equal")
+	case m.B != m1.B:
+		return false, errors.New("Byte not equal")
+	case m.Int16 != m1.Int16:
+		return false, errors.New("Int16 not equal")
+	case m.Int32 != m1.Int32:
+		return false, errors.New("Int32 not equal")
+	case m.Int64 != m1.Int64:
+		return false, errors.New("Int64 not equal")
+	case m.D != m1.D:
+		return false, errors.New("Double not equal")
+	case m.St != m1.St:
+		return false, errors.New("String not equal")
+
+	case len(m.Bin) != len(m1.Bin):
+		return false, errors.New("Binary size not equal")
+	case len(m.Bin) == len(m1.Bin):
+		for i := range m.Bin {
+			if m.Bin[i] != m1.Bin[i] {
+				return false, errors.New("Binary not equal")
+			}
+		}
+	case len(m.StringMap) != len(m1.StringMap):
+		return false, errors.New("StringMap size not equal")
+	case len(m.StringList) != len(m1.StringList):
+		return false, errors.New("StringList size not equal")
+	case len(m.StringSet) != len(m1.StringSet):
+		return false, errors.New("StringSet size not equal")
+
+	case m.E != m1.E:
+		return false, errors.New("MyTestEnum not equal")
+
+	default:
+		return true, nil
+
+	}
+	return true, nil
+}
+
+func ProtocolTest1(test *testing.T, pf ProtocolFactory) (bool, error) {
+	t := NewTSerializer()
+	t.Protocol = pf.GetProtocol(t.Transport)
+	var m = MyTestStruct{}
+	m.On = true
+	m.B = int8(0)
+	m.Int16 = 1
+	m.Int32 = 2
+	m.Int64 = 3
+	m.D = 4.1
+	m.St = "Test"
+	m.Bin = make([]byte, 10)
+	m.StringMap = make(map[string]string, 5)
+	m.StringList = make([]string, 5)
+	m.StringSet = make(map[string]struct{}, 5)
+	m.E = 2
+
+	s, err := t.WriteString(context.Background(), &m)
+	if err != nil {
+		return false, errors.New(fmt.Sprintf("Unable to Serialize struct\n\t %s", err))
+	}
+
+	t1 := NewTDeserializer()
+	t1.Protocol = pf.GetProtocol(t1.Transport)
+	var m1 = MyTestStruct{}
+	if err = t1.ReadString(&m1, s); err != nil {
+		return false, errors.New(fmt.Sprintf("Unable to Deserialize struct\n\t %s", err))
+
+	}
+
+	return compareStructs(m, m1)
+
+}
+
+func ProtocolTest2(test *testing.T, pf ProtocolFactory) (bool, error) {
+	t := NewTSerializer()
+	t.Protocol = pf.GetProtocol(t.Transport)
+	var m = MyTestStruct{}
+	m.On = false
+	m.B = int8(0)
+	m.Int16 = 1
+	m.Int32 = 2
+	m.Int64 = 3
+	m.D = 4.1
+	m.St = "Test"
+	m.Bin = make([]byte, 10)
+	m.StringMap = make(map[string]string, 5)
+	m.StringList = make([]string, 5)
+	m.StringSet = make(map[string]struct{}, 5)
+	m.E = 2
+
+	s, err := t.WriteString(context.Background(), &m)
+	if err != nil {
+		return false, errors.New(fmt.Sprintf("Unable to Serialize struct\n\t %s", err))
+
+	}
+
+	t1 := NewTDeserializer()
+	t1.Protocol = pf.GetProtocol(t1.Transport)
+	var m1 = MyTestStruct{}
+	if err = t1.ReadString(&m1, s); err != nil {
+		return false, errors.New(fmt.Sprintf("Unable to Deserialize struct\n\t %s", err))
+
+	}
+
+	return compareStructs(m, m1)
+
+}
+
+func TestSerializer(t *testing.T) {
+
+	var protocol_factories map[string]ProtocolFactory
+	protocol_factories = make(map[string]ProtocolFactory)
+	protocol_factories["Binary"] = NewTBinaryProtocolFactoryDefault()
+	protocol_factories["Compact"] = NewTCompactProtocolFactory()
+	//protocol_factories["SimpleJSON"] = NewTSimpleJSONProtocolFactory() - write only, can't be read back by design
+	protocol_factories["JSON"] = NewTJSONProtocolFactory()
+
+	var tests map[string]func(*testing.T, ProtocolFactory) (bool, error)
+	tests = make(map[string]func(*testing.T, ProtocolFactory) (bool, error))
+	tests["Test 1"] = ProtocolTest1
+	tests["Test 2"] = ProtocolTest2
+	//tests["Test 3"] = ProtocolTest3 // Example of how to add additional tests
+
+	for name, pf := range protocol_factories {
+
+		for test, f := range tests {
+
+			if s, err := f(t, pf); !s || err != nil {
+				t.Errorf("%s Failed for %s protocol\n\t %s", test, name, err)
+			}
+
+		}
+	}
+
+}
diff --git a/lib/go/thrift/serializer_types_test.go b/lib/go/thrift/serializer_types_test.go
new file mode 100644
index 0000000..e5472bb
--- /dev/null
+++ b/lib/go/thrift/serializer_types_test.go
@@ -0,0 +1,633 @@
+/*
+ * 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
+
+// Autogenerated by Thrift Compiler (FIXME)
+// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+
+/* THE FOLLOWING THRIFT FILE WAS USED TO CREATE THIS
+
+enum MyTestEnum {
+	FIRST = 1,
+	SECOND = 2,
+	THIRD = 3,
+	FOURTH = 4,
+}
+
+struct MyTestStruct {
+	1: bool on,
+	2: byte b,
+	3: i16 int16,
+	4: i32 int32,
+	5: i64 int64,
+	6: double d,
+	7: string st,
+	8: binary bin,
+	9: map<string, string> stringMap,
+	10: list<string> stringList,
+	11: set<string> stringSet,
+	12: MyTestEnum e,
+}
+*/
+
+import (
+	"fmt"
+)
+
+// (needed to ensure safety because of naive import list construction.)
+var _ = ZERO
+var _ = fmt.Printf
+
+var GoUnusedProtection__ int
+
+type MyTestEnum int64
+
+const (
+	MyTestEnum_FIRST  MyTestEnum = 1
+	MyTestEnum_SECOND MyTestEnum = 2
+	MyTestEnum_THIRD  MyTestEnum = 3
+	MyTestEnum_FOURTH MyTestEnum = 4
+)
+
+func (p MyTestEnum) String() string {
+	switch p {
+	case MyTestEnum_FIRST:
+		return "FIRST"
+	case MyTestEnum_SECOND:
+		return "SECOND"
+	case MyTestEnum_THIRD:
+		return "THIRD"
+	case MyTestEnum_FOURTH:
+		return "FOURTH"
+	}
+	return "<UNSET>"
+}
+
+func MyTestEnumFromString(s string) (MyTestEnum, error) {
+	switch s {
+	case "FIRST":
+		return MyTestEnum_FIRST, nil
+	case "SECOND":
+		return MyTestEnum_SECOND, nil
+	case "THIRD":
+		return MyTestEnum_THIRD, nil
+	case "FOURTH":
+		return MyTestEnum_FOURTH, nil
+	}
+	return MyTestEnum(0), fmt.Errorf("not a valid MyTestEnum string")
+}
+
+func MyTestEnumPtr(v MyTestEnum) *MyTestEnum { return &v }
+
+type MyTestStruct struct {
+	On         bool                `thrift:"on,1" json:"on"`
+	B          int8                `thrift:"b,2" json:"b"`
+	Int16      int16               `thrift:"int16,3" json:"int16"`
+	Int32      int32               `thrift:"int32,4" json:"int32"`
+	Int64      int64               `thrift:"int64,5" json:"int64"`
+	D          float64             `thrift:"d,6" json:"d"`
+	St         string              `thrift:"st,7" json:"st"`
+	Bin        []byte              `thrift:"bin,8" json:"bin"`
+	StringMap  map[string]string   `thrift:"stringMap,9" json:"stringMap"`
+	StringList []string            `thrift:"stringList,10" json:"stringList"`
+	StringSet  map[string]struct{} `thrift:"stringSet,11" json:"stringSet"`
+	E          MyTestEnum          `thrift:"e,12" json:"e"`
+}
+
+func NewMyTestStruct() *MyTestStruct {
+	return &MyTestStruct{}
+}
+
+func (p *MyTestStruct) GetOn() bool {
+	return p.On
+}
+
+func (p *MyTestStruct) GetB() int8 {
+	return p.B
+}
+
+func (p *MyTestStruct) GetInt16() int16 {
+	return p.Int16
+}
+
+func (p *MyTestStruct) GetInt32() int32 {
+	return p.Int32
+}
+
+func (p *MyTestStruct) GetInt64() int64 {
+	return p.Int64
+}
+
+func (p *MyTestStruct) GetD() float64 {
+	return p.D
+}
+
+func (p *MyTestStruct) GetSt() string {
+	return p.St
+}
+
+func (p *MyTestStruct) GetBin() []byte {
+	return p.Bin
+}
+
+func (p *MyTestStruct) GetStringMap() map[string]string {
+	return p.StringMap
+}
+
+func (p *MyTestStruct) GetStringList() []string {
+	return p.StringList
+}
+
+func (p *MyTestStruct) GetStringSet() map[string]struct{} {
+	return p.StringSet
+}
+
+func (p *MyTestStruct) GetE() MyTestEnum {
+	return p.E
+}
+func (p *MyTestStruct) Read(iprot TProtocol) error {
+	if _, err := iprot.ReadStructBegin(); err != nil {
+		return PrependError(fmt.Sprintf("%T read error: ", p), err)
+	}
+	for {
+		_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
+		if err != nil {
+			return PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
+		}
+		if fieldTypeId == STOP {
+			break
+		}
+		switch fieldId {
+		case 1:
+			if err := p.readField1(iprot); err != nil {
+				return err
+			}
+		case 2:
+			if err := p.readField2(iprot); err != nil {
+				return err
+			}
+		case 3:
+			if err := p.readField3(iprot); err != nil {
+				return err
+			}
+		case 4:
+			if err := p.readField4(iprot); err != nil {
+				return err
+			}
+		case 5:
+			if err := p.readField5(iprot); err != nil {
+				return err
+			}
+		case 6:
+			if err := p.readField6(iprot); err != nil {
+				return err
+			}
+		case 7:
+			if err := p.readField7(iprot); err != nil {
+				return err
+			}
+		case 8:
+			if err := p.readField8(iprot); err != nil {
+				return err
+			}
+		case 9:
+			if err := p.readField9(iprot); err != nil {
+				return err
+			}
+		case 10:
+			if err := p.readField10(iprot); err != nil {
+				return err
+			}
+		case 11:
+			if err := p.readField11(iprot); err != nil {
+				return err
+			}
+		case 12:
+			if err := p.readField12(iprot); err != nil {
+				return err
+			}
+		default:
+			if err := iprot.Skip(fieldTypeId); err != nil {
+				return err
+			}
+		}
+		if err := iprot.ReadFieldEnd(); err != nil {
+			return err
+		}
+	}
+	if err := iprot.ReadStructEnd(); err != nil {
+		return PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
+	}
+	return nil
+}
+
+func (p *MyTestStruct) readField1(iprot TProtocol) error {
+	if v, err := iprot.ReadBool(); err != nil {
+		return PrependError("error reading field 1: ", err)
+	} else {
+		p.On = v
+	}
+	return nil
+}
+
+func (p *MyTestStruct) readField2(iprot TProtocol) error {
+	if v, err := iprot.ReadByte(); err != nil {
+		return PrependError("error reading field 2: ", err)
+	} else {
+		temp := int8(v)
+		p.B = temp
+	}
+	return nil
+}
+
+func (p *MyTestStruct) readField3(iprot TProtocol) error {
+	if v, err := iprot.ReadI16(); err != nil {
+		return PrependError("error reading field 3: ", err)
+	} else {
+		p.Int16 = v
+	}
+	return nil
+}
+
+func (p *MyTestStruct) readField4(iprot TProtocol) error {
+	if v, err := iprot.ReadI32(); err != nil {
+		return PrependError("error reading field 4: ", err)
+	} else {
+		p.Int32 = v
+	}
+	return nil
+}
+
+func (p *MyTestStruct) readField5(iprot TProtocol) error {
+	if v, err := iprot.ReadI64(); err != nil {
+		return PrependError("error reading field 5: ", err)
+	} else {
+		p.Int64 = v
+	}
+	return nil
+}
+
+func (p *MyTestStruct) readField6(iprot TProtocol) error {
+	if v, err := iprot.ReadDouble(); err != nil {
+		return PrependError("error reading field 6: ", err)
+	} else {
+		p.D = v
+	}
+	return nil
+}
+
+func (p *MyTestStruct) readField7(iprot TProtocol) error {
+	if v, err := iprot.ReadString(); err != nil {
+		return PrependError("error reading field 7: ", err)
+	} else {
+		p.St = v
+	}
+	return nil
+}
+
+func (p *MyTestStruct) readField8(iprot TProtocol) error {
+	if v, err := iprot.ReadBinary(); err != nil {
+		return PrependError("error reading field 8: ", err)
+	} else {
+		p.Bin = v
+	}
+	return nil
+}
+
+func (p *MyTestStruct) readField9(iprot TProtocol) error {
+	_, _, size, err := iprot.ReadMapBegin()
+	if err != nil {
+		return PrependError("error reading map begin: ", err)
+	}
+	tMap := make(map[string]string, size)
+	p.StringMap = tMap
+	for i := 0; i < size; i++ {
+		var _key0 string
+		if v, err := iprot.ReadString(); err != nil {
+			return PrependError("error reading field 0: ", err)
+		} else {
+			_key0 = v
+		}
+		var _val1 string
+		if v, err := iprot.ReadString(); err != nil {
+			return PrependError("error reading field 0: ", err)
+		} else {
+			_val1 = v
+		}
+		p.StringMap[_key0] = _val1
+	}
+	if err := iprot.ReadMapEnd(); err != nil {
+		return PrependError("error reading map end: ", err)
+	}
+	return nil
+}
+
+func (p *MyTestStruct) readField10(iprot TProtocol) error {
+	_, size, err := iprot.ReadListBegin()
+	if err != nil {
+		return PrependError("error reading list begin: ", err)
+	}
+	tSlice := make([]string, 0, size)
+	p.StringList = tSlice
+	for i := 0; i < size; i++ {
+		var _elem2 string
+		if v, err := iprot.ReadString(); err != nil {
+			return PrependError("error reading field 0: ", err)
+		} else {
+			_elem2 = v
+		}
+		p.StringList = append(p.StringList, _elem2)
+	}
+	if err := iprot.ReadListEnd(); err != nil {
+		return PrependError("error reading list end: ", err)
+	}
+	return nil
+}
+
+func (p *MyTestStruct) readField11(iprot TProtocol) error {
+	_, size, err := iprot.ReadSetBegin()
+	if err != nil {
+		return PrependError("error reading set begin: ", err)
+	}
+	tSet := make(map[string]struct{}, size)
+	p.StringSet = tSet
+	for i := 0; i < size; i++ {
+		var _elem3 string
+		if v, err := iprot.ReadString(); err != nil {
+			return PrependError("error reading field 0: ", err)
+		} else {
+			_elem3 = v
+		}
+		p.StringSet[_elem3] = struct{}{}
+	}
+	if err := iprot.ReadSetEnd(); err != nil {
+		return PrependError("error reading set end: ", err)
+	}
+	return nil
+}
+
+func (p *MyTestStruct) readField12(iprot TProtocol) error {
+	if v, err := iprot.ReadI32(); err != nil {
+		return PrependError("error reading field 12: ", err)
+	} else {
+		temp := MyTestEnum(v)
+		p.E = temp
+	}
+	return nil
+}
+
+func (p *MyTestStruct) Write(oprot TProtocol) error {
+	if err := oprot.WriteStructBegin("MyTestStruct"); err != nil {
+		return PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
+	}
+	if err := p.writeField1(oprot); err != nil {
+		return err
+	}
+	if err := p.writeField2(oprot); err != nil {
+		return err
+	}
+	if err := p.writeField3(oprot); err != nil {
+		return err
+	}
+	if err := p.writeField4(oprot); err != nil {
+		return err
+	}
+	if err := p.writeField5(oprot); err != nil {
+		return err
+	}
+	if err := p.writeField6(oprot); err != nil {
+		return err
+	}
+	if err := p.writeField7(oprot); err != nil {
+		return err
+	}
+	if err := p.writeField8(oprot); err != nil {
+		return err
+	}
+	if err := p.writeField9(oprot); err != nil {
+		return err
+	}
+	if err := p.writeField10(oprot); err != nil {
+		return err
+	}
+	if err := p.writeField11(oprot); err != nil {
+		return err
+	}
+	if err := p.writeField12(oprot); err != nil {
+		return err
+	}
+	if err := oprot.WriteFieldStop(); err != nil {
+		return PrependError("write field stop error: ", err)
+	}
+	if err := oprot.WriteStructEnd(); err != nil {
+		return PrependError("write struct stop error: ", err)
+	}
+	return nil
+}
+
+func (p *MyTestStruct) writeField1(oprot TProtocol) (err error) {
+	if err := oprot.WriteFieldBegin("on", BOOL, 1); err != nil {
+		return PrependError(fmt.Sprintf("%T write field begin error 1:on: ", p), err)
+	}
+	if err := oprot.WriteBool(bool(p.On)); err != nil {
+		return PrependError(fmt.Sprintf("%T.on (1) field write error: ", p), err)
+	}
+	if err := oprot.WriteFieldEnd(); err != nil {
+		return PrependError(fmt.Sprintf("%T write field end error 1:on: ", p), err)
+	}
+	return err
+}
+
+func (p *MyTestStruct) writeField2(oprot TProtocol) (err error) {
+	if err := oprot.WriteFieldBegin("b", BYTE, 2); err != nil {
+		return PrependError(fmt.Sprintf("%T write field begin error 2:b: ", p), err)
+	}
+	if err := oprot.WriteByte(int8(p.B)); err != nil {
+		return PrependError(fmt.Sprintf("%T.b (2) field write error: ", p), err)
+	}
+	if err := oprot.WriteFieldEnd(); err != nil {
+		return PrependError(fmt.Sprintf("%T write field end error 2:b: ", p), err)
+	}
+	return err
+}
+
+func (p *MyTestStruct) writeField3(oprot TProtocol) (err error) {
+	if err := oprot.WriteFieldBegin("int16", I16, 3); err != nil {
+		return PrependError(fmt.Sprintf("%T write field begin error 3:int16: ", p), err)
+	}
+	if err := oprot.WriteI16(int16(p.Int16)); err != nil {
+		return PrependError(fmt.Sprintf("%T.int16 (3) field write error: ", p), err)
+	}
+	if err := oprot.WriteFieldEnd(); err != nil {
+		return PrependError(fmt.Sprintf("%T write field end error 3:int16: ", p), err)
+	}
+	return err
+}
+
+func (p *MyTestStruct) writeField4(oprot TProtocol) (err error) {
+	if err := oprot.WriteFieldBegin("int32", I32, 4); err != nil {
+		return PrependError(fmt.Sprintf("%T write field begin error 4:int32: ", p), err)
+	}
+	if err := oprot.WriteI32(int32(p.Int32)); err != nil {
+		return PrependError(fmt.Sprintf("%T.int32 (4) field write error: ", p), err)
+	}
+	if err := oprot.WriteFieldEnd(); err != nil {
+		return PrependError(fmt.Sprintf("%T write field end error 4:int32: ", p), err)
+	}
+	return err
+}
+
+func (p *MyTestStruct) writeField5(oprot TProtocol) (err error) {
+	if err := oprot.WriteFieldBegin("int64", I64, 5); err != nil {
+		return PrependError(fmt.Sprintf("%T write field begin error 5:int64: ", p), err)
+	}
+	if err := oprot.WriteI64(int64(p.Int64)); err != nil {
+		return PrependError(fmt.Sprintf("%T.int64 (5) field write error: ", p), err)
+	}
+	if err := oprot.WriteFieldEnd(); err != nil {
+		return PrependError(fmt.Sprintf("%T write field end error 5:int64: ", p), err)
+	}
+	return err
+}
+
+func (p *MyTestStruct) writeField6(oprot TProtocol) (err error) {
+	if err := oprot.WriteFieldBegin("d", DOUBLE, 6); err != nil {
+		return PrependError(fmt.Sprintf("%T write field begin error 6:d: ", p), err)
+	}
+	if err := oprot.WriteDouble(float64(p.D)); err != nil {
+		return PrependError(fmt.Sprintf("%T.d (6) field write error: ", p), err)
+	}
+	if err := oprot.WriteFieldEnd(); err != nil {
+		return PrependError(fmt.Sprintf("%T write field end error 6:d: ", p), err)
+	}
+	return err
+}
+
+func (p *MyTestStruct) writeField7(oprot TProtocol) (err error) {
+	if err := oprot.WriteFieldBegin("st", STRING, 7); err != nil {
+		return PrependError(fmt.Sprintf("%T write field begin error 7:st: ", p), err)
+	}
+	if err := oprot.WriteString(string(p.St)); err != nil {
+		return PrependError(fmt.Sprintf("%T.st (7) field write error: ", p), err)
+	}
+	if err := oprot.WriteFieldEnd(); err != nil {
+		return PrependError(fmt.Sprintf("%T write field end error 7:st: ", p), err)
+	}
+	return err
+}
+
+func (p *MyTestStruct) writeField8(oprot TProtocol) (err error) {
+	if err := oprot.WriteFieldBegin("bin", STRING, 8); err != nil {
+		return PrependError(fmt.Sprintf("%T write field begin error 8:bin: ", p), err)
+	}
+	if err := oprot.WriteBinary(p.Bin); err != nil {
+		return PrependError(fmt.Sprintf("%T.bin (8) field write error: ", p), err)
+	}
+	if err := oprot.WriteFieldEnd(); err != nil {
+		return PrependError(fmt.Sprintf("%T write field end error 8:bin: ", p), err)
+	}
+	return err
+}
+
+func (p *MyTestStruct) writeField9(oprot TProtocol) (err error) {
+	if err := oprot.WriteFieldBegin("stringMap", MAP, 9); err != nil {
+		return PrependError(fmt.Sprintf("%T write field begin error 9:stringMap: ", p), err)
+	}
+	if err := oprot.WriteMapBegin(STRING, STRING, len(p.StringMap)); err != nil {
+		return PrependError("error writing map begin: ", err)
+	}
+	for k, v := range p.StringMap {
+		if err := oprot.WriteString(string(k)); err != nil {
+			return PrependError(fmt.Sprintf("%T. (0) field write error: ", p), err)
+		}
+		if err := oprot.WriteString(string(v)); err != nil {
+			return PrependError(fmt.Sprintf("%T. (0) field write error: ", p), err)
+		}
+	}
+	if err := oprot.WriteMapEnd(); err != nil {
+		return PrependError("error writing map end: ", err)
+	}
+	if err := oprot.WriteFieldEnd(); err != nil {
+		return PrependError(fmt.Sprintf("%T write field end error 9:stringMap: ", p), err)
+	}
+	return err
+}
+
+func (p *MyTestStruct) writeField10(oprot TProtocol) (err error) {
+	if err := oprot.WriteFieldBegin("stringList", LIST, 10); err != nil {
+		return PrependError(fmt.Sprintf("%T write field begin error 10:stringList: ", p), err)
+	}
+	if err := oprot.WriteListBegin(STRING, len(p.StringList)); err != nil {
+		return PrependError("error writing list begin: ", err)
+	}
+	for _, v := range p.StringList {
+		if err := oprot.WriteString(string(v)); err != nil {
+			return PrependError(fmt.Sprintf("%T. (0) field write error: ", p), err)
+		}
+	}
+	if err := oprot.WriteListEnd(); err != nil {
+		return PrependError("error writing list end: ", err)
+	}
+	if err := oprot.WriteFieldEnd(); err != nil {
+		return PrependError(fmt.Sprintf("%T write field end error 10:stringList: ", p), err)
+	}
+	return err
+}
+
+func (p *MyTestStruct) writeField11(oprot TProtocol) (err error) {
+	if err := oprot.WriteFieldBegin("stringSet", SET, 11); err != nil {
+		return PrependError(fmt.Sprintf("%T write field begin error 11:stringSet: ", p), err)
+	}
+	if err := oprot.WriteSetBegin(STRING, len(p.StringSet)); err != nil {
+		return PrependError("error writing set begin: ", err)
+	}
+	for v := range p.StringSet {
+		if err := oprot.WriteString(string(v)); err != nil {
+			return PrependError(fmt.Sprintf("%T. (0) field write error: ", p), err)
+		}
+	}
+	if err := oprot.WriteSetEnd(); err != nil {
+		return PrependError("error writing set end: ", err)
+	}
+	if err := oprot.WriteFieldEnd(); err != nil {
+		return PrependError(fmt.Sprintf("%T write field end error 11:stringSet: ", p), err)
+	}
+	return err
+}
+
+func (p *MyTestStruct) writeField12(oprot TProtocol) (err error) {
+	if err := oprot.WriteFieldBegin("e", I32, 12); err != nil {
+		return PrependError(fmt.Sprintf("%T write field begin error 12:e: ", p), err)
+	}
+	if err := oprot.WriteI32(int32(p.E)); err != nil {
+		return PrependError(fmt.Sprintf("%T.e (12) field write error: ", p), err)
+	}
+	if err := oprot.WriteFieldEnd(); err != nil {
+		return PrependError(fmt.Sprintf("%T write field end error 12:e: ", p), err)
+	}
+	return err
+}
+
+func (p *MyTestStruct) String() string {
+	if p == nil {
+		return "<nil>"
+	}
+	return fmt.Sprintf("MyTestStruct(%+v)", *p)
+}
diff --git a/lib/go/thrift/server_socket.go b/lib/go/thrift/server_socket.go
index 1a01095..7dd24ae 100644
--- a/lib/go/thrift/server_socket.go
+++ b/lib/go/thrift/server_socket.go
@@ -21,6 +21,7 @@
 
 import (
 	"net"
+	"sync"
 	"time"
 )
 
@@ -28,7 +29,10 @@
 	listener      net.Listener
 	addr          net.Addr
 	clientTimeout time.Duration
-	interrupted   bool
+
+	// Protects the interrupted value to make it thread safe.
+	mu          sync.RWMutex
+	interrupted bool
 }
 
 func NewTServerSocket(listenAddr string) (*TServerSocket, error) {
@@ -43,7 +47,14 @@
 	return &TServerSocket{addr: addr, clientTimeout: clientTimeout}, nil
 }
 
+// Creates a TServerSocket from a net.Addr
+func NewTServerSocketFromAddrTimeout(addr net.Addr, clientTimeout time.Duration) *TServerSocket {
+	return &TServerSocket{addr: addr, clientTimeout: clientTimeout}
+}
+
 func (p *TServerSocket) Listen() error {
+	p.mu.Lock()
+	defer p.mu.Unlock()
 	if p.IsListening() {
 		return nil
 	}
@@ -56,13 +67,22 @@
 }
 
 func (p *TServerSocket) Accept() (TTransport, error) {
-	if p.interrupted {
+	p.mu.RLock()
+	interrupted := p.interrupted
+	p.mu.RUnlock()
+
+	if interrupted {
 		return nil, errTransportInterrupted
 	}
-	if p.listener == nil {
+
+	p.mu.Lock()
+	listener := p.listener
+	p.mu.Unlock()
+	if listener == nil {
 		return nil, NewTTransportException(NOT_OPEN, "No underlying server socket")
 	}
-	conn, err := p.listener.Accept()
+
+	conn, err := listener.Accept()
 	if err != nil {
 		return nil, NewTTransportExceptionFromError(err)
 	}
@@ -76,6 +96,8 @@
 
 // Connects the socket, creating a new socket object if necessary.
 func (p *TServerSocket) Open() error {
+	p.mu.Lock()
+	defer p.mu.Unlock()
 	if p.IsListening() {
 		return NewTTransportException(ALREADY_OPEN, "Server socket already open")
 	}
@@ -88,20 +110,28 @@
 }
 
 func (p *TServerSocket) Addr() net.Addr {
+	if p.listener != nil {
+		return p.listener.Addr()
+	}
 	return p.addr
 }
 
 func (p *TServerSocket) Close() error {
-	defer func() {
-		p.listener = nil
-	}()
+	var err error
+	p.mu.Lock()
 	if p.IsListening() {
-		return p.listener.Close()
+		err = p.listener.Close()
+		p.listener = nil
 	}
-	return nil
+	p.mu.Unlock()
+	return err
 }
 
 func (p *TServerSocket) Interrupt() error {
+	p.mu.Lock()
 	p.interrupted = true
+	p.mu.Unlock()
+	p.Close()
+
 	return nil
 }
diff --git a/lib/go/thrift/server_socket_test.go b/lib/go/thrift/server_socket_test.go
new file mode 100644
index 0000000..f1e1983
--- /dev/null
+++ b/lib/go/thrift/server_socket_test.go
@@ -0,0 +1,60 @@
+/*
+ * 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 (
+	"fmt"
+	"testing"
+)
+
+func TestSocketIsntListeningAfterInterrupt(t *testing.T) {
+	host := "127.0.0.1"
+	port := 9090
+	addr := fmt.Sprintf("%s:%d", host, port)
+
+	socket := CreateServerSocket(t, addr)
+	socket.Listen()
+	socket.Interrupt()
+
+	newSocket := CreateServerSocket(t, addr)
+	err := newSocket.Listen()
+	defer newSocket.Interrupt()
+	if err != nil {
+		t.Fatalf("Failed to rebinds: %s", err)
+	}
+}
+
+func TestSocketConcurrency(t *testing.T) {
+	host := "127.0.0.1"
+	port := 9090
+	addr := fmt.Sprintf("%s:%d", host, port)
+
+	socket := CreateServerSocket(t, addr)
+	go func() { socket.Listen() }()
+	go func() { socket.Interrupt() }()
+}
+
+func CreateServerSocket(t *testing.T, addr string) *TServerSocket {
+	socket, err := NewTServerSocket(addr)
+	if err != nil {
+		t.Fatalf("Failed to create server socket: %s", err)
+	}
+	return socket
+}
diff --git a/lib/go/thrift/simple_json_protocol.go b/lib/go/thrift/simple_json_protocol.go
index 9d0f68f..2e8a711 100644
--- a/lib/go/thrift/simple_json_protocol.go
+++ b/lib/go/thrift/simple_json_protocol.go
@@ -22,6 +22,7 @@
 import (
 	"bufio"
 	"bytes"
+	"context"
 	"encoding/base64"
 	"encoding/json"
 	"fmt"
@@ -69,7 +70,7 @@
 	trans TTransport
 
 	parseContextStack []int
-	dumpContext []int
+	dumpContext       []int
 
 	writer *bufio.Writer
 	reader *bufio.Reader
@@ -156,13 +157,14 @@
 }
 
 func (p *TSimpleJSONProtocol) WriteMessageBegin(name string, typeId TMessageType, seqId int32) error {
+	p.resetContextStack() // THRIFT-3735
 	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 {
+	if e := p.WriteByte(int8(typeId)); e != nil {
 		return e
 	}
 	if e := p.WriteI32(seqId); e != nil {
@@ -204,10 +206,10 @@
 	if e := p.OutputListBegin(); e != nil {
 		return e
 	}
-	if e := p.WriteByte(byte(keyType)); e != nil {
+	if e := p.WriteByte(int8(keyType)); e != nil {
 		return e
 	}
-	if e := p.WriteByte(byte(valueType)); e != nil {
+	if e := p.WriteByte(int8(valueType)); e != nil {
 		return e
 	}
 	return p.WriteI32(int32(size))
@@ -237,7 +239,7 @@
 	return p.OutputBool(b)
 }
 
-func (p *TSimpleJSONProtocol) WriteByte(b byte) error {
+func (p *TSimpleJSONProtocol) WriteByte(b int8) error {
 	return p.WriteI32(int32(b))
 }
 
@@ -269,25 +271,26 @@
 	if e := p.OutputPreValue(); e != nil {
 		return e
 	}
-	if _, e := p.writer.Write(JSON_QUOTE_BYTES); e != nil {
+	if _, e := p.write(JSON_QUOTE_BYTES); e != nil {
 		return NewTProtocolException(e)
 	}
 	writer := base64.NewEncoder(base64.StdEncoding, p.writer)
 	if _, e := writer.Write(v); e != nil {
+		p.writer.Reset(p.trans) // THRIFT-3735
 		return NewTProtocolException(e)
 	}
 	if e := writer.Close(); e != nil {
 		return NewTProtocolException(e)
 	}
-	if _, e := p.writer.Write(JSON_QUOTE_BYTES); e != nil {
+	if _, e := p.write(JSON_QUOTE_BYTES); e != nil {
 		return NewTProtocolException(e)
 	}
 	return p.OutputPostValue()
 }
 
 // Reading methods.
-
 func (p *TSimpleJSONProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err error) {
+	p.resetContextStack() // THRIFT-3735
 	if isNull, err := p.ParseListBegin(); isNull || err != nil {
 		return name, typeId, seqId, err
 	}
@@ -322,9 +325,6 @@
 	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] {
@@ -333,6 +333,9 @@
 		case JSON_QUOTE:
 			p.reader.ReadByte()
 			name, err := p.ParseStringBody()
+			// simplejson is not meant to be read back into thrift
+			// - see http://wiki.apache.org/thrift/ThriftUsageJava
+			// - use JSON instead
 			if err != nil {
 				return name, STOP, 0, err
 			}
@@ -411,15 +414,20 @@
 
 func (p *TSimpleJSONProtocol) ReadBool() (bool, error) {
 	var value bool
+
 	if err := p.ParsePreValue(); err != nil {
 		return value, err
 	}
-	b, _ := p.reader.Peek(len(JSON_TRUE))
-	if len(b) > 0 {
-		switch b[0] {
+	f, _ := p.reader.Peek(1)
+	if len(f) > 0 {
+		switch f[0] {
 		case JSON_TRUE[0]:
+			b := make([]byte, len(JSON_TRUE))
+			_, err := p.reader.Read(b)
+			if err != nil {
+				return false, NewTProtocolException(err)
+			}
 			if string(b) == string(JSON_TRUE) {
-				p.reader.Read(b[0:len(JSON_TRUE)])
 				value = true
 			} else {
 				e := fmt.Errorf("Expected \"true\" but found: %s", string(b))
@@ -427,8 +435,12 @@
 			}
 			break
 		case JSON_FALSE[0]:
-			if string(b) == string(JSON_FALSE[:len(b)]) {
-				p.reader.Read(b[0:len(JSON_FALSE)])
+			b := make([]byte, len(JSON_FALSE))
+			_, err := p.reader.Read(b)
+			if err != nil {
+				return false, NewTProtocolException(err)
+			}
+			if string(b) == string(JSON_FALSE) {
 				value = false
 			} else {
 				e := fmt.Errorf("Expected \"false\" but found: %s", string(b))
@@ -436,24 +448,28 @@
 			}
 			break
 		case JSON_NULL[0]:
+			b := make([]byte, len(JSON_NULL))
+			_, err := p.reader.Read(b)
+			if err != nil {
+				return false, NewTProtocolException(err)
+			}
 			if string(b) == string(JSON_NULL) {
-				p.reader.Read(b[0:len(JSON_NULL)])
 				value = false
 			} else {
 				e := fmt.Errorf("Expected \"null\" but found: %s", string(b))
 				return value, NewTProtocolExceptionWithType(INVALID_DATA, e)
 			}
 		default:
-			e := fmt.Errorf("Expected \"true\", \"false\", or \"null\" but found: %s", string(b))
+			e := fmt.Errorf("Expected \"true\", \"false\", or \"null\" but found: %s", string(f))
 			return value, NewTProtocolExceptionWithType(INVALID_DATA, e)
 		}
 	}
 	return value, p.ParsePostValue()
 }
 
-func (p *TSimpleJSONProtocol) ReadByte() (byte, error) {
+func (p *TSimpleJSONProtocol) ReadByte() (int8, error) {
 	v, err := p.ReadI64()
-	return byte(v), err
+	return int8(v), err
 }
 
 func (p *TSimpleJSONProtocol) ReadI16() (int16, error) {
@@ -481,26 +497,26 @@
 	if err := p.ParsePreValue(); err != nil {
 		return v, err
 	}
-	var b []byte
-	if p.reader.Buffered() >= len(JSON_NULL) {
-		b, _ = p.reader.Peek(len(JSON_NULL))
-	} else {
-		b, _ = p.reader.Peek(1)
-	}
-	if len(b) > 0 && b[0] == JSON_QUOTE {
+	f, _ := p.reader.Peek(1)
+	if len(f) > 0 && f[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)])
+	} else if len(f) > 0 && f[0] == JSON_NULL[0] {
+		b := make([]byte, len(JSON_NULL))
+		_, err := p.reader.Read(b)
 		if err != nil {
 			return v, NewTProtocolException(err)
 		}
+		if string(b) != string(JSON_NULL) {
+			e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(b))
+			return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
+		}
 	} else {
-		e := fmt.Errorf("Expected a JSON string, found %s", string(b))
+		e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(f))
 		return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
 	}
 	return v, p.ParsePostValue()
@@ -511,27 +527,33 @@
 	if err := p.ParsePreValue(); err != nil {
 		return nil, err
 	}
-	b, _ := p.reader.Peek(len(JSON_NULL))
-	if len(b) > 0 && b[0] == JSON_QUOTE {
+	f, _ := p.reader.Peek(1)
+	if len(f) > 0 && f[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)])
+	} else if len(f) > 0 && f[0] == JSON_NULL[0] {
+		b := make([]byte, len(JSON_NULL))
+		_, err := p.reader.Read(b)
 		if err != nil {
 			return v, NewTProtocolException(err)
 		}
+		if string(b) != string(JSON_NULL) {
+			e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(b))
+			return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
+		}
 	} else {
-		e := fmt.Errorf("Expected a JSON string, found %s", string(b))
+		e := fmt.Errorf("Expected a JSON string, found unquoted data started with %s", string(f))
 		return v, NewTProtocolExceptionWithType(INVALID_DATA, e)
 	}
+
 	return v, p.ParsePostValue()
 }
 
-func (p *TSimpleJSONProtocol) Flush() (err error) {
+func (p *TSimpleJSONProtocol) Flush(ctx context.Context) (err error) {
 	return NewTProtocolException(p.writer.Flush())
 }
 
@@ -547,12 +569,12 @@
 	cxt := _ParseContext(p.dumpContext[len(p.dumpContext)-1])
 	switch cxt {
 	case _CONTEXT_IN_LIST, _CONTEXT_IN_OBJECT_NEXT_KEY:
-		if _, e := p.writer.Write(JSON_COMMA); e != nil {
+		if _, e := p.write(JSON_COMMA); e != nil {
 			return NewTProtocolException(e)
 		}
 		break
 	case _CONTEXT_IN_OBJECT_NEXT_VALUE:
-		if _, e := p.writer.Write(JSON_COLON); e != nil {
+		if _, e := p.write(JSON_COLON); e != nil {
 			return NewTProtocolException(e)
 		}
 		break
@@ -608,7 +630,7 @@
 	if e := p.OutputPreValue(); e != nil {
 		return e
 	}
-	if _, e := p.writer.Write(JSON_NULL); e != nil {
+	if _, e := p.write(JSON_NULL); e != nil {
 		return NewTProtocolException(e)
 	}
 	return p.OutputPostValue()
@@ -666,7 +688,7 @@
 }
 
 func (p *TSimpleJSONProtocol) OutputStringData(s string) error {
-	_, e := p.writer.Write([]byte(s))
+	_, e := p.write([]byte(s))
 	return NewTProtocolException(e)
 }
 
@@ -674,7 +696,7 @@
 	if e := p.OutputPreValue(); e != nil {
 		return e
 	}
-	if _, e := p.writer.Write(JSON_LBRACE); e != nil {
+	if _, e := p.write(JSON_LBRACE); e != nil {
 		return NewTProtocolException(e)
 	}
 	p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_OBJECT_FIRST))
@@ -682,7 +704,7 @@
 }
 
 func (p *TSimpleJSONProtocol) OutputObjectEnd() error {
-	if _, e := p.writer.Write(JSON_RBRACE); e != nil {
+	if _, e := p.write(JSON_RBRACE); e != nil {
 		return NewTProtocolException(e)
 	}
 	p.dumpContext = p.dumpContext[:len(p.dumpContext)-1]
@@ -696,7 +718,7 @@
 	if e := p.OutputPreValue(); e != nil {
 		return e
 	}
-	if _, e := p.writer.Write(JSON_LBRACKET); e != nil {
+	if _, e := p.write(JSON_LBRACKET); e != nil {
 		return NewTProtocolException(e)
 	}
 	p.dumpContext = append(p.dumpContext, int(_CONTEXT_IN_LIST_FIRST))
@@ -704,7 +726,7 @@
 }
 
 func (p *TSimpleJSONProtocol) OutputListEnd() error {
-	if _, e := p.writer.Write(JSON_RBRACKET); e != nil {
+	if _, e := p.write(JSON_RBRACKET); e != nil {
 		return NewTProtocolException(e)
 	}
 	p.dumpContext = p.dumpContext[:len(p.dumpContext)-1]
@@ -718,7 +740,7 @@
 	if e := p.OutputListBegin(); e != nil {
 		return e
 	}
-	if e := p.WriteByte(byte(elemType)); e != nil {
+	if e := p.WriteByte(int8(elemType)); e != nil {
 		return e
 	}
 	if e := p.WriteI64(int64(size)); e != nil {
@@ -732,9 +754,6 @@
 		return NewTProtocolException(e)
 	}
 	cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1])
-	if p.reader.Buffered() < 1 {
-		return nil
-	}
 	b, _ := p.reader.Peek(1)
 	switch cxt {
 	case _CONTEXT_IN_LIST:
@@ -813,7 +832,7 @@
 }
 
 func (p *TSimpleJSONProtocol) readNonSignificantWhitespace() error {
-	for p.reader.Buffered() > 0 {
+	for {
 		b, _ := p.reader.Peek(1)
 		if len(b) < 1 {
 			return nil
@@ -894,6 +913,12 @@
 	}
 	line2 := line[0 : len(line)-1]
 	l := len(line2)
+	if (l % 4) != 0 {
+		pad := 4 - (l % 4)
+		fill := [...]byte{'=', '=', '='}
+		line2 = append(line2, fill[:pad]...)
+		l = len(line2)
+	}
 	output := make([]byte, base64.StdEncoding.DecodedLen(l))
 	n, err := base64.StdEncoding.Decode(output, line2)
 	return output[0:n], NewTProtocolException(err)
@@ -905,9 +930,8 @@
 	}
 	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)])
+	if p.safePeekContains(JSON_NULL) {
+		p.reader.Read(make([]byte, len(JSON_NULL)))
 		isnull = true
 	} else {
 		num, err := p.readNumeric()
@@ -928,9 +952,8 @@
 	}
 	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)])
+	if p.safePeekContains(JSON_NULL) {
+		p.reader.Read(make([]byte, len(JSON_NULL)))
 		isnull = true
 	} else {
 		num, err := p.readNumeric()
@@ -950,16 +973,15 @@
 		return false, err
 	}
 	var b []byte
-	if p.reader.Buffered() >= len(JSON_NULL) {
-		b, _ = p.reader.Peek(len(JSON_NULL))
-	} else if p.reader.Buffered() >= 1 {
-		b, _ = p.reader.Peek(1)
+	b, err := p.reader.Peek(1)
+	if err != nil {
+		return false, err
 	}
 	if len(b) > 0 && b[0] == JSON_LBRACE[0] {
 		p.reader.ReadByte()
 		p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_OBJECT_FIRST))
 		return false, nil
-	} else if len(b) >= len(JSON_NULL) && string(b[0:len(JSON_NULL)]) == string(JSON_NULL) {
+	} else if p.safePeekContains(JSON_NULL) {
 		return true, nil
 	}
 	e := fmt.Errorf("Expected '{' or null, but found '%s'", string(b))
@@ -971,8 +993,8 @@
 		return err
 	}
 	cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1])
-	if cxt != _CONTEXT_IN_OBJECT_FIRST && cxt != _CONTEXT_IN_OBJECT_NEXT_KEY {
-		e := fmt.Errorf("Expected to be in the Object Context, but not in Object Context")
+	if (cxt != _CONTEXT_IN_OBJECT_FIRST) && (cxt != _CONTEXT_IN_OBJECT_NEXT_KEY) {
+		e := fmt.Errorf("Expected to be in the Object Context, but not in Object Context (%d)", cxt)
 		return NewTProtocolExceptionWithType(INVALID_DATA, e)
 	}
 	line, err := p.reader.ReadString(JSON_RBRACE[0])
@@ -997,11 +1019,7 @@
 		return false, e
 	}
 	var b []byte
-	if p.reader.Buffered() >= len(JSON_NULL) {
-		b, err = p.reader.Peek(len(JSON_NULL))
-	} else {
-		b, err = p.reader.Peek(1)
-	}
+	b, err = p.reader.Peek(1)
 	if err != nil {
 		return false, err
 	}
@@ -1009,7 +1027,7 @@
 		p.parseContextStack = append(p.parseContextStack, int(_CONTEXT_IN_LIST_FIRST))
 		p.reader.ReadByte()
 		isNull = false
-	} else if len(b) >= len(JSON_NULL) && string(b) == string(JSON_NULL) {
+	} else if p.safePeekContains(JSON_NULL) {
 		isNull = true
 	} else {
 		err = fmt.Errorf("Expected \"null\" or \"[\", received %q", b)
@@ -1035,8 +1053,9 @@
 	if isNull, err := p.readIfNull(); isNull || err != nil {
 		return err
 	}
-	if _ParseContext(p.parseContextStack[len(p.parseContextStack)-1]) != _CONTEXT_IN_LIST {
-		e := fmt.Errorf("Expected to be in the List Context, but not in List Context")
+	cxt := _ParseContext(p.parseContextStack[len(p.parseContextStack)-1])
+	if cxt != _CONTEXT_IN_LIST {
+		e := fmt.Errorf("Expected to be in the List Context, but not in List Context (%d)", cxt)
 		return NewTProtocolExceptionWithType(INVALID_DATA, e)
 	}
 	line, err := p.reader.ReadString(JSON_RBRACKET[0])
@@ -1046,13 +1065,16 @@
 	for _, char := range line {
 		switch char {
 		default:
-			e := fmt.Errorf("Expecting end of list \"]\", but found: \"", line, "\"")
+			e := fmt.Errorf("Expecting end of list \"]\", but found: \"%v\"", line)
 			return NewTProtocolExceptionWithType(INVALID_DATA, e)
 		case ' ', '\n', '\r', '\t', rune(JSON_RBRACKET[0]):
 			break
 		}
 	}
 	p.parseContextStack = p.parseContextStack[:len(p.parseContextStack)-1]
+	if _ParseContext(p.parseContextStack[len(p.parseContextStack)-1]) == _CONTEXT_IN_TOPLEVEL {
+		return nil
+	}
 	return p.ParsePostValue()
 }
 
@@ -1061,7 +1083,7 @@
 	if e != nil {
 		return nil, VOID, NewTProtocolException(e)
 	}
-	b, e := p.reader.Peek(10)
+	b, e := p.reader.Peek(1)
 	if len(b) > 0 {
 		c := b[0]
 		switch c {
@@ -1134,7 +1156,7 @@
 
 func (p *TSimpleJSONProtocol) readIfNull() (bool, error) {
 	cont := true
-	for p.reader.Buffered() > 0 && cont {
+	for cont {
 		b, _ := p.reader.Peek(1)
 		if len(b) < 1 {
 			return false, nil
@@ -1150,21 +1172,14 @@
 			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)])
+	if p.safePeekContains(JSON_NULL) {
+		p.reader.Read(make([]byte, 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()
@@ -1296,3 +1311,28 @@
 	}
 	return NewNumericFromJSONString(buf.String(), false), nil
 }
+
+// Safely peeks into the buffer, reading only what is necessary
+func (p *TSimpleJSONProtocol) safePeekContains(b []byte) bool {
+	for i := 0; i < len(b); i++ {
+		a, _ := p.reader.Peek(i + 1)
+		if len(a) == 0 || a[i] != b[i] {
+			return false
+		}
+	}
+	return true
+}
+
+// Reset the context stack to its initial state.
+func (p *TSimpleJSONProtocol) resetContextStack() {
+	p.parseContextStack = []int{int(_CONTEXT_IN_TOPLEVEL)}
+	p.dumpContext = []int{int(_CONTEXT_IN_TOPLEVEL)}
+}
+
+func (p *TSimpleJSONProtocol) write(b []byte) (int, error) {
+	n, err := p.writer.Write(b)
+	if err != nil {
+		p.writer.Reset(p.trans) // THRIFT-3735
+	}
+	return n, err
+}
diff --git a/lib/go/thrift/simple_json_protocol_test.go b/lib/go/thrift/simple_json_protocol_test.go
index 87a5c64..7b98082 100644
--- a/lib/go/thrift/simple_json_protocol_test.go
+++ b/lib/go/thrift/simple_json_protocol_test.go
@@ -20,6 +20,7 @@
 package thrift
 
 import (
+	"context"
 	"encoding/base64"
 	"encoding/json"
 	"fmt"
@@ -37,7 +38,7 @@
 		if e := p.WriteBool(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
@@ -63,7 +64,7 @@
 		} else {
 			trans.Write(JSON_FALSE)
 		}
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadBool()
 		if e != nil {
@@ -88,14 +89,14 @@
 		if e := p.WriteByte(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
 		if s != fmt.Sprint(value) {
 			t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
 		}
-		v := byte(0)
+		v := int8(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)
 		}
@@ -110,7 +111,7 @@
 		trans := NewTMemoryBuffer()
 		p := NewTSimpleJSONProtocol(trans)
 		trans.WriteString(strconv.Itoa(int(value)))
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadByte()
 		if e != nil {
@@ -135,7 +136,7 @@
 		if e := p.WriteI16(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
@@ -157,7 +158,7 @@
 		trans := NewTMemoryBuffer()
 		p := NewTSimpleJSONProtocol(trans)
 		trans.WriteString(strconv.Itoa(int(value)))
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadI16()
 		if e != nil {
@@ -182,7 +183,7 @@
 		if e := p.WriteI32(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
@@ -204,7 +205,7 @@
 		trans := NewTMemoryBuffer()
 		p := NewTSimpleJSONProtocol(trans)
 		trans.WriteString(strconv.Itoa(int(value)))
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadI32()
 		if e != nil {
@@ -221,6 +222,27 @@
 	}
 }
 
+func TestReadSimpleJSONProtocolI32Null(t *testing.T) {
+	thetype := "int32"
+	value := "null"
+
+	trans := NewTMemoryBuffer()
+	p := NewTSimpleJSONProtocol(trans)
+	trans.WriteString(value)
+	trans.Flush(context.Background())
+	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.Error())
+	}
+	if v != 0 {
+		t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+	}
+	trans.Reset()
+	trans.Close()
+}
+
 func TestWriteSimpleJSONProtocolI64(t *testing.T) {
 	thetype := "int64"
 	trans := NewTMemoryBuffer()
@@ -229,7 +251,7 @@
 		if e := p.WriteI64(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
@@ -251,7 +273,7 @@
 		trans := NewTMemoryBuffer()
 		p := NewTSimpleJSONProtocol(trans)
 		trans.WriteString(strconv.FormatInt(value, 10))
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadI64()
 		if e != nil {
@@ -268,6 +290,27 @@
 	}
 }
 
+func TestReadSimpleJSONProtocolI64Null(t *testing.T) {
+	thetype := "int32"
+	value := "null"
+
+	trans := NewTMemoryBuffer()
+	p := NewTSimpleJSONProtocol(trans)
+	trans.WriteString(value)
+	trans.Flush(context.Background())
+	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.Error())
+	}
+	if v != 0 {
+		t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+	}
+	trans.Reset()
+	trans.Close()
+}
+
 func TestWriteSimpleJSONProtocolDouble(t *testing.T) {
 	thetype := "double"
 	trans := NewTMemoryBuffer()
@@ -276,7 +319,7 @@
 		if e := p.WriteDouble(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
@@ -313,7 +356,7 @@
 		p := NewTSimpleJSONProtocol(trans)
 		n := NewNumericFromDouble(value)
 		trans.WriteString(n.String())
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadDouble()
 		if e != nil {
@@ -352,7 +395,7 @@
 		if e := p.WriteString(value); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 		}
-		if e := p.Flush(); e != nil {
+		if e := p.Flush(context.Background()); e != nil {
 			t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 		}
 		s := trans.String()
@@ -374,7 +417,7 @@
 		trans := NewTMemoryBuffer()
 		p := NewTSimpleJSONProtocol(trans)
 		trans.WriteString(jsonQuote(value))
-		trans.Flush()
+		trans.Flush(context.Background())
 		s := trans.String()
 		v, e := p.ReadString()
 		if e != nil {
@@ -391,6 +434,25 @@
 		trans.Close()
 	}
 }
+func TestReadSimpleJSONProtocolStringNull(t *testing.T) {
+	thetype := "string"
+	value := "null"
+
+	trans := NewTMemoryBuffer()
+	p := NewTSimpleJSONProtocol(trans)
+	trans.WriteString(value)
+	trans.Flush(context.Background())
+	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.Error())
+	}
+	if v != "" {
+		t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+	}
+	trans.Reset()
+	trans.Close()
+}
 
 func TestWriteSimpleJSONProtocolBinary(t *testing.T) {
 	thetype := "binary"
@@ -403,7 +465,7 @@
 	if e := p.WriteBinary(value); e != nil {
 		t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.Error())
 	}
-	if e := p.Flush(); e != nil {
+	if e := p.Flush(context.Background()); e != nil {
 		t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.Error())
 	}
 	s := trans.String()
@@ -426,7 +488,7 @@
 	trans := NewTMemoryBuffer()
 	p := NewTSimpleJSONProtocol(trans)
 	trans.WriteString(jsonQuote(b64String))
-	trans.Flush()
+	trans.Flush(context.Background())
 	s := trans.String()
 	v, e := p.ReadBinary()
 	if e != nil {
@@ -448,6 +510,28 @@
 	trans.Close()
 }
 
+func TestReadSimpleJSONProtocolBinaryNull(t *testing.T) {
+	thetype := "binary"
+	value := "null"
+
+	trans := NewTMemoryBuffer()
+	p := NewTSimpleJSONProtocol(trans)
+	trans.WriteString(value)
+	trans.Flush(context.Background())
+	s := trans.String()
+	b, e := p.ReadBinary()
+	v := string(b)
+
+	if e != nil {
+		t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.Error())
+	}
+	if v != "" {
+		t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+	}
+	trans.Reset()
+	trans.Close()
+}
+
 func TestWriteSimpleJSONProtocolList(t *testing.T) {
 	thetype := "list"
 	trans := NewTMemoryBuffer()
@@ -459,7 +543,7 @@
 		}
 	}
 	p.WriteListEnd()
-	if e := p.Flush(); e != nil {
+	if e := p.Flush(context.Background()); e != nil {
 		t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.Error())
 	}
 	str := trans.String()
@@ -513,7 +597,7 @@
 		}
 	}
 	p.WriteSetEnd()
-	if e := p.Flush(); e != nil {
+	if e := p.Flush(context.Background()); e != nil {
 		t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.Error())
 	}
 	str := trans.String()
@@ -570,12 +654,12 @@
 		}
 	}
 	p.WriteMapEnd()
-	if e := p.Flush(); e != nil {
+	if e := p.Flush(context.Background()); e != nil {
 		t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.Error())
 	}
 	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)
+		t.Fatalf("Bad value for %s, wrote: %v, in go: %v", thetype, str, DOUBLE_VALUES)
 	}
 	l := strings.Split(str[1:len(str)-1], ",")
 	if len(l) < 3 {
diff --git a/lib/go/thrift/simple_server.go b/lib/go/thrift/simple_server.go
index b5cb0e1..6035802 100644
--- a/lib/go/thrift/simple_server.go
+++ b/lib/go/thrift/simple_server.go
@@ -21,11 +21,20 @@
 
 import (
 	"log"
+	"runtime/debug"
+	"sync"
+	"sync/atomic"
 )
 
-// Simple, non-concurrent server for testing.
+/*
+ * This is not a typical TSimpleServer as it is not blocked after accept a socket.
+ * It is more like a TThreadedServer that can handle different connections in different goroutines.
+ * This will work if golang user implements a conn-pool like thing in client side.
+ */
 type TSimpleServer struct {
-	stopped bool
+	closed int32
+	wg     sync.WaitGroup
+	mu     sync.Mutex
 
 	processorFactory       TProcessorFactory
 	serverTransport        TServerTransport
@@ -78,7 +87,8 @@
 }
 
 func NewTSimpleServerFactory6(processorFactory TProcessorFactory, serverTransport TServerTransport, inputTransportFactory TTransportFactory, outputTransportFactory TTransportFactory, inputProtocolFactory TProtocolFactory, outputProtocolFactory TProtocolFactory) *TSimpleServer {
-	return &TSimpleServer{processorFactory: processorFactory,
+	return &TSimpleServer{
+		processorFactory:       processorFactory,
 		serverTransport:        serverTransport,
 		inputTransportFactory:  inputTransportFactory,
 		outputTransportFactory: outputTransportFactory,
@@ -111,40 +121,84 @@
 	return p.outputProtocolFactory
 }
 
+func (p *TSimpleServer) Listen() error {
+	return p.serverTransport.Listen()
+}
+
+func (p *TSimpleServer) innerAccept() (int32, error) {
+	client, err := p.serverTransport.Accept()
+	p.mu.Lock()
+	defer p.mu.Unlock()
+	closed := atomic.LoadInt32(&p.closed)
+	if closed != 0 {
+		return closed, nil
+	}
+	if err != nil {
+		return 0, err
+	}
+	if client != nil {
+		p.wg.Add(1)
+		go func() {
+			defer p.wg.Done()
+			if err := p.processRequests(client); err != nil {
+				log.Println("error processing request:", err)
+			}
+		}()
+	}
+	return 0, nil
+}
+
+func (p *TSimpleServer) AcceptLoop() error {
+	for {
+		closed, err := p.innerAccept()
+		if err != nil {
+			return err
+		}
+		if closed != 0 {
+			return nil
+		}
+	}
+}
+
 func (p *TSimpleServer) Serve() error {
-	p.stopped = false
-	err := p.serverTransport.Listen()
+	err := p.Listen()
 	if err != nil {
 		return err
 	}
-	for !p.stopped {
-		client, err := p.serverTransport.Accept()
-		if err != nil {
-			log.Println("Accept err: ", err)
-		}
-		if client != nil {
-			go func() {
-				if err := p.processRequest(client); err != nil {
-					log.Println("error processing request:", err)
-				}
-			}()
-		}
-	}
+	p.AcceptLoop()
 	return nil
 }
 
 func (p *TSimpleServer) Stop() error {
-	p.stopped = true
+	p.mu.Lock()
+	defer p.mu.Unlock()
+	if atomic.LoadInt32(&p.closed) != 0 {
+		return nil
+	}
+	atomic.StoreInt32(&p.closed, 1)
 	p.serverTransport.Interrupt()
+	p.wg.Wait()
 	return nil
 }
 
-func (p *TSimpleServer) processRequest(client TTransport) error {
+func (p *TSimpleServer) processRequests(client TTransport) error {
 	processor := p.processorFactory.GetProcessor(client)
-	inputTransport := p.inputTransportFactory.GetTransport(client)
-	outputTransport := p.outputTransportFactory.GetTransport(client)
+	inputTransport, err := p.inputTransportFactory.GetTransport(client)
+	if err != nil {
+		return err
+	}
+	outputTransport, err := p.outputTransportFactory.GetTransport(client)
+	if err != nil {
+		return err
+	}
 	inputProtocol := p.inputProtocolFactory.GetProtocol(inputTransport)
 	outputProtocol := p.outputProtocolFactory.GetProtocol(outputTransport)
+	defer func() {
+		if e := recover(); e != nil {
+			log.Printf("panic in processor: %s: %s", e, debug.Stack())
+		}
+	}()
+
 	if inputTransport != nil {
 		defer inputTransport.Close()
 	}
@@ -152,13 +206,20 @@
 		defer outputTransport.Close()
 	}
 	for {
-		ok, err := processor.Process(inputProtocol, outputProtocol)
-		if err, ok := err.(TTransportException); ok && err.TypeId() == END_OF_FILE{
+		if atomic.LoadInt32(&p.closed) != 0 {
+			return nil
+		}
+
+		ok, err := processor.Process(defaultCtx, inputProtocol, outputProtocol)
+		if err, ok := err.(TTransportException); ok && err.TypeId() == END_OF_FILE {
 			return nil
 		} else if err != nil {
 			return err
 		}
-		if !ok || !inputProtocol.Transport().Peek() {
+		if err, ok := err.(TApplicationException); ok && err.TypeId() == UNKNOWN_METHOD {
+			continue
+		}
+		if !ok {
 			break
 		}
 	}
diff --git a/lib/go/thrift/simple_server_test.go b/lib/go/thrift/simple_server_test.go
new file mode 100644
index 0000000..58149a8
--- /dev/null
+++ b/lib/go/thrift/simple_server_test.go
@@ -0,0 +1,156 @@
+/*
+ * 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 (
+	"testing"
+	"errors"
+	"runtime"
+)
+
+type mockServerTransport struct {
+	ListenFunc    func() error
+	AcceptFunc    func() (TTransport, error)
+	CloseFunc     func() error
+	InterruptFunc func() error
+}
+
+func (m *mockServerTransport) Listen() error {
+	return m.ListenFunc()
+}
+
+func (m *mockServerTransport) Accept() (TTransport, error) {
+	return m.AcceptFunc()
+}
+
+func (m *mockServerTransport) Close() error {
+	return m.CloseFunc()
+}
+
+func (m *mockServerTransport) Interrupt() error {
+	return m.InterruptFunc()
+}
+
+type mockTTransport struct {
+	TTransport
+}
+
+func (m *mockTTransport) Close() error {
+	return nil
+}
+
+func TestMultipleStop(t *testing.T) {
+	proc := &mockProcessor{
+		ProcessFunc: func(in, out TProtocol) (bool, TException) {
+			return false, nil
+		},
+	}
+
+	var interruptCalled bool
+	c := make(chan struct{})
+	trans := &mockServerTransport{
+		ListenFunc: func() error {
+			return nil
+		},
+		AcceptFunc: func() (TTransport, error) {
+			<-c
+			return nil, nil
+		},
+		CloseFunc: func() error {
+			c <- struct{}{}
+			return nil
+		},
+		InterruptFunc: func() error {
+			interruptCalled = true
+			return nil
+		},
+	}
+
+	serv := NewTSimpleServer2(proc, trans)
+	go serv.Serve()
+	serv.Stop()
+	if !interruptCalled {
+		t.Error("first server transport should have been interrupted")
+	}
+
+	serv = NewTSimpleServer2(proc, trans)
+	interruptCalled = false
+	go serv.Serve()
+	serv.Stop()
+	if !interruptCalled {
+		t.Error("second server transport should have been interrupted")
+	}
+}
+
+func TestWaitRace(t *testing.T) {
+	proc := &mockProcessor{
+		ProcessFunc: func(in, out TProtocol) (bool, TException) {
+			return false, nil
+		},
+	}
+
+	trans := &mockServerTransport{
+		ListenFunc: func() error {
+			return nil
+		},
+		AcceptFunc: func() (TTransport, error) {
+			return &mockTTransport{}, nil
+		},
+		CloseFunc: func() error {
+			return nil
+		},
+		InterruptFunc: func() error {
+			return nil
+		},
+	}
+
+	serv := NewTSimpleServer2(proc, trans)
+	go serv.Serve()
+	runtime.Gosched()
+	serv.Stop()
+}
+
+func TestNoHangDuringStopFromDanglingLockAcquireDuringAcceptLoop(t *testing.T) {
+	proc := &mockProcessor{
+		ProcessFunc: func(in, out TProtocol) (bool, TException) {
+			return false, nil
+		},
+	}
+
+	trans := &mockServerTransport{
+		ListenFunc: func() error {
+			return nil
+		},
+		AcceptFunc: func() (TTransport, error) {
+			return nil, errors.New("no sir")
+		},
+		CloseFunc: func() error {
+			return nil
+		},
+		InterruptFunc: func() error {
+			return nil
+		},
+	}
+
+	serv := NewTSimpleServer2(proc, trans)
+	go serv.Serve()
+	runtime.Gosched()
+	serv.Stop()
+}
diff --git a/lib/go/thrift/socket.go b/lib/go/thrift/socket.go
index a381ea2..8854279 100644
--- a/lib/go/thrift/socket.go
+++ b/lib/go/thrift/socket.go
@@ -20,6 +20,7 @@
 package thrift
 
 import (
+	"context"
 	"net"
 	"time"
 )
@@ -100,7 +101,7 @@
 	return nil
 }
 
-// Retreive the underlying net.Conn
+// Retrieve the underlying net.Conn
 func (p *TSocket) Conn() net.Conn {
 	return p.conn
 }
@@ -126,6 +127,11 @@
 	return nil
 }
 
+//Returns the remote address of the socket.
+func (p *TSocket) Addr() net.Addr {
+	return p.addr
+}
+
 func (p *TSocket) Read(buf []byte) (int, error) {
 	if !p.IsOpen() {
 		return 0, NewTTransportException(NOT_OPEN, "Connection not open")
@@ -143,11 +149,7 @@
 	return p.conn.Write(buf)
 }
 
-func (p *TSocket) Peek() bool {
-	return p.IsOpen()
-}
-
-func (p *TSocket) Flush() error {
+func (p *TSocket) Flush(ctx context.Context) error {
 	return nil
 }
 
@@ -157,3 +159,8 @@
 	}
 	return p.conn.Close()
 }
+
+func (p *TSocket) RemainingBytes() (num_bytes uint64) {
+	const maxSize = ^uint64(0)
+	return maxSize // the thruth is, we just don't know unless framed is used
+}
diff --git a/lib/go/thrift/ssl_server_socket.go b/lib/go/thrift/ssl_server_socket.go
index 58f859b..907afca 100644
--- a/lib/go/thrift/ssl_server_socket.go
+++ b/lib/go/thrift/ssl_server_socket.go
@@ -20,9 +20,9 @@
 package thrift
 
 import (
+	"crypto/tls"
 	"net"
 	"time"
-	"crypto/tls"
 )
 
 type TSSLServerSocket struct {
@@ -38,6 +38,9 @@
 }
 
 func NewTSSLServerSocketTimeout(listenAddr string, cfg *tls.Config, clientTimeout time.Duration) (*TSSLServerSocket, error) {
+	if cfg.MinVersion == 0 {
+		cfg.MinVersion = tls.VersionTLS10
+	}
 	addr, err := net.ResolveTCPAddr("tcp", listenAddr)
 	if err != nil {
 		return nil, err
diff --git a/lib/go/thrift/ssl_socket.go b/lib/go/thrift/ssl_socket.go
index 943bd90..ba63377 100644
--- a/lib/go/thrift/ssl_socket.go
+++ b/lib/go/thrift/ssl_socket.go
@@ -20,13 +20,19 @@
 package thrift
 
 import (
+	"context"
+	"crypto/tls"
 	"net"
 	"time"
-	"crypto/tls"
 )
 
 type TSSLSocket struct {
-	conn    net.Conn
+	conn net.Conn
+	// hostPort contains host:port (e.g. "asdf.com:12345"). The field is
+	// only valid if addr is nil.
+	hostPort string
+	// addr is nil when hostPort is not "", and is only used when the
+	// TSSLSocket is constructed from a net.Addr.
 	addr    net.Addr
 	timeout time.Duration
 	cfg     *tls.Config
@@ -35,7 +41,7 @@
 // NewTSSLSocket creates a net.Conn-backed TTransport, given a host and port and tls Configuration
 //
 // Example:
-// 	trans, err := thrift.NewTSocket("localhost:9090")
+// 	trans, err := thrift.NewTSSLSocket("localhost:9090", nil)
 func NewTSSLSocket(hostPort string, cfg *tls.Config) (*TSSLSocket, error) {
 	return NewTSSLSocketTimeout(hostPort, cfg, 0)
 }
@@ -43,12 +49,10 @@
 // NewTSSLSocketTimeout creates a net.Conn-backed TTransport, given a host and port
 // it also accepts a tls Configuration and a timeout as a time.Duration
 func NewTSSLSocketTimeout(hostPort string, cfg *tls.Config, timeout time.Duration) (*TSSLSocket, error) {
-	//conn, err := net.DialTimeout(network, address, timeout)
-	addr, err := net.ResolveTCPAddr("tcp", hostPort)
-	if err != nil {
-		return nil, err
+	if cfg.MinVersion == 0 {
+		cfg.MinVersion = tls.VersionTLS10
 	}
-	return NewTSSLSocketFromAddrTimeout(addr, cfg, timeout), nil
+	return &TSSLSocket{hostPort: hostPort, timeout: timeout, cfg: cfg}, nil
 }
 
 // Creates a TSSLSocket from a net.Addr
@@ -83,26 +87,36 @@
 
 // Connects the socket, creating a new socket object if necessary.
 func (p *TSSLSocket) Open() 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 error
-	if p.conn, err = tls.Dial(p.addr.Network(), p.addr.String(), p.cfg); err != nil {
-		return NewTTransportException(NOT_OPEN, err.Error())
+	// If we have a hostname, we need to pass the hostname to tls.Dial for
+	// certificate hostname checks.
+	if p.hostPort != "" {
+		if p.conn, err = tls.DialWithDialer(&net.Dialer{
+			Timeout: p.timeout}, "tcp", p.hostPort, p.cfg); err != nil {
+			return NewTTransportException(NOT_OPEN, err.Error())
+		}
+	} else {
+		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.")
+		}
+		if p.conn, err = tls.DialWithDialer(&net.Dialer{
+			Timeout: p.timeout}, p.addr.Network(), p.addr.String(), p.cfg); err != nil {
+			return NewTTransportException(NOT_OPEN, err.Error())
+		}
 	}
 	return nil
 }
 
-// Retreive the underlying net.Conn
+// Retrieve the underlying net.Conn
 func (p *TSSLSocket) Conn() net.Conn {
 	return p.conn
 }
@@ -145,11 +159,7 @@
 	return p.conn.Write(buf)
 }
 
-func (p *TSSLSocket) Peek() bool {
-	return p.IsOpen()
-}
-
-func (p *TSSLSocket) Flush() error {
+func (p *TSSLSocket) Flush(ctx context.Context) error {
 	return nil
 }
 
@@ -159,3 +169,8 @@
 	}
 	return p.conn.Close()
 }
+
+func (p *TSSLSocket) RemainingBytes() (num_bytes uint64) {
+	const maxSize = ^uint64(0)
+	return maxSize // the thruth is, we just don't know unless framed is used
+}
diff --git a/lib/go/thrift/transport.go b/lib/go/thrift/transport.go
index 44823dd..ba2738a 100644
--- a/lib/go/thrift/transport.go
+++ b/lib/go/thrift/transport.go
@@ -20,6 +20,7 @@
 package thrift
 
 import (
+	"context"
 	"errors"
 	"io"
 )
@@ -30,17 +31,40 @@
 	Flush() (err error)
 }
 
+type ContextFlusher interface {
+	Flush(ctx context.Context) (err error)
+}
+
+type ReadSizeProvider interface {
+	RemainingBytes() (num_bytes uint64)
+}
+
 // Encapsulates the I/O layer
 type TTransport interface {
 	io.ReadWriteCloser
-	Flusher
+	ContextFlusher
+	ReadSizeProvider
 
 	// Opens the transport for communication
 	Open() error
 
 	// Returns true if the transport is open
 	IsOpen() bool
+}
 
-	// Returns true if there is more data to be read or the remote side is still open
-	Peek() bool
+type stringWriter interface {
+	WriteString(s string) (n int, err error)
+}
+
+// This is "enchanced" transport with extra capabilities. You need to use one of these
+// to construct protocol.
+// Notably, TSocket does not implement this interface, and it is always a mistake to use
+// TSocket directly in protocol.
+type TRichTransport interface {
+	io.ReadWriter
+	io.ByteReader
+	io.ByteWriter
+	stringWriter
+	ContextFlusher
+	ReadSizeProvider
 }
diff --git a/lib/go/thrift/transport_exception.go b/lib/go/thrift/transport_exception.go
index dbab4d9..9505b44 100644
--- a/lib/go/thrift/transport_exception.go
+++ b/lib/go/thrift/transport_exception.go
@@ -20,13 +20,19 @@
 package thrift
 
 import (
+	"errors"
 	"io"
 )
 
+type timeoutable interface {
+	Timeout() bool
+}
+
 // Thrift Transport exception
 type TTransportException interface {
 	TException
 	TypeId() int
+	Err() error
 }
 
 const (
@@ -38,8 +44,8 @@
 )
 
 type tTransportException struct {
-	typeId  int
-	message string
+	typeId int
+	err    error
 }
 
 func (p *tTransportException) TypeId() int {
@@ -47,22 +53,38 @@
 }
 
 func (p *tTransportException) Error() string {
-	return p.message
+	return p.err.Error()
 }
 
-func NewTTransportException(t int, m string) TTransportException {
-	return &tTransportException{typeId: t, message: m}
+func (p *tTransportException) Err() error {
+	return p.err
+}
+
+func NewTTransportException(t int, e string) TTransportException {
+	return &tTransportException{typeId: t, err: errors.New(e)}
 }
 
 func NewTTransportExceptionFromError(e error) TTransportException {
 	if e == nil {
 		return nil
 	}
+
 	if t, ok := e.(TTransportException); ok {
 		return t
 	}
-	if e == io.EOF {
-		return NewTTransportException(END_OF_FILE, e.Error())
+
+	switch v := e.(type) {
+	case TTransportException:
+		return v
+	case timeoutable:
+		if v.Timeout() {
+			return &tTransportException{typeId: TIMED_OUT, err: e}
+		}
 	}
-	return NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, e.Error())
+
+	if e == io.EOF {
+		return &tTransportException{typeId: END_OF_FILE, err: e}
+	}
+
+	return &tTransportException{typeId: UNKNOWN_TRANSPORT_EXCEPTION, err: e}
 }
diff --git a/lib/go/thrift/transport_exception_test.go b/lib/go/thrift/transport_exception_test.go
new file mode 100644
index 0000000..b44314f
--- /dev/null
+++ b/lib/go/thrift/transport_exception_test.go
@@ -0,0 +1,60 @@
+/*
+ * 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 (
+	"fmt"
+	"io"
+
+	"testing"
+)
+
+type timeout struct{ timedout bool }
+
+func (t *timeout) Timeout() bool {
+	return t.timedout
+}
+
+func (t *timeout) Error() string {
+	return fmt.Sprintf("Timeout: %v", t.timedout)
+}
+
+func TestTExceptionTimeout(t *testing.T) {
+	timeout := &timeout{true}
+	exception := NewTTransportExceptionFromError(timeout)
+	if timeout.Error() != exception.Error() {
+		t.Fatalf("Error did not match: expected %q, got %q", timeout.Error(), exception.Error())
+	}
+
+	if exception.TypeId() != TIMED_OUT {
+		t.Fatalf("TypeId was not TIMED_OUT: expected %v, got %v", TIMED_OUT, exception.TypeId())
+	}
+}
+
+func TestTExceptionEOF(t *testing.T) {
+	exception := NewTTransportExceptionFromError(io.EOF)
+	if io.EOF.Error() != exception.Error() {
+		t.Fatalf("Error did not match: expected %q, got %q", io.EOF.Error(), exception.Error())
+	}
+
+	if exception.TypeId() != END_OF_FILE {
+		t.Fatalf("TypeId was not END_OF_FILE: expected %v, got %v", END_OF_FILE, exception.TypeId())
+	}
+}
diff --git a/lib/go/thrift/transport_factory.go b/lib/go/thrift/transport_factory.go
index 533d1b4..c805807 100644
--- a/lib/go/thrift/transport_factory.go
+++ b/lib/go/thrift/transport_factory.go
@@ -24,14 +24,14 @@
 // 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
+	GetTransport(trans TTransport) (TTransport, error)
 }
 
 type tTransportFactory struct{}
 
 // Return a wrapped instance of the base Transport.
-func (p *tTransportFactory) GetTransport(trans TTransport) TTransport {
-	return trans
+func (p *tTransportFactory) GetTransport(trans TTransport) (TTransport, error) {
+	return trans, nil
 }
 
 func NewTTransportFactory() TTransportFactory {
diff --git a/lib/go/thrift/transport_test.go b/lib/go/thrift/transport_test.go
index c9f1d56..0127803 100644
--- a/lib/go/thrift/transport_test.go
+++ b/lib/go/thrift/transport_test.go
@@ -20,6 +20,7 @@
 package thrift
 
 import (
+	"context"
 	"io"
 	"net"
 	"strconv"
@@ -29,7 +30,8 @@
 const TRANSPORT_BINARY_DATA_SIZE = 4096
 
 var (
-	transport_bdata []byte // test data for writing; same as data
+	transport_bdata  []byte // test data for writing; same as data
+	transport_header map[string]string
 )
 
 func init() {
@@ -37,6 +39,8 @@
 	for i := 0; i < TRANSPORT_BINARY_DATA_SIZE; i++ {
 		transport_bdata[i] = byte((i + 'a') % 255)
 	}
+	transport_header = map[string]string{"key": "User-Agent",
+		"value": "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36"}
 }
 
 func TransportTest(t *testing.T, writeTrans TTransport, readTrans TTransport) {
@@ -51,7 +55,7 @@
 	if err != nil {
 		t.Fatalf("Transport %T cannot write binary data of length %d: %s", writeTrans, len(transport_bdata), err)
 	}
-	err = writeTrans.Flush()
+	err = writeTrans.Flush(context.Background())
 	if err != nil {
 		t.Fatalf("Transport %T cannot flush write of binary data: %s", writeTrans, err)
 	}
@@ -71,7 +75,7 @@
 	if err != nil {
 		t.Fatalf("Transport %T cannot write binary data 2 of length %d: %s", writeTrans, len(transport_bdata), err)
 	}
-	err = writeTrans.Flush()
+	err = writeTrans.Flush(context.Background())
 	if err != nil {
 		t.Fatalf("Transport %T cannot flush write binary data 2: %s", writeTrans, err)
 	}
@@ -94,6 +98,50 @@
 	}
 }
 
+func TransportHeaderTest(t *testing.T, writeTrans TTransport, readTrans TTransport) {
+	buf := make([]byte, TRANSPORT_BINARY_DATA_SIZE)
+	if !writeTrans.IsOpen() {
+		t.Fatalf("Transport %T not open: %s", writeTrans, writeTrans)
+	}
+	if !readTrans.IsOpen() {
+		t.Fatalf("Transport %T not open: %s", readTrans, readTrans)
+	}
+	// Need to assert type of TTransport to THttpClient to expose the Setter
+	httpWPostTrans := writeTrans.(*THttpClient)
+	httpWPostTrans.SetHeader(transport_header["key"], transport_header["value"])
+
+	_, 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(context.Background())
+	if err != nil {
+		t.Fatalf("Transport %T cannot flush write of binary data: %s", writeTrans, err)
+	}
+	// Need to assert type of TTransport to THttpClient to expose the Getter
+	httpRPostTrans := readTrans.(*THttpClient)
+	readHeader := httpRPostTrans.GetHeader(transport_header["key"])
+	if err != nil {
+		t.Errorf("Transport %T cannot read HTTP Header Value", httpRPostTrans)
+	}
+
+	if transport_header["value"] != readHeader {
+		t.Errorf("Expected HTTP Header Value %s, got %s", transport_header["value"], readHeader)
+	}
+	n, err := io.ReadFull(readTrans, 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)
+		}
+	}
+}
+
 func CloseTransports(t *testing.T, readTrans TTransport, writeTrans TTransport) {
 	err := readTrans.Close()
 	if err != nil {
@@ -118,3 +166,12 @@
 	}
 	return nil, NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "Could not find available server port")
 }
+
+func valueInSlice(value string, slice []string) bool {
+	for _, v := range slice {
+		if value == v {
+			return true
+		}
+	}
+	return false
+}
diff --git a/lib/go/thrift/type.go b/lib/go/thrift/type.go
index 7c68c2b..4292ffc 100644
--- a/lib/go/thrift/type.go
+++ b/lib/go/thrift/type.go
@@ -40,7 +40,7 @@
 	LIST   = 15
 	UTF8   = 16
 	UTF16  = 17
-	BINARY = 18
+	//BINARY = 18   wrong and unusued
 )
 
 var typeNames = map[int]string{
@@ -48,6 +48,7 @@
 	VOID:   "VOID",
 	BOOL:   "BOOL",
 	BYTE:   "BYTE",
+	DOUBLE: "DOUBLE",
 	I16:    "I16",
 	I32:    "I32",
 	I64:    "I64",
diff --git a/lib/go/thrift/zlib_transport.go b/lib/go/thrift/zlib_transport.go
new file mode 100644
index 0000000..f3d4267
--- /dev/null
+++ b/lib/go/thrift/zlib_transport.go
@@ -0,0 +1,132 @@
+/*
+* 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 (
+	"compress/zlib"
+	"context"
+	"io"
+	"log"
+)
+
+// TZlibTransportFactory is a factory for TZlibTransport instances
+type TZlibTransportFactory struct {
+	level   int
+	factory TTransportFactory
+}
+
+// TZlibTransport is a TTransport implementation that makes use of zlib compression.
+type TZlibTransport struct {
+	reader    io.ReadCloser
+	transport TTransport
+	writer    *zlib.Writer
+}
+
+// GetTransport constructs a new instance of NewTZlibTransport
+func (p *TZlibTransportFactory) GetTransport(trans TTransport) (TTransport, error) {
+	if p.factory != nil {
+		// wrap other factory
+		var err error
+		trans, err = p.factory.GetTransport(trans)
+		if err != nil {
+			return nil, err
+		}
+	}
+	return NewTZlibTransport(trans, p.level)
+}
+
+// NewTZlibTransportFactory constructs a new instance of NewTZlibTransportFactory
+func NewTZlibTransportFactory(level int) *TZlibTransportFactory {
+	return &TZlibTransportFactory{level: level, factory: nil}
+}
+
+// NewTZlibTransportFactory constructs a new instance of TZlibTransportFactory
+// as a wrapper over existing transport factory
+func NewTZlibTransportFactoryWithFactory(level int, factory TTransportFactory) *TZlibTransportFactory {
+	return &TZlibTransportFactory{level: level, factory: factory}
+}
+
+// NewTZlibTransport constructs a new instance of TZlibTransport
+func NewTZlibTransport(trans TTransport, level int) (*TZlibTransport, error) {
+	w, err := zlib.NewWriterLevel(trans, level)
+	if err != nil {
+		log.Println(err)
+		return nil, err
+	}
+
+	return &TZlibTransport{
+		writer:    w,
+		transport: trans,
+	}, nil
+}
+
+// Close closes the reader and writer (flushing any unwritten data) and closes
+// the underlying transport.
+func (z *TZlibTransport) Close() error {
+	if z.reader != nil {
+		if err := z.reader.Close(); err != nil {
+			return err
+		}
+	}
+	if err := z.writer.Close(); err != nil {
+		return err
+	}
+	return z.transport.Close()
+}
+
+// Flush flushes the writer and its underlying transport.
+func (z *TZlibTransport) Flush(ctx context.Context) error {
+	if err := z.writer.Flush(); err != nil {
+		return err
+	}
+	return z.transport.Flush(ctx)
+}
+
+// IsOpen returns true if the transport is open
+func (z *TZlibTransport) IsOpen() bool {
+	return z.transport.IsOpen()
+}
+
+// Open opens the transport for communication
+func (z *TZlibTransport) Open() error {
+	return z.transport.Open()
+}
+
+func (z *TZlibTransport) Read(p []byte) (int, error) {
+	if z.reader == nil {
+		r, err := zlib.NewReader(z.transport)
+		if err != nil {
+			return 0, NewTTransportExceptionFromError(err)
+		}
+		z.reader = r
+	}
+
+	return z.reader.Read(p)
+}
+
+// RemainingBytes returns the size in bytes of the data that is still to be
+// read.
+func (z *TZlibTransport) RemainingBytes() uint64 {
+	return z.transport.RemainingBytes()
+}
+
+func (z *TZlibTransport) Write(p []byte) (int, error) {
+	return z.writer.Write(p)
+}
diff --git a/lib/go/thrift/zlib_transport_test.go b/lib/go/thrift/zlib_transport_test.go
new file mode 100644
index 0000000..3c6f11e
--- /dev/null
+++ b/lib/go/thrift/zlib_transport_test.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
+
+import (
+	"compress/zlib"
+	"testing"
+)
+
+func TestZlibTransport(t *testing.T) {
+	trans, err := NewTZlibTransport(NewTMemoryBuffer(), zlib.BestCompression)
+	if err != nil {
+		t.Fatal(err)
+	}
+	TransportTest(t, trans, trans)
+}
+
+type DummyTransportFactory struct{}
+
+func (p *DummyTransportFactory) GetTransport(trans TTransport) (TTransport, error) {
+	return NewTMemoryBuffer(), nil
+}
+
+func TestZlibFactoryTransportWithFactory(t *testing.T) {
+	factory := NewTZlibTransportFactoryWithFactory(
+		zlib.BestCompression,
+		&DummyTransportFactory{},
+	)
+	buffer := NewTMemoryBuffer()
+	trans, err := factory.GetTransport(buffer)
+	if err != nil {
+		t.Fatal(err)
+	}
+	TransportTest(t, trans, trans)
+}
+
+func TestZlibFactoryTransportWithoutFactory(t *testing.T) {
+	factory := NewTZlibTransportFactoryWithFactory(zlib.BestCompression, nil)
+	buffer := NewTMemoryBuffer()
+	trans, err := factory.GetTransport(buffer)
+	if err != nil {
+		t.Fatal(err)
+	}
+	TransportTest(t, trans, trans)
+}
diff --git a/lib/haxe/README.md b/lib/haxe/README.md
new file mode 100644
index 0000000..e74b773
--- /dev/null
+++ b/lib/haxe/README.md
@@ -0,0 +1,164 @@
+Thrift Haxe Software Library
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+Using Thrift with Haxe
+========================
+
+Haxe setup
+---------------
+
+Thrift requires Haxe 3.1.3. Installers for Windows and OSX
+platforms are available at `http://haxe.org/download`. 
+
+Depending on the desired targets, you may have to install the appropriate HaxeLibs 
+after installing Haxe itself. For example, if you plan to target C#, Java and C++,
+enter the following commands after installing Haxe:
+
+    haxelib install hxcpp
+    haxelib install hxjava
+    haxelib install hxcs
+
+For other targets, please consult the Haxe documentation whether or not any additional
+target libraries need to be installed and how to achieve this.
+
+
+Haxe on Linux 
+---------------
+
+For Linux platforms it is recommended to use the distro-specific package
+manager, where possible. More detailed information can be found at the 
+Haxe Linux download section: http://haxe.org/download/linux
+
+If you run into the error message 
+
+    Uncaught exception - load.c(237) : Failed to load library : /usr/lib/neko/regexp.ndll  
+	(libpcre.so.3: cannot open shared object file: No such file or directory)
+
+this can be solved depending on your OSes bitness by either
+
+    sudo ln -sf /usr/lib/libpcre.so.1 /usr/lib/libpcre.so.3
+    sudo ldconfig
+	
+or
+
+    sudo ln -sf /usr/lib64/libpcre.so.1 /usr/lib64/libpcre.so.3
+    sudo ldconfig
+
+Thrift Haxe bindings
+-------------------
+	
+Thrift Haxe bindings can be set up via the `haxelib` tool  
+either from the official ASF repo, or via the github mirror.
+
+- To set up any **stable version**, choose the appropriate branch (e.g. `1.0.0`, etc.):
+
+    - `haxelib git thrift https://git.apache.org/thrift.git 1.0.0 lib/haxe`
+    - `haxelib git thrift https://github.com/apache/thrift.git 1.0.0 lib/haxe`
+
+- To set up the current **development version**, use the `master` branch:
+  
+    - `haxelib git thrift https://git.apache.org/thrift.git master lib/haxe`	
+    - `haxelib git thrift https://github.com/apache/thrift.git master lib/haxe`
+
+As usual, the installed library can be updated using `haxelib upgrade` 
+or `haxelib update thrift`.
+
+In order to work with Thrift, you will need to install the Thrift compiler 
+or build from source, depending on your operating system. Appropriate 
+downloads and more information can be found at http://thrift.apache.org
+	
+To get started, visit the /tutorial/haxe and /test/haxe dirs for examples. 
+If you are using HIDE or the FlashDevelop IDE, you'll find appropriate 
+project files in these folders.
+
+
+Current status
+========================
+- tested with Haxe C++ target
+- tested with Haxe PHP target (console/web server, binary protocols)
+- transports: Socket, HTTP (servers run inside PHP server/PHP target only), Stream
+- protocols: Binary, JSON, Multiplex, Compact
+- tutorial client and server available
+- cross-test client and server available 
+
+
+Further developments
+========================
+- improve to work with C#, Java and JavaScript Haxe/OpenFL targets
+- improve to work with more (ideally all) Haxe/OpenFL targets
+- add HTTP server, update tutorial and tests accordingly
+
+
+Known restrictions
+========================
+
+Although designed with maximum portability in mind, for technical reasons some platforms
+may only support parts of the library, or not be compatible at all.
+
+Javascript:
+- tutorial fails to build because of unsupported Sys.args
+
+PHP HTTP Server notes
+========================
+
+- you have to import PHP files generated by haxe into PHP
+```php
+require_once  dirname(__FILE__) . '/bin/php-web-server/Main-debug.php';
+```
+
+- trace() by default outputs into stdout (http response), so you have to redirect it to stderr or you own logs, something like
+```haxe
+//remap trace to error log
+haxe.Log.trace = function(v:Dynamic, ?infos:haxe.PosInfos) 
+{ 
+	//simulate normal trace https://github.com/HaxeFoundation/haxe/blob/development/std/haxe/Log.hx
+	var newValue : Dynamic;
+	if (infos != null && infos.customParams!=null) {
+		var extra:String = "";
+		for( v in infos.customParams )
+			extra += "," + v;
+		newValue = v + extra;
+	}
+	else {
+		newValue = v;
+	}
+	var msg = infos != null ? infos.fileName + ':' + infos.lineNumber + ': ' : '';
+	Sys.stderr().writeString('${msg}${newValue}\n');
+}
+```
+
+- to allow thrift server to read/write HTTP request/response, it should be pointed out to php streams
+```haxe
+transport =	new TWrappingServerTransport(
+				new TStreamTransport(
+					new TFileStream("php://input", Read),
+					new TFileStream("php://output", Append)
+					)
+				);
+```
+
+- TSimpleServer doesn't stop after first call, so processor.process() should be called instead, or use runOnce property 
+```haxe
+var server = new TSimpleServer( processor, transport, transfactory, protfactory);
+server.runOnce = true;
+```
+
diff --git a/lib/haxe/coding_standards.md b/lib/haxe/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/haxe/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/haxe/haxelib.json b/lib/haxe/haxelib.json
new file mode 100644
index 0000000..992ad90
--- /dev/null
+++ b/lib/haxe/haxelib.json
@@ -0,0 +1,12 @@
+{
+	"name": "thrift",
+	"url" : "http://thrift.apache.org",
+	"license": "Apache",
+	"tags": ["thrift", "rpc", "serialization", "cross", "framework"],
+	"description": "Haxe bindings for the Apache Thrift RPC and serialization framework",
+	"version": "1.0.0",
+	"releasenote": "Licensed under Apache License, Version 2.0. The Apache Thrift compiler needs to be installed separately.",
+	"contributors": ["Apache Software Foundation (ASF)"],
+	"dependencies": { },
+	"classPath": "src"
+}
diff --git a/lib/haxe/src/org/apache/thrift/AbstractMethodError.hx b/lib/haxe/src/org/apache/thrift/AbstractMethodError.hx
new file mode 100644
index 0000000..54b8153
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/AbstractMethodError.hx
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift;
+
+#if flash
+import flash.errors.IllegalOperationError;
+#else
+import org.apache.thrift.TException;
+#end
+
+class AbstractMethodError
+#if flash
+extends IllegalOperationError
+#else
+extends TException
+#end
+{
+
+    public function new(message : String="") {
+          super("Attempt to call an abstract method");
+    }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/ArgumentError.hx b/lib/haxe/src/org/apache/thrift/ArgumentError.hx
new file mode 100644
index 0000000..3ca04fd
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/ArgumentError.hx
@@ -0,0 +1,29 @@
+/*
+ * 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 org.apache.thrift;
+
+#if ! flash
+// predefined for flash only
+class ArgumentError extends TException {
+    public function new(msg : String = "") {
+        super(msg);
+    }
+}
+#end
diff --git a/lib/haxe/src/org/apache/thrift/Limits.hx b/lib/haxe/src/org/apache/thrift/Limits.hx
new file mode 100644
index 0000000..44eec3a
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/Limits.hx
@@ -0,0 +1,44 @@
+/*
+ * 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 org.apache.thrift;
+
+class Limits {
+
+    // Haxe limits are not fixed values, they depend on the target platform
+    // For example, neko limits an int to 31 bits instead of 32. So we detect
+    // the values once during intialisation in order to
+    // (a) get the right values for the current  platform, and
+    // (b) prevent us from dependecies to a bunch of defines
+
+    public static var I32_MAX = {
+        var last : Int = 0;
+        var next : Int = 0;
+        for(bit in 0 ... 32) {
+            last = next;
+            next = last | (1 << bit);
+            if(next < 0) {
+                break;
+            }
+        }
+        last; // final value
+    }
+
+    // add whatever you need
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/TApplicationException.hx b/lib/haxe/src/org/apache/thrift/TApplicationException.hx
new file mode 100644
index 0000000..7fe844f
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/TApplicationException.hx
@@ -0,0 +1,104 @@
+/*
+ * 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 org.apache.thrift;
+
+import org.apache.thrift.protocol.TField;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolUtil;
+import org.apache.thrift.protocol.TStruct;
+import org.apache.thrift.protocol.TType;
+
+  /**
+   * Application level exception
+   */
+class TApplicationException extends TException {
+
+    private static var TAPPLICATION_EXCEPTION_STRUCT = { new TStruct("TApplicationException"); };
+    private static var MESSAGE_FIELD = { new TField("message", TType.STRING, 1); };
+    private static var TYPE_FIELD = { new TField("type", TType.I32, 2); };
+
+    // WARNING: These are subject to be extended in the future, so we can't use enums
+    // with Haxe 3.1.3 because of https://github.com/HaxeFoundation/haxe/issues/3649
+    public static inline var UNKNOWN : Int = 0;
+    public static inline var UNKNOWN_METHOD : Int = 1;
+    public static inline var INVALID_MESSAGE_TYPE : Int = 2;
+    public static inline var WRONG_METHOD_NAME : Int = 3;
+    public static inline var BAD_SEQUENCE_ID : Int = 4;
+    public static inline var MISSING_RESULT : Int = 5;
+    public static inline var INTERNAL_ERROR : Int = 6;
+    public static inline var PROTOCOL_ERROR : Int = 7;
+    public static inline var INVALID_TRANSFORM : Int = 8;
+    public static inline var INVALID_PROTOCOL : Int = 9;
+    public static inline var UNSUPPORTED_CLIENT_TYPE : Int = 10;
+
+    public function new(type : Int = UNKNOWN, message : String = "") {
+      super(message, type);
+    }
+
+    public static function read(iprot:TProtocol) : TApplicationException {
+      var field:TField;
+      iprot.readStructBegin();
+
+      var message : String = null;
+      var type : Int = UNKNOWN;
+
+      while (true) {
+        field = iprot.readFieldBegin();
+        if (field.type == TType.STOP) {
+          break;
+        }
+        switch (field.id) {
+          case 1:
+            if (field.type == TType.STRING) {
+              message = iprot.readString();
+            }
+            else {
+              TProtocolUtil.skip(iprot, field.type);
+            }
+          case 2:
+            if (field.type == TType.I32) {
+              type = iprot.readI32();
+            }
+            else {
+              TProtocolUtil.skip(iprot, field.type);
+            }
+          default:
+            TProtocolUtil.skip(iprot, field.type);
+        }
+        iprot.readFieldEnd();
+      }
+      iprot.readStructEnd();
+      return new TApplicationException(type, message);
+    }
+
+    public function write(oprot:TProtocol) : Void {
+        oprot.writeStructBegin(TAPPLICATION_EXCEPTION_STRUCT);
+        if (errorMsg != null) {
+          oprot.writeFieldBegin(MESSAGE_FIELD);
+          oprot.writeString(errorMsg);
+          oprot.writeFieldEnd();
+        }
+        oprot.writeFieldBegin(TYPE_FIELD);
+        oprot.writeI32(errorID);
+        oprot.writeFieldEnd();
+        oprot.writeFieldStop();
+        oprot.writeStructEnd();
+      }
+}
diff --git a/lib/haxe/src/org/apache/thrift/TBase.hx b/lib/haxe/src/org/apache/thrift/TBase.hx
new file mode 100644
index 0000000..ede0beb
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/TBase.hx
@@ -0,0 +1,73 @@
+/*
+ * 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 org.apache.thrift;
+
+// Make sure we use at least 3.1.3
+// Some Linux platforms have waaaay too old packages in their repos
+// Pro Tip: Look at http://openfl.com for a good Linux install script
+#if( haxe_ver < 3.103)
+#error Haxe 3.1.3 or newer required, sorry!
+#end
+
+import org.apache.thrift.protocol.TProtocol;
+
+  /**
+   * Generic base interface for generated Thrift objects.
+   *
+   */
+interface TBase {
+
+    /**
+     * Reads the TObject from the given input protocol.
+     *
+     * @param iprot Input protocol
+     */
+    function read(iprot:TProtocol) : Void;
+
+    /**
+     * Writes the objects out to the protocol
+     *
+     * @param oprot Output protocol
+     */
+    function write(oprot:TProtocol) : Void;
+
+    /**
+     * Check if a field is currently set or unset.
+     *
+     * @param fieldId The field's id tag as found in the IDL.
+     */
+    function isSet(fieldId : Int) : Bool;
+
+    /**
+     * Get a field's value by id. Primitive types will be wrapped in the
+     * appropriate "boxed" types.
+     *
+     * @param fieldId The field's id tag as found in the IDL.
+     */
+    function getFieldValue(fieldId : Int) : Dynamic;
+
+    /**
+     * Set a field's value by id. Primitive types must be "boxed" in the
+     * appropriate object wrapper type.
+     *
+     * @param fieldId The field's id tag as found in the IDL.
+     */
+    function setFieldValue(fieldId : Int, value : Dynamic) : Void;
+}
diff --git a/lib/haxe/src/org/apache/thrift/TException.hx b/lib/haxe/src/org/apache/thrift/TException.hx
new file mode 100644
index 0000000..54fa1ff
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/TException.hx
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.thrift;
+
+class TException {
+
+    @:isVar
+    public var errorID(default,null) : Int;
+    @:isVar
+    public var errorMsg(default,null) : String;
+
+
+    public function new(msg : String = "", id : Int = 0) {
+        errorID = id;
+        errorMsg = msg;
+    }
+
+}
+ 
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/TFieldRequirementType.hx b/lib/haxe/src/org/apache/thrift/TFieldRequirementType.hx
new file mode 100644
index 0000000..039a2cf
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/TFieldRequirementType.hx
@@ -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 org.apache.thrift;
+
+  /**
+   * Requirement type constants.
+   *
+   */
+@:enum
+abstract TFieldRequirementType(Int)  from Int to Int  {
+    public static inline var REQUIRED : Int = 1;
+    public static inline var OPTIONAL : Int = 2;
+    public static inline var DEFAULT  : Int = 3;
+}
diff --git a/lib/haxe/src/org/apache/thrift/TProcessor.hx b/lib/haxe/src/org/apache/thrift/TProcessor.hx
new file mode 100644
index 0000000..0cb6f7d
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/TProcessor.hx
@@ -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 org.apache.thrift;
+
+import org.apache.thrift.protocol.TProtocol;
+
+/**
+ * A processor is a generic object which operates upon an input stream and
+ * writes to some output stream.
+ */
+interface TProcessor {
+    function process(input:TProtocol, output:TProtocol) : Bool;
+}
diff --git a/lib/haxe/src/org/apache/thrift/helper/BitConverter.hx b/lib/haxe/src/org/apache/thrift/helper/BitConverter.hx
new file mode 100644
index 0000000..ee0aaa8
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/BitConverter.hx
@@ -0,0 +1,170 @@
+/*
+ * 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 org.apache.thrift.helper;
+
+import haxe.Int64;
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+
+class BitConverter {
+
+    public static function DoubleToInt64Bits( db : Float) : Int64 {
+        var buf = new BytesBuffer();
+        buf.addDouble( db);
+        return bytesToLong( buf.getBytes());
+    }
+
+
+    public static function Int64BitsToDouble( i64 : Int64) : Float {
+        var buf = new BytesBuffer();
+        buf.add( fixedLongToBytes( i64));
+        return buf.getBytes().getDouble(0);
+    }
+
+
+
+    /**
+     * Convert a long into little-endian bytes in buf starting at off and going
+     * until off+7.
+     */
+    public static function fixedLongToBytes( n : Int64)  : Bytes {
+        var buf = Bytes.alloc(8);
+        #if( haxe_ver < 3.2)
+        buf.set( 0, Int64.getLow( Int64.and( n, Int64.make(0, 0xff))));
+        buf.set( 1, Int64.getLow( Int64.and( Int64.shr( n, 8),  Int64.make(0, 0xff))));
+        buf.set( 2, Int64.getLow( Int64.and( Int64.shr( n, 16), Int64.make(0, 0xff))));
+        buf.set( 3, Int64.getLow( Int64.and( Int64.shr( n, 24), Int64.make(0, 0xff))));
+        buf.set( 4, Int64.getLow( Int64.and( Int64.shr( n, 32), Int64.make(0, 0xff))));
+        buf.set( 5, Int64.getLow( Int64.and( Int64.shr( n, 40), Int64.make(0, 0xff))));
+        buf.set( 6, Int64.getLow( Int64.and( Int64.shr( n, 48), Int64.make(0, 0xff))));
+        buf.set( 7, Int64.getLow( Int64.and( Int64.shr( n, 56), Int64.make(0, 0xff))));
+        #else
+        buf.set( 0, Int64.and( n, Int64.make(0, 0xff)).low);
+        buf.set( 1, Int64.and( Int64.shr( n, 8),  Int64.make(0, 0xff)).low);
+        buf.set( 2, Int64.and( Int64.shr( n, 16), Int64.make(0, 0xff)).low);
+        buf.set( 3, Int64.and( Int64.shr( n, 24), Int64.make(0, 0xff)).low);
+        buf.set( 4, Int64.and( Int64.shr( n, 32), Int64.make(0, 0xff)).low);
+        buf.set( 5, Int64.and( Int64.shr( n, 40), Int64.make(0, 0xff)).low);
+        buf.set( 6, Int64.and( Int64.shr( n, 48), Int64.make(0, 0xff)).low);
+        buf.set( 7, Int64.and( Int64.shr( n, 56), Int64.make(0, 0xff)).low);
+        #end
+        return buf;
+    }
+
+    /**
+     * 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.
+     */
+    public static function bytesToLong( bytes : Bytes) : Int64 {
+        var result : Int64 = Int64.make(0, 0);
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(7)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(6)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(5)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(4)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(3)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(2)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(1)));
+        result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(0)));
+        return result;
+    }
+
+
+    #if debug
+    private static function TestBTL( test : Int64) : Void {
+        var buf : Bytes = fixedLongToBytes( test);
+        var erg = bytesToLong(buf);
+        if ( Int64.compare( erg, test) != 0)
+            throw 'BitConverter.bytesToLongTest($test) failed: $erg';
+    }
+    #end
+
+
+    #if debug
+    private static function TestPair( a : Float, b : Int64) : Void {
+        var bx = DoubleToInt64Bits(a);
+        if ( Int64.compare( bx, b) != 0)
+            throw 'BitConverter.TestPair: DoubleToInt64Bits($a): expected $b, got $bx';
+        var ax = Int64BitsToDouble(b);
+        if( ax != a)
+            throw 'BitConverter.TestPair: Int64BitsToDouble($b: expected $a, got  $ax';
+    }
+    #end
+
+
+    #if debug
+    public static function UnitTest() : Void {
+
+        // bytesToLong()
+        var i : Int;
+        TestBTL( Int64.make(0,0));
+        for ( i in 0 ... 62) {
+            TestBTL( Int64.shl( Int64.make(0,1), i));
+            TestBTL( Int64.sub( Int64.make(0,0), Int64.shl( Int64.make(0,1), i)));
+        }
+        TestBTL( Int64.make(0x7FFFFFFF,0xFFFFFFFF));
+        TestBTL( Int64.make(cast(0x80000000,Int),0x00000000));
+
+        // DoubleToInt64Bits;
+        TestPair( 1.0000000000000000E+000,  Int64.make(cast(0x3FF00000,Int),cast(0x00000000,Int)));
+        TestPair( 1.5000000000000000E+001,  Int64.make(cast(0x402E0000,Int),cast(0x00000000,Int)));
+        TestPair( 2.5500000000000000E+002,  Int64.make(cast(0x406FE000,Int),cast(0x00000000,Int)));
+        TestPair( 4.2949672950000000E+009,  Int64.make(cast(0x41EFFFFF,Int),cast(0xFFE00000,Int)));
+        TestPair( 3.9062500000000000E-003,  Int64.make(cast(0x3F700000,Int),cast(0x00000000,Int)));
+        TestPair( 2.3283064365386963E-010,  Int64.make(cast(0x3DF00000,Int),cast(0x00000000,Int)));
+        TestPair( 1.2345678901230000E-300,  Int64.make(cast(0x01AA74FE,Int),cast(0x1C1E7E45,Int)));
+        TestPair( 1.2345678901234500E-150,  Int64.make(cast(0x20D02A36,Int),cast(0x586DB4BB,Int)));
+        TestPair( 1.2345678901234565E+000,  Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FA,Int)));
+        TestPair( 1.2345678901234567E+000,  Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FB,Int)));
+        TestPair( 1.2345678901234569E+000,  Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FC,Int)));
+        TestPair( 1.2345678901234569E+150,  Int64.make(cast(0x5F182344,Int),cast(0xCD3CDF9F,Int)));
+        TestPair( 1.2345678901234569E+300,  Int64.make(cast(0x7E3D7EE8,Int),cast(0xBCBBD352,Int)));
+        TestPair( -1.7976931348623157E+308, Int64.make(cast(0xFFEFFFFF,Int),cast(0xFFFFFFFF,Int)));
+        TestPair( 1.7976931348623157E+308,  Int64.make(cast(0x7FEFFFFF,Int),cast(0xFFFFFFFF,Int)));
+        TestPair( 4.9406564584124654E-324,  Int64.make(cast(0x00000000,Int),cast(0x00000001,Int)));
+        TestPair( 0.0000000000000000E+000,  Int64.make(cast(0x00000000,Int),cast(0x00000000,Int)));
+        TestPair( 4.94065645841247E-324,    Int64.make(cast(0x00000000,Int),cast(0x00000001,Int)));
+        TestPair( 3.2378592100206092E-319,  Int64.make(cast(0x00000000,Int),cast(0x0000FFFF,Int)));
+        TestPair( 1.3906711615669959E-309,  Int64.make(cast(0x0000FFFF,Int),cast(0xFFFFFFFF,Int)));
+        TestPair( Math.NEGATIVE_INFINITY,   Int64.make(cast(0xFFF00000,Int),cast(0x00000000,Int)));
+        TestPair( Math.POSITIVE_INFINITY,   Int64.make(cast(0x7FF00000,Int),cast(0x00000000,Int)));
+
+        // NaN is special
+        var i64nan = DoubleToInt64Bits( Math.NaN);
+        var i64cmp = Int64.make(cast(0xFFF80000, Int), cast(0x00000000, Int));
+        if ( ! Math.isNaN( Int64BitsToDouble( i64cmp)))
+            throw 'BitConverter NaN-Test #1: expected NaN';
+
+        // For doubles, a quiet NaN is a bit pattern
+        // between 7FF8000000000000 and 7FFFFFFFFFFFFFFF
+        //      or FFF8000000000000 and FFFFFFFFFFFFFFFF
+        var min1 = Int64.make( cast(0x7FF80000, Int), cast(0x00000000, Int));
+        var max1 = Int64.make( cast(0x7FFFFFFF, Int), cast(0xFFFFFFFF, Int));
+        var min2 = Int64.make( cast(0xFFF80000, Int), cast(0x00000000, Int));
+        var max2 = Int64.make( cast(0xFFFFFFFF, Int), cast(0xFFFFFFFF, Int));
+        var ok1 =  (Int64.compare( min1, i64nan) <= 0) && (Int64.compare( i64nan, max1) <= 0);
+        var ok2 =  (Int64.compare( min2, i64nan) <= 0) && (Int64.compare( i64nan, max2) <= 0);
+        if( ! (ok1 || ok2))
+            throw 'BitConverter NaN-Test #2: failed';
+    }
+    #end
+
+}
+    
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx b/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx
new file mode 100644
index 0000000..8845fd0
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx
@@ -0,0 +1,295 @@
+/*
+ * 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 org.apache.thrift.helper;
+
+import Map;
+import haxe.Int64;
+import haxe.ds.IntMap;
+
+
+// Int64Map allows mapping of Int64 keys to arbitrary values.
+// ObjectMap<> cannot be used, since we want to compare by value, not address
+
+class Int64Map<T> implements IMap< Int64, T> {
+
+    private var SubMaps : IntMap< IntMap< T>>;  // Hi -> Lo -> Value
+
+    public function new() : Void {
+        SubMaps = new IntMap< IntMap< T>>();
+    };
+
+    private function GetSubMap( hi : haxe.Int32, canCreate : Bool) : IntMap< T> {
+        if( SubMaps.exists(hi)) {
+            return SubMaps.get(hi);
+        }
+
+        if( ! canCreate) {
+            return null;
+        }
+
+        var lomap = new IntMap< T>();
+        SubMaps.set( hi, lomap);
+        return lomap;
+    }
+
+
+    private function GetLowMap( key : haxe.Int64, canCreate : Bool) : IntMap< T> {
+        #if( haxe_ver < 3.2)
+        return GetSubMap( Int64.getHigh(key), canCreate);
+        #else
+        return GetSubMap( key.high, canCreate);
+        #end
+    }
+
+
+    private function GetLowIndex( key : haxe.Int64) : haxe.Int32 {
+        #if( haxe_ver < 3.2)
+        return Int64.getLow(key);
+        #else
+        return key.low;
+        #end
+    }
+
+
+    private function NullCheck( key : haxe.Int64) : Bool {
+        #if( haxe_ver < 3.2)
+        return (key != null);
+        #else
+        return true;  // Int64 is not nullable anymore (it never really was)
+        #end
+    };
+
+
+
+    /**
+        Maps `key` to `value`.
+        If `key` already has a mapping, the previous value disappears.
+        If `key` is null, the result is unspecified.
+    **/
+    public function set( key : Int64, value : T ) : Void {
+        if( ! NullCheck(key)) {
+            return;
+        }
+
+        var lomap = GetLowMap( key, true);
+        lomap.set( GetLowIndex(key), value);
+    }
+
+
+    /**
+        Returns the current mapping of `key`.
+        If no such mapping exists, null is returned.
+        If `key` is null, the result is unspecified.
+
+        Note that a check like `map.get(key) == null` can hold for two reasons:
+
+            1. the map has no mapping for `key`
+            2. the map has a mapping with a value of `null`
+
+        If it is important to distinguish these cases, `exists()` should be
+        used.
+
+    **/
+    public function get( key : Int64) : Null<T> {
+        if( ! NullCheck(key)) {
+            return null;
+        }
+
+        var lomap = GetLowMap( key, true);
+        if( lomap == null) {
+            return null;
+        }
+
+        return lomap.get( GetLowIndex(key));
+    }
+
+    /**
+        Returns true if `key` has a mapping, false otherwise.
+        If `key` is null, the result is unspecified.
+    **/
+    public function exists( key : Int64) : Bool {
+        if( ! NullCheck(key)) {
+            return false;
+        }
+
+        var lomap = GetLowMap( key, true);
+        if( lomap == null) {
+            return false;
+        }
+
+        return lomap.exists( GetLowIndex(key));
+    }
+
+    /**
+        Removes the mapping of `key` and returns true if such a mapping existed,
+        false otherwise. If `key` is null, the result is unspecified.
+    **/
+    public function remove( key : Int64) : Bool {
+        if( ! NullCheck(key)) {
+            return false;
+        }
+
+        var lomap = GetLowMap( key, true);
+        if( lomap == null) {
+            return false;
+        }
+
+        return lomap.remove( GetLowIndex(key));
+    }
+
+
+    /**
+        Returns an Iterator over the keys of `this` Map.
+        The order of keys is undefined.
+    **/
+    public function keys() : Iterator<Int64> {
+        return new Int64KeyIterator<T>(SubMaps);
+    }
+
+    /**
+        Returns an Iterator over the values of `this` Map.
+        The order of values is undefined.
+    **/
+    public function iterator() : Iterator<T> {
+        return new Int64ValueIterator<T>(SubMaps);
+    }
+
+    /**
+        Returns a String representation of `this` Map.
+        The exact representation depends on the platform and key-type.
+    **/
+    public function toString() : String {
+        var result : String = "{";
+
+        var first = true;
+        for( key in this.keys()) {
+            if( first) {
+                first = false;
+            } else {
+                result += ",";
+            }
+
+            result += " ";
+            var value = this.get(key);
+            result += Int64.toStr(key) + ' => $value';
+        }
+
+        return result + "}";
+    }
+
+}
+
+
+// internal helper class for Int64Map<T>
+// all class with matching methods can be used as iterator (duck typing)
+private class Int64MapIteratorBase<T> {
+
+    private var SubMaps : IntMap< IntMap< T>>;  // Hi -> Lo -> Value
+
+    private var HiIterator : Iterator< Int> = null;
+    private var LoIterator : Iterator< Int> = null;
+    private var CurrentHi : Int = 0;
+
+    public function new( data : IntMap< IntMap< T>>) : Void {
+        SubMaps = data;
+        HiIterator = SubMaps.keys();
+        LoIterator = null;
+        CurrentHi = 0;
+    };
+
+    /**
+        Returns false if the iteration is complete, true otherwise.
+
+        Usually iteration is considered to be complete if all elements of the
+        underlying data structure were handled through calls to next(). However,
+        in custom iterators any logic may be used to determine the completion
+        state.
+    **/
+    public function hasNext() : Bool {
+
+        if( (LoIterator != null) && LoIterator.hasNext()) {
+            return true;
+        }
+
+        while( (HiIterator != null) && HiIterator.hasNext()) {
+            CurrentHi = HiIterator.next();
+            LoIterator = SubMaps.get(CurrentHi).keys();
+            if( (LoIterator != null) && LoIterator.hasNext()) {
+                return true;
+            }
+        }
+
+        HiIterator = null;
+        LoIterator = null;
+        return false;
+    }
+
+}
+
+
+// internal helper class for Int64Map<T>
+// all class with matching methods can be used as iterator (duck typing)
+private class Int64KeyIterator<T>extends Int64MapIteratorBase<T> {
+
+    public function new( data : IntMap< IntMap< T>>) : Void {
+        super(data);
+    };
+
+    /**
+        Returns the current item of the Iterator and advances to the next one.
+
+        This method is not required to check hasNext() first. A call to this
+        method while hasNext() is false yields unspecified behavior.
+    **/
+    public function next() : Int64 {
+        if( hasNext()) {
+            return Int64.make( CurrentHi, LoIterator.next());
+        } else {
+            throw "no more elements";
+        }
+    }
+}
+
+
+// internal helper class for Int64Map<T>
+// all class with matching methods can be used as iterator (duck typing)
+private class Int64ValueIterator<T> extends Int64MapIteratorBase<T> {
+
+    public function new( data : IntMap< IntMap< T>>) : Void {
+        super(data);
+    };
+
+    /**
+        Returns the current item of the Iterator and advances to the next one.
+
+        This method is not required to check hasNext() first. A call to this
+        method while hasNext() is false yields unspecified behavior.
+    **/
+    public function next() : T {
+        if( hasNext()) {
+            return SubMaps.get(CurrentHi).get(LoIterator.next());
+        } else {
+            throw "no more elements";
+        }
+    }
+}
+
+
+// EOF
diff --git a/lib/haxe/src/org/apache/thrift/helper/IntSet.hx b/lib/haxe/src/org/apache/thrift/helper/IntSet.hx
new file mode 100644
index 0000000..91e5d8e
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/IntSet.hx
@@ -0,0 +1,96 @@
+/*
+ * 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 org.apache.thrift.helper;
+
+import Map;
+
+
+class IntSet {
+
+    private var _elements = new haxe.ds.IntMap<Int>();
+    private var _size : Int = 0;
+    public var size(get,never) : Int;
+
+    public function new( values : Array<Int> = null) {
+        if ( values != null) {
+            for ( value in values) {
+                 add(value);
+            }
+        }
+    }
+
+    public function iterator():Iterator<Int> {
+        return _elements.keys();
+    }
+
+    public function traceAll() : Void {
+        trace('$_size entries');
+        for(entry in this) {
+            var yes = contains(entry);
+            trace('- $entry, contains() = $yes');
+        }
+    }
+
+    public function add(o : Int) : Bool {
+        if( _elements.exists(o)) {
+            return false;
+        }
+        _size++;
+        _elements.set(o,_size);
+        return true;
+    }
+
+    public function clear() : Void {
+        while( _size > 0) {
+            remove( _elements.keys().next());
+        }
+    }
+
+    public function contains(o : Int) : Bool {
+        return _elements.exists(o);
+    }
+
+    public function isEmpty() : Bool {
+        return _size == 0;
+    }
+
+    public function remove(o : Int) : Bool {
+        if (contains(o)) {
+            _elements.remove(o);
+            _size--;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public function toArray() : Array<Int> {
+        var ret : Array<Int> = new Array<Int>();
+        for (key in _elements.keys()) {
+            ret.push(key);
+        }
+        return ret;
+    }
+
+    public function get_size() : Int {
+        return _size;
+    }
+}
+    
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx b/lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx
new file mode 100644
index 0000000..bcf72fb
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/ObjectSet.hx
@@ -0,0 +1,96 @@
+/*
+ * 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 org.apache.thrift.helper;
+
+import Map;
+
+
+class ObjectSet<K> {
+
+    private var _elements = new haxe.ds.ObjectMap<K,Int>();
+    private var _size : Int = 0;
+    public var size(get,never) : Int;
+
+    public function new( values : Array<K> = null) {
+        if ( values != null) {
+            for ( value in values) {
+                 add(value);
+            }
+        }
+    }
+
+    public function iterator():Iterator<K> {
+        return _elements.keys();
+    }
+
+    public function traceAll() : Void {
+        trace('$_size entries');
+        for(entry in this) {
+            var yes = contains(entry);
+            trace('- $entry, contains() = $yes');
+        }
+    }
+
+    public function add(o : K) : Bool {
+        if( _elements.exists(o)) {
+            return false;
+        }
+        _size++;
+        _elements.set(o,_size);
+        return true;
+    }
+
+    public function clear() : Void {
+        while( _size > 0) {
+            remove( _elements.keys().next());
+        }
+    }
+
+    public function contains(o : K) : Bool {
+        return _elements.exists(o);
+    }
+
+    public function isEmpty() : Bool {
+        return _size == 0;
+    }
+
+    public function remove(o : K) : Bool {
+        if (contains(o)) {
+            _elements.remove(o);
+            _size--;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public function toArray() : Array<K> {
+        var ret : Array<K> = new Array<K>();
+        for (key in _elements.keys()) {
+            ret.push(key);
+        }
+        return ret;
+    }
+
+    public function get_size() : Int {
+        return _size;
+    }
+}
+    
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/helper/StringSet.hx b/lib/haxe/src/org/apache/thrift/helper/StringSet.hx
new file mode 100644
index 0000000..d8c0d90
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/StringSet.hx
@@ -0,0 +1,96 @@
+/*
+ * 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 org.apache.thrift.helper;
+
+import Map;
+
+
+class StringSet {
+
+    private var _elements = new haxe.ds.StringMap<Int>();
+    private var _size : Int = 0;
+    public var size(get,never) : Int;
+
+    public function new( values : Array<String> = null) {
+        if ( values != null) {
+            for ( value in values) {
+                 add(value);
+            }
+        }
+    }
+
+    public function iterator():Iterator<String> {
+        return _elements.keys();
+    }
+
+    public function traceAll() : Void {
+        trace('$_size entries');
+        for(entry in this) {
+            var yes = contains(entry);
+            trace('- $entry, contains() = $yes');
+        }
+    }
+
+    public function add(o : String) : Bool {
+        if( _elements.exists(o)) {
+            return false;
+        }
+        _size++;
+        _elements.set(o,_size);
+        return true;
+    }
+
+    public function clear() : Void {
+        while( _size > 0) {
+            remove( _elements.keys().next());
+        }
+    }
+
+    public function contains(o : String) : Bool {
+        return _elements.exists(o);
+    }
+
+    public function isEmpty() : Bool {
+        return _size == 0;
+    }
+
+    public function remove(o : String) : Bool {
+        if (contains(o)) {
+            _elements.remove(o);
+            _size--;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public function toArray() : Array<String> {
+        var ret : Array<String> = new Array<String>();
+        for (key in _elements.keys()) {
+            ret.push(key);
+        }
+        return ret;
+    }
+
+    public function get_size() : String {
+        return _size;
+    }
+}
+    
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/helper/ZigZag.hx b/lib/haxe/src/org/apache/thrift/helper/ZigZag.hx
new file mode 100644
index 0000000..3f8601b
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/ZigZag.hx
@@ -0,0 +1,158 @@
+/*
+ * 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 org.apache.thrift.helper;
+
+import haxe.Int64;
+import haxe.Int32;
+
+class ZigZag {
+
+    /**
+     * Convert n into a zigzag int. This allows negative numbers to be
+     * represented compactly as a varint.
+     */
+    public static function FromInt( n : Int) : UInt    {
+        #if php
+
+        return cast(cast(cast(n,Int32) << 1,Int32) ^ cast(cast(n,Int32) >> 31,Int32),UInt);
+
+        #else
+
+        return cast(n << 1,UInt) ^ cast(n >> 31,UInt);
+
+        #end
+    }
+
+
+    /**
+     * Convert from zigzag int to int.
+     */
+    public static function ToInt( n : UInt) : Int {
+        #if php
+
+        var a = (0x7FFFFFFF & cast(n >> 1,Int));
+        var b = (cast(n & 1,Int));
+        b = -b;  // workaround for https://github.com/HaxeFoundation/haxe/issues/5288
+        return a ^ b;
+
+        #else
+
+        return (0x7FFFFFFF & cast(n >> 1,Int)) ^ (-cast(n & 1,Int));
+
+        #end
+    }
+
+
+    /**
+     * Convert l into a zigzag long. This allows negative numbers to be
+     * represented compactly as a varint.
+     */
+    public static function FromLong( n : Int64) : Int64 {
+        return Int64.xor( Int64.shl(n, 1), Int64.shr(n, 63));
+    }
+
+
+    /**
+     * Convert from zigzag long to long.
+     */
+    public static function ToLong( n : Int64) : Int64 {
+        return Int64.xor(
+            Int64.and(
+                Int64.shr(n, 1),
+                Int64.make(0x7FFFFFFF, 0xFFFFFFFF)),
+            Int64.sub(
+                Int64.make(0, 0),
+                Int64.and(n, Int64.make(0,1))));
+    }
+
+
+    #if debug
+    private static function Test32( test : Int) : Void {
+        var a : UInt = ZigZag.FromInt( test);
+        var b : Int = ZigZag.ToInt(a);
+        #if php
+        test = test & 0xFFFFFFFF;  // workaround for https://github.com/HaxeFoundation/haxe/issues/5289
+        #end
+        if( test != b)
+            throw 'ZigZag.Test32($test) failed: a = $a, b = $b';
+    }
+    #end
+
+
+
+    #if debug
+    private static function Test64( test : haxe.Int64) : Void {
+        var a : Int64 = ZigZag.FromLong( test);
+        var b : Int64 = ZigZag.ToLong(a);
+        if( Int64.compare( test, b) != 0)
+            throw 'ZigZag.Test64($test) failed: a = $a, b = $b';
+    }
+    #end
+
+
+    #if debug
+    public static function UnitTest() : Void {
+      var u1 : UInt = 0xFFFFFFFE;
+      var u2 : UInt = 0xFFFFFFFF;
+      var i1 : Int = 2147483647;
+      var i2 : Int = -2147483648;
+
+      #if php
+      i2 = i2 & 0xFFFFFFFF;  // workaround for https://github.com/HaxeFoundation/haxe/issues/5289
+      #end
+
+      // protobuf testcases
+      if( FromInt(0)  != 0) throw 'pb #1 to ZigZag';
+      if( FromInt(-1) != 1) throw 'pb #2 to ZigZag';
+      if( FromInt(1)  != 2) throw 'pb #3 to ZigZag';
+      if( FromInt(-2) != 3) throw 'pb #4 to ZigZag';
+      if( FromInt(i1) != u1) throw 'pb #5 to ZigZag';
+      if( FromInt(i2) != u2) throw 'pb #6 to ZigZag';
+
+      // protobuf testcases
+      if( ToInt(0) != 0) throw 'pb #1 from ZigZag';
+      if( ToInt(1) != -1) throw 'pb #2 from ZigZag';
+      if( ToInt(2) != 1) throw 'pb #3 from ZigZag';
+      if( ToInt(3) != -2) throw 'pb #4 from ZigZag';
+      if( ToInt(u1) != i1) throw 'pb #5 from ZigZag, got ${ToInt(u1)} expected $i1';
+      if( ToInt(u2) != i2) throw 'pb #6 from ZigZag, got ${ToInt(u2)} expected $i2';
+
+      // back and forth 32
+      Test32( 0);
+      for( i in 0 ... 30) {
+        Test32( 1 << i);
+        Test32( -(1  << i));
+      }
+      Test32( 0x7FFFFFFF);
+      Test32( cast(0x80000000,Int));
+
+      // back and forth 64
+      Test64( Int64.make(0,0));
+      for( i in 0 ... 62) {
+        Test64( Int64.shl( Int64.make(0,1), i));
+        Test64( Int64.sub( Int64.make(0,0), Int64.shl( Int64.make(0,1), i)));
+      }
+      Test64( Int64.make(0x7FFFFFFF,0xFFFFFFFF));
+      Test64( Int64.make(cast(0x80000000,Int),0x00000000));
+    }
+    #end
+}
+
+   
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/meta_data/FieldMetaData.hx b/lib/haxe/src/org/apache/thrift/meta_data/FieldMetaData.hx
new file mode 100644
index 0000000..26db113
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/meta_data/FieldMetaData.hx
@@ -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 org.apache.thrift.meta_data;
+
+import flash.utils.Dictionary;
+
+/**
+* This class is used to store meta data about thrift fields. Every field in a
+* a struct should have a corresponding instance of this class describing it.
+*
+*/
+class FieldMetaData {
+
+  public var fieldName : String;
+  public var requirementType : Int;
+  public var valueMetaData:FieldValueMetaData;
+
+  private static var structMap:Dictionary = new Dictionary();
+
+  public function FieldMetaData(name : String, req : Int, vMetaData:FieldValueMetaData) {
+    this.fieldName = name;
+    this.requirementType = req;
+    this.valueMetaData = vMetaData;
+  }
+
+  public static function addStructMetaDataMap(sClass:Class, map:Dictionary) : Void{
+    structMap[sClass] = map;
+  }
+
+  /**
+   * Returns a map with metadata (i.e. instances of FieldMetaData) that
+   * describe the fields of the given class.
+   *
+   * @param sClass The TBase class for which the metadata map is requested
+   */
+  public static function getStructMetaDataMap(sClass:Class):Dictionary {
+    return structMap[sClass];
+  }
+}
diff --git a/lib/haxe/src/org/apache/thrift/meta_data/FieldValueMetaData.hx b/lib/haxe/src/org/apache/thrift/meta_data/FieldValueMetaData.hx
new file mode 100644
index 0000000..8879d91
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/meta_data/FieldValueMetaData.hx
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.thrift.meta_data;
+
+import org.apache.thrift.protocol.TType;
+
+/**
+ * FieldValueMetaData and collection of subclasses to store metadata about
+ * the value(s) of a field
+ */
+class FieldValueMetaData {
+
+  public var type : Int;
+
+  public function FieldValueMetaData(type : Int) {
+    this.type = type;
+  }
+
+  public function isStruct() : Bool {
+    return type == TType.STRUCT;
+  }
+
+  public function isContainer() : Bool {
+    return type == TType.LIST || type == TType.MAP || type == TType.SET;
+  }
+}
diff --git a/lib/haxe/src/org/apache/thrift/meta_data/ListMetaData.hx b/lib/haxe/src/org/apache/thrift/meta_data/ListMetaData.hx
new file mode 100644
index 0000000..40ca31b
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/meta_data/ListMetaData.hx
@@ -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 org.apache.thrift.meta_data;
+
+class ListMetaData extends FieldValueMetaData {
+
+    public var elemMetaData:FieldValueMetaData;
+
+    public function ListMetaData(type : Int, eMetaData:FieldValueMetaData) {
+      super(type);
+      this.elemMetaData = eMetaData;
+    }
+}
+ 
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/meta_data/MapMetaData.hx b/lib/haxe/src/org/apache/thrift/meta_data/MapMetaData.hx
new file mode 100644
index 0000000..5463e62
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/meta_data/MapMetaData.hx
@@ -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 org.apache.thrift.meta_data;
+
+class MapMetaData extends FieldValueMetaData {
+
+    public var keyMetaData:FieldValueMetaData;
+    public var valueMetaData:FieldValueMetaData;
+
+    public function MapMetaData(type : Int, kMetaData:FieldValueMetaData, vMetaData:FieldValueMetaData) {
+      super(type);
+      this.keyMetaData = kMetaData;
+      this.valueMetaData = vMetaData;
+    }
+}
+   
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/meta_data/SetMetaData.hx b/lib/haxe/src/org/apache/thrift/meta_data/SetMetaData.hx
new file mode 100644
index 0000000..a3367f4
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/meta_data/SetMetaData.hx
@@ -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 org.apache.thrift.meta_data;
+
+class SetMetaData extends FieldValueMetaData {
+
+    public var elemMetaData:FieldValueMetaData;
+
+    public function SetMetaData(type : Int, eMetaData:FieldValueMetaData) {
+      super(type);
+      this.elemMetaData = eMetaData;
+    }
+}
diff --git a/lib/haxe/src/org/apache/thrift/meta_data/StructMetaData.hx b/lib/haxe/src/org/apache/thrift/meta_data/StructMetaData.hx
new file mode 100644
index 0000000..1822dd3
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/meta_data/StructMetaData.hx
@@ -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 org.apache.thrift.meta_data;
+
+class StructMetaData extends FieldValueMetaData {
+
+    public var structClass:Class;
+
+    public function StructMetaData(type : Int, sClass:Class) {
+      super(type);
+      this.structClass = sClass;
+    }
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx
new file mode 100644
index 0000000..7ef291c
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx
@@ -0,0 +1,301 @@
+/*
+ * 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 org.apache.thrift.protocol;
+
+import haxe.io.Bytes;
+import haxe.io.BytesInput;
+import haxe.io.BytesOutput;
+import haxe.io.BytesBuffer;
+import haxe.Int64;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransport;
+
+/**
+* Binary protocol implementation for thrift.
+*/
+class TBinaryProtocol extends TRecursionTracker implements TProtocol {
+
+    private static var ANONYMOUS_STRUCT:TStruct = new TStruct();
+
+    private static inline var VERSION_MASK : haxe.Int32 = 0xffff0000;
+    private static inline var VERSION_1 : haxe.Int32 = 0x80010000;
+
+    private var strictRead_ : Bool = false;
+    private var strictWrite_ : Bool = true;
+    private var trans_ : TTransport;
+
+    /**
+     * Constructor
+     */
+    public function new(trans:TTransport, strictRead : Bool=false, strictWrite : Bool=true) {
+      trans_ = trans;
+      strictRead_ = strictRead;
+      strictWrite_ = strictWrite;
+    }
+
+    public function getTransport():TTransport {
+      return trans_;
+    }
+
+    public function writeMessageBegin(message:TMessage) : Void {
+        if (strictWrite_) {
+          var version : Int = VERSION_1 | message.type;
+          writeI32(version);
+          writeString(message.name);
+          writeI32(message.seqid);
+        } else {
+          writeString(message.name);
+          writeByte(message.type);
+          writeI32(message.seqid);
+        }
+    }
+
+    public function writeMessageEnd() : Void {}
+
+    public function writeStructBegin(struct:TStruct) : Void {}
+
+    public function writeStructEnd() : Void {}
+
+    public function writeFieldBegin(field:TField) : Void {
+      writeByte(field.type);
+      writeI16(field.id);
+    }
+
+    public function writeFieldEnd() : Void {}
+
+    public function writeFieldStop() : Void {
+      writeByte(TType.STOP);
+    }
+
+    public function writeMapBegin(map:TMap) : Void {
+      writeByte(map.keyType);
+      writeByte(map.valueType);
+      writeI32(map.size);
+    }
+
+    public function writeMapEnd() : Void {}
+
+    public function writeListBegin(list:TList) : Void {
+        writeByte(list.elemType);
+        writeI32(list.size);
+    }
+
+    public function writeListEnd() : Void {}
+
+    public function writeSetBegin(set:TSet) : Void {
+        writeByte(set.elemType);
+        writeI32(set.size);
+    }
+
+    public function writeSetEnd() : Void {}
+
+    public function writeBool(b : Bool) : Void {
+        writeByte(b ? 1 : 0);
+    }
+
+
+    public function writeByte(b : Int) : Void {
+        var out = new BytesOutput();
+        out.bigEndian = true;
+        out.writeByte(b);
+        trans_.write(out.getBytes(), 0, 1);
+    }
+
+    public function writeI16(i16 : Int) : Void {
+        var out = new BytesOutput();
+        out.bigEndian = true;
+        out.writeInt16(i16);
+        trans_.write(out.getBytes(), 0, 2);
+    }
+
+    public function writeI32(i32 : Int) : Void {
+        var out = new BytesOutput();
+        out.bigEndian = true;
+        out.writeInt32(i32);
+        trans_.write(out.getBytes(), 0, 4);
+    }
+
+    public function writeI64(i64 : haxe.Int64) : Void {
+        var out = new BytesOutput();
+        out.bigEndian = true;
+        #if( haxe_ver < 3.2)
+        var hi = Int64.getHigh(i64);
+        var lo = Int64.getLow(i64);
+        out.writeInt32(hi);
+        out.writeInt32(lo);
+        #else
+        out.writeInt32(i64.high);
+        out.writeInt32(i64.low);
+        #end
+        trans_.write(out.getBytes(), 0, 8);
+    }
+
+    public function writeDouble(dub:Float) : Void {
+        var out = new BytesOutput();
+        out.bigEndian = true;
+        out.writeDouble(dub);
+        trans_.write(out.getBytes(), 0, 8);
+    }
+
+    public function writeString(str : String) : Void {
+        var out = new BytesOutput();
+        out.bigEndian = true;
+        out.writeString(str);
+        var bytes = out.getBytes();
+        writeI32( bytes.length);
+        trans_.write( bytes, 0, bytes.length);
+    }
+
+    public function writeBinary(bin:Bytes) : Void {
+        writeI32(bin.length);
+        trans_.write(bin, 0, bin.length);
+    }
+
+    /**
+     * Reading methods.
+     */
+
+    public function readMessageBegin():TMessage {
+        var size : Int = readI32();
+        if (size < 0) {
+            var version : Int = size & VERSION_MASK;
+            if (version != VERSION_1) {
+                throw new TProtocolException(TProtocolException.BAD_VERSION, "Bad version in readMessageBegin");
+            }
+            return new TMessage(readString(), size & 0x000000ff, readI32());
+        } else {
+            if (strictRead_) {
+                throw new TProtocolException(TProtocolException.BAD_VERSION, "Missing version in readMessageBegin, old client?");
+            }
+            return new TMessage(readStringBody(size), readByte(), readI32());
+        }
+    }
+
+    public function readMessageEnd() : Void {}
+
+    public function readStructBegin():TStruct {
+        return ANONYMOUS_STRUCT;
+    }
+
+    public function readStructEnd() : Void {}
+
+    public function readFieldBegin() : TField {
+        var type : Int = readByte();
+        var id : Int = 0;
+        if (type != TType.STOP)
+        {
+            id = readI16();
+        }
+        return new TField("", type, id);
+    }
+
+    public function readFieldEnd() : Void {}
+
+    public function readMapBegin() : TMap {
+        return new TMap(readByte(), readByte(), readI32());
+    }
+
+    public function readMapEnd() : Void {}
+
+    public function readListBegin():TList {
+        return new TList(readByte(), readI32());
+    }
+
+    public function readListEnd() : Void {}
+
+    public function readSetBegin() : TSet {
+      return new TSet(readByte(), readI32());
+    }
+
+    public function readSetEnd() : Void {}
+
+    public function readBool() : Bool {
+        return (readByte() == 1);
+    }
+
+
+    public function readByte() : Int {
+        var buffer = new BytesBuffer();
+        var len = trans_.readAll( buffer, 0, 1);
+        var inp = new BytesInput( buffer.getBytes(), 0, 1);
+        inp.bigEndian = true;
+        return inp.readByte();
+    }
+
+    public function readI16() : Int {
+        var buffer = new BytesBuffer();
+        var len = trans_.readAll( buffer, 0, 2);
+        var inp = new BytesInput( buffer.getBytes(), 0, 2);
+        inp.bigEndian = true;
+        return inp.readInt16();
+    }
+
+    public function readI32() : Int {
+        var buffer = new BytesBuffer();
+        var len = trans_.readAll( buffer, 0, 4);
+        var inp = new BytesInput( buffer.getBytes(), 0, 4);
+        inp.bigEndian = true;
+        return inp.readInt32();
+    }
+
+    public function readI64() : haxe.Int64 {
+        var buffer = new BytesBuffer();
+        var len = trans_.readAll( buffer, 0, 8);
+        var inp = new BytesInput( buffer.getBytes(), 0, 8);
+        inp.bigEndian = true;
+        var hi = inp.readInt32();
+        var lo = inp.readInt32();
+        return Int64.make(hi,lo);
+    }
+
+    public function readDouble():Float {
+        var buffer = new BytesBuffer();
+        var len = trans_.readAll( buffer, 0, 8);
+        var inp = new BytesInput( buffer.getBytes(), 0, 8);
+        inp.bigEndian = true;
+        return inp.readDouble();
+    }
+
+    public function readString() : String {
+        return readStringBody( readI32());
+    }
+
+    public function readStringBody(len : Int) : String {
+        if( len > 0) {
+            var buffer = new BytesBuffer();
+            trans_.readAll( buffer, 0, len);
+            var inp = new BytesInput( buffer.getBytes(), 0, len);
+            inp.bigEndian = true;
+            return inp.readString(len);
+        } else {
+            return "";
+        }
+    }
+
+    public function readBinary() : Bytes {
+        var len : Int = readI32();
+        var buffer = new BytesBuffer();
+        trans_.readAll( buffer, 0, len);
+        return buffer.getBytes();
+    }
+
+}
+
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocolFactory.hx b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocolFactory.hx
new file mode 100644
index 0000000..f4a9bec
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocolFactory.hx
@@ -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 org.apache.thrift.protocol;
+
+import org.apache.thrift.transport.TTransport;
+
+
+/**
+* Binary Protocol Factory
+*/
+class TBinaryProtocolFactory implements TProtocolFactory {
+
+    private var strictRead_ : Bool = false;
+    private var strictWrite_ : Bool = true;
+
+    public function new( strictRead : Bool = false, strictWrite : Bool = true) {
+        strictRead_  = strictRead;
+        strictWrite_ = strictWrite;
+    }
+
+    public function getProtocol( trans : TTransport) : TProtocol  {
+        return new TBinaryProtocol( trans, strictRead_, strictWrite_);
+    }
+}
+
+
+
+    
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx
new file mode 100644
index 0000000..03b13e2
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx
@@ -0,0 +1,718 @@
+/**
+ * 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 org.apache.thrift.protocol;
+
+import haxe.io.Bytes;
+import haxe.io.BytesInput;
+import haxe.io.BytesOutput;
+import haxe.io.BytesBuffer;
+import haxe.ds.GenericStack;
+import haxe.Int32;
+import haxe.Int64;
+import haxe.Utf8;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.helper.ZigZag;
+import org.apache.thrift.helper.BitConverter;
+
+
+/**
+* Compact protocol implementation for thrift.
+*/
+class TCompactProtocol extends TRecursionTracker implements TProtocol {
+
+    private static var ANONYMOUS_STRUCT : TStruct = new TStruct("");
+    private static var TSTOP : TField = new TField("", TType.STOP, 0);
+
+    private static inline var PROTOCOL_ID : Int = 0x82;
+    private static inline var VERSION : Int = 1;
+    private static inline var VERSION_MASK : Int = 0x1f; // 0001 1111
+    private static inline var TYPE_MASK : Int = 0xE0; // 1110 0000
+    private static inline var TYPE_BITS : Int = 0x07; // 0000 0111
+    private static inline var TYPE_SHIFT_AMOUNT : Int = 5;
+
+
+    private static var ttypeToCompactType = [
+        TType.STOP    => TCompactTypes.STOP,
+        TType.BOOL    => TCompactTypes.BOOLEAN_TRUE,
+        TType.BYTE    => TCompactTypes.BYTE,
+        TType.DOUBLE  => TCompactTypes.DOUBLE,
+        TType.I16     => TCompactTypes.I16,
+        TType.I32     => TCompactTypes.I32,
+        TType.I64     => TCompactTypes.I64,
+        TType.STRING  => TCompactTypes.BINARY,
+        TType.STRUCT  => TCompactTypes.STRUCT,
+        TType.MAP     => TCompactTypes.MAP,
+        TType.SET     => TCompactTypes.SET,
+        TType.LIST    => TCompactTypes.LIST
+    ];
+
+    private static var tcompactTypeToType = [
+        TCompactTypes.STOP          => TType.STOP,
+        TCompactTypes.BOOLEAN_TRUE  => TType.BOOL,
+        TCompactTypes.BOOLEAN_FALSE => TType.BOOL,
+        TCompactTypes.BYTE          => TType.BYTE,
+        TCompactTypes.I16           => TType.I16,
+        TCompactTypes.I32           => TType.I32,
+        TCompactTypes.I64           => TType.I64,
+        TCompactTypes.DOUBLE        => TType.DOUBLE,
+        TCompactTypes.BINARY        => TType.STRING,
+        TCompactTypes.LIST          => TType.LIST,
+        TCompactTypes.SET           => TType.SET,
+        TCompactTypes.MAP           => TType.MAP,
+        TCompactTypes.STRUCT        => TType.STRUCT
+    ];
+
+
+    /**
+     * Used to keep track of the last field for the current and previous structs,
+     * so we can do the delta stuff.
+     */
+    private var lastField_ : GenericStack<Int> = new GenericStack<Int>();
+    private var lastFieldId_ : Int = 0;
+
+    /**
+     * If we encounter a boolean field begin, save the TField here so it can
+     * have the value incorporated.
+     */
+    private var booleanField_ : Null<TField>;
+
+    /**
+     * If we Read a field header, and it's a boolean field, save the boolean
+     * value here so that ReadBool can use it.
+     */
+    private var boolValue_ : Null<Bool>;
+
+
+    // whether the underlying system holds Strings as UTF-8
+    // http://old.haxe.org/manual/encoding
+    private static var utf8Strings = haxe.Utf8.validate("Ç-ß-Æ-Ю-Ш");
+
+    // the transport used
+    public var trans(default,null) : TTransport;
+
+
+    // TCompactProtocol Constructor
+    public function new( trans : TTransport) {
+        this.trans = trans;
+    }
+
+    public function getTransport() : TTransport {
+      return trans;
+    }
+
+
+    public function Reset() : Void{
+        while ( ! lastField_.isEmpty()) {
+            lastField_.pop();
+        }
+        lastFieldId_ = 0;
+    }
+
+
+    /**
+     * Writes a byte without any possibility of all that field header nonsense.
+     * Used internally by other writing methods that know they need to Write a byte.
+     */
+    private function WriteByteDirect( b : Int) : Void {
+        var buf = Bytes.alloc(1);
+        buf.set( 0, b);
+        trans.write( buf, 0, 1);
+    }
+
+    /**
+     * Write an i32 as a varint. Results in 1-5 bytes on the wire.
+     */
+    private function WriteVarint32( n : UInt) : Void {
+        var i32buf = new BytesBuffer();
+        while (true)
+        {
+            if ((n & ~0x7F) == 0)
+            {
+                i32buf.addByte( n & 0xFF);
+                break;
+            }
+            else
+            {
+                i32buf.addByte( (n & 0x7F) | 0x80);
+                n >>= 7;
+            }
+        }
+
+        var tmp = i32buf.getBytes();
+        trans.write( tmp, 0, tmp.length);
+    }
+
+    /**
+    * 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.
+    */
+    public function writeMessageBegin( message : TMessage) : Void {
+        Reset();
+
+        var versionAndType : Int =  (VERSION & VERSION_MASK) | ((message.type << TYPE_SHIFT_AMOUNT) & TYPE_MASK);
+        WriteByteDirect( PROTOCOL_ID);
+        WriteByteDirect( versionAndType);
+        WriteVarint32( cast( message.seqid, UInt));
+        writeString( message.name);
+    }
+
+    /**
+     * 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.
+     */
+    public function writeStructBegin(struct:TStruct) : Void {
+        lastField_.add( lastFieldId_);
+        lastFieldId_ = 0;
+    }
+
+    /**
+     * 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.
+     */
+    public function writeStructEnd() : Void {
+        lastFieldId_ = lastField_.pop();
+    }
+
+    /**
+     * Write a field header containing the field id and field type. If the
+     * difference between the current field id and the last one is small (< 15),
+     * then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
+     * field id will follow the type header as a zigzag varint.
+     */
+    public function writeFieldBegin(field:TField) : Void {
+        if (field.type == TType.BOOL)
+            booleanField_ = field; // we want to possibly include the value, so we'll wait.
+        else
+            WriteFieldBeginInternal(field, 0xFF);
+    }
+
+    /**
+     * 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.
+     */
+    private function WriteFieldBeginInternal( field : TField, typeOverride : Int) : Void {
+        // if there's a type override, use that.
+        var typeToWrite : Int;
+        if ( typeOverride == 0xFF)
+            typeToWrite = getCompactType( field.type);
+        else
+            typeToWrite = typeOverride;
+
+        // check if we can use delta encoding for the field id
+        if (field.id > lastFieldId_ && field.id - lastFieldId_ <= 15)
+        {
+            // Write them together
+            WriteByteDirect((field.id - lastFieldId_) << 4 | typeToWrite);
+        }
+        else
+        {
+            // Write them separate
+            WriteByteDirect(typeToWrite);
+            writeI16(field.id);
+        }
+
+        lastFieldId_ = field.id;
+    }
+
+    /**
+     * Write the STOP symbol so we know there are no more fields in this struct.
+     */
+    public function writeFieldStop() : Void {
+        WriteByteDirect( cast(TCompactTypes.STOP, Int));
+    }
+
+    /**
+     * Write a map header. If the map is empty, omit the key and value type
+     * headers, as we don't need any additional information to skip it.
+     */
+    public function writeMapBegin(map:TMap) : Void {
+        if (map.size == 0)
+        {
+            WriteByteDirect(0);
+        }
+        else
+        {
+            var kvtype = (getCompactType(map.keyType) << 4) | getCompactType(map.valueType);
+            WriteVarint32( cast( map.size, UInt));
+            WriteByteDirect( kvtype);
+        }
+    }
+
+    /**
+     * Write a list header.
+     */
+    public function writeListBegin( list : TList) : Void {
+        WriteCollectionBegin( list.elemType, list.size);
+    }
+
+    /**
+     * Write a set header.
+     */
+    public function writeSetBegin( set : TSet) : Void {
+        WriteCollectionBegin( set.elemType, set.size);
+    }
+
+    /**
+     * Write a boolean value. Potentially, this could be a boolean field, in
+     * which case the field header info isn't written yet. If so, decide what the
+     * right type header is for the value and then Write the field header.
+     * Otherwise, Write a single byte.
+     */
+    public function writeBool(b : Bool) : Void {
+        var bct : Int = b ? TCompactTypes.BOOLEAN_TRUE : TCompactTypes.BOOLEAN_FALSE;
+
+        if (booleanField_ != null)
+        {
+            // we haven't written the field header yet
+            WriteFieldBeginInternal( booleanField_, bct);
+            booleanField_ = null;
+        }
+        else
+        {
+            // we're not part of a field, so just Write the value.
+            WriteByteDirect( bct);
+        }
+    }
+
+    /**
+     * Write a byte. Nothing to see here!
+     */
+    public function writeByte( b : Int) : Void {
+        WriteByteDirect( b);
+    }
+
+    /**
+     * Write an I16 as a zigzag varint.
+     */
+    public function writeI16( i16 : Int) : Void {
+        WriteVarint32( ZigZag.FromInt( i16));
+    }
+
+    /**
+     * Write an i32 as a zigzag varint.
+     */
+    public function writeI32( i32 : Int) : Void {
+        WriteVarint32( ZigZag.FromInt( i32));
+    }
+
+    /**
+     * Write an i64 as a zigzag varint.
+     */
+    public function writeI64( i64 : haxe.Int64) : Void {
+        WriteVarint64(  ZigZag.FromLong( i64));
+    }
+
+    /**
+     * Write a double to the wire as 8 bytes.
+     */
+    public function writeDouble( dub : Float) : Void {
+        var data = BitConverter.fixedLongToBytes( BitConverter.DoubleToInt64Bits(dub));
+        trans.write( data, 0, data.length);
+    }
+
+    /**
+     * Write a string to the wire with a varint size preceding.
+     */
+    public function writeString(str : String) : Void {
+        var buf = new BytesBuffer();
+        if( utf8Strings)
+            buf.addString( str);  // no need to encode on UTF8 targets, the string is just fine
+        else
+            buf.addString( Utf8.encode( str));
+        var tmp = buf.getBytes();
+        writeBinary( tmp);
+    }
+
+    /**
+     * Write a byte array, using a varint for the size.
+     */
+    public function writeBinary( bin : Bytes) : Void {
+        WriteVarint32( cast(bin.length,UInt));
+        trans.write( bin, 0, bin.length);
+    }
+
+
+    // These methods are called by structs, but don't actually have any wire
+    // output or purpose.
+    public function writeMessageEnd() : Void { }
+    public function writeMapEnd() : Void { }
+    public function writeListEnd() : Void { }
+    public function writeSetEnd() : Void { }
+    public function writeFieldEnd() : Void { }
+
+    //
+    // 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.
+     */
+    private function WriteCollectionBegin( elemType : Int, size : Int) : Void {
+        if (size <= 14)    {
+            WriteByteDirect( size << 4 | getCompactType(elemType));
+        }
+        else {
+            WriteByteDirect( 0xf0 | getCompactType(elemType));
+            WriteVarint32( cast(size, UInt));
+        }
+    }
+
+    /**
+     * Write an i64 as a varint. Results in 1-10 bytes on the wire.
+     */
+    private function WriteVarint64(n : haxe.Int64) : Void    {
+        var varint64out = new BytesBuffer();
+        while (true)
+        {
+            if( Int64.isZero( Int64.and( n, Int64.neg(Int64.make(0,0x7F)))))
+            {
+                #if( haxe_ver < 3.2)
+                varint64out.addByte( Int64.getLow(n));
+                #else
+                varint64out.addByte( n.low);
+                #end
+                break;
+            }
+            else
+            {
+                #if ( haxe_ver < 3.2)
+                varint64out.addByte( (Int64.getLow(n) & 0x7F) | 0x80);
+                #else
+                varint64out.addByte( (n.low & 0x7F) | 0x80);
+                #end
+                n = Int64.shr( n, 7);
+                n = Int64.and( n, Int64.make(0x01FFFFFF,0xFFFFFFFF));  // clean out the shifted 7 bits
+            }
+        }
+        var tmp = varint64out.getBytes();
+        trans.write( tmp, 0, tmp.length);
+    }
+
+
+    /**
+     * Read a message header.
+     */
+    public function readMessageBegin():TMessage {
+        Reset();
+
+        var protocolId : Int = readByte();
+        if (protocolId != PROTOCOL_ID) {
+            throw new TProtocolException( TProtocolException.INVALID_DATA, "Expected protocol id " + StringTools.hex(PROTOCOL_ID,2) + " but got " + StringTools.hex(protocolId));
+        }
+
+        var versionAndType : Int = readByte();
+        var version : Int = (versionAndType & VERSION_MASK);
+        if (version != VERSION) {
+            throw new TProtocolException( TProtocolException.INVALID_DATA, "Expected version " + VERSION + " but got " + version);
+        }
+
+        var type : Int = ((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
+        var seqid : Int = cast( ReadVarint32(), Int);
+        var msgNm : String = readString();
+        return new TMessage( msgNm, type, seqid);
+    }
+
+    /**
+     * 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.
+     */
+    public function readStructBegin():TStruct {
+        lastField_.add(lastFieldId_);
+        lastFieldId_ = 0;
+        return ANONYMOUS_STRUCT;
+    }
+
+    /**
+     * Doesn't actually consume any wire data, just removes the last field for
+     * this struct from the field stack.
+     */
+    public function readStructEnd() : Void {
+        // consume the last field we Read off the wire.
+        lastFieldId_ = lastField_.pop();
+    }
+
+    /**
+     * Read a field header off the wire.
+     */
+    public function readFieldBegin() : TField {
+        var type : Int = readByte();
+
+        // if it's a stop, then we can return immediately, as the struct is over.
+        if (type == cast(TCompactTypes.STOP,Int)) {
+            return TSTOP;
+        }
+
+        var fieldId : Int;
+
+        // mask off the 4 MSB of the type header. it could contain a field id delta.
+        var modifier : Int = ((type & 0xf0) >> 4);
+        if (modifier == 0)
+            fieldId = readI16();  // not a delta. look ahead for the zigzag varint field id.
+        else
+            fieldId = lastFieldId_ + modifier; // add the delta to the last Read field id.
+
+        var field : TField  = new TField( "", cast(getTType(type & 0x0f),Int), fieldId);
+
+        // if this happens to be a boolean field, the value is encoded in the type
+        if (isBoolType(type)) {
+            // save the boolean value in a special instance variable.
+            boolValue_ = ((type & 0x0f) == cast(TCompactTypes.BOOLEAN_TRUE,Int));
+        }
+
+        // push the new field onto the field stack so we can keep the deltas going.
+        lastFieldId_ = field.id;
+        return field;
+    }
+
+    /**
+     * 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.
+     */
+    public function readMapBegin() : TMap {
+        var size : Int = cast( ReadVarint32(), Int);
+        var keyAndValueType : Int = ((size == 0)  ?  0  :  readByte());
+        var key : Int = cast( getTType( (keyAndValueType & 0xF0) >> 4), Int);
+        var val : Int = cast( getTType( keyAndValueType & 0x0F), Int);
+        return new TMap( key, val, size);
+    }
+
+    /**
+     * 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.
+     */
+    public function readListBegin():TList {
+        var size_and_type : Int = readByte();
+
+        var size : Int = ((size_and_type & 0xF0) >> 4) & 0x0F;
+        if (size == 15) {
+            size = cast( ReadVarint32(), Int);
+        }
+
+        var type = getTType(size_and_type);
+        return new TList( type, size);
+    }
+
+    /**
+     * 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.
+     */
+    public function readSetBegin() : TSet {
+        var size_and_type : Int = readByte();
+
+        var size : Int = ((size_and_type & 0xF0) >> 4) & 0x0F;
+        if (size == 15) {
+            size = cast( ReadVarint32(), Int);
+        }
+
+        var type = getTType(size_and_type);
+        return new TSet( type, size);
+    }
+
+    /**
+     * 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.
+     */
+    public function readBool() : Bool {
+        if (boolValue_ != null) {
+            var result : Bool = boolValue_;
+            boolValue_ = null;
+            return result;
+        }
+
+        return (readByte() == cast(TCompactTypes.BOOLEAN_TRUE,Int));
+    }
+
+    /**
+     * Read a single byte off the wire. Nothing interesting here.
+     */
+    public function readByte() : Int {
+        var byteRawBuf = new BytesBuffer();
+        trans.readAll( byteRawBuf, 0, 1);
+        return byteRawBuf.getBytes().get(0);
+    }
+
+    /**
+     * Read an i16 from the wire as a zigzag varint.
+     */
+    public function readI16() : Int {
+        return ZigZag.ToInt( ReadVarint32());
+    }
+
+    /**
+     * Read an i32 from the wire as a zigzag varint.
+     */
+    public function readI32() : Int {
+        return ZigZag.ToInt( ReadVarint32());
+    }
+
+    /**
+     * Read an i64 from the wire as a zigzag varint.
+     */
+    public function readI64() : haxe.Int64 {
+        return ZigZag.ToLong( ReadVarint64());
+    }
+
+    /**
+     * No magic here - just Read a double off the wire.
+     */
+    public function readDouble():Float {
+        var longBits = new BytesBuffer();
+        trans.readAll( longBits, 0, 8);
+        return BitConverter.Int64BitsToDouble( BitConverter.bytesToLong( longBits.getBytes()));
+    }
+
+    /**
+     * Reads a byte[] (via ReadBinary), and then UTF-8 decodes it.
+     */
+    public function readString() : String {
+        var length : Int = cast( ReadVarint32(), Int);
+
+        if (length == 0) {
+            return "";
+        }
+
+        var buf = new BytesBuffer();
+        trans.readAll( buf, 0, length);
+
+        length = buf.length;
+        var inp = new BytesInput( buf.getBytes());
+        var str = inp.readString( length);
+        if( utf8Strings)
+            return str;  // no need to decode on UTF8 targets, the string is just fine
+        else
+            return Utf8.decode( str);
+    }
+
+    /**
+     * Read a byte[] from the wire.
+     */
+    public function readBinary() : Bytes {
+        var length : Int = cast( ReadVarint32(), Int);
+        if (length == 0) {
+            return Bytes.alloc(0);
+        }
+
+        var buf = new BytesBuffer();
+        trans.readAll( buf, 0, length);
+        return buf.getBytes();
+    }
+
+
+    // These methods are here for the struct to call, but don't have any wire
+    // encoding.
+    public function readMessageEnd() : Void { }
+    public function readFieldEnd() : Void { }
+    public function readMapEnd() : Void { }
+    public function readListEnd() : Void { }
+    public function readSetEnd() : Void { }
+
+    //
+    // 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.
+     */
+    private function ReadVarint32() : UInt {
+        var result : UInt = 0;
+        var shift : Int = 0;
+        while (true) {
+            var b : Int = readByte();
+            result |= cast((b & 0x7f) << shift, UInt);
+            if ((b & 0x80) != 0x80) {
+                break;
+            }
+            shift += 7;
+        }
+        return result;
+    }
+
+    /**
+     * 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.
+     */
+    private function ReadVarint64() : Int64 {
+        var shift : Int = 0;
+        var result : Int64 = Int64.make(0,0);
+        while (true) {
+            var b : Int = readByte();
+            result = Int64.or( result, Int64.shl( Int64.make(0,b & 0x7f), shift));
+            if ((b & 0x80) != 0x80) {
+                break;
+            }
+            shift += 7;
+        }
+
+        return result;
+    }
+
+
+    //
+    // type testing and converting
+    //
+
+    private function isBoolType( b : Int) : Bool {
+        var lowerNibble : Int = b & 0x0f;
+        switch(lowerNibble)
+        {
+            case TCompactTypes.BOOLEAN_TRUE: return true;
+            case TCompactTypes.BOOLEAN_FALSE: return true;
+            default: return false;
+        }
+    }
+
+
+    /**
+     * Given a TCompactProtocol.TCompactTypes constant, convert it to its corresponding
+     * TType value.
+     */
+    private function getTType( type : Int) : Int {
+        try
+        {
+            return tcompactTypeToType[type];
+        }
+        catch ( e : Dynamic)
+        {
+            var tt : Int = (type & 0x0f);
+            throw new TProtocolException( TProtocolException.UNKNOWN, 'don\'t know what type: $tt ($e)');
+        }
+    }
+
+    /**
+     * Given a TType value, find the appropriate TCompactProtocol.TCompactTypes constant.
+     */
+    private function getCompactType( ttype : Int) : Int
+    {
+        return cast( ttypeToCompactType[ttype], Int);
+    }
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocolFactory.hx b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocolFactory.hx
new file mode 100644
index 0000000..c5673b4
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocolFactory.hx
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+import org.apache.thrift.transport.TTransport;
+
+
+/**
+* Compact Protocol Factory
+*/
+class TCompactProtocolFactory implements TProtocolFactory {
+
+    public function new() {
+    }
+
+    public function getProtocol( trans : TTransport) : TProtocol  {
+        return new TCompactProtocol( trans);
+    }
+}
+
+
+
+    
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TCompactTypes.hx b/lib/haxe/src/org/apache/thrift/protocol/TCompactTypes.hx
new file mode 100644
index 0000000..cdd3d87
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TCompactTypes.hx
@@ -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 org.apache.thrift.protocol;
+
+/**
+ * All of the on-wire type codes.
+ */
+@:enum
+abstract TCompactTypes(Int)  from Int to Int  {
+    public static inline var STOP          = 0x00;
+    public static inline var BOOLEAN_TRUE  = 0x01;
+    public static inline var BOOLEAN_FALSE = 0x02;
+    public static inline var BYTE          = 0x03;
+    public static inline var I16           = 0x04;
+    public static inline var I32           = 0x05;
+    public static inline var I64           = 0x06;
+    public static inline var DOUBLE        = 0x07;
+    public static inline var BINARY        = 0x08;
+    public static inline var LIST          = 0x09;
+    public static inline var SET           = 0x0A;
+    public static inline var MAP           = 0x0B;
+    public static inline var STRUCT        = 0x0C;
+}
+
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TField.hx b/lib/haxe/src/org/apache/thrift/protocol/TField.hx
new file mode 100644
index 0000000..3f5498d
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TField.hx
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.thrift.protocol;
+
+class TField {
+
+    public var name : String;
+    public var type : Int;
+    public var id : Int;
+
+    public function new(n : String = "", t : Int = 0, i : Int = 0) {
+      name = n;
+      type = t;
+      id = i;
+    }
+
+    public function toString() : String {
+      return '<TField name:"$name" type:"$type" field-id:"$id">';
+    }
+
+    public function equals( otherField : TField) : Bool {
+      return (type == otherField.type)
+          && (id == otherField.id);
+    }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx
new file mode 100644
index 0000000..e20ff33
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx
@@ -0,0 +1,1073 @@
+/*
+ * 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 org.apache.thrift.protocol;
+
+import haxe.io.Bytes;
+import haxe.io.BytesInput;
+import haxe.io.BytesOutput;
+import haxe.io.BytesBuffer;
+import haxe.ds.GenericStack;
+import haxe.Utf8;
+import haxe.crypto.Base64;
+import haxe.Int64;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TMessage;
+import org.apache.thrift.protocol.TField;
+import org.apache.thrift.protocol.TMap;
+import org.apache.thrift.protocol.TSet;
+import org.apache.thrift.protocol.TList;
+import org.apache.thrift.transport.TTransport;
+
+
+
+/* JSON protocol implementation for thrift.
+*  This is a full-featured protocol supporting Write and Read.
+*
+*  Please see the C++ class header for a detailed description of the wire format.
+*
+*  Adapted from the Java version.
+*/
+class TJSONProtocol extends TRecursionTracker implements TProtocol {
+
+    public var trans(default,null) : TTransport;
+
+    // Stack of nested contexts that we may be in
+    private var contextStack : GenericStack<JSONBaseContext> = new GenericStack<JSONBaseContext>();
+
+    // Current context that we are in
+    private var context : JSONBaseContext;
+
+    // Reader that manages a 1-byte buffer
+    private var reader : LookaheadReader;
+
+    // whether the underlying system holds Strings as UTF-8
+    // http://old.haxe.org/manual/encoding
+    private static var utf8Strings = haxe.Utf8.validate("Ç-ß-Æ-Ю-Ш");
+
+    // TJSONProtocol Constructor
+    public function new( trans : TTransport)
+    {
+        this.trans = trans;
+        this.context = new JSONBaseContext(this);
+        this.reader = new LookaheadReader(this);
+    }
+
+    public function getTransport() : TTransport {
+      return trans;
+    }
+
+    public function writeMessageBegin(message:TMessage) : Void {
+        WriteJSONArrayStart();
+        WriteJSONInteger( JSONConstants.VERSION);
+        WriteJSONString( BytesFromString(message.name));
+        WriteJSONInteger( message.type);
+        WriteJSONInteger( message.seqid);
+    }
+
+    public function writeMessageEnd() : Void {
+        WriteJSONArrayEnd();
+    }
+
+    public function writeStructBegin(struct:TStruct) : Void {
+        WriteJSONObjectStart();
+    }
+
+    public function writeStructEnd() : Void {
+        WriteJSONObjectEnd();
+    }
+
+    public function writeFieldBegin(field:TField) : Void {
+        WriteJSONInteger( field.id );
+        WriteJSONObjectStart();
+        WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( field.type)));
+    }
+
+    public function writeFieldEnd() : Void {
+        WriteJSONObjectEnd();
+    }
+
+    public function writeFieldStop() : Void { }
+
+    public function writeMapBegin(map:TMap) : Void {
+        WriteJSONArrayStart();
+        WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( map.keyType)));
+        WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( map.valueType)));
+        WriteJSONInteger( map.size);
+        WriteJSONObjectStart();
+    }
+
+    public function writeMapEnd() : Void {
+        WriteJSONObjectEnd();
+        WriteJSONArrayEnd();
+    }
+
+    public function writeListBegin(list:TList) : Void {
+        WriteJSONArrayStart();
+        WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( list.elemType )));
+        WriteJSONInteger( list.size);
+    }
+
+    public function writeListEnd() : Void {
+        WriteJSONArrayEnd();
+    }
+
+    public function writeSetBegin(set:TSet) : Void {
+        WriteJSONArrayStart();
+        WriteJSONString( BytesFromString( JSONConstants.GetTypeNameForTypeID( set.elemType)));
+        WriteJSONInteger( set.size);
+    }
+
+    public function writeSetEnd() : Void {
+        WriteJSONArrayEnd();
+    }
+
+    public function writeBool(b : Bool) : Void {
+        if( b)
+            WriteJSONInteger( 1);
+        else
+            WriteJSONInteger( 0);
+    }
+
+    public function writeByte(b : Int) : Void {
+        WriteJSONInteger( b);
+    }
+
+    public function writeI16(i16 : Int) : Void {
+        WriteJSONInteger( i16);
+    }
+
+    public function writeI32(i32 : Int) : Void {
+        WriteJSONInteger( i32);
+    }
+
+    public function writeI64(i64 : haxe.Int64) : Void {
+        WriteJSONInt64( i64);
+    }
+
+    public function writeDouble(dub:Float) : Void {
+        WriteJSONDouble(dub);
+    }
+
+    public function writeString(str : String) : Void {
+        WriteJSONString( BytesFromString(str));
+    }
+
+    public function writeBinary(bin:Bytes) : Void {
+        WriteJSONBase64(bin);
+    }
+
+    public function readMessageBegin():TMessage {
+        var message : TMessage = new TMessage();
+        ReadJSONArrayStart();
+        if (ReadJSONInteger() != JSONConstants.VERSION)
+        {
+            throw new TProtocolException(TProtocolException.BAD_VERSION,
+                                         "Message contained bad version.");
+        }
+
+        message.name = ReadJSONString(false);
+        message.type = ReadJSONInteger();
+        message.seqid = ReadJSONInteger();
+        return message;
+    }
+
+    public function readMessageEnd() : Void {
+        ReadJSONArrayEnd();
+    }
+
+    public function readStructBegin():TStruct {
+        ReadJSONObjectStart();
+        return new TStruct();
+    }
+
+    public function readStructEnd() : Void {
+        ReadJSONObjectEnd();
+    }
+
+    public function readFieldBegin() : TField {
+        var field : TField = new TField();
+        var ch = reader.Peek();
+        if (StringFromBytes(ch) == JSONConstants.RBRACE)
+        {
+            field.type = TType.STOP;
+        }
+        else
+        {
+            field.id = ReadJSONInteger();
+            ReadJSONObjectStart();
+            field.type = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false));
+        }
+        return field;
+    }
+
+    public function readFieldEnd() : Void {
+        ReadJSONObjectEnd();
+    }
+
+    public function readMapBegin() : TMap {
+        ReadJSONArrayStart();
+        var KeyType = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false));
+        var ValueType = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false));
+        var Count : Int = ReadJSONInteger();
+        ReadJSONObjectStart();
+
+        var map = new TMap( KeyType, ValueType, Count);
+        return map;
+    }
+
+    public function readMapEnd() : Void {
+        ReadJSONObjectEnd();
+        ReadJSONArrayEnd();
+    }
+
+    public function readListBegin():TList {
+        ReadJSONArrayStart();
+        var ElementType = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false));
+        var Count : Int = ReadJSONInteger();
+
+        var list = new TList( ElementType, Count);
+        return list;
+    }
+
+    public function readListEnd() : Void {
+        ReadJSONArrayEnd();
+    }
+
+    public function readSetBegin() : TSet {
+        ReadJSONArrayStart();
+        var ElementType = JSONConstants.GetTypeIDForTypeName( ReadJSONString(false));
+        var Count : Int = ReadJSONInteger();
+
+        var set = new TSet( ElementType, Count);
+        return set;
+    }
+
+    public function readSetEnd() : Void {
+        ReadJSONArrayEnd();
+    }
+
+    public function readBool() : Bool {
+        return (ReadJSONInteger() != 0);
+    }
+
+    public function readByte() : Int {
+        return ReadJSONInteger();
+    }
+
+    public function readI16() : Int {
+        return ReadJSONInteger();
+    }
+
+    public function readI32() : Int {
+        return ReadJSONInteger();
+    }
+
+    public function readI64() : haxe.Int64 {
+        return ReadJSONInt64();
+    }
+
+    public function readDouble():Float {
+        return ReadJSONDouble();
+    }
+
+    public function readString() : String {
+        return ReadJSONString(false);
+    }
+
+    public function readBinary() : Bytes {
+        return ReadJSONBase64();
+    }
+
+    // Push a new JSON context onto the stack.
+    private function  PushContext(c : JSONBaseContext) : Void {
+        contextStack.add(context);
+        context = c;
+    }
+
+    // Pop the last JSON context off the stack
+    private function  PopContext() : Void {
+        context = contextStack.pop();
+    }
+
+
+    // Write the bytes in array buf as a JSON characters, escaping as needed
+    private function WriteJSONString( b : Bytes) : Void {
+        context.Write();
+
+        var tmp = BytesFromString( JSONConstants.QUOTE);
+        trans.write( tmp, 0, tmp.length);
+
+        for (i in 0 ... b.length) {
+            var value = b.get(i);
+
+            if ((value & 0x00FF) >= 0x30)
+            {
+                if (String.fromCharCode(value) == JSONConstants.BACKSLASH.charAt(0))
+                {
+                    tmp = BytesFromString( JSONConstants.BACKSLASH + JSONConstants.BACKSLASH);
+                    trans.write( tmp, 0, tmp.length);
+                }
+                else
+                {
+                    trans.write( b, i, 1);
+                }
+            }
+            else
+            {
+                var num = JSONConstants.JSON_CHAR_TABLE[value];
+                if (num == 1)
+                {
+                    trans.write( b, i, 1);
+                }
+                else if (num > 1)
+                {
+                    var buf = new BytesBuffer();
+                    buf.addString( JSONConstants.BACKSLASH);
+                    buf.addByte( num);
+                    tmp = buf.getBytes();
+                    trans.write( tmp, 0, tmp.length);
+                }
+                else
+                {
+                    var buf = new BytesBuffer();
+                    buf.addString( JSONConstants.ESCSEQ);
+                    buf.addString( HexChar( (value & 0xFF000000) >> 12));
+                    buf.addString( HexChar( (value & 0x00FF0000) >> 8));
+                    buf.addString( HexChar( (value & 0x0000FF00) >> 4));
+                    buf.addString( HexChar( value & 0x000000FF));
+                    tmp = buf.getBytes();
+                    trans.write( tmp, 0, tmp.length);
+                }
+            }
+        }
+
+        tmp = BytesFromString( JSONConstants.QUOTE);
+        trans.write( tmp, 0, tmp.length);
+    }
+
+    // Write out number as a JSON value. If the context dictates so,
+    // it will be wrapped in quotes to output as a JSON string.
+    private function WriteJSONInteger( num : Int) : Void {
+        context.Write();
+
+        var str : String = "";
+        var escapeNum : Bool = context.EscapeNumbers();
+
+        if (escapeNum) {
+            str += JSONConstants.QUOTE;
+        }
+
+        str += Std.string(num);
+
+        if (escapeNum) {
+            str += JSONConstants.QUOTE;
+        }
+
+        var tmp = BytesFromString( str);
+        trans.write( tmp, 0, tmp.length);
+    }
+
+    // Write out number as a JSON value. If the context dictates so,
+    // it will be wrapped in quotes to output as a JSON string.
+    private function WriteJSONInt64( num : Int64) : Void {
+        context.Write();
+
+        var str : String = "";
+        var escapeNum : Bool = context.EscapeNumbers();
+
+        if (escapeNum) {
+            str += JSONConstants.QUOTE;
+        }
+
+        str += Std.string(num);
+
+        if (escapeNum) {
+            str += JSONConstants.QUOTE;
+        }
+
+        var tmp = BytesFromString( str);
+        trans.write( tmp, 0, tmp.length);
+    }
+
+    // Write out a double as a JSON value. If it is NaN or infinity or if the
+    // context dictates escaping, Write out as JSON string.
+    private function WriteJSONDouble(num : Float) : Void {
+        context.Write();
+
+
+        var special : Bool = false;
+        var rendered : String = "";
+        if( Math.isNaN(num)) {
+            special = true;
+            rendered = JSONConstants.FLOAT_IS_NAN;
+        } else if (! Math.isFinite(num)) {
+            special = true;
+            if( num > 0) {
+                rendered = JSONConstants.FLOAT_IS_POS_INF;
+            } else {
+                rendered = JSONConstants.FLOAT_IS_NEG_INF;
+            }
+        } else {
+            rendered = Std.string(num);  // plain and simple float number
+        }
+
+        // compose output
+        var escapeNum : Bool = special || context.EscapeNumbers();
+        var str : String = "";
+        if (escapeNum) {
+            str += JSONConstants.QUOTE;
+        }
+        str += rendered;
+        if (escapeNum) {
+            str += JSONConstants.QUOTE;
+        }
+
+        var tmp = BytesFromString( str);
+        trans.write( tmp, 0, tmp.length);
+    }
+
+    // Write out contents of byte array b as a JSON string with base-64 encoded data
+    private function WriteJSONBase64( b : Bytes) : Void {
+        context.Write();
+
+        var buf = new BytesBuffer();
+        buf.addString( JSONConstants.QUOTE);
+        buf.addString( Base64.encode(b));
+        buf.addString( JSONConstants.QUOTE);
+
+        var tmp = buf.getBytes();
+        trans.write( tmp, 0, tmp.length);
+    }
+
+    private function WriteJSONObjectStart() : Void {
+        context.Write();
+        var tmp = BytesFromString( JSONConstants.LBRACE);
+        trans.write( tmp, 0, tmp.length);
+        PushContext( new JSONPairContext(this));
+    }
+
+    private function WriteJSONObjectEnd() : Void {
+        PopContext();
+        var tmp = BytesFromString( JSONConstants.RBRACE);
+        trans.write( tmp, 0, tmp.length);
+    }
+
+    private function WriteJSONArrayStart() : Void {
+        context.Write();
+        var tmp = BytesFromString( JSONConstants.LBRACKET);
+        trans.write( tmp, 0, tmp.length);
+        PushContext( new JSONListContext(this));
+    }
+
+    private function WriteJSONArrayEnd() : Void {
+        PopContext();
+        var tmp = BytesFromString( JSONConstants.RBRACKET);
+        trans.write( tmp, 0, tmp.length);
+    }
+
+
+    /**
+     * Reading methods.
+     */
+
+    // Read a byte that must match char, otherwise an exception is thrown.
+    public function ReadJSONSyntaxChar( char : String) : Void {
+        var b = BytesFromString( char);
+
+        var ch = reader.Read();
+        if (ch.get(0) != b.get(0))
+        {
+            throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                         'Unexpected character: $ch');
+        }
+    }
+
+    // Read in a JSON string, unescaping as appropriate.
+    // Skip Reading from the context if skipContext is true.
+    private function ReadJSONString(skipContext : Bool) : String
+    {
+        if (!skipContext)
+        {
+            context.Read();
+        }
+
+        var buffer : BytesBuffer = new BytesBuffer();
+
+        ReadJSONSyntaxChar( JSONConstants.QUOTE);
+        while (true)
+        {
+            var ch = reader.Read();
+
+            // end of string?
+            if (StringFromBytes(ch) == JSONConstants.QUOTE)
+            {
+                break;
+            }
+
+            // escaped?
+            if (StringFromBytes(ch) != JSONConstants.ESCSEQ.charAt(0))
+            {
+                buffer.addByte( ch.get(0));
+                continue;
+            }
+
+            // distinguish between \uXXXX (hex unicode) and \X (control chars)
+            ch = reader.Read();
+            if (StringFromBytes(ch) != JSONConstants.ESCSEQ.charAt(1))
+            {
+                var value = JSONConstants.ESCAPE_CHARS_TO_VALUES[ch.get(0)];
+                if( value == null)
+                {
+                    throw new TProtocolException( TProtocolException.INVALID_DATA, "Expected control char");
+                }
+                buffer.addByte( value);
+                continue;
+            }
+
+
+            // it's \uXXXX
+            var hexbuf = new BytesBuffer();
+            var hexlen = trans.readAll( hexbuf, 0, 4);
+            if( hexlen != 4)
+            {
+                throw new TProtocolException( TProtocolException.INVALID_DATA, "Not enough data for \\uNNNN sequence");
+            }
+
+            var hexdigits = hexbuf.getBytes();
+            var charcode = 0;
+            charcode = (charcode << 4) + HexVal( String.fromCharCode(hexdigits.get(0)));
+            charcode = (charcode << 4) + HexVal( String.fromCharCode(hexdigits.get(1)));
+            charcode = (charcode << 4) + HexVal( String.fromCharCode(hexdigits.get(2)));
+            charcode = (charcode << 4) + HexVal( String.fromCharCode(hexdigits.get(3)));
+            buffer.addString( String.fromCharCode(charcode));
+        }
+
+        return StringFromBytes( buffer.getBytes());
+    }
+
+    // Return true if the given byte could be a valid part of a JSON number.
+    private function IsJSONNumeric(b : Int) : Bool {
+        switch (b)
+        {
+            case "+".code:  return true;
+            case "-".code:  return true;
+            case ".".code:  return true;
+            case "0".code:  return true;
+            case "1".code:  return true;
+            case "2".code:  return true;
+            case "3".code:  return true;
+            case "4".code:  return true;
+            case "5".code:  return true;
+            case "6".code:  return true;
+            case "7".code:  return true;
+            case "8".code:  return true;
+            case "9".code:  return true;
+            case "E".code:  return true;
+            case "e".code:  return true;
+        }
+        return false;
+    }
+
+    // Read in a sequence of characters that are all valid in JSON numbers. Does
+    // not do a complete regex check to validate that this is actually a number.
+    private function ReadJSONNumericChars() : String
+    {
+        var buffer : BytesBuffer = new BytesBuffer();
+        while (true)
+        {
+            var ch = reader.Peek();
+            if( ! IsJSONNumeric( ch.get(0)))
+            {
+                break;
+            }
+            buffer.addByte( reader.Read().get(0));
+        }
+        return StringFromBytes( buffer.getBytes());
+    }
+
+    // Read in a JSON number. If the context dictates, Read in enclosing quotes.
+    private function ReadJSONInteger() : Int {
+        context.Read();
+
+        if (context.EscapeNumbers()) {
+            ReadJSONSyntaxChar( JSONConstants.QUOTE);
+        }
+
+        var str : String = ReadJSONNumericChars();
+
+        if (context.EscapeNumbers()) {
+            ReadJSONSyntaxChar( JSONConstants.QUOTE);
+        }
+
+        var value = Std.parseInt(str);
+        if( value == null) {
+            throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
+        }
+
+        return value;
+    }
+
+    // Read in a JSON number. If the context dictates, Read in enclosing quotes.
+    private function ReadJSONInt64() : haxe.Int64 {
+        context.Read();
+
+        if (context.EscapeNumbers()) {
+            ReadJSONSyntaxChar( JSONConstants.QUOTE);
+        }
+
+        var str : String = ReadJSONNumericChars();
+        if( str.length == 0) {
+            throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
+        }
+
+        if (context.EscapeNumbers()) {
+            ReadJSONSyntaxChar( JSONConstants.QUOTE);
+        }
+
+        // process sign
+        var bMinus = false;
+        var startAt = 0;
+        if( (str.charAt(0) == "+") || (str.charAt(0) == "-")) {
+            bMinus = (str.charAt(0) == "-");
+            startAt++;
+        }
+
+        // process digits
+        var value : Int64 = Int64.make(0,0);
+        var bGotDigits = false;
+        for( i in startAt ... str.length) {
+            var ch = str.charAt(i);
+            var digit = JSONConstants.DECIMAL_DIGITS[ch];
+            if( digit == null) {
+                throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
+            }
+            bGotDigits = true;
+
+            // these are decimal digits
+            value = Int64.mul( value, Int64.make(0,10));
+            value = Int64.add( value, Int64.make(0,digit));
+        }
+
+        // process pending minus sign, if applicable
+        // this should also handle the edge case MIN_INT64 correctly
+        if( bMinus && (Int64.compare(value,Int64.make(0,0)) > 0)) {
+            value = Int64.neg( value);
+            bMinus = false;
+        }
+
+        if( ! bGotDigits) {
+            throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
+        }
+
+        return value;
+    }
+
+    // Read in a JSON double value. Throw if the value is not wrapped in quotes
+    // when expected or if wrapped in quotes when not expected.
+    private function ReadJSONDouble() : Float {
+        context.Read();
+
+        var str : String = "";
+        if (StringFromBytes(reader.Peek()) == JSONConstants.QUOTE) {
+            str = ReadJSONString(true);
+
+            // special cases
+            if( str == JSONConstants.FLOAT_IS_NAN) {
+                return Math.NaN;
+            }
+            if( str == JSONConstants.FLOAT_IS_POS_INF) {
+                return Math.POSITIVE_INFINITY;
+            }
+            if( str == JSONConstants.FLOAT_IS_NEG_INF) {
+                return Math.NEGATIVE_INFINITY;
+            }
+
+            if( ! context.EscapeNumbers())    {
+                // throw - we should not be in a string in this case
+                throw new TProtocolException(TProtocolException.INVALID_DATA, "Numeric data unexpectedly quoted");
+            }
+        }
+        else
+        {
+            if( context.EscapeNumbers())    {
+                // This will throw - we should have had a quote if EscapeNumbers() == true
+                ReadJSONSyntaxChar( JSONConstants.QUOTE);
+            }
+
+            str = ReadJSONNumericChars();
+        }
+
+        // parse and check - we should have at least one valid digit
+        var dub = Std.parseFloat( str);
+        if( (str.length == 0) || Math.isNaN(dub)) {
+            throw new TProtocolException(TProtocolException.INVALID_DATA, 'Bad numeric data: $str');
+        }
+
+        return dub;
+    }
+
+    // Read in a JSON string containing base-64 encoded data and decode it.
+    private function ReadJSONBase64() : Bytes
+    {
+        var str = ReadJSONString(false);
+        return Base64.decode( str);
+    }
+
+    private function ReadJSONObjectStart() : Void {
+        context.Read();
+        ReadJSONSyntaxChar( JSONConstants.LBRACE);
+        PushContext(new JSONPairContext(this));
+    }
+
+    private function ReadJSONObjectEnd() : Void {
+        ReadJSONSyntaxChar( JSONConstants.RBRACE);
+        PopContext();
+    }
+
+    private function ReadJSONArrayStart() : Void {
+        context.Read();
+        ReadJSONSyntaxChar( JSONConstants.LBRACKET);
+        PushContext(new JSONListContext(this));
+    }
+
+    private function ReadJSONArrayEnd() : Void {
+        ReadJSONSyntaxChar( JSONConstants.RBRACKET);
+        PopContext();
+    }
+
+
+    public static function BytesFromString( str : String) : Bytes {
+        var buf = new BytesBuffer();
+        if( utf8Strings)
+            buf.addString( str);  // no need to encode on UTF8 targets, the string is just fine
+        else
+            buf.addString( Utf8.encode( str));
+        return buf.getBytes();
+    }
+
+    public static function StringFromBytes( buf : Bytes) : String {
+        var inp = new BytesInput( buf);
+        if( buf.length == 0)
+            return "";  // readString() would return null in that case, which is wrong
+        var str = inp.readString( buf.length);
+        if( utf8Strings)
+            return str;  // no need to decode on UTF8 targets, the string is just fine
+        else
+            return Utf8.decode( str);
+    }
+
+    // Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its corresponding hex value
+    private static function HexVal(char : String) : Int {
+        var value = JSONConstants.HEX_DIGITS[char];
+        if( value == null) {
+            throw new TProtocolException(TProtocolException.INVALID_DATA, 'Expected hex character: $char');
+        }
+        return value;
+    }
+
+    // Convert a byte containing a hex nibble to its corresponding hex character
+    private static function HexChar(nibble : Int) : String
+    {
+        return "0123456789abcdef".charAt(nibble & 0x0F);
+    }
+
+
+}
+
+
+@:allow(TJSONProtocol)
+class JSONConstants {
+    public static var COMMA = ",";
+    public static var COLON = ":";
+    public static var LBRACE = "{";
+    public static var RBRACE = "}";
+    public static var LBRACKET = "[";
+    public static var RBRACKET = "]";
+    public static var QUOTE = "\"";
+    public static var BACKSLASH = "\\";
+
+    public static var ESCSEQ = "\\u";
+
+    public static var FLOAT_IS_NAN = "NaN";
+    public static var FLOAT_IS_POS_INF = "Infinity";
+    public static var FLOAT_IS_NEG_INF = "-Infinity";
+
+    public static var VERSION = 1;
+    public static var JSON_CHAR_TABLE = [
+        0,  0,  0,  0,  0,  0,  0,  0,
+        "b".code, "t".code, "n".code,  0, "f".code, "r".code,  0,  0,
+        0,  0,  0,  0,  0,  0,  0,  0,
+        0,  0,  0,  0,  0,  0,  0,  0,
+        1,  1, "\"".code,  1,  1,  1,  1,  1,
+        1,  1,  1,  1,  1,  1,  1,  1,
+    ];
+
+    public static var ESCAPE_CHARS     = ['"','\\','/','b','f','n','r','t'];
+    public static var ESCAPE_CHARS_TO_VALUES = [
+        "\"".code => 0x22,
+        "\\".code => 0x5C,
+        "/".code  => 0x2F,
+        "b".code  => 0x08,
+        "f".code  => 0x0C,
+        "n".code  => 0x0A,
+        "r".code  => 0x0D,
+        "t".code  => 0x09
+    ];
+
+    public static var DECIMAL_DIGITS = [
+        "0" => 0,
+        "1" => 1,
+        "2" => 2,
+        "3" => 3,
+        "4" => 4,
+        "5" => 5,
+        "6" => 6,
+        "7" => 7,
+        "8" => 8,
+        "9" => 9
+    ];
+
+    public static var HEX_DIGITS = [
+        "0" => 0,
+        "1" => 1,
+        "2" => 2,
+        "3" => 3,
+        "4" => 4,
+        "5" => 5,
+        "6" => 6,
+        "7" => 7,
+        "8" => 8,
+        "9" => 9,
+        "A" => 10,
+        "a" => 10,
+        "B" => 11,
+        "b" => 11,
+        "C" => 12,
+        "c" => 12,
+        "D" => 13,
+        "d" => 13,
+        "E" => 14,
+        "e" => 14,
+        "F" => 15,
+        "f" => 15
+    ];
+
+
+    public static var DEF_STRING_SIZE = 16;
+
+    public static var NAME_BOOL   = 'tf';
+    public static var NAME_BYTE   = 'i8';
+    public static var NAME_I16    = 'i16';
+    public static var NAME_I32    = 'i32';
+    public static var NAME_I64    = 'i64';
+    public static var NAME_DOUBLE = 'dbl';
+    public static var NAME_STRUCT = 'rec';
+    public static var NAME_STRING = 'str';
+    public static var NAME_MAP    = 'map';
+    public static var NAME_LIST   = 'lst';
+    public static var NAME_SET    = 'set';
+
+    public static function GetTypeNameForTypeID(typeID : Int) : String {
+        switch (typeID)
+        {
+            case TType.BOOL:     return NAME_BOOL;
+            case TType.BYTE:     return NAME_BYTE;
+            case TType.I16:         return NAME_I16;
+            case TType.I32:         return NAME_I32;
+            case TType.I64:         return NAME_I64;
+            case TType.DOUBLE:     return NAME_DOUBLE;
+            case TType.STRING:     return NAME_STRING;
+            case TType.STRUCT:     return NAME_STRUCT;
+            case TType.MAP:         return NAME_MAP;
+            case TType.SET:         return NAME_SET;
+            case TType.LIST:     return NAME_LIST;
+        }
+        throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized type");
+    }
+
+    private static var NAMES_TO_TYPES = [
+        NAME_BOOL   => TType.BOOL,
+        NAME_BYTE   => TType.BYTE,
+        NAME_I16    => TType.I16,
+        NAME_I32    => TType.I32,
+        NAME_I64    => TType.I64,
+        NAME_DOUBLE => TType.DOUBLE,
+        NAME_STRING => TType.STRING,
+        NAME_STRUCT => TType.STRUCT,
+        NAME_MAP    => TType.MAP,
+        NAME_SET    => TType.SET,
+        NAME_LIST   => TType.LIST
+    ];
+
+    public static function GetTypeIDForTypeName(name : String) : Int
+    {
+        var type = NAMES_TO_TYPES[name];
+        if( null != type) {
+            return type;
+        }
+        throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized type");
+    }
+
+}
+
+
+// Base class for tracking JSON contexts that may require inserting/Reading
+// additional JSON syntax characters. This base context does nothing.
+@:allow(TJSONProtocol)
+class JSONBaseContext
+{
+    private var proto : TJSONProtocol;
+
+    public function new(proto : TJSONProtocol )
+    {
+        this.proto = proto;
+    }
+
+    public function Write() : Void { }
+    public function Read() : Void { }
+
+    public function EscapeNumbers() : Bool {
+        return false;
+    }
+}
+
+
+// Context for JSON lists.
+// Will insert/Read commas before each item except for the first one
+@:allow(TJSONProtocol)
+class JSONListContext extends JSONBaseContext
+{
+    public function new( proto : TJSONProtocol) {
+        super(proto);
+    }
+
+    private var first : Bool = true;
+
+    public override function Write() : Void {
+        if (first)
+        {
+            first = false;
+        }
+        else
+        {
+            var buf = new BytesBuffer();
+            buf.addString( JSONConstants.COMMA);
+            var tmp = buf.getBytes();
+            proto.trans.write( tmp, 0, tmp.length);
+        }
+    }
+
+    public override function Read() : Void {
+        if (first)
+        {
+            first = false;
+        }
+        else
+        {
+            proto.ReadJSONSyntaxChar( JSONConstants.COMMA);
+        }
+    }
+}
+
+
+// Context for JSON records.
+// Will insert/Read colons before the value portion of each record
+// pair, and commas before each key except the first. In addition,
+// will indicate that numbers in the key position need to be escaped
+// in quotes (since JSON keys must be strings).
+@:allow(TJSONProtocol)
+class JSONPairContext extends JSONBaseContext
+{
+    public function new( proto : TJSONProtocol ) {
+        super( proto);
+    }
+
+    private var first : Bool = true;
+    private var colon : Bool  = true;
+
+    public override function Write() : Void {
+        if (first)
+        {
+            first = false;
+            colon = true;
+        }
+        else
+        {
+            var buf = new BytesBuffer();
+            buf.addString( colon ? JSONConstants.COLON : JSONConstants.COMMA);
+            var tmp = buf.getBytes();
+            proto.trans.write( tmp, 0, tmp.length);
+            colon = !colon;
+        }
+    }
+
+    public override function Read() : Void {
+        if (first)
+        {
+            first = false;
+            colon = true;
+        }
+        else
+        {
+            proto.ReadJSONSyntaxChar( colon ? JSONConstants.COLON : JSONConstants.COMMA);
+            colon = !colon;
+        }
+    }
+
+    public override function EscapeNumbers() : Bool
+    {
+        return colon;
+    }
+}
+
+// Holds up to one byte from the transport
+@:allow(TJSONProtocol)
+class LookaheadReader {
+
+    private var proto : TJSONProtocol;
+    private var data : Bytes;
+
+    public function new( proto : TJSONProtocol ) {
+        this.proto = proto;
+        data = null;
+    }
+
+
+    // Return and consume the next byte to be Read, either taking it from the
+    // data buffer if present or getting it from the transport otherwise.
+    public function Read() : Bytes {
+        var retval = Peek();
+        data = null;
+        return retval;
+    }
+
+    // Return the next byte to be Read without consuming, filling the data
+    // buffer if it has not been filled alReady.
+    public function Peek() : Bytes {
+        if (data == null) {
+            var buf = new BytesBuffer();
+            proto.trans.readAll(buf, 0, 1);
+            data = buf.getBytes();
+        }
+        return data;
+    }
+}
+
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocolFactory.hx b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocolFactory.hx
new file mode 100644
index 0000000..363558a
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocolFactory.hx
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift.protocol;
+
+import org.apache.thrift.transport.TTransport;
+
+
+/**
+* JSON Protocol Factory
+*/
+class TJSONProtocolFactory implements TProtocolFactory {
+
+    public function new() {
+    }
+
+    public function getProtocol( trans : TTransport) : TProtocol  {
+        return new TJSONProtocol( trans);
+    }
+}
+
+
+
+    
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TList.hx b/lib/haxe/src/org/apache/thrift/protocol/TList.hx
new file mode 100644
index 0000000..5a1fb55
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TList.hx
@@ -0,0 +1,32 @@
+/*
+ * 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 org.apache.thrift.protocol;
+
+class TList {
+
+    public var elemType : Int;
+    public var size : Int;
+
+      public function new(t : Int = 0, s : Int = 0) {
+        elemType = t;
+        size = s;
+      }
+
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TMap.hx b/lib/haxe/src/org/apache/thrift/protocol/TMap.hx
new file mode 100644
index 0000000..f4e6288
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TMap.hx
@@ -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 org.apache.thrift.protocol;
+
+class TMap {
+
+    public var keyType : Int;
+    public var valueType : Int;
+    public var size : Int;
+
+    public function new(k : Int = 0, v : Int = 0, s : Int = 0) {
+      keyType = k;
+      valueType = v;
+      size = s;
+    }
+
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TMessage.hx b/lib/haxe/src/org/apache/thrift/protocol/TMessage.hx
new file mode 100644
index 0000000..d99264a
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TMessage.hx
@@ -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 org.apache.thrift.protocol;
+
+class TMessage {
+
+    public var name : String;
+    public var type : Int;
+    public var seqid : Int;
+
+    public function new(n : String = "", t : Int = 0, s : Int = 0) {
+      name = n;
+      type = t;
+      seqid = s;
+    }
+
+    public function toString() : String {
+      return "<TMessage name:'" + name + "' type: " + type + " seqid:" + seqid + ">";
+    }
+
+    public function equals(other:TMessage) : Bool {
+      return name == other.name && type == other.type && seqid == other.seqid;
+    }
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TMessageType.hx b/lib/haxe/src/org/apache/thrift/protocol/TMessageType.hx
new file mode 100644
index 0000000..706d329
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TMessageType.hx
@@ -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 org.apache.thrift.protocol;
+
+@:enum
+abstract TMessageType(Int)  from Int to Int  {
+    public static inline var CALL      : Int = 1;
+    public static inline var REPLY     : Int = 2;
+    public static inline var EXCEPTION : Int = 3;
+    public static inline var ONEWAY    : Int = 4;
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TMultiplexedProcessor.hx b/lib/haxe/src/org/apache/thrift/protocol/TMultiplexedProcessor.hx
new file mode 100644
index 0000000..50aa3cd
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TMultiplexedProcessor.hx
@@ -0,0 +1,177 @@
+/**
+ * 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 org.apache.thrift.protocol;
+
+import haxe.ds.StringMap;
+import org.apache.thrift.TApplicationException;
+import org.apache.thrift.TProcessor;
+
+import org.apache.thrift.transport.TTransport;
+
+
+/**
+ * TMultiplexedProcessor is a TProcessor allowing a single TServer to provide multiple services.
+ * To do so, you instantiate the processor and then register additional processors with it,
+ * as shown in the following example:
+ *
+ *     TMultiplexedProcessor processor = new TMultiplexedProcessor();
+ *
+ *     processor.registerProcessor(
+ *         "Calculator",
+ *         new Calculator.Processor(new CalculatorHandler()));
+ *
+ *     processor.registerProcessor(
+ *         "WeatherReport",
+ *         new WeatherReport.Processor(new WeatherReportHandler()));
+ *
+ *     TServerTransport t = new TServerSocket(9090);
+ *     TSimpleServer server = new TSimpleServer(processor, t);
+ *
+ *     server.serve();
+ */
+class TMultiplexedProcessor implements TProcessor
+{
+    private var serviceProcessorMap : StringMap<TProcessor> = new StringMap<TProcessor>();
+    private var defaultProcessor : TProcessor = null;
+
+    public function new() {
+    }
+
+    /**
+     * 'Register' a service with this TMultiplexedProcessor. This allows us to broker
+     * requests to individual services by using the service name to select them at request time.
+     *
+     * Args:
+     * - serviceName    Name of a service, has to be identical to the name
+     *                  declared in the Thrift IDL, e.g. "WeatherReport".
+     * - processor      Implementation of a service, usually referred to as "handlers",
+     *                  e.g. WeatherReportHandler implementing WeatherReport.Iface.
+     */
+    public function RegisterProcessor(serviceName : String, processor : TProcessor, asDefault : Bool = false) : Void {
+        serviceProcessorMap.set(serviceName, processor);
+        if ( asDefault) {
+            if( defaultProcessor != null) {
+                throw new TApplicationException( TApplicationException.UNKNOWN, "Can't have multiple default processors");
+            } else {
+                defaultProcessor = processor;
+            }
+        }
+    }
+
+
+    private function Fail( oprot : TProtocol, message : TMessage, extype : Int, etxt : String) : Void {
+        var appex = new TApplicationException( extype, etxt);
+
+        var newMessage = new TMessage(message.name, TMessageType.EXCEPTION, message.seqid);
+
+        oprot.writeMessageBegin(newMessage);
+        appex.write( oprot);
+        oprot.writeMessageEnd();
+        oprot.getTransport().flush();
+    }
+
+
+    /**
+     * This implementation of process performs the following steps:
+     *
+     * - Read the beginning of the message.
+     * - Extract the service name from the message.
+     * - Using the service name to locate the appropriate processor.
+     * - Dispatch to the processor, with a decorated instance of TProtocol
+     *    that allows readMessageBegin() to return the original TMessage.
+     *
+     * Throws an exception if
+     * - the message type is not CALL or ONEWAY,
+     * - the service name was not found in the message, or
+     * - the service name has not been RegisterProcessor()ed.
+     */
+    public function process( iprot : TProtocol, oprot : TProtocol) : Bool {
+        /*  Use the actual underlying protocol (e.g. TBinaryProtocol) to read the
+            message header.  This pulls the message "off the wire", which we'll
+            deal with at the end of this method. */
+
+        var message : TMessage = iprot.readMessageBegin();
+        var methodName : String = "";
+
+        if ((message.type != TMessageType.CALL) && (message.type != TMessageType.ONEWAY))
+        {
+            Fail(oprot, message,
+                  TApplicationException.INVALID_MESSAGE_TYPE,
+                  "Message type CALL or ONEWAY expected");
+            return false;
+        }
+
+        // Extract the service name
+        var actualProcessor : TProcessor = null;
+        var index = message.name.indexOf(TMultiplexedProtocol.SEPARATOR);
+        if (index < 0) {
+            // fallback to default processor
+            methodName = message.name;
+            actualProcessor = defaultProcessor;
+            if( actualProcessor == null) {
+                Fail(oprot, message,
+                      TApplicationException.INVALID_PROTOCOL,
+                      "Service name not found in message name: " + message.name + " and no default processor defined. " +
+                      "Did you forget to use a TMultiplexProtocol in your client?");
+                return false;
+            }
+
+        } else {
+            // service name given
+            var serviceName = message.name.substring(0, index);
+            methodName = message.name.substring( serviceName.length + TMultiplexedProtocol.SEPARATOR.length);
+            actualProcessor = serviceProcessorMap.get( serviceName);
+            if( actualProcessor == null) {
+                Fail(oprot, message,
+                      TApplicationException.INTERNAL_ERROR,
+                      "Service name not found: " + serviceName + ". " +
+                      "Did you forget to call RegisterProcessor()?");
+                return false;
+            }
+        }
+
+        // Create a new TMessage, removing the service name
+        // Dispatch processing to the stored processor
+        var newMessage = new TMessage( methodName, message.type, message.seqid);
+        var storedMsg = new StoredMessageProtocol( iprot, newMessage);
+        return actualProcessor.process( storedMsg, oprot);
+    }
+}
+
+
+/**
+ *  Our goal was to work with any protocol.  In order to do that, we needed
+ *  to allow them to call readMessageBegin() and get a TMessage in exactly
+ *  the standard format, without the service name prepended to TMessage.name.
+ */
+class StoredMessageProtocol extends TProtocolDecorator
+{
+    private var messageBegin : TMessage;
+
+    public function new( protocol : TProtocol, messageBegin : TMessage) {
+        super( protocol);
+        this.messageBegin = messageBegin;
+    }
+
+    public override function readMessageBegin() : TMessage {
+        return messageBegin;
+    }
+}
+
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TMultiplexedProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TMultiplexedProtocol.hx
new file mode 100644
index 0000000..cacd1d7
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TMultiplexedProtocol.hx
@@ -0,0 +1,97 @@
+/**
+ * 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 org.apache.thrift.protocol;
+
+import org.apache.thrift.transport.TTransport;
+
+
+/**
+ * TMultiplexedProtocol is a protocol-independent concrete decorator that allows a Thrift
+ * client to communicate with a multiplexing Thrift server, by prepending the service name
+ * to the function name during function calls.
+ *
+ * NOTE: THIS IS NOT TO BE USED BY SERVERS.
+ * On the server, use TMultiplexedProcessor to handle requests from a multiplexing client.
+ *
+ * This example uses a single socket transport to invoke two services:
+ *
+ *     TSocket transport = new TSocket("localhost", 9090);
+ *     transport.open();
+ *
+ *     TBinaryProtocol protocol = new TBinaryProtocol(transport);
+ *
+ *     TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "Calculator");
+ *     Calculator.Client service = new Calculator.Client(mp);
+ *
+ *     TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, "WeatherReport");
+ *     WeatherReport.Client service2 = new WeatherReport.Client(mp2);
+ *
+ *     System.out.println(service.add(2,2));
+ *     System.out.println(service2.getTemperature());
+ *
+ */
+class TMultiplexedProtocol extends TProtocolDecorator {
+
+    /** Used to delimit the service name from the function name */
+    public static inline var SEPARATOR : String = ":";
+
+    private var service : String;
+
+    /**
+     * Wrap the specified protocol, allowing it to be used to communicate with a
+     * multiplexing server.  The <code>serviceName</code> is required as it is
+     * prepended to the message header so that the multiplexing server can broker
+     * the function call to the proper service.
+     *
+     * Args:
+     *  protocol        Your communication protocol of choice, e.g. TBinaryProtocol
+     *  serviceName     The service name of the service communicating via this protocol.
+     */
+    public function new( protocol : TProtocol, serviceName : String)    {
+        super( protocol);
+        service = serviceName;
+    }
+
+    /**
+     * Prepends the service name to the function name, separated by TMultiplexedProtocol.SEPARATOR.
+     * Args:
+     *   tMessage     The original message.
+     */
+    public override function writeMessageBegin( message : TMessage) : Void {
+        switch( message.type)
+        {
+            case TMessageType.CALL:
+                super.writeMessageBegin(new TMessage(
+                    service + SEPARATOR + message.name,
+                    message.type,
+                    message.seqid));
+
+            case TMessageType.ONEWAY:
+                super.writeMessageBegin(new TMessage(
+                    service + SEPARATOR + message.name,
+                    message.type,
+                    message.seqid));
+
+            default:
+                super.writeMessageBegin(message);
+        }
+    }
+}
+
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx
new file mode 100644
index 0000000..b7f3842
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx
@@ -0,0 +1,85 @@
+/*
+ * 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 org.apache.thrift.protocol;
+
+import haxe.io.Bytes;
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransport;
+
+/**
+* Protocol interface definition
+*/
+interface TProtocol {
+
+    function getTransport() : TTransport;
+
+    /**
+     * Writing methods.
+     */
+    function writeMessageBegin(message:TMessage) : Void;
+    function writeMessageEnd() : Void;
+    function writeStructBegin(struct:TStruct) : Void;
+    function writeStructEnd() : Void;
+    function writeFieldBegin(field:TField) : Void;
+    function writeFieldEnd() : Void;
+    function writeFieldStop() : Void;
+    function writeMapBegin(map:TMap) : Void;
+    function writeMapEnd() : Void;
+    function writeListBegin(list:TList) : Void;
+    function writeListEnd() : Void;
+    function writeSetBegin(set:TSet) : Void;
+    function writeSetEnd() : Void;
+    function writeBool(b : Bool) : Void;
+    function writeByte(b : Int) : Void;
+    function writeI16(i16 : Int) : Void;
+    function writeI32(i32 : Int) : Void;
+    function writeI64(i64 : haxe.Int64) : Void;
+    function writeDouble(dub : Float) : Void;
+    function writeString(str : String) : Void;
+    function writeBinary(bin : Bytes) : Void;
+
+    /**
+     * Reading methods.
+     */
+    function readMessageBegin():TMessage;
+    function readMessageEnd() : Void;
+    function readStructBegin():TStruct;
+    function readStructEnd() : Void;
+    function readFieldBegin():TField;
+    function readFieldEnd() : Void;
+    function readMapBegin():TMap;
+    function readMapEnd() : Void;
+    function readListBegin():TList;
+    function readListEnd() : Void;
+    function readSetBegin():TSet;
+    function readSetEnd() : Void;
+    function readBool() : Bool;
+    function readByte() : Int;
+    function readI16() : Int;
+    function readI32() : Int;
+    function readI64() : haxe.Int64;
+    function readDouble() : Float;
+    function readString() : String;
+    function readBinary() : Bytes;
+
+    // recursion tracking
+    function IncrementRecursionDepth() : Void;
+    function DecrementRecursionDepth() : Void;
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocolDecorator.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocolDecorator.hx
new file mode 100644
index 0000000..769e93c
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocolDecorator.hx
@@ -0,0 +1,226 @@
+/**
+ * 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 org.apache.thrift.protocol;
+
+import haxe.io.Bytes;
+import haxe.Int64;
+
+import org.apache.thrift.transport.TTransport;
+
+
+/**
+ * TProtocolDecorator forwards all requests to an enclosed TProtocol instance,
+ * providing a way to author concise concrete decorator subclasses.  While it has
+ * no abstract methods, it is marked abstract as a reminder that by itself,
+ * it does not modify the behaviour of the enclosed TProtocol.
+ *
+ * See p.175 of Design Patterns (by Gamma et al.)
+ * See TMultiplexedProtocol
+ */
+class TProtocolDecorator implements TProtocol
+{
+    private var wrapped : TProtocol;
+
+    /**
+     * Encloses the specified protocol.
+     * @param protocol All operations will be forward to this protocol.  Must be non-null.
+     */
+    private function new( protocol : TProtocol)  // not to be instantiated, must derive a class
+    {
+        wrapped = protocol;
+    }
+
+    public function getTransport() : TTransport {
+      return wrapped.getTransport();
+    }
+
+    public function writeMessageBegin( value : TMessage) : Void    {
+        wrapped.writeMessageBegin( value);
+    }
+
+    public function writeMessageEnd() : Void {
+        wrapped.writeMessageEnd();
+    }
+
+    public function writeStructBegin(value : TStruct) : Void {
+        wrapped.writeStructBegin( value);
+    }
+
+    public function writeStructEnd() : Void {
+        wrapped.writeStructEnd();
+    }
+
+    public function writeFieldBegin(value : TField) : Void {
+        wrapped.writeFieldBegin( value);
+    }
+
+    public function writeFieldEnd() : Void {
+        wrapped.writeFieldEnd();
+    }
+
+    public function writeFieldStop() : Void {
+        wrapped.writeFieldStop();
+    }
+
+    public function writeMapBegin( value : TMap) : Void {
+        wrapped.writeMapBegin( value);
+    }
+
+    public function writeMapEnd() : Void {
+        wrapped.writeMapEnd();
+    }
+
+    public function writeListBegin( value : TList) : Void {
+        wrapped.writeListBegin( value);
+    }
+
+    public function writeListEnd() : Void {
+        wrapped.writeListEnd();
+    }
+
+    public function writeSetBegin( value : TSet) : Void {
+        wrapped.writeSetBegin( value);
+    }
+
+    public function writeSetEnd() : Void {
+        wrapped.writeSetEnd();
+    }
+
+    public function writeBool(value : Bool) : Void {
+        wrapped.writeBool( value);
+    }
+
+    public function writeByte(value : Int) : Void {
+        wrapped.writeByte( value);
+    }
+
+    public function writeI16(value : Int) : Void {
+        wrapped.writeI16( value);
+    }
+
+    public function writeI32(value : Int) : Void {
+        wrapped.writeI32( value);
+    }
+
+    public function writeI64(value : haxe.Int64) : Void {
+        wrapped.writeI64( value);
+    }
+
+    public function writeDouble(value : Float) : Void {
+        wrapped.writeDouble( value);
+    }
+
+    public function writeString(value : String) : Void {
+        wrapped.writeString( value);
+    }
+
+    public function writeBinary(value : Bytes ) : Void {
+        wrapped.writeBinary( value);
+    }
+
+    public function readMessageBegin() : TMessage {
+        return wrapped.readMessageBegin();
+    }
+
+    public function readMessageEnd() : Void {
+        wrapped.readMessageEnd();
+    }
+
+    public function readStructBegin() : TStruct {
+        return wrapped.readStructBegin();
+    }
+
+    public function readStructEnd() : Void {
+        wrapped.readStructEnd();
+    }
+
+    public function readFieldBegin() : TField {
+        return wrapped.readFieldBegin();
+    }
+
+    public function readFieldEnd() : Void {
+        wrapped.readFieldEnd();
+    }
+
+    public function readMapBegin() : TMap {
+        return wrapped.readMapBegin();
+    }
+
+    public function readMapEnd() : Void {
+        wrapped.readMapEnd();
+    }
+
+    public function readListBegin() : TList {
+        return wrapped.readListBegin();
+    }
+
+    public function readListEnd() : Void {
+        wrapped.readListEnd();
+    }
+
+    public function readSetBegin() : TSet {
+        return wrapped.readSetBegin();
+    }
+
+    public function readSetEnd() : Void {
+        wrapped.readSetEnd();
+    }
+
+    public function readBool() : Bool
+    {
+        return wrapped.readBool();
+    }
+
+    public function readByte() : Int {
+        return wrapped.readByte();
+    }
+
+    public function readI16() : Int {
+        return wrapped.readI16();
+    }
+
+    public function readI32() : Int {
+        return wrapped.readI32();
+    }
+
+    public function readI64() : haxe.Int64 {
+        return wrapped.readI64();
+    }
+
+    public function readDouble() : Float {
+        return wrapped.readDouble();
+    }
+
+    public function readString() : String {
+        return wrapped.readString();
+    }
+
+    public function readBinary() : Bytes {
+        return wrapped.readBinary();
+    }
+
+    public function IncrementRecursionDepth() : Void {
+        return wrapped.IncrementRecursionDepth();
+    }
+
+    public function DecrementRecursionDepth() : Void {
+        return wrapped.DecrementRecursionDepth();
+    }
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocolException.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocolException.hx
new file mode 100644
index 0000000..a3b37a5
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocolException.hx
@@ -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 org.apache.thrift.protocol;
+
+import org.apache.thrift.TException;
+
+class TProtocolException extends TException {
+
+    // WARNING: These are subject to be extended in the future, so we can't use enums
+    // with Haxe 3.1.3 because of https://github.com/HaxeFoundation/haxe/issues/3649
+    public static inline var UNKNOWN : Int = 0;
+    public static inline var INVALID_DATA : Int = 1;
+    public static inline var NEGATIVE_SIZE : Int = 2;
+    public static inline var SIZE_LIMIT : Int = 3;
+    public static inline var BAD_VERSION : Int = 4;
+    public static inline var NOT_IMPLEMENTED : Int = 5;
+    public static inline var DEPTH_LIMIT : Int = 6;
+
+    public function new(error : Int = UNKNOWN, message : String = "") {
+      super(message, error);
+    }
+
+
+} 
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocolFactory.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocolFactory.hx
new file mode 100644
index 0000000..1c2d62e
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocolFactory.hx
@@ -0,0 +1,26 @@
+/*
+ * 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 org.apache.thrift.protocol;
+
+import org.apache.thrift.transport.TTransport;
+
+interface TProtocolFactory {
+     function getProtocol(trans:TTransport):TProtocol;
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocolUtil.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocolUtil.hx
new file mode 100644
index 0000000..001e405
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocolUtil.hx
@@ -0,0 +1,110 @@
+/*
+ * 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 org.apache.thrift.protocol;
+
+import org.apache.thrift.*;
+
+  /**
+   * Utility class with static methods for interacting with protocol data
+   * streams.
+   *
+   */
+class TProtocolUtil {
+
+    /**
+     * 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.
+     */
+    public static function skip(prot:TProtocol, type : Int) : Void {
+        prot.IncrementRecursionDepth();
+        try
+        {
+            switch (type) {
+                case TType.BOOL:
+                    prot.readBool();
+
+                case TType.BYTE:
+                    prot.readByte();
+
+                case TType.I16:
+                    prot.readI16();
+
+                case TType.I32:
+                    prot.readI32();
+
+                case TType.I64:
+                    prot.readI64();
+
+                case TType.DOUBLE:
+                    prot.readDouble();
+
+                case TType.STRING:
+                    prot.readBinary();
+
+                case TType.STRUCT:
+                    prot.readStructBegin();
+                    while (true) {
+                        var field:TField = prot.readFieldBegin();
+                        if (field.type == TType.STOP) {
+                          break;
+                        }
+                        skip(prot, field.type);
+                        prot.readFieldEnd();
+                    }
+                    prot.readStructEnd();
+
+                case TType.MAP:
+                    var map:TMap = prot.readMapBegin();
+                    for (i in 0 ... map.size) {
+                        skip(prot, map.keyType);
+                        skip(prot, map.valueType);
+                    }
+                    prot.readMapEnd();
+
+                case TType.SET:
+                    var set:TSet = prot.readSetBegin();
+                    for (j in 0 ... set.size) {
+                        skip(prot, set.elemType);
+                    }
+                    prot.readSetEnd();
+
+                case TType.LIST:
+                    var list:TList = prot.readListBegin();
+                    for (k in 0 ... list.size) {
+                        skip(prot, list.elemType);
+                    }
+                    prot.readListEnd();
+
+                default:
+					throw new TProtocolException(TProtocolException.UNKNOWN, "Unknown field type ${type}");
+            }
+
+            prot.DecrementRecursionDepth();
+        }
+        catch(e:Dynamic)
+        {
+            prot.DecrementRecursionDepth();
+            throw e;
+        }
+    }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TRecursionTracker.hx b/lib/haxe/src/org/apache/thrift/protocol/TRecursionTracker.hx
new file mode 100644
index 0000000..cf0211b
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TRecursionTracker.hx
@@ -0,0 +1,48 @@
+/*
+ * 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 org.apache.thrift.protocol;
+
+import org.apache.thrift.*;
+
+
+class TRecursionTracker {
+
+    // default
+    private static inline var DEFAULT_RECURSION_DEPTH : Int = 64;
+
+    // limit and actual value
+    public var recursionLimit : Int = DEFAULT_RECURSION_DEPTH;
+    private var recursionDepth : Int = 0;
+
+    public function IncrementRecursionDepth() : Void
+    {
+        if (recursionDepth < recursionLimit)
+            ++recursionDepth;
+        else
+            throw new TProtocolException(TProtocolException.DEPTH_LIMIT, "Depth limit exceeded");
+    }
+
+    public function DecrementRecursionDepth() : Void
+    {
+        --recursionDepth;
+    }
+
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TSet.hx b/lib/haxe/src/org/apache/thrift/protocol/TSet.hx
new file mode 100644
index 0000000..44eab36
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TSet.hx
@@ -0,0 +1,32 @@
+/*
+ * 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 org.apache.thrift.protocol;
+
+class TSet {
+
+    public var elemType : Int;
+    public var size : Int;
+
+      public function new(t : Int = 0, s : Int = 0) {
+        elemType = t;
+        size = s;
+      }
+
+}    
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TStruct.hx b/lib/haxe/src/org/apache/thrift/protocol/TStruct.hx
new file mode 100644
index 0000000..9e0b7dd
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TStruct.hx
@@ -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 org.apache.thrift.protocol;
+
+class TStruct {
+
+    public var name : String;
+
+    public function new(n : String = "") {
+      name = n;
+    }
+
+}  
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TType.hx b/lib/haxe/src/org/apache/thrift/protocol/TType.hx
new file mode 100644
index 0000000..6abbc96
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/protocol/TType.hx
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.thrift.protocol;
+
+@:enum
+abstract TType(Int)  from Int to Int  {
+    public static inline var STOP : Int   = 0;
+    public static inline var VOID : Int   = 1;
+    public static inline var BOOL : Int   = 2;
+    public static inline var BYTE : Int   = 3;
+    public static inline var DOUBLE : Int = 4;
+    public static inline var I16 : Int    = 6;
+    public static inline var I32 : Int    = 8;
+    public static inline var I64 : Int    = 10;
+    public static inline var STRING : Int = 11;
+    public static inline var STRUCT : Int = 12;
+    public static inline var MAP : Int    = 13;
+    public static inline var SET : Int    = 14;
+    public static inline var LIST : Int   = 15;
+}
diff --git a/lib/haxe/src/org/apache/thrift/server/TServer.hx b/lib/haxe/src/org/apache/thrift/server/TServer.hx
new file mode 100644
index 0000000..56eee0a
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/server/TServer.hx
@@ -0,0 +1,111 @@
+/*
+ * 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 org.apache.thrift.server;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.meta_data.*;
+
+class TServer
+{
+    private var processor : TProcessor = null;
+    private var serverTransport : TServerTransport = null;
+    private var inputTransportFactory : TTransportFactory = null;
+    private var outputTransportFactory : TTransportFactory = null;
+    private var inputProtocolFactory : TProtocolFactory = null;
+    private var outputProtocolFactory : TProtocolFactory = null;
+
+    // server events
+    public var serverEventHandler : TServerEventHandler = null;
+
+    // Log delegation
+    private var _logDelegate : Dynamic->Void  = null;
+    public var logDelegate(get,set) : Dynamic->Void;
+
+    public function new( processor : TProcessor,
+                         serverTransport : TServerTransport,
+                         inputTransportFactory : TTransportFactory = null,
+                         outputTransportFactory : TTransportFactory = null,
+                         inputProtocolFactory : TProtocolFactory = null,
+                         outputProtocolFactory : TProtocolFactory = null,
+                         logDelegate : Dynamic->Void = null)
+    {
+      this.processor = processor;
+      this.serverTransport = serverTransport;
+      this.inputTransportFactory = inputTransportFactory;
+      this.outputTransportFactory = outputTransportFactory;
+      this.inputProtocolFactory = inputProtocolFactory;
+      this.outputProtocolFactory = outputProtocolFactory;
+      this.logDelegate = logDelegate;
+
+      ApplyMissingDefaults();
+    }
+
+    private function ApplyMissingDefaults() {
+        if( processor == null)
+            throw "Invalid server configuration: processor missing";
+        if( serverTransport == null)
+            throw "Invalid server configuration: serverTransport missing";
+        if( inputTransportFactory == null)
+            inputTransportFactory = new TTransportFactory();
+        if( outputTransportFactory  == null)
+            outputTransportFactory = new TTransportFactory();
+        if( inputProtocolFactory  == null)
+            inputProtocolFactory = new TBinaryProtocolFactory();
+        if( outputProtocolFactory == null)
+            outputProtocolFactory= new TBinaryProtocolFactory();
+        if( logDelegate == null)
+            logDelegate = DefaultLogDelegate;
+    }
+
+
+    private function set_logDelegate(value : Dynamic->Void) : Dynamic->Void {
+        if(value != null) {
+            _logDelegate = value;
+        } else {
+            _logDelegate = DefaultLogDelegate;
+        }
+        return _logDelegate;
+    }
+
+
+    private function get_logDelegate() : Dynamic->Void {
+        return _logDelegate;
+    }
+
+
+    private function DefaultLogDelegate(value : Dynamic) : Void  {
+        trace( value);
+    }
+
+
+
+    public function Serve() : Void {
+        throw new AbstractMethodError();
+    }
+
+
+    public function Stop() : Void {
+        throw new AbstractMethodError();
+    }
+
+}
+ 
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx b/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx
new file mode 100644
index 0000000..9bc9927
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/server/TServerEventHandler.hx
@@ -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 org.apache.thrift.server;
+
+import org.apache.thrift.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.protocol.*;
+
+
+// Interface implemented by server users to handle events from the server
+interface TServerEventHandler {
+
+    // Called before the server begins
+    function preServe() : Void;
+
+    // Called when a new client has connected and is about to being processing
+    function createContext( input : TProtocol, output : TProtocol) : Dynamic;
+
+    // Called when a client has finished request-handling to delete server context
+    function deleteContext( serverContext : Dynamic, input : TProtocol, output : TProtocol) : Void;
+
+    // Called when a client is about to call the processor
+    function processContext( serverContext : Dynamic, transport : TTransport) : Void;
+}
diff --git a/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx b/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx
new file mode 100644
index 0000000..0600744
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/server/TSimpleServer.hx
@@ -0,0 +1,141 @@
+/*
+ * 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 org.apache.thrift.server;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.meta_data.*;
+
+// Simple single-threaded server for testing
+class TSimpleServer extends TServer  {
+
+    private var stop : Bool = false;
+
+    //stops just after input transport returns EOF
+    //useful for limited scenarios, like embeding into php server
+    public var runOnce : Bool = false;
+
+    public function new( processor : TProcessor,
+                         serverTransport : TServerTransport,
+                         transportFactory : TTransportFactory = null,
+                         protocolFactory : TProtocolFactory = null,
+                         logger : Dynamic->Void = null) {
+      super( processor, serverTransport,
+             transportFactory, transportFactory,
+             protocolFactory, protocolFactory,
+             logger);
+    }
+
+
+    public override function Serve() : Void
+    {
+        try
+        {
+            serverTransport.Listen();
+        }
+        catch (ttx : TTransportException)
+        {
+            logDelegate(ttx);
+            return;
+        }
+
+        // Fire the preServe server event when server is up,
+        // but before any client connections
+        if (serverEventHandler != null) {
+            serverEventHandler.preServe();
+        }
+
+        while( ! stop)
+        {
+            var client : TTransport = null;
+            var inputTransport : TTransport = null;
+            var outputTransport : TTransport = null;
+            var inputProtocol : TProtocol = null;
+            var outputProtocol : TProtocol = null;
+            var connectionContext : Dynamic = null;
+            try
+            {
+                client = serverTransport.Accept();
+                if (client != null) {
+                    inputTransport = inputTransportFactory.getTransport( client);
+                    outputTransport = outputTransportFactory.getTransport( client);
+                    inputProtocol = inputProtocolFactory.getProtocol( inputTransport);
+                    outputProtocol = outputProtocolFactory.getProtocol( outputTransport);
+
+                    // Recover event handler (if any) and fire createContext
+                    // server event when a client connects
+                    if (serverEventHandler != null) {
+                        connectionContext = serverEventHandler.createContext(inputProtocol, outputProtocol);
+                    }
+
+                    // Process client requests until client disconnects
+                    while( true) {
+                        // Fire processContext server event
+                        // N.B. This is the pattern implemented in C++ and the event fires provisionally.
+                        // That is to say it may be many minutes between the event firing and the client request
+                        // actually arriving or the client may hang up without ever makeing a request.
+                        if (serverEventHandler != null) {
+                            serverEventHandler.processContext(connectionContext, inputTransport);
+                        }
+
+                        //Process client request (blocks until transport is readable)
+                        if( ! processor.process( inputProtocol, outputProtocol)) {
+                            break;
+                        }
+                    }
+                }
+            }
+            catch( ttx : TTransportException)
+            {
+                // Usually a client disconnect, expected
+                if(runOnce && ttx.errorID == TTransportException.END_OF_FILE) {
+                  //input returns eof, exit
+                  //follows lib/cpp/src/thrift/server/TServerFramework.cpp
+                  Stop();
+                }
+            }
+            catch( pex : TProtocolException)
+            {
+                logDelegate('$pex ${pex.errorID} ${pex.errorMsg}'); // Unexpected
+            }
+            catch( e : Dynamic)
+            {
+                logDelegate(e); // Unexpected
+            }
+
+            if(client != null && !runOnce)
+            {
+                client.close();
+            }
+
+            // Fire deleteContext server event after client disconnects
+            if (serverEventHandler != null) {
+                serverEventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
+            }
+        }
+    }
+
+    public override function Stop() : Void
+    {
+      stop = true;
+      serverTransport.Close();
+    }
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TBufferedTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TBufferedTransport.hx
new file mode 100644
index 0000000..4b33fcf
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TBufferedTransport.hx
@@ -0,0 +1,155 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import org.apache.thrift.transport.*;
+
+import haxe.io.Eof;
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+import haxe.io.BytesOutput;
+import haxe.io.BytesInput;
+
+
+class TBufferedTransport extends TTransport
+{
+    // constants
+    public static inline var DEFAULT_BUFSIZE : Int = 0x1000;    // 4096 Bytes
+    public static inline var MIN_BUFSIZE : Int = 0x100;         // 256 Bytes
+    public static inline var MAX_BUFSIZE : Int = 0x100000;      // 1 MB
+
+    // Underlying transport
+    public var transport(default,null) :  TTransport = null;
+
+    // Buffer for input/output
+    private var readBuffer_ : BytesInput = null;
+    private var writeBuffer_ : BytesOutput = null;
+    private var bufSize : Int;
+
+    // Constructor wraps around another transport
+    public function new( transport : TTransport, bufSize : Int = DEFAULT_BUFSIZE) {
+
+        // ensure buffer size is in the range
+        if ( bufSize < MIN_BUFSIZE)
+            bufSize = MIN_BUFSIZE;
+        else if( bufSize > MAX_BUFSIZE)
+            bufSize = MAX_BUFSIZE;
+
+        this.transport = transport;
+        this.bufSize = bufSize;
+        this.writeBuffer_ = new BytesOutput();
+        this.writeBuffer_.bigEndian = true;
+    }
+
+    public override function open() : Void {
+        transport.open();
+    }
+
+    public override function isOpen() : Bool {
+        return transport.isOpen();
+    }
+
+    public override function close() : Void {
+        transport.close();
+    }
+
+    public override function read(buf : BytesBuffer, off : Int, len : Int) : Int {
+        try {
+            var data = Bytes.alloc(len);
+
+            while( true) {
+                if ((readBuffer_ != null) && (readBuffer_.position < readBuffer_.length)) {
+                    var got = readBuffer_.readBytes(data, 0, len);
+                    if (got > 0) {
+                        buf.addBytes(data, 0, got);
+                        return got;
+                    }
+                }
+
+                // there is no point in buffering whenever the
+                // remaining length exceeds the buffer size
+                if ( len >= bufSize) {
+                    var got = transport.read( buf, off, len);
+                    if (got > 0) {
+                        buf.addBytes(data, 0, got);
+                        return got;
+                    }
+                }
+
+                // fill the buffer
+                if ( readChunk() <= 0)
+                    break;
+            }
+
+            throw new TTransportException(TTransportException.END_OF_FILE, 'Can\'t read $len bytes!');
+        }
+        catch (eof : Eof) {
+            throw new TTransportException(TTransportException.END_OF_FILE, 'Can\'t read $len bytes!');
+        }
+    }
+
+    function readChunk() : Int {
+        var size = bufSize;
+        try {
+            var buffer = new BytesBuffer();
+            size = transport.read( buffer, 0, size);
+            readBuffer_ = new BytesInput( buffer.getBytes(), 0, size);
+            readBuffer_.bigEndian = true;
+            return size;
+        }
+        catch(eof : Eof) {
+            throw new TTransportException(TTransportException.END_OF_FILE, 'Can\'t read $size bytes!');
+        }
+    }
+
+    private function writeChunk(forceWrite : Bool) : Void {
+        if( writeBuffer_.length > 0) {
+            if ( forceWrite || (writeBuffer_.length >= bufSize)) {
+                var buf = writeBuffer_.getBytes();
+                writeBuffer_ = new BytesOutput();
+                writeBuffer_.bigEndian = true;
+                transport.write(buf, 0, buf.length);
+            }
+        }
+    }
+
+    public override function write(buf : Bytes, off : Int, len : Int) : Void {
+        var halfSize : Int = Std.int(bufSize / 2);
+
+        // No point in buffering if len exceeds the buffer size.
+        // However, if the buffer is less than half full we should still consider
+        // squashing all into one write, except when the actual write len is very large.
+        var huge_write : Bool = (len >= (2 * bufSize));
+        var exceeds_buf : Bool = huge_write || (len >= bufSize);
+        var write_thru : Bool = exceeds_buf && (writeBuffer_.length >= halfSize);
+        if ( write_thru) {
+            writeChunk(true); // force send whatever we have in there
+            transport.write(buf, off, len);  // write thru
+        } else {
+            writeBuffer_.writeBytes(buf, off, len);
+            writeChunk(false);
+        }
+    }
+
+    public override function flush( callback : Dynamic->Void =null) : Void {
+        writeChunk(true);
+        transport.flush(callback);
+    }
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TBufferedTransportFactory.hx b/lib/haxe/src/org/apache/thrift/transport/TBufferedTransportFactory.hx
new file mode 100644
index 0000000..539e720
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TBufferedTransportFactory.hx
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import org.apache.thrift.transport.*;
+
+
+class TBufferedTransportFactory extends TTransportFactory {
+
+    private var bufSize : Int;
+
+    public function new(bufSize : Int = TBufferedTransport.DEFAULT_BUFSIZE) {
+        super();
+        this.bufSize = bufSize;
+    }
+
+    public override function getTransport(base : TTransport) : TTransport {
+        return new TBufferedTransport(base, bufSize);
+    }
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TFileStream.hx b/lib/haxe/src/org/apache/thrift/transport/TFileStream.hx
new file mode 100644
index 0000000..cd8ad17
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TFileStream.hx
@@ -0,0 +1,101 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+import haxe.io.Input;
+import haxe.io.Output;
+
+
+enum TFileMode {
+    CreateNew;
+    Append;
+    Read;
+}
+
+
+class TFileStream implements TStream {
+
+    public var FileName(default,null) : String;
+
+    private var Input  : sys.io.FileInput;
+    private var Output : sys.io.FileOutput;
+
+
+    public function new( fname : String, mode : TFileMode) {
+        FileName = fname;
+        switch ( mode)
+        {
+            case TFileMode.CreateNew:
+                Output = sys.io.File.write( fname, true);
+
+            case TFileMode.Append:
+                Output = sys.io.File.append( fname, true);
+
+            case TFileMode.Read:
+                Input = sys.io.File.read( fname, true);
+
+            default:
+                throw new TTransportException( TTransportException.UNKNOWN,
+                                               "Unsupported mode");
+        }
+
+    }
+
+    public function Close() : Void {
+        if( Input != null) {
+            Input.close();
+            Input = null;
+        }
+        if( Output != null) {
+            Output.close();
+            Output = null;
+        }
+    }
+
+    public function Peek() : Bool {
+        if( Input == null)
+            throw new TTransportException( TTransportException.NOT_OPEN, "File not open for input");
+
+        return (! Input.eof());
+    }
+
+    public function Read( buf : Bytes, offset : Int, count : Int) : Int {
+        if( Input == null)
+            throw new TTransportException( TTransportException.NOT_OPEN, "File not open for input");
+
+        return Input.readBytes( buf, offset, count);
+    }
+
+    public function Write( buf : Bytes, offset : Int, count : Int) : Void {
+        if( Output == null)
+            throw new TTransportException( TTransportException.NOT_OPEN, "File not open for output");
+
+        Output.writeBytes( buf, offset, count);
+    }
+
+    public function Flush() : Void {
+        if( Output != null)
+            Output.flush();
+    }
+
+}
+ 
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx
new file mode 100644
index 0000000..cef82ef
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TFramedTransport.hx
@@ -0,0 +1,158 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import org.apache.thrift.transport.*;
+
+import haxe.io.Eof;
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+import haxe.io.BytesOutput;
+import haxe.io.BytesInput;
+
+
+/**
+ * TFramedTransport is a buffered TTransport that ensures a fully read message
+ * every time by preceding messages with a 4-byte frame size.
+ */
+class TFramedTransport extends TTransport
+{
+    public static inline var DEFAULT_MAX_LENGTH = 16384000;
+
+    var maxLength_ :  Int;
+
+    /**
+     * Underlying transport
+     */
+    var transport_ :  TTransport = null;
+
+    /**
+     * Buffer for output
+     */
+    var writeBuffer_ : BytesOutput = new BytesOutput();
+
+    /**
+     * Buffer for input
+     */
+    var readBuffer_ : BytesInput = null;
+
+    /**
+     * Constructor wraps around another transport
+     */
+    public function new( transport : TTransport, maxLength : Int = DEFAULT_MAX_LENGTH) {
+        transport_ = transport;
+        maxLength_ = maxLength;
+    }
+
+    public override function open() : Void {
+        transport_.open();
+    }
+
+    public override function isOpen() : Bool {
+        return transport_.isOpen();
+    }
+
+    public override function close() : Void {
+        transport_.close();
+    }
+
+    public override function read(buf : BytesBuffer, off : Int, len : Int) : Int {
+        try {
+            var data = Bytes.alloc(len);
+
+            if ((readBuffer_ != null) && (readBuffer_.position < readBuffer_.length)) {
+                var got : Int = readBuffer_.readBytes(data, off, len);
+                if (got > 0) {
+                    buf.addBytes(data,0,got);
+                    return got;
+                };
+            };
+
+            // Read another frame of data
+            readFrame();
+
+            var got = readBuffer_.readBytes(data, off, len);
+            buf.addBytes(data,0,got);
+            return got;
+        }
+        catch (eof : Eof) {
+            throw new TTransportException(TTransportException.END_OF_FILE, 'Can\'t read $len bytes!');
+        }
+    }
+
+
+    function readFrameSize() : Int {
+        try {
+            var buffer = new BytesBuffer();
+            var len = transport_.readAll( buffer, 0, 4);
+            var inp = new BytesInput( buffer.getBytes(), 0, 4);
+            inp.bigEndian = true;
+            return inp.readInt32();
+        }
+        catch(eof : Eof) {
+            throw new TTransportException(TTransportException.END_OF_FILE, 'Can\'t read 4 bytes!');
+        }
+    }
+
+
+    function readFrame() : Void {
+        var size : Int = readFrameSize();
+
+        if (size < 0) {
+            throw new TTransportException(TTransportException.UNKNOWN, 'Read a negative frame size ($size)!');
+        };
+        if (size > maxLength_) {
+            throw new TTransportException(TTransportException.UNKNOWN, 'Frame size ($size) larger than max length ($maxLength_)!');
+        };
+
+        try {
+            var buffer = new BytesBuffer();
+            size = transport_.readAll( buffer, 0, size);
+            readBuffer_ = new BytesInput( buffer.getBytes(), 0, size);
+            readBuffer_.bigEndian = true;
+        }
+        catch(eof : Eof) {
+            throw new TTransportException(TTransportException.END_OF_FILE, 'Can\'t read $size bytes!');
+        }
+    }
+
+    public override function write(buf : Bytes, off : Int, len : Int) : Void {
+        writeBuffer_.writeBytes(buf, off, len);
+    }
+
+    function writeFrameSize(len : Int) : Void {
+        var out = new BytesOutput();
+        out.bigEndian = true;
+        out.writeInt32(len);
+        transport_.write(out.getBytes(), 0, 4);
+    }
+
+    public override function flush( callback : Dynamic->Void =null) : Void {
+        var buf : Bytes = writeBuffer_.getBytes();
+        var len : Int = buf.length;
+        writeBuffer_ = new BytesOutput();
+
+        writeFrameSize(len);
+        transport_.write(buf, 0, len);
+        transport_.flush(callback);
+    }
+}
+
+
diff --git a/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx b/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx
new file mode 100644
index 0000000..8d45a64
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TFramedTransportFactory.hx
@@ -0,0 +1,37 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import org.apache.thrift.transport.*;
+
+
+class TFramedTransportFactory extends TTransportFactory {
+
+    var maxLength_ : Int;
+
+    public function new(maxLength : Int = TFramedTransport.DEFAULT_MAX_LENGTH) {
+        super();
+        maxLength_ = maxLength;
+    }
+
+    public override function getTransport(base : TTransport) : TTransport {
+        return new TFramedTransport(base, maxLength_);
+    }
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx
new file mode 100644
index 0000000..1972853
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TFullDuplexHttpClient.hx
@@ -0,0 +1,253 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import flash.errors.EOFError;
+import flash.events.Event;
+import flash.events.IOErrorEvent;
+import flash.events.ProgressEvent;
+import flash.events.SecurityErrorEvent;
+import flash.net.URLLoader;
+import flash.net.URLLoaderDataFormat;
+import flash.net.URLRequest;
+import flash.net.URLRequestMethod;
+import flash.utils.IDataInput;
+import flash.utils.IDataOutput;
+import haxe.io.Bytes;
+import flash.net.Socket;
+import flash.events.EventDispatcher;
+
+
+    /**
+     * HTTP implementation of the TTransport interface. Used for working with a
+     * Thrift web services implementation.
+     * Unlike Http Client, it uses a single POST, and chunk-encoding to transfer all messages.
+     */
+
+    public class TFullDuplexHttpClient extends TTransport
+    {
+        private var socket : Socket = null;
+        private var host  :  String;
+        private var port  :  Int;
+        private var resource  :  String;
+        private var stripped  :  Bool = false;
+        private var obuffer : Bytes = new Bytes();
+        private var input : IDataInput;
+        private var output : IDataOutput;
+        private var bytesInChunk  :  Int = 0;
+        private var CRLF : Bytes = new Bytes();
+        private var ioCallback : TException->Void = null;
+        private var eventDispatcher : EventDispatcher = new EventDispatcher();
+
+        public function new(host  :  String, port  :  Int, resource  :  String)  :  Void
+        {
+            CRLF.writeByte(13);
+            CRLF.writeByte(10);
+            this.host = host;
+            this.port = port;
+            this.resource = resource;
+        }
+
+        public override function close()  :  Void
+        {
+            this.input = null;
+            this.output = null;
+            this.stripped = false;
+            socket.close()
+        }
+
+        public override function peek()  :  Bool
+        {
+            if(socket.connected)
+            {
+                trace("Bytes remained:" + socket.bytesAvailable);
+                return socket.bytesAvailable>0;
+            }
+            return false;
+        }
+
+        public override function read(buf : Bytes, off  :  Int, len  :  Int)  :  Int
+        {
+            var n1  :  Int = 0, n2  :  Int = 0, n3  :  Int = 0, n4  :  Int = 0, cidx  :  Int = 2;
+            var chunkSize : Bytes = new Bytes();
+
+            try
+            {
+                while (!stripped)
+                {
+                    n1 = n2;
+                    n2 = n3;
+                    n3 = n4;
+                    n4 = input.readByte();
+                    if ((n1 == 13) && (n2 == 10) && (n3 == 13) && (n4 == 10))
+                    {
+                        stripped = true;
+                    }
+                }
+
+                // read chunk size
+                if (bytesInChunk == 0)
+                {
+                    n1 = input.readByte();
+                    n2 = input.readByte();
+
+                    chunkSize.writeByte(n1);
+                    chunkSize.writeByte(n2);
+
+                    while (!((n1 == 13) && (n2 == 10)))
+                    {
+                        n1 = n2;
+                        n2 = input.readByte();
+                        chunkSize.writeByte(n2);
+                    }
+
+                    bytesInChunk = parseInt(chunkSize.toString(), 16);
+                }
+
+                input.readBytes(buf, off, len);
+                debugBuffer(buf);
+                bytesInChunk -= len;
+
+                if (bytesInChunk == 0)
+                {
+                    // advance the  :  "\r\n"
+                    input.readUTFBytes(2);
+                }
+                return len;
+            }
+            catch (e : EOFError)
+            {
+                trace(e);
+                throw new TTransportException(TTransportException.UNKNOWN, "No more data available.");
+            }
+            catch (e : TException)
+            {
+                trace('TException $e');
+                throw e;
+            }
+            catch (e : Error)
+            {
+                trace(e);
+                throw new TTransportException(TTransportException.UNKNOWN, 'Bad IO error: $e');
+            }
+            catch (e : Dynamic)
+            {
+                trace(e);
+                throw new TTransportException(TTransportException.UNKNOWN, 'Bad IO error: $e');
+            }
+            return 0;
+        }
+
+        public function debugBuffer(buf : Bytes)  :  Void
+        {
+            var debug  :  String = "BUFFER >>";
+            var i  :  Int;
+            for (i = 0; i < buf.length; i++)
+            {
+                debug += buf[i] as int;
+                debug += " ";
+            }
+
+            trace(debug + "<<");
+        }
+
+        public override function write(buf : Bytes, off  :  Int, len  :  Int)  :  Void
+        {
+            obuffer.writeBytes(buf, off, len);
+        }
+
+        public function addEventListener(type  :  String, listener : Function, useCapture  :  Bool = false, priority  :  Int = 0, useWeakReference  :  Bool = false)  :  Void
+        {
+            this.eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
+        }
+
+        public override function open()  :  Void
+        {
+            this.socket = new Socket();
+            this.socket.addEventListener(Event.CONNECT, socketConnected);
+            this.socket.addEventListener(IOErrorEvent.IO_ERROR, socketError);
+            this.socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, socketSecurityError);
+            this.socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
+            this.socket.connect(host, port);
+        }
+
+        public function socketConnected(event : Event)  :  Void
+        {
+            this.output = this.socket;
+            this.input = this.socket;
+            this.output.writeUTF( "CONNECT " + resource + " HTTP/1.1\n"
+                                + "Host :  " + host + ":" + port + "\r\n"
+                                + "User-Agent :  Thrift/Haxe\r\n"
+                                + "Transfer-Encoding :  chunked\r\n"
+                                + "content-type :  application/x-thrift\r\n"
+                                + "Accept :  */*\r\n"
+                                + "\r\n");
+            this.eventDispatcher.dispatchEvent(event);
+        }
+
+        public function socketError(event : IOErrorEvent)  :  Void
+        {
+            trace("Error Connecting:" + event);
+            this.close();
+            if (ioCallback == null)
+            {
+                return;
+            }
+            ioCallback(new TTransportException(TTransportException.UNKNOWN, "IOError :  " + event.text));
+            this.eventDispatcher.dispatchEvent(event);
+        }
+
+        public function socketSecurityError(event : SecurityErrorEvent)  :  Void
+        {
+            trace("Security Error Connecting:" + event);
+            this.close();
+            this.eventDispatcher.dispatchEvent(event);
+        }
+
+        public function socketDataHandler(event : ProgressEvent)  :  Void
+        {
+            trace("Got Data call:" +ioCallback);
+            if (ioCallback != null)
+            {
+                ioCallback(null);
+            };
+            this.eventDispatcher.dispatchEvent(event);
+        }
+
+        public override function flush(callback : Error->Void = null)  :  Void
+        {
+            trace("set callback:" + callback);
+            this.ioCallback = callback;
+            this.output.writeUTF(this.obuffer.length.toString(16));
+            this.output.writeBytes(CRLF);
+            this.output.writeBytes(this.obuffer);
+            this.output.writeBytes(CRLF);
+            this.socket.flush();
+            // waiting for  new Flex sdk 3.5
+            //this.obuffer.clear();
+            this.obuffer = new Bytes();
+        }
+
+        public override function isOpen()  :  Bool
+        {
+            return (this.socket == null ? false  :  this.socket.connected);
+        }
+
+}
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx
new file mode 100644
index 0000000..79f8661
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/THttpClient.hx
@@ -0,0 +1,103 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+import haxe.io.BytesOutput;
+import haxe.io.BytesInput;
+
+import haxe.Http;
+
+
+
+/**
+* HTTP implementation of the TTransport interface. Used for working with a
+* Thrift web services implementation.
+*/
+
+class THttpClient extends TTransport {
+
+    private var requestBuffer_  : BytesOutput = new BytesOutput();
+    private var responseBuffer_ : BytesInput = null;
+
+    private var request_        : Http = null;
+
+
+    public function new( requestUrl : String) : Void {
+          request_ = new Http(requestUrl);
+        request_.addHeader( "contentType", "application/x-thrift");
+    }
+
+
+    public override function open() : Void {
+    }
+
+    public override function close() : Void {
+    }
+
+    public override function isOpen() : Bool {
+      return true;
+    }
+
+    public override function read(buf:BytesBuffer, off : Int, len : Int) : Int {
+        if (responseBuffer_ == null) {
+            throw new TTransportException(TTransportException.UNKNOWN, "Response buffer is empty, no request.");
+        }
+
+        var data =Bytes.alloc(len);
+        len = responseBuffer_.readBytes(data, off, len);
+        buf.addBytes(data,0,len);
+        return len;
+    }
+
+    public override function write(buf:Bytes, off : Int, len : Int) : Void {
+      requestBuffer_.writeBytes(buf, off, len);
+    }
+
+
+    public override function flush(callback:Dynamic->Void = null) : Void {
+        var buffer = requestBuffer_;
+        requestBuffer_ = new BytesOutput();
+        responseBuffer_ = null;
+
+        request_.onData = function(data : String) {
+            var tmp = new BytesBuffer();
+            tmp.addString(data);
+            responseBuffer_ = new BytesInput(tmp.getBytes());
+            if( callback != null) {
+                callback(null);
+            }
+        };
+
+        request_.onError = function(msg : String) {
+            if( callback != null) {
+                callback(new TTransportException(TTransportException.UNKNOWN, "IOError: " + msg));
+            }
+        };
+
+        request_.setPostData(buffer.getBytes().toString());
+        request_.request(true/*POST*/);
+    }
+
+}
+
+    
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx
new file mode 100644
index 0000000..4badb2a
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TServerSocket.hx
@@ -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 org.apache.thrift.transport;
+
+import haxe.remoting.SocketProtocol;
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+import haxe.io.BytesInput;
+import haxe.io.BytesOutput;
+import haxe.io.Input;
+import haxe.io.Output;
+import haxe.io.Eof;
+
+//import flash.net.ServerSocket; - not yet available on Haxe 3.1.3
+#if ! (flash || html5)
+
+import sys.net.Host;
+
+
+class TServerSocket extends TServerTransport {
+
+    // Underlying server with socket
+    private var _socket : Socket= null;
+
+    // Timeout for client sockets from accept
+    private var _clientTimeout : Float = 5;
+
+    // Whether or not to wrap new TSocket connections in buffers
+    private var _useBufferedSockets : Bool = false;
+
+
+    public function new(?address : String = 'localhost',  port : Int, clientTimeout : Float = 5, useBufferedSockets : Bool = false)
+    {
+        _clientTimeout = clientTimeout;
+        _useBufferedSockets = useBufferedSockets;
+
+        try
+        {
+            _socket = new Socket();
+            _socket.bind( new Host(address), port);
+        }
+        catch (e : Dynamic)
+        {
+            _socket = null;
+            throw new TTransportException( TTransportException.UNKNOWN, 'Could not create ServerSocket on port $port: $e');
+        }
+    }
+
+
+    public override function Listen() : Void
+    {
+        // Make sure not to block on accept
+        if (_socket != null)    {
+            try
+            {
+                #if !php
+                _socket.listen(1);
+                #end
+            }
+            catch (e : Dynamic)
+            {
+                trace('Error $e');
+                throw new TTransportException( TTransportException.UNKNOWN, 'Could not accept on listening socket: $e');
+            }
+        }
+    }
+
+    private override function AcceptImpl() : TTransport
+    {
+        if (_socket == null) {
+            throw new TTransportException( TTransportException.NOT_OPEN, "No underlying server socket.");
+        }
+
+        try
+        {
+            var accepted = _socket.accept();
+            var result = TSocket.fromSocket(accepted);
+            result.setTimeout( _clientTimeout);
+
+            if( _useBufferedSockets)
+            {
+                throw "buffered transport not yet supported";  // TODO
+                //result = new TBufferedTransport(result);
+            }
+
+            return result;
+        }
+        catch (e : Dynamic)
+        {
+            trace('Error $e');
+            throw new TTransportException( TTransportException.UNKNOWN, '$e');
+        }
+    }
+
+    public override function Close() : Void
+    {
+        if (_socket != null)
+        {
+            try
+            {
+                _socket.close();
+            }
+            catch (e : Dynamic)
+            {
+                trace('Error $e');
+                throw new TTransportException( TTransportException.UNKNOWN, 'WARNING: Could not close server socket: $e');
+            }
+            _socket = null;
+        }
+    }
+}
+
+#end
diff --git a/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx
new file mode 100644
index 0000000..2189981
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TServerTransport.hx
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+class TServerTransport {
+
+    public function Accept() : TTransport {
+        var transport = AcceptImpl();
+        if (transport == null) {
+          throw new TTransportException( TTransportException.UNKNOWN, "accept() may not return NULL");
+        }
+        return transport;
+    }
+
+    public function Listen() : Void {
+        throw new AbstractMethodError();
+    }
+
+    public function Close() : Void {
+        throw new AbstractMethodError();
+    }
+
+    private function AcceptImpl() : TTransport {
+        throw new AbstractMethodError();
+    }
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TSocket.hx b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx
new file mode 100644
index 0000000..7941ab9
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TSocket.hx
@@ -0,0 +1,318 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+#if flash
+import flash.net.Socket;
+#elseif js
+import js.html.WebSocket;
+#else
+import haxe.remoting.SocketProtocol;
+#end
+
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+import haxe.io.BytesInput;
+import haxe.io.BytesOutput;
+import haxe.io.Input;
+import haxe.io.Output;
+import haxe.io.Eof;
+
+
+#if ! (flash || js)
+import sys.net.Host;
+#end
+
+
+  /**
+   * Socket implementation of the TTransport interface. Used for working with a
+   * Thrift Socket Server based implementations.
+   */
+
+class TSocket extends TTransport  {
+
+    #if (flash || js)
+    private var host  :  String;
+    #else
+    private var host  :  Host;
+    #end
+
+    private var port  :  Int;
+
+    #if js
+    private var socket : WebSocket = null;
+    #else
+    private var socket : Socket = null;
+    #end
+
+    #if js
+    private var input : Dynamic = null;
+    private var output : WebSocket = null;
+    #elseif flash
+    private var input : Socket = null;
+    private var output : Socket = null;
+    #else
+    private var input : Input = null;
+    private var output : Output = null;
+    #end
+
+    private var timeout : Float = 30;
+
+    private var obuffer : BytesOutput = new BytesOutput();
+    private var ioCallback : TException->Void = null;
+    private var readCount : Int = 0;
+
+    public function new(host : String, port  :  Int)  :  Void  {
+        #if (flash || js)
+        this.host = host;
+        #else
+        this.host = new Host(host);
+        #end
+
+        this.port = port;
+    }
+
+    #if ! (flash || js)
+    // used by TSocketServer
+    public static function fromSocket( socket : Socket) : TSocket  {
+        var socketHost = socket.host();
+        var result = new TSocket(socketHost.host.toString(), socketHost.port);
+        result.assignSocket(socket);
+        return result;
+    }
+    #end
+
+    public override function close()  :  Void  {
+        input = null;
+        output = null;
+        socket.close();
+    }
+
+    public override function peek()  :  Bool  {
+        if( (input == null) || (socket == null)) {
+            return false;
+        } else {
+            #if flash
+            return (input.bytesAvailable > 0);
+            #elseif js
+            return true;
+            #else
+            var ready = Socket.select( [socket], null, null, 0);
+            return (ready.read.length > 0);
+            #end
+        }
+    }
+
+    // Reads up to len bytes into buffer buf, starting att offset off.
+    // May return less bytes than len required
+    public override function read( buf : BytesBuffer, off : Int, len : Int) : Int   {
+        try
+        {
+            #if flash
+
+            var remaining = len;
+            while( remaining > 0) {
+                buf.addByte( input.readByte());
+                --remaining;
+            }
+            return len;
+
+            #elseif js
+
+            if( input == null) {
+                throw new TTransportException(TTransportException.UNKNOWN, "Still no data ");  // don't block
+            }
+            var nr = len;
+            while( nr < len) {
+                buf.addByte( input.get(off+nr));
+                ++nr;
+            }
+            return len;
+
+            #else
+
+            //socket.waitForRead();  -  no, this ignores timeout and blocks infinitely
+            if(readCount < off) {
+                input.read(off-readCount);
+                readCount = off;
+            }
+
+            var data = Bytes.alloc(len);
+            var got = input.readBytes(data, 0, len);
+            buf.addBytes( data, 0, got);
+            readCount += got;
+            return got;
+
+            #end
+        }
+        catch (e : Eof)
+        {
+            trace('Eof $e');
+            throw new TTransportException(TTransportException.END_OF_FILE, "No more data available.");
+        }
+        catch (e : TException)
+        {
+            trace('TException $e');
+            throw e;
+        }
+        catch (e : Dynamic)
+        {
+            trace('Error $e');
+            throw new TTransportException(TTransportException.UNKNOWN, 'Bad IO error : $e');
+        }
+    }
+
+
+    public override function write(buf : Bytes, off  :  Int, len  :  Int)  :  Void
+    {
+        obuffer.writeBytes(buf, off, len);
+    }
+
+
+
+    public override function flush(callback : Dynamic->Void = null)  :  Void
+    {
+        if( ! isOpen())
+        {
+            throw new TTransportException(TTransportException.NOT_OPEN, "Transport not open");
+        }
+
+        #if flash
+
+        var bytes = new flash.utils.ByteArray();
+        var data = obuffer.getBytes();
+        var len = 0;
+        while( len < data.length) {
+            bytes.writeByte(data.get(len));
+            ++len;
+        }
+
+        #elseif js
+
+        var data = obuffer.getBytes();
+        var outbuf = new js.html.Int8Array(data.length);
+        var len = 0;
+        while( len < data.length) {
+            outbuf.set( [data.get(len)], len);
+            ++len;
+        }
+        var bytes = outbuf.buffer;
+
+        #else
+
+        var bytes = obuffer.getBytes();
+        var len = bytes.length;
+
+        #end
+
+        obuffer = new BytesOutput();
+
+
+        ioCallback = callback;
+        try {
+            readCount = 0;
+
+            #if js
+            output.send( bytes);
+            #else
+            output.writeBytes( bytes, 0, bytes.length);
+            #end
+
+            if(ioCallback != null) {
+                ioCallback(null);  // success call
+            }
+        }
+        catch (e : TException)
+        {
+            trace('TException $e, message : ${e.errorMsg}');
+            if(ioCallback != null) {
+                ioCallback(e);
+            }
+        }
+        catch (e : Dynamic) {
+            trace(e);
+            if(ioCallback != null) {
+                ioCallback(new TTransportException(TTransportException.UNKNOWN, 'Bad IO error : $e'));
+            }
+        }
+    }
+
+    public override function isOpen()  :  Bool
+    {
+        return (socket != null);
+    }
+
+    public override function open()  :  Void
+    {
+        #if js
+        var socket = new WebSocket();
+        socket.onmessage = function( event : js.html.MessageEvent) {
+            this.input = event.data;
+        }
+
+        #elseif flash
+        var socket = new Socket();
+        socket.connect(host, port);
+
+        #elseif php
+        var socket = new Socket();
+        socket.connect(host, port);
+        socket.setBlocking(true);
+        socket.setTimeout(timeout);
+
+        #else
+        var socket = new Socket();
+        socket.setBlocking(true);
+        socket.setFastSend(true);
+        socket.setTimeout(timeout);
+        socket.connect(host, port);
+
+        #end
+
+        assignSocket( socket);
+    }
+
+    #if js
+    private function assignSocket( socket : WebSocket)  :  Void
+    #else
+    private function assignSocket( socket : Socket)  :  Void
+    #end
+    {
+        this.socket = socket;
+
+        #if (flash || js)
+        output = socket;
+        input = socket;
+
+        #else
+        output = socket.output;
+        input = socket.input;
+
+        #end
+    }
+
+    public function setTimeout( timeout : Float ) : Void {
+        if(isOpen()) {
+            socket.setTimeout(timeout);
+        }
+        this.timeout = timeout;
+    }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TStream.hx b/lib/haxe/src/org/apache/thrift/transport/TStream.hx
new file mode 100644
index 0000000..50b3ed3
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TStream.hx
@@ -0,0 +1,32 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+
+
+interface TStream {
+    function Close() : Void;
+    function Peek() : Bool;
+    function Read( buf : Bytes, offset : Int, count : Int) : Int;
+    function Write( buf : Bytes, offset : Int, count : Int) : Void;
+    function Flush() : Void;
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TStreamTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TStreamTransport.hx
new file mode 100644
index 0000000..31a7c14
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TStreamTransport.hx
@@ -0,0 +1,103 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import org.apache.thrift.transport.*;
+import org.apache.thrift.helper.*;
+
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+import haxe.io.BytesOutput;
+import haxe.io.BytesInput;
+
+
+class TStreamTransport extends TTransport {
+
+    public var InputStream(default,null) : TStream;
+    public var OutputStream(default,null) : TStream;
+
+
+    public function new( input : TStream, output : TStream) {
+        this.InputStream = input;
+        this.OutputStream = output;
+    }
+
+    public override function isOpen() : Bool {
+        return true;
+    }
+
+    public override function peek() : Bool {
+        return (InputStream != null);
+    }
+
+    public override function open() : Void {
+    }
+
+    public override function close() : Void {
+        if (InputStream != null)
+        {
+            InputStream.Close();
+            InputStream = null;
+        }
+        if (OutputStream != null)
+        {
+            OutputStream.Close();
+            OutputStream = null;
+        }
+    }
+
+    public override function read( buf : BytesBuffer, off : Int, len : Int) : Int {
+        if (InputStream == null)
+        {
+            throw new TTransportException( TTransportException.NOT_OPEN,
+                                             "Cannot read from null InputStream");
+        }
+
+        var data : Bytes =  Bytes.alloc(len);
+        var size = InputStream.Read( data, off, len);
+        buf.addBytes( data, 0, size);
+        return size;
+    }
+
+    public override function write(buf:Bytes, off : Int, len : Int) : Void {
+        if (OutputStream == null)
+        {
+            throw new TTransportException( TTransportException.NOT_OPEN,
+                                           "Cannot write to null OutputStream");
+        }
+
+        OutputStream.Write(buf, off, len);
+    }
+
+    public override function flush(callback:Dynamic->Void =null) : Void {
+        if (OutputStream == null)
+        {
+            var err = new TTransportException( TTransportException.NOT_OPEN,
+                                               "Cannot flush null OutputStream");
+            if(callback != null)
+                callback(err);
+            else
+                throw err;
+        }
+
+        OutputStream.Flush();
+    }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TTransport.hx
new file mode 100644
index 0000000..e6b3179
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TTransport.hx
@@ -0,0 +1,139 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import haxe.io.Eof;
+import haxe.io.Bytes;
+import haxe.io.BytesBuffer;
+import org.apache.thrift.AbstractMethodError;
+
+class TTransport {
+
+    /**
+     * Queries whether the transport is open.
+     *
+     * @return True if the transport is open.
+     */
+    public function isOpen() : Bool {
+          throw new AbstractMethodError();
+    }
+
+    /**
+     * Is there more data to be read?
+     *
+     * @return True if the remote side is still alive and feeding us
+     */
+    public function peek() : Bool {
+          return isOpen();
+    }
+
+    /**
+     * Opens the transport for reading/writing.
+     *
+     * @throws TTransportException if the transport could not be opened
+     */
+    public function open() : Void {
+          throw new AbstractMethodError();
+    }
+
+    /**
+     * Closes the transport.
+     */
+    public function close() : Void {
+          throw new AbstractMethodError();
+    };
+
+    /**
+     * 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 bytes count actually read
+     * @throws TTransportException if there was an error reading data
+     */
+     public function read( buf : BytesBuffer, off : Int, len : Int) : Int {
+          throw new AbstractMethodError();
+     }
+
+    /**
+     * 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
+     * @throws TTransportException if there was an error reading data
+     */
+    public function readAll(buf : BytesBuffer, off : Int, len : Int) : Int {
+        var got : Int = 0;
+        var ret : Int = 0;
+        while (got < len) {
+          try {
+            ret = read(buf, off+got, len-got);
+            if (ret <= 0) {
+              throw new TTransportException(TTransportException.UNKNOWN,
+                          "Cannot read. Remote side has closed. Tried to read "
+                          + len + " bytes, but only got " + got + " bytes.");
+            }
+          }
+          catch (eof : Eof) {
+            throw new TTransportException(TTransportException.END_OF_FILE, 'Can\'t read $len bytes!');
+          }
+          got += ret;
+        }
+        return got;
+    }
+
+    /**
+     * Writes the buffer to the output
+     *
+     * @param buf The output data buffer
+     * @throws TTransportException if an error occurs writing data
+     */
+    public function writeAll(buf:Bytes) : Void {
+        write(buf, 0, buf.length);
+    }
+
+    /**
+     * Writes up to len bytes from the buffer.
+     *
+     * @param buf The output data buffer
+     * @param off The offset to start writing from
+     * @param len The number of bytes to write
+     * @throws TTransportException if there was an error writing data
+     */
+    public function write(buf:Bytes, off : Int, len : Int) : Void {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Flush any pending data out of a transport buffer.
+     *
+     * @throws TTransportException if there was an error writing out data.
+     */
+    public function flush(callback:Dynamic->Void =null) : Void {
+        if(callback != null)
+            callback(new AbstractMethodError());
+        else
+            throw new AbstractMethodError();
+    }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TTransportException.hx b/lib/haxe/src/org/apache/thrift/transport/TTransportException.hx
new file mode 100644
index 0000000..ad028dd
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TTransportException.hx
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import org.apache.thrift.TException;
+
+class TTransportException extends TException {
+
+    // WARNING: These are subject to be extended in the future, so we can't use enums
+    // with Haxe 3.1.3 because of https://github.com/HaxeFoundation/haxe/issues/3649
+    public static inline var UNKNOWN : Int = 0;
+    public static inline var NOT_OPEN : Int = 1;
+    public static inline var ALREADY_OPEN : Int = 2;
+    public static inline var TIMED_OUT : Int = 3;
+    public static inline var END_OF_FILE : Int = 4;
+
+    public function new(error : Int = UNKNOWN, message : String = "") {
+        super(message, error);
+    }
+
+}
+ 
\ No newline at end of file
diff --git a/lib/haxe/src/org/apache/thrift/transport/TTransportFactory.hx b/lib/haxe/src/org/apache/thrift/transport/TTransportFactory.hx
new file mode 100644
index 0000000..361f35f
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TTransportFactory.hx
@@ -0,0 +1,44 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+/**
+ * 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)
+ *
+ */
+class TTransportFactory {
+
+    public function new() {
+    }
+
+    /**
+    * Return a wrapped instance of the base Transport.
+    *
+    * @param trans The base transport
+    * @return Wrapped Transport
+    */
+    public function getTransport( trans : TTransport) : TTransport {
+        return trans;
+    }
+
+}
diff --git a/lib/haxe/src/org/apache/thrift/transport/TWrappingServerTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TWrappingServerTransport.hx
new file mode 100644
index 0000000..b2272f3
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/transport/TWrappingServerTransport.hx
@@ -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 org.apache.thrift.transport;
+
+
+/*
+   wraps real transport, provided by constructor
+*/
+class TWrappingServerTransport extends TServerTransport {
+
+  private var transport(default,null) : TTransport;
+
+  public function new(transport : TTransport) {
+    this.transport = transport;
+  }
+
+  public override function Listen() : Void
+  {
+  }
+
+  private override function AcceptImpl() : TTransport
+  {
+    return transport;
+  }
+
+  public override function Close() : Void
+  {
+
+  }
+}
diff --git a/lib/haxe/test/HaxeTests.hxproj b/lib/haxe/test/HaxeTests.hxproj
new file mode 100644
index 0000000..3beed82
--- /dev/null
+++ b/lib/haxe/test/HaxeTests.hxproj
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project version="2">
+  <!-- Output SWF options -->
+  <output>
+    <movie outputType="Application" />
+    <movie input="" />
+    <movie path="bin/HaxeTests" />
+    <movie fps="30" />
+    <movie width="800" />
+    <movie height="600" />
+    <movie version="1" />
+    <movie minorVersion="0" />
+    <movie platform="C++" />
+    <movie background="#FFFFFF" />
+  </output>
+  <!-- Other classes to be compiled into your SWF -->
+  <classpaths>
+    <class path="src" />
+    <class path="gen-haxe" />
+    <class path="../src" />
+  </classpaths>
+  <!-- Build options -->
+  <build>
+    <option directives="" />
+    <option flashStrict="False" />
+    <option noInlineOnDebug="False" />
+    <option mainClass="Main" />
+    <option enabledebug="False" />
+    <option additional="" />
+  </build>
+  <!-- haxelib libraries -->
+  <haxelib>
+    <!-- example: <library name="..." /> -->
+  </haxelib>
+  <!-- Class files to compile (other referenced classes will automatically be included) -->
+  <compileTargets>
+    <!-- example: <compile path="..." /> -->
+  </compileTargets>
+  <!-- Paths to exclude from the Project Explorer tree -->
+  <hiddenPaths>
+    <hidden path="obj" />
+    <hidden path="cpp.hxml" />
+    <hidden path="csharp.hxml" />
+    <hidden path="flash.hxml" />
+    <hidden path="java.hxml" />
+    <hidden path="javascript.hxml" />
+    <hidden path="make_all.bat" />
+    <hidden path="make_all.sh" />
+    <hidden path="Makefile.am" />
+    <hidden path="neko.hxml" />
+    <hidden path="php.hxml" />
+    <hidden path="project.hide" />
+    <hidden path="python.hxml" />
+  </hiddenPaths>
+  <!-- Executed before build -->
+  <preBuildCommand>thrift -r -gen haxe  ../../../test/ThriftTest.thrift
+thrift -r -gen haxe  ../../../contrib/async-test/aggr.thrift
+thrift -r -gen haxe  ../../../lib/rb/benchmark/Benchmark.thrift</preBuildCommand>
+  <!-- Executed after build -->
+  <postBuildCommand alwaysRun="False" />
+  <!-- Other project options -->
+  <options>
+    <option showHiddenPaths="False" />
+    <option testMovie="Custom" />
+    <option testMovieCommand="bin/HaxeTests/Main.exe server multiplex" />
+  </options>
+  <!-- Plugin storage -->
+  <storage />
+</project>
\ No newline at end of file
diff --git a/lib/haxe/test/Makefile.am b/lib/haxe/test/Makefile.am
new file mode 100644
index 0000000..2b8b245
--- /dev/null
+++ b/lib/haxe/test/Makefile.am
@@ -0,0 +1,85 @@
+#
+# 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.
+#
+
+THRIFTCMD = $(THRIFT) --gen haxe -r
+THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift
+AGGR = $(top_srcdir)/contrib/async-test/aggr.thrift
+BENCHMARK = $(top_srcdir)/lib/rb/benchmark/Benchmark.thrift
+
+BIN_CPP = bin/Main-debug
+BIN_PHP = bin/php/Main-debug.php
+
+gen-haxe/thrift/test/ThriftTest.hx: $(THRIFTTEST)
+	$(THRIFTCMD) $(THRIFTTEST)
+
+gen-haxe/thrift/test/Aggr.hx: $(AGGR)
+	$(THRIFTCMD) $(AGGR)
+
+gen-haxe/thrift/test/BenchmarkService.hx: $(BENCHMARK)
+	$(THRIFTCMD) $(BENCHMARK)
+
+all-local: $(BIN_CPP) $(BIN_PHP)
+
+$(BIN_CPP): \
+		src/*.hx \
+		../src/org/apache/thrift/**/*.hx \
+		gen-haxe/thrift/test/ThriftTest.hx \
+		gen-haxe/thrift/test/Aggr.hx \
+		gen-haxe/thrift/test/BenchmarkService.hx
+	$(HAXE) --cwd .  cpp.hxml
+
+$(BIN_PHP): \
+		src/*.hx \
+		../src/org/apache/thrift/**/*.hx \
+		gen-haxe/thrift/test/ThriftTest.hx \
+		gen-haxe/thrift/test/Aggr.hx \
+		gen-haxe/thrift/test/BenchmarkService.hx
+	$(HAXE) --cwd .  php.hxml
+
+
+#TODO: other haxe targets
+#    $(HAXE)  --cwd .  csharp
+#    $(HAXE)  --cwd .  flash
+#    $(HAXE)  --cwd .  java
+#    $(HAXE)  --cwd .  javascript
+#    $(HAXE)  --cwd .  neko
+#    $(HAXE)  --cwd .  python  # needs Haxe 3.2.0
+
+
+clean-local:
+	$(RM) -r gen-haxe bin
+
+check: $(BIN_CPP) $(BIN_PHP)
+	$(BIN_CPP)
+	php -f $(BIN_PHP)
+
+EXTRA_DIST = \
+             src \
+             cpp.hxml \
+             csharp.hxml \
+             flash.hxml \
+             java.hxml \
+             javascript.hxml \
+             neko.hxml \
+             php.hxml \
+             python.hxml \
+             project.hide \
+             HaxeTests.hxproj \
+             make_all.bat \
+             make_all.sh
diff --git a/lib/haxe/test/cpp.hxml b/lib/haxe/test/cpp.hxml
new file mode 100644
index 0000000..73848a8
--- /dev/null
+++ b/lib/haxe/test/cpp.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp ../src
+-cp gen-haxe
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#CPP target
+-cpp bin
+
+#To produce 64 bit binaries the file should define the HXCPP_M64 compile variable:
+#-D HXCPP_M64
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/lib/haxe/test/csharp.hxml b/lib/haxe/test/csharp.hxml
new file mode 100644
index 0000000..4c34b0d
--- /dev/null
+++ b/lib/haxe/test/csharp.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp ../src
+-cp gen-haxe
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#CSHARP target
+-cs bin/Test.exe
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/lib/haxe/test/flash.hxml b/lib/haxe/test/flash.hxml
new file mode 100644
index 0000000..8b17631
--- /dev/null
+++ b/lib/haxe/test/flash.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp ../src
+-cp gen-haxe
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Flash target
+-swf bin/Test.swf
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/lib/haxe/test/java.hxml b/lib/haxe/test/java.hxml
new file mode 100644
index 0000000..c947159
--- /dev/null
+++ b/lib/haxe/test/java.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp ../src
+-cp gen-haxe
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Java target
+-java bin/Test.jar
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/lib/haxe/test/javascript.hxml b/lib/haxe/test/javascript.hxml
new file mode 100644
index 0000000..18d9964
--- /dev/null
+++ b/lib/haxe/test/javascript.hxml
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp ../src
+-cp gen-haxe
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#JavaScript target
+-js bin/Test.js
+
+#You can use -D source-map-content (requires Haxe 3.1+) to have the .hx 
+#files directly embedded into the map file, this way you only have to 
+#upload it, and it will be always in sync with the compiled .js even if 
+#you modify your .hx files.
+-D source-map-content
+
+#Generate source map and add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/lib/haxe/test/make_all.bat b/lib/haxe/test/make_all.bat
new file mode 100644
index 0000000..0314e18
--- /dev/null
+++ b/lib/haxe/test/make_all.bat
@@ -0,0 +1,70 @@
+@echo off
+rem /*
+rem  * Licensed to the Apache Software Foundation (ASF) under one
+rem  * or more contributor license agreements. See the NOTICE file
+rem  * distributed with this work for additional information
+rem  * regarding copyright ownership. The ASF licenses this file
+rem  * to you under the Apache License, Version 2.0 (the
+rem  * "License"); you may not use this file except in compliance
+rem  * with the License. You may obtain a copy of the License at
+rem  *
+rem  *   http://www.apache.org/licenses/LICENSE-2.0
+rem  *
+rem  * Unless required by applicable law or agreed to in writing,
+rem  * software distributed under the License is distributed on an
+rem  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem  * KIND, either express or implied. See the License for the
+rem  * specific language governing permissions and limitations
+rem  * under the License.
+rem  */
+
+setlocal
+if "%HOMEDRIVE%"=="" goto MISSINGVARS
+if "%HOMEPATH%"=="" goto MISSINGVARS
+if "%HAXEPATH%"=="" goto NOTINSTALLED
+
+set path=%HAXEPATH%;%HAXEPATH%\..\neko;%path%
+
+rem # invoke Thrift comnpiler
+thrift -r -gen haxe  ..\..\..\test\ThriftTest.thrift
+thrift -r -gen haxe  ..\..\..\contrib\async-test\aggr.thrift
+thrift -r -gen haxe  ..\..\..\lib\rb\benchmark\Benchmark.thrift
+if errorlevel 1 goto STOP
+
+rem # invoke Haxe compiler for all targets
+for %%a in (*.hxml) do (
+	rem * filter Python, as it is not supported by Haxe 3.1.3 (but will be in 3.1.4)
+	if not "%%a"=="python.hxml" (
+		echo --------------------------
+		echo Building %%a ...
+		echo --------------------------
+		haxe  --cwd .  %%a
+	)
+)
+
+
+echo.
+echo done.
+pause
+goto eof
+
+:NOTINSTALLED
+echo FATAL: Either Haxe is not installed, or the HAXEPATH variable is not set.
+pause
+goto eof
+
+:MISSINGVARS
+echo FATAL: Unable to locate home folder.
+echo.
+echo Both HOMEDRIVE and HOMEPATH need to be set to point to your Home folder.
+echo The current values are:
+echo HOMEDRIVE=%HOMEDRIVE%
+echo HOMEPATH=%HOMEPATH%
+pause
+goto eof
+
+:STOP
+pause
+goto eof
+
+:eof
diff --git a/lib/haxe/test/make_all.sh b/lib/haxe/test/make_all.sh
new file mode 100644
index 0000000..512f5ec
--- /dev/null
+++ b/lib/haxe/test/make_all.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# 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.
+#
+
+# invoke Thrift comnpiler
+thrift -r -gen haxe  ../../../test/ThriftTest.thrift
+thrift -r -gen haxe  ../../../contrib/async-test/aggr.thrift
+thrift -r -gen haxe  ../../../lib/rb/benchmark/Benchmark.thrift
+
+# output folder
+if [ ! -d bin ]; then
+  mkdir  bin
+fi
+
+# invoke Haxe compiler
+for target in *.hxml; do 
+  echo --------------------------
+  echo Building ${target} ...
+  echo --------------------------
+  if [ ! -d bin/${target} ]; then
+    mkdir  bin/${target}
+  fi
+  haxe  --cwd .  ${target} 
+done
+
+
+#eof
diff --git a/lib/haxe/test/neko.hxml b/lib/haxe/test/neko.hxml
new file mode 100644
index 0000000..2db70c8
--- /dev/null
+++ b/lib/haxe/test/neko.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp ../src
+-cp gen-haxe
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#neko target
+-neko bin/Test.n
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/lib/haxe/test/php.hxml b/lib/haxe/test/php.hxml
new file mode 100644
index 0000000..14f2b2d
--- /dev/null
+++ b/lib/haxe/test/php.hxml
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp ../src
+-cp gen-haxe
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#PHP target
+-php bin/php/
+--php-front Main-debug.php
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
diff --git a/lib/haxe/test/project.hide b/lib/haxe/test/project.hide
new file mode 100644
index 0000000..16ef98e
--- /dev/null
+++ b/lib/haxe/test/project.hide
@@ -0,0 +1,67 @@
+{
+     "type" : 0
+    ,"target" : 4
+    ,"name" : "Test"
+    ,"main" : null
+    ,"projectPackage" : ""
+    ,"company" : ""
+    ,"license" : ""
+    ,"url" : ""
+    ,"targetData" : [
+         {
+             "pathToHxml" : "flash.hxml"
+            ,"runActionType" : 1
+            ,"runActionText" : "bin/Test.swf"
+        }
+        ,{
+             "pathToHxml" : "javascript.hxml"
+            ,"runActionType" : 1
+            ,"runActionText" : "bin\\index.html"
+        }
+        ,{
+             "pathToHxml" : "neko.hxml"
+            ,"runActionType" : 2
+            ,"runActionText" : "neko bin/Test.n"
+        }
+        ,{
+             "pathToHxml" : "php.hxml"
+        }
+        ,{
+             "pathToHxml" : "cpp.hxml"
+            ,"runActionType" : 2
+            ,"runActionText" : "bin/Main-debug.exe"
+        }
+        ,{
+             "pathToHxml" : "java.hxml"
+        }
+        ,{
+             "pathToHxml" : "csharp.hxml"
+        }
+        ,{
+             "pathToHxml" : "python.hxml"
+            ,"runActionType" : 2
+            ,"runActionText" : "python bin/Test.py"
+        }
+    ]
+    ,"files" : [
+         {
+             "path" : "src\\Main.hx"
+            ,"useTabs" : true
+            ,"indentSize" : 4
+            ,"foldedRegions" : [
+
+            ]
+            ,"activeLine" : 13
+        }
+    ]
+    ,"activeFile" : "src\\Main.hx"
+    ,"openFLTarget" : null
+    ,"openFLBuildMode" : "Debug"
+    ,"runActionType" : null
+    ,"runActionText" : null
+    ,"buildActionCommand" : null
+    ,"hiddenItems" : [
+
+    ]
+    ,"showHiddenItems" : false
+}
\ No newline at end of file
diff --git a/lib/haxe/test/python.hxml b/lib/haxe/test/python.hxml
new file mode 100644
index 0000000..4d6a133
--- /dev/null
+++ b/lib/haxe/test/python.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp ../src
+-cp gen-haxe
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Python target
+-python bin/Test.py
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/lib/haxe/test/src/Main.hx b/lib/haxe/test/src/Main.hx
new file mode 100644
index 0000000..6c262d7
--- /dev/null
+++ b/lib/haxe/test/src/Main.hx
@@ -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;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import thrift.test.*;  // generated code
+
+
+enum WhatTests {
+    Normal;
+    Multiplex;
+}
+
+class Main
+{
+    static private var tests : WhatTests = Normal;
+    static private var server : Bool = false;
+
+    static private inline var CMDLINEHELP : String
+        = "\nHaxeTests  [client|server]  [multiplex]\n"
+        + "  client|server  ... determines run mode for some tests, default is client\n"
+        + "  multiplex ........ run multiplex test server or client\n";
+
+    static private function ParseArgs() {
+        #if sys
+
+        var args = Sys.args();
+        if ( args != null) {
+            for ( arg in args) {
+                switch(arg.toLowerCase()) {
+                    case "client":
+                        server = false;
+                    case "server" :
+                        server = true;
+                    case "multiplex" :
+                        tests = Multiplex;
+                    default:
+                throw 'Invalid argument "$arg"\n'+CMDLINEHELP;
+                }
+            }
+        }
+
+        #end
+    }
+
+    static public function main()
+    {
+        try
+        {
+            ParseArgs();
+
+            switch( tests) {
+                case Normal:
+                    StreamTest.Run(server);
+                case Multiplex:
+                    MultiplexTest.Run(server);
+                default:
+                    throw "Unhandled test mode $tests";
+            }
+
+            trace("All tests completed.");
+        }
+        catch( e: Dynamic)
+        {
+            trace('$e');
+            #if sys
+            Sys.exit(1);  // indicate error
+            #end
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/haxe/test/src/MultiplexTest.hx b/lib/haxe/test/src/MultiplexTest.hx
new file mode 100644
index 0000000..3818b66
--- /dev/null
+++ b/lib/haxe/test/src/MultiplexTest.hx
@@ -0,0 +1,224 @@
+/*
+ * 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;
+
+import haxe.Int64;
+import haxe.Int32;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+// debug only
+import org.apache.thrift.protocol.TProtocolDecorator;
+import org.apache.thrift.protocol.TMultiplexedProtocol;
+import org.apache.thrift.protocol.TMultiplexedProcessor;
+
+// generated code imports
+import Aggr;
+import AggrImpl;
+import AggrProcessor;
+import BenchmarkService;
+import BenchmarkServiceImpl;
+import BenchmarkServiceProcessor;
+import Error;
+
+
+class BenchmarkServiceHandler implements BenchmarkService
+{
+    public function new() {
+    }
+
+    public function fibonacci(n : haxe.Int32) : haxe.Int32 {
+        trace('Benchmark.fibonacci($n)');
+        var next : Int;
+        var prev   = 0;
+        var result = 1;
+        while( n > 0)
+        {
+            next   = result + prev;
+            prev   = result;
+            result = next;
+            --n;
+        }
+        return result;
+    }
+}
+
+
+class AggrServiceHandler implements Aggr
+{
+    private var values : List<haxe.Int32> = new List<haxe.Int32>();
+
+    public function new() {
+    }
+
+    public function addValue(value : haxe.Int32) : Void    {
+        trace('Aggr.addValue($value)');
+        values.add( value);
+    }
+
+    public function getValues() : List< haxe.Int32> {
+        trace('Aggr.getValues()');
+        return values;
+    }
+}
+
+
+
+class MultiplexTest extends TestBase {
+
+    private inline static var NAME_BENCHMARKSERVICE : String = "BenchmarkService";
+    private inline static var NAME_AGGR             : String  = "Aggr";
+
+
+    public static override function Run(server : Bool) : Void {
+        if ( server) {
+            RunMultiplexServer();
+        } else {
+            RunMultiplexClient();
+            RunDefaultClient();
+        }
+    }
+
+
+    // run the multiplex server
+    public static override function RunMultiplexServer() : Void  {
+       try
+       {
+            var benchHandler : BenchmarkService = new BenchmarkServiceHandler();
+            var benchProcessor : TProcessor = new BenchmarkServiceProcessor( benchHandler);
+
+            var aggrHandler : Aggr = new AggrServiceHandler();
+            var aggrProcessor : TProcessor = new AggrProcessor( aggrHandler);
+
+            var multiplex : TMultiplexedProcessor = new TMultiplexedProcessor();
+            multiplex.RegisterProcessor( NAME_BENCHMARKSERVICE, benchProcessor, true);  // default
+            multiplex.RegisterProcessor( NAME_AGGR, aggrProcessor);
+
+            // protocol+transport stack
+            var protfact : TProtocolFactory = new TBinaryProtocolFactory(true,true);
+            var servertrans : TServerTransport = new TServerSocket( 9090, 5, false);
+            var transfact : TTransportFactory = new TFramedTransportFactory();
+
+            var server : TServer = new TSimpleServer( multiplex, servertrans, transfact, protfact);
+
+            trace("Starting the server ...");
+            server.Serve();
+       }
+        catch( e : TApplicationException)
+        {
+            TestBase.Expect(false,'${e.errorID} ${e.errorMsg}');
+        }
+        catch( e : TException)
+        {
+            TestBase.Expect(false,'$e');
+        }
+    }
+
+
+    // run multiplex client against multiplex server
+    public static override function RunMultiplexClient() : Void  {
+        try
+        {
+            var trans : TTransport;
+            trans = new TSocket("localhost", 9090);
+            trans = new TFramedTransport(trans);
+            trans.open();
+
+            var protocol : TProtocol = new TBinaryProtocol(trans,true,true);
+            var multiplex : TMultiplexedProtocol;
+
+            multiplex = new TMultiplexedProtocol( protocol, NAME_BENCHMARKSERVICE);
+            var bench = new BenchmarkServiceImpl( multiplex);
+
+            multiplex = new TMultiplexedProtocol( protocol, NAME_AGGR);
+            var aggr = new AggrImpl( multiplex);
+
+            trace('calling aggr.add( bench.fibo())...');
+            for( i in 1 ... 10)
+            {
+                trace('$i');
+                aggr.addValue( bench.fibonacci(i));
+            }
+
+            trace('calling aggr ...');
+            var i = 1;
+            var values = aggr.getValues();
+            TestBase.Expect(values != null,'aggr.getValues() == null');
+            for( k in values)
+            {
+                trace('fib($i) = $k');
+                ++i;
+            }
+
+            trans.close();
+            trace('done.');
+
+        }
+        catch( e : TApplicationException)
+        {
+            TestBase.Expect(false,'${e.errorID} ${e.errorMsg}');
+        }
+        catch( e : TException)
+        {
+            TestBase.Expect(false,'$e');
+        }
+    }
+
+
+    // run non-multiplex client against multiplex server to test default fallback
+    public static override function RunDefaultClient() : Void  {
+        try
+        {
+            var trans : TTransport;
+            trans = new TSocket("localhost", 9090);
+            trans = new TFramedTransport(trans);
+            trans.open();
+
+            var protocol : TProtocol = new TBinaryProtocol(trans,true,true);
+
+            var bench = new BenchmarkServiceImpl( protocol);
+
+            trace('calling bench (via default) ...');
+            for( i in 1 ... 10)
+            {
+                var k = bench.fibonacci(i);
+                trace('fib($i) = $k');
+            }
+
+            trans.close();
+            trace('done.');
+        }
+        catch( e : TApplicationException)
+        {
+            TestBase.Expect(false,'${e.errorID} ${e.errorMsg}');
+        }
+        catch( e : TException)
+        {
+            TestBase.Expect(false,'$e');
+        }
+    }
+
+}
+
+
diff --git a/lib/haxe/test/src/StreamTest.hx b/lib/haxe/test/src/StreamTest.hx
new file mode 100644
index 0000000..244f1ea
--- /dev/null
+++ b/lib/haxe/test/src/StreamTest.hx
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package;
+
+import haxe.Int64;
+import sys.FileSystem;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import thrift.test.*;  // generated code
+
+
+class StreamTest extends TestBase {
+
+
+    private inline static var tmpfile : String = "data.tmp";
+
+
+    private static function MakeTestData() : Xtruct {
+        var data : Xtruct = new Xtruct();
+        data.string_thing = "Streamtest";
+        data.byte_thing = -128;
+        data.i32_thing = 4711;
+        data.i64_thing = Int64.make(0x12345678,0x9ABCDEF0);
+        return data;
+    }
+
+    public static function WriteData() : Xtruct
+    {
+        var stream : TStream = new TFileStream( tmpfile, CreateNew);
+        var trans : TTransport = new TStreamTransport( null, stream);
+        var prot = new TJSONProtocol( trans);
+
+        var data = MakeTestData();
+        data.write(prot);
+        trans.close();
+
+        return data;
+    }
+
+    public static function ReadData() : Xtruct
+    {
+        var stream : TStream = new TFileStream( tmpfile, Read);
+        var trans : TTransport = new TStreamTransport( stream, null);
+        var prot = new TJSONProtocol( trans);
+
+        var data : Xtruct = new Xtruct();
+        data.read(prot);
+        trans.close();
+
+        return data;
+    }
+
+    public static override function Run(server : Bool) : Void
+    {
+        try {
+            var written = WriteData();
+            var read = ReadData();
+            FileSystem.deleteFile(tmpfile);
+
+            TestBase.Expect( read.string_thing == written.string_thing, "string data");
+            TestBase.Expect( read.byte_thing == written.byte_thing, "byte data");
+            TestBase.Expect( read.i32_thing == written.i32_thing, "i32 data");
+            TestBase.Expect( Int64.compare( read.i64_thing, written.i64_thing) == 0, "i64 data");
+
+        } catch(e:Dynamic) {
+            FileSystem.deleteFile(tmpfile);
+            throw e;
+        }
+    }
+
+}
+
+
diff --git a/lib/haxe/test/src/TestBase.hx b/lib/haxe/test/src/TestBase.hx
new file mode 100644
index 0000000..1232773
--- /dev/null
+++ b/lib/haxe/test/src/TestBase.hx
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+
+class TestBase {
+
+    private function new() {
+        // override, if necessary
+    }
+
+    public static function Run(server : Bool) : Void {
+          throw new AbstractMethodError();
+    }
+
+    public static function Expect( expr : Bool, info : String, ?pos : haxe.PosInfos) : Void {
+        if( ! expr) {
+            throw ('Test "$info" failed at '+pos.methodName+' in '+pos.fileName+':'+pos.lineNumber);
+        }
+    }
+
+}
+ 
\ No newline at end of file
diff --git a/lib/hs/CMakeLists.txt b/lib/hs/CMakeLists.txt
new file mode 100644
index 0000000..a20a319
--- /dev/null
+++ b/lib/hs/CMakeLists.txt
@@ -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.
+#
+
+# Rebuild when any of these files changes
+set(haskell_sources
+    src/Thrift.hs
+    src/Thrift/Arbitraries.hs
+    src/Thrift/Protocol.hs
+    src/Thrift/Protocol/Binary.hs
+    src/Thrift/Protocol/Compact.hs
+    src/Thrift/Protocol/JSON.hs
+    src/Thrift/Server.hs
+    src/Thrift/Transport.hs
+    src/Thrift/Transport/Empty.hs
+    src/Thrift/Transport/Framed.hs
+    src/Thrift/Transport/Handle.hs
+    src/Thrift/Transport/HttpClient.hs
+    src/Thrift/Transport/IOBuffer.hs
+    src/Thrift/Types.hs
+    thrift.cabal
+)
+
+if(BUILD_TESTING)
+    list(APPEND haskell_soruces
+        test/Spec.hs
+        test/BinarySpec.hs
+        test/CompactSpec.hs
+        test/JSONSpec.hs
+    )
+    set(hs_enable_test "--enable-tests")
+endif()
+
+set(haskell_artifacts thrift_cabal.stamp)
+# Adding *.hi files so that any missing file triggers the build
+foreach(SRC ${haskell_sources})
+    get_filename_component(EX ${SRC} EXT)
+    if(${EX} STREQUAL ".hs")
+        file(RELATIVE_PATH REL ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/${SRC})
+        get_filename_component(DIR ${REL} DIRECTORY)
+        get_filename_component(BASE ${REL} NAME_WE)
+        list(APPEND haskell_artifacts dist/build/${DIR}/${BASE}.hi)
+    endif()
+endforeach()
+
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+    set(hs_optimize -O0)
+elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
+    set(hs_optimize -O1)
+endif()
+
+add_custom_command(
+    OUTPUT ${haskell_artifacts}
+    COMMAND ${CABAL} update
+    # Build dependencies first without --builddir, otherwise it fails.
+    COMMAND ${CABAL} install --only-dependencies ${hs_enable_test}
+    COMMAND ${CABAL} configure ${hs_optimize} ${hs_enable_test} --builddir=${CMAKE_CURRENT_BINARY_DIR}/dist
+    COMMAND ${CABAL} build --builddir=${CMAKE_CURRENT_BINARY_DIR}/dist
+    COMMAND ${CABAL} install --builddir=${CMAKE_CURRENT_BINARY_DIR}/dist
+    COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/thrift_cabal.stamp
+    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+    DEPENDS ${haskell_sources}
+    COMMENT "Building Haskell library")
+
+add_custom_target(haskell_library ALL
+    DEPENDS ${haskell_artifacts})
+
+if(BUILD_TESTING)
+    add_test(NAME HaskellCabalCheck
+            COMMAND ${CABAL} check
+            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+    add_test(NAME HaskellCabalTest
+            # Cabal fails to find built executable when --builddir is specified.
+            # So we invoke the executable directly.
+            # COMMAND ${CABAL} test --builddir=${CMAKE_CURRENT_BINARY_DIR}/dist
+            # WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+            COMMAND dist/build/spec/spec)
+endif()
diff --git a/lib/hs/Makefile.am b/lib/hs/Makefile.am
index 3464a4f..3cd8b57 100644
--- a/lib/hs/Makefile.am
+++ b/lib/hs/Makefile.am
@@ -18,26 +18,33 @@
 #
 
 EXTRA_DIST = \
-  LICENSE \
-  README \
-  Setup.lhs \
-  TODO \
-  Thrift.cabal \
-  src
+	coding_standards.md \
+	CMakeLists.txt \
+	LICENSE \
+	README.md \
+	Setup.lhs \
+	TODO \
+	thrift.cabal \
+	src \
+	test
 
 all-local:
-	$(RUNHASKELL) Setup.lhs configure $(CABAL_CONFIGURE_FLAGS)
-	$(RUNHASKELL) Setup.lhs build
+	$(CABAL) update
+	$(CABAL) install
 
 install-exec-hook:
-	$(RUNHASKELL) Setup.lhs install
+	$(CABAL) install
 
 # Make sure this doesn't fail if Haskell is not configured.
 clean-local:
-	$(RUNHASKELL) Setup.lhs clean
+	$(CABAL) clean
 
 maintainer-clean-local:
-	$(RUNHASKELL) Setup.lhs clean
+	$(CABAL) clean
 
 check-local:
 	$(CABAL) check
+	$(CABAL) install --only-dependencies --enable-tests
+	$(CABAL) configure --enable-tests
+	$(CABAL) build
+	$(CABAL) test
diff --git a/lib/hs/README b/lib/hs/README
deleted file mode 100644
index fe525bd..0000000
--- a/lib/hs/README
+++ /dev/null
@@ -1,99 +0,0 @@
-Haskell Thrift Bindings
-
-License
-=======
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-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.
-
-Compile
-=======
-
-Use Cabal to compile and install; ./configure uses Cabal underneath, and that
-path is not yet well tested. Thrift's library and generated code should compile
-with pretty much any GHC extensions or warnings you enable (or disable).
-Please report this not being the case as a bug on
-https://issues.apache.org/jira/secure/CreateIssue!default.jspa
-
-Chances you'll need to muck a bit with Cabal flags to install Thrift:
-
-CABAL_CONFIGURE_FLAGS="--user" ./configure
-
-Base Types
-==========
-
-The mapping from Thrift types to Haskell's is:
-
- * double -> Double
- * byte -> Data.Word.Word8
- * i16 -> Data.Int.Int16
- * i32 -> Data.Int.Int32
- * i64 -> Data.Int.Int64
- * string -> Text
- * binary -> Data.ByteString.Lazy
- * bool -> Boolean
-
-Enums
-=====
-
-Become Haskell 'data' types. Use fromEnum to get out the int value.
-
-Lists
-=====
-
-Become Data.Vector.Vector from the vector package.
-
-Maps and Sets
-=============
-
-Become Data.HashMap.Strict.Map and Data.HashSet.Set from the
-unordered-containers package.
-
-Structs
-=======
-
-Become records. Field labels are ugly, of the form f_STRUCTNAME_FIELDNAME. All
-fields are Maybe types.
-
-Exceptions
-==========
-
-Identical to structs. Use them with throw and catch from Control.Exception.
-
-Client
-======
-
-Just a bunch of functions. You may have to import a bunch of client files to
-deal with inheritance.
-
-Interface
-=========
-
-You should only have to import the last one in the chain of inheritors. To make
-an interface, declare a label:
-
-  data MyIface = MyIface
-
-and then declare it an instance of each iface class, starting with the superest
-class and proceding down (all the while defining the methods).  Then pass your
-label to process as the handler.
-
-Processor
-=========
-
-Just a function that takes a handler label, protocols. It calls the
-superclasses process if there is a superclass.
diff --git a/lib/hs/README.md b/lib/hs/README.md
new file mode 100644
index 0000000..eea0a73
--- /dev/null
+++ b/lib/hs/README.md
@@ -0,0 +1,99 @@
+Haskell Thrift Bindings
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+Compile
+=======
+
+Use Cabal to compile and install; ./configure uses Cabal underneath, and that
+path is not yet well tested. Thrift's library and generated code should compile
+with pretty much any GHC extensions or warnings you enable (or disable).
+Please report this not being the case as a bug on
+https://issues.apache.org/jira/secure/CreateIssue!default.jspa
+
+Chances you'll need to muck a bit with Cabal flags to install Thrift:
+
+CABAL_CONFIGURE_FLAGS="--user" ./configure
+
+Base Types
+==========
+
+The mapping from Thrift types to Haskell's is:
+
+ * double -> Double
+ * byte -> Data.Int.Int8
+ * i16 -> Data.Int.Int16
+ * i32 -> Data.Int.Int32
+ * i64 -> Data.Int.Int64
+ * string -> Text
+ * binary -> Data.ByteString.Lazy
+ * bool -> Boolean
+
+Enums
+=====
+
+Become Haskell 'data' types. Use fromEnum to get out the int value.
+
+Lists
+=====
+
+Become Data.Vector.Vector from the vector package.
+
+Maps and Sets
+=============
+
+Become Data.HashMap.Strict.Map and Data.HashSet.Set from the
+unordered-containers package.
+
+Structs
+=======
+
+Become records. Field labels are ugly, of the form f_STRUCTNAME_FIELDNAME. All
+fields are Maybe types.
+
+Exceptions
+==========
+
+Identical to structs. Use them with throw and catch from Control.Exception.
+
+Client
+======
+
+Just a bunch of functions. You may have to import a bunch of client files to
+deal with inheritance.
+
+Interface
+=========
+
+You should only have to import the last one in the chain of inheritors. To make
+an interface, declare a label:
+
+  data MyIface = MyIface
+
+and then declare it an instance of each iface class, starting with the superest
+class and proceeding down (all the while defining the methods).  Then pass your
+label to process as the handler.
+
+Processor
+=========
+
+Just a function that takes a handler label, protocols. It calls the
+superclasses process if there is a superclass.
diff --git a/lib/hs/Setup.lhs b/lib/hs/Setup.lhs
old mode 100644
new mode 100755
diff --git a/lib/hs/Thrift.cabal b/lib/hs/Thrift.cabal
deleted file mode 100644
index 6c22e35..0000000
--- a/lib/hs/Thrift.cabal
+++ /dev/null
@@ -1,58 +0,0 @@
---
--- Licensed to the Apache Software Foundation (ASF) under one
--- or more contributor license agreements. See the NOTICE file
--- distributed with this work for additional information
--- regarding copyright ownership. The ASF licenses this file
--- to you under the Apache License, Version 2.0 (the
--- "License"); you may not use this file except in compliance
--- with the License. You may obtain a copy of the License at
---
---   http://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing,
--- software distributed under the License is distributed on an
--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
--- KIND, either express or implied. See the License for the
--- specific language governing permissions and limitations
--- under the License.
---
-
-Name:           thrift
-Version:        0.9.1
-Cabal-Version:  >= 1.4
-License:        OtherLicense
-Category:       Foreign
-Build-Type:     Simple
-Synopsis:       Haskell bindings for the Apache Thrift RPC system
-Homepage:       http://thrift.apache.org
-Bug-Reports:    https://issues.apache.org/jira/browse/THRIFT
-Maintainer:     dev@thrift.apache.org
-License-File:   LICENSE
-
-Description:
-  Haskell bindings for the Apache Thrift RPC system. Requires the use of the thrift code generator.
-
-Library
-  Hs-Source-Dirs:
-    src
-  Build-Depends:
-    base >= 4, base < 5, network, ghc-prim, binary, bytestring, hashable, HTTP, text, unordered-containers, vector
-  Exposed-Modules:
-    Thrift,
-    Thrift.Protocol,
-    Thrift.Protocol.Binary,
-    Thrift.Server,
-    Thrift.Transport,
-    Thrift.Transport.Framed,
-    Thrift.Transport.Handle,
-    Thrift.Transport.HttpClient,
-    Thrift.Types
-  Extensions:
-    DeriveDataTypeable,
-    ExistentialQuantification,
-    FlexibleInstances,
-    KindSignatures,
-    MagicHash,
-    RankNTypes,
-    ScopedTypeVariables,
-    TypeSynonymInstances
diff --git a/lib/hs/coding_standards.md b/lib/hs/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/hs/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/hs/src/Thrift.hs b/lib/hs/src/Thrift.hs
index 65a2208..6580209 100644
--- a/lib/hs/src/Thrift.hs
+++ b/lib/hs/src/Thrift.hs
@@ -1,5 +1,4 @@
 {-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RankNTypes #-}
 --
@@ -31,15 +30,17 @@
     , ThriftException(..)
     ) where
 
-import Control.Monad ( when )
 import Control.Exception
 
-import Data.Text.Lazy ( pack, unpack )
+import Data.Int
+import Data.Text.Lazy ( Text, pack, unpack )
+import Data.Text.Lazy.Encoding
 import Data.Typeable ( Typeable )
+import qualified Data.HashMap.Strict as Map
 
-import Thrift.Transport
 import Thrift.Protocol
-
+import Thrift.Transport
+import Thrift.Types
 
 data ThriftException = ThriftException
   deriving ( Show, Typeable )
@@ -89,45 +90,25 @@
   deriving ( Show, Typeable )
 instance Exception AppExn
 
-writeAppExn :: (Protocol p, Transport t) => p t -> AppExn -> IO ()
-writeAppExn pt ae = do
-    writeStructBegin pt "TApplicationException"
+writeAppExn :: Protocol p => p -> AppExn -> IO ()
+writeAppExn pt ae = writeVal pt $ TStruct $ Map.fromList
+                    [ (1, ("message", TString $ encodeUtf8 $ pack $ ae_message ae))
+                    , (2, ("type", TI32 $ fromIntegral $ fromEnum (ae_type ae)))
+                    ]
 
-    when (ae_message ae /= "") $ do
-        writeFieldBegin pt ("message", T_STRING , 1)
-        writeString pt (pack $ ae_message ae)
-        writeFieldEnd pt
-
-    writeFieldBegin pt ("type", T_I32, 2);
-    writeI32 pt (fromIntegral $ fromEnum (ae_type ae))
-    writeFieldEnd pt
-    writeFieldStop pt
-    writeStructEnd pt
-
-readAppExn :: (Protocol p, Transport t) => p t -> IO AppExn
+readAppExn :: Protocol p => p -> IO AppExn
 readAppExn pt = do
-    _ <- readStructBegin pt
-    record <- readAppExnFields pt (AppExn {ae_type = undefined, ae_message = undefined})
-    readStructEnd pt
-    return record
+    let typemap = Map.fromList [(1,("message",T_STRING)),(2,("type",T_I32))]
+    TStruct fields <- readVal pt $ T_STRUCT typemap
+    return $ readAppExnFields fields
 
-readAppExnFields :: forall (a :: * -> *) t. (Protocol a, Transport t) => a t -> AppExn -> IO AppExn 
-readAppExnFields pt record = do
-    (_, ft, tag) <- readFieldBegin pt
-    if ft == T_STOP
-        then return record
-        else case tag of
-                 1 -> if ft == T_STRING then
-                          do s <- readString pt
-                             readAppExnFields pt record{ae_message = unpack s}
-                          else do skip pt ft
-                                  readAppExnFields pt record
-                 2 -> if ft == T_I32 then
-                          do i <- readI32 pt
-                             readAppExnFields pt record{ae_type = (toEnum $ fromIntegral i)}
-                          else do skip pt ft
-                                  readAppExnFields pt record
-                 _ -> do skip pt ft
-                         readFieldEnd pt
-                         readAppExnFields pt record
-
+readAppExnFields :: Map.HashMap Int16 (Text, ThriftVal) -> AppExn
+readAppExnFields fields = AppExn{
+  ae_message = maybe undefined unwrapMessage $ Map.lookup 1 fields,
+  ae_type    = maybe undefined unwrapType $ Map.lookup 2 fields
+  }
+  where
+    unwrapMessage (_, TString s) = unpack $ decodeUtf8 s
+    unwrapMessage _ = undefined
+    unwrapType (_, TI32 i) = toEnum $ fromIntegral i
+    unwrapType _ = undefined
diff --git a/lib/hs/src/Thrift/Arbitraries.hs b/lib/hs/src/Thrift/Arbitraries.hs
new file mode 100644
index 0000000..e9c0fc3
--- /dev/null
+++ b/lib/hs/src/Thrift/Arbitraries.hs
@@ -0,0 +1,55 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module Thrift.Arbitraries where
+
+import Data.Bits()
+
+import Test.QuickCheck.Arbitrary
+
+import Control.Applicative ((<$>))
+import Data.Map (Map)
+import qualified Data.Map as Map
+import qualified Data.Set as Set
+import qualified Data.Vector as Vector
+import qualified Data.Text.Lazy as Text
+import qualified Data.HashSet as HSet
+import qualified Data.HashMap.Strict as HMap
+import Data.Hashable (Hashable)
+
+import Data.ByteString.Lazy (ByteString)
+import qualified Data.ByteString.Lazy as BS
+
+-- String has an Arbitrary instance already
+-- Bool has an Arbitrary instance already
+-- A Thrift 'list' is a Vector.
+
+instance Arbitrary ByteString where
+  arbitrary = BS.pack . filter (/= 0) <$> arbitrary
+
+instance (Arbitrary k) => Arbitrary (Vector.Vector k) where
+  arbitrary = Vector.fromList <$> arbitrary
+
+instance Arbitrary Text.Text where
+  arbitrary = Text.pack . filter (/= '\0') <$> arbitrary
+
+instance (Eq k, Hashable k, Arbitrary k) => Arbitrary (HSet.HashSet k) where
+  arbitrary = HSet.fromList <$> arbitrary
+
+instance (Eq k, Hashable k, Arbitrary k, Arbitrary v) =>
+    Arbitrary (HMap.HashMap k v) where
+  arbitrary = HMap.fromList <$> arbitrary
+
+{-
+   To handle Thrift 'enum' we would ideally use something like:
+
+instance (Enum a, Bounded a) => Arbitrary a
+    where arbitrary = elements (enumFromTo minBound maxBound)
+
+Unfortunately this doesn't play nicely with the type system.
+Instead we'll generate an arbitrary instance along with the code.
+-}
+
+{-
+    There might be some way to introspect on the Haskell structure of a
+    Thrift 'struct' or 'exception' but generating the code directly is simpler.
+-}
diff --git a/lib/hs/src/Thrift/Protocol.hs b/lib/hs/src/Thrift/Protocol.hs
index f3b342a..67a9175 100644
--- a/lib/hs/src/Thrift/Protocol.hs
+++ b/lib/hs/src/Thrift/Protocol.hs
@@ -1,4 +1,6 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE OverloadedStrings #-}
 --
 -- Licensed to the Apache Software Foundation (ASF) under one
 -- or more contributor license agreements. See the NOTICE file
@@ -20,167 +22,46 @@
 
 module Thrift.Protocol
     ( Protocol(..)
-    , skip
-    , MessageType(..)
-    , ThriftType(..)
+    , StatelessProtocol(..)
     , ProtocolExn(..)
     , ProtocolExnType(..)
+    , getTypeOf
+    , runParser
+    , bsToDouble
+    , bsToDoubleLE
     ) where
 
-import Control.Monad ( replicateM_, unless )
 import Control.Exception
-import Data.ByteString.Lazy
+import Data.Attoparsec.ByteString
+import Data.Bits
+import Data.ByteString.Unsafe
+import Data.Functor ((<$>))
 import Data.Int
-import Data.Text.Lazy ( Text )
-import Data.Typeable ( Typeable )
+import Data.Monoid (mempty)
+import Data.Text.Lazy (Text)
+import Data.Typeable (Typeable)
+import Data.Word
+import Foreign.Ptr (castPtr)
+import Foreign.Storable (peek, poke)
+import System.IO.Unsafe
+import qualified Data.ByteString as BS
+import qualified Data.HashMap.Strict as Map
+import qualified Data.ByteString.Lazy as LBS
 
 import Thrift.Transport
-
-
-data ThriftType
-    = T_STOP
-    | T_VOID
-    | T_BOOL
-    | T_BYTE
-    | T_DOUBLE
-    | T_I16
-    | T_I32
-    | T_I64
-    | T_STRING
-    | T_STRUCT
-    | T_MAP
-    | T_SET
-    | T_LIST
-      deriving ( Eq )
-
-instance Enum ThriftType where
-    fromEnum T_STOP   = 0
-    fromEnum T_VOID   = 1
-    fromEnum T_BOOL   = 2
-    fromEnum T_BYTE   = 3
-    fromEnum T_DOUBLE = 4
-    fromEnum T_I16    = 6
-    fromEnum T_I32    = 8
-    fromEnum T_I64    = 10
-    fromEnum T_STRING = 11
-    fromEnum T_STRUCT = 12
-    fromEnum T_MAP    = 13
-    fromEnum T_SET    = 14
-    fromEnum T_LIST   = 15
-
-    toEnum 0  = T_STOP
-    toEnum 1  = T_VOID
-    toEnum 2  = T_BOOL
-    toEnum 3  = T_BYTE
-    toEnum 4  = T_DOUBLE
-    toEnum 6  = T_I16
-    toEnum 8  = T_I32
-    toEnum 10 = T_I64
-    toEnum 11 = T_STRING
-    toEnum 12 = T_STRUCT
-    toEnum 13 = T_MAP
-    toEnum 14 = T_SET
-    toEnum 15 = T_LIST
-    toEnum t = error $ "Invalid ThriftType " ++ show t
-
-data MessageType
-    = M_CALL
-    | M_REPLY
-    | M_EXCEPTION
-      deriving ( Eq )
-
-instance Enum MessageType where
-    fromEnum M_CALL      =  1
-    fromEnum M_REPLY     =  2
-    fromEnum M_EXCEPTION =  3
-
-    toEnum 1 = M_CALL
-    toEnum 2 = M_REPLY
-    toEnum 3 = M_EXCEPTION
-    toEnum t = error $ "Invalid MessageType " ++ show t
-
+import Thrift.Types
 
 class Protocol a where
-    getTransport :: Transport t => a t -> t
+  readByte :: a -> IO LBS.ByteString
+  readVal :: a -> ThriftType -> IO ThriftVal
+  readMessage :: a -> ((Text, MessageType, Int32) -> IO b) -> IO b
 
-    writeMessageBegin :: Transport t => a t -> (Text, MessageType, Int32) -> IO ()
-    writeMessageEnd   :: Transport t => a t -> IO ()
+  writeVal :: a -> ThriftVal -> IO ()
+  writeMessage :: a -> (Text, MessageType, Int32) -> IO () -> IO ()
 
-    writeStructBegin :: Transport t => a t -> Text -> IO ()
-    writeStructEnd   :: Transport t => a t -> IO ()
-    writeFieldBegin  :: Transport t => a t -> (Text, ThriftType, Int16) -> IO ()
-    writeFieldEnd    :: Transport t => a t -> IO ()
-    writeFieldStop   :: Transport t => a t -> IO ()
-    writeMapBegin    :: Transport t => a t -> (ThriftType, ThriftType, Int32) -> IO ()
-    writeMapEnd      :: Transport t => a t -> IO ()
-    writeListBegin   :: Transport t => a t -> (ThriftType, Int32) -> IO ()
-    writeListEnd     :: Transport t => a t -> IO ()
-    writeSetBegin    :: Transport t => a t -> (ThriftType, Int32) -> IO ()
-    writeSetEnd      :: Transport t => a t -> IO ()
-
-    writeBool   :: Transport t => a t -> Bool -> IO ()
-    writeByte   :: Transport t => a t -> Int8 -> IO ()
-    writeI16    :: Transport t => a t -> Int16 -> IO ()
-    writeI32    :: Transport t => a t -> Int32 -> IO ()
-    writeI64    :: Transport t => a t -> Int64 -> IO ()
-    writeDouble :: Transport t => a t -> Double -> IO ()
-    writeString :: Transport t => a t -> Text -> IO ()
-    writeBinary :: Transport t => a t -> ByteString -> IO ()
-
-
-    readMessageBegin :: Transport t => a t -> IO (Text, MessageType, Int32)
-    readMessageEnd   :: Transport t => a t -> IO ()
-
-    readStructBegin :: Transport t => a t -> IO Text
-    readStructEnd   :: Transport t => a t -> IO ()
-    readFieldBegin  :: Transport t => a t -> IO (Text, ThriftType, Int16)
-    readFieldEnd    :: Transport t => a t -> IO ()
-    readMapBegin    :: Transport t => a t -> IO (ThriftType, ThriftType, Int32)
-    readMapEnd      :: Transport t => a t -> IO ()
-    readListBegin   :: Transport t => a t -> IO (ThriftType, Int32)
-    readListEnd     :: Transport t => a t -> IO ()
-    readSetBegin    :: Transport t => a t -> IO (ThriftType, Int32)
-    readSetEnd      :: Transport t => a t -> IO ()
-
-    readBool   :: Transport t => a t -> IO Bool
-    readByte   :: Transport t => a t -> IO Int8
-    readI16    :: Transport t => a t -> IO Int16
-    readI32    :: Transport t => a t -> IO Int32
-    readI64    :: Transport t => a t -> IO Int64
-    readDouble :: Transport t => a t -> IO Double
-    readString :: Transport t => a t -> IO Text
-    readBinary :: Transport t => a t -> IO ByteString
-
-
-skip :: (Protocol p, Transport t) => p t -> ThriftType -> IO ()
-skip _ T_STOP = return ()
-skip _ T_VOID = return ()
-skip p T_BOOL = readBool p >> return ()
-skip p T_BYTE = readByte p >> return ()
-skip p T_I16 = readI16 p >> return ()
-skip p T_I32 = readI32 p >> return ()
-skip p T_I64 = readI64 p >> return ()
-skip p T_DOUBLE = readDouble p >> return ()
-skip p T_STRING = readString p >> return ()
-skip p T_STRUCT = do _ <- readStructBegin p
-                     skipFields p
-                     readStructEnd p
-skip p T_MAP = do (k, v, s) <- readMapBegin p
-                  replicateM_ (fromIntegral s) (skip p k >> skip p v)
-                  readMapEnd p
-skip p T_SET = do (t, n) <- readSetBegin p
-                  replicateM_ (fromIntegral n) (skip p t)
-                  readSetEnd p
-skip p T_LIST = do (t, n) <- readListBegin p
-                   replicateM_ (fromIntegral n) (skip p t)
-                   readListEnd p
-
-
-skipFields :: (Protocol p, Transport t) => p t -> IO ()
-skipFields p = do
-    (_, t, _) <- readFieldBegin p
-    unless (t == T_STOP) (skip p t >> readFieldEnd p >> skipFields p)
-
+class Protocol a => StatelessProtocol a where
+  serializeVal :: a -> ThriftVal -> LBS.ByteString
+  deserializeVal :: a -> ThriftType -> LBS.ByteString -> ThriftVal
 
 data ProtocolExnType
     = PE_UNKNOWN
@@ -188,8 +69,68 @@
     | PE_NEGATIVE_SIZE
     | PE_SIZE_LIMIT
     | PE_BAD_VERSION
+    | PE_NOT_IMPLEMENTED
+    | PE_MISSING_REQUIRED_FIELD
       deriving ( Eq, Show, Typeable )
 
 data ProtocolExn = ProtocolExn ProtocolExnType String
   deriving ( Show, Typeable )
 instance Exception ProtocolExn
+
+getTypeOf :: ThriftVal -> ThriftType
+getTypeOf v =  case v of
+  TStruct{} -> T_STRUCT Map.empty
+  TMap{} -> T_MAP T_VOID T_VOID
+  TList{} -> T_LIST T_VOID
+  TSet{} -> T_SET T_VOID
+  TBool{} -> T_BOOL
+  TByte{} -> T_BYTE
+  TI16{} -> T_I16
+  TI32{} -> T_I32
+  TI64{} -> T_I64
+  TString{} -> T_STRING
+  TBinary{} -> T_BINARY
+  TDouble{} -> T_DOUBLE
+
+runParser :: (Protocol p, Show a) => p -> Parser a -> IO a
+runParser prot p = refill >>= getResult . parse p
+  where
+    refill = handle handleEOF $ LBS.toStrict <$> readByte prot
+    getResult (Done _ a) = return a
+    getResult (Partial k) = refill >>= getResult . k
+    getResult f = throw $ ProtocolExn PE_INVALID_DATA (show f)
+
+handleEOF :: SomeException -> IO BS.ByteString
+handleEOF = const $ return mempty
+
+-- | Converts a ByteString to a Floating point number
+-- The ByteString is assumed to be encoded in network order (Big Endian)
+-- therefore the behavior of this function varies based on whether the local
+-- machine is big endian or little endian.
+bsToDouble :: BS.ByteString -> Double
+bsToDoubleLE :: BS.ByteString -> Double
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+bsToDouble bs = unsafeDupablePerformIO $ unsafeUseAsCString bs castBsSwapped
+bsToDoubleLE bs = unsafeDupablePerformIO $ unsafeUseAsCString bs castBs
+#else
+bsToDouble bs = unsafeDupablePerformIO $ unsafeUseAsCString bs castBs
+bsToDoubleLE bs = unsafeDupablePerformIO $ unsafeUseAsCString bs castBsSwapped
+#endif
+
+
+castBsSwapped chrPtr = do
+  w <- peek (castPtr chrPtr)
+  poke (castPtr chrPtr) (byteSwap w)
+  peek (castPtr chrPtr)
+castBs = peek . castPtr
+
+-- | Swap endianness of a 64-bit word
+byteSwap :: Word64 -> Word64
+byteSwap w = (w `shiftL` 56 .&. 0xFF00000000000000) .|.
+             (w `shiftL` 40 .&. 0x00FF000000000000) .|.
+             (w `shiftL` 24 .&. 0x0000FF0000000000) .|.
+             (w `shiftL` 8  .&. 0x000000FF00000000) .|.
+             (w `shiftR` 8  .&. 0x00000000FF000000) .|.
+             (w `shiftR` 24 .&. 0x0000000000FF0000) .|.
+             (w `shiftR` 40 .&. 0x000000000000FF00) .|.
+             (w `shiftR` 56 .&. 0x00000000000000FF)
diff --git a/lib/hs/src/Thrift/Protocol/Binary.hs b/lib/hs/src/Thrift/Protocol/Binary.hs
index 1bc9add..7b0acd9 100644
--- a/lib/hs/src/Thrift/Protocol/Binary.hs
+++ b/lib/hs/src/Thrift/Protocol/Binary.hs
@@ -1,6 +1,3 @@
-{-# LANGUAGE ExistentialQuantification #-}
-{-# LANGUAGE MagicHash #-}
-{-# LANGUAGE OverloadedStrings #-}
 --
 -- Licensed to the Apache Software Foundation (ASF) under one
 -- or more contributor license agreements. See the NOTICE file
@@ -20,145 +17,196 @@
 -- under the License.
 --
 
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
 module Thrift.Protocol.Binary
     ( module Thrift.Protocol
     , BinaryProtocol(..)
+    , versionMask
+    , version1
     ) where
 
 import Control.Exception ( throw )
-import Control.Monad ( liftM )
-
-import qualified Data.Binary
+import Control.Monad
 import Data.Bits
+import Data.ByteString.Lazy.Builder
+import Data.Functor
 import Data.Int
+import Data.Monoid
 import Data.Text.Lazy.Encoding ( decodeUtf8, encodeUtf8 )
-
-import GHC.Exts
-import GHC.Word
+import Data.Word
 
 import Thrift.Protocol
 import Thrift.Transport
+import Thrift.Types
 
+import qualified Data.Attoparsec.ByteString as P
+import qualified Data.Attoparsec.ByteString.Lazy as LP
+import qualified Data.Binary as Binary
 import qualified Data.ByteString.Lazy as LBS
+import qualified Data.HashMap.Strict as Map
+import qualified Data.Text.Lazy as LT
 
-version_mask :: Int32
-version_mask = 0xffff0000
+versionMask :: Int32
+versionMask = fromIntegral (0xffff0000 :: Word32)
 
-version_1 :: Int32
-version_1    = 0x80010000
+version1 :: Int32
+version1 = fromIntegral (0x80010000 :: Word32)
 
 data BinaryProtocol a = Transport a => BinaryProtocol a
 
+getTransport :: Transport t => BinaryProtocol t -> t
+getTransport (BinaryProtocol t) = t
 
-instance Protocol BinaryProtocol where
-    getTransport (BinaryProtocol t) = t
-
-    writeMessageBegin p (n, t, s) = do
-        writeI32 p (version_1 .|. (fromIntegral $ fromEnum t))
-        writeString p n
-        writeI32 p s
-    writeMessageEnd _ = return ()
-
-    writeStructBegin _ _ = return ()
-    writeStructEnd _ = return ()
-    writeFieldBegin p (_, t, i) = writeType p t >> writeI16 p i
-    writeFieldEnd _ = return ()
-    writeFieldStop p = writeType p T_STOP
-    writeMapBegin p (k, v, n) = writeType p k >> writeType p v >> writeI32 p n
-    writeMapEnd _ = return ()
-    writeListBegin p (t, n) = writeType p t >> writeI32 p n
-    writeListEnd _ = return ()
-    writeSetBegin p (t, n) = writeType p t >> writeI32 p n
-    writeSetEnd _ = return ()
-
-    writeBool p b = tWrite (getTransport p) $ LBS.singleton $ toEnum $ if b then 1 else 0
-    writeByte p b = tWrite (getTransport p) $ Data.Binary.encode b
-    writeI16 p b = tWrite (getTransport p) $ Data.Binary.encode b
-    writeI32 p b = tWrite (getTransport p) $ Data.Binary.encode b
-    writeI64 p b = tWrite (getTransport p) $ Data.Binary.encode b
-    writeDouble p d = writeI64 p (fromIntegral $ floatBits d)
-    writeString p s = writeI32 p (fromIntegral $ LBS.length s') >> tWrite (getTransport p) s'
+-- NOTE: Reading and Writing functions rely on Builders and Data.Binary to
+-- encode and decode data.  Data.Binary assumes that the binary values it is
+-- encoding to and decoding from are in BIG ENDIAN format, and converts the
+-- endianness as necessary to match the local machine.
+instance Transport t => Protocol (BinaryProtocol t) where
+    readByte p = tReadAll (getTransport p) 1
+    -- flushTransport p = tFlush (getTransport p)
+    writeMessage p (n, t, s) f = do
+      tWrite (getTransport p) messageBegin
+      f
+      tFlush $ getTransport p
       where
-        s' = encodeUtf8 s
-    writeBinary p s = writeI32 p (fromIntegral $ LBS.length s) >> tWrite (getTransport p) s
+        messageBegin = toLazyByteString $
+          buildBinaryValue (TI32 (version1 .|. fromIntegral (fromEnum t))) <>
+          buildBinaryValue (TString $ encodeUtf8 n) <>
+          buildBinaryValue (TI32 s)
 
-    readMessageBegin p = do
-        ver <- readI32 p
-        if (ver .&. version_mask /= version_1)
+    readMessage p = (readMessageBegin p >>=)
+      where
+        readMessageBegin p = runParser p $ do
+          TI32 ver <- parseBinaryValue T_I32
+          if ver .&. versionMask /= version1
             then throw $ ProtocolExn PE_BAD_VERSION "Missing version identifier"
             else do
-              s <- readString p
-              sz <- readI32 p
-              return (s, toEnum $ fromIntegral $ ver .&. 0xFF, sz)
-    readMessageEnd _ = return ()
-    readStructBegin _ = return ""
-    readStructEnd _ = return ()
-    readFieldBegin p = do
-        t <- readType p
-        n <- if t /= T_STOP then readI16 p else return 0
-        return ("", t, n)
-    readFieldEnd _ = return ()
-    readMapBegin p = do
-        kt <- readType p
-        vt <- readType p
-        n <- readI32 p
-        return (kt, vt, n)
-    readMapEnd _ = return ()
-    readListBegin p = do
-        t <- readType p
-        n <- readI32 p
-        return (t, n)
-    readListEnd _ = return ()
-    readSetBegin p = do
-        t <- readType p
-        n <- readI32 p
-        return (t, n)
-    readSetEnd _ = return ()
+              TString s <- parseBinaryValue T_STRING
+              TI32 sz <- parseBinaryValue T_I32
+              return (decodeUtf8 s, toEnum $ fromIntegral $ ver .&. 0xFF, sz)
 
-    readBool p = (== 1) `fmap` readByte p
+    writeVal p = tWrite (getTransport p) . toLazyByteString . buildBinaryValue
+    readVal p = runParser p . parseBinaryValue
 
-    readByte p = do
-        bs <- tReadAll (getTransport p) 1
-        return $ Data.Binary.decode bs
+instance Transport t => StatelessProtocol (BinaryProtocol t) where
+    serializeVal _ = toLazyByteString . buildBinaryValue
+    deserializeVal _ ty bs =
+      case LP.eitherResult $ LP.parse (parseBinaryValue ty) bs of
+        Left s -> error s
+        Right val -> val
 
-    readI16 p = do
-        bs <- tReadAll (getTransport p) 2
-        return $ Data.Binary.decode bs
+-- | Writing Functions
+buildBinaryValue :: ThriftVal -> Builder
+buildBinaryValue (TStruct fields) = buildBinaryStruct fields <> buildType T_STOP
+buildBinaryValue (TMap ky vt entries) =
+  buildType ky <>
+  buildType vt <>
+  int32BE (fromIntegral (length entries)) <>
+  buildBinaryMap entries
+buildBinaryValue (TList ty entries) =
+  buildType ty <>
+  int32BE (fromIntegral (length entries)) <>
+  buildBinaryList entries
+buildBinaryValue (TSet ty entries) =
+  buildType ty <>
+  int32BE (fromIntegral (length entries)) <>
+  buildBinaryList entries
+buildBinaryValue (TBool b) =
+  word8 $ toEnum $ if b then 1 else 0
+buildBinaryValue (TByte b) = int8 b
+buildBinaryValue (TI16 i) = int16BE i
+buildBinaryValue (TI32 i) = int32BE i
+buildBinaryValue (TI64 i) = int64BE i
+buildBinaryValue (TDouble d) = doubleBE d
+buildBinaryValue (TString s) = int32BE len <> lazyByteString s
+  where
+    len :: Int32 = fromIntegral (LBS.length s)
+buildBinaryValue (TBinary s) = buildBinaryValue (TString s)
 
-    readI32 p = do
-        bs <- tReadAll (getTransport p) 4
-        return $ Data.Binary.decode bs
+buildBinaryStruct :: Map.HashMap Int16 (LT.Text, ThriftVal) -> Builder
+buildBinaryStruct = Map.foldrWithKey combine mempty
+  where
+    combine fid (_,val) s =
+      buildTypeOf val <> int16BE fid <> buildBinaryValue val <> s
 
-    readI64 p = do
-        bs <- tReadAll (getTransport p) 8
-        return $ Data.Binary.decode bs
+buildBinaryMap :: [(ThriftVal, ThriftVal)] -> Builder
+buildBinaryMap = foldl combine mempty
+  where
+    combine s (key, val) = s <> buildBinaryValue key <> buildBinaryValue val
 
-    readDouble p = do
-        bs <- readI64 p
-        return $ floatOfBits $ fromIntegral bs
+buildBinaryList :: [ThriftVal] -> Builder
+buildBinaryList = foldr (mappend . buildBinaryValue) mempty
 
-    readString p = do
-        i <- readI32 p
-        decodeUtf8 `liftM` tReadAll (getTransport p) (fromIntegral i)
+-- | Reading Functions
+parseBinaryValue :: ThriftType -> P.Parser ThriftVal
+parseBinaryValue (T_STRUCT tmap) = TStruct <$> parseBinaryStruct tmap
+parseBinaryValue (T_MAP _ _) = do
+  kt <- parseType
+  vt <- parseType
+  n <- Binary.decode . LBS.fromStrict <$> P.take 4
+  TMap kt vt <$> parseBinaryMap kt vt n
+parseBinaryValue (T_LIST _) = do
+  t <- parseType
+  n <- Binary.decode . LBS.fromStrict <$> P.take 4
+  TList t <$> parseBinaryList t n
+parseBinaryValue (T_SET _) = do
+  t <- parseType
+  n <- Binary.decode . LBS.fromStrict <$> P.take 4
+  TSet t <$> parseBinaryList t n
+parseBinaryValue T_BOOL = TBool . (/=0) <$> P.anyWord8
+parseBinaryValue T_BYTE = TByte . Binary.decode . LBS.fromStrict <$> P.take 1
+parseBinaryValue T_I16 = TI16 . Binary.decode . LBS.fromStrict <$> P.take 2
+parseBinaryValue T_I32 = TI32 . Binary.decode . LBS.fromStrict <$> P.take 4
+parseBinaryValue T_I64 = TI64 . Binary.decode . LBS.fromStrict <$> P.take 8
+parseBinaryValue T_DOUBLE = TDouble . bsToDouble <$> P.take 8
+parseBinaryValue T_STRING = parseBinaryString TString
+parseBinaryValue T_BINARY = parseBinaryString TBinary
+parseBinaryValue ty = error $ "Cannot read value of type " ++ show ty
 
-    readBinary p = do
-        i <- readI32 p
-        tReadAll (getTransport p) (fromIntegral i)
+parseBinaryString ty = do
+  i :: Int32  <- Binary.decode . LBS.fromStrict <$> P.take 4
+  ty . LBS.fromStrict <$> P.take (fromIntegral i)
+
+parseBinaryStruct :: TypeMap -> P.Parser (Map.HashMap Int16 (LT.Text, ThriftVal))
+parseBinaryStruct tmap = Map.fromList <$> P.manyTill parseField (matchType T_STOP)
+  where
+    parseField = do
+      t <- parseType
+      n <- Binary.decode . LBS.fromStrict <$> P.take 2
+      v <- case (t, Map.lookup n tmap) of
+             (T_STRING, Just (_, T_BINARY)) -> parseBinaryValue T_BINARY
+             _ -> parseBinaryValue t
+      return (n, ("", v))
+
+parseBinaryMap :: ThriftType -> ThriftType -> Int32 -> P.Parser [(ThriftVal, ThriftVal)]
+parseBinaryMap kt vt n | n <= 0 = return []
+                       | otherwise = do
+  k <- parseBinaryValue kt
+  v <- parseBinaryValue vt
+  ((k,v) :) <$> parseBinaryMap kt vt (n-1)
+
+parseBinaryList :: ThriftType -> Int32 -> P.Parser [ThriftVal]
+parseBinaryList ty n | n <= 0 = return []
+                     | otherwise = liftM2 (:) (parseBinaryValue ty)
+                                   (parseBinaryList ty (n-1))
+
 
 
 -- | Write a type as a byte
-writeType :: (Protocol p, Transport t) => p t -> ThriftType -> IO ()
-writeType p t = writeByte p (fromIntegral $ fromEnum t)
+buildType :: ThriftType -> Builder
+buildType t = word8 $ fromIntegral $ fromEnum t
+
+-- | Write type of a ThriftVal as a byte
+buildTypeOf :: ThriftVal -> Builder
+buildTypeOf = buildType . getTypeOf
 
 -- | Read a byte as though it were a ThriftType
-readType :: (Protocol p, Transport t) => p t -> IO ThriftType
-readType p = do
-    b <- readByte p
-    return $ toEnum $ fromIntegral b
+parseType :: P.Parser ThriftType
+parseType = toEnum . fromIntegral <$> P.anyWord8
 
-floatBits :: Double -> Word64
-floatBits (D# d#) = W64# (unsafeCoerce# d#)
-
-floatOfBits :: Word64 -> Double
-floatOfBits (W64# b#) = D# (unsafeCoerce# b#)
-
+matchType :: ThriftType -> P.Parser ThriftType
+matchType t = t <$ P.word8 (fromIntegral $ fromEnum t)
diff --git a/lib/hs/src/Thrift/Protocol/Compact.hs b/lib/hs/src/Thrift/Protocol/Compact.hs
new file mode 100644
index 0000000..f23970a
--- /dev/null
+++ b/lib/hs/src/Thrift/Protocol/Compact.hs
@@ -0,0 +1,311 @@
+--
+-- 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.
+--
+
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module Thrift.Protocol.Compact
+    ( module Thrift.Protocol
+    , CompactProtocol(..)
+    , parseVarint
+    , buildVarint
+    ) where
+
+import Control.Applicative
+import Control.Monad
+import Data.Attoparsec.ByteString as P
+import Data.Attoparsec.ByteString.Lazy as LP
+import Data.Bits
+import Data.ByteString.Lazy.Builder as B
+import Data.Int
+import Data.List as List
+import Data.Monoid
+import Data.Word
+import Data.Text.Lazy.Encoding ( decodeUtf8, encodeUtf8 )
+
+import Thrift.Protocol
+import Thrift.Transport
+import Thrift.Types
+
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as LBS
+import qualified Data.HashMap.Strict as Map
+import qualified Data.Text.Lazy as LT
+
+-- | the Compact Protocol implements the standard Thrift 'TCompactProcotol'
+-- which is similar to the 'TBinaryProtocol', but takes less space on the wire.
+-- Integral types are encoded using as varints.
+data CompactProtocol a = CompactProtocol a
+                         -- ^ Constuct a 'CompactProtocol' with a 'Transport'
+
+protocolID, version, versionMask, typeMask, typeBits :: Word8
+protocolID  = 0x82 -- 1000 0010
+version     = 0x01
+versionMask = 0x1f -- 0001 1111
+typeMask    = 0xe0 -- 1110 0000
+typeBits    = 0x07 -- 0000 0111
+typeShiftAmount :: Int
+typeShiftAmount = 5
+
+getTransport :: Transport t => CompactProtocol t -> t
+getTransport (CompactProtocol t) = t
+
+instance Transport t => Protocol (CompactProtocol t) where
+    readByte p = tReadAll (getTransport p) 1
+    writeMessage p (n, t, s) f = do
+      tWrite (getTransport p) messageBegin
+      f
+      tFlush $ getTransport p
+      where
+        messageBegin = toLazyByteString $
+          B.word8 protocolID <>
+          B.word8 ((version .&. versionMask) .|.
+                  (((fromIntegral $ fromEnum t) `shiftL`
+                  typeShiftAmount) .&. typeMask)) <>
+          buildVarint (i32ToZigZag s) <>
+          buildCompactValue (TString $ encodeUtf8 n)
+
+    readMessage p f = readMessageBegin >>= f
+      where
+        readMessageBegin = runParser p $ do
+          pid <- fromIntegral <$> P.anyWord8
+          when (pid /= protocolID) $ error "Bad Protocol ID"
+          w <- fromIntegral <$> P.anyWord8
+          let ver = w .&. versionMask
+          when (ver /= version) $ error "Bad Protocol version"
+          let typ = (w `shiftR` typeShiftAmount) .&. typeBits
+          seqId <- parseVarint zigZagToI32
+          TString name <- parseCompactValue T_STRING
+          return (decodeUtf8 name, toEnum $ fromIntegral $ typ, seqId)
+
+    writeVal p = tWrite (getTransport p) . toLazyByteString . buildCompactValue
+    readVal p ty = runParser p $ parseCompactValue ty
+
+instance Transport t => StatelessProtocol (CompactProtocol t) where
+    serializeVal _ = toLazyByteString . buildCompactValue
+    deserializeVal _ ty bs =
+      case LP.eitherResult $ LP.parse (parseCompactValue ty) bs of
+        Left s -> error s
+        Right val -> val
+
+-- | Writing Functions
+buildCompactValue :: ThriftVal -> Builder
+buildCompactValue (TStruct fields) = buildCompactStruct fields
+buildCompactValue (TMap kt vt entries) =
+  let len = fromIntegral $ length entries :: Word32 in
+  if len == 0
+  then B.word8 0x00
+  else buildVarint len <>
+       B.word8 (fromTType kt `shiftL` 4 .|. fromTType vt) <>
+       buildCompactMap entries
+buildCompactValue (TList ty entries) =
+  let len = length entries in
+  (if len < 15
+   then B.word8 $ (fromIntegral len `shiftL` 4) .|. fromTType ty
+   else B.word8 (0xF0 .|. fromTType ty) <>
+        buildVarint (fromIntegral len :: Word32)) <>
+  buildCompactList entries
+buildCompactValue (TSet ty entries) = buildCompactValue (TList ty entries)
+buildCompactValue (TBool b) =
+  B.word8 $ toEnum $ if b then 1 else 0
+buildCompactValue (TByte b) = int8 b
+buildCompactValue (TI16 i) = buildVarint $ i16ToZigZag i
+buildCompactValue (TI32 i) = buildVarint $ i32ToZigZag i
+buildCompactValue (TI64 i) = buildVarint $ i64ToZigZag i
+buildCompactValue (TDouble d) = doubleLE d
+buildCompactValue (TString s) = buildVarint len <> lazyByteString s
+  where
+    len = fromIntegral (LBS.length s) :: Word32
+buildCompactValue (TBinary s) = buildCompactValue (TString s)
+
+buildCompactStruct :: Map.HashMap Int16 (LT.Text, ThriftVal) -> Builder
+buildCompactStruct = flip (loop 0) mempty . Map.toList
+  where
+    loop _ [] acc = acc <> B.word8 (fromTType T_STOP)
+    loop lastId ((fid, (_,val)) : fields) acc = loop fid fields $ acc <>
+      (if fid > lastId && fid - lastId <= 15
+       then B.word8 $ fromIntegral ((fid - lastId) `shiftL` 4) .|. typeOf val
+       else B.word8 (typeOf val) <> buildVarint (i16ToZigZag fid)) <>
+      (if typeOf val > 0x02 -- Not a T_BOOL
+       then buildCompactValue val
+       else mempty) -- T_BOOLs are encoded in the type
+buildCompactMap :: [(ThriftVal, ThriftVal)] -> Builder
+buildCompactMap = foldl combine mempty
+  where
+    combine s (key, val) = buildCompactValue key <> buildCompactValue val <> s
+
+buildCompactList :: [ThriftVal] -> Builder
+buildCompactList = foldr (mappend . buildCompactValue) mempty
+
+-- | Reading Functions
+parseCompactValue :: ThriftType -> Parser ThriftVal
+parseCompactValue (T_STRUCT tmap) = TStruct <$> parseCompactStruct tmap
+parseCompactValue (T_MAP kt' vt') = do
+  n <- parseVarint id
+  if n == 0
+    then return $ TMap kt' vt' []
+    else do
+    w <- P.anyWord8
+    let kt = typeFrom $ w `shiftR` 4
+        vt = typeFrom $ w .&. 0x0F
+    TMap kt vt <$> parseCompactMap kt vt n
+parseCompactValue (T_LIST ty) = TList ty <$> parseCompactList
+parseCompactValue (T_SET ty) = TSet ty <$> parseCompactList
+parseCompactValue T_BOOL = TBool . (/=0) <$> P.anyWord8
+parseCompactValue T_BYTE = TByte . fromIntegral <$> P.anyWord8
+parseCompactValue T_I16 = TI16 <$> parseVarint zigZagToI16
+parseCompactValue T_I32 = TI32 <$> parseVarint zigZagToI32
+parseCompactValue T_I64 = TI64 <$> parseVarint zigZagToI64
+parseCompactValue T_DOUBLE = TDouble . bsToDoubleLE <$> P.take 8
+parseCompactValue T_STRING = parseCompactString TString
+parseCompactValue T_BINARY = parseCompactString TBinary
+parseCompactValue ty = error $ "Cannot read value of type " ++ show ty
+
+parseCompactString ty = do
+  len :: Word32 <- parseVarint id
+  ty . LBS.fromStrict <$> P.take (fromIntegral len)
+
+parseCompactStruct :: TypeMap -> Parser (Map.HashMap Int16 (LT.Text, ThriftVal))
+parseCompactStruct tmap = Map.fromList <$> parseFields 0
+  where
+    parseFields :: Int16 -> Parser [(Int16, (LT.Text, ThriftVal))]
+    parseFields lastId = do
+      w <- P.anyWord8
+      if w == 0x00
+        then return []
+        else do
+          let ty = typeFrom (w .&. 0x0F)
+              modifier = (w .&. 0xF0) `shiftR` 4
+          fid <- if modifier /= 0
+                 then return (lastId + fromIntegral modifier)
+                 else parseVarint zigZagToI16
+          val <- if ty == T_BOOL
+                 then return (TBool $ (w .&. 0x0F) == 0x01)
+                 else case (ty, Map.lookup fid tmap) of
+                        (T_STRING, Just (_, T_BINARY)) -> parseCompactValue T_BINARY
+                        _ -> parseCompactValue ty
+          ((fid, (LT.empty, val)) : ) <$> parseFields fid
+
+parseCompactMap :: ThriftType -> ThriftType -> Int32 ->
+                   Parser [(ThriftVal, ThriftVal)]
+parseCompactMap kt vt n | n <= 0 = return []
+                        | otherwise = do
+  k <- parseCompactValue kt
+  v <- parseCompactValue vt
+  ((k,v) :) <$> parseCompactMap kt vt (n-1)
+
+parseCompactList :: Parser [ThriftVal]
+parseCompactList = do
+  w <- P.anyWord8
+  let ty = typeFrom $ w .&. 0x0F
+      lsize = w `shiftR` 4
+  size <- if lsize == 0xF
+          then parseVarint id
+          else return $ fromIntegral lsize
+  loop ty size
+  where
+    loop :: ThriftType -> Int32 -> Parser [ThriftVal]
+    loop ty n | n <= 0 = return []
+              | otherwise = liftM2 (:) (parseCompactValue ty)
+                            (loop ty (n-1))
+
+-- Signed numbers must be converted to "Zig Zag" format before they can be
+-- serialized in the Varint format
+i16ToZigZag :: Int16 -> Word16
+i16ToZigZag n = fromIntegral $ (n `shiftL` 1) `xor` (n `shiftR` 15)
+
+zigZagToI16 :: Word16 -> Int16
+zigZagToI16 n = fromIntegral $ (n `shiftR` 1) `xor` negate (n .&. 0x1)
+
+i32ToZigZag :: Int32 -> Word32
+i32ToZigZag n = fromIntegral $ (n `shiftL` 1) `xor` (n `shiftR` 31)
+
+zigZagToI32 :: Word32 -> Int32
+zigZagToI32 n = fromIntegral $ (n `shiftR` 1) `xor` negate (n .&. 0x1)
+
+i64ToZigZag :: Int64 -> Word64
+i64ToZigZag n = fromIntegral $ (n `shiftL` 1) `xor` (n `shiftR` 63)
+
+zigZagToI64 :: Word64 -> Int64
+zigZagToI64 n = fromIntegral $ (n `shiftR` 1) `xor` negate (n .&. 0x1)
+
+buildVarint :: (Bits a, Integral a)  => a -> Builder
+buildVarint n | n .&. complement 0x7F == 0 = B.word8 $ fromIntegral n
+              | otherwise = B.word8 (0x80 .|. (fromIntegral n .&. 0x7F)) <>
+                            buildVarint (n `shiftR` 7)
+
+parseVarint :: (Bits a, Integral a, Ord a) => (a -> b) -> Parser b
+parseVarint fromZigZag = do
+  bytestemp <- BS.unpack <$> P.takeTill (not . flip testBit 7)
+  lsb <- P.anyWord8
+  let bytes = lsb : List.reverse bytestemp
+  return $ fromZigZag $ List.foldl' combine 0x00 bytes
+  where combine a b = (a `shiftL` 7) .|. (fromIntegral b .&. 0x7f)
+
+-- | Compute the Compact Type
+fromTType :: ThriftType -> Word8
+fromTType ty = case ty of
+  T_STOP -> 0x00
+  T_BOOL -> 0x01
+  T_BYTE -> 0x03
+  T_I16 -> 0x04
+  T_I32 -> 0x05
+  T_I64 -> 0x06
+  T_DOUBLE -> 0x07
+  T_STRING -> 0x08
+  T_BINARY -> 0x08
+  T_LIST{} -> 0x09
+  T_SET{} -> 0x0A
+  T_MAP{} -> 0x0B
+  T_STRUCT{} -> 0x0C
+  T_VOID -> error "No Compact type for T_VOID"
+
+typeOf :: ThriftVal -> Word8
+typeOf v = case v of
+  TBool True -> 0x01
+  TBool False -> 0x02
+  TByte _ -> 0x03
+  TI16 _ -> 0x04
+  TI32 _ -> 0x05
+  TI64 _ -> 0x06
+  TDouble _ -> 0x07
+  TString _ -> 0x08
+  TBinary _ -> 0x08
+  TList{} -> 0x09
+  TSet{} -> 0x0A
+  TMap{} -> 0x0B
+  TStruct{} -> 0x0C
+
+typeFrom :: Word8 -> ThriftType
+typeFrom w = case w of
+  0x01 -> T_BOOL
+  0x02 -> T_BOOL
+  0x03 -> T_BYTE
+  0x04 -> T_I16
+  0x05 -> T_I32
+  0x06 -> T_I64
+  0x07 -> T_DOUBLE
+  0x08 -> T_STRING
+  0x09 -> T_LIST T_VOID
+  0x0A -> T_SET T_VOID
+  0x0B -> T_MAP T_VOID T_VOID
+  0x0C -> T_STRUCT Map.empty
+  n -> error $ "typeFrom: " ++ show n ++ " is not a compact type"
diff --git a/lib/hs/src/Thrift/Protocol/Header.hs b/lib/hs/src/Thrift/Protocol/Header.hs
new file mode 100644
index 0000000..5f42db4
--- /dev/null
+++ b/lib/hs/src/Thrift/Protocol/Header.hs
@@ -0,0 +1,141 @@
+--
+-- 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.
+--
+
+
+module Thrift.Protocol.Header
+    ( module Thrift.Protocol
+    , HeaderProtocol(..)
+    , getProtocolType
+    , setProtocolType
+    , getHeaders
+    , getWriteHeaders
+    , setHeader
+    , setHeaders
+    , createHeaderProtocol
+    , createHeaderProtocol1
+    ) where
+
+import Thrift.Protocol
+import Thrift.Protocol.Binary
+import Thrift.Protocol.JSON
+import Thrift.Protocol.Compact
+import Thrift.Transport
+import Thrift.Transport.Header
+import Data.IORef
+import qualified Data.Map as Map
+
+data ProtocolWrap = forall a. (Protocol a) => ProtocolWrap(a)
+
+instance Protocol ProtocolWrap where
+  readByte (ProtocolWrap p) = readByte p
+  readVal (ProtocolWrap p) = readVal p
+  readMessage (ProtocolWrap p) = readMessage p
+  writeVal (ProtocolWrap p) = writeVal p
+  writeMessage (ProtocolWrap p) = writeMessage p
+
+data HeaderProtocol i o = (Transport i, Transport o) => HeaderProtocol {
+    trans :: HeaderTransport i o,
+    wrappedProto :: IORef ProtocolWrap
+  }
+
+createProtocolWrap :: Transport t => ProtocolType -> t -> ProtocolWrap
+createProtocolWrap typ t =
+  case typ of
+    TBinary -> ProtocolWrap $ BinaryProtocol t
+    TCompact -> ProtocolWrap $ CompactProtocol t
+    TJSON -> ProtocolWrap $ JSONProtocol t
+
+createHeaderProtocol :: (Transport i, Transport o) => i -> o -> IO(HeaderProtocol i o)
+createHeaderProtocol i o = do
+  t <- openHeaderTransport i o
+  pid <- readIORef $ protocolType t
+  proto <- newIORef $ createProtocolWrap pid t
+  return $ HeaderProtocol { trans = t, wrappedProto = proto }
+
+createHeaderProtocol1 :: Transport t => t -> IO(HeaderProtocol t t)
+createHeaderProtocol1 t = createHeaderProtocol t t
+
+resetProtocol :: (Transport i, Transport o) => HeaderProtocol i o -> IO ()
+resetProtocol p = do
+  pid <- readIORef $ protocolType $ trans p
+  writeIORef (wrappedProto p) $ createProtocolWrap pid $ trans p
+
+getWrapped = readIORef . wrappedProto
+
+setTransport :: (Transport i, Transport o) => HeaderProtocol i o -> HeaderTransport i o -> HeaderProtocol i o
+setTransport p t = p { trans = t }
+
+updateTransport :: (Transport i, Transport o) => HeaderProtocol i o -> (HeaderTransport i o -> HeaderTransport i o)-> HeaderProtocol i o
+updateTransport p f = setTransport p (f $ trans p)
+
+type Headers = Map.Map String String
+
+-- TODO: we want to set headers without recreating client...
+setHeader :: (Transport i, Transport o) => HeaderProtocol i o -> String -> String -> HeaderProtocol i o
+setHeader p k v = updateTransport p $ \t -> t { writeHeaders = Map.insert k v $ writeHeaders t }
+
+setHeaders :: (Transport i, Transport o) => HeaderProtocol i o -> Headers -> HeaderProtocol i o
+setHeaders p h = updateTransport p $ \t -> t { writeHeaders = h }
+
+-- TODO: make it public once we have first transform implementation for Haskell
+setTransforms :: (Transport i, Transport o) => HeaderProtocol i o -> [TransformType] -> HeaderProtocol i o
+setTransforms p trs = updateTransport p $ \t -> t { writeTransforms = trs }
+
+setTransform :: (Transport i, Transport o) => HeaderProtocol i o -> TransformType -> HeaderProtocol i o
+setTransform p tr = updateTransport p $ \t -> t { writeTransforms = tr:(writeTransforms t) }
+
+getWriteHeaders :: (Transport i, Transport o) => HeaderProtocol i o -> Headers
+getWriteHeaders = writeHeaders . trans
+
+getHeaders :: (Transport i, Transport o) => HeaderProtocol i o -> IO [(String, String)]
+getHeaders = readIORef . headers . trans
+
+getProtocolType :: (Transport i, Transport o) => HeaderProtocol i o -> IO ProtocolType
+getProtocolType p = readIORef $ protocolType $ trans p
+
+setProtocolType :: (Transport i, Transport o) => HeaderProtocol i o -> ProtocolType -> IO ()
+setProtocolType p typ = do
+  typ0 <- getProtocolType p
+  if typ == typ0
+    then return ()
+    else do
+      tSetProtocol (trans p) typ
+      resetProtocol p
+
+instance (Transport i, Transport o) => Protocol (HeaderProtocol i o) where
+  readByte p = tReadAll (trans p) 1
+
+  readVal p tp = do
+    proto <- getWrapped p
+    readVal proto tp
+
+  readMessage p f = do
+    tResetProtocol (trans p)
+    resetProtocol p
+    proto <- getWrapped p
+    readMessage proto f
+
+  writeVal p v = do
+    proto <- getWrapped p
+    writeVal proto v
+
+  writeMessage p x f = do
+    proto <- getWrapped p
+    writeMessage proto x f
+
diff --git a/lib/hs/src/Thrift/Protocol/JSON.hs b/lib/hs/src/Thrift/Protocol/JSON.hs
new file mode 100644
index 0000000..839eddc
--- /dev/null
+++ b/lib/hs/src/Thrift/Protocol/JSON.hs
@@ -0,0 +1,362 @@
+--
+-- 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.
+--
+
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TupleSections #-}
+
+module Thrift.Protocol.JSON
+    ( module Thrift.Protocol
+    , JSONProtocol(..)
+    ) where
+
+import Control.Applicative
+import Control.Exception (bracket)
+import Control.Monad
+import Data.Attoparsec.ByteString as P
+import Data.Attoparsec.ByteString.Char8 as PC
+import Data.Attoparsec.ByteString.Lazy as LP
+import Data.ByteString.Base64.Lazy as B64C
+import Data.ByteString.Lazy.Builder as B
+import Data.ByteString.Internal (c2w, w2c)
+import Data.Functor
+import Data.Int
+import Data.List
+import Data.Maybe (catMaybes)
+import Data.Monoid
+import Data.Text.Lazy.Encoding
+import Data.Word
+import qualified Data.HashMap.Strict as Map
+
+import Thrift.Protocol
+import Thrift.Transport
+import Thrift.Types
+
+import qualified Data.ByteString.Lazy as LBS
+import qualified Data.ByteString.Lazy.Char8 as LBSC
+import qualified Data.Text.Lazy as LT
+
+-- | The JSON Protocol data uses the standard 'TJSONProtocol'.  Data is
+-- encoded as a JSON 'ByteString'
+data JSONProtocol t = JSONProtocol t
+                      -- ^ Construct a 'JSONProtocol' with a 'Transport'
+getTransport :: Transport t => JSONProtocol t -> t
+getTransport (JSONProtocol t) = t
+
+instance Transport t => Protocol (JSONProtocol t) where
+    readByte p = tReadAll (getTransport p) 1
+
+    writeMessage (JSONProtocol t) (s, ty, sq) = bracket readMessageBegin readMessageEnd . const
+      where
+        readMessageBegin = tWrite t $ toLazyByteString $
+          B.char8 '[' <> buildShowable (1 :: Int32) <>
+          B.string8 ",\"" <> escape (encodeUtf8 s) <> B.char8 '\"' <>
+          B.char8 ',' <> buildShowable (fromEnum ty) <>
+          B.char8 ',' <> buildShowable sq <>
+          B.char8 ','
+        readMessageEnd _ = do
+          tWrite t "]"
+          tFlush t
+
+    readMessage p = bracket readMessageBegin readMessageEnd
+      where
+        readMessageBegin = runParser p $ skipSpace *> do
+          _ver :: Int32 <- lexeme (PC.char8 '[') *> lexeme (signed decimal)
+          bs <- lexeme (PC.char8 ',') *> lexeme escapedString
+          case decodeUtf8' bs of
+            Left _ -> fail "readMessage: invalid text encoding"
+            Right str -> do
+              ty <- toEnum <$> (lexeme (PC.char8 ',') *> lexeme (signed decimal))
+              seqNum <- lexeme (PC.char8 ',') *> lexeme (signed decimal)
+              _ <- PC.char8 ','
+              return (str, ty, seqNum)
+        readMessageEnd _ = void $ runParser p (PC.char8 ']')
+
+    writeVal p = tWrite (getTransport p) . toLazyByteString . buildJSONValue
+    readVal p ty = runParser p $ skipSpace *> parseJSONValue ty
+
+instance Transport t => StatelessProtocol (JSONProtocol t) where
+    serializeVal _ = toLazyByteString . buildJSONValue
+    deserializeVal _ ty bs =
+      case LP.eitherResult $ LP.parse (parseJSONValue ty) bs of
+        Left s -> error s
+        Right val -> val
+
+-- Writing Functions
+
+buildJSONValue :: ThriftVal -> Builder
+buildJSONValue (TStruct fields) = B.char8 '{' <> buildJSONStruct fields <> B.char8 '}'
+buildJSONValue (TMap kt vt entries) =
+  B.char8 '[' <> B.char8 '"' <> getTypeName kt <> B.char8 '"' <>
+  B.char8 ',' <> B.char8 '"' <> getTypeName vt <> B.char8 '"' <>
+  B.char8 ',' <> buildShowable (length entries) <>
+  B.char8 ',' <> B.char8 '{' <> buildJSONMap entries <> B.char8 '}' <>
+  B.char8 ']'
+buildJSONValue (TList ty entries) =
+  B.char8 '[' <> B.char8 '"' <> getTypeName ty <> B.char8 '"' <>
+  B.char8 ',' <> buildShowable (length entries) <>
+  (if length entries > 0
+   then B.char8 ',' <> buildJSONList entries
+   else mempty) <>
+  B.char8 ']'
+buildJSONValue (TSet ty entries) = buildJSONValue (TList ty entries)
+buildJSONValue (TBool b) = if b then B.char8 '1' else B.char8 '0'
+buildJSONValue (TByte b) = buildShowable b
+buildJSONValue (TI16 i) = buildShowable i
+buildJSONValue (TI32 i) = buildShowable i
+buildJSONValue (TI64 i) = buildShowable i
+buildJSONValue (TDouble d) = buildShowable d
+buildJSONValue (TString s) = B.char8 '\"' <> escape s <> B.char8 '\"'
+buildJSONValue (TBinary s) = B.char8 '\"' <> (B.lazyByteString . B64C.encode $ s) <> B.char8 '\"'
+
+buildJSONStruct :: Map.HashMap Int16 (LT.Text, ThriftVal) -> Builder
+buildJSONStruct = mconcat . intersperse (B.char8 ',') . Map.foldrWithKey buildField []
+  where 
+    buildField fid (_,val) = (:) $
+      B.char8 '"' <> buildShowable fid <> B.string8 "\":" <> 
+      B.char8 '{' <>
+      B.char8 '"' <> getTypeName (getTypeOf val) <> B.string8 "\":" <>
+      buildJSONValue val <>
+      B.char8 '}'
+
+buildJSONMap :: [(ThriftVal, ThriftVal)] -> Builder
+buildJSONMap = mconcat . intersperse (B.char8 ',') . map buildKV
+  where
+    buildKV (key@(TString _), val) =
+      buildJSONValue key <> B.char8 ':' <> buildJSONValue val
+    buildKV (key, val) =
+      B.char8 '\"' <> buildJSONValue key <> B.string8 "\":" <> buildJSONValue val
+buildJSONList :: [ThriftVal] -> Builder
+buildJSONList = mconcat . intersperse (B.char8 ',') . map buildJSONValue
+
+buildShowable :: Show a => a ->  Builder
+buildShowable = B.string8 . show
+
+-- Reading Functions
+
+parseJSONValue :: ThriftType -> Parser ThriftVal
+parseJSONValue (T_STRUCT tmap) =
+  TStruct <$> (lexeme (PC.char8 '{') *> parseJSONStruct tmap <* PC.char8 '}')
+parseJSONValue (T_MAP kt vt) = fmap (TMap kt vt) $
+  between '[' ']' $
+    lexeme escapedString *> lexeme (PC.char8 ',') *>
+    lexeme escapedString *> lexeme (PC.char8 ',') *>
+    lexeme decimal *> lexeme (PC.char8 ',') *>
+    between '{' '}' (parseJSONMap kt vt)
+parseJSONValue (T_LIST ty) = fmap (TList ty) $
+  between '[' ']' $ do
+    len <- lexeme escapedString *> lexeme (PC.char8 ',') *> lexeme decimal
+    if len > 0
+      then lexeme (PC.char8 ',') *> parseJSONList ty
+      else return []
+parseJSONValue (T_SET ty) = fmap (TSet ty) $
+  between '[' ']' $ do
+    len <- lexeme escapedString *> lexeme (PC.char8 ',') *> lexeme decimal
+    if len > 0
+      then  lexeme (PC.char8 ',') *> parseJSONList ty
+      else return []
+parseJSONValue T_BOOL =
+  (TBool True <$ PC.char8 '1') <|> (TBool False <$ PC.char8 '0')
+parseJSONValue T_BYTE = TByte <$> signed decimal
+parseJSONValue T_I16 = TI16 <$> signed decimal
+parseJSONValue T_I32 = TI32 <$> signed decimal
+parseJSONValue T_I64 = TI64 <$> signed decimal
+parseJSONValue T_DOUBLE = TDouble <$> double
+parseJSONValue T_STRING = TString <$> escapedString
+parseJSONValue T_BINARY = TBinary <$> base64String
+parseJSONValue T_STOP = fail "parseJSONValue: cannot parse type T_STOP"
+parseJSONValue T_VOID = fail "parseJSONValue: cannot parse type T_VOID"
+
+parseAnyValue :: Parser ()
+parseAnyValue = choice $
+                skipBetween '{' '}' :
+                skipBetween '[' ']' :
+                map (void . parseJSONValue)
+                  [ T_BOOL
+                  , T_I16
+                  , T_I32
+                  , T_I64
+                  , T_DOUBLE
+                  , T_STRING
+                  , T_BINARY
+                  ]
+  where
+    skipBetween :: Char -> Char -> Parser ()
+    skipBetween a b = between a b $ void (PC.satisfy (\c -> c /= a && c /= b))
+                                          <|> skipBetween a b
+
+parseJSONStruct :: TypeMap -> Parser (Map.HashMap Int16 (LT.Text, ThriftVal))
+parseJSONStruct tmap = Map.fromList . catMaybes <$> parseField
+                       `sepBy` lexeme (PC.char8 ',')
+  where
+    parseField = do
+      fid <- lexeme (between '"' '"' decimal) <* lexeme (PC.char8 ':')
+      case Map.lookup fid tmap of
+        Just (str, ftype) -> between '{' '}' $ do
+          _ <- lexeme (escapedString) *> lexeme (PC.char8 ':')
+          val <- lexeme (parseJSONValue ftype)
+          return $ Just (fid, (str, val))
+        Nothing -> lexeme parseAnyValue *> return Nothing
+
+parseJSONMap :: ThriftType -> ThriftType -> Parser [(ThriftVal, ThriftVal)]
+parseJSONMap kt vt =
+  ((,) <$> lexeme (parseJSONKey kt) <*>
+   (lexeme (PC.char8 ':') *> lexeme (parseJSONValue vt))) `sepBy`
+  lexeme (PC.char8 ',')
+  where
+    parseJSONKey T_STRING = parseJSONValue T_STRING
+    parseJSONKey T_BINARY = parseJSONValue T_BINARY
+    parseJSONKey kt = PC.char8 '"' *> parseJSONValue kt <* PC.char8 '"'
+
+parseJSONList :: ThriftType -> Parser [ThriftVal]
+parseJSONList ty = lexeme (parseJSONValue ty) `sepBy` lexeme (PC.char8 ',')
+
+escapedString :: Parser LBS.ByteString
+escapedString = PC.char8 '"' *>
+                (LBS.pack <$> P.many' (escapedChar <|> notChar8 '"')) <*
+                PC.char8 '"'
+
+base64String :: Parser LBS.ByteString
+base64String = PC.char8 '"' *>
+               (decodeBase64 . LBSC.pack <$> P.many' (PC.notChar '"')) <*
+               PC.char8 '"'
+               where
+                 decodeBase64 b =
+                   let padded = case (LBS.length b) `mod` 4 of
+                                  2 -> LBS.append b "=="
+                                  3 -> LBS.append b "="
+                                  _ -> b in
+                   case B64C.decode padded of
+                     Right s -> s
+                     Left x -> error x
+
+escapedChar :: Parser Word8
+escapedChar = PC.char8 '\\' *> (c2w <$> choice
+                                [ '\SOH' <$ P.string "u0001"
+                                , '\STX' <$ P.string "u0002"
+                                , '\ETX' <$ P.string "u0003"
+                                , '\EOT' <$ P.string "u0004"
+                                , '\ENQ' <$ P.string "u0005"
+                                , '\ACK' <$ P.string "u0006"
+                                , '\BEL' <$ P.string "u0007"
+                                , '\BS'  <$ P.string "u0008"
+                                , '\VT'  <$ P.string "u000b"
+                                , '\FF'  <$ P.string "u000c"
+                                , '\CR'  <$ P.string "u000d"
+                                , '\SO'  <$ P.string "u000e"
+                                , '\SI'  <$ P.string "u000f"
+                                , '\DLE' <$ P.string "u0010"
+                                , '\DC1' <$ P.string "u0011"
+                                , '\DC2' <$ P.string "u0012"
+                                , '\DC3' <$ P.string "u0013"
+                                , '\DC4' <$ P.string "u0014"
+                                , '\NAK' <$ P.string "u0015"
+                                , '\SYN' <$ P.string "u0016"
+                                , '\ETB' <$ P.string "u0017"
+                                , '\CAN' <$ P.string "u0018"
+                                , '\EM'  <$ P.string "u0019"
+                                , '\SUB' <$ P.string "u001a"
+                                , '\ESC' <$ P.string "u001b"
+                                , '\FS'  <$ P.string "u001c"
+                                , '\GS'  <$ P.string "u001d"
+                                , '\RS'  <$ P.string "u001e"
+                                , '\US'  <$ P.string "u001f"
+                                , '\DEL' <$ P.string "u007f"
+                                , '\0' <$ PC.char '0'
+                                , '\a' <$ PC.char 'a'
+                                , '\b' <$ PC.char 'b'
+                                , '\f' <$ PC.char 'f'
+                                , '\n' <$ PC.char 'n'
+                                , '\r' <$ PC.char 'r'
+                                , '\t' <$ PC.char 't'
+                                , '\v' <$ PC.char 'v'
+                                , '\"' <$ PC.char '"'
+                                , '\'' <$ PC.char '\''
+                                , '\\' <$ PC.char '\\'
+                                , '/'  <$ PC.char '/'
+                                ])
+
+escape :: LBS.ByteString -> Builder
+escape = LBS.foldl' escapeChar mempty
+  where
+    escapeChar b w = b <> (B.lazyByteString $ case w2c w of
+      '\0' -> "\\0"
+      '\b' -> "\\b"
+      '\f' -> "\\f"
+      '\n' -> "\\n"
+      '\r' -> "\\r"
+      '\t' -> "\\t"
+      '\"' -> "\\\""
+      '\\' -> "\\\\"
+      '\SOH' -> "\\u0001"
+      '\STX' -> "\\u0002"
+      '\ETX' -> "\\u0003"
+      '\EOT' -> "\\u0004"
+      '\ENQ' -> "\\u0005"
+      '\ACK' -> "\\u0006"
+      '\BEL' -> "\\u0007"
+      '\VT'  -> "\\u000b"
+      '\SO'  -> "\\u000e"
+      '\SI'  -> "\\u000f"
+      '\DLE' -> "\\u0010"
+      '\DC1' -> "\\u0011"
+      '\DC2' -> "\\u0012"
+      '\DC3' -> "\\u0013"
+      '\DC4' -> "\\u0014"
+      '\NAK' -> "\\u0015"
+      '\SYN' -> "\\u0016"
+      '\ETB' -> "\\u0017"
+      '\CAN' -> "\\u0018"
+      '\EM'  -> "\\u0019"
+      '\SUB' -> "\\u001a"
+      '\ESC' -> "\\u001b"
+      '\FS'  -> "\\u001c"
+      '\GS'  -> "\\u001d"
+      '\RS'  -> "\\u001e"
+      '\US'  -> "\\u001f"
+      '\DEL' -> "\\u007f"
+      _ -> LBS.singleton w)
+
+lexeme :: Parser a -> Parser a
+lexeme = (<* skipSpace)
+
+notChar8 :: Char -> Parser Word8
+notChar8 c = P.satisfy (/= c2w c)
+
+between :: Char -> Char -> Parser a -> Parser a
+between a b p = lexeme (PC.char8 a) *> lexeme p <* lexeme (PC.char8 b)
+
+getTypeName :: ThriftType -> Builder
+getTypeName ty = B.string8 $ case ty of
+  T_STRUCT _ -> "rec"
+  T_MAP _ _  -> "map"
+  T_LIST _   -> "lst"
+  T_SET _    -> "set"
+  T_BOOL     -> "tf"
+  T_BYTE     -> "i8"
+  T_I16      -> "i16"
+  T_I32      -> "i32"
+  T_I64      -> "i64"
+  T_DOUBLE   -> "dbl"
+  T_STRING   -> "str"
+  T_BINARY   -> "str"
+  _ -> error "Unrecognized Type"
+
diff --git a/lib/hs/src/Thrift/Server.hs b/lib/hs/src/Thrift/Server.hs
index ed74ceb..543f338 100644
--- a/lib/hs/src/Thrift/Server.hs
+++ b/lib/hs/src/Thrift/Server.hs
@@ -38,10 +38,10 @@
 
 -- | A threaded sever that is capable of using any Transport or Protocol
 -- instances.
-runThreadedServer :: (Transport t, Protocol i, Protocol o)
-                  => (Socket -> IO (i t, o t))
+runThreadedServer :: (Protocol i, Protocol o)
+                  => (Socket -> IO (i, o))
                   -> h
-                  -> (h -> (i t, o t) -> IO Bool)
+                  -> (h -> (i, o) -> IO Bool)
                   -> PortID
                   -> IO a
 runThreadedServer accepter hand proc_ port = do
diff --git a/lib/hs/src/Thrift/Transport.hs b/lib/hs/src/Thrift/Transport.hs
index 3e5f18b..306edc2 100644
--- a/lib/hs/src/Thrift/Transport.hs
+++ b/lib/hs/src/Thrift/Transport.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 --
 -- Licensed to the Apache Software Foundation (ASF) under one
 -- or more contributor license agreements. See the NOTICE file
@@ -26,8 +27,9 @@
 
 import Control.Monad ( when )
 import Control.Exception ( Exception, throw )
-
+import Data.Functor ( (<$>) )
 import Data.Typeable ( Typeable )
+import Data.Word
 
 import qualified Data.ByteString.Lazy as LBS
 import Data.Monoid
@@ -36,6 +38,7 @@
     tIsOpen :: a -> IO Bool
     tClose  :: a -> IO ()
     tRead   :: a -> Int -> IO LBS.ByteString
+    tPeek   :: a -> IO (Maybe Word8)
     tWrite  :: a -> LBS.ByteString -> IO ()
     tFlush  :: a -> IO ()
     tReadAll :: a -> Int -> IO LBS.ByteString
@@ -46,8 +49,8 @@
         let rlen = fromIntegral $ LBS.length result
         when (rlen == 0) (throw $ TransportExn "Cannot read. Remote side has closed." TE_UNKNOWN)
         if len <= rlen
-            then return result
-            else (result `mappend`) `fmap` (tReadAll a (len - rlen))
+          then return result
+          else (result `mappend`) <$> tReadAll a (len - rlen)
 
 data TransportExn = TransportExn String TransportExnType
   deriving ( Show, Typeable )
@@ -60,4 +63,3 @@
     | TE_TIMED_OUT
     | TE_END_OF_FILE
       deriving ( Eq, Show, Typeable )
-
diff --git a/lib/hs/src/Thrift/Transport/Empty.hs b/lib/hs/src/Thrift/Transport/Empty.hs
new file mode 100644
index 0000000..47af5fe
--- /dev/null
+++ b/lib/hs/src/Thrift/Transport/Empty.hs
@@ -0,0 +1,36 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings #-}
+--
+-- 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.
+--
+
+module Thrift.Transport.Empty
+       ( EmptyTransport(..)
+       ) where
+
+import Thrift.Transport
+
+data EmptyTransport = EmptyTransport
+
+instance Transport EmptyTransport where
+    tIsOpen = const $ return False
+    tClose  = const $ return ()
+    tRead _ _ = return ""
+    tPeek = const $ return Nothing
+    tWrite _ _ = return ()
+    tFlush = const$ return ()
diff --git a/lib/hs/src/Thrift/Transport/Framed.hs b/lib/hs/src/Thrift/Transport/Framed.hs
index d4feac0..42fc43f 100644
--- a/lib/hs/src/Thrift/Transport/Framed.hs
+++ b/lib/hs/src/Thrift/Transport/Framed.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 --
 -- Licensed to the Apache Software Foundation (ASF) under one
 -- or more contributor license agreements. See the NOTICE file
@@ -25,13 +26,10 @@
     ) where
 
 import Thrift.Transport
+import Thrift.Transport.IOBuffer
 
-import Control.Monad (liftM)
 import Data.Int (Int32)
-import Data.Monoid (mappend, mempty)
-import Control.Concurrent.MVar
 import qualified Data.Binary as B
-import qualified Data.Binary.Builder as BB
 import qualified Data.ByteString.Lazy as LBS
 
 
@@ -65,8 +63,17 @@
                  then tRead trans n
                  else return bs
          else return bs
+    tPeek trans = do
+      mw <- peekBuf (readBuffer trans)
+      case mw of
+        Just _ -> return mw
+        Nothing -> do
+          len <- readFrame trans
+          if len > 0
+             then tPeek trans
+             else return Nothing
 
-    tWrite trans = writeBuf (writeBuffer trans)
+    tWrite = writeBuf . writeBuffer
 
     tFlush trans = do
       bs <- flushBuf (writeBuffer trans)
@@ -84,37 +91,9 @@
   let sz = fromIntegral (B.decode szBs :: Int32)
 
   -- Read the frame and stuff it into the read buffer.
-  bs   <- tRead (wrappedTrans trans) sz
+  bs <- tRead (wrappedTrans trans) sz
   fillBuf (readBuffer trans) bs
 
   -- Return the frame size so that the caller knows whether to expect
   -- something in the read buffer or not.
   return sz
-
-
--- Mini IO buffers (stolen from HttpClient.hs)
-
-type WriteBuffer = MVar (BB.Builder)
-
-newWriteBuffer :: IO WriteBuffer
-newWriteBuffer = newMVar mempty
-
-writeBuf :: WriteBuffer -> LBS.ByteString -> IO ()
-writeBuf w s = modifyMVar_ w $ return . (\builder ->
-                 builder `mappend` (BB.fromLazyByteString s))
-
-flushBuf :: WriteBuffer -> IO (LBS.ByteString)
-flushBuf w = BB.toLazyByteString `liftM` swapMVar w mempty
-
-
-type ReadBuffer = MVar (LBS.ByteString)
-
-newReadBuffer :: IO ReadBuffer
-newReadBuffer = newMVar mempty
-
-fillBuf :: ReadBuffer -> LBS.ByteString -> IO ()
-fillBuf r s = swapMVar r s >> return ()
-
-readBuf :: ReadBuffer -> Int -> IO (LBS.ByteString)
-readBuf r n = modifyMVar r $ return . flipPair . LBS.splitAt (fromIntegral n)
-    where flipPair (a, b) = (b, a)
diff --git a/lib/hs/src/Thrift/Transport/Handle.hs b/lib/hs/src/Thrift/Transport/Handle.hs
index cf4822b..ff6295b 100644
--- a/lib/hs/src/Thrift/Transport/Handle.hs
+++ b/lib/hs/src/Thrift/Transport/Handle.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeSynonymInstances #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
@@ -27,10 +27,9 @@
     , HandleSource(..)
     ) where
 
-import Prelude hiding ( catch )
-
 import Control.Exception ( catch, throw )
-import Control.Monad ()
+import Data.ByteString.Internal (c2w)
+import Data.Functor
 
 import Network
 
@@ -44,9 +43,16 @@
 
 instance Transport Handle where
     tIsOpen = hIsOpen
-    tClose h    = hClose h
-    tRead  h n  = LBS.hGet h n `catch` handleEOF
-    tWrite h s  = LBS.hPut h s
+    tClose = hClose
+    tRead h n = read `Control.Exception.catch` handleEOF mempty
+      where
+        read = do
+          hLookAhead h
+          LBS.hGetNonBlocking h n
+    tReadAll _ 0 = return mempty
+    tReadAll h n = LBS.hGet h n `Control.Exception.catch` throwTransportExn
+    tPeek h = (Just . c2w <$> hLookAhead h) `Control.Exception.catch` handleEOF Nothing
+    tWrite = LBS.hPut
     tFlush = hFlush
 
 
@@ -61,8 +67,12 @@
 instance HandleSource (HostName, PortID) where
     hOpen = uncurry connectTo
 
+throwTransportExn :: IOError -> IO a
+throwTransportExn e = if isEOFError e
+    then throw $ TransportExn "Cannot read. Remote side has closed." TE_UNKNOWN
+    else throw $ TransportExn "Handle tReadAll: Could not read" TE_UNKNOWN
 
-handleEOF :: forall a (m :: * -> *).(Monoid a, Monad m) => IOError -> m a
-handleEOF e = if isEOFError e
-    then return mempty
-    else throw $ TransportExn "TChannelTransport: Could not read" TE_UNKNOWN
+handleEOF :: a -> IOError -> IO a
+handleEOF a e = if isEOFError e
+    then return a
+    else throw $ TransportExn "Handle: Could not read" TE_UNKNOWN
diff --git a/lib/hs/src/Thrift/Transport/Header.hs b/lib/hs/src/Thrift/Transport/Header.hs
new file mode 100644
index 0000000..2dacad2
--- /dev/null
+++ b/lib/hs/src/Thrift/Transport/Header.hs
@@ -0,0 +1,354 @@
+--
+-- 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.
+--
+
+module Thrift.Transport.Header
+  ( module Thrift.Transport
+  , HeaderTransport(..)
+  , openHeaderTransport
+  , ProtocolType(..)
+  , TransformType(..)
+  , ClientType(..)
+  , tResetProtocol
+  , tSetProtocol
+  ) where
+
+import Thrift.Transport
+import Thrift.Protocol.Compact
+import Control.Applicative
+import Control.Exception ( throw )
+import Control.Monad
+import Data.Bits
+import Data.IORef
+import Data.Int
+import Data.Monoid
+import Data.Word
+
+import qualified Data.Attoparsec.ByteString as P
+import qualified Data.Binary as Binary
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Char8 as C
+import qualified Data.ByteString.Lazy as LBS
+import qualified Data.ByteString.Lazy.Builder as B
+import qualified Data.Map as Map
+
+data ProtocolType = TBinary | TCompact | TJSON deriving (Enum, Eq)
+data ClientType = HeaderClient | Framed | Unframed deriving (Enum, Eq)
+
+infoIdKeyValue = 1
+
+type Headers = Map.Map String String
+
+data TransformType = ZlibTransform deriving (Enum, Eq)
+
+fromTransportType :: TransformType -> Int16
+fromTransportType ZlibTransform = 1
+
+toTransportType :: Int16 -> TransformType
+toTransportType 1 = ZlibTransform
+toTransportType _ =  throw $ TransportExn "HeaderTransport: Unknown transform ID" TE_UNKNOWN
+
+data HeaderTransport i o = (Transport i, Transport o) => HeaderTransport
+    { readBuffer :: IORef LBS.ByteString
+    , writeBuffer :: IORef B.Builder
+    , inTrans :: i
+    , outTrans :: o
+    , clientType :: IORef ClientType
+    , protocolType :: IORef ProtocolType
+    , headers :: IORef [(String, String)]
+    , writeHeaders :: Headers
+    , transforms :: IORef [TransformType]
+    , writeTransforms :: [TransformType]
+    }
+
+openHeaderTransport :: (Transport i, Transport o) => i -> o -> IO (HeaderTransport i o)
+openHeaderTransport i o = do
+  pid <- newIORef TCompact
+  rBuf <- newIORef LBS.empty
+  wBuf <- newIORef mempty
+  cType <- newIORef HeaderClient
+  h <- newIORef []
+  trans <- newIORef []
+  return HeaderTransport
+      { readBuffer = rBuf
+      , writeBuffer = wBuf
+      , inTrans = i
+      , outTrans = o
+      , clientType = cType
+      , protocolType = pid
+      , headers = h
+      , writeHeaders = Map.empty
+      , transforms = trans
+      , writeTransforms = []
+      }
+
+isFramed t = (/= Unframed) <$> readIORef (clientType t)
+
+readFrame :: (Transport i, Transport o) => HeaderTransport i o -> IO Bool
+readFrame t = do
+  let input = inTrans t
+  let rBuf = readBuffer t
+  let cType = clientType t
+  lsz <- tRead input 4
+  let sz = LBS.toStrict lsz
+  case P.parseOnly P.endOfInput sz of
+    Right _ -> do return False
+    Left _ -> do
+      case parseBinaryMagic sz of
+        Right _ -> do
+          writeIORef rBuf $ lsz
+          writeIORef cType Unframed
+          writeIORef (protocolType t) TBinary
+          return True
+        Left _ -> do
+          case parseCompactMagic sz of
+            Right _ -> do
+              writeIORef rBuf $ lsz
+              writeIORef cType Unframed
+              writeIORef (protocolType t) TCompact
+              return True
+            Left _ -> do
+              let len = Binary.decode lsz :: Int32
+              lbuf <- tReadAll input $ fromIntegral len
+              let buf = LBS.toStrict lbuf
+              case parseBinaryMagic buf of
+                Right _ -> do
+                  writeIORef cType Framed
+                  writeIORef (protocolType t) TBinary
+                  writeIORef rBuf lbuf
+                  return True
+                Left _ -> do
+                  case parseCompactMagic buf of
+                    Right _ -> do
+                      writeIORef cType Framed
+                      writeIORef (protocolType t) TCompact
+                      writeIORef rBuf lbuf
+                      return True
+                    Left _ -> do
+                      case parseHeaderMagic buf of
+                        Right flags -> do
+                          let (flags, seqNum, header, body) = extractHeader buf
+                          writeIORef cType HeaderClient
+                          handleHeader t header
+                          payload <- untransform t body
+                          writeIORef rBuf $ LBS.fromStrict $ payload
+                          return True
+                        Left _ ->
+                          throw $ TransportExn "HeaderTransport: unkonwn client type" TE_UNKNOWN
+
+parseBinaryMagic = P.parseOnly $ P.word8 0x80 *> P.word8 0x01 *> P.word8 0x00 *> P.anyWord8
+parseCompactMagic = P.parseOnly $ P.word8 0x82 *> P.satisfy (\b -> b .&. 0x1f == 0x01)
+parseHeaderMagic = P.parseOnly $ P.word8 0x0f *> P.word8 0xff *> (P.count 2 P.anyWord8)
+
+parseI32 :: P.Parser Int32
+parseI32 = Binary.decode . LBS.fromStrict <$> P.take 4
+parseI16 :: P.Parser Int16
+parseI16 = Binary.decode . LBS.fromStrict <$> P.take 2
+
+extractHeader :: BS.ByteString -> (Int16, Int32, BS.ByteString, BS.ByteString)
+extractHeader bs =
+  case P.parse extractHeader_ bs of
+    P.Done remain (flags, seqNum, header) -> (flags, seqNum, header, remain)
+    _ -> throw $ TransportExn "HeaderTransport: Invalid header" TE_UNKNOWN
+  where
+    extractHeader_ = do
+      magic <- P.word8 0x0f *> P.word8 0xff
+      flags <- parseI16
+      seqNum <- parseI32
+      (headerSize :: Int) <- (* 4) . fromIntegral <$> parseI16
+      header <- P.take headerSize
+      return (flags, seqNum, header)
+
+handleHeader t header =
+  case P.parseOnly parseHeader header of
+    Right (pType, trans, info) -> do
+      writeIORef (protocolType t) pType
+      writeIORef (transforms t) trans
+      writeIORef (headers t) info
+    _ -> throw $ TransportExn "HeaderTransport: Invalid header" TE_UNKNOWN
+
+
+iw16 :: Int16 -> Word16
+iw16 = fromIntegral
+iw32 :: Int32 -> Word32
+iw32 = fromIntegral
+wi16 :: Word16 -> Int16
+wi16 = fromIntegral
+wi32 :: Word32 -> Int32
+wi32 = fromIntegral
+
+parseHeader :: P.Parser (ProtocolType, [TransformType], [(String, String)])
+parseHeader = do
+  protocolType <- toProtocolType <$> parseVarint wi16
+  numTrans <- fromIntegral <$> parseVarint wi16
+  trans <- replicateM numTrans parseTransform
+  info <- parseInfo
+  return (protocolType, trans, info)
+
+toProtocolType :: Int16 -> ProtocolType
+toProtocolType 0 = TBinary
+toProtocolType 1 = TJSON
+toProtocolType 2 = TCompact
+
+fromProtocolType :: ProtocolType -> Int16
+fromProtocolType TBinary = 0
+fromProtocolType TJSON = 1
+fromProtocolType TCompact = 2
+
+parseTransform :: P.Parser TransformType
+parseTransform = toTransportType <$> parseVarint wi16
+
+parseInfo :: P.Parser [(String, String)]
+parseInfo = do
+  n <- P.eitherP P.endOfInput (parseVarint wi32)
+  case n of
+    Left _ -> return []
+    Right n0 ->
+      replicateM (fromIntegral n0) $ do
+        klen <- parseVarint wi16
+        k <- P.take $ fromIntegral klen
+        vlen <- parseVarint wi16
+        v <- P.take $ fromIntegral vlen
+        return (C.unpack k, C.unpack v)
+
+parseString :: P.Parser BS.ByteString
+parseString = parseVarint wi32 >>= (P.take . fromIntegral)
+
+buildHeader :: HeaderTransport i o -> IO B.Builder
+buildHeader t = do
+  pType <- readIORef $ protocolType t
+  let pId = buildVarint $ iw16 $ fromProtocolType pType
+  let headerContent = pId <> (buildTransforms t) <> (buildInfo t)
+  let len = fromIntegral $ LBS.length $ B.toLazyByteString headerContent
+  -- TODO: length limit check
+  let padding = mconcat $ replicate (mod len 4) $ B.word8 0
+  let codedLen = B.int16BE (fromIntegral $ (quot (len - 1) 4) + 1)
+  let flags = 0
+  let seqNum = 0
+  return $ B.int16BE 0x0fff <> B.int16BE flags <> B.int32BE seqNum <> codedLen <> headerContent <> padding
+
+buildTransforms :: HeaderTransport i o -> B.Builder
+-- TODO: check length limit
+buildTransforms t =
+  let trans = writeTransforms t in
+  (buildVarint $ iw16 $ fromIntegral $ length trans) <>
+  (mconcat $ map (buildVarint . iw16 . fromTransportType) trans)
+
+buildInfo :: HeaderTransport i o -> B.Builder
+buildInfo t =
+  let h = Map.assocs $ writeHeaders t in
+  -- TODO: check length limit
+  case length h of
+    0 -> mempty
+    len -> (buildVarint $ iw16 $ fromIntegral $ len) <> (mconcat $ map buildInfoEntry h)
+  where
+    buildInfoEntry (k, v) = buildVarStr k <> buildVarStr v
+    -- TODO: check length limit
+    buildVarStr s = (buildVarint $ iw16 $ fromIntegral $ length s) <> B.string8 s
+
+tResetProtocol :: (Transport i, Transport o) => HeaderTransport i o -> IO Bool
+tResetProtocol t = do
+  rBuf <- readIORef $ readBuffer t
+  writeIORef (clientType t) HeaderClient
+  readFrame t
+
+tSetProtocol :: (Transport i, Transport o) => HeaderTransport i o -> ProtocolType -> IO ()
+tSetProtocol t = writeIORef (protocolType t)
+
+transform :: HeaderTransport i o -> LBS.ByteString -> LBS.ByteString
+transform t bs =
+  foldr applyTransform bs $ writeTransforms t
+  where
+    -- applyTransform bs ZlibTransform =
+    --   throw $ TransportExn "HeaderTransport: not implemented: ZlibTransform  " TE_UNKNOWN
+    applyTransform bs _ =
+      throw $ TransportExn "HeaderTransport: Unknown transform" TE_UNKNOWN
+
+untransform :: HeaderTransport i o -> BS.ByteString -> IO BS.ByteString
+untransform t bs = do
+  trans <- readIORef $ transforms t
+  return $ foldl unapplyTransform bs trans
+  where
+    -- unapplyTransform bs ZlibTransform =
+    --   throw $ TransportExn "HeaderTransport: not implemented: ZlibTransform  " TE_UNKNOWN
+    unapplyTransform bs _ =
+      throw $ TransportExn "HeaderTransport: Unknown transform" TE_UNKNOWN
+
+instance (Transport i, Transport o) => Transport (HeaderTransport i o) where
+  tIsOpen t = do
+    tIsOpen (inTrans t)
+    tIsOpen (outTrans t)
+
+  tClose t = do
+    tClose(outTrans t)
+    tClose(inTrans t)
+
+  tRead t len = do
+    rBuf <- readIORef $ readBuffer t
+    if not $ LBS.null rBuf
+      then do
+        let (consumed, remain) = LBS.splitAt (fromIntegral len) rBuf
+        writeIORef (readBuffer t) remain
+        return consumed
+      else do
+        framed <- isFramed t
+        if not framed
+          then tRead (inTrans t) len
+          else do
+            ok <- readFrame t
+            if ok
+              then tRead t len
+              else return LBS.empty
+
+  tPeek t = do
+    rBuf <- readIORef (readBuffer t)
+    if not $ LBS.null rBuf
+      then return $ Just $ LBS.head rBuf
+      else do
+        framed <- isFramed t
+        if not framed
+          then tPeek (inTrans t)
+          else do
+            ok <- readFrame t
+            if ok
+              then tPeek t
+              else return Nothing
+
+  tWrite t buf = do
+    let wBuf = writeBuffer t
+    framed <- isFramed t
+    if framed
+      then modifyIORef wBuf (<> B.lazyByteString buf)
+      else
+        -- TODO: what should we do when switched to unframed in the middle ?
+        tWrite(outTrans t) buf
+
+  tFlush t = do
+    cType <- readIORef $ clientType t
+    case cType of
+      Unframed -> tFlush $ outTrans t
+      Framed -> flushBuffer t id mempty
+      HeaderClient -> buildHeader t >>= flushBuffer t (transform t)
+    where
+      flushBuffer t f header = do
+        wBuf <- readIORef $ writeBuffer t
+        writeIORef (writeBuffer t) mempty
+        let payload = B.toLazyByteString (header <> wBuf)
+        tWrite (outTrans t) $ Binary.encode (fromIntegral $ LBS.length payload :: Int32)
+        tWrite (outTrans t) $ f payload
+        tFlush (outTrans t)
diff --git a/lib/hs/src/Thrift/Transport/HttpClient.hs b/lib/hs/src/Thrift/Transport/HttpClient.hs
index b1b0982..edeb320 100644
--- a/lib/hs/src/Thrift/Transport/HttpClient.hs
+++ b/lib/hs/src/Thrift/Transport/HttpClient.hs
@@ -22,18 +22,16 @@
     ( module Thrift.Transport
     , HttpClient (..)
     , openHttpClient
-    ) where
+) where
 
 import Thrift.Transport
+import Thrift.Transport.IOBuffer
 import Network.URI
 import Network.HTTP hiding (port, host)
 
-import Control.Monad (liftM)
 import Data.Maybe (fromJust)
-import Data.Monoid (mappend, mempty)
+import Data.Monoid (mempty)
 import Control.Exception (throw)
-import Control.Concurrent.MVar
-import qualified Data.Binary.Builder as B
 import qualified Data.ByteString.Lazy as LBS
 
 
@@ -73,11 +71,13 @@
 
 instance Transport HttpClient where
 
-    tClose  = close . hstream
+    tClose = close . hstream
 
-    tRead hclient n = readBuf (readBuffer hclient) n
+    tPeek = peekBuf . readBuffer
 
-    tWrite hclient = writeBuf (writeBuffer hclient)
+    tRead = readBuf . readBuffer
+
+    tWrite = writeBuf . writeBuffer
 
     tFlush hclient = do
       body <- flushBuf $ writeBuffer hclient
@@ -92,36 +92,10 @@
 
       res <- sendHTTP (hstream hclient) request
       case res of
-        Right response -> do
-            fillBuf (readBuffer hclient) (rspBody response)
-        Left _ -> do
+        Right response ->
+          fillBuf (readBuffer hclient) (rspBody response)
+        Left _ ->
             throw $ TransportExn "THttpConnection: HTTP failure from server" TE_UNKNOWN
       return ()
 
     tIsOpen _ = return True
--- Mini IO buffers
-
-type WriteBuffer = MVar (B.Builder)
-
-newWriteBuffer :: IO WriteBuffer
-newWriteBuffer = newMVar mempty
-
-writeBuf :: WriteBuffer -> LBS.ByteString -> IO ()
-writeBuf w s = modifyMVar_ w $ return . (\builder ->
-                 builder `mappend` (B.fromLazyByteString s))
-
-flushBuf :: WriteBuffer -> IO (LBS.ByteString)
-flushBuf w = B.toLazyByteString `liftM` swapMVar w mempty
-
-
-type ReadBuffer = MVar (LBS.ByteString)
-
-newReadBuffer :: IO ReadBuffer
-newReadBuffer = newMVar mempty
-
-fillBuf :: ReadBuffer -> LBS.ByteString -> IO ()
-fillBuf r s = swapMVar r s >> return ()
-
-readBuf :: ReadBuffer -> Int -> IO (LBS.ByteString)
-readBuf r n = modifyMVar r $ return . flipPair . LBS.splitAt (fromIntegral n)
-    where flipPair (a, b) = (b, a)
diff --git a/lib/hs/src/Thrift/Transport/IOBuffer.hs b/lib/hs/src/Thrift/Transport/IOBuffer.hs
new file mode 100644
index 0000000..7ebd7d8
--- /dev/null
+++ b/lib/hs/src/Thrift/Transport/IOBuffer.hs
@@ -0,0 +1,69 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+module Thrift.Transport.IOBuffer
+       ( WriteBuffer
+       , newWriteBuffer
+       , writeBuf
+       , flushBuf
+       , ReadBuffer
+       , newReadBuffer
+       , fillBuf
+       , readBuf
+       , peekBuf
+       ) where
+
+import Data.ByteString.Lazy.Builder
+import Data.Functor
+import Data.IORef
+import Data.Monoid
+import Data.Word
+
+import qualified Data.ByteString.Lazy as LBS
+
+type WriteBuffer = IORef Builder
+type ReadBuffer = IORef LBS.ByteString
+
+newWriteBuffer :: IO WriteBuffer
+newWriteBuffer = newIORef mempty
+
+writeBuf :: WriteBuffer -> LBS.ByteString -> IO ()
+writeBuf w s = modifyIORef w ( <> lazyByteString s)
+
+flushBuf :: WriteBuffer -> IO LBS.ByteString
+flushBuf w = do
+  buf <- readIORef w
+  writeIORef w mempty
+  return $ toLazyByteString buf
+
+newReadBuffer :: IO ReadBuffer
+newReadBuffer = newIORef mempty
+
+fillBuf :: ReadBuffer -> LBS.ByteString -> IO ()
+fillBuf = writeIORef
+
+readBuf :: ReadBuffer -> Int -> IO LBS.ByteString
+readBuf r n = do
+  bs <- readIORef r
+  let (hd, tl) = LBS.splitAt (fromIntegral n) bs
+  writeIORef r tl
+  return hd
+
+peekBuf :: ReadBuffer -> IO (Maybe Word8)
+peekBuf r = (fmap fst . LBS.uncons) <$> readIORef r
diff --git a/lib/hs/src/Thrift/Transport/Memory.hs b/lib/hs/src/Thrift/Transport/Memory.hs
new file mode 100644
index 0000000..1c93af6
--- /dev/null
+++ b/lib/hs/src/Thrift/Transport/Memory.hs
@@ -0,0 +1,77 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+module Thrift.Transport.Memory
+       ( openMemoryBuffer
+       , MemoryBuffer(..)
+       ) where
+
+import Data.ByteString.Lazy.Builder
+import Data.Functor
+import Data.IORef
+import Data.Monoid
+import qualified Data.ByteString.Lazy as LBS
+
+import Thrift.Transport
+
+
+data MemoryBuffer = MemoryBuffer {
+  writeBuffer :: IORef Builder,
+  readBuffer :: IORef LBS.ByteString
+}
+
+openMemoryBuffer :: IO MemoryBuffer
+openMemoryBuffer = do
+  wbuf <- newIORef mempty
+  rbuf <- newIORef mempty
+  return MemoryBuffer {
+    writeBuffer = wbuf,
+    readBuffer = rbuf
+  }
+
+instance Transport MemoryBuffer where
+  tIsOpen = const $ return False
+  tClose  = const $ return ()
+  tFlush trans = do
+    let wBuf = writeBuffer trans
+    wb <- readIORef wBuf
+    modifyIORef (readBuffer trans) $ \rb -> mappend rb $ toLazyByteString wb
+    writeIORef wBuf mempty
+
+  tRead _ 0 = return mempty
+  tRead trans n = do
+    let rbuf = readBuffer trans
+    rb <- readIORef rbuf
+    let len = fromIntegral $ LBS.length rb
+    if len == 0
+      then do
+        tFlush trans
+        rb2 <- readIORef (readBuffer trans)
+        if (fromIntegral $ LBS.length rb2) == 0
+          then return mempty
+          else tRead trans n
+      else do
+        let (ret, remain) = LBS.splitAt (fromIntegral n) rb
+        writeIORef rbuf remain
+        return ret
+
+  tPeek trans = (fmap fst . LBS.uncons) <$> readIORef (readBuffer trans)
+
+  tWrite trans v = do
+    modifyIORef (writeBuffer trans) (<> lazyByteString v)
diff --git a/lib/hs/src/Thrift/Types.hs b/lib/hs/src/Thrift/Types.hs
index e917e39..2a20025 100644
--- a/lib/hs/src/Thrift/Types.hs
+++ b/lib/hs/src/Thrift/Types.hs
@@ -16,19 +16,115 @@
 -- under the License.
 --
 
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
 module Thrift.Types where
 
 import Data.Foldable (foldl')
 import Data.Hashable ( Hashable, hashWithSalt )
+import Data.Int
+import Test.QuickCheck.Arbitrary
+import Test.QuickCheck.Gen (elements)
+import Data.Text.Lazy (Text)
+import qualified Data.ByteString.Lazy as LBS
 import qualified Data.HashMap.Strict as Map
 import qualified Data.HashSet as Set
 import qualified Data.Vector as Vector
 
-instance (Hashable k, Hashable v) => Hashable (Map.HashMap k v) where
-  hashWithSalt salt = foldl' hashWithSalt salt . Map.toList
-
-instance (Hashable a) => Hashable (Set.HashSet a) where
-  hashWithSalt salt = foldl' hashWithSalt salt
-
 instance (Hashable a) => Hashable (Vector.Vector a) where
-  hashWithSalt salt = Vector.foldl' hashWithSalt salt
+  hashWithSalt = Vector.foldl' hashWithSalt
+
+
+type TypeMap = Map.HashMap Int16 (Text, ThriftType)
+
+data ThriftVal = TStruct (Map.HashMap Int16 (Text, ThriftVal))
+               | TMap ThriftType ThriftType [(ThriftVal, ThriftVal)]
+               | TList ThriftType [ThriftVal]
+               | TSet ThriftType [ThriftVal]
+               | TBool Bool
+               | TByte Int8
+               | TI16 Int16
+               | TI32 Int32
+               | TI64 Int64
+               | TString LBS.ByteString
+               | TBinary LBS.ByteString
+               | TDouble Double
+                 deriving (Eq, Show)
+
+-- Information is needed here for collection types (ie T_STRUCT, T_MAP,
+-- T_LIST, and T_SET) so that we know what types those collections are
+-- parameterized by.  In most protocols, this cannot be discerned directly
+-- from the data being read.
+data ThriftType
+    = T_STOP
+    | T_VOID
+    | T_BOOL
+    | T_BYTE
+    | T_DOUBLE
+    | T_I16
+    | T_I32
+    | T_I64
+    | T_STRING
+    | T_BINARY
+    | T_STRUCT TypeMap
+    | T_MAP ThriftType ThriftType
+    | T_SET ThriftType
+    | T_LIST ThriftType
+      deriving ( Eq, Show )
+
+-- NOTE: when using toEnum information about parametized types is NOT preserved.
+-- This design choice is consistent woth the Thrift implementation in other
+-- languages
+instance Enum ThriftType where
+    fromEnum T_STOP       = 0
+    fromEnum T_VOID       = 1
+    fromEnum T_BOOL       = 2
+    fromEnum T_BYTE       = 3
+    fromEnum T_DOUBLE     = 4
+    fromEnum T_I16        = 6
+    fromEnum T_I32        = 8
+    fromEnum T_I64        = 10
+    fromEnum T_STRING     = 11
+    fromEnum T_BINARY     = 11
+    fromEnum (T_STRUCT _) = 12
+    fromEnum (T_MAP _ _)  = 13
+    fromEnum (T_SET _)    = 14
+    fromEnum (T_LIST _)   = 15
+
+    toEnum 0  = T_STOP
+    toEnum 1  = T_VOID
+    toEnum 2  = T_BOOL
+    toEnum 3  = T_BYTE
+    toEnum 4  = T_DOUBLE
+    toEnum 6  = T_I16
+    toEnum 8  = T_I32
+    toEnum 10 = T_I64
+    toEnum 11 = T_STRING
+    -- toEnum 11 = T_BINARY
+    toEnum 12 = T_STRUCT Map.empty
+    toEnum 13 = T_MAP T_VOID T_VOID
+    toEnum 14 = T_SET T_VOID
+    toEnum 15 = T_LIST T_VOID
+    toEnum t = error $ "Invalid ThriftType " ++ show t
+
+data MessageType
+    = M_CALL
+    | M_REPLY
+    | M_EXCEPTION
+    | M_ONEWAY
+      deriving ( Eq, Show )
+
+instance Enum MessageType where
+    fromEnum M_CALL      =  1
+    fromEnum M_REPLY     =  2
+    fromEnum M_EXCEPTION =  3
+    fromEnum M_ONEWAY    =  4
+
+    toEnum 1 = M_CALL
+    toEnum 2 = M_REPLY
+    toEnum 3 = M_EXCEPTION
+    toEnum 4 = M_ONEWAY
+    toEnum t = error $ "Invalid MessageType " ++ show t
+
+instance Arbitrary MessageType where
+  arbitrary = elements [M_CALL, M_REPLY, M_EXCEPTION, M_ONEWAY]
diff --git a/lib/hs/test/BinarySpec.hs b/lib/hs/test/BinarySpec.hs
new file mode 100644
index 0000000..d692fab
--- /dev/null
+++ b/lib/hs/test/BinarySpec.hs
@@ -0,0 +1,91 @@
+--
+-- 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.
+--
+
+module BinarySpec where
+
+import Test.Hspec
+import Test.Hspec.QuickCheck (prop)
+
+import qualified Data.ByteString.Lazy as LBS
+import qualified Data.ByteString.Lazy.Char8 as C
+
+import Thrift.Types
+import Thrift.Transport
+import Thrift.Transport.Memory
+import Thrift.Protocol
+import Thrift.Protocol.Binary
+
+spec :: Spec
+spec = do
+  describe "BinaryProtocol" $ do
+    describe "double" $ do
+      it "writes in big endian order" $ do
+        let val = 2 ** 53
+        trans <- openMemoryBuffer
+        let proto = BinaryProtocol trans
+        writeVal proto (TDouble val)
+        bin <- tRead trans 8
+        (LBS.unpack bin) `shouldBe`[67, 64, 0, 0, 0, 0, 0, 0]
+
+      it "reads in big endian order" $ do
+        let bin = LBS.pack [67, 64, 0, 0, 0, 0, 0, 0]
+        trans <- openMemoryBuffer
+        let proto = BinaryProtocol trans
+        tWrite trans bin
+        val <- readVal proto T_DOUBLE
+        val `shouldBe` (TDouble $ 2 ** 53)
+
+      prop "round trip" $ \val -> do
+        trans <- openMemoryBuffer
+        let proto = BinaryProtocol trans
+        writeVal proto $ TDouble val
+        val2 <- readVal proto T_DOUBLE
+        val2 `shouldBe` (TDouble val)
+
+    describe "string" $ do
+      it "writes" $ do
+        let val = C.pack "aaa"
+        trans <- openMemoryBuffer
+        let proto = BinaryProtocol trans
+        writeVal proto (TString val)
+        bin <- tRead trans 7
+        (LBS.unpack bin) `shouldBe` [0, 0, 0, 3, 97, 97, 97]
+
+    describe "binary" $ do
+      it "writes" $ do
+        trans <- openMemoryBuffer
+        let proto = BinaryProtocol trans
+        writeVal proto (TBinary $ LBS.pack [42, 43, 44])
+        bin <- tRead trans 100
+        (LBS.unpack bin) `shouldBe` [0, 0, 0, 3, 42, 43, 44]
+
+      it "reads" $ do
+        trans <- openMemoryBuffer
+        let proto = BinaryProtocol trans
+        tWrite trans $ LBS.pack [0, 0, 0, 3, 42, 43, 44]
+        val <- readVal proto (T_BINARY)
+        val `shouldBe` (TBinary $ LBS.pack [42, 43, 44])
+
+      prop "round trip" $ \val -> do
+        trans <- openMemoryBuffer
+        let proto = BinaryProtocol trans
+        writeVal proto (TBinary $ LBS.pack val)
+        val2 <- readVal proto (T_BINARY)
+        val2 `shouldBe` (TBinary $ LBS.pack val)
+
diff --git a/lib/hs/test/CompactSpec.hs b/lib/hs/test/CompactSpec.hs
new file mode 100644
index 0000000..5540e7b
--- /dev/null
+++ b/lib/hs/test/CompactSpec.hs
@@ -0,0 +1,81 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+module CompactSpec where
+
+import Test.Hspec
+import Test.Hspec.QuickCheck (prop)
+
+import qualified Data.ByteString.Lazy as LBS
+
+import Thrift.Types
+import Thrift.Transport
+import Thrift.Transport.Memory
+import Thrift.Protocol
+import Thrift.Protocol.Compact
+
+spec :: Spec
+spec = do
+  describe "CompactProtocol" $ do
+    describe "double" $ do
+      it "writes in little endian order" $ do
+        let val = 2 ** 53
+        trans <- openMemoryBuffer
+        let proto = CompactProtocol trans
+        writeVal proto (TDouble val)
+        bin <- tReadAll trans 8
+        (LBS.unpack bin) `shouldBe`[0, 0, 0, 0, 0, 0, 64, 67]
+
+      it "reads in little endian order" $ do
+        let bin = LBS.pack [0, 0, 0, 0, 0, 0, 64, 67]
+        trans <- openMemoryBuffer
+        let proto = CompactProtocol trans
+        tWrite trans bin
+        val <- readVal proto T_DOUBLE
+        val `shouldBe` (TDouble $ 2 ** 53)
+
+      prop "round trip" $ \val -> do
+        trans <- openMemoryBuffer
+        let proto = CompactProtocol trans
+        writeVal proto $ TDouble val
+        val2 <- readVal proto T_DOUBLE
+        val2 `shouldBe` (TDouble val)
+
+    describe "binary" $ do
+      it "writes" $ do
+        trans <- openMemoryBuffer
+        let proto = CompactProtocol trans
+        writeVal proto (TBinary $ LBS.pack [42, 43, 44])
+        bin <- tRead trans 100
+        (LBS.unpack bin) `shouldBe` [3, 42, 43, 44]
+
+      it "reads" $ do
+        trans <- openMemoryBuffer
+        let proto = CompactProtocol trans
+        tWrite trans $ LBS.pack [3, 42, 43, 44]
+        val <- readVal proto (T_BINARY)
+        val `shouldBe` (TBinary $ LBS.pack [42, 43, 44])
+
+      prop "round trip" $ \val -> do
+        trans <- openMemoryBuffer
+        let proto = CompactProtocol trans
+        writeVal proto (TBinary $ LBS.pack val)
+        val2 <- readVal proto (T_BINARY)
+        val2 `shouldBe` (TBinary $ LBS.pack val)
+
diff --git a/lib/hs/test/JSONSpec.hs b/lib/hs/test/JSONSpec.hs
new file mode 100644
index 0000000..022c826
--- /dev/null
+++ b/lib/hs/test/JSONSpec.hs
@@ -0,0 +1,225 @@
+--
+-- 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.
+--
+
+module JSONSpec where
+
+import Test.Hspec
+import Test.Hspec.QuickCheck (prop)
+
+import qualified Data.ByteString.Lazy as LBS
+import qualified Data.ByteString.Lazy.Char8 as C
+
+import Thrift.Types
+import Thrift.Transport
+import Thrift.Transport.Memory
+import Thrift.Protocol
+import Thrift.Protocol.JSON
+
+tString :: [Char] -> ThriftVal
+tString = TString . C.pack
+
+spec :: Spec
+spec = do
+  describe "JSONProtocol" $ do
+    describe "bool" $ do
+      it "writes true as 1" $ do
+        let val = True
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto (TBool val)
+        bin <-tRead trans 100
+        (C.unpack bin) `shouldBe` ['1']
+
+      it "writes false as 0" $ do
+        let val = False
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto (TBool val)
+        bin <- tRead trans 100
+        (C.unpack bin) `shouldBe` ['0']
+
+      prop "round trip" $ \val -> do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto $ TBool val
+        val2 <- readVal proto T_BOOL
+        val2 `shouldBe` (TBool val)
+
+    describe "string" $ do
+      it "writes" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto (TString $ C.pack "\"a")
+        bin <- tRead trans 100
+        (C.unpack bin) `shouldBe` "\"\\\"a\""
+
+      it "reads" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        tWrite trans $ C.pack "\"\\\"a\""
+        val <- readVal proto (T_STRING)
+        val `shouldBe` (TString $ C.pack "\"a")
+
+      prop "round trip" $ \val -> do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto (TString $ C.pack val)
+        val2 <- readVal proto (T_STRING)
+        val2 `shouldBe` (TString $ C.pack val)
+
+    describe "binary" $ do
+      it "writes with padding" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto (TBinary $ LBS.pack [1])
+        bin <- tRead trans 100
+        (C.unpack bin) `shouldBe` "\"AQ==\""
+
+      it "reads with padding" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        tWrite trans $ C.pack "\"AQ==\""
+        val <- readVal proto (T_BINARY)
+        val `shouldBe` (TBinary $ LBS.pack [1])
+
+      it "reads without padding" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        tWrite trans $ C.pack "\"AQ\""
+        val <- readVal proto (T_BINARY)
+        val `shouldBe` (TBinary $ LBS.pack [1])
+
+      prop "round trip" $ \val -> do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto (TBinary $ LBS.pack val)
+        val2 <- readVal proto (T_BINARY)
+        val2 `shouldBe` (TBinary $ LBS.pack val)
+
+    describe "list" $ do
+      it "writes empty list" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto (TList T_BYTE [])
+        bin <- tRead trans 100
+        (C.unpack bin) `shouldBe` "[\"i8\",0]"
+
+      it "reads empty" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        tWrite trans (C.pack "[\"i8\",0]")
+        val <- readVal proto (T_LIST T_BYTE)
+        val `shouldBe` (TList T_BYTE [])
+
+      it "writes single element" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto (TList T_BYTE [TByte 0])
+        bin <- tRead trans 100
+        (C.unpack bin) `shouldBe` "[\"i8\",1,0]"
+
+      it "reads single element" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        tWrite trans (C.pack "[\"i8\",1,0]")
+        val <- readVal proto (T_LIST T_BYTE)
+        val `shouldBe` (TList T_BYTE [TByte 0])
+
+      it "reads elements" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        tWrite trans (C.pack "[\"i8\",2,42, 43]")
+        val <- readVal proto (T_LIST T_BYTE)
+        val `shouldBe` (TList T_BYTE [TByte 42, TByte 43])
+
+      prop "round trip" $ \val -> do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto $ (TList T_STRING $ map tString val)
+        val2 <- readVal proto $ T_LIST T_STRING
+        val2 `shouldBe` (TList T_STRING $ map tString val)
+
+    describe "set" $ do
+      it "writes empty" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto (TSet T_BYTE [])
+        bin <- tRead trans 100
+        (C.unpack bin) `shouldBe` "[\"i8\",0]"
+
+      it "reads empty" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        tWrite trans (C.pack "[\"i8\",0]")
+        val <- readVal proto (T_SET T_BYTE)
+        val `shouldBe` (TSet T_BYTE [])
+
+      it "reads single element" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        tWrite trans (C.pack "[\"i8\",1,0]")
+        val <- readVal proto (T_SET T_BYTE)
+        val `shouldBe` (TSet T_BYTE [TByte 0])
+
+      it "reads elements" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        tWrite trans (C.pack "[\"i8\",2,42, 43]")
+        val <- readVal proto (T_SET T_BYTE)
+        val `shouldBe` (TSet T_BYTE [TByte 42, TByte 43])
+
+      prop "round trip" $ \val -> do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto $ (TSet T_STRING $ map tString val)
+        val2 <- readVal proto $ T_SET T_STRING
+        val2 `shouldBe` (TSet T_STRING $ map tString val)
+
+    describe "map" $ do
+      it "writes empty" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto (TMap T_BYTE T_BYTE [])
+        bin <- tRead trans 100
+        (C.unpack bin) `shouldBe`"[\"i8\",\"i8\",0,{}]"
+
+      it "reads empty" $ do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        tWrite trans (C.pack "[\"i8\",\"i8\",0,{}]")
+        val <- readVal proto (T_MAP T_BYTE T_BYTE)
+        val `shouldBe` (TMap T_BYTE T_BYTE [])
+
+      it "reads string-string" $ do
+        let bin = "[\"str\",\"str\",2,{\"a\":\"2\",\"b\":\"blah\"}]"
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        tWrite trans (C.pack bin)
+        val <- readVal proto (T_MAP T_STRING T_STRING)
+        val`shouldBe` (TMap T_STRING T_STRING [(tString "a", tString "2"), (tString "b", tString "blah")])
+
+      prop "round trip" $ \val -> do
+        trans <- openMemoryBuffer
+        let proto = JSONProtocol trans
+        writeVal proto $ (TMap T_STRING T_STRING $ map toKV val)
+        val2 <- readVal proto $ T_MAP T_STRING T_STRING
+        val2 `shouldBe` (TMap T_STRING T_STRING $ map toKV val)
+        where
+          toKV v = (tString v, tString v)
+
diff --git a/lib/hs/test/Spec.hs b/lib/hs/test/Spec.hs
new file mode 100644
index 0000000..7ec9a99
--- /dev/null
+++ b/lib/hs/test/Spec.hs
@@ -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.
+--
+
+-- Our CI does not work well with auto discover.
+-- Need to add build-time PATH variable to hspec-discover dir from CMake
+-- or install hspec system-wide for the following to work.
+-- {-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+
+import Test.Hspec
+
+import qualified BinarySpec
+import qualified CompactSpec
+import qualified JSONSpec
+
+main :: IO ()
+main = hspec spec
+
+spec :: Spec
+spec = do
+  describe "Binary" BinarySpec.spec
+  describe "Compact" CompactSpec.spec
+  describe "JSON" JSONSpec.spec
diff --git a/lib/hs/thrift.cabal b/lib/hs/thrift.cabal
new file mode 100644
index 0000000..5515556
--- /dev/null
+++ b/lib/hs/thrift.cabal
@@ -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.
+--
+
+Name:           thrift
+Version:        1.0.0
+Cabal-Version:  1.24
+License:        OtherLicense
+Category:       Foreign
+Build-Type:     Simple
+Synopsis:       Haskell bindings for the Apache Thrift RPC system
+Homepage:       http://thrift.apache.org
+Bug-Reports:    https://issues.apache.org/jira/browse/THRIFT
+Maintainer:     dev@thrift.apache.org
+License-File:   LICENSE
+
+Description:
+  Haskell bindings for the Apache Thrift RPC system. Requires the use of the thrift code generator.
+
+flag network-uri
+   description: Get Network.URI from the network-uri package
+   default: True
+
+Library
+  Hs-Source-Dirs:
+    src
+  Build-Depends:
+    base >= 4, base < 5, containers, ghc-prim, attoparsec, binary, bytestring >= 0.10, base64-bytestring, hashable, HTTP, text, hspec-core > 2.4.0, unordered-containers >= 0.2.6, vector >= 0.10.12.2, QuickCheck >= 2.8.2, split
+  if flag(network-uri)
+     build-depends: network-uri >= 2.6, network >= 2.6
+  else
+     build-depends: network < 2.6
+  Exposed-Modules:
+    Thrift,
+    Thrift.Arbitraries
+    Thrift.Protocol,
+    Thrift.Protocol.Header,
+    Thrift.Protocol.Binary,
+    Thrift.Protocol.Compact,
+    Thrift.Protocol.JSON,
+    Thrift.Server,
+    Thrift.Transport,
+    Thrift.Transport.Empty,
+    Thrift.Transport.Framed,
+    Thrift.Transport.Handle,
+    Thrift.Transport.Header,
+    Thrift.Transport.HttpClient,
+    Thrift.Transport.IOBuffer,
+    Thrift.Transport.Memory,
+    Thrift.Types
+  Default-Language: Haskell2010
+  Default-Extensions:
+    DeriveDataTypeable,
+    ExistentialQuantification,
+    FlexibleInstances,
+    KindSignatures,
+    MagicHash,
+    RankNTypes,
+    RecordWildCards,
+    ScopedTypeVariables,
+    TypeSynonymInstances
+
+Test-Suite spec
+  Type: exitcode-stdio-1.0
+  Hs-Source-Dirs: test
+  Ghc-Options: -Wall
+  main-is: Spec.hs
+  Build-Depends: base, thrift, hspec, QuickCheck >= 2.8.2, bytestring >= 0.10, unordered-containers >= 0.2.6
+  Default-Language: Haskell2010
diff --git a/lib/java/CMakeLists.txt b/lib/java/CMakeLists.txt
new file mode 100644
index 0000000..46064e6
--- /dev/null
+++ b/lib/java/CMakeLists.txt
@@ -0,0 +1,87 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if(ANDROID)
+    set(THRIFT_AAR outputs/aar/thrift-debug.aar outputs/aar/thrift-release.aar)
+    add_custom_command(
+        OUTPUT ${THRIFT_AAR}
+        COMMAND ${GRADLE_EXECUTABLE}
+            -p "${CMAKE_CURRENT_SOURCE_DIR}/android"
+            "-PbuildDir=${CMAKE_CURRENT_BINARY_DIR}/android/build" assemble
+    )
+    add_custom_target(thrift_aar ALL DEPENDS ${THRIFT_AAR})
+
+else(ANDROID)
+
+    if(IS_ABSOLUTE "${LIB_INSTALL_DIR}")
+        set(JAVA_INSTALL_DIR "${LIB_INSTALL_DIR}/java")
+    else()
+        set(JAVA_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}/java")
+    endif()
+
+    if(IS_ABSOLUTE "${DOC_INSTALL_DIR}")
+        set(JAVA_DOC_INSTALL_DIR "${DOC_INSTALL_DIR}/java")
+    else()
+        set(JAVA_DOC_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${DOC_INSTALL_DIR}/java")
+    endif()
+
+    add_custom_target(ThriftJava ALL
+        COMMENT "Building Java library using Gradle Wrapper"
+        COMMAND ${GRADLEW_EXECUTABLE} ${GRADLE_OPTS} assemble
+            --console=plain --no-daemon
+            -Prelease=true
+            -Pthrift.version=${thrift_VERSION}
+            "-Pbuild.dir=${CMAKE_CURRENT_BINARY_DIR}/build"
+        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+    )
+
+    # Enable publishing from CMake if the publishing information is provided
+    add_custom_target(MavenPublish
+        COMMENT "Publishing Java Library to Apache Maven staging"
+        COMMAND ${GRADLEW_EXECUTABLE} ${GRADLE_OPTS} clean uploadArchives
+            --console=plain --no-daemon
+            -Prelease=true
+            -Pthrift.version=${thrift_VERSION}
+            "-Pbuild.dir=${CMAKE_CURRENT_BINARY_DIR}/build"
+        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+    )
+
+    # Hook the CMake install process to the results from make ALL.
+    # This works best when 'make all && sudo make install/fast' is used.
+    # Using slash to end the source location to avoid copying the directory path.
+    install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/build/libs/
+            DESTINATION ${JAVA_INSTALL_DIR}
+            FILES_MATCHING PATTERN "libthrift-${thrift_VERSION}.jar")
+    install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/build/deps/
+            DESTINATION ${JAVA_INSTALL_DIR}
+            FILES_MATCHING PATTERN "*.jar")
+    install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/build/docs/javadoc/
+            DESTINATION ${JAVA_DOC_INSTALL_DIR})
+
+    if(BUILD_TESTING)
+        add_test(NAME JavaTest
+                COMMAND ${GRADLEW_EXECUTABLE} ${GRADLE_OPTS} test
+                    --console=plain --no-daemon
+                    -Prelease=true
+                    -Pthrift.version=${thrift_VERSION}
+                    "-Pbuild.dir=${CMAKE_CURRENT_BINARY_DIR}/build"
+                    "-Pthrift.compiler=${THRIFT_COMPILER}"
+                WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+    endif()
+endif(ANDROID)
diff --git a/lib/java/Makefile.am b/lib/java/Makefile.am
index ea01978..65981ca 100644
--- a/lib/java/Makefile.am
+++ b/lib/java/Makefile.am
@@ -17,22 +17,56 @@
 # under the License.
 #
 
-EXTRA_DIST = build.xml build.properties src test
-
 export CLASSPATH
 
 all-local:
-	$(ANT) $(ANT_FLAGS)
+	./gradlew $(GRADLE_OPTS) assemble \
+		-Prelease=true \
+		-Pthrift.version=$(PACKAGE_VERSION) \
+		--console=plain
 
 install-exec-hook:
-	$(ANT) $(ANT_FLAGS) install -Dinstall.path=$(DESTDIR)$(JAVA_PREFIX) \
-		-Dinstall.javadoc.path=$(DESTDIR)$(docdir)/java
+	./gradlew $(GRADLE_OPTS) install \
+		-Prelease=true \
+		-Pinstall.path=$(DESTDIR)$(JAVA_PREFIX) \
+		-Pinstall.javadoc.path=$(DESTDIR)$(docdir)/java \
+		-Pthrift.version=$(PACKAGE_VERSION) \
+		--console=plain
 
-# Make sure this doesn't fail if ant is not configured.
 clean-local:
-	ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \
-	$$ANT $(ANT_FLAGS) clean
+	./gradlew $(GRADLE_OPTS) clean --console=plain
 
-check-local: all
-	$(ANT) $(ANT_FLAGS) test
+precross: $(THRIFT)
+	./gradlew $(GRADLE_OPTS) shadowJar \
+		-Prelease=true \
+		-Pthrift.version=$(PACKAGE_VERSION) \
+		-Pthrift.compiler=$(THRIFT) \
+		--console=plain
 
+check-local: $(THRIFT)
+	./gradlew $(GRADLE_OPTS) test \
+		-Prelease=true \
+		-Pthrift.version=$(PACKAGE_VERSION) \
+		-Pthrift.compiler=$(THRIFT) \
+		--console=plain
+
+maven-publish:
+	./gradlew $(GRADLE_OPTS) uploadArchives \
+		-Prelease=true \
+		-Pthrift.version=$(PACKAGE_VERSION) \
+		--console=plain
+
+EXTRA_DIST = \
+	build.gradle \
+	gradle.properties \
+	settings.gradle \
+	gradle \
+	gradlew \
+	gradlew.bat \
+	CMakeLists.txt \
+	coding_standards.md \
+	android \
+	src \
+	test \
+	code_quality_tools \
+	README.md
diff --git a/lib/java/README b/lib/java/README
deleted file mode 100644
index 12b3afe..0000000
--- a/lib/java/README
+++ /dev/null
@@ -1,53 +0,0 @@
-Thrift Java Software Library
-
-License
-=======
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-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.
-
-Using Thrift with Java
-======================
-
-The Thrift Java source is not build using the GNU tools, but rather uses
-the Apache Ant build system, which tends to be predominant amongst Java
-developers.
-
-To compile the Java Thrift libraries, simply do the following:
-
-ant
-
-Yep, that's easy. Look for libthrift.jar in the base directory.
-
-To include Thrift in your applications simply add libthrift.jar to your
-classpath, or install if in your default system classpath of choice.
-
-
-Build Thrift behind a proxy:
-
-ant -Dproxy.enabled=1 -Dproxy.host=myproxyhost -Dproxy.user=thriftuser -Dproxy.pass=topsecret
-
-or via
-
-./configure --with-java ANT_FLAGS='-Dproxy.enabled=1 -Dproxy.host=myproxyhost -Dproxy.user=thriftuser -Dproxy.pass=topsecret'
-
-
-Dependencies
-============
-
-Apache Ant
-http://ant.apache.org/
diff --git a/lib/java/README.md b/lib/java/README.md
new file mode 100644
index 0000000..0b5f0d8
--- /dev/null
+++ b/lib/java/README.md
@@ -0,0 +1,176 @@
+Thrift Java Software Library
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+Building and installing from source
+===================================
+
+When using a CMake build from the source distribution on Linux the
+easiest way to build and install is this simple command line:
+
+    make all && sudo make install/fast
+
+It is important to use the install/fast option to eliminate
+the automatic rebuild by dependency that causes issues because
+the build tooling is designed to work with cached files in the
+user home directory during the build process. Instead this builds
+the code in the expected local build tree and then uses CMake
+install code to copy to the target destination.
+
+Building Thrift with Gradle without CMake/Autoconf
+==================================================
+
+The Thrift Java source is not build using the GNU tools, but rather uses
+the Gradle build system, which tends to be predominant amongst Java
+developers.
+
+To compile the Java Thrift libraries, simply do the following:
+
+    ./gradlew
+
+Yep, that's easy. Look for libthrift-<version>.jar in the build/libs directory.
+
+The default build will run the unit tests which expect a usable
+Thrift compiler to exist on the system. You have two choices for
+that.
+
+* Build the Thrift executable from source at the default
+  location in the source tree. The project is configured
+  to look for it there.
+* Install the published binary distribution to have Thrift
+  executable in a known location and add the path to the
+  ~/.gradle/gradle.properties file using the property name
+  "thrift.compiler". For example this would set the path in
+  a Windows box if Thrift was installed under C:\Thrift
+
+    thrift.compiler=C:/Thrift/thrift.exe
+
+To just build the library without running unit tests you simply do this.
+
+    ./gradlew assemble
+
+To install the library in the local Maven repository location
+where other Maven or Gradle builds can reference it simply do this.
+
+    ./gradlew install
+
+The library will be placed in your home directory under .m2/repository
+
+To include Thrift in your applications simply add libthrift.jar to your
+classpath, or install if in your default system classpath of choice.
+
+
+Build Thrift behind a proxy:
+
+    ./gradlew -Dhttp.proxyHost=myproxyhost -Dhttp.proxyPort=8080 -Dhttp.proxyUser=thriftuser -Dhttp.proxyPassword=topsecret
+
+or via
+
+    ./configure --with-java GRADLE_OPTS='-Dhttp.proxyHost=myproxyhost -Dhttp.proxyPort=8080 -Dhttp.proxyUser=thriftuser -Dhttp.proxyPassword=topsecret'
+
+
+Unit Test HTML Reports
+======================
+
+The build will automatically generate an HTML Unit Test report. This can be found
+under build/reports/tests/test/index.html. It can be viewed with a browser
+directly from that location.
+
+
+Clover Code Coverage for Thrift
+===============================
+
+The build will optionally generate Clover Code coverage if the Gradle property
+`cloverEnabled=true` is set in ~/.gradle/gradle.properties or on the command line
+via `-PcloverEnabled=true`. The generated report can be found under the location
+build/reports/clover/html/index.html. It can be viewed with a browser
+directly from that location. Additionally, a PDF report is generated and is found
+under the location build/reports/clover/clover.pdf.
+
+The following command will build, unit test, and generate Clover reports:
+
+    ./gradlew -PcloverEnabled=true
+
+
+Publishing Maven Artifacts to Maven Central
+===========================================
+
+The Automake build generates a Makefile that provides the correct parameters
+when you run the build provided the configure.ac has been set with the correct
+version number. The Gradle build will receive the correct value for the build.
+The same applies to the CMake build, the value from the configure.ac file will
+be used if you execute these commands:
+
+    make maven-publish   -- This is for an Automake Linux build
+    make MavenPublish    -- This is for a CMake generated build
+
+The uploadArchives task in Gradle is preconfigured with all necessary details
+to sign and publish the artifacts from the build to the Apache Maven staging
+repository. The task requires the following externally provided properties to
+authenticate to the repository and sign the artifacts. The preferred approach
+is to create or edit the ~/.gradle/gradle.properties file and add the following
+properties to it.
+
+    # Signing key information for artifacts PGP signature (values are examples)
+    signing.keyId=24875D73
+    signing.password=secret
+    signing.secretKeyRingFile=/Users/me/.gnupg/secring.gpg
+
+    # Apache Maven staging repository user credentials
+    mavenUser=meMyselfAndI
+    mavenPassword=MySuperAwesomeSecretPassword
+
+It is also possible to manually publish using the Gradle build directly.
+With the key information and credentials in place the following will generate
+if needed the build artifacts and proceed to publish the results.
+
+    ./gradlew -Prelease=true -Pthrift.version=0.11.0 uploadArchives
+
+It is also possible to override the target repository for the Maven Publication
+by using a Gradle property, for example you can publish signed JAR files to your
+company internal server if you add this to the command line or in the
+~/.gradle/gradle.properties file. The URL below assumes a Nexus Repository.
+
+    maven-repository-url=https://my.company.com/service/local/staging/deploy/maven2
+
+Or the same on the command line:
+
+    ./gradlew -Pmaven-repository-url=https://my.company.com/service/local/staging/deploy/maven2 -Prelease=true -Pthrift.version=0.11.0 uploadArchives
+
+
+Dependencies
+============
+
+Gradle
+http://gradle.org/
+
+# Breaking Changes
+
+## 0.12.0
+
+The access modifier of the AutoExpandingBuffer class has been changed from
+public to default (package) and will no longer be accessible by third-party
+libraries.
+
+The access modifier of the ShortStack class has been changed from
+public to default (package) and will no longer be accessible by third-party
+libraries.
+
diff --git a/lib/java/android/build.gradle b/lib/java/android/build.gradle
new file mode 100644
index 0000000..c998423
--- /dev/null
+++ b/lib/java/android/build.gradle
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+apply plugin: 'com.android.library'
+
+android {
+    compileSdkVersion 23
+    buildToolsVersion "23.0.1"
+    useLibrary 'org.apache.http.legacy'
+    sourceSets.main.java {
+        srcDir '../src'
+        exclude 'org/apache/thrift/transport/TSaslClientTransport.java'
+        exclude 'org/apache/thrift/transport/TSaslServerTransport.java'
+        exclude 'org/apache/thrift/transport/TSaslTransport.java'
+    }
+}
+
+repositories {
+    mavenCentral()
+}
+dependencies {
+    compile 'org.slf4j:slf4j-api:1.7.13'
+    compile 'javax.servlet:servlet-api:2.5'
+    compile 'org.apache.httpcomponents:httpcore:4.4.4'
+}
+
+buildscript {
+    repositories {
+        mavenCentral()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:1.5.0'
+    }
+}
diff --git a/lib/java/android/settings.gradle b/lib/java/android/settings.gradle
new file mode 100644
index 0000000..75e97be
--- /dev/null
+++ b/lib/java/android/settings.gradle
@@ -0,0 +1 @@
+rootProject.name='thrift'
diff --git a/lib/java/android/src/main/AndroidManifest.xml b/lib/java/android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..43abdb7
--- /dev/null
+++ b/lib/java/android/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest package="org.apache.thrift">
+  <application />
+</manifest>
diff --git a/lib/java/build.gradle b/lib/java/build.gradle
new file mode 100644
index 0000000..4302f77
--- /dev/null
+++ b/lib/java/build.gradle
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+// Using the legacy plugin classpath for Clover so it can be loaded optionally
+buildscript {
+    repositories {
+        google()
+        jcenter()
+        gradlePluginPortal()
+    }
+
+    dependencies {
+        classpath 'com.bmuschko:gradle-clover-plugin:2.2.0'
+    }
+}
+
+plugins {
+    id 'java'
+    id 'maven'
+    id 'signing'
+    id 'com.github.johnrengelman.shadow' version '2.0.2'
+}
+
+description = 'Apache Thrift Java Library'
+
+defaultTasks 'build'
+
+// Version components for this project
+group = property('thrift.groupid')
+
+// Drop the -dev suffix, we use the SNAPSHOT suffix for non-release versions
+def parsedVersion = property('thrift.version').toString().replace('-dev', '')
+if (Boolean.parseBoolean(project.release)) {
+    version = parsedVersion
+} else {
+    version = parsedVersion + '-SNAPSHOT'
+}
+
+// Keeping the rest of the build logic in functional named scripts for clarity
+apply from: 'gradle/environment.gradle'
+apply from: 'gradle/sourceConfiguration.gradle'
+apply from: 'gradle/additionalArtifacts.gradle'
+apply from: 'gradle/generateTestThrift.gradle'
+apply from: 'gradle/unitTests.gradle'
+apply from: 'gradle/cloverCoverage.gradle'
+apply from: 'gradle/functionalTests.gradle'
+apply from: 'gradle/publishing.gradle'
+apply from: 'gradle/codeQualityChecks.gradle'
diff --git a/lib/java/build.properties b/lib/java/build.properties
deleted file mode 100644
index b73c38f..0000000
--- a/lib/java/build.properties
+++ /dev/null
@@ -1,32 +0,0 @@
-thrift.version=0.9.1
-thrift.groupid=org.apache.thrift
-release=true
-
-# Jar Versions 
-mvn.ant.task.version=2.1.3
-
-# Local Install paths
-install.path=/usr/local/lib
-install.javadoc.path=${install.path}
-
-# Maven dependency download locations
-mvn.repo=http://repo1.maven.org/maven2
-apache.repo=https://repository.apache.org/content/repositories/releases
-mvn.ant.task.url=${mvn.repo}/org/apache/maven/maven-ant-tasks/${mvn.ant.task.version}
-mvn.ant.task.jar=maven-ant-tasks-${mvn.ant.task.version}.jar
-
-# Apache Maven publish 
-license=http://www.apache.org/licenses/LICENSE-2.0.txt
-maven-repository-url=https://repository.apache.org/service/local/staging/deploy/maven2
-maven-repository-id=apache.releases.https
-
-# Jar Versions 
-mvn.ant.task.version=2.1.3
-
-# Dependency versions
-httpclient.version=4.2.5
-httpcore.version=4.2.4
-slf4j.version=1.5.8
-commons-lang3.version=3.1
-servlet.version=2.5
-
diff --git a/lib/java/build.xml b/lib/java/build.xml
deleted file mode 100755
index c2bfd9c..0000000
--- a/lib/java/build.xml
+++ /dev/null
@@ -1,382 +0,0 @@
-<?xml version="1.0"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
- 
- http://www.apache.org/licenses/LICENSE-2.0
- 
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
- -->
-<project name="libthrift" default="dist" basedir="."
-  xmlns:artifact="antlib:org.apache.maven.artifact.ant">
-  
-  <description>Thrift Build File</description>
-  <property name="thrift.root" location="../../"/>
-  <property name="thrift.artifactid" value="libthrift"/>
-
-  <!-- Include the base properties file -->
-  <property file="${basedir}/build.properties" />
-
-  <property environment="env"/>
-
-  <condition property="version" value="${thrift.version}">
-    <isset property="release"/>
-  </condition>
-  <property name="version" value="${thrift.version}-snapshot"/> 
-
-  <property name="final.name" value="${thrift.artifactid}-${version}"/>
-
-  <property name="src" location="${basedir}/src"/>
-  <property name="build.dir" location="${basedir}/build"/>
-  <property name="build.lib.dir" location="${build.dir}/lib"/>
-  <property name="build.tools.dir" location="${build.dir}/tools"/>
-  <property name="src.test" location="test"/>
-  <property name="javadoc.dir" location="${build.dir}/javadoc"/>
-  <property name="build.test.dir" location="${build.dir}/test"/>
-  <property name="test.thrift.home" location="${thrift.root}/test"/>
-
-  <property name="gen" location="gen-java"/>
-  <property name="genbean" location="gen-javabean"/>
-
-  <property name="jar.file" location="${build.dir}/${final.name}.jar"/>
-  <property name="test.jar.file" location="${build.dir}/${final.name}-test.jar"/>
-  <property name="javadoc.jar.file" location="${build.dir}/${final.name}-javadoc.jar"/>
-  <property name="source.tar.gz" location="${build.dir}/${final.name}-src.tar.gz"/>
-
-  <!-- Junit properties -->
-  <property name="test.junit.output.format" value="plain"/>
-  <property name="test.timeout" value="2000000"/>
-  <property name="test.src.dir" location="${basedir}/test"/>
-  <property name="test.log.dir" value="${build.test.dir}/log"/>
-  <property name="test.port" value="9090"/> 
-
-  <!-- maven properties -->
-  <property name="pom.xml" location="${build.dir}/${final.name}.pom"/>
-
-  <path id="compile.classpath">
-    <fileset dir="${build.lib.dir}"> 
-      <include name="**/*.jar"/>
-    </fileset>
-  </path>
-
-  <path id="test.classpath">
-    <path refid="compile.classpath"/>
-    <pathelement path="${env.CLASSPATH}"/>
-    <pathelement location="${build.test.dir}"/>
-    <pathelement location="${jar.file}"/>
-    <pathelement location="${test.jar.file}"/>
-  </path>
-
-  <!-- Tasks --> 
-  <target name="init" depends="setup.init,mvn.init" unless="init.finished">
-    <property name="init.finished" value="true"/>
-  </target>
-
-  <target name="setup.init">
-    <tstamp/>
-    <mkdir dir="${build.dir}"/>
-    <mkdir dir="${build.lib.dir}"/>
-    <mkdir dir="${build.tools.dir}"/>
-    <mkdir dir="${build.test.dir}"/>
-  </target>
-
-  <target name="compile" depends="init">
-    <javac srcdir="${src}" destdir="${build.dir}" source="1.5" target="1.5" 
-    debug="true" classpathref="compile.classpath" includeantruntime="false">
-      <compilerarg value="-Xlint:unchecked"/>
-    </javac>
-  </target>
-
-  <target name="javadoc" depends="init">
-    <javadoc sourcepath="${src}" destdir="${javadoc.dir}"
-      version="true" windowtitle="Thrift Java API" doctitle="Thrift Java API"
-      classpathref="test.classpath">
-    </javadoc>
-    <jar jarfile="${javadoc.jar.file}" basedir="${javadoc.dir}">
-      <manifest>
-        <attribute name="Implementation-Version" value="${version}"/>
-      </manifest>
-    </jar>
-  </target>
-
-  <target name="dist" depends="compile">
-    <mkdir dir="${build.dir}/META-INF"/>
-    <copy file="${thrift.root}/LICENSE" tofile="${build.dir}/META-INF/LICENSE.txt"/>
-    <copy file="${thrift.root}/NOTICE" tofile="${build.dir}/META-INF/NOTICE.txt"/>
-    <jar jarfile="${jar.file}">
-      <manifest>
-        <attribute name="Implementation-Version" value="${version}"/>
-        <attribute name="Bundle-ManifestVersion" value="2"/>
-        <attribute name="Bundle-SymbolicName" value="${thrift.groupid}"/>
-        <attribute name="Bundle-Name" value="Apache Thrift"/>
-        <attribute name="Bundle-Version" value="${version}"/>
-        <attribute name="Bundle-Description" value="Apache Thrift library"/>
-        <attribute name="Bundle-License" value="${license}"/>
-        <attribute name="Bundle-ActivationPolicy" value="lazy"/>
-        <attribute name="Export-Package" value="${thrift.groupid};version=${version}"/>
-      </manifest>
-      <fileset dir="${build.dir}">
-        <include name="org/apache/thrift/**/*.class"/>
-        <include name="META-INF/*.txt"/>
-      </fileset>
-    </jar>
-  </target>
-
-  <target name="pack.src">
-    <tar destfile="${source.tar.gz}" basedir="${src}" compression="gzip"/>
-  </target>
-
-  <target name="install" depends="dist,javadoc">
-    <copy todir="${install.path}">
-      <fileset dir="${build.dir}" includes="*.jar"/>
-      <fileset dir="${build.lib.dir}" includes="*.jar"/>
-    </copy>
-    <copy todir="${install.javadoc.path}">
-      <fileset dir="${javadoc.dir}" includes="**/*"/>
-    </copy>
-  </target>
-
-  <target name="clean">
-    <delete dir="${build.dir}"/>
-    <delete dir="${gen}"/>
-    <delete dir="${genbean}"/>
-  </target>
-
-  <target name="optional-generate" unless="no-gen-thrift"> 
-    <antcall target="generate">
-    </antcall>
-  </target>
-
-  <target name="compile-test" description="Build the test suite classes" depends="optional-generate,dist">
-    <javac debug="true" srcdir="${gen}" destdir="${build.test.dir}" classpathref="test.classpath" includeantruntime="false">
-      <compilerarg value="-Xlint:deprecation"/>
-      <!--<compilerarg value="-Xlint:unchecked"/>-->
-    </javac>  
-    <javac debug="true" srcdir="${genbean}" destdir="${build.test.dir}" classpathref="test.classpath" includeantruntime="false">
-      <compilerarg value="-Xlint:deprecation"/>
-      <!--<compilerarg value="-Xlint:unchecked"/>-->
-    </javac>  
-    <javac debug="true" srcdir="${src.test}" destdir="${build.test.dir}" classpathref="test.classpath" includeantruntime="false">
-      <compilerarg value="-Xlint:deprecation"/>
-      <!--<compilerarg value="-Xlint:unchecked"/>-->
-    </javac>  
-    <copy todir="${build.test.dir}">
-      <fileset dir="${src.test}" includes="log4j.properties"/>
-    </copy>
-    <jar jarfile="${test.jar.file}" basedir="${build.test.dir}"/>
-  </target>
-
-  <target name="junit-test" description="Run the JUnit test suite" depends="compile-test">
-    <mkdir dir="${test.log.dir}"/>
-    <junit printsummary="true" showoutput="${test.output}" timeout="${test.timeout}" 
-      haltonfailure="true" errorProperty="tests.failed" failureProperty="tests.failed"
-      fork="true" forkmode="perTest" maxmemory="512m"
-    >
-      <sysproperty key="build.test" value="${build.test.dir}"/>
-      <sysproperty key="test.port" value="${test.port}"/>
-      <sysproperty key="javax.net.ssl.trustStore" value="${src.test}/.truststore"/>
-      <sysproperty key="javax.net.ssl.trustStorePassword" value="thrift"/>
-      <sysproperty key="javax.net.ssl.keyStore" value="${src.test}/.keystore"/>
-      <sysproperty key="javax.net.ssl.keyStorePassword" value="thrift"/>
-      <classpath refid="test.classpath"/>
-      <formatter type="${test.junit.output.format}"/>
-      <batchtest todir="${test.log.dir}" unless="testcase">
-        <fileset dir="${test.src.dir}">
-          <include name="**/Test*.java"/>
-          <exclude name="**/TestClient.java"/>
-          <exclude name="**/TestServer.java"/>
-          <exclude name="**/TestNonblockingServer.java"/>
-        </fileset>
-      </batchtest>
-      <batchtest todir="${test.log.dir}" if="testcase">
-        <fileset dir="${test.src.dir}" includes="**/${testcase}.java"/>
-      </batchtest>
-    </junit>
-    <fail if="tests.failed">Tests failed!</fail>
-  </target>
-
-  <target name="deprecated-test" description="Run the non-JUnit test suite" depends="compile-test">
-    <java classname="org.apache.thrift.test.EqualityTest" classpathref="test.classpath" failonerror="true"/>
-    <java classname="org.apache.thrift.test.JavaBeansTest" classpathref="test.classpath" failonerror="true"/>
-  </target>
-
-  <target name="test" description="Run the full test suite" depends="junit-test,deprecated-test"/>
-
-  <target name="testclient" description="Run a test client" depends="compile-test">
-    <java classname="org.apache.thrift.test.TestClient"
-      classpathref="test.classpath" failonerror="true" fork="true">
-      <sysproperty key="javax.net.ssl.trustStore" value="${src.test}/.truststore"/>
-      <sysproperty key="javax.net.ssl.trustStorePassword" value="thrift"/>
-      <arg line="${testargs}"/>
-    </java>
-  </target>
-
-  <target name="testserver" description="Run a test server" depends="compile-test">
-    <java classname="org.apache.thrift.test.TestServer"
-      classpathref="test.classpath" failonerror="true" fork="true"> 
-      <sysproperty key="javax.net.ssl.keyStore" value="${src.test}/.keystore"/>
-      <sysproperty key="javax.net.ssl.keyStorePassword" value="thrift"/>
-      <arg line="${testargs}"/> 
-    </java>
-  </target>
-
-  <target name="testnonblockingserver" description="Run a test nonblocking server" depends="compile-test">
-    <java classname="org.apache.thrift.test.TestNonblockingServer"
-      classpathref="test.classpath" failonerror="true">
-      <arg line="${testargs}"/>
-    </java>
-  </target>
-
-  <target name="generate">
-    <!-- Generate the thrift gen-java source -->
-    <exec executable="../../compiler/cpp/thrift" failonerror="true">
-      <arg line="--gen java:hashcode ${test.thrift.home}/ThriftTest.thrift"/>
-    </exec>
-    <exec executable="../../compiler/cpp/thrift" failonerror="true">
-      <arg line="--gen java:hashcode ${test.thrift.home}/DebugProtoTest.thrift"/>
-    </exec>
-    <exec executable="../../compiler/cpp/thrift" failonerror="true">
-      <arg line="--gen java:hashcode ${test.thrift.home}/OptionalRequiredTest.thrift"/>
-    </exec>
-    <exec executable="../../compiler/cpp/thrift" failonerror="true">
-      <arg line="--gen java:beans,nocamel ${test.thrift.home}/JavaBeansTest.thrift"/>
-    </exec>
-    <exec executable="../../compiler/cpp/thrift" failonerror="true">
-      <arg line="--gen java:hashcode ${test.thrift.home}/ManyOptionals.thrift"/>
-    </exec>
-  </target>
-
-  <target name="proxy" if="proxy.enabled">
-    <setproxy proxyhost="${proxy.host}" proxyport="${proxy.port}"
-      proxyuser="${proxy.user}" proxypassword="${proxy.pass}"/>
-  </target>
-
-  <target name="mvn.ant.tasks.download" depends="setup.init,mvn.ant.tasks.check,proxy" unless="mvn.ant.tasks.found">
-    <get src="${mvn.ant.task.url}/${mvn.ant.task.jar}" dest="${build.tools.dir}/${mvn.ant.task.jar}" usetimestamp="true"/>
-  </target>
-
-  <target name="mvn.ant.tasks.check">
-    <condition property="mvn.ant.tasks.found">
-      <typefound uri="antlib:org.apache.maven.artifact.ant" name="artifact"/>
-    </condition>
-  </target> 
-
-  <target name="mvn.init" depends="mvn.ant.tasks.download" unless="mvn.finished">
-    <!-- Download mvn ant tasks, download dependencies, and setup pom file -->
-    <typedef uri="antlib:org.apache.maven.artifact.ant" classpath="${build.tools.dir}/${mvn.ant.task.jar}"/>
-
-    <!-- remote repositories used to download dependencies from -->
-    <artifact:remoteRepository id="central" url="${mvn.repo}"/>
-    <artifact:remoteRepository id="apache" url="${apache.repo}"/>
-
-    <!-- Pom file information -->
-    <artifact:pom id="pom" 
-      groupId="${thrift.groupid}" 
-      artifactId="${thrift.artifactid}"
-      version="${version}" 
-      url="http://thrift.apache.org"
-      name="Apache Thrift"
-      description="Thrift is a software framework for scalable cross-language services development."
-      packaging="pom"
-    >
-      <remoteRepository refid="central"/>
-      <remoteRepository refid="apache"/>
-      <license name="The Apache Software License, Version 2.0" url="${license}"/>
-      <scm connection="scm:git:https://git-wip-us.apache.org/repos/asf/thrift.git" 
-      developerConnection="scm:git:https://git-wip-us.apache.org/repos/asf/thrift.git"
-      url="https://git-wip-us.apache.org/repos/asf?p=thrift.git"
-      />
-      <!-- Thrift Developers -->
-      <developer id="mcslee" name="Mark Slee"/>
-      <developer id="dreiss" name="David Reiss"/>
-      <developer id="aditya" name="Aditya Agarwal"/>
-      <developer id="marck" name="Marc Kwiatkowski"/>
-      <developer id="jwang" name="James Wang"/>
-      <developer id="cpiro" name="Chris Piro"/>
-      <developer id="bmaurer" name="Ben Maurer"/>
-      <developer id="kclark" name="Kevin Clark"/>
-      <developer id="jake" name="Jake Luciani"/>
-      <developer id="bryanduxbury" name="Bryan Duxbury"/>
-      <developer id="esteve" name="Esteve Fernandez"/>
-      <developer id="todd" name="Todd Lipcon"/>
-      <developer id="geechorama" name="Andrew McGeachie"/>
-      <developer id="molinaro" name="Anthony Molinaro"/>
-      <developer id="roger" name="Roger Meier"/>
-      <developer id="jfarrell" name="Jake Farrell"/>
-      <developer id="jensg" name="Jens Geyer"/>
-      <developer id="carl" name="Carl Yeksigian"/>
-
-      <!-- Thrift dependencies list -->
-      <dependency groupId="org.slf4j" artifactId="slf4j-api" version="${slf4j.version}"/>
-      <dependency groupId="org.apache.commons" artifactId="commons-lang3" version="${commons-lang3.version}"/>
-      <dependency groupId="javax.servlet" artifactId="servlet-api" version="${servlet.version}" scope="provided"/>
-      <dependency groupId="org.apache.httpcomponents" artifactId="httpclient" version="${httpclient.version}"/>
-      <dependency groupId="org.apache.httpcomponents" artifactId="httpcore" version="${httpcore.version}"/>
-    </artifact:pom>
-
-    <!-- Generate the pom file -->
-    <artifact:writepom pomRefId="pom" file="${pom.xml}"/>
-
-    <!-- Download the dependencies -->
-    <artifact:dependencies filesetId="build-dependency-jars" pomRefId="pom"/>
-
-    <!-- Copy the dependencies to the build/lib dir -->
-    <copy todir="${build.dir}/lib">
-      <fileset refid="build-dependency-jars"/>
-      <mapper type="flatten"/>
-    </copy>
-
-    <!-- Dependencies needed for testing -->
-    <artifact:dependencies filesetId="test-dependency-jars" useScope="runtime">
-      <dependency groupId="org.slf4j" artifactId="slf4j-log4j12" version="1.5.8"/>
-      <dependency groupId="junit" artifactId="junit" version="4.4"/>
-    </artifact:dependencies>
-
-    <!-- Copy the test dependencies to the build/lib dir -->
-    <copy todir="${build.dir}/lib">
-      <fileset refid="test-dependency-jars"/>
-      <mapper type="flatten"/>
-    </copy>
-
-    <property name="mvn.finished" value="true"/>
-  </target>
-
-  <macrodef name="signAndDeploy">
-    <!-- Sign and deploy jars to apache repo -->
-    <attribute name="file"/>
-    <attribute name="classifier" default=""/>
-    <attribute name="packaging" default="jar"/>
-    <attribute name="pom" default=""/>
-    <sequential>
-      <artifact:mvn fork="true">
-        <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.1:sign-and-deploy-file"/>
-        <arg value="-DrepositoryId=${maven-repository-id}"/>
-        <arg value="-Durl=${maven-repository-url}"/>
-        <arg value="-DpomFile=@{pom}"/>
-        <arg value="-Dfile=@{file}"/>
-        <arg value="-Dclassifier=@{classifier}"/>
-        <arg value="-Dpackaging=@{packaging}"/>
-        <arg value="-Pgpg"/>
-      </artifact:mvn>
-    </sequential>
-  </macrodef>
-
-  <target name="publish" depends="clean,init,test,dist,javadoc,pack.src">
-    <!-- Compile, package, test and then send release to apache maven repo -->
-    <!-- run with: ant -Drelease=true publish-->
-    <signAndDeploy file="${pom.xml}" packaging="pom" classifier="" pom="${pom.xml}"/>
-    <signAndDeploy file="${jar.file}" packaging="jar" classifier="" pom="${pom.xml}"/>
-    <signAndDeploy file="${javadoc.jar.file}" packaging="jar" classifier="javadoc" pom="${pom.xml}"/>
-    <signAndDeploy file="${source.tar.gz}" packaging="src" classifier="tar.gz" pom="${pom.xml}"/>
-  </target>
-</project>
diff --git a/lib/java/code_quality_tools/findbugs-filter.xml b/lib/java/code_quality_tools/findbugs-filter.xml
new file mode 100644
index 0000000..8a93b0a
--- /dev/null
+++ b/lib/java/code_quality_tools/findbugs-filter.xml
@@ -0,0 +1,51 @@
+<FindBugsFilter>
+    <!--
+        This file controls filtering some of the more obnoxious findbugs reports.
+        Some may be worthy of examination and resolution, others are too nit-picky.
+    -->
+    <Match>
+        <Or>
+            <!-- Filter the missing serialVersionUID errors -->
+            <Bug code="SnVI" />
+            <!-- Filter Malicious code vulnerability Warnings -->
+            <Bug code="EI,EI2" />
+            <!-- Filter Unchecked/unconfirmed cast -->
+            <Bug code="BC" />
+            <!-- Filter Should return a zero length array rather than null? -->
+            <Bug code="PZLA" />
+            <!-- Filter Redundant nullcheck -->
+            <Bug code="RCN" />
+            <!-- Filter Exception is caught when Exception is not thrown -->
+            <Bug code="REC" />
+            <!-- Filter Switch statement found where default case is missing -->
+            <Bug code="SF" />
+            <!-- Filter Unread public/protected field -->
+            <Bug code="UrF" />
+            <!-- Filter Field not initialized in constructor and dereferenced -->
+            <Bug code="UwF" />
+        </Or>
+    </Match>
+     <Match>
+        <!-- Filter method invokes System.exit(...), which shuts down the entire virtual machine -->
+        <Class name="org.apache.thrift.transport.TFileTransport" />
+        <Method name="printUsage" />
+        <Bug code="Dm" />
+     </Match>
+     <Match>
+        <!-- Filter method might ignore java.lang.Exception -->
+       <Class name="org.apache.thrift.transport.TSimpleFileTransport" />
+       <Method name="close" />
+       <Bug code="DE" />
+     </Match>
+     <Match>
+        <!-- Filter method might ignore java.lang.Exception -->
+       <Class name="org.apache.thrift.TNonblockingMultiFetchClient$MultiFetch" />
+       <Method name="run" />
+       <Bug code="DE" />
+     </Match>
+     <Match>
+        <!-- Filter Class defines non-transient non-serializable instance field -->
+       <Class name="org.apache.thrift.server.TServlet" />
+       <Bug code="Se" />
+     </Match>
+</FindBugsFilter>
diff --git a/lib/java/coding_standards.md b/lib/java/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/java/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/java/gradle.properties b/lib/java/gradle.properties
new file mode 100644
index 0000000..056a96e
--- /dev/null
+++ b/lib/java/gradle.properties
@@ -0,0 +1,33 @@
+# This file is shared currently between this Gradle build and the
+# Ant builds for fd303 and JavaScript. Keep the dotted notation for
+# the properties to minimize the changes in the dependencies.
+thrift.version=1.0.0
+thrift.groupid=org.apache.thrift
+release=true
+
+# Local Install paths
+install.path=/usr/local/lib
+install.javadoc.path=/usr/local/lib
+
+# Test execution properties
+testPort=9090
+
+# Test with Clover Code coverage (disabled by default)
+cloverEnabled=false
+
+# Maven dependency download locations
+mvn.repo=http://repo1.maven.org/maven2
+apache.repo=https://repository.apache.org/content/repositories/releases
+
+# Apache Maven publish
+license=http://www.apache.org/licenses/LICENSE-2.0.txt
+maven-repository-url=https://repository.apache.org/service/local/staging/deploy/maven2
+maven-repository-id=apache.releases.https
+
+# Dependency versions
+httpclient.version=4.4.1
+httpcore.version=4.4.1
+slf4j.version=1.7.12
+servlet.version=2.5
+junit.version=4.12
+mockito.version=1.9.5
diff --git a/lib/java/gradle/additionalArtifacts.gradle b/lib/java/gradle/additionalArtifacts.gradle
new file mode 100644
index 0000000..201469d
--- /dev/null
+++ b/lib/java/gradle/additionalArtifacts.gradle
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+task sourcesJar(type: Jar, group: 'Build') {
+    description = 'Assembles a jar archive containing the main Java sources.'
+
+    classifier 'sources'
+    from sourceSets.main.allSource
+}
+
+task javadocJar(type: Jar, dependsOn: javadoc, group: 'Build') {
+    description = 'Assembles a jar archive containing the JavaDoc.'
+
+    classifier 'javadoc'
+    from javadoc.destinationDir
+}
+
+artifacts {
+    archives sourcesJar
+    archives javadocJar
+}
+
diff --git a/lib/java/gradle/cloverCoverage.gradle b/lib/java/gradle/cloverCoverage.gradle
new file mode 100644
index 0000000..cef0e79
--- /dev/null
+++ b/lib/java/gradle/cloverCoverage.gradle
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// Keep this as an optional feature for now, disabled by default
+if (Boolean.parseBoolean(project.cloverEnabled)) {
+    apply plugin: 'com.bmuschko.clover'
+
+    dependencies {
+        clover 'org.openclover:clover:4.2.+'
+    }
+
+    clover {
+
+        testIncludes = ['**/Test*.java']
+        // Exclude the generated test code from code coverage
+        testExcludes = ['thrift/test/Test*.java']
+
+        compiler {
+            encoding = 'UTF-8'
+            debug = true
+        }
+
+        report {
+            html = true
+            pdf = true
+        }
+    }
+
+    build.dependsOn cloverGenerateReport
+}
diff --git a/lib/java/gradle/codeQualityChecks.gradle b/lib/java/gradle/codeQualityChecks.gradle
new file mode 100644
index 0000000..1ff1c29
--- /dev/null
+++ b/lib/java/gradle/codeQualityChecks.gradle
@@ -0,0 +1,39 @@
+
+// =================================================================
+// Configure the Gradle code quality plugins here.
+//
+
+apply plugin: 'findbugs'
+
+findbugs {
+    ignoreFailures = true
+    toolVersion = '3.0.1'
+    sourceSets = [ sourceSets.main ]
+    effort = 'max'
+    reportLevel = 'low'
+    excludeFilter = file('code_quality_tools/findbugs-filter.xml')
+}
+
+tasks.withType(FindBugs) {
+    reports {
+        text.enabled = false
+        html.enabled = true
+        xml.enabled = false
+    }
+}
+
+apply plugin: 'pmd'
+
+pmd {
+    ignoreFailures = true
+    toolVersion = '6.0.0'
+    sourceSets = [ sourceSets.main ]
+    ruleSets = [ 'java-basic' ]
+}
+
+tasks.withType(Pmd) {
+    reports {
+        html.enabled = true
+        xml.enabled = false
+    }
+}
diff --git a/lib/java/gradle/environment.gradle b/lib/java/gradle/environment.gradle
new file mode 100644
index 0000000..9b7eb1e
--- /dev/null
+++ b/lib/java/gradle/environment.gradle
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// Override the build directory if CMake is used (allows for out-of-tree-builds)
+if (hasProperty('build.dir')) {
+    buildDir = file(property('build.dir'))
+}
+
+// In order to remain compatible with other Ant based builds in the system
+// we convert the gradle.properties into DSL friendly camelCased properties
+ext.installPath = property('install.path')
+ext.installJavadocPath = property('install.javadoc.path')
+
+ext.thriftRoot = file('../..')
+
+if (hasProperty('thrift.compiler')) {
+    ext.thriftCompiler = property('thrift.compiler')
+} else {
+    ext.thriftCompiler = "$thriftRoot/compiler/cpp/thrift"
+}
+
+ext.mvnRepo = property('mvn.repo')
+ext.apacheRepo = property('apache.repo')
+ext.mavenRepositoryUrl = property('maven-repository-url')
+
+// Versions used in this project
+ext.httpclientVersion = property('httpclient.version')
+ext.httpcoreVersion = property('httpcore.version')
+ext.servletVersion = property('servlet.version')
+ext.slf4jVersion = property('slf4j.version')
+ext.junitVersion = property('junit.version')
+ext.mockitoVersion = property('mockito.version')
+
+// In this section you declare where to find the dependencies of your project
+repositories {
+    maven {
+        name 'Maven Central Repository'
+        url mvnRepo
+    }
+    maven {
+        name 'Apache Maven Repository'
+        url apacheRepo
+    }
+}
+
+dependencies {
+    compile "org.slf4j:slf4j-api:${slf4jVersion}"
+    compile "org.apache.httpcomponents:httpclient:${httpclientVersion}"
+    compile "org.apache.httpcomponents:httpcore:${httpcoreVersion}"
+    compile "javax.servlet:servlet-api:${servletVersion}"
+
+    testCompile "junit:junit:${junitVersion}"
+    testCompile "org.mockito:mockito-all:${mockitoVersion}"
+    testRuntime "org.slf4j:slf4j-log4j12:${slf4jVersion}"
+}
diff --git a/lib/java/gradle/functionalTests.gradle b/lib/java/gradle/functionalTests.gradle
new file mode 100644
index 0000000..c420d12
--- /dev/null
+++ b/lib/java/gradle/functionalTests.gradle
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// ----------------------------------------------------------------------------
+// Functional testing harness creation. This helps run the cross-check tests.
+// The Makefile precross target invokes the shadowJar task and the tests.json
+// code is changed to call runclient or runserver as needed.
+
+// ----------------------------------------------------------------------------
+// Cross Test sources are separated in their own sourceSet
+//
+sourceSets {
+    crossTest {
+        java {
+            srcDir 'test'
+            include '**/test/TestClient.java'
+            include '**/test/TestServer.java'
+            include '**/test/TestNonblockingServer.java'
+        }
+    }
+}
+
+configurations {
+    crossTestCompile { extendsFrom testCompile }
+    crossTestRuntime { extendsFrom crossTestCompile, testRuntime }
+}
+
+dependencies {
+    crossTestCompile sourceSets.main.output
+    crossTestCompile sourceSets.test.output
+}
+
+// I am using shadow plugin to make a self contained functional test Uber JAR that
+// eliminates startup problems with wrapping the cross-check harness in Gradle.
+// This is used by the runner scripts as the single classpath entry which
+// allows the process to be as lightweight as it can.
+shadowJar {
+    description = 'Assemble a test JAR file for cross-check execution'
+    // make sure the runners are created when this runs
+    dependsOn 'generateRunnerScriptForClient', 'generateRunnerScriptForServer', 'generateRunnerScriptForNonblockingServer'
+
+    baseName = 'functionalTest'
+    destinationDir = file("$buildDir/functionalTestJar")
+    classifier = null
+
+    // We do not need a version number for this internal jar
+    version = null
+
+    // Bundle the complete set of unit test classes including generated code
+    // and the runtime dependencies in one JAR to expedite execution.
+    from sourceSets.test.output
+    from sourceSets.crossTest.output
+    configurations = [project.configurations.testRuntime]
+}
+
+// Common script runner configuration elements
+def scriptExt = ''
+def execExt = ''
+def scriptHead = '#!/bin/bash'
+def args = '$*'
+
+// Although this is marked internal it is an available and stable interface
+if (org.gradle.internal.os.OperatingSystem.current().windows) {
+    scriptExt = '.bat'
+    execExt = '.exe'
+    scriptHead = '@echo off'
+    args = '%*'
+}
+
+// The Java executable to use with the runner scripts
+def javaExe = file("${System.getProperty('java.home')}/bin/java${execExt}").canonicalPath
+// The common Uber jar path
+def jarPath = shadowJar.archivePath.canonicalPath
+def trustStore = file('test/.truststore').canonicalPath
+def keyStore = file('test/.keystore').canonicalPath
+
+task generateRunnerScriptForClient(group: 'Build') {
+    description = 'Generate a runner script for cross-check tests with TestClient'
+
+    def clientFile = file("$buildDir/runclient${scriptExt}")
+
+    def runClientText = """\
+${scriptHead}
+
+"${javaExe}" -cp "$jarPath" "-Djavax.net.ssl.trustStore=$trustStore" -Djavax.net.ssl.trustStorePassword=thrift org.apache.thrift.test.TestClient $args
+"""
+    inputs.property 'runClientText', runClientText
+    outputs.file clientFile
+
+    doLast {
+        clientFile.parentFile.mkdirs()
+        clientFile.text = runClientText
+        clientFile.setExecutable(true, false)
+    }
+}
+
+task generateRunnerScriptForServer(group: 'Build') {
+    description = 'Generate a runner script for cross-check tests with TestServer'
+
+    def serverFile = file("$buildDir/runserver${scriptExt}")
+
+    def runServerText = """\
+${scriptHead}
+
+"${javaExe}" -cp "$jarPath" "-Djavax.net.ssl.keyStore=$keyStore" -Djavax.net.ssl.keyStorePassword=thrift org.apache.thrift.test.TestServer $args
+"""
+
+    inputs.property 'runServerText', runServerText
+    outputs.file serverFile
+
+    doLast {
+        serverFile.parentFile.mkdirs()
+        serverFile.text = runServerText
+        serverFile.setExecutable(true, false)
+    }
+}
+
+task generateRunnerScriptForNonblockingServer(group: 'Build') {
+    description = 'Generate a runner script for cross-check tests with TestNonblockingServer'
+
+    def serverFile = file("$buildDir/runnonblockingserver${scriptExt}")
+
+    def runServerText = """\
+${scriptHead}
+
+"${javaExe}" -cp "$jarPath" "-Djavax.net.ssl.keyStore=$keyStore" -Djavax.net.ssl.keyStorePassword=thrift org.apache.thrift.test.TestNonblockingServer $args
+"""
+
+    inputs.property 'runServerText', runServerText
+    outputs.file serverFile
+
+    doLast {
+        serverFile.parentFile.mkdirs()
+        serverFile.text = runServerText
+        serverFile.setExecutable(true, false)
+    }
+}
diff --git a/lib/java/gradle/generateTestThrift.gradle b/lib/java/gradle/generateTestThrift.gradle
new file mode 100644
index 0000000..2b53739
--- /dev/null
+++ b/lib/java/gradle/generateTestThrift.gradle
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// Generated code locations for Unit tests
+ext.genSrc = file("$buildDir/gen-java")
+ext.genBeanSrc = file("$buildDir/gen-javabean")
+ext.genReuseSrc = file("$buildDir/gen-javareuse")
+ext.genFullCamelSrc = file("$buildDir/gen-fullcamel")
+ext.genUnsafeSrc = file("$buildDir/gen-unsafe")
+
+// Add the generated code directories to the test source set
+sourceSets {
+    test.java.srcDirs genSrc, genBeanSrc, genReuseSrc, genFullCamelSrc, genUnsafeSrc
+}
+
+// ----------------------------------------------------------------------------
+// Code generation for Unit Testing
+
+// A callable closure to make this easier
+ext.thriftCompile = { Task task, String thriftFileName, String generator = 'java', File outputDir = genSrc ->
+    def thriftFile = file("$thriftRoot/test/$thriftFileName")
+    assert thriftFile.exists()
+
+    task.inputs.file thriftFile
+    task.outputs.dir outputDir
+
+    task.doLast {
+        outputDir.mkdirs()
+        def result = exec {
+            executable file(thriftCompiler)
+            args '--gen', generator
+            args '-out', outputDir
+            args thriftFile
+            standardOutput = task.outputBuffer
+            errorOutput = task.outputBuffer
+            ignoreExitValue = true
+        }
+        if (result.exitValue != 0) {
+            // Only show the Thrift compiler output on failures, cuts down on noise!
+            println task.outputBuffer.toString()
+            result.rethrowFailure()
+        }
+    }
+}
+
+task generate(group: 'Build') {
+    description = 'Generate all unit test Thrift sources'
+    compileTestJava.dependsOn it
+}
+
+task generateJava(group: 'Build') {
+    description = 'Generate the thrift gen-java source'
+    generate.dependsOn it
+
+    ext.outputBuffer = new ByteArrayOutputStream()
+
+    thriftCompile(it, 'ThriftTest.thrift')
+    thriftCompile(it, 'JavaTypes.thrift')
+    thriftCompile(it, 'DebugProtoTest.thrift')
+    thriftCompile(it, 'DoubleConstantsTest.thrift')
+    thriftCompile(it, 'OptionalRequiredTest.thrift')
+    thriftCompile(it, 'ManyOptionals.thrift')
+    thriftCompile(it, 'JavaDeepCopyTest.thrift')
+    thriftCompile(it, 'EnumContainersTest.thrift')
+}
+
+task generateBeanJava(group: 'Build') {
+    description = 'Generate the thrift gen-javabean source'
+    generate.dependsOn it
+
+    ext.outputBuffer = new ByteArrayOutputStream()
+
+    thriftCompile(it, 'JavaBeansTest.thrift', 'java:beans,nocamel', genBeanSrc)
+}
+
+task generateReuseJava(group: 'Build') {
+    description = 'Generate the thrift gen-javareuse source'
+    generate.dependsOn it
+
+    ext.outputBuffer = new ByteArrayOutputStream()
+
+    thriftCompile(it, 'FullCamelTest.thrift', 'java:fullcamel', genFullCamelSrc)
+}
+
+task generateFullCamelJava(group: 'Build') {
+    description = 'Generate the thrift gen-fullcamel source'
+    generate.dependsOn it
+
+    ext.outputBuffer = new ByteArrayOutputStream()
+
+    thriftCompile(it, 'ReuseObjects.thrift', 'java:reuse-objects', genReuseSrc)
+}
+
+task generateUnsafeBinariesJava(group: 'Build') {
+    description = 'Generate the thrift gen-unsafebinaries source'
+    generate.dependsOn it
+
+    ext.outputBuffer = new ByteArrayOutputStream()
+
+    thriftCompile(it, 'UnsafeTypes.thrift', 'java:unsafe_binaries', genUnsafeSrc)
+}
diff --git a/lib/java/gradle/publishing.gradle b/lib/java/gradle/publishing.gradle
new file mode 100644
index 0000000..6b04043
--- /dev/null
+++ b/lib/java/gradle/publishing.gradle
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// ----------------------------------------------------------------------------
+// Installation subtasks, not used currently, we use "make install/fast"
+task installDist(type: Copy, group: 'Install') {
+    description = "Copy Thrift JAR and dependencies into $installPath location"
+
+    destinationDir = file(installPath)
+
+    from jar
+    from configurations.compile
+}
+
+task installJavadoc(type: Copy, group: 'Install', dependsOn: javadoc) {
+    description = "Install Thrift JavaDoc into $installJavadocPath location"
+
+    destinationDir = file(installJavadocPath)
+
+    from javadoc.destinationDir
+}
+
+// This is not needed by Gradle builds but the remaining Ant builds seem to
+// need access to the generated test classes for Thrift unit tests so we
+// assist them to use it this way.
+task copyDependencies(type: Copy, group: 'Build') {
+    description = 'Copy runtime dependencies in a common location for other Ant based projects'
+    project.assemble.dependsOn it
+
+    destinationDir = file("$buildDir/deps")
+    from configurations.testRuntime
+    // exclude some very specific unit test dependencies
+    exclude '**/junit*.jar', '**/mockito*.jar', '**/hamcrest*.jar'
+}
+
+// ----------------------------------------------------------------------------
+// Allow this configuration to be shared between install and uploadArchives tasks
+def configurePom(pom) {
+    pom.project {
+        name 'Apache Thrift'
+        description 'Thrift is a software framework for scalable cross-language services development.'
+        packaging 'jar'
+        url 'http://thrift.apache.org'
+
+        scm {
+            url 'https://github.com/apache/thrift.git'
+            connection 'scm:git:https://github.com/apache/thrift.git'
+            developerConnection 'scm:git:https://github.com/apache/thrift.git'
+        }
+
+        licenses {
+            license {
+                name 'The Apache Software License, Version 2.0'
+                url "${project.license}"
+                distribution 'repo'
+            }
+        }
+
+        developers {
+            developer {
+                id 'dev'
+                name 'Apache Thrift Developers'
+                email 'dev@thrift.apache.org'
+            }
+        }
+    }
+
+    pom.whenConfigured {
+        // Fixup the scope for servlet-api to be 'provided' instead of 'compile'
+        dependencies.find { dep -> dep.groupId == 'javax.servlet' && dep.artifactId == 'servlet-api' }.with {
+            // it.optional = true
+            it.scope = 'provided'
+        }
+    }
+}
+
+install {
+    repositories.mavenInstaller {
+        configurePom(pom)
+    }
+}
+
+uploadArchives {
+    dependsOn test // make sure we run unit tests when publishing
+    repositories.mavenDeployer {
+        // signPom will silently do nothing when no signing information is provided
+        beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
+        repository(url: project.mavenRepositoryUrl) {
+            if (project.hasProperty('mavenUser') && project.hasProperty('mavenPassword')) {
+                authentication(userName: mavenUser, password: mavenPassword)
+            }
+        }
+        configurePom(pom)
+    }
+}
+
+// Signing configuration, optional, only when release and uploadArchives is activated
+signing {
+    required { !version.endsWith("SNAPSHOT") && gradle.taskGraph.hasTask("uploadArchives") }
+    sign configurations.archives
+}
diff --git a/lib/java/gradle/sourceConfiguration.gradle b/lib/java/gradle/sourceConfiguration.gradle
new file mode 100644
index 0000000..8dd0331
--- /dev/null
+++ b/lib/java/gradle/sourceConfiguration.gradle
@@ -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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// ----------------------------------------------------------------------------
+// source sets for main and test sources
+sourceSets {
+    main {
+        java {
+            srcDir 'src'
+        }
+    }
+    test {
+        java {
+            srcDir 'test'
+            // see functionalTests.gradle for these files
+            exclude '**/test/TestClient.java'
+            exclude '**/test/TestServer.java'
+            exclude '**/test/TestNonblockingServer.java'
+        }
+        resources {
+            srcDir 'test'
+            include 'log4j.properties'
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+// Compiler configuration details
+
+sourceCompatibility = '1.8'
+targetCompatibility = '1.8'
+
+tasks.withType(JavaCompile) {
+    options.encoding = 'UTF-8'
+    options.debug = true
+    options.deprecation = true
+    // options.compilerArgs.addAll('-Xlint:unchecked')
+}
+
+// ----------------------------------------------------------------------------
+// Jar packaging details
+processResources {
+    into('META-INF') {
+        from "$thriftRoot/LICENSE"
+        from "$thriftRoot/NOTICE"
+        rename('(.+)', '$1.txt')
+    }
+}
+
+jar {
+    project.test.dependsOn it
+    manifest {
+        attributes([
+            "Implementation-Version": "${project.version}",
+            "Bundle-ManifestVersion": "2",
+            "Bundle-SymbolicName": "${project.group}",
+            "Bundle-Name": "Apache Thrift",
+            "Bundle-Version": "${project.version}",
+            "Bundle-Description": "Apache Thrift library",
+            "Bundle-License": "${project.license}",
+            "Bundle-ActivationPolicy": "lazy",
+            "Export-Package": "${project.group}.async;uses:=\"${project.group}.protocol,${project.group}.transport,org.slf4j,${project.group}\";version=\"${version}\",${project.group}.protocol;uses:=\"${project.group}.transport,${project.group},${project.group}.scheme\";version=\"${version}\",${project.group}.server;uses:=\"${project.group}.transport,${project.group}.protocol,${project.group},org.slf4j,javax.servlet,javax.servlet.http\";version=\"${version}\",${project.group}.transport;uses:=\"${project.group}.protocol,${project.group},org.apache.http.client,org.apache.http.params,org.apache.http.entity,org.apache.http.client.methods,org.apache.http,org.slf4j,javax.net.ssl,javax.net,javax.security.sasl,javax.security.auth.callback\";version=\"${version}\",${project.group};uses:=\"${project.group}.protocol,${project.group}.async,${project.group}.server,${project.group}.transport,org.slf4j,org.apache.log4j,${project.group}.scheme\";version=\"${version}\",${project.group}.meta_data;uses:=\"${project.group}\";version=\"${version}\",${project.group}.scheme;uses:=\"${project.group}.protocol,${project.group}\";version=\"${version}\"",
+            "Import-Package": "javax.net,javax.net.ssl,javax.security.auth.callback,javax.security.sasl,javax.servlet;resolution:=optional,javax.servlet.http;resolution:=optional,org.slf4j;resolution:=optional;version=\"[1.4,2)\",org.apache.http.client;resolution:=optional,org.apache.http.params;resolution:=optional,org.apache.http.entity;resolution:=optional,org.apache.http.client.methods;resolution:=optional,org.apache.http;resolution:=optional"
+        ])
+    }
+}
diff --git a/lib/java/gradle/unitTests.gradle b/lib/java/gradle/unitTests.gradle
new file mode 100644
index 0000000..61f2fbd
--- /dev/null
+++ b/lib/java/gradle/unitTests.gradle
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+// Following Gradle best practices to keep build logic organized
+
+// Bundle the test classes in a JAR for other Ant based builds
+task testJar(type: Jar, group: 'Build') {
+    description = 'Assembles a jar archive containing the test classes.'
+    project.test.dependsOn it
+
+    classifier 'test'
+    from sourceSets.test.output
+}
+
+// ----------------------------------------------------------------------------
+// Unit test tasks and configurations
+
+// Help the up to date algorithm to make these tests done
+ext.markTaskDone = { task ->
+    def buildFile = file("$buildDir/${task.name}.flag")
+    task.inputs.files task.classpath
+    task.outputs.file buildFile
+    task.doLast {
+        buildFile.text = 'Passed!'
+    }
+}
+
+task deprecatedEqualityTest(type: JavaExec, group: 'Verification') {
+    description = 'Run the non-JUnit test suite '
+    classpath = sourceSets.test.runtimeClasspath
+    main 'org.apache.thrift.test.EqualityTest'
+    markTaskDone(it)
+}
+
+task deprecatedJavaBeansTest(type: JavaExec, group: 'Verification') {
+    description = 'Run the non-JUnit test suite '
+    classpath = sourceSets.test.runtimeClasspath
+    main 'org.apache.thrift.test.JavaBeansTest'
+    markTaskDone(it)
+}
+
+// Main Unit Test task configuration
+test {
+    description="Run the full test suite"
+    dependsOn deprecatedEqualityTest, deprecatedJavaBeansTest
+
+    // Allow repeating tests even after successful execution
+    if (project.hasProperty('rerunTests')) {
+        outputs.upToDateWhen { false }
+    }
+
+    include '**/Test*.class'
+    exclude '**/Test*\$*.class'
+
+    maxHeapSize = '512m'
+    forkEvery = 1
+
+    systemProperties = [
+        'build.test': "${compileTestJava.destinationDir}",
+        'test.port': "${testPort}",
+        'javax.net.ssl.trustStore': "${projectDir}/test/.truststore",
+        'javax.net.ssl.trustStorePassword': 'thrift',
+        'javax.net.ssl.keyStore': "${projectDir}/test/.keystore",
+        'javax.net.ssl.keyStorePassword': 'thrift'
+    ]
+}
diff --git a/lib/java/gradle/wrapper/gradle-wrapper.jar b/lib/java/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..99340b4
--- /dev/null
+++ b/lib/java/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/lib/java/gradle/wrapper/gradle-wrapper.properties b/lib/java/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..2c2bbe5
--- /dev/null
+++ b/lib/java/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-bin.zip
diff --git a/lib/java/gradlew b/lib/java/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/lib/java/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/lib/java/gradlew.bat b/lib/java/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/lib/java/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/lib/java/settings.gradle b/lib/java/settings.gradle
new file mode 100644
index 0000000..c9bd8bc
--- /dev/null
+++ b/lib/java/settings.gradle
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+rootProject.name = 'libthrift'
diff --git a/lib/java/src/org/apache/thrift/AsyncProcessFunction.java b/lib/java/src/org/apache/thrift/AsyncProcessFunction.java
index 799e02d..483c8d0 100644
--- a/lib/java/src/org/apache/thrift/AsyncProcessFunction.java
+++ b/lib/java/src/org/apache/thrift/AsyncProcessFunction.java
@@ -20,11 +20,10 @@
 
 import org.apache.thrift.async.AsyncMethodCallback;
 import org.apache.thrift.protocol.TMessage;
-import org.apache.thrift.protocol.TMessageType;
 import org.apache.thrift.protocol.TProtocol;
 import org.apache.thrift.server.AbstractNonblockingServer;
 
-public abstract class AsyncProcessFunction<I, T, R> {
+public abstract class AsyncProcessFunction<I, T extends TBase, R> {
     final String methodName;
 
     public AsyncProcessFunction(String methodName) {
@@ -37,13 +36,13 @@
 
     public abstract T getEmptyArgsInstance();
 
-    public abstract AsyncMethodCallback getResultHandler(final AbstractNonblockingServer.AsyncFrameBuffer fb, int seqid);
+    public abstract AsyncMethodCallback<R> getResultHandler(final AbstractNonblockingServer.AsyncFrameBuffer fb, int seqid);
 
     public String getMethodName() {
         return methodName;
     }
 
-    public void sendResponse(final AbstractNonblockingServer.AsyncFrameBuffer fb, final TBase result, final byte type, final int seqid) throws TException {
+    public void sendResponse(final AbstractNonblockingServer.AsyncFrameBuffer fb, final TSerializable result, final byte type, final int seqid) throws TException {
         TProtocol oprot = fb.getOutputProtocol();
 
         oprot.writeMessageBegin(new TMessage(getMethodName(), type, seqid));
diff --git a/lib/java/src/org/apache/thrift/Option.java b/lib/java/src/org/apache/thrift/Option.java
new file mode 100644
index 0000000..d5cd309
--- /dev/null
+++ b/lib/java/src/org/apache/thrift/Option.java
@@ -0,0 +1,125 @@
+/*
+ * 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 org.apache.thrift;
+
+/**
+ * Implementation of the Option type pattern
+ */
+public abstract class Option<T> {
+
+    @SuppressWarnings("rawtypes")
+    private static final Option NONE = new None();
+
+    /**
+     * Whether the Option is defined or not
+     * @return
+     *         true if the Option is defined (of type Some)
+     *         false if the Option is not defined (of type None)
+     */
+    public abstract boolean isDefined();
+
+    /**
+     * Get the value of the Option (if it is defined)
+     * @return the value
+     * @throws IllegalStateException if called on a None
+     */
+    public abstract T get();
+
+    /**
+     * Get the contained value (if defined) or else return a default value
+     * @param other what to return if the value is not defined (a None)
+     * @return either the value, or other if the value is not defined
+     */
+    public T or(T other) {
+        if (isDefined()) {
+            return get();
+        } else {
+            return other;
+        }
+    }
+    /**
+     * The None type, representing an absent value (instead of "null")
+     */
+    public static class None<T> extends Option<T> {
+        public boolean isDefined() {
+            return false;
+        }
+
+        public T get() {
+            throw new IllegalStateException("Cannot call get() on None");
+        }
+
+        public String toString() {
+            return "None";
+        }
+    }
+
+    /**
+     * The Some type, representing an existence of some value
+     * @param <T> The type of value
+     */
+    public static class Some<T> extends Option<T> {
+        private final T value;
+        public Some(T value) {
+            this.value = value;
+        }
+
+        public boolean isDefined() {
+            return true;
+        }
+
+        public T get() {
+            return value;
+        }
+
+        public String toString() {
+            return "Some(" + value + ")";
+        }
+    }
+
+    /**
+     * Wraps value in an Option type, depending on whether or not value is null
+     * @param value
+     * @param <T> type of value
+     * @return Some(value) if value is not null, None if value is null
+     */
+    public static <T> Option<T> fromNullable(T value) {
+        if (value != null) {
+            return some(value);
+        } else {
+            return none();
+        }
+    }
+
+    /**
+     * Wrap value in a Some type (NB! value must not be null!)
+     * @param value
+     * @param <T> type of value
+     * @return a new Some(value)
+     */
+    public static <T> Some<T> some(T value) {
+        return new Some<T>(value);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> None<T> none() {
+        return (None<T>) NONE;
+    }
+}
\ No newline at end of file
diff --git a/lib/java/src/org/apache/thrift/ProcessFunction.java b/lib/java/src/org/apache/thrift/ProcessFunction.java
index 19c8f14..e6213df 100644
--- a/lib/java/src/org/apache/thrift/ProcessFunction.java
+++ b/lib/java/src/org/apache/thrift/ProcessFunction.java
@@ -1,12 +1,10 @@
-/**
- * 
- */
 package org.apache.thrift;
 
 import org.apache.thrift.protocol.TMessage;
 import org.apache.thrift.protocol.TMessageType;
 import org.apache.thrift.protocol.TProtocol;
 import org.apache.thrift.protocol.TProtocolException;
+import org.apache.thrift.transport.TTransportException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,27 +31,49 @@
       return;
     }
     iprot.readMessageEnd();
-    TBase result = null;
+    TSerializable result = null;
+    byte msgType = TMessageType.REPLY;
 
     try {
       result = getResult(iface, args);
-    } catch(TException tex) {
-      LOGGER.error("Internal error processing " + getMethodName(), tex);
-      TApplicationException x = new TApplicationException(TApplicationException.INTERNAL_ERROR, 
+    } catch (TTransportException ex) {
+      LOGGER.error("Transport error while processing " + getMethodName(), ex);
+      throw ex;
+    } catch (TApplicationException ex) {
+      LOGGER.error("Internal application error processing " + getMethodName(), ex);
+      result = ex;
+      msgType = TMessageType.EXCEPTION;
+    } catch (Exception ex) {
+      LOGGER.error("Internal error processing " + getMethodName(), ex);
+      if(rethrowUnhandledExceptions()) throw new RuntimeException(ex.getMessage(), ex);
+      if(!isOneway()) {
+        result = new TApplicationException(TApplicationException.INTERNAL_ERROR,
+            "Internal error processing " + getMethodName());
+        msgType = TMessageType.EXCEPTION;
+      }
+    }
+
+    if(!isOneway()) {
+      oprot.writeMessageBegin(new TMessage(getMethodName(), msgType, seqid));
+      result.write(oprot);
+      oprot.writeMessageEnd();
+      oprot.getTransport().flush();
+    }
+  }
+
+  private void handleException(int seqid, TProtocol oprot) throws TException {
+    if (!isOneway()) {
+      TApplicationException x = new TApplicationException(TApplicationException.INTERNAL_ERROR,
         "Internal error processing " + getMethodName());
       oprot.writeMessageBegin(new TMessage(getMethodName(), TMessageType.EXCEPTION, seqid));
       x.write(oprot);
       oprot.writeMessageEnd();
       oprot.getTransport().flush();
-      return;
     }
+  }
 
-    if(!isOneway()) {
-      oprot.writeMessageBegin(new TMessage(getMethodName(), TMessageType.REPLY, seqid));
-      result.write(oprot);
-      oprot.writeMessageEnd();
-      oprot.getTransport().flush();
-    }
+  protected boolean rethrowUnhandledExceptions(){
+    return false;
   }
 
   protected abstract boolean isOneway();
diff --git a/lib/java/src/org/apache/thrift/ShortStack.java b/lib/java/src/org/apache/thrift/ShortStack.java
deleted file mode 100644
index 4957d1c..0000000
--- a/lib/java/src/org/apache/thrift/ShortStack.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.thrift;
-
-/**
- * ShortStack is a short-specific Stack implementation written for the express
- * purpose of very fast operations on TCompactProtocol's field id stack. This
- * implementation performs at least 10x faster than java.util.Stack.
- */
-public class ShortStack {
-
-  private short[] vector;
-  private int top = -1;
-
-  public ShortStack(int initialCapacity) {
-    vector = new short[initialCapacity];
-  }
-
-  public short pop() {
-    return vector[top--];
-  }
-
-  public void push(short pushed) {
-    if (vector.length == top + 1) {
-      grow();
-    }
-    vector[++top] = pushed;
-  }
-
-  private void grow() {
-    short[] newVector = new short[vector.length * 2];
-    System.arraycopy(vector, 0, newVector, 0, vector.length);
-    vector = newVector;
-  }
-
-  public short peek() {
-    return vector[top];
-  }
-
-  public void clear() {
-    top = -1;
-  }
-
-  @Override
-  public String toString() {
-    StringBuilder sb = new StringBuilder();
-    sb.append("<ShortStack vector:[");
-    for (int i = 0; i < vector.length; i++) {
-      if (i != 0) {
-        sb.append(" ");
-      }
-
-      if (i == top) {
-        sb.append(">>");
-      }
-
-      sb.append(vector[i]);
-
-      if (i == top) {
-        sb.append("<<");
-      }
-    }
-    sb.append("]>");
-    return sb.toString();
-  }
-}
diff --git a/lib/java/src/org/apache/thrift/TApplicationException.java b/lib/java/src/org/apache/thrift/TApplicationException.java
index b54a5ce..4d693d9 100644
--- a/lib/java/src/org/apache/thrift/TApplicationException.java
+++ b/lib/java/src/org/apache/thrift/TApplicationException.java
@@ -29,7 +29,7 @@
  * Application level exception
  *
  */
-public class TApplicationException extends TException {
+public class TApplicationException extends TException implements TSerializable {
 
   private static final TStruct TAPPLICATION_EXCEPTION_STRUCT = new TStruct("TApplicationException");
   private static final TField MESSAGE_FIELD = new TField("message", TType.STRING, (short)1);
@@ -50,6 +50,7 @@
   public static final int UNSUPPORTED_CLIENT_TYPE = 10;
 
   protected int type_ = UNKNOWN;
+  private String message_ = null;
 
   public TApplicationException() {
     super();
@@ -73,7 +74,18 @@
     return type_;
   }
 
-  public static TApplicationException read(TProtocol iprot) throws TException {
+  @Override
+  public String getMessage() {
+    if (message_ == null) {
+      return super.getMessage();
+    }
+    else {
+      return message_;
+    }
+  }
+
+  public void read(TProtocol iprot) throws TException
+  {
     TField field;
     iprot.readStructBegin();
 
@@ -86,32 +98,43 @@
         break;
       }
       switch (field.id) {
-      case 1:
-        if (field.type == TType.STRING) {
-          message = iprot.readString();
-        } else {
+        case 1:
+          if (field.type == TType.STRING) {
+            message = iprot.readString();
+          } else {
+            TProtocolUtil.skip(iprot, field.type);
+          }
+          break;
+        case 2:
+          if (field.type == TType.I32) {
+            type = iprot.readI32();
+          } else {
+            TProtocolUtil.skip(iprot, field.type);
+          }
+          break;
+        default:
           TProtocolUtil.skip(iprot, field.type);
-        }
-        break;
-      case 2:
-        if (field.type == TType.I32) {
-          type = iprot.readI32();
-        } else {
-          TProtocolUtil.skip(iprot, field.type);
-        }
-        break;
-      default:
-        TProtocolUtil.skip(iprot, field.type);
-        break;
+          break;
       }
       iprot.readFieldEnd();
     }
     iprot.readStructEnd();
-
-    return new TApplicationException(type, message);
+    type_ = type;
+    message_ = message;
   }
 
-  public void write(TProtocol oprot) throws TException {
+  /**
+   * Convenience factory method for constructing a TApplicationException given a TProtocol input
+   */
+  public static TApplicationException readFrom(TProtocol iprot) throws TException
+  {
+    TApplicationException result = new TApplicationException();
+    result.read(iprot);
+    return result;
+  }
+
+  public void write(TProtocol oprot) throws TException
+  {
     oprot.writeStructBegin(TAPPLICATION_EXCEPTION_STRUCT);
     if (getMessage() != null) {
       oprot.writeFieldBegin(MESSAGE_FIELD);
diff --git a/lib/java/src/org/apache/thrift/TAsyncProcessor.java b/lib/java/src/org/apache/thrift/TAsyncProcessor.java
new file mode 100644
index 0000000..533e74d
--- /dev/null
+++ b/lib/java/src/org/apache/thrift/TAsyncProcessor.java
@@ -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 org.apache.thrift;
+
+import org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer;
+
+public interface TAsyncProcessor {
+    /**
+     * Implementations must call fb.responseReady() once processing is complete
+     */
+    public boolean process(final AsyncFrameBuffer fb) throws TException;
+}
diff --git a/lib/java/src/org/apache/thrift/TBase.java b/lib/java/src/org/apache/thrift/TBase.java
index b3ed1bc..e1489d5 100644
--- a/lib/java/src/org/apache/thrift/TBase.java
+++ b/lib/java/src/org/apache/thrift/TBase.java
@@ -27,21 +27,7 @@
  * Generic base interface for generated Thrift objects.
  *
  */
-public interface TBase<T extends TBase<?,?>, F extends TFieldIdEnum> extends Comparable<T>,  Serializable {
-
-  /**
-   * Reads the TObject from the given input protocol.
-   *
-   * @param iprot Input protocol
-   */
-  public void read(TProtocol iprot) throws TException;
-
-  /**
-   * Writes the objects out to the protocol
-   *
-   * @param oprot Output protocol
-   */
-  public void write(TProtocol oprot) throws TException;
+public interface TBase<T extends TBase<T,F>, F extends TFieldIdEnum> extends Comparable<T>,  TSerializable, Serializable {
 
   /**
    * Get the F instance that corresponds to fieldId.
@@ -56,7 +42,7 @@
   public boolean isSet(F field);
 
   /**
-   * Get a field's value by field variable. Primitive types will be wrapped in 
+   * Get a field's value by field variable. Primitive types will be wrapped in
    * the appropriate "boxed" types.
    *
    * @param field
@@ -71,7 +57,7 @@
    */
   public void setFieldValue(F field, Object value);
 
-  public TBase<T, F> deepCopy();
+  public T deepCopy();
 
   /**
    * Return to the state of having just been initialized, as though you had just
diff --git a/lib/java/src/org/apache/thrift/TBaseAsyncProcessor.java b/lib/java/src/org/apache/thrift/TBaseAsyncProcessor.java
index da41620..0ab1827 100644
--- a/lib/java/src/org/apache/thrift/TBaseAsyncProcessor.java
+++ b/lib/java/src/org/apache/thrift/TBaseAsyncProcessor.java
@@ -19,6 +19,7 @@
 package org.apache.thrift;
 
 import org.apache.thrift.protocol.*;
+import org.apache.thrift.async.AsyncMethodCallback;
 
 import org.apache.thrift.server.AbstractNonblockingServer.*;
 import org.slf4j.Logger;
@@ -27,7 +28,7 @@
 import java.util.Collections;
 import java.util.Map;
 
-public class TBaseAsyncProcessor<I> implements TProcessor {
+public class TBaseAsyncProcessor<I> implements TAsyncProcessor, TProcessor {
     protected final Logger LOGGER = LoggerFactory.getLogger(getClass().getName());
 
     final I iface;
@@ -53,35 +54,57 @@
         if (fn == null) {
             TProtocolUtil.skip(in, TType.STRUCT);
             in.readMessageEnd();
-            TApplicationException x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, "Invalid method name: '"+msg.name+"'");
-            out.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));
-            x.write(out);
-            out.writeMessageEnd();
-            out.getTransport().flush();
+
+            TApplicationException x = new TApplicationException(TApplicationException.UNKNOWN_METHOD,
+                "Invalid method name: '" + msg.name + "'");
+            LOGGER.debug("Invalid method name", x);
+
+            // this means it is a two-way request, so we can send a reply
+            if (msg.type == TMessageType.CALL) {
+              out.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));
+              x.write(out);
+              out.writeMessageEnd();
+              out.getTransport().flush();
+            }
             fb.responseReady();
             return true;
         }
 
         //Get Args
-        TBase args = (TBase)fn.getEmptyArgsInstance();
+        TBase args = fn.getEmptyArgsInstance();
 
         try {
             args.read(in);
         } catch (TProtocolException e) {
             in.readMessageEnd();
-            TApplicationException x = new TApplicationException(TApplicationException.PROTOCOL_ERROR, e.getMessage());
-            out.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));
-            x.write(out);
-            out.writeMessageEnd();
-            out.getTransport().flush();
+
+            TApplicationException x = new TApplicationException(TApplicationException.PROTOCOL_ERROR,
+                e.getMessage());
+            LOGGER.debug("Could not retrieve function arguments", x);
+
+            if (!fn.isOneway()) {
+              out.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));
+              x.write(out);
+              out.writeMessageEnd();
+              out.getTransport().flush();
+            }
             fb.responseReady();
             return true;
         }
         in.readMessageEnd();
 
+        if (fn.isOneway()) {
+          fb.responseReady();
+        }
 
         //start off processing function
-        fn.start(iface, args,fn.getResultHandler(fb,msg.seqid));
+        AsyncMethodCallback resultHandler = fn.getResultHandler(fb, msg.seqid);
+        try {
+          fn.start(iface, args, resultHandler);
+        } catch (Exception e) {
+          LOGGER.debug("Exception handling function", e);
+          resultHandler.onError(e);
+        }
         return true;
     }
 
diff --git a/lib/java/src/org/apache/thrift/TBaseHelper.java b/lib/java/src/org/apache/thrift/TBaseHelper.java
index eec648b..6f6c6eb 100644
--- a/lib/java/src/org/apache/thrift/TBaseHelper.java
+++ b/lib/java/src/org/apache/thrift/TBaseHelper.java
@@ -17,6 +17,7 @@
  */
 package org.apache.thrift;
 
+import java.io.Serializable;
 import java.nio.ByteBuffer;
 import java.util.Comparator;
 import java.util.Iterator;
@@ -24,9 +25,11 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedMap;
-import java.util.SortedSet;
 import java.util.TreeMap;
-import java.util.TreeSet;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 
 public final class TBaseHelper {
 
@@ -51,57 +54,27 @@
   }
 
   public static int compareTo(boolean a, boolean b) {
-    return Boolean.valueOf(a).compareTo(b);
+    return Boolean.compare(a, b);
   }
 
   public static int compareTo(byte a, byte b) {
-    if (a < b) {
-      return -1;
-    } else if (b < a) {
-      return 1;
-    } else {
-      return 0;
-    }
+    return Byte.compare(a, b);
   }
 
   public static int compareTo(short a, short b) {
-    if (a < b) {
-      return -1;
-    } else if (b < a) {
-      return 1;
-    } else {
-      return 0;
-    }
+    return Short.compare(a,b);
   }
 
   public static int compareTo(int a, int b) {
-    if (a < b) {
-      return -1;
-    } else if (b < a) {
-      return 1;
-    } else {
-      return 0;
-    }
+    return Integer.compare(a, b);
   }
 
   public static int compareTo(long a, long b) {
-    if (a < b) {
-      return -1;
-    } else if (b < a) {
-      return 1;
-    } else {
-      return 0;
-    }
+    return Long.compare(a, b);
   }
 
   public static int compareTo(double a, double b) {
-    if (a < b) {
-      return -1;
-    } else if (b < a) {
-      return 1;
-    } else {
-      return 0;
-    }
+    return Double.compare(a, b);
   }
 
   public static int compareTo(String a, String b) {
@@ -109,17 +82,16 @@
   }
 
   public static int compareTo(byte[] a, byte[] b) {
-    int sizeCompare = compareTo(a.length, b.length);
-    if (sizeCompare != 0) {
-      return sizeCompare;
-    }
-    for (int i = 0; i < a.length; i++) {
-      int byteCompare = compareTo(a[i], b[i]);
-      if (byteCompare != 0) {
-        return byteCompare;
+    int compare = compareTo(a.length, b.length);
+    if (compare == 0) {
+      for (int i = 0; i < a.length; i++) {
+        compare = compareTo(a[i], b[i]);
+        if (compare != 0) {
+          break;
+        }
       }
     }
-    return 0;
+    return compare;
   }
 
   public static int compareTo(Comparable a, Comparable b) {
@@ -127,41 +99,39 @@
   }
 
   public static int compareTo(List a, List b) {
-    int lastComparison = compareTo(a.size(), b.size());
-    if (lastComparison != 0) {
-      return lastComparison;
-    }
-    for (int i = 0; i < a.size(); i++) {
-      lastComparison = comparator.compare(a.get(i), b.get(i));
-      if (lastComparison != 0) {
-        return lastComparison;
+    int compare = compareTo(a.size(), b.size());
+    if (compare == 0) {
+      for (int i = 0; i < a.size(); i++) {
+        compare = comparator.compare(a.get(i), b.get(i));
+        if (compare != 0) {
+          break;
+        }
       }
     }
-    return 0;
+    return compare;
   }
 
   public static int compareTo(Set a, Set b) {
-    int lastComparison = compareTo(a.size(), b.size());
-    if (lastComparison != 0) {
-      return lastComparison;
-    }
-    SortedSet sortedA = new TreeSet(comparator);
-    sortedA.addAll(a);
-    SortedSet sortedB = new TreeSet(comparator);
-    sortedB.addAll(b);
+    int compare = compareTo(a.size(), b.size());
+    if (compare == 0) {
+      ArrayList sortedA = new ArrayList(a);
+      ArrayList sortedB = new ArrayList(b);
 
-    Iterator iterA = sortedA.iterator();
-    Iterator iterB = sortedB.iterator();
+      Collections.sort(sortedA, comparator);
+      Collections.sort(sortedB, comparator);
 
-    // Compare each item.
-    while (iterA.hasNext() && iterB.hasNext()) {
-      lastComparison = comparator.compare(iterA.next(), iterB.next());
-      if (lastComparison != 0) {
-        return lastComparison;
+      Iterator iterA = sortedA.iterator();
+      Iterator iterB = sortedB.iterator();
+
+      // Compare each item.
+      while (iterA.hasNext() && iterB.hasNext()) {
+        compare = comparator.compare(iterA.next(), iterB.next());
+        if (compare != 0) {
+          break;
+        }
       }
     }
-
-    return 0;
+    return compare;
   }
 
   public static int compareTo(Map a, Map b) {
@@ -198,7 +168,7 @@
   /**
    * Comparator to compare items inside a structure (e.g. a list, set, or map).
    */
-  private static class NestedStructureComparator implements Comparator {
+  private static class NestedStructureComparator implements Comparator, Serializable {
     public int compare(Object oA, Object oB) {
       if (oA == null && oB == null) {
         return 0;
@@ -220,6 +190,25 @@
     }
   }
 
+  public static void toString(Collection<ByteBuffer> bbs, StringBuilder sb) {
+    Iterator<ByteBuffer> it = bbs.iterator();
+    if (!it.hasNext()) {
+      sb.append("[]");
+    } else {
+      sb.append("[");
+      while (true) {
+        ByteBuffer bb = it.next();
+        org.apache.thrift.TBaseHelper.toString(bb, sb);
+        if (!it.hasNext()) {
+          sb.append("]");
+          return;
+        } else {
+          sb.append(", ");
+        }
+      }
+    }
+  }
+
   public static void toString(ByteBuffer bb, StringBuilder sb) {
     byte[] buf = bb.array();
 
@@ -295,12 +284,14 @@
   }
 
   public static byte[] copyBinary(final byte[] orig) {
-    if (orig == null) {
-      return null;
-    }
+    return (orig == null) ? null : Arrays.copyOf(orig, orig.length);
+  }
 
-    byte[] copy = new byte[orig.length];
-    System.arraycopy(orig, 0, copy, 0, orig.length);
-    return copy;
+  public static int hashCode(long value) {
+    return Long.hashCode(value);
+  }
+
+  public static int hashCode(double value) {
+    return Double.hashCode(value);
   }
 }
diff --git a/lib/java/src/org/apache/thrift/TByteArrayOutputStream.java b/lib/java/src/org/apache/thrift/TByteArrayOutputStream.java
index 9ed83c0..3a2d56c 100644
--- a/lib/java/src/org/apache/thrift/TByteArrayOutputStream.java
+++ b/lib/java/src/org/apache/thrift/TByteArrayOutputStream.java
@@ -20,6 +20,7 @@
 package org.apache.thrift;
 
 import java.io.ByteArrayOutputStream;
+import java.nio.charset.Charset;
 
 /**
  * Class that allows access to the underlying buf without doing deep
@@ -27,19 +28,34 @@
  *
  */
 public class TByteArrayOutputStream extends ByteArrayOutputStream {
+
+  private final int initialSize;
+
   public TByteArrayOutputStream(int size) {
     super(size);
+    this.initialSize = size;
   }
 
   public TByteArrayOutputStream() {
-    super();
+    this(32);
   }
 
   public byte[] get() {
     return buf;
   }
 
+  public void reset() {
+    super.reset();
+    if (buf.length > initialSize) {
+      buf = new byte[initialSize];
+    }
+  }
+
   public int len() {
     return count;
   }
+
+  public String toString(Charset charset) {
+    return new String(buf, 0, count, charset);
+  }
 }
diff --git a/lib/java/src/org/apache/thrift/TDeserializer.java b/lib/java/src/org/apache/thrift/TDeserializer.java
index 803d9c6..d1d3966 100644
--- a/lib/java/src/org/apache/thrift/TDeserializer.java
+++ b/lib/java/src/org/apache/thrift/TDeserializer.java
@@ -64,8 +64,20 @@
    * @param bytes The array to read from
    */
   public void deserialize(TBase base, byte[] bytes) throws TException {
+      deserialize(base, bytes, 0, bytes.length);
+  }
+
+  /**
+   * Deserialize the Thrift object from a byte array.
+   *
+   * @param base The object to read into
+   * @param bytes The array to read from
+   * @param offset The offset into {@code bytes}
+   * @param length The length to read from {@code bytes}
+   */
+  public void deserialize(TBase base, byte[] bytes, int offset, int length) throws TException {
     try {
-      trans_.reset(bytes);
+      trans_.reset(bytes, offset, length);
       base.read(protocol_);
     } finally {
       trans_.clear();
@@ -239,48 +251,31 @@
     try {
       TField field = locateField(bytes, fieldIdPathFirst, fieldIdPathRest);
       if (field != null) {
-        // if this point is reached, iprot will be positioned at the start of the field.
-        switch(ttype){
+        if (ttype == field.type) {
+          // if this point is reached, iprot will be positioned at the start of
+          // the field
+          switch (ttype) {
           case TType.BOOL:
-            if (field.type == TType.BOOL){
-              return protocol_.readBool();
-            }
-            break;
+            return protocol_.readBool();
           case TType.BYTE:
-            if (field.type == TType.BYTE) {
-              return protocol_.readByte();
-            }
-            break;
+            return protocol_.readByte();
           case TType.DOUBLE:
-            if (field.type == TType.DOUBLE) {
-              return protocol_.readDouble();
-            }
-            break;
+            return protocol_.readDouble();
           case TType.I16:
-            if (field.type == TType.I16) {
-              return protocol_.readI16();
-            }
-            break;
+            return protocol_.readI16();
           case TType.I32:
-            if (field.type == TType.I32) {
-              return protocol_.readI32();
-            }
-            break;
+            return protocol_.readI32();
           case TType.I64:
-            if (field.type == TType.I64) {
-              return protocol_.readI64();
-            }
-            break;
+            return protocol_.readI64();
           case TType.STRING:
-            if (field.type == TType.STRING) {
-              return protocol_.readString();
-            }
-            break;
-          case 100: // hack to differentiate between string and binary
-            if (field.type == TType.STRING) {
-              return protocol_.readBinary();
-            }
-            break;
+            return protocol_.readString();
+          default:
+            return null;
+          }
+        }
+        // hack to differentiate between string and binary
+        if (ttype == 100 && field.type == TType.STRING) {
+          return protocol_.readBinary();
         }
       }
       return null;
@@ -295,11 +290,9 @@
   private TField locateField(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException {
     trans_.reset(bytes);
 
-    TFieldIdEnum[] fieldIdPath= new TFieldIdEnum[fieldIdPathRest.length + 1];
+    TFieldIdEnum[] fieldIdPath = new TFieldIdEnum[fieldIdPathRest.length + 1];
     fieldIdPath[0] = fieldIdPathFirst;
-    for (int i = 0; i < fieldIdPathRest.length; i++){
-      fieldIdPath[i + 1] = fieldIdPathRest[i];
-    }
+    System.arraycopy(fieldIdPathRest, 0, fieldIdPath, 1, fieldIdPathRest.length);
 
     // index into field ID path being currently searched for
     int curPathIndex = 0;
diff --git a/lib/java/src/org/apache/thrift/TEnumHelper.java b/lib/java/src/org/apache/thrift/TEnumHelper.java
index c17d661..fbc7787 100644
--- a/lib/java/src/org/apache/thrift/TEnumHelper.java
+++ b/lib/java/src/org/apache/thrift/TEnumHelper.java
@@ -19,7 +19,6 @@
 
 package org.apache.thrift;
 
-import java.lang.InstantiationException;
 import java.lang.NoSuchMethodException;
 import java.lang.IllegalAccessException;
 import java.lang.reflect.InvocationTargetException;
diff --git a/lib/java/src/org/apache/thrift/TMultiplexedProcessor.java b/lib/java/src/org/apache/thrift/TMultiplexedProcessor.java
index dad6155..d0c5603 100644
--- a/lib/java/src/org/apache/thrift/TMultiplexedProcessor.java
+++ b/lib/java/src/org/apache/thrift/TMultiplexedProcessor.java
@@ -52,6 +52,7 @@
 
     private final Map<String,TProcessor> SERVICE_PROCESSOR_MAP
             = new HashMap<String,TProcessor>();
+    private TProcessor defaultProcessor;
 
     /**
      * 'Register' a service with this <code>TMultiplexedProcessor</code>.  This
@@ -60,7 +61,7 @@
      *
      * @param serviceName Name of a service, has to be identical to the name
      * declared in the Thrift IDL, e.g. "WeatherReport".
-     * @param processor Implementation of a service, ususally referred to
+     * @param processor Implementation of a service, usually referred to
      * as "handlers", e.g. WeatherReportHandler implementing WeatherReport.Iface.
      */
     public void registerProcessor(String serviceName, TProcessor processor) {
@@ -68,6 +69,14 @@
     }
 
     /**
+     * Register a service to be called to process queries without service name
+     * @param processor
+     */
+    public void registerDefault(TProcessor processor) {
+        defaultProcessor = processor;
+    }
+
+    /**
      * This implementation of <code>process</code> performs the following steps:
      *
      * <ol>
@@ -77,7 +86,7 @@
      *     <li>Dispatch to the processor, with a decorated instance of TProtocol
      *         that allows readMessageBegin() to return the original TMessage.</li>
      * </ol>
-     *  
+     *
      * @throws TException If the message type is not CALL or ONEWAY, if
      * the service name was not found in the message, or if the service
      * name was not found in the service map.  You called {@link #registerProcessor(String, TProcessor) registerProcessor}
@@ -92,14 +101,16 @@
         TMessage message = iprot.readMessageBegin();
 
         if (message.type != TMessageType.CALL && message.type != TMessageType.ONEWAY) {
-            // TODO Apache Guys - Can the server ever get an EXCEPTION or REPLY?
-            // TODO Should we check for this here?
             throw new TException("This should not have happened!?");
         }
 
         // Extract the service name
         int index = message.name.indexOf(TMultiplexedProtocol.SEPARATOR);
         if (index < 0) {
+          if (defaultProcessor != null) {
+                // Dispatch processing to the stored processor
+                return defaultProcessor.process(new StoredMessageProtocol(iprot, message), oprot);
+          }
             throw new TException("Service name not found in message name: " + message.name + ".  Did you " +
                     "forget to use a TMultiplexProtocol in your client?");
         }
@@ -128,7 +139,7 @@
      *  to allow them to call readMessageBegin() and get a TMessage in exactly
      *  the standard format, without the service name prepended to TMessage.name.
      */
-    private class StoredMessageProtocol extends TProtocolDecorator {
+    private static class StoredMessageProtocol extends TProtocolDecorator {
         TMessage messageBegin;
         public StoredMessageProtocol(TProtocol protocol, TMessage messageBegin) {
             super(protocol);
diff --git a/lib/java/src/org/apache/thrift/TNonblockingMultiFetchClient.java b/lib/java/src/org/apache/thrift/TNonblockingMultiFetchClient.java
old mode 100755
new mode 100644
index efa846c..382d978
--- a/lib/java/src/org/apache/thrift/TNonblockingMultiFetchClient.java
+++ b/lib/java/src/org/apache/thrift/TNonblockingMultiFetchClient.java
@@ -17,7 +17,8 @@
  */
 package org.apache.thrift;
 
-import org.apache.log4j.Logger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.net.InetSocketAddress;
@@ -74,8 +75,10 @@
  *
  */
 public class TNonblockingMultiFetchClient {
-  private static final Logger LOG = Logger.getLogger(
-    TNonblockingMultiFetchClient.class);
+  
+  private static final Logger LOGGER = LoggerFactory.getLogger(
+    TNonblockingMultiFetchClient.class.getName()
+  );
 
   // if the size of the response msg exceeds this limit (in byte), we will
   // not read the msg
@@ -163,15 +166,15 @@
     } catch(InterruptedException ie) {
       // attempt to cancel execution of the task.
       task.cancel(true);
-      LOG.error("interrupted during fetch: "+ie.toString());
+      LOGGER.error("interrupted during fetch: "+ie.toString());
     } catch(ExecutionException ee) {
       // attempt to cancel execution of the task.
       task.cancel(true);
-      LOG.error("exception during fetch: "+ee.toString());
+      LOGGER.error("exception during fetch: "+ee.toString());
     } catch(TimeoutException te) {
       // attempt to cancel execution of the task.  
       task.cancel(true);
-      LOG.error("timeout for fetch: "+te.toString());
+      LOGGER.error("timeout for fetch: "+te.toString());
     }
 
     executor.shutdownNow();
@@ -213,7 +216,7 @@
       try {
         selector = Selector.open();
       } catch (IOException e) {
-        LOG.error("selector opens error: "+e.toString());
+        LOGGER.error("selector opens error: "+e.toString());
         return;
       }
 
@@ -239,7 +242,7 @@
           stats.incNumConnectErrorServers();  
           String err = String.format("set up socket to server %s error: %s",
             server.toString(), e.toString());
-          LOG.error(err);
+          LOGGER.error(err);
           // free resource
           if (s != null) {
             try {s.close();} catch (Exception ex) {}
@@ -261,7 +264,7 @@
         try{
           selector.select();
         } catch (Exception e) {
-          LOG.error("selector selects error: "+e.toString());
+          LOGGER.error("selector selects error: "+e.toString());
           continue;
         }
 
@@ -284,7 +287,7 @@
               String err = String.format("socket %d connects to server %s " +
                 "error: %s",
                 index, servers.get(index).toString(), e.toString());
-              LOG.error(err);
+              LOGGER.error(err);
             }
           }
 
@@ -299,7 +302,7 @@
                 String err = String.format("socket %d writes to server %s " +
                   "error: %s",
                   index, servers.get(index).toString(), e.toString());
-                LOG.error(err);
+                LOGGER.error(err);
               }
             }
           }
@@ -325,7 +328,7 @@
                     String err = String.format("Read an invalid frame size %d"
                       + " from %s. Does the server use TFramedTransport? ",
                       frameSize[index], servers.get(index).toString());
-                    LOG.error(err);
+                    LOGGER.error(err);
                     sChannel.close();
                     continue;
                   }
@@ -340,7 +343,7 @@
                       + " total buffer size would exceed limit %d",
                       frameSize[index], servers.get(index).toString(),
                       maxRecvBufBytesPerServer);
-                    LOG.error(err);                      
+                    LOGGER.error(err);                      
                     sChannel.close();
                     continue;
                   }
@@ -366,7 +369,7 @@
               String err = String.format("socket %d reads from server %s " +
                 "error: %s",
                 index, servers.get(index).toString(), e.toString());
-              LOG.error(err);
+              LOGGER.error(err);
             }
           }
         }
@@ -389,7 +392,7 @@
           selector.close();
         }
       } catch (IOException e) {
-        LOG.error("free resource error: "+e.toString());
+        LOGGER.error("free resource error: "+e.toString());
       }
     }
   }
diff --git a/lib/java/src/org/apache/thrift/TNonblockingMultiFetchStats.java b/lib/java/src/org/apache/thrift/TNonblockingMultiFetchStats.java
old mode 100755
new mode 100644
diff --git a/lib/java/src/org/apache/thrift/TProcessorFactory.java b/lib/java/src/org/apache/thrift/TProcessorFactory.java
index f6dfb14..81933a2 100644
--- a/lib/java/src/org/apache/thrift/TProcessorFactory.java
+++ b/lib/java/src/org/apache/thrift/TProcessorFactory.java
@@ -38,6 +38,6 @@
   }
 
   public boolean isAsyncProcessor() {
-      return processor_ instanceof TBaseAsyncProcessor;
+      return processor_ instanceof TAsyncProcessor;
   }
 }
diff --git a/lib/java/src/org/apache/thrift/TSerializable.java b/lib/java/src/org/apache/thrift/TSerializable.java
new file mode 100644
index 0000000..80002c7
--- /dev/null
+++ b/lib/java/src/org/apache/thrift/TSerializable.java
@@ -0,0 +1,44 @@
+/*
+ * 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 org.apache.thrift;
+
+import org.apache.thrift.protocol.TProtocol;
+
+/**
+ * Generic base interface for generated Thrift objects.
+ *
+ */
+public interface TSerializable {
+
+  /**
+   * Reads the TObject from the given input protocol.
+   *
+   * @param iprot Input protocol
+   */
+  public void read(TProtocol iprot) throws TException;
+
+  /**
+   * Writes the objects out to the protocol
+   *
+   * @param oprot Output protocol
+   */
+  public void write(TProtocol oprot) throws TException;
+
+}
diff --git a/lib/java/src/org/apache/thrift/TServiceClient.java b/lib/java/src/org/apache/thrift/TServiceClient.java
index 15715f1..00a36ee 100644
--- a/lib/java/src/org/apache/thrift/TServiceClient.java
+++ b/lib/java/src/org/apache/thrift/TServiceClient.java
@@ -58,22 +58,32 @@
     return this.oprot_;
   }
 
-  protected void sendBase(String methodName, TBase args) throws TException {
-    oprot_.writeMessageBegin(new TMessage(methodName, TMessageType.CALL, ++seqid_));
+  protected void sendBase(String methodName, TBase<?,?> args) throws TException {
+    sendBase(methodName, args, TMessageType.CALL);
+  }
+
+  protected void sendBaseOneway(String methodName, TBase<?,?> args) throws TException {
+    sendBase(methodName, args, TMessageType.ONEWAY);
+  }
+
+  private void sendBase(String methodName, TBase<?,?> args, byte type) throws TException {
+    oprot_.writeMessageBegin(new TMessage(methodName, type, ++seqid_));
     args.write(oprot_);
     oprot_.writeMessageEnd();
     oprot_.getTransport().flush();
   }
 
-  protected void receiveBase(TBase result, String methodName) throws TException {
+  protected void receiveBase(TBase<?,?> result, String methodName) throws TException {
     TMessage msg = iprot_.readMessageBegin();
     if (msg.type == TMessageType.EXCEPTION) {
-      TApplicationException x = TApplicationException.read(iprot_);
+      TApplicationException x = new TApplicationException();
+      x.read(iprot_);
       iprot_.readMessageEnd();
       throw x;
     }
     if (msg.seqid != seqid_) {
-      throw new TApplicationException(TApplicationException.BAD_SEQUENCE_ID, methodName + " failed: out of sequence response");
+      throw new TApplicationException(TApplicationException.BAD_SEQUENCE_ID,
+          String.format("%s failed: out of sequence response: expected %d but got %d", methodName, seqid_, msg.seqid));
     }
     result.read(iprot_);
     iprot_.readMessageEnd();
diff --git a/lib/java/src/org/apache/thrift/TUnion.java b/lib/java/src/org/apache/thrift/TUnion.java
index 3052ee1..1ef11df 100644
--- a/lib/java/src/org/apache/thrift/TUnion.java
+++ b/lib/java/src/org/apache/thrift/TUnion.java
@@ -34,7 +34,7 @@
 import org.apache.thrift.scheme.StandardScheme;
 import org.apache.thrift.scheme.TupleScheme;
 
-public abstract class TUnion<T extends TUnion<?,?>, F extends TFieldIdEnum> implements TBase<T, F> {
+public abstract class TUnion<T extends TUnion<T,F>, F extends TFieldIdEnum> implements TBase<T, F> {
 
   protected Object value_;
   protected F setField_;
@@ -79,7 +79,7 @@
   }
 
   private static Map deepCopyMap(Map<Object, Object> map) {
-    Map copy = new HashMap();
+    Map copy = new HashMap(map.size());
     for (Map.Entry<Object, Object> entry : map.entrySet()) {
       copy.put(deepCopyObject(entry.getKey()), deepCopyObject(entry.getValue()));
     }
@@ -87,7 +87,7 @@
   }
 
   private static Set deepCopySet(Set set) {
-    Set copy = new HashSet();
+    Set copy = new HashSet(set.size());
     for (Object o : set) {
       copy.add(deepCopyObject(o));
     }
diff --git a/lib/java/src/org/apache/thrift/annotation/Nullable.java b/lib/java/src/org/apache/thrift/annotation/Nullable.java
new file mode 100644
index 0000000..a34b01e
--- /dev/null
+++ b/lib/java/src/org/apache/thrift/annotation/Nullable.java
@@ -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 org.apache.thrift.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Annotation indicating a field, method return, or method parameter may be {@code null}.
+ * We package our own annotation to avoid a mandatory third-party dependency.
+ */
+@Retention(RetentionPolicy.CLASS)
+public @interface Nullable {
+
+}
diff --git a/lib/java/src/org/apache/thrift/async/AsyncMethodCallback.java b/lib/java/src/org/apache/thrift/async/AsyncMethodCallback.java
index 00004b7..4ebde07 100644
--- a/lib/java/src/org/apache/thrift/async/AsyncMethodCallback.java
+++ b/lib/java/src/org/apache/thrift/async/AsyncMethodCallback.java
@@ -18,22 +18,34 @@
  */
 package org.apache.thrift.async;
 
-
+/**
+ * A handler interface asynchronous clients can implement to receive future
+ * notice of the results of an asynchronous method call.
+ *
+ * @param <T> The return type of the asynchronously invoked method.
+ */
 public interface AsyncMethodCallback<T> {
   /**
    * This method will be called when the remote side has completed invoking
-   * your method call and the result is fully read. For oneway method calls,
-   * this method will be called as soon as we have completed writing out the
-   * request.
-   * @param response
+   * your method call and the result is fully read. For {@code oneway} method
+   * calls, this method will be called as soon as we have completed writing out
+   * the request.
+   *
+   * @param response The return value of the asynchronously invoked method;
+   *                 {@code null} for void methods which includes
+   *                 {@code oneway} methods.
    */
-  public void onComplete(T response);
+  void onComplete(T response);
 
   /**
-   * This method will be called when there is an unexpected clientside
-   * exception. This does not include application-defined exceptions that
-   * appear in the IDL, but rather things like IOExceptions.
-   * @param exception
+   * This method will be called when there is either an unexpected client-side
+   * exception like an IOException or else when the remote method raises an
+   * exception, either declared in the IDL or due to an unexpected server-side
+   * error.
+   *
+   * @param exception The exception encountered processing the the asynchronous
+   *                  method call, may be a local exception or an unmarshalled
+   *                  remote exception.
    */
-  public void onError(Exception exception);
+  void onError(Exception exception);
 }
diff --git a/lib/java/src/org/apache/thrift/async/TAsyncClient.java b/lib/java/src/org/apache/thrift/async/TAsyncClient.java
index 9a22717..005018a 100644
--- a/lib/java/src/org/apache/thrift/async/TAsyncClient.java
+++ b/lib/java/src/org/apache/thrift/async/TAsyncClient.java
@@ -66,7 +66,7 @@
 
   /**
    * Get the client's error - returns null if no error
-   * @return Get the client's error. <br /> returns null if no error
+   * @return Get the client's error. <p> returns null if no error
    */
   public Exception getError() {
     return ___error;
diff --git a/lib/java/src/org/apache/thrift/async/TAsyncClientManager.java b/lib/java/src/org/apache/thrift/async/TAsyncClientManager.java
index 98f7194..c07ccd5 100644
--- a/lib/java/src/org/apache/thrift/async/TAsyncClientManager.java
+++ b/lib/java/src/org/apache/thrift/async/TAsyncClientManager.java
@@ -19,6 +19,7 @@
 package org.apache.thrift.async;
 
 import java.io.IOException;
+import java.io.Serializable;
 import java.nio.channels.ClosedSelectorException;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
@@ -116,6 +117,12 @@
           LOGGER.error("Ignoring uncaught exception in SelectThread", exception);
         }
       }
+
+      try {
+        selector.close();
+      } catch (IOException ex) {
+        LOGGER.warn("Could not close selector. This may result in leaked resources!", ex);
+      }
     }
 
     // Transition methods for ready keys
@@ -182,7 +189,7 @@
   }
 
   /** Comparator used in TreeSet */
-  private static class TAsyncMethodCallTimeoutComparator implements Comparator<TAsyncMethodCall> {
+  private static class TAsyncMethodCallTimeoutComparator implements Comparator<TAsyncMethodCall>, Serializable {
     public int compare(TAsyncMethodCall left, TAsyncMethodCall right) {
       if (left.getTimeoutTimestamp() == right.getTimeoutTimestamp()) {
         return (int)(left.getSequenceId() - right.getSequenceId());
diff --git a/lib/java/src/org/apache/thrift/async/TAsyncMethodCall.java b/lib/java/src/org/apache/thrift/async/TAsyncMethodCall.java
index fcd50ea..3bf1747 100644
--- a/lib/java/src/org/apache/thrift/async/TAsyncMethodCall.java
+++ b/lib/java/src/org/apache/thrift/async/TAsyncMethodCall.java
@@ -33,11 +33,15 @@
 import org.apache.thrift.transport.TTransportException;
 
 /**
- * Encapsulates an async method call
+ * Encapsulates an async method call.
+ * <p>
  * Need to generate:
- *   - private void write_args(TProtocol protocol)
- *   - public T getResult() throws <Exception_1>, <Exception_2>, ...
- * @param <T>
+ * <ul>
+ *   <li>protected abstract void write_args(TProtocol protocol)</li>
+ *   <li>protected abstract T getResult() throws &lt;Exception_1&gt;, &lt;Exception_2&gt;, ...</li>
+ * </ul>
+ *
+ * @param <T> The return type of the encapsulated method call.
  */
 public abstract class TAsyncMethodCall<T> {
 
@@ -65,7 +69,8 @@
   private final AsyncMethodCallback<T> callback;
   private final boolean isOneway;
   private long sequenceId;
-  
+  private final long timeout;
+
   private ByteBuffer sizeBuffer;
   private final byte[] sizeBufferArray = new byte[4];
   private ByteBuffer frameBuffer;
@@ -79,6 +84,7 @@
     this.client = client;
     this.isOneway = isOneway;
     this.sequenceId = TAsyncMethodCall.sequenceIdCounter.getAndIncrement();
+    this.timeout = client.getTimeout();
   }
 
   protected State getState() {
@@ -102,15 +108,17 @@
   }
   
   public boolean hasTimeout() {
-    return client.hasTimeout();
+    return timeout > 0;
   }
   
   public long getTimeoutTimestamp() {
-    return client.getTimeout() + startTime;
+    return timeout + startTime;
   }
 
   protected abstract void write_args(TProtocol protocol) throws TException;
 
+  protected abstract T getResult() throws Exception;
+
   /**
    * Initialize buffers.
    * @throws TException if buffer initialization fails
@@ -165,7 +173,7 @@
    * select interests without worrying about concurrency.
    * @param key
    */
-  protected void transition(SelectionKey key) {
+  void transition(SelectionKey key) {
     // Ensure key is valid
     if (!key.isValid()) {
       key.cancel();
@@ -223,8 +231,14 @@
     key.interestOps(0);
     // this ensures that the TAsyncMethod instance doesn't hang around
     key.attach(null);
-    client.onComplete();
-    callback.onComplete((T)this);
+    try {
+      T result = this.getResult();
+      client.onComplete();
+      callback.onComplete(result);
+    } catch (Exception e) {
+      key.cancel();
+      onError(e);
+    }
   }
 
   private void doReadingResponseSize() throws IOException {
diff --git a/lib/java/src/org/apache/thrift/meta_data/FieldMetaData.java b/lib/java/src/org/apache/thrift/meta_data/FieldMetaData.java
index b634291..445f7e4 100644
--- a/lib/java/src/org/apache/thrift/meta_data/FieldMetaData.java
+++ b/lib/java/src/org/apache/thrift/meta_data/FieldMetaData.java
@@ -45,7 +45,7 @@
     this.valueMetaData = vMetaData;
   }
   
-  public static void addStructMetaDataMap(Class<? extends TBase> sClass, Map<? extends TFieldIdEnum, FieldMetaData> map){
+  public static synchronized void addStructMetaDataMap(Class<? extends TBase> sClass, Map<? extends TFieldIdEnum, FieldMetaData> map){
     structMap.put(sClass, map);
   }
 
@@ -55,7 +55,7 @@
    *
    * @param sClass The TBase class for which the metadata map is requested
    */
-  public static Map<? extends TFieldIdEnum, FieldMetaData> getStructMetaDataMap(Class<? extends TBase> sClass){
+  public static synchronized Map<? extends TFieldIdEnum, FieldMetaData> getStructMetaDataMap(Class<? extends TBase> sClass){
     if (!structMap.containsKey(sClass)){ // Load class if it hasn't been loaded
       try{
         sClass.newInstance();
diff --git a/lib/java/src/org/apache/thrift/protocol/ShortStack.java b/lib/java/src/org/apache/thrift/protocol/ShortStack.java
new file mode 100644
index 0000000..9e65930
--- /dev/null
+++ b/lib/java/src/org/apache/thrift/protocol/ShortStack.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.thrift.protocol;
+
+import java.util.Arrays;
+
+/**
+ * ShortStack is a short-specific Stack implementation written for the express
+ * purpose of very fast operations on TCompactProtocol's field id stack. This
+ * implementation performs at least 10x faster than java.util.Stack.
+ */
+class ShortStack {
+
+  private short[] vector;
+
+  /** Always points to the next location */
+  private int top = 0;
+
+  public ShortStack(int initialCapacity) {
+    vector = new short[initialCapacity];
+  }
+
+  public short pop() {
+    return vector[--top];
+  }
+
+  public void push(short pushed) {
+    if (vector.length == top) {
+      grow();
+    }
+    vector[top++] = pushed;
+  }
+
+  private void grow() {
+    vector = Arrays.copyOf(vector, vector.length << 1);
+  }
+
+  public void clear() {
+    top = 0;
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("<ShortStack vector:[");
+    for (int i = 0; i < vector.length; i++) {
+      boolean isTop = (i == (top - 1));
+      short value = vector[i];
+      if (i != 0) {
+        sb.append(' ');
+      }
+      if (isTop) {
+        sb.append(">>").append(value).append("<<");
+      } else {
+        sb.append(value);
+      }
+    }
+    sb.append("]>");
+    return sb.toString();
+  }
+}
diff --git a/lib/java/src/org/apache/thrift/protocol/TBinaryProtocol.java b/lib/java/src/org/apache/thrift/protocol/TBinaryProtocol.java
index 32a761f..7924e2f 100644
--- a/lib/java/src/org/apache/thrift/protocol/TBinaryProtocol.java
+++ b/lib/java/src/org/apache/thrift/protocol/TBinaryProtocol.java
@@ -19,8 +19,8 @@
 
 package org.apache.thrift.protocol;
 
-import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
 
 import org.apache.thrift.TException;
 import org.apache.thrift.transport.TTransport;
@@ -31,31 +31,59 @@
  */
 public class TBinaryProtocol extends TProtocol {
   private static final TStruct ANONYMOUS_STRUCT = new TStruct();
+  private static final long NO_LENGTH_LIMIT = -1;
 
   protected static final int VERSION_MASK = 0xffff0000;
   protected static final int VERSION_1 = 0x80010000;
 
-  protected boolean strictRead_ = false;
-  protected boolean strictWrite_ = true;
+  /**
+   * The maximum number of bytes to read from the transport for
+   * variable-length fields (such as strings or binary) or {@link #NO_LENGTH_LIMIT} for
+   * unlimited.
+   */
+  private final long stringLengthLimit_;
+
+  /**
+   * The maximum number of elements to read from the network for
+   * containers (maps, sets, lists), or {@link #NO_LENGTH_LIMIT} for unlimited.
+   */
+  private final long containerLengthLimit_;
+
+  protected boolean strictRead_;
+  protected boolean strictWrite_;
+
+  private final byte[] inoutTemp = new byte[8];
 
   /**
    * Factory
    */
   public static class Factory implements TProtocolFactory {
-    protected boolean strictRead_ = false;
-    protected boolean strictWrite_ = true;
+    protected long stringLengthLimit_;
+    protected long containerLengthLimit_;
+    protected boolean strictRead_;
+    protected boolean strictWrite_;
 
     public Factory() {
       this(false, true);
     }
 
     public Factory(boolean strictRead, boolean strictWrite) {
+      this(strictRead, strictWrite, NO_LENGTH_LIMIT, NO_LENGTH_LIMIT);
+    }
+
+    public Factory(long stringLengthLimit, long containerLengthLimit) {
+      this(false, true, stringLengthLimit, containerLengthLimit);
+    }
+
+    public Factory(boolean strictRead, boolean strictWrite, long stringLengthLimit, long containerLengthLimit) {
+      stringLengthLimit_ = stringLengthLimit;
+      containerLengthLimit_ = containerLengthLimit;
       strictRead_ = strictRead;
       strictWrite_ = strictWrite;
     }
 
     public TProtocol getProtocol(TTransport trans) {
-      return new TBinaryProtocol(trans, strictRead_, strictWrite_);
+      return new TBinaryProtocol(trans, stringLengthLimit_, containerLengthLimit_, strictRead_, strictWrite_);
     }
   }
 
@@ -67,11 +95,22 @@
   }
 
   public TBinaryProtocol(TTransport trans, boolean strictRead, boolean strictWrite) {
+    this(trans, NO_LENGTH_LIMIT, NO_LENGTH_LIMIT, strictRead, strictWrite);
+  }
+
+  public TBinaryProtocol(TTransport trans, long stringLengthLimit, long containerLengthLimit) {
+    this(trans, stringLengthLimit, containerLengthLimit, false, true);
+  }
+
+  public TBinaryProtocol(TTransport trans, long stringLengthLimit, long containerLengthLimit, boolean strictRead, boolean strictWrite) {
     super(trans);
+    stringLengthLimit_ = stringLengthLimit;
+    containerLengthLimit_ = containerLengthLimit;
     strictRead_ = strictRead;
     strictWrite_ = strictWrite;
   }
 
+  @Override
   public void writeMessageBegin(TMessage message) throws TException {
     if (strictWrite_) {
       int version = VERSION_1 | message.type;
@@ -85,98 +124,110 @@
     }
   }
 
-  public void writeMessageEnd() {}
+  @Override
+  public void writeMessageEnd() throws TException {}
 
-  public void writeStructBegin(TStruct struct) {}
+  @Override
+  public void writeStructBegin(TStruct struct) throws TException {}
 
-  public void writeStructEnd() {}
+  @Override
+  public void writeStructEnd() throws TException {}
 
+  @Override
   public void writeFieldBegin(TField field) throws TException {
     writeByte(field.type);
     writeI16(field.id);
   }
 
-  public void writeFieldEnd() {}
+  @Override
+  public void writeFieldEnd() throws TException {}
 
+  @Override
   public void writeFieldStop() throws TException {
     writeByte(TType.STOP);
   }
 
+  @Override
   public void writeMapBegin(TMap map) throws TException {
     writeByte(map.keyType);
     writeByte(map.valueType);
     writeI32(map.size);
   }
 
-  public void writeMapEnd() {}
+  @Override
+  public void writeMapEnd() throws TException {}
 
+  @Override
   public void writeListBegin(TList list) throws TException {
     writeByte(list.elemType);
     writeI32(list.size);
   }
 
-  public void writeListEnd() {}
+  @Override
+  public void writeListEnd() throws TException {}
 
+  @Override
   public void writeSetBegin(TSet set) throws TException {
     writeByte(set.elemType);
     writeI32(set.size);
   }
 
-  public void writeSetEnd() {}
+  @Override
+  public void writeSetEnd() throws TException {}
 
+  @Override
   public void writeBool(boolean b) throws TException {
     writeByte(b ? (byte)1 : (byte)0);
   }
 
-  private byte [] bout = new byte[1];
+  @Override
   public void writeByte(byte b) throws TException {
-    bout[0] = b;
-    trans_.write(bout, 0, 1);
+    inoutTemp[0] = b;
+    trans_.write(inoutTemp, 0, 1);
   }
 
-  private byte[] i16out = new byte[2];
+  @Override
   public void writeI16(short i16) throws TException {
-    i16out[0] = (byte)(0xff & (i16 >> 8));
-    i16out[1] = (byte)(0xff & (i16));
-    trans_.write(i16out, 0, 2);
+    inoutTemp[0] = (byte)(0xff & (i16 >> 8));
+    inoutTemp[1] = (byte)(0xff & (i16));
+    trans_.write(inoutTemp, 0, 2);
   }
 
-  private byte[] i32out = new byte[4];
+  @Override
   public void writeI32(int i32) throws TException {
-    i32out[0] = (byte)(0xff & (i32 >> 24));
-    i32out[1] = (byte)(0xff & (i32 >> 16));
-    i32out[2] = (byte)(0xff & (i32 >> 8));
-    i32out[3] = (byte)(0xff & (i32));
-    trans_.write(i32out, 0, 4);
+    inoutTemp[0] = (byte)(0xff & (i32 >> 24));
+    inoutTemp[1] = (byte)(0xff & (i32 >> 16));
+    inoutTemp[2] = (byte)(0xff & (i32 >> 8));
+    inoutTemp[3] = (byte)(0xff & (i32));
+    trans_.write(inoutTemp, 0, 4);
   }
 
-  private byte[] i64out = new byte[8];
+  @Override
   public void writeI64(long i64) throws TException {
-    i64out[0] = (byte)(0xff & (i64 >> 56));
-    i64out[1] = (byte)(0xff & (i64 >> 48));
-    i64out[2] = (byte)(0xff & (i64 >> 40));
-    i64out[3] = (byte)(0xff & (i64 >> 32));
-    i64out[4] = (byte)(0xff & (i64 >> 24));
-    i64out[5] = (byte)(0xff & (i64 >> 16));
-    i64out[6] = (byte)(0xff & (i64 >> 8));
-    i64out[7] = (byte)(0xff & (i64));
-    trans_.write(i64out, 0, 8);
+    inoutTemp[0] = (byte)(0xff & (i64 >> 56));
+    inoutTemp[1] = (byte)(0xff & (i64 >> 48));
+    inoutTemp[2] = (byte)(0xff & (i64 >> 40));
+    inoutTemp[3] = (byte)(0xff & (i64 >> 32));
+    inoutTemp[4] = (byte)(0xff & (i64 >> 24));
+    inoutTemp[5] = (byte)(0xff & (i64 >> 16));
+    inoutTemp[6] = (byte)(0xff & (i64 >> 8));
+    inoutTemp[7] = (byte)(0xff & (i64));
+    trans_.write(inoutTemp, 0, 8);
   }
 
+  @Override
   public void writeDouble(double dub) throws TException {
     writeI64(Double.doubleToLongBits(dub));
   }
 
+  @Override
   public void writeString(String str) throws TException {
-    try {
-      byte[] dat = str.getBytes("UTF-8");
-      writeI32(dat.length);
-      trans_.write(dat, 0, dat.length);
-    } catch (UnsupportedEncodingException uex) {
-      throw new TException("JVM DOES NOT SUPPORT UTF-8");
-    }
+    byte[] dat = str.getBytes(StandardCharsets.UTF_8);
+    writeI32(dat.length);
+    trans_.write(dat, 0, dat.length);
   }
 
+  @Override
   public void writeBinary(ByteBuffer bin) throws TException {
     int length = bin.limit() - bin.position();
     writeI32(length);
@@ -187,6 +238,7 @@
    * Reading methods.
    */
 
+  @Override
   public TMessage readMessageBegin() throws TException {
     int size = readI32();
     if (size < 0) {
@@ -203,58 +255,76 @@
     }
   }
 
-  public void readMessageEnd() {}
+  @Override
+  public void readMessageEnd() throws TException {}
 
-  public TStruct readStructBegin() {
+  @Override
+  public TStruct readStructBegin() throws TException {
     return ANONYMOUS_STRUCT;
   }
 
-  public void readStructEnd() {}
+  @Override
+  public void readStructEnd() throws TException {}
 
+  @Override
   public TField readFieldBegin() throws TException {
     byte type = readByte();
     short id = type == TType.STOP ? 0 : readI16();
     return new TField("", type, id);
   }
 
-  public void readFieldEnd() {}
+  @Override
+  public void readFieldEnd() throws TException {}
 
+  @Override
   public TMap readMapBegin() throws TException {
-    return new TMap(readByte(), readByte(), readI32());
+    TMap map = new TMap(readByte(), readByte(), readI32());
+    checkContainerReadLength(map.size);
+    return map;
   }
 
-  public void readMapEnd() {}
+  @Override
+  public void readMapEnd() throws TException {}
 
+  @Override
   public TList readListBegin() throws TException {
-    return new TList(readByte(), readI32());
+    TList list = new TList(readByte(), readI32());
+    checkContainerReadLength(list.size);
+    return list;
   }
 
-  public void readListEnd() {}
+  @Override
+  public void readListEnd() throws TException {}
 
+  @Override
   public TSet readSetBegin() throws TException {
-    return new TSet(readByte(), readI32());
+    TSet set = new TSet(readByte(), readI32());
+    checkContainerReadLength(set.size);
+    return set;
   }
 
-  public void readSetEnd() {}
+  @Override
+  public void readSetEnd() throws TException {}
 
+  @Override
   public boolean readBool() throws TException {
     return (readByte() == 1);
   }
 
-  private byte[] bin = new byte[1];
+  @Override
   public byte readByte() throws TException {
     if (trans_.getBytesRemainingInBuffer() >= 1) {
       byte b = trans_.getBuffer()[trans_.getBufferPosition()];
       trans_.consumeBuffer(1);
       return b;
     }
-    readAll(bin, 0, 1);
-    return bin[0];
+    readAll(inoutTemp, 0, 1);
+    return inoutTemp[0];
   }
 
-  private byte[] i16rd = new byte[2];
+  @Override
   public short readI16() throws TException {
-    byte[] buf = i16rd;
+    byte[] buf = inoutTemp;
     int off = 0;
 
     if (trans_.getBytesRemainingInBuffer() >= 2) {
@@ -262,7 +332,7 @@
       off = trans_.getBufferPosition();
       trans_.consumeBuffer(2);
     } else {
-      readAll(i16rd, 0, 2);
+      readAll(inoutTemp, 0, 2);
     }
 
     return
@@ -271,9 +341,9 @@
        ((buf[off+1] & 0xff)));
   }
 
-  private byte[] i32rd = new byte[4];
+  @Override
   public int readI32() throws TException {
-    byte[] buf = i32rd;
+    byte[] buf = inoutTemp;
     int off = 0;
 
     if (trans_.getBytesRemainingInBuffer() >= 4) {
@@ -281,7 +351,7 @@
       off = trans_.getBufferPosition();
       trans_.consumeBuffer(4);
     } else {
-      readAll(i32rd, 0, 4);
+      readAll(inoutTemp, 0, 4);
     }
     return
       ((buf[off] & 0xff) << 24) |
@@ -290,9 +360,9 @@
       ((buf[off+3] & 0xff));
   }
 
-  private byte[] i64rd = new byte[8];
+  @Override
   public long readI64() throws TException {
-    byte[] buf = i64rd;
+    byte[] buf = inoutTemp;
     int off = 0;
 
     if (trans_.getBytesRemainingInBuffer() >= 8) {
@@ -300,7 +370,7 @@
       off = trans_.getBufferPosition();
       trans_.consumeBuffer(8);
     } else {
-      readAll(i64rd, 0, 8);
+      readAll(inoutTemp, 0, 8);
     }
 
     return
@@ -314,39 +384,40 @@
       ((long)(buf[off+7] & 0xff));
   }
 
+  @Override
   public double readDouble() throws TException {
     return Double.longBitsToDouble(readI64());
   }
 
+  @Override
   public String readString() throws TException {
     int size = readI32();
 
+    checkStringReadLength(size);
+
     if (trans_.getBytesRemainingInBuffer() >= size) {
-      try {
-        String s = new String(trans_.getBuffer(), trans_.getBufferPosition(), size, "UTF-8");
-        trans_.consumeBuffer(size);
-        return s;
-      } catch (UnsupportedEncodingException e) {
-        throw new TException("JVM DOES NOT SUPPORT UTF-8");
-      }
+      String s = new String(trans_.getBuffer(), trans_.getBufferPosition(),
+          size, StandardCharsets.UTF_8);
+      trans_.consumeBuffer(size);
+      return s;
     }
 
     return readStringBody(size);
   }
 
   public String readStringBody(int size) throws TException {
-    try {
-      byte[] buf = new byte[size];
-      trans_.readAll(buf, 0, size);
-      return new String(buf, "UTF-8");
-    } catch (UnsupportedEncodingException uex) {
-      throw new TException("JVM DOES NOT SUPPORT UTF-8");
-    }
+    checkStringReadLength(size);
+    byte[] buf = new byte[size];
+    trans_.readAll(buf, 0, size);
+    return new String(buf, StandardCharsets.UTF_8);
   }
 
+  @Override
   public ByteBuffer readBinary() throws TException {
     int size = readI32();
 
+    checkStringReadLength(size);
+
     if (trans_.getBytesRemainingInBuffer() >= size) {
       ByteBuffer bb = ByteBuffer.wrap(trans_.getBuffer(), trans_.getBufferPosition(), size);
       trans_.consumeBuffer(size);
@@ -358,6 +429,28 @@
     return ByteBuffer.wrap(buf);
   }
 
+  private void checkStringReadLength(int length) throws TProtocolException {
+    if (length < 0) {
+      throw new TProtocolException(TProtocolException.NEGATIVE_SIZE,
+                                   "Negative length: " + length);
+    }
+    if (stringLengthLimit_ != NO_LENGTH_LIMIT && length > stringLengthLimit_) {
+      throw new TProtocolException(TProtocolException.SIZE_LIMIT,
+                                   "Length exceeded max allowed: " + length);
+    }
+  }
+
+  private void checkContainerReadLength(int length) throws TProtocolException {
+    if (length < 0) {
+      throw new TProtocolException(TProtocolException.NEGATIVE_SIZE,
+                                   "Negative length: " + length);
+    }
+    if (containerLengthLimit_ != NO_LENGTH_LIMIT && length > containerLengthLimit_) {
+      throw new TProtocolException(TProtocolException.SIZE_LIMIT,
+                                   "Length exceeded max allowed: " + length);
+    }
+  }
+
   private int readAll(byte[] buf, int off, int len) throws TException {
     return trans_.readAll(buf, off, len);
   }
diff --git a/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java b/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java
index 7b273c5..ee05869 100644
--- a/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java
+++ b/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java
@@ -22,21 +22,25 @@
 
 import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
 
-import org.apache.thrift.ShortStack;
 import org.apache.thrift.TException;
 import org.apache.thrift.transport.TTransport;
 
 /**
  * TCompactProtocol2 is the Java implementation of the compact protocol specified
- * in THRIFT-110. The fundamental approach to reducing the overhead of 
+ * in THRIFT-110. The fundamental approach to reducing the overhead of
  * structures is a) use variable-length integers all over the place and b) make
- * use of unused bits wherever possible. Your savings will obviously vary 
- * based on the specific makeup of your structs, but in general, the more 
+ * use of unused bits wherever possible. Your savings will obviously vary
+ * based on the specific makeup of your structs, but in general, the more
  * fields, nested structures, short strings and collections, and low-value i32
  * and i64 fields you have, the more benefit you'll see.
  */
 public class TCompactProtocol extends TProtocol {
+  private final static byte[] EMPTY_BYTES = new byte[0];
+  private final static ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap(EMPTY_BYTES);
+
+  private final static long NO_LENGTH_LIMIT = -1;
 
   private final static TStruct ANONYMOUS_STRUCT = new TStruct("");
   private final static TField TSTOP = new TField("", TType.STOP, (short)0);
@@ -62,18 +66,24 @@
    * TProtocolFactory that produces TCompactProtocols.
    */
   public static class Factory implements TProtocolFactory {
-    private final long maxNetworkBytes_;
+    private final long stringLengthLimit_;
+    private final long containerLengthLimit_;
 
     public Factory() {
-      maxNetworkBytes_ = -1;
+      this(NO_LENGTH_LIMIT, NO_LENGTH_LIMIT);
     }
 
-    public Factory(int maxNetworkBytes) {
-      maxNetworkBytes_ = maxNetworkBytes;
+    public Factory(long stringLengthLimit) {
+      this(stringLengthLimit, NO_LENGTH_LIMIT);
+    }
+
+    public Factory(long stringLengthLimit, long containerLengthLimit) {
+      this.containerLengthLimit_ = containerLengthLimit;
+      this.stringLengthLimit_ = stringLengthLimit;
     }
 
     public TProtocol getProtocol(TTransport trans) {
-      return new TCompactProtocol(trans, maxNetworkBytes_);
+      return new TCompactProtocol(trans, stringLengthLimit_, containerLengthLimit_);
     }
   }
 
@@ -81,6 +91,7 @@
   private static final byte VERSION = 1;
   private static final byte VERSION_MASK = 0x1f; // 0001 1111
   private static final byte TYPE_MASK = (byte)0xE0; // 1110 0000
+  private static final byte TYPE_BITS = 0x07; // 0000 0111
   private static final int  TYPE_SHIFT_AMOUNT = 5;
 
   /**
@@ -101,7 +112,7 @@
     public static final byte STRUCT         = 0x0C;
   }
 
-  /** 
+  /**
    * Used to keep track of the last field for the current and previous structs,
    * so we can do the delta stuff.
    */
@@ -110,34 +121,62 @@
   private short lastFieldId_ = 0;
 
   /**
-   * If we encounter a boolean field begin, save the TField here so it can 
+   * If we encounter a boolean field begin, save the TField here so it can
    * have the value incorporated.
    */
   private TField booleanField_ = null;
 
   /**
-   * If we read a field header, and it's a boolean field, save the boolean 
+   * If we read a field header, and it's a boolean field, save the boolean
    * value here so that readBool can use it.
    */
   private Boolean boolValue_ = null;
 
   /**
-   * The maximum number of bytes to read from the network for
-   * variable-length fields (such as strings or binary) or -1 for
+   * The maximum number of bytes to read from the transport for
+   * variable-length fields (such as strings or binary) or {@link #NO_LENGTH_LIMIT} for
    * unlimited.
    */
-  private final long maxNetworkBytes_;
+  private final long stringLengthLimit_;
+
+  /**
+   * The maximum number of elements to read from the network for
+   * containers (maps, sets, lists), or {@link #NO_LENGTH_LIMIT} for unlimited.
+   */
+  private final long containerLengthLimit_;
+
+  /**
+   * Temporary buffer used for various operations that would otherwise require a
+   * small allocation.
+   */
+  private final byte[] temp = new byte[10];
 
   /**
    * Create a TCompactProtocol.
    *
    * @param transport the TTransport object to read from or write to.
-   * @param maxNetworkBytes the maximum number of bytes to read for
+   * @param stringLengthLimit the maximum number of bytes to read for
    *     variable-length fields.
+   * @param containerLengthLimit the maximum number of elements to read
+   *     for containers.
    */
-  public TCompactProtocol(TTransport transport, long maxNetworkBytes) {
+  public TCompactProtocol(TTransport transport, long stringLengthLimit, long containerLengthLimit) {
     super(transport);
-    maxNetworkBytes_ = maxNetworkBytes;
+    this.stringLengthLimit_ = stringLengthLimit;
+    this.containerLengthLimit_ = containerLengthLimit;
+  }
+
+  /**
+   * Create a TCompactProtocol.
+   *
+   * @param transport the TTransport object to read from or write to.
+   * @param stringLengthLimit the maximum number of bytes to read for
+   *     variable-length fields.
+   * @deprecated Use constructor specifying both string limit and container limit instead
+   */
+  @Deprecated
+  public TCompactProtocol(TTransport transport, long stringLengthLimit) {
+    this(transport, stringLengthLimit, NO_LENGTH_LIMIT);
   }
 
   /**
@@ -146,7 +185,7 @@
    * @param transport the TTransport object to read from or write to.
    */
   public TCompactProtocol(TTransport transport) {
-    this(transport, -1);
+    this(transport, NO_LENGTH_LIMIT, NO_LENGTH_LIMIT);
   }
 
   @Override
@@ -163,6 +202,7 @@
    * 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.
    */
+  @Override
   public void writeMessageBegin(TMessage message) throws TException {
     writeByteDirect(PROTOCOL_ID);
     writeByteDirect((VERSION & VERSION_MASK) | ((message.type << TYPE_SHIFT_AMOUNT) & TYPE_MASK));
@@ -171,10 +211,11 @@
   }
 
   /**
-   * Write a struct begin. This doesn't actually put anything on the wire. We 
+   * 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.
    */
+  @Override
   public void writeStructBegin(TStruct struct) throws TException {
     lastField_.push(lastFieldId_);
     lastFieldId_ = 0;
@@ -191,10 +232,10 @@
 
   /**
    * Write a field header containing the field id and field type. If the
-   * difference between the current field id and the last one is small (< 15),
+   * difference between the current field id and the last one is small (&lt; 15),
    * then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
    * field id will follow the type header as a zigzag varint.
-   */ 
+   */
   public void writeFieldBegin(TField field) throws TException {
     if (field.type == TType.BOOL) {
       // we want to possibly include the value, so we'll wait.
@@ -205,8 +246,8 @@
   }
 
   /**
-   * The workhorse of writeFieldBegin. It has the option of doing a 
-   * 'type override' of the type header. This is used specifically in the 
+   * 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.
    */
   private void writeFieldBeginInternal(TField field, byte typeOverride) throws TException {
@@ -237,7 +278,7 @@
   }
 
   /**
-   * Write a map header. If the map is empty, omit the key and value type 
+   * Write a map header. If the map is empty, omit the key and value type
    * headers, as we don't need any additional information to skip it.
    */
   public void writeMapBegin(TMap map) throws TException {
@@ -248,8 +289,8 @@
       writeByteDirect(getCompactType(map.keyType) << 4 | getCompactType(map.valueType));
     }
   }
-  
-  /** 
+
+  /**
    * Write a list header.
    */
   public void writeListBegin(TList list) throws TException {
@@ -264,9 +305,9 @@
   }
 
   /**
-   * Write a boolean value. Potentially, this could be a boolean field, in 
+   * Write a boolean value. Potentially, this could be a boolean field, in
    * which case the field header info isn't written yet. If so, decide what the
-   * right type header is for the value and then write the field header. 
+   * right type header is for the value and then write the field header.
    * Otherwise, write a single byte.
    */
   public void writeBool(boolean b) throws TException {
@@ -280,7 +321,7 @@
     }
   }
 
-  /** 
+  /**
    * Write a byte. Nothing to see here!
    */
   public void writeByte(byte b) throws TException {
@@ -310,27 +351,22 @@
 
   /**
    * Write a double to the wire as 8 bytes.
-   */ 
+   */
   public void writeDouble(double dub) throws TException {
-    byte[] data = new byte[]{0, 0, 0, 0, 0, 0, 0, 0};
-    fixedLongToBytes(Double.doubleToLongBits(dub), data, 0);
-    trans_.write(data);
+    fixedLongToBytes(Double.doubleToLongBits(dub), temp, 0);
+    trans_.write(temp, 0, 8);
   }
 
   /**
    * Write a string to the wire with a varint size preceding.
    */
   public void writeString(String str) throws TException {
-    try {
-      byte[] bytes = str.getBytes("UTF-8");
-      writeBinary(bytes, 0, bytes.length);
-    } catch (UnsupportedEncodingException e) {
-      throw new TException("UTF-8 not supported!");
-    }
+    byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
+    writeBinary(bytes, 0, bytes.length);
   }
 
   /**
-   * Write a byte array, using a varint for the size. 
+   * Write a byte array, using a varint for the size.
    */
   public void writeBinary(ByteBuffer bin) throws TException {
     int length = bin.limit() - bin.position();
@@ -343,9 +379,9 @@
   }
 
   //
-  // These methods are called by structs, but don't actually have any wire 
+  // These methods are called by structs, but don't actually have any wire
   // output or purpose.
-  // 
+  //
 
   public void writeMessageEnd() throws TException {}
   public void writeMapEnd() throws TException {}
@@ -358,7 +394,7 @@
   //
 
   /**
-   * Abstract method for writing the start of lists and sets. List and sets on 
+   * Abstract method for writing the start of lists and sets. List and sets on
    * the wire differ only by the type indicator.
    */
   protected void writeCollectionBegin(byte elemType, int size) throws TException {
@@ -374,44 +410,42 @@
    * Write an i32 as a varint. Results in 1-5 bytes on the wire.
    * TODO: make a permanent buffer like writeVarint64?
    */
-  byte[] i32buf = new byte[5];
   private void writeVarint32(int n) throws TException {
     int idx = 0;
     while (true) {
       if ((n & ~0x7F) == 0) {
-        i32buf[idx++] = (byte)n;
+        temp[idx++] = (byte)n;
         // writeByteDirect((byte)n);
         break;
         // return;
       } else {
-        i32buf[idx++] = (byte)((n & 0x7F) | 0x80);
+        temp[idx++] = (byte)((n & 0x7F) | 0x80);
         // writeByteDirect((byte)((n & 0x7F) | 0x80));
         n >>>= 7;
       }
     }
-    trans_.write(i32buf, 0, idx);
+    trans_.write(temp, 0, idx);
   }
 
   /**
    * Write an i64 as a varint. Results in 1-10 bytes on the wire.
    */
-  byte[] varint64out = new byte[10];
   private void writeVarint64(long n) throws TException {
     int idx = 0;
     while (true) {
       if ((n & ~0x7FL) == 0) {
-        varint64out[idx++] = (byte)n;
+        temp[idx++] = (byte)n;
         break;
       } else {
-        varint64out[idx++] = ((byte)((n & 0x7F) | 0x80));
+        temp[idx++] = ((byte)((n & 0x7F) | 0x80));
         n >>>= 7;
       }
     }
-    trans_.write(varint64out, 0, idx);
+    trans_.write(temp, 0, idx);
   }
 
   /**
-   * Convert l into a zigzag long. This allows negative numbers to be 
+   * Convert l into a zigzag long. This allows negative numbers to be
    * represented compactly as a varint.
    */
   private long longToZigzag(long l) {
@@ -419,7 +453,7 @@
   }
 
   /**
-   * Convert n into a zigzag int. This allows negative numbers to be 
+   * Convert n into a zigzag int. This allows negative numbers to be
    * represented compactly as a varint.
    */
   private int intToZigZag(int n) {
@@ -427,7 +461,7 @@
   }
 
   /**
-   * Convert a long into little-endian bytes in buf starting at off and going 
+   * Convert a long into little-endian bytes in buf starting at off and going
    * until off+7.
    */
   private void fixedLongToBytes(long n, byte[] buf, int off) {
@@ -441,17 +475,16 @@
     buf[off+7] = (byte)((n >> 56) & 0xff);
   }
 
-  /** 
-   * Writes a byte without any possibility of all that field header nonsense. 
+  /**
+   * Writes a byte without any possibility of all that field header nonsense.
    * Used internally by other writing methods that know they need to write a byte.
    */
-  private byte[] byteDirectBuffer = new byte[1];
   private void writeByteDirect(byte b) throws TException {
-    byteDirectBuffer[0] = b;
-    trans_.write(byteDirectBuffer);
+    temp[0] = b;
+    trans_.write(temp, 0, 1);
   }
 
-  /** 
+  /**
    * Writes a byte without any possibility of all that field header nonsense.
    */
   private void writeByteDirect(int n) throws TException {
@@ -459,12 +492,12 @@
   }
 
 
-  // 
+  //
   // Reading methods.
-  // 
+  //
 
   /**
-   * Read a message header. 
+   * Read a message header.
    */
   public TMessage readMessageBegin() throws TException {
     byte protocolId = readByte();
@@ -476,7 +509,7 @@
     if (version != VERSION) {
       throw new TProtocolException("Expected version " + VERSION + " but got " + version);
     }
-    byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & 0x03);
+    byte type = (byte)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
     int seqid = readVarint32();
     String messageName = readString();
     return new TMessage(messageName, type, seqid);
@@ -493,16 +526,16 @@
   }
 
   /**
-   * Doesn't actually consume any wire data, just removes the last field for 
+   * Doesn't actually consume any wire data, just removes the last field for
    * this struct from the field stack.
    */
   public void readStructEnd() throws TException {
     // consume the last field we read off the wire.
     lastFieldId_ = lastField_.pop();
   }
-  
+
   /**
-   * Read a field header off the wire. 
+   * Read a field header off the wire.
    */
   public TField readFieldBegin() throws TException {
     byte type = readByte();
@@ -530,26 +563,27 @@
     if (isBoolType(type)) {
       // save the boolean value in a special instance variable.
       boolValue_ = (byte)(type & 0x0f) == Types.BOOLEAN_TRUE ? Boolean.TRUE : Boolean.FALSE;
-    } 
+    }
 
     // push the new field onto the field stack so we can keep the deltas going.
     lastFieldId_ = field.id;
     return field;
   }
 
-  /** 
+  /**
    * 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.
    */
   public TMap readMapBegin() throws TException {
     int size = readVarint32();
+    checkContainerReadLength(size);
     byte keyAndValueType = size == 0 ? 0 : readByte();
     return new TMap(getTType((byte)(keyAndValueType >> 4)), getTType((byte)(keyAndValueType & 0xf)), size);
   }
 
   /**
-   * Read a list header off the wire. If the list size is 0-14, the size will 
+   * 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.
@@ -560,12 +594,13 @@
     if (size == 15) {
       size = readVarint32();
     }
+    checkContainerReadLength(size);
     byte type = getTType(size_and_type);
     return new TList(type, size);
   }
 
   /**
-   * Read a set header off the wire. If the set size is 0-14, the size will 
+   * 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.
@@ -588,7 +623,6 @@
     return readByte() == Types.BOOLEAN_TRUE;
   }
 
-  byte[] byteRawBuf = new byte[1];
   /**
    * Read a single byte off the wire. Nothing interesting here.
    */
@@ -598,8 +632,8 @@
       b = trans_.getBuffer()[trans_.getBufferPosition()];
       trans_.consumeBuffer(1);
     } else {
-      trans_.readAll(byteRawBuf, 0, 1);
-      b = byteRawBuf[0];
+      trans_.readAll(temp, 0, 1);
+      b = temp[0];
     }
     return b;
   }
@@ -629,9 +663,8 @@
    * No magic here - just read a double off the wire.
    */
   public double readDouble() throws TException {
-    byte[] longBits = new byte[8];
-    trans_.readAll(longBits, 0, 8);
-    return Double.longBitsToDouble(bytesToLong(longBits));
+    trans_.readAll(temp, 0, 8);
+    return Double.longBitsToDouble(bytesToLong(temp));
   }
 
   /**
@@ -639,32 +672,36 @@
    */
   public String readString() throws TException {
     int length = readVarint32();
-    checkReadLength(length);
+    checkStringReadLength(length);
 
     if (length == 0) {
       return "";
     }
 
-    try {
-      if (trans_.getBytesRemainingInBuffer() >= length) {
-        String str = new String(trans_.getBuffer(), trans_.getBufferPosition(), length, "UTF-8");
-        trans_.consumeBuffer(length);
-        return str;
-      } else {
-        return new String(readBinary(length), "UTF-8");
-      }
-    } catch (UnsupportedEncodingException e) {
-      throw new TException("UTF-8 not supported!");
+    final String str;
+    if (trans_.getBytesRemainingInBuffer() >= length) {
+      str = new String(trans_.getBuffer(), trans_.getBufferPosition(),
+          length, StandardCharsets.UTF_8);
+      trans_.consumeBuffer(length);
+    } else {
+      str = new String(readBinary(length), StandardCharsets.UTF_8);
     }
+    return str;
   }
 
   /**
-   * Read a byte[] from the wire. 
+   * Read a byte[] from the wire.
    */
   public ByteBuffer readBinary() throws TException {
     int length = readVarint32();
-    checkReadLength(length);
-    if (length == 0) return ByteBuffer.wrap(new byte[0]);
+    checkStringReadLength(length);
+    if (length == 0) return EMPTY_BUFFER;
+
+    if (trans_.getBytesRemainingInBuffer() >= length) {
+      ByteBuffer bb = ByteBuffer.wrap(trans_.getBuffer(), trans_.getBufferPosition(), length);
+      trans_.consumeBuffer(length);
+      return bb;
+    }
 
     byte[] buf = new byte[length];
     trans_.readAll(buf, 0, length);
@@ -672,27 +709,40 @@
   }
 
   /**
-   * Read a byte[] of a known length from the wire. 
+   * Read a byte[] of a known length from the wire.
    */
   private byte[] readBinary(int length) throws TException {
-    if (length == 0) return new byte[0];
+    if (length == 0) return EMPTY_BYTES;
 
     byte[] buf = new byte[length];
     trans_.readAll(buf, 0, length);
     return buf;
   }
 
-  private void checkReadLength(int length) throws TProtocolException {
+  private void checkStringReadLength(int length) throws TProtocolException {
     if (length < 0) {
-      throw new TProtocolException("Negative length: " + length);
+      throw new TProtocolException(TProtocolException.NEGATIVE_SIZE,
+                                   "Negative length: " + length);
     }
-    if (maxNetworkBytes_ != -1 && length > maxNetworkBytes_) {
-      throw new TProtocolException("Length exceeded max allowed: " + length);
+    if (stringLengthLimit_ != NO_LENGTH_LIMIT && length > stringLengthLimit_) {
+      throw new TProtocolException(TProtocolException.SIZE_LIMIT,
+                                   "Length exceeded max allowed: " + length);
+    }
+  }
+
+  private void checkContainerReadLength(int length) throws TProtocolException {
+    if (length < 0) {
+      throw new TProtocolException(TProtocolException.NEGATIVE_SIZE,
+                                   "Negative length: " + length);
+    }
+    if (containerLengthLimit_ != NO_LENGTH_LIMIT && length > containerLengthLimit_) {
+      throw new TProtocolException(TProtocolException.SIZE_LIMIT,
+                                   "Length exceeded max allowed: " + length);
     }
   }
 
   //
-  // These methods are here for the struct to call, but don't have any wire 
+  // These methods are here for the struct to call, but don't have any wire
   // encoding.
   //
   public void readMessageEnd() throws TException {}
@@ -736,7 +786,7 @@
   }
 
   /**
-   * Read an i64 from the wire as a proper varint. The MSB of each byte is set 
+   * 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.
    */
   private long readVarint64() throws TException {
@@ -776,7 +826,7 @@
     return (n >>> 1) ^ -(n & 1);
   }
 
-  /** 
+  /**
    * Convert from zigzag long to long.
    */
   private long zigzagToLong(long n) {
@@ -784,7 +834,7 @@
   }
 
   /**
-   * Note that it's important that the mask bytes are long literals, 
+   * 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.
    */
@@ -810,7 +860,7 @@
   }
 
   /**
-   * Given a TCompactProtocol.Types constant, convert it to its corresponding 
+   * Given a TCompactProtocol.Types constant, convert it to its corresponding
    * TType value.
    */
   private byte getTType(byte type) throws TProtocolException {
diff --git a/lib/java/src/org/apache/thrift/protocol/TField.java b/lib/java/src/org/apache/thrift/protocol/TField.java
index 03affda..31331bb 100644
--- a/lib/java/src/org/apache/thrift/protocol/TField.java
+++ b/lib/java/src/org/apache/thrift/protocol/TField.java
@@ -42,7 +42,25 @@
     return "<TField name:'" + name + "' type:" + type + " field-id:" + id + ">";
   }
 
-  public boolean equals(TField otherField) {
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + id;
+    result = prime * result + ((name == null) ? 0 : name.hashCode());
+    result = prime * result + type;
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj)
+      return true;
+    if (obj == null)
+      return false;
+    if (getClass() != obj.getClass())
+      return false;
+    TField otherField = (TField) obj;
     return type == otherField.type && id == otherField.id;
   }
 }
diff --git a/lib/java/src/org/apache/thrift/protocol/TJSONProtocol.java b/lib/java/src/org/apache/thrift/protocol/TJSONProtocol.java
index f07a4a7..d37c493 100644
--- a/lib/java/src/org/apache/thrift/protocol/TJSONProtocol.java
+++ b/lib/java/src/org/apache/thrift/protocol/TJSONProtocol.java
@@ -19,8 +19,10 @@
 
 package org.apache.thrift.protocol;
 
-import java.io.UnsupportedEncodingException;
+import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.Stack;
 
 import org.apache.thrift.TByteArrayOutputStream;
@@ -42,9 +44,16 @@
    * Factory for JSON protocol objects
    */
   public static class Factory implements TProtocolFactory {
+    protected boolean fieldNamesAsString_ = false;
+
+    public Factory() {}
+
+    public Factory(boolean fieldNamesAsString) {
+      fieldNamesAsString_ = fieldNamesAsString;
+    }
 
     public TProtocol getProtocol(TTransport trans) {
-      return new TJSONProtocol(trans);
+      return new TJSONProtocol(trans, fieldNamesAsString_);
     }
 
   }
@@ -70,10 +79,10 @@
     1,  1,'"',  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, // 2
   };
 
-  private static final String ESCAPE_CHARS = "\"\\bfnrt";
+  private static final String ESCAPE_CHARS = "\"\\/bfnrt";
 
   private static final byte[] ESCAPE_CHAR_VALS = {
-    '"', '\\', '\b', '\f', '\n', '\r', '\t',
+    '"', '\\', '/', '\b', '\f', '\n', '\r', '\t',
   };
 
   private static final int  DEF_STRING_SIZE = 16;
@@ -285,6 +294,9 @@
   // Reader that manages a 1-byte buffer
   private LookaheadReader reader_ = new LookaheadReader();
 
+  // Write out the TField names as a string instead of the default integer value
+  private boolean fieldNamesAsString_ = false;
+
   // Push a new JSON context onto the stack.
   private void pushContext(JSONBaseContext c) {
     contextStack_.push(context_);
@@ -296,6 +308,13 @@
     context_ = contextStack_.pop();
   }
 
+  // Reset the context stack to its initial state
+  private void resetContext() {
+    while (!contextStack_.isEmpty()) {
+      popContext();
+    }
+  }
+
   /**
    * Constructor
    */
@@ -303,6 +322,11 @@
     super(trans);
   }
 
+  public TJSONProtocol(TTransport trans, boolean fieldNamesAsString) {
+    super(trans);
+    fieldNamesAsString_ = fieldNamesAsString;
+  }
+
   @Override
   public void reset() {
     contextStack_.clear();
@@ -394,12 +418,8 @@
     if (escapeNum) {
       trans_.write(QUOTE);
     }
-    try {
-      byte[] buf = str.getBytes("UTF-8");
-      trans_.write(buf);
-    } catch (UnsupportedEncodingException uex) {
-      throw new TException("JVM DOES NOT SUPPORT UTF-8");
-    }
+    byte[] buf = str.getBytes(StandardCharsets.UTF_8);
+    trans_.write(buf);
     if (escapeNum) {
       trans_.write(QUOTE);
     }
@@ -421,18 +441,16 @@
         special = true;
       }
       break;
-    }
+    default:
+      break;
+  }
 
     boolean escapeNum = special || context_.escapeNum();
     if (escapeNum) {
       trans_.write(QUOTE);
     }
-    try {
-      byte[] b = str.getBytes("UTF-8");
-      trans_.write(b, 0, b.length);
-    } catch (UnsupportedEncodingException uex) {
-      throw new TException("JVM DOES NOT SUPPORT UTF-8");
-    }
+    byte[] b = str.getBytes(StandardCharsets.UTF_8);
+    trans_.write(b, 0, b.length);
     if (escapeNum) {
       trans_.write(QUOTE);
     }
@@ -484,14 +502,11 @@
 
   @Override
   public void writeMessageBegin(TMessage message) throws TException {
+    resetContext(); // THRIFT-3743
     writeJSONArrayStart();
     writeJSONInteger(VERSION);
-    try {
-      byte[] b = message.name.getBytes("UTF-8");
-      writeJSONString(b);
-    } catch (UnsupportedEncodingException uex) {
-      throw new TException("JVM DOES NOT SUPPORT UTF-8");
-    }
+    byte[] b = message.name.getBytes(StandardCharsets.UTF_8);
+    writeJSONString(b);
     writeJSONInteger(message.type);
     writeJSONInteger(message.seqid);
   }
@@ -513,7 +528,11 @@
 
   @Override
   public void writeFieldBegin(TField field) throws TException {
-    writeJSONInteger(field.id);
+    if (fieldNamesAsString_) {
+      writeString(field.name);
+    } else {
+      writeJSONInteger(field.id);
+    }
     writeJSONObjectStart();
     writeJSONString(getTypeNameForTypeID(field.type));
   }
@@ -597,12 +616,8 @@
 
   @Override
   public void writeString(String str) throws TException {
-    try {
-      byte[] b = str.getBytes("UTF-8");
-      writeJSONString(b);
-    } catch (UnsupportedEncodingException uex) {
-      throw new TException("JVM DOES NOT SUPPORT UTF-8");
-    }
+    byte[] b = str.getBytes(StandardCharsets.UTF_8);
+    writeJSONString(b);
   }
 
   @Override
@@ -619,6 +634,7 @@
   private TByteArrayOutputStream readJSONString(boolean skipContext)
     throws TException {
     TByteArrayOutputStream arr = new TByteArrayOutputStream(DEF_STRING_SIZE);
+    ArrayList<Character> codeunits = new ArrayList<Character>();
     if (!skipContext) {
       context_.read();
     }
@@ -631,10 +647,41 @@
       if (ch == ESCSEQ[0]) {
         ch = reader_.read();
         if (ch == ESCSEQ[1]) {
-          readJSONSyntaxChar(ZERO);
-          readJSONSyntaxChar(ZERO);
-          trans_.readAll(tmpbuf_, 0, 2);
-          ch = (byte)((hexVal((byte)tmpbuf_[0]) << 4) + hexVal(tmpbuf_[1]));
+          trans_.readAll(tmpbuf_, 0, 4);
+          short cu = (short)(
+              ((short)hexVal(tmpbuf_[0]) << 12) +
+              ((short)hexVal(tmpbuf_[1]) << 8) +
+              ((short)hexVal(tmpbuf_[2]) << 4) +
+              (short)hexVal(tmpbuf_[3]));
+          try {
+            if (Character.isHighSurrogate((char)cu)) {
+              if (codeunits.size() > 0) {
+                throw new TProtocolException(TProtocolException.INVALID_DATA,
+                    "Expected low surrogate char");
+              }
+              codeunits.add((char)cu);
+            }
+            else if (Character.isLowSurrogate((char)cu)) {
+              if (codeunits.size() == 0) {
+                throw new TProtocolException(TProtocolException.INVALID_DATA,
+                    "Expected high surrogate char");
+              }
+
+              codeunits.add((char)cu);
+              arr.write(
+                  (new String(new int[] { codeunits.get(0), codeunits.get(1) },
+                      0, 2)).getBytes(StandardCharsets.UTF_8));
+              codeunits.clear();
+            }
+            else {
+              arr.write((new String(new int[] { cu }, 0, 1))
+                  .getBytes(StandardCharsets.UTF_8));
+            }
+            continue;
+          } catch (IOException ex) {
+            throw new TProtocolException(TProtocolException.INVALID_DATA,
+                "Invalid unicode sequence");
+          }
         }
         else {
           int off = ESCAPE_CHARS.indexOf(ch);
@@ -712,19 +759,14 @@
     context_.read();
     if (reader_.peek() == QUOTE[0]) {
       TByteArrayOutputStream arr = readJSONString(true);
-      try {
-        double dub = Double.valueOf(arr.toString("UTF-8"));
-        if (!context_.escapeNum() && !Double.isNaN(dub) &&
-            !Double.isInfinite(dub)) {
-          // Throw exception -- we should not be in a string in this case
-          throw new TProtocolException(TProtocolException.INVALID_DATA,
-                                       "Numeric data unexpectedly quoted");
-        }
-        return dub;
+      double dub = Double.valueOf(arr.toString(StandardCharsets.UTF_8));
+      if (!context_.escapeNum() && !Double.isNaN(dub)
+          && !Double.isInfinite(dub)) {
+        // Throw exception -- we should not be in a string in this case
+        throw new TProtocolException(TProtocolException.INVALID_DATA,
+            "Numeric data unexpectedly quoted");
       }
-      catch (UnsupportedEncodingException ex) {
-        throw new TException("JVM DOES NOT SUPPORT UTF-8");
-      }
+      return dub;
     }
     else {
       if (context_.escapeNum()) {
@@ -748,6 +790,11 @@
     int len = arr.len();
     int off = 0;
     int size = 0;
+    // Ignore padding
+    int bound = len >= 2 ? len - 2 : 0;
+    for (int i = len - 1; i >= bound && b[i] == '='; --i) {
+      --len;
+    }
     while (len >= 4) {
       // Decode 4 bytes at a time
       TBase64Utils.decode(b, off, 4, b, size); // NB: decoded in place
@@ -792,18 +839,13 @@
 
   @Override
   public TMessage readMessageBegin() throws TException {
+    resetContext(); // THRIFT-3743
     readJSONArrayStart();
     if (readJSONInteger() != VERSION) {
       throw new TProtocolException(TProtocolException.BAD_VERSION,
                                    "Message contained bad version.");
     }
-    String name;
-    try {
-      name = readJSONString(false).toString("UTF-8");
-    }
-    catch (UnsupportedEncodingException ex) {
-      throw new TException("JVM DOES NOT SUPPORT UTF-8");
-    }
+    String name = readJSONString(false).toString(StandardCharsets.UTF_8);
     byte type = (byte) readJSONInteger();
     int seqid = (int) readJSONInteger();
     return new TMessage(name, type, seqid);
@@ -920,12 +962,7 @@
 
   @Override
   public String readString() throws TException {
-    try {
-      return readJSONString(false).toString("UTF-8");
-    }
-    catch (UnsupportedEncodingException ex) {
-      throw new TException("JVM DOES NOT SUPPORT UTF-8");
-    }
+    return readJSONString(false).toString(StandardCharsets.UTF_8);
   }
 
   @Override
diff --git a/lib/java/src/org/apache/thrift/protocol/TMessage.java b/lib/java/src/org/apache/thrift/protocol/TMessage.java
index 1438b11..f13b8ca 100644
--- a/lib/java/src/org/apache/thrift/protocol/TMessage.java
+++ b/lib/java/src/org/apache/thrift/protocol/TMessage.java
@@ -44,14 +44,33 @@
   }
 
   @Override
-  public boolean equals(Object other) {
-    if (other instanceof TMessage) {
-      return equals((TMessage) other);
-    }
-    return false;
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + ((name == null) ? 0 : name.hashCode());
+    result = prime * result + seqid;
+    result = prime * result + type;
+    return result;
   }
 
-  public boolean equals(TMessage other) {
-    return name.equals(other.name) && type == other.type && seqid == other.seqid;
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj)
+      return true;
+    if (obj == null)
+      return false;
+    if (getClass() != obj.getClass())
+      return false;
+    TMessage other = (TMessage) obj;
+    if (name == null) {
+      if (other.name != null)
+        return false;
+    } else if (!name.equals(other.name))
+      return false;
+    if (seqid != other.seqid)
+      return false;
+    if (type != other.type)
+      return false;
+    return true;
   }
 }
diff --git a/lib/java/src/org/apache/thrift/protocol/TMultiplexedProtocol.java b/lib/java/src/org/apache/thrift/protocol/TMultiplexedProtocol.java
index 3535274..0ea566b 100644
--- a/lib/java/src/org/apache/thrift/protocol/TMultiplexedProtocol.java
+++ b/lib/java/src/org/apache/thrift/protocol/TMultiplexedProtocol.java
@@ -31,21 +31,23 @@
  *
  * <p>This example uses a single socket transport to invoke two services:
  *
- * <blockquote><code>
- *     TSocket transport = new TSocket("localhost", 9090);<br/>
- *     transport.open();<br/>
- *<br/>
- *     TBinaryProtocol protocol = new TBinaryProtocol(transport);<br/>
- *<br/>
- *     TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "Calculator");<br/>
- *     Calculator.Client service = new Calculator.Client(mp);<br/>
- *<br/>
- *     TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, "WeatherReport");<br/>
- *     WeatherReport.Client service2 = new WeatherReport.Client(mp2);<br/>
- *<br/>
- *     System.out.println(service.add(2,2));<br/>
- *     System.out.println(service2.getTemperature());<br/>
- * </code></blockquote>
+ * <pre>
+ * {@code
+ *     TSocket transport = new TSocket("localhost", 9090);
+ *     transport.open();
+ *
+ *     TBinaryProtocol protocol = new TBinaryProtocol(transport);
+ *
+ *     TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "Calculator");
+ *     Calculator.Client service = new Calculator.Client(mp);
+ *
+ *     TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, "WeatherReport");
+ *     WeatherReport.Client service2 = new WeatherReport.Client(mp2);
+ *
+ *     System.out.println(service.add(2,2));
+ *     System.out.println(service2.getTemperature());
+ * }
+ * </pre>
  *
  * @see org.apache.thrift.protocol.TProtocolDecorator
  */
diff --git a/lib/java/src/org/apache/thrift/protocol/TProtocolException.java b/lib/java/src/org/apache/thrift/protocol/TProtocolException.java
index 248815b..870f1b9 100644
--- a/lib/java/src/org/apache/thrift/protocol/TProtocolException.java
+++ b/lib/java/src/org/apache/thrift/protocol/TProtocolException.java
@@ -35,6 +35,7 @@
   public static final int SIZE_LIMIT = 3;
   public static final int BAD_VERSION = 4;
   public static final int NOT_IMPLEMENTED = 5;
+  public static final int DEPTH_LIMIT = 6;
 
   protected int type_ = UNKNOWN;
 
diff --git a/lib/java/src/org/apache/thrift/protocol/TProtocolUtil.java b/lib/java/src/org/apache/thrift/protocol/TProtocolUtil.java
index 752520a..cdaa30b 100644
--- a/lib/java/src/org/apache/thrift/protocol/TProtocolUtil.java
+++ b/lib/java/src/org/apache/thrift/protocol/TProtocolUtil.java
@@ -141,7 +141,8 @@
         break;
 
       default:
-        break;
+        throw new TProtocolException(TProtocolException.INVALID_DATA,
+                                   "Unrecognized type " + type);
     }
   }
 
@@ -152,7 +153,7 @@
    * In some cases, no guess can be done, in that case we return the
    * fallback TProtocolFactory.
    * To be certain to correctly detect the protocol, the first encoded
-   * field should have a field id < 256
+   * field should have a field id &lt; 256
    *
    * @param data The serialized data to guess the protocol for.
    * @param fallback The TProtocol to return if no guess can be made.
diff --git a/lib/java/src/org/apache/thrift/protocol/TSimpleJSONProtocol.java b/lib/java/src/org/apache/thrift/protocol/TSimpleJSONProtocol.java
index 33cad24..eb7e23b 100644
--- a/lib/java/src/org/apache/thrift/protocol/TSimpleJSONProtocol.java
+++ b/lib/java/src/org/apache/thrift/protocol/TSimpleJSONProtocol.java
@@ -19,8 +19,8 @@
 
 package org.apache.thrift.protocol;
 
-import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
 import java.util.Stack;
 
 import org.apache.thrift.TException;
@@ -45,13 +45,13 @@
     }
   }
 
-  public static final byte[] COMMA = new byte[] {','};
-  public static final byte[] COLON = new byte[] {':'};
-  public static final byte[] LBRACE = new byte[] {'{'};
-  public static final byte[] RBRACE = new byte[] {'}'};
-  public static final byte[] LBRACKET = new byte[] {'['};
-  public static final byte[] RBRACKET = new byte[] {']'};
-  public static final char QUOTE = '"';
+  private static final byte[] COMMA = new byte[] {','};
+  private static final byte[] COLON = new byte[] {':'};
+  private static final byte[] LBRACE = new byte[] {'{'};
+  private static final byte[] RBRACE = new byte[] {'}'};
+  private static final byte[] LBRACKET = new byte[] {'['};
+  private static final byte[] RBRACKET = new byte[] {']'};
+  private static final char QUOTE = '"';
 
   private static final TStruct ANONYMOUS_STRUCT = new TStruct();
   private static final TField ANONYMOUS_FIELD = new TField();
@@ -59,9 +59,17 @@
   private static final TSet EMPTY_SET = new TSet();
   private static final TList EMPTY_LIST = new TList();
   private static final TMap EMPTY_MAP = new TMap();
+  private static final String LIST = "list";
+  private static final String SET = "set";
+  private static final String MAP = "map";
 
   protected class Context {
     protected void write() throws TException {}
+
+    /**
+     * Returns whether the current value is a key in a map
+     */
+    protected boolean isMapKey() { return  false; }
   }
 
   protected class ListContext extends Context {
@@ -91,6 +99,22 @@
     }
   }
 
+  protected class MapContext extends StructContext {
+    protected boolean isKey = true;
+
+    @Override
+    protected void write() throws TException {
+      super.write();
+      isKey = !isKey;
+    }
+
+    protected boolean isMapKey() {
+      // we want to coerce map keys to json strings regardless
+      // of their type
+      return isKey;
+    }
+  }
+
   protected final Context BASE_CONTEXT = new Context();
 
   /**
@@ -119,13 +143,33 @@
   }
 
   /**
+   * Reset the write context stack to its initial state.
+   */
+  protected void resetWriteContext() {
+    while (!writeContextStack_.isEmpty()) {
+      popWriteContext();
+    }
+  }
+
+  /**
+   * Used to make sure that we are not encountering a map whose keys are containers
+   */
+  protected void assertContextIsNotMapKey(String invalidKeyType) throws CollectionMapKeyException {
+    if (writeContext_.isMapKey()) {
+      throw new CollectionMapKeyException("Cannot serialize a map with keys that are of type " + invalidKeyType);
+    }
+  }
+
+  /**
    * Constructor
    */
   public TSimpleJSONProtocol(TTransport trans) {
     super(trans);
   }
 
+  @Override
   public void writeMessageBegin(TMessage message) throws TException {
+    resetWriteContext(); // THRIFT-3743
     trans_.write(LBRACKET);
     pushWriteContext(new ListContext());
     writeString(message.name);
@@ -133,103 +177,133 @@
     writeI32(message.seqid);
   }
 
+  @Override
   public void writeMessageEnd() throws TException {
     popWriteContext();
     trans_.write(RBRACKET);
   }
 
+  @Override
   public void writeStructBegin(TStruct struct) throws TException {
     writeContext_.write();
     trans_.write(LBRACE);
     pushWriteContext(new StructContext());
   }
 
+  @Override
   public void writeStructEnd() throws TException {
     popWriteContext();
     trans_.write(RBRACE);
   }
 
+  @Override
   public void writeFieldBegin(TField field) throws TException {
     // Note that extra type information is omitted in JSON!
     writeString(field.name);
   }
 
-  public void writeFieldEnd() {}
+  @Override
+  public void writeFieldEnd() throws TException {}
 
-  public void writeFieldStop() {}
+  @Override
+  public void writeFieldStop() throws TException {}
 
+  @Override
   public void writeMapBegin(TMap map) throws TException {
+    assertContextIsNotMapKey(MAP);
     writeContext_.write();
     trans_.write(LBRACE);
-    pushWriteContext(new StructContext());
+    pushWriteContext(new MapContext());
     // No metadata!
   }
 
+  @Override
   public void writeMapEnd() throws TException {
     popWriteContext();
     trans_.write(RBRACE);
   }
 
+  @Override
   public void writeListBegin(TList list) throws TException {
+    assertContextIsNotMapKey(LIST);
     writeContext_.write();
     trans_.write(LBRACKET);
     pushWriteContext(new ListContext());
     // No metadata!
   }
 
+  @Override
   public void writeListEnd() throws TException {
     popWriteContext();
     trans_.write(RBRACKET);
   }
 
+  @Override
   public void writeSetBegin(TSet set) throws TException {
+    assertContextIsNotMapKey(SET);
     writeContext_.write();
     trans_.write(LBRACKET);
     pushWriteContext(new ListContext());
     // No metadata!
   }
 
+  @Override
   public void writeSetEnd() throws TException {
     popWriteContext();
     trans_.write(RBRACKET);
   }
 
+  @Override
   public void writeBool(boolean b) throws TException {
     writeByte(b ? (byte)1 : (byte)0);
   }
 
+  @Override
   public void writeByte(byte b) throws TException {
     writeI32(b);
   }
 
+  @Override
   public void writeI16(short i16) throws TException {
     writeI32(i16);
   }
 
+  @Override
   public void writeI32(int i32) throws TException {
-    writeContext_.write();
-    _writeStringData(Integer.toString(i32));
-  }
-
-  public void _writeStringData(String s) throws TException {
-    try {
-      byte[] b = s.getBytes("UTF-8");
-      trans_.write(b);
-    } catch (UnsupportedEncodingException uex) {
-      throw new TException("JVM DOES NOT SUPPORT UTF-8");
+    if(writeContext_.isMapKey()) {
+      writeString(Integer.toString(i32));
+    } else {
+      writeContext_.write();
+      _writeStringData(Integer.toString(i32));
     }
   }
 
+  public void _writeStringData(String s) throws TException {
+    byte[] b = s.getBytes(StandardCharsets.UTF_8);
+    trans_.write(b);
+  }
+
+  @Override
   public void writeI64(long i64) throws TException {
-    writeContext_.write();
-    _writeStringData(Long.toString(i64));
+    if(writeContext_.isMapKey()) {
+      writeString(Long.toString(i64));
+    } else {
+      writeContext_.write();
+      _writeStringData(Long.toString(i64));
+    }
   }
 
+  @Override
   public void writeDouble(double dub) throws TException {
-    writeContext_.write();
-    _writeStringData(Double.toString(dub));
+    if(writeContext_.isMapKey()) {
+      writeString(Double.toString(dub));
+    } else {
+      writeContext_.write();
+      _writeStringData(Double.toString(dub));
+    }
   }
 
+  @Override
   public void writeString(String str) throws TException {
     writeContext_.write();
     int length = str.length();
@@ -283,90 +357,108 @@
     _writeStringData(escape.toString());
   }
 
+  @Override
   public void writeBinary(ByteBuffer bin) throws TException {
-    try {
-      // TODO(mcslee): Fix this
-      writeString(new String(bin.array(), bin.position() + bin.arrayOffset(), bin.limit() - bin.position() - bin.arrayOffset(), "UTF-8"));
-    } catch (UnsupportedEncodingException uex) {
-      throw new TException("JVM DOES NOT SUPPORT UTF-8");
-    }
+    // TODO(mcslee): Fix this
+    writeString(new String(bin.array(), bin.position() + bin.arrayOffset(),
+        bin.limit() - bin.position() - bin.arrayOffset(),
+        StandardCharsets.UTF_8));
   }
 
   /**
    * Reading methods.
    */
 
+  @Override
   public TMessage readMessageBegin() throws TException {
     // TODO(mcslee): implement
     return EMPTY_MESSAGE;
   }
 
-  public void readMessageEnd() {}
+  @Override
+  public void readMessageEnd() throws TException {}
 
-  public TStruct readStructBegin() {
+  @Override
+  public TStruct readStructBegin() throws TException {
     // TODO(mcslee): implement
     return ANONYMOUS_STRUCT;
   }
 
-  public void readStructEnd() {}
+  @Override
+  public void readStructEnd() throws TException {}
 
+  @Override
   public TField readFieldBegin() throws TException {
     // TODO(mcslee): implement
     return ANONYMOUS_FIELD;
   }
 
-  public void readFieldEnd() {}
+  @Override
+  public void readFieldEnd() throws TException {}
 
+  @Override
   public TMap readMapBegin() throws TException {
     // TODO(mcslee): implement
     return EMPTY_MAP;
   }
 
-  public void readMapEnd() {}
+  @Override
+  public void readMapEnd() throws TException {}
 
+  @Override
   public TList readListBegin() throws TException {
     // TODO(mcslee): implement
     return EMPTY_LIST;
   }
 
-  public void readListEnd() {}
+  @Override
+  public void readListEnd() throws TException {}
 
+  @Override
   public TSet readSetBegin() throws TException {
     // TODO(mcslee): implement
     return EMPTY_SET;
   }
 
-  public void readSetEnd() {}
+  @Override
+  public void readSetEnd() throws TException {}
 
+  @Override
   public boolean readBool() throws TException {
     return (readByte() == 1);
   }
 
+  @Override
   public byte readByte() throws TException {
     // TODO(mcslee): implement
     return 0;
   }
 
+  @Override
   public short readI16() throws TException {
     // TODO(mcslee): implement
     return 0;
   }
 
+  @Override
   public int readI32() throws TException {
     // TODO(mcslee): implement
     return 0;
   }
 
+  @Override
   public long readI64() throws TException {
     // TODO(mcslee): implement
     return 0;
   }
 
+  @Override
   public double readDouble() throws TException {
     // TODO(mcslee): implement
     return 0;
   }
 
+  @Override
   public String readString() throws TException {
     // TODO(mcslee): implement
     return "";
@@ -377,9 +469,15 @@
     return "";
   }
 
+  @Override
   public ByteBuffer readBinary() throws TException {
     // TODO(mcslee): implement
     return ByteBuffer.wrap(new byte[0]);
   }
 
+  public static class CollectionMapKeyException extends TException {
+    public CollectionMapKeyException(String message) {
+      super(message);
+    }
+  }
 }
diff --git a/lib/java/src/org/apache/thrift/server/AbstractNonblockingServer.java b/lib/java/src/org/apache/thrift/server/AbstractNonblockingServer.java
index 80da6ca..8c206e4 100644
--- a/lib/java/src/org/apache/thrift/server/AbstractNonblockingServer.java
+++ b/lib/java/src/org/apache/thrift/server/AbstractNonblockingServer.java
@@ -19,16 +19,7 @@
 
 package org.apache.thrift.server;
 
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.Selector;
-import java.nio.channels.spi.SelectorProvider;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.apache.thrift.TBaseAsyncProcessor;
+import org.apache.thrift.TAsyncProcessor;
 import org.apache.thrift.TByteArrayOutputStream;
 import org.apache.thrift.TException;
 import org.apache.thrift.protocol.TProtocol;
@@ -42,6 +33,15 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
 /**
  * Provides common methods and classes used by nonblocking TServer
  * implementations.
@@ -50,7 +50,7 @@
   protected final Logger LOGGER = LoggerFactory.getLogger(getClass().getName());
 
   public static abstract class AbstractNonblockingServerArgs<T extends AbstractNonblockingServerArgs<T>> extends AbstractServerArgs<T> {
-    public long maxReadBufferBytes = Long.MAX_VALUE;
+    public long maxReadBufferBytes = 256 * 1024 * 1024;
 
     public AbstractNonblockingServerArgs(TNonblockingServerTransport transport) {
       super(transport);
@@ -102,7 +102,7 @@
 
   /**
    * Starts any threads required for serving.
-   * 
+   *
    * @return true if everything went ok, false if threads could not be started.
    */
   protected abstract boolean startThreads();
@@ -115,7 +115,7 @@
 
   /**
    * Have the server transport start accepting connections.
-   * 
+   *
    * @return true if we started listening successfully, false if something went
    *         wrong.
    */
@@ -139,7 +139,7 @@
   /**
    * Perform an invocation. This method could behave several different ways -
    * invoke immediately inline, queue for separate execution, etc.
-   * 
+   *
    * @return true if invocation was successfully requested, which is not a
    *         guarantee that invocation has completed. False if the request
    *         failed.
@@ -152,7 +152,7 @@
    * corresponding to requests.
    */
   protected abstract class AbstractSelectThread extends Thread {
-    protected final Selector selector;
+    protected Selector selector;
 
     // List of FrameBuffers that want to change their selection interests.
     protected final Set<FrameBuffer> selectInterestChanges = new HashSet<FrameBuffer>();
@@ -285,21 +285,21 @@
     protected ByteBuffer buffer_;
 
     protected final TByteArrayOutputStream response_;
-    
+
     // the frame that the TTransport should wrap.
     protected final TMemoryInputTransport frameTrans_;
-    
+
     // the transport that should be used to connect to clients
     protected final TTransport inTrans_;
-    
+
     protected final TTransport outTrans_;
-    
+
     // the input protocol to use on frames
     protected final TProtocol inProt_;
-    
+
     // the output protocol to use on frames
     protected final TProtocol outProt_;
-    
+
     // context associated with this connection
     protected final ServerContext context_;
 
@@ -328,7 +328,7 @@
     /**
      * Give this FrameBuffer a chance to read. The selector loop should have
      * received a read event for this FrameBuffer.
-     * 
+     *
      * @return true if the connection should live on, false if it should be
      *         closed
      */
@@ -435,17 +435,23 @@
      * has come in.
      */
     public void changeSelectInterests() {
-      if (state_ == FrameBufferState.AWAITING_REGISTER_WRITE) {
+      switch (state_) {
+      case AWAITING_REGISTER_WRITE:
         // set the OP_WRITE interest
         selectionKey_.interestOps(SelectionKey.OP_WRITE);
         state_ = FrameBufferState.WRITING;
-      } else if (state_ == FrameBufferState.AWAITING_REGISTER_READ) {
+        break;
+      case AWAITING_REGISTER_READ:
         prepareRead();
-      } else if (state_ == FrameBufferState.AWAITING_CLOSE) {
+        break;
+      case AWAITING_CLOSE:
         close();
         selectionKey_.cancel();
-      } else {
-        LOGGER.error("changeSelectInterest was called, but state is invalid (" + state_ + ")");
+        break;
+      default:
+        LOGGER.error(
+            "changeSelectInterest was called, but state is invalid ({})",
+            state_);
       }
     }
 
@@ -455,7 +461,9 @@
     public void close() {
       // if we're being closed due to an error, we might have allocated a
       // buffer that we need to subtract for our memory accounting.
-      if (state_ == FrameBufferState.READING_FRAME || state_ == FrameBufferState.READ_FRAME_COMPLETE) {
+      if (state_ == FrameBufferState.READING_FRAME ||
+          state_ == FrameBufferState.READ_FRAME_COMPLETE ||
+          state_ == FrameBufferState.AWAITING_CLOSE) {
         readBufferBytesAllocated.addAndGet(-buffer_.array().length);
       }
       trans_.close();
@@ -508,7 +516,7 @@
     public void invoke() {
       frameTrans_.reset(buffer_.array());
       response_.reset();
-      
+
       try {
         if (eventHandler_ != null) {
           eventHandler_.processContext(context_, inTrans_, outTrans_);
@@ -528,7 +536,7 @@
 
     /**
      * Perform a read into buffer.
-     * 
+     *
      * @return true if the read succeeded, false if there was an error or the
      *         connection closed.
      */
@@ -595,7 +603,7 @@
         if (eventHandler_ != null) {
           eventHandler_.processContext(context_, inTrans_, outTrans_);
         }
-        ((TBaseAsyncProcessor)processorFactory_.getProcessor(inTrans_)).process(this);
+        ((TAsyncProcessor)processorFactory_.getProcessor(inTrans_)).process(this);
         return;
       } catch (TException te) {
         LOGGER.warn("Exception while invoking!", te);
diff --git a/lib/java/src/org/apache/thrift/server/TExtensibleServlet.java b/lib/java/src/org/apache/thrift/server/TExtensibleServlet.java
index d328dd6..75082c0 100644
--- a/lib/java/src/org/apache/thrift/server/TExtensibleServlet.java
+++ b/lib/java/src/org/apache/thrift/server/TExtensibleServlet.java
@@ -63,7 +63,7 @@
    * Returns the appropriate {@link TProcessor}. This will be called <b>once</b> just
    * after the {@link #init()} method
    * 
-   * @return
+   * @return the appropriate {@link TProcessor}
    */
   protected abstract TProcessor getProcessor();
 
@@ -71,7 +71,7 @@
    * Returns the appropriate in {@link TProtocolFactory}. This will be called
    * <b>once</b> just after the {@link #init()} method
    * 
-   * @return
+   * @return the appropriate in {@link TProtocolFactory}
    */
   protected abstract TProtocolFactory getInProtocolFactory();
 
@@ -79,7 +79,7 @@
    * Returns the appropriate out {@link TProtocolFactory}. This will be called
    * <b>once</b> just after the {@link #init()} method
    * 
-   * @return
+   * @return the appropriate out {@link TProtocolFactory}
    */
   protected abstract TProtocolFactory getOutProtocolFactory();
 
diff --git a/lib/java/src/org/apache/thrift/server/THsHaServer.java b/lib/java/src/org/apache/thrift/server/THsHaServer.java
index 3541154..4c5d7b5 100644
--- a/lib/java/src/org/apache/thrift/server/THsHaServer.java
+++ b/lib/java/src/org/apache/thrift/server/THsHaServer.java
@@ -35,7 +35,8 @@
 public class THsHaServer extends TNonblockingServer {
 
   public static class Args extends AbstractNonblockingServerArgs<Args> {
-    private int workerThreads = 5;
+    public int minWorkerThreads = 5;
+    public int maxWorkerThreads = Integer.MAX_VALUE;
     private int stopTimeoutVal = 60;
     private TimeUnit stopTimeoutUnit = TimeUnit.SECONDS;
     private ExecutorService executorService = null;
@@ -44,13 +45,44 @@
       super(transport);
     }
 
-    public Args workerThreads(int i) {
-      workerThreads = i;
+
+    /**
+     * Sets the min and max threads.
+     *
+     * @deprecated use {@link #minWorkerThreads(int)} and {@link #maxWorkerThreads(int)}  instead.
+     */
+    @Deprecated
+    public Args workerThreads(int n) {
+      minWorkerThreads = n;
+      maxWorkerThreads = n;
       return this;
     }
 
+    /**
+     * @return what the min threads was set to.
+     * @deprecated use {@link #getMinWorkerThreads()} and {@link #getMaxWorkerThreads()} instead.
+     */
+    @Deprecated
     public int getWorkerThreads() {
-      return workerThreads;
+      return minWorkerThreads;
+    }
+
+    public Args minWorkerThreads(int n) {
+      minWorkerThreads = n;
+      return this;
+    }
+
+    public Args maxWorkerThreads(int n) {
+      maxWorkerThreads = n;
+      return this;
+    }
+
+    public int getMinWorkerThreads() {
+      return minWorkerThreads;
+    }
+
+    public int getMaxWorkerThreads() {
+      return maxWorkerThreads;
     }
 
     public int getStopTimeoutVal() {
@@ -99,7 +131,7 @@
   }
 
   /**
-   * @inheritDoc
+   * {@inheritDoc}
    */
   @Override
   protected void waitForShutdown() {
@@ -111,17 +143,21 @@
    * Helper to create an invoker pool
    */
   protected static ExecutorService createInvokerPool(Args options) {
-    int workerThreads = options.workerThreads;
+    int minWorkerThreads = options.minWorkerThreads;
+    int maxWorkerThreads = options.maxWorkerThreads;
     int stopTimeoutVal = options.stopTimeoutVal;
     TimeUnit stopTimeoutUnit = options.stopTimeoutUnit;
 
     LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
-    ExecutorService invoker = new ThreadPoolExecutor(workerThreads,
-      workerThreads, stopTimeoutVal, stopTimeoutUnit, queue);
+    ExecutorService invoker = new ThreadPoolExecutor(minWorkerThreads,
+      maxWorkerThreads, stopTimeoutVal, stopTimeoutUnit, queue);
 
     return invoker;
   }
 
+  protected ExecutorService getInvoker() {
+    return invoker;
+  }
 
   protected void gracefullyShutdownInvokerPool() {
     // try to gracefully shut down the executor service
diff --git a/lib/java/src/org/apache/thrift/server/TNonblockingServer.java b/lib/java/src/org/apache/thrift/server/TNonblockingServer.java
index a6e7476..fe0365a 100644
--- a/lib/java/src/org/apache/thrift/server/TNonblockingServer.java
+++ b/lib/java/src/org/apache/thrift/server/TNonblockingServer.java
@@ -47,10 +47,6 @@
     }
   }
 
-  // Flag for stopping the server
-  // Please see THRIFT-1795 for the usage of this flag
-  private volatile boolean stopped_ = false;
-
   private SelectAcceptThread selectAcceptThread_;
 
   public TNonblockingServer(AbstractNonblockingServerArgs args) {
@@ -164,6 +160,11 @@
       } catch (Throwable t) {
         LOGGER.error("run() exiting due to uncaught error", t);
       } finally {
+        try {
+          selector.close();
+        } catch (IOException e) {
+          LOGGER.error("Got an IOException while closing selector!", e);
+        }
         stopped_ = true;
       }
     }
@@ -212,6 +213,14 @@
       }
     }
 
+    protected FrameBuffer createFrameBuffer(final TNonblockingTransport trans,
+        final SelectionKey selectionKey,
+        final AbstractSelectThread selectThread) {
+        return processorFactory_.isAsyncProcessor() ?
+                  new AsyncFrameBuffer(trans, selectionKey, selectThread) :
+                  new FrameBuffer(trans, selectionKey, selectThread);
+    }
+
     /**
      * Accept a new connection.
      */
@@ -224,9 +233,7 @@
         clientKey = client.registerSelector(selector, SelectionKey.OP_READ);
 
         // add this key to the map
-          FrameBuffer frameBuffer = processorFactory_.isAsyncProcessor() ?
-                  new AsyncFrameBuffer(client, clientKey,SelectAcceptThread.this) :
-                  new FrameBuffer(client, clientKey,SelectAcceptThread.this);
+          FrameBuffer frameBuffer = createFrameBuffer(client, clientKey, SelectAcceptThread.this);
 
           clientKey.attach(frameBuffer);
       } catch (TTransportException tte) {
diff --git a/lib/java/src/org/apache/thrift/server/TServer.java b/lib/java/src/org/apache/thrift/server/TServer.java
index a85a429..bac06b2 100644
--- a/lib/java/src/org/apache/thrift/server/TServer.java
+++ b/lib/java/src/org/apache/thrift/server/TServer.java
@@ -123,10 +123,14 @@
    */
   protected TProtocolFactory outputProtocolFactory_;
 
-  private boolean isServing;
+  private volatile boolean isServing;
 
   protected TServerEventHandler eventHandler_;
 
+  // Flag for stopping the server
+  // Please see THRIFT-1795 for the usage of this flag
+  protected volatile boolean stopped_ = false;
+
   protected TServer(AbstractServerArgs args) {
     processorFactory_ = args.processorFactory;
     serverTransport_ = args.serverTransport;
@@ -162,4 +166,12 @@
   public TServerEventHandler getEventHandler() {
     return eventHandler_;
   }
+
+  public boolean getShouldStop() {
+    return this.stopped_;
+  }
+
+  public void setShouldStop(boolean shouldStop) {
+    this.stopped_ = shouldStop;
+  }
 }
diff --git a/lib/java/src/org/apache/thrift/server/TSimpleServer.java b/lib/java/src/org/apache/thrift/server/TSimpleServer.java
index 4dfc176..e815b2c 100644
--- a/lib/java/src/org/apache/thrift/server/TSimpleServer.java
+++ b/lib/java/src/org/apache/thrift/server/TSimpleServer.java
@@ -35,9 +35,6 @@
 
   private static final Logger LOGGER = LoggerFactory.getLogger(TSimpleServer.class.getName());
 
-  // Please see THRIFT-1795 for the usage of this flag
-  private volatile boolean stopped_ = false;
-
   public TSimpleServer(AbstractServerArgs args) {
     super(args);
   }
diff --git a/lib/java/src/org/apache/thrift/server/TThreadPoolServer.java b/lib/java/src/org/apache/thrift/server/TThreadPoolServer.java
index 38dfd58..1697ad6 100644
--- a/lib/java/src/org/apache/thrift/server/TThreadPoolServer.java
+++ b/lib/java/src/org/apache/thrift/server/TThreadPoolServer.java
@@ -19,6 +19,7 @@
 
 package org.apache.thrift.server;
 
+import java.util.Random;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.SynchronousQueue;
@@ -28,6 +29,7 @@
 import org.apache.thrift.TException;
 import org.apache.thrift.TProcessor;
 import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.transport.TSaslTransportException;
 import org.apache.thrift.transport.TServerTransport;
 import org.apache.thrift.transport.TTransport;
 import org.apache.thrift.transport.TTransportException;
@@ -49,6 +51,10 @@
     public ExecutorService executorService;
     public int stopTimeoutVal = 60;
     public TimeUnit stopTimeoutUnit = TimeUnit.SECONDS;
+    public int requestTimeout = 20;
+    public TimeUnit requestTimeoutUnit = TimeUnit.SECONDS;
+    public int beBackoffSlotLength = 100;
+    public TimeUnit beBackoffSlotLengthUnit = TimeUnit.MILLISECONDS;
 
     public Args(TServerTransport transport) {
       super(transport);
@@ -64,6 +70,37 @@
       return this;
     }
 
+    public Args stopTimeoutVal(int n) {
+      stopTimeoutVal = n;
+      return this;
+    }
+
+    public Args stopTimeoutUnit(TimeUnit tu) {
+      stopTimeoutUnit = tu;
+      return this;
+    }
+
+    public Args requestTimeout(int n) {
+      requestTimeout = n;
+      return this;
+    }
+
+    public Args requestTimeoutUnit(TimeUnit tu) {
+      requestTimeoutUnit = tu;
+      return this;
+    }
+    //Binary exponential backoff slot length
+    public Args beBackoffSlotLength(int n) {
+      beBackoffSlotLength = n;
+      return this;
+    }
+
+    //Binary exponential backoff slot time unit
+    public Args beBackoffSlotLengthUnit(TimeUnit tu) {
+      beBackoffSlotLengthUnit = tu;
+      return this;
+    }
+
     public Args executorService(ExecutorService executorService) {
       this.executorService = executorService;
       return this;
@@ -73,19 +110,26 @@
   // Executor service for handling client connections
   private ExecutorService executorService_;
 
-  // Flag for stopping the server
-  // Please see THRIFT-1795 for the usage of this flag
-  private volatile boolean stopped_ = false;
-
   private final TimeUnit stopTimeoutUnit;
 
   private final long stopTimeoutVal;
 
+  private final TimeUnit requestTimeoutUnit;
+
+  private final long requestTimeout;
+
+  private final long beBackoffSlotInMillis;
+
+  private Random random = new Random(System.currentTimeMillis());
+
   public TThreadPoolServer(Args args) {
     super(args);
 
     stopTimeoutUnit = args.stopTimeoutUnit;
     stopTimeoutVal = args.stopTimeoutVal;
+    requestTimeoutUnit = args.requestTimeoutUnit;
+    requestTimeout = args.requestTimeout;
+    beBackoffSlotInMillis = args.beBackoffSlotLengthUnit.toMillis(args.beBackoffSlotLength);
 
     executorService_ = args.executorService != null ?
         args.executorService : createDefaultExecutorService(args);
@@ -96,46 +140,86 @@
       new SynchronousQueue<Runnable>();
     return new ThreadPoolExecutor(args.minWorkerThreads,
                                   args.maxWorkerThreads,
-                                  60,
-                                  TimeUnit.SECONDS,
+                                  args.stopTimeoutVal,
+                                  args.stopTimeoutUnit,
                                   executorQueue);
   }
 
-
-  public void serve() {
-    try {
+  protected ExecutorService getExecutorService() {
+    return executorService_;
+  }
+  
+  protected boolean preServe() {
+  	try {
       serverTransport_.listen();
     } catch (TTransportException ttx) {
       LOGGER.error("Error occurred during listening.", ttx);
-      return;
+      return false;
     }
 
     // Run the preServe event
     if (eventHandler_ != null) {
       eventHandler_.preServe();
     }
-
     stopped_ = false;
     setServing(true);
+    
+    return true;
+  }
+
+  public void serve() {
+  	if (!preServe()) {
+  		return;
+  	}
+
+  	execute();
+  	waitForShutdown();
+    
+    setServing(false);
+  }
+  
+  protected void execute() {
+    int failureCount = 0;
     while (!stopped_) {
-      int failureCount = 0;
       try {
         TTransport client = serverTransport_.accept();
         WorkerProcess wp = new WorkerProcess(client);
+
+        int retryCount = 0;
+        long remainTimeInMillis = requestTimeoutUnit.toMillis(requestTimeout);
         while(true) {
-          int rejections = 0;
           try {
             executorService_.execute(wp);
             break;
-          } catch(RejectedExecutionException ex) {
-            LOGGER.warn("ExecutorService rejected client " + (++rejections) +
-                " times(s)", ex);
-            try {
-              TimeUnit.SECONDS.sleep(1);
-            } catch (InterruptedException e) {
-              LOGGER.warn("Interrupted while waiting to place client on" +
-              		" executor queue.");
-              Thread.currentThread().interrupt();
+          } catch(Throwable t) {
+            if (t instanceof RejectedExecutionException) {
+              retryCount++;
+              try {
+                if (remainTimeInMillis > 0) {
+                  //do a truncated 20 binary exponential backoff sleep
+                  long sleepTimeInMillis = ((long) (random.nextDouble() *
+                      (1L << Math.min(retryCount, 20)))) * beBackoffSlotInMillis;
+                  sleepTimeInMillis = Math.min(sleepTimeInMillis, remainTimeInMillis);
+                  TimeUnit.MILLISECONDS.sleep(sleepTimeInMillis);
+                  remainTimeInMillis = remainTimeInMillis - sleepTimeInMillis;
+                } else {
+                  client.close();
+                  wp = null;
+                  LOGGER.warn("Task has been rejected by ExecutorService " + retryCount
+                      + " times till timedout, reason: " + t);
+                  break;
+                }
+              } catch (InterruptedException e) {
+                LOGGER.warn("Interrupted while waiting to place client on executor queue.");
+                Thread.currentThread().interrupt();
+                break;
+              }
+            } else if (t instanceof Error) {
+              LOGGER.error("ExecutorService threw error: " + t, t);
+              throw (Error)t;
+            } else {
+              //for other possible runtime errors from ExecutorService, should also not kill serve
+              LOGGER.warn("ExecutorService threw error: " + t, t);
               break;
             }
           }
@@ -147,8 +231,10 @@
         }
       }
     }
-
-    executorService_.shutdown();
+  }
+  
+  protected void waitForShutdown() {
+  	executorService_.shutdown();
 
     // Loop until awaitTermination finally does return without a interrupted
     // exception. If we don't do this, then we'll shut down prematurely. We want
@@ -166,7 +252,6 @@
         now = newnow;
       }
     }
-    setServing(false);
   }
 
   public void stop() {
@@ -208,7 +293,7 @@
         inputTransport = inputTransportFactory_.getTransport(client_);
         outputTransport = outputTransportFactory_.getTransport(client_);
         inputProtocol = inputProtocolFactory_.getProtocol(inputTransport);
-        outputProtocol = outputProtocolFactory_.getProtocol(outputTransport);	  
+        outputProtocol = outputProtocolFactory_.getProtocol(outputTransport);
 
         eventHandler = getEventHandler();
         if (eventHandler != null) {
@@ -226,24 +311,35 @@
               break;
             }
         }
-      } catch (TTransportException ttx) {
-        // Assume the client died and continue silently
       } catch (TException tx) {
         LOGGER.error("Thrift error occurred during processing of message.", tx);
       } catch (Exception x) {
-        LOGGER.error("Error occurred during processing of message.", x);
-      }
-
-      if (eventHandler != null) {
-        eventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
-      }
-
-      if (inputTransport != null) {
-        inputTransport.close();
-      }
-
-      if (outputTransport != null) {
-        outputTransport.close();
+        // We'll usually receive RuntimeException types here
+        // Need to unwrap to ascertain real causing exception before we choose to ignore
+        Throwable realCause = x.getCause();
+        // Ignore err-logging all transport-level/type exceptions
+        if ((realCause != null && realCause instanceof TTransportException)
+            || (x instanceof TTransportException)) {
+          LOGGER.debug(
+              "Received TTransportException during processing of message. Ignoring.",
+              x);
+        } else {
+          // Log the exception at error level and continue
+          LOGGER.error("Error occurred during processing of message.", x);
+        }
+      } finally {
+        if (eventHandler != null) {
+          eventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
+        }
+        if (inputTransport != null) {
+          inputTransport.close();
+        }
+        if (outputTransport != null) {
+          outputTransport.close();
+        }
+        if (client_.isOpen()) {
+          client_.close();
+        }
       }
     }
   }
diff --git a/lib/java/src/org/apache/thrift/server/TThreadedSelectorServer.java b/lib/java/src/org/apache/thrift/server/TThreadedSelectorServer.java
index 8a68632..038507e 100644
--- a/lib/java/src/org/apache/thrift/server/TThreadedSelectorServer.java
+++ b/lib/java/src/org/apache/thrift/server/TThreadedSelectorServer.java
@@ -19,7 +19,15 @@
 
 package org.apache.thrift.server;
 
+import org.apache.thrift.transport.TNonblockingServerTransport;
+import org.apache.thrift.transport.TNonblockingTransport;
+import org.apache.thrift.transport.TTransportException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import java.io.IOException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SelectableChannel;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.channels.spi.SelectorProvider;
@@ -37,24 +45,18 @@
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.thrift.transport.TNonblockingServerTransport;
-import org.apache.thrift.transport.TNonblockingTransport;
-import org.apache.thrift.transport.TTransportException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 /**
  * A Half-Sync/Half-Async server with a separate pool of threads to handle
  * non-blocking I/O. Accepts are handled on a single thread, and a configurable
  * number of nonblocking selector threads manage reading and writing of client
  * connections. A synchronous worker thread pool handles processing of requests.
- * 
+ *
  * Performs better than TNonblockingServer/THsHaServer in multi-core
  * environments when the the bottleneck is CPU on the single selector thread
  * handling I/O. In addition, because the accept handling is decoupled from
  * reads/writes and invocation, the server has better ability to handle back-
  * pressure from new connections (e.g. stop accepting when busy).
- * 
+ *
  * Like TNonblockingServer, it relies on the use of TFramedTransport.
  */
 public class TThreadedSelectorServer extends AbstractNonblockingServer {
@@ -180,10 +182,6 @@
     }
   }
 
-  // Flag for stopping the server
-  // Please see THRIFT-1795 for the usage of this flag
-  private volatile boolean stopped_ = false;
-
   // The thread handling all accepts
   private AcceptThread acceptThread;
 
@@ -209,7 +207,7 @@
 
   /**
    * Start the accept and selector threads running to deal with clients.
-   * 
+   *
    * @return true if everything went ok, false if we couldn't start for some
    *         reason.
    */
@@ -353,7 +351,7 @@
 
     /**
      * Set up the AcceptThead
-     * 
+     *
      * @throws IOException
      */
     public AcceptThread(TNonblockingServerTransport serverTransport,
@@ -379,8 +377,13 @@
           select();
         }
       } catch (Throwable t) {
-        LOGGER.error("run() exiting due to uncaught error", t);
+        LOGGER.error("run() on AcceptThread exiting due to uncaught error", t);
       } finally {
+        try {
+          acceptSelector.close();
+        } catch (IOException e) {
+          LOGGER.error("Got an IOException while closing accept selector!", e);
+        }
         // This will wake up the selector threads
         TThreadedSelectorServer.this.stop();
       }
@@ -477,10 +480,13 @@
 
     // Accepted connections added by the accept thread.
     private final BlockingQueue<TNonblockingTransport> acceptedQueue;
+    private int SELECTOR_AUTO_REBUILD_THRESHOLD = 512;
+    private long MONITOR_PERIOD = 1000L;
+    private int jvmBug = 0;
 
     /**
      * Set up the SelectorThread with an unbounded queue for incoming accepts.
-     * 
+     *
      * @throws IOException
      *           if a selector cannot be created
      */
@@ -490,7 +496,7 @@
 
     /**
      * Set up the SelectorThread with an bounded queue for incoming accepts.
-     * 
+     *
      * @throws IOException
      *           if a selector cannot be created
      */
@@ -500,7 +506,7 @@
 
     /**
      * Set up the SelectorThread with a specified queue for connections.
-     * 
+     *
      * @param acceptedQueue
      *          The BlockingQueue implementation for holding incoming accepted
      *          connections.
@@ -514,7 +520,7 @@
     /**
      * Hands off an accepted connection to be handled by this thread. This
      * method will block if the queue for new connections is at capacity.
-     * 
+     *
      * @param accepted
      *          The connection that has been accepted.
      * @return true if the connection has been successfully added.
@@ -545,8 +551,13 @@
           cleanupSelectionKey(selectionKey);
         }
       } catch (Throwable t) {
-        LOGGER.error("run() exiting due to uncaught error", t);
+        LOGGER.error("run() on SelectorThread exiting due to uncaught error", t);
       } finally {
+        try {
+          selector.close();
+        } catch (IOException e) {
+          LOGGER.error("Got an IOException while closing selector!", e);
+        }
         // This will wake up the accept thread and the other selector threads
         TThreadedSelectorServer.this.stop();
       }
@@ -560,8 +571,8 @@
      */
     private void select() {
       try {
-        // wait for io events.
-        selector.select();
+
+        doSelect();
 
         // process the io events we received
         Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
@@ -590,6 +601,77 @@
       }
     }
 
+    /**
+     * Do select and judge epoll bug happen.
+     * See : https://issues.apache.org/jira/browse/THRIFT-4251
+     */
+    private void doSelect() throws IOException {
+      long beforeSelect = System.currentTimeMillis();
+      int selectedNums = selector.select();
+      long afterSelect = System.currentTimeMillis();
+
+      if (selectedNums == 0) {
+        jvmBug++;
+      } else {
+        jvmBug = 0;
+      }
+
+      long selectedTime = afterSelect - beforeSelect;
+      if (selectedTime >= MONITOR_PERIOD) {
+        jvmBug = 0;
+      } else if (jvmBug > SELECTOR_AUTO_REBUILD_THRESHOLD) {
+        LOGGER.warn("In {} ms happen {} times jvm bug; rebuilding selector.", MONITOR_PERIOD, jvmBug);
+        rebuildSelector();
+        selector.selectNow();
+        jvmBug = 0;
+      }
+
+    }
+
+    /**
+     * Replaces the current Selector of this SelectorThread with newly created Selector to work
+     * around the infamous epoll 100% CPU bug.
+     */
+    private synchronized void rebuildSelector() {
+      final Selector oldSelector = selector;
+      if (oldSelector == null) {
+        return;
+      }
+      Selector newSelector = null;
+      try {
+        newSelector = Selector.open();
+        LOGGER.warn("Created new Selector.");
+      } catch (IOException e) {
+        LOGGER.error("Create new Selector error.", e);
+      }
+
+      for (SelectionKey key : oldSelector.selectedKeys()) {
+        if (!key.isValid() && key.readyOps() == 0)
+          continue;
+        SelectableChannel channel = key.channel();
+        Object attachment = key.attachment();
+
+        try {
+          if (attachment == null) {
+            channel.register(newSelector, key.readyOps());
+          } else {
+            channel.register(newSelector, key.readyOps(), attachment);
+          }
+        } catch (ClosedChannelException e) {
+          LOGGER.error("Register new selector key error.", e);
+        }
+
+      }
+
+      selector = newSelector;
+      try {
+        oldSelector.close();
+      } catch (IOException e) {
+        LOGGER.error("Close old selector error.", e);
+      }
+      LOGGER.warn("Replace new selector success.");
+    }
+
     private void processAcceptedConnections() {
       // Register accepted connections
       while (!stopped_) {
@@ -601,14 +683,20 @@
       }
     }
 
+    protected FrameBuffer createFrameBuffer(final TNonblockingTransport trans,
+        final SelectionKey selectionKey,
+        final AbstractSelectThread selectThread) {
+        return processorFactory_.isAsyncProcessor() ?
+                  new AsyncFrameBuffer(trans, selectionKey, selectThread) :
+                  new FrameBuffer(trans, selectionKey, selectThread);
+    }
+
     private void registerAccepted(TNonblockingTransport accepted) {
       SelectionKey clientKey = null;
       try {
         clientKey = accepted.registerSelector(selector, SelectionKey.OP_READ);
 
-        FrameBuffer frameBuffer = processorFactory_.isAsyncProcessor() ?
-                new AsyncFrameBuffer(accepted, clientKey, SelectorThread.this) :
-                new FrameBuffer(accepted, clientKey, SelectorThread.this);
+        FrameBuffer frameBuffer = createFrameBuffer(accepted, clientKey, SelectorThread.this);
 
         clientKey.attach(frameBuffer);
       } catch (IOException e) {
@@ -633,7 +721,7 @@
    * A round robin load balancer for choosing selector threads for new
    * connections.
    */
-  protected class SelectorThreadLoadBalancer {
+  protected static class SelectorThreadLoadBalancer {
     private final Collection<? extends SelectorThread> threads;
     private Iterator<? extends SelectorThread> nextThreadIterator;
 
diff --git a/lib/java/src/org/apache/thrift/transport/AutoExpandingBuffer.java b/lib/java/src/org/apache/thrift/transport/AutoExpandingBuffer.java
index b02905f..fc3aa92 100644
--- a/lib/java/src/org/apache/thrift/transport/AutoExpandingBuffer.java
+++ b/lib/java/src/org/apache/thrift/transport/AutoExpandingBuffer.java
@@ -18,6 +18,8 @@
  */
 package org.apache.thrift.transport;
 
+import java.util.Arrays;
+
 /**
  * Helper class that wraps a byte[] so that it can expand and be reused. Users
  * should call resizeIfNecessary to make sure the buffer has suitable capacity,
@@ -25,28 +27,24 @@
  * rate slightly faster than the requested capacity with the (untested)
  * objective of avoiding expensive buffer allocations and copies.
  */
-public class AutoExpandingBuffer {
+class AutoExpandingBuffer {
   private byte[] array;
 
-  private final double growthCoefficient;
-
-  public AutoExpandingBuffer(int initialCapacity, double growthCoefficient) {
-    if (growthCoefficient < 1.0) {
-      throw new IllegalArgumentException("Growth coefficient must be >= 1.0");
-    }
-    array = new byte[initialCapacity];
-    this.growthCoefficient = growthCoefficient;
+  public AutoExpandingBuffer(int initialCapacity) {
+    this.array = new byte[initialCapacity];
   }
 
   public void resizeIfNecessary(int size) {
-    if (array.length < size) {
-      byte[] newBuf = new byte[(int)(size * growthCoefficient)];
-      System.arraycopy(array, 0, newBuf, 0, array.length);
-      array = newBuf;
+    final int currentCapacity = this.array.length;
+    if (currentCapacity < size) {
+      // Increase by a factor of 1.5x
+      int growCapacity = currentCapacity + (currentCapacity >> 1);
+      int newCapacity = Math.max(growCapacity, size);
+      this.array = Arrays.copyOf(array, newCapacity);
     }
   }
 
   public byte[] array() {
-    return array;
+    return this.array;
   }
 }
diff --git a/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferReadTransport.java b/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferReadTransport.java
index 081bc48..a28d254 100644
--- a/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferReadTransport.java
+++ b/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferReadTransport.java
@@ -28,8 +28,8 @@
   private int pos = 0;
   private int limit = 0;
 
-  public AutoExpandingBufferReadTransport(int initialCapacity, double overgrowthCoefficient) {
-    this.buf = new AutoExpandingBuffer(initialCapacity, overgrowthCoefficient);
+  public AutoExpandingBufferReadTransport(int initialCapacity) {
+    this.buf = new AutoExpandingBuffer(initialCapacity);
   }
 
   public void fill(TTransport inTrans, int length) throws TTransportException {
diff --git a/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferWriteTransport.java b/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferWriteTransport.java
index 9b35693..ec7e7d4 100644
--- a/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferWriteTransport.java
+++ b/lib/java/src/org/apache/thrift/transport/AutoExpandingBufferWriteTransport.java
@@ -25,10 +25,29 @@
 
   private final AutoExpandingBuffer buf;
   private int pos;
+  private int res;
 
-  public AutoExpandingBufferWriteTransport(int initialCapacity, double growthCoefficient) {
-    this.buf = new AutoExpandingBuffer(initialCapacity, growthCoefficient);
-    this.pos = 0;
+  /**
+   * Constructor.
+   * @param initialCapacity the initial capacity of the buffer
+   * @param frontReserve space, if any, to reserve at the beginning such
+   *                     that the first write is after this reserve.
+   *                     This allows framed transport to reserve space
+   *                     for the frame buffer length.
+   * @throws IllegalArgumentException if initialCapacity is less than one
+   * @throws IllegalArgumentException if frontReserve is less than zero
+   * @throws IllegalArgumentException if frontReserve is greater than initialCapacity
+   */
+  public AutoExpandingBufferWriteTransport(int initialCapacity, int frontReserve) {
+    if (initialCapacity < 1) {
+      throw new IllegalArgumentException("initialCapacity");
+    }
+    if (frontReserve < 0 || initialCapacity < frontReserve) {
+      throw new IllegalArgumentException("frontReserve");
+    }
+    this.buf = new AutoExpandingBuffer(initialCapacity);
+    this.pos = frontReserve;
+    this.res = frontReserve;
   }
 
   @Override
@@ -56,11 +75,14 @@
     return buf;
   }
 
-  public int getPos() {
+  /**
+   * @return length of the buffer, including any front reserve
+   */
+  public int getLength() {
     return pos;
   }
 
   public void reset() {
-    pos = 0;
+    pos = res;
   }
 }
diff --git a/lib/java/src/org/apache/thrift/transport/TByteBuffer.java b/lib/java/src/org/apache/thrift/transport/TByteBuffer.java
new file mode 100644
index 0000000..b6b0657
--- /dev/null
+++ b/lib/java/src/org/apache/thrift/transport/TByteBuffer.java
@@ -0,0 +1,87 @@
+package org.apache.thrift.transport;
+
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+
+/**
+ * ByteBuffer-backed implementation of TTransport.
+ */
+public final class TByteBuffer extends TTransport {
+  private final ByteBuffer byteBuffer;
+
+  /**
+   * Creates a new TByteBuffer wrapping a given NIO ByteBuffer.
+   */
+  public TByteBuffer(ByteBuffer byteBuffer) {
+    this.byteBuffer = byteBuffer;
+  }
+
+  @Override
+  public boolean isOpen() {
+    return true;
+  }
+
+  @Override
+  public void open() {
+  }
+
+  @Override
+  public void close() {
+  }
+
+  @Override
+  public int read(byte[] buf, int off, int len) throws TTransportException {
+    final int n = Math.min(byteBuffer.remaining(), len);
+    if (n > 0) {
+      try {
+        byteBuffer.get(buf, off, n);
+      } catch (BufferUnderflowException e) {
+        throw new TTransportException("Unexpected end of input buffer", e);
+      }
+    }
+    return n;
+  }
+
+  @Override
+  public void write(byte[] buf, int off, int len) throws TTransportException {
+    try {
+      byteBuffer.put(buf, off, len);
+    } catch (BufferOverflowException e) {
+      throw new TTransportException("Not enough room in output buffer", e);
+    }
+  }
+
+  /**
+   * Get the underlying NIO ByteBuffer.
+   */
+  public ByteBuffer getByteBuffer() {
+    return byteBuffer;
+  }
+
+  /**
+   * Convenience method to call clear() on the underlying NIO ByteBuffer.
+   */
+  public TByteBuffer clear() {
+    byteBuffer.clear();
+    return this;
+  }
+
+  /**
+   * Convenience method to call flip() on the underlying NIO ByteBuffer.
+     */
+  public TByteBuffer flip() {
+    byteBuffer.flip();
+    return this;
+  }
+
+  /**
+   * Convenience method to convert the underlying NIO ByteBuffer to a
+   * plain old byte array.
+   */
+  public byte[] toByteArray() {
+    final byte[] data = new byte[byteBuffer.remaining()];
+    byteBuffer.slice().get(data);
+    return data;
+  }
+}
diff --git a/lib/java/src/org/apache/thrift/transport/TFastFramedTransport.java b/lib/java/src/org/apache/thrift/transport/TFastFramedTransport.java
index e32b7db..a1fd249 100644
--- a/lib/java/src/org/apache/thrift/transport/TFastFramedTransport.java
+++ b/lib/java/src/org/apache/thrift/transport/TFastFramedTransport.java
@@ -19,12 +19,12 @@
 package org.apache.thrift.transport;
 
 /**
- * This transport is wire compatible with {@link TFramedTransport}, but makes 
+ * This transport is wire compatible with {@link TFramedTransport}, but makes
  * use of reusable, expanding read and write buffers in order to avoid
  * allocating new byte[]s all the time. Since the buffers only expand, you
  * should probably only use this transport if your messages are not too variably
  * large, unless the persistent memory cost is not an issue.
- * 
+ *
  * This implementation is NOT threadsafe.
  */
 public class TFastFramedTransport extends TTransport {
@@ -65,7 +65,8 @@
 
   private final TTransport underlying;
   private final AutoExpandingBufferWriteTransport writeBuffer;
-  private final AutoExpandingBufferReadTransport readBuffer;
+  private AutoExpandingBufferReadTransport readBuffer;
+  private final int initialBufferCapacity;
   private final byte[] i32buf = new byte[4];
   private final int maxLength;
 
@@ -91,7 +92,7 @@
   }
 
   /**
-   * 
+   *
    * @param underlying Transport that real reads and writes will go through to.
    * @param initialBufferCapacity The initial size of the read and write buffers.
    * In practice, it's not critical to set this unless you know in advance that
@@ -104,8 +105,9 @@
   public TFastFramedTransport(TTransport underlying, int initialBufferCapacity, int maxLength) {
     this.underlying = underlying;
     this.maxLength = maxLength;
-    writeBuffer = new AutoExpandingBufferWriteTransport(initialBufferCapacity, 1.5);
-    readBuffer = new AutoExpandingBufferReadTransport(initialBufferCapacity, 1.5);
+    this.initialBufferCapacity = initialBufferCapacity;
+    readBuffer = new AutoExpandingBufferReadTransport(initialBufferCapacity);
+    writeBuffer = new AutoExpandingBufferWriteTransport(initialBufferCapacity, 4);
   }
 
   @Override
@@ -141,11 +143,14 @@
     int size = TFramedTransport.decodeFrameSize(i32buf);
 
     if (size < 0) {
-      throw new TTransportException("Read a negative frame size (" + size + ")!");
+      close();
+      throw new TTransportException(TTransportException.CORRUPTED_DATA, "Read a negative frame size (" + size + ")!");
     }
 
     if (size > maxLength) {
-      throw new TTransportException("Frame size (" + size + ") larger than max length (" + maxLength + ")!");
+      close();
+      throw new TTransportException(TTransportException.CORRUPTED_DATA,
+          "Frame size (" + size + ") larger than max length (" + maxLength + ")!");
     }
 
     readBuffer.fill(underlying, size);
@@ -161,12 +166,19 @@
     readBuffer.consumeBuffer(len);
   }
 
+  /**
+   * Only clears the read buffer!
+   */
+  public void clear() {
+    readBuffer = new AutoExpandingBufferReadTransport(initialBufferCapacity);
+  }
+
   @Override
   public void flush() throws TTransportException {
-    int length = writeBuffer.getPos();
-    TFramedTransport.encodeFrameSize(length, i32buf);
-    underlying.write(i32buf, 0, 4);
-    underlying.write(writeBuffer.getBuf().array(), 0, length);
+    int payloadLength = writeBuffer.getLength() - 4;        
+    byte[] data = writeBuffer.getBuf().array();
+    TFramedTransport.encodeFrameSize(payloadLength, data);
+    underlying.write(data, 0, payloadLength + 4);
     writeBuffer.reset();
     underlying.flush();
   }
diff --git a/lib/java/src/org/apache/thrift/transport/TFileProcessor.java b/lib/java/src/org/apache/thrift/transport/TFileProcessor.java
index 4e6a198..96087d1 100644
--- a/lib/java/src/org/apache/thrift/transport/TFileProcessor.java
+++ b/lib/java/src/org/apache/thrift/transport/TFileProcessor.java
@@ -27,8 +27,6 @@
 /**
  * FileProcessor: helps in processing files generated by TFileTransport.
  * Port of original cpp implementation
- *
- * @author Joydeep Sen Sarma <jssarma@facebook.com>
  */
 public class TFileProcessor {
 
diff --git a/lib/java/src/org/apache/thrift/transport/TFileTransport.java b/lib/java/src/org/apache/thrift/transport/TFileTransport.java
index f5abe53..c011c52 100644
--- a/lib/java/src/org/apache/thrift/transport/TFileTransport.java
+++ b/lib/java/src/org/apache/thrift/transport/TFileTransport.java
@@ -33,19 +33,17 @@
  * It may make better sense to provide a basic stream access on top of the framed file format
  * The FileTransport can then be a user of this framed file format with some additional logic
  * for chunking.
- *
- * @author Joydeep Sen Sarma <jssarma@facebook.com>
  */
 public class TFileTransport extends TTransport {
 
-  public static class truncableBufferedInputStream extends BufferedInputStream {
+  public static class TruncableBufferedInputStream extends BufferedInputStream {
     public void trunc() {
       pos = count = 0;
     }        
-    public truncableBufferedInputStream(InputStream in) {
+    public TruncableBufferedInputStream(InputStream in) {
       super(in);
     }
-    public truncableBufferedInputStream(InputStream in, int size) {
+    public TruncableBufferedInputStream(InputStream in, int size) {
       super(in, size);
     }
   }
@@ -87,7 +85,7 @@
     }
   };
 
-  public static class chunkState {
+  public static class ChunkState {
     /**
      * Chunk Size. Must be same across all implementations
      */
@@ -96,8 +94,8 @@
     private int chunk_size_ = DEFAULT_CHUNK_SIZE;
     private long offset_ = 0;
 
-    public chunkState() {}
-    public chunkState(int chunk_size) { chunk_size_ = chunk_size; }
+    public ChunkState() {}
+    public ChunkState(int chunk_size) { chunk_size_ = chunk_size; }
 
     public void skip(int size) {offset_ += size; }
     public void seek(long offset) {offset_ = offset;}
@@ -108,7 +106,7 @@
     public long getOffset() { return (offset_);}
   }
 
-  public static enum tailPolicy {
+  public static enum TailPolicy {
 
     NOWAIT(0, 0),
       WAIT_FOREVER(500, -1);
@@ -133,7 +131,7 @@
      * @param retries number of retries
      */
 
-    tailPolicy(int timeout, int retries) {
+    TailPolicy(int timeout, int retries) {
       timeout_ = timeout;
       retries_ = retries;
     }
@@ -142,7 +140,7 @@
   /**
    * Current tailing policy
    */
-  tailPolicy currentPolicy_ = tailPolicy.NOWAIT;
+  TailPolicy currentPolicy_ = TailPolicy.NOWAIT;
 
 
   /** 
@@ -169,12 +167,7 @@
   /**
    * current Chunk state
    */
-  chunkState cs = null;
-
-  /**
-   * Read timeout
-   */
-  private int readTimeout_ = 0;
+  ChunkState cs = null;
 
   /**
    * is read only?
@@ -186,7 +179,7 @@
    * 
    * @return current read policy
    */
-  public tailPolicy getTailPolicy() {
+  public TailPolicy getTailPolicy() {
     return (currentPolicy_);
   }
 
@@ -196,8 +189,8 @@
    * @param policy New policy to set
    * @return Old policy
    */
-  public tailPolicy setTailPolicy(tailPolicy policy) {
-    tailPolicy old = currentPolicy_;
+  public TailPolicy setTailPolicy(TailPolicy policy) {
+    TailPolicy old = currentPolicy_;
     currentPolicy_ = policy;
     return (old);
   }
@@ -212,10 +205,10 @@
     InputStream is;
     try {
       if(inputStream_ != null) {
-        ((truncableBufferedInputStream)inputStream_).trunc();
+        ((TruncableBufferedInputStream)inputStream_).trunc();
         is = inputStream_;
       } else {
-        is = new truncableBufferedInputStream(inputFile_.getInputStream());
+        is = new TruncableBufferedInputStream(inputFile_.getInputStream());
       }
     } catch (IOException iox) {
       System.err.println("createInputStream: "+iox.getMessage());
@@ -236,7 +229,7 @@
    * @return number of bytes read
    */
   private int tailRead(InputStream is, byte[] buf, 
-                       int off, int len, tailPolicy tp) throws TTransportException {
+                       int off, int len, TailPolicy tp) throws TTransportException {
     int orig_len = len;
     try {
       int retries = 0;
@@ -369,11 +362,11 @@
 
     try {
       inputStream_ = createInputStream();
-      cs = new chunkState();
+      cs = new ChunkState();
       currentEvent_ = new Event(new byte [256]);
 
       if(!readOnly_)
-        outputStream_ = new BufferedOutputStream(inputFile_.getOutputStream(), 8192);
+        outputStream_ = new BufferedOutputStream(inputFile_.getOutputStream());
     } catch (IOException iox) {
       throw new TTransportException(TTransportException.NOT_OPEN, iox);
     }
@@ -545,7 +538,7 @@
     if(seekToEnd) {
       // waiting forever here - otherwise we can hit EOF and end up
       // having consumed partial data from the data stream.
-      tailPolicy old = setTailPolicy(tailPolicy.WAIT_FOREVER);
+      TailPolicy old = setTailPolicy(TailPolicy.WAIT_FOREVER);
       while(cs.getOffset() < eofOffset) { readEvent(); }
       currentEvent_.setAvailable(0);
       setTailPolicy(old);
diff --git a/lib/java/src/org/apache/thrift/transport/TFramedTransport.java b/lib/java/src/org/apache/thrift/transport/TFramedTransport.java
index c948aa4..a006c3a 100644
--- a/lib/java/src/org/apache/thrift/transport/TFramedTransport.java
+++ b/lib/java/src/org/apache/thrift/transport/TFramedTransport.java
@@ -45,7 +45,8 @@
   /**
    * Buffer for input
    */
-  private TMemoryInputTransport readBuffer_ = new TMemoryInputTransport(new byte[0]);
+  private final TMemoryInputTransport readBuffer_ =
+    new TMemoryInputTransport(new byte[0]);
 
   public static class Factory extends TTransportFactory {
     private int maxLength_;
@@ -65,16 +66,25 @@
   }
 
   /**
+   * Something to fill in the first four bytes of the buffer
+   * to make room for the frame size.  This allows the
+   * implementation to write once instead of twice.
+   */
+  private static final byte[] sizeFiller_ = new byte[] { 0x00, 0x00, 0x00, 0x00 };
+
+  /**
    * Constructor wraps around another transport
    */
   public TFramedTransport(TTransport transport, int maxLength) {
     transport_ = transport;
     maxLength_ = maxLength;
+    writeBuffer_.write(sizeFiller_, 0, 4);
   }
 
   public TFramedTransport(TTransport transport) {
     transport_ = transport;
     maxLength_ = TFramedTransport.DEFAULT_MAX_LENGTH;
+    writeBuffer_.write(sizeFiller_, 0, 4);
   }
 
   public void open() throws TTransportException {
@@ -90,11 +100,9 @@
   }
 
   public int read(byte[] buf, int off, int len) throws TTransportException {
-    if (readBuffer_ != null) {
-      int got = readBuffer_.read(buf, off, len);
-      if (got > 0) {
-        return got;
-      }
+    int got = readBuffer_.read(buf, off, len);
+    if (got > 0) {
+      return got;
     }
 
     // Read another frame of data
@@ -123,6 +131,10 @@
     readBuffer_.consumeBuffer(len);
   }
 
+  public void clear() {
+    readBuffer_.clear();
+  }
+
   private final byte[] i32buf = new byte[4];
 
   private void readFrame() throws TTransportException {
@@ -130,11 +142,14 @@
     int size = decodeFrameSize(i32buf);
 
     if (size < 0) {
-      throw new TTransportException("Read a negative frame size (" + size + ")!");
+      close();
+      throw new TTransportException(TTransportException.CORRUPTED_DATA, "Read a negative frame size (" + size + ")!");
     }
 
     if (size > maxLength_) {
-      throw new TTransportException("Frame size (" + size + ") larger than max length (" + maxLength_ + ")!");
+      close();
+      throw new TTransportException(TTransportException.CORRUPTED_DATA,
+          "Frame size (" + size + ") larger than max length (" + maxLength_ + ")!");
     }
 
     byte[] buff = new byte[size];
@@ -149,12 +164,12 @@
   @Override
   public void flush() throws TTransportException {
     byte[] buf = writeBuffer_.get();
-    int len = writeBuffer_.len();
+    int len = writeBuffer_.len() - 4;       // account for the prepended frame size
     writeBuffer_.reset();
+    writeBuffer_.write(sizeFiller_, 0, 4);  // make room for the next frame's size data
 
-    encodeFrameSize(len, i32buf);
-    transport_.write(i32buf, 0, 4);
-    transport_.write(buf, 0, len);
+    encodeFrameSize(len, buf);              // this is the frame length without the filler
+    transport_.write(buf, 0, len + 4);      // we have to write the frame size and frame data
     transport_.flush();
   }
 
@@ -166,7 +181,7 @@
   }
 
   public static final int decodeFrameSize(final byte[] buf) {
-    return 
+    return
       ((buf[0] & 0xff) << 24) |
       ((buf[1] & 0xff) << 16) |
       ((buf[2] & 0xff) <<  8) |
diff --git a/lib/java/src/org/apache/thrift/transport/THttpClient.java b/lib/java/src/org/apache/thrift/transport/THttpClient.java
index 5a5b37c..c3063fe 100644
--- a/lib/java/src/org/apache/thrift/transport/THttpClient.java
+++ b/lib/java/src/org/apache/thrift/transport/THttpClient.java
@@ -304,6 +304,9 @@
           throw new TTransportException(ioe);
         }
       }
+      if (post != null) {
+        post.releaseConnection();
+      }
     }
   }
 
diff --git a/lib/java/src/org/apache/thrift/transport/TMemoryBuffer.java b/lib/java/src/org/apache/thrift/transport/TMemoryBuffer.java
index 53354af..b19ac86 100644
--- a/lib/java/src/org/apache/thrift/transport/TMemoryBuffer.java
+++ b/lib/java/src/org/apache/thrift/transport/TMemoryBuffer.java
@@ -20,7 +20,7 @@
 package org.apache.thrift.transport;
 
 import org.apache.thrift.TByteArrayOutputStream;
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
 
 /**
  * Memory buffer-based implementation of the TTransport interface.
@@ -30,6 +30,8 @@
    * Create a TMemoryBuffer with an initial buffer size of <i>size</i>. The
    * internal buffer will grow as necessary to accommodate the size of the data
    * being written to it.
+   *
+   * @param size the initial size of the buffer
    */
   public TMemoryBuffer(int size) {
     arr_ = new TByteArrayOutputStream(size);
@@ -69,20 +71,20 @@
   /**
    * Output the contents of the memory buffer as a String, using the supplied
    * encoding
-   * @param enc  the encoding to use
+   * @param charset the encoding to use
    * @return the contents of the memory buffer as a String
    */
-  public String toString(String enc) throws UnsupportedEncodingException {
-    return arr_.toString(enc);
+  public String toString(Charset charset) {
+    return arr_.toString(charset);
   }
 
   public String inspect() {
-    String buf = "";
+    StringBuilder buf = new StringBuilder();
     byte[] bytes = arr_.toByteArray();
     for (int i = 0; i < bytes.length; i++) {
-      buf += (pos_ == i ? "==>" : "" ) + Integer.toHexString(bytes[i] & 0xff) + " ";
+      buf.append(pos_ == i ? "==>" : "" ).append(Integer.toHexString(bytes[i] & 0xff)).append(" ");
     }
-    return buf;
+    return buf.toString();
   }
 
   // The contents of the buffer
diff --git a/lib/java/src/org/apache/thrift/transport/TNonblockingServerSocket.java b/lib/java/src/org/apache/thrift/transport/TNonblockingServerSocket.java
index 25b487e..ef82ac2 100644
--- a/lib/java/src/org/apache/thrift/transport/TNonblockingServerSocket.java
+++ b/lib/java/src/org/apache/thrift/transport/TNonblockingServerSocket.java
@@ -37,7 +37,7 @@
  * Wrapper around ServerSocketChannel
  */
 public class TNonblockingServerSocket extends TNonblockingServerTransport {
-  private static final Logger LOGGER = LoggerFactory.getLogger(TNonblockingServerTransport.class.getName());
+  private static final Logger LOGGER = LoggerFactory.getLogger(TNonblockingServerSocket.class.getName());
 
   /**
    * This channel is where all the nonblocking magic happens.
@@ -54,6 +54,9 @@
    */
   private int clientTimeout_ = 0;
 
+  public static class NonblockingAbstractServerSocketArgs extends
+      AbstractServerTransportArgs<NonblockingAbstractServerSocketArgs> {}
+
   /**
    * Creates just a port listening server socket
    */
@@ -65,7 +68,7 @@
    * Creates just a port listening server socket
    */
   public TNonblockingServerSocket(int port, int clientTimeout) throws TTransportException {
-    this(new InetSocketAddress(port), clientTimeout);
+    this(new NonblockingAbstractServerSocketArgs().port(port).clientTimeout(clientTimeout));
   }
 
   public TNonblockingServerSocket(InetSocketAddress bindAddr) throws TTransportException {
@@ -73,7 +76,11 @@
   }
 
   public TNonblockingServerSocket(InetSocketAddress bindAddr, int clientTimeout) throws TTransportException {
-    clientTimeout_ = clientTimeout;
+    this(new NonblockingAbstractServerSocketArgs().bindAddr(bindAddr).clientTimeout(clientTimeout));
+  }
+
+  public TNonblockingServerSocket(NonblockingAbstractServerSocketArgs args) throws TTransportException {
+    clientTimeout_ = args.clientTimeout;
     try {
       serverSocketChannel = ServerSocketChannel.open();
       serverSocketChannel.configureBlocking(false);
@@ -83,10 +90,10 @@
       // Prevent 2MSL delay problem on server restarts
       serverSocket_.setReuseAddress(true);
       // Bind to listening port
-      serverSocket_.bind(bindAddr);
+      serverSocket_.bind(args.bindAddr, args.backlog);
     } catch (IOException ioe) {
       serverSocket_ = null;
-      throw new TTransportException("Could not create ServerSocket on address " + bindAddr.toString() + ".");
+      throw new TTransportException("Could not create ServerSocket on address " + args.bindAddr.toString() + ".", ioe);
     }
   }
 
@@ -147,4 +154,10 @@
     close();
   }
 
+  public int getPort() {
+    if (serverSocket_ == null)
+      return -1;
+    return serverSocket_.getLocalPort();
+  }
+
 }
diff --git a/lib/java/src/org/apache/thrift/transport/TNonblockingSocket.java b/lib/java/src/org/apache/thrift/transport/TNonblockingSocket.java
index 482bd14..f86a48b 100644
--- a/lib/java/src/org/apache/thrift/transport/TNonblockingSocket.java
+++ b/lib/java/src/org/apache/thrift/transport/TNonblockingSocket.java
@@ -55,7 +55,6 @@
    * Create a new nonblocking socket transport that will be connected to host:port.
    * @param host
    * @param port
-   * @throws TTransportException
    * @throws IOException
    */
   public TNonblockingSocket(String host, int port, int timeout) throws IOException {
@@ -85,6 +84,7 @@
     Socket socket = socketChannel.socket();
     socket.setSoLinger(false, 0);
     socket.setTcpNoDelay(true);
+    socket.setKeepAlive(true);
     setTimeout(timeout);
   }
 
diff --git a/lib/java/src/org/apache/thrift/transport/TSSLTransportFactory.java b/lib/java/src/org/apache/thrift/transport/TSSLTransportFactory.java
index 25df97f..2232a31 100644
--- a/lib/java/src/org/apache/thrift/transport/TSSLTransportFactory.java
+++ b/lib/java/src/org/apache/thrift/transport/TSSLTransportFactory.java
@@ -20,8 +20,14 @@
 package org.apache.thrift.transport;
 
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
 import java.net.InetAddress;
+import java.net.URL;
+import java.net.MalformedURLException;
 import java.security.KeyStore;
+import java.util.Arrays;
 
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
@@ -32,7 +38,7 @@
 import javax.net.ssl.TrustManagerFactory;
 
 /**
- *  A Factory for providing and setting up Client and Server SSL wrapped 
+ *  A Factory for providing and setting up Client and Server SSL wrapped
  *  TSocket and TServerSocket
  */
 public class TSSLTransportFactory {
@@ -41,24 +47,24 @@
    * Get a SSL wrapped TServerSocket bound to the specified port. In this
    * configuration the default settings are used. Default settings are retrieved
    * from System properties that are set.
-   * 
+   *
    * Example system properties:
-   * -Djavax.net.ssl.trustStore=<truststore location>
+   * -Djavax.net.ssl.trustStore=&lt;truststore location&gt;
    * -Djavax.net.ssl.trustStorePassword=password
-   * -Djavax.net.ssl.keyStore=<keystore location>
+   * -Djavax.net.ssl.keyStore=&lt;keystore location&gt;
    * -Djavax.net.ssl.keyStorePassword=password
-   * 
+   *
    * @param port
    * @return A SSL wrapped TServerSocket
    * @throws TTransportException
    */
   public static TServerSocket getServerSocket(int port) throws TTransportException {
-    return getServerSocket(port, 0); 
+    return getServerSocket(port, 0);
   }
 
   /**
    * Get a default SSL wrapped TServerSocket bound to the specified port
-   * 
+   *
    * @param port
    * @param clientTimeout
    * @return A SSL wrapped TServerSocket
@@ -70,7 +76,7 @@
 
   /**
    * Get a default SSL wrapped TServerSocket bound to the specified port and interface
-   * 
+   *
    * @param port
    * @param clientTimeout
    * @param ifAddress
@@ -79,14 +85,14 @@
    */
   public static TServerSocket getServerSocket(int port, int clientTimeout, boolean clientAuth, InetAddress ifAddress) throws TTransportException {
     SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
-    return createServer(factory, port, clientTimeout, clientAuth, ifAddress, null); 
+    return createServer(factory, port, clientTimeout, clientAuth, ifAddress, null);
   }
 
   /**
-   * Get a configured SSL wrapped TServerSocket bound to the specified port and interface. 
-   * Here the TSSLTransportParameters are used to set the values for the algorithms, keystore, 
+   * Get a configured SSL wrapped TServerSocket bound to the specified port and interface.
+   * Here the TSSLTransportParameters are used to set the values for the algorithms, keystore,
    * truststore and other settings
-   * 
+   *
    * @param port
    * @param clientTimeout
    * @param ifAddress
@@ -112,7 +118,8 @@
       if (params != null && params.cipherSuites != null) {
         serverSocket.setEnabledCipherSuites(params.cipherSuites);
       }
-      return new TServerSocket(serverSocket, timeout);
+      return new TServerSocket(new TServerSocket.ServerSocketTransportArgs().
+        serverSocket(serverSocket).clientTimeout(timeout));
     } catch (Exception e) {
       throw new TTransportException("Could not bind to port " + port, e);
     }
@@ -120,9 +127,9 @@
 
   /**
    * Get a default SSL wrapped TSocket connected to the specified host and port. All
-   * the client methods return a bound connection. So there is no need to call open() on the 
+   * the client methods return a bound connection. So there is no need to call open() on the
    * TTransport.
-   * 
+   *
    * @param host
    * @param port
    * @param timeout
@@ -136,7 +143,7 @@
 
   /**
    * Get a default SSL wrapped TSocket connected to the specified host and port.
-   * 
+   *
    * @param host
    * @param port
    * @return A SSL wrapped TSocket
@@ -147,9 +154,9 @@
   }
 
   /**
-   * Get a custom configured SSL wrapped TSocket. The SSL settings are obtained from the 
+   * Get a custom configured SSL wrapped TSocket. The SSL settings are obtained from the
    * passed in TSSLTransportParameters.
-   * 
+   *
    * @param host
    * @param port
    * @param timeout
@@ -168,6 +175,9 @@
 
   private static SSLContext createSSLContext(TSSLTransportParameters params) throws TTransportException {
     SSLContext ctx;
+    InputStream in = null;
+    InputStream is = null;
+
     try {
       ctx = SSLContext.getInstance(params.protocol);
       TrustManagerFactory tmf = null;
@@ -176,14 +186,25 @@
       if (params.isTrustStoreSet) {
         tmf = TrustManagerFactory.getInstance(params.trustManagerType);
         KeyStore ts = KeyStore.getInstance(params.trustStoreType);
-        ts.load(new FileInputStream(params.trustStore), params.trustPass.toCharArray());
+        if (params.trustStoreStream != null) {
+          in = params.trustStoreStream;
+        } else {
+          in = getStoreAsStream(params.trustStore);
+        }
+        ts.load(in,
+                (params.trustPass != null ? params.trustPass.toCharArray() : null));
         tmf.init(ts);
       }
 
       if (params.isKeyStoreSet) {
         kmf = KeyManagerFactory.getInstance(params.keyManagerType);
         KeyStore ks = KeyStore.getInstance(params.keyStoreType);
-        ks.load(new FileInputStream(params.keyStore), params.keyPass.toCharArray());
+        if (params.keyStoreStream != null) {
+        	is = params.keyStoreStream;
+        } else {
+        	is = getStoreAsStream(params.keyStore);
+        }
+        ks.load(is, params.keyPass.toCharArray());
         kmf.init(ks, params.keyPass.toCharArray());
       }
 
@@ -199,10 +220,50 @@
 
     } catch (Exception e) {
       throw new TTransportException("Error creating the transport", e);
+    } finally {
+      if (in != null) {
+        try {
+          in.close();
+        } catch (IOException e) {
+          e.printStackTrace();
+        }
+      }
+      if (is != null) {
+        try {
+          is.close();
+        } catch (IOException e) {
+          e.printStackTrace();
+        }
+      }
     }
+
     return ctx;
   }
 
+  private static InputStream getStoreAsStream(String store) throws IOException {
+    try {
+      return new FileInputStream(store);
+    } catch(FileNotFoundException e) {
+    }
+
+    InputStream storeStream = null;
+    try {
+      storeStream = new URL(store).openStream();
+      if (storeStream != null) {
+        return storeStream;
+      }
+    } catch(MalformedURLException e) {
+    }
+
+    storeStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(store);
+
+    if (storeStream != null) {
+      return storeStream;
+    } else {
+      throw new IOException("Could not load file: " + store);
+    }
+  }
+
   private static TSocket createClient(SSLSocketFactory factory, String host, int port, int timeout) throws TTransportException {
     try {
       SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
@@ -220,10 +281,12 @@
   public static class TSSLTransportParameters {
     protected String protocol = "TLS";
     protected String keyStore;
+    protected InputStream keyStoreStream;
     protected String keyPass;
     protected String keyManagerType = KeyManagerFactory.getDefaultAlgorithm();
     protected String keyStoreType = "JKS";
     protected String trustStore;
+    protected InputStream trustStoreStream;
     protected String trustPass;
     protected String trustManagerType = TrustManagerFactory.getDefaultAlgorithm();
     protected String trustStoreType = "JKS";
@@ -236,7 +299,7 @@
 
     /**
      * Create parameters specifying the protocol and cipher suites
-     * 
+     *
      * @param protocol The specific protocol (TLS/SSL) can be specified with versions
      * @param cipherSuites
      */
@@ -247,7 +310,7 @@
     /**
      * Create parameters specifying the protocol, cipher suites and if client authentication
      * is required
-     * 
+     *
      * @param protocol The specific protocol (TLS/SSL) can be specified with versions
      * @param cipherSuites
      * @param clientAuth
@@ -256,13 +319,13 @@
       if (protocol != null) {
         this.protocol = protocol;
       }
-      this.cipherSuites = cipherSuites;
+      this.cipherSuites = cipherSuites != null ? Arrays.copyOf(cipherSuites, cipherSuites.length) : null;
       this.clientAuth = clientAuth;
     }
 
     /**
      * Set the keystore, password, certificate type and the store type
-     * 
+     *
      * @param keyStore Location of the Keystore on disk
      * @param keyPass Keystore password
      * @param keyManagerType The default is X509
@@ -279,20 +342,43 @@
       }
       isKeyStoreSet = true;
     }
-
+    
+    /**
+     * Set the keystore, password, certificate type and the store type
+     *
+     * @param keyStoreStream Keystore content input stream
+     * @param keyPass Keystore password
+     * @param keyManagerType The default is X509
+     * @param keyStoreType The default is JKS
+     */
+    public void setKeyStore(InputStream keyStoreStream, String keyPass, String keyManagerType, String keyStoreType) {
+    	this.keyStoreStream = keyStoreStream;
+    	setKeyStore("", keyPass, keyManagerType, keyStoreType);
+    }
+    
     /**
      * Set the keystore and password
-     * 
+     *
      * @param keyStore Location of the Keystore on disk
      * @param keyPass Keystore password
      */
     public void setKeyStore(String keyStore, String keyPass) {
       setKeyStore(keyStore, keyPass, null, null);
     }
-
+    
+    /**
+     * Set the keystore and password
+     *
+     * @param keyStoreStream Keystore content input stream
+     * @param keyPass Keystore password
+     */
+    public void setKeyStore(InputStream keyStoreStream, String keyPass) {
+      setKeyStore(keyStoreStream, keyPass, null, null);
+    }
+    
     /**
      * Set the truststore, password, certificate type and the store type
-     * 
+     *
      * @param trustStore Location of the Truststore on disk
      * @param trustPass Truststore password
      * @param trustManagerType The default is X509
@@ -309,24 +395,47 @@
       }
       isTrustStoreSet = true;
     }
+    
+    /**
+     * Set the truststore, password, certificate type and the store type
+     *
+     * @param trustStoreStream Truststore content input stream
+     * @param trustPass Truststore password
+     * @param trustManagerType The default is X509
+     * @param trustStoreType The default is JKS
+     */
+    public void setTrustStore(InputStream trustStoreStream, String trustPass, String trustManagerType, String trustStoreType) {
+      this.trustStoreStream = trustStoreStream;
+      setTrustStore("", trustPass, trustManagerType, trustStoreType);
+    }
 
     /**
      * Set the truststore and password
-     * 
+     *
      * @param trustStore Location of the Truststore on disk
      * @param trustPass Truststore password
      */
     public void setTrustStore(String trustStore, String trustPass) {
       setTrustStore(trustStore, trustPass, null, null);
     }
+    
+    /**
+     * Set the truststore and password
+     *
+     * @param trustStoreStream Truststore content input stream
+     * @param trustPass Truststore password
+     */
+    public void setTrustStore(InputStream trustStoreStream, String trustPass) {
+      setTrustStore(trustStoreStream, trustPass, null, null);
+    }
 
     /**
      * Set if client authentication is required
-     * 
+     *
      * @param clientAuth
      */
     public void requireClientAuth(boolean clientAuth) {
       this.clientAuth = clientAuth;
-    }
-  }
+		}
+	}
 }
diff --git a/lib/java/src/org/apache/thrift/transport/TSaslClientTransport.java b/lib/java/src/org/apache/thrift/transport/TSaslClientTransport.java
index 5aa0ccd..4b1ca0a 100644
--- a/lib/java/src/org/apache/thrift/transport/TSaslClientTransport.java
+++ b/lib/java/src/org/apache/thrift/transport/TSaslClientTransport.java
@@ -19,6 +19,7 @@
 
 package org.apache.thrift.transport;
 
+import java.nio.charset.StandardCharsets;
 import java.util.Map;
 
 import javax.security.auth.callback.CallbackHandler;
@@ -96,7 +97,7 @@
     LOGGER.debug("Sending mechanism name {} and initial response of length {}", mechanism,
         initialResponse.length);
 
-    byte[] mechanismBytes = mechanism.getBytes();
+    byte[] mechanismBytes = mechanism.getBytes(StandardCharsets.UTF_8);
     sendSaslMessage(NegotiationStatus.START,
                     mechanismBytes);
     // Send initial response
diff --git a/lib/java/src/org/apache/thrift/transport/TSaslServerTransport.java b/lib/java/src/org/apache/thrift/transport/TSaslServerTransport.java
index 1a74d53..39b81ca 100644
--- a/lib/java/src/org/apache/thrift/transport/TSaslServerTransport.java
+++ b/lib/java/src/org/apache/thrift/transport/TSaslServerTransport.java
@@ -20,6 +20,7 @@
 package org.apache.thrift.transport;
 
 import java.lang.ref.WeakReference;
+import java.nio.charset.StandardCharsets;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -126,16 +127,16 @@
 
     LOGGER.debug("Received start message with status {}", message.status);
     if (message.status != NegotiationStatus.START) {
-      sendAndThrowMessage(NegotiationStatus.ERROR, "Expecting START status, received " + message.status);
+      throw sendAndThrowMessage(NegotiationStatus.ERROR, "Expecting START status, received " + message.status);
     }
 
     // Get the mechanism name.
-    String mechanismName = new String(message.payload);
+    String mechanismName = new String(message.payload, StandardCharsets.UTF_8);
     TSaslServerDefinition serverDefinition = serverDefinitionMap.get(mechanismName);
     LOGGER.debug("Received mechanism name '{}'", mechanismName);
 
     if (serverDefinition == null) {
-      sendAndThrowMessage(NegotiationStatus.BAD, "Unsupported mechanism type " + mechanismName);
+      throw sendAndThrowMessage(NegotiationStatus.BAD, "Unsupported mechanism type " + mechanismName);
     }
     SaslServer saslServer = Sasl.createSaslServer(serverDefinition.mechanism,
         serverDefinition.protocol, serverDefinition.serverName, serverDefinition.props,
@@ -145,7 +146,7 @@
 
   /**
    * <code>TTransportFactory</code> to create
-   * <code>TSaslServerTransports<c/ode>. Ensures that a given
+   * <code>TSaslServerTransports</code>. Ensures that a given
    * underlying <code>TTransport</code> instance receives the same
    * <code>TSaslServerTransport</code>. This is kind of an awful hack to work
    * around the fact that Thrift is designed assuming that
diff --git a/lib/java/src/org/apache/thrift/transport/TSaslTransport.java b/lib/java/src/org/apache/thrift/transport/TSaslTransport.java
index b54746c..bed3b39 100644
--- a/lib/java/src/org/apache/thrift/transport/TSaslTransport.java
+++ b/lib/java/src/org/apache/thrift/transport/TSaslTransport.java
@@ -19,7 +19,7 @@
 
 package org.apache.thrift.transport;
 
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -35,7 +35,7 @@
 
 /**
  * A superclass for SASL client/server thrift transports. A subclass need only
- * implement the <code>open</open> method.
+ * implement the <code>open</code> method.
  */
 abstract class TSaslTransport extends TTransport {
 
@@ -113,7 +113,7 @@
   /**
    * Create a TSaslTransport. It's assumed that setSaslServer will be called
    * later to initialize the SASL endpoint underlying this transport.
-   * 
+   *
    * @param underlyingTransport
    *          The thrift transport which this transport is wrapping.
    */
@@ -123,7 +123,7 @@
 
   /**
    * Create a TSaslTransport which acts as a client.
-   * 
+   *
    * @param saslClient
    *          The <code>SaslClient</code> which this transport will use for SASL
    *          negotiation.
@@ -144,7 +144,7 @@
 
   /**
    * Send a complete Thrift SASL message.
-   * 
+   *
    * @param status
    *          The status to send.
    * @param payload
@@ -158,9 +158,9 @@
     messageHeader[0] = status.getValue();
     EncodingUtils.encodeBigEndian(payload.length, messageHeader, STATUS_BYTES);
 
-    if (LOGGER.isDebugEnabled())
-      LOGGER.debug(getRole() + ": Writing message with status {} and payload length {}",
-                   status, payload.length);
+    LOGGER.debug("{}: Writing message with status {} and payload length {}",
+        getRole(), status, payload.length);
+
     underlyingTransport.write(messageHeader);
     underlyingTransport.write(payload);
     underlyingTransport.flush();
@@ -168,7 +168,7 @@
 
   /**
    * Read a complete Thrift SASL message.
-   * 
+   *
    * @return The SASL status and payload from this message.
    * @throws TTransportException
    *           Thrown if there is a failure reading from the underlying
@@ -178,24 +178,27 @@
     underlyingTransport.readAll(messageHeader, 0, messageHeader.length);
 
     byte statusByte = messageHeader[0];
-    byte[] payload = new byte[EncodingUtils.decodeBigEndian(messageHeader, STATUS_BYTES)];
-    underlyingTransport.readAll(payload, 0, payload.length);
 
     NegotiationStatus status = NegotiationStatus.byValue(statusByte);
     if (status == null) {
-      sendAndThrowMessage(NegotiationStatus.ERROR, "Invalid status " + statusByte);
-    } else if (status == NegotiationStatus.BAD || status == NegotiationStatus.ERROR) {
-      try {
-        String remoteMessage = new String(payload, "UTF-8");
-        throw new TTransportException("Peer indicated failure: " + remoteMessage);
-      } catch (UnsupportedEncodingException e) {
-        throw new TTransportException(e);
-      }
+      throw sendAndThrowMessage(NegotiationStatus.ERROR, "Invalid status " + statusByte);
     }
 
-    if (LOGGER.isDebugEnabled())
-      LOGGER.debug(getRole() + ": Received message with status {} and payload length {}",
-                   status, payload.length);
+    int payloadBytes = EncodingUtils.decodeBigEndian(messageHeader, STATUS_BYTES);
+    if (payloadBytes < 0 || payloadBytes > 104857600 /* 100 MB */) {
+      throw sendAndThrowMessage(
+        NegotiationStatus.ERROR, "Invalid payload header length: " + payloadBytes);
+    }
+
+    byte[] payload = new byte[payloadBytes];
+    underlyingTransport.readAll(payload, 0, payload.length);
+
+    if (status == NegotiationStatus.BAD || status == NegotiationStatus.ERROR) {
+      String remoteMessage = new String(payload, StandardCharsets.UTF_8);
+      throw new TTransportException("Peer indicated failure: " + remoteMessage);
+    }
+    LOGGER.debug("{}: Received message with status {} and payload length {}",
+        getRole(), status, payload.length);
     return new SaslResponse(status, payload);
   }
 
@@ -203,17 +206,19 @@
    * Send a Thrift SASL message with the given status (usually BAD or ERROR) and
    * string message, and then throw a TTransportException with the given
    * message.
-   * 
+   *
    * @param status
    *          The Thrift SASL status code to send. Usually BAD or ERROR.
    * @param message
    *          The optional message to send to the other side.
    * @throws TTransportException
    *           Always thrown with the message provided.
+   * @return always throws TTransportException but declares return type to allow
+   *          throw sendAndThrowMessage(...) to inform compiler control flow
    */
-  protected void sendAndThrowMessage(NegotiationStatus status, String message) throws TTransportException {
+  protected TTransportException sendAndThrowMessage(NegotiationStatus status, String message) throws TTransportException {
     try {
-      sendSaslMessage(status, message.getBytes());
+      sendSaslMessage(status, message.getBytes(StandardCharsets.UTF_8));
     } catch (Exception e) {
       LOGGER.warn("Could not send failure response", e);
       message += "\nAlso, could not send response: " + e.toString();
@@ -225,7 +230,7 @@
    * Implemented by subclasses to start the Thrift SASL handshake process. When
    * this method completes, the <code>SaslParticipant</code> in this class is
    * assumed to be initialized.
-   * 
+   *
    * @throws TTransportException
    * @throws SaslException
    */
@@ -240,6 +245,13 @@
    */
   @Override
   public void open() throws TTransportException {
+    /*
+     * readSaslHeader is used to tag whether the SASL header has been read properly.
+     * If there is a problem in reading the header, there might not be any
+     * data in the stream, possibly a TCP health check from load balancer.
+     */
+    boolean readSaslHeader = false;
+
     LOGGER.debug("opening transport {}", this);
     if (sasl != null && sasl.isComplete())
       throw new TTransportException("SASL transport already open");
@@ -251,6 +263,7 @@
       // Negotiate a SASL mechanism. The client also sends its
       // initial response, or an empty one.
       handleSaslStartMessage();
+      readSaslHeader = true;
       LOGGER.debug("{}: Start message handled", getRole());
 
       SaslResponse message = null;
@@ -268,7 +281,7 @@
         if (message.status == NegotiationStatus.COMPLETE &&
             getRole() == SaslRole.CLIENT) {
           LOGGER.debug("{}: All done!", getRole());
-          break;
+          continue;
         }
 
         sendSaslMessage(sasl.isComplete() ? NegotiationStatus.COMPLETE : NegotiationStatus.OK,
@@ -276,8 +289,6 @@
       }
       LOGGER.debug("{}: Main negotiation loop complete", getRole());
 
-      assert sasl.isComplete();
-
       // If we're the client, and we're complete, but the server isn't
       // complete yet, we need to wait for its response. This will occur
       // with ANONYMOUS auth, for example, where we send an initial response
@@ -294,10 +305,21 @@
     } catch (SaslException e) {
       try {
         LOGGER.error("SASL negotiation failure", e);
-        sendAndThrowMessage(NegotiationStatus.BAD, e.getMessage());
+        throw sendAndThrowMessage(NegotiationStatus.BAD, e.getMessage());
       } finally {
         underlyingTransport.close();
       }
+    } catch (TTransportException e) {
+      /*
+       * If there is no-data or no-sasl header in the stream, throw a different
+       * type of exception so we can handle this scenario differently.
+       */
+      if (!readSaslHeader && e.getType() == TTransportException.END_OF_FILE) {
+        underlyingTransport.close();
+        LOGGER.debug("No data or no sasl data in the stream");
+        throw new TSaslTransportException("No data or no sasl data in the stream");
+      }
+      throw e;
     }
 
     String qop = (String) sasl.getNegotiatedProperty(Sasl.QOP);
@@ -307,7 +329,7 @@
 
   /**
    * Get the underlying <code>SaslClient</code>.
-   * 
+   *
    * @return The <code>SaslClient</code>, or <code>null</code> if this transport
    *         is backed by a <code>SaslServer</code>.
    */
@@ -325,7 +347,7 @@
 
   /**
    * Get the underlying <code>SaslServer</code>.
-   * 
+   *
    * @return The <code>SaslServer</code>, or <code>null</code> if this transport
    *         is backed by a <code>SaslClient</code>.
    */
@@ -336,7 +358,7 @@
   /**
    * Read a 4-byte word from the underlying transport and interpret it as an
    * integer.
-   * 
+   *
    * @return The length prefix of the next SASL message to read.
    * @throws TTransportException
    *           Thrown if reading from the underlying transport fails.
@@ -349,7 +371,7 @@
 
   /**
    * Write the given integer as 4 bytes to the underlying transport.
-   * 
+   *
    * @param length
    *          The length prefix of the next SASL message to write.
    * @throws TTransportException
@@ -413,7 +435,7 @@
   /**
    * Read a single frame of data from the underlying transport, unwrapping if
    * necessary.
-   * 
+   *
    * @throws TTransportException
    *           Thrown if there's an error reading from the underlying transport.
    * @throws SaslException
diff --git a/lib/java/src/org/apache/thrift/transport/TSaslTransportException.java b/lib/java/src/org/apache/thrift/transport/TSaslTransportException.java
new file mode 100644
index 0000000..90189f4
--- /dev/null
+++ b/lib/java/src/org/apache/thrift/transport/TSaslTransportException.java
@@ -0,0 +1,43 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+/*
+ * This exception is used to track exceptions in TSaslTransport
+ * that does not have Sasl signature in their stream.
+ */
+public class TSaslTransportException extends TTransportException {
+
+  public TSaslTransportException() {
+    super();
+  }
+
+  public TSaslTransportException(String message) {
+    super(message);
+  }
+
+  public TSaslTransportException(Throwable cause) {
+    super(cause);
+  }
+
+  public TSaslTransportException(String message, Throwable cause) {
+    super(message, cause);
+  }
+}
diff --git a/lib/java/src/org/apache/thrift/transport/TServerSocket.java b/lib/java/src/org/apache/thrift/transport/TServerSocket.java
index 147074a..79f7b7f 100644
--- a/lib/java/src/org/apache/thrift/transport/TServerSocket.java
+++ b/lib/java/src/org/apache/thrift/transport/TServerSocket.java
@@ -46,19 +46,27 @@
    */
   private int clientTimeout_ = 0;
 
+  public static class ServerSocketTransportArgs extends AbstractServerTransportArgs<ServerSocketTransportArgs> {
+    ServerSocket serverSocket;
+
+    public ServerSocketTransportArgs serverSocket(ServerSocket serverSocket) {
+      this.serverSocket = serverSocket;
+      return this;
+    }
+  }
+
   /**
    * Creates a server socket from underlying socket object
    */
-  public TServerSocket(ServerSocket serverSocket) {
+  public TServerSocket(ServerSocket serverSocket) throws TTransportException {
     this(serverSocket, 0);
   }
 
   /**
    * Creates a server socket from underlying socket object
    */
-  public TServerSocket(ServerSocket serverSocket, int clientTimeout) {
-    serverSocket_ = serverSocket;
-    clientTimeout_ = clientTimeout;
+  public TServerSocket(ServerSocket serverSocket, int clientTimeout) throws TTransportException {
+    this(new ServerSocketTransportArgs().serverSocket(serverSocket).clientTimeout(clientTimeout));
   }
 
   /**
@@ -80,22 +88,30 @@
   }
 
   public TServerSocket(InetSocketAddress bindAddr, int clientTimeout) throws TTransportException {
-    clientTimeout_ = clientTimeout;
+    this(new ServerSocketTransportArgs().bindAddr(bindAddr).clientTimeout(clientTimeout));
+  }
+
+  public TServerSocket(ServerSocketTransportArgs args) throws TTransportException {
+    clientTimeout_ = args.clientTimeout;
+    if (args.serverSocket != null) {
+      this.serverSocket_ = args.serverSocket;
+      return;
+    }
     try {
       // Make server socket
       serverSocket_ = new ServerSocket();
       // Prevent 2MSL delay problem on server restarts
       serverSocket_.setReuseAddress(true);
       // Bind to listening port
-      serverSocket_.bind(bindAddr);
+      serverSocket_.bind(args.bindAddr, args.backlog);
     } catch (IOException ioe) {
-      serverSocket_ = null;
-      throw new TTransportException("Could not create ServerSocket on address " + bindAddr.toString() + ".");
+      close();
+      throw new TTransportException("Could not create ServerSocket on address " + args.bindAddr.toString() + ".", ioe);
     }
   }
 
   public void listen() throws TTransportException {
-    // Make sure not to block on accept
+    // Make sure to block on accept
     if (serverSocket_ != null) {
       try {
         serverSocket_.setSoTimeout(0);
diff --git a/lib/java/src/org/apache/thrift/transport/TServerTransport.java b/lib/java/src/org/apache/thrift/transport/TServerTransport.java
index 17ff86b..424e4fa 100644
--- a/lib/java/src/org/apache/thrift/transport/TServerTransport.java
+++ b/lib/java/src/org/apache/thrift/transport/TServerTransport.java
@@ -19,11 +19,40 @@
 
 package org.apache.thrift.transport;
 
+import java.io.Closeable;
+import java.net.InetSocketAddress;
+
 /**
  * Server transport. Object which provides client transports.
  *
  */
-public abstract class TServerTransport {
+public abstract class TServerTransport implements Closeable {
+
+  public static abstract class AbstractServerTransportArgs<T extends AbstractServerTransportArgs<T>> {
+    int backlog = 0; // A value of 0 means the default value will be used (currently set at 50)
+    int clientTimeout = 0;
+    InetSocketAddress bindAddr;
+
+    public T backlog(int backlog) {
+      this.backlog = backlog;
+      return (T) this;
+    }
+
+    public T clientTimeout(int clientTimeout) {
+      this.clientTimeout = clientTimeout;
+      return (T) this;
+    }
+
+    public T port(int port) {
+      this.bindAddr = new InetSocketAddress(port);
+      return (T) this;
+    }
+
+    public T bindAddr(InetSocketAddress bindAddr) {
+      this.bindAddr = bindAddr;
+      return (T) this;
+    }
+  }
 
   public abstract void listen() throws TTransportException;
 
diff --git a/lib/java/src/org/apache/thrift/transport/TSimpleFileTransport.java b/lib/java/src/org/apache/thrift/transport/TSimpleFileTransport.java
new file mode 100644
index 0000000..42102d9
--- /dev/null
+++ b/lib/java/src/org/apache/thrift/transport/TSimpleFileTransport.java
@@ -0,0 +1,216 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+
+/**
+ * Basic file support for the TTransport interface
+ */
+public final class TSimpleFileTransport extends TTransport {
+
+  private RandomAccessFile file = null;   
+  private boolean readable;               
+  private boolean writable;               
+  private String path_;               
+
+
+  /**
+   * Create a transport backed by a simple file 
+   * 
+   * @param path the path to the file to open/create
+   * @param read true to support read operations
+   * @param write true to support write operations
+   * @param openFile true to open the file on construction
+   * @throws TTransportException if file open fails
+   */
+  public TSimpleFileTransport(String path, boolean read, 
+                              boolean write, boolean openFile)
+          throws TTransportException {
+    if (path.length() <= 0) {
+      throw new TTransportException("No path specified");
+    }
+    if (!read && !write) {
+      throw new TTransportException("Neither READ nor WRITE specified");
+    }
+    readable = read;
+    writable = write;
+    path_ = path;
+    if (openFile) {
+      open();
+    }
+  }
+  
+  /**
+   * Create a transport backed by a simple file 
+   * Implicitly opens file to conform to C++ behavior.
+   * 
+   * @param path the path to the file to open/create
+   * @param read true to support read operations
+   * @param write true to support write operations
+   * @throws TTransportException if file open fails
+   */
+  public TSimpleFileTransport(String path, boolean read, boolean write)
+          throws TTransportException {
+    this(path, read, write, true);
+  }
+  
+  /**
+   * Create a transport backed by a simple read only disk file (implicitly opens
+   * file)
+   *
+   * @param path the path to the file to open/create
+   * @throws TTransportException if file open fails
+   */
+  public TSimpleFileTransport(String path) throws TTransportException {
+    this(path, true, false, true);
+  }
+
+  /**
+   * Test file status
+   *
+   * @return true if open, otherwise false
+   */
+  @Override
+  public boolean isOpen() {
+    return (file != null);
+  }
+
+  /**
+   * Open file if not previously opened. 
+   *
+   * @throws TTransportException if open fails
+   */
+  @Override
+  public void open() throws TTransportException {
+    if (file == null){
+      try {
+        String access = "r";       //RandomAccessFile objects must be readable
+        if (writable) {
+          access += "w";
+        }
+        file = new RandomAccessFile(path_, access);
+      } catch (IOException ioe) {
+        file = null;
+        throw new TTransportException(ioe.getMessage());
+      }      
+    }
+  }
+
+  /**
+   * Close file, subsequent read/write activity will throw exceptions
+   */
+  @Override
+  public void close() {
+    if (file != null) {
+      try {
+        file.close();
+      } catch (Exception e) {
+        //Nothing to do
+      }
+      file = null;
+    }
+  }
+
+  /**
+   * Read up to len many bytes into buf at offset 
+   *
+   * @param buf houses bytes read
+   * @param off offset into buff to begin writing to
+   * @param len maximum number of bytes to read
+   * @return number of bytes actually read
+   * @throws TTransportException on read failure
+   */
+  @Override
+  public int read(byte[] buf, int off, int len) throws TTransportException {
+    if (!readable) {
+      throw new TTransportException("Read operation on write only file");
+    }
+    int iBytesRead = 0;
+    try {
+      iBytesRead = file.read(buf, off, len);
+    } catch (IOException ioe) {
+      file = null;
+      throw new TTransportException(ioe.getMessage());
+    }
+    return iBytesRead;
+  }
+
+  /**
+   * Write len many bytes from buff starting at offset 
+   *
+   * @param buf buffer containing bytes to write
+   * @param off offset into buffer to begin writing from
+   * @param len number of bytes to write
+   * @throws TTransportException on write failure
+   */
+  @Override
+  public void write(byte[] buf, int off, int len) throws TTransportException {
+    try {
+      file.write(buf, off, len);
+    } catch (IOException ioe) {
+      file = null;
+      throw new TTransportException(ioe.getMessage());
+    }
+  }
+
+  /**
+   * Move file pointer to specified offset, new read/write calls will act here
+   *
+   * @param offset bytes from beginning of file to move pointer to
+   * @throws TTransportException is seek fails
+   */
+  public void seek(long offset) throws TTransportException {
+    try {
+      file.seek(offset);
+    } catch (IOException ex) {
+      throw new TTransportException(ex.getMessage());
+    }
+  }
+
+  /**
+   * Return the length of the file in bytes
+   *
+   * @return length of the file in bytes
+   * @throws TTransportException if file access fails
+   */
+  public long length() throws TTransportException {
+    try {
+      return file.length();
+    } catch (IOException ex) {
+      throw new TTransportException(ex.getMessage());
+    }
+  }
+
+  /**
+   * Return current file pointer position in bytes from beginning of file
+   *
+   * @return file pointer position
+   * @throws TTransportException if file access fails
+   */
+  public long getFilePointer() throws TTransportException {
+    try {
+      return file.getFilePointer();
+    } catch (IOException ex) {
+      throw new TTransportException(ex.getMessage());
+    }
+  }
+}
\ No newline at end of file
diff --git a/lib/java/src/org/apache/thrift/transport/TSocket.java b/lib/java/src/org/apache/thrift/transport/TSocket.java
index 606e8a9..b20b32b 100644
--- a/lib/java/src/org/apache/thrift/transport/TSocket.java
+++ b/lib/java/src/org/apache/thrift/transport/TSocket.java
@@ -40,22 +40,27 @@
   /**
    * Wrapped Socket object
    */
-  private Socket socket_ = null;
+  private Socket socket_;
 
   /**
    * Remote host
    */
-  private String host_  = null;
+  private String host_;
 
   /**
    * Remote port
    */
-  private int port_ = 0;
+  private int port_;
 
   /**
-   * Socket timeout
+   * Socket timeout - read timeout on the socket
    */
-  private int timeout_ = 0;
+  private int socketTimeout_;
+
+  /**
+   * Connection timeout
+   */
+  private int connectTimeout_;
 
   /**
    * Constructor that takes an already created socket.
@@ -68,14 +73,15 @@
     try {
       socket_.setSoLinger(false, 0);
       socket_.setTcpNoDelay(true);
+      socket_.setKeepAlive(true);
     } catch (SocketException sx) {
       LOGGER.warn("Could not configure socket.", sx);
     }
 
     if (isOpen()) {
       try {
-        inputStream_ = new BufferedInputStream(socket_.getInputStream(), 1024);
-        outputStream_ = new BufferedOutputStream(socket_.getOutputStream(), 1024);
+        inputStream_ = new BufferedInputStream(socket_.getInputStream());
+        outputStream_ = new BufferedOutputStream(socket_.getOutputStream());
       } catch (IOException iox) {
         close();
         throw new TTransportException(TTransportException.NOT_OPEN, iox);
@@ -100,12 +106,27 @@
    *
    * @param host    Remote host
    * @param port    Remote port
-   * @param timeout Socket timeout
+   * @param timeout Socket timeout and connection timeout
    */
   public TSocket(String host, int port, int timeout) {
+    this(host, port, timeout, timeout);
+  }
+
+  /**
+   * Creates a new unconnected socket that will connect to the given host
+   * on the given port, with a specific connection timeout and a
+   * specific socket timeout.
+   *
+   * @param host            Remote host
+   * @param port            Remote port
+   * @param socketTimeout   Socket timeout
+   * @param connectTimeout  Connection timeout
+   */
+  public TSocket(String host, int port, int socketTimeout, int connectTimeout) {
     host_ = host;
     port_ = port;
-    timeout_ = timeout;
+    socketTimeout_ = socketTimeout;
+    connectTimeout_ = connectTimeout;
     initSocket();
   }
 
@@ -117,19 +138,39 @@
     try {
       socket_.setSoLinger(false, 0);
       socket_.setTcpNoDelay(true);
-      socket_.setSoTimeout(timeout_);
+      socket_.setKeepAlive(true);
+      socket_.setSoTimeout(socketTimeout_);
     } catch (SocketException sx) {
       LOGGER.error("Could not configure socket.", sx);
     }
   }
 
   /**
+   * Sets the socket timeout and connection timeout.
+   *
+   * @param timeout Milliseconds timeout
+   */
+  public void setTimeout(int timeout) {
+    this.setConnectTimeout(timeout);
+    this.setSocketTimeout(timeout);
+  }
+
+  /**
+   * Sets the time after which the connection attempt will time out
+   *
+   * @param timeout Milliseconds timeout
+   */
+  public void setConnectTimeout(int timeout) {
+    connectTimeout_ = timeout;
+  }
+
+  /**
    * Sets the socket timeout
    *
    * @param timeout Milliseconds timeout
    */
-  public void setTimeout(int timeout) {
-    timeout_ = timeout;
+  public void setSocketTimeout(int timeout) {
+    socketTimeout_ = timeout;
     try {
       socket_.setSoTimeout(timeout);
     } catch (SocketException sx) {
@@ -165,11 +206,11 @@
       throw new TTransportException(TTransportException.ALREADY_OPEN, "Socket already connected.");
     }
 
-    if (host_.length() == 0) {
+    if (host_ == null || host_.length() == 0) {
       throw new TTransportException(TTransportException.NOT_OPEN, "Cannot open null host.");
     }
-    if (port_ <= 0) {
-      throw new TTransportException(TTransportException.NOT_OPEN, "Cannot open without port.");
+    if (port_ <= 0 || port_ > 65535) {
+      throw new TTransportException(TTransportException.NOT_OPEN, "Invalid port " + port_);
     }
 
     if (socket_ == null) {
@@ -177,9 +218,9 @@
     }
 
     try {
-      socket_.connect(new InetSocketAddress(host_, port_), timeout_);
-      inputStream_ = new BufferedInputStream(socket_.getInputStream(), 1024);
-      outputStream_ = new BufferedOutputStream(socket_.getOutputStream(), 1024);
+      socket_.connect(new InetSocketAddress(host_, port_), connectTimeout_);
+      inputStream_ = new BufferedInputStream(socket_.getInputStream());
+      outputStream_ = new BufferedOutputStream(socket_.getOutputStream());
     } catch (IOException iox) {
       close();
       throw new TTransportException(TTransportException.NOT_OPEN, iox);
diff --git a/lib/java/src/org/apache/thrift/transport/TTransport.java b/lib/java/src/org/apache/thrift/transport/TTransport.java
index 6eab3b0..73ad730 100644
--- a/lib/java/src/org/apache/thrift/transport/TTransport.java
+++ b/lib/java/src/org/apache/thrift/transport/TTransport.java
@@ -19,12 +19,14 @@
 
 package org.apache.thrift.transport;
 
+import java.io.Closeable;
+
 /**
  * Generic class that encapsulates the I/O layer. This is basically a thin
  * wrapper around the combined functionality of Java input/output streams.
  *
  */
-public abstract class TTransport {
+public abstract class TTransport implements Closeable {
 
   /**
    * Queries whether the transport is open.
diff --git a/lib/java/src/org/apache/thrift/transport/TTransportException.java b/lib/java/src/org/apache/thrift/transport/TTransportException.java
index d08f3b0..b886bc2 100644
--- a/lib/java/src/org/apache/thrift/transport/TTransportException.java
+++ b/lib/java/src/org/apache/thrift/transport/TTransportException.java
@@ -34,6 +34,7 @@
   public static final int ALREADY_OPEN = 2;
   public static final int TIMED_OUT = 3;
   public static final int END_OF_FILE = 4;
+  public static final int CORRUPTED_DATA = 5;
 
   protected int type_ = UNKNOWN;
 
diff --git a/lib/java/src/org/apache/thrift/transport/TZlibTransport.java b/lib/java/src/org/apache/thrift/transport/TZlibTransport.java
new file mode 100644
index 0000000..e755aa5
--- /dev/null
+++ b/lib/java/src/org/apache/thrift/transport/TZlibTransport.java
@@ -0,0 +1,148 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
+
+/**
+ * TZlibTransport deflates on write and inflates on read.
+ */
+public class TZlibTransport extends TIOStreamTransport {
+
+    private TTransport transport_ = null;
+
+    public static class Factory extends TTransportFactory {
+        public Factory() {
+        }
+
+        @Override
+        public TTransport getTransport(TTransport base) {
+            return new TZlibTransport(base);
+        }
+    }
+
+    /**
+     * Constructs a new TZlibTransport instance.
+     * @param  transport the underlying transport to read from and write to
+     */
+    public TZlibTransport(TTransport transport) {
+        this(transport, Deflater.BEST_COMPRESSION);
+    }
+
+    /**
+     * Constructs a new TZlibTransport instance.
+     * @param  transport the underlying transport to read from and write to
+     * @param  compressionLevel 0 for no compression, 9 for maximum compression
+     */
+    public TZlibTransport(TTransport transport, int compressionLevel) {
+        transport_ = transport;
+        inputStream_ = new InflaterInputStream(new TTransportInputStream(transport_), new Inflater());
+        outputStream_ = new DeflaterOutputStream(new TTransportOutputStream(transport_), new Deflater(compressionLevel, false), true);
+    }
+
+    @Override
+    public boolean isOpen() {
+        return transport_.isOpen();
+    }
+
+    @Override
+    public void open() throws TTransportException {
+        transport_.open();
+    }
+
+    @Override
+    public void close() {
+        super.close();
+        if (transport_.isOpen()) {
+            transport_.close();
+        }
+    }
+}
+
+class TTransportInputStream extends InputStream {
+
+    private TTransport transport = null;
+
+    public TTransportInputStream(TTransport transport) {
+        this.transport = transport;
+    }
+
+    @Override
+    public int read() throws IOException {
+        try {
+            byte[] buf = new byte[1];
+            transport.read(buf, 0, 1);
+            return buf[0];
+        } catch (TTransportException e) {
+            throw new IOException(e);
+        }
+    }
+
+    @Override
+    public int read(byte b[], int off, int len) throws IOException {
+        try {
+            return transport.read(b, off, len);
+        } catch (TTransportException e) {
+            throw new IOException(e);
+        }
+    }
+}
+
+class TTransportOutputStream extends OutputStream {
+
+    private TTransport transport = null;
+
+    public TTransportOutputStream(TTransport transport) {
+        this.transport = transport;
+    }
+
+    @Override
+    public void write(final int b) throws IOException {
+        try {
+            transport.write(new byte[]{(byte) b});
+        } catch (TTransportException e) {
+            throw new IOException(e);
+        }
+    }
+
+    @Override
+    public void write(byte b[], int off, int len) throws IOException {
+        try {
+            transport.write(b, off, len);
+        } catch (TTransportException e) {
+            throw new IOException(e);
+        }
+    }
+
+    @Override
+    public void flush() throws IOException {
+        try {
+            transport.flush();
+        } catch (TTransportException e) {
+            throw new IOException(e);
+        }
+    }
+}
+
diff --git a/lib/java/test/.keystore b/lib/java/test/.keystore
index 0c85111..4dd66ac 100644
--- a/lib/java/test/.keystore
+++ b/lib/java/test/.keystore
Binary files differ
diff --git a/lib/java/test/.truststore b/lib/java/test/.truststore
index c24b4a2..26fbd19 100644
--- a/lib/java/test/.truststore
+++ b/lib/java/test/.truststore
Binary files differ
diff --git a/lib/java/test/log4j.properties b/lib/java/test/log4j.properties
index 878b2fc..ab9beba 100644
--- a/lib/java/test/log4j.properties
+++ b/lib/java/test/log4j.properties
@@ -1,6 +1,6 @@
 # log4j configuration used during build and unit tests
 log4j.rootLogger=debug,stdout
-log4j.threshhold=ALL
+log4j.threshold=ALL
 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
diff --git a/lib/java/test/org/apache/thrift/Fixtures.java b/lib/java/test/org/apache/thrift/Fixtures.java
index 9f28124..61f40a5 100644
--- a/lib/java/test/org/apache/thrift/Fixtures.java
+++ b/lib/java/test/org/apache/thrift/Fixtures.java
@@ -20,6 +20,7 @@
 package org.apache.thrift;
 
 import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -267,7 +268,7 @@
       oneOfEach.setInteger64((long) 6000 * 1000 * 1000);
       oneOfEach.setDouble_precision(Math.PI);
       oneOfEach.setSome_characters("JSON THIS! \"\1");
-      oneOfEach.setZomg_unicode(new String(kUnicodeBytes, "UTF-8"));
+      oneOfEach.setZomg_unicode(new String(kUnicodeBytes, StandardCharsets.UTF_8));
       oneOfEach.setBase64(ByteBuffer.wrap("base64".getBytes()));
       // byte, i16, and i64 lists are populated by default constructor
 
@@ -277,7 +278,7 @@
       nesting = new Nesting(bonk, oneOfEach);
 
       holyMoley = new HolyMoley();
-      ArrayList big = new ArrayList<OneOfEach>();
+      List<OneOfEach> big = new ArrayList<OneOfEach>();
       big.add(new OneOfEach(oneOfEach));
       big.add(nesting.my_ooe);
       holyMoley.setBig(big);
diff --git a/lib/java/test/org/apache/thrift/TestDeepCopy.java b/lib/java/test/org/apache/thrift/TestDeepCopy.java
new file mode 100644
index 0000000..acafaef
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/TestDeepCopy.java
@@ -0,0 +1,34 @@
+package org.apache.thrift;
+
+import junit.framework.TestCase;
+import thrift.test.DeepCopyBar;
+import thrift.test.DeepCopyFoo;
+
+public class TestDeepCopy extends TestCase {
+
+  public void testDeepCopy() throws Exception {
+    final DeepCopyFoo foo = new DeepCopyFoo();
+
+    foo.addToL(new DeepCopyBar());
+    foo.addToS(new DeepCopyBar());
+    foo.putToM("test 3", new DeepCopyBar());
+
+    foo.addToLi(new thrift.test.Object());
+    foo.addToSi(new thrift.test.Object());
+    foo.putToMi("test 3", new thrift.test.Object());
+
+    foo.setBar(new DeepCopyBar());
+
+    final DeepCopyFoo deepCopyFoo = foo.deepCopy();
+
+    assertNotSame(foo.getBar(), deepCopyFoo.getBar());
+
+    assertNotSame(foo.getL().get(0),                          deepCopyFoo.getL().get(0));
+    assertNotSame(foo.getS().toArray(new DeepCopyBar[0])[0],  deepCopyFoo.getS().toArray(new DeepCopyBar[0])[0]);
+    assertNotSame(foo.getM().get("test 3"),                   deepCopyFoo.getM().get("test 3"));
+
+    assertNotSame(foo.getLi().get(0),                                 deepCopyFoo.getLi().get(0));
+    assertNotSame(foo.getSi().toArray(new thrift.test.Object[0])[0],  deepCopyFoo.getSi().toArray(new thrift.test.Object[0])[0]);
+    assertNotSame(foo.getMi().get("test 3"),                          deepCopyFoo.getMi().get("test 3"));
+  }
+}
diff --git a/lib/java/test/org/apache/thrift/TestEnumContainers.java b/lib/java/test/org/apache/thrift/TestEnumContainers.java
new file mode 100644
index 0000000..683246b
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/TestEnumContainers.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift;
+
+import junit.framework.TestCase;
+import thrift.test.enumcontainers.EnumContainersTestConstants;
+import thrift.test.enumcontainers.GodBean;
+import thrift.test.enumcontainers.GreekGodGoddess;
+
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+
+public class TestEnumContainers extends TestCase {
+
+    public void testEnumContainers() throws Exception {
+        final GodBean b1 = new GodBean();
+        b1.addToGoddess(GreekGodGoddess.HERA);
+        b1.getGoddess().add(GreekGodGoddess.APHRODITE);
+        b1.putToPower(GreekGodGoddess.ZEUS, 1000);
+        b1.getPower().put(GreekGodGoddess.HERA, 333);
+        b1.putToByAlias("Mr. Z", GreekGodGoddess.ZEUS);
+        b1.addToImages("Baths of Aphrodite 01.jpeg");
+
+        final GodBean b2 = new GodBean(b1);
+
+        final GodBean b3 = new GodBean();
+        {
+            final TSerializer serializer = new TSerializer();
+            final TDeserializer deserializer = new TDeserializer();
+
+            final byte[] bytes = serializer.serialize(b1);
+            deserializer.deserialize(b3, bytes);
+        }
+
+        assertTrue(b1.getGoddess() != b2.getGoddess());
+        assertTrue(b1.getPower() != b2.getPower());
+
+        assertTrue(b1.getGoddess() != b3.getGoddess());
+        assertTrue(b1.getPower() != b3.getPower());
+
+        for (GodBean each : new GodBean[]{b1, b2, b3}) {
+            assertTrue(each.getGoddess().contains(GreekGodGoddess.HERA));
+            assertFalse(each.getGoddess().contains(GreekGodGoddess.POSEIDON));
+            assertTrue(each.getGoddess() instanceof EnumSet);
+
+            assertEquals(Integer.valueOf(1000), each.getPower().get(GreekGodGoddess.ZEUS));
+            assertEquals(Integer.valueOf(333), each.getPower().get(GreekGodGoddess.HERA));
+            assertTrue(each.getPower() instanceof EnumMap);
+
+            assertTrue(each.getByAlias() instanceof HashMap);
+            assertTrue(each.getImages() instanceof HashSet);
+        }
+    }
+
+    public void testEnumConstants() {
+        assertEquals("lightning bolt", EnumContainersTestConstants.ATTRIBUTES.get(GreekGodGoddess.ZEUS));
+        assertTrue(EnumContainersTestConstants.ATTRIBUTES instanceof EnumMap);
+
+        assertTrue(EnumContainersTestConstants.BEAUTY.contains(GreekGodGoddess.APHRODITE));
+        assertTrue(EnumContainersTestConstants.BEAUTY instanceof EnumSet);
+    }
+}
diff --git a/lib/java/test/org/apache/thrift/TestFullCamel.java b/lib/java/test/org/apache/thrift/TestFullCamel.java
new file mode 100644
index 0000000..fc98898
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/TestFullCamel.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.thrift;
+
+import java.util.HashSet;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TType;
+
+import thrift.test.fullcamel.OneOfEachZZ;
+import thrift.test.fullcamel.UnderscoreSrv;
+
+// Sanity check for the code generated by 'fullcamel'.
+//
+public class TestFullCamel extends TestCase {
+
+  public void testCamelCaseSyntax() throws Exception {
+    TSerializer   binarySerializer   = new   TSerializer(new TBinaryProtocol.Factory());
+    TDeserializer binaryDeserializer = new TDeserializer(new TBinaryProtocol.Factory());
+
+    OneOfEachZZ obj = new OneOfEachZZ();
+    obj.setABite((byte) 0xae);
+    obj.setImFalse(true);
+    byte[] serBytes = binarySerializer.serialize(obj);
+    binaryDeserializer.deserialize(obj, serBytes);
+    assertTrue( obj.getABite() == (byte) 0xae );
+    assertTrue( obj.isImFalse() == true );
+  }
+
+  public void testCamelCaseRpcMethods() throws Exception {
+    final UnderscoreSrv.Iface srv = new UnderscoreSrv.Iface() {
+      @Override
+      public long someRpcCall(String message) {
+        return 1l;
+      }
+    };
+    assertTrue(1l == srv.someRpcCall("test"));
+  }
+}
+
diff --git a/lib/java/test/org/apache/thrift/TestMultiplexedProcessor.java b/lib/java/test/org/apache/thrift/TestMultiplexedProcessor.java
new file mode 100644
index 0000000..01776ca
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/TestMultiplexedProcessor.java
@@ -0,0 +1,86 @@
+/*
+ * 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 org.apache.thrift;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.thrift.protocol.TMessage;
+import org.apache.thrift.protocol.TMessageType;
+import org.apache.thrift.protocol.TProtocol;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestMultiplexedProcessor {
+  private TMultiplexedProcessor mp;
+  private TProtocol iprot;
+  private TProtocol oprot;
+
+  @Before
+  public void setUp() throws Exception {
+    mp = new TMultiplexedProcessor();
+    iprot = mock(TProtocol.class);
+    oprot = mock(TProtocol.class);
+  }
+
+  @Test(expected = TException.class)
+  public void testWrongMessageType() throws TException {
+    when (iprot.readMessageBegin()).thenReturn(new TMessage("service:func", TMessageType.REPLY, 42));
+    mp.process(iprot, oprot);
+  }
+
+  @Test(expected = TException.class)
+  public void testNoSuchService() throws TException {
+    when(iprot.readMessageBegin()).thenReturn(new TMessage("service:func", TMessageType.CALL, 42));
+
+    mp.process(iprot, oprot);
+  }
+
+  static class StubProcessor implements TProcessor {
+    @Override
+    public boolean process(TProtocol in, TProtocol out) throws TException {
+      TMessage msg = in.readMessageBegin();
+      if (!"func".equals(msg.name) || msg.type!=TMessageType.CALL || msg.seqid!=42) {
+        throw new TException("incorrect parameters");
+      }
+      out.writeMessageBegin(new TMessage("func", TMessageType.REPLY, 42));
+      return true;
+    }
+  }
+
+  @Test
+  public void testExistingService() throws TException {
+    when(iprot.readMessageBegin()).thenReturn(new TMessage("service:func", TMessageType.CALL, 42));
+    mp.registerProcessor("service", new StubProcessor());
+    mp.process(iprot, oprot);
+    verify(oprot).writeMessageBegin(any(TMessage.class));
+  }
+
+  @Test
+  public void testDefaultService() throws TException {
+    when(iprot.readMessageBegin()).thenReturn(new TMessage("func", TMessageType.CALL, 42));
+    mp.registerDefault(new StubProcessor());
+    mp.process(iprot, oprot);
+    verify(oprot).writeMessageBegin(any(TMessage.class));
+  }
+
+}
diff --git a/lib/java/test/org/apache/thrift/TestOptionType.java b/lib/java/test/org/apache/thrift/TestOptionType.java
new file mode 100644
index 0000000..f70285f
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/TestOptionType.java
@@ -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 org.apache.thrift;
+
+import junit.framework.TestCase;
+import org.apache.thrift.Option;
+
+// Tests and documents behavior for the "Option<T>" type
+public class TestOptionType extends TestCase {
+    public void testSome() throws Exception {
+        String name = "Chuck Norris";
+        Option<String> option = Option.fromNullable(name);
+
+        assertTrue(option instanceof Option.Some);
+        assertTrue(option.isDefined());
+        assertEquals("Some(Chuck Norris)", option.toString());
+        assertEquals(option.or("default value"), "Chuck Norris");
+        assertEquals(option.get(),"Chuck Norris");
+    }
+
+    public void testNone() throws Exception {
+        String name = null;
+        Option<String> option = Option.fromNullable(name);
+
+        assertTrue(option instanceof Option.None);
+        assertFalse(option.isDefined());
+        assertEquals("None", option.toString());
+        assertEquals(option.or("default value"), "default value");
+        // Expect exception
+        try {
+            Object value = option.get();
+            fail("Expected IllegalStateException, got no exception");
+        } catch (IllegalStateException ex) {
+
+        } catch(Exception ex) {
+            fail("Expected IllegalStateException, got some other exception: "+ex.toString());
+        }
+    }
+
+    public void testMakeSome() throws Exception {
+        Option<String> some = Option.some("wee");
+        assertTrue(some instanceof Option.Some);
+    }
+
+    public void testMakeNone() throws Exception {
+        Option<Integer> none = Option.none();
+        assertTrue(none instanceof Option.None);
+    }
+}
diff --git a/lib/java/test/org/apache/thrift/TestRenderedDoubleConstants.java b/lib/java/test/org/apache/thrift/TestRenderedDoubleConstants.java
new file mode 100644
index 0000000..d691fe3
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/TestRenderedDoubleConstants.java
@@ -0,0 +1,179 @@
+/*
+ * 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 org.apache.thrift;
+
+import java.util.List;
+import junit.framework.TestCase;
+import static org.junit.Assert.*;
+import org.junit.Test;
+import thrift.test.DoubleConstantsTestConstants;
+
+public class TestRenderedDoubleConstants extends TestCase {
+    private static final double EPSILON = 0.0000001;
+    private static final String ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST =
+        "failed to verify a double constant generated by Thrift (expected = %f, got = %f)";
+    private static final String ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_LIST_TEST =
+        "failed to verify a list item by Thrift (expected = %f, got = %f)";
+    private static final String ASSERTION_MESSAGE_FOR_TYPE_CHECKS =
+        "the rendered variable with name %s is not of double type";
+
+    // to make sure lists containing doubles are generated correctly
+    public void testRenderedDoubleList() throws Exception {
+        final double[] EXPECTED_LIST =
+            {1d,-100d,100d,9223372036854775807d,-9223372036854775807d,3.14159265359,1000000.1,-1000000.1,1.7e+308,
+             -1.7e+308,9223372036854775816.43,-9223372036854775816.43};
+        assertEquals(EXPECTED_LIST.length, DoubleConstantsTestConstants.DOUBLE_LIST_TEST.size());
+        for (int i = 0; i < EXPECTED_LIST.length; ++i) {
+            assertEquals(
+                String.format(
+                    ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_LIST_TEST,
+                    EXPECTED_LIST[i],
+                    DoubleConstantsTestConstants.DOUBLE_LIST_TEST.get(i)),
+                EXPECTED_LIST[i], DoubleConstantsTestConstants.DOUBLE_LIST_TEST.get(i), EPSILON);
+        }
+    }
+
+    // to make sure the variables inside Thrift files are generated correctly
+    public void testRenderedDoubleConstants() throws Exception {
+        final double EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT = 1.0;
+        final double EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT = -100.0;
+        final double EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT = 9223372036854775807.0;
+        final double EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT = -9223372036854775807.0;
+        final double EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS = 3.14159265359;
+        final double EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE = 1000000.1;
+        final double EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE = -1000000.1;
+        final double EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE = 1.7e+308;
+        final double EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE = 9223372036854775816.43;
+        final double EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE = -1.7e+308;
+        final double EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE = -9223372036854775816.43;
+        assertEquals(
+            String.format(
+                ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+                EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT,
+                DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST),
+            EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT,
+            DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST, EPSILON);
+        assertEquals(
+            String.format(
+                ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+                EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT,
+                DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST),
+            EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT,
+            DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST, EPSILON);
+        assertEquals(
+            String.format(
+                ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+                EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT,
+                DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST),
+            EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT,
+            DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST, EPSILON);
+        assertEquals(
+            String.format(
+                ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+                EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT,
+                DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST),
+            EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT,
+            DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST, EPSILON);
+        assertEquals(
+            String.format(
+                ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+                EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS,
+                DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST),
+            EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS,
+            DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST, EPSILON);
+        assertEquals(
+            String.format(
+                ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+                EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE,
+                DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST),
+            EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE,
+            DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST, EPSILON);
+        assertEquals(
+            String.format(
+                ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+                EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE,
+                DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST),
+            EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE,
+            DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST, EPSILON);
+        assertEquals(
+            String.format(
+                ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+                EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE,
+                DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST),
+            EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE,
+            DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST, EPSILON);
+        assertEquals(
+            String.format(
+                ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+                EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE,
+                DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST),
+            EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE,
+            DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST, EPSILON);
+        assertEquals(
+            String.format(
+                ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+                EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE,
+                DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST),
+            EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE,
+            DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST, EPSILON);
+        assertEquals(
+            String.format(
+                ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST,
+                EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE,
+                DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST),
+            EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE,
+            DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST, EPSILON);
+        assertTrue(
+            String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST"),
+            Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST));
+        assertTrue(
+            String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST"),
+            Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST));
+        assertTrue(
+            String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST"),
+            Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST));
+        assertTrue(
+            String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST"),
+            Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST));
+        assertTrue(
+            String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST"),
+            Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST));
+        assertTrue(
+            String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST"),
+            Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST));
+        assertTrue(
+            String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST"),
+            Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST));
+        //assertTrue(
+        //    String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST"),
+        //    Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST));
+        assertTrue(
+            String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST"),
+            Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST));
+        //assertTrue(
+        //    String.format(ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST"),
+        //    Double.class.isInstance(DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST));
+        assertTrue(
+            String.format(
+                ASSERTION_MESSAGE_FOR_TYPE_CHECKS, "DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST"),
+            Double.class.isInstance(
+                DoubleConstantsTestConstants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST));
+    }
+}
diff --git a/lib/java/test/org/apache/thrift/TestReuse.java b/lib/java/test/org/apache/thrift/TestReuse.java
new file mode 100644
index 0000000..b44abd0
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/TestReuse.java
@@ -0,0 +1,57 @@
+/*
+ * 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 org.apache.thrift;
+
+import java.util.HashSet;
+
+import org.apache.thrift.protocol.TBinaryProtocol;
+
+import thrift.test.Reuse;
+
+// Tests reusing objects for deserialization.
+//
+public class TestReuse extends TestStruct {
+
+  public void testReuseObject() throws Exception {
+    TSerializer   binarySerializer   = new   TSerializer(new TBinaryProtocol.Factory());
+    TDeserializer binaryDeserializer = new TDeserializer(new TBinaryProtocol.Factory());
+
+    Reuse ru1 = new Reuse();
+    HashSet<String> hs1 = new HashSet<String>();
+    byte[] serBytes;    
+    String st1 = new String("string1");
+    String st2 = new String("string2");
+
+    ru1.setVal1(11);
+    ru1.setVal2(hs1);
+    ru1.addToVal2(st1);
+    
+    serBytes = binarySerializer.serialize(ru1);
+
+    // update hash set after serialization
+    hs1.add(st2);
+
+    binaryDeserializer.deserialize(ru1, serBytes);
+   
+    assertTrue( ru1.getVal2() == hs1 );
+    assertTrue( hs1.size() == 2 );
+  }
+
+}
diff --git a/lib/java/test/org/apache/thrift/TestShortStack.java b/lib/java/test/org/apache/thrift/TestShortStack.java
deleted file mode 100644
index 07831e5..0000000
--- a/lib/java/test/org/apache/thrift/TestShortStack.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.thrift;
-
-import java.util.Stack;
-
-import junit.framework.TestCase;
-
-public class TestShortStack extends TestCase {
-  private static final int NUM_TRIALS = 5;
-  private static final int NUM_REPS = 10000000;
-
-  public void testOps() throws Exception {
-    ShortStack s = new ShortStack(10);
-    s.push((short)10);
-    s.push((short)11);
-    s.push((short)12);
-    assertEquals((short)12, s.peek());
-    assertEquals((short)12, s.peek());
-    assertEquals((short)12, s.pop());
-    assertEquals((short)11, s.pop());
-    s.push((short)40);
-    assertEquals((short)40, s.peek());
-    assertEquals((short)40, s.pop());
-    assertEquals((short)10, s.peek());
-    assertEquals((short)10, s.pop());
-    try {
-      s.peek();
-      fail("should have thrown an exception!");
-    } catch (Exception e) {
-      // yay
-    }
-
-    try {
-      s.pop();
-      fail("should have thrown an exception!");
-    } catch (Exception e) {
-      // yay
-    }
-  }
-
-  public void testGrow() throws Exception {
-    ShortStack s = new ShortStack(1);
-    s.push((short)1);
-    s.push((short)1);
-    s.push((short)1);
-    s.push((short)1);
-    s.push((short)1);
-  }
-
-  public static void main(String[] args) throws Exception {
-    for (int trial = 0; trial < NUM_TRIALS; trial++) {
-      long start = System.currentTimeMillis();
-      ShortStack s = new ShortStack(10);
-      for (int rep = 0; rep < NUM_REPS; rep++) {
-        s.push((short)1);
-        s.push((short)11);
-        s.push((short)111);
-        s.pop();
-        s.pop();
-        s.push((short)12);
-        s.push((short)121);
-        s.push((short)1211);
-        s.push((short)12111);
-        s.pop();
-        s.pop();
-        s.pop();
-        s.pop();
-        s.push((short)5);
-        s.pop();
-        s.pop();
-      }
-      long end = System.currentTimeMillis();
-      System.out.println("ShortStack: " + (end-start));
-
-      start = System.currentTimeMillis();
-      Stack<Short> stdStack = new Stack<Short>();
-      for (int rep = 0; rep < NUM_REPS; rep++) {
-        stdStack.push((short)1);
-        stdStack.push((short)11);
-        stdStack.push((short)111);
-        stdStack.pop();
-        stdStack.pop();
-        stdStack.push((short)12);
-        stdStack.push((short)121);
-        stdStack.push((short)1211);
-        stdStack.push((short)12111);
-        stdStack.pop();
-        stdStack.pop();
-        stdStack.pop();
-        stdStack.pop();
-        stdStack.push((short)5);
-        stdStack.pop();
-        stdStack.pop();
-      }
-      end = System.currentTimeMillis();
-      System.out.println("Built-in stack: " + (end-start));
-    }
-  }
-}
diff --git a/lib/java/test/org/apache/thrift/TestStruct.java b/lib/java/test/org/apache/thrift/TestStruct.java
index b0dffc8..3379ed1 100644
--- a/lib/java/test/org/apache/thrift/TestStruct.java
+++ b/lib/java/test/org/apache/thrift/TestStruct.java
@@ -308,12 +308,40 @@
         object.toString());
   }
 
+  private static void assertArrayEquals(byte[] expected, byte[] actual) {
+    if (!java.util.Arrays.equals(expected, actual)) {
+      fail("Expected byte array did not match actual.");
+    }
+  }
+
   public void testBytesBufferFeatures() throws Exception {
-    JavaTestHelper o = new JavaTestHelper();
+    
+    final String testString = "testBytesBufferFeatures";
+    final JavaTestHelper o = new JavaTestHelper();
+
     o.setReq_bin((ByteBuffer)null);
     assertNull(o.getReq_bin());
+
+    o.setReq_bin(ByteBuffer.wrap(testString.getBytes()));
+    assertArrayEquals(testString.getBytes(), o.getReq_bin());
+
     o.setReq_bin((byte[])null);
     assertNull(o.getReq_bin());
+
+    o.setReq_bin(testString.getBytes());
+    assertArrayEquals(testString.getBytes(), o.getReq_bin());
+
+    o.setFieldValue(JavaTestHelper._Fields.REQ_BIN, null);
+    assertNull(o.getReq_bin());
+
+    o.setFieldValue(JavaTestHelper._Fields.REQ_BIN, testString.getBytes());
+    assertArrayEquals(testString.getBytes(), o.getReq_bin());
+
+    o.setFieldValue(JavaTestHelper._Fields.REQ_BIN, null);
+    assertNull(o.getReq_bin());
+
+    o.setFieldValue(JavaTestHelper._Fields.REQ_BIN, ByteBuffer.wrap(testString.getBytes()));
+    assertArrayEquals(testString.getBytes(), o.getReq_bin());
   }
 
   public void testJavaSerializable() throws Exception {
diff --git a/lib/java/test/org/apache/thrift/TestUnsafeBinaries.java b/lib/java/test/org/apache/thrift/TestUnsafeBinaries.java
new file mode 100644
index 0000000..d1fc213
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/TestUnsafeBinaries.java
@@ -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 org.apache.thrift;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import thrift.test.SafeBytes;
+import thrift.test.UnsafeBytes;
+
+//  test generating types with un-copied byte[]/ByteBuffer input/output
+//
+public class TestUnsafeBinaries extends TestStruct {
+
+  private static byte[] input() {
+    return new byte[]{1, 1};
+  }
+
+  //
+  //  verify that the unsafe_binaries option modifies behavior
+  //
+
+  //  constructor doesn't copy
+  public void testUnsafeConstructor() throws Exception {
+
+    byte[] input = input();
+    UnsafeBytes struct = new UnsafeBytes(ByteBuffer.wrap(input));
+
+    input[0] = 2;
+
+    assertTrue(Arrays.equals(
+        new byte[]{2, 1},
+        struct.getBytes())
+    );
+
+  }
+
+  //  getter doesn't copy
+  //  note: this behavior is the same with/without the flag, but if this default ever changes, the current behavior
+  //        should be retained when using this flag
+  public void testUnsafeGetter(){
+    UnsafeBytes struct = new UnsafeBytes(ByteBuffer.wrap(input()));
+
+    byte[] val = struct.getBytes();
+    val[0] = 2;
+
+    assertTrue(Arrays.equals(
+        new byte[]{2, 1},
+        struct.getBytes())
+    );
+
+  }
+
+  //  setter doesn't copy
+  public void testUnsafeSetter(){
+    UnsafeBytes struct = new UnsafeBytes();
+
+    byte[] val = input();
+    struct.setBytes(val);
+
+    val[0] = 2;
+
+    assertTrue(Arrays.equals(
+        new byte[]{2, 1},
+        struct.getBytes())
+    );
+
+  }
+
+  //  buffer doens't copy
+  public void testUnsafeBufferFor(){
+    UnsafeBytes struct = new UnsafeBytes(ByteBuffer.wrap(input()));
+
+    ByteBuffer val = struct.bufferForBytes();
+    val.array()[0] = 2;
+
+    assertTrue(Arrays.equals(
+        new byte[]{2, 1},
+        struct.getBytes())
+    );
+
+  }
+
+  //
+  //  verify that the default generator does not change behavior
+  //
+
+  public void testSafeConstructor() {
+
+    byte[] input = input();
+    SafeBytes struct = new SafeBytes(ByteBuffer.wrap(input));
+
+    input[0] = 2;
+
+    assertTrue(Arrays.equals(
+        new byte[]{1, 1},
+        struct.getBytes())
+    );
+
+  }
+
+  public void testSafeSetter() {
+
+    byte[] input = input();
+    SafeBytes struct = new SafeBytes(ByteBuffer.wrap(input));
+
+    input[0] = 2;
+
+    assertTrue(Arrays.equals(
+        new byte[]{1, 1},
+        struct.getBytes())
+    );
+
+  }
+
+  public void testSafeBufferFor(){
+    SafeBytes struct = new SafeBytes(ByteBuffer.wrap(input()));
+
+    ByteBuffer val = struct.bufferForBytes();
+    val.array()[0] = 2;
+
+    assertTrue(Arrays.equals(
+        new byte[]{1, 1},
+        struct.getBytes())
+    );
+
+  }
+
+}
diff --git a/lib/java/test/org/apache/thrift/async/TestTAsyncClientManager.java b/lib/java/test/org/apache/thrift/async/TestTAsyncClientManager.java
index d88b8a5..c483cf2 100644
--- a/lib/java/test/org/apache/thrift/async/TestTAsyncClientManager.java
+++ b/lib/java/test/org/apache/thrift/async/TestTAsyncClientManager.java
@@ -22,11 +22,13 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
 
 import junit.framework.TestCase;
 
@@ -39,12 +41,9 @@
 import org.apache.thrift.transport.TNonblockingSocket;
 
 import thrift.test.CompactProtoTestStruct;
+import thrift.test.ExceptionWithAMap;
 import thrift.test.Srv;
 import thrift.test.Srv.Iface;
-import thrift.test.Srv.AsyncClient.Janky_call;
-import thrift.test.Srv.AsyncClient.onewayMethod_call;
-import thrift.test.Srv.AsyncClient.primitiveMethod_call;
-import thrift.test.Srv.AsyncClient.voidMethod_call;
 
 public class TestTAsyncClientManager extends TestCase {
 
@@ -53,7 +52,9 @@
   private TAsyncClientManager clientManager_;
 
   public void setUp() throws Exception {
-    server_ = new THsHaServer(new Args(new TNonblockingServerSocket(ServerTestBase.PORT)).processor(new Srv.Processor(new SrvHandler())));
+    server_ = new THsHaServer(new Args(new TNonblockingServerSocket(
+      new TNonblockingServerSocket.NonblockingAbstractServerSocketArgs().port(ServerTestBase.PORT))).
+      processor(new Srv.Processor(new SrvHandler())));
     serverThread_ = new Thread(new Runnable() {
       public void run() {
         server_.serve();
@@ -79,82 +80,136 @@
     Srv.AsyncClient client = getClient();
     client.setTimeout(5000);
     basicCall(client);
-  } 
-  
+  }
+
+  private static abstract class ErrorCallTest<C extends TAsyncClient, R> {
+    final void runTest() throws Exception {
+      final CountDownLatch latch = new CountDownLatch(1);
+      final AtomicReference<Exception> error = new AtomicReference<Exception>();
+      C client = executeErroringCall(new AsyncMethodCallback<R>() {
+        @Override
+        public void onComplete(R response) {
+          latch.countDown();
+        }
+
+        @Override
+        public void onError(Exception exception) {
+          error.set(exception);
+          latch.countDown();
+        }
+      });
+      latch.await(2, TimeUnit.SECONDS);
+      assertTrue(client.hasError());
+      Exception exception = error.get();
+      assertNotNull(exception);
+      assertSame(exception, client.getError());
+      validateError(client, exception);
+    }
+
+    /**
+     * Executes a call that is expected to raise an exception.
+     *
+     * @param callback The testing callback that should be installed.
+     * @return The client the call was made against.
+     * @throws Exception if there was a problem setting up the client or making the call.
+     */
+    abstract C executeErroringCall(AsyncMethodCallback<R> callback) throws Exception;
+
+    /**
+     * Further validates the properties of the error raised in the remote call and the state of the
+     * client after that call.
+     *
+     * @param client The client returned from {@link #executeErroringCall(AsyncMethodCallback)}.
+     * @param error The exception raised by the remote call.
+     */
+    abstract void validateError(C client, Exception error);
+  }
+
+  public void testUnexpectedRemoteExceptionCall() throws Exception {
+    new ErrorCallTest<Srv.AsyncClient, Boolean>() {
+      @Override
+      Srv.AsyncClient executeErroringCall(AsyncMethodCallback<Boolean> callback) throws Exception {
+        Srv.AsyncClient client = getClient();
+        client.declaredExceptionMethod(false, callback);
+        return client;
+      }
+
+      @Override
+      void validateError(Srv.AsyncClient client, Exception error) {
+        assertFalse(client.hasTimeout());
+        assertTrue(error instanceof TException);
+      }
+    }.runTest();
+  }
+
+  public void testDeclaredRemoteExceptionCall() throws Exception {
+    new ErrorCallTest<Srv.AsyncClient, Boolean>() {
+      @Override
+      Srv.AsyncClient executeErroringCall(AsyncMethodCallback<Boolean> callback) throws Exception {
+        Srv.AsyncClient client = getClient();
+        client.declaredExceptionMethod(true, callback);
+        return client;
+      }
+
+      @Override
+      void validateError(Srv.AsyncClient client, Exception error) {
+        assertFalse(client.hasTimeout());
+        assertEquals(ExceptionWithAMap.class, error.getClass());
+        ExceptionWithAMap exceptionWithAMap = (ExceptionWithAMap) error;
+        assertEquals("blah", exceptionWithAMap.getBlah());
+        assertEquals(new HashMap<String, String>(), exceptionWithAMap.getMap_field());
+      }
+    }.runTest();
+  }
+
   public void testTimeoutCall() throws Exception {
-    final CountDownLatch latch = new CountDownLatch(1);
-    Srv.AsyncClient client = getClient();
-    client.setTimeout(100);
-    client.primitiveMethod(new AsyncMethodCallback<primitiveMethod_call>() {
+    new ErrorCallTest<Srv.AsyncClient, Integer>() {
       @Override
-      public void onError(Exception exception) {
-        try {
-          if (!(exception instanceof TimeoutException)) {
-            StringWriter sink = new StringWriter();
-            exception.printStackTrace(new PrintWriter(sink, true));
-            fail("expected TimeoutException but got " + sink.toString());
-          }
-        } finally {
-          latch.countDown();
-        }
+      Srv.AsyncClient executeErroringCall(AsyncMethodCallback<Integer> callback) throws Exception {
+        Srv.AsyncClient client = getClient();
+        client.setTimeout(100);
+        client.primitiveMethod(callback);
+        return client;
       }
-      
+
       @Override
-      public void onComplete(primitiveMethod_call response) {
-        try {
-          fail("Should not have finished timed out call.");
-        } finally {
-          latch.countDown();
-        }
+      void validateError(Srv.AsyncClient client, Exception error) {
+        assertTrue(client.hasTimeout());
+        assertTrue(error instanceof TimeoutException);
       }
-    });
-    latch.await(2, TimeUnit.SECONDS);
-    assertTrue(client.hasError());
-    assertTrue(client.getError() instanceof TimeoutException);
-  } 
-  
+    }.runTest();
+  }
+
   public void testVoidCall() throws Exception {
     final CountDownLatch latch = new CountDownLatch(1);
     final AtomicBoolean returned = new AtomicBoolean(false);
     Srv.AsyncClient client = getClient();
-    client.voidMethod(new FailureLessCallback<Srv.AsyncClient.voidMethod_call>() {
+    client.voidMethod(new FailureLessCallback<Void>() {
       @Override
-      public void onComplete(voidMethod_call response) {
-        try {
-          response.getResult();
-          returned.set(true);
-        } catch (TException e) {
-          fail(e);
-        } finally {
-          latch.countDown();
-        }
+      public void onComplete(Void response) {
+        returned.set(true);
+        latch.countDown();
       }
     });
     latch.await(1, TimeUnit.SECONDS);
     assertTrue(returned.get());
-  } 
-  
+  }
+
   public void testOnewayCall() throws Exception {
     final CountDownLatch latch = new CountDownLatch(1);
     final AtomicBoolean returned = new AtomicBoolean(false);
     Srv.AsyncClient client = getClient();
-    client.onewayMethod(new FailureLessCallback<onewayMethod_call>() {
+    client.onewayMethod(new FailureLessCallback<Void>() {
       @Override
-      public void onComplete(onewayMethod_call response) {
-        try {
-          response.getResult();
-          returned.set(true);
-        } catch (TException e) {
-          fail(e);
-        } finally {
-          latch.countDown();
-        }
+      public void onComplete(Void response) {
+        returned.set(true);
+        latch.countDown();
       }
     });
     latch.await(1, TimeUnit.SECONDS);
     assertTrue(returned.get());
-  } 
-  
+  }
+
   public void testParallelCalls() throws Exception {
     // make multiple calls with deserialization in the selector thread (repro Eric's issue)
     int numThreads = 50;
@@ -176,29 +231,24 @@
       numSuccesses += runnable.getNumSuccesses();
     }
     assertEquals(numThreads * numCallsPerThread, numSuccesses);
-  }  
-  
+  }
+
   private Srv.AsyncClient getClient() throws IOException {
     TNonblockingSocket clientSocket = new TNonblockingSocket(ServerTestBase.HOST, ServerTestBase.PORT);
     return new Srv.AsyncClient(new TBinaryProtocol.Factory(), clientManager_, clientSocket);
   }
-  
+
   private void basicCall(Srv.AsyncClient client) throws Exception {
     final CountDownLatch latch = new CountDownLatch(1);
     final AtomicBoolean returned = new AtomicBoolean(false);
-    client.Janky(1, new FailureLessCallback<Srv.AsyncClient.Janky_call>() {
+    client.Janky(1, new FailureLessCallback<Integer>() {
       @Override
-      public void onComplete(Janky_call response) {
-        try {
-          assertEquals(3, response.getResult());
-          returned.set(true);
-        } catch (TException e) {
-          fail(e);
-        } finally {
-          latch.countDown();
-        }
+      public void onComplete(Integer response) {
+        assertEquals(3, response.intValue());
+        returned.set(true);
+        latch.countDown();
       }
-      
+
       @Override
       public void onError(Exception exception) {
         try {
@@ -213,7 +263,7 @@
     latch.await(100, TimeUnit.SECONDS);
     assertTrue(returned.get());
   }
-  
+
   public class SrvHandler implements Iface {
     // Use this method for a standard call testing
     @Override
@@ -232,7 +282,7 @@
       }
       return 0;
     }
-    
+
     @Override
     public void methodWithDefaultArgs(int something) throws TException { }
 
@@ -248,21 +298,30 @@
     @Override
     public void onewayMethod() throws TException {
     }
+
+    @Override
+    public boolean declaredExceptionMethod(boolean shouldThrowDeclared) throws TException {
+      if (shouldThrowDeclared) {
+        throw new ExceptionWithAMap("blah", new HashMap<String, String>());
+      } else {
+        throw new TException("Unexpected!");
+      }
+    }
   }
-  
-  private static abstract class FailureLessCallback<T extends TAsyncMethodCall> implements AsyncMethodCallback<T> {
+
+  private static abstract class FailureLessCallback<T> implements AsyncMethodCallback<T> {
     @Override
     public void onError(Exception exception) {
       fail(exception);
     }
   }
-  
+
   private static void fail(Exception exception) {
     StringWriter sink = new StringWriter();
     exception.printStackTrace(new PrintWriter(sink, true));
     fail("unexpected error " + sink.toString());
   }
-  
+
   private class JankyRunnable implements Runnable {
     private int numCalls_;
     private int numSuccesses_ = 0;
@@ -285,18 +344,13 @@
           // connect an async client
           final CountDownLatch latch = new CountDownLatch(1);
           final AtomicBoolean returned = new AtomicBoolean(false);
-          client_.Janky(1, new AsyncMethodCallback<Srv.AsyncClient.Janky_call>() {
-            
+          client_.Janky(1, new AsyncMethodCallback<Integer>() {
+
             @Override
-            public void onComplete(Janky_call response) {
-              try {
-                assertEquals(3, response.getResult());
-                returned.set(true);
-                latch.countDown();
-              } catch (TException e) {
-                latch.countDown();
-                fail(e);
-              }
+            public void onComplete(Integer result) {
+              assertEquals(3, result.intValue());
+              returned.set(true);
+              latch.countDown();
             }
 
             @Override
@@ -321,4 +375,4 @@
       }
     }
   }
-}
\ No newline at end of file
+}
diff --git a/lib/java/test/org/apache/thrift/protocol/ProtocolTestBase.java b/lib/java/test/org/apache/thrift/protocol/ProtocolTestBase.java
index 2ac0211..0386d83 100644
--- a/lib/java/test/org/apache/thrift/protocol/ProtocolTestBase.java
+++ b/lib/java/test/org/apache/thrift/protocol/ProtocolTestBase.java
@@ -327,6 +327,11 @@
       @Override
       public void onewayMethod() throws TException {
       }
+
+      @Override
+      public boolean declaredExceptionMethod(boolean shouldThrow) throws TException {
+        return shouldThrow;
+      }
     };
 
     Srv.Processor testProcessor = new Srv.Processor(handler);
diff --git a/lib/java/test/org/apache/thrift/protocol/TestShortStack.java b/lib/java/test/org/apache/thrift/protocol/TestShortStack.java
new file mode 100644
index 0000000..c8e78ee
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/protocol/TestShortStack.java
@@ -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 org.apache.thrift.protocol;
+
+import junit.framework.TestCase;
+
+public class TestShortStack extends TestCase {
+
+  public void testOps() throws Exception {
+    ShortStack s = new ShortStack(1);
+    s.push((short)10);
+    s.push((short)11);
+    s.push((short)12);
+    assertEquals((short)12, s.pop());
+    assertEquals((short)11, s.pop());
+    s.push((short)40);
+    assertEquals((short)40, s.pop());
+    assertEquals((short)10, s.pop());
+    try {
+      s.pop();
+      fail("should have thrown an exception!");
+    } catch (Exception e) {
+      // yay
+    }
+  }
+}
diff --git a/lib/java/test/org/apache/thrift/protocol/TestTJSONProtocol.java b/lib/java/test/org/apache/thrift/protocol/TestTJSONProtocol.java
index d7376ac..c2ca1fa 100644
--- a/lib/java/test/org/apache/thrift/protocol/TestTJSONProtocol.java
+++ b/lib/java/test/org/apache/thrift/protocol/TestTJSONProtocol.java
@@ -18,6 +18,12 @@
  */
 package org.apache.thrift.protocol;
 
+import java.nio.charset.StandardCharsets;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TJSONProtocol;
+import org.apache.thrift.transport.TMemoryBuffer;
+
 public class TestTJSONProtocol extends ProtocolTestBase {
   @Override
   protected TProtocolFactory getFactory() {
@@ -28,4 +34,15 @@
   protected boolean canBeUsedNaked() {
     return false;
   }
+
+  public void testEscapedUnicode() throws TException {
+    String jsonString = "\"hello unicode \\u0e01\\ud834\\udd1e world\"";
+    String expectedString = "hello unicode \u0e01\ud834\udd1e world";
+
+    TMemoryBuffer buffer = new TMemoryBuffer(1000);
+    TJSONProtocol protocol = new TJSONProtocol(buffer);
+    buffer.write(jsonString.getBytes(StandardCharsets.UTF_8));
+
+    assertEquals(expectedString, protocol.readString());
+  }
 }
diff --git a/lib/java/test/org/apache/thrift/protocol/TestTProtocolUtil.java b/lib/java/test/org/apache/thrift/protocol/TestTProtocolUtil.java
index 199c707..89cf536 100644
--- a/lib/java/test/org/apache/thrift/protocol/TestTProtocolUtil.java
+++ b/lib/java/test/org/apache/thrift/protocol/TestTProtocolUtil.java
@@ -18,24 +18,10 @@
  */
 package org.apache.thrift.protocol;
 
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-
 import junit.framework.TestCase;
 
-import org.apache.thrift.Fixtures;
-import org.apache.thrift.TBase;
-import org.apache.thrift.TDeserializer;
-import org.apache.thrift.TException;
 import org.apache.thrift.TSerializer;
-import org.apache.thrift.transport.TMemoryBuffer;
 
-import thrift.test.CompactProtoTestStruct;
-import thrift.test.HolyMoley;
-import thrift.test.Nesting;
-import thrift.test.OneOfEach;
-import thrift.test.Srv;
 import thrift.test.GuessProtocolStruct;
 
 public class TestTProtocolUtil extends TestCase {
diff --git a/lib/java/test/org/apache/thrift/protocol/TestTSimpleJSONProtocol.java b/lib/java/test/org/apache/thrift/protocol/TestTSimpleJSONProtocol.java
new file mode 100644
index 0000000..9d125b1
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/protocol/TestTSimpleJSONProtocol.java
@@ -0,0 +1,94 @@
+/*
+ * 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 org.apache.thrift.protocol;
+
+import java.nio.charset.StandardCharsets;
+
+import junit.framework.TestCase;
+
+import org.apache.thrift.Fixtures;
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TMemoryBuffer;
+
+import thrift.test.CompactProtoTestStruct;
+import thrift.test.HolyMoley;
+
+public class TestTSimpleJSONProtocol extends TestCase {
+  private TMemoryBuffer buf;
+  private TSimpleJSONProtocol proto;
+
+  @Override
+  protected void setUp() throws Exception {
+    buf = new TMemoryBuffer(1000);
+    proto = new TSimpleJSONProtocol(buf);
+  }
+
+  private String bufToString() {
+    return buf.toString(StandardCharsets.UTF_8);
+  }
+
+  public void testHolyMoley() throws TException {
+    final HolyMoley holyMoley = Fixtures.holyMoley.deepCopy();
+    // unset sets that produce inconsistent ordering between JDK7/8
+    holyMoley.unsetBonks();
+    holyMoley.unsetContain();
+    holyMoley.write(proto);
+    assertEquals("{\"big\":[{\"im_true\":1,\"im_false\":0,\"a_bite\":35,\"integer16\":27000,\"integer32\":16777216,\"integer64\":6000000000,\"double_precision\":3.141592653589793,\"some_characters\":\"JSON THIS! \\\"\\u0001\",\"zomg_unicode\":\"ӀⅮΝ Нοⅿоɡгаρℎ Αttαⅽκ�‼\",\"what_who\":0,\"base64\":\"base64\",\"byte_list\":[1,2,3],\"i16_list\":[1,2,3],\"i64_list\":[1,2,3]},{\"im_true\":1,\"im_false\":0,\"a_bite\":-42,\"integer16\":27000,\"integer32\":16777216,\"integer64\":6000000000,\"double_precision\":3.141592653589793,\"some_characters\":\"JSON THIS! \\\"\\u0001\",\"zomg_unicode\":\"ӀⅮΝ Нοⅿоɡгаρℎ Αttαⅽκ�‼\",\"what_who\":0,\"base64\":\"base64\",\"byte_list\":[1,2,3],\"i16_list\":[1,2,3],\"i64_list\":[1,2,3]}]}", bufToString());
+  }
+
+  public void testNesting() throws TException {
+    Fixtures.nesting.write(proto);
+    assertEquals("{\"my_bonk\":{\"type\":31337,\"message\":\"I am a bonk... xor!\"},\"my_ooe\":{\"im_true\":1,\"im_false\":0,\"a_bite\":-42,\"integer16\":27000,\"integer32\":16777216,\"integer64\":6000000000,\"double_precision\":3.141592653589793,\"some_characters\":\"JSON THIS! \\\"\\u0001\",\"zomg_unicode\":\"ӀⅮΝ Нοⅿоɡгаρℎ Αttαⅽκ�‼\",\"what_who\":0,\"base64\":\"base64\",\"byte_list\":[1,2,3],\"i16_list\":[1,2,3],\"i64_list\":[1,2,3]}}", bufToString());
+  }
+
+  public void testOneOfEach() throws TException {
+    Fixtures.oneOfEach.write(proto);
+    assertEquals("{\"im_true\":1,\"im_false\":0,\"a_bite\":-42,\"integer16\":27000,\"integer32\":16777216,\"integer64\":6000000000,\"double_precision\":3.141592653589793,\"some_characters\":\"JSON THIS! \\\"\\u0001\",\"zomg_unicode\":\"ӀⅮΝ Нοⅿоɡгаρℎ Αttαⅽκ�‼\",\"what_who\":0,\"base64\":\"base64\",\"byte_list\":[1,2,3],\"i16_list\":[1,2,3],\"i64_list\":[1,2,3]}", bufToString());
+  }
+
+  public void testSanePartsOfCompactProtoTestStruct() throws TException {
+    // unset all the maps with container keys
+    CompactProtoTestStruct struct = Fixtures.compactProtoTestStruct.deepCopy();
+    struct.unsetList_byte_map();
+    struct.unsetSet_byte_map();
+    struct.unsetMap_byte_map();
+    // unset sets and maps that produce inconsistent ordering between JDK7/8
+    struct.unsetByte_set();
+    struct.unsetI16_set();
+    struct.unsetI64_set();
+    struct.unsetDouble_set();
+    struct.unsetString_set();
+    struct.unsetI16_byte_map();
+    struct.unsetI32_byte_map();
+    struct.unsetI64_byte_map();
+    struct.unsetDouble_byte_map();
+    struct.unsetString_byte_map();
+    struct.write(proto);
+    assertEquals("{\"a_byte\":127,\"a_i16\":32000,\"a_i32\":1000000000,\"a_i64\":1099511627775,\"a_double\":5.6789,\"a_string\":\"my string\",\"a_binary\":\"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\",\"true_field\":1,\"false_field\":0,\"empty_struct_field\":{},\"byte_list\":[-127,-1,0,1,127],\"i16_list\":[-1,0,1,32767],\"i32_list\":[-1,0,255,65535,16777215,2147483647],\"i64_list\":[-1,0,255,65535,16777215,4294967295,1099511627775,281474976710655,72057594037927935,9223372036854775807],\"double_list\":[0.1,0.2,0.3],\"string_list\":[\"first\",\"second\",\"third\"],\"boolean_list\":[1,1,1,0,0,0],\"struct_list\":[{},{}],\"i32_set\":[1,2,3],\"boolean_set\":[0,1],\"struct_set\":[{}],\"byte_byte_map\":{\"1\":2},\"boolean_byte_map\":{\"0\":0,\"1\":1},\"byte_i16_map\":{\"1\":1,\"2\":-1,\"3\":32767},\"byte_i32_map\":{\"1\":1,\"2\":-1,\"3\":2147483647},\"byte_i64_map\":{\"1\":1,\"2\":-1,\"3\":9223372036854775807},\"byte_double_map\":{\"1\":0.1,\"2\":-0.1,\"3\":1000000.1},\"byte_string_map\":{\"1\":\"\",\"2\":\"blah\",\"3\":\"loooooooooooooong string\"},\"byte_boolean_map\":{\"1\":1,\"2\":0},\"byte_map_map\":{\"0\":{},\"1\":{\"1\":1},\"2\":{\"1\":1,\"2\":2}},\"byte_set_map\":{\"0\":[],\"1\":[1],\"2\":[1,2]},\"byte_list_map\":{\"0\":[],\"1\":[1],\"2\":[1,2]}}", bufToString());
+  }
+
+  public void testThrowsOnCollectionKeys() throws TException {
+    try {
+      Fixtures.compactProtoTestStruct.write(proto);
+      fail("this should throw a CollectionMapKeyException");
+    } catch (TSimpleJSONProtocol.CollectionMapKeyException e) {
+      //
+    }
+  }
+}
diff --git a/lib/java/test/org/apache/thrift/server/ServerTestBase.java b/lib/java/test/org/apache/thrift/server/ServerTestBase.java
old mode 100755
new mode 100644
index 4cbb511..1dee22d
--- a/lib/java/test/org/apache/thrift/server/ServerTestBase.java
+++ b/lib/java/test/org/apache/thrift/server/ServerTestBase.java
@@ -26,6 +26,8 @@
 import java.util.Map;
 import java.util.Set;
 
+import java.nio.ByteBuffer;
+
 import junit.framework.TestCase;
 
 import org.apache.thrift.TException;
@@ -52,38 +54,54 @@
 public abstract class ServerTestBase extends TestCase {
 
   public static class TestHandler implements ThriftTest.Iface {
-  
+
     public TestHandler() {}
-  
+
     public void testVoid() {
       System.out.print("testVoid()\n");
     }
-  
+
     public String testString(String thing) {
       System.out.print("testString(\"" + thing + "\")\n");
       return thing;
     }
-  
+
+    public boolean testBool(boolean thing) {
+      System.out.print("testBool(" + thing + ")\n");
+      return thing;
+    }
+
     public byte testByte(byte thing) {
       System.out.print("testByte(" + thing + ")\n");
       return thing;
     }
-  
+
     public int testI32(int thing) {
       System.out.print("testI32(" + thing + ")\n");
       return thing;
     }
-  
+
     public long testI64(long thing) {
       System.out.print("testI64(" + thing + ")\n");
       return thing;
     }
-  
+
     public double testDouble(double thing) {
       System.out.print("testDouble(" + thing + ")\n");
       return thing;
     }
-  
+
+    public ByteBuffer testBinary(ByteBuffer thing) {
+      StringBuilder sb = new StringBuilder(thing.remaining() * 3);
+      thing.mark();
+      while (thing.remaining() > 0) {
+        sb.append(String.format("%02X ", thing.get()));
+      }
+      System.out.print("testBinary(" + sb.toString() + ")\n");
+      thing.reset();
+      return thing;
+    }
+
     public Xtruct testStruct(Xtruct thing) {
       System.out.print("testStruct({" +
                        "\"" + thing.string_thing + "\", " +
@@ -92,7 +110,7 @@
                        thing.i64_thing + "})\n");
       return thing;
     }
-  
+
     public Xtruct2 testNest(Xtruct2 nest) {
       Xtruct thing = nest.struct_thing;
       System.out.print("testNest({" +
@@ -104,7 +122,7 @@
                        nest.i32_thing + "})\n");
       return nest;
     }
-  
+
     public Map<Integer,Integer> testMap(Map<Integer,Integer> thing) {
       System.out.print("testMap({");
       System.out.print(thing);
@@ -118,7 +136,7 @@
       System.out.print("})\n");
       return thing;
     }
-  
+
     public Set<Integer> testSet(Set<Integer> thing) {
       System.out.print("testSet({");
       boolean first = true;
@@ -133,7 +151,7 @@
       System.out.print("})\n");
       return thing;
     }
-  
+
     public List<Integer> testList(List<Integer> thing) {
       System.out.print("testList({");
       boolean first = true;
@@ -148,78 +166,58 @@
       System.out.print("})\n");
       return thing;
     }
-  
+
     public Numberz testEnum(Numberz thing) {
       System.out.print("testEnum(" + thing + ")\n");
       return thing;
     }
-  
+
     public long testTypedef(long thing) {
       System.out.print("testTypedef(" + thing + ")\n");
       return thing;
     }
-  
+
     public Map<Integer,Map<Integer,Integer>> testMapMap(int hello) {
       System.out.print("testMapMap(" + hello + ")\n");
       Map<Integer,Map<Integer,Integer>> mapmap =
         new HashMap<Integer,Map<Integer,Integer>>();
-  
+
       HashMap<Integer,Integer> pos = new HashMap<Integer,Integer>();
       HashMap<Integer,Integer> neg = new HashMap<Integer,Integer>();
       for (int i = 1; i < 5; i++) {
         pos.put(i, i);
         neg.put(-i, -i);
       }
-  
+
       mapmap.put(4, pos);
       mapmap.put(-4, neg);
-  
+
       return mapmap;
     }
-  
+
     public Map<Long, Map<Numberz,Insanity>> testInsanity(Insanity argument) {
       System.out.print("testInsanity()\n");
-  
-      Xtruct hello = new Xtruct();
-      hello.string_thing = "Hello2";
-      hello.byte_thing = 2;
-      hello.i32_thing = 2;
-      hello.i64_thing = 2;
-  
-      Xtruct goodbye = new Xtruct();
-      goodbye.string_thing = "Goodbye4";
-      goodbye.byte_thing = (byte)4;
-      goodbye.i32_thing = 4;
-      goodbye.i64_thing = (long)4;
-  
-      Insanity crazy = new Insanity();
-      crazy.userMap = new HashMap<Numberz, Long>();
-      crazy.userMap.put(Numberz.EIGHT, (long)8);
-      crazy.userMap.put(Numberz.FIVE, (long)5);
-      crazy.xtructs = new ArrayList<Xtruct>();
-      crazy.xtructs.add(goodbye);
-      crazy.xtructs.add(hello);
-  
+
       HashMap<Numberz,Insanity> first_map = new HashMap<Numberz, Insanity>();
       HashMap<Numberz,Insanity> second_map = new HashMap<Numberz, Insanity>();;
-  
-      first_map.put(Numberz.TWO, crazy);
-      first_map.put(Numberz.THREE, crazy);
-  
+
+      first_map.put(Numberz.TWO, argument);
+      first_map.put(Numberz.THREE, argument);
+
       Insanity looney = new Insanity();
       second_map.put(Numberz.SIX, looney);
-  
+
       Map<Long,Map<Numberz,Insanity>> insane =
         new HashMap<Long, Map<Numberz,Insanity>>();
       insane.put((long)1, first_map);
       insane.put((long)2, second_map);
-  
+
       return insane;
     }
-  
+
     public Xtruct testMulti(byte arg0, int arg1, long arg2, Map<Short,String> arg3, Numberz arg4, long arg5) {
       System.out.print("testMulti()\n");
-  
+
       Xtruct hello = new Xtruct();;
       hello.string_thing = "Hello2";
       hello.byte_thing = arg0;
@@ -227,23 +225,24 @@
       hello.i64_thing = arg2;
       return hello;
     }
-  
+
     public void testException(String arg) throws Xception, TException {
       System.out.print("testException("+arg+")\n");
-      if (arg.equals("Xception")) {
+      if ("Xception".equals(arg)) {
         Xception x = new Xception();
         x.errorCode = 1001;
         x.message = arg;
         throw x;
-      } else if (arg.equals("TException")) {
-        throw new TException(arg);
+      } else if ("TException".equals(arg)) {
+        // Unspecified exception should yield a TApplicationException on client side
+        throw new RuntimeException(arg);
       } else {
         Xtruct result = new Xtruct();
         result.string_thing = arg;
       }
       return;
     }
-  
+
     public Xtruct testMultiException(String arg0, String arg1) throws Xception, Xception2 {
       System.out.print("testMultiException(" + arg0 + ", " + arg1 + ")\n");
       if (arg0.equals("Xception")) {
@@ -258,17 +257,17 @@
         x.struct_thing.string_thing = "This is an Xception2";
         throw x;
       }
-  
+
       Xtruct result = new Xtruct();
       result.string_thing = arg1;
       return result;
     }
-  
+
     public void testOneway(int sleepFor) {
       System.out.println("testOneway(" + Integer.toString(sleepFor) +
                          ") => sleeping...");
       try {
-        Thread.sleep(sleepFor * 1000);
+        Thread.sleep(sleepFor * SLEEP_DELAY);
         System.out.println("Done sleeping!");
       } catch (InterruptedException ie) {
         throw new RuntimeException(ie);
@@ -283,7 +282,8 @@
   public static final String HOST = "localhost";
   public static final int PORT = Integer.valueOf(
     System.getProperty("test.port", "9090"));
-  protected static final int SOCKET_TIMEOUT = 1000;
+  protected static final int SLEEP_DELAY = 1000;
+  protected static final int SOCKET_TIMEOUT = 1500;
   private static final Xtruct XSTRUCT = new Xtruct("Zero", (byte) 1, -3, -5);
   private static final Xtruct2 XSTRUCT2 = new Xtruct2((byte)1, XSTRUCT, 5);
 
@@ -297,6 +297,13 @@
 
   public abstract TTransport getClientTransport(TTransport underlyingTransport) throws Exception;
 
+  private void testBool(ThriftTest.Client testClient) throws TException {
+    boolean t = testClient.testBool(true);
+    assertEquals(true, t);
+    boolean f = testClient.testBool(false);
+    assertEquals(false, f);
+  }
+
   private void testByte(ThriftTest.Client testClient) throws TException {
     byte i8 = testClient.testByte((byte)1);
     assertEquals(1, i8);
@@ -328,7 +335,7 @@
   // todo: add assertions
   private void testInsanity(ThriftTest.Client testClient) throws TException {
     Insanity insane;
-  
+
     insane = new Insanity();
     insane.userMap = new HashMap<Numberz, Long>();
     insane.userMap.put(Numberz.FIVE, (long)5000);
@@ -346,7 +353,7 @@
     for (long key : whoa.keySet()) {
       Map<Numberz,Insanity> val = whoa.get(key);
       System.out.print(key + " => {");
-  
+
       for (Numberz k2 : val.keySet()) {
         Insanity v2 = val.get(k2);
         System.out.print(k2 + " => {");
@@ -358,7 +365,7 @@
           }
         }
         System.out.print("}, ");
-  
+
         List<Xtruct> xtructs = v2.xtructs;
         System.out.print("{");
         if (xtructs != null) {
@@ -367,7 +374,7 @@
           }
         }
         System.out.print("}");
-  
+
         System.out.print("}, ");
       }
       System.out.print("}, ");
@@ -382,7 +389,7 @@
   public void testIt() throws Exception {
 
     for (TProtocolFactory protoFactory : getProtocols()) {
-      TProcessor processor = useAsyncProcessor() ? new ThriftTest.AsyncProcessor(new AsyncTestHandler()) : new ThriftTest.Processor(new TestHandler());
+      TProcessor processor = useAsyncProcessor() ? new ThriftTest.AsyncProcessor<AsyncTestHandler>(new AsyncTestHandler()) : new ThriftTest.Processor<TestHandler>(new TestHandler());
 
       startServer(processor, protoFactory);
 
@@ -396,6 +403,7 @@
       open(transport);
       testVoid(testClient);
       testString(testClient);
+      testBool(testClient);
       testByte(testClient);
       testI32(testClient);
       testI64(testClient);
@@ -410,9 +418,11 @@
       testTypedef(testClient);
       testNestedMap(testClient);
       testInsanity(testClient);
-      testOneway(testClient);
       testException(testClient);
+      testOneway(testClient);
+      testI32(testClient);
       transport.close();
+      socket.close();
 
       stopServer();
     }
@@ -423,7 +433,7 @@
   }
 
   public List<TProtocolFactory> getProtocols() {
-    return PROTOCOLS;  
+    return PROTOCOLS;
   }
 
   private void testList(ThriftTest.Client testClient) throws TException {
@@ -459,14 +469,14 @@
       testClient.testMapMap(1);
     Map<Integer,Map<Integer,Integer>> mapmap =
       new HashMap<Integer,Map<Integer,Integer>>();
-  
+
     HashMap<Integer,Integer> pos = new HashMap<Integer,Integer>();
     HashMap<Integer,Integer> neg = new HashMap<Integer,Integer>();
     for (int i = 1; i < 5; i++) {
       pos.put(i, i);
       neg.put(-i, -i);
     }
-  
+
     mapmap.put(4, pos);
     mapmap.put(-4, neg);
     assertEquals(mapmap, mm);
@@ -478,7 +488,10 @@
   }
 
   private void testOneway(ThriftTest.Client testClient) throws Exception {
-    testClient.testOneway(3);
+    long begin = System.currentTimeMillis();
+    testClient.testOneway(1);
+    long elapsed = System.currentTimeMillis() - begin;
+    assertTrue(elapsed < 500);
   }
 
   private void testSet(ThriftTest.Client testClient) throws TException {
@@ -523,153 +536,176 @@
   }
 
   public void testTransportFactory() throws Exception {
-    
     for (TProtocolFactory protoFactory : getProtocols()) {
       TestHandler handler = new TestHandler();
-      ThriftTest.Processor processor = new ThriftTest.Processor(handler);
-  
+      ThriftTest.Processor<TestHandler> processor = new ThriftTest.Processor<TestHandler>(handler);
+
       final CallCountingTransportFactory factory = new CallCountingTransportFactory(new TFramedTransport.Factory());
-  
+
       startServer(processor, protoFactory, factory);
       assertEquals(0, factory.count);
-  
+
       TSocket socket = new TSocket(HOST, PORT);
       socket.setTimeout(SOCKET_TIMEOUT);
       TTransport transport = getClientTransport(socket);
       open(transport);
-  
+
       TProtocol protocol = protoFactory.getProtocol(transport);
       ThriftTest.Client testClient = new ThriftTest.Client(protocol);
       assertEquals(0, testClient.testByte((byte) 0));
       assertEquals(2, factory.count);
+      socket.close();
       stopServer();
     }
   }
 
   private void testException(ThriftTest.Client testClient) throws TException, Xception {
-    //@TODO testException
-    //testClient.testException("no Exception");
-    /*try {
-        testClient.testException("Xception");
+    try {
+      testClient.testException("Xception");
+      assert false;
     } catch(Xception e) {
-    	assertEquals(e.message, "Xception");
-    }*/
-    /*try {
-        testClient.testException("ApplicationException");
+      assertEquals(e.message, "Xception");
+      assertEquals(e.errorCode, 1001);
+    }
+    try {
+      testClient.testException("TException");
+      assert false;
     } catch(TException e) {
-    	assertEquals(e.message, "ApplicationException");
-    }*/
+    }
+    testClient.testException("no Exception");
   }
 
 
-    public static class AsyncTestHandler implements ThriftTest.AsyncIface {
+  public static class AsyncTestHandler implements ThriftTest.AsyncIface {
 
-        TestHandler handler = new TestHandler();
+    TestHandler handler = new TestHandler();
 
-        @Override
-        public void testVoid(AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(null);
-        }
-
-        @Override
-        public void testString(String thing, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testString(thing));
-        }
-
-        @Override
-        public void testByte(byte thing, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testByte(thing));
-        }
-
-        @Override
-        public void testI32(int thing, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testI32(thing));
-        }
-
-        @Override
-        public void testI64(long thing, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testI64(thing));
-        }
-
-        @Override
-        public void testDouble(double thing, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testDouble(thing));
-        }
-
-        @Override
-        public void testStruct(Xtruct thing, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testStruct(thing));
-        }
-
-        @Override
-        public void testNest(Xtruct2 thing, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testNest(thing));
-        }
-
-        @Override
-        public void testMap(Map<Integer, Integer> thing, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testMap(thing));
-        }
-
-        @Override
-        public void testStringMap(Map<String, String> thing, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testStringMap(thing));
-        }
-
-        @Override
-        public void testSet(Set<Integer> thing, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testSet(thing));
-        }
-
-        @Override
-        public void testList(List<Integer> thing, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testList(thing));
-        }
-
-        @Override
-        public void testEnum(Numberz thing, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testEnum(thing));
-        }
-
-        @Override
-        public void testTypedef(long thing, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testTypedef(thing));
-        }
-
-        @Override
-        public void testMapMap(int hello, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testMapMap(hello));
-        }
-
-        @Override
-        public void testInsanity(Insanity argument, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testInsanity(argument));
-        }
-
-        @Override
-        public void testMulti(byte arg0, int arg1, long arg2, Map<Short, String> arg3, Numberz arg4, long arg5, AsyncMethodCallback resultHandler) throws TException {
-            resultHandler.onComplete(handler.testMulti(arg0,arg1,arg2,arg3,arg4,arg5));
-        }
-
-        @Override
-        public void testException(String arg, AsyncMethodCallback resultHandler) throws TException {
-            try {
-               // handler.testException();
-            } catch (Exception e) {
-
-            }
-        }
-
-        @Override
-        public void testMultiException(String arg0, String arg1, AsyncMethodCallback resultHandler) throws TException {
-            //To change body of implemented methods use File | Settings | File Templates.
-        }
-
-        @Override
-        public void testOneway(int secondsToSleep, AsyncMethodCallback resultHandler) throws TException {
-            handler.testOneway(secondsToSleep);
-            resultHandler.onComplete(null);
-        }
+    @Override
+    public void testVoid(AsyncMethodCallback<Void> resultHandler) throws TException {
+      resultHandler.onComplete(null);
     }
 
+    @Override
+    public void testString(String thing, AsyncMethodCallback<String> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testString(thing));
+    }
+
+    @Override
+    public void testBool(boolean thing, AsyncMethodCallback<Boolean> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testBool(thing));
+    }
+
+    @Override
+    public void testByte(byte thing, AsyncMethodCallback<Byte> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testByte(thing));
+    }
+
+    @Override
+    public void testI32(int thing, AsyncMethodCallback<Integer> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testI32(thing));
+    }
+
+    @Override
+    public void testI64(long thing, AsyncMethodCallback<Long> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testI64(thing));
+    }
+
+    @Override
+    public void testDouble(double thing, AsyncMethodCallback<Double> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testDouble(thing));
+    }
+
+    @Override
+    public void testBinary(ByteBuffer thing, AsyncMethodCallback<ByteBuffer> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testBinary(thing));
+    }
+
+    @Override
+    public void testStruct(Xtruct thing, AsyncMethodCallback<Xtruct> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testStruct(thing));
+    }
+
+    @Override
+    public void testNest(Xtruct2 thing, AsyncMethodCallback<Xtruct2> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testNest(thing));
+    }
+
+    @Override
+    public void testMap(Map<Integer, Integer> thing, AsyncMethodCallback<Map<Integer, Integer>> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testMap(thing));
+    }
+
+    @Override
+    public void testStringMap(Map<String, String> thing, AsyncMethodCallback<Map<String, String>> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testStringMap(thing));
+    }
+
+    @Override
+    public void testSet(Set<Integer> thing, AsyncMethodCallback<Set<Integer>> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testSet(thing));
+    }
+
+    @Override
+    public void testList(List<Integer> thing, AsyncMethodCallback<List<Integer>> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testList(thing));
+    }
+
+    @Override
+    public void testEnum(Numberz thing, AsyncMethodCallback<Numberz> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testEnum(thing));
+    }
+
+    @Override
+    public void testTypedef(long thing, AsyncMethodCallback<Long> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testTypedef(thing));
+    }
+
+    @Override
+    public void testMapMap(int hello, AsyncMethodCallback<Map<Integer,Map<Integer,Integer>>> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testMapMap(hello));
+    }
+
+    @Override
+    public void testInsanity(Insanity argument, AsyncMethodCallback<Map<Long, Map<Numberz,Insanity>>> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testInsanity(argument));
+    }
+
+    @Override
+    public void testMulti(byte arg0, int arg1, long arg2, Map<Short, String> arg3, Numberz arg4, long arg5, AsyncMethodCallback<Xtruct> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testMulti(arg0,arg1,arg2,arg3,arg4,arg5));
+    }
+
+    @Override
+    public void testException(String arg, AsyncMethodCallback<Void> resultHandler) throws TException {
+      System.out.print("testException("+arg+")\n");
+      if ("Xception".equals(arg)) {
+        Xception x = new Xception();
+        x.errorCode = 1001;
+        x.message = arg;
+        // throw and onError yield the same result.
+        // throw x;
+        resultHandler.onError(x);
+        return;
+      } else if ("TException".equals(arg)) {
+        // throw and onError yield the same result.
+        // resultHandler.onError(new TException(arg));
+        // return;
+        // Unspecified exception should yield a TApplicationException on client side
+        throw new RuntimeException(arg);
+      }
+      resultHandler.onComplete(null);
+    }
+
+    @Override
+    public void testMultiException(String arg0, String arg1, AsyncMethodCallback<Xtruct> resultHandler) throws TException {
+      //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void testOneway(int secondsToSleep, AsyncMethodCallback<Void> resultHandler) throws TException {
+      handler.testOneway(secondsToSleep);
+      resultHandler.onComplete(null);
+    }
+  }
+
 }
diff --git a/lib/java/test/org/apache/thrift/server/TestNonblockingServer.java b/lib/java/test/org/apache/thrift/server/TestNonblockingServer.java
index 7837695..3df3bd8 100644
--- a/lib/java/test/org/apache/thrift/server/TestNonblockingServer.java
+++ b/lib/java/test/org/apache/thrift/server/TestNonblockingServer.java
@@ -53,7 +53,7 @@
         try {
           // Transport
           TNonblockingServerSocket tServerSocket =
-            new TNonblockingServerSocket(PORT);
+            new TNonblockingServerSocket(new TNonblockingServerSocket.NonblockingAbstractServerSocketArgs().port(PORT));
 
           server = getServer(processor, tServerSocket, protoFactory, factory);
 
diff --git a/lib/java/test/org/apache/thrift/test/TestClient.java b/lib/java/test/org/apache/thrift/test/TestClient.java
index 4e7e507..feaa972 100644
--- a/lib/java/test/org/apache/thrift/test/TestClient.java
+++ b/lib/java/test/org/apache/thrift/test/TestClient.java
@@ -19,32 +19,40 @@
 
 package org.apache.thrift.test;
 
-// Generated code
-import thrift.test.*;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import org.apache.thrift.TApplicationException;
 import org.apache.thrift.TException;
 import org.apache.thrift.TSerializer;
-import org.apache.thrift.transport.TTransport;
-import org.apache.thrift.transport.TSocket;
-import org.apache.thrift.transport.THttpClient;
-import org.apache.thrift.transport.TFramedTransport;
-import org.apache.thrift.transport.TFastFramedTransport;
-import org.apache.thrift.transport.TTransportException;
-import org.apache.thrift.transport.TSSLTransportFactory;
-import org.apache.thrift.transport.TSSLTransportFactory.TSSLTransportParameters;
 import org.apache.thrift.protocol.TBinaryProtocol;
-import org.apache.thrift.protocol.TProtocol;
-import org.apache.thrift.protocol.TJSONProtocol;
 import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.protocol.TJSONProtocol;
+import org.apache.thrift.protocol.TMultiplexedProtocol;
+import org.apache.thrift.protocol.TProtocol;
 import org.apache.thrift.protocol.TSimpleJSONProtocol;
+import org.apache.thrift.transport.TFastFramedTransport;
+import org.apache.thrift.transport.TFramedTransport;
+import org.apache.thrift.transport.THttpClient;
+import org.apache.thrift.transport.TSSLTransportFactory;
+import org.apache.thrift.transport.TSocket;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportException;
 
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.List;
-import java.util.ArrayList;
+// Generated code
+import thrift.test.Insanity;
+import thrift.test.Numberz;
+import thrift.test.SecondService;
+import thrift.test.ThriftTest;
+import thrift.test.Xception;
+import thrift.test.Xception2;
+import thrift.test.Xtruct;
+import thrift.test.Xtruct2;
 
 /**
  * Test Java client for thrift. Essentially just a copy of the C++ version,
@@ -53,6 +61,14 @@
  *
  */
 public class TestClient {
+
+  private static int ERR_BASETYPES = 1;
+  private static int ERR_STRUCTS = 2;
+  private static int ERR_CONTAINERS = 4;
+  private static int ERR_EXCEPTIONS = 8;
+  private static int ERR_PROTOCOLS = 16;
+  private static int ERR_UNKNOWN = 64;
+
   public static void main(String [] args) {
     String host = "localhost";
     int port = 9090;
@@ -69,8 +85,8 @@
           host = args[i].split("=")[1];
           host.trim();
         } else if (args[i].startsWith("--port")) {
-          port = Integer.valueOf(args[i].split("=")[1]); 
-        } else if (args[i].startsWith("--n") || 
+          port = Integer.valueOf(args[i].split("=")[1]);
+        } else if (args[i].startsWith("--n") ||
             args[i].startsWith("--testloops")){
           numTests = Integer.valueOf(args[i].split("=")[1]);
         } else if (args[i].equals("--timeout")) {
@@ -85,11 +101,11 @@
           ssl = true;
         } else if (args[i].equals("--help")) {
           System.out.println("Allowed options:");
-          System.out.println("  --help\t\t\tProduce help message"); 
+          System.out.println("  --help\t\t\tProduce help message");
           System.out.println("  --host=arg (=" + host + ")\tHost to connect");
           System.out.println("  --port=arg (=" + port + ")\tPort number to connect");
           System.out.println("  --transport=arg (=" + transport_type + ")\n\t\t\t\tTransport: buffered, framed, fastframed, http");
-          System.out.println("  --protocol=arg (=" + protocol_type + ")\tProtocol: binary, json, compact");
+          System.out.println("  --protocol=arg (=" + protocol_type + ")\tProtocol: binary, compact, json, multi, multic, multij");
           System.out.println("  --ssl\t\t\tEncrypted Transport using SSL");
           System.out.println("  --testloops[--n]=arg (=" + numTests + ")\tNumber of Tests");
           System.exit(0);
@@ -97,15 +113,18 @@
       }
     } catch (Exception x) {
       System.err.println("Can not parse arguments! See --help");
-      System.exit(1);
+      System.exit(ERR_UNKNOWN);
     }
 
     try {
       if (protocol_type.equals("binary")) {
       } else if (protocol_type.equals("compact")) {
       } else if (protocol_type.equals("json")) {
+      } else if (protocol_type.equals("multi")) {
+      } else if (protocol_type.equals("multic")) {
+      } else if (protocol_type.equals("multij")) {
       } else {
-        throw new Exception("Unknown protocol type! " + protocol_type); 
+        throw new Exception("Unknown protocol type! " + protocol_type);
       }
       if (transport_type.equals("buffered")) {
       } else if (transport_type.equals("framed")) {
@@ -119,7 +138,7 @@
       }
     } catch (Exception e) {
       System.err.println("Error: " + e.getMessage());
-      System.exit(1);
+      System.exit(ERR_UNKNOWN);
     }
 
     TTransport transport = null;
@@ -146,27 +165,32 @@
       }
     } catch (Exception x) {
       x.printStackTrace();
-      System.exit(1);
+      System.exit(ERR_UNKNOWN);
     }
 
     TProtocol tProtocol = null;
-    if (protocol_type.equals("json")) {
+    TProtocol tProtocol2 = null;
+    if (protocol_type.equals("json") || protocol_type.equals("multij")) {
       tProtocol = new TJSONProtocol(transport);
-    } else if (protocol_type.equals("compact")) {
+    } else if (protocol_type.equals("compact") || protocol_type.equals("multic")) {
       tProtocol = new TCompactProtocol(transport);
     } else {
       tProtocol = new TBinaryProtocol(transport);
     }
 
-    ThriftTest.Client testClient =
-      new ThriftTest.Client(tProtocol);
+    if (protocol_type.startsWith("multi")) {
+      tProtocol2 = new TMultiplexedProtocol(tProtocol, "SecondService");
+      tProtocol = new TMultiplexedProtocol(tProtocol, "ThriftTest");
+    }
+
+    ThriftTest.Client testClient = new ThriftTest.Client(tProtocol);
     Insanity insane = new Insanity();
 
     long timeMin = 0;
     long timeMax = 0;
     long timeTot = 0;
 
-    int failCount = 0;
+    int returnCode = 0;
     for (int test = 0; test < numTests; ++test) {
       try {
         /**
@@ -180,7 +204,7 @@
           } catch (TTransportException ttx) {
             ttx.printStackTrace();
             System.out.println("Connect failed: " + ttx.getMessage());
-            System.exit(1);
+            System.exit(ERR_UNKNOWN);
           }
         }
 
@@ -195,7 +219,7 @@
           System.out.print(" = void\n");
         } catch (TApplicationException tax) {
           tax.printStackTrace();
-          failCount++;
+          returnCode |= ERR_BASETYPES;
         }
 
         /**
@@ -205,19 +229,32 @@
         String s = testClient.testString("Test");
         System.out.print(" = \"" + s + "\"\n");
         if (!s.equals("Test")) {
-          failCount++;
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_BASETYPES;
+          System.out.println("*** FAILURE ***\n");
         }
 
         /**
+         * Multiplexed test
+         */
+        if (protocol_type.startsWith("multi")) {
+          SecondService.Client secondClient = new SecondService.Client(tProtocol2);
+          System.out.print("secondtestString(\"Test2\")");
+          s = secondClient.secondtestString("Test2");
+          System.out.print(" = \"" + s + "\"\n");
+          if (!s.equals("testString(\"Test2\")")) {
+            returnCode |= ERR_PROTOCOLS;
+            System.out.println("*** FAILURE ***\n");
+          }
+        }
+        /**
          * BYTE TEST
          */
         System.out.print("testByte(1)");
         byte i8 = testClient.testByte((byte)1);
         System.out.print(" = " + i8 + "\n");
         if (i8 != 1) {
-          failCount++; 
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_BASETYPES;
+          System.out.println("*** FAILURE ***\n");
         }
 
         /**
@@ -227,8 +264,8 @@
         int i32 = testClient.testI32(-1);
         System.out.print(" = " + i32 + "\n");
         if (i32 != -1) {
-          failCount++; 
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_BASETYPES;
+          System.out.println("*** FAILURE ***\n");
         }
 
         /**
@@ -238,8 +275,8 @@
         long i64 = testClient.testI64(-34359738368L);
         System.out.print(" = " + i64 + "\n");
         if (i64 != -34359738368L) {
-          failCount++;
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_BASETYPES;
+          System.out.println("*** FAILURE ***\n");
         }
 
         /**
@@ -249,8 +286,39 @@
         double dub = testClient.testDouble(-5.325098235);
         System.out.print(" = " + dub + "\n");
         if (Math.abs(dub - (-5.325098235)) > 0.001) {
-          failCount++;
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_BASETYPES;
+          System.out.println("*** FAILURE ***\n");
+        }
+
+        /**
+         * BINARY TEST
+         */
+        try {
+          System.out.print("testBinary(-128...127) = ");
+          byte[] data = new byte[] {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, -98, -97, -96, -95, -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, -68, -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127};
+          ByteBuffer bin = testClient.testBinary(ByteBuffer.wrap(data));
+          bin.mark();
+          byte[] bytes = new byte[bin.limit() - bin.position()];
+          bin.get(bytes);
+          bin.reset();
+          System.out.print("{");
+          boolean first = true;
+          for (int i = 0; i < bytes.length; ++i) {
+            if (first)
+              first = false;
+            else
+              System.out.print(", ");
+            System.out.print(bytes[i]);
+          }
+          System.out.println("}");
+          if (!ByteBuffer.wrap(data).equals(bin)) {
+            returnCode |= ERR_BASETYPES;
+            System.out.println("*** FAILURE ***\n");
+          }
+        } catch (Exception ex) {
+          returnCode |= ERR_BASETYPES;
+          System.out.println("\n*** FAILURE ***\n");
+          ex.printStackTrace(System.out);
         }
 
         /**
@@ -263,14 +331,14 @@
         out.i32_thing = -3;
         out.i64_thing = -5;
         Xtruct in = testClient.testStruct(out);
-        System.out.print(" = {" + "\"" + 
-                         in.string_thing + "\"," + 
-                         in.byte_thing + ", " + 
-                         in.i32_thing + ", " + 
+        System.out.print(" = {" + "\"" +
+                         in.string_thing + "\"," +
+                         in.byte_thing + ", " +
+                         in.i32_thing + ", " +
                          in.i64_thing + "}\n");
         if (!in.equals(out)) {
-          failCount++; 
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_STRUCTS;
+          System.out.println("*** FAILURE ***\n");
         }
 
         /**
@@ -283,15 +351,15 @@
         out2.i32_thing = 5;
         Xtruct2 in2 = testClient.testNest(out2);
         in = in2.struct_thing;
-        System.out.print(" = {" + in2.byte_thing + ", {" + "\"" + 
-                         in.string_thing + "\", " + 
+        System.out.print(" = {" + in2.byte_thing + ", {" + "\"" +
+                         in.string_thing + "\", " +
                          in.byte_thing + ", " +
                          in.i32_thing + ", " +
                          in.i64_thing + "}, " +
                          in2.i32_thing + "}\n");
         if (!in2.equals(out2)) {
-          failCount++;
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_STRUCTS;
+          System.out.println("*** FAILURE ***\n");
         }
 
         /**
@@ -325,14 +393,48 @@
         }
         System.out.print("}\n");
         if (!mapout.equals(mapin)) {
-          failCount++; 
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_CONTAINERS;
+          System.out.println("*** FAILURE ***\n");
         }
 
         /**
          * STRING MAP TEST
-         *  missing
          */
+        try {
+          Map<String, String> smapout = new HashMap<String, String>();
+          smapout.put("a", "2");
+          smapout.put("b", "blah");
+          smapout.put("some", "thing");
+          for (String key : smapout.keySet()) {
+            if (first) {
+              first = false;
+            } else {
+              System.out.print(", ");
+            }
+            System.out.print(key + " => " + smapout.get(key));
+          }
+          System.out.print("})");
+          Map<String, String> smapin = testClient.testStringMap(smapout);
+          System.out.print(" = {");
+          first = true;
+          for (String key : smapin.keySet()) {
+            if (first) {
+              first = false;
+            } else {
+              System.out.print(", ");
+            }
+            System.out.print(key + " => " + smapout.get(key));
+          }
+          System.out.print("}\n");
+          if (!smapout.equals(smapin)) {
+            returnCode |= ERR_CONTAINERS;
+            System.out.println("*** FAILURE ***\n");
+          }
+        } catch (Exception ex) {
+          returnCode |= ERR_CONTAINERS;
+          System.out.println("*** FAILURE ***\n");
+          ex.printStackTrace(System.out);
+        }
 
         /**
          * SET TEST
@@ -365,8 +467,8 @@
         }
         System.out.print("}\n");
         if (!setout.equals(setin)) {
-          failCount++; 
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_CONTAINERS;
+          System.out.println("*** FAILURE ***\n");
         }
 
         /**
@@ -400,8 +502,8 @@
         }
         System.out.print("}\n");
         if (!listout.equals(listin)) {
-          failCount++; 
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_CONTAINERS;
+          System.out.println("*** FAILURE ***\n");
         }
 
         /**
@@ -411,40 +513,40 @@
         Numberz ret = testClient.testEnum(Numberz.ONE);
         System.out.print(" = " + ret + "\n");
         if (ret != Numberz.ONE) {
-          failCount++;
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_STRUCTS;
+          System.out.println("*** FAILURE ***\n");
         }
 
         System.out.print("testEnum(TWO)");
         ret = testClient.testEnum(Numberz.TWO);
         System.out.print(" = " + ret + "\n");
         if (ret != Numberz.TWO) {
-          failCount++; 
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_STRUCTS;
+          System.out.println("*** FAILURE ***\n");
         }
 
         System.out.print("testEnum(THREE)");
         ret = testClient.testEnum(Numberz.THREE);
         System.out.print(" = " + ret + "\n");
         if (ret != Numberz.THREE) {
-          failCount++;
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_STRUCTS;
+          System.out.println("*** FAILURE ***\n");
         }
 
         System.out.print("testEnum(FIVE)");
         ret = testClient.testEnum(Numberz.FIVE);
         System.out.print(" = " + ret + "\n");
         if (ret != Numberz.FIVE) {
-          failCount++;
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_STRUCTS;
+          System.out.println("*** FAILURE ***\n");
         }
 
         System.out.print("testEnum(EIGHT)");
         ret = testClient.testEnum(Numberz.EIGHT);
         System.out.print(" = " + ret + "\n");
         if (ret != Numberz.EIGHT) {
-          failCount++;
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_STRUCTS;
+          System.out.println("*** FAILURE ***\n");
         }
 
         /**
@@ -454,8 +556,8 @@
         long uid = testClient.testTypedef(309858235082523L);
         System.out.print(" = " + uid + "\n");
         if (uid != 309858235082523L) {
-          failCount++;
-          System.out.println("FAILURE\n");
+          returnCode |= ERR_BASETYPES;
+          System.out.println("*** FAILURE ***\n");
         }
 
         /**
@@ -474,121 +576,174 @@
           System.out.print("}, ");
         }
         System.out.print("}\n");
+        if (mm.size() != 2 || !mm.containsKey(4) || !mm.containsKey(-4)) {
+          returnCode |= ERR_CONTAINERS;
+          System.out.println("*** FAILURE ***\n");
+        } else {
+          Map<Integer, Integer> m1 = mm.get(4);
+          Map<Integer, Integer> m2 = mm.get(-4);
+          if (m1.get(1) != 1 || m1.get(2) != 2 || m1.get(3) != 3 || m1.get(4) != 4 ||
+              m2.get(-1) != -1 || m2.get(-2) != -2 || m2.get(-3) != -3 || m2.get(-4) != -4) {
+            returnCode |= ERR_CONTAINERS;
+            System.out.println("*** FAILURE ***\n");
+          }
+        }
 
         /**
          * INSANITY TEST
          */
-        insane = new Insanity();
-        insane.userMap = new HashMap<Numberz, Long>();
-        insane.userMap.put(Numberz.FIVE, (long)5000);
-        Xtruct truck = new Xtruct();
-        truck.string_thing = "Truck";
-        truck.byte_thing = (byte)8;
-        truck.i32_thing = 8;
-        truck.i64_thing = 8;
-        insane.xtructs = new ArrayList<Xtruct>();
-        insane.xtructs.add(truck);
-        System.out.print("testInsanity()");
-        Map<Long,Map<Numberz,Insanity>> whoa =
-          testClient.testInsanity(insane);
-        System.out.print(" = {");
-        for (long key : whoa.keySet()) {
-          Map<Numberz,Insanity> val = whoa.get(key);
-          System.out.print(key + " => {");
 
-          for (Numberz k2 : val.keySet()) {
-            Insanity v2 = val.get(k2);
-            System.out.print(k2 + " => {");
-            Map<Numberz, Long> userMap = v2.userMap;
-            System.out.print("{");
-            if (userMap != null) {
-              for (Numberz k3 : userMap.keySet()) {
-                System.out.print(k3 + " => " + userMap.get(k3) + ", ");
+        boolean insanityFailed = true;
+        try {
+          Xtruct hello = new Xtruct();
+          hello.string_thing = "Hello2";
+          hello.byte_thing = 2;
+          hello.i32_thing = 2;
+          hello.i64_thing = 2;
+
+          Xtruct goodbye = new Xtruct();
+          goodbye.string_thing = "Goodbye4";
+          goodbye.byte_thing = (byte)4;
+          goodbye.i32_thing = 4;
+          goodbye.i64_thing = (long)4;
+
+          insane.userMap = new HashMap<Numberz, Long>();
+          insane.userMap.put(Numberz.EIGHT, (long)8);
+          insane.userMap.put(Numberz.FIVE, (long)5);
+          insane.xtructs = new ArrayList<Xtruct>();
+          insane.xtructs.add(goodbye);
+          insane.xtructs.add(hello);
+
+          System.out.print("testInsanity()");
+          Map<Long,Map<Numberz,Insanity>> whoa =
+            testClient.testInsanity(insane);
+          System.out.print(" = {");
+          for (long key : whoa.keySet()) {
+            Map<Numberz,Insanity> val = whoa.get(key);
+            System.out.print(key + " => {");
+
+            for (Numberz k2 : val.keySet()) {
+              Insanity v2 = val.get(k2);
+              System.out.print(k2 + " => {");
+              Map<Numberz, Long> userMap = v2.userMap;
+              System.out.print("{");
+              if (userMap != null) {
+                for (Numberz k3 : userMap.keySet()) {
+                  System.out.print(k3 + " => " + userMap.get(k3) + ", ");
+                }
               }
-            }
-            System.out.print("}, ");
+              System.out.print("}, ");
 
-            List<Xtruct> xtructs = v2.xtructs;
-            System.out.print("{");
-            if (xtructs != null) {
-              for (Xtruct x : xtructs) {
-                System.out.print("{" + "\"" + x.string_thing + "\", " + x.byte_thing + ", " + x.i32_thing + ", "+ x.i64_thing + "}, ");
+              List<Xtruct> xtructs = v2.xtructs;
+              System.out.print("{");
+              if (xtructs != null) {
+                for (Xtruct x : xtructs) {
+                  System.out.print("{" + "\"" + x.string_thing + "\", " + x.byte_thing + ", " + x.i32_thing + ", "+ x.i64_thing + "}, ");
+                }
               }
-            }
-            System.out.print("}");
+              System.out.print("}");
 
+              System.out.print("}, ");
+            }
             System.out.print("}, ");
           }
-          System.out.print("}, ");
+          System.out.print("}\n");
+          if (whoa.size() == 2 && whoa.containsKey(1L) && whoa.containsKey(2L)) {
+            Map<Numberz, Insanity> first_map = whoa.get(1L);
+            Map<Numberz, Insanity> second_map = whoa.get(2L);
+            if (first_map.size() == 2 &&
+                first_map.containsKey(Numberz.TWO) &&
+                first_map.containsKey(Numberz.THREE) &&
+                second_map.size() == 1 &&
+                second_map.containsKey(Numberz.SIX) &&
+                insane.equals(first_map.get(Numberz.TWO)) &&
+                insane.equals(first_map.get(Numberz.THREE))) {
+              Insanity six =second_map.get(Numberz.SIX);
+              // Cannot use "new Insanity().equals(six)" because as of now, struct/container
+              // fields with default requiredness have isset=false for local instances and yet
+              // received empty values from other languages like C++ have isset=true .
+              if (six.getUserMapSize() == 0 && six.getXtructsSize() == 0) {
+                // OK
+                insanityFailed = false;
+              }
+            }
+          }
+        } catch (Exception ex) {
+          returnCode |= ERR_STRUCTS;
+          System.out.println("*** FAILURE ***\n");
+          ex.printStackTrace(System.out);
+          insanityFailed = false;
         }
-        System.out.print("}\n");
+        if (insanityFailed) {
+          returnCode |= ERR_STRUCTS;
+          System.out.println("*** FAILURE ***\n");
+        }
 
-        
         /**
          * EXECPTION TEST
          */
         try {
           System.out.print("testClient.testException(\"Xception\") =>");
           testClient.testException("Xception");
-          System.out.print("  void\nFAILURE\n");
-          failCount++;
+          System.out.print("  void\n*** FAILURE ***\n");
+          returnCode |= ERR_EXCEPTIONS;
         } catch(Xception e) {
           System.out.printf("  {%d, \"%s\"}\n", e.errorCode, e.message);
         }
-        
+
         try {
           System.out.print("testClient.testException(\"TException\") =>");
           testClient.testException("TException");
-          System.out.print("  void\nFAILURE\n");
-          failCount++;
+          System.out.print("  void\n*** FAILURE ***\n");
+          returnCode |= ERR_EXCEPTIONS;
         } catch(TException e) {
           System.out.printf("  {\"%s\"}\n", e.getMessage());
         }
-        
+
         try {
           System.out.print("testClient.testException(\"success\") =>");
           testClient.testException("success");
           System.out.print("  void\n");
         }catch(Exception e) {
-          System.out.printf("  exception\nFAILURE\n");
-          failCount++;
+          System.out.printf("  exception\n*** FAILURE ***\n");
+          returnCode |= ERR_EXCEPTIONS;
         }
-        
-        
+
+
         /**
          * MULTI EXCEPTION TEST
          */
-        
+
         try {
           System.out.printf("testClient.testMultiException(\"Xception\", \"test 1\") =>");
           testClient.testMultiException("Xception", "test 1");
-          System.out.print("  result\nFAILURE\n");
-          failCount++;
+          System.out.print("  result\n*** FAILURE ***\n");
+          returnCode |= ERR_EXCEPTIONS;
         } catch(Xception e) {
           System.out.printf("  {%d, \"%s\"}\n", e.errorCode, e.message);
         }
-        
+
         try {
           System.out.printf("testClient.testMultiException(\"Xception2\", \"test 2\") =>");
           testClient.testMultiException("Xception2", "test 2");
-          System.out.print("  result\nFAILURE\n");
-          failCount++;
+          System.out.print("  result\n*** FAILURE ***\n");
+          returnCode |= ERR_EXCEPTIONS;
         } catch(Xception2 e) {
           System.out.printf("  {%d, {\"%s\"}}\n", e.errorCode, e.struct_thing.string_thing);
         }
-        
+
         try {
           System.out.print("testClient.testMultiException(\"success\", \"test 3\") =>");
           Xtruct result;
           result = testClient.testMultiException("success", "test 3");
           System.out.printf("  {{\"%s\"}}\n", result.string_thing);
         } catch(Exception e) {
-          System.out.printf("  exception\nFAILURE\n");
-          failCount++;
+          System.out.printf("  exception\n*** FAILURE ***\n");
+          returnCode |= ERR_EXCEPTIONS;
         }
 
 
-        
+
         /**
          * ONEWAY TEST
          */
@@ -598,9 +753,10 @@
         long onewayElapsedMillis = (System.nanoTime() - startOneway) / 1000000;
         if (onewayElapsedMillis > 200) {
           System.out.println("Oneway test failed: took " +
-                              Long.toString(onewayElapsedMillis) +
-                              "ms");
-          failCount++;
+                             Long.toString(onewayElapsedMillis) +
+                             "ms");
+          System.out.printf("*** FAILURE ***\n");
+          returnCode |= ERR_BASETYPES;
         } else {
           System.out.println("Success - took " +
                              Long.toString(onewayElapsedMillis) +
@@ -623,8 +779,9 @@
 
         transport.close();
       } catch (Exception x) {
+        System.out.printf("*** FAILURE ***\n");
         x.printStackTrace();
-        failCount++;
+        returnCode |= ERR_UNKNOWN;
       }
     }
 
@@ -636,13 +793,14 @@
 
     try {
       String json = (new TSerializer(new TSimpleJSONProtocol.Factory())).toString(insane);
-      System.out.println("\nFor good meausre here is some JSON:\n" + json);
+      System.out.println("\nSample TSimpleJSONProtocol output:\n" + json);
     } catch (TException x) {
+      System.out.println("*** FAILURE ***");
       x.printStackTrace();
-      System.exit(1);
+      returnCode |= ERR_BASETYPES;
     }
 
 
-    System.exit(failCount);
+    System.exit(returnCode);
   }
 }
diff --git a/lib/java/test/org/apache/thrift/test/TestNonblockingServer.java b/lib/java/test/org/apache/thrift/test/TestNonblockingServer.java
index 18343b0..41c4b65 100644
--- a/lib/java/test/org/apache/thrift/test/TestNonblockingServer.java
+++ b/lib/java/test/org/apache/thrift/test/TestNonblockingServer.java
@@ -52,7 +52,7 @@
 
       // Transport
       TNonblockingServerSocket tServerSocket =
-        new TNonblockingServerSocket(port);
+        new TNonblockingServerSocket(new TNonblockingServerSocket.NonblockingAbstractServerSocketArgs().port(port));
 
       TServer serverEngine;
 
diff --git a/lib/java/test/org/apache/thrift/test/TestServer.java b/lib/java/test/org/apache/thrift/test/TestServer.java
index 125a773..1f3e555 100644
--- a/lib/java/test/org/apache/thrift/test/TestServer.java
+++ b/lib/java/test/org/apache/thrift/test/TestServer.java
@@ -30,6 +30,7 @@
 import org.apache.thrift.protocol.TJSONProtocol;
 import org.apache.thrift.protocol.TProtocol;
 import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.protocol.TMultiplexedProtocol;
 import org.apache.thrift.server.ServerContext;
 import org.apache.thrift.server.TServer;
 import org.apache.thrift.server.TServer.Args;
@@ -46,10 +47,11 @@
 import org.apache.thrift.transport.TTransport;
 import org.apache.thrift.transport.TTransportFactory;
 import org.apache.thrift.transport.TNonblockingServerSocket;
-
+import org.apache.thrift.TMultiplexedProcessor;
 
 import thrift.test.Insanity;
 import thrift.test.Numberz;
+import thrift.test.SecondService;
 import thrift.test.ThriftTest;
 import thrift.test.Xception;
 import thrift.test.Xception2;
@@ -58,6 +60,24 @@
 
 public class TestServer {
 
+  // Multiplexed Protocol Support Details:
+  //
+  // For multiplexed testing we always use binary protocol underneath.
+  //
+  // "ThriftTest" named service implements "ThriftTest" from ThriftTest.thrift
+  // "SecondService" named service implements "SecondService" from ThriftTest.thrift
+  // In addition, to support older non-multiplexed clients using the same concrete protocol
+  // the multiplexed processor is taught to use "ThriftTest" if the incoming request has no
+  // multiplexed call name decoration.
+
+  static class SecondHandler implements thrift.test.SecondService.Iface {
+
+    @Override
+    public java.lang.String secondtestString(java.lang.String thing) throws org.apache.thrift.TException
+    { return "testString(\"" + thing + "\")"; }
+
+  }
+
   static class TestServerContext implements ServerContext {
 
         int connectionId;
@@ -111,6 +131,8 @@
       String protocol_type = "binary";
       String server_type = "thread-pool";
       String domain_socket = "";
+      int string_limit = -1;
+      int container_limit = -1;
       try {
         for (int i = 0; i < args.length; i++) {
           if (args[i].startsWith("--port")) {
@@ -124,18 +146,24 @@
             protocol_type = args[i].split("=")[1];
             protocol_type.trim();
           } else if (args[i].startsWith("--transport")) {
-            transport_type = args[i].split("=")[1];  
+            transport_type = args[i].split("=")[1];
             transport_type.trim();
           } else if (args[i].equals("--ssl")) {
             ssl = true;
+          } else if (args[i].startsWith("--string-limit")) {
+            string_limit = Integer.valueOf(args[i].split("=")[1]);
+          } else if (args[i].startsWith("--container-limit")) {
+            container_limit = Integer.valueOf(args[i].split("=")[1]);
           } else if (args[i].equals("--help")) {
-            System.out.println("Allowed options:"); 
+            System.out.println("Allowed options:");
             System.out.println("  --help\t\t\tProduce help message");
             System.out.println("  --port=arg (=" + port + ")\tPort number to connect");
             System.out.println("  --transport=arg (=" + transport_type + ")\n\t\t\t\tTransport: buffered, framed, fastframed");
-            System.out.println("  --protocol=arg (=" + protocol_type + ")\tProtocol: binary, json, compact");
+            System.out.println("  --protocol=arg (=" + protocol_type + ")\tProtocol: binary, compact, json, multi, multic, multij");
             System.out.println("  --ssl\t\t\tEncrypted Transport using SSL");
             System.out.println("  --server-type=arg (=" + server_type +")\n\t\t\t\tType of server: simple, thread-pool, nonblocking, threaded-selector");
+            System.out.println("  --string-limit=arg (=" + string_limit + ")\tString read length limit");
+            System.out.println("  --container-limit=arg (=" + container_limit + ")\tContainer read length limit");
             System.exit(0);
           }
         }
@@ -143,7 +171,7 @@
         System.err.println("Can not parse arguments! See --help");
         System.exit(1);
       }
-      
+
       try {
         if (server_type.equals("simple")) {
         } else if (server_type.equals("thread-pool")) {
@@ -156,13 +184,16 @@
             throw new Exception("SSL is not supported over nonblocking servers!");
           }
         } else {
-          throw new Exception("Unknown server type! " + server_type); 
+          throw new Exception("Unknown server type! " + server_type);
         }
         if (protocol_type.equals("binary")) {
-        } else if (protocol_type.equals("json")) {
         } else if (protocol_type.equals("compact")) {
+        } else if (protocol_type.equals("json")) {
+        } else if (protocol_type.equals("multi")) {
+        } else if (protocol_type.equals("multic")) {
+        } else if (protocol_type.equals("multij")) {
         } else {
-          throw new Exception("Unknown protocol type! " + protocol_type); 
+          throw new Exception("Unknown protocol type! " + protocol_type);
         }
         if (transport_type.equals("buffered")) {
         } else if (transport_type.equals("framed")) {
@@ -171,24 +202,25 @@
           throw new Exception("Unknown transport type! " + transport_type);
         }
       } catch (Exception e) {
-        System.err.println("Error: " + e.getMessage()); 
+        System.err.println("Error: " + e.getMessage());
         System.exit(1);
       }
 
-      // Processor
-      TestHandler testHandler =
-        new TestHandler();
-      ThriftTest.Processor testProcessor =
-        new ThriftTest.Processor(testHandler);
+      // Processors
+      TestHandler testHandler = new TestHandler();
+      ThriftTest.Processor testProcessor = new ThriftTest.Processor(testHandler);
+
+      SecondHandler secondHandler = new SecondHandler();
+      SecondService.Processor secondProcessor = new SecondService.Processor(secondHandler);
 
       // Protocol factory
       TProtocolFactory tProtocolFactory = null;
-      if (protocol_type.equals("json")) {
+      if (protocol_type.equals("json") || protocol_type.equals("multij")) {
         tProtocolFactory = new TJSONProtocol.Factory();
-      } else if (protocol_type.equals("compact")) {
-        tProtocolFactory = new TCompactProtocol.Factory();
-      } else {
-        tProtocolFactory = new TBinaryProtocol.Factory();
+      } else if (protocol_type.equals("compact") || protocol_type.equals("multic")) {
+        tProtocolFactory = new TCompactProtocol.Factory(string_limit, container_limit);
+      } else { // also covers multi
+        tProtocolFactory = new TBinaryProtocol.Factory(string_limit, container_limit);
       }
 
       TTransportFactory tTransportFactory = null;
@@ -203,30 +235,33 @@
 
       TServer serverEngine = null;
 
+      // If we are multiplexing services in one server...
+      TMultiplexedProcessor multiplexedProcessor = new TMultiplexedProcessor();
+      multiplexedProcessor.registerDefault  (testProcessor);
+      multiplexedProcessor.registerProcessor("ThriftTest", testProcessor);
+      multiplexedProcessor.registerProcessor("SecondService", secondProcessor);
 
-      if (server_type.equals("nonblocking") || 
+      if (server_type.equals("nonblocking") ||
           server_type.equals("threaded-selector")) {
         // Nonblocking servers
         TNonblockingServerSocket tNonblockingServerSocket =
-          new TNonblockingServerSocket(port);
-          
-        if (server_type.equals("nonblocking")) {
+          new TNonblockingServerSocket(new TNonblockingServerSocket.NonblockingAbstractServerSocketArgs().port(port));
+
+        if (server_type.contains("nonblocking")) {
           // Nonblocking Server
-          TNonblockingServer.Args tNonblockingServerArgs 
+          TNonblockingServer.Args tNonblockingServerArgs
               = new TNonblockingServer.Args(tNonblockingServerSocket);
-          tNonblockingServerArgs.processor(testProcessor);
+          tNonblockingServerArgs.processor(protocol_type.startsWith("multi") ? multiplexedProcessor : testProcessor);
           tNonblockingServerArgs.protocolFactory(tProtocolFactory);
           tNonblockingServerArgs.transportFactory(tTransportFactory);
-
           serverEngine = new TNonblockingServer(tNonblockingServerArgs);
         } else { // server_type.equals("threaded-selector")
           // ThreadedSelector Server
-          TThreadedSelectorServer.Args tThreadedSelectorServerArgs 
+          TThreadedSelectorServer.Args tThreadedSelectorServerArgs
               = new TThreadedSelectorServer.Args(tNonblockingServerSocket);
-          tThreadedSelectorServerArgs.processor(testProcessor);
+          tThreadedSelectorServerArgs.processor(protocol_type.startsWith("multi") ? multiplexedProcessor : testProcessor);
           tThreadedSelectorServerArgs.protocolFactory(tProtocolFactory);
           tThreadedSelectorServerArgs.transportFactory(tTransportFactory);
-    
           serverEngine = new TThreadedSelectorServer(tThreadedSelectorServerArgs);
         }
       } else {
@@ -237,35 +272,34 @@
         if (ssl) {
           tServerSocket = TSSLTransportFactory.getServerSocket(port, 0);
         } else {
-          tServerSocket = new TServerSocket(port);
+          tServerSocket = new TServerSocket(new TServerSocket.ServerSocketTransportArgs().port(port));
         }
 
         if (server_type.equals("simple")) {
           // Simple Server
           TServer.Args tServerArgs = new TServer.Args(tServerSocket);
-          tServerArgs.processor(testProcessor);
+          tServerArgs.processor(protocol_type.startsWith("multi") ? multiplexedProcessor : testProcessor);
           tServerArgs.protocolFactory(tProtocolFactory);
           tServerArgs.transportFactory(tTransportFactory);
-
           serverEngine = new TSimpleServer(tServerArgs);
         } else { // server_type.equals("threadpool")
           // ThreadPool Server
-          TThreadPoolServer.Args tThreadPoolServerArgs 
+          TThreadPoolServer.Args tThreadPoolServerArgs
               = new TThreadPoolServer.Args(tServerSocket);
-          tThreadPoolServerArgs.processor(testProcessor);
+          tThreadPoolServerArgs.processor(protocol_type.startsWith("multi") ? multiplexedProcessor : testProcessor);
           tThreadPoolServerArgs.protocolFactory(tProtocolFactory);
           tThreadPoolServerArgs.transportFactory(tTransportFactory);
-
           serverEngine = new TThreadPoolServer(tThreadPoolServerArgs);
         }
       }
 
-
-      //Set server event handler
+      // Set server event handler
       serverEngine.setServerEventHandler(new TestServerEventHandler());
 
       // Run it
-      System.out.println("Starting the server on port " + port + "...");
+      System.out.println("Starting the " + (ssl ? "ssl server" : "server") +
+        " [" + protocol_type + "/" + transport_type + "/" + server_type + "] on " +
+        ((domain_socket == "") ? ("port " + port) : ("unix socket " + domain_socket)));
       serverEngine.serve();
 
     } catch (Exception x) {
diff --git a/lib/java/test/org/apache/thrift/transport/ReadCountingTransport.java b/lib/java/test/org/apache/thrift/transport/ReadCountingTransport.java
index 8474188..3c749f9 100644
--- a/lib/java/test/org/apache/thrift/transport/ReadCountingTransport.java
+++ b/lib/java/test/org/apache/thrift/transport/ReadCountingTransport.java
@@ -22,26 +22,40 @@
 public class ReadCountingTransport extends TTransport {
   public int readCount = 0;
   private TTransport trans;
+  private boolean open = true;
 
   public ReadCountingTransport(TTransport underlying) {
     trans = underlying;
   }
 
   @Override
-  public void close() {}
+  public void close() {
+    open = false;
+  }
 
   @Override
-  public boolean isOpen() {return true;}
+  public boolean isOpen() {
+    return open;
+  }
 
   @Override
-  public void open() throws TTransportException {}
+  public void open() throws TTransportException {
+    open = true;
+  }
 
   @Override
   public int read(byte[] buf, int off, int len) throws TTransportException {
+    if (!isOpen()) {
+      throw new TTransportException(TTransportException.NOT_OPEN, "Transport is closed");
+    }
     readCount++;
     return trans.read(buf, off, len);
   }
 
   @Override
-  public void write(byte[] buf, int off, int len) throws TTransportException {}
-}
\ No newline at end of file
+  public void write(byte[] buf, int off, int len) throws TTransportException {
+    if (!isOpen()) {
+      throw new TTransportException(TTransportException.NOT_OPEN, "Transport is closed");
+    }
+  }
+}
diff --git a/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBuffer.java b/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBuffer.java
index 337dcf8..c353489 100644
--- a/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBuffer.java
+++ b/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBuffer.java
@@ -23,7 +23,7 @@
 public class TestAutoExpandingBuffer extends TestCase {
   public void testExpands() throws Exception {
     // has expected initial capacity
-    AutoExpandingBuffer b = new AutoExpandingBuffer(10, 1.5);
+    AutoExpandingBuffer b = new AutoExpandingBuffer(10);
     assertEquals(10, b.array().length);
 
     // doesn't shrink
diff --git a/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferReadTransport.java b/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferReadTransport.java
index 2e1f947..83ebc2d 100644
--- a/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferReadTransport.java
+++ b/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferReadTransport.java
@@ -32,7 +32,7 @@
   }
 
   public void testIt() throws Exception {
-    AutoExpandingBufferReadTransport t = new AutoExpandingBufferReadTransport(150, 1.5);
+    AutoExpandingBufferReadTransport t = new AutoExpandingBufferReadTransport(150);
 
     TMemoryInputTransport membuf = new TMemoryInputTransport(HUNDRED_BYTES);
 
diff --git a/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferWriteTransport.java b/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferWriteTransport.java
index d5f239d..86b5b0d 100644
--- a/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferWriteTransport.java
+++ b/lib/java/test/org/apache/thrift/transport/TestAutoExpandingBufferWriteTransport.java
@@ -19,26 +19,51 @@
 package org.apache.thrift.transport;
 
 import java.nio.ByteBuffer;
+import org.junit.Test;
+import static org.junit.Assert.*;
 
-import junit.framework.TestCase;
+public class TestAutoExpandingBufferWriteTransport {
 
-public class TestAutoExpandingBufferWriteTransport extends TestCase {
-
+  @Test
   public void testIt() throws Exception {
-    AutoExpandingBufferWriteTransport t = new AutoExpandingBufferWriteTransport(1, 1.5);
+    AutoExpandingBufferWriteTransport t = new AutoExpandingBufferWriteTransport(1, 0);
+    assertEquals(0, t.getLength());
     assertEquals(1, t.getBuf().array().length);
     byte[] b1 = new byte[]{1,2,3};
     t.write(b1);
-    assertEquals(3, t.getPos());
+    assertEquals(3, t.getLength());
     assertTrue(t.getBuf().array().length >= 3);
     assertEquals(ByteBuffer.wrap(b1), ByteBuffer.wrap(t.getBuf().array(), 0, 3));
 
     t.reset();
+    assertEquals(0, t.getLength());
     assertTrue(t.getBuf().array().length >= 3);
-    assertEquals(0, t.getPos());
     byte[] b2 = new byte[]{4,5};
     t.write(b2);
-    assertEquals(2, t.getPos());
+    assertEquals(2, t.getLength());
     assertEquals(ByteBuffer.wrap(b2), ByteBuffer.wrap(t.getBuf().array(), 0, 2));
+
+    AutoExpandingBufferWriteTransport uut = new AutoExpandingBufferWriteTransport(8, 4);
+    assertEquals(4, uut.getLength());
+    assertEquals(8, uut.getBuf().array().length);
+    uut.write(b1);
+    assertEquals(7, uut.getLength());
+    assertEquals(8, uut.getBuf().array().length);
+    assertEquals(ByteBuffer.wrap(b1), ByteBuffer.wrap(uut.getBuf().array(), 4, 3));
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testBadInitialSize() throws IllegalArgumentException {
+    new AutoExpandingBufferWriteTransport(0, 0);
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testBadFrontReserveSize() throws IllegalArgumentException {
+    new AutoExpandingBufferWriteTransport(4, -1);
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testTooSmallFrontReserveSize() throws IllegalArgumentException {
+    new AutoExpandingBufferWriteTransport(4, 5);
   }
 }
diff --git a/lib/java/test/org/apache/thrift/transport/TestTByteBuffer.java b/lib/java/test/org/apache/thrift/transport/TestTByteBuffer.java
new file mode 100644
index 0000000..a73075b
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/transport/TestTByteBuffer.java
@@ -0,0 +1,36 @@
+package org.apache.thrift.transport;
+
+import junit.framework.TestCase;
+import org.apache.commons.codec.Charsets;
+import org.apache.thrift.TException;
+
+import java.nio.ByteBuffer;
+
+public class TestTByteBuffer extends TestCase {
+  public void testReadWrite() throws Exception {
+    final TByteBuffer byteBuffer = new TByteBuffer(ByteBuffer.allocate(16));
+    byteBuffer.write("Hello World".getBytes(Charsets.UTF_8));
+    assertEquals("Hello World", new String(byteBuffer.flip().toByteArray(), Charsets.UTF_8));
+  }
+
+  public void testReuseReadWrite() throws Exception {
+    final TByteBuffer byteBuffer = new TByteBuffer(ByteBuffer.allocate(16));
+    byteBuffer.write("Hello World".getBytes(Charsets.UTF_8));
+    assertEquals("Hello World", new String(byteBuffer.flip().toByteArray(), Charsets.UTF_8));
+
+    byteBuffer.clear();
+
+    byteBuffer.write("Goodbye Horses".getBytes(Charsets.UTF_8));
+    assertEquals("Goodbye Horses", new String(byteBuffer.flip().toByteArray(), Charsets.UTF_8));
+  }
+
+  public void testOverflow() throws Exception {
+    final TByteBuffer byteBuffer = new TByteBuffer(ByteBuffer.allocate(4));
+    try {
+      byteBuffer.write("Hello World".getBytes(Charsets.UTF_8));
+      fail("Expected write operation to fail with TTransportException");
+    } catch (TTransportException e) {
+      assertEquals("Not enough room in output buffer", e.getMessage());
+    }
+  }
+}
diff --git a/lib/java/test/org/apache/thrift/transport/TestTFastFramedTransport.java b/lib/java/test/org/apache/thrift/transport/TestTFastFramedTransport.java
index e024049..06ee206 100644
--- a/lib/java/test/org/apache/thrift/transport/TestTFastFramedTransport.java
+++ b/lib/java/test/org/apache/thrift/transport/TestTFastFramedTransport.java
@@ -19,8 +19,15 @@
 package org.apache.thrift.transport;
 
 public class TestTFastFramedTransport extends TestTFramedTransport {
+  protected final static int INITIAL_CAPACITY = 50;
+
   @Override
   protected TTransport getTransport(TTransport underlying) {
-    return new TFastFramedTransport(underlying, 50, 10 * 1024 * 1024);
+    return new TFastFramedTransport(underlying, INITIAL_CAPACITY, 10 * 1024 * 1024);
+  }
+
+  @Override
+  protected TTransport getTransport(TTransport underlying, int maxLength) {
+    return new TFastFramedTransport(underlying, INITIAL_CAPACITY, maxLength);
   }
 }
diff --git a/lib/java/test/org/apache/thrift/transport/TestTFramedTransport.java b/lib/java/test/org/apache/thrift/transport/TestTFramedTransport.java
index 78f58ec..e30d74b 100644
--- a/lib/java/test/org/apache/thrift/transport/TestTFramedTransport.java
+++ b/lib/java/test/org/apache/thrift/transport/TestTFramedTransport.java
@@ -34,6 +34,10 @@
     return new TFramedTransport(underlying);
   }
 
+  protected TTransport getTransport(TTransport underlying, int maxLength) {
+    return new TFramedTransport(underlying, maxLength);
+  }
+
   public static byte[] byteSequence(int start, int end) {
     byte[] result = new byte[end-start+1];
     for (int i = 0; i <= (end-start); i++) {
@@ -75,6 +79,40 @@
     assertEquals(4, countTrans.readCount);
   }
 
+  public void testInvalidFrameSize() throws IOException, TTransportException {
+    int maxLength = 128;
+
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    DataOutputStream dos = new DataOutputStream(baos);
+    dos.writeInt(130);
+    dos.write(byteSequence(0, 129));
+
+    TMemoryBuffer membuf = new TMemoryBuffer(0);
+    membuf.write(baos.toByteArray());
+
+    ReadCountingTransport countTrans = new ReadCountingTransport(membuf);
+    TTransport trans = getTransport(countTrans, maxLength);
+
+    byte[] readBuf = new byte[10];
+    try {
+      trans.read(readBuf, 0, 4);
+      fail("Expected a TTransportException");
+    } catch (TTransportException e) {
+      // We expect this exception because the frame we're trying to read is larger than our max frame length
+      assertEquals(TTransportException.CORRUPTED_DATA, e.getType());
+    }
+
+    assertFalse(trans.isOpen());
+
+    try {
+      trans.read(readBuf, 0, 4);
+      fail("Expected a TTransportException");
+    } catch (TTransportException e) {
+      // This time we get an exception indicating the connection was closed
+      assertEquals(TTransportException.NOT_OPEN, e.getType());
+    }
+  }
+
   public void testWrite() throws TTransportException, IOException {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     WriteCountingTransport countingTrans = new WriteCountingTransport(new TIOStreamTransport(new BufferedOutputStream(baos)));
@@ -87,11 +125,11 @@
     assertEquals(0, countingTrans.writeCount);
 
     trans.flush();
-    assertEquals(2, countingTrans.writeCount);
+    assertEquals(1, countingTrans.writeCount);
 
     trans.write(byteSequence(0, 245));
     trans.flush();
-    assertEquals(4, countingTrans.writeCount);
+    assertEquals(2, countingTrans.writeCount);
 
     DataInputStream din = new DataInputStream(new ByteArrayInputStream(baos.toByteArray()));
     assertEquals(256, din.readInt());
@@ -145,4 +183,32 @@
     assertEquals(65, trans.getBytesRemainingInBuffer());
     assertEquals(10, trans.getBufferPosition());
   }
+
+  public void testClear() throws IOException, TTransportException {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    DataOutputStream dos = new DataOutputStream(baos);
+    dos.writeInt(220);
+    dos.write(byteSequence(0, 219));
+
+    TMemoryBuffer membuf = new TMemoryBuffer(0);
+    membuf.write(baos.toByteArray());
+
+    ReadCountingTransport countTrans = new ReadCountingTransport(membuf);
+    TTransport trans = getTransport(countTrans);
+
+    byte[] readBuf = new byte[220];
+    trans.read(readBuf, 0, 220);
+    assertTrue(Arrays.equals(readBuf, byteSequence(0,219)));
+
+    assertTrue(trans instanceof TFramedTransport || trans instanceof TFastFramedTransport);
+    if (trans instanceof TFramedTransport) {
+      assertTrue(trans.getBuffer() != null && trans.getBuffer().length > 0);
+      ((TFramedTransport) trans).clear();
+      assertTrue(trans.getBuffer() == null);
+    } else if (trans instanceof TFastFramedTransport) {
+      assertTrue(trans.getBuffer().length > TestTFastFramedTransport.INITIAL_CAPACITY);
+      ((TFastFramedTransport) trans).clear();
+      assertTrue(trans.getBuffer().length == TestTFastFramedTransport.INITIAL_CAPACITY);
+    }
+  }
 }
diff --git a/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactory.java b/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactory.java
index 478407a..032c2eb 100644
--- a/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactory.java
+++ b/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactory.java
@@ -45,6 +45,10 @@
   throws Exception {
     return TSSLTransportFactory.getClientSocket(HOST, PORT);
   }
+  
+  protected TServerSocket getServerTransport() throws Exception {
+    return TSSLTransportFactory.getServerSocket(PORT);
+  }
 
   @Override
   public void startServer(final TProcessor processor, final TProtocolFactory protoFactory, final TTransportFactory factory)
@@ -52,11 +56,11 @@
     serverThread = new Thread() {
       public void run() {
         try {
-          TServerTransport serverTransport = TSSLTransportFactory.getServerSocket(PORT);
+          TServerTransport serverTransport = getServerTransport();
           final Args args = new Args(serverTransport).processor(processor);
           server = new TSimpleServer(args);
           server.serve();
-        } catch (TTransportException e) {
+        } catch (Exception e) {
           e.printStackTrace();
           assert false;
         }
@@ -64,7 +68,7 @@
     };
 
     serverThread.start();
-    Thread.sleep(1000);
+    Thread.sleep(SLEEP_DELAY);
   }
 
   @Override
diff --git a/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient1.java b/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient1.java
new file mode 100644
index 0000000..da1659f
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient1.java
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+public class TestTSSLTransportFactoryCustomClient1 extends TestTSSLTransportFactory {
+
+  @Override
+  public TTransport getClientTransport(TTransport underlyingTransport)
+  throws Exception {
+    TSSLTransportFactory.TSSLTransportParameters params = new
+      TSSLTransportFactory.TSSLTransportParameters();
+
+    params.setTrustStore(System.getProperty("javax.net.ssl.trustStore"),
+      System.getProperty("javax.net.ssl.trustStorePassword"));
+
+    return TSSLTransportFactory.getClientSocket(HOST, PORT, 0/*timeout*/, params);
+  }
+}
diff --git a/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient2.java b/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient2.java
new file mode 100644
index 0000000..eaed460
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryCustomClient2.java
@@ -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 org.apache.thrift.transport;
+
+public class TestTSSLTransportFactoryCustomClient2 extends TestTSSLTransportFactory {
+
+  @Override
+  public TTransport getClientTransport(TTransport underlyingTransport)
+  throws Exception {
+    TSSLTransportFactory.TSSLTransportParameters params = new
+      TSSLTransportFactory.TSSLTransportParameters();
+
+    params.setTrustStore(System.getProperty("javax.net.ssl.trustStore"), null);
+
+    return TSSLTransportFactory.getClientSocket(HOST, PORT, 0/*timeout*/, params);
+  }
+}
diff --git a/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryStreamedStore.java b/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryStreamedStore.java
new file mode 100644
index 0000000..25bf5ce
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/transport/TestTSSLTransportFactoryStreamedStore.java
@@ -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 org.apache.thrift.transport;
+
+import java.io.FileInputStream;
+import java.net.InetAddress;
+
+public class TestTSSLTransportFactoryStreamedStore extends TestTSSLTransportFactory {
+  private static String keyStoreLocation = System.getProperty("javax.net.ssl.keyStore");
+  private static String trustStoreLocation = System.getProperty("javax.net.ssl.trustStore");
+  
+  public TestTSSLTransportFactoryStreamedStore() {
+    super();
+    
+    /**
+     *  Override system properties to be able to test passing
+     *  the trustStore and keyStore as input stream
+     */
+    System.setProperty("javax.net.ssl.trustStore", "");
+    System.setProperty("javax.net.ssl.keyStore", "");
+  }
+
+  @Override
+  public TTransport getClientTransport(TTransport underlyingTransport)
+  throws Exception {
+    TSSLTransportFactory.TSSLTransportParameters params = new
+      TSSLTransportFactory.TSSLTransportParameters();
+
+    params.setTrustStore(new FileInputStream(trustStoreLocation),
+                         System.getProperty("javax.net.ssl.trustStorePassword"));
+    
+    return TSSLTransportFactory.getClientSocket(HOST, PORT, 0/*timeout*/, params);
+  }
+
+  @Override
+  protected TServerSocket getServerTransport() throws Exception {
+    TSSLTransportFactory.TSSLTransportParameters params = new
+        TSSLTransportFactory.TSSLTransportParameters();
+    
+    params.setKeyStore(new FileInputStream(keyStoreLocation), 
+                       System.getProperty("javax.net.ssl.keyStorePassword"));
+    
+    return TSSLTransportFactory.getServerSocket(PORT, 0/*timeout*/, InetAddress.getByName(HOST), params);
+  }
+}
\ No newline at end of file
diff --git a/lib/java/test/org/apache/thrift/transport/TestTSaslTransports.java b/lib/java/test/org/apache/thrift/transport/TestTSaslTransports.java
index 41d08f6..36a06e9 100644
--- a/lib/java/test/org/apache/thrift/transport/TestTSaslTransports.java
+++ b/lib/java/test/org/apache/thrift/transport/TestTSaslTransports.java
@@ -20,6 +20,7 @@
 package org.apache.thrift.transport;
 
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -73,7 +74,7 @@
       + "score and seven years ago our fathers brought forth on this "
       + "continent a new nation, conceived in liberty, and dedicated to the "
       + "proposition that all men are created equal.";
-  
+
   private static final String testMessage2 = "I have a dream that one day "
       + "this nation will rise up and live out the true meaning of its creed: "
       + "'We hold these truths to be self-evident, that all men are created equal.'";
@@ -123,7 +124,9 @@
     }
 
     private void internalRun() throws Exception {
-      TServerSocket serverSocket = new TServerSocket(ServerTestBase.PORT);
+      TServerSocket serverSocket = new TServerSocket(
+        new TServerSocket.ServerSocketTransportArgs().
+          port(ServerTestBase.PORT));
       try {
         acceptAndWrite(serverSocket);
       } finally {
@@ -280,7 +283,7 @@
         public void run() {
           try {
             // Transport
-            TServerSocket socket = new TServerSocket(PORT);
+            TServerSocket socket = new TServerSocket(new TServerSocket.ServerSocketTransportArgs().port(PORT));
 
             TTransportFactory factory = new TSaslServerTransport.Factory(
               WRAPPED_MECHANISM, SERVICE, HOST, WRAPPED_PROPS,
@@ -330,12 +333,8 @@
         throw new SaslException("Already complete!");
       }
 
-      try {
-        hasProvidedInitialResponse = true;
-        return username.getBytes("UTF-8");
-      } catch (IOException e) {
-        throw new SaslException(e.toString());
-      }
+      hasProvidedInitialResponse = true;
+      return username.getBytes(StandardCharsets.UTF_8);
     }
     public boolean isComplete() { return hasProvidedInitialResponse; }
     public byte[] unwrap(byte[] incoming, int offset, int len) {
@@ -352,11 +351,7 @@
     private String user;
     public String getMechanismName() { return "ANONYMOUS"; }
     public byte[] evaluateResponse(byte[] response) throws SaslException {
-      try {
-        this.user = new String(response, "UTF-8");
-      } catch (IOException e) {
-        throw new SaslException(e.toString());
-      }
+      this.user = new String(response, StandardCharsets.UTF_8);
       return null;
     }
     public boolean isComplete() { return user != null; }
@@ -410,4 +405,67 @@
       put("SaslServerFactory.ANONYMOUS", SaslAnonymousFactory.class.getName());
     }
   }
+
+  private static class MockTTransport extends TTransport {
+
+    byte[] badHeader = null;
+    private TMemoryInputTransport readBuffer = new TMemoryInputTransport();
+
+    public MockTTransport(int mode) {
+      if (mode==1) {
+        // Invalid status byte
+        badHeader = new byte[] { (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x05 };
+      } else if (mode == 2) {
+        // Valid status byte, negative payload length
+        badHeader = new byte[] { (byte)0x01, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF };
+      } else if (mode == 3) {
+        // Valid status byte, excessively large, bogus payload length
+        badHeader = new byte[] { (byte)0x01, (byte)0x64, (byte)0x00, (byte)0x00, (byte)0x00 };
+      }
+      readBuffer.reset(badHeader);
+    }
+
+    @Override
+    public boolean isOpen() {
+      return true;
+    }
+
+    @Override
+    public void open() throws TTransportException {}
+
+    @Override
+    public void close() {}
+
+    @Override
+    public int read(byte[] buf, int off, int len) throws TTransportException {
+      return readBuffer.read(buf, off, len);
+    }
+
+    @Override
+    public void write(byte[] buf, int off, int len) throws TTransportException {}
+  }
+
+  public void testBadHeader() {
+    TSaslTransport saslTransport = new TSaslServerTransport(new MockTTransport(1));
+    try {
+      saslTransport.receiveSaslMessage();
+      fail("Should have gotten an error due to incorrect status byte value.");
+    } catch (TTransportException e) {
+      assertEquals(e.getMessage(), "Invalid status -1");
+    }
+    saslTransport = new TSaslServerTransport(new MockTTransport(2));
+    try {
+      saslTransport.receiveSaslMessage();
+      fail("Should have gotten an error due to negative payload length.");
+    } catch (TTransportException e) {
+      assertEquals(e.getMessage(), "Invalid payload header length: -1");
+    }
+    saslTransport = new TSaslServerTransport(new MockTTransport(3));
+    try {
+      saslTransport.receiveSaslMessage();
+      fail("Should have gotten an error due to bogus (large) payload length.");
+    } catch (TTransportException e) {
+      assertEquals(e.getMessage(), "Invalid payload header length: 1677721600");
+    }
+  }
 }
diff --git a/lib/java/test/org/apache/thrift/transport/TestTSimpleFileTransport.java b/lib/java/test/org/apache/thrift/transport/TestTSimpleFileTransport.java
new file mode 100644
index 0000000..7b880f4
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/transport/TestTSimpleFileTransport.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.thrift.transport;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import junit.framework.TestCase;
+
+public class TestTSimpleFileTransport extends TestCase {
+  public void testFresh() throws Exception {
+    //Test write side
+    Path tempFilePathName = Files.createTempFile("TSimpleFileTransportTest", null);
+    Files.delete(tempFilePathName);
+    byte[] input_buf = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    TSimpleFileTransport trans_write = new TSimpleFileTransport(tempFilePathName.toString(),false, true, false);
+    assert (!trans_write.isOpen());
+    trans_write.open();
+    assert(trans_write.isOpen());
+    trans_write.write(input_buf);
+    trans_write.write(input_buf,2,2);
+    trans_write.flush();
+    trans_write.close();
+
+    //Test read side
+    TSimpleFileTransport trans = new TSimpleFileTransport(tempFilePathName.toString(),true, false);
+    assert(trans.isOpen());
+
+    //Simple file trans provides no buffer access
+    assert(0 == trans.getBufferPosition());
+    assert(null == trans.getBuffer());
+    assert(-1 == trans.getBytesRemainingInBuffer());
+
+    //Test file pointer operations
+    assert(0 == trans.getFilePointer());
+    assert(12 == trans.length());
+
+    final int BUFSIZ = 4;
+    byte[] buf1 = new byte[BUFSIZ];
+    trans.readAll(buf1, 0, BUFSIZ);
+    assert(BUFSIZ == trans.getFilePointer());
+    assert(Arrays.equals(new byte[]{1, 2, 3, 4}, buf1));
+
+    int bytesRead = trans.read(buf1, 0, BUFSIZ);
+    assert(bytesRead > 0);
+    for (int i = 0; i < bytesRead; ++i) {
+      assert(buf1[i] == i+5);
+    }
+
+    trans.seek(0);
+    assert(0 == trans.getFilePointer());
+    trans.readAll(buf1, 0, BUFSIZ);
+    assert(Arrays.equals(new byte[]{1, 2, 3, 4}, buf1));
+    assert(BUFSIZ == trans.getFilePointer());
+    trans.close();
+    Files.delete(tempFilePathName);
+  }
+}
diff --git a/lib/java/test/org/apache/thrift/transport/TestTZlibTransport.java b/lib/java/test/org/apache/thrift/transport/TestTZlibTransport.java
new file mode 100644
index 0000000..3d7f9c1
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/transport/TestTZlibTransport.java
@@ -0,0 +1,140 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.zip.DataFormatException;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.InflaterInputStream;
+
+import junit.framework.TestCase;
+
+public class TestTZlibTransport extends TestCase {
+
+  protected TTransport getTransport(TTransport underlying) {
+    return new TZlibTransport(underlying);
+  }
+
+  public static byte[] byteSequence(int start, int end) {
+    byte[] result = new byte[end-start+1];
+    for (int i = 0; i <= (end-start); i++) {
+      result[i] = (byte)(start+i);
+    }
+    return result;
+  }
+
+  public void testClose() throws TTransportException {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    WriteCountingTransport countingTrans = new WriteCountingTransport(new TIOStreamTransport(new BufferedOutputStream
+        (baos)));
+    TTransport trans = getTransport(countingTrans);
+    trans.write(byteSequence(0, 245));
+    countingTrans.close();
+    trans.close();
+  }
+
+  public void testCloseOpen() throws TTransportException {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    TTransport trans = getTransport(new TIOStreamTransport(baos));
+    byte[] uncompressed = byteSequence(0, 245);
+    trans.write(uncompressed);
+    trans.close();
+    final byte[] compressed = baos.toByteArray();
+
+    final byte[] buf = new byte[255];
+    TTransport transRead = getTransport(new TIOStreamTransport(new ByteArrayInputStream(compressed)));
+    int readBytes = transRead.read(buf, 0, buf.length);
+    assertEquals(uncompressed.length, readBytes);
+    transRead.close();
+  }
+
+  public void testRead() throws IOException, TTransportException {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(baos);
+    DataOutputStream dos = new DataOutputStream(deflaterOutputStream);
+    dos.write(byteSequence(0, 49));
+    dos.write(byteSequence(0, 219));
+
+    deflaterOutputStream.finish();
+
+    TMemoryBuffer membuf = new TMemoryBuffer(0);
+    membuf.write(baos.toByteArray());
+
+    ReadCountingTransport countTrans = new ReadCountingTransport(membuf);
+    TTransport trans = getTransport(countTrans);
+
+    byte[] readBuf = new byte[10];
+    trans.read(readBuf, 0, 10);
+    assertTrue(Arrays.equals(readBuf, byteSequence(0,9)));
+    assertEquals(1, countTrans.readCount);
+
+    trans.read(readBuf, 0, 10);
+    assertTrue(Arrays.equals(readBuf, byteSequence(10,19)));
+    assertEquals(1, countTrans.readCount);
+
+    assertEquals(30, trans.read(new byte[30], 0, 30));
+    assertEquals(1, countTrans.readCount);
+
+    readBuf = new byte[220];
+    assertEquals(220, trans.read(readBuf, 0, 220));
+    assertTrue(Arrays.equals(readBuf, byteSequence(0, 219)));
+    assertEquals(1, countTrans.readCount);
+  }
+
+  public void testWrite() throws TTransportException, IOException, DataFormatException {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    WriteCountingTransport countingTrans = new WriteCountingTransport(new TIOStreamTransport(new BufferedOutputStream(baos)));
+    TTransport trans = getTransport(countingTrans);
+
+    trans.write(byteSequence(0, 100));
+    assertEquals(1, countingTrans.writeCount);
+    trans.write(byteSequence(101, 200));
+    trans.write(byteSequence(201, 255));
+    assertEquals(1, countingTrans.writeCount);
+
+    trans.flush();
+    assertEquals(2, countingTrans.writeCount);
+
+    trans.write(byteSequence(0, 245));
+    trans.flush();
+    assertEquals(3, countingTrans.writeCount);
+
+    DataInputStream din = new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(baos.toByteArray())));
+    byte[] buf = new byte[256];
+    int n = din.read(buf, 0, 256);
+    assertEquals(n, 256);
+    assertTrue(Arrays.equals(byteSequence(0, 255), buf));
+
+    buf = new byte[246];
+    n = din.read(buf, 0, 246);
+    assertEquals(n, 246);
+    for (int i = 0; i<buf.length; i++) {
+      assertEquals("for "+i, byteSequence(0,245)[i], buf[i]);
+    }
+
+    assertTrue(Arrays.equals(byteSequence(0,245), buf));
+  }
+
+}
diff --git a/lib/javame/coding_standards.md b/lib/javame/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/javame/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/javame/src/org/apache/thrift/meta_data/FieldMetaData.java b/lib/javame/src/org/apache/thrift/meta_data/FieldMetaData.java
index 11a5a08..bce02c7 100644
--- a/lib/javame/src/org/apache/thrift/meta_data/FieldMetaData.java
+++ b/lib/javame/src/org/apache/thrift/meta_data/FieldMetaData.java
@@ -63,7 +63,7 @@
     this.valueMetaData = vMetaData;
   }
   
-  public static void addStructMetaDataMap(Class sClass, Hashtable map){
+  public static synchronized void addStructMetaDataMap(Class sClass, Hashtable map){
     structMap.put(sClass, map);
   }
 
@@ -73,7 +73,7 @@
    *
    * @param sClass The TBase class for which the metadata map is requested
    */
-  public static Hashtable getStructMetaDataMap(Class sClass){
+  public static synchronized Hashtable getStructMetaDataMap(Class sClass){
     if (!structMap.containsKey(sClass)){ // Load class if it hasn't been loaded
       try{
         sClass.newInstance();
diff --git a/lib/javame/src/org/apache/thrift/protocol/TJSONProtocol.java b/lib/javame/src/org/apache/thrift/protocol/TJSONProtocol.java
new file mode 100644
index 0000000..d391686
--- /dev/null
+++ b/lib/javame/src/org/apache/thrift/protocol/TJSONProtocol.java
@@ -0,0 +1,973 @@
+/*
+ * 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 org.apache.thrift.protocol;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Stack;
+
+import org.apache.thrift.TByteArrayOutputStream;
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransport;
+
+/**
+ * JSON protocol implementation for thrift.
+ * This is a full-featured protocol supporting write and read.
+ * Please see the C++ class header for a detailed description of the
+ * protocol's wire format.
+ */
+public class TJSONProtocol extends TProtocol {
+
+  /**
+   * Factory for JSON protocol objects
+   */
+  public static class Factory implements TProtocolFactory {
+
+    public TProtocol getProtocol(TTransport trans) {
+      return new TJSONProtocol(trans);
+    }
+
+  }
+
+  private static final byte[]  COMMA            = new byte[] { ',' };
+  private static final byte[]  COLON            = new byte[] { ':' };
+  private static final byte[]  LBRACE           = new byte[] { '{' };
+  private static final byte[]  RBRACE           = new byte[] { '}' };
+  private static final byte[]  LBRACKET         = new byte[] { '[' };
+  private static final byte[]  RBRACKET         = new byte[] { ']' };
+  private static final byte[]  QUOTE            = new byte[] { '"' };
+  private static final byte[]  BACKSLASH        = new byte[] { '\\' };
+  private static final byte[]  ZERO             = new byte[] { '0' };
+
+  private static final byte[]  ESCSEQ           = new byte[] { '\\', 'u', '0', '0' };
+
+  private static final long    VERSION          = 1;
+
+  private static final byte[]  JSON_CHAR_TABLE  = {
+                                                /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+                                                0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, // 0
+      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
+      1, 1, '"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
+                                                };
+
+  private static final String  ESCAPE_CHARS     = "\"\\/bfnrt";
+
+  private static final byte[]  ESCAPE_CHAR_VALS = {
+                                                '"', '\\', '/', '\b', '\f', '\n', '\r', '\t',
+                                                };
+
+  private static final int     DEF_STRING_SIZE  = 16;
+
+  private static final byte[]  NAME_BOOL        = new byte[] { 't', 'f' };
+  private static final byte[]  NAME_BYTE        = new byte[] { 'i', '8' };
+  private static final byte[]  NAME_I16         = new byte[] { 'i', '1', '6' };
+  private static final byte[]  NAME_I32         = new byte[] { 'i', '3', '2' };
+  private static final byte[]  NAME_I64         = new byte[] { 'i', '6', '4' };
+  private static final byte[]  NAME_DOUBLE      = new byte[] { 'd', 'b', 'l' };
+  private static final byte[]  NAME_STRUCT      = new byte[] { 'r', 'e', 'c' };
+  private static final byte[]  NAME_STRING      = new byte[] { 's', 't', 'r' };
+  private static final byte[]  NAME_MAP         = new byte[] { 'm', 'a', 'p' };
+  private static final byte[]  NAME_LIST        = new byte[] { 'l', 's', 't' };
+  private static final byte[]  NAME_SET         = new byte[] { 's', 'e', 't' };
+
+  private static final TStruct ANONYMOUS_STRUCT = new TStruct();
+
+  private static final byte[] getTypeNameForTypeID(byte typeID)
+                                                               throws TException {
+    switch (typeID) {
+    case TType.BOOL:
+      return NAME_BOOL;
+    case TType.BYTE:
+      return NAME_BYTE;
+    case TType.I16:
+      return NAME_I16;
+    case TType.I32:
+      return NAME_I32;
+    case TType.I64:
+      return NAME_I64;
+    case TType.DOUBLE:
+      return NAME_DOUBLE;
+    case TType.STRING:
+      return NAME_STRING;
+    case TType.STRUCT:
+      return NAME_STRUCT;
+    case TType.MAP:
+      return NAME_MAP;
+    case TType.SET:
+      return NAME_SET;
+    case TType.LIST:
+      return NAME_LIST;
+    default:
+      throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+          "Unrecognized type");
+    }
+  }
+
+  private static final byte getTypeIDForTypeName(byte[] name)
+                                                             throws TException {
+    byte result = TType.STOP;
+    if (name.length > 1) {
+      switch (name[0]) {
+      case 'd':
+        result = TType.DOUBLE;
+        break;
+      case 'i':
+        switch (name[1]) {
+        case '8':
+          result = TType.BYTE;
+          break;
+        case '1':
+          result = TType.I16;
+          break;
+        case '3':
+          result = TType.I32;
+          break;
+        case '6':
+          result = TType.I64;
+          break;
+        }
+        break;
+      case 'l':
+        result = TType.LIST;
+        break;
+      case 'm':
+        result = TType.MAP;
+        break;
+      case 'r':
+        result = TType.STRUCT;
+        break;
+      case 's':
+        if (name[1] == 't') {
+          result = TType.STRING;
+        }
+        else if (name[1] == 'e') {
+          result = TType.SET;
+        }
+        break;
+      case 't':
+        result = TType.BOOL;
+        break;
+      }
+    }
+    if (result == TType.STOP) {
+      throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+          "Unrecognized type");
+    }
+    return result;
+  }
+
+  // Base class for tracking JSON contexts that may require inserting/reading
+  // additional JSON syntax characters
+  // This base context does nothing.
+  protected class JSONBaseContext {
+    /**
+     * @throws TException
+     */
+    protected void write() throws TException {}
+
+    /**
+     * @throws TException
+     */
+    protected void read() throws TException {}
+
+    protected boolean escapeNum() {
+      return false;
+    }
+  }
+
+  // Context for JSON lists. Will insert/read commas before each item except
+  // for the first one
+  protected class JSONListContext extends JSONBaseContext {
+    private boolean first_ = true;
+
+    protected void write() throws TException {
+      if (first_) {
+        first_ = false;
+      } else {
+        trans_.write(COMMA);
+      }
+    }
+
+    protected void read() throws TException {
+      if (first_) {
+        first_ = false;
+      } else {
+        readJSONSyntaxChar(COMMA);
+      }
+    }
+  }
+
+  // Context for JSON records. Will insert/read colons before the value portion
+  // of each record pair, and commas before each key except the first. In
+  // addition, will indicate that numbers in the key position need to be
+  // escaped in quotes (since JSON keys must be strings).
+  protected class JSONPairContext extends JSONBaseContext {
+    private boolean first_ = true;
+    private boolean colon_ = true;
+
+    protected void write() throws TException {
+      if (first_) {
+        first_ = false;
+        colon_ = true;
+      } else {
+        trans_.write(colon_ ? COLON : COMMA);
+        colon_ = !colon_;
+      }
+    }
+
+    protected void read() throws TException {
+      if (first_) {
+        first_ = false;
+        colon_ = true;
+      } else {
+        readJSONSyntaxChar(colon_ ? COLON : COMMA);
+        colon_ = !colon_;
+      }
+    }
+
+    protected boolean escapeNum() {
+      return colon_;
+    }
+  }
+
+  // Holds up to one byte from the transport
+  protected class LookaheadReader {
+
+    private boolean hasData_;
+    private byte[]  data_ = new byte[1];
+
+    // Return and consume the next byte to be read, either taking it from the
+    // data buffer if present or getting it from the transport otherwise.
+    protected byte read() throws TException {
+      if (hasData_) {
+        hasData_ = false;
+      }
+      else {
+        trans_.readAll(data_, 0, 1);
+      }
+      return data_[0];
+    }
+
+    // Return the next byte to be read without consuming, filling the data
+    // buffer if it has not been filled already.
+    protected byte peek() throws TException {
+      if (!hasData_) {
+        trans_.readAll(data_, 0, 1);
+      }
+      hasData_ = true;
+      return data_[0];
+    }
+  }
+
+  // Stack of nested contexts of type JSONBaseContext that we may be in
+  private Stack           contextStack_ = new Stack();
+
+  // Current context that we are in
+  private JSONBaseContext context_      = new JSONBaseContext();
+
+  // Reader that manages a 1-byte buffer
+  private LookaheadReader reader_       = new LookaheadReader();
+
+  // Push a new JSON context onto the stack.
+  private void pushContext(JSONBaseContext c) {
+    contextStack_.push(context_);
+    context_ = c;
+  }
+
+  // Pop the last JSON context off the stack
+  private void popContext() {
+    context_ = (JSONBaseContext)contextStack_.pop();
+  }
+
+  /**
+   * Constructor
+   */
+  public TJSONProtocol(TTransport trans) {
+    super(trans);
+  }
+
+  public void reset() {
+    contextStack_.clear();
+    context_ = new JSONBaseContext();
+    reader_ = new LookaheadReader();
+  }
+
+  // Temporary buffer used by several methods
+  private byte[] tmpbuf_ = new byte[4];
+
+  // Read a byte that must match b[0]; otherwise an exception is thrown.
+  // Marked protected to avoid synthetic accessor in JSONListContext.read
+  // and JSONPairContext.read
+  protected void readJSONSyntaxChar(byte[] b) throws TException {
+    byte ch = reader_.read();
+    if (ch != b[0]) {
+      throw new TProtocolException(TProtocolException.INVALID_DATA,
+          "Unexpected character:" + (char)ch);
+    }
+  }
+
+  // Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its
+  // corresponding hex value
+  private static final byte hexVal(byte ch) throws TException {
+    if ((ch >= '0') && (ch <= '9')) {
+      return (byte)((char)ch - '0');
+    }
+    else if ((ch >= 'a') && (ch <= 'f')) {
+      return (byte)((char)ch - 'a' + 10);
+    }
+    else {
+      throw new TProtocolException(TProtocolException.INVALID_DATA,
+          "Expected hex character");
+    }
+  }
+
+  // Convert a byte containing a hex value to its corresponding hex character
+  private static final byte hexChar(byte val) {
+    val &= 0x0F;
+    if (val < 10) {
+      return (byte)((char)val + '0');
+    }
+    else {
+      return (byte)((char)(val - 10) + 'a');
+    }
+  }
+
+  private static boolean isHighSurrogate(char c) {
+    return c >= '\uD800' && c <= '\uDBFF';
+  }
+
+  private static boolean isLowSurrogate(char c) {
+    return c >= '\uDC00' && c <= '\uDFFF';
+  }
+
+  private static byte[] toUTF8(int codepoint) {
+    final int[] FIRST_BYTE_MASK = { 0, 0xc0, 0xe0, 0xf0 };
+    int length = 0;
+    if (codepoint <= 0x7f) length = 1;
+    else if (codepoint <= 0x7ff) length = 2;
+    else if (codepoint <= 0xffff) length = 3;
+    else if (codepoint <= 0x1fffff) length = 4;
+    else throw new RuntimeException("Code point over U+1FFFFF is not supported");
+
+    byte[] bytes = new byte[length];
+    switch (length) {
+    case 4:
+      bytes[3] = (byte)((codepoint & 0x3f) | 0x80);
+      codepoint >>= 6;
+    case 3:
+      bytes[2] = (byte)((codepoint & 0x3f) | 0x80);
+      codepoint >>= 6;
+    case 2:
+      bytes[1] = (byte)((codepoint & 0x3f) | 0x80);
+      codepoint >>= 6;
+    case 1:
+      bytes[0] = (byte)(codepoint | FIRST_BYTE_MASK[length - 1]);
+    }
+
+    return bytes;
+  }
+
+  private static byte[] toUTF8(int high, int low) {
+    int codepoint = (1 << 16) + ((high & 0x3ff) << 10);
+    codepoint += low & 0x3ff;
+    return toUTF8(codepoint);
+  }
+
+  // Write the bytes in array buf as a JSON characters, escaping as needed
+  private void writeJSONString(byte[] b) throws TException {
+    context_.write();
+    trans_.write(QUOTE);
+    int len = b.length;
+    for (int i = 0; i < len; i++) {
+      if ((b[i] & 0x00FF) >= 0x30) {
+        if (b[i] == BACKSLASH[0]) {
+          trans_.write(BACKSLASH);
+          trans_.write(BACKSLASH);
+        }
+        else {
+          trans_.write(b, i, 1);
+        }
+      }
+      else {
+        tmpbuf_[0] = JSON_CHAR_TABLE[b[i]];
+        if (tmpbuf_[0] == 1) {
+          trans_.write(b, i, 1);
+        }
+        else if (tmpbuf_[0] > 1) {
+          trans_.write(BACKSLASH);
+          trans_.write(tmpbuf_, 0, 1);
+        }
+        else {
+          trans_.write(ESCSEQ);
+          tmpbuf_[0] = hexChar((byte)(b[i] >> 4));
+          tmpbuf_[1] = hexChar(b[i]);
+          trans_.write(tmpbuf_, 0, 2);
+        }
+      }
+    }
+    trans_.write(QUOTE);
+  }
+
+  // Write out number as a JSON value. If the context dictates so, it will be
+  // wrapped in quotes to output as a JSON string.
+  private void writeJSONInteger(long num) throws TException {
+    context_.write();
+    String str = Long.toString(num);
+    boolean escapeNum = context_.escapeNum();
+    if (escapeNum) {
+      trans_.write(QUOTE);
+    }
+    try {
+      byte[] buf = str.getBytes("UTF-8");
+      trans_.write(buf);
+    } catch (UnsupportedEncodingException uex) {
+      throw new TException("JVM DOES NOT SUPPORT UTF-8");
+    }
+    if (escapeNum) {
+      trans_.write(QUOTE);
+    }
+  }
+
+  // Write out a double as a JSON value. If it is NaN or infinity or if the
+  // context dictates escaping, write out as JSON string.
+  private void writeJSONDouble(double num) throws TException {
+    context_.write();
+    String str = Double.toString(num);
+    boolean special = false;
+    switch (str.charAt(0)) {
+    case 'N': // NaN
+    case 'I': // Infinity
+      special = true;
+      break;
+    case '-':
+      if (str.charAt(1) == 'I') { // -Infinity
+        special = true;
+      }
+      break;
+    }
+
+    boolean escapeNum = special || context_.escapeNum();
+    if (escapeNum) {
+      trans_.write(QUOTE);
+    }
+    try {
+      byte[] b = str.getBytes("UTF-8");
+      trans_.write(b, 0, b.length);
+    } catch (UnsupportedEncodingException uex) {
+      throw new TException("JVM DOES NOT SUPPORT UTF-8");
+    }
+    if (escapeNum) {
+      trans_.write(QUOTE);
+    }
+  }
+
+  // Write out contents of byte array b as a JSON string with base-64 encoded
+  // data
+  private void writeJSONBase64(byte[] b, int offset, int length) throws TException {
+    context_.write();
+    trans_.write(QUOTE);
+    int len = length;
+    int off = offset;
+    while (len >= 3) {
+      // Encode 3 bytes at a time
+      TBase64Utils.encode(b, off, 3, tmpbuf_, 0);
+      trans_.write(tmpbuf_, 0, 4);
+      off += 3;
+      len -= 3;
+    }
+    if (len > 0) {
+      // Encode remainder
+      TBase64Utils.encode(b, off, len, tmpbuf_, 0);
+      trans_.write(tmpbuf_, 0, len + 1);
+    }
+    trans_.write(QUOTE);
+  }
+
+  private void writeJSONObjectStart() throws TException {
+    context_.write();
+    trans_.write(LBRACE);
+    pushContext(new JSONPairContext());
+  }
+
+  private void writeJSONObjectEnd() throws TException {
+    popContext();
+    trans_.write(RBRACE);
+  }
+
+  private void writeJSONArrayStart() throws TException {
+    context_.write();
+    trans_.write(LBRACKET);
+    pushContext(new JSONListContext());
+  }
+
+  private void writeJSONArrayEnd() throws TException {
+    popContext();
+    trans_.write(RBRACKET);
+  }
+
+  public void writeMessageBegin(TMessage message) throws TException {
+    writeJSONArrayStart();
+    writeJSONInteger(VERSION);
+    try {
+      byte[] b = message.name.getBytes("UTF-8");
+      writeJSONString(b);
+    } catch (UnsupportedEncodingException uex) {
+      throw new TException("JVM DOES NOT SUPPORT UTF-8");
+    }
+    writeJSONInteger(message.type);
+    writeJSONInteger(message.seqid);
+  }
+
+  public void writeMessageEnd() throws TException {
+    writeJSONArrayEnd();
+  }
+
+  public void writeStructBegin(TStruct struct) throws TException {
+    writeJSONObjectStart();
+  }
+
+  public void writeStructEnd() throws TException {
+    writeJSONObjectEnd();
+  }
+
+  public void writeFieldBegin(TField field) throws TException {
+    writeJSONInteger(field.id);
+    writeJSONObjectStart();
+    writeJSONString(getTypeNameForTypeID(field.type));
+  }
+
+  public void writeFieldEnd() throws TException {
+    writeJSONObjectEnd();
+  }
+
+  public void writeFieldStop() {}
+
+  public void writeMapBegin(TMap map) throws TException {
+    writeJSONArrayStart();
+    writeJSONString(getTypeNameForTypeID(map.keyType));
+    writeJSONString(getTypeNameForTypeID(map.valueType));
+    writeJSONInteger(map.size);
+    writeJSONObjectStart();
+  }
+
+  public void writeMapEnd() throws TException {
+    writeJSONObjectEnd();
+    writeJSONArrayEnd();
+  }
+
+  public void writeListBegin(TList list) throws TException {
+    writeJSONArrayStart();
+    writeJSONString(getTypeNameForTypeID(list.elemType));
+    writeJSONInteger(list.size);
+  }
+
+  public void writeListEnd() throws TException {
+    writeJSONArrayEnd();
+  }
+
+  public void writeSetBegin(TSet set) throws TException {
+    writeJSONArrayStart();
+    writeJSONString(getTypeNameForTypeID(set.elemType));
+    writeJSONInteger(set.size);
+  }
+
+  public void writeSetEnd() throws TException {
+    writeJSONArrayEnd();
+  }
+
+  public void writeBool(boolean b) throws TException {
+    writeJSONInteger(b ? (long)1 : (long)0);
+  }
+
+  public void writeByte(byte b) throws TException {
+    writeJSONInteger(b);
+  }
+
+  public void writeI16(short i16) throws TException {
+    writeJSONInteger(i16);
+  }
+
+  public void writeI32(int i32) throws TException {
+    writeJSONInteger(i32);
+  }
+
+  public void writeI64(long i64) throws TException {
+    writeJSONInteger(i64);
+  }
+
+  public void writeDouble(double dub) throws TException {
+    writeJSONDouble(dub);
+  }
+
+  public void writeString(String str) throws TException {
+    try {
+      byte[] b = str.getBytes("UTF-8");
+      writeJSONString(b);
+    } catch (UnsupportedEncodingException uex) {
+      throw new TException("JVM DOES NOT SUPPORT UTF-8");
+    }
+  }
+
+  public void writeBinary(byte[] bin) throws TException {
+    writeJSONBase64(bin, 0, bin.length);
+  }
+
+  /**
+   * Reading methods.
+   */
+
+  // Read in a JSON string, unescaping as appropriate.. Skip reading from the
+  // context if skipContext is true.
+  private TByteArrayOutputStream readJSONString(boolean skipContext)
+                                                                    throws TException {
+    TByteArrayOutputStream arr = new TByteArrayOutputStream(DEF_STRING_SIZE);
+    int highSurrogate = 0;
+    if (!skipContext) {
+      context_.read();
+    }
+    readJSONSyntaxChar(QUOTE);
+    while (true) {
+      byte ch = reader_.read();
+      if (ch == QUOTE[0]) {
+        break;
+      }
+      if (ch == ESCSEQ[0]) {
+        ch = reader_.read();
+        if (ch == ESCSEQ[1]) {
+          trans_.readAll(tmpbuf_, 0, 4);
+          short cu = (short)(
+              ((short)hexVal(tmpbuf_[0]) << 12) +
+              ((short)hexVal(tmpbuf_[1]) << 8) +
+              ((short)hexVal(tmpbuf_[2]) << 4) +
+              (short)hexVal(tmpbuf_[3]));
+          try {
+            if (isHighSurrogate((char)cu)) {
+              if (highSurrogate != 0) {
+                throw new TProtocolException(TProtocolException.INVALID_DATA,
+                    "Expected low surrogate char");
+              }
+              highSurrogate = cu;
+            }
+            else if (isLowSurrogate((char)cu)) {
+              if (highSurrogate == 0) {
+                throw new TProtocolException(TProtocolException.INVALID_DATA,
+                    "Expected high surrogate char");
+              }
+
+              arr.write(toUTF8(highSurrogate, cu));
+              highSurrogate = 0;
+            }
+            else {
+              arr.write(toUTF8(cu));
+            }
+            continue;
+          }
+          catch (UnsupportedEncodingException ex) {
+            throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED,
+                "JVM does not support UTF-8");
+          }
+          catch (IOException ex) {
+            throw new TProtocolException(TProtocolException.INVALID_DATA,
+                "Invalid unicode sequence");
+          }
+        }
+        else {
+          int off = ESCAPE_CHARS.indexOf(ch);
+          if (off == -1) {
+            throw new TProtocolException(TProtocolException.INVALID_DATA,
+                "Expected control char");
+          }
+          ch = ESCAPE_CHAR_VALS[off];
+        }
+      }
+      arr.write(ch);
+    }
+
+    if (highSurrogate != 0) {
+      throw new TProtocolException(TProtocolException.INVALID_DATA,
+          "Expected low surrogate char");
+    }
+    return arr;
+  }
+
+  // Return true if the given byte could be a valid part of a JSON number.
+  private boolean isJSONNumeric(byte b) {
+    switch (b) {
+    case '+':
+    case '-':
+    case '.':
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case 'E':
+    case 'e':
+      return true;
+    }
+    return false;
+  }
+
+  // Read in a sequence of characters that are all valid in JSON numbers. Does
+  // not do a complete regex check to validate that this is actually a number.
+  private String readJSONNumericChars() throws TException {
+    StringBuffer strbuf = new StringBuffer();
+    while (true) {
+      byte ch = reader_.peek();
+      if (!isJSONNumeric(ch)) {
+        break;
+      }
+      strbuf.append((char)reader_.read());
+    }
+    return strbuf.toString();
+  }
+
+  // Read in a JSON number. If the context dictates, read in enclosing quotes.
+  private long readJSONInteger() throws TException {
+    context_.read();
+    if (context_.escapeNum()) {
+      readJSONSyntaxChar(QUOTE);
+    }
+    String str = readJSONNumericChars();
+    if (context_.escapeNum()) {
+      readJSONSyntaxChar(QUOTE);
+    }
+    try {
+      return Long.valueOf(str).longValue();
+    } catch (NumberFormatException ex) {
+      throw new TProtocolException(TProtocolException.INVALID_DATA,
+          "Bad data encounted in numeric data");
+    }
+  }
+
+  // Read in a JSON double value. Throw if the value is not wrapped in quotes
+  // when expected or if wrapped in quotes when not expected.
+  private double readJSONDouble() throws TException {
+    context_.read();
+    if (reader_.peek() == QUOTE[0]) {
+      TByteArrayOutputStream arr = readJSONString(true);
+      try {
+        double dub = Double.valueOf(arr.toString("UTF-8")).doubleValue();
+        if (!context_.escapeNum() && !Double.isNaN(dub) &&
+            !Double.isInfinite(dub)) {
+          // Throw exception -- we should not be in a string in this case
+          throw new TProtocolException(TProtocolException.INVALID_DATA,
+              "Numeric data unexpectedly quoted");
+        }
+        return dub;
+      } catch (UnsupportedEncodingException ex) {
+        throw new TException("JVM DOES NOT SUPPORT UTF-8");
+      }
+    }
+    else {
+      if (context_.escapeNum()) {
+        // This will throw - we should have had a quote if escapeNum == true
+        readJSONSyntaxChar(QUOTE);
+      }
+      try {
+        return Double.valueOf(readJSONNumericChars()).doubleValue();
+      } catch (NumberFormatException ex) {
+        throw new TProtocolException(TProtocolException.INVALID_DATA,
+            "Bad data encounted in numeric data");
+      }
+    }
+  }
+
+  // Read in a JSON string containing base-64 encoded data and decode it.
+  private byte[] readJSONBase64() throws TException {
+    TByteArrayOutputStream arr = readJSONString(false);
+    byte[] b = arr.get();
+    int len = arr.len();
+    int off = 0;
+    int size = 0;
+    // Ignore padding
+    int bound = len >= 2 ? len - 2 : 0;
+    for (int i = len - 1; i >= bound && b[i] == '='; --i) {
+      --len;
+    }
+    while (len >= 4) {
+      // Decode 4 bytes at a time
+      TBase64Utils.decode(b, off, 4, b, size); // NB: decoded in place
+      off += 4;
+      len -= 4;
+      size += 3;
+    }
+    // Don't decode if we hit the end or got a single leftover byte (invalid
+    // base64 but legal for skip of regular string type)
+    if (len > 1) {
+      // Decode remainder
+      TBase64Utils.decode(b, off, len, b, size); // NB: decoded in place
+      size += len - 1;
+    }
+    // Sadly we must copy the byte[] (any way around this?)
+    byte[] result = new byte[size];
+    System.arraycopy(b, 0, result, 0, size);
+    return result;
+  }
+
+  private void readJSONObjectStart() throws TException {
+    context_.read();
+    readJSONSyntaxChar(LBRACE);
+    pushContext(new JSONPairContext());
+  }
+
+  private void readJSONObjectEnd() throws TException {
+    readJSONSyntaxChar(RBRACE);
+    popContext();
+  }
+
+  private void readJSONArrayStart() throws TException {
+    context_.read();
+    readJSONSyntaxChar(LBRACKET);
+    pushContext(new JSONListContext());
+  }
+
+  private void readJSONArrayEnd() throws TException {
+    readJSONSyntaxChar(RBRACKET);
+    popContext();
+  }
+
+  public TMessage readMessageBegin() throws TException {
+    readJSONArrayStart();
+    if (readJSONInteger() != VERSION) {
+      throw new TProtocolException(TProtocolException.BAD_VERSION,
+          "Message contained bad version.");
+    }
+    String name;
+    try {
+      name = readJSONString(false).toString("UTF-8");
+    } catch (UnsupportedEncodingException ex) {
+      throw new TException("JVM DOES NOT SUPPORT UTF-8");
+    }
+    byte type = (byte)readJSONInteger();
+    int seqid = (int)readJSONInteger();
+    return new TMessage(name, type, seqid);
+  }
+
+  public void readMessageEnd() throws TException {
+    readJSONArrayEnd();
+  }
+
+  public TStruct readStructBegin() throws TException {
+    readJSONObjectStart();
+    return ANONYMOUS_STRUCT;
+  }
+
+  public void readStructEnd() throws TException {
+    readJSONObjectEnd();
+  }
+
+  public TField readFieldBegin() throws TException {
+    byte ch = reader_.peek();
+    byte type;
+    short id = 0;
+    if (ch == RBRACE[0]) {
+      type = TType.STOP;
+    }
+    else {
+      id = (short)readJSONInteger();
+      readJSONObjectStart();
+      type = getTypeIDForTypeName(readJSONString(false).get());
+    }
+    return new TField("", type, id);
+  }
+
+  public void readFieldEnd() throws TException {
+    readJSONObjectEnd();
+  }
+
+  public TMap readMapBegin() throws TException {
+    readJSONArrayStart();
+    byte keyType = getTypeIDForTypeName(readJSONString(false).get());
+    byte valueType = getTypeIDForTypeName(readJSONString(false).get());
+    int size = (int)readJSONInteger();
+    readJSONObjectStart();
+    return new TMap(keyType, valueType, size);
+  }
+
+  public void readMapEnd() throws TException {
+    readJSONObjectEnd();
+    readJSONArrayEnd();
+  }
+
+  public TList readListBegin() throws TException {
+    readJSONArrayStart();
+    byte elemType = getTypeIDForTypeName(readJSONString(false).get());
+    int size = (int)readJSONInteger();
+    return new TList(elemType, size);
+  }
+
+  public void readListEnd() throws TException {
+    readJSONArrayEnd();
+  }
+
+  public TSet readSetBegin() throws TException {
+    readJSONArrayStart();
+    byte elemType = getTypeIDForTypeName(readJSONString(false).get());
+    int size = (int)readJSONInteger();
+    return new TSet(elemType, size);
+  }
+
+  public void readSetEnd() throws TException {
+    readJSONArrayEnd();
+  }
+
+  public boolean readBool() throws TException {
+    return (readJSONInteger() == 0 ? false : true);
+  }
+
+  public byte readByte() throws TException {
+    return (byte)readJSONInteger();
+  }
+
+  public short readI16() throws TException {
+    return (short)readJSONInteger();
+  }
+
+  public int readI32() throws TException {
+    return (int)readJSONInteger();
+  }
+
+  public long readI64() throws TException {
+    return readJSONInteger();
+  }
+
+  public double readDouble() throws TException {
+    return readJSONDouble();
+  }
+
+  public String readString() throws TException {
+    try {
+      return readJSONString(false).toString("UTF-8");
+    } catch (UnsupportedEncodingException ex) {
+      throw new TException("JVM DOES NOT SUPPORT UTF-8");
+    }
+  }
+
+  public byte[] readBinary() throws TException {
+    return readJSONBase64();
+  }
+
+}
diff --git a/lib/javame/src/org/apache/thrift/transport/THttpClient.java b/lib/javame/src/org/apache/thrift/transport/THttpClient.java
index 451a2e5..e6ffba4 100644
--- a/lib/javame/src/org/apache/thrift/transport/THttpClient.java
+++ b/lib/javame/src/org/apache/thrift/transport/THttpClient.java
@@ -42,6 +42,8 @@
 
   private InputStream inputStream_ = null;
 
+  private HttpConnection connection = null;
+
   private int connectTimeout_ = 0;
 
   private int readTimeout_ = 0;
@@ -49,7 +51,7 @@
   private Hashtable customHeaders_ = null;
 
   public THttpClient(String url) throws TTransportException {
-                url_ = url;
+    url_ = url;
   }
 
   public void setConnectTimeout(int timeout) {
@@ -81,6 +83,14 @@
       }
       inputStream_ = null;
     }
+
+    if (connection != null) {
+      try {
+        connection.close();
+      } catch (IOException ioe) {
+      }
+      connection = null;
+    }
   }
 
   public boolean isOpen() {
@@ -106,62 +116,48 @@
     requestBuffer_.write(buf, off, len);
   }
   
-    public void flush() throws TTransportException {
+  public void flush() throws TTransportException {
     // Extract request and reset buffer
-        byte[] data = requestBuffer_.toByteArray();
-        requestBuffer_.reset();
+    byte[] data = requestBuffer_.toByteArray();
+    requestBuffer_.reset();
 
-        try {
-            // Create connection object
-            HttpConnection connection = (HttpConnection)Connector.open(url_);
-    
-            // Timeouts, only if explicitly set
-            if (connectTimeout_ > 0) {
-            //  XXX: not available
-            //  connection.setConnectTimeout(connectTimeout_);
-            }   
-            if (readTimeout_ > 0) {
-            //  XXX: not available
-            //  connection.setReadTimeout(readTimeout_);
-            }
-    
-            // Make the request
-            connection.setRequestMethod("POST");
-            connection.setRequestProperty("Content-Type", "application/x-thrift");
-            connection.setRequestProperty("Accept", "application/x-thrift");
-            connection.setRequestProperty("User-Agent", "JavaME/THttpClient");
+    try {
+      // Create connection object
+      connection = (HttpConnection)Connector.open(url_);
+  
+      // Make the request
+      connection.setRequestMethod("POST");
+      connection.setRequestProperty("Content-Type", "application/x-thrift");
+      connection.setRequestProperty("Accept", "application/x-thrift");
+      connection.setRequestProperty("User-Agent", "JavaME/THttpClient");
 
-            connection.setRequestProperty("Connection", "Keep-Alive");
-            connection.setRequestProperty("Keep-Alive", "5000");
-            connection.setRequestProperty("Http-version", "HTTP/1.1");
-            connection.setRequestProperty("Cache-Control", "no-transform");
+      connection.setRequestProperty("Connection", "Keep-Alive");
+      connection.setRequestProperty("Keep-Alive", "5000");
+      connection.setRequestProperty("Http-version", "HTTP/1.1");
+      connection.setRequestProperty("Cache-Control", "no-transform");
 
-
-            if (customHeaders_ != null) {
-                for (Enumeration e = customHeaders_.keys() ; e.hasMoreElements() ;) {
-                    String key = (String)e.nextElement();
-                    String value = (String)customHeaders_.get(key);
-                    connection.setRequestProperty(key, value);
-                }
-            }
-            // connection.setDoOutput(true);
-            //  connection.connect();
-    
-            OutputStream os = connection.openOutputStream();
-            os.write(data);
-            os.close();
-
-            int responseCode = connection.getResponseCode();
-            if (responseCode != HttpConnection.HTTP_OK) {
-                throw new TTransportException("HTTP Response code: " + responseCode);
-            }
-
-            // Read the responses
-            inputStream_ = connection.openInputStream();
-
-        } catch (IOException iox) {
-            System.out.println(iox.toString());
-            throw new TTransportException(iox);
+      if (customHeaders_ != null) {
+        for (Enumeration e = customHeaders_.keys() ; e.hasMoreElements() ;) {
+          String key = (String)e.nextElement();
+          String value = (String)customHeaders_.get(key);
+          connection.setRequestProperty(key, value);
         }
+      }
+  
+      OutputStream os = connection.openOutputStream();
+      os.write(data);
+      os.close();
+
+      int responseCode = connection.getResponseCode();
+      if (responseCode != HttpConnection.HTTP_OK) {
+        throw new TTransportException("HTTP Response code: " + responseCode);
+      }
+
+      // Read the responses
+      inputStream_ = connection.openInputStream();
+    } catch (IOException iox) {
+      System.out.println(iox.toString());
+      throw new TTransportException(iox);
     }
+  }
 }
diff --git a/lib/javame/src/org/apache/thrift/transport/TMemoryBuffer.java b/lib/javame/src/org/apache/thrift/transport/TMemoryBuffer.java
new file mode 100644
index 0000000..4ae1ab2
--- /dev/null
+++ b/lib/javame/src/org/apache/thrift/transport/TMemoryBuffer.java
@@ -0,0 +1,97 @@
+/*
+ * 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 org.apache.thrift.transport;
+
+import org.apache.thrift.TByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Memory buffer-based implementation of the TTransport interface.
+ */
+public class TMemoryBuffer extends TTransport {
+  /**
+   * Create a TMemoryBuffer with an initial buffer size of <i>size</i>. The
+   * internal buffer will grow as necessary to accommodate the size of the data
+   * being written to it.
+   */
+  public TMemoryBuffer(int size) {
+    arr_ = new TByteArrayOutputStream(size);
+  }
+
+  public boolean isOpen() {
+    return true;
+  }
+
+  public void open() {
+    /* Do nothing */
+  }
+
+  public void close() {
+    /* Do nothing */
+  }
+
+  public int read(byte[] buf, int off, int len) {
+    byte[] src = arr_.get();
+    int amtToRead = (len > arr_.len() - pos_ ? arr_.len() - pos_ : len);
+    if (amtToRead > 0) {
+      System.arraycopy(src, pos_, buf, off, amtToRead);
+      pos_ += amtToRead;
+    }
+    return amtToRead;
+  }
+
+  public void write(byte[] buf, int off, int len) {
+    arr_.write(buf, off, len);
+  }
+
+  /**
+   * Output the contents of the memory buffer as a String, using the supplied
+   * encoding
+   * 
+   * @param enc the encoding to use
+   * @return the contents of the memory buffer as a String
+   */
+  public String toString(String enc) throws UnsupportedEncodingException {
+    return arr_.toString(enc);
+  }
+
+  public String inspect() {
+    String buf = "";
+    byte[] bytes = arr_.toByteArray();
+    for (int i = 0; i < bytes.length; i++) {
+      buf += (pos_ == i ? "==>" : "") + Integer.toHexString(bytes[i] & 0xff) + " ";
+    }
+    return buf;
+  }
+
+  // The contents of the buffer
+  private TByteArrayOutputStream arr_;
+
+  // Position to read next byte from
+  private int                    pos_;
+
+  public int length() {
+    return arr_.size();
+  }
+
+  public byte[] getArray() {
+    return arr_.get();
+  }
+}
diff --git a/lib/js/Gruntfile.js b/lib/js/Gruntfile.js
new file mode 100644
index 0000000..b32a016
--- /dev/null
+++ b/lib/js/Gruntfile.js
@@ -0,0 +1,293 @@
+//To build dist/thrift.js, dist/thrift.min.js and doc/*
+//run grunt at the command line in this directory.
+//Prerequisites:
+// Node Setup -   nodejs.org
+// Grunt Setup -  npm install  //reads the ./package.json and installs project dependencies
+// Run grunt -    npx grunt  // uses project-local installed version of grunt (from package.json)
+
+module.exports = function(grunt) {
+  'use strict';
+
+  grunt.initConfig({
+    pkg: grunt.file.readJSON('package.json'),
+    concat: {
+      options: {
+        separator: ';'
+      },
+      dist: {
+        src: ['src/**/*.js'],
+        dest: 'dist/<%= pkg.name %>.js'
+      }
+    },
+    jsdoc : {
+        dist : {
+            src: ['src/*.js', './README.md'],
+            options: {
+              destination: 'doc'
+            }
+        }
+    },
+    uglify: {
+      options: {
+        banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
+      },
+      dist: {
+        files: {
+          'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
+        }
+      }
+    },
+    shell: {
+      InstallThriftJS: {
+        command: 'mkdir -p test/build/js/lib; cp src/thrift.js test/build/js/thrift.js'
+      },
+      InstallThriftNodeJSDep: {
+        command: 'cd ../..; npm install'
+      },
+      InstallTestLibs: {
+        command: 'cd test; ant download_jslibs'
+      },
+      ThriftGen: {
+        command: [
+          'mkdir -p test/gen-js',
+          '../../compiler/cpp/thrift -gen js --out test/gen-js ../../test/ThriftTest.thrift',
+          '../../compiler/cpp/thrift -gen js --out test/gen-js ../../test/JsDeepConstructorTest.thrift',
+          'mkdir -p test/gen-js-jquery',
+          '../../compiler/cpp/thrift -gen js:jquery --out test/gen-js-jquery ../../test/ThriftTest.thrift',
+          'mkdir -p test/gen-nodejs',
+          '../../compiler/cpp/thrift -gen js:node --out test/gen-nodejs ../../test/ThriftTest.thrift',
+          'mkdir -p test/gen-js-es6',
+          '../../compiler/cpp/thrift -gen js:es6 --out test/gen-js-es6 ../../test/ThriftTest.thrift',
+          'mkdir -p test/gen-nodejs-es6',
+          '../../compiler/cpp/thrift -gen js:node,es6 --out ./test/gen-nodejs-es6 ../../test/ThriftTest.thrift',
+        ].join(' && ')
+      },
+      ThriftGenJQ: {
+        command: '../../compiler/cpp/thrift -gen js:jquery -gen js:node -o test ../../test/ThriftTest.thrift'
+      },
+      ThriftGenDeepConstructor: {
+        command: '../../compiler/cpp/thrift -gen js -o test ../../test/JsDeepConstructorTest.thrift'
+      },
+      ThriftGenDoubleConstants: {
+        command: '../../compiler/cpp/thrift -gen js -o test ../../test/DoubleConstantsTest.thrift'
+      },
+      ThriftTestServer: {
+        options: {
+          async: true,
+          execOptions: {
+            cwd: "./test",
+            env: {NODE_PATH: "../../nodejs/lib:../../../node_modules"}
+          }
+        },
+        command: "node server_http.js",
+      },
+      ThriftTestServerES6: {
+        options: {
+          async: true,
+          execOptions: {
+            cwd: "./test",
+            env: {NODE_PATH: "../../nodejs/lib:../../../node_modules"}
+          }
+        },
+        command: "node server_http.js --es6",
+      },
+      ThriftTestServer_TLS: {
+        options: {
+          async: true,
+          execOptions: {
+            cwd: "./test",
+            env: {NODE_PATH: "../../nodejs/lib:../../../node_modules"}
+          }
+        },
+        command: "node server_https.js",
+      },
+      ThriftTestServerES6_TLS: {
+        options: {
+          async: true,
+          execOptions: {
+            cwd: "./test",
+            env: {NODE_PATH: "../../nodejs/lib:../../../node_modules"}
+          }
+        },
+        command: "node server_https.js --es6",
+      },
+    },
+    qunit: {
+      ThriftJS: {
+        options: {
+          urls: [
+            'http://localhost:8089/test-nojq.html'
+          ],
+          puppeteer: {
+            headless: true,
+            args: ['--no-sandbox'],
+          },
+        }
+      },
+      ThriftJSJQ: {
+        options: {
+          urls: [
+            'http://localhost:8089/test.html'
+          ],
+          puppeteer: {
+            headless: true,
+            args: ['--no-sandbox'],
+          },
+        }
+      },
+      ThriftJS_DoubleRendering: {
+        options: {
+          urls: [
+            'http://localhost:8089/test-double-rendering.html'
+          ],
+          puppeteer: {
+            headless: true,
+            args: ['--no-sandbox'],
+            ignoreHTTPSErrors: true,
+          },
+        }
+      },
+      ThriftWS: {
+        options: {
+          urls: [
+            'http://localhost:8089/testws.html'
+          ],
+          puppeteer: {
+            headless: true,
+            args: ['--no-sandbox'],
+          },
+        }
+      },
+      ThriftJS_TLS: {
+        options: {
+          urls: [
+            'https://localhost:8091/test-nojq.html'
+          ],
+          puppeteer: {
+            headless: true,
+            args: ['--no-sandbox'],
+            ignoreHTTPSErrors: true,
+          },
+        }
+      },
+      ThriftJSJQ_TLS: {
+        options: {
+          urls: [
+            'https://localhost:8091/test.html'
+          ],
+          puppeteer: {
+            headless: true,
+            args: ['--no-sandbox'],
+            ignoreHTTPSErrors: true,
+          },
+        }
+      },
+      ThriftWS_TLS: {
+        options: {
+          urls: [
+            'https://localhost:8091/testws.html'
+          ],
+          puppeteer: {
+            headless: true,
+            args: ['--no-sandbox'],
+            ignoreHTTPSErrors: true,
+          },
+        }
+      },
+      ThriftDeepConstructor: {
+        options: {
+          urls: [
+            'http://localhost:8089/test-deep-constructor.html'
+          ],
+          puppeteer: {
+            headless: true,
+            args: ['--no-sandbox'],
+          },
+        }
+      },
+      ThriftWSES6: {
+        options: {
+          urls: [
+            'http://localhost:8088/test-es6.html'
+          ],
+          puppeteer: {
+            headless: true,
+            args: ['--no-sandbox'],
+          },
+        }
+      }
+    },
+    jshint: {
+      // The main thrift library file. not es6 yet :(
+      lib: {
+        src: ['src/**/*.js'],
+      },
+      // The test files use es6
+      test: {
+        src: ['Gruntfile.js', 'test/*.js'],
+        options: {
+          esversion: 6,
+        }
+      },
+      gen_js_code: {
+        src: ['test/gen-js/*.js', 'test/gen-js-jquery/*.js'],
+      },
+      gen_es6_code: {
+        src: ['test/gen-js-es6/*.js'],
+        options: {
+          esversion: 6,
+        }
+      },
+      gen_node_code: {
+        src: ['test/gen-nodejs/*.js'],
+        options: {
+          node: true,
+        }
+      },
+      gen_node_es6_code: {
+        src: ['test/gen-nodejs-es6/*.js'],
+        options: {
+          node: true,
+          esversion: 6,
+        }
+      }
+    },
+  });
+
+  grunt.loadNpmTasks('grunt-contrib-uglify');
+  grunt.loadNpmTasks('grunt-contrib-jshint');
+  grunt.loadNpmTasks('grunt-contrib-qunit');
+  grunt.loadNpmTasks('grunt-contrib-concat');
+  grunt.loadNpmTasks('grunt-jsdoc');
+  grunt.loadNpmTasks('grunt-shell-spawn');
+
+  grunt.registerTask('wait', 'Wait just one second for server to start', function () {
+    var done = this.async();
+    setTimeout(function() {
+      done(true);
+    }, 1000);
+  });
+
+  grunt.registerTask('installAndGenerate', [
+    'shell:InstallThriftJS', 'shell:InstallThriftNodeJSDep', 'shell:ThriftGen',
+    'shell:ThriftGenDeepConstructor', 'shell:ThriftGenDoubleConstants',
+    'shell:InstallTestLibs',
+  ]);
+
+  grunt.registerTask('test', [
+    'installAndGenerate',
+    'jshint',
+    'shell:ThriftTestServer', 'shell:ThriftTestServer_TLS',
+    'shell:ThriftTestServerES6', 'shell:ThriftTestServerES6_TLS',
+    'wait',
+    'qunit:ThriftDeepConstructor',
+    'qunit:ThriftJS', 'qunit:ThriftJS_TLS',
+    'qunit:ThriftJS_DoubleRendering',
+    'qunit:ThriftWS',
+    'qunit:ThriftJSJQ', 'qunit:ThriftJSJQ_TLS',
+    'qunit:ThriftWSES6',
+    'shell:ThriftTestServer:kill', 'shell:ThriftTestServer_TLS:kill',
+    'shell:ThriftTestServerES6:kill', 'shell:ThriftTestServerES6_TLS:kill',
+  ]);
+  grunt.registerTask('default', ['test', 'concat', 'uglify', 'jsdoc']);
+};
diff --git a/lib/js/Makefile.am b/lib/js/Makefile.am
new file mode 100644
index 0000000..9ea20a4
--- /dev/null
+++ b/lib/js/Makefile.am
@@ -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.
+#
+
+# Make sure this doesn't fail if ant is not configured.
+# We call install twice to work around npm issues
+#
+if HAVE_NPM
+SUBDIRS = test
+
+check-local: all
+	$(NPM) install || $(NPM) install
+	$(NPM) list
+	./node_modules/.bin/grunt
+endif
diff --git a/lib/js/README b/lib/js/README
deleted file mode 100644
index fafdc43..0000000
--- a/lib/js/README
+++ /dev/null
@@ -1,40 +0,0 @@
-Thrift Javascript Library
-
-License
-=======
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-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.
-
-Using Thrift with Javascript
-=====================
-
-Allows javascript client interfaces to Thrift services.
-This is geared for use in a web browser.
-
-This client can only speak the JSON Protocol and the only supported
-transport is AJAX.
-
-There is a test httpd service in the test dir that requires
-http://hc.apache.org under test dir
-
-Dependencies
-============
-A JavaScript enabled browser. Tested with:
- *IE 6,7,8
- *FF 2,3
- *Safari 3 & 4
diff --git a/lib/js/README.md b/lib/js/README.md
new file mode 100644
index 0000000..9d51e2a
--- /dev/null
+++ b/lib/js/README.md
@@ -0,0 +1,140 @@
+Thrift Javascript Library
+=========================
+This browser based Apache Thrift implementation supports
+RPC clients using the JSON protocol over Http[s] with XHR
+and WebSocket.
+
+License
+-------
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+Grunt Build
+------------
+This is the base directory for the Apache Thrift JavaScript
+library. This directory contains a Gruntfile.js and a
+package.json. Many of the build and test tools used here
+require a recent version of Node.js to be installed. To 
+install the support files for the Grunt build tool execute
+the command:
+
+    npm install
+    
+This reads the package.json and pulls in the appropriate
+sources from the internet. To build the JavaScript branch
+of Apache Thrift execute the command:
+
+    npx grunt
+    
+This runs the grunt build tool (from within `./node_modules/.bin/`),
+linting all of the source files, setting up and running the
+tests, concatenating and minifying the main libraries and
+generating the html documentation.
+
+Tree
+----
+The following directories are present (some only after the
+grunt build):
+  /src  - The JavaScript Apache Thrift source
+  /doc  - HTML documentation
+  /dist - Distribution files (thrift.js and thrift.min.js)
+  /test - Various tests, this is a good place to look for
+          example code
+  /node_modules - Build support files installed by npm
+
+
+Example JavaScript Client and Server
+------------------------------------
+The listing below demonstrates a simple browser based JavaScript
+Thrift client and Node.js JavaScript server for the hello_svc 
+service. 
+
+### hello.thrift - Service IDL 
+### build with: $ thrift -gen js -gen js:node hello.thrift
+    service hello_svc {
+      string get_message(1: string name)
+    }
+
+### hello.html - Browser Client
+    <!DOCTYPE html>
+    <html lang="en">
+      <head>
+        <meta charset="utf-8">
+        <title>Hello Thrift</title>
+      </head>
+      <body>
+        Name: <input type="text" id="name_in">
+        <input type="button" id="get_msg" value="Get Message" >
+        <div id="output"></div>
+  
+        <script src="thrift.js"></script>
+        <script src="gen-js/hello_svc.js"></script>
+        <script>
+          (function() {
+            var transport = new Thrift.TXHRTransport("/hello");
+            var protocol  = new Thrift.TJSONProtocol(transport);
+            var client    = new hello_svcClient(protocol);
+            var nameElement = document.getElementById("name_in");
+            var outputElement = document.getElementById("output");
+            document.getElementById("get_msg")
+              .addEventListener("click", function(){
+                client.get_message(nameElement.value, function(result) {
+                  outputElement.innerHTML = result;
+                });
+              });
+          })();
+        </script>
+      </body>
+    </html>
+
+### hello.js - Node Server
+    var thrift = require('thrift');
+    var hello_svc = require('./gen-nodejs/hello_svc.js');
+    
+    var hello_handler = {
+      get_message: function(name, result) {
+        var msg = "Hello " + name + "!";
+        result(null, msg);
+      }
+    }
+    
+    var hello_svc_opt = {
+      transport: thrift.TBufferedTransport,
+      protocol: thrift.TJSONProtocol,
+      processor: hello_svc,
+      handler: hello_handler
+    };
+    
+    var server_opt = {
+      staticFilePath: ".",
+      services: {
+        "/hello": hello_svc_opt
+      }
+    }
+    
+    var server = Thrift.createWebServer(server_opt);
+    var port = 9099;
+    server.listen(port);
+    console.log("Http/Thrift Server running on port: " + port);
+
+
+TypeScript
+------------------------------------
+TypeScript definition files can also be generated by running:
+
+    thrift --gen js:ts file.thrift
+
diff --git a/lib/js/coding_standards.md b/lib/js/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/js/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/js/package-lock.json b/lib/js/package-lock.json
new file mode 100644
index 0000000..63d81c3
--- /dev/null
+++ b/lib/js/package-lock.json
@@ -0,0 +1,3777 @@
+{
+  "name": "thrift",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "abbrev": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+    },
+    "agent-base": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
+      "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
+      "dev": true,
+      "requires": {
+        "es6-promisify": "^5.0.0"
+      }
+    },
+    "ajv": {
+      "version": "5.5.2",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
+      "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "co": "^4.6.0",
+        "fast-deep-equal": "^1.0.0",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.3.0"
+      }
+    },
+    "align-text": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
+      "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2",
+        "longest": "^1.0.1",
+        "repeat-string": "^1.5.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+      "dev": true
+    },
+    "ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "requires": {
+        "color-convert": "^1.9.0"
+      }
+    },
+    "argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "requires": {
+        "sprintf-js": "~1.0.2"
+      },
+      "dependencies": {
+        "sprintf-js": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+          "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+          "dev": true
+        }
+      }
+    },
+    "arr-diff": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+      "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+      "dev": true
+    },
+    "arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+      "dev": true
+    },
+    "arr-union": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+      "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+      "dev": true
+    },
+    "array-each": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
+      "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=",
+      "dev": true
+    },
+    "array-find-index": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+      "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
+      "dev": true
+    },
+    "array-slice": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
+      "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==",
+      "dev": true
+    },
+    "array-unique": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+      "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+      "dev": true
+    },
+    "asn1": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+      "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "safer-buffer": "~2.1.0"
+      }
+    },
+    "assert-plus": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+      "dev": true
+    },
+    "assign-symbols": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+      "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+      "dev": true
+    },
+    "async": {
+      "version": "1.5.2",
+      "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz",
+      "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+      "dev": true
+    },
+    "async-limiter": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
+      "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
+      "dev": true
+    },
+    "asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+      "dev": true,
+      "optional": true
+    },
+    "atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "dev": true
+    },
+    "aws-sign2": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+      "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+      "dev": true,
+      "optional": true
+    },
+    "aws4": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
+      "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
+      "dev": true,
+      "optional": true
+    },
+    "babylon": {
+      "version": "7.0.0-beta.19",
+      "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz",
+      "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A=="
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "dev": true
+    },
+    "base": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+      "dev": true,
+      "requires": {
+        "cache-base": "^1.0.1",
+        "class-utils": "^0.3.5",
+        "component-emitter": "^1.2.1",
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.1",
+        "mixin-deep": "^1.2.0",
+        "pascalcase": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "bcrypt-pbkdf": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+      "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "tweetnacl": "^0.14.3"
+      }
+    },
+    "bluebird": {
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz",
+      "integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg=="
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "braces": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+      "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+      "dev": true,
+      "requires": {
+        "arr-flatten": "^1.1.0",
+        "array-unique": "^0.3.2",
+        "extend-shallow": "^2.0.1",
+        "fill-range": "^4.0.0",
+        "isobject": "^3.0.1",
+        "repeat-element": "^1.1.2",
+        "snapdragon": "^0.8.1",
+        "snapdragon-node": "^2.0.1",
+        "split-string": "^3.0.2",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "browserify-zlib": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
+      "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=",
+      "dev": true,
+      "requires": {
+        "pako": "~0.2.0"
+      }
+    },
+    "buffer-from": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+      "dev": true
+    },
+    "buffer-shims": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz",
+      "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=",
+      "dev": true
+    },
+    "builtin-modules": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+      "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+      "dev": true
+    },
+    "cache-base": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+      "dev": true,
+      "requires": {
+        "collection-visit": "^1.0.0",
+        "component-emitter": "^1.2.1",
+        "get-value": "^2.0.6",
+        "has-value": "^1.0.0",
+        "isobject": "^3.0.1",
+        "set-value": "^2.0.0",
+        "to-object-path": "^0.3.0",
+        "union-value": "^1.0.0",
+        "unset-value": "^1.0.0"
+      }
+    },
+    "camelcase": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
+      "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
+      "dev": true
+    },
+    "camelcase-keys": {
+      "version": "2.1.0",
+      "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+      "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
+      "dev": true,
+      "requires": {
+        "camelcase": "^2.0.0",
+        "map-obj": "^1.0.0"
+      }
+    },
+    "caseless": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+      "dev": true,
+      "optional": true
+    },
+    "catharsis": {
+      "version": "0.8.9",
+      "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz",
+      "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=",
+      "requires": {
+        "underscore-contrib": "~0.3.0"
+      }
+    },
+    "center-align": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
+      "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
+      "dev": true,
+      "requires": {
+        "align-text": "^0.1.3",
+        "lazy-cache": "^1.0.3"
+      }
+    },
+    "chalk": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+      "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      }
+    },
+    "class-utils": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+      "dev": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "define-property": "^0.2.5",
+        "isobject": "^3.0.0",
+        "static-extend": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        }
+      }
+    },
+    "cli": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz",
+      "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=",
+      "dev": true,
+      "requires": {
+        "exit": "0.1.2",
+        "glob": "^7.1.1"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.1.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+          "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.0.4",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        }
+      }
+    },
+    "cliui": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
+      "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
+      "dev": true,
+      "requires": {
+        "center-align": "^0.1.1",
+        "right-align": "^0.1.1",
+        "wordwrap": "0.0.2"
+      }
+    },
+    "co": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+      "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
+      "dev": true,
+      "optional": true
+    },
+    "coffeescript": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.10.0.tgz",
+      "integrity": "sha1-56qDAZF+9iGzXYo580jc3R234z4=",
+      "dev": true
+    },
+    "collection-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+      "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+      "dev": true,
+      "requires": {
+        "map-visit": "^1.0.0",
+        "object-visit": "^1.0.0"
+      }
+    },
+    "color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "requires": {
+        "color-name": "1.1.3"
+      }
+    },
+    "color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+      "dev": true
+    },
+    "colors": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+      "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
+      "dev": true
+    },
+    "combined-stream": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
+      "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
+      "dev": true,
+      "requires": {
+        "delayed-stream": "~1.0.0"
+      }
+    },
+    "component-emitter": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+      "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+      "dev": true
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "concat-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.2.2",
+        "typedarray": "^0.0.6"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "2.3.6",
+          "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "console-browserify": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+      "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
+      "dev": true,
+      "requires": {
+        "date-now": "^0.1.4"
+      }
+    },
+    "copy-descriptor": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+      "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+      "dev": true
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
+    },
+    "cross-spawn": {
+      "version": "6.0.5",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+      "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+      "dev": true,
+      "requires": {
+        "nice-try": "^1.0.4",
+        "path-key": "^2.0.1",
+        "semver": "^5.5.0",
+        "shebang-command": "^1.2.0",
+        "which": "^1.2.9"
+      }
+    },
+    "currently-unhandled": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+      "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
+      "dev": true,
+      "requires": {
+        "array-find-index": "^1.0.1"
+      }
+    },
+    "cycle": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",
+      "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=",
+      "dev": true,
+      "optional": true
+    },
+    "dashdash": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "assert-plus": "^1.0.0"
+      }
+    },
+    "date-now": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+      "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
+      "dev": true
+    },
+    "dateformat": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz",
+      "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=",
+      "dev": true,
+      "requires": {
+        "get-stdin": "^4.0.1",
+        "meow": "^3.3.0"
+      }
+    },
+    "debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "requires": {
+        "ms": "2.0.0"
+      }
+    },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+      "dev": true
+    },
+    "decode-uri-component": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+      "dev": true
+    },
+    "define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "requires": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "dependencies": {
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+      "dev": true
+    },
+    "detect-file": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+      "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
+      "dev": true
+    },
+    "dom-serializer": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
+      "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
+      "dev": true,
+      "requires": {
+        "domelementtype": "~1.1.1",
+        "entities": "~1.1.1"
+      },
+      "dependencies": {
+        "domelementtype": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
+          "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=",
+          "dev": true
+        },
+        "entities": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
+          "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=",
+          "dev": true
+        }
+      }
+    },
+    "domelementtype": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
+      "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=",
+      "dev": true
+    },
+    "domhandler": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz",
+      "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=",
+      "dev": true,
+      "requires": {
+        "domelementtype": "1"
+      }
+    },
+    "domutils": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
+      "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
+      "dev": true,
+      "requires": {
+        "dom-serializer": "0",
+        "domelementtype": "1"
+      }
+    },
+    "ecc-jsbn": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+      "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "jsbn": "~0.1.0",
+        "safer-buffer": "^2.1.0"
+      }
+    },
+    "entities": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz",
+      "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=",
+      "dev": true
+    },
+    "error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dev": true,
+      "requires": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "es6-promise": {
+      "version": "4.2.5",
+      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz",
+      "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==",
+      "dev": true
+    },
+    "es6-promisify": {
+      "version": "5.0.0",
+      "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+      "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
+      "dev": true,
+      "requires": {
+        "es6-promise": "^4.0.3"
+      }
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+    },
+    "esprima": {
+      "version": "2.7.3",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+      "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+      "dev": true
+    },
+    "eventemitter2": {
+      "version": "0.4.14",
+      "resolved": "http://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
+      "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=",
+      "dev": true
+    },
+    "exit": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+      "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
+      "dev": true
+    },
+    "expand-brackets": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+      "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+      "dev": true,
+      "requires": {
+        "debug": "^2.3.3",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "posix-character-classes": "^0.1.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "expand-tilde": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+      "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1"
+      }
+    },
+    "extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true
+    },
+    "extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+      "dev": true,
+      "requires": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        }
+      }
+    },
+    "extglob": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+      "dev": true,
+      "requires": {
+        "array-unique": "^0.3.2",
+        "define-property": "^1.0.0",
+        "expand-brackets": "^2.1.4",
+        "extend-shallow": "^2.0.1",
+        "fragment-cache": "^0.2.1",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "extract-zip": {
+      "version": "1.6.7",
+      "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz",
+      "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=",
+      "dev": true,
+      "requires": {
+        "concat-stream": "1.6.2",
+        "debug": "2.6.9",
+        "mkdirp": "0.5.1",
+        "yauzl": "2.4.1"
+      }
+    },
+    "extsprintf": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+      "dev": true
+    },
+    "eyes": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
+      "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=",
+      "dev": true,
+      "optional": true
+    },
+    "fast-deep-equal": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
+      "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
+      "dev": true,
+      "optional": true
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
+      "dev": true,
+      "optional": true
+    },
+    "fd-slicer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
+      "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
+      "dev": true,
+      "requires": {
+        "pend": "~1.2.0"
+      }
+    },
+    "figures": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+      "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+      "dev": true,
+      "requires": {
+        "escape-string-regexp": "^1.0.5",
+        "object-assign": "^4.1.0"
+      }
+    },
+    "fill-range": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+      "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^2.0.1",
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1",
+        "to-regex-range": "^2.1.0"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "find-up": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+      "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+      "dev": true,
+      "requires": {
+        "path-exists": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
+      }
+    },
+    "findup-sync": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz",
+      "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=",
+      "dev": true,
+      "requires": {
+        "glob": "~5.0.0"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "5.0.15",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+          "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+          "dev": true,
+          "requires": {
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "2 || 3",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        }
+      }
+    },
+    "fined": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.0.tgz",
+      "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.2",
+        "is-plain-object": "^2.0.3",
+        "object.defaults": "^1.1.0",
+        "object.pick": "^1.2.0",
+        "parse-filepath": "^1.0.1"
+      }
+    },
+    "flagged-respawn": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.0.tgz",
+      "integrity": "sha1-Tnmumy6zi/hrO7Vr8+ClaqX8q9c=",
+      "dev": true
+    },
+    "for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+      "dev": true
+    },
+    "for-own": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+      "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
+      "dev": true,
+      "requires": {
+        "for-in": "^1.0.1"
+      }
+    },
+    "forever-agent": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+      "dev": true,
+      "optional": true
+    },
+    "form-data": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+      "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.6",
+        "mime-types": "^2.1.12"
+      }
+    },
+    "fragment-cache": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+      "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+      "dev": true,
+      "requires": {
+        "map-cache": "^0.2.2"
+      }
+    },
+    "fs-extra": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz",
+      "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "jsonfile": "^2.1.0",
+        "klaw": "^1.0.0"
+      },
+      "dependencies": {
+        "klaw": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
+          "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "graceful-fs": "^4.1.9"
+          }
+        }
+      }
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "get-stdin": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+      "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
+      "dev": true
+    },
+    "get-value": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+      "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+      "dev": true
+    },
+    "getobject": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz",
+      "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=",
+      "dev": true
+    },
+    "getpass": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+      "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "assert-plus": "^1.0.0"
+      }
+    },
+    "glob": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
+      "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
+      "dev": true,
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.2",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "global-modules": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+      "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+      "dev": true,
+      "requires": {
+        "global-prefix": "^1.0.1",
+        "is-windows": "^1.0.1",
+        "resolve-dir": "^1.0.0"
+      }
+    },
+    "global-prefix": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+      "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.2",
+        "homedir-polyfill": "^1.0.1",
+        "ini": "^1.3.4",
+        "is-windows": "^1.0.1",
+        "which": "^1.2.14"
+      }
+    },
+    "graceful-fs": {
+      "version": "4.1.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+      "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
+    },
+    "grunt": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.3.tgz",
+      "integrity": "sha512-/JzmZNPfKorlCrrmxWqQO4JVodO+DVd5XX4DkocL/1WlLlKVLE9+SdEIempOAxDhWPysLle6afvn/hg7Ck2k9g==",
+      "dev": true,
+      "requires": {
+        "coffeescript": "~1.10.0",
+        "dateformat": "~1.0.12",
+        "eventemitter2": "~0.4.13",
+        "exit": "~0.1.1",
+        "findup-sync": "~0.3.0",
+        "glob": "~7.0.0",
+        "grunt-cli": "~1.2.0",
+        "grunt-known-options": "~1.1.0",
+        "grunt-legacy-log": "~2.0.0",
+        "grunt-legacy-util": "~1.1.1",
+        "iconv-lite": "~0.4.13",
+        "js-yaml": "~3.5.2",
+        "minimatch": "~3.0.2",
+        "mkdirp": "~0.5.1",
+        "nopt": "~3.0.6",
+        "path-is-absolute": "~1.0.0",
+        "rimraf": "~2.6.2"
+      },
+      "dependencies": {
+        "grunt-cli": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz",
+          "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=",
+          "dev": true,
+          "requires": {
+            "findup-sync": "~0.3.0",
+            "grunt-known-options": "~1.1.0",
+            "nopt": "~3.0.6",
+            "resolve": "~1.1.0"
+          }
+        },
+        "nopt": {
+          "version": "3.0.6",
+          "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+          "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+          "dev": true,
+          "requires": {
+            "abbrev": "1"
+          }
+        }
+      }
+    },
+    "grunt-cli": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.3.1.tgz",
+      "integrity": "sha512-UwBRu/QpAjDc53DRLEkyilFdL0zenpxu+fddTIlsF/KJqdNcHaQmvyu1W3cDesZ9rqqZdKK5A8+QDIyLUEWoZQ==",
+      "dev": true,
+      "requires": {
+        "grunt-known-options": "~1.1.0",
+        "interpret": "~1.1.0",
+        "liftoff": "~2.5.0",
+        "nopt": "~4.0.1",
+        "v8flags": "~3.0.2"
+      }
+    },
+    "grunt-contrib-concat": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-1.0.1.tgz",
+      "integrity": "sha1-YVCYYwhOhx1+ht5IwBUlntl3Rb0=",
+      "dev": true,
+      "requires": {
+        "chalk": "^1.0.0",
+        "source-map": "^0.5.3"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+          "dev": true
+        }
+      }
+    },
+    "grunt-contrib-jshint": {
+      "version": "1.1.0",
+      "resolved": "http://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-1.1.0.tgz",
+      "integrity": "sha1-Np2QmyWTxA6L55lAshNAhQx5Oaw=",
+      "dev": true,
+      "requires": {
+        "chalk": "^1.1.1",
+        "hooker": "^0.2.3",
+        "jshint": "~2.9.4"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+          "dev": true
+        }
+      }
+    },
+    "grunt-contrib-qunit": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/grunt-contrib-qunit/-/grunt-contrib-qunit-3.0.1.tgz",
+      "integrity": "sha512-s994+ipKwc+oUUIWaGIw1soyID4pExSGMd/cHQN5h0p8KbIjR1Le3ZC3giSDDKXtZFE0i+Obf0uIjNvjftX2Cw==",
+      "dev": true,
+      "requires": {
+        "eventemitter2": "^5.0.1",
+        "p-each-series": "^1.0.0",
+        "puppeteer": "1.7.0"
+      },
+      "dependencies": {
+        "eventemitter2": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz",
+          "integrity": "sha1-YZegldX7a1folC9v1+qtY6CclFI=",
+          "dev": true
+        }
+      }
+    },
+    "grunt-contrib-uglify": {
+      "version": "1.0.2",
+      "resolved": "http://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-1.0.2.tgz",
+      "integrity": "sha1-rmekb5FT7dTLEYE6Vetpxw19svs=",
+      "dev": true,
+      "requires": {
+        "chalk": "^1.0.0",
+        "lodash": "^4.0.1",
+        "maxmin": "^1.1.0",
+        "uglify-js": "~2.6.2",
+        "uri-path": "^1.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+          "dev": true
+        }
+      }
+    },
+    "grunt-jsdoc": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/grunt-jsdoc/-/grunt-jsdoc-2.3.0.tgz",
+      "integrity": "sha512-gC66TCRXeQMj3HIyqVSBJm8zdUz43e5vaG/PLO/627A1edbJnzxhJV7nF0KqLwMM0RDNu1istC6fvfnYqFKi3w==",
+      "dev": true,
+      "requires": {
+        "cross-spawn": "^6.0.5",
+        "jsdoc": "~3.5.5",
+        "marked": "^0.5.0"
+      },
+      "dependencies": {
+        "marked": {
+          "version": "0.5.1",
+          "resolved": "https://registry.npmjs.org/marked/-/marked-0.5.1.tgz",
+          "integrity": "sha512-iUkBZegCZou4AdwbKTwSW/lNDcz5OuRSl3qdcl31Ia0B2QPG0Jn+tKblh/9/eP9/6+4h27vpoh8wel/vQOV0vw==",
+          "dev": true
+        }
+      }
+    },
+    "grunt-known-options": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz",
+      "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==",
+      "dev": true
+    },
+    "grunt-legacy-log": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-2.0.0.tgz",
+      "integrity": "sha512-1m3+5QvDYfR1ltr8hjiaiNjddxGdQWcH0rw1iKKiQnF0+xtgTazirSTGu68RchPyh1OBng1bBUjLmX8q9NpoCw==",
+      "dev": true,
+      "requires": {
+        "colors": "~1.1.2",
+        "grunt-legacy-log-utils": "~2.0.0",
+        "hooker": "~0.2.3",
+        "lodash": "~4.17.5"
+      }
+    },
+    "grunt-legacy-log-utils": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.0.1.tgz",
+      "integrity": "sha512-o7uHyO/J+i2tXG8r2bZNlVk20vlIFJ9IEYyHMCQGfWYru8Jv3wTqKZzvV30YW9rWEjq0eP3cflQ1qWojIe9VFA==",
+      "dev": true,
+      "requires": {
+        "chalk": "~2.4.1",
+        "lodash": "~4.17.10"
+      }
+    },
+    "grunt-legacy-util": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.1.1.tgz",
+      "integrity": "sha512-9zyA29w/fBe6BIfjGENndwoe1Uy31BIXxTH3s8mga0Z5Bz2Sp4UCjkeyv2tI449ymkx3x26B+46FV4fXEddl5A==",
+      "dev": true,
+      "requires": {
+        "async": "~1.5.2",
+        "exit": "~0.1.1",
+        "getobject": "~0.1.0",
+        "hooker": "~0.2.3",
+        "lodash": "~4.17.10",
+        "underscore.string": "~3.3.4",
+        "which": "~1.3.0"
+      }
+    },
+    "grunt-shell-spawn": {
+      "version": "0.3.10",
+      "resolved": "https://registry.npmjs.org/grunt-shell-spawn/-/grunt-shell-spawn-0.3.10.tgz",
+      "integrity": "sha1-gbuNRX7EfTGCqH1jCO+EXd+5SI8=",
+      "dev": true,
+      "requires": {
+        "grunt": ">=0.4.x",
+        "sync-exec": "~0.6.2"
+      }
+    },
+    "gzip-size": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-1.0.0.tgz",
+      "integrity": "sha1-Zs+LEBBHInuVus5uodoMF37Vwi8=",
+      "dev": true,
+      "requires": {
+        "browserify-zlib": "^0.1.4",
+        "concat-stream": "^1.4.1"
+      }
+    },
+    "har-schema": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+      "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+      "dev": true,
+      "optional": true
+    },
+    "har-validator": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz",
+      "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "ajv": "^5.3.0",
+        "har-schema": "^2.0.0"
+      }
+    },
+    "has-ansi": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "^2.0.0"
+      }
+    },
+    "has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+      "dev": true
+    },
+    "has-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+      "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+      "dev": true,
+      "requires": {
+        "get-value": "^2.0.6",
+        "has-values": "^1.0.0",
+        "isobject": "^3.0.0"
+      }
+    },
+    "has-values": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+      "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+      "dev": true,
+      "requires": {
+        "is-number": "^3.0.0",
+        "kind-of": "^4.0.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+          "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "hasha": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz",
+      "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "is-stream": "^1.0.1",
+        "pinkie-promise": "^2.0.0"
+      }
+    },
+    "homedir-polyfill": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz",
+      "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=",
+      "dev": true,
+      "requires": {
+        "parse-passwd": "^1.0.0"
+      }
+    },
+    "hooker": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
+      "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=",
+      "dev": true
+    },
+    "hosted-git-info": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
+      "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==",
+      "dev": true
+    },
+    "htmlparser2": {
+      "version": "3.8.3",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
+      "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=",
+      "dev": true,
+      "requires": {
+        "domelementtype": "1",
+        "domhandler": "2.3",
+        "domutils": "1.5",
+        "entities": "1.0",
+        "readable-stream": "1.1"
+      }
+    },
+    "http-signature": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+      "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "assert-plus": "^1.0.0",
+        "jsprim": "^1.2.2",
+        "sshpk": "^1.7.0"
+      }
+    },
+    "https-proxy-agent": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
+      "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==",
+      "dev": true,
+      "requires": {
+        "agent-base": "^4.1.0",
+        "debug": "^3.1.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.2.6",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "ms": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+          "dev": true
+        }
+      }
+    },
+    "iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "dev": true,
+      "requires": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      }
+    },
+    "indent-string": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+      "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
+      "dev": true,
+      "requires": {
+        "repeating": "^2.0.0"
+      }
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+      "dev": true
+    },
+    "ini": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+      "dev": true
+    },
+    "interpret": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
+      "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=",
+      "dev": true
+    },
+    "is-absolute": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+      "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
+      "dev": true,
+      "requires": {
+        "is-relative": "^1.0.0",
+        "is-windows": "^1.0.1"
+      }
+    },
+    "is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+      "dev": true
+    },
+    "is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true
+    },
+    "is-builtin-module": {
+      "version": "1.0.0",
+      "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
+      "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
+      "dev": true,
+      "requires": {
+        "builtin-modules": "^1.0.0"
+      }
+    },
+    "is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "requires": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+          "dev": true
+        }
+      }
+    },
+    "is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+      "dev": true
+    },
+    "is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+      "dev": true
+    },
+    "is-finite": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
+      "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
+      "dev": true,
+      "requires": {
+        "number-is-nan": "^1.0.0"
+      }
+    },
+    "is-glob": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+      "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+      "dev": true,
+      "requires": {
+        "is-extglob": "^2.1.0"
+      }
+    },
+    "is-number": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+      "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
+    "is-relative": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+      "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
+      "dev": true,
+      "requires": {
+        "is-unc-path": "^1.0.0"
+      }
+    },
+    "is-stream": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+      "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
+      "dev": true,
+      "optional": true
+    },
+    "is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+      "dev": true,
+      "optional": true
+    },
+    "is-unc-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+      "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
+      "dev": true,
+      "requires": {
+        "unc-path-regex": "^0.1.2"
+      }
+    },
+    "is-utf8": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+      "dev": true
+    },
+    "is-windows": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+      "dev": true
+    },
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+      "dev": true
+    },
+    "isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true
+    },
+    "isstream": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+      "dev": true
+    },
+    "js-yaml": {
+      "version": "3.5.5",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz",
+      "integrity": "sha1-A3fDgBfKvHMisNH7zSWkkWQfL74=",
+      "dev": true,
+      "requires": {
+        "argparse": "^1.0.2",
+        "esprima": "^2.6.0"
+      }
+    },
+    "js2xmlparser": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz",
+      "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=",
+      "requires": {
+        "xmlcreate": "^1.0.1"
+      }
+    },
+    "jsbn": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+      "dev": true
+    },
+    "jsdoc": {
+      "version": "3.5.5",
+      "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz",
+      "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==",
+      "requires": {
+        "babylon": "7.0.0-beta.19",
+        "bluebird": "~3.5.0",
+        "catharsis": "~0.8.9",
+        "escape-string-regexp": "~1.0.5",
+        "js2xmlparser": "~3.0.0",
+        "klaw": "~2.0.0",
+        "marked": "~0.3.6",
+        "mkdirp": "~0.5.1",
+        "requizzle": "~0.2.1",
+        "strip-json-comments": "~2.0.1",
+        "taffydb": "2.6.2",
+        "underscore": "~1.8.3"
+      }
+    },
+    "jshint": {
+      "version": "2.9.6",
+      "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.6.tgz",
+      "integrity": "sha512-KO9SIAKTlJQOM4lE64GQUtGBRpTOuvbrRrSZw3AhUxMNG266nX9hK2cKA4SBhXOj0irJGyNyGSLT62HGOVDEOA==",
+      "dev": true,
+      "requires": {
+        "cli": "~1.0.0",
+        "console-browserify": "1.1.x",
+        "exit": "0.1.x",
+        "htmlparser2": "3.8.x",
+        "lodash": "~4.17.10",
+        "minimatch": "~3.0.2",
+        "phantom": "~4.0.1",
+        "phantomjs-prebuilt": "~2.1.7",
+        "shelljs": "0.3.x",
+        "strip-json-comments": "1.0.x",
+        "unicode-5.2.0": "^0.7.5"
+      },
+      "dependencies": {
+        "strip-json-comments": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
+          "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=",
+          "dev": true
+        }
+      }
+    },
+    "jslint": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/jslint/-/jslint-0.12.0.tgz",
+      "integrity": "sha512-RoCsyICcKA+6TFsbys9DpKTfPVaC71Mm5QSjvrWA0lDVN+LIvx6apa42FFisMqmCTvJ8DxkcoQGJ0j7m3kTVow==",
+      "dev": true,
+      "requires": {
+        "exit": "~0.1.2",
+        "glob": "~7.1.2",
+        "nopt": "~3.0.1",
+        "readable-stream": "~2.1.5"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.1.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+          "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.0.4",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "nopt": {
+          "version": "3.0.6",
+          "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+          "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+          "dev": true,
+          "requires": {
+            "abbrev": "1"
+          }
+        },
+        "process-nextick-args": {
+          "version": "1.0.7",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+          "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.1.5",
+          "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz",
+          "integrity": "sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA=",
+          "dev": true,
+          "requires": {
+            "buffer-shims": "^1.0.0",
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.1",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~1.0.6",
+            "string_decoder": "~0.10.x",
+            "util-deprecate": "~1.0.1"
+          }
+        }
+      }
+    },
+    "json-schema": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+      "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+      "dev": true,
+      "optional": true
+    },
+    "json-schema-traverse": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
+      "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
+      "dev": true,
+      "optional": true
+    },
+    "json-stringify-safe": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+      "dev": true,
+      "optional": true
+    },
+    "jsonfile": {
+      "version": "2.4.0",
+      "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
+      "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "jsprim": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+      "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "assert-plus": "1.0.0",
+        "extsprintf": "1.3.0",
+        "json-schema": "0.2.3",
+        "verror": "1.10.0"
+      }
+    },
+    "kew": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz",
+      "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=",
+      "dev": true,
+      "optional": true
+    },
+    "kind-of": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+      "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+      "dev": true
+    },
+    "klaw": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz",
+      "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=",
+      "requires": {
+        "graceful-fs": "^4.1.9"
+      }
+    },
+    "lazy-cache": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
+      "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
+      "dev": true
+    },
+    "liftoff": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz",
+      "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=",
+      "dev": true,
+      "requires": {
+        "extend": "^3.0.0",
+        "findup-sync": "^2.0.0",
+        "fined": "^1.0.1",
+        "flagged-respawn": "^1.0.0",
+        "is-plain-object": "^2.0.4",
+        "object.map": "^1.0.0",
+        "rechoir": "^0.6.2",
+        "resolve": "^1.1.7"
+      },
+      "dependencies": {
+        "findup-sync": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
+          "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
+          "dev": true,
+          "requires": {
+            "detect-file": "^1.0.0",
+            "is-glob": "^3.1.0",
+            "micromatch": "^3.0.4",
+            "resolve-dir": "^1.0.1"
+          }
+        }
+      }
+    },
+    "load-json-file": {
+      "version": "1.1.0",
+      "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+      "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "parse-json": "^2.2.0",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0",
+        "strip-bom": "^2.0.0"
+      }
+    },
+    "lodash": {
+      "version": "4.17.11",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+      "dev": true
+    },
+    "longest": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
+      "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
+      "dev": true
+    },
+    "loud-rejection": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
+      "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
+      "dev": true,
+      "requires": {
+        "currently-unhandled": "^0.4.1",
+        "signal-exit": "^3.0.0"
+      }
+    },
+    "make-iterator": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
+      "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^6.0.2"
+      }
+    },
+    "map-cache": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+      "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+      "dev": true
+    },
+    "map-obj": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+      "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+      "dev": true
+    },
+    "map-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+      "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+      "dev": true,
+      "requires": {
+        "object-visit": "^1.0.0"
+      }
+    },
+    "marked": {
+      "version": "0.3.19",
+      "resolved": "http://registry.npmjs.org/marked/-/marked-0.3.19.tgz",
+      "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg=="
+    },
+    "maxmin": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz",
+      "integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=",
+      "dev": true,
+      "requires": {
+        "chalk": "^1.0.0",
+        "figures": "^1.0.1",
+        "gzip-size": "^1.0.0",
+        "pretty-bytes": "^1.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+          "dev": true
+        }
+      }
+    },
+    "meow": {
+      "version": "3.7.0",
+      "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+      "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
+      "dev": true,
+      "requires": {
+        "camelcase-keys": "^2.0.0",
+        "decamelize": "^1.1.2",
+        "loud-rejection": "^1.0.0",
+        "map-obj": "^1.0.1",
+        "minimist": "^1.1.3",
+        "normalize-package-data": "^2.3.4",
+        "object-assign": "^4.0.1",
+        "read-pkg-up": "^1.0.1",
+        "redent": "^1.0.0",
+        "trim-newlines": "^1.0.0"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "dev": true
+        }
+      }
+    },
+    "micromatch": {
+      "version": "3.1.10",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+      "dev": true,
+      "requires": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "braces": "^2.3.1",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "extglob": "^2.0.4",
+        "fragment-cache": "^0.2.1",
+        "kind-of": "^6.0.2",
+        "nanomatch": "^1.2.9",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.2"
+      }
+    },
+    "mime": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz",
+      "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==",
+      "dev": true
+    },
+    "mime-db": {
+      "version": "1.37.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz",
+      "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==",
+      "dev": true
+    },
+    "mime-types": {
+      "version": "2.1.21",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz",
+      "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==",
+      "dev": true,
+      "requires": {
+        "mime-db": "~1.37.0"
+      }
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "minimist": {
+      "version": "0.0.8",
+      "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+    },
+    "mixin-deep": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
+      "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
+      "dev": true,
+      "requires": {
+        "for-in": "^1.0.2",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        }
+      }
+    },
+    "mkdirp": {
+      "version": "0.5.1",
+      "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "requires": {
+        "minimist": "0.0.8"
+      }
+    },
+    "ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "nanomatch": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+      "dev": true,
+      "requires": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "fragment-cache": "^0.2.1",
+        "is-windows": "^1.0.2",
+        "kind-of": "^6.0.2",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      }
+    },
+    "nice-try": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+      "dev": true
+    },
+    "nopt": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
+      "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
+      "requires": {
+        "abbrev": "1",
+        "osenv": "^0.1.4"
+      }
+    },
+    "normalize-package-data": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+      "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
+      "dev": true,
+      "requires": {
+        "hosted-git-info": "^2.1.4",
+        "is-builtin-module": "^1.0.0",
+        "semver": "2 || 3 || 4 || 5",
+        "validate-npm-package-license": "^3.0.1"
+      }
+    },
+    "number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+      "dev": true
+    },
+    "oauth-sign": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+      "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+      "dev": true,
+      "optional": true
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+      "dev": true
+    },
+    "object-copy": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+      "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+      "dev": true,
+      "requires": {
+        "copy-descriptor": "^0.1.0",
+        "define-property": "^0.2.5",
+        "kind-of": "^3.0.3"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "object-visit": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+      "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.0"
+      }
+    },
+    "object.defaults": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
+      "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=",
+      "dev": true,
+      "requires": {
+        "array-each": "^1.0.1",
+        "array-slice": "^1.0.0",
+        "for-own": "^1.0.0",
+        "isobject": "^3.0.0"
+      }
+    },
+    "object.map": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
+      "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=",
+      "dev": true,
+      "requires": {
+        "for-own": "^1.0.0",
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "object.pick": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+      "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true,
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "os-homedir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+    },
+    "osenv": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+      "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+      "requires": {
+        "os-homedir": "^1.0.0",
+        "os-tmpdir": "^1.0.0"
+      }
+    },
+    "p-each-series": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz",
+      "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=",
+      "dev": true,
+      "requires": {
+        "p-reduce": "^1.0.0"
+      }
+    },
+    "p-reduce": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz",
+      "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=",
+      "dev": true
+    },
+    "pako": {
+      "version": "0.2.9",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
+      "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=",
+      "dev": true
+    },
+    "parse-filepath": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
+      "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=",
+      "dev": true,
+      "requires": {
+        "is-absolute": "^1.0.0",
+        "map-cache": "^0.2.0",
+        "path-root": "^0.1.1"
+      }
+    },
+    "parse-json": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+      "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+      "dev": true,
+      "requires": {
+        "error-ex": "^1.2.0"
+      }
+    },
+    "parse-passwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+      "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+      "dev": true
+    },
+    "pascalcase": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+      "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+      "dev": true
+    },
+    "path-exists": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+      "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+      "dev": true,
+      "requires": {
+        "pinkie-promise": "^2.0.0"
+      }
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true
+    },
+    "path-key": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+      "dev": true
+    },
+    "path-root": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
+      "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=",
+      "dev": true,
+      "requires": {
+        "path-root-regex": "^0.1.0"
+      }
+    },
+    "path-root-regex": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
+      "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=",
+      "dev": true
+    },
+    "path-type": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+      "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
+      }
+    },
+    "pend": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+      "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+      "dev": true
+    },
+    "performance-now": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+      "dev": true,
+      "optional": true
+    },
+    "phantom": {
+      "version": "4.0.12",
+      "resolved": "https://registry.npmjs.org/phantom/-/phantom-4.0.12.tgz",
+      "integrity": "sha512-Tz82XhtPmwCk1FFPmecy7yRGZG2btpzY2KI9fcoPT7zT9det0CcMyfBFPp1S8DqzsnQnm8ZYEfdy528mwVtksA==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "phantomjs-prebuilt": "^2.1.16",
+        "split": "^1.0.1",
+        "winston": "^2.4.0"
+      }
+    },
+    "phantomjs-prebuilt": {
+      "version": "2.1.16",
+      "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz",
+      "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "es6-promise": "^4.0.3",
+        "extract-zip": "^1.6.5",
+        "fs-extra": "^1.0.0",
+        "hasha": "^2.2.0",
+        "kew": "^0.7.0",
+        "progress": "^1.1.8",
+        "request": "^2.81.0",
+        "request-progress": "^2.0.1",
+        "which": "^1.2.10"
+      }
+    },
+    "pify": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+      "dev": true
+    },
+    "pinkie": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+      "dev": true
+    },
+    "pinkie-promise": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "dev": true,
+      "requires": {
+        "pinkie": "^2.0.0"
+      }
+    },
+    "posix-character-classes": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+      "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+      "dev": true
+    },
+    "pretty-bytes": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz",
+      "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=",
+      "dev": true,
+      "requires": {
+        "get-stdin": "^4.0.1",
+        "meow": "^3.1.0"
+      }
+    },
+    "process-nextick-args": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+      "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+      "dev": true
+    },
+    "progress": {
+      "version": "1.1.8",
+      "resolved": "http://registry.npmjs.org/progress/-/progress-1.1.8.tgz",
+      "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=",
+      "dev": true,
+      "optional": true
+    },
+    "proxy-from-env": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
+      "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=",
+      "dev": true
+    },
+    "psl": {
+      "version": "1.1.29",
+      "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz",
+      "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==",
+      "dev": true,
+      "optional": true
+    },
+    "punycode": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+      "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+      "dev": true,
+      "optional": true
+    },
+    "puppeteer": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.7.0.tgz",
+      "integrity": "sha512-f+1DxKHPqce6CXUBz2eVO2WcATeVeQSOPG9GYaGObEZDCiCEUwG+gogjMsrvn7he2wHTqNVb5p6RUrwmr8XFBA==",
+      "dev": true,
+      "requires": {
+        "debug": "^3.1.0",
+        "extract-zip": "^1.6.6",
+        "https-proxy-agent": "^2.2.1",
+        "mime": "^2.0.3",
+        "progress": "^2.0.0",
+        "proxy-from-env": "^1.0.0",
+        "rimraf": "^2.6.1",
+        "ws": "^5.1.1"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.2.6",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "ms": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+          "dev": true
+        },
+        "progress": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz",
+          "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==",
+          "dev": true
+        }
+      }
+    },
+    "qs": {
+      "version": "6.5.2",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+      "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+      "dev": true,
+      "optional": true
+    },
+    "read-pkg": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+      "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+      "dev": true,
+      "requires": {
+        "load-json-file": "^1.0.0",
+        "normalize-package-data": "^2.3.2",
+        "path-type": "^1.0.0"
+      }
+    },
+    "read-pkg-up": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+      "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+      "dev": true,
+      "requires": {
+        "find-up": "^1.0.0",
+        "read-pkg": "^1.0.0"
+      }
+    },
+    "readable-stream": {
+      "version": "1.1.14",
+      "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+      "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+      "dev": true,
+      "requires": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.1",
+        "isarray": "0.0.1",
+        "string_decoder": "~0.10.x"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+          "dev": true
+        }
+      }
+    },
+    "rechoir": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+      "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+      "dev": true,
+      "requires": {
+        "resolve": "^1.1.6"
+      }
+    },
+    "redent": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
+      "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
+      "dev": true,
+      "requires": {
+        "indent-string": "^2.1.0",
+        "strip-indent": "^1.0.1"
+      }
+    },
+    "regex-not": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^3.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
+    "repeat-element": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+      "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+      "dev": true
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+      "dev": true
+    },
+    "repeating": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+      "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+      "dev": true,
+      "requires": {
+        "is-finite": "^1.0.0"
+      }
+    },
+    "request": {
+      "version": "2.88.0",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
+      "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "aws-sign2": "~0.7.0",
+        "aws4": "^1.8.0",
+        "caseless": "~0.12.0",
+        "combined-stream": "~1.0.6",
+        "extend": "~3.0.2",
+        "forever-agent": "~0.6.1",
+        "form-data": "~2.3.2",
+        "har-validator": "~5.1.0",
+        "http-signature": "~1.2.0",
+        "is-typedarray": "~1.0.0",
+        "isstream": "~0.1.2",
+        "json-stringify-safe": "~5.0.1",
+        "mime-types": "~2.1.19",
+        "oauth-sign": "~0.9.0",
+        "performance-now": "^2.1.0",
+        "qs": "~6.5.2",
+        "safe-buffer": "^5.1.2",
+        "tough-cookie": "~2.4.3",
+        "tunnel-agent": "^0.6.0",
+        "uuid": "^3.3.2"
+      }
+    },
+    "request-progress": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz",
+      "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "throttleit": "^1.0.0"
+      }
+    },
+    "requizzle": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz",
+      "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=",
+      "requires": {
+        "underscore": "~1.6.0"
+      },
+      "dependencies": {
+        "underscore": {
+          "version": "1.6.0",
+          "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
+          "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag="
+        }
+      }
+    },
+    "resolve": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+      "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
+      "dev": true
+    },
+    "resolve-dir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+      "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.0",
+        "global-modules": "^1.0.0"
+      }
+    },
+    "resolve-url": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+      "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+      "dev": true
+    },
+    "ret": {
+      "version": "0.1.15",
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+      "dev": true
+    },
+    "right-align": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
+      "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
+      "dev": true,
+      "requires": {
+        "align-text": "^0.1.1"
+      }
+    },
+    "rimraf": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+      "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+      "dev": true,
+      "requires": {
+        "glob": "^7.0.5"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
+    },
+    "safe-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+      "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+      "dev": true,
+      "requires": {
+        "ret": "~0.1.10"
+      }
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
+    },
+    "semver": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+      "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
+      "dev": true
+    },
+    "set-value": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
+      "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^2.0.1",
+        "is-extendable": "^0.1.1",
+        "is-plain-object": "^2.0.3",
+        "split-string": "^3.0.1"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "shebang-command": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "dev": true,
+      "requires": {
+        "shebang-regex": "^1.0.0"
+      }
+    },
+    "shebang-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+      "dev": true
+    },
+    "shelljs": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
+      "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=",
+      "dev": true
+    },
+    "signal-exit": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+      "dev": true
+    },
+    "snapdragon": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+      "dev": true,
+      "requires": {
+        "base": "^0.11.1",
+        "debug": "^2.2.0",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "map-cache": "^0.2.2",
+        "source-map": "^0.5.6",
+        "source-map-resolve": "^0.5.0",
+        "use": "^3.1.0"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "snapdragon-node": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+      "dev": true,
+      "requires": {
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.0",
+        "snapdragon-util": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "snapdragon-util": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.2.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "source-map": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+      "dev": true
+    },
+    "source-map-resolve": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
+      "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
+      "dev": true,
+      "requires": {
+        "atob": "^2.1.1",
+        "decode-uri-component": "^0.2.0",
+        "resolve-url": "^0.2.1",
+        "source-map-url": "^0.4.0",
+        "urix": "^0.1.0"
+      }
+    },
+    "source-map-url": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+      "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
+      "dev": true
+    },
+    "spdx-correct": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz",
+      "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==",
+      "dev": true,
+      "requires": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-exceptions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+      "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+      "dev": true
+    },
+    "spdx-expression-parse": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+      "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+      "dev": true,
+      "requires": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-license-ids": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz",
+      "integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==",
+      "dev": true
+    },
+    "split": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
+      "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "through": "2"
+      }
+    },
+    "split-string": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^3.0.0"
+      }
+    },
+    "sprintf-js": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz",
+      "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw=",
+      "dev": true
+    },
+    "sshpk": {
+      "version": "1.15.1",
+      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.1.tgz",
+      "integrity": "sha512-mSdgNUaidk+dRU5MhYtN9zebdzF2iG0cNPWy8HG+W8y+fT1JnSkh0fzzpjOa0L7P8i1Rscz38t0h4gPcKz43xA==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "asn1": "~0.2.3",
+        "assert-plus": "^1.0.0",
+        "bcrypt-pbkdf": "^1.0.0",
+        "dashdash": "^1.12.0",
+        "ecc-jsbn": "~0.1.1",
+        "getpass": "^0.1.1",
+        "jsbn": "~0.1.0",
+        "safer-buffer": "^2.0.2",
+        "tweetnacl": "~0.14.0"
+      }
+    },
+    "stack-trace": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+      "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=",
+      "dev": true,
+      "optional": true
+    },
+    "static-extend": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+      "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+      "dev": true,
+      "requires": {
+        "define-property": "^0.2.5",
+        "object-copy": "^0.1.0"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        }
+      }
+    },
+    "string_decoder": {
+      "version": "0.10.31",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+      "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+      "dev": true
+    },
+    "strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "^2.0.0"
+      }
+    },
+    "strip-bom": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+      "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+      "dev": true,
+      "requires": {
+        "is-utf8": "^0.2.0"
+      }
+    },
+    "strip-indent": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
+      "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
+      "dev": true,
+      "requires": {
+        "get-stdin": "^4.0.1"
+      }
+    },
+    "strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+    },
+    "supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "requires": {
+        "has-flag": "^3.0.0"
+      }
+    },
+    "sync-exec": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/sync-exec/-/sync-exec-0.6.2.tgz",
+      "integrity": "sha1-cX0izFPwzh3vVZQ2LzqJouu5EQU=",
+      "dev": true
+    },
+    "taffydb": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz",
+      "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg="
+    },
+    "throttleit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz",
+      "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=",
+      "dev": true,
+      "optional": true
+    },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+      "dev": true,
+      "optional": true
+    },
+    "to-object-path": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+      "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "to-regex": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+      "dev": true,
+      "requires": {
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "regex-not": "^1.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
+    "to-regex-range": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+      "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+      "dev": true,
+      "requires": {
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1"
+      }
+    },
+    "tough-cookie": {
+      "version": "2.4.3",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+      "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "psl": "^1.1.24",
+        "punycode": "^1.4.1"
+      }
+    },
+    "trim-newlines": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
+      "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
+      "dev": true
+    },
+    "tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "tweetnacl": {
+      "version": "0.14.5",
+      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+      "dev": true
+    },
+    "typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+      "dev": true
+    },
+    "uglify-js": {
+      "version": "2.6.4",
+      "resolved": "http://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz",
+      "integrity": "sha1-ZeovswWck5RpLxX+2HwrNsFrmt8=",
+      "dev": true,
+      "requires": {
+        "async": "~0.2.6",
+        "source-map": "~0.5.1",
+        "uglify-to-browserify": "~1.0.0",
+        "yargs": "~3.10.0"
+      },
+      "dependencies": {
+        "async": {
+          "version": "0.2.10",
+          "resolved": "http://registry.npmjs.org/async/-/async-0.2.10.tgz",
+          "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
+          "dev": true
+        }
+      }
+    },
+    "uglify-to-browserify": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+      "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
+      "dev": true
+    },
+    "unc-path-regex": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
+      "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
+      "dev": true
+    },
+    "underscore": {
+      "version": "1.8.3",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
+      "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
+    },
+    "underscore-contrib": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz",
+      "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=",
+      "requires": {
+        "underscore": "1.6.0"
+      },
+      "dependencies": {
+        "underscore": {
+          "version": "1.6.0",
+          "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
+          "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag="
+        }
+      }
+    },
+    "underscore.string": {
+      "version": "3.3.5",
+      "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz",
+      "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==",
+      "dev": true,
+      "requires": {
+        "sprintf-js": "^1.0.3",
+        "util-deprecate": "^1.0.2"
+      }
+    },
+    "unicode-5.2.0": {
+      "version": "0.7.5",
+      "resolved": "https://registry.npmjs.org/unicode-5.2.0/-/unicode-5.2.0-0.7.5.tgz",
+      "integrity": "sha512-KVGLW1Bri30x00yv4HNM8kBxoqFXr0Sbo55735nvrlsx4PYBZol3UtoWgO492fSwmsetzPEZzy73rbU8OGXJcA==",
+      "dev": true
+    },
+    "union-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
+      "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+      "dev": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "get-value": "^2.0.6",
+        "is-extendable": "^0.1.1",
+        "set-value": "^0.4.3"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "set-value": {
+          "version": "0.4.3",
+          "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
+          "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
+          "dev": true,
+          "requires": {
+            "extend-shallow": "^2.0.1",
+            "is-extendable": "^0.1.1",
+            "is-plain-object": "^2.0.1",
+            "to-object-path": "^0.3.0"
+          }
+        }
+      }
+    },
+    "unset-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+      "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+      "dev": true,
+      "requires": {
+        "has-value": "^0.3.1",
+        "isobject": "^3.0.0"
+      },
+      "dependencies": {
+        "has-value": {
+          "version": "0.3.1",
+          "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+          "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+          "dev": true,
+          "requires": {
+            "get-value": "^2.0.3",
+            "has-values": "^0.1.4",
+            "isobject": "^2.0.0"
+          },
+          "dependencies": {
+            "isobject": {
+              "version": "2.1.0",
+              "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+              "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+              "dev": true,
+              "requires": {
+                "isarray": "1.0.0"
+              }
+            }
+          }
+        },
+        "has-values": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+          "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+          "dev": true
+        }
+      }
+    },
+    "uri-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz",
+      "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=",
+      "dev": true
+    },
+    "urix": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+      "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+      "dev": true
+    },
+    "use": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+      "dev": true
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
+    "uuid": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+      "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
+      "dev": true,
+      "optional": true
+    },
+    "v8flags": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.2.tgz",
+      "integrity": "sha512-6sgSKoFw1UpUPd3cFdF7QGnrH6tDeBgW1F3v9gy8gLY0mlbiBXq8soy8aQpY6xeeCjH5K+JvC62Acp7gtl7wWA==",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1"
+      }
+    },
+    "validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "dev": true,
+      "requires": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
+    "verror": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+      "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "assert-plus": "^1.0.0",
+        "core-util-is": "1.0.2",
+        "extsprintf": "^1.2.0"
+      }
+    },
+    "which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "requires": {
+        "isexe": "^2.0.0"
+      }
+    },
+    "window-size": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
+      "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
+      "dev": true
+    },
+    "winston": {
+      "version": "2.4.4",
+      "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.4.tgz",
+      "integrity": "sha512-NBo2Pepn4hK4V01UfcWcDlmiVTs7VTB1h7bgnB0rgP146bYhMxX0ypCz3lBOfNxCO4Zuek7yeT+y/zM1OfMw4Q==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "async": "~1.0.0",
+        "colors": "1.0.x",
+        "cycle": "1.0.x",
+        "eyes": "0.1.x",
+        "isstream": "0.1.x",
+        "stack-trace": "0.0.x"
+      },
+      "dependencies": {
+        "async": {
+          "version": "1.0.0",
+          "resolved": "http://registry.npmjs.org/async/-/async-1.0.0.tgz",
+          "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=",
+          "dev": true,
+          "optional": true
+        },
+        "colors": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
+          "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "wordwrap": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
+      "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
+      "dev": true
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
+    },
+    "ws": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
+      "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
+      "dev": true,
+      "requires": {
+        "async-limiter": "~1.0.0"
+      }
+    },
+    "xmlcreate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz",
+      "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8="
+    },
+    "yargs": {
+      "version": "3.10.0",
+      "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+      "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
+      "dev": true,
+      "requires": {
+        "camelcase": "^1.0.2",
+        "cliui": "^2.1.0",
+        "decamelize": "^1.0.0",
+        "window-size": "0.1.0"
+      },
+      "dependencies": {
+        "camelcase": {
+          "version": "1.2.1",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
+          "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
+          "dev": true
+        }
+      }
+    },
+    "yauzl": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
+      "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
+      "dev": true,
+      "requires": {
+        "fd-slicer": "~1.0.1"
+      }
+    }
+  }
+}
diff --git a/lib/js/package.json b/lib/js/package.json
new file mode 100644
index 0000000..a59cdc4
--- /dev/null
+++ b/lib/js/package.json
@@ -0,0 +1,19 @@
+{
+  "name": "thrift",
+  "version": "1.0.0",
+  "devDependencies": {
+    "grunt": "^1.0.2",
+    "grunt-cli": "^1.2.0",
+    "grunt-contrib-concat": "^1.0.1",
+    "grunt-contrib-jshint": "^1.0.0",
+    "grunt-contrib-qunit": "^3.0.1",
+    "grunt-contrib-uglify": "^1.0.1",
+    "grunt-jsdoc": "^2.2.1",
+    "grunt-shell-spawn": "^0.3.10",
+    "jslint": "^0.12.0"
+  },
+  "dependencies": {
+    "jsdoc": "^3.5.5",
+    "nopt": "^4.0.1"
+  }
+}
diff --git a/lib/js/src/thrift.js b/lib/js/src/thrift.js
new file mode 100644
index 0000000..9bf8127
--- /dev/null
+++ b/lib/js/src/thrift.js
@@ -0,0 +1,1569 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*jshint evil:true*/
+
+/**
+ * The Thrift namespace houses the Apache Thrift JavaScript library
+ * elements providing JavaScript bindings for the Apache Thrift RPC
+ * system. End users will typically only directly make use of the
+ * Transport (TXHRTransport/TWebSocketTransport) and Protocol
+ * (TJSONPRotocol/TBinaryProtocol) constructors.
+ *
+ * Object methods beginning with a __ (e.g. __onOpen()) are internal
+ * and should not be called outside of the object's own methods.
+ *
+ * This library creates one global object: Thrift
+ * Code in this library must never create additional global identifiers,
+ * all features must be scoped within the Thrift namespace.
+ * @namespace
+ * @example
+ *     var transport = new Thrift.Transport('http://localhost:8585');
+ *     var protocol  = new Thrift.Protocol(transport);
+ *     var client = new MyThriftSvcClient(protocol);
+ *     var result = client.MyMethod();
+ */
+var Thrift = {
+    /**
+     * Thrift JavaScript library version.
+     * @readonly
+     * @const {string} Version
+     * @memberof Thrift
+     */
+    Version: '1.0.0',
+
+    /**
+     * Thrift IDL type string to Id mapping.
+     * @readonly
+     * @property {number}  STOP   - End of a set of fields.
+     * @property {number}  VOID   - No value (only legal for return types).
+     * @property {number}  BOOL   - True/False integer.
+     * @property {number}  BYTE   - Signed 8 bit integer.
+     * @property {number}  I08    - Signed 8 bit integer.
+     * @property {number}  DOUBLE - 64 bit IEEE 854 floating point.
+     * @property {number}  I16    - Signed 16 bit integer.
+     * @property {number}  I32    - Signed 32 bit integer.
+     * @property {number}  I64    - Signed 64 bit integer.
+     * @property {number}  STRING - Array of bytes representing a string of characters.
+     * @property {number}  UTF7   - Array of bytes representing a string of UTF7 encoded characters.
+     * @property {number}  STRUCT - A multifield type.
+     * @property {number}  MAP    - A collection type (map/associative-array/dictionary).
+     * @property {number}  SET    - A collection type (unordered and without repeated values).
+     * @property {number}  LIST   - A collection type (unordered).
+     * @property {number}  UTF8   - Array of bytes representing a string of UTF8 encoded characters.
+     * @property {number}  UTF16  - Array of bytes representing a string of UTF16 encoded characters.
+     */
+    Type: {
+        STOP: 0,
+        VOID: 1,
+        BOOL: 2,
+        BYTE: 3,
+        I08: 3,
+        DOUBLE: 4,
+        I16: 6,
+        I32: 8,
+        I64: 10,
+        STRING: 11,
+        UTF7: 11,
+        STRUCT: 12,
+        MAP: 13,
+        SET: 14,
+        LIST: 15,
+        UTF8: 16,
+        UTF16: 17
+    },
+
+    /**
+     * Thrift RPC message type string to Id mapping.
+     * @readonly
+     * @property {number}  CALL      - RPC call sent from client to server.
+     * @property {number}  REPLY     - RPC call normal response from server to client.
+     * @property {number}  EXCEPTION - RPC call exception response from server to client.
+     * @property {number}  ONEWAY    - Oneway RPC call from client to server with no response.
+     */
+    MessageType: {
+        CALL: 1,
+        REPLY: 2,
+        EXCEPTION: 3,
+        ONEWAY: 4
+    },
+
+    /**
+     * Utility function returning the count of an object's own properties.
+     * @param {object} obj - Object to test.
+     * @returns {number} number of object's own properties
+     */
+    objectLength: function(obj) {
+        var length = 0;
+        for (var k in obj) {
+            if (obj.hasOwnProperty(k)) {
+                length++;
+            }
+        }
+        return length;
+    },
+
+    /**
+     * Utility function to establish prototype inheritance.
+     * @see {@link http://javascript.crockford.com/prototypal.html|Prototypal Inheritance}
+     * @param {function} constructor - Contstructor function to set as derived.
+     * @param {function} superConstructor - Contstructor function to set as base.
+     * @param {string} [name] - Type name to set as name property in derived prototype.
+     */
+    inherits: function(constructor, superConstructor, name) {
+      function F() {}
+      F.prototype = superConstructor.prototype;
+      constructor.prototype = new F();
+      constructor.prototype.name = name || '';
+    }
+};
+
+/**
+ * Initializes a Thrift TException instance.
+ * @constructor
+ * @augments Error
+ * @param {string} message - The TException message (distinct from the Error message).
+ * @classdesc TException is the base class for all Thrift exceptions types.
+ */
+Thrift.TException = function(message) {
+    this.message = message;
+};
+Thrift.inherits(Thrift.TException, Error, 'TException');
+
+/**
+ * Returns the message set on the exception.
+ * @readonly
+ * @returns {string} exception message
+ */
+Thrift.TException.prototype.getMessage = function() {
+    return this.message;
+};
+
+/**
+ * Thrift Application Exception type string to Id mapping.
+ * @readonly
+ * @property {number}  UNKNOWN                 - Unknown/undefined.
+ * @property {number}  UNKNOWN_METHOD          - Client attempted to call a method unknown to the server.
+ * @property {number}  INVALID_MESSAGE_TYPE    - Client passed an unknown/unsupported MessageType.
+ * @property {number}  WRONG_METHOD_NAME       - Unused.
+ * @property {number}  BAD_SEQUENCE_ID         - Unused in Thrift RPC, used to flag proprietary sequence number errors.
+ * @property {number}  MISSING_RESULT          - Raised by a server processor if a handler fails to supply the required return result.
+ * @property {number}  INTERNAL_ERROR          - Something bad happened.
+ * @property {number}  PROTOCOL_ERROR          - The protocol layer failed to serialize or deserialize data.
+ * @property {number}  INVALID_TRANSFORM       - Unused.
+ * @property {number}  INVALID_PROTOCOL        - The protocol (or version) is not supported.
+ * @property {number}  UNSUPPORTED_CLIENT_TYPE - Unused.
+ */
+Thrift.TApplicationExceptionType = {
+    UNKNOWN: 0,
+    UNKNOWN_METHOD: 1,
+    INVALID_MESSAGE_TYPE: 2,
+    WRONG_METHOD_NAME: 3,
+    BAD_SEQUENCE_ID: 4,
+    MISSING_RESULT: 5,
+    INTERNAL_ERROR: 6,
+    PROTOCOL_ERROR: 7,
+    INVALID_TRANSFORM: 8,
+    INVALID_PROTOCOL: 9,
+    UNSUPPORTED_CLIENT_TYPE: 10
+};
+
+/**
+ * Initializes a Thrift TApplicationException instance.
+ * @constructor
+ * @augments Thrift.TException
+ * @param {string} message - The TApplicationException message (distinct from the Error message).
+ * @param {Thrift.TApplicationExceptionType} [code] - The TApplicationExceptionType code.
+ * @classdesc TApplicationException is the exception class used to propagate exceptions from an RPC server back to a calling client.
+*/
+Thrift.TApplicationException = function(message, code) {
+    this.message = message;
+    this.code = typeof code === 'number' ? code : 0;
+};
+Thrift.inherits(Thrift.TApplicationException, Thrift.TException, 'TApplicationException');
+
+/**
+ * Read a TApplicationException from the supplied protocol.
+ * @param {object} input - The input protocol to read from.
+ */
+Thrift.TApplicationException.prototype.read = function(input) {
+    while (1) {
+        var ret = input.readFieldBegin();
+
+        if (ret.ftype == Thrift.Type.STOP) {
+            break;
+        }
+
+        var fid = ret.fid;
+
+        switch (fid) {
+            case 1:
+                if (ret.ftype == Thrift.Type.STRING) {
+                    ret = input.readString();
+                    this.message = ret.value;
+                } else {
+                    ret = input.skip(ret.ftype);
+                }
+                break;
+            case 2:
+                if (ret.ftype == Thrift.Type.I32) {
+                    ret = input.readI32();
+                    this.code = ret.value;
+                } else {
+                    ret = input.skip(ret.ftype);
+                }
+                break;
+           default:
+                ret = input.skip(ret.ftype);
+                break;
+        }
+
+        input.readFieldEnd();
+    }
+
+    input.readStructEnd();
+};
+
+/**
+ * Wite a TApplicationException to the supplied protocol.
+ * @param {object} output - The output protocol to write to.
+ */
+Thrift.TApplicationException.prototype.write = function(output) {
+    output.writeStructBegin('TApplicationException');
+
+    if (this.message) {
+        output.writeFieldBegin('message', Thrift.Type.STRING, 1);
+        output.writeString(this.getMessage());
+        output.writeFieldEnd();
+    }
+
+    if (this.code) {
+        output.writeFieldBegin('type', Thrift.Type.I32, 2);
+        output.writeI32(this.code);
+        output.writeFieldEnd();
+    }
+
+    output.writeFieldStop();
+    output.writeStructEnd();
+};
+
+/**
+ * Returns the application exception code set on the exception.
+ * @readonly
+ * @returns {Thrift.TApplicationExceptionType} exception code
+ */
+Thrift.TApplicationException.prototype.getCode = function() {
+    return this.code;
+};
+
+Thrift.TProtocolExceptionType = {
+    UNKNOWN: 0,
+    INVALID_DATA: 1,
+    NEGATIVE_SIZE: 2,
+    SIZE_LIMIT: 3,
+    BAD_VERSION: 4,
+    NOT_IMPLEMENTED: 5,
+    DEPTH_LIMIT: 6
+};
+
+Thrift.TProtocolException = function TProtocolException(type, message) {
+    Error.call(this);
+    Error.captureStackTrace(this, this.constructor);
+    this.name = this.constructor.name;
+    this.type = type;
+    this.message = message;
+};
+Thrift.inherits(Thrift.TProtocolException, Thrift.TException, 'TProtocolException');
+
+/**
+ * Constructor Function for the XHR transport.
+ * If you do not specify a url then you must handle XHR operations on
+ * your own. This type can also be constructed using the Transport alias
+ * for backward compatibility.
+ * @constructor
+ * @param {string} [url] - The URL to connect to.
+ * @classdesc The Apache Thrift Transport layer performs byte level I/O
+ * between RPC clients and servers. The JavaScript TXHRTransport object
+ * uses Http[s]/XHR. Target servers must implement the http[s] transport
+ * (see: node.js example server_http.js).
+ * @example
+ *     var transport = new Thrift.TXHRTransport("http://localhost:8585");
+ */
+Thrift.Transport = Thrift.TXHRTransport = function(url, options) {
+    this.url = url;
+    this.wpos = 0;
+    this.rpos = 0;
+    this.useCORS = (options && options.useCORS);
+    this.customHeaders = options ? (options.customHeaders ? options.customHeaders : {}): {};
+    this.send_buf = '';
+    this.recv_buf = '';
+};
+
+Thrift.TXHRTransport.prototype = {
+    /**
+     * Gets the browser specific XmlHttpRequest Object.
+     * @returns {object} the browser XHR interface object
+     */
+    getXmlHttpRequestObject: function() {
+        try { return new XMLHttpRequest(); } catch (e1) { }
+        try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { }
+        try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { }
+
+        throw "Your browser doesn't support XHR.";
+    },
+
+    /**
+     * Sends the current XRH request if the transport was created with a URL
+     * and the async parameter is false. If the transport was not created with
+     * a URL, or the async parameter is True and no callback is provided, or
+     * the URL is an empty string, the current send buffer is returned.
+     * @param {object} async - If true the current send buffer is returned.
+     * @param {object} callback - Optional async completion callback
+     * @returns {undefined|string} Nothing or the current send buffer.
+     * @throws {string} If XHR fails.
+     */
+    flush: function(async, callback) {
+        var self = this;
+        if ((async && !callback) || this.url === undefined || this.url === '') {
+            return this.send_buf;
+        }
+
+        var xreq = this.getXmlHttpRequestObject();
+
+        if (xreq.overrideMimeType) {
+            xreq.overrideMimeType('application/vnd.apache.thrift.json; charset=utf-8');
+        }
+
+        if (callback) {
+            //Ignore XHR callbacks until the data arrives, then call the
+            //  client's callback
+            xreq.onreadystatechange =
+              (function() {
+                var clientCallback = callback;
+                return function() {
+                  if (this.readyState == 4 && this.status == 200) {
+                    self.setRecvBuffer(this.responseText);
+                    clientCallback();
+                  }
+                };
+              }());
+
+            // detect net::ERR_CONNECTION_REFUSED and call the callback.
+            xreq.onerror =
+                (function() {
+                  var clientCallback = callback;
+                  return function() {
+                      clientCallback();
+                  };
+                }());
+
+        }
+
+        xreq.open('POST', this.url, !!async);
+
+        // add custom headers
+        Object.keys(self.customHeaders).forEach(function(prop) {
+            xreq.setRequestHeader(prop, self.customHeaders[prop]);
+        });
+
+        if (xreq.setRequestHeader) {
+            xreq.setRequestHeader('Accept', 'application/vnd.apache.thrift.json; charset=utf-8');
+            xreq.setRequestHeader('Content-Type', 'application/vnd.apache.thrift.json; charset=utf-8');
+        }
+
+        xreq.send(this.send_buf);
+        if (async && callback) {
+            return;
+        }
+
+        if (xreq.readyState != 4) {
+            throw 'encountered an unknown ajax ready state: ' + xreq.readyState;
+        }
+
+        if (xreq.status != 200) {
+            throw 'encountered a unknown request status: ' + xreq.status;
+        }
+
+        this.recv_buf = xreq.responseText;
+        this.recv_buf_sz = this.recv_buf.length;
+        this.wpos = this.recv_buf.length;
+        this.rpos = 0;
+    },
+
+    /**
+     * Creates a jQuery XHR object to be used for a Thrift server call.
+     * @param {object} client - The Thrift Service client object generated by the IDL compiler.
+     * @param {object} postData - The message to send to the server.
+     * @param {function} args - The original call arguments with the success call back at the end.
+     * @param {function} recv_method - The Thrift Service Client receive method for the call.
+     * @returns {object} A new jQuery XHR object.
+     * @throws {string} If the jQuery version is prior to 1.5 or if jQuery is not found.
+     */
+    jqRequest: function(client, postData, args, recv_method) {
+        if (typeof jQuery === 'undefined' ||
+            typeof jQuery.Deferred === 'undefined') {
+            throw 'Thrift.js requires jQuery 1.5+ to use asynchronous requests';
+        }
+
+        var thriftTransport = this;
+
+        var jqXHR = jQuery.ajax({
+            url: this.url,
+            data: postData,
+            type: 'POST',
+            cache: false,
+            contentType: 'application/vnd.apache.thrift.json; charset=utf-8',
+            dataType: 'text thrift',
+            converters: {
+                'text thrift' : function(responseData) {
+                    thriftTransport.setRecvBuffer(responseData);
+                    var value = recv_method.call(client);
+                    return value;
+                }
+            },
+            context: client,
+            success: jQuery.makeArray(args).pop()
+        });
+
+        return jqXHR;
+    },
+
+    /**
+     * Sets the buffer to provide the protocol when deserializing.
+     * @param {string} buf - The buffer to supply the protocol.
+     */
+    setRecvBuffer: function(buf) {
+        this.recv_buf = buf;
+        this.recv_buf_sz = this.recv_buf.length;
+        this.wpos = this.recv_buf.length;
+        this.rpos = 0;
+    },
+
+    /**
+     * Returns true if the transport is open, XHR always returns true.
+     * @readonly
+     * @returns {boolean} Always True.
+     */
+    isOpen: function() {
+        return true;
+    },
+
+    /**
+     * Opens the transport connection, with XHR this is a nop.
+     */
+    open: function() {},
+
+    /**
+     * Closes the transport connection, with XHR this is a nop.
+     */
+    close: function() {},
+
+    /**
+     * Returns the specified number of characters from the response
+     * buffer.
+     * @param {number} len - The number of characters to return.
+     * @returns {string} Characters sent by the server.
+     */
+    read: function(len) {
+        var avail = this.wpos - this.rpos;
+
+        if (avail === 0) {
+            return '';
+        }
+
+        var give = len;
+
+        if (avail < len) {
+            give = avail;
+        }
+
+        var ret = this.read_buf.substr(this.rpos, give);
+        this.rpos += give;
+
+        //clear buf when complete?
+        return ret;
+    },
+
+    /**
+     * Returns the entire response buffer.
+     * @returns {string} Characters sent by the server.
+     */
+    readAll: function() {
+        return this.recv_buf;
+    },
+
+    /**
+     * Sets the send buffer to buf.
+     * @param {string} buf - The buffer to send.
+     */
+    write: function(buf) {
+        this.send_buf = buf;
+    },
+
+    /**
+     * Returns the send buffer.
+     * @readonly
+     * @returns {string} The send buffer.
+     */
+    getSendBuffer: function() {
+        return this.send_buf;
+    }
+
+};
+
+
+/**
+ * Constructor Function for the WebSocket transport.
+ * @constructor
+ * @param {string} [url] - The URL to connect to.
+ * @classdesc The Apache Thrift Transport layer performs byte level I/O
+ * between RPC clients and servers. The JavaScript TWebSocketTransport object
+ * uses the WebSocket protocol. Target servers must implement WebSocket.
+ * (see: node.js example server_http.js).
+ * @example
+ *   var transport = new Thrift.TWebSocketTransport("http://localhost:8585");
+ */
+Thrift.TWebSocketTransport = function(url) {
+    this.__reset(url);
+};
+
+Thrift.TWebSocketTransport.prototype = {
+    __reset: function(url) {
+      this.url = url;             //Where to connect
+      this.socket = null;         //The web socket
+      this.callbacks = [];        //Pending callbacks
+      this.send_pending = [];     //Buffers/Callback pairs waiting to be sent
+      this.send_buf = '';         //Outbound data, immutable until sent
+      this.recv_buf = '';         //Inbound data
+      this.rb_wpos = 0;           //Network write position in receive buffer
+      this.rb_rpos = 0;           //Client read position in receive buffer
+    },
+
+    /**
+     * Sends the current WS request and registers callback. The async
+     * parameter is ignored (WS flush is always async) and the callback
+     * function parameter is required.
+     * @param {object} async - Ignored.
+     * @param {object} callback - The client completion callback.
+     * @returns {undefined|string} Nothing (undefined)
+     */
+    flush: function(async, callback) {
+      var self = this;
+      if (this.isOpen()) {
+        //Send data and register a callback to invoke the client callback
+        this.socket.send(this.send_buf);
+        this.callbacks.push((function() {
+          var clientCallback = callback;
+          return function(msg) {
+            self.setRecvBuffer(msg);
+            if (clientCallback) {
+                clientCallback();
+            }
+          };
+        }()));
+      } else {
+        //Queue the send to go out __onOpen
+        this.send_pending.push({
+          buf: this.send_buf,
+          cb: callback
+        });
+      }
+    },
+
+    __onOpen: function() {
+       var self = this;
+       if (this.send_pending.length > 0) {
+          //If the user made calls before the connection was fully
+          //open, send them now
+          this.send_pending.forEach(function(elem) {
+             self.socket.send(elem.buf);
+             self.callbacks.push((function() {
+               var clientCallback = elem.cb;
+               return function(msg) {
+                  self.setRecvBuffer(msg);
+                  clientCallback();
+               };
+             }()));
+          });
+          this.send_pending = [];
+       }
+    },
+
+    __onClose: function(evt) {
+      this.__reset(this.url);
+    },
+
+    __onMessage: function(evt) {
+      if (this.callbacks.length) {
+        this.callbacks.shift()(evt.data);
+      }
+    },
+
+    __onError: function(evt) {
+      console.log('Thrift WebSocket Error: ' + evt.toString());
+      this.socket.close();
+    },
+
+    /**
+     * Sets the buffer to use when receiving server responses.
+     * @param {string} buf - The buffer to receive server responses.
+     */
+    setRecvBuffer: function(buf) {
+        this.recv_buf = buf;
+        this.recv_buf_sz = this.recv_buf.length;
+        this.wpos = this.recv_buf.length;
+        this.rpos = 0;
+    },
+
+    /**
+     * Returns true if the transport is open
+     * @readonly
+     * @returns {boolean}
+     */
+    isOpen: function() {
+        return this.socket && this.socket.readyState == this.socket.OPEN;
+    },
+
+    /**
+     * Opens the transport connection
+     */
+    open: function() {
+      //If OPEN/CONNECTING/CLOSING ignore additional opens
+      if (this.socket && this.socket.readyState != this.socket.CLOSED) {
+        return;
+      }
+      //If there is no socket or the socket is closed:
+      this.socket = new WebSocket(this.url);
+      this.socket.onopen = this.__onOpen.bind(this);
+      this.socket.onmessage = this.__onMessage.bind(this);
+      this.socket.onerror = this.__onError.bind(this);
+      this.socket.onclose = this.__onClose.bind(this);
+    },
+
+    /**
+     * Closes the transport connection
+     */
+    close: function() {
+      this.socket.close();
+    },
+
+    /**
+     * Returns the specified number of characters from the response
+     * buffer.
+     * @param {number} len - The number of characters to return.
+     * @returns {string} Characters sent by the server.
+     */
+    read: function(len) {
+        var avail = this.wpos - this.rpos;
+
+        if (avail === 0) {
+            return '';
+        }
+
+        var give = len;
+
+        if (avail < len) {
+            give = avail;
+        }
+
+        var ret = this.read_buf.substr(this.rpos, give);
+        this.rpos += give;
+
+        //clear buf when complete?
+        return ret;
+    },
+
+    /**
+     * Returns the entire response buffer.
+     * @returns {string} Characters sent by the server.
+     */
+    readAll: function() {
+        return this.recv_buf;
+    },
+
+    /**
+     * Sets the send buffer to buf.
+     * @param {string} buf - The buffer to send.
+     */
+    write: function(buf) {
+        this.send_buf = buf;
+    },
+
+    /**
+     * Returns the send buffer.
+     * @readonly
+     * @returns {string} The send buffer.
+     */
+    getSendBuffer: function() {
+        return this.send_buf;
+    }
+
+};
+
+/**
+ * Initializes a Thrift JSON protocol instance.
+ * @constructor
+ * @param {Thrift.Transport} transport - The transport to serialize to/from.
+ * @classdesc Apache Thrift Protocols perform serialization which enables cross
+ * language RPC. The Protocol type is the JavaScript browser implementation
+ * of the Apache Thrift TJSONProtocol.
+ * @example
+ *     var protocol  = new Thrift.Protocol(transport);
+ */
+Thrift.TJSONProtocol = Thrift.Protocol = function(transport) {
+    this.tstack = [];
+    this.tpos = [];
+    this.transport = transport;
+};
+
+/**
+ * Thrift IDL type Id to string mapping.
+ * @readonly
+ * @see {@link Thrift.Type}
+ */
+Thrift.Protocol.Type = {};
+Thrift.Protocol.Type[Thrift.Type.BOOL] = '"tf"';
+Thrift.Protocol.Type[Thrift.Type.BYTE] = '"i8"';
+Thrift.Protocol.Type[Thrift.Type.I16] = '"i16"';
+Thrift.Protocol.Type[Thrift.Type.I32] = '"i32"';
+Thrift.Protocol.Type[Thrift.Type.I64] = '"i64"';
+Thrift.Protocol.Type[Thrift.Type.DOUBLE] = '"dbl"';
+Thrift.Protocol.Type[Thrift.Type.STRUCT] = '"rec"';
+Thrift.Protocol.Type[Thrift.Type.STRING] = '"str"';
+Thrift.Protocol.Type[Thrift.Type.MAP] = '"map"';
+Thrift.Protocol.Type[Thrift.Type.LIST] = '"lst"';
+Thrift.Protocol.Type[Thrift.Type.SET] = '"set"';
+
+/**
+ * Thrift IDL type string to Id mapping.
+ * @readonly
+ * @see {@link Thrift.Type}
+ */
+Thrift.Protocol.RType = {};
+Thrift.Protocol.RType.tf = Thrift.Type.BOOL;
+Thrift.Protocol.RType.i8 = Thrift.Type.BYTE;
+Thrift.Protocol.RType.i16 = Thrift.Type.I16;
+Thrift.Protocol.RType.i32 = Thrift.Type.I32;
+Thrift.Protocol.RType.i64 = Thrift.Type.I64;
+Thrift.Protocol.RType.dbl = Thrift.Type.DOUBLE;
+Thrift.Protocol.RType.rec = Thrift.Type.STRUCT;
+Thrift.Protocol.RType.str = Thrift.Type.STRING;
+Thrift.Protocol.RType.map = Thrift.Type.MAP;
+Thrift.Protocol.RType.lst = Thrift.Type.LIST;
+Thrift.Protocol.RType.set = Thrift.Type.SET;
+
+/**
+ * The TJSONProtocol version number.
+ * @readonly
+ * @const {number} Version
+ * @memberof Thrift.Protocol
+ */
+ Thrift.Protocol.Version = 1;
+
+Thrift.Protocol.prototype = {
+    /**
+     * Returns the underlying transport.
+     * @readonly
+     * @returns {Thrift.Transport} The underlying transport.
+     */
+    getTransport: function() {
+        return this.transport;
+    },
+
+    /**
+     * Serializes the beginning of a Thrift RPC message.
+     * @param {string} name - The service method to call.
+     * @param {Thrift.MessageType} messageType - The type of method call.
+     * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift).
+     */
+    writeMessageBegin: function(name, messageType, seqid) {
+        this.tstack = [];
+        this.tpos = [];
+
+        this.tstack.push([Thrift.Protocol.Version, '"' +
+            name + '"', messageType, seqid]);
+    },
+
+    /**
+     * Serializes the end of a Thrift RPC message.
+     */
+    writeMessageEnd: function() {
+        var obj = this.tstack.pop();
+
+        this.wobj = this.tstack.pop();
+        this.wobj.push(obj);
+
+        this.wbuf = '[' + this.wobj.join(',') + ']';
+
+        this.transport.write(this.wbuf);
+     },
+
+
+    /**
+     * Serializes the beginning of a struct.
+     * @param {string} name - The name of the struct.
+     */
+    writeStructBegin: function(name) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push({});
+    },
+
+    /**
+     * Serializes the end of a struct.
+     */
+    writeStructEnd: function() {
+
+        var p = this.tpos.pop();
+        var struct = this.tstack[p];
+        var str = '{';
+        var first = true;
+        for (var key in struct) {
+            if (first) {
+                first = false;
+            } else {
+                str += ',';
+            }
+
+            str += key + ':' + struct[key];
+        }
+
+        str += '}';
+        this.tstack[p] = str;
+    },
+
+    /**
+     * Serializes the beginning of a struct field.
+     * @param {string} name - The name of the field.
+     * @param {Thrift.Protocol.Type} fieldType - The data type of the field.
+     * @param {number} fieldId - The field's unique identifier.
+     */
+    writeFieldBegin: function(name, fieldType, fieldId) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push({ 'fieldId': '"' +
+            fieldId + '"', 'fieldType': Thrift.Protocol.Type[fieldType]
+        });
+
+    },
+
+    /**
+     * Serializes the end of a field.
+     */
+    writeFieldEnd: function() {
+        var value = this.tstack.pop();
+        var fieldInfo = this.tstack.pop();
+
+        this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' +
+            fieldInfo.fieldType + ':' + value + '}';
+        this.tpos.pop();
+    },
+
+    /**
+     * Serializes the end of the set of fields for a struct.
+     */
+    writeFieldStop: function() {
+        //na
+    },
+
+    /**
+     * Serializes the beginning of a map collection.
+     * @param {Thrift.Type} keyType - The data type of the key.
+     * @param {Thrift.Type} valType - The data type of the value.
+     * @param {number} [size] - The number of elements in the map (ignored).
+     */
+    writeMapBegin: function(keyType, valType, size) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push([Thrift.Protocol.Type[keyType],
+            Thrift.Protocol.Type[valType], 0]);
+    },
+
+    /**
+     * Serializes the end of a map.
+     */
+    writeMapEnd: function() {
+        var p = this.tpos.pop();
+
+        if (p == this.tstack.length) {
+            return;
+        }
+
+        if ((this.tstack.length - p - 1) % 2 !== 0) {
+            this.tstack.push('');
+        }
+
+        var size = (this.tstack.length - p - 1) / 2;
+
+        this.tstack[p][this.tstack[p].length - 1] = size;
+
+        var map = '}';
+        var first = true;
+        while (this.tstack.length > p + 1) {
+            var v = this.tstack.pop();
+            var k = this.tstack.pop();
+            if (first) {
+                first = false;
+            } else {
+                map = ',' + map;
+            }
+
+            if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings
+            map = k + ':' + v + map;
+        }
+        map = '{' + map;
+
+        this.tstack[p].push(map);
+        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
+    },
+
+    /**
+     * Serializes the beginning of a list collection.
+     * @param {Thrift.Type} elemType - The data type of the elements.
+     * @param {number} size - The number of elements in the list.
+     */
+    writeListBegin: function(elemType, size) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push([Thrift.Protocol.Type[elemType], size]);
+    },
+
+    /**
+     * Serializes the end of a list.
+     */
+    writeListEnd: function() {
+        var p = this.tpos.pop();
+
+        while (this.tstack.length > p + 1) {
+            var tmpVal = this.tstack[p + 1];
+            this.tstack.splice(p + 1, 1);
+            this.tstack[p].push(tmpVal);
+        }
+
+        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
+    },
+
+    /**
+     * Serializes the beginning of a set collection.
+     * @param {Thrift.Type} elemType - The data type of the elements.
+     * @param {number} size - The number of elements in the list.
+     */
+    writeSetBegin: function(elemType, size) {
+        this.tpos.push(this.tstack.length);
+        this.tstack.push([Thrift.Protocol.Type[elemType], size]);
+    },
+
+    /**
+     * Serializes the end of a set.
+     */
+    writeSetEnd: function() {
+        var p = this.tpos.pop();
+
+        while (this.tstack.length > p + 1) {
+            var tmpVal = this.tstack[p + 1];
+            this.tstack.splice(p + 1, 1);
+            this.tstack[p].push(tmpVal);
+        }
+
+        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
+    },
+
+    /** Serializes a boolean */
+    writeBool: function(value) {
+        this.tstack.push(value ? 1 : 0);
+    },
+
+    /** Serializes a number */
+    writeByte: function(i8) {
+        this.tstack.push(i8);
+    },
+
+    /** Serializes a number */
+    writeI16: function(i16) {
+        this.tstack.push(i16);
+    },
+
+    /** Serializes a number */
+    writeI32: function(i32) {
+        this.tstack.push(i32);
+    },
+
+    /** Serializes a number */
+    writeI64: function(i64) {
+        this.tstack.push(i64);
+    },
+
+    /** Serializes a number */
+    writeDouble: function(dbl) {
+        this.tstack.push(dbl);
+    },
+
+    /** Serializes a string */
+    writeString: function(str) {
+        // We do not encode uri components for wire transfer:
+        if (str === null) {
+            this.tstack.push(null);
+        } else {
+            // concat may be slower than building a byte buffer
+            var escapedString = '';
+            for (var i = 0; i < str.length; i++) {
+                var ch = str.charAt(i);      // a single double quote: "
+                if (ch === '\"') {
+                    escapedString += '\\\"'; // write out as: \"
+                } else if (ch === '\\') {    // a single backslash
+                    escapedString += '\\\\'; // write out as double backslash
+                } else if (ch === '\b') {    // a single backspace: invisible
+                    escapedString += '\\b';  // write out as: \b"
+                } else if (ch === '\f') {    // a single formfeed: invisible
+                    escapedString += '\\f';  // write out as: \f"
+                } else if (ch === '\n') {    // a single newline: invisible
+                    escapedString += '\\n';  // write out as: \n"
+                } else if (ch === '\r') {    // a single return: invisible
+                    escapedString += '\\r';  // write out as: \r"
+                } else if (ch === '\t') {    // a single tab: invisible
+                    escapedString += '\\t';  // write out as: \t"
+                } else {
+                    escapedString += ch;     // Else it need not be escaped
+                }
+            }
+            this.tstack.push('"' + escapedString + '"');
+        }
+    },
+
+    /** Serializes a string */
+    writeBinary: function(binary) {
+        var str = '';
+        if (typeof binary == 'string') {
+            str = binary;
+        } else if (binary instanceof Uint8Array) {
+            var arr = binary;
+            for (var i = 0; i < arr.length; ++i) {
+                str += String.fromCharCode(arr[i]);
+            }
+        } else {
+            throw new TypeError('writeBinary only accepts String or Uint8Array.');
+        }
+        this.tstack.push('"' + btoa(str) + '"');
+    },
+
+    /**
+       @class
+       @name AnonReadMessageBeginReturn
+       @property {string} fname - The name of the service method.
+       @property {Thrift.MessageType} mtype - The type of message call.
+       @property {number} rseqid - The sequence number of the message (0 in Thrift RPC).
+     */
+    /**
+     * Deserializes the beginning of a message.
+     * @returns {AnonReadMessageBeginReturn}
+     */
+    readMessageBegin: function() {
+        this.rstack = [];
+        this.rpos = [];
+
+        if (typeof JSON !== 'undefined' && typeof JSON.parse === 'function') {
+            this.robj = JSON.parse(this.transport.readAll());
+        } else if (typeof jQuery !== 'undefined') {
+            this.robj = jQuery.parseJSON(this.transport.readAll());
+        } else {
+            this.robj = eval(this.transport.readAll());
+        }
+
+        var r = {};
+        var version = this.robj.shift();
+
+        if (version != Thrift.Protocol.Version) {
+            throw 'Wrong thrift protocol version: ' + version;
+        }
+
+        r.fname = this.robj.shift();
+        r.mtype = this.robj.shift();
+        r.rseqid = this.robj.shift();
+
+
+        //get to the main obj
+        this.rstack.push(this.robj.shift());
+
+        return r;
+    },
+
+    /** Deserializes the end of a message. */
+    readMessageEnd: function() {
+    },
+
+    /**
+     * Deserializes the beginning of a struct.
+     * @param {string} [name] - The name of the struct (ignored)
+     * @returns {object} - An object with an empty string fname property
+     */
+    readStructBegin: function(name) {
+        var r = {};
+        r.fname = '';
+
+        //incase this is an array of structs
+        if (this.rstack[this.rstack.length - 1] instanceof Array) {
+            this.rstack.push(this.rstack[this.rstack.length - 1].shift());
+        }
+
+        return r;
+    },
+
+    /** Deserializes the end of a struct. */
+    readStructEnd: function() {
+        if (this.rstack[this.rstack.length - 2] instanceof Array) {
+            this.rstack.pop();
+        }
+    },
+
+    /**
+       @class
+       @name AnonReadFieldBeginReturn
+       @property {string} fname - The name of the field (always '').
+       @property {Thrift.Type} ftype - The data type of the field.
+       @property {number} fid - The unique identifier of the field.
+     */
+    /**
+     * Deserializes the beginning of a field.
+     * @returns {AnonReadFieldBeginReturn}
+     */
+    readFieldBegin: function() {
+        var r = {};
+
+        var fid = -1;
+        var ftype = Thrift.Type.STOP;
+
+        //get a fieldId
+        for (var f in (this.rstack[this.rstack.length - 1])) {
+            if (f === null) {
+              continue;
+            }
+
+            fid = parseInt(f, 10);
+            this.rpos.push(this.rstack.length);
+
+            var field = this.rstack[this.rstack.length - 1][fid];
+
+            //remove so we don't see it again
+            delete this.rstack[this.rstack.length - 1][fid];
+
+            this.rstack.push(field);
+
+            break;
+        }
+
+        if (fid != -1) {
+
+            //should only be 1 of these but this is the only
+            //way to match a key
+            for (var i in (this.rstack[this.rstack.length - 1])) {
+                if (Thrift.Protocol.RType[i] === null) {
+                    continue;
+                }
+
+                ftype = Thrift.Protocol.RType[i];
+                this.rstack[this.rstack.length - 1] =
+                    this.rstack[this.rstack.length - 1][i];
+            }
+        }
+
+        r.fname = '';
+        r.ftype = ftype;
+        r.fid = fid;
+
+        return r;
+    },
+
+    /** Deserializes the end of a field. */
+    readFieldEnd: function() {
+        var pos = this.rpos.pop();
+
+        //get back to the right place in the stack
+        while (this.rstack.length > pos) {
+            this.rstack.pop();
+        }
+
+    },
+
+    /**
+       @class
+       @name AnonReadMapBeginReturn
+       @property {Thrift.Type} ktype - The data type of the key.
+       @property {Thrift.Type} vtype - The data type of the value.
+       @property {number} size - The number of elements in the map.
+     */
+    /**
+     * Deserializes the beginning of a map.
+     * @returns {AnonReadMapBeginReturn}
+     */
+    readMapBegin: function() {
+        var map = this.rstack.pop();
+        var first = map.shift();
+        if (first instanceof Array) {
+          this.rstack.push(map);
+          map = first;
+          first = map.shift();
+        }
+
+        var r = {};
+        r.ktype = Thrift.Protocol.RType[first];
+        r.vtype = Thrift.Protocol.RType[map.shift()];
+        r.size = map.shift();
+
+
+        this.rpos.push(this.rstack.length);
+        this.rstack.push(map.shift());
+
+        return r;
+    },
+
+    /** Deserializes the end of a map. */
+    readMapEnd: function() {
+        this.readFieldEnd();
+    },
+
+    /**
+       @class
+       @name AnonReadColBeginReturn
+       @property {Thrift.Type} etype - The data type of the element.
+       @property {number} size - The number of elements in the collection.
+     */
+    /**
+     * Deserializes the beginning of a list.
+     * @returns {AnonReadColBeginReturn}
+     */
+    readListBegin: function() {
+        var list = this.rstack[this.rstack.length - 1];
+
+        var r = {};
+        r.etype = Thrift.Protocol.RType[list.shift()];
+        r.size = list.shift();
+
+        this.rpos.push(this.rstack.length);
+        this.rstack.push(list.shift());
+
+        return r;
+    },
+
+    /** Deserializes the end of a list. */
+    readListEnd: function() {
+        var pos = this.rpos.pop() - 2;
+        var st = this.rstack;
+        st.pop();
+        if (st instanceof Array && st.length > pos && st[pos].length > 0) {
+          st.push(st[pos].shift());
+        }
+    },
+
+    /**
+     * Deserializes the beginning of a set.
+     * @returns {AnonReadColBeginReturn}
+     */
+    readSetBegin: function(elemType, size) {
+        return this.readListBegin(elemType, size);
+    },
+
+    /** Deserializes the end of a set. */
+    readSetEnd: function() {
+        return this.readListEnd();
+    },
+
+    /** Returns an object with a value property set to
+     *  False unless the next number in the protocol buffer
+     *  is 1, in which case the value property is True */
+    readBool: function() {
+        var r = this.readI32();
+
+        if (r !== null && r.value == '1') {
+            r.value = true;
+        } else {
+            r.value = false;
+        }
+
+        return r;
+    },
+
+    /** Returns the an object with a value property set to the
+        next value found in the protocol buffer */
+    readByte: function() {
+        return this.readI32();
+    },
+
+    /** Returns the an object with a value property set to the
+        next value found in the protocol buffer */
+    readI16: function() {
+        return this.readI32();
+    },
+
+    /** Returns the an object with a value property set to the
+        next value found in the protocol buffer */
+    readI32: function(f) {
+        if (f === undefined) {
+            f = this.rstack[this.rstack.length - 1];
+        }
+
+        var r = {};
+
+        if (f instanceof Array) {
+            if (f.length === 0) {
+                r.value = undefined;
+            } else {
+                if (!f.isReversed) {
+                    f.reverse();
+                    f.isReversed = true;
+                }
+                r.value = f.pop();
+            }
+        } else if (f instanceof Object) {
+           for (var i in f) {
+                if (i === null) {
+                  continue;
+                }
+                this.rstack.push(f[i]);
+                delete f[i];
+
+                r.value = i;
+                break;
+           }
+        } else {
+            r.value = f;
+            this.rstack.pop();
+        }
+
+        return r;
+    },
+
+    /** Returns the an object with a value property set to the
+        next value found in the protocol buffer */
+    readI64: function() {
+        return this.readI32();
+    },
+
+    /** Returns the an object with a value property set to the
+        next value found in the protocol buffer */
+    readDouble: function() {
+        return this.readI32();
+    },
+
+    /** Returns the an object with a value property set to the
+        next value found in the protocol buffer */
+    readString: function() {
+        var r = this.readI32();
+        return r;
+    },
+
+    /** Returns the an object with a value property set to the
+        next value found in the protocol buffer */
+    readBinary: function() {
+        var r = this.readI32();
+        r.value = atob(r.value);
+        return r;
+    },
+
+    /**
+     * Method to arbitrarily skip over data */
+    skip: function(type) {
+        var ret, i;
+        switch (type) {
+            case Thrift.Type.STOP:
+                return null;
+
+            case Thrift.Type.BOOL:
+                return this.readBool();
+
+            case Thrift.Type.BYTE:
+                return this.readByte();
+
+            case Thrift.Type.I16:
+                return this.readI16();
+
+            case Thrift.Type.I32:
+                return this.readI32();
+
+            case Thrift.Type.I64:
+                return this.readI64();
+
+            case Thrift.Type.DOUBLE:
+                return this.readDouble();
+
+            case Thrift.Type.STRING:
+                return this.readString();
+
+            case Thrift.Type.STRUCT:
+                this.readStructBegin();
+                while (true) {
+                    ret = this.readFieldBegin();
+                    if (ret.ftype == Thrift.Type.STOP) {
+                        break;
+                    }
+                    this.skip(ret.ftype);
+                    this.readFieldEnd();
+                }
+                this.readStructEnd();
+                return null;
+
+            case Thrift.Type.MAP:
+                ret = this.readMapBegin();
+                for (i = 0; i < ret.size; i++) {
+                    if (i > 0) {
+                        if (this.rstack.length > this.rpos[this.rpos.length - 1] + 1) {
+                            this.rstack.pop();
+                        }
+                    }
+                    this.skip(ret.ktype);
+                    this.skip(ret.vtype);
+                }
+                this.readMapEnd();
+                return null;
+
+            case Thrift.Type.SET:
+                ret = this.readSetBegin();
+                for (i = 0; i < ret.size; i++) {
+                    this.skip(ret.etype);
+                }
+                this.readSetEnd();
+                return null;
+
+            case Thrift.Type.LIST:
+                ret = this.readListBegin();
+                for (i = 0; i < ret.size; i++) {
+                    this.skip(ret.etype);
+                }
+                this.readListEnd();
+                return null;
+
+            default:
+                throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA);
+        }
+    }
+};
+
+
+/**
+ * Initializes a MutilplexProtocol Implementation as a Wrapper for Thrift.Protocol
+ * @constructor
+ */
+Thrift.MultiplexProtocol = function(srvName, trans, strictRead, strictWrite) {
+    Thrift.Protocol.call(this, trans, strictRead, strictWrite);
+    this.serviceName = srvName;
+};
+Thrift.inherits(Thrift.MultiplexProtocol, Thrift.Protocol, 'multiplexProtocol');
+
+/** Override writeMessageBegin method of prototype*/
+Thrift.MultiplexProtocol.prototype.writeMessageBegin = function(name, type, seqid) {
+
+    if (type === Thrift.MessageType.CALL || type === Thrift.MessageType.ONEWAY) {
+        Thrift.Protocol.prototype.writeMessageBegin.call(this, this.serviceName + ':' + name, type, seqid);
+    } else {
+        Thrift.Protocol.prototype.writeMessageBegin.call(this, name, type, seqid);
+    }
+};
+
+Thrift.Multiplexer = function() {
+    this.seqid = 0;
+};
+
+/** Instantiates a multiplexed client for a specific service
+ * @constructor
+ * @param {String} serviceName - The transport to serialize to/from.
+ * @param {Thrift.ServiceClient} SCl - The Service Client Class
+ * @param {Thrift.Transport} transport - Thrift.Transport instance which provides remote host:port
+ * @example
+ *    var mp = new Thrift.Multiplexer();
+ *    var transport = new Thrift.Transport("http://localhost:9090/foo.thrift");
+ *    var protocol = new Thrift.Protocol(transport);
+ *    var client = mp.createClient('AuthService', AuthServiceClient, transport);
+*/
+Thrift.Multiplexer.prototype.createClient = function(serviceName, SCl, transport) {
+    if (SCl.Client) {
+        SCl = SCl.Client;
+    }
+    var self = this;
+    SCl.prototype.new_seqid = function() {
+        self.seqid += 1;
+        return self.seqid;
+    };
+    var client = new SCl(new Thrift.MultiplexProtocol(serviceName, transport));
+
+    return client;
+};
+
+
+
+var copyList, copyMap;
+
+copyList = function(lst, types) {
+
+  if (!lst) {return lst; }
+
+  var type;
+
+  if (types.shift === undefined) {
+    type = types;
+  }
+  else {
+    type = types[0];
+  }
+  var Type = type;
+
+  var len = lst.length, result = [], i, val;
+  for (i = 0; i < len; i++) {
+    val = lst[i];
+    if (type === null) {
+      result.push(val);
+    }
+    else if (type === copyMap || type === copyList) {
+      result.push(type(val, types.slice(1)));
+    }
+    else {
+      result.push(new Type(val));
+    }
+  }
+  return result;
+};
+
+copyMap = function(obj, types) {
+
+  if (!obj) {return obj; }
+
+  var type;
+
+  if (types.shift === undefined) {
+    type = types;
+  }
+  else {
+    type = types[0];
+  }
+  var Type = type;
+
+  var result = {}, val;
+  for (var prop in obj) {
+    if (obj.hasOwnProperty(prop)) {
+      val = obj[prop];
+      if (type === null) {
+        result[prop] = val;
+      }
+      else if (type === copyMap || type === copyList) {
+        result[prop] = type(val, types.slice(1));
+      }
+      else {
+        result[prop] = new Type(val);
+      }
+    }
+  }
+  return result;
+};
+
+Thrift.copyMap = copyMap;
+Thrift.copyList = copyList;
diff --git a/lib/js/test/README.md b/lib/js/test/README.md
new file mode 100644
index 0000000..9ad140e
--- /dev/null
+++ b/lib/js/test/README.md
@@ -0,0 +1,68 @@
+Thrift Javascript Library
+=========================
+This browser based Apache Thrift implementation supports
+RPC clients using the JSON protocol over Http[s] with XHR
+and WebSocket.
+
+License
+-------
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+Test Servers
+------------
+drwxr-xr-x 2 randy randy  4096 Feb  8 15:44 sec
+-rw-r--r-- 1 randy randy  2183 Feb  9 04:01 server_http.js
+-rw-r--r-- 1 randy randy  2386 Feb  9 05:39 server_https.js
+
+server_http.js is a Node.js web server which support the
+standard Apache Thrift test suite (thrift/test/ThriftTest.thrift).
+The server supports Apache Thrift XHR and WebSocket clients.
+
+server_https.js is the same but uses SSL/TLS. The server key 
+and cert are pulled from the thrift/test/keys folder.
+
+Both of these servers support WebSocket (the http: supports ws:,
+and the https: support wss:).
+
+To run the client test with the Java test server use: 
+$ make check (requires the Apache Thrift Java branch 
+and make check must have been run in thrift/lib/java 
+previously).
+
+To run the client tests with the Node servers run the grunt
+ build in the parent js directory (see README there).
+ 
+Test Clients
+------------
+-rw-r--r-- 1 randy randy 13558 Feb  9 07:18 test-async.js
+-rw-r--r-- 1 randy randy  5724 Feb  9 03:45 test_handler.js
+-rwxr-xr-x 1 randy randy  2719 Feb  9 06:04 test.html
+-rw-r--r-- 1 randy randy  4611 Feb  9 06:05 test-jq.js
+-rwxr-xr-x 1 randy randy 12153 Feb  9 06:04 test.js
+-rw-r--r-- 1 randy randy  2593 Feb  9 06:16 test-nojq.html
+-rw-r--r-- 1 randy randy  1450 Feb  9 06:14 test-nojq.js
+-rw-r--r-- 1 randy randy  2847 Feb  9 06:31 testws.html
+
+There are three html test driver files, all of which are
+QUnit based. test.html tests the Apache Thrift jQuery
+generated code (thrift -gen js:jquery). The test-nojq.html
+runs almost identical tests against normal JavaScript builds
+(thrift -gen js). Both of the previous tests use the XHR 
+transport. The testws.html runs similar tests using the
+WebSocket transport. The test*.js files are loaded by the
+html drivers and contain the actual Apache Thrift tests.
diff --git a/lib/js/test/build.properties b/lib/js/test/build.properties
new file mode 100644
index 0000000..8463668
--- /dev/null
+++ b/lib/js/test/build.properties
@@ -0,0 +1,5 @@
+# Maven Ant tasks Jar details
+mvn.ant.task.version=2.1.3
+mvn.repo=http://repo1.maven.org/maven2
+mvn.ant.task.url=${mvn.repo}/org/apache/maven/maven-ant-tasks/${mvn.ant.task.version}
+mvn.ant.task.jar=maven-ant-tasks-${mvn.ant.task.version}.jar
diff --git a/lib/js/test/build.xml b/lib/js/test/build.xml
index 53bec58..04c1360 100755
--- a/lib/js/test/build.xml
+++ b/lib/js/test/build.xml
@@ -31,17 +31,21 @@
   <!-- the root directory, where you unpack thrift distibution (e.g. thrift-0.x.x.tar.gz) -->
   <property name="thrift.dir" location="../../../" />
   <property name="thrift.java.dir" location="${thrift.dir}/lib/java" />
+  <property name="build.tools.dir" location="${thrift.java.dir}/build/tools/"/>
+  <property file="${basedir}/build.properties"/>
 
   <!-- Include the base java properties file -->
-  <property file="${thrift.java.dir}/build.properties" />
+  <property file="${thrift.java.dir}/gradle.properties" />
 
   <property name="thrift.compiler" location="${thrift.dir}/compiler/cpp/thrift" />
 
   <path id="libs.classpath">
-    <fileset dir="${thrift.java.dir}/build/">
-      <include name="*.jar" />
+    <fileset dir="${thrift.java.dir}/build/libs">
+      <include name="libthrift*.jar" />
+      <exclude name="libthrift*javadoc.jar" />
+      <exclude name="libthrift*sources.jar" />
     </fileset>
-    <fileset dir="${thrift.java.dir}/build/lib">
+    <fileset dir="${thrift.java.dir}/build/deps">
       <include name="*.jar" />
     </fileset>
     <fileset dir="${build}/lib">
@@ -59,15 +63,16 @@
       <condition>
         <not>
           <resourcecount count="2">
-            <fileset id="fs" dir="${thrift.java.dir}/build">
+            <fileset id="fs" dir="${thrift.java.dir}/build/libs">
               <include name="libthrift*.jar" />
               <exclude name="libthrift*javadoc.jar" />
+              <exclude name="libthrift*sources.jar" />
             </fileset>
           </resourcecount>
         </not>
       </condition>
       You need libthrift*.jar and libthrift*test.jar located at
-      ${thrift.java.dir}/build
+      ${thrift.java.dir}/build/libs
       Did you compile Thrift Java library and its test suite by "ant compile-test"?
     </fail>
     <fail>
@@ -84,6 +89,7 @@
 
   <target name="init" depends="dependencies">
     <tstamp />
+    <mkdir dir="${build.tools.dir}"/>
     <mkdir dir="${build}"/>
     <mkdir dir="${build}/js/lib"/>
     <mkdir dir="${build}/lib"/>
@@ -92,21 +98,19 @@
     <mkdir dir="${build}/test/log"/>
   </target>
 
-  <target name="jslibs" depends="init, proxy">
-    <get src="http://code.jquery.com/jquery-1.7.2.js" dest="${build}/js/lib" usetimestamp="true"/>
-    <get src="http://js-test-driver.googlecode.com/svn/trunk/JsTestDriver/contrib/qunit/src/equiv.js" dest="${build}/js/lib" usetimestamp="true"/>
-    <get src="http://js-test-driver.googlecode.com/svn/trunk/JsTestDriver/contrib/qunit/src/QUnitAdapter.js" dest="${build}/js/lib" usetimestamp="true"/>
+  <target name="download_jslibs">
+    <get src="http://code.jquery.com/jquery-1.11.3.min.js" dest="${build}/js/lib/jquery.js" usetimestamp="true"/>
+    <get src="http://code.jquery.com/qunit/qunit-2.6.2.js" dest="${build}/js/lib/qunit.js" usetimestamp="true"/>
+    <get src="http://code.jquery.com/qunit/qunit-2.6.2.css" dest="${build}/js/lib/qunit.css" usetimestamp="true"/>
+  </target>
 
-    <get src="http://code.jquery.com/qunit/qunit-1.5.0.js" dest="${build}/js/lib/qunit.js" usetimestamp="true"/>
-    <get src="http://code.jquery.com/qunit/qunit-1.5.0.css" dest="${build}/js/lib/qunit.css" usetimestamp="true"/>
-    <!-- js-test-driver has issues with relative path...so we need a copy -->
-    <copy file="../thrift.js" todir="${build}/js/"/>
+  <target name="jslibs" depends="init, proxy, download_jslibs">
   </target>
 
   <target name="compile" description="compile the test suite" depends="init, generate, resolve">
     <!-- //TODO enable <compilerarg value="-Xlint"/>-->
-    <javac includeantruntime="false" srcdir="${genjava}" destdir="${build}/test" classpathref="libs.classpath"/>
-    <javac includeantruntime="false" srcdir="${src}" destdir="${build}/test" classpathref="libs.classpath"/>
+    <javac compiler="modern" includeantruntime="false" srcdir="${genjava}" destdir="${build}/test" classpathref="libs.classpath"/>
+    <javac compiler="modern" includeantruntime="false" srcdir="${src}" destdir="${build}/test" classpathref="libs.classpath"/>
   </target>
 
   <target name="jstest" description="create the test suite jar file" depends="compile">
@@ -159,41 +163,6 @@
     </parallel>
   </target>
 
-  <target name="jstestdriver-server" description="start the js-test-driver server" depends="init, resolve">
-    <echo>Starting js-test-driver Server...</echo>
-    <java jar="${build}/lib/jstestdriver-1.3.2.jar" dir="." fork="true"
-            failonerror="true" output="${build}/log/jstestdriver-server.log">
-      <arg line="--port 9876"/>
-    </java>
-  </target>
-
-  <target name="jstestdriver" description="do unit tests with js-test-driver" depends="init, jstest, jslibs">
-    <parallel>
-      <java classname="test.Httpd" fork="true" timeout="10000"
-        classpathref="test.classpath" failonerror="false" output="${build}/log/unittest.log">
-        <arg value="../" />
-      </java>
-      <sequential>
-        <sleep seconds="2"/>
-        <echo>Running Unit Tests with js-test-driver</echo>
-          <java jar="${build}/lib/jstestdriver-1.3.2.jar" dir="." fork="true" 
-            failonerror="true" output="${build}/log/jstestdriver.log">
-            <arg value="--config" />
-            <arg value="jsTestDriver.conf" />
-
-            <arg value="--reset" />
-            <arg value="--verbose" />
-
-            <arg value="--tests" />
-            <arg value="all" />
-
-            <arg value="--testOutput" />
-            <arg value="${build}/test/log/" />
-        </java>
-      </sequential>
-    </parallel>
-  </target>
-
   <target name="generate">
     <exec executable="${thrift.compiler}" failonerror="true">
       <arg line="--gen java ${thrift.dir}/test/ThriftTest.thrift" />
@@ -201,6 +170,9 @@
     <exec executable="${thrift.compiler}" failonerror="true">
       <arg line="--gen js:jquery ${thrift.dir}/test/ThriftTest.thrift" />
     </exec>
+    <exec executable="${thrift.compiler}" failonerror="true">
+      <arg line="--gen js:jquery ${thrift.dir}/test/DoubleConstantsTest.thrift" />
+    </exec>
   </target>
 
   <target name="test" description="run test suite (lint, unittest)" depends="lint, unittest"/>
@@ -216,7 +188,7 @@
     <jsl:jslint options="evil,forin,browser,bitwise,regexp,newcap,immed" encoding="UTF-8">
       <formatter type="plain" />
       <fileset dir="${genjs}" includes="**/*.js" />
-      <fileset dir=".." includes="thrift.js" />
+      <fileset dir="../src" includes="thrift.js" />
 
       <!-- issues with unsafe character -->
       <!-- fileset dir="." includes="*test*.js" /> -->
@@ -234,7 +206,7 @@
     <exec executable="gjslint" failifexecutionfails="no">
       <arg line="--nojsdoc"/>
       <arg line="${genjs}/*.js"/>
-      <arg line="../thrift.js"/>
+      <arg line="../src/thrift.js"/>
 
       <!-- issues with unsafe character, etc. -->
       <!-- <arg line="*test*.js"/> -->
@@ -247,16 +219,23 @@
     <delete dir="${genjs}" />
   </target>
 
-  <target name="resolve" unless="mvn.finished">
+  <target name="mvn.ant.tasks.download" depends="init,mvn.ant.tasks.check" unless="mvn.ant.tasks.found">
+    <get src="${mvn.ant.task.url}/${mvn.ant.task.jar}" dest="${build.tools.dir}/${mvn.ant.task.jar}" usetimestamp="true"/>
+  </target>
+
+  <target name="mvn.ant.tasks.check">
+    <condition property="mvn.ant.tasks.found">
+      <typefound uri="antlib:org.apache.maven.artifact.ant" name="artifact"/>
+    </condition>
+  </target>
+
+  <target name="resolve" depends="mvn.ant.tasks.download" unless="mvn.finished">
     <typedef uri="antlib:org.apache.maven.artifact.ant" classpath="${thrift.java.dir}/build/tools/${mvn.ant.task.jar}"/>
 
     <artifact:dependencies filesetId="js.test.dependency.jars">
       <dependency groupId="org.apache.httpcomponents" artifactId="httpclient" version="4.0.1"/>
       <dependency groupId="com.googlecode.jslint4java" artifactId="jslint4java-ant" version="1.4.6"/>
       <dependency groupId="eu.medsea.mimeutil" artifactId="mime-util" version="2.1.3"/>
-      <!-- get jstestdriver.jar via maven-->
-      <remoteRepository id="jstd-maven-plugin google code repo" url="http://jstd-maven-plugin.googlecode.com/svn/maven2"/>
-      <dependency groupId="com.google.jstestdriver" artifactId="maven-jstestdriver-plugin" version="1.3.2.3"/>
     </artifact:dependencies>
 
     <!-- Copy the dependencies to the build/lib dir -->
@@ -264,8 +243,7 @@
       <fileset refid="js.test.dependency.jars"/>
       <mapper type="flatten"/>
     </copy>
-    
+
     <property name="mvn.finished" value="true"/>
   </target>
 </project>
-
diff --git a/lib/js/test/deep-constructor.test.js b/lib/js/test/deep-constructor.test.js
new file mode 100644
index 0000000..82d3a1e
--- /dev/null
+++ b/lib/js/test/deep-constructor.test.js
@@ -0,0 +1,213 @@
+function serialize(data) {
+  const transport = new Thrift.Transport('/service');
+  const protocol = new Thrift.Protocol(transport);
+  protocol.writeMessageBegin('', 0, 0);
+  data.write(protocol);
+  protocol.writeMessageEnd();
+  return transport.send_buf;
+}
+
+function deserialize(serialized, type) {
+  const transport = new Thrift.Transport('/service');
+  transport.setRecvBuffer(serialized);
+  const protocol = new Thrift.Protocol(transport);
+  protocol.readMessageBegin();
+  const data = new type();
+  data.read(protocol);
+  protocol.readMessageEnd();
+  return data;
+}
+
+
+function createThriftObj() {
+
+  return new Complex({
+
+    struct_field: new Simple({value: 'a'}),
+
+    struct_list_field: [
+      new Simple({value: 'b'}),
+      new Simple({value: 'c'})
+    ],
+
+    struct_set_field: [
+      new Simple({value: 'd'}),
+      new Simple({value: 'e'})
+    ],
+
+    struct_map_field: {
+      A: new Simple({value: 'f'}),
+      B: new Simple({value: 'g'})
+    },
+
+    struct_nested_containers_field: [
+      [
+        {
+          C: [
+            new Simple({value: 'h'}),
+            new Simple({value: 'i'})
+          ]
+        }
+      ]
+    ],
+
+
+    struct_nested_containers_field2: {
+      D: [
+        {
+          DA: new Simple({value: 'j'})
+        },
+        {
+          DB: new Simple({value: 'k'})
+        }
+      ]
+    },
+
+    list_of_list_field: [
+       ['one', 'two'],
+       ['three', 'four'],
+       ['five', 'six']
+    ]
+  }
+  );
+}
+
+
+function createJsObj() {
+
+  return {
+
+    struct_field: {value: 'a'},
+
+    struct_list_field: [
+      {value: 'b'},
+      {value: 'c'}
+    ],
+
+    struct_set_field: [
+      {value: 'd'},
+      {value: 'e'}
+    ],
+
+    struct_map_field: {
+      A: {value: 'f'},
+      B: {value: 'g'}
+    },
+
+    struct_nested_containers_field: [
+      [
+        {
+          C: [
+            {value: 'h'},
+            {value: 'i'}
+          ]
+        }
+      ]
+    ],
+
+    struct_nested_containers_field2: {
+      D: [
+        {
+          DA: {value: 'j'}
+        },
+        {
+          DB: {value: 'k'}
+        }
+      ]
+    },
+
+    list_of_list_field: [
+      ['one', 'two'],
+      ['three', 'four'],
+      ['five', 'six']
+   ]
+  };
+}
+
+
+function assertValues(obj, assert) {
+    assert.equal(obj.struct_field.value, 'a');
+    assert.equal(obj.struct_list_field[0].value, 'b');
+    assert.equal(obj.struct_list_field[1].value, 'c');
+    assert.equal(obj.struct_set_field[0].value, 'd');
+    assert.equal(obj.struct_set_field[1].value, 'e');
+    assert.equal(obj.struct_map_field.A.value, 'f');
+    assert.equal(obj.struct_map_field.B.value, 'g');
+    assert.equal(obj.struct_nested_containers_field[0][0].C[0].value, 'h');
+    assert.equal(obj.struct_nested_containers_field[0][0].C[1].value, 'i');
+    assert.equal(obj.struct_nested_containers_field2.D[0].DA.value, 'j');
+    assert.equal(obj.struct_nested_containers_field2.D[1].DB.value, 'k');
+    assert.equal(obj.list_of_list_field[0][0], 'one');
+    assert.equal(obj.list_of_list_field[0][1], 'two');
+    assert.equal(obj.list_of_list_field[1][0], 'three');
+    assert.equal(obj.list_of_list_field[1][1], 'four');
+    assert.equal(obj.list_of_list_field[2][0], 'five');
+    assert.equal(obj.list_of_list_field[2][1], 'six');
+}
+
+const cases = {
+
+  'Serialize/deserialize simple struct should return equal object': function(assert) {
+    const tObj = new Simple({value: 'a'});
+    const received = deserialize(serialize(tObj), Simple);
+    assert.ok(tObj !== received);
+    assert.deepEqual(received, tObj);
+  },
+
+
+  'Serialize/deserialize should return equal object': function(assert) {
+    const tObj = createThriftObj();
+    const received = deserialize(serialize(tObj), Complex);
+    assert.ok(tObj !== received);
+    assert.deepEqual(received, tObj);
+  },
+
+  'Nested structs and containers initialized from plain js objects should serialize same as if initialized from thrift objects': function(assert) {
+    const tObj1 = createThriftObj();
+    const tObj2 = new Complex(createJsObj());
+    assertValues(tObj2, assert);
+    assert.equal(serialize(tObj2), serialize(tObj1));
+  },
+
+  'Modifications to args object should not affect constructed Thrift object': function(assert) {
+
+    const args = createJsObj();
+    assertValues(args, assert);
+
+    const tObj = new Complex(args);
+    assertValues(tObj, assert);
+
+    args.struct_field.value = 'ZZZ';
+    args.struct_list_field[0].value = 'ZZZ';
+    args.struct_list_field[1].value = 'ZZZ';
+    args.struct_set_field[0].value = 'ZZZ';
+    args.struct_set_field[1].value = 'ZZZ';
+    args.struct_map_field.A.value = 'ZZZ';
+    args.struct_map_field.B.value = 'ZZZ';
+    args.struct_nested_containers_field[0][0].C[0] = 'ZZZ';
+    args.struct_nested_containers_field[0][0].C[1] = 'ZZZ';
+    args.struct_nested_containers_field2.D[0].DA = 'ZZZ';
+    args.struct_nested_containers_field2.D[0].DB = 'ZZZ';
+
+    assertValues(tObj, assert);
+  },
+
+  'nulls are ok': function(assert) {
+    const tObj = new Complex({
+      struct_field: null,
+      struct_list_field: null,
+      struct_set_field: null,
+      struct_map_field: null,
+      struct_nested_containers_field: null,
+      struct_nested_containers_field2: null
+    });
+    const received = deserialize(serialize(tObj), Complex);
+    assert.ok(tObj !== received);
+    assert.deepEqual(tObj, received);
+  }
+
+};
+
+Object.keys(cases).forEach(function(caseName) {
+  QUnit.test(caseName, cases[caseName]);
+});
diff --git a/lib/js/test/jsTestDriver.conf b/lib/js/test/jsTestDriver.conf
index 22e62ea..eb1588c 100755
--- a/lib/js/test/jsTestDriver.conf
+++ b/lib/js/test/jsTestDriver.conf
@@ -5,8 +5,9 @@
   - build/js/lib/equiv.js
   - build/js/lib/QUnitAdapter.js
 # dependencies
-  - build/js/lib/jquery-1.5.2.js
+  - build/js/lib/jquery.js
   - build/js/thrift.js
+  - gen-js/DoubleConstantsTest_constants.js
   - gen-js/ThriftTest_types.js
   - gen-js/ThriftTest.js
 # the test suite
diff --git a/lib/js/test/phantom-client.js b/lib/js/test/phantom-client.js
new file mode 100644
index 0000000..d517e71
--- /dev/null
+++ b/lib/js/test/phantom-client.js
@@ -0,0 +1,382 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /* jshint -W100 */
+
+(function() {
+  'use strict';
+
+  // Rudimentary test helper functions
+  // TODO: Return error code based on kind of errors rather than throw
+  var ok = function(t, msg) {
+    if (!t) {
+      console.log('*** FAILED ***');
+      throw new Error(msg);
+    }
+  };
+  var equal = function(a, b) {
+    if (a !== b) {
+      console.log('*** FAILED ***');
+      throw new Error();
+    }
+  };
+  var test = function(name, f) {
+    console.log('TEST : ' + name);
+    f();
+    console.log('OK\n');
+  };
+
+  var parseArgs = function(args) {
+    var skips = [
+      '--transport=http',
+      '--protocol=json'
+    ];
+    var opts = {
+      port: '9090'
+      // protocol: 'json',
+    };
+    var keys = {};
+    for (var key in opts) {
+      keys['--' + key + '='] = key;
+    }
+    for (var i in args) {
+      var arg = args[i];
+      if (skips.indexOf(arg) != -1) {
+        continue;
+      }
+      var hit = false;
+      for (var k in keys) {
+        if (arg.slice(0, k.length) === k) {
+          opts[keys[k]] = arg.slice(k.length);
+          hit = true;
+          break;
+        }
+      }
+      if (!hit) {
+        throw new Error('Unknown argument: ' + arg);
+      }
+    }
+    opts.port = parseInt(opts.port, 10);
+    if (!opts.port || opts.port < 1 || opts.port > 65535) {
+      throw new Error('Invalid port number');
+    }
+    return opts;
+  };
+
+  var execute = function() {
+    console.log('### Apache Thrift Javascript standalone test client');
+    console.log('------------------------------------------------------------');
+
+    phantom.page.injectJs('src/thrift.js');
+    phantom.page.injectJs('test/gen-js/ThriftTest_types.js');
+    phantom.page.injectJs('test/gen-js/ThriftTest.js');
+
+    var system = require('system');
+    var opts = parseArgs(system.args.slice(1));
+    var port = opts.port;
+    var transport = new Thrift.Transport('http://localhost:' + port + '/service');
+    var protocol = new Thrift.Protocol(transport);
+    var client = new ThriftTest.ThriftTestClient(protocol);
+
+
+    // TODO: Remove duplicate code with test.js.
+    // all Languages in UTF-8
+    var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語";
+
+    function checkRecursively(map1, map2) {
+      if (typeof map1 !== 'function' && typeof map2 !== 'function') {
+        if (!map1 || typeof map1 !== 'object') {
+          equal(map1, map2);
+        } else {
+          for (var key in map1) {
+            checkRecursively(map1[key], map2[key]);
+          }
+        }
+      }
+    }
+
+    test('Void', function() {
+      equal(client.testVoid(), undefined);
+    });
+    test('Binary (String)', function() {
+      var binary = '';
+      for (var v = 255; v >= 0; --v) {
+        binary += String.fromCharCode(v);
+      }
+      equal(client.testBinary(binary), binary);
+    });
+    test('Binary (Uint8Array)', function() {
+      var binary = '';
+      for (var v = 255; v >= 0; --v) {
+        binary += String.fromCharCode(v);
+      }
+      var arr = new Uint8Array(binary.length);
+      for (var i = 0; i < binary.length; ++i) {
+        arr[i] = binary[i].charCodeAt();
+      }
+      equal(client.testBinary(arr), binary);
+    });
+    test('String', function() {
+      equal(client.testString(''), '');
+      equal(client.testString(stringTest), stringTest);
+
+      var specialCharacters = 'quote: \" backslash:' +
+        ' forwardslash-escaped: \/ ' +
+          ' backspace: \b formfeed: \f newline: \n return: \r tab: ' +
+            ' now-all-of-them-together: "\\\/\b\n\r\t' +
+              ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><';
+              equal(client.testString(specialCharacters), specialCharacters);
+    });
+    test('Double', function() {
+      equal(client.testDouble(0), 0);
+      equal(client.testDouble(-1), -1);
+      equal(client.testDouble(3.14), 3.14);
+      equal(client.testDouble(Math.pow(2, 60)), Math.pow(2, 60));
+    });
+    test('Bool', function() {
+      equal(client.testBool(true), true);
+      equal(client.testBool(false), false);
+    });
+    test('I8', function() {
+      equal(client.testByte(0), 0);
+      equal(client.testByte(0x01), 0x01);
+    });
+    test('I32', function() {
+      equal(client.testI32(0), 0);
+      equal(client.testI32(Math.pow(2, 30)), Math.pow(2, 30));
+      equal(client.testI32(-Math.pow(2, 30)), -Math.pow(2, 30));
+    });
+    test('I64', function() {
+      equal(client.testI64(0), 0);
+      //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+      equal(client.testI64(Math.pow(2, 52)), Math.pow(2, 52));
+      equal(client.testI64(-Math.pow(2, 52)), -Math.pow(2, 52));
+    });
+
+    test('Struct', function() {
+      var structTestInput = new ThriftTest.Xtruct();
+      structTestInput.string_thing = 'worked';
+      structTestInput.byte_thing = 0x01;
+      structTestInput.i32_thing = Math.pow(2, 30);
+      //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+      structTestInput.i64_thing = Math.pow(2, 52);
+
+      var structTestOutput = client.testStruct(structTestInput);
+
+      equal(structTestOutput.string_thing, structTestInput.string_thing);
+      equal(structTestOutput.byte_thing, structTestInput.byte_thing);
+      equal(structTestOutput.i32_thing, structTestInput.i32_thing);
+      equal(structTestOutput.i64_thing, structTestInput.i64_thing);
+
+      equal(JSON.stringify(structTestOutput), JSON.stringify(structTestInput));
+    });
+
+    test('Nest', function() {
+      var xtrTestInput = new ThriftTest.Xtruct();
+      xtrTestInput.string_thing = 'worked';
+      xtrTestInput.byte_thing = 0x01;
+      xtrTestInput.i32_thing = Math.pow(2, 30);
+      //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+      xtrTestInput.i64_thing = Math.pow(2, 52);
+
+      var nestTestInput = new ThriftTest.Xtruct2();
+      nestTestInput.byte_thing = 0x02;
+      nestTestInput.struct_thing = xtrTestInput;
+      nestTestInput.i32_thing = Math.pow(2, 15);
+
+      var nestTestOutput = client.testNest(nestTestInput);
+
+      equal(nestTestOutput.byte_thing, nestTestInput.byte_thing);
+      equal(nestTestOutput.struct_thing.string_thing, nestTestInput.struct_thing.string_thing);
+      equal(nestTestOutput.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing);
+      equal(nestTestOutput.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing);
+      equal(nestTestOutput.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing);
+      equal(nestTestOutput.i32_thing, nestTestInput.i32_thing);
+
+      equal(JSON.stringify(nestTestOutput), JSON.stringify(nestTestInput));
+    });
+
+    test('Map', function() {
+      var mapTestInput = {7: 77, 8: 88, 9: 99};
+
+      var mapTestOutput = client.testMap(mapTestInput);
+
+      for (var key in mapTestOutput) {
+        equal(mapTestOutput[key], mapTestInput[key]);
+      }
+    });
+
+    test('StringMap', function() {
+      var mapTestInput = {
+        'a': '123', 'a b': 'with spaces ', 'same': 'same', '0': 'numeric key',
+        'longValue': stringTest, stringTest: 'long key'
+      };
+
+      var mapTestOutput = client.testStringMap(mapTestInput);
+
+      for (var key in mapTestOutput) {
+        equal(mapTestOutput[key], mapTestInput[key]);
+      }
+    });
+
+    test('Set', function() {
+      var setTestInput = [1, 2, 3];
+      ok(client.testSet(setTestInput), setTestInput);
+    });
+
+    test('List', function() {
+      var listTestInput = [1, 2, 3];
+      ok(client.testList(listTestInput), listTestInput);
+    });
+
+    test('Enum', function() {
+      equal(client.testEnum(ThriftTest.Numberz.ONE), ThriftTest.Numberz.ONE);
+    });
+
+    test('TypeDef', function() {
+      equal(client.testTypedef(69), 69);
+    });
+
+    test('Skip', function() {
+      var structTestInput = new ThriftTest.Xtruct();
+      var modifiedClient = new ThriftTest.ThriftTestClient(protocol);
+
+      modifiedClient.recv_testStruct = function() {
+        var input = modifiedClient.input;
+        var xtruct3 = new ThriftTest.Xtruct3();
+
+        input.readMessageBegin();
+        input.readStructBegin();
+
+        // read Xtruct data with Xtruct3
+        input.readFieldBegin();
+        xtruct3.read(input);
+        input.readFieldEnd();
+        // read Thrift.Type.STOP message
+        input.readFieldBegin();
+        input.readFieldEnd();
+
+        input.readStructEnd();
+        input.readMessageEnd();
+
+        return xtruct3;
+      };
+
+      structTestInput.string_thing = 'worked';
+      structTestInput.byte_thing = 0x01;
+      structTestInput.i32_thing = Math.pow(2, 30);
+      structTestInput.i64_thing = Math.pow(2, 52);
+
+      var structTestOutput = modifiedClient.testStruct(structTestInput);
+
+      equal(structTestOutput instanceof ThriftTest.Xtruct3, true);
+      equal(structTestOutput.string_thing, structTestInput.string_thing);
+      equal(structTestOutput.changed, null);
+      equal(structTestOutput.i32_thing, structTestInput.i32_thing);
+      equal(structTestOutput.i64_thing, structTestInput.i64_thing);
+    });
+
+    test('MapMap', function() {
+      var mapMapTestExpectedResult = {
+        '4': {'1': 1, '2': 2, '3': 3, '4': 4},
+        '-4': {'-4': -4, '-3': -3, '-2': -2, '-1': -1}
+      };
+
+      var mapMapTestOutput = client.testMapMap(1);
+
+
+      for (var key in mapMapTestOutput) {
+        for (var key2 in mapMapTestOutput[key]) {
+          equal(mapMapTestOutput[key][key2], mapMapTestExpectedResult[key][key2]);
+        }
+      }
+
+      checkRecursively(mapMapTestOutput, mapMapTestExpectedResult);
+    });
+
+    test('Xception', function() {
+      try {
+        client.testException('Xception');
+        ok(false);
+      } catch (e) {
+        equal(e.errorCode, 1001);
+        equal(e.message, 'Xception');
+      }
+    });
+
+    test('no Exception', function() {
+      try {
+        client.testException('no Exception');
+      } catch (e) {
+        ok(false);
+      }
+    });
+
+    test('TException', function() {
+      try {
+        client.testException('TException');
+        ok(false);
+      } catch (e) {
+        ok(ok);
+      }
+    });
+
+    var crazy = {
+      'userMap': { '5': 5, '8': 8 },
+      'xtructs': [{
+        'string_thing': 'Goodbye4',
+        'byte_thing': 4,
+        'i32_thing': 4,
+        'i64_thing': 4
+      },
+      {
+        'string_thing': 'Hello2',
+        'byte_thing': 2,
+        'i32_thing': 2,
+        'i64_thing': 2
+      }]
+    };
+    test('Insanity', function() {
+      var insanity = {
+        '1': {
+          '2': crazy,
+          '3': crazy
+        },
+        '2': { '6': { 'userMap': null, 'xtructs': null } }
+      };
+      var res = client.testInsanity(new ThriftTest.Insanity(crazy));
+      ok(res, JSON.stringify(res));
+      ok(insanity, JSON.stringify(insanity));
+
+      checkRecursively(res, insanity);
+    });
+
+    console.log('------------------------------------------------------------');
+    console.log('### All tests succeeded.');
+    return 0;
+  };
+
+  try {
+    var ret = execute();
+    phantom.exit(ret);
+  } catch (err) {
+    // Catch all and exit to avoid hang.
+    console.error(err);
+    phantom.exit(1);
+  }
+})();
diff --git a/lib/js/test/phantomjs-qunit.js b/lib/js/test/phantomjs-qunit.js
index d52b522..c1d7a5b 100755
--- a/lib/js/test/phantomjs-qunit.js
+++ b/lib/js/test/phantomjs-qunit.js
@@ -1,3 +1,5 @@
+/*jshint evil:true*/
+
 /* This file is only used by the test suite.
  *
  * Origin:  https://github.com/ariya/phantomjs/blob/master/examples/run-qunit.js
@@ -6,6 +8,8 @@
  * Inclusion into Apache products is allowed according to http://www.apache.org/legal/3party.html
  */
 
+var system = require('system');
+
 
 /**
  * Wait until the test condition is true or a timeout occurs. Useful for waiting
@@ -24,26 +28,30 @@
         start = new Date().getTime(),
         condition = false,
         interval = setInterval(function() {
-            if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
+            if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) {
                 // If not time-out yet and condition not yet fulfilled
-                condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
+                condition = (typeof(testFx) === 'string' ? eval(testFx) : testFx()); //< defensive code
             } else {
-                if(!condition) {
+                if (!condition) {
                     // If condition still not fulfilled (timeout but condition is 'false')
                     console.log("'waitFor()' timeout");
                     phantom.exit(1);
                 } else {
                     // Condition fulfilled (timeout and/or condition is 'true')
-                    console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
-                    typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
+                    console.log("'waitFor()' finished in " + (new Date().getTime() - start) + 'ms.');
+                    if (typeof(onReady) === 'string') {
+                        eval(onReady);
+                    } else {
+                        onReady(); //< Do what it's supposed to do once the condition is fulfilled
+                    }
                     clearInterval(interval); //< Stop this interval
                 }
             }
         }, 100); //< repeat check every 250ms
-};
+}
 
 
-if (phantom.args.length === 0 || phantom.args.length > 2) {
+if (system.args.length === 1 || system.args.length > 3) {
     console.log('Usage: phantomjs phantomjs-qunit.js URL');
     phantom.exit(1);
 }
@@ -55,21 +63,21 @@
     console.log(msg);
 };
 
-page.open(phantom.args[0], function(status){
-    if (status !== "success") {
-        console.log("Unable to access network");
+page.open(system.args[1], function(status) {
+    if (status !== 'success') {
+        console.log('Unable to access network');
         phantom.exit(1);
     } else {
-        waitFor(function(){
-            return page.evaluate(function(){
+        waitFor(function() {
+            return page.evaluate(function() {
                 var el = document.getElementById('qunit-testresult');
                 if (el && el.innerText.match('completed')) {
                     return true;
                 }
                 return false;
             });
-        }, function(){
-            var failedNum = page.evaluate(function(){
+        }, function() {
+            var failedNum = page.evaluate(function() {
                 var el = document.getElementById('qunit-testresult');
                 console.log(el.innerText);
                 try {
diff --git a/lib/js/test/server_http.js b/lib/js/test/server_http.js
new file mode 100644
index 0000000..8380c3a
--- /dev/null
+++ b/lib/js/test/server_http.js
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//  This HTTP server is designed to serve the test.html browser
+//  based JavaScript test page (which must be in the current directory).
+//  This server also supplies the Thrift based test service, which depends
+//  on the standard ThriftTest.thrift IDL service (which must be compiled
+//  for Node and browser based JavaScript in ./gen-nodejs and ./gen-js
+//  respectively).
+//
+//  Using the command flag --es6, this server can be run using nodejs code built
+//  for the es6 environment or for pre-es6 environment.
+//
+
+const thrift = require('../../nodejs/lib/thrift');
+const es6Mode = process.argv.includes('--es6');
+const genFolder = es6Mode ? 'gen-nodejs-es6' : 'gen-nodejs';
+const ThriftTestSvc = require(`./${genFolder}/ThriftTest.js`);
+const ThriftTestHandler = require('./test_handler').ThriftTestHandler;
+
+const ThriftTestSvcOpt = {
+	transport: thrift.TBufferedTransport,
+	protocol: thrift.TJSONProtocol,
+	processor: ThriftTestSvc,
+	handler: ThriftTestHandler
+};
+
+const ThriftWebServerOptions = {
+	files: __dirname,
+	services: {
+		'/service': ThriftTestSvcOpt
+	}
+};
+
+const server = thrift.createWebServer(ThriftWebServerOptions);
+const port = es6Mode ? 8088 : 8089;
+server.listen(port);
+console.log(`Serving files from: ${__dirname}`);
+console.log(`Http/Thrift Server (ES6 mode ${es6Mode}) running on port: ${port}`);
diff --git a/lib/js/test/server_https.js b/lib/js/test/server_https.js
new file mode 100644
index 0000000..1a171dd
--- /dev/null
+++ b/lib/js/test/server_https.js
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//This HTTP server is designed to server the test.html browser
+//  based JavaScript test page (which must be in the current directory).
+//  This server also supplies the Thrift based test service, which depends
+//  on the standard ThriftTest.thrift IDL service (which must be compiled
+//  for Node and browser based JavaScript in ./gen-nodejs and ./gen-js
+//  respectively). The current directory must also include the browser
+//  support libraries for test.html (jquery.js, qunit.js and qunit.css
+//  in ./build/js/lib).
+
+const fs = require('fs');
+const thrift = require('../../nodejs/lib/thrift');
+const es6Mode = process.argv.includes('--es6');
+const genFolder = es6Mode ? 'gen-nodejs-es6' : 'gen-nodejs';
+const ThriftTestSvc = require(`./${genFolder}/ThriftTest.js`);
+const ThriftTestHandler = require('./test_handler').ThriftTestHandler;
+
+//Setup the I/O stack options for the ThriftTest service
+const ThriftTestSvcOpt = {
+  transport: thrift.TBufferedTransport,
+  protocol: thrift.TJSONProtocol,
+  processor: ThriftTestSvc,
+  handler: ThriftTestHandler
+};
+
+const ThriftWebServerOptions = {
+  files: __dirname,
+  tls: {
+     key: fs.readFileSync('../../../test/keys/server.key'),
+     cert: fs.readFileSync('../../../test/keys/server.crt')
+  },
+  services: {
+    '/service': ThriftTestSvcOpt
+  }
+};
+
+const server = thrift.createWebServer(ThriftWebServerOptions);
+const port = es6Mode ? 8090 : 8091;
+server.listen(port);
+console.log(`Serving files from: ${__dirname}`);
+console.log(`Http/Thrift Server (ES6 mode ${es6Mode}) running on port: ${port}`);
diff --git a/lib/js/test/src/test/Httpd.java b/lib/js/test/src/test/Httpd.java
index f1291d8..e4fc0cc 100644
--- a/lib/js/test/src/test/Httpd.java
+++ b/lib/js/test/src/test/Httpd.java
@@ -183,16 +183,18 @@
 
                 } else {
 
-		    String mimeType = "application/octet-stream";
-		    MimeUtil2 mimeUtil = new MimeUtil2();
-		    mimeUtil.registerMimeDetector(ExtensionMimeDetector.class.getName());
-		    Collection<MimeType> collection = mimeUtil.getMimeTypes(file);
-		    Iterator<MimeType> iterator = collection.iterator();
-		    while(iterator.hasNext()) {
-			MimeType mt = iterator.next();
-			mimeType =  mt.getMediaType() + "/" + mt.getSubType();
-			break;
-		    }
+                    String mimeType = "application/octet-stream";
+                    MimeUtil2 mimeUtil = new MimeUtil2();
+                    synchronized (this) {
+                        mimeUtil.registerMimeDetector(ExtensionMimeDetector.class.getName());
+                    }
+                    Collection<MimeType> collection = mimeUtil.getMimeTypes(file);
+                    Iterator<MimeType> iterator = collection.iterator();
+                    while(iterator.hasNext()) {
+                        MimeType mt = iterator.next();
+                        mimeType =  mt.getMediaType() + "/" + mt.getSubType();
+                        break;
+                    }
 
                     response.setStatusCode(HttpStatus.SC_OK);
                     FileEntity body = new FileEntity(file, mimeType);
diff --git a/lib/js/test/test-async.js b/lib/js/test/test-async.js
new file mode 100644
index 0000000..8c6b13e
--- /dev/null
+++ b/lib/js/test/test-async.js
@@ -0,0 +1,370 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /* jshint -W100 */
+
+/*
+ * Fully Async JavaScript test suite for ThriftTest.thrift.
+ * These tests are designed to exercise the WebSocket transport
+ * (which is exclusively async).
+ *
+ * To compile client code for this test use:
+ *      $ thrift -gen js ThriftTest.thrift
+ */
+
+
+
+// all Languages in UTF-8
+const stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語";
+
+function checkRecursively(assert, map1, map2) {
+  if (typeof map1 !== 'function' && typeof map2 !== 'function') {
+    if (!map1 || typeof map1 !== 'object') {
+        assert.equal(map1, map2);
+    } else {
+      for (let key in map1) {
+        checkRecursively(assert, map1[key], map2[key]);
+      }
+    }
+  }
+}
+
+QUnit.module('Base Types');
+
+  QUnit.test('Void', function(assert) {
+    assert.expect(1);
+    const done = assert.async();
+    client.testVoid(function(result) {
+      assert.equal(result, undefined);
+      done();
+    });
+  });
+
+
+  QUnit.test('String', function(assert) {
+    assert.expect(3);
+    const done = assert.async(3);
+    client.testString('', function(result) {
+       assert.equal(result, '');
+       done();
+    });
+    client.testString(stringTest, function(result) {
+       assert.equal(result, stringTest);
+       done();
+    });
+
+    const specialCharacters = 'quote: \" backslash:' +
+          ' forwardslash-escaped: \/ ' +
+          ' backspace: \b formfeed: \f newline: \n return: \r tab: ' +
+          ' now-all-of-them-together: "\\\/\b\n\r\t' +
+          ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><';
+    client.testString(specialCharacters, function(result) {
+       assert.equal(result, specialCharacters);
+       done();
+    });
+  });
+  QUnit.test('Double', function(assert) {
+    assert.expect(4);
+    const done = assert.async(4);
+    client.testDouble(0, function(result) {
+       assert.equal(result, 0);
+       done();
+    });
+    client.testDouble(-1, function(result) {
+       assert.equal(result, -1);
+       done();
+    });
+    client.testDouble(3.14, function(result) {
+       assert.equal(result, 3.14);
+       done();
+    });
+    client.testDouble(Math.pow(2, 60), function(result) {
+       assert.equal(result, Math.pow(2, 60));
+       done();
+    });
+  });
+  // TODO: add testBinary()
+  QUnit.test('Byte', function(assert) {
+    assert.expect(2);
+    const done = assert.async(2);
+    client.testByte(0, function(result) {
+       assert.equal(result, 0);
+       done();
+    });
+    client.testByte(0x01, function(result) {
+       assert.equal(result, 0x01);
+       done();
+    });
+  });
+  QUnit.test('I32', function(assert) {
+    assert.expect(3);
+    const done = assert.async(3);
+    client.testI32(0, function(result) {
+       assert.equal(result, 0);
+       done();
+    });
+    client.testI32(Math.pow(2, 30), function(result) {
+       assert.equal(result, Math.pow(2, 30));
+       done();
+    });
+    client.testI32(-Math.pow(2, 30), function(result) {
+       assert.equal(result, -Math.pow(2, 30));
+       done();
+    });
+  });
+  QUnit.test('I64', function(assert) {
+    assert.expect(3);
+    const done = assert.async(3);
+    client.testI64(0, function(result) {
+       assert.equal(result, 0);
+       done();
+    });
+    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+    client.testI64(Math.pow(2, 52), function(result) {
+       assert.equal(result, Math.pow(2, 52));
+       done();
+    });
+    client.testI64(-Math.pow(2, 52), function(result) {
+       assert.equal(result, -Math.pow(2, 52));
+       done();
+    });
+  });
+
+
+
+
+QUnit.module('Structured Types');
+
+  QUnit.test('Struct', function(assert) {
+    assert.expect(5);
+    const done = assert.async();
+    const structTestInput = new ThriftTest.Xtruct();
+    structTestInput.string_thing = 'worked';
+    structTestInput.byte_thing = 0x01;
+    structTestInput.i32_thing = Math.pow(2, 30);
+    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+    structTestInput.i64_thing = Math.pow(2, 52);
+
+    client.testStruct(structTestInput, function(result) {
+      assert.equal(result.string_thing, structTestInput.string_thing);
+      assert.equal(result.byte_thing, structTestInput.byte_thing);
+      assert.equal(result.i32_thing, structTestInput.i32_thing);
+      assert.equal(result.i64_thing, structTestInput.i64_thing);
+      assert.equal(JSON.stringify(result), JSON.stringify(structTestInput));
+      done();
+    });
+  });
+
+  QUnit.test('Nest', function(assert) {
+    assert.expect(7);
+    const done = assert.async();
+    const xtrTestInput = new ThriftTest.Xtruct();
+    xtrTestInput.string_thing = 'worked';
+    xtrTestInput.byte_thing = 0x01;
+    xtrTestInput.i32_thing = Math.pow(2, 30);
+    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+    xtrTestInput.i64_thing = Math.pow(2, 52);
+
+    const nestTestInput = new ThriftTest.Xtruct2();
+    nestTestInput.byte_thing = 0x02;
+    nestTestInput.struct_thing = xtrTestInput;
+    nestTestInput.i32_thing = Math.pow(2, 15);
+
+    client.testNest(nestTestInput, function(result) {
+      assert.equal(result.byte_thing, nestTestInput.byte_thing);
+      assert.equal(result.struct_thing.string_thing, nestTestInput.struct_thing.string_thing);
+      assert.equal(result.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing);
+      assert.equal(result.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing);
+      assert.equal(result.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing);
+      assert.equal(result.i32_thing, nestTestInput.i32_thing);
+      assert.equal(JSON.stringify(result), JSON.stringify(nestTestInput));
+      done();
+    });
+  });
+
+  QUnit.test('Map', function(assert) {
+    assert.expect(3);
+    const done = assert.async();
+    const mapTestInput = {7: 77, 8: 88, 9: 99};
+
+    client.testMap(mapTestInput, function(result) {
+      for (let key in result) {
+        assert.equal(result[key], mapTestInput[key]);
+      }
+      done();
+    });
+  });
+
+  QUnit.test('StringMap', function(assert) {
+    assert.expect(6);
+    const done = assert.async();
+    const mapTestInput = {
+      'a': '123', 'a b': 'with spaces ', 'same': 'same', '0': 'numeric key',
+      'longValue': stringTest, stringTest: 'long key'
+    };
+
+    client.testStringMap(mapTestInput, function(result) {
+      for (let key in result) {
+        assert.equal(result[key], mapTestInput[key]);
+      }
+      done();
+    });
+  });
+
+  QUnit.test('Set', function(assert) {
+    assert.expect(1);
+    const done = assert.async();
+    const setTestInput = [1, 2, 3];
+    client.testSet(setTestInput, function(result) {
+      assert.ok(result, setTestInput);
+      done();
+    });
+  });
+
+  QUnit.test('List', function(assert) {
+    assert.expect(1);
+    const done = assert.async();
+    const listTestInput = [1, 2, 3];
+    client.testList(listTestInput, function(result) {
+      assert.ok(result, listTestInput);
+      done();
+    });
+  });
+
+  QUnit.test('Enum', function(assert) {
+    assert.expect(1);
+    const done = assert.async();
+    client.testEnum(ThriftTest.Numberz.ONE, function(result) {
+      assert.equal(result, ThriftTest.Numberz.ONE);
+      done();
+    });
+  });
+
+  QUnit.test('TypeDef', function(assert) {
+    assert.expect(1);
+    const done = assert.async();
+    client.testTypedef(69, function(result) {
+      assert.equal(result, 69);
+      done();
+    });
+  });
+
+
+QUnit.module('deeper!');
+
+  QUnit.test('MapMap', function(assert) {
+    assert.expect(16);
+    const done = assert.async();
+    const mapMapTestExpectedResult = {
+      '4': {'1': 1, '2': 2, '3': 3, '4': 4},
+      '-4': {'-4': -4, '-3': -3, '-2': -2, '-1': -1}
+    };
+
+    client.testMapMap(1, function(result) {
+      for (let key in result) {
+        for (let key2 in result[key]) {
+          assert.equal(result[key][key2], mapMapTestExpectedResult[key][key2]);
+        }
+      }
+      checkRecursively(assert, result, mapMapTestExpectedResult);
+      done();
+    });
+  });
+
+
+QUnit.module('Exception');
+
+  QUnit.test('Xception', function(assert) {
+    assert.expect(2);
+    const done = assert.async();
+    client.testException('Xception', function(e) {
+      assert.equal(e.errorCode, 1001);
+      assert.equal(e.message, 'Xception');
+      done();
+    });
+  });
+
+  QUnit.test('no Exception', function(assert) {
+    assert.expect(1);
+    const done = assert.async();
+    client.testException('no Exception', function(e) {
+      assert.ok(!e);
+      done();
+    });
+  });
+
+QUnit.module('Insanity');
+
+  QUnit.test('testInsanity', function(assert) {
+    assert.expect(24);
+    const done = assert.async();
+    const insanity = {
+      '1': {
+        '2': {
+          'userMap': { '5': 5, '8': 8 },
+          'xtructs': [{
+              'string_thing': 'Goodbye4',
+              'byte_thing': 4,
+              'i32_thing': 4,
+              'i64_thing': 4
+            },
+            {
+              'string_thing': 'Hello2',
+              'byte_thing': 2,
+              'i32_thing': 2,
+              'i64_thing': 2
+            }
+          ]
+        },
+        '3': {
+          'userMap': { '5': 5, '8': 8 },
+          'xtructs': [{
+              'string_thing': 'Goodbye4',
+              'byte_thing': 4,
+              'i32_thing': 4,
+              'i64_thing': 4
+            },
+            {
+              'string_thing': 'Hello2',
+              'byte_thing': 2,
+              'i32_thing': 2,
+              'i64_thing': 2
+            }
+          ]
+        }
+      },
+      '2': { '6': { 'userMap': null, 'xtructs': null } }
+    };
+    client.testInsanity(new ThriftTest.Insanity(), function(res) {
+      assert.ok(res, JSON.stringify(res));
+      assert.ok(insanity, JSON.stringify(insanity));
+      checkRecursively(assert, res, insanity);
+      done();
+    });
+  });
+
+QUnit.module('Oneway');
+
+  QUnit.test('testOneway', function(assert) {
+    assert.expect(1);
+    const done = assert.async();
+    client.testOneway(1, function(result) {
+      assert.equal(result, undefined);
+      done();
+    });
+  });
diff --git a/lib/js/test/test-deep-constructor.html b/lib/js/test/test-deep-constructor.html
new file mode 100755
index 0000000..dfc0da6
--- /dev/null
+++ b/lib/js/test/test-deep-constructor.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  <title>Thrift Javascript Bindings: Unit Test</title>
+
+  <script src="build/js/thrift.js"         type="text/javascript" charset="utf-8"></script>
+  <script src="gen-js/JsDeepConstructorTest_types.js" type="text/javascript" charset="utf-8"></script>
+  <!-- jQuery -->
+  <script type="text/javascript" src="build/js/lib/jquery.js" charset="utf-8"></script>
+
+  <!-- QUnit Test framework-->
+	<script type="text/javascript" src="build/js/lib/qunit.js" charset="utf-8"></script>
+	<link rel="stylesheet" href="build/js/lib/qunit.css" type="text/css" media="screen" />
+
+  <!-- the Test Suite-->
+  <script type="text/javascript" src="deep-constructor.test.js" charset="utf-8"></script>
+</head>
+<body>
+  <h1 id="qunit-header">Thrift Javascript Bindings: Deep Constructor Test (<a href="https://github.com/apache/thrift/blob/master/test/JsDeepConstructorTest.thrift">JsDeepConstructorTest.thrift</a>)</h1>
+  <h2 id="qunit-banner"></h2>
+  <div id="qunit-testrunner-toolbar"></div>
+  <h2 id="qunit-userAgent"></h2>
+  <ol id="qunit-tests"><li><!-- get valid xhtml strict--></li></ol>
+  <p>
+      <a href="http://validator.w3.org/check/referer"><img
+          src="http://www.w3.org/Icons/valid-xhtml10"
+          alt="Valid XHTML 1.0!" height="31" width="88" /></a>
+  </p>
+</body>
+</html>
diff --git a/lib/js/test/test-double-rendering.html b/lib/js/test/test-double-rendering.html
new file mode 100644
index 0000000..7a430a5
--- /dev/null
+++ b/lib/js/test/test-double-rendering.html
@@ -0,0 +1,55 @@
++<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+      <title>Rendering Double Constants in JS: Unit Test</title>
+
+      <script src="build/js/thrift.js"         type="text/javascript" charset="utf-8"></script>
+      <script src="gen-js/ThriftTest_types.js" type="text/javascript" charset="utf-8"></script>
+      <script src="gen-js/ThriftTest.js"       type="text/javascript" charset="utf-8"></script>
+      <!-- double constants to check -->
+      <script src="gen-js/DoubleConstantsTest_types.js"         type="text/javascript" charset="utf-8"></script>
+
+      <!-- jQuery -->
+      <script type="text/javascript" src="build/js/lib/jquery.js" charset="utf-8"></script>
+
+      <!-- QUnit Test framework-->
+      <script type="text/javascript" src="build/js/lib/qunit.js" charset="utf-8"></script>
+      <link rel="stylesheet" href="build/js/lib/qunit.css" type="text/css" media="screen" />
+
+      <!-- the Test Suite-->
+      <script type="text/javascript" src="test-double-rendering.js" charset="utf-8"></script>
+    </head>
+<body>
+  <h1 id="qunit-header">Rendering Double Constants in JS: Unit Test</h1>
+  <h2 id="qunit-banner"></h2>
+  <div id="qunit-testrunner-toolbar"></div>
+  <h2 id="qunit-userAgent"></h2>
+  <ol id="qunit-tests"><li><!-- get valid xhtml strict--></li></ol>
+  <!-- Uncomment this to check the validity. This significantly slows down the test.
+  <p>
+      <a href="http://validator.w3.org/check/referer"><img
+          src="http://www.w3.org/Icons/valid-xhtml10"
+          alt="Valid XHTML 1.0!" height="31" width="88" /></a>
+  </p>
+  -->
+</body>
+</html>
diff --git a/lib/js/test/test-double-rendering.js b/lib/js/test/test-double-rendering.js
new file mode 100644
index 0000000..1790c1b
--- /dev/null
+++ b/lib/js/test/test-double-rendering.js
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /* jshint -W100 */
+
+/*
+ * JavaScript test suite for double constants inside
+ * DoubleConstantsTest.thrift. These tests will run against Normal (-gen js)
+ * Apache Thrift interfaces.
+ *
+ * To compile client code for this test use:
+ *      $ thrift -gen js DoubleConstantsTest.thrift
+ */
+
+// double assertion threshold
+const EPSILON = 0.0000001;
+
+// Work around for old API used by QUnitAdapter of jsTestDriver
+if (typeof QUnit.log == 'function') {
+  // When using real QUnit (fron PhantomJS) log failures to console
+  QUnit.log(function(details) {
+    if (!details.result) {
+      console.log('======== FAIL ========');
+      console.log('TestName: ' + details.name);
+      if (details.message) console.log(details.message);
+      console.log('Expected: ' + details.expected);
+      console.log('Actual  : ' + details.actual);
+      console.log('======================');
+    }
+  });
+}
+
+QUnit.module('Double rendering');
+
+  QUnit.test('Double (rendering)', function(assert) {
+    console.log('Double rendering test -- starts');
+    const EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT = 1;
+    const EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT = -100;
+    const EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT = 9223372036854775807;
+    const EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT = -9223372036854775807;
+    const EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS = 3.14159265359;
+    const EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE = 1000000.1;
+    const EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE = -1000000.1;
+    const EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE = 1.7e+308;
+    const EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE = 9223372036854775816.43;
+    const EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE = -1.7e+308;
+    const EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE = -9223372036854775816.43;
+    assert.ok(
+        Math.abs(EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT - DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST) <= EPSILON);
+    assert.ok(
+        Math.abs(
+            EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT -
+            DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST) <= EPSILON);
+    assert.ok(
+        Math.abs(
+            EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT -
+            DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST) <= EPSILON);
+    assert.ok(
+        Math.abs(
+            EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT -
+            DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST) <= EPSILON);
+    assert.ok(
+        Math.abs(
+            EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS -
+            DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST) <= EPSILON);
+    assert.ok(
+        Math.abs(
+            EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE -
+            DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST) <= EPSILON);
+    assert.ok(
+        Math.abs(
+            EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE -
+            DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST) <= EPSILON);
+    assert.ok(
+        Math.abs(
+            EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE -
+            DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST) <= EPSILON);
+    assert.ok(
+        Math.abs(
+            EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE -
+            DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST) <= EPSILON);
+    assert.ok(
+        Math.abs(
+            EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE -
+            DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST) <= EPSILON);
+    assert.ok(
+        Math.abs(
+            EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE -
+            DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST) <= EPSILON);
+    assert.equal(typeof DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST, 'number');
+    assert.equal(typeof DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST, 'number');
+    assert.equal(typeof DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST, 'number');
+    assert.equal(typeof DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST, 'number');
+    assert.equal(typeof DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST, 'number');
+    assert.equal(typeof DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST, 'number');
+    assert.equal(typeof DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST, 'number');
+    assert.equal(typeof DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST, 'number');
+    assert.equal(typeof DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST, 'number');
+    assert.equal(typeof DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST, 'number');
+    assert.equal(typeof DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST, 'number');
+    const EXPECTED_DOUBLE_LIST =
+        [1,-100,100,9223372036854775807,-9223372036854775807,3.14159265359,1000000.1,-1000000.1,1.7e+308,-1.7e+308,
+            9223372036854775816.43,-9223372036854775816.43];
+    assert.equal(DOUBLE_LIST_TEST.length, EXPECTED_DOUBLE_LIST.length);
+    for (let i = 0; i < EXPECTED_DOUBLE_LIST.length; ++i) {
+           assert.ok(Math.abs(EXPECTED_DOUBLE_LIST[i] - DOUBLE_LIST_TEST[i]) <= EPSILON);
+    }
+    console.log('Double rendering test -- ends');
+  });
+
diff --git a/lib/js/test/test-es6.html b/lib/js/test/test-es6.html
new file mode 100644
index 0000000..bf04901
--- /dev/null
+++ b/lib/js/test/test-es6.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  <title>Thrift Javascript Bindings: Unit Test</title>
+
+  <script src="build/js/thrift.js"         type="text/javascript" charset="utf-8"></script>
+  <script src="gen-js-es6/ThriftTest_types.js" type="text/javascript" charset="utf-8"></script>
+  <script src="gen-js-es6/ThriftTest.js"       type="text/javascript" charset="utf-8"></script>
+
+  <!-- jQuery -->
+  <script type="text/javascript" src="build/js/lib/jquery.js" charset="utf-8"></script>
+
+  <!-- QUnit Test framework-->
+  <script type="text/javascript" src="build/js/lib/qunit.js" charset="utf-8"></script>
+  <link rel="stylesheet" href="build/js/lib/qunit.css" type="text/css" media="screen" />
+
+  <!-- the Test Suite-->
+  <script>
+    const loc = window.location;
+    const ws_uri = ((loc.protocol === "https:") ? "wss://" : "ws://") +
+                   loc.hostname + ":" + loc.port + loc.pathname;
+    const transport = new Thrift.TWebSocketTransport(ws_uri);
+    const protocol  = new Thrift.Protocol(transport);
+    const client    = new ThriftTest.ThriftTestClient(protocol);
+    transport.open();
+  </script>
+  <script type="text/javascript" src="test-es6.js" charset="utf-8"></script>
+</head>
+<body>
+  <h1 id="qunit-header">Thrift Javascript Bindings: Unit Test (<a href="https://github.com/apache/thrift/blob/master/test/ThriftTest.thrift">ThriftTest.thrift</a>)</h1>
+  <h2 id="qunit-banner"></h2>
+  <div id="qunit-testrunner-toolbar"></div>
+  <h2 id="qunit-userAgent"></h2>
+  <ol id="qunit-tests"><li><!-- get valid xhtml strict--></li></ol>
+  <!-- Uncomment this to check the validity. This significantly slows down the test.
+  <p>
+      <a href="http://validator.w3.org/check/referer"><img
+          src="http://www.w3.org/Icons/valid-xhtml10"
+          alt="Valid XHTML 1.0!" height="31" width="88" /></a>
+  </p>
+  -->
+</body>
+</html>
diff --git a/lib/js/test/test-es6.js b/lib/js/test/test-es6.js
new file mode 100644
index 0000000..845171b
--- /dev/null
+++ b/lib/js/test/test-es6.js
@@ -0,0 +1,374 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /* jshint -W100 */
+
+/*
+ * Fully Async JavaScript test suite for ThriftTest.thrift.
+ * These tests are designed to exercise the WebSocket transport
+ * (which is exclusively async).
+ *
+ * To compile client code for this test use:
+ *      $ thrift -gen js:es6 ThriftTest.thrift
+ */
+
+
+
+// all Languages in UTF-8
+
+const stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語";
+
+function checkRecursively(assert, map1, map2) {
+  if (typeof map1 !== 'function' && typeof map2 !== 'function') {
+    if (!map1 || typeof map1 !== 'object') {
+        assert.equal(map1, map2);
+    } else {
+      for (var key in map1) {
+        checkRecursively(assert, map1[key], map2[key]);
+      }
+    }
+  }
+}
+
+QUnit.module('Base Types');
+
+  QUnit.test('Void', function( assert ) {
+    assert.expect(1);
+    const done = assert.async();
+    client.testVoid().then(function(result) {
+      assert.equal(result, undefined);
+      done();
+    });
+  });
+
+  QUnit.test('String', function( assert ) {
+    assert.expect(3);
+    const done = assert.async(3);
+    client.testString('').then(function(result) {
+       assert.equal(result, '');
+       done();
+    });
+    client.testString(stringTest).then(function(result) {
+       assert.equal(result, stringTest);
+       done();
+    });
+    var specialCharacters = 'quote: \" backslash:' +
+          ' forwardslash-escaped: \/ ' +
+          ' backspace: \b formfeed: \f newline: \n return: \r tab: ' +
+          ' now-all-of-them-together: "\\\/\b\n\r\t' +
+          ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><';
+    client.testString(specialCharacters).then(function(result) {
+       assert.equal(result, specialCharacters);
+       done();
+    });
+  });
+
+  QUnit.test('Double', function( assert ) {
+    assert.expect(4);
+    const done = assert.async(4);
+    client.testDouble(0).then(function(result) {
+       assert.equal(result, 0);
+       done();
+    });
+    client.testDouble(-1).then(function(result) {
+       assert.equal(result, -1);
+       done();
+    });
+    client.testDouble(3.14).then(function(result) {
+       assert.equal(result, 3.14);
+       done();
+    });
+    client.testDouble(Math.pow(2, 60)).then(function(result) {
+       assert.equal(result, Math.pow(2, 60));
+       done();
+    });
+  });
+  // TODO: add testBinary()
+  QUnit.test('Byte', function( assert ) {
+    assert.expect(2);
+    const done = assert.async(2);
+    client.testByte(0).then(function(result) {
+       assert.equal(result, 0);
+       done();
+    });
+    client.testByte(0x01).then(function(result) {
+       assert.equal(result, 0x01);
+       done();
+    });
+  });
+  QUnit.test('I32', function( assert ) {
+    assert.expect(3);
+    const done = assert.async(3);
+    client.testI32(0).then(function(result) {
+       assert.equal(result, 0);
+       done();
+    });
+    client.testI32(Math.pow(2, 30)).then(function(result) {
+       assert.equal(result, Math.pow(2, 30));
+       done();
+    });
+    client.testI32(-Math.pow(2, 30)).then(function(result) {
+       assert.equal(result, -Math.pow(2, 30));
+       done();
+    });
+  });
+  QUnit.test('I64', function( assert ) {
+    assert.expect(3);
+    const done = assert.async(3);
+    client.testI64(0).then(function(result) {
+       assert.equal(result, 0);
+       done();
+    });
+    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+    client.testI64(Math.pow(2, 52)).then(function(result) {
+       assert.equal(result, Math.pow(2, 52));
+       done();
+    });
+    client.testI64(-Math.pow(2, 52)).then(function(result) {
+       assert.equal(result, -Math.pow(2, 52));
+       done();
+    });
+  });
+
+
+QUnit.module('Structured Types');
+
+  QUnit.test('Struct', function( assert ) {
+    assert.expect(5);
+    const done = assert.async();
+    var structTestInput = new ThriftTest.Xtruct();
+    structTestInput.string_thing = 'worked';
+    structTestInput.byte_thing = 0x01;
+    structTestInput.i32_thing = Math.pow(2, 30);
+    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+    structTestInput.i64_thing = Math.pow(2, 52);
+
+    client.testStruct(structTestInput).then(function(result) {
+      assert.equal(result.string_thing, structTestInput.string_thing);
+      assert.equal(result.byte_thing, structTestInput.byte_thing);
+      assert.equal(result.i32_thing, structTestInput.i32_thing);
+      assert.equal(result.i64_thing, structTestInput.i64_thing);
+      assert.equal(JSON.stringify(result), JSON.stringify(structTestInput));
+      done();
+    });
+  });
+
+  QUnit.test('Nest', function( assert ) {
+    assert.expect(7);
+    const done = assert.async();
+    var xtrTestInput = new ThriftTest.Xtruct();
+    xtrTestInput.string_thing = 'worked';
+    xtrTestInput.byte_thing = 0x01;
+    xtrTestInput.i32_thing = Math.pow(2, 30);
+    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+    xtrTestInput.i64_thing = Math.pow(2, 52);
+
+    var nestTestInput = new ThriftTest.Xtruct2();
+    nestTestInput.byte_thing = 0x02;
+    nestTestInput.struct_thing = xtrTestInput;
+    nestTestInput.i32_thing = Math.pow(2, 15);
+
+    client.testNest(nestTestInput).then(function(result) {
+      assert.equal(result.byte_thing, nestTestInput.byte_thing);
+      assert.equal(result.struct_thing.string_thing, nestTestInput.struct_thing.string_thing);
+      assert.equal(result.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing);
+      assert.equal(result.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing);
+      assert.equal(result.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing);
+      assert.equal(result.i32_thing, nestTestInput.i32_thing);
+      assert.equal(JSON.stringify(result), JSON.stringify(nestTestInput));
+      done();
+    });
+  });
+
+  QUnit.test('Map', function( assert ) {
+    assert.expect(3);
+    const done = assert.async();
+    var mapTestInput = {7: 77, 8: 88, 9: 99};
+
+    client.testMap(mapTestInput).then(function(result) {
+      for (var key in result) {
+        assert.equal(result[key], mapTestInput[key]);
+      }
+      done();
+    });
+  });
+
+  QUnit.test('StringMap', function( assert ) {
+    assert.expect(6);
+    const done = assert.async();
+    var mapTestInput = {
+      'a': '123', 'a b': 'with spaces ', 'same': 'same', '0': 'numeric key',
+      'longValue': stringTest, stringTest: 'long key'
+    };
+
+    client.testStringMap(mapTestInput).then(function(result) {
+      for (var key in result) {
+        assert.equal(result[key], mapTestInput[key]);
+      }
+      done();
+    });
+  });
+
+  QUnit.test('Set', function( assert ) {
+    assert.expect(1);
+    const done = assert.async();
+    var setTestInput = [1, 2, 3];
+    client.testSet(setTestInput).then(function(result) {
+      assert.ok(result, setTestInput);
+      done();
+    });
+  });
+
+  QUnit.test('List', function( assert ) {
+    assert.expect(1);
+    const done = assert.async();
+    var listTestInput = [1, 2, 3];
+    client.testList(listTestInput).then(function(result) {
+      assert.ok(result, listTestInput);
+      done();
+    });
+  });
+
+  QUnit.test('Enum', function( assert ) {
+    assert.expect(1);
+    const done = assert.async();
+    client.testEnum(ThriftTest.Numberz.ONE).then(function(result) {
+      assert.equal(result, ThriftTest.Numberz.ONE);
+      done();
+    });
+  });
+
+  QUnit.test('TypeDef', function( assert ) {
+    assert.expect(1);
+    const done = assert.async();
+    client.testTypedef(69).then(function(result) {
+      assert.equal(result, 69);
+      done();
+    });
+  });
+
+
+QUnit.module('deeper!');
+
+  QUnit.test('MapMap', function( assert ) {
+    assert.expect(16);
+    const done = assert.async();
+    var mapMapTestExpectedResult = {
+      '4': {'1': 1, '2': 2, '3': 3, '4': 4},
+      '-4': {'-4': -4, '-3': -3, '-2': -2, '-1': -1}
+    };
+
+    client.testMapMap(1).then(function(result) {
+      for (var key in result) {
+        for (var key2 in result[key]) {
+          assert.equal(result[key][key2], mapMapTestExpectedResult[key][key2]);
+        }
+      }
+      checkRecursively(assert, result, mapMapTestExpectedResult);
+      done();
+    });
+  });
+
+
+QUnit.module('Exception');
+
+  QUnit.test('Xception', function( assert ) {
+    assert.expect(2);
+    const done = assert.async();
+    client.testException('Xception').then(function(res) {
+      assert.ok(false);
+    }).catch(function(e) {
+
+      console.log(`Exception exception e`);
+      console.log(e);
+      console.log(JSON.stringify(e, null, 2));
+
+      assert.equal(e.errorCode, 1001);
+      assert.equal(e.message, 'Xception');
+      done();
+    });
+  });
+
+  QUnit.test('no Exception', function( assert ) {
+    assert.expect(1);
+    const done = assert.async();
+    client.testException('no Exception').then(function(e) {
+      assert.ok(!e);
+      done();
+    });
+  });
+
+QUnit.module('Insanity');
+
+  QUnit.test('testInsanity', function( assert ) {
+    assert.expect(24);
+    const done = assert.async();
+    var insanity = {
+      '1': {
+        '2': {
+          'userMap': { '5': 5, '8': 8 },
+          'xtructs': [{
+              'string_thing': 'Goodbye4',
+              'byte_thing': 4,
+              'i32_thing': 4,
+              'i64_thing': 4
+            },
+            {
+              'string_thing': 'Hello2',
+              'byte_thing': 2,
+              'i32_thing': 2,
+              'i64_thing': 2
+            }
+          ]
+        },
+        '3': {
+          'userMap': { '5': 5, '8': 8 },
+          'xtructs': [{
+              'string_thing': 'Goodbye4',
+              'byte_thing': 4,
+              'i32_thing': 4,
+              'i64_thing': 4
+            },
+            {
+              'string_thing': 'Hello2',
+              'byte_thing': 2,
+              'i32_thing': 2,
+              'i64_thing': 2
+            }
+          ]
+        }
+      },
+      '2': { '6': { 'userMap': null, 'xtructs': null } }
+    };
+    client.testInsanity(new ThriftTest.Insanity()).then(function(res) {
+      assert.ok(res, JSON.stringify(res));
+      assert.ok(insanity, JSON.stringify(insanity));
+      checkRecursively(assert, res, insanity);
+      done();
+    });
+  });
+
+QUnit.module('Oneway');
+  QUnit.test('testOneway', function( assert ) {
+    assert.expect(1);
+    const done = assert.async();
+    client.testOneway(1).then(function(result) {
+      assert.equal(result, undefined);
+      done();
+    });
+  });
diff --git a/lib/js/test/test-jq.js b/lib/js/test/test-jq.js
new file mode 100644
index 0000000..f62bb95
--- /dev/null
+++ b/lib/js/test/test-jq.js
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /* jshint -W100 */
+
+/*
+ * JavaScript test suite for ThriftTest.thrift. These tests
+ * will run only with jQuery (-gen js:jquery) Apache Thrift
+ * interfaces. To create client code:
+ *      $ thrift -gen js:jquery ThriftTest.thrift
+ *
+ * See also:
+ * ++ test.js for generic tests
+ * ++ test-nojq.js for "-gen js" only tests
+ */
+
+
+//////////////////////////////////
+//jQuery asynchronous tests
+jQuery.ajaxSetup({ timeout: 0 });
+
+QUnit.module('jQ Async Manual');
+
+  QUnit.test('testI32', function(assert) {
+    assert.expect(2);
+    const done = assert.async(2);
+
+    const transport = new Thrift.Transport();
+    const protocol = new Thrift.Protocol(transport);
+    const client = new ThriftTest.ThriftTestClient(protocol);
+
+    const jqxhr = jQuery.ajax({
+      url: '/service',
+      data: client.send_testI32(Math.pow(-2, 31)),
+      type: 'POST',
+      cache: false,
+      dataType: 'text',
+      success: function(res) {
+        transport.setRecvBuffer(res);
+        assert.equal(client.recv_testI32(), Math.pow(-2, 31));
+        done();
+      },
+      error: function() { assert.ok(false); },
+      complete: function() {
+        assert.ok(true);
+        done();
+      }
+    });
+  });
+
+  QUnit.test('testI64', function(assert) {
+    assert.expect(2);
+    const done = assert.async(2);
+
+    const transport = new Thrift.Transport();
+    const protocol = new Thrift.Protocol(transport);
+    const client = new ThriftTest.ThriftTestClient(protocol);
+
+    jQuery.ajax({
+      url: '/service',
+      //This is usually 2^61 but JS cannot represent anything over 2^52 accurately
+      data: client.send_testI64(Math.pow(-2, 52)),
+      type: 'POST',
+      cache: false,
+      dataType: 'text',
+      success: function(res) {
+        transport.setRecvBuffer(res);
+        //This is usually 2^61 but JS cannot represent anything over 2^52 accurately
+        assert.equal(client.recv_testI64(), Math.pow(-2, 52));
+        done();
+      },
+      error: function() { assert.ok(false); },
+      complete: function() {
+        assert.ok(true);
+        done();
+      }
+    });
+  });
+
+
+QUnit.module('jQ Async');
+  QUnit.test('I32', function(assert) {
+    assert.expect(3);
+
+    const done = assert.async(3);
+    client.testI32(Math.pow(2, 30), function(result) {
+      assert.equal(result, Math.pow(2, 30));
+      done();
+    });
+
+    const jqxhr = client.testI32(Math.pow(-2, 31), function(result) {
+      assert.equal(result, Math.pow(-2, 31));
+      done();
+    });
+
+    jqxhr.success(function(result) {
+      assert.equal(result, Math.pow(-2, 31));
+      done();
+    });
+  });
+
+  QUnit.test('I64', function(assert) {
+    assert.expect(4);
+
+    const done = assert.async(4);
+    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+    client.testI64(Math.pow(2, 52), function(result) {
+      assert.equal(result, Math.pow(2, 52));
+      done();
+    });
+
+    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+    client.testI64(Math.pow(-2, 52), function(result) {
+      assert.equal(result, Math.pow(-2, 52));
+      done();
+    })
+    .error(function(xhr, status, e) { assert.ok(false, e.message); })
+    .success(function(result) {
+      //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+      assert.equal(result, Math.pow(-2, 52));
+      done();
+    })
+    .complete(function() {
+      assert.ok(true);
+      done();
+    });
+  });
+
+  QUnit.test('Xception', function(assert) {
+    assert.expect(2);
+
+    const done = assert.async(2);
+
+    const dfd = client.testException('Xception', function(result) {
+      assert.ok(false);
+      done();
+    })
+    .error(function(xhr, status, e) {
+      assert.equal(e.errorCode, 1001);
+      assert.equal(e.message, 'Xception');
+      done();
+      $(document).ajaxError( function() { done(); } );
+    });
+  });
diff --git a/lib/js/test/test-nojq.html b/lib/js/test/test-nojq.html
new file mode 100644
index 0000000..408424e
--- /dev/null
+++ b/lib/js/test/test-nojq.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  <title>Thrift Javascript Bindings: Unit Test</title>
+
+  <script src="build/js/thrift.js"         type="text/javascript" charset="utf-8"></script>
+  <script src="gen-js/ThriftTest_types.js" type="text/javascript" charset="utf-8"></script>
+  <script src="gen-js/ThriftTest.js"       type="text/javascript" charset="utf-8"></script>
+
+  <!-- QUnit Test framework-->
+  <script type="text/javascript" src="build/js/lib/qunit.js" charset="utf-8"></script>
+  <link rel="stylesheet" href="build/js/lib/qunit.css" type="text/css" media="screen" />
+
+  <!-- the Test Suite-->
+  <script type="text/javascript" src="test.js" charset="utf-8"></script>
+  <script type="text/javascript" src="test-nojq.js" charset="utf-8"></script>
+</head>
+<body>
+  <h1 id="qunit-header">Thrift Javascript Bindings: Unit Test (<a href="https://github.com/apache/thrift/blob/master/test/ThriftTest.thrift">ThriftTest.thrift</a>)</h1>
+  <h2 id="qunit-banner"></h2>
+  <div id="qunit-testrunner-toolbar"></div>
+  <h2 id="qunit-userAgent"></h2>
+  <ol id="qunit-tests"><li><!-- get valid xhtml strict--></li></ol>
+  <!-- Uncomment this to check the validity. This significantly slows down the test.
+  <p>
+      <a href="http://validator.w3.org/check/referer"><img
+          src="http://www.w3.org/Icons/valid-xhtml10"
+          alt="Valid XHTML 1.0!" height="31" width="88" /></a>
+  </p>
+  -->
+</body>
+</html>
+
diff --git a/lib/js/test/test-nojq.js b/lib/js/test/test-nojq.js
new file mode 100644
index 0000000..2b801d2
--- /dev/null
+++ b/lib/js/test/test-nojq.js
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /* jshint -W100 */
+
+/*
+ * JavaScript test suite for ThriftTest.thrift. These tests
+ * will run only with normal "-gen js" Apache Thrift interfaces.
+ * To create client code:
+ *      $ thrift -gen js ThriftTest.thrift
+ *
+ * See also:
+ * ++ test.js for generic tests
+ * ++ test-jq.js for "-gen js:jquery" only tests
+ */
+
+
+//////////////////////////////////
+//Async exception tests
+
+QUnit.module('NojQ Async');
+
+QUnit.test('Xception', function(assert) {
+    assert.expect(2);
+    const done = assert.async();
+
+    client.testException('Xception', function(result) {
+      assert.equal(result.errorCode, 1001);
+      assert.equal(result.message, 'Xception');
+      done();
+    });
+  });
+
diff --git a/lib/js/test/test.html b/lib/js/test/test.html
index 1c8fc9a..8b67014 100755
--- a/lib/js/test/test.html
+++ b/lib/js/test/test.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <!--
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements. See the NOTICE file
@@ -22,30 +22,33 @@
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>Thrift Javascript Bindings: Unit Test</title>
 
-  <script src="/thrift.js"                  type="text/javascript" charset="utf-8"></script>
-  <script src="gen-js/ThriftTest_types.js" type="text/javascript" charset="utf-8"></script>
-  <script src="gen-js/ThriftTest.js"       type="text/javascript" charset="utf-8"></script>
+  <script src="build/js/thrift.js"         type="text/javascript" charset="utf-8"></script>
+  <script src="gen-js-jquery/ThriftTest_types.js" type="text/javascript" charset="utf-8"></script>
+  <script src="gen-js-jquery/ThriftTest.js"       type="text/javascript" charset="utf-8"></script>
 
   <!-- jQuery -->
-  <script type="text/javascript" src="build/js/lib/jquery-1.7.2.js" charset="utf-8"></script>
-  
+  <script type="text/javascript" src="build/js/lib/jquery.js" charset="utf-8"></script>
+
   <!-- QUnit Test framework-->
   <script type="text/javascript" src="build/js/lib/qunit.js" charset="utf-8"></script>
   <link rel="stylesheet" href="build/js/lib/qunit.css" type="text/css" media="screen" />
-  
+
   <!-- the Test Suite-->
   <script type="text/javascript" src="test.js" charset="utf-8"></script>
+  <script type="text/javascript" src="test-jq.js" charset="utf-8"></script>
 </head>
 <body>
-  <h1 id="qunit-header">Thrift Javascript Bindings: Unit Test (<a href="https://git-wip-us.apache.org/repos/asf?p=thrift.git;a=blob;f=test/ThriftTest.thrift;hb=HEAD">ThriftTest.thrift</a>)</h1>
+  <h1 id="qunit-header">Thrift Javascript Bindings: Unit Test (<a href="https://github.com/apache/thrift/blob/master/test/ThriftTest.thrift">ThriftTest.thrift</a>)</h1>
   <h2 id="qunit-banner"></h2>
-  <div id="qunit-testrunner-toolbar"></div> 
+  <div id="qunit-testrunner-toolbar"></div>
   <h2 id="qunit-userAgent"></h2>
   <ol id="qunit-tests"><li><!-- get valid xhtml strict--></li></ol>
+  <!-- Uncomment this to check the validity. This significantly slows down the test.
   <p>
       <a href="http://validator.w3.org/check/referer"><img
           src="http://www.w3.org/Icons/valid-xhtml10"
           alt="Valid XHTML 1.0!" height="31" width="88" /></a>
   </p>
+  -->
 </body>
 </html>
diff --git a/lib/js/test/test.js b/lib/js/test/test.js
index 99fcc41..a86a509 100755
--- a/lib/js/test/test.js
+++ b/lib/js/test/test.js
@@ -1,4 +1,4 @@
-/*
+/*
  * 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
@@ -16,391 +16,400 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- 
- 
+ /* jshint -W100 */
+
 /*
- * JavaScript test suite
+ * JavaScript test suite for ThriftTest.thrift. These tests
+ * will run against Normal (-gen js) and jQuery (-gen js:jquery)
+ * Apache Thrift interfaces.
+ *
+ * Synchronous blocking calls should be identical in both
+ * Normal and jQuery interfaces. All synchronous tests belong
+ * here.
+ *
+ * Asynchronous success callbacks passed as the last parameter
+ * of an RPC call should be identical in both Normal and jQuery
+ * interfaces. Async success tests belong here.
+ *
+ * Asynchronous exception processing is different in Normal
+ * and jQuery interfaces. Such tests belong in the test-nojq.js
+ * or test-jq.js files respectively. jQuery specific XHR object
+ * tests also belong in test-jq.js. Do not create any jQuery
+ * dependencies in this file or in test-nojq.js
+ *
+ * To compile client code for this test use:
+ *      $ thrift -gen js ThriftTest.thrift
+ *      -- or --
+ *      $ thrift -gen js:jquery ThriftTest.thrift
+ *
+ * See also:
+ * ++ test-nojq.js for "-gen js" only tests
+ * ++ test-jq.js for "-gen js:jquery" only tests
  */
 
-var transport = new Thrift.Transport("/service");
-var protocol  = new Thrift.Protocol(transport);
-var client    = new ThriftTest.ThriftTestClient(protocol);
+const transport = new Thrift.Transport('/service');
+const protocol = new Thrift.Protocol(transport);
+const client = new ThriftTest.ThriftTestClient(protocol);
+
+// Work around for old API used by QUnitAdapter of jsTestDriver
+if (typeof QUnit.log == 'function') {
+  // When using real QUnit (fron PhantomJS) log failures to console
+  QUnit.log(function(details) {
+    if (!details.result) {
+      console.log('======== FAIL ========');
+      console.log('TestName: ' + details.name);
+      if (details.message) console.log(details.message);
+      console.log('Expected: ' + details.expected);
+      console.log('Actual  : ' + details.actual);
+      console.log('======================');
+    }
+  });
+}
 
 // all Languages in UTF-8
-var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語";
-  
-function checkRecursively(map1, map2) {
+const stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語";
+
+function checkRecursively(assert, map1, map2) {
   if (typeof map1 !== 'function' && typeof map2 !== 'function') {
     if (!map1 || typeof map1 !== 'object') {
-        equal(map1, map2);
+        assert.equal(map1, map2);
     } else {
-      for (var key in map1) {
-        checkRecursively(map1[key], map2[key]);
+      for (let key in map1) {
+        checkRecursively(assert, map1[key], map2[key]);
       }
     }
   }
 }
 
-module("Base Types");
+QUnit.module('Base Types');
 
-  test("Void", function() {
-    equal(client.testVoid(), undefined);
+  QUnit.test('Void', function(assert) {
+    assert.equal(client.testVoid(), undefined);
   });
-  test("String", function() {
-    equal(client.testString(''), '');
-    equal(client.testString(stringTest), stringTest);
+  QUnit.test('Binary (String)', function(assert) {
+    let binary = '';
+    for (let v = 255; v >= 0; --v) {
+      binary += String.fromCharCode(v);
+    }
+    assert.equal(client.testBinary(binary), binary);
+  });
+  QUnit.test('Binary (Uint8Array)', function(assert) {
+    let binary = '';
+    for (let v = 255; v >= 0; --v) {
+      binary += String.fromCharCode(v);
+    }
+    const arr = new Uint8Array(binary.length);
+    for (let i = 0; i < binary.length; ++i) {
+      arr[i] = binary[i].charCodeAt();
+    }
+    assert.equal(client.testBinary(arr), binary);
+  });
+  QUnit.test('String', function(assert) {
+    assert.equal(client.testString(''), '');
+    assert.equal(client.testString(stringTest), stringTest);
 
-    var specialCharacters = 'quote: \" backslash:' +
+    const specialCharacters = 'quote: \" backslash:' +
           ' forwardslash-escaped: \/ ' +
           ' backspace: \b formfeed: \f newline: \n return: \r tab: ' +
           ' now-all-of-them-together: "\\\/\b\n\r\t' +
           ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><';
-    equal(client.testString(specialCharacters),specialCharacters);
+    assert.equal(client.testString(specialCharacters), specialCharacters);
   });
-  test("Double", function() {
-    equal(client.testDouble(0), 0);
-    equal(client.testDouble(-1), -1);
-    equal(client.testDouble(3.14), 3.14);
-    equal(client.testDouble(Math.pow(2,60)), Math.pow(2,60));
+  QUnit.test('Double', function(assert) {
+    assert.equal(client.testDouble(0), 0);
+    assert.equal(client.testDouble(-1), -1);
+    assert.equal(client.testDouble(3.14), 3.14);
+    assert.equal(client.testDouble(Math.pow(2, 60)), Math.pow(2, 60));
   });
-  test("Byte", function() {
-    equal(client.testByte(0), 0);
-    equal(client.testByte(0x01), 0x01);
+  QUnit.test('Byte', function(assert) {
+    assert.equal(client.testByte(0), 0);
+    assert.equal(client.testByte(0x01), 0x01);
   });
-  test("I32", function() {
-    equal(client.testI32(0), 0);
-    equal(client.testI32(Math.pow(2,30)), Math.pow(2,30));
-    equal(client.testI32(-Math.pow(2,30)), -Math.pow(2,30));
+  QUnit.test('I32', function(assert) {
+    assert.equal(client.testI32(0), 0);
+    assert.equal(client.testI32(Math.pow(2, 30)), Math.pow(2, 30));
+    assert.equal(client.testI32(-Math.pow(2, 30)), -Math.pow(2, 30));
   });
-  test("I64", function() {
-    equal(client.testI64(0), 0);
-    equal(client.testI64(Math.pow(2,60)), Math.pow(2,60));
-    equal(client.testI64(-Math.pow(2,60)), -Math.pow(2,60));
+  QUnit.test('I64', function(assert) {
+    assert.equal(client.testI64(0), 0);
+    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+    assert.equal(client.testI64(Math.pow(2, 52)), Math.pow(2, 52));
+    assert.equal(client.testI64(-Math.pow(2, 52)), -Math.pow(2, 52));
   });
 
 
-module("Structured Types");
+QUnit.module('Structured Types');
 
-  test("Struct", function() {
-    var structTestInput = new ThriftTest.Xtruct();
+  QUnit.test('Struct', function(assert) {
+    const structTestInput = new ThriftTest.Xtruct();
     structTestInput.string_thing = 'worked';
     structTestInput.byte_thing = 0x01;
-    structTestInput.i32_thing = Math.pow(2,30);
-    structTestInput.i64_thing = Math.pow(2,60);
+    structTestInput.i32_thing = Math.pow(2, 30);
+    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+    structTestInput.i64_thing = Math.pow(2, 52);
 
-    var structTestOutput = client.testStruct(structTestInput);
+    const structTestOutput = client.testStruct(structTestInput);
 
-    equal(structTestOutput.string_thing, structTestInput.string_thing);
-    equal(structTestOutput.byte_thing, structTestInput.byte_thing);
-    equal(structTestOutput.i32_thing, structTestInput.i32_thing);
-    equal(structTestOutput.i64_thing, structTestInput.i64_thing);
-    
-    equal(JSON.stringify(structTestOutput), JSON.stringify(structTestInput));
+    assert.equal(structTestOutput.string_thing, structTestInput.string_thing);
+    assert.equal(structTestOutput.byte_thing, structTestInput.byte_thing);
+    assert.equal(structTestOutput.i32_thing, structTestInput.i32_thing);
+    assert.equal(structTestOutput.i64_thing, structTestInput.i64_thing);
+
+    assert.equal(JSON.stringify(structTestOutput), JSON.stringify(structTestInput));
   });
 
-  test("Nest", function() {
-    var xtrTestInput = new ThriftTest.Xtruct();
+  QUnit.test('Nest', function(assert) {
+    const xtrTestInput = new ThriftTest.Xtruct();
     xtrTestInput.string_thing = 'worked';
     xtrTestInput.byte_thing = 0x01;
-    xtrTestInput.i32_thing = Math.pow(2,30);
-    xtrTestInput.i64_thing = Math.pow(2,60);
-    
-    var nestTestInput = new ThriftTest.Xtruct2();
+    xtrTestInput.i32_thing = Math.pow(2, 30);
+    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+    xtrTestInput.i64_thing = Math.pow(2, 52);
+
+    const nestTestInput = new ThriftTest.Xtruct2();
     nestTestInput.byte_thing = 0x02;
     nestTestInput.struct_thing = xtrTestInput;
-    nestTestInput.i32_thing = Math.pow(2,15);
-    
-    var nestTestOutput = client.testNest(nestTestInput);
-    
-    equal(nestTestOutput.byte_thing, nestTestInput.byte_thing);
-    equal(nestTestOutput.struct_thing.string_thing, nestTestInput.struct_thing.string_thing);
-    equal(nestTestOutput.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing);
-    equal(nestTestOutput.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing);
-    equal(nestTestOutput.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing);
-    equal(nestTestOutput.i32_thing, nestTestInput.i32_thing);
-    
-    equal(JSON.stringify(nestTestOutput), JSON.stringify(nestTestInput));
+    nestTestInput.i32_thing = Math.pow(2, 15);
+
+    const nestTestOutput = client.testNest(nestTestInput);
+
+    assert.equal(nestTestOutput.byte_thing, nestTestInput.byte_thing);
+    assert.equal(nestTestOutput.struct_thing.string_thing, nestTestInput.struct_thing.string_thing);
+    assert.equal(nestTestOutput.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing);
+    assert.equal(nestTestOutput.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing);
+    assert.equal(nestTestOutput.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing);
+    assert.equal(nestTestOutput.i32_thing, nestTestInput.i32_thing);
+
+    assert.equal(JSON.stringify(nestTestOutput), JSON.stringify(nestTestInput));
   });
 
-  test("Map", function() {
-    var mapTestInput = {7:77, 8:88, 9:99};
+  QUnit.test('Map', function(assert) {
+    const mapTestInput = {7: 77, 8: 88, 9: 99};
 
-    var mapTestOutput = client.testMap(mapTestInput);
+    const mapTestOutput = client.testMap(mapTestInput);
 
-    for (var key in mapTestOutput) {
-      equal(mapTestOutput[key], mapTestInput[key]);
+    for (let key in mapTestOutput) {
+      assert.equal(mapTestOutput[key], mapTestInput[key]);
     }
   });
 
-  test("StringMap", function() {
-    var mapTestInput = {
-      "a":"123", "a b":"with spaces ", "same":"same", "0":"numeric key",
-      "longValue":stringTest, stringTest:"long key"
+  QUnit.test('StringMap', function(assert) {
+    const mapTestInput = {
+      'a': '123', 'a b': 'with spaces ', 'same': 'same', '0': 'numeric key',
+      'longValue': stringTest, stringTest: 'long key'
     };
 
-    var mapTestOutput = client.testStringMap(mapTestInput);
+    const mapTestOutput = client.testStringMap(mapTestInput);
 
-    for (var key in mapTestOutput) {
-      equal(mapTestOutput[key], mapTestInput[key]);
+    for (let key in mapTestOutput) {
+      assert.equal(mapTestOutput[key], mapTestInput[key]);
     }
   });
 
-  test("Set", function() {
-    var setTestInput = [1,2,3];
-    ok(client.testSet(setTestInput), setTestInput);
+  QUnit.test('Set', function(assert) {
+    const setTestInput = [1, 2, 3];
+    assert.ok(client.testSet(setTestInput), setTestInput);
   });
 
-  test("List", function() {
-    var listTestInput = [1,2,3];
-    ok(client.testList(listTestInput), listTestInput);
+  QUnit.test('List', function(assert) {
+    const listTestInput = [1, 2, 3];
+    assert.ok(client.testList(listTestInput), listTestInput);
   });
 
-  test("Enum", function() {
-    equal(client.testEnum(ThriftTest.Numberz.ONE), ThriftTest.Numberz.ONE);
+  QUnit.test('Enum', function(assert) {
+    assert.equal(client.testEnum(ThriftTest.Numberz.ONE), ThriftTest.Numberz.ONE);
   });
 
-  test("TypeDef", function() {
-    equal(client.testTypedef(69), 69);
+  QUnit.test('TypeDef', function(assert) {
+    assert.equal(client.testTypedef(69), 69);
   });
 
+  QUnit.test('Skip', function(assert) {
+    const structTestInput = new ThriftTest.Xtruct();
+    const modifiedClient = new ThriftTest.ThriftTestClient(protocol);
 
-module("deeper!");
+    modifiedClient.recv_testStruct = function() {
+      const input = modifiedClient.input;
+      const xtruct3 = new ThriftTest.Xtruct3();
 
-  test("MapMap", function() {
-    var mapMapTestExpectedResult = {
-      "4":{"1":1,"2":2,"3":3,"4":4},
-      "-4":{"-4":-4, "-3":-3, "-2":-2, "-1":-1}
+      input.readMessageBegin();
+      input.readStructBegin();
+
+      // read Xtruct data with Xtruct3
+      input.readFieldBegin();
+      xtruct3.read(input);
+      input.readFieldEnd();
+      // read Thrift.Type.STOP message
+      input.readFieldBegin();
+      input.readFieldEnd();
+
+      input.readStructEnd();
+      input.readMessageEnd();
+
+      return xtruct3;
     };
 
-    var mapMapTestOutput = client.testMapMap(1);
+    structTestInput.string_thing = 'worked';
+    structTestInput.byte_thing = 0x01;
+    structTestInput.i32_thing = Math.pow(2, 30);
+    structTestInput.i64_thing = Math.pow(2, 52);
+
+    const structTestOutput = modifiedClient.testStruct(structTestInput);
+
+    assert.equal(structTestOutput instanceof ThriftTest.Xtruct3, true);
+    assert.equal(structTestOutput.string_thing, structTestInput.string_thing);
+    assert.equal(structTestOutput.changed, null);
+    assert.equal(structTestOutput.i32_thing, structTestInput.i32_thing);
+    assert.equal(structTestOutput.i64_thing, structTestInput.i64_thing);
+  });
 
 
-    for (var key in mapMapTestOutput) {
-      for (var key2 in mapMapTestOutput[key]) {
-        equal(mapMapTestOutput[key][key2], mapMapTestExpectedResult[key][key2]);
+QUnit.module('deeper!');
+
+  QUnit.test('MapMap', function(assert) {
+    const mapMapTestExpectedResult = {
+      '4': {'1': 1, '2': 2, '3': 3, '4': 4},
+      '-4': {'-4': -4, '-3': -3, '-2': -2, '-1': -1}
+    };
+
+    const mapMapTestOutput = client.testMapMap(1);
+
+
+    for (let key in mapMapTestOutput) {
+      for (let key2 in mapMapTestOutput[key]) {
+        assert.equal(mapMapTestOutput[key][key2], mapMapTestExpectedResult[key][key2]);
       }
     }
-    
-    checkRecursively(mapMapTestOutput, mapMapTestExpectedResult);
+
+    checkRecursively(assert, mapMapTestOutput, mapMapTestExpectedResult);
   });
 
 
-module("Exception");
+QUnit.module('Exception');
 
-  test("Xception", function() {
-    expect(2);
-    try{
-      client.testException("Xception");
-    }catch(e){
-      equal(e.errorCode, 1001);
-      equal(e.message, "Xception");
+  QUnit.test('Xception', function(assert) {
+    assert.expect(2);
+    const done = assert.async();
+    try {
+      client.testException('Xception');
+      assert.ok(false);
+    }catch (e) {
+      assert.equal(e.errorCode, 1001);
+      assert.equal(e.message, 'Xception');
+      done();
     }
   });
 
-  test("no Exception", 0, function() {
-    try{
-      client.testException("no Exception");
-    }catch(e){
-      ok(false);
+  QUnit.test('no Exception', function(assert) {
+    assert.expect(1);
+    try {
+      client.testException('no Exception');
+      assert.ok(true);
+    }catch (e) {
+      assert.ok(false);
     }
   });
 
-  test("TException", function() {
-    expect(1);
-    try{
-      client.testException("TException");
-    } catch(e) {
-      ok(true);
+  QUnit.test('TException', function(assert) {
+    //ThriftTest does not list TException as a legal exception so it will
+    // generate an exception on the server that does not propagate back to
+    // the client. This test has been modified to equate to "no exception"
+    assert.expect(1);
+    try {
+      client.testException('TException');
+    } catch (e) {
+      //assert.ok(false);
     }
+    assert.ok(true);
   });
 
 
-module("Insanity");
+QUnit.module('Insanity');
 
-  test("testInsanity", function() {
-    var insanity = {
-      "1":{
-        "2":{
-          "userMap":{ "5":5, "8":8 },
-          "xtructs":[{
-              "string_thing":"Goodbye4",
-              "byte_thing":4,
-              "i32_thing":4,
-              "i64_thing":4
-            },
-            {
-              "string_thing":"Hello2",
-              "byte_thing":2,
-              "i32_thing":2,
-              "i64_thing":2
-            }
-          ]
-        },
-        "3":{
-          "userMap":{ "5":5, "8":8 },
-          "xtructs":[{
-              "string_thing":"Goodbye4",
-              "byte_thing":4,
-              "i32_thing":4,
-              "i64_thing":4
-            },
-            {
-              "string_thing":"Hello2",
-              "byte_thing":2,
-              "i32_thing":2,
-              "i64_thing":2
-            }
-          ]
-        }
+  const crazy = {
+    'userMap': { '5': 5, '8': 8 },
+    'xtructs': [{
+      'string_thing': 'Goodbye4',
+      'byte_thing': 4,
+      'i32_thing': 4,
+      'i64_thing': 4
+    },
+    {
+      'string_thing': 'Hello2',
+      'byte_thing': 2,
+      'i32_thing': 2,
+      'i64_thing': 2
+    }]
+  };
+  QUnit.test('testInsanity', function(assert) {
+    const insanity = {
+      '1': {
+        '2': crazy,
+        '3': crazy
       },
-      "2":{ "6":{ "userMap":null, "xtructs":null } }
+      '2': { '6': { 'userMap': null, 'xtructs': null } }
     };
-    var res = client.testInsanity(new ThriftTest.Insanity());
-    ok(res, JSON.stringify(res));
-    ok(insanity, JSON.stringify(insanity));
+    const res = client.testInsanity(new ThriftTest.Insanity(crazy));
+    assert.ok(res, JSON.stringify(res));
+    assert.ok(insanity, JSON.stringify(insanity));
 
-    checkRecursively(res, insanity);
+    checkRecursively(assert, res, insanity);
   });
 
 
 //////////////////////////////////
 //Run same tests asynchronously
-jQuery.ajaxSetup({ timeout: 0 });
-$(document).ajaxError( function() { QUnit.start(); } );
 
-module("Async Manual");
+QUnit.module('Async');
 
-  test("testI32", function() {
-    expect( 2 );
-    QUnit.stop();
+  QUnit.test('Double', function(assert) {
+    assert.expect(1);
 
-    var transport = new Thrift.Transport();
-    var protocol  = new Thrift.Protocol(transport);
-    var client    = new ThriftTest.ThriftTestClient(protocol);
-
-    var jqxhr = jQuery.ajax({
-      url: "/service",
-      data: client.send_testI32(Math.pow(-2,31)),
-      type: "POST",
-      cache: false,
-      dataType: "text",
-      success: function(res){
-        transport.setRecvBuffer( res );
-        equal(client.recv_testI32(), Math.pow(-2,31));
-      },
-      error: function() { ok(false); },
-      complete: function() {
-        ok(true);
-        QUnit.start();
-      }
-    });
-  });
-
-
-  test("testI64", function() {
-    expect( 2 );
-    QUnit.stop();
-
-    var transport = new Thrift.Transport();
-    var protocol  = new Thrift.Protocol(transport);
-    var client    = new ThriftTest.ThriftTestClient(protocol);
-
-    jQuery.ajax({
-      url: "/service",
-      data: client.send_testI64(Math.pow(-2,61)),
-      type: "POST",
-      cache: false,
-      dataType: "text",
-      success: function(res){
-        transport.setRecvBuffer( res );
-        equal(client.recv_testI64(), Math.pow(-2,61));
-      },
-      error: function() { ok(false); },
-      complete: function() {
-        ok(true);
-        QUnit.start();
-      }
-    });
-  });
-
-
-module("Async");
-
-  test("Double", function() {
-    expect( 1 );
-
-    QUnit.stop();
+    const done = assert.async();
     client.testDouble(3.14159265, function(result) {
-      equal(result, 3.14159265);
-      QUnit.start();
+      assert.equal(result, 3.14159265);
+      done();
     });
   });
 
-  test("Byte", function() {
-    expect( 1 );
+  QUnit.test('Byte', function(assert) {
+    assert.expect(1);
 
-    QUnit.stop();
+    const done = assert.async();
     client.testByte(0x01, function(result) {
-      equal(result, 0x01);
-      QUnit.start();
+      assert.equal(result, 0x01);
+      done();
     });
   });
 
-  test("I32", function() {
-    expect( 3 );
+  QUnit.test('I32', function(assert) {
+    assert.expect(2);
 
-    QUnit.stop();
-    client.testI32(Math.pow(2,30), function(result) {
-      equal(result, Math.pow(2,30));
-      QUnit.start();
+    const done = assert.async(2);
+    client.testI32(Math.pow(2, 30), function(result) {
+      assert.equal(result, Math.pow(2, 30));
+      done();
     });
 
-    QUnit.stop();
-    var jqxhr = client.testI32(Math.pow(-2,31), function(result) {
-      equal(result, Math.pow(-2,31));
-    });
-
-    jqxhr.success(function(result) {
-      equal(result, Math.pow(-2,31));
-      QUnit.start();
+    client.testI32(Math.pow(-2, 31), function(result) {
+      assert.equal(result, Math.pow(-2, 31));
+      done();
     });
   });
 
-  test("I64", function() {
-    expect( 4 );
+  QUnit.test('I64', function(assert) {
+    assert.expect(2);
 
-    QUnit.stop();
-    client.testI64(Math.pow(2,60), function(result) {
-      equal(result, Math.pow(2,60));
-      QUnit.start();
+    const done = assert.async(2);
+    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+    client.testI64(Math.pow(2, 52), function(result) {
+      assert.equal(result, Math.pow(2, 52));
+      done();
     });
 
-    QUnit.stop();
-    client.testI64(Math.pow(-2,61), function(result) {
-      equal(result, Math.pow(-2,61));
-    })
-    .error( function(xhr, status, e) {  ok(false, e.message); } )
-    .success(function(result) {
-      equal(result, Math.pow(-2,61));
-    })
-    .complete(function() {
-      ok(true);
-      QUnit.start();
-    });
-  });
-
-  test("Xception", function() {
-    expect( 2 );
-
-    QUnit.stop();
-
-    var dfd = client.testException("Xception", function(result) {
-      ok(false);
-      QUnit.start();
-    })
-    .error(function(xhr, status, e){
-      equal(e.errorCode, 1001);
-      equal(e.message, "Xception");
-      QUnit.start();
+    //This is usually 2^60 but JS cannot represent anything over 2^52 accurately
+    client.testI64(Math.pow(-2, 52), function(result) {
+      assert.equal(result, Math.pow(-2, 52));
+      done();
     });
   });
diff --git a/lib/js/test/test_handler.js b/lib/js/test/test_handler.js
new file mode 100644
index 0000000..af5f7bd
--- /dev/null
+++ b/lib/js/test/test_handler.js
@@ -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.
+ */
+
+//This is the server side Node test handler for the standard
+//  Apache Thrift test service.
+
+const es6Mode = process.argv.includes('--es6');
+const genFolder = es6Mode ? 'gen-nodejs-es6' : 'gen-nodejs';
+const ttypes = require(`./${genFolder}/ThriftTest_types`);
+const TException = require('../../nodejs/lib/thrift').TException;
+
+exports.ThriftTestHandler = {
+  testVoid: function(result) {
+    console.log('testVoid()');
+    result(null);
+  },
+  testString: function(thing, result) {
+    console.log('testString(\'' + thing + '\')');
+    result(null, thing);
+  },
+  testByte: function(thing, result) {
+    console.log('testByte(' + thing + ')');
+    result(null, thing);
+  },
+  testI32: function(thing, result) {
+    console.log('testI32(' + thing + ')');
+    result(null, thing);
+  },
+  testI64: function(thing, result) {
+    console.log('testI64(' + thing + ')');
+    result(null, thing);
+  },
+  testDouble: function(thing, result) {
+    console.log('testDouble(' + thing + ')');
+    result(null, thing);
+  },
+  testBinary: function(thing, result) {
+    console.log('testBinary(\'' + thing + '\')');
+    result(null, thing);
+  },
+  testStruct: function(thing, result) {
+    console.log('testStruct(');
+    console.log(thing);
+    console.log(')');
+    result(null, thing);
+  },
+  testNest: function(nest, result) {
+    console.log('testNest(');
+    console.log(nest);
+    console.log(')');
+    result(null, nest);
+  },
+  testMap: function(thing, result) {
+    console.log('testMap(');
+    console.log(thing);
+    console.log(')');
+    result(null, thing);
+  },
+  testStringMap: function(thing, result) {
+    console.log('testStringMap(');
+    console.log(thing);
+    console.log(')');
+    result(null, thing);
+  },
+  testSet: function(thing, result) {
+    console.log('testSet(');
+    console.log(thing);
+    console.log(')');
+    result(null, thing);
+  },
+  testList: function(thing, result) {
+    console.log('testList(');
+    console.log(thing);
+    console.log(')');
+    result(null, thing);
+  },
+  testEnum: function(thing, result) {
+    console.log('testEnum(' + thing + ')');
+    result(null, thing);
+  },
+  testTypedef: function(thing, result) {
+    console.log('testTypedef(' + thing + ')');
+    result(null, thing);
+  },
+  testMapMap: function(hello, result) {
+    console.log('testMapMap(' + hello + ')');
+
+    const mapmap = [];
+    const pos = [];
+    const neg = [];
+    for (let i = 1; i < 5; i++) {
+      pos[i] = i;
+      neg[-i] = -i;
+    }
+    mapmap[4] = pos;
+    mapmap[-4] = neg;
+
+    result(null, mapmap);
+  },
+  testInsanity: function(argument, result) {
+    console.log('testInsanity(');
+    console.log(argument);
+    console.log(')');
+
+    const hello = new ttypes.Xtruct();
+    hello.string_thing = 'Hello2';
+    hello.byte_thing = 2;
+    hello.i32_thing = 2;
+    hello.i64_thing = 2;
+
+    const goodbye = new ttypes.Xtruct();
+    goodbye.string_thing = 'Goodbye4';
+    goodbye.byte_thing = 4;
+    goodbye.i32_thing = 4;
+    goodbye.i64_thing = 4;
+
+    const crazy = new ttypes.Insanity();
+    crazy.userMap = [];
+    crazy.userMap[ttypes.Numberz.EIGHT] = 8;
+    crazy.userMap[ttypes.Numberz.FIVE] = 5;
+    crazy.xtructs = [goodbye, hello];
+
+    const first_map = [];
+    const second_map = [];
+
+    first_map[ttypes.Numberz.TWO] = crazy;
+    first_map[ttypes.Numberz.THREE] = crazy;
+
+    const looney = new ttypes.Insanity();
+    second_map[ttypes.Numberz.SIX] = looney;
+
+    const insane = [];
+    insane[1] = first_map;
+    insane[2] = second_map;
+
+    console.log('insane result:');
+    console.log(insane);
+    result(null, insane);
+  },
+  testMulti: function(arg0, arg1, arg2, arg3, arg4, arg5, result) {
+    console.log('testMulti()');
+
+    const hello = new ttypes.Xtruct();
+    hello.string_thing = 'Hello2';
+    hello.byte_thing = arg0;
+    hello.i32_thing = arg1;
+    hello.i64_thing = arg2;
+    result(null, hello);
+  },
+  testException: function(arg, result) {
+    console.log('testException(' + arg + ')');
+    if (arg === 'Xception') {
+      const x = new ttypes.Xception();
+      x.errorCode = 1001;
+      x.message = arg;
+      result(x);
+    } else if (arg === 'TException') {
+      result(new TException(arg));
+    } else {
+      result(null);
+    }
+  },
+  testMultiException: function(arg0, arg1, result) {
+    console.log('testMultiException(' + arg0 + ', ' + arg1 + ')');
+    if (arg0 === ('Xception')) {
+      const x = new ttypes.Xception();
+      x.errorCode = 1001;
+      x.message = 'This is an Xception';
+      result(x);
+    } else if (arg0 === ('Xception2')) {
+      const x2 = new ttypes.Xception2();
+      x2.errorCode = 2002;
+      x2.struct_thing = new ttypes.Xtruct();
+      x2.struct_thing.string_thing = 'This is an Xception2';
+      result(x2);
+    }
+
+    const res = new ttypes.Xtruct();
+    res.string_thing = arg1;
+    result(null, res);
+  },
+  testOneway: function(sleepFor, result) {
+    console.log('testOneway(' + sleepFor + ') => JavaScript (like Rust) never sleeps!');
+  }
+};   //ThriftTestSvcHandler
diff --git a/lib/js/test/testws.html b/lib/js/test/testws.html
new file mode 100644
index 0000000..184500f
--- /dev/null
+++ b/lib/js/test/testws.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  <title>Thrift Javascript Bindings: Unit Test</title>
+
+  <script src="build/js/thrift.js"         type="text/javascript" charset="utf-8"></script>
+  <script src="gen-js/ThriftTest_types.js" type="text/javascript" charset="utf-8"></script>
+  <script src="gen-js/ThriftTest.js"       type="text/javascript" charset="utf-8"></script>
+
+  <!-- jQuery -->
+  <script type="text/javascript" src="build/js/lib/jquery.js" charset="utf-8"></script>
+
+  <!-- QUnit Test framework-->
+  <script type="text/javascript" src="build/js/lib/qunit.js" charset="utf-8"></script>
+  <link rel="stylesheet" href="build/js/lib/qunit.css" type="text/css" media="screen" />
+
+  <!-- the Test Suite-->
+  <script>
+    const loc = window.location;
+    const ws_uri = ((loc.protocol === "https:") ? "wss://" : "ws://") +
+                   loc.hostname + ":" + loc.port + loc.pathname;
+    const transport = new Thrift.TWebSocketTransport(ws_uri);
+    const protocol  = new Thrift.Protocol(transport);
+    const client    = new ThriftTest.ThriftTestClient(protocol);
+    transport.open();
+  </script>
+  <script type="text/javascript" src="test-async.js" charset="utf-8"></script>
+</head>
+<body>
+  <h1 id="qunit-header">Thrift Javascript Bindings: Unit Test (<a href="https://github.com/apache/thrift/blob/master/test/ThriftTest.thrift">ThriftTest.thrift</a>)</h1>
+  <h2 id="qunit-banner"></h2>
+  <div id="qunit-testrunner-toolbar"></div>
+  <h2 id="qunit-userAgent"></h2>
+  <ol id="qunit-tests"><li><!-- get valid xhtml strict--></li></ol>
+  <!-- Uncomment this to check the validity. This significantly slows down the test.
+  <p>
+      <a href="http://validator.w3.org/check/referer"><img
+          src="http://www.w3.org/Icons/valid-xhtml10"
+          alt="Valid XHTML 1.0!" height="31" width="88" /></a>
+  </p>
+  -->
+</body>
+</html>
diff --git a/lib/js/thrift.js b/lib/js/thrift.js
deleted file mode 100644
index 5dcfec1..0000000
--- a/lib/js/thrift.js
+++ /dev/null
@@ -1,779 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-var Thrift = {
-    Version: '0.9.1',
-/*
-    Description: 'JavaScript bindings for the Apache Thrift RPC system',
-    License: 'http://www.apache.org/licenses/LICENSE-2.0',
-    Homepage: 'http://thrift.apache.org',
-    BugReports: 'https://issues.apache.org/jira/browse/THRIFT',
-    Maintainer: 'dev@thrift.apache.org',
-*/
-
-    Type: {
-        'STOP' : 0,
-        'VOID' : 1,
-        'BOOL' : 2,
-        'BYTE' : 3,
-        'I08' : 3,
-        'DOUBLE' : 4,
-        'I16' : 6,
-        'I32' : 8,
-        'I64' : 10,
-        'STRING' : 11,
-        'UTF7' : 11,
-        'STRUCT' : 12,
-        'MAP' : 13,
-        'SET' : 14,
-        'LIST' : 15,
-        'UTF8' : 16,
-        'UTF16' : 17
-    },
-
-    MessageType: {
-        'CALL' : 1,
-        'REPLY' : 2,
-        'EXCEPTION' : 3
-    },
-
-    objectLength: function(obj) {
-        var length = 0;
-        for (var k in obj) {
-            if (obj.hasOwnProperty(k)) {
-                length++;
-            }
-        }
-
-        return length;
-    },
-
-    inherits: function(constructor, superConstructor) {
-      //Prototypal Inheritance http://javascript.crockford.com/prototypal.html
-      function F() {}
-      F.prototype = superConstructor.prototype;
-      constructor.prototype = new F();
-    }
-};
-
-
-
-Thrift.TException = function(message) {
-    this.message = message;
-};
-Thrift.inherits(Thrift.TException, Error);
-Thrift.TException.prototype.name = 'TException';
-
-Thrift.TApplicationExceptionType = {
-    'UNKNOWN' : 0,
-    'UNKNOWN_METHOD' : 1,
-    'INVALID_MESSAGE_TYPE' : 2,
-    'WRONG_METHOD_NAME' : 3,
-    'BAD_SEQUENCE_ID' : 4,
-    'MISSING_RESULT' : 5,
-    'INTERNAL_ERROR' : 6,
-    'PROTOCOL_ERROR' : 7,
-    'INVALID_TRANSFORM' : 8,
-    'INVALID_PROTOCOL' : 9,
-    'UNSUPPORTED_CLIENT_TYPE' : 10
-};
-
-Thrift.TApplicationException = function(message, code) {
-    this.message = message;
-    this.code = (code === null) ? 0 : code;
-};
-Thrift.inherits(Thrift.TApplicationException, Thrift.TException);
-Thrift.TApplicationException.prototype.name = 'TApplicationException';
-
-Thrift.TApplicationException.prototype.read = function(input) {
-    while (1) {
-        var ret = input.readFieldBegin();
-
-        if (ret.ftype == Thrift.Type.STOP) {
-            break;
-        }
-
-        var fid = ret.fid;
-
-        switch (fid) {
-            case 1:
-                if (ret.ftype == Thrift.Type.STRING) {
-                    ret = input.readString();
-                    this.message = ret.value;
-                } else {
-                    ret = input.skip(ret.ftype);
-                }
-                break;
-            case 2:
-                if (ret.ftype == Thrift.Type.I32) {
-                    ret = input.readI32();
-                    this.code = ret.value;
-                } else {
-                    ret = input.skip(ret.ftype);
-                }
-                break;
-           default:
-                ret = input.skip(ret.ftype);
-                break;
-        }
-
-        input.readFieldEnd();
-    }
-
-    input.readStructEnd();
-};
-
-Thrift.TApplicationException.prototype.write = function(output) {
-    var xfer = 0;
-
-    output.writeStructBegin('TApplicationException');
-
-    if (this.message) {
-        output.writeFieldBegin('message', Thrift.Type.STRING, 1);
-        output.writeString(this.getMessage());
-        output.writeFieldEnd();
-    }
-
-    if (this.code) {
-        output.writeFieldBegin('type', Thrift.Type.I32, 2);
-        output.writeI32(this.code);
-        output.writeFieldEnd();
-    }
-
-    output.writeFieldStop();
-    output.writeStructEnd();
-};
-
-Thrift.TApplicationException.prototype.getCode = function() {
-    return this.code;
-};
-
-Thrift.TApplicationException.prototype.getMessage = function() {
-    return this.message;
-};
-
-/**
- *If you do not specify a url then you must handle ajax on your own.
- *This is how to use js bindings in a async fashion.
- */
-Thrift.Transport = function(url) {
-    this.url = url;
-    this.wpos = 0;
-    this.rpos = 0;
-
-    this.send_buf = '';
-    this.recv_buf = '';
-};
-
-Thrift.Transport.prototype = {
-
-    //Gets the browser specific XmlHttpRequest Object
-    getXmlHttpRequestObject: function() {
-        try { return new XMLHttpRequest(); } catch (e1) { }
-        try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { }
-        try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { }
-
-        throw "Your browser doesn't support the XmlHttpRequest object.";
-    },
-
-    flush: function(async) {
-        //async mode
-        if (async || this.url === undefined || this.url === '') {
-            return this.send_buf;
-        }
-
-        var xreq = this.getXmlHttpRequestObject();
-
-        if (xreq.overrideMimeType) {
-            xreq.overrideMimeType('application/json');
-        }
-
-        xreq.open('POST', this.url, false);
-        xreq.send(this.send_buf);
-
-        if (xreq.readyState != 4) {
-            throw 'encountered an unknown ajax ready state: ' + xreq.readyState;
-        }
-
-        if (xreq.status != 200) {
-            throw 'encountered a unknown request status: ' + xreq.status;
-        }
-
-        this.recv_buf = xreq.responseText;
-        this.recv_buf_sz = this.recv_buf.length;
-        this.wpos = this.recv_buf.length;
-        this.rpos = 0;
-    },
-
-    jqRequest: function(client, postData, args, recv_method) {
-        if (typeof jQuery === 'undefined' ||
-            typeof jQuery.Deferred === 'undefined') {
-            throw 'Thrift.js requires jQuery 1.5+ to use asynchronous requests';
-        }
-
-        var thriftTransport = this;
-
-        var jqXHR = jQuery.ajax({
-            url: this.url,
-            data: postData,
-            type: 'POST',
-            cache: false,
-            contentType: 'application/json',
-            dataType: 'text thrift',
-            converters: {
-                'text thrift' : function(responseData) {
-                    thriftTransport.setRecvBuffer(responseData);
-                    var value = recv_method.call(client);
-                    return value;
-                }
-            },
-            context: client,
-            success: jQuery.makeArray(args).pop()
-        });
-
-        return jqXHR;
-    },
-
-    setRecvBuffer: function(buf) {
-        this.recv_buf = buf;
-        this.recv_buf_sz = this.recv_buf.length;
-        this.wpos = this.recv_buf.length;
-        this.rpos = 0;
-    },
-
-    isOpen: function() {
-        return true;
-    },
-
-    open: function() {},
-
-    close: function() {},
-
-    read: function(len) {
-        var avail = this.wpos - this.rpos;
-
-        if (avail === 0) {
-            return '';
-        }
-
-        var give = len;
-
-        if (avail < len) {
-            give = avail;
-        }
-
-        var ret = this.read_buf.substr(this.rpos, give);
-        this.rpos += give;
-
-        //clear buf when complete?
-        return ret;
-    },
-
-    readAll: function() {
-        return this.recv_buf;
-    },
-
-    write: function(buf) {
-        this.send_buf = buf;
-    },
-
-    getSendBuffer: function() {
-        return this.send_buf;
-    }
-
-};
-
-
-
-Thrift.Protocol = function(transport) {
-    this.transport = transport;
-};
-
-Thrift.Protocol.Type = {};
-Thrift.Protocol.Type[Thrift.Type.BOOL] = '"tf"';
-Thrift.Protocol.Type[Thrift.Type.BYTE] = '"i8"';
-Thrift.Protocol.Type[Thrift.Type.I16] = '"i16"';
-Thrift.Protocol.Type[Thrift.Type.I32] = '"i32"';
-Thrift.Protocol.Type[Thrift.Type.I64] = '"i64"';
-Thrift.Protocol.Type[Thrift.Type.DOUBLE] = '"dbl"';
-Thrift.Protocol.Type[Thrift.Type.STRUCT] = '"rec"';
-Thrift.Protocol.Type[Thrift.Type.STRING] = '"str"';
-Thrift.Protocol.Type[Thrift.Type.MAP] = '"map"';
-Thrift.Protocol.Type[Thrift.Type.LIST] = '"lst"';
-Thrift.Protocol.Type[Thrift.Type.SET] = '"set"';
-
-
-Thrift.Protocol.RType = {};
-Thrift.Protocol.RType.tf = Thrift.Type.BOOL;
-Thrift.Protocol.RType.i8 = Thrift.Type.BYTE;
-Thrift.Protocol.RType.i16 = Thrift.Type.I16;
-Thrift.Protocol.RType.i32 = Thrift.Type.I32;
-Thrift.Protocol.RType.i64 = Thrift.Type.I64;
-Thrift.Protocol.RType.dbl = Thrift.Type.DOUBLE;
-Thrift.Protocol.RType.rec = Thrift.Type.STRUCT;
-Thrift.Protocol.RType.str = Thrift.Type.STRING;
-Thrift.Protocol.RType.map = Thrift.Type.MAP;
-Thrift.Protocol.RType.lst = Thrift.Type.LIST;
-Thrift.Protocol.RType.set = Thrift.Type.SET;
-
-Thrift.Protocol.Version = 1;
-
-Thrift.Protocol.prototype = {
-
-    getTransport: function() {
-        return this.transport;
-    },
-
-    //Write functions
-    writeMessageBegin: function(name, messageType, seqid) {
-        this.tstack = [];
-        this.tpos = [];
-
-        this.tstack.push([Thrift.Protocol.Version, '"' +
-            name + '"', messageType, seqid]);
-    },
-
-    writeMessageEnd: function() {
-        var obj = this.tstack.pop();
-
-        this.wobj = this.tstack.pop();
-        this.wobj.push(obj);
-
-        this.wbuf = '[' + this.wobj.join(',') + ']';
-
-        this.transport.write(this.wbuf);
-     },
-
-
-    writeStructBegin: function(name) {
-        this.tpos.push(this.tstack.length);
-        this.tstack.push({});
-    },
-
-    writeStructEnd: function() {
-
-        var p = this.tpos.pop();
-        var struct = this.tstack[p];
-        var str = '{';
-        var first = true;
-        for (var key in struct) {
-            if (first) {
-                first = false;
-            } else {
-                str += ',';
-            }
-
-            str += key + ':' + struct[key];
-        }
-
-        str += '}';
-        this.tstack[p] = str;
-    },
-
-    writeFieldBegin: function(name, fieldType, fieldId) {
-        this.tpos.push(this.tstack.length);
-        this.tstack.push({ 'fieldId': '"' +
-            fieldId + '"', 'fieldType': Thrift.Protocol.Type[fieldType]
-        });
-
-    },
-
-    writeFieldEnd: function() {
-        var value = this.tstack.pop();
-        var fieldInfo = this.tstack.pop();
-
-        this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' +
-            fieldInfo.fieldType + ':' + value + '}';
-        this.tpos.pop();
-    },
-
-    writeFieldStop: function() {
-        //na
-    },
-
-    writeMapBegin: function(keyType, valType, size) {
-        //size is invalid, we'll set it on end.
-        this.tpos.push(this.tstack.length);
-        this.tstack.push([Thrift.Protocol.Type[keyType],
-            Thrift.Protocol.Type[valType], 0]);
-    },
-
-    writeMapEnd: function() {
-        var p = this.tpos.pop();
-
-        if (p == this.tstack.length) {
-            return;
-        }
-
-        if ((this.tstack.length - p - 1) % 2 !== 0) {
-            this.tstack.push('');
-        }
-
-        var size = (this.tstack.length - p - 1) / 2;
-
-        this.tstack[p][this.tstack[p].length - 1] = size;
-
-        var map = '}';
-        var first = true;
-        while (this.tstack.length > p + 1) {
-            var v = this.tstack.pop();
-            var k = this.tstack.pop();
-            if (first) {
-                first = false;
-            } else {
-                map = ',' + map;
-            }
-
-            if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings
-            map = k + ':' + v + map;
-        }
-        map = '{' + map;
-
-        this.tstack[p].push(map);
-        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
-    },
-
-    writeListBegin: function(elemType, size) {
-        this.tpos.push(this.tstack.length);
-        this.tstack.push([Thrift.Protocol.Type[elemType], size]);
-    },
-
-    writeListEnd: function() {
-        var p = this.tpos.pop();
-
-        while (this.tstack.length > p + 1) {
-            var tmpVal = this.tstack[p + 1];
-            this.tstack.splice(p + 1, 1);
-            this.tstack[p].push(tmpVal);
-        }
-
-        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
-    },
-
-    writeSetBegin: function(elemType, size) {
-        this.tpos.push(this.tstack.length);
-        this.tstack.push([Thrift.Protocol.Type[elemType], size]);
-    },
-
-    writeSetEnd: function() {
-        var p = this.tpos.pop();
-
-        while (this.tstack.length > p + 1) {
-            var tmpVal = this.tstack[p + 1];
-            this.tstack.splice(p + 1, 1);
-            this.tstack[p].push(tmpVal);
-        }
-
-        this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
-    },
-
-    writeBool: function(value) {
-        this.tstack.push(value ? 1 : 0);
-    },
-
-    writeByte: function(i8) {
-        this.tstack.push(i8);
-    },
-
-    writeI16: function(i16) {
-        this.tstack.push(i16);
-    },
-
-    writeI32: function(i32) {
-        this.tstack.push(i32);
-    },
-
-    writeI64: function(i64) {
-        this.tstack.push(i64);
-    },
-
-    writeDouble: function(dbl) {
-        this.tstack.push(dbl);
-    },
-
-    writeString: function(str) {
-        // We do not encode uri components for wire transfer:
-        if (str === null) {
-            this.tstack.push(null);
-        } else {
-            // concat may be slower than building a byte buffer
-            var escapedString = '';
-            for (var i = 0; i < str.length; i++) {
-                var ch = str.charAt(i);      // a single double quote: "
-                if (ch === '\"') {
-                    escapedString += '\\\"'; // write out as: \"
-                } else if (ch === '\\') {    // a single backslash: \
-                    escapedString += '\\\\'; // write out as: \\
-                /* Currently escaped forward slashes break TJSONProtocol.
-                 * As it stands, we can simply pass forward slashes into
-                 * our strings across the wire without being escaped.
-                 * I think this is the protocol's bug, not thrift.js
-                 * } else if(ch === '/') {   // a single forward slash: /
-                 *  escapedString += '\\/';  // write out as \/
-                 * }
-                 */
-                } else if (ch === '\b') {    // a single backspace: invisible
-                    escapedString += '\\b';  // write out as: \b"
-                } else if (ch === '\f') {    // a single formfeed: invisible
-                    escapedString += '\\f';  // write out as: \f"
-                } else if (ch === '\n') {    // a single newline: invisible
-                    escapedString += '\\n';  // write out as: \n"
-                } else if (ch === '\r') {    // a single return: invisible
-                    escapedString += '\\r';  // write out as: \r"
-                } else if (ch === '\t') {    // a single tab: invisible
-                    escapedString += '\\t';  // write out as: \t"
-                } else {
-                    escapedString += ch;     // Else it need not be escaped
-                }
-            }
-            this.tstack.push('"' + escapedString + '"');
-        }
-    },
-
-    writeBinary: function(str) {
-        this.writeString(str);
-    },
-
-
-
-    // Reading functions
-    readMessageBegin: function(name, messageType, seqid) {
-        this.rstack = [];
-        this.rpos = [];
-
-        if (typeof jQuery !== 'undefined') {
-            this.robj = jQuery.parseJSON(this.transport.readAll());
-        } else {
-            this.robj = eval(this.transport.readAll());
-        }
-
-        var r = {};
-        var version = this.robj.shift();
-
-        if (version != Thrift.Protocol.Version) {
-            throw 'Wrong thrift protocol version: ' + version;
-        }
-
-        r.fname = this.robj.shift();
-        r.mtype = this.robj.shift();
-        r.rseqid = this.robj.shift();
-
-
-        //get to the main obj
-        this.rstack.push(this.robj.shift());
-
-        return r;
-    },
-
-    readMessageEnd: function() {
-    },
-
-    readStructBegin: function(name) {
-        var r = {};
-        r.fname = '';
-
-        //incase this is an array of structs
-        if (this.rstack[this.rstack.length - 1] instanceof Array) {
-            this.rstack.push(this.rstack[this.rstack.length - 1].shift());
-        }
-
-        return r;
-    },
-
-    readStructEnd: function() {
-        if (this.rstack[this.rstack.length - 2] instanceof Array) {
-            this.rstack.pop();
-        }
-    },
-
-    readFieldBegin: function() {
-        var r = {};
-
-        var fid = -1;
-        var ftype = Thrift.Type.STOP;
-
-        //get a fieldId
-        for (var f in (this.rstack[this.rstack.length - 1])) {
-            if (f === null) {
-              continue;
-            }
-
-            fid = parseInt(f, 10);
-            this.rpos.push(this.rstack.length);
-
-            var field = this.rstack[this.rstack.length - 1][fid];
-
-            //remove so we don't see it again
-            delete this.rstack[this.rstack.length - 1][fid];
-
-            this.rstack.push(field);
-
-            break;
-        }
-
-        if (fid != -1) {
-
-            //should only be 1 of these but this is the only
-            //way to match a key
-            for (var i in (this.rstack[this.rstack.length - 1])) {
-                if (Thrift.Protocol.RType[i] === null) {
-                    continue;
-                }
-
-                ftype = Thrift.Protocol.RType[i];
-                this.rstack[this.rstack.length - 1] =
-                    this.rstack[this.rstack.length - 1][i];
-            }
-        }
-
-        r.fname = '';
-        r.ftype = ftype;
-        r.fid = fid;
-
-        return r;
-    },
-
-    readFieldEnd: function() {
-        var pos = this.rpos.pop();
-
-        //get back to the right place in the stack
-        while (this.rstack.length > pos) {
-            this.rstack.pop();
-        }
-
-    },
-
-    readMapBegin: function(keyType, valType, size) {
-        var map = this.rstack.pop();
-
-        var r = {};
-        r.ktype = Thrift.Protocol.RType[map.shift()];
-        r.vtype = Thrift.Protocol.RType[map.shift()];
-        r.size = map.shift();
-
-
-        this.rpos.push(this.rstack.length);
-        this.rstack.push(map.shift());
-
-        return r;
-    },
-
-    readMapEnd: function() {
-        this.readFieldEnd();
-    },
-
-    readListBegin: function(elemType, size) {
-        var list = this.rstack[this.rstack.length - 1];
-
-        var r = {};
-        r.etype = Thrift.Protocol.RType[list.shift()];
-        r.size = list.shift();
-
-        this.rpos.push(this.rstack.length);
-        this.rstack.push(list);
-
-        return r;
-    },
-
-    readListEnd: function() {
-        this.readFieldEnd();
-    },
-
-    readSetBegin: function(elemType, size) {
-        return this.readListBegin(elemType, size);
-    },
-
-    readSetEnd: function() {
-        return this.readListEnd();
-    },
-
-    readBool: function() {
-        var r = this.readI32();
-
-        if (r !== null && r.value == '1') {
-            r.value = true;
-        } else {
-            r.value = false;
-        }
-
-        return r;
-    },
-
-    readByte: function() {
-        return this.readI32();
-    },
-
-    readI16: function() {
-        return this.readI32();
-    },
-
-    readI32: function(f) {
-        if (f === undefined) {
-            f = this.rstack[this.rstack.length - 1];
-        }
-
-        var r = {};
-
-        if (f instanceof Array) {
-            if (f.length === 0) {
-                r.value = undefined;
-            } else {
-                r.value = f.shift();
-            }
-        } else if (f instanceof Object) {
-           for (var i in f) {
-                if (i === null) {
-                  continue;
-                }
-                this.rstack.push(f[i]);
-                delete f[i];
-
-                r.value = i;
-                break;
-           }
-        } else {
-            r.value = f;
-            this.rstack.pop();
-        }
-
-        return r;
-    },
-
-    readI64: function() {
-        return this.readI32();
-    },
-
-    readDouble: function() {
-        return this.readI32();
-    },
-
-    readString: function() {
-        var r = this.readI32();
-        return r;
-    },
-
-    readBinary: function() {
-        return this.readString();
-    },
-
-
-    //Method to arbitrarily skip over data.
-    skip: function(type) {
-        throw 'skip not supported yet';
-    }
-};
diff --git a/lib/json/Makefile.am b/lib/json/Makefile.am
new file mode 100644
index 0000000..1051b9b
--- /dev/null
+++ b/lib/json/Makefile.am
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+
+SUBDIRS =
+
+if WITH_JAVA
+# Schema validation test depends on java
+SUBDIRS += test
+endif
+
+EXTRA_DIST = \
+    schema.json \
+    test
diff --git a/lib/json/schema.json b/lib/json/schema.json
new file mode 100644
index 0000000..d058a7c
--- /dev/null
+++ b/lib/json/schema.json
@@ -0,0 +1,344 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+
+  "id": "http://thrift.apache.org/schema.json#",
+  "description": "Schema for Apache Thrift protocol descriptors",
+
+  "definitions": {
+    "type-id": {
+      "title": "Any type id (name)",
+      "enum": [
+        "void",
+        "string",
+        "bool",
+        "byte",
+        "i8",
+        "i16",
+        "i32",
+        "i64",
+        "double",
+        "list",
+        "set",
+        "map",
+        "union",
+        "struct",
+        "binary"
+      ]
+    },
+    "base-type": {
+      "title": "Base type schema",
+      "type": "object",
+      "properties": {
+        "typeId": {
+          "enum": ["void", "string", "bool", "byte", "i8", "i16", "i32", "i64", "double", "binary" ]
+        }
+      },
+      "required": [ "typeId" ]
+    },
+    "list-type": {
+      "title": "List and set schema",
+      "type": "object",
+      "properties": {
+        "typeId": {
+          "enum": [ "list", "set" ]
+        },
+        "elemTypeId":  { "$ref": "#/definitions/type-id" },
+        "elemType":    { "$ref": "#/definitions/type-desc" }
+      },
+      "required": [ "typeId", "elemTypeId" ]
+    },
+    "map-type": {
+      "title": "Map schema",
+      "type": "object",
+      "properties": {
+        "typeId": {
+          "enum": [ "map" ]
+        },
+        "keyTypeId":   { "$ref": "#/definitions/type-id" },
+        "keyType":     { "$ref": "#/definitions/type-desc" },
+        "valueTypeId": { "$ref": "#/definitions/type-id" },
+        "valueType":   { "$ref": "#/definitions/type-desc" }
+      },
+      "required": [ "typeId", "keyTypeId", "valueTypeId" ]
+    },
+    "struct-type": {
+      "title": "Struct, union and exception schema",
+      "type": "object",
+      "properties": {
+        "typeId": {
+          "enum": [ "union", "struct", "exception" ]
+        }
+      },
+      "required": [ "typeId", "class" ]
+    },
+    "type-desc": {
+      "title": "Type descriptor schema",
+      "allOf": [
+        {
+            "type": "object",
+            "properties": {
+                "typeId":      { "type": "string" },
+                "class":       { "type": "string" }
+            }
+        },
+        {
+          "oneOf":
+          [
+            { "$ref": "#/definitions/base-type" },
+            { "$ref": "#/definitions/list-type" },
+            { "$ref": "#/definitions/map-type" },
+            { "$ref": "#/definitions/struct-type" }
+          ]
+        }
+      ]
+    },
+    "name-and-doc": {
+      "title": "Name and documentation sub-schema",
+      "type": "object",
+      "properties": {
+        "name": { "type": "string" },
+        "doc": { "type": "string" }
+      },
+      "required": [ "name" ]
+    },
+    "enum": {
+      "title": "Thrift 'enum' definition schema",
+      "type": "object",
+      "allOf": [
+        { "$ref": "#/definitions/name-and-doc" },
+        {
+          "required": [ "members" ],
+          "properties": {
+            "members": {
+              "type": "array",
+              "items": {
+                "type": "object",
+                "properties": {
+                  "name": { "type": "string" },
+                  "value": { "type": "integer" }
+                },
+                "required": [ "name", "value" ]
+              }
+            }
+          }
+        }
+      ]
+    },
+    "typedef": {
+      "title": "Thrift typedef definition schema",
+      "type": "object",
+      "allOf": [
+        { "$ref": "#/definitions/name-and-doc" },
+        {
+          "properties": {
+            "typeId": { "$ref": "#/definitions/type-id" },
+            "type": { "$ref": "#/definitions/type-desc" }
+          },
+          "required": [ "typeId" ]
+        }
+      ]
+    },
+    "constant": {
+      "title": "Thrift constant definition schema",
+      "type": "object",
+      "allOf": [
+        { "$ref": "#/definitions/name-and-doc" },
+        { "$ref": "#/definitions/type-desc" },
+        {
+          "properties": {
+            "value": {
+              "oneOf": [
+                { "type": "string" },
+                { "type": "number" },
+                { "type": "array" },
+                { "type": "object" }
+              ]
+            }
+          },
+          "required": [ "value" ]
+        }
+      ]
+    },
+    "field": {
+      "title": "Thrift struct field definition schema",
+      "type": "object",
+      "allOf": [
+        { "$ref": "#/definitions/name-and-doc" },
+        {
+          "properties": {
+            "key": {
+              "type": "integer",
+              "minimum": 1,
+              "maximum": 65535
+            },
+            "required": {
+              "enum": [ "required", "optional", "req_out" ]
+            },
+            "typeId": { "$ref": "#/definitions/type-id" },
+            "type": { "$ref": "#/definitions/type-desc" },
+            "default": {
+              "oneOf": [
+                { "type": "string" },
+                { "type": "number" },
+                { "type": "array" },
+                { "type": "object" }
+              ]
+            }
+          },
+          "required": [ "key", "required" ]
+        }
+      ]
+    },
+    "struct": {
+      "title": "Thrift struct definition schema",
+      "type": "object",
+      "allOf": [
+        { "$ref": "#/definitions/name-and-doc" },
+        {
+          "properties": {
+            "isException": { "type": "boolean" },
+            "isUnion": { "type": "boolean" },
+            "fields": {
+              "type": "array",
+              "items": {
+                "$ref": "#/definitions/field"
+              }
+            }
+          },
+          "required": [ "isException", "isUnion", "fields" ]
+        }
+      ]
+    },
+    "union": {
+      "title": "Thrift union definition schema",
+      "$ref": "#/definitions/struct"
+    },
+    "exception": {
+      "title": "Thrift exception definition schema",
+      "type": "object",
+      "properties": {
+        "key": {
+          "type": "integer",
+          "minimum": 1,
+          "maximum": 65535
+        },
+        "name": { "type": "string" },
+        "typeId": { "enum": [ "exception" ] },
+        "type": { "$ref": "#/definitions/struct-type" }
+      },
+      "required": [ "key", "name", "typeId" ]
+    },
+    "function": {
+      "title": "Thrift service function definition schema",
+      "type": "object",
+      "allOf": [
+        { "$ref": "#/definitions/name-and-doc" },
+        {
+          "properties": {
+            "oneway": {
+              "type": "boolean"
+            },
+            "returnType": {
+              "$ref": "#/definitions/type-desc"
+            },
+            "arguments": {
+              "type": "array",
+              "items": {
+                "$ref": "#/definitions/field"
+              }
+            },
+            "exceptions": {
+              "type": "array",
+              "items": { "$ref": "#/definitions/exception" }
+            }
+          },
+          "required": [ "oneway", "arguments", "exceptions" ]
+        }
+      ]
+    },
+    "service": {
+      "title": "Thrift service definition schema",
+      "type": "object",
+      "allOf": [
+        { "$ref": "#/definitions/name-and-doc" },
+        {
+          "properties": {
+            "functions": {
+              "type": "array",
+              "items": {
+                "$ref": "#/definitions/function"
+              }
+            }
+          },
+          "required": [ "functions" ]
+        }
+      ]
+    },
+    "annotations": {
+      "title": "Map of annotation names to values",
+      "type": "object",
+      "additionalProperties": {
+        "type": "string"
+      }
+    }
+  },
+
+  "type": "object",
+  "required": [
+    "name",
+    "enums",
+    "typedefs",
+    "structs",
+    "constants",
+    "services"
+  ],
+  "properties": {
+    "name": {
+      "type": "string"
+    },
+    "includes": {
+      "type": "array",
+      "items": {
+        "type": "string"
+      },
+      "uniqueItems": true
+    },
+    "namespaces": {
+      "type": "object",
+      "additionalProperties": {
+        "type": "string"
+      }
+    },
+    "enums": {
+      "type": "array",
+      "items": {
+        "$ref": "#/definitions/enum"
+      }
+    },
+    "typedefs": {
+      "type": "array",
+      "items": {
+        "$ref": "#/definitions/typedef"
+      }
+    },
+    "structs": {
+      "type": "array",
+      "items": {
+        "$ref": "#/definitions/struct"
+      }
+    },
+    "constants": {
+      "type": "array",
+      "items": {
+        "$ref": "#/definitions/constant"
+      }
+    },
+    "services": {
+      "type": "array",
+      "items": {
+        "$ref": "#/definitions/service"
+      }
+    }
+  },
+  "additionalProperties": false
+}
diff --git a/lib/json/test/Makefile.am b/lib/json/test/Makefile.am
new file mode 100644
index 0000000..bb87a52
--- /dev/null
+++ b/lib/json/test/Makefile.am
@@ -0,0 +1,26 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+check:
+	$(ANT) $(ANT_FLAGS) test
+
+# Make sure this doesn't fail if ant is not configured.
+clean-local:
+	ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \
+	$$ANT $(ANT_FLAGS) clean
diff --git a/lib/json/test/build.properties b/lib/json/test/build.properties
new file mode 100644
index 0000000..075f640
--- /dev/null
+++ b/lib/json/test/build.properties
@@ -0,0 +1,10 @@
+# Jar versions
+mvn.ant.task.version=2.1.3
+
+# Dependency versions
+json-schema-validator.version=2.2.6
+
+# Maven dependency download locations
+mvn.repo=http://repo1.maven.org/maven2
+mvn.ant.task.url=${mvn.repo}/org/apache/maven/maven-ant-tasks/${mvn.ant.task.version}
+mvn.ant.task.jar=maven-ant-tasks-${mvn.ant.task.version}.jar
diff --git a/lib/json/test/build.xml b/lib/json/test/build.xml
new file mode 100644
index 0000000..956a238
--- /dev/null
+++ b/lib/json/test/build.xml
@@ -0,0 +1,144 @@
+<!--
+ 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.
+-->
+<project name="JSON Schema Test" default="test" basedir="."
+  xmlns:artifact="antlib:org.apache.maven.artifact.ant">
+
+  <description>JSON Schema Validation Test</description>
+
+  <property name="build.dir" location="${basedir}/build" />
+  <property name="json.dir" location="${basedir}/.." />
+  <property name="gen.json.dir" location="${build.dir}/gen-json" />
+  <property name="json.schema" location="${json.dir}/schema.json" />
+  <property name="build.tools.dir" location="${build.dir}/tools"/>
+  <property name="build.lib.dir" location="${build.dir}/lib"/>
+
+  <!-- the root directory, where you unpack thrift distibution (e.g. thrift-0.x.x.tar.gz) -->
+  <property name="thrift.dir" location="../../../" />
+  <property name="thrift.test.dir" location="${thrift.dir}/test" />
+  <property name="thrift.compiler" location="${thrift.dir}/compiler/cpp/thrift" />
+
+  <!-- Get maven dependency versions from here -->
+  <property file="${basedir}/build.properties" />
+
+  <path id="test.classpath">
+    <fileset dir="${build.lib.dir}">
+      <include name="*.jar" />
+    </fileset>
+  </path>
+
+  <target name="compiler.check">
+    <fail>
+      <condition>
+        <not>
+          <resourcecount count="1">
+            <fileset id="fs" file="${thrift.compiler}"/>
+          </resourcecount>
+        </not>
+      </condition>
+      Thrift compiler is missing !
+    </fail>
+  </target>
+
+  <target name="init" depends="compiler.check, mkdirs, mvn.init">
+    <tstamp />
+  </target>
+
+  <target name="mkdirs">
+    <mkdir dir="${build.dir}"/>
+    <mkdir dir="${build.lib.dir}"/>
+    <mkdir dir="${build.tools.dir}"/>
+    <mkdir dir="${gen.json.dir}"/>
+  </target>
+
+  <target name="generate" depends="init">
+    <exec executable="${thrift.compiler}" failonerror="true">
+      <arg line="--gen json"/>
+      <arg line="-out ${gen.json.dir}"/>
+      <arg line="${thrift.test.dir}/ThriftTest.thrift"/>
+    </exec>
+    <exec executable="${thrift.compiler}" failonerror="true">
+      <arg line="--gen json:merge"/>
+      <arg line="-out ${gen.json.dir}"/>
+      <arg line="${thrift.test.dir}/Include.thrift"/>
+    </exec>
+  </target>
+
+  <target name="test" description="run schema validation"
+          depends="validate-schema, validate-generated-json"/>
+
+  <target name="validate-schema" depends="init">
+    <java classname="com.github.fge.jsonschema.main.cli.Main"
+          classpathref="test.classpath" failonerror="true">
+      <arg value="--syntax"/>
+      <arg value="${json.schema}"/>
+    </java>
+  </target>
+
+  <target name="validate-generated-json" depends="init, generate">
+    <validate-json file="${gen.json.dir}/ThriftTest.json"/>
+    <validate-json file="${gen.json.dir}/Include.json"/>
+  </target>
+
+  <target name="clean">
+    <delete dir="${build.dir}" />
+    <delete dir="${gen.json.dir}" />
+  </target>
+
+  <target name="mvn.ant.tasks.download" depends="mkdirs,mvn.ant.tasks.check" unless="mvn.ant.tasks.found">
+    <get src="${mvn.ant.task.url}/${mvn.ant.task.jar}" dest="${build.tools.dir}/${mvn.ant.task.jar}" usetimestamp="true"/>
+  </target>
+
+  <target name="mvn.ant.tasks.check">
+    <condition property="mvn.ant.tasks.found">
+      <typefound uri="antlib:org.apache.maven.artifact.ant" name="artifact"/>
+    </condition>
+  </target>
+
+  <target name="mvn.init" depends="mvn.ant.tasks.download" unless="mvn.finished">
+    <typedef uri="antlib:org.apache.maven.artifact.ant" classpath="${build.tools.dir}/${mvn.ant.task.jar}"/>
+
+    <artifact:dependencies filesetId="test.dependency.jars">
+      <dependency groupId="com.github.fge" artifactId="json-schema-validator" version="${json-schema-validator.version}"/>
+    </artifact:dependencies>
+
+    <!-- Copy the dependencies to the build/lib dir -->
+    <copy todir="${build.lib.dir}">
+      <fileset refid="test.dependency.jars"/>
+      <mapper type="flatten"/>
+    </copy>
+
+    <property name="mvn.finished" value="true"/>
+  </target>
+
+  <macrodef name="validate-json">
+    <attribute name="file" default=""/>
+    <sequential>
+      <java failonerror="true"
+            fork="true"
+            dir="${json.dir}"
+            classname="com.github.fge.jsonschema.main.cli.Main"
+            classpathref="test.classpath">
+        <arg line="--fakeroot http://thrift.apache.org/"/>
+        <arg value="${json.schema}"/>
+        <arg value="@{file}"/>
+      </java>
+    </sequential>
+  </macrodef>
+
+</project>
diff --git a/lib/lua/Makefile.am b/lib/lua/Makefile.am
new file mode 100644
index 0000000..5b0f17a
--- /dev/null
+++ b/lib/lua/Makefile.am
@@ -0,0 +1,73 @@
+#
+# 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.
+#
+
+AUTOMAKE_OPTIONS = subdir-objects
+
+SUBDIRS = .
+
+lib_LTLIBRARIES = \
+			libluasocket.la \
+			liblualongnumber.la \
+			libluabpack.la \
+			libluabitwise.la
+
+libluasocket_la_SOURCES = \
+			src/luasocket.c \
+			src/usocket.c
+
+nobase_include_HEADERS = src/socket.h
+
+libluasocket_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE
+libluasocket_la_LDFLAGS = $(AM_LDFLAGS)
+libluasocket_la_LIBADD = $(LUA_LIB) -lm
+
+libluabpack_la_SOURCES = src/luabpack.c
+
+libluabpack_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE
+libluabpack_la_LDFLAGS = $(AM_LDFLAGS)
+libluabpack_la_LIBADD = liblualongnumber.la $(LUA_LIB) -lm
+
+libluabitwise_la_SOURCES = src/luabitwise.c
+
+libluabitwise_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE
+libluabitwise_la_LDFLAGS = $(AM_LDFLAGS)
+libluabitwise_la_LIBADD = $(LUA_LIB) -lm
+
+liblualongnumber_la_SOURCES = \
+		src/lualongnumber.c \
+		src/longnumberutils.c
+
+liblualongnumber_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE
+liblualongnumber_la_LDFLAGS = $(AM_LDFLAGS)
+liblualongnumber_la_LIBADD = $(LUA_LIB) -lm
+
+EXTRA_DIST = \
+		coding_standards.md \
+		TBinaryProtocol.lua \
+		TBufferedTransport.lua \
+		TCompactProtocol.lua \
+		TFramedTransport.lua \
+		Thrift.lua \
+		THttpTransport.lua \
+		TJsonProtocol.lua \
+		TMemoryBuffer.lua \
+		TProtocol.lua \
+		TServer.lua \
+		TSocket.lua \
+		TTransport.lua
diff --git a/lib/lua/TBinaryProtocol.lua b/lib/lua/TBinaryProtocol.lua
new file mode 100644
index 0000000..4b8e98a
--- /dev/null
+++ b/lib/lua/TBinaryProtocol.lua
@@ -0,0 +1,264 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+require 'TProtocol'
+require 'libluabpack'
+require 'libluabitwise'
+
+TBinaryProtocol = __TObject.new(TProtocolBase, {
+  __type = 'TBinaryProtocol',
+  VERSION_MASK = -65536, -- 0xffff0000
+  VERSION_1    = -2147418112, -- 0x80010000
+  TYPE_MASK    = 0x000000ff,
+  strictRead   = false,
+  strictWrite  = true
+})
+
+function TBinaryProtocol:writeMessageBegin(name, ttype, seqid)
+  if self.strictWrite then
+    self:writeI32(libluabitwise.bor(TBinaryProtocol.VERSION_1, ttype))
+    self:writeString(name)
+    self:writeI32(seqid)
+  else
+    self:writeString(name)
+    self:writeByte(ttype)
+    self:writeI32(seqid)
+  end
+end
+
+function TBinaryProtocol:writeMessageEnd()
+end
+
+function TBinaryProtocol:writeStructBegin(name)
+end
+
+function TBinaryProtocol:writeStructEnd()
+end
+
+function TBinaryProtocol:writeFieldBegin(name, ttype, id)
+  self:writeByte(ttype)
+  self:writeI16(id)
+end
+
+function TBinaryProtocol:writeFieldEnd()
+end
+
+function TBinaryProtocol:writeFieldStop()
+  self:writeByte(TType.STOP);
+end
+
+function TBinaryProtocol:writeMapBegin(ktype, vtype, size)
+  self:writeByte(ktype)
+  self:writeByte(vtype)
+  self:writeI32(size)
+end
+
+function TBinaryProtocol:writeMapEnd()
+end
+
+function TBinaryProtocol:writeListBegin(etype, size)
+  self:writeByte(etype)
+  self:writeI32(size)
+end
+
+function TBinaryProtocol:writeListEnd()
+end
+
+function TBinaryProtocol:writeSetBegin(etype, size)
+  self:writeByte(etype)
+  self:writeI32(size)
+end
+
+function TBinaryProtocol:writeSetEnd()
+end
+
+function TBinaryProtocol:writeBool(bool)
+  if bool then
+    self:writeByte(1)
+  else
+    self:writeByte(0)
+  end
+end
+
+function TBinaryProtocol:writeByte(byte)
+  local buff = libluabpack.bpack('c', byte)
+  self.trans:write(buff)
+end
+
+function TBinaryProtocol:writeI16(i16)
+  local buff = libluabpack.bpack('s', i16)
+  self.trans:write(buff)
+end
+
+function TBinaryProtocol:writeI32(i32)
+  local buff = libluabpack.bpack('i', i32)
+  self.trans:write(buff)
+end
+
+function TBinaryProtocol:writeI64(i64)
+  local buff = libluabpack.bpack('l', i64)
+  self.trans:write(buff)
+end
+
+function TBinaryProtocol:writeDouble(dub)
+  local buff = libluabpack.bpack('d', dub)
+  self.trans:write(buff)
+end
+
+function TBinaryProtocol:writeString(str)
+  -- Should be utf-8
+  self:writeI32(string.len(str))
+  self.trans:write(str)
+end
+
+function TBinaryProtocol:readMessageBegin()
+  local sz, ttype, name, seqid = self:readI32()
+  if sz < 0 then
+    local version = libluabitwise.band(sz, TBinaryProtocol.VERSION_MASK)
+    if version ~= TBinaryProtocol.VERSION_1 then
+      terror(TProtocolException:new{
+        message = 'Bad version in readMessageBegin: ' .. sz
+      })
+    end
+    ttype = libluabitwise.band(sz, TBinaryProtocol.TYPE_MASK)
+    name = self:readString()
+    seqid = self:readI32()
+  else
+    if self.strictRead then
+      terror(TProtocolException:new{message = 'No protocol version header'})
+    end
+    name = self.trans:readAll(sz)
+    ttype = self:readByte()
+    seqid = self:readI32()
+  end
+  return name, ttype, seqid
+end
+
+function TBinaryProtocol:readMessageEnd()
+end
+
+function TBinaryProtocol:readStructBegin()
+  return nil
+end
+
+function TBinaryProtocol:readStructEnd()
+end
+
+function TBinaryProtocol:readFieldBegin()
+  local ttype = self:readByte()
+  if ttype == TType.STOP then
+    return nil, ttype, 0
+  end
+  local id = self:readI16()
+  return nil, ttype, id
+end
+
+function TBinaryProtocol:readFieldEnd()
+end
+
+function TBinaryProtocol:readMapBegin()
+  local ktype = self:readByte()
+  local vtype = self:readByte()
+  local size = self:readI32()
+  return ktype, vtype, size
+end
+
+function TBinaryProtocol:readMapEnd()
+end
+
+function TBinaryProtocol:readListBegin()
+  local etype = self:readByte()
+  local size = self:readI32()
+  return etype, size
+end
+
+function TBinaryProtocol:readListEnd()
+end
+
+function TBinaryProtocol:readSetBegin()
+  local etype = self:readByte()
+  local size = self:readI32()
+  return etype, size
+end
+
+function TBinaryProtocol:readSetEnd()
+end
+
+function TBinaryProtocol:readBool()
+  local byte = self:readByte()
+  if byte == 0 then
+    return false
+  end
+  return true
+end
+
+function TBinaryProtocol:readByte()
+  local buff = self.trans:readAll(1)
+  local val = libluabpack.bunpack('c', buff)
+  return val
+end
+
+function TBinaryProtocol:readI16()
+  local buff = self.trans:readAll(2)
+  local val = libluabpack.bunpack('s', buff)
+  return val
+end
+
+function TBinaryProtocol:readI32()
+  local buff = self.trans:readAll(4)
+  local val = libluabpack.bunpack('i', buff)
+  return val
+end
+
+function TBinaryProtocol:readI64()
+  local buff = self.trans:readAll(8)
+  local val = libluabpack.bunpack('l', buff)
+  return val
+end
+
+function TBinaryProtocol:readDouble()
+  local buff = self.trans:readAll(8)
+  local val = libluabpack.bunpack('d', buff)
+  return val
+end
+
+function TBinaryProtocol:readString()
+  local len = self:readI32()
+  local str = self.trans:readAll(len)
+  return str
+end
+
+TBinaryProtocolFactory = TProtocolFactory:new{
+  __type = 'TBinaryProtocolFactory',
+  strictRead = false
+}
+
+function TBinaryProtocolFactory:getProtocol(trans)
+  -- TODO Enforce that this must be a transport class (ie not a bool)
+  if not trans then
+    terror(TProtocolException:new{
+      message = 'Must supply a transport to ' .. ttype(self)
+    })
+  end
+  return TBinaryProtocol:new{
+    trans = trans,
+    strictRead = self.strictRead,
+    strictWrite = true
+  }
+end
diff --git a/lib/lua/TBufferedTransport.lua b/lib/lua/TBufferedTransport.lua
new file mode 100644
index 0000000..45ef4b1
--- /dev/null
+++ b/lib/lua/TBufferedTransport.lua
@@ -0,0 +1,91 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+require 'TTransport'
+
+TBufferedTransport = TTransportBase:new{
+  __type = 'TBufferedTransport',
+  rBufSize = 2048,
+  wBufSize = 2048,
+  wBuf = '',
+  rBuf = ''
+}
+
+function TBufferedTransport:new(obj)
+  if ttype(obj) ~= 'table' then
+    error(ttype(self) .. 'must be initialized with a table')
+  end
+
+  -- Ensure a transport is provided
+  if not obj.trans then
+    error('You must provide ' .. ttype(self) .. ' with a trans')
+  end
+
+  return TTransportBase.new(self, obj)
+end
+
+function TBufferedTransport:isOpen()
+  return self.trans:isOpen()
+end
+
+function TBufferedTransport:open()
+  return self.trans:open()
+end
+
+function TBufferedTransport:close()
+  return self.trans:close()
+end
+
+function TBufferedTransport:read(len)
+  return self.trans:read(len)
+end
+
+function TBufferedTransport:readAll(len)
+  return self.trans:readAll(len)
+end
+
+function TBufferedTransport:write(buf)
+  self.wBuf = self.wBuf .. buf
+  if string.len(self.wBuf) >= self.wBufSize then
+    self.trans:write(self.wBuf)
+    self.wBuf = ''
+  end
+end
+
+function TBufferedTransport:flush()
+  if string.len(self.wBuf) > 0 then
+    self.trans:write(self.wBuf)
+    self.wBuf = ''
+  end
+end
+
+TBufferedTransportFactory = TTransportFactoryBase:new{
+  __type = 'TBufferedTransportFactory'
+}
+
+function TBufferedTransportFactory:getTransport(trans)
+  if not trans then
+    terror(TTransportException:new{
+      message = 'Must supply a transport to ' .. ttype(self)
+    })
+  end
+  return TBufferedTransport:new{
+    trans = trans
+  }
+end
diff --git a/lib/lua/TCompactProtocol.lua b/lib/lua/TCompactProtocol.lua
new file mode 100644
index 0000000..877595a
--- /dev/null
+++ b/lib/lua/TCompactProtocol.lua
@@ -0,0 +1,457 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+require 'TProtocol'
+require 'libluabpack'
+require 'libluabitwise'
+require 'liblualongnumber'
+
+TCompactProtocol = __TObject.new(TProtocolBase, {
+  __type = 'TCompactProtocol',
+  COMPACT_PROTOCOL_ID       = 0x82,
+  COMPACT_VERSION           = 1,
+  COMPACT_VERSION_MASK      = 0x1f,
+  COMPACT_TYPE_MASK         = 0xE0,
+  COMPACT_TYPE_BITS         = 0x07,
+  COMPACT_TYPE_SHIFT_AMOUNT = 5,
+
+  -- Used to keep track of the last field for the current and previous structs,
+  -- so we can do the delta stuff.
+  lastField = {},
+  lastFieldId = 0,
+  lastFieldIndex = 1,
+
+  -- If we encounter a boolean field begin, save the TField here so it can
+  -- have the value incorporated.
+  booleanFieldName    = "",
+  booleanFieldId      = 0,
+  booleanFieldPending = false,
+
+  -- If we read a field header, and it's a boolean field, save the boolean
+  -- value here so that readBool can use it.
+  boolValue          = false,
+  boolValueIsNotNull = false,
+})
+
+TCompactType = {
+  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
+}
+
+TTypeToCompactType = {}
+TTypeToCompactType[TType.STOP]   = TType.STOP
+TTypeToCompactType[TType.BOOL]   = TCompactType.COMPACT_BOOLEAN_TRUE
+TTypeToCompactType[TType.BYTE]   = TCompactType.COMPACT_BYTE
+TTypeToCompactType[TType.I16]    = TCompactType.COMPACT_I16
+TTypeToCompactType[TType.I32]    = TCompactType.COMPACT_I32
+TTypeToCompactType[TType.I64]    = TCompactType.COMPACT_I64
+TTypeToCompactType[TType.DOUBLE] = TCompactType.COMPACT_DOUBLE
+TTypeToCompactType[TType.STRING] = TCompactType.COMPACT_BINARY
+TTypeToCompactType[TType.LIST]   = TCompactType.COMPACT_LIST
+TTypeToCompactType[TType.SET]    = TCompactType.COMPACT_SET
+TTypeToCompactType[TType.MAP]    = TCompactType.COMPACT_MAP
+TTypeToCompactType[TType.STRUCT] = TCompactType.COMPACT_STRUCT
+
+CompactTypeToTType = {}
+CompactTypeToTType[TType.STOP]                        = TType.STOP
+CompactTypeToTType[TCompactType.COMPACT_BOOLEAN_TRUE] = TType.BOOL
+CompactTypeToTType[TCompactType.COMPACT_BOOLEAN_FALSE] = TType.BOOL
+CompactTypeToTType[TCompactType.COMPACT_BYTE]         = TType.BYTE
+CompactTypeToTType[TCompactType.COMPACT_I16]          = TType.I16
+CompactTypeToTType[TCompactType.COMPACT_I32]          = TType.I32
+CompactTypeToTType[TCompactType.COMPACT_I64]          = TType.I64
+CompactTypeToTType[TCompactType.COMPACT_DOUBLE]       = TType.DOUBLE
+CompactTypeToTType[TCompactType.COMPACT_BINARY]       = TType.STRING
+CompactTypeToTType[TCompactType.COMPACT_LIST]         = TType.LIST
+CompactTypeToTType[TCompactType.COMPACT_SET]          = TType.SET
+CompactTypeToTType[TCompactType.COMPACT_MAP]          = TType.MAP
+CompactTypeToTType[TCompactType.COMPACT_STRUCT]       = TType.STRUCT
+
+function TCompactProtocol:resetLastField()
+  self.lastField = {}
+  self.lastFieldId = 0
+  self.lastFieldIndex = 1
+end
+
+function TCompactProtocol:packCompactType(ktype, vtype)
+  return libluabitwise.bor(libluabitwise.shiftl(ktype, 4), vtype)
+end
+
+function TCompactProtocol:writeMessageBegin(name, ttype, seqid)
+  self:writeByte(TCompactProtocol.COMPACT_PROTOCOL_ID)
+  self:writeByte(libluabpack.packMesgType(TCompactProtocol.COMPACT_VERSION,
+    TCompactProtocol.COMPACT_VERSION_MASK,ttype,
+    TCompactProtocol.COMPACT_TYPE_SHIFT_AMOUNT,
+    TCompactProtocol.COMPACT_TYPE_MASK))
+  self:writeVarint32(seqid)
+  self:writeString(name)
+  self:resetLastField()
+end
+
+function TCompactProtocol:writeMessageEnd()
+end
+
+function TCompactProtocol:writeStructBegin(name)
+  self.lastFieldIndex = self.lastFieldIndex + 1
+  self.lastField[self.lastFieldIndex] = self.lastFieldId
+  self.lastFieldId = 0
+end
+
+function TCompactProtocol:writeStructEnd()
+  self.lastFieldIndex = self.lastFieldIndex - 1
+  self.lastFieldId = self.lastField[self.lastFieldIndex]
+end
+
+function TCompactProtocol:writeFieldBegin(name, ttype, id)
+  if ttype == TType.BOOL then
+    self.booleanFieldName = name
+    self.booleanFieldId   = id
+    self.booleanFieldPending = true
+  else
+    self:writeFieldBeginInternal(name, ttype, id, -1)
+  end
+end
+
+function TCompactProtocol:writeFieldEnd()
+end
+
+function TCompactProtocol:writeFieldStop()
+  self:writeByte(TType.STOP);
+end
+
+function TCompactProtocol:writeMapBegin(ktype, vtype, size)
+  if size == 0 then
+    self:writeByte(0)
+  else
+    self:writeVarint32(size)
+    self:writeByte(self:packCompactType(TTypeToCompactType[ktype], TTypeToCompactType[vtype]))
+  end
+end
+
+function TCompactProtocol:writeMapEnd()
+end
+
+function TCompactProtocol:writeListBegin(etype, size)
+  self:writeCollectionBegin(etype, size)
+end
+
+function TCompactProtocol:writeListEnd()
+end
+
+function TCompactProtocol:writeSetBegin(etype, size)
+  self:writeCollectionBegin(etype, size)
+end
+
+function TCompactProtocol:writeSetEnd()
+end
+
+function TCompactProtocol:writeBool(bool)
+  local value = TCompactType.COMPACT_BOOLEAN_FALSE
+  if bool then
+    value = TCompactType.COMPACT_BOOLEAN_TRUE
+  end
+  print(value,self.booleanFieldPending,self.booleanFieldId)
+  if self.booleanFieldPending then
+    self:writeFieldBeginInternal(self.booleanFieldName, TType.BOOL, self.booleanFieldId, value)
+    self.booleanFieldPending = false
+  else
+    self:writeByte(value)
+  end
+end
+
+function TCompactProtocol:writeByte(byte)
+  local buff = libluabpack.bpack('c', byte)
+  self.trans:write(buff)
+end
+
+function TCompactProtocol:writeI16(i16)
+  self:writeVarint32(libluabpack.i32ToZigzag(i16))
+end
+
+function TCompactProtocol:writeI32(i32)
+  self:writeVarint32(libluabpack.i32ToZigzag(i32))
+end
+
+function TCompactProtocol:writeI64(i64)
+  self:writeVarint64(libluabpack.i64ToZigzag(i64))
+end
+
+function TCompactProtocol:writeDouble(dub)
+  local buff = libluabpack.bpack('d', dub)
+  self.trans:write(buff)
+end
+
+function TCompactProtocol:writeString(str)
+  -- Should be utf-8
+  self:writeBinary(str)
+end
+
+function TCompactProtocol:writeBinary(str)
+  -- Should be utf-8
+  self:writeVarint32(string.len(str))
+  self.trans:write(str)
+end
+
+function TCompactProtocol:writeFieldBeginInternal(name, ttype, id, typeOverride)
+  if typeOverride == -1 then
+    typeOverride = TTypeToCompactType[ttype]
+  end
+  local offset = id - self.lastFieldId
+  if id > self.lastFieldId and offset <= 15 then
+    self:writeByte(libluabitwise.bor(libluabitwise.shiftl(offset, 4), typeOverride))
+  else
+    self:writeByte(typeOverride)
+    self:writeI16(id)
+  end
+  self.lastFieldId = id
+end
+
+function TCompactProtocol:writeCollectionBegin(etype, size)
+  if size <= 14 then
+    self:writeByte(libluabitwise.bor(libluabitwise.shiftl(size, 4), TTypeToCompactType[etype]))
+  else
+    self:writeByte(libluabitwise.bor(0xf0, TTypeToCompactType[etype]))
+    self:writeVarint32(size)
+  end
+end
+
+function TCompactProtocol:writeVarint32(i32)
+  -- Should be utf-8
+  local str = libluabpack.toVarint32(i32)
+  self.trans:write(str)
+end
+
+function TCompactProtocol:writeVarint64(i64)
+  -- Should be utf-8
+  local str = libluabpack.toVarint64(i64)
+  self.trans:write(str)
+end
+
+function TCompactProtocol:readMessageBegin()
+  local protocolId = self:readSignByte()
+  if protocolId ~= self.COMPACT_PROTOCOL_ID then
+    terror(TProtocolException:new{
+      message = "Expected protocol id " .. self.COMPACT_PROTOCOL_ID .. " but got " .. protocolId})
+  end
+  local versionAndType = self:readSignByte()
+  local version = libluabitwise.band(versionAndType, self.COMPACT_VERSION_MASK)
+  local ttype = libluabitwise.band(libluabitwise.shiftr(versionAndType,
+    self.COMPACT_TYPE_SHIFT_AMOUNT), self.COMPACT_TYPE_BITS)
+  if version ~= self.COMPACT_VERSION then
+    terror(TProtocolException:new{
+      message = "Expected version " .. self.COMPACT_VERSION .. " but got " .. version})
+  end
+  local seqid = self:readVarint32()
+  local name = self:readString()
+  return name, ttype, seqid
+end
+
+function TCompactProtocol:readMessageEnd()
+end
+
+function TCompactProtocol:readStructBegin()
+  self.lastField[self.lastFieldIndex] = self.lastFieldId
+  self.lastFieldIndex = self.lastFieldIndex + 1
+  self.lastFieldId = 0
+  return nil
+end
+
+function TCompactProtocol:readStructEnd()
+  self.lastFieldIndex = self.lastFieldIndex - 1
+  self.lastFieldId = self.lastField[self.lastFieldIndex]
+end
+
+function TCompactProtocol:readFieldBegin()
+  local field_and_ttype = self:readSignByte()
+  local ttype = self:getTType(field_and_ttype)
+  if ttype == TType.STOP then
+    return nil, ttype, 0
+  end
+  -- mask off the 4 MSB of the type header. it could contain a field id delta.
+  local modifier = libluabitwise.shiftr(libluabitwise.band(field_and_ttype, 0xf0), 4)
+  local id = 0
+  if modifier == 0 then
+    id = self:readI16()
+  else
+    id = self.lastFieldId + modifier
+  end
+  if ttype == TType.BOOL then
+    boolValue = libluabitwise.band(field_and_ttype, 0x0f) == TCompactType.COMPACT_BOOLEAN_TRUE
+    boolValueIsNotNull = true
+  end
+  self.lastFieldId = id
+  return nil, ttype, id
+end
+
+function TCompactProtocol:readFieldEnd()
+end
+
+function TCompactProtocol:readMapBegin()
+  local size = self:readVarint32()
+  if size < 0 then
+    return nil,nil,nil
+  end
+  local kvtype = self:readSignByte()
+  local ktype = self:getTType(libluabitwise.shiftr(kvtype, 4))
+  local vtype = self:getTType(kvtype)
+  return ktype, vtype, size
+end
+
+function TCompactProtocol:readMapEnd()
+end
+
+function TCompactProtocol:readListBegin()
+  local size_and_type = self:readSignByte()
+  local size = libluabitwise.band(libluabitwise.shiftr(size_and_type, 4), 0x0f)
+  if size == 15 then
+    size = self:readVarint32()
+  end
+  if size < 0 then
+    return nil,nil
+  end
+  local etype = self:getTType(libluabitwise.band(size_and_type, 0x0f))
+  return etype, size
+end
+
+function TCompactProtocol:readListEnd()
+end
+
+function TCompactProtocol:readSetBegin()
+  return self:readListBegin()
+end
+
+function TCompactProtocol:readSetEnd()
+end
+
+function TCompactProtocol:readBool()
+  if boolValueIsNotNull then
+    boolValueIsNotNull = true
+    return boolValue
+  end
+  local val = self:readSignByte()
+  if val == TCompactType.COMPACT_BOOLEAN_TRUE then
+    return true
+  end
+  return false
+end
+
+function TCompactProtocol:readByte()
+  local buff = self.trans:readAll(1)
+  local val = libluabpack.bunpack('c', buff)
+  return val
+end
+
+function TCompactProtocol:readSignByte()
+  local buff = self.trans:readAll(1)
+  local val = libluabpack.bunpack('C', buff)
+  return val
+end
+
+function TCompactProtocol:readI16()
+  return self:readI32()
+end
+
+function TCompactProtocol:readI32()
+  local v = self:readVarint32()
+  local value = libluabpack.zigzagToI32(v)
+  return value
+end
+
+function TCompactProtocol:readI64()
+  local value = self:readVarint64()
+  return value
+end
+
+function TCompactProtocol:readDouble()
+  local buff = self.trans:readAll(8)
+  local val = libluabpack.bunpack('d', buff)
+  return val
+end
+
+function TCompactProtocol:readString()
+  return self:readBinary()
+end
+
+function TCompactProtocol:readBinary()
+  local size = self:readVarint32()
+  if size <= 0 then
+    return ""
+  end
+  return self.trans:readAll(size)
+end
+
+function TCompactProtocol:readVarint32()
+  local shiftl = 0
+  local result = 0
+  while true do
+    b = self:readByte()
+    result = libluabitwise.bor(result,
+             libluabitwise.shiftl(libluabitwise.band(b, 0x7f), shiftl))
+    if libluabitwise.band(b, 0x80) ~= 0x80 then
+      break
+    end
+    shiftl = shiftl + 7
+  end
+  return result
+end
+
+function TCompactProtocol:readVarint64()
+  local result = liblualongnumber.new
+  local data = result(0)
+  local shiftl = 0
+  while true do
+    b = self:readByte()
+    endFlag, data = libluabpack.fromVarint64(b, shiftl, data)
+    shiftl = shiftl + 7
+    if endFlag == 0 then
+      break
+    end
+  end
+  return data
+end
+
+function TCompactProtocol:getTType(ctype)
+  return CompactTypeToTType[libluabitwise.band(ctype, 0x0f)]
+end
+
+TCompactProtocolFactory = TProtocolFactory:new{
+  __type = 'TCompactProtocolFactory',
+}
+
+function TCompactProtocolFactory:getProtocol(trans)
+  -- TODO Enforce that this must be a transport class (ie not a bool)
+  if not trans then
+    terror(TProtocolException:new{
+      message = 'Must supply a transport to ' .. ttype(self)
+    })
+  end
+  return TCompactProtocol:new{
+    trans = trans
+  }
+end
diff --git a/lib/lua/TFramedTransport.lua b/lib/lua/TFramedTransport.lua
new file mode 100644
index 0000000..768e2d9
--- /dev/null
+++ b/lib/lua/TFramedTransport.lua
@@ -0,0 +1,118 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+require 'TTransport'
+require 'libluabpack'
+
+TFramedTransport = TTransportBase:new{
+  __type = 'TFramedTransport',
+  doRead = true,
+  doWrite = true,
+  wBuf = '',
+  rBuf = ''
+}
+
+function TFramedTransport:new(obj)
+  if ttype(obj) ~= 'table' then
+    error(ttype(self) .. 'must be initialized with a table')
+  end
+
+  -- Ensure a transport is provided
+  if not obj.trans then
+    error('You must provide ' .. ttype(self) .. ' with a trans')
+  end
+
+  return TTransportBase.new(self, obj)
+end
+
+function TFramedTransport:isOpen()
+  return self.trans:isOpen()
+end
+
+function TFramedTransport:open()
+  return self.trans:open()
+end
+
+function TFramedTransport:close()
+  return self.trans:close()
+end
+
+function TFramedTransport:read(len)
+  if string.len(self.rBuf) == 0 then
+    self:__readFrame()
+  end
+
+  if self.doRead == false then
+    return self.trans:read(len)
+  end
+
+  if len > string.len(self.rBuf) then
+    local val = self.rBuf
+    self.rBuf = ''
+    return val
+  end
+
+  local val = string.sub(self.rBuf, 0, len)
+  self.rBuf = string.sub(self.rBuf, len+1)
+  return val
+end
+
+function TFramedTransport:__readFrame()
+  local buf = self.trans:readAll(4)
+  local frame_len = libluabpack.bunpack('i', buf)
+  self.rBuf = self.trans:readAll(frame_len)
+end
+
+
+function TFramedTransport:write(buf, len)
+  if self.doWrite == false then
+    return self.trans:write(buf, len)
+  end
+
+  if len and len < string.len(buf) then
+    buf = string.sub(buf, 0, len)
+  end
+  self.wBuf = self.wBuf .. buf
+end
+
+function TFramedTransport:flush()
+  if self.doWrite == false then
+    return self.trans:flush()
+  end
+
+  -- If the write fails we still want wBuf to be clear
+  local tmp = self.wBuf
+  self.wBuf = ''
+  local frame_len_buf = libluabpack.bpack("i", string.len(tmp))
+  tmp = frame_len_buf .. tmp
+  self.trans:write(tmp)
+  self.trans:flush()
+end
+
+TFramedTransportFactory = TTransportFactoryBase:new{
+  __type = 'TFramedTransportFactory'
+}
+function TFramedTransportFactory:getTransport(trans)
+  if not trans then
+    terror(TProtocolException:new{
+      message = 'Must supply a transport to ' .. ttype(self)
+    })
+  end
+  return TFramedTransport:new{trans = trans}
+end
diff --git a/lib/lua/THttpTransport.lua b/lib/lua/THttpTransport.lua
new file mode 100644
index 0000000..2951db7
--- /dev/null
+++ b/lib/lua/THttpTransport.lua
@@ -0,0 +1,182 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+require 'TTransport'
+
+THttpTransport = TTransportBase:new{
+  __type = 'THttpTransport',
+  path = '/',
+  wBuf = '',
+  rBuf = '',
+  CRLF = '\r\n',
+  VERSION = version,
+  isServer = true
+}
+
+function THttpTransport:new(obj)
+  if ttype(obj) ~= 'table' then
+    error(ttype(self) .. 'must be initialized with a table')
+  end
+
+  -- Ensure a transport is provided
+  if not obj.trans then
+    error('You must provide ' .. ttype(self) .. ' with a trans')
+  end
+
+  return TTransportBase.new(self, obj)
+end
+
+function THttpTransport:isOpen()
+  return self.trans:isOpen()
+end
+
+function THttpTransport:open()
+  return self.trans:open()
+end
+
+function THttpTransport:close()
+  return self.trans:close()
+end
+
+function THttpTransport:readAll(len)
+  return self:read(len)
+end
+
+function THttpTransport:read(len)
+  if string.len(self.rBuf) == 0 then
+    self:_readMsg()
+  end
+  if len > string.len(self.rBuf) then
+    local val = self.rBuf
+    self.rBuf = ''
+    return val
+  end
+
+  local val = string.sub(self.rBuf, 0, len)
+  self.rBuf = string.sub(self.rBuf, len+1)
+  return val
+end
+
+function THttpTransport:_readMsg()
+  while true do
+    self.rBuf = self.rBuf .. self.trans:read(4)
+    if string.find(self.rBuf, self.CRLF .. self.CRLF) then
+      break
+    end
+  end
+  if not self.rBuf then
+    self.rBuf = ""
+    return
+  end
+  self:getLine()
+  local headers = self:_parseHeaders()
+  if not headers then
+    self.rBuf = ""
+    return
+  end
+
+  local length = tonumber(headers["Content-Length"])
+  if length then
+    length = length - string.len(self.rBuf)
+    self.rBuf = self.rBuf .. self.trans:readAll(length)
+  end
+  if self.rBuf == nil then
+    self.rBuf = ""
+  end
+end
+
+function THttpTransport:getLine()
+  local a,b = string.find(self.rBuf, self.CRLF)
+  local line = ""
+  if a and b then
+    line = string.sub(self.rBuf, 0, a-1)
+    self.rBuf = string.sub(self.rBuf, b+1)
+  end
+  return line
+end
+
+function THttpTransport:_parseHeaders()
+  local headers = {}
+
+  repeat
+    local line = self:getLine()
+    for key, val in string.gmatch(line, "([%w%-]+)%s*:%s*(.+)") do
+      if headers[key] then
+        local delimiter = ", "
+        if key == "Set-Cookie" then
+          delimiter = "; "
+        end
+        headers[key] = headers[key] .. delimiter .. tostring(val)
+      else
+        headers[key] = tostring(val)
+      end
+    end
+  until string.find(line, "^%s*$")
+
+  return headers
+end
+
+function THttpTransport:write(buf, len)
+  if len and len < string.len(buf) then
+    buf = string.sub(buf, 0, len)
+  end
+  self.wBuf = self.wBuf .. buf
+end
+
+function THttpTransport:writeHttpHeader(content_len)
+  if self.isServer then
+    local header =  "HTTP/1.1 200 OK" .. self.CRLF
+      .. "Server: Thrift/" .. self.VERSION .. self.CRLF
+      .. "Access-Control-Allow-Origin: *" .. self.CRLF
+      .. "Content-Type: application/x-thrift" .. self.CRLF
+      .. "Content-Length: " .. content_len .. self.CRLF
+      .. "Connection: Keep-Alive" .. self.CRLF .. self.CRLF
+    self.trans:write(header)
+  else
+    local header = "POST " .. self.path .. " HTTP/1.1" .. self.CRLF
+      .. "Host: " .. self.trans.host .. self.CRLF
+      .. "Content-Type: application/x-thrift" .. self.CRLF
+      .. "Content-Length: " .. content_len .. self.CRLF
+      .. "Accept: application/x-thrift " .. self.CRLF
+      .. "User-Agent: Thrift/" .. self.VERSION .. " (Lua/THttpClient)"
+      .. self.CRLF .. self.CRLF
+    self.trans:write(header)
+  end
+end
+
+function THttpTransport:flush()
+  -- If the write fails we still want wBuf to be clear
+  local tmp = self.wBuf
+  self.wBuf = ''
+  self:writeHttpHeader(string.len(tmp))
+  self.trans:write(tmp)
+  self.trans:flush()
+end
+
+THttpTransportFactory = TTransportFactoryBase:new{
+  __type = 'THttpTransportFactory'
+}
+function THttpTransportFactory:getTransport(trans)
+  if not trans then
+    terror(TProtocolException:new{
+      message = 'Must supply a transport to ' .. ttype(self)
+    })
+  end
+  return THttpTransport:new{trans = trans}
+end
diff --git a/lib/lua/TJsonProtocol.lua b/lib/lua/TJsonProtocol.lua
new file mode 100644
index 0000000..db08eec
--- /dev/null
+++ b/lib/lua/TJsonProtocol.lua
@@ -0,0 +1,727 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"), you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+require 'TProtocol'
+require 'libluabpack'
+require 'libluabitwise'
+
+TJSONProtocol = __TObject.new(TProtocolBase, {
+  __type = 'TJSONProtocol',
+  THRIFT_JSON_PROTOCOL_VERSION = 1,
+  jsonContext = {},
+  jsonContextVal = {first = true, colon = true, ttype = 2, null = true},
+  jsonContextIndex = 1,
+  hasReadByte = ""
+})
+
+TTypeToString = {}
+TTypeToString[TType.BOOL]   = "tf"
+TTypeToString[TType.BYTE]   = "i8"
+TTypeToString[TType.I16]    = "i16"
+TTypeToString[TType.I32]    = "i32"
+TTypeToString[TType.I64]    = "i64"
+TTypeToString[TType.DOUBLE] = "dbl"
+TTypeToString[TType.STRING] = "str"
+TTypeToString[TType.STRUCT] = "rec"
+TTypeToString[TType.LIST]   = "lst"
+TTypeToString[TType.SET]    = "set"
+TTypeToString[TType.MAP]    = "map"
+
+StringToTType = {
+  tf  = TType.BOOL,
+  i8  = TType.BYTE,
+  i16 = TType.I16,
+  i32 = TType.I32,
+  i64 = TType.I64,
+  dbl = TType.DOUBLE,
+  str = TType.STRING,
+  rec = TType.STRUCT,
+  map = TType.MAP,
+  set = TType.SET,
+  lst = TType.LIST
+}
+
+JSONNode = {
+  ObjectBegin = '{',
+  ObjectEnd = '}',
+  ArrayBegin = '[',
+  ArrayEnd = ']',
+  PairSeparator = ':',
+  ElemSeparator = ',',
+  Backslash = '\\',
+  StringDelimiter = '"',
+  ZeroChar = '0',
+  EscapeChar = 'u',
+  Nan = 'NaN',
+  Infinity = 'Infinity',
+  NegativeInfinity = '-Infinity',
+  EscapeChars = "\"\\bfnrt",
+  EscapePrefix = "\\u00"
+}
+
+EscapeCharVals = {
+  '"', '\\', '\b', '\f', '\n', '\r', '\t'
+}
+
+JSONCharTable = {
+  --0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+    0,  0,  0,  0,  0,  0,  0,  0, 98,116,110,  0,102,114,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    1,  1,34,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+}
+
+-- character table string
+local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+
+-- encoding
+function base64_encode(data)
+    return ((data:gsub('.', function(x) 
+        local r,b='',x:byte()
+        for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
+        return r;
+    end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
+        if (#x < 6) then return '' end
+        local c=0
+        for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
+        return b:sub(c+1,c+1)
+    end)..({ '', '==', '=' })[#data%3+1])
+end
+
+-- decoding
+function base64_decode(data)
+    data = string.gsub(data, '[^'..b..'=]', '')
+    return (data:gsub('.', function(x)
+        if (x == '=') then return '' end
+        local r,f='',(b:find(x)-1)
+        for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
+        return r;
+    end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
+        if (#x ~= 8) then return '' end
+        local c=0
+        for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
+        return string.char(c)
+    end))
+end
+
+function TJSONProtocol:resetContext()
+  self.jsonContext = {}
+  self.jsonContextVal = {first = true, colon = true, ttype = 2, null = true}
+  self.jsonContextIndex = 1
+end
+
+function TJSONProtocol:contextPush(context)
+  self.jsonContextIndex = self.jsonContextIndex + 1
+  self.jsonContext[self.jsonContextIndex] = self.jsonContextVal
+  self.jsonContextVal = context
+end
+
+function TJSONProtocol:contextPop()
+  self.jsonContextVal = self.jsonContext[self.jsonContextIndex]
+  self.jsonContextIndex = self.jsonContextIndex - 1
+end
+
+function TJSONProtocol:escapeNum()
+  if self.jsonContextVal.ttype == 1 then
+    return self.jsonContextVal.colon
+  else
+    return false
+  end
+end
+
+function TJSONProtocol:writeElemSeparator()
+  if self.jsonContextVal.null then
+    return
+  end
+  if self.jsonContextVal.first then
+    self.jsonContextVal.first = false
+  else
+    if self.jsonContextVal.ttype == 1 then
+      if self.jsonContextVal.colon then
+        self.trans:write(JSONNode.PairSeparator)
+        self.jsonContextVal.colon = false
+      else
+        self.trans:write(JSONNode.ElemSeparator)
+        self.jsonContextVal.colon = true
+      end
+    else
+      self.trans:write(JSONNode.ElemSeparator)
+    end
+  end
+end
+
+function TJSONProtocol:hexChar(val)
+  val = libluabitwise.band(val, 0x0f)
+  if val < 10 then
+    return val + 48
+  else
+    return val + 87
+  end
+end
+
+function TJSONProtocol:writeJSONEscapeChar(ch)
+  self.trans:write(JSONNode.EscapePrefix)
+  local outCh = hexChar(libluabitwise.shiftr(ch, 4))
+  local buff = libluabpack.bpack('c', outCh)
+  self.trans:write(buff)
+  outCh = hexChar(ch)
+  buff = libluabpack.bpack('c', outCh)
+  self.trans:write(buff)
+end
+
+function TJSONProtocol:writeJSONChar(byte)
+  ch = string.byte(byte)
+  if ch >= 0x30 then
+    if ch == JSONNode.Backslash then
+      self.trans:write(JSONNode.Backslash)
+      self.trans:write(JSONNode.Backslash)
+    else
+      self.trans:write(byte)
+    end
+  else
+    local outCh = JSONCharTable[ch+1]
+    if outCh == 1 then
+      self.trans:write(byte)
+    elseif outCh > 1 then
+      self.trans:write(JSONNode.Backslash)
+      local buff = libluabpack.bpack('c', outCh)
+      self.trans:write(buff)
+    else
+      self:writeJSONEscapeChar(ch)
+    end
+  end
+end
+
+function TJSONProtocol:writeJSONString(str)
+  self:writeElemSeparator()
+  self.trans:write(JSONNode.StringDelimiter)
+  -- TODO escape special characters
+  local length = string.len(str)
+  local ii = 1
+  while ii <= length do
+    self:writeJSONChar(string.sub(str, ii, ii))
+    ii = ii + 1
+  end
+  self.trans:write(JSONNode.StringDelimiter)
+end
+
+function TJSONProtocol:writeJSONBase64(str)
+  self:writeElemSeparator()
+  self.trans:write(JSONNode.StringDelimiter)
+  local length = string.len(str)
+  local offset = 1
+  while length >= 3 do
+    -- Encode 3 bytes at a time
+    local bytes = base64_encode(string.sub(str, offset, offset+3))
+    self.trans:write(bytes)
+    length = length - 3
+    offset = offset + 3
+  end
+  if length > 0 then
+    local bytes = base64_encode(string.sub(str, offset, offset+length))
+    self.trans:write(bytes)
+  end
+  self.trans:write(JSONNode.StringDelimiter)
+end
+
+function TJSONProtocol:writeJSONInteger(num)
+  self:writeElemSeparator()
+  if self:escapeNum() then
+    self.trans:write(JSONNode.StringDelimiter)
+  end
+  local numstr = "" .. num
+  numstr = string.sub(numstr, string.find(numstr, "^[+-]?%d+"))
+  self.trans:write(numstr)
+  if self:escapeNum() then
+    self.trans:write(JSONNode.StringDelimiter)
+  end
+end
+
+function TJSONProtocol:writeJSONDouble(dub)
+  self:writeElemSeparator()
+  local val = "" .. dub
+  local prefix = string.sub(val, 1, 1)
+  local special = false
+  if prefix == 'N' or prefix == 'n' then
+    val = JSONNode.Nan
+    special = true
+  elseif prefix == 'I' or prefix == 'i' then
+    val = JSONNode.Infinity
+    special = true
+  elseif prefix == '-' then
+    local secondByte = string.sub(val, 2, 2)
+    if secondByte == 'I' or secondByte == 'i' then
+      val = JSONNode.NegativeInfinity
+      special = true
+    end
+  end
+
+  if special or self:escapeNum() then
+    self.trans:write(JSONNode.StringDelimiter)
+  end
+  self.trans:write(val)
+  if special or self:escapeNum() then
+    self.trans:write(JSONNode.StringDelimiter)
+  end
+end
+
+function TJSONProtocol:writeJSONObjectBegin()
+  self:writeElemSeparator()
+  self.trans:write(JSONNode.ObjectBegin)
+  self:contextPush({first = true, colon = true, ttype = 1, null = false})
+end
+
+function TJSONProtocol:writeJSONObjectEnd()
+  self:contextPop()
+  self.trans:write(JSONNode.ObjectEnd)
+end
+
+function TJSONProtocol:writeJSONArrayBegin()
+  self:writeElemSeparator()
+  self.trans:write(JSONNode.ArrayBegin)
+  self:contextPush({first = true, colon = true, ttype = 2, null = false})
+end
+
+function TJSONProtocol:writeJSONArrayEnd()
+  self:contextPop()
+  self.trans:write(JSONNode.ArrayEnd)
+end
+
+function TJSONProtocol:writeMessageBegin(name, ttype, seqid)
+  self:resetContext()
+  self:writeJSONArrayBegin()
+  self:writeJSONInteger(TJSONProtocol.THRIFT_JSON_PROTOCOL_VERSION)
+  self:writeJSONString(name)
+  self:writeJSONInteger(ttype)
+  self:writeJSONInteger(seqid)
+end
+
+function TJSONProtocol:writeMessageEnd()
+  self:writeJSONArrayEnd()
+end
+
+function TJSONProtocol:writeStructBegin(name)
+  self:writeJSONObjectBegin()
+end
+
+function TJSONProtocol:writeStructEnd()
+  self:writeJSONObjectEnd()
+end
+
+function TJSONProtocol:writeFieldBegin(name, ttype, id)
+  self:writeJSONInteger(id)
+  self:writeJSONObjectBegin()
+  self:writeJSONString(TTypeToString[ttype])
+end
+
+function TJSONProtocol:writeFieldEnd()
+  self:writeJSONObjectEnd()
+end
+
+function TJSONProtocol:writeFieldStop()
+end
+
+function TJSONProtocol:writeMapBegin(ktype, vtype, size)
+  self:writeJSONArrayBegin()
+  self:writeJSONString(TTypeToString[ktype])
+  self:writeJSONString(TTypeToString[vtype])
+  self:writeJSONInteger(size)
+  return self:writeJSONObjectBegin()
+end
+
+function TJSONProtocol:writeMapEnd()
+  self:writeJSONObjectEnd()
+  self:writeJSONArrayEnd()
+end
+
+function TJSONProtocol:writeListBegin(etype, size)
+  self:writeJSONArrayBegin()
+  self:writeJSONString(TTypeToString[etype])
+  self:writeJSONInteger(size)
+end
+
+function TJSONProtocol:writeListEnd()
+  self:writeJSONArrayEnd()
+end
+
+function TJSONProtocol:writeSetBegin(etype, size)
+  self:writeJSONArrayBegin()
+  self:writeJSONString(TTypeToString[etype])
+  self:writeJSONInteger(size)
+end
+
+function TJSONProtocol:writeSetEnd()
+  self:writeJSONArrayEnd()
+end
+
+function TJSONProtocol:writeBool(bool)
+  if bool then
+    self:writeJSONInteger(1)
+  else
+    self:writeJSONInteger(0)
+  end
+end
+
+function TJSONProtocol:writeByte(byte)
+  local buff = libluabpack.bpack('c', byte)
+  local val = libluabpack.bunpack('c', buff)
+  self:writeJSONInteger(val)
+end
+
+function TJSONProtocol:writeI16(i16)
+  local buff = libluabpack.bpack('s', i16)
+  local val = libluabpack.bunpack('s', buff)
+  self:writeJSONInteger(val)
+end
+
+function TJSONProtocol:writeI32(i32)
+  local buff = libluabpack.bpack('i', i32)
+  local val = libluabpack.bunpack('i', buff)
+  self:writeJSONInteger(val)
+end
+
+function TJSONProtocol:writeI64(i64)
+  local buff = libluabpack.bpack('l', i64)
+  local val = libluabpack.bunpack('l', buff)
+  self:writeJSONInteger(tostring(val))
+end
+
+function TJSONProtocol:writeDouble(dub)
+  self:writeJSONDouble(string.format("%.16f", dub))
+end
+
+function TJSONProtocol:writeString(str)
+  self:writeJSONString(str)
+end
+
+function TJSONProtocol:writeBinary(str)
+  -- Should be utf-8
+  self:writeJSONBase64(str)
+end
+
+function TJSONProtocol:readJSONSyntaxChar(ch)
+  local ch2 = ""
+  if self.hasReadByte ~= "" then
+    ch2 = self.hasReadByte
+    self.hasReadByte = ""
+  else
+    ch2 = self.trans:readAll(1)
+  end
+  if ch2 ~= ch then
+    terror(TProtocolException:new{message = "Expected ".. ch .. ", got " .. ch2})
+  end
+end
+
+function TJSONProtocol:readElemSeparator()
+  if self.jsonContextVal.null then
+    return
+  end
+  if self.jsonContextVal.first then
+    self.jsonContextVal.first = false
+  else
+    if self.jsonContextVal.ttype == 1 then
+      if self.jsonContextVal.colon then
+        self:readJSONSyntaxChar(JSONNode.PairSeparator)
+        self.jsonContextVal.colon = false
+      else
+        self:readJSONSyntaxChar(JSONNode.ElemSeparator)
+        self.jsonContextVal.colon = true
+      end
+    else
+      self:readJSONSyntaxChar(JSONNode.ElemSeparator)
+    end
+  end
+end
+
+function TJSONProtocol:hexVal(ch)
+  local val = string.byte(ch)
+  if val >= 48 and val <= 57 then
+    return val - 48
+  elseif val >= 97 and val <= 102 then
+    return val - 87
+  else
+    terror(TProtocolException:new{message = "Expected hex val ([0-9a-f]); got " .. ch})
+  end
+end
+
+function TJSONProtocol:readJSONEscapeChar(ch)
+  self:readJSONSyntaxChar(JSONNode.ZeroChar)
+  self:readJSONSyntaxChar(JSONNode.ZeroChar)
+  local b1 = self.trans:readAll(1)
+  local b2 = self.trans:readAll(1)
+  return libluabitwise.shiftl(self:hexVal(b1), 4) + self:hexVal(b2)
+end
+
+
+function TJSONProtocol:readJSONString()
+  self:readElemSeparator()
+  self:readJSONSyntaxChar(JSONNode.StringDelimiter)
+  local result = ""
+  while true do
+    local ch = self.trans:readAll(1)
+    if ch == JSONNode.StringDelimiter then
+      break
+    end
+    if ch == JSONNode.Backslash then
+      ch = self.trans:readAll(1)
+      if ch == JSONNode.EscapeChar then
+        self:readJSONEscapeChar(ch)
+      else
+        local pos, _ = string.find(JSONNode.EscapeChars, ch)
+        if pos == nil then
+          terror(TProtocolException:new{message = "Expected control char, got " .. ch})
+        end
+        ch = EscapeCharVals[pos]
+      end
+    end
+    result = result .. ch
+  end
+  return result
+end
+
+function TJSONProtocol:readJSONBase64()
+  local result = self:readJSONString()
+  local length = string.len(result)
+  local str = ""
+  local offset = 1
+  while length >= 4 do
+    local bytes = string.sub(result, offset, offset+4)
+    str = str .. base64_decode(bytes)
+    offset = offset + 4
+    length = length - 4
+  end
+  if length >= 0 then
+    str = str .. base64_decode(string.sub(result, offset, offset + length))
+  end
+  return str
+end
+
+function TJSONProtocol:readJSONNumericChars()
+  local result = ""
+  while true do
+    local ch = self.trans:readAll(1)
+    if string.find(ch, '[-+0-9.Ee]') then
+      result = result .. ch
+    else
+      self.hasReadByte = ch
+      break
+    end
+  end
+  return result
+end
+
+function TJSONProtocol:readJSONLongInteger()
+  self:readElemSeparator()
+  if self:escapeNum() then
+    self:readJSONSyntaxChar(JSONNode.StringDelimiter)
+  end
+  local result = self:readJSONNumericChars()
+  if self:escapeNum() then
+    self:readJSONSyntaxChar(JSONNode.StringDelimiter)
+  end
+  return result
+end
+
+function TJSONProtocol:readJSONInteger()
+  return tonumber(self:readJSONLongInteger())
+end
+
+function TJSONProtocol:readJSONDouble()
+  self:readElemSeparator()
+  local delimiter = self.trans:readAll(1)
+  local num = 0.0
+  if delimiter == JSONNode.StringDelimiter then
+    local str = self:readJSONString()
+    if str == JSONNode.Nan then
+      num = 1.0
+    elseif str == JSONNode.Infinity then
+      num = math.maxinteger
+    elseif str == JSONNode.NegativeInfinity then
+      num = math.mininteger
+    else
+      num = tonumber(str)
+    end
+  else
+    if self:escapeNum() then
+      self:readJSONSyntaxChar(JSONNode.StringDelimiter)
+    end
+    local result = self:readJSONNumericChars()
+    num = tonumber(delimiter.. result)
+  end
+  return num
+end
+
+function TJSONProtocol:readJSONObjectBegin()
+  self:readElemSeparator()
+  self:readJSONSyntaxChar(JSONNode.ObjectBegin)
+  self:contextPush({first = true, colon = true, ttype = 1, null = false})
+end
+
+function TJSONProtocol:readJSONObjectEnd()
+  self:readJSONSyntaxChar(JSONNode.ObjectEnd)
+  self:contextPop()
+end
+
+function TJSONProtocol:readJSONArrayBegin()
+  self:readElemSeparator()
+  self:readJSONSyntaxChar(JSONNode.ArrayBegin)
+  self:contextPush({first = true, colon = true, ttype = 2, null = false})
+end
+
+function TJSONProtocol:readJSONArrayEnd()
+  self:readJSONSyntaxChar(JSONNode.ArrayEnd)
+  self:contextPop()
+end
+
+function TJSONProtocol:readMessageBegin()
+  self:resetContext()
+  self:readJSONArrayBegin()
+  local version = self:readJSONInteger()
+  if version ~= self.THRIFT_JSON_PROTOCOL_VERSION then
+    terror(TProtocolException:new{message = "Message contained bad version."})
+  end
+  local name = self:readJSONString()
+  local ttype = self:readJSONInteger()
+  local seqid = self:readJSONInteger()
+  return name, ttype, seqid
+end
+
+function TJSONProtocol:readMessageEnd()
+  self:readJSONArrayEnd()
+end
+
+function TJSONProtocol:readStructBegin()
+  self:readJSONObjectBegin()
+  return nil
+end
+
+function TJSONProtocol:readStructEnd()
+  self:readJSONObjectEnd()
+end
+
+function TJSONProtocol:readFieldBegin()
+  local ttype = TType.STOP
+  local id = 0
+  local ch = self.trans:readAll(1)
+  self.hasReadByte = ch
+  if ch ~= JSONNode.ObjectEnd then
+    id = self:readJSONInteger()
+    self:readJSONObjectBegin()
+    local typeName = self:readJSONString()
+    ttype = StringToTType[typeName]
+  end
+  return nil, ttype, id
+end
+
+function TJSONProtocol:readFieldEnd()
+  self:readJSONObjectEnd()
+end
+
+function TJSONProtocol:readMapBegin()
+  self:readJSONArrayBegin()
+  local typeName = self:readJSONString()
+  local ktype = StringToTType[typeName]
+  typeName = self:readJSONString()
+  local vtype = StringToTType[typeName]
+  local size = self:readJSONInteger()
+  self:readJSONObjectBegin()
+  return ktype, vtype, size
+end
+
+function TJSONProtocol:readMapEnd()
+  self:readJSONObjectEnd()
+  self:readJSONArrayEnd()
+end
+
+function TJSONProtocol:readListBegin()
+  self:readJSONArrayBegin()
+  local typeName = self:readJSONString()
+  local etype = StringToTType[typeName]
+  local size = self:readJSONInteger()
+  return etype, size
+end
+
+function TJSONProtocol:readListEnd()
+  return self:readJSONArrayEnd()
+end
+
+function TJSONProtocol:readSetBegin()
+  return self:readListBegin()
+end
+
+function TJSONProtocol:readSetEnd()
+  return self:readJSONArrayEnd()
+end
+
+function TJSONProtocol:readBool()
+  local result = self:readJSONInteger()
+  if result == 1 then
+    return true
+  else
+    return false
+  end
+end
+
+function TJSONProtocol:readByte()
+  local result = self:readJSONInteger()
+  if result >= 256 then
+    terror(TProtocolException:new{message = "UnExpected Byte " .. result})
+  end
+  return result
+end
+
+function TJSONProtocol:readI16()
+  return self:readJSONInteger()
+end
+
+function TJSONProtocol:readI32()
+  return self:readJSONInteger()
+end
+
+function TJSONProtocol:readI64()
+  local long = liblualongnumber.new
+  return long(self:readJSONLongInteger())
+end
+
+function TJSONProtocol:readDouble()
+  return self:readJSONDouble()
+end
+
+function TJSONProtocol:readString()
+  return self:readJSONString()
+end
+
+function TJSONProtocol:readBinary()
+  return self:readJSONBase64()
+end
+
+TJSONProtocolFactory = TProtocolFactory:new{
+  __type = 'TJSONProtocolFactory',
+}
+
+function TJSONProtocolFactory:getProtocol(trans)
+  -- TODO Enforce that this must be a transport class (ie not a bool)
+  if not trans then
+    terror(TProtocolException:new{
+      message = 'Must supply a transport to ' .. ttype(self)
+    })
+  end
+  return TJSONProtocol:new{
+    trans = trans
+  }
+end
diff --git a/lib/lua/TMemoryBuffer.lua b/lib/lua/TMemoryBuffer.lua
new file mode 100644
index 0000000..78b2f5c
--- /dev/null
+++ b/lib/lua/TMemoryBuffer.lua
@@ -0,0 +1,91 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+require 'TTransport'
+
+TMemoryBuffer = TTransportBase:new{
+  __type = 'TMemoryBuffer',
+  buffer = '',
+  bufferSize = 1024,
+  wPos = 0,
+  rPos = 0
+}
+function TMemoryBuffer:isOpen()
+  return 1
+end
+function TMemoryBuffer:open() end
+function TMemoryBuffer:close() end
+
+function TMemoryBuffer:peak()
+  return self.rPos < self.wPos
+end
+
+function TMemoryBuffer:getBuffer()
+  return self.buffer
+end
+
+function TMemoryBuffer:resetBuffer(buf)
+  if buf then
+    self.buffer = buf
+    self.bufferSize = string.len(buf)
+  else
+    self.buffer = ''
+    self.bufferSize = 1024
+  end
+  self.wPos = string.len(buf)
+  self.rPos = 0
+end
+
+function TMemoryBuffer:available()
+  return self.wPos - self.rPos
+end
+
+function TMemoryBuffer:read(len)
+  local avail = self:available()
+  if avail == 0 then
+    return ''
+  end
+
+  if avail < len then
+    len = avail
+  end
+
+  local val = string.sub(self.buffer, self.rPos + 1, self.rPos + len)
+  self.rPos = self.rPos + len
+  return val
+end
+
+function TMemoryBuffer:readAll(len)
+  local avail = self:available()
+
+  if avail < len then
+    local msg = string.format('Attempt to readAll(%d) found only %d available',
+                              len, avail)
+    terror(TTransportException:new{message = msg})
+  end
+  -- read should block so we don't need a loop here
+  return self:read(len)
+end
+
+function TMemoryBuffer:write(buf)
+  self.buffer = self.buffer .. buf
+  self.wPos = self.wPos + string.len(buf)
+end
+
+function TMemoryBuffer:flush() end
diff --git a/lib/lua/TProtocol.lua b/lib/lua/TProtocol.lua
new file mode 100644
index 0000000..616e167
--- /dev/null
+++ b/lib/lua/TProtocol.lua
@@ -0,0 +1,162 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+require 'Thrift'
+
+TProtocolException = TException:new {
+  UNKNOWN          = 0,
+  INVALID_DATA     = 1,
+  NEGATIVE_SIZE    = 2,
+  SIZE_LIMIT       = 3,
+  BAD_VERSION      = 4,
+  INVALID_PROTOCOL = 5,
+  DEPTH_LIMIT      = 6,
+  errorCode        = 0,
+  __type = 'TProtocolException'
+}
+function TProtocolException:__errorCodeToString()
+  if self.errorCode == self.INVALID_DATA then
+    return 'Invalid data'
+  elseif self.errorCode == self.NEGATIVE_SIZE then
+    return 'Negative size'
+  elseif self.errorCode == self.SIZE_LIMIT then
+    return 'Size limit'
+  elseif self.errorCode == self.BAD_VERSION then
+    return 'Bad version'
+  elseif self.errorCode == self.INVALID_PROTOCOL then
+    return 'Invalid protocol'
+  elseif self.errorCode == self.DEPTH_LIMIT then
+    return 'Exceeded size limit'
+  else
+    return 'Default (unknown)'
+  end
+end
+
+TProtocolBase = __TObject:new{
+  __type = 'TProtocolBase',
+  trans
+}
+
+function TProtocolBase:new(obj)
+  if ttype(obj) ~= 'table' then
+    error(ttype(self) .. 'must be initialized with a table')
+  end
+
+  -- Ensure a transport is provided
+  if not obj.trans then
+    error('You must provide ' .. ttype(self) .. ' with a trans')
+  end
+
+  return __TObject.new(self, obj)
+end
+
+function TProtocolBase:writeMessageBegin(name, ttype, seqid) end
+function TProtocolBase:writeMessageEnd() end
+function TProtocolBase:writeStructBegin(name) end
+function TProtocolBase:writeStructEnd() end
+function TProtocolBase:writeFieldBegin(name, ttype, id) end
+function TProtocolBase:writeFieldEnd() end
+function TProtocolBase:writeFieldStop() end
+function TProtocolBase:writeMapBegin(ktype, vtype, size) end
+function TProtocolBase:writeMapEnd() end
+function TProtocolBase:writeListBegin(ttype, size) end
+function TProtocolBase:writeListEnd() end
+function TProtocolBase:writeSetBegin(ttype, size) end
+function TProtocolBase:writeSetEnd() end
+function TProtocolBase:writeBool(bool) end
+function TProtocolBase:writeByte(byte) end
+function TProtocolBase:writeI16(i16) end
+function TProtocolBase:writeI32(i32) end
+function TProtocolBase:writeI64(i64) end
+function TProtocolBase:writeDouble(dub) end
+function TProtocolBase:writeString(str) end
+function TProtocolBase:readMessageBegin() end
+function TProtocolBase:readMessageEnd() end
+function TProtocolBase:readStructBegin() end
+function TProtocolBase:readStructEnd() end
+function TProtocolBase:readFieldBegin() end
+function TProtocolBase:readFieldEnd() end
+function TProtocolBase:readMapBegin() end
+function TProtocolBase:readMapEnd() end
+function TProtocolBase:readListBegin() end
+function TProtocolBase:readListEnd() end
+function TProtocolBase:readSetBegin() end
+function TProtocolBase:readSetEnd() end
+function TProtocolBase:readBool() end
+function TProtocolBase:readByte() end
+function TProtocolBase:readI16() end
+function TProtocolBase:readI32() end
+function TProtocolBase:readI64() end
+function TProtocolBase:readDouble() end
+function TProtocolBase:readString() end
+
+function TProtocolBase:skip(ttype)
+  if type == TType.STOP then
+    return
+  elseif ttype == TType.BOOL then
+    self:readBool()
+  elseif ttype == TType.BYTE then
+    self:readByte()
+  elseif ttype == TType.I16 then
+    self:readI16()
+  elseif ttype == TType.I32 then
+    self:readI32()
+  elseif ttype == TType.I64 then
+    self:readI64()
+  elseif ttype == TType.DOUBLE then
+    self:readDouble()
+  elseif ttype == TType.STRING then
+    self:readString()
+  elseif ttype == TType.STRUCT then
+    local name = self:readStructBegin()
+    while true do
+      local name, ttype, id = self:readFieldBegin()
+      if ttype == TType.STOP then
+        break
+      end
+      self:skip(ttype)
+      self:readFieldEnd()
+    end
+    self:readStructEnd()
+  elseif ttype == TType.MAP then
+    local kttype, vttype, size = self:readMapBegin()
+    for i = 1, size, 1 do
+      self:skip(kttype)
+      self:skip(vttype)
+    end
+    self:readMapEnd()
+  elseif ttype == TType.SET then
+    local ettype, size = self:readSetBegin()
+    for i = 1, size, 1 do
+      self:skip(ettype)
+    end
+    self:readSetEnd()
+  elseif ttype == TType.LIST then
+    local ettype, size = self:readListBegin()
+    for i = 1, size, 1 do
+      self:skip(ettype)
+    end
+    self:readListEnd()
+  end
+end
+
+TProtocolFactory = __TObject:new{
+  __type = 'TProtocolFactory',
+}
+function TProtocolFactory:getProtocol(trans) end
diff --git a/lib/lua/TServer.lua b/lib/lua/TServer.lua
new file mode 100644
index 0000000..4e37d58
--- /dev/null
+++ b/lib/lua/TServer.lua
@@ -0,0 +1,140 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+require 'Thrift'
+require 'TFramedTransport'
+require 'TBinaryProtocol'
+
+-- TServer
+TServer = __TObject:new{
+  __type = 'TServer'
+}
+
+-- 2 possible constructors
+--   1. {processor, serverTransport}
+--   2. {processor, serverTransport, transportFactory, protocolFactory}
+function TServer:new(args)
+  if ttype(args) ~= 'table' then
+    error('TServer must be initialized with a table')
+  end
+  if args.processor == nil then
+    terror('You must provide ' .. ttype(self) .. ' with a processor')
+  end
+  if args.serverTransport == nil then
+    terror('You must provide ' .. ttype(self) .. ' with a serverTransport')
+  end
+
+  -- Create the object
+  local obj = __TObject.new(self, args)
+
+  if obj.transportFactory then
+    obj.inputTransportFactory = obj.transportFactory
+    obj.outputTransportFactory = obj.transportFactory
+    obj.transportFactory = nil
+  else
+    obj.inputTransportFactory = TFramedTransportFactory:new{}
+    obj.outputTransportFactory = obj.inputTransportFactory
+  end
+
+  if obj.protocolFactory then
+    obj.inputProtocolFactory = obj.protocolFactory
+    obj.outputProtocolFactory = obj.protocolFactory
+    obj.protocolFactory = nil
+  else
+    obj.inputProtocolFactory = TBinaryProtocolFactory:new{}
+    obj.outputProtocolFactory = obj.inputProtocolFactory
+  end
+
+  -- Set the __server variable in the handler so we can stop the server
+  obj.processor.handler.__server = self
+
+  return obj
+end
+
+function TServer:setServerEventHandler(handler)
+  self.serverEventHandler = handler
+end
+
+function TServer:_clientBegin(content, iprot, oprot)
+  if self.serverEventHandler and
+    type(self.serverEventHandler.clientBegin) == 'function' then
+    self.serverEventHandler:clientBegin(iprot, oprot)
+  end
+end
+
+function TServer:_preServe()
+  if self.serverEventHandler and
+    type(self.serverEventHandler.preServe) == 'function' then
+    self.serverEventHandler:preServe(self.serverTransport:getSocketInfo())
+  end
+end
+
+function TServer:_handleException(err)
+  if string.find(err, 'TTransportException') == nil then
+    print(err)
+  end
+end
+
+function TServer:serve() end
+function TServer:handle(client)
+  local itrans, otrans =
+    self.inputTransportFactory:getTransport(client),
+    self.outputTransportFactory:getTransport(client)
+  local iprot, oprot =
+    self.inputProtocolFactory:getProtocol(itrans),
+    self.outputProtocolFactory:getProtocol(otrans)
+
+  self:_clientBegin(iprot, oprot)
+  while true do
+    local ret, err = pcall(self.processor.process, self.processor, iprot, oprot)
+    if ret == false and err then
+      if not string.find(err, "TTransportException") then
+        self:_handleException(err)
+      end
+      break
+    end
+  end
+  itrans:close()
+  otrans:close()
+end
+
+function TServer:close()
+  self.serverTransport:close()
+end
+
+-- TSimpleServer
+--  Single threaded server that handles one transport (connection)
+TSimpleServer = __TObject:new(TServer, {
+  __type = 'TSimpleServer',
+  __stop = false
+})
+
+function TSimpleServer:serve()
+  self.serverTransport:listen()
+  self:_preServe()
+  while not self.__stop do
+    client = self.serverTransport:accept()
+    self:handle(client)
+  end
+  self:close()
+end
+
+function TSimpleServer:stop()
+  self.__stop = true
+end
diff --git a/lib/lua/TSocket.lua b/lib/lua/TSocket.lua
new file mode 100644
index 0000000..d71fc1f
--- /dev/null
+++ b/lib/lua/TSocket.lua
@@ -0,0 +1,132 @@
+---- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+require 'TTransport'
+require 'libluasocket'
+
+-- TSocketBase
+TSocketBase = TTransportBase:new{
+  __type = 'TSocketBase',
+  timeout = 1000,
+  host = 'localhost',
+  port = 9090,
+  handle
+}
+
+function TSocketBase:close()
+  if self.handle then
+    self.handle:destroy()
+    self.handle = nil
+  end
+end
+
+-- Returns a table with the fields host and port
+function TSocketBase:getSocketInfo()
+  if self.handle then
+    return self.handle:getsockinfo()
+  end
+  terror(TTransportException:new{errorCode = TTransportException.NOT_OPEN})
+end
+
+function TSocketBase:setTimeout(timeout)
+  if timeout and ttype(timeout) == 'number' then
+    if self.handle then
+      self.handle:settimeout(timeout)
+    end
+    self.timeout = timeout
+  end
+end
+
+-- TSocket
+TSocket = TSocketBase:new{
+  __type = 'TSocket',
+  host = 'localhost',
+  port = 9090
+}
+
+function TSocket:isOpen()
+  if self.handle then
+    return true
+  end
+  return false
+end
+
+function TSocket:open()
+  if self.handle then
+    self:close()
+  end
+
+  -- Create local handle
+  local sock, err = luasocket.create_and_connect(
+    self.host, self.port, self.timeout)
+  if err == nil then
+    self.handle = sock
+  end
+
+  if err then
+    terror(TTransportException:new{
+      message = 'Could not connect to ' .. self.host .. ':' .. self.port
+        .. ' (' .. err .. ')'
+    })
+  end
+end
+
+function TSocket:read(len)
+  local buf = self.handle:receive(self.handle, len)
+  if not buf or string.len(buf) ~= len then
+    terror(TTransportException:new{errorCode = TTransportException.UNKNOWN})
+  end
+  return buf
+end
+
+function TSocket:write(buf)
+  self.handle:send(self.handle, buf)
+end
+
+function TSocket:flush()
+end
+
+-- TServerSocket
+TServerSocket = TSocketBase:new{
+  __type = 'TServerSocket',
+  host = 'localhost',
+  port = 9090
+}
+
+function TServerSocket:listen()
+  if self.handle then
+    self:close()
+  end
+
+  local sock, err = luasocket.create(self.host, self.port)
+  if not err then
+    self.handle = sock
+  else
+    terror(err)
+  end
+  self.handle:settimeout(self.timeout)
+  self.handle:listen()
+end
+
+function TServerSocket:accept()
+  local client, err = self.handle:accept()
+  if err then
+    terror(err)
+  end
+  return TSocket:new({handle = client})
+end
diff --git a/lib/lua/TTransport.lua b/lib/lua/TTransport.lua
new file mode 100644
index 0000000..01c7e59
--- /dev/null
+++ b/lib/lua/TTransport.lua
@@ -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.
+--
+
+require 'Thrift'
+
+TTransportException = TException:new {
+  UNKNOWN             = 0,
+  NOT_OPEN            = 1,
+  ALREADY_OPEN        = 2,
+  TIMED_OUT           = 3,
+  END_OF_FILE         = 4,
+  INVALID_FRAME_SIZE  = 5,
+  INVALID_TRANSFORM   = 6,
+  INVALID_CLIENT_TYPE = 7,
+  errorCode        = 0,
+  __type = 'TTransportException'
+}
+
+function TTransportException:__errorCodeToString()
+  if self.errorCode == self.NOT_OPEN then
+    return 'Transport not open'
+  elseif self.errorCode == self.ALREADY_OPEN then
+    return 'Transport already open'
+  elseif self.errorCode == self.TIMED_OUT then
+    return 'Transport timed out'
+  elseif self.errorCode == self.END_OF_FILE then
+    return 'End of file'
+  elseif self.errorCode == self.INVALID_FRAME_SIZE then
+    return 'Invalid frame size'
+  elseif self.errorCode == self.INVALID_TRANSFORM then
+    return 'Invalid transform'
+  elseif self.errorCode == self.INVALID_CLIENT_TYPE then
+    return 'Invalid client type'
+  else
+    return 'Default (unknown)'
+  end
+end
+
+TTransportBase = __TObject:new{
+  __type = 'TTransportBase'
+}
+
+function TTransportBase:isOpen() end
+function TTransportBase:open() end
+function TTransportBase:close() end
+function TTransportBase:read(len) end
+function TTransportBase:readAll(len)
+  local buf, have, chunk = '', 0
+  while have < len do
+    chunk = self:read(len - have)
+    have = have + string.len(chunk)
+    buf = buf .. chunk
+
+    if string.len(chunk) == 0 then
+      terror(TTransportException:new{
+        errorCode = TTransportException.END_OF_FILE
+      })
+    end
+  end
+  return buf
+end
+function TTransportBase:write(buf) end
+function TTransportBase:flush() end
+
+TServerTransportBase = __TObject:new{
+  __type = 'TServerTransportBase'
+}
+function TServerTransportBase:listen() end
+function TServerTransportBase:accept() end
+function TServerTransportBase:close() end
+
+TTransportFactoryBase = __TObject:new{
+  __type = 'TTransportFactoryBase'
+}
+function TTransportFactoryBase:getTransport(trans)
+  return trans
+end
diff --git a/lib/lua/Thrift.lua b/lib/lua/Thrift.lua
new file mode 100644
index 0000000..68d4ba8
--- /dev/null
+++ b/lib/lua/Thrift.lua
@@ -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.
+--
+
+---- namespace thrift
+--thrift = {}
+--setmetatable(thrift, {__index = _G}) --> perf hit for accessing global methods
+--setfenv(1, thrift)
+
+package.cpath = package.cpath .. ';bin/?.so' -- TODO FIX
+function ttype(obj)
+  if type(obj) == 'table' and
+    obj.__type and
+    type(obj.__type) == 'string' then
+      return obj.__type
+  end
+  return type(obj)
+end
+
+function terror(e)
+  if e and e.__tostring then
+    error(e:__tostring())
+    return
+  end
+  error(e)
+end
+
+function ttable_size(t)
+  local count = 0
+  for k, v in pairs(t) do
+    count = count + 1
+  end
+  return count
+end
+
+version = '1.0.0'
+
+TType = {
+  STOP   = 0,
+  VOID   = 1,
+  BOOL   = 2,
+  BYTE   = 3,
+  I08    = 3,
+  DOUBLE = 4,
+  I16    = 6,
+  I32    = 8,
+  I64    = 10,
+  STRING = 11,
+  UTF7   = 11,
+  STRUCT = 12,
+  MAP    = 13,
+  SET    = 14,
+  LIST   = 15,
+  UTF8   = 16,
+  UTF16  = 17
+}
+
+TMessageType = {
+  CALL  = 1,
+  REPLY = 2,
+  EXCEPTION = 3,
+  ONEWAY = 4
+}
+
+-- Recursive __index function to achieve inheritance
+function __tobj_index(self, key)
+  local v = rawget(self, key)
+  if v ~= nil then
+    return v
+  end
+
+  local p = rawget(self, '__parent')
+  if p then
+    return __tobj_index(p, key)
+  end
+
+  return nil
+end
+
+-- Basic Thrift-Lua Object
+__TObject = {
+  __type = '__TObject',
+  __mt = {
+    __index = __tobj_index
+  }
+}
+function __TObject:new(init_obj)
+  local obj = {}
+  if ttype(obj) == 'table' then
+    obj = init_obj
+  end
+
+  -- Use the __parent key and the __index function to achieve inheritance
+  obj.__parent = self
+  setmetatable(obj, __TObject.__mt)
+  return obj
+end
+
+-- Return a string representation of any lua variable
+function thrift_print_r(t)
+  local ret = ''
+  local ltype = type(t)
+  if (ltype == 'table') then
+    ret = ret .. '{ '
+    for key,value in pairs(t) do
+      ret = ret .. tostring(key) .. '=' .. thrift_print_r(value) .. ' '
+    end
+    ret = ret .. '}'
+  elseif ltype == 'string' then
+    ret = ret .. "'" .. tostring(t) .. "'"
+  else
+    ret = ret .. tostring(t)
+  end
+  return ret
+end
+
+-- Basic Exception
+TException = __TObject:new{
+  message,
+  errorCode,
+  __type = 'TException'
+}
+function TException:__tostring()
+  if self.message then
+    return string.format('%s: %s', self.__type, self.message)
+  else
+    local message
+    if self.errorCode and self.__errorCodeToString then
+      message = string.format('%d: %s', self.errorCode, self:__errorCodeToString())
+    else
+      message = thrift_print_r(self)
+    end
+    return string.format('%s:%s', self.__type, message)
+  end
+end
+
+TApplicationException = TException:new{
+  UNKNOWN                 = 0,
+  UNKNOWN_METHOD          = 1,
+  INVALID_MESSAGE_TYPE    = 2,
+  WRONG_METHOD_NAME       = 3,
+  BAD_SEQUENCE_ID         = 4,
+  MISSING_RESULT          = 5,
+  INTERNAL_ERROR          = 6,
+  PROTOCOL_ERROR          = 7,
+  INVALID_TRANSFORM       = 8,
+  INVALID_PROTOCOL        = 9,
+  UNSUPPORTED_CLIENT_TYPE = 10,
+  errorCode               = 0,
+  __type = 'TApplicationException'
+}
+
+function TApplicationException:__errorCodeToString()
+  if self.errorCode == self.UNKNOWN_METHOD then
+    return 'Unknown method'
+  elseif self.errorCode == self.INVALID_MESSAGE_TYPE then
+    return 'Invalid message type'
+  elseif self.errorCode == self.WRONG_METHOD_NAME then
+    return 'Wrong method name'
+  elseif self.errorCode == self.BAD_SEQUENCE_ID then
+    return 'Bad sequence ID'
+  elseif self.errorCode == self.MISSING_RESULT then
+    return 'Missing result'
+  elseif self.errorCode == self.INTERNAL_ERROR then
+    return 'Internal error'
+  elseif self.errorCode == self.PROTOCOL_ERROR then
+    return 'Protocol error'
+  elseif self.errorCode == self.INVALID_TRANSFORM then
+    return 'Invalid transform'
+  elseif self.errorCode == self.INVALID_PROTOCOL then
+    return 'Invalid protocol'
+  elseif self.errorCode == self.UNSUPPORTED_CLIENT_TYPE then
+    return 'Unsupported client type'
+  else
+    return 'Default (unknown)'
+  end
+end
+
+function TException:read(iprot)
+  iprot:readStructBegin()
+  while true do
+    local fname, ftype, fid = iprot:readFieldBegin()
+    if ftype == TType.STOP then
+      break
+    elseif fid == 1 then
+      if ftype == TType.STRING then
+        self.message = iprot:readString()
+      else
+        iprot:skip(ftype)
+      end
+    elseif fid == 2 then
+      if ftype == TType.I32 then
+        self.errorCode = iprot:readI32()
+      else
+        iprot:skip(ftype)
+      end
+    else
+      iprot:skip(ftype)
+    end
+    iprot:readFieldEnd()
+  end
+  iprot:readStructEnd()
+end
+
+function TException:write(oprot)
+  oprot:writeStructBegin('TApplicationException')
+  if self.message then
+    oprot:writeFieldBegin('message', TType.STRING, 1)
+    oprot:writeString(self.message)
+    oprot:writeFieldEnd()
+  end
+  if self.errorCode then
+    oprot:writeFieldBegin('type', TType.I32, 2)
+    oprot:writeI32(self.errorCode)
+    oprot:writeFieldEnd()
+  end
+  oprot:writeFieldStop()
+  oprot:writeStructEnd()
+end
+
+-- Basic Client (used in generated lua code)
+__TClient = __TObject:new{
+  __type = '__TClient',
+  _seqid = 0
+}
+function __TClient:new(obj)
+  if ttype(obj) ~= 'table' then
+    error('TClient must be initialized with a table')
+  end
+
+  -- Set iprot & oprot
+  if obj.protocol then
+    obj.iprot = obj.protocol
+    obj.oprot = obj.protocol
+    obj.protocol = nil
+  elseif not obj.iprot then
+    error('You must provide ' .. ttype(self) .. ' with an iprot')
+  end
+  if not obj.oprot then
+    obj.oprot = obj.iprot
+  end
+
+  return __TObject.new(self, obj)
+end
+
+function __TClient:close()
+  self.iprot.trans:close()
+  self.oprot.trans:close()
+end
+
+-- Basic Processor (used in generated lua code)
+__TProcessor = __TObject:new{
+  __type = '__TProcessor'
+}
+function __TProcessor:new(obj)
+  if ttype(obj) ~= 'table' then
+    error('TProcessor must be initialized with a table')
+  end
+
+  -- Ensure a handler is provided
+  if not obj.handler then
+    error('You must provide ' .. ttype(self) .. ' with a handler')
+  end
+
+  return __TObject.new(self, obj)
+end
diff --git a/lib/lua/coding_standards.md b/lib/lua/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/lua/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/lua/src/longnumberutils.c b/lib/lua/src/longnumberutils.c
new file mode 100644
index 0000000..fbc6789
--- /dev/null
+++ b/lib/lua/src/longnumberutils.c
@@ -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.
+//
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+const char * LONG_NUM_TYPE = "__thrift_longnumber";
+int64_t lualongnumber_checklong(lua_State *L, int index) {
+  switch (lua_type(L, index)) {
+    case LUA_TNUMBER:
+      return (int64_t)lua_tonumber(L, index);
+    case LUA_TSTRING:
+      return atoll(lua_tostring(L, index));
+    default:
+      return *((int64_t *)luaL_checkudata(L, index, LONG_NUM_TYPE));
+  }
+}
+
+// Creates a new longnumber and pushes it onto the statck
+int64_t * lualongnumber_pushlong(lua_State *L, int64_t *val) {
+  int64_t *data = (int64_t *)lua_newuserdata(L, sizeof(int64_t)); // longnum
+  luaL_getmetatable(L, LONG_NUM_TYPE);                            // longnum, mt
+  lua_setmetatable(L, -2);                                        // longnum
+  if (val) {
+    *data = *val;
+  }
+  return data;
+}
+
diff --git a/lib/lua/src/luabitwise.c b/lib/lua/src/luabitwise.c
new file mode 100644
index 0000000..2e07e17
--- /dev/null
+++ b/lib/lua/src/luabitwise.c
@@ -0,0 +1,83 @@
+//
+// 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.
+//
+
+#include <lua.h>
+#include <lauxlib.h>
+
+static int l_not(lua_State *L) {
+  int a = luaL_checkinteger(L, 1);
+  a = ~a;
+  lua_pushnumber(L, a);
+  return 1;
+}
+
+static int l_xor(lua_State *L) {
+  int a = luaL_checkinteger(L, 1);
+  int b = luaL_checkinteger(L, 2);
+  a ^= b;
+  lua_pushnumber(L, a);
+  return 1;
+}
+
+static int l_and(lua_State *L) {
+  int a = luaL_checkinteger(L, 1);
+  int b = luaL_checkinteger(L, 2);
+  a &= b;
+  lua_pushnumber(L, a);
+  return 1;
+}
+
+static int l_or(lua_State *L) {
+  int a = luaL_checkinteger(L, 1);
+  int b = luaL_checkinteger(L, 2);
+  a |= b;
+  lua_pushnumber(L, a);
+  return 1;
+}
+
+static int l_shiftr(lua_State *L) {
+  int a = luaL_checkinteger(L, 1);
+  int b = luaL_checkinteger(L, 2);
+  a = a >> b;
+  lua_pushnumber(L, a);
+  return 1;
+}
+
+static int l_shiftl(lua_State *L) {
+  int a = luaL_checkinteger(L, 1);
+  int b = luaL_checkinteger(L, 2);
+  a = a << b;
+  lua_pushnumber(L, a);
+  return 1;
+}
+
+static const struct luaL_Reg funcs[] = {
+  {"band", l_and},
+  {"bor", l_or},
+  {"bxor", l_xor},
+  {"bnot", l_not},
+  {"shiftl", l_shiftl},
+  {"shiftr", l_shiftr},
+  {NULL, NULL}
+};
+
+int luaopen_libluabitwise(lua_State *L) {
+  luaL_register(L, "libluabitwise", funcs);
+  return 1;
+}
diff --git a/lib/lua/src/luabpack.c b/lib/lua/src/luabpack.c
new file mode 100644
index 0000000..077b6aa
--- /dev/null
+++ b/lib/lua/src/luabpack.c
@@ -0,0 +1,308 @@
+//
+// 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.
+//
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <netinet/in.h>
+
+extern int64_t lualongnumber_checklong(lua_State *L, int index);
+extern int64_t lualongnumber_pushlong(lua_State *L, int64_t *val);
+
+// host order to network order (64-bit)
+static int64_t T_htonll(uint64_t data) {
+  uint32_t d1 = htonl((uint32_t)data);
+  uint32_t d2 = htonl((uint32_t)(data >> 32));
+  return ((uint64_t)d1 << 32) + (uint64_t)d2;
+}
+
+// network order to host order (64-bit)
+static int64_t T_ntohll(uint64_t data) {
+  uint32_t d1 = ntohl((uint32_t)data);
+  uint32_t d2 = ntohl((uint32_t)(data >> 32));
+  return ((uint64_t)d1 << 32) + (uint64_t)d2;
+}
+
+/**
+ * bpack(type, data)
+ *  c - Signed Byte
+ *  s - Signed Short
+ *  i - Signed Int
+ *  l - Signed Long
+ *  d - Double
+ */
+static int l_bpack(lua_State *L) {
+  const char *code = luaL_checkstring(L, 1);
+  luaL_argcheck(L, code[1] == '\0', 0, "Format code must be one character.");
+  luaL_Buffer buf;
+  luaL_buffinit(L, &buf);
+
+  switch (code[0]) {
+    case 'c': {
+      int8_t data = luaL_checknumber(L, 2);
+      luaL_addlstring(&buf, (void*)&data, sizeof(data));
+      break;
+    }
+    case 's': {
+      int16_t data = luaL_checknumber(L, 2);
+      data = (int16_t)htons(data);
+      luaL_addlstring(&buf, (void*)&data, sizeof(data));
+      break;
+    }
+    case 'i': {
+      int32_t data = luaL_checkinteger(L, 2);
+      data = (int32_t)htonl(data);
+      luaL_addlstring(&buf, (void*)&data, sizeof(data));
+      break;
+    }
+    case 'l': {
+      int64_t data = lualongnumber_checklong(L, 2);
+      data = (int64_t)T_htonll(data);
+      luaL_addlstring(&buf, (void*)&data, sizeof(data));
+      break;
+    }
+    case 'd': {
+      double data = luaL_checknumber(L, 2);
+      luaL_addlstring(&buf, (void*)&data, sizeof(data));
+      break;
+    }
+    default:
+      luaL_argcheck(L, 0, 0, "Invalid format code.");
+  }
+
+  luaL_pushresult(&buf);
+  return 1;
+}
+
+/**
+ * bunpack(type, data)
+ *  c - Signed Byte
+ *  C - Unsigned Byte
+ *  s - Signed Short
+ *  i - Signed Int
+ *  l - Signed Long
+ *  d - Double
+ */
+static int l_bunpack(lua_State *L) {
+  const char *code = luaL_checkstring(L, 1);
+  luaL_argcheck(L, code[1] == '\0', 0, "Format code must be one character.");
+  const char *data = luaL_checkstring(L, 2);
+#if LUA_VERSION_NUM >= 502
+  size_t len = lua_rawlen(L, 2);
+#else
+  size_t len = lua_objlen(L, 2);
+#endif
+
+  switch (code[0]) {
+    case 'c': {
+      int8_t val;
+      luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
+      memcpy(&val, data, sizeof(val));
+      lua_pushnumber(L, val);
+      break;
+    }
+    /**
+     * unpack unsigned Byte.
+     */
+    case 'C': {
+      uint8_t val;
+      luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
+      memcpy(&val, data, sizeof(val));
+      lua_pushnumber(L, val);
+      break;
+    }
+    case 's': {
+      int16_t val;
+      luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
+      memcpy(&val, data, sizeof(val));
+      val = (int16_t)ntohs(val);
+      lua_pushnumber(L, val);
+      break;
+    }
+    case 'i': {
+      int32_t val;
+      luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
+      memcpy(&val, data, sizeof(val));
+      val = (int32_t)ntohl(val);
+      lua_pushnumber(L, val);
+      break;
+    }
+    case 'l': {
+      int64_t val;
+      luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
+      memcpy(&val, data, sizeof(val));
+      val = (int64_t)T_ntohll(val);
+      lualongnumber_pushlong(L, &val);
+      break;
+    }
+    case 'd': {
+      double val;
+      luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
+      memcpy(&val, data, sizeof(val));
+      lua_pushnumber(L, val);
+      break;
+    }
+    default:
+      luaL_argcheck(L, 0, 0, "Invalid format code.");
+  }
+  return 1;
+}
+
+/**
+ * Convert l into a zigzag long. This allows negative numbers to be
+ * represented compactly as a varint.
+ */
+static int l_i64ToZigzag(lua_State *L) {
+  int64_t n = lualongnumber_checklong(L, 1);
+  int64_t result = (n << 1) ^ (n >> 63);
+  lualongnumber_pushlong(L, &result);
+  return 1;
+}
+/**
+ * Convert n into a zigzag int. This allows negative numbers to be
+ * represented compactly as a varint.
+ */
+static int l_i32ToZigzag(lua_State *L) {
+  int32_t n = luaL_checkinteger(L, 1);
+  uint32_t result = (uint32_t)(n << 1) ^ (n >> 31);
+  lua_pushnumber(L, result);
+  return 1;
+}
+
+/**
+ * Convert from zigzag int to int.
+ */
+static int l_zigzagToI32(lua_State *L) {
+  uint32_t n = luaL_checkinteger(L, 1);
+  int32_t result = (int32_t)(n >> 1) ^ (uint32_t)(-(int32_t)(n & 1));
+  lua_pushnumber(L, result);
+  return 1;
+}
+
+/**
+ * Convert from zigzag long to long.
+ */
+static int l_zigzagToI64(lua_State *L) {
+  int64_t n = lualongnumber_checklong(L, 1);
+  int64_t result = (int64_t)(n >> 1) ^ (uint64_t)(-(int64_t)(n & 1));
+  lualongnumber_pushlong(L, &result);
+  return 1;
+}
+
+/**
+ * Convert an i32 to a varint. Results in 1-5 bytes on the buffer.
+ */
+static int l_toVarint32(lua_State *L) {
+  uint8_t buf[5];
+  uint32_t n = luaL_checkinteger(L, 1);
+  uint32_t wsize = 0;
+
+  while (1) {
+    if ((n & ~0x7F) == 0) {
+      buf[wsize++] = (int8_t)n;
+      break;
+    } else {
+      buf[wsize++] = (int8_t)((n & 0x7F) | 0x80);
+      n >>= 7;
+    }
+  }
+  lua_pushlstring(L, buf, wsize);
+  return 1;
+}
+
+/**
+ * Convert an i64 to a varint. Results in 1-10 bytes on the buffer.
+ */
+static int l_toVarint64(lua_State *L) {
+  uint8_t data[10];
+  uint64_t n = lualongnumber_checklong(L, 1);
+  uint32_t wsize = 0;
+  luaL_Buffer buf;
+  luaL_buffinit(L, &buf);
+
+  while (1) {
+    if ((n & ~0x7FL) == 0) {
+      data[wsize++] = (int8_t)n;
+      break;
+    } else {
+      data[wsize++] = (int8_t)((n & 0x7F) | 0x80);
+      n >>= 7;
+    }
+  }
+
+  luaL_addlstring(&buf, (void*)&data, wsize);
+  luaL_pushresult(&buf);
+  return 1;
+}
+
+/**
+ * Convert a varint to i64.
+ */
+static int l_fromVarint64(lua_State *L) {
+  int64_t result;
+  uint8_t byte = luaL_checknumber(L, 1);
+  int32_t shift = luaL_checknumber(L, 2);
+  uint64_t n = (uint64_t)lualongnumber_checklong(L, 3);
+  n |= (uint64_t)(byte & 0x7f) << shift;
+
+  if (!(byte & 0x80)) {
+    result = (int64_t)(n >> 1) ^ (uint64_t)(-(int64_t)(n & 1));
+    lua_pushnumber(L, 0);
+  } else {
+    result = n;
+    lua_pushnumber(L, 1);
+  }
+  lualongnumber_pushlong(L, &result);
+  return 2;
+}
+
+/**
+ * To pack message type of compact protocol.
+ */
+static int l_packMesgType(lua_State *L) {
+  int32_t version_n = luaL_checkinteger(L, 1);
+  int32_t version_mask = luaL_checkinteger(L, 2);
+  int32_t messagetype = luaL_checkinteger(L, 3);
+  int32_t type_shift_amount = luaL_checkinteger(L, 4);
+  int32_t type_mask = luaL_checkinteger(L, 5);
+  int32_t to_mesg_type = (version_n & version_mask) |
+    (((int32_t)messagetype << type_shift_amount) & type_mask);
+  lua_pushnumber(L, to_mesg_type);
+  return 1;
+}
+
+static const struct luaL_Reg lua_bpack[] = {
+  {"bpack", l_bpack},
+  {"bunpack", l_bunpack},
+  {"i32ToZigzag", l_i32ToZigzag},
+  {"i64ToZigzag", l_i64ToZigzag},
+  {"zigzagToI32", l_zigzagToI32},
+  {"zigzagToI64", l_zigzagToI64},
+  {"toVarint32", l_toVarint32},
+  {"toVarint64", l_toVarint64},
+  {"fromVarint64", l_fromVarint64},
+  {"packMesgType", l_packMesgType},
+  {NULL, NULL}
+};
+
+int luaopen_libluabpack(lua_State *L) {
+  luaL_register(L, "libluabpack", lua_bpack);
+  return 1;
+}
diff --git a/lib/lua/src/lualongnumber.c b/lib/lua/src/lualongnumber.c
new file mode 100644
index 0000000..9001e4a
--- /dev/null
+++ b/lib/lua/src/lualongnumber.c
@@ -0,0 +1,228 @@
+//
+// 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.
+//
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <stdlib.h>
+#include <math.h>
+#include <inttypes.h>
+#include <string.h>
+
+extern const char * LONG_NUM_TYPE;
+extern int64_t lualongnumber_checklong(lua_State *L, int index);
+extern int64_t lualongnumber_pushlong(lua_State *L, int64_t *val);
+
+////////////////////////////////////////////////////////////////////////////////
+
+static void l_serialize(char *buf, int len, int64_t val) {
+  snprintf(buf, len, "%"PRId64, val);
+}
+
+static int64_t l_deserialize(const char *buf) {
+  int64_t data;
+  int rv;
+  // Support hex prefixed with '0x'
+  if (strstr(buf, "0x") == buf) {
+    rv = sscanf(buf, "%"PRIx64, &data);
+  } else {
+    rv = sscanf(buf, "%"PRId64, &data);
+  }
+  if (rv == 1) {
+    return data;
+  }
+  return 0; // Failed
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static int l_new(lua_State *L) {
+  int64_t val;
+  const char *str = NULL;
+  if (lua_type(L, 1) == LUA_TSTRING) {
+    str = lua_tostring(L, 1);
+    val = l_deserialize(str);
+  } else if (lua_type(L, 1) == LUA_TNUMBER) {
+    val = (int64_t)lua_tonumber(L, 1);
+    str = (const char *)1;
+  }
+  lualongnumber_pushlong(L, (str ? &val : NULL));
+  return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// a + b
+static int l_add(lua_State *L) {
+  int64_t a, b, c;
+  a = lualongnumber_checklong(L, 1);
+  b = lualongnumber_checklong(L, 2);
+  c = a + b;
+  lualongnumber_pushlong(L, &c);
+  return 1;
+}
+
+// a / b
+static int l_div(lua_State *L) {
+  int64_t a, b, c;
+  a = lualongnumber_checklong(L, 1);
+  b = lualongnumber_checklong(L, 2);
+  c = a / b;
+  lualongnumber_pushlong(L, &c);
+  return 1;
+}
+
+// a == b (both a and b are lualongnumber's)
+static int l_eq(lua_State *L) {
+  int64_t a, b;
+  a = lualongnumber_checklong(L, 1);
+  b = lualongnumber_checklong(L, 2);
+  lua_pushboolean(L, (a == b ? 1 : 0));
+  return 1;
+}
+
+// garbage collection
+static int l_gc(lua_State *L) {
+  lua_pushnil(L);
+  lua_setmetatable(L, 1);
+  return 0;
+}
+
+// a < b
+static int l_lt(lua_State *L) {
+  int64_t a, b;
+  a = lualongnumber_checklong(L, 1);
+  b = lualongnumber_checklong(L, 2);
+  lua_pushboolean(L, (a < b ? 1 : 0));
+  return 1;
+}
+
+// a <= b
+static int l_le(lua_State *L) {
+  int64_t a, b;
+  a = lualongnumber_checklong(L, 1);
+  b = lualongnumber_checklong(L, 2);
+  lua_pushboolean(L, (a <= b ? 1 : 0));
+  return 1;
+}
+
+// a % b
+static int l_mod(lua_State *L) {
+  int64_t a, b, c;
+  a = lualongnumber_checklong(L, 1);
+  b = lualongnumber_checklong(L, 2);
+  c = a % b;
+  lualongnumber_pushlong(L, &c);
+  return 1;
+}
+
+// a * b
+static int l_mul(lua_State *L) {
+  int64_t a, b, c;
+  a = lualongnumber_checklong(L, 1);
+  b = lualongnumber_checklong(L, 2);
+  c = a * b;
+  lualongnumber_pushlong(L, &c);
+  return 1;
+}
+
+// a ^ b
+static int l_pow(lua_State *L) {
+  long double a, b;
+  int64_t c;
+  a = (long double)lualongnumber_checklong(L, 1);
+  b = (long double)lualongnumber_checklong(L, 2);
+  c = (int64_t)pow(a, b);
+  lualongnumber_pushlong(L, &c);
+  return 1;
+}
+
+// a - b
+static int l_sub(lua_State *L) {
+  int64_t a, b, c;
+  a = lualongnumber_checklong(L, 1);
+  b = lualongnumber_checklong(L, 2);
+  c = a - b;
+  lualongnumber_pushlong(L, &c);
+  return 1;
+}
+
+// tostring()
+static int l_tostring(lua_State *L) {
+  int64_t a;
+  char str[256];
+  l_serialize(str, 256, lualongnumber_checklong(L, 1));
+  lua_pushstring(L, str);
+  return 1;
+}
+
+// -a
+static int l_unm(lua_State *L) {
+  int64_t a, c;
+  a = lualongnumber_checklong(L, 1);
+  c = -a;
+  lualongnumber_pushlong(L, &c);
+  return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static const luaL_Reg methods[] = {
+  {"__add", l_add},
+  {"__div", l_div},
+  {"__eq", l_eq},
+  {"__gc", l_gc},
+  {"__lt", l_lt},
+  {"__le", l_le},
+  {"__mod", l_mod},
+  {"__mul", l_mul},
+  {"__pow", l_pow},
+  {"__sub", l_sub},
+  {"__tostring", l_tostring},
+  {"__unm", l_unm},
+  {NULL, NULL},
+};
+
+static const luaL_Reg funcs[] = {
+  {"new", l_new},
+  {NULL, NULL}
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+static void set_methods(lua_State *L,
+  const char *metatablename,
+  const struct luaL_Reg *methods) {
+  luaL_getmetatable(L, metatablename);   // mt
+  // No need for a __index table since everything is __*
+  for (; methods->name; methods++) {
+    lua_pushstring(L, methods->name);    // mt, "name"
+    lua_pushcfunction(L, methods->func); // mt, "name", func
+    lua_rawset(L, -3);                   // mt
+  }
+  lua_pop(L, 1);
+}
+
+LUALIB_API int luaopen_liblualongnumber(lua_State *L) {
+  luaL_newmetatable(L, LONG_NUM_TYPE);
+  lua_pop(L, 1);
+  set_methods(L, LONG_NUM_TYPE, methods);
+
+  luaL_register(L, "liblualongnumber", funcs);
+  return 1;
+}
diff --git a/lib/lua/src/luasocket.c b/lib/lua/src/luasocket.c
new file mode 100644
index 0000000..d483510
--- /dev/null
+++ b/lib/lua/src/luasocket.c
@@ -0,0 +1,380 @@
+//
+// 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.
+//
+
+#include <lua.h>
+#include <lauxlib.h>
+
+#include <unistd.h>
+#include "string.h"
+#include "socket.h"
+
+////////////////////////////////////////////////////////////////////////////////
+
+static const char *SOCKET_ANY     = "__thrift_socket_any";
+static const char *SOCKET_CONN    = "__thrift_socket_connected";
+
+static const char *SOCKET_GENERIC = "__thrift_socket_generic";
+static const char *SOCKET_CLIENT  = "__thrift_socket_client";
+static const char *SOCKET_SERVER  = "__thrift_socket_server";
+
+static const char *DEFAULT_HOST   = "localhost";
+
+typedef struct __t_tcp {
+  t_socket sock;
+  int timeout; // Milliseconds
+} t_tcp;
+typedef t_tcp *p_tcp;
+
+////////////////////////////////////////////////////////////////////////////////
+// Util
+
+static void throw_argerror(lua_State *L, int index, const char *expected) {
+  char msg[256];
+  sprintf(msg, "%s expected, got %s", expected, luaL_typename(L, index));
+  luaL_argerror(L, index, msg);
+}
+
+static void *checkgroup(lua_State *L, int index, const char *groupname) {
+  if (!lua_getmetatable(L, index)) {
+    throw_argerror(L, index, groupname);
+  }
+
+  lua_pushstring(L, groupname);
+  lua_rawget(L, -2);
+  if (lua_isnil(L, -1)) {
+    lua_pop(L, 2);
+    throw_argerror(L, index, groupname);
+  } else {
+    lua_pop(L, 2);
+    return lua_touserdata(L, index);
+  }
+  return NULL; // Not reachable
+}
+
+static void *checktype(lua_State *L, int index, const char *typename) {
+  if (strcmp(typename, SOCKET_ANY) == 0 ||
+      strcmp(typename, SOCKET_CONN) == 0) {
+    return checkgroup(L, index, typename);
+  } else {
+    return luaL_checkudata(L, index, typename);
+  }
+}
+
+static void settype(lua_State *L, int index, const char *typename) {
+  luaL_getmetatable(L, typename);
+  lua_setmetatable(L, index);
+}
+
+#define LUA_SUCCESS_RETURN(L) \
+  lua_pushnumber(L, 1); \
+  return 1
+
+#define LUA_CHECK_RETURN(L, err) \
+  if (err) { \
+    lua_pushnil(L); \
+    lua_pushstring(L, err); \
+    return 2; \
+  } \
+  LUA_SUCCESS_RETURN(L)
+
+////////////////////////////////////////////////////////////////////////////////
+
+static int l_socket_create(lua_State *L);
+static int l_socket_destroy(lua_State *L);
+static int l_socket_settimeout(lua_State *L);
+static int l_socket_getsockinfo(lua_State *L);
+
+static int l_socket_accept(lua_State *L);
+static int l_socket_listen(lua_State *L);
+
+static int l_socket_create_and_connect(lua_State *L);
+static int l_socket_connect(lua_State *L);
+static int l_socket_send(lua_State *L);
+static int l_socket_receive(lua_State *L);
+
+////////////////////////////////////////////////////////////////////////////////
+
+static const struct luaL_Reg methods_generic[] = {
+  {"destroy",     l_socket_destroy},
+  {"settimeout",  l_socket_settimeout},
+  {"getsockinfo", l_socket_getsockinfo},
+  {"listen",      l_socket_listen},
+  {"connect",     l_socket_connect},
+  {NULL, NULL}
+};
+
+static const struct luaL_Reg methods_server[] = {
+  {"destroy",     l_socket_destroy},
+  {"getsockinfo", l_socket_getsockinfo},
+  {"accept",      l_socket_accept},
+  {"send",        l_socket_send},
+  {"receive",     l_socket_receive},
+  {NULL, NULL}
+};
+
+static const struct luaL_Reg methods_client[] = {
+  {"destroy",     l_socket_destroy},
+  {"settimeout",  l_socket_settimeout},
+  {"getsockinfo", l_socket_getsockinfo},
+  {"send",        l_socket_send},
+  {"receive",     l_socket_receive},
+  {NULL, NULL}
+};
+
+static const struct luaL_Reg funcs_luasocket[] = {
+  {"create",             l_socket_create},
+  {"create_and_connect", l_socket_create_and_connect},
+  {NULL, NULL}
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Check/enforce inheritance
+static void add_to_group(lua_State *L,
+                  const char *metatablename,
+                  const char *groupname) {
+  luaL_getmetatable(L, metatablename); // mt
+  lua_pushstring(L, groupname);        // mt, "name"
+  lua_pushboolean(L, 1);               // mt, "name", true
+  lua_rawset(L, -3);                   // mt
+  lua_pop(L, 1);
+}
+
+static void set_methods(lua_State *L,
+  const char *metatablename,
+  const struct luaL_Reg *methods) {
+  luaL_getmetatable(L, metatablename);   // mt
+  // Create the __index table
+  lua_pushstring(L, "__index");          // mt, "__index"
+  lua_newtable(L);                       // mt, "__index", t
+  for (; methods->name; methods++) {
+    lua_pushstring(L, methods->name);    // mt, "__index", t, "name"
+    lua_pushcfunction(L, methods->func); // mt, "__index", t, "name", func
+    lua_rawset(L, -3);                   // mt, "__index", t
+  }
+  lua_rawset(L, -3);                     // mt
+  lua_pop(L, 1);
+}
+
+int luaopen_libluasocket(lua_State *L) {
+  luaL_newmetatable(L, SOCKET_GENERIC);
+  luaL_newmetatable(L, SOCKET_CLIENT);
+  luaL_newmetatable(L, SOCKET_SERVER);
+  lua_pop(L, 3);
+  add_to_group(L, SOCKET_GENERIC, SOCKET_ANY);
+  add_to_group(L, SOCKET_CLIENT, SOCKET_ANY);
+  add_to_group(L, SOCKET_SERVER, SOCKET_ANY);
+  add_to_group(L, SOCKET_CLIENT, SOCKET_CONN);
+  add_to_group(L, SOCKET_SERVER, SOCKET_CONN);
+  set_methods(L, SOCKET_GENERIC, methods_generic);
+  set_methods(L, SOCKET_CLIENT, methods_client);
+  set_methods(L, SOCKET_SERVER, methods_server);
+
+  luaL_register(L, "luasocket", funcs_luasocket);
+  return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// General
+
+// sock,err create(bind_host, bind_port)
+// sock,err create(bind_host) -> any port
+// sock,err create() -> any port on localhost
+static int l_socket_create(lua_State *L) {
+  const char *err;
+  t_socket sock;
+  const char *addr = lua_tostring(L, 1);
+  if (!addr) {
+    addr = DEFAULT_HOST;
+  }
+  unsigned short port = lua_tonumber(L, 2);
+  err = tcp_create(&sock);
+  if (!err) {
+    err = tcp_bind(&sock, addr, port); // bind on create
+    if (err) {
+      tcp_destroy(&sock);
+    } else {
+      p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
+      settype(L, -2, SOCKET_GENERIC);
+      socket_setnonblocking(&sock);
+      tcp->sock = sock;
+      tcp->timeout = 0;
+      return 1; // Return userdata
+    }
+  }
+  LUA_CHECK_RETURN(L, err);
+}
+
+// destroy()
+static int l_socket_destroy(lua_State *L) {
+  p_tcp tcp = (p_tcp) checktype(L, 1, SOCKET_ANY);
+  const char *err = tcp_destroy(&tcp->sock);
+  LUA_CHECK_RETURN(L, err);
+}
+
+// send(socket, data)
+static int l_socket_send(lua_State *L) {
+  p_tcp self = (p_tcp) checktype(L, 1, SOCKET_CONN);
+  p_tcp tcp = (p_tcp) checktype(L, 2, SOCKET_CONN);
+  size_t len;
+  const char *data = luaL_checklstring(L, 3, &len);
+  const char *err =
+    tcp_send(&tcp->sock, data, len, tcp->timeout);
+  LUA_CHECK_RETURN(L, err);
+}
+
+#define LUA_READ_STEP 8192
+static int l_socket_receive(lua_State *L) {
+  p_tcp self = (p_tcp) checktype(L, 1, SOCKET_CONN);
+  p_tcp handle = (p_tcp) checktype(L, 2, SOCKET_CONN);
+  size_t len = luaL_checknumber(L, 3);
+  char buf[LUA_READ_STEP];
+  const char *err = NULL;
+  int received;
+  size_t got = 0, step = 0;
+  luaL_Buffer b;
+
+  luaL_buffinit(L, &b);
+  do {
+    step = (LUA_READ_STEP < len - got ? LUA_READ_STEP : len - got);
+    err = tcp_raw_receive(&handle->sock, buf, step, self->timeout, &received);
+    if (err == NULL) {
+      luaL_addlstring(&b, buf, received);
+      got += received;
+    }
+  } while (err == NULL && got < len);
+
+  if (err) {
+    lua_pushnil(L);
+    lua_pushstring(L, err);
+    return 2;
+  }
+  luaL_pushresult(&b);
+  return 1;
+}
+
+// settimeout(timeout)
+static int l_socket_settimeout(lua_State *L) {
+  p_tcp self = (p_tcp) checktype(L, 1, SOCKET_ANY);
+  int timeout = luaL_checknumber(L, 2);
+  self->timeout = timeout;
+  LUA_SUCCESS_RETURN(L);
+}
+
+// table getsockinfo()
+static int l_socket_getsockinfo(lua_State *L) {
+  char buf[256];
+  short port = 0;
+  p_tcp tcp = (p_tcp) checktype(L, 1, SOCKET_ANY);
+  if (socket_get_info(&tcp->sock, &port, buf, 256) == SUCCESS) {
+    lua_newtable(L);                    // t
+    lua_pushstring(L, "host");          // t, "host"
+    lua_pushstring(L, buf);             // t, "host", buf
+    lua_rawset(L, -3);                  // t
+    lua_pushstring(L, "port");          // t, "port"
+    lua_pushnumber(L, port);            // t, "port", port
+    lua_rawset(L, -3);                  // t
+    return 1;
+  }
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Server
+
+// accept()
+static int l_socket_accept(lua_State *L) {
+  const char *err;
+  p_tcp self = (p_tcp) checktype(L, 1, SOCKET_SERVER);
+  t_socket sock;
+  err = tcp_accept(&self->sock, &sock, self->timeout);
+  if (!err) { // Success
+    // Create a reference to the client
+    p_tcp client = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
+    settype(L, 2, SOCKET_CLIENT);
+    socket_setnonblocking(&sock);
+    client->sock = sock;
+    client->timeout = self->timeout;
+    return 1;
+  }
+  LUA_CHECK_RETURN(L, err);
+}
+
+static int l_socket_listen(lua_State *L) {
+  const char* err;
+  p_tcp tcp = (p_tcp) checktype(L, 1, SOCKET_GENERIC);
+  int backlog = 10;
+  err = tcp_listen(&tcp->sock, backlog);
+  if (!err) {
+    // Set the current as a server
+    settype(L, 1, SOCKET_SERVER); // Now a server
+  }
+  LUA_CHECK_RETURN(L, err);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Client
+
+// create_and_connect(host, port, timeout)
+extern double __gettime();
+static int l_socket_create_and_connect(lua_State *L) {
+  const char* err = NULL;
+  double end;
+  t_socket sock;
+  const char *host = luaL_checkstring(L, 1);
+  unsigned short port = luaL_checknumber(L, 2);
+  int timeout = luaL_checknumber(L, 3);
+
+  // Create and connect loop for timeout milliseconds
+  end = __gettime() + timeout/1000;
+  do {
+    // Create the socket
+    err = tcp_create(&sock);
+    if (!err) {
+        // Connect
+        err = tcp_connect(&sock, host, port, timeout);
+        if (err) {
+          tcp_destroy(&sock);
+          usleep(100000); // sleep for 100ms
+        } else {
+          p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
+          settype(L, -2, SOCKET_CLIENT);
+          socket_setnonblocking(&sock);
+          tcp->sock = sock;
+          tcp->timeout = timeout;
+          return 1; // Return userdata
+        }
+    }
+  } while (err && __gettime() < end);
+
+  LUA_CHECK_RETURN(L, err);
+}
+
+// connect(host, port)
+static int l_socket_connect(lua_State *L) {
+  const char *err;
+  p_tcp tcp = (p_tcp) checktype(L, 1, SOCKET_GENERIC);
+  const char *host = luaL_checkstring(L, 2);
+  unsigned short port = luaL_checknumber(L, 3);
+  err = tcp_connect(&tcp->sock, host, port, tcp->timeout);
+  if (!err) {
+    settype(L, 1, SOCKET_CLIENT); // Now a client
+  }
+  LUA_CHECK_RETURN(L, err);
+}
diff --git a/lib/lua/src/socket.h b/lib/lua/src/socket.h
new file mode 100644
index 0000000..afb827e
--- /dev/null
+++ b/lib/lua/src/socket.h
@@ -0,0 +1,78 @@
+//
+// 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.
+//
+
+#ifndef LUA_THRIFT_SOCKET_H
+#define LUA_THRIFT_SOCKET_H
+
+#include <sys/socket.h>
+
+#ifdef _WIN32
+// SOL
+#else
+typedef int t_socket;
+typedef t_socket* p_socket;
+#endif
+
+// Error Codes
+enum {
+  SUCCESS = 0,
+  TIMEOUT = -1,
+  CLOSED = -2,
+};
+typedef int T_ERRCODE;
+
+static const char * TIMEOUT_MSG = "Timeout";
+static const char * CLOSED_MSG = "Connection Closed";
+
+typedef struct sockaddr t_sa;
+typedef t_sa * p_sa;
+
+T_ERRCODE socket_create(p_socket sock, int domain, int type, int protocol);
+T_ERRCODE socket_destroy(p_socket sock);
+T_ERRCODE socket_bind(p_socket sock, p_sa addr, int addr_len);
+T_ERRCODE socket_get_info(p_socket sock, short *port, char *buf, size_t len);
+T_ERRCODE socket_send(p_socket sock, const char *data, size_t len, int timeout);
+T_ERRCODE socket_recv(p_socket sock, char *data, size_t len, int timeout,
+                      int *received);
+
+T_ERRCODE socket_setblocking(p_socket sock);
+T_ERRCODE socket_setnonblocking(p_socket sock);
+
+T_ERRCODE socket_accept(p_socket sock, p_socket sibling,
+                        p_sa addr, socklen_t *addr_len, int timeout);
+T_ERRCODE socket_listen(p_socket sock, int backlog);
+
+T_ERRCODE socket_connect(p_socket sock, p_sa addr, int addr_len, int timeout);
+
+const char * tcp_create(p_socket sock);
+const char * tcp_destroy(p_socket sock);
+const char * tcp_bind(p_socket sock, const char *host, unsigned short port);
+const char * tcp_send(p_socket sock, const char *data, size_t w_len,
+                      int timeout);
+const char * tcp_receive(p_socket sock, char *data, size_t r_len, int timeout);
+const char * tcp_raw_receive(p_socket sock, char * data, size_t r_len,
+                             int timeout, int *received);
+
+const char * tcp_listen(p_socket sock, int backlog);
+const char * tcp_accept(p_socket sock, p_socket client, int timeout);
+
+const char * tcp_connect(p_socket sock, const char *host, unsigned short port,
+                         int timeout);
+
+#endif
diff --git a/lib/lua/src/usocket.c b/lib/lua/src/usocket.c
new file mode 100644
index 0000000..1a1b549
--- /dev/null
+++ b/lib/lua/src/usocket.c
@@ -0,0 +1,376 @@
+//
+// 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.
+//
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <stdio.h> // TODO REMOVE
+
+#include "socket.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Private
+
+// Num seconds since Jan 1 1970 (UTC)
+#ifdef _WIN32
+// SOL
+#else
+  double __gettime() {
+    struct timeval v;
+    gettimeofday(&v, (struct timezone*) NULL);
+    return v.tv_sec + v.tv_usec/1.0e6;
+  }
+#endif
+
+#define WAIT_MODE_R  1
+#define WAIT_MODE_W  2
+#define WAIT_MODE_C  (WAIT_MODE_R|WAIT_MODE_W)
+T_ERRCODE socket_wait(p_socket sock, int mode, int timeout) {
+  int ret = 0;
+  fd_set rfds, wfds;
+  struct timeval tv;
+  double end, t;
+  if (!timeout) {
+    return TIMEOUT;
+  }
+
+  end = __gettime() + timeout/1000;
+  do {
+    FD_ZERO(&rfds);
+    FD_ZERO(&wfds);
+
+    // Specify what I/O operations we care about
+    if (mode & WAIT_MODE_R) {
+      FD_SET(*sock, &rfds);
+    }
+    if (mode & WAIT_MODE_W) {
+      FD_SET(*sock, &wfds);
+    }
+
+    // Check for timeout
+    t = end - __gettime();
+    if (t < 0.0) {
+      break;
+    }
+
+    // Wait
+    tv.tv_sec = (int)t;
+    tv.tv_usec = (int)((t - tv.tv_sec) * 1.0e6);
+    ret = select(*sock+1, &rfds, &wfds, NULL, &tv);
+  } while (ret == -1 && errno == EINTR);
+  if (ret == -1) {
+    return errno;
+  }
+
+  // Check for timeout
+  if (ret == 0) {
+    return TIMEOUT;
+  }
+
+  // Verify that we can actually read from the remote host
+  if (mode & WAIT_MODE_C && FD_ISSET(*sock, &rfds) &&
+      recv(*sock, (char*) &rfds, 0, 0) != 0) {
+    return errno;
+  }
+
+  return SUCCESS;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// General
+
+T_ERRCODE socket_create(p_socket sock, int domain, int type, int protocol) {
+  *sock = socket(domain, type, protocol);
+  if (*sock > 0) {
+    return SUCCESS;
+  } else {
+    return errno;
+  }
+}
+
+T_ERRCODE socket_destroy(p_socket sock) {
+  // TODO Figure out if I should be free-ing this
+  if (*sock > 0) {
+    (void)socket_setblocking(sock);
+    close(*sock);
+    *sock = -1;
+  }
+  return SUCCESS;
+}
+
+T_ERRCODE socket_bind(p_socket sock, p_sa addr, int addr_len) {
+  int ret = socket_setblocking(sock);
+  if (ret != SUCCESS) {
+    return ret;
+  }
+  if (bind(*sock, addr, addr_len)) {
+    ret = errno;
+  }
+  int ret2 = socket_setnonblocking(sock);
+  return ret == SUCCESS ? ret2 : ret;
+}
+
+T_ERRCODE socket_get_info(p_socket sock, short *port, char *buf, size_t len) {
+  struct sockaddr_storage sa;
+  memset(&sa, 0, sizeof(sa));
+  socklen_t addrlen = sizeof(sa);
+  int rc = getsockname(*sock, (struct sockaddr*)&sa, &addrlen);
+  if (!rc) {
+    if (sa.ss_family == AF_INET6) {
+      struct sockaddr_in6* sin = (struct sockaddr_in6*)(&sa);
+      if (!inet_ntop(AF_INET6, &sin->sin6_addr, buf, len)) {
+        return errno;
+      }
+      *port = ntohs(sin->sin6_port);
+    } else {
+      struct sockaddr_in* sin = (struct sockaddr_in*)(&sa);
+      if (!inet_ntop(AF_INET, &sin->sin_addr, buf, len)) {
+        return errno;
+      }
+      *port = ntohs(sin->sin_port);
+    }
+    return SUCCESS;
+  }
+  return errno;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Server
+
+T_ERRCODE socket_accept(p_socket sock, p_socket client,
+                  p_sa addr, socklen_t *addrlen, int timeout) {
+  int err;
+  if (*sock < 0) {
+    return CLOSED;
+  }
+  do {
+    *client = accept(*sock, addr, addrlen);
+    if (*client > 0) {
+      return SUCCESS;
+    }
+  } while ((err = errno) == EINTR);
+
+  if (err == EAGAIN || err == ECONNABORTED) {
+    return socket_wait(sock, WAIT_MODE_R, timeout);
+  }
+
+  return err;
+}
+
+T_ERRCODE socket_listen(p_socket sock, int backlog) {
+  int ret = socket_setblocking(sock);
+  if (ret != SUCCESS) {
+    return ret;
+  }
+  if (listen(*sock, backlog)) {
+    ret = errno;
+  }
+  int ret2 = socket_setnonblocking(sock);
+  return ret == SUCCESS ? ret2 : ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Client
+
+T_ERRCODE socket_connect(p_socket sock, p_sa addr, int addr_len, int timeout) {
+  int err;
+  if (*sock < 0) {
+    return CLOSED;
+  }
+
+  do {
+    if (connect(*sock, addr, addr_len) == 0) {
+      return SUCCESS;
+    }
+  } while ((err = errno) == EINTR);
+  if (err != EINPROGRESS && err != EAGAIN) {
+    return err;
+  }
+  return socket_wait(sock, WAIT_MODE_C, timeout);
+}
+
+T_ERRCODE socket_send(
+  p_socket sock, const char *data, size_t len, int timeout) {
+  int err, put = 0;
+  if (*sock < 0) {
+    return CLOSED;
+  }
+  do {
+    put = send(*sock, data, len, 0);
+    if (put > 0) {
+      return SUCCESS;
+    }
+  } while ((err = errno) == EINTR);
+
+  if (err == EAGAIN) {
+    return socket_wait(sock, WAIT_MODE_W, timeout);
+  }
+
+  return err;
+}
+
+T_ERRCODE socket_recv(
+  p_socket sock, char *data, size_t len, int timeout, int *received) {
+  int err, got = 0;
+  if (*sock < 0) {
+    return CLOSED;
+  }
+  *received = 0;
+
+  do {
+    got = recv(*sock, data, len, 0);
+    if (got > 0) {
+      *received = got;
+      return SUCCESS;
+    }
+    err = errno;
+
+    // Connection has been closed by peer
+    if (got == 0) {
+      return CLOSED;
+    }
+  } while (err == EINTR);
+
+  if (err == EAGAIN) {
+    return socket_wait(sock, WAIT_MODE_R, timeout);
+  }
+
+  return err;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Util
+
+T_ERRCODE socket_setnonblocking(p_socket sock) {
+  int flags = fcntl(*sock, F_GETFL, 0);
+  flags |= O_NONBLOCK;
+  return fcntl(*sock, F_SETFL, flags) != -1 ? SUCCESS : errno;
+}
+
+T_ERRCODE socket_setblocking(p_socket sock) {
+  int flags = fcntl(*sock, F_GETFL, 0);
+  flags &= (~(O_NONBLOCK));
+  return fcntl(*sock, F_SETFL, flags) != -1 ? SUCCESS : errno;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TCP
+
+#define ERRORSTR_RETURN(err) \
+  if (err == SUCCESS) { \
+    return NULL; \
+  } else if (err == TIMEOUT) { \
+    return TIMEOUT_MSG; \
+  } else if (err == CLOSED) { \
+    return CLOSED_MSG; \
+  } \
+  return strerror(err)
+
+const char * tcp_create(p_socket sock) {
+  int err = socket_create(sock, AF_INET, SOCK_STREAM, 0);
+  ERRORSTR_RETURN(err);
+}
+
+const char * tcp_destroy(p_socket sock) {
+  int err = socket_destroy(sock);
+  ERRORSTR_RETURN(err);
+}
+
+const char * tcp_bind(p_socket sock, const char *host, unsigned short port) {
+  int err;
+  struct hostent *h;
+  struct sockaddr_in local;
+  memset(&local, 0, sizeof(local));
+  local.sin_family = AF_INET;
+  local.sin_addr.s_addr = htonl(INADDR_ANY);
+  local.sin_port = htons(port);
+  if (strcmp(host, "*") && !inet_aton(host, &local.sin_addr)) {
+    h = gethostbyname(host);
+    if (!h) {
+      return hstrerror(h_errno);
+    }
+    memcpy(&local.sin_addr,
+           (struct in_addr *)h->h_addr_list[0],
+           sizeof(struct in_addr));
+  }
+  err = socket_bind(sock, (p_sa) &local, sizeof(local));
+  ERRORSTR_RETURN(err);
+}
+
+const char * tcp_listen(p_socket sock, int backlog) {
+  int err = socket_listen(sock, backlog);
+  ERRORSTR_RETURN(err);
+}
+
+const char * tcp_accept(p_socket sock, p_socket client, int timeout) {
+  int err = socket_accept(sock, client, NULL, NULL, timeout);
+  ERRORSTR_RETURN(err);
+}
+
+const char * tcp_connect(p_socket sock,
+                         const char *host,
+                         unsigned short port,
+                         int timeout) {
+  int err;
+  struct hostent *h;
+  struct sockaddr_in remote;
+  memset(&remote, 0, sizeof(remote));
+  remote.sin_family = AF_INET;
+  remote.sin_port = htons(port);
+  if (strcmp(host, "*") && !inet_aton(host, &remote.sin_addr)) {
+    h = gethostbyname(host);
+    if (!h) {
+      return hstrerror(h_errno);
+    }
+    memcpy(&remote.sin_addr,
+           (struct in_addr *)h->h_addr_list[0],
+           sizeof(struct in_addr));
+  }
+  err = socket_connect(sock, (p_sa) &remote, sizeof(remote), timeout);
+  ERRORSTR_RETURN(err);
+}
+
+#define WRITE_STEP 8192
+const char * tcp_send(
+  p_socket sock, const char * data, size_t w_len, int timeout) {
+  int err;
+  size_t put = 0, step;
+  if (!w_len) {
+    return NULL;
+  }
+
+  do {
+    step = (WRITE_STEP < w_len - put ? WRITE_STEP : w_len - put);
+    err = socket_send(sock, data + put, step, timeout);
+    put += step;
+  } while (err == SUCCESS && put < w_len);
+  ERRORSTR_RETURN(err);
+}
+
+const char * tcp_raw_receive(
+  p_socket sock, char * data, size_t r_len, int timeout, int *received) {
+  int err = socket_recv(sock, data, r_len, timeout, received);
+  ERRORSTR_RETURN(err);
+}
diff --git a/lib/netcore/Makefile.am b/lib/netcore/Makefile.am
new file mode 100644
index 0000000..caf3f34
--- /dev/null
+++ b/lib/netcore/Makefile.am
@@ -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.
+#
+
+SUBDIRS = . 
+
+all-local:
+	$(DOTNETCORE) build
+
+check-local:
+	$(DOTNETCORE) test Tests/Thrift.Tests/Thrift.Tests.csproj
+	${DOTNETCORE} test Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj
+
+clean-local:
+	$(RM) -r Thrift/bin
+	$(RM) -r Thrift/obj
+
+EXTRA_DIST = \
+	README.md \
+	Tests \
+	Thrift \
+	Thrift.sln \
+	build.cmd \
+	build.sh \
+	runtests.cmd \
+	runtests.sh
diff --git a/lib/netcore/README.md b/lib/netcore/README.md
new file mode 100644
index 0000000..94b047f
--- /dev/null
+++ b/lib/netcore/README.md
@@ -0,0 +1,24 @@
+# Apache Thrift netcore
+
+Thrift client library ported to Microsoft .Net Core 
+
+# Content
+- Tests/Thrift.PublicInterfaces.Compile.Tests - project for checking public interfaces during adding changes to Thrift library
+- Thrift - Thrift library 
+
+# Reused components 
+- .NET Standard 1.6 (SDK 2.0.0)
+
+# How to build on Windows
+- Get Thrift IDL compiler executable, add to some folder and add path to this folder into PATH variable
+- Open the Thrift.sln project with Visual Studio and build.
+or 
+- Build with scripts
+
+# How to build on Unix
+- Ensure you have .NET Core 2.0.0 SDK installed or use the Ubuntu Xenial docker image
+- Follow common build practice for Thrift: bootstrap, configure, and make
+
+# Known issues
+- In trace logging mode you can see some not important internal exceptions
+
diff --git a/lib/netcore/Tests/Thrift.IntegrationTests/.gitignore b/lib/netcore/Tests/Thrift.IntegrationTests/.gitignore
new file mode 100644
index 0000000..7254c31
--- /dev/null
+++ b/lib/netcore/Tests/Thrift.IntegrationTests/.gitignore
@@ -0,0 +1,2 @@
+# ignore for autogenerated files
+/Apache
diff --git a/lib/netcore/Tests/Thrift.IntegrationTests/Protocols/ProtocolsOperationsTests.cs b/lib/netcore/Tests/Thrift.IntegrationTests/Protocols/ProtocolsOperationsTests.cs
new file mode 100644
index 0000000..bc4afa1
--- /dev/null
+++ b/lib/netcore/Tests/Thrift.IntegrationTests/Protocols/ProtocolsOperationsTests.cs
@@ -0,0 +1,502 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using KellermanSoftware.CompareNetObjects;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Thrift.Protocols;
+using Thrift.Protocols.Entities;
+using Thrift.Transports.Client;
+
+namespace Thrift.IntegrationTests.Protocols
+{
+    [TestClass]
+    public class ProtocolsOperationsTests
+    {
+        private readonly CompareLogic _compareLogic = new CompareLogic();
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol), TMessageType.Call)]
+        [DataRow(typeof(TBinaryProtocol), TMessageType.Exception)]
+        [DataRow(typeof(TBinaryProtocol), TMessageType.Oneway)]
+        [DataRow(typeof(TBinaryProtocol), TMessageType.Reply)]
+        [DataRow(typeof(TCompactProtocol), TMessageType.Call)]
+        [DataRow(typeof(TCompactProtocol), TMessageType.Exception)]
+        [DataRow(typeof(TCompactProtocol), TMessageType.Oneway)]
+        [DataRow(typeof(TCompactProtocol), TMessageType.Reply)]
+        [DataRow(typeof(TJsonProtocol), TMessageType.Call)]
+        [DataRow(typeof(TJsonProtocol), TMessageType.Exception)]
+        [DataRow(typeof(TJsonProtocol), TMessageType.Oneway)]
+        [DataRow(typeof(TJsonProtocol), TMessageType.Reply)]
+        public async Task WriteReadMessage_Test(Type protocolType, TMessageType messageType)
+        {
+            var expected = new TMessage(nameof(TMessage), messageType, 1);
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteMessageBeginAsync(expected);
+                    await protocol.WriteMessageEndAsync();
+
+                    stream.Seek(0, SeekOrigin.Begin);
+
+                    var actualMessage = await protocol.ReadMessageBeginAsync();
+                    await protocol.ReadMessageEndAsync();
+
+                    var result = _compareLogic.Compare(expected, actualMessage);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+        }
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol))]
+        [DataRow(typeof(TCompactProtocol))]
+        [DataRow(typeof(TJsonProtocol))]
+        [ExpectedException(typeof(Exception))]
+        public async Task WriteReadStruct_Test(Type protocolType)
+        {
+            var expected = new TStruct(nameof(TStruct));
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteStructBeginAsync(expected);
+                    await protocol.WriteStructEndAsync();
+
+                    stream?.Seek(0, SeekOrigin.Begin);
+
+                    var actual = await protocol.ReadStructBeginAsync();
+                    await protocol.ReadStructEndAsync();
+
+                    var result = _compareLogic.Compare(expected, actual);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+        }
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol))]
+        [DataRow(typeof(TCompactProtocol))]
+        [DataRow(typeof(TJsonProtocol))]
+        [ExpectedException(typeof(Exception))]
+        public async Task WriteReadField_Test(Type protocolType)
+        {
+            var expected = new TField(nameof(TField), TType.String, 1);
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteFieldBeginAsync(expected);
+                    await protocol.WriteFieldEndAsync();
+
+                    stream?.Seek(0, SeekOrigin.Begin);
+
+                    var actual = await protocol.ReadFieldBeginAsync();
+                    await protocol.ReadFieldEndAsync();
+
+                    var result = _compareLogic.Compare(expected, actual);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+        }
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol))]
+        [DataRow(typeof(TCompactProtocol))]
+        [DataRow(typeof(TJsonProtocol))]
+        public async Task WriteReadMap_Test(Type protocolType)
+        {
+            var expected = new TMap(TType.String, TType.String, 1);
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteMapBeginAsync(expected);
+                    await protocol.WriteMapEndAsync();
+
+                    stream?.Seek(0, SeekOrigin.Begin);
+
+                    var actual = await protocol.ReadMapBeginAsync();
+                    await protocol.ReadMapEndAsync();
+
+                    var result = _compareLogic.Compare(expected, actual);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+
+        }
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol))]
+        [DataRow(typeof(TCompactProtocol))]
+        [DataRow(typeof(TJsonProtocol))]
+        public async Task WriteReadList_Test(Type protocolType)
+        {
+            var expected = new TList(TType.String, 1);
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteListBeginAsync(expected);
+                    await protocol.WriteListEndAsync();
+
+                    stream?.Seek(0, SeekOrigin.Begin);
+
+                    var actual = await protocol.ReadListBeginAsync();
+                    await protocol.ReadListEndAsync();
+
+                    var result = _compareLogic.Compare(expected, actual);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+        }
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol))]
+        [DataRow(typeof(TCompactProtocol))]
+        [DataRow(typeof(TJsonProtocol))]
+        public async Task WriteReadSet_Test(Type protocolType)
+        {
+            var expected = new TSet(TType.String, 1);
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteSetBeginAsync(expected);
+                    await protocol.WriteSetEndAsync();
+
+                    stream?.Seek(0, SeekOrigin.Begin);
+
+                    var actual = await protocol.ReadSetBeginAsync();
+                    await protocol.ReadSetEndAsync();
+
+                    var result = _compareLogic.Compare(expected, actual);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+        }
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol))]
+        [DataRow(typeof(TCompactProtocol))]
+        [DataRow(typeof(TJsonProtocol))]
+        public async Task WriteReadBool_Test(Type protocolType)
+        {
+            var expected = true;
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteBoolAsync(expected);
+
+                    stream?.Seek(0, SeekOrigin.Begin);
+
+                    var actual = await protocol.ReadBoolAsync();
+
+                    var result = _compareLogic.Compare(expected, actual);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+        }
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol))]
+        [DataRow(typeof(TCompactProtocol))]
+        [DataRow(typeof(TJsonProtocol))]
+        public async Task WriteReadByte_Test(Type protocolType)
+        {
+            var expected = sbyte.MaxValue;
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteByteAsync(expected);
+
+                    stream?.Seek(0, SeekOrigin.Begin);
+
+                    var actual = await protocol.ReadByteAsync();
+
+                    var result = _compareLogic.Compare(expected, actual);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+        }
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol))]
+        [DataRow(typeof(TCompactProtocol))]
+        [DataRow(typeof(TJsonProtocol))]
+        public async Task WriteReadI16_Test(Type protocolType)
+        {
+            var expected = short.MaxValue;
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteI16Async(expected);
+
+                    stream?.Seek(0, SeekOrigin.Begin);
+
+                    var actual = await protocol.ReadI16Async();
+
+                    var result = _compareLogic.Compare(expected, actual);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+        }
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol))]
+        [DataRow(typeof(TCompactProtocol))]
+        [DataRow(typeof(TJsonProtocol))]
+        public async Task WriteReadI32_Test(Type protocolType)
+        {
+            var expected = int.MaxValue;
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteI32Async(expected);
+
+                    stream?.Seek(0, SeekOrigin.Begin);
+
+                    var actual = await protocol.ReadI32Async();
+
+                    var result = _compareLogic.Compare(expected, actual);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+        }
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol))]
+        [DataRow(typeof(TCompactProtocol))]
+        [DataRow(typeof(TJsonProtocol))]
+        public async Task WriteReadI64_Test(Type protocolType)
+        {
+            var expected = long.MaxValue;
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteI64Async(expected);
+
+                    stream?.Seek(0, SeekOrigin.Begin);
+
+                    var actual = await protocol.ReadI64Async();
+
+                    var result = _compareLogic.Compare(expected, actual);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+        }
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol))]
+        [DataRow(typeof(TCompactProtocol))]
+        [DataRow(typeof(TJsonProtocol))]
+        public async Task WriteReadDouble_Test(Type protocolType)
+        {
+            var expected = double.MaxValue;
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteDoubleAsync(expected);
+
+                    stream?.Seek(0, SeekOrigin.Begin);
+
+                    var actual = await protocol.ReadDoubleAsync();
+
+                    var result = _compareLogic.Compare(expected, actual);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+        }
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol))]
+        [DataRow(typeof(TCompactProtocol))]
+        [DataRow(typeof(TJsonProtocol))]
+        public async Task WriteReadString_Test(Type protocolType)
+        {
+            var expected = nameof(String);
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteStringAsync(expected);
+
+                    stream?.Seek(0, SeekOrigin.Begin);
+
+                    var actual = await protocol.ReadStringAsync();
+
+                    var result = _compareLogic.Compare(expected, actual);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+        }
+
+        [DataTestMethod]
+        [DataRow(typeof(TBinaryProtocol))]
+        [DataRow(typeof(TCompactProtocol))]
+        [DataRow(typeof(TJsonProtocol))]
+        public async Task WriteReadBinary_Test(Type protocolType)
+        {
+            var expected = Encoding.UTF8.GetBytes(nameof(String));
+
+            try
+            {
+                var tuple = GetProtocolInstance(protocolType);
+                using (var stream = tuple.Item1)
+                {
+                    var protocol = tuple.Item2;
+
+                    await protocol.WriteBinaryAsync(expected);
+
+                    stream?.Seek(0, SeekOrigin.Begin);
+
+                    var actual = await protocol.ReadBinaryAsync();
+
+                    var result = _compareLogic.Compare(expected, actual);
+                    Assert.IsTrue(result.AreEqual, result.DifferencesString);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
+            }
+        }
+
+        private static Tuple<Stream, TProtocol> GetProtocolInstance(Type protocolType)
+        {
+            var memoryStream = new MemoryStream();
+            var streamClientTransport = new TStreamClientTransport(memoryStream, memoryStream);
+            var protocol = (TProtocol) Activator.CreateInstance(protocolType, streamClientTransport);
+            return new Tuple<Stream, TProtocol>(memoryStream, protocol);
+        }
+    }
+}
diff --git a/lib/netcore/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj b/lib/netcore/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj
new file mode 100644
index 0000000..f25dac5
--- /dev/null
+++ b/lib/netcore/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj
@@ -0,0 +1,29 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.0</TargetFramework>
+    <AssemblyName>Thrift.IntegrationTests</AssemblyName>
+    <PackageId>Thrift.IntegrationTests</PackageId>
+    <OutputType>Exe</OutputType>
+    <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
+    <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
+    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
+    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
+    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
+    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="CompareNETObjects" Version="4.3.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
+    <PackageReference Include="MSTest.TestAdapter" Version="1.2.0" />
+    <PackageReference Include="MSTest.TestFramework" Version="1.2.0" />
+    <PackageReference Include="System.ServiceModel.Primitives" Version="4.4.0" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\Thrift\Thrift.csproj" />
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
+  </ItemGroup>
+
+</Project>
\ No newline at end of file
diff --git a/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/.gitignore b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/.gitignore
new file mode 100644
index 0000000..ae929a3
--- /dev/null
+++ b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/.gitignore
@@ -0,0 +1,4 @@
+# ignore for autogenerated files
+/ThriftTest
+/Apache
+/Facebook
diff --git a/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/CassandraTest.thrift b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/CassandraTest.thrift
new file mode 100644
index 0000000..4b92720
--- /dev/null
+++ b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/CassandraTest.thrift
@@ -0,0 +1,705 @@
+#!/usr/local/bin/thrift --java --php --py
+# 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.
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# *** PLEASE REMEMBER TO EDIT THE VERSION CONSTANT WHEN MAKING CHANGES ***
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+#
+# Interface definition for Cassandra Service
+#
+
+namespace netcore Apache.Cassandra.Test
+
+# Thrift.rb has a bug where top-level modules that include modules 
+# with the same name are not properly referenced, so we can't do
+# Cassandra::Cassandra::Client.
+namespace rb CassandraThrift
+
+# The API version (NOT the product version), composed as a dot delimited
+# string with major, minor, and patch level components.
+#
+#  - Major: Incremented for backward incompatible changes. An example would
+#           be changes to the number or disposition of method arguments.
+#  - Minor: Incremented for backward compatible changes. An example would
+#           be the addition of a new (optional) method.
+#  - Patch: Incremented for bug fixes. The patch level should be increased
+#           for every edit that doesn't result in a change to major/minor.
+#
+# See the Semantic Versioning Specification (SemVer) http://semver.org.
+const string VERSION = "19.24.0"
+
+
+#
+# data structures
+#
+
+/** Basic unit of data within a ColumnFamily.
+ * @param name, the name by which this column is set and retrieved.  Maximum 64KB long.
+ * @param value. The data associated with the name.  Maximum 2GB long, but in practice you should limit it to small numbers of MB (since Thrift must read the full value into memory to operate on it).
+ * @param timestamp. The timestamp is used for conflict detection/resolution when two columns with same name need to be compared.
+ * @param ttl. An optional, positive delay (in seconds) after which the column will be automatically deleted. 
+ */
+struct Column {
+   1: required binary name,
+   2: optional binary value,
+   3: optional i64 timestamp,
+   4: optional i32 ttl,
+}
+
+/** A named list of columns.
+ * @param name. see Column.name.
+ * @param columns. A collection of standard Columns.  The columns within a super column are defined in an adhoc manner.
+ *                 Columns within a super column do not have to have matching structures (similarly named child columns).
+ */
+struct SuperColumn {
+   1: required binary name,
+   2: required list<Column> columns,
+}
+
+struct CounterColumn {
+    1: required binary name,
+    2: required i64 value
+}
+
+struct CounterSuperColumn {
+    1: required binary name,
+    2: required list<CounterColumn> columns
+}
+
+/**
+    Methods for fetching rows/records from Cassandra will return either a single instance of ColumnOrSuperColumn or a list
+    of ColumnOrSuperColumns (get_slice()). If you're looking up a SuperColumn (or list of SuperColumns) then the resulting
+    instances of ColumnOrSuperColumn will have the requested SuperColumn in the attribute super_column. For queries resulting
+    in Columns, those values will be in the attribute column. This change was made between 0.3 and 0.4 to standardize on
+    single query methods that may return either a SuperColumn or Column.
+
+    If the query was on a counter column family, you will either get a counter_column (instead of a column) or a 
+    counter_super_column (instead of a super_column)
+
+    @param column. The Column returned by get() or get_slice().
+    @param super_column. The SuperColumn returned by get() or get_slice().
+    @param counter_column. The Counterolumn returned by get() or get_slice().
+    @param counter_super_column. The CounterSuperColumn returned by get() or get_slice().
+ */
+struct ColumnOrSuperColumn {
+    1: optional Column column,
+    2: optional SuperColumn super_column,
+    3: optional CounterColumn counter_column,
+    4: optional CounterSuperColumn counter_super_column
+}
+
+
+#
+# Exceptions
+# (note that internal server errors will raise a TApplicationException, courtesy of Thrift)
+#
+
+/** A specific column was requested that does not exist. */
+exception NotFoundException {
+}
+
+/** Invalid request could mean keyspace or column family does not exist, required parameters are missing, or a parameter is malformed. 
+    why contains an associated error message.
+*/
+exception InvalidRequestException {
+    1: required string why
+}
+
+/** Not all the replicas required could be created and/or read. */
+exception UnavailableException {
+}
+
+/** RPC timeout was exceeded.  either a node failed mid-operation, or load was too high, or the requested op was too large. */
+exception TimedOutException {
+}
+
+/** invalid authentication request (invalid keyspace, user does not exist, or credentials invalid) */
+exception AuthenticationException {
+    1: required string why
+}
+
+/** invalid authorization request (user does not have access to keyspace) */
+exception AuthorizationException {
+    1: required string why
+}
+
+/** schemas are not in agreement across all nodes */
+exception SchemaDisagreementException {
+}
+
+
+#
+# service api
+#
+/** 
+ * The ConsistencyLevel is an enum that controls both read and write
+ * behavior based on the ReplicationFactor of the keyspace.  The
+ * different consistency levels have different meanings, depending on
+ * if you're doing a write or read operation. 
+ *
+ * If W + R > ReplicationFactor, where W is the number of nodes to
+ * block for on write, and R the number to block for on reads, you
+ * will have strongly consistent behavior; that is, readers will
+ * always see the most recent write. Of these, the most interesting is
+ * to do QUORUM reads and writes, which gives you consistency while
+ * still allowing availability in the face of node failures up to half
+ * of <ReplicationFactor>. Of course if latency is more important than
+ * consistency then you can use lower values for either or both.
+ * 
+ * Some ConsistencyLevels (ONE, TWO, THREE) refer to a specific number
+ * of replicas rather than a logical concept that adjusts
+ * automatically with the replication factor.  Of these, only ONE is
+ * commonly used; TWO and (even more rarely) THREE are only useful
+ * when you care more about guaranteeing a certain level of
+ * durability, than consistency.
+ * 
+ * Write consistency levels make the following guarantees before reporting success to the client:
+ *   ANY          Ensure that the write has been written once somewhere, including possibly being hinted in a non-target node.
+ *   ONE          Ensure that the write has been written to at least 1 node's commit log and memory table
+ *   TWO          Ensure that the write has been written to at least 2 node's commit log and memory table
+ *   THREE        Ensure that the write has been written to at least 3 node's commit log and memory table
+ *   QUORUM       Ensure that the write has been written to <ReplicationFactor> / 2 + 1 nodes
+ *   LOCAL_QUORUM Ensure that the write has been written to <ReplicationFactor> / 2 + 1 nodes, within the local datacenter (requires NetworkTopologyStrategy)
+ *   EACH_QUORUM  Ensure that the write has been written to <ReplicationFactor> / 2 + 1 nodes in each datacenter (requires NetworkTopologyStrategy)
+ *   ALL          Ensure that the write is written to <code>&lt;ReplicationFactor&gt;</code> nodes before responding to the client.
+ * 
+ * Read consistency levels make the following guarantees before returning successful results to the client:
+ *   ANY          Not supported. You probably want ONE instead.
+ *   ONE          Returns the record obtained from a single replica.
+ *   TWO          Returns the record with the most recent timestamp once two replicas have replied.
+ *   THREE        Returns the record with the most recent timestamp once three replicas have replied.
+ *   QUORUM       Returns the record with the most recent timestamp once a majority of replicas have replied.
+ *   LOCAL_QUORUM Returns the record with the most recent timestamp once a majority of replicas within the local datacenter have replied.
+ *   EACH_QUORUM  Returns the record with the most recent timestamp once a majority of replicas within each datacenter have replied.
+ *   ALL          Returns the record with the most recent timestamp once all replicas have replied (implies no replica may be down)..
+*/
+enum ConsistencyLevel {
+    ONE = 1,
+    QUORUM = 2,
+    LOCAL_QUORUM = 3,
+    EACH_QUORUM = 4,
+    ALL = 5,
+    ANY = 6,
+    TWO = 7,
+    THREE = 8,
+}
+
+/**
+    ColumnParent is used when selecting groups of columns from the same ColumnFamily. In directory structure terms, imagine
+    ColumnParent as ColumnPath + '/../'.
+
+    See also <a href="cassandra.html#Struct_ColumnPath">ColumnPath</a>
+ */
+struct ColumnParent {
+    3: required string column_family,
+    4: optional binary super_column,
+}
+
+/** The ColumnPath is the path to a single column in Cassandra. It might make sense to think of ColumnPath and
+ * ColumnParent in terms of a directory structure.
+ *
+ * ColumnPath is used to looking up a single column.
+ *
+ * @param column_family. The name of the CF of the column being looked up.
+ * @param super_column. The super column name.
+ * @param column. The column name.
+ */
+struct ColumnPath {
+    3: required string column_family,
+    4: optional binary super_column,
+    5: optional binary column,
+}
+
+/**
+    A slice range is a structure that stores basic range, ordering and limit information for a query that will return
+    multiple columns. It could be thought of as Cassandra's version of LIMIT and ORDER BY
+
+    @param start. The column name to start the slice with. This attribute is not required, though there is no default value,
+                  and can be safely set to '', i.e., an empty byte array, to start with the first column name. Otherwise, it
+                  must a valid value under the rules of the Comparator defined for the given ColumnFamily.
+    @param finish. The column name to stop the slice at. This attribute is not required, though there is no default value,
+                   and can be safely set to an empty byte array to not stop until 'count' results are seen. Otherwise, it
+                   must also be a valid value to the ColumnFamily Comparator.
+    @param reversed. Whether the results should be ordered in reversed order. Similar to ORDER BY blah DESC in SQL.
+    @param count. How many columns to return. Similar to LIMIT in SQL. May be arbitrarily large, but Thrift will
+                  materialize the whole result into memory before returning it to the client, so be aware that you may
+                  be better served by iterating through slices by passing the last value of one call in as the 'start'
+                  of the next instead of increasing 'count' arbitrarily large.
+ */
+struct SliceRange {
+    1: required binary start,
+    2: required binary finish,
+    3: required bool reversed=0,
+    4: required i32 count=100,
+}
+
+/**
+    A SlicePredicate is similar to a mathematic predicate (see http://en.wikipedia.org/wiki/Predicate_(mathematical_logic)),
+    which is described as "a property that the elements of a set have in common."
+
+    SlicePredicate's in Cassandra are described with either a list of column_names or a SliceRange.  If column_names is
+    specified, slice_range is ignored.
+
+    @param column_name. A list of column names to retrieve. This can be used similar to Memcached's "multi-get" feature
+                        to fetch N known column names. For instance, if you know you wish to fetch columns 'Joe', 'Jack',
+                        and 'Jim' you can pass those column names as a list to fetch all three at once.
+    @param slice_range. A SliceRange describing how to range, order, and/or limit the slice.
+ */
+struct SlicePredicate {
+    1: optional list<binary> column_names,
+    2: optional SliceRange   slice_range,
+}
+
+enum IndexOperator {
+    EQ,
+    GTE,
+    GT,
+    LTE,
+    LT
+}
+
+struct IndexExpression {
+    1: required binary column_name,
+    2: required IndexOperator op,
+    3: required binary value,
+}
+
+struct IndexClause {
+    1: required list<IndexExpression> expressions
+    2: required binary start_key,
+    3: required i32 count=100,
+}
+
+/**
+The semantics of start keys and tokens are slightly different.
+Keys are start-inclusive; tokens are start-exclusive.  Token
+ranges may also wrap -- that is, the end token may be less
+than the start one.  Thus, a range from keyX to keyX is a
+one-element range, but a range from tokenY to tokenY is the
+full ring.
+*/
+struct KeyRange {
+    1: optional binary start_key,
+    2: optional binary end_key,
+    3: optional string start_token,
+    4: optional string end_token,
+    5: required i32 count=100
+}
+
+/**
+    A KeySlice is key followed by the data it maps to. A collection of KeySlice is returned by the get_range_slice operation.
+
+    @param key. a row key
+    @param columns. List of data represented by the key. Typically, the list is pared down to only the columns specified by
+                    a SlicePredicate.
+ */
+struct KeySlice {
+    1: required binary key,
+    2: required list<ColumnOrSuperColumn> columns,
+}
+
+struct KeyCount {
+    1: required binary key,
+    2: required i32 count
+}
+
+/**
+ * Note that the timestamp is only optional in case of counter deletion.
+ */
+struct Deletion {
+    1: optional i64 timestamp,
+    2: optional binary super_column,
+    3: optional SlicePredicate predicate,
+}
+
+/**
+    A Mutation is either an insert (represented by filling column_or_supercolumn) or a deletion (represented by filling the deletion attribute).
+    @param column_or_supercolumn. An insert to a column or supercolumn (possibly counter column or supercolumn)
+    @param deletion. A deletion of a column or supercolumn
+*/
+struct Mutation {
+    1: optional ColumnOrSuperColumn column_or_supercolumn,
+    2: optional Deletion deletion,
+}
+
+struct EndpointDetails {
+    1: string host,
+    2: string datacenter,
+    3: optional string rack
+}
+
+/**
+    A TokenRange describes part of the Cassandra ring, it is a mapping from a range to
+    endpoints responsible for that range.
+    @param start_token The first token in the range
+    @param end_token The last token in the range
+    @param endpoints The endpoints responsible for the range (listed by their configured listen_address)
+    @param rpc_endpoints The endpoints responsible for the range (listed by their configured rpc_address)
+*/
+struct TokenRange {
+    1: required string start_token,
+    2: required string end_token,
+    3: required list<string> endpoints,
+    4: optional list<string> rpc_endpoints
+    5: optional list<EndpointDetails> endpoint_details,
+}
+
+/**
+    Authentication requests can contain any data, dependent on the IAuthenticator used
+*/
+struct AuthenticationRequest {
+    1: required map<string, string> credentials
+}
+
+enum IndexType {
+    KEYS,
+    CUSTOM
+}
+
+/* describes a column in a column family. */
+struct ColumnDef {
+    1: required binary name,
+    2: required string validation_class,
+    3: optional IndexType index_type,
+    4: optional string index_name,
+    5: optional map<string,string> index_options
+}
+
+
+/* describes a column family. */
+struct CfDef {
+    1: required string keyspace,
+    2: required string name,
+    3: optional string column_type="Standard",
+    5: optional string comparator_type="BytesType",
+    6: optional string subcomparator_type,
+    8: optional string comment,
+    12: optional double read_repair_chance=1.0,
+    13: optional list<ColumnDef> column_metadata,
+    14: optional i32 gc_grace_seconds,
+    15: optional string default_validation_class,
+    16: optional i32 id,
+    17: optional i32 min_compaction_threshold,
+    18: optional i32 max_compaction_threshold,
+    24: optional bool replicate_on_write,
+    25: optional double merge_shards_chance,
+    26: optional string key_validation_class,
+    28: optional binary key_alias,
+    29: optional string compaction_strategy,
+    30: optional map<string,string> compaction_strategy_options,
+    32: optional map<string,string> compression_options,
+    33: optional double bloom_filter_fp_chance,
+}
+
+/* describes a keyspace. */
+struct KsDef {
+    1: required string name,
+    2: required string strategy_class,
+    3: optional map<string,string> strategy_options,
+
+    /** @deprecated */
+    4: optional i32 replication_factor, 
+
+    5: required list<CfDef> cf_defs,
+    6: optional bool durable_writes=1,
+}
+
+/** CQL query compression */
+enum Compression {
+    GZIP = 1,
+    NONE = 2
+}
+
+enum CqlResultType {
+    ROWS = 1,
+    VOID = 2,
+    INT = 3
+}
+
+/** Row returned from a CQL query */
+struct CqlRow {
+    1: required binary key,
+    2: required list<Column> columns
+}
+
+struct CqlMetadata {
+    1: required map<binary,string> name_types,
+    2: required map<binary,string> value_types,
+    3: required string default_name_type,
+    4: required string default_value_type
+}
+
+struct CqlResult {
+    1: required CqlResultType type,
+    2: optional list<CqlRow> rows,
+    3: optional i32 num,
+    4: optional CqlMetadata schema
+}
+
+struct CqlPreparedResult {
+    1: required i32 itemId,
+    2: required i32 count
+}
+
+
+service Cassandra {
+  # auth methods
+  void login(1: required AuthenticationRequest auth_request) throws (1:AuthenticationException authnx, 2:AuthorizationException authzx),
+ 
+  # set keyspace
+  void set_keyspace(1: required string keyspace) throws (1:InvalidRequestException ire),
+  
+  # retrieval methods
+
+  /**
+    Get the Column or SuperColumn at the given column_path. If no value is present, NotFoundException is thrown. (This is
+    the only method that can throw an exception under non-failure conditions.)
+   */
+  ColumnOrSuperColumn get(1:required binary key,
+                          2:required ColumnPath column_path,
+                          3:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
+                      throws (1:InvalidRequestException ire, 2:NotFoundException nfe, 3:UnavailableException ue, 4:TimedOutException te),
+
+  /**
+    Get the group of columns contained by column_parent (either a ColumnFamily name or a ColumnFamily/SuperColumn name
+    pair) specified by the given SlicePredicate. If no matching values are found, an empty list is returned.
+   */
+  list<ColumnOrSuperColumn> get_slice(1:required binary key, 
+                                      2:required ColumnParent column_parent, 
+                                      3:required SlicePredicate predicate, 
+                                      4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
+                            throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
+
+  /**
+    returns the number of columns matching <code>predicate</code> for a particular <code>key</code>, 
+    <code>ColumnFamily</code> and optionally <code>SuperColumn</code>.
+  */
+  i32 get_count(1:required binary key, 
+                2:required ColumnParent column_parent, 
+                3:required SlicePredicate predicate,
+                4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
+      throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
+
+  /**
+    Performs a get_slice for column_parent and predicate for the given keys in parallel.
+  */
+  map<binary,list<ColumnOrSuperColumn>> multiget_slice(1:required list<binary> keys, 
+                                                       2:required ColumnParent column_parent, 
+                                                       3:required SlicePredicate predicate, 
+                                                       4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
+                                        throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
+
+  /**
+    Perform a get_count in parallel on the given list<binary> keys. The return value maps keys to the count found.
+  */
+  map<binary, i32> multiget_count(1:required list<binary> keys,
+                2:required ColumnParent column_parent,
+                3:required SlicePredicate predicate,
+                4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
+      throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
+
+  /**
+   returns a subset of columns for a contiguous range of keys.
+  */
+  list<KeySlice> get_range_slices(1:required ColumnParent column_parent, 
+                                  2:required SlicePredicate predicate,
+                                  3:required KeyRange range,
+                                  4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
+                 throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
+
+  /** Returns the subset of columns specified in SlicePredicate for the rows matching the IndexClause */
+  list<KeySlice> get_indexed_slices(1:required ColumnParent column_parent,
+                                    2:required IndexClause index_clause,
+                                    3:required SlicePredicate column_predicate,
+                                    4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
+                 throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
+
+  # modification methods
+
+  /**
+   * Insert a Column at the given column_parent.column_family and optional column_parent.super_column.
+   */
+  void insert(1:required binary key, 
+              2:required ColumnParent column_parent,
+              3:required Column column,
+              4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
+       throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
+
+  /**
+   * Increment or decrement a counter.
+   */
+  void add(1:required binary key,
+           2:required ColumnParent column_parent,
+           3:required CounterColumn column,
+           4:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
+       throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
+
+  /**
+    Remove data from the row specified by key at the granularity specified by column_path, and the given timestamp. Note
+    that all the values in column_path besides column_path.column_family are truly optional: you can remove the entire
+    row by just specifying the ColumnFamily, or you can remove a SuperColumn or a single Column by specifying those levels too.
+   */
+  void remove(1:required binary key,
+              2:required ColumnPath column_path,
+              3:required i64 timestamp,
+              4:ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
+       throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
+
+  /**
+   * Remove a counter at the specified location.
+   * Note that counters have limited support for deletes: if you remove a counter, you must wait to issue any following update
+   * until the delete has reached all the nodes and all of them have been fully compacted.
+   */
+  void remove_counter(1:required binary key,
+                      2:required ColumnPath path,
+                      3:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
+      throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
+
+
+  /**
+    Mutate many columns or super columns for many row keys. See also: Mutation.
+
+    mutation_map maps key to column family to a list of Mutation objects to take place at that scope.
+  **/
+  void batch_mutate(1:required map<binary, map<string, list<Mutation>>> mutation_map,
+                    2:required ConsistencyLevel consistency_level=ConsistencyLevel.ONE)
+       throws (1:InvalidRequestException ire, 2:UnavailableException ue, 3:TimedOutException te),
+       
+  /**
+   Truncate will mark and entire column family as deleted.
+   From the user's perspective a successful call to truncate will result complete data deletion from cfname.
+   Internally, however, disk space will not be immediatily released, as with all deletes in cassandra, this one
+   only marks the data as deleted.
+   The operation succeeds only if all hosts in the cluster at available and will throw an UnavailableException if 
+   some hosts are down.
+  */
+  void truncate(1:required string cfname)
+       throws (1: InvalidRequestException ire, 2: UnavailableException ue, 3: TimedOutException te),
+
+
+    
+  // Meta-APIs -- APIs to get information about the node or cluster,
+  // rather than user data.  The nodeprobe program provides usage examples.
+  
+  /** 
+   * for each schema version present in the cluster, returns a list of nodes at that version.
+   * hosts that do not respond will be under the key DatabaseDescriptor.INITIAL_VERSION. 
+   * the cluster is all on the same version if the size of the map is 1. 
+   */
+  map<string, list<string>> describe_schema_versions()
+       throws (1: InvalidRequestException ire),
+
+  /** list the defined keyspaces in this cluster */
+  list<KsDef> describe_keyspaces()
+    throws (1:InvalidRequestException ire),
+
+  /** get the cluster name */
+  string describe_cluster_name(),
+
+  /** get the thrift api version */
+  string describe_version(),
+
+  /** get the token ring: a map of ranges to host addresses,
+      represented as a set of TokenRange instead of a map from range
+      to list of endpoints, because you can't use Thrift structs as
+      map keys:
+      https://issues.apache.org/jira/browse/THRIFT-162 
+
+      for the same reason, we can't return a set here, even though
+      order is neither important nor predictable. */
+  list<TokenRange> describe_ring(1:required string keyspace)
+                   throws (1:InvalidRequestException ire),
+
+  /** returns the partitioner used by this cluster */
+  string describe_partitioner(),
+
+  /** returns the snitch used by this cluster */
+  string describe_snitch(),
+
+  /** describe specified keyspace */
+  KsDef describe_keyspace(1:required string keyspace)
+    throws (1:NotFoundException nfe, 2:InvalidRequestException ire),
+
+  /** experimental API for hadoop/parallel query support.  
+      may change violently and without warning. 
+
+      returns list of token strings such that first subrange is (list[0], list[1]],
+      next is (list[1], list[2]], etc. */
+  list<string> describe_splits(1:required string cfName,
+                               2:required string start_token, 
+                               3:required string end_token,
+                               4:required i32 keys_per_split)
+    throws (1:InvalidRequestException ire),
+
+  /** adds a column family. returns the new schema id. */
+  string system_add_column_family(1:required CfDef cf_def)
+    throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde),
+    
+  /** drops a column family. returns the new schema id. */
+  string system_drop_column_family(1:required string column_family)
+    throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde), 
+  
+  /** adds a keyspace and any column families that are part of it. returns the new schema id. */
+  string system_add_keyspace(1:required KsDef ks_def)
+    throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde),
+  
+  /** drops a keyspace and any column families that are part of it. returns the new schema id. */
+  string system_drop_keyspace(1:required string keyspace)
+    throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde),
+  
+  /** updates properties of a keyspace. returns the new schema id. */
+  string system_update_keyspace(1:required KsDef ks_def)
+    throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde),
+        
+  /** updates properties of a column family. returns the new schema id. */
+  string system_update_column_family(1:required CfDef cf_def)
+    throws (1:InvalidRequestException ire, 2:SchemaDisagreementException sde),
+  
+  /**
+   * Executes a CQL (Cassandra Query Language) statement and returns a
+   * CqlResult containing the results.
+   */
+  CqlResult execute_cql_query(1:required binary query, 2:required Compression compression)
+    throws (1:InvalidRequestException ire,
+            2:UnavailableException ue,
+            3:TimedOutException te,
+            4:SchemaDisagreementException sde)
+            
+            
+  /**
+   * Prepare a CQL (Cassandra Query Language) statement by compiling and returning
+   * - the type of CQL statement
+   * - an id token of the compiled CQL stored on the server side.
+   * - a count of the discovered bound markers in the statement 
+   */
+  CqlPreparedResult prepare_cql_query(1:required binary query, 2:required Compression compression)
+    throws (1:InvalidRequestException ire)
+
+             
+  /**
+   * Executes a prepared CQL (Cassandra Query Language) statement by passing an id token and  a list of variables
+   * to bind and returns a CqlResult containing the results.
+   */
+  CqlResult execute_prepared_cql_query(1:required i32 itemId, 2:required list<string> values)
+    throws (1:InvalidRequestException ire,
+            2:UnavailableException ue,
+            3:TimedOutException te,
+            4:SchemaDisagreementException sde)
+           
+
+}
diff --git a/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Properties/AssemblyInfo.cs b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0bb460f
--- /dev/null
+++ b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+
+[assembly: Guid("d0d3706b-fed5-4cf5-b984-04f448de9d7b")]
\ No newline at end of file
diff --git a/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj
new file mode 100644
index 0000000..c4a84a3
--- /dev/null
+++ b/lib/netcore/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj
@@ -0,0 +1,36 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.0</TargetFramework>
+    <AssemblyName>Thrift.PublicInterfaces.Compile.Tests</AssemblyName>
+    <PackageId>Thrift.PublicInterfaces.Compile.Tests</PackageId>
+    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
+    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
+    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
+    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="../../Thrift/Thrift.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="System.ServiceModel.Primitives" Version="[4.1.0,)" />
+  </ItemGroup>
+
+  <Target Name="PreBuild" BeforeTargets="_GenerateRestoreProjectSpec;Restore;Compile">
+    <Exec Condition="'$(OS)' == 'Windows_NT'" Command="where thrift" ConsoleToMSBuild="true">
+      <Output TaskParameter="ConsoleOutput" PropertyName="PathToThrift" />
+    </Exec>
+    <Exec Condition="Exists('$(PathToThrift)')" Command="$(PathToThrift) -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./CassandraTest.thrift" />
+    <Exec Condition="Exists('thrift')" Command="thrift -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./CassandraTest.thrift" />
+    <Exec Condition="Exists('$(ProjectDir)/../../../compiler/cpp/thrift')" Command="$(ProjectDir)/../../../compiler/cpp/thrift -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./CassandraTest.thrift" />
+    <Exec Condition="Exists('$(PathToThrift)')" Command="$(PathToThrift) -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../../../test/ThriftTest.thrift" />
+    <Exec Condition="Exists('thrift')" Command="thrift -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../../../test/ThriftTest.thrift" />
+    <Exec Condition="Exists('$(ProjectDir)/../../../compiler/cpp/thrift')" Command="$(ProjectDir)/../../../compiler/cpp/thrift -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../../../test/ThriftTest.thrift" />
+    <Exec Condition="Exists('$(PathToThrift)')" Command="$(PathToThrift) -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../../../contrib/fb303/if/fb303.thrift" />
+    <Exec Condition="Exists('thrift')" Command="thrift -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../../../contrib/fb303/if/fb303.thrift" />
+    <Exec Condition="Exists('$(ProjectDir)/../../../compiler/cpp/thrift')" Command="$(ProjectDir)/../../../compiler/cpp/thrift -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../../../contrib/fb303/if/fb303.thrift" />
+  </Target>
+
+</Project>
diff --git a/lib/netcore/Tests/Thrift.Tests/Collections/TCollectionsTests.cs b/lib/netcore/Tests/Thrift.Tests/Collections/TCollectionsTests.cs
new file mode 100644
index 0000000..1be99b4
--- /dev/null
+++ b/lib/netcore/Tests/Thrift.Tests/Collections/TCollectionsTests.cs
@@ -0,0 +1,83 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Thrift.Collections;
+
+namespace Thrift.Tests.Collections
+{
+    // ReSharper disable once InconsistentNaming
+    [TestClass]
+    public class TCollectionsTests
+    {
+        //TODO: Add tests for IEnumerable with objects and primitive values inside
+
+        [TestMethod]
+        public void TCollection_Equals_Primitive_Test()
+        {
+            var collection1 = new List<int> {1,2,3};
+            var collection2 = new List<int> {1,2,3};
+
+            var result = TCollections.Equals(collection1, collection2);
+
+            Assert.IsTrue(result);
+        }
+
+        [TestMethod]
+        public void TCollection_Equals_Primitive_Different_Test()
+        {
+            var collection1 = new List<int> { 1, 2, 3 };
+            var collection2 = new List<int> { 1, 2 };
+
+            var result = TCollections.Equals(collection1, collection2);
+
+            Assert.IsFalse(result);
+        }
+
+        [TestMethod]
+        public void TCollection_Equals_Objects_Test()
+        {
+            var collection1 = new List<ExampleClass> { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } };
+            var collection2 = new List<ExampleClass> { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } };
+
+            var result = TCollections.Equals(collection1, collection2);
+
+            // references to different collections
+            Assert.IsFalse(result);
+        }
+
+        [TestMethod]
+        public void TCollection_Equals_OneAndTheSameObject_Test()
+        {
+            var collection1 = new List<ExampleClass> { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } };
+            var collection2 = collection1;
+
+            var result = TCollections.Equals(collection1, collection2);
+
+            // references to one and the same collection
+            Assert.IsTrue(result);
+        }
+
+        private class ExampleClass
+        {
+            public int X { get; set; }
+        }
+    }
+}
diff --git a/lib/netcore/Tests/Thrift.Tests/Collections/THashSetTests.cs b/lib/netcore/Tests/Thrift.Tests/Collections/THashSetTests.cs
new file mode 100644
index 0000000..8de573e
--- /dev/null
+++ b/lib/netcore/Tests/Thrift.Tests/Collections/THashSetTests.cs
@@ -0,0 +1,71 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Thrift.Collections;
+
+namespace Thrift.Tests.Collections
+{
+    // ReSharper disable once InconsistentNaming
+    [TestClass]
+    public class THashSetTests
+    {
+        [TestMethod]
+        public void THashSet_Equals_Primitive_Test()
+        {
+            const int value = 1;
+
+            var hashSet = new THashSet<int> {value};
+            
+            Assert.IsTrue(hashSet.Contains(value));
+
+            hashSet.Remove(value);
+
+            Assert.IsTrue(hashSet.Count == 0);
+
+            hashSet.Add(value);
+
+            Assert.IsTrue(hashSet.Contains(value));
+
+            hashSet.Clear();
+
+            Assert.IsTrue(hashSet.Count == 0);
+
+            var newArr = new int[1];
+            hashSet.Add(value);
+            hashSet.CopyTo(newArr, 0);
+
+            Assert.IsTrue(newArr.Contains(value));
+
+            var en = hashSet.GetEnumerator();
+            en.MoveNext();
+
+            Assert.IsTrue((int)en.Current == value);
+            
+            using (var ien = ((IEnumerable<int>)hashSet).GetEnumerator())
+            {
+                ien.MoveNext();
+
+                Assert.IsTrue(ien.Current == value);
+            }
+        }
+    }
+}
diff --git a/lib/netcore/Tests/Thrift.Tests/Protocols/TJsonProtocolHelperTests.cs b/lib/netcore/Tests/Thrift.Tests/Protocols/TJsonProtocolHelperTests.cs
new file mode 100644
index 0000000..cdc8317
--- /dev/null
+++ b/lib/netcore/Tests/Thrift.Tests/Protocols/TJsonProtocolHelperTests.cs
@@ -0,0 +1,172 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Thrift.Protocols;
+using Thrift.Protocols.Entities;
+using Thrift.Protocols.Utilities;
+
+namespace Thrift.Tests.Protocols
+{
+    [TestClass]
+    public class TJSONProtocolHelperTests
+    {
+        [TestMethod]
+        public void GetTypeNameForTypeId_Test()
+        {
+            // input/output
+            var sets = new List<Tuple<TType, byte[]>>
+            {
+                new Tuple<TType, byte[]>(TType.Bool, TJSONProtocolConstants.TypeNames.NameBool),
+                new Tuple<TType, byte[]>(TType.Byte, TJSONProtocolConstants.TypeNames.NameByte),
+                new Tuple<TType, byte[]>(TType.I16, TJSONProtocolConstants.TypeNames.NameI16),
+                new Tuple<TType, byte[]>(TType.I32, TJSONProtocolConstants.TypeNames.NameI32),
+                new Tuple<TType, byte[]>(TType.I64, TJSONProtocolConstants.TypeNames.NameI64),
+                new Tuple<TType, byte[]>(TType.Double, TJSONProtocolConstants.TypeNames.NameDouble),
+                new Tuple<TType, byte[]>(TType.String, TJSONProtocolConstants.TypeNames.NameString),
+                new Tuple<TType, byte[]>(TType.Struct, TJSONProtocolConstants.TypeNames.NameStruct),
+                new Tuple<TType, byte[]>(TType.Map, TJSONProtocolConstants.TypeNames.NameMap),
+                new Tuple<TType, byte[]>(TType.Set, TJSONProtocolConstants.TypeNames.NameSet),
+                new Tuple<TType, byte[]>(TType.List, TJSONProtocolConstants.TypeNames.NameList),
+            };
+
+            foreach (var t in sets)
+            {
+                Assert.IsTrue(TJSONProtocolHelper.GetTypeNameForTypeId(t.Item1) == t.Item2, $"Wrong mapping of TypeName {t.Item2} to TType: {t.Item1}");
+            }
+        }
+
+        [TestMethod]
+        [ExpectedException(typeof(TProtocolException))]
+        public void GetTypeNameForTypeId_TStop_Test()
+        {
+            TJSONProtocolHelper.GetTypeNameForTypeId(TType.Stop);
+        }
+
+        [TestMethod]
+        [ExpectedException(typeof(TProtocolException))]
+        public void GetTypeNameForTypeId_NonExistingTType_Test()
+        {
+            TJSONProtocolHelper.GetTypeNameForTypeId((TType)100);
+        }
+
+        [TestMethod]
+        public void GetTypeIdForTypeName_Test()
+        {
+            // input/output
+            var sets = new List<Tuple<TType, byte[]>>
+            {
+                new Tuple<TType, byte[]>(TType.Bool, TJSONProtocolConstants.TypeNames.NameBool),
+                new Tuple<TType, byte[]>(TType.Byte, TJSONProtocolConstants.TypeNames.NameByte),
+                new Tuple<TType, byte[]>(TType.I16, TJSONProtocolConstants.TypeNames.NameI16),
+                new Tuple<TType, byte[]>(TType.I32, TJSONProtocolConstants.TypeNames.NameI32),
+                new Tuple<TType, byte[]>(TType.I64, TJSONProtocolConstants.TypeNames.NameI64),
+                new Tuple<TType, byte[]>(TType.Double, TJSONProtocolConstants.TypeNames.NameDouble),
+                new Tuple<TType, byte[]>(TType.String, TJSONProtocolConstants.TypeNames.NameString),
+                new Tuple<TType, byte[]>(TType.Struct, TJSONProtocolConstants.TypeNames.NameStruct),
+                new Tuple<TType, byte[]>(TType.Map, TJSONProtocolConstants.TypeNames.NameMap),
+                new Tuple<TType, byte[]>(TType.Set, TJSONProtocolConstants.TypeNames.NameSet),
+                new Tuple<TType, byte[]>(TType.List, TJSONProtocolConstants.TypeNames.NameList),
+            };
+
+            foreach (var t in sets)
+            {
+                Assert.IsTrue(TJSONProtocolHelper.GetTypeIdForTypeName(t.Item2) == t.Item1, $"Wrong mapping of TypeName {t.Item2} to TType: {t.Item1}");
+            }
+        }
+
+        [TestMethod]
+        [ExpectedException(typeof(TProtocolException))]
+        public void GetTypeIdForTypeName_TStopTypeName_Test()
+        {
+            TJSONProtocolHelper.GetTypeIdForTypeName(new []{(byte)TType.Stop, (byte)TType.Stop});
+        }
+
+        [TestMethod]
+        [ExpectedException(typeof(TProtocolException))]
+        public void GetTypeIdForTypeName_NonExistingTypeName_Test()
+        {
+            TJSONProtocolHelper.GetTypeIdForTypeName(new byte[]{100});
+        }
+
+        [TestMethod]
+        [ExpectedException(typeof(TProtocolException))]
+        public void GetTypeIdForTypeName_EmptyName_Test()
+        {
+            TJSONProtocolHelper.GetTypeIdForTypeName(new byte[] {});
+        }
+
+        [TestMethod]
+        public void IsJsonNumeric_Test()
+        {
+            // input/output
+            var correctJsonNumeric = "+-.0123456789Ee";
+            var incorrectJsonNumeric = "AaBcDd/*\\";
+
+            var sets = correctJsonNumeric.Select(ch => new Tuple<byte, bool>((byte) ch, true)).ToList();
+            sets.AddRange(incorrectJsonNumeric.Select(ch => new Tuple<byte, bool>((byte) ch, false)));
+
+            foreach (var t in sets)
+            {
+                Assert.IsTrue(TJSONProtocolHelper.IsJsonNumeric(t.Item1) == t.Item2, $"Wrong mapping of Char {t.Item1} to bool: {t.Item2}");
+            }
+        }
+
+        [TestMethod]
+        public void ToHexVal_Test()
+        {
+            // input/output
+            var chars = "0123456789abcdef";
+            var expectedHexValues = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+
+            var sets = chars.Select((ch, i) => new Tuple<char, byte>(ch, expectedHexValues[i])).ToList();
+
+            foreach (var t in sets)
+            {
+                var actualResult = TJSONProtocolHelper.ToHexVal((byte)t.Item1);
+                Assert.IsTrue(actualResult == t.Item2, $"Wrong mapping of char byte {t.Item1} to it expected hex value: {t.Item2}. Actual hex value: {actualResult}");
+            }
+        }
+
+        [TestMethod]
+        [ExpectedException(typeof(TProtocolException))]
+        public void ToHexVal_WrongInputChar_Test()
+        {
+            TJSONProtocolHelper.ToHexVal((byte)'s');
+        }
+
+        [TestMethod]
+        public void ToHexChar_Test()
+        {
+            // input/output
+            var hexValues = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+            var expectedChars = "0123456789abcdef";
+            
+
+            var sets = hexValues.Select((hv, i) => new Tuple<byte, char>(hv, expectedChars[i])).ToList();
+
+            foreach (var t in sets)
+            {
+                var actualResult = TJSONProtocolHelper.ToHexChar(t.Item1);
+                Assert.IsTrue(actualResult == t.Item2, $"Wrong mapping of hex value {t.Item1} to it expected char: {t.Item2}. Actual hex value: {actualResult}");
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Tests/Thrift.Tests/Protocols/TJsonProtocolTests.cs b/lib/netcore/Tests/Thrift.Tests/Protocols/TJsonProtocolTests.cs
new file mode 100644
index 0000000..5237360
--- /dev/null
+++ b/lib/netcore/Tests/Thrift.Tests/Protocols/TJsonProtocolTests.cs
@@ -0,0 +1,67 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using NSubstitute;
+using Thrift.Protocols;
+using Thrift.Protocols.Entities;
+using Thrift.Transports;
+using Thrift.Transports.Client;
+
+namespace Thrift.Tests.Protocols
+{
+    // ReSharper disable once InconsistentNaming
+    [TestClass]
+    public class TJSONProtocolTests
+    {
+        [TestMethod]
+        public void TJSONProtocol_Can_Create_Instance_Test()
+        {
+            var httpClientTransport = Substitute.For<THttpClientTransport>(new Uri("http://localhost"), null);
+
+            var result = new TJSONProtocolWrapper(httpClientTransport);
+
+            Assert.IsNotNull(result);
+            Assert.IsNotNull(result.WrappedContext);
+            Assert.IsNotNull(result.WrappedReader);
+            Assert.IsNotNull(result.Transport);
+            Assert.IsTrue(result.WrappedRecursionDepth == 0);
+            Assert.IsTrue(result.WrappedRecursionLimit == TProtocol.DefaultRecursionDepth);
+
+            Assert.IsTrue(result.Transport.Equals(httpClientTransport));
+            Assert.IsTrue(result.WrappedContext.GetType().Name.Equals("JSONBaseContext", StringComparison.OrdinalIgnoreCase));
+            Assert.IsTrue(result.WrappedReader.GetType().Name.Equals("LookaheadReader", StringComparison.OrdinalIgnoreCase));
+        }
+
+        private class TJSONProtocolWrapper : TJsonProtocol
+        {
+            public TJSONProtocolWrapper(TClientTransport trans) : base(trans)
+            {
+            }
+
+            public object WrappedContext => Context;
+            public object WrappedReader => Reader;
+            public int WrappedRecursionDepth => RecursionDepth;
+            public int WrappedRecursionLimit => RecursionLimit;
+        }
+    }
+}
diff --git a/lib/netcore/Tests/Thrift.Tests/Thrift.Tests.csproj b/lib/netcore/Tests/Thrift.Tests/Thrift.Tests.csproj
new file mode 100644
index 0000000..e46f165
--- /dev/null
+++ b/lib/netcore/Tests/Thrift.Tests/Thrift.Tests.csproj
@@ -0,0 +1,18 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.0</TargetFramework>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="CompareNETObjects" Version="4.3.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
+    <PackageReference Include="MSTest.TestAdapter" Version="1.2.0" />
+    <PackageReference Include="MSTest.TestFramework" Version="1.2.0" />
+    <PackageReference Include="NSubstitute" Version="3.1.0" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\Thrift\Thrift.csproj" />
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/lib/netcore/Thrift.sln b/lib/netcore/Thrift.sln
new file mode 100644
index 0000000..fe30aa5
--- /dev/null
+++ b/lib/netcore/Thrift.sln
@@ -0,0 +1,85 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26730.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{F51FC4DA-CAC0-48B1-A069-B1712BCAA5BE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift", "Thrift\Thrift.csproj", "{D85F572F-7D80-40A4-9A9B-2731ED187C24}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.IntegrationTests", "Tests\Thrift.IntegrationTests\Thrift.IntegrationTests.csproj", "{9F9A11BF-3C95-4E80-AFBF-768541996844}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.Tests", "Tests\Thrift.Tests\Thrift.Tests.csproj", "{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift.PublicInterfaces.Compile.Tests", "Tests\Thrift.PublicInterfaces.Compile.Tests\Thrift.PublicInterfaces.Compile.Tests.csproj", "{A429F05B-F511-45EF-AE7B-04E1AE9C9367}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{D85F572F-7D80-40A4-9A9B-2731ED187C24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D85F572F-7D80-40A4-9A9B-2731ED187C24}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D85F572F-7D80-40A4-9A9B-2731ED187C24}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{D85F572F-7D80-40A4-9A9B-2731ED187C24}.Debug|x64.Build.0 = Debug|Any CPU
+		{D85F572F-7D80-40A4-9A9B-2731ED187C24}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{D85F572F-7D80-40A4-9A9B-2731ED187C24}.Debug|x86.Build.0 = Debug|Any CPU
+		{D85F572F-7D80-40A4-9A9B-2731ED187C24}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D85F572F-7D80-40A4-9A9B-2731ED187C24}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D85F572F-7D80-40A4-9A9B-2731ED187C24}.Release|x64.ActiveCfg = Release|Any CPU
+		{D85F572F-7D80-40A4-9A9B-2731ED187C24}.Release|x64.Build.0 = Release|Any CPU
+		{D85F572F-7D80-40A4-9A9B-2731ED187C24}.Release|x86.ActiveCfg = Release|Any CPU
+		{D85F572F-7D80-40A4-9A9B-2731ED187C24}.Release|x86.Build.0 = Release|Any CPU
+		{9F9A11BF-3C95-4E80-AFBF-768541996844}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9F9A11BF-3C95-4E80-AFBF-768541996844}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9F9A11BF-3C95-4E80-AFBF-768541996844}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{9F9A11BF-3C95-4E80-AFBF-768541996844}.Debug|x64.Build.0 = Debug|Any CPU
+		{9F9A11BF-3C95-4E80-AFBF-768541996844}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{9F9A11BF-3C95-4E80-AFBF-768541996844}.Debug|x86.Build.0 = Debug|Any CPU
+		{9F9A11BF-3C95-4E80-AFBF-768541996844}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9F9A11BF-3C95-4E80-AFBF-768541996844}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9F9A11BF-3C95-4E80-AFBF-768541996844}.Release|x64.ActiveCfg = Release|Any CPU
+		{9F9A11BF-3C95-4E80-AFBF-768541996844}.Release|x64.Build.0 = Release|Any CPU
+		{9F9A11BF-3C95-4E80-AFBF-768541996844}.Release|x86.ActiveCfg = Release|Any CPU
+		{9F9A11BF-3C95-4E80-AFBF-768541996844}.Release|x86.Build.0 = Release|Any CPU
+		{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1}.Debug|x64.Build.0 = Debug|Any CPU
+		{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1}.Debug|x86.Build.0 = Debug|Any CPU
+		{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1}.Release|x64.ActiveCfg = Release|Any CPU
+		{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1}.Release|x64.Build.0 = Release|Any CPU
+		{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1}.Release|x86.ActiveCfg = Release|Any CPU
+		{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1}.Release|x86.Build.0 = Release|Any CPU
+		{A429F05B-F511-45EF-AE7B-04E1AE9C9367}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A429F05B-F511-45EF-AE7B-04E1AE9C9367}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A429F05B-F511-45EF-AE7B-04E1AE9C9367}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{A429F05B-F511-45EF-AE7B-04E1AE9C9367}.Debug|x64.Build.0 = Debug|Any CPU
+		{A429F05B-F511-45EF-AE7B-04E1AE9C9367}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{A429F05B-F511-45EF-AE7B-04E1AE9C9367}.Debug|x86.Build.0 = Debug|Any CPU
+		{A429F05B-F511-45EF-AE7B-04E1AE9C9367}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A429F05B-F511-45EF-AE7B-04E1AE9C9367}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A429F05B-F511-45EF-AE7B-04E1AE9C9367}.Release|x64.ActiveCfg = Release|Any CPU
+		{A429F05B-F511-45EF-AE7B-04E1AE9C9367}.Release|x64.Build.0 = Release|Any CPU
+		{A429F05B-F511-45EF-AE7B-04E1AE9C9367}.Release|x86.ActiveCfg = Release|Any CPU
+		{A429F05B-F511-45EF-AE7B-04E1AE9C9367}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{9F9A11BF-3C95-4E80-AFBF-768541996844} = {F51FC4DA-CAC0-48B1-A069-B1712BCAA5BE}
+		{75C2F9DC-3546-4D0A-A2DF-31C93516B6C1} = {F51FC4DA-CAC0-48B1-A069-B1712BCAA5BE}
+		{A429F05B-F511-45EF-AE7B-04E1AE9C9367} = {F51FC4DA-CAC0-48B1-A069-B1712BCAA5BE}
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {FD20BC4A-0109-41D8-8C0C-893E784D7EF9}
+	EndGlobalSection
+EndGlobal
diff --git a/lib/netcore/Thrift/Collections/TCollections.cs b/lib/netcore/Thrift/Collections/TCollections.cs
new file mode 100644
index 0000000..147bfc7
--- /dev/null
+++ b/lib/netcore/Thrift/Collections/TCollections.cs
@@ -0,0 +1,101 @@
+// 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.
+
+using System.Collections;
+
+namespace Thrift.Collections
+{
+    // ReSharper disable once InconsistentNaming
+    public class TCollections
+    {
+        /// <summary>
+        ///     This will return true if the two collections are value-wise the same.
+        ///     If the collection contains a collection, the collections will be compared using this method.
+        /// </summary>
+        public static bool Equals(IEnumerable first, IEnumerable second)
+        {
+            if (first == null && second == null)
+            {
+                return true;
+            }
+
+            if (first == null || second == null)
+            {
+                return false;
+            }
+
+            var fiter = first.GetEnumerator();
+            var siter = second.GetEnumerator();
+
+            var fnext = fiter.MoveNext();
+            var snext = siter.MoveNext();
+
+            while (fnext && snext)
+            {
+                var fenum = fiter.Current as IEnumerable;
+                var senum = siter.Current as IEnumerable;
+
+                if (fenum != null && senum != null)
+                {
+                    if (!Equals(fenum, senum))
+                    {
+                        return false;
+                    }
+                }
+                else if (fenum == null ^ senum == null)
+                {
+                    return false;
+                }
+                else if (!Equals(fiter.Current, siter.Current))
+                {
+                    return false;
+                }
+
+                fnext = fiter.MoveNext();
+                snext = siter.MoveNext();
+            }
+
+            return fnext == snext;
+        }
+
+        /// <summary>
+        ///     This returns a hashcode based on the value of the enumerable.
+        /// </summary>
+        public static int GetHashCode(IEnumerable enumerable)
+        {
+            if (enumerable == null)
+            {
+                return 0;
+            }
+
+            var hashcode = 0;
+
+            foreach (var obj in enumerable)
+            {
+                var enum2 = obj as IEnumerable;
+                var objHash = enum2 == null ? obj.GetHashCode() : GetHashCode(enum2);
+
+                unchecked
+                {
+                    hashcode = (hashcode*397) ^ (objHash);
+                }
+            }
+
+            return hashcode;
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Collections/THashSet.cs b/lib/netcore/Thrift/Collections/THashSet.cs
new file mode 100644
index 0000000..011f0a0
--- /dev/null
+++ b/lib/netcore/Thrift/Collections/THashSet.cs
@@ -0,0 +1,67 @@
+// 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.
+
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Thrift.Collections
+{
+    // ReSharper disable once InconsistentNaming
+    public class THashSet<T> : ICollection<T>
+    {
+        private readonly HashSet<T> _set = new HashSet<T>();
+
+        public int Count => _set.Count;
+
+        public bool IsReadOnly => false;
+
+        public void Add(T item)
+        {
+            _set.Add(item);
+        }
+
+        public void Clear()
+        {
+            _set.Clear();
+        }
+
+        public bool Contains(T item)
+        {
+            return _set.Contains(item);
+        }
+
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            _set.CopyTo(array, arrayIndex);
+        }
+
+        public IEnumerator GetEnumerator()
+        {
+            return _set.GetEnumerator();
+        }
+
+        IEnumerator<T> IEnumerable<T>.GetEnumerator()
+        {
+            return ((IEnumerable<T>) _set).GetEnumerator();
+        }
+
+        public bool Remove(T item)
+        {
+            return _set.Remove(item);
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/ITAsyncProcessor.cs b/lib/netcore/Thrift/ITAsyncProcessor.cs
new file mode 100644
index 0000000..db8e40a
--- /dev/null
+++ b/lib/netcore/Thrift/ITAsyncProcessor.cs
@@ -0,0 +1,29 @@
+// 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.
+
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols;
+
+namespace Thrift
+{
+    public interface ITAsyncProcessor
+    {
+        Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot);
+        Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken);
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/ITProcessorFactory.cs b/lib/netcore/Thrift/ITProcessorFactory.cs
new file mode 100644
index 0000000..5133e5c
--- /dev/null
+++ b/lib/netcore/Thrift/ITProcessorFactory.cs
@@ -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.
+
+using Thrift.Server;
+using Thrift.Transports;
+
+namespace Thrift
+{
+    // ReSharper disable once InconsistentNaming
+    public interface ITProcessorFactory
+    {
+        ITAsyncProcessor GetAsyncProcessor(TClientTransport trans, TBaseServer baseServer = null);
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Properties/AssemblyInfo.cs b/lib/netcore/Thrift/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..8341723
--- /dev/null
+++ b/lib/netcore/Thrift/Properties/AssemblyInfo.cs
@@ -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.
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+
+[assembly: AssemblyTitle("Thrift")]
+[assembly: AssemblyDescription("C# .NET Core bindings for the Apache Thrift RPC system")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+//@TODO where to put License information?
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a exType in this assembly from
+// COM, set the ComVisible attribute to true on that exType.
+
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+
+[assembly: Guid("df3f8ef0-e0a3-4c86-a65b-8ec84e016b1d")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/lib/netcore/Thrift/Protocols/Entities/TField.cs b/lib/netcore/Thrift/Protocols/Entities/TField.cs
new file mode 100644
index 0000000..d311535
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Entities/TField.cs
@@ -0,0 +1,37 @@
+// 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.
+
+namespace Thrift.Protocols.Entities
+{
+    // ReSharper disable once InconsistentNaming
+    public struct TField
+    {
+        public TField(string name, TType type, short id)
+        {
+            Name = name;
+            Type = type;
+            ID = id;
+        }
+
+        public string Name { get; set; }
+
+        public TType Type { get; set; }
+
+        // ReSharper disable once InconsistentNaming - do not rename - it used for generation 
+        public short ID { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/Entities/TList.cs b/lib/netcore/Thrift/Protocols/Entities/TList.cs
new file mode 100644
index 0000000..ce23220
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Entities/TList.cs
@@ -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.
+
+namespace Thrift.Protocols.Entities
+{
+    // ReSharper disable once InconsistentNaming
+    public struct TList
+    {
+        public TList(TType elementType, int count)
+        {
+            ElementType = elementType;
+            Count = count;
+        }
+
+        public TType ElementType { get; set; }
+
+        public int Count { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/Entities/TMap.cs b/lib/netcore/Thrift/Protocols/Entities/TMap.cs
new file mode 100644
index 0000000..9195593
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Entities/TMap.cs
@@ -0,0 +1,36 @@
+// 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.
+
+namespace Thrift.Protocols.Entities
+{
+    // ReSharper disable once InconsistentNaming
+    public struct TMap
+    {
+        public TMap(TType keyType, TType valueType, int count)
+        {
+            KeyType = keyType;
+            ValueType = valueType;
+            Count = count;
+        }
+
+        public TType KeyType { get; set; }
+
+        public TType ValueType { get; set; }
+
+        public int Count { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/Entities/TMessage.cs b/lib/netcore/Thrift/Protocols/Entities/TMessage.cs
new file mode 100644
index 0000000..17f4929
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Entities/TMessage.cs
@@ -0,0 +1,37 @@
+// 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.
+
+namespace Thrift.Protocols.Entities
+{
+    // ReSharper disable once InconsistentNaming
+    public struct TMessage
+    {
+        public TMessage(string name, TMessageType type, int seqid)
+        {
+            Name = name;
+            Type = type;
+            SeqID = seqid;
+        }
+
+        public string Name { get; set; }
+
+        public TMessageType Type { get; set; }
+
+        // ReSharper disable once InconsistentNaming - do not rename - it used for generation 
+        public int SeqID { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/Entities/TMessageType.cs b/lib/netcore/Thrift/Protocols/Entities/TMessageType.cs
new file mode 100644
index 0000000..d7b9a22
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Entities/TMessageType.cs
@@ -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.
+
+namespace Thrift.Protocols.Entities
+{
+    // ReSharper disable once InconsistentNaming
+    public enum TMessageType
+    {
+        Call = 1,
+        Reply = 2,
+        Exception = 3,
+        Oneway = 4
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/Entities/TSet.cs b/lib/netcore/Thrift/Protocols/Entities/TSet.cs
new file mode 100644
index 0000000..a583b54
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Entities/TSet.cs
@@ -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.
+
+namespace Thrift.Protocols.Entities
+{
+    // ReSharper disable once InconsistentNaming
+    public struct TSet
+    {
+        public TSet(TType elementType, int count)
+        {
+            ElementType = elementType;
+            Count = count;
+        }
+
+        public TSet(TList list)
+            : this(list.ElementType, list.Count)
+        {
+        }
+
+        public TType ElementType { get; set; }
+
+        public int Count { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/Entities/TStruct.cs b/lib/netcore/Thrift/Protocols/Entities/TStruct.cs
new file mode 100644
index 0000000..a28dcc3
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Entities/TStruct.cs
@@ -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.
+
+namespace Thrift.Protocols.Entities
+{
+    // ReSharper disable once InconsistentNaming
+    public struct TStruct
+    {
+        public TStruct(string name)
+        {
+            Name = name;
+        }
+
+        public string Name { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/Entities/TType.cs b/lib/netcore/Thrift/Protocols/Entities/TType.cs
new file mode 100644
index 0000000..ebe781c
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Entities/TType.cs
@@ -0,0 +1,37 @@
+// 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.
+
+namespace Thrift.Protocols.Entities
+{
+    // ReSharper disable once InconsistentNaming
+    public enum TType : byte
+    {
+        Stop = 0,
+        Void = 1,
+        Bool = 2,
+        Byte = 3,
+        Double = 4,
+        I16 = 6,
+        I32 = 8,
+        I64 = 10,
+        String = 11,
+        Struct = 12,
+        Map = 13,
+        Set = 14,
+        List = 15
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/ITProtocolFactory.cs b/lib/netcore/Thrift/Protocols/ITProtocolFactory.cs
new file mode 100644
index 0000000..ecc5cc4
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/ITProtocolFactory.cs
@@ -0,0 +1,27 @@
+// 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.
+
+using Thrift.Transports;
+
+namespace Thrift.Protocols
+{
+    // ReSharper disable once InconsistentNaming
+    public interface ITProtocolFactory
+    {
+        TProtocol GetProtocol(TClientTransport trans);
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/TAbstractBase.cs b/lib/netcore/Thrift/Protocols/TAbstractBase.cs
new file mode 100644
index 0000000..4e18681
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TAbstractBase.cs
@@ -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.
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Thrift.Protocols
+{
+    // ReSharper disable once InconsistentNaming
+    public interface TAbstractBase
+    {
+        Task WriteAsync(TProtocol tProtocol, CancellationToken cancellationToken);
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/TBase.cs b/lib/netcore/Thrift/Protocols/TBase.cs
new file mode 100644
index 0000000..014e1ae
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TBase.cs
@@ -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.
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Thrift.Protocols
+{
+    // ReSharper disable once InconsistentNaming
+    public interface TBase : TAbstractBase
+    {
+        Task ReadAsync(TProtocol tProtocol, CancellationToken cancellationToken);
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/TBinaryProtocol.cs b/lib/netcore/Thrift/Protocols/TBinaryProtocol.cs
new file mode 100644
index 0000000..deec85c
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TBinaryProtocol.cs
@@ -0,0 +1,613 @@
+// 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.
+
+using System;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols.Entities;
+using Thrift.Transports;
+
+namespace Thrift.Protocols
+{
+    // ReSharper disable once InconsistentNaming
+    public class TBinaryProtocol : TProtocol
+    {
+        //TODO: Unit tests
+        //TODO: Localization
+        //TODO: pragma
+
+        protected const uint VersionMask = 0xffff0000;
+        protected const uint Version1 = 0x80010000;
+
+        protected bool StrictRead;
+        protected bool StrictWrite;
+
+        public TBinaryProtocol(TClientTransport trans)
+            : this(trans, false, true)
+        {
+        }
+
+        public TBinaryProtocol(TClientTransport trans, bool strictRead, bool strictWrite)
+            : base(trans)
+        {
+            StrictRead = strictRead;
+            StrictWrite = strictWrite;
+        }
+
+        public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            if (StrictWrite)
+            {
+                var version = Version1 | (uint) message.Type;
+                await WriteI32Async((int) version, cancellationToken);
+                await WriteStringAsync(message.Name, cancellationToken);
+                await WriteI32Async(message.SeqID, cancellationToken);
+            }
+            else
+            {
+                await WriteStringAsync(message.Name, cancellationToken);
+                await WriteByteAsync((sbyte) message.Type, cancellationToken);
+                await WriteI32Async(message.SeqID, cancellationToken);
+            }
+        }
+
+        public override async Task WriteMessageEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task WriteStructEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            await WriteByteAsync((sbyte) field.Type, cancellationToken);
+            await WriteI16Async(field.ID, cancellationToken);
+        }
+
+        public override async Task WriteFieldEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task WriteFieldStopAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            await WriteByteAsync((sbyte) TType.Stop, cancellationToken);
+        }
+
+        public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            await WriteByteAsync((sbyte) map.KeyType, cancellationToken);
+            await WriteByteAsync((sbyte) map.ValueType, cancellationToken);
+            await WriteI32Async(map.Count, cancellationToken);
+        }
+
+        public override async Task WriteMapEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            await WriteByteAsync((sbyte) list.ElementType, cancellationToken);
+            await WriteI32Async(list.Count, cancellationToken);
+        }
+
+        public override async Task WriteListEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            await WriteByteAsync((sbyte) set.ElementType, cancellationToken);
+            await WriteI32Async(set.Count, cancellationToken);
+        }
+
+        public override async Task WriteSetEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            await WriteByteAsync(b ? (sbyte) 1 : (sbyte) 0, cancellationToken);
+        }
+
+        protected internal static byte[] CreateWriteByte(sbyte b)
+        {
+            var bout = new byte[1];
+
+            bout[0] = (byte) b;
+
+            return bout;
+        }
+
+        public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            var bout = CreateWriteByte(b);
+            await Trans.WriteAsync(bout, 0, 1, cancellationToken);
+        }
+
+        protected internal static byte[] CreateWriteI16(short s)
+        {
+            var i16Out = new byte[2];
+
+            i16Out[0] = (byte) (0xff & (s >> 8));
+            i16Out[1] = (byte) (0xff & s);
+
+            return i16Out;
+        }
+
+        public override async Task WriteI16Async(short i16, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            var i16Out = CreateWriteI16(i16);
+            await Trans.WriteAsync(i16Out, 0, 2, cancellationToken);
+        }
+
+        protected internal static byte[] CreateWriteI32(int i32)
+        {
+            var i32Out = new byte[4];
+
+            i32Out[0] = (byte) (0xff & (i32 >> 24));
+            i32Out[1] = (byte) (0xff & (i32 >> 16));
+            i32Out[2] = (byte) (0xff & (i32 >> 8));
+            i32Out[3] = (byte) (0xff & i32);
+
+            return i32Out;
+        }
+
+        public override async Task WriteI32Async(int i32, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            var i32Out = CreateWriteI32(i32);
+            await Trans.WriteAsync(i32Out, 0, 4, cancellationToken);
+        }
+
+        protected internal static byte[] CreateWriteI64(long i64)
+        {
+            var i64Out = new byte[8];
+
+            i64Out[0] = (byte) (0xff & (i64 >> 56));
+            i64Out[1] = (byte) (0xff & (i64 >> 48));
+            i64Out[2] = (byte) (0xff & (i64 >> 40));
+            i64Out[3] = (byte) (0xff & (i64 >> 32));
+            i64Out[4] = (byte) (0xff & (i64 >> 24));
+            i64Out[5] = (byte) (0xff & (i64 >> 16));
+            i64Out[6] = (byte) (0xff & (i64 >> 8));
+            i64Out[7] = (byte) (0xff & i64);
+
+            return i64Out;
+        }
+
+        public override async Task WriteI64Async(long i64, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            var i64Out = CreateWriteI64(i64);
+            await Trans.WriteAsync(i64Out, 0, 8, cancellationToken);
+        }
+
+        public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            await WriteI64Async(BitConverter.DoubleToInt64Bits(d), cancellationToken);
+        }
+
+        public override async Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            await WriteI32Async(bytes.Length, cancellationToken);
+            await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
+        }
+
+        public override async Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<TMessage>(cancellationToken);
+            }
+
+            var message = new TMessage();
+            var size = await ReadI32Async(cancellationToken);
+            if (size < 0)
+            {
+                var version = (uint) size & VersionMask;
+                if (version != Version1)
+                {
+                    throw new TProtocolException(TProtocolException.BAD_VERSION,
+                        $"Bad version in ReadMessageBegin: {version}");
+                }
+                message.Type = (TMessageType) (size & 0x000000ff);
+                message.Name = await ReadStringAsync(cancellationToken);
+                message.SeqID = await ReadI32Async(cancellationToken);
+            }
+            else
+            {
+                if (StrictRead)
+                {
+                    throw new TProtocolException(TProtocolException.BAD_VERSION,
+                        "Missing version in ReadMessageBegin, old client?");
+                }
+                message.Name = await ReadStringBodyAsync(size, cancellationToken);
+                message.Type = (TMessageType) await ReadByteAsync(cancellationToken);
+                message.SeqID = await ReadI32Async(cancellationToken);
+            }
+            return message;
+        }
+
+        public override async Task ReadMessageEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+
+            //TODO: no read from internal transport?
+            return new TStruct();
+        }
+
+        public override async Task ReadStructEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<TField>(cancellationToken);
+            }
+
+            var field = new TField
+            {
+                Type = (TType) await ReadByteAsync(cancellationToken)
+            };
+
+            if (field.Type != TType.Stop)
+            {
+                field.ID = await ReadI16Async(cancellationToken);
+            }
+
+            return field;
+        }
+
+        public override async Task ReadFieldEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<TMap>(cancellationToken);
+            }
+
+            var map = new TMap
+            {
+                KeyType = (TType) await ReadByteAsync(cancellationToken),
+                ValueType = (TType) await ReadByteAsync(cancellationToken),
+                Count = await ReadI32Async(cancellationToken)
+            };
+
+            return map;
+        }
+
+        public override async Task ReadMapEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task<TList> ReadListBeginAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<TList>(cancellationToken);
+            }
+
+            var list = new TList
+            {
+                ElementType = (TType) await ReadByteAsync(cancellationToken),
+                Count = await ReadI32Async(cancellationToken)
+            };
+
+            return list;
+        }
+
+        public override async Task ReadListEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<TSet>(cancellationToken);
+            }
+
+            var set = new TSet
+            {
+                ElementType = (TType) await ReadByteAsync(cancellationToken),
+                Count = await ReadI32Async(cancellationToken)
+            };
+
+            return set;
+        }
+
+        public override async Task ReadSetEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task<bool> ReadBoolAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<bool>(cancellationToken);
+            }
+
+            return await ReadByteAsync(cancellationToken) == 1;
+        }
+
+        public override async Task<sbyte> ReadByteAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<sbyte>(cancellationToken);
+            }
+
+            var bin = new byte[1];
+            await Trans.ReadAllAsync(bin, 0, 1, cancellationToken); //TODO: why readall ?
+            return (sbyte) bin[0];
+        }
+
+        public override async Task<short> ReadI16Async(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<short>(cancellationToken);
+            }
+
+            var i16In = new byte[2];
+            await Trans.ReadAllAsync(i16In, 0, 2, cancellationToken);
+            var result = (short) (((i16In[0] & 0xff) << 8) | i16In[1] & 0xff);
+            return result;
+        }
+
+        public override async Task<int> ReadI32Async(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<int>(cancellationToken);
+            }
+
+            var i32In = new byte[4];
+            await Trans.ReadAllAsync(i32In, 0, 4, cancellationToken);
+
+            var result = 
+                ((i32In[0] & 0xff) << 24) | 
+                ((i32In[1] & 0xff) << 16) | 
+                ((i32In[2] & 0xff) << 8) |
+                i32In[3] & 0xff;
+
+            return result;
+        }
+
+#pragma warning disable 675
+
+        protected internal long CreateReadI64(byte[] buf)
+        {
+            var result =
+                ((long) (buf[0] & 0xff) << 56) |
+                ((long) (buf[1] & 0xff) << 48) |
+                ((long) (buf[2] & 0xff) << 40) |
+                ((long) (buf[3] & 0xff) << 32) |
+                ((long) (buf[4] & 0xff) << 24) |
+                ((long) (buf[5] & 0xff) << 16) |
+                ((long) (buf[6] & 0xff) << 8) |
+                buf[7] & 0xff;
+
+            return result;
+        }
+
+#pragma warning restore 675
+
+        public override async Task<long> ReadI64Async(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<long>(cancellationToken);
+            }
+
+            var i64In = new byte[8];
+            await Trans.ReadAllAsync(i64In, 0, 8, cancellationToken);
+            return CreateReadI64(i64In);
+        }
+
+        public override async Task<double> ReadDoubleAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<double>(cancellationToken);
+            }
+
+            var d = await ReadI64Async(cancellationToken);
+            return BitConverter.Int64BitsToDouble(d);
+        }
+
+        public override async Task<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<byte[]>(cancellationToken);
+            }
+
+            var size = await ReadI32Async(cancellationToken);
+            var buf = new byte[size];
+            await Trans.ReadAllAsync(buf, 0, size, cancellationToken);
+            return buf;
+        }
+
+        private async Task<string> ReadStringBodyAsync(int size, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled<string>(cancellationToken);
+            }
+
+            var buf = new byte[size];
+            await Trans.ReadAllAsync(buf, 0, size, cancellationToken);
+            return Encoding.UTF8.GetString(buf, 0, buf.Length);
+        }
+
+        public class Factory : ITProtocolFactory
+        {
+            protected bool StrictRead;
+            protected bool StrictWrite;
+
+            public Factory()
+                : this(false, true)
+            {
+            }
+
+            public Factory(bool strictRead, bool strictWrite)
+            {
+                StrictRead = strictRead;
+                StrictWrite = strictWrite;
+            }
+
+            public TProtocol GetProtocol(TClientTransport trans)
+            {
+                return new TBinaryProtocol(trans, StrictRead, StrictWrite);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/TCompactProtocol.cs b/lib/netcore/Thrift/Protocols/TCompactProtocol.cs
new file mode 100644
index 0000000..cecdf03
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TCompactProtocol.cs
@@ -0,0 +1,922 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols.Entities;
+using Thrift.Transports;
+
+namespace Thrift.Protocols
+{
+    //TODO: implementation of TProtocol
+
+    // ReSharper disable once InconsistentNaming
+    public class TCompactProtocol : TProtocol
+    {
+        private const byte ProtocolId = 0x82;
+        private const byte Version = 1;
+        private const byte VersionMask = 0x1f; // 0001 1111
+        private const byte TypeMask = 0xE0; // 1110 0000
+        private const byte TypeBits = 0x07; // 0000 0111
+        private const int TypeShiftAmount = 5;
+        private static readonly TStruct AnonymousStruct = new TStruct(string.Empty);
+        private static readonly TField Tstop = new TField(string.Empty, TType.Stop, 0);
+
+        // ReSharper disable once InconsistentNaming
+        private static readonly byte[] TTypeToCompactType = new byte[16];
+
+        /// <summary>
+        ///     Used to keep track of the last field for the current and previous structs, so we can do the delta stuff.
+        /// </summary>
+        private readonly Stack<short> _lastField = new Stack<short>(15);
+
+        /// <summary>
+        ///     If we encounter a boolean field begin, save the TField here so it can have the value incorporated.
+        /// </summary>
+        private TField? _booleanField;
+
+        /// <summary>
+        ///     If we Read a field header, and it's a boolean field, save the boolean value here so that ReadBool can use it.
+        /// </summary>
+        private bool? _boolValue;
+
+        private short _lastFieldId;
+
+        public TCompactProtocol(TClientTransport trans)
+            : base(trans)
+        {
+            TTypeToCompactType[(int) TType.Stop] = Types.Stop;
+            TTypeToCompactType[(int) TType.Bool] = Types.BooleanTrue;
+            TTypeToCompactType[(int) TType.Byte] = Types.Byte;
+            TTypeToCompactType[(int) TType.I16] = Types.I16;
+            TTypeToCompactType[(int) TType.I32] = Types.I32;
+            TTypeToCompactType[(int) TType.I64] = Types.I64;
+            TTypeToCompactType[(int) TType.Double] = Types.Double;
+            TTypeToCompactType[(int) TType.String] = Types.Binary;
+            TTypeToCompactType[(int) TType.List] = Types.List;
+            TTypeToCompactType[(int) TType.Set] = Types.Set;
+            TTypeToCompactType[(int) TType.Map] = Types.Map;
+            TTypeToCompactType[(int) TType.Struct] = Types.Struct;
+        }
+
+        public void Reset()
+        {
+            _lastField.Clear();
+            _lastFieldId = 0;
+        }
+
+        public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            await Trans.WriteAsync(new[] {ProtocolId}, cancellationToken);
+            await
+                Trans.WriteAsync(
+                    new[] {(byte) ((Version & VersionMask) | (((uint) message.Type << TypeShiftAmount) & TypeMask))},
+                    cancellationToken);
+
+            var bufferTuple = CreateWriteVarInt32((uint) message.SeqID);
+            await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+
+            await WriteStringAsync(message.Name, cancellationToken);
+        }
+
+        public override async Task WriteMessageEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        /// <summary>
+        ///     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.
+        /// </summary>
+        public override async Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+
+            _lastField.Push(_lastFieldId);
+            _lastFieldId = 0;
+        }
+
+        public override async Task WriteStructEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+
+            _lastFieldId = _lastField.Pop();
+        }
+
+        private async Task WriteFieldBeginInternalAsync(TField field, byte typeOverride,
+            CancellationToken cancellationToken)
+        {
+            // if there's a exType override, use that.
+            var typeToWrite = typeOverride == 0xFF ? GetCompactType(field.Type) : typeOverride;
+
+            // check if we can use delta encoding for the field id
+            if ((field.ID > _lastFieldId) && (field.ID - _lastFieldId <= 15))
+            {
+                var b = (byte) (((field.ID - _lastFieldId) << 4) | typeToWrite);
+                // Write them together
+                await Trans.WriteAsync(new[] {b}, cancellationToken);
+            }
+            else
+            {
+                // Write them separate
+                await Trans.WriteAsync(new[] {typeToWrite}, cancellationToken);
+                await WriteI16Async(field.ID, cancellationToken);
+            }
+
+            _lastFieldId = field.ID;
+        }
+
+        public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken)
+        {
+            if (field.Type == TType.Bool)
+            {
+                _booleanField = field;
+            }
+            else
+            {
+                await WriteFieldBeginInternalAsync(field, 0xFF, cancellationToken);
+            }
+        }
+
+        public override async Task WriteFieldEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task WriteFieldStopAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            await Trans.WriteAsync(new[] {Types.Stop}, cancellationToken);
+        }
+
+        protected async Task WriteCollectionBeginAsync(TType elemType, int size, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            /*
+            Abstract method for writing the start of lists and sets. List and sets on
+             the wire differ only by the exType indicator.
+            */
+
+            if (size <= 14)
+            {
+                await Trans.WriteAsync(new[] {(byte) ((size << 4) | GetCompactType(elemType))}, cancellationToken);
+            }
+            else
+            {
+                await Trans.WriteAsync(new[] {(byte) (0xf0 | GetCompactType(elemType))}, cancellationToken);
+
+                var bufferTuple = CreateWriteVarInt32((uint) size);
+                await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+            }
+        }
+
+        public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken)
+        {
+            await WriteCollectionBeginAsync(list.ElementType, list.Count, cancellationToken);
+        }
+
+        public override async Task WriteListEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            await WriteCollectionBeginAsync(set.ElementType, set.Count, cancellationToken);
+        }
+
+        public override async Task WriteSetEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            /*
+            Write a boolean value. Potentially, this could be a boolean field, in
+            which case the field header info isn't written yet. If so, decide what the
+            right exType header is for the value and then Write the field header.
+            Otherwise, Write a single byte.
+            */
+
+            if (_booleanField != null)
+            {
+                // we haven't written the field header yet
+                await
+                    WriteFieldBeginInternalAsync(_booleanField.Value, b ? Types.BooleanTrue : Types.BooleanFalse,
+                        cancellationToken);
+                _booleanField = null;
+            }
+            else
+            {
+                // we're not part of a field, so just Write the value.
+                await Trans.WriteAsync(new[] {b ? Types.BooleanTrue : Types.BooleanFalse}, cancellationToken);
+            }
+        }
+
+        public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            await Trans.WriteAsync(new[] {(byte) b}, cancellationToken);
+        }
+
+        public override async Task WriteI16Async(short i16, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            var bufferTuple = CreateWriteVarInt32(IntToZigzag(i16));
+            await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+        }
+
+        protected internal Tuple<byte[], int> CreateWriteVarInt32(uint n)
+        {
+            // Write an i32 as a varint.Results in 1 - 5 bytes on the wire.
+            var i32Buf = new byte[5];
+            var idx = 0;
+
+            while (true)
+            {
+                if ((n & ~0x7F) == 0)
+                {
+                    i32Buf[idx++] = (byte) n;
+                    break;
+                }
+
+                i32Buf[idx++] = (byte) ((n & 0x7F) | 0x80);
+                n >>= 7;
+            }
+
+            return new Tuple<byte[], int>(i32Buf, idx);
+        }
+
+        public override async Task WriteI32Async(int i32, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            var bufferTuple = CreateWriteVarInt32(IntToZigzag(i32));
+            await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+        }
+
+        protected internal Tuple<byte[], int> CreateWriteVarInt64(ulong n)
+        {
+            // Write an i64 as a varint. Results in 1-10 bytes on the wire.
+            var buf = new byte[10];
+            var idx = 0;
+
+            while (true)
+            {
+                if ((n & ~(ulong) 0x7FL) == 0)
+                {
+                    buf[idx++] = (byte) n;
+                    break;
+                }
+                buf[idx++] = (byte) ((n & 0x7F) | 0x80);
+                n >>= 7;
+            }
+
+            return new Tuple<byte[], int>(buf, idx);
+        }
+
+        public override async Task WriteI64Async(long i64, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            var bufferTuple = CreateWriteVarInt64(LongToZigzag(i64));
+            await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+        }
+
+        public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            var data = new byte[8];
+            FixedLongToBytes(BitConverter.DoubleToInt64Bits(d), data, 0);
+            await Trans.WriteAsync(data, cancellationToken);
+        }
+
+        public override async Task WriteStringAsync(string str, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            var bytes = Encoding.UTF8.GetBytes(str);
+
+            var bufferTuple = CreateWriteVarInt32((uint) bytes.Length);
+            await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+            await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
+        }
+
+        public override async Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            var bufferTuple = CreateWriteVarInt32((uint) bytes.Length);
+            await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+            await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
+        }
+
+        public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return;
+            }
+
+            if (map.Count == 0)
+            {
+                await Trans.WriteAsync(new[] {(byte) 0}, cancellationToken);
+            }
+            else
+            {
+                var bufferTuple = CreateWriteVarInt32((uint) map.Count);
+                await Trans.WriteAsync(bufferTuple.Item1, 0, bufferTuple.Item2, cancellationToken);
+                await
+                    Trans.WriteAsync(
+                        new[] {(byte) ((GetCompactType(map.KeyType) << 4) | GetCompactType(map.ValueType))},
+                        cancellationToken);
+            }
+        }
+
+        public override async Task WriteMapEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<TMessage>(cancellationToken);
+            }
+
+            var protocolId = (byte) await ReadByteAsync(cancellationToken);
+            if (protocolId != ProtocolId)
+            {
+                throw new TProtocolException($"Expected protocol id {ProtocolId:X} but got {protocolId:X}");
+            }
+
+            var versionAndType = (byte) await ReadByteAsync(cancellationToken);
+            var version = (byte) (versionAndType & VersionMask);
+
+            if (version != Version)
+            {
+                throw new TProtocolException($"Expected version {Version} but got {version}");
+            }
+
+            var type = (byte) ((versionAndType >> TypeShiftAmount) & TypeBits);
+            var seqid = (int) await ReadVarInt32Async(cancellationToken);
+            var messageName = await ReadStringAsync(cancellationToken);
+
+            return new TMessage(messageName, (TMessageType) type, seqid);
+        }
+
+        public override async Task ReadMessageEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<TStruct>(cancellationToken);
+            }
+
+            // some magic is here )
+
+            _lastField.Push(_lastFieldId);
+            _lastFieldId = 0;
+
+            return AnonymousStruct;
+        }
+
+        public override async Task ReadStructEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+
+            /*
+            Doesn't actually consume any wire data, just removes the last field for
+            this struct from the field stack.
+            */
+
+            // consume the last field we Read off the wire.
+            _lastFieldId = _lastField.Pop();
+        }
+
+        public override async Task<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
+        {
+            // Read a field header off the wire.
+            var type = (byte) await ReadByteAsync(cancellationToken);
+            // if it's a stop, then we can return immediately, as the struct is over.
+            if (type == Types.Stop)
+            {
+                return Tstop;
+            }
+
+            short fieldId;
+            // mask off the 4 MSB of the exType header. it could contain a field id delta.
+            var modifier = (short) ((type & 0xf0) >> 4);
+            if (modifier == 0)
+            {
+                fieldId = await ReadI16Async(cancellationToken);
+            }
+            else
+            {
+                fieldId = (short) (_lastFieldId + modifier);
+            }
+
+            var field = new TField(string.Empty, GetTType((byte) (type & 0x0f)), fieldId);
+            // if this happens to be a boolean field, the value is encoded in the exType
+            if (IsBoolType(type))
+            {
+                _boolValue = (byte) (type & 0x0f) == Types.BooleanTrue;
+            }
+
+            // push the new field onto the field stack so we can keep the deltas going.
+            _lastFieldId = field.ID;
+            return field;
+        }
+
+        public override async Task ReadFieldEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled<TMap>(cancellationToken);
+            }
+
+            /*
+            Read a map header off the wire. If the size is zero, skip Reading the key
+            and value exType. This means that 0-length maps will yield TMaps without the
+            "correct" types.
+            */
+
+            var size = (int) await ReadVarInt32Async(cancellationToken);
+            var keyAndValueType = size == 0 ? (byte) 0 : (byte) await ReadByteAsync(cancellationToken);
+            return new TMap(GetTType((byte) (keyAndValueType >> 4)), GetTType((byte) (keyAndValueType & 0xf)), size);
+        }
+
+        public override async Task ReadMapEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
+        {
+            /*
+            Read a set header off the wire. If the set size is 0-14, the size will
+            be packed into the element exType header. If it's a longer set, the 4 MSB
+            of the element exType header will be 0xF, and a varint will follow with the
+            true size.
+            */
+
+            return new TSet(await ReadListBeginAsync(cancellationToken));
+        }
+
+        public override async Task<bool> ReadBoolAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<bool>(cancellationToken);
+            }
+
+            /*
+            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.
+            */
+
+            if (_boolValue != null)
+            {
+                var result = _boolValue.Value;
+                _boolValue = null;
+                return result;
+            }
+
+            return await ReadByteAsync(cancellationToken) == Types.BooleanTrue;
+        }
+
+        public override async Task<sbyte> ReadByteAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<sbyte>(cancellationToken);
+            }
+
+            // Read a single byte off the wire. Nothing interesting here.
+            var buf = new byte[1];
+            await Trans.ReadAllAsync(buf, 0, 1, cancellationToken);
+            return (sbyte) buf[0];
+        }
+
+        public override async Task<short> ReadI16Async(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<short>(cancellationToken);
+            }
+
+            return (short) ZigzagToInt(await ReadVarInt32Async(cancellationToken));
+        }
+
+        public override async Task<int> ReadI32Async(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<int>(cancellationToken);
+            }
+
+            return ZigzagToInt(await ReadVarInt32Async(cancellationToken));
+        }
+
+        public override async Task<long> ReadI64Async(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<long>(cancellationToken);
+            }
+
+            return ZigzagToLong(await ReadVarInt64Async(cancellationToken));
+        }
+
+        public override async Task<double> ReadDoubleAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<double>(cancellationToken);
+            }
+
+            var longBits = new byte[8];
+            await Trans.ReadAllAsync(longBits, 0, 8, cancellationToken);
+
+            return BitConverter.Int64BitsToDouble(BytesToLong(longBits));
+        }
+
+        public override async Task<string> ReadStringAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled<string>(cancellationToken);
+            }
+
+            // Reads a byte[] (via ReadBinary), and then UTF-8 decodes it.
+            var length = (int) await ReadVarInt32Async(cancellationToken);
+
+            if (length == 0)
+            {
+                return string.Empty;
+            }
+
+            var buf = new byte[length];
+            await Trans.ReadAllAsync(buf, 0, length, cancellationToken);
+
+            return Encoding.UTF8.GetString(buf);
+        }
+
+        public override async Task<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<byte[]>(cancellationToken);
+            }
+
+            // Read a byte[] from the wire.
+            var length = (int) await ReadVarInt32Async(cancellationToken);
+            if (length == 0)
+            {
+                return new byte[0];
+            }
+
+            var buf = new byte[length];
+            await Trans.ReadAllAsync(buf, 0, length, cancellationToken);
+            return buf;
+        }
+
+        public override async Task<TList> ReadListBeginAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled<TList>(cancellationToken);
+            }
+
+            /*
+            Read a list header off the wire. If the list size is 0-14, the size will
+            be packed into the element exType header. If it's a longer list, the 4 MSB
+            of the element exType header will be 0xF, and a varint will follow with the
+            true size.
+            */
+
+            var sizeAndType = (byte) await ReadByteAsync(cancellationToken);
+            var size = (sizeAndType >> 4) & 0x0f;
+            if (size == 15)
+            {
+                size = (int) await ReadVarInt32Async(cancellationToken);
+            }
+
+            var type = GetTType(sizeAndType);
+            return new TList(type, size);
+        }
+
+        public override async Task ReadListEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task ReadSetEndAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        private static byte GetCompactType(TType ttype)
+        {
+            // Given a TType value, find the appropriate TCompactProtocol.Types constant.
+            return TTypeToCompactType[(int) ttype];
+        }
+
+
+        private async Task<uint> ReadVarInt32Async(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<uint>(cancellationToken);
+            }
+
+            /*
+            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.
+            */
+
+            uint result = 0;
+            var shift = 0;
+
+            while (true)
+            {
+                var b = (byte) await ReadByteAsync(cancellationToken);
+                result |= (uint) (b & 0x7f) << shift;
+                if ((b & 0x80) != 0x80)
+                {
+                    break;
+                }
+                shift += 7;
+            }
+
+            return result;
+        }
+
+        private async Task<ulong> ReadVarInt64Async(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<uint>(cancellationToken);
+            }
+
+            /*
+            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.
+            */
+
+            var shift = 0;
+            ulong result = 0;
+            while (true)
+            {
+                var b = (byte) await ReadByteAsync(cancellationToken);
+                result |= (ulong) (b & 0x7f) << shift;
+                if ((b & 0x80) != 0x80)
+                {
+                    break;
+                }
+                shift += 7;
+            }
+
+            return result;
+        }
+
+        private static int ZigzagToInt(uint n)
+        {
+            return (int) (n >> 1) ^ -(int) (n & 1);
+        }
+
+        private static long ZigzagToLong(ulong n)
+        {
+            return (long) (n >> 1) ^ -(long) (n & 1);
+        }
+
+        private static long BytesToLong(byte[] bytes)
+        {
+            /*
+            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.
+            */
+
+            return
+                ((bytes[7] & 0xffL) << 56) |
+                ((bytes[6] & 0xffL) << 48) |
+                ((bytes[5] & 0xffL) << 40) |
+                ((bytes[4] & 0xffL) << 32) |
+                ((bytes[3] & 0xffL) << 24) |
+                ((bytes[2] & 0xffL) << 16) |
+                ((bytes[1] & 0xffL) << 8) |
+                (bytes[0] & 0xffL);
+        }
+
+        private static bool IsBoolType(byte b)
+        {
+            var lowerNibble = b & 0x0f;
+            return (lowerNibble == Types.BooleanTrue) || (lowerNibble == Types.BooleanFalse);
+        }
+
+        private static TType GetTType(byte type)
+        {
+            // Given a TCompactProtocol.Types constant, convert it to its corresponding TType value.
+            switch ((byte) (type & 0x0f))
+            {
+                case Types.Stop:
+                    return TType.Stop;
+                case Types.BooleanFalse:
+                case Types.BooleanTrue:
+                    return TType.Bool;
+                case Types.Byte:
+                    return TType.Byte;
+                case Types.I16:
+                    return TType.I16;
+                case Types.I32:
+                    return TType.I32;
+                case Types.I64:
+                    return TType.I64;
+                case Types.Double:
+                    return TType.Double;
+                case Types.Binary:
+                    return TType.String;
+                case Types.List:
+                    return TType.List;
+                case Types.Set:
+                    return TType.Set;
+                case Types.Map:
+                    return TType.Map;
+                case Types.Struct:
+                    return TType.Struct;
+                default:
+                    throw new TProtocolException($"Don't know what exType: {(byte) (type & 0x0f)}");
+            }
+        }
+
+        private static ulong LongToZigzag(long n)
+        {
+            // Convert l into a zigzag long. This allows negative numbers to be represented compactly as a varint
+            return (ulong) (n << 1) ^ (ulong) (n >> 63);
+        }
+
+        private static uint IntToZigzag(int n)
+        {
+            // Convert n into a zigzag int. This allows negative numbers to be represented compactly as a varint
+            return (uint) (n << 1) ^ (uint) (n >> 31);
+        }
+
+        private static void FixedLongToBytes(long n, byte[] buf, int off)
+        {
+            // Convert a long into little-endian bytes in buf starting at off and going until off+7.
+            buf[off + 0] = (byte) (n & 0xff);
+            buf[off + 1] = (byte) ((n >> 8) & 0xff);
+            buf[off + 2] = (byte) ((n >> 16) & 0xff);
+            buf[off + 3] = (byte) ((n >> 24) & 0xff);
+            buf[off + 4] = (byte) ((n >> 32) & 0xff);
+            buf[off + 5] = (byte) ((n >> 40) & 0xff);
+            buf[off + 6] = (byte) ((n >> 48) & 0xff);
+            buf[off + 7] = (byte) ((n >> 56) & 0xff);
+        }
+
+        public class Factory : ITProtocolFactory
+        {
+            public TProtocol GetProtocol(TClientTransport trans)
+            {
+                return new TCompactProtocol(trans);
+            }
+        }
+
+        /// <summary>
+        ///     All of the on-wire exType codes.
+        /// </summary>
+        private static class Types
+        {
+            public const byte Stop = 0x00;
+            public const byte BooleanTrue = 0x01;
+            public const byte BooleanFalse = 0x02;
+            public const byte Byte = 0x03;
+            public const byte I16 = 0x04;
+            public const byte I32 = 0x05;
+            public const byte I64 = 0x06;
+            public const byte Double = 0x07;
+            public const byte Binary = 0x08;
+            public const byte List = 0x09;
+            public const byte Set = 0x0A;
+            public const byte Map = 0x0B;
+            public const byte Struct = 0x0C;
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/TJSONProtocol.cs b/lib/netcore/Thrift/Protocols/TJSONProtocol.cs
new file mode 100644
index 0000000..6d33f02
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TJSONProtocol.cs
@@ -0,0 +1,981 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols.Entities;
+using Thrift.Protocols.Utilities;
+using Thrift.Transports;
+
+namespace Thrift.Protocols
+{
+    /// <summary>
+    ///     JSON protocol implementation for thrift.
+    ///     This is a full-featured protocol supporting Write and Read.
+    ///     Please see the C++ class header for a detailed description of the
+    ///     protocol's wire format.
+    ///     Adapted from the Java version.
+    /// </summary>
+    // ReSharper disable once InconsistentNaming
+    public class TJsonProtocol : TProtocol
+    {
+        private const long Version = 1;
+
+        // Temporary buffer used by several methods
+        private readonly byte[] _tempBuffer = new byte[4];
+
+        // Current context that we are in
+        protected JSONBaseContext Context;
+
+        // Stack of nested contexts that we may be in
+        protected Stack<JSONBaseContext> ContextStack = new Stack<JSONBaseContext>();
+
+        // Reader that manages a 1-byte buffer
+        protected LookaheadReader Reader;
+
+        // Default encoding
+        protected Encoding Utf8Encoding = Encoding.UTF8;
+
+        /// <summary>
+        ///     TJsonProtocol Constructor
+        /// </summary>
+        public TJsonProtocol(TClientTransport trans)
+            : base(trans)
+        {
+            Context = new JSONBaseContext(this);
+            Reader = new LookaheadReader(this);
+        }
+
+        /// <summary>
+        ///     Push a new JSON context onto the stack.
+        /// </summary>
+        protected void PushContext(JSONBaseContext c)
+        {
+            ContextStack.Push(Context);
+            Context = c;
+        }
+
+        /// <summary>
+        ///     Pop the last JSON context off the stack
+        /// </summary>
+        protected void PopContext()
+        {
+            Context = ContextStack.Pop();
+        }
+
+        /// <summary>
+        ///     Read a byte that must match b[0]; otherwise an exception is thrown.
+        ///     Marked protected to avoid synthetic accessor in JSONListContext.Read
+        ///     and JSONPairContext.Read
+        /// </summary>
+        protected async Task ReadJsonSyntaxCharAsync(byte[] bytes, CancellationToken cancellationToken)
+        {
+            var ch = await Reader.ReadAsync(cancellationToken);
+            if (ch != bytes[0])
+            {
+                throw new TProtocolException(TProtocolException.INVALID_DATA, $"Unexpected character: {(char) ch}");
+            }
+        }
+
+        /// <summary>
+        ///     Write the bytes in array buf as a JSON characters, escaping as needed
+        /// </summary>
+        private async Task WriteJsonStringAsync(byte[] bytes, CancellationToken cancellationToken)
+        {
+            await Context.WriteAsync(cancellationToken);
+            await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken);
+
+            var len = bytes.Length;
+            for (var i = 0; i < len; i++)
+            {
+                if ((bytes[i] & 0x00FF) >= 0x30)
+                {
+                    if (bytes[i] == TJSONProtocolConstants.Backslash[0])
+                    {
+                        await Trans.WriteAsync(TJSONProtocolConstants.Backslash, cancellationToken);
+                        await Trans.WriteAsync(TJSONProtocolConstants.Backslash, cancellationToken);
+                    }
+                    else
+                    {
+                        await Trans.WriteAsync(bytes.ToArray(), i, 1, cancellationToken);
+                    }
+                }
+                else
+                {
+                    _tempBuffer[0] = TJSONProtocolConstants.JsonCharTable[bytes[i]];
+                    if (_tempBuffer[0] == 1)
+                    {
+                        await Trans.WriteAsync(bytes, i, 1, cancellationToken);
+                    }
+                    else if (_tempBuffer[0] > 1)
+                    {
+                        await Trans.WriteAsync(TJSONProtocolConstants.Backslash, cancellationToken);
+                        await Trans.WriteAsync(_tempBuffer, 0, 1, cancellationToken);
+                    }
+                    else
+                    {
+                        await Trans.WriteAsync(TJSONProtocolConstants.EscSequences, cancellationToken);
+                        _tempBuffer[0] = TJSONProtocolHelper.ToHexChar((byte) (bytes[i] >> 4));
+                        _tempBuffer[1] = TJSONProtocolHelper.ToHexChar(bytes[i]);
+                        await Trans.WriteAsync(_tempBuffer, 0, 2, cancellationToken);
+                    }
+                }
+            }
+            await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken);
+        }
+
+        /// <summary>
+        ///     Write out number as a JSON value. If the context dictates so, it will be
+        ///     wrapped in quotes to output as a JSON string.
+        /// </summary>
+        private async Task WriteJsonIntegerAsync(long num, CancellationToken cancellationToken)
+        {
+            await Context.WriteAsync(cancellationToken);
+            var str = num.ToString();
+
+            var escapeNum = Context.EscapeNumbers();
+            if (escapeNum)
+            {
+                await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken);
+            }
+
+            var bytes = Utf8Encoding.GetBytes(str);
+            await Trans.WriteAsync(bytes, cancellationToken);
+
+            if (escapeNum)
+            {
+                await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken);
+            }
+        }
+
+        /// <summary>
+        ///     Write out a double as a JSON value. If it is NaN or infinity or if the
+        ///     context dictates escaping, Write out as JSON string.
+        /// </summary>
+        private async Task WriteJsonDoubleAsync(double num, CancellationToken cancellationToken)
+        {
+            await Context.WriteAsync(cancellationToken);
+            var str = num.ToString("G17", CultureInfo.InvariantCulture);
+            var special = false;
+
+            switch (str[0])
+            {
+                case 'N': // NaN
+                case 'I': // Infinity
+                    special = true;
+                    break;
+                case '-':
+                    if (str[1] == 'I')
+                    {
+                        // -Infinity
+                        special = true;
+                    }
+                    break;
+            }
+
+            var escapeNum = special || Context.EscapeNumbers();
+
+            if (escapeNum)
+            {
+                await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken);
+            }
+
+            await Trans.WriteAsync(Utf8Encoding.GetBytes(str), cancellationToken);
+
+            if (escapeNum)
+            {
+                await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken);
+            }
+        }
+
+        /// <summary>
+        ///     Write out contents of byte array b as a JSON string with base-64 encoded
+        ///     data
+        /// </summary>
+        private async Task WriteJsonBase64Async(byte[] bytes, CancellationToken cancellationToken)
+        {
+            await Context.WriteAsync(cancellationToken);
+            await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken);
+
+            var len = bytes.Length;
+            var off = 0;
+
+            while (len >= 3)
+            {
+                // Encode 3 bytes at a time
+                TBase64Helper.Encode(bytes, off, 3, _tempBuffer, 0);
+                await Trans.WriteAsync(_tempBuffer, 0, 4, cancellationToken);
+                off += 3;
+                len -= 3;
+            }
+
+            if (len > 0)
+            {
+                // Encode remainder
+                TBase64Helper.Encode(bytes, off, len, _tempBuffer, 0);
+                await Trans.WriteAsync(_tempBuffer, 0, len + 1, cancellationToken);
+            }
+
+            await Trans.WriteAsync(TJSONProtocolConstants.Quote, cancellationToken);
+        }
+
+        private async Task WriteJsonObjectStartAsync(CancellationToken cancellationToken)
+        {
+            await Context.WriteAsync(cancellationToken);
+            await Trans.WriteAsync(TJSONProtocolConstants.LeftBrace, cancellationToken);
+            PushContext(new JSONPairContext(this));
+        }
+
+        private async Task WriteJsonObjectEndAsync(CancellationToken cancellationToken)
+        {
+            PopContext();
+            await Trans.WriteAsync(TJSONProtocolConstants.RightBrace, cancellationToken);
+        }
+
+        private async Task WriteJsonArrayStartAsync(CancellationToken cancellationToken)
+        {
+            await Context.WriteAsync(cancellationToken);
+            await Trans.WriteAsync(TJSONProtocolConstants.LeftBracket, cancellationToken);
+            PushContext(new JSONListContext(this));
+        }
+
+        private async Task WriteJsonArrayEndAsync(CancellationToken cancellationToken)
+        {
+            PopContext();
+            await Trans.WriteAsync(TJSONProtocolConstants.RightBracket, cancellationToken);
+        }
+
+        public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayStartAsync(cancellationToken);
+            await WriteJsonIntegerAsync(Version, cancellationToken);
+
+            var b = Utf8Encoding.GetBytes(message.Name);
+            await WriteJsonStringAsync(b, cancellationToken);
+
+            await WriteJsonIntegerAsync((long) message.Type, cancellationToken);
+            await WriteJsonIntegerAsync(message.SeqID, cancellationToken);
+        }
+
+        public override async Task WriteMessageEndAsync(CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken)
+        {
+            await WriteJsonObjectStartAsync(cancellationToken);
+        }
+
+        public override async Task WriteStructEndAsync(CancellationToken cancellationToken)
+        {
+            await WriteJsonObjectEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken)
+        {
+            await WriteJsonIntegerAsync(field.ID, cancellationToken);
+            await WriteJsonObjectStartAsync(cancellationToken);
+            await WriteJsonStringAsync(TJSONProtocolHelper.GetTypeNameForTypeId(field.Type), cancellationToken);
+        }
+
+        public override async Task WriteFieldEndAsync(CancellationToken cancellationToken)
+        {
+            await WriteJsonObjectEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteFieldStopAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayStartAsync(cancellationToken);
+            await WriteJsonStringAsync(TJSONProtocolHelper.GetTypeNameForTypeId(map.KeyType), cancellationToken);
+            await WriteJsonStringAsync(TJSONProtocolHelper.GetTypeNameForTypeId(map.ValueType), cancellationToken);
+            await WriteJsonIntegerAsync(map.Count, cancellationToken);
+            await WriteJsonObjectStartAsync(cancellationToken);
+        }
+
+        public override async Task WriteMapEndAsync(CancellationToken cancellationToken)
+        {
+            await WriteJsonObjectEndAsync(cancellationToken);
+            await WriteJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayStartAsync(cancellationToken);
+            await WriteJsonStringAsync(TJSONProtocolHelper.GetTypeNameForTypeId(list.ElementType), cancellationToken);
+            await WriteJsonIntegerAsync(list.Count, cancellationToken);
+        }
+
+        public override async Task WriteListEndAsync(CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayStartAsync(cancellationToken);
+            await WriteJsonStringAsync(TJSONProtocolHelper.GetTypeNameForTypeId(set.ElementType), cancellationToken);
+            await WriteJsonIntegerAsync(set.Count, cancellationToken);
+        }
+
+        public override async Task WriteSetEndAsync(CancellationToken cancellationToken)
+        {
+            await WriteJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken)
+        {
+            await WriteJsonIntegerAsync(b ? 1 : 0, cancellationToken);
+        }
+
+        public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken)
+        {
+            await WriteJsonIntegerAsync(b, cancellationToken);
+        }
+
+        public override async Task WriteI16Async(short i16, CancellationToken cancellationToken)
+        {
+            await WriteJsonIntegerAsync(i16, cancellationToken);
+        }
+
+        public override async Task WriteI32Async(int i32, CancellationToken cancellationToken)
+        {
+            await WriteJsonIntegerAsync(i32, cancellationToken);
+        }
+
+        public override async Task WriteI64Async(long i64, CancellationToken cancellationToken)
+        {
+            await WriteJsonIntegerAsync(i64, cancellationToken);
+        }
+
+        public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken)
+        {
+            await WriteJsonDoubleAsync(d, cancellationToken);
+        }
+
+        public override async Task WriteStringAsync(string s, CancellationToken cancellationToken)
+        {
+            var b = Utf8Encoding.GetBytes(s);
+            await WriteJsonStringAsync(b, cancellationToken);
+        }
+
+        public override async Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken)
+        {
+            await WriteJsonBase64Async(bytes, cancellationToken);
+        }
+
+        /// <summary>
+        ///     Read in a JSON string, unescaping as appropriate.. Skip Reading from the
+        ///     context if skipContext is true.
+        /// </summary>
+        private async Task<byte[]> ReadJsonStringAsync(bool skipContext, CancellationToken cancellationToken)
+        {
+            using (var buffer = new MemoryStream())
+            {
+                var codeunits = new List<char>();
+
+
+                if (!skipContext)
+                {
+                    await Context.ReadAsync(cancellationToken);
+                }
+
+                await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.Quote, cancellationToken);
+
+                while (true)
+                {
+                    var ch = await Reader.ReadAsync(cancellationToken);
+                    if (ch == TJSONProtocolConstants.Quote[0])
+                    {
+                        break;
+                    }
+
+                    // escaped?
+                    if (ch != TJSONProtocolConstants.EscSequences[0])
+                    {
+                        await buffer.WriteAsync(new[] {ch}, 0, 1, cancellationToken);
+                        continue;
+                    }
+
+                    // distinguish between \uXXXX and \?
+                    ch = await Reader.ReadAsync(cancellationToken);
+                    if (ch != TJSONProtocolConstants.EscSequences[1]) // control chars like \n
+                    {
+                        var off = Array.IndexOf(TJSONProtocolConstants.EscapeChars, (char) ch);
+                        if (off == -1)
+                        {
+                            throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected control char");
+                        }
+                        ch = TJSONProtocolConstants.EscapeCharValues[off];
+                        await buffer.WriteAsync(new[] {ch}, 0, 1, cancellationToken);
+                        continue;
+                    }
+
+                    // it's \uXXXX
+                    await Trans.ReadAllAsync(_tempBuffer, 0, 4, cancellationToken);
+
+                    var wch = (short) ((TJSONProtocolHelper.ToHexVal(_tempBuffer[0]) << 12) +
+                                       (TJSONProtocolHelper.ToHexVal(_tempBuffer[1]) << 8) +
+                                       (TJSONProtocolHelper.ToHexVal(_tempBuffer[2]) << 4) +
+                                       TJSONProtocolHelper.ToHexVal(_tempBuffer[3]));
+
+                    if (char.IsHighSurrogate((char) wch))
+                    {
+                        if (codeunits.Count > 0)
+                        {
+                            throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected low surrogate char");
+                        }
+                        codeunits.Add((char) wch);
+                    }
+                    else if (char.IsLowSurrogate((char) wch))
+                    {
+                        if (codeunits.Count == 0)
+                        {
+                            throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected high surrogate char");
+                        }
+
+                        codeunits.Add((char) wch);
+                        var tmp = Utf8Encoding.GetBytes(codeunits.ToArray());
+                        await buffer.WriteAsync(tmp, 0, tmp.Length, cancellationToken);
+                        codeunits.Clear();
+                    }
+                    else
+                    {
+                        var tmp = Utf8Encoding.GetBytes(new[] {(char) wch});
+                        await buffer.WriteAsync(tmp, 0, tmp.Length, cancellationToken);
+                    }
+                }
+
+                if (codeunits.Count > 0)
+                {
+                    throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected low surrogate char");
+                }
+
+                return buffer.ToArray();
+            }
+        }
+
+        /// <summary>
+        ///     Read in a sequence of characters that are all valid in JSON numbers. Does
+        ///     not do a complete regex check to validate that this is actually a number.
+        /// </summary>
+        private async Task<string> ReadJsonNumericCharsAsync(CancellationToken cancellationToken)
+        {
+            var strbld = new StringBuilder();
+            while (true)
+            {
+                //TODO: workaround for primitive types with TJsonProtocol, think - how to rewrite into more easy form without exceptions
+                try
+                {
+                    var ch = await Reader.PeekAsync(cancellationToken);
+                    if (!TJSONProtocolHelper.IsJsonNumeric(ch))
+                    {
+                        break;
+                    }
+                    var c = (char)await Reader.ReadAsync(cancellationToken);
+                    strbld.Append(c);
+                }
+                catch (TTransportException)
+                {
+                    break;
+                }
+            }
+            return strbld.ToString();
+        }
+
+        /// <summary>
+        ///     Read in a JSON number. If the context dictates, Read in enclosing quotes.
+        /// </summary>
+        private async Task<long> ReadJsonIntegerAsync(CancellationToken cancellationToken)
+        {
+            await Context.ReadAsync(cancellationToken);
+            if (Context.EscapeNumbers())
+            {
+                await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.Quote, cancellationToken);
+            }
+
+            var str = await ReadJsonNumericCharsAsync(cancellationToken);
+            if (Context.EscapeNumbers())
+            {
+                await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.Quote, cancellationToken);
+            }
+
+            try
+            {
+                return long.Parse(str);
+            }
+            catch (FormatException)
+            {
+                throw new TProtocolException(TProtocolException.INVALID_DATA, "Bad data encounted in numeric data");
+            }
+        }
+
+        /// <summary>
+        ///     Read in a JSON double value. Throw if the value is not wrapped in quotes
+        ///     when expected or if wrapped in quotes when not expected.
+        /// </summary>
+        private async Task<double> ReadJsonDoubleAsync(CancellationToken cancellationToken)
+        {
+            await Context.ReadAsync(cancellationToken);
+            if (await Reader.PeekAsync(cancellationToken) == TJSONProtocolConstants.Quote[0])
+            {
+                var arr = await ReadJsonStringAsync(true, cancellationToken);
+                var dub = double.Parse(Utf8Encoding.GetString(arr, 0, arr.Length), CultureInfo.InvariantCulture);
+
+                if (!Context.EscapeNumbers() && !double.IsNaN(dub) && !double.IsInfinity(dub))
+                {
+                    // Throw exception -- we should not be in a string in this case
+                    throw new TProtocolException(TProtocolException.INVALID_DATA, "Numeric data unexpectedly quoted");
+                }
+
+                return dub;
+            }
+
+            if (Context.EscapeNumbers())
+            {
+                // This will throw - we should have had a quote if escapeNum == true
+                await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.Quote, cancellationToken);
+            }
+
+            try
+            {
+                return double.Parse(await ReadJsonNumericCharsAsync(cancellationToken), CultureInfo.InvariantCulture);
+            }
+            catch (FormatException)
+            {
+                throw new TProtocolException(TProtocolException.INVALID_DATA, "Bad data encounted in numeric data");
+            }
+        }
+
+        /// <summary>
+        ///     Read in a JSON string containing base-64 encoded data and decode it.
+        /// </summary>
+        private async Task<byte[]> ReadJsonBase64Async(CancellationToken cancellationToken)
+        {
+            var b = await ReadJsonStringAsync(false, cancellationToken);
+            var len = b.Length;
+            var off = 0;
+            var size = 0;
+
+            // reduce len to ignore fill bytes
+            while ((len > 0) && (b[len - 1] == '='))
+            {
+                --len;
+            }
+
+            // read & decode full byte triplets = 4 source bytes
+            while (len > 4)
+            {
+                // Decode 4 bytes at a time
+                TBase64Helper.Decode(b, off, 4, b, size); // NB: decoded in place
+                off += 4;
+                len -= 4;
+                size += 3;
+            }
+
+            // Don't decode if we hit the end or got a single leftover byte (invalid
+            // base64 but legal for skip of regular string exType)
+            if (len > 1)
+            {
+                // Decode remainder
+                TBase64Helper.Decode(b, off, len, b, size); // NB: decoded in place
+                size += len - 1;
+            }
+
+            // Sadly we must copy the byte[] (any way around this?)
+            var result = new byte[size];
+            Array.Copy(b, 0, result, 0, size);
+            return result;
+        }
+
+        private async Task ReadJsonObjectStartAsync(CancellationToken cancellationToken)
+        {
+            await Context.ReadAsync(cancellationToken);
+            await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.LeftBrace, cancellationToken);
+            PushContext(new JSONPairContext(this));
+        }
+
+        private async Task ReadJsonObjectEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.RightBrace, cancellationToken);
+            PopContext();
+        }
+
+        private async Task ReadJsonArrayStartAsync(CancellationToken cancellationToken)
+        {
+            await Context.ReadAsync(cancellationToken);
+            await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.LeftBracket, cancellationToken);
+            PushContext(new JSONListContext(this));
+        }
+
+        private async Task ReadJsonArrayEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonSyntaxCharAsync(TJSONProtocolConstants.RightBracket, cancellationToken);
+            PopContext();
+        }
+
+        public override async Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
+        {
+            var message = new TMessage();
+            await ReadJsonArrayStartAsync(cancellationToken);
+            if (await ReadJsonIntegerAsync(cancellationToken) != Version)
+            {
+                throw new TProtocolException(TProtocolException.BAD_VERSION, "Message contained bad version.");
+            }
+
+            var buf = await ReadJsonStringAsync(false, cancellationToken);
+            message.Name = Utf8Encoding.GetString(buf, 0, buf.Length);
+            message.Type = (TMessageType) await ReadJsonIntegerAsync(cancellationToken);
+            message.SeqID = (int) await ReadJsonIntegerAsync(cancellationToken);
+            return message;
+        }
+
+        public override async Task ReadMessageEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonObjectStartAsync(cancellationToken);
+            return new TStruct();
+        }
+
+        public override async Task ReadStructEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonObjectEndAsync(cancellationToken);
+        }
+
+        public override async Task<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
+        {
+            var field = new TField();
+            var ch = await Reader.PeekAsync(cancellationToken);
+            if (ch == TJSONProtocolConstants.RightBrace[0])
+            {
+                field.Type = TType.Stop;
+            }
+            else
+            {
+                field.ID = (short) await ReadJsonIntegerAsync(cancellationToken);
+                await ReadJsonObjectStartAsync(cancellationToken);
+                field.Type = TJSONProtocolHelper.GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken));
+            }
+            return field;
+        }
+
+        public override async Task ReadFieldEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonObjectEndAsync(cancellationToken);
+        }
+
+        public override async Task<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
+        {
+            var map = new TMap();
+            await ReadJsonArrayStartAsync(cancellationToken);
+            map.KeyType = TJSONProtocolHelper.GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken));
+            map.ValueType = TJSONProtocolHelper.GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken));
+            map.Count = (int) await ReadJsonIntegerAsync(cancellationToken);
+            await ReadJsonObjectStartAsync(cancellationToken);
+            return map;
+        }
+
+        public override async Task ReadMapEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonObjectEndAsync(cancellationToken);
+            await ReadJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task<TList> ReadListBeginAsync(CancellationToken cancellationToken)
+        {
+            var list = new TList();
+            await ReadJsonArrayStartAsync(cancellationToken);
+            list.ElementType = TJSONProtocolHelper.GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken));
+            list.Count = (int) await ReadJsonIntegerAsync(cancellationToken);
+            return list;
+        }
+
+        public override async Task ReadListEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
+        {
+            var set = new TSet();
+            await ReadJsonArrayStartAsync(cancellationToken);
+            set.ElementType = TJSONProtocolHelper.GetTypeIdForTypeName(await ReadJsonStringAsync(false, cancellationToken));
+            set.Count = (int) await ReadJsonIntegerAsync(cancellationToken);
+            return set;
+        }
+
+        public override async Task ReadSetEndAsync(CancellationToken cancellationToken)
+        {
+            await ReadJsonArrayEndAsync(cancellationToken);
+        }
+
+        public override async Task<bool> ReadBoolAsync(CancellationToken cancellationToken)
+        {
+            return await ReadJsonIntegerAsync(cancellationToken) != 0;
+        }
+
+        public override async Task<sbyte> ReadByteAsync(CancellationToken cancellationToken)
+        {
+            return (sbyte) await ReadJsonIntegerAsync(cancellationToken);
+        }
+
+        public override async Task<short> ReadI16Async(CancellationToken cancellationToken)
+        {
+            return (short) await ReadJsonIntegerAsync(cancellationToken);
+        }
+
+        public override async Task<int> ReadI32Async(CancellationToken cancellationToken)
+        {
+            return (int) await ReadJsonIntegerAsync(cancellationToken);
+        }
+
+        public override async Task<long> ReadI64Async(CancellationToken cancellationToken)
+        {
+            return await ReadJsonIntegerAsync(cancellationToken);
+        }
+
+        public override async Task<double> ReadDoubleAsync(CancellationToken cancellationToken)
+        {
+            return await ReadJsonDoubleAsync(cancellationToken);
+        }
+
+        public override async Task<string> ReadStringAsync(CancellationToken cancellationToken)
+        {
+            var buf = await ReadJsonStringAsync(false, cancellationToken);
+            return Utf8Encoding.GetString(buf, 0, buf.Length);
+        }
+
+        public override async Task<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
+        {
+            return await ReadJsonBase64Async(cancellationToken);
+        }
+
+        /// <summary>
+        ///     Factory for JSON protocol objects
+        /// </summary>
+        public class Factory : ITProtocolFactory
+        {
+            public TProtocol GetProtocol(TClientTransport trans)
+            {
+                return new TJsonProtocol(trans);
+            }
+        }
+
+        /// <summary>
+        ///     Base class for tracking JSON contexts that may require
+        ///     inserting/Reading additional JSON syntax characters
+        ///     This base context does nothing.
+        /// </summary>
+        protected class JSONBaseContext
+        {
+            protected TJsonProtocol Proto;
+
+            public JSONBaseContext(TJsonProtocol proto)
+            {
+                Proto = proto;
+            }
+
+            public virtual async Task WriteAsync(CancellationToken cancellationToken)
+            {
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    await Task.FromCanceled(cancellationToken);
+                }
+            }
+
+            public virtual async Task ReadAsync(CancellationToken cancellationToken)
+            {
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    await Task.FromCanceled(cancellationToken);
+                }
+            }
+
+            public virtual bool EscapeNumbers()
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        ///     Context for JSON lists. Will insert/Read commas before each item except
+        ///     for the first one
+        /// </summary>
+        protected class JSONListContext : JSONBaseContext
+        {
+            private bool _first = true;
+
+            public JSONListContext(TJsonProtocol protocol)
+                : base(protocol)
+            {
+            }
+
+            public override async Task WriteAsync(CancellationToken cancellationToken)
+            {
+                if (_first)
+                {
+                    _first = false;
+                }
+                else
+                {
+                    await Proto.Trans.WriteAsync(TJSONProtocolConstants.Comma, cancellationToken);
+                }
+            }
+
+            public override async Task ReadAsync(CancellationToken cancellationToken)
+            {
+                if (_first)
+                {
+                    _first = false;
+                }
+                else
+                {
+                    await Proto.ReadJsonSyntaxCharAsync(TJSONProtocolConstants.Comma, cancellationToken);
+                }
+            }
+        }
+
+        /// <summary>
+        ///     Context for JSON records. Will insert/Read colons before the value portion
+        ///     of each record pair, and commas before each key except the first. In
+        ///     addition, will indicate that numbers in the key position need to be
+        ///     escaped in quotes (since JSON keys must be strings).
+        /// </summary>
+        // ReSharper disable once InconsistentNaming
+        protected class JSONPairContext : JSONBaseContext
+        {
+            private bool _colon = true;
+
+            private bool _first = true;
+
+            public JSONPairContext(TJsonProtocol proto)
+                : base(proto)
+            {
+            }
+
+            public override async Task WriteAsync(CancellationToken cancellationToken)
+            {
+                if (_first)
+                {
+                    _first = false;
+                    _colon = true;
+                }
+                else
+                {
+                    await Proto.Trans.WriteAsync(_colon ? TJSONProtocolConstants.Colon : TJSONProtocolConstants.Comma, cancellationToken);
+                    _colon = !_colon;
+                }
+            }
+
+            public override async Task ReadAsync(CancellationToken cancellationToken)
+            {
+                if (_first)
+                {
+                    _first = false;
+                    _colon = true;
+                }
+                else
+                {
+                    await Proto.ReadJsonSyntaxCharAsync(_colon ? TJSONProtocolConstants.Colon : TJSONProtocolConstants.Comma, cancellationToken);
+                    _colon = !_colon;
+                }
+            }
+
+            public override bool EscapeNumbers()
+            {
+                return _colon;
+            }
+        }
+
+        /// <summary>
+        ///     Holds up to one byte from the transport
+        /// </summary>
+        protected class LookaheadReader
+        {
+            private readonly byte[] _data = new byte[1];
+
+            private bool _hasData;
+            protected TJsonProtocol Proto;
+
+            public LookaheadReader(TJsonProtocol proto)
+            {
+                Proto = proto;
+            }
+
+            /// <summary>
+            ///     Return and consume the next byte to be Read, either taking it from the
+            ///     data buffer if present or getting it from the transport otherwise.
+            /// </summary>
+            public async Task<byte> ReadAsync(CancellationToken cancellationToken)
+            {
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    return await Task.FromCanceled<byte>(cancellationToken);
+                }
+
+                if (_hasData)
+                {
+                    _hasData = false;
+                }
+                else
+                {
+                    // find more easy way to avoid exception on reading primitive types
+                    await Proto.Trans.ReadAllAsync(_data, 0, 1, cancellationToken);
+                }
+                return _data[0];
+            }
+
+            /// <summary>
+            ///     Return the next byte to be Read without consuming, filling the data
+            ///     buffer if it has not been filled alReady.
+            /// </summary>
+            public async Task<byte> PeekAsync(CancellationToken cancellationToken)
+            {
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    return await Task.FromCanceled<byte>(cancellationToken);
+                }
+
+                if (!_hasData)
+                {
+                    // find more easy way to avoid exception on reading primitive types
+                    await Proto.Trans.ReadAllAsync(_data, 0, 1, cancellationToken);
+                }
+                _hasData = true;
+                return _data[0];
+            }
+        }
+    }
+}
diff --git a/lib/netcore/Thrift/Protocols/TMultiplexedProtocol.cs b/lib/netcore/Thrift/Protocols/TMultiplexedProtocol.cs
new file mode 100644
index 0000000..367e4e6
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TMultiplexedProtocol.cs
@@ -0,0 +1,91 @@
+// 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.
+
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols.Entities;
+
+namespace Thrift.Protocols
+{
+    /**
+    * TMultiplexedProtocol is a protocol-independent concrete decorator that allows a Thrift
+    * client to communicate with a multiplexing Thrift server, by prepending the service name
+    * to the function name during function calls.
+    *
+    * NOTE: THIS IS NOT TO BE USED BY SERVERS.
+    * On the server, use TMultiplexedProcessor to handle requests from a multiplexing client.
+    *
+    * This example uses a single socket transport to invoke two services:
+    *
+    *     TSocketClientTransport transport = new TSocketClientTransport("localhost", 9090);
+    *     transport.open();
+    *
+    *     TBinaryProtocol protocol = new TBinaryProtocol(transport);
+    *
+    *     TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "Calculator");
+    *     Calculator.Client service = new Calculator.Client(mp);
+    *
+    *     TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, "WeatherReport");
+    *     WeatherReport.Client service2 = new WeatherReport.Client(mp2);
+    *
+    *     System.out.println(service.add(2,2));
+    *     System.out.println(service2.getTemperature());
+    *
+    */
+
+    //TODO: implementation of TProtocol
+
+    // ReSharper disable once InconsistentNaming
+    public class TMultiplexedProtocol : TProtocolDecorator
+    {
+        /** Used to delimit the service name from the function name */
+        public const string Separator = ":";
+
+        private readonly string _serviceName;
+
+        /**
+         * Wrap the specified protocol, allowing it to be used to communicate with a
+         * multiplexing server.  The <code>serviceName</code> is required as it is
+         * prepended to the message header so that the multiplexing server can broker
+         * the function call to the proper service.
+         *
+         * Args:
+         *  protocol        Your communication protocol of choice, e.g. TBinaryProtocol
+         *  serviceName     The service name of the service communicating via this protocol.
+         */
+
+        public TMultiplexedProtocol(TProtocol protocol, string serviceName)
+            : base(protocol)
+        {
+            _serviceName = serviceName;
+        }
+
+        public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
+        {
+            switch (message.Type)
+            {
+                case TMessageType.Call:
+                case TMessageType.Oneway:
+                    await base.WriteMessageBeginAsync(new TMessage($"{_serviceName}{Separator}{message.Name}", message.Type, message.SeqID), cancellationToken);
+                    break;
+                default:
+                    await base.WriteMessageBeginAsync(message, cancellationToken);
+                    break;
+            }
+        }
+    }
+}
diff --git a/lib/netcore/Thrift/Protocols/TProtocol.cs b/lib/netcore/Thrift/Protocols/TProtocol.cs
new file mode 100644
index 0000000..91e009d
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TProtocol.cs
@@ -0,0 +1,376 @@
+// 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.
+
+using System;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols.Entities;
+using Thrift.Transports;
+
+namespace Thrift.Protocols
+{
+    // ReSharper disable once InconsistentNaming
+    public abstract class TProtocol : IDisposable
+    {
+        public const int DefaultRecursionDepth = 64;
+        private bool _isDisposed;
+        protected int RecursionDepth;
+
+        protected TClientTransport Trans;
+
+        protected TProtocol(TClientTransport trans)
+        {
+            Trans = trans;
+            RecursionLimit = DefaultRecursionDepth;
+            RecursionDepth = 0;
+        }
+
+        public TClientTransport Transport => Trans;
+
+        protected int RecursionLimit { get; set; }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        public void IncrementRecursionDepth()
+        {
+            if (RecursionDepth < RecursionLimit)
+            {
+                ++RecursionDepth;
+            }
+            else
+            {
+                throw new TProtocolException(TProtocolException.DEPTH_LIMIT, "Depth limit exceeded");
+            }
+        }
+
+        public void DecrementRecursionDepth()
+        {
+            --RecursionDepth;
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_isDisposed)
+            {
+                if (disposing)
+                {
+                    (Trans as IDisposable)?.Dispose();
+                }
+            }
+            _isDisposed = true;
+        }
+
+        public virtual async Task WriteMessageBeginAsync(TMessage message)
+        {
+            await WriteMessageBeginAsync(message, CancellationToken.None);
+        }
+
+        public abstract Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken);
+
+        public virtual async Task WriteMessageEndAsync()
+        {
+            await WriteMessageEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteMessageEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteStructBeginAsync(TStruct @struct)
+        {
+            await WriteStructBeginAsync(@struct, CancellationToken.None);
+        }
+
+        public abstract Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken);
+
+        public virtual async Task WriteStructEndAsync()
+        {
+            await WriteStructEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteStructEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteFieldBeginAsync(TField field)
+        {
+            await WriteFieldBeginAsync(field, CancellationToken.None);
+        }
+
+        public abstract Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken);
+
+        public virtual async Task WriteFieldEndAsync()
+        {
+            await WriteFieldEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteFieldEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteFieldStopAsync()
+        {
+            await WriteFieldStopAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteFieldStopAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteMapBeginAsync(TMap map)
+        {
+            await WriteMapBeginAsync(map, CancellationToken.None);
+        }
+
+        public abstract Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken);
+
+        public virtual async Task WriteMapEndAsync()
+        {
+            await WriteMapEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteMapEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteListBeginAsync(TList list)
+        {
+            await WriteListBeginAsync(list, CancellationToken.None);
+        }
+
+        public abstract Task WriteListBeginAsync(TList list, CancellationToken cancellationToken);
+
+        public virtual async Task WriteListEndAsync()
+        {
+            await WriteListEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteListEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteSetBeginAsync(TSet set)
+        {
+            await WriteSetBeginAsync(set, CancellationToken.None);
+        }
+
+        public abstract Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken);
+
+        public virtual async Task WriteSetEndAsync()
+        {
+            await WriteSetEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task WriteSetEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task WriteBoolAsync(bool b)
+        {
+            await WriteBoolAsync(b, CancellationToken.None);
+        }
+
+        public abstract Task WriteBoolAsync(bool b, CancellationToken cancellationToken);
+
+        public virtual async Task WriteByteAsync(sbyte b)
+        {
+            await WriteByteAsync(b, CancellationToken.None);
+        }
+
+        public abstract Task WriteByteAsync(sbyte b, CancellationToken cancellationToken);
+
+        public virtual async Task WriteI16Async(short i16)
+        {
+            await WriteI16Async(i16, CancellationToken.None);
+        }
+
+        public abstract Task WriteI16Async(short i16, CancellationToken cancellationToken);
+
+        public virtual async Task WriteI32Async(int i32)
+        {
+            await WriteI32Async(i32, CancellationToken.None);
+        }
+
+        public abstract Task WriteI32Async(int i32, CancellationToken cancellationToken);
+
+        public virtual async Task WriteI64Async(long i64)
+        {
+            await WriteI64Async(i64, CancellationToken.None);
+        }
+
+        public abstract Task WriteI64Async(long i64, CancellationToken cancellationToken);
+
+        public virtual async Task WriteDoubleAsync(double d)
+        {
+            await WriteDoubleAsync(d, CancellationToken.None);
+        }
+
+        public abstract Task WriteDoubleAsync(double d, CancellationToken cancellationToken);
+
+        public virtual async Task WriteStringAsync(string s)
+        {
+            await WriteStringAsync(s, CancellationToken.None);
+        }
+
+        public virtual async Task WriteStringAsync(string s, CancellationToken cancellationToken)
+        {
+            var bytes = Encoding.UTF8.GetBytes(s);
+            await WriteBinaryAsync(bytes, cancellationToken);
+        }
+
+        public virtual async Task WriteBinaryAsync(byte[] bytes)
+        {
+            await WriteBinaryAsync(bytes, CancellationToken.None);
+        }
+
+        public abstract Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken);
+
+        public virtual async Task<TMessage> ReadMessageBeginAsync()
+        {
+            return await ReadMessageBeginAsync(CancellationToken.None);
+        }
+
+        public abstract Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken);
+
+        public virtual async Task ReadMessageEndAsync()
+        {
+            await ReadMessageEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task ReadMessageEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<TStruct> ReadStructBeginAsync()
+        {
+            return await ReadStructBeginAsync(CancellationToken.None);
+        }
+
+        public abstract Task<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken);
+
+        public virtual async Task ReadStructEndAsync()
+        {
+            await ReadStructEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task ReadStructEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<TField> ReadFieldBeginAsync()
+        {
+            return await ReadFieldBeginAsync(CancellationToken.None);
+        }
+
+        public abstract Task<TField> ReadFieldBeginAsync(CancellationToken cancellationToken);
+
+        public virtual async Task ReadFieldEndAsync()
+        {
+            await ReadFieldEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task ReadFieldEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<TMap> ReadMapBeginAsync()
+        {
+            return await ReadMapBeginAsync(CancellationToken.None);
+        }
+
+        public abstract Task<TMap> ReadMapBeginAsync(CancellationToken cancellationToken);
+
+        public virtual async Task ReadMapEndAsync()
+        {
+            await ReadMapEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task ReadMapEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<TList> ReadListBeginAsync()
+        {
+            return await ReadListBeginAsync(CancellationToken.None);
+        }
+
+        public abstract Task<TList> ReadListBeginAsync(CancellationToken cancellationToken);
+
+        public virtual async Task ReadListEndAsync()
+        {
+            await ReadListEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task ReadListEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<TSet> ReadSetBeginAsync()
+        {
+            return await ReadSetBeginAsync(CancellationToken.None);
+        }
+
+        public abstract Task<TSet> ReadSetBeginAsync(CancellationToken cancellationToken);
+
+        public virtual async Task ReadSetEndAsync()
+        {
+            await ReadSetEndAsync(CancellationToken.None);
+        }
+
+        public abstract Task ReadSetEndAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<bool> ReadBoolAsync()
+        {
+            return await ReadBoolAsync(CancellationToken.None);
+        }
+
+        public abstract Task<bool> ReadBoolAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<sbyte> ReadByteAsync()
+        {
+            return await ReadByteAsync(CancellationToken.None);
+        }
+
+        public abstract Task<sbyte> ReadByteAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<short> ReadI16Async()
+        {
+            return await ReadI16Async(CancellationToken.None);
+        }
+
+        public abstract Task<short> ReadI16Async(CancellationToken cancellationToken);
+
+        public virtual async Task<int> ReadI32Async()
+        {
+            return await ReadI32Async(CancellationToken.None);
+        }
+
+        public abstract Task<int> ReadI32Async(CancellationToken cancellationToken);
+
+        public virtual async Task<long> ReadI64Async()
+        {
+            return await ReadI64Async(CancellationToken.None);
+        }
+
+        public abstract Task<long> ReadI64Async(CancellationToken cancellationToken);
+
+        public virtual async Task<double> ReadDoubleAsync()
+        {
+            return await ReadDoubleAsync(CancellationToken.None);
+        }
+
+        public abstract Task<double> ReadDoubleAsync(CancellationToken cancellationToken);
+
+        public virtual async Task<string> ReadStringAsync()
+        {
+            return await ReadStringAsync(CancellationToken.None);
+        }
+
+        public virtual async Task<string> ReadStringAsync(CancellationToken cancellationToken)
+        {
+            var buf = await ReadBinaryAsync(cancellationToken);
+            return Encoding.UTF8.GetString(buf, 0, buf.Length);
+        }
+
+        public virtual async Task<byte[]> ReadBinaryAsync()
+        {
+            return await ReadBinaryAsync(CancellationToken.None);
+        }
+
+        public abstract Task<byte[]> ReadBinaryAsync(CancellationToken cancellationToken);
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/TProtocolDecorator.cs b/lib/netcore/Thrift/Protocols/TProtocolDecorator.cs
new file mode 100644
index 0000000..3222754
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TProtocolDecorator.cs
@@ -0,0 +1,247 @@
+// 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.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols.Entities;
+
+namespace Thrift.Protocols
+{
+    // ReSharper disable once InconsistentNaming
+    /// <summary>
+    ///     TProtocolDecorator forwards all requests to an enclosed TProtocol instance,
+    ///     providing a way to author concise concrete decorator subclasses.While it has
+    ///     no abstract methods, it is marked abstract as a reminder that by itself,
+    ///     it does not modify the behaviour of the enclosed TProtocol.
+    /// </summary>
+    public abstract class TProtocolDecorator : TProtocol
+    {
+        private readonly TProtocol _wrappedProtocol;
+
+        protected TProtocolDecorator(TProtocol protocol)
+            : base(protocol.Transport)
+        {
+            _wrappedProtocol = protocol ?? throw new ArgumentNullException(nameof(protocol));
+        }
+
+        public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteMessageBeginAsync(message, cancellationToken);
+        }
+
+        public override async Task WriteMessageEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteMessageEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteStructBeginAsync(@struct, cancellationToken);
+        }
+
+        public override async Task WriteStructEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteStructEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteFieldBeginAsync(field, cancellationToken);
+        }
+
+        public override async Task WriteFieldEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteFieldEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteFieldStopAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteFieldStopAsync(cancellationToken);
+        }
+
+        public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteMapBeginAsync(map, cancellationToken);
+        }
+
+        public override async Task WriteMapEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteMapEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteListBeginAsync(list, cancellationToken);
+        }
+
+        public override async Task WriteListEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteListEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteSetBeginAsync(set, cancellationToken);
+        }
+
+        public override async Task WriteSetEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteSetEndAsync(cancellationToken);
+        }
+
+        public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteBoolAsync(b, cancellationToken);
+        }
+
+        public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteByteAsync(b, cancellationToken);
+        }
+
+        public override async Task WriteI16Async(short i16, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteI16Async(i16, cancellationToken);
+        }
+
+        public override async Task WriteI32Async(int i32, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteI32Async(i32, cancellationToken);
+        }
+
+        public override async Task WriteI64Async(long i64, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteI64Async(i64, cancellationToken);
+        }
+
+        public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteDoubleAsync(d, cancellationToken);
+        }
+
+        public override async Task WriteStringAsync(string s, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteStringAsync(s, cancellationToken);
+        }
+
+        public override async Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteBinaryAsync(bytes, cancellationToken);
+        }
+
+        public override async Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadMessageBeginAsync(cancellationToken);
+        }
+
+        public override async Task ReadMessageEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.ReadMessageEndAsync(cancellationToken);
+        }
+
+        public override async Task<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadStructBeginAsync(cancellationToken);
+        }
+
+        public override async Task ReadStructEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.ReadStructEndAsync(cancellationToken);
+        }
+
+        public override async Task<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadFieldBeginAsync(cancellationToken);
+        }
+
+        public override async Task ReadFieldEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.ReadFieldEndAsync(cancellationToken);
+        }
+
+        public override async Task<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadMapBeginAsync(cancellationToken);
+        }
+
+        public override async Task ReadMapEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.ReadMapEndAsync(cancellationToken);
+        }
+
+        public override async Task<TList> ReadListBeginAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadListBeginAsync(cancellationToken);
+        }
+
+        public override async Task ReadListEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.ReadListEndAsync(cancellationToken);
+        }
+
+        public override async Task<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadSetBeginAsync(cancellationToken);
+        }
+
+        public override async Task ReadSetEndAsync(CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.ReadSetEndAsync(cancellationToken);
+        }
+
+        public override async Task<bool> ReadBoolAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadBoolAsync(cancellationToken);
+        }
+
+        public override async Task<sbyte> ReadByteAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadByteAsync(cancellationToken);
+        }
+
+        public override async Task<short> ReadI16Async(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadI16Async(cancellationToken);
+        }
+
+        public override async Task<int> ReadI32Async(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadI32Async(cancellationToken);
+        }
+
+        public override async Task<long> ReadI64Async(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadI64Async(cancellationToken);
+        }
+
+        public override async Task<double> ReadDoubleAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadDoubleAsync(cancellationToken);
+        }
+
+        public override async Task<string> ReadStringAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadStringAsync(cancellationToken);
+        }
+
+        public override async Task<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadBinaryAsync(cancellationToken);
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/TProtocolException.cs b/lib/netcore/Thrift/Protocols/TProtocolException.cs
new file mode 100644
index 0000000..8c67c3b
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/TProtocolException.cs
@@ -0,0 +1,59 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// ReSharper disable InconsistentNaming
+namespace Thrift.Protocols
+{
+    public class TProtocolException : TException
+    {
+        // do not rename public constants - they used in generated files
+        public const int UNKNOWN = 0;
+        public const int INVALID_DATA = 1;
+        public const int NEGATIVE_SIZE = 2;
+        public const int SIZE_LIMIT = 3;
+        public const int BAD_VERSION = 4;
+        public const int NOT_IMPLEMENTED = 5;
+        public const int DEPTH_LIMIT = 6;
+
+        protected int Type = UNKNOWN;
+
+        public TProtocolException()
+        {
+        }
+
+        public TProtocolException(int type)
+        {
+            Type = type;
+        }
+
+        public TProtocolException(int type, string message)
+            : base(message)
+        {
+            Type = type;
+        }
+
+        public TProtocolException(string message)
+            : base(message)
+        {
+        }
+
+        public int GetExceptionType()
+        {
+            return Type;
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/Utilities/TBase64Helper.cs b/lib/netcore/Thrift/Protocols/Utilities/TBase64Helper.cs
new file mode 100644
index 0000000..7eff5e1
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Utilities/TBase64Helper.cs
@@ -0,0 +1,101 @@
+// 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.
+
+using System;
+
+namespace Thrift.Protocols.Utilities
+{
+    // ReSharper disable once InconsistentNaming
+    internal static class TBase64Helper
+    {
+        //TODO: Constants
+        //TODO: Check for args
+        //TODO: Unitests
+
+        internal const string EncodeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+        private static readonly int[] DecodeTable =
+        {
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+            -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+        };
+
+        internal static void Encode(byte[] src, int srcOff, int len, byte[] dst, int dstOff)
+        {
+            if (src == null)
+            {
+                throw new ArgumentNullException(nameof(src));
+            }
+
+            dst[dstOff] = (byte) EncodeTable[(src[srcOff] >> 2) & 0x3F];
+
+            if (len == 3)
+            {
+                dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+                dst[dstOff + 2] = (byte) EncodeTable[((src[srcOff + 1] << 2) & 0x3C) | ((src[srcOff + 2] >> 6) & 0x03)];
+                dst[dstOff + 3] = (byte) EncodeTable[src[srcOff + 2] & 0x3F];
+            }
+            else if (len == 2)
+            {
+                dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+                dst[dstOff + 2] = (byte) EncodeTable[(src[srcOff + 1] << 2) & 0x3C];
+            }
+            else
+            {
+                // len == 1
+                dst[dstOff + 1] = (byte) EncodeTable[(src[srcOff] << 4) & 0x30];
+            }
+        }
+
+        internal static void Decode(byte[] src, int srcOff, int len, byte[] dst, int dstOff)
+        {
+            if (src == null)
+            {
+                throw new ArgumentNullException(nameof(src));
+            }
+
+            dst[dstOff] = (byte) ((DecodeTable[src[srcOff] & 0x0FF] << 2) | (DecodeTable[src[srcOff + 1] & 0x0FF] >> 4));
+
+            if (len > 2)
+            {
+                dst[dstOff + 1] =
+                    (byte)
+                    (((DecodeTable[src[srcOff + 1] & 0x0FF] << 4) & 0xF0) | (DecodeTable[src[srcOff + 2] & 0x0FF] >> 2));
+                if (len > 3)
+                {
+                    dst[dstOff + 2] =
+                        (byte)
+                        (((DecodeTable[src[srcOff + 2] & 0x0FF] << 6) & 0xC0) | DecodeTable[src[srcOff + 3] & 0x0FF]);
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/Utilities/TBase64Utils.cs b/lib/netcore/Thrift/Protocols/Utilities/TBase64Utils.cs
new file mode 100644
index 0000000..15fd45c
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Utilities/TBase64Utils.cs
@@ -0,0 +1,101 @@
+// 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.
+
+using System;
+
+namespace Thrift.Protocols.Utilities
+{
+    // ReSharper disable once InconsistentNaming
+    internal static class TBase64Utils
+    {
+        //TODO: Constants
+        //TODO: Check for args
+        //TODO: Unitests
+
+        internal const string EncodeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+        private static readonly int[] DecodeTable =
+        {
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+            -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+        };
+
+        internal static void Encode(byte[] src, int srcOff, int len, byte[] dst, int dstOff)
+        {
+            if (src == null)
+            {
+                throw new ArgumentNullException(nameof(src));
+            }
+
+            dst[dstOff] = (byte) EncodeTable[(src[srcOff] >> 2) & 0x3F];
+
+            if (len == 3)
+            {
+                dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+                dst[dstOff + 2] = (byte) EncodeTable[((src[srcOff + 1] << 2) & 0x3C) | ((src[srcOff + 2] >> 6) & 0x03)];
+                dst[dstOff + 3] = (byte) EncodeTable[src[srcOff + 2] & 0x3F];
+            }
+            else if (len == 2)
+            {
+                dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
+                dst[dstOff + 2] = (byte) EncodeTable[(src[srcOff + 1] << 2) & 0x3C];
+            }
+            else
+            {
+                // len == 1
+                dst[dstOff + 1] = (byte) EncodeTable[(src[srcOff] << 4) & 0x30];
+            }
+        }
+
+        internal static void Decode(byte[] src, int srcOff, int len, byte[] dst, int dstOff)
+        {
+            if (src == null)
+            {
+                throw new ArgumentNullException(nameof(src));
+            }
+
+            dst[dstOff] = (byte) ((DecodeTable[src[srcOff] & 0x0FF] << 2) | (DecodeTable[src[srcOff + 1] & 0x0FF] >> 4));
+
+            if (len > 2)
+            {
+                dst[dstOff + 1] =
+                    (byte)
+                    (((DecodeTable[src[srcOff + 1] & 0x0FF] << 4) & 0xF0) | (DecodeTable[src[srcOff + 2] & 0x0FF] >> 2));
+                if (len > 3)
+                {
+                    dst[dstOff + 2] =
+                        (byte)
+                        (((DecodeTable[src[srcOff + 2] & 0x0FF] << 6) & 0xC0) | DecodeTable[src[srcOff + 3] & 0x0FF]);
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/Utilities/TJsonProtocolConstants.cs b/lib/netcore/Thrift/Protocols/Utilities/TJsonProtocolConstants.cs
new file mode 100644
index 0000000..93eff78
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Utilities/TJsonProtocolConstants.cs
@@ -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.
+
+namespace Thrift.Protocols.Utilities
+{
+    // ReSharper disable once InconsistentNaming
+    public static class TJSONProtocolConstants
+    {
+        //TODO Check for performance for reusing ImmutableArray from System.Collections.Immutable (https://blogs.msdn.microsoft.com/dotnet/2013/06/24/please-welcome-immutablearrayt/)
+        // can be possible to get better performance and also better GC
+
+        public static readonly byte[] Comma = {(byte) ','};
+        public static readonly byte[] Colon = {(byte) ':'};
+        public static readonly byte[] LeftBrace = {(byte) '{'};
+        public static readonly byte[] RightBrace = {(byte) '}'};
+        public static readonly byte[] LeftBracket = {(byte) '['};
+        public static readonly byte[] RightBracket = {(byte) ']'};
+        public static readonly byte[] Quote = {(byte) '"'};
+        public static readonly byte[] Backslash = {(byte) '\\'};
+
+        public static readonly byte[] JsonCharTable =
+        {
+            0, 0, 0, 0, 0, 0, 0, 0, (byte) 'b', (byte) 't', (byte) 'n', 0, (byte) 'f', (byte) 'r', 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            1, 1, (byte) '"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+        };
+
+        public static readonly char[] EscapeChars = "\"\\/bfnrt".ToCharArray();
+        public static readonly byte[] EscapeCharValues = {(byte) '"', (byte) '\\', (byte) '/', (byte) '\b', (byte) '\f', (byte) '\n', (byte) '\r', (byte) '\t'};
+        public static readonly byte[] EscSequences = {(byte) '\\', (byte) 'u', (byte) '0', (byte) '0'};
+
+        public static class TypeNames
+        {
+            public static readonly byte[] NameBool = { (byte)'t', (byte)'f' };
+            public static readonly byte[] NameByte = { (byte)'i', (byte)'8' };
+            public static readonly byte[] NameI16 = { (byte)'i', (byte)'1', (byte)'6' };
+            public static readonly byte[] NameI32 = { (byte)'i', (byte)'3', (byte)'2' };
+            public static readonly byte[] NameI64 = { (byte)'i', (byte)'6', (byte)'4' };
+            public static readonly byte[] NameDouble = { (byte)'d', (byte)'b', (byte)'l' };
+            public static readonly byte[] NameStruct = { (byte)'r', (byte)'e', (byte)'c' };
+            public static readonly byte[] NameString = { (byte)'s', (byte)'t', (byte)'r' };
+            public static readonly byte[] NameMap = { (byte)'m', (byte)'a', (byte)'p' };
+            public static readonly byte[] NameList = { (byte)'l', (byte)'s', (byte)'t' };
+            public static readonly byte[] NameSet = { (byte)'s', (byte)'e', (byte)'t' };
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/Utilities/TJsonProtocolHelper.cs b/lib/netcore/Thrift/Protocols/Utilities/TJsonProtocolHelper.cs
new file mode 100644
index 0000000..adc26a9
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Utilities/TJsonProtocolHelper.cs
@@ -0,0 +1,176 @@
+// 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.
+
+using Thrift.Protocols.Entities;
+
+namespace Thrift.Protocols.Utilities
+{
+    // ReSharper disable once InconsistentNaming
+    public static class TJSONProtocolHelper
+    {
+        public static byte[] GetTypeNameForTypeId(TType typeId)
+        {
+            switch (typeId)
+            {
+                case TType.Bool:
+                    return TJSONProtocolConstants.TypeNames.NameBool;
+                case TType.Byte:
+                    return TJSONProtocolConstants.TypeNames.NameByte;
+                case TType.I16:
+                    return TJSONProtocolConstants.TypeNames.NameI16;
+                case TType.I32:
+                    return TJSONProtocolConstants.TypeNames.NameI32;
+                case TType.I64:
+                    return TJSONProtocolConstants.TypeNames.NameI64;
+                case TType.Double:
+                    return TJSONProtocolConstants.TypeNames.NameDouble;
+                case TType.String:
+                    return TJSONProtocolConstants.TypeNames.NameString;
+                case TType.Struct:
+                    return TJSONProtocolConstants.TypeNames.NameStruct;
+                case TType.Map:
+                    return TJSONProtocolConstants.TypeNames.NameMap;
+                case TType.Set:
+                    return TJSONProtocolConstants.TypeNames.NameSet;
+                case TType.List:
+                    return TJSONProtocolConstants.TypeNames.NameList;
+                default:
+                    throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized exType");
+            }
+        }
+
+        public static TType GetTypeIdForTypeName(byte[] name)
+        {
+            var result = TType.Stop;
+            if (name.Length > 1)
+            {
+                switch (name[0])
+                {
+                    case (byte) 'd':
+                        result = TType.Double;
+                        break;
+                    case (byte) 'i':
+                        switch (name[1])
+                        {
+                            case (byte) '8':
+                                result = TType.Byte;
+                                break;
+                            case (byte) '1':
+                                result = TType.I16;
+                                break;
+                            case (byte) '3':
+                                result = TType.I32;
+                                break;
+                            case (byte) '6':
+                                result = TType.I64;
+                                break;
+                        }
+                        break;
+                    case (byte) 'l':
+                        result = TType.List;
+                        break;
+                    case (byte) 'm':
+                        result = TType.Map;
+                        break;
+                    case (byte) 'r':
+                        result = TType.Struct;
+                        break;
+                    case (byte) 's':
+                        if (name[1] == (byte) 't')
+                        {
+                            result = TType.String;
+                        }
+                        else if (name[1] == (byte) 'e')
+                        {
+                            result = TType.Set;
+                        }
+                        break;
+                    case (byte) 't':
+                        result = TType.Bool;
+                        break;
+                }
+            }
+            if (result == TType.Stop)
+            {
+                throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized exType");
+            }
+            return result;
+        }
+
+        /// <summary>
+        ///     Return true if the given byte could be a valid part of a JSON number.
+        /// </summary>
+        public static bool IsJsonNumeric(byte b)
+        {
+            switch (b)
+            {
+                case (byte)'+':
+                case (byte)'-':
+                case (byte)'.':
+                case (byte)'0':
+                case (byte)'1':
+                case (byte)'2':
+                case (byte)'3':
+                case (byte)'4':
+                case (byte)'5':
+                case (byte)'6':
+                case (byte)'7':
+                case (byte)'8':
+                case (byte)'9':
+                case (byte)'E':
+                case (byte)'e':
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        /// <summary>
+        ///     Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its
+        ///     corresponding hex value
+        /// </summary>
+        public static byte ToHexVal(byte ch)
+        {
+            if (ch >= '0' && ch <= '9')
+            {
+                return (byte)((char)ch - '0');
+            }
+
+            if (ch >= 'a' && ch <= 'f')
+            {
+                ch += 10;
+                return (byte)((char)ch - 'a');
+            }
+
+            throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected hex character");
+        }
+
+        /// <summary>
+        ///     Convert a byte containing a hex value to its corresponding hex character
+        /// </summary>
+        public static byte ToHexChar(byte val)
+        {
+            val &= 0x0F;
+            if (val < 10)
+            {
+                return (byte)((char)val + '0');
+            }
+            val -= 10;
+            return (byte)((char)val + 'a');
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Protocols/Utilities/TProtocolUtil.cs b/lib/netcore/Thrift/Protocols/Utilities/TProtocolUtil.cs
new file mode 100644
index 0000000..50b0385
--- /dev/null
+++ b/lib/netcore/Thrift/Protocols/Utilities/TProtocolUtil.cs
@@ -0,0 +1,110 @@
+// 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.
+
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols.Entities;
+
+namespace Thrift.Protocols.Utilities
+{
+    // ReSharper disable once InconsistentNaming
+    public static class TProtocolUtil
+    {
+        public static async Task SkipAsync(TProtocol protocol, TType type, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+
+            protocol.IncrementRecursionDepth();
+            try
+            {
+                switch (type)
+                {
+                    case TType.Bool:
+                        await protocol.ReadBoolAsync(cancellationToken);
+                        break;
+                    case TType.Byte:
+                        await protocol.ReadByteAsync(cancellationToken);
+                        break;
+                    case TType.I16:
+                        await protocol.ReadI16Async(cancellationToken);
+                        break;
+                    case TType.I32:
+                        await protocol.ReadI32Async(cancellationToken);
+                        break;
+                    case TType.I64:
+                        await protocol.ReadI64Async(cancellationToken);
+                        break;
+                    case TType.Double:
+                        await protocol.ReadDoubleAsync(cancellationToken);
+                        break;
+                    case TType.String:
+                        // Don't try to decode the string, just skip it.
+                        await protocol.ReadBinaryAsync(cancellationToken);
+                        break;
+                    case TType.Struct:
+                        await protocol.ReadStructBeginAsync(cancellationToken);
+                        while (true)
+                        {
+                            var field = await protocol.ReadFieldBeginAsync(cancellationToken);
+                            if (field.Type == TType.Stop)
+                            {
+                                break;
+                            }
+                            await SkipAsync(protocol, field.Type, cancellationToken);
+                            await protocol.ReadFieldEndAsync(cancellationToken);
+                        }
+                        await protocol.ReadStructEndAsync(cancellationToken);
+                        break;
+                    case TType.Map:
+                        var map = await protocol.ReadMapBeginAsync(cancellationToken);
+                        for (var i = 0; i < map.Count; i++)
+                        {
+                            await SkipAsync(protocol, map.KeyType, cancellationToken);
+                            await SkipAsync(protocol, map.ValueType, cancellationToken);
+                        }
+                        await protocol.ReadMapEndAsync(cancellationToken);
+                        break;
+                    case TType.Set:
+                        var set = await protocol.ReadSetBeginAsync(cancellationToken);
+                        for (var i = 0; i < set.Count; i++)
+                        {
+                            await SkipAsync(protocol, set.ElementType, cancellationToken);
+                        }
+                        await protocol.ReadSetEndAsync(cancellationToken);
+                        break;
+                    case TType.List:
+                        var list = await protocol.ReadListBeginAsync(cancellationToken);
+                        for (var i = 0; i < list.Count; i++)
+                        {
+                            await SkipAsync(protocol, list.ElementType, cancellationToken);
+                        }
+                        await protocol.ReadListEndAsync(cancellationToken);
+                        break;
+                    default:
+                        throw new TProtocolException(TProtocolException.INVALID_DATA, "Unknown data type " + type.ToString("d"));
+                }
+            }
+            finally
+            {
+                protocol.DecrementRecursionDepth();
+            }
+        }
+    }
+}
diff --git a/lib/netcore/Thrift/Server/AsyncBaseServer.cs b/lib/netcore/Thrift/Server/AsyncBaseServer.cs
new file mode 100644
index 0000000..325c39c
--- /dev/null
+++ b/lib/netcore/Thrift/Server/AsyncBaseServer.cs
@@ -0,0 +1,183 @@
+// 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.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Thrift.Protocols;
+using Thrift.Transports;
+
+namespace Thrift.Server
+{
+    //TODO: unhandled exceptions, etc.
+
+    // ReSharper disable once InconsistentNaming
+    public class AsyncBaseServer : TBaseServer
+    {
+        private readonly int _clientWaitingDelay;
+        private volatile Task _serverTask;
+
+        public AsyncBaseServer(ITAsyncProcessor processor, TServerTransport serverTransport,
+            ITProtocolFactory inputProtocolFactory, ITProtocolFactory outputProtocolFactory,
+            ILoggerFactory loggerFactory, int clientWaitingDelay = 10)
+            : this(new SingletonTProcessorFactory(processor), serverTransport,
+                new TTransportFactory(), new TTransportFactory(),
+                inputProtocolFactory, outputProtocolFactory,
+                loggerFactory.CreateLogger(nameof(AsyncBaseServer)), clientWaitingDelay)
+        {
+        }
+
+        public AsyncBaseServer(ITProcessorFactory itProcessorFactory, TServerTransport serverTransport,
+            TTransportFactory inputTransportFactory, TTransportFactory outputTransportFactory,
+            ITProtocolFactory inputProtocolFactory, ITProtocolFactory outputProtocolFactory,
+            ILogger logger, int clientWaitingDelay = 10)
+            : base(itProcessorFactory, serverTransport, inputTransportFactory, outputTransportFactory,
+                inputProtocolFactory, outputProtocolFactory, logger)
+        {
+            _clientWaitingDelay = clientWaitingDelay;
+        }
+
+        public override async Task ServeAsync(CancellationToken cancellationToken)
+        {
+            try
+            {
+                // cancelation token
+                _serverTask = Task.Factory.StartNew(() => StartListening(cancellationToken), TaskCreationOptions.LongRunning);
+                await _serverTask;
+            }
+            catch (Exception ex)
+            {
+                Logger.LogError(ex.ToString());
+            }
+        }
+
+        private async Task StartListening(CancellationToken cancellationToken)
+        {
+            ServerTransport.Listen();
+
+            Logger.LogTrace("Started listening at server");
+
+            if (ServerEventHandler != null)
+            {
+                await ServerEventHandler.PreServeAsync(cancellationToken);
+            }
+
+            while (!cancellationToken.IsCancellationRequested)
+            {
+                if (ServerTransport.IsClientPending())
+                {
+                    Logger.LogTrace("Waiting for client connection");
+
+                    try
+                    {
+                        var client = await ServerTransport.AcceptAsync(cancellationToken);
+                        await Task.Factory.StartNew(() => Execute(client, cancellationToken), cancellationToken);
+                    }
+                    catch (TTransportException ttx)
+                    {
+                        Logger.LogTrace($"Transport exception: {ttx}");
+
+                        if (ttx.Type != TTransportException.ExceptionType.Interrupted)
+                        {
+                            Logger.LogError(ttx.ToString());
+                        }
+                    }
+                }
+                else
+                {
+                    try
+                    {
+                        await Task.Delay(TimeSpan.FromMilliseconds(_clientWaitingDelay), cancellationToken);
+                    }
+                    catch(TaskCanceledException) { }
+                }
+            }
+
+            ServerTransport.Close();
+
+            Logger.LogTrace("Completed listening at server");
+        }
+
+        public override void Stop()
+        {
+        }
+
+        private async Task Execute(TClientTransport client, CancellationToken cancellationToken)
+        {
+            Logger.LogTrace("Started client request processing");
+
+            var processor = ItProcessorFactory.GetAsyncProcessor(client, this);
+
+            TClientTransport inputTransport = null;
+            TClientTransport outputTransport = null;
+            TProtocol inputProtocol = null;
+            TProtocol outputProtocol = null;
+            object connectionContext = null;
+
+            try
+            {
+                inputTransport = InputTransportFactory.GetTransport(client);
+                outputTransport = OutputTransportFactory.GetTransport(client);
+
+                inputProtocol = InputProtocolFactory.GetProtocol(inputTransport);
+                outputProtocol = OutputProtocolFactory.GetProtocol(outputTransport);
+
+                if (ServerEventHandler != null)
+                {
+                    connectionContext = await ServerEventHandler.CreateContextAsync(inputProtocol, outputProtocol, cancellationToken);
+                }
+
+                while (!cancellationToken.IsCancellationRequested)
+                {
+                    if (!await inputTransport.PeekAsync(cancellationToken))
+                    {
+                        break;
+                    }
+
+                    if (ServerEventHandler != null)
+                    {
+                        await ServerEventHandler.ProcessContextAsync(connectionContext, inputTransport, cancellationToken);
+                    }
+
+                    if (!await processor.ProcessAsync(inputProtocol, outputProtocol, cancellationToken))
+                    {
+                        break;
+                    }
+                }
+            }
+            catch (TTransportException ttx)
+            {
+                Logger.LogTrace($"Transport exception: {ttx}");
+            }
+            catch (Exception x)
+            {
+                Logger.LogError($"Error: {x}");
+            }
+
+            if (ServerEventHandler != null)
+            {
+                await ServerEventHandler.DeleteContextAsync(connectionContext, inputProtocol, outputProtocol, cancellationToken);
+            }
+
+            inputTransport?.Close();
+            outputTransport?.Close();
+
+            Logger.LogTrace("Completed client request processing");
+        }
+    }
+}
diff --git a/lib/netcore/Thrift/Server/TBaseServer.cs b/lib/netcore/Thrift/Server/TBaseServer.cs
new file mode 100644
index 0000000..741dd5c
--- /dev/null
+++ b/lib/netcore/Thrift/Server/TBaseServer.cs
@@ -0,0 +1,79 @@
+// 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.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Thrift.Protocols;
+using Thrift.Transports;
+
+namespace Thrift.Server
+{
+    // ReSharper disable once InconsistentNaming
+    public abstract class TBaseServer
+    {
+        protected readonly ILogger Logger;
+        protected ITProtocolFactory InputProtocolFactory;
+        protected TTransportFactory InputTransportFactory;
+        protected ITProcessorFactory ItProcessorFactory;
+        protected ITProtocolFactory OutputProtocolFactory;
+        protected TTransportFactory OutputTransportFactory;
+
+        protected TServerEventHandler ServerEventHandler;
+        protected TServerTransport ServerTransport;
+
+        protected TBaseServer(ITProcessorFactory itProcessorFactory, TServerTransport serverTransport,
+            TTransportFactory inputTransportFactory, TTransportFactory outputTransportFactory,
+            ITProtocolFactory inputProtocolFactory, ITProtocolFactory outputProtocolFactory,
+            ILogger logger)
+        {
+            ItProcessorFactory = itProcessorFactory ?? throw new ArgumentNullException(nameof(itProcessorFactory));
+            ServerTransport = serverTransport;
+            InputTransportFactory = inputTransportFactory ?? throw new ArgumentNullException(nameof(inputTransportFactory));
+            OutputTransportFactory = outputTransportFactory ?? throw new ArgumentNullException(nameof(outputTransportFactory));
+            InputProtocolFactory = inputProtocolFactory ?? throw new ArgumentNullException(nameof(inputProtocolFactory));
+            OutputProtocolFactory = outputProtocolFactory ?? throw new ArgumentNullException(nameof(outputProtocolFactory));
+            Logger = logger ?? throw new ArgumentNullException(nameof(logger));
+        }
+
+        public void SetEventHandler(TServerEventHandler seh)
+        {
+            ServerEventHandler = seh;
+        }
+
+        public TServerEventHandler GetEventHandler()
+        {
+            return ServerEventHandler;
+        }
+
+        public abstract void Stop();
+
+        public virtual void Start()
+        {
+            // do nothing
+        }
+
+        public virtual async Task ServeAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Server/TServerEventHandler.cs b/lib/netcore/Thrift/Server/TServerEventHandler.cs
new file mode 100644
index 0000000..733bb4b
--- /dev/null
+++ b/lib/netcore/Thrift/Server/TServerEventHandler.cs
@@ -0,0 +1,54 @@
+// 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.
+
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols;
+using Thrift.Transports;
+
+namespace Thrift.Server
+{
+    //TODO: replacement by event?
+
+    /// <summary>
+    ///     Interface implemented by server users to handle events from the server
+    /// </summary>
+    // ReSharper disable once InconsistentNaming
+    public interface TServerEventHandler
+    {
+        /// <summary>
+        ///     Called before the server begins */
+        /// </summary>
+        Task PreServeAsync(CancellationToken cancellationToken);
+
+        /// <summary>
+        ///     Called when a new client has connected and is about to being processing */
+        /// </summary>
+        Task<object> CreateContextAsync(TProtocol input, TProtocol output, CancellationToken cancellationToken);
+
+        /// <summary>
+        ///     Called when a client has finished request-handling to delete server context */
+        /// </summary>
+        Task DeleteContextAsync(object serverContext, TProtocol input, TProtocol output,
+            CancellationToken cancellationToken);
+
+        /// <summary>
+        ///     Called when a client is about to call the processor */
+        /// </summary>
+        Task ProcessContextAsync(object serverContext, TClientTransport transport, CancellationToken cancellationToken);
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/SingletonTProcessorFactory.cs b/lib/netcore/Thrift/SingletonTProcessorFactory.cs
new file mode 100644
index 0000000..c351233
--- /dev/null
+++ b/lib/netcore/Thrift/SingletonTProcessorFactory.cs
@@ -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.
+
+using Thrift.Server;
+using Thrift.Transports;
+
+namespace Thrift
+{
+    // ReSharper disable once InconsistentNaming
+    public class SingletonTProcessorFactory : ITProcessorFactory
+    {
+        private readonly ITAsyncProcessor _tAsyncProcessor;
+
+        public SingletonTProcessorFactory(ITAsyncProcessor tAsyncProcessor)
+        {
+            _tAsyncProcessor = tAsyncProcessor;
+        }
+
+        public ITAsyncProcessor GetAsyncProcessor(TClientTransport trans, TBaseServer baseServer = null)
+        {
+            return _tAsyncProcessor;
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/TApplicationException.cs b/lib/netcore/Thrift/TApplicationException.cs
new file mode 100644
index 0000000..9ec145a
--- /dev/null
+++ b/lib/netcore/Thrift/TApplicationException.cs
@@ -0,0 +1,150 @@
+// 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.
+
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols;
+using Thrift.Protocols.Entities;
+using Thrift.Protocols.Utilities;
+
+namespace Thrift
+{
+    // ReSharper disable once InconsistentNaming
+    public class TApplicationException : TException
+    {
+        public enum ExceptionType
+        {
+            Unknown,
+            UnknownMethod,
+            InvalidMessageType,
+            WrongMethodName,
+            BadSequenceId,
+            MissingResult,
+            InternalError,
+            ProtocolError,
+            InvalidTransform,
+            InvalidProtocol,
+            UnsupportedClientType
+        }
+
+        private const int MessageTypeFieldId = 1;
+        private const int ExTypeFieldId = 2;
+
+        protected ExceptionType Type;
+
+        public TApplicationException()
+        {
+        }
+
+        public TApplicationException(ExceptionType type)
+        {
+            Type = type;
+        }
+
+        public TApplicationException(ExceptionType type, string message)
+            : base(message)
+        {
+            Type = type;
+        }
+
+        public static async Task<TApplicationException> ReadAsync(TProtocol inputProtocol, CancellationToken cancellationToken)
+        {
+            string message = null;
+            var type = ExceptionType.Unknown;
+
+            await inputProtocol.ReadStructBeginAsync(cancellationToken);
+            while (true)
+            {
+                var field = await inputProtocol.ReadFieldBeginAsync(cancellationToken);
+                if (field.Type == TType.Stop)
+                {
+                    break;
+                }
+
+                switch (field.ID)
+                {
+                    case MessageTypeFieldId:
+                        if (field.Type == TType.String)
+                        {
+                            message = await inputProtocol.ReadStringAsync(cancellationToken);
+                        }
+                        else
+                        {
+                            await TProtocolUtil.SkipAsync(inputProtocol, field.Type, cancellationToken);
+                        }
+                        break;
+                    case ExTypeFieldId:
+                        if (field.Type == TType.I32)
+                        {
+                            type = (ExceptionType) await inputProtocol.ReadI32Async(cancellationToken);
+                        }
+                        else
+                        {
+                            await TProtocolUtil.SkipAsync(inputProtocol, field.Type, cancellationToken);
+                        }
+                        break;
+                    default:
+                        await TProtocolUtil.SkipAsync(inputProtocol, field.Type, cancellationToken);
+                        break;
+                }
+
+                await inputProtocol.ReadFieldEndAsync(cancellationToken);
+            }
+
+            await inputProtocol.ReadStructEndAsync(cancellationToken);
+
+            return new TApplicationException(type, message);
+        }
+
+        public async Task WriteAsync(TProtocol outputProtocol, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+
+            const string messageTypeFieldName = "message";
+            const string exTypeFieldName = "exType";
+            const string structApplicationExceptionName = "TApplicationException";
+
+            var struc = new TStruct(structApplicationExceptionName);
+            var field = new TField();
+
+            await outputProtocol.WriteStructBeginAsync(struc, cancellationToken);
+
+            if (!string.IsNullOrEmpty(Message))
+            {
+                field.Name = messageTypeFieldName;
+                field.Type = TType.String;
+                field.ID = MessageTypeFieldId;
+                await outputProtocol.WriteFieldBeginAsync(field, cancellationToken);
+                await outputProtocol.WriteStringAsync(Message, cancellationToken);
+                await outputProtocol.WriteFieldEndAsync(cancellationToken);
+            }
+
+            field.Name = exTypeFieldName;
+            field.Type = TType.I32;
+            field.ID = ExTypeFieldId;
+
+            await outputProtocol.WriteFieldBeginAsync(field, cancellationToken);
+            await outputProtocol.WriteI32Async((int) Type, cancellationToken);
+            await outputProtocol.WriteFieldEndAsync(cancellationToken);
+            await outputProtocol.WriteFieldStopAsync(cancellationToken);
+            await outputProtocol.WriteStructEndAsync(cancellationToken);
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/TBaseClient.cs b/lib/netcore/Thrift/TBaseClient.cs
new file mode 100644
index 0000000..e019251
--- /dev/null
+++ b/lib/netcore/Thrift/TBaseClient.cs
@@ -0,0 +1,91 @@
+// 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.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols;
+
+namespace Thrift
+{
+    // ReSharper disable once InconsistentNaming
+    /// <summary>
+    ///     TBaseClient.
+    ///     Base client for generated clients.
+    ///     Do not change this class without checking generated code (namings, etc.)
+    /// </summary>
+    public abstract class TBaseClient
+    {
+        private readonly TProtocol _inputProtocol;
+        private readonly TProtocol _outputProtocol;
+        private bool _isDisposed;
+        private int _seqId;
+        public readonly Guid ClientId = Guid.NewGuid();
+
+        protected TBaseClient(TProtocol inputProtocol, TProtocol outputProtocol)
+        {
+            _inputProtocol = inputProtocol ?? throw new ArgumentNullException(nameof(inputProtocol));
+            _outputProtocol = outputProtocol ?? throw new ArgumentNullException(nameof(outputProtocol));
+        }
+
+        public TProtocol InputProtocol => _inputProtocol;
+
+        public TProtocol OutputProtocol => _outputProtocol;
+
+        public int SeqId
+        {
+            get { return ++_seqId; }
+        }
+
+        public virtual async Task OpenTransportAsync()
+        {
+            await OpenTransportAsync(CancellationToken.None);
+        }
+
+        public virtual async Task OpenTransportAsync(CancellationToken cancellationToken)
+        {
+            if (!_inputProtocol.Transport.IsOpen)
+            {
+                await _inputProtocol.Transport.OpenAsync(cancellationToken);
+            }
+
+            if (!_inputProtocol.Transport.IsOpen)
+            {
+                await _outputProtocol.Transport.OpenAsync(cancellationToken);
+            }
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_isDisposed)
+            {
+                if (disposing)
+                {
+                    _inputProtocol?.Dispose();
+                    _outputProtocol?.Dispose();
+                }
+            }
+
+            _isDisposed = true;
+        }
+    }
+}
diff --git a/lib/netcore/Thrift/TException.cs b/lib/netcore/Thrift/TException.cs
new file mode 100644
index 0000000..6aa588d
--- /dev/null
+++ b/lib/netcore/Thrift/TException.cs
@@ -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.
+
+using System;
+
+namespace Thrift
+{
+    // ReSharper disable once InconsistentNaming
+    public class TException : Exception
+    {
+        public TException()
+        {
+        }
+
+        public TException(string message)
+            : base(message)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/TMultiplexedProcessor.cs b/lib/netcore/Thrift/TMultiplexedProcessor.cs
new file mode 100644
index 0000000..ad0e749
--- /dev/null
+++ b/lib/netcore/Thrift/TMultiplexedProcessor.cs
@@ -0,0 +1,143 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Protocols;
+using Thrift.Protocols.Entities;
+
+namespace Thrift
+{
+    // ReSharper disable once InconsistentNaming
+    public class TMultiplexedProcessor : ITAsyncProcessor
+    {
+        //TODO: Localization
+
+        private readonly Dictionary<string, ITAsyncProcessor> _serviceProcessorMap =
+            new Dictionary<string, ITAsyncProcessor>();
+
+        public async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)
+        {
+            return await ProcessAsync(iprot, oprot, CancellationToken.None);
+        }
+
+        public async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<bool>(cancellationToken);
+            }
+
+            try
+            {
+                var message = await iprot.ReadMessageBeginAsync(cancellationToken);
+
+                if ((message.Type != TMessageType.Call) && (message.Type != TMessageType.Oneway))
+                {
+                    await FailAsync(oprot, message, TApplicationException.ExceptionType.InvalidMessageType,
+                        "Message exType CALL or ONEWAY expected", cancellationToken);
+                    return false;
+                }
+
+                // Extract the service name
+                var index = message.Name.IndexOf(TMultiplexedProtocol.Separator, StringComparison.Ordinal);
+                if (index < 0)
+                {
+                    await FailAsync(oprot, message, TApplicationException.ExceptionType.InvalidProtocol,
+                        $"Service name not found in message name: {message.Name}. Did you forget to use a TMultiplexProtocol in your client?",
+                        cancellationToken);
+                    return false;
+                }
+
+                // Create a new TMessage, something that can be consumed by any TProtocol
+                var serviceName = message.Name.Substring(0, index);
+                ITAsyncProcessor actualProcessor;
+                if (!_serviceProcessorMap.TryGetValue(serviceName, out actualProcessor))
+                {
+                    await FailAsync(oprot, message, TApplicationException.ExceptionType.InternalError,
+                        $"Service name not found: {serviceName}. Did you forget to call RegisterProcessor()?",
+                        cancellationToken);
+                    return false;
+                }
+
+                // Create a new TMessage, removing the service name
+                var newMessage = new TMessage(
+                    message.Name.Substring(serviceName.Length + TMultiplexedProtocol.Separator.Length),
+                    message.Type,
+                    message.SeqID);
+
+                // Dispatch processing to the stored processor
+                return
+                    await
+                        actualProcessor.ProcessAsync(new StoredMessageProtocol(iprot, newMessage), oprot,
+                            cancellationToken);
+            }
+            catch (IOException)
+            {
+                return false; // similar to all other processors
+            }
+        }
+
+        public void RegisterProcessor(string serviceName, ITAsyncProcessor processor)
+        {
+            if (_serviceProcessorMap.ContainsKey(serviceName))
+            {
+                throw new InvalidOperationException(
+                    $"Processor map already contains processor with name: '{serviceName}'");
+            }
+
+            _serviceProcessorMap.Add(serviceName, processor);
+        }
+
+        private async Task FailAsync(TProtocol oprot, TMessage message, TApplicationException.ExceptionType extype,
+            string etxt, CancellationToken cancellationToken)
+        {
+            var appex = new TApplicationException(extype, etxt);
+
+            var newMessage = new TMessage(message.Name, TMessageType.Exception, message.SeqID);
+
+            await oprot.WriteMessageBeginAsync(newMessage, cancellationToken);
+            await appex.WriteAsync(oprot, cancellationToken);
+            await oprot.WriteMessageEndAsync(cancellationToken);
+            await oprot.Transport.FlushAsync(cancellationToken);
+        }
+
+        private class StoredMessageProtocol : TProtocolDecorator
+        {
+            readonly TMessage _msgBegin;
+
+            public StoredMessageProtocol(TProtocol protocol, TMessage messageBegin)
+                : base(protocol)
+            {
+                _msgBegin = messageBegin;
+            }
+
+            public override async Task<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
+            {
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    return await Task.FromCanceled<TMessage>(cancellationToken);
+                }
+
+                return _msgBegin;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Thrift.csproj b/lib/netcore/Thrift/Thrift.csproj
new file mode 100644
index 0000000..e806fed
--- /dev/null
+++ b/lib/netcore/Thrift/Thrift.csproj
@@ -0,0 +1,31 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <AssemblyName>Thrift</AssemblyName>
+    <PackageId>Thrift</PackageId>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+    <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
+    <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
+    <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
+    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
+    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
+    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
+    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
+    <GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
+    <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore" Version="[2.0,)" />
+    <PackageReference Include="Microsoft.Extensions.Logging" Version="[2.0,)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="[2.0,)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="[2.0,)" />
+    <PackageReference Include="System.IO.Pipes" Version="[4.3,)" />
+    <PackageReference Include="System.Net.Http.WinHttpHandler" Version="4.4.0" />
+    <PackageReference Include="System.Net.NameResolution" Version="[4.3,)" />
+    <PackageReference Include="System.Net.Requests" Version="[4.3,)" />
+    <PackageReference Include="System.Net.Security" Version="[4.3,)" />
+  </ItemGroup>
+
+</Project>
diff --git a/lib/netcore/Thrift/Transports/Client/TBufferedClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TBufferedClientTransport.cs
new file mode 100644
index 0000000..761f1ac
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/Client/TBufferedClientTransport.cs
@@ -0,0 +1,206 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Thrift.Transports.Client
+{
+    // ReSharper disable once InconsistentNaming
+    public class TBufferedClientTransport : TClientTransport
+    {
+        private readonly int _bufSize;
+        private readonly MemoryStream _inputBuffer = new MemoryStream(0);
+        private readonly MemoryStream _outputBuffer = new MemoryStream(0);
+        private readonly TClientTransport _transport;
+        private bool _isDisposed;
+
+        //TODO: should support only specified input transport?
+        public TBufferedClientTransport(TClientTransport transport, int bufSize = 1024)
+        {
+            if (bufSize <= 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(bufSize), "Buffer size must be a positive number.");
+            }
+
+            _transport = transport ?? throw new ArgumentNullException(nameof(transport));
+            _bufSize = bufSize;
+        }
+
+        public TClientTransport UnderlyingTransport
+        {
+            get
+            {
+                CheckNotDisposed();
+
+                return _transport;
+            }
+        }
+
+        public override bool IsOpen => !_isDisposed && _transport.IsOpen;
+
+        public override async Task OpenAsync(CancellationToken cancellationToken)
+        {
+            CheckNotDisposed();
+
+            await _transport.OpenAsync(cancellationToken);
+        }
+
+        public override void Close()
+        {
+            CheckNotDisposed();
+
+            _transport.Close();
+        }
+
+        public override async Task<int> ReadAsync(byte[] buffer, int offset, int length,
+            CancellationToken cancellationToken)
+        {
+            //TODO: investigate how it should work correctly
+            CheckNotDisposed();
+
+            ValidateBufferArgs(buffer, offset, length);
+
+            if (!IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            }
+
+            if (_inputBuffer.Capacity < _bufSize)
+            {
+                _inputBuffer.Capacity = _bufSize;
+            }
+
+            var got = await _inputBuffer.ReadAsync(buffer, offset, length, cancellationToken);
+            if (got > 0)
+            {
+                return got;
+            }
+
+            _inputBuffer.Seek(0, SeekOrigin.Begin);
+            _inputBuffer.SetLength(_inputBuffer.Capacity);
+
+            ArraySegment<byte> bufSegment;
+            _inputBuffer.TryGetBuffer(out bufSegment);
+
+            // investigate
+            var filled = await _transport.ReadAsync(bufSegment.Array, 0, (int) _inputBuffer.Length, cancellationToken);
+            _inputBuffer.SetLength(filled);
+
+            if (filled == 0)
+            {
+                return 0;
+            }
+
+            return await ReadAsync(buffer, offset, length, cancellationToken);
+        }
+
+        public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
+        {
+            CheckNotDisposed();
+
+            ValidateBufferArgs(buffer, offset, length);
+
+            if (!IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            }
+
+            // Relative offset from "off" argument
+            var writtenCount = 0;
+            if (_outputBuffer.Length > 0)
+            {
+                var capa = (int) (_outputBuffer.Capacity - _outputBuffer.Length);
+                var writeSize = capa <= length ? capa : length;
+                await _outputBuffer.WriteAsync(buffer, offset, writeSize, cancellationToken);
+
+                writtenCount += writeSize;
+                if (writeSize == capa)
+                {
+                    //ArraySegment<byte> bufSegment;
+                    //_outputBuffer.TryGetBuffer(out bufSegment);
+                    var data = _outputBuffer.ToArray();
+                    //await _transport.WriteAsync(bufSegment.Array, cancellationToken);
+                    await _transport.WriteAsync(data, cancellationToken);
+                    _outputBuffer.SetLength(0);
+                }
+            }
+
+            while (length - writtenCount >= _bufSize)
+            {
+                await _transport.WriteAsync(buffer, offset + writtenCount, _bufSize, cancellationToken);
+                writtenCount += _bufSize;
+            }
+
+            var remain = length - writtenCount;
+            if (remain > 0)
+            {
+                if (_outputBuffer.Capacity < _bufSize)
+                {
+                    _outputBuffer.Capacity = _bufSize;
+                }
+                await _outputBuffer.WriteAsync(buffer, offset + writtenCount, remain, cancellationToken);
+            }
+        }
+
+        public override async Task FlushAsync(CancellationToken cancellationToken)
+        {
+            CheckNotDisposed();
+
+            if (!IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            }
+
+            if (_outputBuffer.Length > 0)
+            {
+                //ArraySegment<byte> bufSegment;
+                var data = _outputBuffer.ToArray(); // TryGetBuffer(out bufSegment);
+
+                await _transport.WriteAsync(data /*bufSegment.Array*/, cancellationToken);
+                _outputBuffer.SetLength(0);
+            }
+
+            await _transport.FlushAsync(cancellationToken);
+        }
+
+        private void CheckNotDisposed()
+        {
+            if (_isDisposed)
+            {
+                throw new ObjectDisposedException(nameof(_transport));
+            }
+        }
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_isDisposed)
+            {
+                if (disposing)
+                {
+                    _inputBuffer?.Dispose();
+                    _outputBuffer?.Dispose();
+                    _transport?.Dispose();
+                }
+            }
+            _isDisposed = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/Client/TFramedClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TFramedClientTransport.cs
new file mode 100644
index 0000000..d11bb95
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/Client/TFramedClientTransport.cs
@@ -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.
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Thrift.Transports.Client
+{
+    //TODO: check for correct implementation 
+
+    // ReSharper disable once InconsistentNaming
+    public class TFramedClientTransport : TClientTransport
+    {
+        private const int HeaderSize = 4;
+        private readonly byte[] _headerBuf = new byte[HeaderSize];
+        private readonly MemoryStream _readBuffer = new MemoryStream(1024);
+        private readonly TClientTransport _transport;
+        private readonly MemoryStream _writeBuffer = new MemoryStream(1024);
+
+        private bool _isDisposed;
+
+        public TFramedClientTransport(TClientTransport transport)
+        {
+            _transport = transport ?? throw new ArgumentNullException(nameof(transport));
+
+            InitWriteBuffer();
+        }
+
+        public override bool IsOpen => !_isDisposed && _transport.IsOpen;
+
+        public override async Task OpenAsync(CancellationToken cancellationToken)
+        {
+            CheckNotDisposed();
+
+            await _transport.OpenAsync(cancellationToken);
+        }
+
+        public override void Close()
+        {
+            CheckNotDisposed();
+
+            _transport.Close();
+        }
+
+        public override async Task<int> ReadAsync(byte[] buffer, int offset, int length,
+            CancellationToken cancellationToken)
+        {
+            CheckNotDisposed();
+
+            ValidateBufferArgs(buffer, offset, length);
+
+            if (!IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            }
+
+            var got = await _readBuffer.ReadAsync(buffer, offset, length, cancellationToken);
+            if (got > 0)
+            {
+                return got;
+            }
+
+            // Read another frame of data
+            await ReadFrameAsync(cancellationToken);
+
+            return await _readBuffer.ReadAsync(buffer, offset, length, cancellationToken);
+        }
+
+        private async Task ReadFrameAsync(CancellationToken cancellationToken)
+        {
+            await _transport.ReadAllAsync(_headerBuf, 0, HeaderSize, cancellationToken);
+
+            var size = DecodeFrameSize(_headerBuf);
+
+            _readBuffer.SetLength(size);
+            _readBuffer.Seek(0, SeekOrigin.Begin);
+
+            ArraySegment<byte> bufSegment;
+            _readBuffer.TryGetBuffer(out bufSegment);
+
+            var buff = bufSegment.Array;
+
+            await _transport.ReadAllAsync(buff, 0, size, cancellationToken);
+        }
+
+        public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
+        {
+            CheckNotDisposed();
+
+            ValidateBufferArgs(buffer, offset, length);
+
+            if (!IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            }
+
+            if (_writeBuffer.Length + length > int.MaxValue)
+            {
+                await FlushAsync(cancellationToken);
+            }
+
+            await _writeBuffer.WriteAsync(buffer, offset, length, cancellationToken);
+        }
+
+        public override async Task FlushAsync(CancellationToken cancellationToken)
+        {
+            CheckNotDisposed();
+
+            if (!IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            }
+
+            //ArraySegment<byte> bufSegment;
+            //_writeBuffer.TryGetBuffer(out bufSegment);
+            //var buf = bufSegment.Array;
+            var buf = _writeBuffer.ToArray();
+
+            //var len = (int)_writeBuffer.Length;
+            var dataLen = (int) _writeBuffer.Length - HeaderSize;
+            if (dataLen < 0)
+            {
+                throw new InvalidOperationException(); // logic error actually
+            }
+
+            // Inject message header into the reserved buffer space
+            EncodeFrameSize(dataLen, buf);
+
+            // Send the entire message at once
+            await _transport.WriteAsync(buf, cancellationToken);
+
+            InitWriteBuffer();
+
+            await _transport.FlushAsync(cancellationToken);
+        }
+
+        private void InitWriteBuffer()
+        {
+            // Reserve space for message header to be put right before sending it out
+            _writeBuffer.SetLength(HeaderSize);
+            _writeBuffer.Seek(0, SeekOrigin.End);
+        }
+
+        private static void EncodeFrameSize(int frameSize, byte[] buf)
+        {
+            buf[0] = (byte) (0xff & (frameSize >> 24));
+            buf[1] = (byte) (0xff & (frameSize >> 16));
+            buf[2] = (byte) (0xff & (frameSize >> 8));
+            buf[3] = (byte) (0xff & (frameSize));
+        }
+
+        private static int DecodeFrameSize(byte[] buf)
+        {
+            return
+                ((buf[0] & 0xff) << 24) |
+                ((buf[1] & 0xff) << 16) |
+                ((buf[2] & 0xff) << 8) |
+                (buf[3] & 0xff);
+        }
+
+
+        private void CheckNotDisposed()
+        {
+            if (_isDisposed)
+            {
+                throw new ObjectDisposedException("TFramedClientTransport");
+            }
+        }
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_isDisposed)
+            {
+                if (disposing)
+                {
+                    _readBuffer?.Dispose();
+                    _writeBuffer?.Dispose();
+                    _transport?.Dispose();
+                }
+            }
+            _isDisposed = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/Client/THttpClientTransport.cs b/lib/netcore/Thrift/Transports/Client/THttpClientTransport.cs
new file mode 100644
index 0000000..797d380
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/Client/THttpClientTransport.cs
@@ -0,0 +1,226 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Thrift.Transports.Client
+{
+    // ReSharper disable once InconsistentNaming
+    public class THttpClientTransport : TClientTransport
+    {
+        private readonly X509Certificate[] _certificates;
+        private readonly Uri _uri;
+
+        // Timeouts in milliseconds
+        private int _connectTimeout = 30000;
+        private HttpClient _httpClient;
+        private Stream _inputStream;
+
+        private bool _isDisposed;
+        private MemoryStream _outputStream = new MemoryStream();
+
+        public THttpClientTransport(Uri u, IDictionary<string, string> customHeaders)
+            : this(u, Enumerable.Empty<X509Certificate>(), customHeaders)
+        {
+        }
+
+        public THttpClientTransport(Uri u, IEnumerable<X509Certificate> certificates,
+            IDictionary<string, string> customHeaders)
+        {
+            _uri = u;
+            _certificates = (certificates ?? Enumerable.Empty<X509Certificate>()).ToArray();
+            CustomHeaders = customHeaders;
+
+            // due to current bug with performance of Dispose in netcore https://github.com/dotnet/corefx/issues/8809
+            // this can be switched to default way (create client->use->dispose per flush) later
+            _httpClient = CreateClient();
+        }
+
+        public IDictionary<string, string> CustomHeaders { get; }
+
+        public int ConnectTimeout
+        {
+            set { _connectTimeout = value; }
+        }
+
+        public override bool IsOpen => true;
+
+        public override async Task OpenAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override void Close()
+        {
+            if (_inputStream != null)
+            {
+                _inputStream.Dispose();
+                _inputStream = null;
+            }
+
+            if (_outputStream != null)
+            {
+                _outputStream.Dispose();
+                _outputStream = null;
+            }
+
+            if (_httpClient != null)
+            {
+                _httpClient.Dispose();
+                _httpClient = null;
+            }
+        }
+
+        public override async Task<int> ReadAsync(byte[] buffer, int offset, int length,
+            CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<int>(cancellationToken);
+            }
+
+            if (_inputStream == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No request has been sent");
+            }
+
+            try
+            {
+                var ret = await _inputStream.ReadAsync(buffer, offset, length, cancellationToken);
+
+                if (ret == -1)
+                {
+                    throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "No more data available");
+                }
+
+                return ret;
+            }
+            catch (IOException iox)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString());
+            }
+        }
+
+        public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+
+            await _outputStream.WriteAsync(buffer, offset, length, cancellationToken);
+        }
+
+        private HttpClient CreateClient()
+        {
+            var handler = new HttpClientHandler();
+            handler.ClientCertificates.AddRange(_certificates);
+
+            var httpClient = new HttpClient(handler);
+
+            if (_connectTimeout > 0)
+            {
+                httpClient.Timeout = TimeSpan.FromSeconds(_connectTimeout);
+            }
+
+            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-thrift"));
+            httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("THttpClientTransport", "1.0.0"));
+
+            if (CustomHeaders != null)
+            {
+                foreach (var item in CustomHeaders)
+                {
+                    httpClient.DefaultRequestHeaders.Add(item.Key, item.Value);
+                }
+            }
+
+            return httpClient;
+        }
+
+        public override async Task FlushAsync(CancellationToken cancellationToken)
+        {
+            try
+            {
+                try
+                {
+                    if (_outputStream.CanSeek)
+                    {
+                        _outputStream.Seek(0, SeekOrigin.Begin);
+                    }
+
+                    using (var outStream = new StreamContent(_outputStream))
+                    {
+                        var msg = await _httpClient.PostAsync(_uri, outStream, cancellationToken);
+
+                        msg.EnsureSuccessStatusCode();
+
+                        if (_inputStream != null)
+                        {
+                            _inputStream.Dispose();
+                            _inputStream = null;
+                        }
+
+                        _inputStream = await msg.Content.ReadAsStreamAsync();
+                        if (_inputStream.CanSeek)
+                        {
+                            _inputStream.Seek(0, SeekOrigin.Begin);
+                        }
+                    }
+                }
+                catch (IOException iox)
+                {
+                    throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString());
+                }
+                catch (HttpRequestException wx)
+                {
+                    throw new TTransportException(TTransportException.ExceptionType.Unknown,
+                        "Couldn't connect to server: " + wx);
+                }
+            }
+            finally
+            {
+                _outputStream = new MemoryStream();
+            }
+        }
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_isDisposed)
+            {
+                if (disposing)
+                {
+                    _inputStream?.Dispose();
+                    _outputStream?.Dispose();
+                    _httpClient?.Dispose();
+                }
+            }
+            _isDisposed = true;
+        }
+    }
+}
diff --git a/lib/netcore/Thrift/Transports/Client/TMemoryBufferClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TMemoryBufferClientTransport.cs
new file mode 100644
index 0000000..46a55a6
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/Client/TMemoryBufferClientTransport.cs
@@ -0,0 +1,97 @@
+// 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.
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Thrift.Transports.Client
+{
+    // ReSharper disable once InconsistentNaming
+    public class TMemoryBufferClientTransport : TClientTransport
+    {
+        private readonly MemoryStream _byteStream;
+        private bool _isDisposed;
+
+        public TMemoryBufferClientTransport()
+        {
+            _byteStream = new MemoryStream();
+        }
+
+        public TMemoryBufferClientTransport(byte[] buf)
+        {
+            _byteStream = new MemoryStream(buf);
+        }
+
+        public override bool IsOpen => true;
+
+        public override async Task OpenAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override void Close()
+        {
+            /** do nothing **/
+        }
+
+        public override async Task<int> ReadAsync(byte[] buffer, int offset, int length,
+            CancellationToken cancellationToken)
+        {
+            return await _byteStream.ReadAsync(buffer, offset, length, cancellationToken);
+        }
+
+        public override async Task WriteAsync(byte[] buffer, CancellationToken cancellationToken)
+        {
+            await _byteStream.WriteAsync(buffer, 0, buffer.Length, cancellationToken);
+        }
+
+        public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
+        {
+            await _byteStream.WriteAsync(buffer, offset, length, cancellationToken);
+        }
+
+        public override async Task FlushAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public byte[] GetBuffer()
+        {
+            return _byteStream.ToArray();
+        }
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_isDisposed)
+            {
+                if (disposing)
+                {
+                    _byteStream?.Dispose();
+                }
+            }
+            _isDisposed = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/Client/TNamedPipeClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TNamedPipeClientTransport.cs
new file mode 100644
index 0000000..f5e4baf
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/Client/TNamedPipeClientTransport.cs
@@ -0,0 +1,95 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System.IO.Pipes;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Thrift.Transports.Client
+{
+    // ReSharper disable once InconsistentNaming
+    public class TNamedPipeClientTransport : TClientTransport
+    {
+        private NamedPipeClientStream _client;
+
+        public TNamedPipeClientTransport(string pipe) : this(".", pipe)
+        {
+        }
+
+        public TNamedPipeClientTransport(string server, string pipe)
+        {
+            var serverName = string.IsNullOrWhiteSpace(server) ? server : ".";
+
+            _client = new NamedPipeClientStream(serverName, pipe, PipeDirection.InOut, PipeOptions.None);
+        }
+
+        public override bool IsOpen => _client != null && _client.IsConnected;
+
+        public override async Task OpenAsync(CancellationToken cancellationToken)
+        {
+            if (IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen);
+            }
+
+            await _client.ConnectAsync(cancellationToken);
+        }
+
+        public override void Close()
+        {
+            if (_client != null)
+            {
+                _client.Dispose();
+                _client = null;
+            }
+        }
+
+        public override async Task<int> ReadAsync(byte[] buffer, int offset, int length,
+            CancellationToken cancellationToken)
+        {
+            if (_client == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            }
+
+            return await _client.ReadAsync(buffer, offset, length, cancellationToken);
+        }
+
+        public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
+        {
+            if (_client == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+            }
+
+            await _client.WriteAsync(buffer, offset, length, cancellationToken);
+        }
+
+        public override async Task FlushAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            _client.Dispose();
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/Client/TSocketClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TSocketClientTransport.cs
new file mode 100644
index 0000000..e769d14
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/Client/TSocketClientTransport.cs
@@ -0,0 +1,139 @@
+// 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.
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Thrift.Transports.Client
+{
+    // ReSharper disable once InconsistentNaming
+    public class TSocketClientTransport : TStreamClientTransport
+    {
+        private bool _isDisposed;
+
+        public TSocketClientTransport(TcpClient client)
+        {
+            TcpClient = client ?? throw new ArgumentNullException(nameof(client));
+
+            if (IsOpen)
+            {
+                InputStream = client.GetStream();
+                OutputStream = client.GetStream();
+            }
+        }
+
+        public TSocketClientTransport(IPAddress host, int port)
+            : this(host, port, 0)
+        {
+        }
+
+        public TSocketClientTransport(IPAddress host, int port, int timeout)
+        {
+            Host = host;
+            Port = port;
+
+            TcpClient = new TcpClient();
+            TcpClient.ReceiveTimeout = TcpClient.SendTimeout = timeout;
+            TcpClient.Client.NoDelay = true;
+        }
+
+        public TcpClient TcpClient { get; private set; }
+        public IPAddress Host { get; }
+        public int Port { get; }
+
+        public int Timeout
+        {
+            set
+            {
+                if (TcpClient != null)
+                {
+                    TcpClient.ReceiveTimeout = TcpClient.SendTimeout = value;
+                }
+            }
+        }
+
+        public override bool IsOpen
+        {
+            get
+            {
+                if (TcpClient == null)
+                {
+                    return false;
+                }
+
+                return TcpClient.Connected;
+            }
+        }
+
+        public override async Task OpenAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+
+            if (IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
+            }
+
+            if (Port <= 0)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
+            }
+
+            if (TcpClient == null)
+            {
+                throw new InvalidOperationException("Invalid or not initialized tcp client");
+            }
+
+            await TcpClient.ConnectAsync(Host, Port);
+
+            InputStream = TcpClient.GetStream();
+            OutputStream = TcpClient.GetStream();
+        }
+
+        public override void Close()
+        {
+            base.Close();
+
+            if (TcpClient != null)
+            {
+                TcpClient.Dispose();
+                TcpClient = null;
+            }
+        }
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_isDisposed)
+            {
+                if (disposing)
+                {
+                    TcpClient?.Dispose();
+
+                    base.Dispose(disposing);
+                }
+            }
+            _isDisposed = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/Client/TStreamClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TStreamClientTransport.cs
new file mode 100644
index 0000000..f7164f0
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/Client/TStreamClientTransport.cs
@@ -0,0 +1,110 @@
+// 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.
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Thrift.Transports.Client
+{
+    // ReSharper disable once InconsistentNaming
+    public class TStreamClientTransport : TClientTransport
+    {
+        private bool _isDisposed;
+
+        protected TStreamClientTransport()
+        {
+        }
+
+        public TStreamClientTransport(Stream inputStream, Stream outputStream)
+        {
+            InputStream = inputStream;
+            OutputStream = outputStream;
+        }
+
+        protected Stream OutputStream { get; set; }
+
+        protected Stream InputStream { get; set; }
+
+        public override bool IsOpen => true;
+
+        public override async Task OpenAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                await Task.FromCanceled(cancellationToken);
+            }
+        }
+
+        public override void Close()
+        {
+            if (InputStream != null)
+            {
+                InputStream.Dispose();
+                InputStream = null;
+            }
+
+            if (OutputStream != null)
+            {
+                OutputStream.Dispose();
+                OutputStream = null;
+            }
+        }
+
+        public override async Task<int> ReadAsync(byte[] buffer, int offset, int length,
+            CancellationToken cancellationToken)
+        {
+            if (InputStream == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen,
+                    "Cannot read from null inputstream");
+            }
+
+            return await InputStream.ReadAsync(buffer, offset, length, cancellationToken);
+        }
+
+        public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
+        {
+            if (OutputStream == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen,
+                    "Cannot read from null inputstream");
+            }
+
+            await OutputStream.WriteAsync(buffer, offset, length, cancellationToken);
+        }
+
+        public override async Task FlushAsync(CancellationToken cancellationToken)
+        {
+            await OutputStream.FlushAsync(cancellationToken);
+        }
+
+        // IDisposable
+        protected override void Dispose(bool disposing)
+        {
+            if (!_isDisposed)
+            {
+                if (disposing)
+                {
+                    InputStream?.Dispose();
+                    OutputStream?.Dispose();
+                }
+            }
+            _isDisposed = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/Client/TTlsSocketClientTransport.cs b/lib/netcore/Thrift/Transports/Client/TTlsSocketClientTransport.cs
new file mode 100644
index 0000000..c8be4ed
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/Client/TTlsSocketClientTransport.cs
@@ -0,0 +1,237 @@
+// 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.
+
+using System;
+using System.Net;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Thrift.Transports.Client
+{
+    //TODO: check for correct work
+
+    // ReSharper disable once InconsistentNaming
+    public class TTlsSocketClientTransport : TStreamClientTransport
+    {
+        private readonly X509Certificate2 _certificate;
+        private readonly RemoteCertificateValidationCallback _certValidator;
+        private readonly IPAddress _host;
+        private readonly bool _isServer;
+        private readonly LocalCertificateSelectionCallback _localCertificateSelectionCallback;
+        private readonly int _port;
+        private readonly SslProtocols _sslProtocols;
+        private TcpClient _client;
+        private SslStream _secureStream;
+        private int _timeout;
+
+        public TTlsSocketClientTransport(TcpClient client, X509Certificate2 certificate, bool isServer = false,
+            RemoteCertificateValidationCallback certValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            SslProtocols sslProtocols = SslProtocols.Tls12)
+        {
+            _client = client;
+            _certificate = certificate;
+            _certValidator = certValidator;
+            _localCertificateSelectionCallback = localCertificateSelectionCallback;
+            _sslProtocols = sslProtocols;
+            _isServer = isServer;
+
+            if (isServer && certificate == null)
+            {
+                throw new ArgumentException("TTlsSocketClientTransport needs certificate to be used for server",
+                    nameof(certificate));
+            }
+
+            if (IsOpen)
+            {
+                InputStream = client.GetStream();
+                OutputStream = client.GetStream();
+            }
+        }
+
+        public TTlsSocketClientTransport(IPAddress host, int port, string certificatePath,
+            RemoteCertificateValidationCallback certValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            SslProtocols sslProtocols = SslProtocols.Tls12)
+            : this(host, port, 0,
+                new X509Certificate2(certificatePath),
+                certValidator,
+                localCertificateSelectionCallback,
+                sslProtocols)
+        {
+        }
+
+        public TTlsSocketClientTransport(IPAddress host, int port,
+            X509Certificate2 certificate = null,
+            RemoteCertificateValidationCallback certValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            SslProtocols sslProtocols = SslProtocols.Tls12)
+            : this(host, port, 0,
+                certificate,
+                certValidator,
+                localCertificateSelectionCallback,
+                sslProtocols)
+        {
+        }
+
+        public TTlsSocketClientTransport(IPAddress host, int port, int timeout,
+            X509Certificate2 certificate,
+            RemoteCertificateValidationCallback certValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            SslProtocols sslProtocols = SslProtocols.Tls12)
+        {
+            _host = host;
+            _port = port;
+            _timeout = timeout;
+            _certificate = certificate;
+            _certValidator = certValidator;
+            _localCertificateSelectionCallback = localCertificateSelectionCallback;
+            _sslProtocols = sslProtocols;
+
+            InitSocket();
+        }
+
+        public int Timeout
+        {
+            set { _client.ReceiveTimeout = _client.SendTimeout = _timeout = value; }
+        }
+
+        public TcpClient TcpClient => _client;
+
+        public IPAddress Host => _host;
+
+        public int Port => _port;
+
+        public override bool IsOpen
+        {
+            get
+            {
+                if (_client == null)
+                {
+                    return false;
+                }
+
+                return _client.Connected;
+            }
+        }
+
+        private void InitSocket()
+        {
+            _client = new TcpClient();
+            _client.ReceiveTimeout = _client.SendTimeout = _timeout;
+            _client.Client.NoDelay = true;
+        }
+
+        private bool DefaultCertificateValidator(object sender, X509Certificate certificate, X509Chain chain,
+            SslPolicyErrors sslValidationErrors)
+        {
+            return sslValidationErrors == SslPolicyErrors.None;
+        }
+
+        public override async Task OpenAsync(CancellationToken cancellationToken)
+        {
+            if (IsOpen)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
+            }
+
+            if (_host == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host");
+            }
+
+            if (_port <= 0)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
+            }
+
+            if (_client == null)
+            {
+                InitSocket();
+            }
+
+            if (_client != null)
+            {
+                await _client.ConnectAsync(_host, _port);
+                await SetupTlsAsync();
+            }
+        }
+
+        public async Task SetupTlsAsync()
+        {
+            var validator = _certValidator ?? DefaultCertificateValidator;
+
+            if (_localCertificateSelectionCallback != null)
+            {
+                _secureStream = new SslStream(_client.GetStream(), false, validator, _localCertificateSelectionCallback);
+            }
+            else
+            {
+                _secureStream = new SslStream(_client.GetStream(), false, validator);
+            }
+
+            try
+            {
+                if (_isServer)
+                {
+                    // Server authentication
+                    await
+                        _secureStream.AuthenticateAsServerAsync(_certificate, _certValidator != null, _sslProtocols,
+                            true);
+                }
+                else
+                {
+                    // Client authentication
+                    var certs = _certificate != null
+                        ? new X509CertificateCollection {_certificate}
+                        : new X509CertificateCollection();
+
+                    var targetHost = _host.ToString();
+                    await _secureStream.AuthenticateAsClientAsync(targetHost, certs, _sslProtocols, true);
+                }
+            }
+            catch (Exception)
+            {
+                Close();
+                throw;
+            }
+
+            InputStream = _secureStream;
+            OutputStream = _secureStream;
+        }
+
+        public override void Close()
+        {
+            base.Close();
+            if (_client != null)
+            {
+                _client.Dispose();
+                _client = null;
+            }
+
+            if (_secureStream != null)
+            {
+                _secureStream.Dispose();
+                _secureStream = null;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/Server/THttpServerTransport.cs b/lib/netcore/Thrift/Transports/Server/THttpServerTransport.cs
new file mode 100644
index 0000000..032063a
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/Server/THttpServerTransport.cs
@@ -0,0 +1,98 @@
+// 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.
+
+using System;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+using Thrift.Protocols;
+using Thrift.Transports.Client;
+
+namespace Thrift.Transports.Server
+{
+    // ReSharper disable once InconsistentNaming
+    public class THttpServerTransport
+    {
+        protected const string ContentType = "application/x-thrift";
+        private readonly ILogger _logger;
+        private readonly RequestDelegate _next;
+        protected Encoding Encoding = Encoding.UTF8;
+
+        protected ITProtocolFactory InputProtocolFactory;
+        protected ITProtocolFactory OutputProtocolFactory;
+
+        protected ITAsyncProcessor Processor;
+
+        public THttpServerTransport(ITAsyncProcessor processor, RequestDelegate next, ILoggerFactory loggerFactory)
+            : this(processor, new TBinaryProtocol.Factory(), next, loggerFactory)
+        {
+        }
+
+        public THttpServerTransport(ITAsyncProcessor processor, ITProtocolFactory protocolFactory, RequestDelegate next,
+            ILoggerFactory loggerFactory)
+            : this(processor, protocolFactory, protocolFactory, next, loggerFactory)
+        {
+        }
+
+        public THttpServerTransport(ITAsyncProcessor processor, ITProtocolFactory inputProtocolFactory,
+            ITProtocolFactory outputProtocolFactory, RequestDelegate next, ILoggerFactory loggerFactory)
+        {
+            if (loggerFactory == null)
+            {
+                throw new ArgumentNullException(nameof(loggerFactory));
+            }
+
+            Processor = processor ?? throw new ArgumentNullException(nameof(processor));
+            InputProtocolFactory = inputProtocolFactory ?? throw new ArgumentNullException(nameof(inputProtocolFactory));
+            OutputProtocolFactory = outputProtocolFactory ?? throw new ArgumentNullException(nameof(outputProtocolFactory));
+
+            _next = next;
+            _logger = loggerFactory.CreateLogger<THttpServerTransport>();
+        }
+
+        public async Task Invoke(HttpContext context)
+        {
+            context.Response.ContentType = ContentType;
+            await ProcessRequestAsync(context, context.RequestAborted); //TODO: check for correct logic
+        }
+
+        public async Task ProcessRequestAsync(HttpContext context, CancellationToken cancellationToken)
+        {
+            var transport = new TStreamClientTransport(context.Request.Body, context.Response.Body);
+
+            try
+            {
+                var input = InputProtocolFactory.GetProtocol(transport);
+                var output = OutputProtocolFactory.GetProtocol(transport);
+
+                while (await Processor.ProcessAsync(input, output, cancellationToken))
+                {
+                }
+            }
+            catch (TTransportException)
+            {
+                // Client died, just move on
+            }
+            finally
+            {
+                transport.Close();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/Server/TNamedPipeServerTransport.cs b/lib/netcore/Thrift/Transports/Server/TNamedPipeServerTransport.cs
new file mode 100644
index 0000000..186786e
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/Server/TNamedPipeServerTransport.cs
@@ -0,0 +1,191 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System;
+using System.IO.Pipes;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Thrift.Transports.Server
+{
+    // ReSharper disable once InconsistentNaming
+    public class TNamedPipeServerTransport : TServerTransport
+    {
+        /// <summary>
+        ///     This is the address of the Pipe on the localhost.
+        /// </summary>
+        private readonly string _pipeAddress;
+
+        private bool _asyncMode = true;
+        private volatile bool _isPending = true;
+
+        private NamedPipeServerStream _stream = null;
+
+        public TNamedPipeServerTransport(string pipeAddress)
+        {
+            _pipeAddress = pipeAddress;
+        }
+
+        public override void Listen()
+        {
+            // nothing to do here
+        }
+
+        public override void Close()
+        {
+            if (_stream != null)
+            {
+                try
+                {
+                    //TODO: check for disconection 
+                    _stream.Disconnect();
+                    _stream.Dispose();
+                }
+                finally
+                {
+                    _stream = null;
+                    _isPending = false;
+                }
+            }
+        }
+
+        public override bool IsClientPending()
+        {
+            return _isPending;
+        }
+
+        private void EnsurePipeInstance()
+        {
+            if (_stream == null)
+            {
+                var direction = PipeDirection.InOut;
+                var maxconn = 254;
+                var mode = PipeTransmissionMode.Byte;
+                var options = _asyncMode ? PipeOptions.Asynchronous : PipeOptions.None;
+                var inbuf = 4096;
+                var outbuf = 4096;
+                // TODO: security
+
+                try
+                {
+                    _stream = new NamedPipeServerStream(_pipeAddress, direction, maxconn, mode, options, inbuf, outbuf);
+                }
+                catch (NotImplementedException) // Mono still does not support async, fallback to sync
+                {
+                    if (_asyncMode)
+                    {
+                        options &= (~PipeOptions.Asynchronous);
+                        _stream = new NamedPipeServerStream(_pipeAddress, direction, maxconn, mode, options, inbuf,
+                            outbuf);
+                        _asyncMode = false;
+                    }
+                    else
+                    {
+                        throw;
+                    }
+                }
+            }
+        }
+
+        protected override async Task<TClientTransport> AcceptImplementationAsync(CancellationToken cancellationToken)
+        {
+            try
+            {
+                EnsurePipeInstance();
+
+                await _stream.WaitForConnectionAsync(cancellationToken);
+
+                var trans = new ServerTransport(_stream);
+                _stream = null; // pass ownership to ServerTransport
+
+                //_isPending = false;
+
+                return trans;
+            }
+            catch (TTransportException)
+            {
+                Close();
+                throw;
+            }
+            catch (Exception e)
+            {
+                Close();
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, e.Message);
+            }
+        }
+
+        private class ServerTransport : TClientTransport
+        {
+            private readonly NamedPipeServerStream _stream;
+
+            public ServerTransport(NamedPipeServerStream stream)
+            {
+                _stream = stream;
+            }
+
+            public override bool IsOpen => _stream != null && _stream.IsConnected;
+
+            public override async Task OpenAsync(CancellationToken cancellationToken)
+            {
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    await Task.FromCanceled(cancellationToken);
+                }
+            }
+
+            public override void Close()
+            {
+                _stream?.Dispose();
+            }
+
+            public override async Task<int> ReadAsync(byte[] buffer, int offset, int length,
+                CancellationToken cancellationToken)
+            {
+                if (_stream == null)
+                {
+                    throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+                }
+
+                return await _stream.ReadAsync(buffer, offset, length, cancellationToken);
+            }
+
+            public override async Task WriteAsync(byte[] buffer, int offset, int length,
+                CancellationToken cancellationToken)
+            {
+                if (_stream == null)
+                {
+                    throw new TTransportException(TTransportException.ExceptionType.NotOpen);
+                }
+
+                await _stream.WriteAsync(buffer, offset, length, cancellationToken);
+            }
+
+            public override async Task FlushAsync(CancellationToken cancellationToken)
+            {
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    await Task.FromCanceled(cancellationToken);
+                }
+            }
+
+            protected override void Dispose(bool disposing)
+            {
+                _stream?.Dispose();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/Server/TServerFramedTransport.cs b/lib/netcore/Thrift/Transports/Server/TServerFramedTransport.cs
new file mode 100644
index 0000000..0b86e9e
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/Server/TServerFramedTransport.cs
@@ -0,0 +1,150 @@
+// 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.
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Transports.Client;
+
+namespace Thrift.Transports.Server
+{
+    // ReSharper disable once InconsistentNaming
+    public class TServerFramedTransport : TServerTransport
+    {
+        private readonly int _clientTimeout;
+        private readonly int _port;
+        private TcpListener _server;
+
+        public TServerFramedTransport(TcpListener listener)
+            : this(listener, 0)
+        {
+        }
+
+        public TServerFramedTransport(TcpListener listener, int clientTimeout)
+        {
+            _server = listener;
+            _clientTimeout = clientTimeout;
+        }
+
+        public TServerFramedTransport(int port)
+            : this(port, 0)
+        {
+        }
+
+        public TServerFramedTransport(int port, int clientTimeout)
+        {
+            _port = port;
+            _clientTimeout = clientTimeout;
+            try
+            {
+                // Make server socket
+                _server = new TcpListener(IPAddress.Any, _port);
+                _server.Server.NoDelay = true;
+            }
+            catch (Exception)
+            {
+                _server = null;
+                throw new TTransportException("Could not create ServerSocket on port " + port + ".");
+            }
+        }
+
+        public override void Listen()
+        {
+            // Make sure not to block on accept
+            if (_server != null)
+            {
+                try
+                {
+                    _server.Start();
+                }
+                catch (SocketException sx)
+                {
+                    throw new TTransportException("Could not accept on listening socket: " + sx.Message);
+                }
+            }
+        }
+
+        public override bool IsClientPending()
+        {
+            return _server.Pending();
+        }
+
+        protected override async Task<TClientTransport> AcceptImplementationAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<TClientTransport>(cancellationToken);
+            }
+
+            if (_server == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket.");
+            }
+
+            try
+            {
+                TFramedClientTransport tSocketTransport = null;
+                var tcpClient = await _server.AcceptTcpClientAsync();
+
+                try
+                {
+                    tSocketTransport = new TFramedClientTransport(new TSocketClientTransport(tcpClient)
+                    {
+                        Timeout = _clientTimeout
+                    });
+
+                    return tSocketTransport;
+                }
+                catch (Exception)
+                {
+                    if (tSocketTransport != null)
+                    {
+                        tSocketTransport.Dispose();
+                    }
+                    else //  Otherwise, clean it up ourselves.
+                    {
+                        ((IDisposable) tcpClient).Dispose();
+                    }
+
+                    throw;
+                }
+            }
+            catch (Exception ex)
+            {
+                throw new TTransportException(ex.ToString());
+            }
+        }
+
+        public override void Close()
+        {
+            if (_server != null)
+            {
+                try
+                {
+                    _server.Stop();
+                }
+                catch (Exception ex)
+                {
+                    throw new TTransportException("WARNING: Could not close server socket: " + ex);
+                }
+                _server = null;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/Server/TServerSocketTransport.cs b/lib/netcore/Thrift/Transports/Server/TServerSocketTransport.cs
new file mode 100644
index 0000000..3a9d8a1
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/Server/TServerSocketTransport.cs
@@ -0,0 +1,174 @@
+// 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.
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Transports.Client;
+
+namespace Thrift.Transports.Server
+{
+    // ReSharper disable once InconsistentNaming
+    public class TServerSocketTransport : TServerTransport
+    {
+        private readonly int _clientTimeout;
+        private readonly int _port;
+        private readonly bool _useBufferedSockets;
+        private readonly bool _useFramedTransport;
+        private TcpListener _server;
+
+        public TServerSocketTransport(TcpListener listener)
+            : this(listener, 0)
+        {
+        }
+
+        public TServerSocketTransport(TcpListener listener, int clientTimeout)
+        {
+            _server = listener;
+            _clientTimeout = clientTimeout;
+        }
+
+        public TServerSocketTransport(int port)
+            : this(port, 0)
+        {
+        }
+
+        public TServerSocketTransport(int port, int clientTimeout)
+            : this(port, clientTimeout, false)
+        {
+        }
+
+        public TServerSocketTransport(int port, int clientTimeout, bool useBufferedSockets):
+            this(port, clientTimeout, useBufferedSockets, false)
+        {
+        }
+        
+        public TServerSocketTransport(int port, int clientTimeout, bool useBufferedSockets, bool useFramedTransport)
+        {
+            _port = port;
+            _clientTimeout = clientTimeout;
+            _useBufferedSockets = useBufferedSockets;
+            _useFramedTransport = useFramedTransport;
+            try
+            {
+                // Make server socket
+                _server = new TcpListener(IPAddress.Any, _port);
+                _server.Server.NoDelay = true;
+            }
+            catch (Exception)
+            {
+                _server = null;
+                throw new TTransportException("Could not create ServerSocket on port " + port + ".");
+            }
+        }
+
+        public override void Listen()
+        {
+            // Make sure not to block on accept
+            if (_server != null)
+            {
+                try
+                {
+                    _server.Start();
+                }
+                catch (SocketException sx)
+                {
+                    throw new TTransportException("Could not accept on listening socket: " + sx.Message);
+                }
+            }
+        }
+
+        public override bool IsClientPending()
+        {
+            return _server.Pending();
+        }
+
+        protected override async Task<TClientTransport> AcceptImplementationAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<TClientTransport>(cancellationToken);
+            }
+
+            if (_server == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket.");
+            }
+
+            try
+            {
+                TClientTransport tSocketTransport = null;
+                var tcpClient = await _server.AcceptTcpClientAsync();
+
+                try
+                {
+                    tSocketTransport = new TSocketClientTransport(tcpClient)
+                    {
+                        Timeout = _clientTimeout
+                    };
+
+                    if (_useBufferedSockets)
+                    {
+                        tSocketTransport = new TBufferedClientTransport(tSocketTransport);
+                    }
+
+                    if (_useFramedTransport)
+                    {
+                        tSocketTransport = new TFramedClientTransport(tSocketTransport);
+                    }
+
+                    return tSocketTransport;
+                }
+                catch (Exception)
+                {
+                    if (tSocketTransport != null)
+                    {
+                        tSocketTransport.Dispose();
+                    }
+                    else //  Otherwise, clean it up ourselves.
+                    {
+                        ((IDisposable) tcpClient).Dispose();
+                    }
+
+                    throw;
+                }
+            }
+            catch (Exception ex)
+            {
+                throw new TTransportException(ex.ToString());
+            }
+        }
+
+        public override void Close()
+        {
+            if (_server != null)
+            {
+                try
+                {
+                    _server.Stop();
+                }
+                catch (Exception ex)
+                {
+                    throw new TTransportException("WARNING: Could not close server socket: " + ex);
+                }
+                _server = null;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/Server/TTlsServerSocketTransport.cs b/lib/netcore/Thrift/Transports/Server/TTlsServerSocketTransport.cs
new file mode 100644
index 0000000..759feed
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/Server/TTlsServerSocketTransport.cs
@@ -0,0 +1,177 @@
+// 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.
+
+using System;
+using System.Net;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Transports.Client;
+
+namespace Thrift.Transports.Server
+{
+    // ReSharper disable once InconsistentNaming
+    public class TTlsServerSocketTransport : TServerTransport
+    {
+        private readonly RemoteCertificateValidationCallback _clientCertValidator;
+        private readonly int _clientTimeout = 0;
+        private readonly LocalCertificateSelectionCallback _localCertificateSelectionCallback;
+        private readonly int _port;
+        private readonly X509Certificate2 _serverCertificate;
+        private readonly SslProtocols _sslProtocols;
+        private readonly bool _useBufferedSockets;
+        private readonly bool _useFramedTransport;
+        private TcpListener _server;
+
+        public TTlsServerSocketTransport(int port, X509Certificate2 certificate)
+            : this(port, false, certificate)
+        {
+        }
+
+        public TTlsServerSocketTransport(
+            int port,
+            bool useBufferedSockets,
+            X509Certificate2 certificate,
+            RemoteCertificateValidationCallback clientCertValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            SslProtocols sslProtocols = SslProtocols.Tls12) 
+            : this(port, useBufferedSockets, false, certificate,
+                clientCertValidator, localCertificateSelectionCallback, sslProtocols)
+        {
+        }
+        
+        public TTlsServerSocketTransport(
+            int port,
+            bool useBufferedSockets,
+            bool useFramedTransport,
+            X509Certificate2 certificate,
+            RemoteCertificateValidationCallback clientCertValidator = null,
+            LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
+            SslProtocols sslProtocols = SslProtocols.Tls12)
+        {
+            if (!certificate.HasPrivateKey)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown,
+                    "Your server-certificate needs to have a private key");
+            }
+
+            _port = port;
+            _serverCertificate = certificate;
+            _useBufferedSockets = useBufferedSockets;
+            _useFramedTransport = useFramedTransport;
+            _clientCertValidator = clientCertValidator;
+            _localCertificateSelectionCallback = localCertificateSelectionCallback;
+            _sslProtocols = sslProtocols;
+
+            try
+            {
+                // Create server socket
+                _server = new TcpListener(IPAddress.Any, _port);
+                _server.Server.NoDelay = true;
+            }
+            catch (Exception)
+            {
+                _server = null;
+                throw new TTransportException($"Could not create ServerSocket on port {port}.");
+            }
+        }
+
+        public override void Listen()
+        {
+            // Make sure accept is not blocking
+            if (_server != null)
+            {
+                try
+                {
+                    _server.Start();
+                }
+                catch (SocketException sx)
+                {
+                    throw new TTransportException($"Could not accept on listening socket: {sx.Message}");
+                }
+            }
+        }
+
+        public override bool IsClientPending()
+        {
+            return _server.Pending();
+        }
+
+        protected override async Task<TClientTransport> AcceptImplementationAsync(CancellationToken cancellationToken)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<TClientTransport>(cancellationToken);
+            }
+
+            if (_server == null)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No underlying server socket.");
+            }
+
+            try
+            {
+                var client = await _server.AcceptTcpClientAsync();
+                client.SendTimeout = client.ReceiveTimeout = _clientTimeout;
+
+                //wrap the client in an SSL Socket passing in the SSL cert
+                var tTlsSocket = new TTlsSocketClientTransport(client, _serverCertificate, true, _clientCertValidator,
+                    _localCertificateSelectionCallback, _sslProtocols);
+
+                await tTlsSocket.SetupTlsAsync();
+
+                TClientTransport trans = tTlsSocket;
+                
+                if (_useBufferedSockets)
+                {
+                    trans = new TBufferedClientTransport(trans);
+                }
+
+                if (_useFramedTransport)
+                {
+                    trans = new TFramedClientTransport(trans);
+                }
+                
+                return trans;
+            }
+            catch (Exception ex)
+            {
+                throw new TTransportException(ex.ToString());
+            }
+        }
+
+        public override void Close()
+        {
+            if (_server != null)
+            {
+                try
+                {
+                    _server.Stop();
+                }
+                catch (Exception ex)
+                {
+                    throw new TTransportException($"WARNING: Could not close server socket: {ex}");
+                }
+
+                _server = null;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/TClientTransport.cs b/lib/netcore/Thrift/Transports/TClientTransport.cs
new file mode 100644
index 0000000..0dd96cb
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/TClientTransport.cs
@@ -0,0 +1,179 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Thrift.Transports
+{
+    //TODO: think about client info 
+    // ReSharper disable once InconsistentNaming
+    public abstract class TClientTransport : IDisposable
+    {
+        //TODO: think how to avoid peek byte
+        private readonly byte[] _peekBuffer = new byte[1];
+        private bool _hasPeekByte;
+        public abstract bool IsOpen { get; }
+
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        public async Task<bool> PeekAsync(CancellationToken cancellationToken)
+        {
+            //If we already have a byte read but not consumed, do nothing.
+            if (_hasPeekByte)
+            {
+                return true;
+            }
+
+            //If transport closed we can't peek.
+            if (!IsOpen)
+            {
+                return false;
+            }
+
+            //Try to read one byte. If succeeds we will need to store it for the next read.
+            try
+            {
+                var bytes = await ReadAsync(_peekBuffer, 0, 1, cancellationToken);
+                if (bytes == 0)
+                {
+                    return false;
+                }
+            }
+            catch (IOException)
+            {
+                return false;
+            }
+
+            _hasPeekByte = true;
+            return true;
+        }
+
+        public virtual async Task OpenAsync()
+        {
+            await OpenAsync(CancellationToken.None);
+        }
+
+        public abstract Task OpenAsync(CancellationToken cancellationToken);
+
+        public abstract void Close();
+
+        protected static void ValidateBufferArgs(byte[] buffer, int offset, int length)
+        {
+            if (buffer == null)
+            {
+                throw new ArgumentNullException(nameof(buffer));
+            }
+
+            if (offset < 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(offset), "Buffer offset is smaller than zero.");
+            }
+
+            if (length < 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(length), "Buffer length is smaller than zero.");
+            }
+
+            if (offset + length > buffer.Length)
+            {
+                throw new ArgumentOutOfRangeException(nameof(buffer), "Not enough data.");
+            }
+        }
+
+        public virtual async Task<int> ReadAsync(byte[] buffer, int offset, int length)
+        {
+            return await ReadAsync(buffer, offset, length, CancellationToken.None);
+        }
+
+        public abstract Task<int> ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken);
+
+        public virtual async Task<int> ReadAllAsync(byte[] buffer, int offset, int length)
+        {
+            return await ReadAllAsync(buffer, offset, length, CancellationToken.None);
+        }
+
+        public virtual async Task<int> ReadAllAsync(byte[] buffer, int offset, int length,
+            CancellationToken cancellationToken)
+        {
+            ValidateBufferArgs(buffer, offset, length);
+
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return await Task.FromCanceled<int>(cancellationToken);
+            }
+
+            var retrieved = 0;
+
+            //If we previously peeked a byte, we need to use that first.
+            if (_hasPeekByte)
+            {
+                buffer[offset + retrieved++] = _peekBuffer[0];
+                _hasPeekByte = false;
+            }
+
+            while (retrieved < length)
+            {
+                if (cancellationToken.IsCancellationRequested)
+                {
+                    return await Task.FromCanceled<int>(cancellationToken);
+                }
+
+                var returnedCount = await ReadAsync(buffer, offset + retrieved, length - retrieved, cancellationToken);
+                if (returnedCount <= 0)
+                {
+                    throw new TTransportException(TTransportException.ExceptionType.EndOfFile,
+                        "Cannot read, Remote side has closed");
+                }
+                retrieved += returnedCount;
+            }
+            return retrieved;
+        }
+
+        public virtual async Task WriteAsync(byte[] buffer)
+        {
+            await WriteAsync(buffer, CancellationToken.None);
+        }
+
+        public virtual async Task WriteAsync(byte[] buffer, CancellationToken cancellationToken)
+        {
+            await WriteAsync(buffer, 0, buffer.Length, CancellationToken.None);
+        }
+
+        public virtual async Task WriteAsync(byte[] buffer, int offset, int length)
+        {
+            await WriteAsync(buffer, offset, length, CancellationToken.None);
+        }
+
+        public abstract Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken);
+
+        public virtual async Task FlushAsync()
+        {
+            await FlushAsync(CancellationToken.None);
+        }
+
+        public abstract Task FlushAsync(CancellationToken cancellationToken);
+
+        protected abstract void Dispose(bool disposing);
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/TServerTransport.cs b/lib/netcore/Thrift/Transports/TServerTransport.cs
new file mode 100644
index 0000000..0d45a55
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/TServerTransport.cs
@@ -0,0 +1,54 @@
+// 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.
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Thrift.Transports
+{
+    // ReSharper disable once InconsistentNaming
+    public abstract class TServerTransport
+    {
+        public abstract void Listen();
+        public abstract void Close();
+        public abstract bool IsClientPending();
+
+        protected virtual async Task<TClientTransport> AcceptImplementationAsync()
+        {
+            return await AcceptImplementationAsync(CancellationToken.None);
+        }
+
+        protected abstract Task<TClientTransport> AcceptImplementationAsync(CancellationToken cancellationToken);
+
+        public async Task<TClientTransport> AcceptAsync()
+        {
+            return await AcceptAsync(CancellationToken.None);
+        }
+
+        public async Task<TClientTransport> AcceptAsync(CancellationToken cancellationToken)
+        {
+            var transport = await AcceptImplementationAsync(cancellationToken);
+
+            if (transport == null)
+            {
+                throw new TTransportException($"{nameof(AcceptImplementationAsync)} should not return null");
+            }
+
+            return transport;
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/TTransportException.cs b/lib/netcore/Thrift/Transports/TTransportException.cs
new file mode 100644
index 0000000..b7c42e3
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/TTransportException.cs
@@ -0,0 +1,58 @@
+// 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.
+
+namespace Thrift.Transports
+{
+    // ReSharper disable once InconsistentNaming
+    public class TTransportException : TException
+    {
+        public enum ExceptionType
+        {
+            Unknown,
+            NotOpen,
+            AlreadyOpen,
+            TimedOut,
+            EndOfFile,
+            Interrupted
+        }
+
+        protected ExceptionType ExType;
+
+        public TTransportException()
+        {
+        }
+
+        public TTransportException(ExceptionType exType)
+            : this()
+        {
+            ExType = exType;
+        }
+
+        public TTransportException(ExceptionType exType, string message)
+            : base(message)
+        {
+            ExType = exType;
+        }
+
+        public TTransportException(string message)
+            : base(message)
+        {
+        }
+
+        public ExceptionType Type => ExType;
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/Thrift/Transports/TTransportFactory.cs b/lib/netcore/Thrift/Transports/TTransportFactory.cs
new file mode 100644
index 0000000..26c3cc4
--- /dev/null
+++ b/lib/netcore/Thrift/Transports/TTransportFactory.cs
@@ -0,0 +1,35 @@
+// 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.
+
+namespace Thrift.Transports
+{
+    /// <summary>
+    ///     From Mark Slee & Aditya Agarwal of Facebook:
+    ///     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)
+    /// </summary>
+    // ReSharper disable once InconsistentNaming
+    public class TTransportFactory
+    {
+        public virtual TClientTransport GetTransport(TClientTransport trans)
+        {
+            return trans;
+        }
+    }
+}
\ No newline at end of file
diff --git a/lib/netcore/build.cmd b/lib/netcore/build.cmd
new file mode 100644
index 0000000..863c4b4
--- /dev/null
+++ b/lib/netcore/build.cmd
@@ -0,0 +1,27 @@
+@echo off
+rem /*
+rem  * Licensed to the Apache Software Foundation (ASF) under one
+rem  * or more contributor license agreements. See the NOTICE file
+rem  * distributed with this work for additional information
+rem  * regarding copyright ownership. The ASF licenses this file
+rem  * to you under the Apache License, Version 2.0 (the
+rem  * "License"); you may not use this file except in compliance
+rem  * with the License. You may obtain a copy of the License at
+rem  *
+rem  *   http://www.apache.org/licenses/LICENSE-2.0
+rem  *
+rem  * Unless required by applicable law or agreed to in writing,
+rem  * software distributed under the License is distributed on an
+rem  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem  * KIND, either express or implied. See the License for the
+rem  * specific language governing permissions and limitations
+rem  * under the License.
+rem  */
+
+setlocal
+
+thrift -version
+dotnet --info
+dotnet build 
+
+:eof
diff --git a/lib/netcore/build.sh b/lib/netcore/build.sh
new file mode 100644
index 0000000..ae18bce
--- /dev/null
+++ b/lib/netcore/build.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+#
+# 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.
+#
+
+#exit if any command fails
+#set -e
+
+thrift --version
+dotnet --info
+dotnet build 
+
+#revision=${TRAVIS_JOB_ID:=1}  
+#revision=$(printf "%04d" $revision) 
+
+#dotnet pack ./src/PROJECT_NAME -c Release -o ./artifacts --version-suffix=$revision  
diff --git a/lib/netcore/runtests.cmd b/lib/netcore/runtests.cmd
new file mode 100644
index 0000000..5114bc5
--- /dev/null
+++ b/lib/netcore/runtests.cmd
@@ -0,0 +1,28 @@
+@echo off
+rem /*
+rem  * Licensed to the Apache Software Foundation (ASF) under one
+rem  * or more contributor license agreements. See the NOTICE file
+rem  * distributed with this work for additional information
+rem  * regarding copyright ownership. The ASF licenses this file
+rem  * to you under the Apache License, Version 2.0 (the
+rem  * "License"); you may not use this file except in compliance
+rem  * with the License. You may obtain a copy of the License at
+rem  *
+rem  *   http://www.apache.org/licenses/LICENSE-2.0
+rem  *
+rem  * Unless required by applicable law or agreed to in writing,
+rem  * software distributed under the License is distributed on an
+rem  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem  * KIND, either express or implied. See the License for the
+rem  * specific language governing permissions and limitations
+rem  * under the License.
+rem  */
+setlocal
+
+thrift -version
+dotnet --info
+
+dotnet test Tests\Thrift.IntegrationTests\Thrift.IntegrationTests.csproj
+dotnet test Tests\Thrift.Tests\Thrift.Tests.csproj
+
+:eof
diff --git a/lib/netcore/runtests.sh b/lib/netcore/runtests.sh
new file mode 100644
index 0000000..a26cc36
--- /dev/null
+++ b/lib/netcore/runtests.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+#
+# 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.
+#
+
+thrift -version
+dotnet --info
+
+dotnet test Tests\Thrift.IntegrationTests\Thrift.IntegrationTests.csproj
+dotnet test Tests\Thrift.Tests\Thrift.Tests.csproj
\ No newline at end of file
diff --git a/lib/nodejs/Makefile.am b/lib/nodejs/Makefile.am
new file mode 100755
index 0000000..68ea3ea
--- /dev/null
+++ b/lib/nodejs/Makefile.am
@@ -0,0 +1,43 @@
+# 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.
+
+# We call npm twice to work around npm issues
+
+stubs: $(top_srcdir)/test/ThriftTest.thrift
+	$(THRIFT) --gen js:node -o test/ $(top_srcdir)/test/ThriftTest.thrift
+
+deps: $(top_srcdir)/package.json
+	$(NPM) install $(top_srcdir)/ || $(NPM) install $(top_srcdir)/
+
+all-local: deps
+
+precross: deps stubs
+
+# TODO: Lint nodejs lib and gen-code as part of build
+check: deps
+	cd $(top_srcdir) && $(NPM) test && $(NPM) run lint-tests && cd lib/nodejs
+
+clean-local:
+	$(RM) -r test/gen-nodejs
+	$(RM) -r $(top_srcdir)/node_modules
+
+EXTRA_DIST = \
+	examples \
+	lib \
+	test \
+	coding_standards.md \
+	README.md
diff --git a/lib/nodejs/README.md b/lib/nodejs/README.md
index 02dfc74..50acfbd 100644
--- a/lib/nodejs/README.md
+++ b/lib/nodejs/README.md
@@ -1,25 +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.
+Thrift Node.js Library
+=========================
 
+License
+-------
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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
 
-NOTE: you must use the framed thrift transport, TFramedTransport in most
-implementations, on the server side. Using a popular example, this is enabled
-by default in Cassandra 0.7 (but configuration must be changed in Cassandra
-0.6.x and earlier).
+  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.
+
+## Compatibility
+
+node version 6 or later is required
 
 ## Install
 
@@ -27,7 +30,7 @@
 
 ## Thrift Compiler
 
-You can compile nodejs sources by running the following:
+You can compile IDL sources for Node.js with the following command:
 
     thrift --gen js:node thrift_file
 
@@ -35,35 +38,33 @@
 
 Here is a Cassandra example:
 
-    var thrift = require('thrift'),
-        Cassandra = require('./gen-nodejs/Cassandra')
-        ttypes = require('./gen-nodejs/cassandra_types');
+```js
+var thrift = require('thrift'),
+    Cassandra = require('./gen-nodejs/Cassandra')
+    ttypes = require('./gen-nodejs/cassandra_types');
 
-    var connection = thrift.createConnection("localhost", 9160),
-        client = thrift.createClient(Cassandra, connection);
+var connection = thrift.createConnection("localhost", 9160),
+    client = thrift.createClient(Cassandra, connection);
 
-    connection.on('error', function(err) {
-      console.error(err);
-    });
+connection.on('error', function(err) {
+  console.error(err);
+});
 
-    client.get_slice("Keyspace", "key", new ttypes.ColumnParent({column_family: "ExampleCF"}), new ttypes.SlicePredicate({slice_range: new ttypes.SliceRange({start: '', finish: ''})}), ttypes.ConsistencyLevel.ONE, function(err, data) {
-      if (err) {
-        // handle err
-      } else {
-        // data == [ttypes.ColumnOrSuperColumn, ...]
-      }
-      connection.end();
-    });
+client.get_slice("Keyspace", "key", new ttypes.ColumnParent({column_family: "ExampleCF"}), new ttypes.SlicePredicate({slice_range: new ttypes.SliceRange({start: '', finish: ''})}), ttypes.ConsistencyLevel.ONE, function(err, data) {
+  if (err) {
+    // handle err
+  } else {
+    // data == [ttypes.ColumnOrSuperColumn, ...]
+  }
+  connection.end();
+});
+```
 
 <a name="int64"></a>
 ## Int64
 
-Since JavaScript represents all numbers as doubles, int64 values cannot be accurately represented naturally. To solve this, int64 values in responses will be wrapped with Thirft.Int64 objects. The Int64 implementation used is [broofa/node-int64](https://github.com/broofa/node-int64).
+Since JavaScript represents all numbers as doubles, int64 values cannot be accurately represented naturally. To solve this, int64 values in responses will be wrapped with Thrift.Int64 objects. The Int64 implementation used is [broofa/node-int64](https://github.com/broofa/node-int64).
 
-## Libraries using node-thrift
+## Client and server examples
 
-* [yukim/node_cassandra](https://github.com/yukim/node_cassandra)
-
-## Custom client and server example
-
-An example based on the one shown on the Thrift front page is included in the examples/ folder.
+Several example clients and servers are included in the thrift/lib/nodejs/examples folder and the cross language tutorial thrift/tutorial/nodejs folder.
diff --git a/lib/nodejs/coding_standards.md b/lib/nodejs/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/nodejs/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/nodejs/examples/Makefile b/lib/nodejs/examples/Makefile
index b4283dc..87157db 100644
--- a/lib/nodejs/examples/Makefile
+++ b/lib/nodejs/examples/Makefile
@@ -18,7 +18,7 @@
 	../../../compiler/cpp/thrift --gen js:node user.thrift
 
 server: all	
-	NODE_PATH=../lib:../lib/thrift node server.js
+	NODE_PATH=../lib:../lib/thrift:$(NODE_PATH) node server.js
 
 client: all	
-	NODE_PATH=../lib:../lib/thrift node client.js
+	NODE_PATH=../lib:../lib/thrift:$(NODE_PATH) node client.js
diff --git a/lib/nodejs/examples/README.md b/lib/nodejs/examples/README.md
index a87581f..7350c10 100644
--- a/lib/nodejs/examples/README.md
+++ b/lib/nodejs/examples/README.md
@@ -1,29 +1,40 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-# Running the user example
+# Thrift Node.js Examples
 
-#Generate the bindings:
-../../../compiler/cpp/thrift --gen js:node user.thrift
+## License
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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
 
-#To run the user example, first start up the server in one terminal:
-NODE_PATH=../lib:../lib/thrift node server.js
+  http://www.apache.org/licenses/LICENSE-2.0
 
-#Now run the client:
-NODE_PATH=../lib:../lib/thrift node client.js
+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.
 
+## Running the user example
 
-    
+Generate the bindings:
+
+    ../../../compiler/cpp/thrift --gen js:node user.thrift
+    ../../../compiler/cpp/thrift --gen js:node --gen py hello.thrift
+
+To run the user example, first start up the server in one terminal:
+
+    NODE_PATH=../lib:../lib/thrift node server.js
+
+Now run the client:
+
+    NODE_PATH=../lib:../lib/thrift node client.js
+
+For an example using JavaScript in the browser to connect to
+a node.js server look at hello.html, hello.js and hello.thrift
+
+HTTP examples are provided also: httpClient.js and httpServer.js
+You can test HTTP cross platform with the httpServer.py Python server
diff --git a/lib/nodejs/examples/hello.html b/lib/nodejs/examples/hello.html
new file mode 100644
index 0000000..fe85a7e
--- /dev/null
+++ b/lib/nodejs/examples/hello.html
@@ -0,0 +1,65 @@
+<!--
+ * 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.
+-->
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <title>Apache Thrift JavaScript Browser Client Demo</title>
+    <script src="thrift.js" type="text/javascript"></script>
+    <script src="gen-js/HelloSvc.js" type="text/javascript"></script>
+    <script src="gen-js/TimesTwo.js" type="text/javascript"></script>
+</head>
+<body>
+    <h1>Apache Thrift JavaScript Browser Client Demo</h1>
+    <p>This html file demonstrates Apache Thrift JavaScrpt RPC between a browser client to a node.js server. Clicking the buttons below will call the RPC functions hosted by the Apache Thrift server at localhost:8585. The file hello.js contains the JavaScript node.js server required. Here are the steps to get the example running:</p>
+    <ol>
+        <li>Install Node.js <pre><a href="http://nodejs.org">nodejs.org</a></pre></li>
+        <li>Install Apache Thrift for node (note that the node package manager will create the node_modules folder in the current directory so make sure to run npm from the same directory as hello.js so that the server can find the Thrift libraries. This example requires Apache Thrift 0.9.2+) <pre>$ npm install thrift</pre></li>
+        <li>Compile the hello.idl for JavaScript and Node.js (you'll need to have the Apache Thrift compiler installed for this step. This also needs to be executed in the same directory as hello.js because hello.js and hello.html look for the gen-nodejs and gen-js directories here.)<pre>$ thrift -gen js -gen js:node hello.thrift</pre></li>
+        <li>Run the node server in the directory with the hello.html file<pre>$ node hello.js</pre></li>
+        <li>Copy the Apache Thrift JavaScript library, thrift.js, into the directory with this html file.<pre>$ cp ...../thrift.js . (you should be able to use Bower to install the browser based Apache Thrift library in the near future.)</pre>
+        <li>Reload this page in a browser through the node server using using the URL: <pre>http://localhost:8585/hello.html</pre>then click a button below to make an RPC call</li>
+    </ol>
+    <button id="btn">Get Message from Node Server</button>
+    <button id="btnDbl">Double 25</button>
+    <script type="text/javascript">
+        document.getElementById("btn").addEventListener("click", getMessage, false);
+
+        function getMessage() {
+            var transport = new Thrift.TXHRTransport("http://localhost:8585/hello");
+            var protocol  = new Thrift.TJSONProtocol(transport);
+            var client = new HelloSvcClient(protocol);
+            var msg = client.hello_func();
+            document.getElementById("output").innerHTML = msg;
+        }
+
+        document.getElementById("btnDbl").addEventListener("click", dblMessage, false);
+
+        function dblMessage() {
+            var transport = new Thrift.TXHRTransport("http://localhost:8585/dbl");
+            var protocol  = new Thrift.TJSONProtocol(transport);
+            var client = new TimesTwoClient(protocol);
+            var val = client.dbl(25);
+            document.getElementById("output2").innerHTML = val;
+        }
+    </script>
+    <h2>Server Response: <div id="output"></div></h2>
+    <h2>Server Dbl: <div id="output2"></div></h2>
+</body> 
+</html>
+
diff --git a/lib/nodejs/examples/hello.js b/lib/nodejs/examples/hello.js
new file mode 100644
index 0000000..8b7c4e4
--- /dev/null
+++ b/lib/nodejs/examples/hello.js
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var thrift = require('thrift');
+var HelloSvc = require('./gen-nodejs/HelloSvc.js');
+var TimesTwoSvc = require('./gen-nodejs/TimesTwo.js');
+
+var helloHandler = {
+	hello_func: function(result) {
+		this.call_counter = this.call_counter || 0;
+		console.log("Client call: " + (++this.call_counter));
+		result(null, "Hello Apache Thrift for JavaScript " + this.call_counter);
+	}
+}
+
+var timesTwoHandler = {
+	dbl: function(val, result) {
+		console.log("Client call: " + val);
+		result(null, val * 2);
+	}
+}
+
+var helloService = {
+	transport: thrift.TBufferedTransport,
+	protocol: thrift.TJSONProtocol,
+	processor: HelloSvc,
+	handler: helloHandler
+};
+
+var dblService = {
+	transport: thrift.TBufferedTransport,
+	protocol: thrift.TJSONProtocol,
+	processor: TimesTwoSvc,
+	handler: timesTwoHandler
+};
+
+var ServerOptions = {
+	files: ".",
+	services: {
+		"/hello": helloService,
+		"/dbl": dblService,
+	}
+}
+
+var server = thrift.createWebServer(ServerOptions);
+var port = 8585;
+server.listen(port);
+console.log("Http/Thrift Server running on port: " + port);
diff --git a/lib/nodejs/examples/hello.thrift b/lib/nodejs/examples/hello.thrift
new file mode 100644
index 0000000..deaf5a5
--- /dev/null
+++ b/lib/nodejs/examples/hello.thrift
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+service HelloSvc {
+    string hello_func(),
+}
+
+service TimesTwo {
+    i64 dbl(1: i64 val),
+}
+
+
diff --git a/lib/nodejs/examples/httpClient.js b/lib/nodejs/examples/httpClient.js
new file mode 100644
index 0000000..19cc0c3
--- /dev/null
+++ b/lib/nodejs/examples/httpClient.js
@@ -0,0 +1,23 @@
+var thrift = require('thrift');
+var helloSvc = require('./gen-nodejs/HelloSvc.js');
+
+var options = {
+   transport: thrift.TBufferedTransport,
+   protocol: thrift.TJSONProtocol,
+   path: "/hello",
+   headers: {"Connection": "close"},
+   https: false
+};
+
+var connection = thrift.createHttpConnection("localhost", 9090, options);
+var client = thrift.createHttpClient(helloSvc, connection);
+
+connection.on("error", function(err) {
+   console.log("Error: " + err);
+});
+
+client.hello_func(function(error, result) {
+   console.log("Msg from server: " + result);
+});
+
+
diff --git a/lib/nodejs/examples/httpServer.js b/lib/nodejs/examples/httpServer.js
new file mode 100644
index 0000000..acae136
--- /dev/null
+++ b/lib/nodejs/examples/httpServer.js
@@ -0,0 +1,31 @@
+var thrift = require('thrift');                 	
+var helloSvc = require('./gen-nodejs/HelloSvc');
+
+//ServiceHandler: Implement the hello service 
+var helloHandler = {
+  hello_func: function (result) {
+    console.log("Received Hello call");
+    result(null, "Hello from Node.js");
+  }
+};
+
+//ServiceOptions: The I/O stack for the service
+var helloSvcOpt = {                       		
+    handler: helloHandler,                      	
+    processor: helloSvc,                         	
+    protocol: thrift.TJSONProtocol,                 
+    transport: thrift.TBufferedTransport 		
+};                                  
+
+//ServerOptions: Define server features
+var serverOpt = {                          	
+   services: {                         
+      "/hello": helloSvcOpt                 
+   }                               
+}                                   
+
+//Create and start the web server 
+var port = 9090;                            		
+thrift.createWebServer(serverOpt).listen(port);                        		
+console.log("Http/Thrift Server running on port: " + port);
+
diff --git a/lib/nodejs/examples/httpServer.py b/lib/nodejs/examples/httpServer.py
new file mode 100644
index 0000000..b712fcd
--- /dev/null
+++ b/lib/nodejs/examples/httpServer.py
@@ -0,0 +1,18 @@
+import sys
+sys.path.append('gen-py')
+
+from hello import HelloSvc
+from thrift.protocol import TJSONProtocol
+from thrift.server import THttpServer
+
+class HelloSvcHandler:
+  def hello_func(self):
+    print("Hello Called")
+    return "hello from Python"
+
+processor = HelloSvc.Processor(HelloSvcHandler())
+protoFactory = TJSONProtocol.TJSONProtocolFactory()
+port = 9090
+server = THttpServer.THttpServer(processor, ("localhost", port), protoFactory)
+print "Python server running on port " + str(port)
+server.serve()
diff --git a/lib/nodejs/examples/server_http.js b/lib/nodejs/examples/server_http.js
new file mode 100644
index 0000000..ef2dc83
--- /dev/null
+++ b/lib/nodejs/examples/server_http.js
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var connect = require('connect');
+var thrift = require('thrift');
+
+var UserStorage = require('./gen-nodejs/UserStorage'),
+    ttypes = require('./gen-nodejs/user_types');
+
+var users = {};
+
+var store = function(user, result) {
+  console.log("stored:", user.uid);
+  users[user.uid] = user;
+  result(null);
+};
+var retrieve = function(uid, result) {
+  console.log("retrieved:", uid);
+  result(null, users[uid]);
+};
+
+var server_http = thrift.createHttpServer(UserStorage, {
+  store: store,
+  retrieve: retrieve
+});
+server_http.listen(9090);
+
+var server_connect = connect(thrift.httpMiddleware(UserStorage, {
+ store: store,
+ retrieve: retrieve
+}));
+server_http.listen(9091);
+
+var server_connect_json = connect(thrift.httpMiddleware(UserStorage, {
+ store: store,
+ retrieve: retrieve
+}, {protocol: thrift.TJSONProtocol}));
+server_connect_json.listen(9092);
diff --git a/lib/nodejs/examples/user.thrift b/lib/nodejs/examples/user.thrift
index ee260e5..d087fd4 100644
--- a/lib/nodejs/examples/user.thrift
+++ b/lib/nodejs/examples/user.thrift
@@ -14,7 +14,7 @@
 # KIND, either express or implied. See the License for the
 # specific language governing permissions and limitations
 # under the License.
- 
+
 struct UserProfile {
   1: i32 uid,
   2: string name,
diff --git a/lib/nodejs/lib/thrift/binary.js b/lib/nodejs/lib/thrift/binary.js
index 62c3f72..9813ffd 100644
--- a/lib/nodejs/lib/thrift/binary.js
+++ b/lib/nodejs/lib/thrift/binary.js
@@ -17,18 +17,18 @@
  * under the License.
  */
 
-var POW_8 = Math.pow(2, 8)
-var POW_16 = Math.pow(2, 16)
-var POW_24 = Math.pow(2, 24)
-var POW_32 = Math.pow(2, 32)
-var POW_40 = Math.pow(2, 40)
-var POW_48 = Math.pow(2, 48)
-var POW_52 = Math.pow(2, 52)
-var POW_1022 = Math.pow(2, 1022)
+var POW_8 = Math.pow(2, 8);
+var POW_16 = Math.pow(2, 16);
+var POW_24 = Math.pow(2, 24);
+var POW_32 = Math.pow(2, 32);
+var POW_40 = Math.pow(2, 40);
+var POW_48 = Math.pow(2, 48);
+var POW_52 = Math.pow(2, 52);
+var POW_1022 = Math.pow(2, 1022);
 
-exports.readByte = function(byte){
-	return byte > 127 ? byte-256 : byte;
-}
+exports.readByte = function(b){
+	return b > 127 ? b-256 : b;
+};
 
 exports.readI16 = function(buff, off) {
   off = off || 0;
@@ -38,7 +38,7 @@
     v -= POW_16;
   }
   return v;
-}
+};
 
 exports.readI32 = function(buff, off) {
   off = off || 0;
@@ -50,14 +50,14 @@
     v -= POW_32;
   }
   return v;
-}
+};
 
 exports.writeI16 = function(buff, v) {
   buff[1] = v & 0xff;
   v >>= 8;
   buff[0] = v & 0xff;
   return buff;
-}
+};
 
 exports.writeI32 = function(buff, v) {
   buff[3] = v & 0xff;
@@ -68,7 +68,7 @@
   v >>= 8;
   buff[0] = v & 0xff;
   return buff;
-}
+};
 
 exports.readDouble = function(buff, off) {
   off = off || 0;
@@ -86,7 +86,7 @@
 
   switch (e) {
     case 0:
-      e = -1022
+      e = -1022;
       break;
     case 2047:
       return m ? NaN : (signed ? -Infinity : Infinity);
@@ -100,7 +100,7 @@
   }
 
   return m * Math.pow(2, e - 52);
-}
+};
 
 /*
  * Based on code from the jspack module:
@@ -109,9 +109,9 @@
 exports.writeDouble = function(buff, v) {
   var m, e, c;
 
-  buff[0] = (v < 0 ? 0x80 : 0x00)
+  buff[0] = (v < 0 ? 0x80 : 0x00);
 
-  v = Math.abs(v)
+  v = Math.abs(v);
   if (v !== v) {
     // NaN, use QNaN IEEE format
     m = 2251799813685248;
@@ -120,8 +120,8 @@
     m = 0;
     e = 2047;
   } else {
-    e = Math.floor(Math.log(v) / Math.LN2)
-    c = Math.pow(2, -e)
+    e = Math.floor(Math.log(v) / Math.LN2);
+    c = Math.pow(2, -e);
     if (v * c < 1) {
       e--;
       c *= 2;
@@ -165,4 +165,4 @@
   buff[1] |= m & 0x0f;
 
   return buff;
-}
+};
diff --git a/lib/nodejs/lib/thrift/binary_protocol.js b/lib/nodejs/lib/thrift/binary_protocol.js
new file mode 100644
index 0000000..b57c8c5
--- /dev/null
+++ b/lib/nodejs/lib/thrift/binary_protocol.js
@@ -0,0 +1,365 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var log = require('./log');
+var binary = require('./binary');
+var Int64 = require('node-int64');
+var Thrift = require('./thrift');
+var Type = Thrift.Type;
+
+module.exports = TBinaryProtocol;
+
+// JavaScript supports only numeric doubles, therefore even hex values are always signed.
+// The largest integer value which can be represented in JavaScript is +/-2^53.
+// Bitwise operations convert numbers to 32 bit integers but perform sign extension
+// upon assigning values back to variables.
+var VERSION_MASK = -65536,   // 0xffff0000
+    VERSION_1 = -2147418112, // 0x80010000
+    TYPE_MASK = 0x000000ff;
+
+function TBinaryProtocol(trans, strictRead, strictWrite) {
+  this.trans = trans;
+  this.strictRead = (strictRead !== undefined ? strictRead : false);
+  this.strictWrite = (strictWrite !== undefined ? strictWrite : true);
+  this._seqid = null;
+};
+
+TBinaryProtocol.prototype.flush = function() {
+  return this.trans.flush();
+};
+
+TBinaryProtocol.prototype.writeMessageBegin = function(name, type, seqid) {
+    if (this.strictWrite) {
+      this.writeI32(VERSION_1 | type);
+      this.writeString(name);
+      this.writeI32(seqid);
+    } else {
+      this.writeString(name);
+      this.writeByte(type);
+      this.writeI32(seqid);
+    }
+    // Record client seqid to find callback again
+    if (this._seqid !== null) {
+      log.warning('SeqId already set', { 'name': name });
+    } else {
+      this._seqid = seqid;
+      this.trans.setCurrSeqId(seqid);
+    }
+};
+
+TBinaryProtocol.prototype.writeMessageEnd = function() {
+    if (this._seqid !== null) {
+        this._seqid = null;
+    } else {
+        log.warning('No seqid to unset');
+    }
+};
+
+TBinaryProtocol.prototype.writeStructBegin = function(name) {
+};
+
+TBinaryProtocol.prototype.writeStructEnd = function() {
+};
+
+TBinaryProtocol.prototype.writeFieldBegin = function(name, type, id) {
+  this.writeByte(type);
+  this.writeI16(id);
+};
+
+TBinaryProtocol.prototype.writeFieldEnd = function() {
+};
+
+TBinaryProtocol.prototype.writeFieldStop = function() {
+  this.writeByte(Type.STOP);
+};
+
+TBinaryProtocol.prototype.writeMapBegin = function(ktype, vtype, size) {
+  this.writeByte(ktype);
+  this.writeByte(vtype);
+  this.writeI32(size);
+};
+
+TBinaryProtocol.prototype.writeMapEnd = function() {
+};
+
+TBinaryProtocol.prototype.writeListBegin = function(etype, size) {
+  this.writeByte(etype);
+  this.writeI32(size);
+};
+
+TBinaryProtocol.prototype.writeListEnd = function() {
+};
+
+TBinaryProtocol.prototype.writeSetBegin = function(etype, size) {
+  this.writeByte(etype);
+  this.writeI32(size);
+};
+
+TBinaryProtocol.prototype.writeSetEnd = function() {
+};
+
+TBinaryProtocol.prototype.writeBool = function(bool) {
+  if (bool) {
+    this.writeByte(1);
+  } else {
+    this.writeByte(0);
+  }
+};
+
+TBinaryProtocol.prototype.writeByte = function(b) {
+  this.trans.write(new Buffer([b]));
+};
+
+TBinaryProtocol.prototype.writeI16 = function(i16) {
+  this.trans.write(binary.writeI16(new Buffer(2), i16));
+};
+
+TBinaryProtocol.prototype.writeI32 = function(i32) {
+  this.trans.write(binary.writeI32(new Buffer(4), i32));
+};
+
+TBinaryProtocol.prototype.writeI64 = function(i64) {
+  if (i64.buffer) {
+    this.trans.write(i64.buffer);
+  } else {
+    this.trans.write(new Int64(i64).buffer);
+  }
+};
+
+TBinaryProtocol.prototype.writeDouble = function(dub) {
+  this.trans.write(binary.writeDouble(new Buffer(8), dub));
+};
+
+TBinaryProtocol.prototype.writeStringOrBinary = function(name, encoding, arg) {
+  if (typeof(arg) === 'string') {
+    this.writeI32(Buffer.byteLength(arg, encoding));
+    this.trans.write(new Buffer(arg, encoding));
+  } else if ((arg instanceof Buffer) ||
+             (Object.prototype.toString.call(arg) == '[object Uint8Array]')) {
+    // Buffers in Node.js under Browserify may extend UInt8Array instead of
+    // defining a new object. We detect them here so we can write them
+    // correctly
+    this.writeI32(arg.length);
+    this.trans.write(arg);
+  } else {
+    throw new Error(name + ' called without a string/Buffer argument: ' + arg);
+  }
+};
+
+TBinaryProtocol.prototype.writeString = function(arg) {
+  this.writeStringOrBinary('writeString', 'utf8', arg);
+};
+
+TBinaryProtocol.prototype.writeBinary = function(arg) {
+  this.writeStringOrBinary('writeBinary', 'binary', arg);
+};
+
+TBinaryProtocol.prototype.readMessageBegin = function() {
+  var sz = this.readI32();
+  var type, name, seqid;
+
+  if (sz < 0) {
+    var version = sz & VERSION_MASK;
+    if (version != VERSION_1) {
+      throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "Bad version in readMessageBegin: " + sz);
+    }
+    type = sz & TYPE_MASK;
+    name = this.readString();
+    seqid = this.readI32();
+  } else {
+    if (this.strictRead) {
+      throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "No protocol version header");
+    }
+    name = this.trans.read(sz);
+    type = this.readByte();
+    seqid = this.readI32();
+  }
+  return {fname: name, mtype: type, rseqid: seqid};
+};
+
+TBinaryProtocol.prototype.readMessageEnd = function() {
+};
+
+TBinaryProtocol.prototype.readStructBegin = function() {
+  return {fname: ''};
+};
+
+TBinaryProtocol.prototype.readStructEnd = function() {
+};
+
+TBinaryProtocol.prototype.readFieldBegin = function() {
+  var type = this.readByte();
+  if (type == Type.STOP) {
+    return {fname: null, ftype: type, fid: 0};
+  }
+  var id = this.readI16();
+  return {fname: null, ftype: type, fid: id};
+};
+
+TBinaryProtocol.prototype.readFieldEnd = function() {
+};
+
+TBinaryProtocol.prototype.readMapBegin = function() {
+  var ktype = this.readByte();
+  var vtype = this.readByte();
+  var size = this.readI32();
+  return {ktype: ktype, vtype: vtype, size: size};
+};
+
+TBinaryProtocol.prototype.readMapEnd = function() {
+};
+
+TBinaryProtocol.prototype.readListBegin = function() {
+  var etype = this.readByte();
+  var size = this.readI32();
+  return {etype: etype, size: size};
+};
+
+TBinaryProtocol.prototype.readListEnd = function() {
+};
+
+TBinaryProtocol.prototype.readSetBegin = function() {
+  var etype = this.readByte();
+  var size = this.readI32();
+  return {etype: etype, size: size};
+};
+
+TBinaryProtocol.prototype.readSetEnd = function() {
+};
+
+TBinaryProtocol.prototype.readBool = function() {
+  var b = this.readByte();
+  if (b === 0) {
+    return false;
+  }
+  return true;
+};
+
+TBinaryProtocol.prototype.readByte = function() {
+  return this.trans.readByte();
+};
+
+TBinaryProtocol.prototype.readI16 = function() {
+  return this.trans.readI16();
+};
+
+TBinaryProtocol.prototype.readI32 = function() {
+  return this.trans.readI32();
+};
+
+TBinaryProtocol.prototype.readI64 = function() {
+  var buff = this.trans.read(8);
+  return new Int64(buff);
+};
+
+TBinaryProtocol.prototype.readDouble = function() {
+  return this.trans.readDouble();
+};
+
+TBinaryProtocol.prototype.readBinary = function() {
+  var len = this.readI32();
+  if (len === 0) {
+    return new Buffer(0);
+  }
+
+  if (len < 0) {
+    throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative binary size");
+  }
+  return this.trans.read(len);
+};
+
+TBinaryProtocol.prototype.readString = function() {
+  var len = this.readI32();
+  if (len === 0) {
+    return "";
+  }
+
+  if (len < 0) {
+    throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative string size");
+  }
+  return this.trans.readString(len);
+};
+
+TBinaryProtocol.prototype.getTransport = function() {
+  return this.trans;
+};
+
+TBinaryProtocol.prototype.skip = function(type) {
+  switch (type) {
+    case Type.STOP:
+      return;
+    case Type.BOOL:
+      this.readBool();
+      break;
+    case Type.BYTE:
+      this.readByte();
+      break;
+    case Type.I16:
+      this.readI16();
+      break;
+    case Type.I32:
+      this.readI32();
+      break;
+    case Type.I64:
+      this.readI64();
+      break;
+    case Type.DOUBLE:
+      this.readDouble();
+      break;
+    case Type.STRING:
+      this.readString();
+      break;
+    case Type.STRUCT:
+      this.readStructBegin();
+      while (true) {
+        var r = this.readFieldBegin();
+        if (r.ftype === Type.STOP) {
+          break;
+        }
+        this.skip(r.ftype);
+        this.readFieldEnd();
+      }
+      this.readStructEnd();
+      break;
+    case Type.MAP:
+      var mapBegin = this.readMapBegin();
+      for (var i = 0; i < mapBegin.size; ++i) {
+        this.skip(mapBegin.ktype);
+        this.skip(mapBegin.vtype);
+      }
+      this.readMapEnd();
+      break;
+    case Type.SET:
+      var setBegin = this.readSetBegin();
+      for (var i2 = 0; i2 < setBegin.size; ++i2) {
+        this.skip(setBegin.etype);
+      }
+      this.readSetEnd();
+      break;
+    case Type.LIST:
+      var listBegin = this.readListBegin();
+      for (var i3 = 0; i3 < listBegin.size; ++i3) {
+        this.skip(listBegin.etype);
+      }
+      this.readListEnd();
+      break;
+    default:
+      throw new  Error("Invalid type: " + type);
+  }
+};
diff --git a/lib/nodejs/lib/thrift/browser.js b/lib/nodejs/lib/thrift/browser.js
new file mode 100644
index 0000000..67ce853
--- /dev/null
+++ b/lib/nodejs/lib/thrift/browser.js
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+exports.Thrift = require('./thrift');
+
+var xhrConnection = require('./xhr_connection');
+exports.XHRConnection = xhrConnection.XHRConnection;
+exports.createXHRConnection = xhrConnection.createXHRConnection;
+exports.createXHRClient = xhrConnection.createXHRClient;
+
+exports.Multiplexer = require('./multiplexed_protocol').Multiplexer;
+
+exports.TWebSocketTransport = require('./ws_transport');
+exports.TBufferedTransport = require('./buffered_transport');
+exports.TFramedTransport = require('./framed_transport');
+
+exports.Protocol = exports.TJSONProtocol = require('./json_protocol');
+exports.TBinaryProtocol = require('./binary_protocol');
+exports.TCompactProtocol = require('./compact_protocol');
+
+exports.Int64 = require('node-int64');
diff --git a/lib/nodejs/lib/thrift/buffered_transport.js b/lib/nodejs/lib/thrift/buffered_transport.js
new file mode 100644
index 0000000..a9e006e
--- /dev/null
+++ b/lib/nodejs/lib/thrift/buffered_transport.js
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var binary = require('./binary');
+var InputBufferUnderrunError = require('./input_buffer_underrun_error');
+
+module.exports = TBufferedTransport;
+
+function TBufferedTransport(buffer, callback) {
+  this.defaultReadBufferSize = 1024;
+  this.writeBufferSize = 512; // Soft Limit
+  this.inBuf = new Buffer(this.defaultReadBufferSize);
+  this.readCursor = 0;
+  this.writeCursor = 0; // for input buffer
+  this.outBuffers = [];
+  this.outCount = 0;
+  this.onFlush = callback;
+};
+
+TBufferedTransport.prototype.reset = function() {
+  this.inBuf = new Buffer(this.defaultReadBufferSize);
+  this.readCursor = 0;
+  this.writeCursor = 0;
+  this.outBuffers = [];
+  this.outCount = 0;
+}
+
+TBufferedTransport.receiver = function(callback, seqid) {
+  var reader = new TBufferedTransport();
+
+  return function(data) {
+    if (reader.writeCursor + data.length > reader.inBuf.length) {
+      var buf = new Buffer(reader.writeCursor + data.length);
+      reader.inBuf.copy(buf, 0, 0, reader.writeCursor);
+      reader.inBuf = buf;
+    }
+    data.copy(reader.inBuf, reader.writeCursor, 0);
+    reader.writeCursor += data.length;
+
+    callback(reader, seqid);
+  };
+};
+
+
+TBufferedTransport.prototype.commitPosition = function(){
+  var unreadSize = this.writeCursor - this.readCursor;
+  var bufSize = (unreadSize * 2 > this.defaultReadBufferSize) ?
+    unreadSize * 2 : this.defaultReadBufferSize;
+  var buf = new Buffer(bufSize);
+  if (unreadSize > 0) {
+    this.inBuf.copy(buf, 0, this.readCursor, this.writeCursor);
+  }
+  this.readCursor = 0;
+  this.writeCursor = unreadSize;
+  this.inBuf = buf;
+};
+
+TBufferedTransport.prototype.rollbackPosition = function(){
+  this.readCursor = 0;
+}
+
+  // TODO: Implement open/close support
+TBufferedTransport.prototype.isOpen = function() {
+  return true;
+};
+
+TBufferedTransport.prototype.open = function() {
+};
+
+TBufferedTransport.prototype.close = function() {
+};
+
+  // Set the seqid of the message in the client
+  // So that callbacks can be found
+TBufferedTransport.prototype.setCurrSeqId = function(seqid) {
+  this._seqid = seqid;
+};
+
+TBufferedTransport.prototype.ensureAvailable = function(len) {
+  if (this.readCursor + len > this.writeCursor) {
+    throw new InputBufferUnderrunError();
+  }
+};
+
+TBufferedTransport.prototype.read = function(len) {
+  this.ensureAvailable(len);
+  var buf = new Buffer(len);
+  this.inBuf.copy(buf, 0, this.readCursor, this.readCursor + len);
+  this.readCursor += len;
+  return buf;
+};
+
+TBufferedTransport.prototype.readByte = function() {
+  this.ensureAvailable(1);
+  return binary.readByte(this.inBuf[this.readCursor++]);
+};
+
+TBufferedTransport.prototype.readI16 = function() {
+  this.ensureAvailable(2);
+  var i16 = binary.readI16(this.inBuf, this.readCursor);
+  this.readCursor += 2;
+  return i16;
+};
+
+TBufferedTransport.prototype.readI32 = function() {
+  this.ensureAvailable(4);
+  var i32 = binary.readI32(this.inBuf, this.readCursor);
+  this.readCursor += 4;
+  return i32;
+};
+
+TBufferedTransport.prototype.readDouble = function() {
+  this.ensureAvailable(8);
+  var d = binary.readDouble(this.inBuf, this.readCursor);
+  this.readCursor += 8;
+  return d;
+};
+
+TBufferedTransport.prototype.readString = function(len) {
+  this.ensureAvailable(len);
+  var str = this.inBuf.toString('utf8', this.readCursor, this.readCursor + len);
+  this.readCursor += len;
+  return str;
+};
+
+TBufferedTransport.prototype.borrow = function() {
+  var obj = {buf: this.inBuf, readIndex: this.readCursor, writeIndex: this.writeCursor};
+  return obj;
+};
+
+TBufferedTransport.prototype.consume = function(bytesConsumed) {
+  this.readCursor += bytesConsumed;
+};
+
+TBufferedTransport.prototype.write = function(buf) {
+  if (typeof(buf) === "string") {
+    buf = new Buffer(buf, 'utf8');
+  }
+  this.outBuffers.push(buf);
+  this.outCount += buf.length;
+};
+
+TBufferedTransport.prototype.flush = function() {
+  // If the seqid of the callback is available pass it to the onFlush
+  // Then remove the current seqid
+  var seqid = this._seqid;
+  this._seqid = null;
+
+  if (this.outCount < 1) {
+    return;
+  }
+
+  var msg = new Buffer(this.outCount),
+      pos = 0;
+  this.outBuffers.forEach(function(buf) {
+    buf.copy(msg, pos, 0);
+    pos += buf.length;
+  });
+
+  if (this.onFlush) {
+    // Passing seqid through this call to get it to the connection
+    this.onFlush(msg, seqid);
+  }
+
+  this.outBuffers = [];
+  this.outCount = 0;
+}
diff --git a/lib/nodejs/lib/thrift/compact_protocol.js b/lib/nodejs/lib/thrift/compact_protocol.js
new file mode 100644
index 0000000..5c531e5
--- /dev/null
+++ b/lib/nodejs/lib/thrift/compact_protocol.js
@@ -0,0 +1,917 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var log = require('./log');
+var Int64 = require('node-int64');
+var Thrift = require('./thrift');
+var Type = Thrift.Type;
+
+module.exports = TCompactProtocol;
+
+var POW_8 = Math.pow(2, 8);
+var POW_24 = Math.pow(2, 24);
+var POW_32 = Math.pow(2, 32);
+var POW_40 = Math.pow(2, 40);
+var POW_48 = Math.pow(2, 48);
+var POW_52 = Math.pow(2, 52);
+var POW_1022 = Math.pow(2, 1022);
+
+/**
+ * Constructor Function for the Compact Protocol.
+ * @constructor
+ * @param {object} [trans] - The underlying transport to read/write.
+ * @classdesc The Apache Thrift Protocol layer performs serialization
+ *     of base types, the compact protocol serializes data in binary
+ *     form with minimal space used for scalar values.
+ */
+function TCompactProtocol(trans) {
+  this.trans = trans;
+  this.lastField_ = [];
+  this.lastFieldId_ = 0;
+  this.string_limit_ = 0;
+  this.string_buf_ = null;
+  this.string_buf_size_ = 0;
+  this.container_limit_ = 0;
+  this.booleanField_ = {
+    name: null,
+    hasBoolValue: false
+  };
+  this.boolValue_ = {
+    hasBoolValue: false,
+    boolValue: false
+  };
+};
+
+
+//
+// Compact Protocol Constants
+//
+
+/**
+  * Compact Protocol ID number.
+  * @readonly
+  * @const {number} PROTOCOL_ID
+  */
+TCompactProtocol.PROTOCOL_ID = -126;  //1000 0010
+
+/**
+  * Compact Protocol version number.
+  * @readonly
+  * @const {number} VERSION_N
+  */
+TCompactProtocol.VERSION_N = 1;
+
+/**
+  * Compact Protocol version mask for combining protocol version and message type in one byte.
+  * @readonly
+  * @const {number} VERSION_MASK
+  */
+TCompactProtocol.VERSION_MASK = 0x1f; //0001 1111
+
+/**
+  * Compact Protocol message type mask for combining protocol version and message type in one byte.
+  * @readonly
+  * @const {number} TYPE_MASK
+  */
+TCompactProtocol.TYPE_MASK = -32;     //1110 0000
+
+/**
+  * Compact Protocol message type bits for ensuring message type bit size.
+  * @readonly
+  * @const {number} TYPE_BITS
+  */
+TCompactProtocol.TYPE_BITS = 7; //0000 0111
+
+/**
+  * Compact Protocol message type shift amount for combining protocol version and message type in one byte.
+  * @readonly
+  * @const {number} TYPE_SHIFT_AMOUNT
+  */
+TCompactProtocol.TYPE_SHIFT_AMOUNT = 5;
+
+/**
+ * Compact Protocol type IDs used to keep type data within one nibble.
+ * @readonly
+ * @property {number}  CT_STOP          - End of a set of fields.
+ * @property {number}  CT_BOOLEAN_TRUE  - Flag for Boolean field with true value (packed field and value).
+ * @property {number}  CT_BOOLEAN_FALSE - Flag for Boolean field with false value (packed field and value).
+ * @property {number}  CT_BYTE          - Signed 8 bit integer.
+ * @property {number}  CT_I16           - Signed 16 bit integer.
+ * @property {number}  CT_I32           - Signed 32 bit integer.
+ * @property {number}  CT_I64           - Signed 64 bit integer (2^53 max in JavaScript).
+ * @property {number}  CT_DOUBLE        - 64 bit IEEE 854 floating point.
+ * @property {number}  CT_BINARY        - Array of bytes (used for strings also).
+ * @property {number}  CT_LIST          - A collection type (unordered).
+ * @property {number}  CT_SET           - A collection type (unordered and without repeated values).
+ * @property {number}  CT_MAP           - A collection type (map/associative-array/dictionary).
+ * @property {number}  CT_STRUCT        - A multifield type.
+ */
+TCompactProtocol.Types = {
+  CT_STOP:           0x00,
+  CT_BOOLEAN_TRUE:   0x01,
+  CT_BOOLEAN_FALSE:  0x02,
+  CT_BYTE:           0x03,
+  CT_I16:            0x04,
+  CT_I32:            0x05,
+  CT_I64:            0x06,
+  CT_DOUBLE:         0x07,
+  CT_BINARY:         0x08,
+  CT_LIST:           0x09,
+  CT_SET:            0x0A,
+  CT_MAP:            0x0B,
+  CT_STRUCT:         0x0C
+};
+
+/**
+ * Array mapping Compact type IDs to standard Thrift type IDs.
+ * @readonly
+ */
+TCompactProtocol.TTypeToCType = [
+  TCompactProtocol.Types.CT_STOP,         // T_STOP
+  0,                                      // unused
+  TCompactProtocol.Types.CT_BOOLEAN_TRUE, // T_BOOL
+  TCompactProtocol.Types.CT_BYTE,         // T_BYTE
+  TCompactProtocol.Types.CT_DOUBLE,       // T_DOUBLE
+  0,                                      // unused
+  TCompactProtocol.Types.CT_I16,          // T_I16
+  0,                                      // unused
+  TCompactProtocol.Types.CT_I32,          // T_I32
+  0,                                      // unused
+  TCompactProtocol.Types.CT_I64,          // T_I64
+  TCompactProtocol.Types.CT_BINARY,       // T_STRING
+  TCompactProtocol.Types.CT_STRUCT,       // T_STRUCT
+  TCompactProtocol.Types.CT_MAP,          // T_MAP
+  TCompactProtocol.Types.CT_SET,          // T_SET
+  TCompactProtocol.Types.CT_LIST,         // T_LIST
+];
+
+
+//
+// Compact Protocol Utilities
+//
+
+/**
+ * Returns the underlying transport layer.
+ * @return {object} The underlying transport layer.
+ */TCompactProtocol.prototype.getTransport = function() {
+  return this.trans;
+};
+
+/**
+ * Lookup a Compact Protocol Type value for a given Thrift Type value.
+ * N.B. Used only internally.
+ * @param {number} ttype - Thrift type value
+ * @returns {number} Compact protocol type value
+ */
+TCompactProtocol.prototype.getCompactType = function(ttype) {
+  return TCompactProtocol.TTypeToCType[ttype];
+};
+
+/**
+ * Lookup a Thrift Type value for a given Compact Protocol Type value.
+ * N.B. Used only internally.
+ * @param {number} type - Compact Protocol type value
+ * @returns {number} Thrift Type value
+ */
+TCompactProtocol.prototype.getTType = function(type) {
+  switch (type) {
+    case Type.STOP:
+      return Type.STOP;
+    case TCompactProtocol.Types.CT_BOOLEAN_FALSE:
+    case TCompactProtocol.Types.CT_BOOLEAN_TRUE:
+      return Type.BOOL;
+    case TCompactProtocol.Types.CT_BYTE:
+      return Type.BYTE;
+    case TCompactProtocol.Types.CT_I16:
+      return Type.I16;
+    case TCompactProtocol.Types.CT_I32:
+      return Type.I32;
+    case TCompactProtocol.Types.CT_I64:
+      return Type.I64;
+    case TCompactProtocol.Types.CT_DOUBLE:
+      return Type.DOUBLE;
+    case TCompactProtocol.Types.CT_BINARY:
+      return Type.STRING;
+    case TCompactProtocol.Types.CT_LIST:
+      return Type.LIST;
+    case TCompactProtocol.Types.CT_SET:
+      return Type.SET;
+    case TCompactProtocol.Types.CT_MAP:
+      return Type.MAP;
+    case TCompactProtocol.Types.CT_STRUCT:
+      return Type.STRUCT;
+    default:
+      throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Unknown type: " + type);
+  }
+  return Type.STOP;
+};
+
+
+//
+// Compact Protocol write operations
+//
+
+/**
+ * Send any buffered bytes to the end point.
+ */
+TCompactProtocol.prototype.flush = function() {
+  return this.trans.flush();
+};
+
+/**
+ * Writes an RPC message header
+ * @param {string} name - The method name for the message.
+ * @param {number} type - The type of message (CALL, REPLY, EXCEPTION, ONEWAY).
+ * @param {number} seqid - The call sequence number (if any).
+ */
+TCompactProtocol.prototype.writeMessageBegin = function(name, type, seqid) {
+  this.writeByte(TCompactProtocol.PROTOCOL_ID);
+  this.writeByte((TCompactProtocol.VERSION_N & TCompactProtocol.VERSION_MASK) |
+                     ((type << TCompactProtocol.TYPE_SHIFT_AMOUNT) & TCompactProtocol.TYPE_MASK));
+  this.writeVarint32(seqid);
+  this.writeString(name);
+
+  // Record client seqid to find callback again
+  if (this._seqid) {
+    log.warning('SeqId already set', { 'name': name });
+  } else {
+    this._seqid = seqid;
+    this.trans.setCurrSeqId(seqid);
+  }
+};
+
+TCompactProtocol.prototype.writeMessageEnd = function() {
+};
+
+TCompactProtocol.prototype.writeStructBegin = function(name) {
+  this.lastField_.push(this.lastFieldId_);
+  this.lastFieldId_ = 0;
+};
+
+TCompactProtocol.prototype.writeStructEnd = function() {
+  this.lastFieldId_ = this.lastField_.pop();
+};
+
+/**
+ * Writes a struct field header
+ * @param {string} name - The field name (not written with the compact protocol).
+ * @param {number} type - The field data type (a normal Thrift field Type).
+ * @param {number} id - The IDL field Id.
+ */
+TCompactProtocol.prototype.writeFieldBegin = function(name, type, id) {
+  if (type != Type.BOOL) {
+    return this.writeFieldBeginInternal(name, type, id, -1);
+  }
+
+  this.booleanField_.name = name;
+  this.booleanField_.fieldType = type;
+  this.booleanField_.fieldId = id;
+};
+
+TCompactProtocol.prototype.writeFieldEnd = function() {
+};
+
+TCompactProtocol.prototype.writeFieldStop = function() {
+  this.writeByte(TCompactProtocol.Types.CT_STOP);
+};
+
+/**
+ * Writes a map collection header
+ * @param {number} keyType - The Thrift type of the map keys.
+ * @param {number} valType - The Thrift type of the map values.
+ * @param {number} size - The number of k/v pairs in the map.
+ */
+TCompactProtocol.prototype.writeMapBegin = function(keyType, valType, size) {
+  if (size === 0) {
+    this.writeByte(0);
+  } else {
+    this.writeVarint32(size);
+    this.writeByte(this.getCompactType(keyType) << 4 | this.getCompactType(valType));
+  }
+};
+
+TCompactProtocol.prototype.writeMapEnd = function() {
+};
+
+/**
+ * Writes a list collection header
+ * @param {number} elemType - The Thrift type of the list elements.
+ * @param {number} size - The number of elements in the list.
+ */
+TCompactProtocol.prototype.writeListBegin = function(elemType, size) {
+  this.writeCollectionBegin(elemType, size);
+};
+
+TCompactProtocol.prototype.writeListEnd = function() {
+};
+
+/**
+ * Writes a set collection header
+ * @param {number} elemType - The Thrift type of the set elements.
+ * @param {number} size - The number of elements in the set.
+ */
+TCompactProtocol.prototype.writeSetBegin = function(elemType, size) {
+  this.writeCollectionBegin(elemType, size);
+};
+
+TCompactProtocol.prototype.writeSetEnd = function() {
+};
+
+TCompactProtocol.prototype.writeBool = function(value) {
+  if (this.booleanField_.name !== null) {
+    // we haven't written the field header yet
+    this.writeFieldBeginInternal(this.booleanField_.name,
+                                 this.booleanField_.fieldType,
+                                 this.booleanField_.fieldId,
+                                 (value ? TCompactProtocol.Types.CT_BOOLEAN_TRUE
+                                          : TCompactProtocol.Types.CT_BOOLEAN_FALSE));
+    this.booleanField_.name = null;
+  } else {
+    // we're not part of a field, so just write the value
+    this.writeByte((value ? TCompactProtocol.Types.CT_BOOLEAN_TRUE
+                            : TCompactProtocol.Types.CT_BOOLEAN_FALSE));
+  }
+};
+
+TCompactProtocol.prototype.writeByte = function(b) {
+  this.trans.write(new Buffer([b]));
+};
+
+TCompactProtocol.prototype.writeI16 = function(i16) {
+  this.writeVarint32(this.i32ToZigzag(i16));
+};
+
+TCompactProtocol.prototype.writeI32 = function(i32) {
+  this.writeVarint32(this.i32ToZigzag(i32));
+};
+
+TCompactProtocol.prototype.writeI64 = function(i64) {
+  this.writeVarint64(this.i64ToZigzag(i64));
+};
+
+// Little-endian, unlike TBinaryProtocol
+TCompactProtocol.prototype.writeDouble = function(v) {
+  var buff = new Buffer(8);
+  var m, e, c;
+
+  buff[7] = (v < 0 ? 0x80 : 0x00);
+
+  v = Math.abs(v);
+  if (v !== v) {
+    // NaN, use QNaN IEEE format
+    m = 2251799813685248;
+    e = 2047;
+  } else if (v === Infinity) {
+    m = 0;
+    e = 2047;
+  } else {
+    e = Math.floor(Math.log(v) / Math.LN2);
+    c = Math.pow(2, -e);
+    if (v * c < 1) {
+      e--;
+      c *= 2;
+    }
+
+    if (e + 1023 >= 2047)
+    {
+      // Overflow
+      m = 0;
+      e = 2047;
+    }
+    else if (e + 1023 >= 1)
+    {
+      // Normalized - term order matters, as Math.pow(2, 52-e) and v*Math.pow(2, 52) can overflow
+      m = (v*c-1) * POW_52;
+      e += 1023;
+    }
+    else
+    {
+      // Denormalized - also catches the '0' case, somewhat by chance
+      m = (v * POW_1022) * POW_52;
+      e = 0;
+    }
+  }
+
+  buff[6] = (e << 4) & 0xf0;
+  buff[7] |= (e >> 4) & 0x7f;
+
+  buff[0] = m & 0xff;
+  m = Math.floor(m / POW_8);
+  buff[1] = m & 0xff;
+  m = Math.floor(m / POW_8);
+  buff[2] = m & 0xff;
+  m = Math.floor(m / POW_8);
+  buff[3] = m & 0xff;
+  m >>= 8;
+  buff[4] = m & 0xff;
+  m >>= 8;
+  buff[5] = m & 0xff;
+  m >>= 8;
+  buff[6] |= m & 0x0f;
+
+  this.trans.write(buff);
+};
+
+TCompactProtocol.prototype.writeStringOrBinary = function(name, encoding, arg) {
+  if (typeof arg === 'string') {
+    this.writeVarint32(Buffer.byteLength(arg, encoding)) ;
+    this.trans.write(new Buffer(arg, encoding));
+  } else if (arg instanceof Buffer ||
+             Object.prototype.toString.call(arg) == '[object Uint8Array]') {
+    // Buffers in Node.js under Browserify may extend UInt8Array instead of
+    // defining a new object. We detect them here so we can write them
+    // correctly
+    this.writeVarint32(arg.length);
+    this.trans.write(arg);
+  } else {
+    throw new Error(name + ' called without a string/Buffer argument: ' + arg);
+  }
+};
+
+TCompactProtocol.prototype.writeString = function(arg) {
+  this.writeStringOrBinary('writeString', 'utf8', arg);
+};
+
+TCompactProtocol.prototype.writeBinary = function(arg) {
+  this.writeStringOrBinary('writeBinary', 'binary', arg);
+};
+
+
+//
+// Compact Protocol internal write methods
+//
+
+TCompactProtocol.prototype.writeFieldBeginInternal = function(name,
+                                                              fieldType,
+                                                              fieldId,
+                                                              typeOverride) {
+  //If there's a type override, use that.
+  var typeToWrite = (typeOverride == -1 ? this.getCompactType(fieldType) : typeOverride);
+  //Check if we can delta encode the field id
+  if (fieldId > this.lastFieldId_ && fieldId - this.lastFieldId_ <= 15) {
+    //Include the type delta with the field ID
+    this.writeByte((fieldId - this.lastFieldId_) << 4 | typeToWrite);
+  } else {
+    //Write separate type and ID values
+    this.writeByte(typeToWrite);
+    this.writeI16(fieldId);
+  }
+  this.lastFieldId_ = fieldId;
+};
+
+TCompactProtocol.prototype.writeCollectionBegin = function(elemType, size) {
+  if (size <= 14) {
+    //Combine size and type in one byte if possible
+    this.writeByte(size << 4 | this.getCompactType(elemType));
+  } else {
+    this.writeByte(0xf0 | this.getCompactType(elemType));
+    this.writeVarint32(size);
+  }
+};
+
+/**
+ * Write an i32 as a varint. Results in 1-5 bytes on the wire.
+ */
+TCompactProtocol.prototype.writeVarint32 = function(n) {
+  var buf = new Buffer(5);
+  var wsize = 0;
+  while (true) {
+    if ((n & ~0x7F) === 0) {
+      buf[wsize++] = n;
+      break;
+    } else {
+      buf[wsize++] = ((n & 0x7F) | 0x80);
+      n = n >>> 7;
+    }
+  }
+  var wbuf = new Buffer(wsize);
+  buf.copy(wbuf,0,0,wsize);
+  this.trans.write(wbuf);
+};
+
+/**
+ * Write an i64 as a varint. Results in 1-10 bytes on the wire.
+ * N.B. node-int64 is always big endian
+ */
+TCompactProtocol.prototype.writeVarint64 = function(n) {
+  if (typeof n === "number"){
+    n = new Int64(n);
+  }
+  if (! (n instanceof Int64)) {
+    throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Expected Int64 or Number, found: " + n);
+  }
+
+  var buf = new Buffer(10);
+  var wsize = 0;
+  var hi = n.buffer.readUInt32BE(0, true);
+  var lo = n.buffer.readUInt32BE(4, true);
+  var mask = 0;
+  while (true) {
+    if (((lo & ~0x7F) === 0) && (hi === 0)) {
+      buf[wsize++] = lo;
+      break;
+    } else {
+      buf[wsize++] = ((lo & 0x7F) | 0x80);
+      mask = hi << 25;
+      lo = lo >>> 7;
+      hi = hi >>> 7;
+      lo = lo | mask;
+    }
+  }
+  var wbuf = new Buffer(wsize);
+  buf.copy(wbuf,0,0,wsize);
+  this.trans.write(wbuf);
+};
+
+/**
+ * Convert l into a zigzag long. This allows negative numbers to be
+ * represented compactly as a varint.
+ */
+TCompactProtocol.prototype.i64ToZigzag = function(l) {
+  if (typeof l === 'string') {
+    l = new Int64(parseInt(l, 10));
+  } else if (typeof l === 'number') {
+    l = new Int64(l);
+  }
+  if (! (l instanceof Int64)) {
+    throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Expected Int64 or Number, found: " + l);
+  }
+  var hi = l.buffer.readUInt32BE(0, true);
+  var lo = l.buffer.readUInt32BE(4, true);
+  var sign = hi >>> 31;
+  hi = ((hi << 1) | (lo >>> 31)) ^ ((!!sign) ? 0xFFFFFFFF : 0);
+  lo = (lo << 1) ^ ((!!sign) ? 0xFFFFFFFF : 0);
+  return new Int64(hi, lo);
+};
+
+/**
+ * Convert n into a zigzag int. This allows negative numbers to be
+ * represented compactly as a varint.
+ */
+TCompactProtocol.prototype.i32ToZigzag = function(n) {
+  return (n << 1) ^ ((n & 0x80000000) ? 0xFFFFFFFF : 0);
+};
+
+
+//
+// Compact Protocol read operations
+//
+
+TCompactProtocol.prototype.readMessageBegin = function() {
+  //Read protocol ID
+  var protocolId = this.trans.readByte();
+  if (protocolId != TCompactProtocol.PROTOCOL_ID) {
+    throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "Bad protocol identifier " + protocolId);
+  }
+
+  //Read Version and Type
+  var versionAndType = this.trans.readByte();
+  var version = (versionAndType & TCompactProtocol.VERSION_MASK);
+  if (version != TCompactProtocol.VERSION_N) {
+    throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.BAD_VERSION, "Bad protocol version " + version);
+  }
+  var type = ((versionAndType >> TCompactProtocol.TYPE_SHIFT_AMOUNT) & TCompactProtocol.TYPE_BITS);
+
+  //Read SeqId
+  var seqid = this.readVarint32();
+
+  //Read name
+  var name = this.readString();
+
+  return {fname: name, mtype: type, rseqid: seqid};
+};
+
+TCompactProtocol.prototype.readMessageEnd = function() {
+};
+
+TCompactProtocol.prototype.readStructBegin = function() {
+  this.lastField_.push(this.lastFieldId_);
+  this.lastFieldId_ = 0;
+  return {fname: ''};
+};
+
+TCompactProtocol.prototype.readStructEnd = function() {
+  this.lastFieldId_ = this.lastField_.pop();
+};
+
+TCompactProtocol.prototype.readFieldBegin = function() {
+  var fieldId = 0;
+  var b = this.trans.readByte(b);
+  var type = (b & 0x0f);
+
+  if (type == TCompactProtocol.Types.CT_STOP) {
+    return {fname: null, ftype: Thrift.Type.STOP, fid: 0};
+  }
+
+  //Mask off the 4 MSB of the type header to check for field id delta.
+  var modifier = ((b & 0x000000f0) >>> 4);
+  if (modifier === 0) {
+    //If not a delta read the field id.
+    fieldId = this.readI16();
+  } else {
+    //Recover the field id from the delta
+    fieldId = (this.lastFieldId_ + modifier);
+  }
+  var fieldType = this.getTType(type);
+
+  //Boolean are encoded with the type
+  if (type == TCompactProtocol.Types.CT_BOOLEAN_TRUE ||
+      type == TCompactProtocol.Types.CT_BOOLEAN_FALSE) {
+    this.boolValue_.hasBoolValue = true;
+    this.boolValue_.boolValue =
+      (type == TCompactProtocol.Types.CT_BOOLEAN_TRUE ? true : false);
+  }
+
+  //Save the new field for the next delta computation.
+  this.lastFieldId_ = fieldId;
+  return {fname: null, ftype: fieldType, fid: fieldId};
+};
+
+TCompactProtocol.prototype.readFieldEnd = function() {
+};
+
+TCompactProtocol.prototype.readMapBegin = function() {
+  var msize = this.readVarint32();
+  if (msize < 0) {
+    throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative map size");
+  }
+
+  var kvType = 0;
+  if (msize !== 0) {
+    kvType = this.trans.readByte();
+  }
+
+  var keyType = this.getTType((kvType & 0xf0) >>> 4);
+  var valType = this.getTType(kvType & 0xf);
+  return {ktype: keyType, vtype: valType, size: msize};
+};
+
+TCompactProtocol.prototype.readMapEnd = function() {
+};
+
+TCompactProtocol.prototype.readListBegin = function() {
+  var size_and_type = this.trans.readByte();
+
+  var lsize = (size_and_type >>> 4) & 0x0000000f;
+  if (lsize == 15) {
+    lsize = this.readVarint32();
+  }
+
+  if (lsize < 0) {
+    throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative list size");
+  }
+
+  var elemType = this.getTType(size_and_type & 0x0000000f);
+
+  return {etype: elemType, size: lsize};
+};
+
+TCompactProtocol.prototype.readListEnd = function() {
+};
+
+TCompactProtocol.prototype.readSetBegin = function() {
+  return this.readListBegin();
+};
+
+TCompactProtocol.prototype.readSetEnd = function() {
+};
+
+TCompactProtocol.prototype.readBool = function() {
+  var value = false;
+  var rsize = 0;
+  if (this.boolValue_.hasBoolValue === true) {
+    value = this.boolValue_.boolValue;
+    this.boolValue_.hasBoolValue = false;
+  } else {
+    var res = this.trans.readByte();
+    rsize = res.rsize;
+    value = (res.value == TCompactProtocol.Types.CT_BOOLEAN_TRUE);
+  }
+  return value;
+};
+
+TCompactProtocol.prototype.readByte = function() {
+  return this.trans.readByte();
+};
+
+TCompactProtocol.prototype.readI16 = function() {
+  return this.readI32();
+};
+
+TCompactProtocol.prototype.readI32 = function() {
+  return this.zigzagToI32(this.readVarint32());
+};
+
+TCompactProtocol.prototype.readI64 = function() {
+  return this.zigzagToI64(this.readVarint64());
+};
+
+// Little-endian, unlike TBinaryProtocol
+TCompactProtocol.prototype.readDouble = function() {
+  var buff = this.trans.read(8);
+  var off = 0;
+
+  var signed = buff[off + 7] & 0x80;
+  var e = (buff[off+6] & 0xF0) >> 4;
+  e += (buff[off+7] & 0x7F) << 4;
+
+  var m = buff[off];
+  m += buff[off+1] << 8;
+  m += buff[off+2] << 16;
+  m += buff[off+3] * POW_24;
+  m += buff[off+4] * POW_32;
+  m += buff[off+5] * POW_40;
+  m += (buff[off+6] & 0x0F) * POW_48;
+
+  switch (e) {
+    case 0:
+      e = -1022;
+      break;
+    case 2047:
+      return m ? NaN : (signed ? -Infinity : Infinity);
+    default:
+      m += POW_52;
+      e -= 1023;
+  }
+
+  if (signed) {
+    m *= -1;
+  }
+
+  return m * Math.pow(2, e - 52);
+};
+
+TCompactProtocol.prototype.readBinary = function() {
+  var size = this.readVarint32();
+  if (size === 0) {
+    return new Buffer(0);
+  }
+
+  if (size < 0) {
+    throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative binary size");
+  }
+  return this.trans.read(size);
+};
+
+TCompactProtocol.prototype.readString = function() {
+  var size = this.readVarint32();
+  // Catch empty string case
+  if (size === 0) {
+    return "";
+  }
+
+  // Catch error cases
+  if (size < 0) {
+    throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.NEGATIVE_SIZE, "Negative string size");
+  }
+  return this.trans.readString(size);
+};
+
+
+//
+// Compact Protocol internal read operations
+//
+
+/**
+ * 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.
+ */
+TCompactProtocol.prototype.readVarint32 = function() {
+  return this.readVarint64().toNumber();
+};
+
+/**
+ * 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.
+ */
+TCompactProtocol.prototype.readVarint64 = function() {
+  var rsize = 0;
+  var lo = 0;
+  var hi = 0;
+  var shift = 0;
+  while (true) {
+    var b = this.trans.readByte();
+    rsize ++;
+    if (shift <= 25) {
+      lo = lo | ((b & 0x7f) << shift);
+    } else if (25 < shift && shift < 32) {
+      lo = lo | ((b & 0x7f) << shift);
+      hi = hi | ((b & 0x7f) >>> (32-shift));
+    } else {
+      hi = hi | ((b & 0x7f) << (shift-32));
+    }
+    shift += 7;
+    if (!(b & 0x80)) {
+      break;
+    }
+    if (rsize >= 10) {
+      throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.INVALID_DATA, "Variable-length int over 10 bytes.");
+    }
+  }
+  return new Int64(hi, lo);
+};
+
+/**
+ * Convert from zigzag int to int.
+ */
+TCompactProtocol.prototype.zigzagToI32 = function(n) {
+  return (n >>> 1) ^ (-1 * (n & 1));
+};
+
+/**
+ * Convert from zigzag long to long.
+ */
+TCompactProtocol.prototype.zigzagToI64 = function(n) {
+  var hi = n.buffer.readUInt32BE(0, true);
+  var lo = n.buffer.readUInt32BE(4, true);
+
+  var neg = new Int64(hi & 0, lo & 1);
+  neg._2scomp();
+  var hi_neg = neg.buffer.readUInt32BE(0, true);
+  var lo_neg = neg.buffer.readUInt32BE(4, true);
+
+  var hi_lo = (hi << 31);
+  hi = (hi >>> 1) ^ (hi_neg);
+  lo = ((lo >>> 1) | hi_lo) ^ (lo_neg);
+  return new Int64(hi, lo);
+};
+
+TCompactProtocol.prototype.skip = function(type) {
+  switch (type) {
+    case Type.STOP:
+      return;
+    case Type.BOOL:
+      this.readBool();
+      break;
+    case Type.BYTE:
+      this.readByte();
+      break;
+    case Type.I16:
+      this.readI16();
+      break;
+    case Type.I32:
+      this.readI32();
+      break;
+    case Type.I64:
+      this.readI64();
+      break;
+    case Type.DOUBLE:
+      this.readDouble();
+      break;
+    case Type.STRING:
+      this.readString();
+      break;
+    case Type.STRUCT:
+      this.readStructBegin();
+      while (true) {
+        var r = this.readFieldBegin();
+        if (r.ftype === Type.STOP) {
+          break;
+        }
+        this.skip(r.ftype);
+        this.readFieldEnd();
+      }
+      this.readStructEnd();
+      break;
+    case Type.MAP:
+      var mapBegin = this.readMapBegin();
+      for (var i = 0; i < mapBegin.size; ++i) {
+        this.skip(mapBegin.ktype);
+        this.skip(mapBegin.vtype);
+      }
+      this.readMapEnd();
+      break;
+    case Type.SET:
+      var setBegin = this.readSetBegin();
+      for (var i2 = 0; i2 < setBegin.size; ++i2) {
+        this.skip(setBegin.etype);
+      }
+      this.readSetEnd();
+      break;
+    case Type.LIST:
+      var listBegin = this.readListBegin();
+      for (var i3 = 0; i3 < listBegin.size; ++i3) {
+        this.skip(listBegin.etype);
+      }
+      this.readListEnd();
+      break;
+    default:
+      throw new  Error("Invalid type: " + type);
+  }
+};
diff --git a/lib/nodejs/lib/thrift/connection.js b/lib/nodejs/lib/thrift/connection.js
index a49d427..9e5c063 100644
--- a/lib/nodejs/lib/thrift/connection.js
+++ b/lib/nodejs/lib/thrift/connection.js
@@ -16,11 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-var util = require('util'),
-    EventEmitter = require("events").EventEmitter,
-    net = require('net'),
-    ttransport = require('./transport'),
-    tprotocol = require('./protocol');
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+var constants = require('constants');
+var net = require('net');
+var tls = require('tls');
+var thrift = require('./thrift');
+var log = require('./log');
+
+var TBufferedTransport = require('./buffered_transport');
+var TBinaryProtocol = require('./binary_protocol');
+var InputBufferUnderrunError = require('./input_buffer_underrun_error');
+
+var createClient = require('./create_client');
 
 var binary = require('./binary');
 
@@ -28,14 +36,36 @@
   var self = this;
   EventEmitter.call(this);
 
+  this.seqId2Service = {};
   this.connection = stream;
+  this.ssl = (stream.encrypted);
   this.options = options || {};
-  this.transport = this.options.transport || ttransport.TBufferedTransport;
-  this.protocol = this.options.protocol || tprotocol.TBinaryProtocol;
+  this.transport = this.options.transport || TBufferedTransport;
+  this.protocol = this.options.protocol || TBinaryProtocol;
   this.offline_queue = [];
   this.connected = false;
+  this.initialize_retry_vars();
 
-  this.connection.addListener("connect", function() {
+  this._debug = this.options.debug || false;
+  if (this.options.max_attempts &&
+      !isNaN(this.options.max_attempts) &&
+      this.options.max_attempts > 0) {
+     this.max_attempts = +this.options.max_attempts;
+  }
+  this.retry_max_delay = null;
+  if (this.options.retry_max_delay !== undefined &&
+      !isNaN(this.options.retry_max_delay) &&
+      this.options.retry_max_delay > 0) {
+     this.retry_max_delay = this.options.retry_max_delay;
+  }
+  this.connect_timeout = false;
+  if (this.options.connect_timeout &&
+      !isNaN(this.options.connect_timeout) &&
+      this.options.connect_timeout > 0) {
+     this.connect_timeout = +this.options.connect_timeout;
+  }
+
+  this.connection.addListener(this.ssl ? "secureConnect" : "connect", function() {
     self.connected = true;
 
     this.setTimeout(self.options.timeout || 0);
@@ -43,6 +73,7 @@
     this.frameLeft = 0;
     this.framePos = 0;
     this.frame = null;
+    self.initialize_retry_vars();
 
     self.offline_queue.forEach(function(data) {
       self.connection.write(data);
@@ -53,16 +84,17 @@
 
   this.connection.addListener("error", function(err) {
     // Only emit the error if no-one else is listening on the connection
-    // or if someone is listening on us
-    if (self.connection.listeners('error').length === 1
-        || self.listeners('error').length > 0) {
-      self.emit("error", err)
+    // or if someone is listening on us, because Node turns unhandled
+    // 'error' events into exceptions.
+    if (self.connection.listeners('error').length === 1 ||
+        self.listeners('error').length > 0) {
+      self.emit("error", err);
     }
   });
 
   // Add a close listener
   this.connection.addListener("close", function() {
-    self.emit("close");
+    self.connection_gone(); // handle close event. try to reconnect
   });
 
   this.connection.addListener("timeout", function() {
@@ -72,26 +104,57 @@
   this.connection.addListener("data", self.transport.receiver(function(transport_with_data) {
     var message = new self.protocol(transport_with_data);
     try {
-      var header = message.readMessageBegin();
-      var dummy_seqid = header.rseqid * -1;
-      var client = self.client;
-      client._reqs[dummy_seqid] = function(err, success){
-        transport_with_data.commitPosition();
-
-        var callback = client._reqs[header.rseqid];
-        delete client._reqs[header.rseqid];
-        if (callback) {
-          callback(err, success);
+      while (true) {
+        var header = message.readMessageBegin();
+        var dummy_seqid = header.rseqid * -1;
+        var client = self.client;
+        //The Multiplexed Protocol stores a hash of seqid to service names
+        //  in seqId2Service. If the SeqId is found in the hash we need to
+        //  lookup the appropriate client for this call.
+        //  The connection.client object is a single client object when not
+        //  multiplexing, when using multiplexing it is a service name keyed
+        //  hash of client objects.
+        //NOTE: The 2 way interdependencies between protocols, transports,
+        //  connections and clients in the Node.js implementation are irregular
+        //  and make the implementation difficult to extend and maintain. We
+        //  should bring this stuff inline with typical thrift I/O stack
+        //  operation soon.
+        //  --ra
+        var service_name = self.seqId2Service[header.rseqid];
+        if (service_name) {
+          client = self.client[service_name];
         }
-      };
-      client['recv_' + header.fname](message, header.mtype, dummy_seqid);
+        /*jshint -W083 */
+        client._reqs[dummy_seqid] = function(err, success){
+          transport_with_data.commitPosition();
+
+          var callback = client._reqs[header.rseqid];
+          delete client._reqs[header.rseqid];
+          if (service_name) {
+            delete self.seqId2Service[header.rseqid];
+          }
+          if (callback) {
+            callback(err, success);
+          }
+        };
+        /*jshint +W083 */
+
+        if(client['recv_' + header.fname]) {
+          client['recv_' + header.fname](message, header.mtype, dummy_seqid);
+        } else {
+          delete client._reqs[dummy_seqid];
+          self.emit("error",
+                    new thrift.TApplicationException(thrift.TApplicationExceptionType.WRONG_METHOD_NAME,
+                             "Received a response to an unknown RPC function"));
+        }
+      }
     }
     catch (e) {
-      if (e instanceof ttransport.InputBufferUnderrunError) {
+      if (e instanceof InputBufferUnderrunError) {
         transport_with_data.rollbackPosition();
       }
       else {
-        throw e;
+        self.emit('error', e);
       }
     }
   }));
@@ -100,7 +163,19 @@
 
 Connection.prototype.end = function() {
   this.connection.end();
-}
+};
+
+Connection.prototype.destroy = function() {
+  this.connection.destroy();
+};
+
+Connection.prototype.initialize_retry_vars = function () {
+  this.retry_timer = null;
+  this.retry_totaltime = 0;
+  this.retry_delay = 150;
+  this.retry_backoff = 1.7;
+  this.attempts = 0;
+};
 
 Connection.prototype.write = function(data) {
   if (!this.connected) {
@@ -108,7 +183,68 @@
     return;
   }
   this.connection.write(data);
-}
+};
+
+Connection.prototype.connection_gone = function () {
+  var self = this;
+  this.connected = false;
+
+  // If a retry is already in progress, just let that happen
+  if (this.retry_timer) {
+    return;
+  }
+  // We cannot reconnect a secure socket.
+  if (!this.max_attempts || this.ssl) {
+    self.emit("close");
+    return;
+  }
+
+  if (this.retry_max_delay !== null && this.retry_delay >= this.retry_max_delay) {
+    this.retry_delay = this.retry_max_delay;
+  } else {
+    this.retry_delay = Math.floor(this.retry_delay * this.retry_backoff);
+  }
+
+  log.debug("Retry connection in " + this.retry_delay + " ms");
+
+  if (this.max_attempts && this.attempts >= this.max_attempts) {
+    this.retry_timer = null;
+    console.error("thrift: Couldn't get thrift connection after " + this.max_attempts + " attempts.");
+    self.emit("close");
+    return;
+  }
+
+  this.attempts += 1;
+  this.emit("reconnecting", {
+    delay: self.retry_delay,
+    attempt: self.attempts
+  });
+
+  this.retry_timer = setTimeout(function () {
+    if (self.connection.destroyed) {
+      self.retry_timer = null;
+      return;
+    }
+
+    log.debug("Retrying connection...");
+
+    self.retry_totaltime += self.retry_delay;
+
+    if (self.connect_timeout && self.retry_totaltime >= self.connect_timeout) {
+       self.retry_timer = null;
+       console.error("thrift: Couldn't get thrift connection after " + self.retry_totaltime + "ms.");
+       self.emit("close");
+       return;
+    }
+
+    if (self.path !== undefined) {
+      self.connection.connect(self.path);
+    } else {
+      self.connection.connect(self.port, self.host);
+    }
+    self.retry_timer = null;
+  }, this.retry_delay);
+};
 
 exports.createConnection = function(host, port, options) {
   var stream = net.createConnection(port, host);
@@ -117,21 +253,32 @@
   connection.port = port;
 
   return connection;
-}
+};
 
-exports.createClient = function(cls, connection) {
-  if (cls.Client) {
-    cls = cls.Client;
+exports.createUDSConnection = function(path, options) {
+  var stream = net.createConnection(path);
+  var connection = new Connection(stream, options);
+  connection.path = path;
+
+  return connection;
+};
+
+exports.createSSLConnection = function(host, port, options) {
+  if (!('secureProtocol' in options) && !('secureOptions' in options)) {
+    options.secureProtocol = "SSLv23_method";
+    options.secureOptions = constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3;
   }
-  var client = new cls(new connection.transport(undefined, function(buf) {
-    connection.write(buf);
-  }), connection.protocol);
 
-  // TODO clean this up
-  connection.client = client;
+  var stream = tls.connect(port, host, options);
+  var connection = new Connection(stream, options);
+  connection.host = host;
+  connection.port = port;
 
-  return client;
-}
+  return connection;
+};
+
+
+exports.createClient = createClient;
 
 var child_process = require('child_process');
 var StdIOConnection = exports.StdIOConnection = function(command, options) {
@@ -143,20 +290,19 @@
   var self = this;
   EventEmitter.call(this);
 
-  this._debug = options.debug || false;
   this.connection = child.stdin;
   this.options = options || {};
-  this.transport = this.options.transport || ttransport.TBufferedTransport;
-  this.protocol = this.options.protocol || tprotocol.TBinaryProtocol;
+  this.transport = this.options.transport || TBufferedTransport;
+  this.protocol = this.options.protocol || TBinaryProtocol;
   this.offline_queue = [];
 
-  if(this._debug === true){
-    this.child.stderr.on('data',function(err){
-      console.log(err.toString(),'CHILD ERROR');
+  if (log.getLogLevel() === 'debug') {
+    this.child.stderr.on('data', function (err) {
+      log.debug(err.toString(), 'CHILD ERROR');
     });
 
-    this.child.on('exit',function(code,signal){
-      console.log(code+':'+signal,'CHILD EXITED');
+    this.child.on('exit', function (code,signal) {
+      log.debug(code + ':' + signal, 'CHILD EXITED');
     });
   }
 
@@ -197,7 +343,7 @@
       client['recv_' + header.fname](message, header.mtype, dummy_seqid);
     }
     catch (e) {
-      if (e instanceof ttransport.InputBufferUnderrunError) {
+      if (e instanceof InputBufferUnderrunError) {
         transport_with_data.rollbackPosition();
       }
       else {
@@ -205,14 +351,13 @@
       }
     }
   }));
-
 };
 
-util.inherits(StdIOConnection, EventEmitter);     
+util.inherits(StdIOConnection, EventEmitter);
 
 StdIOConnection.prototype.end = function() {
   this.connection.end();
-}
+};
 
 StdIOConnection.prototype.write = function(data) {
   if (!this.connected) {
@@ -220,23 +365,10 @@
     return;
   }
   this.connection.write(data);
-}
-exports.createStdIOConnection = function(command,options){
-  return new StdIOConnection(command,options);
-
 };
 
-exports.createStdIOClient = function(cls,connection) {
-  if (cls.Client) {
-    cls = cls.Client;
-  }
+exports.createStdIOConnection = function(command,options){
+  return new StdIOConnection(command,options);
+};
 
-  var client = new cls(new connection.transport(undefined, function(buf) {
-    connection.write(buf);
-  }), connection.protocol);
-
-  // TODO clean this up
-  connection.client = client;
-
-  return client;
-}
+exports.createStdIOClient = createClient;
diff --git a/lib/nodejs/lib/thrift/create_client.js b/lib/nodejs/lib/thrift/create_client.js
new file mode 100644
index 0000000..d6b77a8
--- /dev/null
+++ b/lib/nodejs/lib/thrift/create_client.js
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+module.exports = createClient;
+
+/**
+ * Creates a new client object for the specified Thrift service.
+ * @param {object} ServiceClient - The module containing the generated service client
+ * @param {Connection} Connection - The connection to use.
+ * @returns {object} The client object.
+ */
+function createClient(ServiceClient, connection) {
+  // TODO validate required options and throw otherwise
+  if (ServiceClient.Client) {
+    ServiceClient = ServiceClient.Client;
+  }
+  // TODO detangle these initialization calls
+  // creating "client" requires
+  //   - new service client instance
+  //
+  // New service client instance requires
+  //   - new transport instance
+  //   - protocol class reference
+  //
+  // New transport instance requires
+  //   - Buffer to use (or none)
+  //   - Callback to call on flush
+
+  // Wrap the write method
+  var writeCb = function(buf, seqid) {
+    connection.write(buf, seqid);
+  };
+  var transport = new connection.transport(undefined, writeCb);
+  var client = new ServiceClient(transport, connection.protocol);
+  transport.client = client;
+  connection.client = client;
+  return client;
+};
diff --git a/lib/nodejs/lib/thrift/framed_transport.js b/lib/nodejs/lib/thrift/framed_transport.js
new file mode 100644
index 0000000..6947925
--- /dev/null
+++ b/lib/nodejs/lib/thrift/framed_transport.js
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var binary = require('./binary');
+var InputBufferUnderrunError = require('./input_buffer_underrun_error');
+
+module.exports = TFramedTransport;
+
+function TFramedTransport(buffer, callback) {
+  this.inBuf = buffer || new Buffer(0);
+  this.outBuffers = [];
+  this.outCount = 0;
+  this.readPos = 0;
+  this.onFlush = callback;
+};
+
+TFramedTransport.receiver = function(callback, seqid) {
+  var residual = null;
+
+  return function(data) {
+    // Prepend any residual data from our previous read
+    if (residual) {
+      data = Buffer.concat([residual, data]);
+      residual = null;
+    }
+
+    // framed transport
+    while (data.length) {
+      if (data.length < 4) {
+        // Not enough bytes to continue, save and resume on next packet
+        residual = data;
+        return;
+      }
+      var frameSize = binary.readI32(data, 0);
+      if (data.length < 4 + frameSize) {
+        // Not enough bytes to continue, save and resume on next packet
+        residual = data;
+        return;
+      }
+
+      var frame = data.slice(4, 4 + frameSize);
+      residual = data.slice(4 + frameSize);
+
+      callback(new TFramedTransport(frame), seqid);
+
+      data = residual;
+      residual = null;
+    }
+  };
+};
+
+TFramedTransport.prototype.commitPosition = function(){},
+TFramedTransport.prototype.rollbackPosition = function(){},
+
+  // TODO: Implement open/close support
+TFramedTransport.prototype.isOpen = function() {
+  return true;
+};
+TFramedTransport.prototype.open = function() {};
+TFramedTransport.prototype.close =  function() {};
+
+  // Set the seqid of the message in the client
+  // So that callbacks can be found
+TFramedTransport.prototype.setCurrSeqId = function(seqid) {
+  this._seqid = seqid;
+};
+
+TFramedTransport.prototype.ensureAvailable = function(len) {
+  if (this.readPos + len > this.inBuf.length) {
+    throw new InputBufferUnderrunError();
+  }
+};
+
+TFramedTransport.prototype.read = function(len) { // this function will be used for each frames.
+  this.ensureAvailable(len);
+  var end = this.readPos + len;
+
+  if (this.inBuf.length < end) {
+    throw new Error('read(' + len + ') failed - not enough data');
+  }
+
+  var buf = this.inBuf.slice(this.readPos, end);
+  this.readPos = end;
+  return buf;
+};
+
+TFramedTransport.prototype.readByte = function() {
+  this.ensureAvailable(1);
+  return binary.readByte(this.inBuf[this.readPos++]);
+};
+
+TFramedTransport.prototype.readI16 = function() {
+  this.ensureAvailable(2);
+  var i16 = binary.readI16(this.inBuf, this.readPos);
+  this.readPos += 2;
+  return i16;
+};
+
+TFramedTransport.prototype.readI32 = function() {
+  this.ensureAvailable(4);
+  var i32 = binary.readI32(this.inBuf, this.readPos);
+  this.readPos += 4;
+  return i32;
+};
+
+TFramedTransport.prototype.readDouble = function() {
+  this.ensureAvailable(8);
+  var d = binary.readDouble(this.inBuf, this.readPos);
+  this.readPos += 8;
+  return d;
+};
+
+TFramedTransport.prototype.readString = function(len) {
+  this.ensureAvailable(len);
+  var str = this.inBuf.toString('utf8', this.readPos, this.readPos + len);
+  this.readPos += len;
+  return str;
+};
+
+TFramedTransport.prototype.borrow = function() {
+  return {
+    buf: this.inBuf,
+    readIndex: this.readPos,
+    writeIndex: this.inBuf.length
+  };
+};
+
+TFramedTransport.prototype.consume = function(bytesConsumed) {
+  this.readPos += bytesConsumed;
+};
+
+TFramedTransport.prototype.write = function(buf, encoding) {
+  if (typeof(buf) === "string") {
+    buf = new Buffer(buf, encoding || 'utf8');
+  }
+  this.outBuffers.push(buf);
+  this.outCount += buf.length;
+};
+
+TFramedTransport.prototype.flush = function() {
+  // If the seqid of the callback is available pass it to the onFlush
+  // Then remove the current seqid
+  var seqid = this._seqid;
+  this._seqid = null;
+
+  var out = new Buffer(this.outCount),
+      pos = 0;
+  this.outBuffers.forEach(function(buf) {
+    buf.copy(out, pos, 0);
+    pos += buf.length;
+  });
+
+  if (this.onFlush) {
+    // TODO: optimize this better, allocate one buffer instead of both:
+    var msg = new Buffer(out.length + 4);
+    binary.writeI32(msg, out.length);
+    out.copy(msg, 4, 0, out.length);
+    if (this.onFlush) {
+      // Passing seqid through this call to get it to the connection
+      this.onFlush(msg, seqid);
+    }
+  }
+
+  this.outBuffers = [];
+  this.outCount = 0;
+};
diff --git a/lib/nodejs/lib/thrift/http_connection.js b/lib/nodejs/lib/thrift/http_connection.js
new file mode 100644
index 0000000..3c2ab0f
--- /dev/null
+++ b/lib/nodejs/lib/thrift/http_connection.js
@@ -0,0 +1,263 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var util = require('util');
+var http = require('http');
+var https = require('https');
+var EventEmitter = require('events').EventEmitter;
+var thrift = require('./thrift');
+
+var TBufferedTransport = require('./buffered_transport');
+var TBinaryProtocol = require('./binary_protocol');
+var InputBufferUnderrunError = require('./input_buffer_underrun_error');
+
+var createClient = require('./create_client');
+
+/**
+ * @class
+ * @name ConnectOptions
+ * @property {string} transport - The Thrift layered transport to use (TBufferedTransport, etc).
+ * @property {string} protocol - The Thrift serialization protocol to use (TBinaryProtocol, etc.).
+ * @property {string} path - The URL path to POST to (e.g. "/", "/mySvc", "/thrift/quoteSvc", etc.).
+ * @property {object} headers - A standard Node.js header hash, an object hash containing key/value
+ *        pairs where the key is the header name string and the value is the header value string.
+ * @property {boolean} https - True causes the connection to use https, otherwise http is used.
+ * @property {object} nodeOptions - Options passed on to node.
+ * @example
+ *     //Use a connection that requires ssl/tls, closes the connection after each request,
+ *     //  uses the buffered transport layer, uses the JSON protocol and directs RPC traffic
+ *     //  to https://thrift.example.com:9090/hello
+ *     var thrift = require('thrift');
+ *     var options = {
+ *        transport: thrift.TBufferedTransport,
+ *        protocol: thrift.TJSONProtocol,
+ *        path: "/hello",
+ *        headers: {"Connection": "close"},
+ *        https: true
+ *     };
+ *     var con = thrift.createHttpConnection("thrift.example.com", 9090, options);
+ *     var client = thrift.createHttpClient(myService, connection);
+ *     client.myServiceFunction();
+ */
+
+/**
+ * Initializes a Thrift HttpConnection instance (use createHttpConnection() rather than
+ *    instantiating directly).
+ * @constructor
+ * @param {ConnectOptions} options - The configuration options to use.
+ * @throws {error} Exceptions other than InputBufferUnderrunError are rethrown
+ * @event {error} The "error" event is fired when a Node.js error event occurs during
+ *     request or response processing, in which case the node error is passed on. An "error"
+ *     event may also be fired when the connection can not map a response back to the
+ *     appropriate client (an internal error), generating a TApplicationException.
+ * @classdesc HttpConnection objects provide Thrift end point transport
+ *     semantics implemented over the Node.js http.request() method.
+ * @see {@link createHttpConnection}
+ */
+var HttpConnection = exports.HttpConnection = function(options) {
+  //Initialize the emitter base object
+  EventEmitter.call(this);
+
+  //Set configuration
+  var self = this;
+  this.options = options || {};
+  this.host = this.options.host;
+  this.port = this.options.port;
+  this.socketPath = this.options.socketPath;
+  this.https = this.options.https || false;
+  this.transport = this.options.transport || TBufferedTransport;
+  this.protocol = this.options.protocol || TBinaryProtocol;
+
+  //Prepare Node.js options
+  this.nodeOptions = {
+    host: this.host,
+    port: this.port,
+    socketPath: this.socketPath,
+    path: this.options.path || '/',
+    method: 'POST',
+    headers: this.options.headers || {},
+    responseType: this.options.responseType || null
+  };
+  for (var attrname in this.options.nodeOptions) {
+    this.nodeOptions[attrname] = this.options.nodeOptions[attrname];
+  }
+  /*jshint -W069 */
+  if (! this.nodeOptions.headers['Connection']) {
+    this.nodeOptions.headers['Connection'] = 'keep-alive';
+  }
+  /*jshint +W069 */
+
+  //The sequence map is used to map seqIDs back to the
+  //  calling client in multiplexed scenarios
+  this.seqId2Service = {};
+
+  function decodeCallback(transport_with_data) {
+    var proto = new self.protocol(transport_with_data);
+    try {
+      while (true) {
+        var header = proto.readMessageBegin();
+        var dummy_seqid = header.rseqid * -1;
+        var client = self.client;
+        //The Multiplexed Protocol stores a hash of seqid to service names
+        //  in seqId2Service. If the SeqId is found in the hash we need to
+        //  lookup the appropriate client for this call.
+        //  The client var is a single client object when not multiplexing,
+        //  when using multiplexing it is a service name keyed hash of client
+        //  objects.
+        //NOTE: The 2 way interdependencies between protocols, transports,
+        //  connections and clients in the Node.js implementation are irregular
+        //  and make the implementation difficult to extend and maintain. We
+        //  should bring this stuff inline with typical thrift I/O stack
+        //  operation soon.
+        //  --ra
+        var service_name = self.seqId2Service[header.rseqid];
+        if (service_name) {
+          client = self.client[service_name];
+          delete self.seqId2Service[header.rseqid];
+        }
+        /*jshint -W083 */
+        client._reqs[dummy_seqid] = function(err, success){
+          transport_with_data.commitPosition();
+          var clientCallback = client._reqs[header.rseqid];
+          delete client._reqs[header.rseqid];
+          if (clientCallback) {
+            process.nextTick(function() {
+              clientCallback(err, success);
+            });
+          }
+        };
+        /*jshint +W083 */
+        if(client['recv_' + header.fname]) {
+          client['recv_' + header.fname](proto, header.mtype, dummy_seqid);
+        } else {
+          delete client._reqs[dummy_seqid];
+          self.emit("error",
+                    new thrift.TApplicationException(
+                       thrift.TApplicationExceptionType.WRONG_METHOD_NAME,
+                       "Received a response to an unknown RPC function"));
+        }
+      }
+    }
+    catch (e) {
+      if (e instanceof InputBufferUnderrunError) {
+        transport_with_data.rollbackPosition();
+      } else {
+        self.emit('error', e);
+      }
+    }
+  }
+
+
+  //Response handler
+  //////////////////////////////////////////////////
+  this.responseCallback = function(response) {
+    var data = [];
+    var dataLen = 0;
+
+    if (response.statusCode !== 200) {
+      this.emit("error", new THTTPException(response));
+    }
+
+    response.on('error', function (e) {
+      self.emit("error", e);
+    });
+
+    // When running directly under node, chunk will be a buffer,
+    // however, when running in a Browser (e.g. Browserify), chunk
+    // will be a string or an ArrayBuffer.
+    response.on('data', function (chunk) {
+      if ((typeof chunk == 'string') ||
+          (Object.prototype.toString.call(chunk) == '[object Uint8Array]')) {
+        // Wrap ArrayBuffer/string in a Buffer so data[i].copy will work
+        data.push(new Buffer(chunk));
+      } else {
+        data.push(chunk);
+      }
+      dataLen += chunk.length;
+    });
+
+    response.on('end', function(){
+      var buf = new Buffer(dataLen);
+      for (var i=0, len=data.length, pos=0; i<len; i++) {
+        data[i].copy(buf, pos);
+        pos += data[i].length;
+      }
+      //Get the receiver function for the transport and
+      //  call it with the buffer
+      self.transport.receiver(decodeCallback)(buf);
+    });
+  };
+};
+util.inherits(HttpConnection, EventEmitter);
+
+/**
+ * Writes Thrift message data to the connection
+ * @param {Buffer} data - A Node.js Buffer containing the data to write
+ * @returns {void} No return value.
+ * @event {error} the "error" event is raised upon request failure passing the
+ *     Node.js error object to the listener.
+ */
+HttpConnection.prototype.write = function(data) {
+  var self = this;
+  var opts = self.nodeOptions;
+  opts.headers["Content-length"] = data.length;
+  if (!opts.headers["Content-Type"])
+    opts.headers["Content-Type"] = "application/x-thrift";  
+  var req = (self.https) ?
+      https.request(opts, self.responseCallback) :
+      http.request(opts, self.responseCallback);
+  req.on('error', function(err) {
+    self.emit("error", err);
+  });
+  req.write(data);
+  req.end();
+};
+
+/**
+ * Creates a new HttpConnection object, used by Thrift clients to connect
+ *    to Thrift HTTP based servers.
+ * @param {string} host - The host name or IP to connect to.
+ * @param {number} port - The TCP port to connect to.
+ * @param {ConnectOptions} options - The configuration options to use.
+ * @returns {HttpConnection} The connection object.
+ * @see {@link ConnectOptions}
+ */
+exports.createHttpConnection = function(host, port, options) {
+  options.host = host;
+  options.port = port || 80;
+  return new HttpConnection(options);
+};
+
+exports.createHttpUDSConnection = function(path, options) {
+  options.socketPath = path;
+  return new HttpConnection(options);
+};
+
+exports.createHttpClient = createClient
+
+
+function THTTPException(response) {
+  thrift.TApplicationException.call(this);
+  Error.captureStackTrace(this, this.constructor);
+  this.name = this.constructor.name;
+  this.statusCode = response.statusCode;
+  this.response = response;
+  this.type = thrift.TApplicationExceptionType.PROTOCOL_ERROR;
+  this.message = "Received a response with a bad HTTP status code: " + response.statusCode;
+}
+util.inherits(THTTPException, thrift.TApplicationException);
diff --git a/lib/nodejs/lib/thrift/index.js b/lib/nodejs/lib/thrift/index.js
index 2554a2f..b09953d 100644
--- a/lib/nodejs/lib/thrift/index.js
+++ b/lib/nodejs/lib/thrift/index.js
@@ -18,21 +18,57 @@
  */
 exports.Thrift = require('./thrift');
 
+var log = require('./log');
+exports.setLogFunc = log.setLogFunc;
+exports.setLogLevel = log.setLogLevel;
+exports.getLogLevel = log.getLogLevel;
+
 var connection = require('./connection');
 exports.Connection = connection.Connection;
 exports.createClient = connection.createClient;
 exports.createConnection = connection.createConnection;
+exports.createUDSConnection = connection.createUDSConnection;
+exports.createSSLConnection = connection.createSSLConnection;
 exports.createStdIOClient = connection.createStdIOClient;
 exports.createStdIOConnection = connection.createStdIOConnection;
 
-exports.createServer = require('./server').createServer;
+var httpConnection = require('./http_connection');
+exports.HttpConnection = httpConnection.HttpConnection;
+exports.createHttpConnection = httpConnection.createHttpConnection;
+exports.createHttpUDSConnection = httpConnection.createHttpUDSConnection;
+exports.createHttpClient = httpConnection.createHttpClient;
 
-exports.Int64 = require('node-int64')
+var wsConnection = require('./ws_connection');
+exports.WSConnection = wsConnection.WSConnection;
+exports.createWSConnection = wsConnection.createWSConnection;
+exports.createWSClient = wsConnection.createWSClient;
+
+var xhrConnection = require('./xhr_connection');
+exports.XHRConnection = xhrConnection.XHRConnection;
+exports.createXHRConnection = xhrConnection.createXHRConnection;
+exports.createXHRClient = xhrConnection.createXHRClient;
+
+var server = require('./server');
+exports.createServer = server.createServer;
+exports.createMultiplexServer = server.createMultiplexServer;
+
+var web_server = require('./web_server');
+exports.createWebServer = web_server.createWebServer;
+
+exports.Int64 = require('node-int64');
+exports.Q = require('q');
+
+var mprocessor = require('./multiplexed_processor');
+var mprotocol = require('./multiplexed_protocol');
+exports.Multiplexer = mprotocol.Multiplexer;
+exports.MultiplexedProcessor = mprocessor.MultiplexedProcessor;
 
 /*
- * Export transport and protocol so they can be used outside of a 
+ * Export transport and protocol so they can be used outside of a
  * cassandra/server context
  */
-exports.TFramedTransport = require('./transport').TFramedTransport;
-exports.TBufferedTransport = require('./transport').TBufferedTransport;
-exports.TBinaryProtocol = require('./protocol').TBinaryProtocol;
+exports.TFramedTransport = require('./framed_transport');
+exports.TBufferedTransport = require('./buffered_transport');
+exports.TBinaryProtocol = require('./binary_protocol');
+exports.TJSONProtocol = require('./json_protocol');
+exports.TCompactProtocol = require('./compact_protocol');
diff --git a/lib/nodejs/lib/thrift/input_buffer_underrun_error.js b/lib/nodejs/lib/thrift/input_buffer_underrun_error.js
new file mode 100644
index 0000000..72555e5
--- /dev/null
+++ b/lib/nodejs/lib/thrift/input_buffer_underrun_error.js
@@ -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.
+ */
+var util = require("util");
+
+module.exports = InputBufferUnderrunError;
+
+function InputBufferUnderrunError(message) {
+  Error.call(this);
+  Error.captureStackTrace(this, this.constructor);
+  this.name = this.constructor.name;
+  this.message = message;
+};
+
+util.inherits(InputBufferUnderrunError, Error);
diff --git a/lib/nodejs/lib/thrift/int64_util.js b/lib/nodejs/lib/thrift/int64_util.js
new file mode 100644
index 0000000..e8d707d
--- /dev/null
+++ b/lib/nodejs/lib/thrift/int64_util.js
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var Int64 = require('node-int64');
+
+var Int64Util = module.exports = {};
+
+var POW2_24 = Math.pow(2, 24);
+var POW2_31 = Math.pow(2, 31);
+var POW2_32 = Math.pow(2, 32);
+var POW10_11 = Math.pow(10, 11);
+
+Int64Util.toDecimalString = function(i64) {
+  var b = i64.buffer;
+  var o = i64.offset;
+  if ((!b[o] && !(b[o + 1] & 0xe0)) ||
+      (!~b[o] && !~(b[o + 1] & 0xe0))) {
+    // The magnitude is small enough.
+    return i64.toString();
+  } else {
+    var negative = b[o] & 0x80;
+    if (negative) {
+      // 2's complement
+      var incremented = false;
+      var buffer = new Buffer(8);
+      for (var i = 7; i >= 0; --i) {
+        buffer[i] = (~b[o + i] + (incremented ? 0 : 1)) & 0xff;
+        incremented |= b[o + i];
+      }
+      b = buffer;
+    }
+    var high2 = b[o + 1] + (b[o] << 8);
+    // Lesser 11 digits with exceeding values but is under 53 bits capacity.
+    var low = b[o + 7] + (b[o + 6] << 8) + (b[o + 5] << 16)
+        + b[o + 4] * POW2_24  // Bit shift renders 32th bit as sign, so use multiplication
+        + (b[o + 3] + (b[o + 2] << 8)) * POW2_32 + high2 * 74976710656;  // The literal is 2^48 % 10^11
+    // 12th digit and greater.
+    var high = Math.floor(low / POW10_11) + high2 * 2814;  // The literal is 2^48 / 10^11
+    // Make it exactly 11 with leading zeros.
+    low = ('00000000000' + String(low % POW10_11)).slice(-11);
+    return (negative ? '-' : '') + String(high) + low;
+  }
+};
+
+Int64Util.fromDecimalString = function(text) {
+  var negative = text.charAt(0) === '-';
+  if (text.length < (negative ? 17 : 16)) {
+    // The magnitude is smaller than 2^53.
+    return new Int64(+text);
+  } else if (text.length > (negative ? 20 : 19)) {
+    throw new RangeError('Too many digits for Int64: ' + text);
+  } else {
+    // Most significant (up to 5) digits
+    var high5 = +text.slice(negative ? 1 : 0, -15);
+    var low = +text.slice(-15) + high5 * 2764472320;  // The literal is 10^15 % 2^32
+    var high = Math.floor(low / POW2_32) + high5 * 232830;  // The literal is 10^15 / 2^&32
+    low = low % POW2_32;
+    if (high >= POW2_31 &&
+        !(negative && high == POW2_31 && low == 0)  // Allow minimum Int64
+       ) {
+      throw new RangeError('The magnitude is too large for Int64.');
+    }
+    if (negative) {
+      // 2's complement
+      high = ~high;
+      if (low === 0) {
+        high = (high + 1) & 0xffffffff;
+      } else {
+        low = ~low + 1;
+      }
+      high = 0x80000000 | high;
+    }
+    return new Int64(high, low);
+  }
+};
diff --git a/lib/nodejs/lib/thrift/json_parse.js b/lib/nodejs/lib/thrift/json_parse.js
new file mode 100644
index 0000000..93b0bf2
--- /dev/null
+++ b/lib/nodejs/lib/thrift/json_parse.js
@@ -0,0 +1,299 @@
+/*
+ * Imported from Douglas Crockford's reference implementation with minimum modification
+ * to handle Int64.
+ *
+ * https://github.com/douglascrockford/JSON-js/blob/c98948ae1944a28e2e8ebc3717894e580aeaaa05/json_parse.js
+ *
+ * Original license header:
+ *
+ * json_parse.js
+ * 2015-05-02
+ * Public Domain.
+ * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+ */
+
+
+/*jslint for */
+
+/*property
+    at, b, call, charAt, f, fromCharCode, hasOwnProperty, message, n, name,
+    prototype, push, r, t, text
+*/
+
+var Int64 = require('node-int64');
+var Int64Util = require('./int64_util');
+
+var json_parse = module.exports = (function () {
+    "use strict";
+
+// This is a function that can parse a JSON text, producing a JavaScript
+// data structure. It is a simple, recursive descent parser. It does not use
+// eval or regular expressions, so it can be used as a model for implementing
+// a JSON parser in other languages.
+
+// We are defining the function inside of another function to avoid creating
+// global variables.
+
+    var at,     // The index of the current character
+        ch,     // The current character
+        escapee = {
+            '"': '"',
+            '\\': '\\',
+            '/': '/',
+            b: '\b',
+            f: '\f',
+            n: '\n',
+            r: '\r',
+            t: '\t'
+        },
+        text,
+
+        error = function (m) {
+
+// Call error when something is wrong.
+
+            throw new SyntaxError(m);
+        },
+
+        next = function (c) {
+
+// If a c parameter is provided, verify that it matches the current character.
+
+            if (c && c !== ch) {
+                error("Expected '" + c + "' instead of '" + ch + "'");
+            }
+
+// Get the next character. When there are no more characters,
+// return the empty string.
+
+            ch = text.charAt(at);
+            at += 1;
+            return ch;
+        },
+
+        number = function () {
+
+// Parse a number value.
+
+            var number,
+                string = '';
+
+            if (ch === '-') {
+                string = '-';
+                next('-');
+            }
+            while (ch >= '0' && ch <= '9') {
+                string += ch;
+                next();
+            }
+            if (ch === '.') {
+                string += '.';
+                while (next() && ch >= '0' && ch <= '9') {
+                    string += ch;
+                }
+            }
+            if (ch === 'e' || ch === 'E') {
+                string += ch;
+                next();
+                if (ch === '-' || ch === '+') {
+                    string += ch;
+                    next();
+                }
+                while (ch >= '0' && ch <= '9') {
+                    string += ch;
+                    next();
+                }
+            }
+            number = +string;
+            if (!isFinite(number)) {
+                error("Bad number");
+            } else if (number >= Int64.MAX_INT || number <= Int64.MIN_INT) {
+                // Return raw string for further process in TJSONProtocol
+                return string;
+            } else {
+                return number;
+            }
+        },
+
+        string = function () {
+
+// Parse a string value.
+
+            var hex,
+                i,
+                string = '',
+                uffff;
+
+// When parsing for string values, we must look for " and \ characters.
+
+            if (ch === '"') {
+                while (next()) {
+                    if (ch === '"') {
+                        next();
+                        return string;
+                    }
+                    if (ch === '\\') {
+                        next();
+                        if (ch === 'u') {
+                            uffff = 0;
+                            for (i = 0; i < 4; i += 1) {
+                                hex = parseInt(next(), 16);
+                                if (!isFinite(hex)) {
+                                    break;
+                                }
+                                uffff = uffff * 16 + hex;
+                            }
+                            string += String.fromCharCode(uffff);
+                        } else if (typeof escapee[ch] === 'string') {
+                            string += escapee[ch];
+                        } else {
+                            break;
+                        }
+                    } else {
+                        string += ch;
+                    }
+                }
+            }
+            error("Bad string");
+        },
+
+        white = function () {
+
+// Skip whitespace.
+
+            while (ch && ch <= ' ') {
+                next();
+            }
+        },
+
+        word = function () {
+
+// true, false, or null.
+
+            switch (ch) {
+            case 't':
+                next('t');
+                next('r');
+                next('u');
+                next('e');
+                return true;
+            case 'f':
+                next('f');
+                next('a');
+                next('l');
+                next('s');
+                next('e');
+                return false;
+            case 'n':
+                next('n');
+                next('u');
+                next('l');
+                next('l');
+                return null;
+            }
+            error("Unexpected '" + ch + "'");
+        },
+
+        value,  // Place holder for the value function.
+
+        array = function () {
+
+// Parse an array value.
+
+            var array = [];
+
+            if (ch === '[') {
+                next('[');
+                white();
+                if (ch === ']') {
+                    next(']');
+                    return array;   // empty array
+                }
+                while (ch) {
+                    array.push(value());
+                    white();
+                    if (ch === ']') {
+                        next(']');
+                        return array;
+                    }
+                    next(',');
+                    white();
+                }
+            }
+            error("Bad array");
+        },
+
+        object = function () {
+
+// Parse an object value.
+
+            var key,
+                object = {};
+
+            if (ch === '{') {
+                next('{');
+                white();
+                if (ch === '}') {
+                    next('}');
+                    return object;   // empty object
+                }
+                while (ch) {
+                    key = string();
+                    white();
+                    next(':');
+                    if (Object.hasOwnProperty.call(object, key)) {
+                        error('Duplicate key "' + key + '"');
+                    }
+                    object[key] = value();
+                    white();
+                    if (ch === '}') {
+                        next('}');
+                        return object;
+                    }
+                    next(',');
+                    white();
+                }
+            }
+            error("Bad object");
+        };
+
+    value = function () {
+
+// Parse a JSON value. It could be an object, an array, a string, a number,
+// or a word.
+
+        white();
+        switch (ch) {
+        case '{':
+            return object();
+        case '[':
+            return array();
+        case '"':
+            return string();
+        case '-':
+            return number();
+        default:
+            return ch >= '0' && ch <= '9'
+                ? number()
+                : word();
+        }
+    };
+
+// Return the json_parse function. It will have access to all of the above
+// functions and variables.
+
+    return function (source) {
+        var result;
+
+        text = source;
+        at = 0;
+        ch = ' ';
+        result = value();
+        white();
+        if (ch) {
+            error("Syntax error");
+        }
+
+        return result;
+    };
+}());
diff --git a/lib/nodejs/lib/thrift/json_protocol.js b/lib/nodejs/lib/thrift/json_protocol.js
new file mode 100644
index 0000000..727a3b2
--- /dev/null
+++ b/lib/nodejs/lib/thrift/json_protocol.js
@@ -0,0 +1,801 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var Int64 = require('node-int64');
+var Thrift = require('./thrift');
+var Type = Thrift.Type;
+var util = require("util");
+
+var Int64Util = require('./int64_util');
+var json_parse = require('./json_parse');
+
+var InputBufferUnderrunError = require('./input_buffer_underrun_error');
+
+module.exports = TJSONProtocol;
+
+/**
+ * Initializes a Thrift JSON protocol instance.
+ * @constructor
+ * @param {Thrift.Transport} trans - The transport to serialize to/from.
+ * @classdesc Apache Thrift Protocols perform serialization which enables cross
+ * language RPC. The Protocol type is the JavaScript browser implementation
+ * of the Apache Thrift TJSONProtocol.
+ * @example
+ *     var protocol  = new Thrift.Protocol(transport);
+ */
+function TJSONProtocol(trans) {
+  this.tstack = [];
+  this.tpos = [];
+  this.trans = trans;
+};
+
+/**
+ * Thrift IDL type Id to string mapping.
+ * @readonly
+ * @see {@link Thrift.Type}
+ */
+TJSONProtocol.Type = {};
+TJSONProtocol.Type[Type.BOOL] = '"tf"';
+TJSONProtocol.Type[Type.BYTE] = '"i8"';
+TJSONProtocol.Type[Type.I16] = '"i16"';
+TJSONProtocol.Type[Type.I32] = '"i32"';
+TJSONProtocol.Type[Type.I64] = '"i64"';
+TJSONProtocol.Type[Type.DOUBLE] = '"dbl"';
+TJSONProtocol.Type[Type.STRUCT] = '"rec"';
+TJSONProtocol.Type[Type.STRING] = '"str"';
+TJSONProtocol.Type[Type.MAP] = '"map"';
+TJSONProtocol.Type[Type.LIST] = '"lst"';
+TJSONProtocol.Type[Type.SET] = '"set"';
+
+/**
+ * Thrift IDL type string to Id mapping.
+ * @readonly
+ * @see {@link Thrift.Type}
+ */
+TJSONProtocol.RType = {};
+TJSONProtocol.RType.tf = Type.BOOL;
+TJSONProtocol.RType.i8 = Type.BYTE;
+TJSONProtocol.RType.i16 = Type.I16;
+TJSONProtocol.RType.i32 = Type.I32;
+TJSONProtocol.RType.i64 = Type.I64;
+TJSONProtocol.RType.dbl = Type.DOUBLE;
+TJSONProtocol.RType.rec = Type.STRUCT;
+TJSONProtocol.RType.str = Type.STRING;
+TJSONProtocol.RType.map = Type.MAP;
+TJSONProtocol.RType.lst = Type.LIST;
+TJSONProtocol.RType.set = Type.SET;
+
+/**
+ * The TJSONProtocol version number.
+ * @readonly
+ * @const {number} Version
+ * @memberof Thrift.Protocol
+ */
+TJSONProtocol.Version = 1;
+
+TJSONProtocol.prototype.flush = function() {
+  this.writeToTransportIfStackIsFlushable();
+  return this.trans.flush();
+};
+
+TJSONProtocol.prototype.writeToTransportIfStackIsFlushable = function() {
+  if (this.tstack.length === 1) {
+    this.trans.write(this.tstack.pop());
+  }
+};
+
+/**
+ * Serializes the beginning of a Thrift RPC message.
+ * @param {string} name - The service method to call.
+ * @param {Thrift.MessageType} messageType - The type of method call.
+ * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift).
+ */
+TJSONProtocol.prototype.writeMessageBegin = function(name, messageType, seqid) {
+  this.tstack.push([TJSONProtocol.Version, '"' + name + '"', messageType, seqid]);
+};
+
+/**
+ * Serializes the end of a Thrift RPC message.
+ */
+TJSONProtocol.prototype.writeMessageEnd = function() {
+  var obj = this.tstack.pop();
+
+  this.wobj = this.tstack.pop();
+  this.wobj.push(obj);
+
+  this.wbuf = '[' + this.wobj.join(',') + ']';
+
+  // we assume there is nothing more to come so we write
+  this.trans.write(this.wbuf);
+};
+
+/**
+ * Serializes the beginning of a struct.
+ * @param {string} name - The name of the struct.
+ */
+TJSONProtocol.prototype.writeStructBegin = function(name) {
+  this.tpos.push(this.tstack.length);
+  this.tstack.push({});
+};
+
+/**
+ * Serializes the end of a struct.
+ */
+TJSONProtocol.prototype.writeStructEnd = function() {
+  var p = this.tpos.pop();
+  var struct = this.tstack[p];
+  var str = '{';
+  var first = true;
+  for (var key in struct) {
+    if (first) {
+      first = false;
+    } else {
+      str += ',';
+    }
+
+    str += key + ':' + struct[key];
+  }
+
+  str += '}';
+  this.tstack[p] = str;
+
+  this.writeToTransportIfStackIsFlushable();
+};
+
+/**
+ * Serializes the beginning of a struct field.
+ * @param {string} name - The name of the field.
+ * @param {Thrift.Protocol.Type} fieldType - The data type of the field.
+ * @param {number} fieldId - The field's unique identifier.
+ */
+TJSONProtocol.prototype.writeFieldBegin = function(name, fieldType, fieldId) {
+  this.tpos.push(this.tstack.length);
+  this.tstack.push({ 'fieldId': '"' +
+    fieldId + '"', 'fieldType': TJSONProtocol.Type[fieldType]
+  });
+};
+
+/**
+ * Serializes the end of a field.
+ */
+TJSONProtocol.prototype.writeFieldEnd = function() {
+  var value = this.tstack.pop();
+  var fieldInfo = this.tstack.pop();
+
+  if (':' + value === ":[object Object]") {
+    this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' +
+      fieldInfo.fieldType + ':' + JSON.stringify(value) + '}';
+  } else {
+    this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' +
+      fieldInfo.fieldType + ':' + value + '}';
+  }
+  this.tpos.pop();
+
+  this.writeToTransportIfStackIsFlushable();
+};
+
+/**
+ * Serializes the end of the set of fields for a struct.
+ */
+TJSONProtocol.prototype.writeFieldStop = function() {
+};
+
+/**
+ * Serializes the beginning of a map collection.
+ * @param {Thrift.Type} keyType - The data type of the key.
+ * @param {Thrift.Type} valType - The data type of the value.
+ * @param {number} [size] - The number of elements in the map (ignored).
+ */
+TJSONProtocol.prototype.writeMapBegin = function(keyType, valType, size) {
+  //size is invalid, we'll set it on end.
+  this.tpos.push(this.tstack.length);
+  this.tstack.push([TJSONProtocol.Type[keyType], TJSONProtocol.Type[valType], 0]);
+};
+
+/**
+ * Serializes the end of a map.
+ */
+TJSONProtocol.prototype.writeMapEnd = function() {
+  var p = this.tpos.pop();
+
+  if (p == this.tstack.length) {
+    return;
+  }
+
+  if ((this.tstack.length - p - 1) % 2 !== 0) {
+    this.tstack.push('');
+  }
+
+  var size = (this.tstack.length - p - 1) / 2;
+
+  this.tstack[p][this.tstack[p].length - 1] = size;
+
+  var map = '}';
+  var first = true;
+  while (this.tstack.length > p + 1) {
+    var v = this.tstack.pop();
+    var k = this.tstack.pop();
+    if (first) {
+      first = false;
+    } else {
+      map = ',' + map;
+    }
+
+    if (! isNaN(k)) { k = '"' + k + '"'; } //json "keys" need to be strings
+    map = k + ':' + v + map;
+  }
+  map = '{' + map;
+
+  this.tstack[p].push(map);
+  this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
+
+  this.writeToTransportIfStackIsFlushable();
+};
+
+/**
+ * Serializes the beginning of a list collection.
+ * @param {Thrift.Type} elemType - The data type of the elements.
+ * @param {number} size - The number of elements in the list.
+ */
+TJSONProtocol.prototype.writeListBegin = function(elemType, size) {
+  this.tpos.push(this.tstack.length);
+  this.tstack.push([TJSONProtocol.Type[elemType], size]);
+};
+
+/**
+ * Serializes the end of a list.
+ */
+TJSONProtocol.prototype.writeListEnd = function() {
+  var p = this.tpos.pop();
+
+  while (this.tstack.length > p + 1) {
+    var tmpVal = this.tstack[p + 1];
+    this.tstack.splice(p + 1, 1);
+    this.tstack[p].push(tmpVal);
+  }
+
+  this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
+
+  this.writeToTransportIfStackIsFlushable();
+};
+
+/**
+ * Serializes the beginning of a set collection.
+ * @param {Thrift.Type} elemType - The data type of the elements.
+ * @param {number} size - The number of elements in the list.
+ */
+TJSONProtocol.prototype.writeSetBegin = function(elemType, size) {
+    this.tpos.push(this.tstack.length);
+    this.tstack.push([TJSONProtocol.Type[elemType], size]);
+};
+
+/**
+ * Serializes the end of a set.
+ */
+TJSONProtocol.prototype.writeSetEnd = function() {
+  var p = this.tpos.pop();
+
+  while (this.tstack.length > p + 1) {
+    var tmpVal = this.tstack[p + 1];
+    this.tstack.splice(p + 1, 1);
+    this.tstack[p].push(tmpVal);
+  }
+
+  this.tstack[p] = '[' + this.tstack[p].join(',') + ']';
+
+  this.writeToTransportIfStackIsFlushable();
+};
+
+/** Serializes a boolean */
+TJSONProtocol.prototype.writeBool = function(bool) {
+  this.tstack.push(bool ? 1 : 0);
+};
+
+/** Serializes a number */
+TJSONProtocol.prototype.writeByte = function(byte) {
+  this.tstack.push(byte);
+};
+
+/** Serializes a number */
+TJSONProtocol.prototype.writeI16 = function(i16) {
+  this.tstack.push(i16);
+};
+
+/** Serializes a number */
+TJSONProtocol.prototype.writeI32 = function(i32) {
+  this.tstack.push(i32);
+};
+
+/** Serializes a number */
+TJSONProtocol.prototype.writeI64 = function(i64) {
+  if (i64 instanceof Int64) {
+    this.tstack.push(Int64Util.toDecimalString(i64));
+  } else {
+    this.tstack.push(i64);
+  }
+};
+
+/** Serializes a number */
+TJSONProtocol.prototype.writeDouble = function(dub) {
+  this.tstack.push(dub);
+};
+
+/** Serializes a string */
+TJSONProtocol.prototype.writeString = function(arg) {
+  // We do not encode uri components for wire transfer:
+  if (arg === null) {
+      this.tstack.push(null);
+  } else {
+      if (typeof arg === 'string') {
+        var str = arg;
+      } else if (arg instanceof Buffer) {
+        var str = arg.toString('utf8');
+      } else {
+        throw new Error('writeString called without a string/Buffer argument: ' + arg);
+      }
+
+      // concat may be slower than building a byte buffer
+      var escapedString = '';
+      for (var i = 0; i < str.length; i++) {
+          var ch = str.charAt(i);      // a single double quote: "
+          if (ch === '\"') {
+              escapedString += '\\\"'; // write out as: \"
+          } else if (ch === '\\') {    // a single backslash: \
+              escapedString += '\\\\'; // write out as: \\
+          /* Currently escaped forward slashes break TJSONProtocol.
+           * As it stands, we can simply pass forward slashes into
+           * our strings across the wire without being escaped.
+           * I think this is the protocol's bug, not thrift.js
+           * } else if(ch === '/') {   // a single forward slash: /
+           *  escapedString += '\\/';  // write out as \/
+           * }
+           */
+          } else if (ch === '\b') {    // a single backspace: invisible
+              escapedString += '\\b';  // write out as: \b"
+          } else if (ch === '\f') {    // a single formfeed: invisible
+              escapedString += '\\f';  // write out as: \f"
+          } else if (ch === '\n') {    // a single newline: invisible
+              escapedString += '\\n';  // write out as: \n"
+          } else if (ch === '\r') {    // a single return: invisible
+              escapedString += '\\r';  // write out as: \r"
+          } else if (ch === '\t') {    // a single tab: invisible
+              escapedString += '\\t';  // write out as: \t"
+          } else {
+              escapedString += ch;     // Else it need not be escaped
+          }
+      }
+      this.tstack.push('"' + escapedString + '"');
+  }
+};
+
+/** Serializes a string */
+TJSONProtocol.prototype.writeBinary = function(arg) {
+  if (typeof arg === 'string') {
+    var buf = new Buffer(arg, 'binary');
+  } else if (arg instanceof Buffer ||
+             Object.prototype.toString.call(arg) == '[object Uint8Array]')  {
+    var buf = arg;
+  } else {
+    throw new Error('writeBinary called without a string/Buffer argument: ' + arg);
+  }
+  this.tstack.push('"' + buf.toString('base64') + '"');
+};
+
+/**
+ * @class
+ * @name AnonReadMessageBeginReturn
+ * @property {string} fname - The name of the service method.
+ * @property {Thrift.MessageType} mtype - The type of message call.
+ * @property {number} rseqid - The sequence number of the message (0 in Thrift RPC).
+ */
+/**
+ * Deserializes the beginning of a message.
+ * @returns {AnonReadMessageBeginReturn}
+ */
+TJSONProtocol.prototype.readMessageBegin = function() {
+  this.rstack = [];
+  this.rpos = [];
+
+  //Borrow the inbound transport buffer and ensure data is present/consistent
+  var transBuf = this.trans.borrow();
+  if (transBuf.readIndex >= transBuf.writeIndex) {
+    throw new InputBufferUnderrunError();
+  }
+  var cursor = transBuf.readIndex;
+
+  if (transBuf.buf[cursor] !== 0x5B) { //[
+    throw new Error("Malformed JSON input, no opening bracket");
+  }
+
+  //Parse a single message (there may be several in the buffer)
+  //  TODO: Handle characters using multiple code units
+  cursor++;
+  var openBracketCount = 1;
+  var inString = false;
+  for (; cursor < transBuf.writeIndex; cursor++) {
+    var chr = transBuf.buf[cursor];
+    //we use hexa charcode here because data[i] returns an int and not a char
+    if (inString) {
+      if (chr === 0x22) { //"
+        inString = false;
+      } else if (chr === 0x5C) { //\
+        //escaped character, skip
+        cursor += 1;
+      }
+    } else {
+      if (chr === 0x5B) { //[
+        openBracketCount += 1;
+      } else if (chr === 0x5D) { //]
+        openBracketCount -= 1;
+        if (openBracketCount === 0) {
+          //end of json message detected
+          break;
+        }
+      } else if (chr === 0x22) { //"
+        inString = true;
+      }
+    }
+  }
+
+  if (openBracketCount !== 0) {
+    // Missing closing bracket. Can be buffer underrun.
+    throw new InputBufferUnderrunError();
+  }
+
+  //Reconstitute the JSON object and conume the necessary bytes
+  this.robj = json_parse(transBuf.buf.slice(transBuf.readIndex, cursor+1).toString());
+  this.trans.consume(cursor + 1 - transBuf.readIndex);
+
+  //Verify the protocol version
+  var version = this.robj.shift();
+  if (version != TJSONProtocol.Version) {
+    throw new Error('Wrong thrift protocol version: ' + version);
+  }
+
+  //Objectify the thrift message {name/type/sequence-number} for return
+  // and then save the JSON object in rstack
+  var r = {};
+  r.fname = this.robj.shift();
+  r.mtype = this.robj.shift();
+  r.rseqid = this.robj.shift();
+  this.rstack.push(this.robj.shift());
+  return r;
+};
+
+/** Deserializes the end of a message. */
+TJSONProtocol.prototype.readMessageEnd = function() {
+};
+
+/**
+ * Deserializes the beginning of a struct.
+ * @param {string} [name] - The name of the struct (ignored)
+ * @returns {object} - An object with an empty string fname property
+ */
+TJSONProtocol.prototype.readStructBegin = function() {
+  var r = {};
+  r.fname = '';
+
+  //incase this is an array of structs
+  if (this.rstack[this.rstack.length - 1] instanceof Array) {
+    this.rstack.push(this.rstack[this.rstack.length - 1].shift());
+  }
+
+  return r;
+};
+
+/** Deserializes the end of a struct. */
+TJSONProtocol.prototype.readStructEnd = function() {
+  this.rstack.pop();
+};
+
+/**
+ * @class
+ * @name AnonReadFieldBeginReturn
+ * @property {string} fname - The name of the field (always '').
+ * @property {Thrift.Type} ftype - The data type of the field.
+ * @property {number} fid - The unique identifier of the field.
+ */
+/**
+ * Deserializes the beginning of a field.
+ * @returns {AnonReadFieldBeginReturn}
+ */
+TJSONProtocol.prototype.readFieldBegin = function() {
+  var r = {};
+
+  var fid = -1;
+  var ftype = Type.STOP;
+
+  //get a fieldId
+  for (var f in (this.rstack[this.rstack.length - 1])) {
+    if (f === null) {
+      continue;
+    }
+
+    fid = parseInt(f, 10);
+    this.rpos.push(this.rstack.length);
+
+    var field = this.rstack[this.rstack.length - 1][fid];
+
+    //remove so we don't see it again
+    delete this.rstack[this.rstack.length - 1][fid];
+
+    this.rstack.push(field);
+
+    break;
+  }
+
+  if (fid != -1) {
+    //should only be 1 of these but this is the only
+    //way to match a key
+    for (var i in (this.rstack[this.rstack.length - 1])) {
+      if (TJSONProtocol.RType[i] === null) {
+        continue;
+      }
+
+      ftype = TJSONProtocol.RType[i];
+      this.rstack[this.rstack.length - 1] = this.rstack[this.rstack.length - 1][i];
+    }
+  }
+
+  r.fname = '';
+  r.ftype = ftype;
+  r.fid = fid;
+
+  return r;
+};
+
+/** Deserializes the end of a field. */
+TJSONProtocol.prototype.readFieldEnd = function() {
+  var pos = this.rpos.pop();
+
+  //get back to the right place in the stack
+  while (this.rstack.length > pos) {
+    this.rstack.pop();
+  }
+};
+
+/**
+ * @class
+ * @name AnonReadMapBeginReturn
+ * @property {Thrift.Type} ktype - The data type of the key.
+ * @property {Thrift.Type} vtype - The data type of the value.
+ * @property {number} size - The number of elements in the map.
+ */
+/**
+ * Deserializes the beginning of a map.
+ * @returns {AnonReadMapBeginReturn}
+ */
+TJSONProtocol.prototype.readMapBegin = function() {
+  var map = this.rstack.pop();
+  var first = map.shift();
+  if (first instanceof Array) {
+    this.rstack.push(map);
+    map = first;
+    first = map.shift();
+  }
+
+  var r = {};
+  r.ktype = TJSONProtocol.RType[first];
+  r.vtype = TJSONProtocol.RType[map.shift()];
+  r.size = map.shift();
+
+
+  this.rpos.push(this.rstack.length);
+  this.rstack.push(map.shift());
+
+  return r;
+};
+
+/** Deserializes the end of a map. */
+TJSONProtocol.prototype.readMapEnd = function() {
+  this.readFieldEnd();
+};
+
+/**
+ * @class
+ * @name AnonReadColBeginReturn
+ * @property {Thrift.Type} etype - The data type of the element.
+ * @property {number} size - The number of elements in the collection.
+ */
+/**
+ * Deserializes the beginning of a list.
+ * @returns {AnonReadColBeginReturn}
+ */
+TJSONProtocol.prototype.readListBegin = function() {
+  var list = this.rstack[this.rstack.length - 1];
+
+  var r = {};
+  r.etype = TJSONProtocol.RType[list.shift()];
+  r.size = list.shift();
+
+  this.rpos.push(this.rstack.length);
+  this.rstack.push(list.shift());
+
+  return r;
+};
+
+/** Deserializes the end of a list. */
+TJSONProtocol.prototype.readListEnd = function() {
+  var pos = this.rpos.pop() - 2;
+  var st = this.rstack;
+  st.pop();
+  if (st instanceof Array && st.length > pos && st[pos].length > 0) {
+    st.push(st[pos].shift());
+  }
+};
+
+/**
+ * Deserializes the beginning of a set.
+ * @returns {AnonReadColBeginReturn}
+ */
+TJSONProtocol.prototype.readSetBegin = function() {
+  return this.readListBegin();
+};
+
+/** Deserializes the end of a set. */
+TJSONProtocol.prototype.readSetEnd = function() {
+  return this.readListEnd();
+};
+
+TJSONProtocol.prototype.readBool = function() {
+  return this.readValue() == '1';
+};
+
+TJSONProtocol.prototype.readByte = function() {
+  return this.readI32();
+};
+
+TJSONProtocol.prototype.readI16 = function() {
+  return this.readI32();
+};
+
+TJSONProtocol.prototype.readI32 = function(f) {
+  return +this.readValue();
+}
+
+/** Returns the next value found in the protocol buffer */
+TJSONProtocol.prototype.readValue = function(f) {
+  if (f === undefined) {
+    f = this.rstack[this.rstack.length - 1];
+  }
+
+  var r = {};
+
+  if (f instanceof Array) {
+    if (f.length === 0) {
+      r.value = undefined;
+    } else {
+      r.value = f.shift();
+    }
+  } else if (!(f instanceof Int64) && f instanceof Object) {
+    for (var i in f) {
+      if (i === null) {
+        continue;
+      }
+      this.rstack.push(f[i]);
+      delete f[i];
+
+      r.value = i;
+      break;
+    }
+  } else {
+    r.value = f;
+    this.rstack.pop();
+  }
+
+  return r.value;
+};
+
+TJSONProtocol.prototype.readI64 = function() {
+  var n = this.readValue()
+  if (typeof n === 'string') {
+    // Assuming no one is sending in 1.11111e+33 format
+    return Int64Util.fromDecimalString(n);
+  } else {
+    return new Int64(n);
+  }
+};
+
+TJSONProtocol.prototype.readDouble = function() {
+  return this.readI32();
+};
+
+TJSONProtocol.prototype.readBinary = function() {
+  return new Buffer(this.readValue(), 'base64');
+};
+
+TJSONProtocol.prototype.readString = function() {
+  return this.readValue();
+};
+
+/**
+ * Returns the underlying transport.
+ * @readonly
+ * @returns {Thrift.Transport} The underlying transport.
+ */
+TJSONProtocol.prototype.getTransport = function() {
+  return this.trans;
+};
+
+/**
+ * Method to arbitrarily skip over data
+ */
+TJSONProtocol.prototype.skip = function(type) {
+    switch (type) {
+    case Type.STOP:
+      return;
+    case Type.BOOL:
+      this.readBool();
+      break;
+    case Type.BYTE:
+      this.readByte();
+      break;
+    case Type.I16:
+      this.readI16();
+      break;
+    case Type.I32:
+      this.readI32();
+      break;
+    case Type.I64:
+      this.readI64();
+      break;
+    case Type.DOUBLE:
+      this.readDouble();
+      break;
+    case Type.STRING:
+      this.readString();
+      break;
+    case Type.STRUCT:
+      this.readStructBegin();
+      while (true) {
+        var r = this.readFieldBegin();
+        if (r.ftype === Type.STOP) {
+          break;
+        }
+        this.skip(r.ftype);
+        this.readFieldEnd();
+      }
+      this.readStructEnd();
+      break;
+    case Type.MAP:
+      var mapBegin = this.readMapBegin();
+      for (var i = 0; i < mapBegin.size; ++i) {
+        this.skip(mapBegin.ktype);
+        this.skip(mapBegin.vtype);
+      }
+      this.readMapEnd();
+      break;
+    case Type.SET:
+      var setBegin = this.readSetBegin();
+      for (var i2 = 0; i2 < setBegin.size; ++i2) {
+        this.skip(setBegin.etype);
+      }
+      this.readSetEnd();
+      break;
+    case Type.LIST:
+      var listBegin = this.readListBegin();
+      for (var i3 = 0; i3 < listBegin.size; ++i3) {
+        this.skip(listBegin.etype);
+      }
+      this.readListEnd();
+      break;
+    default:
+      throw new  Error("Invalid type: " + type);
+  }
+};
diff --git a/lib/nodejs/lib/thrift/log.js b/lib/nodejs/lib/thrift/log.js
new file mode 100644
index 0000000..053e813
--- /dev/null
+++ b/lib/nodejs/lib/thrift/log.js
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var util = require('util');
+
+var disabled = function () {};
+var logFunc = console.log;
+var logLevel = 'error'; // default level
+
+function factory(level) {
+  return function () {
+    // better use spread syntax, but due to compatibility,
+    // use legacy method here.
+    var args = ['thrift: [' + level + '] '].concat(Array.from(arguments));
+    return logFunc(util.format.apply(null, args));
+  };
+}
+
+var trace = disabled;
+var debug = disabled;
+var error = disabled;
+var warning = disabled;
+var info = disabled;
+
+exports.setLogFunc = function (func) {
+  logFunc = func;
+};
+
+var setLogLevel = exports.setLogLevel = function (level) {
+  trace = debug = error = warning = info = disabled;
+  logLevel = level;
+  switch (logLevel) {
+  case 'trace':
+    trace = factory('TRACE');
+  case 'debug':
+    debug = factory('DEBUG');
+  case 'error':
+    error = factory('ERROR');
+  case 'warning':
+    warning = factory('WARN');
+  case 'info':
+    info = factory('INFO');
+  }
+};
+
+// set default
+setLogLevel(logLevel);
+
+exports.getLogLevel = function () {
+  return logLevel;
+};
+
+exports.trace = function () {
+  return trace.apply(null, arguments);
+};
+
+exports.debug = function () {
+  return debug.apply(null, arguments);
+};
+
+exports.error = function () {
+  return error.apply(null, arguments);
+};
+
+exports.warning = function () {
+  return warning.apply(null, arguments);
+};
+
+exports.info = function () {
+  return info.apply(null, arguments);
+};
diff --git a/lib/nodejs/lib/thrift/multiplexed_processor.js b/lib/nodejs/lib/thrift/multiplexed_processor.js
new file mode 100644
index 0000000..67b62f7
--- /dev/null
+++ b/lib/nodejs/lib/thrift/multiplexed_processor.js
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var Thrift = require('./thrift');
+
+exports.MultiplexedProcessor = MultiplexedProcessor;
+
+function MultiplexedProcessor(stream, options) {
+  this.services = {};
+};
+
+MultiplexedProcessor.prototype.registerProcessor = function(name, handler) {
+  this.services[name] = handler;
+};
+
+MultiplexedProcessor.prototype.process = function(inp, out) {
+  var begin = inp.readMessageBegin();
+
+  if (begin.mtype != Thrift.MessageType.CALL && begin.mtype != Thrift.MessageType.ONEWAY) {
+    throw new Thrift.TException('TMultiplexedProcessor: Unexpected message type');
+  }
+
+  var p = begin.fname.split(':');
+  var sname = p[0];
+  var fname = p[1];
+
+  if (! (sname in this.services)) {
+    throw new Thrift.TException('TMultiplexedProcessor: Unknown service: ' + sname);
+  }
+
+  //construct a proxy object which stubs the readMessageBegin
+  //for the service
+  var inpProxy = {};
+
+  for (var attr in inp) {
+    inpProxy[attr] = inp[attr];
+  }
+
+  inpProxy.readMessageBegin = function() {
+    return {
+      fname: fname,
+      mtype: begin.mtype,
+      rseqid: begin.rseqid
+    };
+  };
+
+  this.services[sname].process(inpProxy, out);
+};
diff --git a/lib/nodejs/lib/thrift/multiplexed_protocol.js b/lib/nodejs/lib/thrift/multiplexed_protocol.js
new file mode 100644
index 0000000..d078aa2
--- /dev/null
+++ b/lib/nodejs/lib/thrift/multiplexed_protocol.js
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var util = require('util');
+var Thrift = require('./thrift');
+
+exports.Multiplexer = Multiplexer;
+
+function Wrapper(serviceName, protocol, connection) {
+
+  function MultiplexProtocol(trans, strictRead, strictWrite) {
+    protocol.call(this, trans, strictRead, strictWrite);
+  };
+
+  util.inherits(MultiplexProtocol, protocol);
+
+  MultiplexProtocol.prototype.writeMessageBegin = function(name, type, seqid) {
+    if (type == Thrift.MessageType.CALL || type == Thrift.MessageType.ONEWAY) {
+      connection.seqId2Service[seqid] = serviceName;
+      MultiplexProtocol.super_.prototype.writeMessageBegin.call(this,
+                                                                serviceName + ":" + name,
+                                                                type,
+                                                                seqid);
+    } else {
+      MultiplexProtocol.super_.prototype.writeMessageBegin.call(this, name, type, seqid);
+    }
+  };
+
+  return MultiplexProtocol;
+};
+
+function Multiplexer() {
+  this.seqid = 0;
+};
+
+Multiplexer.prototype.createClient = function(serviceName, ServiceClient, connection) {
+  if (ServiceClient.Client) {
+    ServiceClient = ServiceClient.Client;
+  }
+  var writeCb = function(buf, seqid) {
+    connection.write(buf,seqid);
+  };
+  var transport = new connection.transport(undefined, writeCb);
+  var protocolWrapper = new Wrapper(serviceName, connection.protocol, connection);
+  var client = new ServiceClient(transport, protocolWrapper);
+  var self = this;
+  client.new_seqid = function() {
+    self.seqid += 1;
+    return self.seqid;
+  };
+
+  if (typeof connection.client !== 'object') {
+    connection.client = {};
+  }
+  connection.client[serviceName] = client;
+
+  return client;
+};
diff --git a/lib/nodejs/lib/thrift/protocol.js b/lib/nodejs/lib/thrift/protocol.js
index cbf6c9a..a70ebe2 100644
--- a/lib/nodejs/lib/thrift/protocol.js
+++ b/lib/nodejs/lib/thrift/protocol.js
@@ -16,337 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-var util = require('util'),
-    Thrift = require('./thrift'),
-    Type = Thrift.Type;
 
-var binary = require('./binary'),
-    Int64 = require('node-int64');
-
-var UNKNOWN = 0,
-    INVALID_DATA = 1,
-    NEGATIVE_SIZE = 2,
-    SIZE_LIMIT = 3,
-    BAD_VERSION = 4;
-
-var TProtocolException = function(type, message) {
-  Error.call(this, message);
-  this.name = 'TProtocolException';
-  this.type = type;
-}
-util.inherits(TProtocolException, Error);
-
-var TBinaryProtocol = exports.TBinaryProtocol = function(trans, strictRead, strictWrite) {
-  this.trans = trans;
-  this.strictRead = (strictRead !== undefined ? strictRead : false);
-  this.strictWrite = (strictWrite !== undefined ? strictWrite : true);
-}
-
-TBinaryProtocol.prototype.flush = function() {
-  return this.trans.flush();
-}
-
-// NastyHaxx. JavaScript forces hex constants to be
-// positive, converting this into a long. If we hardcode the int value
-// instead it'll stay in 32 bit-land.
-
-var VERSION_MASK = -65536, // 0xffff0000
-    VERSION_1 = -2147418112, // 0x80010000
-    TYPE_MASK = 0x000000ff;
-
-TBinaryProtocol.prototype.writeMessageBegin = function(name, type, seqid) {
-    if (this.strictWrite) {
-      this.writeI32(VERSION_1 | type);
-      this.writeString(name);
-      this.writeI32(seqid);
-    } else {
-      this.writeString(name);
-      this.writeByte(type);
-      this.writeI32(seqid);
-    }
-}
-
-TBinaryProtocol.prototype.writeMessageEnd = function() {
-}
-
-TBinaryProtocol.prototype.writeStructBegin = function(name) {
-}
-
-TBinaryProtocol.prototype.writeStructEnd = function() {
-}
-
-TBinaryProtocol.prototype.writeFieldBegin = function(name, type, id) {
-  this.writeByte(type);
-  this.writeI16(id);
-}
-
-TBinaryProtocol.prototype.writeFieldEnd = function() {
-}
-
-TBinaryProtocol.prototype.writeFieldStop = function() {
-  this.writeByte(Type.STOP);
-}
-
-TBinaryProtocol.prototype.writeMapBegin = function(ktype, vtype, size) {
-  this.writeByte(ktype);
-  this.writeByte(vtype);
-  this.writeI32(size);
-}
-
-TBinaryProtocol.prototype.writeMapEnd = function() {
-}
-
-TBinaryProtocol.prototype.writeListBegin = function(etype, size) {
-  this.writeByte(etype);
-  this.writeI32(size);
-}
-
-TBinaryProtocol.prototype.writeListEnd = function() {
-}
-
-TBinaryProtocol.prototype.writeSetBegin = function(etype, size) {
-  console.log('write set', etype, size);
-  this.writeByte(etype);
-  this.writeI32(size);
-}
-
-TBinaryProtocol.prototype.writeSetEnd = function() {
-}
-
-TBinaryProtocol.prototype.writeBool = function(bool) {
-  if (bool) {
-    this.writeByte(1);
-  } else {
-    this.writeByte(0);
-  }
-}
-
-TBinaryProtocol.prototype.writeByte = function(byte) {
-  this.trans.write(new Buffer([byte]));
-}
-
-TBinaryProtocol.prototype.writeI16 = function(i16) {
-  this.trans.write(binary.writeI16(new Buffer(2), i16));
-}
-
-TBinaryProtocol.prototype.writeI32 = function(i32) {
-  this.trans.write(binary.writeI32(new Buffer(4), i32));
-}
-
-TBinaryProtocol.prototype.writeI64 = function(i64) {
-  if (i64.buffer) {
-    this.trans.write(i64.buffer);
-  } else {
-    this.trans.write(new Int64(i64).buffer)
-  }
-}
-
-TBinaryProtocol.prototype.writeDouble = function(dub) {
-  this.trans.write(binary.writeDouble(new Buffer(8), dub));
-}
-
-TBinaryProtocol.prototype.writeString = function(arg) {
-  if (typeof(arg) === 'string') {
-    this.writeI32(Buffer.byteLength(arg, 'utf8'))
-    this.trans.write(arg, 'utf8');
-  } else if (arg instanceof Buffer) {
-    this.writeI32(arg.length)
-    this.trans.write(arg);
-  } else {
-    throw new Error('writeString called without a string/Buffer argument: ' + arg)
-  }
-}
-
-TBinaryProtocol.prototype.writeBinary = function(arg) {
-  if (typeof(arg) === 'string') {
-    this.writeI32(Buffer.byteLength(arg, 'utf8'))
-    this.trans.write(arg, 'utf8');
-  } else if (arg instanceof Buffer) {
-    this.writeI32(arg.length)
-    this.trans.write(arg);
-  } else {
-    throw new Error('writeBinary called without a string/Buffer argument: ' + arg)
-  }
-}
-
-TBinaryProtocol.prototype.readMessageBegin = function() {
-  var sz = this.readI32();
-  var type, name, seqid;
-
-  if (sz < 0) {
-    var version = sz & VERSION_MASK;
-    if (version != VERSION_1) {
-      console.log("BAD: " + version);
-      throw TProtocolException(BAD_VERSION, "Bad version in readMessageBegin: " + sz);
-    }
-    type = sz & TYPE_MASK;
-    name = this.readString();
-    seqid = this.readI32();
-  } else {
-    if (this.strictRead) {
-      throw TProtocolException(BAD_VERSION, "No protocol version header");
-    }
-    name = this.trans.read(sz);
-    type = this.readByte();
-    seqid = this.readI32();
-  }
-  return {fname: name, mtype: type, rseqid: seqid};
-}
-
-TBinaryProtocol.prototype.readMessageEnd = function() {
-}
-
-TBinaryProtocol.prototype.readStructBegin = function() {
-  return {fname: ''}
-}
-
-TBinaryProtocol.prototype.readStructEnd = function() {
-}
-
-TBinaryProtocol.prototype.readFieldBegin = function() {
-  var type = this.readByte();
-  if (type == Type.STOP) {
-    return {fname: null, ftype: type, fid: 0};
-  }
-  var id = this.readI16();
-  return {fname: null, ftype: type, fid: id};
-}
-
-TBinaryProtocol.prototype.readFieldEnd = function() {
-}
-
-TBinaryProtocol.prototype.readMapBegin = function() {
-  var ktype = this.readByte();
-  var vtype = this.readByte();
-  var size = this.readI32();
-  return {ktype: ktype, vtype: vtype, size: size};
-}
-
-TBinaryProtocol.prototype.readMapEnd = function() {
-}
-
-TBinaryProtocol.prototype.readListBegin = function() {
-  var etype = this.readByte();
-  var size = this.readI32();
-  return {etype: etype, size: size};
-}
-
-TBinaryProtocol.prototype.readListEnd = function() {
-}
-
-TBinaryProtocol.prototype.readSetBegin = function() {
-  var etype = this.readByte();
-  var size = this.readI32();
-  return {etype: etype, size: size};
-}
-
-TBinaryProtocol.prototype.readSetEnd = function() {
-}
-
-TBinaryProtocol.prototype.readBool = function() {
-  var byte = this.readByte();
-  if (byte == 0) {
-    return false;
-  }
-  return true;
-}
-
-TBinaryProtocol.prototype.readByte = function() {
-  return this.trans.readByte();
-}
-
-TBinaryProtocol.prototype.readI16 = function() {
-  return this.trans.readI16();
-}
-
-TBinaryProtocol.prototype.readI32 = function() {
-  return this.trans.readI32();
-}
-
-TBinaryProtocol.prototype.readI64 = function() {
-  var buff = this.trans.read(8);
-  return new Int64(buff);
-}
-
-TBinaryProtocol.prototype.readDouble = function() {
-  return this.trans.readDouble();
-}
-
-TBinaryProtocol.prototype.readBinary = function() {
-  var len = this.readI32();
-  return this.trans.read(len);
-}
-
-TBinaryProtocol.prototype.readString = function() {
-  var len = this.readI32();
-  return this.trans.readString(len);
-}
-
-TBinaryProtocol.prototype.getTransport = function() {
-  return this.trans;
-}
-
-TBinaryProtocol.prototype.skip = function(type) {
-  // console.log("skip: " + type);
-  switch (type) {
-    case Type.STOP:
-      return;
-    case Type.BOOL:
-      this.readBool();
-      break;
-    case Type.BYTE:
-      this.readByte();
-      break;
-    case Type.I16:
-      this.readI16();
-      break;
-    case Type.I32:
-      this.readI32();
-      break;
-    case Type.I64:
-      this.readI64();
-      break;
-    case Type.DOUBLE:
-      this.readDouble();
-      break;
-    case Type.STRING:
-      this.readString();
-      break;
-    case Type.STRUCT:
-      this.readStructBegin();
-      while (true) {
-        var r = this.readFieldBegin();
-        if (r.ftype === Type.STOP) {
-          break;
-        }
-        this.skip(r.ftype);
-        this.readFieldEnd();
-      }
-      this.readStructEnd();
-      break;
-    case Type.MAP:
-      var r = this.readMapBegin();
-      for (var i = 0; i < r.size; ++i) {
-        this.skip(r.ktype);
-        this.skip(r.vtype);
-      }
-      this.readMapEnd();
-      break;
-    case Type.SET:
-      var r = this.readSetBegin();
-      for (var i = 0; i < r.size; ++i) {
-        this.skip(r.etype);
-      }
-      this.readSetEnd();
-      break;
-    case Type.LIST:
-      var r = this.readListBegin();
-      for (var i = 0; i < r.size; ++i) {
-        this.skip(r.etype);
-      }
-      this.readListEnd();
-      break;
-    default:
-      throw Error("Invalid type: " + type);
-  }
-}
+module.exports.TBinaryProtocol = require('./binary_protocol');
+module.exports.TCompactProtocol = require('./compact_protocol');
+module.exports.TJSONProtocol = require('./json_protocol');
diff --git a/lib/nodejs/lib/thrift/server.js b/lib/nodejs/lib/thrift/server.js
index f219048..e124acc 100644
--- a/lib/nodejs/lib/thrift/server.js
+++ b/lib/nodejs/lib/thrift/server.js
@@ -16,21 +16,31 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
+var constants = require('constants');
 var net = require('net');
+var tls = require('tls');
 
-var ttransport = require('./transport')
-  , TBinaryProtocol = require('./protocol').TBinaryProtocol;
+var TBufferedTransport = require('./buffered_transport');
+var TBinaryProtocol = require('./binary_protocol');
+var InputBufferUnderrunError = require('./input_buffer_underrun_error');
 
-exports.createServer = function(cls, handler, options) {
-  if (cls.Processor) {
-    cls = cls.Processor;
-  }
-  var processor = new cls(handler);
-  var transport = (options && options.transport) ? options.transport : ttransport.TBufferedTransport;
+/**
+ * Create a Thrift server which can serve one or multiple services.
+ * @param {object} processor - A normal or multiplexedProcessor (must
+ *                             be preconstructed with the desired handler).
+ * @param {ServerOptions} options - Optional additional server configuration.
+ * @returns {object} - The Apache Thrift Multiplex Server.
+ */
+exports.createMultiplexServer = function(processor, options) {
+  var transport = (options && options.transport) ? options.transport : TBufferedTransport;
   var protocol = (options && options.protocol) ? options.protocol : TBinaryProtocol;
 
-  return net.createServer(function(stream) {
+  function serverImpl(stream) {
     var self = this;
+    stream.on('error', function(err) {
+        self.emit('error', err);
+    });
     stream.on('data', transport.receiver(function(transportWithData) {
       var input = new protocol(transportWithData);
       var output = new protocol(new transport(undefined, function(buf) {
@@ -43,14 +53,30 @@
       }));
 
       try {
-        processor.process(input, output);
-        transportWithData.commitPosition();
-      }
-      catch (err) {
-        if (err instanceof ttransport.InputBufferUnderrunError) {
+        do {
+          processor.process(input, output);
+          transportWithData.commitPosition();
+        } while (true);
+      } catch (err) {
+        if (err instanceof InputBufferUnderrunError) {
+          //The last data in the buffer was not a complete message, wait for the rest
+          transportWithData.rollbackPosition();
+        }
+        else if (err.message === "Invalid type: undefined") {
+          //No more data in the buffer
+          //This trap is a bit hackish
+          //The next step to improve the node behavior here is to have
+          //  the compiler generated process method throw a more explicit
+          //  error when the network buffer is empty (regardles of the
+          //  protocol/transport stack in use) and replace this heuristic.
+          //  Also transports should probably not force upper layers to
+          //  manage their buffer positions (i.e. rollbackPosition() and
+          //  commitPosition() should be eliminated in lieu of a transport
+          //  encapsulated buffer management strategy.)
           transportWithData.rollbackPosition();
         }
         else {
+          //Unexpected error
           self.emit('error', err);
           stream.end();
         }
@@ -60,5 +86,28 @@
     stream.on('end', function() {
       stream.end();
     });
-  });
+  }
+
+  if (options && options.tls) {
+    if (!('secureProtocol' in options.tls) && !('secureOptions' in options.tls)) {
+      options.tls.secureProtocol = "SSLv23_method";
+      options.tls.secureOptions = constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3;
+    }
+    return tls.createServer(options.tls, serverImpl);
+  } else {
+    return net.createServer(serverImpl);
+  }
+};
+
+/**
+ * Create a single service Apache Thrift server.
+ * @param {object} processor - A service class or processor function.
+ * @param {ServerOptions} options - Optional additional server configuration.
+ * @returns {object} - The Apache Thrift Multiplex Server.
+ */
+exports.createServer = function(processor, handler, options) {
+  if (processor.Processor) {
+    processor = processor.Processor;
+  }
+  return exports.createMultiplexServer(new processor(handler), options);
 };
diff --git a/lib/nodejs/lib/thrift/thrift.js b/lib/nodejs/lib/thrift/thrift.js
index 94223e3..f2b2896 100644
--- a/lib/nodejs/lib/thrift/thrift.js
+++ b/lib/nodejs/lib/thrift/thrift.js
@@ -35,20 +35,24 @@
   SET: 14,
   LIST: 15,
   UTF8: 16,
-  UTF16: 17,
-}
+  UTF16: 17
+};
 
 exports.MessageType = {
   CALL: 1,
   REPLY: 2,
   EXCEPTION: 3,
-  ONEWAY: 4,
-}
+  ONEWAY: 4
+};
 
-var TException = exports.TException = function(message) {
-  Error.call(this, message);
-  this.name = 'TException';
-}
+exports.TException = TException;
+
+function TException(message) {
+  Error.call(this);
+  Error.captureStackTrace(this, this.constructor);
+  this.name = this.constructor.name;
+  this.message = message;
+};
 util.inherits(TException, Error);
 
 var TApplicationExceptionType = exports.TApplicationExceptionType = {
@@ -63,81 +67,166 @@
   INVALID_TRANSFORM: 8,
   INVALID_PROTOCOL: 9,
   UNSUPPORTED_CLIENT_TYPE: 10
-}
+};
 
-var TApplicationException = exports.TApplicationException = function(type, message) {
-  TException.call(this, message);
+exports.TApplicationException = TApplicationException;
+
+function TApplicationException(type, message) {
+  TException.call(this);
+  Error.captureStackTrace(this, this.constructor);
   this.type = type || TApplicationExceptionType.UNKNOWN;
-  this.name = 'TApplicationException';
-}
+  this.name = this.constructor.name;
+  this.message = message;
+};
 util.inherits(TApplicationException, TException);
 
 TApplicationException.prototype.read = function(input) {
-  var ftype
-  var fid
-  var ret = input.readStructBegin('TApplicationException')
+  var ftype;
+  var ret = input.readStructBegin('TApplicationException');
 
   while(1){
-
-      ret = input.readFieldBegin()
-
+      ret = input.readFieldBegin();
       if(ret.ftype == Type.STOP)
-          break
+          break;
 
-      var fid = ret.fid
-
-      switch(fid){
+      switch(ret.fid){
           case 1:
               if( ret.ftype == Type.STRING ){
-                  ret = input.readString()
-                  this.message = ret
+                  ret = input.readString();
+                  this.message = ret;
               } else {
-                  ret = input.skip(ret.ftype)
+                  ret = input.skip(ret.ftype);
               }
-
-              break
+              break;
           case 2:
               if( ret.ftype == Type.I32 ){
-                  ret = input.readI32()
-                  this.type = ret
+                  ret = input.readI32();
+                  this.type = ret;
               } else {
-                  ret   = input.skip(ret.ftype)
+                  ret   = input.skip(ret.ftype);
               }
-              break
-
+              break;
           default:
-              ret = input.skip(ret.ftype)
-              break
+              ret = input.skip(ret.ftype);
+              break;
       }
-      input.readFieldEnd()
+      input.readFieldEnd();
   }
-
-  input.readStructEnd()
-}
+  input.readStructEnd();
+};
 
 TApplicationException.prototype.write = function(output){
   output.writeStructBegin('TApplicationException');
 
   if (this.message) {
-      output.writeFieldBegin('message', Type.STRING, 1)
-      output.writeString(this.message)
-      output.writeFieldEnd()
+      output.writeFieldBegin('message', Type.STRING, 1);
+      output.writeString(this.message);
+      output.writeFieldEnd();
   }
 
   if (this.code) {
-      output.writeFieldBegin('type', Type.I32, 2)
-      output.writeI32(this.code)
-      output.writeFieldEnd()
+      output.writeFieldBegin('type', Type.I32, 2);
+      output.writeI32(this.code);
+      output.writeFieldEnd();
   }
 
-  output.writeFieldStop()
-  output.writeStructEnd()
-}
+  output.writeFieldStop();
+  output.writeStructEnd();
+};
+
+var TProtocolExceptionType = exports.TProtocolExceptionType = {
+  UNKNOWN: 0,
+  INVALID_DATA: 1,
+  NEGATIVE_SIZE: 2,
+  SIZE_LIMIT: 3,
+  BAD_VERSION: 4,
+  NOT_IMPLEMENTED: 5,
+  DEPTH_LIMIT: 6
+};
+
+
+exports.TProtocolException = TProtocolException;
+
+function TProtocolException(type, message) {
+  Error.call(this);
+  Error.captureStackTrace(this, this.constructor);
+  this.name = this.constructor.name;
+  this.type = type;
+  this.message = message;
+};
+util.inherits(TProtocolException, Error);
 
 exports.objectLength = function(obj) {
   return Object.keys(obj).length;
-}
+};
 
 exports.inherits = function(constructor, superConstructor) {
   util.inherits(constructor, superConstructor);
-}
+};
+
+var copyList, copyMap;
+
+copyList = function(lst, types) {
+
+  if (!lst) {return lst; }
+
+  var type;
+
+  if (types.shift === undefined) {
+    type = types;
+  }
+  else {
+    type = types[0];
+  }
+  var Type = type;
+
+  var len = lst.length, result = [], i, val;
+  for (i = 0; i < len; i++) {
+    val = lst[i];
+    if (type === null) {
+      result.push(val);
+    }
+    else if (type === copyMap || type === copyList) {
+      result.push(type(val, types.slice(1)));
+    }
+    else {
+      result.push(new Type(val));
+    }
+  }
+  return result;
+};
+
+copyMap = function(obj, types){
+
+  if (!obj) {return obj; }
+
+  var type;
+
+  if (types.shift === undefined) {
+    type = types;
+  }
+  else {
+    type = types[0];
+  }
+  var Type = type;
+
+  var result = {}, val;
+  for(var prop in obj) {
+    if(obj.hasOwnProperty(prop)) {
+      val = obj[prop];
+      if (type === null) {
+        result[prop] = val;
+      }
+      else if (type === copyMap || type === copyList) {
+        result[prop] = type(val, types.slice(1));
+      }
+      else {
+        result[prop] = new Type(val);
+      }
+    }
+  }
+  return result;
+};
+
+module.exports.copyMap = copyMap;
+module.exports.copyList = copyList;
diff --git a/lib/nodejs/lib/thrift/transport.js b/lib/nodejs/lib/thrift/transport.js
index e918335..59daa98 100644
--- a/lib/nodejs/lib/thrift/transport.js
+++ b/lib/nodejs/lib/thrift/transport.js
@@ -16,290 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-var emptyBuf = new Buffer(0);
 
-var binary = require('./binary');
-
-var InputBufferUnderrunError = exports.InputBufferUnderrunError = function() {
-};
-
-var TFramedTransport = exports.TFramedTransport = function(buffer, callback) {
-  this.inBuf = buffer || emptyBuf;
-  this.outBuffers = [];
-  this.outCount = 0;
-  this.readPos = 0;
-  this.onFlush = callback;
-};
-TFramedTransport.receiver = function(callback) {
-  var frameLeft = 0,
-      framePos = 0,
-      frame = null;
-  var residual = null;
-
-  return function(data) {
-    // Prepend any residual data from our previous read
-    if (residual) {
-      var dat = new Buffer(data.length + residual.length);
-      residual.copy(dat, 0, 0);
-      data.copy(dat, residual.length, 0);
-      residual = null;
-    }
-
-    // framed transport
-    while (data.length) {
-      if (frameLeft === 0) {
-        // TODO assumes we have all 4 bytes
-        if (data.length < 4) {
-          console.log("Expecting > 4 bytes, found only " + data.length);
-          residual = data;
-          break;
-          //throw Error("Expecting > 4 bytes, found only " + data.length);
-        }
-        frameLeft = binary.readI32(data, 0);
-        frame = new Buffer(frameLeft);
-        framePos = 0;
-        data = data.slice(4, data.length);
-      }
-      
-      if (data.length >= frameLeft) {
-        data.copy(frame, framePos, 0, frameLeft);
-        data = data.slice(frameLeft, data.length);
-        
-        frameLeft = 0;
-        callback(new TFramedTransport(frame));
-      } else if (data.length) {
-        data.copy(frame, framePos, 0, data.length);
-        frameLeft -= data.length;
-        framePos += data.length;
-        data = data.slice(data.length, data.length);
-      }
-    }
-  };
-};
-
-TFramedTransport.prototype = {
-  commitPosition: function(){},
-  rollbackPosition: function(){},
-
-  // TODO: Implement open/close support
-  isOpen: function() {return true;},
-  open: function() {},
-  close: function() {},
-
-  read: function(len) { // this function will be used for each frames.
-    var end = this.readPos + len;
-
-    if (this.inBuf.length < end) {
-      throw new Error('read(' + len + ') failed - not enough data');
-    }
-
-    var buf = this.inBuf.slice(this.readPos, end);
-    this.readPos = end;
-    return buf;
-  },
-
-  readByte: function() {
-    return binary.readByte(this.inBuf[this.readPos++]);
-  },
-
-  readI16: function() {
-    var i16 = binary.readI16(this.inBuf, this.readPos);
-    this.readPos += 2;
-    return i16;
-  },
-
-  readI32: function() {
-    var i32 = binary.readI32(this.inBuf, this.readPos);
-    this.readPos += 4;
-    return i32;
-  },
-
-  readDouble: function() {
-    var d = binary.readDouble(this.inBuf, this.readPos);
-    this.readPos += 8;
-    return d;
-  },
-
-  readString: function(len) {
-    var str = this.inBuf.toString('utf8', this.readPos, this.readPos + len);
-    this.readPos += len;
-    return str;
-  },
-
-  readAll: function() {
-    return this.inBuf;
-  },
-
-  write: function(buf, encoding) {
-    if (typeof(buf) === "string") {
-      buf = new Buffer(buf, encoding || 'utf8');
-    }
-    this.outBuffers.push(buf);
-    this.outCount += buf.length;
-  },
-
-  flush: function() {
-    var out = new Buffer(this.outCount),
-        pos = 0;
-    this.outBuffers.forEach(function(buf) {
-      buf.copy(out, pos, 0);
-      pos += buf.length;
-    });
-    
-    if (this.onFlush) {
-      // TODO: optimize this better, allocate one buffer instead of both:
-      var msg = new Buffer(out.length + 4);
-      binary.writeI32(msg, out.length)
-      frameLeft = binary.readI32(this.inBuf, 0);
-      out.copy(msg, 4, 0, out.length);
-      this.onFlush(msg);
-    }
-
-    this.outBuffers = [];
-    this.outCount = 0;
-  }
-};
-
-var TBufferedTransport = exports.TBufferedTransport = function(buffer, callback) {
-  this.defaultReadBufferSize = 1024;
-  this.writeBufferSize = 512; // Soft Limit
-  this.inBuf = new Buffer(this.defaultReadBufferSize);
-  this.readCursor = 0;
-  this.writeCursor = 0; // for input buffer
-  this.outBuffers = [];
-  this.outCount = 0;
-  this.onFlush = callback;
-};
-TBufferedTransport.receiver = function(callback) {
-  var reader = new TBufferedTransport();
-
-  return function(data) {
-    if (reader.writeCursor + data.length > reader.inBuf.length) {
-      var buf = new Buffer(reader.writeCursor + data.length);
-      reader.inBuf.copy(buf, 0, 0, reader.writeCursor);
-      reader.inBuf = buf;
-    }
-    data.copy(reader.inBuf, reader.writeCursor, 0);
-    reader.writeCursor += data.length;
-
-    callback(reader);
-  };
-};
-
-TBufferedTransport.prototype = {
-  commitPosition: function(){
-    var unreadedSize = this.writeCursor - this.readCursor;
-    var bufSize = (unreadedSize * 2 > this.defaultReadBufferSize) ? unreadedSize * 2 : this.defaultReadBufferSize;
-    var buf = new Buffer(bufSize);
-    if (unreadedSize > 0) {
-      this.inBuf.copy(buf, 0, this.readCursor, this.writeCursor);
-    }
-    this.readCursor = 0;
-    this.writeCursor = unreadedSize;
-    this.inBuf = buf;
-  },
-  rollbackPosition: function(){
-    this.readCursor = 0;
-  },
-
-  // TODO: Implement open/close support
-  isOpen: function() {return true;},
-  open: function() {},
-  close: function() {},
-
-  ensureAvailable: function(len) {
-    if (this.readCursor + len > this.writeCursor) {
-      throw new InputBufferUnderrunError();
-    }
-  },
-
-  read: function(len) {
-    this.ensureAvailable(len)
-    var buf = new Buffer(len);
-    this.inBuf.copy(buf, 0, this.readCursor, this.readCursor + len);
-    this.readCursor += len;
-    return buf;
-  },
-
-  readByte: function() {
-    this.ensureAvailable(1)
-    return binary.readByte(this.inBuf[this.readCursor++]);
-  },
-
-  readI16: function() {
-    this.ensureAvailable(2)
-    var i16 = binary.readI16(this.inBuf, this.readCursor);
-    this.readCursor += 2;
-    return i16;
-  },
-
-  readI32: function() {
-    this.ensureAvailable(4)
-    var i32 = binary.readI32(this.inBuf, this.readCursor);
-    this.readCursor += 4;
-    return i32;
-  },
-
-  readDouble: function() {
-    this.ensureAvailable(8)
-    var d = binary.readDouble(this.inBuf, this.readCursor);
-    this.readCursor += 8;
-    return d;
-  },
-
-  readString: function(len) {
-    this.ensureAvailable(len)
-    var str = this.inBuf.toString('utf8', this.readCursor, this.readCursor + len);
-    this.readCursor += len;
-    return str;
-  },
-
-
-  readAll: function() {
-    if (this.readCursor >= this.writeCursor) {
-      throw new InputBufferUnderrunError();
-    }
-    var buf = new Buffer(this.writeCursor - this.readCursor);
-    this.inBuf.copy(buf, 0, this.readCursor, this.writeCursor);
-    this.readCursor = this.writeCursor;
-    return buf;
-  },
-
-  write: function(buf, encoding) {
-    if (typeof(buf) === "string") {
-      // Defaulting to ascii encoding here since that's more like the original
-      // code, but I feel like 'utf8' would be a better choice.
-      buf = new Buffer(buf, encoding || 'ascii');
-    }
-    if (this.outCount + buf.length > this.writeBufferSize) {
-      this.flush();
-    }
-
-    this.outBuffers.push(buf);
-    this.outCount += buf.length;
-
-    if (this.outCount >= this.writeBufferSize) {
-      this.flush();
-    }
-  },
-
-  flush: function() {
-    if (this.outCount < 1) {
-      return;
-    }
-    
-    var msg = new Buffer(this.outCount),
-        pos = 0;
-    this.outBuffers.forEach(function(buf) {
-      buf.copy(msg, pos, 0);
-      pos += buf.length;
-    });
-    
-    if (this.onFlush) {
-      this.onFlush(msg);
-    }
-
-    this.outBuffers = [];
-    this.outCount = 0;
-  }
-};
+module.exports.TBufferedTransport = require('./buffered_transport');
+module.exports.TFramedTransport = require('./framed_transport');
+module.exports.InputBufferUnderrunError = require('./input_buffer_underrun_error');
diff --git a/lib/nodejs/lib/thrift/web_server.js b/lib/nodejs/lib/thrift/web_server.js
new file mode 100644
index 0000000..a33f47a
--- /dev/null
+++ b/lib/nodejs/lib/thrift/web_server.js
@@ -0,0 +1,567 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var http = require('http');
+var https = require('https');
+var url = require("url");
+var path = require("path");
+var fs = require("fs");
+var crypto = require("crypto");
+var log = require('./log');
+
+var MultiplexedProcessor = require('./multiplexed_processor').MultiplexedProcessor;
+
+var TBufferedTransport = require('./buffered_transport');
+var TBinaryProtocol = require('./binary_protocol');
+var InputBufferUnderrunError = require('./input_buffer_underrun_error');
+
+// WSFrame constructor and prototype
+/////////////////////////////////////////////////////////////////////
+
+/** Apache Thrift RPC Web Socket Transport
+ *  Frame layout conforming to RFC 6455 circa 12/2011
+ *
+ * Theoretical frame size limit is 4GB*4GB, however the Node Buffer
+ * limit is 1GB as of v0.10. The frame length encoding is also
+ * configured for a max of 4GB presently and needs to be adjusted
+ * if Node/Browsers become capabile of > 4GB frames.
+ *
+ *  - FIN is 1 if the message is complete
+ *  - RSV1/2/3 are always 0
+ *  - Opcode is 1(TEXT) for TJSONProtocol and 2(BIN) for TBinaryProtocol
+ *  - Mask Present bit is 1 sending to-server and 0 sending to-client
+ *  - Payload Len:
+ *        + If < 126: then represented directly
+ *        + If >=126: but within range of an unsigned 16 bit integer
+ *             then Payload Len is 126 and the two following bytes store
+ *             the length
+ *        + Else: Payload Len is 127 and the following 8 bytes store the
+ *             length as an unsigned 64 bit integer
+ *  - Masking key is a 32 bit key only present when sending to the server
+ *  - Payload follows the masking key or length
+ *
+ *     0                   1                   2                   3
+ *     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *    +-+-+-+-+-------+-+-------------+-------------------------------+
+ *    |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
+ *    |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
+ *    |N|V|V|V|       |S|             |   (if payload len==126/127)   |
+ *    | |1|2|3|       |K|             |                               |
+ *    +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
+ *    |     Extended payload length continued, if payload len == 127  |
+ *    + - - - - - - - - - - - - - - - +-------------------------------+
+ *    |                               |Masking-key, if MASK set to 1  |
+ *    +-------------------------------+-------------------------------+
+ *    | Masking-key (continued)       |          Payload Data         |
+ *    +-------------------------------- - - - - - - - - - - - - - - - +
+ *    :                     Payload Data continued ...                :
+ *    + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+ *    |                     Payload Data continued ...                |
+ *    +---------------------------------------------------------------+
+ */
+var wsFrame = {
+  /** Encodes a WebSocket frame
+   *
+   * @param {Buffer} data - The raw data to encode
+   * @param {Buffer} mask - The mask to apply when sending to server, null for no mask
+   * @param {Boolean} binEncoding - True for binary encoding, false for text encoding
+   * @returns {Buffer} - The WebSocket frame, ready to send
+   */
+  encode: function(data, mask, binEncoding) {
+      var frame = new Buffer(wsFrame.frameSizeFromData(data, mask));
+      //Byte 0 - FIN & OPCODE
+      frame[0] = wsFrame.fin.FIN +
+          (binEncoding ? wsFrame.frameOpCodes.BIN : wsFrame.frameOpCodes.TEXT);
+      //Byte 1 or 1-3 or 1-9 - MASK FLAG & SIZE
+      var payloadOffset = 2;
+      if (data.length < 0x7E) {
+        frame[1] = data.length + (mask ? wsFrame.mask.TO_SERVER : wsFrame.mask.TO_CLIENT);
+      } else if (data.length < 0xFFFF) {
+        frame[1] = 0x7E + (mask ? wsFrame.mask.TO_SERVER : wsFrame.mask.TO_CLIENT);
+        frame.writeUInt16BE(data.length, 2, true);
+        payloadOffset = 4;
+      } else {
+        frame[1] = 0x7F + (mask ? wsFrame.mask.TO_SERVER : wsFrame.mask.TO_CLIENT);
+        frame.writeUInt32BE(0, 2, true);
+        frame.writeUInt32BE(data.length, 6, true);
+        payloadOffset = 10;
+      }
+      //MASK
+      if (mask) {
+        mask.copy(frame, payloadOffset, 0, 4);
+        payloadOffset += 4;
+      }
+      //Payload
+      data.copy(frame, payloadOffset);
+      if (mask) {
+        wsFrame.applyMask(frame.slice(payloadOffset), frame.slice(payloadOffset-4,payloadOffset));
+      }
+      return frame;
+  },
+
+  /**
+   * @class
+   * @name WSDecodeResult
+   * @property {Buffer} data - The decoded data for the first ATRPC message
+   * @property {Buffer} mask - The frame mask
+   * @property {Boolean} binEncoding - True if binary (TBinaryProtocol),
+   *                                   False if text (TJSONProtocol)
+   * @property {Buffer} nextFrame - Multiple ATRPC messages may be sent in a
+   *                                single WebSocket frame, this Buffer contains
+   *                                any bytes remaining to be decoded
+   * @property {Boolean} FIN - True is the message is complete
+   */
+
+   /** Decodes a WebSocket frame
+   *
+   * @param {Buffer} frame - The raw inbound frame, if this is a continuation
+   *                         frame it must have a mask property with the mask.
+   * @returns {WSDecodeResult} - The decoded payload
+   *
+   * @see {@link WSDecodeResult}
+   */
+  decode: function(frame) {
+      var result = {
+        data: null,
+        mask: null,
+        binEncoding: false,
+        nextFrame: null,
+        FIN: true
+      };
+
+      //Byte 0 - FIN & OPCODE
+      if (wsFrame.fin.FIN != (frame[0] & wsFrame.fin.FIN)) {
+        result.FIN = false;
+      }
+      result.binEncoding = (wsFrame.frameOpCodes.BIN == (frame[0] & wsFrame.frameOpCodes.BIN));
+      //Byte 1 or 1-3 or 1-9 - SIZE
+      var lenByte = (frame[1] & 0x0000007F);
+      var len = lenByte;
+      var dataOffset = 2;
+      if (lenByte == 0x7E) {
+        len = frame.readUInt16BE(2);
+        dataOffset = 4;
+      } else if (lenByte == 0x7F) {
+        len = frame.readUInt32BE(6);
+        dataOffset = 10;
+      }
+      //MASK
+      if (wsFrame.mask.TO_SERVER == (frame[1] & wsFrame.mask.TO_SERVER)) {
+        result.mask = new Buffer(4);
+        frame.copy(result.mask, 0, dataOffset, dataOffset + 4);
+        dataOffset += 4;
+      }
+      //Payload
+      result.data = new Buffer(len);
+      frame.copy(result.data, 0, dataOffset, dataOffset+len);
+      if (result.mask) {
+        wsFrame.applyMask(result.data, result.mask);
+      }
+      //Next Frame
+      if (frame.length > dataOffset+len) {
+        result.nextFrame = new Buffer(frame.length - (dataOffset+len));
+        frame.copy(result.nextFrame, 0, dataOffset+len, frame.length);
+      }
+      //Don't forward control frames
+      if (frame[0] & wsFrame.frameOpCodes.FINCTRL) {
+        result.data = null;
+      }
+
+      return result;
+  },
+
+  /** Masks/Unmasks data
+   *
+   * @param {Buffer} data - data to mask/unmask in place
+   * @param {Buffer} mask - the mask
+   */
+  applyMask: function(data, mask){
+    //TODO: look into xoring words at a time
+    var dataLen = data.length;
+    var maskLen = mask.length;
+    for (var i = 0; i < dataLen; i++) {
+      data[i] = data[i] ^ mask[i%maskLen];
+    }
+  },
+
+  /** Computes frame size on the wire from data to be sent
+   *
+   * @param {Buffer} data - data.length is the assumed payload size
+   * @param {Boolean} mask - true if a mask will be sent (TO_SERVER)
+   */
+  frameSizeFromData: function(data, mask) {
+    var headerSize = 10;
+    if (data.length < 0x7E) {
+      headerSize = 2;
+    } else if (data.length < 0xFFFF) {
+      headerSize = 4;
+    }
+    return headerSize + data.length + (mask ? 4 : 0);
+  },
+
+  frameOpCodes: {
+    CONT:     0x00,
+    TEXT:     0x01,
+    BIN:      0x02,
+    CTRL:     0x80
+  },
+
+  mask: {
+    TO_SERVER: 0x80,
+    TO_CLIENT: 0x00
+  },
+
+  fin: {
+    CONT: 0x00,
+    FIN: 0x80
+  }
+};
+
+
+// createWebServer constructor and options
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * @class
+ * @name ServerOptions
+ * @property {array} cors - Array of CORS origin strings to permit requests from.
+ * @property {string} files - Path to serve static files from, if absent or ""
+ *                               static file service is disabled.
+ * @property {object} headers - An object hash mapping header strings to header value
+ *                              strings, these headers are transmitted in response to
+ *                              static file GET operations.
+ * @property {object} services - An object hash mapping service URI strings
+ *                               to ServiceOptions objects
+ * @property {object} tls - Node.js TLS options (see: nodejs.org/api/tls.html),
+ *                          if not present or null regular http is used,
+ *                          at least a key and a cert must be defined to use SSL/TLS
+ * @see {@link ServiceOptions}
+ */
+
+/**
+ * @class
+ * @name ServiceOptions
+ * @property {object} transport - The layered transport to use (defaults
+ *                                to TBufferedTransport).
+ * @property {object} protocol - The serialization Protocol to use (defaults to
+ *                               TBinaryProtocol).
+ * @property {object} processor - The Thrift Service class/processor generated
+ *                                by the IDL Compiler for the service (the "cls"
+ *                                key can also be used for this attribute).
+ * @property {object} handler - The handler methods for the Thrift Service.
+ */
+
+/**
+ * Create a Thrift server which can serve static files and/or one or
+ * more Thrift Services.
+ * @param {ServerOptions} options - The server configuration.
+ * @returns {object} - The Apache Thrift Web Server.
+ */
+exports.createWebServer = function(options) {
+  var baseDir = options.files;
+  var contentTypesByExtension = {
+    '.txt': 'text/plain',
+    '.html': 'text/html',
+    '.css': 'text/css',
+    '.xml': 'application/xml',
+    '.json': 'application/json',
+    '.js': 'application/javascript',
+    '.jpg': 'image/jpeg',
+    '.jpeg': 'image/jpeg',
+    '.gif': 'image/gif',
+    '.png': 'image/png',
+    '.svg': 'image/svg+xml'
+  };
+
+  //Setup all of the services
+  var services = options.services;
+  for (var uri in services) {
+    var svcObj = services[uri];
+
+    //Setup the processor
+    if (svcObj.processor instanceof MultiplexedProcessor) {
+      //Multiplex processors have pre embedded processor/handler pairs, save as is
+      svcObj.processor = svcObj.processor;
+    } else {
+      //For historical reasons Node.js supports processors passed in directly or via the
+      //  IDL Compiler generated class housing the processor. Also, the options property
+      //  for a Processor has been called both cls and processor at different times. We
+      //  support any of the four possibilities here.
+      var processor = (svcObj.processor) ? (svcObj.processor.Processor || svcObj.processor) :
+                                           (svcObj.cls.Processor || svcObj.cls);
+      //Processors can be supplied as constructed objects with handlers already embedded,
+      //  if a handler is provided we construct a new processor, if not we use the processor
+      //  object directly
+      if (svcObj.handler) {
+        svcObj.processor = new processor(svcObj.handler);
+      } else {
+        svcObj.processor = processor;
+      }
+    }
+    svcObj.transport = svcObj.transport ? svcObj.transport : TBufferedTransport;
+    svcObj.protocol = svcObj.protocol ? svcObj.protocol : TBinaryProtocol;
+  }
+
+  //Verify CORS requirements
+  function VerifyCORSAndSetHeaders(request, response) {
+    if (request.headers.origin && options.cors) {
+      if (options.cors["*"] || options.cors[request.headers.origin]) {
+        //Allow, origin allowed
+        response.setHeader("access-control-allow-origin", request.headers.origin);
+        response.setHeader("access-control-allow-methods", "GET, POST, OPTIONS");
+        response.setHeader("access-control-allow-headers", "content-type, accept");
+        response.setHeader("access-control-max-age", "60");
+        return true;
+      } else {
+        //Disallow, origin denied
+        return false;
+      }
+    }
+    //Allow, CORS is not in use
+    return true;
+  }
+
+
+  //Handle OPTIONS method (CORS)
+  ///////////////////////////////////////////////////
+  function processOptions(request, response) {
+    if (VerifyCORSAndSetHeaders(request, response)) {
+      response.writeHead("204", "No Content", {"content-length": 0});
+    } else {
+      response.writeHead("403", "Origin " + request.headers.origin + " not allowed", {});
+    }
+    response.end();
+  }
+
+
+  //Handle POST methods (TXHRTransport)
+  ///////////////////////////////////////////////////
+  function processPost(request, response) {
+    //Lookup service
+    var uri = url.parse(request.url).pathname;
+    var svc = services[uri];
+    if (!svc) {
+      response.writeHead("403", "No Apache Thrift Service at " + uri, {});
+      response.end();
+      return;
+    }
+
+    //Verify CORS requirements
+    if (!VerifyCORSAndSetHeaders(request, response)) {
+      response.writeHead("403", "Origin " + request.headers.origin + " not allowed", {});
+      response.end();
+      return;
+    }
+
+    //Process XHR payload
+    request.on('data', svc.transport.receiver(function(transportWithData) {
+      var input = new svc.protocol(transportWithData);
+      var output = new svc.protocol(new svc.transport(undefined, function(buf) {
+        try {
+          response.writeHead(200);
+          response.end(buf);
+        } catch (err) {
+          response.writeHead(500);
+          response.end();
+        }
+      }));
+
+      try {
+        svc.processor.process(input, output);
+        transportWithData.commitPosition();
+      } catch (err) {
+        if (err instanceof InputBufferUnderrunError) {
+          transportWithData.rollbackPosition();
+        } else {
+          response.writeHead(500);
+          response.end();
+        }
+      }
+    }));
+  }
+
+
+  //Handle GET methods (Static Page Server)
+  ///////////////////////////////////////////////////
+  function processGet(request, response) {
+    //Undefined or empty base directory means do not serve static files
+    if (!baseDir || "" === baseDir) {
+      response.writeHead(404);
+      response.end();
+      return;
+    }
+
+    //Verify CORS requirements
+    if (!VerifyCORSAndSetHeaders(request, response)) {
+      response.writeHead("403", "Origin " + request.headers.origin + " not allowed", {});
+      response.end();
+      return;
+    }
+
+    //Locate the file requested and send it
+    var uri = url.parse(request.url).pathname;
+    var filename = path.resolve(path.join(baseDir, uri));
+
+    //Ensure the basedir path is not able to be escaped
+    if (filename.indexOf(baseDir) != 0) {
+      response.writeHead(400, "Invalid request path", {});
+      response.end();
+      return;
+    }
+
+    fs.exists(filename, function(exists) {
+      if(!exists) {
+        response.writeHead(404);
+        response.end();
+        return;
+      }
+
+      if (fs.statSync(filename).isDirectory()) {
+        filename += '/index.html';
+      }
+
+      fs.readFile(filename, "binary", function(err, file) {
+        if (err) {
+          response.writeHead(500);
+          response.end(err + "\n");
+          return;
+        }
+        var headers = {};
+        var contentType = contentTypesByExtension[path.extname(filename)];
+        if (contentType) {
+          headers["Content-Type"] = contentType;
+        }
+        for (var k in options.headers) {
+          headers[k] = options.headers[k];
+        }
+        response.writeHead(200, headers);
+        response.write(file, "binary");
+        response.end();
+      });
+    });
+  }
+
+
+  //Handle WebSocket calls (TWebSocketTransport)
+  ///////////////////////////////////////////////////
+  function processWS(data, socket, svc, binEncoding) {
+    svc.transport.receiver(function(transportWithData) {
+      var input = new svc.protocol(transportWithData);
+      var output = new svc.protocol(new svc.transport(undefined, function(buf) {
+        try {
+          var frame = wsFrame.encode(buf, null, binEncoding);
+          socket.write(frame);
+        } catch (err) {
+          //TODO: Add better error processing
+        }
+      }));
+
+      try {
+        svc.processor.process(input, output);
+        transportWithData.commitPosition();
+      }
+      catch (err) {
+        if (err instanceof InputBufferUnderrunError) {
+          transportWithData.rollbackPosition();
+        }
+        else {
+          //TODO: Add better error processing
+        }
+      }
+    })(data);
+  }
+
+  //Create the server (HTTP or HTTPS)
+  var server = null;
+  if (options.tls) {
+    server = https.createServer(options.tls);
+  } else {
+    server = http.createServer();
+  }
+
+  //Wire up listeners for upgrade(to WebSocket) & request methods for:
+  //   - GET static files,
+  //   - POST XHR Thrift services
+  //   - OPTIONS CORS requests
+  server.on('request', function(request, response) {
+    if (request.method === 'POST') {
+      processPost(request, response);
+    } else if (request.method === 'GET') {
+      processGet(request, response);
+    } else if (request.method === 'OPTIONS') {
+      processOptions(request, response);
+    } else {
+      response.writeHead(500);
+      response.end();
+    }
+  }).on('upgrade', function(request, socket, head) {
+    //Lookup service
+    var svc;
+    try {
+      svc = services[Object.keys(services)[0]];
+    } catch(e) {
+      socket.write("HTTP/1.1 403 No Apache Thrift Service available\r\n\r\n");
+      return;
+    }
+    //Perform upgrade
+    var hash = crypto.createHash("sha1");
+    hash.update(request.headers['sec-websocket-key'] + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
+    socket.write("HTTP/1.1 101 Switching Protocols\r\n" +
+                   "Upgrade: websocket\r\n" +
+                   "Connection: Upgrade\r\n" +
+                   "Sec-WebSocket-Accept: " + hash.digest("base64") + "\r\n" +
+                   "Sec-WebSocket-Origin: " + request.headers.origin + "\r\n" +
+                   "Sec-WebSocket-Location: ws://" + request.headers.host + request.url + "\r\n" +
+                   "\r\n");
+    //Handle WebSocket traffic
+    var data = null;
+    socket.on('data', function(frame) {
+      try {
+        while (frame) {
+          var result = wsFrame.decode(frame);
+          //Prepend any existing decoded data
+          if (data) {
+            if (result.data) {
+              var newData = new Buffer(data.length + result.data.length);
+              data.copy(newData);
+              result.data.copy(newData, data.length);
+              result.data = newData;
+            } else {
+              result.data = data;
+            }
+            data = null;
+          }
+          //If this completes a message process it
+          if (result.FIN) {
+            processWS(result.data, socket, svc, result.binEncoding);
+          } else {
+            data = result.data;
+          }
+          //Prepare next frame for decoding (if any)
+          frame = result.nextFrame;
+        }
+      } catch(e) {
+        log.error('TWebSocketTransport Exception: ' + e);
+        socket.destroy();
+      }
+    });
+  });
+
+  //Return the server
+  return server;
+};
diff --git a/lib/nodejs/lib/thrift/ws_connection.js b/lib/nodejs/lib/thrift/ws_connection.js
new file mode 100644
index 0000000..052cbd4
--- /dev/null
+++ b/lib/nodejs/lib/thrift/ws_connection.js
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var util = require('util');
+var WebSocket = require('ws');
+var EventEmitter = require("events").EventEmitter;
+var thrift = require('./thrift');
+var ttransport = require('./transport');
+var tprotocol = require('./protocol');
+
+var TBufferedTransport = require('./buffered_transport');
+var TJSONProtocol = require('./json_protocol');
+var InputBufferUnderrunError = require('./input_buffer_underrun_error');
+
+var createClient = require('./create_client');
+
+exports.WSConnection = WSConnection;
+
+/**
+ * @class
+ * @name WSConnectOptions
+ * @property {string} transport - The Thrift layered transport to use (TBufferedTransport, etc).
+ * @property {string} protocol - The Thrift serialization protocol to use (TJSONProtocol, etc.).
+ * @property {string} path - The URL path to connect to (e.g. "/", "/mySvc", "/thrift/quoteSvc", etc.).
+ * @property {object} headers - A standard Node.js header hash, an object hash containing key/value
+ *        pairs where the key is the header name string and the value is the header value string.
+ * @property {boolean} secure - True causes the connection to use wss, otherwise ws is used.
+ * @property {object} wsOptions - Options passed on to WebSocket.
+ * @example
+ *     //Use a secured websocket connection
+ *     //  uses the buffered transport layer, uses the JSON protocol and directs RPC traffic
+ *     //  to wss://thrift.example.com:9090/hello
+ *     var thrift = require('thrift');
+ *     var options = {
+ *        transport: thrift.TBufferedTransport,
+ *        protocol: thrift.TJSONProtocol,
+ *        path: "/hello",
+ *        secure: true
+ *     };
+ *     var con = thrift.createWSConnection("thrift.example.com", 9090, options);
+ *     con.open()
+ *     var client = thrift.createWSClient(myService, connection);
+ *     client.myServiceFunction();
+ *     con.close()
+ */
+
+/**
+ * Initializes a Thrift WSConnection instance (use createWSConnection() rather than
+ *    instantiating directly).
+ * @constructor
+ * @param {string} host - The host name or IP to connect to.
+ * @param {number} port - The TCP port to connect to.
+ * @param {WSConnectOptions} options - The configuration options to use.
+ * @throws {error} Exceptions other than ttransport.InputBufferUnderrunError are rethrown
+ * @event {error} The "error" event is fired when a Node.js error event occurs during
+ *     request or response processing, in which case the node error is passed on. An "error"
+ *     event may also be fired when the connectison can not map a response back to the
+ *     appropriate client (an internal error), generating a TApplicationException.
+ * @classdesc WSConnection objects provide Thrift end point transport
+ *     semantics implemented using Websockets.
+ * @see {@link createWSConnection}
+ */
+function WSConnection(host, port, options) {
+  //Initialize the emitter base object
+  EventEmitter.call(this);
+
+  //Set configuration
+  var self = this;
+  this.options = options || {};
+  this.host = host;
+  this.port = port;
+  this.secure = this.options.secure || false;
+  this.transport = this.options.transport || TBufferedTransport;
+  this.protocol = this.options.protocol || TJSONProtocol;
+  this.path = this.options.path;
+  this.send_pending = [];
+
+  //The sequence map is used to map seqIDs back to the
+  //  calling client in multiplexed scenarios
+  this.seqId2Service = {};
+
+  //Prepare WebSocket options
+  this.wsOptions = {
+    host: this.host,
+    port: this.port || 80,
+    path: this.options.path || '/',
+    headers: this.options.headers || {}
+  };
+  for (var attrname in this.options.wsOptions) {
+    this.wsOptions[attrname] = this.options.wsOptions[attrname];
+  }
+};
+util.inherits(WSConnection, EventEmitter);
+
+WSConnection.prototype.__reset = function() {
+  this.socket = null; //The web socket
+  this.send_pending = []; //Buffers/Callback pairs waiting to be sent
+};
+
+WSConnection.prototype.__onOpen = function() {
+  var self = this;
+  this.emit("open");
+  if (this.send_pending.length > 0) {
+    //If the user made calls before the connection was fully
+    //open, send them now
+    this.send_pending.forEach(function(data) {
+      self.socket.send(data);
+    });
+    this.send_pending = [];
+  }
+};
+
+WSConnection.prototype.__onClose = function(evt) {
+  this.emit("close");
+  this.__reset();
+};
+
+WSConnection.prototype.__decodeCallback = function(transport_with_data) {
+  var proto = new this.protocol(transport_with_data);
+  try {
+    while (true) {
+      var header = proto.readMessageBegin();
+      var dummy_seqid = header.rseqid * -1;
+      var client = this.client;
+      //The Multiplexed Protocol stores a hash of seqid to service names
+      //  in seqId2Service. If the SeqId is found in the hash we need to
+      //  lookup the appropriate client for this call.
+      //  The client var is a single client object when not multiplexing,
+      //  when using multiplexing it is a service name keyed hash of client
+      //  objects.
+      //NOTE: The 2 way interdependencies between protocols, transports,
+      //  connections and clients in the Node.js implementation are irregular
+      //  and make the implementation difficult to extend and maintain. We
+      //  should bring this stuff inline with typical thrift I/O stack
+      //  operation soon.
+      //  --ra
+      var service_name = this.seqId2Service[header.rseqid];
+      if (service_name) {
+        client = this.client[service_name];
+        delete this.seqId2Service[header.rseqid];
+      }
+      /*jshint -W083 */
+      client._reqs[dummy_seqid] = function(err, success) {
+        transport_with_data.commitPosition();
+        var clientCallback = client._reqs[header.rseqid];
+        delete client._reqs[header.rseqid];
+        if (clientCallback) {
+          clientCallback(err, success);
+        }
+      };
+      /*jshint +W083 */
+      if (client['recv_' + header.fname]) {
+        client['recv_' + header.fname](proto, header.mtype, dummy_seqid);
+      } else {
+        delete client._reqs[dummy_seqid];
+        this.emit("error",
+          new thrift.TApplicationException(
+            thrift.TApplicationExceptionType.WRONG_METHOD_NAME,
+            "Received a response to an unknown RPC function"));
+      }
+    }
+  } catch (e) {
+    if (e instanceof InputBufferUnderrunError) {
+      transport_with_data.rollbackPosition();
+    } else {
+      throw e;
+    }
+  }
+};
+
+WSConnection.prototype.__onData = function(data) {
+  if (Object.prototype.toString.call(data) == "[object ArrayBuffer]") {
+    data = new Uint8Array(data);
+  }
+  var buf = new Buffer(data);
+  this.transport.receiver(this.__decodeCallback.bind(this))(buf);
+
+};
+
+WSConnection.prototype.__onMessage = function(evt) {
+  this.__onData(evt.data);
+};
+
+WSConnection.prototype.__onError = function(evt) {
+  this.emit("error", evt);
+  this.socket.close();
+};
+
+/**
+ * Returns true if the transport is open
+ * @readonly
+ * @returns {boolean}
+ */
+WSConnection.prototype.isOpen = function() {
+  return this.socket && this.socket.readyState == this.socket.OPEN;
+};
+
+/**
+ * Opens the transport connection
+ */
+WSConnection.prototype.open = function() {
+  //If OPEN/CONNECTING/CLOSING ignore additional opens
+  if (this.socket && this.socket.readyState != this.socket.CLOSED) {
+    return;
+  }
+  //If there is no socket or the socket is closed:
+  this.socket = new WebSocket(this.uri(), "", this.wsOptions);
+  this.socket.binaryType = 'arraybuffer';
+  this.socket.onopen = this.__onOpen.bind(this);
+  this.socket.onmessage = this.__onMessage.bind(this);
+  this.socket.onerror = this.__onError.bind(this);
+  this.socket.onclose = this.__onClose.bind(this);
+};
+
+/**
+ * Closes the transport connection
+ */
+WSConnection.prototype.close = function() {
+  this.socket.close();
+};
+
+/**
+ * Return URI for the connection
+ * @returns {string} URI
+ */
+WSConnection.prototype.uri = function() {
+  var schema = this.secure ? 'wss' : 'ws';
+  var port = '';
+  var path = this.path || '/';
+  var host = this.host;
+
+  // avoid port if default for schema
+  if (this.port && (('wss' == schema && this.port != 443) ||
+    ('ws' == schema && this.port != 80))) {
+    port = ':' + this.port;
+  }
+
+  return schema + '://' + host + port + path;
+};
+
+/**
+ * Writes Thrift message data to the connection
+ * @param {Buffer} data - A Node.js Buffer containing the data to write
+ * @returns {void} No return value.
+ * @event {error} the "error" event is raised upon request failure passing the
+ *     Node.js error object to the listener.
+ */
+WSConnection.prototype.write = function(data) {
+  if (this.isOpen()) {
+    //Send data and register a callback to invoke the client callback
+    this.socket.send(data);
+  } else {
+    //Queue the send to go out __onOpen
+    this.send_pending.push(data);
+  }
+};
+
+/**
+ * Creates a new WSConnection object, used by Thrift clients to connect
+ *    to Thrift HTTP based servers.
+ * @param {string} host - The host name or IP to connect to.
+ * @param {number} port - The TCP port to connect to.
+ * @param {WSConnectOptions} options - The configuration options to use.
+ * @returns {WSConnection} The connection object.
+ * @see {@link WSConnectOptions}
+ */
+exports.createWSConnection = function(host, port, options) {
+  return new WSConnection(host, port, options);
+};
+
+exports.createWSClient = createClient;
diff --git a/lib/nodejs/lib/thrift/ws_transport.js b/lib/nodejs/lib/thrift/ws_transport.js
new file mode 100644
index 0000000..3513b84
--- /dev/null
+++ b/lib/nodejs/lib/thrift/ws_transport.js
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var log = require('./log');
+
+module.exports = TWebSocketTransport;
+
+/**
+ * Constructor Function for the WebSocket transport.
+ * @constructor
+ * @param {string} [url] - The URL to connect to.
+ * @classdesc The Apache Thrift Transport layer performs byte level I/O
+ * between RPC clients and servers. The JavaScript TWebSocketTransport object
+ * uses the WebSocket protocol. Target servers must implement WebSocket.
+ * (see: node.js example server_http.js).
+ * @example
+ *   var transport = new Thrift.TWebSocketTransport("http://localhost:8585");
+ */
+function TWebSocketTransport(url) {
+    this.__reset(url);
+};
+
+
+TWebSocketTransport.prototype.__reset = function(url) {
+  this.url = url;             //Where to connect
+  this.socket = null;         //The web socket
+  this.callbacks = [];        //Pending callbacks
+  this.send_pending = [];     //Buffers/Callback pairs waiting to be sent
+  this.send_buf = '';         //Outbound data, immutable until sent
+  this.recv_buf = '';         //Inbound data
+  this.rb_wpos = 0;           //Network write position in receive buffer
+  this.rb_rpos = 0;           //Client read position in receive buffer
+};
+
+/**
+ * Sends the current WS request and registers callback. The async
+ * parameter is ignored (WS flush is always async) and the callback
+ * function parameter is required.
+ * @param {object} async - Ignored.
+ * @param {object} callback - The client completion callback.
+ * @returns {undefined|string} Nothing (undefined)
+ */
+TWebSocketTransport.prototype.flush = function(async, callback) {
+  var self = this;
+  if (this.isOpen()) {
+    //Send data and register a callback to invoke the client callback
+    this.socket.send(this.send_buf);
+    this.callbacks.push((function() {
+      var clientCallback = callback;
+      return function(msg) {
+        self.setRecvBuffer(msg);
+        clientCallback();
+      };
+    }()));
+  } else {
+    //Queue the send to go out __onOpen
+    this.send_pending.push({
+      buf: this.send_buf,
+      cb:  callback
+    });
+  }
+};
+
+TWebSocketTransport.prototype.__onOpen = function() {
+   var self = this;
+   if (this.send_pending.length > 0) {
+      //If the user made calls before the connection was fully
+      //open, send them now
+      this.send_pending.forEach(function(elem) {
+         this.socket.send(elem.buf);
+         this.callbacks.push((function() {
+           var clientCallback = elem.cb;
+           return function(msg) {
+              self.setRecvBuffer(msg);
+              clientCallback();
+           };
+         }()));
+      });
+      this.send_pending = [];
+   }
+};
+
+TWebSocketTransport.prototype.__onClose = function(evt) {
+  this.__reset(this.url);
+};
+
+TWebSocketTransport.prototype.__onMessage = function(evt) {
+  if (this.callbacks.length) {
+    this.callbacks.shift()(evt.data);
+  }
+};
+
+TWebSocketTransport.prototype.__onError = function(evt) {
+  log.error('websocket: ' + evt.toString());
+  this.socket.close();
+};
+
+/**
+ * Sets the buffer to use when receiving server responses.
+ * @param {string} buf - The buffer to receive server responses.
+ */
+TWebSocketTransport.prototype.setRecvBuffer = function(buf) {
+  this.recv_buf = buf;
+  this.recv_buf_sz = this.recv_buf.length;
+  this.wpos = this.recv_buf.length;
+  this.rpos = 0;
+};
+
+/**
+ * Returns true if the transport is open
+ * @readonly
+ * @returns {boolean}
+ */
+TWebSocketTransport.prototype.isOpen = function() {
+  return this.socket && this.socket.readyState == this.socket.OPEN;
+};
+
+/**
+ * Opens the transport connection
+ */
+TWebSocketTransport.prototype.open = function() {
+  //If OPEN/CONNECTING/CLOSING ignore additional opens
+  if (this.socket && this.socket.readyState != this.socket.CLOSED) {
+    return;
+  }
+  //If there is no socket or the socket is closed:
+  this.socket = new WebSocket(this.url);
+  this.socket.onopen = this.__onOpen.bind(this);
+  this.socket.onmessage = this.__onMessage.bind(this);
+  this.socket.onerror = this.__onError.bind(this);
+  this.socket.onclose = this.__onClose.bind(this);
+};
+
+/**
+ * Closes the transport connection
+ */
+TWebSocketTransport.prototype.close = function() {
+  this.socket.close();
+};
+
+/**
+ * Returns the specified number of characters from the response
+ * buffer.
+ * @param {number} len - The number of characters to return.
+ * @returns {string} Characters sent by the server.
+ */
+TWebSocketTransport.prototype.read = function(len) {
+  var avail = this.wpos - this.rpos;
+
+  if (avail === 0) {
+    return '';
+  }
+
+  var give = len;
+
+  if (avail < len) {
+    give = avail;
+  }
+
+  var ret = this.read_buf.substr(this.rpos, give);
+  this.rpos += give;
+
+  //clear buf when complete?
+  return ret;
+};
+
+/**
+ * Returns the entire response buffer.
+ * @returns {string} Characters sent by the server.
+ */
+TWebSocketTransport.prototype.readAll = function() {
+  return this.recv_buf;
+};
+
+/**
+ * Sets the send buffer to buf.
+ * @param {string} buf - The buffer to send.
+ */
+TWebSocketTransport.prototype.write = function(buf) {
+  this.send_buf = buf;
+};
+
+/**
+ * Returns the send buffer.
+ * @readonly
+ * @returns {string} The send buffer.
+ */
+TWebSocketTransport.prototype.getSendBuffer = function() {
+  return this.send_buf;
+};
diff --git a/lib/nodejs/lib/thrift/xhr_connection.js b/lib/nodejs/lib/thrift/xhr_connection.js
new file mode 100644
index 0000000..6459c90
--- /dev/null
+++ b/lib/nodejs/lib/thrift/xhr_connection.js
@@ -0,0 +1,280 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var util = require('util');
+var EventEmitter = require("events").EventEmitter;
+var thrift = require('./thrift');
+
+var TBufferedTransport = require('./buffered_transport');
+var TJSONProtocol = require('./json_protocol');
+var InputBufferUnderrunError = require('./input_buffer_underrun_error');
+
+var createClient = require('./create_client');
+
+exports.XHRConnection = XHRConnection;
+
+/**
+ * Constructor Function for the XHR Connection.
+ * If you do not specify a host and port then XHRConnection will default to the
+ * host and port of the page from which this javascript is served.
+ * @constructor
+ * @param {string} [url] - The URL to connect to.
+ * @classdesc TXHRConnection objects provide Thrift end point transport
+ *     semantics implemented using XHR.
+ * @example
+ *     var transport = new Thrift.TXHRConnection('localhost', 9099, {});
+ */
+function XHRConnection(host, port, options) {
+  this.options = options || {};
+  this.wpos = 0;
+  this.rpos = 0;
+  this.useCORS = (options && options.useCORS);
+  this.send_buf = '';
+  this.recv_buf = '';
+  this.transport = options.transport || TBufferedTransport;
+  this.protocol = options.protocol || TJSONProtocol;
+  this.headers = options.headers || {};
+
+  host = host || window.location.host;
+  port = port || window.location.port;
+  var prefix = options.https ? 'https://' : 'http://';
+  var path = options.path || '/';
+
+  if (port === '') {
+    port = undefined;
+  }
+
+  if (!port || port === 80 || port === '80') {
+    this.url = prefix + host + path;
+  } else {
+    this.url = prefix + host + ':' + port + path;
+  }
+
+  //The sequence map is used to map seqIDs back to the
+  //  calling client in multiplexed scenarios
+  this.seqId2Service = {};
+};
+
+util.inherits(XHRConnection, EventEmitter);
+
+/**
+* Gets the browser specific XmlHttpRequest Object.
+* @returns {object} the browser XHR interface object
+*/
+XHRConnection.prototype.getXmlHttpRequestObject = function() {
+  try { return new XMLHttpRequest(); } catch (e1) { }
+  try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { }
+  try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { }
+
+  throw "Your browser doesn't support XHR.";
+};
+
+/**
+ * Sends the current XRH request if the transport was created with a URL
+ * and the async parameter is false. If the transport was not created with
+ * a URL, or the async parameter is True and no callback is provided, or
+ * the URL is an empty string, the current send buffer is returned.
+ * @param {object} async - If true the current send buffer is returned.
+ * @param {object} callback - Optional async completion callback
+ * @returns {undefined|string} Nothing or the current send buffer.
+ * @throws {string} If XHR fails.
+ */
+XHRConnection.prototype.flush = function() {
+  var self = this;
+  if (this.url === undefined || this.url === '') {
+    return this.send_buf;
+  }
+
+  var xreq = this.getXmlHttpRequestObject();
+
+  if (xreq.overrideMimeType) {
+    xreq.overrideMimeType('application/json');
+  }
+
+  xreq.onreadystatechange = function() {
+    if (this.readyState == 4 && this.status == 200) {
+      self.setRecvBuffer(this.responseText);
+    }
+  };
+
+  xreq.open('POST', this.url, true);
+
+  Object.keys(this.headers).forEach(function(headerKey) {
+    xreq.setRequestHeader(headerKey, self.headers[headerKey]);
+  });
+
+  xreq.send(this.send_buf);
+};
+
+/**
+ * Sets the buffer to provide the protocol when deserializing.
+ * @param {string} buf - The buffer to supply the protocol.
+ */
+XHRConnection.prototype.setRecvBuffer = function(buf) {
+  this.recv_buf = buf;
+  this.recv_buf_sz = this.recv_buf.length;
+  this.wpos = this.recv_buf.length;
+  this.rpos = 0;
+
+  if (Object.prototype.toString.call(buf) == "[object ArrayBuffer]") {
+    var data = new Uint8Array(buf);
+  }
+  var thing = new Buffer(data || buf);
+
+  this.transport.receiver(this.__decodeCallback.bind(this))(thing);
+
+};
+
+XHRConnection.prototype.__decodeCallback = function(transport_with_data) {
+  var proto = new this.protocol(transport_with_data);
+  try {
+    while (true) {
+      var header = proto.readMessageBegin();
+      var dummy_seqid = header.rseqid * -1;
+      var client = this.client;
+      //The Multiplexed Protocol stores a hash of seqid to service names
+      //  in seqId2Service. If the SeqId is found in the hash we need to
+      //  lookup the appropriate client for this call.
+      //  The client var is a single client object when not multiplexing,
+      //  when using multiplexing it is a service name keyed hash of client
+      //  objects.
+      //NOTE: The 2 way interdependencies between protocols, transports,
+      //  connections and clients in the Node.js implementation are irregular
+      //  and make the implementation difficult to extend and maintain. We
+      //  should bring this stuff inline with typical thrift I/O stack
+      //  operation soon.
+      //  --ra
+      var service_name = this.seqId2Service[header.rseqid];
+      if (service_name) {
+        client = this.client[service_name];
+        delete this.seqId2Service[header.rseqid];
+      }
+      /*jshint -W083 */
+      client._reqs[dummy_seqid] = function(err, success) {
+        transport_with_data.commitPosition();
+        var clientCallback = client._reqs[header.rseqid];
+        delete client._reqs[header.rseqid];
+        if (clientCallback) {
+          clientCallback(err, success);
+        }
+      };
+      /*jshint +W083 */
+      if (client['recv_' + header.fname]) {
+        client['recv_' + header.fname](proto, header.mtype, dummy_seqid);
+      } else {
+        delete client._reqs[dummy_seqid];
+        this.emit("error",
+          new thrift.TApplicationException(
+            thrift.TApplicationExceptionType.WRONG_METHOD_NAME,
+            "Received a response to an unknown RPC function"));
+      }
+    }
+  } catch (e) {
+    if (e instanceof InputBufferUnderrunError) {
+      transport_with_data.rollbackPosition();
+    } else {
+      throw e;
+    }
+  }
+};
+
+/**
+ * Returns true if the transport is open, XHR always returns true.
+ * @readonly
+ * @returns {boolean} Always True.
+ */
+XHRConnection.prototype.isOpen = function() {
+  return true;
+};
+
+/**
+ * Opens the transport connection, with XHR this is a nop.
+ */
+XHRConnection.prototype.open = function() {};
+
+/**
+ * Closes the transport connection, with XHR this is a nop.
+ */
+XHRConnection.prototype.close = function() {};
+
+/**
+ * Returns the specified number of characters from the response
+ * buffer.
+ * @param {number} len - The number of characters to return.
+ * @returns {string} Characters sent by the server.
+ */
+XHRConnection.prototype.read = function(len) {
+  var avail = this.wpos - this.rpos;
+
+  if (avail === 0) {
+    return '';
+  }
+
+  var give = len;
+
+  if (avail < len) {
+    give = avail;
+  }
+
+  var ret = this.read_buf.substr(this.rpos, give);
+  this.rpos += give;
+
+  //clear buf when complete?
+  return ret;
+};
+
+/**
+ * Returns the entire response buffer.
+ * @returns {string} Characters sent by the server.
+ */
+XHRConnection.prototype.readAll = function() {
+  return this.recv_buf;
+};
+
+/**
+ * Sets the send buffer to buf.
+ * @param {string} buf - The buffer to send.
+ */
+XHRConnection.prototype.write = function(buf) {
+  this.send_buf = buf;
+  this.flush();
+};
+
+/**
+ * Returns the send buffer.
+ * @readonly
+ * @returns {string} The send buffer.
+ */
+XHRConnection.prototype.getSendBuffer = function() {
+  return this.send_buf;
+};
+
+/**
+ * Creates a new TXHRTransport object, used by Thrift clients to connect
+ *    to Thrift HTTP based servers.
+ * @param {string} host - The host name or IP to connect to.
+ * @param {number} port - The TCP port to connect to.
+ * @param {XHRConnectOptions} options - The configuration options to use.
+ * @returns {XHRConnection} The connection object.
+ * @see {@link XHRConnectOptions}
+ */
+exports.createXHRConnection = function(host, port, options) {
+  return new XHRConnection(host, port, options);
+};
+
+exports.createXHRClient = createClient;
diff --git a/lib/nodejs/package.json b/lib/nodejs/package.json
deleted file mode 100755
index 78dc141..0000000
--- a/lib/nodejs/package.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
-  "name": "thrift",
-  "description": "node.js bindings for the Apache Thrift RPC system",
-  "homepage": "http://thrift.apache.org/",
-  "repository":
-    { "type" : "git",
-      "url" : "https://git-wip-us.apache.org/repos/asf/thrift.git"
-    },
-  "version": "0.9.1",
-  "author":
-    { "name": "Apache Thrift Developers",
-      "email": "dev@thrift.apache.org",
-      "url": "http://thrift.apache.org"
-    },
-  "licenses":
-    [ { "type": "Apache-2.0",
-        "url": "http://www.apache.org/licenses/LICENSE-2.0"
-      }
-    ],
-  "bugs":
-    { "mail": "dev@thrift.apache.org",
-      "url": "https://issues.apache.org/jira/browse/THRIFT"
-    },
-  "directories" : { "lib" : "./lib/thrift" },
-  "main": "./lib/thrift",
-  "engines": { "node": ">= 0.2.4" },
-  "dependencies": {
-    "node-int64": "~0.3.0",
-    "nodeunit": "~0.8.0"
-  }
-}
diff --git a/lib/nodejs/test/binary.test.js b/lib/nodejs/test/binary.test.js
index c7f6f72..187cd18 100644
--- a/lib/nodejs/test/binary.test.js
+++ b/lib/nodejs/test/binary.test.js
@@ -17,117 +17,198 @@
  * under the License.
  */
 
-var testCase = require('nodeunit').testCase;
-var binary = require('thrift/binary');
+const test = require("tape");
+const binary = require("thrift/binary");
 
-module.exports = testCase({
-  "Should read signed byte": function(test){
-    test.equal(1, binary.readByte([0x01]));
-    test.equal(-1, binary.readByte([0xFF]));
-    
-    test.equal(127, binary.readByte([0x7F]));
-    test.equal(-128, binary.readByte([0x80]));
-    test.done();
+const cases = {
+  "Should read signed byte": function(assert) {
+    assert.equal(1, binary.readByte(0x01));
+    assert.equal(-1, binary.readByte(0xff));
+
+    assert.equal(127, binary.readByte(0x7f));
+    assert.equal(-128, binary.readByte(0x80));
+    assert.end();
   },
-  "Should write byte": function(test){
-  	//Protocol simply writes to the buffer. Nothing to test.. yet.
-  	test.ok(true);
-  	test.done();
+  "Should write byte": function(assert) {
+    //Protocol simply writes to the buffer. Nothing to test.. yet.
+    assert.ok(true);
+    assert.end();
   },
-  "Should read I16": function(test) {
-    test.equal(0, binary.readI16([0x00, 0x00]));
-    test.equal(1, binary.readI16([0x00, 0x01]));
-    test.equal(-1, binary.readI16([0xff, 0xff]));
+  "Should read I16": function(assert) {
+    assert.equal(0, binary.readI16([0x00, 0x00]));
+    assert.equal(1, binary.readI16([0x00, 0x01]));
+    assert.equal(-1, binary.readI16([0xff, 0xff]));
 
     // Min I16
-    test.equal(-32768, binary.readI16([0x80, 0x00]));
+    assert.equal(-32768, binary.readI16([0x80, 0x00]));
     // Max I16
-    test.equal(32767, binary.readI16([0x7f, 0xff]));
-    test.done();
+    assert.equal(32767, binary.readI16([0x7f, 0xff]));
+    assert.end();
   },
 
-  "Should write I16": function(test) {
-    test.deepEqual([0x00, 0x00], binary.writeI16([], 0));
-    test.deepEqual([0x00, 0x01], binary.writeI16([], 1));
-    test.deepEqual([0xff, 0xff], binary.writeI16([], -1));
+  "Should write I16": function(assert) {
+    assert.deepEqual([0x00, 0x00], binary.writeI16([], 0));
+    assert.deepEqual([0x00, 0x01], binary.writeI16([], 1));
+    assert.deepEqual([0xff, 0xff], binary.writeI16([], -1));
 
     // Min I16
-    test.deepEqual([0x80, 0x00], binary.writeI16([], -32768));
+    assert.deepEqual([0x80, 0x00], binary.writeI16([], -32768));
     // Max I16
-    test.deepEqual([0x7f, 0xff], binary.writeI16([], 32767));
-    test.done();
+    assert.deepEqual([0x7f, 0xff], binary.writeI16([], 32767));
+    assert.end();
   },
 
-  "Should read I32": function(test) {
-    test.equal(0, binary.readI32([0x00, 0x00, 0x00, 0x00]));
-    test.equal(1, binary.readI32([0x00, 0x00, 0x00, 0x01]));
-    test.equal(-1, binary.readI32([0xff, 0xff, 0xff, 0xff]));
+  "Should read I32": function(assert) {
+    assert.equal(0, binary.readI32([0x00, 0x00, 0x00, 0x00]));
+    assert.equal(1, binary.readI32([0x00, 0x00, 0x00, 0x01]));
+    assert.equal(-1, binary.readI32([0xff, 0xff, 0xff, 0xff]));
 
     // Min I32
-    test.equal(-2147483648, binary.readI32([0x80, 0x00, 0x00, 0x00]));
+    assert.equal(-2147483648, binary.readI32([0x80, 0x00, 0x00, 0x00]));
     // Max I32
-    test.equal(2147483647, binary.readI32([0x7f, 0xff, 0xff, 0xff]));
-    test.done();
+    assert.equal(2147483647, binary.readI32([0x7f, 0xff, 0xff, 0xff]));
+    assert.end();
   },
 
-  "Should write I32": function(test) {
-    test.deepEqual([0x00, 0x00, 0x00, 0x00], binary.writeI32([], 0));
-    test.deepEqual([0x00, 0x00, 0x00, 0x01], binary.writeI32([], 1));
-    test.deepEqual([0xff, 0xff, 0xff, 0xff], binary.writeI32([], -1));
+  "Should write I32": function(assert) {
+    assert.deepEqual([0x00, 0x00, 0x00, 0x00], binary.writeI32([], 0));
+    assert.deepEqual([0x00, 0x00, 0x00, 0x01], binary.writeI32([], 1));
+    assert.deepEqual([0xff, 0xff, 0xff, 0xff], binary.writeI32([], -1));
 
     // Min I32
-    test.deepEqual([0x80, 0x00, 0x00, 0x00], binary.writeI32([], -2147483648));
+    assert.deepEqual(
+      [0x80, 0x00, 0x00, 0x00],
+      binary.writeI32([], -2147483648)
+    );
     // Max I32
-    test.deepEqual([0x7f, 0xff, 0xff, 0xff], binary.writeI32([], 2147483647));
- 	test.done();
+    assert.deepEqual([0x7f, 0xff, 0xff, 0xff], binary.writeI32([], 2147483647));
+    assert.end();
   },
 
-  "Should read doubles": function(test) {
-    test.equal(0, binary.readDouble([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))
-    test.equal(0, binary.readDouble([0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))
-    test.equal(1, binary.readDouble([0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))
-    test.equal(2, binary.readDouble([0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))
-    test.equal(-2, binary.readDouble([0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))
+  "Should read doubles": function(assert) {
+    assert.equal(
+      0,
+      binary.readDouble([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+    );
+    assert.equal(
+      0,
+      binary.readDouble([0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+    );
+    assert.equal(
+      1,
+      binary.readDouble([0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+    );
+    assert.equal(
+      2,
+      binary.readDouble([0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+    );
+    assert.equal(
+      -2,
+      binary.readDouble([0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+    );
 
-    test.equal(Math.PI, binary.readDouble([0x40, 0x9, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18]))
+    assert.equal(
+      Math.PI,
+      binary.readDouble([0x40, 0x9, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18])
+    );
 
-    test.equal(Infinity, binary.readDouble([0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))
-    test.equal(-Infinity, binary.readDouble([0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))
+    assert.equal(
+      Infinity,
+      binary.readDouble([0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+    );
+    assert.equal(
+      -Infinity,
+      binary.readDouble([0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+    );
 
-    test.ok(isNaN(binary.readDouble([0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])))
+    assert.ok(
+      isNaN(binary.readDouble([0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))
+    );
 
-    test.equal(1/3, binary.readDouble([0x3f, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55]))
+    assert.equal(
+      1 / 3,
+      binary.readDouble([0x3f, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55])
+    );
 
     // Min subnormal positive double
-    test.equal(4.9406564584124654e-324, binary.readDouble([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]))
+    assert.equal(
+      4.9406564584124654e-324,
+      binary.readDouble([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01])
+    );
     // Min normal positive double
-    test.equal(2.2250738585072014e-308, binary.readDouble([0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))
+    assert.equal(
+      2.2250738585072014e-308,
+      binary.readDouble([0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+    );
     // Max positive double
-    test.equal(1.7976931348623157e308, binary.readDouble([0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]))
-  	test.done();
+    assert.equal(
+      1.7976931348623157e308,
+      binary.readDouble([0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])
+    );
+    assert.end();
   },
 
-  "Should write doubles": function(test) {
-    test.deepEqual([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], 0));
-    test.deepEqual([0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], 1));
-    test.deepEqual([0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], 2));
-    test.deepEqual([0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], -2));
+  "Should write doubles": function(assert) {
+    assert.deepEqual(
+      [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
+      binary.writeDouble([], 0)
+    );
+    assert.deepEqual(
+      [0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
+      binary.writeDouble([], 1)
+    );
+    assert.deepEqual(
+      [0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
+      binary.writeDouble([], 2)
+    );
+    assert.deepEqual(
+      [0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
+      binary.writeDouble([], -2)
+    );
 
-    test.deepEqual([0x40, 0x9, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18], binary.writeDouble([], Math.PI));
+    assert.deepEqual(
+      [0x40, 0x9, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18],
+      binary.writeDouble([], Math.PI)
+    );
 
-    test.deepEqual([0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], Infinity));
-    test.deepEqual([0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], -Infinity));
+    assert.deepEqual(
+      [0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
+      binary.writeDouble([], Infinity)
+    );
+    assert.deepEqual(
+      [0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
+      binary.writeDouble([], -Infinity)
+    );
 
-    test.deepEqual([0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], NaN));
+    assert.deepEqual(
+      [0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
+      binary.writeDouble([], NaN)
+    );
 
-    test.deepEqual([0x3f, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55], binary.writeDouble([], 1/3));
+    assert.deepEqual(
+      [0x3f, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55],
+      binary.writeDouble([], 1 / 3)
+    );
 
     // Min subnormal positive double
-    test.deepEqual([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01], binary.writeDouble([], 4.9406564584124654e-324)); 
+    assert.deepEqual(
+      [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
+      binary.writeDouble([], 4.9406564584124654e-324)
+    );
     // Min normal positive double
-    test.deepEqual([0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], binary.writeDouble([], 2.2250738585072014e-308)); 
+    assert.deepEqual(
+      [0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
+      binary.writeDouble([], 2.2250738585072014e-308)
+    );
     // Max positive double
-    test.deepEqual([0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], binary.writeDouble([], 1.7976931348623157e308)); 
-  	test.done();
+    assert.deepEqual(
+      [0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
+      binary.writeDouble([], 1.7976931348623157e308)
+    );
+    assert.end();
   }
-});
\ No newline at end of file
+};
+
+Object.keys(cases).forEach(function(caseName) {
+  test(caseName, cases[caseName]);
+});
diff --git a/lib/nodejs/test/certificates.README b/lib/nodejs/test/certificates.README
new file mode 100644
index 0000000..06c507e
--- /dev/null
+++ b/lib/nodejs/test/certificates.README
@@ -0,0 +1,7 @@
+server.crt AND server.key ARE PROVIDED FOR TEST PURPOSE AND SHOULD *NEVER* BE USED IN PRODUCTION
+
+
+Origin of the test key and cert is the folder test/keys of Apache Thrift source code distribution
+
+We need copies for npm deployment
+
diff --git a/lib/nodejs/test/client.js b/lib/nodejs/test/client.js
new file mode 100644
index 0000000..49e3a5e
--- /dev/null
+++ b/lib/nodejs/test/client.js
@@ -0,0 +1,170 @@
+#!/usr/bin/env node
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const assert = require("assert");
+const thrift = require("thrift");
+const helpers = require("./helpers");
+
+const ThriftTest = require(`./${helpers.genPath}/ThriftTest`);
+const ThriftTestDriver = require("./test_driver").ThriftTestDriver;
+const ThriftTestDriverPromise = require("./test_driver")
+  .ThriftTestDriverPromise;
+const SecondService = require(`./${helpers.genPath}/SecondService`);
+
+const program = require("commander");
+
+program
+  .option(
+    "-p, --protocol <protocol>",
+    "Set thrift protocol (binary|compact|json) [protocol]"
+  )
+  .option(
+    "-t, --transport <transport>",
+    "Set thrift transport (buffered|framed|http) [transport]"
+  )
+  .option("--port <port>", "Set thrift server port number to connect", 9090)
+  .option("--host <host>", "Set thrift server host to connect", "localhost")
+  .option(
+    "--domain-socket <path>",
+    "Set thrift server unix domain socket to connect"
+  )
+  .option("--ssl", "use SSL transport")
+  .option("--callback", "test with callback style functions")
+  .option(
+    "-t, --type <type>",
+    "Select server type (http|multiplex|tcp|websocket)",
+    "tcp"
+  )
+  .option("--es6", "Use es6 code")
+  .option("--es5", "Use es5 code")
+  .parse(process.argv);
+
+const host = program.host;
+const port = program.port;
+const domainSocket = program.domainSocket;
+const ssl = program.ssl;
+let type = program.type;
+
+/* for compatibility with cross test invocation for http transport testing */
+if (program.transport === "http") {
+  program.transport = "buffered";
+  type = "http";
+}
+
+const options = {
+  transport: helpers.transports[program.transport],
+  protocol: helpers.protocols[program.protocol]
+};
+
+if (type === "http" || type === "websocket") {
+  options.path = "/test";
+}
+
+if (type === "http") {
+  options.headers = { Connection: "close" };
+}
+
+if (ssl) {
+  if (type === "tcp" || type === "multiplex") {
+    options.rejectUnauthorized = false;
+  } else if (type === "http") {
+    options.nodeOptions = { rejectUnauthorized: false };
+    options.https = true;
+  } else if (type === "websocket") {
+    options.wsOptions = { rejectUnauthorized: false };
+    options.secure = true;
+  }
+}
+
+let connection;
+let client;
+const testDriver = program.callback
+  ? ThriftTestDriver
+  : ThriftTestDriverPromise;
+if (helpers.ecmaMode === "es6" && program.callback) {
+  console.log("ES6 does not support callback style");
+  process.exit(0);
+}
+
+if (type === "tcp" || type === "multiplex") {
+  if (domainSocket) {
+    connection = thrift.createUDSConnection(domainSocket, options);
+  } else {
+    connection = ssl
+      ? thrift.createSSLConnection(host, port, options)
+      : thrift.createConnection(host, port, options);
+  }
+} else if (type === "http") {
+  if (domainSocket) {
+    connection = thrift.createHttpUDSConnection(domainSocket, options);
+  } else {
+    connection = thrift.createHttpConnection(host, port, options);
+  }
+} else if (type === "websocket") {
+  connection = thrift.createWSConnection(host, port, options);
+  connection.open();
+}
+
+connection.on("error", function(err) {
+  assert(false, err);
+});
+
+if (type === "tcp") {
+  client = thrift.createClient(ThriftTest, connection);
+  runTests();
+} else if (type === "multiplex") {
+  const mp = new thrift.Multiplexer();
+  client = mp.createClient("ThriftTest", ThriftTest, connection);
+  const secondclient = mp.createClient(
+    "SecondService",
+    SecondService,
+    connection
+  );
+
+  connection.on("connect", function() {
+    secondclient.secondtestString("Test", function(err, response) {
+      assert(!err);
+      assert.equal('testString("Test")', response);
+    });
+
+    runTests();
+  });
+} else if (type === "http") {
+  client = thrift.createHttpClient(ThriftTest, connection);
+  runTests();
+} else if (type === "websocket") {
+  client = thrift.createWSClient(ThriftTest, connection);
+  runTests();
+}
+
+function runTests() {
+  testDriver(client, function(status) {
+    console.log(status);
+    if (type !== "http" && type !== "websocket") {
+      connection.end();
+    }
+    if (type !== "multiplex") {
+      process.exit(0);
+    }
+  });
+}
+
+exports.expressoTest = function() {};
diff --git a/lib/nodejs/test/deep-constructor.test.js b/lib/nodejs/test/deep-constructor.test.js
new file mode 100644
index 0000000..504dacf
--- /dev/null
+++ b/lib/nodejs/test/deep-constructor.test.js
@@ -0,0 +1,333 @@
+/*
+ * 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.
+ */
+
+const ttypes = require("./gen-nodejs/JsDeepConstructorTest_types");
+const thrift = require("thrift");
+const test = require("tape");
+const bufferEquals = require("buffer-equals");
+
+function serializeBinary(data) {
+  let buff;
+  const transport = new thrift.TBufferedTransport(null, function(msg) {
+    buff = msg;
+  });
+  const prot = new thrift.TBinaryProtocol(transport);
+  data.write(prot);
+  prot.flush();
+  return buff;
+}
+
+function deserializeBinary(serialized, type) {
+  const t = new thrift.TFramedTransport(serialized);
+  const p = new thrift.TBinaryProtocol(t);
+  const data = new type();
+  data.read(p);
+  return data;
+}
+
+function serializeJSON(data) {
+  let buff;
+  const transport = new thrift.TBufferedTransport(null, function(msg) {
+    buff = msg;
+  });
+  const protocol = new thrift.TJSONProtocol(transport);
+  protocol.writeMessageBegin("", 0, 0);
+  data.write(protocol);
+  protocol.writeMessageEnd();
+  protocol.flush();
+  return buff;
+}
+
+function deserializeJSON(serialized, type) {
+  const transport = new thrift.TFramedTransport(serialized);
+  const protocol = new thrift.TJSONProtocol(transport);
+  protocol.readMessageBegin();
+  const data = new type();
+  data.read(protocol);
+  protocol.readMessageEnd();
+  return data;
+}
+
+function createThriftObj() {
+  return new ttypes.Complex({
+    struct_field: new ttypes.Simple({ value: "a" }),
+
+    struct_list_field: [
+      new ttypes.Simple({ value: "b" }),
+      new ttypes.Simple({ value: "c" })
+    ],
+
+    struct_set_field: [
+      new ttypes.Simple({ value: "d" }),
+      new ttypes.Simple({ value: "e" })
+    ],
+
+    struct_map_field: {
+      A: new ttypes.Simple({ value: "f" }),
+      B: new ttypes.Simple({ value: "g" })
+    },
+
+    struct_nested_containers_field: [
+      [
+        {
+          C: [
+            new ttypes.Simple({ value: "h" }),
+            new ttypes.Simple({ value: "i" })
+          ]
+        }
+      ]
+    ],
+
+    struct_nested_containers_field2: {
+      D: [
+        {
+          DA: new ttypes.Simple({ value: "j" })
+        },
+        {
+          DB: new ttypes.Simple({ value: "k" })
+        }
+      ]
+    },
+
+    list_of_list_field: [
+      ["l00", "l01", "l02"],
+      ["l10", "l11", "l12"],
+      ["l20", "l21", "l22"]
+    ],
+
+    list_of_list_of_list_field: [
+      [
+        ["m000", "m001", "m002"],
+        ["m010", "m011", "m012"],
+        ["m020", "m021", "m022"]
+      ],
+      [
+        ["m100", "m101", "m102"],
+        ["m110", "m111", "m112"],
+        ["m120", "m121", "m122"]
+      ],
+      [
+        ["m200", "m201", "m202"],
+        ["m210", "m211", "m212"],
+        ["m220", "m221", "m222"]
+      ]
+    ]
+  });
+}
+
+function createJsObj() {
+  return {
+    struct_field: { value: "a" },
+
+    struct_list_field: [{ value: "b" }, { value: "c" }],
+
+    struct_set_field: [{ value: "d" }, { value: "e" }],
+
+    struct_map_field: {
+      A: { value: "f" },
+      B: { value: "g" }
+    },
+
+    struct_nested_containers_field: [
+      [
+        {
+          C: [{ value: "h" }, { value: "i" }]
+        }
+      ]
+    ],
+
+    struct_nested_containers_field2: {
+      D: [
+        {
+          DA: { value: "j" }
+        },
+        {
+          DB: { value: "k" }
+        }
+      ]
+    },
+
+    list_of_list_field: [
+      ["l00", "l01", "l02"],
+      ["l10", "l11", "l12"],
+      ["l20", "l21", "l22"]
+    ],
+
+    list_of_list_of_list_field: [
+      [
+        ["m000", "m001", "m002"],
+        ["m010", "m011", "m012"],
+        ["m020", "m021", "m022"]
+      ],
+      [
+        ["m100", "m101", "m102"],
+        ["m110", "m111", "m112"],
+        ["m120", "m121", "m122"]
+      ],
+      [
+        ["m200", "m201", "m202"],
+        ["m210", "m211", "m212"],
+        ["m220", "m221", "m222"]
+      ]
+    ]
+  };
+}
+
+function assertValues(obj, assert) {
+  assert.equals(obj.struct_field.value, "a");
+  assert.equals(obj.struct_list_field[0].value, "b");
+  assert.equals(obj.struct_list_field[1].value, "c");
+  assert.equals(obj.struct_set_field[0].value, "d");
+  assert.equals(obj.struct_set_field[1].value, "e");
+  assert.equals(obj.struct_map_field.A.value, "f");
+  assert.equals(obj.struct_map_field.B.value, "g");
+  assert.equals(obj.struct_nested_containers_field[0][0].C[0].value, "h");
+  assert.equals(obj.struct_nested_containers_field[0][0].C[1].value, "i");
+  assert.equals(obj.struct_nested_containers_field2.D[0].DA.value, "j");
+  assert.equals(obj.struct_nested_containers_field2.D[1].DB.value, "k");
+  assert.equals(obj.list_of_list_field[0][0], "l00");
+  assert.equals(obj.list_of_list_field[0][1], "l01");
+  assert.equals(obj.list_of_list_field[0][2], "l02");
+  assert.equals(obj.list_of_list_field[1][0], "l10");
+  assert.equals(obj.list_of_list_field[1][1], "l11");
+  assert.equals(obj.list_of_list_field[1][2], "l12");
+  assert.equals(obj.list_of_list_field[2][0], "l20");
+  assert.equals(obj.list_of_list_field[2][1], "l21");
+  assert.equals(obj.list_of_list_field[2][2], "l22");
+
+  assert.equals(obj.list_of_list_of_list_field[0][0][0], "m000");
+  assert.equals(obj.list_of_list_of_list_field[0][0][1], "m001");
+  assert.equals(obj.list_of_list_of_list_field[0][0][2], "m002");
+  assert.equals(obj.list_of_list_of_list_field[0][1][0], "m010");
+  assert.equals(obj.list_of_list_of_list_field[0][1][1], "m011");
+  assert.equals(obj.list_of_list_of_list_field[0][1][2], "m012");
+  assert.equals(obj.list_of_list_of_list_field[0][2][0], "m020");
+  assert.equals(obj.list_of_list_of_list_field[0][2][1], "m021");
+  assert.equals(obj.list_of_list_of_list_field[0][2][2], "m022");
+
+  assert.equals(obj.list_of_list_of_list_field[1][0][0], "m100");
+  assert.equals(obj.list_of_list_of_list_field[1][0][1], "m101");
+  assert.equals(obj.list_of_list_of_list_field[1][0][2], "m102");
+  assert.equals(obj.list_of_list_of_list_field[1][1][0], "m110");
+  assert.equals(obj.list_of_list_of_list_field[1][1][1], "m111");
+  assert.equals(obj.list_of_list_of_list_field[1][1][2], "m112");
+  assert.equals(obj.list_of_list_of_list_field[1][2][0], "m120");
+  assert.equals(obj.list_of_list_of_list_field[1][2][1], "m121");
+  assert.equals(obj.list_of_list_of_list_field[1][2][2], "m122");
+
+  assert.equals(obj.list_of_list_of_list_field[2][0][0], "m200");
+  assert.equals(obj.list_of_list_of_list_field[2][0][1], "m201");
+  assert.equals(obj.list_of_list_of_list_field[2][0][2], "m202");
+  assert.equals(obj.list_of_list_of_list_field[2][1][0], "m210");
+  assert.equals(obj.list_of_list_of_list_field[2][1][1], "m211");
+  assert.equals(obj.list_of_list_of_list_field[2][1][2], "m212");
+  assert.equals(obj.list_of_list_of_list_field[2][2][0], "m220");
+  assert.equals(obj.list_of_list_of_list_field[2][2][1], "m221");
+  assert.equals(obj.list_of_list_of_list_field[2][2][2], "m222");
+}
+
+function createTestCases(serialize, deserialize) {
+  const cases = {
+    "Serialize/deserialize should return equal object": function(assert) {
+      const tObj = createThriftObj();
+      const received = deserialize(serialize(tObj), ttypes.Complex);
+      assert.ok(tObj !== received, "not the same object");
+      assert.deepEqual(tObj, received);
+      assert.end();
+    },
+
+    "Nested structs and containers initialized from plain js objects should serialize same as if initialized from thrift objects": function(
+      assert
+    ) {
+      const tObj1 = createThriftObj();
+      const tObj2 = new ttypes.Complex(createJsObj());
+      assertValues(tObj2, assert);
+      const s1 = serialize(tObj1);
+      const s2 = serialize(tObj2);
+      assert.ok(bufferEquals(s1, s2));
+      assert.end();
+    },
+
+    "Modifications to args object should not affect constructed Thrift object": function(
+      assert
+    ) {
+      const args = createJsObj();
+      assertValues(args, assert);
+
+      const tObj = new ttypes.Complex(args);
+      assertValues(tObj, assert);
+
+      args.struct_field.value = "ZZZ";
+      args.struct_list_field[0].value = "ZZZ";
+      args.struct_list_field[1].value = "ZZZ";
+      args.struct_set_field[0].value = "ZZZ";
+      args.struct_set_field[1].value = "ZZZ";
+      args.struct_map_field.A.value = "ZZZ";
+      args.struct_map_field.B.value = "ZZZ";
+      args.struct_nested_containers_field[0][0].C[0] = "ZZZ";
+      args.struct_nested_containers_field[0][0].C[1] = "ZZZ";
+      args.struct_nested_containers_field2.D[0].DA = "ZZZ";
+      args.struct_nested_containers_field2.D[0].DB = "ZZZ";
+
+      assertValues(tObj, assert);
+      assert.end();
+    },
+
+    "nulls are ok": function(assert) {
+      const tObj = new ttypes.Complex({
+        struct_field: null,
+        struct_list_field: null,
+        struct_set_field: null,
+        struct_map_field: null,
+        struct_nested_containers_field: null,
+        struct_nested_containers_field2: null
+      });
+      const received = deserialize(serialize(tObj), ttypes.Complex);
+      assert.strictEqual(tObj.struct_field, null);
+      assert.ok(tObj !== received);
+      assert.deepEqual(tObj, received);
+      assert.end();
+    },
+
+    "Can make list with objects": function(assert) {
+      const tObj = new ttypes.ComplexList({
+        struct_list_field: [new ttypes.Complex({})]
+      });
+      const innerObj = tObj.struct_list_field[0];
+      assert.ok(innerObj instanceof ttypes.Complex);
+      assert.strictEqual(innerObj.struct_field, null);
+      assert.strictEqual(innerObj.struct_list_field, null);
+      assert.strictEqual(innerObj.struct_set_field, null);
+      assert.strictEqual(innerObj.struct_map_field, null);
+      assert.strictEqual(innerObj.struct_nested_containers_field, null);
+      assert.strictEqual(innerObj.struct_nested_containers_field2, null);
+      assert.end();
+    }
+  };
+  return cases;
+}
+
+function run(name, cases) {
+  Object.keys(cases).forEach(function(caseName) {
+    test(name + ": " + caseName, cases[caseName]);
+  });
+}
+
+run("binary", createTestCases(serializeBinary, deserializeBinary));
+run("json", createTestCases(serializeJSON, deserializeJSON));
diff --git a/lib/nodejs/test/exceptions.js b/lib/nodejs/test/exceptions.js
new file mode 100644
index 0000000..ab2798a
--- /dev/null
+++ b/lib/nodejs/test/exceptions.js
@@ -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.
+ */
+
+"use strict";
+const test = require("tape");
+const thrift = require("../lib/thrift/thrift.js");
+const InputBufferUnderrunError = require("../lib/thrift/input_buffer_underrun_error");
+
+test("TApplicationException", function t(assert) {
+  const e = new thrift.TApplicationException(1, "foo");
+  assert.ok(
+    e instanceof thrift.TApplicationException,
+    "is instanceof TApplicationException"
+  );
+  assert.ok(e instanceof thrift.TException, "is instanceof TException");
+  assert.ok(e instanceof Error, "is instanceof Error");
+  assert.equal(typeof e.stack, "string", "has stack trace");
+  assert.ok(
+    /^TApplicationException: foo/.test(e.stack),
+    "Stack trace has correct error name and message"
+  );
+  assert.ok(
+    e.stack.indexOf("test/exceptions.js:7:11") !== -1,
+    "stack trace starts on correct line and column"
+  );
+  assert.equal(
+    e.name,
+    "TApplicationException",
+    "has function name TApplicationException"
+  );
+  assert.equal(e.message, "foo", 'has error message "foo"');
+  assert.equal(e.type, 1, "has type 1");
+  assert.end();
+});
+
+test("unexpected TApplicationException ", function t(assert) {
+  const e = new thrift.TApplicationException(1, 100);
+  assert.ok(
+    e instanceof thrift.TApplicationException,
+    "is instanceof TApplicationException"
+  );
+  assert.ok(e instanceof thrift.TException, "is instanceof TException");
+  assert.ok(e instanceof Error, "is instanceof Error");
+  assert.equal(typeof e.stack, "string", "has stack trace");
+  assert.ok(
+    /^TApplicationException: 100/.test(e.stack),
+    "Stack trace has correct error name and message"
+  );
+  assert.ok(
+    e.stack.indexOf("test/exceptions.js:7:11") !== -1,
+    "stack trace starts on correct line and column"
+  );
+  assert.equal(
+    e.name,
+    "TApplicationException",
+    "has function name TApplicationException"
+  );
+  assert.equal(e.message, 100, "has error message 100");
+  assert.equal(e.type, 1, "has type 1");
+  assert.end();
+});
+
+test("TException", function t(assert) {
+  const e = new thrift.TException("foo");
+  assert.ok(e instanceof thrift.TException, "is instanceof TException");
+  assert.ok(e instanceof Error, "is instanceof Error");
+  assert.equal(typeof e.stack, "string", "has stack trace");
+  assert.ok(
+    /^TException: foo/.test(e.stack),
+    "Stack trace has correct error name and message"
+  );
+  assert.ok(
+    e.stack.indexOf("test/exceptions.js:21:11") !== -1,
+    "stack trace starts on correct line and column"
+  );
+  assert.equal(e.name, "TException", "has function name TException");
+  assert.equal(e.message, "foo", 'has error message "foo"');
+  assert.end();
+});
+
+test("TProtocolException", function t(assert) {
+  const e = new thrift.TProtocolException(1, "foo");
+  assert.ok(
+    e instanceof thrift.TProtocolException,
+    "is instanceof TProtocolException"
+  );
+  assert.ok(e instanceof Error, "is instanceof Error");
+  assert.equal(typeof e.stack, "string", "has stack trace");
+  assert.ok(
+    /^TProtocolException: foo/.test(e.stack),
+    "Stack trace has correct error name and message"
+  );
+  assert.ok(
+    e.stack.indexOf("test/exceptions.js:33:11") !== -1,
+    "stack trace starts on correct line and column"
+  );
+  assert.equal(
+    e.name,
+    "TProtocolException",
+    "has function name TProtocolException"
+  );
+  assert.equal(e.message, "foo", 'has error message "foo"');
+  assert.equal(e.type, 1, "has type 1");
+  assert.end();
+});
+
+test("InputBufferUnderrunError", function t(assert) {
+  const e = new InputBufferUnderrunError("foo");
+  assert.ok(
+    e instanceof InputBufferUnderrunError,
+    "is instanceof InputBufferUnderrunError"
+  );
+  assert.ok(e instanceof Error, "is instanceof Error");
+  assert.equal(typeof e.stack, "string", "has stack trace");
+  assert.ok(
+    /^InputBufferUnderrunError: foo/.test(e.stack),
+    "Stack trace has correct error name and message"
+  );
+  assert.ok(
+    e.stack.indexOf("test/exceptions.js:46:11") !== -1,
+    "stack trace starts on correct line and column"
+  );
+  assert.equal(
+    e.name,
+    "InputBufferUnderrunError",
+    "has function name InputBufferUnderrunError"
+  );
+  assert.equal(e.message, "foo", 'has error message "foo"');
+  assert.end();
+});
diff --git a/lib/nodejs/test/helpers.js b/lib/nodejs/test/helpers.js
new file mode 100644
index 0000000..72d128d
--- /dev/null
+++ b/lib/nodejs/test/helpers.js
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+"use strict";
+const thrift = require("../lib/thrift");
+
+module.exports.transports = {
+  buffered: thrift.TBufferedTransport,
+  framed: thrift.TFramedTransport
+};
+
+module.exports.protocols = {
+  json: thrift.TJSONProtocol,
+  binary: thrift.TBinaryProtocol,
+  compact: thrift.TCompactProtocol
+};
+
+module.exports.ecmaMode = process.argv.includes("--es6") ? "es6" : "es5";
+module.exports.genPath = process.argv.includes("--es6")
+  ? "gen-nodejs-es6"
+  : "gen-nodejs";
diff --git a/lib/nodejs/test/server.crt b/lib/nodejs/test/server.crt
new file mode 100644
index 0000000..8a5ef3c
--- /dev/null
+++ b/lib/nodejs/test/server.crt
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD
+VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs
+MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV
+BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3
+DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy
+MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU
+MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh
+cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ
+bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ
+GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6
+L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg
+2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw
+AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX
+wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n
+AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME
+GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
+DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5
+U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm
+T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD
+1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I
+p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO
+r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0
+-----END CERTIFICATE-----
diff --git a/lib/nodejs/test/server.js b/lib/nodejs/test/server.js
new file mode 100644
index 0000000..7402094
--- /dev/null
+++ b/lib/nodejs/test/server.js
@@ -0,0 +1,137 @@
+#!/usr/bin/env node
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * 'License'); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const fs = require("fs");
+const path = require("path");
+const thrift = require("../lib/thrift");
+const program = require("commander");
+const helpers = require("./helpers");
+
+program
+  .option(
+    "-p, --protocol <protocol>",
+    "Set thrift protocol (binary|compact|json)",
+    "binary"
+  )
+  .option(
+    "-t, --transport <transport>",
+    "Set thrift transport (buffered|framed|http)",
+    "buffered"
+  )
+  .option("--ssl", "use ssl transport")
+  .option("--port <port>", "Set thrift server port", 9090)
+  .option("--domain-socket <path>", "Set thift server unix domain socket")
+  .option(
+    "-t, --type <type>",
+    "Select server type (http|multiplex|tcp|websocket)",
+    "tcp"
+  )
+  .option("--callback", "test with callback style functions")
+  .option("--es6", "Use es6 code")
+  .option("--es5", "Use es5 code")
+  .parse(process.argv);
+
+const ThriftTest = require(`./${helpers.genPath}/ThriftTest`);
+const SecondService = require(`./${helpers.genPath}/SecondService`);
+const { ThriftTestHandler } = require("./test_handler");
+
+const port = program.port;
+const domainSocket = program.domainSocket;
+const ssl = program.ssl;
+
+let type = program.type;
+if (program.transport === "http") {
+  program.transport = "buffered";
+  type = "http";
+}
+
+let options = {
+  transport: helpers.transports[program.transport],
+  protocol: helpers.protocols[program.protocol]
+};
+
+if (type === "http" || type === "websocket") {
+  options.handler = ThriftTestHandler;
+  options.processor = ThriftTest;
+
+  options = {
+    services: { "/test": options },
+    cors: {
+      "*": true
+    }
+  };
+}
+
+let processor;
+if (type === "multiplex") {
+  const SecondServiceHandler = {
+    secondtestString: function(thing, result) {
+      console.log('testString("' + thing + '")');
+      result(null, 'testString("' + thing + '")');
+    }
+  };
+
+  processor = new thrift.MultiplexedProcessor();
+
+  processor.registerProcessor(
+    "ThriftTest",
+    new ThriftTest.Processor(ThriftTestHandler)
+  );
+
+  processor.registerProcessor(
+    "SecondService",
+    new SecondService.Processor(SecondServiceHandler)
+  );
+}
+
+if (ssl) {
+  if (
+    type === "tcp" ||
+    type === "multiplex" ||
+    type === "http" ||
+    type === "websocket"
+  ) {
+    options.tls = {
+      key: fs.readFileSync(path.resolve(__dirname, "server.key")),
+      cert: fs.readFileSync(path.resolve(__dirname, "server.crt"))
+    };
+  }
+}
+
+let server;
+if (type === "tcp") {
+  server = thrift.createServer(ThriftTest, ThriftTestHandler, options);
+} else if (type === "multiplex") {
+  server = thrift.createMultiplexServer(processor, options);
+} else if (type === "http" || type === "websocket") {
+  server = thrift.createWebServer(options);
+}
+
+if (domainSocket) {
+  server.listen(domainSocket);
+} else if (
+  type === "tcp" ||
+  type === "multiplex" ||
+  type === "http" ||
+  type === "websocket"
+) {
+  server.listen(port);
+}
diff --git a/lib/nodejs/test/server.key b/lib/nodejs/test/server.key
new file mode 100644
index 0000000..263cfce
--- /dev/null
+++ b/lib/nodejs/test/server.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR
+tLQVDSGQGV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCy
+SN8I2Xw6L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/H
+jKNg6ZKg2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQB
+GmZmMIUwAinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xk
+u62LipkXwCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDm
+trhVQF4nAgMBAAECggEAW/y52YYW6ypROGbZ94DQpFV0kLO7qT8q0Ksxw5sPNaIt
+fEPRIymDa8ikyHWJS5Oxmw84wo5jnJV26jaLmwe2Lupq7Xf1lqej8f5LJtuv7cQR
+xfzp1vM65KJFFJHp6WqjGqJ6HSSZOpVDsnQYcXQjQCdpyAmaSWd3p+FqYSZ1mQmD
+bFNI7jqpczWSZhTdotQ7p7Hn9TVCehflP3yGIB3bQ+wCcCB85dOBz201L+YgaIck
+Sz43A4NvWaQIRLRDw7s9GW4jY5T0Jv282WIeAlVpVxLIwu48r4R4yGTIx9Ydowvq
+57+Y5iPPjAXxu0V9t00oS3bYxDaKh2DUfc/5zowq8QKBgQDYNVPXmaG0aIH4vjQ9
+7fRdw/UDkYcQbn6CnglQOu77/S8ogQzpKCVJgJgkZNqOVtQMEPzekGEcLTbje1gU
+8Bky2k+PL9UwbFy0emnOVh4rqrNXHsRvJcehNT/PRb5hjF3MUMFV/0iD4b+naFaE
+jrSWiZ2ZXj2qfwAK52GFbtOuBQKBgQDJYQuGiY0r22E4waJmCSKczoBT3cwlVzWj
+V2ljgA9RHLNTVkvNNYQLGu2qngFrtwpeaSnsMDerVG4wKAQWyCnYzxVrlnC4uDrJ
+HXuFEltBWi9Ffbgfsnd3749AT0oBP1NT2tMleguyf5DFgjCR3VRJLdrVaaZ8row/
+LqKcFMqnOwKBgB+OIO99l7E584Y3VG6ZdSneOLtNmRXX2pT7tcZE465ZdHGH7Dd3
+SYHhx9K/+Xn+yDH+pLli/xlarAEldmSP6k2WuTfftlC78AfTOfAId5zN7CDR9791
+Fx67I9X/itq33tS8EIuZl57P6uXm/4GXRloWOa8xpvRkVsBApuYPl8t1AoGATQDS
+y2sllDObBXzlgGbV2WgNIgSZ311toTv3jJiXQsjauW8yJRHln+l4H9mzaWDgkiFc
+ang1kUoDqF5k0eFQPxtQcYdhKwEnWWfwp33RbzfxA32DPnubuzzbZhfrkHaKgnIW
+cyor9uFYlm2l7ODZLfJez2RKyTplXnOSsmQw6akCgYAz3dj9Hskyj+HVJ+ht1OcE
+c7ai/ESkSA7Vajp0tjJp0EKjW/zq8DvUSXOtcdnJgkKycFluLwbmnaN4txBds1C1
+Qr8Rt2sUCCBNZe1L6DHe3XBdbkJe9sgZVNTjtUSQrzy8UhvsCqG4YWeCu07Szcbc
+rdPUV9/uQkdx8VrShxlD8A==
+-----END PRIVATE KEY-----
diff --git a/lib/nodejs/test/test-cases.js b/lib/nodejs/test/test-cases.js
new file mode 100644
index 0000000..02c566f
--- /dev/null
+++ b/lib/nodejs/test/test-cases.js
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+"use strict";
+
+const helpers = require("./helpers");
+const ttypes = require(`./${helpers.genPath}/ThriftTest_types`);
+const Int64 = require("node-int64");
+
+//all Languages in UTF-8
+/*jshint -W100 */
+const stringTest = (module.exports.stringTest =
+  "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " +
+  "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " +
+  "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, " +
+  "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, " +
+  "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, " +
+  "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, " +
+  "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, " +
+  "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, " +
+  "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, " +
+  "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, " +
+  "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, " +
+  "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, " +
+  "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, " +
+  "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa " +
+  "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa " +
+  "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪" +
+  "Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, " +
+  "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, " +
+  "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, " +
+  "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple " +
+  "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, " +
+  "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, " +
+  "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, " +
+  "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, " +
+  "Bân-lâm-gú, 粵語");
+/*jshint +W100 */
+
+const specialCharacters = (module.exports.specialCharacters =
+  'quote: " backslash:' +
+  " forwardslash-escaped: / " +
+  " backspace: \b formfeed: \f newline: \n return: \r tab: " +
+  ' now-all-of-them-together: "\\/\b\n\r\t' +
+  " now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><" +
+  ' char-to-test-json-parsing: ]] "]] \\" }}}{ [[[ ');
+
+const mapTestInput = (module.exports.mapTestInput = {
+  a: "123",
+  "a b": "with spaces ",
+  same: "same",
+  "0": "numeric key",
+  longValue: stringTest,
+  stringTest: "long key"
+});
+
+const simple = [
+  ["testVoid", undefined],
+  ["testString", "Test"],
+  ["testString", ""],
+  ["testString", stringTest],
+  ["testString", specialCharacters],
+  ["testBool", true],
+  ["testBool", false],
+  ["testByte", 1],
+  ["testByte", 0],
+  ["testByte", -1],
+  ["testByte", -127],
+  ["testI32", -1],
+  ["testDouble", -5.2098523],
+  ["testDouble", 7.012052175215044],
+  ["testEnum", ttypes.Numberz.ONE],
+  ["testI64", 5],
+  ["testI64", -5],
+  ["testI64", 734359738368],
+  ["testI64", -734359738368],
+  ["testI64", new Int64(new Buffer([0, 0x20, 0, 0, 0, 0, 0, 1]))], // 2^53+1
+  [
+    "testI64",
+    new Int64(new Buffer([0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]))
+  ], // -2^53-1
+  ["testTypedef", 69]
+];
+
+const mapout = {};
+for (let i = 0; i < 5; ++i) {
+  mapout[i] = i - 10;
+}
+
+const deep = [
+  [
+    "testList",
+    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
+  ]
+];
+
+const deepUnordered = [
+  ["testMap", mapout],
+  ["testSet", [1, 2, 3]],
+  ["testStringMap", mapTestInput]
+];
+
+const out = new ttypes.Xtruct({
+  string_thing: "Zero",
+  byte_thing: 1,
+  i32_thing: -3,
+  i64_thing: 1000000
+});
+
+const out2 = new ttypes.Xtruct2();
+out2.byte_thing = 1;
+out2.struct_thing = out;
+out2.i32_thing = 5;
+
+const crazy = new ttypes.Insanity({
+  userMap: { "5": 5, "8": 8 },
+  xtructs: [
+    new ttypes.Xtruct({
+      string_thing: "Goodbye4",
+      byte_thing: 4,
+      i32_thing: 4,
+      i64_thing: 4
+    }),
+    new ttypes.Xtruct({
+      string_thing: "Hello2",
+      byte_thing: 2,
+      i32_thing: 2,
+      i64_thing: 2
+    })
+  ]
+});
+
+const crazy2 = new ttypes.Insanity({
+  userMap: { "5": 5, "8": 8 },
+  xtructs: [
+    {
+      string_thing: "Goodbye4",
+      byte_thing: 4,
+      i32_thing: 4,
+      i64_thing: 4
+    },
+    {
+      string_thing: "Hello2",
+      byte_thing: 2,
+      i32_thing: 2,
+      i64_thing: 2
+    }
+  ]
+});
+
+const insanity = {
+  "1": { "2": crazy, "3": crazy },
+  "2": { "6": { userMap: {}, xtructs: [] } }
+};
+
+module.exports.simple = simple;
+module.exports.deep = deep;
+module.exports.deepUnordered = deepUnordered;
+
+module.exports.out = out;
+module.exports.out2 = out2;
+module.exports.crazy = crazy;
+module.exports.crazy2 = crazy2;
+module.exports.insanity = insanity;
diff --git a/lib/nodejs/test/testAll.sh b/lib/nodejs/test/testAll.sh
new file mode 100755
index 0000000..24f1f2e
--- /dev/null
+++ b/lib/nodejs/test/testAll.sh
@@ -0,0 +1,98 @@
+#! /bin/sh
+
+# 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.
+
+if [ -n "${1}" ]; then
+  COVER=${1};
+fi
+
+DIR="$( cd "$( dirname "$0" )" && pwd )"
+
+ISTANBUL="$DIR/../../../node_modules/istanbul/lib/cli.js"
+
+REPORT_PREFIX="${DIR}/../coverage/report"
+
+COUNT=0
+
+export NODE_PATH="${DIR}:${DIR}/../lib:${NODE_PATH}"
+
+testServer()
+{
+  echo "  [ECMA $1] Testing $2 Client/Server with protocol $3 and transport $4 $5";
+  RET=0
+  if [ -n "${COVER}" ]; then
+    ${ISTANBUL} cover ${DIR}/server.js --dir ${REPORT_PREFIX}${COUNT} --handle-sigint -- --type $2 -p $3 -t $4 $5 &
+    COUNT=$((COUNT+1))
+  else
+    node ${DIR}/server.js --${1} --type $2 -p $3 -t $4 $5 &
+  fi
+  SERVERPID=$!
+  sleep 0.1
+  if [ -n "${COVER}" ]; then
+    ${ISTANBUL} cover ${DIR}/client.js --dir ${REPORT_PREFIX}${COUNT} -- --${1} --type $2 -p $3 -t $4 $5 || RET=1
+    COUNT=$((COUNT+1))
+  else
+    node ${DIR}/client.js --${1} --type $2 -p $3 -t $4 $5 || RET=1
+  fi
+  kill -2 $SERVERPID || RET=1
+  wait $SERVERPID
+  return $RET
+}
+
+
+TESTOK=0
+
+#generating thrift code
+
+${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node ${DIR}/../../../test/ThriftTest.thrift
+${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node ${DIR}/../../../test/JsDeepConstructorTest.thrift
+mkdir ${DIR}/gen-nodejs-es6
+${DIR}/../../../compiler/cpp/thrift -out ${DIR}/gen-nodejs-es6 --gen js:node,es6 ${DIR}/../../../test/ThriftTest.thrift
+${DIR}/../../../compiler/cpp/thrift -out ${DIR}/gen-nodejs-es6 --gen js:node,es6 ${DIR}/../../../test/JsDeepConstructorTest.thrift
+
+#unit tests
+
+node ${DIR}/binary.test.js || TESTOK=1
+node ${DIR}/deep-constructor.test.js || TESTOK=1
+
+#integration tests
+
+for type in tcp multiplex websocket http
+do
+  for protocol in compact binary json
+  do
+    for transport in buffered framed
+    do
+      for ecma_version in es5 es6
+      do
+        testServer $ecma_version $type $protocol $transport || TESTOK=1
+        testServer $ecma_version $type $protocol $transport --ssl || TESTOK=1
+        testServer $ecma_version $type $protocol $transport --callback || TESTOK=1
+      done
+    done
+  done
+done
+
+
+if [ -n "${COVER}" ]; then
+  ${ISTANBUL} report --dir "${DIR}/../coverage" --include "${DIR}/../coverage/report*/coverage.json" lcov cobertura html
+  rm -r ${DIR}/../coverage/report*/*
+  rmdir ${DIR}/../coverage/report*
+fi
+
+exit $TESTOK
diff --git a/lib/nodejs/test/test_driver.js b/lib/nodejs/test/test_driver.js
new file mode 100644
index 0000000..7c9a919
--- /dev/null
+++ b/lib/nodejs/test/test_driver.js
@@ -0,0 +1,361 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * 'License'); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// This is the Node.js test driver for the standard Apache Thrift
+// test service. The driver invokes every function defined in the
+// Thrift Test service with a representative range of parameters.
+//
+// The ThriftTestDriver function requires a client object
+// connected to a server hosting the Thrift Test service and
+// supports an optional callback function which is called with
+// a status message when the test is complete.
+
+const test = require("tape");
+
+const helpers = require("./helpers");
+const ttypes = require(`./${helpers.genPath}/ThriftTest_types`);
+const TException = require("thrift").Thrift.TException;
+const Int64 = require("node-int64");
+const testCases = require("./test-cases");
+
+exports.ThriftTestDriver = function(client, callback) {
+  test(
+    "NodeJS Style Callback Client Tests",
+    { skip: helpers.ecmaMode === "es6" },
+    function(assert) {
+      const checkRecursively = makeRecursiveCheck(assert);
+
+      function makeAsserter(assertionFn) {
+        return function(c) {
+          const fnName = c[0];
+          const expected = c[1];
+          client[fnName](expected, function(err, actual) {
+            assert.error(err, fnName + ": no callback error");
+            assertionFn(actual, expected, fnName);
+          });
+        };
+      }
+
+      testCases.simple.forEach(
+        makeAsserter(function(a, e, m) {
+          if (a instanceof Int64) {
+            const e64 = e instanceof Int64 ? e : new Int64(e);
+            assert.deepEqual(a.buffer, e64.buffer, m);
+          } else {
+            assert.equal(a, e, m);
+          }
+        })
+      );
+      testCases.deep.forEach(makeAsserter(assert.deepEqual));
+      testCases.deepUnordered.forEach(
+        makeAsserter(makeUnorderedDeepEqual(assert))
+      );
+
+      const arr = [];
+      for (let i = 0; i < 256; ++i) {
+        arr[i] = 255 - i;
+      }
+      let buf = new Buffer(arr);
+      client.testBinary(buf, function(err, response) {
+        assert.error(err, "testBinary: no callback error");
+        assert.equal(response.length, 256, "testBinary");
+        assert.deepEqual(response, buf, "testBinary(Buffer)");
+      });
+      buf = new Buffer(arr);
+      client.testBinary(buf.toString("binary"), function(err, response) {
+        assert.error(err, "testBinary: no callback error");
+        assert.equal(response.length, 256, "testBinary");
+        assert.deepEqual(response, buf, "testBinary(string)");
+      });
+
+      client.testMapMap(42, function(err, response) {
+        const expected = {
+          "4": { "1": 1, "2": 2, "3": 3, "4": 4 },
+          "-4": { "-4": -4, "-3": -3, "-2": -2, "-1": -1 }
+        };
+        assert.error(err, "testMapMap: no callback error");
+        assert.deepEqual(expected, response, "testMapMap");
+      });
+
+      client.testStruct(testCases.out, function(err, response) {
+        assert.error(err, "testStruct: no callback error");
+        checkRecursively(testCases.out, response, "testStruct");
+      });
+
+      client.testNest(testCases.out2, function(err, response) {
+        assert.error(err, "testNest: no callback error");
+        checkRecursively(testCases.out2, response, "testNest");
+      });
+
+      client.testInsanity(testCases.crazy, function(err, response) {
+        assert.error(err, "testInsanity: no callback error");
+        checkRecursively(testCases.insanity, response, "testInsanity");
+      });
+
+      client.testInsanity(testCases.crazy2, function(err, response) {
+        assert.error(err, "testInsanity2: no callback error");
+        checkRecursively(testCases.insanity, response, "testInsanity2");
+      });
+
+      client.testException("TException", function(err, response) {
+        assert.ok(
+          err instanceof TException,
+          "testException: correct error type"
+        );
+        assert.ok(!response, "testException: no response");
+      });
+
+      client.testException("Xception", function(err, response) {
+        assert.ok(
+          err instanceof ttypes.Xception,
+          "testException: correct error type"
+        );
+        assert.ok(!response, "testException: no response");
+        assert.equal(err.errorCode, 1001, "testException: correct error code");
+        assert.equal(
+          "Xception",
+          err.message,
+          "testException: correct error message"
+        );
+      });
+
+      client.testException("no Exception", function(err, response) {
+        assert.error(err, "testException: no callback error");
+        assert.ok(!response, "testException: no response");
+      });
+
+      client.testOneway(0, function(err, response) {
+        assert.error(err, "testOneway: no callback error");
+        assert.strictEqual(response, undefined, "testOneway: void response");
+      });
+
+      checkOffByOne(function(done) {
+        client.testI32(-1, function(err, response) {
+          assert.error(err, "checkOffByOne: no callback error");
+          assert.equal(-1, response);
+          assert.end();
+          done();
+        });
+      }, callback);
+    }
+  );
+
+  // ES6 does not support callback style
+  if (helpers.ecmaMode === "es6") {
+    checkOffByOne(done => done(), callback);
+  }
+};
+
+exports.ThriftTestDriverPromise = function(client, callback) {
+  test("Promise Client Tests", function(assert) {
+    const checkRecursively = makeRecursiveCheck(assert);
+
+    function makeAsserter(assertionFn) {
+      return function(c) {
+        const fnName = c[0];
+        const expected = c[1];
+        client[fnName](expected)
+          .then(function(actual) {
+            assertionFn(actual, expected, fnName);
+          })
+          .catch(() => assert.fail("fnName"));
+      };
+    }
+
+    testCases.simple.forEach(
+      makeAsserter(function(a, e, m) {
+        if (a instanceof Int64) {
+          const e64 = e instanceof Int64 ? e : new Int64(e);
+          assert.deepEqual(a.buffer, e64.buffer, m);
+        } else {
+          assert.equal(a, e, m);
+        }
+      })
+    );
+    testCases.deep.forEach(makeAsserter(assert.deepEqual));
+    testCases.deepUnordered.forEach(
+      makeAsserter(makeUnorderedDeepEqual(assert))
+    );
+
+    client
+      .testStruct(testCases.out)
+      .then(function(response) {
+        checkRecursively(testCases.out, response, "testStruct");
+      })
+      .catch(() => assert.fail("testStruct"));
+
+    client
+      .testNest(testCases.out2)
+      .then(function(response) {
+        checkRecursively(testCases.out2, response, "testNest");
+      })
+      .catch(() => assert.fail("testNest"));
+
+    client
+      .testInsanity(testCases.crazy)
+      .then(function(response) {
+        checkRecursively(testCases.insanity, response, "testInsanity");
+      })
+      .catch(() => assert.fail("testInsanity"));
+
+    client
+      .testInsanity(testCases.crazy2)
+      .then(function(response) {
+        checkRecursively(testCases.insanity, response, "testInsanity2");
+      })
+      .catch(() => assert.fail("testInsanity2"));
+
+    client
+      .testException("TException")
+      .then(function() {
+        assert.fail("testException: TException");
+      })
+      .catch(function(err) {
+        assert.ok(err instanceof TException);
+      });
+
+    client
+      .testException("Xception")
+      .then(function() {
+        assert.fail("testException: Xception");
+      })
+      .catch(function(err) {
+        assert.ok(err instanceof ttypes.Xception);
+        assert.equal(err.errorCode, 1001);
+        assert.equal("Xception", err.message);
+      });
+
+    client
+      .testException("no Exception")
+      .then(function(response) {
+        assert.equal(undefined, response); //void
+      })
+      .catch(() => assert.fail("testException"));
+
+    client
+      .testOneway(0)
+      .then(function(response) {
+        assert.strictEqual(response, undefined, "testOneway: void response");
+      })
+      .catch(() => assert.fail("testOneway: should not reject"));
+
+    checkOffByOne(function(done) {
+      client
+        .testI32(-1)
+        .then(function(response) {
+          assert.equal(-1, response);
+          assert.end();
+          done();
+        })
+        .catch(() => assert.fail("checkOffByOne"));
+    }, callback);
+  });
+};
+
+// Helper Functions
+// =========================================================
+
+function makeRecursiveCheck(assert) {
+  return function(map1, map2, msg) {
+    const equal = checkRecursively(map1, map2);
+
+    assert.ok(equal, msg);
+
+    // deepEqual doesn't work with fields using node-int64
+    function checkRecursively(map1, map2) {
+      if (typeof map1 !== "function" && typeof map2 !== "function") {
+        if (!map1 || typeof map1 !== "object") {
+          //Handle int64 types (which use node-int64 in Node.js JavaScript)
+          if (
+            typeof map1 === "number" &&
+            typeof map2 === "object" &&
+            map2.buffer &&
+            map2.buffer instanceof Buffer &&
+            map2.buffer.length === 8
+          ) {
+            const n = new Int64(map2.buffer);
+            return map1 === n.toNumber();
+          } else {
+            return map1 == map2;
+          }
+        } else {
+          return Object.keys(map1).every(function(key) {
+            return checkRecursively(map1[key], map2[key]);
+          });
+        }
+      }
+    }
+  };
+}
+
+function checkOffByOne(done, callback) {
+  const retry_limit = 30;
+  const retry_interval = 100;
+  let test_complete = false;
+  let retrys = 0;
+
+  /**
+   * redo a simple test after the oneway to make sure we aren't "off by one" --
+   * if the server treated oneway void like normal void, this next test will
+   * fail since it will get the void confirmation rather than the correct
+   * result. In this circumstance, the client will throw the exception:
+   *
+   * Because this is the last test against the server, when it completes
+   * the entire suite is complete by definition (the tests run serially).
+   */
+  done(function() {
+    test_complete = true;
+  });
+
+  //We wait up to retry_limit * retry_interval for the test suite to complete
+  function TestForCompletion() {
+    if (test_complete && callback) {
+      callback("Server successfully tested!");
+    } else {
+      if (++retrys < retry_limit) {
+        setTimeout(TestForCompletion, retry_interval);
+      } else if (callback) {
+        callback(
+          "Server test failed to complete after " +
+            (retry_limit * retry_interval) / 1000 +
+            " seconds"
+        );
+      }
+    }
+  }
+
+  setTimeout(TestForCompletion, retry_interval);
+}
+
+function makeUnorderedDeepEqual(assert) {
+  return function(actual, expected, name) {
+    assert.equal(actual.length, expected.length, name);
+    for (const k in actual) {
+      let found = false;
+      for (const k2 in expected) {
+        if (actual[k] === expected[k2]) {
+          found = true;
+        }
+      }
+      if (!found) {
+        assert.fail("Unexpected value " + actual[k] + " with key " + k);
+      }
+    }
+  };
+}
diff --git a/lib/nodejs/test/test_handler.js b/lib/nodejs/test/test_handler.js
new file mode 100644
index 0000000..317a7c8
--- /dev/null
+++ b/lib/nodejs/test/test_handler.js
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * 'License'); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//This is the server side Node test handler for the standard
+//  Apache Thrift test service.
+const helpers = require("./helpers");
+const ttypes = require(`./${helpers.genPath}/ThriftTest_types`);
+const TException = require("thrift").Thrift.TException;
+
+function makeSyncHandler() {
+  return function(thing) {
+    return thing;
+  };
+}
+
+const syncHandlers = {
+  testVoid: testVoid,
+  testMapMap: testMapMap,
+  testInsanity: testInsanity,
+  testMulti: testMulti,
+  testException: testException,
+  testMultiException: testMultiException,
+  testOneway: testOneway
+};
+
+function makeAsyncHandler(label) {
+  return function(thing, result) {
+    thing = syncHandlers[label](thing);
+    result(null, thing);
+  };
+}
+
+const asyncHandlers = {
+  testVoid: testVoidAsync,
+  testMulti: testMultiAsync,
+  testException: testExceptionAsync,
+  testMultiException: testMultiExceptionAsync,
+  testOneway: testOnewayAsync
+};
+
+const identityHandlers = [
+  "testString",
+  "testBool",
+  "testByte",
+  "testI32",
+  "testI64",
+  "testDouble",
+  "testBinary",
+  "testStruct",
+  "testNest",
+  "testMap",
+  "testStringMap",
+  "testSet",
+  "testList",
+  "testEnum",
+  "testTypedef"
+];
+
+function testVoid() {
+  //console.log('testVoid()');
+}
+
+function testVoidAsync(result) {
+  result(testVoid());
+}
+
+function testMapMap() {
+  const mapmap = [];
+  const pos = [];
+  const neg = [];
+  for (let i = 1; i < 5; i++) {
+    pos[i] = i;
+    neg[-i] = -i;
+  }
+  mapmap[4] = pos;
+  mapmap[-4] = neg;
+
+  return mapmap;
+}
+
+function testInsanity(argument) {
+  //console.log('testInsanity(');
+  //console.log(argument);
+  //console.log(')');
+
+  const first_map = [];
+  const second_map = [];
+
+  first_map[ttypes.Numberz.TWO] = argument;
+  first_map[ttypes.Numberz.THREE] = argument;
+
+  const looney = new ttypes.Insanity();
+  second_map[ttypes.Numberz.SIX] = looney;
+
+  const insane = [];
+  insane[1] = first_map;
+  insane[2] = second_map;
+
+  //console.log('insane result:');
+  //console.log(insane);
+  return insane;
+}
+
+function testMulti(arg0, arg1, arg2) {
+  //console.log('testMulti()');
+
+  const hello = new ttypes.Xtruct();
+  hello.string_thing = "Hello2";
+  hello.byte_thing = arg0;
+  hello.i32_thing = arg1;
+  hello.i64_thing = arg2;
+  return hello;
+}
+
+function testMultiAsync(arg0, arg1, arg2, arg3, arg4, arg5, result) {
+  const hello = testMulti(arg0, arg1, arg2, arg3, arg4, arg5);
+  result(null, hello);
+}
+
+function testException(arg) {
+  //console.log('testException('+arg+')');
+  if (arg === "Xception") {
+    const x = new ttypes.Xception();
+    x.errorCode = 1001;
+    x.message = arg;
+    throw x;
+  } else if (arg === "TException") {
+    throw new TException(arg);
+  } else {
+    return;
+  }
+}
+
+function testExceptionAsync(arg, result) {
+  //console.log('testException('+arg+')');
+  if (arg === "Xception") {
+    const x = new ttypes.Xception();
+    x.errorCode = 1001;
+    x.message = arg;
+    result(x);
+  } else if (arg === "TException") {
+    result(new TException(arg));
+  } else {
+    result(null);
+  }
+}
+
+function testMultiException(arg0, arg1) {
+  //console.log('testMultiException(' + arg0 + ', ' + arg1 + ')');
+  if (arg0 === "Xception") {
+    const x = new ttypes.Xception();
+    x.errorCode = 1001;
+    x.message = "This is an Xception";
+    throw x;
+  } else if (arg0 === "Xception2") {
+    const x2 = new ttypes.Xception2();
+    x2.errorCode = 2002;
+    x2.struct_thing = new ttypes.Xtruct();
+    x2.struct_thing.string_thing = "This is an Xception2";
+    throw x2;
+  }
+
+  const res = new ttypes.Xtruct();
+  res.string_thing = arg1;
+  return res;
+}
+
+function testMultiExceptionAsync(arg0, arg1, result) {
+  //console.log('testMultiException(' + arg0 + ', ' + arg1 + ')');
+  if (arg0 === "Xception") {
+    const x = new ttypes.Xception();
+    x.errorCode = 1001;
+    x.message = "This is an Xception";
+    result(x);
+  } else if (arg0 === "Xception2") {
+    const x2 = new ttypes.Xception2();
+    x2.errorCode = 2002;
+    x2.struct_thing = new ttypes.Xtruct();
+    x2.struct_thing.string_thing = "This is an Xception2";
+    result(x2);
+  } else {
+    const res = new ttypes.Xtruct();
+    res.string_thing = arg1;
+    result(null, res);
+  }
+}
+
+//console.log('testOneway(' + sleepFor + ') => JavaScript (like Rust) never sleeps!');
+function testOneway() {}
+
+function testOnewayAsync(sleepFor) {
+  testOneway(sleepFor);
+}
+
+identityHandlers.forEach(function(label) {
+  syncHandlers[label] = makeSyncHandler(label);
+  asyncHandlers[label] = makeAsyncHandler(label);
+});
+
+["testMapMap", "testInsanity"].forEach(function(label) {
+  asyncHandlers[label] = makeAsyncHandler(label);
+});
+
+exports.ThriftTestHandler = asyncHandlers;
diff --git a/lib/nodets/.gitignore b/lib/nodets/.gitignore
new file mode 100644
index 0000000..c7aba89
--- /dev/null
+++ b/lib/nodets/.gitignore
@@ -0,0 +1 @@
+test-compiled/
diff --git a/lib/nodets/Makefile.am b/lib/nodets/Makefile.am
new file mode 100755
index 0000000..ea640cf
--- /dev/null
+++ b/lib/nodets/Makefile.am
@@ -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.
+
+# We call npm twice to work around npm issues
+
+stubs: $(top_srcdir)/test/ThriftTest.thrift
+	mkdir -p test-compiled
+	$(THRIFT) --gen js:node,ts -o test/ $(top_srcdir)/test/ThriftTest.thrift && $(THRIFT) --gen js:node,ts -o test-compiled $(top_srcdir)/test/ThriftTest.thrift
+
+ts-compile: stubs
+	mkdir -p test-compiled
+	../../node_modules/typescript/bin/tsc --outDir test-compiled/ --project test/tsconfig.json
+
+deps: $(top_srcdir)/package.json
+	$(NPM) install $(top_srcdir)/ || $(NPM) install $(top_srcdir)/
+
+all-local: deps ts-compile
+
+precross: deps stubs ts-compile
+
+check: deps ts-compile
+	cd $(top_srcdir) && $(NPM) run test-ts && cd lib/nodets
+
+clean-local:
+	$(RM) -r test/gen-nodejs
+	$(RM) -r $(top_srcdir)/node_modules
+	$(RM) -r test-compiled
+
+EXTRA_DIST = \
+	test \
+	coding_standards.md
diff --git a/lib/nodets/coding_standards.md b/lib/nodets/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/nodets/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/nodets/test/client.ts b/lib/nodets/test/client.ts
new file mode 100644
index 0000000..4fa3c28
--- /dev/null
+++ b/lib/nodets/test/client.ts
@@ -0,0 +1,63 @@
+/*
+ * 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 assert = require("assert");
+import thrift = require("thrift");
+import Thrift = thrift.Thrift;
+import ThriftTest = require("./gen-nodejs/ThriftTest");
+import test_driver = require("./test_driver");
+import ThriftTestDriver = test_driver.ThriftTestDriver;
+import ThriftTestDriverPromise = test_driver.ThriftTestDriverPromise;
+
+// var program = require("commander");
+import * as program from "commander";
+
+program
+  .option("--port <port>", "Set thrift server port number to connect", 9090)
+  .option("--promise", "test with promise style functions")
+  .option("--protocol", "Set thrift protocol (binary) [protocol]")
+  .parse(process.argv);
+
+var port: number = program.port;
+var promise = program.promise;
+
+var options = {
+  transport: Thrift.TBufferedTransport,
+  protocol: Thrift.TBinaryProtocol
+};
+
+var testDriver = promise ? ThriftTestDriverPromise : ThriftTestDriver;
+
+var connection = thrift.createConnection("localhost", port, options);
+
+connection.on("error", function(err: string) {
+    assert(false, err);
+});
+
+var client = thrift.createClient(ThriftTest.Client, connection);
+runTests();
+
+function runTests() {
+  testDriver(client, function (status: string) {
+    console.log(status);
+    process.exit(0);
+  });
+}
+
+exports.expressoTest = function() {};
diff --git a/lib/nodets/test/runClient.sh b/lib/nodets/test/runClient.sh
new file mode 100755
index 0000000..8d5e9a3
--- /dev/null
+++ b/lib/nodets/test/runClient.sh
@@ -0,0 +1,18 @@
+#! /bin/sh
+
+DIR="$( cd "$( dirname "$0" )" && pwd )"
+
+mkdir -p $DIR/../test-compiled
+
+COMPILEDDIR="$(cd $DIR && cd ../test-compiled && pwd)"
+export NODE_PATH="${DIR}:${DIR}/../../nodejs/lib:${NODE_PATH}"
+
+compile()
+{
+  #generating thrift code
+  ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift
+  ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift
+}
+compile
+
+node ${COMPILEDDIR}/client.js $*
diff --git a/lib/nodets/test/runServer.sh b/lib/nodets/test/runServer.sh
new file mode 100755
index 0000000..4eee927
--- /dev/null
+++ b/lib/nodets/test/runServer.sh
@@ -0,0 +1,20 @@
+#! /bin/sh
+
+DIR="$( cd "$( dirname "$0" )" && pwd )"
+
+mkdir -p $DIR/../test-compiled
+
+COMPILEDDIR="$(cd $DIR && cd ../test-compiled && pwd)"
+export NODE_PATH="${DIR}:${DIR}/../../nodejs/lib:${NODE_PATH}"
+
+compile()
+{
+  #generating thrift code
+  ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift
+  ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift
+}
+compile
+
+node ${COMPILEDDIR}/server.js $*
+
+
diff --git a/lib/nodets/test/server.ts b/lib/nodets/test/server.ts
new file mode 100644
index 0000000..2da53ae
--- /dev/null
+++ b/lib/nodets/test/server.ts
@@ -0,0 +1,26 @@
+import thrift = require("thrift");
+var program = require('commander');
+import ThriftTest = require('./gen-nodejs/ThriftTest');
+import test_handler = require('./test_handler');
+
+
+program
+  .option('--port <port>', 'Set thrift server port', 9090)
+  .option('--promise', 'test with promise style functions')
+  .option('--protocol', '"Set thrift protocol (binary) [protocol]"')
+  .parse(process.argv);
+
+var port: number = program.port;
+
+var options: thrift.ServerOptions = {
+  transport: thrift.TBufferedTransport,
+  protocol: thrift.TBinaryProtocol
+};
+
+var server: thrift.Server;
+if (program.promise) {
+  server = thrift.createServer(ThriftTest.Processor, new test_handler.AsyncThriftTestHandler(), options);
+} else {
+  server = thrift.createServer(ThriftTest.Processor, new test_handler.SyncThriftTestHandler(), options);
+}
+server.listen(port);
diff --git a/lib/nodets/test/test-cases.ts b/lib/nodets/test/test-cases.ts
new file mode 100644
index 0000000..ca740ec
--- /dev/null
+++ b/lib/nodets/test/test-cases.ts
@@ -0,0 +1,113 @@
+'use strict';
+
+import ttypes = require('./gen-nodejs/ThriftTest_types');
+
+//all Languages in UTF-8
+/*jshint -W100 */
+export var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " +
+    "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " +
+    "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, " +
+    "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, " +
+    "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, " +
+    "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, " +
+    "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, " +
+    "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, " +
+    "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, " +
+    "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, " +
+    "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, " +
+    "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, " +
+    "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, " +
+    "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa " +
+    "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa " +
+    "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪" +
+    "Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, " +
+    "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, " +
+    "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, " +
+    "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple " +
+    "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, " +
+    "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, " +
+    "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, " +
+    "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, " +
+    "Bân-lâm-gú, 粵語";
+/*jshint +W100 */
+
+export var specialCharacters = 'quote: \" backslash:' +
+    ' forwardslash-escaped: \/ ' +
+    ' backspace: \b formfeed: \f newline: \n return: \r tab: ' +
+    ' now-all-of-them-together: "\\\/\b\n\r\t' +
+    ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><' +
+    ' char-to-test-json-parsing: ]] \"]] \\" }}}{ [[[ ';
+
+export var mapTestInput = {
+  "a":"123", "a b":"with spaces ", "same":"same", "0":"numeric key",
+  "longValue":stringTest, stringTest:"long key"
+};
+
+export var simple = [
+  ['testVoid', undefined],
+  ['testString', 'Test'],
+  ['testString', ''],
+  ['testString', stringTest],
+  ['testString', specialCharacters],
+  ['testByte', 1],
+  ['testByte', 0],
+  ['testByte', -1],
+  ['testByte', -127],
+  ['testI32', -1],
+  ['testDouble', -5.2098523],
+  ['testDouble', 7.012052175215044],
+  ['testEnum', ttypes.Numberz.ONE]
+];
+
+export var simpleLoose = [
+  ['testI64', 5],
+  ['testI64', -5],
+  ['testI64', 734359738368],
+  ['testI64', -34359738368],
+  ['testI64', -734359738368],
+  ['testTypedef', 69]
+]
+
+var mapout: {[key: number]: number; } = {};
+for (var i = 0; i < 5; ++i) {
+  mapout[i] = i-10;
+}
+
+export var deep = [
+  ['testMap', mapout],
+  ['testSet', [1,2,3]],
+  ['testList', [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]],
+  ['testStringMap', mapTestInput]
+];
+
+export var out = new ttypes.Xtruct({
+  string_thing: 'Zero',
+  byte_thing: 1,
+  i32_thing: -3,
+  i64_thing: 1000000
+});
+
+export var out2 = new ttypes.Xtruct2();
+out2.byte_thing = 1;
+out2.struct_thing = out;
+out2.i32_thing = 5;
+
+export var crazy = new ttypes.Insanity({
+  "userMap":{ "5":5, "8":8 },
+  "xtructs":[new ttypes.Xtruct({
+      "string_thing":"Goodbye4",
+      "byte_thing":4,
+      "i32_thing":4,
+      "i64_thing":4
+    }), new ttypes.Xtruct({
+      "string_thing":"Hello2",
+      "byte_thing":2,
+      "i32_thing":2,
+      "i64_thing":2
+    })]
+});
+
+export var insanity: any = {
+  "1":{ "2": crazy, "3": crazy },
+  "2":{ "6":{ "userMap":{}, "xtructs":[] } }
+};
diff --git a/lib/nodets/test/testAll.sh b/lib/nodets/test/testAll.sh
new file mode 100755
index 0000000..a7c00bf
--- /dev/null
+++ b/lib/nodets/test/testAll.sh
@@ -0,0 +1,38 @@
+#! /bin/sh
+
+DIR="$( cd "$( dirname "$0" )" && pwd )"
+
+mkdir -p $DIR/../test-compiled
+
+COMPILEDDIR="$(cd $DIR && cd ../test-compiled && pwd)"
+export NODE_PATH="${DIR}:${DIR}/../../nodejs/lib:${NODE_PATH}"
+
+compile()
+{
+  #generating thrift code
+  ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift
+  ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift
+
+  tsc --outDir $COMPILEDDIR --project $DIR/tsconfig.json
+}
+compile
+
+testServer()
+{
+  echo "start server $1"
+  RET=0
+  node ${COMPILEDDIR}/server.js $1 &
+  SERVERPID=$!
+  sleep 1
+  echo "start client $1"
+  node ${COMPILEDDIR}/client.js $1 || RET=1
+  kill -2 $SERVERPID || RET=1
+  return $RET
+}
+
+#integration tests
+
+testServer || TESTOK=1
+testServer --promise || TESTOK=1
+
+exit $TESTOK
diff --git a/lib/nodets/test/test_driver.ts b/lib/nodets/test/test_driver.ts
new file mode 100644
index 0000000..2c41526
--- /dev/null
+++ b/lib/nodets/test/test_driver.ts
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * 'License'); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+ // This is the Node.js test driver for the standard Apache Thrift
+ // test service. The driver invokes every function defined in the
+ // Thrift Test service with a representative range of parameters.
+ //
+ // The ThriftTestDriver function requires a client object
+ // connected to a server hosting the Thrift Test service and
+ // supports an optional callback function which is called with
+ // a status message when the test is complete.
+
+import test = require("tape");
+import ttypes = require("./gen-nodejs/ThriftTest_types");
+import ThriftTest = require("./gen-nodejs/ThriftTest");
+import thrift = require("thrift");
+import Q = thrift.Q;
+import TException = thrift.Thrift.TException;
+var Int64 = require("node-int64");
+import testCases = require("./test-cases");
+
+export function ThriftTestDriver(client: ThriftTest.Client, callback: (status: string) => void) {
+
+  test("NodeJS Style Callback Client Tests", function(assert) {
+
+    var checkRecursively = makeRecursiveCheck(assert);
+
+    function makeAsserter(assertionFn: (a: any, b: any, msg?: string) => void) {
+      return function(c: (string | any)[]) {
+        var fnName = c[0];
+        var expected = c[1];
+        (<any>client)[fnName](expected, function(err: any, actual: any) {
+          assert.error(err, fnName + ": no callback error");
+          assertionFn(actual, expected, fnName);
+        })
+      };
+    }
+
+    testCases.simple.forEach(makeAsserter(assert.equal));
+    testCases.simpleLoose.forEach(makeAsserter(function(a, e, m){
+      assert.ok(a == e, m);
+    }));
+    testCases.deep.forEach(makeAsserter(assert.deepEqual));
+
+    client.testMapMap(42, function(err, response) {
+      var expected: typeof response = {
+        "4": {"1":1, "2":2, "3":3, "4":4},
+        "-4": {"-4":-4, "-3":-3, "-2":-2, "-1":-1}
+      };
+      assert.error(err, 'testMapMap: no callback error');
+      assert.deepEqual(expected, response, "testMapMap");
+    });
+
+    client.testStruct(testCases.out, function(err, response) {
+      assert.error(err, "testStruct: no callback error");
+      checkRecursively(testCases.out, response, "testStruct");
+    });
+
+    client.testNest(testCases.out2, function(err, response) {
+      assert.error(err, "testNest: no callback error");
+      checkRecursively(testCases.out2, response, "testNest");
+    });
+
+    client.testInsanity(testCases.crazy, function(err, response) {
+      assert.error(err, "testInsanity: no callback error");
+      checkRecursively(testCases.insanity, response, "testInsanity");
+    });
+
+    client.testException("TException", function(err, response) {
+      assert.ok(err instanceof TException, 'testException: correct error type');
+      assert.ok(!Boolean(response), 'testException: no response');
+    });
+
+    client.testException("Xception", function(err, response) {
+      assert.ok(err instanceof ttypes.Xception, 'testException: correct error type');
+      assert.ok(!Boolean(response), 'testException: no response');
+      assert.equal(err.errorCode, 1001, 'testException: correct error code');
+      assert.equal('Xception', err.message, 'testException: correct error message');
+    });
+
+    client.testException("no Exception", function(err, response) {
+      assert.error(err, 'testException: no callback error');
+      assert.ok(!Boolean(response), 'testException: no response');
+    });
+
+    client.testOneway(0, function(err, response) {
+      assert.error(err, 'testOneway: no callback error');
+      assert.strictEqual(response, undefined, 'testOneway: void response');
+    });
+
+    checkOffByOne(function(done) {
+      client.testI32(-1, function(err, response) {
+        assert.error(err, "checkOffByOne: no callback error");
+        assert.equal(-1, response);
+        assert.end();
+        done();
+      });
+    }, callback);
+
+  });
+};
+
+export function ThriftTestDriverPromise(client: ThriftTest.Client, callback: (status: string) => void) {
+
+  test("Q Promise Client Tests", function(assert) {
+
+    var checkRecursively = makeRecursiveCheck(assert);
+
+    function fail(msg: string) {
+      return function(error, response) {
+        if (error !== null) {
+          assert.fail(msg);
+        }
+      }
+    }
+
+    function makeAsserter(assertionFn: (a: any, b: any, msg?: string) => void) {
+      return function(c: (string | any)[]) {
+        var fnName = c[0];
+        var expected = c[1];
+        (<any>client)[fnName](expected)
+          .then(function(actual: any) {
+            assertionFn(actual, expected, fnName);
+          })
+          .fail(fail("fnName"));
+      };
+    }
+
+    testCases.simple.forEach(makeAsserter(assert.equal));
+    testCases.simpleLoose.forEach(makeAsserter(function(a, e, m){
+      assert.ok(a == e, m);
+    }));
+    testCases.deep.forEach(makeAsserter(assert.deepEqual));
+
+    Q.resolve(client.testStruct(testCases.out))
+      .then(function(response) {
+        checkRecursively(testCases.out, response, "testStruct");
+      })
+      .fail(fail("testStruct"));
+
+    Q.resolve(client.testNest(testCases.out2))
+      .then(function(response) {
+        checkRecursively(testCases.out2, response, "testNest");
+      })
+      .fail(fail("testNest"));
+
+    Q.resolve(client.testInsanity(testCases.crazy))
+      .then(function(response) {
+        checkRecursively(testCases.insanity, response, "testInsanity");
+      })
+      .fail(fail("testInsanity"));
+
+    Q.resolve(client.testException("TException"))
+      .then(function(response) {
+        fail("testException: TException");
+      })
+      .fail(function(err) {
+        assert.ok(err instanceof TException);
+      });
+
+    Q.resolve(client.testException("Xception"))
+      .then(function(response) {
+        fail("testException: Xception");
+      })
+      .fail(function(err) {
+        assert.ok(err instanceof ttypes.Xception);
+        assert.equal(err.errorCode, 1001);
+        assert.equal("Xception", err.message);
+      });
+
+    Q.resolve(client.testException("no Exception"))
+      .then(function(response) {
+        assert.equal(undefined, response); //void
+      })
+      .fail(fail("testException"));
+
+    client.testOneway(0, fail("testOneway: should not answer"));
+
+    checkOffByOne(function(done) {
+      Q.resolve(client.testI32(-1))
+        .then(function(response) {
+            assert.equal(-1, response);
+            assert.end();
+            done();
+        })
+        .fail(fail("checkOffByOne"));
+    }, callback);
+  });
+};
+
+
+// Helper Functions
+// =========================================================
+
+function makeRecursiveCheck(assert: test.Test) {
+
+  return function (map1: any, map2: any, msg: string) {
+    var equal = true;
+
+    var equal = checkRecursively(map1, map2);
+
+    assert.ok(equal, msg);
+
+    // deepEqual doesn't work with fields using node-int64
+    function checkRecursively(map1: any, map2: any) : boolean {
+      if (!(typeof map1 !== "function" && typeof map2 !== "function")) {
+        return false;
+      }
+      if (!map1 || typeof map1 !== "object") {
+        //Handle int64 types (which use node-int64 in Node.js JavaScript)
+        if ((typeof map1 === "number") && (typeof map2 === "object") &&
+            (map2.buffer) && (map2.buffer instanceof Buffer) && (map2.buffer.length === 8)) {
+          var n = new Int64(map2.buffer);
+          return map1 === n.toNumber();
+        } else {
+          return map1 == map2;
+        }
+      } else {
+        return Object.keys(map1).every(function(key) {
+          return checkRecursively(map1[key], map2[key]);
+        });
+      }
+    }
+  }
+}
+
+function checkOffByOne(done: (callback: () => void) => void, callback: (message: string) => void) {
+
+  var retry_limit = 30;
+  var retry_interval = 100;
+  var test_complete = false;
+  var retrys = 0;
+
+  /**
+   * redo a simple test after the oneway to make sure we aren't "off by one" --
+   * if the server treated oneway void like normal void, this next test will
+   * fail since it will get the void confirmation rather than the correct
+   * result. In this circumstance, the client will throw the exception:
+   *
+   * Because this is the last test against the server, when it completes
+   * the entire suite is complete by definition (the tests run serially).
+   */
+  done(function() {
+    test_complete = true;
+  });
+
+  //We wait up to retry_limit * retry_interval for the test suite to complete
+  function TestForCompletion() {
+    if(test_complete && callback) {
+      callback("Server successfully tested!");
+    } else {
+      if (++retrys < retry_limit) {
+        setTimeout(TestForCompletion, retry_interval);
+      } else if (callback) {
+        callback("Server test failed to complete after " +
+                 (retry_limit * retry_interval / 1000) + " seconds");
+      }
+    }
+  }
+
+  setTimeout(TestForCompletion, retry_interval);
+}
diff --git a/lib/nodets/test/test_handler.ts b/lib/nodets/test/test_handler.ts
new file mode 100644
index 0000000..1bc855a
--- /dev/null
+++ b/lib/nodets/test/test_handler.ts
@@ -0,0 +1,299 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * 'License'); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//This is the server side Node test handler for the standard
+//  Apache Thrift test service.
+
+import ttypes = require("./gen-nodejs/ThriftTest_types");
+import thrift = require("thrift");
+import Thrift = thrift.Thrift;
+import Q = require("q");
+
+
+export class SyncThriftTestHandler {
+  testVoid(): Q.IPromise<void> {
+    //console.log('testVoid()');
+    return Q.resolve<void>(undefined);
+  }
+  testMapMap(hello: number) {
+    //console.log('testMapMap(' + hello + ')');
+
+    var mapmap: {[key: number]: {[key: number]: number; }} = [];
+    var pos: {[key: number]: number; } = [];
+    var neg: {[key: number]: number; } = [];
+    for (var i = 1; i < 5; i++) {
+      pos[i] = i;
+      neg[-i] = -i;
+    }
+    mapmap[4] = pos;
+    mapmap[-4] = neg;
+
+    return Q.resolve(mapmap);
+  }
+  testInsanity(argument: ttypes.Insanity): Q.IPromise<{ [k: number]: any; }> {
+    const first_map: { [k: number]: any; } = [];
+    const second_map: { [k: number]: any; } = [];
+  
+    first_map[ttypes.Numberz.TWO] = argument;
+    first_map[ttypes.Numberz.THREE] = argument;
+  
+    const looney = new ttypes.Insanity();
+    second_map[ttypes.Numberz.SIX] = looney;
+  
+    const insane: { [k: number]: any; } = [];
+    insane[1] = first_map;
+    insane[2] = second_map;
+
+    return Q.resolve(insane);
+  }
+  testMulti(arg0: any, arg1: number, arg2: number, arg3: { [k: number]: string; }, arg4: ttypes.Numberz, arg5: number) {
+    var hello = new ttypes.Xtruct();
+    hello.string_thing = 'Hello2';
+    hello.byte_thing = arg0;
+    hello.i32_thing = arg1;
+    hello.i64_thing = arg2;
+    return Q.resolve(hello);
+  }
+  testException(arg: string): Q.IPromise<void> {
+    if (arg === 'Xception') {
+      var x = new ttypes.Xception();
+      x.errorCode = 1001;
+      x.message = arg;
+      throw x;
+    } else if (arg === 'TException') {
+      throw new Thrift.TException(arg);
+    } else {
+      return Q.resolve();
+    }
+  }
+  testMultiException(arg0: string, arg1: string) {
+    if (arg0 === ('Xception')) {
+      var x = new ttypes.Xception();
+      x.errorCode = 1001;
+      x.message = 'This is an Xception';
+      throw x;
+    } else if (arg0 === ('Xception2')) {
+      var x2 = new ttypes.Xception2();
+      x2.errorCode = 2002;
+      x2.struct_thing = new ttypes.Xtruct();
+      x2.struct_thing.string_thing = 'This is an Xception2';
+      throw x2;
+    }
+
+    var res = new ttypes.Xtruct();
+    res.string_thing = arg1;
+    return Q.resolve(res);
+  }
+  testOneway(sleepFor: number) {
+  }
+
+  testString(thing: string) {
+    return Q.resolve(thing);
+  }
+  testBool(thing: boolean) {
+    return Q.resolve(thing);
+  }
+  testByte(thing: number) {
+    return Q.resolve(thing);
+  }
+  testI32(thing: number) {
+    return Q.resolve(thing);
+  }
+  testI64(thing: number) {
+    return Q.resolve(thing);
+  }
+  testDouble(thing: number) {
+    return Q.resolve(thing);
+  }
+  testBinary(thing: Buffer) {
+    return Q.resolve(thing);
+  }
+  testStruct(thing: ttypes.Xtruct) {
+    return Q.resolve(thing);
+  }
+  testNest(thing: ttypes.Xtruct2) {
+    return Q.resolve(thing);
+  }
+  testMap(thing: { [k: number]: number; }) {
+    return Q.resolve(thing);
+  }
+  testStringMap(thing: { [k: string]: string; }) {
+    return Q.resolve(thing);
+  }
+  testSet(thing: number[]) {
+    return Q.resolve(thing);
+  }
+  testList(thing: number[]) {
+    return Q.resolve(thing);
+  }
+  testEnum(thing: ttypes.Numberz) {
+    return Q.resolve(thing);
+  }
+  testTypedef(thing: number) {
+    return Q.resolve(thing);
+  }
+}
+
+export class AsyncThriftTestHandler {
+  private syncHandler: SyncThriftTestHandler;
+  constructor() {
+    this.syncHandler = new SyncThriftTestHandler();
+  }
+
+  testVoid(callback: (result: void) => void): Q.IPromise<void> {
+    callback(undefined);
+    return Q.resolve();
+  }
+  testMapMap(hello: number,
+    callback: (err: any, result: { [k: number]: { [k: number]: number; }; }) => void):
+     Q.IPromise<{ [k: number]: { [k: number]: number; }; }> {
+
+    var mapmap: {[key: number]: {[key: number]: number; }} = [];
+    var pos: {[key: number]: number; } = [];
+    var neg: {[key: number]: number; } = [];
+    for (var i = 1; i < 5; i++) {
+      pos[i] = i;
+      neg[-i] = -i;
+    }
+    mapmap[4] = pos;
+    mapmap[-4] = neg;
+
+    callback(null, mapmap);
+    return Q.resolve();
+  }
+  testInsanity(argument: ttypes.Insanity, callback?: (err: any, result: { [k: number]: any; }) => void): Q.IPromise<{ [k: number]: any; }> {
+    const first_map: { [k: number]: any; } = [];
+    const second_map: { [k: number]: any; } = [];
+  
+    first_map[ttypes.Numberz.TWO] = argument;
+    first_map[ttypes.Numberz.THREE] = argument;
+  
+    const looney = new ttypes.Insanity();
+    second_map[ttypes.Numberz.SIX] = looney;
+  
+    const insane: { [k: number]: any; } = [];
+    insane[1] = first_map;
+    insane[2] = second_map;
+
+    if (callback !== undefined){
+      callback(null, insane);
+    }
+    return Q.resolve();
+  }
+  testMulti(arg0: any, arg1: number, arg2: number, arg3: { [k: number]: string; }, arg4: ttypes.Numberz, arg5: number, result: Function): Q.IPromise<ttypes.Xtruct> {
+    var hello = this.syncHandler.testMulti(arg0, arg1, arg2, arg3, arg4, arg5);
+    hello.then(hello => result(null, hello));
+    return Q.resolve();
+  }
+  testException(arg: string, result: (err: any) => void): Q.IPromise<void> {
+    if (arg === 'Xception') {
+      var x = new ttypes.Xception();
+      x.errorCode = 1001;
+      x.message = arg;
+      result(x);
+    } else if (arg === 'TException') {
+      result(new Thrift.TException(arg));
+    } else {
+      result(null);
+    }
+    return Q.resolve();
+  }
+  testMultiException(arg0: string, arg1: string, result: (err: any, res?: ttypes.Xtruct) => void): Q.IPromise<ttypes.Xtruct> {
+    if (arg0 === ('Xception')) {
+      var x = new ttypes.Xception();
+      x.errorCode = 1001;
+      x.message = 'This is an Xception';
+      result(x);
+    } else if (arg0 === ('Xception2')) {
+      var x2 = new ttypes.Xception2();
+      x2.errorCode = 2002;
+      x2.struct_thing = new ttypes.Xtruct();
+      x2.struct_thing.string_thing = 'This is an Xception2';
+      result(x2);
+    } else {
+      var res = new ttypes.Xtruct();
+      res.string_thing = arg1;
+      result(null, res);
+    }
+    return Q.resolve();
+  }
+  testOneway(sleepFor: number, result: Function) {
+    this.syncHandler.testOneway(sleepFor);
+  }
+  testString(thing: string, callback: (err: any, result: string) => void): Q.IPromise<string> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testByte(thing: number, callback: (err: any, result: number) => void): Q.IPromise<number> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testBool(thing: boolean, callback: (err: any, result: boolean) => void ): Q.IPromise<boolean> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testI32(thing: number, callback: (err: any, result: number) => void): Q.IPromise<number>  {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testI64(thing: number, callback: (err: any, result: number) => void): Q.IPromise<number>  {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testDouble(thing: number, callback: (err: any, result: number) => void): Q.IPromise<number>  {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testBinary(thing: Buffer, callback: (err: any, result: Buffer) => void): Q.IPromise<Buffer> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testStruct(thing: ttypes.Xtruct, callback: (err: any, result: ttypes.Xtruct) => void): Q.IPromise<ttypes.Xtruct> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testNest(thing: ttypes.Xtruct2, callback: (err: any, result: ttypes.Xtruct2) => void): Q.IPromise<ttypes.Xtruct2> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testMap(thing: { [k: number]: number; }, callback: (err: any, result: { [k: number]: number; }) => void): Q.IPromise<{ [k: number]: number; }> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testStringMap(thing: { [k: string]: string; }, callback: (err: any, result: { [k: string]: string; }) => void): Q.IPromise<{ [k: string]: string; }> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testSet(thing: number[], callback: (err: any, result: number[]) => void): Q.IPromise<number[]> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testList(thing: number[], callback: (err: any, result: number[]) => void): Q.IPromise<number[]> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testEnum(thing: ttypes.Numberz, callback: (err: any, result: ttypes.Numberz) => void): Q.IPromise<ttypes.Numberz> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+  testTypedef(thing: number, callback: (err: any, result: number) => void): Q.IPromise<number> {
+    callback(null, thing);
+    return Q.resolve();
+  }
+}
diff --git a/lib/nodets/test/tsconfig.json b/lib/nodets/test/tsconfig.json
new file mode 100644
index 0000000..029d06d
--- /dev/null
+++ b/lib/nodets/test/tsconfig.json
@@ -0,0 +1,22 @@
+{
+    "compilerOptions": {
+        "allowJs": false,
+        "alwaysStrict": true,
+        "baseUrl": ".",
+        "declaration": true,
+        "emitDecoratorMetadata": true,
+        "experimentalDecorators": true,
+        "module": "commonjs",
+        "moduleResolution": "node",
+        "noImplicitThis": true,
+        "noUnusedLocals": true,
+        "preserveConstEnums": true,
+        "removeComments": true,
+        "strictFunctionTypes": true,
+        "strictNullChecks": true,
+        "target": "es6",
+        "paths": {
+            "thrift": ["../../nodejs/lib/thrift"]
+        }
+    }
+}
diff --git a/lib/ocaml/.gitignore b/lib/ocaml/.gitignore
new file mode 100644
index 0000000..0d9a6af
--- /dev/null
+++ b/lib/ocaml/.gitignore
@@ -0,0 +1,11 @@
+_build/
+_tags
+configure
+setup.data
+setup.ml
+myocamlbuild.ml
+*/META
+*/*.mllib
+*/*.mldylib
+Makefile
+OCamlMakefile
diff --git a/lib/ocaml/DEVELOPMENT b/lib/ocaml/DEVELOPMENT
new file mode 100644
index 0000000..3d5a03c
--- /dev/null
+++ b/lib/ocaml/DEVELOPMENT
@@ -0,0 +1,76 @@
+Thrift OCaml Development
+========================
+
+Prerequisites
+-------------
+
+In order to build this library, you must have the following installed:
+
+  * The OCaml compiler, preferably >4.00
+  * The Oasis build tool
+
+In addition you may want to install OPAM, which will allow you to setup an
+OCaml development environment that's isolated from your system installation,
+much like virutalenv for Python or the myriad systems available for Ruby. If
+you have OPAM installed, then installing Oasis is as simple as running:
+
+  $ opam install oasis
+
+Building
+--------
+
+Once all the prerequisites have been installed, run the following commands:
+
+  $ oasis setup
+  $ ./configure
+  $ make
+
+The `oasis setup` command will generate the configure script and Makefile,
+along with other files that opam will use to create an installable library.
+The cofigure script will ensure that all build dependencies are installed, and
+make will actually build the library.
+
+To remove files that the compiler geneates, run:
+
+  $ make clean
+
+To remove those files _as well as_ files that the setup and configure process
+generates, run:
+
+  $ rm `cat .gitignore`
+
+Installing
+----------
+
+If you're using opam, simply run the following command:
+
+  $ make install
+
+While development, you may want to install your latest build on the system to
+test against other libraries or programs. To do this, use:
+
+  $ make reinstall
+
+Distribution
+------------
+
+The de facto preferred method for distributing OCaml libraries is through the
+OPAM package repository. To publish the latest package, issue a pull request
+against the following github repository:
+
+  https://github.com/ocaml/opam-repository
+
+The pull requestion should add the following directory structure and files:
+
+  package
+    |__thrift
+       |__thrift.<VERSION>
+          |__ descr
+          |__ opam
+          |__ url
+
+Templates for the following files can be found in the opam/ subdirectory of
+this library's root, with XXX(...) indicating fields that need to be filled
+out. You can find further documentation here:
+
+  http://opam.ocaml.org/doc/Packaging.html
diff --git a/lib/ocaml/Makefile b/lib/ocaml/Makefile
deleted file mode 100644
index 6abeee7..0000000
--- a/lib/ocaml/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-all:
-	cd src; make; cd ..
-clean:
-	cd src; make clean; cd ..
diff --git a/lib/ocaml/OCamlMakefile b/lib/ocaml/OCamlMakefile
deleted file mode 100644
index b0b9252..0000000
--- a/lib/ocaml/OCamlMakefile
+++ /dev/null
@@ -1,1231 +0,0 @@
-###########################################################################
-#                              OCamlMakefile
-#                  Copyright (C) 1999-2007  Markus Mottl
-#
-#                             For updates see:
-#                http://www.ocaml.info/home/ocaml_sources.html
-#
-###########################################################################
-
-# Modified by damien for .glade.ml compilation
-
-# Set these variables to the names of the sources to be processed and
-# the result variable. Order matters during linkage!
-
-ifndef SOURCES
-  SOURCES := foo.ml
-endif
-export SOURCES
-
-ifndef RES_CLIB_SUF
-  RES_CLIB_SUF := _stubs
-endif
-export RES_CLIB_SUF
-
-ifndef RESULT
-  RESULT := foo
-endif
-export RESULT := $(strip $(RESULT))
-
-export LIB_PACK_NAME
-
-ifndef DOC_FILES
-  DOC_FILES := $(filter %.mli, $(SOURCES))
-endif
-export DOC_FILES
-FIRST_DOC_FILE := $(firstword $(DOC_FILES))
-
-export BCSUFFIX
-export NCSUFFIX
-
-ifndef TOPSUFFIX
-  TOPSUFFIX := .top
-endif
-export TOPSUFFIX
-
-# Eventually set include- and library-paths, libraries to link,
-# additional compilation-, link- and ocamlyacc-flags
-# Path- and library information needs not be written with "-I" and such...
-# Define THREADS if you need it, otherwise leave it unset (same for
-# USE_CAMLP4)!
-
-export THREADS
-export VMTHREADS
-export ANNOTATE
-export USE_CAMLP4
-
-export INCDIRS
-export LIBDIRS
-export EXTLIBDIRS
-export RESULTDEPS
-export OCAML_DEFAULT_DIRS
-
-export LIBS
-export CLIBS
-export CFRAMEWORKS
-
-export OCAMLFLAGS
-export OCAMLNCFLAGS
-export OCAMLBCFLAGS
-
-export OCAMLLDFLAGS
-export OCAMLNLDFLAGS
-export OCAMLBLDFLAGS
-
-export OCAMLMKLIB_FLAGS
-
-ifndef OCAMLCPFLAGS
-  OCAMLCPFLAGS := a
-endif
-export OCAMLCPFLAGS
-
-ifndef DOC_DIR
-  DOC_DIR := doc
-endif
-export DOC_DIR
-
-export PPFLAGS
-
-export LFLAGS
-export YFLAGS
-export IDLFLAGS
-
-export OCAMLDOCFLAGS
-
-export OCAMLFIND_INSTFLAGS
-
-export DVIPSFLAGS
-
-export STATIC
-
-# Add a list of optional trash files that should be deleted by "make clean"
-export TRASH
-
-ECHO := echo
-
-ifdef REALLY_QUIET
-  export REALLY_QUIET
-  ECHO := true
-  LFLAGS := $(LFLAGS) -q
-  YFLAGS := $(YFLAGS) -q
-endif
-
-####################  variables depending on your OCaml-installation
-
-ifdef MINGW
-  export MINGW
-  WIN32   := 1
-  CFLAGS_WIN32 := -mno-cygwin
-endif
-ifdef MSVC
-  export MSVC
-  WIN32   := 1
-  ifndef STATIC
-    CPPFLAGS_WIN32 := -DCAML_DLL
-  endif
-  CFLAGS_WIN32 += -nologo
-  EXT_OBJ := obj
-  EXT_LIB := lib
-  ifeq ($(CC),gcc)
-    # work around GNU Make default value
-    ifdef THREADS
-      CC := cl -MT
-    else
-      CC := cl
-    endif
-  endif
-  ifeq ($(CXX),g++)
-    # work around GNU Make default value
-    CXX := $(CC)
-  endif
-  CFLAG_O := -Fo
-endif
-ifdef WIN32
-  EXT_CXX := cpp
-  EXE     := .exe
-endif
-
-ifndef EXT_OBJ
-  EXT_OBJ := o
-endif
-ifndef EXT_LIB
-  EXT_LIB := a
-endif
-ifndef EXT_CXX
-  EXT_CXX := cc
-endif
-ifndef EXE
-  EXE := # empty
-endif
-ifndef CFLAG_O
-  CFLAG_O := -o # do not delete this comment (preserves trailing whitespace)!
-endif
-
-export CC
-export CXX
-export CFLAGS
-export CXXFLAGS
-export LDFLAGS
-export CPPFLAGS
-
-ifndef RPATH_FLAG
-  ifdef ELF_RPATH_FLAG
-    RPATH_FLAG := $(ELF_RPATH_FLAG)
-  else
-    RPATH_FLAG := -R
-  endif
-endif
-export RPATH_FLAG
-
-ifndef MSVC
-ifndef PIC_CFLAGS
-  PIC_CFLAGS := -fPIC
-endif
-ifndef PIC_CPPFLAGS
-  PIC_CPPFLAGS := -DPIC
-endif
-endif
-
-export PIC_CFLAGS
-export PIC_CPPFLAGS
-
-BCRESULT  := $(addsuffix $(BCSUFFIX), $(RESULT))
-NCRESULT  := $(addsuffix $(NCSUFFIX), $(RESULT))
-TOPRESULT := $(addsuffix $(TOPSUFFIX), $(RESULT))
-
-ifndef OCAMLFIND
-  OCAMLFIND := ocamlfind
-endif
-export OCAMLFIND
-
-ifndef OCAMLC
-  OCAMLC := ocamlc
-endif
-export OCAMLC
-
-ifndef OCAMLOPT
-  OCAMLOPT := ocamlopt
-endif
-export OCAMLOPT
-
-ifndef OCAMLMKTOP
-  OCAMLMKTOP := ocamlmktop
-endif
-export OCAMLMKTOP
-
-ifndef OCAMLCP
-  OCAMLCP := ocamlcp
-endif
-export OCAMLCP
-
-ifndef OCAMLDEP
-  OCAMLDEP := ocamldep
-endif
-export OCAMLDEP
-
-ifndef OCAMLLEX
-  OCAMLLEX := ocamllex
-endif
-export OCAMLLEX
-
-ifndef OCAMLYACC
-  OCAMLYACC := ocamlyacc
-endif
-export OCAMLYACC
-
-ifndef OCAMLMKLIB
-  OCAMLMKLIB := ocamlmklib
-endif
-export OCAMLMKLIB
-
-ifndef OCAML_GLADECC
-  OCAML_GLADECC := lablgladecc2
-endif
-export OCAML_GLADECC
-
-ifndef OCAML_GLADECC_FLAGS
-  OCAML_GLADECC_FLAGS :=
-endif
-export OCAML_GLADECC_FLAGS
-
-ifndef CAMELEON_REPORT
-  CAMELEON_REPORT := report
-endif
-export CAMELEON_REPORT
-
-ifndef CAMELEON_REPORT_FLAGS
-  CAMELEON_REPORT_FLAGS :=
-endif
-export CAMELEON_REPORT_FLAGS
-
-ifndef CAMELEON_ZOGGY
-  CAMELEON_ZOGGY := camlp4o pa_zog.cma pr_o.cmo
-endif
-export CAMELEON_ZOGGY
-
-ifndef CAMELEON_ZOGGY_FLAGS
-  CAMELEON_ZOGGY_FLAGS :=
-endif
-export CAMELEON_ZOGGY_FLAGS
-
-ifndef OXRIDL
-  OXRIDL := oxridl
-endif
-export OXRIDL
-
-ifndef CAMLIDL
-  CAMLIDL := camlidl
-endif
-export CAMLIDL
-
-ifndef CAMLIDLDLL
-  CAMLIDLDLL := camlidldll
-endif
-export CAMLIDLDLL
-
-ifndef NOIDLHEADER
-  MAYBE_IDL_HEADER := -header
-endif
-export NOIDLHEADER
-
-export NO_CUSTOM
-
-ifndef CAMLP4
-  CAMLP4 := camlp4
-endif
-export CAMLP4
-
-ifndef REAL_OCAMLFIND
-  ifdef PACKS
-    ifndef CREATE_LIB
-      ifdef THREADS
-	PACKS += threads
-      endif
-    endif
-    empty :=
-    space := $(empty) $(empty)
-    comma := ,
-    ifdef PREDS
-      PRE_OCAML_FIND_PREDICATES := $(subst $(space),$(comma),$(PREDS))
-      PRE_OCAML_FIND_PACKAGES := $(subst $(space),$(comma),$(PACKS))
-      OCAML_FIND_PREDICATES := -predicates $(PRE_OCAML_FIND_PREDICATES)
-  #    OCAML_DEP_PREDICATES := -syntax $(PRE_OCAML_FIND_PREDICATES)
-      OCAML_FIND_PACKAGES := $(OCAML_FIND_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES)
-      OCAML_DEP_PACKAGES := $(OCAML_DEP_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES)
-    else
-      OCAML_FIND_PACKAGES := -package $(subst $(space),$(comma),$(PACKS))
-      OCAML_DEP_PACKAGES :=
-    endif
-    OCAML_FIND_LINKPKG := -linkpkg
-    REAL_OCAMLFIND := $(OCAMLFIND)
-  endif
-endif
-
-export OCAML_FIND_PACKAGES
-export OCAML_DEP_PACKAGES
-export OCAML_FIND_LINKPKG
-export REAL_OCAMLFIND
-
-ifndef OCAMLDOC
-  OCAMLDOC := ocamldoc
-endif
-export OCAMLDOC
-
-ifndef LATEX
-  LATEX := latex
-endif
-export LATEX
-
-ifndef DVIPS
-  DVIPS := dvips
-endif
-export DVIPS
-
-ifndef PS2PDF
-  PS2PDF := ps2pdf
-endif
-export PS2PDF
-
-ifndef OCAMLMAKEFILE
-  OCAMLMAKEFILE := OCamlMakefile
-endif
-export OCAMLMAKEFILE
-
-ifndef OCAMLLIBPATH
-  OCAMLLIBPATH := \
-    $(shell $(OCAMLC) 2>/dev/null -where || echo /usr/local/lib/ocaml)
-endif
-export OCAMLLIBPATH
-
-ifndef OCAML_LIB_INSTALL
-  OCAML_LIB_INSTALL := $(OCAMLLIBPATH)/contrib
-endif
-export OCAML_LIB_INSTALL
-
-###########################################################################
-
-####################  change following sections only if
-####################    you know what you are doing!
-
-# delete target files when a build command fails
-.PHONY: .DELETE_ON_ERROR
-.DELETE_ON_ERROR:
-
-# for pedants using "--warn-undefined-variables"
-export MAYBE_IDL
-export REAL_RESULT
-export CAMLIDLFLAGS
-export THREAD_FLAG
-export RES_CLIB
-export MAKEDLL
-export ANNOT_FLAG
-export C_OXRIDL
-export SUBPROJS
-export CFLAGS_WIN32
-export CPPFLAGS_WIN32
-
-INCFLAGS :=
-
-SHELL := /bin/sh
-
-MLDEPDIR := ._d
-BCDIDIR  := ._bcdi
-NCDIDIR  := ._ncdi
-
-FILTER_EXTNS := %.mli %.ml %.mll %.mly %.idl %.oxridl %.c %.m %.$(EXT_CXX) %.rep %.zog %.glade
-
-FILTERED     := $(filter $(FILTER_EXTNS), $(SOURCES))
-SOURCE_DIRS  := $(filter-out ./, $(sort $(dir $(FILTERED))))
-
-FILTERED_REP := $(filter %.rep, $(FILTERED))
-DEP_REP      := $(FILTERED_REP:%.rep=$(MLDEPDIR)/%.d)
-AUTO_REP     := $(FILTERED_REP:.rep=.ml)
-
-FILTERED_ZOG := $(filter %.zog, $(FILTERED))
-DEP_ZOG      := $(FILTERED_ZOG:%.zog=$(MLDEPDIR)/%.d)
-AUTO_ZOG     := $(FILTERED_ZOG:.zog=.ml)
-
-FILTERED_GLADE := $(filter %.glade, $(FILTERED))
-DEP_GLADE      := $(FILTERED_GLADE:%.glade=$(MLDEPDIR)/%.d)
-AUTO_GLADE     := $(FILTERED_GLADE:.glade=.ml)
-
-FILTERED_ML  := $(filter %.ml, $(FILTERED))
-DEP_ML       := $(FILTERED_ML:%.ml=$(MLDEPDIR)/%.d)
-
-FILTERED_MLI := $(filter %.mli, $(FILTERED))
-DEP_MLI      := $(FILTERED_MLI:.mli=.di)
-
-FILTERED_MLL := $(filter %.mll, $(FILTERED))
-DEP_MLL      := $(FILTERED_MLL:%.mll=$(MLDEPDIR)/%.d)
-AUTO_MLL     := $(FILTERED_MLL:.mll=.ml)
-
-FILTERED_MLY := $(filter %.mly, $(FILTERED))
-DEP_MLY      := $(FILTERED_MLY:%.mly=$(MLDEPDIR)/%.d) $(FILTERED_MLY:.mly=.di)
-AUTO_MLY     := $(FILTERED_MLY:.mly=.mli) $(FILTERED_MLY:.mly=.ml)
-
-FILTERED_IDL := $(filter %.idl, $(FILTERED))
-DEP_IDL      := $(FILTERED_IDL:%.idl=$(MLDEPDIR)/%.d) $(FILTERED_IDL:.idl=.di)
-C_IDL        := $(FILTERED_IDL:%.idl=%_stubs.c)
-ifndef NOIDLHEADER
- C_IDL += $(FILTERED_IDL:.idl=.h)
-endif
-OBJ_C_IDL    := $(FILTERED_IDL:%.idl=%_stubs.$(EXT_OBJ))
-AUTO_IDL     := $(FILTERED_IDL:.idl=.mli) $(FILTERED_IDL:.idl=.ml) $(C_IDL)
-
-FILTERED_OXRIDL := $(filter %.oxridl, $(FILTERED))
-DEP_OXRIDL      := $(FILTERED_OXRIDL:%.oxridl=$(MLDEPDIR)/%.d) $(FILTERED_OXRIDL:.oxridl=.di)
-AUTO_OXRIDL     := $(FILTERED_OXRIDL:.oxridl=.mli) $(FILTERED_OXRIDL:.oxridl=.ml) $(C_OXRIDL)
-
-FILTERED_C_CXX := $(filter %.c %.m %.$(EXT_CXX), $(FILTERED))
-OBJ_C_CXX      := $(FILTERED_C_CXX:.c=.$(EXT_OBJ))
-OBJ_C_CXX      := $(OBJ_C_CXX:.m=.$(EXT_OBJ))
-OBJ_C_CXX      := $(OBJ_C_CXX:.$(EXT_CXX)=.$(EXT_OBJ))
-
-PRE_TARGETS  += $(AUTO_MLL) $(AUTO_MLY) $(AUTO_IDL) $(AUTO_OXRIDL) $(AUTO_ZOG) $(AUTO_REP) $(AUTO_GLADE)
-
-ALL_DEPS     := $(DEP_ML) $(DEP_MLI) $(DEP_MLL) $(DEP_MLY) $(DEP_IDL) $(DEP_OXRIDL) $(DEP_ZOG) $(DEP_REP) $(DEP_GLADE)
-
-MLDEPS       := $(filter %.d, $(ALL_DEPS))
-MLIDEPS      := $(filter %.di, $(ALL_DEPS))
-BCDEPIS      := $(MLIDEPS:%.di=$(BCDIDIR)/%.di)
-NCDEPIS      := $(MLIDEPS:%.di=$(NCDIDIR)/%.di)
-
-ALLML        := $(filter %.mli %.ml %.mll %.mly %.idl %.oxridl %.rep %.zog %.glade, $(FILTERED))
-
-IMPLO_INTF   := $(ALLML:%.mli=%.mli.__)
-IMPLO_INTF   := $(foreach file, $(IMPLO_INTF), \
-                  $(basename $(file)).cmi $(basename $(file)).cmo)
-IMPLO_INTF   := $(filter-out %.mli.cmo, $(IMPLO_INTF))
-IMPLO_INTF   := $(IMPLO_INTF:%.mli.cmi=%.cmi)
-
-IMPLX_INTF   := $(IMPLO_INTF:.cmo=.cmx)
-
-INTF         := $(filter %.cmi, $(IMPLO_INTF))
-IMPL_CMO     := $(filter %.cmo, $(IMPLO_INTF))
-IMPL_CMX     := $(IMPL_CMO:.cmo=.cmx)
-IMPL_ASM     := $(IMPL_CMO:.cmo=.asm)
-IMPL_S       := $(IMPL_CMO:.cmo=.s)
-
-OBJ_LINK     := $(OBJ_C_IDL) $(OBJ_C_CXX)
-OBJ_FILES    := $(IMPL_CMO:.cmo=.$(EXT_OBJ)) $(OBJ_LINK)
-
-EXECS        := $(addsuffix $(EXE), \
-                            $(sort $(TOPRESULT) $(BCRESULT) $(NCRESULT)))
-ifdef WIN32
-  EXECS      += $(BCRESULT).dll $(NCRESULT).dll
-endif
-
-CLIB_BASE    := $(RESULT)$(RES_CLIB_SUF)
-ifneq ($(strip $(OBJ_LINK)),)
-  RES_CLIB     := lib$(CLIB_BASE).$(EXT_LIB)
-endif
-
-ifdef WIN32
-DLLSONAME := $(CLIB_BASE).dll
-else
-DLLSONAME := dll$(CLIB_BASE).so
-endif
-
-NONEXECS     := $(INTF) $(IMPL_CMO) $(IMPL_CMX) $(IMPL_ASM) $(IMPL_S) \
-		$(OBJ_FILES) $(PRE_TARGETS) $(BCRESULT).cma $(NCRESULT).cmxa \
-		$(NCRESULT).$(EXT_LIB) $(BCRESULT).cmi $(BCRESULT).cmo \
-		$(NCRESULT).cmi $(NCRESULT).cmx $(NCRESULT).o \
-		$(RES_CLIB) $(IMPL_CMO:.cmo=.annot) \
-		$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(LIB_PACK_NAME).cmx $(LIB_PACK_NAME).o
-
-ifndef STATIC
-  NONEXECS += $(DLLSONAME)
-endif
-
-ifndef LIBINSTALL_FILES
-  LIBINSTALL_FILES := $(RESULT).mli $(RESULT).cmi $(RESULT).cma \
-		      $(RESULT).cmxa $(RESULT).$(EXT_LIB) $(RES_CLIB)
-  ifndef STATIC
-    ifneq ($(strip $(OBJ_LINK)),)
-      LIBINSTALL_FILES += $(DLLSONAME)
-    endif
-  endif
-endif
-
-export LIBINSTALL_FILES
-
-ifdef WIN32
-  # some extra stuff is created while linking DLLs
-  NONEXECS   += $(BCRESULT).$(EXT_LIB) $(BCRESULT).exp $(NCRESULT).exp $(CLIB_BASE).exp $(CLIB_BASE).lib
-endif
-
-TARGETS      := $(EXECS) $(NONEXECS)
-
-# If there are IDL-files
-ifneq ($(strip $(FILTERED_IDL)),)
-  MAYBE_IDL := -cclib -lcamlidl
-endif
-
-ifdef USE_CAMLP4
-  CAMLP4PATH := \
-    $(shell $(CAMLP4) -where 2>/dev/null || echo /usr/local/lib/camlp4)
-  INCFLAGS := -I $(CAMLP4PATH)
-  CINCFLAGS := -I$(CAMLP4PATH)
-endif
-
-DINCFLAGS := $(INCFLAGS) $(SOURCE_DIRS:%=-I %) $(OCAML_DEFAULT_DIRS:%=-I %)
-INCFLAGS := $(DINCFLAGS) $(INCDIRS:%=-I %)
-CINCFLAGS += $(SOURCE_DIRS:%=-I%) $(INCDIRS:%=-I%) $(OCAML_DEFAULT_DIRS:%=-I%)
-
-ifndef MSVC
-  CLIBFLAGS += $(SOURCE_DIRS:%=-L%) $(LIBDIRS:%=-L%) \
-               $(EXTLIBDIRS:%=-L%) $(OCAML_DEFAULT_DIRS:%=-L%)
-
-  ifeq ($(ELF_RPATH), yes)
-    CLIBFLAGS += $(EXTLIBDIRS:%=-Wl,$(RPATH_FLAG)%)
-  endif
-endif
-
-ifndef PROFILING
-  INTF_OCAMLC := $(OCAMLC)
-else
-  ifndef THREADS
-    INTF_OCAMLC := $(OCAMLCP) -p $(OCAMLCPFLAGS)
-  else
-    # OCaml does not support profiling byte code
-    # with threads (yet), therefore we force an error.
-    ifndef REAL_OCAMLC
-      $(error Profiling of multithreaded byte code not yet supported by OCaml)
-    endif
-    INTF_OCAMLC := $(OCAMLC)
-  endif
-endif
-
-ifndef MSVC
-  COMMON_LDFLAGS := $(LDFLAGS:%=-ccopt %) $(SOURCE_DIRS:%=-ccopt -L%) \
-		    $(LIBDIRS:%=-ccopt -L%) $(EXTLIBDIRS:%=-ccopt -L%) \
-		    $(EXTLIBDIRS:%=-ccopt -Wl $(OCAML_DEFAULT_DIRS:%=-ccopt -L%))
-
-  ifeq ($(ELF_RPATH),yes)
-    COMMON_LDFLAGS += $(EXTLIBDIRS:%=-ccopt -Wl,$(RPATH_FLAG)%)
-  endif
-else
-  COMMON_LDFLAGS := -ccopt "/link -NODEFAULTLIB:LIBC $(LDFLAGS:%=%) $(SOURCE_DIRS:%=-LIBPATH:%) \
-		    $(LIBDIRS:%=-LIBPATH:%) $(EXTLIBDIRS:%=-LIBPATH:%) \
-		    $(OCAML_DEFAULT_DIRS:%=-LIBPATH:%) "
-endif
-
-CLIBS_OPTS := $(CLIBS:%=-cclib -l%) $(CFRAMEWORKS:%=-cclib '-framework %')
-ifdef MSVC
-  ifndef STATIC
-  # MSVC libraries do not have 'lib' prefix
-  CLIBS_OPTS := $(CLIBS:%=-cclib %.lib)
-  endif
-endif
-
-ifneq ($(strip $(OBJ_LINK)),)
-  ifdef CREATE_LIB
-    OBJS_LIBS := -cclib -l$(CLIB_BASE) $(CLIBS_OPTS) $(MAYBE_IDL)
-  else
-    OBJS_LIBS := $(OBJ_LINK) $(CLIBS_OPTS) $(MAYBE_IDL)
-  endif
-else
-  OBJS_LIBS := $(CLIBS_OPTS) $(MAYBE_IDL)
-endif
-
-# If we have to make byte-code
-ifndef REAL_OCAMLC
-  BYTE_OCAML := y
-
-  # EXTRADEPS is added dependencies we have to insert for all
-  # executable files we generate.  Ideally it should be all of the
-  # libraries we use, but it's hard to find the ones that get searched on
-  # the path since I don't know the paths built into the compiler, so
-  # just include the ones with slashes in their names.
-  EXTRADEPS := $(addsuffix .cma,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i))))
-  SPECIAL_OCAMLFLAGS := $(OCAMLBCFLAGS)
-
-  REAL_OCAMLC := $(INTF_OCAMLC)
-
-  REAL_IMPL := $(IMPL_CMO)
-  REAL_IMPL_INTF := $(IMPLO_INTF)
-  IMPL_SUF := .cmo
-
-  DEPFLAGS  :=
-  MAKE_DEPS := $(MLDEPS) $(BCDEPIS)
-
-  ifdef CREATE_LIB
-    override CFLAGS := $(PIC_CFLAGS) $(CFLAGS)
-    override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS)
-    ifndef STATIC
-      ifneq ($(strip $(OBJ_LINK)),)
-	MAKEDLL := $(DLLSONAME)
-	ALL_LDFLAGS := -dllib $(DLLSONAME)
-      endif
-    endif
-  endif
-
-  ifndef NO_CUSTOM
-    ifneq "$(strip $(OBJ_LINK) $(THREADS) $(MAYBE_IDL) $(CLIBS) $(CFRAMEWORKS))" ""
-      ALL_LDFLAGS += -custom
-    endif
-  endif
-
-  ALL_LDFLAGS += $(INCFLAGS) $(OCAMLLDFLAGS) $(OCAMLBLDFLAGS) \
-                 $(COMMON_LDFLAGS) $(LIBS:%=%.cma)
-  CAMLIDLDLLFLAGS :=
-
-  ifdef THREADS
-    ifdef VMTHREADS
-      THREAD_FLAG := -vmthread
-    else
-      THREAD_FLAG := -thread
-    endif
-    ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS)
-    ifndef CREATE_LIB
-      ifndef REAL_OCAMLFIND
-        ALL_LDFLAGS := unix.cma threads.cma $(ALL_LDFLAGS)
-      endif
-    endif
-  endif
-
-# we have to make native-code
-else
-  EXTRADEPS := $(addsuffix .cmxa,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i))))
-  ifndef PROFILING
-    SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS)
-    PLDFLAGS :=
-  else
-    SPECIAL_OCAMLFLAGS := -p $(OCAMLNCFLAGS)
-    PLDFLAGS := -p
-  endif
-
-  REAL_IMPL := $(IMPL_CMX)
-  REAL_IMPL_INTF := $(IMPLX_INTF)
-  IMPL_SUF := .cmx
-
-  override CPPFLAGS := -DNATIVE_CODE $(CPPFLAGS)
-
-  DEPFLAGS  := -native
-  MAKE_DEPS := $(MLDEPS) $(NCDEPIS)
-
-  ALL_LDFLAGS := $(PLDFLAGS) $(INCFLAGS) $(OCAMLLDFLAGS) \
-                 $(OCAMLNLDFLAGS) $(COMMON_LDFLAGS)
-  CAMLIDLDLLFLAGS := -opt
-
-  ifndef CREATE_LIB
-    ALL_LDFLAGS += $(LIBS:%=%.cmxa)
-  else
-    override CFLAGS := $(PIC_CFLAGS) $(CFLAGS)
-    override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS)
-  endif
-
-  ifdef THREADS
-    THREAD_FLAG := -thread
-    ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS)
-    ifndef CREATE_LIB
-      ifndef REAL_OCAMLFIND
-        ALL_LDFLAGS := unix.cmxa threads.cmxa $(ALL_LDFLAGS)
-      endif
-    endif
-  endif
-endif
-
-export MAKE_DEPS
-
-ifdef ANNOTATE
-  ANNOT_FLAG := -dtypes
-else
-endif
-
-ALL_OCAMLCFLAGS := $(THREAD_FLAG) $(ANNOT_FLAG) $(OCAMLFLAGS) \
-                   $(INCFLAGS) $(SPECIAL_OCAMLFLAGS)
-
-ifdef make_deps
-  -include $(MAKE_DEPS)
-  PRE_TARGETS :=
-endif
-
-###########################################################################
-# USER RULES
-
-# Call "OCamlMakefile QUIET=" to get rid of all of the @'s.
-QUIET=@
-
-# generates byte-code (default)
-byte-code:		$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
-				REAL_RESULT="$(BCRESULT)" make_deps=yes
-bc:	byte-code
-
-byte-code-nolink:	$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
-				REAL_RESULT="$(BCRESULT)" make_deps=yes
-bcnl:	byte-code-nolink
-
-top:			$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(TOPRESULT) \
-				REAL_RESULT="$(BCRESULT)" make_deps=yes
-
-# generates native-code
-
-native-code:		$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \
-				REAL_RESULT="$(NCRESULT)" \
-				REAL_OCAMLC="$(OCAMLOPT)" \
-				make_deps=yes
-nc:	native-code
-
-native-code-nolink:	$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
-				REAL_RESULT="$(NCRESULT)" \
-				REAL_OCAMLC="$(OCAMLOPT)" \
-				make_deps=yes
-ncnl:	native-code-nolink
-
-# generates byte-code libraries
-byte-code-library:	$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
-				$(RES_CLIB) $(BCRESULT).cma \
-				REAL_RESULT="$(BCRESULT)" \
-				CREATE_LIB=yes \
-				make_deps=yes
-bcl:	byte-code-library
-
-# generates native-code libraries
-native-code-library:	$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
-				$(RES_CLIB) $(NCRESULT).cmxa \
-				REAL_RESULT="$(NCRESULT)" \
-				REAL_OCAMLC="$(OCAMLOPT)" \
-				CREATE_LIB=yes \
-				make_deps=yes
-ncl:	native-code-library
-
-ifdef WIN32
-# generates byte-code dll
-byte-code-dll:		$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
-				$(RES_CLIB) $(BCRESULT).dll \
-				REAL_RESULT="$(BCRESULT)" \
-				make_deps=yes
-bcd:	byte-code-dll
-
-# generates native-code dll
-native-code-dll:	$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
-				$(RES_CLIB) $(NCRESULT).dll \
-				REAL_RESULT="$(NCRESULT)" \
-				REAL_OCAMLC="$(OCAMLOPT)" \
-				make_deps=yes
-ncd:	native-code-dll
-endif
-
-# generates byte-code with debugging information
-debug-code:		$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
-				REAL_RESULT="$(BCRESULT)" make_deps=yes \
-				OCAMLFLAGS="-g $(OCAMLFLAGS)" \
-				OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
-dc:	debug-code
-
-debug-code-nolink:	$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
-				REAL_RESULT="$(BCRESULT)" make_deps=yes \
-				OCAMLFLAGS="-g $(OCAMLFLAGS)" \
-				OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
-dcnl:	debug-code-nolink
-
-# generates byte-code with debugging information (native code)
-debug-native-code:	$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \
-				REAL_RESULT="$(NCRESULT)" make_deps=yes \
-				REAL_OCAMLC="$(OCAMLOPT)" \
-				OCAMLFLAGS="-g $(OCAMLFLAGS)" \
-				OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
-dnc:	debug-native-code
-
-debug-native-code-nolink:	$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
-				REAL_RESULT="$(NCRESULT)" make_deps=yes \
-				REAL_OCAMLC="$(OCAMLOPT)" \
-				OCAMLFLAGS="-g $(OCAMLFLAGS)" \
-				OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
-dncnl:	debug-native-code-nolink
-
-# generates byte-code libraries with debugging information
-debug-code-library:	$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
-				$(RES_CLIB) $(BCRESULT).cma \
-				REAL_RESULT="$(BCRESULT)" make_deps=yes \
-				CREATE_LIB=yes \
-				OCAMLFLAGS="-g $(OCAMLFLAGS)" \
-				OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
-dcl:	debug-code-library
-
-# generates byte-code libraries with debugging information (native code)
-debug-native-code-library:	$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
-				$(RES_CLIB) $(NCRESULT).cma \
-				REAL_RESULT="$(NCRESULT)" make_deps=yes \
-				REAL_OCAMLC="$(OCAMLOPT)" \
-				CREATE_LIB=yes \
-				OCAMLFLAGS="-g $(OCAMLFLAGS)" \
-				OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
-dncl:	debug-native-code-library
-
-# generates byte-code for profiling
-profiling-byte-code:		$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
-				REAL_RESULT="$(BCRESULT)" PROFILING="y" \
-				make_deps=yes
-pbc:	profiling-byte-code
-
-# generates native-code
-
-profiling-native-code:		$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \
-				REAL_RESULT="$(NCRESULT)" \
-				REAL_OCAMLC="$(OCAMLOPT)" \
-				PROFILING="y" \
-				make_deps=yes
-pnc:	profiling-native-code
-
-# generates byte-code libraries
-profiling-byte-code-library:	$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
-				$(RES_CLIB) $(BCRESULT).cma \
-				REAL_RESULT="$(BCRESULT)" PROFILING="y" \
-				CREATE_LIB=yes \
-				make_deps=yes
-pbcl:	profiling-byte-code-library
-
-# generates native-code libraries
-profiling-native-code-library:	$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
-				$(RES_CLIB) $(NCRESULT).cmxa \
-				REAL_RESULT="$(NCRESULT)" PROFILING="y" \
-				REAL_OCAMLC="$(OCAMLOPT)" \
-				CREATE_LIB=yes \
-				make_deps=yes
-pncl:	profiling-native-code-library
-
-# packs byte-code objects
-pack-byte-code:			$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT).cmo \
-				REAL_RESULT="$(BCRESULT)" \
-				PACK_LIB=yes make_deps=yes
-pabc:	pack-byte-code
-
-# packs native-code objects
-pack-native-code:		$(PRE_TARGETS)
-			$(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
-				$(NCRESULT).cmx $(NCRESULT).o \
-				REAL_RESULT="$(NCRESULT)" \
-				REAL_OCAMLC="$(OCAMLOPT)" \
-				PACK_LIB=yes make_deps=yes
-panc:	pack-native-code
-
-# generates HTML-documentation
-htdoc:	$(DOC_DIR)/$(RESULT)/html/index.html
-
-# generates Latex-documentation
-ladoc:	$(DOC_DIR)/$(RESULT)/latex/doc.tex
-
-# generates PostScript-documentation
-psdoc:	$(DOC_DIR)/$(RESULT)/latex/doc.ps
-
-# generates PDF-documentation
-pdfdoc:	$(DOC_DIR)/$(RESULT)/latex/doc.pdf
-
-# generates all supported forms of documentation
-doc: htdoc ladoc psdoc pdfdoc
-
-###########################################################################
-# LOW LEVEL RULES
-
-$(REAL_RESULT):		$(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(RESULTDEPS)
-			$(REAL_OCAMLFIND) $(REAL_OCAMLC) \
-				$(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \
-				$(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \
-				$(REAL_IMPL)
-
-nolink:			$(REAL_IMPL_INTF) $(OBJ_LINK)
-
-ifdef WIN32
-$(REAL_RESULT).dll:	$(REAL_IMPL_INTF) $(OBJ_LINK)
-			$(CAMLIDLDLL) $(CAMLIDLDLLFLAGS) $(OBJ_LINK) $(CLIBS) \
-				-o $@ $(REAL_IMPL)
-endif
-
-%$(TOPSUFFIX):		$(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS)
-			$(REAL_OCAMLFIND) $(OCAMLMKTOP) \
-				$(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \
-				$(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \
-				$(REAL_IMPL)
-
-.SUFFIXES:		.mli .ml .cmi .cmo .cmx .cma .cmxa .$(EXT_OBJ) \
-                        .mly .di .d .$(EXT_LIB) .idl %.oxridl .c .m .$(EXT_CXX) .h .so \
-                        .rep .zog .glade
-
-ifndef STATIC
-ifdef MINGW
-$(DLLSONAME):		$(OBJ_LINK)
-			$(CC) $(CFLAGS) $(CFLAGS_WIN32) $(OBJ_LINK) -shared -o $@ \
-			-Wl,--whole-archive $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/lib%.a))) \
-			 $(OCAMLLIBPATH)/ocamlrun.a \
-			-Wl,--export-all-symbols \
-			-Wl,--no-whole-archive
-else
-ifdef MSVC
-$(DLLSONAME):		$(OBJ_LINK)
-			link /NOLOGO /DLL /OUT:$@ $(OBJ_LINK) \
-			 $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/%.lib))) \
-			 $(OCAMLLIBPATH)/ocamlrun.lib
-
-else
-$(DLLSONAME):		$(OBJ_LINK)
-			$(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \
-				-o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) $(CFRAMEWORKS:%=-framework %) \
-				$(OCAMLMKLIB_FLAGS)
-endif
-endif
-endif
-
-ifndef LIB_PACK_NAME
-$(RESULT).cma:		$(REAL_IMPL_INTF) $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS)
-			$(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@ $(REAL_IMPL)
-
-$(RESULT).cmxa $(RESULT).$(EXT_LIB):	$(REAL_IMPL_INTF) $(EXTRADEPS) $(RESULTDEPS)
-			$(REAL_OCAMLFIND) $(OCAMLOPT) -a $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@ $(REAL_IMPL)
-else
-ifdef BYTE_OCAML
-$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo: $(REAL_IMPL_INTF)
-			$(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmo $(OCAMLLDFLAGS) $(REAL_IMPL)
-else
-$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx: $(REAL_IMPL_INTF)
-			$(REAL_OCAMLFIND) $(OCAMLOPT) -pack -o $(LIB_PACK_NAME).cmx  $(OCAMLLDFLAGS) $(REAL_IMPL)
-endif
-
-$(RESULT).cma:		$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS)
-			$(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@ $(LIB_PACK_NAME).cmo
-
-$(RESULT).cmxa $(RESULT).$(EXT_LIB):	$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx $(EXTRADEPS) $(RESULTDEPS)
-			$(REAL_OCAMLFIND) $(OCAMLOPT) -a $(filter-out -custom, $(ALL_LDFLAGS)) $(OBJS_LIBS) -o $@ $(LIB_PACK_NAME).cmx
-endif
-
-$(RES_CLIB): 		$(OBJ_LINK)
-ifndef MSVC
-  ifneq ($(strip $(OBJ_LINK)),)
-		      $(AR) rcs $@ $(OBJ_LINK)
-  endif
-else
-  ifneq ($(strip $(OBJ_LINK)),)
-			lib -nologo -debugtype:cv -out:$(RES_CLIB) $(OBJ_LINK)
-  endif
-endif
-
-.mli.cmi: $(EXTRADEPS)
-			$(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
-			if [ -z "$$pp" ]; then \
-			  $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
-				-c $(THREAD_FLAG) $(ANNOT_FLAG) \
-				$(OCAMLFLAGS) $(INCFLAGS) $<; \
-			  $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
-				-c $(THREAD_FLAG) $(ANNOT_FLAG) \
-				$(OCAMLFLAGS) $(INCFLAGS) $<; \
-			else \
-			    $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
-				-c -pp \"$$pp $(PPFLAGS)\" $(THREAD_FLAG) $(ANNOT_FLAG) \
-				$(OCAMLFLAGS) $(INCFLAGS) $<; \
-			    $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
-				-c -pp "$$pp $(PPFLAGS)" $(THREAD_FLAG) $(ANNOT_FLAG) \
-				$(OCAMLFLAGS) $(INCFLAGS) $<; \
-			fi
-
-.ml.cmi .ml.$(EXT_OBJ) .ml.cmx .ml.cmo: $(EXTRADEPS)
-			$(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
-			if [ -z "$$pp" ]; then \
-			  $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
-				-c $(ALL_OCAMLCFLAGS) $<; \
-			  $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
-				-c $(ALL_OCAMLCFLAGS) $<; \
-			else \
-			  $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
-				-c -pp \"$$pp $(PPFLAGS)\" $(ALL_OCAMLCFLAGS) $<; \
-			  $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
-				-c -pp "$$pp $(PPFLAGS)" $(ALL_OCAMLCFLAGS) $<; \
-			fi
-
-ifdef PACK_LIB
-$(REAL_RESULT).cmo $(REAL_RESULT).cmx $(REAL_RESULT).o: $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS)
-			$(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack $(ALL_LDFLAGS) \
-				$(OBJS_LIBS) -o $@ $(REAL_IMPL)
-endif
-
-.PRECIOUS:		%.ml
-%.ml:			%.mll
-			$(OCAMLLEX) $(LFLAGS) $<
-
-.PRECIOUS:              %.ml %.mli
-%.ml %.mli:             %.mly
-			$(OCAMLYACC) $(YFLAGS) $<
-			$(QUIET)pp=`sed -n -e 's/.*(\*pp \([^*]*\) \*).*/\1/p;q' $<`; \
-			if [ ! -z "$$pp" ]; then \
-			  mv $*.ml $*.ml.temporary; \
-			  echo "(*pp $$pp $(PPFLAGS)*)" > $*.ml; \
-			  cat $*.ml.temporary >> $*.ml; \
-			  rm $*.ml.temporary; \
-			  mv $*.mli $*.mli.temporary; \
-			  echo "(*pp $$pp $(PPFLAGS)*)" > $*.mli; \
-			  cat $*.mli.temporary >> $*.mli; \
-			  rm $*.mli.temporary; \
-			fi
-
-
-.PRECIOUS:		%.ml
-%.ml:			%.rep
-			$(CAMELEON_REPORT) $(CAMELEON_REPORT_FLAGS) -gen $<
-
-.PRECIOUS:		%.ml
-%.ml:			%.zog
-			$(CAMELEON_ZOGGY)  $(CAMELEON_ZOGGY_FLAGS) -impl $< > $@
-
-.PRECIOUS:		%.ml
-%.ml:			%.glade
-			$(OCAML_GLADECC)  $(OCAML_GLADECC_FLAGS) $< > $@
-
-.PRECIOUS:		%.ml %.mli
-%.ml %.mli:		%.oxridl
-			$(OXRIDL) $<
-
-.PRECIOUS:		%.ml %.mli %_stubs.c %.h
-%.ml %.mli %_stubs.c %.h:		%.idl
-			$(CAMLIDL) $(MAYBE_IDL_HEADER) $(IDLFLAGS) \
-				$(CAMLIDLFLAGS) $<
-			$(QUIET)if [ $(NOIDLHEADER) ]; then touch $*.h; fi
-
-.c.$(EXT_OBJ):
-			$(OCAMLC) -c -cc "$(CC)" -ccopt "$(CFLAGS) \
-				$(CPPFLAGS) $(CPPFLAGS_WIN32) \
-				$(CFLAGS_WIN32) $(CINCFLAGS) $(CFLAG_O)$@ " $<
-
-.m.$(EXT_OBJ):
-			$(CC) -c $(CFLAGS) $(CINCFLAGS) $(CPPFLAGS) \
-				-I'$(OCAMLLIBPATH)' \
-				$< $(CFLAG_O)$@
-
-.$(EXT_CXX).$(EXT_OBJ):
-			$(CXX) -c $(CXXFLAGS) $(CINCFLAGS) $(CPPFLAGS) \
-				-I'$(OCAMLLIBPATH)' \
-				$< $(CFLAG_O)$@
-
-$(MLDEPDIR)/%.d:	%.ml
-			$(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi
-			$(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
-			if [ -z "$$pp" ]; then \
-			  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
-				$(DINCFLAGS) $< \> $@; \
-			  $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
-				$(DINCFLAGS) $< > $@; \
-			else \
-			  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
-				-pp \"$$pp $(PPFLAGS)\" $(DINCFLAGS) $< \> $@; \
-			  $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
-				-pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \
-			fi
-
-$(BCDIDIR)/%.di $(NCDIDIR)/%.di:	%.mli
-			$(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi
-			$(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
-			if [ -z "$$pp" ]; then \
-			  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(DINCFLAGS) $< \> $@; \
-			  $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(DINCFLAGS) $< > $@; \
-			else \
-			  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \
-			    -pp \"$$pp $(PPFLAGS)\" $(DINCFLAGS) $< \> $@; \
-			  $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \
-			    -pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \
-			fi
-
-$(DOC_DIR)/$(RESULT)/html:
-	mkdir -p $@
-
-$(DOC_DIR)/$(RESULT)/html/index.html: $(DOC_DIR)/$(RESULT)/html $(DOC_FILES)
-	rm -rf $</*
-	$(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $(FIRST_DOC_FILE)`; \
-	if [ -z "$$pp" ]; then \
-	  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -html -d $< $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \
-	  $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -html -d $< $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \
-	else \
-	  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -pp \"$$pp $(PPFLAGS)\" -html -d $< $(OCAMLDOCFLAGS) \
-	  	$(INCFLAGS) $(DOC_FILES); \
-	  $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -pp "$$pp $(PPFLAGS)" -html -d $< $(OCAMLDOCFLAGS) \
-	  	$(INCFLAGS) $(DOC_FILES); \
-	fi
-
-$(DOC_DIR)/$(RESULT)/latex:
-	mkdir -p $@
-
-$(DOC_DIR)/$(RESULT)/latex/doc.tex: $(DOC_DIR)/$(RESULT)/latex $(DOC_FILES)
-	rm -rf $</*
-	$(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $(FIRST_DOC_FILE)`; \
-	if [ -z "$$pp" ]; then \
-	  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) \
-	  	$(DOC_FILES) -o $@; \
-	  $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES) \
-	  	-o $@; \
-	else \
-	  $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -pp \"$$pp $(PPFLAGS)\" -latex $(OCAMLDOCFLAGS) \
-	  	$(INCFLAGS) $(DOC_FILES) -o $@; \
-	  $(REAL_OCAMLFIND) $(OCAMLDOC) $(OCAML_FIND_PACKAGES) -pp "$$pp $(PPFLAGS)" -latex $(OCAMLDOCFLAGS) \
-	  	$(INCFLAGS) $(DOC_FILES) -o $@; \
-	fi
-
-$(DOC_DIR)/$(RESULT)/latex/doc.ps: $(DOC_DIR)/$(RESULT)/latex/doc.tex
-	cd $(DOC_DIR)/$(RESULT)/latex && \
-	  $(LATEX) doc.tex && \
-	  $(LATEX) doc.tex && \
-	  $(DVIPS) $(DVIPSFLAGS) doc.dvi -o $(@F)
-
-$(DOC_DIR)/$(RESULT)/latex/doc.pdf: $(DOC_DIR)/$(RESULT)/latex/doc.ps
-	cd $(DOC_DIR)/$(RESULT)/latex && $(PS2PDF) $(<F)
-
-define make_subproj
-.PHONY:
-subproj_$(1):
-	$$(eval $$(call PROJ_$(1)))
-	$(QUIET)if [ "$(SUBTARGET)" != "all" ]; then \
-	  $(MAKE) -f $(OCAMLMAKEFILE) $(SUBTARGET); \
-	fi
-endef
-
-$(foreach subproj,$(SUBPROJS),$(eval $(call make_subproj,$(subproj))))
-
-.PHONY:
-subprojs: $(SUBPROJS:%=subproj_%)
-
-###########################################################################
-# (UN)INSTALL RULES FOR LIBRARIES
-
-.PHONY: libinstall
-libinstall:	all
-	$(QUIET)printf "\nInstalling library with ocamlfind\n"
-	$(OCAMLFIND) install $(OCAMLFIND_INSTFLAGS) $(RESULT) META $(LIBINSTALL_FILES)
-	$(QUIET)printf "\nInstallation successful.\n"
-
-.PHONY: libinstall-byte-code
-libinstall-byte-code:	all
-	$(QUIET)printf "\nInstalling byte-code library with ocamlfind\n"
-	$(OCAMLFIND) install $(OCAMLFIND_INSTFLAGS) $(RESULT) META \
-	  $(filter-out $(RESULT).$(EXT_LIB) $(RESULT).cmxa, $(LIBINSTALL_FILES))
-	$(QUIET)printf "\nInstallation successful.\n"
-
-.PHONY: libinstall-native-code
-libinstall-native-code:	all
-	$(QUIET)printf "\nInstalling native-code library with ocamlfind\n"
-	$(OCAMLFIND) install $(OCAMLFIND_INSTFLAGS) $(RESULT) META \
-	  $(filter-out $(DLLSONAME) $(RESULT).cma, $(LIBINSTALL_FILES))
-	$(QUIET)printf "\nInstallation successful.\n"
-
-.PHONY: libuninstall
-libuninstall:
-	$(QUIET)printf "\nUninstalling library with ocamlfind\n"
-	$(OCAMLFIND) remove $(OCAMLFIND_INSTFLAGS) $(RESULT)
-	$(QUIET)printf "\nUninstallation successful.\n"
-
-.PHONY: rawinstall
-rawinstall:	all
-	$(QUIET)printf "\nInstalling library to: $(OCAML_LIB_INSTALL)\n"
-	-install -d $(OCAML_LIB_INSTALL)
-	for i in $(LIBINSTALL_FILES); do \
-	  if [ -f $$i ]; then \
-	    install -c -m 0644 $$i $(OCAML_LIB_INSTALL); \
-	  fi; \
-	done
-	$(QUIET)printf "\nInstallation successful.\n"
-
-.PHONY: rawuninstall
-rawuninstall:
-	$(QUIET)printf "\nUninstalling library from: $(OCAML_LIB_INSTALL)\n"
-	cd $(OCAML_LIB_INSTALL) && rm $(notdir $(LIBINSTALL_FILES))
-	$(QUIET)printf "\nUninstallation successful.\n"
-
-###########################################################################
-# MAINTENANCE RULES
-
-.PHONY:	clean
-clean::
-	rm -f $(TARGETS) $(TRASH)
-	rm -rf $(BCDIDIR) $(NCDIDIR) $(MLDEPDIR)
-
-.PHONY:	cleanup
-cleanup::
-	rm -f $(NONEXECS) $(TRASH)
-	rm -rf $(BCDIDIR) $(NCDIDIR) $(MLDEPDIR)
-
-.PHONY: clean-doc
-clean-doc::
-	rm -rf $(DOC_DIR)/$(RESULT)
-
-.PHONY: clean-all
-clean-all:: clean clean-doc
-
-.PHONY: nobackup
-nobackup:
-	rm -f *.bak *~ *.dup
diff --git a/lib/ocaml/README-OCamlMakefile b/lib/ocaml/README-OCamlMakefile
deleted file mode 100644
index 0a97c64..0000000
--- a/lib/ocaml/README-OCamlMakefile
+++ /dev/null
@@ -1,643 +0,0 @@
-NOTE (bryanduxbury): OCamlMakefile is safe to include in the project after
-https://issues.apache.org/jira/browse/LEGAL-58.
-
----------------------------------------------------------------------------
-
-                        Distribution of "ocaml_make"
-     Copyright (C) 1999 - 2006  Markus Mottl - free to copy and modify!
-                           USE AT YOUR OWN RISK!
-
----------------------------------------------------------------------------
-
-                            PREREQUISITES
-
-             *** YOU WILL NEED GNU-MAKE VERSION >3.80 ***
-
----------------------------------------------------------------------------
-
-                    Contents of this distribution
-
-Changes        - guess what? ;-)
-
-OCamlMakefile  - Makefile for easy handling of compilation of not so easy
-                 OCaml-projects.  It generates dependencies of OCaml-files
-                 automatically, is able to handle "ocamllex"-,
-                 "ocamlyacc"-, IDL- and C-files, knows how to run
-                 preprocessors and generates native- or byte-code, as
-                 executable or as library - with thread-support if you
-                 want! Profiling and debugging support can be added on
-                 the fly!  There is also support for installing libraries.
-                 Ah, yes, and you can also create toplevels from any
-                 sources: this allows you immediate interactive testing.
-                 Automatic generation of documentation is easy due to
-                 integration of support for OCamldoc.
-
-README         - this file
-
-calc/          - Directory containing a quite fully-featured example
-                 of what "OCamlMakefile" can do for you. This example
-                 makes use of "ocamllex", "ocamlyacc", IDL + C and
-                 threads.
-
-camlp4/        - This simple example demonstrates how to automatically
-                 preprocess files with the camlp4-preprocessor.
-
-gtk/           - Demonstration of how to use OCamlMakefile with GTK
-                 and threads. Courtesy of Tim Freeman <tim@fungible.com>.
-
-idl/           - Contains a very small example of how to use
-                 "camlidl" together with "OCamlMakefile". Also intended
-                 to show, how easy it is to interface OCaml and C.
-
-threads/       - Two examples of how to use threads (originally
-                 posted by Xavier Leroy some time ago). Shows the use of
-                 "OCamlMakefile" in an environment of multiple compilation
-                 targets.
-
----------------------------------------------------------------------------
-
-                      Why should you use it?
-
-For several reasons:
-
-  * It is well-tested (I use it in all of my projects).
-
-  * In contrast to most other approaches it generates dependencies
-    correctly by ensuring that all automatically generated OCaml-files
-    exist before dependency calculation.  This is the only way to
-    guarantee that "ocamldep" works correctly.
-
-  * It is extremely convenient (at least I think so ;-).
-    Even quite complex compilation processes (see example "calc.ml")
-    need very little information to work correctly - actually just about
-    the minimum (file names of sources).
-
----------------------------------------------------------------------------
-
-                     When you shouldn't use it...
-
-In projects where every compilation unit needs different flags - but
-in such complicated cases you will be on your own anyway. Luckily,
-this doesn't happen too frequently...
-
----------------------------------------------------------------------------
-
-             How to use "OCamlMakefile" in your own project
-         (Take a look at the examples for a quick introduction!)
-
-Create your project-specific "Makefile" in the appropriate directory.
-
-Now there are two ways of making use of "OCamlMakefile":
-
-  1) Have a look at the default settings in "OCamlMakefile" and set
-     them to the values that are vaild on your system - whether the
-     path to the standard libraries is ok, what executables shall be
-     used, etc...
-
-  2) Copy it into the directory of the project to be compiled.
-     Add "-include OCamlMakefile" as a last line of your "Makefile".
-
-  3) Put it somewhere else on the system. In this case you will have to
-     set a variable "OCAMLMAKEFILE" in your project-specific "Makefile".
-     This is the way in which the examples are written: so you need
-     only one version of "OCamlMakefile" to manage all your projects!
-     See the examples for details.
-
-You should usually specify two further variables for your project:
-
-  * SOURCES  (default: foo.ml)
-  * RESULT   (default: foo)
-
-Put all the sources necessary for a target into variable "SOURCES".
-Then set "RESULT" to the name of the target. If you want to generate
-libraries, you should *not* specify the suffix (".cma", ".cmxa", ".a")
-- it will be added automatically if you specify that you want to build
-a library.
-
-      **      Don't forget to add the ".mli"-files, too!        **
-      **  Don't forget that order of the source files matters!  **
-
-The order is important, because it matters during linking anyway
-due to potential side effects caused at program startup. This is
-why OCamlMakefile does not attempt to partially order dependencies by
-itself, which might confuse users even more. It just compiles and links
-OCaml-sources in the order specified by the user, even if it could
-determine automatically that the order cannot be correct.
-
-The minimum of your "Makefile" looks like this (assuming that
-"OCamlMakefile" is in the search path of "make"):
-
-  -include OCamlMakefile
-
-This will assume that you want to compile a file "foo.ml" to a binary
-"foo".
-
-Otherwise, your Makefile will probably contain something like this:
-
-  SOURCES = foo.ml
-  RESULT  = foo
-  -include OCamlMakefile
-
-Be careful with the names you put into these variables: if they are wrong,
-a "make clean" might erase the wrong files - but I know you will not do
-that ;-)
-
-A simple "make" will generate a byte-code executable. If you want to
-change this, you may add an "all"-rule that generates something else.
-
-E.g.:
-
-  SOURCES = foo.ml
-  RESULT  = foo
-  all: native-code-library
-  -include OCamlMakefile
-
-This will build a native-code library "foo.cmxa" (+ "foo.a") from file
-"foo.ml".
-
-You may even build several targets at once. To produce byte- and native-code
-executables with one "make", add the following rule:
-
-    all: byte-code native-code
-
-You will probably want to use a different suffix for each of these targets
-so that the result will not be overwritten (see optional variables below
-for details).
-
-You may also tell "make" at the command-line what kind of target to
-produce (e.g. "make nc").  Here all the possibilities with shortcuts
-between parenthesis:
-
-   * byte-code                     (bc)
-   * byte-code-nolink              (bcnl)   - no linking stage
-   * byte-code-library             (bcl)
-   * native-code                   (nc)
-   * native-code-nolink            (ncnl)   - no linking stage
-   * native-code-library           (ncl)
-   * debug-code                    (dc)
-   * debug-code-nolink             (dcnl)   - no linking stage
-   * debug-code-library            (dcl)
-   * profiling-byte-code           (pbc)
-   * profiling-byte-code-library   (pbcl)
-   * profiling-native-code         (pnc)
-   * profiling-native-code-library (pncl)
-   * byte-code-dll                 (bcd)
-   * native-code-dll               (ncd)
-   * pack-byte-code                (pabc)
-   * pack-native-code              (panc)
-   * toplevel interpreter          (top)
-   * subprojs
-
-Here a short note concerning building and linking byte code libraries
-with C-files:
-
-  OCaml links C-object files only when they are used in an executable.
-  After compilation they should be placed in some directory that is in
-  your include path if you link your library against an executable.
-
-  It is sometimes more convenient to link all C-object files into a
-  single C-library. Then you have to override the automatic link flags
-  of your library using "-noautolink" and add another linkflag that
-  links in your C-library explicitly.
-
-What concerns maintainance:
-
-  "make clean" removes all (all!) automatically generated files - so
-  again: make sure your variables are ok!
-
-  "make cleanup" is similar to "make clean" but leaves executables.
-
-Another way to destroy some important files is by having "OCamlMakefile"
-automatically generate files with the same name. Read the documentation
-about the tools in the OCaml-distribution to see what kind of files are
-generated. "OCamlMakefile" additionally generates ('%' is basename of
-source file):
-
-  %_idl.c  - "camlidl" generates a file "%.c" from "%.idl", but this is
-             not such a good idea, because when generating native-code,
-             both the file "%.c" and "%.ml" would generate files "%.o"
-             which would overwrite each other. Thus, "OCamlMakefile"
-             renames "%.c" to "%_idl.c" to work around this problem.
-
-The dependencies are stored in three different subdirectories (dot dirs):
-
-  ._d    - contains dependencies for .ml-files
-  ._bcdi - contains byte code dependencies for .mli-files
-  ._ncdi - contains native code dependencies for .mli-files
-
-The endings of the dependency files are: "%.d" for those generated from
-"%.ml"-files, "%.di" for ones derived from "%.mli"-files.
-
----------------------------------------------------------------------------
-
-                                 Debugging
-
-  This is easy: if you discover a bug, just do a "make clean; make dc"
-  to recompile your project with debugging information. Then you can
-  immediately apply "ocamldebug" to the executable.
-
----------------------------------------------------------------------------
-
-                                 Profiling
-
-  For generating code that can be profiled with "ocamlprof" (byte code)
-  or "gprof" (native code), compile your project with one of the profiling
-  targets (see targets above). E.g.:
-
-    * "make pbc" will build byte code that can be profiled with
-      "ocamlprof".
-
-    * "make pnc" will build native code that can be profiled with
-      "gprof".
-
-  Please note that it is not currently possible to profile byte code with
-  threads. OCamlMakefile will force an error if you try to do this.
-
-  A short hint for DEC Alpha-users (under Digital Unix): you may also
-  compile your sources to native code without any further profiling
-  options/targets. Then call "pixie my_exec", "my_exec" being your
-  executable. This will produce (among other files) an executable
-  "my_exec.pixie". Call it and it will produce profiling information which
-  can be analysed using "prof -pixie my_exec". The resulting information
-  is extremely detailed and allows analysis up to the clock cycle level...
-
----------------------------------------------------------------------------
-
-                             Using Preprocessors
-
-  Because one could employ any kind of program that reads from standard
-  input and prints to standard output as preprocessor, there cannot be any
-  default way to handle all of them correctly without further knowledge.
-
-  Therefore you have to cooperate a bit with OCamlMakefile to let
-  preprocessing happen automatically. Basically, this only requires
-  that you put a comment into the first line of files that should be
-  preprocessed, e.g.:
-
-    (*pp cat *)
-    ... rest of program ...
-
-  OCamlMakefile looks at the first line of your files, and if it finds
-  a comment that starts with "(*pp", then it will assume that the
-  rest of the comment tells it how to correctly call the appropriate
-  preprocessor. In this case the program "cat" will be called, which will,
-  of course, just output the source text again without changing it.
-
-  If you are, for example, an advocate of the new "revised syntax",
-  which is supported by the camlp4 preprocessor, you could simply write:
-
-    (*pp camlp4r *)
-    ... rest of program in revised syntax ...
-
-  Simple, isn't it?
-
-  If you want to write your own syntax extensions, just take a look at the
-  example in the directory "camlp4": it implements the "repeat ... until"
-  extension as described in the camlp4-tutorial.
-
----------------------------------------------------------------------------
-
-                     Library (Un-)Installation Support
-
-  OCamlMakefile contains two targets using "ocamlfind" for this purpose:
-
-    * libinstall
-    * libuninstall
-
-  These two targets require the existence of the variable
-  "LIBINSTALL_FILES", which should be set to all the files that you
-  want to install in the library directory (usually %.mli, %.cmi, %.cma,
-  %.cmxa, %.a and possibly further C-libraries). The target "libinstall"
-  has the dependency "all" to force compilation of the library so make
-  sure you define target "all" in your Makefile appropriately.
-
-  The targets inform the user about the configured install path and ask
-  for confirmation to (un)install there. If you want to use them, it
-  is often a good idea to just alias them in your Makefile to "install"
-  and "uninstall" respectively.
-
-  Two other targets allow installation of files into a particular
-  directory (without using ocamlfind):
-
-    * rawinstall
-    * rawuninstall
-
----------------------------------------------------------------------------
-
-                            Building toplevels
-
-  There is just one target for this:
-
-    * top
-
-  The generated file can be used immediately for interactive sessions -
-  even with scanners, parsers, C-files, etc.!
-
----------------------------------------------------------------------------
-
-                         Generating documentation
-
-  The following targets are supported:
-
-   * htdoc      - generates HTML-documentation
-   * ladoc      - generates Latex-documentation
-   * psdoc      - generates PostScript-documentation
-   * pdfdoc     - generates PDF-documentation
-   * doc        - generates all supported forms of documentation
-   * clean-doc  - generates all supported forms of documentation
-
-  All of them generate a sub-directory "doc". More precisely, for HTML it
-  is "doc/$(RESULT)/html" and for Latex, PostScript and PDF the directory
-  "doc/$(RESULT)/latex". See the OCamldoc-manual for details and the
-  optional variables below for settings you can control.
-
----------------------------------------------------------------------------
-
-                           Handling subprojects
-
-  You can have several targets in the same directory and manage them
-  from within an single Makefile.
-
-  Give each subproject a name, e.g. "p1", "p2", etc. Then you export
-  settings specific to each project by using variables of the form
-  "PROJ_p1", "PROJ_p2", etc.  E.g.:
-
-    define PROJ_p1
-      SOURCES="foo.ml main.ml"
-      RESULT="p1"
-      OCAMLFLAGS="-unsafe"
-    endef
-    export PROJ_p1
-
-    define PROJ_p2
-      ...
-    endef
-    export PROJ_p2
-
-  You may also export common settings used by all projects directly, e.g.
-  "export THREADS = y".
-
-  Now it is a good idea to define, which projects should be affected by
-  commands by default.  E.g.:
-
-    ifndef SUBPROJS
-      export SUBPROJS = p1 p2
-    endif
-
-  This will automatically generate a given target for all those
-  subprojects if this variable has not been defined in the shell
-  environment or in the command line of the make-invocation by the user.
-  E.g., "make dc" will generate debug code for all subprojects.
-
-  Then you need to define a default action for your subprojects if "make"
-  has been called without arguments:
-
-    all: bc
-
-  This will build byte code by default for all subprojects.
-
-  Finally, you'll have to define a catch-all target that uses the target
-  provided by the user for all subprojects. Just add (assuming that
-  OCAMLMAKEFILE has been defined appropriately):
-
-    %:
-            @make -f $(OCAMLMAKEFILE) subprojs SUBTARGET=$@
-
-  See the "threads"-directory in the distribution for a short example!
-
----------------------------------------------------------------------------
-
-         Optional variables that may be passed to "OCamlMakefile"
-
-  * LIB_PACK_NAME - packs all modules of a library into a module whose
-                    name is given in variable "LIB_PACK_NAME".
-
-  * RES_CLIB_SUF  - when building a library that contains C-stubs, this
-                    variable controls the suffix appended to the name
-                    of the C-library (default: "_stubs").
-
-  * THREADS       - say "THREADS = yes" if you need thread support compiled in,
-                    otherwise leave it away.
-
-  * VMTHREADS     - say "VMTHREADS = yes" if you want to force VM-level
-                    scheduling of threads (byte-code only).
-
-  * ANNOTATE      - say "ANNOTATE = yes" to generate type annotation files
-                    (.annot) to support displaying of type information
-                    in editors.
-
-  * USE_CAMLP4    - say "USE_CAMLP4 = yes" in your "Makefile" if you
-                    want to include the camlp4 directory during the
-                    build process, otherwise leave it away.
-
-  * INCDIRS       - directories that should be searched for ".cmi"- and
-                    ".cmo"-files.  You need not write "-I ..." - just the
-                    plain names.
-  * LIBDIRS       - directories that should be searched for libraries
-                    Also just put the plain paths into this variable
-  * EXTLIBDIRS    - Same as "LIBDIRS", but paths in this variable are
-                    also added to the binary via the "-R"-flag so that
-                    dynamic libraries in non-standard places can be found.
-  * RESULTDEPS    - Targets on which results (executables or libraries)
-                    should additionally depend.
-
-  * PACKS         - adds packages under control of "findlib".
-
-  * PREDS         - specifies "findlib"-predicates.
-
-  * LIBS          - OCaml-libraries that should be linked (just plain names).
-                    E.g. if you want to link the Str-library, just write
-                    "str" (without quotes).
-                    The new OCaml-compiler handles libraries in such
-                    a way that they "remember" whether they have to
-                    be linked against a C-library and it gets linked
-                    in automatically.
-                    If there is a slash in the library name (such as
-                    "./str" or "lib/foo") then make is told that the
-                    generated files depend on the library.  This
-                    helps to ensure that changes to your libraries are
-                    taken into account, which is important if you are
-                    regenerating your libraries frequently.
-  * CLIBS         - C-libraries that should be linked (just plain names).
-
-  * PRE_TARGETS   - set this to a list of target files that you want
-                    to have buildt before dependency calculation actually
-                    takes place. E.g. use this to automatically compile
-                    modules needed by camlp4, which have to be available
-                    before other modules can be parsed at all.
-
-                    ** WARNING **: the files mentioned in this variable
-                    will be removed when "make clean" is executed!
-
-  * LIBINSTALL_FILES - the files of a library that should be installed
-                       using "findlib". Default:
-
-                         $(RESULT).mli $(RESULT).cmi $(RESULT).cma
-                         $(RESULT).cmxa $(RESULT).a lib$(RESULT).a
-
-  * OCAML_LIB_INSTALL - target directory for "rawinstall/rawuninstall".
-                        (default: $(OCAMLLIBPATH)/contrib)
-
-  * DOC_FILES     - names of files from which documentation is generated.
-                    (default: all .mli-files in your $(SOURCES)).
-
-  * DOC_DIR       - name of directory where documentation should be stored.
-
-  * OCAMLFLAGS    - flags passed to the compilers
-  * OCAMLBCFLAGS  - flags passed to the byte code compiler only
-  * OCAMLNCFLAGS  - flags passed to the native code compiler only
-
-  * OCAMLLDFLAGS  - flags passed to the OCaml-linker
-  * OCAMLBLDFLAGS - flags passed to the OCaml-linker when linking byte code
-  * OCAMLNLDFLAGS - flags passed to the OCaml-linker when linking
-                    native code
-
-  * OCAMLMKLIB_FLAGS - flags passed to the OCaml library tool
-
-  * OCAMLCPFLAGS  - profiling flags passed to "ocamlcp" (default: "a")
-
-  * PPFLAGS       - additional flags passed to the preprocessor (default: none)
-
-  * LFLAGS        - flags passed to "ocamllex"
-  * YFLAGS        - flags passed to "ocamlyacc"
-  * IDLFLAGS      - flags passed to "camlidl"
-
-  * OCAMLDOCFLAGS - flags passed to "ocamldoc"
-
-  * OCAMLFIND_INSTFLAGS - flags passed to "ocamlfind" during installation
-                          (default: none)
-
-  * DVIPSFLAGS    - flags passed to dvips
-                    (when generating documentation in PostScript).
-
-  * STATIC        - set this variable if you want to force creation
-                    of static libraries
-
-  * CC            - the C-compiler to be used
-  * CXX           - the C++-compiler to be used
-
-  * CFLAGS        - additional flags passed to the C-compiler.
-                    The flag "-DNATIVE_CODE" will be passed automatically
-                    if you choose to build native code. This allows you
-                    to compile your C-files conditionally. But please
-                    note: You should do a "make clean" or remove the
-                    object files manually or touch the %.c-files:
-                    otherwise, they may not be correctly recompiled
-                    between different builds.
-
-  * CXXFLAGS      - additional flags passed to the C++-compiler.
-
-  * CPPFLAGS      - additional flags passed to the C-preprocessor.
-
-  * CFRAMEWORKS   - Objective-C framework to pass to linker on MacOS X.
-
-  * LDFLAGS       - additional flags passed to the C-linker
-
-  * RPATH_FLAG    - flag passed through to the C-linker to set a path for
-                    dynamic libraries.  May need to be set by user on
-                    exotic platforms.  (default: "-R").
-
-  * ELF_RPATH_FLAG - this flag is used to set the rpath on ELF-platforms.
-                     (default: "-R")
-
-  * ELF_RPATH     - if this flag is "yes", then the RPATH_FLAG will be
-                    passed by "-Wl" to the linker as normal on
-                    ELF-platforms.
-
-  * OCAMLLIBPATH  - path to the OCaml-standard-libraries
-                    (first default: `$(OCAMLC) -where`)
-                    (second default: "/usr/local/lib/ocaml")
-
-  * OCAML_DEFAULT_DIRS - additional path in which the user can supply
-                         default directories to his own collection of
-                         libraries.  The idea is to pass this as an environment
-                         variable so that the Makefiles do not have to contain
-                         this path all the time.
-
-  * OCAMLFIND     - ocamlfind from findlib       (default: "ocamlfind")
-  * OCAMLC        - byte-code compiler           (default: "ocamlc")
-  * OCAMLOPT      - native-code compiler         (default: "ocamlopt")
-  * OCAMLMKTOP    - top-level compiler           (default: "ocamlmktop")
-  * OCAMLCP       - profiling byte-code compiler (default: "ocamlcp")
-  * OCAMLDEP      - dependency generator         (default: "ocamldep")
-  * OCAMLLEX      - scanner generator            (default: "ocamllex")
-  * OCAMLYACC     - parser generator             (default: "ocamlyacc")
-  * OCAMLMKLIB    - tool to create libraries     (default: "ocamlmklib")
-  * CAMLIDL       - IDL-code generator           (default: "camlidl")
-  * CAMLIDLDLL    - IDL-utility                  (default: "camlidldll")
-  * CAMLP4        - camlp4 preprocessor          (default: "camlp4")
-  * OCAMLDOC      - OCamldoc-command             (default: "ocamldoc")
-
-  * LATEX         - Latex-processor              (default: "latex")
-  * DVIPS         - dvips-command                (default: "dvips")
-  * PS2PDF        - PostScript-to-PDF converter  (default: "ps2pdf")
-
-  * CAMELEON_REPORT - report tool of Cameleon  (default: "report")
-  * CAMELEON_REPORT_FLAGS - flags for the report tool of Cameleon
-
-  * CAMELEON_ZOGGY - zoggy tool of Cameleon
-                     (default: "camlp4o pa_zog.cma pr_o.cmo")
-  * CAMELEON_ZOGGY_FLAGS - flags for the zoggy tool of Cameleon
-
-  * OCAML_GLADECC - Glade compiler for OCaml     (default: "lablgladecc2")
-  * OCAML_GLADECC_FLAGS - flags for the Glade compiler
-
-  * OXRIDL        - OXRIDL-generator  (default: "oxridl")
-
-  * NOIDLHEADER   - set to "yes" to prohibit "OCamlMakefile" from using
-                    the default camlidl-flag "-header".
-
-  * NO_CUSTOM     - Prevent linking in custom mode.
-
-  * QUIET         - unsetting this variable (e.g. "make QUIET=")
-                    will print all executed commands, including
-                    intermediate ones. This allows more comfortable
-                    debugging when things go wrong during a build.
-
-  * REALLY_QUIET  - when set this flag turns off output from some commands.
-
-  * OCAMLMAKEFILE - location of (=path to) this "OCamlMakefile".
-                    Because it calles itself recursively, it has to
-                    know where it is. (default: "OCamlMakefile" =
-                    local directory)
-
-  * BCSUFFIX      - Suffix for all byte-code files. E.g.:
-
-                      RESULT   = foo
-                      BCSUFFIX = _bc
-
-                    This will produce byte-code executables/libraries
-                    with basename "foo_bc".
-
-  * NCSUFFIX      - Similar to "BCSUFFIX", but for native-code files.
-  * TOPSUFFIX     - Suffix added to toplevel interpreters (default: ".top")
-
-  * SUBPROJS      - variable containing the names of subprojects to be
-                    compiled.
-
-  * SUBTARGET     - target to be built for all projects in variable
-                    SUBPROJS.
-
----------------------------------------------------------------------------
-
-                    Optional variables for Windows users
-
-  * MINGW         - variable to detect the MINGW-environment
-  * MSVC          - variable to detect the MSVC-compiler
-
----------------------------------------------------------------------------
-
-Up-to-date information (newest release of distribution) can always be
-found at:
-
-  http://www.ocaml.info/home/ocaml_sources.html
-
----------------------------------------------------------------------------
-
-Enjoy!
-
-New York, 2007-04-22
-Markus Mottl
-
-e-mail: markus.mottl@gmail.com
-WWW:    http://www.ocaml.info
diff --git a/lib/ocaml/README b/lib/ocaml/README.md
similarity index 100%
rename from lib/ocaml/README
rename to lib/ocaml/README.md
diff --git a/lib/ocaml/_oasis b/lib/ocaml/_oasis
index 4dd95e5..5ad90df 100644
--- a/lib/ocaml/_oasis
+++ b/lib/ocaml/_oasis
@@ -1,5 +1,5 @@
 Name: libthrift-ocaml
-Version: 1.0
+Version: 1.0.0
 OASISFormat: 0.3
 Synopsis: OCaml bindings for the Apache Thrift RPC system
 Authors: Apache Thrift Developers <dev@thrift.apache.org>
diff --git a/lib/ocaml/coding_standards.md b/lib/ocaml/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/ocaml/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/ocaml/descr b/lib/ocaml/descr
new file mode 100644
index 0000000..a41749d
--- /dev/null
+++ b/lib/ocaml/descr
@@ -0,0 +1 @@
+OCaml bindings for the Apache Thrift RPC system
diff --git a/lib/ocaml/opam b/lib/ocaml/opam
new file mode 100644
index 0000000..9dbc3d9
--- /dev/null
+++ b/lib/ocaml/opam
@@ -0,0 +1,8 @@
+opam-version: "1"
+maintainer: "XXX(FILL ME IN WITH EMAIL)"
+build: [
+  [make]
+  [make "install"]
+]
+remove: [["ocamlfind" "remove" "thrift"]]
+depends: ["ocamlfind"]
diff --git a/lib/ocaml/src/Thrift.ml b/lib/ocaml/src/Thrift.ml
index f176a43..f0d7a42 100644
--- a/lib/ocaml/src/Thrift.ml
+++ b/lib/ocaml/src/Thrift.ml
@@ -261,6 +261,8 @@
       | NEGATIVE_SIZE
       | SIZE_LIMIT
       | BAD_VERSION
+      | NOT_IMPLEMENTED
+      | DEPTH_LIMIT
 
   exception E of exn_type * string;;
 
diff --git a/lib/ocaml/url b/lib/ocaml/url
new file mode 100644
index 0000000..fe4d604
--- /dev/null
+++ b/lib/ocaml/url
@@ -0,0 +1,2 @@
+archive: "XXX(FILL ME IN WITH URL)"
+checksum: "XXX(FILL ME IN WITH MD5)"
diff --git a/lib/perl/MANIFEST.SKIP b/lib/perl/MANIFEST.SKIP
new file mode 100644
index 0000000..7963b42
--- /dev/null
+++ b/lib/perl/MANIFEST.SKIP
@@ -0,0 +1,13 @@
+blib/.*$
+build-cpan-dist.sh
+FixupDist.pl
+MANIFEST.bak
+MANIFEST.SKIP
+MYMETA.json
+Makefile
+Makefile.am
+Makefile.in
+pm_to_blib
+test/Makefile.am
+test/Makefile.in
+tools/FixupDist.pl
diff --git a/lib/perl/Makefile.PL b/lib/perl/Makefile.PL
index ceca86f..bdeaad2 100644
--- a/lib/perl/Makefile.PL
+++ b/lib/perl/Makefile.PL
@@ -17,13 +17,20 @@
 # under the License.
 #
 
+use 5.10.0;
+use strict;
+use warnings;
+
 use ExtUtils::MakeMaker;
-WriteMakefile( 'NAME' => 'Thrift',
-               'VERSION_FROM' => 'lib/Thrift.pm',
-               'PREREQ_PM'              => {
-                   'Bit::Vector' => 0,
+
+WriteMakefile( ABSTRACT => 'Apache Thrift is a software framework for scalable cross-language services development.',
+               AUTHOR => 'Apache Thrift <dev@thrift.apache.org>',
+               LICENSE => 'apache_2_0',
+               MIN_PERL_VERSION => '5.010000',
+               NAME => 'Thrift',
+               NEEDS_LINKING => 0,
+               PREREQ_PM => {
+                   'Bit::Vector'     => 0,
                    'Class::Accessor' => 0
                },
-               ($] >= 5.005 ?
- (                AUTHOR     => 'Apache Thrift <dev@thrift.apache.org>') : ()),
-               );
+               VERSION_FROM => 'lib/Thrift.pm' );
diff --git a/lib/perl/Makefile.am b/lib/perl/Makefile.am
index 8e0caae..fa0f16b 100644
--- a/lib/perl/Makefile.am
+++ b/lib/perl/Makefile.am
@@ -23,33 +23,86 @@
 	$(PERL) Makefile.PL MAKEFILE=Makefile-perl.mk INSTALLDIRS=$(INSTALLDIRS) INSTALL_BASE=$(PERL_PREFIX)
 
 all-local: Makefile-perl.mk
-	$(MAKE) -f Makefile-perl.mk
+	$(MAKE) -f $<
 	find blib -name 'Makefile*' -exec rm -f {} \;
 
-check-local:
-	$(PERL) -Iblib/lib -I@abs_srcdir@ -I@builddir@/test/gen-perl \
-		@abs_srcdir@/test.pl @abs_srcdir@/test/*.t
-
 install-exec-local: Makefile-perl.mk
-	$(MAKE) -f Makefile-perl.mk install DESTDIR=$(DESTDIR)/
+	$(MAKE) -f $< install DESTDIR=$(DESTDIR)/
 
 clean-local:
 	if test -f Makefile-perl.mk ; then \
 		$(MAKE) -f Makefile-perl.mk clean ; \
 	fi
-	rm -f Makefile-perl.mk.old
+	$(RM) Makefile-perl.mk.old
+	$(RM) -r gen-perl gen-perl2
 
 EXTRA_DIST = \
+	coding_standards.md \
+	build-cpan-dist.sh \
 	Makefile.PL \
 	test.pl \
 	lib/Thrift.pm \
 	lib/Thrift.pm \
 	lib/Thrift/BinaryProtocol.pm \
 	lib/Thrift/BufferedTransport.pm \
+	lib/Thrift/Exception.pm \
 	lib/Thrift/FramedTransport.pm \
 	lib/Thrift/HttpClient.pm \
 	lib/Thrift/MemoryBuffer.pm \
+	lib/Thrift/MessageType.pm \
+	lib/Thrift/MultiplexedProcessor.pm \
+	lib/Thrift/MultiplexedProtocol.pm \
 	lib/Thrift/Protocol.pm \
+	lib/Thrift/ProtocolDecorator.pm \
 	lib/Thrift/Server.pm \
+	lib/Thrift/ServerSocket.pm \
 	lib/Thrift/Socket.pm \
-	lib/Thrift/Transport.pm
+	lib/Thrift/SSLSocket.pm \
+	lib/Thrift/SSLServerSocket.pm \
+	lib/Thrift/UnixServerSocket.pm \
+	lib/Thrift/UnixSocket.pm \
+	lib/Thrift/Type.pm \
+	lib/Thrift/Transport.pm \
+	README.md
+
+THRIFT = @top_builddir@/compiler/cpp/thrift
+THRIFT_IF = @top_srcdir@/test/ThriftTest.thrift
+NAME_BENCHMARKSERVICE =  @top_srcdir@/lib/rb/benchmark/Benchmark.thrift
+NAME_AGGR = @top_srcdir@/contrib/async-test/aggr.thrift
+
+THRIFTTEST_GEN = \
+	gen-perl/ThriftTest/Constants.pm \
+	gen-perl/ThriftTest/SecondService.pm \
+	gen-perl/ThriftTest/ThriftTest.pm \
+	gen-perl/ThriftTest/Types.pm
+
+BENCHMARK_GEN = \
+	gen-perl/BenchmarkService.pm \
+	gen-perl/Constants.pm \
+	gen-perl/Types.pm
+
+AGGR_GEN = \
+	gen-perl2/Aggr.pm \
+	gen-perl2/Constants.pm \
+	gen-perl2/Types.pm
+
+PERL_GEN = \
+	$(THRIFTTEST_GEN) \
+	$(BENCHMARK_GEN) \
+	$(AGGR_GEN)
+
+BUILT_SOURCES = $(PERL_GEN)
+
+check-local: $(PERL_GEN)
+	$(PERL) -Iblib/lib -I@abs_srcdir@ -I@builddir@/gen-perl2 -I@builddir@/gen-perl \
+		@abs_srcdir@/test.pl @abs_srcdir@/test/*.t
+
+$(THRIFTTEST_GEN): $(THRIFT_IF) $(THRIFT)
+	$(THRIFT) --gen perl $<
+
+$(BENCHMARK_GEN): $(NAME_BENCHMARKSERVICE) $(THRIFT)
+	$(THRIFT) --gen perl $<
+
+$(AGGR_GEN): $(NAME_AGGR) $(THRIFT)
+	$(MKDIR_P) gen-perl2
+	$(THRIFT) -out gen-perl2 --gen perl $<
diff --git a/lib/perl/README b/lib/perl/README
deleted file mode 100644
index 691488b..0000000
--- a/lib/perl/README
+++ /dev/null
@@ -1,41 +0,0 @@
-Thrift Perl Software Library
-
-License
-=======
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-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.
-
-Using Thrift with Perl
-=====================
-
-Thrift requires Perl >= 5.6.0
-
-Exceptions are thrown with die so be sure to wrap eval{} statments
-around any code that contains exceptions.
-
-The 64bit Integers work only upto 2^42 on my machine :-?
-Math::BigInt is probably needed.
-
-Please see tutoral and test dirs for examples...
-
-Dependencies
-============
-
-Bit::Vector     - comes with modern perl installations.
-Class::Accessor
-
diff --git a/lib/perl/README.md b/lib/perl/README.md
new file mode 100644
index 0000000..bd1e5b2
--- /dev/null
+++ b/lib/perl/README.md
@@ -0,0 +1,124 @@
+Thrift Perl Software Library
+
+# Summary
+
+Apache Thrift is a software framework for scalable cross-language services development.
+It combines a software stack with a code generation engine to build services that work
+efficiently and seamlessly between many programming languages.  A language-neutral IDL
+is used to generate functioning client libraries and server-side handling frameworks.
+
+# License
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+# For More Information
+
+See the [Apache Thrift Web Site](http://thrift.apache.org/) for more information.
+
+# Using Thrift with Perl
+
+Thrift requires Perl >= 5.10.0
+
+Unexpected exceptions in a service handler are converted to
+TApplicationException with type INTERNAL ERROR and the string
+of the exception is delivered as the message.
+
+On the client side, exceptions are thrown with die, so be sure
+to wrap eval{} statments around any code that contains exceptions.
+
+Please see tutoral and test dirs for examples.
+
+The Perl ForkingServer ignores SIGCHLD allowing the forks to be
+reaped by the operating system naturally when they exit.  This means
+one cannot use a custom SIGCHLD handler in the consuming perl
+implementation that calls serve().  It is acceptable to use
+a custom SIGCHLD handler within a thrift handler implementation
+as the ForkingServer resets the forked child process to use
+default signal handling.
+
+# Dependencies
+
+The following modules are not provided by Perl 5.10.0 but are required
+to use Thrift.
+
+## Runtime
+
+  * Bit::Vector
+  * Class::Accessor
+
+### HttpClient Transport
+
+These are only required if using Thrift::HttpClient:
+
+  * HTTP::Request
+  * IO::String
+  * LWP::UserAgent
+
+### SSL/TLS
+
+These are only required if using Thrift::SSLSocket or Thrift::SSLServerSocket:
+
+  * IO::Socket::SSL
+
+# Breaking Changes
+
+## 0.10.0
+
+The socket classes were refactored in 0.10.0 so that there is one package per
+file.  This means `use Socket;` no longer defines SSLSocket.  You can use this
+technique to make your application run against 0.10.0 as well as earlier versions:
+
+`eval { require Thrift::SSLSocket; } or do { require Thrift::Socket; }`
+
+## 0.11.0
+
+  * Namespaces of packages that were not scoped within Thrift have been fixed.
+  ** TApplicationException is now Thrift::TApplicationException
+  ** TException is now Thrift::TException
+  ** TMessageType is now Thrift::TMessageType
+  ** TProtocolException is now Thrift::TProtocolException
+  ** TProtocolFactory is now Thrift::TProtocolFactory
+  ** TTransportException is now Thrift::TTransportException
+  ** TType is now Thrift::TType
+
+If you need a single version of your code to work with both older and newer thrift
+namespace changes, you can make the new, correct namespaces behave like the old ones
+in your files with this technique to create an alias, which will allow you code to
+run against either version of the perl runtime for thrift:
+
+`BEGIN {*TType:: = *Thrift::TType::}`
+
+  * Packages found in Thrift.pm were moved into the Thrift/ directory in separate files:
+  ** Thrift::TApplicationException is now in Thrift/Exception.pm
+  ** Thrift::TException is now in Thrift/Exception.pm
+  ** Thrift::TMessageType is now in Thrift/MessageType.pm
+  ** Thrift::TType is now in Thrift/Type.pm
+
+If you need to modify your code to work against both older or newer thrift versions,
+you can deal with these changes in a backwards compatible way in your projects using eval:
+
+`eval  { require Thrift::Exception; require Thrift::MessageType; require Thrift::Type; }
+ or do { require Thrift; }`
+
+# Deprecations
+
+## 0.11.0
+
+Thrift::HttpClient setRecvTimeout() and setSendTimeout() are deprecated. 
+Use setTimeout instead.
+
diff --git a/lib/perl/build-cpan-dist.sh b/lib/perl/build-cpan-dist.sh
new file mode 100755
index 0000000..ae22e7e
--- /dev/null
+++ b/lib/perl/build-cpan-dist.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+#
+# This script is intended to be used after tagging the repository and updating
+# the version files for a release.  It will create a CPAN archive.  Run this
+# from inside a docker image like ubuntu-xenial.
+#
+
+set -e
+
+rm -f MANIFEST
+rm -rf Thrift-*
+
+# setup cpan without a prompt
+echo | cpan
+cpan install HTTP::Date
+cpan install CPAN
+cpan install CPAN::Meta ExtUtils::MakeMaker JSON::PP
+
+perl Makefile.PL
+rm MYMETA.yml
+make manifest
+make dist
+
+#
+# We unpack the archive so we can add version metadata for CPAN
+# so that it properly indexes Thrift and remove unnecessary files.
+#
+
+echo '-----------------------------------------------------------'
+set -x
+
+DISTFILE=$(ls Thrift*.gz)
+NEWFILE=${DISTFILE/t-v/t-}
+if [[ "$DISTFILE" != "$NEWFILE" ]]; then
+    mv $DISTFILE $NEWFILE
+    DISTFILE="$NEWFILE"
+fi
+tar xzf $DISTFILE
+rm $DISTFILE
+DISTDIR=$(ls -d Thrift*)
+# cpan doesn't like "Thrift-v0.nn.0 as a directory name
+# needs to be Thrift-0.nn.0
+NEWDIR=${DISTDIR/t-v/t-}
+if [[ "$DISTDIR" != "$NEWDIR" ]]; then
+    mv $DISTDIR $NEWDIR
+    DISTDIR="$NEWDIR"
+fi
+cd $DISTDIR
+cp -p ../Makefile.PL .
+perl ../tools/FixupDist.pl
+cd ..
+tar cvzf $DISTFILE $DISTDIR
+rm -r $DISTDIR
diff --git a/lib/perl/coding_standards.md b/lib/perl/coding_standards.md
new file mode 100644
index 0000000..e4e8255
--- /dev/null
+++ b/lib/perl/coding_standards.md
@@ -0,0 +1,2 @@
+Please follow [General Coding Standards](/doc/coding_standards.md).
+Additional perl coding standards can be found in [perlstyle](http://perldoc.perl.org/perlstyle.html).
diff --git a/lib/perl/lib/Thrift.pm b/lib/perl/lib/Thrift.pm
index 6bdb375..ab40930 100644
--- a/lib/perl/lib/Thrift.pm
+++ b/lib/perl/lib/Thrift.pm
@@ -17,166 +17,20 @@
 # under the License.
 #
 
-our $VERSION = '0.9.1';
-
-require 5.6.0;
+use 5.10.0;
 use strict;
 use warnings;
 
 #
-# Data types that can be sent via Thrift
+# Versioning
 #
-package TType;
-use constant STOP   => 0;
-use constant VOID   => 1;
-use constant BOOL   => 2;
-use constant BYTE   => 3;
-use constant I08    => 3;
-use constant DOUBLE => 4;
-use constant I16    => 6;
-use constant I32    => 8;
-use constant I64    => 10;
-use constant STRING => 11;
-use constant UTF7   => 11;
-use constant STRUCT => 12;
-use constant MAP    => 13;
-use constant SET    => 14;
-use constant LIST   => 15;
-use constant UTF8   => 16;
-use constant UTF16  => 17;
-1;
-
+# Every perl module for Thrift will have the same version
+# declaration.  For a production build, change it below to
+# something like "v0.11.0" and all of the packages in all
+# of the files will pick it up from here.
 #
-# Message types for RPC
-#
-package TMessageType;
-use constant CALL      => 1;
-use constant REPLY     => 2;
-use constant EXCEPTION => 3;
-use constant ONEWAY    => 4;
-1;
 
-package Thrift::TException;
-
-sub new {
-    my $classname = shift;
-    my $self = {message => shift, code => shift || 0};
-
-    return bless($self,$classname);
-}
-1;
-
-package TApplicationException;
-use base('Thrift::TException');
-
-use constant UNKNOWN                 => 0;
-use constant UNKNOWN_METHOD          => 1;
-use constant INVALID_MESSAGE_TYPE    => 2;
-use constant WRONG_METHOD_NAME       => 3;
-use constant BAD_SEQUENCE_ID         => 4;
-use constant MISSING_RESULT          => 5;
-use constant INTERNAL_ERROR          => 6;
-use constant PROTOCOL_ERROR          => 7;
-use constant INVALID_TRANSFORM       => 8;
-use constant INVALID_PROTOCOL        => 9;
-use constant UNSUPPORTED_CLIENT_TYPE => 10;
-
-sub new {
-    my $classname = shift;
-
-    my $self = $classname->SUPER::new();
-
-    return bless($self,$classname);
-}
-
-sub read {
-    my $self  = shift;
-    my $input = shift;
-
-    my $xfer  = 0;
-    my $fname = undef;
-    my $ftype = 0;
-    my $fid   = 0;
-
-    $xfer += $input->readStructBegin(\$fname);
-
-    while (1)
-    {
-        $xfer += $input->readFieldBegin(\$fname, \$ftype, \$fid);
-        if ($ftype == TType::STOP) {
-            last; next;
-        }
-
-      SWITCH: for($fid)
-      {
-          /1/ && do{
-
-              if ($ftype == TType::STRING) {
-                  $xfer += $input->readString(\$self->{message});
-              } else {
-                  $xfer += $input->skip($ftype);
-              }
-
-              last;
-          };
-
-          /2/ && do{
-              if ($ftype == TType::I32) {
-                  $xfer += $input->readI32(\$self->{code});
-              } else {
-                  $xfer += $input->skip($ftype);
-              }
-              last;
-          };
-
-          $xfer += $input->skip($ftype);
-      }
-
-      $xfer += $input->readFieldEnd();
-    }
-    $xfer += $input->readStructEnd();
-
-    return $xfer;
-}
-
-sub write {
-    my $self   = shift;
-    my $output = shift;
-
-    my $xfer   = 0;
-
-    $xfer += $output->writeStructBegin('TApplicationException');
-
-    if ($self->getMessage()) {
-        $xfer += $output->writeFieldBegin('message', TType::STRING, 1);
-        $xfer += $output->writeString($self->getMessage());
-        $xfer += $output->writeFieldEnd();
-    }
-
-    if ($self->getCode()) {
-        $xfer += $output->writeFieldBegin('type', TType::I32, 2);
-        $xfer += $output->writeI32($self->getCode());
-        $xfer += $output->writeFieldEnd();
-    }
-
-    $xfer += $output->writeFieldStop();
-    $xfer += $output->writeStructEnd();
-
-    return $xfer;
-}
-
-sub getMessage
-{
-    my $self = shift;
-
-    return $self->{message};
-}
-
-sub getCode
-{
-    my $self = shift;
-
-    return $self->{code};
-}
+package Thrift;
+use version 0.77; our $VERSION = version->declare("v1.0.0");
 
 1;
diff --git a/lib/perl/lib/Thrift/BinaryProtocol.pm b/lib/perl/lib/Thrift/BinaryProtocol.pm
index c638ead..d62509a 100644
--- a/lib/perl/lib/Thrift/BinaryProtocol.pm
+++ b/lib/perl/lib/Thrift/BinaryProtocol.pm
@@ -17,28 +17,29 @@
 # under the License.
 #
 
-require 5.6.0;
-
+use 5.10.0;
 use strict;
 use warnings;
 
-use utf8;
-use Encode;
-
-use Thrift;
-use Thrift::Protocol;
-
 use Bit::Vector;
+use Encode;
+use Thrift;
+use Thrift::Exception;
+use Thrift::MessageType;
+use Thrift::Protocol;
+use Thrift::Type;
+use utf8;
 
 #
 # Binary implementation of the Thrift protocol.
 #
 package Thrift::BinaryProtocol;
 use base('Thrift::Protocol');
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 use constant VERSION_MASK   => 0xffff0000;
 use constant VERSION_1      => 0x80010000;
-use constant IS_BIG_ENDIAN  => unpack("h*", pack("s", 1)) =~ /01/;
+use constant IS_BIG_ENDIAN  => unpack('h*', pack('s', 1)) =~ m/01/;
 
 sub new
 {
@@ -66,7 +67,8 @@
     return 0;
 }
 
-sub writeStructBegin{
+sub writeStructBegin
+{
     my $self = shift;
     my $name = shift;
     return 0;
@@ -97,7 +99,7 @@
 sub writeFieldStop
 {
     my $self = shift;
-    return $self->writeByte(TType::STOP);
+    return $self->writeByte(Thrift::TType::STOP);
 }
 
 sub writeMapBegin
@@ -252,14 +254,16 @@
     my $result = $self->readI32(\$version);
     if (($version & VERSION_MASK) > 0) {
       if (($version & VERSION_MASK) != VERSION_1) {
-        die new Thrift::TException('Missing version identifier')
+        die Thrift::TProtocolException->new('Missing version identifier',
+                                           Thrift::TProtocolException::BAD_VERSION);
       }
       $$type = $version & 0x000000ff;
       return
           $result +
           $self->readString($name) +
           $self->readI32($seqid);
-    } else { # old client support code
+    }
+    else { # old client support code
       return
         $result +
         $self->readStringBody($name, $version) + # version here holds the size of the string
@@ -297,7 +301,7 @@
 
     my $result = $self->readByte($fieldType);
 
-    if ($$fieldType == TType::STOP) {
+    if ($$fieldType == Thrift::TType::STOP) {
       $$fieldId = 0;
       return $result;
     }
@@ -425,7 +429,7 @@
 
     my ($hi,$lo)=unpack('NN',$data);
 
-    my $vec = new Bit::Vector(64);
+    my $vec = Bit::Vector->new(64);
 
     $vec->Chunk_Store(32,32,$hi);
     $vec->Chunk_Store(32,0,$lo);
@@ -447,7 +451,7 @@
     else {
       $data = scalar reverse($self->{trans}->readAll(8));
     }
-    
+
     my @arr = unpack('d', $data);
 
     $$value = $arr[0];
@@ -465,7 +469,8 @@
 
     if ($len) {
       $$value = $self->{trans}->readAll($len);
-    } else {
+    }
+    else {
       $$value = '';
     }
 
@@ -480,7 +485,8 @@
 
     if ($len) {
       $$value = $self->{trans}->readAll($len);
-    } else {
+    }
+    else {
       $$value = '';
     }
 
@@ -491,7 +497,8 @@
 # Binary Protocol Factory
 #
 package Thrift::BinaryProtocolFactory;
-use base('TProtocolFactory');
+use base('Thrift::TProtocolFactory');
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 sub new
 {
@@ -505,7 +512,7 @@
     my $self  = shift;
     my $trans = shift;
 
-    return new Thrift::BinaryProtocol($trans);
+    return Thrift::BinaryProtocol->new($trans);
 }
 
 1;
diff --git a/lib/perl/lib/Thrift/BufferedTransport.pm b/lib/perl/lib/Thrift/BufferedTransport.pm
index 3868ca2..6b5bf7a 100644
--- a/lib/perl/lib/Thrift/BufferedTransport.pm
+++ b/lib/perl/lib/Thrift/BufferedTransport.pm
@@ -17,15 +17,17 @@
 # under the License.
 #
 
-require 5.6.0;
+use 5.10.0;
 use strict;
 use warnings;
 
 use Thrift;
+use Thrift::Exception;
 use Thrift::Transport;
 
 package Thrift::BufferedTransport;
 use base('Thrift::Transport');
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 sub new
 {
@@ -110,6 +112,7 @@
 # BufferedTransport factory creates buffered transport objects from transports
 #
 package Thrift::BufferedTransportFactory;
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 sub new {
     my $classname = shift;
diff --git a/lib/perl/lib/Thrift/Exception.pm b/lib/perl/lib/Thrift/Exception.pm
new file mode 100644
index 0000000..e404068
--- /dev/null
+++ b/lib/perl/lib/Thrift/Exception.pm
@@ -0,0 +1,161 @@
+#
+# 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.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+
+use Thrift;
+use Thrift::Type;
+
+package Thrift::TException;
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+use overload '""' => sub {
+    return
+        sprintf '%s error: %s (code %s)',
+          ref( $_[0] ),
+          ( $_[0]->{message} || 'empty message' ),
+          ( defined $_[0]->{code} ? $_[0]->{code} : 'undefined' );
+    };
+
+sub new {
+    my $classname = shift;
+    my $self = {message => shift, code => shift || 0};
+
+    return bless($self,$classname);
+}
+
+package Thrift::TApplicationException;
+use parent -norequire, 'Thrift::TException';
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+use constant UNKNOWN                 => 0;
+use constant UNKNOWN_METHOD          => 1;
+use constant INVALID_MESSAGE_TYPE    => 2;
+use constant WRONG_METHOD_NAME       => 3;
+use constant BAD_SEQUENCE_ID         => 4;
+use constant MISSING_RESULT          => 5;
+use constant INTERNAL_ERROR          => 6;
+use constant PROTOCOL_ERROR          => 7;
+use constant INVALID_TRANSFORM       => 8;
+use constant INVALID_PROTOCOL        => 9;
+use constant UNSUPPORTED_CLIENT_TYPE => 10;
+
+sub new {
+    my $classname = shift;
+
+    my $self = $classname->SUPER::new(@_);
+
+    return bless($self,$classname);
+}
+
+sub read {
+    my $self  = shift;
+    my $input = shift;
+
+    my $xfer  = 0;
+    my $fname = undef;
+    my $ftype = 0;
+    my $fid   = 0;
+
+    $xfer += $input->readStructBegin(\$fname);
+
+    while (1)
+    {
+        $xfer += $input->readFieldBegin(\$fname, \$ftype, \$fid);
+        if ($ftype == Thrift::TType::STOP) {
+            last; next;
+        }
+
+      SWITCH: for($fid)
+      {
+          /1/ && do{
+
+              if ($ftype == Thrift::TType::STRING) {
+                  $xfer += $input->readString(\$self->{message});
+              }
+              else {
+                  $xfer += $input->skip($ftype);
+              }
+
+              last;
+          };
+
+          /2/ && do{
+              if ($ftype == Thrift::TType::I32) {
+                  $xfer += $input->readI32(\$self->{code});
+              }
+              else {
+                  $xfer += $input->skip($ftype);
+              }
+              last;
+          };
+
+          $xfer += $input->skip($ftype);
+      }
+
+      $xfer += $input->readFieldEnd();
+    }
+    $xfer += $input->readStructEnd();
+
+    return $xfer;
+}
+
+sub write {
+    my $self   = shift;
+    my $output = shift;
+
+    my $xfer   = 0;
+
+    $xfer += $output->writeStructBegin('TApplicationException');
+
+    if ($self->getMessage()) {
+        $xfer += $output->writeFieldBegin('message', Thrift::TType::STRING, 1);
+        $xfer += $output->writeString($self->getMessage());
+        $xfer += $output->writeFieldEnd();
+    }
+
+    if ($self->getCode()) {
+        $xfer += $output->writeFieldBegin('type', Thrift::TType::I32, 2);
+        $xfer += $output->writeI32($self->getCode());
+        $xfer += $output->writeFieldEnd();
+    }
+
+    $xfer += $output->writeFieldStop();
+    $xfer += $output->writeStructEnd();
+
+    return $xfer;
+}
+
+sub getMessage
+{
+    my $self = shift;
+
+    return $self->{message};
+}
+
+sub getCode
+{
+    my $self = shift;
+
+    return $self->{code};
+}
+
+1;
diff --git a/lib/perl/lib/Thrift/FramedTransport.pm b/lib/perl/lib/Thrift/FramedTransport.pm
index e8e85dc..ba89ba3 100644
--- a/lib/perl/lib/Thrift/FramedTransport.pm
+++ b/lib/perl/lib/Thrift/FramedTransport.pm
@@ -17,6 +17,7 @@
 # under the License.
 #
 
+use 5.10.0;
 use strict;
 use warnings;
 
@@ -30,8 +31,8 @@
 # @package thrift.transport
 #
 package Thrift::FramedTransport;
-
 use base('Thrift::Transport');
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 sub new
 {
@@ -69,7 +70,7 @@
     my $self = shift;
 
     if (defined $self->{transport}) {
-      $self->{transport}->close();
+        $self->{transport}->close();
     }
 }
 
@@ -163,4 +164,31 @@
 
 }
 
+#
+# FramedTransport factory creates framed transport objects from transports
+#
+package Thrift::FramedTransportFactory;
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+sub new {
+    my $classname = shift;
+    my $self      = {};
+
+    return bless($self, $classname);
+}
+
+#
+# Build a framed transport from the base transport
+#
+# @return Thrift::FramedTransport transport
+#
+sub getTransport
+{
+    my $self  = shift;
+    my $trans = shift;
+
+    my $buffered = Thrift::FramedTransport->new($trans);
+    return $buffered;
+}
+
 1;
diff --git a/lib/perl/lib/Thrift/HttpClient.pm b/lib/perl/lib/Thrift/HttpClient.pm
index d6fc8be..40ec9ce 100644
--- a/lib/perl/lib/Thrift/HttpClient.pm
+++ b/lib/perl/lib/Thrift/HttpClient.pm
@@ -17,26 +17,25 @@
 # under the License.
 #
 
-require 5.6.0;
+use 5.10.0;
 use strict;
 use warnings;
 
+use HTTP::Request;
+use IO::String;
+use LWP::UserAgent;
 use Thrift;
+use Thrift::Exception;
 use Thrift::Transport;
 
-use HTTP::Request;
-use LWP::UserAgent;
-use IO::String;
-
 package Thrift::HttpClient;
-
 use base('Thrift::Transport');
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 sub new
 {
     my $classname = shift;
     my $url       = shift || 'http://localhost:9090';
-    my $debugHandler = shift;
 
     my $out = IO::String->new;
     binmode($out);
@@ -44,44 +43,44 @@
     my $self = {
         url          => $url,
         out          => $out,
-        debugHandler => $debugHandler,
-        debug        => 0,
-        sendTimeout  => 100,
-        recvTimeout  => 750,
+        timeout      => 100,
         handle       => undef,
+        headers      => {},
     };
 
     return bless($self,$classname);
 }
 
+sub setTimeout
+{
+    my $self    = shift;
+    my $timeout = shift;
+
+    $self->{timeout} = $timeout;
+}
+
+sub setRecvTimeout
+{
+    warn 'setRecvTimeout is deprecated - use setTimeout instead';
+    # note: recvTimeout was never used so we do not need to do anything here
+}
+
 sub setSendTimeout
 {
     my $self    = shift;
     my $timeout = shift;
 
-    $self->{sendTimeout} = $timeout;
+    warn 'setSendTimeout is deprecated - use setTimeout instead';
+
+    $self->setTimeout($timeout);
 }
 
-sub setRecvTimeout
+sub setHeader
 {
-    my $self    = shift;
-    my $timeout = shift;
+    my $self = shift;
+    my ($name, $value) = @_;
 
-    $self->{recvTimeout} = $timeout;
-}
-
-
-#
-#Sets debugging output on or off
-#
-# @param bool $debug
-#
-sub setDebug
-{
-    my $self  = shift;
-    my $debug = shift;
-
-    $self->{debug} = $debug;
+    $self->{headers}->{$name} = $value;
 }
 
 #
@@ -103,8 +102,8 @@
 {
     my $self = shift;
     if (defined($self->{io})) {
-      close($self->{io});
-      $self->{io} = undef;
+        close($self->{io});
+        $self->{io} = undef;
     }
 }
 
@@ -122,7 +121,8 @@
     my $buf = $self->read($len);
 
     if (!defined($buf)) {
-      die new Thrift::TException('TSocket: Could not read '.$len.' bytes from input buffer');
+        die Thrift::TTransportException->new("TSocket: Could not read $len bytes from input buffer",
+                                          Thrift::TTransportException::END_OF_FILE);
     }
     return $buf;
 }
@@ -140,15 +140,18 @@
     my $in = $self->{in};
 
     if (!defined($in)) {
-      die new Thrift::TException("Response buffer is empty, no request.");
+        die Thrift::TTransportException->new('Response buffer is empty, no request.',
+                                          Thrift::TTransportException::END_OF_FILE);
     }
     eval {
-      my $ret = sysread($in, $buf, $len);
-      if (! defined($ret)) {
-        die new Thrift::TException("No more data available.");
-      }
-    }; if($@){
-      die new Thrift::TException($@);
+        my $ret = sysread($in, $buf, $len);
+        if (! defined($ret)) {
+            die Thrift::TTransportException->new('No more data available.',
+                                            Thrift::TTransportException::TIMED_OUT);
+        }
+    };
+    if($@){
+        die Thrift::TTransportException->new("$@", Thrift::TTransportException::UNKNOWN);
     }
 
     return $buf;
@@ -171,8 +174,9 @@
 {
     my $self = shift;
 
-    my $ua = LWP::UserAgent->new('timeout' => ($self->{sendTimeout} / 1000),
-      'agent' => 'Perl/THttpClient'
+    my $ua = LWP::UserAgent->new(
+        'timeout' => ($self->{timeout} / 1000),
+        'agent'   => 'Perl/THttpClient'
      );
     $ua->default_header('Accept' => 'application/x-thrift');
     $ua->default_header('Content-Type' => 'application/x-thrift');
@@ -182,7 +186,7 @@
     $out->setpos(0); # rewind
     my $buf = join('', <$out>);
 
-    my $request = new HTTP::Request(POST => $self->{url}, undef, $buf);
+    my $request = HTTP::Request->new(POST => $self->{url}, ($self->{headers} || undef), $buf);
     my $response = $ua->request($request);
     my $content_ref = $response->content_ref;
 
diff --git a/lib/perl/lib/Thrift/MemoryBuffer.pm b/lib/perl/lib/Thrift/MemoryBuffer.pm
index 0b28687..be97ce4 100644
--- a/lib/perl/lib/Thrift/MemoryBuffer.pm
+++ b/lib/perl/lib/Thrift/MemoryBuffer.pm
@@ -17,7 +17,7 @@
 # under the License.
 #
 
-require 5.6.0;
+use 5.10.0;
 use strict;
 use warnings;
 
@@ -26,6 +26,7 @@
 
 package Thrift::MemoryBuffer;
 use base('Thrift::Transport');
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 sub new
 {
@@ -34,10 +35,10 @@
     my $bufferSize= shift || 1024;
 
     my $self = {
-        buffer    => '',
-        bufferSize=> $bufferSize,
-        wPos      => 0,
-        rPos      => 0,
+        buffer     => '',
+        bufferSize => $bufferSize,
+        wPos       => 0,
+        rPos       => 0,
     };
 
     return bless($self,$classname);
@@ -116,7 +117,8 @@
 
     my $avail = ($self->{wPos} - $self->{rPos});
     if ($avail < $len) {
-        die new TTransportException("Attempt to readAll($len) found only $avail available");
+        die TTransportException->new("Attempt to readAll($len) found only $avail available",
+                                    Thrift::TTransportException::END_OF_FILE);
     }
 
     my $data = '';
diff --git a/lib/perl/lib/Thrift/MessageType.pm b/lib/perl/lib/Thrift/MessageType.pm
new file mode 100644
index 0000000..d25c2f7
--- /dev/null
+++ b/lib/perl/lib/Thrift/MessageType.pm
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+
+use Thrift;
+
+#
+# Message types for RPC
+#
+package Thrift::TMessageType;
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+use constant CALL      => 1;
+use constant REPLY     => 2;
+use constant EXCEPTION => 3;
+use constant ONEWAY    => 4;
+
+1;
diff --git a/lib/perl/lib/Thrift/MultiplexedProcessor.pm b/lib/perl/lib/Thrift/MultiplexedProcessor.pm
new file mode 100644
index 0000000..ae925d7
--- /dev/null
+++ b/lib/perl/lib/Thrift/MultiplexedProcessor.pm
@@ -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.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+
+use Thrift;
+use Thrift::MessageType;
+use Thrift::MultiplexedProtocol;
+use Thrift::Protocol;
+use Thrift::ProtocolDecorator;
+
+package Thrift::StoredMessageProtocol;
+use base qw(Thrift::ProtocolDecorator);
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+sub new {
+    my $classname = shift;
+    my $protocol  = shift;
+    my $fname  = shift;
+    my $mtype  = shift;
+    my $rseqid  = shift;
+    my $self  = $classname->SUPER::new($protocol);
+
+    $self->{fname} = $fname;
+    $self->{mtype} = $mtype;
+    $self->{rseqid} = $rseqid;
+
+    return bless($self,$classname);
+}
+
+sub readMessageBegin
+{
+    my $self = shift;
+    my $name = shift;
+    my $type = shift;
+    my $seqid = shift;
+
+    $$name = $self->{fname};
+    $$type = $self->{mtype};
+    $$seqid = $self->{rseqid};
+}
+
+package Thrift::MultiplexedProcessor;
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+sub new {
+    my $classname = shift;
+    my $self      = {};
+
+    $self->{serviceProcessorMap} = {};
+    $self->{defaultProcessor} = undef;
+
+    return bless($self,$classname);
+}
+
+sub defaultProcessor {
+    my $self = shift;
+    my $processor = shift;
+
+    $self->{defaultProcessor} = $processor;
+}
+
+sub registerProcessor {
+    my $self = shift;
+    my $serviceName = shift;
+    my $processor = shift;
+
+     $self->{serviceProcessorMap}->{$serviceName} = $processor;
+}
+
+sub process {
+    my $self = shift;
+    my $input = shift;
+    my $output = shift;
+
+    #
+    #  Use the actual underlying protocol (e.g. BinaryProtocol) to read the
+    #  message header. This pulls the message "off the wire", which we'll
+    #  deal with at the end of this method.
+    #
+
+    my ($fname, $mtype, $rseqid);
+    $input->readMessageBegin(\$fname, \$mtype, \$rseqid);
+
+    if ($mtype ne Thrift::TMessageType::CALL && $mtype ne Thrift::TMessageType::ONEWAY) {
+        die Thrift::TException->new('This should not have happened!?');
+    }
+
+    # Extract the service name and the new Message name.
+    if (index($fname, Thrift::MultiplexedProtocol::SEPARATOR) == -1) {
+        if (defined $self->{defaultProcessor}) {
+            return $self->{defaultProcessor}->process(
+                Thrift::StoredMessageProtocol->new($input, $fname, $mtype, $rseqid), $output
+            );
+        } else {
+            die Thrift::TException->new("Service name not found in message name: {$fname} and no default processor defined. Did you " .
+                'forget to use a MultiplexProtocol in your client?');
+        }
+    }
+
+    (my $serviceName, my $messageName) = split(':', $fname, 2);
+
+    if (!exists($self->{serviceProcessorMap}->{$serviceName})) {
+        die Thrift::TException->new("Service name not found: {$serviceName}.  Did you forget " .
+            'to call registerProcessor()?');
+    }
+
+    # Dispatch processing to the stored processor
+    my $processor = $self->{serviceProcessorMap}->{$serviceName};
+    return $processor->process(
+        Thrift::StoredMessageProtocol->new($input, $messageName, $mtype, $rseqid), $output
+    );
+}
+
+1;
diff --git a/lib/perl/lib/Thrift/MultiplexedProtocol.pm b/lib/perl/lib/Thrift/MultiplexedProtocol.pm
new file mode 100644
index 0000000..5b5b60b
--- /dev/null
+++ b/lib/perl/lib/Thrift/MultiplexedProtocol.pm
@@ -0,0 +1,68 @@
+#
+# 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.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+
+use Thrift;
+use Thrift::MessageType;
+use Thrift::Protocol;
+use Thrift::ProtocolDecorator;
+
+package Thrift::MultiplexedProtocol;
+use base qw(Thrift::ProtocolDecorator);
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+use constant SEPARATOR  => ':';
+
+sub new {
+    my $classname = shift;
+    my $protocol  = shift;
+    my $serviceName  = shift;
+    my $self      = $classname->SUPER::new($protocol);
+
+    $self->{serviceName} = $serviceName;
+
+    return bless($self,$classname);
+}
+
+#
+# Writes the message header.
+# Prepends the service name to the function name, separated by MultiplexedProtocol::SEPARATOR.
+#
+# @param string $name  Function name.
+# @param int    $type  Message type.
+# @param int    $seqid The sequence id of this message.
+#
+sub writeMessageBegin
+{
+    my $self = shift;
+    my ($name, $type, $seqid) = @_;
+
+    if ($type == Thrift::TMessageType::CALL || $type == Thrift::TMessageType::ONEWAY) {
+        my $nameWithService = $self->{serviceName}.SEPARATOR.$name;
+        $self->SUPER::writeMessageBegin($nameWithService, $type, $seqid);
+    }
+    else {
+        $self->SUPER::writeMessageBegin($name, $type, $seqid);
+    }
+}
+
+1;
diff --git a/lib/perl/lib/Thrift/Protocol.pm b/lib/perl/lib/Thrift/Protocol.pm
index e2801fe..26ef46a 100644
--- a/lib/perl/lib/Thrift/Protocol.pm
+++ b/lib/perl/lib/Thrift/Protocol.pm
@@ -17,23 +17,28 @@
 # under the License.
 #
 
-require 5.6.0;
+use 5.10.0;
 use strict;
 use warnings;
 
 use Thrift;
+use Thrift::Exception;
+use Thrift::Type;
 
 #
 # Protocol exceptions
 #
-package TProtocolException;
+package Thrift::TProtocolException;
 use base('Thrift::TException');
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
-use constant UNKNOWN       => 0;
-use constant INVALID_DATA  => 1;
-use constant NEGATIVE_SIZE => 2;
-use constant SIZE_LIMIT    => 3;
-use constant BAD_VERSION   => 4;
+use constant UNKNOWN         => 0;
+use constant INVALID_DATA    => 1;
+use constant NEGATIVE_SIZE   => 2;
+use constant SIZE_LIMIT      => 3;
+use constant BAD_VERSION     => 4;
+use constant NOT_IMPLEMENTED => 5;
+use constant DEPTH_LIMIT     => 6;
 
 sub new {
     my $classname = shift;
@@ -47,6 +52,7 @@
 # Protocol base class module.
 #
 package Thrift::Protocol;
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 sub new {
     my $classname = shift;
@@ -75,37 +81,37 @@
 sub writeMessageBegin
 {
     my ($name, $type, $seqid);
-    die "abstract";
+    die 'abstract';
 }
 
 #
 # Close the message
 #
 sub writeMessageEnd {
-    die "abstract";
+    die 'abstract';
 }
 
 #
 # Writes a struct header.
 #
 # @param string     $name Struct name
-# @throws TException on write error
+# @throws TProtocolException on write error
 # @return int How many bytes written
 #
 sub writeStructBegin {
     my ($name);
 
-    die "abstract";
+    die 'abstract';
 }
 
 #
 # Close a struct.
 #
-# @throws TException on write error
+# @throws TProtocolException on write error
 # @return int How many bytes written
 #
 sub writeStructEnd {
-    die "abstract";
+    die 'abstract';
 }
 
 #
@@ -114,85 +120,85 @@
 # @param string     $name Field name
 # @param int        $type Field type
 # @param int        $fid  Field id
-# @throws TException on write error
+# @throws TProtocolException on write error
 # @return int How many bytes written
 #
 sub writeFieldBegin {
     my ($fieldName, $fieldType, $fieldId);
 
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeFieldEnd {
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeFieldStop {
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeMapBegin {
     my ($keyType, $valType, $size);
 
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeMapEnd {
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeListBegin {
     my ($elemType, $size);
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeListEnd {
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeSetBegin {
     my ($elemType, $size);
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeSetEnd {
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeBool {
     my ($bool);
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeByte {
     my ($byte);
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeI16 {
     my ($i16);
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeI32 {
     my ($i32);
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeI64 {
     my ($i64);
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeDouble {
     my ($dub);
-    die "abstract";
+    die 'abstract';
 }
 
 sub writeString
 {
     my ($str);
-    die "abstract";
+    die 'abstract';
 }
 
 #
@@ -205,7 +211,7 @@
 sub readMessageBegin
 {
     my ($name, $type, $seqid);
-    die "abstract";
+    die 'abstract';
 }
 
 #
@@ -213,105 +219,105 @@
 #
 sub readMessageEnd
 {
-    die "abstract";
+    die 'abstract';
 }
 
 sub readStructBegin
 {
     my($name);
 
-    die "abstract";
+    die 'abstract';
 }
 
 sub readStructEnd
 {
-    die "abstract";
+    die 'abstract';
 }
 
 sub readFieldBegin
 {
     my ($name, $fieldType, $fieldId);
-    die "abstract";
+    die 'abstract';
 }
 
 sub readFieldEnd
 {
-    die "abstract";
+    die 'abstract';
 }
 
 sub readMapBegin
 {
     my ($keyType, $valType, $size);
-    die "abstract";
+    die 'abstract';
 }
 
 sub readMapEnd
 {
-    die "abstract";
+    die 'abstract';
 }
 
 sub readListBegin
 {
     my ($elemType, $size);
-    die "abstract";
+    die 'abstract';
 }
 
 sub readListEnd
 {
-    die "abstract";
+    die 'abstract';
 }
 
 sub readSetBegin
 {
     my ($elemType, $size);
-    die "abstract";
+    die 'abstract';
 }
 
 sub readSetEnd
 {
-    die "abstract";
+    die 'abstract';
 }
 
 sub readBool
 {
     my ($bool);
-    die "abstract";
+    die 'abstract';
 }
 
 sub readByte
 {
     my ($byte);
-    die "abstract";
+    die 'abstract';
 }
 
 sub readI16
 {
     my ($i16);
-    die "abstract";
+    die 'abstract';
 }
 
 sub readI32
 {
     my ($i32);
-    die "abstract";
+    die 'abstract';
 }
 
 sub readI64
 {
     my ($i64);
-    die "abstract";
+    die 'abstract';
 }
 
 sub readDouble
 {
     my ($dub);
-    die "abstract";
+    die 'abstract';
 }
 
 sub readString
 {
     my ($str);
-    die "abstract";
+    die 'abstract';
 }
 
 #
@@ -329,36 +335,36 @@
     my $result;
     my $i;
 
-    if($type == TType::BOOL)
+    if($type == Thrift::TType::BOOL)
     {
         return $self->readBool(\$ref);
     }
-    elsif($type == TType::BYTE){
+    elsif($type == Thrift::TType::BYTE){
         return $self->readByte(\$ref);
     }
-    elsif($type == TType::I16){
+    elsif($type == Thrift::TType::I16){
         return $self->readI16(\$ref);
     }
-    elsif($type == TType::I32){
+    elsif($type == Thrift::TType::I32){
         return $self->readI32(\$ref);
     }
-    elsif($type == TType::I64){
+    elsif($type == Thrift::TType::I64){
         return $self->readI64(\$ref);
     }
-    elsif($type == TType::DOUBLE){
+    elsif($type == Thrift::TType::DOUBLE){
         return $self->readDouble(\$ref);
     }
-    elsif($type == TType::STRING)
+    elsif($type == Thrift::TType::STRING)
     {
         return $self->readString(\$ref);
     }
-    elsif($type == TType::STRUCT)
+    elsif($type == Thrift::TType::STRUCT)
     {
         $result = $self->readStructBegin(\$ref);
         while (1) {
             my ($ftype,$fid);
             $result += $self->readFieldBegin(\$ref, \$ftype, \$fid);
-            if ($ftype == TType::STOP) {
+            if ($ftype == Thrift::TType::STOP) {
                 last;
             }
             $result += $self->skip($ftype);
@@ -367,7 +373,7 @@
         $result += $self->readStructEnd();
         return $result;
     }
-    elsif($type == TType::MAP)
+    elsif($type == Thrift::TType::MAP)
     {
         my($keyType,$valType,$size);
         $result = $self->readMapBegin(\$keyType, \$valType, \$size);
@@ -378,7 +384,7 @@
         $result += $self->readMapEnd();
         return $result;
     }
-    elsif($type == TType::SET)
+    elsif($type == Thrift::TType::SET)
     {
         my ($elemType,$size);
         $result = $self->readSetBegin(\$elemType, \$size);
@@ -388,7 +394,7 @@
         $result += $self->readSetEnd();
         return $result;
     }
-    elsif($type == TType::LIST)
+    elsif($type == Thrift::TType::LIST)
     {
         my ($elemType,$size);
         $result = $self->readListBegin(\$elemType, \$size);
@@ -399,7 +405,8 @@
         return $result;
     }
 
-    die new Thrift::TException("Type $type not recognised --- corrupt data?");
+    die Thrift::TProtocolException->new("Type $type not recognized --- corrupt data?",
+                                       Thrift::TProtocolException::INVALID_DATA);
 
   }
 
@@ -415,31 +422,31 @@
     my $itrans = shift;
     my $type   = shift;
 
-    if($type == TType::BOOL)
-    {
-      return $itrans->readAll(1);
-    }
-    elsif($type == TType::BYTE)
+    if($type == Thrift::TType::BOOL)
     {
         return $itrans->readAll(1);
     }
-    elsif($type == TType::I16)
+    elsif($type == Thrift::TType::BYTE)
+    {
+        return $itrans->readAll(1);
+    }
+    elsif($type == Thrift::TType::I16)
     {
         return $itrans->readAll(2);
     }
-    elsif($type == TType::I32)
+    elsif($type == Thrift::TType::I32)
     {
         return $itrans->readAll(4);
     }
-    elsif($type == TType::I64)
+    elsif($type == Thrift::TType::I64)
     {
         return $itrans->readAll(8);
     }
-    elsif($type == TType::DOUBLE)
+    elsif($type == Thrift::TType::DOUBLE)
     {
         return $itrans->readAll(8);
     }
-    elsif( $type == TType::STRING )
+    elsif( $type == Thrift::TType::STRING )
     {
         my @len = unpack('N', $itrans->readAll(4));
         my $len = $len[0];
@@ -448,25 +455,25 @@
         }
         return 4 + $itrans->readAll($len);
     }
-    elsif( $type == TType::STRUCT )
+    elsif( $type == Thrift::TType::STRUCT )
     {
         my $result = 0;
         while (1) {
-          my $ftype = 0;
-          my $fid = 0;
-          my $data = $itrans->readAll(1);
-          my @arr = unpack('c', $data);
-          $ftype = $arr[0];
-          if ($ftype == TType::STOP) {
-            last;
-          }
-          # I16 field id
-          $result += $itrans->readAll(2);
-          $result += $self->skipBinary($itrans, $ftype);
+            my $ftype = 0;
+            my $fid = 0;
+            my $data = $itrans->readAll(1);
+            my @arr = unpack('c', $data);
+            $ftype = $arr[0];
+            if ($ftype == Thrift::TType::STOP) {
+                last;
+            }
+            # I16 field id
+            $result += $itrans->readAll(2);
+            $result += $self->skipBinary($itrans, $ftype);
         }
         return $result;
     }
-    elsif($type == TType::MAP)
+    elsif($type == Thrift::TType::MAP)
     {
         # Ktype
         my $data = $itrans->readAll(1);
@@ -490,7 +497,7 @@
         }
         return $result;
     }
-    elsif($type == TType::SET || $type == TType::LIST)
+    elsif($type == Thrift::TType::SET || $type == Thrift::TType::LIST)
     {
         # Vtype
         my $data = $itrans->readAll(1);
@@ -510,14 +517,15 @@
         return $result;
     }
 
-    die new Thrift::TException("Type $type not recognised --- corrupt data?");
+    die Thrift::TProtocolException->new("Type $type not recognized --- corrupt data?",
+                                       Thrift::TProtocolException::INVALID_DATA);
 }
 
 #
 # Protocol factory creates protocol objects from transports
 #
-package TProtocolFactory;
-
+package Thrift::TProtocolFactory;
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 sub new {
     my $classname = shift;
@@ -534,7 +542,7 @@
 sub getProtocol
 {
     my ($trans);
-    die "interface";
+    die 'interface';
 }
 
 
diff --git a/lib/perl/lib/Thrift/ProtocolDecorator.pm b/lib/perl/lib/Thrift/ProtocolDecorator.pm
new file mode 100644
index 0000000..cc5c9da
--- /dev/null
+++ b/lib/perl/lib/Thrift/ProtocolDecorator.pm
@@ -0,0 +1,363 @@
+#
+# 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.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+
+use Thrift;
+use Thrift::Protocol;
+
+package Thrift::ProtocolDecorator;
+use base qw(Thrift::Protocol);
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+sub new {
+    my $classname = shift;
+    my $protocol  = shift;
+    my $self      = $classname->SUPER::new($protocol->getTransport());
+
+    $self->{concreteProtocol} = $protocol;
+
+    return bless($self,$classname);
+}
+
+#
+# Writes the message header
+#
+# @param string $name Function name
+# @param int $type message type TMessageType::CALL or TMessageType::REPLY
+# @param int $seqid The sequence id of this message
+#
+sub writeMessageBegin {
+    my $self = shift;
+    my ($name, $type, $seqid) = @_;
+
+      return  $self->{concreteProtocol}->writeMessageBegin($name, $type, $seqid);
+}
+
+#
+# Close the message
+#
+sub writeMessageEnd {
+     my $self = shift;
+
+     return $self->{concreteProtocol}->writeMessageEnd();
+}
+
+#
+# Writes a struct header.
+#
+# @param string     $name Struct name
+# @throws TException on write error
+# @return int How many bytes written
+#
+sub writeStructBegin {
+    my $self = shift;
+    my ($name) = @_;
+
+    return $self->{concreteProtocol}->writeStructBegin($name);
+}
+
+#
+# Close a struct.
+#
+# @throws TException on write error
+# @return int How many bytes written
+#
+sub writeStructEnd {
+    my $self = shift;
+
+    return $self->{concreteProtocol}->writeStructEnd();
+}
+
+#
+# Starts a field.
+#
+# @param string     $name Field name
+# @param int        $type Field type
+# @param int        $fid  Field id
+# @throws TException on write error
+# @return int How many bytes written
+#
+sub writeFieldBegin {
+    my $self = shift;
+    my ($fieldName, $fieldType, $fieldId) = @_;
+
+    return $self->{concreteProtocol}->writeFieldBegin($fieldName, $fieldType, $fieldId);
+}
+
+sub writeFieldEnd {
+    my $self = shift;
+
+    return $self->{concreteProtocol}->writeFieldEnd();
+}
+
+sub writeFieldStop {
+    my $self = shift;
+
+    return $self->{concreteProtocol}->writeFieldStop();
+}
+
+sub writeMapBegin {
+    my $self = shift;
+    my ($keyType, $valType, $size) = @_;
+
+    return $self->{concreteProtocol}->writeMapBegin($keyType, $valType, $size);
+}
+
+sub writeMapEnd {
+    my $self = shift;
+
+    return $self->{concreteProtocol}->writeMapEnd();
+}
+
+sub writeListBegin {
+    my $self = shift;
+    my ($elemType, $size) = @_;
+
+    return $self->{concreteProtocol}->writeListBegin($elemType, $size);
+}
+
+sub writeListEnd {
+    my $self = shift;
+
+    return $self->{concreteProtocol}->writeListEnd();
+}
+
+sub writeSetBegin {
+    my $self = shift;
+    my ($elemType, $size) = @_;
+
+    return $self->{concreteProtocol}->writeSetBegin($elemType, $size);
+}
+
+sub writeSetEnd {
+    my $self = shift;
+
+    return $self->{concreteProtocol}->writeListEnd();
+}
+
+sub writeBool {
+    my $self = shift;
+    my $bool = shift;
+
+    return $self->{concreteProtocol}->writeBool($bool);
+}
+
+sub writeByte {
+    my $self = shift;
+    my $byte = shift;
+
+    return $self->{concreteProtocol}->writeByte($byte);
+}
+
+sub writeI16 {
+    my $self = shift;
+    my $i16 = shift;
+
+    return $self->{concreteProtocol}->writeI16($i16);
+}
+
+sub writeI32 {
+    my $self = shift;
+    my ($i32) = @_;
+
+    return $self->{concreteProtocol}->writeI32($i32);
+
+}
+
+sub writeI64 {
+    my $self = shift;
+    my $i64 = shift;
+
+    return $self->{concreteProtocol}->writeI64($i64);
+}
+
+sub writeDouble {
+    my $self = shift;
+    my $dub = shift;
+
+    return $self->{concreteProtocol}->writeDouble($dub);
+}
+
+sub writeString {
+    my $self = shift;
+    my $str = shift;
+
+    return $self->{concreteProtocol}->writeString($str);
+}
+
+#
+# Reads the message header
+#
+# @param string $name Function name
+# @param int $type message type TMessageType::CALL or TMessageType::REPLY
+# @parem int $seqid The sequence id of this message
+#
+sub readMessageBegin
+{
+    my $self = shift;
+    my ($name, $type, $seqid) = @_;
+
+    return $self->{concreteProtocol}->readMessageBegin($name, $type, $seqid);
+}
+
+#
+# Read the close of message
+#
+sub readMessageEnd
+{
+    my $self = shift;
+
+    return $self->{concreteProtocol}->readMessageEnd();
+}
+
+sub readStructBegin
+{
+    my $self = shift;
+    my $name = shift;
+
+    return $self->{concreteProtocol}->readStructBegin($name);
+}
+
+sub readStructEnd
+{
+    my $self = shift;
+
+    return $self->{concreteProtocol}->readStructEnd();
+}
+
+sub readFieldBegin
+{
+    my $self = shift;
+    my ($name, $fieldType, $fieldId) = @_;
+
+    return $self->{concreteProtocol}->readFieldBegin($name, $fieldType, $fieldId);
+}
+
+sub readFieldEnd
+{
+    my $self = shift;
+
+    return $self->{concreteProtocol}->readFieldEnd();
+}
+
+sub readMapBegin
+{
+    my $self = shift;
+    my ($keyType, $valType, $size) = @_;
+
+    return $self->{concreteProtocol}->readMapBegin($keyType, $valType, $size);
+}
+
+sub readMapEnd
+{
+    my $self = shift;
+
+    return $self->{concreteProtocol}->readMapEnd();
+}
+
+sub readListBegin
+{
+    my $self = shift;
+    my ($elemType, $size) = @_;
+
+    return $self->{concreteProtocol}->readListBegin($elemType, $size);
+}
+
+sub readListEnd
+{
+    my $self = shift;
+
+    return $self->{concreteProtocol}->readListEnd();
+}
+
+sub readSetBegin
+{
+    my $self = shift;
+    my ($elemType, $size) = @_;
+
+    return $self->{concreteProtocol}->readSetBegin($elemType, $size);
+}
+
+sub readSetEnd
+{
+    my $self = shift;
+
+    return $self->{concreteProtocol}->readSetEnd();
+}
+
+sub readBool
+{
+    my $self = shift;
+    my $bool = shift;
+
+    return $self->{concreteProtocol}->readBool($bool);
+}
+
+sub readByte
+{
+    my $self = shift;
+    my $byte = shift;
+
+    return $self->{concreteProtocol}->readByte($byte);
+}
+
+sub readI16
+{
+    my $self = shift;
+    my $i16 = shift;
+
+    return $self->{concreteProtocol}->readI16($i16);
+}
+
+sub readI32
+{
+    my $self = shift;
+    my $i32  = shift;
+
+    return $self->{concreteProtocol}->readI32($i32);
+}
+
+sub readI64
+{
+    my $self = shift;
+    my $i64  = shift;
+
+    return $self->{concreteProtocol}->readI64($i64);
+}
+
+sub readDouble
+{
+    my $self = shift;
+    my $dub  = shift;
+
+    return $self->{concreteProtocol}->readDouble($dub);
+}
+
+sub readString
+{
+    my $self = shift;
+    my $str = shift;
+
+    return $self->{concreteProtocol}->readString($str);
+}
+
+1;
diff --git a/lib/perl/lib/Thrift/SSLServerSocket.pm b/lib/perl/lib/Thrift/SSLServerSocket.pm
new file mode 100644
index 0000000..7b06431
--- /dev/null
+++ b/lib/perl/lib/Thrift/SSLServerSocket.pm
@@ -0,0 +1,76 @@
+#
+# 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.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+
+use Thrift;
+use Thrift::SSLSocket;
+use Thrift::ServerSocket;
+
+use IO::Socket::SSL;
+
+package Thrift::SSLServerSocket;
+use base qw( Thrift::ServerSocket );
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+#
+# Constructor.
+# Takes a hash:
+# See Thrift::Socket for base class parameters.
+# @param[in]  ca     certificate authority filename - not required
+# @param[in]  cert   certificate filename; may contain key in which case key is not required
+# @param[in]  key    private key filename for the certificate if it is not inside the cert file
+#
+sub new
+{
+    my $classname = shift;
+    my $self      = $classname->SUPER::new(@_);
+    return bless($self, $classname);
+}
+
+sub __client
+{
+  return Thrift::SSLSocket->new();
+}
+
+sub __listen
+{
+    my $self = shift;
+    my $opts = {Listen        => $self->{queue},
+                LocalAddr     => $self->{host},
+                LocalPort     => $self->{port},
+                Proto         => 'tcp',
+                ReuseAddr     => 1};
+
+    my $verify = IO::Socket::SSL::SSL_VERIFY_PEER | IO::Socket::SSL::SSL_VERIFY_FAIL_IF_NO_PEER_CERT | IO::Socket::SSL::SSL_VERIFY_CLIENT_ONCE;
+
+    $opts->{SSL_ca_file}      = $self->{ca}      if defined $self->{ca};
+    $opts->{SSL_cert_file}    = $self->{cert}    if defined $self->{cert};
+    $opts->{SSL_cipher_list}  = $self->{ciphers} if defined $self->{ciphers};
+    $opts->{SSL_key_file}     = $self->{key}     if defined $self->{key};
+    $opts->{SSL_use_cert}     = (defined $self->{cert}) ? 1 : 0;
+    $opts->{SSL_verify_mode}  = (defined $self->{ca}) ? $verify : IO::Socket::SSL::SSL_VERIFY_NONE;
+    $opts->{SSL_version}      = (defined $self->{version}) ? $self->{version} : 'SSLv23:!SSLv3:!SSLv2';
+
+    return IO::Socket::SSL->new(%$opts);
+}
+
+1;
diff --git a/lib/perl/lib/Thrift/SSLSocket.pm b/lib/perl/lib/Thrift/SSLSocket.pm
new file mode 100644
index 0000000..e34924d
--- /dev/null
+++ b/lib/perl/lib/Thrift/SSLSocket.pm
@@ -0,0 +1,126 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+
+use Thrift;
+use Thrift::Socket;
+
+use IO::Socket::SSL;
+
+package Thrift::SSLSocket;
+use base qw( Thrift::Socket );
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+#
+# Construction and usage
+#
+# my $opts = {}
+# my $socket = Thrift::SSLSocket->new(\%opts);
+#
+# options:
+#
+# Any option from Socket.pm is valid, and then:
+#
+# ca          => certificate authority file (PEM file) to authenticate the
+#                server against; if not specified then the server is not
+#                authenticated
+# cert        => certificate to use as the client; if not specified then
+#                the client does not present one but still connects using
+#                secure protocol
+# ciphers     => allowed cipher list
+#                (see http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS)
+# key         => certificate key for "cert" option
+# version     => acceptable SSL/TLS versions - if not specified then the
+#                default is to use SSLv23 handshake but only negotiate
+#                at TLSv1.0 or later
+#
+
+sub new
+{
+    my $classname = shift;
+    my $self      = $classname->SUPER::new(@_);
+
+    return bless($self, $classname);
+}
+
+sub __open
+{
+    my $self = shift;
+    my $opts = {PeerAddr      => $self->{host},
+                PeerPort      => $self->{port},
+                Proto         => 'tcp',
+                Timeout       => $self->{sendTimeout} / 1000};
+
+    my $verify = IO::Socket::SSL::SSL_VERIFY_PEER | IO::Socket::SSL::SSL_VERIFY_FAIL_IF_NO_PEER_CERT | IO::Socket::SSL::SSL_VERIFY_CLIENT_ONCE;
+
+    $opts->{SSL_ca_file}      = $self->{ca}      if defined $self->{ca};
+    $opts->{SSL_cert_file}    = $self->{cert}    if defined $self->{cert};
+    $opts->{SSL_cipher_list}  = $self->{ciphers} if defined $self->{ciphers};
+    $opts->{SSL_key_file}     = $self->{key}     if defined $self->{key};
+    $opts->{SSL_use_cert}     = (defined $self->{cert}) ? 1 : 0;
+    $opts->{SSL_verify_mode}  = (defined $self->{ca}) ? $verify : IO::Socket::SSL::SSL_VERIFY_NONE;
+    $opts->{SSL_version}      = (defined $self->{version}) ? $self->{version} : 'SSLv23:!SSLv3:!SSLv2';
+
+    return IO::Socket::SSL->new(%$opts);
+}
+
+sub __close
+{
+    my $self = shift;
+    my $sock = ($self->{handle}->handles())[0];
+    if ($sock) {
+      $sock->close(SSL_no_shutdown => 1);
+    }
+}
+
+sub __recv
+{
+  my $self = shift;
+  my $sock = shift;
+  my $len = shift;
+  my $buf = undef;
+  if ($sock) {
+    sysread($sock, $buf, $len);
+  }
+  return $buf;
+}
+
+sub __send
+{
+    my $self = shift;
+    my $sock = shift;
+    my $buf = shift;
+    return syswrite($sock, $buf);
+}
+
+sub __wait
+{
+    my $self = shift;
+    my $sock = ($self->{handle}->handles())[0];
+    if ($sock and $sock->pending() eq 0) {
+        return $self->SUPER::__wait();
+    }
+    return $sock;
+}
+
+
+1;
diff --git a/lib/perl/lib/Thrift/Server.pm b/lib/perl/lib/Thrift/Server.pm
index 960fbd1..28822e8 100644
--- a/lib/perl/lib/Thrift/Server.pm
+++ b/lib/perl/lib/Thrift/Server.pm
@@ -17,25 +17,31 @@
 # under the License.
 #
 
-require 5.6.0;
+use 5.10.0;
 use strict;
 use warnings;
 
 use Thrift;
-use Thrift::BufferedTransport;
 use Thrift::BinaryProtocol;
+use Thrift::BufferedTransport;
+use Thrift::Exception;
 
 #
 # Server base class module
 #
 package Thrift::Server;
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
+#
 # 3 possible constructors:
 #   1.  (processor, serverTransport)
+#       Uses a BufferedTransportFactory and a BinaryProtocolFactory.
 #   2.  (processor, serverTransport, transportFactory, protocolFactory)
+#       Uses the same factory for input and output of each type.
 #   3.  (processor, serverTransport,
 #        inputTransportFactory, outputTransportFactory,
 #        inputProtocolFactory, outputProtocolFactory)
+#
 sub new
 {
     my $classname    = shift;
@@ -45,7 +51,7 @@
 
     if (scalar @args == 2)
     {
-      $self = _init($args[0], $args[1],
+        $self = _init($args[0], $args[1],
                     Thrift::BufferedTransportFactory->new(),
                     Thrift::BufferedTransportFactory->new(),
                     Thrift::BinaryProtocolFactory->new(),
@@ -61,7 +67,7 @@
     }
     else
     {
-      die "Thrift::Server expects exactly 2, 4, or 6 args";
+      die Thrift::TException->new('Thrift::Server expects exactly 2, 4, or 6 args');
     }
 
     return bless($self,$classname);
@@ -88,7 +94,7 @@
 
 sub serve
 {
-    die "abstract";
+    die 'abstract';
 }
 
 sub _clientBegin
@@ -109,62 +115,68 @@
     my $self = shift;
     my $e    = shift;
 
-    if ($e =~ m/TException/ and exists $e->{message}) {
+    if ($e->isa('Thrift::TException') and exists $e->{message}) {
         my $message = $e->{message};
         my $code    = $e->{code};
         my $out     = $code . ':' . $message;
 
         $message =~ m/TTransportException/ and die $out;
-        if ($message =~ m/TSocket/) {
-            # suppress TSocket messages
-        } else {
+        if ($message =~ m/Socket/) {
+            # suppress Socket messages
+        }
+        else {
             warn $out;
         }
-    } else {
+    }
+    else {
         warn $e;
     }
 }
 
-
 #
 # SimpleServer from the Server base class that handles one connection at a time
 #
 package Thrift::SimpleServer;
-use base qw( Thrift::Server );
+use parent -norequire, 'Thrift::Server';
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 sub new
 {
     my $classname = shift;
-    my @args      = @_;
 
-    my $self      = $classname->SUPER::new(@args);
+    my $self      = $classname->SUPER::new(@_);
+
     return bless($self,$classname);
 }
 
 sub serve
 {
     my $self = shift;
+    my $stop = 0;
 
     $self->{serverTransport}->listen();
-    while (1)
-    {
+    while (!$stop) {
         my $client = $self->{serverTransport}->accept();
-        my $itrans = $self->{inputTransportFactory}->getTransport($client);
-        my $otrans = $self->{outputTransportFactory}->getTransport($client);
-        my $iprot  = $self->{inputProtocolFactory}->getProtocol($itrans);
-        my $oprot  = $self->{outputProtocolFactory}->getProtocol($otrans);
-        eval {
-            $self->_clientBegin($iprot, $oprot);
-            while (1)
-            {
-                $self->{processor}->process($iprot, $oprot);
+        if (defined $client) {
+            my $itrans = $self->{inputTransportFactory}->getTransport($client);
+            my $otrans = $self->{outputTransportFactory}->getTransport($client);
+            my $iprot  = $self->{inputProtocolFactory}->getProtocol($itrans);
+            my $oprot  = $self->{outputProtocolFactory}->getProtocol($otrans);
+            eval {
+                $self->_clientBegin($iprot, $oprot);
+                while (1)
+                {
+                    $self->{processor}->process($iprot, $oprot);
+                }
+            };
+            if($@) {
+                $self->_handleException($@);
             }
-        }; if($@) {
-            $self->_handleException($@);
+            $itrans->close();
+            $otrans->close();
+        } else {
+            $stop = 1;
         }
-
-        $itrans->close();
-        $otrans->close();
     }
 }
 
@@ -173,9 +185,9 @@
 # ForkingServer that forks a new process for each request
 #
 package Thrift::ForkingServer;
-use base qw( Thrift::Server );
-
-use POSIX ":sys_wait_h";
+use parent -norequire, 'Thrift::Server';
+use POSIX ':sys_wait_h';
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 sub new
 {
@@ -191,6 +203,9 @@
 {
     my $self = shift;
 
+    # THRIFT-3848: without ignoring SIGCHLD, perl ForkingServer goes into a tight loop
+    $SIG{CHLD} = 'IGNORE';
+
     $self->{serverTransport}->listen();
     while (1)
     {
@@ -215,13 +230,15 @@
 
         my $pid = fork();
 
-        if ($pid) #parent
+        if ($pid)
         {
             $self->_parent($pid, $itrans, $otrans);
-        } else {
+        }
+        else {
             $self->_child($itrans, $otrans, $iprot, $oprot);
         }
-    }; if($@) {
+    };
+    if($@) {
         $self->_handleException($@);
     }
 }
@@ -233,10 +250,6 @@
     my $itrans = shift;
     my $otrans = shift;
 
-    # add before collect, otherwise you race w/ waitpid
-    $self->{children}->{$pid} = 1;
-    $self->_collectChildren();
-
     # Parent must close socket or the connection may not get closed promptly
     $self->tryClose($itrans);
     $self->tryClose($otrans);
@@ -252,11 +265,14 @@
 
     my $ecode = 0;
     eval {
+        # THRIFT-4065 ensure child process has normal signal handling in case thrift handler uses it
+        $SIG{CHLD} = 'DEFAULT';
         while (1)
         {
             $self->{processor}->process($iprot, $oprot);
         }
-    }; if($@) {
+    };
+    if($@) {
         $ecode = 1;
         $self->_handleException($@);
     }
@@ -277,37 +293,19 @@
         {
           $file->close();
         }
-    }; if($@) {
-        if ($@ =~ m/TException/ and exists $@->{message}) {
+    };
+    if($@) {
+        if ($@->isa('Thrift::TException') and exists $@->{message}) {
             my $message = $@->{message};
             my $code    = $@->{code};
             my $out     = $code . ':' . $message;
 
             warn $out;
-        } else {
+        }
+        else {
             warn $@;
         }
     }
 }
 
-sub _collectChildren
-{
-    my $self = shift;
-
-    while (scalar keys %{$self->{children}})
-    {
-        my $pid    = waitpid(-1, WNOHANG);
-
-        if ($pid>0)
-        {
-            delete $self->{children}->{$pid};
-        }
-        else
-        {
-            last;
-        }
-    }
-}
-
-
 1;
diff --git a/lib/perl/lib/Thrift/ServerSocket.pm b/lib/perl/lib/Thrift/ServerSocket.pm
new file mode 100644
index 0000000..3972643
--- /dev/null
+++ b/lib/perl/lib/Thrift/ServerSocket.pm
@@ -0,0 +1,125 @@
+#
+# 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.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+
+use IO::Socket::INET;
+use IO::Select;
+use Thrift;
+use Thrift::Transport;
+use Thrift::Socket;
+
+package Thrift::ServerSocket;
+use base qw( Thrift::ServerTransport );
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+#
+# Constructor.
+# Legacy construction takes one argument, port number.
+# New construction takes a hash:
+# @param[in]  host   host interface to listen on (undef = all interfaces)
+# @param[in]  port   port number to listen on (required)
+# @param[in]  queue  the listen queue size (default if not specified is 128)
+# @example    my $serversock = Thrift::ServerSocket->new(host => undef, port => port)
+#
+sub new
+{
+    my $classname = shift;
+    my $args      = shift;
+    my $self;
+
+    # Support both old-style "port number" construction and newer...
+    if (ref($args) eq 'HASH') {
+        $self = $args;
+    }
+    else {
+        $self = { port => $args };
+    }
+
+    if (not defined $self->{queue}) {
+        $self->{queue} = 128;
+    }
+
+    return bless($self, $classname);
+}
+
+sub listen
+{
+    my $self = shift;
+
+    my $sock = $self->__listen() || do {
+        my $error = ref($self) . ': Could not bind to ' . '*:' . $self->{port} . ' (' . $! . ')';
+
+        if ($self->{debug}) {
+            $self->{debugHandler}->($error);
+        }
+
+        die Thrift::TTransportException->new($error, Thrift::TTransportException::NOT_OPEN);
+    };
+
+    $self->{handle} = $sock;
+}
+
+sub accept
+{
+    my $self = shift;
+
+    if ( exists $self->{handle} and defined $self->{handle} ) {
+        my $client        = $self->{handle}->accept();
+        my $result        = $self->__client();
+        $result->{handle} = IO::Select->new($client);
+        return $result;
+    }
+
+    return undef;
+}
+
+sub close
+{
+    my $self = shift;
+
+    if ( exists $self->{handle} and defined $self->{handle} )
+    {
+        $self->{handle}->close();
+    }
+}
+
+###
+### Overridable methods
+###
+
+sub __client
+{
+  return Thrift::Socket->new();
+}
+
+sub __listen
+{
+    my $self = shift;
+    return IO::Socket::INET->new(LocalAddr => $self->{host},
+                                 LocalPort => $self->{port},
+                                 Proto     => 'tcp',
+                                 Listen    => $self->{queue},
+                                 ReuseAddr => 1);
+}
+
+
+1;
diff --git a/lib/perl/lib/Thrift/Socket.pm b/lib/perl/lib/Thrift/Socket.pm
index 7ebea35..ba0db5e 100644
--- a/lib/perl/lib/Thrift/Socket.pm
+++ b/lib/perl/lib/Thrift/Socket.pm
@@ -17,37 +17,63 @@
 # under the License.
 #
 
-require 5.6.0;
+use 5.10.0;
 use strict;
 use warnings;
 
 use Thrift;
+use Thrift::Exception;
 use Thrift::Transport;
 
 use IO::Socket::INET;
 use IO::Select;
 
 package Thrift::Socket;
+use base qw( Thrift::Transport );
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
-use base('Thrift::Transport');
+#
+# Construction and usage
+#
+# my $opts = {}
+# my $socket = Thrift::Socket->new(\%opts);
+#
+# options:
+#
+# host        => host to connect to
+# port        => port to connect to
+# sendTimeout => timeout used for send and for connect
+# recvTimeout => timeout used for recv
+#
 
 sub new
 {
-    my $classname    = shift;
-    my $host         = shift || "localhost";
-    my $port         = shift || 9090;
-    my $debugHandler = shift;
+    my $classname = shift;
+    my $opts      = shift;
 
+    # default settings:
     my $self = {
-        host         => $host,
-        port         => $port,
-        debugHandler => $debugHandler,
-        debug        => 0,
-        sendTimeout  => 10000,
+        host         => 'localhost',
+        port         => 9090,
         recvTimeout  => 10000,
-        handle       => undef,
+        sendTimeout  => 10000,
+
+        handle       => undef
     };
 
+    if (defined $opts and ref $opts eq ref {}) {
+
+      # argument is a hash of options so override the defaults
+      $self->{$_} = $opts->{$_} for keys %$opts;
+
+    } else {
+
+      # older style constructor takes 3 arguments, none of which are required
+      $self->{host} = $opts || 'localhost';
+      $self->{port} = shift || 9090;
+
+    }
+
     return bless($self,$classname);
 }
 
@@ -70,19 +96,6 @@
 
 
 #
-#Sets debugging output on or off
-#
-# @param bool $debug
-#
-sub setDebug
-{
-    my $self  = shift;
-    my $debug = shift;
-
-    $self->{debug} = $debug;
-}
-
-#
 # Tests whether this is open
 #
 # @return bool true if the socket is open
@@ -105,23 +118,12 @@
 {
     my $self = shift;
 
-    my $sock = IO::Socket::INET->new(PeerAddr => $self->{host},
-                                            PeerPort => $self->{port},
-                                            Proto    => 'tcp',
-                                            Timeout  => $self->{sendTimeout}/1000)
-        || do {
-            my $error = 'TSocket: Could not connect to '.$self->{host}.':'.$self->{port}.' ('.$!.')';
+    my $sock = $self->__open() || do {
+        my $error = ref($self).': Could not connect to '.$self->{host}.':'.$self->{port}.' ('.$!.')';
+        die Thrift::TTransportException->new($error, Thrift::TTransportException::NOT_OPEN);
+    };
 
-            if ($self->{debug}) {
-                $self->{debugHandler}->($error);
-            }
-
-            die new Thrift::TException($error);
-
-        };
-
-
-    $self->{handle} = new IO::Select( $sock );
+    $self->{handle} = IO::Select->new( $sock );
 }
 
 #
@@ -130,9 +132,8 @@
 sub close
 {
     my $self = shift;
-
-    if( defined $self->{handle} ){
-        CORE::close( ($self->{handle}->handles())[0] );
+    if( defined $self->{handle} ) {
+      $self->__close();
     }
 }
 
@@ -153,30 +154,22 @@
     my $pre = "";
     while (1) {
 
-        #check for timeout
-        my @sockets = $self->{handle}->can_read( $self->{recvTimeout} / 1000 );
-
-        if(@sockets == 0){
-            die new Thrift::TException('TSocket: timed out reading '.$len.' bytes from '.
-                                       $self->{host}.':'.$self->{port});
-        }
-
-        my $sock = $sockets[0];
-
-        my ($buf,$sz);
-        $sock->recv($buf, $len);
+        my $sock = $self->__wait();
+        my $buf = $self->__recv($sock, $len);
 
         if (!defined $buf || $buf eq '') {
 
-            die new Thrift::TException('TSocket: Could not read '.$len.' bytes from '.
-                               $self->{host}.':'.$self->{port});
+            die Thrift::TTransportException->new(ref($self).': Could not read '.$len.' bytes from '.
+                               $self->{host}.':'.$self->{port}, Thrift::TTransportException::END_OF_FILE);
 
-        } elsif (($sz = length($buf)) < $len) {
+        }
+        elsif ((my $sz = length($buf)) < $len) {
 
             $pre .= $buf;
             $len -= $sz;
 
-        } else {
+        }
+        else {
             return $pre.$buf;
         }
     }
@@ -195,23 +188,13 @@
 
     return unless defined $self->{handle};
 
-    #check for timeout
-    my @sockets = $self->{handle}->can_read( $self->{recvTimeout} / 1000 );
-
-    if(@sockets == 0){
-        die new Thrift::TException('TSocket: timed out reading '.$len.' bytes from '.
-                                   $self->{host}.':'.$self->{port});
-    }
-
-    my $sock = $sockets[0];
-
-    my ($buf,$sz);
-    $sock->recv($buf, $len);
+    my $sock = $self->__wait();
+    my $buf = $self->__recv($sock, $len);
 
     if (!defined $buf || $buf eq '') {
 
-        die new TException('TSocket: Could not read '.$len.' bytes from '.
-                           $self->{host}.':'.$self->{port});
+        die Thrift::TTransportException->new(ref($self).': Could not read '.$len.' bytes from '.
+                           $self->{host}.':'.$self->{port}, Thrift::TTransportException::END_OF_FILE);
 
     }
 
@@ -229,30 +212,27 @@
     my $self = shift;
     my $buf  = shift;
 
-
     return unless defined $self->{handle};
 
     while (length($buf) > 0) {
-
-
         #check for timeout
         my @sockets = $self->{handle}->can_write( $self->{sendTimeout} / 1000 );
 
         if(@sockets == 0){
-            die new Thrift::TException('TSocket: timed out writing to bytes from '.
-                                       $self->{host}.':'.$self->{port});
+            die Thrift::TTransportException->new(ref($self).': timed out writing to bytes from '.
+                                       $self->{host}.':'.$self->{port}, Thrift::TTransportException::TIMED_OUT);
         }
 
-        my $sock = $sockets[0];
+        my $sent = $self->__send($sockets[0], $buf);
 
-        my $got = $sock->send($buf);
+        if (!defined $sent || $sent == 0 ) {
 
-        if (!defined $got || $got == 0 ) {
-            die new Thrift::TException('TSocket: Could not write '.length($buf).' bytes '.
-                                 $self->{host}.':'.$self->{host});
+            die Thrift::TTransportException->new(ref($self).': Could not write '.length($buf).' bytes '.
+                                 $self->{host}.':'.$self->{host}, Thrift::TTransportException::END_OF_FILE);
+
         }
 
-        $buf = substr($buf, $got);
+        $buf = substr($buf, $sent);
     }
 }
 
@@ -265,65 +245,82 @@
 
     return unless defined $self->{handle};
 
-    my $ret  = ($self->{handle}->handles())[0]->flush;
+    my $ret = ($self->{handle}->handles())[0]->flush;
 }
 
+###
+### Overridable methods
+###
 
 #
-# Build a ServerSocket from the ServerTransport base class
+# Open a connection to a server.
 #
-package  Thrift::ServerSocket;
-
-use base qw( Thrift::Socket Thrift::ServerTransport );
-
-use constant LISTEN_QUEUE_SIZE => 128;
-
-sub new
-{
-    my $classname   = shift;
-    my $port        = shift;
-
-    my $self        = $classname->SUPER::new(undef, $port, undef);
-    return bless($self,$classname);
-}
-
-sub listen
+sub __open
 {
     my $self = shift;
-
-    # Listen to a new socket
-    my $sock = IO::Socket::INET->new(LocalAddr => undef, # any addr
-                                     LocalPort => $self->{port},
-                                     Proto     => 'tcp',
-                                     Listen    => LISTEN_QUEUE_SIZE,
-                                     ReuseAddr => 1)
-        || do {
-            my $error = 'TServerSocket: Could not bind to ' .
-                        $self->{host} . ':' . $self->{port} . ' (' . $! . ')';
-
-            if ($self->{debug}) {
-                $self->{debugHandler}->($error);
-            }
-
-            die new Thrift::TException($error);
-        };
-
-    $self->{handle} = $sock;
+    return IO::Socket::INET->new(PeerAddr => $self->{host},
+                                 PeerPort => $self->{port},
+                                 Proto    => 'tcp',
+                                 Timeout  => $self->{sendTimeout} / 1000);
 }
 
-sub accept
+#
+# Close the connection
+#
+sub __close
+{
+  my $self = shift;
+    CORE::close(($self->{handle}->handles())[0]);
+}
+
+#
+# Read data
+#
+# @param[in] $sock the socket
+# @param[in] $len the length to read
+# @returns the data buffer that was read
+#
+sub __recv
+{
+  my $self = shift;
+  my $sock = shift;
+  my $len = shift;
+  my $buf = undef;
+  $sock->recv($buf, $len);
+  return $buf;
+}
+
+#
+# Send data
+#
+# @param[in] $sock the socket
+# @param[in] $buf the data buffer
+# @returns the number of bytes written
+#
+sub __send
 {
     my $self = shift;
+    my $sock = shift;
+    my $buf = shift;
+    return $sock->send($buf);
+}
 
-    if ( exists $self->{handle} and defined $self->{handle} )
-    {
-        my $client        = $self->{handle}->accept();
-        my $result        = new Thrift::Socket;
-        $result->{handle} = new IO::Select($client);
-        return $result;
+#
+# Wait for data to be readable
+#
+# @returns a socket that can be read
+#
+sub __wait
+{
+    my $self = shift;
+    my @sockets = $self->{handle}->can_read( $self->{recvTimeout} / 1000 );
+
+    if (@sockets == 0) {
+        die Thrift::TTransportException->new(ref($self).': timed out reading from '.
+                                   $self->{host}.':'.$self->{port}, Thrift::TTransportException::TIMED_OUT);
     }
 
-    return 0;
+    return $sockets[0];
 }
 
 
diff --git a/lib/perl/lib/Thrift/Transport.pm b/lib/perl/lib/Thrift/Transport.pm
index 5ec6fee..41b7e15 100644
--- a/lib/perl/lib/Thrift/Transport.pm
+++ b/lib/perl/lib/Thrift/Transport.pm
@@ -17,17 +17,19 @@
 # under the License.
 #
 
-require 5.6.0;
+use 5.10.0;
 use strict;
 use warnings;
 
 use Thrift;
+use Thrift::Exception;
 
 #
 # Transport exceptions
 #
-package TTransportException;
+package Thrift::TTransportException;
 use base('Thrift::TException');
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 use constant UNKNOWN      => 0;
 use constant NOT_OPEN     => 1;
@@ -35,7 +37,7 @@
 use constant TIMED_OUT    => 3;
 use constant END_OF_FILE  => 4;
 
-sub new{
+sub new {
     my $classname = shift;
     my $self      = $classname->SUPER::new(@_);
 
@@ -43,6 +45,7 @@
 }
 
 package Thrift::Transport;
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 #
 # Whether this transport is open.
@@ -51,7 +54,7 @@
 #
 sub isOpen
 {
-    die "abstract";
+    die 'abstract';
 }
 
 #
@@ -61,7 +64,7 @@
 #
 sub open
 {
-    die "abstract";
+    die 'abstract';
 }
 
 #
@@ -69,7 +72,7 @@
 #
 sub close
 {
-    die "abstract";
+    die 'abstract';
 }
 
 #
@@ -81,8 +84,7 @@
 #
 sub read
 {
-    my ($len);
-    die("abstract");
+    die 'abstract';
 }
 
 #
@@ -114,8 +116,7 @@
 #
 sub write
 {
-    my ($buf);
-    die "abstract";
+    die 'abstract';
 }
 
 #
@@ -130,6 +131,7 @@
 # TransportFactory creates transport objects from transports
 #
 package Thrift::TransportFactory;
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 sub new {
     my $classname = shift;
@@ -156,20 +158,21 @@
 #  ServerTransport base class module
 #
 package Thrift::ServerTransport;
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
 
 sub listen
 {
-    die "abstract";
+    die 'abstract';
 }
 
 sub accept
 {
-    die "abstract";
+    die 'abstract';
 }
 
 sub close
 {
-    die "abstract";
+    die 'abstract';
 }
 
 
diff --git a/lib/perl/lib/Thrift/Type.pm b/lib/perl/lib/Thrift/Type.pm
new file mode 100644
index 0000000..ad8da3b
--- /dev/null
+++ b/lib/perl/lib/Thrift/Type.pm
@@ -0,0 +1,50 @@
+#
+# 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.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+
+use Thrift;
+
+#
+# Data types that can be sent via Thrift
+#
+package Thrift::TType;
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+use constant STOP   => 0;
+use constant VOID   => 1;
+use constant BOOL   => 2;
+use constant BYTE   => 3;
+use constant I08    => 3;
+use constant DOUBLE => 4;
+use constant I16    => 6;
+use constant I32    => 8;
+use constant I64    => 10;
+use constant STRING => 11;
+use constant UTF7   => 11;
+use constant STRUCT => 12;
+use constant MAP    => 13;
+use constant SET    => 14;
+use constant LIST   => 15;
+use constant UTF8   => 16;
+use constant UTF16  => 17;
+
+1;
diff --git a/lib/perl/lib/Thrift/UnixServerSocket.pm b/lib/perl/lib/Thrift/UnixServerSocket.pm
new file mode 100644
index 0000000..875e804
--- /dev/null
+++ b/lib/perl/lib/Thrift/UnixServerSocket.pm
@@ -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.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+
+use Thrift;
+use Thrift::ServerSocket;
+use Thrift::UnixSocket;
+
+use IO::Socket::UNIX;
+
+package Thrift::UnixServerSocket;
+use base qw( Thrift::ServerSocket );
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+#
+# Constructor.
+# If a single argument is given that is not a hash, that is the unix domain socket path.
+# If a single argument is given that is a hash:
+# @param[in]  path   unix domain socket file name
+# @param[in]  queue  the listen queue size (default is not specified is supplied by ServerSocket)
+# @example    my $serversock = Thrift::UnixServerSocket->new($path);
+# @example    my $serversock = Thrift::UnixServerSocket->new(path => "somepath", queue => 64);
+#
+sub new
+{
+    my $classname = shift;
+    my $args      = shift;
+    my $self;
+
+    if (ref($args) eq 'HASH') {
+        $self = $classname->SUPER::new($args);
+    } else {
+        $self = $classname->SUPER::new();
+        $self->{path} = $args;
+    }
+
+    return bless($self, $classname);
+}
+
+sub __client
+{
+  return Thrift::UnixSocket->new();
+}
+
+sub __listen
+{
+    my $self = shift;
+
+    my $sock = IO::Socket::UNIX->new(
+        Type      => IO::Socket::SOCK_STREAM,
+        Local     => $self->{path},
+        Listen    => $self->{queue})
+    || do {
+        my $error = 'UnixServerSocket: Could not bind to ' .
+                    $self->{path} . ' (' . $! . ')';
+        if ($self->{debug}) {
+            $self->{debugHandler}->($error);
+        }
+        die Thrift::TTransportException->new($error, Thrift::TTransportException::NOT_OPEN);
+    };
+
+    return $sock;
+}
+
+1;
diff --git a/lib/perl/lib/Thrift/UnixSocket.pm b/lib/perl/lib/Thrift/UnixSocket.pm
new file mode 100644
index 0000000..ba386d1
--- /dev/null
+++ b/lib/perl/lib/Thrift/UnixSocket.pm
@@ -0,0 +1,67 @@
+#
+# 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.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+
+use Thrift;
+use Thrift::Socket;
+
+use IO::Socket::UNIX;
+
+package Thrift::UnixSocket;
+use base qw( Thrift::Socket );
+use version 0.77; our $VERSION = version->declare("$Thrift::VERSION");
+
+#
+# Constructor.
+# Takes a unix domain socket filename.
+# See Thrift::Socket for base class parameters.
+# @param[in]  path   path to unix socket file
+# @example    my $sock = Thrift::UnixSocket->new($path);
+#
+sub new
+{
+    my $classname = shift;
+    my $self      = $classname->SUPER::new();
+    $self->{path} = shift;
+    return bless($self, $classname);
+}
+
+sub __open
+{
+    my $self = shift;
+
+    my $sock = IO::Socket::UNIX->new(
+        Type      => IO::Socket::SOCK_STREAM,
+        Peer      => $self->{path})
+    || do {
+        my $error = 'UnixSocket: Could not connect to ' .
+            $self->{path} . ' (' . $! . ')';
+        if ($self->{debug}) {
+            $self->{debugHandler}->($error);
+        }
+        die Thrift::TTransportException->new($error, Thrift::TTransportException::NOT_OPEN);
+    };
+
+    return $sock;
+}
+
+1;
diff --git a/lib/perl/test/Makefile.am b/lib/perl/test/Makefile.am
index 795aaed..de03971 100644
--- a/lib/perl/test/Makefile.am
+++ b/lib/perl/test/Makefile.am
@@ -17,15 +17,4 @@
 # under the License.
 #
 
-THRIFT = @top_builddir@/compiler/cpp/thrift
-THRIFT_IF = @top_srcdir@/test/ThriftTest.thrift
-
-check-local: gen-perl/ThriftTest/Types.pm
-
-gen-perl/ThriftTest/Types.pm: $(THRIFT_IF)
-	$(THRIFT) --gen perl $(THRIFT_IF)
-
-clean-local:
-	rm -rf gen-perl
-
-EXTRA_DIST = memory_buffer.t processor.t
+EXTRA_DIST = memory_buffer.t processor.t multiplex.t
diff --git a/lib/perl/test/multiplex.t b/lib/perl/test/multiplex.t
new file mode 100644
index 0000000..90a9b4d
--- /dev/null
+++ b/lib/perl/test/multiplex.t
@@ -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.
+#
+
+use Test::More tests => 6;
+
+use strict;
+use warnings;
+
+use Thrift::BinaryProtocol;
+use Thrift::FramedTransport;
+use Thrift::MemoryBuffer;
+use Thrift::MessageType;
+use Thrift::MultiplexedProcessor;
+use Thrift::Server;
+use Thrift::Socket;
+
+use BenchmarkService;
+use Aggr;
+
+use constant NAME_BENCHMARKSERVICE => 'BenchmarkService';
+use constant NAME_AGGR  =>  'Aggr';
+
+my $buffer    = Thrift::MemoryBuffer->new(1024);
+my $aggr_protocol  = Thrift::MultiplexedProtocol->new(Thrift::BinaryProtocol->new($buffer), NAME_AGGR);
+my $aggr_client    = AggrClient->new($aggr_protocol);
+my $benchmark_protocol = Thrift::MultiplexedProtocol->new(Thrift::BinaryProtocol->new($buffer), NAME_BENCHMARKSERVICE);
+my $benchmark_client = BenchmarkServiceClient->new($benchmark_protocol); 
+
+$buffer->open();
+
+for(my $i = 1; $i <= 5; $i++) {
+    $aggr_client->send_addValue($i);
+    $aggr_client->{seqid}++;
+}
+
+$aggr_client->send_getValues();
+
+for(my $i = 1; $i <= 5; $i++) {
+    $benchmark_client->send_fibonacci($i);
+    $benchmark_client->{seqid}++;
+}
+$benchmark_client->{seqid}--;
+
+my $client_command_binary = $buffer->getBuffer;
+$buffer->resetBuffer;
+
+
+# Process by server
+my $server_output_binary;
+{
+    my $benchmark_handler = My::BenchmarkService->new();
+    my $benchmark_processor = BenchmarkServiceProcessor->new($benchmark_handler);
+    my $aggr_handler = My::Aggr->new(); 
+    my $aggr_processor = AggrProcessor->new($aggr_handler);
+    
+    my $protocol_factory = Thrift::BinaryProtocolFactory->new();
+
+    my $input_buffer    = Thrift::MemoryBuffer->new();
+    $input_buffer->write($client_command_binary);
+
+    my $input_protocol  = $protocol_factory->getProtocol($input_buffer);
+
+    my $output_buffer   = Thrift::MemoryBuffer->new();
+    my $output_protocol = $protocol_factory->getProtocol($output_buffer);
+
+    my $processor = Thrift::MultiplexedProcessor->new();
+
+    $processor->registerProcessor(NAME_BENCHMARKSERVICE, $benchmark_processor);
+    $processor->registerProcessor(NAME_AGGR, $aggr_processor);
+    my $result;
+    for(my $i = 1; $i <= 11; $i++) {
+        $result = $processor->process($input_protocol, $output_protocol);
+        print "process resulted in $result\n";
+    }
+
+    $server_output_binary = $output_buffer->getBuffer();
+}
+
+$buffer->write($server_output_binary);
+
+
+
+for(my $i = 1; $i <= 5; $i++) {
+    my ($function_name, $message_type, $sequence_id);
+
+    $aggr_protocol->readMessageBegin(\$function_name, \$message_type, \$sequence_id);
+
+    if ($message_type == Thrift::TMessageType::EXCEPTION) {
+       die;
+    }
+    
+    my $aggr_result = Aggr_addValue_result->new();
+    $aggr_result->read($aggr_protocol);
+    $aggr_protocol->readMessageEnd();
+}
+
+my ($function_name, $message_type, $sequence_id);
+
+$aggr_protocol->readMessageBegin(\$function_name, \$message_type, \$sequence_id);
+
+if ($message_type == Thrift::TMessageType::EXCEPTION) {
+    die;
+}
+    
+my $aggr_result = Aggr_getValues_result->new();
+$aggr_result->read($aggr_protocol);
+$aggr_protocol->readMessageEnd();
+
+is_deeply($aggr_result->success(), [1,2,3,4,5]);
+ 
+
+foreach my $val((1,2,3,5,8)) {
+    my ($function_name, $message_type, $sequence_id);
+
+    $benchmark_protocol->readMessageBegin(\$function_name, \$message_type, \$sequence_id);
+
+    if ($message_type == Thrift::TMessageType::EXCEPTION) {
+        die;
+    }
+    my $benchmark_result = BenchmarkService_fibonacci_result->new();
+    $benchmark_result->read($benchmark_protocol);
+    $benchmark_protocol->readMessageEnd();
+    
+    is($benchmark_result->success(), $val);
+}
+
+
+package My::Aggr;
+use base qw(AggrIf); 
+
+use strict;
+use warnings; 
+
+sub new {
+    my $classname = shift;
+    my $self      = {};
+    
+    $self->{values} = ();
+
+    return bless($self,$classname);
+}
+
+sub addValue{
+    my $self = shift;
+    my $value = shift;
+
+    push (@{$self->{values}}, $value);  
+}
+
+sub getValues{
+    my $self = shift;
+    
+   return $self->{values};
+}
+
+
+
+package My::BenchmarkService;
+use base qw(BenchmarkServiceIf);
+
+use strict;
+use warnings;
+
+sub new {
+    my $class = shift;
+    return bless {}, $class;
+}
+
+sub fibonacci {
+    my ($self, $n) = @_;
+    
+    my $prev = 0;
+    my $next;
+    my $result = 1;
+    
+    while ($n > 0) {
+        $next = $result + $prev;
+        $prev = $result;
+        $result = $next;
+        --$n;
+    }
+    
+    return $result;
+}
+
diff --git a/lib/perl/test/processor.t b/lib/perl/test/processor.t
index 1d8be73..f833035 100644
--- a/lib/perl/test/processor.t
+++ b/lib/perl/test/processor.t
@@ -22,9 +22,9 @@
 use strict;
 use warnings;
 
-use Thrift;
 use Thrift::BinaryProtocol;
 use Thrift::MemoryBuffer;
+use Thrift::MessageType;
 
 use ThriftTest::ThriftTest;
 use ThriftTest::Types;
@@ -72,7 +72,7 @@
     $protocol->readMessageBegin(\$function_name, \$message_type, \$sequence_id);
     print "  $function_name, $message_type, $sequence_id\n";
 
-    if ($message_type == TMessageType::EXCEPTION) {
+    if ($message_type == Thrift::TMessageType::EXCEPTION) {
         die;
     }
 
diff --git a/lib/perl/tools/FixupDist.pl b/lib/perl/tools/FixupDist.pl
new file mode 100644
index 0000000..24a2b20
--- /dev/null
+++ b/lib/perl/tools/FixupDist.pl
@@ -0,0 +1,35 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# This will fix up the distribution so that CPAN properly
+# indexes Thrift.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+use utf8;
+
+use Data::Dumper;
+use CPAN::Meta;
+
+my $meta = CPAN::Meta->load_file('META.json');
+$meta->{'provides'} = { 'Thrift' => { 'file' => 'lib/Thrift.pm', 'version' => $meta->version() } };
+$meta->save('META.json');
diff --git a/lib/php/Makefile.am b/lib/php/Makefile.am
index 927de98..8d9050a 100755
--- a/lib/php/Makefile.am
+++ b/lib/php/Makefile.am
@@ -22,104 +22,126 @@
 SUBDIRS = test
 endif
 
-%.so:
-	cd src/ext/thrift_protocol/ \
-	  && $(MAKE)
-
 if WITH_PHP_EXTENSION
+%.so:
+	cd src/ext/thrift_protocol/ && $(MAKE)
+
 phpconfdir=$(PHP_CONFIG_PREFIX)
 phpconf_DATA=thrift_protocol.ini
 
 phpmoduledir = `php-config --extension-dir`
 phpmodule_SCRIPTS = src/ext/thrift_protocol/modules/thrift_protocol.so
+
+distclean-local:
+	cd $(phpmodule_SCRIPTS) && $(PHPIZE) --clean
+
 endif
 
-phpdir = $(PHP_PREFIX)/Thrift
+phpdir = $(PHP_PREFIX)/
+php_DATA = \
+  lib/TMultiplexedProcessor.php
 
 phpbasedir = $(phpdir)/Base
 phpbase_DATA = \
-  lib/Thrift/Base/TBase.php
+  lib/Base/TBase.php
 
 phpclassloaderdir = $(phpdir)/ClassLoader
 phpclassloader_DATA = \
-  lib/Thrift/ClassLoader/ThriftClassLoader.php
+  lib/ClassLoader/ThriftClassLoader.php
 
 phpexceptiondir = $(phpdir)/Exception
 phpexception_DATA = \
-  lib/Thrift/Exception/TApplicationException.php \
-  lib/Thrift/Exception/TException.php \
-  lib/Thrift/Exception/TProtocolException.php \
-  lib/Thrift/Exception/TTransportException.php
+  lib/Exception/TApplicationException.php \
+  lib/Exception/TException.php \
+  lib/Exception/TProtocolException.php \
+  lib/Exception/TTransportException.php
 
 phpfactorydir = $(phpdir)/Factory
 phpfactory_DATA = \
-  lib/Thrift/Factory/TBinaryProtocolFactory.php \
-  lib/Thrift/Factory/TCompactProtocolFactory.php \
-  lib/Thrift/Factory/TJSONProtocolFactory.php \
-  lib/Thrift/Factory/TProtocolFactory.php \
-  lib/Thrift/Factory/TStringFuncFactory.php \
-  lib/Thrift/Factory/TTransportFactory.php
+  lib/Factory/TBinaryProtocolFactory.php \
+  lib/Factory/TCompactProtocolFactory.php \
+  lib/Factory/TJSONProtocolFactory.php \
+  lib/Factory/TProtocolFactory.php \
+  lib/Factory/TStringFuncFactory.php \
+  lib/Factory/TTransportFactory.php
 
 phpprotocoldir = $(phpdir)/Protocol
 phpprotocol_DATA = \
-  lib/Thrift/Protocol/TBinaryProtocolAccelerated.php \
-  lib/Thrift/Protocol/TBinaryProtocol.php \
-  lib/Thrift/Protocol/TCompactProtocol.php \
-  lib/Thrift/Protocol/TJSONProtocol.php \
-  lib/Thrift/Protocol/TProtocol.php
+  lib/Protocol/TBinaryProtocolAccelerated.php \
+  lib/Protocol/TBinaryProtocol.php \
+  lib/Protocol/TCompactProtocol.php \
+  lib/Protocol/TJSONProtocol.php \
+  lib/Protocol/TMultiplexedProtocol.php \
+  lib/Protocol/TProtocol.php \
+  lib/Protocol/TProtocolDecorator.php \
+  lib/Protocol/TSimpleJSONProtocol.php
 
 phpprotocoljsondir = $(phpprotocoldir)/JSON
 phpprotocoljson_DATA = \
-  lib/Thrift/Protocol/JSON/BaseContext.php \
-  lib/Thrift/Protocol/JSON/ListContext.php \
-  lib/Thrift/Protocol/JSON/LookaheadReader.php \
-  lib/Thrift/Protocol/JSON/PairContext.php
+  lib/Protocol/JSON/BaseContext.php \
+  lib/Protocol/JSON/ListContext.php \
+  lib/Protocol/JSON/LookaheadReader.php \
+  lib/Protocol/JSON/PairContext.php
+
+phpprotocolsimplejsondir = $(phpprotocoldir)/SimpleJSON
+phpprotocolsimplejson_DATA = \
+  lib/Protocol/SimpleJSON/CollectionMapKeyException.php \
+  lib/Protocol/SimpleJSON/Context.php \
+  lib/Protocol/SimpleJSON/ListContext.php \
+  lib/Protocol/SimpleJSON/MapContext.php \
+  lib/Protocol/SimpleJSON/StructContext.php
 
 phpserializerdir = $(phpdir)/Serializer
 phpserializer_DATA = \
-  lib/Thrift/Serializer/TBinarySerializer.php
+  lib/Serializer/TBinarySerializer.php
 
 phpserverdir = $(phpdir)/Server
 phpserver_DATA = \
-  lib/Thrift/Server/TServerSocket.php \
-  lib/Thrift/Server/TForkingServer.php \
-  lib/Thrift/Server/TServer.php \
-  lib/Thrift/Server/TServerTransport.php \
-  lib/Thrift/Server/TSimpleServer.php
+  lib/Server/TServerSocket.php \
+  lib/Server/TForkingServer.php \
+  lib/Server/TServer.php \
+  lib/Server/TServerTransport.php \
+  lib/Server/TSimpleServer.php
 
 phpstringfuncdir = $(phpdir)/StringFunc
 phpstringfunc_DATA = \
-  lib/Thrift/StringFunc/Mbstring.php \
-  lib/Thrift/StringFunc/Core.php \
-  lib/Thrift/StringFunc/TStringFunc.php
+  lib/StringFunc/Mbstring.php \
+  lib/StringFunc/Core.php \
+  lib/StringFunc/TStringFunc.php
 
 phptransportdir = $(phpdir)/Transport
 phptransport_DATA = \
-  lib/Thrift/Transport/TBufferedTransport.php \
-  lib/Thrift/Transport/TFramedTransport.php \
-  lib/Thrift/Transport/THttpClient.php \
-  lib/Thrift/Transport/TMemoryBuffer.php \
-  lib/Thrift/Transport/TNullTransport.php \
-  lib/Thrift/Transport/TPhpStream.php \
-  lib/Thrift/Transport/TSocket.php \
-  lib/Thrift/Transport/TSocketPool.php \
-  lib/Thrift/Transport/TTransport.php
+  lib/Transport/TBufferedTransport.php \
+  lib/Transport/TCurlClient.php \
+  lib/Transport/TFramedTransport.php \
+  lib/Transport/THttpClient.php \
+  lib/Transport/TMemoryBuffer.php \
+  lib/Transport/TNullTransport.php \
+  lib/Transport/TPhpStream.php \
+  lib/Transport/TSocket.php \
+  lib/Transport/TSocketPool.php \
+  lib/Transport/TTransport.php
 
 phptypedir = $(phpdir)/Type
 phptype_DATA = \
-  lib/Thrift/Type/TMessageType.php \
-  lib/Thrift/Type/TType.php
+  lib/Type/TMessageType.php \
+  lib/Type/TType.php \
+  lib/Type/TConstant.php
 
 EXTRA_DIST = \
   lib \
   src/autoload.php \
+  src/ext/thrift_protocol/config.m4 \
   src/ext/thrift_protocol/config.w32 \
   src/ext/thrift_protocol/php_thrift_protocol.cpp \
   src/ext/thrift_protocol/php_thrift_protocol.h \
+  src/ext/thrift_protocol/run-tests.php \
   src/Thrift.php \
   src/TStringUtils.php \
+  coding_standards.md \
   thrift_protocol.ini \
-  README.apache
+  README.apache.md \
+  README.md
 
 MAINTAINERCLEANFILES = \
   Makefile \
diff --git a/lib/php/README b/lib/php/README
deleted file mode 100644
index c24ee2c..0000000
--- a/lib/php/README
+++ /dev/null
@@ -1,53 +0,0 @@
-Thrift PHP Software Library
-
-License
-=======
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-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.
-
-Using Thrift with PHP
-=====================
-
-Thrift requires PHP 5. Thrift makes as few assumptions about your PHP
-environment as possible while trying to make some more advanced PHP
-features (i.e. APC cacheing using asbolute path URLs) as simple as possible.
-
-To use Thrift in your PHP codebase, take the following steps:
-
-#1) Copy all of thrift/lib/php/lib into your PHP codebase
-#2) Configure Symfony Autoloader (or whatever you usually use)
-
-After that, you have to manually include the Thrift package
-created by the compiler:
-
-require_once 'packages/Service/Service.php';
-require_once 'packages/Service/Types.php';
-
-Dependencies
-============
-
-PHP_INT_SIZE
-
-  This built-in signals whether your architecture is 32 or 64 bit and is
-  used by the TBinaryProtocol to properly use pack() and unpack() to
-  serialize data.
-
-apc_fetch(), apc_store()
-
-  APC cache is used by the TSocketPool class. If you do not have APC installed,
-  Thrift will fill in null stub function definitions.
diff --git a/lib/php/README.apache b/lib/php/README.apache.md
similarity index 100%
rename from lib/php/README.apache
rename to lib/php/README.apache.md
diff --git a/lib/php/README.md b/lib/php/README.md
new file mode 100644
index 0000000..7170104
--- /dev/null
+++ b/lib/php/README.md
@@ -0,0 +1,60 @@
+Thrift PHP Software Library
+
+# License
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+# Using Thrift with PHP
+
+Thrift requires PHP 5. Thrift makes as few assumptions about your PHP
+environment as possible while trying to make some more advanced PHP
+features (i.e. APC cacheing using asbolute path URLs) as simple as possible.
+
+To use Thrift in your PHP codebase, take the following steps:
+
+1. Copy all of thrift/lib/php/lib into your PHP codebase
+2. Configure Symfony Autoloader (or whatever you usually use)
+
+After that, you have to manually include the Thrift package
+created by the compiler:
+
+```
+require_once 'packages/Service/Service.php';
+require_once 'packages/Service/Types.php';
+```
+
+# Dependencies
+
+PHP_INT_SIZE
+
+    This built-in signals whether your architecture is 32 or 64 bit and is
+    used by the TBinaryProtocol to properly use pack() and unpack() to
+    serialize data.
+
+apc_fetch(), apc_store()
+
+    APC cache is used by the TSocketPool class. If you do not have APC installed,
+    Thrift will fill in null stub function definitions.
+
+# Breaking Changes
+
+## 0.12.0
+
+1. [PSR-4](https://www.php-fig.org/psr/psr-4/) loader is now the default. If you want to use class maps instead, use `-gen php:classmap`.
+
+2. If using PSR-4, use `$thriftClassLoader->registerNamespace('namespace', '<path>')` instead of `$thriftClassLoader->registerDefinition('namespace', '<path>')`.
diff --git a/lib/php/coding_standards.md b/lib/php/coding_standards.md
new file mode 100644
index 0000000..e217539
--- /dev/null
+++ b/lib/php/coding_standards.md
@@ -0,0 +1,5 @@
+## PHP Coding Standards
+
+Please follow:
+ * [Thrift General Coding Standards](/doc/coding_standards.md)
+ * [PSR-2](http://www.php-fig.org/psr/psr-2/)
diff --git a/lib/php/lib/Base/TBase.php b/lib/php/lib/Base/TBase.php
new file mode 100644
index 0000000..c61b631
--- /dev/null
+++ b/lib/php/lib/Base/TBase.php
@@ -0,0 +1,382 @@
+<?php
+/*
+ * 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
+ */
+
+namespace Thrift\Base;
+
+use Thrift\Type\TType;
+
+/**
+ * Base class from which other Thrift structs extend. This is so that we can
+ * cut back on the size of the generated code which is turning out to have a
+ * nontrivial cost just to load thanks to the wondrously abysmal implementation
+ * of PHP. Note that code is intentionally duplicated in here to avoid making
+ * function calls for every field or member of a container..
+ */
+abstract class TBase
+{
+    public static $tmethod = array(
+        TType::BOOL => 'Bool',
+        TType::BYTE => 'Byte',
+        TType::I16 => 'I16',
+        TType::I32 => 'I32',
+        TType::I64 => 'I64',
+        TType::DOUBLE => 'Double',
+        TType::STRING => 'String'
+    );
+
+    abstract public function read($input);
+
+    abstract public function write($output);
+
+    public function __construct($spec = null, $vals = null)
+    {
+        if (is_array($spec) && is_array($vals)) {
+            foreach ($spec as $fid => $fspec) {
+                $var = $fspec['var'];
+                if (isset($vals[$var])) {
+                    $this->$var = $vals[$var];
+                }
+            }
+        }
+    }
+
+    public function __wakeup()
+    {
+        $this->__construct(get_object_vars($this));
+    }
+
+    private function _readMap(&$var, $spec, $input)
+    {
+        $xfer = 0;
+        $ktype = $spec['ktype'];
+        $vtype = $spec['vtype'];
+        $kread = $vread = null;
+        if (isset(TBase::$tmethod[$ktype])) {
+            $kread = 'read' . TBase::$tmethod[$ktype];
+        } else {
+            $kspec = $spec['key'];
+        }
+        if (isset(TBase::$tmethod[$vtype])) {
+            $vread = 'read' . TBase::$tmethod[$vtype];
+        } else {
+            $vspec = $spec['val'];
+        }
+        $var = array();
+        $_ktype = $_vtype = $size = 0;
+        $xfer += $input->readMapBegin($_ktype, $_vtype, $size);
+        for ($i = 0; $i < $size; ++$i) {
+            $key = $val = null;
+            if ($kread !== null) {
+                $xfer += $input->$kread($key);
+            } else {
+                switch ($ktype) {
+                    case TType::STRUCT:
+                        $class = $kspec['class'];
+                        $key = new $class();
+                        $xfer += $key->read($input);
+                        break;
+                    case TType::MAP:
+                        $xfer += $this->_readMap($key, $kspec, $input);
+                        break;
+                    case TType::LST:
+                        $xfer += $this->_readList($key, $kspec, $input, false);
+                        break;
+                    case TType::SET:
+                        $xfer += $this->_readList($key, $kspec, $input, true);
+                        break;
+                }
+            }
+            if ($vread !== null) {
+                $xfer += $input->$vread($val);
+            } else {
+                switch ($vtype) {
+                    case TType::STRUCT:
+                        $class = $vspec['class'];
+                        $val = new $class();
+                        $xfer += $val->read($input);
+                        break;
+                    case TType::MAP:
+                        $xfer += $this->_readMap($val, $vspec, $input);
+                        break;
+                    case TType::LST:
+                        $xfer += $this->_readList($val, $vspec, $input, false);
+                        break;
+                    case TType::SET:
+                        $xfer += $this->_readList($val, $vspec, $input, true);
+                        break;
+                }
+            }
+            $var[$key] = $val;
+        }
+        $xfer += $input->readMapEnd();
+
+        return $xfer;
+    }
+
+    private function _readList(&$var, $spec, $input, $set = false)
+    {
+        $xfer = 0;
+        $etype = $spec['etype'];
+        $eread = $vread = null;
+        if (isset(TBase::$tmethod[$etype])) {
+            $eread = 'read' . TBase::$tmethod[$etype];
+        } else {
+            $espec = $spec['elem'];
+        }
+        $var = array();
+        $_etype = $size = 0;
+        if ($set) {
+            $xfer += $input->readSetBegin($_etype, $size);
+        } else {
+            $xfer += $input->readListBegin($_etype, $size);
+        }
+        for ($i = 0; $i < $size; ++$i) {
+            $elem = null;
+            if ($eread !== null) {
+                $xfer += $input->$eread($elem);
+            } else {
+                $espec = $spec['elem'];
+                switch ($etype) {
+                    case TType::STRUCT:
+                        $class = $espec['class'];
+                        $elem = new $class();
+                        $xfer += $elem->read($input);
+                        break;
+                    case TType::MAP:
+                        $xfer += $this->_readMap($elem, $espec, $input);
+                        break;
+                    case TType::LST:
+                        $xfer += $this->_readList($elem, $espec, $input, false);
+                        break;
+                    case TType::SET:
+                        $xfer += $this->_readList($elem, $espec, $input, true);
+                        break;
+                }
+            }
+            if ($set) {
+                $var[$elem] = true;
+            } else {
+                $var [] = $elem;
+            }
+        }
+        if ($set) {
+            $xfer += $input->readSetEnd();
+        } else {
+            $xfer += $input->readListEnd();
+        }
+
+        return $xfer;
+    }
+
+    protected function _read($class, $spec, $input)
+    {
+        $xfer = 0;
+        $fname = null;
+        $ftype = 0;
+        $fid = 0;
+        $xfer += $input->readStructBegin($fname);
+        while (true) {
+            $xfer += $input->readFieldBegin($fname, $ftype, $fid);
+            if ($ftype == TType::STOP) {
+                break;
+            }
+            if (isset($spec[$fid])) {
+                $fspec = $spec[$fid];
+                $var = $fspec['var'];
+                if ($ftype == $fspec['type']) {
+                    $xfer = 0;
+                    if (isset(TBase::$tmethod[$ftype])) {
+                        $func = 'read' . TBase::$tmethod[$ftype];
+                        $xfer += $input->$func($this->$var);
+                    } else {
+                        switch ($ftype) {
+                            case TType::STRUCT:
+                                $class = $fspec['class'];
+                                $this->$var = new $class();
+                                $xfer += $this->$var->read($input);
+                                break;
+                            case TType::MAP:
+                                $xfer += $this->_readMap($this->$var, $fspec, $input);
+                                break;
+                            case TType::LST:
+                                $xfer += $this->_readList($this->$var, $fspec, $input, false);
+                                break;
+                            case TType::SET:
+                                $xfer += $this->_readList($this->$var, $fspec, $input, true);
+                                break;
+                        }
+                    }
+                } else {
+                    $xfer += $input->skip($ftype);
+                }
+            } else {
+                $xfer += $input->skip($ftype);
+            }
+            $xfer += $input->readFieldEnd();
+        }
+        $xfer += $input->readStructEnd();
+
+        return $xfer;
+    }
+
+    private function _writeMap($var, $spec, $output)
+    {
+        $xfer = 0;
+        $ktype = $spec['ktype'];
+        $vtype = $spec['vtype'];
+        $kwrite = $vwrite = null;
+        if (isset(TBase::$tmethod[$ktype])) {
+            $kwrite = 'write' . TBase::$tmethod[$ktype];
+        } else {
+            $kspec = $spec['key'];
+        }
+        if (isset(TBase::$tmethod[$vtype])) {
+            $vwrite = 'write' . TBase::$tmethod[$vtype];
+        } else {
+            $vspec = $spec['val'];
+        }
+        $xfer += $output->writeMapBegin($ktype, $vtype, count($var));
+        foreach ($var as $key => $val) {
+            if (isset($kwrite)) {
+                $xfer += $output->$kwrite($key);
+            } else {
+                switch ($ktype) {
+                    case TType::STRUCT:
+                        $xfer += $key->write($output);
+                        break;
+                    case TType::MAP:
+                        $xfer += $this->_writeMap($key, $kspec, $output);
+                        break;
+                    case TType::LST:
+                        $xfer += $this->_writeList($key, $kspec, $output, false);
+                        break;
+                    case TType::SET:
+                        $xfer += $this->_writeList($key, $kspec, $output, true);
+                        break;
+                }
+            }
+            if (isset($vwrite)) {
+                $xfer += $output->$vwrite($val);
+            } else {
+                switch ($vtype) {
+                    case TType::STRUCT:
+                        $xfer += $val->write($output);
+                        break;
+                    case TType::MAP:
+                        $xfer += $this->_writeMap($val, $vspec, $output);
+                        break;
+                    case TType::LST:
+                        $xfer += $this->_writeList($val, $vspec, $output, false);
+                        break;
+                    case TType::SET:
+                        $xfer += $this->_writeList($val, $vspec, $output, true);
+                        break;
+                }
+            }
+        }
+        $xfer += $output->writeMapEnd();
+
+        return $xfer;
+    }
+
+    private function _writeList($var, $spec, $output, $set = false)
+    {
+        $xfer = 0;
+        $etype = $spec['etype'];
+        $ewrite = null;
+        if (isset(TBase::$tmethod[$etype])) {
+            $ewrite = 'write' . TBase::$tmethod[$etype];
+        } else {
+            $espec = $spec['elem'];
+        }
+        if ($set) {
+            $xfer += $output->writeSetBegin($etype, count($var));
+        } else {
+            $xfer += $output->writeListBegin($etype, count($var));
+        }
+        foreach ($var as $key => $val) {
+            $elem = $set ? $key : $val;
+            if (isset($ewrite)) {
+                $xfer += $output->$ewrite($elem);
+            } else {
+                switch ($etype) {
+                    case TType::STRUCT:
+                        $xfer += $elem->write($output);
+                        break;
+                    case TType::MAP:
+                        $xfer += $this->_writeMap($elem, $espec, $output);
+                        break;
+                    case TType::LST:
+                        $xfer += $this->_writeList($elem, $espec, $output, false);
+                        break;
+                    case TType::SET:
+                        $xfer += $this->_writeList($elem, $espec, $output, true);
+                        break;
+                }
+            }
+        }
+        if ($set) {
+            $xfer += $output->writeSetEnd();
+        } else {
+            $xfer += $output->writeListEnd();
+        }
+
+        return $xfer;
+    }
+
+    protected function _write($class, $spec, $output)
+    {
+        $xfer = 0;
+        $xfer += $output->writeStructBegin($class);
+        foreach ($spec as $fid => $fspec) {
+            $var = $fspec['var'];
+            if ($this->$var !== null) {
+                $ftype = $fspec['type'];
+                $xfer += $output->writeFieldBegin($var, $ftype, $fid);
+                if (isset(TBase::$tmethod[$ftype])) {
+                    $func = 'write' . TBase::$tmethod[$ftype];
+                    $xfer += $output->$func($this->$var);
+                } else {
+                    switch ($ftype) {
+                        case TType::STRUCT:
+                            $xfer += $this->$var->write($output);
+                            break;
+                        case TType::MAP:
+                            $xfer += $this->_writeMap($this->$var, $fspec, $output);
+                            break;
+                        case TType::LST:
+                            $xfer += $this->_writeList($this->$var, $fspec, $output, false);
+                            break;
+                        case TType::SET:
+                            $xfer += $this->_writeList($this->$var, $fspec, $output, true);
+                            break;
+                    }
+                }
+                $xfer += $output->writeFieldEnd();
+            }
+        }
+        $xfer += $output->writeFieldStop();
+        $xfer += $output->writeStructEnd();
+
+        return $xfer;
+    }
+}
diff --git a/lib/php/lib/ClassLoader/ThriftClassLoader.php b/lib/php/lib/ClassLoader/ThriftClassLoader.php
new file mode 100644
index 0000000..4361bd8
--- /dev/null
+++ b/lib/php/lib/ClassLoader/ThriftClassLoader.php
@@ -0,0 +1,206 @@
+<?php
+/*
+ * 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.
+ *
+ * ClassLoader to load Thrift library and definitions
+ * Inspired from UniversalClassLoader from Symfony 2
+ *
+ * @package thrift.classloader
+ */
+
+namespace Thrift\ClassLoader;
+
+class ThriftClassLoader
+{
+    /**
+     * Namespaces path
+     * @var array
+     */
+    protected $namespaces = array();
+
+    /**
+     * Thrift definition paths
+     * @var type
+     */
+    protected $definitions = array();
+
+    /**
+     * Do we use APC cache ?
+     * @var boolean
+     */
+    protected $apc = false;
+
+    /**
+     * APC Cache prefix
+     * @var string
+     */
+    protected $apc_prefix;
+
+    /**
+     * Set autoloader to use APC cache
+     * @param boolean $apc
+     * @param string $apc_prefix
+     */
+    public function __construct($apc = false, $apc_prefix = null)
+    {
+        $this->apc = $apc;
+        $this->apc_prefix = $apc_prefix;
+    }
+
+    /**
+     * Registers a namespace.
+     *
+     * @param string $namespace The namespace
+     * @param array|string $paths The location(s) of the namespace
+     */
+    public function registerNamespace($namespace, $paths)
+    {
+        $this->namespaces[$namespace] = (array)$paths;
+    }
+
+    /**
+     * Registers a Thrift definition namespace.
+     *
+     * @param string $namespace The definition namespace
+     * @param array|string $paths The location(s) of the definition namespace
+     */
+    public function registerDefinition($namespace, $paths)
+    {
+        $this->definitions[$namespace] = (array)$paths;
+    }
+
+    /**
+     * Registers this instance as an autoloader.
+     *
+     * @param Boolean $prepend Whether to prepend the autoloader or not
+     */
+    public function register($prepend = false)
+    {
+        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+    }
+
+    /**
+     * Loads the given class, definition or interface.
+     *
+     * @param string $class The name of the class
+     */
+    public function loadClass($class)
+    {
+        if ((true === $this->apc && ($file = $this->findFileInApc($class))) or
+            ($file = $this->findFile($class))
+        ) {
+            require_once $file;
+        }
+    }
+
+    /**
+     * Loads the given class or interface in APC.
+     * @param  string $class The name of the class
+     * @return string
+     */
+    protected function findFileInApc($class)
+    {
+        if (false === $file = apc_fetch($this->apc_prefix . $class)) {
+            apc_store($this->apc_prefix . $class, $file = $this->findFile($class));
+        }
+
+        return $file;
+    }
+
+    /**
+     * Find class in namespaces or definitions directories
+     * @param  string $class
+     * @return string
+     */
+    public function findFile($class)
+    {
+        // Remove first backslash
+        if ('\\' == $class[0]) {
+            $class = substr($class, 1);
+        }
+
+        if (false !== $pos = strrpos($class, '\\')) {
+            // Namespaced class name
+            $namespace = substr($class, 0, $pos);
+
+            // Iterate in normal namespaces
+            foreach ($this->namespaces as $ns => $dirs) {
+                //Don't interfere with other autoloaders
+                if (0 !== strpos($namespace, $ns)) {
+                    continue;
+                }
+
+                foreach ($dirs as $dir) {
+                    $className = substr($class, $pos + 1);
+
+                    $file = $dir . DIRECTORY_SEPARATOR .
+                        str_replace('\\', DIRECTORY_SEPARATOR, $namespace) .
+                        DIRECTORY_SEPARATOR .
+                        $className . '.php';
+
+                    if (file_exists($file)) {
+                        return $file;
+                    }
+                }
+            }
+
+            // Iterate in Thrift namespaces
+
+            // Remove first part of namespace
+            $m = explode('\\', $class);
+
+            // Ignore wrong call
+            if (count($m) <= 1) {
+                return;
+            }
+
+            $class = array_pop($m);
+            $namespace = implode('\\', $m);
+
+            foreach ($this->definitions as $ns => $dirs) {
+                //Don't interfere with other autoloaders
+                if (0 !== strpos($namespace, $ns)) {
+                    continue;
+                }
+
+                foreach ($dirs as $dir) {
+                    /**
+                     * Available in service: Interface, Client, Processor, Rest
+                     * And every service methods (_.+)
+                     */
+                    if (0 === preg_match('#(.+)(if|client|processor|rest)$#i', $class, $n) and
+                        0 === preg_match('#(.+)_[a-z0-9]+_(args|result)$#i', $class, $n)
+                    ) {
+                        $className = 'Types';
+                    } else {
+                        $className = $n[1];
+                    }
+
+                    $file = $dir . DIRECTORY_SEPARATOR .
+                        str_replace('\\', DIRECTORY_SEPARATOR, $namespace) .
+                        DIRECTORY_SEPARATOR .
+                        $className . '.php';
+
+                    if (file_exists($file)) {
+                        return $file;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/lib/php/lib/Exception/TApplicationException.php b/lib/php/lib/Exception/TApplicationException.php
new file mode 100644
index 0000000..ebb6a6a
--- /dev/null
+++ b/lib/php/lib/Exception/TApplicationException.php
@@ -0,0 +1,76 @@
+<?php
+/*
+ * 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
+ */
+
+namespace Thrift\Exception;
+
+use Thrift\Type\TType;
+
+class TApplicationException extends TException
+{
+    public static $_TSPEC =
+        array(1 => array('var' => 'message',
+            'type' => TType::STRING),
+            2 => array('var' => 'code',
+                'type' => TType::I32));
+
+    const UNKNOWN = 0;
+    const UNKNOWN_METHOD = 1;
+    const INVALID_MESSAGE_TYPE = 2;
+    const WRONG_METHOD_NAME = 3;
+    const BAD_SEQUENCE_ID = 4;
+    const MISSING_RESULT = 5;
+    const INTERNAL_ERROR = 6;
+    const PROTOCOL_ERROR = 7;
+    const INVALID_TRANSFORM = 8;
+    const INVALID_PROTOCOL = 9;
+    const UNSUPPORTED_CLIENT_TYPE = 10;
+
+    public function __construct($message = null, $code = 0)
+    {
+        parent::__construct($message, $code);
+    }
+
+    public function read($output)
+    {
+        return $this->_read('TApplicationException', self::$_TSPEC, $output);
+    }
+
+    public function write($output)
+    {
+        $xfer = 0;
+        $xfer += $output->writeStructBegin('TApplicationException');
+        if ($message = $this->getMessage()) {
+            $xfer += $output->writeFieldBegin('message', TType::STRING, 1);
+            $xfer += $output->writeString($message);
+            $xfer += $output->writeFieldEnd();
+        }
+        if ($code = $this->getCode()) {
+            $xfer += $output->writeFieldBegin('type', TType::I32, 2);
+            $xfer += $output->writeI32($code);
+            $xfer += $output->writeFieldEnd();
+        }
+        $xfer += $output->writeFieldStop();
+        $xfer += $output->writeStructEnd();
+
+        return $xfer;
+    }
+}
diff --git a/lib/php/lib/Exception/TException.php b/lib/php/lib/Exception/TException.php
new file mode 100644
index 0000000..7dbf832
--- /dev/null
+++ b/lib/php/lib/Exception/TException.php
@@ -0,0 +1,384 @@
+<?php
+/*
+ * 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
+ */
+
+namespace Thrift\Exception;
+
+use Thrift\Type\TType;
+use Thrift\Base\TBase;
+
+/**
+ * NOTE(mcslee): This currently contains a ton of duplicated code from TBase
+ * because we need to save CPU cycles and this is not yet in an extension.
+ * Ideally we'd multiply-inherit TException from both Exception and Base, but
+ * that's not possible in PHP and there are no modules either, so for now we
+ * apologetically take a trip to HackTown.
+ *
+ * Can be called with standard Exception constructor (message, code) or with
+ * Thrift Base object constructor (spec, vals).
+ *
+ * @param mixed $p1 Message (string) or type-spec (array)
+ * @param mixed $p2 Code (integer) or values (array)
+ */
+class TException extends \Exception
+{
+    public function __construct($p1 = null, $p2 = 0)
+    {
+        if (is_array($p1) && is_array($p2)) {
+            $spec = $p1;
+            $vals = $p2;
+            foreach ($spec as $fid => $fspec) {
+                $var = $fspec['var'];
+                if (isset($vals[$var])) {
+                    $this->$var = $vals[$var];
+                }
+            }
+        } else {
+            parent::__construct($p1, $p2);
+        }
+    }
+
+    public static $tmethod = array(
+        TType::BOOL => 'Bool',
+        TType::BYTE => 'Byte',
+        TType::I16 => 'I16',
+        TType::I32 => 'I32',
+        TType::I64 => 'I64',
+        TType::DOUBLE => 'Double',
+        TType::STRING => 'String'
+    );
+
+    private function _readMap(&$var, $spec, $input)
+    {
+        $xfer = 0;
+        $ktype = $spec['ktype'];
+        $vtype = $spec['vtype'];
+        $kread = $vread = null;
+        if (isset(TBase::$tmethod[$ktype])) {
+            $kread = 'read' . TBase::$tmethod[$ktype];
+        } else {
+            $kspec = $spec['key'];
+        }
+        if (isset(TBase::$tmethod[$vtype])) {
+            $vread = 'read' . TBase::$tmethod[$vtype];
+        } else {
+            $vspec = $spec['val'];
+        }
+        $var = array();
+        $_ktype = $_vtype = $size = 0;
+        $xfer += $input->readMapBegin($_ktype, $_vtype, $size);
+        for ($i = 0; $i < $size; ++$i) {
+            $key = $val = null;
+            if ($kread !== null) {
+                $xfer += $input->$kread($key);
+            } else {
+                switch ($ktype) {
+                    case TType::STRUCT:
+                        $class = $kspec['class'];
+                        $key = new $class();
+                        $xfer += $key->read($input);
+                        break;
+                    case TType::MAP:
+                        $xfer += $this->_readMap($key, $kspec, $input);
+                        break;
+                    case TType::LST:
+                        $xfer += $this->_readList($key, $kspec, $input, false);
+                        break;
+                    case TType::SET:
+                        $xfer += $this->_readList($key, $kspec, $input, true);
+                        break;
+                }
+            }
+            if ($vread !== null) {
+                $xfer += $input->$vread($val);
+            } else {
+                switch ($vtype) {
+                    case TType::STRUCT:
+                        $class = $vspec['class'];
+                        $val = new $class();
+                        $xfer += $val->read($input);
+                        break;
+                    case TType::MAP:
+                        $xfer += $this->_readMap($val, $vspec, $input);
+                        break;
+                    case TType::LST:
+                        $xfer += $this->_readList($val, $vspec, $input, false);
+                        break;
+                    case TType::SET:
+                        $xfer += $this->_readList($val, $vspec, $input, true);
+                        break;
+                }
+            }
+            $var[$key] = $val;
+        }
+        $xfer += $input->readMapEnd();
+
+        return $xfer;
+    }
+
+    private function _readList(&$var, $spec, $input, $set = false)
+    {
+        $xfer = 0;
+        $etype = $spec['etype'];
+        $eread = $vread = null;
+        if (isset(TBase::$tmethod[$etype])) {
+            $eread = 'read' . TBase::$tmethod[$etype];
+        } else {
+            $espec = $spec['elem'];
+        }
+        $var = array();
+        $_etype = $size = 0;
+        if ($set) {
+            $xfer += $input->readSetBegin($_etype, $size);
+        } else {
+            $xfer += $input->readListBegin($_etype, $size);
+        }
+        for ($i = 0; $i < $size; ++$i) {
+            $elem = null;
+            if ($eread !== null) {
+                $xfer += $input->$eread($elem);
+            } else {
+                $espec = $spec['elem'];
+                switch ($etype) {
+                    case TType::STRUCT:
+                        $class = $espec['class'];
+                        $elem = new $class();
+                        $xfer += $elem->read($input);
+                        break;
+                    case TType::MAP:
+                        $xfer += $this->_readMap($elem, $espec, $input);
+                        break;
+                    case TType::LST:
+                        $xfer += $this->_readList($elem, $espec, $input, false);
+                        break;
+                    case TType::SET:
+                        $xfer += $this->_readList($elem, $espec, $input, true);
+                        break;
+                }
+            }
+            if ($set) {
+                $var[$elem] = true;
+            } else {
+                $var [] = $elem;
+            }
+        }
+        if ($set) {
+            $xfer += $input->readSetEnd();
+        } else {
+            $xfer += $input->readListEnd();
+        }
+
+        return $xfer;
+    }
+
+    protected function _read($class, $spec, $input)
+    {
+        $xfer = 0;
+        $fname = null;
+        $ftype = 0;
+        $fid = 0;
+        $xfer += $input->readStructBegin($fname);
+        while (true) {
+            $xfer += $input->readFieldBegin($fname, $ftype, $fid);
+            if ($ftype == TType::STOP) {
+                break;
+            }
+            if (isset($spec[$fid])) {
+                $fspec = $spec[$fid];
+                $var = $fspec['var'];
+                if ($ftype == $fspec['type']) {
+                    $xfer = 0;
+                    if (isset(TBase::$tmethod[$ftype])) {
+                        $func = 'read' . TBase::$tmethod[$ftype];
+                        $xfer += $input->$func($this->$var);
+                    } else {
+                        switch ($ftype) {
+                            case TType::STRUCT:
+                                $class = $fspec['class'];
+                                $this->$var = new $class();
+                                $xfer += $this->$var->read($input);
+                                break;
+                            case TType::MAP:
+                                $xfer += $this->_readMap($this->$var, $fspec, $input);
+                                break;
+                            case TType::LST:
+                                $xfer += $this->_readList($this->$var, $fspec, $input, false);
+                                break;
+                            case TType::SET:
+                                $xfer += $this->_readList($this->$var, $fspec, $input, true);
+                                break;
+                        }
+                    }
+                } else {
+                    $xfer += $input->skip($ftype);
+                }
+            } else {
+                $xfer += $input->skip($ftype);
+            }
+            $xfer += $input->readFieldEnd();
+        }
+        $xfer += $input->readStructEnd();
+
+        return $xfer;
+    }
+
+    private function _writeMap($var, $spec, $output)
+    {
+        $xfer = 0;
+        $ktype = $spec['ktype'];
+        $vtype = $spec['vtype'];
+        $kwrite = $vwrite = null;
+        if (isset(TBase::$tmethod[$ktype])) {
+            $kwrite = 'write' . TBase::$tmethod[$ktype];
+        } else {
+            $kspec = $spec['key'];
+        }
+        if (isset(TBase::$tmethod[$vtype])) {
+            $vwrite = 'write' . TBase::$tmethod[$vtype];
+        } else {
+            $vspec = $spec['val'];
+        }
+        $xfer += $output->writeMapBegin($ktype, $vtype, count($var));
+        foreach ($var as $key => $val) {
+            if (isset($kwrite)) {
+                $xfer += $output->$kwrite($key);
+            } else {
+                switch ($ktype) {
+                    case TType::STRUCT:
+                        $xfer += $key->write($output);
+                        break;
+                    case TType::MAP:
+                        $xfer += $this->_writeMap($key, $kspec, $output);
+                        break;
+                    case TType::LST:
+                        $xfer += $this->_writeList($key, $kspec, $output, false);
+                        break;
+                    case TType::SET:
+                        $xfer += $this->_writeList($key, $kspec, $output, true);
+                        break;
+                }
+            }
+            if (isset($vwrite)) {
+                $xfer += $output->$vwrite($val);
+            } else {
+                switch ($vtype) {
+                    case TType::STRUCT:
+                        $xfer += $val->write($output);
+                        break;
+                    case TType::MAP:
+                        $xfer += $this->_writeMap($val, $vspec, $output);
+                        break;
+                    case TType::LST:
+                        $xfer += $this->_writeList($val, $vspec, $output, false);
+                        break;
+                    case TType::SET:
+                        $xfer += $this->_writeList($val, $vspec, $output, true);
+                        break;
+                }
+            }
+        }
+        $xfer += $output->writeMapEnd();
+
+        return $xfer;
+    }
+
+    private function _writeList($var, $spec, $output, $set = false)
+    {
+        $xfer = 0;
+        $etype = $spec['etype'];
+        $ewrite = null;
+        if (isset(TBase::$tmethod[$etype])) {
+            $ewrite = 'write' . TBase::$tmethod[$etype];
+        } else {
+            $espec = $spec['elem'];
+        }
+        if ($set) {
+            $xfer += $output->writeSetBegin($etype, count($var));
+        } else {
+            $xfer += $output->writeListBegin($etype, count($var));
+        }
+        foreach ($var as $key => $val) {
+            $elem = $set ? $key : $val;
+            if (isset($ewrite)) {
+                $xfer += $output->$ewrite($elem);
+            } else {
+                switch ($etype) {
+                    case TType::STRUCT:
+                        $xfer += $elem->write($output);
+                        break;
+                    case TType::MAP:
+                        $xfer += $this->_writeMap($elem, $espec, $output);
+                        break;
+                    case TType::LST:
+                        $xfer += $this->_writeList($elem, $espec, $output, false);
+                        break;
+                    case TType::SET:
+                        $xfer += $this->_writeList($elem, $espec, $output, true);
+                        break;
+                }
+            }
+        }
+        if ($set) {
+            $xfer += $output->writeSetEnd();
+        } else {
+            $xfer += $output->writeListEnd();
+        }
+
+        return $xfer;
+    }
+
+    protected function _write($class, $spec, $output)
+    {
+        $xfer = 0;
+        $xfer += $output->writeStructBegin($class);
+        foreach ($spec as $fid => $fspec) {
+            $var = $fspec['var'];
+            if ($this->$var !== null) {
+                $ftype = $fspec['type'];
+                $xfer += $output->writeFieldBegin($var, $ftype, $fid);
+                if (isset(TBase::$tmethod[$ftype])) {
+                    $func = 'write' . TBase::$tmethod[$ftype];
+                    $xfer += $output->$func($this->$var);
+                } else {
+                    switch ($ftype) {
+                        case TType::STRUCT:
+                            $xfer += $this->$var->write($output);
+                            break;
+                        case TType::MAP:
+                            $xfer += $this->_writeMap($this->$var, $fspec, $output);
+                            break;
+                        case TType::LST:
+                            $xfer += $this->_writeList($this->$var, $fspec, $output, false);
+                            break;
+                        case TType::SET:
+                            $xfer += $this->_writeList($this->$var, $fspec, $output, true);
+                            break;
+                    }
+                }
+                $xfer += $output->writeFieldEnd();
+            }
+        }
+        $xfer += $output->writeFieldStop();
+        $xfer += $output->writeStructEnd();
+
+        return $xfer;
+    }
+}
diff --git a/lib/php/lib/Exception/TProtocolException.php b/lib/php/lib/Exception/TProtocolException.php
new file mode 100644
index 0000000..3a55d45
--- /dev/null
+++ b/lib/php/lib/Exception/TProtocolException.php
@@ -0,0 +1,50 @@
+<?php
+/*
+ * 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.protocol
+ * @author: rmarin (marin.radu@facebook.com)
+ */
+
+namespace Thrift\Exception;
+
+/**
+ * Protocol module. Contains all the types and definitions needed to implement
+ * a protocol encoder/decoder.
+ *
+ * @package thrift.protocol
+ */
+
+/**
+ * Protocol exceptions
+ */
+class TProtocolException extends TException
+{
+    const UNKNOWN = 0;
+    const INVALID_DATA = 1;
+    const NEGATIVE_SIZE = 2;
+    const SIZE_LIMIT = 3;
+    const BAD_VERSION = 4;
+    const NOT_IMPLEMENTED = 5;
+    const DEPTH_LIMIT = 6;
+
+    public function __construct($message = null, $code = 0)
+    {
+        parent::__construct($message, $code);
+    }
+}
diff --git a/lib/php/lib/Exception/TTransportException.php b/lib/php/lib/Exception/TTransportException.php
new file mode 100644
index 0000000..7d8d567
--- /dev/null
+++ b/lib/php/lib/Exception/TTransportException.php
@@ -0,0 +1,40 @@
+<?php
+/*
+ * 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.transport
+ */
+
+namespace Thrift\Exception;
+
+/**
+ * Transport exceptions
+ */
+class TTransportException extends TException
+{
+    const UNKNOWN = 0;
+    const NOT_OPEN = 1;
+    const ALREADY_OPEN = 2;
+    const TIMED_OUT = 3;
+    const END_OF_FILE = 4;
+
+    public function __construct($message = null, $code = 0)
+    {
+        parent::__construct($message, $code);
+    }
+}
diff --git a/lib/php/lib/Factory/TBinaryProtocolFactory.php b/lib/php/lib/Factory/TBinaryProtocolFactory.php
new file mode 100644
index 0000000..2519183
--- /dev/null
+++ b/lib/php/lib/Factory/TBinaryProtocolFactory.php
@@ -0,0 +1,45 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Factory;
+
+use Thrift\Protocol\TBinaryProtocol;
+
+/**
+ * Binary Protocol Factory
+ */
+class TBinaryProtocolFactory implements TProtocolFactory
+{
+    private $strictRead_ = false;
+    private $strictWrite_ = false;
+
+    public function __construct($strictRead = false, $strictWrite = false)
+    {
+        $this->strictRead_ = $strictRead;
+        $this->strictWrite_ = $strictWrite;
+    }
+
+    public function getProtocol($trans)
+    {
+        return new TBinaryProtocol($trans, $this->strictRead_, $this->strictWrite_);
+    }
+}
diff --git a/lib/php/lib/Factory/TCompactProtocolFactory.php b/lib/php/lib/Factory/TCompactProtocolFactory.php
new file mode 100644
index 0000000..11fb8ff
--- /dev/null
+++ b/lib/php/lib/Factory/TCompactProtocolFactory.php
@@ -0,0 +1,40 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Factory;
+
+use Thrift\Protocol\TCompactProtocol;
+
+/**
+ * Compact Protocol Factory
+ */
+class TCompactProtocolFactory implements TProtocolFactory
+{
+    public function __construct()
+    {
+    }
+
+    public function getProtocol($trans)
+    {
+        return new TCompactProtocol($trans);
+    }
+}
diff --git a/lib/php/lib/Factory/TJSONProtocolFactory.php b/lib/php/lib/Factory/TJSONProtocolFactory.php
new file mode 100644
index 0000000..fbfb1d7
--- /dev/null
+++ b/lib/php/lib/Factory/TJSONProtocolFactory.php
@@ -0,0 +1,40 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Factory;
+
+use Thrift\Protocol\TJSONProtocol;
+
+/**
+ * JSON Protocol Factory
+ */
+class TJSONProtocolFactory implements TProtocolFactory
+{
+    public function __construct()
+    {
+    }
+
+    public function getProtocol($trans)
+    {
+        return new TJSONProtocol($trans);
+    }
+}
diff --git a/lib/php/lib/Factory/TProtocolFactory.php b/lib/php/lib/Factory/TProtocolFactory.php
new file mode 100644
index 0000000..d3066c8
--- /dev/null
+++ b/lib/php/lib/Factory/TProtocolFactory.php
@@ -0,0 +1,36 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Factory;
+
+/**
+ * Protocol factory creates protocol objects from transports
+ */
+interface TProtocolFactory
+{
+    /**
+     * Build a protocol from the base transport
+     *
+     * @return Thrift\Protocol\TProtocol protocol
+     */
+    public function getProtocol($trans);
+}
diff --git a/lib/php/lib/Factory/TStringFuncFactory.php b/lib/php/lib/Factory/TStringFuncFactory.php
new file mode 100644
index 0000000..30de4d7
--- /dev/null
+++ b/lib/php/lib/Factory/TStringFuncFactory.php
@@ -0,0 +1,66 @@
+<?php
+/*
+ * 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.
+ *
+ */
+
+namespace Thrift\Factory;
+
+use Thrift\StringFunc\Core;
+use Thrift\StringFunc\Mbstring;
+use Thrift\StringFunc\TStringFunc;
+
+class TStringFuncFactory
+{
+    private static $_instance;
+
+    /**
+     * Get the Singleton instance of TStringFunc implementation that is
+     * compatible with the current system's mbstring.func_overload settings.
+     *
+     * @return TStringFunc
+     */
+    public static function create()
+    {
+        if (!self::$_instance) {
+            self::_setInstance();
+        }
+
+        return self::$_instance;
+    }
+
+    private static function _setInstance()
+    {
+        /**
+         * Cannot use str* functions for byte counting because multibyte
+         * characters will be read a single bytes.
+         *
+         * See: http://php.net/manual/en/mbstring.overload.php
+         */
+        if (ini_get('mbstring.func_overload') & 2) {
+            self::$_instance = new Mbstring();
+        } else {
+            /**
+             * mbstring is not installed or does not have function overloading
+             * of the str* functions enabled so use PHP core str* functions for
+             * byte counting.
+             */
+            self::$_instance = new Core();
+        }
+    }
+}
diff --git a/lib/php/lib/Factory/TTransportFactory.php b/lib/php/lib/Factory/TTransportFactory.php
new file mode 100644
index 0000000..43f2eec
--- /dev/null
+++ b/lib/php/lib/Factory/TTransportFactory.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Thrift\Factory;
+
+use Thrift\Transport\TTransport;
+
+class TTransportFactory
+{
+    /**
+     * @static
+     * @param TTransport $transport
+     * @return TTransport
+     */
+    public static function getTransport(TTransport $transport)
+    {
+        return $transport;
+    }
+}
diff --git a/lib/php/lib/Protocol/JSON/BaseContext.php b/lib/php/lib/Protocol/JSON/BaseContext.php
new file mode 100644
index 0000000..31bcb48
--- /dev/null
+++ b/lib/php/lib/Protocol/JSON/BaseContext.php
@@ -0,0 +1,39 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol\JSON;
+
+class BaseContext
+{
+    public function escapeNum()
+    {
+        return false;
+    }
+
+    public function write()
+    {
+    }
+
+    public function read()
+    {
+    }
+}
diff --git a/lib/php/lib/Protocol/JSON/ListContext.php b/lib/php/lib/Protocol/JSON/ListContext.php
new file mode 100644
index 0000000..eef6594
--- /dev/null
+++ b/lib/php/lib/Protocol/JSON/ListContext.php
@@ -0,0 +1,54 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol\JSON;
+
+use Thrift\Protocol\TJSONProtocol;
+
+class ListContext extends BaseContext
+{
+    private $first_ = true;
+    private $p_;
+
+    public function __construct($p)
+    {
+        $this->p_ = $p;
+    }
+
+    public function write()
+    {
+        if ($this->first_) {
+            $this->first_ = false;
+        } else {
+            $this->p_->getTransport()->write(TJSONProtocol::COMMA);
+        }
+    }
+
+    public function read()
+    {
+        if ($this->first_) {
+            $this->first_ = false;
+        } else {
+            $this->p_->readJSONSyntaxChar(TJSONProtocol::COMMA);
+        }
+    }
+}
diff --git a/lib/php/lib/Protocol/JSON/LookaheadReader.php b/lib/php/lib/Protocol/JSON/LookaheadReader.php
new file mode 100644
index 0000000..0b18c40
--- /dev/null
+++ b/lib/php/lib/Protocol/JSON/LookaheadReader.php
@@ -0,0 +1,57 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol\JSON;
+
+class LookaheadReader
+{
+    private $hasData_ = false;
+    private $data_ = array();
+    private $p_;
+
+    public function __construct($p)
+    {
+        $this->p_ = $p;
+    }
+
+    public function read()
+    {
+        if ($this->hasData_) {
+            $this->hasData_ = false;
+        } else {
+            $this->data_ = $this->p_->getTransport()->readAll(1);
+        }
+
+        return substr($this->data_, 0, 1);
+    }
+
+    public function peek()
+    {
+        if (!$this->hasData_) {
+            $this->data_ = $this->p_->getTransport()->readAll(1);
+        }
+
+        $this->hasData_ = true;
+
+        return substr($this->data_, 0, 1);
+    }
+}
diff --git a/lib/php/lib/Protocol/JSON/PairContext.php b/lib/php/lib/Protocol/JSON/PairContext.php
new file mode 100644
index 0000000..7b353c4
--- /dev/null
+++ b/lib/php/lib/Protocol/JSON/PairContext.php
@@ -0,0 +1,64 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol\JSON;
+
+use Thrift\Protocol\TJSONProtocol;
+
+class PairContext extends BaseContext
+{
+    private $first_ = true;
+    private $colon_ = true;
+    private $p_ = null;
+
+    public function __construct($p)
+    {
+        $this->p_ = $p;
+    }
+
+    public function write()
+    {
+        if ($this->first_) {
+            $this->first_ = false;
+            $this->colon_ = true;
+        } else {
+            $this->p_->getTransport()->write($this->colon_ ? TJSONProtocol::COLON : TJSONProtocol::COMMA);
+            $this->colon_ = !$this->colon_;
+        }
+    }
+
+    public function read()
+    {
+        if ($this->first_) {
+            $this->first_ = false;
+            $this->colon_ = true;
+        } else {
+            $this->p_->readJSONSyntaxChar($this->colon_ ? TJSONProtocol::COLON : TJSONProtocol::COMMA);
+            $this->colon_ = !$this->colon_;
+        }
+    }
+
+    public function escapeNum()
+    {
+        return $this->colon_;
+    }
+}
diff --git a/lib/php/lib/Protocol/SimpleJSON/CollectionMapKeyException.php b/lib/php/lib/Protocol/SimpleJSON/CollectionMapKeyException.php
new file mode 100644
index 0000000..522b85a
--- /dev/null
+++ b/lib/php/lib/Protocol/SimpleJSON/CollectionMapKeyException.php
@@ -0,0 +1,33 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol\SimpleJSON;
+
+use Thrift\Exception\TException;
+
+class CollectionMapKeyException extends TException
+{
+    public function __construct($message)
+    {
+        parent::__construct($message);
+    }
+}
diff --git a/lib/php/lib/Protocol/SimpleJSON/Context.php b/lib/php/lib/Protocol/SimpleJSON/Context.php
new file mode 100644
index 0000000..dbd16fa
--- /dev/null
+++ b/lib/php/lib/Protocol/SimpleJSON/Context.php
@@ -0,0 +1,35 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol\SimpleJSON;
+
+class Context
+{
+    public function write()
+    {
+    }
+
+    public function isMapKey()
+    {
+        return false;
+    }
+}
diff --git a/lib/php/lib/Protocol/SimpleJSON/ListContext.php b/lib/php/lib/Protocol/SimpleJSON/ListContext.php
new file mode 100644
index 0000000..6f346d8
--- /dev/null
+++ b/lib/php/lib/Protocol/SimpleJSON/ListContext.php
@@ -0,0 +1,45 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol\SimpleJSON;
+
+use Thrift\Protocol\TSimpleJSONProtocol;
+
+class ListContext extends Context
+{
+    protected $first_ = true;
+    private $p_;
+
+    public function __construct($p)
+    {
+        $this->p_ = $p;
+    }
+
+    public function write()
+    {
+        if ($this->first_) {
+            $this->first_ = false;
+        } else {
+            $this->p_->getTransport()->write(TSimpleJSONProtocol::COMMA);
+        }
+    }
+}
diff --git a/lib/php/lib/Protocol/SimpleJSON/MapContext.php b/lib/php/lib/Protocol/SimpleJSON/MapContext.php
new file mode 100644
index 0000000..61c060d
--- /dev/null
+++ b/lib/php/lib/Protocol/SimpleJSON/MapContext.php
@@ -0,0 +1,47 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol\SimpleJSON;
+
+class MapContext extends StructContext
+{
+    protected $isKey = true;
+    private $p_;
+
+    public function __construct($p)
+    {
+        parent::__construct($p);
+    }
+
+    public function write()
+    {
+        parent::write();
+        $this->isKey = !$this->isKey;
+    }
+
+    public function isMapKey()
+    {
+        // we want to coerce map keys to json strings regardless
+        // of their type
+        return $this->isKey;
+    }
+}
diff --git a/lib/php/lib/Protocol/SimpleJSON/StructContext.php b/lib/php/lib/Protocol/SimpleJSON/StructContext.php
new file mode 100644
index 0000000..38a62d1
--- /dev/null
+++ b/lib/php/lib/Protocol/SimpleJSON/StructContext.php
@@ -0,0 +1,52 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol\SimpleJSON;
+
+use Thrift\Protocol\TSimpleJSONProtocol;
+
+class StructContext extends Context
+{
+    protected $first_ = true;
+    protected $colon_ = true;
+    private $p_;
+
+    public function __construct($p)
+    {
+        $this->p_ = $p;
+    }
+
+    public function write()
+    {
+        if ($this->first_) {
+            $this->first_ = false;
+            $this->colon_ = true;
+        } else {
+            $this->p_->getTransport()->write(
+                $this->colon_ ?
+                    TSimpleJSONProtocol::COLON :
+                    TSimpleJSONProtocol::COMMA
+            );
+            $this->colon_ = !$this->colon_;
+        }
+    }
+}
diff --git a/lib/php/lib/Protocol/TBinaryProtocol.php b/lib/php/lib/Protocol/TBinaryProtocol.php
new file mode 100644
index 0000000..cda5c0d
--- /dev/null
+++ b/lib/php/lib/Protocol/TBinaryProtocol.php
@@ -0,0 +1,453 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol;
+
+use Thrift\Type\TType;
+use Thrift\Exception\TProtocolException;
+use Thrift\Factory\TStringFuncFactory;
+
+/**
+ * Binary implementation of the Thrift protocol.
+ *
+ */
+class TBinaryProtocol extends TProtocol
+{
+    const VERSION_MASK = 0xffff0000;
+    const VERSION_1 = 0x80010000;
+
+    protected $strictRead_ = false;
+    protected $strictWrite_ = true;
+
+    public function __construct($trans, $strictRead = false, $strictWrite = true)
+    {
+        parent::__construct($trans);
+        $this->strictRead_ = $strictRead;
+        $this->strictWrite_ = $strictWrite;
+    }
+
+    public function writeMessageBegin($name, $type, $seqid)
+    {
+        if ($this->strictWrite_) {
+            $version = self::VERSION_1 | $type;
+
+            return
+                $this->writeI32($version) +
+                $this->writeString($name) +
+                $this->writeI32($seqid);
+        } else {
+            return
+                $this->writeString($name) +
+                $this->writeByte($type) +
+                $this->writeI32($seqid);
+        }
+    }
+
+    public function writeMessageEnd()
+    {
+        return 0;
+    }
+
+    public function writeStructBegin($name)
+    {
+        return 0;
+    }
+
+    public function writeStructEnd()
+    {
+        return 0;
+    }
+
+    public function writeFieldBegin($fieldName, $fieldType, $fieldId)
+    {
+        return
+            $this->writeByte($fieldType) +
+            $this->writeI16($fieldId);
+    }
+
+    public function writeFieldEnd()
+    {
+        return 0;
+    }
+
+    public function writeFieldStop()
+    {
+        return
+            $this->writeByte(TType::STOP);
+    }
+
+    public function writeMapBegin($keyType, $valType, $size)
+    {
+        return
+            $this->writeByte($keyType) +
+            $this->writeByte($valType) +
+            $this->writeI32($size);
+    }
+
+    public function writeMapEnd()
+    {
+        return 0;
+    }
+
+    public function writeListBegin($elemType, $size)
+    {
+        return
+            $this->writeByte($elemType) +
+            $this->writeI32($size);
+    }
+
+    public function writeListEnd()
+    {
+        return 0;
+    }
+
+    public function writeSetBegin($elemType, $size)
+    {
+        return
+            $this->writeByte($elemType) +
+            $this->writeI32($size);
+    }
+
+    public function writeSetEnd()
+    {
+        return 0;
+    }
+
+    public function writeBool($value)
+    {
+        $data = pack('c', $value ? 1 : 0);
+        $this->trans_->write($data, 1);
+
+        return 1;
+    }
+
+    public function writeByte($value)
+    {
+        $data = pack('c', $value);
+        $this->trans_->write($data, 1);
+
+        return 1;
+    }
+
+    public function writeI16($value)
+    {
+        $data = pack('n', $value);
+        $this->trans_->write($data, 2);
+
+        return 2;
+    }
+
+    public function writeI32($value)
+    {
+        $data = pack('N', $value);
+        $this->trans_->write($data, 4);
+
+        return 4;
+    }
+
+    public function writeI64($value)
+    {
+        // If we are on a 32bit architecture we have to explicitly deal with
+        // 64-bit twos-complement arithmetic since PHP wants to treat all ints
+        // as signed and any int over 2^31 - 1 as a float
+        if (PHP_INT_SIZE == 4) {
+            $neg = $value < 0;
+
+            if ($neg) {
+                $value *= -1;
+            }
+
+            $hi = (int)($value / 4294967296);
+            $lo = (int)$value;
+
+            if ($neg) {
+                $hi = ~$hi;
+                $lo = ~$lo;
+                if (($lo & (int)0xffffffff) == (int)0xffffffff) {
+                    $lo = 0;
+                    $hi++;
+                } else {
+                    $lo++;
+                }
+            }
+            $data = pack('N2', $hi, $lo);
+        } else {
+            $hi = $value >> 32;
+            $lo = $value & 0xFFFFFFFF;
+            $data = pack('N2', $hi, $lo);
+        }
+
+        $this->trans_->write($data, 8);
+
+        return 8;
+    }
+
+    public function writeDouble($value)
+    {
+        $data = pack('d', $value);
+        $this->trans_->write(strrev($data), 8);
+
+        return 8;
+    }
+
+    public function writeString($value)
+    {
+        $len = TStringFuncFactory::create()->strlen($value);
+        $result = $this->writeI32($len);
+        if ($len) {
+            $this->trans_->write($value, $len);
+        }
+
+        return $result + $len;
+    }
+
+    public function readMessageBegin(&$name, &$type, &$seqid)
+    {
+        $result = $this->readI32($sz);
+        if ($sz < 0) {
+            $version = (int)($sz & self::VERSION_MASK);
+            if ($version != (int)self::VERSION_1) {
+                throw new TProtocolException('Bad version identifier: ' . $sz, TProtocolException::BAD_VERSION);
+            }
+            $type = $sz & 0x000000ff;
+            $result +=
+                $this->readString($name) +
+                $this->readI32($seqid);
+        } else {
+            if ($this->strictRead_) {
+                throw new TProtocolException(
+                    'No version identifier, old protocol client?',
+                    TProtocolException::BAD_VERSION
+                );
+            } else {
+                // Handle pre-versioned input
+                $name = $this->trans_->readAll($sz);
+                $result +=
+                    $sz +
+                    $this->readByte($type) +
+                    $this->readI32($seqid);
+            }
+        }
+
+        return $result;
+    }
+
+    public function readMessageEnd()
+    {
+        return 0;
+    }
+
+    public function readStructBegin(&$name)
+    {
+        $name = '';
+
+        return 0;
+    }
+
+    public function readStructEnd()
+    {
+        return 0;
+    }
+
+    public function readFieldBegin(&$name, &$fieldType, &$fieldId)
+    {
+        $result = $this->readByte($fieldType);
+        if ($fieldType == TType::STOP) {
+            $fieldId = 0;
+
+            return $result;
+        }
+        $result += $this->readI16($fieldId);
+
+        return $result;
+    }
+
+    public function readFieldEnd()
+    {
+        return 0;
+    }
+
+    public function readMapBegin(&$keyType, &$valType, &$size)
+    {
+        return
+            $this->readByte($keyType) +
+            $this->readByte($valType) +
+            $this->readI32($size);
+    }
+
+    public function readMapEnd()
+    {
+        return 0;
+    }
+
+    public function readListBegin(&$elemType, &$size)
+    {
+        return
+            $this->readByte($elemType) +
+            $this->readI32($size);
+    }
+
+    public function readListEnd()
+    {
+        return 0;
+    }
+
+    public function readSetBegin(&$elemType, &$size)
+    {
+        return
+            $this->readByte($elemType) +
+            $this->readI32($size);
+    }
+
+    public function readSetEnd()
+    {
+        return 0;
+    }
+
+    public function readBool(&$value)
+    {
+        $data = $this->trans_->readAll(1);
+        $arr = unpack('c', $data);
+        $value = $arr[1] == 1;
+
+        return 1;
+    }
+
+    public function readByte(&$value)
+    {
+        $data = $this->trans_->readAll(1);
+        $arr = unpack('c', $data);
+        $value = $arr[1];
+
+        return 1;
+    }
+
+    public function readI16(&$value)
+    {
+        $data = $this->trans_->readAll(2);
+        $arr = unpack('n', $data);
+        $value = $arr[1];
+        if ($value > 0x7fff) {
+            $value = 0 - (($value - 1) ^ 0xffff);
+        }
+
+        return 2;
+    }
+
+    public function readI32(&$value)
+    {
+        $data = $this->trans_->readAll(4);
+        $arr = unpack('N', $data);
+        $value = $arr[1];
+        if ($value > 0x7fffffff) {
+            $value = 0 - (($value - 1) ^ 0xffffffff);
+        }
+
+        return 4;
+    }
+
+    public function readI64(&$value)
+    {
+        $data = $this->trans_->readAll(8);
+
+        $arr = unpack('N2', $data);
+
+        // If we are on a 32bit architecture we have to explicitly deal with
+        // 64-bit twos-complement arithmetic since PHP wants to treat all ints
+        // as signed and any int over 2^31 - 1 as a float
+        if (PHP_INT_SIZE == 4) {
+            $hi = $arr[1];
+            $lo = $arr[2];
+            $isNeg = $hi < 0;
+
+            // Check for a negative
+            if ($isNeg) {
+                $hi = ~$hi & (int)0xffffffff;
+                $lo = ~$lo & (int)0xffffffff;
+
+                if ($lo == (int)0xffffffff) {
+                    $hi++;
+                    $lo = 0;
+                } else {
+                    $lo++;
+                }
+            }
+
+            // Force 32bit words in excess of 2G to pe positive - we deal wigh sign
+            // explicitly below
+
+            if ($hi & (int)0x80000000) {
+                $hi &= (int)0x7fffffff;
+                $hi += 0x80000000;
+            }
+
+            if ($lo & (int)0x80000000) {
+                $lo &= (int)0x7fffffff;
+                $lo += 0x80000000;
+            }
+
+            $value = $hi * 4294967296 + $lo;
+
+            if ($isNeg) {
+                $value = 0 - $value;
+            }
+        } else {
+            // Upcast negatives in LSB bit
+            if ($arr[2] & 0x80000000) {
+                $arr[2] = $arr[2] & 0xffffffff;
+            }
+
+            // Check for a negative
+            if ($arr[1] & 0x80000000) {
+                $arr[1] = $arr[1] & 0xffffffff;
+                $arr[1] = $arr[1] ^ 0xffffffff;
+                $arr[2] = $arr[2] ^ 0xffffffff;
+                $value = 0 - $arr[1] * 4294967296 - $arr[2] - 1;
+            } else {
+                $value = $arr[1] * 4294967296 + $arr[2];
+            }
+        }
+
+        return 8;
+    }
+
+    public function readDouble(&$value)
+    {
+        $data = strrev($this->trans_->readAll(8));
+        $arr = unpack('d', $data);
+        $value = $arr[1];
+
+        return 8;
+    }
+
+    public function readString(&$value)
+    {
+        $result = $this->readI32($len);
+        if ($len) {
+            $value = $this->trans_->readAll($len);
+        } else {
+            $value = '';
+        }
+
+        return $result + $len;
+    }
+}
diff --git a/lib/php/lib/Protocol/TBinaryProtocolAccelerated.php b/lib/php/lib/Protocol/TBinaryProtocolAccelerated.php
new file mode 100644
index 0000000..ff799a6
--- /dev/null
+++ b/lib/php/lib/Protocol/TBinaryProtocolAccelerated.php
@@ -0,0 +1,67 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol;
+
+use Thrift\Transport\TBufferedTransport;
+
+/**
+ * Accelerated binary protocol: used in conjunction with the thrift_protocol
+ * extension for faster deserialization
+ */
+class TBinaryProtocolAccelerated extends TBinaryProtocol
+{
+    public function __construct($trans, $strictRead = false, $strictWrite = true)
+    {
+        // If the transport doesn't implement putBack, wrap it in a
+        // TBufferedTransport (which does)
+
+        // NOTE (t.heintz): This is very evil to do, because the TBufferedTransport may swallow bytes, which
+        // are then never written to the underlying transport. This happens precisely when a number of bytes
+        // less than the max buffer size (512 by default) is written to the transport and then flush() is NOT
+        // called. In that case the data stays in the writeBuffer of the transport, from where it can never be
+        // accessed again (for example through read()).
+        //
+        // Since the caller of this method does not know about the wrapping transport, this creates bugs which
+        // are very difficult to find. Hence the wrapping of a transport in a buffer should be left to the
+        // calling code. An interface could used to mandate the presence of the putBack() method in the transport.
+        //
+        // I am leaving this code in nonetheless, because there may be applications depending on this behavior.
+        //
+        // @see THRIFT-1579
+
+        if (!method_exists($trans, 'putBack')) {
+            $trans = new TBufferedTransport($trans);
+        }
+        parent::__construct($trans, $strictRead, $strictWrite);
+    }
+
+    public function isStrictRead()
+    {
+        return $this->strictRead_;
+    }
+
+    public function isStrictWrite()
+    {
+        return $this->strictWrite_;
+    }
+}
diff --git a/lib/php/lib/Protocol/TCompactProtocol.php b/lib/php/lib/Protocol/TCompactProtocol.php
new file mode 100644
index 0000000..1af2a27
--- /dev/null
+++ b/lib/php/lib/Protocol/TCompactProtocol.php
@@ -0,0 +1,739 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol;
+
+use Thrift\Type\TType;
+use Thrift\Exception\TProtocolException;
+use Thrift\Factory\TStringFuncFactory;
+
+/**
+ * Compact implementation of the Thrift protocol.
+ *
+ */
+class TCompactProtocol extends TProtocol
+{
+    const COMPACT_STOP = 0x00;
+    const COMPACT_TRUE = 0x01;
+    const COMPACT_FALSE = 0x02;
+    const COMPACT_BYTE = 0x03;
+    const COMPACT_I16 = 0x04;
+    const COMPACT_I32 = 0x05;
+    const COMPACT_I64 = 0x06;
+    const COMPACT_DOUBLE = 0x07;
+    const COMPACT_BINARY = 0x08;
+    const COMPACT_LIST = 0x09;
+    const COMPACT_SET = 0x0A;
+    const COMPACT_MAP = 0x0B;
+    const COMPACT_STRUCT = 0x0C;
+
+    const STATE_CLEAR = 0;
+    const STATE_FIELD_WRITE = 1;
+    const STATE_VALUE_WRITE = 2;
+    const STATE_CONTAINER_WRITE = 3;
+    const STATE_BOOL_WRITE = 4;
+    const STATE_FIELD_READ = 5;
+    const STATE_CONTAINER_READ = 6;
+    const STATE_VALUE_READ = 7;
+    const STATE_BOOL_READ = 8;
+
+    const VERSION_MASK = 0x1f;
+    const VERSION = 1;
+    const PROTOCOL_ID = 0x82;
+    const TYPE_MASK = 0xe0;
+    const TYPE_BITS = 0x07;
+    const TYPE_SHIFT_AMOUNT = 5;
+
+    protected static $ctypes = array(
+        TType::STOP => TCompactProtocol::COMPACT_STOP,
+        TType::BOOL => TCompactProtocol::COMPACT_TRUE, // used for collection
+        TType::BYTE => TCompactProtocol::COMPACT_BYTE,
+        TType::I16 => TCompactProtocol::COMPACT_I16,
+        TType::I32 => TCompactProtocol::COMPACT_I32,
+        TType::I64 => TCompactProtocol::COMPACT_I64,
+        TType::DOUBLE => TCompactProtocol::COMPACT_DOUBLE,
+        TType::STRING => TCompactProtocol::COMPACT_BINARY,
+        TType::STRUCT => TCompactProtocol::COMPACT_STRUCT,
+        TType::LST => TCompactProtocol::COMPACT_LIST,
+        TType::SET => TCompactProtocol::COMPACT_SET,
+        TType::MAP => TCompactProtocol::COMPACT_MAP,
+    );
+
+    protected static $ttypes = array(
+        TCompactProtocol::COMPACT_STOP => TType::STOP,
+        TCompactProtocol::COMPACT_TRUE => TType::BOOL, // used for collection
+        TCompactProtocol::COMPACT_FALSE => TType::BOOL,
+        TCompactProtocol::COMPACT_BYTE => TType::BYTE,
+        TCompactProtocol::COMPACT_I16 => TType::I16,
+        TCompactProtocol::COMPACT_I32 => TType::I32,
+        TCompactProtocol::COMPACT_I64 => TType::I64,
+        TCompactProtocol::COMPACT_DOUBLE => TType::DOUBLE,
+        TCompactProtocol::COMPACT_BINARY => TType::STRING,
+        TCompactProtocol::COMPACT_STRUCT => TType::STRUCT,
+        TCompactProtocol::COMPACT_LIST => TType::LST,
+        TCompactProtocol::COMPACT_SET => TType::SET,
+        TCompactProtocol::COMPACT_MAP => TType::MAP,
+    );
+
+    protected $state = TCompactProtocol::STATE_CLEAR;
+    protected $lastFid = 0;
+    protected $boolFid = null;
+    protected $boolValue = null;
+    protected $structs = array();
+    protected $containers = array();
+
+    // Some varint / zigzag helper methods
+    public function toZigZag($n, $bits)
+    {
+        return ($n << 1) ^ ($n >> ($bits - 1));
+    }
+
+    public function fromZigZag($n)
+    {
+        return ($n >> 1) ^ -($n & 1);
+    }
+
+    public function getVarint($data)
+    {
+        $out = "";
+        while (true) {
+            if (($data & ~0x7f) === 0) {
+                $out .= chr($data);
+                break;
+            } else {
+                $out .= chr(($data & 0xff) | 0x80);
+                $data = $data >> 7;
+            }
+        }
+
+        return $out;
+    }
+
+    public function writeVarint($data)
+    {
+        $out = $this->getVarint($data);
+        $result = TStringFuncFactory::create()->strlen($out);
+        $this->trans_->write($out, $result);
+
+        return $result;
+    }
+
+    public function readVarint(&$result)
+    {
+        $idx = 0;
+        $shift = 0;
+        $result = 0;
+        while (true) {
+            $x = $this->trans_->readAll(1);
+            $arr = unpack('C', $x);
+            $byte = $arr[1];
+            $idx += 1;
+            $result |= ($byte & 0x7f) << $shift;
+            if (($byte >> 7) === 0) {
+                return $idx;
+            }
+            $shift += 7;
+        }
+
+        return $idx;
+    }
+
+    public function __construct($trans)
+    {
+        parent::__construct($trans);
+    }
+
+    public function writeMessageBegin($name, $type, $seqid)
+    {
+        $written =
+            $this->writeUByte(TCompactProtocol::PROTOCOL_ID) +
+            $this->writeUByte(TCompactProtocol::VERSION |
+                ($type << TCompactProtocol::TYPE_SHIFT_AMOUNT)) +
+            $this->writeVarint($seqid) +
+            $this->writeString($name);
+        $this->state = TCompactProtocol::STATE_VALUE_WRITE;
+
+        return $written;
+    }
+
+    public function writeMessageEnd()
+    {
+        $this->state = TCompactProtocol::STATE_CLEAR;
+
+        return 0;
+    }
+
+    public function writeStructBegin($name)
+    {
+        $this->structs[] = array($this->state, $this->lastFid);
+        $this->state = TCompactProtocol::STATE_FIELD_WRITE;
+        $this->lastFid = 0;
+
+        return 0;
+    }
+
+    public function writeStructEnd()
+    {
+        $old_values = array_pop($this->structs);
+        $this->state = $old_values[0];
+        $this->lastFid = $old_values[1];
+
+        return 0;
+    }
+
+    public function writeFieldStop()
+    {
+        return $this->writeByte(0);
+    }
+
+    public function writeFieldHeader($type, $fid)
+    {
+        $written = 0;
+        $delta = $fid - $this->lastFid;
+        if (0 < $delta && $delta <= 15) {
+            $written = $this->writeUByte(($delta << 4) | $type);
+        } else {
+            $written = $this->writeByte($type) +
+                $this->writeI16($fid);
+        }
+        $this->lastFid = $fid;
+
+        return $written;
+    }
+
+    public function writeFieldBegin($field_name, $field_type, $field_id)
+    {
+        if ($field_type == TTYPE::BOOL) {
+            $this->state = TCompactProtocol::STATE_BOOL_WRITE;
+            $this->boolFid = $field_id;
+
+            return 0;
+        } else {
+            $this->state = TCompactProtocol::STATE_VALUE_WRITE;
+
+            return $this->writeFieldHeader(self::$ctypes[$field_type], $field_id);
+        }
+    }
+
+    public function writeFieldEnd()
+    {
+        $this->state = TCompactProtocol::STATE_FIELD_WRITE;
+
+        return 0;
+    }
+
+    public function writeCollectionBegin($etype, $size)
+    {
+        $written = 0;
+        if ($size <= 14) {
+            $written = $this->writeUByte($size << 4 |
+                self::$ctypes[$etype]);
+        } else {
+            $written = $this->writeUByte(0xf0 |
+                    self::$ctypes[$etype]) +
+                $this->writeVarint($size);
+        }
+        $this->containers[] = $this->state;
+        $this->state = TCompactProtocol::STATE_CONTAINER_WRITE;
+
+        return $written;
+    }
+
+    public function writeMapBegin($key_type, $val_type, $size)
+    {
+        $written = 0;
+        if ($size == 0) {
+            $written = $this->writeByte(0);
+        } else {
+            $written = $this->writeVarint($size) +
+                $this->writeUByte(self::$ctypes[$key_type] << 4 |
+                    self::$ctypes[$val_type]);
+        }
+        $this->containers[] = $this->state;
+
+        return $written;
+    }
+
+    public function writeCollectionEnd()
+    {
+        $this->state = array_pop($this->containers);
+
+        return 0;
+    }
+
+    public function writeMapEnd()
+    {
+        return $this->writeCollectionEnd();
+    }
+
+    public function writeListBegin($elem_type, $size)
+    {
+        return $this->writeCollectionBegin($elem_type, $size);
+    }
+
+    public function writeListEnd()
+    {
+        return $this->writeCollectionEnd();
+    }
+
+    public function writeSetBegin($elem_type, $size)
+    {
+        return $this->writeCollectionBegin($elem_type, $size);
+    }
+
+    public function writeSetEnd()
+    {
+        return $this->writeCollectionEnd();
+    }
+
+    public function writeBool($value)
+    {
+        if ($this->state == TCompactProtocol::STATE_BOOL_WRITE) {
+            $ctype = TCompactProtocol::COMPACT_FALSE;
+            if ($value) {
+                $ctype = TCompactProtocol::COMPACT_TRUE;
+            }
+
+            return $this->writeFieldHeader($ctype, $this->boolFid);
+        } elseif ($this->state == TCompactProtocol::STATE_CONTAINER_WRITE) {
+            return $this->writeByte($value ? 1 : 0);
+        } else {
+            throw new TProtocolException('Invalid state in compact protocol');
+        }
+    }
+
+    public function writeByte($value)
+    {
+        $data = pack('c', $value);
+        $this->trans_->write($data, 1);
+
+        return 1;
+    }
+
+    public function writeUByte($byte)
+    {
+        $this->trans_->write(pack('C', $byte), 1);
+
+        return 1;
+    }
+
+    public function writeI16($value)
+    {
+        $thing = $this->toZigZag($value, 16);
+
+        return $this->writeVarint($thing);
+    }
+
+    public function writeI32($value)
+    {
+        $thing = $this->toZigZag($value, 32);
+
+        return $this->writeVarint($thing);
+    }
+
+    public function writeDouble($value)
+    {
+        $data = pack('d', $value);
+        $this->trans_->write($data, 8);
+
+        return 8;
+    }
+
+    public function writeString($value)
+    {
+        $len = TStringFuncFactory::create()->strlen($value);
+        $result = $this->writeVarint($len);
+        if ($len) {
+            $this->trans_->write($value, $len);
+        }
+
+        return $result + $len;
+    }
+
+    public function readFieldBegin(&$name, &$field_type, &$field_id)
+    {
+        $result = $this->readUByte($compact_type_and_delta);
+
+        $compact_type = $compact_type_and_delta & 0x0f;
+
+        if ($compact_type == TType::STOP) {
+            $field_type = $compact_type;
+            $field_id = 0;
+
+            return $result;
+        }
+        $delta = $compact_type_and_delta >> 4;
+        if ($delta == 0) {
+            $result += $this->readI16($field_id);
+        } else {
+            $field_id = $this->lastFid + $delta;
+        }
+        $this->lastFid = $field_id;
+        $field_type = $this->getTType($compact_type);
+
+        if ($compact_type == TCompactProtocol::COMPACT_TRUE) {
+            $this->state = TCompactProtocol::STATE_BOOL_READ;
+            $this->boolValue = true;
+        } elseif ($compact_type == TCompactProtocol::COMPACT_FALSE) {
+            $this->state = TCompactProtocol::STATE_BOOL_READ;
+            $this->boolValue = false;
+        } else {
+            $this->state = TCompactProtocol::STATE_VALUE_READ;
+        }
+
+        return $result;
+    }
+
+    public function readFieldEnd()
+    {
+        $this->state = TCompactProtocol::STATE_FIELD_READ;
+
+        return 0;
+    }
+
+    public function readUByte(&$value)
+    {
+        $data = $this->trans_->readAll(1);
+        $arr = unpack('C', $data);
+        $value = $arr[1];
+
+        return 1;
+    }
+
+    public function readByte(&$value)
+    {
+        $data = $this->trans_->readAll(1);
+        $arr = unpack('c', $data);
+        $value = $arr[1];
+
+        return 1;
+    }
+
+    public function readZigZag(&$value)
+    {
+        $result = $this->readVarint($value);
+        $value = $this->fromZigZag($value);
+
+        return $result;
+    }
+
+    public function readMessageBegin(&$name, &$type, &$seqid)
+    {
+        $protoId = 0;
+        $result = $this->readUByte($protoId);
+        if ($protoId != TCompactProtocol::PROTOCOL_ID) {
+            throw new TProtocolException('Bad protocol id in TCompact message');
+        }
+        $verType = 0;
+        $result += $this->readUByte($verType);
+        $type = ($verType >> TCompactProtocol::TYPE_SHIFT_AMOUNT) & TCompactProtocol::TYPE_BITS;
+        $version = $verType & TCompactProtocol::VERSION_MASK;
+        if ($version != TCompactProtocol::VERSION) {
+            throw new TProtocolException('Bad version in TCompact message');
+        }
+        $result += $this->readVarint($seqid);
+        $result += $this->readString($name);
+
+        return $result;
+    }
+
+    public function readMessageEnd()
+    {
+        return 0;
+    }
+
+    public function readStructBegin(&$name)
+    {
+        $name = ''; // unused
+        $this->structs[] = array($this->state, $this->lastFid);
+        $this->state = TCompactProtocol::STATE_FIELD_READ;
+        $this->lastFid = 0;
+
+        return 0;
+    }
+
+    public function readStructEnd()
+    {
+        $last = array_pop($this->structs);
+        $this->state = $last[0];
+        $this->lastFid = $last[1];
+
+        return 0;
+    }
+
+    public function readCollectionBegin(&$type, &$size)
+    {
+        $sizeType = 0;
+        $result = $this->readUByte($sizeType);
+        $size = $sizeType >> 4;
+        $type = $this->getTType($sizeType);
+        if ($size == 15) {
+            $result += $this->readVarint($size);
+        }
+        $this->containers[] = $this->state;
+        $this->state = TCompactProtocol::STATE_CONTAINER_READ;
+
+        return $result;
+    }
+
+    public function readMapBegin(&$key_type, &$val_type, &$size)
+    {
+        $result = $this->readVarint($size);
+        $types = 0;
+        if ($size > 0) {
+            $result += $this->readUByte($types);
+        }
+        $val_type = $this->getTType($types);
+        $key_type = $this->getTType($types >> 4);
+        $this->containers[] = $this->state;
+        $this->state = TCompactProtocol::STATE_CONTAINER_READ;
+
+        return $result;
+    }
+
+    public function readCollectionEnd()
+    {
+        $this->state = array_pop($this->containers);
+
+        return 0;
+    }
+
+    public function readMapEnd()
+    {
+        return $this->readCollectionEnd();
+    }
+
+    public function readListBegin(&$elem_type, &$size)
+    {
+        return $this->readCollectionBegin($elem_type, $size);
+    }
+
+    public function readListEnd()
+    {
+        return $this->readCollectionEnd();
+    }
+
+    public function readSetBegin(&$elem_type, &$size)
+    {
+        return $this->readCollectionBegin($elem_type, $size);
+    }
+
+    public function readSetEnd()
+    {
+        return $this->readCollectionEnd();
+    }
+
+    public function readBool(&$value)
+    {
+        if ($this->state == TCompactProtocol::STATE_BOOL_READ) {
+            $value = $this->boolValue;
+
+            return 0;
+        } elseif ($this->state == TCompactProtocol::STATE_CONTAINER_READ) {
+            return $this->readByte($value);
+        } else {
+            throw new TProtocolException('Invalid state in compact protocol');
+        }
+    }
+
+    public function readI16(&$value)
+    {
+        return $this->readZigZag($value);
+    }
+
+    public function readI32(&$value)
+    {
+        return $this->readZigZag($value);
+    }
+
+    public function readDouble(&$value)
+    {
+        $data = $this->trans_->readAll(8);
+        $arr = unpack('d', $data);
+        $value = $arr[1];
+
+        return 8;
+    }
+
+    public function readString(&$value)
+    {
+        $result = $this->readVarint($len);
+        if ($len) {
+            $value = $this->trans_->readAll($len);
+        } else {
+            $value = '';
+        }
+
+        return $result + $len;
+    }
+
+    public function getTType($byte)
+    {
+        return self::$ttypes[$byte & 0x0f];
+    }
+
+    // If we are on a 32bit architecture we have to explicitly deal with
+    // 64-bit twos-complement arithmetic since PHP wants to treat all ints
+    // as signed and any int over 2^31 - 1 as a float
+
+    // Read and write I64 as two 32 bit numbers $hi and $lo
+
+    public function readI64(&$value)
+    {
+        // Read varint from wire
+        $hi = 0;
+        $lo = 0;
+
+        $idx = 0;
+        $shift = 0;
+
+        while (true) {
+            $x = $this->trans_->readAll(1);
+            $arr = unpack('C', $x);
+            $byte = $arr[1];
+            $idx += 1;
+            // Shift hi and lo together.
+            if ($shift < 28) {
+                $lo |= (($byte & 0x7f) << $shift);
+            } elseif ($shift == 28) {
+                $lo |= (($byte & 0x0f) << 28);
+                $hi |= (($byte & 0x70) >> 4);
+            } else {
+                $hi |= (($byte & 0x7f) << ($shift - 32));
+            }
+            if (($byte >> 7) === 0) {
+                break;
+            }
+            $shift += 7;
+        }
+
+        // Now, unzig it.
+        $xorer = 0;
+        if ($lo & 1) {
+            $xorer = 0xffffffff;
+        }
+        $lo = ($lo >> 1) & 0x7fffffff;
+        $lo = $lo | (($hi & 1) << 31);
+        $hi = ($hi >> 1) ^ $xorer;
+        $lo = $lo ^ $xorer;
+
+        // Now put $hi and $lo back together
+        $isNeg = $hi < 0 || $hi & 0x80000000;
+
+        // Check for a negative
+        if ($isNeg) {
+            $hi = ~$hi & (int)0xffffffff;
+            $lo = ~$lo & (int)0xffffffff;
+
+            if ($lo == (int)0xffffffff) {
+                $hi++;
+                $lo = 0;
+            } else {
+                $lo++;
+            }
+        }
+
+        // Force 32bit words in excess of 2G to be positive - we deal with sign
+        // explicitly below
+
+        if ($hi & (int)0x80000000) {
+            $hi &= (int)0x7fffffff;
+            $hi += 0x80000000;
+        }
+
+        if ($lo & (int)0x80000000) {
+            $lo &= (int)0x7fffffff;
+            $lo += 0x80000000;
+        }
+
+        // Create as negative value first, since we can store -2^63 but not 2^63
+        $value = -$hi * 4294967296 - $lo;
+
+        if (!$isNeg) {
+            $value = -$value;
+        }
+
+        return $idx;
+    }
+
+    public function writeI64($value)
+    {
+        // If we are in an I32 range, use the easy method below.
+        if (($value > 4294967296) || ($value < -4294967296)) {
+            // Convert $value to $hi and $lo
+            $neg = $value < 0;
+
+            if ($neg) {
+                $value *= -1;
+            }
+
+            $hi = (int)$value >> 32;
+            $lo = (int)$value & 0xffffffff;
+
+            if ($neg) {
+                $hi = ~$hi;
+                $lo = ~$lo;
+                if (($lo & (int)0xffffffff) == (int)0xffffffff) {
+                    $lo = 0;
+                    $hi++;
+                } else {
+                    $lo++;
+                }
+            }
+
+            // Now do the zigging and zagging.
+            $xorer = 0;
+            if ($neg) {
+                $xorer = 0xffffffff;
+            }
+            $lowbit = ($lo >> 31) & 1;
+            $hi = ($hi << 1) | $lowbit;
+            $lo = ($lo << 1);
+            $lo = ($lo ^ $xorer) & 0xffffffff;
+            $hi = ($hi ^ $xorer) & 0xffffffff;
+
+            // now write out the varint, ensuring we shift both hi and lo
+            $out = "";
+            while (true) {
+                if (($lo & ~0x7f) === 0 &&
+                    $hi === 0) {
+                    $out .= chr($lo);
+                    break;
+                } else {
+                    $out .= chr(($lo & 0xff) | 0x80);
+                    $lo = $lo >> 7;
+                    $lo = $lo | ($hi << 25);
+                    $hi = $hi >> 7;
+                    // Right shift carries sign, but we don't want it to.
+                    $hi = $hi & (127 << 25);
+                }
+            }
+
+            $ret = TStringFuncFactory::create()->strlen($out);
+            $this->trans_->write($out, $ret);
+
+            return $ret;
+        } else {
+            return $this->writeVarint($this->toZigZag($value, 64));
+        }
+    }
+}
diff --git a/lib/php/lib/Protocol/TJSONProtocol.php b/lib/php/lib/Protocol/TJSONProtocol.php
new file mode 100644
index 0000000..9144884
--- /dev/null
+++ b/lib/php/lib/Protocol/TJSONProtocol.php
@@ -0,0 +1,815 @@
+<?php
+
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol;
+
+use Thrift\Type\TType;
+use Thrift\Exception\TProtocolException;
+use Thrift\Protocol\JSON\BaseContext;
+use Thrift\Protocol\JSON\LookaheadReader;
+use Thrift\Protocol\JSON\PairContext;
+use Thrift\Protocol\JSON\ListContext;
+
+/**
+ * JSON implementation of thrift protocol, ported from Java.
+ */
+class TJSONProtocol extends TProtocol
+{
+    const COMMA = ',';
+    const COLON = ':';
+    const LBRACE = '{';
+    const RBRACE = '}';
+    const LBRACKET = '[';
+    const RBRACKET = ']';
+    const QUOTE = '"';
+    const BACKSLASH = '\\';
+    const ZERO = '0';
+    const ESCSEQ = '\\';
+    const DOUBLEESC = '__DOUBLE_ESCAPE_SEQUENCE__';
+
+    const VERSION = 1;
+
+    public static $JSON_CHAR_TABLE = array(
+        /*  0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F */
+        0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, // 0
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
+        1, 1, '"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
+    );
+
+    public static $ESCAPE_CHARS = array('"', '\\', '/', "b", "f", "n", "r", "t");
+
+    public static $ESCAPE_CHAR_VALS = array(
+        '"', '\\', '/', "\x08", "\f", "\n", "\r", "\t",
+    );
+
+    const NAME_BOOL = "tf";
+    const NAME_BYTE = "i8";
+    const NAME_I16 = "i16";
+    const NAME_I32 = "i32";
+    const NAME_I64 = "i64";
+    const NAME_DOUBLE = "dbl";
+    const NAME_STRUCT = "rec";
+    const NAME_STRING = "str";
+    const NAME_MAP = "map";
+    const NAME_LIST = "lst";
+    const NAME_SET = "set";
+
+    private function getTypeNameForTypeID($typeID)
+    {
+        switch ($typeID) {
+            case TType::BOOL:
+                return self::NAME_BOOL;
+            case TType::BYTE:
+                return self::NAME_BYTE;
+            case TType::I16:
+                return self::NAME_I16;
+            case TType::I32:
+                return self::NAME_I32;
+            case TType::I64:
+                return self::NAME_I64;
+            case TType::DOUBLE:
+                return self::NAME_DOUBLE;
+            case TType::STRING:
+                return self::NAME_STRING;
+            case TType::STRUCT:
+                return self::NAME_STRUCT;
+            case TType::MAP:
+                return self::NAME_MAP;
+            case TType::SET:
+                return self::NAME_SET;
+            case TType::LST:
+                return self::NAME_LIST;
+            default:
+                throw new TProtocolException("Unrecognized type", TProtocolException::UNKNOWN);
+        }
+    }
+
+    private function getTypeIDForTypeName($name)
+    {
+        $result = TType::STOP;
+
+        if (strlen($name) > 1) {
+            switch (substr($name, 0, 1)) {
+                case 'd':
+                    $result = TType::DOUBLE;
+                    break;
+                case 'i':
+                    switch (substr($name, 1, 1)) {
+                        case '8':
+                            $result = TType::BYTE;
+                            break;
+                        case '1':
+                            $result = TType::I16;
+                            break;
+                        case '3':
+                            $result = TType::I32;
+                            break;
+                        case '6':
+                            $result = TType::I64;
+                            break;
+                    }
+                    break;
+                case 'l':
+                    $result = TType::LST;
+                    break;
+                case 'm':
+                    $result = TType::MAP;
+                    break;
+                case 'r':
+                    $result = TType::STRUCT;
+                    break;
+                case 's':
+                    if (substr($name, 1, 1) == 't') {
+                        $result = TType::STRING;
+                    } elseif (substr($name, 1, 1) == 'e') {
+                        $result = TType::SET;
+                    }
+                    break;
+                case 't':
+                    $result = TType::BOOL;
+                    break;
+            }
+        }
+        if ($result == TType::STOP) {
+            throw new TProtocolException("Unrecognized type", TProtocolException::INVALID_DATA);
+        }
+
+        return $result;
+    }
+
+    public $contextStack_ = array();
+    public $context_;
+    public $reader_;
+
+    private function pushContext($c)
+    {
+        array_push($this->contextStack_, $this->context_);
+        $this->context_ = $c;
+    }
+
+    private function popContext()
+    {
+        $this->context_ = array_pop($this->contextStack_);
+    }
+
+    public function __construct($trans)
+    {
+        parent::__construct($trans);
+        $this->context_ = new BaseContext();
+        $this->reader_ = new LookaheadReader($this);
+    }
+
+    public function reset()
+    {
+        $this->contextStack_ = array();
+        $this->context_ = new BaseContext();
+        $this->reader_ = new LookaheadReader($this);
+    }
+
+    private $tmpbuf_ = array(4);
+
+    public function readJSONSyntaxChar($b)
+    {
+        $ch = $this->reader_->read();
+
+        if (substr($ch, 0, 1) != $b) {
+            throw new TProtocolException("Unexpected character: " . $ch, TProtocolException::INVALID_DATA);
+        }
+    }
+
+    private function hexVal($s)
+    {
+        for ($i = 0; $i < strlen($s); $i++) {
+            $ch = substr($s, $i, 1);
+
+            if (!($ch >= "a" && $ch <= "f") && !($ch >= "0" && $ch <= "9")) {
+                throw new TProtocolException("Expected hex character " . $ch, TProtocolException::INVALID_DATA);
+            }
+        }
+
+        return hexdec($s);
+    }
+
+    private function hexChar($val)
+    {
+        return dechex($val);
+    }
+
+    private function hasJSONUnescapedUnicode()
+    {
+        if (PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private function unescapedUnicode($str)
+    {
+        if ($this->hasJSONUnescapedUnicode()) {
+            return json_encode($str, JSON_UNESCAPED_UNICODE);
+        }
+
+        $json = json_encode($str);
+
+        /*
+         * Unescaped character outside the Basic Multilingual Plane
+         * High surrogate: 0xD800 - 0xDBFF
+         * Low surrogate: 0xDC00 - 0xDFFF
+         */
+        $json = preg_replace_callback(
+            '/\\\\u(d[89ab][0-9a-f]{2})\\\\u(d[cdef][0-9a-f]{2})/i',
+            function ($matches) {
+                return mb_convert_encoding(pack('H*', $matches[1] . $matches[2]), 'UTF-8', 'UTF-16BE');
+            },
+            $json
+        );
+
+        /*
+         * Unescaped characters within the Basic Multilingual Plane
+         */
+        $json = preg_replace_callback(
+            '/\\\\u([0-9a-f]{4})/i',
+            function ($matches) {
+                return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UTF-16BE');
+            },
+            $json
+        );
+
+        return $json;
+    }
+
+    private function writeJSONString($b)
+    {
+        $this->context_->write();
+
+        if (is_numeric($b) && $this->context_->escapeNum()) {
+            $this->trans_->write(self::QUOTE);
+        }
+
+        $this->trans_->write($this->unescapedUnicode($b));
+
+        if (is_numeric($b) && $this->context_->escapeNum()) {
+            $this->trans_->write(self::QUOTE);
+        }
+    }
+
+    private function writeJSONInteger($num)
+    {
+        $this->context_->write();
+
+        if ($this->context_->escapeNum()) {
+            $this->trans_->write(self::QUOTE);
+        }
+
+        $this->trans_->write($num);
+
+        if ($this->context_->escapeNum()) {
+            $this->trans_->write(self::QUOTE);
+        }
+    }
+
+    private function writeJSONDouble($num)
+    {
+        $this->context_->write();
+
+        if ($this->context_->escapeNum()) {
+            $this->trans_->write(self::QUOTE);
+        }
+
+        $this->trans_->write(json_encode($num));
+
+        if ($this->context_->escapeNum()) {
+            $this->trans_->write(self::QUOTE);
+        }
+    }
+
+    private function writeJSONBase64($data)
+    {
+        $this->context_->write();
+        $this->trans_->write(self::QUOTE);
+        $this->trans_->write(json_encode(base64_encode($data)));
+        $this->trans_->write(self::QUOTE);
+    }
+
+    private function writeJSONObjectStart()
+    {
+        $this->context_->write();
+        $this->trans_->write(self::LBRACE);
+        $this->pushContext(new PairContext($this));
+    }
+
+    private function writeJSONObjectEnd()
+    {
+        $this->popContext();
+        $this->trans_->write(self::RBRACE);
+    }
+
+    private function writeJSONArrayStart()
+    {
+        $this->context_->write();
+        $this->trans_->write(self::LBRACKET);
+        $this->pushContext(new ListContext($this));
+    }
+
+    private function writeJSONArrayEnd()
+    {
+        $this->popContext();
+        $this->trans_->write(self::RBRACKET);
+    }
+
+    private function readJSONString($skipContext)
+    {
+        if (!$skipContext) {
+            $this->context_->read();
+        }
+
+        $jsonString = '';
+        $lastChar = null;
+        while (true) {
+            $ch = $this->reader_->read();
+            $jsonString .= $ch;
+            if ($ch == self::QUOTE &&
+                $lastChar !== null &&
+                $lastChar !== self::ESCSEQ) {
+                break;
+            }
+            if ($ch == self::ESCSEQ && $lastChar == self::ESCSEQ) {
+                $lastChar = self::DOUBLEESC;
+            } else {
+                $lastChar = $ch;
+            }
+        }
+
+        return json_decode($jsonString);
+    }
+
+    private function isJSONNumeric($b)
+    {
+        switch ($b) {
+            case '+':
+            case '-':
+            case '.':
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'E':
+            case 'e':
+                return true;
+        }
+
+        return false;
+    }
+
+    private function readJSONNumericChars()
+    {
+        $strbld = array();
+
+        while (true) {
+            $ch = $this->reader_->peek();
+
+            if (!$this->isJSONNumeric($ch)) {
+                break;
+            }
+
+            $strbld[] = $this->reader_->read();
+        }
+
+        return implode("", $strbld);
+    }
+
+    private function readJSONInteger()
+    {
+        $this->context_->read();
+
+        if ($this->context_->escapeNum()) {
+            $this->readJSONSyntaxChar(self::QUOTE);
+        }
+
+        $str = $this->readJSONNumericChars();
+
+        if ($this->context_->escapeNum()) {
+            $this->readJSONSyntaxChar(self::QUOTE);
+        }
+
+        if (!is_numeric($str)) {
+            throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA);
+        }
+
+        return intval($str);
+    }
+
+    /**
+     * Identical to readJSONInteger but without the final cast.
+     * Needed for proper handling of i64 on 32 bit machines.  Why a
+     * separate function?  So we don't have to force the rest of the
+     * use cases through the extra conditional.
+     */
+    private function readJSONIntegerAsString()
+    {
+        $this->context_->read();
+
+        if ($this->context_->escapeNum()) {
+            $this->readJSONSyntaxChar(self::QUOTE);
+        }
+
+        $str = $this->readJSONNumericChars();
+
+        if ($this->context_->escapeNum()) {
+            $this->readJSONSyntaxChar(self::QUOTE);
+        }
+
+        if (!is_numeric($str)) {
+            throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA);
+        }
+
+        return $str;
+    }
+
+    private function readJSONDouble()
+    {
+        $this->context_->read();
+
+        if (substr($this->reader_->peek(), 0, 1) == self::QUOTE) {
+            $arr = $this->readJSONString(true);
+
+            if ($arr == "NaN") {
+                return NAN;
+            } elseif ($arr == "Infinity") {
+                return INF;
+            } elseif (!$this->context_->escapeNum()) {
+                throw new TProtocolException(
+                    "Numeric data unexpectedly quoted " . $arr,
+                    TProtocolException::INVALID_DATA
+                );
+            }
+
+            return floatval($arr);
+        } else {
+            if ($this->context_->escapeNum()) {
+                $this->readJSONSyntaxChar(self::QUOTE);
+            }
+
+            return floatval($this->readJSONNumericChars());
+        }
+    }
+
+    private function readJSONBase64()
+    {
+        $arr = $this->readJSONString(false);
+        $data = base64_decode($arr, true);
+
+        if ($data === false) {
+            throw new TProtocolException("Invalid base64 data " . $arr, TProtocolException::INVALID_DATA);
+        }
+
+        return $data;
+    }
+
+    private function readJSONObjectStart()
+    {
+        $this->context_->read();
+        $this->readJSONSyntaxChar(self::LBRACE);
+        $this->pushContext(new PairContext($this));
+    }
+
+    private function readJSONObjectEnd()
+    {
+        $this->readJSONSyntaxChar(self::RBRACE);
+        $this->popContext();
+    }
+
+    private function readJSONArrayStart()
+    {
+        $this->context_->read();
+        $this->readJSONSyntaxChar(self::LBRACKET);
+        $this->pushContext(new ListContext($this));
+    }
+
+    private function readJSONArrayEnd()
+    {
+        $this->readJSONSyntaxChar(self::RBRACKET);
+        $this->popContext();
+    }
+
+    /**
+     * Writes the message header
+     *
+     * @param string $name Function name
+     * @param int $type message type TMessageType::CALL or TMessageType::REPLY
+     * @param int $seqid The sequence id of this message
+     */
+    public function writeMessageBegin($name, $type, $seqid)
+    {
+        $this->writeJSONArrayStart();
+        $this->writeJSONInteger(self::VERSION);
+        $this->writeJSONString($name);
+        $this->writeJSONInteger($type);
+        $this->writeJSONInteger($seqid);
+    }
+
+    /**
+     * Close the message
+     */
+    public function writeMessageEnd()
+    {
+        $this->writeJSONArrayEnd();
+    }
+
+    /**
+     * Writes a struct header.
+     *
+     * @param  string $name Struct name
+     * @throws TException on write error
+     * @return int        How many bytes written
+     */
+    public function writeStructBegin($name)
+    {
+        $this->writeJSONObjectStart();
+    }
+
+    /**
+     * Close a struct.
+     *
+     * @throws TException on write error
+     * @return int        How many bytes written
+     */
+    public function writeStructEnd()
+    {
+        $this->writeJSONObjectEnd();
+    }
+
+    public function writeFieldBegin($fieldName, $fieldType, $fieldId)
+    {
+        $this->writeJSONInteger($fieldId);
+        $this->writeJSONObjectStart();
+        $this->writeJSONString($this->getTypeNameForTypeID($fieldType));
+    }
+
+    public function writeFieldEnd()
+    {
+        $this->writeJsonObjectEnd();
+    }
+
+    public function writeFieldStop()
+    {
+    }
+
+    public function writeMapBegin($keyType, $valType, $size)
+    {
+        $this->writeJSONArrayStart();
+        $this->writeJSONString($this->getTypeNameForTypeID($keyType));
+        $this->writeJSONString($this->getTypeNameForTypeID($valType));
+        $this->writeJSONInteger($size);
+        $this->writeJSONObjectStart();
+    }
+
+    public function writeMapEnd()
+    {
+        $this->writeJSONObjectEnd();
+        $this->writeJSONArrayEnd();
+    }
+
+    public function writeListBegin($elemType, $size)
+    {
+        $this->writeJSONArrayStart();
+        $this->writeJSONString($this->getTypeNameForTypeID($elemType));
+        $this->writeJSONInteger($size);
+    }
+
+    public function writeListEnd()
+    {
+        $this->writeJSONArrayEnd();
+    }
+
+    public function writeSetBegin($elemType, $size)
+    {
+        $this->writeJSONArrayStart();
+        $this->writeJSONString($this->getTypeNameForTypeID($elemType));
+        $this->writeJSONInteger($size);
+    }
+
+    public function writeSetEnd()
+    {
+        $this->writeJSONArrayEnd();
+    }
+
+    public function writeBool($bool)
+    {
+        $this->writeJSONInteger($bool ? 1 : 0);
+    }
+
+    public function writeByte($byte)
+    {
+        $this->writeJSONInteger($byte);
+    }
+
+    public function writeI16($i16)
+    {
+        $this->writeJSONInteger($i16);
+    }
+
+    public function writeI32($i32)
+    {
+        $this->writeJSONInteger($i32);
+    }
+
+    public function writeI64($i64)
+    {
+        $this->writeJSONInteger($i64);
+    }
+
+    public function writeDouble($dub)
+    {
+        $this->writeJSONDouble($dub);
+    }
+
+    public function writeString($str)
+    {
+        $this->writeJSONString($str);
+    }
+
+    /**
+     * Reads the message header
+     *
+     * @param string $name Function name
+     * @param int $type message type TMessageType::CALL or TMessageType::REPLY
+     * @parem int $seqid The sequence id of this message
+     */
+    public function readMessageBegin(&$name, &$type, &$seqid)
+    {
+        $this->readJSONArrayStart();
+
+        if ($this->readJSONInteger() != self::VERSION) {
+            throw new TProtocolException("Message contained bad version", TProtocolException::BAD_VERSION);
+        }
+
+        $name = $this->readJSONString(false);
+        $type = $this->readJSONInteger();
+        $seqid = $this->readJSONInteger();
+
+        return true;
+    }
+
+    /**
+     * Read the close of message
+     */
+    public function readMessageEnd()
+    {
+        $this->readJSONArrayEnd();
+    }
+
+    public function readStructBegin(&$name)
+    {
+        $this->readJSONObjectStart();
+
+        return 0;
+    }
+
+    public function readStructEnd()
+    {
+        $this->readJSONObjectEnd();
+    }
+
+    public function readFieldBegin(&$name, &$fieldType, &$fieldId)
+    {
+        $ch = $this->reader_->peek();
+        $name = "";
+
+        if (substr($ch, 0, 1) == self::RBRACE) {
+            $fieldType = TType::STOP;
+        } else {
+            $fieldId = $this->readJSONInteger();
+            $this->readJSONObjectStart();
+            $fieldType = $this->getTypeIDForTypeName($this->readJSONString(false));
+        }
+    }
+
+    public function readFieldEnd()
+    {
+        $this->readJSONObjectEnd();
+    }
+
+    public function readMapBegin(&$keyType, &$valType, &$size)
+    {
+        $this->readJSONArrayStart();
+        $keyType = $this->getTypeIDForTypeName($this->readJSONString(false));
+        $valType = $this->getTypeIDForTypeName($this->readJSONString(false));
+        $size = $this->readJSONInteger();
+        $this->readJSONObjectStart();
+    }
+
+    public function readMapEnd()
+    {
+        $this->readJSONObjectEnd();
+        $this->readJSONArrayEnd();
+    }
+
+    public function readListBegin(&$elemType, &$size)
+    {
+        $this->readJSONArrayStart();
+        $elemType = $this->getTypeIDForTypeName($this->readJSONString(false));
+        $size = $this->readJSONInteger();
+
+        return true;
+    }
+
+    public function readListEnd()
+    {
+        $this->readJSONArrayEnd();
+    }
+
+    public function readSetBegin(&$elemType, &$size)
+    {
+        $this->readJSONArrayStart();
+        $elemType = $this->getTypeIDForTypeName($this->readJSONString(false));
+        $size = $this->readJSONInteger();
+
+        return true;
+    }
+
+    public function readSetEnd()
+    {
+        $this->readJSONArrayEnd();
+    }
+
+    public function readBool(&$bool)
+    {
+        $bool = $this->readJSONInteger() == 0 ? false : true;
+
+        return true;
+    }
+
+    public function readByte(&$byte)
+    {
+        $byte = $this->readJSONInteger();
+
+        return true;
+    }
+
+    public function readI16(&$i16)
+    {
+        $i16 = $this->readJSONInteger();
+
+        return true;
+    }
+
+    public function readI32(&$i32)
+    {
+        $i32 = $this->readJSONInteger();
+
+        return true;
+    }
+
+    public function readI64(&$i64)
+    {
+        if (PHP_INT_SIZE === 4) {
+            $i64 = $this->readJSONIntegerAsString();
+        } else {
+            $i64 = $this->readJSONInteger();
+        }
+
+        return true;
+    }
+
+    public function readDouble(&$dub)
+    {
+        $dub = $this->readJSONDouble();
+
+        return true;
+    }
+
+    public function readString(&$str)
+    {
+        $str = $this->readJSONString(false);
+
+        return true;
+    }
+}
diff --git a/lib/php/lib/Protocol/TMultiplexedProtocol.php b/lib/php/lib/Protocol/TMultiplexedProtocol.php
new file mode 100644
index 0000000..d579c09
--- /dev/null
+++ b/lib/php/lib/Protocol/TMultiplexedProtocol.php
@@ -0,0 +1,85 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol;
+
+use Thrift\Type\TMessageType;
+
+/**
+ * <code>TMultiplexedProtocol</code> is a protocol-independent concrete decorator
+ * that allows a Thrift client to communicate with a multiplexing Thrift server,
+ * by prepending the service name to the function name during function calls.
+ *
+ * @package Thrift\Protocol
+ */
+class TMultiplexedProtocol extends TProtocolDecorator
+{
+    /**
+     * Separator between service name and function name.
+     * Should be the same as used at multiplexed Thrift server.
+     *
+     * @var string
+     */
+    const SEPARATOR = ":";
+
+    /**
+     * The name of service.
+     *
+     * @var string
+     */
+    private $serviceName_;
+
+    /**
+     * Constructor of <code>TMultiplexedProtocol</code> class.
+     *
+     * Wrap the specified protocol, allowing it to be used to communicate with a
+     * multiplexing server.  The <code>$serviceName</code> is required as it is
+     * prepended to the message header so that the multiplexing server can broker
+     * the function call to the proper service.
+     *
+     * @param TProtocol $protocol
+     * @param string    $serviceName The name of service.
+     */
+    public function __construct(TProtocol $protocol, $serviceName)
+    {
+        parent::__construct($protocol);
+        $this->serviceName_ = $serviceName;
+    }
+
+    /**
+     * Writes the message header.
+     * Prepends the service name to the function name, separated by <code>TMultiplexedProtocol::SEPARATOR</code>.
+     *
+     * @param string $name  Function name.
+     * @param int    $type  Message type.
+     * @param int    $seqid The sequence id of this message.
+     */
+    public function writeMessageBegin($name, $type, $seqid)
+    {
+        if ($type == TMessageType::CALL || $type == TMessageType::ONEWAY) {
+            $nameWithService = $this->serviceName_ . self::SEPARATOR . $name;
+            parent::writeMessageBegin($nameWithService, $type, $seqid);
+        } else {
+            parent::writeMessageBegin($name, $type, $seqid);
+        }
+    }
+}
diff --git a/lib/php/lib/Protocol/TProtocol.php b/lib/php/lib/Protocol/TProtocol.php
new file mode 100644
index 0000000..81aceb6
--- /dev/null
+++ b/lib/php/lib/Protocol/TProtocol.php
@@ -0,0 +1,350 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol;
+
+use Thrift\Type\TType;
+use Thrift\Exception\TProtocolException;
+
+/**
+ * Protocol base class module.
+ */
+abstract class TProtocol
+{
+    /**
+     * Underlying transport
+     *
+     * @var TTransport
+     */
+    protected $trans_;
+
+    /**
+     * Constructor
+     */
+    protected function __construct($trans)
+    {
+        $this->trans_ = $trans;
+    }
+
+    /**
+     * Accessor for transport
+     *
+     * @return TTransport
+     */
+    public function getTransport()
+    {
+        return $this->trans_;
+    }
+
+    /**
+     * Writes the message header
+     *
+     * @param string $name Function name
+     * @param int $type message type TMessageType::CALL or TMessageType::REPLY
+     * @param int $seqid The sequence id of this message
+     */
+    abstract public function writeMessageBegin($name, $type, $seqid);
+
+    /**
+     * Close the message
+     */
+    abstract public function writeMessageEnd();
+
+    /**
+     * Writes a struct header.
+     *
+     * @param string $name Struct name
+     * @throws TException on write error
+     * @return int How many bytes written
+     */
+    abstract public function writeStructBegin($name);
+
+    /**
+     * Close a struct.
+     *
+     * @throws TException on write error
+     * @return int How many bytes written
+     */
+    abstract public function writeStructEnd();
+
+    /*
+     * Starts a field.
+     *
+     * @param string     $name Field name
+     * @param int        $type Field type
+     * @param int        $fid  Field id
+     * @throws TException on write error
+     * @return int How many bytes written
+     */
+    abstract public function writeFieldBegin($fieldName, $fieldType, $fieldId);
+
+    abstract public function writeFieldEnd();
+
+    abstract public function writeFieldStop();
+
+    abstract public function writeMapBegin($keyType, $valType, $size);
+
+    abstract public function writeMapEnd();
+
+    abstract public function writeListBegin($elemType, $size);
+
+    abstract public function writeListEnd();
+
+    abstract public function writeSetBegin($elemType, $size);
+
+    abstract public function writeSetEnd();
+
+    abstract public function writeBool($bool);
+
+    abstract public function writeByte($byte);
+
+    abstract public function writeI16($i16);
+
+    abstract public function writeI32($i32);
+
+    abstract public function writeI64($i64);
+
+    abstract public function writeDouble($dub);
+
+    abstract public function writeString($str);
+
+    /**
+     * Reads the message header
+     *
+     * @param string $name Function name
+     * @param int $type message type TMessageType::CALL or TMessageType::REPLY
+     * @parem int $seqid The sequence id of this message
+     */
+    abstract public function readMessageBegin(&$name, &$type, &$seqid);
+
+    /**
+     * Read the close of message
+     */
+    abstract public function readMessageEnd();
+
+    abstract public function readStructBegin(&$name);
+
+    abstract public function readStructEnd();
+
+    abstract public function readFieldBegin(&$name, &$fieldType, &$fieldId);
+
+    abstract public function readFieldEnd();
+
+    abstract public function readMapBegin(&$keyType, &$valType, &$size);
+
+    abstract public function readMapEnd();
+
+    abstract public function readListBegin(&$elemType, &$size);
+
+    abstract public function readListEnd();
+
+    abstract public function readSetBegin(&$elemType, &$size);
+
+    abstract public function readSetEnd();
+
+    abstract public function readBool(&$bool);
+
+    abstract public function readByte(&$byte);
+
+    abstract public function readI16(&$i16);
+
+    abstract public function readI32(&$i32);
+
+    abstract public function readI64(&$i64);
+
+    abstract public function readDouble(&$dub);
+
+    abstract public function readString(&$str);
+
+    /**
+     * The skip function is a utility to parse over unrecognized date without
+     * causing corruption.
+     *
+     * @param TType $type What type is it
+     */
+    public function skip($type)
+    {
+        switch ($type) {
+            case TType::BOOL:
+                return $this->readBool($bool);
+            case TType::BYTE:
+                return $this->readByte($byte);
+            case TType::I16:
+                return $this->readI16($i16);
+            case TType::I32:
+                return $this->readI32($i32);
+            case TType::I64:
+                return $this->readI64($i64);
+            case TType::DOUBLE:
+                return $this->readDouble($dub);
+            case TType::STRING:
+                return $this->readString($str);
+            case TType::STRUCT:
+                $result = $this->readStructBegin($name);
+                while (true) {
+                    $result += $this->readFieldBegin($name, $ftype, $fid);
+                    if ($ftype == TType::STOP) {
+                        break;
+                    }
+                    $result += $this->skip($ftype);
+                    $result += $this->readFieldEnd();
+                }
+                $result += $this->readStructEnd();
+
+                return $result;
+
+            case TType::MAP:
+                $result = $this->readMapBegin($keyType, $valType, $size);
+                for ($i = 0; $i < $size; $i++) {
+                    $result += $this->skip($keyType);
+                    $result += $this->skip($valType);
+                }
+                $result += $this->readMapEnd();
+
+                return $result;
+
+            case TType::SET:
+                $result = $this->readSetBegin($elemType, $size);
+                for ($i = 0; $i < $size; $i++) {
+                    $result += $this->skip($elemType);
+                }
+                $result += $this->readSetEnd();
+
+                return $result;
+
+            case TType::LST:
+                $result = $this->readListBegin($elemType, $size);
+                for ($i = 0; $i < $size; $i++) {
+                    $result += $this->skip($elemType);
+                }
+                $result += $this->readListEnd();
+
+                return $result;
+
+            default:
+                throw new TProtocolException(
+                    'Unknown field type: ' . $type,
+                    TProtocolException::INVALID_DATA
+                );
+        }
+    }
+
+    /**
+     * Utility for skipping binary data
+     *
+     * @param TTransport $itrans TTransport object
+     * @param int $type Field type
+     */
+    public static function skipBinary($itrans, $type)
+    {
+        switch ($type) {
+            case TType::BOOL:
+                return $itrans->readAll(1);
+            case TType::BYTE:
+                return $itrans->readAll(1);
+            case TType::I16:
+                return $itrans->readAll(2);
+            case TType::I32:
+                return $itrans->readAll(4);
+            case TType::I64:
+                return $itrans->readAll(8);
+            case TType::DOUBLE:
+                return $itrans->readAll(8);
+            case TType::STRING:
+                $len = unpack('N', $itrans->readAll(4));
+                $len = $len[1];
+                if ($len > 0x7fffffff) {
+                    $len = 0 - (($len - 1) ^ 0xffffffff);
+                }
+
+                return 4 + $itrans->readAll($len);
+
+            case TType::STRUCT:
+                $result = 0;
+                while (true) {
+                    $ftype = 0;
+                    $fid = 0;
+                    $data = $itrans->readAll(1);
+                    $arr = unpack('c', $data);
+                    $ftype = $arr[1];
+                    if ($ftype == TType::STOP) {
+                        break;
+                    }
+                    // I16 field id
+                    $result += $itrans->readAll(2);
+                    $result += self::skipBinary($itrans, $ftype);
+                }
+
+                return $result;
+
+            case TType::MAP:
+                // Ktype
+                $data = $itrans->readAll(1);
+                $arr = unpack('c', $data);
+                $ktype = $arr[1];
+                // Vtype
+                $data = $itrans->readAll(1);
+                $arr = unpack('c', $data);
+                $vtype = $arr[1];
+                // Size
+                $data = $itrans->readAll(4);
+                $arr = unpack('N', $data);
+                $size = $arr[1];
+                if ($size > 0x7fffffff) {
+                    $size = 0 - (($size - 1) ^ 0xffffffff);
+                }
+                $result = 6;
+                for ($i = 0; $i < $size; $i++) {
+                    $result += self::skipBinary($itrans, $ktype);
+                    $result += self::skipBinary($itrans, $vtype);
+                }
+
+                return $result;
+
+            case TType::SET:
+            case TType::LST:
+                // Vtype
+                $data = $itrans->readAll(1);
+                $arr = unpack('c', $data);
+                $vtype = $arr[1];
+                // Size
+                $data = $itrans->readAll(4);
+                $arr = unpack('N', $data);
+                $size = $arr[1];
+                if ($size > 0x7fffffff) {
+                    $size = 0 - (($size - 1) ^ 0xffffffff);
+                }
+                $result = 5;
+                for ($i = 0; $i < $size; $i++) {
+                    $result += self::skipBinary($itrans, $vtype);
+                }
+
+                return $result;
+
+            default:
+                throw new TProtocolException(
+                    'Unknown field type: ' . $type,
+                    TProtocolException::INVALID_DATA
+                );
+        }
+    }
+}
diff --git a/lib/php/lib/Protocol/TProtocolDecorator.php b/lib/php/lib/Protocol/TProtocolDecorator.php
new file mode 100644
index 0000000..a85e0b8
--- /dev/null
+++ b/lib/php/lib/Protocol/TProtocolDecorator.php
@@ -0,0 +1,285 @@
+<?php
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol;
+
+use Thrift\Exception\TException;
+
+/**
+ * <code>TProtocolDecorator</code> forwards all requests to an enclosed
+ * <code>TProtocol</code> instance, providing a way to author concise
+ * concrete decorator subclasses. While it has no abstract methods, it
+ * is marked abstract as a reminder that by itself, it does not modify
+ * the behaviour of the enclosed <code>TProtocol</code>.
+ *
+ * @package Thrift\Protocol
+ */
+abstract class TProtocolDecorator extends TProtocol
+{
+    /**
+     * Instance of protocol, to which all operations will be forwarded.
+     *
+     * @var TProtocol
+     */
+    private $concreteProtocol_;
+
+    /**
+     * Constructor of <code>TProtocolDecorator</code> class.
+     * Encloses the specified protocol.
+     *
+     * @param TProtocol $protocol All operations will be forward to this instance. Must be non-null.
+     */
+    protected function __construct(TProtocol $protocol)
+    {
+        parent::__construct($protocol->getTransport());
+        $this->concreteProtocol_ = $protocol;
+    }
+
+    /**
+     * Writes the message header.
+     *
+     * @param string $name  Function name
+     * @param int    $type  message type TMessageType::CALL or TMessageType::REPLY
+     * @param int    $seqid The sequence id of this message
+     */
+    public function writeMessageBegin($name, $type, $seqid)
+    {
+        return $this->concreteProtocol_->writeMessageBegin($name, $type, $seqid);
+    }
+
+    /**
+     * Closes the message.
+     */
+    public function writeMessageEnd()
+    {
+        return $this->concreteProtocol_->writeMessageEnd();
+    }
+
+    /**
+     * Writes a struct header.
+     *
+     * @param string $name Struct name
+     *
+     * @throws TException on write error
+     * @return int        How many bytes written
+     */
+    public function writeStructBegin($name)
+    {
+        return $this->concreteProtocol_->writeStructBegin($name);
+    }
+
+    /**
+     * Close a struct.
+     *
+     * @throws TException on write error
+     * @return int        How many bytes written
+     */
+    public function writeStructEnd()
+    {
+        return $this->concreteProtocol_->writeStructEnd();
+    }
+
+    public function writeFieldBegin($fieldName, $fieldType, $fieldId)
+    {
+        return $this->concreteProtocol_->writeFieldBegin($fieldName, $fieldType, $fieldId);
+    }
+
+    public function writeFieldEnd()
+    {
+        return $this->concreteProtocol_->writeFieldEnd();
+    }
+
+    public function writeFieldStop()
+    {
+        return $this->concreteProtocol_->writeFieldStop();
+    }
+
+    public function writeMapBegin($keyType, $valType, $size)
+    {
+        return $this->concreteProtocol_->writeMapBegin($keyType, $valType, $size);
+    }
+
+    public function writeMapEnd()
+    {
+        return $this->concreteProtocol_->writeMapEnd();
+    }
+
+    public function writeListBegin($elemType, $size)
+    {
+        return $this->concreteProtocol_->writeListBegin($elemType, $size);
+    }
+
+    public function writeListEnd()
+    {
+        return $this->concreteProtocol_->writeListEnd();
+    }
+
+    public function writeSetBegin($elemType, $size)
+    {
+        return $this->concreteProtocol_->writeSetBegin($elemType, $size);
+    }
+
+    public function writeSetEnd()
+    {
+        return $this->concreteProtocol_->writeSetEnd();
+    }
+
+    public function writeBool($bool)
+    {
+        return $this->concreteProtocol_->writeBool($bool);
+    }
+
+    public function writeByte($byte)
+    {
+        return $this->concreteProtocol_->writeByte($byte);
+    }
+
+    public function writeI16($i16)
+    {
+        return $this->concreteProtocol_->writeI16($i16);
+    }
+
+    public function writeI32($i32)
+    {
+        return $this->concreteProtocol_->writeI32($i32);
+    }
+
+    public function writeI64($i64)
+    {
+        return $this->concreteProtocol_->writeI64($i64);
+    }
+
+    public function writeDouble($dub)
+    {
+        return $this->concreteProtocol_->writeDouble($dub);
+    }
+
+    public function writeString($str)
+    {
+        return $this->concreteProtocol_->writeString($str);
+    }
+
+    /**
+     * Reads the message header
+     *
+     * @param string $name  Function name
+     * @param int    $type  message type TMessageType::CALL or TMessageType::REPLY
+     * @param int    $seqid The sequence id of this message
+     */
+    public function readMessageBegin(&$name, &$type, &$seqid)
+    {
+        return $this->concreteProtocol_->readMessageBegin($name, $type, $seqid);
+    }
+
+    /**
+     * Read the close of message
+     */
+    public function readMessageEnd()
+    {
+        return $this->concreteProtocol_->readMessageEnd();
+    }
+
+    public function readStructBegin(&$name)
+    {
+        return $this->concreteProtocol_->readStructBegin($name);
+    }
+
+    public function readStructEnd()
+    {
+        return $this->concreteProtocol_->readStructEnd();
+    }
+
+    public function readFieldBegin(&$name, &$fieldType, &$fieldId)
+    {
+        return $this->concreteProtocol_->readFieldBegin($name, $fieldType, $fieldId);
+    }
+
+    public function readFieldEnd()
+    {
+        return $this->concreteProtocol_->readFieldEnd();
+    }
+
+    public function readMapBegin(&$keyType, &$valType, &$size)
+    {
+        $this->concreteProtocol_->readMapBegin($keyType, $valType, $size);
+    }
+
+    public function readMapEnd()
+    {
+        return $this->concreteProtocol_->readMapEnd();
+    }
+
+    public function readListBegin(&$elemType, &$size)
+    {
+        $this->concreteProtocol_->readListBegin($elemType, $size);
+    }
+
+    public function readListEnd()
+    {
+        return $this->concreteProtocol_->readListEnd();
+    }
+
+    public function readSetBegin(&$elemType, &$size)
+    {
+        return $this->concreteProtocol_->readSetBegin($elemType, $size);
+    }
+
+    public function readSetEnd()
+    {
+        return $this->concreteProtocol_->readSetEnd();
+    }
+
+    public function readBool(&$bool)
+    {
+        return $this->concreteProtocol_->readBool($bool);
+    }
+
+    public function readByte(&$byte)
+    {
+        return $this->concreteProtocol_->readByte($byte);
+    }
+
+    public function readI16(&$i16)
+    {
+        return $this->concreteProtocol_->readI16($i16);
+    }
+
+    public function readI32(&$i32)
+    {
+        return $this->concreteProtocol_->readI32($i32);
+    }
+
+    public function readI64(&$i64)
+    {
+        return $this->concreteProtocol_->readI64($i64);
+    }
+
+    public function readDouble(&$dub)
+    {
+        return $this->concreteProtocol_->readDouble($dub);
+    }
+
+    public function readString(&$str)
+    {
+        return $this->concreteProtocol_->readString($str);
+    }
+}
diff --git a/lib/php/lib/Protocol/TSimpleJSONProtocol.php b/lib/php/lib/Protocol/TSimpleJSONProtocol.php
new file mode 100644
index 0000000..1cf1f64
--- /dev/null
+++ b/lib/php/lib/Protocol/TSimpleJSONProtocol.php
@@ -0,0 +1,374 @@
+<?php
+
+/*
+ * 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.protocol
+ */
+
+namespace Thrift\Protocol;
+
+use Thrift\Exception\TException;
+use Thrift\Exception\TProtocolException;
+use Thrift\Protocol\SimpleJSON\Context;
+use Thrift\Protocol\SimpleJSON\ListContext;
+use Thrift\Protocol\SimpleJSON\StructContext;
+use Thrift\Protocol\SimpleJSON\MapContext;
+use Thrift\Protocol\SimpleJSON\CollectionMapKeyException;
+
+/**
+ * SimpleJSON implementation of thrift protocol, ported from Java.
+ */
+class TSimpleJSONProtocol extends TProtocol
+{
+    const COMMA = ',';
+    const COLON = ':';
+    const LBRACE = '{';
+    const RBRACE = '}';
+    const LBRACKET = '[';
+    const RBRACKET = ']';
+    const QUOTE = '"';
+
+    const NAME_MAP = "map";
+    const NAME_LIST = "lst";
+    const NAME_SET = "set";
+
+    protected $writeContext_ = null;
+    protected $writeContextStack_ = [];
+
+    /**
+     * Push a new write context onto the stack.
+     */
+    protected function pushWriteContext(Context $c)
+    {
+        $this->writeContextStack_[] = $this->writeContext_;
+        $this->writeContext_ = $c;
+    }
+
+    /**
+     * Pop the last write context off the stack
+     */
+    protected function popWriteContext()
+    {
+        $this->writeContext_ = array_pop($this->writeContextStack_);
+    }
+
+    /**
+     * Used to make sure that we are not encountering a map whose keys are containers
+     */
+    protected function assertContextIsNotMapKey($invalidKeyType)
+    {
+        if ($this->writeContext_->isMapKey()) {
+            throw new CollectionMapKeyException(
+                "Cannot serialize a map with keys that are of type " .
+                $invalidKeyType
+            );
+        }
+    }
+
+    private function writeJSONString($b)
+    {
+        $this->writeContext_->write();
+
+        $this->trans_->write(json_encode((string)$b));
+    }
+
+    private function writeJSONInteger($num)
+    {
+        $isMapKey = $this->writeContext_->isMapKey();
+
+        $this->writeContext_->write();
+
+        if ($isMapKey) {
+            $this->trans_->write(self::QUOTE);
+        }
+
+        $this->trans_->write((int)$num);
+
+        if ($isMapKey) {
+            $this->trans_->write(self::QUOTE);
+        }
+    }
+
+    private function writeJSONDouble($num)
+    {
+        $isMapKey = $this->writeContext_->isMapKey();
+
+        $this->writeContext_->write();
+
+        if ($isMapKey) {
+            $this->trans_->write(self::QUOTE);
+        }
+
+        $this->trans_->write(json_encode((float)$num));
+
+        if ($isMapKey) {
+            $this->trans_->write(self::QUOTE);
+        }
+    }
+
+    /**
+     * Constructor
+     */
+    public function __construct($trans)
+    {
+        parent::__construct($trans);
+        $this->writeContext_ = new Context();
+    }
+
+    /**
+     * Writes the message header
+     *
+     * @param string $name  Function name
+     * @param int    $type  message type TMessageType::CALL or TMessageType::REPLY
+     * @param int    $seqid The sequence id of this message
+     */
+    public function writeMessageBegin($name, $type, $seqid)
+    {
+        $this->trans_->write(self::LBRACKET);
+        $this->pushWriteContext(new ListContext($this));
+        $this->writeJSONString($name);
+        $this->writeJSONInteger($type);
+        $this->writeJSONInteger($seqid);
+    }
+
+    /**
+     * Close the message
+     */
+    public function writeMessageEnd()
+    {
+        $this->popWriteContext();
+        $this->trans_->write(self::RBRACKET);
+    }
+
+    /**
+     * Writes a struct header.
+     *
+     * @param  string     $name Struct name
+     */
+    public function writeStructBegin($name)
+    {
+        $this->writeContext_->write();
+        $this->trans_->write(self::LBRACE);
+        $this->pushWriteContext(new StructContext($this));
+    }
+
+    /**
+     * Close a struct.
+     */
+    public function writeStructEnd()
+    {
+        $this->popWriteContext();
+        $this->trans_->write(self::RBRACE);
+    }
+
+    public function writeFieldBegin($fieldName, $fieldType, $fieldId)
+    {
+        $this->writeJSONString($fieldName);
+    }
+
+    public function writeFieldEnd()
+    {
+    }
+
+    public function writeFieldStop()
+    {
+    }
+
+    public function writeMapBegin($keyType, $valType, $size)
+    {
+        $this->assertContextIsNotMapKey(self::NAME_MAP);
+        $this->writeContext_->write();
+        $this->trans_->write(self::LBRACE);
+        $this->pushWriteContext(new MapContext($this));
+    }
+
+    public function writeMapEnd()
+    {
+        $this->popWriteContext();
+        $this->trans_->write(self::RBRACE);
+    }
+
+    public function writeListBegin($elemType, $size)
+    {
+        $this->assertContextIsNotMapKey(self::NAME_LIST);
+        $this->writeContext_->write();
+        $this->trans_->write(self::LBRACKET);
+        $this->pushWriteContext(new ListContext($this));
+        // No metadata!
+    }
+
+    public function writeListEnd()
+    {
+        $this->popWriteContext();
+        $this->trans_->write(self::RBRACKET);
+    }
+
+    public function writeSetBegin($elemType, $size)
+    {
+        $this->assertContextIsNotMapKey(self::NAME_SET);
+        $this->writeContext_->write();
+        $this->trans_->write(self::LBRACKET);
+        $this->pushWriteContext(new ListContext($this));
+        // No metadata!
+    }
+
+    public function writeSetEnd()
+    {
+        $this->popWriteContext();
+        $this->trans_->write(self::RBRACKET);
+    }
+
+    public function writeBool($bool)
+    {
+        $this->writeJSONInteger($bool ? 1 : 0);
+    }
+
+    public function writeByte($byte)
+    {
+        $this->writeJSONInteger($byte);
+    }
+
+    public function writeI16($i16)
+    {
+        $this->writeJSONInteger($i16);
+    }
+
+    public function writeI32($i32)
+    {
+        $this->writeJSONInteger($i32);
+    }
+
+    public function writeI64($i64)
+    {
+        $this->writeJSONInteger($i64);
+    }
+
+    public function writeDouble($dub)
+    {
+        $this->writeJSONDouble($dub);
+    }
+
+    public function writeString($str)
+    {
+        $this->writeJSONString($str);
+    }
+
+    /**
+     * Reading methods.
+     *
+     * simplejson is not meant to be read back into thrift
+     * - see http://wiki.apache.org/thrift/ThriftUsageJava
+     * - use JSON instead
+     */
+
+    public function readMessageBegin(&$name, &$type, &$seqid)
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readMessageEnd()
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readStructBegin(&$name)
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readStructEnd()
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readFieldBegin(&$name, &$fieldType, &$fieldId)
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readFieldEnd()
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readMapBegin(&$keyType, &$valType, &$size)
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readMapEnd()
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readListBegin(&$elemType, &$size)
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readListEnd()
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readSetBegin(&$elemType, &$size)
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readSetEnd()
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readBool(&$bool)
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readByte(&$byte)
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readI16(&$i16)
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readI32(&$i32)
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readI64(&$i64)
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readDouble(&$dub)
+    {
+        throw new TException("Not implemented");
+    }
+
+    public function readString(&$str)
+    {
+        throw new TException("Not implemented");
+    }
+}
diff --git a/lib/php/lib/Serializer/TBinarySerializer.php b/lib/php/lib/Serializer/TBinarySerializer.php
new file mode 100644
index 0000000..9d2b147
--- /dev/null
+++ b/lib/php/lib/Serializer/TBinarySerializer.php
@@ -0,0 +1,87 @@
+<?php
+/*
+ * 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.protocol
+ * @author: rmarin (marin.radu@facebook.com)
+ */
+
+namespace Thrift\Serializer;
+
+use Thrift\Transport\TMemoryBuffer;
+use Thrift\Protocol\TBinaryProtocolAccelerated;
+use Thrift\Type\TMessageType;
+
+/**
+ * Utility class for serializing and deserializing
+ * a thrift object using TBinaryProtocolAccelerated.
+ */
+class TBinarySerializer
+{
+    // NOTE(rmarin): Because thrift_protocol_write_binary
+    // adds a begin message prefix, you cannot specify
+    // a transport in which to serialize an object. It has to
+    // be a string. Otherwise we will break the compatibility with
+    // normal deserialization.
+    public static function serialize($object)
+    {
+        $transport = new TMemoryBuffer();
+        $protocol = new TBinaryProtocolAccelerated($transport);
+        if (function_exists('thrift_protocol_write_binary')) {
+            thrift_protocol_write_binary(
+                $protocol,
+                $object->getName(),
+                TMessageType::REPLY,
+                $object,
+                0,
+                $protocol->isStrictWrite()
+            );
+
+            $protocol->readMessageBegin($unused_name, $unused_type, $unused_seqid);
+        } else {
+            $object->write($protocol);
+        }
+        $protocol->getTransport()->flush();
+
+        return $transport->getBuffer();
+    }
+
+    public static function deserialize($string_object, $class_name, $buffer_size = 8192)
+    {
+        $transport = new TMemoryBuffer();
+        $protocol = new TBinaryProtocolAccelerated($transport);
+        if (function_exists('thrift_protocol_read_binary')) {
+            // NOTE (t.heintz) TBinaryProtocolAccelerated internally wraps our TMemoryBuffer in a
+            // TBufferedTransport, so we have to retrieve it again or risk losing data when writing
+            // less than 512 bytes to the transport (see the comment there as well).
+            // @see THRIFT-1579
+            $protocol->writeMessageBegin('', TMessageType::REPLY, 0);
+            $protocolTransport = $protocol->getTransport();
+            $protocolTransport->write($string_object);
+            $protocolTransport->flush();
+
+            return thrift_protocol_read_binary($protocol, $class_name, $protocol->isStrictRead(), $buffer_size);
+        } else {
+            $transport->write($string_object);
+            $object = new $class_name();
+            $object->read($protocol);
+
+            return $object;
+        }
+    }
+}
diff --git a/lib/php/lib/Server/TForkingServer.php b/lib/php/lib/Server/TForkingServer.php
new file mode 100644
index 0000000..0bb6e91
--- /dev/null
+++ b/lib/php/lib/Server/TForkingServer.php
@@ -0,0 +1,125 @@
+<?php
+
+namespace Thrift\Server;
+
+use Thrift\Transport\TTransport;
+use Thrift\Exception\TException;
+use Thrift\Exception\TTransportException;
+
+/**
+ * A forking implementation of a Thrift server.
+ *
+ * @package thrift.server
+ */
+class TForkingServer extends TServer
+{
+    /**
+     * Flag for the main serving loop
+     *
+     * @var bool
+     */
+    private $stop_ = false;
+
+    /**
+     * List of children.
+     *
+     * @var array
+     */
+    protected $children_ = array();
+
+    /**
+     * Listens for new client using the supplied
+     * transport. We fork when a new connection
+     * arrives.
+     *
+     * @return void
+     */
+    public function serve()
+    {
+        $this->transport_->listen();
+
+        while (!$this->stop_) {
+            try {
+                $transport = $this->transport_->accept();
+
+                if ($transport != null) {
+                    $pid = pcntl_fork();
+
+                    if ($pid > 0) {
+                        $this->handleParent($transport, $pid);
+                    } elseif ($pid === 0) {
+                        $this->handleChild($transport);
+                    } else {
+                        throw new TException('Failed to fork');
+                    }
+                }
+            } catch (TTransportException $e) {
+            }
+
+            $this->collectChildren();
+        }
+    }
+
+    /**
+     * Code run by the parent
+     *
+     * @param TTransport $transport
+     * @param int $pid
+     * @return void
+     */
+    private function handleParent(TTransport $transport, $pid)
+    {
+        $this->children_[$pid] = $transport;
+    }
+
+    /**
+     * Code run by the child.
+     *
+     * @param TTransport $transport
+     * @return void
+     */
+    private function handleChild(TTransport $transport)
+    {
+        try {
+            $inputTransport = $this->inputTransportFactory_->getTransport($transport);
+            $outputTransport = $this->outputTransportFactory_->getTransport($transport);
+            $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport);
+            $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport);
+            while ($this->processor_->process($inputProtocol, $outputProtocol)) {
+            }
+            @$transport->close();
+        } catch (TTransportException $e) {
+        }
+
+        exit(0);
+    }
+
+    /**
+     * Collects any children we may have
+     *
+     * @return void
+     */
+    private function collectChildren()
+    {
+        foreach ($this->children_ as $pid => $transport) {
+            if (pcntl_waitpid($pid, $status, WNOHANG) > 0) {
+                unset($this->children_[$pid]);
+                if ($transport) {
+                    @$transport->close();
+                }
+            }
+        }
+    }
+
+    /**
+     * Stops the server running. Kills the transport
+     * and then stops the main serving loop
+     *
+     * @return void
+     */
+    public function stop()
+    {
+        $this->transport_->close();
+        $this->stop_ = true;
+    }
+}
diff --git a/lib/php/lib/Server/TSSLServerSocket.php b/lib/php/lib/Server/TSSLServerSocket.php
new file mode 100644
index 0000000..ac589b7
--- /dev/null
+++ b/lib/php/lib/Server/TSSLServerSocket.php
@@ -0,0 +1,97 @@
+<?php
+/*
+ * 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.
+ *
+ */
+
+namespace Thrift\Server;
+
+use Thrift\Transport\TSSLSocket;
+
+/**
+ * Socket implementation of a server agent.
+ *
+ * @package thrift.transport
+ */
+class TSSLServerSocket extends TServerSocket
+{
+    /**
+     * Remote port
+     *
+     * @var resource
+     */
+    protected $context_ = null;
+
+    /**
+     * ServerSocket constructor
+     *
+     * @param string $host Host to listen on
+     * @param int $port Port to listen on
+     * @param resource $context Stream context
+     * @return void
+     */
+    public function __construct($host = 'localhost', $port = 9090, $context = null)
+    {
+        $ssl_host = $this->getSSLHost($host);
+        parent::__construct($ssl_host, $port);
+        $this->context_ = $context;
+    }
+
+    public function getSSLHost($host)
+    {
+        $transport_protocol_loc = strpos($host, "://");
+        if ($transport_protocol_loc === false) {
+            $host = 'ssl://' . $host;
+        }
+        return $host;
+    }
+
+    /**
+     * Opens a new socket server handle
+     *
+     * @return void
+     */
+    public function listen()
+    {
+        $this->listener_ = @stream_socket_server(
+            $this->host_ . ':' . $this->port_,
+            $errno,
+            $errstr,
+            STREAM_SERVER_BIND | STREAM_SERVER_LISTEN,
+            $this->context_
+        );
+    }
+
+    /**
+     * Implementation of accept. If not client is accepted in the given time
+     *
+     * @return TSocket
+     */
+    protected function acceptImpl()
+    {
+        $handle = @stream_socket_accept($this->listener_, $this->acceptTimeout_ / 1000.0);
+        if (!$handle) {
+            return null;
+        }
+
+        $socket = new TSSLSocket();
+        $socket->setHandle($handle);
+
+        return $socket;
+    }
+}
diff --git a/lib/php/lib/Server/TServer.php b/lib/php/lib/Server/TServer.php
new file mode 100644
index 0000000..268c378
--- /dev/null
+++ b/lib/php/lib/Server/TServer.php
@@ -0,0 +1,102 @@
+<?php
+
+namespace Thrift\Server;
+
+use Thrift\Factory\TTransportFactory;
+use Thrift\Factory\TProtocolFactory;
+
+/**
+ * Generic class for a Thrift server.
+ *
+ * @package thrift.server
+ */
+abstract class TServer
+{
+    /**
+     * Processor to handle new clients
+     *
+     * @var TProcessor
+     */
+    protected $processor_;
+
+    /**
+     * Server transport to be used for listening
+     * and accepting new clients
+     *
+     * @var TServerTransport
+     */
+    protected $transport_;
+
+    /**
+     * Input transport factory
+     *
+     * @var TTransportFactory
+     */
+    protected $inputTransportFactory_;
+
+    /**
+     * Output transport factory
+     *
+     * @var TTransportFactory
+     */
+    protected $outputTransportFactory_;
+
+    /**
+     * Input protocol factory
+     *
+     * @var TProtocolFactory
+     */
+    protected $inputProtocolFactory_;
+
+    /**
+     * Output protocol factory
+     *
+     * @var TProtocolFactory
+     */
+    protected $outputProtocolFactory_;
+
+    /**
+     * Sets up all the factories, etc
+     *
+     * @param object $processor
+     * @param TServerTransport $transport
+     * @param TTransportFactory $inputTransportFactory
+     * @param TTransportFactory $outputTransportFactory
+     * @param TProtocolFactory $inputProtocolFactory
+     * @param TProtocolFactory $outputProtocolFactory
+     * @return void
+     */
+    public function __construct(
+        $processor,
+        TServerTransport $transport,
+        TTransportFactory $inputTransportFactory,
+        TTransportFactory $outputTransportFactory,
+        TProtocolFactory $inputProtocolFactory,
+        TProtocolFactory $outputProtocolFactory
+    ) {
+        $this->processor_ = $processor;
+        $this->transport_ = $transport;
+        $this->inputTransportFactory_ = $inputTransportFactory;
+        $this->outputTransportFactory_ = $outputTransportFactory;
+        $this->inputProtocolFactory_ = $inputProtocolFactory;
+        $this->outputProtocolFactory_ = $outputProtocolFactory;
+    }
+
+    /**
+     * Serves the server. This should never return
+     * unless a problem permits it to do so or it
+     * is interrupted intentionally
+     *
+     * @abstract
+     * @return void
+     */
+    abstract public function serve();
+
+    /**
+     * Stops the server serving
+     *
+     * @abstract
+     * @return void
+     */
+    abstract public function stop();
+}
diff --git a/lib/php/lib/Server/TServerSocket.php b/lib/php/lib/Server/TServerSocket.php
new file mode 100644
index 0000000..8f38fb2
--- /dev/null
+++ b/lib/php/lib/Server/TServerSocket.php
@@ -0,0 +1,124 @@
+<?php
+/*
+ * 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.transport
+ */
+
+namespace Thrift\Server;
+
+use Thrift\Transport\TSocket;
+
+/**
+ * Socket implementation of a server agent.
+ *
+ * @package thrift.transport
+ */
+class TServerSocket extends TServerTransport
+{
+    /**
+     * Handle for the listener socket
+     *
+     * @var resource
+     */
+    protected $listener_;
+
+    /**
+     * Port for the listener to listen on
+     *
+     * @var int
+     */
+    protected $port_;
+
+    /**
+     * Timeout when listening for a new client
+     *
+     * @var int
+     */
+    protected $acceptTimeout_ = 30000;
+
+    /**
+     * Host to listen on
+     *
+     * @var string
+     */
+    protected $host_;
+
+    /**
+     * ServerSocket constructor
+     *
+     * @param string $host Host to listen on
+     * @param int $port Port to listen on
+     * @return void
+     */
+    public function __construct($host = 'localhost', $port = 9090)
+    {
+        $this->host_ = $host;
+        $this->port_ = $port;
+    }
+
+    /**
+     * Sets the accept timeout
+     *
+     * @param int $acceptTimeout
+     * @return void
+     */
+    public function setAcceptTimeout($acceptTimeout)
+    {
+        $this->acceptTimeout_ = $acceptTimeout;
+    }
+
+    /**
+     * Opens a new socket server handle
+     *
+     * @return void
+     */
+    public function listen()
+    {
+        $this->listener_ = stream_socket_server('tcp://' . $this->host_ . ':' . $this->port_);
+    }
+
+    /**
+     * Closes the socket server handle
+     *
+     * @return void
+     */
+    public function close()
+    {
+        @fclose($this->listener_);
+        $this->listener_ = null;
+    }
+
+    /**
+     * Implementation of accept. If not client is accepted in the given time
+     *
+     * @return TSocket
+     */
+    protected function acceptImpl()
+    {
+        $handle = @stream_socket_accept($this->listener_, $this->acceptTimeout_ / 1000.0);
+        if (!$handle) {
+            return null;
+        }
+
+        $socket = new TSocket();
+        $socket->setHandle($handle);
+
+        return $socket;
+    }
+}
diff --git a/lib/php/lib/Server/TServerTransport.php b/lib/php/lib/Server/TServerTransport.php
new file mode 100644
index 0000000..15a27af
--- /dev/null
+++ b/lib/php/lib/Server/TServerTransport.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Thrift\Server;
+
+use Thrift\Exception\TTransportException;
+
+/**
+ * Generic class for Server agent.
+ *
+ * @package thrift.transport
+ */
+abstract class TServerTransport
+{
+    /**
+     * List for new clients
+     *
+     * @abstract
+     * @return void
+     */
+    abstract public function listen();
+
+    /**
+     * Close the server
+     *
+     * @abstract
+     * @return void
+     */
+    abstract public function close();
+
+    /**
+     * Subclasses should use this to implement
+     * accept.
+     *
+     * @abstract
+     * @return TTransport
+     */
+    abstract protected function acceptImpl();
+
+    /**
+     * Uses the accept implemtation. If null is returned, an
+     * exception is thrown.
+     *
+     * @throws TTransportException
+     * @return TTransport
+     */
+    public function accept()
+    {
+        $transport = $this->acceptImpl();
+
+        if ($transport == null) {
+            throw new TTransportException("accept() may not return NULL");
+        }
+
+        return $transport;
+    }
+}
diff --git a/lib/php/lib/Server/TSimpleServer.php b/lib/php/lib/Server/TSimpleServer.php
new file mode 100644
index 0000000..4c1dda5
--- /dev/null
+++ b/lib/php/lib/Server/TSimpleServer.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Thrift\Server;
+
+use Thrift\Exception\TTransportException;
+
+/**
+ * Simple implemtation of a Thrift server.
+ *
+ * @package thrift.server
+ */
+class TSimpleServer extends TServer
+{
+    /**
+     * Flag for the main serving loop
+     *
+     * @var bool
+     */
+    private $stop_ = false;
+
+    /**
+     * Listens for new client using the supplied
+     * transport. It handles TTransportExceptions
+     * to avoid timeouts etc killing it
+     *
+     * @return void
+     */
+    public function serve()
+    {
+        $this->transport_->listen();
+
+        while (!$this->stop_) {
+            try {
+                $transport = $this->transport_->accept();
+
+                if ($transport != null) {
+                    $inputTransport = $this->inputTransportFactory_->getTransport($transport);
+                    $outputTransport = $this->outputTransportFactory_->getTransport($transport);
+                    $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport);
+                    $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport);
+                    while ($this->processor_->process($inputProtocol, $outputProtocol)) {
+                    }
+                }
+            } catch (TTransportException $e) {
+            }
+        }
+    }
+
+    /**
+     * Stops the server running. Kills the transport
+     * and then stops the main serving loop
+     *
+     * @return void
+     */
+    public function stop()
+    {
+        $this->transport_->close();
+        $this->stop_ = true;
+    }
+}
diff --git a/lib/php/lib/StoredMessageProtocol.php b/lib/php/lib/StoredMessageProtocol.php
new file mode 100644
index 0000000..c4aaaa9
--- /dev/null
+++ b/lib/php/lib/StoredMessageProtocol.php
@@ -0,0 +1,53 @@
+<?php
+/*
+ * 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.processor
+ */
+
+namespace Thrift;
+
+use Thrift\Protocol\TProtocol;
+use Thrift\Protocol\TProtocolDecorator;
+
+/**
+ *  Our goal was to work with any protocol. In order to do that, we needed
+ *  to allow them to call readMessageBegin() and get the Message in exactly
+ *  the standard format, without the service name prepended to the Message name.
+ */
+class StoredMessageProtocol extends TProtocolDecorator
+{
+    private $fname_;
+    private $mtype_;
+    private $rseqid_;
+
+    public function __construct(TProtocol $protocol, $fname, $mtype, $rseqid)
+    {
+        parent::__construct($protocol);
+        $this->fname_  = $fname;
+        $this->mtype_  = $mtype;
+        $this->rseqid_ = $rseqid;
+    }
+
+    public function readMessageBegin(&$name, &$type, &$seqid)
+    {
+        $name  = $this->fname_;
+        $type  = $this->mtype_;
+        $seqid = $this->rseqid_;
+    }
+}
diff --git a/lib/php/lib/StringFunc/Core.php b/lib/php/lib/StringFunc/Core.php
new file mode 100644
index 0000000..39a75b3
--- /dev/null
+++ b/lib/php/lib/StringFunc/Core.php
@@ -0,0 +1,40 @@
+<?php
+/*
+ * 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.
+ *
+ */
+
+namespace Thrift\StringFunc;
+
+class Core implements TStringFunc
+{
+    public function substr($str, $start, $length = null)
+    {
+        // specifying a null $length would return an empty string
+        if ($length === null) {
+            return substr($str, $start);
+        }
+
+        return substr($str, $start, $length);
+    }
+
+    public function strlen($str)
+    {
+        return strlen($str);
+    }
+}
diff --git a/lib/php/lib/StringFunc/Mbstring.php b/lib/php/lib/StringFunc/Mbstring.php
new file mode 100644
index 0000000..968ff18
--- /dev/null
+++ b/lib/php/lib/StringFunc/Mbstring.php
@@ -0,0 +1,46 @@
+<?php
+/*
+ * 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.
+ *
+ */
+
+namespace Thrift\StringFunc;
+
+class Mbstring implements TStringFunc
+{
+    public function substr($str, $start, $length = null)
+    {
+        /**
+         * We need to set the charset parameter, which is the second
+         * optional parameter and the first optional parameter can't
+         * be null or false as a "magic" value because that would
+         * cause an empty string to be returned, so we need to
+         * actually calculate the proper length value.
+         */
+        if ($length === null) {
+            $length = $this->strlen($str) - $start;
+        }
+
+        return mb_substr($str, $start, $length, '8bit');
+    }
+
+    public function strlen($str)
+    {
+        return mb_strlen($str, '8bit');
+    }
+}
diff --git a/lib/php/lib/StringFunc/TStringFunc.php b/lib/php/lib/StringFunc/TStringFunc.php
new file mode 100644
index 0000000..dea497f
--- /dev/null
+++ b/lib/php/lib/StringFunc/TStringFunc.php
@@ -0,0 +1,28 @@
+<?php
+/*
+ * 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.
+ *
+ */
+
+namespace Thrift\StringFunc;
+
+interface TStringFunc
+{
+    public function substr($str, $start, $length = null);
+    public function strlen($str);
+}
diff --git a/lib/php/lib/TMultiplexedProcessor.php b/lib/php/lib/TMultiplexedProcessor.php
new file mode 100644
index 0000000..a64a968
--- /dev/null
+++ b/lib/php/lib/TMultiplexedProcessor.php
@@ -0,0 +1,118 @@
+<?php
+/*
+ * 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.processor
+ */
+
+namespace Thrift;
+
+use Thrift\Exception\TException;
+use Thrift\Protocol\TProtocol;
+use Thrift\Protocol\TMultiplexedProtocol;
+use Thrift\Type\TMessageType;
+
+/**
+ * <code>TMultiplexedProcessor</code> is a Processor allowing
+ * a single <code>TServer</code> to provide multiple services.
+ *
+ * <p>To do so, you instantiate the processor and then register additional
+ * processors with it, as shown in the following example:</p>
+ *
+ * <blockquote><code>
+ *     $processor = new TMultiplexedProcessor();
+ *
+ *     processor->registerProcessor(
+ *         "Calculator",
+ *         new \tutorial\CalculatorProcessor(new CalculatorHandler()));
+ *
+ *     processor->registerProcessor(
+ *         "WeatherReport",
+ *         new \tutorial\WeatherReportProcessor(new WeatherReportHandler()));
+ *
+ *     $processor->process($protocol, $protocol);
+ * </code></blockquote>
+ */
+
+class TMultiplexedProcessor
+{
+    private $serviceProcessorMap_;
+
+    /**
+     * 'Register' a service with this <code>TMultiplexedProcessor</code>.  This
+     * allows us to broker requests to individual services by using the service
+     * name to select them at request time.
+     *
+     * @param serviceName Name of a service, has to be identical to the name
+     * declared in the Thrift IDL, e.g. "WeatherReport".
+     * @param processor Implementation of a service, usually referred to
+     * as "handlers", e.g. WeatherReportHandler implementing WeatherReport.Iface.
+     */
+    public function registerProcessor($serviceName, $processor)
+    {
+        $this->serviceProcessorMap_[$serviceName] = $processor;
+    }
+
+    /**
+     * This implementation of <code>process</code> performs the following steps:
+     *
+     * <ol>
+     *     <li>Read the beginning of the message.</li>
+     *     <li>Extract the service name from the message.</li>
+     *     <li>Using the service name to locate the appropriate processor.</li>
+     *     <li>Dispatch to the processor, with a decorated instance of TProtocol
+     *         that allows readMessageBegin() to return the original Message.</li>
+     * </ol>
+     *
+     * @throws TException If the message type is not CALL or ONEWAY, if
+     *                    the service name was not found in the message, or if the service
+     *                    name was not found in the service map.
+     */
+    public function process(TProtocol $input, TProtocol $output)
+    {
+        /*
+            Use the actual underlying protocol (e.g. TBinaryProtocol) to read the
+            message header. This pulls the message "off the wire", which we'll
+            deal with at the end of this method.
+        */
+        $input->readMessageBegin($fname, $mtype, $rseqid);
+
+        if ($mtype !== TMessageType::CALL && $mtype != TMessageType::ONEWAY) {
+            throw new TException("This should not have happened!?");
+        }
+
+        // Extract the service name and the new Message name.
+        if (strpos($fname, TMultiplexedProtocol::SEPARATOR) === false) {
+            throw new TException("Service name not found in message name: {$fname}. Did you " .
+                "forget to use a TMultiplexProtocol in your client?");
+        }
+        list($serviceName, $messageName) = explode(':', $fname, 2);
+        if (!array_key_exists($serviceName, $this->serviceProcessorMap_)) {
+            throw new TException("Service name not found: {$serviceName}.  Did you forget " .
+                "to call registerProcessor()?");
+        }
+
+        // Dispatch processing to the stored processor
+        $processor = $this->serviceProcessorMap_[$serviceName];
+
+        return $processor->process(
+            new StoredMessageProtocol($input, $messageName, $mtype, $rseqid),
+            $output
+        );
+    }
+}
diff --git a/lib/php/lib/Thrift/Base/TBase.php b/lib/php/lib/Thrift/Base/TBase.php
deleted file mode 100644
index 3d5b526..0000000
--- a/lib/php/lib/Thrift/Base/TBase.php
+++ /dev/null
@@ -1,367 +0,0 @@
-<?php
-/*
- * 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
- */
-
-namespace Thrift\Base;
-
-use Thrift\Type\TType;
-
-/**
- * Base class from which other Thrift structs extend. This is so that we can
- * cut back on the size of the generated code which is turning out to have a
- * nontrivial cost just to load thanks to the wondrously abysmal implementation
- * of PHP. Note that code is intentionally duplicated in here to avoid making
- * function calls for every field or member of a container..
- */
-abstract class TBase {
-
-  static $tmethod = array(TType::BOOL   => 'Bool',
-                          TType::BYTE   => 'Byte',
-                          TType::I16    => 'I16',
-                          TType::I32    => 'I32',
-                          TType::I64    => 'I64',
-                          TType::DOUBLE => 'Double',
-                          TType::STRING => 'String');
-
-  abstract function read($input);
-
-  abstract function write($output);
-
-  public function __construct($spec=null, $vals=null) {
-    if (is_array($spec) && is_array($vals)) {
-      foreach ($spec as $fid => $fspec) {
-        $var = $fspec['var'];
-        if (isset($vals[$var])) {
-          $this->$var = $vals[$var];
-        }
-      }
-    }
-  }
-
-  public function __wakeup()
-  {
-    $this->__construct(get_object_vars($this));
-  }
-
-  private function _readMap(&$var, $spec, $input) {
-    $xfer = 0;
-    $ktype = $spec['ktype'];
-    $vtype = $spec['vtype'];
-    $kread = $vread = null;
-    if (isset(TBase::$tmethod[$ktype])) {
-      $kread = 'read'.TBase::$tmethod[$ktype];
-    } else {
-      $kspec = $spec['key'];
-    }
-    if (isset(TBase::$tmethod[$vtype])) {
-      $vread = 'read'.TBase::$tmethod[$vtype];
-    } else {
-      $vspec = $spec['val'];
-    }
-    $var = array();
-    $_ktype = $_vtype = $size = 0;
-    $xfer += $input->readMapBegin($_ktype, $_vtype, $size);
-    for ($i = 0; $i < $size; ++$i) {
-      $key = $val = null;
-      if ($kread !== null) {
-        $xfer += $input->$kread($key);
-      } else {
-        switch ($ktype) {
-        case TType::STRUCT:
-          $class = $kspec['class'];
-          $key = new $class();
-          $xfer += $key->read($input);
-          break;
-        case TType::MAP:
-          $xfer += $this->_readMap($key, $kspec, $input);
-          break;
-        case TType::LST:
-          $xfer += $this->_readList($key, $kspec, $input, false);
-          break;
-        case TType::SET:
-          $xfer += $this->_readList($key, $kspec, $input, true);
-          break;
-        }
-      }
-      if ($vread !== null) {
-        $xfer += $input->$vread($val);
-      } else {
-        switch ($vtype) {
-        case TType::STRUCT:
-          $class = $vspec['class'];
-          $val = new $class();
-          $xfer += $val->read($input);
-          break;
-        case TType::MAP:
-          $xfer += $this->_readMap($val, $vspec, $input);
-          break;
-        case TType::LST:
-          $xfer += $this->_readList($val, $vspec, $input, false);
-          break;
-        case TType::SET:
-          $xfer += $this->_readList($val, $vspec, $input, true);
-          break;
-        }
-      }
-      $var[$key] = $val;
-    }
-    $xfer += $input->readMapEnd();
-    return $xfer;
-  }
-
-  private function _readList(&$var, $spec, $input, $set=false) {
-    $xfer = 0;
-    $etype = $spec['etype'];
-    $eread = $vread = null;
-    if (isset(TBase::$tmethod[$etype])) {
-      $eread = 'read'.TBase::$tmethod[$etype];
-    } else {
-      $espec = $spec['elem'];
-    }
-    $var = array();
-    $_etype = $size = 0;
-    if ($set) {
-      $xfer += $input->readSetBegin($_etype, $size);
-    } else {
-      $xfer += $input->readListBegin($_etype, $size);
-    }
-    for ($i = 0; $i < $size; ++$i) {
-      $elem = null;
-      if ($eread !== null) {
-        $xfer += $input->$eread($elem);
-      } else {
-        $espec = $spec['elem'];
-        switch ($etype) {
-        case TType::STRUCT:
-          $class = $espec['class'];
-          $elem = new $class();
-          $xfer += $elem->read($input);
-          break;
-        case TType::MAP:
-          $xfer += $this->_readMap($elem, $espec, $input);
-          break;
-        case TType::LST:
-          $xfer += $this->_readList($elem, $espec, $input, false);
-          break;
-        case TType::SET:
-          $xfer += $this->_readList($elem, $espec, $input, true);
-          break;
-        }
-      }
-      if ($set) {
-        $var[$elem] = true;
-      } else {
-        $var []= $elem;
-      }
-    }
-    if ($set) {
-      $xfer += $input->readSetEnd();
-    } else {
-      $xfer += $input->readListEnd();
-    }
-    return $xfer;
-  }
-
-  protected function _read($class, $spec, $input) {
-    $xfer = 0;
-    $fname = null;
-    $ftype = 0;
-    $fid = 0;
-    $xfer += $input->readStructBegin($fname);
-    while (true) {
-      $xfer += $input->readFieldBegin($fname, $ftype, $fid);
-      if ($ftype == TType::STOP) {
-        break;
-      }
-      if (isset($spec[$fid])) {
-        $fspec = $spec[$fid];
-        $var = $fspec['var'];
-        if ($ftype == $fspec['type']) {
-          $xfer = 0;
-          if (isset(TBase::$tmethod[$ftype])) {
-            $func = 'read'.TBase::$tmethod[$ftype];
-            $xfer += $input->$func($this->$var);
-          } else {
-            switch ($ftype) {
-            case TType::STRUCT:
-              $class = $fspec['class'];
-              $this->$var = new $class();
-              $xfer += $this->$var->read($input);
-              break;
-            case TType::MAP:
-              $xfer += $this->_readMap($this->$var, $fspec, $input);
-              break;
-            case TType::LST:
-              $xfer += $this->_readList($this->$var, $fspec, $input, false);
-              break;
-            case TType::SET:
-              $xfer += $this->_readList($this->$var, $fspec, $input, true);
-              break;
-            }
-          }
-        } else {
-          $xfer += $input->skip($ftype);
-        }
-      } else {
-        $xfer += $input->skip($ftype);
-      }
-      $xfer += $input->readFieldEnd();
-    }
-    $xfer += $input->readStructEnd();
-    return $xfer;
-  }
-
-  private function _writeMap($var, $spec, $output) {
-    $xfer = 0;
-    $ktype = $spec['ktype'];
-    $vtype = $spec['vtype'];
-    $kwrite = $vwrite = null;
-    if (isset(TBase::$tmethod[$ktype])) {
-      $kwrite = 'write'.TBase::$tmethod[$ktype];
-    } else {
-      $kspec = $spec['key'];
-    }
-    if (isset(TBase::$tmethod[$vtype])) {
-      $vwrite = 'write'.TBase::$tmethod[$vtype];
-    } else {
-      $vspec = $spec['val'];
-    }
-    $xfer += $output->writeMapBegin($ktype, $vtype, count($var));
-    foreach ($var as $key => $val) {
-      if (isset($kwrite)) {
-        $xfer += $output->$kwrite($key);
-      } else {
-        switch ($ktype) {
-        case TType::STRUCT:
-          $xfer += $key->write($output);
-          break;
-        case TType::MAP:
-          $xfer += $this->_writeMap($key, $kspec, $output);
-          break;
-        case TType::LST:
-          $xfer += $this->_writeList($key, $kspec, $output, false);
-          break;
-        case TType::SET:
-          $xfer += $this->_writeList($key, $kspec, $output, true);
-          break;
-        }
-      }
-      if (isset($vwrite)) {
-        $xfer += $output->$vwrite($val);
-      } else {
-        switch ($vtype) {
-        case TType::STRUCT:
-          $xfer += $val->write($output);
-          break;
-        case TType::MAP:
-          $xfer += $this->_writeMap($val, $vspec, $output);
-          break;
-        case TType::LST:
-          $xfer += $this->_writeList($val, $vspec, $output, false);
-          break;
-        case TType::SET:
-          $xfer += $this->_writeList($val, $vspec, $output, true);
-          break;
-        }
-      }
-    }
-    $xfer += $output->writeMapEnd();
-    return $xfer;
-  }
-
-  private function _writeList($var, $spec, $output, $set=false) {
-    $xfer = 0;
-    $etype = $spec['etype'];
-    $ewrite = null;
-    if (isset(TBase::$tmethod[$etype])) {
-      $ewrite = 'write'.TBase::$tmethod[$etype];
-    } else {
-      $espec = $spec['elem'];
-    }
-    if ($set) {
-      $xfer += $output->writeSetBegin($etype, count($var));
-    } else {
-      $xfer += $output->writeListBegin($etype, count($var));
-    }
-    foreach ($var as $key => $val) {
-      $elem = $set ? $key : $val;
-      if (isset($ewrite)) {
-        $xfer += $output->$ewrite($elem);
-      } else {
-        switch ($etype) {
-        case TType::STRUCT:
-          $xfer += $elem->write($output);
-          break;
-        case TType::MAP:
-          $xfer += $this->_writeMap($elem, $espec, $output);
-          break;
-        case TType::LST:
-          $xfer += $this->_writeList($elem, $espec, $output, false);
-          break;
-        case TType::SET:
-          $xfer += $this->_writeList($elem, $espec, $output, true);
-          break;
-        }
-      }
-    }
-    if ($set) {
-      $xfer += $output->writeSetEnd();
-    } else {
-      $xfer += $output->writeListEnd();
-    }
-    return $xfer;
-  }
-
-  protected function _write($class, $spec, $output) {
-    $xfer = 0;
-    $xfer += $output->writeStructBegin($class);
-    foreach ($spec as $fid => $fspec) {
-      $var = $fspec['var'];
-      if ($this->$var !== null) {
-        $ftype = $fspec['type'];
-        $xfer += $output->writeFieldBegin($var, $ftype, $fid);
-        if (isset(TBase::$tmethod[$ftype])) {
-          $func = 'write'.TBase::$tmethod[$ftype];
-          $xfer += $output->$func($this->$var);
-        } else {
-          switch ($ftype) {
-          case TType::STRUCT:
-            $xfer += $this->$var->write($output);
-            break;
-          case TType::MAP:
-            $xfer += $this->_writeMap($this->$var, $fspec, $output);
-            break;
-          case TType::LST:
-            $xfer += $this->_writeList($this->$var, $fspec, $output, false);
-            break;
-          case TType::SET:
-            $xfer += $this->_writeList($this->$var, $fspec, $output, true);
-            break;
-          }
-        }
-        $xfer += $output->writeFieldEnd();
-      }
-    }
-    $xfer += $output->writeFieldStop();
-    $xfer += $output->writeStructEnd();
-    return $xfer;
-  }
-}
diff --git a/lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php b/lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php
deleted file mode 100644
index bce93f5..0000000
--- a/lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php
+++ /dev/null
@@ -1,223 +0,0 @@
-<?php
-/*
- * 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.
- *
- * ClassLoader to load Thrift library and definitions
- * Inspired from UniversalClassLoader from Symfony 2 
- *
- * @package thrift.classloader
- */
-
-namespace Thrift\ClassLoader;
-
-class ThriftClassLoader
-{
-    /**
-     * Namespaces path
-     * @var array
-     */
-    protected $namespaces = array();
-
-    /**
-     * Thrift definition paths
-     * @var type
-     */
-    protected $definitions = array();
-
-    /**
-     * Do we use APC cache ?
-     * @var boolean
-     */
-    protected $apc = false;
-
-    /**
-     * APC Cache prefix
-     * @var string
-     */
-    protected $apc_prefix;
-
-    /**
-     * Set autoloader to use APC cache
-     * @param boolean $apc
-     * @param string $apc_prefix
-     */
-    public function __construct($apc = false, $apc_prefix = null)
-    {
-        $this->apc = $apc;
-        $this->apc_prefix = $apc_prefix;
-    }
-
-    /**
-     * Registers a namespace.
-     *
-     * @param string       $namespace The namespace
-     * @param array|string $paths     The location(s) of the namespace
-     */
-    public function registerNamespace($namespace, $paths)
-    {
-        $this->namespaces[$namespace] = (array) $paths;
-    }
-
-    /**
-     * Registers a Thrift definition namespace.
-     *
-     * @param string       $namespace The definition namespace
-     * @param array|string $paths     The location(s) of the definition namespace
-     */
-    public function registerDefinition($namespace, $paths)
-    {
-        $this->definitions[$namespace] = (array) $paths;
-    }
-
-    /**
-     * Registers this instance as an autoloader.
-     *
-     * @param Boolean $prepend Whether to prepend the autoloader or not
-     */
-    public function register($prepend = false)
-    {
-        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
-    }
-
-    /**
-     * Loads the given class, definition or interface.
-     *
-     * @param string $class The name of the class
-     */
-    public function loadClass($class)
-    {
-        if (
-            (true === $this->apc && ($file = $this->findFileInApc($class))) or
-            ($file = $this->findFile($class))
-        )
-        {
-            require_once $file;
-        }
-    }
-
-    /**
-     * Loads the given class or interface in APC.
-     * @param string $class The name of the class
-     * @return string
-     */
-    protected function findFileInApc($class)
-    {
-        if (false === $file = apc_fetch($this->apc_prefix.$class)) {
-            apc_store($this->apc_prefix.$class, $file = $this->findFile($class));
-        }
-
-        return $file;
-    }
-
-    /**
-     * Find class in namespaces or definitions directories
-     * @param string $class
-     * @return string
-     */
-    public function findFile($class)
-    {
-        // Remove first backslash
-        if ('\\' == $class[0])
-        {
-            $class = substr($class, 1);
-        }
-
-        if (false !== $pos = strrpos($class, '\\'))
-        {
-            // Namespaced class name
-            $namespace = substr($class, 0, $pos);
-
-            // Iterate in normal namespaces
-            foreach ($this->namespaces as $ns => $dirs)
-            {
-                //Don't interfere with other autoloaders
-                if (0 !== strpos($namespace, $ns))
-                {
-                    continue;
-                }
-
-                foreach ($dirs as $dir)
-                {
-                    $className = substr($class, $pos + 1);
-
-                    $file = $dir.DIRECTORY_SEPARATOR.
-                                 str_replace('\\', DIRECTORY_SEPARATOR, $namespace).
-                                 DIRECTORY_SEPARATOR.
-                                 $className.'.php';
-
-                    if (file_exists($file))
-                    {
-                        return $file;
-                    }
-                }
-            }
-
-            // Iterate in Thrift namespaces
-
-            // Remove first part of namespace
-            $m = explode('\\', $class);
-
-            // Ignore wrong call
-            if(count($m) <= 1)
-            {
-                return;
-            }
-
-            $class = array_pop($m);
-            $namespace = implode('\\', $m);
-
-            foreach ($this->definitions as $ns => $dirs)
-            {
-                //Don't interfere with other autoloaders
-                if (0 !== strpos($namespace, $ns))
-                {
-                    continue;
-                }
-
-                foreach ($dirs as $dir)
-                {
-                    /**
-                     * Available in service: Interface, Client, Processor, Rest
-                     * And every service methods (_.+)
-                     */
-                    if(
-                        0 === preg_match('#(.+)(if|client|processor|rest)$#i', $class, $n) and
-                        0 === preg_match('#(.+)_[a-z0-9]+_(args|result)$#i', $class, $n)
-                    )
-                    {
-                        $className = 'Types';
-                    }
-                    else
-                    {
-                        $className = $n[1];
-                    }
-
-                    $file = $dir.DIRECTORY_SEPARATOR .
-                                 str_replace('\\', DIRECTORY_SEPARATOR, $namespace) .
-                                 DIRECTORY_SEPARATOR .
-                                 $className . '.php';
-
-                    if (file_exists($file))
-                    {
-                        return $file;
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/lib/php/lib/Thrift/Exception/TApplicationException.php b/lib/php/lib/Thrift/Exception/TApplicationException.php
deleted file mode 100644
index 9081973..0000000
--- a/lib/php/lib/Thrift/Exception/TApplicationException.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-/*
- * 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
- */
-
-namespace Thrift\Exception;
-
-use Thrift\Exception\TException;
-use Thrift\Type\TType;
-
-class TApplicationException extends TException {
-  static $_TSPEC =
-    array(1 => array('var' => 'message',
-                     'type' => TType::STRING),
-          2 => array('var' => 'code',
-                     'type' => TType::I32));
-
-  const UNKNOWN = 0;
-  const UNKNOWN_METHOD = 1;
-  const INVALID_MESSAGE_TYPE = 2;
-  const WRONG_METHOD_NAME = 3;
-  const BAD_SEQUENCE_ID = 4;
-  const MISSING_RESULT = 5;
-  const INTERNAL_ERROR = 6;
-  const PROTOCOL_ERROR = 7;
-  const INVALID_TRANSFORM = 8;
-  const INVALID_PROTOCOL = 9;
-  const UNSUPPORTED_CLIENT_TYPE = 10;
-
-  function __construct($message=null, $code=0) {
-    parent::__construct($message, $code);
-  }
-
-  public function read($output) {
-    return $this->_read('TApplicationException', self::$_TSPEC, $output);
-  }
-
-  public function write($output) {
-    $xfer = 0;
-    $xfer += $output->writeStructBegin('TApplicationException');
-    if ($message = $this->getMessage()) {
-      $xfer += $output->writeFieldBegin('message', TType::STRING, 1);
-      $xfer += $output->writeString($message);
-      $xfer += $output->writeFieldEnd();
-    }
-    if ($code = $this->getCode()) {
-      $xfer += $output->writeFieldBegin('type', TType::I32, 2);
-      $xfer += $output->writeI32($code);
-      $xfer += $output->writeFieldEnd();
-    }
-    $xfer += $output->writeFieldStop();
-    $xfer += $output->writeStructEnd();
-    return $xfer;
-  }
-}
diff --git a/lib/php/lib/Thrift/Exception/TException.php b/lib/php/lib/Thrift/Exception/TException.php
deleted file mode 100644
index 8e8cd28..0000000
--- a/lib/php/lib/Thrift/Exception/TException.php
+++ /dev/null
@@ -1,369 +0,0 @@
-<?php
-/*
- * 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
- */
-
-namespace Thrift\Exception;
-
-use Thrift\Type\TType;
-use Thrift\Base\TBase;
-
-/**
- * NOTE(mcslee): This currently contains a ton of duplicated code from TBase
- * because we need to save CPU cycles and this is not yet in an extension.
- * Ideally we'd multiply-inherit TException from both Exception and Base, but
- * that's not possible in PHP and there are no modules either, so for now we
- * apologetically take a trip to HackTown.
- *
- * Can be called with standard Exception constructor (message, code) or with
- * Thrift Base object constructor (spec, vals).
- *
- * @param mixed $p1 Message (string) or type-spec (array)
- * @param mixed $p2 Code (integer) or values (array)
- */
-class TException extends \Exception {
-  function __construct($p1=null, $p2=0) {
-    if (is_array($p1) && is_array($p2)) {
-      $spec = $p1;
-      $vals = $p2;
-      foreach ($spec as $fid => $fspec) {
-        $var = $fspec['var'];
-        if (isset($vals[$var])) {
-          $this->$var = $vals[$var];
-        }
-      }
-    } else {
-      parent::__construct($p1, $p2);
-    }
-  }
-
-  static $tmethod = array(TType::BOOL   => 'Bool',
-                          TType::BYTE   => 'Byte',
-                          TType::I16    => 'I16',
-                          TType::I32    => 'I32',
-                          TType::I64    => 'I64',
-                          TType::DOUBLE => 'Double',
-                          TType::STRING => 'String');
-
-  private function _readMap(&$var, $spec, $input) {
-    $xfer = 0;
-    $ktype = $spec['ktype'];
-    $vtype = $spec['vtype'];
-    $kread = $vread = null;
-    if (isset(TBase::$tmethod[$ktype])) {
-      $kread = 'read'.TBase::$tmethod[$ktype];
-    } else {
-      $kspec = $spec['key'];
-    }
-    if (isset(TBase::$tmethod[$vtype])) {
-      $vread = 'read'.TBase::$tmethod[$vtype];
-    } else {
-      $vspec = $spec['val'];
-    }
-    $var = array();
-    $_ktype = $_vtype = $size = 0;
-    $xfer += $input->readMapBegin($_ktype, $_vtype, $size);
-    for ($i = 0; $i < $size; ++$i) {
-      $key = $val = null;
-      if ($kread !== null) {
-        $xfer += $input->$kread($key);
-      } else {
-        switch ($ktype) {
-        case TType::STRUCT:
-          $class = $kspec['class'];
-          $key = new $class();
-          $xfer += $key->read($input);
-          break;
-        case TType::MAP:
-          $xfer += $this->_readMap($key, $kspec, $input);
-          break;
-        case TType::LST:
-          $xfer += $this->_readList($key, $kspec, $input, false);
-          break;
-        case TType::SET:
-          $xfer += $this->_readList($key, $kspec, $input, true);
-          break;
-        }
-      }
-      if ($vread !== null) {
-        $xfer += $input->$vread($val);
-      } else {
-        switch ($vtype) {
-        case TType::STRUCT:
-          $class = $vspec['class'];
-          $val = new $class();
-          $xfer += $val->read($input);
-          break;
-        case TType::MAP:
-          $xfer += $this->_readMap($val, $vspec, $input);
-          break;
-        case TType::LST:
-          $xfer += $this->_readList($val, $vspec, $input, false);
-          break;
-        case TType::SET:
-          $xfer += $this->_readList($val, $vspec, $input, true);
-          break;
-        }
-      }
-      $var[$key] = $val;
-    }
-    $xfer += $input->readMapEnd();
-    return $xfer;
-  }
-
-  private function _readList(&$var, $spec, $input, $set=false) {
-    $xfer = 0;
-    $etype = $spec['etype'];
-    $eread = $vread = null;
-    if (isset(TBase::$tmethod[$etype])) {
-      $eread = 'read'.TBase::$tmethod[$etype];
-    } else {
-      $espec = $spec['elem'];
-    }
-    $var = array();
-    $_etype = $size = 0;
-    if ($set) {
-      $xfer += $input->readSetBegin($_etype, $size);
-    } else {
-      $xfer += $input->readListBegin($_etype, $size);
-    }
-    for ($i = 0; $i < $size; ++$i) {
-      $elem = null;
-      if ($eread !== null) {
-        $xfer += $input->$eread($elem);
-      } else {
-        $espec = $spec['elem'];
-        switch ($etype) {
-        case TType::STRUCT:
-          $class = $espec['class'];
-          $elem = new $class();
-          $xfer += $elem->read($input);
-          break;
-        case TType::MAP:
-          $xfer += $this->_readMap($elem, $espec, $input);
-          break;
-        case TType::LST:
-          $xfer += $this->_readList($elem, $espec, $input, false);
-          break;
-        case TType::SET:
-          $xfer += $this->_readList($elem, $espec, $input, true);
-          break;
-        }
-      }
-      if ($set) {
-        $var[$elem] = true;
-      } else {
-        $var []= $elem;
-      }
-    }
-    if ($set) {
-      $xfer += $input->readSetEnd();
-    } else {
-      $xfer += $input->readListEnd();
-    }
-    return $xfer;
-  }
-
-  protected function _read($class, $spec, $input) {
-    $xfer = 0;
-    $fname = null;
-    $ftype = 0;
-    $fid = 0;
-    $xfer += $input->readStructBegin($fname);
-    while (true) {
-      $xfer += $input->readFieldBegin($fname, $ftype, $fid);
-      if ($ftype == TType::STOP) {
-        break;
-      }
-      if (isset($spec[$fid])) {
-        $fspec = $spec[$fid];
-        $var = $fspec['var'];
-        if ($ftype == $fspec['type']) {
-          $xfer = 0;
-          if (isset(TBase::$tmethod[$ftype])) {
-            $func = 'read'.TBase::$tmethod[$ftype];
-            $xfer += $input->$func($this->$var);
-          } else {
-            switch ($ftype) {
-            case TType::STRUCT:
-              $class = $fspec['class'];
-              $this->$var = new $class();
-              $xfer += $this->$var->read($input);
-              break;
-            case TType::MAP:
-              $xfer += $this->_readMap($this->$var, $fspec, $input);
-              break;
-            case TType::LST:
-              $xfer += $this->_readList($this->$var, $fspec, $input, false);
-              break;
-            case TType::SET:
-              $xfer += $this->_readList($this->$var, $fspec, $input, true);
-              break;
-            }
-          }
-        } else {
-          $xfer += $input->skip($ftype);
-        }
-      } else {
-        $xfer += $input->skip($ftype);
-      }
-      $xfer += $input->readFieldEnd();
-    }
-    $xfer += $input->readStructEnd();
-    return $xfer;
-  }
-
-  private function _writeMap($var, $spec, $output) {
-    $xfer = 0;
-    $ktype = $spec['ktype'];
-    $vtype = $spec['vtype'];
-    $kwrite = $vwrite = null;
-    if (isset(TBase::$tmethod[$ktype])) {
-      $kwrite = 'write'.TBase::$tmethod[$ktype];
-    } else {
-      $kspec = $spec['key'];
-    }
-    if (isset(TBase::$tmethod[$vtype])) {
-      $vwrite = 'write'.TBase::$tmethod[$vtype];
-    } else {
-      $vspec = $spec['val'];
-    }
-    $xfer += $output->writeMapBegin($ktype, $vtype, count($var));
-    foreach ($var as $key => $val) {
-      if (isset($kwrite)) {
-        $xfer += $output->$kwrite($key);
-      } else {
-        switch ($ktype) {
-        case TType::STRUCT:
-          $xfer += $key->write($output);
-          break;
-        case TType::MAP:
-          $xfer += $this->_writeMap($key, $kspec, $output);
-          break;
-        case TType::LST:
-          $xfer += $this->_writeList($key, $kspec, $output, false);
-          break;
-        case TType::SET:
-          $xfer += $this->_writeList($key, $kspec, $output, true);
-          break;
-        }
-      }
-      if (isset($vwrite)) {
-        $xfer += $output->$vwrite($val);
-      } else {
-        switch ($vtype) {
-        case TType::STRUCT:
-          $xfer += $val->write($output);
-          break;
-        case TType::MAP:
-          $xfer += $this->_writeMap($val, $vspec, $output);
-          break;
-        case TType::LST:
-          $xfer += $this->_writeList($val, $vspec, $output, false);
-          break;
-        case TType::SET:
-          $xfer += $this->_writeList($val, $vspec, $output, true);
-          break;
-        }
-      }
-    }
-    $xfer += $output->writeMapEnd();
-    return $xfer;
-  }
-
-  private function _writeList($var, $spec, $output, $set=false) {
-    $xfer = 0;
-    $etype = $spec['etype'];
-    $ewrite = null;
-    if (isset(TBase::$tmethod[$etype])) {
-      $ewrite = 'write'.TBase::$tmethod[$etype];
-    } else {
-      $espec = $spec['elem'];
-    }
-    if ($set) {
-      $xfer += $output->writeSetBegin($etype, count($var));
-    } else {
-      $xfer += $output->writeListBegin($etype, count($var));
-    }
-    foreach ($var as $key => $val) {
-      $elem = $set ? $key : $val;
-      if (isset($ewrite)) {
-        $xfer += $output->$ewrite($elem);
-      } else {
-        switch ($etype) {
-        case TType::STRUCT:
-          $xfer += $elem->write($output);
-          break;
-        case TType::MAP:
-          $xfer += $this->_writeMap($elem, $espec, $output);
-          break;
-        case TType::LST:
-          $xfer += $this->_writeList($elem, $espec, $output, false);
-          break;
-        case TType::SET:
-          $xfer += $this->_writeList($elem, $espec, $output, true);
-          break;
-        }
-      }
-    }
-    if ($set) {
-      $xfer += $output->writeSetEnd();
-    } else {
-      $xfer += $output->writeListEnd();
-    }
-    return $xfer;
-  }
-
-  protected function _write($class, $spec, $output) {
-    $xfer = 0;
-    $xfer += $output->writeStructBegin($class);
-    foreach ($spec as $fid => $fspec) {
-      $var = $fspec['var'];
-      if ($this->$var !== null) {
-        $ftype = $fspec['type'];
-        $xfer += $output->writeFieldBegin($var, $ftype, $fid);
-        if (isset(TBase::$tmethod[$ftype])) {
-          $func = 'write'.TBase::$tmethod[$ftype];
-          $xfer += $output->$func($this->$var);
-        } else {
-          switch ($ftype) {
-          case TType::STRUCT:
-            $xfer += $this->$var->write($output);
-            break;
-          case TType::MAP:
-            $xfer += $this->_writeMap($this->$var, $fspec, $output);
-            break;
-          case TType::LST:
-            $xfer += $this->_writeList($this->$var, $fspec, $output, false);
-            break;
-          case TType::SET:
-            $xfer += $this->_writeList($this->$var, $fspec, $output, true);
-            break;
-          }
-        }
-        $xfer += $output->writeFieldEnd();
-      }
-    }
-    $xfer += $output->writeFieldStop();
-    $xfer += $output->writeStructEnd();
-    return $xfer;
-  }
-
-}
diff --git a/lib/php/lib/Thrift/Exception/TProtocolException.php b/lib/php/lib/Thrift/Exception/TProtocolException.php
deleted file mode 100644
index 98a8d9d..0000000
--- a/lib/php/lib/Thrift/Exception/TProtocolException.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-/*
- * 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.protocol
- * @author: rmarin (marin.radu@facebook.com)
- */
-
-namespace Thrift\Exception;
-
-use Thrift\Exception\TException;
-
-/**
- * Protocol module. Contains all the types and definitions needed to implement
- * a protocol encoder/decoder.
- *
- * @package thrift.protocol
- */
-
-/**
- * Protocol exceptions
- */
-class TProtocolException extends TException {
-  const UNKNOWN = 0;
-  const INVALID_DATA = 1;
-  const NEGATIVE_SIZE = 2;
-  const SIZE_LIMIT = 3;
-  const BAD_VERSION = 4;
-
-  function __construct($message=null, $code=0) {
-    parent::__construct($message, $code);
-  }
-}
diff --git a/lib/php/lib/Thrift/Exception/TTransportException.php b/lib/php/lib/Thrift/Exception/TTransportException.php
deleted file mode 100644
index f467eb9..0000000
--- a/lib/php/lib/Thrift/Exception/TTransportException.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-/*
- * 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.transport
- */
-
-namespace Thrift\Exception;
-
-use Thrift\Exception\TException;
-
-/**
- * Transport exceptions
- */
-class TTransportException extends TException {
-
-  const UNKNOWN = 0;
-  const NOT_OPEN = 1;
-  const ALREADY_OPEN = 2;
-  const TIMED_OUT = 3;
-  const END_OF_FILE = 4;
-
-  function __construct($message=null, $code=0) {
-    parent::__construct($message, $code);
-  }
-}
\ No newline at end of file
diff --git a/lib/php/lib/Thrift/Factory/TBinaryProtocolFactory.php b/lib/php/lib/Thrift/Factory/TBinaryProtocolFactory.php
deleted file mode 100644
index 85da567..0000000
--- a/lib/php/lib/Thrift/Factory/TBinaryProtocolFactory.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-/*
- * 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.protocol
- */
-
-namespace Thrift\Factory;
-
-use Thrift\Factory\TProtocolFactory;
-use Thrift\Protocol\TBinaryProtocol;
-
-/**
- * Binary Protocol Factory
- */
-class TBinaryProtocolFactory implements TProtocolFactory {
-  private $strictRead_ = false;
-  private $strictWrite_ = false;
-
-  public function __construct($strictRead=false, $strictWrite=false) {
-    $this->strictRead_ = $strictRead;
-    $this->strictWrite_ = $strictWrite;
-  }
-
-  public function getProtocol($trans) {
-    return new TBinaryProtocol($trans, $this->strictRead_, $this->strictWrite_);
-  }
-}
\ No newline at end of file
diff --git a/lib/php/lib/Thrift/Factory/TCompactProtocolFactory.php b/lib/php/lib/Thrift/Factory/TCompactProtocolFactory.php
deleted file mode 100644
index 9f972aa..0000000
--- a/lib/php/lib/Thrift/Factory/TCompactProtocolFactory.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-/*
- * 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.protocol
- */
-
-namespace Thrift\Factory;
-
-use Thrift\Factory\TProtocolFactory;
-use Thrift\Protocol\TCompactProtocol;
-
-/**
- * Compact Protocol Factory
- */
-class TCompactProtocolFactory implements TProtocolFactory {
-
-  public function __construct() {
-  }
-
-  public function getProtocol($trans) {
-    return new TCompactProtocol($trans);
-  }
-}
\ No newline at end of file
diff --git a/lib/php/lib/Thrift/Factory/TJSONProtocolFactory.php b/lib/php/lib/Thrift/Factory/TJSONProtocolFactory.php
deleted file mode 100644
index 27e4391..0000000
--- a/lib/php/lib/Thrift/Factory/TJSONProtocolFactory.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-/*
- * 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.protocol
- */
-
-namespace Thrift\Factory;
-
-use Thrift\Factory\TProtocolFactory;
-use Thrift\Protocol\TJSONProtocol;
-
-/**
- * JSON Protocol Factory
- */
-class TJSONProtocolFactory implements TProtocolFactory
-{
-    public function __construct()
-    {
-    }
-
-    public function getProtocol($trans)
-    {
-        return new TJSONProtocol($trans);
-    }
-}
diff --git a/lib/php/lib/Thrift/Factory/TProtocolFactory.php b/lib/php/lib/Thrift/Factory/TProtocolFactory.php
deleted file mode 100644
index 6b322eb..0000000
--- a/lib/php/lib/Thrift/Factory/TProtocolFactory.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-/*
- * 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.protocol
- */
-
-namespace Thrift\Factory;
-
-/**
- * Protocol factory creates protocol objects from transports
- */
-interface TProtocolFactory {
-  /**
-   * Build a protocol from the base transport
-   *
-   * @return Thrift\Protocol\TProtocol protocol
-   */
-  public function getProtocol($trans);
-}
diff --git a/lib/php/lib/Thrift/Factory/TStringFuncFactory.php b/lib/php/lib/Thrift/Factory/TStringFuncFactory.php
deleted file mode 100644
index edc3649..0000000
--- a/lib/php/lib/Thrift/Factory/TStringFuncFactory.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-/*
- * 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.
- *
- */
-
-namespace Thrift\Factory;
-
-use Thrift\StringFunc\Mbstring;
-use Thrift\StringFunc\Core;
-
-class TStringFuncFactory {
-    private static $_instance;
-
-    /**
-     * Get the Singleton instance of TStringFunc implementation that is
-     * compatible with the current system's mbstring.func_overload settings.
-     *
-     * @return TStringFunc
-     */
-    public static function create() {
-        if(!self::$_instance) {
-            self::_setInstance();
-        }
-
-        return self::$_instance;
-    }
-
-    private static function _setInstance() {
-        /**
-         * Cannot use str* functions for byte counting because multibyte
-         * characters will be read a single bytes.
-         *
-         * See: http://us.php.net/manual/en/mbstring.overload.php
-         */
-        if(ini_get('mbstring.func_overload') & 2) {
-            self::$_instance = new Mbstring();
-        }
-        /**
-         * mbstring is not installed or does not have function overloading
-         * of the str* functions enabled so use PHP core str* functions for
-         * byte counting.
-         */
-        else {
-            self::$_instance = new Core();
-        }
-    }
-}
\ No newline at end of file
diff --git a/lib/php/lib/Thrift/Factory/TTransportFactory.php b/lib/php/lib/Thrift/Factory/TTransportFactory.php
deleted file mode 100644
index f3ae123..0000000
--- a/lib/php/lib/Thrift/Factory/TTransportFactory.php
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-
-namespace Thrift\Factory;
-
-use Thrift\Transport\TTransport;
-
-class TTransportFactory {
-  /**
-   * @static
-   * @param TTransport $transport
-   * @return TTransport
-   */
-  public static function getTransport(TTransport $transport) {
-    return $transport;
-  }
-}
diff --git a/lib/php/lib/Thrift/Protocol/JSON/BaseContext.php b/lib/php/lib/Thrift/Protocol/JSON/BaseContext.php
deleted file mode 100644
index e96e504..0000000
--- a/lib/php/lib/Thrift/Protocol/JSON/BaseContext.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-/*
- * 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.protocol
- */
-
-namespace Thrift\Protocol\JSON;
-
-class BaseContext
-{
-    function escapeNum()
-    {
-        return false;
-    }
-
-    function write()
-    {
-    }
-
-    function read()
-    {
-    }
-}
\ No newline at end of file
diff --git a/lib/php/lib/Thrift/Protocol/JSON/ListContext.php b/lib/php/lib/Thrift/Protocol/JSON/ListContext.php
deleted file mode 100644
index a2b75b1..0000000
--- a/lib/php/lib/Thrift/Protocol/JSON/ListContext.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-/*
- * 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.protocol
- */
-
-namespace Thrift\Protocol\JSON;
-
-use Thrift\Protocol\JSON\BaseContext;
-use Thrift\Protocol\TJSONProtocol;
-
-class ListContext extends BaseContext
-{
-    private $first_ = true;
-    private $p_;
-
-    public function __construct($p) {
-        $this->p_ = $p;
-    }
-
-    public function write() {
-        if ($this->first_) {
-            $this->first_ = false;
-        } else {
-            $this->p_->getTransport()->write(TJSONProtocol::COMMA);
-        }
-    }
-
-    public function read() {
-        if ($this->first_) {
-            $this->first_ = false;
-        } else {
-            $this->p_->readJSONSyntaxChar(TJSONProtocol::COMMA);
-        }
-    }
-}
\ No newline at end of file
diff --git a/lib/php/lib/Thrift/Protocol/JSON/LookaheadReader.php b/lib/php/lib/Thrift/Protocol/JSON/LookaheadReader.php
deleted file mode 100644
index 128b5fc..0000000
--- a/lib/php/lib/Thrift/Protocol/JSON/LookaheadReader.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-/*
- * 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.protocol
- */
-
-namespace Thrift\Protocol\JSON;
-
-class LookaheadReader
-{
-    private $hasData_ = false;
-    private $data_ = array();
-    private $p_;
-
-    public function __construct($p)
-    {
-        $this->p_ = $p;
-    }
-
-    public function read() {
-        if ($this->hasData_) {
-            $this->hasData_ = false;
-        } else {
-            $this->data_ = $this->p_->getTransport()->readAll(1);
-        }
-
-        return substr($this->data_, 0, 1);
-    }
-
-    public function peek() {
-        if (!$this->hasData_) {
-            $this->data_ = $this->p_->getTransport()->readAll(1);
-        }
-
-        $this->hasData_ = true;
-        return substr($this->data_, 0, 1);
-    }
-}
\ No newline at end of file
diff --git a/lib/php/lib/Thrift/Protocol/JSON/PairContext.php b/lib/php/lib/Thrift/Protocol/JSON/PairContext.php
deleted file mode 100644
index 1c87dd3..0000000
--- a/lib/php/lib/Thrift/Protocol/JSON/PairContext.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-/*
- * 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.protocol
- */
-
-namespace Thrift\Protocol\JSON;
-
-use Thrift\Protocol\JSON\BaseContext;
-use Thrift\Protocol\TJSONProtocol;
-
-class PairContext extends BaseContext {
-    private $first_ = true;
-    private $colon_ = true;
-    private $p_ = null;
-
-    public function __construct($p) {
-        $this->p_ = $p;
-    }
-
-    public function write() {
-        if ($this->first_) {
-            $this->first_ = false;
-            $this->colon_ = true;
-        } else {
-            $this->p_->getTransport()->write($this->colon_ ? TJSONProtocol::COLON : TJSONProtocol::COMMA);
-            $this->colon_ = !$this->colon_;
-        }
-    }
-
-    public function read() {
-        if ($this->first_) {
-            $this->first_ = false;
-            $this->colon_ = true;
-        } else {
-            $this->p_->readJSONSyntaxChar($this->colon_ ? TJSONProtocol::COLON : TJSONProtocol::COMMA);
-            $this->colon_ = !$this->colon_;
-        }
-    }
-
-    public function escapeNum() {
-        return $this->colon_;
-    }
-}
\ No newline at end of file
diff --git a/lib/php/lib/Thrift/Protocol/TBinaryProtocol.php b/lib/php/lib/Thrift/Protocol/TBinaryProtocol.php
deleted file mode 100644
index b1fddac..0000000
--- a/lib/php/lib/Thrift/Protocol/TBinaryProtocol.php
+++ /dev/null
@@ -1,396 +0,0 @@
-<?php
-/*
- * 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.protocol
- */
-
-namespace Thrift\Protocol;
-
-use Thrift\Protocol\TProtocol;
-use Thrift\Type\TType;
-use Thrift\Exception\TProtocolException;
-use Thrift\Factory\TStringFuncFactory;
-
-/**
- * Binary implementation of the Thrift protocol.
- *
- */
-class TBinaryProtocol extends TProtocol {
-
-  const VERSION_MASK = 0xffff0000;
-  const VERSION_1 = 0x80010000;
-
-  protected $strictRead_ = false;
-  protected $strictWrite_ = true;
-
-  public function __construct($trans, $strictRead=false, $strictWrite=true) {
-    parent::__construct($trans);
-    $this->strictRead_ = $strictRead;
-    $this->strictWrite_ = $strictWrite;
-  }
-
-  public function writeMessageBegin($name, $type, $seqid) {
-    if ($this->strictWrite_) {
-      $version = self::VERSION_1 | $type;
-      return
-        $this->writeI32($version) +
-        $this->writeString($name) +
-        $this->writeI32($seqid);
-    } else {
-      return
-        $this->writeString($name) +
-        $this->writeByte($type) +
-        $this->writeI32($seqid);
-    }
-  }
-
-  public function writeMessageEnd() {
-    return 0;
-  }
-
-  public function writeStructBegin($name) {
-    return 0;
-  }
-
-  public function writeStructEnd() {
-    return 0;
-  }
-
-  public function writeFieldBegin($fieldName, $fieldType, $fieldId) {
-    return
-      $this->writeByte($fieldType) +
-      $this->writeI16($fieldId);
-  }
-
-  public function writeFieldEnd() {
-    return 0;
-  }
-
-  public function writeFieldStop() {
-    return
-      $this->writeByte(TType::STOP);
-  }
-
-  public function writeMapBegin($keyType, $valType, $size) {
-    return
-      $this->writeByte($keyType) +
-      $this->writeByte($valType) +
-      $this->writeI32($size);
-  }
-
-  public function writeMapEnd() {
-    return 0;
-  }
-
-  public function writeListBegin($elemType, $size) {
-    return
-      $this->writeByte($elemType) +
-      $this->writeI32($size);
-  }
-
-  public function writeListEnd() {
-    return 0;
-  }
-
-  public function writeSetBegin($elemType, $size) {
-    return
-      $this->writeByte($elemType) +
-      $this->writeI32($size);
-  }
-
-  public function writeSetEnd() {
-    return 0;
-  }
-
-  public function writeBool($value) {
-    $data = pack('c', $value ? 1 : 0);
-    $this->trans_->write($data, 1);
-    return 1;
-  }
-
-  public function writeByte($value) {
-    $data = pack('c', $value);
-    $this->trans_->write($data, 1);
-    return 1;
-  }
-
-  public function writeI16($value) {
-    $data = pack('n', $value);
-    $this->trans_->write($data, 2);
-    return 2;
-  }
-
-  public function writeI32($value) {
-    $data = pack('N', $value);
-    $this->trans_->write($data, 4);
-    return 4;
-  }
-
-  public function writeI64($value) {
-    // If we are on a 32bit architecture we have to explicitly deal with
-    // 64-bit twos-complement arithmetic since PHP wants to treat all ints
-    // as signed and any int over 2^31 - 1 as a float
-    if (PHP_INT_SIZE == 4) {
-      $neg = $value < 0;
-
-      if ($neg) {
-        $value *= -1;
-      }
-
-      $hi = (int)($value / 4294967296);
-      $lo = (int)$value;
-
-      if ($neg) {
-        $hi = ~$hi;
-        $lo = ~$lo;
-        if (($lo & (int)0xffffffff) == (int)0xffffffff) {
-          $lo = 0;
-          $hi++;
-        } else {
-          $lo++;
-        }
-      }
-      $data = pack('N2', $hi, $lo);
-
-    } else {
-      $hi = $value >> 32;
-      $lo = $value & 0xFFFFFFFF;
-      $data = pack('N2', $hi, $lo);
-    }
-
-    $this->trans_->write($data, 8);
-    return 8;
-  }
-
-  public function writeDouble($value) {
-    $data = pack('d', $value);
-    $this->trans_->write(strrev($data), 8);
-    return 8;
-  }
-
-  public function writeString($value) {
-    $len = TStringFuncFactory::create()->strlen($value);
-    $result = $this->writeI32($len);
-    if ($len) {
-      $this->trans_->write($value, $len);
-    }
-    return $result + $len;
-  }
-
-  public function readMessageBegin(&$name, &$type, &$seqid) {
-    $result = $this->readI32($sz);
-    if ($sz < 0) {
-      $version = (int) ($sz & self::VERSION_MASK);
-      if ($version != (int) self::VERSION_1) {
-        throw new TProtocolException('Bad version identifier: '.$sz, TProtocolException::BAD_VERSION);
-      }
-      $type = $sz & 0x000000ff;
-      $result +=
-        $this->readString($name) +
-        $this->readI32($seqid);
-    } else {
-      if ($this->strictRead_) {
-        throw new TProtocolException('No version identifier, old protocol client?', TProtocolException::BAD_VERSION);
-      } else {
-        // Handle pre-versioned input
-        $name = $this->trans_->readAll($sz);
-        $result +=
-          $sz +
-          $this->readByte($type) +
-          $this->readI32($seqid);
-      }
-    }
-    return $result;
-  }
-
-  public function readMessageEnd() {
-    return 0;
-  }
-
-  public function readStructBegin(&$name) {
-    $name = '';
-    return 0;
-  }
-
-  public function readStructEnd() {
-    return 0;
-  }
-
-  public function readFieldBegin(&$name, &$fieldType, &$fieldId) {
-    $result = $this->readByte($fieldType);
-    if ($fieldType == TType::STOP) {
-      $fieldId = 0;
-      return $result;
-    }
-    $result += $this->readI16($fieldId);
-    return $result;
-  }
-
-  public function readFieldEnd() {
-    return 0;
-  }
-
-  public function readMapBegin(&$keyType, &$valType, &$size) {
-    return
-      $this->readByte($keyType) +
-      $this->readByte($valType) +
-      $this->readI32($size);
-  }
-
-  public function readMapEnd() {
-    return 0;
-  }
-
-  public function readListBegin(&$elemType, &$size) {
-    return
-      $this->readByte($elemType) +
-      $this->readI32($size);
-  }
-
-  public function readListEnd() {
-    return 0;
-  }
-
-  public function readSetBegin(&$elemType, &$size) {
-    return
-      $this->readByte($elemType) +
-      $this->readI32($size);
-  }
-
-  public function readSetEnd() {
-    return 0;
-  }
-
-  public function readBool(&$value) {
-    $data = $this->trans_->readAll(1);
-    $arr = unpack('c', $data);
-    $value = $arr[1] == 1;
-    return 1;
-  }
-
-  public function readByte(&$value) {
-    $data = $this->trans_->readAll(1);
-    $arr = unpack('c', $data);
-    $value = $arr[1];
-    return 1;
-  }
-
-  public function readI16(&$value) {
-    $data = $this->trans_->readAll(2);
-    $arr = unpack('n', $data);
-    $value = $arr[1];
-    if ($value > 0x7fff) {
-      $value = 0 - (($value - 1) ^ 0xffff);
-    }
-    return 2;
-  }
-
-  public function readI32(&$value) {
-    $data = $this->trans_->readAll(4);
-    $arr = unpack('N', $data);
-    $value = $arr[1];
-    if ($value > 0x7fffffff) {
-      $value = 0 - (($value - 1) ^ 0xffffffff);
-    }
-    return 4;
-  }
-
-  public function readI64(&$value) {
-    $data = $this->trans_->readAll(8);
-
-    $arr = unpack('N2', $data);
-
-    // If we are on a 32bit architecture we have to explicitly deal with
-    // 64-bit twos-complement arithmetic since PHP wants to treat all ints
-    // as signed and any int over 2^31 - 1 as a float
-    if (PHP_INT_SIZE == 4) {
-
-      $hi = $arr[1];
-      $lo = $arr[2];
-      $isNeg = $hi  < 0;
-
-      // Check for a negative
-      if ($isNeg) {
-        $hi = ~$hi & (int)0xffffffff;
-        $lo = ~$lo & (int)0xffffffff;
-
-        if ($lo == (int)0xffffffff) {
-          $hi++;
-          $lo = 0;
-        } else {
-          $lo++;
-        }
-      }
-
-      // Force 32bit words in excess of 2G to pe positive - we deal wigh sign
-      // explicitly below
-
-      if ($hi & (int)0x80000000) {
-        $hi &= (int)0x7fffffff;
-        $hi += 0x80000000;
-      }
-
-      if ($lo & (int)0x80000000) {
-        $lo &= (int)0x7fffffff;
-        $lo += 0x80000000;
-      }
-
-      $value = $hi * 4294967296 + $lo;
-
-      if ($isNeg) {
-        $value = 0 - $value;
-      }
-    } else {
-
-      // Upcast negatives in LSB bit
-      if ($arr[2] & 0x80000000) {
-        $arr[2] = $arr[2] & 0xffffffff;
-      }
-
-      // Check for a negative
-      if ($arr[1] & 0x80000000) {
-        $arr[1] = $arr[1] & 0xffffffff;
-        $arr[1] = $arr[1] ^ 0xffffffff;
-        $arr[2] = $arr[2] ^ 0xffffffff;
-        $value = 0 - $arr[1]*4294967296 - $arr[2] - 1;
-      } else {
-        $value = $arr[1]*4294967296 + $arr[2];
-      }
-    }
-
-    return 8;
-  }
-
-  public function readDouble(&$value) {
-    $data = strrev($this->trans_->readAll(8));
-    $arr = unpack('d', $data);
-    $value = $arr[1];
-    return 8;
-  }
-
-  public function readString(&$value) {
-    $result = $this->readI32($len);
-    if ($len) {
-      $value = $this->trans_->readAll($len);
-    } else {
-      $value = '';
-    }
-    return $result + $len;
-  }
-}
diff --git a/lib/php/lib/Thrift/Protocol/TBinaryProtocolAccelerated.php b/lib/php/lib/Thrift/Protocol/TBinaryProtocolAccelerated.php
deleted file mode 100644
index 392aa21..0000000
--- a/lib/php/lib/Thrift/Protocol/TBinaryProtocolAccelerated.php
+++ /dev/null
@@ -1,47 +0,0 @@
-<?php
-/*
- * 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.protocol
- */
-
-namespace Thrift\Protocol;
-
-use Thrift\Protocol\TBinaryProtocol;
-use Thrift\Transport\TBufferedTransport;
-
-/**
- * Accelerated binary protocol: used in conjunction with the thrift_protocol
- * extension for faster deserialization
- */
-class TBinaryProtocolAccelerated extends TBinaryProtocol {
-  public function __construct($trans, $strictRead=false, $strictWrite=true) {
-    // If the transport doesn't implement putBack, wrap it in a
-    // TBufferedTransport (which does)
-    if (!method_exists($trans, 'putBack')) {
-      $trans = new TBufferedTransport($trans);
-    }
-    parent::__construct($trans, $strictRead, $strictWrite);
-  }
-  public function isStrictRead() {
-    return $this->strictRead_;
-  }
-  public function isStrictWrite() {
-    return $this->strictWrite_;
-  }
-}
\ No newline at end of file
diff --git a/lib/php/lib/Thrift/Protocol/TCompactProtocol.php b/lib/php/lib/Thrift/Protocol/TCompactProtocol.php
deleted file mode 100644
index e637a59..0000000
--- a/lib/php/lib/Thrift/Protocol/TCompactProtocol.php
+++ /dev/null
@@ -1,669 +0,0 @@
-<?php
-/*
- * 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.protocol
- */
-
-namespace Thrift\Protocol;
-
-use Thrift\Protocol\TProtocol;
-use Thrift\Type\TType;
-use Thrift\Exception\TProtocolException;
-use Thrift\Factory\TStringFuncFactory;
-
-/**
- * Compact implementation of the Thrift protocol.
- *
- */
-class TCompactProtocol extends TProtocol {
-
-  const COMPACT_STOP = 0x00;
-  const COMPACT_TRUE = 0x01;
-  const COMPACT_FALSE = 0x02;
-  const COMPACT_BYTE = 0x03;
-  const COMPACT_I16 = 0x04;
-  const COMPACT_I32 = 0x05;
-  const COMPACT_I64 = 0x06;
-  const COMPACT_DOUBLE = 0x07;
-  const COMPACT_BINARY = 0x08;
-  const COMPACT_LIST = 0x09;
-  const COMPACT_SET = 0x0A;
-  const COMPACT_MAP = 0x0B;
-  const COMPACT_STRUCT = 0x0C;
-
-  const STATE_CLEAR = 0;
-  const STATE_FIELD_WRITE = 1;
-  const STATE_VALUE_WRITE = 2;
-  const STATE_CONTAINER_WRITE = 3;
-  const STATE_BOOL_WRITE = 4;
-  const STATE_FIELD_READ = 5;
-  const STATE_CONTAINER_READ = 6;
-  const STATE_VALUE_READ = 7;
-  const STATE_BOOL_READ = 8;
-
-  const VERSION_MASK = 0x1f;
-  const VERSION = 1;
-  const PROTOCOL_ID = 0x82;
-  const TYPE_MASK = 0xe0;
-  const TYPE_SHIFT_AMOUNT = 5;
-
-  protected static $ctypes = array(
-    TType::STOP => TCompactProtocol::COMPACT_STOP,
-    TType::BOOL => TCompactProtocol::COMPACT_TRUE, // used for collection
-    TType::BYTE => TCompactProtocol::COMPACT_BYTE,
-    TType::I16 => TCompactProtocol::COMPACT_I16,
-    TType::I32 => TCompactProtocol::COMPACT_I32,
-    TType::I64 => TCompactProtocol::COMPACT_I64,
-    TType::DOUBLE => TCompactProtocol::COMPACT_DOUBLE,
-    TType::STRING => TCompactProtocol::COMPACT_BINARY,
-    TType::STRUCT => TCompactProtocol::COMPACT_STRUCT,
-    TType::LST => TCompactProtocol::COMPACT_LIST,
-    TType::SET => TCompactProtocol::COMPACT_SET,
-    TType::MAP => TCompactProtocol::COMPACT_MAP,
-  );
-
-  protected static $ttypes = array(
-    TCompactProtocol::COMPACT_STOP => TType::STOP ,
-    TCompactProtocol::COMPACT_TRUE => TType::BOOL, // used for collection
-    TCompactProtocol::COMPACT_FALSE => TType::BOOL,
-    TCompactProtocol::COMPACT_BYTE => TType::BYTE,
-    TCompactProtocol::COMPACT_I16 => TType::I16,
-    TCompactProtocol::COMPACT_I32 => TType::I32,
-    TCompactProtocol::COMPACT_I64 => TType::I64,
-    TCompactProtocol::COMPACT_DOUBLE => TType::DOUBLE,
-    TCompactProtocol::COMPACT_BINARY => TType::STRING,
-    TCompactProtocol::COMPACT_STRUCT => TType::STRUCT,
-    TCompactProtocol::COMPACT_LIST => TType::LST,
-    TCompactProtocol::COMPACT_SET => TType::SET,
-    TCompactProtocol::COMPACT_MAP => TType::MAP,
-  );
-
-  protected $state = TCompactProtocol::STATE_CLEAR;
-  protected $lastFid = 0;
-  protected $boolFid = null;
-  protected $boolValue = null;
-  protected $structs = array();
-  protected $containers = array();
-
-  // Some varint / zigzag helper methods
-  public function toZigZag($n, $bits) {
-    return ($n << 1) ^ ($n >> ($bits - 1));
-  }
-
-  public function fromZigZag($n) {
-    return ($n >> 1) ^ -($n & 1);
-  }
-
-  public function getVarint($data) {
-    $out = "";
-    while (true) {
-      if (($data & ~0x7f) === 0) {
-        $out .= chr($data);
-        break;
-      } else {
-        $out .= chr(($data & 0xff) | 0x80);
-        $data = $data >> 7;
-      }
-    }
-    return $out;
-  }
-
-  public function writeVarint($data) {
-    $out = $this->getVarint($data);
-    $result = TStringFuncFactory::create()->strlen($out);
-    $this->trans_->write($out, $result);
-    return $result;
-  }
-
-  public function readVarint(&$result) {
-    $idx = 0;
-    $shift = 0;
-    $result = 0;
-    while (true) {
-      $x = $this->trans_->readAll(1);
-      $arr = unpack('C', $x);
-      $byte = $arr[1];
-      $idx += 1;
-      $result |= ($byte & 0x7f) << $shift;
-      if (($byte >> 7) === 0) {
-        return $idx;
-      }
-      $shift += 7;
-    }
-
-    return $idx;
-  }
-
-  public function __construct($trans) {
-    parent::__construct($trans);
-  }
-
-  public function writeMessageBegin($name, $type, $seqid) {
-    $written =
-      $this->writeUByte(TCompactProtocol::PROTOCOL_ID) +
-      $this->writeUByte(TCompactProtocol::VERSION |
-                        ($type << TCompactProtocol::TYPE_SHIFT_AMOUNT)) +
-      $this->writeVarint($seqid) +
-      $this->writeString($name);
-    $this->state = TCompactProtocol::STATE_VALUE_WRITE;
-    return $written;
-  }
-
-  public function writeMessageEnd() {
-    $this->state = TCompactProtocol::STATE_CLEAR;
-    return 0;
-  }
-
-  public function writeStructBegin($name) {
-    $this->structs[] = array($this->state, $this->lastFid);
-    $this->state = TCompactProtocol::STATE_FIELD_WRITE;
-    $this->lastFid = 0;
-    return 0;
-  }
-
-  public function writeStructEnd() {
-    $old_values = array_pop($this->structs);
-    $this->state = $old_values[0];
-    $this->lastFid = $old_values[1];
-    return 0;
-  }
-
-  public function writeFieldStop() {
-    return $this->writeByte(0);
-  }
-
-  public function writeFieldHeader($type, $fid) {
-    $written = 0;
-    $delta = $fid - $this->lastFid;
-    if (0 < $delta && $delta <= 15) {
-      $written = $this->writeUByte(($delta << 4) | $type);
-    } else {
-      $written = $this->writeByte($type) +
-        $this->writeI16($fid);
-    }
-    $this->lastFid = $fid;
-    return $written;
-  }
-
-  public function writeFieldBegin($field_name, $field_type, $field_id) {
-    if ($field_type == TTYPE::BOOL) {
-      $this->state = TCompactProtocol::STATE_BOOL_WRITE;
-      $this->boolFid = $field_id;
-      return 0;
-    } else {
-      $this->state = TCompactProtocol::STATE_VALUE_WRITE;
-      return $this->writeFieldHeader(self::$ctypes[$field_type], $field_id);
-    }
-  }
-
-  public function writeFieldEnd() {
-    $this->state = TCompactProtocol::STATE_FIELD_WRITE;
-    return 0;
-  }
-
-  public function writeCollectionBegin($etype, $size) {
-    $written = 0;
-    if ($size <= 14) {
-      $written = $this->writeUByte($size << 4 |
-                                    self::$ctypes[$etype]);
-    } else {
-      $written = $this->writeUByte(0xf0 |
-                                   self::$ctypes[$etype]) +
-        $this->writeVarint($size);
-    }
-    $this->containers[] = $this->state;
-    $this->state = TCompactProtocol::STATE_CONTAINER_WRITE;
-
-    return $written;
-  }
-
-  public function writeMapBegin($key_type, $val_type, $size) {
-    $written = 0;
-    if ($size == 0) {
-      $written = $this->writeByte(0);
-    } else {
-      $written = $this->writeVarint($size) +
-        $this->writeUByte(self::$ctypes[$key_type] << 4 |
-                          self::$ctypes[$val_type]);
-    }
-    $this->containers[] = $this->state;
-    return $written;
-  }
-
-  public function writeCollectionEnd() {
-    $this->state = array_pop($this->containers);
-    return 0;
-  }
-
-  public function writeMapEnd() {
-    return $this->writeCollectionEnd();
-  }
-
-  public function writeListBegin($elem_type, $size) {
-    return $this->writeCollectionBegin($elem_type, $size);
-  }
-
-  public function writeListEnd() {
-    return $this->writeCollectionEnd();
-  }
-
-  public function writeSetBegin($elem_type, $size) {
-    return $this->writeCollectionBegin($elem_type, $size);
-  }
-
-  public function writeSetEnd() {
-    return $this->writeCollectionEnd();
-  }
-
-  public function writeBool($value) {
-    if ($this->state == TCompactProtocol::STATE_BOOL_WRITE) {
-      $ctype = TCompactProtocol::COMPACT_FALSE;
-      if ($value) {
-        $ctype = TCompactProtocol::COMPACT_TRUE;
-      }
-      return $this->writeFieldHeader($ctype, $this->boolFid);
-    } else if ($this->state == TCompactProtocol::STATE_CONTAINER_WRITE) {
-      return $this->writeByte($value ? 1 : 0);
-    } else {
-      throw new TProtocolException('Invalid state in compact protocol');
-    }
-  }
-
-  public function writeByte($value) {
-    $data = pack('c', $value);
-    $this->trans_->write($data, 1);
-    return 1;
-  }
-
-  public function writeUByte($byte) {
-    $this->trans_->write(pack('C', $byte), 1);
-    return 1;
-  }
-
-  public function writeI16($value) {
-    $thing = $this->toZigZag($value, 16);
-    return $this->writeVarint($thing);
-  }
-
-  public function writeI32($value) {
-    $thing = $this->toZigZag($value, 32);
-    return $this->writeVarint($thing);
-  }
-
-  public function writeDouble($value) {
-    $data = pack('d', $value);
-    $this->trans_->write(strrev($data), 8);
-    return 8;
-  }
-
-  public function writeString($value) {
-    $len = TStringFuncFactory::create()->strlen($value);
-    $result = $this->writeVarint($len);
-    if ($len) {
-      $this->trans_->write($value, $len);
-    }
-    return $result + $len;
-  }
-
-  public function readFieldBegin(&$name, &$field_type, &$field_id) {
-    $result = $this->readUByte($field_type);
-
-    if (($field_type & 0x0f) == TType::STOP) {
-      $field_id = 0;
-      return $result;
-    }
-    $delta = $field_type >> 4;
-    if ($delta == 0) {
-      $result += $this->readI16($field_id);
-    } else {
-      $field_id = $this->lastFid + $delta;
-    }
-    $this->lastFid = $field_id;
-    $field_type = $this->getTType($field_type & 0x0f);
-    if ($field_type == TCompactProtocol::COMPACT_TRUE) {
-      $this->state = TCompactProtocol::STATE_BOOL_READ;
-      $this->boolValue = true;
-    } else if ($field_type == TCompactProtocol::COMPACT_FALSE) {
-      $this->state = TCompactProtocol::STATE_BOOL_READ;
-      $this->boolValue = false;
-    } else {
-      $this->state = TCompactProtocol::STATE_VALUE_READ;
-    }
-    return $result;
-  }
-
-  public function readFieldEnd() {
-    $this->state = TCompactProtocol::STATE_FIELD_READ;
-    return 0;
-  }
-
-  public function readUByte(&$value) {
-    $data = $this->trans_->readAll(1);
-    $arr = unpack('C', $data);
-    $value = $arr[1];
-    return 1;
-  }
-
-  public function readByte(&$value) {
-    $data = $this->trans_->readAll(1);
-    $arr = unpack('c', $data);
-    $value = $arr[1];
-    return 1;
-  }
-
-  public function readZigZag(&$value) {
-    $result = $this->readVarint($value);
-    $value = $this->fromZigZag($value);
-    return $result;
-  }
-
-  public function readMessageBegin(&$name, &$type, &$seqid) {
-    $protoId = 0;
-    $result = $this->readUByte($protoId);
-    if ($protoId != TCompactProtocol::PROTOCOL_ID) {
-      throw new TProtocolException('Bad protocol id in TCompact message');
-    }
-    $verType = 0;
-    $result += $this->readUByte($verType);
-    $type = ($verType & TCompactProtocol::TYPE_MASK) >>
-      TCompactProtocol::TYPE_SHIFT_AMOUNT;
-    $version = $verType & TCompactProtocol::VERSION_MASK;
-    if ($version != TCompactProtocol::VERSION) {
-      throw new TProtocolException('Bad version in TCompact message');
-    }
-    $result += $this->readVarint($seqId);
-    $name += $this->readString($name);
-
-    return $result;
-  }
-
-  public function readMessageEnd() {
-    return 0;
-  }
-
-  public function readStructBegin(&$name) {
-    $name = ''; // unused
-    $this->structs[] = array($this->state, $this->lastFid);
-    $this->state = TCompactProtocol::STATE_FIELD_READ;
-    $this->lastFid = 0;
-    return 0;
-  }
-
-  public function readStructEnd() {
-    $last = array_pop($this->structs);
-    $this->state = $last[0];
-    $this->lastFid = $last[1];
-    return 0;
-  }
-
-  public function readCollectionBegin(&$type, &$size) {
-    $sizeType = 0;
-    $result = $this->readUByte($sizeType);
-    $size = $sizeType >> 4;
-    $type = $this->getTType($sizeType);
-    if ($size == 15) {
-      $result += $this->readVarint($size);
-    }
-    $this->containers[] = $this->state;
-    $this->state = TCompactProtocol::STATE_CONTAINER_READ;
-
-    return $result;
-  }
-
-  public function readMapBegin(&$key_type, &$val_type, &$size) {
-    $result = $this->readVarint($size);
-    $types = 0;
-    if ($size > 0) {
-      $result += $this->readUByte($types);
-    }
-    $val_type = $this->getTType($types);
-    $key_type = $this->getTType($types >> 4);
-    $this->containers[] = $this->state;
-    $this->state = TCompactProtocol::STATE_CONTAINER_READ;
-
-    return $result;
-  }
-
-  public function readCollectionEnd() {
-    $this->state = array_pop($this->containers);
-    return 0;
-  }
-
-  public function readMapEnd() {
-    return $this->readCollectionEnd();
-  }
-
-  public function readListBegin(&$elem_type, &$size) {
-    return $this->readCollectionBegin($elem_type, $size);
-  }
-
-  public function readListEnd() {
-    return $this->readCollectionEnd();
-  }
-
-  public function readSetBegin(&$elem_type, &$size) {
-    return $this->readCollectionBegin($elem_type, $size);
-  }
-
-  public function readSetEnd() {
-    return $this->readCollectionEnd();
-  }
-
-  public function readBool(&$value) {
-    if ($this->state == TCompactProtocol::STATE_BOOL_READ) {
-      $value = $this->boolValue;
-      return 0;
-    } else if ($this->state == TCompactProtocol::STATE_CONTAINER_READ) {
-      return $this->readByte($value);
-    } else {
-      throw new TProtocolException('Invalid state in compact protocol');
-    }
-  }
-
-  public function readI16(&$value) {
-    return $this->readZigZag($value);
-  }
-
-  public function readI32(&$value) {
-    return $this->readZigZag($value);
-  }
-
-  public function readDouble(&$value) {
-    $data = strrev($this->trans_->readAll(8));
-    $arr = unpack('d', $data);
-    $value = $arr[1];
-    return 8;
-  }
-
-  public function readString(&$value) {
-    $result = $this->readVarint($len);
-    if ($len) {
-      $value = $this->trans_->readAll($len);
-    } else {
-      $value = '';
-    }
-    return $result + $len;
-  }
-
-  public function getTType($byte) {
-    return self::$ttypes[$byte & 0x0f];
-  }
-
-  // If we are on a 32bit architecture we have to explicitly deal with
-  // 64-bit twos-complement arithmetic since PHP wants to treat all ints
-  // as signed and any int over 2^31 - 1 as a float
-
-  // Read and write I64 as two 32 bit numbers $hi and $lo
-
-  public function readI64(&$value) {
-    // Read varint from wire
-    $hi = 0;
-    $lo = 0;
-
-    $idx = 0;
-    $shift = 0;
-
-    while (true) {
-      $x = $this->trans_->readAll(1);
-      $arr = unpack('C', $x);
-      $byte = $arr[1];
-      $idx += 1;
-      if ($shift < 32) {
-        $lo |= (($byte & 0x7f) << $shift) &
-          0x00000000ffffffff;
-      }
-      // Shift hi and lo together.
-      if ($shift >= 32) {
-        $hi |= (($byte & 0x7f) << ($shift - 32));
-      } else if ($shift > 25) {
-        $hi |= (($byte & 0x7f) >> ($shift - 25));
-      }
-      if (($byte >> 7) === 0) {
-        break;
-      }
-      $shift += 7;
-    }
-
-    // Now, unzig it.
-    $xorer = 0;
-    if ($lo & 1) {
-      $xorer = 0xffffffff;
-    }
-    $lo = ($lo >> 1) & 0x7fffffff;
-    $lo = $lo | (($hi & 1) << 31);
-    $hi = ($hi >> 1) ^ $xorer;
-    $lo = $lo ^ $xorer;
-
-    // Now put $hi and $lo back together
-    if (true) {
-      $isNeg = $hi  < 0;
-
-      // Check for a negative
-      if ($isNeg) {
-        $hi = ~$hi & (int)0xffffffff;
-        $lo = ~$lo & (int)0xffffffff;
-
-        if ($lo == (int)0xffffffff) {
-          $hi++;
-          $lo = 0;
-        } else {
-          $lo++;
-        }
-      }
-
-      // Force 32bit words in excess of 2G to be positive - we deal with sign
-      // explicitly below
-
-      if ($hi & (int)0x80000000) {
-        $hi &= (int)0x7fffffff;
-        $hi += 0x80000000;
-      }
-
-      if ($lo & (int)0x80000000) {
-        $lo &= (int)0x7fffffff;
-        $lo += 0x80000000;
-      }
-
-      $value = $hi * 4294967296 + $lo;
-
-      if ($isNeg) {
-        $value = 0 - $value;
-      }
-    } else {
-
-      // Upcast negatives in LSB bit
-      if ($arr[2] & 0x80000000) {
-        $arr[2] = $arr[2] & 0xffffffff;
-      }
-
-      // Check for a negative
-      if ($arr[1] & 0x80000000) {
-        $arr[1] = $arr[1] & 0xffffffff;
-        $arr[1] = $arr[1] ^ 0xffffffff;
-        $arr[2] = $arr[2] ^ 0xffffffff;
-        $value = 0 - $arr[1] * 4294967296 - $arr[2] - 1;
-      } else {
-        $value = $arr[1] * 4294967296 + $arr[2];
-      }
-    }
-
-    return $idx;
-  }
-
-  public function writeI64($value) {
-    // If we are in an I32 range, use the easy method below.
-    if (($value > 4294967296) || ($value < -4294967296)) {
-      // Convert $value to $hi and $lo
-      $neg = $value < 0;
-
-      if ($neg) {
-        $value *= -1;
-      }
-
-      $hi = (int)$value >> 32;
-      $lo = (int)$value & 0xffffffff;
-
-      if ($neg) {
-        $hi = ~$hi;
-        $lo = ~$lo;
-        if (($lo & (int)0xffffffff) == (int)0xffffffff) {
-          $lo = 0;
-          $hi++;
-        } else {
-          $lo++;
-        }
-      }
-
-      // Now do the zigging and zagging.
-      $xorer = 0;
-      if ($neg) {
-        $xorer = 0xffffffff;
-      }
-      $lowbit = ($lo >> 31) & 1;
-      $hi = ($hi << 1) | $lowbit;
-      $lo = ($lo << 1);
-      $lo = ($lo ^ $xorer) & 0xffffffff;
-      $hi = ($hi ^ $xorer) & 0xffffffff;
-
-      // now write out the varint, ensuring we shift both hi and lo
-      $out = "";
-      while (true) {
-        if (($lo & ~0x7f) === 0 &&
-           $hi === 0) {
-          $out .= chr($lo);
-          break;
-        } else {
-          $out .= chr(($lo & 0xff) | 0x80);
-          $lo = $lo >> 7;
-          $lo = $lo | ($hi << 25);
-          $hi = $hi >> 7;
-          // Right shift carries sign, but we don't want it to.
-          $hi = $hi & (127 << 25);
-        }
-      }
-
-      $ret = TStringFuncFactory::create()->strlen($out);
-      $this->trans_->write($out, $ret);
-
-      return $ret;
-    } else {
-      return $this->writeVarint($this->toZigZag($value, 64));
-    }
-  }
-}
diff --git a/lib/php/lib/Thrift/Protocol/TJSONProtocol.php b/lib/php/lib/Thrift/Protocol/TJSONProtocol.php
deleted file mode 100644
index 3d39583..0000000
--- a/lib/php/lib/Thrift/Protocol/TJSONProtocol.php
+++ /dev/null
@@ -1,694 +0,0 @@
-<?php
-
-/*
- * 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.protocol
- */
-
-namespace Thrift\Protocol;
-
-use Thrift\Protocol\TProtocol;
-use Thrift\Type\TType;
-use Thrift\Exception\TProtocolException;
-use Thrift\Protocol\JSON\BaseContext;
-use Thrift\Protocol\JSON\LookaheadReader;
-use Thrift\Protocol\JSON\PairContext;
-use Thrift\Protocol\JSON\ListContext;
-
-/**
- * JSON implementation of thrift protocol, ported from Java.
- */
-class TJSONProtocol extends TProtocol
-{
-    const COMMA = ',';
-    const COLON = ':';
-    const LBRACE = '{';
-    const RBRACE = '}';
-    const LBRACKET = '[';
-    const RBRACKET = ']';
-    const QUOTE = '"';
-    const BACKSLASH = '\\';
-    const ZERO = '0';
-    const ESCSEQ = '\\';
-    const DOUBLEESC = '__DOUBLE_ESCAPE_SEQUENCE__';
-
-    const VERSION = 1;
-
-    public static $JSON_CHAR_TABLE = array(
-        /*  0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F */
-        0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, // 0
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
-        1, 1, '"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
-    );
-
-    public static $ESCAPE_CHARS = array('"', '\\', "b", "f", "n", "r", "t");
-
-    public static $ESCAPE_CHAR_VALS = array(
-        '"', '\\', "\x08", "\f", "\n", "\r", "\t",
-    );
-
-    const NAME_BOOL = "tf";
-    const NAME_BYTE = "i8";
-    const NAME_I16 = "i16";
-    const NAME_I32 = "i32";
-    const NAME_I64 = "i64";
-    const NAME_DOUBLE = "dbl";
-    const NAME_STRUCT = "rec";
-    const NAME_STRING = "str";
-    const NAME_MAP = "map";
-    const NAME_LIST = "lst";
-    const NAME_SET = "set";
-
-    private function getTypeNameForTypeID($typeID)
-    {
-        switch ($typeID) {
-            case TType::BOOL:
-                return self::NAME_BOOL;
-            case TType::BYTE:
-                return self::NAME_BYTE;
-            case TType::I16:
-                return self::NAME_I16;
-            case TType::I32:
-                return self::NAME_I32;
-            case TType::I64:
-                return self::NAME_I64;
-            case TType::DOUBLE:
-                return self::NAME_DOUBLE;
-            case TType::STRING:
-                return self::NAME_STRING;
-            case TType::STRUCT:
-                return self::NAME_STRUCT;
-            case TType::MAP:
-                return self::NAME_MAP;
-            case TType::SET:
-                return self::NAME_SET;
-            case TType::LST:
-                return self::NAME_LIST;
-            default:
-                throw new TProtocolException("Unrecognized type", TProtocolException::UNKNOWN);
-        }
-    }
-
-    private function getTypeIDForTypeName($name)
-    {
-        $result = TType::STOP;
-
-        if (strlen($name) > 1) {
-            switch (substr($name, 0, 1)) {
-                case 'd':
-                    $result = TType::DOUBLE;
-                    break;
-                case 'i':
-                    switch (substr($name, 1, 1)) {
-                        case '8':
-                            $result = TType::BYTE;
-                            break;
-                        case '1':
-                            $result = TType::I16;
-                            break;
-                        case '3':
-                            $result = TType::I32;
-                            break;
-                        case '6':
-                            $result = TType::I64;
-                            break;
-                    }
-                    break;
-                case 'l':
-                    $result = TType::LST;
-                    break;
-                case 'm':
-                    $result = TType::MAP;
-                    break;
-                case 'r':
-                    $result = TType::STRUCT;
-                    break;
-                case 's':
-                    if (substr($name, 1, 1) == 't') {
-                        $result = TType::STRING;
-                    }
-                    else if (substr($name, 1, 1) == 'e') {
-                        $result = TType::SET;
-                    }
-                    break;
-                case 't':
-                    $result = TType::BOOL;
-                    break;
-            }
-        }
-        if ($result == TType::STOP) {
-            throw new TProtocolException("Unrecognized type", TProtocolException::INVALID_DATA);
-        }
-        return $result;
-    }
-
-    public $contextStack_ = array();
-    public $context_;
-    public $reader_;
-
-    private function pushContext($c) {
-        array_push($this->contextStack_, $this->context_);
-        $this->context_ = $c;
-    }
-
-    private function popContext() {
-        $this->context_ = array_pop($this->contextStack_);
-    }
-
-    public function __construct($trans) {
-        parent::__construct($trans);
-        $this->context_ = new BaseContext();
-        $this->reader_ = new LookaheadReader($this);
-    }
-
-    public function reset() {
-        $this->contextStack_ = array();
-        $this->context_ = new BaseContext();
-        $this->reader_ = new LookaheadReader($this);
-    }
-
-    private $tmpbuf_ = array(4);
-
-    public function readJSONSyntaxChar($b) {
-        $ch = $this->reader_->read();
-
-        if (substr($ch, 0, 1) != $b) {
-            throw new TProtocolException("Unexpected character: " . $ch, TProtocolException::INVALID_DATA);
-        }
-    }
-
-    private function hexVal($s) {
-        for ($i = 0; $i < strlen($s); $i++) {
-            $ch = substr($s, $i, 1);
-
-            if (!($ch >= "a" && $ch <= "f") && !($ch >= "0" && $ch <= "9")) {
-                throw new TProtocolException("Expected hex character " . $ch, TProtocolException::INVALID_DATA);
-            }
-        }
-
-        return hexdec($s);
-    }
-
-    private function hexChar($val) {
-        return dechex($val);
-    }
-
-    private function writeJSONString($b) {
-        $this->context_->write();
-
-        if (is_numeric($b) && $this->context_->escapeNum()) {
-            $this->trans_->write(self::QUOTE);
-        }
-
-        $this->trans_->write(json_encode($b));
-
-        if (is_numeric($b) && $this->context_->escapeNum()) {
-            $this->trans_->write(self::QUOTE);
-        }
-    }
-
-    private function writeJSONInteger($num) {
-        $this->context_->write();
-
-        if ($this->context_->escapeNum()) {
-            $this->trans_->write(self::QUOTE);
-        }
-
-        $this->trans_->write($num);
-
-        if ($this->context_->escapeNum()) {
-            $this->trans_->write(self::QUOTE);
-        }
-    }
-
-    private function writeJSONDouble($num) {
-        $this->context_->write();
-
-        if ($this->context_->escapeNum()) {
-            $this->trans_->write(self::QUOTE);
-        }
-
-        $this->trans_->write(json_encode($num));
-
-        if ($this->context_->escapeNum()) {
-            $this->trans_->write(self::QUOTE);
-        }
-    }
-
-    private function writeJSONBase64($data) {
-        $this->context_->write();
-        $this->trans_->write(self::QUOTE);
-        $this->trans_->write(json_encode(base64_encode($data)));
-        $this->trans_->write(self::QUOTE);
-    }
-
-    private function writeJSONObjectStart() {
-      $this->context_->write();
-      $this->trans_->write(self::LBRACE);
-      $this->pushContext(new PairContext($this));
-    }
-
-    private function writeJSONObjectEnd() {
-      $this->popContext();
-      $this->trans_->write(self::RBRACE);
-    }
-
-    private function writeJSONArrayStart() {
-      $this->context_->write();
-      $this->trans_->write(self::LBRACKET);
-      $this->pushContext(new ListContext($this));
-    }
-
-    private function writeJSONArrayEnd() {
-      $this->popContext();
-      $this->trans_->write(self::RBRACKET);
-    }
-
-    private function readJSONString($skipContext) {
-      if (!$skipContext) {
-        $this->context_->read();
-      }
-
-      $jsonString = '';
-      $lastChar = NULL;
-      while (true) {
-        $ch = $this->reader_->read();
-        $jsonString .= $ch;
-        if ($ch == self::QUOTE &&
-          $lastChar !== NULL &&
-            $lastChar !== self::ESCSEQ) {
-          break;
-        }
-        if ($ch == self::ESCSEQ && $lastChar == self::ESCSEQ) {
-          $lastChar = self::DOUBLEESC;
-        } else {
-          $lastChar = $ch;
-        }
-      }
-      return json_decode($jsonString);
-    }
-
-    private function isJSONNumeric($b) {
-        switch ($b) {
-            case '+':
-            case '-':
-            case '.':
-            case '0':
-            case '1':
-            case '2':
-            case '3':
-            case '4':
-            case '5':
-            case '6':
-            case '7':
-            case '8':
-            case '9':
-            case 'E':
-            case 'e':
-              return true;
-            }
-        return false;
-    }
-
-    private function readJSONNumericChars() {
-        $strbld = array();
-
-        while (true) {
-            $ch = $this->reader_->peek();
-
-            if (!$this->isJSONNumeric($ch)) {
-                break;
-            }
-
-            $strbld[] = $this->reader_->read();
-        }
-
-        return implode("", $strbld);
-    }
-
-    private function readJSONInteger() {
-        $this->context_->read();
-
-        if ($this->context_->escapeNum()) {
-            $this->readJSONSyntaxChar(self::QUOTE);
-        }
-
-        $str = $this->readJSONNumericChars();
-
-        if ($this->context_->escapeNum()) {
-            $this->readJSONSyntaxChar(self::QUOTE);
-        }
-
-        if (!is_numeric($str)) {
-            throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA);
-        }
-
-        return intval($str);
-    }
-
-    /**
-     * Identical to readJSONInteger but without the final cast.
-     * Needed for proper handling of i64 on 32 bit machines.  Why a
-     * separate function?  So we don't have to force the rest of the
-     * use cases through the extra conditional.
-     */
-    private function readJSONIntegerAsString() {
-        $this->context_->read();
-
-        if ($this->context_->escapeNum()) {
-            $this->readJSONSyntaxChar(self::QUOTE);
-        }
-
-        $str = $this->readJSONNumericChars();
-
-        if ($this->context_->escapeNum()) {
-            $this->readJSONSyntaxChar(self::QUOTE);
-        }
-
-        if (!is_numeric($str)) {
-            throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA);
-        }
-
-        return $str;
-    }
-
-    private function readJSONDouble() {
-        $this->context_->read();
-
-        if (substr($this->reader_->peek(), 0, 1) == self::QUOTE) {
-            $arr = $this->readJSONString(true);
-
-            if ($arr == "NaN") {
-                return NAN;
-            } else if ($arr == "Infinity") {
-                return INF;
-            } else if (!$this->context_->escapeNum()) {
-                throw new TProtocolException("Numeric data unexpectedly quoted " . $arr,
-                                              TProtocolException::INVALID_DATA);
-            }
-
-            return floatval($arr);
-        } else {
-            if ($this->context_->escapeNum()) {
-                $this->readJSONSyntaxChar(self::QUOTE);
-            }
-
-            return floatval($this->readJSONNumericChars());
-        }
-    }
-
-    private function readJSONBase64() {
-        $arr = $this->readJSONString(false);
-        $data = base64_decode($arr, true);
-
-        if ($data === false) {
-            throw new TProtocolException("Invalid base64 data " . $arr, TProtocolException::INVALID_DATA);
-        }
-
-        return $data;
-    }
-
-    private function readJSONObjectStart() {
-        $this->context_->read();
-        $this->readJSONSyntaxChar(self::LBRACE);
-        $this->pushContext(new PairContext($this));
-    }
-
-    private function readJSONObjectEnd() {
-        $this->readJSONSyntaxChar(self::RBRACE);
-        $this->popContext();
-    }
-
-    private function readJSONArrayStart()
-    {
-        $this->context_->read();
-        $this->readJSONSyntaxChar(self::LBRACKET);
-        $this->pushContext(new ListContext($this));
-    }
-
-    private function readJSONArrayEnd() {
-        $this->readJSONSyntaxChar(self::RBRACKET);
-        $this->popContext();
-    }
-
-    /**
-     * Writes the message header
-     *
-     * @param string $name Function name
-     * @param int $type message type TMessageType::CALL or TMessageType::REPLY
-     * @param int $seqid The sequence id of this message
-     */
-    public function writeMessageBegin($name, $type, $seqid) {
-        $this->writeJSONArrayStart();
-        $this->writeJSONInteger(self::VERSION);
-        $this->writeJSONString($name);
-        $this->writeJSONInteger($type);
-        $this->writeJSONInteger($seqid);
-    }
-
-    /**
-     * Close the message
-     */
-    public function writeMessageEnd() {
-        $this->writeJSONArrayEnd();
-    }
-
-    /**
-     * Writes a struct header.
-     *
-     * @param string     $name Struct name
-     * @throws TException on write error
-     * @return int How many bytes written
-     */
-    public function writeStructBegin($name) {
-        $this->writeJSONObjectStart();
-    }
-
-    /**
-     * Close a struct.
-     *
-     * @throws TException on write error
-     * @return int How many bytes written
-     */
-    public function writeStructEnd() {
-        $this->writeJSONObjectEnd();
-    }
-
-    public function writeFieldBegin($fieldName, $fieldType, $fieldId) {
-        $this->writeJSONInteger($fieldId);
-        $this->writeJSONObjectStart();
-        $this->writeJSONString($this->getTypeNameForTypeID($fieldType));
-    }
-
-    public function writeFieldEnd() {
-        $this->writeJsonObjectEnd();
-    }
-
-    public function writeFieldStop() {
-    }
-
-    public function writeMapBegin($keyType, $valType, $size) {
-        $this->writeJSONArrayStart();
-        $this->writeJSONString($this->getTypeNameForTypeID($keyType));
-        $this->writeJSONString($this->getTypeNameForTypeID($valType));
-        $this->writeJSONInteger($size);
-        $this->writeJSONObjectStart();
-    }
-
-    public function writeMapEnd() {
-        $this->writeJSONObjectEnd();
-        $this->writeJSONArrayEnd();
-    }
-
-    public function writeListBegin($elemType, $size) {
-        $this->writeJSONArrayStart();
-        $this->writeJSONString($this->getTypeNameForTypeID($elemType));
-        $this->writeJSONInteger($size);
-    }
-
-    public function writeListEnd() {
-        $this->writeJSONArrayEnd();
-    }
-
-    public function writeSetBegin($elemType, $size) {
-        $this->writeJSONArrayStart();
-        $this->writeJSONString($this->getTypeNameForTypeID($elemType));
-        $this->writeJSONInteger($size);
-    }
-
-    public function writeSetEnd() {
-        $this->writeJSONArrayEnd();
-    }
-
-    public function writeBool($bool) {
-        $this->writeJSONInteger($bool ? 1 : 0);
-    }
-
-    public function writeByte($byte) {
-        $this->writeJSONInteger($byte);
-    }
-
-    public function writeI16($i16) {
-        $this->writeJSONInteger($i16);
-    }
-
-    public function writeI32($i32) {
-        $this->writeJSONInteger($i32);
-    }
-
-    public function writeI64($i64) {
-        $this->writeJSONInteger($i64);
-    }
-
-    public function writeDouble($dub) {
-        $this->writeJSONDouble($dub);
-    }
-
-    public function writeString($str) {
-        $this->writeJSONString($str);
-    }
-
-    /**
-     * Reads the message header
-     *
-     * @param string $name Function name
-     * @param int $type message type TMessageType::CALL or TMessageType::REPLY
-     * @parem int $seqid The sequence id of this message
-     */
-    public function readMessageBegin(&$name, &$type, &$seqid) {
-        $this->readJSONArrayStart();
-
-        if ($this->readJSONInteger() != self::VERSION) {
-            throw new TProtocolException("Message contained bad version", TProtocolException::BAD_VERSION);
-        }
-
-        $name = $this->readJSONString(false);
-        $type = $this->readJSONInteger();
-        $seqid = $this->readJSONInteger();
-
-        return true;
-    }
-
-    /**
-     * Read the close of message
-     */
-    public function readMessageEnd() {
-        $this->readJSONArrayEnd();
-    }
-
-    public function readStructBegin(&$name) {
-        $this->readJSONObjectStart();
-        return 0;
-    }
-
-    public function readStructEnd() {
-        $this->readJSONObjectEnd();
-    }
-
-    public function readFieldBegin(&$name, &$fieldType, &$fieldId) {
-        $ch = $this->reader_->peek();
-        $name = "";
-
-        if (substr($ch, 0, 1) == self::RBRACE) {
-            $fieldType = TType::STOP;
-        } else {
-            $fieldId = $this->readJSONInteger();
-            $this->readJSONObjectStart();
-            $fieldType = $this->getTypeIDForTypeName($this->readJSONString(false));
-        }
-    }
-
-    public function readFieldEnd() {
-        $this->readJSONObjectEnd();
-    }
-
-    public function readMapBegin(&$keyType, &$valType, &$size) {
-        $this->readJSONArrayStart();
-        $keyType = $this->getTypeIDForTypeName($this->readJSONString(false));
-        $valType = $this->getTypeIDForTypeName($this->readJSONString(false));
-        $size = $this->readJSONInteger();
-        $this->readJSONObjectStart();
-    }
-
-    public function readMapEnd() {
-        $this->readJSONObjectEnd();
-        $this->readJSONArrayEnd();
-    }
-
-    public function readListBegin(&$elemType, &$size) {
-        $this->readJSONArrayStart();
-        $elemType = $this->getTypeIDForTypeName($this->readJSONString(false));
-        $size = $this->readJSONInteger();
-        return true;
-    }
-
-    public function readListEnd() {
-        $this->readJSONArrayEnd();
-    }
-
-    public function readSetBegin(&$elemType, &$size) {
-        $this->readJSONArrayStart();
-        $elemType = $this->getTypeIDForTypeName($this->readJSONString(false));
-        $size = $this->readJSONInteger();
-        return true;
-    }
-
-    public function readSetEnd() {
-        $this->readJSONArrayEnd();
-    }
-
-    public function readBool(&$bool) {
-        $bool = $this->readJSONInteger() == 0 ? false : true;
-        return true;
-    }
-
-    public function readByte(&$byte) {
-        $byte = $this->readJSONInteger();
-        return true;
-    }
-
-    public function readI16(&$i16) {
-        $i16 = $this->readJSONInteger();
-        return true;
-    }
-
-    public function readI32(&$i32) {
-        $i32 = $this->readJSONInteger();
-        return true;
-    }
-
-    public function readI64(&$i64) {
-        if ( PHP_INT_SIZE === 4 ) {
-            $i64 = $this->readJSONIntegerAsString();
-        } else {
-            $i64 = $this->readJSONInteger();
-        }
-        return true;
-    }
-
-    public function readDouble(&$dub) {
-        $dub = $this->readJSONDouble();
-        return true;
-    }
-
-    public function readString(&$str) {
-        $str = $this->readJSONString(false);
-        return true;
-    }
-}
diff --git a/lib/php/lib/Thrift/Protocol/TProtocol.php b/lib/php/lib/Thrift/Protocol/TProtocol.php
deleted file mode 100644
index 380ff10..0000000
--- a/lib/php/lib/Thrift/Protocol/TProtocol.php
+++ /dev/null
@@ -1,340 +0,0 @@
-<?php
-/*
- * 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.protocol
- */
-
-namespace Thrift\Protocol;
-
-use Thrift\Type\TType;
-use Thrift\Exception\TProtocolException;
-
-/**
- * Protocol base class module.
- */
-abstract class TProtocol {
-
-  /**
-   * Underlying transport
-   *
-   * @var TTransport
-   */
-  protected $trans_;
-
-  /**
-   * Constructor
-   */
-  protected function __construct($trans) {
-    $this->trans_ = $trans;
-  }
-
-  /**
-   * Accessor for transport
-   *
-   * @return TTransport
-   */
-  public function getTransport() {
-    return $this->trans_;
-  }
-
-  /**
-   * Writes the message header
-   *
-   * @param string $name Function name
-   * @param int $type message type TMessageType::CALL or TMessageType::REPLY
-   * @param int $seqid The sequence id of this message
-   */
-  public abstract function writeMessageBegin($name, $type, $seqid);
-
-  /**
-   * Close the message
-   */
-  public abstract function writeMessageEnd();
-
-  /**
-   * Writes a struct header.
-   *
-   * @param string     $name Struct name
-   * @throws TException on write error
-   * @return int How many bytes written
-   */
-  public abstract function writeStructBegin($name);
-
-  /**
-   * Close a struct.
-   *
-   * @throws TException on write error
-   * @return int How many bytes written
-   */
-  public abstract function writeStructEnd();
-
-  /*
-   * Starts a field.
-   *
-   * @param string     $name Field name
-   * @param int        $type Field type
-   * @param int        $fid  Field id
-   * @throws TException on write error
-   * @return int How many bytes written
-   */
-  public abstract function writeFieldBegin($fieldName, $fieldType, $fieldId);
-
-  public abstract function writeFieldEnd();
-
-  public abstract function writeFieldStop();
-
-  public abstract function writeMapBegin($keyType, $valType, $size);
-
-  public abstract function writeMapEnd();
-
-  public abstract function writeListBegin($elemType, $size);
-
-  public abstract function writeListEnd();
-
-  public abstract function writeSetBegin($elemType, $size);
-
-  public abstract function writeSetEnd();
-
-  public abstract function writeBool($bool);
-
-  public abstract function writeByte($byte);
-
-  public abstract function writeI16($i16);
-
-  public abstract function writeI32($i32);
-
-  public abstract function writeI64($i64);
-
-  public abstract function writeDouble($dub);
-
-  public abstract function writeString($str);
-
-  /**
-   * Reads the message header
-   *
-   * @param string $name Function name
-   * @param int $type message type TMessageType::CALL or TMessageType::REPLY
-   * @parem int $seqid The sequence id of this message
-   */
-  public abstract function readMessageBegin(&$name, &$type, &$seqid);
-
-  /**
-   * Read the close of message
-   */
-  public abstract function readMessageEnd();
-
-  public abstract function readStructBegin(&$name);
-
-  public abstract function readStructEnd();
-
-  public abstract function readFieldBegin(&$name, &$fieldType, &$fieldId);
-
-  public abstract function readFieldEnd();
-
-  public abstract function readMapBegin(&$keyType, &$valType, &$size);
-
-  public abstract function readMapEnd();
-
-  public abstract function readListBegin(&$elemType, &$size);
-
-  public abstract function readListEnd();
-
-  public abstract function readSetBegin(&$elemType, &$size);
-
-  public abstract function readSetEnd();
-
-  public abstract function readBool(&$bool);
-
-  public abstract function readByte(&$byte);
-
-  public abstract function readI16(&$i16);
-
-  public abstract function readI32(&$i32);
-
-  public abstract function readI64(&$i64);
-
-  public abstract function readDouble(&$dub);
-
-  public abstract function readString(&$str);
-
-  /**
-   * The skip function is a utility to parse over unrecognized date without
-   * causing corruption.
-   *
-   * @param TType $type What type is it
-   */
-  public function skip($type) {
-    switch ($type) {
-    case TType::BOOL:
-      return $this->readBool($bool);
-    case TType::BYTE:
-      return $this->readByte($byte);
-    case TType::I16:
-      return $this->readI16($i16);
-    case TType::I32:
-      return $this->readI32($i32);
-    case TType::I64:
-      return $this->readI64($i64);
-    case TType::DOUBLE:
-      return $this->readDouble($dub);
-    case TType::STRING:
-      return $this->readString($str);
-    case TType::STRUCT:
-      {
-        $result = $this->readStructBegin($name);
-        while (true) {
-          $result += $this->readFieldBegin($name, $ftype, $fid);
-          if ($ftype == TType::STOP) {
-            break;
-          }
-          $result += $this->skip($ftype);
-          $result += $this->readFieldEnd();
-        }
-        $result += $this->readStructEnd();
-        return $result;
-      }
-    case TType::MAP:
-      {
-        $result = $this->readMapBegin($keyType, $valType, $size);
-        for ($i = 0; $i < $size; $i++) {
-          $result += $this->skip($keyType);
-          $result += $this->skip($valType);
-        }
-        $result += $this->readMapEnd();
-        return $result;
-      }
-    case TType::SET:
-      {
-        $result = $this->readSetBegin($elemType, $size);
-        for ($i = 0; $i < $size; $i++) {
-          $result += $this->skip($elemType);
-        }
-        $result += $this->readSetEnd();
-        return $result;
-      }
-    case TType::LST:
-      {
-        $result = $this->readListBegin($elemType, $size);
-        for ($i = 0; $i < $size; $i++) {
-          $result += $this->skip($elemType);
-        }
-        $result += $this->readListEnd();
-        return $result;
-      }
-    default:
-      throw new TProtocolException('Unknown field type: '.$type,
-                                   TProtocolException::INVALID_DATA);
-    }
-  }
-
-  /**
-   * Utility for skipping binary data
-   *
-   * @param TTransport $itrans TTransport object
-   * @param int        $type   Field type
-   */
-  public static function skipBinary($itrans, $type) {
-    switch ($type) {
-    case TType::BOOL:
-      return $itrans->readAll(1);
-    case TType::BYTE:
-      return $itrans->readAll(1);
-    case TType::I16:
-      return $itrans->readAll(2);
-    case TType::I32:
-      return $itrans->readAll(4);
-    case TType::I64:
-      return $itrans->readAll(8);
-    case TType::DOUBLE:
-      return $itrans->readAll(8);
-    case TType::STRING:
-      $len = unpack('N', $itrans->readAll(4));
-      $len = $len[1];
-      if ($len > 0x7fffffff) {
-        $len = 0 - (($len - 1) ^ 0xffffffff);
-      }
-      return 4 + $itrans->readAll($len);
-    case TType::STRUCT:
-      {
-        $result = 0;
-        while (true) {
-          $ftype = 0;
-          $fid = 0;
-          $data = $itrans->readAll(1);
-          $arr = unpack('c', $data);
-          $ftype = $arr[1];
-          if ($ftype == TType::STOP) {
-            break;
-          }
-          // I16 field id
-          $result += $itrans->readAll(2);
-          $result += self::skipBinary($itrans, $ftype);
-        }
-        return $result;
-      }
-    case TType::MAP:
-      {
-        // Ktype
-        $data = $itrans->readAll(1);
-        $arr = unpack('c', $data);
-        $ktype = $arr[1];
-        // Vtype
-        $data = $itrans->readAll(1);
-        $arr = unpack('c', $data);
-        $vtype = $arr[1];
-        // Size
-        $data = $itrans->readAll(4);
-        $arr = unpack('N', $data);
-        $size = $arr[1];
-        if ($size > 0x7fffffff) {
-          $size = 0 - (($size - 1) ^ 0xffffffff);
-        }
-        $result = 6;
-        for ($i = 0; $i < $size; $i++) {
-          $result += self::skipBinary($itrans, $ktype);
-          $result += self::skipBinary($itrans, $vtype);
-        }
-        return $result;
-      }
-    case TType::SET:
-    case TType::LST:
-      {
-        // Vtype
-        $data = $itrans->readAll(1);
-        $arr = unpack('c', $data);
-        $vtype = $arr[1];
-        // Size
-        $data = $itrans->readAll(4);
-        $arr = unpack('N', $data);
-        $size = $arr[1];
-        if ($size > 0x7fffffff) {
-          $size = 0 - (($size - 1) ^ 0xffffffff);
-        }
-        $result = 5;
-        for ($i = 0; $i < $size; $i++) {
-          $result += self::skipBinary($itrans, $vtype);
-        }
-        return $result;
-      }
-    default:
-      throw new TProtocolException('Unknown field type: '.$type,
-                                   TProtocolException::INVALID_DATA);
-    }
-  }
-}
diff --git a/lib/php/lib/Thrift/Serializer/TBinarySerializer.php b/lib/php/lib/Thrift/Serializer/TBinarySerializer.php
deleted file mode 100644
index 2a7cc3e..0000000
--- a/lib/php/lib/Thrift/Serializer/TBinarySerializer.php
+++ /dev/null
@@ -1,73 +0,0 @@
-<?php
-/*
- * 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.protocol
- * @author: rmarin (marin.radu@facebook.com)
- */
-
-namespace Thrift\Serializer;
-
-use Thrift\Transport\TMemoryBuffer;
-use Thrift\Protocol\TBinaryProtocolAccelerated;
-use Thrift\Type\TMessageType;
-
-/**
- * Utility class for serializing and deserializing
- * a thrift object using TBinaryProtocolAccelerated.
- */
-class TBinarySerializer {
-
-  // NOTE(rmarin): Because thrift_protocol_write_binary
-  // adds a begin message prefix, you cannot specify
-  // a transport in which to serialize an object. It has to
-  // be a string. Otherwise we will break the compatibility with
-  // normal deserialization.
-  public static function serialize($object) {
-    $transport = new TMemoryBuffer();
-    $protocol = new TBinaryProtocolAccelerated($transport);
-    if (function_exists('thrift_protocol_write_binary')) {
-      thrift_protocol_write_binary($protocol, $object->getName(),
-                                   TMessageType::REPLY, $object,
-                                   0, $protocol->isStrictWrite());
-
-      $protocol->readMessageBegin($unused_name, $unused_type,
-                                  $unused_seqid);
-    } else {
-      $object->write($protocol);
-    }
-    $protocol->getTransport()->flush();
-    return $transport->getBuffer();
-  }
-
-  public static function deserialize($string_object, $class_name) {
-     $transport = new TMemoryBuffer();
-     $protocol = new TBinaryProtocolAccelerated($transport);
-     if (function_exists('thrift_protocol_read_binary')) {
-       $protocol->writeMessageBegin('', TMessageType::REPLY, 0);
-       $transport->write($string_object);
-       return thrift_protocol_read_binary($protocol, $class_name,
-                                          $protocol->isStrictRead());
-     } else {
-       $transport->write($string_object);
-       $object = new $class_name();
-       $object->read($protocol);
-       return $object;
-     }
-  }
-}
diff --git a/lib/php/lib/Thrift/Server/TForkingServer.php b/lib/php/lib/Thrift/Server/TForkingServer.php
deleted file mode 100644
index 6fca305..0000000
--- a/lib/php/lib/Thrift/Server/TForkingServer.php
+++ /dev/null
@@ -1,119 +0,0 @@
-<?php
-
-namespace Thrift\Server;
-
-use Thrift\Server\TServer;
-use Thrift\Transport\TTransport;
-use Thrift\Exception\TException;
-use Thrift\Exception\TTransportException;
-
-/**
- * A forking implementation of a Thrift server.
- *
- * @package thrift.server
- */
-class TForkingServer extends TServer {
-  /**
-   * Flag for the main serving loop
-   *
-   * @var bool
-   */
-  private $stop_ = false;
-
-  /**
-   * List of children.
-   *
-   * @var array
-   */
-  protected $children_ = array();
-
-  /**
-   * Listens for new client using the supplied
-   * transport. We fork when a new connection
-   * arrives.
-   *
-   * @return void
-   */
-  public function serve() {
-    $this->transport_->listen();
-
-    while (!$this->stop_) {
-      try {
-        $transport = $this->transport_->accept();
-
-        if ($transport != null) {
-          $pid = pcntl_fork();
-
-          if ($pid > 0) {
-            $this->handleParent($transport, $pid);
-          }
-          else if ($pid === 0) {
-            $this->handleChild($transport);
-          }
-          else {
-            throw new TException('Failed to fork');
-          }
-        }
-      }
-      catch (TTransportException $e) { }
-
-      $this->collectChildren();
-    }
-  }
-
-  /**
-   * Code run by the parent
-   *
-   * @param TTransport $transport
-   * @param int $pid
-   * @return void
-   */
-  private function handleParent(TTransport $transport, $pid) {
-    $this->children_[$pid] = $transport;
-  }
-
-  /**
-   * Code run by the child.
-   *
-   * @param TTransport $transport
-   * @return void
-   */
-  private function handleChild(TTransport $transport) {
-    try {
-      $inputTransport = $this->inputTransportFactory_->getTransport($transport);
-      $outputTransport = $this->outputTransportFactory_->getTransport($transport);
-      $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport);
-      $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport);
-      while ($this->processor_->process($inputProtocol, $outputProtocol)) { }
-      @$transport->close();
-    }
-    catch (TTransportException $e) { }
-
-    exit(0);
-  }
-
-  /**
-   * Collects any children we may have
-   *
-   * @return void
-   */
-  private function collectChildren() {
-    foreach ($this->children_ as $pid => $transport) {
-      if (pcntl_waitpid($pid, $status, WNOHANG) > 0) {
-        unset($this->children_[$pid]);
-        if ($transport) @$transport->close();
-      }
-    }
-  }
-
-  /**
-   * Stops the server running. Kills the transport
-   * and then stops the main serving loop
-   *
-   * @return void
-   */
-  public function stop() {
-    $this->transport_->close();
-    $this->stop_ = true;
-  }
-}
diff --git a/lib/php/lib/Thrift/Server/TServer.php b/lib/php/lib/Thrift/Server/TServer.php
deleted file mode 100644
index 343bf4b..0000000
--- a/lib/php/lib/Thrift/Server/TServer.php
+++ /dev/null
@@ -1,101 +0,0 @@
-<?php
-
-namespace Thrift\Server;
-
-use Thrift\Server\TServerTransport;
-use Thrift\Factory\TTransportFactory;
-use Thrift\Factory\TProtocolFactory;
-
-/**
- * Generic class for a Thrift server.
- *
- * @package thrift.server
- */
-abstract class TServer {
-
-  /**
-   * Processor to handle new clients
-   *
-   * @var TProcessor
-   */
-  protected $processor_;
-
-  /**
-   * Server transport to be used for listening
-   * and accepting new clients
-   *
-   * @var TServerTransport
-   */
-  protected $transport_;
-
-  /**
-   * Input transport factory
-   *
-   * @var TTransportFactory
-   */
-  protected $inputTransportFactory_;
-
-  /**
-   * Output transport factory
-   *
-   * @var TTransportFactory
-   */
-  protected $outputTransportFactory_;
-
-  /**
-   * Input protocol factory
-   *
-   * @var TProtocolFactory
-   */
-  protected $inputProtocolFactory_;
-
-  /**
-   * Output protocol factory
-   *
-   * @var TProtocolFactory
-   */
-  protected $outputProtocolFactory_;
-
-  /**
-   * Sets up all the factories, etc
-   *
-   * @param object $processor
-   * @param TServerTransport $transport
-   * @param TTransportFactory $inputTransportFactory
-   * @param TTransportFactory $outputTransportFactory
-   * @param TProtocolFactory $inputProtocolFactory
-   * @param TProtocolFactory $outputProtocolFactory
-   * @return void
-   */
-  public function __construct($processor,
-                              TServerTransport $transport,
-                              TTransportFactory $inputTransportFactory,
-                              TTransportFactory $outputTransportFactory,
-                              TProtocolFactory $inputProtocolFactory,
-                              TProtocolFactory $outputProtocolFactory) {
-    $this->processor_ = $processor;
-    $this->transport_ = $transport;
-    $this->inputTransportFactory_ = $inputTransportFactory;
-    $this->outputTransportFactory_ = $outputTransportFactory;
-    $this->inputProtocolFactory_ = $inputProtocolFactory;
-    $this->outputProtocolFactory_ = $outputProtocolFactory;
-  }
-
-  /**
-   * Serves the server. This should never return
-   * unless a problem permits it to do so or it
-   * is interrupted intentionally
-   *
-   * @abstract
-   * @return void
-   */
-  abstract public function serve();
-
-  /**
-   * Stops the server serving
-   *
-   * @abstract
-   * @return void
-   */
-  abstract public function stop();
-}
diff --git a/lib/php/lib/Thrift/Server/TServerSocket.php b/lib/php/lib/Thrift/Server/TServerSocket.php
deleted file mode 100644
index 00a6fb9..0000000
--- a/lib/php/lib/Thrift/Server/TServerSocket.php
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-
-namespace Thrift\Server;
-
-use Thrift\Server\TServerTransport;
-use Thrift\Transport\TSocket;
-
-/**
- * Socket implementation of a server agent.
- *
- * @package thrift.transport
- */
-class TServerSocket extends TServerTransport {
-
-  /**
-   * Handle for the listener socket
-   *
-   * @var resource
-   */
-  private $listener_;
-
-  /**
-   * Port for the listener to listen on
-   *
-   * @var int
-   */
-  private $port_;
-
-  /**
-   * Timeout when listening for a new client
-   *
-   * @var int
-   */
-  private $acceptTimeout_ = 30000;
-
-  /**
-   * Host to listen on
-   *
-   * @var string
-   */
-  private $host_;
-
-  /**
-   * ServerSocket constructor
-   *
-   * @param string $host        Host to listen on
-   * @param int $port           Port to listen on
-   * @return void
-   */
-  public function __construct($host = 'localhost', $port = 9090) {
-    $this->host_ = $host;
-    $this->port_ = $port;
-  }
-
-  /**
-   * Sets the accept timeout
-   *
-   * @param int $acceptTimeout
-   * @return void
-   */
-  public function setAcceptTimeout($acceptTimeout) {
-    $this->acceptTimeout_ = $acceptTimeout;
-  }
-
-  /**
-   * Opens a new socket server handle
-   *
-   * @return void
-   */
-  public function listen() {
-    $this->listener_ = stream_socket_server('tcp://' . $this->host_ . ':' . $this->port_);
-  }
-
-  /**
-   * Closes the socket server handle
-   *
-   * @return void
-   */
-  public function close() {
-    @fclose($this->listener_);
-    $this->listener_ = null;
-  }
-
-  /**
-   * Implementation of accept. If not client is accepted in the given time
-   *
-   * @return TSocket
-   */
-  protected function acceptImpl() {
-    $handle = @stream_socket_accept($this->listener_, $this->acceptTimeout_ / 1000.0);
-    if(!$handle) return null;
-
-    $socket = new TSocket();
-    $socket->setHandle($handle);
-
-    return $socket;
-  }
-}
diff --git a/lib/php/lib/Thrift/Server/TServerTransport.php b/lib/php/lib/Thrift/Server/TServerTransport.php
deleted file mode 100644
index 5324712..0000000
--- a/lib/php/lib/Thrift/Server/TServerTransport.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-
-namespace Thrift\Server;
-
-use Thrift\Exception\TTransportException;
-
-/**
- * Generic class for Server agent.
- *
- * @package thrift.transport
- */
-abstract class TServerTransport {
-  /**
-   * List for new clients
-   *
-   * @abstract
-   * @return void
-   */
-  abstract public function listen();
-
-  /**
-   * Close the server
-   *
-   * @abstract
-   * @return void
-   */
-  abstract public function close();
-
-  /**
-   * Subclasses should use this to implement
-   * accept.
-   *
-   * @abstract
-   * @return TTransport
-   */
-  protected abstract function acceptImpl();
-
-  /**
-   * Uses the accept implemtation. If null is returned, an
-   * exception is thrown.
-   *
-   * @throws TTransportException
-   * @return TTransport
-   */
-  public function accept() {
-    $transport = $this->acceptImpl();
-
-    if ($transport == null) {
-      throw new TTransportException("accept() may not return NULL");
-    }
-
-    return $transport;
-  }
-}
diff --git a/lib/php/lib/Thrift/Server/TSimpleServer.php b/lib/php/lib/Thrift/Server/TSimpleServer.php
deleted file mode 100644
index 790e48f..0000000
--- a/lib/php/lib/Thrift/Server/TSimpleServer.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-
-namespace Thrift\Server;
-
-use Thrift\Server\TServer;
-use Thrift\Exception\TTransportException;
-
-/**
- * Simple implemtation of a Thrift server.
- *
- * @package thrift.server
- */
-class TSimpleServer extends TServer {
-  /**
-   * Flag for the main serving loop
-   *
-   * @var bool
-   */
-  private $stop_ = false;
-
-  /**
-   * Listens for new client using the supplied
-   * transport. It handles TTransportExceptions
-   * to avoid timeouts etc killing it
-   *
-   * @return void
-   */
-  public function serve() {
-    $this->transport_->listen();
-
-    while (!$this->stop_) {
-      try {
-        $transport = $this->transport_->accept();
-
-        if ($transport != null) {
-          $inputTransport = $this->inputTransportFactory_->getTransport($transport);
-          $outputTransport = $this->outputTransportFactory_->getTransport($transport);
-          $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport);
-          $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport);
-          while ($this->processor_->process($inputProtocol, $outputProtocol)) { }
-        }
-      }
-      catch (TTransportException $e) { }
-    }
-  }
-
-  /**
-   * Stops the server running. Kills the transport
-   * and then stops the main serving loop
-   *
-   * @return void
-   */
-  public function stop() {
-    $this->transport_->close();
-    $this->stop_ = true;
-  }
-}
diff --git a/lib/php/lib/Thrift/StringFunc/Core.php b/lib/php/lib/Thrift/StringFunc/Core.php
deleted file mode 100644
index e38a5b2..0000000
--- a/lib/php/lib/Thrift/StringFunc/Core.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-/*
- * 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.
- *
- */
-
-namespace Thrift\StringFunc;
-
-use Thrift\StringFunc\TStringFunc;
-
-class Core implements TStringFunc {
-    public function substr($str, $start, $length = null) {
-        // specifying a null $length would return an empty string
-        if($length === null) {
-            return substr($str, $start);
-        }
-        return substr($str, $start, $length);
-    }
-
-    public function strlen($str) {
-        return strlen($str);
-    }
-}
\ No newline at end of file
diff --git a/lib/php/lib/Thrift/StringFunc/Mbstring.php b/lib/php/lib/Thrift/StringFunc/Mbstring.php
deleted file mode 100644
index c1ace13..0000000
--- a/lib/php/lib/Thrift/StringFunc/Mbstring.php
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-/*
- * 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.
- *
- */
-
-namespace Thrift\StringFunc;
-
-use Thrift\StringFunc\TStringFunc;
-
-class Mbstring implements TStringFunc {
-    public function substr($str, $start, $length = null) {
-        /**
-         * We need to set the charset parameter, which is the second
-         * optional parameter and the first optional parameter can't
-         * be null or false as a "magic" value because that would
-         * cause an empty string to be returned, so we need to
-         * actually calculate the proper length value.
-         */
-        if($length === null) {
-            $length = $this->strlen($str) - $start;
-        }
-
-        return mb_substr($str, $start, $length, '8bit');
-    }
-
-    public function strlen($str) {
-        return mb_strlen($str, '8bit');
-    }
-}
\ No newline at end of file
diff --git a/lib/php/lib/Thrift/StringFunc/TStringFunc.php b/lib/php/lib/Thrift/StringFunc/TStringFunc.php
deleted file mode 100644
index c5bb390..0000000
--- a/lib/php/lib/Thrift/StringFunc/TStringFunc.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-/*
- * 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.
- *
- */
-
-namespace Thrift\StringFunc;
-
-interface TStringFunc {
-    public function substr($str, $start, $length = null);
-    public function strlen($str);
-}
\ No newline at end of file
diff --git a/lib/php/lib/Thrift/Transport/TBufferedTransport.php b/lib/php/lib/Thrift/Transport/TBufferedTransport.php
deleted file mode 100644
index 0d3ad98..0000000
--- a/lib/php/lib/Thrift/Transport/TBufferedTransport.php
+++ /dev/null
@@ -1,165 +0,0 @@
-<?php
-/*
- * 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.transport
- */
-
-namespace Thrift\Transport;
-
-use Thrift\Transport\TTransport;
-use Thrift\Factory\TStringFuncFactory;
-
-/**
- * Buffered transport. Stores data to an internal buffer that it doesn't
- * actually write out until flush is called. For reading, we do a greedy
- * read and then serve data out of the internal buffer.
- *
- * @package thrift.transport
- */
-class TBufferedTransport extends TTransport {
-
-  /**
-   * Constructor. Creates a buffered transport around an underlying transport
-   */
-  public function __construct($transport=null, $rBufSize=512, $wBufSize=512) {
-    $this->transport_ = $transport;
-    $this->rBufSize_ = $rBufSize;
-    $this->wBufSize_ = $wBufSize;
-  }
-
-  /**
-   * The underlying transport
-   *
-   * @var TTransport
-   */
-  protected $transport_ = null;
-
-  /**
-   * The receive buffer size
-   *
-   * @var int
-   */
-  protected $rBufSize_ = 512;
-
-  /**
-   * The write buffer size
-   *
-   * @var int
-   */
-  protected $wBufSize_ = 512;
-
-  /**
-   * The write buffer.
-   *
-   * @var string
-   */
-  protected $wBuf_ = '';
-
-  /**
-   * The read buffer.
-   *
-   * @var string
-   */
-  protected $rBuf_ = '';
-
-  public function isOpen() {
-    return $this->transport_->isOpen();
-  }
-
-  public function open() {
-    $this->transport_->open();
-  }
-
-  public function close() {
-    $this->transport_->close();
-  }
-
-  public function putBack($data) {
-    if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
-      $this->rBuf_ = $data;
-    } else {
-      $this->rBuf_ = ($data . $this->rBuf_);
-    }
-  }
-
-  /**
-   * The reason that we customize readAll here is that the majority of PHP
-   * streams are already internally buffered by PHP. The socket stream, for
-   * example, buffers internally and blocks if you call read with $len greater
-   * than the amount of data available, unlike recv() in C.
-   *
-   * Therefore, use the readAll method of the wrapped transport inside
-   * the buffered readAll.
-   */
-  public function readAll($len) {
-    $have = TStringFuncFactory::create()->strlen($this->rBuf_);
-    if ($have == 0) {
-      $data = $this->transport_->readAll($len);
-    } else if ($have < $len) {
-      $data = $this->rBuf_;
-      $this->rBuf_ = '';
-      $data .= $this->transport_->readAll($len - $have);
-    } else if ($have == $len) {
-      $data = $this->rBuf_;
-      $this->rBuf_ = '';
-    } else if ($have > $len) {
-      $data = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len);
-      $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len);
-    }
-    return $data;
-  }
-
-  public function read($len) {
-    if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
-      $this->rBuf_ = $this->transport_->read($this->rBufSize_);
-    }
-
-    if (TStringFuncFactory::create()->strlen($this->rBuf_) <= $len) {
-      $ret = $this->rBuf_;
-      $this->rBuf_ = '';
-      return $ret;
-    }
-
-    $ret = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len);
-    $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len);
-    return $ret;
-  }
-
-  public function write($buf) {
-    $this->wBuf_ .= $buf;
-    if (TStringFuncFactory::create()->strlen($this->wBuf_) >= $this->wBufSize_) {
-      $out = $this->wBuf_;
-
-      // Note that we clear the internal wBuf_ prior to the underlying write
-      // to ensure we're in a sane state (i.e. internal buffer cleaned)
-      // if the underlying write throws up an exception
-      $this->wBuf_ = '';
-      $this->transport_->write($out);
-    }
-  }
-
-  public function flush() {
-    if (TStringFuncFactory::create()->strlen($this->wBuf_) > 0) {
-      $this->transport_->write($this->wBuf_);
-      $this->wBuf_ = '';
-    }
-    $this->transport_->flush();
-  }
-
-}
diff --git a/lib/php/lib/Thrift/Transport/TFramedTransport.php b/lib/php/lib/Thrift/Transport/TFramedTransport.php
deleted file mode 100644
index d80d548..0000000
--- a/lib/php/lib/Thrift/Transport/TFramedTransport.php
+++ /dev/null
@@ -1,183 +0,0 @@
-<?php
-/*
- * 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.transport
- */
-
-namespace Thrift\Transport;
-
-use Thrift\Transport\TTransport;
-use Thrift\Factory\TStringFuncFactory;
-
-/**
- * Framed transport. Writes and reads data in chunks that are stamped with
- * their length.
- *
- * @package thrift.transport
- */
-class TFramedTransport extends TTransport {
-
-  /**
-   * Underlying transport object.
-   *
-   * @var TTransport
-   */
-  private $transport_;
-
-  /**
-   * Buffer for read data.
-   *
-   * @var string
-   */
-  private $rBuf_;
-
-  /**
-   * Buffer for queued output data
-   *
-   * @var string
-   */
-  private $wBuf_;
-
-  /**
-   * Whether to frame reads
-   *
-   * @var bool
-   */
-  private $read_;
-
-  /**
-   * Whether to frame writes
-   *
-   * @var bool
-   */
-  private $write_;
-
-  /**
-   * Constructor.
-   *
-   * @param TTransport $transport Underlying transport
-   */
-  public function __construct($transport=null, $read=true, $write=true) {
-    $this->transport_ = $transport;
-    $this->read_ = $read;
-    $this->write_ = $write;
-  }
-
-  public function isOpen() {
-    return $this->transport_->isOpen();
-  }
-
-  public function open() {
-    $this->transport_->open();
-  }
-
-  public function close() {
-    $this->transport_->close();
-  }
-
-  /**
-   * Reads from the buffer. When more data is required reads another entire
-   * chunk and serves future reads out of that.
-   *
-   * @param int $len How much data
-   */
-  public function read($len) {
-    if (!$this->read_) {
-      return $this->transport_->read($len);
-    }
-
-    if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
-      $this->readFrame();
-    }
-
-    // Just return full buff
-    if ($len >= TStringFuncFactory::create()->strlen($this->rBuf_)) {
-      $out = $this->rBuf_;
-      $this->rBuf_ = null;
-      return $out;
-    }
-
-    // Return TStringFuncFactory::create()->substr
-    $out = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len);
-    $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len);
-    return $out;
-  }
-
-  /**
-   * Put previously read data back into the buffer
-   *
-   * @param string $data data to return
-   */
-  public function putBack($data) {
-    if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
-      $this->rBuf_ = $data;
-    } else {
-      $this->rBuf_ = ($data . $this->rBuf_);
-    }
-  }
-
-  /**
-   * Reads a chunk of data into the internal read buffer.
-   */
-  private function readFrame() {
-    $buf = $this->transport_->readAll(4);
-    $val = unpack('N', $buf);
-    $sz = $val[1];
-
-    $this->rBuf_ = $this->transport_->readAll($sz);
-  }
-
-  /**
-   * Writes some data to the pending output buffer.
-   *
-   * @param string $buf The data
-   * @param int    $len Limit of bytes to write
-   */
-  public function write($buf, $len=null) {
-    if (!$this->write_) {
-      return $this->transport_->write($buf, $len);
-    }
-
-    if ($len !== null && $len < TStringFuncFactory::create()->strlen($buf)) {
-      $buf = TStringFuncFactory::create()->substr($buf, 0, $len);
-    }
-    $this->wBuf_ .= $buf;
-  }
-
-  /**
-   * Writes the output buffer to the stream in the format of a 4-byte length
-   * followed by the actual data.
-   */
-  public function flush() {
-    if (!$this->write_ || TStringFuncFactory::create()->strlen($this->wBuf_) == 0) {
-      return $this->transport_->flush();
-    }
-
-    $out = pack('N', TStringFuncFactory::create()->strlen($this->wBuf_));
-    $out .= $this->wBuf_;
-
-    // Note that we clear the internal wBuf_ prior to the underlying write
-    // to ensure we're in a sane state (i.e. internal buffer cleaned)
-    // if the underlying write throws up an exception
-    $this->wBuf_ = '';
-    $this->transport_->write($out);
-    $this->transport_->flush();
-  }
-
-}
diff --git a/lib/php/lib/Thrift/Transport/THttpClient.php b/lib/php/lib/Thrift/Transport/THttpClient.php
deleted file mode 100644
index f46b18a..0000000
--- a/lib/php/lib/Thrift/Transport/THttpClient.php
+++ /dev/null
@@ -1,221 +0,0 @@
-<?php
-/*
- * 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.transport
- */
-
-namespace Thrift\Transport;
-
-use Thrift\Transport\TTransport;
-use Thrift\Exception\TTransportException;
-use Thrift\Factory\TStringFuncFactory;
-
-/**
- * HTTP client for Thrift
- *
- * @package thrift.transport
- */
-class THttpClient extends TTransport {
-
-  /**
-   * The host to connect to
-   *
-   * @var string
-   */
-  protected $host_;
-
-  /**
-   * The port to connect on
-   *
-   * @var int
-   */
-  protected $port_;
-
-  /**
-   * The URI to request
-   *
-   * @var string
-   */
-  protected $uri_;
-
-  /**
-   * The scheme to use for the request, i.e. http, https
-   *
-   * @var string
-   */
-  protected $scheme_;
-
-  /**
-   * Buffer for the HTTP request data
-   *
-   * @var string
-   */
-  protected $buf_;
-
-  /**
-   * Input socket stream.
-   *
-   * @var resource
-   */
-  protected $handle_;
-
-  /**
-   * Read timeout
-   *
-   * @var float
-   */
-  protected $timeout_;
-
-  /**
-   * http headers
-   *
-   * @var array
-   */
-  protected $headers_;
-
-  /**
-   * Make a new HTTP client.
-   *
-   * @param string $host
-   * @param int    $port
-   * @param string $uri
-   */
-  public function __construct($host, $port=80, $uri='', $scheme = 'http') {
-    if ((TStringFuncFactory::create()->strlen($uri) > 0) && ($uri{0} != '/')) {
-      $uri = '/'.$uri;
-    }
-    $this->scheme_ = $scheme;
-    $this->host_ = $host;
-    $this->port_ = $port;
-    $this->uri_ = $uri;
-    $this->buf_ = '';
-    $this->handle_ = null;
-    $this->timeout_ = null;
-    $this->headers_ = array();
-  }
-
-  /**
-   * Set read timeout
-   *
-   * @param float $timeout
-   */
-  public function setTimeoutSecs($timeout) {
-    $this->timeout_ = $timeout;
-  }
-
-  /**
-   * Whether this transport is open.
-   *
-   * @return boolean true if open
-   */
-  public function isOpen() {
-    return true;
-  }
-
-  /**
-   * Open the transport for reading/writing
-   *
-   * @throws TTransportException if cannot open
-   */
-  public function open() {}
-
-  /**
-   * Close the transport.
-   */
-  public function close() {
-    if ($this->handle_) {
-      @fclose($this->handle_);
-      $this->handle_ = null;
-    }
-  }
-
-  /**
-   * Read some data into the array.
-   *
-   * @param int    $len How much to read
-   * @return string The data that has been read
-   * @throws TTransportException if cannot read any more data
-   */
-  public function read($len) {
-    $data = @fread($this->handle_, $len);
-    if ($data === FALSE || $data === '') {
-      $md = stream_get_meta_data($this->handle_);
-      if ($md['timed_out']) {
-        throw new TTransportException('THttpClient: timed out reading '.$len.' bytes from '.$this->host_.':'.$this->port_.$this->uri_, TTransportException::TIMED_OUT);
-      } else {
-        throw new TTransportException('THttpClient: Could not read '.$len.' bytes from '.$this->host_.':'.$this->port_.$this->uri_, TTransportException::UNKNOWN);
-      }
-    }
-    return $data;
-  }
-
-  /**
-   * Writes some data into the pending buffer
-   *
-   * @param string $buf  The data to write
-   * @throws TTransportException if writing fails
-   */
-  public function write($buf) {
-    $this->buf_ .= $buf;
-  }
-
-  /**
-   * Opens and sends the actual request over the HTTP connection
-   *
-   * @throws TTransportException if a writing error occurs
-   */
-  public function flush() {
-    // God, PHP really has some esoteric ways of doing simple things.
-    $host = $this->host_.($this->port_ != 80 ? ':'.$this->port_ : '');
-
-    $headers = array();
-    $defaultHeaders = array('Host' => $host,
-                            'Accept' => 'application/x-thrift',
-                            'User-Agent' => 'PHP/THttpClient',
-                            'Content-Type' => 'application/x-thrift',
-                            'Content-Length' => TStringFuncFactory::create()->strlen($this->buf_));
-    foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) {
-        $headers[] = "$key: $value";
-    }
-
-    $options = array('method' => 'POST',
-                     'header' => implode("\r\n", $headers),
-                     'max_redirects' => 1,
-                     'content' => $this->buf_);
-    if ($this->timeout_ > 0) {
-      $options['timeout'] = $this->timeout_;
-    }
-    $this->buf_ = '';
-
-    $contextid = stream_context_create(array('http' => $options));
-    $this->handle_ = @fopen($this->scheme_.'://'.$host.$this->uri_, 'r', false, $contextid);
-
-    // Connect failed?
-    if ($this->handle_ === FALSE) {
-      $this->handle_ = null;
-      $error = 'THttpClient: Could not connect to '.$host.$this->uri_;
-      throw new TTransportException($error, TTransportException::NOT_OPEN);
-    }
-  }
-
-  public function addHeaders($headers) {
-    $this->headers_ = array_merge($this->headers_, $headers);
-  }
-
-}
diff --git a/lib/php/lib/Thrift/Transport/TMemoryBuffer.php b/lib/php/lib/Thrift/Transport/TMemoryBuffer.php
deleted file mode 100644
index 911fab6..0000000
--- a/lib/php/lib/Thrift/Transport/TMemoryBuffer.php
+++ /dev/null
@@ -1,89 +0,0 @@
-<?php
-/*
- * 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.transport
- */
-
-namespace Thrift\Transport;
-
-use Thrift\Transport\TTransport;
-use Thrift\Exception\TTransportException;
-use Thrift\Factory\TStringFuncFactory;
-
-/**
- * A memory buffer is a tranpsort that simply reads from and writes to an
- * in-memory string buffer. Anytime you call write on it, the data is simply
- * placed into a buffer, and anytime you call read, data is read from that
- * buffer.
- *
- * @package thrift.transport
- */
-class TMemoryBuffer extends TTransport {
-
-  /**
-   * Constructor. Optionally pass an initial value
-   * for the buffer.
-   */
-  public function __construct($buf = '') {
-    $this->buf_ = $buf;
-  }
-
-  protected $buf_ = '';
-
-  public function isOpen() {
-    return true;
-  }
-
-  public function open() {}
-
-  public function close() {}
-
-  public function write($buf) {
-    $this->buf_ .= $buf;
-  }
-
-  public function read($len) {
-    $bufLength = TStringFuncFactory::create()->strlen($this->buf_);
-
-    if ($bufLength === 0) {
-      throw new TTransportException('TMemoryBuffer: Could not read ' .
-                                    $len . ' bytes from buffer.',
-                                    TTransportException::UNKNOWN);
-    }
-
-    if ($bufLength <= $len) {
-      $ret = $this->buf_;
-      $this->buf_ = '';
-      return $ret;
-    }
-
-    $ret = TStringFuncFactory::create()->substr($this->buf_, 0, $len);
-    $this->buf_ = TStringFuncFactory::create()->substr($this->buf_, $len);
-
-    return $ret;
-  }
-
-  function getBuffer() {
-    return $this->buf_;
-  }
-
-  public function available() {
-    return TStringFuncFactory::create()->strlen($this->buf_);
-  }
-}
diff --git a/lib/php/lib/Thrift/Transport/TNullTransport.php b/lib/php/lib/Thrift/Transport/TNullTransport.php
deleted file mode 100644
index 4bf10ed..0000000
--- a/lib/php/lib/Thrift/Transport/TNullTransport.php
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-/*
- * 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.transport
- */
-
-namespace Thrift\Transport;
-
-use Thrift\Transport\TTransport;
-use Thrift\Exception\TTransportException;
-
-/**
- * Transport that only accepts writes and ignores them.
- * This is useful for measuring the serialized size of structures.
- *
- * @package thrift.transport
- */
-class TNullTransport extends TTransport {
-
-  public function isOpen() {
-    return true;
-  }
-
-  public function open() {}
-
-  public function close() {}
-
-  public function read($len) {
-    throw new TTransportException("Can't read from TNullTransport.");
-  }
-
-  public function write($buf) {}
-
-}
diff --git a/lib/php/lib/Thrift/Transport/TPhpStream.php b/lib/php/lib/Thrift/Transport/TPhpStream.php
deleted file mode 100644
index 691d0cf..0000000
--- a/lib/php/lib/Thrift/Transport/TPhpStream.php
+++ /dev/null
@@ -1,114 +0,0 @@
-<?php
-/*
- * 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.transport
- */
-
-namespace Thrift\Transport;
-
-use Thrift\Transport\TTransport;
-use Thrift\Exception\TException;
-use Thrift\Factory\TStringFuncFactory;
-
-/**
- * Php stream transport. Reads to and writes from the php standard streams
- * php://input and php://output
- *
- * @package thrift.transport
- */
-class TPhpStream extends TTransport {
-
-  const MODE_R = 1;
-  const MODE_W = 2;
-
-  private $inStream_ = null;
-
-  private $outStream_ = null;
-
-  private $read_ = false;
-
-  private $write_ = false;
-
-  public function __construct($mode) {
-    $this->read_ = $mode & self::MODE_R;
-    $this->write_ = $mode & self::MODE_W;
-  }
-
-  public function open() {
-    if ($this->read_) {
-      $this->inStream_ = @fopen(self::inStreamName(), 'r');
-      if (!is_resource($this->inStream_)) {
-        throw new TException('TPhpStream: Could not open php://input');
-      }
-    }
-    if ($this->write_) {
-      $this->outStream_ = @fopen('php://output', 'w');
-      if (!is_resource($this->outStream_)) {
-        throw new TException('TPhpStream: Could not open php://output');
-      }
-    }
-  }
-
-  public function close() {
-    if ($this->read_) {
-      @fclose($this->inStream_);
-      $this->inStream_ = null;
-    }
-    if ($this->write_) {
-      @fclose($this->outStream_);
-      $this->outStream_ = null;
-    }
-  }
-
-  public function isOpen() {
-    return
-      (!$this->read_ || is_resource($this->inStream_)) &&
-      (!$this->write_ || is_resource($this->outStream_));
-  }
-
-  public function read($len) {
-    $data = @fread($this->inStream_, $len);
-    if ($data === FALSE || $data === '') {
-      throw new TException('TPhpStream: Could not read '.$len.' bytes');
-    }
-    return $data;
-  }
-
-  public function write($buf) {
-    while (TStringFuncFactory::create()->strlen($buf) > 0) {
-      $got = @fwrite($this->outStream_, $buf);
-      if ($got === 0 || $got === FALSE) {
-        throw new TException('TPhpStream: Could not write '.TStringFuncFactory::create()->strlen($buf).' bytes');
-      }
-      $buf = TStringFuncFactory::create()->substr($buf, $got);
-    }
-  }
-
-  public function flush() {
-    @fflush($this->outStream_);
-  }
-
-  private static function inStreamName() {
-    if (php_sapi_name() == 'cli') {
-      return 'php://stdin';
-    }
-    return 'php://input';
-  }
-
-}
diff --git a/lib/php/lib/Thrift/Transport/TSocket.php b/lib/php/lib/Thrift/Transport/TSocket.php
deleted file mode 100644
index 3ad3bf7..0000000
--- a/lib/php/lib/Thrift/Transport/TSocket.php
+++ /dev/null
@@ -1,326 +0,0 @@
-<?php
-/*
- * 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.transport
- */
-
-namespace Thrift\Transport;
-
-use Thrift\Transport\TTransport;
-use Thrift\Exception\TException;
-use Thrift\Exception\TTransportException;
-use Thrift\Factory\TStringFuncFactory;
-
-/**
- * Sockets implementation of the TTransport interface.
- *
- * @package thrift.transport
- */
-class TSocket extends TTransport {
-
-  /**
-   * Handle to PHP socket
-   *
-   * @var resource
-   */
-  private $handle_ = null;
-
-  /**
-   * Remote hostname
-   *
-   * @var string
-   */
-  protected $host_ = 'localhost';
-
-  /**
-   * Remote port
-   *
-   * @var int
-   */
-  protected $port_ = '9090';
-
-  /**
-   * Send timeout in seconds.
-   *
-   * Combined with sendTimeoutUsec this is used for send timeouts.
-   *
-   * @var int
-   */
-  private $sendTimeoutSec_ = 0;
-
-  /**
-   * Send timeout in microseconds.
-   *
-   * Combined with sendTimeoutSec this is used for send timeouts.
-   *
-   * @var int
-   */
-  private $sendTimeoutUsec_ = 100000;
-
-  /**
-   * Recv timeout in seconds
-   *
-   * Combined with recvTimeoutUsec this is used for recv timeouts.
-   *
-   * @var int
-   */
-  private $recvTimeoutSec_ = 0;
-
-  /**
-   * Recv timeout in microseconds
-   *
-   * Combined with recvTimeoutSec this is used for recv timeouts.
-   *
-   * @var int
-   */
-  private $recvTimeoutUsec_ = 750000;
-
-  /**
-   * Persistent socket or plain?
-   *
-   * @var bool
-   */
-  protected $persist_ = FALSE;
-
-  /**
-   * Debugging on?
-   *
-   * @var bool
-   */
-  protected $debug_ = FALSE;
-
-  /**
-   * Debug handler
-   *
-   * @var mixed
-   */
-  protected $debugHandler_ = null;
-
-  /**
-   * Socket constructor
-   *
-   * @param string $host         Remote hostname
-   * @param int    $port         Remote port
-   * @param bool   $persist      Whether to use a persistent socket
-   * @param string $debugHandler Function to call for error logging
-   */
-  public function __construct($host='localhost',
-                              $port=9090,
-                              $persist=FALSE,
-                              $debugHandler=null) {
-    $this->host_ = $host;
-    $this->port_ = $port;
-    $this->persist_ = $persist;
-    $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log';
-  }
-
-  /**
-   * @param resource $handle
-   * @return void
-   */
-  public function setHandle($handle) {
-    $this->handle_ = $handle;
-  }
-
-  /**
-   * Sets the send timeout.
-   *
-   * @param int $timeout  Timeout in milliseconds.
-   */
-  public function setSendTimeout($timeout) {
-    $this->sendTimeoutSec_ = floor($timeout / 1000);
-    $this->sendTimeoutUsec_ =
-            ($timeout - ($this->sendTimeoutSec_ * 1000)) * 1000;
-  }
-
-  /**
-   * Sets the receive timeout.
-   *
-   * @param int $timeout  Timeout in milliseconds.
-   */
-  public function setRecvTimeout($timeout) {
-    $this->recvTimeoutSec_ = floor($timeout / 1000);
-    $this->recvTimeoutUsec_ =
-            ($timeout - ($this->recvTimeoutSec_ * 1000)) * 1000;
-  }
-
-  /**
-   * Sets debugging output on or off
-   *
-   * @param bool $debug
-   */
-  public function setDebug($debug) {
-    $this->debug_ = $debug;
-  }
-
-  /**
-   * Get the host that this socket is connected to
-   *
-   * @return string host
-   */
-  public function getHost() {
-    return $this->host_;
-  }
-
-  /**
-   * Get the remote port that this socket is connected to
-   *
-   * @return int port
-   */
-  public function getPort() {
-    return $this->port_;
-  }
-
-  /**
-   * Tests whether this is open
-   *
-   * @return bool true if the socket is open
-   */
-  public function isOpen() {
-    return is_resource($this->handle_);
-  }
-
-  /**
-   * Connects the socket.
-   */
-  public function open() {
-    if ($this->isOpen()) {
-      throw new TTransportException('Socket already connected', TTransportException::ALREADY_OPEN);
-    }
-
-    if (empty($this->host_)) {
-      throw new TTransportException('Cannot open null host', TTransportException::NOT_OPEN);
-    }
-
-    if ($this->port_ <= 0) {
-      throw new TTransportException('Cannot open without port', TTransportException::NOT_OPEN);
-    }
-
-    if ($this->persist_) {
-      $this->handle_ = @pfsockopen($this->host_,
-                                   $this->port_,
-                                   $errno,
-                                   $errstr,
-                                   $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000));
-    } else {
-      $this->handle_ = @fsockopen($this->host_,
-                                  $this->port_,
-                                  $errno,
-                                  $errstr,
-                                  $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000));
-    }
-
-    // Connect failed?
-    if ($this->handle_ === FALSE) {
-      $error = 'TSocket: Could not connect to '.$this->host_.':'.$this->port_.' ('.$errstr.' ['.$errno.'])';
-      if ($this->debug_) {
-        call_user_func($this->debugHandler_, $error);
-      }
-      throw new TException($error);
-    }
-  }
-
-  /**
-   * Closes the socket.
-   */
-  public function close() {
-    if (!$this->persist_) {
-      @fclose($this->handle_);
-      $this->handle_ = null;
-    }
-  }
-
-  /**
-   * Read from the socket at most $len bytes.
-   *
-   * This method will not wait for all the requested data, it will return as
-   * soon as any data is received.
-   *
-   * @param int $len Maximum number of bytes to read.
-   * @return string Binary data
-   */
-  public function read($len) {
-    $null = null;
-    $read = array($this->handle_);
-    $readable = @stream_select($read, $null, $null, $this->recvTimeoutSec_, $this->recvTimeoutUsec_);
-
-    if ($readable > 0) {
-      $data = @stream_socket_recvfrom($this->handle_, $len);
-      if ($data === false) {
-          throw new TTransportException('TSocket: Could not read '.$len.' bytes from '.
-                               $this->host_.':'.$this->port_);
-      } elseif($data == '' && feof($this->handle_)) {
-          throw new TTransportException('TSocket read 0 bytes');
-        }
-
-      return $data;
-    } else if ($readable === 0) {
-        throw new TTransportException('TSocket: timed out reading '.$len.' bytes from '.
-                             $this->host_.':'.$this->port_);
-      } else {
-        throw new TTransportException('TSocket: Could not read '.$len.' bytes from '.
-                             $this->host_.':'.$this->port_);
-      }
-    }
-
-  /**
-   * Write to the socket.
-   *
-   * @param string $buf The data to write
-   */
-  public function write($buf) {
-    $null = null;
-    $write = array($this->handle_);
-
-    // keep writing until all the data has been written
-    while (TStringFuncFactory::create()->strlen($buf) > 0) {
-      // wait for stream to become available for writing
-      $writable = @stream_select($null, $write, $null, $this->sendTimeoutSec_, $this->sendTimeoutUsec_);
-      if ($writable > 0) {
-        // write buffer to stream
-        $written = @stream_socket_sendto($this->handle_, $buf);
-        if ($written === -1 || $written === false) {
-          throw new TTransportException('TSocket: Could not write '.TStringFuncFactory::create()->strlen($buf).' bytes '.
-                                   $this->host_.':'.$this->port_);
-        }
-        // determine how much of the buffer is left to write
-        $buf = TStringFuncFactory::create()->substr($buf, $written);
-      } else if ($writable === 0) {
-          throw new TTransportException('TSocket: timed out writing '.TStringFuncFactory::create()->strlen($buf).' bytes from '.
-                               $this->host_.':'.$this->port_);
-        } else {
-            throw new TTransportException('TSocket: Could not write '.TStringFuncFactory::create()->strlen($buf).' bytes '.
-                                 $this->host_.':'.$this->port_);
-        }
-      }
-    }
-
-  /**
-   * Flush output to the socket.
-   *
-   * Since read(), readAll() and write() operate on the sockets directly,
-   * this is a no-op
-   *
-   * If you wish to have flushable buffering behaviour, wrap this TSocket
-   * in a TBufferedTransport.
-   */
-  public function flush() {
-    // no-op
-    }
-  }
diff --git a/lib/php/lib/Thrift/Transport/TSocketPool.php b/lib/php/lib/Thrift/Transport/TSocketPool.php
deleted file mode 100644
index e1610cb..0000000
--- a/lib/php/lib/Thrift/Transport/TSocketPool.php
+++ /dev/null
@@ -1,295 +0,0 @@
-<?php
-/*
- * 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.transport
- */
-
-namespace Thrift\Transport;
-
-use Thrift\Transport\TSocket;
-use Thrift\Exception\TException;
-
-/**
- * This library makes use of APC cache to make hosts as down in a web
- * environment. If you are running from the CLI or on a system without APC
- * installed, then these null functions will step in and act like cache
- * misses.
- */
-if (!function_exists('apc_fetch')) {
-  function apc_fetch($key) { return FALSE; }
-  function apc_store($key, $var, $ttl=0) { return FALSE; }
-}
-
-/**
- * Sockets implementation of the TTransport interface that allows connection
- * to a pool of servers.
- *
- * @package thrift.transport
- */
-class TSocketPool extends TSocket {
-
-  /**
-   * Remote servers. Array of associative arrays with 'host' and 'port' keys
-   */
-  private $servers_ = array();
-
-  /**
-   * How many times to retry each host in connect
-   *
-   * @var int
-   */
-  private $numRetries_ = 1;
-
-  /**
-   * Retry interval in seconds, how long to not try a host if it has been
-   * marked as down.
-   *
-   * @var int
-   */
-  private $retryInterval_ = 60;
-
-  /**
-   * Max consecutive failures before marking a host down.
-   *
-   * @var int
-   */
-  private $maxConsecutiveFailures_ = 1;
-
-  /**
-   * Try hosts in order? or Randomized?
-   *
-   * @var bool
-   */
-  private $randomize_ = TRUE;
-
-  /**
-   * Always try last host, even if marked down?
-   *
-   * @var bool
-   */
-  private $alwaysTryLast_ = TRUE;
-
-  /**
-   * Socket pool constructor
-   *
-   * @param array  $hosts        List of remote hostnames
-   * @param mixed  $ports        Array of remote ports, or a single common port
-   * @param bool   $persist      Whether to use a persistent socket
-   * @param mixed  $debugHandler Function for error logging
-   */
-  public function __construct($hosts=array('localhost'),
-                              $ports=array(9090),
-                              $persist=FALSE,
-                              $debugHandler=null) {
-    parent::__construct(null, 0, $persist, $debugHandler);
-
-    if (!is_array($ports)) {
-      $port = $ports;
-      $ports = array();
-      foreach ($hosts as $key => $val) {
-        $ports[$key] = $port;
-      }
-    }
-
-    foreach ($hosts as $key => $host) {
-      $this->servers_ []= array('host' => $host,
-                                'port' => $ports[$key]);
-    }
-  }
-
-  /**
-   * Add a server to the pool
-   *
-   * This function does not prevent you from adding a duplicate server entry.
-   *
-   * @param string $host hostname or IP
-   * @param int $port port
-   */
-  public function addServer($host, $port) {
-    $this->servers_[] = array('host' => $host, 'port' => $port);
-  }
-
-  /**
-   * Sets how many time to keep retrying a host in the connect function.
-   *
-   * @param int $numRetries
-   */
-  public function setNumRetries($numRetries) {
-    $this->numRetries_ = $numRetries;
-  }
-
-  /**
-   * Sets how long to wait until retrying a host if it was marked down
-   *
-   * @param int $numRetries
-   */
-  public function setRetryInterval($retryInterval) {
-    $this->retryInterval_ = $retryInterval;
-  }
-
-  /**
-   * Sets how many time to keep retrying a host before marking it as down.
-   *
-   * @param int $numRetries
-   */
-  public function setMaxConsecutiveFailures($maxConsecutiveFailures) {
-    $this->maxConsecutiveFailures_ = $maxConsecutiveFailures;
-  }
-
-  /**
-   * Turns randomization in connect order on or off.
-   *
-   * @param bool $randomize
-   */
-  public function setRandomize($randomize) {
-    $this->randomize_ = $randomize;
-  }
-
-  /**
-   * Whether to always try the last server.
-   *
-   * @param bool $alwaysTryLast
-   */
-  public function setAlwaysTryLast($alwaysTryLast) {
-    $this->alwaysTryLast_ = $alwaysTryLast;
-  }
-
-
-  /**
-   * Connects the socket by iterating through all the servers in the pool
-   * and trying to find one that works.
-   */
-  public function open() {
-    // Check if we want order randomization
-    if ($this->randomize_) {
-      shuffle($this->servers_);
-    }
-
-    // Count servers to identify the "last" one
-    $numServers = count($this->servers_);
-
-    for ($i = 0; $i < $numServers; ++$i) {
-
-      // This extracts the $host and $port variables
-      extract($this->servers_[$i]);
-
-      // Check APC cache for a record of this server being down
-      $failtimeKey = 'thrift_failtime:'.$host.':'.$port.'~';
-
-      // Cache miss? Assume it's OK
-      $lastFailtime = apc_fetch($failtimeKey);
-      if ($lastFailtime === FALSE) {
-        $lastFailtime = 0;
-      }
-
-      $retryIntervalPassed = FALSE;
-
-      // Cache hit...make sure enough the retry interval has elapsed
-      if ($lastFailtime > 0) {
-        $elapsed = time() - $lastFailtime;
-        if ($elapsed > $this->retryInterval_) {
-          $retryIntervalPassed = TRUE;
-          if ($this->debug_) {
-            call_user_func($this->debugHandler_,
-                           'TSocketPool: retryInterval '.
-                           '('.$this->retryInterval_.') '.
-                           'has passed for host '.$host.':'.$port);
-          }
-        }
-      }
-
-      // Only connect if not in the middle of a fail interval, OR if this
-      // is the LAST server we are trying, just hammer away on it
-      $isLastServer = FALSE;
-      if ($this->alwaysTryLast_) {
-        $isLastServer = ($i == ($numServers - 1));
-      }
-
-      if (($lastFailtime === 0) ||
-          ($isLastServer) ||
-          ($lastFailtime > 0 && $retryIntervalPassed)) {
-
-        // Set underlying TSocket params to this one
-        $this->host_ = $host;
-        $this->port_ = $port;
-
-        // Try up to numRetries_ connections per server
-        for ($attempt = 0; $attempt < $this->numRetries_; $attempt++) {
-          try {
-            // Use the underlying TSocket open function
-            parent::open();
-
-            // Only clear the failure counts if required to do so
-            if ($lastFailtime > 0) {
-              apc_store($failtimeKey, 0);
-            }
-
-            // Successful connection, return now
-            return;
-
-          } catch (TException $tx) {
-            // Connection failed
-          }
-        }
-
-        // Mark failure of this host in the cache
-        $consecfailsKey = 'thrift_consecfails:'.$host.':'.$port.'~';
-
-        // Ignore cache misses
-        $consecfails = apc_fetch($consecfailsKey);
-        if ($consecfails === FALSE) {
-          $consecfails = 0;
-        }
-
-        // Increment by one
-        $consecfails++;
-
-        // Log and cache this failure
-        if ($consecfails >= $this->maxConsecutiveFailures_) {
-          if ($this->debug_) {
-            call_user_func($this->debugHandler_,
-                           'TSocketPool: marking '.$host.':'.$port.
-                           ' as down for '.$this->retryInterval_.' secs '.
-                           'after '.$consecfails.' failed attempts.');
-          }
-          // Store the failure time
-          apc_store($failtimeKey, time());
-
-          // Clear the count of consecutive failures
-          apc_store($consecfailsKey, 0);
-        } else {
-          apc_store($consecfailsKey, $consecfails);
-        }
-      }
-    }
-
-    // Oh no; we failed them all. The system is totally ill!
-    $error = 'TSocketPool: All hosts in pool are down. ';
-    $hosts = array();
-    foreach ($this->servers_ as $server) {
-      $hosts []= $server['host'].':'.$server['port'];
-    }
-    $hostlist = implode(',', $hosts);
-    $error .= '('.$hostlist.')';
-    if ($this->debug_) {
-      call_user_func($this->debugHandler_, $error);
-    }
-    throw new TException($error);
-  }
-}
diff --git a/lib/php/lib/Thrift/Transport/TTransport.php b/lib/php/lib/Thrift/Transport/TTransport.php
deleted file mode 100644
index 2e44366..0000000
--- a/lib/php/lib/Thrift/Transport/TTransport.php
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
-/*
- * 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.transport
- */
-
-namespace Thrift\Transport;
-
-use Thrift\Factory\TStringFuncFactory;
-
-/**
- * Base interface for a transport agent.
- *
- * @package thrift.transport
- */
-abstract class TTransport {
-
-  /**
-   * Whether this transport is open.
-   *
-   * @return boolean true if open
-   */
-  public abstract function isOpen();
-
-  /**
-   * Open the transport for reading/writing
-   *
-   * @throws TTransportException if cannot open
-   */
-  public abstract function open();
-
-  /**
-   * Close the transport.
-   */
-  public abstract function close();
-
-  /**
-   * Read some data into the array.
-   *
-   * @param int    $len How much to read
-   * @return string The data that has been read
-   * @throws TTransportException if cannot read any more data
-   */
-  public abstract function read($len);
-
-  /**
-   * Guarantees that the full amount of data is read.
-   *
-   * @return string The data, of exact length
-   * @throws TTransportException if cannot read data
-   */
-  public function readAll($len) {
-    // return $this->read($len);
-
-    $data = '';
-    $got = 0;
-    while (($got = TStringFuncFactory::create()->strlen($data)) < $len) {
-      $data .= $this->read($len - $got);
-    }
-    return $data;
-  }
-
-  /**
-   * Writes the given data out.
-   *
-   * @param string $buf  The data to write
-   * @throws TTransportException if writing fails
-   */
-  public abstract function write($buf);
-
-  /**
-   * Flushes any pending data out of a buffer
-   *
-   * @throws TTransportException if a writing error occurs
-   */
-  public function flush() {}
-}
diff --git a/lib/php/lib/Thrift/Type/TMessageType.php b/lib/php/lib/Thrift/Type/TMessageType.php
deleted file mode 100644
index 681c45c..0000000
--- a/lib/php/lib/Thrift/Type/TMessageType.php
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-/*
- * 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
- */
-
-namespace Thrift\Type;
-
-/**
- * Message types for RPC
- */
-class TMessageType {
-  const CALL  = 1;
-  const REPLY = 2;
-  const EXCEPTION = 3;
-  const ONEWAY = 4;
-}
\ No newline at end of file
diff --git a/lib/php/lib/Thrift/Type/TType.php b/lib/php/lib/Thrift/Type/TType.php
deleted file mode 100644
index c1cf228..0000000
--- a/lib/php/lib/Thrift/Type/TType.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/*
- * 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
- */
-
-namespace Thrift\Type;
-
-/**
- * Data types that can be sent via Thrift
- */
-class TType {
-  const STOP   = 0;
-  const VOID   = 1;
-  const BOOL   = 2;
-  const BYTE   = 3;
-  const I08    = 3;
-  const DOUBLE = 4;
-  const I16    = 6;
-  const I32    = 8;
-  const I64    = 10;
-  const STRING = 11;
-  const UTF7   = 11;
-  const STRUCT = 12;
-  const MAP    = 13;
-  const SET    = 14;
-  const LST    = 15;    // N.B. cannot use LIST keyword in PHP!
-  const UTF8   = 16;
-  const UTF16  = 17;
-}
diff --git a/lib/php/lib/Transport/TBufferedTransport.php b/lib/php/lib/Transport/TBufferedTransport.php
new file mode 100644
index 0000000..253c5ac
--- /dev/null
+++ b/lib/php/lib/Transport/TBufferedTransport.php
@@ -0,0 +1,206 @@
+<?php
+/*
+ * 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.transport
+ */
+
+namespace Thrift\Transport;
+
+use Thrift\Exception\TTransportException;
+use Thrift\Factory\TStringFuncFactory;
+
+/**
+ * Buffered transport. Stores data to an internal buffer that it doesn't
+ * actually write out until flush is called. For reading, we do a greedy
+ * read and then serve data out of the internal buffer.
+ *
+ * @package thrift.transport
+ */
+class TBufferedTransport extends TTransport
+{
+    /**
+     * The underlying transport
+     *
+     * @var TTransport
+     */
+    protected $transport_;
+
+    /**
+     * The receive buffer size
+     *
+     * @var int
+     */
+    protected $rBufSize_ = 512;
+
+    /**
+     * The write buffer size
+     *
+     * @var int
+     */
+    protected $wBufSize_ = 512;
+
+    /**
+     * The write buffer.
+     *
+     * @var string
+     */
+    protected $wBuf_ = '';
+
+    /**
+     * The read buffer.
+     *
+     * @var string
+     */
+    protected $rBuf_ = '';
+
+    /**
+     * Constructor. Creates a buffered transport around an underlying transport
+     */
+    public function __construct($transport, $rBufSize = 512, $wBufSize = 512)
+    {
+        $this->transport_ = $transport;
+        $this->rBufSize_ = $rBufSize;
+        $this->wBufSize_ = $wBufSize;
+    }
+
+    public function isOpen()
+    {
+        return $this->transport_->isOpen();
+    }
+
+    /**
+     * @inheritdoc
+     *
+     * @throws TTransportException
+     */
+    public function open()
+    {
+        $this->transport_->open();
+    }
+
+    public function close()
+    {
+        $this->transport_->close();
+    }
+
+    public function putBack($data)
+    {
+        if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
+            $this->rBuf_ = $data;
+        } else {
+            $this->rBuf_ = ($data . $this->rBuf_);
+        }
+    }
+
+    /**
+     * The reason that we customize readAll here is that the majority of PHP
+     * streams are already internally buffered by PHP. The socket stream, for
+     * example, buffers internally and blocks if you call read with $len greater
+     * than the amount of data available, unlike recv() in C.
+     *
+     * Therefore, use the readAll method of the wrapped transport inside
+     * the buffered readAll.
+     *
+     * @throws TTransportException
+     */
+    public function readAll($len)
+    {
+        $have = TStringFuncFactory::create()->strlen($this->rBuf_);
+        if ($have == 0) {
+            $data = $this->transport_->readAll($len);
+        } elseif ($have < $len) {
+            $data = $this->rBuf_;
+            $this->rBuf_ = '';
+            $data .= $this->transport_->readAll($len - $have);
+        } elseif ($have == $len) {
+            $data = $this->rBuf_;
+            $this->rBuf_ = '';
+        } elseif ($have > $len) {
+            $data = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len);
+            $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len);
+        }
+
+        return $data;
+    }
+
+    /**
+     * @inheritdoc
+     *
+     * @param int $len
+     * @return string
+     * @throws TTransportException
+     */
+    public function read($len)
+    {
+        if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
+            $this->rBuf_ = $this->transport_->read($this->rBufSize_);
+        }
+
+        if (TStringFuncFactory::create()->strlen($this->rBuf_) <= $len) {
+            $ret = $this->rBuf_;
+            $this->rBuf_ = '';
+
+            return $ret;
+        }
+
+        $ret = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len);
+        $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len);
+
+        return $ret;
+    }
+
+    /**
+     * @inheritdoc
+     *
+     * @param string $buf
+     * @throws TTransportException
+     */
+    public function write($buf)
+    {
+        $this->wBuf_ .= $buf;
+        if (TStringFuncFactory::create()->strlen($this->wBuf_) >= $this->wBufSize_) {
+            $out = $this->wBuf_;
+
+            // Note that we clear the internal wBuf_ prior to the underlying write
+            // to ensure we're in a sane state (i.e. internal buffer cleaned)
+            // if the underlying write throws up an exception
+            $this->wBuf_ = '';
+            $this->transport_->write($out);
+        }
+    }
+
+    /**
+     * @inheritdoc
+     *
+     * @throws TTransportException
+     */
+    public function flush()
+    {
+        if (TStringFuncFactory::create()->strlen($this->wBuf_) > 0) {
+            $out = $this->wBuf_;
+
+            // Note that we clear the internal wBuf_ prior to the underlying write
+            // to ensure we're in a sane state (i.e. internal buffer cleaned)
+            // if the underlying write throws up an exception
+            $this->wBuf_ = '';
+            $this->transport_->write($out);
+        }
+        $this->transport_->flush();
+    }
+}
diff --git a/lib/php/lib/Transport/TCurlClient.php b/lib/php/lib/Transport/TCurlClient.php
new file mode 100644
index 0000000..482b43b
--- /dev/null
+++ b/lib/php/lib/Transport/TCurlClient.php
@@ -0,0 +1,276 @@
+<?php
+/*
+ * 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.transport
+ */
+
+namespace Thrift\Transport;
+
+use Thrift\Exception\TTransportException;
+use Thrift\Factory\TStringFuncFactory;
+
+/**
+ * HTTP client for Thrift
+ *
+ * @package thrift.transport
+ */
+class TCurlClient extends TTransport
+{
+    private static $curlHandle;
+
+    /**
+     * The host to connect to
+     *
+     * @var string
+     */
+    protected $host_;
+
+    /**
+     * The port to connect on
+     *
+     * @var int
+     */
+    protected $port_;
+
+    /**
+     * The URI to request
+     *
+     * @var string
+     */
+    protected $uri_;
+
+    /**
+     * The scheme to use for the request, i.e. http, https
+     *
+     * @var string
+     */
+    protected $scheme_;
+
+    /**
+     * Buffer for the HTTP request data
+     *
+     * @var string
+     */
+    protected $request_;
+
+    /**
+     * Buffer for the HTTP response data.
+     *
+     * @var binary string
+     */
+    protected $response_;
+
+    /**
+     * Read timeout
+     *
+     * @var float
+     */
+    protected $timeout_;
+
+    /**
+     * http headers
+     *
+     * @var array
+     */
+    protected $headers_;
+
+    /**
+     * Make a new HTTP client.
+     *
+     * @param string $host
+     * @param int $port
+     * @param string $uri
+     */
+    public function __construct($host, $port = 80, $uri = '', $scheme = 'http')
+    {
+        if ((TStringFuncFactory::create()->strlen($uri) > 0) && ($uri{0} != '/')) {
+            $uri = '/' . $uri;
+        }
+        $this->scheme_ = $scheme;
+        $this->host_ = $host;
+        $this->port_ = $port;
+        $this->uri_ = $uri;
+        $this->request_ = '';
+        $this->response_ = null;
+        $this->timeout_ = null;
+        $this->headers_ = array();
+    }
+
+    /**
+     * Set read timeout
+     *
+     * @param float $timeout
+     */
+    public function setTimeoutSecs($timeout)
+    {
+        $this->timeout_ = $timeout;
+    }
+
+    /**
+     * Whether this transport is open.
+     *
+     * @return boolean true if open
+     */
+    public function isOpen()
+    {
+        return true;
+    }
+
+    /**
+     * Open the transport for reading/writing
+     *
+     * @throws TTransportException if cannot open
+     */
+    public function open()
+    {
+    }
+
+    /**
+     * Close the transport.
+     */
+    public function close()
+    {
+        $this->request_ = '';
+        $this->response_ = null;
+    }
+
+    /**
+     * Read some data into the array.
+     *
+     * @param int $len How much to read
+     * @return string The data that has been read
+     * @throws TTransportException if cannot read any more data
+     */
+    public function read($len)
+    {
+        if ($len >= strlen($this->response_)) {
+            return $this->response_;
+        } else {
+            $ret = substr($this->response_, 0, $len);
+            $this->response_ = substr($this->response_, $len);
+
+            return $ret;
+        }
+    }
+
+    /**
+     * Guarantees that the full amount of data is read. Since TCurlClient gets entire payload at
+     * once, parent readAll cannot be used.
+     *
+     * @return string The data, of exact length
+     * @throws TTransportException if cannot read data
+     */
+    public function readAll($len)
+    {
+        $data = $this->read($len);
+
+        if (TStringFuncFactory::create()->strlen($data) !== $len) {
+            throw new TTransportException('TCurlClient could not read '.$len.' bytes');
+        }
+
+        return $data;
+    }
+
+    /**
+     * Writes some data into the pending buffer
+     *
+     * @param string $buf The data to write
+     * @throws TTransportException if writing fails
+     */
+    public function write($buf)
+    {
+        $this->request_ .= $buf;
+    }
+
+    /**
+     * Opens and sends the actual request over the HTTP connection
+     *
+     * @throws TTransportException if a writing error occurs
+     */
+    public function flush()
+    {
+        if (!self::$curlHandle) {
+            register_shutdown_function(array('Thrift\\Transport\\TCurlClient', 'closeCurlHandle'));
+            self::$curlHandle = curl_init();
+            curl_setopt(self::$curlHandle, CURLOPT_RETURNTRANSFER, true);
+            curl_setopt(self::$curlHandle, CURLOPT_BINARYTRANSFER, true);
+            curl_setopt(self::$curlHandle, CURLOPT_USERAGENT, 'PHP/TCurlClient');
+            curl_setopt(self::$curlHandle, CURLOPT_CUSTOMREQUEST, 'POST');
+            curl_setopt(self::$curlHandle, CURLOPT_FOLLOWLOCATION, true);
+            curl_setopt(self::$curlHandle, CURLOPT_MAXREDIRS, 1);
+        }
+        // God, PHP really has some esoteric ways of doing simple things.
+        $host = $this->host_ . ($this->port_ != 80 ? ':' . $this->port_ : '');
+        $fullUrl = $this->scheme_ . "://" . $host . $this->uri_;
+
+        $headers = array();
+        $defaultHeaders = array('Accept' => 'application/x-thrift',
+            'Content-Type' => 'application/x-thrift',
+            'Content-Length' => TStringFuncFactory::create()->strlen($this->request_));
+        foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) {
+            $headers[] = "$key: $value";
+        }
+
+        curl_setopt(self::$curlHandle, CURLOPT_HTTPHEADER, $headers);
+
+        if ($this->timeout_ > 0) {
+            curl_setopt(self::$curlHandle, CURLOPT_TIMEOUT, $this->timeout_);
+        }
+        curl_setopt(self::$curlHandle, CURLOPT_POSTFIELDS, $this->request_);
+        $this->request_ = '';
+
+        curl_setopt(self::$curlHandle, CURLOPT_URL, $fullUrl);
+        $this->response_ = curl_exec(self::$curlHandle);
+        $responseError = curl_error(self::$curlHandle);
+
+        $code = curl_getinfo(self::$curlHandle, CURLINFO_HTTP_CODE);
+
+        // Handle non 200 status code / connect failure
+        if ($this->response_ === false || $code !== 200) {
+            curl_close(self::$curlHandle);
+            self::$curlHandle = null;
+            $this->response_ = null;
+            $error = 'TCurlClient: Could not connect to ' . $fullUrl;
+            if ($responseError) {
+                $error .= ', ' . $responseError;
+            }
+            if ($code) {
+                $error .= ', HTTP status code: ' . $code;
+            }
+            throw new TTransportException($error, TTransportException::UNKNOWN);
+        }
+    }
+
+    public static function closeCurlHandle()
+    {
+        try {
+            if (self::$curlHandle) {
+                curl_close(self::$curlHandle);
+                self::$curlHandle = null;
+            }
+        } catch (\Exception $x) {
+            error_log('There was an error closing the curl handle: ' . $x->getMessage());
+        }
+    }
+
+    public function addHeaders($headers)
+    {
+        $this->headers_ = array_merge($this->headers_, $headers);
+    }
+}
diff --git a/lib/php/lib/Transport/TFramedTransport.php b/lib/php/lib/Transport/TFramedTransport.php
new file mode 100644
index 0000000..39d1869
--- /dev/null
+++ b/lib/php/lib/Transport/TFramedTransport.php
@@ -0,0 +1,192 @@
+<?php
+/*
+ * 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.transport
+ */
+
+namespace Thrift\Transport;
+
+use Thrift\Factory\TStringFuncFactory;
+
+/**
+ * Framed transport. Writes and reads data in chunks that are stamped with
+ * their length.
+ *
+ * @package thrift.transport
+ */
+class TFramedTransport extends TTransport
+{
+    /**
+     * Underlying transport object.
+     *
+     * @var TTransport
+     */
+    private $transport_;
+
+    /**
+     * Buffer for read data.
+     *
+     * @var string
+     */
+    private $rBuf_;
+
+    /**
+     * Buffer for queued output data
+     *
+     * @var string
+     */
+    private $wBuf_;
+
+    /**
+     * Whether to frame reads
+     *
+     * @var bool
+     */
+    private $read_;
+
+    /**
+     * Whether to frame writes
+     *
+     * @var bool
+     */
+    private $write_;
+
+    /**
+     * Constructor.
+     *
+     * @param TTransport $transport Underlying transport
+     */
+    public function __construct($transport = null, $read = true, $write = true)
+    {
+        $this->transport_ = $transport;
+        $this->read_ = $read;
+        $this->write_ = $write;
+    }
+
+    public function isOpen()
+    {
+        return $this->transport_->isOpen();
+    }
+
+    public function open()
+    {
+        $this->transport_->open();
+    }
+
+    public function close()
+    {
+        $this->transport_->close();
+    }
+
+    /**
+     * Reads from the buffer. When more data is required reads another entire
+     * chunk and serves future reads out of that.
+     *
+     * @param int $len How much data
+     */
+    public function read($len)
+    {
+        if (!$this->read_) {
+            return $this->transport_->read($len);
+        }
+
+        if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
+            $this->readFrame();
+        }
+
+        // Just return full buff
+        if ($len >= TStringFuncFactory::create()->strlen($this->rBuf_)) {
+            $out = $this->rBuf_;
+            $this->rBuf_ = null;
+
+            return $out;
+        }
+
+        // Return TStringFuncFactory::create()->substr
+        $out = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len);
+        $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len);
+
+        return $out;
+    }
+
+    /**
+     * Put previously read data back into the buffer
+     *
+     * @param string $data data to return
+     */
+    public function putBack($data)
+    {
+        if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
+            $this->rBuf_ = $data;
+        } else {
+            $this->rBuf_ = ($data . $this->rBuf_);
+        }
+    }
+
+    /**
+     * Reads a chunk of data into the internal read buffer.
+     */
+    private function readFrame()
+    {
+        $buf = $this->transport_->readAll(4);
+        $val = unpack('N', $buf);
+        $sz = $val[1];
+
+        $this->rBuf_ = $this->transport_->readAll($sz);
+    }
+
+    /**
+     * Writes some data to the pending output buffer.
+     *
+     * @param string $buf The data
+     * @param int $len Limit of bytes to write
+     */
+    public function write($buf, $len = null)
+    {
+        if (!$this->write_) {
+            return $this->transport_->write($buf, $len);
+        }
+
+        if ($len !== null && $len < TStringFuncFactory::create()->strlen($buf)) {
+            $buf = TStringFuncFactory::create()->substr($buf, 0, $len);
+        }
+        $this->wBuf_ .= $buf;
+    }
+
+    /**
+     * Writes the output buffer to the stream in the format of a 4-byte length
+     * followed by the actual data.
+     */
+    public function flush()
+    {
+        if (!$this->write_ || TStringFuncFactory::create()->strlen($this->wBuf_) == 0) {
+            return $this->transport_->flush();
+        }
+
+        $out = pack('N', TStringFuncFactory::create()->strlen($this->wBuf_));
+        $out .= $this->wBuf_;
+
+        // Note that we clear the internal wBuf_ prior to the underlying write
+        // to ensure we're in a sane state (i.e. internal buffer cleaned)
+        // if the underlying write throws up an exception
+        $this->wBuf_ = '';
+        $this->transport_->write($out);
+        $this->transport_->flush();
+    }
+}
diff --git a/lib/php/lib/Transport/THttpClient.php b/lib/php/lib/Transport/THttpClient.php
new file mode 100644
index 0000000..0158809
--- /dev/null
+++ b/lib/php/lib/Transport/THttpClient.php
@@ -0,0 +1,258 @@
+<?php
+/*
+ * 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.transport
+ */
+
+namespace Thrift\Transport;
+
+use Thrift\Exception\TTransportException;
+use Thrift\Factory\TStringFuncFactory;
+
+/**
+ * HTTP client for Thrift
+ *
+ * @package thrift.transport
+ */
+class THttpClient extends TTransport
+{
+    /**
+     * The host to connect to
+     *
+     * @var string
+     */
+    protected $host_;
+
+    /**
+     * The port to connect on
+     *
+     * @var int
+     */
+    protected $port_;
+
+    /**
+     * The URI to request
+     *
+     * @var string
+     */
+    protected $uri_;
+
+    /**
+     * The scheme to use for the request, i.e. http, https
+     *
+     * @var string
+     */
+    protected $scheme_;
+
+    /**
+     * Buffer for the HTTP request data
+     *
+     * @var string
+     */
+    protected $buf_;
+
+    /**
+     * Input socket stream.
+     *
+     * @var resource
+     */
+    protected $handle_;
+
+    /**
+     * Read timeout
+     *
+     * @var float
+     */
+    protected $timeout_;
+
+    /**
+     * http headers
+     *
+     * @var array
+     */
+    protected $headers_;
+
+    /**
+     * Context additional options
+     *
+     * @var array
+     */
+    protected $context_;
+
+    /**
+     * Make a new HTTP client.
+     *
+     * @param string $host
+     * @param int    $port
+     * @param string $uri
+     * @param string $scheme
+     * @param array  $context
+     */
+    public function __construct($host, $port = 80, $uri = '', $scheme = 'http', array $context = array())
+    {
+        if ((TStringFuncFactory::create()->strlen($uri) > 0) && ($uri{0} != '/')) {
+            $uri = '/' . $uri;
+        }
+        $this->scheme_ = $scheme;
+        $this->host_ = $host;
+        $this->port_ = $port;
+        $this->uri_ = $uri;
+        $this->buf_ = '';
+        $this->handle_ = null;
+        $this->timeout_ = null;
+        $this->headers_ = array();
+        $this->context_ = $context;
+    }
+
+    /**
+     * Set read timeout
+     *
+     * @param float $timeout
+     */
+    public function setTimeoutSecs($timeout)
+    {
+        $this->timeout_ = $timeout;
+    }
+
+    /**
+     * Whether this transport is open.
+     *
+     * @return boolean true if open
+     */
+    public function isOpen()
+    {
+        return true;
+    }
+
+    /**
+     * Open the transport for reading/writing
+     *
+     * @throws TTransportException if cannot open
+     */
+    public function open()
+    {
+    }
+
+    /**
+     * Close the transport.
+     */
+    public function close()
+    {
+        if ($this->handle_) {
+            @fclose($this->handle_);
+            $this->handle_ = null;
+        }
+    }
+
+    /**
+     * Read some data into the array.
+     *
+     * @param int $len How much to read
+     * @return string The data that has been read
+     * @throws TTransportException if cannot read any more data
+     */
+    public function read($len)
+    {
+        $data = @fread($this->handle_, $len);
+        if ($data === false || $data === '') {
+            $md = stream_get_meta_data($this->handle_);
+            if ($md['timed_out']) {
+                throw new TTransportException(
+                    'THttpClient: timed out reading ' . $len . ' bytes from ' .
+                    $this->host_ . ':' . $this->port_ . $this->uri_,
+                    TTransportException::TIMED_OUT
+                );
+            } else {
+                throw new TTransportException(
+                    'THttpClient: Could not read ' . $len . ' bytes from ' .
+                    $this->host_ . ':' . $this->port_ . $this->uri_,
+                    TTransportException::UNKNOWN
+                );
+            }
+        }
+
+        return $data;
+    }
+
+    /**
+     * Writes some data into the pending buffer
+     *
+     * @param string $buf The data to write
+     * @throws TTransportException if writing fails
+     */
+    public function write($buf)
+    {
+        $this->buf_ .= $buf;
+    }
+
+    /**
+     * Opens and sends the actual request over the HTTP connection
+     *
+     * @throws TTransportException if a writing error occurs
+     */
+    public function flush()
+    {
+        // God, PHP really has some esoteric ways of doing simple things.
+        $host = $this->host_ . ($this->port_ != 80 ? ':' . $this->port_ : '');
+
+        $headers = array();
+        $defaultHeaders = array('Host' => $host,
+            'Accept' => 'application/x-thrift',
+            'User-Agent' => 'PHP/THttpClient',
+            'Content-Type' => 'application/x-thrift',
+            'Content-Length' => TStringFuncFactory::create()->strlen($this->buf_));
+        foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) {
+            $headers[] = "$key: $value";
+        }
+
+        $options = $this->context_;
+
+        $baseHttpOptions = isset($options["http"]) ? $options["http"] : array();
+
+        $httpOptions = $baseHttpOptions + array('method' => 'POST',
+            'header' => implode("\r\n", $headers),
+            'max_redirects' => 1,
+            'content' => $this->buf_);
+        if ($this->timeout_ > 0) {
+            $httpOptions['timeout'] = $this->timeout_;
+        }
+        $this->buf_ = '';
+
+        $options["http"] = $httpOptions;
+        $contextid = stream_context_create($options);
+        $this->handle_ = @fopen(
+            $this->scheme_ . '://' . $host . $this->uri_,
+            'r',
+            false,
+            $contextid
+        );
+
+        // Connect failed?
+        if ($this->handle_ === false) {
+            $this->handle_ = null;
+            $error = 'THttpClient: Could not connect to ' . $host . $this->uri_;
+            throw new TTransportException($error, TTransportException::NOT_OPEN);
+        }
+    }
+
+    public function addHeaders($headers)
+    {
+        $this->headers_ = array_merge($this->headers_, $headers);
+    }
+}
diff --git a/lib/php/lib/Transport/TMemoryBuffer.php b/lib/php/lib/Transport/TMemoryBuffer.php
new file mode 100644
index 0000000..fee03a2
--- /dev/null
+++ b/lib/php/lib/Transport/TMemoryBuffer.php
@@ -0,0 +1,106 @@
+<?php
+/*
+ * 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.transport
+ */
+
+namespace Thrift\Transport;
+
+use Thrift\Exception\TTransportException;
+use Thrift\Factory\TStringFuncFactory;
+
+/**
+ * A memory buffer is a tranpsort that simply reads from and writes to an
+ * in-memory string buffer. Anytime you call write on it, the data is simply
+ * placed into a buffer, and anytime you call read, data is read from that
+ * buffer.
+ *
+ * @package thrift.transport
+ */
+class TMemoryBuffer extends TTransport
+{
+    /**
+     * Constructor. Optionally pass an initial value
+     * for the buffer.
+     */
+    public function __construct($buf = '')
+    {
+        $this->buf_ = $buf;
+    }
+
+    protected $buf_ = '';
+
+    public function isOpen()
+    {
+        return true;
+    }
+
+    public function open()
+    {
+    }
+
+    public function close()
+    {
+    }
+
+    public function write($buf)
+    {
+        $this->buf_ .= $buf;
+    }
+
+    public function read($len)
+    {
+        $bufLength = TStringFuncFactory::create()->strlen($this->buf_);
+
+        if ($bufLength === 0) {
+            throw new TTransportException(
+                'TMemoryBuffer: Could not read ' .
+                $len . ' bytes from buffer.',
+                TTransportException::UNKNOWN
+            );
+        }
+
+        if ($bufLength <= $len) {
+            $ret = $this->buf_;
+            $this->buf_ = '';
+
+            return $ret;
+        }
+
+        $ret = TStringFuncFactory::create()->substr($this->buf_, 0, $len);
+        $this->buf_ = TStringFuncFactory::create()->substr($this->buf_, $len);
+
+        return $ret;
+    }
+
+    public function getBuffer()
+    {
+        return $this->buf_;
+    }
+
+    public function available()
+    {
+        return TStringFuncFactory::create()->strlen($this->buf_);
+    }
+
+    public function putBack($data)
+    {
+        $this->buf_ = $data . $this->buf_;
+    }
+}
diff --git a/lib/php/lib/Transport/TNullTransport.php b/lib/php/lib/Transport/TNullTransport.php
new file mode 100644
index 0000000..7e086b6
--- /dev/null
+++ b/lib/php/lib/Transport/TNullTransport.php
@@ -0,0 +1,56 @@
+<?php
+/*
+ * 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.transport
+ */
+
+namespace Thrift\Transport;
+
+use Thrift\Exception\TTransportException;
+
+/**
+ * Transport that only accepts writes and ignores them.
+ * This is useful for measuring the serialized size of structures.
+ *
+ * @package thrift.transport
+ */
+class TNullTransport extends TTransport
+{
+    public function isOpen()
+    {
+        return true;
+    }
+
+    public function open()
+    {
+    }
+
+    public function close()
+    {
+    }
+
+    public function read($len)
+    {
+        throw new TTransportException("Can't read from TNullTransport.");
+    }
+
+    public function write($buf)
+    {
+    }
+}
diff --git a/lib/php/lib/Transport/TPhpStream.php b/lib/php/lib/Transport/TPhpStream.php
new file mode 100644
index 0000000..42823ff
--- /dev/null
+++ b/lib/php/lib/Transport/TPhpStream.php
@@ -0,0 +1,124 @@
+<?php
+/*
+ * 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.transport
+ */
+
+namespace Thrift\Transport;
+
+use Thrift\Exception\TException;
+use Thrift\Factory\TStringFuncFactory;
+
+/**
+ * Php stream transport. Reads to and writes from the php standard streams
+ * php://input and php://output
+ *
+ * @package thrift.transport
+ */
+class TPhpStream extends TTransport
+{
+    const MODE_R = 1;
+    const MODE_W = 2;
+
+    private $inStream_ = null;
+
+    private $outStream_ = null;
+
+    private $read_ = false;
+
+    private $write_ = false;
+
+    public function __construct($mode)
+    {
+        $this->read_ = $mode & self::MODE_R;
+        $this->write_ = $mode & self::MODE_W;
+    }
+
+    public function open()
+    {
+        if ($this->read_) {
+            $this->inStream_ = @fopen(self::inStreamName(), 'r');
+            if (!is_resource($this->inStream_)) {
+                throw new TException('TPhpStream: Could not open php://input');
+            }
+        }
+        if ($this->write_) {
+            $this->outStream_ = @fopen('php://output', 'w');
+            if (!is_resource($this->outStream_)) {
+                throw new TException('TPhpStream: Could not open php://output');
+            }
+        }
+    }
+
+    public function close()
+    {
+        if ($this->read_) {
+            @fclose($this->inStream_);
+            $this->inStream_ = null;
+        }
+        if ($this->write_) {
+            @fclose($this->outStream_);
+            $this->outStream_ = null;
+        }
+    }
+
+    public function isOpen()
+    {
+        return
+            (!$this->read_ || is_resource($this->inStream_)) &&
+            (!$this->write_ || is_resource($this->outStream_));
+    }
+
+    public function read($len)
+    {
+        $data = @fread($this->inStream_, $len);
+        if ($data === false || $data === '') {
+            throw new TException('TPhpStream: Could not read ' . $len . ' bytes');
+        }
+
+        return $data;
+    }
+
+    public function write($buf)
+    {
+        while (TStringFuncFactory::create()->strlen($buf) > 0) {
+            $got = @fwrite($this->outStream_, $buf);
+            if ($got === 0 || $got === false) {
+                throw new TException(
+                    'TPhpStream: Could not write ' . TStringFuncFactory::create()->strlen($buf) . ' bytes'
+                );
+            }
+            $buf = TStringFuncFactory::create()->substr($buf, $got);
+        }
+    }
+
+    public function flush()
+    {
+        @fflush($this->outStream_);
+    }
+
+    private static function inStreamName()
+    {
+        if (php_sapi_name() == 'cli') {
+            return 'php://stdin';
+        }
+
+        return 'php://input';
+    }
+}
diff --git a/lib/php/lib/Transport/TSSLSocket.php b/lib/php/lib/Transport/TSSLSocket.php
new file mode 100644
index 0000000..b4a0adb
--- /dev/null
+++ b/lib/php/lib/Transport/TSSLSocket.php
@@ -0,0 +1,117 @@
+<?php
+/*
+ * 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.transport
+ */
+
+namespace Thrift\Transport;
+
+use Thrift\Exception\TException;
+use Thrift\Exception\TTransportException;
+use Thrift\Factory\TStringFuncFactory;
+
+/**
+ * Sockets implementation of the TTransport interface.
+ *
+ * @package thrift.transport
+ */
+class TSSLSocket extends TSocket
+{
+    /**
+     * Remote port
+     *
+     * @var resource
+     */
+    protected $context_ = null;
+
+    /**
+     * Socket constructor
+     *
+     * @param string $host Remote hostname
+     * @param int $port Remote port
+     * @param resource $context Stream context
+     * @param bool $persist Whether to use a persistent socket
+     * @param string $debugHandler Function to call for error logging
+     */
+    public function __construct(
+        $host = 'localhost',
+        $port = 9090,
+        $context = null,
+        $debugHandler = null
+    ) {
+        $this->host_ = $this->getSSLHost($host);
+        $this->port_ = $port;
+        $this->context_ = $context;
+        $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log';
+    }
+
+    /**
+     * Creates a host name with SSL transport protocol
+     * if no transport protocol already specified in
+     * the host name.
+     *
+     * @param string $host Host to listen on
+     * @return string $host   Host name with transport protocol
+     */
+    private function getSSLHost($host)
+    {
+        $transport_protocol_loc = strpos($host, "://");
+        if ($transport_protocol_loc === false) {
+            $host = 'ssl://' . $host;
+        }
+        return $host;
+    }
+
+    /**
+     * Connects the socket.
+     */
+    public function open()
+    {
+        if ($this->isOpen()) {
+            throw new TTransportException('Socket already connected', TTransportException::ALREADY_OPEN);
+        }
+
+        if (empty($this->host_)) {
+            throw new TTransportException('Cannot open null host', TTransportException::NOT_OPEN);
+        }
+
+        if ($this->port_ <= 0) {
+            throw new TTransportException('Cannot open without port', TTransportException::NOT_OPEN);
+        }
+
+        $this->handle_ = @stream_socket_client(
+            $this->host_ . ':' . $this->port_,
+            $errno,
+            $errstr,
+            $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000),
+            STREAM_CLIENT_CONNECT,
+            $this->context_
+        );
+
+        // Connect failed?
+        if ($this->handle_ === false) {
+            $error = 'TSocket: Could not connect to ' .
+                $this->host_ . ':' . $this->port_ . ' (' . $errstr . ' [' . $errno . '])';
+            if ($this->debug_) {
+                call_user_func($this->debugHandler_, $error);
+            }
+            throw new TException($error);
+        }
+    }
+}
diff --git a/lib/php/lib/Transport/TSocket.php b/lib/php/lib/Transport/TSocket.php
new file mode 100644
index 0000000..5147efa
--- /dev/null
+++ b/lib/php/lib/Transport/TSocket.php
@@ -0,0 +1,366 @@
+<?php
+/*
+ * 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.transport
+ */
+
+namespace Thrift\Transport;
+
+use Thrift\Exception\TException;
+use Thrift\Exception\TTransportException;
+use Thrift\Factory\TStringFuncFactory;
+
+/**
+ * Sockets implementation of the TTransport interface.
+ *
+ * @package thrift.transport
+ */
+class TSocket extends TTransport
+{
+    /**
+     * Handle to PHP socket
+     *
+     * @var resource
+     */
+    protected $handle_ = null;
+
+    /**
+     * Remote hostname
+     *
+     * @var string
+     */
+    protected $host_ = 'localhost';
+
+    /**
+     * Remote port
+     *
+     * @var int
+     */
+    protected $port_ = '9090';
+
+    /**
+     * Send timeout in seconds.
+     *
+     * Combined with sendTimeoutUsec this is used for send timeouts.
+     *
+     * @var int
+     */
+    protected $sendTimeoutSec_ = 0;
+
+    /**
+     * Send timeout in microseconds.
+     *
+     * Combined with sendTimeoutSec this is used for send timeouts.
+     *
+     * @var int
+     */
+    protected $sendTimeoutUsec_ = 100000;
+
+    /**
+     * Recv timeout in seconds
+     *
+     * Combined with recvTimeoutUsec this is used for recv timeouts.
+     *
+     * @var int
+     */
+    protected $recvTimeoutSec_ = 0;
+
+    /**
+     * Recv timeout in microseconds
+     *
+     * Combined with recvTimeoutSec this is used for recv timeouts.
+     *
+     * @var int
+     */
+    protected $recvTimeoutUsec_ = 750000;
+
+    /**
+     * Persistent socket or plain?
+     *
+     * @var bool
+     */
+    protected $persist_ = false;
+
+    /**
+     * Debugging on?
+     *
+     * @var bool
+     */
+    protected $debug_ = false;
+
+    /**
+     * Debug handler
+     *
+     * @var mixed
+     */
+    protected $debugHandler_ = null;
+
+    /**
+     * Socket constructor
+     *
+     * @param string $host Remote hostname
+     * @param int $port Remote port
+     * @param bool $persist Whether to use a persistent socket
+     * @param string $debugHandler Function to call for error logging
+     */
+    public function __construct(
+        $host = 'localhost',
+        $port = 9090,
+        $persist = false,
+        $debugHandler = null
+    ) {
+        $this->host_ = $host;
+        $this->port_ = $port;
+        $this->persist_ = $persist;
+        $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log';
+    }
+
+    /**
+     * @param resource $handle
+     * @return void
+     */
+    public function setHandle($handle)
+    {
+        $this->handle_ = $handle;
+        stream_set_blocking($this->handle_, false);
+    }
+
+    /**
+     * Sets the send timeout.
+     *
+     * @param int $timeout Timeout in milliseconds.
+     */
+    public function setSendTimeout($timeout)
+    {
+        $this->sendTimeoutSec_ = floor($timeout / 1000);
+        $this->sendTimeoutUsec_ =
+            ($timeout - ($this->sendTimeoutSec_ * 1000)) * 1000;
+    }
+
+    /**
+     * Sets the receive timeout.
+     *
+     * @param int $timeout Timeout in milliseconds.
+     */
+    public function setRecvTimeout($timeout)
+    {
+        $this->recvTimeoutSec_ = floor($timeout / 1000);
+        $this->recvTimeoutUsec_ =
+            ($timeout - ($this->recvTimeoutSec_ * 1000)) * 1000;
+    }
+
+    /**
+     * Sets debugging output on or off
+     *
+     * @param bool $debug
+     */
+    public function setDebug($debug)
+    {
+        $this->debug_ = $debug;
+    }
+
+    /**
+     * Get the host that this socket is connected to
+     *
+     * @return string host
+     */
+    public function getHost()
+    {
+        return $this->host_;
+    }
+
+    /**
+     * Get the remote port that this socket is connected to
+     *
+     * @return int port
+     */
+    public function getPort()
+    {
+        return $this->port_;
+    }
+
+    /**
+     * Tests whether this is open
+     *
+     * @return bool true if the socket is open
+     */
+    public function isOpen()
+    {
+        return is_resource($this->handle_);
+    }
+
+    /**
+     * Connects the socket.
+     */
+    public function open()
+    {
+        if ($this->isOpen()) {
+            throw new TTransportException('Socket already connected', TTransportException::ALREADY_OPEN);
+        }
+
+        if (empty($this->host_)) {
+            throw new TTransportException('Cannot open null host', TTransportException::NOT_OPEN);
+        }
+
+        if ($this->port_ <= 0) {
+            throw new TTransportException('Cannot open without port', TTransportException::NOT_OPEN);
+        }
+
+        if ($this->persist_) {
+            $this->handle_ = @pfsockopen(
+                $this->host_,
+                $this->port_,
+                $errno,
+                $errstr,
+                $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000)
+            );
+        } else {
+            $this->handle_ = @fsockopen(
+                $this->host_,
+                $this->port_,
+                $errno,
+                $errstr,
+                $this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000)
+            );
+        }
+
+        // Connect failed?
+        if ($this->handle_ === false) {
+            $error = 'TSocket: Could not connect to ' .
+                $this->host_ . ':' . $this->port_ . ' (' . $errstr . ' [' . $errno . '])';
+            if ($this->debug_) {
+                call_user_func($this->debugHandler_, $error);
+            }
+            throw new TException($error);
+        }
+
+        if (function_exists('socket_import_stream') && function_exists('socket_set_option')) {
+            $socket = socket_import_stream($this->handle_);
+            socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1);
+        }
+    }
+
+    /**
+     * Closes the socket.
+     */
+    public function close()
+    {
+        @fclose($this->handle_);
+        $this->handle_ = null;
+    }
+
+    /**
+     * Read from the socket at most $len bytes.
+     *
+     * This method will not wait for all the requested data, it will return as
+     * soon as any data is received.
+     *
+     * @param int $len Maximum number of bytes to read.
+     * @return string Binary data
+     */
+    public function read($len)
+    {
+        $null = null;
+        $read = array($this->handle_);
+        $readable = @stream_select(
+            $read,
+            $null,
+            $null,
+            $this->recvTimeoutSec_,
+            $this->recvTimeoutUsec_
+        );
+
+        if ($readable > 0) {
+            $data = fread($this->handle_, $len);
+            if ($data === false) {
+                throw new TTransportException('TSocket: Could not read ' . $len . ' bytes from ' .
+                    $this->host_ . ':' . $this->port_);
+            } elseif ($data == '' && feof($this->handle_)) {
+                throw new TTransportException('TSocket read 0 bytes');
+            }
+
+            return $data;
+        } elseif ($readable === 0) {
+            throw new TTransportException('TSocket: timed out reading ' . $len . ' bytes from ' .
+                $this->host_ . ':' . $this->port_);
+        } else {
+            throw new TTransportException('TSocket: Could not read ' . $len . ' bytes from ' .
+                $this->host_ . ':' . $this->port_);
+        }
+    }
+
+    /**
+     * Write to the socket.
+     *
+     * @param string $buf The data to write
+     */
+    public function write($buf)
+    {
+        $null = null;
+        $write = array($this->handle_);
+
+        // keep writing until all the data has been written
+        while (TStringFuncFactory::create()->strlen($buf) > 0) {
+            // wait for stream to become available for writing
+            $writable = @stream_select(
+                $null,
+                $write,
+                $null,
+                $this->sendTimeoutSec_,
+                $this->sendTimeoutUsec_
+            );
+            if ($writable > 0) {
+                // write buffer to stream
+                $written = fwrite($this->handle_, $buf);
+                if ($written === -1 || $written === false) {
+                    throw new TTransportException(
+                        'TSocket: Could not write ' . TStringFuncFactory::create()->strlen($buf) . ' bytes ' .
+                        $this->host_ . ':' . $this->port_
+                    );
+                }
+                // determine how much of the buffer is left to write
+                $buf = TStringFuncFactory::create()->substr($buf, $written);
+            } elseif ($writable === 0) {
+                throw new TTransportException(
+                    'TSocket: timed out writing ' . TStringFuncFactory::create()->strlen($buf) . ' bytes from ' .
+                    $this->host_ . ':' . $this->port_
+                );
+            } else {
+                throw new TTransportException(
+                    'TSocket: Could not write ' . TStringFuncFactory::create()->strlen($buf) . ' bytes ' .
+                    $this->host_ . ':' . $this->port_
+                );
+            }
+        }
+    }
+
+    /**
+     * Flush output to the socket.
+     *
+     * Since read(), readAll() and write() operate on the sockets directly,
+     * this is a no-op
+     *
+     * If you wish to have flushable buffering behaviour, wrap this TSocket
+     * in a TBufferedTransport.
+     */
+    public function flush()
+    {
+        // no-op
+    }
+}
diff --git a/lib/php/lib/Transport/TSocketPool.php b/lib/php/lib/Transport/TSocketPool.php
new file mode 100644
index 0000000..cb9e8dd
--- /dev/null
+++ b/lib/php/lib/Transport/TSocketPool.php
@@ -0,0 +1,310 @@
+<?php
+/*
+ * 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.transport
+ */
+
+namespace Thrift\Transport;
+
+use Thrift\Exception\TException;
+
+/**
+ * This library makes use of APC cache to make hosts as down in a web
+ * environment. If you are running from the CLI or on a system without APC
+ * installed, then these null functions will step in and act like cache
+ * misses.
+ */
+if (!function_exists('apc_fetch')) {
+    function apc_fetch($key)
+    {
+        return false;
+    }
+
+    function apc_store($key, $var, $ttl = 0)
+    {
+        return false;
+    }
+}
+
+/**
+ * Sockets implementation of the TTransport interface that allows connection
+ * to a pool of servers.
+ *
+ * @package thrift.transport
+ */
+class TSocketPool extends TSocket
+{
+    /**
+     * Remote servers. Array of associative arrays with 'host' and 'port' keys
+     */
+    private $servers_ = array();
+
+    /**
+     * How many times to retry each host in connect
+     *
+     * @var int
+     */
+    private $numRetries_ = 1;
+
+    /**
+     * Retry interval in seconds, how long to not try a host if it has been
+     * marked as down.
+     *
+     * @var int
+     */
+    private $retryInterval_ = 60;
+
+    /**
+     * Max consecutive failures before marking a host down.
+     *
+     * @var int
+     */
+    private $maxConsecutiveFailures_ = 1;
+
+    /**
+     * Try hosts in order? or Randomized?
+     *
+     * @var bool
+     */
+    private $randomize_ = true;
+
+    /**
+     * Always try last host, even if marked down?
+     *
+     * @var bool
+     */
+    private $alwaysTryLast_ = true;
+
+    /**
+     * Socket pool constructor
+     *
+     * @param array $hosts List of remote hostnames
+     * @param mixed $ports Array of remote ports, or a single common port
+     * @param bool $persist Whether to use a persistent socket
+     * @param mixed $debugHandler Function for error logging
+     */
+    public function __construct(
+        $hosts = array('localhost'),
+        $ports = array(9090),
+        $persist = false,
+        $debugHandler = null
+    ) {
+        parent::__construct(null, 0, $persist, $debugHandler);
+
+        if (!is_array($ports)) {
+            $port = $ports;
+            $ports = array();
+            foreach ($hosts as $key => $val) {
+                $ports[$key] = $port;
+            }
+        }
+
+        foreach ($hosts as $key => $host) {
+            $this->servers_ [] = array('host' => $host,
+                'port' => $ports[$key]);
+        }
+    }
+
+    /**
+     * Add a server to the pool
+     *
+     * This function does not prevent you from adding a duplicate server entry.
+     *
+     * @param string $host hostname or IP
+     * @param int $port port
+     */
+    public function addServer($host, $port)
+    {
+        $this->servers_[] = array('host' => $host, 'port' => $port);
+    }
+
+    /**
+     * Sets how many time to keep retrying a host in the connect function.
+     *
+     * @param int $numRetries
+     */
+    public function setNumRetries($numRetries)
+    {
+        $this->numRetries_ = $numRetries;
+    }
+
+    /**
+     * Sets how long to wait until retrying a host if it was marked down
+     *
+     * @param int $numRetries
+     */
+    public function setRetryInterval($retryInterval)
+    {
+        $this->retryInterval_ = $retryInterval;
+    }
+
+    /**
+     * Sets how many time to keep retrying a host before marking it as down.
+     *
+     * @param int $numRetries
+     */
+    public function setMaxConsecutiveFailures($maxConsecutiveFailures)
+    {
+        $this->maxConsecutiveFailures_ = $maxConsecutiveFailures;
+    }
+
+    /**
+     * Turns randomization in connect order on or off.
+     *
+     * @param bool $randomize
+     */
+    public function setRandomize($randomize)
+    {
+        $this->randomize_ = $randomize;
+    }
+
+    /**
+     * Whether to always try the last server.
+     *
+     * @param bool $alwaysTryLast
+     */
+    public function setAlwaysTryLast($alwaysTryLast)
+    {
+        $this->alwaysTryLast_ = $alwaysTryLast;
+    }
+
+    /**
+     * Connects the socket by iterating through all the servers in the pool
+     * and trying to find one that works.
+     */
+    public function open()
+    {
+        // Check if we want order randomization
+        if ($this->randomize_) {
+            shuffle($this->servers_);
+        }
+
+        // Count servers to identify the "last" one
+        $numServers = count($this->servers_);
+
+        for ($i = 0; $i < $numServers; ++$i) {
+            // This extracts the $host and $port variables
+            extract($this->servers_[$i]);
+
+            // Check APC cache for a record of this server being down
+            $failtimeKey = 'thrift_failtime:' . $host . ':' . $port . '~';
+
+            // Cache miss? Assume it's OK
+            $lastFailtime = apc_fetch($failtimeKey);
+            if ($lastFailtime === false) {
+                $lastFailtime = 0;
+            }
+
+            $retryIntervalPassed = false;
+
+            // Cache hit...make sure enough the retry interval has elapsed
+            if ($lastFailtime > 0) {
+                $elapsed = time() - $lastFailtime;
+                if ($elapsed > $this->retryInterval_) {
+                    $retryIntervalPassed = true;
+                    if ($this->debug_) {
+                        call_user_func(
+                            $this->debugHandler_,
+                            'TSocketPool: retryInterval ' .
+                            '(' . $this->retryInterval_ . ') ' .
+                            'has passed for host ' . $host . ':' . $port
+                        );
+                    }
+                }
+            }
+
+            // Only connect if not in the middle of a fail interval, OR if this
+            // is the LAST server we are trying, just hammer away on it
+            $isLastServer = false;
+            if ($this->alwaysTryLast_) {
+                $isLastServer = ($i == ($numServers - 1));
+            }
+
+            if (($lastFailtime === 0) ||
+                ($isLastServer) ||
+                ($lastFailtime > 0 && $retryIntervalPassed)) {
+                // Set underlying TSocket params to this one
+                $this->host_ = $host;
+                $this->port_ = $port;
+
+                // Try up to numRetries_ connections per server
+                for ($attempt = 0; $attempt < $this->numRetries_; $attempt++) {
+                    try {
+                        // Use the underlying TSocket open function
+                        parent::open();
+
+                        // Only clear the failure counts if required to do so
+                        if ($lastFailtime > 0) {
+                            apc_store($failtimeKey, 0);
+                        }
+
+                        // Successful connection, return now
+                        return;
+                    } catch (TException $tx) {
+                        // Connection failed
+                    }
+                }
+
+                // Mark failure of this host in the cache
+                $consecfailsKey = 'thrift_consecfails:' . $host . ':' . $port . '~';
+
+                // Ignore cache misses
+                $consecfails = apc_fetch($consecfailsKey);
+                if ($consecfails === false) {
+                    $consecfails = 0;
+                }
+
+                // Increment by one
+                $consecfails++;
+
+                // Log and cache this failure
+                if ($consecfails >= $this->maxConsecutiveFailures_) {
+                    if ($this->debug_) {
+                        call_user_func(
+                            $this->debugHandler_,
+                            'TSocketPool: marking ' . $host . ':' . $port .
+                            ' as down for ' . $this->retryInterval_ . ' secs ' .
+                            'after ' . $consecfails . ' failed attempts.'
+                        );
+                    }
+                    // Store the failure time
+                    apc_store($failtimeKey, time());
+
+                    // Clear the count of consecutive failures
+                    apc_store($consecfailsKey, 0);
+                } else {
+                    apc_store($consecfailsKey, $consecfails);
+                }
+            }
+        }
+
+        // Oh no; we failed them all. The system is totally ill!
+        $error = 'TSocketPool: All hosts in pool are down. ';
+        $hosts = array();
+        foreach ($this->servers_ as $server) {
+            $hosts [] = $server['host'] . ':' . $server['port'];
+        }
+        $hostlist = implode(',', $hosts);
+        $error .= '(' . $hostlist . ')';
+        if ($this->debug_) {
+            call_user_func($this->debugHandler_, $error);
+        }
+        throw new TException($error);
+    }
+}
diff --git a/lib/php/lib/Transport/TTransport.php b/lib/php/lib/Transport/TTransport.php
new file mode 100644
index 0000000..35921c6
--- /dev/null
+++ b/lib/php/lib/Transport/TTransport.php
@@ -0,0 +1,98 @@
+<?php
+/*
+ * 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.transport
+ */
+
+namespace Thrift\Transport;
+
+use Thrift\Exception\TTransportException;
+use Thrift\Factory\TStringFuncFactory;
+
+/**
+ * Base interface for a transport agent.
+ *
+ * @package thrift.transport
+ */
+abstract class TTransport
+{
+    /**
+     * Whether this transport is open.
+     *
+     * @return boolean true if open
+     */
+    abstract public function isOpen();
+
+    /**
+     * Open the transport for reading/writing
+     *
+     * @throws TTransportException if cannot open
+     */
+    abstract public function open();
+
+    /**
+     * Close the transport.
+     */
+    abstract public function close();
+
+    /**
+     * Read some data into the array.
+     *
+     * @param int $len How much to read
+     * @return string The data that has been read
+     * @throws TTransportException if cannot read any more data
+     */
+    abstract public function read($len);
+
+    /**
+     * Guarantees that the full amount of data is read.
+     *
+     * @return string The data, of exact length
+     * @throws TTransportException if cannot read data
+     */
+    public function readAll($len)
+    {
+        // return $this->read($len);
+
+        $data = '';
+        $got = 0;
+        while (($got = TStringFuncFactory::create()->strlen($data)) < $len) {
+            $data .= $this->read($len - $got);
+        }
+
+        return $data;
+    }
+
+    /**
+     * Writes the given data out.
+     *
+     * @param string $buf The data to write
+     * @throws TTransportException if writing fails
+     */
+    abstract public function write($buf);
+
+    /**
+     * Flushes any pending data out of a buffer
+     *
+     * @throws TTransportException if a writing error occurs
+     */
+    public function flush()
+    {
+    }
+}
diff --git a/lib/php/lib/Type/TConstant.php b/lib/php/lib/Type/TConstant.php
new file mode 100644
index 0000000..215da4a
--- /dev/null
+++ b/lib/php/lib/Type/TConstant.php
@@ -0,0 +1,52 @@
+<?php
+/*
+ * 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
+ */
+
+namespace Thrift\Type;
+
+/**
+ * Base class for constant Management
+ */
+abstract class TConstant
+{
+    /**
+     * Don't instanciate this class
+     */
+    protected function __construct()
+    {
+    }
+
+    /**
+     * Get a constant value
+     * @param  string $constant
+     * @return mixed
+     */
+    public static function get($constant)
+    {
+        if (is_null(static::$$constant)) {
+            static::$$constant = call_user_func(
+                sprintf('static::init_%s', $constant)
+            );
+        }
+
+        return static::$$constant;
+    }
+}
diff --git a/lib/php/lib/Type/TMessageType.php b/lib/php/lib/Type/TMessageType.php
new file mode 100644
index 0000000..dc9ae62
--- /dev/null
+++ b/lib/php/lib/Type/TMessageType.php
@@ -0,0 +1,34 @@
+<?php
+/*
+ * 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
+ */
+
+namespace Thrift\Type;
+
+/**
+ * Message types for RPC
+ */
+class TMessageType
+{
+    const CALL  = 1;
+    const REPLY = 2;
+    const EXCEPTION = 3;
+    const ONEWAY = 4;
+}
diff --git a/lib/php/lib/Type/TType.php b/lib/php/lib/Type/TType.php
new file mode 100644
index 0000000..3fdb15f
--- /dev/null
+++ b/lib/php/lib/Type/TType.php
@@ -0,0 +1,47 @@
+<?php
+/*
+ * 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
+ */
+
+namespace Thrift\Type;
+
+/**
+ * Data types that can be sent via Thrift
+ */
+class TType
+{
+    const STOP   = 0;
+    const VOID   = 1;
+    const BOOL   = 2;
+    const BYTE   = 3;
+    const I08    = 3;
+    const DOUBLE = 4;
+    const I16    = 6;
+    const I32    = 8;
+    const I64    = 10;
+    const STRING = 11;
+    const UTF7   = 11;
+    const STRUCT = 12;
+    const MAP    = 13;
+    const SET    = 14;
+    const LST    = 15;    // N.B. cannot use LIST keyword in PHP!
+    const UTF8   = 16;
+    const UTF16  = 17;
+}
diff --git a/lib/php/src/TStringUtils.php b/lib/php/src/TStringUtils.php
index 69672e8..894baf8 100644
--- a/lib/php/src/TStringUtils.php
+++ b/lib/php/src/TStringUtils.php
@@ -1,28 +1,33 @@
 <?php
 
-interface TStringFunc {
+interface TStringFunc
+{
     public function substr($str, $start, $length = null);
     public function strlen($str);
 }
 
 class TStringFunc_Core
 implements TStringFunc {
-    public function substr($str, $start, $length = null) {
+    public function substr($str, $start, $length = null)
+    {
         // specifying a null $length would return an empty string
-        if($length === null) {
+        if ($length === null) {
             return substr($str, $start);
         }
+
         return substr($str, $start, $length);
     }
 
-    public function strlen($str) {
+    public function strlen($str)
+    {
         return strlen($str);
     }
 }
 
 class TStringFunc_Mbstring
 implements TStringFunc {
-    public function substr($str, $start, $length = null) {
+    public function substr($str, $start, $length = null)
+    {
         /**
          * We need to set the charset parameter, which is the second
          * optional parameter and the first optional parameter can't
@@ -30,19 +35,21 @@
          * cause an empty string to be returned, so we need to
          * actually calculate the proper length value.
          */
-        if($length === null) {
+        if ($length === null) {
             $length = $this->strlen($str) - $start;
         }
 
         return mb_substr($str, $start, $length, '8bit');
     }
 
-    public function strlen($str) {
+    public function strlen($str)
+    {
         return mb_strlen($str, '8bit');
     }
 }
 
-class TStringFuncFactory {
+class TStringFuncFactory
+{
     private static $_instance;
 
     /**
@@ -51,22 +58,24 @@
      *
      * @return TStringFunc
      */
-    public static function create() {
-        if(!self::$_instance) {
+    public static function create()
+    {
+        if (!self::$_instance) {
             self::_setInstance();
         }
 
         return self::$_instance;
     }
 
-    private static function _setInstance() {
+    private static function _setInstance()
+    {
         /**
          * Cannot use str* functions for byte counting because multibyte
          * characters will be read a single bytes.
          *
          * See: http://us.php.net/manual/en/mbstring.overload.php
          */
-        if(ini_get('mbstring.func_overload') & 2) {
+        if (ini_get('mbstring.func_overload') & 2) {
             self::$_instance = new TStringFunc_Mbstring();
         }
         /**
diff --git a/lib/php/src/Thrift.php b/lib/php/src/Thrift.php
index c845395..4fe4392 100644
--- a/lib/php/src/Thrift.php
+++ b/lib/php/src/Thrift.php
@@ -20,11 +20,11 @@
  * @package thrift
  */
 
-
 /**
  * Data types that can be sent via Thrift
  */
-class TType {
+class TType
+{
   const STOP   = 0;
   const VOID   = 1;
   const BOOL   = 2;
@@ -47,7 +47,8 @@
 /**
  * Message types for RPC
  */
-class TMessageType {
+class TMessageType
+{
   const CALL  = 1;
   const REPLY = 2;
   const EXCEPTION = 3;
@@ -67,8 +68,10 @@
  * @param mixed $p1 Message (string) or type-spec (array)
  * @param mixed $p2 Code (integer) or values (array)
  */
-class TException extends Exception {
-  function __construct($p1=null, $p2=0) {
+class TException extends Exception
+{
+  public function __construct($p1=null, $p2=0)
+  {
     if (is_array($p1) && is_array($p2)) {
       $spec = $p1;
       $vals = $p2;
@@ -91,7 +94,8 @@
                           TType::DOUBLE => 'Double',
                           TType::STRING => 'String');
 
-  private function _readMap(&$var, $spec, $input) {
+  private function _readMap(&$var, $spec, $input)
+  {
     $xfer = 0;
     $ktype = $spec['ktype'];
     $vtype = $spec['vtype'];
@@ -154,10 +158,12 @@
       $var[$key] = $val;
     }
     $xfer += $input->readMapEnd();
+
     return $xfer;
   }
 
-  private function _readList(&$var, $spec, $input, $set=false) {
+  private function _readList(&$var, $spec, $input, $set=false)
+  {
     $xfer = 0;
     $etype = $spec['etype'];
     $eread = $vread = null;
@@ -207,10 +213,12 @@
     } else {
       $xfer += $input->readListEnd();
     }
+
     return $xfer;
   }
 
-  protected function _read($class, $spec, $input) {
+  protected function _read($class, $spec, $input)
+  {
     $xfer = 0;
     $fname = null;
     $ftype = 0;
@@ -256,10 +264,12 @@
       $xfer += $input->readFieldEnd();
     }
     $xfer += $input->readStructEnd();
+
     return $xfer;
   }
 
-  private function _writeMap($var, $spec, $output) {
+  private function _writeMap($var, $spec, $output)
+  {
     $xfer = 0;
     $ktype = $spec['ktype'];
     $vtype = $spec['vtype'];
@@ -314,10 +324,12 @@
       }
     }
     $xfer += $output->writeMapEnd();
+
     return $xfer;
   }
 
-  private function _writeList($var, $spec, $output, $set=false) {
+  private function _writeList($var, $spec, $output, $set=false)
+  {
     $xfer = 0;
     $etype = $spec['etype'];
     $ewrite = null;
@@ -357,10 +369,12 @@
     } else {
       $xfer += $output->writeListEnd();
     }
+
     return $xfer;
   }
 
-  protected function _write($class, $spec, $output) {
+  protected function _write($class, $spec, $output)
+  {
     $xfer = 0;
     $xfer += $output->writeStructBegin($class);
     foreach ($spec as $fid => $fspec) {
@@ -392,6 +406,7 @@
     }
     $xfer += $output->writeFieldStop();
     $xfer += $output->writeStructEnd();
+
     return $xfer;
   }
 
@@ -404,8 +419,8 @@
  * of PHP. Note that code is intentionally duplicated in here to avoid making
  * function calls for every field or member of a container..
  */
-abstract class TBase {
-
+abstract class TBase
+{
   static $tmethod = array(TType::BOOL   => 'Bool',
                           TType::BYTE   => 'Byte',
                           TType::I16    => 'I16',
@@ -414,11 +429,12 @@
                           TType::DOUBLE => 'Double',
                           TType::STRING => 'String');
 
-  abstract function read($input);
+  abstract public function read($input);
 
-  abstract function write($output);
+  abstract public function write($output);
 
-  public function __construct($spec=null, $vals=null) {
+  public function __construct($spec=null, $vals=null)
+  {
     if (is_array($spec) && is_array($vals)) {
       foreach ($spec as $fid => $fspec) {
         $var = $fspec['var'];
@@ -429,7 +445,8 @@
     }
   }
 
-  private function _readMap(&$var, $spec, $input) {
+  private function _readMap(&$var, $spec, $input)
+  {
     $xfer = 0;
     $ktype = $spec['ktype'];
     $vtype = $spec['vtype'];
@@ -492,10 +509,12 @@
       $var[$key] = $val;
     }
     $xfer += $input->readMapEnd();
+
     return $xfer;
   }
 
-  private function _readList(&$var, $spec, $input, $set=false) {
+  private function _readList(&$var, $spec, $input, $set=false)
+  {
     $xfer = 0;
     $etype = $spec['etype'];
     $eread = $vread = null;
@@ -545,10 +564,12 @@
     } else {
       $xfer += $input->readListEnd();
     }
+
     return $xfer;
   }
 
-  protected function _read($class, $spec, $input) {
+  protected function _read($class, $spec, $input)
+  {
     $xfer = 0;
     $fname = null;
     $ftype = 0;
@@ -594,10 +615,12 @@
       $xfer += $input->readFieldEnd();
     }
     $xfer += $input->readStructEnd();
+
     return $xfer;
   }
 
-  private function _writeMap($var, $spec, $output) {
+  private function _writeMap($var, $spec, $output)
+  {
     $xfer = 0;
     $ktype = $spec['ktype'];
     $vtype = $spec['vtype'];
@@ -652,10 +675,12 @@
       }
     }
     $xfer += $output->writeMapEnd();
+
     return $xfer;
   }
 
-  private function _writeList($var, $spec, $output, $set=false) {
+  private function _writeList($var, $spec, $output, $set=false)
+  {
     $xfer = 0;
     $etype = $spec['etype'];
     $ewrite = null;
@@ -695,10 +720,12 @@
     } else {
       $xfer += $output->writeListEnd();
     }
+
     return $xfer;
   }
 
-  protected function _write($class, $spec, $output) {
+  protected function _write($class, $spec, $output)
+  {
     $xfer = 0;
     $xfer += $output->writeStructBegin($class);
     foreach ($spec as $fid => $fspec) {
@@ -730,11 +757,13 @@
     }
     $xfer += $output->writeFieldStop();
     $xfer += $output->writeStructEnd();
+
     return $xfer;
   }
 }
 
-class TApplicationException extends TException {
+class TApplicationException extends TException
+{
   static $_TSPEC =
     array(1 => array('var' => 'message',
                      'type' => TType::STRING),
@@ -750,15 +779,18 @@
   const INTERNAL_ERROR = 6;
   const PROTOCOL_ERROR = 7;
 
-  function __construct($message=null, $code=0) {
+  public function __construct($message=null, $code=0)
+  {
     parent::__construct($message, $code);
   }
 
-  public function read($output) {
+  public function read($output)
+  {
     return $this->_read('TApplicationException', self::$_TSPEC, $output);
   }
 
-  public function write($output) {
+  public function write($output)
+  {
     $xfer = 0;
     $xfer += $output->writeStructBegin('TApplicationException');
     if ($message = $this->getMessage()) {
@@ -773,6 +805,7 @@
     }
     $xfer += $output->writeFieldStop();
     $xfer += $output->writeStructEnd();
+
     return $xfer;
   }
 }
@@ -786,4 +819,3 @@
 include_once $GLOBALS['THRIFT_ROOT'].'/protocol/TProtocol.php';
 include_once $GLOBALS['THRIFT_ROOT'].'/transport/TTransport.php';
 include_once $GLOBALS['THRIFT_ROOT'].'/TStringUtils.php';
-
diff --git a/lib/php/src/autoload.php b/lib/php/src/autoload.php
index 3a35545..85bd797 100644
--- a/lib/php/src/autoload.php
+++ b/lib/php/src/autoload.php
@@ -20,7 +20,6 @@
  * @package thrift
  */
 
-
 /**
  * Include this file if you wish to use autoload with your PHP generated Thrift
  * code. The generated code will *not* include any defined Thrift classes by
@@ -37,12 +36,13 @@
 $GLOBALS['AUTOLOAD_HOOKS'] = array();
 
 if (!function_exists('__autoload')) {
-  function __autoload($class) {
+  function __autoload($class)
+  {
     global $THRIFT_AUTOLOAD;
     $classl = strtolower($class);
     if (isset($THRIFT_AUTOLOAD[$classl])) {
       include_once $GLOBALS['THRIFT_ROOT'].'/packages/'.$THRIFT_AUTOLOAD[$classl];
-    } else if (!empty($GLOBALS['AUTOLOAD_HOOKS'])) {
+    } elseif (!empty($GLOBALS['AUTOLOAD_HOOKS'])) {
       foreach ($GLOBALS['AUTOLOAD_HOOKS'] as $hook) {
         $hook($class);
       }
diff --git a/lib/php/src/ext/thrift_protocol/config.m4 b/lib/php/src/ext/thrift_protocol/config.m4
index 2c338a0..e2138c8 100644
--- a/lib/php/src/ext/thrift_protocol/config.m4
+++ b/lib/php/src/ext/thrift_protocol/config.m4
@@ -2,14 +2,33 @@
 dnl Copying and distribution of this file, with or without modification,
 dnl are permitted in any medium without royalty provided the copyright
 dnl notice and this notice are preserved.
+dnl
+dnl Licensed to the Apache Software Foundation (ASF) under one
+dnl or more contributor license agreements. See the NOTICE file
+dnl distributed with this work for additional information
+dnl regarding copyright ownership. The ASF licenses this file
+dnl to you under the Apache License, Version 2.0 (the
+dnl "License"); you may not use this file except in compliance
+dnl with the License. You may obtain a copy of the License at
+dnl
+dnl  http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing,
+dnl software distributed under the License is distributed on an
+dnl "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+dnl KIND, either express or implied. See the License for the
+dnl specific language governing permissions and limitations
+dnl under the License.
 
 PHP_ARG_ENABLE(thrift_protocol, whether to enable the thrift_protocol extension,
-[  --enable-thrift_protocol	Enable the fbthrift_protocol extension])
+[  --enable-thrift_protocol	Enable the thrift_protocol extension])
 
 if test "$PHP_THRIFT_PROTOCOL" != "no"; then
   PHP_REQUIRE_CXX()
   PHP_ADD_LIBRARY_WITH_PATH(stdc++, "", THRIFT_PROTOCOL_SHARED_LIBADD)
   PHP_SUBST(THRIFT_PROTOCOL_SHARED_LIBADD)
+  CXXFLAGS="$CXXFLAGS -std=c++11"
+
   PHP_NEW_EXTENSION(thrift_protocol, php_thrift_protocol.cpp, $ext_shared)
 fi
 
diff --git a/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp b/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp
index 551d438..63c8905 100644
--- a/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp
+++ b/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp
@@ -16,25 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
+#include "php.h"
+#include "zend_interfaces.h"
+#include "zend_exceptions.h"
+#include "php_thrift_protocol.h"
+
+#if PHP_VERSION_ID >= 70000
+
 #include <sys/types.h>
-#if defined( WIN32 ) || defined( _WIN64 )
-typedef int  int32_t; 
-typedef signed char int8_t;
-typedef unsigned char   uint8_t;
-typedef unsigned short  uint16_t;
-typedef long long  int64_t;
-typedef unsigned   uint32_t; 
-typedef short  int16_t; 
-typedef unsigned long long   uint64_t;
-#else
-#include <arpa/inet.h> 
-#endif
+#include <arpa/inet.h>
+
+#include <cstdint>
 #include <stdexcept>
+#include <algorithm>
 
 #ifndef bswap_64
 #define	bswap_64(x)     (((uint64_t)(x) << 56) | \
@@ -57,10 +55,6 @@
 #error Unknown __BYTE_ORDER
 #endif
 
-#ifndef Z_ADDREF_P
-#define Z_ADDREF_P ZVAL_ADDREF
-#endif
-
 enum TType {
   T_STOP       = 0,
   T_VOID       = 1,
@@ -91,26 +85,22 @@
 const int INVALID_DATA = 1;
 const int BAD_VERSION = 4;
 
-#include "php.h"
-#include "zend_interfaces.h"
-#include "zend_exceptions.h"
-#include "php_thrift_protocol.h"
-
 static zend_function_entry thrift_protocol_functions[] = {
-  PHP_FE(thrift_protocol_write_binary, NULL)
-  PHP_FE(thrift_protocol_read_binary, NULL)
-  {NULL, NULL, NULL}
-} ;
+  PHP_FE(thrift_protocol_write_binary, nullptr)
+  PHP_FE(thrift_protocol_read_binary, nullptr)
+  PHP_FE(thrift_protocol_read_binary_after_message_begin, nullptr)
+  {nullptr, nullptr, nullptr}
+};
 
 zend_module_entry thrift_protocol_module_entry = {
   STANDARD_MODULE_HEADER,
   "thrift_protocol",
   thrift_protocol_functions,
-  NULL,
-  NULL,
-  NULL,
-  NULL,
-  NULL,
+  nullptr,
+  nullptr,
+  nullptr,
+  nullptr,
+  nullptr,
   "1.0",
   STANDARD_MODULE_PROPERTIES
 };
@@ -121,42 +111,61 @@
 
 class PHPExceptionWrapper : public std::exception {
 public:
-  PHPExceptionWrapper(zval* _ex) throw() : ex(_ex) {
-    snprintf(_what, 40, "PHP exception zval=%p", ex);
+  PHPExceptionWrapper(zval* _ex) throw() {
+    ZVAL_COPY(&ex, _ex);
+    snprintf(_what, 40, "PHP exception zval=%p", _ex);
   }
-  const char* what() const throw() { return _what; }
-  ~PHPExceptionWrapper() throw() {}
-  operator zval*() const throw() { return const_cast<zval*>(ex); } // Zend API doesn't do 'const'...
+
+  PHPExceptionWrapper(zend_object* _exobj) throw() {
+    ZVAL_OBJ(&ex, _exobj);
+    snprintf(_what, 40, "PHP exception zval=%p", _exobj);
+  }
+  ~PHPExceptionWrapper() throw() {
+    zval_dtor(&ex);
+  }
+
+  const char* what() const throw() {
+    return _what;
+  }
+  operator zval*() const throw() {
+    return const_cast<zval*>(&ex);
+  } // Zend API doesn't do 'const'...
 protected:
-  zval* ex;
+  zval ex;
   char _what[40];
 } ;
 
 class PHPTransport {
-public:
-  zval* protocol() { return p; }
-  zval* transport() { return t; }
 protected:
-  PHPTransport() {}
+  PHPTransport(zval* _p, size_t _buffer_size) {
+    assert(Z_TYPE_P(_p) == IS_OBJECT);
 
-  void construct_with_zval(zval* _p, size_t _buffer_size) {
+    ZVAL_UNDEF(&t);
+
     buffer = reinterpret_cast<char*>(emalloc(_buffer_size));
     buffer_ptr = buffer;
     buffer_used = 0;
     buffer_size = _buffer_size;
-    p = _p;
 
     // Get the transport for the passed protocol
     zval gettransport;
-    ZVAL_STRING(&gettransport, "getTransport", 0);
-    MAKE_STD_ZVAL(t);
-    ZVAL_NULL(t);
-    TSRMLS_FETCH();
-    call_user_function(EG(function_table), &p, &gettransport, t, 0, NULL TSRMLS_CC);
+    ZVAL_STRING(&gettransport, "getTransport");
+    call_user_function(nullptr, _p, &gettransport, &t, 0, nullptr);
+
+    zval_dtor(&gettransport);
+
+    if (EG(exception)) {
+      zend_object *ex = EG(exception);
+      EG(exception) = nullptr;
+      throw PHPExceptionWrapper(ex);
+    }
+
+    assert(Z_TYPE(t) == IS_OBJECT);
   }
+
   ~PHPTransport() {
     efree(buffer);
-    zval_ptr_dtor(&t);
+    zval_dtor(&t);
   }
 
   char* buffer;
@@ -164,20 +173,14 @@
   size_t buffer_used;
   size_t buffer_size;
 
-  zval* p;
-  zval* t;
+  zval t;
 };
 
 
 class PHPOutputTransport : public PHPTransport {
 public:
-  PHPOutputTransport(zval* _p, size_t _buffer_size = 8192) {
-    construct_with_zval(_p, _buffer_size);
-  }
-
-  ~PHPOutputTransport() {
-    //flush();
-  }
+  PHPOutputTransport(zval* _p, size_t _buffer_size = 8192) : PHPTransport(_p, _buffer_size) { }
+  ~PHPOutputTransport() { }
 
   void write(const char* data, size_t len) {
     if ((len + buffer_used) > buffer_size) {
@@ -235,32 +238,35 @@
     }
   }
   void directFlush() {
-    zval ret;
+    zval ret, flushfn;
     ZVAL_NULL(&ret);
-    zval flushfn;
-    ZVAL_STRING(&flushfn, "flush", 0);
-    TSRMLS_FETCH();
-    call_user_function(EG(function_table), &t, &flushfn, &ret, 0, NULL TSRMLS_CC);
-    zval_dtor(&ret);
-  }
-  void directWrite(const char* data, size_t len) {
-    zval writefn;
-    ZVAL_STRING(&writefn, "write", 0);
-    char* newbuf = (char*)emalloc(len + 1);
-    memcpy(newbuf, data, len);
-    newbuf[len] = '\0';
-    zval *args[1];
-    MAKE_STD_ZVAL(args[0]);
-    ZVAL_STRINGL(args[0], newbuf, len, 0);
-    TSRMLS_FETCH();
-    zval ret;
-    ZVAL_NULL(&ret);
-    call_user_function(EG(function_table), &t, &writefn, &ret, 1, args TSRMLS_CC);
-    zval_ptr_dtor(args);
+    ZVAL_STRING(&flushfn, "flush");
+
+    call_user_function(EG(function_table), &(this->t), &flushfn, &ret, 0, nullptr);
+    zval_dtor(&flushfn);
     zval_dtor(&ret);
     if (EG(exception)) {
-      zval* ex = EG(exception);
-      EG(exception) = NULL;
+      zend_object *ex = EG(exception);
+      EG(exception) = nullptr;
+      throw PHPExceptionWrapper(ex);
+    }
+  }
+  void directWrite(const char* data, size_t len) {
+    zval args[1], ret, writefn;
+
+    ZVAL_STRING(&writefn, "write");
+    ZVAL_STRINGL(&args[0], data, len);
+
+    ZVAL_NULL(&ret);
+    call_user_function(EG(function_table), &(this->t), &writefn, &ret, 1, args);
+
+    zval_dtor(&writefn);
+    zval_dtor(&ret);
+    zval_dtor(&args[0]);
+
+    if (EG(exception)) {
+      zend_object *ex = EG(exception);
+      EG(exception) = nullptr;
       throw PHPExceptionWrapper(ex);
     }
   }
@@ -268,8 +274,7 @@
 
 class PHPInputTransport : public PHPTransport {
 public:
-  PHPInputTransport(zval* _p, size_t _buffer_size = 8192) {
-    construct_with_zval(_p, _buffer_size);
+  PHPInputTransport(zval* _p, size_t _buffer_size = 8192) : PHPTransport(_p, _buffer_size) {
   }
 
   ~PHPInputTransport() {
@@ -278,24 +283,21 @@
 
   void put_back() {
     if (buffer_used) {
-      zval putbackfn;
-      ZVAL_STRING(&putbackfn, "putBack", 0);
-
-      char* newbuf = (char*)emalloc(buffer_used + 1);
-      memcpy(newbuf, buffer_ptr, buffer_used);
-      newbuf[buffer_used] = '\0';
-
-      zval *args[1];
-      MAKE_STD_ZVAL(args[0]);
-      ZVAL_STRINGL(args[0], newbuf, buffer_used, 0);
-
-      TSRMLS_FETCH();
-
-      zval ret;
+      zval args[1], ret, putbackfn;
+      ZVAL_STRINGL(&args[0], buffer_ptr, buffer_used);
+      ZVAL_STRING(&putbackfn, "putBack");
       ZVAL_NULL(&ret);
-      call_user_function(EG(function_table), &t, &putbackfn, &ret, 1, args TSRMLS_CC);
-      zval_ptr_dtor(args);
+
+      call_user_function(EG(function_table), &(this->t), &putbackfn, &ret, 1, args);
+
+      zval_dtor(&putbackfn);
       zval_dtor(&ret);
+      zval_dtor(&args[0]);
+      if (EG(exception)) {
+        zend_object *ex = EG(exception);
+        EG(exception) = nullptr;
+        throw PHPExceptionWrapper(ex);
+      }
     }
     buffer_used = 0;
     buffer_ptr = buffer;
@@ -303,7 +305,7 @@
 
   void skip(size_t len) {
     while (len) {
-      size_t chunk_size = MIN(len, buffer_used);
+      size_t chunk_size = (std::min)(len, buffer_used);
       if (chunk_size) {
         buffer_ptr = reinterpret_cast<char*>(buffer_ptr) + chunk_size;
         buffer_used -= chunk_size;
@@ -316,7 +318,7 @@
 
   void readBytes(void* buf, size_t len) {
     while (len) {
-      size_t chunk_size = MIN(len, buffer_used);
+      size_t chunk_size = (std::min)(len, buffer_used);
       if (chunk_size) {
         memcpy(buf, buffer_ptr, chunk_size);
         buffer_ptr = reinterpret_cast<char*>(buffer_ptr) + chunk_size;
@@ -357,29 +359,29 @@
   void refill() {
     assert(buffer_used == 0);
     zval retval;
-    ZVAL_NULL(&retval);
-
-    zval *args[1];
-    MAKE_STD_ZVAL(args[0]);
-    ZVAL_LONG(args[0], buffer_size);
-
-    TSRMLS_FETCH();
-
+    zval args[1];
     zval funcname;
-    ZVAL_STRING(&funcname, "read", 0);
 
-    call_user_function(EG(function_table), &t, &funcname, &retval, 1, args TSRMLS_CC);
-    zval_ptr_dtor(args);
+    ZVAL_NULL(&retval);
+    ZVAL_LONG(&args[0], buffer_size);
+
+    ZVAL_STRING(&funcname, "read");
+
+    call_user_function(EG(function_table), &(this->t), &funcname, &retval, 1, args);
+    zval_dtor(&args[0]);
+    zval_dtor(&funcname);
 
     if (EG(exception)) {
       zval_dtor(&retval);
-      zval* ex = EG(exception);
-      EG(exception) = NULL;
+
+      zend_object *ex = EG(exception);
+      EG(exception) = nullptr;
       throw PHPExceptionWrapper(ex);
     }
 
     buffer_used = Z_STRLEN(retval);
     memcpy(buffer, Z_STRVAL(retval), buffer_used);
+
     zval_dtor(&retval);
 
     buffer_ptr = buffer;
@@ -387,222 +389,63 @@
 
 };
 
+static
 void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTable* spec);
+static
 void binary_serialize_spec(zval* zthis, PHPOutputTransport& transport, HashTable* spec);
-void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, zval** value, HashTable* fieldspec);
-void skip_element(long thrift_typeID, PHPInputTransport& transport);
-void protocol_writeMessageBegin(zval *transport, const char* method_name, int32_t msgtype, int32_t seqID);
-
+static
+void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, zval* value, HashTable* fieldspec);
+static inline
+bool ttype_is_scalar(int8_t t);
 
 // Create a PHP object given a typename and call the ctor, optionally passing up to 2 arguments
-void createObject(char* obj_typename, zval* return_value, int nargs = 0, zval* arg1 = NULL, zval* arg2 = NULL) {
-  TSRMLS_FETCH();
-  size_t obj_typename_len = strlen(obj_typename);
-  zend_class_entry* ce = zend_fetch_class(obj_typename, obj_typename_len, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);
+static
+void createObject(const char* obj_typename, zval* return_value, int nargs = 0, zval* arg1 = nullptr, zval* arg2 = nullptr) {
+  /* is there a better way to do that on the stack ? */
+  zend_string *obj_name = zend_string_init(obj_typename, strlen(obj_typename), 0);
+  zend_class_entry* ce = zend_fetch_class(obj_name, ZEND_FETCH_CLASS_DEFAULT);
+  zend_string_release(obj_name);
+
   if (! ce) {
-    php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s does not exist", obj_typename);
+    php_error_docref(nullptr, E_ERROR, "Class %s does not exist", obj_typename);
     RETURN_NULL();
   }
 
-  object_and_properties_init(return_value, ce, NULL);
-  zend_function* constructor = zend_std_get_constructor(return_value TSRMLS_CC);
-  zval* ctor_rv = NULL;
-  zend_call_method(&return_value, ce, &constructor, NULL, 0, &ctor_rv, nargs, arg1, arg2 TSRMLS_CC);
-  zval_ptr_dtor(&ctor_rv);
+  object_and_properties_init(return_value, ce, nullptr);
+  zend_function* constructor = zend_std_get_constructor(Z_OBJ_P(return_value));
+  zval ctor_rv;
+  zend_call_method(return_value, ce, &constructor, NULL, 0, &ctor_rv, nargs, arg1, arg2);
+  zval_dtor(&ctor_rv);
+  if (EG(exception)) {
+    zend_object *ex = EG(exception);
+    EG(exception) = nullptr;
+    throw PHPExceptionWrapper(ex);
+  }
 }
 
-void throw_tprotocolexception(char* what, long errorcode) {
-  TSRMLS_FETCH();
+static
+void throw_tprotocolexception(const char* what, long errorcode) {
+  zval zwhat, zerrorcode;
 
-  zval *zwhat, *zerrorcode;
-  MAKE_STD_ZVAL(zwhat);
-  MAKE_STD_ZVAL(zerrorcode);
+  ZVAL_STRING(&zwhat, what);
+  ZVAL_LONG(&zerrorcode, errorcode);
 
-  ZVAL_STRING(zwhat, what, 1);
-  ZVAL_LONG(zerrorcode, errorcode);
+  zval ex;
+  createObject("\\Thrift\\Exception\\TProtocolException", &ex, 2, &zwhat, &zerrorcode);
 
-  zval* ex;
-  MAKE_STD_ZVAL(ex);
-  createObject("\\Thrift\\Exception\\TProtocolException", ex, 2, zwhat, zerrorcode);
-  zval_ptr_dtor(&zwhat);
-  zval_ptr_dtor(&zerrorcode);
-  throw PHPExceptionWrapper(ex);
+  zval_dtor(&zwhat);
+  zval_dtor(&zerrorcode);
+
+  throw PHPExceptionWrapper(&ex);
 }
 
 // Sets EG(exception), call this and then RETURN_NULL();
-void throw_zend_exception_from_std_exception(const std::exception& ex TSRMLS_DC) {
-  zend_throw_exception(zend_exception_get_default(TSRMLS_C), const_cast<char*>(ex.what()), 0 TSRMLS_CC);
+static
+void throw_zend_exception_from_std_exception(const std::exception& ex) {
+  zend_throw_exception(zend_exception_get_default(), const_cast<char*>(ex.what()), 0);
 }
 
-
-void binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport, zval* return_value, HashTable* fieldspec) {
-  zval** val_ptr;
-  Z_TYPE_P(return_value) = IS_NULL; // just in case
-
-  switch (thrift_typeID) {
-    case T_STOP:
-    case T_VOID:
-      RETURN_NULL();
-      return;
-    case T_STRUCT: {
-      if (zend_hash_find(fieldspec, "class", 6, (void**)&val_ptr) != SUCCESS) {
-        throw_tprotocolexception("no class type in spec", INVALID_DATA);
-        skip_element(T_STRUCT, transport);
-        RETURN_NULL();
-      }
-      char* structType = Z_STRVAL_PP(val_ptr);
-      createObject(structType, return_value);
-      if (Z_TYPE_P(return_value) == IS_NULL) {
-        // unable to create class entry
-        skip_element(T_STRUCT, transport);
-        RETURN_NULL();
-      }
-      TSRMLS_FETCH();
-      zval* spec = zend_read_static_property(zend_get_class_entry(return_value TSRMLS_CC), "_TSPEC", 6, false TSRMLS_CC);
-      if (Z_TYPE_P(spec) != IS_ARRAY) {
-        char errbuf[128];
-        snprintf(errbuf, 128, "spec for %s is wrong type: %d\n", structType, Z_TYPE_P(spec));
-        throw_tprotocolexception(errbuf, INVALID_DATA);
-        RETURN_NULL();
-      }
-      binary_deserialize_spec(return_value, transport, Z_ARRVAL_P(spec));
-      return;
-    } break;
-    case T_BOOL: {
-      uint8_t c;
-      transport.readBytes(&c, 1);
-      RETURN_BOOL(c != 0);
-    }
-  //case T_I08: // same numeric value as T_BYTE
-    case T_BYTE: {
-      uint8_t c;
-      transport.readBytes(&c, 1);
-      RETURN_LONG((int8_t)c);
-    }
-    case T_I16: {
-      uint16_t c;
-      transport.readBytes(&c, 2);
-      RETURN_LONG((int16_t)ntohs(c));
-    }
-    case T_I32: {
-      uint32_t c;
-      transport.readBytes(&c, 4);
-      RETURN_LONG((int32_t)ntohl(c));
-    }
-    case T_U64:
-    case T_I64: {
-      uint64_t c;
-      transport.readBytes(&c, 8);
-      RETURN_LONG((int64_t)ntohll(c));
-    }
-    case T_DOUBLE: {
-      union {
-        uint64_t c;
-        double d;
-      } a;
-      transport.readBytes(&(a.c), 8);
-      a.c = ntohll(a.c);
-      RETURN_DOUBLE(a.d);
-    }
-    //case T_UTF7: // aliases T_STRING
-    case T_UTF8:
-    case T_UTF16:
-    case T_STRING: {
-      uint32_t size = transport.readU32();
-      if (size) {
-        char* strbuf = (char*) emalloc(size + 1);
-        transport.readBytes(strbuf, size);
-        strbuf[size] = '\0';
-        ZVAL_STRINGL(return_value, strbuf, size, 0);
-      } else {
-        ZVAL_EMPTY_STRING(return_value);
-      }
-      return;
-    }
-    case T_MAP: { // array of key -> value
-      uint8_t types[2];
-      transport.readBytes(types, 2);
-      uint32_t size = transport.readU32();
-      array_init(return_value);
-
-      zend_hash_find(fieldspec, "key", 4, (void**)&val_ptr);
-      HashTable* keyspec = Z_ARRVAL_PP(val_ptr);
-      zend_hash_find(fieldspec, "val", 4, (void**)&val_ptr);
-      HashTable* valspec = Z_ARRVAL_PP(val_ptr);
-
-      for (uint32_t s = 0; s < size; ++s) {
-        zval *value;
-        MAKE_STD_ZVAL(value);
-
-        zval* key;
-        MAKE_STD_ZVAL(key);
-
-        binary_deserialize(types[0], transport, key, keyspec);
-        binary_deserialize(types[1], transport, value, valspec);
-        if (Z_TYPE_P(key) == IS_LONG) {
-          zend_hash_index_update(return_value->value.ht, Z_LVAL_P(key), &value, sizeof(zval *), NULL);
-        }
-        else {
-          if (Z_TYPE_P(key) != IS_STRING) convert_to_string(key);
-          zend_hash_update(return_value->value.ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof(zval *), NULL);
-        }
-        zval_ptr_dtor(&key);
-      }
-      return; // return_value already populated
-    }
-    case T_LIST: { // array with autogenerated numeric keys
-      int8_t type = transport.readI8();
-      uint32_t size = transport.readU32();
-      zend_hash_find(fieldspec, "elem", 5, (void**)&val_ptr);
-      HashTable* elemspec = Z_ARRVAL_PP(val_ptr);
-
-      array_init(return_value);
-      for (uint32_t s = 0; s < size; ++s) {
-        zval *value;
-        MAKE_STD_ZVAL(value);
-        binary_deserialize(type, transport, value, elemspec);
-        zend_hash_next_index_insert(return_value->value.ht, &value, sizeof(zval *), NULL);
-      }
-      return;
-    }
-    case T_SET: { // array of key -> TRUE
-      uint8_t type;
-      uint32_t size;
-      transport.readBytes(&type, 1);
-      transport.readBytes(&size, 4);
-      size = ntohl(size);
-      zend_hash_find(fieldspec, "elem", 5, (void**)&val_ptr);
-      HashTable* elemspec = Z_ARRVAL_PP(val_ptr);
-
-      array_init(return_value);
-
-      for (uint32_t s = 0; s < size; ++s) {
-        zval* key;
-        zval* value;
-        MAKE_STD_ZVAL(key);
-        MAKE_STD_ZVAL(value);
-        ZVAL_TRUE(value);
-
-        binary_deserialize(type, transport, key, elemspec);
-
-        if (Z_TYPE_P(key) == IS_LONG) {
-          zend_hash_index_update(return_value->value.ht, Z_LVAL_P(key), &value, sizeof(zval *), NULL);
-        }
-        else {
-          if (Z_TYPE_P(key) != IS_STRING) convert_to_string(key);
-          zend_hash_update(return_value->value.ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof(zval *), NULL);
-        }
-        zval_ptr_dtor(&key);
-      }
-      return;
-    }
-  };
-
-  char errbuf[128];
-  sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID);
-  throw_tprotocolexception(errbuf, INVALID_DATA);
-}
-
+static
 void skip_element(long thrift_typeID, PHPInputTransport& transport) {
   switch (thrift_typeID) {
     case T_STOP:
@@ -662,101 +505,472 @@
   throw_tprotocolexception(errbuf, INVALID_DATA);
 }
 
-void protocol_writeMessageBegin(zval* transport, const char* method_name, int32_t msgtype, int32_t seqID) {
-  TSRMLS_FETCH();
-  zval *args[3];
-
-  MAKE_STD_ZVAL(args[0]);
-  ZVAL_STRINGL(args[0], (char*)method_name, strlen(method_name), 1);
-
-  MAKE_STD_ZVAL(args[1]);
-  ZVAL_LONG(args[1], msgtype);
-
-  MAKE_STD_ZVAL(args[2]);
-  ZVAL_LONG(args[2], seqID);
-
-  zval ret;
-  ZVAL_NULL(&ret);
-
-  zval writeMessagefn;
-  ZVAL_STRING(&writeMessagefn, "writeMessageBegin", 0);
-
-  call_user_function(EG(function_table), &transport, &writeMessagefn, &ret, 3, args TSRMLS_CC);
-
-  zval_ptr_dtor(&args[0]);
-  zval_ptr_dtor(&args[1]);
-  zval_ptr_dtor(&args[2]);
-  zval_dtor(&ret);
+static inline
+bool zval_is_bool(zval* v) {
+  return Z_TYPE_P(v) == IS_TRUE || Z_TYPE_P(v) == IS_FALSE;
 }
 
-void binary_serialize_hashtable_key(int8_t keytype, PHPOutputTransport& transport, HashTable* ht, HashPosition& ht_pos) {
+static
+void binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport, zval* return_value, HashTable* fieldspec) {
+  ZVAL_NULL(return_value);
+
+  switch (thrift_typeID) {
+    case T_STOP:
+    case T_VOID:
+      RETURN_NULL();
+      return;
+    case T_STRUCT: {
+      zval* val_ptr = zend_hash_str_find(fieldspec, "class", sizeof("class")-1);
+      if (val_ptr == nullptr) {
+        throw_tprotocolexception("no class type in spec", INVALID_DATA);
+        skip_element(T_STRUCT, transport);
+        RETURN_NULL();
+      }
+
+      char* structType = Z_STRVAL_P(val_ptr);
+      // Create an object in PHP userland based on our spec
+      createObject(structType, return_value);
+      if (Z_TYPE_P(return_value) == IS_NULL) {
+        // unable to create class entry
+        skip_element(T_STRUCT, transport);
+        RETURN_NULL();
+      }
+
+      zval* spec = zend_read_static_property(Z_OBJCE_P(return_value), "_TSPEC", sizeof("_TSPEC")-1, false);
+      ZVAL_DEREF(spec);
+      if (EG(exception)) {
+        zend_object *ex = EG(exception);
+        EG(exception) = nullptr;
+        throw PHPExceptionWrapper(ex);
+      }
+      if (Z_TYPE_P(spec) != IS_ARRAY) {
+        char errbuf[128];
+        snprintf(errbuf, 128, "spec for %s is wrong type: %d\n", structType, Z_TYPE_P(spec));
+        throw_tprotocolexception(errbuf, INVALID_DATA);
+        RETURN_NULL();
+      }
+      binary_deserialize_spec(return_value, transport, Z_ARRVAL_P(spec));
+      return;
+    } break;
+    case T_BOOL: {
+      uint8_t c;
+      transport.readBytes(&c, 1);
+      RETURN_BOOL(c != 0);
+    }
+  //case T_I08: // same numeric value as T_BYTE
+    case T_BYTE: {
+      uint8_t c;
+      transport.readBytes(&c, 1);
+      RETURN_LONG((int8_t)c);
+    }
+    case T_I16: {
+      uint16_t c;
+      transport.readBytes(&c, 2);
+      RETURN_LONG((int16_t)ntohs(c));
+    }
+    case T_I32: {
+      uint32_t c;
+      transport.readBytes(&c, 4);
+      RETURN_LONG((int32_t)ntohl(c));
+    }
+    case T_U64:
+    case T_I64: {
+      uint64_t c;
+      transport.readBytes(&c, 8);
+      RETURN_LONG((int64_t)ntohll(c));
+    }
+    case T_DOUBLE: {
+      union {
+        uint64_t c;
+        double d;
+      } a;
+      transport.readBytes(&(a.c), 8);
+      a.c = ntohll(a.c);
+      RETURN_DOUBLE(a.d);
+    }
+    //case T_UTF7: // aliases T_STRING
+    case T_UTF8:
+    case T_UTF16:
+    case T_STRING: {
+      uint32_t size = transport.readU32();
+      if (size) {
+        char strbuf[size+1];
+        transport.readBytes(strbuf, size);
+        strbuf[size] = '\0';
+        ZVAL_STRINGL(return_value, strbuf, size);
+      } else {
+        ZVAL_EMPTY_STRING(return_value);
+      }
+      return;
+    }
+    case T_MAP: { // array of key -> value
+      uint8_t types[2];
+      transport.readBytes(types, 2);
+      uint32_t size = transport.readU32();
+      array_init(return_value);
+
+      zval *val_ptr;
+      val_ptr = zend_hash_str_find(fieldspec, "key", sizeof("key")-1);
+      HashTable* keyspec = Z_ARRVAL_P(val_ptr);
+      val_ptr = zend_hash_str_find(fieldspec, "val", sizeof("val")-1);
+      HashTable* valspec = Z_ARRVAL_P(val_ptr);
+
+      for (uint32_t s = 0; s < size; ++s) {
+        zval key, value;
+
+        binary_deserialize(types[0], transport, &key, keyspec);
+        binary_deserialize(types[1], transport, &value, valspec);
+        if (Z_TYPE(key) == IS_LONG) {
+          zend_hash_index_update(Z_ARR_P(return_value), Z_LVAL(key), &value);
+        } else {
+          if (Z_TYPE(key) != IS_STRING) convert_to_string(&key);
+          zend_symtable_update(Z_ARR_P(return_value), Z_STR(key), &value);
+        }
+        zval_dtor(&key);
+      }
+      return; // return_value already populated
+    }
+    case T_LIST: { // array with autogenerated numeric keys
+      int8_t type = transport.readI8();
+      uint32_t size = transport.readU32();
+      zval *val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1);
+      HashTable* elemspec = Z_ARRVAL_P(val_ptr);
+
+      array_init(return_value);
+      for (uint32_t s = 0; s < size; ++s) {
+        zval value;
+        binary_deserialize(type, transport, &value, elemspec);
+        zend_hash_next_index_insert(Z_ARR_P(return_value), &value);
+      }
+      return;
+    }
+    case T_SET: { // array of key -> TRUE
+      uint8_t type;
+      uint32_t size;
+      transport.readBytes(&type, 1);
+      transport.readBytes(&size, 4);
+      size = ntohl(size);
+      zval *val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1);
+      HashTable* elemspec = Z_ARRVAL_P(val_ptr);
+
+      array_init(return_value);
+
+      for (uint32_t s = 0; s < size; ++s) {
+        zval key, value;
+        ZVAL_TRUE(&value);
+
+        binary_deserialize(type, transport, &key, elemspec);
+
+        if (Z_TYPE(key) == IS_LONG) {
+          zend_hash_index_update(Z_ARR_P(return_value), Z_LVAL(key), &value);
+        } else {
+          if (Z_TYPE(key) != IS_STRING) convert_to_string(&key);
+          zend_symtable_update(Z_ARR_P(return_value), Z_STR(key), &value);
+        }
+        zval_dtor(&key);
+      }
+      return;
+    }
+  };
+
+  char errbuf[128];
+  sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID);
+  throw_tprotocolexception(errbuf, INVALID_DATA);
+}
+
+static
+void binary_serialize_hashtable_key(int8_t keytype, PHPOutputTransport& transport, HashTable* ht, HashPosition& ht_pos, HashTable* spec) {
   bool keytype_is_numeric = (!((keytype == T_STRING) || (keytype == T_UTF8) || (keytype == T_UTF16)));
 
-  char* key;
+  zend_string* key;
   uint key_len;
   long index = 0;
 
-  zval* z;
-  MAKE_STD_ZVAL(z);
+  zval z;
 
-  int res = zend_hash_get_current_key_ex(ht, &key, &key_len, (ulong*)&index, 0, &ht_pos);
-  if (keytype_is_numeric) {
-    if (res == HASH_KEY_IS_STRING) {
-      index = strtol(key, NULL, 10);
-    }
-    ZVAL_LONG(z, index);
+  int res = zend_hash_get_current_key_ex(ht, &key, (zend_ulong*)&index, &ht_pos);
+  if (res == HASH_KEY_IS_STRING) {
+    ZVAL_STR_COPY(&z, key);
   } else {
-    char buf[64];
-    if (res == HASH_KEY_IS_STRING) {
-      key_len -= 1; // skip the null terminator
-    } else {
-      sprintf(buf, "%ld", index);
-      key = buf; key_len = strlen(buf);
-    }
-    ZVAL_STRINGL(z, key, key_len, 1);
+    ZVAL_LONG(&z, index);
   }
-  binary_serialize(keytype, transport, &z, NULL);
-  zval_ptr_dtor(&z);
+  binary_serialize(keytype, transport, &z, spec);
+  zval_dtor(&z);
 }
 
-inline bool ttype_is_int(int8_t t) {
+static
+void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, zval* value, HashTable* fieldspec) {
+  if (value) {
+    ZVAL_DEREF(value);
+  }
+  // At this point the typeID (and field num, if applicable) should've already been written to the output so all we need to do is write the payload.
+  switch (thrift_typeID) {
+    case T_STOP:
+    case T_VOID:
+      return;
+    case T_STRUCT: {
+      if (Z_TYPE_P(value) != IS_OBJECT) {
+        throw_tprotocolexception("Attempt to send non-object type as a T_STRUCT", INVALID_DATA);
+      }
+      zval* spec = zend_read_static_property(Z_OBJCE_P(value), "_TSPEC", sizeof("_TSPEC")-1, true);
+      if (spec && Z_TYPE_P(spec) == IS_REFERENCE) {
+        ZVAL_DEREF(spec);
+      }
+      if (!spec || Z_TYPE_P(spec) != IS_ARRAY) {
+        throw_tprotocolexception("Attempt to send non-Thrift object as a T_STRUCT", INVALID_DATA);
+      }
+      binary_serialize_spec(value, transport, Z_ARRVAL_P(spec));
+    } return;
+    case T_BOOL:
+      if (!zval_is_bool(value)) convert_to_boolean(value);
+      transport.writeI8(Z_TYPE_INFO_P(value) == IS_TRUE ? 1 : 0);
+      return;
+    case T_BYTE:
+      if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value);
+      transport.writeI8(Z_LVAL_P(value));
+      return;
+    case T_I16:
+      if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value);
+      transport.writeI16(Z_LVAL_P(value));
+      return;
+    case T_I32:
+      if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value);
+      transport.writeI32(Z_LVAL_P(value));
+      return;
+    case T_I64:
+    case T_U64: {
+      int64_t l_data;
+#if defined(_LP64) || defined(_WIN64)
+      if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value);
+      l_data = Z_LVAL_P(value);
+#else
+      if (Z_TYPE_P(value) != IS_DOUBLE) convert_to_double(value);
+      l_data = (int64_t)Z_DVAL_P(value);
+#endif
+      transport.writeI64(l_data);
+    } return;
+    case T_DOUBLE: {
+      union {
+        int64_t c;
+        double d;
+      } a;
+      if (Z_TYPE_P(value) != IS_DOUBLE) convert_to_double(value);
+      a.d = Z_DVAL_P(value);
+      transport.writeI64(a.c);
+    } return;
+    case T_UTF8:
+    case T_UTF16:
+    case T_STRING:
+      if (Z_TYPE_P(value) != IS_STRING) convert_to_string(value);
+      transport.writeString(Z_STRVAL_P(value), Z_STRLEN_P(value));
+      return;
+    case T_MAP: {
+      if (Z_TYPE_P(value) != IS_ARRAY) convert_to_array(value);
+      if (Z_TYPE_P(value) != IS_ARRAY) {
+        throw_tprotocolexception("Attempt to send an incompatible type as an array (T_MAP)", INVALID_DATA);
+      }
+      HashTable* ht = Z_ARRVAL_P(value);
+      zval* val_ptr;
+
+      val_ptr = zend_hash_str_find(fieldspec, "ktype", sizeof("ktype")-1);
+      if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr);
+      uint8_t keytype = Z_LVAL_P(val_ptr);
+      transport.writeI8(keytype);
+      val_ptr = zend_hash_str_find(fieldspec, "vtype", sizeof("vtype")-1);
+      if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr);
+      uint8_t valtype = Z_LVAL_P(val_ptr);
+      transport.writeI8(valtype);
+
+      val_ptr = zend_hash_str_find(fieldspec, "val", sizeof("val")-1);
+      HashTable* valspec = Z_ARRVAL_P(val_ptr);
+      HashTable* keyspec = Z_ARRVAL_P(zend_hash_str_find(fieldspec, "key", sizeof("key")-1));
+
+      transport.writeI32(zend_hash_num_elements(ht));
+      HashPosition key_ptr;
+      for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr);
+           (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr;
+           zend_hash_move_forward_ex(ht, &key_ptr)) {
+        binary_serialize_hashtable_key(keytype, transport, ht, key_ptr, keyspec);
+        binary_serialize(valtype, transport, val_ptr, valspec);
+      }
+    } return;
+    case T_LIST: {
+      if (Z_TYPE_P(value) != IS_ARRAY) convert_to_array(value);
+      if (Z_TYPE_P(value) != IS_ARRAY) {
+        throw_tprotocolexception("Attempt to send an incompatible type as an array (T_LIST)", INVALID_DATA);
+      }
+      HashTable* ht = Z_ARRVAL_P(value);
+      zval* val_ptr;
+
+      val_ptr = zend_hash_str_find(fieldspec, "etype", sizeof("etype")-1);
+      if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr);
+      uint8_t valtype = Z_LVAL_P(val_ptr);
+      transport.writeI8(valtype);
+
+      val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1);
+      HashTable* valspec = Z_ARRVAL_P(val_ptr);
+
+      transport.writeI32(zend_hash_num_elements(ht));
+      HashPosition key_ptr;
+      for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr);
+           (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr;
+           zend_hash_move_forward_ex(ht, &key_ptr)) {
+        binary_serialize(valtype, transport, val_ptr, valspec);
+      }
+    } return;
+    case T_SET: {
+      if (Z_TYPE_P(value) != IS_ARRAY) convert_to_array(value);
+      if (Z_TYPE_P(value) != IS_ARRAY) {
+        throw_tprotocolexception("Attempt to send an incompatible type as an array (T_SET)", INVALID_DATA);
+      }
+      HashTable* ht = Z_ARRVAL_P(value);
+      zval* val_ptr;
+
+      val_ptr = zend_hash_str_find(fieldspec, "etype", sizeof("etype")-1);
+      HashTable* spec = Z_ARRVAL_P(zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1));
+      if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr);
+      uint8_t keytype = Z_LVAL_P(val_ptr);
+      transport.writeI8(keytype);
+
+      transport.writeI32(zend_hash_num_elements(ht));
+      HashPosition key_ptr;
+      if(ttype_is_scalar(keytype)){
+        for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr);
+             (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr;
+             zend_hash_move_forward_ex(ht, &key_ptr)) {
+          binary_serialize_hashtable_key(keytype, transport, ht, key_ptr, spec);
+        }
+      } else {
+        for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr);
+             (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr;
+             zend_hash_move_forward_ex(ht, &key_ptr)) {
+          binary_serialize(keytype, transport, val_ptr, spec);
+        }
+      }
+    } return;
+  };
+
+  char errbuf[128];
+  snprintf(errbuf, 128, "Unknown thrift typeID %d", thrift_typeID);
+  throw_tprotocolexception(errbuf, INVALID_DATA);
+}
+
+static
+void protocol_writeMessageBegin(zval* transport, zend_string* method_name, int32_t msgtype, int32_t seqID) {
+  zval args[3];
+  zval ret;
+  zval writeMessagefn;
+
+  ZVAL_STR_COPY(&args[0], method_name);
+  ZVAL_LONG(&args[1], msgtype);
+  ZVAL_LONG(&args[2], seqID);
+  ZVAL_NULL(&ret);
+  ZVAL_STRING(&writeMessagefn, "writeMessageBegin");
+
+  call_user_function(EG(function_table), transport, &writeMessagefn, &ret, 3, args);
+
+  zval_dtor(&writeMessagefn);
+  zval_dtor(&args[2]); zval_dtor(&args[1]); zval_dtor(&args[0]);
+  zval_dtor(&ret);
+  if (EG(exception)) {
+    zend_object *ex = EG(exception);
+    EG(exception) = nullptr;
+    throw PHPExceptionWrapper(ex);
+  }
+}
+
+static inline
+bool ttype_is_int(int8_t t) {
   return ((t == T_BYTE) || ((t >= T_I16)  && (t <= T_I64)));
 }
+static inline
+bool ttype_is_scalar(int8_t t) {
+  return !((t == T_STRUCT) || ( t== T_MAP)  || (t == T_SET) || (t == T_LIST));
+}
 
-inline bool ttypes_are_compatible(int8_t t1, int8_t t2) {
+static inline
+bool ttypes_are_compatible(int8_t t1, int8_t t2) {
   // Integer types of different widths are considered compatible;
   // otherwise the typeID must match.
   return ((t1 == t2) || (ttype_is_int(t1) && ttype_is_int(t2)));
 }
 
+//is used to validate objects before serialization and after deserialization. For now, only required fields are validated.
+static
+void validate_thrift_object(zval* object) {
+    zend_class_entry* object_class_entry = Z_OBJCE_P(object);
+    zval* is_validate = zend_read_static_property(object_class_entry, "isValidate", sizeof("isValidate")-1, true);
+    if (is_validate) {
+      ZVAL_DEREF(is_validate);
+    }
+    zval* spec = zend_read_static_property(object_class_entry, "_TSPEC", sizeof("_TSPEC")-1, true);
+    if (spec) {
+      ZVAL_DEREF(spec);
+    }
+    HashPosition key_ptr;
+    zval* val_ptr;
+
+    if (is_validate && Z_TYPE_INFO_P(is_validate) == IS_TRUE) {
+        for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(spec), &key_ptr);
+           (val_ptr = zend_hash_get_current_data_ex(Z_ARRVAL_P(spec), &key_ptr)) != nullptr;
+           zend_hash_move_forward_ex(Z_ARRVAL_P(spec), &key_ptr)) {
+
+            zend_ulong fieldno;
+            if (zend_hash_get_current_key_ex(Z_ARRVAL_P(spec), nullptr, &fieldno, &key_ptr) != HASH_KEY_IS_LONG) {
+              throw_tprotocolexception("Bad keytype in TSPEC (expected 'long')", INVALID_DATA);
+              return;
+            }
+            HashTable* fieldspec = Z_ARRVAL_P(val_ptr);
+
+            // field name
+            zval* zvarname = zend_hash_str_find(fieldspec, "var", sizeof("var")-1);
+            char* varname = Z_STRVAL_P(zvarname);
+
+            zval* is_required = zend_hash_str_find(fieldspec, "isRequired", sizeof("isRequired")-1);
+            zval rv;
+            zval* prop = zend_read_property(object_class_entry, object, varname, strlen(varname), false, &rv);
+
+            if (Z_TYPE_INFO_P(is_required) == IS_TRUE && Z_TYPE_P(prop) == IS_NULL) {
+                char errbuf[128];
+                snprintf(errbuf, 128, "Required field %s.%s is unset!", ZSTR_VAL(object_class_entry->name), varname);
+                throw_tprotocolexception(errbuf, INVALID_DATA);
+            }
+        }
+    }
+}
+
+static
 void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTable* spec) {
   // SET and LIST have 'elem' => array('type', [optional] 'class')
   // MAP has 'val' => array('type', [optiona] 'class')
-  TSRMLS_FETCH();
-  zend_class_entry* ce = zend_get_class_entry(zthis TSRMLS_CC);
+  zend_class_entry* ce = Z_OBJCE_P(zthis);
   while (true) {
-    zval** val_ptr = NULL;
-
     int8_t ttype = transport.readI8();
-    if (ttype == T_STOP) return;
+    if (ttype == T_STOP) {
+      validate_thrift_object(zthis);
+      return;
+    }
+
     int16_t fieldno = transport.readI16();
-    if (zend_hash_index_find(spec, fieldno, (void**)&val_ptr) == SUCCESS) {
-      HashTable* fieldspec = Z_ARRVAL_PP(val_ptr);
+    zval* val_ptr = zend_hash_index_find(spec, fieldno);
+    if (val_ptr != nullptr) {
+      HashTable* fieldspec = Z_ARRVAL_P(val_ptr);
       // pull the field name
-      // zend hash tables use the null at the end in the length... so strlen(hash key) + 1.
-      zend_hash_find(fieldspec, "var", 4, (void**)&val_ptr);
-      char* varname = Z_STRVAL_PP(val_ptr);
+      val_ptr = zend_hash_str_find(fieldspec, "var", sizeof("var")-1);
+      char* varname = Z_STRVAL_P(val_ptr);
 
       // and the type
-      zend_hash_find(fieldspec, "type", 5, (void**)&val_ptr);
-      if (Z_TYPE_PP(val_ptr) != IS_LONG) convert_to_long(*val_ptr);
-      int8_t expected_ttype = Z_LVAL_PP(val_ptr);
+      val_ptr = zend_hash_str_find(fieldspec, "type", sizeof("type")-1);
+      if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr);
+      int8_t expected_ttype = Z_LVAL_P(val_ptr);
 
       if (ttypes_are_compatible(ttype, expected_ttype)) {
-        zval* rv = NULL;
-        MAKE_STD_ZVAL(rv);
-        binary_deserialize(ttype, transport, rv, fieldspec);
-        zend_update_property(ce, zthis, varname, strlen(varname), rv TSRMLS_CC);
+        zval rv;
+        ZVAL_UNDEF(&rv);
+
+        binary_deserialize(ttype, transport, &rv, fieldspec);
+        zend_update_property(ce, zthis, varname, strlen(varname), &rv);
+
         zval_ptr_dtor(&rv);
       } else {
         skip_element(ttype, transport);
@@ -767,219 +981,44 @@
   }
 }
 
-void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, zval** value, HashTable* fieldspec) {
-  Z_ADDREF_P(*value);
-  // At this point the typeID (and field num, if applicable) should've already been written to the output so all we need to do is write the payload.
-  switch (thrift_typeID) {
-    case T_STOP:
-    case T_VOID:
-      return;
-    case T_STRUCT: {
-      TSRMLS_FETCH();
-      if (Z_TYPE_PP(value) != IS_OBJECT) {
-        throw_tprotocolexception("Attempt to send non-object type as a T_STRUCT", INVALID_DATA);
-      }
-      zval* spec = zend_read_static_property(zend_get_class_entry(*value TSRMLS_CC), "_TSPEC", 6, false TSRMLS_CC);
-      if (Z_TYPE_P(spec) != IS_ARRAY) {
-        throw_tprotocolexception("Attempt to send non-Thrift object as a T_STRUCT", INVALID_DATA);
-      }
-      binary_serialize_spec(*value, transport, Z_ARRVAL_P(spec));
-    } return;
-    case T_BOOL:
-      if (Z_TYPE_PP(value) != IS_BOOL) {
-        SEPARATE_ZVAL(value);
-        convert_to_boolean(*value);
-      }
-      transport.writeI8(Z_BVAL_PP(value) ? 1 : 0);
-      zval_ptr_dtor(value);
-      return;
-    case T_BYTE:
-      if (Z_TYPE_PP(value) != IS_LONG) {
-        SEPARATE_ZVAL(value);
-        convert_to_long(*value);
-      }
-      transport.writeI8(Z_LVAL_PP(value));
-      zval_ptr_dtor(value);
-      return;
-    case T_I16:
-      if (Z_TYPE_PP(value) != IS_LONG) {
-        SEPARATE_ZVAL(value);
-        convert_to_long(*value);
-      }
-      transport.writeI16(Z_LVAL_PP(value));
-      zval_ptr_dtor(value);
-      return;
-    case T_I32:
-      if (Z_TYPE_PP(value) != IS_LONG) {
-        SEPARATE_ZVAL(value);
-        convert_to_long(*value);
-      }
-      transport.writeI32(Z_LVAL_PP(value));
-      zval_ptr_dtor(value);
-      return;
-    case T_I64:
-    case T_U64: {
-      int64_t l_data;
-#if defined(_LP64) || defined(_WIN64)
-      if (Z_TYPE_PP(value) != IS_LONG) {
-        SEPARATE_ZVAL(value);
-        convert_to_long(*value);
-      }
-      l_data = Z_LVAL_PP(value);
-#else
-      if (Z_TYPE_PP(value) != IS_DOUBLE) {
-        SEPARATE_ZVAL(value);
-        convert_to_double(*value);
-      }
-      l_data = (int64_t)Z_DVAL_PP(value);
-#endif
-      transport.writeI64(l_data);
-    } return;
-    case T_DOUBLE: {
-      union {
-        int64_t c;
-        double d;
-      } a;
-      if (Z_TYPE_PP(value) != IS_DOUBLE) {
-        SEPARATE_ZVAL(value);
-        convert_to_double(*value);
-      }
-      a.d = Z_DVAL_PP(value);
-      transport.writeI64(a.c);
-      zval_ptr_dtor(value);
-    } return;
-    //case T_UTF7:
-    case T_UTF8:
-    case T_UTF16:
-    case T_STRING:
-      if (Z_TYPE_PP(value) != IS_STRING) {
-        SEPARATE_ZVAL(value);
-        convert_to_string(*value);
-      }
-      transport.writeString(Z_STRVAL_PP(value), Z_STRLEN_PP(value));
-      zval_ptr_dtor(value);
-      return;
-    case T_MAP: {
-      if (Z_TYPE_PP(value) != IS_ARRAY) {
-        SEPARATE_ZVAL(value);
-        convert_to_array(*value);
-      }
-      if (Z_TYPE_PP(value) != IS_ARRAY) {
-        zval_ptr_dtor(value);
-        throw_tprotocolexception("Attempt to send an incompatible type as an array (T_MAP)", INVALID_DATA);
-      }
-      HashTable* ht = Z_ARRVAL_PP(value);
-      zval** val_ptr;
-
-      zend_hash_find(fieldspec, "ktype", 6, (void**)&val_ptr);
-      if (Z_TYPE_PP(val_ptr) != IS_LONG) convert_to_long(*val_ptr);
-      uint8_t keytype = Z_LVAL_PP(val_ptr);
-      transport.writeI8(keytype);
-      zend_hash_find(fieldspec, "vtype", 6, (void**)&val_ptr);
-      if (Z_TYPE_PP(val_ptr) != IS_LONG) convert_to_long(*val_ptr);
-      uint8_t valtype = Z_LVAL_PP(val_ptr);
-      transport.writeI8(valtype);
-
-      zend_hash_find(fieldspec, "val", 4, (void**)&val_ptr);
-      HashTable* valspec = Z_ARRVAL_PP(val_ptr);
-
-      transport.writeI32(zend_hash_num_elements(ht));
-      HashPosition key_ptr;
-      for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); zend_hash_get_current_data_ex(ht, (void**)&val_ptr, &key_ptr) == SUCCESS; zend_hash_move_forward_ex(ht, &key_ptr)) {
-        binary_serialize_hashtable_key(keytype, transport, ht, key_ptr);
-        binary_serialize(valtype, transport, val_ptr, valspec);
-      }
-      zval_ptr_dtor(value);
-    } return;
-    case T_LIST: {
-      if (Z_TYPE_PP(value) != IS_ARRAY) {
-        SEPARATE_ZVAL(value);
-        convert_to_array(*value);
-      }
-      if (Z_TYPE_PP(value) != IS_ARRAY) {
-        zval_ptr_dtor(value);
-        throw_tprotocolexception("Attempt to send an incompatible type as an array (T_LIST)", INVALID_DATA);
-      }
-      HashTable* ht = Z_ARRVAL_PP(value);
-      zval** val_ptr;
-
-      zend_hash_find(fieldspec, "etype", 6, (void**)&val_ptr);
-      if (Z_TYPE_PP(val_ptr) != IS_LONG) convert_to_long(*val_ptr);
-      uint8_t valtype = Z_LVAL_PP(val_ptr);
-      transport.writeI8(valtype);
-
-      zend_hash_find(fieldspec, "elem", 5, (void**)&val_ptr);
-      HashTable* valspec = Z_ARRVAL_PP(val_ptr);
-
-      transport.writeI32(zend_hash_num_elements(ht));
-      HashPosition key_ptr;
-      for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); zend_hash_get_current_data_ex(ht, (void**)&val_ptr, &key_ptr) == SUCCESS; zend_hash_move_forward_ex(ht, &key_ptr)) {
-        binary_serialize(valtype, transport, val_ptr, valspec);
-      }
-      zval_ptr_dtor(value);
-    } return;
-    case T_SET: {
-      if (Z_TYPE_PP(value) != IS_ARRAY) {
-        SEPARATE_ZVAL(value);
-        convert_to_array(*value);
-      }
-      if (Z_TYPE_PP(value) != IS_ARRAY) {
-        zval_ptr_dtor(value);
-        throw_tprotocolexception("Attempt to send an incompatible type as an array (T_SET)", INVALID_DATA);
-      }
-      HashTable* ht = Z_ARRVAL_PP(value);
-      zval** val_ptr;
-
-      zend_hash_find(fieldspec, "etype", 6, (void**)&val_ptr);
-      if (Z_TYPE_PP(val_ptr) != IS_LONG) convert_to_long(*val_ptr);
-      uint8_t keytype = Z_LVAL_PP(val_ptr);
-      transport.writeI8(keytype);
-
-      transport.writeI32(zend_hash_num_elements(ht));
-      HashPosition key_ptr;
-      for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); zend_hash_get_current_data_ex(ht, (void**)&val_ptr, &key_ptr) == SUCCESS; zend_hash_move_forward_ex(ht, &key_ptr)) {
-        binary_serialize_hashtable_key(keytype, transport, ht, key_ptr);
-      }
-      zval_ptr_dtor(value);
-    } return;
-  };
-
-  zval_ptr_dtor(value);
-  char errbuf[128];
-  sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID);
-  throw_tprotocolexception(errbuf, INVALID_DATA);
-}
-
-
+static
 void binary_serialize_spec(zval* zthis, PHPOutputTransport& transport, HashTable* spec) {
+
+  validate_thrift_object(zthis);
+
   HashPosition key_ptr;
-  zval** val_ptr;
+  zval* val_ptr;
 
-  TSRMLS_FETCH();
-  zend_class_entry* ce = zend_get_class_entry(zthis TSRMLS_CC);
+  for (zend_hash_internal_pointer_reset_ex(spec, &key_ptr);
+       (val_ptr = zend_hash_get_current_data_ex(spec, &key_ptr)) != nullptr;
+       zend_hash_move_forward_ex(spec, &key_ptr)) {
 
-  for (zend_hash_internal_pointer_reset_ex(spec, &key_ptr); zend_hash_get_current_data_ex(spec, (void**)&val_ptr, &key_ptr) == SUCCESS; zend_hash_move_forward_ex(spec, &key_ptr)) {
-    ulong fieldno;
-    if (zend_hash_get_current_key_ex(spec, NULL, NULL, &fieldno, 0, &key_ptr) != HASH_KEY_IS_LONG) {
+    zend_ulong fieldno;
+    if (zend_hash_get_current_key_ex(spec, nullptr, &fieldno, &key_ptr) != HASH_KEY_IS_LONG) {
       throw_tprotocolexception("Bad keytype in TSPEC (expected 'long')", INVALID_DATA);
       return;
     }
-    HashTable* fieldspec = Z_ARRVAL_PP(val_ptr);
+    HashTable* fieldspec = Z_ARRVAL_P(val_ptr);
 
     // field name
-    zend_hash_find(fieldspec, "var", 4, (void**)&val_ptr);
-    char* varname = Z_STRVAL_PP(val_ptr);
+    val_ptr = zend_hash_str_find(fieldspec, "var", sizeof("var")-1);
+    char* varname = Z_STRVAL_P(val_ptr);
 
     // thrift type
-    zend_hash_find(fieldspec, "type", 5, (void**)&val_ptr);
-    if (Z_TYPE_PP(val_ptr) != IS_LONG) convert_to_long(*val_ptr);
-    int8_t ttype = Z_LVAL_PP(val_ptr);
+    val_ptr = zend_hash_str_find(fieldspec, "type", sizeof("type")-1);
+    if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr);
+    int8_t ttype = Z_LVAL_P(val_ptr);
 
-    zval* prop = zend_read_property(ce, zthis, varname, strlen(varname), false TSRMLS_CC);
+    zval rv;
+    zval* prop = zend_read_property(Z_OBJCE_P(zthis), zthis, varname, strlen(varname), false, &rv);
+
+    if (Z_TYPE_P(prop) == IS_REFERENCE){
+      ZVAL_UNREF(prop);
+    }
     if (Z_TYPE_P(prop) != IS_NULL) {
       transport.writeI8(ttype);
       transport.writeI16(fieldno);
-      binary_serialize(ttype, transport, &prop, fieldspec);
+      binary_serialize(ttype, transport, prop, fieldspec);
     }
   }
   transport.writeI8(T_STOP); // struct end
@@ -987,93 +1026,59 @@
 
 // 6 params: $transport $method_name $ttype $request_struct $seqID $strict_write
 PHP_FUNCTION(thrift_protocol_write_binary) {
-  int argc = ZEND_NUM_ARGS();
-  if (argc < 6) {
-    WRONG_PARAM_COUNT;
+  zval *protocol;
+  zval *request_struct;
+  zend_string *method_name;
+  long msgtype, seqID;
+  zend_bool strict_write;
+
+  if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "oSlolb",
+    &protocol, &method_name, &msgtype,
+    &request_struct, &seqID, &strict_write) == FAILURE) {
+      return;
   }
 
-  zval ***args = (zval***) emalloc(argc * sizeof(zval**));
-  zend_get_parameters_array_ex(argc, args);
-
-  if (Z_TYPE_PP(args[0]) != IS_OBJECT) {
-    php_error_docref(NULL TSRMLS_CC, E_ERROR, "1st parameter is not an object (transport)");
-    efree(args);
-    RETURN_NULL();
-  }
-
-  if (Z_TYPE_PP(args[1]) != IS_STRING) {
-    php_error_docref(NULL TSRMLS_CC, E_ERROR, "2nd parameter is not a string (method name)");
-    efree(args);
-    RETURN_NULL();
-  }
-
-  if (Z_TYPE_PP(args[3]) != IS_OBJECT) {
-    php_error_docref(NULL TSRMLS_CC, E_ERROR, "4th parameter is not an object (request struct)");
-    efree(args);
-    RETURN_NULL();
-  }
-
-
   try {
-    PHPOutputTransport transport(*args[0]);
-    zval *protocol = *args[0];
-    const char* method_name = Z_STRVAL_PP(args[1]);
-    convert_to_long(*args[2]);
-    int32_t msgtype = Z_LVAL_PP(args[2]);
-    zval* request_struct = *args[3];
-    convert_to_long(*args[4]);
-    int32_t seqID = Z_LVAL_PP(args[4]);
-    convert_to_boolean(*args[5]);
-    bool strictWrite = Z_BVAL_PP(args[5]);
-    efree(args);
-    args = NULL;
-    protocol_writeMessageBegin(protocol, method_name, msgtype, seqID);
-    zval* spec = zend_read_static_property(zend_get_class_entry(request_struct TSRMLS_CC), "_TSPEC", 6, false TSRMLS_CC);
-    if (Z_TYPE_P(spec) != IS_ARRAY) {
-        throw_tprotocolexception("Attempt to send non-Thrift object", INVALID_DATA);
+    zval* spec = zend_read_static_property(Z_OBJCE_P(request_struct), "_TSPEC", sizeof("_TSPEC")-1, true);
+    if (spec) {
+      ZVAL_DEREF(spec);
     }
+
+    if (!spec || Z_TYPE_P(spec) != IS_ARRAY) {
+      throw_tprotocolexception("Attempt serialize from non-Thrift object", INVALID_DATA);
+    }
+
+    PHPOutputTransport transport(protocol);
+    protocol_writeMessageBegin(protocol, method_name, (int32_t) msgtype, (int32_t) seqID);
     binary_serialize_spec(request_struct, transport, Z_ARRVAL_P(spec));
     transport.flush();
+
   } catch (const PHPExceptionWrapper& ex) {
-    zend_throw_exception_object(ex TSRMLS_CC);
+    // ex will be destructed, so copy to a zval that zend_throw_exception_object can take ownership of
+    zval myex;
+    ZVAL_COPY(&myex, ex);
+    zend_throw_exception_object(&myex);
     RETURN_NULL();
   } catch (const std::exception& ex) {
-    throw_zend_exception_from_std_exception(ex TSRMLS_CC);
+    throw_zend_exception_from_std_exception(ex);
     RETURN_NULL();
   }
 }
 
-// 3 params: $transport $response_Typename $strict_read
+
+// 4 params: $transport $response_Typename $strict_read $buffer_size
 PHP_FUNCTION(thrift_protocol_read_binary) {
-  int argc = ZEND_NUM_ARGS();
+  zval *protocol;
+  zend_string *obj_typename;
+  zend_bool strict_read;
+  size_t buffer_size = 8192;
 
-  if (argc < 3) {
-    WRONG_PARAM_COUNT;
-  }
-
-  zval ***args = (zval***) emalloc(argc * sizeof(zval**));
-  zend_get_parameters_array_ex(argc, args);
-
-  if (Z_TYPE_PP(args[0]) != IS_OBJECT) {
-    php_error_docref(NULL TSRMLS_CC, E_ERROR, "1st parameter is not an object (transport)");
-    efree(args);
-    RETURN_NULL();
-  }
-
-  if (Z_TYPE_PP(args[1]) != IS_STRING) {
-    php_error_docref(NULL TSRMLS_CC, E_ERROR, "2nd parameter is not a string (typename of expected response struct)");
-    efree(args);
-    RETURN_NULL();
+  if (zend_parse_parameters(ZEND_NUM_ARGS(), "oSb|l", &protocol, &obj_typename, &strict_read, &buffer_size) == FAILURE) {
+    return;
   }
 
   try {
-    PHPInputTransport transport(*args[0]);
-    char* obj_typename = Z_STRVAL_PP(args[1]);
-    convert_to_boolean(*args[2]);
-    bool strict_read = Z_BVAL_PP(args[2]);
-    efree(args);
-    args = NULL;
-
+    PHPInputTransport transport(protocol, buffer_size);
     int8_t messageType = 0;
     int32_t sz = transport.readI32();
 
@@ -1099,23 +1104,69 @@
     }
 
     if (messageType == T_EXCEPTION) {
-      zval* ex;
-      MAKE_STD_ZVAL(ex);
-      createObject("\\Thrift\\Exception\\TApplicationException", ex);
-      zval* spec = zend_read_static_property(zend_get_class_entry(ex TSRMLS_CC), "_TSPEC", 6, false TSRMLS_CC);
-      binary_deserialize_spec(ex, transport, Z_ARRVAL_P(spec));
-      throw PHPExceptionWrapper(ex);
+      zval ex;
+      createObject("\\Thrift\\Exception\\TApplicationException", &ex);
+      zval* spec = zend_read_static_property(Z_OBJCE(ex), "_TSPEC", sizeof("_TPSEC")-1, false);
+      ZVAL_DEREF(spec);
+      if (EG(exception)) {
+        zend_object *ex = EG(exception);
+        EG(exception) = nullptr;
+        throw PHPExceptionWrapper(ex);
+      }
+      binary_deserialize_spec(&ex, transport, Z_ARRVAL_P(spec));
+      throw PHPExceptionWrapper(&ex);
     }
 
-    createObject(obj_typename, return_value);
-    zval* spec = zend_read_static_property(zend_get_class_entry(return_value TSRMLS_CC), "_TSPEC", 6, false TSRMLS_CC);
+    createObject(ZSTR_VAL(obj_typename), return_value);
+    zval* spec = zend_read_static_property(Z_OBJCE_P(return_value), "_TSPEC", sizeof("_TSPEC")-1, true);
+    if (spec) {
+      ZVAL_DEREF(spec);
+    }
+    if (!spec || Z_TYPE_P(spec) != IS_ARRAY) {
+      throw_tprotocolexception("Attempt deserialize to non-Thrift object", INVALID_DATA);
+    }
     binary_deserialize_spec(return_value, transport, Z_ARRVAL_P(spec));
   } catch (const PHPExceptionWrapper& ex) {
-    zend_throw_exception_object(ex TSRMLS_CC);
+    // ex will be destructed, so copy to a zval that zend_throw_exception_object can ownership of
+    zval myex;
+    ZVAL_COPY(&myex, ex);
+    zval_dtor(return_value);
+    zend_throw_exception_object(&myex);
     RETURN_NULL();
   } catch (const std::exception& ex) {
-    throw_zend_exception_from_std_exception(ex TSRMLS_CC);
+    throw_zend_exception_from_std_exception(ex);
     RETURN_NULL();
   }
 }
 
+// 4 params: $transport $response_Typename $strict_read $buffer_size
+PHP_FUNCTION(thrift_protocol_read_binary_after_message_begin) {
+  zval *protocol;
+  zend_string *obj_typename;
+  zend_bool strict_read;
+  size_t buffer_size = 8192;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS(), "oSb|l", &protocol, &obj_typename, &strict_read, &buffer_size) == FAILURE) {
+    return;
+  }
+
+  try {
+    PHPInputTransport transport(protocol, buffer_size);
+
+    createObject(ZSTR_VAL(obj_typename), return_value);
+    zval* spec = zend_read_static_property(Z_OBJCE_P(return_value), "_TSPEC", sizeof("_TSPEC")-1, false);
+    ZVAL_DEREF(spec);
+    binary_deserialize_spec(return_value, transport, Z_ARRVAL_P(spec));
+  } catch (const PHPExceptionWrapper& ex) {
+    // ex will be destructed, so copy to a zval that zend_throw_exception_object can take ownership of
+    zval myex;
+    ZVAL_COPY(&myex, ex);
+    zend_throw_exception_object(&myex);
+    RETURN_NULL();
+  } catch (const std::exception& ex) {
+    throw_zend_exception_from_std_exception(ex);
+    RETURN_NULL();
+  }
+}
+
+#endif /* PHP_VERSION_ID >= 70000 */
diff --git a/lib/php/src/ext/thrift_protocol/php_thrift_protocol.h b/lib/php/src/ext/thrift_protocol/php_thrift_protocol.h
index 44d03cc..0420997 100644
--- a/lib/php/src/ext/thrift_protocol/php_thrift_protocol.h
+++ b/lib/php/src/ext/thrift_protocol/php_thrift_protocol.h
@@ -21,6 +21,7 @@
 
 PHP_FUNCTION(thrift_protocol_write_binary);
 PHP_FUNCTION(thrift_protocol_read_binary);
+PHP_FUNCTION(thrift_protocol_read_binary_after_message_begin);
 
 extern zend_module_entry thrift_protocol_module_entry;
 #define phpext_thrift_protocol_ptr &thrift_protocol_module_entry
diff --git a/lib/php/test/Fixtures.php b/lib/php/test/Fixtures.php
new file mode 100644
index 0000000..fd57d83
--- /dev/null
+++ b/lib/php/test/Fixtures.php
@@ -0,0 +1,194 @@
+<?php
+
+/*
+ * 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
+ */
+
+namespace Test\Thrift;
+
+use ThriftTest\Xtruct;
+use ThriftTest\Xtruct2;
+use ThriftTest\Numberz;
+use ThriftTest\Insanity;
+
+class Fixtures
+{
+    public static $bufsize = 8192; //big enough to read biggest serialized Fixture arg.
+    public static $testArgs = array();
+
+    public static function populateTestArgs()
+    {
+        self::$testArgs['testString1'] = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語";
+
+        self::$testArgs['testString2'] =
+            "quote: \\\" backslash:" .
+            " forwardslash-escaped: \\/ " .
+            " backspace: \b formfeed: \f newline: \n return: \r tab: " .
+            " now-all-of-them-together: \"\\\/\b\n\r\t" .
+            " now-a-bunch-of-junk: !@#\$%&()(&%$#{}{}<><><";
+
+        self::$testArgs['testString3'] =
+            "string that ends in double-backslash \\\\";
+
+        self::$testArgs['testUnicodeStringWithNonBMP'] =
+            "สวัสดี/𝒯";
+
+        self::$testArgs['testDouble'] = 3.1415926535898;
+
+        // TODO: add testBinary() call
+
+        self::$testArgs['testByte'] = 0x01;
+
+        self::$testArgs['testI32'] = pow(2, 30);
+
+        if (PHP_INT_SIZE == 8) {
+            self::$testArgs['testI64'] = pow(2, 60);
+        } else {
+            self::$testArgs['testI64'] = "1152921504606847000";
+        }
+
+        self::$testArgs['testStruct'] =
+            new Xtruct(
+                array(
+                    'string_thing' => 'worked',
+                    'byte_thing' => 0x01,
+                    'i32_thing' => pow(2, 30),
+                    'i64_thing' => self::$testArgs['testI64']
+                )
+            );
+
+        self::$testArgs['testNestNested'] =
+            new Xtruct(
+                array(
+                    'string_thing' => 'worked',
+                    'byte_thing' => 0x01,
+                    'i32_thing' => pow(2, 30),
+                    'i64_thing' => self::$testArgs['testI64']
+                )
+            );
+
+        self::$testArgs['testNest'] =
+            new Xtruct2(
+                array(
+                    'byte_thing' => 0x01,
+                    'struct_thing' => self::$testArgs['testNestNested'],
+                    'i32_thing' => pow(2, 15)
+                )
+            );
+
+        self::$testArgs['testMap'] =
+            array(
+                7 => 77,
+                8 => 88,
+                9 => 99
+            );
+
+        self::$testArgs['testStringMap'] =
+            array(
+                "a" => "123",
+                "a b" => "with spaces ",
+                "same" => "same",
+                "0" => "numeric key",
+                "longValue" => self::$testArgs['testString1'],
+                self::$testArgs['testString1'] => "long key"
+            );
+
+        self::$testArgs['testSet'] = array(1 => true, 5 => true, 6 => true);
+
+        self::$testArgs['testList'] = array(1, 2, 3);
+
+        self::$testArgs['testEnum'] = Numberz::ONE;
+
+        self::$testArgs['testTypedef'] = 69;
+
+        self::$testArgs['testMapMapExpectedResult'] =
+            array(
+                4 => array(
+                    1 => 1,
+                    2 => 2,
+                    3 => 3,
+                    4 => 4,
+                ),
+                -4 => array(
+                    -4 => -4,
+                    -3 => -3,
+                    -2 => -2,
+                    -1 => -1
+                )
+            );
+
+        // testInsanity ... takes a few steps to set up!
+
+        $xtruct1 =
+            new Xtruct(
+                array(
+                    'string_thing' => 'Goodbye4',
+                    'byte_thing' => 4,
+                    'i32_thing' => 4,
+                    'i64_thing' => 4
+                )
+            );
+
+        $xtruct2 =
+            new Xtruct(
+                array(
+                    'string_thing' => 'Hello2',
+                    'byte_thing' => 2,
+                    'i32_thing' => 2,
+                    'i64_thing' => 2
+                )
+            );
+
+        $userMap =
+            array(
+                Numberz::FIVE => 5,
+                Numberz::EIGHT => 8
+            );
+
+        $insanity2 =
+            new Insanity(
+                array(
+                    'userMap' => $userMap,
+                    'xtructs' => array($xtruct1, $xtruct2)
+                )
+            );
+
+        $insanity3 = $insanity2;
+
+        $insanity6 =
+            new Insanity(
+                array(
+                    'userMap' => null,
+                    'xtructs' => null
+                )
+            );
+
+        self::$testArgs['testInsanityExpectedResult'] =
+            array(
+                "1" => array(
+                    Numberz::TWO => $insanity2,
+                    Numberz::THREE => $insanity3
+                ),
+                "2" => array(
+                    Numberz::SIX => $insanity6
+                )
+            );
+    }
+}
diff --git a/lib/php/test/JsonSerialize/JsonSerializeTest.php b/lib/php/test/JsonSerialize/JsonSerializeTest.php
new file mode 100644
index 0000000..c668652
--- /dev/null
+++ b/lib/php/test/JsonSerialize/JsonSerializeTest.php
@@ -0,0 +1,116 @@
+<?php
+/*
+ * 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.
+ */
+
+namespace Test\Thrift\JsonSerialize;
+
+use PHPUnit\Framework\TestCase;
+use stdClass;
+
+require __DIR__ . '/../../../../vendor/autoload.php';
+
+/**
+ * @runTestsInSeparateProcesses
+ */
+class JsonSerializeTest extends TestCase
+{
+    protected function setUp()
+    {
+        if (version_compare(phpversion(), '5.4', '<')) {
+            $this->markTestSkipped('Requires PHP 5.4 or newer!');
+        }
+        /** @var \Composer\Autoload\ClassLoader $loader */
+        $loader = require __DIR__ . '/../../../../vendor/autoload.php';
+        $loader->addPsr4('', __DIR__ . '/../packages/phpjs');
+    }
+
+    public function testEmptyStruct()
+    {
+        $empty = new \ThriftTest\EmptyStruct(array('non_existing_key' => 'bar'));
+        $this->assertEquals(new stdClass(), json_decode(json_encode($empty)));
+    }
+
+    public function testStringsAndInts()
+    {
+        $input = array(
+            'string_thing' => 'foo',
+            'i64_thing' => 1234567890,
+        );
+        $xtruct = new \ThriftTest\Xtruct($input);
+
+        // Xtruct's 'i32_thing' and 'byte_thing' fields should not be present here!
+        $expected = new stdClass();
+        $expected->string_thing = $input['string_thing'];
+        $expected->i64_thing = $input['i64_thing'];
+        $this->assertEquals($expected, json_decode(json_encode($xtruct)));
+    }
+
+    public function testNestedStructs()
+    {
+        $xtruct2 = new \ThriftTest\Xtruct2(array(
+            'byte_thing' => 42,
+            'struct_thing' => new \ThriftTest\Xtruct(array(
+                'i32_thing' => 123456,
+            )),
+        ));
+
+        $expected = new stdClass();
+        $expected->byte_thing = $xtruct2->byte_thing;
+        $expected->struct_thing = new stdClass();
+        $expected->struct_thing->i32_thing = $xtruct2->struct_thing->i32_thing;
+        $this->assertEquals($expected, json_decode(json_encode($xtruct2)));
+    }
+
+    public function testInsanity()
+    {
+        $xinput = array('string_thing' => 'foo');
+        $xtruct = new \ThriftTest\Xtruct($xinput);
+        $insanity = new \ThriftTest\Insanity(array(
+            'xtructs' => array($xtruct, $xtruct, $xtruct)
+        ));
+        $expected = new stdClass();
+        $expected->xtructs = array((object)$xinput, (object)$xinput, (object)$xinput);
+        $this->assertEquals($expected, json_decode(json_encode($insanity)));
+    }
+
+    public function testNestedLists()
+    {
+        $bonk = new \ThriftTest\Bonk(array('message' => 'foo'));
+        $nested = new \ThriftTest\NestedListsBonk(array('bonk' => array(array(array($bonk)))));
+        $expected = new stdClass();
+        $expected->bonk = array(array(array((object)array('message' => 'foo'))));
+        $this->assertEquals($expected, json_decode(json_encode($nested)));
+    }
+
+    public function testMaps()
+    {
+        $intmap = new \ThriftTest\ThriftTest_testMap_args(['thing' => [0 => 'zero']]);
+        $emptymap = new \ThriftTest\ThriftTest_testMap_args([]);
+        $this->assertEquals('{"thing":{"0":"zero"}}', json_encode($intmap));
+        $this->assertEquals('{}', json_encode($emptymap));
+    }
+
+    public function testScalarTypes()
+    {
+        $b = new \ThriftTest\Bools(['im_true' => '1', 'im_false' => '0']);
+        $this->assertEquals('{"im_true":true,"im_false":false}', json_encode($b));
+        $s = new \ThriftTest\StructA(['s' => 42]);
+        $this->assertEquals('{"s":"42"}', json_encode($s));
+    }
+}
diff --git a/lib/php/test/Makefile.am b/lib/php/test/Makefile.am
index 2fd7f81..4824688 100755
--- a/lib/php/test/Makefile.am
+++ b/lib/php/test/Makefile.am
@@ -17,19 +17,37 @@
 # under the License.
 #
 
-THRIFT = $(top_builddir)/compiler/cpp/thrift
+PHPUNIT=php $(top_srcdir)/vendor/bin/phpunit
 
-stubs: ../../../test/ThriftTest.thrift
-	mkdir -p ./packages
-	$(THRIFT) --gen php -r --out ./packages ../../../test/ThriftTest.thrift
+stubs: ../../../test/ThriftTest.thrift  TestValidators.thrift
+	mkdir -p ./packages/php
+	$(THRIFT) --gen php -r --out ./packages/php ../../../test/ThriftTest.thrift
+	mkdir -p ./packages/phpv
+	mkdir -p ./packages/phpvo
+	mkdir -p ./packages/phpjs
+	$(THRIFT) --gen php:validate     -r --out ./packages/phpv   TestValidators.thrift
+	$(THRIFT) --gen php:validate,oop -r --out ./packages/phpvo  TestValidators.thrift
+	$(THRIFT) --gen php:json         -r --out ./packages/phpjs  TestValidators.thrift
 
-if HAVE_PHPUNIT
-check: stubs
-	$(PHPUNIT) --log-junit=phpunit.xml Test/Thrift/Protocol/TestTJSONProtocol.php
-endif
+deps: $(top_srcdir)/composer.json
+	composer install --working-dir=$(top_srcdir)
+
+all-local: deps
+
+check-json-serializer: deps stubs
+	$(PHPUNIT) --log-junit=TEST-log-json-serializer.xml JsonSerialize/
+
+check-validator: deps stubs
+	$(PHPUNIT) --log-junit=TEST-log-validator.xml Validator/
+
+check-protocol:	deps stubs
+	$(PHPUNIT) --log-junit=TEST-log-protocol.xml Protocol/
+
+check: deps stubs \
+  check-protocol \
+  check-validator \
+  check-json-serializer
 
 clean-local:
 	$(RM) -r ./packages
-
-EXTRA_DIST = Test
-
+	$(RM) TEST-*.xml
diff --git a/lib/php/test/Protocol/BinarySerializerTest.php b/lib/php/test/Protocol/BinarySerializerTest.php
new file mode 100644
index 0000000..71b0bb5
--- /dev/null
+++ b/lib/php/test/Protocol/BinarySerializerTest.php
@@ -0,0 +1,60 @@
+<?php
+
+/*
+ * 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
+ */
+
+namespace Test\Thrift\Protocol;
+
+use PHPUnit\Framework\TestCase;
+use Thrift\Serializer\TBinarySerializer;
+
+require __DIR__ . '/../../../../vendor/autoload.php';
+
+/***
+ * This test suite depends on running the compiler against the
+ * standard ThriftTest.thrift file:
+ *
+ * lib/php/test$ ../../../compiler/cpp/thrift --gen php -r \
+ *   --out ./packages ../../../test/ThriftTest.thrift
+ *
+ * @runTestsInSeparateProcesses
+ */
+class BinarySerializerTest extends TestCase
+{
+    public function setUp()
+    {
+        /** @var \Composer\Autoload\ClassLoader $loader */
+        $loader = require __DIR__ . '/../../../../vendor/autoload.php';
+        $loader->addPsr4('', __DIR__ . '/../packages/php');
+    }
+
+    /**
+     * We try to serialize and deserialize a random object to make sure no exceptions are thrown.
+     * @see THRIFT-1579
+     */
+    public function testBinarySerializer()
+    {
+        $struct = new \ThriftTest\Xtruct(array('string_thing' => 'abc'));
+        $serialized = TBinarySerializer::serialize($struct, 'ThriftTest\\Xtruct');
+        $deserialized = TBinarySerializer::deserialize($serialized, 'ThriftTest\\Xtruct');
+        $this->assertEquals($struct, $deserialized);
+    }
+}
diff --git a/lib/php/test/Protocol/TJSONProtocolFixtures.php b/lib/php/test/Protocol/TJSONProtocolFixtures.php
new file mode 100644
index 0000000..dd9039f
--- /dev/null
+++ b/lib/php/test/Protocol/TJSONProtocolFixtures.php
@@ -0,0 +1,74 @@
+<?php
+
+/*
+ * 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
+ */
+
+namespace Test\Thrift\Protocol;
+
+class TJSONProtocolFixtures
+{
+    public static $testArgsJSON = array();
+
+    public static function populateTestArgsJSON()
+    {
+        self::$testArgsJSON['testVoid'] = '{}';
+
+        self::$testArgsJSON['testString1'] = '{"1":{"str":"Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ \/ ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe\'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски \/ Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча\/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"}}';
+
+        self::$testArgsJSON['testString2'] = '{"1":{"str":"quote: \\\\\" backslash: forwardslash-escaped: \\\\\/  backspace: \\\\b formfeed: \f newline: \n return: \r tab:  now-all-of-them-together: \"\\\\\\\\\/\\\\b\n\r\t now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><"}}';
+
+        self::$testArgsJSON['testString3'] = '{"1":{"str":"string that ends in double-backslash \\\\\\\\"}}';
+
+        self::$testArgsJSON['testUnicodeStringWithNonBMP'] = '{"1":{"str":"สวัสดี\/𝒯"}}';
+
+        self::$testArgsJSON['testDouble'] = '{"1":{"dbl":3.1415926535898}}';
+
+        self::$testArgsJSON['testByte'] = '{"1":{"i8":1}}';
+
+        self::$testArgsJSON['testI32'] = '{"1":{"i32":1073741824}}';
+
+        if (PHP_INT_SIZE == 8) {
+            self::$testArgsJSON['testI64'] = '{"1":{"i64":' . pow(2, 60) . '}}';
+            self::$testArgsJSON['testStruct'] = '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":' . pow(2, 60) . '}}}}';
+            self::$testArgsJSON['testNest'] = '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":' . pow(2, 60) . '}}},"3":{"i32":32768}}}}';
+        } else {
+            self::$testArgsJSON['testI64'] = '{"1":{"i64":1152921504606847000}}';
+            self::$testArgsJSON['testStruct'] = '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}}}';
+            self::$testArgsJSON['testNest'] = '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}},"3":{"i32":32768}}}}';
+        }
+
+        self::$testArgsJSON['testMap'] = '{"1":{"map":["i32","i32",3,{"7":77,"8":88,"9":99}]}}';
+
+        self::$testArgsJSON['testStringMap'] = '{"1":{"map":["str","str",6,{"a":"123","a b":"with spaces ","same":"same","0":"numeric key","longValue":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e","Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e":"long key"}]}}';
+
+        self::$testArgsJSON['testSet'] = '{"1":{"set":["i32",3,1,5,6]}}';
+
+        self::$testArgsJSON['testList'] = '{"1":{"lst":["i32",3,1,2,3]}}';
+
+        self::$testArgsJSON['testEnum'] = '{"1":{"i32":1}}';
+
+        self::$testArgsJSON['testTypedef'] = '{"1":{"i64":69}}';
+
+        self::$testArgsJSON['testMapMap'] = '{"0":{"map":["i32","map",2,{"4":["i32","i32",4,{"1":1,"2":2,"3":3,"4":4}],"-4":["i32","i32",4,{"-4":-4,"-3":-3,"-2":-2,"-1":-1}]}]}}';
+
+        self::$testArgsJSON['testInsanity'] = '{"0":{"map":["i64","map",2,{"1":["i32","rec",2,{"2":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}},"3":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}}}],"2":["i32","rec",1,{"6":{}}]}]}}';
+    }
+}
diff --git a/lib/php/test/Protocol/TJSONProtocolTest.php b/lib/php/test/Protocol/TJSONProtocolTest.php
new file mode 100644
index 0000000..bf0ecce
--- /dev/null
+++ b/lib/php/test/Protocol/TJSONProtocolTest.php
@@ -0,0 +1,518 @@
+<?php
+
+/*
+ * 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
+ */
+
+namespace Test\Thrift\Protocol;
+
+use PHPUnit\Framework\TestCase;
+use Test\Thrift\Fixtures;
+use Thrift\Protocol\TJSONProtocol;
+use Thrift\Transport\TMemoryBuffer;
+
+require __DIR__ . '/../../../../vendor/autoload.php';
+
+/***
+ * This test suite depends on running the compiler against the
+ * standard ThriftTest.thrift file:
+ *
+ * lib/php/test$ ../../../compiler/cpp/thrift --gen php -r \
+ *   --out ./packages ../../../test/ThriftTest.thrift
+ *
+ * @runTestsInSeparateProcesses
+ */
+class TJSONProtocolTest extends TestCase
+{
+    private $transport;
+    private $protocol;
+
+    public static function setUpBeforeClass()
+    {
+        /** @var \Composer\Autoload\ClassLoader $loader */
+        $loader = require __DIR__ . '/../../../../vendor/autoload.php';
+        $loader->addPsr4('', __DIR__ . '/../packages/php');
+
+        Fixtures::populateTestArgs();
+        TJSONProtocolFixtures::populateTestArgsJSON();
+    }
+
+    public function setUp()
+    {
+        $this->transport = new TMemoryBuffer();
+        $this->protocol = new TJSONProtocol($this->transport);
+        $this->transport->open();
+    }
+
+    /**
+     * WRITE TESTS
+     */
+    public function testVoidWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testVoid_args();
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testVoid'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testString1Write()
+    {
+        $args = new \ThriftTest\ThriftTest_testString_args();
+        $args->thing = Fixtures::$testArgs['testString1'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testString1'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testString2Write()
+    {
+        $args = new \ThriftTest\ThriftTest_testString_args();
+        $args->thing = Fixtures::$testArgs['testString2'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testString2'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testDoubleWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testDouble_args();
+        $args->thing = Fixtures::$testArgs['testDouble'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testDouble'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testByteWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testByte_args();
+        $args->thing = Fixtures::$testArgs['testByte'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testByte'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testI32Write()
+    {
+        $args = new \ThriftTest\ThriftTest_testI32_args();
+        $args->thing = Fixtures::$testArgs['testI32'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testI32'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testI64Write()
+    {
+        $args = new \ThriftTest\ThriftTest_testI64_args();
+        $args->thing = Fixtures::$testArgs['testI64'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testI64'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testStructWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testStruct_args();
+        $args->thing = Fixtures::$testArgs['testStruct'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testStruct'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testNestWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testNest_args();
+        $args->thing = Fixtures::$testArgs['testNest'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testNest'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testMapWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testMap_args();
+        $args->thing = Fixtures::$testArgs['testMap'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testMap'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testStringMapWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testStringMap_args();
+        $args->thing = Fixtures::$testArgs['testStringMap'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testStringMap'];
+
+        /*
+         * The $actual returns unescaped string.
+         * It is required to to decode then encode it again
+         * to get the expected escaped unicode.
+         */
+        $this->assertEquals($expected, json_encode(json_decode($actual)));
+    }
+
+    public function testSetWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testSet_args();
+        $args->thing = Fixtures::$testArgs['testSet'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testSet'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testListWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testList_args();
+        $args->thing = Fixtures::$testArgs['testList'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testList'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testEnumWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testEnum_args();
+        $args->thing = Fixtures::$testArgs['testEnum'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testEnum'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testTypedefWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testTypedef_args();
+        $args->thing = Fixtures::$testArgs['testTypedef'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testTypedef'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    /**
+     * READ TESTS
+     */
+    public function testVoidRead()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testVoid']
+        );
+        $args = new \ThriftTest\ThriftTest_testVoid_args();
+        $args->read($this->protocol);
+    }
+
+    public function testString1Read()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testString1']
+        );
+        $args = new \ThriftTest\ThriftTest_testString_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testString1'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testString2Read()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testString2']
+        );
+        $args = new \ThriftTest\ThriftTest_testString_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testString2'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testString3Write()
+    {
+        $args = new \ThriftTest\ThriftTest_testString_args();
+        $args->thing = Fixtures::$testArgs['testString3'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testString3'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testString4Write()
+    {
+        $args = new \ThriftTest\ThriftTest_testString_args();
+        $args->thing = Fixtures::$testArgs['testUnicodeStringWithNonBMP'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TJSONProtocolFixtures::$testArgsJSON['testUnicodeStringWithNonBMP'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testDoubleRead()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testDouble']
+        );
+        $args = new \ThriftTest\ThriftTest_testDouble_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testDouble'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testByteRead()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testByte']
+        );
+        $args = new \ThriftTest\ThriftTest_testByte_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testByte'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testI32Read()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testI32']
+        );
+        $args = new \ThriftTest\ThriftTest_testI32_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testI32'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testI64Read()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testI64']
+        );
+        $args = new \ThriftTest\ThriftTest_testI64_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testI64'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testStructRead()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testStruct']
+        );
+        $args = new \ThriftTest\ThriftTest_testStruct_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testStruct'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testNestRead()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testNest']
+        );
+        $args = new \ThriftTest\ThriftTest_testNest_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testNest'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testMapRead()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testMap']
+        );
+        $args = new \ThriftTest\ThriftTest_testMap_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testMap'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testStringMapRead()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testStringMap']
+        );
+        $args = new \ThriftTest\ThriftTest_testStringMap_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testStringMap'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testSetRead()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testSet']
+        );
+        $args = new \ThriftTest\ThriftTest_testSet_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testSet'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testListRead()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testList']
+        );
+        $args = new \ThriftTest\ThriftTest_testList_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testList'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testEnumRead()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testEnum']
+        );
+        $args = new \ThriftTest\ThriftTest_testEnum_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testEnum'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testTypedefRead()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testTypedef']
+        );
+        $args = new \ThriftTest\ThriftTest_testTypedef_args();
+        $args->read($this->protocol);
+
+        $actual = $args->thing;
+        $expected = Fixtures::$testArgs['testTypedef'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testMapMapRead()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testMapMap']
+        );
+        $result = new \ThriftTest\ThriftTest_testMapMap_result();
+        $result->read($this->protocol);
+
+        $actual = $result->success;
+        $expected = Fixtures::$testArgs['testMapMapExpectedResult'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testInsanityRead()
+    {
+        $this->transport->write(
+            TJSONProtocolFixtures::$testArgsJSON['testInsanity']
+        );
+        $result = new \ThriftTest\ThriftTest_testInsanity_result();
+        $result->read($this->protocol);
+
+        $actual = $result->success;
+        $expected = Fixtures::$testArgs['testInsanityExpectedResult'];
+
+        $this->assertEquals($expected, $actual);
+    }
+}
diff --git a/lib/php/test/Protocol/TSimpleJSONProtocolFixtures.php b/lib/php/test/Protocol/TSimpleJSONProtocolFixtures.php
new file mode 100644
index 0000000..547fd86
--- /dev/null
+++ b/lib/php/test/Protocol/TSimpleJSONProtocolFixtures.php
@@ -0,0 +1,67 @@
+<?php
+
+/*
+ * 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
+ */
+
+namespace test\Thrift\Protocol;
+
+class TSimpleJSONProtocolFixtures
+{
+    public static $testArgsJSON = array();
+
+    public static function populateTestArgsSimpleJSON()
+    {
+        self::$testArgsJSON['testVoid'] = '{}';
+
+        self::$testArgsJSON['testString1'] = '{"thing":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e"}';
+
+        self::$testArgsJSON['testString2'] = '{"thing":"quote: \\\\\" backslash: forwardslash-escaped: \\\\\/  backspace: \\\\b formfeed: \f newline: \n return: \r tab:  now-all-of-them-together: \"\\\\\\\\\/\\\\b\n\r\t now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><"}';
+
+        self::$testArgsJSON['testDouble'] = '{"thing":3.1415926535898}';
+
+        self::$testArgsJSON['testByte'] = '{"thing":1}';
+
+        self::$testArgsJSON['testI32'] = '{"thing":1073741824}';
+
+        if (PHP_INT_SIZE == 8) {
+            self::$testArgsJSON['testI64'] = '{"thing":' . pow(2, 60) . '}';
+            self::$testArgsJSON['testStruct'] = '{"thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":' . pow(2, 60) . '}}';
+            self::$testArgsJSON['testNest'] = '{"thing":{"byte_thing":1,"struct_thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":' . pow(2, 60) . '},"i32_thing":32768}}';
+        } else {
+            self::$testArgsJSON['testI64'] = '{"thing":1152921504606847000}';
+
+            self::$testArgsJSON['testStruct'] = '{"thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":1152921504606847000}}';
+            self::$testArgsJSON['testNest'] = '{"thing":{"byte_thing":1,"struct_thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":1152921504606847000},"i32_thing":32768}}';
+        }
+
+        self::$testArgsJSON['testMap'] = '{"thing":{"7":77,"8":88,"9":99}}';
+
+        self::$testArgsJSON['testStringMap'] = '{"thing":{"a":"123","a b":"with spaces ","same":"same","0":"numeric key","longValue":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e","Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e":"long key"}}';
+
+        self::$testArgsJSON['testSet'] = '{"thing":[1,5,6]}';
+
+        self::$testArgsJSON['testList'] = '{"thing":[1,2,3]}';
+
+        self::$testArgsJSON['testEnum'] = '{"thing":1}';
+
+        self::$testArgsJSON['testTypedef'] = '{"thing":69}';
+    }
+}
diff --git a/lib/php/test/Protocol/TSimpleJSONProtocolTest.php b/lib/php/test/Protocol/TSimpleJSONProtocolTest.php
new file mode 100644
index 0000000..e4a1373
--- /dev/null
+++ b/lib/php/test/Protocol/TSimpleJSONProtocolTest.php
@@ -0,0 +1,254 @@
+<?php
+
+/*
+ * 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
+ */
+
+namespace Test\Thrift\Protocol;
+
+use PHPUnit\Framework\TestCase;
+use Test\Thrift\Fixtures;
+use Thrift\Protocol\TSimpleJSONProtocol;
+use Thrift\Transport\TMemoryBuffer;
+
+require __DIR__ . '/../../../../vendor/autoload.php';
+
+/***
+ * This test suite depends on running the compiler against the
+ * standard ThriftTest.thrift file:
+ *
+ * lib/php/test$ ../../../compiler/cpp/thrift --gen php -r \
+ *   --out ./packages ../../../test/ThriftTest.thrift
+ *
+ * @runTestsInSeparateProcesses
+ */
+class TSimpleJSONProtocolTest extends TestCase
+{
+    private $transport;
+    private $protocol;
+
+    public static function setUpBeforeClass()
+    {
+
+        /** @var \Composer\Autoload\ClassLoader $loader */
+        $loader = require __DIR__ . '/../../../../vendor/autoload.php';
+        $loader->addPsr4('', __DIR__ . '/../packages/php');
+
+        Fixtures::populateTestArgs();
+        TSimpleJSONProtocolFixtures::populateTestArgsSimpleJSON();
+    }
+
+    public function setUp()
+    {
+        $this->transport = new TMemoryBuffer();
+        $this->protocol = new TSimpleJSONProtocol($this->transport);
+        $this->transport->open();
+    }
+
+    /**
+     * WRITE TESTS
+     */
+    public function testVoidWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testVoid_args();
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testVoid'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testString1Write()
+    {
+        $args = new \ThriftTest\ThriftTest_testString_args();
+        $args->thing = Fixtures::$testArgs['testString1'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testString1'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testString2Write()
+    {
+        $args = new \ThriftTest\ThriftTest_testString_args();
+        $args->thing = Fixtures::$testArgs['testString2'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testString2'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testDoubleWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testDouble_args();
+        $args->thing = Fixtures::$testArgs['testDouble'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testDouble'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testByteWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testByte_args();
+        $args->thing = Fixtures::$testArgs['testByte'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testByte'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testI32Write()
+    {
+        $args = new \ThriftTest\ThriftTest_testI32_args();
+        $args->thing = Fixtures::$testArgs['testI32'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testI32'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testI64Write()
+    {
+        $args = new \ThriftTest\ThriftTest_testI64_args();
+        $args->thing = Fixtures::$testArgs['testI64'];
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testI64'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testStructWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testStruct_args();
+        $args->thing = Fixtures::$testArgs['testStruct'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testStruct'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testNestWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testNest_args();
+        $args->thing = Fixtures::$testArgs['testNest'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testNest'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testMapWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testMap_args();
+        $args->thing = Fixtures::$testArgs['testMap'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testMap'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testStringMapWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testStringMap_args();
+        $args->thing = Fixtures::$testArgs['testStringMap'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testStringMap'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testSetWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testSet_args();
+        $args->thing = Fixtures::$testArgs['testSet'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testSet'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testListWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testList_args();
+        $args->thing = Fixtures::$testArgs['testList'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testList'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testEnumWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testEnum_args();
+        $args->thing = Fixtures::$testArgs['testEnum'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testEnum'];
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testTypedefWrite()
+    {
+        $args = new \ThriftTest\ThriftTest_testTypedef_args();
+        $args->thing = Fixtures::$testArgs['testTypedef'];
+
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(Fixtures::$bufsize);
+        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testTypedef'];
+
+        $this->assertEquals($expected, $actual);
+    }
+}
diff --git a/lib/php/test/Test/Thrift/Fixtures.php b/lib/php/test/Test/Thrift/Fixtures.php
deleted file mode 100644
index 1b86f59..0000000
--- a/lib/php/test/Test/Thrift/Fixtures.php
+++ /dev/null
@@ -1,192 +0,0 @@
-<?php
-
-/*
- * 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
- */
-
-namespace Test\Thrift;
-
-use ThriftTest\Xtruct;
-use ThriftTest\Xtruct2;
-use ThriftTest\Numberz;
-use ThriftTest\Insanity;
-
-class Fixtures
-{
-  public static $testArgs = array();
-
-  public static function populateTestArgs()
-  {
-    self::$testArgs['testString1'] = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語";
-
-    self::$testArgs['testString2'] =
-      "quote: \\\" backslash:" .
-      " forwardslash-escaped: \\/ " .
-      " backspace: \b formfeed: \f newline: \n return: \r tab: " .
-      " now-all-of-them-together: \"\\\/\b\n\r\t" .
-      " now-a-bunch-of-junk: !@#\$%&()(&%$#{}{}<><><";
-
-    self::$testArgs['testString3'] =
-      "string that ends in double-backslash \\\\";
-
-    self::$testArgs['testDouble'] = 3.1415926535898;
-
-    self::$testArgs['testByte'] = 0x01;
-
-    self::$testArgs['testI32'] = pow( 2, 30 );
-
-    if ( PHP_INT_SIZE == 8 )
-    {
-      self::$testArgs['testI64'] = pow( 2, 60 );
-    }
-    else
-    {
-      self::$testArgs['testI64'] = "1152921504606847000";
-    }
-
-    self::$testArgs['testStruct'] =
-      new Xtruct(
-            array(
-                    'string_thing' => 'worked',
-                    'byte_thing' => 0x01,
-                    'i32_thing' => pow( 2, 30 ),
-                    'i64_thing' => self::$testArgs['testI64']
-                    )
-            );
-
-    self::$testArgs['testNestNested'] =
-      new Xtruct(
-            array(
-                    'string_thing' => 'worked',
-                    'byte_thing' => 0x01,
-                    'i32_thing' => pow( 2, 30 ),
-                    'i64_thing' => self::$testArgs['testI64']
-                    )
-            );
-
-    self::$testArgs['testNest'] =
-      new Xtruct2(
-            array(
-                'byte_thing' => 0x01,
-                'struct_thing' => self::$testArgs['testNestNested'],
-                'i32_thing' => pow( 2, 15 )
-                )
-            );
-
-    self::$testArgs['testMap'] =
-      array(
-            7 => 77,
-            8 => 88,
-            9 => 99
-            );
-
-    self::$testArgs['testStringMap'] =
-      array(
-            "a" => "123",
-            "a b" => "with spaces ",
-            "same" => "same",
-            "0" => "numeric key",
-            "longValue" => self::$testArgs['testString1'],
-            self::$testArgs['testString1'] => "long key"
-            );
-
-    self::$testArgs['testSet'] = array( 1 => true, 5 => true, 6 => true );
-
-    self::$testArgs['testList'] = array( 1, 2, 3 );
-
-    self::$testArgs['testEnum'] = Numberz::ONE;
-
-    self::$testArgs['testTypedef'] = 69;
-
-    self::$testArgs['testMapMapExpectedResult'] =
-      array(
-            4 => array(
-                       1 => 1,
-                       2 => 2,
-                       3 => 3,
-                       4 => 4,
-                       ),
-            -4 => array(
-                        -4 => -4,
-                        -3 => -3,
-                        -2 => -2,
-                        -1 => -1
-                        )
-            );
-
-    // testInsanity ... takes a few steps to set up!
-
-    $xtruct1 =
-      new Xtruct(
-            array(
-                'string_thing' => 'Goodbye4',
-                'byte_thing' => 4,
-                'i32_thing' => 4,
-                'i64_thing' => 4
-                )
-            );
-
-    $xtruct2 =
-      new Xtruct(
-            array(
-                'string_thing' => 'Hello2',
-                'byte_thing' =>2,
-                'i32_thing' => 2,
-                'i64_thing' => 2
-                )
-            );
-
-    $userMap =
-      array(
-            Numberz::FIVE => 5,
-            Numberz::EIGHT => 8
-            );
-
-    $insanity2 =
-      new Insanity(
-            array(
-                'userMap' => $userMap,
-                'xtructs' => array($xtruct1,$xtruct2)
-                )
-            );
-
-    $insanity3 = $insanity2;
-
-    $insanity6 =
-      new Insanity(
-            array(
-                'userMap' => null,
-                'xtructs' => null
-                )
-            );
-
-    self::$testArgs['testInsanityExpectedResult'] =
-      array(
-            "1" => array(
-                         Numberz::TWO => $insanity2,
-                         Numberz::THREE => $insanity3
-                    ),
-            "2" => array(
-                         Numberz::SIX => $insanity6
-                    )
-            );
-
-  }
-}
diff --git a/lib/php/test/Test/Thrift/Protocol/TestTJSONProtocol.php b/lib/php/test/Test/Thrift/Protocol/TestTJSONProtocol.php
deleted file mode 100755
index d5aa69c..0000000
--- a/lib/php/test/Test/Thrift/Protocol/TestTJSONProtocol.php
+++ /dev/null
@@ -1,568 +0,0 @@
-<?php
-
-/*
- * 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
- */
-
-namespace test\Thrift\Protocol;
-
-use Thrift\ClassLoader\ThriftClassLoader;
-use Test\Thrift\Fixtures;
-use Thrift\Transport\TMemoryBuffer;
-use Thrift\Protocol\TJSONProtocol;
-
-
-define( 'BUFSIZ', 8192 ); //big enough to read biggest serialized Fixture arg.
-
-require_once __DIR__.'/../../../../lib/Thrift/ClassLoader/ThriftClassLoader.php';
-
-$loader = new ThriftClassLoader();
-$loader->registerNamespace('Thrift', __DIR__ . '/../../../../lib');
-$loader->registerNamespace('Test', __DIR__ . '/../../..');
-$loader->registerDefinition('ThriftTest', __DIR__ . '/../../../packages');
-$loader->register();
-
-/***
- * This test suite depends on running the compiler against the
- * standard ThriftTest.thrift file:
- *
- * lib/php/test$ ../../../compiler/cpp/thrift --gen php -r \
- *   --out ./packages ../../../test/ThriftTest.thrift
- */
-
-class TestTJSONProtocol extends \PHPUnit_Framework_TestCase
-{
-  private $transport;
-  private $protocol;
-
-  public static function setUpBeforeClass()
-  {
-    Fixtures::populateTestArgs();
-    TestTJSONProtocol_Fixtures::populateTestArgsJSON();
-  }
-
-  public function setUp()
-  {
-    $this->transport = new TMemoryBuffer();
-    $this->protocol = new TJSONProtocol($this->transport);
-    $this->transport->open();
-  }
-
-  /***
-   * WRITE TESTS
-   */
-
-  public function testVoid_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testVoid_args();
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testVoid'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testString1_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testString_args();
-    $args->thing = Fixtures::$testArgs['testString1'];
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testString1'];
-
-    #$this->assertEquals( $expected, $actual );
-  }
-
-  public function testString2_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testString_args();
-    $args->thing = Fixtures::$testArgs['testString2'];
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testString2'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testDouble_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testDouble_args();
-    $args->thing = Fixtures::$testArgs['testDouble'];
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testDouble'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testByte_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testByte_args();
-    $args->thing = Fixtures::$testArgs['testByte'];
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testByte'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testI32_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testI32_args();
-    $args->thing = Fixtures::$testArgs['testI32'];
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testI32'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testI64_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testI64_args();
-    $args->thing = Fixtures::$testArgs['testI64'];
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testI64'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testStruct_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testStruct_args();
-    $args->thing = Fixtures::$testArgs['testStruct'];
-
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testStruct'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testNest_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testNest_args();
-    $args->thing = Fixtures::$testArgs['testNest'];
-
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testNest'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testMap_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testMap_args();
-    $args->thing = Fixtures::$testArgs['testMap'];
-
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testMap'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testStringMap_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testStringMap_args();
-    $args->thing = Fixtures::$testArgs['testStringMap'];
-
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testStringMap'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testSet_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testSet_args();
-    $args->thing = Fixtures::$testArgs['testSet'];
-
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testSet'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testList_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testList_args();
-    $args->thing = Fixtures::$testArgs['testList'];
-
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testList'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testEnum_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testEnum_args();
-    $args->thing = Fixtures::$testArgs['testEnum'];
-
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testEnum'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testTypedef_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testTypedef_args();
-    $args->thing = Fixtures::$testArgs['testTypedef'];
-
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testTypedef'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  /***
-   * READ TESTS
-   */
-
-  public function testVoid_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testVoid']
-			    );
-    $args = new \ThriftTest\ThriftTest_testVoid_args();
-    $args->read( $this->protocol );
-  }
-
-  public function testString1_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testString1']
-			    );
-    $args = new \ThriftTest\ThriftTest_testString_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testString1'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testString2_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testString2']
-			    );
-    $args = new \ThriftTest\ThriftTest_testString_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testString2'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testString3_Write()
-  {
-    $args = new \ThriftTest\ThriftTest_testString_args();
-    $args->thing = Fixtures::$testArgs['testString3'];
-    $args->write( $this->protocol );
-
-    $actual = $this->transport->read( BUFSIZ );
-    $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testString3'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testDouble_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testDouble']
-			    );
-    $args = new \ThriftTest\ThriftTest_testDouble_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testDouble'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testByte_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testByte']
-			    );
-    $args = new \ThriftTest\ThriftTest_testByte_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testByte'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testI32_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testI32']
-			    );
-    $args = new \ThriftTest\ThriftTest_testI32_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testI32'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testI64_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testI64']
-			    );
-    $args = new \ThriftTest\ThriftTest_testI64_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testI64'];
-
-    $this->assertEquals( $expected, $actual );
-
-  }
-
-  public function testStruct_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testStruct']
-			    );
-    $args = new \ThriftTest\ThriftTest_testStruct_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testStruct'];
-
-    $this->assertEquals( $expected, $actual );
-
-  }
-
-  public function testNest_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testNest']
-			    );
-    $args = new \ThriftTest\ThriftTest_testNest_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testNest'];
-
-    $this->assertEquals( $expected, $actual );
-
-  }
-
-  public function testMap_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testMap']
-			    );
-    $args = new \ThriftTest\ThriftTest_testMap_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testMap'];
-
-    $this->assertEquals( $expected, $actual );
-
-  }
-
-  public function testStringMap_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testStringMap']
-			    );
-    $args = new \ThriftTest\ThriftTest_testStringMap_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testStringMap'];
-
-    $this->assertEquals( $expected, $actual );
-
-  }
-
-  public function testSet_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testSet']
-			    );
-    $args = new \ThriftTest\ThriftTest_testSet_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testSet'];
-
-    $this->assertEquals( $expected, $actual );
-
-  }
-
-  public function testList_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testList']
-			    );
-    $args = new \ThriftTest\ThriftTest_testList_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testList'];
-
-    $this->assertEquals( $expected, $actual );
-
-  }
-
-  public function testEnum_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testEnum']
-			    );
-    $args = new \ThriftTest\ThriftTest_testEnum_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testEnum'];
-
-    $this->assertEquals( $expected, $actual );
-
-  }
-
-  public function testTypedef_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testTypedef']
-			    );
-    $args = new \ThriftTest\ThriftTest_testTypedef_args();
-    $args->read( $this->protocol );
-
-    $actual = $args->thing;
-    $expected = Fixtures::$testArgs['testTypedef'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testMapMap_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testMapMap']
-			    );
-    $result = new \ThriftTest\ThriftTest_testMapMap_result();
-    $result->read( $this->protocol );
-
-    $actual = $result->success;
-    $expected = Fixtures::$testArgs['testMapMapExpectedResult'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-  public function testInsanity_Read()
-  {
-    $this->transport->write(
-			    TestTJSONProtocol_Fixtures::$testArgsJSON['testInsanity']
-			    );
-    $result = new \ThriftTest\ThriftTest_testInsanity_result();
-    $result->read( $this->protocol );
-
-    $actual = $result->success;
-    $expected = Fixtures::$testArgs['testInsanityExpectedResult'];
-
-    $this->assertEquals( $expected, $actual );
-  }
-
-}
-
-class TestTJSONProtocol_Fixtures
-{
-  public static $testArgsJSON = array();
-
-  public static function populateTestArgsJSON()
-  {
-    self::$testArgsJSON['testVoid'] = '{}';
-
-    self::$testArgsJSON['testString1'] = '{"1":{"str":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e"}}';
-
-    self::$testArgsJSON['testString2'] = '{"1":{"str":"quote: \\\\\" backslash: forwardslash-escaped: \\\\\/  backspace: \\\\b formfeed: \f newline: \n return: \r tab:  now-all-of-them-together: \"\\\\\\\\\/\\\\b\n\r\t now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><"}}';
-
-    self::$testArgsJSON['testString3'] = '{"1":{"str":"string that ends in double-backslash \\\\\\\\"}}';
-
-    self::$testArgsJSON['testDouble'] = '{"1":{"dbl":3.1415926535898}}';
-
-    self::$testArgsJSON['testByte'] = '{"1":{"i8":1}}';
-
-    self::$testArgsJSON['testI32'] = '{"1":{"i32":1073741824}}';
-
-    if ( PHP_INT_SIZE == 8 )
-    {
-      self::$testArgsJSON['testI64'] = '{"1":{"i64":'.pow( 2, 60 ).'}}';
-      self::$testArgsJSON['testStruct'] = '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":'.pow( 2, 60 ).'}}}}';
-      self::$testArgsJSON['testNest'] = '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":'.pow( 2, 60 ).'}}},"3":{"i32":32768}}}}';
-    }
-    else
-    {
-      self::$testArgsJSON['testI64'] = '{"1":{"i64":1152921504606847000}}';
-      self::$testArgsJSON['testStruct'] = '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}}}';
-      self::$testArgsJSON['testNest'] = '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}},"3":{"i32":32768}}}}';
-    }
-
-    self::$testArgsJSON['testMap'] = '{"1":{"map":["i32","i32",3,{"7":77,"8":88,"9":99}]}}';
-
-    self::$testArgsJSON['testStringMap'] = '{"1":{"map":["str","str",6,{"a":"123","a b":"with spaces ","same":"same","0":"numeric key","longValue":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e","Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e":"long key"}]}}';
-
-    self::$testArgsJSON['testSet'] = '{"1":{"set":["i32",3,1,5,6]}}';
-
-    self::$testArgsJSON['testList'] = '{"1":{"lst":["i32",3,1,2,3]}}';
-
-    self::$testArgsJSON['testEnum'] = '{"1":{"i32":1}}';
-
-    self::$testArgsJSON['testTypedef'] = '{"1":{"i64":69}}';
-
-    self::$testArgsJSON['testMapMap'] = '{"0":{"map":["i32","map",2,{"4":["i32","i32",4,{"1":1,"2":2,"3":3,"4":4}],"-4":["i32","i32",4,{"-4":-4,"-3":-3,"-2":-2,"-1":-1}]}]}}';
-
-    self::$testArgsJSON['testInsanity'] = '{"0":{"map":["i64","map",2,{"1":["i32","rec",2,{"2":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}},"3":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}}}],"2":["i32","rec",1,{"6":{}}]}]}}';
-
-  }
-}
diff --git a/lib/php/test/TestValidators.thrift b/lib/php/test/TestValidators.thrift
new file mode 100644
index 0000000..9c38d92
--- /dev/null
+++ b/lib/php/test/TestValidators.thrift
@@ -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.
+ */
+
+namespace php TestValidators
+
+include "../../../test/ThriftTest.thrift"
+
+union UnionOfStrings {
+  1: string aa;
+  2: string bb;
+}
+
+service TestService {
+    void test() throws(1: ThriftTest.Xception xception);
+}
diff --git a/lib/php/test/Validator/BaseValidatorTest.php b/lib/php/test/Validator/BaseValidatorTest.php
new file mode 100644
index 0000000..6029083
--- /dev/null
+++ b/lib/php/test/Validator/BaseValidatorTest.php
@@ -0,0 +1,154 @@
+<?php
+/*
+ * 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.
+ */
+
+namespace Test\Thrift;
+
+use PHPUnit\Framework\TestCase;
+use Thrift\Exception\TProtocolException;
+use Thrift\Protocol\TBinaryProtocol;
+use Thrift\Transport\TMemoryBuffer;
+
+abstract class BaseValidatorTest extends TestCase
+{
+    public function testEmptyStructValidator()
+    {
+        $this->assertNoReadValidator('ThriftTest\EmptyStruct');
+        $this->assertNoWriteValidator('ThriftTest\EmptyStruct');
+    }
+
+    public function testBonkValidator()
+    {
+        $this->assertNoReadValidator('ThriftTest\Bonk');
+        $this->assertHasWriteValidator('ThriftTest\Bonk');
+    }
+
+    public function testStructAValidator()
+    {
+        $this->assertHasReadValidator('ThriftTest\StructA');
+        $this->assertHasWriteValidator('ThriftTest\StructA');
+    }
+
+    public function testUnionOfStringsValidator()
+    {
+        $this->assertNoWriteValidator('TestValidators\UnionOfStrings');
+    }
+
+    public function testServiceResultValidator()
+    {
+        $this->assertNoReadValidator('TestValidators\TestService_test_result');
+        $this->assertNoWriteValidator('TestValidators\TestService_test_result');
+    }
+
+    public function testReadEmpty()
+    {
+        $bonk = new \ThriftTest\Bonk();
+        $transport = new TMemoryBuffer("\000");
+        $protocol = new TBinaryProtocol($transport);
+        $bonk->read($protocol);
+    }
+
+    public function testWriteEmpty()
+    {
+        $bonk = new \ThriftTest\Bonk();
+        $transport = new TMemoryBuffer();
+        $protocol = new TBinaryProtocol($transport);
+        try {
+            $bonk->write($protocol);
+            $this->fail('Bonk was able to write an empty object');
+        } catch (TProtocolException $e) {
+        }
+    }
+
+    public function testWriteWithMissingRequired()
+    {
+        // Check that we are not able to write StructA with a missing required field
+        $structa = new \ThriftTest\StructA();
+        $transport = new TMemoryBuffer();
+        $protocol = new TBinaryProtocol($transport);
+
+        try {
+            $structa->write($protocol);
+            $this->fail('StructA was able to write an empty object');
+        } catch (TProtocolException $e) {
+        }
+    }
+
+    public function testReadStructA()
+    {
+        $transport = new TMemoryBuffer(base64_decode('CwABAAAAA2FiYwA='));
+        $protocol = new TBinaryProtocol($transport);
+        $structa = new \ThriftTest\StructA();
+        $structa->read($protocol);
+        $this->assertEquals("abc", $structa->s);
+    }
+
+    public function testWriteStructA()
+    {
+        $transport = new TMemoryBuffer();
+        $protocol = new TBinaryProtocol($transport);
+        $structa = new \ThriftTest\StructA();
+        $structa->s = "abc";
+        $structa->write($protocol);
+        $writeResult = base64_encode($transport->getBuffer());
+        $this->assertEquals('CwABAAAAA2FiYwA=', $writeResult);
+    }
+
+    protected static function assertHasReadValidator($class)
+    {
+        if (!static::hasReadValidator($class)) {
+            static::fail($class . ' class should have a read validator');
+        }
+    }
+
+    protected static function assertNoReadValidator($class)
+    {
+        if (static::hasReadValidator($class)) {
+            static::fail($class . ' class should not have a write validator');
+        }
+    }
+
+    protected static function assertHasWriteValidator($class)
+    {
+        if (!static::hasWriteValidator($class)) {
+            static::fail($class . ' class should have a write validator');
+        }
+    }
+
+    protected static function assertNoWriteValidator($class)
+    {
+        if (static::hasWriteValidator($class)) {
+            static::fail($class . ' class should not have a write validator');
+        }
+    }
+
+    private static function hasReadValidator($class)
+    {
+        $rc = new \ReflectionClass($class);
+
+        return $rc->hasMethod('_validateForRead');
+    }
+
+    private static function hasWriteValidator($class)
+    {
+        $rc = new \ReflectionClass($class);
+
+        return $rc->hasMethod('_validateForWrite');
+    }
+}
diff --git a/lib/php/test/Validator/ValidatorTest.php b/lib/php/test/Validator/ValidatorTest.php
new file mode 100644
index 0000000..fa6c7a9
--- /dev/null
+++ b/lib/php/test/Validator/ValidatorTest.php
@@ -0,0 +1,41 @@
+<?php
+/*
+ * 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.
+ */
+
+namespace Test\Thrift;
+
+require __DIR__ . '/../../../../vendor/autoload.php';
+
+use Thrift\ClassLoader\ThriftClassLoader;
+
+/**
+ * Class TestValidators
+ * @package Test\Thrift
+ *
+ * @runTestsInSeparateProcesses
+ */
+class ValidatorTest extends BaseValidatorTest
+{
+    public function setUp()
+    {
+        /** @var \Composer\Autoload\ClassLoader $loader */
+        $loader = require __DIR__ . '/../../../../vendor/autoload.php';
+        $loader->addPsr4('', __DIR__ . '/../packages/phpv');
+    }
+}
diff --git a/lib/php/test/Validator/ValidatorTestOop.php b/lib/php/test/Validator/ValidatorTestOop.php
new file mode 100644
index 0000000..93bca4d
--- /dev/null
+++ b/lib/php/test/Validator/ValidatorTestOop.php
@@ -0,0 +1,41 @@
+<?php
+/*
+ * 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.
+ */
+
+namespace Test\Thrift;
+
+require_once __DIR__ . '/../../../../vendor/autoload.php';
+
+use Thrift\ClassLoader\ThriftClassLoader;
+
+/**
+ * Class TestValidatorsOop
+ * @package Test\Thrift
+ *
+ * @runTestsInSeparateProcesses
+ */
+class ValidatorTestOop extends BaseValidatorTest
+{
+    public function setUp()
+    {
+        /** @var \Composer\Autoload\ClassLoader $loader */
+        $loader = require __DIR__ . '/../../../../vendor/autoload.php';
+        $loader->addPsr4('', __DIR__ . '/../packages/phpvo');
+    }
+}
diff --git a/lib/py/CMakeLists.txt b/lib/py/CMakeLists.txt
new file mode 100644
index 0000000..7bb91fe
--- /dev/null
+++ b/lib/py/CMakeLists.txt
@@ -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.
+#
+
+include_directories(${PYTHON_INCLUDE_DIRS})
+
+add_custom_target(python_build ALL
+    COMMAND ${PYTHON_EXECUTABLE} setup.py build
+    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+    COMMENT "Building Python library"
+)
+
+if(BUILD_TESTING)
+    add_test(PythonTestSSLSocket ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/test_sslsocket.py)
+    add_test(PythonThriftJson ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/thrift_json.py)
+endif()
diff --git a/lib/py/MANIFEST.in b/lib/py/MANIFEST.in
new file mode 100644
index 0000000..af54e29
--- /dev/null
+++ b/lib/py/MANIFEST.in
@@ -0,0 +1 @@
+include src/ext/*
diff --git a/lib/py/Makefile.am b/lib/py/Makefile.am
old mode 100755
new mode 100644
index e33bf13..5861858
--- a/lib/py/Makefile.am
+++ b/lib/py/Makefile.am
@@ -16,11 +16,21 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-.NOTPARALLEL:
+AUTOMAKE_OPTIONS = serial-tests
 DESTDIR ?= /
-EXTRA_DIST = setup.py setup.cfg src compat
 
-all-local:
+if WITH_PY3
+py3-build:
+	$(PYTHON3) setup.py build
+py3-test: py3-build
+	$(PYTHON3) test/thrift_json.py
+	$(PYTHON3) test/test_sslsocket.py
+else
+py3-build:
+py3-test:
+endif
+
+all-local: py3-build
 	$(PYTHON) setup.py build
 
 # We're ignoring prefix here because site-packages seems to be
@@ -33,4 +43,17 @@
 clean-local:
 	$(RM) -r build
 
-check-local: all
+check-local: all py3-test
+	$(PYTHON) test/thrift_json.py
+	$(PYTHON) test/test_sslsocket.py
+
+EXTRA_DIST = \
+	CMakeLists.txt \
+	MANIFEST.in \
+	coding_standards.md \
+	compat \
+	setup.py \
+	setup.cfg \
+	src \
+	test \
+	README.md
diff --git a/lib/py/README b/lib/py/README.md
similarity index 100%
rename from lib/py/README
rename to lib/py/README.md
diff --git a/lib/py/coding_standards.md b/lib/py/coding_standards.md
new file mode 100644
index 0000000..4c560b5
--- /dev/null
+++ b/lib/py/coding_standards.md
@@ -0,0 +1,7 @@
+## Python Coding Standards
+
+Please follow:
+ * [Thrift General Coding Standards](/doc/coding_standards.md)
+ * Code Style for Python Code [PEP8](http://legacy.python.org/dev/peps/pep-0008/)
+
+When in doubt - check with <http://www.pylint.org/> or online with <http://pep8online.com>.
diff --git a/lib/py/setup.cfg b/lib/py/setup.cfg
index 2dca2f8..c9ed0ae 100644
--- a/lib/py/setup.cfg
+++ b/lib/py/setup.cfg
@@ -1,2 +1,6 @@
 [install]
 optimize = 1
+[metadata]
+description-file = README.md
+[flake8]
+max-line-length = 100
diff --git a/lib/py/setup.py b/lib/py/setup.py
index d44fd9c..3cf1469 100644
--- a/lib/py/setup.py
+++ b/lib/py/setup.py
@@ -9,7 +9,7 @@
 # "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
+#   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
@@ -22,83 +22,118 @@
 import sys
 try:
     from setuptools import setup, Extension
-except:
-    from distutils.core import setup, Extension, Command
+except Exception:
+    from distutils.core import setup, Extension
 
 from distutils.command.build_ext import build_ext
 from distutils.errors import CCompilerError, DistutilsExecError, DistutilsPlatformError
 
-include_dirs = []
+# Fix to build sdist under vagrant
+import os
+if 'vagrant' in str(os.environ):
+    try:
+        del os.link
+    except AttributeError:
+        pass
+
+include_dirs = ['src']
 if sys.platform == 'win32':
     include_dirs.append('compat/win32')
     ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError, IOError)
 else:
     ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError)
 
+
 class BuildFailed(Exception):
     pass
 
+
 class ve_build_ext(build_ext):
     def run(self):
         try:
             build_ext.run(self)
-        except DistutilsPlatformError, x:
+        except DistutilsPlatformError:
             raise BuildFailed()
 
     def build_extension(self, ext):
         try:
             build_ext.build_extension(self, ext)
-        except ext_errors, x:
+        except ext_errors:
             raise BuildFailed()
 
+
 def run_setup(with_binary):
     if with_binary:
         extensions = dict(
-            ext_modules = [
-                 Extension('thrift.protocol.fastbinary',
-                       sources = ['src/protocol/fastbinary.c'],
-                    include_dirs = include_dirs,
-                )
+            ext_modules=[
+                Extension('thrift.protocol.fastbinary',
+                          sources=[
+                              'src/ext/module.cpp',
+                              'src/ext/types.cpp',
+                              'src/ext/binary.cpp',
+                              'src/ext/compact.cpp',
+                          ],
+                          include_dirs=include_dirs,
+                          )
             ],
             cmdclass=dict(build_ext=ve_build_ext)
         )
     else:
         extensions = dict()
-        
-    setup(name = 'thrift',
-        version = '0.9.1',
-        description = 'Python bindings for the Apache Thrift RPC system',
-        author = ['Thrift Developers'],
-        author_email = ['dev@thrift.apache.org'],
-        url = 'http://thrift.apache.org',
-        license = 'Apache License 2.0',
-        packages = [
-            'thrift',
-            'thrift.protocol',
-            'thrift.transport',
-            'thrift.server',
-        ],
-        package_dir = {'thrift' : 'src'},
-        classifiers = [
-            'Development Status :: 5 - Production/Stable',
-            'Environment :: Console',
-            'Intended Audience :: Developers',
-            'Programming Language :: Python',
-            'Programming Language :: Python :: 2',
-            'Topic :: Software Development :: Libraries',
-            'Topic :: System :: Networking'
-        ],
-        **extensions
-    )
+
+    ssl_deps = []
+    if sys.version_info[0] == 2:
+        ssl_deps.append('ipaddress')
+    if sys.hexversion < 0x03050000:
+        ssl_deps.append('backports.ssl_match_hostname>=3.5')
+    tornado_deps = ['tornado>=4.0']
+    twisted_deps = ['twisted']
+
+    setup(name='thrift',
+          version='1.0.0',
+          description='Python bindings for the Apache Thrift RPC system',
+          author='Apache Thrift Developers',
+          author_email='dev@thrift.apache.org',
+          url='http://thrift.apache.org',
+          license='Apache License 2.0',
+          install_requires=['six>=1.7.2'],
+          extras_require={
+              'ssl': ssl_deps,
+              'tornado': tornado_deps,
+              'twisted': twisted_deps,
+              'all': ssl_deps + tornado_deps + twisted_deps,
+          },
+          packages=[
+              'thrift',
+              'thrift.protocol',
+              'thrift.transport',
+              'thrift.server',
+          ],
+          package_dir={'thrift': 'src'},
+          classifiers=[
+              'Development Status :: 5 - Production/Stable',
+              'Environment :: Console',
+              'Intended Audience :: Developers',
+              'Programming Language :: Python',
+              'Programming Language :: Python :: 2',
+              'Programming Language :: Python :: 3',
+              'Topic :: Software Development :: Libraries',
+              'Topic :: System :: Networking'
+          ],
+          zip_safe=False,
+          **extensions
+          )
+
 
 try:
-    run_setup(True)
+    with_binary = True
+    run_setup(with_binary)
 except BuildFailed:
-    print
-    print '*' * 80
-    print "An error occured while trying to compile with the C extension enabled" 
-    print "Attempting to build without the extension now"
-    print '*' * 80
-    print
+    print()
+    print('*' * 80)
+    print("An error occurred while trying to compile with the C extension enabled")
+    print("Attempting to build without the extension now")
+    print('*' * 80)
+    print()
 
     run_setup(False)
diff --git a/lib/py/src/TMultiplexedProcessor.py b/lib/py/src/TMultiplexedProcessor.py
new file mode 100644
index 0000000..3ac5af0
--- /dev/null
+++ b/lib/py/src/TMultiplexedProcessor.py
@@ -0,0 +1,54 @@
+#
+# 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.
+#
+
+from thrift.Thrift import TProcessor, TMessageType, TException
+from thrift.protocol import TProtocolDecorator, TMultiplexedProtocol
+
+
+class TMultiplexedProcessor(TProcessor):
+    def __init__(self):
+        self.services = {}
+
+    def registerProcessor(self, serviceName, processor):
+        self.services[serviceName] = processor
+
+    def process(self, iprot, oprot):
+        (name, type, seqid) = iprot.readMessageBegin()
+        if type != TMessageType.CALL and type != TMessageType.ONEWAY:
+            raise TException("TMultiplexed protocol only supports CALL & ONEWAY")
+
+        index = name.find(TMultiplexedProtocol.SEPARATOR)
+        if index < 0:
+            raise TException("Service name not found in message name: " + name + ". Did you forget to use TMultiplexedProtocol in your client?")
+
+        serviceName = name[0:index]
+        call = name[index + len(TMultiplexedProtocol.SEPARATOR):]
+        if serviceName not in self.services:
+            raise TException("Service name not found: " + serviceName + ". Did you forget to call registerProcessor()?")
+
+        standardMessage = (call, type, seqid)
+        return self.services[serviceName].process(StoredMessageProtocol(iprot, standardMessage), oprot)
+
+
+class StoredMessageProtocol(TProtocolDecorator.TProtocolDecorator):
+    def __init__(self, protocol, messageBegin):
+        self.messageBegin = messageBegin
+
+    def readMessageBegin(self):
+        return self.messageBegin
diff --git a/lib/py/src/TRecursive.py b/lib/py/src/TRecursive.py
new file mode 100644
index 0000000..abf202c
--- /dev/null
+++ b/lib/py/src/TRecursive.py
@@ -0,0 +1,83 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+from thrift.Thrift import TType
+
+TYPE_IDX = 1
+SPEC_ARGS_IDX = 3
+SPEC_ARGS_CLASS_REF_IDX = 0
+SPEC_ARGS_THRIFT_SPEC_IDX = 1
+
+
+def fix_spec(all_structs):
+    """Wire up recursive references for all TStruct definitions inside of each thrift_spec."""
+    for struc in all_structs:
+        spec = struc.thrift_spec
+        for thrift_spec in spec:
+            if thrift_spec is None:
+                continue
+            elif thrift_spec[TYPE_IDX] == TType.STRUCT:
+                other = thrift_spec[SPEC_ARGS_IDX][SPEC_ARGS_CLASS_REF_IDX].thrift_spec
+                thrift_spec[SPEC_ARGS_IDX][SPEC_ARGS_THRIFT_SPEC_IDX] = other
+            elif thrift_spec[TYPE_IDX] in (TType.LIST, TType.SET):
+                _fix_list_or_set(thrift_spec[SPEC_ARGS_IDX])
+            elif thrift_spec[TYPE_IDX] == TType.MAP:
+                _fix_map(thrift_spec[SPEC_ARGS_IDX])
+
+
+def _fix_list_or_set(element_type):
+    # For a list or set, the thrift_spec entry looks like,
+    # (1, TType.LIST, 'lister', (TType.STRUCT, [RecList, None], False), None, ),  # 1
+    # so ``element_type`` will be,
+    # (TType.STRUCT, [RecList, None], False)
+    if element_type[0] == TType.STRUCT:
+        element_type[1][1] = element_type[1][0].thrift_spec
+    elif element_type[0] in (TType.LIST, TType.SET):
+        _fix_list_or_set(element_type[1])
+    elif element_type[0] == TType.MAP:
+        _fix_map(element_type[1])
+
+
+def _fix_map(element_type):
+    # For a map of key -> value type, ``element_type`` will be,
+    # (TType.I16, None, TType.STRUCT, [RecMapBasic, None], False), None, )
+    # which is just a normal struct definition.
+    #
+    # For a map of key -> list / set, ``element_type`` will be,
+    # (TType.I16, None, TType.LIST, (TType.STRUCT, [RecMapList, None], False), False)
+    # and we need to process the 3rd element as a list.
+    #
+    # For a map of key -> map, ``element_type`` will be,
+    # (TType.I16, None, TType.MAP, (TType.I16, None, TType.STRUCT,
+    #  [RecMapMap, None], False), False)
+    # and need to process 3rd element as a map.
+
+    # Is the map key a struct?
+    if element_type[0] == TType.STRUCT:
+        element_type[1][1] = element_type[1][0].thrift_spec
+    elif element_type[0] in (TType.LIST, TType.SET):
+        _fix_list_or_set(element_type[1])
+    elif element_type[0] == TType.MAP:
+        _fix_map(element_type[1])
+
+    # Is the map value a struct?
+    if element_type[2] == TType.STRUCT:
+        element_type[3][1] = element_type[3][0].thrift_spec
+    elif element_type[2] in (TType.LIST, TType.SET):
+        _fix_list_or_set(element_type[3])
+    elif element_type[2] == TType.MAP:
+        _fix_map(element_type[3])
diff --git a/lib/py/src/TSCons.py b/lib/py/src/TSCons.py
index da8d283..bc67d70 100644
--- a/lib/py/src/TSCons.py
+++ b/lib/py/src/TSCons.py
@@ -19,17 +19,18 @@
 
 from os import path
 from SCons.Builder import Builder
+from six.moves import map
 
 
 def scons_env(env, add=''):
-  opath = path.dirname(path.abspath('$TARGET'))
-  lstr = 'thrift --gen cpp -o ' + opath + ' ' + add + ' $SOURCE'
-  cppbuild = Builder(action=lstr)
-  env.Append(BUILDERS={'ThriftCpp': cppbuild})
+    opath = path.dirname(path.abspath('$TARGET'))
+    lstr = 'thrift --gen cpp -o ' + opath + ' ' + add + ' $SOURCE'
+    cppbuild = Builder(action=lstr)
+    env.Append(BUILDERS={'ThriftCpp': cppbuild})
 
 
 def gen_cpp(env, dir, file):
-  scons_env(env)
-  suffixes = ['_types.h', '_types.cpp']
-  targets = map(lambda s: 'gen-cpp/' + file + s, suffixes)
-  return env.ThriftCpp(targets, dir + file + '.thrift')
+    scons_env(env)
+    suffixes = ['_types.h', '_types.cpp']
+    targets = map(lambda s: 'gen-cpp/' + file + s, suffixes)
+    return env.ThriftCpp(targets, dir + file + '.thrift')
diff --git a/lib/py/src/TSerialization.py b/lib/py/src/TSerialization.py
index 8a58d89..fbbe768 100644
--- a/lib/py/src/TSerialization.py
+++ b/lib/py/src/TSerialization.py
@@ -17,8 +17,8 @@
 # under the License.
 #
 
-from protocol import TBinaryProtocol
-from transport import TTransport
+from .protocol import TBinaryProtocol
+from .transport import TTransport
 
 
 def serialize(thrift_object,
diff --git a/lib/py/src/TTornado.py b/lib/py/src/TTornado.py
index af309c3..5eff11d 100644
--- a/lib/py/src/TTornado.py
+++ b/lib/py/src/TTornado.py
@@ -17,58 +17,93 @@
 # under the License.
 #
 
-from cStringIO import StringIO
+from __future__ import absolute_import
 import logging
 import socket
 import struct
 
-from thrift.transport import TTransport
-from thrift.transport.TTransport import TTransportException
+from .transport.TTransport import TTransportException, TTransportBase, TMemoryBuffer
 
-from tornado import gen
-from tornado import iostream
-from tornado import netutil
+from io import BytesIO
+from collections import deque
+from contextlib import contextmanager
+from tornado import gen, iostream, ioloop, tcpserver, concurrent
+
+__all__ = ['TTornadoServer', 'TTornadoStreamTransport']
+
+logger = logging.getLogger(__name__)
 
 
-class TTornadoStreamTransport(TTransport.TTransportBase):
+class _Lock(object):
+    def __init__(self):
+        self._waiters = deque()
+
+    def acquired(self):
+        return len(self._waiters) > 0
+
+    @gen.coroutine
+    def acquire(self):
+        blocker = self._waiters[-1] if self.acquired() else None
+        future = concurrent.Future()
+        self._waiters.append(future)
+        if blocker:
+            yield blocker
+
+        raise gen.Return(self._lock_context())
+
+    def release(self):
+        assert self.acquired(), 'Lock not aquired'
+        future = self._waiters.popleft()
+        future.set_result(None)
+
+    @contextmanager
+    def _lock_context(self):
+        try:
+            yield
+        finally:
+            self.release()
+
+
+class TTornadoStreamTransport(TTransportBase):
     """a framed, buffered transport over a Tornado stream"""
-    def __init__(self, host, port, stream=None):
+    def __init__(self, host, port, stream=None, io_loop=None):
         self.host = host
         self.port = port
-        self.is_queuing_reads = False
-        self.read_queue = []
-        self.__wbuf = StringIO()
+        self.io_loop = io_loop or ioloop.IOLoop.current()
+        self.__wbuf = BytesIO()
+        self._read_lock = _Lock()
 
         # servers provide a ready-to-go stream
         self.stream = stream
-        if self.stream is not None:
-            self._set_close_callback()
 
-    # not the same number of parameters as TTransportBase.open
-    def open(self, callback):
-        logging.debug('socket connecting')
+    def with_timeout(self, timeout, future):
+        return gen.with_timeout(timeout, future, self.io_loop)
+
+    @gen.coroutine
+    def open(self, timeout=None):
+        logger.debug('socket connecting')
         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
         self.stream = iostream.IOStream(sock)
 
-        def on_close_in_connect(*_):
-            message = 'could not connect to {}:{}'.format(self.host, self.port)
+        try:
+            connect = self.stream.connect((self.host, self.port))
+            if timeout is not None:
+                yield self.with_timeout(timeout, connect)
+            else:
+                yield connect
+        except (socket.error, IOError, ioloop.TimeoutError) as e:
+            message = 'could not connect to {}:{} ({})'.format(self.host, self.port, e)
             raise TTransportException(
                 type=TTransportException.NOT_OPEN,
                 message=message)
-        self.stream.set_close_callback(on_close_in_connect)
 
-        def finish(*_):
-            self._set_close_callback()
-            callback()
+        raise gen.Return(self)
 
-        self.stream.connect((self.host, self.port), callback=finish)
-
-    def _set_close_callback(self):
-        def on_close():
-            raise TTransportException(
-                type=TTransportException.END_OF_FILE,
-                message='socket closed')
-        self.stream.set_close_callback(self.close)
+    def set_close_callback(self, callback):
+        """
+        Should be called only after open() returns
+        """
+        self.stream.set_close_callback(callback)
 
     def close(self):
         # don't raise if we intend to close
@@ -78,54 +113,46 @@
     def read(self, _):
         # The generated code for Tornado shouldn't do individual reads -- only
         # frames at a time
-        assert "you're doing it wrong" is True
+        assert False, "you're doing it wrong"
 
-    @gen.engine
-    def readFrame(self, callback):
-        self.read_queue.append(callback)
-        logging.debug('read queue: %s', self.read_queue)
+    @contextmanager
+    def io_exception_context(self):
+        try:
+            yield
+        except (socket.error, IOError) as e:
+            raise TTransportException(
+                type=TTransportException.END_OF_FILE,
+                message=str(e))
+        except iostream.StreamBufferFullError as e:
+            raise TTransportException(
+                type=TTransportException.UNKNOWN,
+                message=str(e))
 
-        if self.is_queuing_reads:
-            # If a read is already in flight, then the while loop below should
-            # pull it from self.read_queue
-            return
-
-        self.is_queuing_reads = True
-        while self.read_queue:
-            next_callback = self.read_queue.pop()
-            result = yield gen.Task(self._readFrameFromStream)
-            next_callback(result)
-        self.is_queuing_reads = False
-
-    @gen.engine
-    def _readFrameFromStream(self, callback):
-        logging.debug('_readFrameFromStream')
-        frame_header = yield gen.Task(self.stream.read_bytes, 4)
-        frame_length, = struct.unpack('!i', frame_header)
-        logging.debug('received frame header, frame length = %i', frame_length)
-        frame = yield gen.Task(self.stream.read_bytes, frame_length)
-        logging.debug('received frame payload')
-        callback(frame)
+    @gen.coroutine
+    def readFrame(self):
+        # IOStream processes reads one at a time
+        with (yield self._read_lock.acquire()):
+            with self.io_exception_context():
+                frame_header = yield self.stream.read_bytes(4)
+                if len(frame_header) == 0:
+                    raise iostream.StreamClosedError('Read zero bytes from stream')
+                frame_length, = struct.unpack('!i', frame_header)
+                frame = yield self.stream.read_bytes(frame_length)
+                raise gen.Return(frame)
 
     def write(self, buf):
         self.__wbuf.write(buf)
 
-    def flush(self, callback=None):
-        wout = self.__wbuf.getvalue()
-        wsz = len(wout)
+    def flush(self):
+        frame = self.__wbuf.getvalue()
         # reset wbuf before write/flush to preserve state on underlying failure
-        self.__wbuf = StringIO()
-        # N.B.: Doing this string concatenation is WAY cheaper than making
-        # two separate calls to the underlying socket object. Socket writes in
-        # Python turn out to be REALLY expensive, but it seems to do a pretty
-        # good job of managing string buffer operations without excessive copies
-        buf = struct.pack("!i", wsz) + wout
-
-        logging.debug('writing frame length = %i', wsz)
-        self.stream.write(buf, callback)
+        frame_length = struct.pack('!i', len(frame))
+        self.__wbuf = BytesIO()
+        with self.io_exception_context():
+            return self.stream.write(frame_length + frame)
 
 
-class TTornadoServer(netutil.TCPServer):
+class TTornadoServer(tcpserver.TCPServer):
     def __init__(self, processor, iprot_factory, oprot_factory=None,
                  *args, **kwargs):
         super(TTornadoServer, self).__init__(*args, **kwargs)
@@ -135,19 +162,27 @@
         self._oprot_factory = (oprot_factory if oprot_factory is not None
                                else iprot_factory)
 
+    @gen.coroutine
     def handle_stream(self, stream, address):
+        host, port = address[:2]
+        trans = TTornadoStreamTransport(host=host, port=port, stream=stream,
+                                        io_loop=self.io_loop)
+        oprot = self._oprot_factory.getProtocol(trans)
+
         try:
-            host, port = address
-            trans = TTornadoStreamTransport(host=host, port=port, stream=stream)
-            oprot = self._oprot_factory.getProtocol(trans)
-
-            def next_pass():
-                if not trans.stream.closed():
-                    self._processor.process(trans, self._iprot_factory, oprot,
-                                            callback=next_pass)
-
-            next_pass()
-
+            while not trans.stream.closed():
+                try:
+                    frame = yield trans.readFrame()
+                except TTransportException as e:
+                    if e.type == TTransportException.END_OF_FILE:
+                        break
+                    else:
+                        raise
+                tr = TMemoryBuffer(frame)
+                iprot = self._iprot_factory.getProtocol(tr)
+                yield self._processor.process(iprot, oprot)
         except Exception:
-            logging.exception('thrift exception in handle_stream')
+            logger.exception('thrift exception in handle_stream')
             trans.close()
+
+        logger.info('client disconnected %s:%d', host, port)
diff --git a/lib/py/src/Thrift.py b/lib/py/src/Thrift.py
index 9890af7..00941d8 100644
--- a/lib/py/src/Thrift.py
+++ b/lib/py/src/Thrift.py
@@ -20,151 +20,173 @@
 import sys
 
 
-class TType:
-  STOP   = 0
-  VOID   = 1
-  BOOL   = 2
-  BYTE   = 3
-  I08    = 3
-  DOUBLE = 4
-  I16    = 6
-  I32    = 8
-  I64    = 10
-  STRING = 11
-  UTF7   = 11
-  STRUCT = 12
-  MAP    = 13
-  SET    = 14
-  LIST   = 15
-  UTF8   = 16
-  UTF16  = 17
+class TType(object):
+    STOP = 0
+    VOID = 1
+    BOOL = 2
+    BYTE = 3
+    I08 = 3
+    DOUBLE = 4
+    I16 = 6
+    I32 = 8
+    I64 = 10
+    STRING = 11
+    UTF7 = 11
+    STRUCT = 12
+    MAP = 13
+    SET = 14
+    LIST = 15
+    UTF8 = 16
+    UTF16 = 17
 
-  _VALUES_TO_NAMES = ('STOP',
-                      'VOID',
-                      'BOOL',
-                      'BYTE',
-                      'DOUBLE',
-                      None,
-                      'I16',
-                      None,
-                      'I32',
-                      None,
-                     'I64',
-                     'STRING',
-                     'STRUCT',
-                     'MAP',
-                     'SET',
-                     'LIST',
-                     'UTF8',
-                     'UTF16')
+    _VALUES_TO_NAMES = (
+        'STOP',
+        'VOID',
+        'BOOL',
+        'BYTE',
+        'DOUBLE',
+        None,
+        'I16',
+        None,
+        'I32',
+        None,
+        'I64',
+        'STRING',
+        'STRUCT',
+        'MAP',
+        'SET',
+        'LIST',
+        'UTF8',
+        'UTF16',
+    )
 
 
-class TMessageType:
-  CALL = 1
-  REPLY = 2
-  EXCEPTION = 3
-  ONEWAY = 4
+class TMessageType(object):
+    CALL = 1
+    REPLY = 2
+    EXCEPTION = 3
+    ONEWAY = 4
 
 
-class TProcessor:
-  """Base class for procsessor, which works on two streams."""
+class TProcessor(object):
+    """Base class for processor, which works on two streams."""
 
-  def process(iprot, oprot):
-    pass
+    def process(self, iprot, oprot):
+        pass
 
 
 class TException(Exception):
-  """Base class for all thrift exceptions."""
+    """Base class for all thrift exceptions."""
 
-  # BaseException.message is deprecated in Python v[2.6,3.0)
-  if (2, 6, 0) <= sys.version_info < (3, 0):
-    def _get_message(self):
-      return self._message
+    # BaseException.message is deprecated in Python v[2.6,3.0)
+    if (2, 6, 0) <= sys.version_info < (3, 0):
+        def _get_message(self):
+            return self._message
 
-    def _set_message(self, message):
-      self._message = message
-    message = property(_get_message, _set_message)
+        def _set_message(self, message):
+            self._message = message
+        message = property(_get_message, _set_message)
 
-  def __init__(self, message=None):
-    Exception.__init__(self, message)
-    self.message = message
+    def __init__(self, message=None):
+        Exception.__init__(self, message)
+        self.message = message
 
 
 class TApplicationException(TException):
-  """Application level thrift exceptions."""
+    """Application level thrift exceptions."""
 
-  UNKNOWN = 0
-  UNKNOWN_METHOD = 1
-  INVALID_MESSAGE_TYPE = 2
-  WRONG_METHOD_NAME = 3
-  BAD_SEQUENCE_ID = 4
-  MISSING_RESULT = 5
-  INTERNAL_ERROR = 6
-  PROTOCOL_ERROR = 7
-  INVALID_TRANSFORM = 8
-  INVALID_PROTOCOL = 9
-  UNSUPPORTED_CLIENT_TYPE = 10
+    UNKNOWN = 0
+    UNKNOWN_METHOD = 1
+    INVALID_MESSAGE_TYPE = 2
+    WRONG_METHOD_NAME = 3
+    BAD_SEQUENCE_ID = 4
+    MISSING_RESULT = 5
+    INTERNAL_ERROR = 6
+    PROTOCOL_ERROR = 7
+    INVALID_TRANSFORM = 8
+    INVALID_PROTOCOL = 9
+    UNSUPPORTED_CLIENT_TYPE = 10
 
-  def __init__(self, type=UNKNOWN, message=None):
-    TException.__init__(self, message)
-    self.type = type
+    def __init__(self, type=UNKNOWN, message=None):
+        TException.__init__(self, message)
+        self.type = type
 
-  def __str__(self):
-    if self.message:
-      return self.message
-    elif self.type == self.UNKNOWN_METHOD:
-      return 'Unknown method'
-    elif self.type == self.INVALID_MESSAGE_TYPE:
-      return 'Invalid message type'
-    elif self.type == self.WRONG_METHOD_NAME:
-      return 'Wrong method name'
-    elif self.type == self.BAD_SEQUENCE_ID:
-      return 'Bad sequence ID'
-    elif self.type == self.MISSING_RESULT:
-      return 'Missing result'
-    elif self.type == self.INTERNAL_ERROR:
-      return 'Internal error'
-    elif self.type == self.PROTOCOL_ERROR:
-      return 'Protocol error'
-    elif self.type == self.INVALID_TRANSFORM:
-      return 'Invalid transform'
-    elif self.type == self.INVALID_PROTOCOL:
-      return 'Invalid protocol'
-    elif self.type == self.UNSUPPORTED_CLIENT_TYPE:
-      return 'Unsupported client type'
-    else:
-      return 'Default (unknown) TApplicationException'
-
-  def read(self, iprot):
-    iprot.readStructBegin()
-    while True:
-      (fname, ftype, fid) = iprot.readFieldBegin()
-      if ftype == TType.STOP:
-        break
-      if fid == 1:
-        if ftype == TType.STRING:
-          self.message = iprot.readString()
+    def __str__(self):
+        if self.message:
+            return self.message
+        elif self.type == self.UNKNOWN_METHOD:
+            return 'Unknown method'
+        elif self.type == self.INVALID_MESSAGE_TYPE:
+            return 'Invalid message type'
+        elif self.type == self.WRONG_METHOD_NAME:
+            return 'Wrong method name'
+        elif self.type == self.BAD_SEQUENCE_ID:
+            return 'Bad sequence ID'
+        elif self.type == self.MISSING_RESULT:
+            return 'Missing result'
+        elif self.type == self.INTERNAL_ERROR:
+            return 'Internal error'
+        elif self.type == self.PROTOCOL_ERROR:
+            return 'Protocol error'
+        elif self.type == self.INVALID_TRANSFORM:
+            return 'Invalid transform'
+        elif self.type == self.INVALID_PROTOCOL:
+            return 'Invalid protocol'
+        elif self.type == self.UNSUPPORTED_CLIENT_TYPE:
+            return 'Unsupported client type'
         else:
-          iprot.skip(ftype)
-      elif fid == 2:
-        if ftype == TType.I32:
-          self.type = iprot.readI32()
-        else:
-          iprot.skip(ftype)
-      else:
-        iprot.skip(ftype)
-      iprot.readFieldEnd()
-    iprot.readStructEnd()
+            return 'Default (unknown) TApplicationException'
 
-  def write(self, oprot):
-    oprot.writeStructBegin('TApplicationException')
-    if self.message is not None:
-      oprot.writeFieldBegin('message', TType.STRING, 1)
-      oprot.writeString(self.message)
-      oprot.writeFieldEnd()
-    if self.type is not None:
-      oprot.writeFieldBegin('type', TType.I32, 2)
-      oprot.writeI32(self.type)
-      oprot.writeFieldEnd()
-    oprot.writeFieldStop()
-    oprot.writeStructEnd()
+    def read(self, iprot):
+        iprot.readStructBegin()
+        while True:
+            (fname, ftype, fid) = iprot.readFieldBegin()
+            if ftype == TType.STOP:
+                break
+            if fid == 1:
+                if ftype == TType.STRING:
+                    self.message = iprot.readString()
+                else:
+                    iprot.skip(ftype)
+            elif fid == 2:
+                if ftype == TType.I32:
+                    self.type = iprot.readI32()
+                else:
+                    iprot.skip(ftype)
+            else:
+                iprot.skip(ftype)
+            iprot.readFieldEnd()
+        iprot.readStructEnd()
+
+    def write(self, oprot):
+        oprot.writeStructBegin('TApplicationException')
+        if self.message is not None:
+            oprot.writeFieldBegin('message', TType.STRING, 1)
+            oprot.writeString(self.message)
+            oprot.writeFieldEnd()
+        if self.type is not None:
+            oprot.writeFieldBegin('type', TType.I32, 2)
+            oprot.writeI32(self.type)
+            oprot.writeFieldEnd()
+        oprot.writeFieldStop()
+        oprot.writeStructEnd()
+
+
+class TFrozenDict(dict):
+    """A dictionary that is "frozen" like a frozenset"""
+
+    def __init__(self, *args, **kwargs):
+        super(TFrozenDict, self).__init__(*args, **kwargs)
+        # Sort the items so they will be in a consistent order.
+        # XOR in the hash of the class so we don't collide with
+        # the hash of a list of tuples.
+        self.__hashval = hash(TFrozenDict) ^ hash(tuple(sorted(self.items())))
+
+    def __setitem__(self, *args):
+        raise TypeError("Can't modify frozen TFreezableDict")
+
+    def __delitem__(self, *args):
+        raise TypeError("Can't modify frozen TFreezableDict")
+
+    def __hash__(self):
+        return self.__hashval
diff --git a/lib/py/src/compat.py b/lib/py/src/compat.py
new file mode 100644
index 0000000..0e8271d
--- /dev/null
+++ b/lib/py/src/compat.py
@@ -0,0 +1,46 @@
+#
+# 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 sys
+
+if sys.version_info[0] == 2:
+
+    from cStringIO import StringIO as BufferIO
+
+    def binary_to_str(bin_val):
+        return bin_val
+
+    def str_to_binary(str_val):
+        return str_val
+
+    def byte_index(bytes_val, i):
+        return ord(bytes_val[i])
+
+else:
+
+    from io import BytesIO as BufferIO  # noqa
+
+    def binary_to_str(bin_val):
+        return bin_val.decode('utf8')
+
+    def str_to_binary(str_val):
+        return bytes(str_val, 'utf8')
+
+    def byte_index(bytes_val, i):
+        return bytes_val[i]
diff --git a/lib/py/src/ext/binary.cpp b/lib/py/src/ext/binary.cpp
new file mode 100644
index 0000000..85d8d92
--- /dev/null
+++ b/lib/py/src/ext/binary.cpp
@@ -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.
+ */
+
+#include "ext/binary.h"
+namespace apache {
+namespace thrift {
+namespace py {
+
+bool BinaryProtocol::readFieldBegin(TType& type, int16_t& tag) {
+  uint8_t b = 0;
+  if (!readByte(b)) {
+    return false;
+  }
+  type = static_cast<TType>(b);
+  if (type == T_STOP) {
+    return true;
+  }
+  return readI16(tag);
+}
+}
+}
+}
diff --git a/lib/py/src/ext/binary.h b/lib/py/src/ext/binary.h
new file mode 100644
index 0000000..960b0d0
--- /dev/null
+++ b/lib/py/src/ext/binary.h
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+#ifndef THRIFT_PY_BINARY_H
+#define THRIFT_PY_BINARY_H
+
+#include <Python.h>
+#include "ext/protocol.h"
+#include "ext/endian.h"
+#include <stdint.h>
+
+namespace apache {
+namespace thrift {
+namespace py {
+
+class BinaryProtocol : public ProtocolBase<BinaryProtocol> {
+public:
+  virtual ~BinaryProtocol() {}
+
+  void writeI8(int8_t val) { writeBuffer(reinterpret_cast<char*>(&val), sizeof(int8_t)); }
+
+  void writeI16(int16_t val) {
+    int16_t net = static_cast<int16_t>(htons(val));
+    writeBuffer(reinterpret_cast<char*>(&net), sizeof(int16_t));
+  }
+
+  void writeI32(int32_t val) {
+    int32_t net = static_cast<int32_t>(htonl(val));
+    writeBuffer(reinterpret_cast<char*>(&net), sizeof(int32_t));
+  }
+
+  void writeI64(int64_t val) {
+    int64_t net = static_cast<int64_t>(htonll(val));
+    writeBuffer(reinterpret_cast<char*>(&net), sizeof(int64_t));
+  }
+
+  void writeDouble(double dub) {
+    // Unfortunately, bitwise_cast doesn't work in C.  Bad C!
+    union {
+      double f;
+      int64_t t;
+    } transfer;
+    transfer.f = dub;
+    writeI64(transfer.t);
+  }
+
+  void writeBool(int v) { writeByte(static_cast<uint8_t>(v)); }
+
+  void writeString(PyObject* value, int32_t len) {
+    writeI32(len);
+    writeBuffer(PyBytes_AS_STRING(value), len);
+  }
+
+  bool writeListBegin(PyObject* value, const SetListTypeArgs& parsedargs, int32_t len) {
+    writeByte(parsedargs.element_type);
+    writeI32(len);
+    return true;
+  }
+
+  bool writeMapBegin(PyObject* value, const MapTypeArgs& parsedargs, int32_t len) {
+    writeByte(parsedargs.ktag);
+    writeByte(parsedargs.vtag);
+    writeI32(len);
+    return true;
+  }
+
+  bool writeStructBegin() { return true; }
+  bool writeStructEnd() { return true; }
+  bool writeField(PyObject* value, const StructItemSpec& parsedspec) {
+    writeByte(static_cast<uint8_t>(parsedspec.type));
+    writeI16(parsedspec.tag);
+    return encodeValue(value, parsedspec.type, parsedspec.typeargs);
+  }
+
+  void writeFieldStop() { writeByte(static_cast<uint8_t>(T_STOP)); }
+
+  bool readBool(bool& val) {
+    char* buf;
+    if (!readBytes(&buf, 1)) {
+      return false;
+    }
+    val = buf[0] == 1;
+    return true;
+  }
+
+  bool readI8(int8_t& val) {
+    char* buf;
+    if (!readBytes(&buf, 1)) {
+      return false;
+    }
+    val = buf[0];
+    return true;
+  }
+
+  bool readI16(int16_t& val) {
+    char* buf;
+    if (!readBytes(&buf, sizeof(int16_t))) {
+      return false;
+    }
+    memcpy(&val, buf, sizeof(int16_t));
+    val = ntohs(val);
+    return true;
+  }
+
+  bool readI32(int32_t& val) {
+    char* buf;
+    if (!readBytes(&buf, sizeof(int32_t))) {
+      return false;
+    }
+    memcpy(&val, buf, sizeof(int32_t));
+    val = ntohl(val);
+    return true;
+  }
+
+  bool readI64(int64_t& val) {
+    char* buf;
+    if (!readBytes(&buf, sizeof(int64_t))) {
+      return false;
+    }
+    memcpy(&val, buf, sizeof(int64_t));
+    val = ntohll(val);
+    return true;
+  }
+
+  bool readDouble(double& val) {
+    union {
+      int64_t f;
+      double t;
+    } transfer;
+
+    if (!readI64(transfer.f)) {
+      return false;
+    }
+    val = transfer.t;
+    return true;
+  }
+
+  int32_t readString(char** buf) {
+    int32_t len = 0;
+    if (!readI32(len) || !checkLengthLimit(len, stringLimit()) || !readBytes(buf, len)) {
+      return -1;
+    }
+    return len;
+  }
+
+  int32_t readListBegin(TType& etype) {
+    int32_t len;
+    uint8_t b = 0;
+    if (!readByte(b) || !readI32(len) || !checkLengthLimit(len, containerLimit())) {
+      return -1;
+    }
+    etype = static_cast<TType>(b);
+    return len;
+  }
+
+  int32_t readMapBegin(TType& ktype, TType& vtype) {
+    int32_t len;
+    uint8_t k, v;
+    if (!readByte(k) || !readByte(v) || !readI32(len) || !checkLengthLimit(len, containerLimit())) {
+      return -1;
+    }
+    ktype = static_cast<TType>(k);
+    vtype = static_cast<TType>(v);
+    return len;
+  }
+
+  bool readStructBegin() { return true; }
+  bool readStructEnd() { return true; }
+
+  bool readFieldBegin(TType& type, int16_t& tag);
+
+#define SKIPBYTES(n)                                                                               \
+  do {                                                                                             \
+    if (!readBytes(&dummy_buf_, (n))) {                                                            \
+      return false;                                                                                \
+    }                                                                                              \
+    return true;                                                                                   \
+  } while (0)
+
+  bool skipBool() { SKIPBYTES(1); }
+  bool skipByte() { SKIPBYTES(1); }
+  bool skipI16() { SKIPBYTES(2); }
+  bool skipI32() { SKIPBYTES(4); }
+  bool skipI64() { SKIPBYTES(8); }
+  bool skipDouble() { SKIPBYTES(8); }
+  bool skipString() {
+    int32_t len;
+    if (!readI32(len)) {
+      return false;
+    }
+    SKIPBYTES(len);
+  }
+#undef SKIPBYTES
+
+private:
+  char* dummy_buf_;
+};
+}
+}
+}
+#endif // THRIFT_PY_BINARY_H
diff --git a/lib/py/src/ext/compact.cpp b/lib/py/src/ext/compact.cpp
new file mode 100644
index 0000000..15a99a0
--- /dev/null
+++ b/lib/py/src/ext/compact.cpp
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "ext/compact.h"
+
+namespace apache {
+namespace thrift {
+namespace py {
+
+const uint8_t CompactProtocol::TTypeToCType[] = {
+    CT_STOP,         // T_STOP
+    0,               // unused
+    CT_BOOLEAN_TRUE, // T_BOOL
+    CT_BYTE,         // T_BYTE
+    CT_DOUBLE,       // T_DOUBLE
+    0,               // unused
+    CT_I16,          // T_I16
+    0,               // unused
+    CT_I32,          // T_I32
+    0,               // unused
+    CT_I64,          // T_I64
+    CT_BINARY,       // T_STRING
+    CT_STRUCT,       // T_STRUCT
+    CT_MAP,          // T_MAP
+    CT_SET,          // T_SET
+    CT_LIST,         // T_LIST
+};
+
+bool CompactProtocol::readFieldBegin(TType& type, int16_t& tag) {
+  uint8_t b;
+  if (!readByte(b)) {
+    return false;
+  }
+  uint8_t ctype = b & 0xf;
+  type = getTType(ctype);
+  if (type == -1) {
+    return false;
+  } else if (type == T_STOP) {
+    tag = 0;
+    return true;
+  }
+  uint8_t diff = (b & 0xf0) >> 4;
+  if (diff) {
+    tag = readTags_.top() + diff;
+  } else if (!readI16(tag)) {
+    readTags_.top() = -1;
+    return false;
+  }
+  if (ctype == CT_BOOLEAN_FALSE || ctype == CT_BOOLEAN_TRUE) {
+    readBool_.exists = true;
+    readBool_.value = ctype == CT_BOOLEAN_TRUE;
+  }
+  readTags_.top() = tag;
+  return true;
+}
+
+TType CompactProtocol::getTType(uint8_t type) {
+  switch (type) {
+  case T_STOP:
+    return T_STOP;
+  case CT_BOOLEAN_FALSE:
+  case CT_BOOLEAN_TRUE:
+    return T_BOOL;
+  case CT_BYTE:
+    return T_BYTE;
+  case CT_I16:
+    return T_I16;
+  case CT_I32:
+    return T_I32;
+  case CT_I64:
+    return T_I64;
+  case CT_DOUBLE:
+    return T_DOUBLE;
+  case CT_BINARY:
+    return T_STRING;
+  case CT_LIST:
+    return T_LIST;
+  case CT_SET:
+    return T_SET;
+  case CT_MAP:
+    return T_MAP;
+  case CT_STRUCT:
+    return T_STRUCT;
+  default:
+    PyErr_Format(PyExc_TypeError, "don't know what type: %d", type);
+    return static_cast<TType>(-1);
+  }
+}
+}
+}
+}
diff --git a/lib/py/src/ext/compact.h b/lib/py/src/ext/compact.h
new file mode 100644
index 0000000..a78d7a7
--- /dev/null
+++ b/lib/py/src/ext/compact.h
@@ -0,0 +1,368 @@
+/*
+ * 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.
+ */
+
+#ifndef THRIFT_PY_COMPACT_H
+#define THRIFT_PY_COMPACT_H
+
+#include <Python.h>
+#include "ext/protocol.h"
+#include "ext/endian.h"
+#include <stdint.h>
+#include <stack>
+
+namespace apache {
+namespace thrift {
+namespace py {
+
+class CompactProtocol : public ProtocolBase<CompactProtocol> {
+public:
+  CompactProtocol() { readBool_.exists = false; }
+
+  virtual ~CompactProtocol() {}
+
+  void writeI8(int8_t val) { writeBuffer(reinterpret_cast<char*>(&val), 1); }
+
+  void writeI16(int16_t val) { writeVarint(toZigZag(val)); }
+
+  int writeI32(int32_t val) { return writeVarint(toZigZag(val)); }
+
+  void writeI64(int64_t val) { writeVarint64(toZigZag64(val)); }
+
+  void writeDouble(double dub) {
+    union {
+      double f;
+      int64_t t;
+    } transfer;
+    transfer.f = htolell(dub);
+    writeBuffer(reinterpret_cast<char*>(&transfer.t), sizeof(int64_t));
+  }
+
+  void writeBool(int v) { writeByte(static_cast<uint8_t>(v ? CT_BOOLEAN_TRUE : CT_BOOLEAN_FALSE)); }
+
+  void writeString(PyObject* value, int32_t len) {
+    writeVarint(len);
+    writeBuffer(PyBytes_AS_STRING(value), len);
+  }
+
+  bool writeListBegin(PyObject* value, const SetListTypeArgs& args, int32_t len) {
+    int ctype = toCompactType(args.element_type);
+    if (len <= 14) {
+      writeByte(static_cast<uint8_t>(len << 4 | ctype));
+    } else {
+      writeByte(0xf0 | ctype);
+      writeVarint(len);
+    }
+    return true;
+  }
+
+  bool writeMapBegin(PyObject* value, const MapTypeArgs& args, int32_t len) {
+    if (len == 0) {
+      writeByte(0);
+      return true;
+    }
+    int ctype = toCompactType(args.ktag) << 4 | toCompactType(args.vtag);
+    writeVarint(len);
+    writeByte(ctype);
+    return true;
+  }
+
+  bool writeStructBegin() {
+    writeTags_.push(0);
+    return true;
+  }
+  bool writeStructEnd() {
+    writeTags_.pop();
+    return true;
+  }
+
+  bool writeField(PyObject* value, const StructItemSpec& spec) {
+    if (spec.type == T_BOOL) {
+      doWriteFieldBegin(spec, PyObject_IsTrue(value) ? CT_BOOLEAN_TRUE : CT_BOOLEAN_FALSE);
+      return true;
+    } else {
+      doWriteFieldBegin(spec, toCompactType(spec.type));
+      return encodeValue(value, spec.type, spec.typeargs);
+    }
+  }
+
+  void writeFieldStop() { writeByte(0); }
+
+  bool readBool(bool& val) {
+    if (readBool_.exists) {
+      readBool_.exists = false;
+      val = readBool_.value;
+      return true;
+    }
+    char* buf;
+    if (!readBytes(&buf, 1)) {
+      return false;
+    }
+    val = buf[0] == CT_BOOLEAN_TRUE;
+    return true;
+  }
+  bool readI8(int8_t& val) {
+    char* buf;
+    if (!readBytes(&buf, 1)) {
+      return false;
+    }
+    val = buf[0];
+    return true;
+  }
+
+  bool readI16(int16_t& val) {
+    uint16_t uval;
+    if (readVarint<uint16_t, 3>(uval)) {
+      val = fromZigZag<int16_t, uint16_t>(uval);
+      return true;
+    }
+    return false;
+  }
+
+  bool readI32(int32_t& val) {
+    uint32_t uval;
+    if (readVarint<uint32_t, 5>(uval)) {
+      val = fromZigZag<int32_t, uint32_t>(uval);
+      return true;
+    }
+    return false;
+  }
+
+  bool readI64(int64_t& val) {
+    uint64_t uval;
+    if (readVarint<uint64_t, 10>(uval)) {
+      val = fromZigZag<int64_t, uint64_t>(uval);
+      return true;
+    }
+    return false;
+  }
+
+  bool readDouble(double& val) {
+    union {
+      int64_t f;
+      double t;
+    } transfer;
+
+    char* buf;
+    if (!readBytes(&buf, 8)) {
+      return false;
+    }
+    memcpy(&transfer.f, buf, sizeof(int64_t));
+    transfer.f = letohll(transfer.f);
+    val = transfer.t;
+    return true;
+  }
+
+  int32_t readString(char** buf) {
+    uint32_t len;
+    if (!readVarint<uint32_t, 5>(len) || !checkLengthLimit(len, stringLimit())) {
+      return -1;
+    }
+    if (len == 0) {
+      return 0;
+    }
+    if (!readBytes(buf, len)) {
+      return -1;
+    }
+    return len;
+  }
+
+  int32_t readListBegin(TType& etype) {
+    uint8_t b;
+    if (!readByte(b)) {
+      return -1;
+    }
+    etype = getTType(b & 0xf);
+    if (etype == -1) {
+      return -1;
+    }
+    uint32_t len = (b >> 4) & 0xf;
+    if (len == 15 && !readVarint<uint32_t, 5>(len)) {
+      return -1;
+    }
+    if (!checkLengthLimit(len, containerLimit())) {
+      return -1;
+    }
+    return len;
+  }
+
+  int32_t readMapBegin(TType& ktype, TType& vtype) {
+    uint32_t len;
+    if (!readVarint<uint32_t, 5>(len) || !checkLengthLimit(len, containerLimit())) {
+      return -1;
+    }
+    if (len != 0) {
+      uint8_t kvType;
+      if (!readByte(kvType)) {
+        return -1;
+      }
+      ktype = getTType(kvType >> 4);
+      vtype = getTType(kvType & 0xf);
+      if (ktype == -1 || vtype == -1) {
+        return -1;
+      }
+    }
+    return len;
+  }
+
+  bool readStructBegin() {
+    readTags_.push(0);
+    return true;
+  }
+  bool readStructEnd() {
+    readTags_.pop();
+    return true;
+  }
+  bool readFieldBegin(TType& type, int16_t& tag);
+
+  bool skipBool() {
+    bool val;
+    return readBool(val);
+  }
+#define SKIPBYTES(n)                                                                               \
+  do {                                                                                             \
+    if (!readBytes(&dummy_buf_, (n))) {                                                            \
+      return false;                                                                                \
+    }                                                                                              \
+    return true;                                                                                   \
+  } while (0)
+  bool skipByte() { SKIPBYTES(1); }
+  bool skipDouble() { SKIPBYTES(8); }
+  bool skipI16() {
+    int16_t val;
+    return readI16(val);
+  }
+  bool skipI32() {
+    int32_t val;
+    return readI32(val);
+  }
+  bool skipI64() {
+    int64_t val;
+    return readI64(val);
+  }
+  bool skipString() {
+    uint32_t len;
+    if (!readVarint<uint32_t, 5>(len)) {
+      return false;
+    }
+    SKIPBYTES(len);
+  }
+#undef SKIPBYTES
+
+private:
+  enum Types {
+    CT_STOP = 0x00,
+    CT_BOOLEAN_TRUE = 0x01,
+    CT_BOOLEAN_FALSE = 0x02,
+    CT_BYTE = 0x03,
+    CT_I16 = 0x04,
+    CT_I32 = 0x05,
+    CT_I64 = 0x06,
+    CT_DOUBLE = 0x07,
+    CT_BINARY = 0x08,
+    CT_LIST = 0x09,
+    CT_SET = 0x0A,
+    CT_MAP = 0x0B,
+    CT_STRUCT = 0x0C
+  };
+
+  static const uint8_t TTypeToCType[];
+
+  TType getTType(uint8_t type);
+
+  int toCompactType(TType type) {
+    int i = static_cast<int>(type);
+    return i < 16 ? TTypeToCType[i] : -1;
+  }
+
+  uint32_t toZigZag(int32_t val) { return (val >> 31) ^ (val << 1); }
+
+  uint64_t toZigZag64(int64_t val) { return (val >> 63) ^ (val << 1); }
+
+  int writeVarint(uint32_t val) {
+    int cnt = 1;
+    while (val & ~0x7fU) {
+      writeByte(static_cast<char>((val & 0x7fU) | 0x80U));
+      val >>= 7;
+      ++cnt;
+    }
+    writeByte(static_cast<char>(val));
+    return cnt;
+  }
+
+  int writeVarint64(uint64_t val) {
+    int cnt = 1;
+    while (val & ~0x7fULL) {
+      writeByte(static_cast<char>((val & 0x7fULL) | 0x80ULL));
+      val >>= 7;
+      ++cnt;
+    }
+    writeByte(static_cast<char>(val));
+    return cnt;
+  }
+
+  template <typename T, int Max>
+  bool readVarint(T& result) {
+    uint8_t b;
+    T val = 0;
+    int shift = 0;
+    for (int i = 0; i < Max; ++i) {
+      if (!readByte(b)) {
+        return false;
+      }
+      if (b & 0x80) {
+        val |= static_cast<T>(b & 0x7f) << shift;
+      } else {
+        val |= static_cast<T>(b) << shift;
+        result = val;
+        return true;
+      }
+      shift += 7;
+    }
+    PyErr_Format(PyExc_OverflowError, "varint exceeded %d bytes", Max);
+    return false;
+  }
+
+  template <typename S, typename U>
+  S fromZigZag(U val) {
+    return (val >> 1) ^ static_cast<U>(-static_cast<S>(val & 1));
+  }
+
+  void doWriteFieldBegin(const StructItemSpec& spec, int ctype) {
+    int diff = spec.tag - writeTags_.top();
+    if (diff > 0 && diff <= 15) {
+      writeByte(static_cast<uint8_t>(diff << 4 | ctype));
+    } else {
+      writeByte(static_cast<uint8_t>(ctype));
+      writeI16(spec.tag);
+    }
+    writeTags_.top() = spec.tag;
+  }
+
+  std::stack<int> writeTags_;
+  std::stack<int> readTags_;
+  struct {
+    bool exists;
+    bool value;
+  } readBool_;
+  char* dummy_buf_;
+};
+}
+}
+}
+#endif // THRIFT_PY_COMPACT_H
diff --git a/lib/py/src/ext/endian.h b/lib/py/src/ext/endian.h
new file mode 100644
index 0000000..91372a7
--- /dev/null
+++ b/lib/py/src/ext/endian.h
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#ifndef THRIFT_PY_ENDIAN_H
+#define THRIFT_PY_ENDIAN_H
+
+#include <Python.h>
+
+#ifndef _WIN32
+#include <netinet/in.h>
+#else
+#include <WinSock2.h>
+#pragma comment(lib, "ws2_32.lib")
+#define BIG_ENDIAN (4321)
+#define LITTLE_ENDIAN (1234)
+#define BYTE_ORDER LITTLE_ENDIAN
+#define inline __inline
+#endif
+
+/* Fix endianness issues on Solaris */
+#if defined(__SVR4) && defined(__sun)
+#if defined(__i386) && !defined(__i386__)
+#define __i386__
+#endif
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN (4321)
+#endif
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN (1234)
+#endif
+
+/* I386 is LE, even on Solaris */
+#if !defined(BYTE_ORDER) && defined(__i386__)
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#endif
+
+#ifndef __BYTE_ORDER
+#if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
+#define __BYTE_ORDER BYTE_ORDER
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#define __BIG_ENDIAN BIG_ENDIAN
+#else
+#error "Cannot determine endianness"
+#endif
+#endif
+
+// Same comment as the enum.  Sorry.
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define ntohll(n) (n)
+#define htonll(n) (n)
+#if defined(__GNUC__) && defined(__GLIBC__)
+#include <byteswap.h>
+#define letohll(n) bswap_64(n)
+#define htolell(n) bswap_64(n)
+#else /* GNUC & GLIBC */
+#define letohll(n) ((((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32))
+#define htolell(n) ((((unsigned long long)htonl(n)) << 32) + htonl(n >> 32))
+#endif
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#if defined(__GNUC__) && defined(__GLIBC__)
+#include <byteswap.h>
+#define ntohll(n) bswap_64(n)
+#define htonll(n) bswap_64(n)
+#else /* GNUC & GLIBC */
+#define ntohll(n) ((((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32))
+#define htonll(n) ((((unsigned long long)htonl(n)) << 32) + htonl(n >> 32))
+#endif /* GNUC & GLIBC */
+#define letohll(n) (n)
+#define htolell(n) (n)
+#else /* __BYTE_ORDER */
+#error "Can't define htonll or ntohll!"
+#endif
+
+#endif // THRIFT_PY_ENDIAN_H
diff --git a/lib/py/src/ext/module.cpp b/lib/py/src/ext/module.cpp
new file mode 100644
index 0000000..7158b8f
--- /dev/null
+++ b/lib/py/src/ext/module.cpp
@@ -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.
+ */
+
+#include <Python.h>
+#include "types.h"
+#include "binary.h"
+#include "compact.h"
+#include <limits>
+#include <stdint.h>
+
+// TODO(dreiss): defval appears to be unused.  Look into removing it.
+// TODO(dreiss): Make parse_spec_args recursive, and cache the output
+//               permanently in the object.  (Malloc and orphan.)
+// TODO(dreiss): Why do we need cStringIO for reading, why not just char*?
+//               Can cStringIO let us work with a BufferedTransport?
+// TODO(dreiss): Don't ignore the rv from cwrite (maybe).
+
+// Doing a benchmark shows that interning actually makes a difference, amazingly.
+
+/** Pointer to interned string to speed up attribute lookup. */
+PyObject* INTERN_STRING(TFrozenDict);
+PyObject* INTERN_STRING(cstringio_buf);
+PyObject* INTERN_STRING(cstringio_refill);
+static PyObject* INTERN_STRING(string_length_limit);
+static PyObject* INTERN_STRING(container_length_limit);
+static PyObject* INTERN_STRING(trans);
+
+namespace apache {
+namespace thrift {
+namespace py {
+
+template <typename T>
+static PyObject* encode_impl(PyObject* args) {
+  if (!args)
+    return NULL;
+
+  PyObject* enc_obj = NULL;
+  PyObject* type_args = NULL;
+  if (!PyArg_ParseTuple(args, "OO", &enc_obj, &type_args)) {
+    return NULL;
+  }
+  if (!enc_obj || !type_args) {
+    return NULL;
+  }
+
+  T protocol;
+  if (!protocol.prepareEncodeBuffer() || !protocol.encodeValue(enc_obj, T_STRUCT, type_args)) {
+    return NULL;
+  }
+
+  return protocol.getEncodedValue();
+}
+
+static inline long as_long_then_delete(PyObject* value, long default_value) {
+  ScopedPyObject scope(value);
+  long v = PyInt_AsLong(value);
+  if (INT_CONV_ERROR_OCCURRED(v)) {
+    PyErr_Clear();
+    return default_value;
+  }
+  return v;
+}
+
+template <typename T>
+static PyObject* decode_impl(PyObject* args) {
+  PyObject* output_obj = NULL;
+  PyObject* oprot = NULL;
+  PyObject* typeargs = NULL;
+  if (!PyArg_ParseTuple(args, "OOO", &output_obj, &oprot, &typeargs)) {
+    return NULL;
+  }
+
+  T protocol;
+  int32_t default_limit = (std::numeric_limits<int32_t>::max)();
+  protocol.setStringLengthLimit(
+      as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(string_length_limit)),
+                          default_limit));
+  protocol.setContainerLengthLimit(
+      as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(container_length_limit)),
+                          default_limit));
+  ScopedPyObject transport(PyObject_GetAttr(oprot, INTERN_STRING(trans)));
+  if (!transport) {
+    return NULL;
+  }
+
+  StructTypeArgs parsedargs;
+  if (!parse_struct_args(&parsedargs, typeargs)) {
+    return NULL;
+  }
+
+  if (!protocol.prepareDecodeBufferFromTransport(transport.get())) {
+    return NULL;
+  }
+
+  return protocol.readStruct(output_obj, parsedargs.klass, parsedargs.spec);
+}
+}
+}
+}
+
+using namespace apache::thrift::py;
+
+/* -- PYTHON MODULE SETUP STUFF --- */
+
+extern "C" {
+
+static PyObject* encode_binary(PyObject*, PyObject* args) {
+  return encode_impl<BinaryProtocol>(args);
+}
+
+static PyObject* decode_binary(PyObject*, PyObject* args) {
+  return decode_impl<BinaryProtocol>(args);
+}
+
+static PyObject* encode_compact(PyObject*, PyObject* args) {
+  return encode_impl<CompactProtocol>(args);
+}
+
+static PyObject* decode_compact(PyObject*, PyObject* args) {
+  return decode_impl<CompactProtocol>(args);
+}
+
+static PyMethodDef ThriftFastBinaryMethods[] = {
+    {"encode_binary", encode_binary, METH_VARARGS, ""},
+    {"decode_binary", decode_binary, METH_VARARGS, ""},
+    {"encode_compact", encode_compact, METH_VARARGS, ""},
+    {"decode_compact", decode_compact, METH_VARARGS, ""},
+    {NULL, NULL, 0, NULL} /* Sentinel */
+};
+
+#if PY_MAJOR_VERSION >= 3
+
+static struct PyModuleDef ThriftFastBinaryDef = {PyModuleDef_HEAD_INIT,
+                                                 "thrift.protocol.fastbinary",
+                                                 NULL,
+                                                 0,
+                                                 ThriftFastBinaryMethods,
+                                                 NULL,
+                                                 NULL,
+                                                 NULL,
+                                                 NULL};
+
+#define INITERROR return NULL;
+
+PyObject* PyInit_fastbinary() {
+
+#else
+
+#define INITERROR return;
+
+void initfastbinary() {
+
+  PycString_IMPORT;
+  if (PycStringIO == NULL)
+    INITERROR
+
+#endif
+
+#define INIT_INTERN_STRING(value)                                                                  \
+  do {                                                                                             \
+    INTERN_STRING(value) = PyString_InternFromString(#value);                                      \
+    if (!INTERN_STRING(value))                                                                     \
+      INITERROR                                                                                    \
+  } while (0)
+
+  INIT_INTERN_STRING(TFrozenDict);
+  INIT_INTERN_STRING(cstringio_buf);
+  INIT_INTERN_STRING(cstringio_refill);
+  INIT_INTERN_STRING(string_length_limit);
+  INIT_INTERN_STRING(container_length_limit);
+  INIT_INTERN_STRING(trans);
+#undef INIT_INTERN_STRING
+
+  PyObject* module =
+#if PY_MAJOR_VERSION >= 3
+      PyModule_Create(&ThriftFastBinaryDef);
+#else
+      Py_InitModule("thrift.protocol.fastbinary", ThriftFastBinaryMethods);
+#endif
+  if (module == NULL)
+    INITERROR;
+
+#if PY_MAJOR_VERSION >= 3
+  return module;
+#endif
+}
+}
diff --git a/lib/py/src/ext/protocol.h b/lib/py/src/ext/protocol.h
new file mode 100644
index 0000000..521b7ee
--- /dev/null
+++ b/lib/py/src/ext/protocol.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#ifndef THRIFT_PY_PROTOCOL_H
+#define THRIFT_PY_PROTOCOL_H
+
+#include "ext/types.h"
+#include <limits>
+#include <stdint.h>
+
+namespace apache {
+namespace thrift {
+namespace py {
+
+template <typename Impl>
+class ProtocolBase {
+
+public:
+  ProtocolBase()
+    : stringLimit_((std::numeric_limits<int32_t>::max)()),
+      containerLimit_((std::numeric_limits<int32_t>::max)()),
+      output_(NULL) {}
+  inline virtual ~ProtocolBase();
+
+  bool prepareDecodeBufferFromTransport(PyObject* trans);
+
+  PyObject* readStruct(PyObject* output, PyObject* klass, PyObject* spec_seq);
+
+  bool prepareEncodeBuffer();
+
+  bool encodeValue(PyObject* value, TType type, PyObject* typeargs);
+
+  PyObject* getEncodedValue();
+
+  long stringLimit() const { return stringLimit_; }
+  void setStringLengthLimit(long limit) { stringLimit_ = limit; }
+
+  long containerLimit() const { return containerLimit_; }
+  void setContainerLengthLimit(long limit) { containerLimit_ = limit; }
+
+protected:
+  bool readBytes(char** output, int len);
+
+  bool readByte(uint8_t& val) {
+    char* buf;
+    if (!readBytes(&buf, 1)) {
+      return false;
+    }
+    val = static_cast<uint8_t>(buf[0]);
+    return true;
+  }
+
+  bool writeBuffer(char* data, size_t len);
+
+  void writeByte(uint8_t val) { writeBuffer(reinterpret_cast<char*>(&val), 1); }
+
+  PyObject* decodeValue(TType type, PyObject* typeargs);
+
+  bool skip(TType type);
+
+  inline bool checkType(TType got, TType expected);
+  inline bool checkLengthLimit(int32_t len, long limit);
+
+  inline bool isUtf8(PyObject* typeargs);
+
+private:
+  Impl* impl() { return static_cast<Impl*>(this); }
+
+  long stringLimit_;
+  long containerLimit_;
+  EncodeBuffer* output_;
+  DecodeBuffer input_;
+};
+}
+}
+}
+
+#include "ext/protocol.tcc"
+
+#endif // THRIFT_PY_PROTOCOL_H
diff --git a/lib/py/src/ext/protocol.tcc b/lib/py/src/ext/protocol.tcc
new file mode 100644
index 0000000..e15df7e
--- /dev/null
+++ b/lib/py/src/ext/protocol.tcc
@@ -0,0 +1,913 @@
+/*
+ * 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.
+ */
+
+#ifndef THRIFT_PY_PROTOCOL_TCC
+#define THRIFT_PY_PROTOCOL_TCC
+
+#include <iterator>
+
+#define CHECK_RANGE(v, min, max) (((v) <= (max)) && ((v) >= (min)))
+#define INIT_OUTBUF_SIZE 128
+
+#if PY_MAJOR_VERSION < 3
+#include <cStringIO.h>
+#else
+#include <algorithm>
+#endif
+
+namespace apache {
+namespace thrift {
+namespace py {
+
+#if PY_MAJOR_VERSION < 3
+
+namespace detail {
+
+inline bool input_check(PyObject* input) {
+  return PycStringIO_InputCheck(input);
+}
+
+inline EncodeBuffer* new_encode_buffer(size_t size) {
+  if (!PycStringIO) {
+    PycString_IMPORT;
+  }
+  if (!PycStringIO) {
+    return NULL;
+  }
+  return PycStringIO->NewOutput(size);
+}
+
+inline int read_buffer(PyObject* buf, char** output, int len) {
+  if (!PycStringIO) {
+    PycString_IMPORT;
+  }
+  if (!PycStringIO) {
+    PyErr_SetString(PyExc_ImportError, "failed to import native cStringIO");
+    return -1;
+  }
+  return PycStringIO->cread(buf, output, len);
+}
+}
+
+template <typename Impl>
+inline ProtocolBase<Impl>::~ProtocolBase() {
+  if (output_) {
+    Py_CLEAR(output_);
+  }
+}
+
+template <typename Impl>
+inline bool ProtocolBase<Impl>::isUtf8(PyObject* typeargs) {
+  return PyString_Check(typeargs) && !strncmp(PyString_AS_STRING(typeargs), "UTF8", 4);
+}
+
+template <typename Impl>
+PyObject* ProtocolBase<Impl>::getEncodedValue() {
+  if (!PycStringIO) {
+    PycString_IMPORT;
+  }
+  if (!PycStringIO) {
+    return NULL;
+  }
+  return PycStringIO->cgetvalue(output_);
+}
+
+template <typename Impl>
+inline bool ProtocolBase<Impl>::writeBuffer(char* data, size_t size) {
+  if (!PycStringIO) {
+    PycString_IMPORT;
+  }
+  if (!PycStringIO) {
+    PyErr_SetString(PyExc_ImportError, "failed to import native cStringIO");
+    return false;
+  }
+  int len = PycStringIO->cwrite(output_, data, size);
+  if (len < 0) {
+    PyErr_SetString(PyExc_IOError, "failed to write to cStringIO object");
+    return false;
+  }
+  if (static_cast<size_t>(len) != size) {
+    PyErr_Format(PyExc_EOFError, "write length mismatch: expected %lu got %d", size, len);
+    return false;
+  }
+  return true;
+}
+
+#else
+
+namespace detail {
+
+inline bool input_check(PyObject* input) {
+  // TODO: Check for BytesIO type
+  return true;
+}
+
+inline EncodeBuffer* new_encode_buffer(size_t size) {
+  EncodeBuffer* buffer = new EncodeBuffer;
+  buffer->buf.reserve(size);
+  buffer->pos = 0;
+  return buffer;
+}
+
+struct bytesio {
+  PyObject_HEAD
+#if PY_MINOR_VERSION < 5
+      char* buf;
+#else
+      PyObject* buf;
+#endif
+  Py_ssize_t pos;
+  Py_ssize_t string_size;
+};
+
+inline int read_buffer(PyObject* buf, char** output, int len) {
+  bytesio* buf2 = reinterpret_cast<bytesio*>(buf);
+#if PY_MINOR_VERSION < 5
+  *output = buf2->buf + buf2->pos;
+#else
+  *output = PyBytes_AS_STRING(buf2->buf) + buf2->pos;
+#endif
+  Py_ssize_t pos0 = buf2->pos;
+  buf2->pos = (std::min)(buf2->pos + static_cast<Py_ssize_t>(len), buf2->string_size);
+  return static_cast<int>(buf2->pos - pos0);
+}
+}
+
+template <typename Impl>
+inline ProtocolBase<Impl>::~ProtocolBase() {
+  if (output_) {
+    delete output_;
+  }
+}
+
+template <typename Impl>
+inline bool ProtocolBase<Impl>::isUtf8(PyObject* typeargs) {
+  // while condition for py2 is "arg == 'UTF8'", it should be "arg != 'BINARY'" for py3.
+  // HACK: check the length and don't bother reading the value
+  return !PyUnicode_Check(typeargs) || PyUnicode_GET_LENGTH(typeargs) != 6;
+}
+
+template <typename Impl>
+PyObject* ProtocolBase<Impl>::getEncodedValue() {
+  return PyBytes_FromStringAndSize(output_->buf.data(), output_->buf.size());
+}
+
+template <typename Impl>
+inline bool ProtocolBase<Impl>::writeBuffer(char* data, size_t size) {
+  size_t need = size + output_->pos;
+  if (output_->buf.capacity() < need) {
+    try {
+      output_->buf.reserve(need);
+    } catch (std::bad_alloc& ex) {
+      PyErr_SetString(PyExc_MemoryError, "Failed to allocate write buffer");
+      return false;
+    }
+  }
+  std::copy(data, data + size, std::back_inserter(output_->buf));
+  return true;
+}
+
+#endif
+
+namespace detail {
+
+#define DECLARE_OP_SCOPE(name, op)                                                                 \
+  template <typename Impl>                                                                         \
+  struct name##Scope {                                                                             \
+    Impl* impl;                                                                                    \
+    bool valid;                                                                                    \
+    name##Scope(Impl* thiz) : impl(thiz), valid(impl->op##Begin()) {}                              \
+    ~name##Scope() {                                                                               \
+      if (valid)                                                                                   \
+        impl->op##End();                                                                           \
+    }                                                                                              \
+    operator bool() { return valid; }                                                              \
+  };                                                                                               \
+  template <typename Impl, template <typename> class T>                                            \
+  name##Scope<Impl> op##Scope(T<Impl>* thiz) {                                                     \
+    return name##Scope<Impl>(static_cast<Impl*>(thiz));                                            \
+  }
+DECLARE_OP_SCOPE(WriteStruct, writeStruct)
+DECLARE_OP_SCOPE(ReadStruct, readStruct)
+#undef DECLARE_OP_SCOPE
+
+inline bool check_ssize_t_32(Py_ssize_t len) {
+  // error from getting the int
+  if (INT_CONV_ERROR_OCCURRED(len)) {
+    return false;
+  }
+  if (!CHECK_RANGE(len, 0, (std::numeric_limits<int32_t>::max)())) {
+    PyErr_SetString(PyExc_OverflowError, "size out of range: exceeded INT32_MAX");
+    return false;
+  }
+  return true;
+}
+}
+
+template <typename T>
+bool parse_pyint(PyObject* o, T* ret, int32_t min, int32_t max) {
+  long val = PyInt_AsLong(o);
+
+  if (INT_CONV_ERROR_OCCURRED(val)) {
+    return false;
+  }
+  if (!CHECK_RANGE(val, min, max)) {
+    PyErr_SetString(PyExc_OverflowError, "int out of range");
+    return false;
+  }
+
+  *ret = static_cast<T>(val);
+  return true;
+}
+
+template <typename Impl>
+inline bool ProtocolBase<Impl>::checkType(TType got, TType expected) {
+  if (expected != got) {
+    PyErr_SetString(PyExc_TypeError, "got wrong ttype while reading field");
+    return false;
+  }
+  return true;
+}
+
+template <typename Impl>
+bool ProtocolBase<Impl>::checkLengthLimit(int32_t len, long limit) {
+  if (len < 0) {
+    PyErr_Format(PyExc_OverflowError, "negative length: %ld", limit);
+    return false;
+  }
+  if (len > limit) {
+    PyErr_Format(PyExc_OverflowError, "size exceeded specified limit: %ld", limit);
+    return false;
+  }
+  return true;
+}
+
+template <typename Impl>
+bool ProtocolBase<Impl>::readBytes(char** output, int len) {
+  if (len < 0) {
+    PyErr_Format(PyExc_ValueError, "attempted to read negative length: %d", len);
+    return false;
+  }
+  // TODO(dreiss): Don't fear the malloc.  Think about taking a copy of
+  //               the partial read instead of forcing the transport
+  //               to prepend it to its buffer.
+
+  int rlen = detail::read_buffer(input_.stringiobuf.get(), output, len);
+
+  if (rlen == len) {
+    return true;
+  } else if (rlen == -1) {
+    return false;
+  } else {
+    // using building functions as this is a rare codepath
+    ScopedPyObject newiobuf(PyObject_CallFunction(input_.refill_callable.get(), refill_signature,
+                                                  *output, rlen, len, NULL));
+    if (!newiobuf) {
+      return false;
+    }
+
+    // must do this *AFTER* the call so that we don't deref the io buffer
+    input_.stringiobuf.reset(newiobuf.release());
+
+    rlen = detail::read_buffer(input_.stringiobuf.get(), output, len);
+
+    if (rlen == len) {
+      return true;
+    } else if (rlen == -1) {
+      return false;
+    } else {
+      // TODO(dreiss): This could be a valid code path for big binary blobs.
+      PyErr_SetString(PyExc_TypeError, "refill claimed to have refilled the buffer, but didn't!!");
+      return false;
+    }
+  }
+}
+
+template <typename Impl>
+bool ProtocolBase<Impl>::prepareDecodeBufferFromTransport(PyObject* trans) {
+  if (input_.stringiobuf) {
+    PyErr_SetString(PyExc_ValueError, "decode buffer is already initialized");
+    return false;
+  }
+
+  ScopedPyObject stringiobuf(PyObject_GetAttr(trans, INTERN_STRING(cstringio_buf)));
+  if (!stringiobuf) {
+    return false;
+  }
+  if (!detail::input_check(stringiobuf.get())) {
+    PyErr_SetString(PyExc_TypeError, "expecting stringio input_");
+    return false;
+  }
+
+  ScopedPyObject refill_callable(PyObject_GetAttr(trans, INTERN_STRING(cstringio_refill)));
+  if (!refill_callable) {
+    return false;
+  }
+  if (!PyCallable_Check(refill_callable.get())) {
+    PyErr_SetString(PyExc_TypeError, "expecting callable");
+    return false;
+  }
+
+  input_.stringiobuf.swap(stringiobuf);
+  input_.refill_callable.swap(refill_callable);
+  return true;
+}
+
+template <typename Impl>
+bool ProtocolBase<Impl>::prepareEncodeBuffer() {
+  output_ = detail::new_encode_buffer(INIT_OUTBUF_SIZE);
+  return output_ != NULL;
+}
+
+template <typename Impl>
+bool ProtocolBase<Impl>::encodeValue(PyObject* value, TType type, PyObject* typeargs) {
+  /*
+   * Refcounting Strategy:
+   *
+   * We assume that elements of the thrift_spec tuple are not going to be
+   * mutated, so we don't ref count those at all. Other than that, we try to
+   * keep a reference to all the user-created objects while we work with them.
+   * encodeValue assumes that a reference is already held. The *caller* is
+   * responsible for handling references
+   */
+
+  switch (type) {
+
+  case T_BOOL: {
+    int v = PyObject_IsTrue(value);
+    if (v == -1) {
+      return false;
+    }
+    impl()->writeBool(v);
+    return true;
+  }
+  case T_I08: {
+    int8_t val;
+
+    if (!parse_pyint(value, &val, (std::numeric_limits<int8_t>::min)(),
+                     (std::numeric_limits<int8_t>::max)())) {
+      return false;
+    }
+
+    impl()->writeI8(val);
+    return true;
+  }
+  case T_I16: {
+    int16_t val;
+
+    if (!parse_pyint(value, &val, (std::numeric_limits<int16_t>::min)(),
+                     (std::numeric_limits<int16_t>::max)())) {
+      return false;
+    }
+
+    impl()->writeI16(val);
+    return true;
+  }
+  case T_I32: {
+    int32_t val;
+
+    if (!parse_pyint(value, &val, (std::numeric_limits<int32_t>::min)(),
+                     (std::numeric_limits<int32_t>::max)())) {
+      return false;
+    }
+
+    impl()->writeI32(val);
+    return true;
+  }
+  case T_I64: {
+    int64_t nval = PyLong_AsLongLong(value);
+
+    if (INT_CONV_ERROR_OCCURRED(nval)) {
+      return false;
+    }
+
+    if (!CHECK_RANGE(nval, (std::numeric_limits<int64_t>::min)(),
+                     (std::numeric_limits<int64_t>::max)())) {
+      PyErr_SetString(PyExc_OverflowError, "int out of range");
+      return false;
+    }
+
+    impl()->writeI64(nval);
+    return true;
+  }
+
+  case T_DOUBLE: {
+    double nval = PyFloat_AsDouble(value);
+    if (nval == -1.0 && PyErr_Occurred()) {
+      return false;
+    }
+
+    impl()->writeDouble(nval);
+    return true;
+  }
+
+  case T_STRING: {
+    ScopedPyObject nval;
+
+    if (PyUnicode_Check(value)) {
+      nval.reset(PyUnicode_AsUTF8String(value));
+      if (!nval) {
+        return false;
+      }
+    } else {
+      Py_INCREF(value);
+      nval.reset(value);
+    }
+
+    Py_ssize_t len = PyBytes_Size(nval.get());
+    if (!detail::check_ssize_t_32(len)) {
+      return false;
+    }
+
+    impl()->writeString(nval.get(), static_cast<int32_t>(len));
+    return true;
+  }
+
+  case T_LIST:
+  case T_SET: {
+    SetListTypeArgs parsedargs;
+    if (!parse_set_list_args(&parsedargs, typeargs)) {
+      return false;
+    }
+
+    Py_ssize_t len = PyObject_Length(value);
+    if (!detail::check_ssize_t_32(len)) {
+      return false;
+    }
+
+    if (!impl()->writeListBegin(value, parsedargs, static_cast<int32_t>(len)) || PyErr_Occurred()) {
+      return false;
+    }
+    ScopedPyObject iterator(PyObject_GetIter(value));
+    if (!iterator) {
+      return false;
+    }
+
+    while (PyObject* rawItem = PyIter_Next(iterator.get())) {
+      ScopedPyObject item(rawItem);
+      if (!encodeValue(item.get(), parsedargs.element_type, parsedargs.typeargs)) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  case T_MAP: {
+    Py_ssize_t len = PyDict_Size(value);
+    if (!detail::check_ssize_t_32(len)) {
+      return false;
+    }
+
+    MapTypeArgs parsedargs;
+    if (!parse_map_args(&parsedargs, typeargs)) {
+      return false;
+    }
+
+    if (!impl()->writeMapBegin(value, parsedargs, static_cast<int32_t>(len)) || PyErr_Occurred()) {
+      return false;
+    }
+    Py_ssize_t pos = 0;
+    PyObject* k = NULL;
+    PyObject* v = NULL;
+    // TODO(bmaurer): should support any mapping, not just dicts
+    while (PyDict_Next(value, &pos, &k, &v)) {
+      if (!encodeValue(k, parsedargs.ktag, parsedargs.ktypeargs)
+          || !encodeValue(v, parsedargs.vtag, parsedargs.vtypeargs)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  case T_STRUCT: {
+    StructTypeArgs parsedargs;
+    if (!parse_struct_args(&parsedargs, typeargs)) {
+      return false;
+    }
+
+    Py_ssize_t nspec = PyTuple_Size(parsedargs.spec);
+    if (nspec == -1) {
+      PyErr_SetString(PyExc_TypeError, "spec is not a tuple");
+      return false;
+    }
+
+    detail::WriteStructScope<Impl> scope = detail::writeStructScope(this);
+    if (!scope) {
+      return false;
+    }
+    for (Py_ssize_t i = 0; i < nspec; i++) {
+      PyObject* spec_tuple = PyTuple_GET_ITEM(parsedargs.spec, i);
+      if (spec_tuple == Py_None) {
+        continue;
+      }
+
+      StructItemSpec parsedspec;
+      if (!parse_struct_item_spec(&parsedspec, spec_tuple)) {
+        return false;
+      }
+
+      ScopedPyObject instval(PyObject_GetAttr(value, parsedspec.attrname));
+
+      if (!instval) {
+        return false;
+      }
+
+      if (instval.get() == Py_None) {
+        continue;
+      }
+
+      bool res = impl()->writeField(instval.get(), parsedspec);
+      if (!res) {
+        return false;
+      }
+    }
+    impl()->writeFieldStop();
+    return true;
+  }
+
+  case T_STOP:
+  case T_VOID:
+  case T_UTF16:
+  case T_UTF8:
+  case T_U64:
+  default:
+    PyErr_Format(PyExc_TypeError, "Unexpected TType for encodeValue: %d", type);
+    return false;
+  }
+
+  return true;
+}
+
+template <typename Impl>
+bool ProtocolBase<Impl>::skip(TType type) {
+  switch (type) {
+  case T_BOOL:
+    return impl()->skipBool();
+  case T_I08:
+    return impl()->skipByte();
+  case T_I16:
+    return impl()->skipI16();
+  case T_I32:
+    return impl()->skipI32();
+  case T_I64:
+    return impl()->skipI64();
+  case T_DOUBLE:
+    return impl()->skipDouble();
+
+  case T_STRING: {
+    return impl()->skipString();
+  }
+
+  case T_LIST:
+  case T_SET: {
+    TType etype = T_STOP;
+    int32_t len = impl()->readListBegin(etype);
+    if (len < 0) {
+      return false;
+    }
+    for (int32_t i = 0; i < len; i++) {
+      if (!skip(etype)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  case T_MAP: {
+    TType ktype = T_STOP;
+    TType vtype = T_STOP;
+    int32_t len = impl()->readMapBegin(ktype, vtype);
+    if (len < 0) {
+      return false;
+    }
+    for (int32_t i = 0; i < len; i++) {
+      if (!skip(ktype) || !skip(vtype)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  case T_STRUCT: {
+    detail::ReadStructScope<Impl> scope = detail::readStructScope(this);
+    if (!scope) {
+      return false;
+    }
+    while (true) {
+      TType type = T_STOP;
+      int16_t tag;
+      if (!impl()->readFieldBegin(type, tag)) {
+        return false;
+      }
+      if (type == T_STOP) {
+        return true;
+      }
+      if (!skip(type)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  case T_STOP:
+  case T_VOID:
+  case T_UTF16:
+  case T_UTF8:
+  case T_U64:
+  default:
+    PyErr_Format(PyExc_TypeError, "Unexpected TType for skip: %d", type);
+    return false;
+  }
+
+  return true;
+}
+
+// Returns a new reference.
+template <typename Impl>
+PyObject* ProtocolBase<Impl>::decodeValue(TType type, PyObject* typeargs) {
+  switch (type) {
+
+  case T_BOOL: {
+    bool v = 0;
+    if (!impl()->readBool(v)) {
+      return NULL;
+    }
+    if (v) {
+      Py_RETURN_TRUE;
+    } else {
+      Py_RETURN_FALSE;
+    }
+  }
+  case T_I08: {
+    int8_t v = 0;
+    if (!impl()->readI8(v)) {
+      return NULL;
+    }
+    return PyInt_FromLong(v);
+  }
+  case T_I16: {
+    int16_t v = 0;
+    if (!impl()->readI16(v)) {
+      return NULL;
+    }
+    return PyInt_FromLong(v);
+  }
+  case T_I32: {
+    int32_t v = 0;
+    if (!impl()->readI32(v)) {
+      return NULL;
+    }
+    return PyInt_FromLong(v);
+  }
+
+  case T_I64: {
+    int64_t v = 0;
+    if (!impl()->readI64(v)) {
+      return NULL;
+    }
+    // TODO(dreiss): Find out if we can take this fastpath always when
+    //               sizeof(long) == sizeof(long long).
+    if (CHECK_RANGE(v, LONG_MIN, LONG_MAX)) {
+      return PyInt_FromLong((long)v);
+    }
+    return PyLong_FromLongLong(v);
+  }
+
+  case T_DOUBLE: {
+    double v = 0.0;
+    if (!impl()->readDouble(v)) {
+      return NULL;
+    }
+    return PyFloat_FromDouble(v);
+  }
+
+  case T_STRING: {
+    char* buf = NULL;
+    int len = impl()->readString(&buf);
+    if (len < 0) {
+      return NULL;
+    }
+    if (isUtf8(typeargs)) {
+      return PyUnicode_DecodeUTF8(buf, len, 0);
+    } else {
+      return PyBytes_FromStringAndSize(buf, len);
+    }
+  }
+
+  case T_LIST:
+  case T_SET: {
+    SetListTypeArgs parsedargs;
+    if (!parse_set_list_args(&parsedargs, typeargs)) {
+      return NULL;
+    }
+
+    TType etype = T_STOP;
+    int32_t len = impl()->readListBegin(etype);
+    if (len < 0) {
+      return NULL;
+    }
+    if (len > 0 && !checkType(etype, parsedargs.element_type)) {
+      return NULL;
+    }
+
+    bool use_tuple = type == T_LIST && parsedargs.immutable;
+    ScopedPyObject ret(use_tuple ? PyTuple_New(len) : PyList_New(len));
+    if (!ret) {
+      return NULL;
+    }
+
+    for (int i = 0; i < len; i++) {
+      PyObject* item = decodeValue(etype, parsedargs.typeargs);
+      if (!item) {
+        return NULL;
+      }
+      if (use_tuple) {
+        PyTuple_SET_ITEM(ret.get(), i, item);
+      } else {
+        PyList_SET_ITEM(ret.get(), i, item);
+      }
+    }
+
+    // TODO(dreiss): Consider biting the bullet and making two separate cases
+    //               for list and set, avoiding this post facto conversion.
+    if (type == T_SET) {
+      PyObject* setret;
+      setret = parsedargs.immutable ? PyFrozenSet_New(ret.get()) : PySet_New(ret.get());
+      return setret;
+    }
+    return ret.release();
+  }
+
+  case T_MAP: {
+    MapTypeArgs parsedargs;
+    if (!parse_map_args(&parsedargs, typeargs)) {
+      return NULL;
+    }
+
+    TType ktype = T_STOP;
+    TType vtype = T_STOP;
+    uint32_t len = impl()->readMapBegin(ktype, vtype);
+    if (len > 0 && (!checkType(ktype, parsedargs.ktag) || !checkType(vtype, parsedargs.vtag))) {
+      return NULL;
+    }
+
+    ScopedPyObject ret(PyDict_New());
+    if (!ret) {
+      return NULL;
+    }
+
+    for (uint32_t i = 0; i < len; i++) {
+      ScopedPyObject k(decodeValue(ktype, parsedargs.ktypeargs));
+      if (!k) {
+        return NULL;
+      }
+      ScopedPyObject v(decodeValue(vtype, parsedargs.vtypeargs));
+      if (!v) {
+        return NULL;
+      }
+      if (PyDict_SetItem(ret.get(), k.get(), v.get()) == -1) {
+        return NULL;
+      }
+    }
+
+    if (parsedargs.immutable) {
+      if (!ThriftModule) {
+        ThriftModule = PyImport_ImportModule("thrift.Thrift");
+      }
+      if (!ThriftModule) {
+        return NULL;
+      }
+
+      ScopedPyObject cls(PyObject_GetAttr(ThriftModule, INTERN_STRING(TFrozenDict)));
+      if (!cls) {
+        return NULL;
+      }
+
+      ScopedPyObject arg(PyTuple_New(1));
+      PyTuple_SET_ITEM(arg.get(), 0, ret.release());
+      ret.reset(PyObject_CallObject(cls.get(), arg.get()));
+    }
+
+    return ret.release();
+  }
+
+  case T_STRUCT: {
+    StructTypeArgs parsedargs;
+    if (!parse_struct_args(&parsedargs, typeargs)) {
+      return NULL;
+    }
+    return readStruct(Py_None, parsedargs.klass, parsedargs.spec);
+  }
+
+  case T_STOP:
+  case T_VOID:
+  case T_UTF16:
+  case T_UTF8:
+  case T_U64:
+  default:
+    PyErr_Format(PyExc_TypeError, "Unexpected TType for decodeValue: %d", type);
+    return NULL;
+  }
+}
+
+template <typename Impl>
+PyObject* ProtocolBase<Impl>::readStruct(PyObject* output, PyObject* klass, PyObject* spec_seq) {
+  int spec_seq_len = PyTuple_Size(spec_seq);
+  bool immutable = output == Py_None;
+  ScopedPyObject kwargs;
+  if (spec_seq_len == -1) {
+    return NULL;
+  }
+
+  if (immutable) {
+    kwargs.reset(PyDict_New());
+    if (!kwargs) {
+      PyErr_SetString(PyExc_TypeError, "failed to prepare kwargument storage");
+      return NULL;
+    }
+  }
+
+  detail::ReadStructScope<Impl> scope = detail::readStructScope(this);
+  if (!scope) {
+    return NULL;
+  }
+  while (true) {
+    TType type = T_STOP;
+    int16_t tag;
+    if (!impl()->readFieldBegin(type, tag)) {
+      return NULL;
+    }
+    if (type == T_STOP) {
+      break;
+    }
+    if (tag < 0 || tag >= spec_seq_len) {
+      if (!skip(type)) {
+        PyErr_SetString(PyExc_TypeError, "Error while skipping unknown field");
+        return NULL;
+      }
+      continue;
+    }
+
+    PyObject* item_spec = PyTuple_GET_ITEM(spec_seq, tag);
+    if (item_spec == Py_None) {
+      if (!skip(type)) {
+        PyErr_SetString(PyExc_TypeError, "Error while skipping unknown field");
+        return NULL;
+      }
+      continue;
+    }
+    StructItemSpec parsedspec;
+    if (!parse_struct_item_spec(&parsedspec, item_spec)) {
+      return NULL;
+    }
+    if (parsedspec.type != type) {
+      if (!skip(type)) {
+        PyErr_Format(PyExc_TypeError, "struct field had wrong type: expected %d but got %d",
+                     parsedspec.type, type);
+        return NULL;
+      }
+      continue;
+    }
+
+    ScopedPyObject fieldval(decodeValue(parsedspec.type, parsedspec.typeargs));
+    if (!fieldval) {
+      return NULL;
+    }
+
+    if ((immutable && PyDict_SetItem(kwargs.get(), parsedspec.attrname, fieldval.get()) == -1)
+        || (!immutable && PyObject_SetAttr(output, parsedspec.attrname, fieldval.get()) == -1)) {
+      return NULL;
+    }
+  }
+  if (immutable) {
+    ScopedPyObject args(PyTuple_New(0));
+    if (!args) {
+      PyErr_SetString(PyExc_TypeError, "failed to prepare argument storage");
+      return NULL;
+    }
+    return PyObject_Call(klass, args.get(), kwargs.get());
+  }
+  Py_INCREF(output);
+  return output;
+}
+}
+}
+}
+#endif // THRIFT_PY_PROTOCOL_H
diff --git a/lib/py/src/ext/types.cpp b/lib/py/src/ext/types.cpp
new file mode 100644
index 0000000..68443fb
--- /dev/null
+++ b/lib/py/src/ext/types.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#include "ext/types.h"
+#include "ext/protocol.h"
+
+namespace apache {
+namespace thrift {
+namespace py {
+
+PyObject* ThriftModule = NULL;
+
+#if PY_MAJOR_VERSION < 3
+char refill_signature[] = {'s', '#', 'i'};
+#else
+const char* refill_signature = "y#i";
+#endif
+
+bool parse_struct_item_spec(StructItemSpec* dest, PyObject* spec_tuple) {
+  // i'd like to use ParseArgs here, but it seems to be a bottleneck.
+  if (PyTuple_Size(spec_tuple) != 5) {
+    PyErr_Format(PyExc_TypeError, "expecting 5 arguments for spec tuple but got %d",
+                 static_cast<int>(PyTuple_Size(spec_tuple)));
+    return false;
+  }
+
+  dest->tag = static_cast<TType>(PyInt_AsLong(PyTuple_GET_ITEM(spec_tuple, 0)));
+  if (INT_CONV_ERROR_OCCURRED(dest->tag)) {
+    return false;
+  }
+
+  dest->type = static_cast<TType>(PyInt_AsLong(PyTuple_GET_ITEM(spec_tuple, 1)));
+  if (INT_CONV_ERROR_OCCURRED(dest->type)) {
+    return false;
+  }
+
+  dest->attrname = PyTuple_GET_ITEM(spec_tuple, 2);
+  dest->typeargs = PyTuple_GET_ITEM(spec_tuple, 3);
+  dest->defval = PyTuple_GET_ITEM(spec_tuple, 4);
+  return true;
+}
+
+bool parse_set_list_args(SetListTypeArgs* dest, PyObject* typeargs) {
+  if (PyTuple_Size(typeargs) != 3) {
+    PyErr_SetString(PyExc_TypeError, "expecting tuple of size 3 for list/set type args");
+    return false;
+  }
+
+  dest->element_type = static_cast<TType>(PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 0)));
+  if (INT_CONV_ERROR_OCCURRED(dest->element_type)) {
+    return false;
+  }
+
+  dest->typeargs = PyTuple_GET_ITEM(typeargs, 1);
+
+  dest->immutable = Py_True == PyTuple_GET_ITEM(typeargs, 2);
+
+  return true;
+}
+
+bool parse_map_args(MapTypeArgs* dest, PyObject* typeargs) {
+  if (PyTuple_Size(typeargs) != 5) {
+    PyErr_SetString(PyExc_TypeError, "expecting 5 arguments for typeargs to map");
+    return false;
+  }
+
+  dest->ktag = static_cast<TType>(PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 0)));
+  if (INT_CONV_ERROR_OCCURRED(dest->ktag)) {
+    return false;
+  }
+
+  dest->vtag = static_cast<TType>(PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 2)));
+  if (INT_CONV_ERROR_OCCURRED(dest->vtag)) {
+    return false;
+  }
+
+  dest->ktypeargs = PyTuple_GET_ITEM(typeargs, 1);
+  dest->vtypeargs = PyTuple_GET_ITEM(typeargs, 3);
+  dest->immutable = Py_True == PyTuple_GET_ITEM(typeargs, 4);
+
+  return true;
+}
+
+bool parse_struct_args(StructTypeArgs* dest, PyObject* typeargs) {
+  if (PyList_Size(typeargs) != 2) {
+    PyErr_SetString(PyExc_TypeError, "expecting list of size 2 for struct args");
+    return false;
+  }
+
+  dest->klass = PyList_GET_ITEM(typeargs, 0);
+  dest->spec = PyList_GET_ITEM(typeargs, 1);
+
+  return true;
+}
+}
+}
+}
diff --git a/lib/py/src/ext/types.h b/lib/py/src/ext/types.h
new file mode 100644
index 0000000..5cd8dda
--- /dev/null
+++ b/lib/py/src/ext/types.h
@@ -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.
+ */
+
+#ifndef THRIFT_PY_TYPES_H
+#define THRIFT_PY_TYPES_H
+
+#include <Python.h>
+
+#ifdef _MSC_VER
+#define __STDC_FORMAT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+#include <stdint.h>
+
+#if PY_MAJOR_VERSION >= 3
+
+#include <vector>
+
+// TODO: better macros
+#define PyInt_AsLong(v) PyLong_AsLong(v)
+#define PyInt_FromLong(v) PyLong_FromLong(v)
+
+#define PyString_InternFromString(v) PyUnicode_InternFromString(v)
+
+#endif
+
+#define INTERN_STRING(value) _intern_##value
+
+#define INT_CONV_ERROR_OCCURRED(v) (((v) == -1) && PyErr_Occurred())
+
+extern "C" {
+extern PyObject* INTERN_STRING(TFrozenDict);
+extern PyObject* INTERN_STRING(cstringio_buf);
+extern PyObject* INTERN_STRING(cstringio_refill);
+}
+
+namespace apache {
+namespace thrift {
+namespace py {
+
+extern PyObject* ThriftModule;
+
+// Stolen out of TProtocol.h.
+// It would be a huge pain to have both get this from one place.
+enum TType {
+  T_INVALID = -1,
+  T_STOP = 0,
+  T_VOID = 1,
+  T_BOOL = 2,
+  T_BYTE = 3,
+  T_I08 = 3,
+  T_I16 = 6,
+  T_I32 = 8,
+  T_U64 = 9,
+  T_I64 = 10,
+  T_DOUBLE = 4,
+  T_STRING = 11,
+  T_UTF7 = 11,
+  T_STRUCT = 12,
+  T_MAP = 13,
+  T_SET = 14,
+  T_LIST = 15,
+  T_UTF8 = 16,
+  T_UTF16 = 17
+};
+
+// replace with unique_ptr when we're OK with C++11
+class ScopedPyObject {
+public:
+  ScopedPyObject() : obj_(NULL) {}
+  explicit ScopedPyObject(PyObject* py_object) : obj_(py_object) {}
+  ~ScopedPyObject() {
+    if (obj_)
+      Py_DECREF(obj_);
+  }
+  PyObject* get() throw() { return obj_; }
+  operator bool() { return obj_; }
+  void reset(PyObject* py_object) throw() {
+    if (obj_)
+      Py_DECREF(obj_);
+    obj_ = py_object;
+  }
+  PyObject* release() throw() {
+    PyObject* tmp = obj_;
+    obj_ = NULL;
+    return tmp;
+  }
+  void swap(ScopedPyObject& other) throw() {
+    ScopedPyObject tmp(other.release());
+    other.reset(release());
+    reset(tmp.release());
+  }
+
+private:
+  ScopedPyObject(const ScopedPyObject&) {}
+  ScopedPyObject& operator=(const ScopedPyObject&) { return *this; }
+
+  PyObject* obj_;
+};
+
+/**
+ * A cache of the two key attributes of a CReadableTransport,
+ * so we don't have to keep calling PyObject_GetAttr.
+ */
+struct DecodeBuffer {
+  ScopedPyObject stringiobuf;
+  ScopedPyObject refill_callable;
+};
+
+#if PY_MAJOR_VERSION < 3
+extern char refill_signature[3];
+typedef PyObject EncodeBuffer;
+#else
+extern const char* refill_signature;
+struct EncodeBuffer {
+  std::vector<char> buf;
+  size_t pos;
+};
+#endif
+
+/**
+ * A cache of the spec_args for a set or list,
+ * so we don't have to keep calling PyTuple_GET_ITEM.
+ */
+struct SetListTypeArgs {
+  TType element_type;
+  PyObject* typeargs;
+  bool immutable;
+};
+
+/**
+ * A cache of the spec_args for a map,
+ * so we don't have to keep calling PyTuple_GET_ITEM.
+ */
+struct MapTypeArgs {
+  TType ktag;
+  TType vtag;
+  PyObject* ktypeargs;
+  PyObject* vtypeargs;
+  bool immutable;
+};
+
+/**
+ * A cache of the spec_args for a struct,
+ * so we don't have to keep calling PyTuple_GET_ITEM.
+ */
+struct StructTypeArgs {
+  PyObject* klass;
+  PyObject* spec;
+  bool immutable;
+};
+
+/**
+ * A cache of the item spec from a struct specification,
+ * so we don't have to keep calling PyTuple_GET_ITEM.
+ */
+struct StructItemSpec {
+  int tag;
+  TType type;
+  PyObject* attrname;
+  PyObject* typeargs;
+  PyObject* defval;
+};
+
+bool parse_set_list_args(SetListTypeArgs* dest, PyObject* typeargs);
+
+bool parse_map_args(MapTypeArgs* dest, PyObject* typeargs);
+
+bool parse_struct_args(StructTypeArgs* dest, PyObject* typeargs);
+
+bool parse_struct_item_spec(StructItemSpec* dest, PyObject* spec_tuple);
+}
+}
+}
+
+#endif // THRIFT_PY_TYPES_H
diff --git a/lib/py/src/protocol/TBase.py b/lib/py/src/protocol/TBase.py
index 6cbd5f3..9ae1b11 100644
--- a/lib/py/src/protocol/TBase.py
+++ b/lib/py/src/protocol/TBase.py
@@ -17,65 +17,66 @@
 # under the License.
 #
 
-from thrift.Thrift import *
-from thrift.protocol import TBinaryProtocol
 from thrift.transport import TTransport
 
-try:
-  from thrift.protocol import fastbinary
-except:
-  fastbinary = None
-
 
 class TBase(object):
-  __slots__ = []
+    __slots__ = ()
 
-  def __repr__(self):
-    L = ['%s=%r' % (key, getattr(self, key))
-              for key in self.__slots__]
-    return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
+    def __repr__(self):
+        L = ['%s=%r' % (key, getattr(self, key)) for key in self.__slots__]
+        return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
 
-  def __eq__(self, other):
-    if not isinstance(other, self.__class__):
-      return False
-    for attr in self.__slots__:
-      my_val = getattr(self, attr)
-      other_val = getattr(other, attr)
-      if my_val != other_val:
-        return False
-    return True
+    def __eq__(self, other):
+        if not isinstance(other, self.__class__):
+            return False
+        for attr in self.__slots__:
+            my_val = getattr(self, attr)
+            other_val = getattr(other, attr)
+            if my_val != other_val:
+                return False
+        return True
 
-  def __ne__(self, other):
-    return not (self == other)
+    def __ne__(self, other):
+        return not (self == other)
 
-  def read(self, iprot):
-    if (iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and
-        isinstance(iprot.trans, TTransport.CReadableTransport) and
-        self.thrift_spec is not None and
-        fastbinary is not None):
-      fastbinary.decode_binary(self,
-                               iprot.trans,
-                               (self.__class__, self.thrift_spec))
-      return
-    iprot.readStruct(self, self.thrift_spec)
+    def read(self, iprot):
+        if (iprot._fast_decode is not None and
+                isinstance(iprot.trans, TTransport.CReadableTransport) and
+                self.thrift_spec is not None):
+            iprot._fast_decode(self, iprot, [self.__class__, self.thrift_spec])
+        else:
+            iprot.readStruct(self, self.thrift_spec)
 
-  def write(self, oprot):
-    if (oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and
-        self.thrift_spec is not None and
-        fastbinary is not None):
-      oprot.trans.write(
-        fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
-      return
-    oprot.writeStruct(self, self.thrift_spec)
+    def write(self, oprot):
+        if (oprot._fast_encode is not None and self.thrift_spec is not None):
+            oprot.trans.write(
+                oprot._fast_encode(self, [self.__class__, self.thrift_spec]))
+        else:
+            oprot.writeStruct(self, self.thrift_spec)
 
 
-class TExceptionBase(Exception):
-  # old style class so python2.4 can raise exceptions derived from this
-  #  This can't inherit from TBase because of that limitation.
-  __slots__ = []
+class TExceptionBase(TBase, Exception):
+    pass
 
-  __repr__ = TBase.__repr__.im_func
-  __eq__ = TBase.__eq__.im_func
-  __ne__ = TBase.__ne__.im_func
-  read = TBase.read.im_func
-  write = TBase.write.im_func
+
+class TFrozenBase(TBase):
+    def __setitem__(self, *args):
+        raise TypeError("Can't modify frozen struct")
+
+    def __delitem__(self, *args):
+        raise TypeError("Can't modify frozen struct")
+
+    def __hash__(self, *args):
+        return hash(self.__class__) ^ hash(self.__slots__)
+
+    @classmethod
+    def read(cls, iprot):
+        if (iprot._fast_decode is not None and
+                isinstance(iprot.trans, TTransport.CReadableTransport) and
+                cls.thrift_spec is not None):
+            self = cls()
+            return iprot._fast_decode(None, iprot,
+                                      [self.__class__, self.thrift_spec])
+        else:
+            return iprot.readStruct(cls, cls.thrift_spec, True)
diff --git a/lib/py/src/protocol/TBinaryProtocol.py b/lib/py/src/protocol/TBinaryProtocol.py
index 6fdd08c..f6be772 100644
--- a/lib/py/src/protocol/TBinaryProtocol.py
+++ b/lib/py/src/protocol/TBinaryProtocol.py
@@ -17,244 +17,285 @@
 # under the License.
 #
 
-from TProtocol import *
+from .TProtocol import TType, TProtocolBase, TProtocolException
 from struct import pack, unpack
 
 
 class TBinaryProtocol(TProtocolBase):
-  """Binary implementation of the Thrift protocol driver."""
+    """Binary implementation of the Thrift protocol driver."""
 
-  # NastyHaxx. Python 2.4+ on 32-bit machines forces hex constants to be
-  # positive, converting this into a long. If we hardcode the int value
-  # instead it'll stay in 32 bit-land.
+    # NastyHaxx. Python 2.4+ on 32-bit machines forces hex constants to be
+    # positive, converting this into a long. If we hardcode the int value
+    # instead it'll stay in 32 bit-land.
 
-  # VERSION_MASK = 0xffff0000
-  VERSION_MASK = -65536
+    # VERSION_MASK = 0xffff0000
+    VERSION_MASK = -65536
 
-  # VERSION_1 = 0x80010000
-  VERSION_1 = -2147418112
+    # VERSION_1 = 0x80010000
+    VERSION_1 = -2147418112
 
-  TYPE_MASK = 0x000000ff
+    TYPE_MASK = 0x000000ff
 
-  def __init__(self, trans, strictRead=False, strictWrite=True):
-    TProtocolBase.__init__(self, trans)
-    self.strictRead = strictRead
-    self.strictWrite = strictWrite
+    def __init__(self, trans, strictRead=False, strictWrite=True, **kwargs):
+        TProtocolBase.__init__(self, trans)
+        self.strictRead = strictRead
+        self.strictWrite = strictWrite
+        self.string_length_limit = kwargs.get('string_length_limit', None)
+        self.container_length_limit = kwargs.get('container_length_limit', None)
 
-  def writeMessageBegin(self, name, type, seqid):
-    if self.strictWrite:
-      self.writeI32(TBinaryProtocol.VERSION_1 | type)
-      self.writeString(name)
-      self.writeI32(seqid)
-    else:
-      self.writeString(name)
-      self.writeByte(type)
-      self.writeI32(seqid)
+    def _check_string_length(self, length):
+        self._check_length(self.string_length_limit, length)
 
-  def writeMessageEnd(self):
-    pass
+    def _check_container_length(self, length):
+        self._check_length(self.container_length_limit, length)
 
-  def writeStructBegin(self, name):
-    pass
+    def writeMessageBegin(self, name, type, seqid):
+        if self.strictWrite:
+            self.writeI32(TBinaryProtocol.VERSION_1 | type)
+            self.writeString(name)
+            self.writeI32(seqid)
+        else:
+            self.writeString(name)
+            self.writeByte(type)
+            self.writeI32(seqid)
 
-  def writeStructEnd(self):
-    pass
+    def writeMessageEnd(self):
+        pass
 
-  def writeFieldBegin(self, name, type, id):
-    self.writeByte(type)
-    self.writeI16(id)
+    def writeStructBegin(self, name):
+        pass
 
-  def writeFieldEnd(self):
-    pass
+    def writeStructEnd(self):
+        pass
 
-  def writeFieldStop(self):
-    self.writeByte(TType.STOP)
+    def writeFieldBegin(self, name, type, id):
+        self.writeByte(type)
+        self.writeI16(id)
 
-  def writeMapBegin(self, ktype, vtype, size):
-    self.writeByte(ktype)
-    self.writeByte(vtype)
-    self.writeI32(size)
+    def writeFieldEnd(self):
+        pass
 
-  def writeMapEnd(self):
-    pass
+    def writeFieldStop(self):
+        self.writeByte(TType.STOP)
 
-  def writeListBegin(self, etype, size):
-    self.writeByte(etype)
-    self.writeI32(size)
+    def writeMapBegin(self, ktype, vtype, size):
+        self.writeByte(ktype)
+        self.writeByte(vtype)
+        self.writeI32(size)
 
-  def writeListEnd(self):
-    pass
+    def writeMapEnd(self):
+        pass
 
-  def writeSetBegin(self, etype, size):
-    self.writeByte(etype)
-    self.writeI32(size)
+    def writeListBegin(self, etype, size):
+        self.writeByte(etype)
+        self.writeI32(size)
 
-  def writeSetEnd(self):
-    pass
+    def writeListEnd(self):
+        pass
 
-  def writeBool(self, bool):
-    if bool:
-      self.writeByte(1)
-    else:
-      self.writeByte(0)
+    def writeSetBegin(self, etype, size):
+        self.writeByte(etype)
+        self.writeI32(size)
 
-  def writeByte(self, byte):
-    buff = pack("!b", byte)
-    self.trans.write(buff)
+    def writeSetEnd(self):
+        pass
 
-  def writeI16(self, i16):
-    buff = pack("!h", i16)
-    self.trans.write(buff)
+    def writeBool(self, bool):
+        if bool:
+            self.writeByte(1)
+        else:
+            self.writeByte(0)
 
-  def writeI32(self, i32):
-    buff = pack("!i", i32)
-    self.trans.write(buff)
+    def writeByte(self, byte):
+        buff = pack("!b", byte)
+        self.trans.write(buff)
 
-  def writeI64(self, i64):
-    buff = pack("!q", i64)
-    self.trans.write(buff)
+    def writeI16(self, i16):
+        buff = pack("!h", i16)
+        self.trans.write(buff)
 
-  def writeDouble(self, dub):
-    buff = pack("!d", dub)
-    self.trans.write(buff)
+    def writeI32(self, i32):
+        buff = pack("!i", i32)
+        self.trans.write(buff)
 
-  def writeString(self, str):
-    self.writeI32(len(str))
-    self.trans.write(str)
+    def writeI64(self, i64):
+        buff = pack("!q", i64)
+        self.trans.write(buff)
 
-  def readMessageBegin(self):
-    sz = self.readI32()
-    if sz < 0:
-      version = sz & TBinaryProtocol.VERSION_MASK
-      if version != TBinaryProtocol.VERSION_1:
-        raise TProtocolException(
-          type=TProtocolException.BAD_VERSION,
-          message='Bad version in readMessageBegin: %d' % (sz))
-      type = sz & TBinaryProtocol.TYPE_MASK
-      name = self.readString()
-      seqid = self.readI32()
-    else:
-      if self.strictRead:
-        raise TProtocolException(type=TProtocolException.BAD_VERSION,
-                                 message='No protocol version header')
-      name = self.trans.readAll(sz)
-      type = self.readByte()
-      seqid = self.readI32()
-    return (name, type, seqid)
+    def writeDouble(self, dub):
+        buff = pack("!d", dub)
+        self.trans.write(buff)
 
-  def readMessageEnd(self):
-    pass
+    def writeBinary(self, str):
+        self.writeI32(len(str))
+        self.trans.write(str)
 
-  def readStructBegin(self):
-    pass
+    def readMessageBegin(self):
+        sz = self.readI32()
+        if sz < 0:
+            version = sz & TBinaryProtocol.VERSION_MASK
+            if version != TBinaryProtocol.VERSION_1:
+                raise TProtocolException(
+                    type=TProtocolException.BAD_VERSION,
+                    message='Bad version in readMessageBegin: %d' % (sz))
+            type = sz & TBinaryProtocol.TYPE_MASK
+            name = self.readString()
+            seqid = self.readI32()
+        else:
+            if self.strictRead:
+                raise TProtocolException(type=TProtocolException.BAD_VERSION,
+                                         message='No protocol version header')
+            name = self.trans.readAll(sz)
+            type = self.readByte()
+            seqid = self.readI32()
+        return (name, type, seqid)
 
-  def readStructEnd(self):
-    pass
+    def readMessageEnd(self):
+        pass
 
-  def readFieldBegin(self):
-    type = self.readByte()
-    if type == TType.STOP:
-      return (None, type, 0)
-    id = self.readI16()
-    return (None, type, id)
+    def readStructBegin(self):
+        pass
 
-  def readFieldEnd(self):
-    pass
+    def readStructEnd(self):
+        pass
 
-  def readMapBegin(self):
-    ktype = self.readByte()
-    vtype = self.readByte()
-    size = self.readI32()
-    return (ktype, vtype, size)
+    def readFieldBegin(self):
+        type = self.readByte()
+        if type == TType.STOP:
+            return (None, type, 0)
+        id = self.readI16()
+        return (None, type, id)
 
-  def readMapEnd(self):
-    pass
+    def readFieldEnd(self):
+        pass
 
-  def readListBegin(self):
-    etype = self.readByte()
-    size = self.readI32()
-    return (etype, size)
+    def readMapBegin(self):
+        ktype = self.readByte()
+        vtype = self.readByte()
+        size = self.readI32()
+        self._check_container_length(size)
+        return (ktype, vtype, size)
 
-  def readListEnd(self):
-    pass
+    def readMapEnd(self):
+        pass
 
-  def readSetBegin(self):
-    etype = self.readByte()
-    size = self.readI32()
-    return (etype, size)
+    def readListBegin(self):
+        etype = self.readByte()
+        size = self.readI32()
+        self._check_container_length(size)
+        return (etype, size)
 
-  def readSetEnd(self):
-    pass
+    def readListEnd(self):
+        pass
 
-  def readBool(self):
-    byte = self.readByte()
-    if byte == 0:
-      return False
-    return True
+    def readSetBegin(self):
+        etype = self.readByte()
+        size = self.readI32()
+        self._check_container_length(size)
+        return (etype, size)
 
-  def readByte(self):
-    buff = self.trans.readAll(1)
-    val, = unpack('!b', buff)
-    return val
+    def readSetEnd(self):
+        pass
 
-  def readI16(self):
-    buff = self.trans.readAll(2)
-    val, = unpack('!h', buff)
-    return val
+    def readBool(self):
+        byte = self.readByte()
+        if byte == 0:
+            return False
+        return True
 
-  def readI32(self):
-    buff = self.trans.readAll(4)
-    val, = unpack('!i', buff)
-    return val
+    def readByte(self):
+        buff = self.trans.readAll(1)
+        val, = unpack('!b', buff)
+        return val
 
-  def readI64(self):
-    buff = self.trans.readAll(8)
-    val, = unpack('!q', buff)
-    return val
+    def readI16(self):
+        buff = self.trans.readAll(2)
+        val, = unpack('!h', buff)
+        return val
 
-  def readDouble(self):
-    buff = self.trans.readAll(8)
-    val, = unpack('!d', buff)
-    return val
+    def readI32(self):
+        buff = self.trans.readAll(4)
+        val, = unpack('!i', buff)
+        return val
 
-  def readString(self):
-    len = self.readI32()
-    str = self.trans.readAll(len)
-    return str
+    def readI64(self):
+        buff = self.trans.readAll(8)
+        val, = unpack('!q', buff)
+        return val
+
+    def readDouble(self):
+        buff = self.trans.readAll(8)
+        val, = unpack('!d', buff)
+        return val
+
+    def readBinary(self):
+        size = self.readI32()
+        self._check_string_length(size)
+        s = self.trans.readAll(size)
+        return s
 
 
-class TBinaryProtocolFactory:
-  def __init__(self, strictRead=False, strictWrite=True):
-    self.strictRead = strictRead
-    self.strictWrite = strictWrite
+class TBinaryProtocolFactory(object):
+    def __init__(self, strictRead=False, strictWrite=True, **kwargs):
+        self.strictRead = strictRead
+        self.strictWrite = strictWrite
+        self.string_length_limit = kwargs.get('string_length_limit', None)
+        self.container_length_limit = kwargs.get('container_length_limit', None)
 
-  def getProtocol(self, trans):
-    prot = TBinaryProtocol(trans, self.strictRead, self.strictWrite)
-    return prot
+    def getProtocol(self, trans):
+        prot = TBinaryProtocol(trans, self.strictRead, self.strictWrite,
+                               string_length_limit=self.string_length_limit,
+                               container_length_limit=self.container_length_limit)
+        return prot
 
 
 class TBinaryProtocolAccelerated(TBinaryProtocol):
-  """C-Accelerated version of TBinaryProtocol.
+    """C-Accelerated version of TBinaryProtocol.
 
-  This class does not override any of TBinaryProtocol's methods,
-  but the generated code recognizes it directly and will call into
-  our C module to do the encoding, bypassing this object entirely.
-  We inherit from TBinaryProtocol so that the normal TBinaryProtocol
-  encoding can happen if the fastbinary module doesn't work for some
-  reason.  (TODO(dreiss): Make this happen sanely in more cases.)
+    This class does not override any of TBinaryProtocol's methods,
+    but the generated code recognizes it directly and will call into
+    our C module to do the encoding, bypassing this object entirely.
+    We inherit from TBinaryProtocol so that the normal TBinaryProtocol
+    encoding can happen if the fastbinary module doesn't work for some
+    reason.  (TODO(dreiss): Make this happen sanely in more cases.)
+    To disable this behavior, pass fallback=False constructor argument.
 
-  In order to take advantage of the C module, just use
-  TBinaryProtocolAccelerated instead of TBinaryProtocol.
+    In order to take advantage of the C module, just use
+    TBinaryProtocolAccelerated instead of TBinaryProtocol.
 
-  NOTE:  This code was contributed by an external developer.
-         The internal Thrift team has reviewed and tested it,
-         but we cannot guarantee that it is production-ready.
-         Please feel free to report bugs and/or success stories
-         to the public mailing list.
-  """
-  pass
+    NOTE:  This code was contributed by an external developer.
+           The internal Thrift team has reviewed and tested it,
+           but we cannot guarantee that it is production-ready.
+           Please feel free to report bugs and/or success stories
+           to the public mailing list.
+    """
+    pass
+
+    def __init__(self, *args, **kwargs):
+        fallback = kwargs.pop('fallback', True)
+        super(TBinaryProtocolAccelerated, self).__init__(*args, **kwargs)
+        try:
+            from thrift.protocol import fastbinary
+        except ImportError:
+            if not fallback:
+                raise
+        else:
+            self._fast_decode = fastbinary.decode_binary
+            self._fast_encode = fastbinary.encode_binary
 
 
-class TBinaryProtocolAcceleratedFactory:
-  def getProtocol(self, trans):
-    return TBinaryProtocolAccelerated(trans)
+class TBinaryProtocolAcceleratedFactory(object):
+    def __init__(self,
+                 string_length_limit=None,
+                 container_length_limit=None,
+                 fallback=True):
+        self.string_length_limit = string_length_limit
+        self.container_length_limit = container_length_limit
+        self._fallback = fallback
+
+    def getProtocol(self, trans):
+        return TBinaryProtocolAccelerated(
+            trans,
+            string_length_limit=self.string_length_limit,
+            container_length_limit=self.container_length_limit,
+            fallback=self._fallback)
diff --git a/lib/py/src/protocol/TCompactProtocol.py b/lib/py/src/protocol/TCompactProtocol.py
index cdec607..e485cff 100644
--- a/lib/py/src/protocol/TCompactProtocol.py
+++ b/lib/py/src/protocol/TCompactProtocol.py
@@ -17,9 +17,11 @@
 # under the License.
 #
 
-from TProtocol import *
+from .TProtocol import TType, TProtocolBase, TProtocolException, checkIntegerLimits
 from struct import pack, unpack
 
+from ..compat import binary_to_str, str_to_binary
+
 __all__ = ['TCompactProtocol', 'TCompactProtocolFactory']
 
 CLEAR = 0
@@ -34,370 +36,440 @@
 
 
 def make_helper(v_from, container):
-  def helper(func):
-    def nested(self, *args, **kwargs):
-      assert self.state in (v_from, container), (self.state, v_from, container)
-      return func(self, *args, **kwargs)
-    return nested
-  return helper
+    def helper(func):
+        def nested(self, *args, **kwargs):
+            assert self.state in (v_from, container), (self.state, v_from, container)
+            return func(self, *args, **kwargs)
+        return nested
+    return helper
+
+
 writer = make_helper(VALUE_WRITE, CONTAINER_WRITE)
 reader = make_helper(VALUE_READ, CONTAINER_READ)
 
 
 def makeZigZag(n, bits):
-  return (n << 1) ^ (n >> (bits - 1))
+    checkIntegerLimits(n, bits)
+    return (n << 1) ^ (n >> (bits - 1))
 
 
 def fromZigZag(n):
-  return (n >> 1) ^ -(n & 1)
+    return (n >> 1) ^ -(n & 1)
 
 
 def writeVarint(trans, n):
-  out = []
-  while True:
-    if n & ~0x7f == 0:
-      out.append(n)
-      break
-    else:
-      out.append((n & 0xff) | 0x80)
-      n = n >> 7
-  trans.write(''.join(map(chr, out)))
+    out = bytearray()
+    while True:
+        if n & ~0x7f == 0:
+            out.append(n)
+            break
+        else:
+            out.append((n & 0xff) | 0x80)
+            n = n >> 7
+    trans.write(bytes(out))
 
 
 def readVarint(trans):
-  result = 0
-  shift = 0
-  while True:
-    x = trans.readAll(1)
-    byte = ord(x)
-    result |= (byte & 0x7f) << shift
-    if byte >> 7 == 0:
-      return result
-    shift += 7
+    result = 0
+    shift = 0
+    while True:
+        x = trans.readAll(1)
+        byte = ord(x)
+        result |= (byte & 0x7f) << shift
+        if byte >> 7 == 0:
+            return result
+        shift += 7
 
 
-class CompactType:
-  STOP = 0x00
-  TRUE = 0x01
-  FALSE = 0x02
-  BYTE = 0x03
-  I16 = 0x04
-  I32 = 0x05
-  I64 = 0x06
-  DOUBLE = 0x07
-  BINARY = 0x08
-  LIST = 0x09
-  SET = 0x0A
-  MAP = 0x0B
-  STRUCT = 0x0C
+class CompactType(object):
+    STOP = 0x00
+    TRUE = 0x01
+    FALSE = 0x02
+    BYTE = 0x03
+    I16 = 0x04
+    I32 = 0x05
+    I64 = 0x06
+    DOUBLE = 0x07
+    BINARY = 0x08
+    LIST = 0x09
+    SET = 0x0A
+    MAP = 0x0B
+    STRUCT = 0x0C
 
-CTYPES = {TType.STOP: CompactType.STOP,
-          TType.BOOL: CompactType.TRUE,  # used for collection
-          TType.BYTE: CompactType.BYTE,
-          TType.I16: CompactType.I16,
-          TType.I32: CompactType.I32,
-          TType.I64: CompactType.I64,
-          TType.DOUBLE: CompactType.DOUBLE,
-          TType.STRING: CompactType.BINARY,
-          TType.STRUCT: CompactType.STRUCT,
-          TType.LIST: CompactType.LIST,
-          TType.SET: CompactType.SET,
-          TType.MAP: CompactType.MAP
-          }
+
+CTYPES = {
+    TType.STOP: CompactType.STOP,
+    TType.BOOL: CompactType.TRUE,  # used for collection
+    TType.BYTE: CompactType.BYTE,
+    TType.I16: CompactType.I16,
+    TType.I32: CompactType.I32,
+    TType.I64: CompactType.I64,
+    TType.DOUBLE: CompactType.DOUBLE,
+    TType.STRING: CompactType.BINARY,
+    TType.STRUCT: CompactType.STRUCT,
+    TType.LIST: CompactType.LIST,
+    TType.SET: CompactType.SET,
+    TType.MAP: CompactType.MAP,
+}
 
 TTYPES = {}
 for k, v in CTYPES.items():
-  TTYPES[v] = k
+    TTYPES[v] = k
 TTYPES[CompactType.FALSE] = TType.BOOL
 del k
 del v
 
 
 class TCompactProtocol(TProtocolBase):
-  """Compact implementation of the Thrift protocol driver."""
+    """Compact implementation of the Thrift protocol driver."""
 
-  PROTOCOL_ID = 0x82
-  VERSION = 1
-  VERSION_MASK = 0x1f
-  TYPE_MASK = 0xe0
-  TYPE_SHIFT_AMOUNT = 5
+    PROTOCOL_ID = 0x82
+    VERSION = 1
+    VERSION_MASK = 0x1f
+    TYPE_MASK = 0xe0
+    TYPE_BITS = 0x07
+    TYPE_SHIFT_AMOUNT = 5
 
-  def __init__(self, trans):
-    TProtocolBase.__init__(self, trans)
-    self.state = CLEAR
-    self.__last_fid = 0
-    self.__bool_fid = None
-    self.__bool_value = None
-    self.__structs = []
-    self.__containers = []
+    def __init__(self, trans,
+                 string_length_limit=None,
+                 container_length_limit=None):
+        TProtocolBase.__init__(self, trans)
+        self.state = CLEAR
+        self.__last_fid = 0
+        self.__bool_fid = None
+        self.__bool_value = None
+        self.__structs = []
+        self.__containers = []
+        self.string_length_limit = string_length_limit
+        self.container_length_limit = container_length_limit
 
-  def __writeVarint(self, n):
-    writeVarint(self.trans, n)
+    def _check_string_length(self, length):
+        self._check_length(self.string_length_limit, length)
 
-  def writeMessageBegin(self, name, type, seqid):
-    assert self.state == CLEAR
-    self.__writeUByte(self.PROTOCOL_ID)
-    self.__writeUByte(self.VERSION | (type << self.TYPE_SHIFT_AMOUNT))
-    self.__writeVarint(seqid)
-    self.__writeString(name)
-    self.state = VALUE_WRITE
+    def _check_container_length(self, length):
+        self._check_length(self.container_length_limit, length)
 
-  def writeMessageEnd(self):
-    assert self.state == VALUE_WRITE
-    self.state = CLEAR
+    def __writeVarint(self, n):
+        writeVarint(self.trans, n)
 
-  def writeStructBegin(self, name):
-    assert self.state in (CLEAR, CONTAINER_WRITE, VALUE_WRITE), self.state
-    self.__structs.append((self.state, self.__last_fid))
-    self.state = FIELD_WRITE
-    self.__last_fid = 0
+    def writeMessageBegin(self, name, type, seqid):
+        assert self.state == CLEAR
+        self.__writeUByte(self.PROTOCOL_ID)
+        self.__writeUByte(self.VERSION | (type << self.TYPE_SHIFT_AMOUNT))
+        self.__writeVarint(seqid)
+        self.__writeBinary(str_to_binary(name))
+        self.state = VALUE_WRITE
 
-  def writeStructEnd(self):
-    assert self.state == FIELD_WRITE
-    self.state, self.__last_fid = self.__structs.pop()
+    def writeMessageEnd(self):
+        assert self.state == VALUE_WRITE
+        self.state = CLEAR
 
-  def writeFieldStop(self):
-    self.__writeByte(0)
+    def writeStructBegin(self, name):
+        assert self.state in (CLEAR, CONTAINER_WRITE, VALUE_WRITE), self.state
+        self.__structs.append((self.state, self.__last_fid))
+        self.state = FIELD_WRITE
+        self.__last_fid = 0
 
-  def __writeFieldHeader(self, type, fid):
-    delta = fid - self.__last_fid
-    if 0 < delta <= 15:
-      self.__writeUByte(delta << 4 | type)
-    else:
-      self.__writeByte(type)
-      self.__writeI16(fid)
-    self.__last_fid = fid
+    def writeStructEnd(self):
+        assert self.state == FIELD_WRITE
+        self.state, self.__last_fid = self.__structs.pop()
 
-  def writeFieldBegin(self, name, type, fid):
-    assert self.state == FIELD_WRITE, self.state
-    if type == TType.BOOL:
-      self.state = BOOL_WRITE
-      self.__bool_fid = fid
-    else:
-      self.state = VALUE_WRITE
-      self.__writeFieldHeader(CTYPES[type], fid)
+    def writeFieldStop(self):
+        self.__writeByte(0)
 
-  def writeFieldEnd(self):
-    assert self.state in (VALUE_WRITE, BOOL_WRITE), self.state
-    self.state = FIELD_WRITE
+    def __writeFieldHeader(self, type, fid):
+        delta = fid - self.__last_fid
+        if 0 < delta <= 15:
+            self.__writeUByte(delta << 4 | type)
+        else:
+            self.__writeByte(type)
+            self.__writeI16(fid)
+        self.__last_fid = fid
 
-  def __writeUByte(self, byte):
-    self.trans.write(pack('!B', byte))
+    def writeFieldBegin(self, name, type, fid):
+        assert self.state == FIELD_WRITE, self.state
+        if type == TType.BOOL:
+            self.state = BOOL_WRITE
+            self.__bool_fid = fid
+        else:
+            self.state = VALUE_WRITE
+            self.__writeFieldHeader(CTYPES[type], fid)
 
-  def __writeByte(self, byte):
-    self.trans.write(pack('!b', byte))
+    def writeFieldEnd(self):
+        assert self.state in (VALUE_WRITE, BOOL_WRITE), self.state
+        self.state = FIELD_WRITE
 
-  def __writeI16(self, i16):
-    self.__writeVarint(makeZigZag(i16, 16))
+    def __writeUByte(self, byte):
+        self.trans.write(pack('!B', byte))
 
-  def __writeSize(self, i32):
-    self.__writeVarint(i32)
+    def __writeByte(self, byte):
+        self.trans.write(pack('!b', byte))
 
-  def writeCollectionBegin(self, etype, size):
-    assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state
-    if size <= 14:
-      self.__writeUByte(size << 4 | CTYPES[etype])
-    else:
-      self.__writeUByte(0xf0 | CTYPES[etype])
-      self.__writeSize(size)
-    self.__containers.append(self.state)
-    self.state = CONTAINER_WRITE
-  writeSetBegin = writeCollectionBegin
-  writeListBegin = writeCollectionBegin
+    def __writeI16(self, i16):
+        self.__writeVarint(makeZigZag(i16, 16))
 
-  def writeMapBegin(self, ktype, vtype, size):
-    assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state
-    if size == 0:
-      self.__writeByte(0)
-    else:
-      self.__writeSize(size)
-      self.__writeUByte(CTYPES[ktype] << 4 | CTYPES[vtype])
-    self.__containers.append(self.state)
-    self.state = CONTAINER_WRITE
+    def __writeSize(self, i32):
+        self.__writeVarint(i32)
 
-  def writeCollectionEnd(self):
-    assert self.state == CONTAINER_WRITE, self.state
-    self.state = self.__containers.pop()
-  writeMapEnd = writeCollectionEnd
-  writeSetEnd = writeCollectionEnd
-  writeListEnd = writeCollectionEnd
+    def writeCollectionBegin(self, etype, size):
+        assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state
+        if size <= 14:
+            self.__writeUByte(size << 4 | CTYPES[etype])
+        else:
+            self.__writeUByte(0xf0 | CTYPES[etype])
+            self.__writeSize(size)
+        self.__containers.append(self.state)
+        self.state = CONTAINER_WRITE
+    writeSetBegin = writeCollectionBegin
+    writeListBegin = writeCollectionBegin
 
-  def writeBool(self, bool):
-    if self.state == BOOL_WRITE:
-      if bool:
-        ctype = CompactType.TRUE
-      else:
-        ctype = CompactType.FALSE
-      self.__writeFieldHeader(ctype, self.__bool_fid)
-    elif self.state == CONTAINER_WRITE:
-      if bool:
-        self.__writeByte(CompactType.TRUE)
-      else:
-        self.__writeByte(CompactType.FALSE)
-    else:
-      raise AssertionError("Invalid state in compact protocol")
+    def writeMapBegin(self, ktype, vtype, size):
+        assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state
+        if size == 0:
+            self.__writeByte(0)
+        else:
+            self.__writeSize(size)
+            self.__writeUByte(CTYPES[ktype] << 4 | CTYPES[vtype])
+        self.__containers.append(self.state)
+        self.state = CONTAINER_WRITE
 
-  writeByte = writer(__writeByte)
-  writeI16 = writer(__writeI16)
+    def writeCollectionEnd(self):
+        assert self.state == CONTAINER_WRITE, self.state
+        self.state = self.__containers.pop()
+    writeMapEnd = writeCollectionEnd
+    writeSetEnd = writeCollectionEnd
+    writeListEnd = writeCollectionEnd
 
-  @writer
-  def writeI32(self, i32):
-    self.__writeVarint(makeZigZag(i32, 32))
+    def writeBool(self, bool):
+        if self.state == BOOL_WRITE:
+            if bool:
+                ctype = CompactType.TRUE
+            else:
+                ctype = CompactType.FALSE
+            self.__writeFieldHeader(ctype, self.__bool_fid)
+        elif self.state == CONTAINER_WRITE:
+            if bool:
+                self.__writeByte(CompactType.TRUE)
+            else:
+                self.__writeByte(CompactType.FALSE)
+        else:
+            raise AssertionError("Invalid state in compact protocol")
 
-  @writer
-  def writeI64(self, i64):
-    self.__writeVarint(makeZigZag(i64, 64))
+    writeByte = writer(__writeByte)
+    writeI16 = writer(__writeI16)
 
-  @writer
-  def writeDouble(self, dub):
-    self.trans.write(pack('!d', dub))
+    @writer
+    def writeI32(self, i32):
+        self.__writeVarint(makeZigZag(i32, 32))
 
-  def __writeString(self, s):
-    self.__writeSize(len(s))
-    self.trans.write(s)
-  writeString = writer(__writeString)
+    @writer
+    def writeI64(self, i64):
+        self.__writeVarint(makeZigZag(i64, 64))
 
-  def readFieldBegin(self):
-    assert self.state == FIELD_READ, self.state
-    type = self.__readUByte()
-    if type & 0x0f == TType.STOP:
-      return (None, 0, 0)
-    delta = type >> 4
-    if delta == 0:
-      fid = self.__readI16()
-    else:
-      fid = self.__last_fid + delta
-    self.__last_fid = fid
-    type = type & 0x0f
-    if type == CompactType.TRUE:
-      self.state = BOOL_READ
-      self.__bool_value = True
-    elif type == CompactType.FALSE:
-      self.state = BOOL_READ
-      self.__bool_value = False
-    else:
-      self.state = VALUE_READ
-    return (None, self.__getTType(type), fid)
+    @writer
+    def writeDouble(self, dub):
+        self.trans.write(pack('<d', dub))
 
-  def readFieldEnd(self):
-    assert self.state in (VALUE_READ, BOOL_READ), self.state
-    self.state = FIELD_READ
+    def __writeBinary(self, s):
+        self.__writeSize(len(s))
+        self.trans.write(s)
+    writeBinary = writer(__writeBinary)
 
-  def __readUByte(self):
-    result, = unpack('!B', self.trans.readAll(1))
-    return result
+    def readFieldBegin(self):
+        assert self.state == FIELD_READ, self.state
+        type = self.__readUByte()
+        if type & 0x0f == TType.STOP:
+            return (None, 0, 0)
+        delta = type >> 4
+        if delta == 0:
+            fid = self.__readI16()
+        else:
+            fid = self.__last_fid + delta
+        self.__last_fid = fid
+        type = type & 0x0f
+        if type == CompactType.TRUE:
+            self.state = BOOL_READ
+            self.__bool_value = True
+        elif type == CompactType.FALSE:
+            self.state = BOOL_READ
+            self.__bool_value = False
+        else:
+            self.state = VALUE_READ
+        return (None, self.__getTType(type), fid)
 
-  def __readByte(self):
-    result, = unpack('!b', self.trans.readAll(1))
-    return result
+    def readFieldEnd(self):
+        assert self.state in (VALUE_READ, BOOL_READ), self.state
+        self.state = FIELD_READ
 
-  def __readVarint(self):
-    return readVarint(self.trans)
+    def __readUByte(self):
+        result, = unpack('!B', self.trans.readAll(1))
+        return result
 
-  def __readZigZag(self):
-    return fromZigZag(self.__readVarint())
+    def __readByte(self):
+        result, = unpack('!b', self.trans.readAll(1))
+        return result
 
-  def __readSize(self):
-    result = self.__readVarint()
-    if result < 0:
-      raise TException("Length < 0")
-    return result
+    def __readVarint(self):
+        return readVarint(self.trans)
 
-  def readMessageBegin(self):
-    assert self.state == CLEAR
-    proto_id = self.__readUByte()
-    if proto_id != self.PROTOCOL_ID:
-      raise TProtocolException(TProtocolException.BAD_VERSION,
-          'Bad protocol id in the message: %d' % proto_id)
-    ver_type = self.__readUByte()
-    type = (ver_type & self.TYPE_MASK) >> self.TYPE_SHIFT_AMOUNT
-    version = ver_type & self.VERSION_MASK
-    if version != self.VERSION:
-      raise TProtocolException(TProtocolException.BAD_VERSION,
-          'Bad version: %d (expect %d)' % (version, self.VERSION))
-    seqid = self.__readVarint()
-    name = self.__readString()
-    return (name, type, seqid)
+    def __readZigZag(self):
+        return fromZigZag(self.__readVarint())
 
-  def readMessageEnd(self):
-    assert self.state == CLEAR
-    assert len(self.__structs) == 0
+    def __readSize(self):
+        result = self.__readVarint()
+        if result < 0:
+            raise TProtocolException("Length < 0")
+        return result
 
-  def readStructBegin(self):
-    assert self.state in (CLEAR, CONTAINER_READ, VALUE_READ), self.state
-    self.__structs.append((self.state, self.__last_fid))
-    self.state = FIELD_READ
-    self.__last_fid = 0
+    def readMessageBegin(self):
+        assert self.state == CLEAR
+        proto_id = self.__readUByte()
+        if proto_id != self.PROTOCOL_ID:
+            raise TProtocolException(TProtocolException.BAD_VERSION,
+                                     'Bad protocol id in the message: %d' % proto_id)
+        ver_type = self.__readUByte()
+        type = (ver_type >> self.TYPE_SHIFT_AMOUNT) & self.TYPE_BITS
+        version = ver_type & self.VERSION_MASK
+        if version != self.VERSION:
+            raise TProtocolException(TProtocolException.BAD_VERSION,
+                                     'Bad version: %d (expect %d)' % (version, self.VERSION))
+        seqid = self.__readVarint()
+        name = binary_to_str(self.__readBinary())
+        return (name, type, seqid)
 
-  def readStructEnd(self):
-    assert self.state == FIELD_READ
-    self.state, self.__last_fid = self.__structs.pop()
+    def readMessageEnd(self):
+        assert self.state == CLEAR
+        assert len(self.__structs) == 0
 
-  def readCollectionBegin(self):
-    assert self.state in (VALUE_READ, CONTAINER_READ), self.state
-    size_type = self.__readUByte()
-    size = size_type >> 4
-    type = self.__getTType(size_type)
-    if size == 15:
-      size = self.__readSize()
-    self.__containers.append(self.state)
-    self.state = CONTAINER_READ
-    return type, size
-  readSetBegin = readCollectionBegin
-  readListBegin = readCollectionBegin
+    def readStructBegin(self):
+        assert self.state in (CLEAR, CONTAINER_READ, VALUE_READ), self.state
+        self.__structs.append((self.state, self.__last_fid))
+        self.state = FIELD_READ
+        self.__last_fid = 0
 
-  def readMapBegin(self):
-    assert self.state in (VALUE_READ, CONTAINER_READ), self.state
-    size = self.__readSize()
-    types = 0
-    if size > 0:
-      types = self.__readUByte()
-    vtype = self.__getTType(types)
-    ktype = self.__getTType(types >> 4)
-    self.__containers.append(self.state)
-    self.state = CONTAINER_READ
-    return (ktype, vtype, size)
+    def readStructEnd(self):
+        assert self.state == FIELD_READ
+        self.state, self.__last_fid = self.__structs.pop()
 
-  def readCollectionEnd(self):
-    assert self.state == CONTAINER_READ, self.state
-    self.state = self.__containers.pop()
-  readSetEnd = readCollectionEnd
-  readListEnd = readCollectionEnd
-  readMapEnd = readCollectionEnd
+    def readCollectionBegin(self):
+        assert self.state in (VALUE_READ, CONTAINER_READ), self.state
+        size_type = self.__readUByte()
+        size = size_type >> 4
+        type = self.__getTType(size_type)
+        if size == 15:
+            size = self.__readSize()
+        self._check_container_length(size)
+        self.__containers.append(self.state)
+        self.state = CONTAINER_READ
+        return type, size
+    readSetBegin = readCollectionBegin
+    readListBegin = readCollectionBegin
 
-  def readBool(self):
-    if self.state == BOOL_READ:
-      return self.__bool_value == CompactType.TRUE
-    elif self.state == CONTAINER_READ:
-      return self.__readByte() == CompactType.TRUE
-    else:
-      raise AssertionError("Invalid state in compact protocol: %d" %
-                           self.state)
+    def readMapBegin(self):
+        assert self.state in (VALUE_READ, CONTAINER_READ), self.state
+        size = self.__readSize()
+        self._check_container_length(size)
+        types = 0
+        if size > 0:
+            types = self.__readUByte()
+        vtype = self.__getTType(types)
+        ktype = self.__getTType(types >> 4)
+        self.__containers.append(self.state)
+        self.state = CONTAINER_READ
+        return (ktype, vtype, size)
 
-  readByte = reader(__readByte)
-  __readI16 = __readZigZag
-  readI16 = reader(__readZigZag)
-  readI32 = reader(__readZigZag)
-  readI64 = reader(__readZigZag)
+    def readCollectionEnd(self):
+        assert self.state == CONTAINER_READ, self.state
+        self.state = self.__containers.pop()
+    readSetEnd = readCollectionEnd
+    readListEnd = readCollectionEnd
+    readMapEnd = readCollectionEnd
 
-  @reader
-  def readDouble(self):
-    buff = self.trans.readAll(8)
-    val, = unpack('!d', buff)
-    return val
+    def readBool(self):
+        if self.state == BOOL_READ:
+            return self.__bool_value == CompactType.TRUE
+        elif self.state == CONTAINER_READ:
+            return self.__readByte() == CompactType.TRUE
+        else:
+            raise AssertionError("Invalid state in compact protocol: %d" %
+                                 self.state)
 
-  def __readString(self):
-    len = self.__readSize()
-    return self.trans.readAll(len)
-  readString = reader(__readString)
+    readByte = reader(__readByte)
+    __readI16 = __readZigZag
+    readI16 = reader(__readZigZag)
+    readI32 = reader(__readZigZag)
+    readI64 = reader(__readZigZag)
 
-  def __getTType(self, byte):
-    return TTYPES[byte & 0x0f]
+    @reader
+    def readDouble(self):
+        buff = self.trans.readAll(8)
+        val, = unpack('<d', buff)
+        return val
+
+    def __readBinary(self):
+        size = self.__readSize()
+        self._check_string_length(size)
+        return self.trans.readAll(size)
+    readBinary = reader(__readBinary)
+
+    def __getTType(self, byte):
+        return TTYPES[byte & 0x0f]
 
 
-class TCompactProtocolFactory:
-  def __init__(self):
+class TCompactProtocolFactory(object):
+    def __init__(self,
+                 string_length_limit=None,
+                 container_length_limit=None):
+        self.string_length_limit = string_length_limit
+        self.container_length_limit = container_length_limit
+
+    def getProtocol(self, trans):
+        return TCompactProtocol(trans,
+                                self.string_length_limit,
+                                self.container_length_limit)
+
+
+class TCompactProtocolAccelerated(TCompactProtocol):
+    """C-Accelerated version of TCompactProtocol.
+
+    This class does not override any of TCompactProtocol's methods,
+    but the generated code recognizes it directly and will call into
+    our C module to do the encoding, bypassing this object entirely.
+    We inherit from TCompactProtocol so that the normal TCompactProtocol
+    encoding can happen if the fastbinary module doesn't work for some
+    reason.
+    To disable this behavior, pass fallback=False constructor argument.
+
+    In order to take advantage of the C module, just use
+    TCompactProtocolAccelerated instead of TCompactProtocol.
+    """
     pass
 
-  def getProtocol(self, trans):
-    return TCompactProtocol(trans)
+    def __init__(self, *args, **kwargs):
+        fallback = kwargs.pop('fallback', True)
+        super(TCompactProtocolAccelerated, self).__init__(*args, **kwargs)
+        try:
+            from thrift.protocol import fastbinary
+        except ImportError:
+            if not fallback:
+                raise
+        else:
+            self._fast_decode = fastbinary.decode_compact
+            self._fast_encode = fastbinary.encode_compact
+
+
+class TCompactProtocolAcceleratedFactory(object):
+    def __init__(self,
+                 string_length_limit=None,
+                 container_length_limit=None,
+                 fallback=True):
+        self.string_length_limit = string_length_limit
+        self.container_length_limit = container_length_limit
+        self._fallback = fallback
+
+    def getProtocol(self, trans):
+        return TCompactProtocolAccelerated(
+            trans,
+            string_length_limit=self.string_length_limit,
+            container_length_limit=self.container_length_limit,
+            fallback=self._fallback)
diff --git a/lib/py/src/protocol/THeaderProtocol.py b/lib/py/src/protocol/THeaderProtocol.py
new file mode 100644
index 0000000..b27a749
--- /dev/null
+++ b/lib/py/src/protocol/THeaderProtocol.py
@@ -0,0 +1,225 @@
+#
+# 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.
+#
+
+from thrift.protocol.TBinaryProtocol import TBinaryProtocolAccelerated
+from thrift.protocol.TCompactProtocol import TCompactProtocolAccelerated
+from thrift.protocol.TProtocol import TProtocolBase, TProtocolException
+from thrift.Thrift import TApplicationException, TMessageType
+from thrift.transport.THeaderTransport import THeaderTransport, THeaderSubprotocolID, THeaderClientType
+
+
+PROTOCOLS_BY_ID = {
+    THeaderSubprotocolID.BINARY: TBinaryProtocolAccelerated,
+    THeaderSubprotocolID.COMPACT: TCompactProtocolAccelerated,
+}
+
+
+class THeaderProtocol(TProtocolBase):
+    """A framed protocol with headers and payload transforms.
+
+    THeaderProtocol frames other Thrift protocols and adds support for optional
+    out-of-band headers. The currently supported subprotocols are
+    TBinaryProtocol and TCompactProtocol.
+
+    It's also possible to apply transforms to the encoded message payload. The
+    only transform currently supported is to gzip.
+
+    When used in a server, THeaderProtocol can accept messages from
+    non-THeaderProtocol clients if allowed (see `allowed_client_types`). This
+    includes framed and unframed transports and both TBinaryProtocol and
+    TCompactProtocol. The server will respond in the appropriate dialect for
+    the connected client. HTTP clients are not currently supported.
+
+    THeaderProtocol does not currently support THTTPServer, TNonblockingServer,
+    or TProcessPoolServer.
+
+    See doc/specs/HeaderFormat.md for details of the wire format.
+
+    """
+
+    def __init__(self, transport, allowed_client_types):
+        # much of the actual work for THeaderProtocol happens down in
+        # THeaderTransport since we need to do low-level shenanigans to detect
+        # if the client is sending us headers or one of the headerless formats
+        # we support. this wraps the real transport with the one that does all
+        # the magic.
+        if not isinstance(transport, THeaderTransport):
+            transport = THeaderTransport(transport, allowed_client_types)
+        super(THeaderProtocol, self).__init__(transport)
+        self._set_protocol()
+
+    def get_headers(self):
+        return self.trans.get_headers()
+
+    def set_header(self, key, value):
+        self.trans.set_header(key, value)
+
+    def clear_headers(self):
+        self.trans.clear_headers()
+
+    def add_transform(self, transform_id):
+        self.trans.add_transform(transform_id)
+
+    def writeMessageBegin(self, name, ttype, seqid):
+        self.trans.sequence_id = seqid
+        return self._protocol.writeMessageBegin(name, ttype, seqid)
+
+    def writeMessageEnd(self):
+        return self._protocol.writeMessageEnd()
+
+    def writeStructBegin(self, name):
+        return self._protocol.writeStructBegin(name)
+
+    def writeStructEnd(self):
+        return self._protocol.writeStructEnd()
+
+    def writeFieldBegin(self, name, ttype, fid):
+        return self._protocol.writeFieldBegin(name, ttype, fid)
+
+    def writeFieldEnd(self):
+        return self._protocol.writeFieldEnd()
+
+    def writeFieldStop(self):
+        return self._protocol.writeFieldStop()
+
+    def writeMapBegin(self, ktype, vtype, size):
+        return self._protocol.writeMapBegin(ktype, vtype, size)
+
+    def writeMapEnd(self):
+        return self._protocol.writeMapEnd()
+
+    def writeListBegin(self, etype, size):
+        return self._protocol.writeListBegin(etype, size)
+
+    def writeListEnd(self):
+        return self._protocol.writeListEnd()
+
+    def writeSetBegin(self, etype, size):
+        return self._protocol.writeSetBegin(etype, size)
+
+    def writeSetEnd(self):
+        return self._protocol.writeSetEnd()
+
+    def writeBool(self, bool_val):
+        return self._protocol.writeBool(bool_val)
+
+    def writeByte(self, byte):
+        return self._protocol.writeByte(byte)
+
+    def writeI16(self, i16):
+        return self._protocol.writeI16(i16)
+
+    def writeI32(self, i32):
+        return self._protocol.writeI32(i32)
+
+    def writeI64(self, i64):
+        return self._protocol.writeI64(i64)
+
+    def writeDouble(self, dub):
+        return self._protocol.writeDouble(dub)
+
+    def writeBinary(self, str_val):
+        return self._protocol.writeBinary(str_val)
+
+    def _set_protocol(self):
+        try:
+            protocol_cls = PROTOCOLS_BY_ID[self.trans.protocol_id]
+        except KeyError:
+            raise TApplicationException(
+                TProtocolException.INVALID_PROTOCOL,
+                "Unknown protocol requested.",
+            )
+
+        self._protocol = protocol_cls(self.trans)
+        self._fast_encode = self._protocol._fast_encode
+        self._fast_decode = self._protocol._fast_decode
+
+    def readMessageBegin(self):
+        try:
+            self.trans.readFrame(0)
+            self._set_protocol()
+        except TApplicationException as exc:
+            self._protocol.writeMessageBegin(b"", TMessageType.EXCEPTION, 0)
+            exc.write(self._protocol)
+            self._protocol.writeMessageEnd()
+            self.trans.flush()
+
+        return self._protocol.readMessageBegin()
+
+    def readMessageEnd(self):
+        return self._protocol.readMessageEnd()
+
+    def readStructBegin(self):
+        return self._protocol.readStructBegin()
+
+    def readStructEnd(self):
+        return self._protocol.readStructEnd()
+
+    def readFieldBegin(self):
+        return self._protocol.readFieldBegin()
+
+    def readFieldEnd(self):
+        return self._protocol.readFieldEnd()
+
+    def readMapBegin(self):
+        return self._protocol.readMapBegin()
+
+    def readMapEnd(self):
+        return self._protocol.readMapEnd()
+
+    def readListBegin(self):
+        return self._protocol.readListBegin()
+
+    def readListEnd(self):
+        return self._protocol.readListEnd()
+
+    def readSetBegin(self):
+        return self._protocol.readSetBegin()
+
+    def readSetEnd(self):
+        return self._protocol.readSetEnd()
+
+    def readBool(self):
+        return self._protocol.readBool()
+
+    def readByte(self):
+        return self._protocol.readByte()
+
+    def readI16(self):
+        return self._protocol.readI16()
+
+    def readI32(self):
+        return self._protocol.readI32()
+
+    def readI64(self):
+        return self._protocol.readI64()
+
+    def readDouble(self):
+        return self._protocol.readDouble()
+
+    def readBinary(self):
+        return self._protocol.readBinary()
+
+
+class THeaderProtocolFactory(object):
+    def __init__(self, allowed_client_types=(THeaderClientType.HEADERS,)):
+        self.allowed_client_types = allowed_client_types
+
+    def getProtocol(self, trans):
+        return THeaderProtocol(trans, self.allowed_client_types)
diff --git a/lib/py/src/protocol/TJSONProtocol.py b/lib/py/src/protocol/TJSONProtocol.py
index 3048197..db2099a 100644
--- a/lib/py/src/protocol/TJSONProtocol.py
+++ b/lib/py/src/protocol/TJSONProtocol.py
@@ -17,10 +17,14 @@
 # under the License.
 #
 
-from TProtocol import TType, TProtocolBase, TProtocolException
+from .TProtocol import (TType, TProtocolBase, TProtocolException,
+                        checkIntegerLimits)
 import base64
-import json
 import math
+import sys
+
+from ..compat import str_to_binary
+
 
 __all__ = ['TJSONProtocol',
            'TJSONProtocolFactory',
@@ -29,494 +33,608 @@
 
 VERSION = 1
 
-COMMA = ','
-COLON = ':'
-LBRACE = '{'
-RBRACE = '}'
-LBRACKET = '['
-RBRACKET = ']'
-QUOTE = '"'
-BACKSLASH = '\\'
-ZERO = '0'
+COMMA = b','
+COLON = b':'
+LBRACE = b'{'
+RBRACE = b'}'
+LBRACKET = b'['
+RBRACKET = b']'
+QUOTE = b'"'
+BACKSLASH = b'\\'
+ZERO = b'0'
 
-ESCSEQ = '\\u00'
-ESCAPE_CHAR = '"\\bfnrt'
-ESCAPE_CHAR_VALS = ['"', '\\', '\b', '\f', '\n', '\r', '\t']
-NUMERIC_CHAR = '+-.0123456789Ee'
+ESCSEQ0 = ord('\\')
+ESCSEQ1 = ord('u')
+ESCAPE_CHAR_VALS = {
+    '"': '\\"',
+    '\\': '\\\\',
+    '\b': '\\b',
+    '\f': '\\f',
+    '\n': '\\n',
+    '\r': '\\r',
+    '\t': '\\t',
+    # '/': '\\/',
+}
+ESCAPE_CHARS = {
+    b'"': '"',
+    b'\\': '\\',
+    b'b': '\b',
+    b'f': '\f',
+    b'n': '\n',
+    b'r': '\r',
+    b't': '\t',
+    b'/': '/',
+}
+NUMERIC_CHAR = b'+-.0123456789Ee'
 
-CTYPES = {TType.BOOL:       'tf',
-          TType.BYTE:       'i8',
-          TType.I16:        'i16',
-          TType.I32:        'i32',
-          TType.I64:        'i64',
-          TType.DOUBLE:     'dbl',
-          TType.STRING:     'str',
-          TType.STRUCT:     'rec',
-          TType.LIST:       'lst',
-          TType.SET:        'set',
-          TType.MAP:        'map'}
+CTYPES = {
+    TType.BOOL: 'tf',
+    TType.BYTE: 'i8',
+    TType.I16: 'i16',
+    TType.I32: 'i32',
+    TType.I64: 'i64',
+    TType.DOUBLE: 'dbl',
+    TType.STRING: 'str',
+    TType.STRUCT: 'rec',
+    TType.LIST: 'lst',
+    TType.SET: 'set',
+    TType.MAP: 'map',
+}
 
 JTYPES = {}
 for key in CTYPES.keys():
-  JTYPES[CTYPES[key]] = key
+    JTYPES[CTYPES[key]] = key
 
 
 class JSONBaseContext(object):
 
-  def __init__(self, protocol):
-    self.protocol = protocol
-    self.first = True
+    def __init__(self, protocol):
+        self.protocol = protocol
+        self.first = True
 
-  def doIO(self, function):
-    pass
-  
-  def write(self):
-    pass
+    def doIO(self, function):
+        pass
 
-  def read(self):
-    pass
+    def write(self):
+        pass
 
-  def escapeNum(self):
-    return False
+    def read(self):
+        pass
 
-  def __str__(self):
-    return self.__class__.__name__
+    def escapeNum(self):
+        return False
+
+    def __str__(self):
+        return self.__class__.__name__
 
 
 class JSONListContext(JSONBaseContext):
-    
-  def doIO(self, function):
-    if self.first is True:
-      self.first = False
-    else:
-      function(COMMA)
 
-  def write(self):
-    self.doIO(self.protocol.trans.write)
+    def doIO(self, function):
+        if self.first is True:
+            self.first = False
+        else:
+            function(COMMA)
 
-  def read(self):
-    self.doIO(self.protocol.readJSONSyntaxChar)
+    def write(self):
+        self.doIO(self.protocol.trans.write)
+
+    def read(self):
+        self.doIO(self.protocol.readJSONSyntaxChar)
 
 
 class JSONPairContext(JSONBaseContext):
-  
-  def __init__(self, protocol):
-    super(JSONPairContext, self).__init__(protocol)
-    self.colon = True
 
-  def doIO(self, function):
-    if self.first:
-      self.first = False
-      self.colon = True
-    else:
-      function(COLON if self.colon else COMMA)
-      self.colon = not self.colon
+    def __init__(self, protocol):
+        super(JSONPairContext, self).__init__(protocol)
+        self.colon = True
 
-  def write(self):
-    self.doIO(self.protocol.trans.write)
+    def doIO(self, function):
+        if self.first:
+            self.first = False
+            self.colon = True
+        else:
+            function(COLON if self.colon else COMMA)
+            self.colon = not self.colon
 
-  def read(self):
-    self.doIO(self.protocol.readJSONSyntaxChar)
+    def write(self):
+        self.doIO(self.protocol.trans.write)
 
-  def escapeNum(self):
-    return self.colon
+    def read(self):
+        self.doIO(self.protocol.readJSONSyntaxChar)
 
-  def __str__(self):
-    return '%s, colon=%s' % (self.__class__.__name__, self.colon)
+    def escapeNum(self):
+        return self.colon
+
+    def __str__(self):
+        return '%s, colon=%s' % (self.__class__.__name__, self.colon)
 
 
 class LookaheadReader():
-  hasData = False
-  data = ''
+    hasData = False
+    data = ''
 
-  def __init__(self, protocol):
-    self.protocol = protocol
+    def __init__(self, protocol):
+        self.protocol = protocol
 
-  def read(self):
-    if self.hasData is True:
-      self.hasData = False
-    else:
-      self.data = self.protocol.trans.read(1)
-    return self.data
+    def read(self):
+        if self.hasData is True:
+            self.hasData = False
+        else:
+            self.data = self.protocol.trans.read(1)
+        return self.data
 
-  def peek(self):
-    if self.hasData is False:
-      self.data = self.protocol.trans.read(1)
-    self.hasData = True
-    return self.data
+    def peek(self):
+        if self.hasData is False:
+            self.data = self.protocol.trans.read(1)
+        self.hasData = True
+        return self.data
+
 
 class TJSONProtocolBase(TProtocolBase):
 
-  def __init__(self, trans):
-    TProtocolBase.__init__(self, trans)
-    self.resetWriteContext()
-    self.resetReadContext()
+    def __init__(self, trans):
+        TProtocolBase.__init__(self, trans)
+        self.resetWriteContext()
+        self.resetReadContext()
 
-  def resetWriteContext(self):
-    self.context = JSONBaseContext(self)
-    self.contextStack = [self.context]
+    # We don't have length limit implementation for JSON protocols
+    @property
+    def string_length_limit(senf):
+        return None
 
-  def resetReadContext(self):
-    self.resetWriteContext()
-    self.reader = LookaheadReader(self)
+    @property
+    def container_length_limit(senf):
+        return None
 
-  def pushContext(self, ctx):
-    self.contextStack.append(ctx)
-    self.context = ctx
+    def resetWriteContext(self):
+        self.context = JSONBaseContext(self)
+        self.contextStack = [self.context]
 
-  def popContext(self):
-    self.contextStack.pop()
-    if self.contextStack:
-      self.context = self.contextStack[-1]
-    else:
-      self.context = JSONBaseContext(self)
+    def resetReadContext(self):
+        self.resetWriteContext()
+        self.reader = LookaheadReader(self)
 
-  def writeJSONString(self, string):
-    self.context.write()
-    self.trans.write(json.dumps(string))
+    def pushContext(self, ctx):
+        self.contextStack.append(ctx)
+        self.context = ctx
 
-  def writeJSONNumber(self, number):
-    self.context.write()
-    jsNumber = str(number)
-    if self.context.escapeNum():
-      jsNumber = "%s%s%s" % (QUOTE, jsNumber,  QUOTE)
-    self.trans.write(jsNumber)
-
-  def writeJSONBase64(self, binary):
-    self.context.write()
-    self.trans.write(QUOTE)
-    self.trans.write(base64.b64encode(binary))
-    self.trans.write(QUOTE)
-
-  def writeJSONObjectStart(self):
-    self.context.write()
-    self.trans.write(LBRACE)
-    self.pushContext(JSONPairContext(self))
-
-  def writeJSONObjectEnd(self):
-    self.popContext()
-    self.trans.write(RBRACE)
-
-  def writeJSONArrayStart(self):
-    self.context.write()
-    self.trans.write(LBRACKET)
-    self.pushContext(JSONListContext(self))
-
-  def writeJSONArrayEnd(self):
-    self.popContext()
-    self.trans.write(RBRACKET)
-
-  def readJSONSyntaxChar(self, character):
-    current = self.reader.read()
-    if character != current:
-      raise TProtocolException(TProtocolException.INVALID_DATA,
-                               "Unexpected character: %s" % current)
-
-  def readJSONString(self, skipContext):
-    string = []
-    if skipContext is False:
-      self.context.read()
-    self.readJSONSyntaxChar(QUOTE)
-    while True:
-      character = self.reader.read()
-      if character == QUOTE:
-        break
-      if character == ESCSEQ[0]:
-        character = self.reader.read()
-        if character == ESCSEQ[1]:
-          self.readJSONSyntaxChar(ZERO)
-          self.readJSONSyntaxChar(ZERO)
-          character = json.JSONDecoder().decode('"\u00%s"' % self.trans.read(2))
+    def popContext(self):
+        self.contextStack.pop()
+        if self.contextStack:
+            self.context = self.contextStack[-1]
         else:
-          off = ESCAPE_CHAR.find(character)
-          if off == -1:
+            self.context = JSONBaseContext(self)
+
+    def writeJSONString(self, string):
+        self.context.write()
+        json_str = ['"']
+        for s in string:
+            escaped = ESCAPE_CHAR_VALS.get(s, s)
+            json_str.append(escaped)
+        json_str.append('"')
+        self.trans.write(str_to_binary(''.join(json_str)))
+
+    def writeJSONNumber(self, number, formatter='{0}'):
+        self.context.write()
+        jsNumber = str(formatter.format(number)).encode('ascii')
+        if self.context.escapeNum():
+            self.trans.write(QUOTE)
+            self.trans.write(jsNumber)
+            self.trans.write(QUOTE)
+        else:
+            self.trans.write(jsNumber)
+
+    def writeJSONBase64(self, binary):
+        self.context.write()
+        self.trans.write(QUOTE)
+        self.trans.write(base64.b64encode(binary))
+        self.trans.write(QUOTE)
+
+    def writeJSONObjectStart(self):
+        self.context.write()
+        self.trans.write(LBRACE)
+        self.pushContext(JSONPairContext(self))
+
+    def writeJSONObjectEnd(self):
+        self.popContext()
+        self.trans.write(RBRACE)
+
+    def writeJSONArrayStart(self):
+        self.context.write()
+        self.trans.write(LBRACKET)
+        self.pushContext(JSONListContext(self))
+
+    def writeJSONArrayEnd(self):
+        self.popContext()
+        self.trans.write(RBRACKET)
+
+    def readJSONSyntaxChar(self, character):
+        current = self.reader.read()
+        if character != current:
             raise TProtocolException(TProtocolException.INVALID_DATA,
-                                     "Expected control char")
-          character = ESCAPE_CHAR_VALS[off]
-      string.append(character)
-    return ''.join(string)
+                                     "Unexpected character: %s" % current)
 
-  def isJSONNumeric(self, character):
-    return (True if NUMERIC_CHAR.find(character) != - 1 else False)
+    def _isHighSurrogate(self, codeunit):
+        return codeunit >= 0xd800 and codeunit <= 0xdbff
 
-  def readJSONQuotes(self):
-    if (self.context.escapeNum()):
-      self.readJSONSyntaxChar(QUOTE)
+    def _isLowSurrogate(self, codeunit):
+        return codeunit >= 0xdc00 and codeunit <= 0xdfff
 
-  def readJSONNumericChars(self):
-    numeric = []
-    while True:
-      character = self.reader.peek()
-      if self.isJSONNumeric(character) is False:
-        break
-      numeric.append(self.reader.read())
-    return ''.join(numeric)
+    def _toChar(self, high, low=None):
+        if not low:
+            if sys.version_info[0] == 2:
+                return ("\\u%04x" % high).decode('unicode-escape') \
+                                         .encode('utf-8')
+            else:
+                return chr(high)
+        else:
+            codepoint = (1 << 16) + ((high & 0x3ff) << 10)
+            codepoint += low & 0x3ff
+            if sys.version_info[0] == 2:
+                s = "\\U%08x" % codepoint
+                return s.decode('unicode-escape').encode('utf-8')
+            else:
+                return chr(codepoint)
 
-  def readJSONInteger(self):
-    self.context.read()
-    self.readJSONQuotes()
-    numeric = self.readJSONNumericChars()
-    self.readJSONQuotes()
-    try:
-      return int(numeric)
-    except ValueError:
-      raise TProtocolException(TProtocolException.INVALID_DATA,
-                               "Bad data encounted in numeric data")
-
-  def readJSONDouble(self):
-    self.context.read()
-    if self.reader.peek() == QUOTE:
-      string  = self.readJSONString(True)
-      try:
-        double = float(string)
-        if (self.context.escapeNum is False and
-            not math.isinf(double) and
-            not math.isnan(double)):
-          raise TProtocolException(TProtocolException.INVALID_DATA,
-                                   "Numeric data unexpectedly quoted")
-        return double
-      except ValueError:
-        raise TProtocolException(TProtocolException.INVALID_DATA,
-                                 "Bad data encounted in numeric data")
-    else:
-      if self.context.escapeNum() is True:
+    def readJSONString(self, skipContext):
+        highSurrogate = None
+        string = []
+        if skipContext is False:
+            self.context.read()
         self.readJSONSyntaxChar(QUOTE)
-      try:
-        return float(self.readJSONNumericChars())
-      except ValueError:
-        raise TProtocolException(TProtocolException.INVALID_DATA,
-                                 "Bad data encounted in numeric data")
+        while True:
+            character = self.reader.read()
+            if character == QUOTE:
+                break
+            if ord(character) == ESCSEQ0:
+                character = self.reader.read()
+                if ord(character) == ESCSEQ1:
+                    character = self.trans.read(4).decode('ascii')
+                    codeunit = int(character, 16)
+                    if self._isHighSurrogate(codeunit):
+                        if highSurrogate:
+                            raise TProtocolException(
+                                TProtocolException.INVALID_DATA,
+                                "Expected low surrogate char")
+                        highSurrogate = codeunit
+                        continue
+                    elif self._isLowSurrogate(codeunit):
+                        if not highSurrogate:
+                            raise TProtocolException(
+                                TProtocolException.INVALID_DATA,
+                                "Expected high surrogate char")
+                        character = self._toChar(highSurrogate, codeunit)
+                        highSurrogate = None
+                    else:
+                        character = self._toChar(codeunit)
+                else:
+                    if character not in ESCAPE_CHARS:
+                        raise TProtocolException(
+                            TProtocolException.INVALID_DATA,
+                            "Expected control char")
+                    character = ESCAPE_CHARS[character]
+            elif character in ESCAPE_CHAR_VALS:
+                raise TProtocolException(TProtocolException.INVALID_DATA,
+                                         "Unescaped control char")
+            elif sys.version_info[0] > 2:
+                utf8_bytes = bytearray([ord(character)])
+                while ord(self.reader.peek()) >= 0x80:
+                    utf8_bytes.append(ord(self.reader.read()))
+                character = utf8_bytes.decode('utf8')
+            string.append(character)
 
-  def readJSONBase64(self):
-    string = self.readJSONString(False)
-    return base64.b64decode(string)
+            if highSurrogate:
+                raise TProtocolException(TProtocolException.INVALID_DATA,
+                                         "Expected low surrogate char")
+        return ''.join(string)
 
-  def readJSONObjectStart(self):
-    self.context.read()
-    self.readJSONSyntaxChar(LBRACE)
-    self.pushContext(JSONPairContext(self))
+    def isJSONNumeric(self, character):
+        return (True if NUMERIC_CHAR.find(character) != - 1 else False)
 
-  def readJSONObjectEnd(self):
-    self.readJSONSyntaxChar(RBRACE)
-    self.popContext()
+    def readJSONQuotes(self):
+        if (self.context.escapeNum()):
+            self.readJSONSyntaxChar(QUOTE)
 
-  def readJSONArrayStart(self):
-    self.context.read()
-    self.readJSONSyntaxChar(LBRACKET)
-    self.pushContext(JSONListContext(self))
+    def readJSONNumericChars(self):
+        numeric = []
+        while True:
+            character = self.reader.peek()
+            if self.isJSONNumeric(character) is False:
+                break
+            numeric.append(self.reader.read())
+        return b''.join(numeric).decode('ascii')
 
-  def readJSONArrayEnd(self):
-    self.readJSONSyntaxChar(RBRACKET)
-    self.popContext()
+    def readJSONInteger(self):
+        self.context.read()
+        self.readJSONQuotes()
+        numeric = self.readJSONNumericChars()
+        self.readJSONQuotes()
+        try:
+            return int(numeric)
+        except ValueError:
+            raise TProtocolException(TProtocolException.INVALID_DATA,
+                                     "Bad data encounted in numeric data")
+
+    def readJSONDouble(self):
+        self.context.read()
+        if self.reader.peek() == QUOTE:
+            string = self.readJSONString(True)
+            try:
+                double = float(string)
+                if (self.context.escapeNum is False and
+                        not math.isinf(double) and
+                        not math.isnan(double)):
+                    raise TProtocolException(
+                        TProtocolException.INVALID_DATA,
+                        "Numeric data unexpectedly quoted")
+                return double
+            except ValueError:
+                raise TProtocolException(TProtocolException.INVALID_DATA,
+                                         "Bad data encounted in numeric data")
+        else:
+            if self.context.escapeNum() is True:
+                self.readJSONSyntaxChar(QUOTE)
+            try:
+                return float(self.readJSONNumericChars())
+            except ValueError:
+                raise TProtocolException(TProtocolException.INVALID_DATA,
+                                         "Bad data encounted in numeric data")
+
+    def readJSONBase64(self):
+        string = self.readJSONString(False)
+        size = len(string)
+        m = size % 4
+        # Force padding since b64encode method does not allow it
+        if m != 0:
+            for i in range(4 - m):
+                string += '='
+        return base64.b64decode(string)
+
+    def readJSONObjectStart(self):
+        self.context.read()
+        self.readJSONSyntaxChar(LBRACE)
+        self.pushContext(JSONPairContext(self))
+
+    def readJSONObjectEnd(self):
+        self.readJSONSyntaxChar(RBRACE)
+        self.popContext()
+
+    def readJSONArrayStart(self):
+        self.context.read()
+        self.readJSONSyntaxChar(LBRACKET)
+        self.pushContext(JSONListContext(self))
+
+    def readJSONArrayEnd(self):
+        self.readJSONSyntaxChar(RBRACKET)
+        self.popContext()
 
 
 class TJSONProtocol(TJSONProtocolBase):
 
-  def readMessageBegin(self):
-    self.resetReadContext()
-    self.readJSONArrayStart()
-    if self.readJSONInteger() != VERSION:
-      raise TProtocolException(TProtocolException.BAD_VERSION,
-                               "Message contained bad version.")
-    name = self.readJSONString(False)
-    typen = self.readJSONInteger()
-    seqid = self.readJSONInteger()
-    return (name, typen, seqid)
+    def readMessageBegin(self):
+        self.resetReadContext()
+        self.readJSONArrayStart()
+        if self.readJSONInteger() != VERSION:
+            raise TProtocolException(TProtocolException.BAD_VERSION,
+                                     "Message contained bad version.")
+        name = self.readJSONString(False)
+        typen = self.readJSONInteger()
+        seqid = self.readJSONInteger()
+        return (name, typen, seqid)
 
-  def readMessageEnd(self):
-    self.readJSONArrayEnd()
+    def readMessageEnd(self):
+        self.readJSONArrayEnd()
 
-  def readStructBegin(self):
-    self.readJSONObjectStart()
+    def readStructBegin(self):
+        self.readJSONObjectStart()
 
-  def readStructEnd(self):
-    self.readJSONObjectEnd()
+    def readStructEnd(self):
+        self.readJSONObjectEnd()
 
-  def readFieldBegin(self):
-    character = self.reader.peek()
-    ttype = 0
-    id = 0
-    if character == RBRACE:
-      ttype = TType.STOP
-    else:
-      id = self.readJSONInteger()
-      self.readJSONObjectStart()
-      ttype = JTYPES[self.readJSONString(False)]
-    return (None, ttype, id)
+    def readFieldBegin(self):
+        character = self.reader.peek()
+        ttype = 0
+        id = 0
+        if character == RBRACE:
+            ttype = TType.STOP
+        else:
+            id = self.readJSONInteger()
+            self.readJSONObjectStart()
+            ttype = JTYPES[self.readJSONString(False)]
+        return (None, ttype, id)
 
-  def readFieldEnd(self):
-    self.readJSONObjectEnd()
+    def readFieldEnd(self):
+        self.readJSONObjectEnd()
 
-  def readMapBegin(self):
-    self.readJSONArrayStart()
-    keyType = JTYPES[self.readJSONString(False)]
-    valueType = JTYPES[self.readJSONString(False)]
-    size = self.readJSONInteger()
-    self.readJSONObjectStart()
-    return (keyType, valueType, size)
+    def readMapBegin(self):
+        self.readJSONArrayStart()
+        keyType = JTYPES[self.readJSONString(False)]
+        valueType = JTYPES[self.readJSONString(False)]
+        size = self.readJSONInteger()
+        self.readJSONObjectStart()
+        return (keyType, valueType, size)
 
-  def readMapEnd(self):
-    self.readJSONObjectEnd()
-    self.readJSONArrayEnd()
+    def readMapEnd(self):
+        self.readJSONObjectEnd()
+        self.readJSONArrayEnd()
 
-  def readCollectionBegin(self):
-    self.readJSONArrayStart()
-    elemType = JTYPES[self.readJSONString(False)]
-    size = self.readJSONInteger()
-    return (elemType, size)
-  readListBegin = readCollectionBegin
-  readSetBegin = readCollectionBegin
+    def readCollectionBegin(self):
+        self.readJSONArrayStart()
+        elemType = JTYPES[self.readJSONString(False)]
+        size = self.readJSONInteger()
+        return (elemType, size)
+    readListBegin = readCollectionBegin
+    readSetBegin = readCollectionBegin
 
-  def readCollectionEnd(self):
-    self.readJSONArrayEnd()
-  readSetEnd = readCollectionEnd
-  readListEnd = readCollectionEnd
+    def readCollectionEnd(self):
+        self.readJSONArrayEnd()
+    readSetEnd = readCollectionEnd
+    readListEnd = readCollectionEnd
 
-  def readBool(self):
-    return (False if self.readJSONInteger() == 0 else True)
+    def readBool(self):
+        return (False if self.readJSONInteger() == 0 else True)
 
-  def readNumber(self):
-    return self.readJSONInteger()
-  readByte = readNumber
-  readI16 = readNumber
-  readI32 = readNumber
-  readI64 = readNumber
+    def readNumber(self):
+        return self.readJSONInteger()
+    readByte = readNumber
+    readI16 = readNumber
+    readI32 = readNumber
+    readI64 = readNumber
 
-  def readDouble(self):
-    return self.readJSONDouble()
+    def readDouble(self):
+        return self.readJSONDouble()
 
-  def readString(self):
-    return self.readJSONString(False)
+    def readString(self):
+        return self.readJSONString(False)
 
-  def readBinary(self):
-    return self.readJSONBase64()
+    def readBinary(self):
+        return self.readJSONBase64()
 
-  def writeMessageBegin(self, name, request_type, seqid):
-    self.resetWriteContext()
-    self.writeJSONArrayStart()
-    self.writeJSONNumber(VERSION)
-    self.writeJSONString(name)
-    self.writeJSONNumber(request_type)
-    self.writeJSONNumber(seqid)
+    def writeMessageBegin(self, name, request_type, seqid):
+        self.resetWriteContext()
+        self.writeJSONArrayStart()
+        self.writeJSONNumber(VERSION)
+        self.writeJSONString(name)
+        self.writeJSONNumber(request_type)
+        self.writeJSONNumber(seqid)
 
-  def writeMessageEnd(self):
-    self.writeJSONArrayEnd()
+    def writeMessageEnd(self):
+        self.writeJSONArrayEnd()
 
-  def writeStructBegin(self, name):
-    self.writeJSONObjectStart()
+    def writeStructBegin(self, name):
+        self.writeJSONObjectStart()
 
-  def writeStructEnd(self):
-    self.writeJSONObjectEnd()
+    def writeStructEnd(self):
+        self.writeJSONObjectEnd()
 
-  def writeFieldBegin(self, name, ttype, id):
-    self.writeJSONNumber(id)
-    self.writeJSONObjectStart()
-    self.writeJSONString(CTYPES[ttype])
+    def writeFieldBegin(self, name, ttype, id):
+        self.writeJSONNumber(id)
+        self.writeJSONObjectStart()
+        self.writeJSONString(CTYPES[ttype])
 
-  def writeFieldEnd(self):
-    self.writeJSONObjectEnd()
+    def writeFieldEnd(self):
+        self.writeJSONObjectEnd()
 
-  def writeFieldStop(self):
-    pass
+    def writeFieldStop(self):
+        pass
 
-  def writeMapBegin(self, ktype, vtype, size):
-    self.writeJSONArrayStart()
-    self.writeJSONString(CTYPES[ktype])
-    self.writeJSONString(CTYPES[vtype])
-    self.writeJSONNumber(size)
-    self.writeJSONObjectStart()
+    def writeMapBegin(self, ktype, vtype, size):
+        self.writeJSONArrayStart()
+        self.writeJSONString(CTYPES[ktype])
+        self.writeJSONString(CTYPES[vtype])
+        self.writeJSONNumber(size)
+        self.writeJSONObjectStart()
 
-  def writeMapEnd(self):
-    self.writeJSONObjectEnd()
-    self.writeJSONArrayEnd()
-    
-  def writeListBegin(self, etype, size):
-    self.writeJSONArrayStart()
-    self.writeJSONString(CTYPES[etype])
-    self.writeJSONNumber(size)
-    
-  def writeListEnd(self):
-    self.writeJSONArrayEnd()
+    def writeMapEnd(self):
+        self.writeJSONObjectEnd()
+        self.writeJSONArrayEnd()
 
-  def writeSetBegin(self, etype, size):
-    self.writeJSONArrayStart()
-    self.writeJSONString(CTYPES[etype])
-    self.writeJSONNumber(size)
-    
-  def writeSetEnd(self):
-    self.writeJSONArrayEnd()
+    def writeListBegin(self, etype, size):
+        self.writeJSONArrayStart()
+        self.writeJSONString(CTYPES[etype])
+        self.writeJSONNumber(size)
 
-  def writeBool(self, boolean):
-    self.writeJSONNumber(1 if boolean is True else 0)
+    def writeListEnd(self):
+        self.writeJSONArrayEnd()
 
-  def writeInteger(self, integer):
-    self.writeJSONNumber(integer)
-  writeByte = writeInteger
-  writeI16 = writeInteger
-  writeI32 = writeInteger
-  writeI64 = writeInteger
+    def writeSetBegin(self, etype, size):
+        self.writeJSONArrayStart()
+        self.writeJSONString(CTYPES[etype])
+        self.writeJSONNumber(size)
 
-  def writeDouble(self, dbl):
-    self.writeJSONNumber(dbl)
+    def writeSetEnd(self):
+        self.writeJSONArrayEnd()
 
-  def writeString(self, string):
-    self.writeJSONString(string)
-    
-  def writeBinary(self, binary):
-    self.writeJSONBase64(binary)
+    def writeBool(self, boolean):
+        self.writeJSONNumber(1 if boolean is True else 0)
+
+    def writeByte(self, byte):
+        checkIntegerLimits(byte, 8)
+        self.writeJSONNumber(byte)
+
+    def writeI16(self, i16):
+        checkIntegerLimits(i16, 16)
+        self.writeJSONNumber(i16)
+
+    def writeI32(self, i32):
+        checkIntegerLimits(i32, 32)
+        self.writeJSONNumber(i32)
+
+    def writeI64(self, i64):
+        checkIntegerLimits(i64, 64)
+        self.writeJSONNumber(i64)
+
+    def writeDouble(self, dbl):
+        # 17 significant digits should be just enough for any double precision
+        # value.
+        self.writeJSONNumber(dbl, '{0:.17g}')
+
+    def writeString(self, string):
+        self.writeJSONString(string)
+
+    def writeBinary(self, binary):
+        self.writeJSONBase64(binary)
 
 
-class TJSONProtocolFactory:
+class TJSONProtocolFactory(object):
+    def getProtocol(self, trans):
+        return TJSONProtocol(trans)
 
-  def getProtocol(self, trans):
-    return TJSONProtocol(trans)
+    @property
+    def string_length_limit(senf):
+        return None
+
+    @property
+    def container_length_limit(senf):
+        return None
 
 
 class TSimpleJSONProtocol(TJSONProtocolBase):
     """Simple, readable, write-only JSON protocol.
-    
+
     Useful for interacting with scripting languages.
     """
 
     def readMessageBegin(self):
         raise NotImplementedError()
-    
+
     def readMessageEnd(self):
         raise NotImplementedError()
-    
+
     def readStructBegin(self):
         raise NotImplementedError()
-    
+
     def readStructEnd(self):
         raise NotImplementedError()
-    
+
     def writeMessageBegin(self, name, request_type, seqid):
         self.resetWriteContext()
-    
+
     def writeMessageEnd(self):
         pass
-    
+
     def writeStructBegin(self, name):
         self.writeJSONObjectStart()
-    
+
     def writeStructEnd(self):
         self.writeJSONObjectEnd()
-      
+
     def writeFieldBegin(self, name, ttype, fid):
         self.writeJSONString(name)
-    
+
     def writeFieldEnd(self):
         pass
-    
+
     def writeMapBegin(self, ktype, vtype, size):
         self.writeJSONObjectStart()
-    
+
     def writeMapEnd(self):
         self.writeJSONObjectEnd()
-    
+
     def _writeCollectionBegin(self, etype, size):
         self.writeJSONArrayStart()
-    
+
     def _writeCollectionEnd(self):
         self.writeJSONArrayEnd()
     writeListBegin = _writeCollectionBegin
@@ -524,22 +642,31 @@
     writeSetBegin = _writeCollectionBegin
     writeSetEnd = _writeCollectionEnd
 
-    def writeInteger(self, integer):
-        self.writeJSONNumber(integer)
-    writeByte = writeInteger
-    writeI16 = writeInteger
-    writeI32 = writeInteger
-    writeI64 = writeInteger
-    
+    def writeByte(self, byte):
+        checkIntegerLimits(byte, 8)
+        self.writeJSONNumber(byte)
+
+    def writeI16(self, i16):
+        checkIntegerLimits(i16, 16)
+        self.writeJSONNumber(i16)
+
+    def writeI32(self, i32):
+        checkIntegerLimits(i32, 32)
+        self.writeJSONNumber(i32)
+
+    def writeI64(self, i64):
+        checkIntegerLimits(i64, 64)
+        self.writeJSONNumber(i64)
+
     def writeBool(self, boolean):
         self.writeJSONNumber(1 if boolean is True else 0)
 
     def writeDouble(self, dbl):
         self.writeJSONNumber(dbl)
-    
+
     def writeString(self, string):
         self.writeJSONString(string)
-      
+
     def writeBinary(self, binary):
         self.writeJSONBase64(binary)
 
diff --git a/lib/py/src/protocol/TMultiplexedProtocol.py b/lib/py/src/protocol/TMultiplexedProtocol.py
new file mode 100644
index 0000000..0f8390f
--- /dev/null
+++ b/lib/py/src/protocol/TMultiplexedProtocol.py
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+
+from thrift.Thrift import TMessageType
+from thrift.protocol import TProtocolDecorator
+
+SEPARATOR = ":"
+
+
+class TMultiplexedProtocol(TProtocolDecorator.TProtocolDecorator):
+    def __init__(self, protocol, serviceName):
+        self.serviceName = serviceName
+
+    def writeMessageBegin(self, name, type, seqid):
+        if (type == TMessageType.CALL or
+                type == TMessageType.ONEWAY):
+            super(TMultiplexedProtocol, self).writeMessageBegin(
+                self.serviceName + SEPARATOR + name,
+                type,
+                seqid
+            )
+        else:
+            super(TMultiplexedProtocol, self).writeMessageBegin(name, type, seqid)
diff --git a/lib/py/src/protocol/TProtocol.py b/lib/py/src/protocol/TProtocol.py
index dc2b095..8314cf6 100644
--- a/lib/py/src/protocol/TProtocol.py
+++ b/lib/py/src/protocol/TProtocol.py
@@ -17,390 +17,404 @@
 # under the License.
 #
 
-from thrift.Thrift import *
+from thrift.Thrift import TException, TType, TFrozenDict
+from thrift.transport.TTransport import TTransportException
+from ..compat import binary_to_str, str_to_binary
+
+import six
+import sys
+from itertools import islice
+from six.moves import zip
 
 
 class TProtocolException(TException):
-  """Custom Protocol Exception class"""
+    """Custom Protocol Exception class"""
 
-  UNKNOWN = 0
-  INVALID_DATA = 1
-  NEGATIVE_SIZE = 2
-  SIZE_LIMIT = 3
-  BAD_VERSION = 4
+    UNKNOWN = 0
+    INVALID_DATA = 1
+    NEGATIVE_SIZE = 2
+    SIZE_LIMIT = 3
+    BAD_VERSION = 4
+    NOT_IMPLEMENTED = 5
+    DEPTH_LIMIT = 6
+    INVALID_PROTOCOL = 7
 
-  def __init__(self, type=UNKNOWN, message=None):
-    TException.__init__(self, message)
-    self.type = type
+    def __init__(self, type=UNKNOWN, message=None):
+        TException.__init__(self, message)
+        self.type = type
 
 
-class TProtocolBase:
-  """Base class for Thrift protocol driver."""
+class TProtocolBase(object):
+    """Base class for Thrift protocol driver."""
 
-  def __init__(self, trans):
-    self.trans = trans
+    def __init__(self, trans):
+        self.trans = trans
+        self._fast_decode = None
+        self._fast_encode = None
 
-  def writeMessageBegin(self, name, ttype, seqid):
-    pass
+    @staticmethod
+    def _check_length(limit, length):
+        if length < 0:
+            raise TTransportException(TTransportException.NEGATIVE_SIZE,
+                                      'Negative length: %d' % length)
+        if limit is not None and length > limit:
+            raise TTransportException(TTransportException.SIZE_LIMIT,
+                                      'Length exceeded max allowed: %d' % limit)
 
-  def writeMessageEnd(self):
-    pass
+    def writeMessageBegin(self, name, ttype, seqid):
+        pass
 
-  def writeStructBegin(self, name):
-    pass
+    def writeMessageEnd(self):
+        pass
 
-  def writeStructEnd(self):
-    pass
+    def writeStructBegin(self, name):
+        pass
 
-  def writeFieldBegin(self, name, ttype, fid):
-    pass
+    def writeStructEnd(self):
+        pass
 
-  def writeFieldEnd(self):
-    pass
+    def writeFieldBegin(self, name, ttype, fid):
+        pass
 
-  def writeFieldStop(self):
-    pass
+    def writeFieldEnd(self):
+        pass
 
-  def writeMapBegin(self, ktype, vtype, size):
-    pass
+    def writeFieldStop(self):
+        pass
 
-  def writeMapEnd(self):
-    pass
+    def writeMapBegin(self, ktype, vtype, size):
+        pass
 
-  def writeListBegin(self, etype, size):
-    pass
+    def writeMapEnd(self):
+        pass
 
-  def writeListEnd(self):
-    pass
+    def writeListBegin(self, etype, size):
+        pass
 
-  def writeSetBegin(self, etype, size):
-    pass
+    def writeListEnd(self):
+        pass
 
-  def writeSetEnd(self):
-    pass
+    def writeSetBegin(self, etype, size):
+        pass
 
-  def writeBool(self, bool_val):
-    pass
+    def writeSetEnd(self):
+        pass
 
-  def writeByte(self, byte):
-    pass
+    def writeBool(self, bool_val):
+        pass
 
-  def writeI16(self, i16):
-    pass
+    def writeByte(self, byte):
+        pass
 
-  def writeI32(self, i32):
-    pass
+    def writeI16(self, i16):
+        pass
 
-  def writeI64(self, i64):
-    pass
+    def writeI32(self, i32):
+        pass
 
-  def writeDouble(self, dub):
-    pass
+    def writeI64(self, i64):
+        pass
 
-  def writeString(self, str_val):
-    pass
+    def writeDouble(self, dub):
+        pass
 
-  def readMessageBegin(self):
-    pass
+    def writeString(self, str_val):
+        self.writeBinary(str_to_binary(str_val))
 
-  def readMessageEnd(self):
-    pass
+    def writeBinary(self, str_val):
+        pass
 
-  def readStructBegin(self):
-    pass
+    def writeUtf8(self, str_val):
+        self.writeString(str_val.encode('utf8'))
 
-  def readStructEnd(self):
-    pass
+    def readMessageBegin(self):
+        pass
 
-  def readFieldBegin(self):
-    pass
+    def readMessageEnd(self):
+        pass
 
-  def readFieldEnd(self):
-    pass
+    def readStructBegin(self):
+        pass
 
-  def readMapBegin(self):
-    pass
+    def readStructEnd(self):
+        pass
 
-  def readMapEnd(self):
-    pass
+    def readFieldBegin(self):
+        pass
 
-  def readListBegin(self):
-    pass
+    def readFieldEnd(self):
+        pass
 
-  def readListEnd(self):
-    pass
+    def readMapBegin(self):
+        pass
 
-  def readSetBegin(self):
-    pass
+    def readMapEnd(self):
+        pass
 
-  def readSetEnd(self):
-    pass
+    def readListBegin(self):
+        pass
 
-  def readBool(self):
-    pass
+    def readListEnd(self):
+        pass
 
-  def readByte(self):
-    pass
+    def readSetBegin(self):
+        pass
 
-  def readI16(self):
-    pass
+    def readSetEnd(self):
+        pass
 
-  def readI32(self):
-    pass
+    def readBool(self):
+        pass
 
-  def readI64(self):
-    pass
+    def readByte(self):
+        pass
 
-  def readDouble(self):
-    pass
+    def readI16(self):
+        pass
 
-  def readString(self):
-    pass
+    def readI32(self):
+        pass
 
-  def skip(self, ttype):
-    if ttype == TType.STOP:
-      return
-    elif ttype == TType.BOOL:
-      self.readBool()
-    elif ttype == TType.BYTE:
-      self.readByte()
-    elif ttype == TType.I16:
-      self.readI16()
-    elif ttype == TType.I32:
-      self.readI32()
-    elif ttype == TType.I64:
-      self.readI64()
-    elif ttype == TType.DOUBLE:
-      self.readDouble()
-    elif ttype == TType.STRING:
-      self.readString()
-    elif ttype == TType.STRUCT:
-      name = self.readStructBegin()
-      while True:
-        (name, ttype, id) = self.readFieldBegin()
+    def readI64(self):
+        pass
+
+    def readDouble(self):
+        pass
+
+    def readString(self):
+        return binary_to_str(self.readBinary())
+
+    def readBinary(self):
+        pass
+
+    def readUtf8(self):
+        return self.readString().decode('utf8')
+
+    def skip(self, ttype):
         if ttype == TType.STOP:
-          break
-        self.skip(ttype)
-        self.readFieldEnd()
-      self.readStructEnd()
-    elif ttype == TType.MAP:
-      (ktype, vtype, size) = self.readMapBegin()
-      for i in xrange(size):
-        self.skip(ktype)
-        self.skip(vtype)
-      self.readMapEnd()
-    elif ttype == TType.SET:
-      (etype, size) = self.readSetBegin()
-      for i in xrange(size):
-        self.skip(etype)
-      self.readSetEnd()
-    elif ttype == TType.LIST:
-      (etype, size) = self.readListBegin()
-      for i in xrange(size):
-        self.skip(etype)
-      self.readListEnd()
+            return
+        elif ttype == TType.BOOL:
+            self.readBool()
+        elif ttype == TType.BYTE:
+            self.readByte()
+        elif ttype == TType.I16:
+            self.readI16()
+        elif ttype == TType.I32:
+            self.readI32()
+        elif ttype == TType.I64:
+            self.readI64()
+        elif ttype == TType.DOUBLE:
+            self.readDouble()
+        elif ttype == TType.STRING:
+            self.readString()
+        elif ttype == TType.STRUCT:
+            name = self.readStructBegin()
+            while True:
+                (name, ttype, id) = self.readFieldBegin()
+                if ttype == TType.STOP:
+                    break
+                self.skip(ttype)
+                self.readFieldEnd()
+            self.readStructEnd()
+        elif ttype == TType.MAP:
+            (ktype, vtype, size) = self.readMapBegin()
+            for i in range(size):
+                self.skip(ktype)
+                self.skip(vtype)
+            self.readMapEnd()
+        elif ttype == TType.SET:
+            (etype, size) = self.readSetBegin()
+            for i in range(size):
+                self.skip(etype)
+            self.readSetEnd()
+        elif ttype == TType.LIST:
+            (etype, size) = self.readListBegin()
+            for i in range(size):
+                self.skip(etype)
+            self.readListEnd()
 
-  # tuple of: ( 'reader method' name, is_container bool, 'writer_method' name )
-  _TTYPE_HANDLERS = (
-       (None, None, False),  # 0 TType.STOP
-       (None, None, False),  # 1 TType.VOID # TODO: handle void?
-       ('readBool', 'writeBool', False),  # 2 TType.BOOL
-       ('readByte',  'writeByte', False),  # 3 TType.BYTE and I08
-       ('readDouble', 'writeDouble', False),  # 4 TType.DOUBLE
-       (None, None, False),  # 5 undefined
-       ('readI16', 'writeI16', False),  # 6 TType.I16
-       (None, None, False),  # 7 undefined
-       ('readI32', 'writeI32', False),  # 8 TType.I32
-       (None, None, False),  # 9 undefined
-       ('readI64', 'writeI64', False),  # 10 TType.I64
-       ('readString', 'writeString', False),  # 11 TType.STRING and UTF7
-       ('readContainerStruct', 'writeContainerStruct', True),  # 12 *.STRUCT
-       ('readContainerMap', 'writeContainerMap', True),  # 13 TType.MAP
-       ('readContainerSet', 'writeContainerSet', True),  # 14 TType.SET
-       ('readContainerList', 'writeContainerList', True),  # 15 TType.LIST
-       (None, None, False),  # 16 TType.UTF8 # TODO: handle utf8 types?
-       (None, None, False)  # 17 TType.UTF16 # TODO: handle utf16 types?
-      )
+    # tuple of: ( 'reader method' name, is_container bool, 'writer_method' name )
+    _TTYPE_HANDLERS = (
+        (None, None, False),  # 0 TType.STOP
+        (None, None, False),  # 1 TType.VOID # TODO: handle void?
+        ('readBool', 'writeBool', False),  # 2 TType.BOOL
+        ('readByte', 'writeByte', False),  # 3 TType.BYTE and I08
+        ('readDouble', 'writeDouble', False),  # 4 TType.DOUBLE
+        (None, None, False),  # 5 undefined
+        ('readI16', 'writeI16', False),  # 6 TType.I16
+        (None, None, False),  # 7 undefined
+        ('readI32', 'writeI32', False),  # 8 TType.I32
+        (None, None, False),  # 9 undefined
+        ('readI64', 'writeI64', False),  # 10 TType.I64
+        ('readString', 'writeString', False),  # 11 TType.STRING and UTF7
+        ('readContainerStruct', 'writeContainerStruct', True),  # 12 *.STRUCT
+        ('readContainerMap', 'writeContainerMap', True),  # 13 TType.MAP
+        ('readContainerSet', 'writeContainerSet', True),  # 14 TType.SET
+        ('readContainerList', 'writeContainerList', True),  # 15 TType.LIST
+        (None, None, False),  # 16 TType.UTF8 # TODO: handle utf8 types?
+        (None, None, False)  # 17 TType.UTF16 # TODO: handle utf16 types?
+    )
 
-  def readFieldByTType(self, ttype, spec):
-    try:
-      (r_handler, w_handler, is_container) = self._TTYPE_HANDLERS[ttype]
-    except IndexError:
-      raise TProtocolException(type=TProtocolException.INVALID_DATA,
-                               message='Invalid field type %d' % (ttype))
-    if r_handler is None:
-      raise TProtocolException(type=TProtocolException.INVALID_DATA,
-                               message='Invalid field type %d' % (ttype))
-    reader = getattr(self, r_handler)
-    if not is_container:
-      return reader()
-    return reader(spec)
+    def _ttype_handlers(self, ttype, spec):
+        if spec == 'BINARY':
+            if ttype != TType.STRING:
+                raise TProtocolException(type=TProtocolException.INVALID_DATA,
+                                         message='Invalid binary field type %d' % ttype)
+            return ('readBinary', 'writeBinary', False)
+        if sys.version_info[0] == 2 and spec == 'UTF8':
+            if ttype != TType.STRING:
+                raise TProtocolException(type=TProtocolException.INVALID_DATA,
+                                         message='Invalid string field type %d' % ttype)
+            return ('readUtf8', 'writeUtf8', False)
+        return self._TTYPE_HANDLERS[ttype] if ttype < len(self._TTYPE_HANDLERS) else (None, None, False)
 
-  def readContainerList(self, spec):
-    results = []
-    ttype, tspec = spec[0], spec[1]
-    r_handler = self._TTYPE_HANDLERS[ttype][0]
-    reader = getattr(self, r_handler)
-    (list_type, list_len) = self.readListBegin()
-    if tspec is None:
-      # list values are simple types
-      for idx in xrange(list_len):
-        results.append(reader())
-    else:
-      # this is like an inlined readFieldByTType
-      container_reader = self._TTYPE_HANDLERS[list_type][0]
-      val_reader = getattr(self, container_reader)
-      for idx in xrange(list_len):
-        val = val_reader(tspec)
-        results.append(val)
-    self.readListEnd()
-    return results
+    def _read_by_ttype(self, ttype, spec, espec):
+        reader_name, _, is_container = self._ttype_handlers(ttype, espec)
+        if reader_name is None:
+            raise TProtocolException(type=TProtocolException.INVALID_DATA,
+                                     message='Invalid type %d' % (ttype))
+        reader_func = getattr(self, reader_name)
+        read = (lambda: reader_func(espec)) if is_container else reader_func
+        while True:
+            yield read()
 
-  def readContainerSet(self, spec):
-    results = set()
-    ttype, tspec = spec[0], spec[1]
-    r_handler = self._TTYPE_HANDLERS[ttype][0]
-    reader = getattr(self, r_handler)
-    (set_type, set_len) = self.readSetBegin()
-    if tspec is None:
-      # set members are simple types
-      for idx in xrange(set_len):
-        results.add(reader())
-    else:
-      container_reader = self._TTYPE_HANDLERS[set_type][0]
-      val_reader = getattr(self, container_reader)
-      for idx in xrange(set_len):
-        results.add(val_reader(tspec))
-    self.readSetEnd()
-    return results
+    def readFieldByTType(self, ttype, spec):
+        return next(self._read_by_ttype(ttype, spec, spec))
 
-  def readContainerStruct(self, spec):
-    (obj_class, obj_spec) = spec
-    obj = obj_class()
-    obj.read(self)
-    return obj
+    def readContainerList(self, spec):
+        ttype, tspec, is_immutable = spec
+        (list_type, list_len) = self.readListBegin()
+        # TODO: compare types we just decoded with thrift_spec
+        elems = islice(self._read_by_ttype(ttype, spec, tspec), list_len)
+        results = (tuple if is_immutable else list)(elems)
+        self.readListEnd()
+        return results
 
-  def readContainerMap(self, spec):
-    results = dict()
-    key_ttype, key_spec = spec[0], spec[1]
-    val_ttype, val_spec = spec[2], spec[3]
-    (map_ktype, map_vtype, map_len) = self.readMapBegin()
-    # TODO: compare types we just decoded with thrift_spec and
-    # abort/skip if types disagree
-    key_reader = getattr(self, self._TTYPE_HANDLERS[key_ttype][0])
-    val_reader = getattr(self, self._TTYPE_HANDLERS[val_ttype][0])
-    # list values are simple types
-    for idx in xrange(map_len):
-      if key_spec is None:
-        k_val = key_reader()
-      else:
-        k_val = self.readFieldByTType(key_ttype, key_spec)
-      if val_spec is None:
-        v_val = val_reader()
-      else:
-        v_val = self.readFieldByTType(val_ttype, val_spec)
-      # this raises a TypeError with unhashable keys types
-      # i.e. this fails: d=dict(); d[[0,1]] = 2
-      results[k_val] = v_val
-    self.readMapEnd()
-    return results
+    def readContainerSet(self, spec):
+        ttype, tspec, is_immutable = spec
+        (set_type, set_len) = self.readSetBegin()
+        # TODO: compare types we just decoded with thrift_spec
+        elems = islice(self._read_by_ttype(ttype, spec, tspec), set_len)
+        results = (frozenset if is_immutable else set)(elems)
+        self.readSetEnd()
+        return results
 
-  def readStruct(self, obj, thrift_spec):
-    self.readStructBegin()
-    while True:
-      (fname, ftype, fid) = self.readFieldBegin()
-      if ftype == TType.STOP:
-        break
-      try:
-        field = thrift_spec[fid]
-      except IndexError:
-        self.skip(ftype)
-      else:
-        if field is not None and ftype == field[1]:
-          fname = field[2]
-          fspec = field[3]
-          val = self.readFieldByTType(ftype, fspec)
-          setattr(obj, fname, val)
-        else:
-          self.skip(ftype)
-      self.readFieldEnd()
-    self.readStructEnd()
+    def readContainerStruct(self, spec):
+        (obj_class, obj_spec) = spec
+        obj = obj_class()
+        obj.read(self)
+        return obj
 
-  def writeContainerStruct(self, val, spec):
-    val.write(self)
+    def readContainerMap(self, spec):
+        ktype, kspec, vtype, vspec, is_immutable = spec
+        (map_ktype, map_vtype, map_len) = self.readMapBegin()
+        # TODO: compare types we just decoded with thrift_spec and
+        # abort/skip if types disagree
+        keys = self._read_by_ttype(ktype, spec, kspec)
+        vals = self._read_by_ttype(vtype, spec, vspec)
+        keyvals = islice(zip(keys, vals), map_len)
+        results = (TFrozenDict if is_immutable else dict)(keyvals)
+        self.readMapEnd()
+        return results
 
-  def writeContainerList(self, val, spec):
-    self.writeListBegin(spec[0], len(val))
-    r_handler, w_handler, is_container = self._TTYPE_HANDLERS[spec[0]]
-    e_writer = getattr(self, w_handler)
-    if not is_container:
-      for elem in val:
-        e_writer(elem)
-    else:
-      for elem in val:
-        e_writer(elem, spec[1])
-    self.writeListEnd()
+    def readStruct(self, obj, thrift_spec, is_immutable=False):
+        if is_immutable:
+            fields = {}
+        self.readStructBegin()
+        while True:
+            (fname, ftype, fid) = self.readFieldBegin()
+            if ftype == TType.STOP:
+                break
+            try:
+                field = thrift_spec[fid]
+            except IndexError:
+                self.skip(ftype)
+            else:
+                if field is not None and ftype == field[1]:
+                    fname = field[2]
+                    fspec = field[3]
+                    val = self.readFieldByTType(ftype, fspec)
+                    if is_immutable:
+                        fields[fname] = val
+                    else:
+                        setattr(obj, fname, val)
+                else:
+                    self.skip(ftype)
+            self.readFieldEnd()
+        self.readStructEnd()
+        if is_immutable:
+            return obj(**fields)
 
-  def writeContainerSet(self, val, spec):
-    self.writeSetBegin(spec[0], len(val))
-    r_handler, w_handler, is_container = self._TTYPE_HANDLERS[spec[0]]
-    e_writer = getattr(self, w_handler)
-    if not is_container:
-      for elem in val:
-        e_writer(elem)
-    else:
-      for elem in val:
-        e_writer(elem, spec[1])
-    self.writeSetEnd()
+    def writeContainerStruct(self, val, spec):
+        val.write(self)
 
-  def writeContainerMap(self, val, spec):
-    k_type = spec[0]
-    v_type = spec[2]
-    ignore, ktype_name, k_is_container = self._TTYPE_HANDLERS[k_type]
-    ignore, vtype_name, v_is_container = self._TTYPE_HANDLERS[v_type]
-    k_writer = getattr(self, ktype_name)
-    v_writer = getattr(self, vtype_name)
-    self.writeMapBegin(k_type, v_type, len(val))
-    for m_key, m_val in val.iteritems():
-      if not k_is_container:
-        k_writer(m_key)
-      else:
-        k_writer(m_key, spec[1])
-      if not v_is_container:
-        v_writer(m_val)
-      else:
-        v_writer(m_val, spec[3])
-    self.writeMapEnd()
+    def writeContainerList(self, val, spec):
+        ttype, tspec, _ = spec
+        self.writeListBegin(ttype, len(val))
+        for _ in self._write_by_ttype(ttype, val, spec, tspec):
+            pass
+        self.writeListEnd()
 
-  def writeStruct(self, obj, thrift_spec):
-    self.writeStructBegin(obj.__class__.__name__)
-    for field in thrift_spec:
-      if field is None:
-        continue
-      fname = field[2]
-      val = getattr(obj, fname)
-      if val is None:
-        # skip writing out unset fields
-        continue
-      fid = field[0]
-      ftype = field[1]
-      fspec = field[3]
-      # get the writer method for this value
-      self.writeFieldBegin(fname, ftype, fid)
-      self.writeFieldByTType(ftype, val, fspec)
-      self.writeFieldEnd()
-    self.writeFieldStop()
-    self.writeStructEnd()
+    def writeContainerSet(self, val, spec):
+        ttype, tspec, _ = spec
+        self.writeSetBegin(ttype, len(val))
+        for _ in self._write_by_ttype(ttype, val, spec, tspec):
+            pass
+        self.writeSetEnd()
 
-  def writeFieldByTType(self, ttype, val, spec):
-    r_handler, w_handler, is_container = self._TTYPE_HANDLERS[ttype]
-    writer = getattr(self, w_handler)
-    if is_container:
-      writer(val, spec)
-    else:
-      writer(val)
+    def writeContainerMap(self, val, spec):
+        ktype, kspec, vtype, vspec, _ = spec
+        self.writeMapBegin(ktype, vtype, len(val))
+        for _ in zip(self._write_by_ttype(ktype, six.iterkeys(val), spec, kspec),
+                     self._write_by_ttype(vtype, six.itervalues(val), spec, vspec)):
+            pass
+        self.writeMapEnd()
+
+    def writeStruct(self, obj, thrift_spec):
+        self.writeStructBegin(obj.__class__.__name__)
+        for field in thrift_spec:
+            if field is None:
+                continue
+            fname = field[2]
+            val = getattr(obj, fname)
+            if val is None:
+                # skip writing out unset fields
+                continue
+            fid = field[0]
+            ftype = field[1]
+            fspec = field[3]
+            self.writeFieldBegin(fname, ftype, fid)
+            self.writeFieldByTType(ftype, val, fspec)
+            self.writeFieldEnd()
+        self.writeFieldStop()
+        self.writeStructEnd()
+
+    def _write_by_ttype(self, ttype, vals, spec, espec):
+        _, writer_name, is_container = self._ttype_handlers(ttype, espec)
+        writer_func = getattr(self, writer_name)
+        write = (lambda v: writer_func(v, espec)) if is_container else writer_func
+        for v in vals:
+            yield write(v)
+
+    def writeFieldByTType(self, ttype, val, spec):
+        next(self._write_by_ttype(ttype, [val], spec, spec))
 
 
-class TProtocolFactory:
-  def getProtocol(self, trans):
-    pass
+def checkIntegerLimits(i, bits):
+    if bits == 8 and (i < -128 or i > 127):
+        raise TProtocolException(TProtocolException.INVALID_DATA,
+                                 "i8 requires -128 <= number <= 127")
+    elif bits == 16 and (i < -32768 or i > 32767):
+        raise TProtocolException(TProtocolException.INVALID_DATA,
+                                 "i16 requires -32768 <= number <= 32767")
+    elif bits == 32 and (i < -2147483648 or i > 2147483647):
+        raise TProtocolException(TProtocolException.INVALID_DATA,
+                                 "i32 requires -2147483648 <= number <= 2147483647")
+    elif bits == 64 and (i < -9223372036854775808 or i > 9223372036854775807):
+        raise TProtocolException(TProtocolException.INVALID_DATA,
+                                 "i64 requires -9223372036854775808 <= number <= 9223372036854775807")
+
+
+class TProtocolFactory(object):
+    def getProtocol(self, trans):
+        pass
diff --git a/lib/py/src/protocol/TProtocolDecorator.py b/lib/py/src/protocol/TProtocolDecorator.py
new file mode 100644
index 0000000..f5546c7
--- /dev/null
+++ b/lib/py/src/protocol/TProtocolDecorator.py
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+
+class TProtocolDecorator(object):
+    def __new__(cls, protocol, *args, **kwargs):
+        decorated_cls = type(''.join(['Decorated', protocol.__class__.__name__]),
+                             (cls, protocol.__class__),
+                             protocol.__dict__)
+        return object.__new__(decorated_cls)
diff --git a/lib/py/src/protocol/__init__.py b/lib/py/src/protocol/__init__.py
index 7eefb45..7148f66 100644
--- a/lib/py/src/protocol/__init__.py
+++ b/lib/py/src/protocol/__init__.py
@@ -17,4 +17,5 @@
 # under the License.
 #
 
-__all__ = ['fastbinary', 'TBase', 'TBinaryProtocol', 'TCompactProtocol', 'TJSONProtocol', 'TProtocol']
+__all__ = ['fastbinary', 'TBase', 'TBinaryProtocol', 'TCompactProtocol',
+           'TJSONProtocol', 'TProtocol']
diff --git a/lib/py/src/protocol/fastbinary.c b/lib/py/src/protocol/fastbinary.c
deleted file mode 100644
index 2ce5660..0000000
--- a/lib/py/src/protocol/fastbinary.c
+++ /dev/null
@@ -1,1219 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <Python.h>
-#include "cStringIO.h"
-#include <stdint.h>
-#ifndef _WIN32
-# include <stdbool.h>
-# include <netinet/in.h>
-#else
-# include <WinSock2.h>
-# pragma comment (lib, "ws2_32.lib")
-# define BIG_ENDIAN (4321)
-# define LITTLE_ENDIAN (1234)
-# define BYTE_ORDER LITTLE_ENDIAN
-# if defined(_MSC_VER) && _MSC_VER < 1600
-   typedef int _Bool;
-#  define bool _Bool
-#  define false 0 
-#  define true 1
-# endif
-# define inline __inline
-#endif
-
-/* Fix endianness issues on Solaris */
-#if defined (__SVR4) && defined (__sun)
- #if defined(__i386) && !defined(__i386__)
-  #define __i386__
- #endif
-
- #ifndef BIG_ENDIAN
-  #define BIG_ENDIAN (4321)
- #endif
- #ifndef LITTLE_ENDIAN
-  #define LITTLE_ENDIAN (1234)
- #endif
-
- /* I386 is LE, even on Solaris */
- #if !defined(BYTE_ORDER) && defined(__i386__)
-  #define BYTE_ORDER LITTLE_ENDIAN
- #endif
-#endif
-
-// TODO(dreiss): defval appears to be unused.  Look into removing it.
-// TODO(dreiss): Make parse_spec_args recursive, and cache the output
-//               permanently in the object.  (Malloc and orphan.)
-// TODO(dreiss): Why do we need cStringIO for reading, why not just char*?
-//               Can cStringIO let us work with a BufferedTransport?
-// TODO(dreiss): Don't ignore the rv from cwrite (maybe).
-
-/* ====== BEGIN UTILITIES ====== */
-
-#define INIT_OUTBUF_SIZE 128
-
-// Stolen out of TProtocol.h.
-// It would be a huge pain to have both get this from one place.
-typedef enum TType {
-  T_STOP       = 0,
-  T_VOID       = 1,
-  T_BOOL       = 2,
-  T_BYTE       = 3,
-  T_I08        = 3,
-  T_I16        = 6,
-  T_I32        = 8,
-  T_U64        = 9,
-  T_I64        = 10,
-  T_DOUBLE     = 4,
-  T_STRING     = 11,
-  T_UTF7       = 11,
-  T_STRUCT     = 12,
-  T_MAP        = 13,
-  T_SET        = 14,
-  T_LIST       = 15,
-  T_UTF8       = 16,
-  T_UTF16      = 17
-} TType;
-
-#ifndef __BYTE_ORDER
-# if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
-#  define __BYTE_ORDER BYTE_ORDER
-#  define __LITTLE_ENDIAN LITTLE_ENDIAN
-#  define __BIG_ENDIAN BIG_ENDIAN
-# else
-#  error "Cannot determine endianness"
-# endif
-#endif
-
-// Same comment as the enum.  Sorry.
-#if __BYTE_ORDER == __BIG_ENDIAN
-# define ntohll(n) (n)
-# define htonll(n) (n)
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
-# if defined(__GNUC__) && defined(__GLIBC__)
-#  include <byteswap.h>
-#  define ntohll(n) bswap_64(n)
-#  define htonll(n) bswap_64(n)
-# else /* GNUC & GLIBC */
-#  define ntohll(n) ( (((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32) )
-#  define htonll(n) ( (((unsigned long long)htonl(n)) << 32) + htonl(n >> 32) )
-# endif /* GNUC & GLIBC */
-#else /* __BYTE_ORDER */
-# error "Can't define htonll or ntohll!"
-#endif
-
-// Doing a benchmark shows that interning actually makes a difference, amazingly.
-#define INTERN_STRING(value) _intern_ ## value
-
-#define INT_CONV_ERROR_OCCURRED(v) ( ((v) == -1) && PyErr_Occurred() )
-#define CHECK_RANGE(v, min, max) ( ((v) <= (max)) && ((v) >= (min)) )
-
-// Py_ssize_t was not defined before Python 2.5
-#if (PY_VERSION_HEX < 0x02050000)
-typedef int Py_ssize_t;
-#endif
-
-/**
- * A cache of the spec_args for a set or list,
- * so we don't have to keep calling PyTuple_GET_ITEM.
- */
-typedef struct {
-  TType element_type;
-  PyObject* typeargs;
-} SetListTypeArgs;
-
-/**
- * A cache of the spec_args for a map,
- * so we don't have to keep calling PyTuple_GET_ITEM.
- */
-typedef struct {
-  TType ktag;
-  TType vtag;
-  PyObject* ktypeargs;
-  PyObject* vtypeargs;
-} MapTypeArgs;
-
-/**
- * A cache of the spec_args for a struct,
- * so we don't have to keep calling PyTuple_GET_ITEM.
- */
-typedef struct {
-  PyObject* klass;
-  PyObject* spec;
-} StructTypeArgs;
-
-/**
- * A cache of the item spec from a struct specification,
- * so we don't have to keep calling PyTuple_GET_ITEM.
- */
-typedef struct {
-  int tag;
-  TType type;
-  PyObject* attrname;
-  PyObject* typeargs;
-  PyObject* defval;
-} StructItemSpec;
-
-/**
- * A cache of the two key attributes of a CReadableTransport,
- * so we don't have to keep calling PyObject_GetAttr.
- */
-typedef struct {
-  PyObject* stringiobuf;
-  PyObject* refill_callable;
-} DecodeBuffer;
-
-/** Pointer to interned string to speed up attribute lookup. */
-static PyObject* INTERN_STRING(cstringio_buf);
-/** Pointer to interned string to speed up attribute lookup. */
-static PyObject* INTERN_STRING(cstringio_refill);
-
-static inline bool
-check_ssize_t_32(Py_ssize_t len) {
-  // error from getting the int
-  if (INT_CONV_ERROR_OCCURRED(len)) {
-    return false;
-  }
-  if (!CHECK_RANGE(len, 0, INT32_MAX)) {
-    PyErr_SetString(PyExc_OverflowError, "string size out of range");
-    return false;
-  }
-  return true;
-}
-
-static inline bool
-parse_pyint(PyObject* o, int32_t* ret, int32_t min, int32_t max) {
-  long val = PyInt_AsLong(o);
-
-  if (INT_CONV_ERROR_OCCURRED(val)) {
-    return false;
-  }
-  if (!CHECK_RANGE(val, min, max)) {
-    PyErr_SetString(PyExc_OverflowError, "int out of range");
-    return false;
-  }
-
-  *ret = (int32_t) val;
-  return true;
-}
-
-
-/* --- FUNCTIONS TO PARSE STRUCT SPECIFICATOINS --- */
-
-static bool
-parse_set_list_args(SetListTypeArgs* dest, PyObject* typeargs) {
-  if (PyTuple_Size(typeargs) != 2) {
-    PyErr_SetString(PyExc_TypeError, "expecting tuple of size 2 for list/set type args");
-    return false;
-  }
-
-  dest->element_type = PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 0));
-  if (INT_CONV_ERROR_OCCURRED(dest->element_type)) {
-    return false;
-  }
-
-  dest->typeargs = PyTuple_GET_ITEM(typeargs, 1);
-
-  return true;
-}
-
-static bool
-parse_map_args(MapTypeArgs* dest, PyObject* typeargs) {
-  if (PyTuple_Size(typeargs) != 4) {
-    PyErr_SetString(PyExc_TypeError, "expecting 4 arguments for typeargs to map");
-    return false;
-  }
-
-  dest->ktag = PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 0));
-  if (INT_CONV_ERROR_OCCURRED(dest->ktag)) {
-    return false;
-  }
-
-  dest->vtag = PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 2));
-  if (INT_CONV_ERROR_OCCURRED(dest->vtag)) {
-    return false;
-  }
-
-  dest->ktypeargs = PyTuple_GET_ITEM(typeargs, 1);
-  dest->vtypeargs = PyTuple_GET_ITEM(typeargs, 3);
-
-  return true;
-}
-
-static bool
-parse_struct_args(StructTypeArgs* dest, PyObject* typeargs) {
-  if (PyTuple_Size(typeargs) != 2) {
-    PyErr_SetString(PyExc_TypeError, "expecting tuple of size 2 for struct args");
-    return false;
-  }
-
-  dest->klass = PyTuple_GET_ITEM(typeargs, 0);
-  dest->spec = PyTuple_GET_ITEM(typeargs, 1);
-
-  return true;
-}
-
-static int
-parse_struct_item_spec(StructItemSpec* dest, PyObject* spec_tuple) {
-
-  // i'd like to use ParseArgs here, but it seems to be a bottleneck.
-  if (PyTuple_Size(spec_tuple) != 5) {
-    PyErr_SetString(PyExc_TypeError, "expecting 5 arguments for spec tuple");
-    return false;
-  }
-
-  dest->tag = PyInt_AsLong(PyTuple_GET_ITEM(spec_tuple, 0));
-  if (INT_CONV_ERROR_OCCURRED(dest->tag)) {
-    return false;
-  }
-
-  dest->type = PyInt_AsLong(PyTuple_GET_ITEM(spec_tuple, 1));
-  if (INT_CONV_ERROR_OCCURRED(dest->type)) {
-    return false;
-  }
-
-  dest->attrname = PyTuple_GET_ITEM(spec_tuple, 2);
-  dest->typeargs = PyTuple_GET_ITEM(spec_tuple, 3);
-  dest->defval = PyTuple_GET_ITEM(spec_tuple, 4);
-  return true;
-}
-
-/* ====== END UTILITIES ====== */
-
-
-/* ====== BEGIN WRITING FUNCTIONS ====== */
-
-/* --- LOW-LEVEL WRITING FUNCTIONS --- */
-
-static void writeByte(PyObject* outbuf, int8_t val) {
-  int8_t net = val;
-  PycStringIO->cwrite(outbuf, (char*)&net, sizeof(int8_t));
-}
-
-static void writeI16(PyObject* outbuf, int16_t val) {
-  int16_t net = (int16_t)htons(val);
-  PycStringIO->cwrite(outbuf, (char*)&net, sizeof(int16_t));
-}
-
-static void writeI32(PyObject* outbuf, int32_t val) {
-  int32_t net = (int32_t)htonl(val);
-  PycStringIO->cwrite(outbuf, (char*)&net, sizeof(int32_t));
-}
-
-static void writeI64(PyObject* outbuf, int64_t val) {
-  int64_t net = (int64_t)htonll(val);
-  PycStringIO->cwrite(outbuf, (char*)&net, sizeof(int64_t));
-}
-
-static void writeDouble(PyObject* outbuf, double dub) {
-  // Unfortunately, bitwise_cast doesn't work in C.  Bad C!
-  union {
-    double f;
-    int64_t t;
-  } transfer;
-  transfer.f = dub;
-  writeI64(outbuf, transfer.t);
-}
-
-
-/* --- MAIN RECURSIVE OUTPUT FUCNTION -- */
-
-static int
-output_val(PyObject* output, PyObject* value, TType type, PyObject* typeargs) {
-  /*
-   * Refcounting Strategy:
-   *
-   * We assume that elements of the thrift_spec tuple are not going to be
-   * mutated, so we don't ref count those at all. Other than that, we try to
-   * keep a reference to all the user-created objects while we work with them.
-   * output_val assumes that a reference is already held. The *caller* is
-   * responsible for handling references
-   */
-
-  switch (type) {
-
-  case T_BOOL: {
-    int v = PyObject_IsTrue(value);
-    if (v == -1) {
-      return false;
-    }
-
-    writeByte(output, (int8_t) v);
-    break;
-  }
-  case T_I08: {
-    int32_t val;
-
-    if (!parse_pyint(value, &val, INT8_MIN, INT8_MAX)) {
-      return false;
-    }
-
-    writeByte(output, (int8_t) val);
-    break;
-  }
-  case T_I16: {
-    int32_t val;
-
-    if (!parse_pyint(value, &val, INT16_MIN, INT16_MAX)) {
-      return false;
-    }
-
-    writeI16(output, (int16_t) val);
-    break;
-  }
-  case T_I32: {
-    int32_t val;
-
-    if (!parse_pyint(value, &val, INT32_MIN, INT32_MAX)) {
-      return false;
-    }
-
-    writeI32(output, val);
-    break;
-  }
-  case T_I64: {
-    int64_t nval = PyLong_AsLongLong(value);
-
-    if (INT_CONV_ERROR_OCCURRED(nval)) {
-      return false;
-    }
-
-    if (!CHECK_RANGE(nval, INT64_MIN, INT64_MAX)) {
-      PyErr_SetString(PyExc_OverflowError, "int out of range");
-      return false;
-    }
-
-    writeI64(output, nval);
-    break;
-  }
-
-  case T_DOUBLE: {
-    double nval = PyFloat_AsDouble(value);
-    if (nval == -1.0 && PyErr_Occurred()) {
-      return false;
-    }
-
-    writeDouble(output, nval);
-    break;
-  }
-
-  case T_STRING: {
-    Py_ssize_t len = PyString_Size(value);
-
-    if (!check_ssize_t_32(len)) {
-      return false;
-    }
-
-    writeI32(output, (int32_t) len);
-    PycStringIO->cwrite(output, PyString_AsString(value), (int32_t) len);
-    break;
-  }
-
-  case T_LIST:
-  case T_SET: {
-    Py_ssize_t len;
-    SetListTypeArgs parsedargs;
-    PyObject *item;
-    PyObject *iterator;
-
-    if (!parse_set_list_args(&parsedargs, typeargs)) {
-      return false;
-    }
-
-    len = PyObject_Length(value);
-
-    if (!check_ssize_t_32(len)) {
-      return false;
-    }
-
-    writeByte(output, parsedargs.element_type);
-    writeI32(output, (int32_t) len);
-
-    iterator =  PyObject_GetIter(value);
-    if (iterator == NULL) {
-      return false;
-    }
-
-    while ((item = PyIter_Next(iterator))) {
-      if (!output_val(output, item, parsedargs.element_type, parsedargs.typeargs)) {
-        Py_DECREF(item);
-        Py_DECREF(iterator);
-        return false;
-      }
-      Py_DECREF(item);
-    }
-
-    Py_DECREF(iterator);
-
-    if (PyErr_Occurred()) {
-      return false;
-    }
-
-    break;
-  }
-
-  case T_MAP: {
-    PyObject *k, *v;
-    Py_ssize_t pos = 0;
-    Py_ssize_t len;
-
-    MapTypeArgs parsedargs;
-
-    len = PyDict_Size(value);
-    if (!check_ssize_t_32(len)) {
-      return false;
-    }
-
-    if (!parse_map_args(&parsedargs, typeargs)) {
-      return false;
-    }
-
-    writeByte(output, parsedargs.ktag);
-    writeByte(output, parsedargs.vtag);
-    writeI32(output, len);
-
-    // TODO(bmaurer): should support any mapping, not just dicts
-    while (PyDict_Next(value, &pos, &k, &v)) {
-      // TODO(dreiss): Think hard about whether these INCREFs actually
-      //               turn any unsafe scenarios into safe scenarios.
-      Py_INCREF(k);
-      Py_INCREF(v);
-
-      if (!output_val(output, k, parsedargs.ktag, parsedargs.ktypeargs)
-          || !output_val(output, v, parsedargs.vtag, parsedargs.vtypeargs)) {
-        Py_DECREF(k);
-        Py_DECREF(v);
-        return false;
-      }
-      Py_DECREF(k);
-      Py_DECREF(v);
-    }
-    break;
-  }
-
-  // TODO(dreiss): Consider breaking this out as a function
-  //               the way we did for decode_struct.
-  case T_STRUCT: {
-    StructTypeArgs parsedargs;
-    Py_ssize_t nspec;
-    Py_ssize_t i;
-
-    if (!parse_struct_args(&parsedargs, typeargs)) {
-      return false;
-    }
-
-    nspec = PyTuple_Size(parsedargs.spec);
-
-    if (nspec == -1) {
-      return false;
-    }
-
-    for (i = 0; i < nspec; i++) {
-      StructItemSpec parsedspec;
-      PyObject* spec_tuple;
-      PyObject* instval = NULL;
-
-      spec_tuple = PyTuple_GET_ITEM(parsedargs.spec, i);
-      if (spec_tuple == Py_None) {
-        continue;
-      }
-
-      if (!parse_struct_item_spec (&parsedspec, spec_tuple)) {
-        return false;
-      }
-
-      instval = PyObject_GetAttr(value, parsedspec.attrname);
-
-      if (!instval) {
-        return false;
-      }
-
-      if (instval == Py_None) {
-        Py_DECREF(instval);
-        continue;
-      }
-
-      writeByte(output, (int8_t) parsedspec.type);
-      writeI16(output, parsedspec.tag);
-
-      if (!output_val(output, instval, parsedspec.type, parsedspec.typeargs)) {
-        Py_DECREF(instval);
-        return false;
-      }
-
-      Py_DECREF(instval);
-    }
-
-    writeByte(output, (int8_t)T_STOP);
-    break;
-  }
-
-  case T_STOP:
-  case T_VOID:
-  case T_UTF16:
-  case T_UTF8:
-  case T_U64:
-  default:
-    PyErr_SetString(PyExc_TypeError, "Unexpected TType");
-    return false;
-
-  }
-
-  return true;
-}
-
-
-/* --- TOP-LEVEL WRAPPER FOR OUTPUT -- */
-
-static PyObject *
-encode_binary(PyObject *self, PyObject *args) {
-  PyObject* enc_obj;
-  PyObject* type_args;
-  PyObject* buf;
-  PyObject* ret = NULL;
-
-  if (!PyArg_ParseTuple(args, "OO", &enc_obj, &type_args)) {
-    return NULL;
-  }
-
-  buf = PycStringIO->NewOutput(INIT_OUTBUF_SIZE);
-  if (output_val(buf, enc_obj, T_STRUCT, type_args)) {
-    ret = PycStringIO->cgetvalue(buf);
-  }
-
-  Py_DECREF(buf);
-  return ret;
-}
-
-/* ====== END WRITING FUNCTIONS ====== */
-
-
-/* ====== BEGIN READING FUNCTIONS ====== */
-
-/* --- LOW-LEVEL READING FUNCTIONS --- */
-
-static void
-free_decodebuf(DecodeBuffer* d) {
-  Py_XDECREF(d->stringiobuf);
-  Py_XDECREF(d->refill_callable);
-}
-
-static bool
-decode_buffer_from_obj(DecodeBuffer* dest, PyObject* obj) {
-  dest->stringiobuf = PyObject_GetAttr(obj, INTERN_STRING(cstringio_buf));
-  if (!dest->stringiobuf) {
-    return false;
-  }
-
-  if (!PycStringIO_InputCheck(dest->stringiobuf)) {
-    free_decodebuf(dest);
-    PyErr_SetString(PyExc_TypeError, "expecting stringio input");
-    return false;
-  }
-
-  dest->refill_callable = PyObject_GetAttr(obj, INTERN_STRING(cstringio_refill));
-
-  if(!dest->refill_callable) {
-    free_decodebuf(dest);
-    return false;
-  }
-
-  if (!PyCallable_Check(dest->refill_callable)) {
-    free_decodebuf(dest);
-    PyErr_SetString(PyExc_TypeError, "expecting callable");
-    return false;
-  }
-
-  return true;
-}
-
-static bool readBytes(DecodeBuffer* input, char** output, int len) {
-  int read;
-
-  // TODO(dreiss): Don't fear the malloc.  Think about taking a copy of
-  //               the partial read instead of forcing the transport
-  //               to prepend it to its buffer.
-
-  read = PycStringIO->cread(input->stringiobuf, output, len);
-
-  if (read == len) {
-    return true;
-  } else if (read == -1) {
-    return false;
-  } else {
-    PyObject* newiobuf;
-
-    // using building functions as this is a rare codepath
-    newiobuf = PyObject_CallFunction(
-        input->refill_callable, "s#i", *output, read, len, NULL);
-    if (newiobuf == NULL) {
-      return false;
-    }
-
-    // must do this *AFTER* the call so that we don't deref the io buffer
-    Py_CLEAR(input->stringiobuf);
-    input->stringiobuf = newiobuf;
-
-    read = PycStringIO->cread(input->stringiobuf, output, len);
-
-    if (read == len) {
-      return true;
-    } else if (read == -1) {
-      return false;
-    } else {
-      // TODO(dreiss): This could be a valid code path for big binary blobs.
-      PyErr_SetString(PyExc_TypeError,
-          "refill claimed to have refilled the buffer, but didn't!!");
-      return false;
-    }
-  }
-}
-
-static int8_t readByte(DecodeBuffer* input) {
-  char* buf;
-  if (!readBytes(input, &buf, sizeof(int8_t))) {
-    return -1;
-  }
-
-  return *(int8_t*) buf;
-}
-
-static int16_t readI16(DecodeBuffer* input) {
-  char* buf;
-  if (!readBytes(input, &buf, sizeof(int16_t))) {
-    return -1;
-  }
-
-  return (int16_t) ntohs(*(int16_t*) buf);
-}
-
-static int32_t readI32(DecodeBuffer* input) {
-  char* buf;
-  if (!readBytes(input, &buf, sizeof(int32_t))) {
-    return -1;
-  }
-  return (int32_t) ntohl(*(int32_t*) buf);
-}
-
-
-static int64_t readI64(DecodeBuffer* input) {
-  char* buf;
-  if (!readBytes(input, &buf, sizeof(int64_t))) {
-    return -1;
-  }
-
-  return (int64_t) ntohll(*(int64_t*) buf);
-}
-
-static double readDouble(DecodeBuffer* input) {
-  union {
-    int64_t f;
-    double t;
-  } transfer;
-
-  transfer.f = readI64(input);
-  if (transfer.f == -1) {
-    return -1;
-  }
-  return transfer.t;
-}
-
-static bool
-checkTypeByte(DecodeBuffer* input, TType expected) {
-  TType got = readByte(input);
-  if (INT_CONV_ERROR_OCCURRED(got)) {
-    return false;
-  }
-
-  if (expected != got) {
-    PyErr_SetString(PyExc_TypeError, "got wrong ttype while reading field");
-    return false;
-  }
-  return true;
-}
-
-static bool
-skip(DecodeBuffer* input, TType type) {
-#define SKIPBYTES(n) \
-  do { \
-    if (!readBytes(input, &dummy_buf, (n))) { \
-      return false; \
-    } \
-  } while(0)
-
-  char* dummy_buf;
-
-  switch (type) {
-
-  case T_BOOL:
-  case T_I08: SKIPBYTES(1); break;
-  case T_I16: SKIPBYTES(2); break;
-  case T_I32: SKIPBYTES(4); break;
-  case T_I64:
-  case T_DOUBLE: SKIPBYTES(8); break;
-
-  case T_STRING: {
-    // TODO(dreiss): Find out if these check_ssize_t32s are really necessary.
-    int len = readI32(input);
-    if (!check_ssize_t_32(len)) {
-      return false;
-    }
-    SKIPBYTES(len);
-    break;
-  }
-
-  case T_LIST:
-  case T_SET: {
-    TType etype;
-    int len, i;
-
-    etype = readByte(input);
-    if (etype == -1) {
-      return false;
-    }
-
-    len = readI32(input);
-    if (!check_ssize_t_32(len)) {
-      return false;
-    }
-
-    for (i = 0; i < len; i++) {
-      if (!skip(input, etype)) {
-        return false;
-      }
-    }
-    break;
-  }
-
-  case T_MAP: {
-    TType ktype, vtype;
-    int len, i;
-
-    ktype = readByte(input);
-    if (ktype == -1) {
-      return false;
-    }
-
-    vtype = readByte(input);
-    if (vtype == -1) {
-      return false;
-    }
-
-    len = readI32(input);
-    if (!check_ssize_t_32(len)) {
-      return false;
-    }
-
-    for (i = 0; i < len; i++) {
-      if (!(skip(input, ktype) && skip(input, vtype))) {
-        return false;
-      }
-    }
-    break;
-  }
-
-  case T_STRUCT: {
-    while (true) {
-      TType type;
-
-      type = readByte(input);
-      if (type == -1) {
-        return false;
-      }
-
-      if (type == T_STOP)
-        break;
-
-      SKIPBYTES(2); // tag
-      if (!skip(input, type)) {
-        return false;
-      }
-    }
-    break;
-  }
-
-  case T_STOP:
-  case T_VOID:
-  case T_UTF16:
-  case T_UTF8:
-  case T_U64:
-  default:
-    PyErr_SetString(PyExc_TypeError, "Unexpected TType");
-    return false;
-
-  }
-
-  return true;
-
-#undef SKIPBYTES
-}
-
-
-/* --- HELPER FUNCTION FOR DECODE_VAL --- */
-
-static PyObject*
-decode_val(DecodeBuffer* input, TType type, PyObject* typeargs);
-
-static bool
-decode_struct(DecodeBuffer* input, PyObject* output, PyObject* spec_seq) {
-  int spec_seq_len = PyTuple_Size(spec_seq);
-  if (spec_seq_len == -1) {
-    return false;
-  }
-
-  while (true) {
-    TType type;
-    int16_t tag;
-    PyObject* item_spec;
-    PyObject* fieldval = NULL;
-    StructItemSpec parsedspec;
-
-    type = readByte(input);
-    if (type == -1) {
-      return false;
-    }
-    if (type == T_STOP) {
-      break;
-    }
-    tag = readI16(input);
-    if (INT_CONV_ERROR_OCCURRED(tag)) {
-      return false;
-    }
-    if (tag >= 0 && tag < spec_seq_len) {
-      item_spec = PyTuple_GET_ITEM(spec_seq, tag);
-    } else {
-      item_spec = Py_None;
-    }
-
-    if (item_spec == Py_None) {
-      if (!skip(input, type)) {
-        return false;
-      } else {
-        continue;
-      }
-    }
-
-    if (!parse_struct_item_spec(&parsedspec, item_spec)) {
-      return false;
-    }
-    if (parsedspec.type != type) {
-      if (!skip(input, type)) {
-        PyErr_SetString(PyExc_TypeError, "struct field had wrong type while reading and can't be skipped");
-        return false;
-      } else {
-        continue;
-      }
-    }
-
-    fieldval = decode_val(input, parsedspec.type, parsedspec.typeargs);
-    if (fieldval == NULL) {
-      return false;
-    }
-
-    if (PyObject_SetAttr(output, parsedspec.attrname, fieldval) == -1) {
-      Py_DECREF(fieldval);
-      return false;
-    }
-    Py_DECREF(fieldval);
-  }
-  return true;
-}
-
-
-/* --- MAIN RECURSIVE INPUT FUCNTION --- */
-
-// Returns a new reference.
-static PyObject*
-decode_val(DecodeBuffer* input, TType type, PyObject* typeargs) {
-  switch (type) {
-
-  case T_BOOL: {
-    int8_t v = readByte(input);
-    if (INT_CONV_ERROR_OCCURRED(v)) {
-      return NULL;
-    }
-
-    switch (v) {
-    case 0: Py_RETURN_FALSE;
-    case 1: Py_RETURN_TRUE;
-    // Don't laugh.  This is a potentially serious issue.
-    default: PyErr_SetString(PyExc_TypeError, "boolean out of range"); return NULL;
-    }
-    break;
-  }
-  case T_I08: {
-    int8_t v = readByte(input);
-    if (INT_CONV_ERROR_OCCURRED(v)) {
-      return NULL;
-    }
-
-    return PyInt_FromLong(v);
-  }
-  case T_I16: {
-    int16_t v = readI16(input);
-    if (INT_CONV_ERROR_OCCURRED(v)) {
-      return NULL;
-    }
-    return PyInt_FromLong(v);
-  }
-  case T_I32: {
-    int32_t v = readI32(input);
-    if (INT_CONV_ERROR_OCCURRED(v)) {
-      return NULL;
-    }
-    return PyInt_FromLong(v);
-  }
-
-  case T_I64: {
-    int64_t v = readI64(input);
-    if (INT_CONV_ERROR_OCCURRED(v)) {
-      return NULL;
-    }
-    // TODO(dreiss): Find out if we can take this fastpath always when
-    //               sizeof(long) == sizeof(long long).
-    if (CHECK_RANGE(v, LONG_MIN, LONG_MAX)) {
-      return PyInt_FromLong((long) v);
-    }
-
-    return PyLong_FromLongLong(v);
-  }
-
-  case T_DOUBLE: {
-    double v = readDouble(input);
-    if (v == -1.0 && PyErr_Occurred()) {
-      return false;
-    }
-    return PyFloat_FromDouble(v);
-  }
-
-  case T_STRING: {
-    Py_ssize_t len = readI32(input);
-    char* buf;
-    if (!readBytes(input, &buf, len)) {
-      return NULL;
-    }
-
-    return PyString_FromStringAndSize(buf, len);
-  }
-
-  case T_LIST:
-  case T_SET: {
-    SetListTypeArgs parsedargs;
-    int32_t len;
-    PyObject* ret = NULL;
-    int i;
-
-    if (!parse_set_list_args(&parsedargs, typeargs)) {
-      return NULL;
-    }
-
-    if (!checkTypeByte(input, parsedargs.element_type)) {
-      return NULL;
-    }
-
-    len = readI32(input);
-    if (!check_ssize_t_32(len)) {
-      return NULL;
-    }
-
-    ret = PyList_New(len);
-    if (!ret) {
-      return NULL;
-    }
-
-    for (i = 0; i < len; i++) {
-      PyObject* item = decode_val(input, parsedargs.element_type, parsedargs.typeargs);
-      if (!item) {
-        Py_DECREF(ret);
-        return NULL;
-      }
-      PyList_SET_ITEM(ret, i, item);
-    }
-
-    // TODO(dreiss): Consider biting the bullet and making two separate cases
-    //               for list and set, avoiding this post facto conversion.
-    if (type == T_SET) {
-      PyObject* setret;
-#if (PY_VERSION_HEX < 0x02050000)
-      // hack needed for older versions
-      setret = PyObject_CallFunctionObjArgs((PyObject*)&PySet_Type, ret, NULL);
-#else
-      // official version
-      setret = PySet_New(ret);
-#endif
-      Py_DECREF(ret);
-      return setret;
-    }
-    return ret;
-  }
-
-  case T_MAP: {
-    int32_t len;
-    int i;
-    MapTypeArgs parsedargs;
-    PyObject* ret = NULL;
-
-    if (!parse_map_args(&parsedargs, typeargs)) {
-      return NULL;
-    }
-
-    if (!checkTypeByte(input, parsedargs.ktag)) {
-      return NULL;
-    }
-    if (!checkTypeByte(input, parsedargs.vtag)) {
-      return NULL;
-    }
-
-    len = readI32(input);
-    if (!check_ssize_t_32(len)) {
-      return false;
-    }
-
-    ret = PyDict_New();
-    if (!ret) {
-      goto error;
-    }
-
-    for (i = 0; i < len; i++) {
-      PyObject* k = NULL;
-      PyObject* v = NULL;
-      k = decode_val(input, parsedargs.ktag, parsedargs.ktypeargs);
-      if (k == NULL) {
-        goto loop_error;
-      }
-      v = decode_val(input, parsedargs.vtag, parsedargs.vtypeargs);
-      if (v == NULL) {
-        goto loop_error;
-      }
-      if (PyDict_SetItem(ret, k, v) == -1) {
-        goto loop_error;
-      }
-
-      Py_DECREF(k);
-      Py_DECREF(v);
-      continue;
-
-      // Yuck!  Destructors, anyone?
-      loop_error:
-      Py_XDECREF(k);
-      Py_XDECREF(v);
-      goto error;
-    }
-
-    return ret;
-
-    error:
-    Py_XDECREF(ret);
-    return NULL;
-  }
-
-  case T_STRUCT: {
-    StructTypeArgs parsedargs;
-	PyObject* ret;
-    if (!parse_struct_args(&parsedargs, typeargs)) {
-      return NULL;
-    }
-
-    ret = PyObject_CallObject(parsedargs.klass, NULL);
-    if (!ret) {
-      return NULL;
-    }
-
-    if (!decode_struct(input, ret, parsedargs.spec)) {
-      Py_DECREF(ret);
-      return NULL;
-    }
-
-    return ret;
-  }
-
-  case T_STOP:
-  case T_VOID:
-  case T_UTF16:
-  case T_UTF8:
-  case T_U64:
-  default:
-    PyErr_SetString(PyExc_TypeError, "Unexpected TType");
-    return NULL;
-  }
-}
-
-
-/* --- TOP-LEVEL WRAPPER FOR INPUT -- */
-
-static PyObject*
-decode_binary(PyObject *self, PyObject *args) {
-  PyObject* output_obj = NULL;
-  PyObject* transport = NULL;
-  PyObject* typeargs = NULL;
-  StructTypeArgs parsedargs;
-  DecodeBuffer input = {0, 0};
-  
-  if (!PyArg_ParseTuple(args, "OOO", &output_obj, &transport, &typeargs)) {
-    return NULL;
-  }
-
-  if (!parse_struct_args(&parsedargs, typeargs)) {
-    return NULL;
-  }
-
-  if (!decode_buffer_from_obj(&input, transport)) {
-    return NULL;
-  }
-
-  if (!decode_struct(&input, output_obj, parsedargs.spec)) {
-    free_decodebuf(&input);
-    return NULL;
-  }
-
-  free_decodebuf(&input);
-
-  Py_RETURN_NONE;
-}
-
-/* ====== END READING FUNCTIONS ====== */
-
-
-/* -- PYTHON MODULE SETUP STUFF --- */
-
-static PyMethodDef ThriftFastBinaryMethods[] = {
-
-  {"encode_binary",  encode_binary, METH_VARARGS, ""},
-  {"decode_binary",  decode_binary, METH_VARARGS, ""},
-
-  {NULL, NULL, 0, NULL}        /* Sentinel */
-};
-
-PyMODINIT_FUNC
-initfastbinary(void) {
-#define INIT_INTERN_STRING(value) \
-  do { \
-    INTERN_STRING(value) = PyString_InternFromString(#value); \
-    if(!INTERN_STRING(value)) return; \
-  } while(0)
-
-  INIT_INTERN_STRING(cstringio_buf);
-  INIT_INTERN_STRING(cstringio_refill);
-#undef INIT_INTERN_STRING
-
-  PycString_IMPORT;
-  if (PycStringIO == NULL) return;
-
-  (void) Py_InitModule("thrift.protocol.fastbinary", ThriftFastBinaryMethods);
-}
diff --git a/lib/py/src/server/THttpServer.py b/lib/py/src/server/THttpServer.py
index be54bab..85cf400 100644
--- a/lib/py/src/server/THttpServer.py
+++ b/lib/py/src/server/THttpServer.py
@@ -17,71 +17,90 @@
 # under the License.
 #
 
-import BaseHTTPServer
+import ssl
+
+from six.moves import BaseHTTPServer
 
 from thrift.server import TServer
 from thrift.transport import TTransport
 
 
 class ResponseException(Exception):
-  """Allows handlers to override the HTTP response
+    """Allows handlers to override the HTTP response
 
-  Normally, THttpServer always sends a 200 response.  If a handler wants
-  to override this behavior (e.g., to simulate a misconfigured or
-  overloaded web server during testing), it can raise a ResponseException.
-  The function passed to the constructor will be called with the
-  RequestHandler as its only argument.
-  """
-  def __init__(self, handler):
-    self.handler = handler
+    Normally, THttpServer always sends a 200 response.  If a handler wants
+    to override this behavior (e.g., to simulate a misconfigured or
+    overloaded web server during testing), it can raise a ResponseException.
+    The function passed to the constructor will be called with the
+    RequestHandler as its only argument.
+    """
+    def __init__(self, handler):
+        self.handler = handler
 
 
 class THttpServer(TServer.TServer):
-  """A simple HTTP-based Thrift server
+    """A simple HTTP-based Thrift server
 
-  This class is not very performant, but it is useful (for example) for
-  acting as a mock version of an Apache-based PHP Thrift endpoint.
-  """
-  def __init__(self,
-               processor,
-               server_address,
-               inputProtocolFactory,
-               outputProtocolFactory=None,
-               server_class=BaseHTTPServer.HTTPServer):
-    """Set up protocol factories and HTTP server.
-
-    See BaseHTTPServer for server_address.
-    See TServer for protocol factories.
+    This class is not very performant, but it is useful (for example) for
+    acting as a mock version of an Apache-based PHP Thrift endpoint.
     """
-    if outputProtocolFactory is None:
-      outputProtocolFactory = inputProtocolFactory
+    def __init__(self,
+                 processor,
+                 server_address,
+                 inputProtocolFactory,
+                 outputProtocolFactory=None,
+                 server_class=BaseHTTPServer.HTTPServer,
+                 **kwargs):
+        """Set up protocol factories and HTTP (or HTTPS) server.
 
-    TServer.TServer.__init__(self, processor, None, None, None,
-        inputProtocolFactory, outputProtocolFactory)
+        See BaseHTTPServer for server_address.
+        See TServer for protocol factories.
 
-    thttpserver = self
+        To make a secure server, provide the named arguments:
+        * cafile    - to validate clients [optional]
+        * cert_file - the server cert
+        * key_file  - the server's key
+        """
+        if outputProtocolFactory is None:
+            outputProtocolFactory = inputProtocolFactory
 
-    class RequestHander(BaseHTTPServer.BaseHTTPRequestHandler):
-      def do_POST(self):
-        # Don't care about the request path.
-        itrans = TTransport.TFileObjectTransport(self.rfile)
-        otrans = TTransport.TFileObjectTransport(self.wfile)
-        itrans = TTransport.TBufferedTransport(
-          itrans, int(self.headers['Content-Length']))
-        otrans = TTransport.TMemoryBuffer()
-        iprot = thttpserver.inputProtocolFactory.getProtocol(itrans)
-        oprot = thttpserver.outputProtocolFactory.getProtocol(otrans)
-        try:
-          thttpserver.processor.process(iprot, oprot)
-        except ResponseException, exn:
-          exn.handler(self)
-        else:
-          self.send_response(200)
-          self.send_header("content-type", "application/x-thrift")
-          self.end_headers()
-          self.wfile.write(otrans.getvalue())
+        TServer.TServer.__init__(self, processor, None, None, None,
+                                 inputProtocolFactory, outputProtocolFactory)
 
-    self.httpd = server_class(server_address, RequestHander)
+        thttpserver = self
 
-  def serve(self):
-    self.httpd.serve_forever()
+        class RequestHander(BaseHTTPServer.BaseHTTPRequestHandler):
+            def do_POST(self):
+                # Don't care about the request path.
+                itrans = TTransport.TFileObjectTransport(self.rfile)
+                otrans = TTransport.TFileObjectTransport(self.wfile)
+                itrans = TTransport.TBufferedTransport(
+                    itrans, int(self.headers['Content-Length']))
+                otrans = TTransport.TMemoryBuffer()
+                iprot = thttpserver.inputProtocolFactory.getProtocol(itrans)
+                oprot = thttpserver.outputProtocolFactory.getProtocol(otrans)
+                try:
+                    thttpserver.processor.process(iprot, oprot)
+                except ResponseException as exn:
+                    exn.handler(self)
+                else:
+                    self.send_response(200)
+                    self.send_header("content-type", "application/x-thrift")
+                    self.end_headers()
+                    self.wfile.write(otrans.getvalue())
+
+        self.httpd = server_class(server_address, RequestHander)
+
+        if (kwargs.get('cafile') or kwargs.get('cert_file') or kwargs.get('key_file')):
+            context = ssl.create_default_context(cafile=kwargs.get('cafile'))
+            context.check_hostname = False
+            context.load_cert_chain(kwargs.get('cert_file'), kwargs.get('key_file'))
+            context.verify_mode = ssl.CERT_REQUIRED if kwargs.get('cafile') else ssl.CERT_NONE
+            self.httpd.socket = context.wrap_socket(self.httpd.socket, server_side=True)
+
+    def serve(self):
+        self.httpd.serve_forever()
+
+    def shutdown(self):
+        self.httpd.socket.close()
+        # self.httpd.shutdown() # hangs forever, python doesn't handle POLLNVAL properly!
diff --git a/lib/py/src/server/TNonblockingServer.py b/lib/py/src/server/TNonblockingServer.py
index fa478d0..f62d486 100644
--- a/lib/py/src/server/TNonblockingServer.py
+++ b/lib/py/src/server/TNonblockingServer.py
@@ -24,18 +24,23 @@
 The thread poool should be sized for concurrent tasks, not
 maximum connections
 """
-import threading
-import socket
-import Queue
-import select
-import struct
+
 import logging
+import select
+import socket
+import struct
+import threading
+
+from collections import deque
+from six.moves import queue
 
 from thrift.transport import TTransport
 from thrift.protocol.TBinaryProtocol import TBinaryProtocolFactory
 
 __all__ = ['TNonblockingServer']
 
+logger = logging.getLogger(__name__)
+
 
 class Worker(threading.Thread):
     """Worker is a small helper to process incoming connection."""
@@ -54,8 +59,9 @@
                 processor.process(iprot, oprot)
                 callback(True, otrans.getvalue())
             except Exception:
-                logging.exception("Exception while processing request")
-                callback(False, '')
+                logger.exception("Exception while processing request", exc_info=True)
+                callback(False, b'')
+
 
 WAIT_LEN = 0
 WAIT_MESSAGE = 1
@@ -81,11 +87,24 @@
         try:
             return func(self, *args, **kwargs)
         except socket.error:
+            logger.debug('ignoring socket exception', exc_info=True)
             self.close()
     return read
 
 
-class Connection:
+class Message(object):
+    def __init__(self, offset, len_, header):
+        self.offset = offset
+        self.len = len_
+        self.buffer = None
+        self.is_header = header
+
+    @property
+    def end(self):
+        return self.offset + self.len
+
+
+class Connection(object):
     """Basic class is represented connection.
 
     It can be in state:
@@ -102,68 +121,60 @@
         self.socket.setblocking(False)
         self.status = WAIT_LEN
         self.len = 0
-        self.message = ''
+        self.received = deque()
+        self._reading = Message(0, 4, True)
+        self._rbuf = b''
+        self._wbuf = b''
         self.lock = threading.Lock()
         self.wake_up = wake_up
-
-    def _read_len(self):
-        """Reads length of request.
-
-        It's a safer alternative to self.socket.recv(4)
-        """
-        read = self.socket.recv(4 - len(self.message))
-        if len(read) == 0:
-            # if we read 0 bytes and self.message is empty, then
-            # the client closed the connection
-            if len(self.message) != 0:
-                logging.error("can't read frame size from socket")
-            self.close()
-            return
-        self.message += read
-        if len(self.message) == 4:
-            self.len, = struct.unpack('!i', self.message)
-            if self.len < 0:
-                logging.error("negative frame size, it seems client "
-                              "doesn't use FramedTransport")
-                self.close()
-            elif self.len == 0:
-                logging.error("empty frame, it's really strange")
-                self.close()
-            else:
-                self.message = ''
-                self.status = WAIT_MESSAGE
+        self.remaining = False
 
     @socket_exception
     def read(self):
         """Reads data from stream and switch state."""
         assert self.status in (WAIT_LEN, WAIT_MESSAGE)
-        if self.status == WAIT_LEN:
-            self._read_len()
-            # go back to the main loop here for simplicity instead of
-            # falling through, even though there is a good chance that
-            # the message is already available
-        elif self.status == WAIT_MESSAGE:
-            read = self.socket.recv(self.len - len(self.message))
-            if len(read) == 0:
-                logging.error("can't read frame from socket (get %d of "
-                              "%d bytes)" % (len(self.message), self.len))
+        assert not self.received
+        buf_size = 8192
+        first = True
+        done = False
+        while not done:
+            read = self.socket.recv(buf_size)
+            rlen = len(read)
+            done = rlen < buf_size
+            self._rbuf += read
+            if first and rlen == 0:
+                if self.status != WAIT_LEN or self._rbuf:
+                    logger.error('could not read frame from socket')
+                else:
+                    logger.debug('read zero length. client might have disconnected')
                 self.close()
-                return
-            self.message += read
-            if len(self.message) == self.len:
+            while len(self._rbuf) >= self._reading.end:
+                if self._reading.is_header:
+                    mlen, = struct.unpack('!i', self._rbuf[:4])
+                    self._reading = Message(self._reading.end, mlen, False)
+                    self.status = WAIT_MESSAGE
+                else:
+                    self._reading.buffer = self._rbuf
+                    self.received.append(self._reading)
+                    self._rbuf = self._rbuf[self._reading.end:]
+                    self._reading = Message(0, 4, True)
+            first = False
+            if self.received:
                 self.status = WAIT_PROCESS
+                break
+        self.remaining = not done
 
     @socket_exception
     def write(self):
         """Writes data from socket and switch state."""
         assert self.status == SEND_ANSWER
-        sent = self.socket.send(self.message)
-        if sent == len(self.message):
+        sent = self.socket.send(self._wbuf)
+        if sent == len(self._wbuf):
             self.status = WAIT_LEN
-            self.message = ''
+            self._wbuf = b''
             self.len = 0
         else:
-            self.message = self.message[sent:]
+            self._wbuf = self._wbuf[sent:]
 
     @locked
     def ready(self, all_ok, message):
@@ -183,13 +194,13 @@
             self.close()
             self.wake_up()
             return
-        self.len = ''
+        self.len = 0
         if len(message) == 0:
             # it was a oneway request, do not write answer
-            self.message = ''
+            self._wbuf = b''
             self.status = WAIT_LEN
         else:
-            self.message = struct.pack('!i', len(message)) + message
+            self._wbuf = struct.pack('!i', len(message)) + message
             self.status = SEND_ANSWER
         self.wake_up()
 
@@ -219,7 +230,7 @@
         self.socket.close()
 
 
-class TNonblockingServer:
+class TNonblockingServer(object):
     """Non-blocking server."""
 
     def __init__(self,
@@ -234,7 +245,7 @@
         self.out_protocol = outputProtocolFactory or self.in_protocol
         self.threads = int(threads)
         self.clients = {}
-        self.tasks = Queue.Queue()
+        self.tasks = queue.Queue()
         self._read, self._write = socket.socketpair()
         self.prepared = False
         self._stop = False
@@ -250,7 +261,7 @@
         if self.prepared:
             return
         self.socket.listen()
-        for _ in xrange(self.threads):
+        for _ in range(self.threads):
             thread = Worker(self.tasks)
             thread.setDaemon(True)
             thread.start()
@@ -259,7 +270,7 @@
     def wake_up(self):
         """Wake up main thread.
 
-        The server usualy waits in select call in we should terminate one.
+        The server usually waits in select call in we should terminate one.
         The simplest way is using socketpair.
 
         Select always wait to read from the first socket of socketpair.
@@ -267,7 +278,7 @@
         In this case, we can just write anything to the second socket from
         socketpair.
         """
-        self._write.send('1')
+        self._write.send(b'1')
 
     def stop(self):
         """Stop the server.
@@ -288,14 +299,20 @@
         """Does select on open connections."""
         readable = [self.socket.handle.fileno(), self._read.fileno()]
         writable = []
-        for i, connection in self.clients.items():
+        remaining = []
+        for i, connection in list(self.clients.items()):
             if connection.is_readable():
                 readable.append(connection.fileno())
+                if connection.remaining or connection.received:
+                    remaining.append(connection.fileno())
             if connection.is_writeable():
                 writable.append(connection.fileno())
             if connection.is_closed():
                 del self.clients[i]
-        return select.select(readable, writable, readable)
+        if remaining:
+            return remaining, [], [], False
+        else:
+            return select.select(readable, writable, readable) + (True,)
 
     def handle(self):
         """Handle requests.
@@ -303,20 +320,27 @@
         WARNING! You must call prepare() BEFORE calling handle()
         """
         assert self.prepared, "You have to call prepare before handle"
-        rset, wset, xset = self._select()
+        rset, wset, xset, selected = self._select()
         for readable in rset:
             if readable == self._read.fileno():
                 # don't care i just need to clean readable flag
                 self._read.recv(1024)
             elif readable == self.socket.handle.fileno():
-                client = self.socket.accept().handle
-                self.clients[client.fileno()] = Connection(client,
-                                                           self.wake_up)
+                try:
+                    client = self.socket.accept()
+                    if client:
+                        self.clients[client.handle.fileno()] = Connection(client.handle,
+                                                                          self.wake_up)
+                except socket.error:
+                    logger.debug('error while accepting', exc_info=True)
             else:
                 connection = self.clients[readable]
-                connection.read()
-                if connection.status == WAIT_PROCESS:
-                    itransport = TTransport.TMemoryBuffer(connection.message)
+                if selected:
+                    connection.read()
+                if connection.received:
+                    connection.status = WAIT_PROCESS
+                    msg = connection.received.popleft()
+                    itransport = TTransport.TMemoryBuffer(msg.buffer, msg.offset)
                     otransport = TTransport.TMemoryBuffer()
                     iprot = self.in_protocol.getProtocol(itransport)
                     oprot = self.out_protocol.getProtocol(otransport)
@@ -330,7 +354,7 @@
 
     def close(self):
         """Closes the server."""
-        for _ in xrange(self.threads):
+        for _ in range(self.threads):
             self.tasks.put([None, None, None, None, None])
         self.socket.close()
         self.prepared = False
diff --git a/lib/py/src/server/TProcessPoolServer.py b/lib/py/src/server/TProcessPoolServer.py
index 7a695a8..fe6dc81 100644
--- a/lib/py/src/server/TProcessPoolServer.py
+++ b/lib/py/src/server/TProcessPoolServer.py
@@ -19,11 +19,14 @@
 
 
 import logging
-from multiprocessing import  Process, Value, Condition, reduction
 
-from TServer import TServer
+from multiprocessing import Process, Value, Condition
+
+from .TServer import TServer
 from thrift.transport.TTransport import TTransportException
 
+logger = logging.getLogger(__name__)
+
 
 class TProcessPoolServer(TServer):
     """Server with a fixed size pool of worker subprocesses to service requests
@@ -56,11 +59,13 @@
         while self.isRunning.value:
             try:
                 client = self.serverTransport.accept()
+                if not client:
+                    continue
                 self.serveClient(client)
             except (KeyboardInterrupt, SystemExit):
                 return 0
-            except Exception, x:
-                logging.exception(x)
+            except Exception as x:
+                logger.exception(x)
 
     def serveClient(self, client):
         """Process input/output from a client for as long as possible"""
@@ -72,10 +77,10 @@
         try:
             while True:
                 self.processor.process(iprot, oprot)
-        except TTransportException, tx:
+        except TTransportException:
             pass
-        except Exception, x:
-            logging.exception(x)
+        except Exception as x:
+            logger.exception(x)
 
         itrans.close()
         otrans.close()
@@ -95,8 +100,8 @@
                 w.daemon = True
                 w.start()
                 self.workers.append(w)
-            except Exception, x:
-                logging.exception(x)
+            except Exception as x:
+                logger.exception(x)
 
         # wait until the condition is set by stop()
         while True:
@@ -106,8 +111,8 @@
                 break
             except (SystemExit, KeyboardInterrupt):
                 break
-            except Exception, x:
-                logging.exception(x)
+            except Exception as x:
+                logger.exception(x)
 
         self.isRunning.value = False
 
diff --git a/lib/py/src/server/TServer.py b/lib/py/src/server/TServer.py
index 2f24842..df2a7bb 100644
--- a/lib/py/src/server/TServer.py
+++ b/lib/py/src/server/TServer.py
@@ -17,253 +17,307 @@
 # under the License.
 #
 
-import Queue
+from six.moves import queue
 import logging
 import os
-import sys
 import threading
-import traceback
 
-from thrift.Thrift import TProcessor
 from thrift.protocol import TBinaryProtocol
+from thrift.protocol.THeaderProtocol import THeaderProtocolFactory
 from thrift.transport import TTransport
 
+logger = logging.getLogger(__name__)
 
-class TServer:
-  """Base interface for a server, which must have a serve() method.
 
-  Three constructors for all servers:
-  1) (processor, serverTransport)
-  2) (processor, serverTransport, transportFactory, protocolFactory)
-  3) (processor, serverTransport,
-      inputTransportFactory, outputTransportFactory,
-      inputProtocolFactory, outputProtocolFactory)
-  """
-  def __init__(self, *args):
-    if (len(args) == 2):
-      self.__initArgs__(args[0], args[1],
-                        TTransport.TTransportFactoryBase(),
-                        TTransport.TTransportFactoryBase(),
-                        TBinaryProtocol.TBinaryProtocolFactory(),
-                        TBinaryProtocol.TBinaryProtocolFactory())
-    elif (len(args) == 4):
-      self.__initArgs__(args[0], args[1], args[2], args[2], args[3], args[3])
-    elif (len(args) == 6):
-      self.__initArgs__(args[0], args[1], args[2], args[3], args[4], args[5])
+class TServer(object):
+    """Base interface for a server, which must have a serve() method.
 
-  def __initArgs__(self, processor, serverTransport,
-                   inputTransportFactory, outputTransportFactory,
-                   inputProtocolFactory, outputProtocolFactory):
-    self.processor = processor
-    self.serverTransport = serverTransport
-    self.inputTransportFactory = inputTransportFactory
-    self.outputTransportFactory = outputTransportFactory
-    self.inputProtocolFactory = inputProtocolFactory
-    self.outputProtocolFactory = outputProtocolFactory
+    Three constructors for all servers:
+    1) (processor, serverTransport)
+    2) (processor, serverTransport, transportFactory, protocolFactory)
+    3) (processor, serverTransport,
+        inputTransportFactory, outputTransportFactory,
+        inputProtocolFactory, outputProtocolFactory)
+    """
+    def __init__(self, *args):
+        if (len(args) == 2):
+            self.__initArgs__(args[0], args[1],
+                              TTransport.TTransportFactoryBase(),
+                              TTransport.TTransportFactoryBase(),
+                              TBinaryProtocol.TBinaryProtocolFactory(),
+                              TBinaryProtocol.TBinaryProtocolFactory())
+        elif (len(args) == 4):
+            self.__initArgs__(args[0], args[1], args[2], args[2], args[3], args[3])
+        elif (len(args) == 6):
+            self.__initArgs__(args[0], args[1], args[2], args[3], args[4], args[5])
 
-  def serve(self):
-    pass
+    def __initArgs__(self, processor, serverTransport,
+                     inputTransportFactory, outputTransportFactory,
+                     inputProtocolFactory, outputProtocolFactory):
+        self.processor = processor
+        self.serverTransport = serverTransport
+        self.inputTransportFactory = inputTransportFactory
+        self.outputTransportFactory = outputTransportFactory
+        self.inputProtocolFactory = inputProtocolFactory
+        self.outputProtocolFactory = outputProtocolFactory
+
+        input_is_header = isinstance(self.inputProtocolFactory, THeaderProtocolFactory)
+        output_is_header = isinstance(self.outputProtocolFactory, THeaderProtocolFactory)
+        if any((input_is_header, output_is_header)) and input_is_header != output_is_header:
+            raise ValueError("THeaderProtocol servers require that both the input and "
+                             "output protocols are THeaderProtocol.")
+
+    def serve(self):
+        pass
 
 
 class TSimpleServer(TServer):
-  """Simple single-threaded server that just pumps around one transport."""
+    """Simple single-threaded server that just pumps around one transport."""
 
-  def __init__(self, *args):
-    TServer.__init__(self, *args)
+    def __init__(self, *args):
+        TServer.__init__(self, *args)
 
-  def serve(self):
-    self.serverTransport.listen()
-    while True:
-      client = self.serverTransport.accept()
-      itrans = self.inputTransportFactory.getTransport(client)
-      otrans = self.outputTransportFactory.getTransport(client)
-      iprot = self.inputProtocolFactory.getProtocol(itrans)
-      oprot = self.outputProtocolFactory.getProtocol(otrans)
-      try:
+    def serve(self):
+        self.serverTransport.listen()
         while True:
-          self.processor.process(iprot, oprot)
-      except TTransport.TTransportException, tx:
-        pass
-      except Exception, x:
-        logging.exception(x)
+            client = self.serverTransport.accept()
+            if not client:
+                continue
 
-      itrans.close()
-      otrans.close()
+            itrans = self.inputTransportFactory.getTransport(client)
+            iprot = self.inputProtocolFactory.getProtocol(itrans)
+
+            # for THeaderProtocol, we must use the same protocol instance for
+            # input and output so that the response is in the same dialect that
+            # the server detected the request was in.
+            if isinstance(self.inputProtocolFactory, THeaderProtocolFactory):
+                otrans = None
+                oprot = iprot
+            else:
+                otrans = self.outputTransportFactory.getTransport(client)
+                oprot = self.outputProtocolFactory.getProtocol(otrans)
+
+            try:
+                while True:
+                    self.processor.process(iprot, oprot)
+            except TTransport.TTransportException:
+                pass
+            except Exception as x:
+                logger.exception(x)
+
+            itrans.close()
+            if otrans:
+                otrans.close()
 
 
 class TThreadedServer(TServer):
-  """Threaded server that spawns a new thread per each connection."""
+    """Threaded server that spawns a new thread per each connection."""
 
-  def __init__(self, *args, **kwargs):
-    TServer.__init__(self, *args)
-    self.daemon = kwargs.get("daemon", False)
+    def __init__(self, *args, **kwargs):
+        TServer.__init__(self, *args)
+        self.daemon = kwargs.get("daemon", False)
 
-  def serve(self):
-    self.serverTransport.listen()
-    while True:
-      try:
-        client = self.serverTransport.accept()
-        t = threading.Thread(target=self.handle, args=(client,))
-        t.setDaemon(self.daemon)
-        t.start()
-      except KeyboardInterrupt:
-        raise
-      except Exception, x:
-        logging.exception(x)
+    def serve(self):
+        self.serverTransport.listen()
+        while True:
+            try:
+                client = self.serverTransport.accept()
+                if not client:
+                    continue
+                t = threading.Thread(target=self.handle, args=(client,))
+                t.setDaemon(self.daemon)
+                t.start()
+            except KeyboardInterrupt:
+                raise
+            except Exception as x:
+                logger.exception(x)
 
-  def handle(self, client):
-    itrans = self.inputTransportFactory.getTransport(client)
-    otrans = self.outputTransportFactory.getTransport(client)
-    iprot = self.inputProtocolFactory.getProtocol(itrans)
-    oprot = self.outputProtocolFactory.getProtocol(otrans)
-    try:
-      while True:
-        self.processor.process(iprot, oprot)
-    except TTransport.TTransportException, tx:
-      pass
-    except Exception, x:
-      logging.exception(x)
+    def handle(self, client):
+        itrans = self.inputTransportFactory.getTransport(client)
+        iprot = self.inputProtocolFactory.getProtocol(itrans)
 
-    itrans.close()
-    otrans.close()
+        # for THeaderProtocol, we must use the same protocol instance for input
+        # and output so that the response is in the same dialect that the
+        # server detected the request was in.
+        if isinstance(self.inputProtocolFactory, THeaderProtocolFactory):
+            otrans = None
+            oprot = iprot
+        else:
+            otrans = self.outputTransportFactory.getTransport(client)
+            oprot = self.outputProtocolFactory.getProtocol(otrans)
+
+        try:
+            while True:
+                self.processor.process(iprot, oprot)
+        except TTransport.TTransportException:
+            pass
+        except Exception as x:
+            logger.exception(x)
+
+        itrans.close()
+        if otrans:
+            otrans.close()
 
 
 class TThreadPoolServer(TServer):
-  """Server with a fixed size pool of threads which service requests."""
+    """Server with a fixed size pool of threads which service requests."""
 
-  def __init__(self, *args, **kwargs):
-    TServer.__init__(self, *args)
-    self.clients = Queue.Queue()
-    self.threads = 10
-    self.daemon = kwargs.get("daemon", False)
+    def __init__(self, *args, **kwargs):
+        TServer.__init__(self, *args)
+        self.clients = queue.Queue()
+        self.threads = 10
+        self.daemon = kwargs.get("daemon", False)
 
-  def setNumThreads(self, num):
-    """Set the number of worker threads that should be created"""
-    self.threads = num
+    def setNumThreads(self, num):
+        """Set the number of worker threads that should be created"""
+        self.threads = num
 
-  def serveThread(self):
-    """Loop around getting clients from the shared queue and process them."""
-    while True:
-      try:
-        client = self.clients.get()
-        self.serveClient(client)
-      except Exception, x:
-        logging.exception(x)
+    def serveThread(self):
+        """Loop around getting clients from the shared queue and process them."""
+        while True:
+            try:
+                client = self.clients.get()
+                self.serveClient(client)
+            except Exception as x:
+                logger.exception(x)
 
-  def serveClient(self, client):
-    """Process input/output from a client for as long as possible"""
-    itrans = self.inputTransportFactory.getTransport(client)
-    otrans = self.outputTransportFactory.getTransport(client)
-    iprot = self.inputProtocolFactory.getProtocol(itrans)
-    oprot = self.outputProtocolFactory.getProtocol(otrans)
-    try:
-      while True:
-        self.processor.process(iprot, oprot)
-    except TTransport.TTransportException, tx:
-      pass
-    except Exception, x:
-      logging.exception(x)
+    def serveClient(self, client):
+        """Process input/output from a client for as long as possible"""
+        itrans = self.inputTransportFactory.getTransport(client)
+        iprot = self.inputProtocolFactory.getProtocol(itrans)
 
-    itrans.close()
-    otrans.close()
+        # for THeaderProtocol, we must use the same protocol instance for input
+        # and output so that the response is in the same dialect that the
+        # server detected the request was in.
+        if isinstance(self.inputProtocolFactory, THeaderProtocolFactory):
+            otrans = None
+            oprot = iprot
+        else:
+            otrans = self.outputTransportFactory.getTransport(client)
+            oprot = self.outputProtocolFactory.getProtocol(otrans)
 
-  def serve(self):
-    """Start a fixed number of worker threads and put client into a queue"""
-    for i in range(self.threads):
-      try:
-        t = threading.Thread(target=self.serveThread)
-        t.setDaemon(self.daemon)
-        t.start()
-      except Exception, x:
-        logging.exception(x)
+        try:
+            while True:
+                self.processor.process(iprot, oprot)
+        except TTransport.TTransportException:
+            pass
+        except Exception as x:
+            logger.exception(x)
 
-    # Pump the socket for clients
-    self.serverTransport.listen()
-    while True:
-      try:
-        client = self.serverTransport.accept()
-        self.clients.put(client)
-      except Exception, x:
-        logging.exception(x)
+        itrans.close()
+        if otrans:
+            otrans.close()
+
+    def serve(self):
+        """Start a fixed number of worker threads and put client into a queue"""
+        for i in range(self.threads):
+            try:
+                t = threading.Thread(target=self.serveThread)
+                t.setDaemon(self.daemon)
+                t.start()
+            except Exception as x:
+                logger.exception(x)
+
+        # Pump the socket for clients
+        self.serverTransport.listen()
+        while True:
+            try:
+                client = self.serverTransport.accept()
+                if not client:
+                    continue
+                self.clients.put(client)
+            except Exception as x:
+                logger.exception(x)
 
 
 class TForkingServer(TServer):
-  """A Thrift server that forks a new process for each request
+    """A Thrift server that forks a new process for each request
 
-  This is more scalable than the threaded server as it does not cause
-  GIL contention.
+    This is more scalable than the threaded server as it does not cause
+    GIL contention.
 
-  Note that this has different semantics from the threading server.
-  Specifically, updates to shared variables will no longer be shared.
-  It will also not work on windows.
+    Note that this has different semantics from the threading server.
+    Specifically, updates to shared variables will no longer be shared.
+    It will also not work on windows.
 
-  This code is heavily inspired by SocketServer.ForkingMixIn in the
-  Python stdlib.
-  """
-  def __init__(self, *args):
-    TServer.__init__(self, *args)
-    self.children = []
+    This code is heavily inspired by SocketServer.ForkingMixIn in the
+    Python stdlib.
+    """
+    def __init__(self, *args):
+        TServer.__init__(self, *args)
+        self.children = []
 
-  def serve(self):
-    def try_close(file):
-      try:
-        file.close()
-      except IOError, e:
-        logging.warning(e, exc_info=True)
-
-    self.serverTransport.listen()
-    while True:
-      client = self.serverTransport.accept()
-      try:
-        pid = os.fork()
-
-        if pid:  # parent
-          # add before collect, otherwise you race w/ waitpid
-          self.children.append(pid)
-          self.collect_children()
-
-          # Parent must close socket or the connection may not get
-          # closed promptly
-          itrans = self.inputTransportFactory.getTransport(client)
-          otrans = self.outputTransportFactory.getTransport(client)
-          try_close(itrans)
-          try_close(otrans)
-        else:
-          itrans = self.inputTransportFactory.getTransport(client)
-          otrans = self.outputTransportFactory.getTransport(client)
-
-          iprot = self.inputProtocolFactory.getProtocol(itrans)
-          oprot = self.outputProtocolFactory.getProtocol(otrans)
-
-          ecode = 0
-          try:
+    def serve(self):
+        def try_close(file):
             try:
-              while True:
-                self.processor.process(iprot, oprot)
-            except TTransport.TTransportException, tx:
-              pass
-            except Exception, e:
-              logging.exception(e)
-              ecode = 1
-          finally:
-            try_close(itrans)
-            try_close(otrans)
+                file.close()
+            except IOError as e:
+                logger.warning(e, exc_info=True)
 
-          os._exit(ecode)
+        self.serverTransport.listen()
+        while True:
+            client = self.serverTransport.accept()
+            if not client:
+                continue
+            try:
+                pid = os.fork()
 
-      except TTransport.TTransportException, tx:
-        pass
-      except Exception, x:
-        logging.exception(x)
+                if pid:  # parent
+                    # add before collect, otherwise you race w/ waitpid
+                    self.children.append(pid)
+                    self.collect_children()
 
-  def collect_children(self):
-    while self.children:
-      try:
-        pid, status = os.waitpid(0, os.WNOHANG)
-      except os.error:
-        pid = None
+                    # Parent must close socket or the connection may not get
+                    # closed promptly
+                    itrans = self.inputTransportFactory.getTransport(client)
+                    otrans = self.outputTransportFactory.getTransport(client)
+                    try_close(itrans)
+                    try_close(otrans)
+                else:
+                    itrans = self.inputTransportFactory.getTransport(client)
+                    iprot = self.inputProtocolFactory.getProtocol(itrans)
 
-      if pid:
-        self.children.remove(pid)
-      else:
-        break
+                    # for THeaderProtocol, we must use the same protocol
+                    # instance for input and output so that the response is in
+                    # the same dialect that the server detected the request was
+                    # in.
+                    if isinstance(self.inputProtocolFactory, THeaderProtocolFactory):
+                        otrans = None
+                        oprot = iprot
+                    else:
+                        otrans = self.outputTransportFactory.getTransport(client)
+                        oprot = self.outputProtocolFactory.getProtocol(otrans)
+
+                    ecode = 0
+                    try:
+                        try:
+                            while True:
+                                self.processor.process(iprot, oprot)
+                        except TTransport.TTransportException:
+                            pass
+                        except Exception as e:
+                            logger.exception(e)
+                            ecode = 1
+                    finally:
+                        try_close(itrans)
+                        if otrans:
+                            try_close(otrans)
+
+                    os._exit(ecode)
+
+            except TTransport.TTransportException:
+                pass
+            except Exception as x:
+                logger.exception(x)
+
+    def collect_children(self):
+        while self.children:
+            try:
+                pid, status = os.waitpid(0, os.WNOHANG)
+            except os.error:
+                pid = None
+
+            if pid:
+                self.children.remove(pid)
+            else:
+                break
diff --git a/lib/py/src/transport/THeaderTransport.py b/lib/py/src/transport/THeaderTransport.py
new file mode 100644
index 0000000..c0d5640
--- /dev/null
+++ b/lib/py/src/transport/THeaderTransport.py
@@ -0,0 +1,352 @@
+#
+# 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 struct
+import zlib
+
+from thrift.compat import BufferIO, byte_index
+from thrift.protocol.TBinaryProtocol import TBinaryProtocol
+from thrift.protocol.TCompactProtocol import TCompactProtocol, readVarint, writeVarint
+from thrift.Thrift import TApplicationException
+from thrift.transport.TTransport import (
+    CReadableTransport,
+    TMemoryBuffer,
+    TTransportBase,
+    TTransportException,
+)
+
+
+U16 = struct.Struct("!H")
+I32 = struct.Struct("!i")
+HEADER_MAGIC = 0x0FFF
+HARD_MAX_FRAME_SIZE = 0x3FFFFFFF
+
+
+class THeaderClientType(object):
+    HEADERS = 0x00
+
+    FRAMED_BINARY = 0x01
+    UNFRAMED_BINARY = 0x02
+
+    FRAMED_COMPACT = 0x03
+    UNFRAMED_COMPACT = 0x04
+
+
+class THeaderSubprotocolID(object):
+    BINARY = 0x00
+    COMPACT = 0x02
+
+
+class TInfoHeaderType(object):
+    KEY_VALUE = 0x01
+
+
+class THeaderTransformID(object):
+    ZLIB = 0x01
+
+
+READ_TRANSFORMS_BY_ID = {
+    THeaderTransformID.ZLIB: zlib.decompress,
+}
+
+
+WRITE_TRANSFORMS_BY_ID = {
+    THeaderTransformID.ZLIB: zlib.compress,
+}
+
+
+def _readString(trans):
+    size = readVarint(trans)
+    if size < 0:
+        raise TTransportException(
+            TTransportException.NEGATIVE_SIZE,
+            "Negative length"
+        )
+    return trans.read(size)
+
+
+def _writeString(trans, value):
+    writeVarint(trans, len(value))
+    trans.write(value)
+
+
+class THeaderTransport(TTransportBase, CReadableTransport):
+    def __init__(self, transport, allowed_client_types):
+        self._transport = transport
+        self._client_type = THeaderClientType.HEADERS
+        self._allowed_client_types = allowed_client_types
+
+        self._read_buffer = BufferIO(b"")
+        self._read_headers = {}
+
+        self._write_buffer = BufferIO()
+        self._write_headers = {}
+        self._write_transforms = []
+
+        self.flags = 0
+        self.sequence_id = 0
+        self._protocol_id = THeaderSubprotocolID.BINARY
+        self._max_frame_size = HARD_MAX_FRAME_SIZE
+
+    def isOpen(self):
+        return self._transport.isOpen()
+
+    def open(self):
+        return self._transport.open()
+
+    def close(self):
+        return self._transport.close()
+
+    def get_headers(self):
+        return self._read_headers
+
+    def set_header(self, key, value):
+        if not isinstance(key, bytes):
+            raise ValueError("header names must be bytes")
+        if not isinstance(value, bytes):
+            raise ValueError("header values must be bytes")
+        self._write_headers[key] = value
+
+    def clear_headers(self):
+        self._write_headers.clear()
+
+    def add_transform(self, transform_id):
+        if transform_id not in WRITE_TRANSFORMS_BY_ID:
+            raise ValueError("unknown transform")
+        self._write_transforms.append(transform_id)
+
+    def set_max_frame_size(self, size):
+        if not 0 < size < HARD_MAX_FRAME_SIZE:
+            raise ValueError("maximum frame size should be < %d and > 0" % HARD_MAX_FRAME_SIZE)
+        self._max_frame_size = size
+
+    @property
+    def protocol_id(self):
+        if self._client_type == THeaderClientType.HEADERS:
+            return self._protocol_id
+        elif self._client_type in (THeaderClientType.FRAMED_BINARY, THeaderClientType.UNFRAMED_BINARY):
+            return THeaderSubprotocolID.BINARY
+        elif self._client_type in (THeaderClientType.FRAMED_COMPACT, THeaderClientType.UNFRAMED_COMPACT):
+            return THeaderSubprotocolID.COMPACT
+        else:
+            raise TTransportException(
+                TTransportException.INVALID_CLIENT_TYPE,
+                "Protocol ID not know for client type %d" % self._client_type,
+            )
+
+    def read(self, sz):
+        # if there are bytes left in the buffer, produce those first.
+        bytes_read = self._read_buffer.read(sz)
+        bytes_left_to_read = sz - len(bytes_read)
+        if bytes_left_to_read == 0:
+            return bytes_read
+
+        # if we've determined this is an unframed client, just pass the read
+        # through to the underlying transport until we're reset again at the
+        # beginning of the next message.
+        if self._client_type in (THeaderClientType.UNFRAMED_BINARY, THeaderClientType.UNFRAMED_COMPACT):
+            return bytes_read + self._transport.read(bytes_left_to_read)
+
+        # we're empty and (maybe) framed. fill the buffers with the next frame.
+        self.readFrame(bytes_left_to_read)
+        return bytes_read + self._read_buffer.read(bytes_left_to_read)
+
+    def _set_client_type(self, client_type):
+        if client_type not in self._allowed_client_types:
+            raise TTransportException(
+                TTransportException.INVALID_CLIENT_TYPE,
+                "Client type %d not allowed by server." % client_type,
+            )
+        self._client_type = client_type
+
+    def readFrame(self, req_sz):
+        # the first word could either be the length field of a framed message
+        # or the first bytes of an unframed message.
+        first_word = self._transport.readAll(I32.size)
+        frame_size, = I32.unpack(first_word)
+        is_unframed = False
+        if frame_size & TBinaryProtocol.VERSION_MASK == TBinaryProtocol.VERSION_1:
+            self._set_client_type(THeaderClientType.UNFRAMED_BINARY)
+            is_unframed = True
+        elif (byte_index(first_word, 0) == TCompactProtocol.PROTOCOL_ID and
+              byte_index(first_word, 1) & TCompactProtocol.VERSION_MASK == TCompactProtocol.VERSION):
+            self._set_client_type(THeaderClientType.UNFRAMED_COMPACT)
+            is_unframed = True
+
+        if is_unframed:
+            bytes_left_to_read = req_sz - I32.size
+            if bytes_left_to_read > 0:
+                rest = self._transport.read(bytes_left_to_read)
+            else:
+                rest = b""
+            self._read_buffer = BufferIO(first_word + rest)
+            return
+
+        # ok, we're still here so we're framed.
+        if frame_size > self._max_frame_size:
+            raise TTransportException(
+                TTransportException.SIZE_LIMIT,
+                "Frame was too large.",
+            )
+        read_buffer = BufferIO(self._transport.readAll(frame_size))
+
+        # the next word is either going to be the version field of a
+        # binary/compact protocol message or the magic value + flags of a
+        # header protocol message.
+        second_word = read_buffer.read(I32.size)
+        version, = I32.unpack(second_word)
+        read_buffer.seek(0)
+        if version >> 16 == HEADER_MAGIC:
+            self._set_client_type(THeaderClientType.HEADERS)
+            self._read_buffer = self._parse_header_format(read_buffer)
+        elif version & TBinaryProtocol.VERSION_MASK == TBinaryProtocol.VERSION_1:
+            self._set_client_type(THeaderClientType.FRAMED_BINARY)
+            self._read_buffer = read_buffer
+        elif (byte_index(second_word, 0) == TCompactProtocol.PROTOCOL_ID and
+              byte_index(second_word, 1) & TCompactProtocol.VERSION_MASK == TCompactProtocol.VERSION):
+            self._set_client_type(THeaderClientType.FRAMED_COMPACT)
+            self._read_buffer = read_buffer
+        else:
+            raise TTransportException(
+                TTransportException.INVALID_CLIENT_TYPE,
+                "Could not detect client transport type.",
+            )
+
+    def _parse_header_format(self, buffer):
+        # make BufferIO look like TTransport for varint helpers
+        buffer_transport = TMemoryBuffer()
+        buffer_transport._buffer = buffer
+
+        buffer.read(2)  # discard the magic bytes
+        self.flags, = U16.unpack(buffer.read(U16.size))
+        self.sequence_id, = I32.unpack(buffer.read(I32.size))
+
+        header_length = U16.unpack(buffer.read(U16.size))[0] * 4
+        end_of_headers = buffer.tell() + header_length
+        if end_of_headers > len(buffer.getvalue()):
+            raise TTransportException(
+                TTransportException.SIZE_LIMIT,
+                "Header size is larger than whole frame.",
+            )
+
+        self._protocol_id = readVarint(buffer_transport)
+
+        transforms = []
+        transform_count = readVarint(buffer_transport)
+        for _ in range(transform_count):
+            transform_id = readVarint(buffer_transport)
+            if transform_id not in READ_TRANSFORMS_BY_ID:
+                raise TApplicationException(
+                    TApplicationException.INVALID_TRANSFORM,
+                    "Unknown transform: %d" % transform_id,
+                )
+            transforms.append(transform_id)
+        transforms.reverse()
+
+        headers = {}
+        while buffer.tell() < end_of_headers:
+            header_type = readVarint(buffer_transport)
+            if header_type == TInfoHeaderType.KEY_VALUE:
+                count = readVarint(buffer_transport)
+                for _ in range(count):
+                    key = _readString(buffer_transport)
+                    value = _readString(buffer_transport)
+                    headers[key] = value
+            else:
+                break  # ignore unknown headers
+        self._read_headers = headers
+
+        # skip padding / anything we didn't understand
+        buffer.seek(end_of_headers)
+
+        payload = buffer.read()
+        for transform_id in transforms:
+            transform_fn = READ_TRANSFORMS_BY_ID[transform_id]
+            payload = transform_fn(payload)
+        return BufferIO(payload)
+
+    def write(self, buf):
+        self._write_buffer.write(buf)
+
+    def flush(self):
+        payload = self._write_buffer.getvalue()
+        self._write_buffer = BufferIO()
+
+        buffer = BufferIO()
+        if self._client_type == THeaderClientType.HEADERS:
+            for transform_id in self._write_transforms:
+                transform_fn = WRITE_TRANSFORMS_BY_ID[transform_id]
+                payload = transform_fn(payload)
+
+            headers = BufferIO()
+            writeVarint(headers, self._protocol_id)
+            writeVarint(headers, len(self._write_transforms))
+            for transform_id in self._write_transforms:
+                writeVarint(headers, transform_id)
+            if self._write_headers:
+                writeVarint(headers, TInfoHeaderType.KEY_VALUE)
+                writeVarint(headers, len(self._write_headers))
+                for key, value in self._write_headers.items():
+                    _writeString(headers, key)
+                    _writeString(headers, value)
+                self._write_headers = {}
+            padding_needed = (4 - (len(headers.getvalue()) % 4)) % 4
+            headers.write(b"\x00" * padding_needed)
+            header_bytes = headers.getvalue()
+
+            buffer.write(I32.pack(10 + len(header_bytes) + len(payload)))
+            buffer.write(U16.pack(HEADER_MAGIC))
+            buffer.write(U16.pack(self.flags))
+            buffer.write(I32.pack(self.sequence_id))
+            buffer.write(U16.pack(len(header_bytes) // 4))
+            buffer.write(header_bytes)
+            buffer.write(payload)
+        elif self._client_type in (THeaderClientType.FRAMED_BINARY, THeaderClientType.FRAMED_COMPACT):
+            buffer.write(I32.pack(len(payload)))
+            buffer.write(payload)
+        elif self._client_type in (THeaderClientType.UNFRAMED_BINARY, THeaderClientType.UNFRAMED_COMPACT):
+            buffer.write(payload)
+        else:
+            raise TTransportException(
+                TTransportException.INVALID_CLIENT_TYPE,
+                "Unknown client type.",
+            )
+
+        # the frame length field doesn't count towards the frame payload size
+        frame_bytes = buffer.getvalue()
+        frame_payload_size = len(frame_bytes) - 4
+        if frame_payload_size > self._max_frame_size:
+            raise TTransportException(
+                TTransportException.SIZE_LIMIT,
+                "Attempting to send frame that is too large.",
+            )
+
+        self._transport.write(frame_bytes)
+        self._transport.flush()
+
+    @property
+    def cstringio_buf(self):
+        return self._read_buffer
+
+    def cstringio_refill(self, partialread, reqlen):
+        result = bytearray(partialread)
+        while len(result) < reqlen:
+            result += self.read(reqlen - len(result))
+        self._read_buffer = BufferIO(result)
+        return self._read_buffer
diff --git a/lib/py/src/transport/THttpClient.py b/lib/py/src/transport/THttpClient.py
index ea80a1a..37b0a4d 100644
--- a/lib/py/src/transport/THttpClient.py
+++ b/lib/py/src/transport/THttpClient.py
@@ -17,133 +17,171 @@
 # under the License.
 #
 
-import httplib
+from io import BytesIO
 import os
-import socket
+import ssl
 import sys
-import urllib
-import urlparse
 import warnings
+import base64
 
-from cStringIO import StringIO
+from six.moves import urllib
+from six.moves import http_client
 
-from TTransport import *
+from .TTransport import TTransportBase
+import six
 
 
 class THttpClient(TTransportBase):
-  """Http implementation of TTransport base."""
+    """Http implementation of TTransport base."""
 
-  def __init__(self, uri_or_host, port=None, path=None):
-    """THttpClient supports two different types constructor parameters.
+    def __init__(self, uri_or_host, port=None, path=None, cafile=None, cert_file=None, key_file=None, ssl_context=None):
+        """THttpClient supports two different types of construction:
 
-    THttpClient(host, port, path) - deprecated
-    THttpClient(uri)
+        THttpClient(host, port, path) - deprecated
+        THttpClient(uri, [port=<n>, path=<s>, cafile=<filename>, cert_file=<filename>, key_file=<filename>, ssl_context=<context>])
 
-    Only the second supports https.
-    """
-    if port is not None:
-      warnings.warn(
-        "Please use the THttpClient('http://host:port/path') syntax",
-        DeprecationWarning,
-        stacklevel=2)
-      self.host = uri_or_host
-      self.port = port
-      assert path
-      self.path = path
-      self.scheme = 'http'
-    else:
-      parsed = urlparse.urlparse(uri_or_host)
-      self.scheme = parsed.scheme
-      assert self.scheme in ('http', 'https')
-      if self.scheme == 'http':
-        self.port = parsed.port or httplib.HTTP_PORT
-      elif self.scheme == 'https':
-        self.port = parsed.port or httplib.HTTPS_PORT
-      self.host = parsed.hostname
-      self.path = parsed.path
-      if parsed.query:
-        self.path += '?%s' % parsed.query
-    self.__wbuf = StringIO()
-    self.__http = None
-    self.__timeout = None
-    self.__custom_headers = None
+        Only the second supports https.  To properly authenticate against the server,
+        provide the client's identity by specifying cert_file and key_file.  To properly
+        authenticate the server, specify either cafile or ssl_context with a CA defined.
+        NOTE: if both cafile and ssl_context are defined, ssl_context will override cafile.
+        """
+        if port is not None:
+            warnings.warn(
+                "Please use the THttpClient('http{s}://host:port/path') constructor",
+                DeprecationWarning,
+                stacklevel=2)
+            self.host = uri_or_host
+            self.port = port
+            assert path
+            self.path = path
+            self.scheme = 'http'
+        else:
+            parsed = urllib.parse.urlparse(uri_or_host)
+            self.scheme = parsed.scheme
+            assert self.scheme in ('http', 'https')
+            if self.scheme == 'http':
+                self.port = parsed.port or http_client.HTTP_PORT
+            elif self.scheme == 'https':
+                self.port = parsed.port or http_client.HTTPS_PORT
+                self.certfile = cert_file
+                self.keyfile = key_file
+                self.context = ssl.create_default_context(cafile=cafile) if (cafile and not ssl_context) else ssl_context
+            self.host = parsed.hostname
+            self.path = parsed.path
+            if parsed.query:
+                self.path += '?%s' % parsed.query
+        try:
+            proxy = urllib.request.getproxies()[self.scheme]
+        except KeyError:
+            proxy = None
+        else:
+            if urllib.request.proxy_bypass(self.host):
+                proxy = None
+        if proxy:
+            parsed = urllib.parse.urlparse(proxy)
+            self.realhost = self.host
+            self.realport = self.port
+            self.host = parsed.hostname
+            self.port = parsed.port
+            self.proxy_auth = self.basic_proxy_auth_header(parsed)
+        else:
+            self.realhost = self.realport = self.proxy_auth = None
+        self.__wbuf = BytesIO()
+        self.__http = None
+        self.__http_response = None
+        self.__timeout = None
+        self.__custom_headers = None
 
-  def open(self):
-    if self.scheme == 'http':
-      self.__http = httplib.HTTP(self.host, self.port)
-    else:
-      self.__http = httplib.HTTPS(self.host, self.port)
+    @staticmethod
+    def basic_proxy_auth_header(proxy):
+        if proxy is None or not proxy.username:
+            return None
+        ap = "%s:%s" % (urllib.parse.unquote(proxy.username),
+                        urllib.parse.unquote(proxy.password))
+        cr = base64.b64encode(ap).strip()
+        return "Basic " + cr
 
-  def close(self):
-    self.__http.close()
-    self.__http = None
+    def using_proxy(self):
+        return self.realhost is not None
 
-  def isOpen(self):
-    return self.__http is not None
+    def open(self):
+        if self.scheme == 'http':
+            self.__http = http_client.HTTPConnection(self.host, self.port,
+                                                     timeout=self.__timeout)
+        elif self.scheme == 'https':
+            self.__http = http_client.HTTPSConnection(self.host, self.port,
+                                                      key_file=self.keyfile,
+                                                      cert_file=self.certfile,
+                                                      timeout=self.__timeout,
+                                                      context=self.context)
+        if self.using_proxy():
+            self.__http.set_tunnel(self.realhost, self.realport,
+                                   {"Proxy-Authorization": self.proxy_auth})
 
-  def setTimeout(self, ms):
-    if not hasattr(socket, 'getdefaulttimeout'):
-      raise NotImplementedError
+    def close(self):
+        self.__http.close()
+        self.__http = None
+        self.__http_response = None
 
-    if ms is None:
-      self.__timeout = None
-    else:
-      self.__timeout = ms / 1000.0
+    def isOpen(self):
+        return self.__http is not None
 
-  def setCustomHeaders(self, headers):
-    self.__custom_headers = headers
+    def setTimeout(self, ms):
+        if ms is None:
+            self.__timeout = None
+        else:
+            self.__timeout = ms / 1000.0
 
-  def read(self, sz):
-    return self.__http.file.read(sz)
+    def setCustomHeaders(self, headers):
+        self.__custom_headers = headers
 
-  def write(self, buf):
-    self.__wbuf.write(buf)
+    def read(self, sz):
+        return self.__http_response.read(sz)
 
-  def __withTimeout(f):
-    def _f(*args, **kwargs):
-      orig_timeout = socket.getdefaulttimeout()
-      socket.setdefaulttimeout(args[0].__timeout)
-      result = f(*args, **kwargs)
-      socket.setdefaulttimeout(orig_timeout)
-      return result
-    return _f
+    def write(self, buf):
+        self.__wbuf.write(buf)
 
-  def flush(self):
-    if self.isOpen():
-      self.close()
-    self.open()
+    def flush(self):
+        if self.isOpen():
+            self.close()
+        self.open()
 
-    # Pull data out of buffer
-    data = self.__wbuf.getvalue()
-    self.__wbuf = StringIO()
+        # Pull data out of buffer
+        data = self.__wbuf.getvalue()
+        self.__wbuf = BytesIO()
 
-    # HTTP request
-    self.__http.putrequest('POST', self.path)
+        # HTTP request
+        if self.using_proxy() and self.scheme == "http":
+            # need full URL of real host for HTTP proxy here (HTTPS uses CONNECT tunnel)
+            self.__http.putrequest('POST', "http://%s:%s%s" %
+                                   (self.realhost, self.realport, self.path))
+        else:
+            self.__http.putrequest('POST', self.path)
 
-    # Write headers
-    self.__http.putheader('Host', self.host)
-    self.__http.putheader('Content-Type', 'application/x-thrift')
-    self.__http.putheader('Content-Length', str(len(data)))
+        # Write headers
+        self.__http.putheader('Content-Type', 'application/x-thrift')
+        self.__http.putheader('Content-Length', str(len(data)))
+        if self.using_proxy() and self.scheme == "http" and self.proxy_auth is not None:
+            self.__http.putheader("Proxy-Authorization", self.proxy_auth)
 
-    if not self.__custom_headers or 'User-Agent' not in self.__custom_headers:
-      user_agent = 'Python/THttpClient'
-      script = os.path.basename(sys.argv[0])
-      if script:
-        user_agent = '%s (%s)' % (user_agent, urllib.quote(script))
-      self.__http.putheader('User-Agent', user_agent)
+        if not self.__custom_headers or 'User-Agent' not in self.__custom_headers:
+            user_agent = 'Python/THttpClient'
+            script = os.path.basename(sys.argv[0])
+            if script:
+                user_agent = '%s (%s)' % (user_agent, urllib.parse.quote(script))
+            self.__http.putheader('User-Agent', user_agent)
 
-    if self.__custom_headers:
-        for key, val in self.__custom_headers.iteritems():
-            self.__http.putheader(key, val)
+        if self.__custom_headers:
+            for key, val in six.iteritems(self.__custom_headers):
+                self.__http.putheader(key, val)
 
-    self.__http.endheaders()
+        self.__http.endheaders()
 
-    # Write payload
-    self.__http.send(data)
+        # Write payload
+        self.__http.send(data)
 
-    # Get reply to flush the request
-    self.code, self.message, self.headers = self.__http.getreply()
-
-  # Decorate if we know how to timeout
-  if hasattr(socket, 'getdefaulttimeout'):
-    flush = __withTimeout(flush)
+        # Get reply to flush the request
+        self.__http_response = self.__http.getresponse()
+        self.code = self.__http_response.status
+        self.message = self.__http_response.reason
+        self.headers = self.__http_response.msg
diff --git a/lib/py/src/transport/TSSLSocket.py b/lib/py/src/transport/TSSLSocket.py
index 81e0984..b54ca5d 100644
--- a/lib/py/src/transport/TSSLSocket.py
+++ b/lib/py/src/transport/TSSLSocket.py
@@ -17,198 +17,380 @@
 # under the License.
 #
 
+import logging
 import os
 import socket
 import ssl
+import sys
+import warnings
 
+from .sslcompat import _match_hostname, _match_has_ipaddress
 from thrift.transport import TSocket
 from thrift.transport.TTransport import TTransportException
 
+logger = logging.getLogger(__name__)
+warnings.filterwarnings(
+    'default', category=DeprecationWarning, module=__name__)
 
-class TSSLSocket(TSocket.TSocket):
-  """
-  SSL implementation of client-side TSocket
 
-  This class creates outbound sockets wrapped using the
-  python standard ssl module for encrypted connections.
+class TSSLBase(object):
+    # SSLContext is not available for Python < 2.7.9
+    _has_ssl_context = sys.hexversion >= 0x020709F0
 
-  The protocol used is set using the class variable
-  SSL_VERSION, which must be one of ssl.PROTOCOL_* and
-  defaults to  ssl.PROTOCOL_TLSv1 for greatest security.
-  """
-  SSL_VERSION = ssl.PROTOCOL_TLSv1
+    # ciphers argument is not available for Python < 2.7.0
+    _has_ciphers = sys.hexversion >= 0x020700F0
 
-  def __init__(self,
-               host='localhost',
-               port=9090,
-               validate=True,
-               ca_certs=None,
-               keyfile=None,
-               certfile=None,
-               unix_socket=None):
-    """Create SSL TSocket
+    # For python >= 2.7.9, use latest TLS that both client and server
+    # supports.
+    # SSL 2.0 and 3.0 are disabled via ssl.OP_NO_SSLv2 and ssl.OP_NO_SSLv3.
+    # For python < 2.7.9, use TLS 1.0 since TLSv1_X nor OP_NO_SSLvX is
+    # unavailable.
+    _default_protocol = ssl.PROTOCOL_SSLv23 if _has_ssl_context else \
+        ssl.PROTOCOL_TLSv1
 
-    @param validate: Set to False to disable SSL certificate validation
-    @type validate: bool
-    @param ca_certs: Filename to the Certificate Authority pem file, possibly a
-    file downloaded from: http://curl.haxx.se/ca/cacert.pem  This is passed to
-    the ssl_wrap function as the 'ca_certs' parameter.
-    @type ca_certs: str
-    @param keyfile: The private key
-    @type keyfile: str
-    @param certfile: The cert file
-    @type certfile: str
-    
-    Raises an IOError exception if validate is True and the ca_certs file is
-    None, not present or unreadable.
+    def _init_context(self, ssl_version):
+        if self._has_ssl_context:
+            self._context = ssl.SSLContext(ssl_version)
+            if self._context.protocol == ssl.PROTOCOL_SSLv23:
+                self._context.options |= ssl.OP_NO_SSLv2
+                self._context.options |= ssl.OP_NO_SSLv3
+        else:
+            self._context = None
+            self._ssl_version = ssl_version
+
+    @property
+    def _should_verify(self):
+        if self._has_ssl_context:
+            return self._context.verify_mode != ssl.CERT_NONE
+        else:
+            return self.cert_reqs != ssl.CERT_NONE
+
+    @property
+    def ssl_version(self):
+        if self._has_ssl_context:
+            return self.ssl_context.protocol
+        else:
+            return self._ssl_version
+
+    @property
+    def ssl_context(self):
+        return self._context
+
+    SSL_VERSION = _default_protocol
     """
-    self.validate = validate
-    self.is_valid = False
-    self.peercert = None
-    if not validate:
-      self.cert_reqs = ssl.CERT_NONE
-    else:
-      self.cert_reqs = ssl.CERT_REQUIRED
-    self.ca_certs = ca_certs
-    self.keyfile = keyfile
-    self.certfile = certfile
-    if validate:
-      if ca_certs is None or not os.access(ca_certs, os.R_OK):
-        raise IOError('Certificate Authority ca_certs file "%s" '
-                      'is not readable, cannot validate SSL '
-                      'certificates.' % (ca_certs))
-    TSocket.TSocket.__init__(self, host, port, unix_socket)
+  Default SSL version.
+  For backword compatibility, it can be modified.
+  Use __init__ keywoard argument "ssl_version" instead.
+  """
 
-  def open(self):
-    try:
-      res0 = self._resolveAddr()
-      for res in res0:
-        sock_family, sock_type = res[0:2]
-        ip_port = res[4]
-        plain_sock = socket.socket(sock_family, sock_type)
-        self.handle = ssl.wrap_socket(plain_sock,
-                                      ssl_version=self.SSL_VERSION,
-                                      do_handshake_on_connect=True,
-                                      ca_certs=self.ca_certs,
-                                      keyfile=self.keyfile,
-                                      certfile=self.certfile,
-                                      cert_reqs=self.cert_reqs)
-        self.handle.settimeout(self._timeout)
+    def _deprecated_arg(self, args, kwargs, pos, key):
+        if len(args) <= pos:
+            return
+        real_pos = pos + 3
+        warnings.warn(
+            '%dth positional argument is deprecated.'
+            'please use keyward argument insteand.'
+            % real_pos, DeprecationWarning, stacklevel=3)
+
+        if key in kwargs:
+            raise TypeError(
+                'Duplicate argument: %dth argument and %s keyward argument.'
+                % (real_pos, key))
+        kwargs[key] = args[pos]
+
+    def _unix_socket_arg(self, host, port, args, kwargs):
+        key = 'unix_socket'
+        if host is None and port is None and len(args) == 1 and key not in kwargs:
+            kwargs[key] = args[0]
+            return True
+        return False
+
+    def __getattr__(self, key):
+        if key == 'SSL_VERSION':
+            warnings.warn(
+                'SSL_VERSION is deprecated.'
+                'please use ssl_version attribute instead.',
+                DeprecationWarning, stacklevel=2)
+            return self.ssl_version
+
+    def __init__(self, server_side, host, ssl_opts):
+        self._server_side = server_side
+        if TSSLBase.SSL_VERSION != self._default_protocol:
+            warnings.warn(
+                'SSL_VERSION is deprecated.'
+                'please use ssl_version keyward argument instead.',
+                DeprecationWarning, stacklevel=2)
+        self._context = ssl_opts.pop('ssl_context', None)
+        self._server_hostname = None
+        if not self._server_side:
+            self._server_hostname = ssl_opts.pop('server_hostname', host)
+        if self._context:
+            self._custom_context = True
+            if ssl_opts:
+                raise ValueError(
+                    'Incompatible arguments: ssl_context and %s'
+                    % ' '.join(ssl_opts.keys()))
+            if not self._has_ssl_context:
+                raise ValueError(
+                    'ssl_context is not available for this version of Python')
+        else:
+            self._custom_context = False
+            ssl_version = ssl_opts.pop('ssl_version', TSSLBase.SSL_VERSION)
+            self._init_context(ssl_version)
+            self.cert_reqs = ssl_opts.pop('cert_reqs', ssl.CERT_REQUIRED)
+            self.ca_certs = ssl_opts.pop('ca_certs', None)
+            self.keyfile = ssl_opts.pop('keyfile', None)
+            self.certfile = ssl_opts.pop('certfile', None)
+            self.ciphers = ssl_opts.pop('ciphers', None)
+
+            if ssl_opts:
+                raise ValueError(
+                    'Unknown keyword arguments: ', ' '.join(ssl_opts.keys()))
+
+            if self._should_verify:
+                if not self.ca_certs:
+                    raise ValueError(
+                        'ca_certs is needed when cert_reqs is not ssl.CERT_NONE')
+                if not os.access(self.ca_certs, os.R_OK):
+                    raise IOError('Certificate Authority ca_certs file "%s" '
+                                  'is not readable, cannot validate SSL '
+                                  'certificates.' % (self.ca_certs))
+
+    @property
+    def certfile(self):
+        return self._certfile
+
+    @certfile.setter
+    def certfile(self, certfile):
+        if self._server_side and not certfile:
+            raise ValueError('certfile is needed for server-side')
+        if certfile and not os.access(certfile, os.R_OK):
+            raise IOError('No such certfile found: %s' % (certfile))
+        self._certfile = certfile
+
+    def _wrap_socket(self, sock):
+        if self._has_ssl_context:
+            if not self._custom_context:
+                self.ssl_context.verify_mode = self.cert_reqs
+                if self.certfile:
+                    self.ssl_context.load_cert_chain(self.certfile,
+                                                     self.keyfile)
+                if self.ciphers:
+                    self.ssl_context.set_ciphers(self.ciphers)
+                if self.ca_certs:
+                    self.ssl_context.load_verify_locations(self.ca_certs)
+            return self.ssl_context.wrap_socket(
+                sock, server_side=self._server_side,
+                server_hostname=self._server_hostname)
+        else:
+            ssl_opts = {
+                'ssl_version': self._ssl_version,
+                'server_side': self._server_side,
+                'ca_certs': self.ca_certs,
+                'keyfile': self.keyfile,
+                'certfile': self.certfile,
+                'cert_reqs': self.cert_reqs,
+            }
+            if self.ciphers:
+                if self._has_ciphers:
+                    ssl_opts['ciphers'] = self.ciphers
+                else:
+                    logger.warning(
+                        'ciphers is specified but ignored due to old Python version')
+            return ssl.wrap_socket(sock, **ssl_opts)
+
+
+class TSSLSocket(TSocket.TSocket, TSSLBase):
+    """
+    SSL implementation of TSocket
+
+    This class creates outbound sockets wrapped using the
+    python standard ssl module for encrypted connections.
+    """
+
+    # New signature
+    # def __init__(self, host='localhost', port=9090, unix_socket=None,
+    #              **ssl_args):
+    # Deprecated signature
+    # def __init__(self, host='localhost', port=9090, validate=True,
+    #              ca_certs=None, keyfile=None, certfile=None,
+    #              unix_socket=None, ciphers=None):
+    def __init__(self, host='localhost', port=9090, *args, **kwargs):
+        """Positional arguments: ``host``, ``port``, ``unix_socket``
+
+        Keyword arguments: ``keyfile``, ``certfile``, ``cert_reqs``,
+                           ``ssl_version``, ``ca_certs``,
+                           ``ciphers`` (Python 2.7.0 or later),
+                           ``server_hostname`` (Python 2.7.9 or later)
+        Passed to ssl.wrap_socket. See ssl.wrap_socket documentation.
+
+        Alternative keyword arguments: (Python 2.7.9 or later)
+          ``ssl_context``: ssl.SSLContext to be used for SSLContext.wrap_socket
+          ``server_hostname``: Passed to SSLContext.wrap_socket
+
+        Common keyword argument:
+          ``validate_callback`` (cert, hostname) -> None:
+              Called after SSL handshake. Can raise when hostname does not
+              match the cert.
+        """
+        self.is_valid = False
+        self.peercert = None
+
+        if args:
+            if len(args) > 6:
+                raise TypeError('Too many positional argument')
+            if not self._unix_socket_arg(host, port, args, kwargs):
+                self._deprecated_arg(args, kwargs, 0, 'validate')
+            self._deprecated_arg(args, kwargs, 1, 'ca_certs')
+            self._deprecated_arg(args, kwargs, 2, 'keyfile')
+            self._deprecated_arg(args, kwargs, 3, 'certfile')
+            self._deprecated_arg(args, kwargs, 4, 'unix_socket')
+            self._deprecated_arg(args, kwargs, 5, 'ciphers')
+
+        validate = kwargs.pop('validate', None)
+        if validate is not None:
+            cert_reqs_name = 'CERT_REQUIRED' if validate else 'CERT_NONE'
+            warnings.warn(
+                'validate is deprecated. please use cert_reqs=ssl.%s instead'
+                % cert_reqs_name,
+                DeprecationWarning, stacklevel=2)
+            if 'cert_reqs' in kwargs:
+                raise TypeError('Cannot specify both validate and cert_reqs')
+            kwargs['cert_reqs'] = ssl.CERT_REQUIRED if validate else ssl.CERT_NONE
+
+        unix_socket = kwargs.pop('unix_socket', None)
+        self._validate_callback = kwargs.pop('validate_callback', _match_hostname)
+        TSSLBase.__init__(self, False, host, kwargs)
+        TSocket.TSocket.__init__(self, host, port, unix_socket)
+
+    @property
+    def validate(self):
+        warnings.warn('validate is deprecated. please use cert_reqs instead',
+                      DeprecationWarning, stacklevel=2)
+        return self.cert_reqs != ssl.CERT_NONE
+
+    @validate.setter
+    def validate(self, value):
+        warnings.warn('validate is deprecated. please use cert_reqs instead',
+                      DeprecationWarning, stacklevel=2)
+        self.cert_reqs = ssl.CERT_REQUIRED if value else ssl.CERT_NONE
+
+    def _do_open(self, family, socktype):
+        plain_sock = socket.socket(family, socktype)
         try:
-          self.handle.connect(ip_port)
-        except socket.error, e:
-          if res is not res0[-1]:
-            continue
-          else:
-            raise e
-        break
-    except socket.error, e:
-      if self._unix_socket:
-        message = 'Could not connect to secure socket %s: %s' \
-                % (self._unix_socket, e)
-      else:
-        message = 'Could not connect to %s:%d: %s' % (self.host, self.port, e)
-      raise TTransportException(type=TTransportException.NOT_OPEN,
-                                message=message)
-    if self.validate:
-      self._validate_cert()
+            return self._wrap_socket(plain_sock)
+        except Exception:
+            plain_sock.close()
+            msg = 'failed to initialize SSL'
+            logger.exception(msg)
+            raise TTransportException(TTransportException.NOT_OPEN, msg)
 
-  def _validate_cert(self):
-    """internal method to validate the peer's SSL certificate, and to check the
-    commonName of the certificate to ensure it matches the hostname we
-    used to make this connection.  Does not support subjectAltName records
-    in certificates.
+    def open(self):
+        super(TSSLSocket, self).open()
+        if self._should_verify:
+            self.peercert = self.handle.getpeercert()
+            try:
+                self._validate_callback(self.peercert, self._server_hostname)
+                self.is_valid = True
+            except TTransportException:
+                raise
+            except Exception as ex:
+                raise TTransportException(TTransportException.UNKNOWN, str(ex))
 
-    raises TTransportException if the certificate fails validation.
+
+class TSSLServerSocket(TSocket.TServerSocket, TSSLBase):
+    """SSL implementation of TServerSocket
+
+    This uses the ssl module's wrap_socket() method to provide SSL
+    negotiated encryption.
     """
-    cert = self.handle.getpeercert()
-    self.peercert = cert
-    if 'subject' not in cert:
-      raise TTransportException(
-        type=TTransportException.NOT_OPEN,
-        message='No SSL certificate found from %s:%s' % (self.host, self.port))
-    fields = cert['subject']
-    for field in fields:
-      # ensure structure we get back is what we expect
-      if not isinstance(field, tuple):
-        continue
-      cert_pair = field[0]
-      if len(cert_pair) < 2:
-        continue
-      cert_key, cert_value = cert_pair[0:2]
-      if cert_key != 'commonName':
-        continue
-      certhost = cert_value
-      # this check should be performed by some sort of Access Manager
-      if certhost == self.host:
-        # success, cert commonName matches desired hostname
-        self.is_valid = True
-        return
-      else:
-        raise TTransportException(
-          type=TTransportException.UNKNOWN,
-          message='Hostname we connected to "%s" doesn\'t match certificate '
-                  'provided commonName "%s"' % (self.host, certhost))
-    raise TTransportException(
-      type=TTransportException.UNKNOWN,
-      message='Could not validate SSL certificate from '
-              'host "%s".  Cert=%s' % (self.host, cert))
 
+    # New signature
+    # def __init__(self, host='localhost', port=9090, unix_socket=None, **ssl_args):
+    # Deprecated signature
+    # def __init__(self, host=None, port=9090, certfile='cert.pem', unix_socket=None, ciphers=None):
+    def __init__(self, host=None, port=9090, *args, **kwargs):
+        """Positional arguments: ``host``, ``port``, ``unix_socket``
 
-class TSSLServerSocket(TSocket.TServerSocket):
-  """SSL implementation of TServerSocket
+        Keyword arguments: ``keyfile``, ``certfile``, ``cert_reqs``, ``ssl_version``,
+                           ``ca_certs``, ``ciphers`` (Python 2.7.0 or later)
+        See ssl.wrap_socket documentation.
 
-  This uses the ssl module's wrap_socket() method to provide SSL
-  negotiated encryption.
-  """
-  SSL_VERSION = ssl.PROTOCOL_TLSv1
+        Alternative keyword arguments: (Python 2.7.9 or later)
+          ``ssl_context``: ssl.SSLContext to be used for SSLContext.wrap_socket
+          ``server_hostname``: Passed to SSLContext.wrap_socket
 
-  def __init__(self,
-               host=None,
-               port=9090,
-               certfile='cert.pem',
-               unix_socket=None):
-    """Initialize a TSSLServerSocket
+        Common keyword argument:
+          ``validate_callback`` (cert, hostname) -> None:
+              Called after SSL handshake. Can raise when hostname does not
+              match the cert.
+        """
+        if args:
+            if len(args) > 3:
+                raise TypeError('Too many positional argument')
+            if not self._unix_socket_arg(host, port, args, kwargs):
+                self._deprecated_arg(args, kwargs, 0, 'certfile')
+            self._deprecated_arg(args, kwargs, 1, 'unix_socket')
+            self._deprecated_arg(args, kwargs, 2, 'ciphers')
 
-    @param certfile: filename of the server certificate, defaults to cert.pem
-    @type certfile: str
-    @param host: The hostname or IP to bind the listen socket to,
-                 i.e. 'localhost' for only allowing local network connections.
-                 Pass None to bind to all interfaces.
-    @type host: str
-    @param port: The port to listen on for inbound connections.
-    @type port: int
-    """
-    self.setCertfile(certfile)
-    TSocket.TServerSocket.__init__(self, host, port)
+        if 'ssl_context' not in kwargs:
+            # Preserve existing behaviors for default values
+            if 'cert_reqs' not in kwargs:
+                kwargs['cert_reqs'] = ssl.CERT_NONE
+            if'certfile' not in kwargs:
+                kwargs['certfile'] = 'cert.pem'
 
-  def setCertfile(self, certfile):
-    """Set or change the server certificate file used to wrap new connections.
+        unix_socket = kwargs.pop('unix_socket', None)
+        self._validate_callback = \
+            kwargs.pop('validate_callback', _match_hostname)
+        TSSLBase.__init__(self, True, None, kwargs)
+        TSocket.TServerSocket.__init__(self, host, port, unix_socket)
+        if self._should_verify and not _match_has_ipaddress:
+            raise ValueError('Need ipaddress and backports.ssl_match_hostname '
+                             'module to verify client certificate')
 
-    @param certfile: The filename of the server certificate,
-                     i.e. '/etc/certs/server.pem'
-    @type certfile: str
+    def setCertfile(self, certfile):
+        """Set or change the server certificate file used to wrap new
+        connections.
 
-    Raises an IOError exception if the certfile is not present or unreadable.
-    """
-    if not os.access(certfile, os.R_OK):
-      raise IOError('No such certfile found: %s' % (certfile))
-    self.certfile = certfile
+        @param certfile: The filename of the server certificate,
+                         i.e. '/etc/certs/server.pem'
+        @type certfile: str
 
-  def accept(self):
-    plain_client, addr = self.handle.accept()
-    try:
-      client = ssl.wrap_socket(plain_client, certfile=self.certfile,
-                      server_side=True, ssl_version=self.SSL_VERSION)
-    except ssl.SSLError, ssl_exc:
-      # failed handshake/ssl wrap, close socket to client
-      plain_client.close()
-      # raise ssl_exc
-      # We can't raise the exception, because it kills most TServer derived
-      # serve() methods.
-      # Instead, return None, and let the TServer instance deal with it in
-      # other exception handling.  (but TSimpleServer dies anyway)
-      return None
-    result = TSocket.TSocket()
-    result.setHandle(client)
-    return result
+        Raises an IOError exception if the certfile is not present or unreadable.
+        """
+        warnings.warn(
+            'setCertfile is deprecated. please use certfile property instead.',
+            DeprecationWarning, stacklevel=2)
+        self.certfile = certfile
+
+    def accept(self):
+        plain_client, addr = self.handle.accept()
+        try:
+            client = self._wrap_socket(plain_client)
+        except (ssl.SSLError, socket.error, OSError):
+            logger.exception('Error while accepting from %s', addr)
+            # failed handshake/ssl wrap, close socket to client
+            plain_client.close()
+            # raise
+            # We can't raise the exception, because it kills most TServer derived
+            # serve() methods.
+            # Instead, return None, and let the TServer instance deal with it in
+            # other exception handling.  (but TSimpleServer dies anyway)
+            return None
+
+        if self._should_verify:
+            client.peercert = client.getpeercert()
+            try:
+                self._validate_callback(client.peercert, addr[0])
+                client.is_valid = True
+            except Exception:
+                logger.warn('Failed to validate client certificate address: %s',
+                            addr[0], exc_info=True)
+                client.close()
+                plain_client.close()
+                return None
+
+        result = TSocket.TSocket()
+        result.handle = client
+        return result
diff --git a/lib/py/src/transport/TSocket.py b/lib/py/src/transport/TSocket.py
index 9e2b384..a7d6617 100644
--- a/lib/py/src/transport/TSocket.py
+++ b/lib/py/src/transport/TSocket.py
@@ -18,159 +18,184 @@
 #
 
 import errno
+import logging
 import os
 import socket
 import sys
 
-from TTransport import *
+from .TTransport import TTransportBase, TTransportException, TServerTransportBase
+
+logger = logging.getLogger(__name__)
 
 
 class TSocketBase(TTransportBase):
-  def _resolveAddr(self):
-    if self._unix_socket is not None:
-      return [(socket.AF_UNIX, socket.SOCK_STREAM, None, None,
-               self._unix_socket)]
-    else:
-      return socket.getaddrinfo(self.host,
-                                self.port,
-                                socket.AF_UNSPEC,
-                                socket.SOCK_STREAM,
-                                0,
-                                socket.AI_PASSIVE | socket.AI_ADDRCONFIG)
+    def _resolveAddr(self):
+        if self._unix_socket is not None:
+            return [(socket.AF_UNIX, socket.SOCK_STREAM, None, None,
+                     self._unix_socket)]
+        else:
+            return socket.getaddrinfo(self.host,
+                                      self.port,
+                                      self._socket_family,
+                                      socket.SOCK_STREAM,
+                                      0,
+                                      socket.AI_PASSIVE | socket.AI_ADDRCONFIG)
 
-  def close(self):
-    if self.handle:
-      self.handle.close()
-      self.handle = None
+    def close(self):
+        if self.handle:
+            self.handle.close()
+            self.handle = None
 
 
 class TSocket(TSocketBase):
-  """Socket implementation of TTransport base."""
+    """Socket implementation of TTransport base."""
 
-  def __init__(self, host='localhost', port=9090, unix_socket=None):
-    """Initialize a TSocket
+    def __init__(self, host='localhost', port=9090, unix_socket=None, socket_family=socket.AF_UNSPEC):
+        """Initialize a TSocket
 
-    @param host(str)  The host to connect to.
-    @param port(int)  The (TCP) port to connect to.
-    @param unix_socket(str)  The filename of a unix socket to connect to.
-                             (host and port will be ignored.)
-    """
-    self.host = host
-    self.port = port
-    self.handle = None
-    self._unix_socket = unix_socket
-    self._timeout = None
+        @param host(str)  The host to connect to.
+        @param port(int)  The (TCP) port to connect to.
+        @param unix_socket(str)  The filename of a unix socket to connect to.
+                                 (host and port will be ignored.)
+        @param socket_family(int)  The socket family to use with this socket.
+        """
+        self.host = host
+        self.port = port
+        self.handle = None
+        self._unix_socket = unix_socket
+        self._timeout = None
+        self._socket_family = socket_family
 
-  def setHandle(self, h):
-    self.handle = h
+    def setHandle(self, h):
+        self.handle = h
 
-  def isOpen(self):
-    return self.handle is not None
+    def isOpen(self):
+        return self.handle is not None
 
-  def setTimeout(self, ms):
-    if ms is None:
-      self._timeout = None
-    else:
-      self._timeout = ms / 1000.0
+    def setTimeout(self, ms):
+        if ms is None:
+            self._timeout = None
+        else:
+            self._timeout = ms / 1000.0
 
-    if self.handle is not None:
-      self.handle.settimeout(self._timeout)
+        if self.handle is not None:
+            self.handle.settimeout(self._timeout)
 
-  def open(self):
-    try:
-      res0 = self._resolveAddr()
-      for res in res0:
-        self.handle = socket.socket(res[0], res[1])
-        self.handle.settimeout(self._timeout)
+    def _do_open(self, family, socktype):
+        return socket.socket(family, socktype)
+
+    @property
+    def _address(self):
+        return self._unix_socket if self._unix_socket else '%s:%d' % (self.host, self.port)
+
+    def open(self):
+        if self.handle:
+            raise TTransportException(TTransportException.ALREADY_OPEN)
         try:
-          self.handle.connect(res[4])
-        except socket.error, e:
-          if res is not res0[-1]:
-            continue
-          else:
-            raise e
-        break
-    except socket.error, e:
-      if self._unix_socket:
-        message = 'Could not connect to socket %s' % self._unix_socket
-      else:
-        message = 'Could not connect to %s:%d' % (self.host, self.port)
-      raise TTransportException(type=TTransportException.NOT_OPEN,
-                                message=message)
+            addrs = self._resolveAddr()
+        except socket.gaierror:
+            msg = 'failed to resolve sockaddr for ' + str(self._address)
+            logger.exception(msg)
+            raise TTransportException(TTransportException.NOT_OPEN, msg)
+        for family, socktype, _, _, sockaddr in addrs:
+            handle = self._do_open(family, socktype)
+            handle.settimeout(self._timeout)
+            try:
+                handle.connect(sockaddr)
+                self.handle = handle
+                return
+            except socket.error:
+                handle.close()
+                logger.info('Could not connect to %s', sockaddr, exc_info=True)
+        msg = 'Could not connect to any of %s' % list(map(lambda a: a[4],
+                                                          addrs))
+        logger.error(msg)
+        raise TTransportException(TTransportException.NOT_OPEN, msg)
 
-  def read(self, sz):
-    try:
-      buff = self.handle.recv(sz)
-    except socket.error, e:
-      if (e.args[0] == errno.ECONNRESET and
-          (sys.platform == 'darwin' or sys.platform.startswith('freebsd'))):
-        # freebsd and Mach don't follow POSIX semantic of recv
-        # and fail with ECONNRESET if peer performed shutdown.
-        # See corresponding comment and code in TSocket::read()
-        # in lib/cpp/src/transport/TSocket.cpp.
-        self.close()
-        # Trigger the check to raise the END_OF_FILE exception below.
-        buff = ''
-      else:
-        raise
-    if len(buff) == 0:
-      raise TTransportException(type=TTransportException.END_OF_FILE,
-                                message='TSocket read 0 bytes')
-    return buff
+    def read(self, sz):
+        try:
+            buff = self.handle.recv(sz)
+        except socket.error as e:
+            if (e.args[0] == errno.ECONNRESET and
+                    (sys.platform == 'darwin' or sys.platform.startswith('freebsd'))):
+                # freebsd and Mach don't follow POSIX semantic of recv
+                # and fail with ECONNRESET if peer performed shutdown.
+                # See corresponding comment and code in TSocket::read()
+                # in lib/cpp/src/transport/TSocket.cpp.
+                self.close()
+                # Trigger the check to raise the END_OF_FILE exception below.
+                buff = ''
+            else:
+                raise
+        if len(buff) == 0:
+            raise TTransportException(type=TTransportException.END_OF_FILE,
+                                      message='TSocket read 0 bytes')
+        return buff
 
-  def write(self, buff):
-    if not self.handle:
-      raise TTransportException(type=TTransportException.NOT_OPEN,
-                                message='Transport not open')
-    sent = 0
-    have = len(buff)
-    while sent < have:
-      plus = self.handle.send(buff)
-      if plus == 0:
-        raise TTransportException(type=TTransportException.END_OF_FILE,
-                                  message='TSocket sent 0 bytes')
-      sent += plus
-      buff = buff[plus:]
+    def write(self, buff):
+        if not self.handle:
+            raise TTransportException(type=TTransportException.NOT_OPEN,
+                                      message='Transport not open')
+        sent = 0
+        have = len(buff)
+        while sent < have:
+            plus = self.handle.send(buff)
+            if plus == 0:
+                raise TTransportException(type=TTransportException.END_OF_FILE,
+                                          message='TSocket sent 0 bytes')
+            sent += plus
+            buff = buff[plus:]
 
-  def flush(self):
-    pass
+    def flush(self):
+        pass
 
 
 class TServerSocket(TSocketBase, TServerTransportBase):
-  """Socket implementation of TServerTransport base."""
+    """Socket implementation of TServerTransport base."""
 
-  def __init__(self, host=None, port=9090, unix_socket=None):
-    self.host = host
-    self.port = port
-    self._unix_socket = unix_socket
-    self.handle = None
+    def __init__(self, host=None, port=9090, unix_socket=None, socket_family=socket.AF_UNSPEC):
+        self.host = host
+        self.port = port
+        self._unix_socket = unix_socket
+        self._socket_family = socket_family
+        self.handle = None
+        self._backlog = 128
 
-  def listen(self):
-    res0 = self._resolveAddr()
-    for res in res0:
-      if res[0] is socket.AF_INET6 or res is res0[-1]:
-        break
+    def setBacklog(self, backlog=None):
+        if not self.handle:
+            self._backlog = backlog
+        else:
+            # We cann't update backlog when it is already listening, since the
+            # handle has been created.
+            logger.warn('You have to set backlog before listen.')
 
-    # We need remove the old unix socket if the file exists and
-    # nobody is listening on it.
-    if self._unix_socket:
-      tmp = socket.socket(res[0], res[1])
-      try:
-        tmp.connect(res[4])
-      except socket.error, err:
-        eno, message = err.args
-        if eno == errno.ECONNREFUSED:
-          os.unlink(res[4])
+    def listen(self):
+        res0 = self._resolveAddr()
+        socket_family = self._socket_family == socket.AF_UNSPEC and socket.AF_INET6 or self._socket_family
+        for res in res0:
+            if res[0] is socket_family or res is res0[-1]:
+                break
 
-    self.handle = socket.socket(res[0], res[1])
-    self.handle.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-    if hasattr(self.handle, 'settimeout'):
-      self.handle.settimeout(None)
-    self.handle.bind(res[4])
-    self.handle.listen(128)
+        # We need remove the old unix socket if the file exists and
+        # nobody is listening on it.
+        if self._unix_socket:
+            tmp = socket.socket(res[0], res[1])
+            try:
+                tmp.connect(res[4])
+            except socket.error as err:
+                eno, message = err.args
+                if eno == errno.ECONNREFUSED:
+                    os.unlink(res[4])
 
-  def accept(self):
-    client, addr = self.handle.accept()
-    result = TSocket()
-    result.setHandle(client)
-    return result
+        self.handle = socket.socket(res[0], res[1])
+        self.handle.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        if hasattr(self.handle, 'settimeout'):
+            self.handle.settimeout(None)
+        self.handle.bind(res[4])
+        self.handle.listen(self._backlog)
+
+    def accept(self):
+        client, addr = self.handle.accept()
+        result = TSocket()
+        result.setHandle(client)
+        return result
diff --git a/lib/py/src/transport/TTransport.py b/lib/py/src/transport/TTransport.py
index 4481371..d13060f 100644
--- a/lib/py/src/transport/TTransport.py
+++ b/lib/py/src/transport/TTransport.py
@@ -17,314 +17,439 @@
 # under the License.
 #
 
-from cStringIO import StringIO
 from struct import pack, unpack
 from thrift.Thrift import TException
+from ..compat import BufferIO
 
 
 class TTransportException(TException):
-  """Custom Transport Exception class"""
+    """Custom Transport Exception class"""
 
-  UNKNOWN = 0
-  NOT_OPEN = 1
-  ALREADY_OPEN = 2
-  TIMED_OUT = 3
-  END_OF_FILE = 4
+    UNKNOWN = 0
+    NOT_OPEN = 1
+    ALREADY_OPEN = 2
+    TIMED_OUT = 3
+    END_OF_FILE = 4
+    NEGATIVE_SIZE = 5
+    SIZE_LIMIT = 6
+    INVALID_CLIENT_TYPE = 7
 
-  def __init__(self, type=UNKNOWN, message=None):
-    TException.__init__(self, message)
-    self.type = type
+    def __init__(self, type=UNKNOWN, message=None):
+        TException.__init__(self, message)
+        self.type = type
 
 
-class TTransportBase:
-  """Base class for Thrift transport layer."""
+class TTransportBase(object):
+    """Base class for Thrift transport layer."""
 
-  def isOpen(self):
-    pass
+    def isOpen(self):
+        pass
 
-  def open(self):
-    pass
+    def open(self):
+        pass
 
-  def close(self):
-    pass
+    def close(self):
+        pass
 
-  def read(self, sz):
-    pass
+    def read(self, sz):
+        pass
 
-  def readAll(self, sz):
-    buff = ''
-    have = 0
-    while (have < sz):
-      chunk = self.read(sz - have)
-      have += len(chunk)
-      buff += chunk
+    def readAll(self, sz):
+        buff = b''
+        have = 0
+        while (have < sz):
+            chunk = self.read(sz - have)
+            chunkLen = len(chunk)
+            have += chunkLen
+            buff += chunk
 
-      if len(chunk) == 0:
-        raise EOFError()
+            if chunkLen == 0:
+                raise EOFError()
 
-    return buff
+        return buff
 
-  def write(self, buf):
-    pass
+    def write(self, buf):
+        pass
 
-  def flush(self):
-    pass
+    def flush(self):
+        pass
 
 
 # This class should be thought of as an interface.
-class CReadableTransport:
-  """base class for transports that are readable from C"""
+class CReadableTransport(object):
+    """base class for transports that are readable from C"""
 
-  # TODO(dreiss): Think about changing this interface to allow us to use
-  #               a (Python, not c) StringIO instead, because it allows
-  #               you to write after reading.
+    # TODO(dreiss): Think about changing this interface to allow us to use
+    #               a (Python, not c) StringIO instead, because it allows
+    #               you to write after reading.
 
-  # NOTE: This is a classic class, so properties will NOT work
-  #       correctly for setting.
-  @property
-  def cstringio_buf(self):
-    """A cStringIO buffer that contains the current chunk we are reading."""
-    pass
+    # NOTE: This is a classic class, so properties will NOT work
+    #       correctly for setting.
+    @property
+    def cstringio_buf(self):
+        """A cStringIO buffer that contains the current chunk we are reading."""
+        pass
 
-  def cstringio_refill(self, partialread, reqlen):
-    """Refills cstringio_buf.
+    def cstringio_refill(self, partialread, reqlen):
+        """Refills cstringio_buf.
 
-    Returns the currently used buffer (which can but need not be the same as
-    the old cstringio_buf). partialread is what the C code has read from the
-    buffer, and should be inserted into the buffer before any more reads.  The
-    return value must be a new, not borrowed reference.  Something along the
-    lines of self._buf should be fine.
+        Returns the currently used buffer (which can but need not be the same as
+        the old cstringio_buf). partialread is what the C code has read from the
+        buffer, and should be inserted into the buffer before any more reads.  The
+        return value must be a new, not borrowed reference.  Something along the
+        lines of self._buf should be fine.
 
-    If reqlen bytes can't be read, throw EOFError.
-    """
-    pass
+        If reqlen bytes can't be read, throw EOFError.
+        """
+        pass
 
 
-class TServerTransportBase:
-  """Base class for Thrift server transports."""
+class TServerTransportBase(object):
+    """Base class for Thrift server transports."""
 
-  def listen(self):
-    pass
+    def listen(self):
+        pass
 
-  def accept(self):
-    pass
+    def accept(self):
+        pass
 
-  def close(self):
-    pass
+    def close(self):
+        pass
 
 
-class TTransportFactoryBase:
-  """Base class for a Transport Factory"""
+class TTransportFactoryBase(object):
+    """Base class for a Transport Factory"""
 
-  def getTransport(self, trans):
-    return trans
+    def getTransport(self, trans):
+        return trans
 
 
-class TBufferedTransportFactory:
-  """Factory transport that builds buffered transports"""
+class TBufferedTransportFactory(object):
+    """Factory transport that builds buffered transports"""
 
-  def getTransport(self, trans):
-    buffered = TBufferedTransport(trans)
-    return buffered
+    def getTransport(self, trans):
+        buffered = TBufferedTransport(trans)
+        return buffered
 
 
 class TBufferedTransport(TTransportBase, CReadableTransport):
-  """Class that wraps another transport and buffers its I/O.
+    """Class that wraps another transport and buffers its I/O.
 
-  The implementation uses a (configurable) fixed-size read buffer
-  but buffers all writes until a flush is performed.
-  """
-  DEFAULT_BUFFER = 4096
+    The implementation uses a (configurable) fixed-size read buffer
+    but buffers all writes until a flush is performed.
+    """
+    DEFAULT_BUFFER = 4096
 
-  def __init__(self, trans, rbuf_size=DEFAULT_BUFFER):
-    self.__trans = trans
-    self.__wbuf = StringIO()
-    self.__rbuf = StringIO("")
-    self.__rbuf_size = rbuf_size
+    def __init__(self, trans, rbuf_size=DEFAULT_BUFFER):
+        self.__trans = trans
+        self.__wbuf = BufferIO()
+        # Pass string argument to initialize read buffer as cStringIO.InputType
+        self.__rbuf = BufferIO(b'')
+        self.__rbuf_size = rbuf_size
 
-  def isOpen(self):
-    return self.__trans.isOpen()
+    def isOpen(self):
+        return self.__trans.isOpen()
 
-  def open(self):
-    return self.__trans.open()
+    def open(self):
+        return self.__trans.open()
 
-  def close(self):
-    return self.__trans.close()
+    def close(self):
+        return self.__trans.close()
 
-  def read(self, sz):
-    ret = self.__rbuf.read(sz)
-    if len(ret) != 0:
-      return ret
+    def read(self, sz):
+        ret = self.__rbuf.read(sz)
+        if len(ret) != 0:
+            return ret
+        self.__rbuf = BufferIO(self.__trans.read(max(sz, self.__rbuf_size)))
+        return self.__rbuf.read(sz)
 
-    self.__rbuf = StringIO(self.__trans.read(max(sz, self.__rbuf_size)))
-    return self.__rbuf.read(sz)
+    def write(self, buf):
+        try:
+            self.__wbuf.write(buf)
+        except Exception as e:
+            # on exception reset wbuf so it doesn't contain a partial function call
+            self.__wbuf = BufferIO()
+            raise e
 
-  def write(self, buf):
-    self.__wbuf.write(buf)
+    def flush(self):
+        out = self.__wbuf.getvalue()
+        # reset wbuf before write/flush to preserve state on underlying failure
+        self.__wbuf = BufferIO()
+        self.__trans.write(out)
+        self.__trans.flush()
 
-  def flush(self):
-    out = self.__wbuf.getvalue()
-    # reset wbuf before write/flush to preserve state on underlying failure
-    self.__wbuf = StringIO()
-    self.__trans.write(out)
-    self.__trans.flush()
+    # Implement the CReadableTransport interface.
+    @property
+    def cstringio_buf(self):
+        return self.__rbuf
 
-  # Implement the CReadableTransport interface.
-  @property
-  def cstringio_buf(self):
-    return self.__rbuf
+    def cstringio_refill(self, partialread, reqlen):
+        retstring = partialread
+        if reqlen < self.__rbuf_size:
+            # try to make a read of as much as we can.
+            retstring += self.__trans.read(self.__rbuf_size)
 
-  def cstringio_refill(self, partialread, reqlen):
-    retstring = partialread
-    if reqlen < self.__rbuf_size:
-      # try to make a read of as much as we can.
-      retstring += self.__trans.read(self.__rbuf_size)
+        # but make sure we do read reqlen bytes.
+        if len(retstring) < reqlen:
+            retstring += self.__trans.readAll(reqlen - len(retstring))
 
-    # but make sure we do read reqlen bytes.
-    if len(retstring) < reqlen:
-      retstring += self.__trans.readAll(reqlen - len(retstring))
-
-    self.__rbuf = StringIO(retstring)
-    return self.__rbuf
+        self.__rbuf = BufferIO(retstring)
+        return self.__rbuf
 
 
 class TMemoryBuffer(TTransportBase, CReadableTransport):
-  """Wraps a cStringIO object as a TTransport.
+    """Wraps a cBytesIO object as a TTransport.
 
-  NOTE: Unlike the C++ version of this class, you cannot write to it
-        then immediately read from it.  If you want to read from a
-        TMemoryBuffer, you must either pass a string to the constructor.
-  TODO(dreiss): Make this work like the C++ version.
-  """
+    NOTE: Unlike the C++ version of this class, you cannot write to it
+          then immediately read from it.  If you want to read from a
+          TMemoryBuffer, you must either pass a string to the constructor.
+    TODO(dreiss): Make this work like the C++ version.
+    """
 
-  def __init__(self, value=None):
-    """value -- a value to read from for stringio
+    def __init__(self, value=None, offset=0):
+        """value -- a value to read from for stringio
 
-    If value is set, this will be a transport for reading,
-    otherwise, it is for writing"""
-    if value is not None:
-      self._buffer = StringIO(value)
-    else:
-      self._buffer = StringIO()
+        If value is set, this will be a transport for reading,
+        otherwise, it is for writing"""
+        if value is not None:
+            self._buffer = BufferIO(value)
+        else:
+            self._buffer = BufferIO()
+        if offset:
+            self._buffer.seek(offset)
 
-  def isOpen(self):
-    return not self._buffer.closed
+    def isOpen(self):
+        return not self._buffer.closed
 
-  def open(self):
-    pass
+    def open(self):
+        pass
 
-  def close(self):
-    self._buffer.close()
+    def close(self):
+        self._buffer.close()
 
-  def read(self, sz):
-    return self._buffer.read(sz)
+    def read(self, sz):
+        return self._buffer.read(sz)
 
-  def write(self, buf):
-    self._buffer.write(buf)
+    def write(self, buf):
+        self._buffer.write(buf)
 
-  def flush(self):
-    pass
+    def flush(self):
+        pass
 
-  def getvalue(self):
-    return self._buffer.getvalue()
+    def getvalue(self):
+        return self._buffer.getvalue()
 
-  # Implement the CReadableTransport interface.
-  @property
-  def cstringio_buf(self):
-    return self._buffer
+    # Implement the CReadableTransport interface.
+    @property
+    def cstringio_buf(self):
+        return self._buffer
 
-  def cstringio_refill(self, partialread, reqlen):
-    # only one shot at reading...
-    raise EOFError()
+    def cstringio_refill(self, partialread, reqlen):
+        # only one shot at reading...
+        raise EOFError()
 
 
-class TFramedTransportFactory:
-  """Factory transport that builds framed transports"""
+class TFramedTransportFactory(object):
+    """Factory transport that builds framed transports"""
 
-  def getTransport(self, trans):
-    framed = TFramedTransport(trans)
-    return framed
+    def getTransport(self, trans):
+        framed = TFramedTransport(trans)
+        return framed
 
 
 class TFramedTransport(TTransportBase, CReadableTransport):
-  """Class that wraps another transport and frames its I/O when writing."""
+    """Class that wraps another transport and frames its I/O when writing."""
 
-  def __init__(self, trans,):
-    self.__trans = trans
-    self.__rbuf = StringIO()
-    self.__wbuf = StringIO()
+    def __init__(self, trans,):
+        self.__trans = trans
+        self.__rbuf = BufferIO(b'')
+        self.__wbuf = BufferIO()
 
-  def isOpen(self):
-    return self.__trans.isOpen()
+    def isOpen(self):
+        return self.__trans.isOpen()
 
-  def open(self):
-    return self.__trans.open()
+    def open(self):
+        return self.__trans.open()
 
-  def close(self):
-    return self.__trans.close()
+    def close(self):
+        return self.__trans.close()
 
-  def read(self, sz):
-    ret = self.__rbuf.read(sz)
-    if len(ret) != 0:
-      return ret
+    def read(self, sz):
+        ret = self.__rbuf.read(sz)
+        if len(ret) != 0:
+            return ret
 
-    self.readFrame()
-    return self.__rbuf.read(sz)
+        self.readFrame()
+        return self.__rbuf.read(sz)
 
-  def readFrame(self):
-    buff = self.__trans.readAll(4)
-    sz, = unpack('!i', buff)
-    self.__rbuf = StringIO(self.__trans.readAll(sz))
+    def readFrame(self):
+        buff = self.__trans.readAll(4)
+        sz, = unpack('!i', buff)
+        self.__rbuf = BufferIO(self.__trans.readAll(sz))
 
-  def write(self, buf):
-    self.__wbuf.write(buf)
+    def write(self, buf):
+        self.__wbuf.write(buf)
 
-  def flush(self):
-    wout = self.__wbuf.getvalue()
-    wsz = len(wout)
-    # reset wbuf before write/flush to preserve state on underlying failure
-    self.__wbuf = StringIO()
-    # N.B.: Doing this string concatenation is WAY cheaper than making
-    # two separate calls to the underlying socket object. Socket writes in
-    # Python turn out to be REALLY expensive, but it seems to do a pretty
-    # good job of managing string buffer operations without excessive copies
-    buf = pack("!i", wsz) + wout
-    self.__trans.write(buf)
-    self.__trans.flush()
+    def flush(self):
+        wout = self.__wbuf.getvalue()
+        wsz = len(wout)
+        # reset wbuf before write/flush to preserve state on underlying failure
+        self.__wbuf = BufferIO()
+        # N.B.: Doing this string concatenation is WAY cheaper than making
+        # two separate calls to the underlying socket object. Socket writes in
+        # Python turn out to be REALLY expensive, but it seems to do a pretty
+        # good job of managing string buffer operations without excessive copies
+        buf = pack("!i", wsz) + wout
+        self.__trans.write(buf)
+        self.__trans.flush()
 
-  # Implement the CReadableTransport interface.
-  @property
-  def cstringio_buf(self):
-    return self.__rbuf
+    # Implement the CReadableTransport interface.
+    @property
+    def cstringio_buf(self):
+        return self.__rbuf
 
-  def cstringio_refill(self, prefix, reqlen):
-    # self.__rbuf will already be empty here because fastbinary doesn't
-    # ask for a refill until the previous buffer is empty.  Therefore,
-    # we can start reading new frames immediately.
-    while len(prefix) < reqlen:
-      self.readFrame()
-      prefix += self.__rbuf.getvalue()
-    self.__rbuf = StringIO(prefix)
-    return self.__rbuf
+    def cstringio_refill(self, prefix, reqlen):
+        # self.__rbuf will already be empty here because fastbinary doesn't
+        # ask for a refill until the previous buffer is empty.  Therefore,
+        # we can start reading new frames immediately.
+        while len(prefix) < reqlen:
+            self.readFrame()
+            prefix += self.__rbuf.getvalue()
+        self.__rbuf = BufferIO(prefix)
+        return self.__rbuf
 
 
 class TFileObjectTransport(TTransportBase):
-  """Wraps a file-like object to make it work as a Thrift transport."""
+    """Wraps a file-like object to make it work as a Thrift transport."""
 
-  def __init__(self, fileobj):
-    self.fileobj = fileobj
+    def __init__(self, fileobj):
+        self.fileobj = fileobj
 
-  def isOpen(self):
-    return True
+    def isOpen(self):
+        return True
 
-  def close(self):
-    self.fileobj.close()
+    def close(self):
+        self.fileobj.close()
 
-  def read(self, sz):
-    return self.fileobj.read(sz)
+    def read(self, sz):
+        return self.fileobj.read(sz)
 
-  def write(self, buf):
-    self.fileobj.write(buf)
+    def write(self, buf):
+        self.fileobj.write(buf)
 
-  def flush(self):
-    self.fileobj.flush()
+    def flush(self):
+        self.fileobj.flush()
+
+
+class TSaslClientTransport(TTransportBase, CReadableTransport):
+    """
+    SASL transport
+    """
+
+    START = 1
+    OK = 2
+    BAD = 3
+    ERROR = 4
+    COMPLETE = 5
+
+    def __init__(self, transport, host, service, mechanism='GSSAPI',
+                 **sasl_kwargs):
+        """
+        transport: an underlying transport to use, typically just a TSocket
+        host: the name of the server, from a SASL perspective
+        service: the name of the server's service, from a SASL perspective
+        mechanism: the name of the preferred mechanism to use
+
+        All other kwargs will be passed to the puresasl.client.SASLClient
+        constructor.
+        """
+
+        from puresasl.client import SASLClient
+
+        self.transport = transport
+        self.sasl = SASLClient(host, service, mechanism, **sasl_kwargs)
+
+        self.__wbuf = BufferIO()
+        self.__rbuf = BufferIO(b'')
+
+    def open(self):
+        if not self.transport.isOpen():
+            self.transport.open()
+
+        self.send_sasl_msg(self.START, self.sasl.mechanism)
+        self.send_sasl_msg(self.OK, self.sasl.process())
+
+        while True:
+            status, challenge = self.recv_sasl_msg()
+            if status == self.OK:
+                self.send_sasl_msg(self.OK, self.sasl.process(challenge))
+            elif status == self.COMPLETE:
+                if not self.sasl.complete:
+                    raise TTransportException(
+                        TTransportException.NOT_OPEN,
+                        "The server erroneously indicated "
+                        "that SASL negotiation was complete")
+                else:
+                    break
+            else:
+                raise TTransportException(
+                    TTransportException.NOT_OPEN,
+                    "Bad SASL negotiation status: %d (%s)"
+                    % (status, challenge))
+
+    def send_sasl_msg(self, status, body):
+        header = pack(">BI", status, len(body))
+        self.transport.write(header + body)
+        self.transport.flush()
+
+    def recv_sasl_msg(self):
+        header = self.transport.readAll(5)
+        status, length = unpack(">BI", header)
+        if length > 0:
+            payload = self.transport.readAll(length)
+        else:
+            payload = ""
+        return status, payload
+
+    def write(self, data):
+        self.__wbuf.write(data)
+
+    def flush(self):
+        data = self.__wbuf.getvalue()
+        encoded = self.sasl.wrap(data)
+        self.transport.write(''.join((pack("!i", len(encoded)), encoded)))
+        self.transport.flush()
+        self.__wbuf = BufferIO()
+
+    def read(self, sz):
+        ret = self.__rbuf.read(sz)
+        if len(ret) != 0:
+            return ret
+
+        self._read_frame()
+        return self.__rbuf.read(sz)
+
+    def _read_frame(self):
+        header = self.transport.readAll(4)
+        length, = unpack('!i', header)
+        encoded = self.transport.readAll(length)
+        self.__rbuf = BufferIO(self.sasl.unwrap(encoded))
+
+    def close(self):
+        self.sasl.dispose()
+        self.transport.close()
+
+    # based on TFramedTransport
+    @property
+    def cstringio_buf(self):
+        return self.__rbuf
+
+    def cstringio_refill(self, prefix, reqlen):
+        # self.__rbuf will already be empty here because fastbinary doesn't
+        # ask for a refill until the previous buffer is empty.  Therefore,
+        # we can start reading new frames immediately.
+        while len(prefix) < reqlen:
+            self._read_frame()
+            prefix += self.__rbuf.getvalue()
+        self.__rbuf = BufferIO(prefix)
+        return self.__rbuf
diff --git a/lib/py/src/transport/TTwisted.py b/lib/py/src/transport/TTwisted.py
index 3ce3eb2..a27f0ad 100644
--- a/lib/py/src/transport/TTwisted.py
+++ b/lib/py/src/transport/TTwisted.py
@@ -17,14 +17,15 @@
 # under the License.
 #
 
-from cStringIO import StringIO
+from io import BytesIO
+import struct
 
-from zope.interface import implements, Interface, Attribute
-from twisted.internet.protocol import Protocol, ServerFactory, ClientFactory, \
+from zope.interface import implementer, Interface, Attribute
+from twisted.internet.protocol import ServerFactory, ClientFactory, \
     connectionDone
 from twisted.internet import defer
+from twisted.internet.threads import deferToThread
 from twisted.protocols import basic
-from twisted.python import log
 from twisted.web import server, resource, http
 
 from thrift.transport import TTransport
@@ -33,15 +34,15 @@
 class TMessageSenderTransport(TTransport.TTransportBase):
 
     def __init__(self):
-        self.__wbuf = StringIO()
+        self.__wbuf = BytesIO()
 
     def write(self, buf):
         self.__wbuf.write(buf)
 
     def flush(self):
         msg = self.__wbuf.getvalue()
-        self.__wbuf = StringIO()
-        self.sendMessage(msg)
+        self.__wbuf = BytesIO()
+        return self.sendMessage(msg)
 
     def sendMessage(self, message):
         raise NotImplementedError
@@ -54,7 +55,7 @@
         self.func = func
 
     def sendMessage(self, message):
-        self.func(message)
+        return self.func(message)
 
 
 class ThriftClientProtocol(basic.Int32StringReceiver):
@@ -81,11 +82,18 @@
         self.started.callback(self.client)
 
     def connectionLost(self, reason=connectionDone):
-        for k, v in self.client._reqs.iteritems():
+        # the called errbacks can add items to our client's _reqs,
+        # so we need to use a tmp, and iterate until no more requests
+        # are added during errbacks
+        if self.client:
             tex = TTransport.TTransportException(
                 type=TTransport.TTransportException.END_OF_FILE,
-                message='Connection closed')
-            v.errback(tex)
+                message='Connection closed (%s)' % reason)
+            while self.client._reqs:
+                _, v = self.client._reqs.popitem()
+                v.errback(tex)
+            del self.client._reqs
+            self.client = None
 
     def stringReceived(self, frame):
         tr = TTransport.TMemoryBuffer(frame)
@@ -101,6 +109,108 @@
         method(iprot, mtype, rseqid)
 
 
+class ThriftSASLClientProtocol(ThriftClientProtocol):
+
+    START = 1
+    OK = 2
+    BAD = 3
+    ERROR = 4
+    COMPLETE = 5
+
+    MAX_LENGTH = 2 ** 31 - 1
+
+    def __init__(self, client_class, iprot_factory, oprot_factory=None,
+                 host=None, service=None, mechanism='GSSAPI', **sasl_kwargs):
+        """
+        host: the name of the server, from a SASL perspective
+        service: the name of the server's service, from a SASL perspective
+        mechanism: the name of the preferred mechanism to use
+
+        All other kwargs will be passed to the puresasl.client.SASLClient
+        constructor.
+        """
+
+        from puresasl.client import SASLClient
+        self.SASLCLient = SASLClient
+
+        ThriftClientProtocol.__init__(self, client_class, iprot_factory, oprot_factory)
+
+        self._sasl_negotiation_deferred = None
+        self._sasl_negotiation_status = None
+        self.client = None
+
+        if host is not None:
+            self.createSASLClient(host, service, mechanism, **sasl_kwargs)
+
+    def createSASLClient(self, host, service, mechanism, **kwargs):
+        self.sasl = self.SASLClient(host, service, mechanism, **kwargs)
+
+    def dispatch(self, msg):
+        encoded = self.sasl.wrap(msg)
+        len_and_encoded = ''.join((struct.pack('!i', len(encoded)), encoded))
+        ThriftClientProtocol.dispatch(self, len_and_encoded)
+
+    @defer.inlineCallbacks
+    def connectionMade(self):
+        self._sendSASLMessage(self.START, self.sasl.mechanism)
+        initial_message = yield deferToThread(self.sasl.process)
+        self._sendSASLMessage(self.OK, initial_message)
+
+        while True:
+            status, challenge = yield self._receiveSASLMessage()
+            if status == self.OK:
+                response = yield deferToThread(self.sasl.process, challenge)
+                self._sendSASLMessage(self.OK, response)
+            elif status == self.COMPLETE:
+                if not self.sasl.complete:
+                    msg = "The server erroneously indicated that SASL " \
+                          "negotiation was complete"
+                    raise TTransport.TTransportException(msg, message=msg)
+                else:
+                    break
+            else:
+                msg = "Bad SASL negotiation status: %d (%s)" % (status, challenge)
+                raise TTransport.TTransportException(msg, message=msg)
+
+        self._sasl_negotiation_deferred = None
+        ThriftClientProtocol.connectionMade(self)
+
+    def _sendSASLMessage(self, status, body):
+        if body is None:
+            body = ""
+        header = struct.pack(">BI", status, len(body))
+        self.transport.write(header + body)
+
+    def _receiveSASLMessage(self):
+        self._sasl_negotiation_deferred = defer.Deferred()
+        self._sasl_negotiation_status = None
+        return self._sasl_negotiation_deferred
+
+    def connectionLost(self, reason=connectionDone):
+        if self.client:
+            ThriftClientProtocol.connectionLost(self, reason)
+
+    def dataReceived(self, data):
+        if self._sasl_negotiation_deferred:
+            # we got a sasl challenge in the format (status, length, challenge)
+            # save the status, let IntNStringReceiver piece the challenge data together
+            self._sasl_negotiation_status, = struct.unpack("B", data[0])
+            ThriftClientProtocol.dataReceived(self, data[1:])
+        else:
+            # normal frame, let IntNStringReceiver piece it together
+            ThriftClientProtocol.dataReceived(self, data)
+
+    def stringReceived(self, frame):
+        if self._sasl_negotiation_deferred:
+            # the frame is just a SASL challenge
+            response = (self._sasl_negotiation_status, frame)
+            self._sasl_negotiation_deferred.callback(response)
+        else:
+            # there's a second 4 byte length prefix inside the frame
+            decoded_frame = self.sasl.unwrap(frame[4:])
+            ThriftClientProtocol.stringReceived(self, decoded_frame)
+
+
 class ThriftServerProtocol(basic.Int32StringReceiver):
 
     MAX_LENGTH = 2 ** 31 - 1
@@ -126,7 +236,7 @@
 
         d = self.factory.processor.process(iprot, oprot)
         d.addCallbacks(self.processOk, self.processError,
-            callbackArgs=(tmo,))
+                       callbackArgs=(tmo,))
 
 
 class IThriftServerFactory(Interface):
@@ -147,10 +257,9 @@
     oprot_factory = Attribute("Output protocol factory")
 
 
+@implementer(IThriftServerFactory)
 class ThriftServerFactory(ServerFactory):
 
-    implements(IThriftServerFactory)
-
     protocol = ThriftServerProtocol
 
     def __init__(self, processor, iprot_factory, oprot_factory=None):
@@ -162,10 +271,9 @@
             self.oprot_factory = oprot_factory
 
 
+@implementer(IThriftClientFactory)
 class ThriftClientFactory(ClientFactory):
 
-    implements(IThriftClientFactory)
-
     protocol = ThriftClientProtocol
 
     def __init__(self, client_class, iprot_factory, oprot_factory=None):
@@ -178,7 +286,7 @@
 
     def buildProtocol(self, addr):
         p = self.protocol(self.client_class, self.iprot_factory,
-            self.oprot_factory)
+                          self.oprot_factory)
         p.factory = self
         return p
 
@@ -188,7 +296,7 @@
     allowedMethods = ('POST',)
 
     def __init__(self, processor, inputProtocolFactory,
-        outputProtocolFactory=None):
+                 outputProtocolFactory=None):
         resource.Resource.__init__(self)
         self.inputProtocolFactory = inputProtocolFactory
         if outputProtocolFactory is None:
diff --git a/lib/py/src/transport/TZlibTransport.py b/lib/py/src/transport/TZlibTransport.py
index a2f42a5..e848579 100644
--- a/lib/py/src/transport/TZlibTransport.py
+++ b/lib/py/src/transport/TZlibTransport.py
@@ -24,225 +24,225 @@
 
 from __future__ import division
 import zlib
-from cStringIO import StringIO
-from TTransport import TTransportBase, CReadableTransport
+from .TTransport import TTransportBase, CReadableTransport
+from ..compat import BufferIO
 
 
 class TZlibTransportFactory(object):
-  """Factory transport that builds zlib compressed transports.
+    """Factory transport that builds zlib compressed transports.
 
-  This factory caches the last single client/transport that it was passed
-  and returns the same TZlibTransport object that was created.
+    This factory caches the last single client/transport that it was passed
+    and returns the same TZlibTransport object that was created.
 
-  This caching means the TServer class will get the _same_ transport
-  object for both input and output transports from this factory.
-  (For non-threaded scenarios only, since the cache only holds one object)
+    This caching means the TServer class will get the _same_ transport
+    object for both input and output transports from this factory.
+    (For non-threaded scenarios only, since the cache only holds one object)
 
-  The purpose of this caching is to allocate only one TZlibTransport where
-  only one is really needed (since it must have separate read/write buffers),
-  and makes the statistics from getCompSavings() and getCompRatio()
-  easier to understand.
-  """
-  # class scoped cache of last transport given and zlibtransport returned
-  _last_trans = None
-  _last_z = None
-
-  def getTransport(self, trans, compresslevel=9):
-    """Wrap a transport, trans, with the TZlibTransport
-    compressed transport class, returning a new
-    transport to the caller.
-
-    @param compresslevel: The zlib compression level, ranging
-    from 0 (no compression) to 9 (best compression).  Defaults to 9.
-    @type compresslevel: int
-
-    This method returns a TZlibTransport which wraps the
-    passed C{trans} TTransport derived instance.
+    The purpose of this caching is to allocate only one TZlibTransport where
+    only one is really needed (since it must have separate read/write buffers),
+    and makes the statistics from getCompSavings() and getCompRatio()
+    easier to understand.
     """
-    if trans == self._last_trans:
-      return self._last_z
-    ztrans = TZlibTransport(trans, compresslevel)
-    self._last_trans = trans
-    self._last_z = ztrans
-    return ztrans
+    # class scoped cache of last transport given and zlibtransport returned
+    _last_trans = None
+    _last_z = None
+
+    def getTransport(self, trans, compresslevel=9):
+        """Wrap a transport, trans, with the TZlibTransport
+        compressed transport class, returning a new
+        transport to the caller.
+
+        @param compresslevel: The zlib compression level, ranging
+        from 0 (no compression) to 9 (best compression).  Defaults to 9.
+        @type compresslevel: int
+
+        This method returns a TZlibTransport which wraps the
+        passed C{trans} TTransport derived instance.
+        """
+        if trans == self._last_trans:
+            return self._last_z
+        ztrans = TZlibTransport(trans, compresslevel)
+        self._last_trans = trans
+        self._last_z = ztrans
+        return ztrans
 
 
 class TZlibTransport(TTransportBase, CReadableTransport):
-  """Class that wraps a transport with zlib, compressing writes
-  and decompresses reads, using the python standard
-  library zlib module.
-  """
-  # Read buffer size for the python fastbinary C extension,
-  # the TBinaryProtocolAccelerated class.
-  DEFAULT_BUFFSIZE = 4096
-
-  def __init__(self, trans, compresslevel=9):
-    """Create a new TZlibTransport, wrapping C{trans}, another
-    TTransport derived object.
-
-    @param trans: A thrift transport object, i.e. a TSocket() object.
-    @type trans: TTransport
-    @param compresslevel: The zlib compression level, ranging
-    from 0 (no compression) to 9 (best compression).  Default is 9.
-    @type compresslevel: int
+    """Class that wraps a transport with zlib, compressing writes
+    and decompresses reads, using the python standard
+    library zlib module.
     """
-    self.__trans = trans
-    self.compresslevel = compresslevel
-    self.__rbuf = StringIO()
-    self.__wbuf = StringIO()
-    self._init_zlib()
-    self._init_stats()
+    # Read buffer size for the python fastbinary C extension,
+    # the TBinaryProtocolAccelerated class.
+    DEFAULT_BUFFSIZE = 4096
 
-  def _reinit_buffers(self):
-    """Internal method to initialize/reset the internal StringIO objects
-    for read and write buffers.
-    """
-    self.__rbuf = StringIO()
-    self.__wbuf = StringIO()
+    def __init__(self, trans, compresslevel=9):
+        """Create a new TZlibTransport, wrapping C{trans}, another
+        TTransport derived object.
 
-  def _init_stats(self):
-    """Internal method to reset the internal statistics counters
-    for compression ratios and bandwidth savings.
-    """
-    self.bytes_in = 0
-    self.bytes_out = 0
-    self.bytes_in_comp = 0
-    self.bytes_out_comp = 0
+        @param trans: A thrift transport object, i.e. a TSocket() object.
+        @type trans: TTransport
+        @param compresslevel: The zlib compression level, ranging
+        from 0 (no compression) to 9 (best compression).  Default is 9.
+        @type compresslevel: int
+        """
+        self.__trans = trans
+        self.compresslevel = compresslevel
+        self.__rbuf = BufferIO()
+        self.__wbuf = BufferIO()
+        self._init_zlib()
+        self._init_stats()
 
-  def _init_zlib(self):
-    """Internal method for setting up the zlib compression and
-    decompression objects.
-    """
-    self._zcomp_read = zlib.decompressobj()
-    self._zcomp_write = zlib.compressobj(self.compresslevel)
+    def _reinit_buffers(self):
+        """Internal method to initialize/reset the internal StringIO objects
+        for read and write buffers.
+        """
+        self.__rbuf = BufferIO()
+        self.__wbuf = BufferIO()
 
-  def getCompRatio(self):
-    """Get the current measured compression ratios (in,out) from
-    this transport.
+    def _init_stats(self):
+        """Internal method to reset the internal statistics counters
+        for compression ratios and bandwidth savings.
+        """
+        self.bytes_in = 0
+        self.bytes_out = 0
+        self.bytes_in_comp = 0
+        self.bytes_out_comp = 0
 
-    Returns a tuple of:
-    (inbound_compression_ratio, outbound_compression_ratio)
+    def _init_zlib(self):
+        """Internal method for setting up the zlib compression and
+        decompression objects.
+        """
+        self._zcomp_read = zlib.decompressobj()
+        self._zcomp_write = zlib.compressobj(self.compresslevel)
 
-    The compression ratios are computed as:
-        compressed / uncompressed
+    def getCompRatio(self):
+        """Get the current measured compression ratios (in,out) from
+        this transport.
 
-    E.g., data that compresses by 10x will have a ratio of: 0.10
-    and data that compresses to half of ts original size will
-    have a ratio of 0.5
+        Returns a tuple of:
+        (inbound_compression_ratio, outbound_compression_ratio)
 
-    None is returned if no bytes have yet been processed in
-    a particular direction.
-    """
-    r_percent, w_percent = (None, None)
-    if self.bytes_in > 0:
-      r_percent = self.bytes_in_comp / self.bytes_in
-    if self.bytes_out > 0:
-      w_percent = self.bytes_out_comp / self.bytes_out
-    return (r_percent, w_percent)
+        The compression ratios are computed as:
+            compressed / uncompressed
 
-  def getCompSavings(self):
-    """Get the current count of saved bytes due to data
-    compression.
+        E.g., data that compresses by 10x will have a ratio of: 0.10
+        and data that compresses to half of ts original size will
+        have a ratio of 0.5
 
-    Returns a tuple of:
-    (inbound_saved_bytes, outbound_saved_bytes)
+        None is returned if no bytes have yet been processed in
+        a particular direction.
+        """
+        r_percent, w_percent = (None, None)
+        if self.bytes_in > 0:
+            r_percent = self.bytes_in_comp / self.bytes_in
+        if self.bytes_out > 0:
+            w_percent = self.bytes_out_comp / self.bytes_out
+        return (r_percent, w_percent)
 
-    Note: if compression is actually expanding your
-    data (only likely with very tiny thrift objects), then
-    the values returned will be negative.
-    """
-    r_saved = self.bytes_in - self.bytes_in_comp
-    w_saved = self.bytes_out - self.bytes_out_comp
-    return (r_saved, w_saved)
+    def getCompSavings(self):
+        """Get the current count of saved bytes due to data
+        compression.
 
-  def isOpen(self):
-    """Return the underlying transport's open status"""
-    return self.__trans.isOpen()
+        Returns a tuple of:
+        (inbound_saved_bytes, outbound_saved_bytes)
 
-  def open(self):
-    """Open the underlying transport"""
-    self._init_stats()
-    return self.__trans.open()
+        Note: if compression is actually expanding your
+        data (only likely with very tiny thrift objects), then
+        the values returned will be negative.
+        """
+        r_saved = self.bytes_in - self.bytes_in_comp
+        w_saved = self.bytes_out - self.bytes_out_comp
+        return (r_saved, w_saved)
 
-  def listen(self):
-    """Invoke the underlying transport's listen() method"""
-    self.__trans.listen()
+    def isOpen(self):
+        """Return the underlying transport's open status"""
+        return self.__trans.isOpen()
 
-  def accept(self):
-    """Accept connections on the underlying transport"""
-    return self.__trans.accept()
+    def open(self):
+        """Open the underlying transport"""
+        self._init_stats()
+        return self.__trans.open()
 
-  def close(self):
-    """Close the underlying transport,"""
-    self._reinit_buffers()
-    self._init_zlib()
-    return self.__trans.close()
+    def listen(self):
+        """Invoke the underlying transport's listen() method"""
+        self.__trans.listen()
 
-  def read(self, sz):
-    """Read up to sz bytes from the decompressed bytes buffer, and
-    read from the underlying transport if the decompression
-    buffer is empty.
-    """
-    ret = self.__rbuf.read(sz)
-    if len(ret) > 0:
-      return ret
-    # keep reading from transport until something comes back
-    while True:
-      if self.readComp(sz):
-        break
-    ret = self.__rbuf.read(sz)
-    return ret
+    def accept(self):
+        """Accept connections on the underlying transport"""
+        return self.__trans.accept()
 
-  def readComp(self, sz):
-    """Read compressed data from the underlying transport, then
-    decompress it and append it to the internal StringIO read buffer
-    """
-    zbuf = self.__trans.read(sz)
-    zbuf = self._zcomp_read.unconsumed_tail + zbuf
-    buf = self._zcomp_read.decompress(zbuf)
-    self.bytes_in += len(zbuf)
-    self.bytes_in_comp += len(buf)
-    old = self.__rbuf.read()
-    self.__rbuf = StringIO(old + buf)
-    if len(old) + len(buf) == 0:
-      return False
-    return True
+    def close(self):
+        """Close the underlying transport,"""
+        self._reinit_buffers()
+        self._init_zlib()
+        return self.__trans.close()
 
-  def write(self, buf):
-    """Write some bytes, putting them into the internal write
-    buffer for eventual compression.
-    """
-    self.__wbuf.write(buf)
+    def read(self, sz):
+        """Read up to sz bytes from the decompressed bytes buffer, and
+        read from the underlying transport if the decompression
+        buffer is empty.
+        """
+        ret = self.__rbuf.read(sz)
+        if len(ret) > 0:
+            return ret
+        # keep reading from transport until something comes back
+        while True:
+            if self.readComp(sz):
+                break
+        ret = self.__rbuf.read(sz)
+        return ret
 
-  def flush(self):
-    """Flush any queued up data in the write buffer and ensure the
-    compression buffer is flushed out to the underlying transport
-    """
-    wout = self.__wbuf.getvalue()
-    if len(wout) > 0:
-      zbuf = self._zcomp_write.compress(wout)
-      self.bytes_out += len(wout)
-      self.bytes_out_comp += len(zbuf)
-    else:
-      zbuf = ''
-    ztail = self._zcomp_write.flush(zlib.Z_SYNC_FLUSH)
-    self.bytes_out_comp += len(ztail)
-    if (len(zbuf) + len(ztail)) > 0:
-      self.__wbuf = StringIO()
-      self.__trans.write(zbuf + ztail)
-    self.__trans.flush()
+    def readComp(self, sz):
+        """Read compressed data from the underlying transport, then
+        decompress it and append it to the internal StringIO read buffer
+        """
+        zbuf = self.__trans.read(sz)
+        zbuf = self._zcomp_read.unconsumed_tail + zbuf
+        buf = self._zcomp_read.decompress(zbuf)
+        self.bytes_in += len(zbuf)
+        self.bytes_in_comp += len(buf)
+        old = self.__rbuf.read()
+        self.__rbuf = BufferIO(old + buf)
+        if len(old) + len(buf) == 0:
+            return False
+        return True
 
-  @property
-  def cstringio_buf(self):
-    """Implement the CReadableTransport interface"""
-    return self.__rbuf
+    def write(self, buf):
+        """Write some bytes, putting them into the internal write
+        buffer for eventual compression.
+        """
+        self.__wbuf.write(buf)
 
-  def cstringio_refill(self, partialread, reqlen):
-    """Implement the CReadableTransport interface for refill"""
-    retstring = partialread
-    if reqlen < self.DEFAULT_BUFFSIZE:
-      retstring += self.read(self.DEFAULT_BUFFSIZE)
-    while len(retstring) < reqlen:
-      retstring += self.read(reqlen - len(retstring))
-    self.__rbuf = StringIO(retstring)
-    return self.__rbuf
+    def flush(self):
+        """Flush any queued up data in the write buffer and ensure the
+        compression buffer is flushed out to the underlying transport
+        """
+        wout = self.__wbuf.getvalue()
+        if len(wout) > 0:
+            zbuf = self._zcomp_write.compress(wout)
+            self.bytes_out += len(wout)
+            self.bytes_out_comp += len(zbuf)
+        else:
+            zbuf = ''
+        ztail = self._zcomp_write.flush(zlib.Z_SYNC_FLUSH)
+        self.bytes_out_comp += len(ztail)
+        if (len(zbuf) + len(ztail)) > 0:
+            self.__wbuf = BufferIO()
+            self.__trans.write(zbuf + ztail)
+        self.__trans.flush()
+
+    @property
+    def cstringio_buf(self):
+        """Implement the CReadableTransport interface"""
+        return self.__rbuf
+
+    def cstringio_refill(self, partialread, reqlen):
+        """Implement the CReadableTransport interface for refill"""
+        retstring = partialread
+        if reqlen < self.DEFAULT_BUFFSIZE:
+            retstring += self.read(self.DEFAULT_BUFFSIZE)
+        while len(retstring) < reqlen:
+            retstring += self.read(reqlen - len(retstring))
+        self.__rbuf = BufferIO(retstring)
+        return self.__rbuf
diff --git a/lib/py/src/transport/sslcompat.py b/lib/py/src/transport/sslcompat.py
new file mode 100644
index 0000000..ab00cb2
--- /dev/null
+++ b/lib/py/src/transport/sslcompat.py
@@ -0,0 +1,100 @@
+#
+# licensed to the apache software foundation (asf) under one
+# or more contributor license agreements. see the notice file
+# distributed with this work for additional information
+# regarding copyright ownership. the asf licenses this file
+# to you under the apache license, version 2.0 (the
+# "license"); you may not use this file except in compliance
+# with the license. you may obtain a copy of the license at
+#
+#   http://www.apache.org/licenses/license-2.0
+#
+# unless required by applicable law or agreed to in writing,
+# software distributed under the license is distributed on an
+# "as is" basis, without warranties or conditions of any
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import logging
+import sys
+
+from thrift.transport.TTransport import TTransportException
+
+logger = logging.getLogger(__name__)
+
+
+def legacy_validate_callback(cert, hostname):
+    """legacy method to validate the peer's SSL certificate, and to check
+    the commonName of the certificate to ensure it matches the hostname we
+    used to make this connection.  Does not support subjectAltName records
+    in certificates.
+
+    raises TTransportException if the certificate fails validation.
+    """
+    if 'subject' not in cert:
+        raise TTransportException(
+            TTransportException.NOT_OPEN,
+            'No SSL certificate found from %s' % hostname)
+    fields = cert['subject']
+    for field in fields:
+        # ensure structure we get back is what we expect
+        if not isinstance(field, tuple):
+            continue
+        cert_pair = field[0]
+        if len(cert_pair) < 2:
+            continue
+        cert_key, cert_value = cert_pair[0:2]
+        if cert_key != 'commonName':
+            continue
+        certhost = cert_value
+        # this check should be performed by some sort of Access Manager
+        if certhost == hostname:
+            # success, cert commonName matches desired hostname
+            return
+        else:
+            raise TTransportException(
+                TTransportException.UNKNOWN,
+                'Hostname we connected to "%s" doesn\'t match certificate '
+                'provided commonName "%s"' % (hostname, certhost))
+    raise TTransportException(
+        TTransportException.UNKNOWN,
+        'Could not validate SSL certificate from host "%s".  Cert=%s'
+        % (hostname, cert))
+
+
+def _optional_dependencies():
+    try:
+        import ipaddress  # noqa
+        logger.debug('ipaddress module is available')
+        ipaddr = True
+    except ImportError:
+        logger.warn('ipaddress module is unavailable')
+        ipaddr = False
+
+    if sys.hexversion < 0x030500F0:
+        try:
+            from backports.ssl_match_hostname import match_hostname, __version__ as ver
+            ver = list(map(int, ver.split('.')))
+            logger.debug('backports.ssl_match_hostname module is available')
+            match = match_hostname
+            if ver[0] * 10 + ver[1] >= 35:
+                return ipaddr, match
+            else:
+                logger.warn('backports.ssl_match_hostname module is too old')
+                ipaddr = False
+        except ImportError:
+            logger.warn('backports.ssl_match_hostname is unavailable')
+            ipaddr = False
+    try:
+        from ssl import match_hostname
+        logger.debug('ssl.match_hostname is available')
+        match = match_hostname
+    except ImportError:
+        logger.warn('using legacy validation callback')
+        match = legacy_validate_callback
+    return ipaddr, match
+
+
+_match_has_ipaddress, _match_hostname = _optional_dependencies()
diff --git a/lib/py/test/_import_local_thrift.py b/lib/py/test/_import_local_thrift.py
new file mode 100644
index 0000000..d223122
--- /dev/null
+++ b/lib/py/test/_import_local_thrift.py
@@ -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.
+#
+
+import glob
+import os
+import sys
+
+SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__))
+ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(SCRIPT_DIR)))
+
+for libpath in glob.glob(os.path.join(ROOT_DIR, 'lib', 'py', 'build', 'lib.*')):
+    if libpath.endswith('-%d.%d' % (sys.version_info[0], sys.version_info[1])):
+        sys.path.insert(0, libpath)
+        break
diff --git a/lib/py/test/test_sslsocket.py b/lib/py/test/test_sslsocket.py
new file mode 100644
index 0000000..f1344e5
--- /dev/null
+++ b/lib/py/test/test_sslsocket.py
@@ -0,0 +1,346 @@
+#
+# 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 inspect
+import logging
+import os
+import platform
+import ssl
+import sys
+import tempfile
+import threading
+import unittest
+import warnings
+from contextlib import contextmanager
+
+import _import_local_thrift  # noqa
+
+SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__))
+ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(SCRIPT_DIR)))
+SERVER_PEM = os.path.join(ROOT_DIR, 'test', 'keys', 'server.pem')
+SERVER_CERT = os.path.join(ROOT_DIR, 'test', 'keys', 'server.crt')
+SERVER_KEY = os.path.join(ROOT_DIR, 'test', 'keys', 'server.key')
+CLIENT_CERT_NO_IP = os.path.join(ROOT_DIR, 'test', 'keys', 'client.crt')
+CLIENT_KEY_NO_IP = os.path.join(ROOT_DIR, 'test', 'keys', 'client.key')
+CLIENT_CERT = os.path.join(ROOT_DIR, 'test', 'keys', 'client_v3.crt')
+CLIENT_KEY = os.path.join(ROOT_DIR, 'test', 'keys', 'client_v3.key')
+CLIENT_CA = os.path.join(ROOT_DIR, 'test', 'keys', 'CA.pem')
+
+TEST_CIPHERS = 'DES-CBC3-SHA:ECDHE-RSA-AES128-GCM-SHA256'
+
+
+class ServerAcceptor(threading.Thread):
+    def __init__(self, server, expect_failure=False):
+        super(ServerAcceptor, self).__init__()
+        self.daemon = True
+        self._server = server
+        self._listening = threading.Event()
+        self._port = None
+        self._port_bound = threading.Event()
+        self._client = None
+        self._client_accepted = threading.Event()
+        self._expect_failure = expect_failure
+        frame = inspect.stack(3)[2]
+        self.name = frame[3]
+        del frame
+
+    def run(self):
+        self._server.listen()
+        self._listening.set()
+
+        try:
+            address = self._server.handle.getsockname()
+            if len(address) > 1:
+                # AF_INET addresses are 2-tuples (host, port) and AF_INET6 are
+                # 4-tuples (host, port, ...), but in each case port is in the second slot.
+                self._port = address[1]
+        finally:
+            self._port_bound.set()
+
+        try:
+            self._client = self._server.accept()
+        except Exception:
+            logging.exception('error on server side (%s):' % self.name)
+            if not self._expect_failure:
+                raise
+        finally:
+            self._client_accepted.set()
+
+    def await_listening(self):
+        self._listening.wait()
+
+    @property
+    def port(self):
+        self._port_bound.wait()
+        return self._port
+
+    @property
+    def client(self):
+        self._client_accepted.wait()
+        return self._client
+
+    def close(self):
+        if self._client:
+            self._client.close()
+        self._server.close()
+
+
+# Python 2.6 compat
+class AssertRaises(object):
+    def __init__(self, expected):
+        self._expected = expected
+
+    def __enter__(self):
+        pass
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        if not exc_type or not issubclass(exc_type, self._expected):
+            raise Exception('fail')
+        return True
+
+
+class TSSLSocketTest(unittest.TestCase):
+    def _server_socket(self, **kwargs):
+        return TSSLServerSocket(port=0, **kwargs)
+
+    @contextmanager
+    def _connectable_client(self, server, expect_failure=False, path=None, **client_kwargs):
+        acc = ServerAcceptor(server, expect_failure)
+        try:
+            acc.start()
+            acc.await_listening()
+
+            host, port = ('localhost', acc.port) if path is None else (None, None)
+            client = TSSLSocket(host, port, unix_socket=path, **client_kwargs)
+            yield acc, client
+        finally:
+            acc.close()
+
+    def _assert_connection_failure(self, server, path=None, **client_args):
+        logging.disable(logging.CRITICAL)
+        try:
+            with self._connectable_client(server, True, path=path, **client_args) as (acc, client):
+                # We need to wait for a connection failure, but not too long.  20ms is a tunable
+                # compromise between test speed and stability
+                client.setTimeout(20)
+                with self._assert_raises(TTransportException):
+                    client.open()
+                self.assertTrue(acc.client is None)
+        finally:
+            logging.disable(logging.NOTSET)
+
+    def _assert_raises(self, exc):
+        if sys.hexversion >= 0x020700F0:
+            return self.assertRaises(exc)
+        else:
+            return AssertRaises(exc)
+
+    def _assert_connection_success(self, server, path=None, **client_args):
+        with self._connectable_client(server, path=path, **client_args) as (acc, client):
+            client.open()
+            try:
+                self.assertTrue(acc.client is not None)
+            finally:
+                client.close()
+
+    # deprecated feature
+    def test_deprecation(self):
+        with warnings.catch_warnings(record=True) as w:
+            warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__)
+            TSSLSocket('localhost', 0, validate=True, ca_certs=SERVER_CERT)
+            self.assertEqual(len(w), 1)
+
+        with warnings.catch_warnings(record=True) as w:
+            warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__)
+            # Deprecated signature
+            # def __init__(self, host='localhost', port=9090, validate=True, ca_certs=None, keyfile=None, certfile=None, unix_socket=None, ciphers=None):
+            TSSLSocket('localhost', 0, True, SERVER_CERT, CLIENT_KEY, CLIENT_CERT, None, TEST_CIPHERS)
+            self.assertEqual(len(w), 7)
+
+        with warnings.catch_warnings(record=True) as w:
+            warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__)
+            # Deprecated signature
+            # def __init__(self, host=None, port=9090, certfile='cert.pem', unix_socket=None, ciphers=None):
+            TSSLServerSocket(None, 0, SERVER_PEM, None, TEST_CIPHERS)
+            self.assertEqual(len(w), 3)
+
+    # deprecated feature
+    def test_set_cert_reqs_by_validate(self):
+        with warnings.catch_warnings(record=True) as w:
+            warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__)
+            c1 = TSSLSocket('localhost', 0, validate=True, ca_certs=SERVER_CERT)
+            self.assertEqual(c1.cert_reqs, ssl.CERT_REQUIRED)
+
+            c1 = TSSLSocket('localhost', 0, validate=False)
+            self.assertEqual(c1.cert_reqs, ssl.CERT_NONE)
+
+            self.assertEqual(len(w), 2)
+
+    # deprecated feature
+    def test_set_validate_by_cert_reqs(self):
+        with warnings.catch_warnings(record=True) as w:
+            warnings.filterwarnings('always', category=DeprecationWarning, module=self.__module__)
+            c1 = TSSLSocket('localhost', 0, cert_reqs=ssl.CERT_NONE)
+            self.assertFalse(c1.validate)
+
+            c2 = TSSLSocket('localhost', 0, cert_reqs=ssl.CERT_REQUIRED, ca_certs=SERVER_CERT)
+            self.assertTrue(c2.validate)
+
+            c3 = TSSLSocket('localhost', 0, cert_reqs=ssl.CERT_OPTIONAL, ca_certs=SERVER_CERT)
+            self.assertTrue(c3.validate)
+
+            self.assertEqual(len(w), 3)
+
+    def test_unix_domain_socket(self):
+        if platform.system() == 'Windows':
+            print('skipping test_unix_domain_socket')
+            return
+        fd, path = tempfile.mkstemp()
+        os.close(fd)
+        try:
+            server = self._server_socket(unix_socket=path, keyfile=SERVER_KEY, certfile=SERVER_CERT)
+            self._assert_connection_success(server, path=path, cert_reqs=ssl.CERT_NONE)
+        finally:
+            os.unlink(path)
+
+    def test_server_cert(self):
+        server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT)
+        self._assert_connection_success(server, cert_reqs=ssl.CERT_REQUIRED, ca_certs=SERVER_CERT)
+
+        server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT)
+        # server cert not in ca_certs
+        self._assert_connection_failure(server, cert_reqs=ssl.CERT_REQUIRED, ca_certs=CLIENT_CERT)
+
+        server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT)
+        self._assert_connection_success(server, cert_reqs=ssl.CERT_NONE)
+
+    def test_set_server_cert(self):
+        server = self._server_socket(keyfile=SERVER_KEY, certfile=CLIENT_CERT)
+        with self._assert_raises(Exception):
+            server.certfile = 'foo'
+        with self._assert_raises(Exception):
+            server.certfile = None
+        server.certfile = SERVER_CERT
+        self._assert_connection_success(server, cert_reqs=ssl.CERT_REQUIRED, ca_certs=SERVER_CERT)
+
+    def test_client_cert(self):
+        if not _match_has_ipaddress:
+            print('skipping test_client_cert')
+            return
+        server = self._server_socket(
+            cert_reqs=ssl.CERT_REQUIRED, keyfile=SERVER_KEY,
+            certfile=SERVER_CERT, ca_certs=CLIENT_CERT)
+        self._assert_connection_failure(server, cert_reqs=ssl.CERT_NONE, certfile=SERVER_CERT, keyfile=SERVER_KEY)
+
+        server = self._server_socket(
+            cert_reqs=ssl.CERT_REQUIRED, keyfile=SERVER_KEY,
+            certfile=SERVER_CERT, ca_certs=CLIENT_CA)
+        self._assert_connection_failure(server, cert_reqs=ssl.CERT_NONE, certfile=CLIENT_CERT_NO_IP, keyfile=CLIENT_KEY_NO_IP)
+
+        server = self._server_socket(
+            cert_reqs=ssl.CERT_REQUIRED, keyfile=SERVER_KEY,
+            certfile=SERVER_CERT, ca_certs=CLIENT_CA)
+        self._assert_connection_success(server, cert_reqs=ssl.CERT_NONE, certfile=CLIENT_CERT, keyfile=CLIENT_KEY)
+
+        server = self._server_socket(
+            cert_reqs=ssl.CERT_OPTIONAL, keyfile=SERVER_KEY,
+            certfile=SERVER_CERT, ca_certs=CLIENT_CA)
+        self._assert_connection_success(server, cert_reqs=ssl.CERT_NONE, certfile=CLIENT_CERT, keyfile=CLIENT_KEY)
+
+    def test_ciphers(self):
+        server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ciphers=TEST_CIPHERS)
+        self._assert_connection_success(server, ca_certs=SERVER_CERT, ciphers=TEST_CIPHERS)
+
+        if not TSSLSocket._has_ciphers:
+            # unittest.skip is not available for Python 2.6
+            print('skipping test_ciphers')
+            return
+        server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT)
+        self._assert_connection_failure(server, ca_certs=SERVER_CERT, ciphers='NULL')
+
+        server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ciphers=TEST_CIPHERS)
+        self._assert_connection_failure(server, ca_certs=SERVER_CERT, ciphers='NULL')
+
+    def test_ssl2_and_ssl3_disabled(self):
+        if not hasattr(ssl, 'PROTOCOL_SSLv3'):
+            print('PROTOCOL_SSLv3 is not available')
+        else:
+            server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT)
+            self._assert_connection_failure(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv3)
+
+            server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv3)
+            self._assert_connection_failure(server, ca_certs=SERVER_CERT)
+
+        if not hasattr(ssl, 'PROTOCOL_SSLv2'):
+            print('PROTOCOL_SSLv2 is not available')
+        else:
+            server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT)
+            self._assert_connection_failure(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv2)
+
+            server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv2)
+            self._assert_connection_failure(server, ca_certs=SERVER_CERT)
+
+    def test_newer_tls(self):
+        if not TSSLSocket._has_ssl_context:
+            # unittest.skip is not available for Python 2.6
+            print('skipping test_newer_tls')
+            return
+        if not hasattr(ssl, 'PROTOCOL_TLSv1_2'):
+            print('PROTOCOL_TLSv1_2 is not available')
+        else:
+            server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_2)
+            self._assert_connection_success(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_2)
+
+        if not hasattr(ssl, 'PROTOCOL_TLSv1_1'):
+            print('PROTOCOL_TLSv1_1 is not available')
+        else:
+            server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_1)
+            self._assert_connection_success(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_1)
+
+        if not hasattr(ssl, 'PROTOCOL_TLSv1_1') or not hasattr(ssl, 'PROTOCOL_TLSv1_2'):
+            print('PROTOCOL_TLSv1_1 and/or PROTOCOL_TLSv1_2 is not available')
+        else:
+            server = self._server_socket(keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_2)
+            self._assert_connection_failure(server, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_1)
+
+    def test_ssl_context(self):
+        if not TSSLSocket._has_ssl_context:
+            # unittest.skip is not available for Python 2.6
+            print('skipping test_ssl_context')
+            return
+        server_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
+        server_context.load_cert_chain(SERVER_CERT, SERVER_KEY)
+        server_context.load_verify_locations(CLIENT_CA)
+        server_context.verify_mode = ssl.CERT_REQUIRED
+        server = self._server_socket(ssl_context=server_context)
+
+        client_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
+        client_context.load_cert_chain(CLIENT_CERT, CLIENT_KEY)
+        client_context.load_verify_locations(SERVER_CERT)
+        client_context.verify_mode = ssl.CERT_REQUIRED
+
+        self._assert_connection_success(server, ssl_context=client_context)
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.WARN)
+    from thrift.transport.TSSLSocket import TSSLSocket, TSSLServerSocket, _match_has_ipaddress
+    from thrift.transport.TTransport import TTransportException
+
+    unittest.main()
diff --git a/lib/py/test/thrift_json.py b/lib/py/test/thrift_json.py
new file mode 100644
index 0000000..40e7a47
--- /dev/null
+++ b/lib/py/test/thrift_json.py
@@ -0,0 +1,51 @@
+#
+# 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 sys
+import unittest
+
+import _import_local_thrift  # noqa
+from thrift.protocol.TJSONProtocol import TJSONProtocol
+from thrift.transport import TTransport
+
+#
+# In order to run the test under Windows. We need to create symbolic link
+# name 'thrift' to '../src' folder by using:
+#
+# mklink /D thrift ..\src
+#
+
+
+class TestJSONString(unittest.TestCase):
+
+    def test_escaped_unicode_string(self):
+        unicode_json = b'"hello \\u0e01\\u0e02\\u0e03\\ud835\\udcab\\udb40\\udc70 unicode"'
+        unicode_text = u'hello \u0e01\u0e02\u0e03\U0001D4AB\U000E0070 unicode'
+
+        buf = TTransport.TMemoryBuffer(unicode_json)
+        transport = TTransport.TBufferedTransportFactory().getTransport(buf)
+        protocol = TJSONProtocol(transport)
+
+        if sys.version_info[0] == 2:
+            unicode_text = unicode_text.encode('utf8')
+        self.assertEqual(protocol.readString(), unicode_text)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/lib/rb/CHANGELOG b/lib/rb/CHANGELOG
deleted file mode 100644
index b5dce2a..0000000
--- a/lib/rb/CHANGELOG
+++ /dev/null
@@ -1 +0,0 @@
-v0.0.1. Initial release
diff --git a/lib/rb/Makefile.am b/lib/rb/Makefile.am
old mode 100644
new mode 100755
index cad71be..137edb4
--- a/lib/rb/Makefile.am
+++ b/lib/rb/Makefile.am
@@ -17,8 +17,29 @@
 # under the License.
 #
 
+DESTDIR ?= /
+
+if HAVE_BUNDLER
+
+all-local:
+	$(BUNDLER) install
+	$(BUNDLER) exec rake build_ext
+
+install-exec-hook:
+	$(BUNDLER) exec rake install
+
+clean-local:
+	$(BUNDLER) install
+	$(BUNDLER) exec rake clean
+
+check-local: all
+	$(BUNDLER) install
+	$(BUNDLER) exec rake
+
+endif
+
 EXTRA_DIST = \
-	CHANGELOG \
+	coding_standards.md \
 	Rakefile \
 	Gemfile \
 	thrift.gemspec \
@@ -26,25 +47,5 @@
 	ext \
 	benchmark \
 	script \
-	spec
-
-DESTDIR ?= /
-
-all-local:
-if HAVE_BUNDLER
-	$(BUNDLER) install
-	$(BUNDLER) exec rake
-endif
-
-install-exec-hook:
-	$(RAKE) install
-
-clean-local:
-	$(RAKE) clean
-
-check-local: all
-if HAVE_BUNDLER
-	$(BUNDLER) install
-	$(BUNDLER) exec rake
-endif
-
+	spec \
+	README.md
diff --git a/lib/rb/README b/lib/rb/README.md
similarity index 100%
rename from lib/rb/README
rename to lib/rb/README.md
diff --git a/lib/rb/Rakefile b/lib/rb/Rakefile
index 132c635..5e5e5ac 100644
--- a/lib/rb/Rakefile
+++ b/lib/rb/Rakefile
@@ -38,13 +38,26 @@
 end
 
 desc 'Compile the .thrift files for the specs'
-task :'gen-rb' => [:'gen-rb:spec', :'gen-rb:benchmark', :'gen-rb:debug_proto']
+task :'gen-rb' => [:'gen-rb:spec', :'gen-rb:namespaced_spec', :'gen-rb:flat_spec', :'gen-rb:benchmark', :'gen-rb:debug_proto']
 namespace :'gen-rb' do
   task :'spec' do
     dir = File.dirname(__FILE__) + '/spec'
     sh THRIFT, '--gen', 'rb', '-o', dir, "#{dir}/ThriftSpec.thrift"
   end
 
+  task :'namespaced_spec' do
+    dir = File.dirname(__FILE__) + '/spec'
+    sh THRIFT, '--gen', 'rb:namespaced', '--recurse', '-o', dir, "#{dir}/ThriftNamespacedSpec.thrift"
+    sh THRIFT, '--gen', 'rb:namespaced', '--recurse', '-o', dir, "#{dir}/BaseService.thrift"
+    sh THRIFT, '--gen', 'rb:namespaced', '--recurse', '-o', dir, "#{dir}/ExtendedService.thrift"
+  end
+
+  task :'flat_spec' do
+    dir = File.dirname(__FILE__) + '/spec'
+    mkdir_p("#{dir}/gen-rb/flat")
+    sh THRIFT, '--gen', 'rb', '--recurse', '-out', "#{dir}/gen-rb/flat", "#{dir}/ThriftNamespacedSpec.thrift"
+  end
+
   task :'benchmark' do
     dir = File.dirname(__FILE__) + '/benchmark'
     sh THRIFT, '--gen', 'rb', '-o', dir, "#{dir}/Benchmark.thrift"
@@ -58,6 +71,7 @@
 
 desc "Build the native library"
 task :build_ext => :'gen-rb' do
+   next if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
    Dir::chdir(File::dirname('ext/extconf.rb')) do
       unless sh "ruby #{File::basename('ext/extconf.rb')}"
         $stderr.puts "Failed to run extconf"
@@ -73,7 +87,7 @@
 desc 'Run the compiler tests (requires full thrift checkout)'
 task :test do
   # ensure this is a full thrift checkout and not a tarball of the ruby libs
-  cmd = 'head -1 ../../README 2>/dev/null | grep Thrift >/dev/null 2>/dev/null'
+  cmd = 'head -1 ../../README.md 2>/dev/null | grep Thrift >/dev/null 2>/dev/null'
   system(cmd) or fail "rake test requires a full thrift checkout"
   sh 'make', '-C', File.dirname(__FILE__) + "/../../test/rb", "check"
 end
@@ -93,7 +107,7 @@
 
 desc 'Install the thrift gem'
 task :install => [:gem] do
-  unless sh 'gem', 'install', 'thrift-*.gem'
+  unless sh 'gem', 'install', Dir.glob('thrift-*.gem').last
     $stderr.puts "Failed to install thrift gem"
     break
   end
diff --git a/lib/rb/coding_standards.md b/lib/rb/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/rb/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/rb/ext/binary_protocol_accelerated.c b/lib/rb/ext/binary_protocol_accelerated.c
index 8b27dbc..65cbe5f 100644
--- a/lib/rb/ext/binary_protocol_accelerated.c
+++ b/lib/rb/ext/binary_protocol_accelerated.c
@@ -283,27 +283,27 @@
   return Qnil;
 }
 
-VALUE rb_thift_binary_proto_read_struct_begin(VALUE self) {
+VALUE rb_thrift_binary_proto_read_struct_begin(VALUE self) {
   return Qnil;
 }
 
-VALUE rb_thift_binary_proto_read_struct_end(VALUE self) {
+VALUE rb_thrift_binary_proto_read_struct_end(VALUE self) {
   return Qnil;
 }
 
-VALUE rb_thift_binary_proto_read_field_end(VALUE self) {
+VALUE rb_thrift_binary_proto_read_field_end(VALUE self) {
   return Qnil;
 }
 
-VALUE rb_thift_binary_proto_read_map_end(VALUE self) {
+VALUE rb_thrift_binary_proto_read_map_end(VALUE self) {
   return Qnil;
 }
 
-VALUE rb_thift_binary_proto_read_list_end(VALUE self) {
+VALUE rb_thrift_binary_proto_read_list_end(VALUE self) {
   return Qnil;
 }
 
-VALUE rb_thift_binary_proto_read_set_end(VALUE self) {
+VALUE rb_thrift_binary_proto_read_set_end(VALUE self) {
   return Qnil;
 }
 
@@ -449,12 +449,12 @@
   rb_define_method(bpa_class, "read_binary",         rb_thrift_binary_proto_read_binary, 0);
   // unused methods
   rb_define_method(bpa_class, "read_message_end", rb_thrift_binary_proto_read_message_end, 0);
-  rb_define_method(bpa_class, "read_struct_begin", rb_thift_binary_proto_read_struct_begin, 0);
-  rb_define_method(bpa_class, "read_struct_end", rb_thift_binary_proto_read_struct_end, 0);
-  rb_define_method(bpa_class, "read_field_end", rb_thift_binary_proto_read_field_end, 0);
-  rb_define_method(bpa_class, "read_map_end", rb_thift_binary_proto_read_map_end, 0);
-  rb_define_method(bpa_class, "read_list_end", rb_thift_binary_proto_read_list_end, 0);
-  rb_define_method(bpa_class, "read_set_end", rb_thift_binary_proto_read_set_end, 0);
+  rb_define_method(bpa_class, "read_struct_begin", rb_thrift_binary_proto_read_struct_begin, 0);
+  rb_define_method(bpa_class, "read_struct_end", rb_thrift_binary_proto_read_struct_end, 0);
+  rb_define_method(bpa_class, "read_field_end", rb_thrift_binary_proto_read_field_end, 0);
+  rb_define_method(bpa_class, "read_map_end", rb_thrift_binary_proto_read_map_end, 0);
+  rb_define_method(bpa_class, "read_list_end", rb_thrift_binary_proto_read_list_end, 0);
+  rb_define_method(bpa_class, "read_set_end", rb_thrift_binary_proto_read_set_end, 0);
 
   rbuf_ivar_id = rb_intern("@rbuf");
 }
diff --git a/lib/rb/ext/compact_protocol.c b/lib/rb/ext/compact_protocol.c
index 1637e99..c0f46b9 100644
--- a/lib/rb/ext/compact_protocol.c
+++ b/lib/rb/ext/compact_protocol.c
@@ -40,6 +40,7 @@
 static int VERSION;
 static int VERSION_MASK;
 static int TYPE_MASK;
+static int TYPE_BITS;
 static int TYPE_SHIFT_AMOUNT;
 static int PROTOCOL_ID;
 
@@ -315,7 +316,7 @@
   buf = force_binary_encoding(buf);
   VALUE transport = GET_TRANSPORT(self);
   write_varint32(transport, RSTRING_LEN(buf));
-  WRITE(transport, RSTRING_PTR(buf), RSTRING_LEN(buf));
+  WRITE(transport, StringValuePtr(buf), RSTRING_LEN(buf));
   return Qnil;
 }
 
@@ -450,7 +451,7 @@
     rb_exc_raise(get_protocol_exception(INT2FIX(-1), rb_str_new2(buf)));
   }
   
-  int8_t type = (version_and_type >> TYPE_SHIFT_AMOUNT) & 0x03;
+  int8_t type = (version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS;
   int32_t seqid = read_varint64(self);
   VALUE messageName = rb_thrift_compact_proto_read_string(self);
   return rb_ary_new3(3, messageName, INT2FIX(type), INT2NUM(seqid));
@@ -570,6 +571,7 @@
   VERSION = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("VERSION")));
   VERSION_MASK = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("VERSION_MASK")));
   TYPE_MASK = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("TYPE_MASK")));
+  TYPE_BITS = rb_num2ll(rb_const_get(thrift_compact_protocol_class, rb_intern("TYPE_BITS")));
   TYPE_SHIFT_AMOUNT = FIX2INT(rb_const_get(thrift_compact_protocol_class, rb_intern("TYPE_SHIFT_AMOUNT")));
   PROTOCOL_ID = FIX2INT(rb_const_get(thrift_compact_protocol_class, rb_intern("PROTOCOL_ID")));
 
diff --git a/lib/rb/ext/constants.h b/lib/rb/ext/constants.h
index 76947e5..e7aec44 100644
--- a/lib/rb/ext/constants.h
+++ b/lib/rb/ext/constants.h
@@ -42,6 +42,7 @@
 extern ID write_i64_method_id;
 extern ID write_double_method_id;
 extern ID write_string_method_id;
+extern ID write_binary_method_id;
 extern ID write_map_begin_method_id;
 extern ID write_map_end_method_id;
 extern ID write_list_begin_method_id;
@@ -54,6 +55,7 @@
 extern ID read_i32_method_id;
 extern ID read_i64_method_id;
 extern ID read_string_method_id;
+extern ID read_binary_method_id;
 extern ID read_double_method_id;
 extern ID read_map_begin_method_id;
 extern ID read_map_end_method_id;
@@ -87,6 +89,7 @@
 extern VALUE value_sym;
 extern VALUE element_sym;
 extern VALUE class_sym;
+extern VALUE binary_sym;
 
 extern VALUE rb_cSet;
 extern VALUE thrift_module;
diff --git a/lib/rb/ext/extconf.rb b/lib/rb/ext/extconf.rb
index 96f6b43..b35f60b 100644
--- a/lib/rb/ext/extconf.rb
+++ b/lib/rb/ext/extconf.rb
@@ -21,8 +21,10 @@
   File.open('Makefile', 'w'){|f| f.puts "all:\n\ninstall:\n" }
 else
   require 'mkmf'
+  require 'rbconfig'
 
-  $ARCH_FLAGS = Config::CONFIG['CFLAGS'].scan( /(-arch )(\S+)/ ).map{|x,y| x + y + ' ' }.join('')
+  $ARCH_FLAGS = RbConfig::CONFIG['CFLAGS'].scan( /(-arch )(\S+)/ ).map{|x,y| x + y + ' ' }.join('')
+
 
   $CFLAGS = "-fsigned-char -g -O2 -Wall -Werror " + $ARCH_FLAGS
 
diff --git a/lib/rb/ext/memory_buffer.c b/lib/rb/ext/memory_buffer.c
index e7253dc..8b52c4a 100644
--- a/lib/rb/ext/memory_buffer.c
+++ b/lib/rb/ext/memory_buffer.c
@@ -39,7 +39,7 @@
 VALUE rb_thrift_memory_buffer_write(VALUE self, VALUE str) {
   VALUE buf = GET_BUF(self);
   str = force_binary_encoding(str);
-  rb_str_buf_cat(buf, RSTRING_PTR(str), RSTRING_LEN(str));
+  rb_str_buf_cat(buf, StringValuePtr(str), RSTRING_LEN(str));
   return Qnil;
 }
 
diff --git a/lib/rb/ext/strlcpy.h b/lib/rb/ext/strlcpy.h
index c6f508f..f6fe0fe 100644
--- a/lib/rb/ext/strlcpy.h
+++ b/lib/rb/ext/strlcpy.h
@@ -17,14 +17,18 @@
  * under the License.
  */
 
-
 #include <sys/types.h>
 #include <string.h>
 
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
 #ifndef HAVE_STRLCPY
-size_t
-strlcpy (char *dst, const char *src, size_t dst_sz);
+size_t strlcpy (char *dst, const char *src, size_t dst_sz);
 #else
+#if !__has_builtin(strlcpy)
 extern size_t strlcpy(char *, const char *, size_t);
 #endif
+#endif
 
diff --git a/lib/rb/ext/struct.c b/lib/rb/ext/struct.c
index 8fbadbe..e3aa855 100644
--- a/lib/rb/ext/struct.c
+++ b/lib/rb/ext/struct.c
@@ -75,6 +75,11 @@
   return Qnil;
 }
 
+VALUE default_write_binary(VALUE protocol, VALUE value) {
+  rb_funcall(protocol, write_binary_method_id, 1, value);
+  return Qnil;
+}
+
 VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) {
   rb_funcall(protocol, write_list_begin_method_id, 2, etype, length);
   return Qnil;
@@ -190,6 +195,10 @@
   return rb_funcall(protocol, read_string_method_id, 0);
 }
 
+VALUE default_read_binary(VALUE protocol) {
+  return rb_funcall(protocol, read_binary_method_id, 0);
+}
+
 VALUE default_read_struct_begin(VALUE protocol) {
   return rb_funcall(protocol, read_struct_begin_method_id, 0);
 }
@@ -281,7 +290,7 @@
 
     if (TYPE(value) == T_ARRAY) {
       items = value;
-    } else {        
+    } else {
       if (rb_cSet == CLASS_OF(value)) {
         items = rb_funcall(value, entries_method_id, 0);
       } else {
@@ -327,7 +336,12 @@
   } else if (ttype == TTYPE_DOUBLE) {
     default_write_double(protocol, value);
   } else if (ttype == TTYPE_STRING) {
-    default_write_string(protocol, value);
+    VALUE is_binary = rb_hash_aref(field_info, binary_sym);
+    if (is_binary != Qtrue) {
+      default_write_string(protocol, value);
+    } else {
+      default_write_binary(protocol, value);
+    }
   } else if (IS_CONTAINER(ttype)) {
     write_container(ttype, field_info, value, protocol);
   } else if (ttype == TTYPE_STRUCT) {
@@ -430,7 +444,12 @@
   } else if (ttype == TTYPE_I64) {
     result = default_read_i64(protocol);
   } else if (ttype == TTYPE_STRING) {
-    result = default_read_string(protocol);
+    VALUE is_binary = rb_hash_aref(field_info, binary_sym);
+    if (is_binary != Qtrue) {
+      result = default_read_string(protocol);
+    } else {
+      result = default_read_binary(protocol);
+    }
   } else if (ttype == TTYPE_DOUBLE) {
     result = default_read_double(protocol);
   } else if (ttype == TTYPE_STRUCT) {
@@ -607,7 +626,7 @@
     if (field_type == specified_type) {
       // read the value
       VALUE name = rb_hash_aref(field_info, name_sym);
-      rb_iv_set(self, "@setfield", ID2SYM(rb_intern(RSTRING_PTR(name))));
+      rb_iv_set(self, "@setfield", rb_str_intern(name));
       rb_iv_set(self, "@value", read_anything(protocol, field_type, field_info));
     } else {
       rb_funcall(protocol, skip_method_id, 1, field_type_value);
@@ -651,6 +670,10 @@
 
   VALUE field_info = rb_hash_aref(struct_fields, field_id);
 
+  if(NIL_P(field_info)) {
+    rb_raise(rb_eRuntimeError, "set_field is not valid for this union!");
+  }
+
   VALUE ttype_value = rb_hash_aref(field_info, type_sym);
   int ttype = FIX2INT(ttype_value);
 
diff --git a/lib/rb/ext/thrift_native.c b/lib/rb/ext/thrift_native.c
index 614f2dd..3430b7c 100644
--- a/lib/rb/ext/thrift_native.c
+++ b/lib/rb/ext/thrift_native.c
@@ -57,6 +57,7 @@
 ID write_i64_method_id;
 ID write_double_method_id;
 ID write_string_method_id;
+ID write_binary_method_id;
 ID write_map_begin_method_id;
 ID write_map_end_method_id;
 ID write_list_begin_method_id;
@@ -69,6 +70,7 @@
 ID read_i32_method_id;
 ID read_i64_method_id;
 ID read_string_method_id;
+ID read_binary_method_id;
 ID read_double_method_id;
 ID read_map_begin_method_id;
 ID read_map_end_method_id;
@@ -104,6 +106,7 @@
 VALUE value_sym;
 VALUE element_sym;
 VALUE class_sym;
+VALUE binary_sym;
 VALUE protocol_exception_class;
 
 void Init_thrift_native() {
@@ -140,6 +143,7 @@
   write_i64_method_id = rb_intern("write_i64");
   write_double_method_id = rb_intern("write_double");
   write_string_method_id = rb_intern("write_string");
+  write_binary_method_id = rb_intern("write_binary");
   write_map_begin_method_id = rb_intern("write_map_begin");
   write_map_end_method_id = rb_intern("write_map_end");
   write_list_begin_method_id = rb_intern("write_list_begin");
@@ -152,6 +156,7 @@
   read_i32_method_id = rb_intern("read_i32");
   read_i64_method_id = rb_intern("read_i64");
   read_string_method_id = rb_intern("read_string");
+  read_binary_method_id = rb_intern("read_binary");
   read_double_method_id = rb_intern("read_double");
   read_map_begin_method_id = rb_intern("read_map_begin");
   read_map_end_method_id = rb_intern("read_map_end");  
@@ -187,6 +192,7 @@
   value_sym = ID2SYM(rb_intern("value"));
   element_sym = ID2SYM(rb_intern("element"));
   class_sym = ID2SYM(rb_intern("class"));
+  binary_sym = ID2SYM(rb_intern("binary"));
 
   Init_struct();
   Init_binary_protocol_accelerated();
diff --git a/lib/rb/lib/thrift.rb b/lib/rb/lib/thrift.rb
index 2443ebd..0f58122 100644
--- a/lib/rb/lib/thrift.rb
+++ b/lib/rb/lib/thrift.rb
@@ -1,4 +1,4 @@
-# 
+#
 # 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
@@ -6,16 +6,16 @@
 # 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.
-# 
+#
 # Contains some contributions under the Thrift Software License.
 # Please see doc/old-thrift-license.txt in the Thrift distribution for
 # details.
@@ -27,6 +27,7 @@
 require 'thrift/exceptions'
 require 'thrift/types'
 require 'thrift/processor'
+require 'thrift/multiplexed_processor'
 require 'thrift/client'
 require 'thrift/struct'
 require 'thrift/union'
@@ -42,12 +43,15 @@
 require 'thrift/protocol/binary_protocol_accelerated'
 require 'thrift/protocol/compact_protocol'
 require 'thrift/protocol/json_protocol'
+require 'thrift/protocol/multiplexed_protocol'
 
 # transport
 require 'thrift/transport/base_transport'
 require 'thrift/transport/base_server_transport'
 require 'thrift/transport/socket'
+require 'thrift/transport/ssl_socket'
 require 'thrift/transport/server_socket'
+require 'thrift/transport/ssl_server_socket'
 require 'thrift/transport/unix_socket'
 require 'thrift/transport/unix_server_socket'
 require 'thrift/transport/buffered_transport'
@@ -62,6 +66,5 @@
 require 'thrift/server/simple_server'
 require 'thrift/server/threaded_server'
 require 'thrift/server/thread_pool_server'
-require 'thrift/server/thin_http_server'
 
 require 'thrift/thrift_native'
diff --git a/lib/rb/lib/thrift/client.rb b/lib/rb/lib/thrift/client.rb
index 5b30f01..64ef059 100644
--- a/lib/rb/lib/thrift/client.rb
+++ b/lib/rb/lib/thrift/client.rb
@@ -1,4 +1,4 @@
-# 
+#
 # 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
@@ -6,16 +6,16 @@
 # 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.
-# 
+#
 
 module Thrift
   module Client
@@ -27,6 +27,15 @@
 
     def send_message(name, args_class, args = {})
       @oprot.write_message_begin(name, MessageTypes::CALL, @seqid)
+      send_message_args(args_class, args)
+    end
+
+    def send_oneway_message(name, args_class, args = {})
+      @oprot.write_message_begin(name, MessageTypes::ONEWAY, @seqid)
+      send_message_args(args_class, args)
+    end
+
+    def send_message_args(args_class, args)
       data = args_class.new
       args.each do |k, v|
         data.send("#{k.to_s}=", v)
diff --git a/lib/rb/lib/thrift/multiplexed_processor.rb b/lib/rb/lib/thrift/multiplexed_processor.rb
new file mode 100644
index 0000000..c734c04
--- /dev/null
+++ b/lib/rb/lib/thrift/multiplexed_processor.rb
@@ -0,0 +1,76 @@
+# 
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+require 'thrift/protocol/protocol_decorator'
+require 'thrift/protocol/base_protocol'
+
+module Thrift
+  class MultiplexedProcessor
+    def initialize
+      @actual_processors = {}
+    end
+ 
+    def register_processor(service_name, processor)
+      @actual_processors[service_name] = processor
+    end
+ 
+    def process(iprot, oprot)
+      name, type, seqid = iprot.read_message_begin
+      check_type(type)
+      check_separator(name)
+      service_name, method = name.split(':')
+      processor(service_name).process(StoredMessageProtocol.new(iprot, [method, type, seqid]), oprot)
+    end
+
+    protected
+
+    def processor(service_name)
+      if @actual_processors.has_key?(service_name)
+        @actual_processors[service_name]
+      else
+        raise Thrift::Exception.new("Service name not found: #{service_name}. Did you forget to call #{self.class.name}#register_processor?")
+      end
+    end
+
+    def check_type(type)
+      unless [MessageTypes::CALL, MessageTypes::ONEWAY].include?(type)
+        raise Thrift::Exception.new('This should not have happened!?')
+      end
+    end
+
+    def check_separator(name)
+      if name.count(':') < 1
+        raise Thrift::Exception.new("Service name not found in message name: #{name}. Did you forget to use a Thrift::Protocol::MultiplexedProtocol in your client?")
+      end
+    end
+  end
+
+  class StoredMessageProtocol < BaseProtocol
+
+    include ProtocolDecorator
+    
+    def initialize(protocol, message_begin)
+      super(protocol)
+      @message_begin = message_begin
+    end
+
+    def read_message_begin
+      @message_begin
+    end
+  end
+end
diff --git a/lib/rb/lib/thrift/processor.rb b/lib/rb/lib/thrift/processor.rb
index 5d9e0a1..ce21e12 100644
--- a/lib/rb/lib/thrift/processor.rb
+++ b/lib/rb/lib/thrift/processor.rb
@@ -17,25 +17,36 @@
 # under the License.
 # 
 
+require 'logger'
+
 module Thrift
   module Processor
-    def initialize(handler)
+    def initialize(handler, logger=nil)
       @handler = handler
+      if logger.nil?
+        @logger = Logger.new(STDERR)
+        @logger.level = Logger::WARN
+      else
+        @logger = logger
+      end
     end
 
     def process(iprot, oprot)
       name, type, seqid  = iprot.read_message_begin
       if respond_to?("process_#{name}")
-        send("process_#{name}", seqid, iprot, oprot)
+        begin
+          send("process_#{name}", seqid, iprot, oprot)
+        rescue => e
+          x = ApplicationException.new(ApplicationException::INTERNAL_ERROR, 'Internal error')
+          @logger.debug "Internal error : #{e.message}\n#{e.backtrace.join("\n")}"
+          write_error(x, oprot, name, seqid)
+        end
         true
       else
         iprot.skip(Types::STRUCT)
         iprot.read_message_end
         x = ApplicationException.new(ApplicationException::UNKNOWN_METHOD, 'Unknown function '+name)
-        oprot.write_message_begin(name, MessageTypes::EXCEPTION, seqid)
-        x.write(oprot)
-        oprot.write_message_end
-        oprot.trans.flush
+        write_error(x, oprot, name, seqid)
         false
       end
     end
@@ -53,5 +64,12 @@
       oprot.write_message_end
       oprot.trans.flush
     end
+
+    def write_error(err, oprot, name, seqid)
+      oprot.write_message_begin(name, MessageTypes::EXCEPTION, seqid)
+      err.write(oprot)
+      oprot.write_message_end
+      oprot.trans.flush
+    end
   end
 end
diff --git a/lib/rb/lib/thrift/protocol/base_protocol.rb b/lib/rb/lib/thrift/protocol/base_protocol.rb
index 2869cc8..5c693e9 100644
--- a/lib/rb/lib/thrift/protocol/base_protocol.rb
+++ b/lib/rb/lib/thrift/protocol/base_protocol.rb
@@ -28,6 +28,8 @@
     NEGATIVE_SIZE = 2
     SIZE_LIMIT = 3
     BAD_VERSION = 4
+    NOT_IMPLEMENTED = 5
+    DEPTH_LIMIT = 6
 
     attr_reader :type
 
@@ -367,11 +369,19 @@
         read_list_end
       end
     end
+    
+    def to_s
+      "#{trans.to_s}"
+    end
   end
 
   class BaseProtocolFactory
     def get_protocol(trans)
       raise NotImplementedError
     end
+    
+    def to_s
+      "base"
+    end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/lib/thrift/protocol/binary_protocol.rb b/lib/rb/lib/thrift/protocol/binary_protocol.rb
index e70b1e3..d8279db 100644
--- a/lib/rb/lib/thrift/protocol/binary_protocol.rb
+++ b/lib/rb/lib/thrift/protocol/binary_protocol.rb
@@ -226,12 +226,19 @@
       size = read_i32
       trans.read_all(size)
     end
-
+    
+    def to_s
+      "binary(#{super.to_s})"
+    end
   end
 
   class BinaryProtocolFactory < BaseProtocolFactory
     def get_protocol(trans)
       return Thrift::BinaryProtocol.new(trans)
     end
+    
+    def to_s
+      "binary"
+    end
   end
 end
diff --git a/lib/rb/lib/thrift/protocol/binary_protocol_accelerated.rb b/lib/rb/lib/thrift/protocol/binary_protocol_accelerated.rb
index 70ea652..09b0264 100644
--- a/lib/rb/lib/thrift/protocol/binary_protocol_accelerated.rb
+++ b/lib/rb/lib/thrift/protocol/binary_protocol_accelerated.rb
@@ -35,5 +35,13 @@
         BinaryProtocol.new(trans)
       end
     end
+
+    def to_s
+      if (defined? BinaryProtocolAccelerated)
+        "binary-accel"
+      else
+        "binary"
+      end
+    end
   end
 end
diff --git a/lib/rb/lib/thrift/protocol/compact_protocol.rb b/lib/rb/lib/thrift/protocol/compact_protocol.rb
index 07a6792..1f9bd30 100644
--- a/lib/rb/lib/thrift/protocol/compact_protocol.rb
+++ b/lib/rb/lib/thrift/protocol/compact_protocol.rb
@@ -24,6 +24,7 @@
     VERSION = 1
     VERSION_MASK = 0x1f
     TYPE_MASK = 0xE0
+    TYPE_BITS = 0x07
     TYPE_SHIFT_AMOUNT = 5
 
     TSTOP = ["", Types::STOP, 0]
@@ -231,7 +232,7 @@
         raise ProtocolException.new("Expected version #{VERSION} but got #{version}");
       end
       
-      type = (version_and_type >> TYPE_SHIFT_AMOUNT) & 0x03
+      type = (version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS
       seqid = read_varint32()
       messageName = read_string()
       [messageName, type, seqid]
@@ -344,6 +345,10 @@
       size = read_varint32()
       trans.read_all(size)
     end
+    
+    def to_s
+      "compact(#{super.to_s})"
+    end
 
     private
     
@@ -430,5 +435,9 @@
     def get_protocol(trans)
       CompactProtocol.new(trans)
     end
+    
+    def to_s
+      "compact"
+    end
   end
 end
diff --git a/lib/rb/lib/thrift/protocol/json_protocol.rb b/lib/rb/lib/thrift/protocol/json_protocol.rb
index 2e85089..91e74e4 100644
--- a/lib/rb/lib/thrift/protocol/json_protocol.rb
+++ b/lib/rb/lib/thrift/protocol/json_protocol.rb
@@ -18,6 +18,7 @@
 # under the License.
 # 
 
+require 'base64'
 
 module Thrift
   class LookaheadReader
@@ -310,7 +311,7 @@
     def write_json_base64(str)
       @context.write(trans)
       trans.write(@@kJSONStringDelimiter)
-      write_json_string([str].pack("m"))
+      trans.write(Base64.strict_encode64(str))
       trans.write(@@kJSONStringDelimiter)
     end
 
@@ -332,7 +333,7 @@
     # "NaN" or "Infinity" or "-Infinity".
     def write_json_double(num)
       @context.write(trans)
-      # Normalize output of boost::lexical_cast for NaNs and Infinities
+      # Normalize output of thrift::to_string for NaNs and Infinities
       special = false;
       if (num.nan?)
         special = true;
@@ -507,13 +508,13 @@
     def read_json_string(skipContext = false)
       # This string's characters must match up with the elements in escape_char_vals.
       # I don't have '/' on this list even though it appears on www.json.org --
-      # it is not in the RFC
-      escape_chars = "\"\\bfnrt"
+      # it is not in the RFC -> it is. See RFC 4627
+      escape_chars = "\"\\/bfnrt"
 
       # The elements of this array must match up with the sequence of characters in
       # escape_chars
       escape_char_vals = [
-        '"', '\\', '\b', '\f', '\n', '\r', '\t',
+        "\"", "\\", "\/", "\b", "\f", "\n", "\r", "\t",
       ]
 
       if !skipContext
@@ -546,7 +547,15 @@
 
     # Reads a block of base64 characters, decoding it, and returns via str
     def read_json_base64
-      read_json_string.unpack("m")[0]
+      str = read_json_string
+      m = str.length % 4
+      if m != 0
+        # Add missing padding
+        (4 - m).times do
+          str += '='
+        end
+      end
+      Base64.strict_decode64(str)
     end
 
     # Reads a sequence of characters, stopping at the first one that is not
@@ -759,11 +768,19 @@
     def read_binary
       read_json_base64
     end
+
+    def to_s
+      "json(#{super.to_s})"
+    end
   end
 
   class JsonProtocolFactory < BaseProtocolFactory
     def get_protocol(trans)
       return Thrift::JsonProtocol.new(trans)
     end
+
+    def to_s
+      "json"
+    end
   end
 end
diff --git a/lib/rb/lib/thrift/protocol/multiplexed_protocol.rb b/lib/rb/lib/thrift/protocol/multiplexed_protocol.rb
new file mode 100644
index 0000000..b4428a7
--- /dev/null
+++ b/lib/rb/lib/thrift/protocol/multiplexed_protocol.rb
@@ -0,0 +1,44 @@
+# 
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+require 'thrift/protocol/protocol_decorator'
+
+module Thrift
+  class MultiplexedProtocol < BaseProtocol
+
+    include ProtocolDecorator
+
+    def initialize(protocol, service_name)
+      super(protocol)
+      @service_name = service_name
+    end
+
+    def write_message_begin(name, type, seqid)
+      case type
+      when MessageTypes::CALL, MessageTypes::ONEWAY
+        @protocol.write_message_begin("#{@service_name}:#{name}", type, seqid)
+      else
+        @protocol.write_message_begin(name, type, seqid)
+      end 
+    end
+    
+    def to_s
+      "multiplexed(#{@service_name=@protocol.to_s})"
+    end
+  end
+end
diff --git a/lib/rb/lib/thrift/protocol/protocol_decorator.rb b/lib/rb/lib/thrift/protocol/protocol_decorator.rb
new file mode 100644
index 0000000..b1e3c15
--- /dev/null
+++ b/lib/rb/lib/thrift/protocol/protocol_decorator.rb
@@ -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.
+
+module Thrift
+  module ProtocolDecorator
+
+    def initialize(protocol)
+      @protocol = protocol
+    end
+
+    def trans
+      @protocol.trans
+    end
+
+    def write_message_begin(name, type, seqid)
+      @protocol.write_message_begin
+    end
+
+    def write_message_end
+      @protocol.write_message_end
+    end
+
+    def write_struct_begin(name)
+      @protocol.write_struct_begin(name)
+    end
+
+    def write_struct_end
+      @protocol.write_struct_end
+    end
+
+    def write_field_begin(name, type, id)
+      @protocol.write_field_begin(name, type, id)
+    end
+
+    def write_field_end
+      @protocol.write_field_end
+    end
+
+    def write_field_stop
+      @protocol.write_field_stop
+    end
+
+    def write_map_begin(ktype, vtype, size)
+      @protocol.write_map_begin(ktype, vtype, size)
+    end
+
+    def write_map_end
+      @protocol.write_map_end
+    end
+
+    def write_list_begin(etype, size)
+      @protocol.write_list_begin(etype, size)
+    end
+
+    def write_list_end
+      @protocol.write_list_end
+    end
+
+    def write_set_begin(etype, size)
+      @protocol.write_set_begin(etype, size)
+    end
+
+    def write_set_end
+      @protocol.write_set_end
+    end
+
+    def write_bool(bool)
+      @protocol.write_bool(bool)
+    end
+
+    def write_byte(byte)
+      @protocol.write_byte(byte)
+    end
+
+    def write_i16(i16)
+      @protocol.write_i16(i16)
+    end
+
+    def write_i32(i32)
+      @protocol.write_i32(i32)
+    end
+
+    def write_i64(i64)
+      @protocol.write_i64(i64)
+    end
+
+    def write_double(dub)
+      @protocol.write_double(dub)
+    end
+
+    def write_string(str)
+      @protocol.write_string(str)
+    end
+
+    def write_binary(buf)
+      @protocol.write_binary(buf)
+    end
+
+    def read_message_begin
+      @protocol.read_message_begin
+    end
+
+    def read_message_end
+      @protocol.read_message_end
+    end
+
+    def read_struct_begin
+      @protocol.read_struct_begin
+    end
+
+    def read_struct_end
+      @protocol.read_struct_end
+    end
+
+    def read_field_begin
+      @protocol.read_field_begin
+    end
+
+    def read_field_end
+      @protocol.read_field_end
+    end
+
+    def read_map_begin
+      @protocol.read_map_begin
+    end
+
+    def read_map_end
+      @protocol.read_map_end
+    end
+
+    def read_list_begin
+      @protocol.read_list_begin
+    end
+
+    def read_list_end
+      @protocol.read_list_end
+    end
+
+    def read_set_begin
+      @protocol.read_set_begin
+    end
+
+    def read_set_end
+      @protocol.read_set_end
+    end
+
+    def read_bool
+      @protocol.read_bool
+    end
+
+    def read_byte
+      @protocol.read_byte
+    end
+
+    def read_i16
+      @protocol.read_i16
+    end
+
+    def read_i32
+      @protocol.read_i32
+    end
+
+    def read_i64
+      @protocol.read_i64
+    end
+
+    def read_double
+      @protocol.read_double
+    end
+
+    def read_string
+      @protocol.read_string
+    end
+
+    def read_binary
+      @protocol.read_binary
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/rb/lib/thrift/server/base_server.rb b/lib/rb/lib/thrift/server/base_server.rb
index 1ee1213..aa4d09c 100644
--- a/lib/rb/lib/thrift/server/base_server.rb
+++ b/lib/rb/lib/thrift/server/base_server.rb
@@ -26,6 +26,12 @@
       @protocol_factory = protocol_factory ? protocol_factory : Thrift::BinaryProtocolFactory.new
     end
 
-    def serve; nil; end
+    def serve
+      raise NotImplementedError
+    end
+
+    def to_s
+      "server(#{@protocol_factory.to_s}(#{@transport_factory.to_s}(#{@server_transport.to_s})))"
+    end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/lib/thrift/server/simple_server.rb b/lib/rb/lib/thrift/server/simple_server.rb
index 21e8659..905fe9b 100644
--- a/lib/rb/lib/thrift/server/simple_server.rb
+++ b/lib/rb/lib/thrift/server/simple_server.rb
@@ -39,5 +39,9 @@
         @server_transport.close
       end
     end
+    
+    def to_s
+      "simple(#{super.to_s})"
+    end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/lib/thrift/server/thread_pool_server.rb b/lib/rb/lib/thrift/server/thread_pool_server.rb
index 8cec805..bb754ad 100644
--- a/lib/rb/lib/thrift/server/thread_pool_server.rb
+++ b/lib/rb/lib/thrift/server/thread_pool_server.rb
@@ -71,5 +71,9 @@
         @server_transport.close
       end
     end
+    
+    def to_s
+      "threadpool(#{super.to_s})"
+    end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/lib/thrift/server/threaded_server.rb b/lib/rb/lib/thrift/server/threaded_server.rb
index a2c917c..88ee183 100644
--- a/lib/rb/lib/thrift/server/threaded_server.rb
+++ b/lib/rb/lib/thrift/server/threaded_server.rb
@@ -43,5 +43,9 @@
         @server_transport.close
       end
     end
+    
+    def to_s
+      "threaded(#{super.to_s})"
+    end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/lib/thrift/transport/base_server_transport.rb b/lib/rb/lib/thrift/transport/base_server_transport.rb
index 68c5af0..0105463 100644
--- a/lib/rb/lib/thrift/transport/base_server_transport.rb
+++ b/lib/rb/lib/thrift/transport/base_server_transport.rb
@@ -34,4 +34,4 @@
       raise NotImplementedError
     end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/lib/thrift/transport/base_transport.rb b/lib/rb/lib/thrift/transport/base_transport.rb
index 8790326..97e5935 100644
--- a/lib/rb/lib/thrift/transport/base_transport.rb
+++ b/lib/rb/lib/thrift/transport/base_transport.rb
@@ -99,11 +99,19 @@
     alias_method :<<, :write
 
     def flush; end
+
+    def to_s
+      "base"
+    end
   end
   
   class BaseTransportFactory
     def get_transport(trans)
       return trans
     end
+    
+    def to_s
+      "base"
+    end
   end
 end
diff --git a/lib/rb/lib/thrift/transport/buffered_transport.rb b/lib/rb/lib/thrift/transport/buffered_transport.rb
index 781d3c6..4fe9c41 100644
--- a/lib/rb/lib/thrift/transport/buffered_transport.rb
+++ b/lib/rb/lib/thrift/transport/buffered_transport.rb
@@ -104,11 +104,19 @@
       
       @transport.flush
     end
+
+    def to_s
+      "buffered(#{@transport.to_s})"
+    end
   end
 
   class BufferedTransportFactory < BaseTransportFactory
     def get_transport(transport)
       return BufferedTransport.new(transport)
     end
+    
+    def to_s
+      "buffered"
+    end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/lib/thrift/transport/framed_transport.rb b/lib/rb/lib/thrift/transport/framed_transport.rb
index d806ce0..9531778 100644
--- a/lib/rb/lib/thrift/transport/framed_transport.rb
+++ b/lib/rb/lib/thrift/transport/framed_transport.rb
@@ -99,6 +99,10 @@
       @wbuf = Bytes.empty_byte_buffer
     end
 
+    def to_s
+      "framed(#{@transport.to_s})"
+    end
+
     private
 
     def read_frame
@@ -113,5 +117,9 @@
     def get_transport(transport)
       return FramedTransport.new(transport)
     end
+    
+    def to_s
+      "framed"
+    end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/lib/thrift/transport/http_client_transport.rb b/lib/rb/lib/thrift/transport/http_client_transport.rb
index 77ffe35..5c1dd5c 100644
--- a/lib/rb/lib/thrift/transport/http_client_transport.rb
+++ b/lib/rb/lib/thrift/transport/http_client_transport.rb
@@ -50,7 +50,12 @@
       data = resp.body
       data = Bytes.force_binary_encoding(data)
       @inbuf = StringIO.new data
+    ensure
       @outbuf = Bytes.empty_byte_buffer
     end
+    
+    def to_s
+      "@{self.url}"
+    end
   end
 end
diff --git a/lib/rb/lib/thrift/transport/io_stream_transport.rb b/lib/rb/lib/thrift/transport/io_stream_transport.rb
index e3c8379..ccec68f 100644
--- a/lib/rb/lib/thrift/transport/io_stream_transport.rb
+++ b/lib/rb/lib/thrift/transport/io_stream_transport.rb
@@ -35,5 +35,8 @@
     def write(buf); @output.write(Bytes.force_binary_encoding(buf)) end
     def close; @input.close; @output.close end
     def to_io; @input end # we're assuming this is used in a IO.select for reading
+    def to_s
+      "iostream(input=#{@input.to_s},output=#{@output.to_s})"
+    end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/lib/thrift/transport/memory_buffer_transport.rb b/lib/rb/lib/thrift/transport/memory_buffer_transport.rb
index ad5ad85..469ea73 100644
--- a/lib/rb/lib/thrift/transport/memory_buffer_transport.rb
+++ b/lib/rb/lib/thrift/transport/memory_buffer_transport.rb
@@ -121,5 +121,9 @@
       end
       out.join(" ")
     end
+    
+    def to_s
+      "memory"
+    end
   end
 end
diff --git a/lib/rb/lib/thrift/transport/server_socket.rb b/lib/rb/lib/thrift/transport/server_socket.rb
index 7feb9ab..5000232 100644
--- a/lib/rb/lib/thrift/transport/server_socket.rb
+++ b/lib/rb/lib/thrift/transport/server_socket.rb
@@ -59,5 +59,10 @@
     end
 
     alias to_io handle
+
+    def to_s
+      "socket(#{@host}:#{@port})"
+    end
+
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/lib/thrift/transport/socket.rb b/lib/rb/lib/thrift/transport/socket.rb
index 2b7ca09..f5e6f3b 100644
--- a/lib/rb/lib/thrift/transport/socket.rb
+++ b/lib/rb/lib/thrift/transport/socket.rb
@@ -33,26 +33,28 @@
     attr_accessor :handle, :timeout
 
     def open
-      begin
-        addrinfo = ::Socket::getaddrinfo(@host, @port, nil, ::Socket::SOCK_STREAM).first
-        @handle = ::Socket.new(addrinfo[4], ::Socket::SOCK_STREAM, 0)
-        @handle.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
-        sockaddr = ::Socket.sockaddr_in(addrinfo[1], addrinfo[3])
+      for addrinfo in ::Socket::getaddrinfo(@host, @port, nil, ::Socket::SOCK_STREAM) do
         begin
-          @handle.connect_nonblock(sockaddr)
-        rescue Errno::EINPROGRESS
-          unless IO.select(nil, [ @handle ], nil, @timeout)
-            raise TransportException.new(TransportException::NOT_OPEN, "Connection timeout to #{@desc}")
-          end
+          socket = ::Socket.new(addrinfo[4], ::Socket::SOCK_STREAM, 0)
+          socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
+          sockaddr = ::Socket.sockaddr_in(addrinfo[1], addrinfo[3])
           begin
-            @handle.connect_nonblock(sockaddr)
-          rescue Errno::EISCONN
+            socket.connect_nonblock(sockaddr)
+          rescue Errno::EINPROGRESS
+            unless IO.select(nil, [ socket ], nil, @timeout)
+              next
+            end
+            begin
+              socket.connect_nonblock(sockaddr)
+            rescue Errno::EISCONN
+            end
           end
+          return @handle = socket
+        rescue StandardError => e
+          next
         end
-        @handle
-      rescue StandardError => e
-        raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: #{e}")
       end
+      raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: #{e}")
     end
 
     def open?
@@ -132,8 +134,10 @@
       @handle = nil
     end
 
-    def to_io
-      @handle
+    alias to_io handle
+
+    def to_s
+      "socket(#{@host}:#{@port})"
     end
   end
 end
diff --git a/lib/rb/lib/thrift/transport/ssl_server_socket.rb b/lib/rb/lib/thrift/transport/ssl_server_socket.rb
new file mode 100644
index 0000000..3abd5ec
--- /dev/null
+++ b/lib/rb/lib/thrift/transport/ssl_server_socket.rb
@@ -0,0 +1,41 @@
+# encoding: ascii-8bit
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'socket'
+
+module Thrift
+  class SSLServerSocket < ServerSocket
+    def initialize(host_or_port, port = nil, ssl_context = nil)
+      super(host_or_port, port)
+      @ssl_context = ssl_context
+    end
+
+    attr_accessor :ssl_context
+
+    def listen
+      socket = TCPServer.new(@host, @port)
+      @handle = OpenSSL::SSL::SSLServer.new(socket, @ssl_context)
+    end
+    
+    def to_s
+      "ssl(#{super.to_s})"
+    end
+  end
+end
diff --git a/lib/rb/lib/thrift/transport/ssl_socket.rb b/lib/rb/lib/thrift/transport/ssl_socket.rb
new file mode 100644
index 0000000..7ab96ab
--- /dev/null
+++ b/lib/rb/lib/thrift/transport/ssl_socket.rb
@@ -0,0 +1,51 @@
+# encoding: ascii-8bit
+#
+# 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.
+
+module Thrift
+  class SSLSocket < Socket
+    def initialize(host='localhost', port=9090, timeout=nil, ssl_context=nil)
+      super(host, port, timeout)
+      @ssl_context = ssl_context
+    end
+
+    attr_accessor :ssl_context
+
+    def open
+      socket = super
+      @handle = OpenSSL::SSL::SSLSocket.new(socket, @ssl_context)
+      begin
+        @handle.connect_nonblock
+        @handle.post_connection_check(@host)
+        @handle
+      rescue IO::WaitReadable
+        IO.select([ @handle ], nil, nil, @timeout)
+        retry
+      rescue IO::WaitWritable
+        IO.select(nil, [ @handle ], nil, @timeout)
+        retry
+      rescue StandardError => e
+        raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: #{e}")
+      end
+    end
+    
+    def to_s
+      "ssl(#{super.to_s})"
+    end
+  end
+end
diff --git a/lib/rb/lib/thrift/transport/unix_server_socket.rb b/lib/rb/lib/thrift/transport/unix_server_socket.rb
index a135d25..057d122 100644
--- a/lib/rb/lib/thrift/transport/unix_server_socket.rb
+++ b/lib/rb/lib/thrift/transport/unix_server_socket.rb
@@ -56,5 +56,9 @@
     end
 
     alias to_io handle
+
+    def to_s
+      "domain(#{@path})"
+    end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/lib/thrift/transport/unix_socket.rb b/lib/rb/lib/thrift/transport/unix_socket.rb
index 8f692e4..5dffd59 100644
--- a/lib/rb/lib/thrift/transport/unix_socket.rb
+++ b/lib/rb/lib/thrift/transport/unix_socket.rb
@@ -36,5 +36,9 @@
         raise TransportException.new(TransportException::NOT_OPEN, "Could not open UNIX socket at #{@path}")
       end
     end
+    
+    def to_s
+      "domain(#{@path})"
+    end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/lib/thrift/union.rb b/lib/rb/lib/thrift/union.rb
index a7058f2..490c55c 100644
--- a/lib/rb/lib/thrift/union.rb
+++ b/lib/rb/lib/thrift/union.rb
@@ -87,12 +87,9 @@
     end
 
     def ==(other)
-      other != nil && @setfield == other.get_set_field && @value == other.get_value
+      other.equal?(self) || other.instance_of?(self.class) && @setfield == other.get_set_field && @value == other.get_value
     end
-
-    def eql?(other)
-      self.class == other.class && self == other
-    end
+    alias_method :eql?, :==
 
     def hash
       [self.class.name, @setfield, @value].hash
@@ -176,4 +173,4 @@
       end
     end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/spec/BaseService.thrift b/lib/rb/spec/BaseService.thrift
new file mode 100644
index 0000000..5c7d32a
--- /dev/null
+++ b/lib/rb/spec/BaseService.thrift
@@ -0,0 +1,27 @@
+# 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.
+#
+
+namespace rb Base
+
+struct Hello {
+  1: string greeting = "hello world"
+}
+
+service BaseService {
+  Hello greeting(1:bool english)
+}
diff --git a/lib/rb/spec/ExtendedService.thrift b/lib/rb/spec/ExtendedService.thrift
new file mode 100644
index 0000000..1a6b705
--- /dev/null
+++ b/lib/rb/spec/ExtendedService.thrift
@@ -0,0 +1,25 @@
+# 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.
+#
+
+namespace rb Extended
+
+include "BaseService.thrift"
+
+service ExtendedService extends BaseService.BaseService {
+  void ping()
+}
diff --git a/lib/rb/spec/Referenced.thrift b/lib/rb/spec/Referenced.thrift
new file mode 100644
index 0000000..98f183f
--- /dev/null
+++ b/lib/rb/spec/Referenced.thrift
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#
+# 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.
+#
+
+namespace rb OtherNamespace
+
+enum SomeEnum {
+  ONE
+  TWO
+}
diff --git a/lib/rb/spec/ThriftNamespacedSpec.thrift b/lib/rb/spec/ThriftNamespacedSpec.thrift
new file mode 100644
index 0000000..02f2889
--- /dev/null
+++ b/lib/rb/spec/ThriftNamespacedSpec.thrift
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#
+# 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.
+#
+
+namespace rb NamespacedSpecNamespace
+
+include "Referenced.thrift"
+
+struct Hello {
+  1: string greeting = "hello world"
+}
+
+service NamespacedNonblockingService {
+  Hello greeting(1:bool english)
+  bool block()
+  oneway void unblock(1:i32 n)
+  oneway void shutdown()
+  void sleep(1:double seconds)
+}
diff --git a/lib/rb/spec/base_protocol_spec.rb b/lib/rb/spec/base_protocol_spec.rb
index ec50c48..eca936b 100644
--- a/lib/rb/spec/base_protocol_spec.rb
+++ b/lib/rb/spec/base_protocol_spec.rb
@@ -22,41 +22,46 @@
 describe 'BaseProtocol' do
 
   before(:each) do
-    @trans = mock("MockTransport")
+    @trans = double("MockTransport")
     @prot = Thrift::BaseProtocol.new(@trans)
   end
 
   describe Thrift::BaseProtocol do
     # most of the methods are stubs, so we can ignore them
 
+    it "should provide a reasonable to_s" do
+      expect(@trans).to receive(:to_s).once.and_return("trans")
+      expect(@prot.to_s).to eq("trans")
+    end
+
     it "should make trans accessible" do
-      @prot.trans.should eql(@trans)
+      expect(@prot.trans).to eql(@trans)
     end
 
     it 'should write out a field nicely (deprecated write_field signature)' do
-      @prot.should_receive(:write_field_begin).with('field', 'type', 'fid').ordered
-      @prot.should_receive(:write_type).with({:name => 'field', :type => 'type'}, 'value').ordered
-      @prot.should_receive(:write_field_end).ordered
+      expect(@prot).to receive(:write_field_begin).with('field', 'type', 'fid').ordered
+      expect(@prot).to receive(:write_type).with({:name => 'field', :type => 'type'}, 'value').ordered
+      expect(@prot).to receive(:write_field_end).ordered
       @prot.write_field('field', 'type', 'fid', 'value')
     end
 
     it 'should write out a field nicely' do
-      @prot.should_receive(:write_field_begin).with('field', 'type', 'fid').ordered
-      @prot.should_receive(:write_type).with({:name => 'field', :type => 'type', :binary => false}, 'value').ordered
-      @prot.should_receive(:write_field_end).ordered
+      expect(@prot).to receive(:write_field_begin).with('field', 'type', 'fid').ordered
+      expect(@prot).to receive(:write_type).with({:name => 'field', :type => 'type', :binary => false}, 'value').ordered
+      expect(@prot).to receive(:write_field_end).ordered
       @prot.write_field({:name => 'field', :type => 'type', :binary => false}, 'fid', 'value')
     end
 
     it 'should write out the different types (deprecated write_type signature)' do
-      @prot.should_receive(:write_bool).with('bool').ordered
-      @prot.should_receive(:write_byte).with('byte').ordered
-      @prot.should_receive(:write_double).with('double').ordered
-      @prot.should_receive(:write_i16).with('i16').ordered
-      @prot.should_receive(:write_i32).with('i32').ordered
-      @prot.should_receive(:write_i64).with('i64').ordered
-      @prot.should_receive(:write_string).with('string').ordered
-      struct = mock('Struct')
-      struct.should_receive(:write).with(@prot).ordered
+      expect(@prot).to receive(:write_bool).with('bool').ordered
+      expect(@prot).to receive(:write_byte).with('byte').ordered
+      expect(@prot).to receive(:write_double).with('double').ordered
+      expect(@prot).to receive(:write_i16).with('i16').ordered
+      expect(@prot).to receive(:write_i32).with('i32').ordered
+      expect(@prot).to receive(:write_i64).with('i64').ordered
+      expect(@prot).to receive(:write_string).with('string').ordered
+      struct = double('Struct')
+      expect(struct).to receive(:write).with(@prot).ordered
       @prot.write_type(Thrift::Types::BOOL, 'bool')
       @prot.write_type(Thrift::Types::BYTE, 'byte')
       @prot.write_type(Thrift::Types::DOUBLE, 'double')
@@ -72,16 +77,16 @@
     end
 
     it 'should write out the different types' do
-      @prot.should_receive(:write_bool).with('bool').ordered
-      @prot.should_receive(:write_byte).with('byte').ordered
-      @prot.should_receive(:write_double).with('double').ordered
-      @prot.should_receive(:write_i16).with('i16').ordered
-      @prot.should_receive(:write_i32).with('i32').ordered
-      @prot.should_receive(:write_i64).with('i64').ordered
-      @prot.should_receive(:write_string).with('string').ordered
-      @prot.should_receive(:write_binary).with('binary').ordered
-      struct = mock('Struct')
-      struct.should_receive(:write).with(@prot).ordered
+      expect(@prot).to receive(:write_bool).with('bool').ordered
+      expect(@prot).to receive(:write_byte).with('byte').ordered
+      expect(@prot).to receive(:write_double).with('double').ordered
+      expect(@prot).to receive(:write_i16).with('i16').ordered
+      expect(@prot).to receive(:write_i32).with('i32').ordered
+      expect(@prot).to receive(:write_i64).with('i64').ordered
+      expect(@prot).to receive(:write_string).with('string').ordered
+      expect(@prot).to receive(:write_binary).with('binary').ordered
+      struct = double('Struct')
+      expect(struct).to receive(:write).with(@prot).ordered
       @prot.write_type({:type => Thrift::Types::BOOL}, 'bool')
       @prot.write_type({:type => Thrift::Types::BYTE}, 'byte')
       @prot.write_type({:type => Thrift::Types::DOUBLE}, 'double')
@@ -98,13 +103,13 @@
     end
 
     it 'should read the different types (deprecated read_type signature)' do
-      @prot.should_receive(:read_bool).ordered
-      @prot.should_receive(:read_byte).ordered
-      @prot.should_receive(:read_i16).ordered
-      @prot.should_receive(:read_i32).ordered
-      @prot.should_receive(:read_i64).ordered
-      @prot.should_receive(:read_double).ordered
-      @prot.should_receive(:read_string).ordered
+      expect(@prot).to receive(:read_bool).ordered
+      expect(@prot).to receive(:read_byte).ordered
+      expect(@prot).to receive(:read_i16).ordered
+      expect(@prot).to receive(:read_i32).ordered
+      expect(@prot).to receive(:read_i64).ordered
+      expect(@prot).to receive(:read_double).ordered
+      expect(@prot).to receive(:read_string).ordered
       @prot.read_type(Thrift::Types::BOOL)
       @prot.read_type(Thrift::Types::BYTE)
       @prot.read_type(Thrift::Types::I16)
@@ -120,14 +125,14 @@
     end
 
     it 'should read the different types' do
-      @prot.should_receive(:read_bool).ordered
-      @prot.should_receive(:read_byte).ordered
-      @prot.should_receive(:read_i16).ordered
-      @prot.should_receive(:read_i32).ordered
-      @prot.should_receive(:read_i64).ordered
-      @prot.should_receive(:read_double).ordered
-      @prot.should_receive(:read_string).ordered
-      @prot.should_receive(:read_binary).ordered
+      expect(@prot).to receive(:read_bool).ordered
+      expect(@prot).to receive(:read_byte).ordered
+      expect(@prot).to receive(:read_i16).ordered
+      expect(@prot).to receive(:read_i32).ordered
+      expect(@prot).to receive(:read_i64).ordered
+      expect(@prot).to receive(:read_double).ordered
+      expect(@prot).to receive(:read_string).ordered
+      expect(@prot).to receive(:read_binary).ordered
       @prot.read_type({:type => Thrift::Types::BOOL})
       @prot.read_type({:type => Thrift::Types::BYTE})
       @prot.read_type({:type => Thrift::Types::I16})
@@ -144,13 +149,13 @@
     end
 
     it "should skip the basic types" do
-      @prot.should_receive(:read_bool).ordered
-      @prot.should_receive(:read_byte).ordered
-      @prot.should_receive(:read_i16).ordered
-      @prot.should_receive(:read_i32).ordered
-      @prot.should_receive(:read_i64).ordered
-      @prot.should_receive(:read_double).ordered
-      @prot.should_receive(:read_string).ordered
+      expect(@prot).to receive(:read_bool).ordered
+      expect(@prot).to receive(:read_byte).ordered
+      expect(@prot).to receive(:read_i16).ordered
+      expect(@prot).to receive(:read_i32).ordered
+      expect(@prot).to receive(:read_i64).ordered
+      expect(@prot).to receive(:read_double).ordered
+      expect(@prot).to receive(:read_string).ordered
       @prot.skip(Thrift::Types::BOOL)
       @prot.skip(Thrift::Types::BYTE)
       @prot.skip(Thrift::Types::I16)
@@ -163,47 +168,47 @@
 
     it "should skip structs" do
       real_skip = @prot.method(:skip)
-      @prot.should_receive(:read_struct_begin).ordered
-      @prot.should_receive(:read_field_begin).exactly(4).times.and_return(
+      expect(@prot).to receive(:read_struct_begin).ordered
+      expect(@prot).to receive(:read_field_begin).exactly(4).times.and_return(
         ['field 1', Thrift::Types::STRING, 1],
         ['field 2', Thrift::Types::I32, 2],
         ['field 3', Thrift::Types::MAP, 3],
         [nil, Thrift::Types::STOP, 0]
       )
-      @prot.should_receive(:read_field_end).exactly(3).times
-      @prot.should_receive(:read_string).exactly(3).times
-      @prot.should_receive(:read_i32).ordered
-      @prot.should_receive(:read_map_begin).ordered.and_return([Thrift::Types::STRING, Thrift::Types::STRING, 1])
+      expect(@prot).to receive(:read_field_end).exactly(3).times
+      expect(@prot).to receive(:read_string).exactly(3).times
+      expect(@prot).to receive(:read_i32).ordered
+      expect(@prot).to receive(:read_map_begin).ordered.and_return([Thrift::Types::STRING, Thrift::Types::STRING, 1])
       # @prot.should_receive(:read_string).exactly(2).times
-      @prot.should_receive(:read_map_end).ordered
-      @prot.should_receive(:read_struct_end).ordered
+      expect(@prot).to receive(:read_map_end).ordered
+      expect(@prot).to receive(:read_struct_end).ordered
       real_skip.call(Thrift::Types::STRUCT)
     end
 
     it "should skip maps" do
       real_skip = @prot.method(:skip)
-      @prot.should_receive(:read_map_begin).ordered.and_return([Thrift::Types::STRING, Thrift::Types::STRUCT, 1])
-      @prot.should_receive(:read_string).ordered
-      @prot.should_receive(:read_struct_begin).ordered.and_return(["some_struct"])
-      @prot.should_receive(:read_field_begin).ordered.and_return([nil, Thrift::Types::STOP, nil]);
-      @prot.should_receive(:read_struct_end).ordered
-      @prot.should_receive(:read_map_end).ordered
+      expect(@prot).to receive(:read_map_begin).ordered.and_return([Thrift::Types::STRING, Thrift::Types::STRUCT, 1])
+      expect(@prot).to receive(:read_string).ordered
+      expect(@prot).to receive(:read_struct_begin).ordered.and_return(["some_struct"])
+      expect(@prot).to receive(:read_field_begin).ordered.and_return([nil, Thrift::Types::STOP, nil]);
+      expect(@prot).to receive(:read_struct_end).ordered
+      expect(@prot).to receive(:read_map_end).ordered
       real_skip.call(Thrift::Types::MAP)
     end
 
     it "should skip sets" do
       real_skip = @prot.method(:skip)
-      @prot.should_receive(:read_set_begin).ordered.and_return([Thrift::Types::I64, 9])
-      @prot.should_receive(:read_i64).ordered.exactly(9).times
-      @prot.should_receive(:read_set_end)
+      expect(@prot).to receive(:read_set_begin).ordered.and_return([Thrift::Types::I64, 9])
+      expect(@prot).to receive(:read_i64).ordered.exactly(9).times
+      expect(@prot).to receive(:read_set_end)
       real_skip.call(Thrift::Types::SET)
     end
 
     it "should skip lists" do
       real_skip = @prot.method(:skip)
-      @prot.should_receive(:read_list_begin).ordered.and_return([Thrift::Types::DOUBLE, 11])
-      @prot.should_receive(:read_double).ordered.exactly(11).times
-      @prot.should_receive(:read_list_end)
+      expect(@prot).to receive(:read_list_begin).ordered.and_return([Thrift::Types::DOUBLE, 11])
+      expect(@prot).to receive(:read_double).ordered.exactly(11).times
+      expect(@prot).to receive(:read_list_end)
       real_skip.call(Thrift::Types::LIST)
     end
   end
@@ -211,7 +216,11 @@
   describe Thrift::BaseProtocolFactory do
     it "should raise NotImplementedError" do
       # returning nil since Protocol is just an abstract class
-      lambda {Thrift::BaseProtocolFactory.new.get_protocol(mock("MockTransport"))}.should raise_error(NotImplementedError)
+      expect {Thrift::BaseProtocolFactory.new.get_protocol(double("MockTransport"))}.to raise_error(NotImplementedError)
+    end
+
+    it "should provide a reasonable to_s" do
+      expect(Thrift::BaseProtocolFactory.new.to_s).to eq("base")
     end
   end
 end
diff --git a/lib/rb/spec/base_transport_spec.rb b/lib/rb/spec/base_transport_spec.rb
index 4196572..d2f60aa 100644
--- a/lib/rb/spec/base_transport_spec.rb
+++ b/lib/rb/spec/base_transport_spec.rb
@@ -24,105 +24,119 @@
   describe Thrift::TransportException do
     it "should make type accessible" do
       exc = Thrift::TransportException.new(Thrift::TransportException::ALREADY_OPEN, "msg")
-      exc.type.should == Thrift::TransportException::ALREADY_OPEN
-      exc.message.should == "msg"
+      expect(exc.type).to eq(Thrift::TransportException::ALREADY_OPEN)
+      expect(exc.message).to eq("msg")
     end
   end
 
   describe Thrift::BaseTransport do
     it "should read the specified size" do
       transport = Thrift::BaseTransport.new
-      transport.should_receive(:read).with(40).ordered.and_return("10 letters")
-      transport.should_receive(:read).with(30).ordered.and_return("fifteen letters")
-      transport.should_receive(:read).with(15).ordered.and_return("more characters")
-      transport.read_all(40).should == "10 lettersfifteen lettersmore characters"
+      expect(transport).to receive(:read).with(40).ordered.and_return("10 letters")
+      expect(transport).to receive(:read).with(30).ordered.and_return("fifteen letters")
+      expect(transport).to receive(:read).with(15).ordered.and_return("more characters")
+      expect(transport.read_all(40)).to eq("10 lettersfifteen lettersmore characters")
     end
 
     it "should stub out the rest of the methods" do
       # can't test for stubbiness, so just make sure they're defined
       [:open?, :open, :close, :read, :write, :flush].each do |sym|
-        Thrift::BaseTransport.method_defined?(sym).should be_true
+        expect(Thrift::BaseTransport.method_defined?(sym)).to be_truthy
       end
     end
 
     it "should alias << to write" do
-      Thrift::BaseTransport.instance_method(:<<).should == Thrift::BaseTransport.instance_method(:write)
+      expect(Thrift::BaseTransport.instance_method(:<<)).to eq(Thrift::BaseTransport.instance_method(:write))
+    end
+    
+    it "should provide a reasonable to_s" do
+      expect(Thrift::BaseTransport.new.to_s).to eq("base")
     end
   end
 
   describe Thrift::BaseServerTransport do
     it "should stub out its methods" do
       [:listen, :accept, :close].each do |sym|
-        Thrift::BaseServerTransport.method_defined?(sym).should be_true
+        expect(Thrift::BaseServerTransport.method_defined?(sym)).to be_truthy
       end
     end
   end
 
   describe Thrift::BaseTransportFactory do
     it "should return the transport it's given" do
-      transport = mock("Transport")
-      Thrift::BaseTransportFactory.new.get_transport(transport).should eql(transport)
+      transport = double("Transport")
+      expect(Thrift::BaseTransportFactory.new.get_transport(transport)).to eql(transport)
+    end
+    
+    it "should provide a reasonable to_s" do
+      expect(Thrift::BaseTransportFactory.new.to_s).to eq("base")
     end
   end
 
   describe Thrift::BufferedTransport do
+    it "should provide a to_s that describes the encapsulation" do
+      trans = double("Transport")
+      expect(trans).to receive(:to_s).and_return("mock")
+      expect(Thrift::BufferedTransport.new(trans).to_s).to eq("buffered(mock)")
+    end
+
     it "should pass through everything but write/flush/read" do
-      trans = mock("Transport")
-      trans.should_receive(:open?).ordered.and_return("+ open?")
-      trans.should_receive(:open).ordered.and_return("+ open")
-      trans.should_receive(:flush).ordered # from the close
-      trans.should_receive(:close).ordered.and_return("+ close")
+      trans = double("Transport")
+      expect(trans).to receive(:open?).ordered.and_return("+ open?")
+      expect(trans).to receive(:open).ordered.and_return("+ open")
+      expect(trans).to receive(:flush).ordered # from the close
+      expect(trans).to receive(:close).ordered.and_return("+ close")
       btrans = Thrift::BufferedTransport.new(trans)
-      btrans.open?.should == "+ open?"
-      btrans.open.should == "+ open"
-      btrans.close.should == "+ close"
+      expect(btrans.open?).to eq("+ open?")
+      expect(btrans.open).to eq("+ open")
+      expect(btrans.close).to eq("+ close")
     end
 
     it "should buffer reads in chunks of #{Thrift::BufferedTransport::DEFAULT_BUFFER}" do
-      trans = mock("Transport")
-      trans.should_receive(:read).with(Thrift::BufferedTransport::DEFAULT_BUFFER).and_return("lorum ipsum dolor emet")
+      trans = double("Transport")
+      expect(trans).to receive(:read).with(Thrift::BufferedTransport::DEFAULT_BUFFER).and_return("lorum ipsum dolor emet")
       btrans = Thrift::BufferedTransport.new(trans)
-      btrans.read(6).should == "lorum "
-      btrans.read(6).should == "ipsum "
-      btrans.read(6).should == "dolor "
-      btrans.read(6).should == "emet"
+      expect(btrans.read(6)).to eq("lorum ")
+      expect(btrans.read(6)).to eq("ipsum ")
+      expect(btrans.read(6)).to eq("dolor ")
+      expect(btrans.read(6)).to eq("emet")
     end
 
     it "should buffer writes and send them on flush" do
-      trans = mock("Transport")
+      trans = double("Transport")
       btrans = Thrift::BufferedTransport.new(trans)
       btrans.write("one/")
       btrans.write("two/")
       btrans.write("three/")
-      trans.should_receive(:write).with("one/two/three/").ordered
-      trans.should_receive(:flush).ordered
+      expect(trans).to receive(:write).with("one/two/three/").ordered
+      expect(trans).to receive(:flush).ordered
       btrans.flush
     end
 
     it "should only send buffered data once" do
-      trans = mock("Transport")
+      trans = double("Transport")
       btrans = Thrift::BufferedTransport.new(trans)
       btrans.write("one/")
       btrans.write("two/")
       btrans.write("three/")
-      trans.should_receive(:write).with("one/two/three/")
-      trans.stub!(:flush)
+      expect(trans).to receive(:write).with("one/two/three/")
+      allow(trans).to receive(:flush)
       btrans.flush
       # Nothing to flush with no data
       btrans.flush
     end
 
     it "should flush on close" do
-      trans = mock("Transport")
-      trans.should_receive(:close)
+      trans = double("Transport")
+      expect(trans).to receive(:close)
       btrans = Thrift::BufferedTransport.new(trans)
-      btrans.should_receive(:flush)
+      expect(btrans).to receive(:flush)
       btrans.close
     end
 
     it "should not write to socket if there's no data" do
-      trans = mock("Transport")
-      trans.should_receive(:flush)
+      trans = double("Transport")
+      expect(trans).to receive(:flush)
       btrans = Thrift::BufferedTransport.new(trans)
       btrans.flush
     end
@@ -130,80 +144,90 @@
 
   describe Thrift::BufferedTransportFactory do
     it "should wrap the given transport in a BufferedTransport" do
-      trans = mock("Transport")
-      btrans = mock("BufferedTransport")
-      Thrift::BufferedTransport.should_receive(:new).with(trans).and_return(btrans)
-      Thrift::BufferedTransportFactory.new.get_transport(trans).should == btrans
+      trans = double("Transport")
+      btrans = double("BufferedTransport")
+      expect(Thrift::BufferedTransport).to receive(:new).with(trans).and_return(btrans)
+      expect(Thrift::BufferedTransportFactory.new.get_transport(trans)).to eq(btrans)
+    end
+    
+    it "should provide a reasonable to_s" do
+      expect(Thrift::BufferedTransportFactory.new.to_s).to eq("buffered")
     end
   end
 
   describe Thrift::FramedTransport do
     before(:each) do
-      @trans = mock("Transport")
+      @trans = double("Transport")
+    end
+
+    it "should provide a to_s that describes the encapsulation" do
+      trans = double("Transport")
+      expect(trans).to receive(:to_s).and_return("mock")
+      expect(Thrift::FramedTransport.new(trans).to_s).to eq("framed(mock)")
     end
 
     it "should pass through open?/open/close" do
       ftrans = Thrift::FramedTransport.new(@trans)
-      @trans.should_receive(:open?).ordered.and_return("+ open?")
-      @trans.should_receive(:open).ordered.and_return("+ open")
-      @trans.should_receive(:close).ordered.and_return("+ close")
-      ftrans.open?.should == "+ open?"
-      ftrans.open.should == "+ open"
-      ftrans.close.should == "+ close"
+      expect(@trans).to receive(:open?).ordered.and_return("+ open?")
+      expect(@trans).to receive(:open).ordered.and_return("+ open")
+      expect(@trans).to receive(:close).ordered.and_return("+ close")
+      expect(ftrans.open?).to eq("+ open?")
+      expect(ftrans.open).to eq("+ open")
+      expect(ftrans.close).to eq("+ close")
     end
 
     it "should pass through read when read is turned off" do
       ftrans = Thrift::FramedTransport.new(@trans, false, true)
-      @trans.should_receive(:read).with(17).ordered.and_return("+ read")
-      ftrans.read(17).should == "+ read"
+      expect(@trans).to receive(:read).with(17).ordered.and_return("+ read")
+      expect(ftrans.read(17)).to eq("+ read")
     end
 
     it "should pass through write/flush when write is turned off" do
       ftrans = Thrift::FramedTransport.new(@trans, true, false)
-      @trans.should_receive(:write).with("foo").ordered.and_return("+ write")
-      @trans.should_receive(:flush).ordered.and_return("+ flush")
-      ftrans.write("foo").should == "+ write"
-      ftrans.flush.should == "+ flush"
+      expect(@trans).to receive(:write).with("foo").ordered.and_return("+ write")
+      expect(@trans).to receive(:flush).ordered.and_return("+ flush")
+      expect(ftrans.write("foo")).to eq("+ write")
+      expect(ftrans.flush).to eq("+ flush")
     end
 
     it "should return a full frame if asked for >= the frame's length" do
       frame = "this is a frame"
-      @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
-      @trans.should_receive(:read_all).with(frame.length).and_return(frame)
-      Thrift::FramedTransport.new(@trans).read(frame.length + 10).should == frame
+      expect(@trans).to receive(:read_all).with(4).and_return("\000\000\000\017")
+      expect(@trans).to receive(:read_all).with(frame.length).and_return(frame)
+      expect(Thrift::FramedTransport.new(@trans).read(frame.length + 10)).to eq(frame)
     end
 
     it "should return slices of the frame when asked for < the frame's length" do
       frame = "this is a frame"
-      @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
-      @trans.should_receive(:read_all).with(frame.length).and_return(frame)
+      expect(@trans).to receive(:read_all).with(4).and_return("\000\000\000\017")
+      expect(@trans).to receive(:read_all).with(frame.length).and_return(frame)
       ftrans = Thrift::FramedTransport.new(@trans)
-      ftrans.read(4).should == "this"
-      ftrans.read(4).should == " is "
-      ftrans.read(16).should == "a frame"
+      expect(ftrans.read(4)).to eq("this")
+      expect(ftrans.read(4)).to eq(" is ")
+      expect(ftrans.read(16)).to eq("a frame")
     end
 
     it "should return nothing if asked for <= 0" do
-      Thrift::FramedTransport.new(@trans).read(-2).should == ""
+      expect(Thrift::FramedTransport.new(@trans).read(-2)).to eq("")
     end
 
     it "should pull a new frame when the first is exhausted" do
       frame = "this is a frame"
       frame2 = "yet another frame"
-      @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021")
-      @trans.should_receive(:read_all).with(frame.length).and_return(frame)
-      @trans.should_receive(:read_all).with(frame2.length).and_return(frame2)
+      expect(@trans).to receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021")
+      expect(@trans).to receive(:read_all).with(frame.length).and_return(frame)
+      expect(@trans).to receive(:read_all).with(frame2.length).and_return(frame2)
       ftrans = Thrift::FramedTransport.new(@trans)
-      ftrans.read(4).should == "this"
-      ftrans.read(8).should == " is a fr"
-      ftrans.read(6).should == "ame"
-      ftrans.read(4).should == "yet "
-      ftrans.read(16).should == "another frame"
+      expect(ftrans.read(4)).to eq("this")
+      expect(ftrans.read(8)).to eq(" is a fr")
+      expect(ftrans.read(6)).to eq("ame")
+      expect(ftrans.read(4)).to eq("yet ")
+      expect(ftrans.read(16)).to eq("another frame")
     end
 
     it "should buffer writes" do
       ftrans = Thrift::FramedTransport.new(@trans)
-      @trans.should_not_receive(:write)
+      expect(@trans).not_to receive(:write)
       ftrans.write("foo")
       ftrans.write("bar")
       ftrans.write("this is a frame")
@@ -213,15 +237,15 @@
       ftrans = Thrift::FramedTransport.new(@trans)
       ftrans.write("foobar", 3)
       ftrans.write("barfoo", 1)
-      @trans.stub!(:flush)
-      @trans.should_receive(:write).with("\000\000\000\004foob")
+      allow(@trans).to receive(:flush)
+      expect(@trans).to receive(:write).with("\000\000\000\004foob")
       ftrans.flush
     end
 
     it "should flush frames with a 4-byte header" do
       ftrans = Thrift::FramedTransport.new(@trans)
-      @trans.should_receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered
-      @trans.should_receive(:flush).ordered
+      expect(@trans).to receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered
+      expect(@trans).to receive(:flush).ordered
       ftrans.write("one/")
       ftrans.write("two/")
       ftrans.write("three/")
@@ -231,22 +255,26 @@
 
     it "should not flush the same buffered data twice" do
       ftrans = Thrift::FramedTransport.new(@trans)
-      @trans.should_receive(:write).with("\000\000\000\007foo/bar")
-      @trans.stub!(:flush)
+      expect(@trans).to receive(:write).with("\000\000\000\007foo/bar")
+      allow(@trans).to receive(:flush)
       ftrans.write("foo")
       ftrans.write("/bar")
       ftrans.flush
-      @trans.should_receive(:write).with("\000\000\000\000")
+      expect(@trans).to receive(:write).with("\000\000\000\000")
       ftrans.flush
     end
   end
 
   describe Thrift::FramedTransportFactory do
     it "should wrap the given transport in a FramedTransport" do
-      trans = mock("Transport")
-      Thrift::FramedTransport.should_receive(:new).with(trans)
+      trans = double("Transport")
+      expect(Thrift::FramedTransport).to receive(:new).with(trans)
       Thrift::FramedTransportFactory.new.get_transport(trans)
     end
+    
+    it "should provide a reasonable to_s" do
+      expect(Thrift::FramedTransportFactory.new.to_s).to eq("framed")
+    end
   end
 
   describe Thrift::MemoryBufferTransport do
@@ -254,96 +282,106 @@
       @buffer = Thrift::MemoryBufferTransport.new
     end
 
+    it "should provide a reasonable to_s" do
+      expect(@buffer.to_s).to eq("memory")
+    end
+
     it "should accept a buffer on input and use it directly" do
       s = "this is a test"
       @buffer = Thrift::MemoryBufferTransport.new(s)
-      @buffer.read(4).should == "this"
+      expect(@buffer.read(4)).to eq("this")
       s.slice!(-4..-1)
-      @buffer.read(@buffer.available).should == " is a "
+      expect(@buffer.read(@buffer.available)).to eq(" is a ")
     end
 
     it "should always remain open" do
-      @buffer.should be_open
+      expect(@buffer).to be_open
       @buffer.close
-      @buffer.should be_open
+      expect(@buffer).to be_open
     end
 
     it "should respond to peek and available" do
       @buffer.write "some data"
-      @buffer.peek.should be_true
-      @buffer.available.should == 9
+      expect(@buffer.peek).to be_truthy
+      expect(@buffer.available).to eq(9)
       @buffer.read(4)
-      @buffer.peek.should be_true
-      @buffer.available.should == 5
+      expect(@buffer.peek).to be_truthy
+      expect(@buffer.available).to eq(5)
       @buffer.read(5)
-      @buffer.peek.should be_false
-      @buffer.available.should == 0
+      expect(@buffer.peek).to be_falsey
+      expect(@buffer.available).to eq(0)
     end
 
     it "should be able to reset the buffer" do
       @buffer.write "test data"
       @buffer.reset_buffer("foobar")
-      @buffer.available.should == 6
-      @buffer.read(@buffer.available).should == "foobar"
+      expect(@buffer.available).to eq(6)
+      expect(@buffer.read(@buffer.available)).to eq("foobar")
       @buffer.reset_buffer
-      @buffer.available.should == 0
+      expect(@buffer.available).to eq(0)
     end
 
     it "should copy the given string when resetting the buffer" do
       s = "this is a test"
       @buffer.reset_buffer(s)
-      @buffer.available.should == 14
+      expect(@buffer.available).to eq(14)
       @buffer.read(10)
-      @buffer.available.should == 4
-      s.should == "this is a test"
+      expect(@buffer.available).to eq(4)
+      expect(s).to eq("this is a test")
     end
 
     it "should return from read what was given in write" do
       @buffer.write "test data"
-      @buffer.read(4).should == "test"
-      @buffer.read(@buffer.available).should == " data"
+      expect(@buffer.read(4)).to eq("test")
+      expect(@buffer.read(@buffer.available)).to eq(" data")
       @buffer.write "foo"
       @buffer.write " bar"
-      @buffer.read(@buffer.available).should == "foo bar"
+      expect(@buffer.read(@buffer.available)).to eq("foo bar")
     end
 
     it "should throw an EOFError when there isn't enough data in the buffer" do
       @buffer.reset_buffer("")
-      lambda{@buffer.read(1)}.should raise_error(EOFError)
+      expect{@buffer.read(1)}.to raise_error(EOFError)
 
       @buffer.reset_buffer("1234")
-      lambda{@buffer.read(5)}.should raise_error(EOFError)
+      expect{@buffer.read(5)}.to raise_error(EOFError)
     end
   end
 
   describe Thrift::IOStreamTransport do
     before(:each) do
-      @input = mock("Input", :closed? => false)
-      @output = mock("Output", :closed? => false)
+      @input = double("Input", :closed? => false)
+      @output = double("Output", :closed? => false)
       @trans = Thrift::IOStreamTransport.new(@input, @output)
     end
 
+    it "should provide a reasonable to_s" do
+      expect(@input).to receive(:to_s).and_return("mock_input")
+      expect(@output).to receive(:to_s).and_return("mock_output")
+      expect(@trans.to_s).to eq("iostream(input=mock_input,output=mock_output)")
+    end
+
     it "should be open as long as both input or output are open" do
-      @trans.should be_open
-      @input.stub!(:closed?).and_return(true)
-      @trans.should be_open
-      @input.stub!(:closed?).and_return(false)
-      @output.stub!(:closed?).and_return(true)
-      @trans.should be_open
-      @input.stub!(:closed?).and_return(true)
-      @trans.should_not be_open
+      expect(@trans).to be_open
+      allow(@input).to receive(:closed?).and_return(true)
+      expect(@trans).to be_open
+      allow(@input).to receive(:closed?).and_return(false)
+      allow(@output).to receive(:closed?).and_return(true)
+      expect(@trans).to be_open
+      allow(@input).to receive(:closed?).and_return(true)
+      expect(@trans).not_to be_open
     end
 
     it "should pass through read/write to input/output" do
-      @input.should_receive(:read).with(17).and_return("+ read")
-      @output.should_receive(:write).with("foobar").and_return("+ write")
-      @trans.read(17).should == "+ read"
-      @trans.write("foobar").should == "+ write"
+      expect(@input).to receive(:read).with(17).and_return("+ read")
+      expect(@output).to receive(:write).with("foobar").and_return("+ write")
+      expect(@trans.read(17)).to eq("+ read")
+      expect(@trans.write("foobar")).to eq("+ write")
     end
 
     it "should close both input and output when closed" do
-      @input.should_receive(:close)
-      @output.should_receive(:close)
+      expect(@input).to receive(:close)
+      expect(@output).to receive(:close)
       @trans.close
     end
   end
diff --git a/lib/rb/spec/binary_protocol_accelerated_spec.rb b/lib/rb/spec/binary_protocol_accelerated_spec.rb
index bac9ea7..b2cd04b 100644
--- a/lib/rb/spec/binary_protocol_accelerated_spec.rb
+++ b/lib/rb/spec/binary_protocol_accelerated_spec.rb
@@ -33,10 +33,14 @@
 
     describe Thrift::BinaryProtocolAcceleratedFactory do
       it "should create a BinaryProtocolAccelerated" do
-        Thrift::BinaryProtocolAcceleratedFactory.new.get_protocol(mock("MockTransport")).should be_instance_of(Thrift::BinaryProtocolAccelerated)
+        expect(Thrift::BinaryProtocolAcceleratedFactory.new.get_protocol(double("MockTransport"))).to be_instance_of(Thrift::BinaryProtocolAccelerated)
+      end
+
+      it "should provide a reasonable to_s" do
+        expect(Thrift::BinaryProtocolAcceleratedFactory.new.to_s).to eq("binary-accel")
       end
     end
   end
 else
   puts "skipping BinaryProtocolAccelerated spec because it is not defined."
-end
\ No newline at end of file
+end
diff --git a/lib/rb/spec/binary_protocol_spec.rb b/lib/rb/spec/binary_protocol_spec.rb
index 32772d3..065f5ce 100644
--- a/lib/rb/spec/binary_protocol_spec.rb
+++ b/lib/rb/spec/binary_protocol_spec.rb
@@ -38,29 +38,37 @@
     it "should read a message header" do
       @trans.write([protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::REPLY].pack('N'))
       @trans.write([42].pack('N'))
-      @prot.should_receive(:read_string).and_return('testMessage')
-      @prot.read_message_begin.should == ['testMessage', Thrift::MessageTypes::REPLY, 42]
+      expect(@prot).to receive(:read_string).and_return('testMessage')
+      expect(@prot.read_message_begin).to eq(['testMessage', Thrift::MessageTypes::REPLY, 42])
     end
 
     it "should raise an exception if the message header has the wrong version" do
-      @prot.should_receive(:read_i32).and_return(-1)
-      lambda { @prot.read_message_begin }.should raise_error(Thrift::ProtocolException, 'Missing version identifier') do |e|
+      expect(@prot).to receive(:read_i32).and_return(-1)
+      expect { @prot.read_message_begin }.to raise_error(Thrift::ProtocolException, 'Missing version identifier') do |e|
         e.type == Thrift::ProtocolException::BAD_VERSION
       end
     end
 
     it "should raise an exception if the message header does not exist and strict_read is enabled" do
-      @prot.should_receive(:read_i32).and_return(42)
-      @prot.should_receive(:strict_read).and_return(true)
-      lambda { @prot.read_message_begin }.should raise_error(Thrift::ProtocolException, 'No version identifier, old protocol client?') do |e|
+      expect(@prot).to receive(:read_i32).and_return(42)
+      expect(@prot).to receive(:strict_read).and_return(true)
+      expect { @prot.read_message_begin }.to raise_error(Thrift::ProtocolException, 'No version identifier, old protocol client?') do |e|
         e.type == Thrift::ProtocolException::BAD_VERSION
       end
     end
+
+    it "should provide a reasonable to_s" do
+      expect(@prot.to_s).to eq("binary(memory)")
+    end
   end
 
   describe Thrift::BinaryProtocolFactory do
     it "should create a BinaryProtocol" do
-      Thrift::BinaryProtocolFactory.new.get_protocol(mock("MockTransport")).should be_instance_of(Thrift::BinaryProtocol)
+      expect(Thrift::BinaryProtocolFactory.new.get_protocol(double("MockTransport"))).to be_instance_of(Thrift::BinaryProtocol)
+    end
+
+    it "should provide a reasonable to_s" do
+      expect(Thrift::BinaryProtocolFactory.new.to_s).to eq("binary")
     end
   end
 end
diff --git a/lib/rb/spec/binary_protocol_spec_shared.rb b/lib/rb/spec/binary_protocol_spec_shared.rb
index c615b58..58d65f0 100644
--- a/lib/rb/spec/binary_protocol_spec_shared.rb
+++ b/lib/rb/spec/binary_protocol_spec_shared.rb
@@ -27,34 +27,34 @@
   end
 
   it "should define the proper VERSION_1, VERSION_MASK AND TYPE_MASK" do
-    protocol_class.const_get(:VERSION_MASK).should == 0xffff0000
-    protocol_class.const_get(:VERSION_1).should == 0x80010000
-    protocol_class.const_get(:TYPE_MASK).should == 0x000000ff
+    expect(protocol_class.const_get(:VERSION_MASK)).to eq(0xffff0000)
+    expect(protocol_class.const_get(:VERSION_1)).to eq(0x80010000)
+    expect(protocol_class.const_get(:TYPE_MASK)).to eq(0x000000ff)
   end
 
   it "should make strict_read readable" do
-    @prot.strict_read.should eql(true)
+    expect(@prot.strict_read).to eql(true)
   end
 
   it "should make strict_write readable" do
-    @prot.strict_write.should eql(true)
+    expect(@prot.strict_write).to eql(true)
   end    
 
   it "should write the message header" do
     @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
-    @trans.read(@trans.available).should == [protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::CALL, "testMessage".size, "testMessage", 17].pack("NNa11N")
+    expect(@trans.read(@trans.available)).to eq([protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::CALL, "testMessage".size, "testMessage", 17].pack("NNa11N"))
   end
   
   it "should write the message header without version when writes are not strict" do
     @prot = protocol_class.new(@trans, true, false) # no strict write
     @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
-    @trans.read(@trans.available).should == "\000\000\000\vtestMessage\001\000\000\000\021"
+    expect(@trans.read(@trans.available)).to eq("\000\000\000\vtestMessage\001\000\000\000\021")
   end
   
   it "should write the message header with a version when writes are strict" do
     @prot = protocol_class.new(@trans) # strict write
     @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
-    @trans.read(@trans.available).should == "\200\001\000\001\000\000\000\vtestMessage\000\000\000\021"
+    expect(@trans.read(@trans.available)).to eq("\200\001\000\001\000\000\000\vtestMessage\000\000\000\021")
   end
   
 
@@ -62,64 +62,67 @@
 
   it "should write the field header" do
     @prot.write_field_begin('foo', Thrift::Types::DOUBLE, 3)
-    @trans.read(@trans.available).should == [Thrift::Types::DOUBLE, 3].pack("cn")
+    expect(@trans.read(@trans.available)).to eq([Thrift::Types::DOUBLE, 3].pack("cn"))
   end
   
   # field footer is a noop
   
   it "should write the STOP field" do
     @prot.write_field_stop
-    @trans.read(1).should == "\000"
+    expect(@trans.read(1)).to eq("\000")
   end
   
   it "should write the map header" do
     @prot.write_map_begin(Thrift::Types::STRING, Thrift::Types::LIST, 17)
-    @trans.read(@trans.available).should == [Thrift::Types::STRING, Thrift::Types::LIST, 17].pack("ccN");
+    expect(@trans.read(@trans.available)).to eq([Thrift::Types::STRING, Thrift::Types::LIST, 17].pack("ccN"));
   end
    
   # map footer is a noop
   
   it "should write the list header" do
     @prot.write_list_begin(Thrift::Types::I16, 42)
-    @trans.read(@trans.available).should == [Thrift::Types::I16, 42].pack("cN")
+    expect(@trans.read(@trans.available)).to eq([Thrift::Types::I16, 42].pack("cN"))
   end
   
   # list footer is a noop
   
   it "should write the set header" do
     @prot.write_set_begin(Thrift::Types::I16, 42)
-    @trans.read(@trans.available).should == [Thrift::Types::I16, 42].pack("cN")
+    expect(@trans.read(@trans.available)).to eq([Thrift::Types::I16, 42].pack("cN"))
   end
   
   it "should write a bool" do
     @prot.write_bool(true)
     @prot.write_bool(false)
-    @trans.read(@trans.available).should == "\001\000"
+    expect(@trans.read(@trans.available)).to eq("\001\000")
   end
   
   it "should treat a nil bool as false" do
     @prot.write_bool(nil)
-    @trans.read(1).should == "\000"
+    expect(@trans.read(1)).to eq("\000")
   end
   
   it "should write a byte" do
     # byte is small enough, let's check -128..127
     (-128..127).each do |i|
       @prot.write_byte(i)
-      @trans.read(1).should == [i].pack('c')
+      expect(@trans.read(1)).to eq([i].pack('c'))
     end
-    # handing it numbers out of signed range should clip
-    @trans.rspec_verify
+  end
+
+  it "should clip numbers out of signed range" do
     (128..255).each do |i|
       @prot.write_byte(i)
-      @trans.read(1).should == [i].pack('c')
+      expect(@trans.read(1)).to eq([i].pack('c'))
     end
-    # and lastly, a Bignum is going to error out
-    lambda { @prot.write_byte(2**65) }.should raise_error(RangeError)
+  end
+
+  it "errors out with a Bignum" do
+    expect { @prot.write_byte(2**65) }.to raise_error(RangeError)
   end
   
   it "should error gracefully when trying to write a nil byte" do
-    lambda { @prot.write_byte(nil) }.should raise_error
+    expect { @prot.write_byte(nil) }.to raise_error
   end
   
   it "should write an i16" do
@@ -131,14 +134,14 @@
     # and try something out of signed range, it should clip
     @prot.write_i16(2**15 + 5)
     
-    @trans.read(@trans.available).should == "\200\000\374\000\000\021\000\000\330\360\006\273\177\377\200\005"
+    expect(@trans.read(@trans.available)).to eq("\200\000\374\000\000\021\000\000\330\360\006\273\177\377\200\005")
     
     # a Bignum should error
     # lambda { @prot.write_i16(2**65) }.should raise_error(RangeError)
   end
   
   it "should error gracefully when trying to write a nil i16" do
-    lambda { @prot.write_i16(nil) }.should raise_error
+    expect { @prot.write_i16(nil) }.to raise_error
   end
   
   it "should write an i32" do
@@ -148,14 +151,14 @@
       @prot.write_i32(i)
     end
     # try something out of signed range, it should clip
-    @trans.read(@trans.available).should == "\200\000\000\000" + "\377\376\037\r" + "\377\377\366\034" + "\377\377\377\375" + "\000\000\000\000" + "\000#\340\203" + "\000\0000+" + "\177\377\377\377"
+    expect(@trans.read(@trans.available)).to eq("\200\000\000\000" + "\377\376\037\r" + "\377\377\366\034" + "\377\377\377\375" + "\000\000\000\000" + "\000#\340\203" + "\000\0000+" + "\177\377\377\377")
     [2 ** 31 + 5, 2 ** 65 + 5].each do |i|
-      lambda { @prot.write_i32(i) }.should raise_error(RangeError)  
+      expect { @prot.write_i32(i) }.to raise_error(RangeError)  
     end
   end
   
   it "should error gracefully when trying to write a nil i32" do
-    lambda { @prot.write_i32(nil) }.should raise_error
+    expect { @prot.write_i32(nil) }.to raise_error
   end
   
   it "should write an i64" do
@@ -165,7 +168,7 @@
       @prot.write_i64(i)
     end
     # try something out of signed range, it should clip
-    @trans.read(@trans.available).should == ["\200\000\000\000\000\000\000\000",
+    expect(@trans.read(@trans.available)).to eq(["\200\000\000\000\000\000\000\000",
       "\377\377\364\303\035\244+]",
       "\377\377\377\377\376\231:\341",
       "\377\377\377\377\377\377\377\026",
@@ -173,12 +176,12 @@
       "\000\000\000\000\000\000\004\317",
       "\000\000\000\000\000#\340\204",
       "\000\000\000\002\340\311~\365",
-      "\177\377\377\377\377\377\377\377"].join("")
-    lambda { @prot.write_i64(2 ** 65 + 5) }.should raise_error(RangeError)
+      "\177\377\377\377\377\377\377\377"].join(""))
+    expect { @prot.write_i64(2 ** 65 + 5) }.to raise_error(RangeError)
   end
   
   it "should error gracefully when trying to write a nil i64" do
-    lambda { @prot.write_i64(nil) }.should raise_error
+    expect { @prot.write_i64(nil) }.to raise_error
   end
   
   it "should write a double" do
@@ -186,12 +189,12 @@
     values = [Float::MIN,-1231.15325, -123123.23, -23.23515123, 0, 12351.1325, 523.23, Float::MAX]
     values.each do |f|
       @prot.write_double(f)
-      @trans.read(@trans.available).should == [f].pack("G")
+      expect(@trans.read(@trans.available)).to eq([f].pack("G"))
     end
   end
   
   it "should error gracefully when trying to write a nil double" do
-    lambda { @prot.write_double(nil) }.should raise_error
+    expect { @prot.write_double(nil) }.to raise_error
   end
 
   if RUBY_VERSION >= '1.9'
@@ -199,111 +202,111 @@
       str = 'abc'
       @prot.write_string(str)
       a = @trans.read(@trans.available)
-      a.encoding.should == Encoding::BINARY
-      a.unpack('C*').should == [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63]
+      expect(a.encoding).to eq(Encoding::BINARY)
+      expect(a.unpack('C*')).to eq([0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63])
     end
 
     it 'should write a string with unicode characters' do
       str = "abc \u20AC \u20AD".encode('UTF-8')
       @prot.write_string(str)
       a = @trans.read(@trans.available)
-      a.encoding.should == Encoding::BINARY
-      a.unpack('C*').should == [0x00, 0x00, 0x00, 0x0B, 0x61, 0x62, 0x63, 0x20,
-                                0xE2, 0x82, 0xAC, 0x20, 0xE2, 0x82, 0xAD]
+      expect(a.encoding).to eq(Encoding::BINARY)
+      expect(a.unpack('C*')).to eq([0x00, 0x00, 0x00, 0x0B, 0x61, 0x62, 0x63, 0x20,
+                                0xE2, 0x82, 0xAC, 0x20, 0xE2, 0x82, 0xAD])
     end
 
     it 'should write should write a string with unicode characters and transcoding' do
       str = "abc \u20AC".encode('ISO-8859-15')
       @prot.write_string(str)
       a = @trans.read(@trans.available)
-      a.encoding.should == Encoding::BINARY
-      a.unpack('C*').should == [0x00, 0x00, 0x00, 0x07, 0x61, 0x62, 0x63, 0x20, 0xE2, 0x82, 0xAC]
+      expect(a.encoding).to eq(Encoding::BINARY)
+      expect(a.unpack('C*')).to eq([0x00, 0x00, 0x00, 0x07, 0x61, 0x62, 0x63, 0x20, 0xE2, 0x82, 0xAC])
     end
 
     it 'should write a binary string' do
       buffer = [0, 1, 2, 3].pack('C*')
       @prot.write_binary(buffer)
       a = @trans.read(@trans.available)
-      a.encoding.should == Encoding::BINARY
-      a.unpack('C*').should == [0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03]
+      expect(a.encoding).to eq(Encoding::BINARY)
+      expect(a.unpack('C*')).to eq([0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03])
     end
   else
     it 'should write a string' do
       str = 'abc'
       @prot.write_string(str)
       a = @trans.read(@trans.available)
-      a.unpack('C*').should == [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63]
+      expect(a.unpack('C*')).to eq([0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63])
     end
 
     it 'should write a binary string' do
       buffer = [0, 1, 2, 3].pack('C*')
       @prot.write_binary(buffer)
       a = @trans.read(@trans.available)
-      a.unpack('C*').should == [0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03]
+      expect(a.unpack('C*')).to eq([0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03])
     end
   end
 
   it "should error gracefully when trying to write a nil string" do
-    lambda { @prot.write_string(nil) }.should raise_error
+    expect { @prot.write_string(nil) }.to raise_error
   end
   
   it "should write the message header without version when writes are not strict" do
     @prot = protocol_class.new(@trans, true, false) # no strict write
     @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
-    @trans.read(@trans.available).should == "\000\000\000\vtestMessage\001\000\000\000\021"
+    expect(@trans.read(@trans.available)).to eq("\000\000\000\vtestMessage\001\000\000\000\021")
   end
     
   it "should write the message header with a version when writes are strict" do
     @prot = protocol_class.new(@trans) # strict write
     @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
-    @trans.read(@trans.available).should == "\200\001\000\001\000\000\000\vtestMessage\000\000\000\021"
+    expect(@trans.read(@trans.available)).to eq("\200\001\000\001\000\000\000\vtestMessage\000\000\000\021")
   end
   
   # message footer is a noop
   
   it "should read a field header" do
     @trans.write([Thrift::Types::STRING, 3].pack("cn"))
-    @prot.read_field_begin.should == [nil, Thrift::Types::STRING, 3]
+    expect(@prot.read_field_begin).to eq([nil, Thrift::Types::STRING, 3])
   end
   
   # field footer is a noop
   
   it "should read a stop field" do
     @trans.write([Thrift::Types::STOP].pack("c"));
-    @prot.read_field_begin.should == [nil, Thrift::Types::STOP, 0]
+    expect(@prot.read_field_begin).to eq([nil, Thrift::Types::STOP, 0])
   end
 
   it "should read a map header" do
     @trans.write([Thrift::Types::DOUBLE, Thrift::Types::I64, 42].pack("ccN"))
-    @prot.read_map_begin.should == [Thrift::Types::DOUBLE, Thrift::Types::I64, 42]
+    expect(@prot.read_map_begin).to eq([Thrift::Types::DOUBLE, Thrift::Types::I64, 42])
   end
   
   # map footer is a noop
   
   it "should read a list header" do
     @trans.write([Thrift::Types::STRING, 17].pack("cN"))
-    @prot.read_list_begin.should == [Thrift::Types::STRING, 17]
+    expect(@prot.read_list_begin).to eq([Thrift::Types::STRING, 17])
   end
   
   # list footer is a noop
   
   it "should read a set header" do
     @trans.write([Thrift::Types::STRING, 17].pack("cN"))
-    @prot.read_set_begin.should == [Thrift::Types::STRING, 17]
+    expect(@prot.read_set_begin).to eq([Thrift::Types::STRING, 17])
   end
   
   # set footer is a noop
   
   it "should read a bool" do
     @trans.write("\001\000");
-    @prot.read_bool.should == true
-    @prot.read_bool.should == false
+    expect(@prot.read_bool).to eq(true)
+    expect(@prot.read_bool).to eq(false)
   end
   
   it "should read a byte" do
     [-128, -57, -3, 0, 17, 24, 127].each do |i|
       @trans.write([i].pack("c"))
-      @prot.read_byte.should == i
+      expect(@prot.read_byte).to eq(i)
     end
   end
   
@@ -311,7 +314,7 @@
     # try a scattering of values, including min/max
     [-2**15, -5237, -353, 0, 1527, 2234, 2**15-1].each do |i|
       @trans.write([i].pack("n"));
-      @prot.read_i16.should == i
+      expect(@prot.read_i16).to eq(i)
     end
   end
   
@@ -319,7 +322,7 @@
     # try a scattering of values, including min/max
     [-2**31, -235125, -6236, 0, 2351, 123123, 2**31-1].each do |i|
       @trans.write([i].pack("N"))
-      @prot.read_i32.should == i
+      expect(@prot.read_i32).to eq(i)
     end
   end
   
@@ -327,7 +330,7 @@
     # try a scattering of values, including min/max
     [-2**63, -123512312, -6346, 0, 32, 2346322323, 2**63-1].each do |i|
       @trans.write([i >> 32, i & 0xFFFFFFFF].pack("NN"))
-      @prot.read_i64.should == i
+      expect(@prot.read_i64).to eq(i)
     end
   end
   
@@ -335,7 +338,7 @@
     # try a random scattering of values, including min/max
     [Float::MIN, -231231.12351, -323.233513, 0, 123.2351235, 2351235.12351235, Float::MAX].each do |f|
       @trans.write([f].pack("G"));
-      @prot.read_double.should == f
+      expect(@prot.read_double).to eq(f)
     end
   end
 
@@ -345,8 +348,8 @@
       buffer = [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63].pack('C*')
       @trans.write(buffer)
       a = @prot.read_string
-      a.should == 'abc'.encode('UTF-8')
-      a.encoding.should == Encoding::UTF_8
+      expect(a).to eq('abc'.encode('UTF-8'))
+      expect(a.encoding).to eq(Encoding::UTF_8)
     end
 
     it 'should read a string containing unicode characters from UTF-8 encoded buffer' do
@@ -354,44 +357,44 @@
       buffer = [0x00, 0x00, 0x00, 0x03, 0xE2, 0x82, 0xAC].pack('C*')
       @trans.write(buffer)
       a = @prot.read_string
-      a.should == "\u20AC".encode('UTF-8')
-      a.encoding.should == Encoding::UTF_8
+      expect(a).to eq("\u20AC".encode('UTF-8'))
+      expect(a.encoding).to eq(Encoding::UTF_8)
     end
 
     it 'should read a binary string' do
       buffer = [0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03].pack('C*')
       @trans.write(buffer)
       a = @prot.read_binary
-      a.should == [0x00, 0x01, 0x02, 0x03].pack('C*')
-      a.encoding.should == Encoding::BINARY
+      expect(a).to eq([0x00, 0x01, 0x02, 0x03].pack('C*'))
+      expect(a.encoding).to eq(Encoding::BINARY)
     end
   else
     it 'should read a string' do
       # i32 of value 3, followed by three characters/UTF-8 bytes 'a', 'b', 'c'
       buffer = [0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63].pack('C*')
       @trans.write(buffer)
-      @prot.read_string.should == 'abc'
+      expect(@prot.read_string).to eq('abc')
     end
 
     it 'should read a binary string' do
       buffer = [0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03].pack('C*')
       @trans.write(buffer)
       a = @prot.read_binary
-      a.should == [0x00, 0x01, 0x02, 0x03].pack('C*')
+      expect(a).to eq([0x00, 0x01, 0x02, 0x03].pack('C*'))
     end
   end
 
   it "should perform a complete rpc with no args or return" do
     srv_test(
       proc {|client| client.send_voidMethod()},
-      proc {|client| client.recv_voidMethod.should == nil}
+      proc {|client| expect(client.recv_voidMethod).to eq(nil)}
     )
   end
 
   it "should perform a complete rpc with a primitive return type" do
     srv_test(
       proc {|client| client.send_primitiveMethod()},
-      proc {|client| client.recv_primitiveMethod.should == 1}
+      proc {|client| expect(client.recv_primitiveMethod).to eq(1)}
     )
   end
 
@@ -402,7 +405,7 @@
         result = client.recv_structMethod
         result.set_byte_map = nil
         result.map_byte_map = nil
-        result.should == Fixtures::COMPACT_PROTOCOL_TEST_STRUCT
+        expect(result).to eq(Fixtures::COMPACT_PROTOCOL_TEST_STRUCT)
       }
     )
   end
@@ -423,9 +426,9 @@
     clientproto = protocol_class.new(clientside)
     serverproto = protocol_class.new(serverside)
 
-    processor = Srv::Processor.new(SrvHandler.new)
+    processor = Thrift::Test::Srv::Processor.new(SrvHandler.new)
 
-    client = Srv::Client.new(clientproto, clientproto)
+    client = Thrift::Test::Srv::Client.new(clientproto, clientproto)
 
     # first block
     firstblock.call(client)
diff --git a/lib/rb/spec/bytes_spec.rb b/lib/rb/spec/bytes_spec.rb
index b82e304..2e8653c 100644
--- a/lib/rb/spec/bytes_spec.rb
+++ b/lib/rb/spec/bytes_spec.rb
@@ -25,33 +25,33 @@
     describe '.empty_byte_buffer' do
       it 'should create an empty buffer' do
         b = Thrift::Bytes.empty_byte_buffer
-        b.length.should == 0
-        b.encoding.should == Encoding::BINARY
+        expect(b.length).to eq(0)
+        expect(b.encoding).to eq(Encoding::BINARY)
       end
 
       it 'should create an empty buffer of given size' do
         b = Thrift::Bytes.empty_byte_buffer 2
-        b.length.should == 2
-        b.getbyte(0).should == 0
-        b.getbyte(1).should == 0
-        b.encoding.should == Encoding::BINARY
+        expect(b.length).to eq(2)
+        expect(b.getbyte(0)).to eq(0)
+        expect(b.getbyte(1)).to eq(0)
+        expect(b.encoding).to eq(Encoding::BINARY)
       end
     end
 
     describe '.force_binary_encoding' do
       it 'should change encoding' do
         e = 'STRING'.encode('UTF-8')
-        e.encoding.should_not == Encoding::BINARY
+        expect(e.encoding).not_to eq(Encoding::BINARY)
         a = Thrift::Bytes.force_binary_encoding e
-        a.encoding.should == Encoding::BINARY
+        expect(a.encoding).to eq(Encoding::BINARY)
       end
     end
 
     describe '.get_string_byte' do
       it 'should get the byte at index' do
         s = "\x41\x42"
-        Thrift::Bytes.get_string_byte(s, 0).should == 0x41
-        Thrift::Bytes.get_string_byte(s, 1).should == 0x42
+        expect(Thrift::Bytes.get_string_byte(s, 0)).to eq(0x41)
+        expect(Thrift::Bytes.get_string_byte(s, 1)).to eq(0x42)
       end
     end
 
@@ -59,42 +59,42 @@
       it 'should set byte value at index' do
         s = "\x41\x42"
         Thrift::Bytes.set_string_byte(s, 0, 0x43)
-        s.getbyte(0).should == 0x43
-        s.should == 'CB'
+        expect(s.getbyte(0)).to eq(0x43)
+        expect(s).to eq('CB')
       end
     end
 
     describe '.convert_to_utf8_byte_buffer' do
       it 'should convert UTF-8 String to byte buffer' do
         e = "\u20AC".encode('UTF-8') # a string with euro sign character U+20AC
-        e.length.should == 1
+        expect(e.length).to eq(1)
 
         a = Thrift::Bytes.convert_to_utf8_byte_buffer e
-        a.encoding.should == Encoding::BINARY
-        a.length.should == 3
-        a.unpack('C*').should == [0xE2, 0x82, 0xAC]
+        expect(a.encoding).to eq(Encoding::BINARY)
+        expect(a.length).to eq(3)
+        expect(a.unpack('C*')).to eq([0xE2, 0x82, 0xAC])
       end
 
       it 'should convert ISO-8859-15 String to UTF-8 byte buffer' do
         # Assumptions
         e = "\u20AC".encode('ISO-8859-15') # a string with euro sign character U+20AC, then converted to ISO-8859-15
-        e.length.should == 1
-        e.unpack('C*').should == [0xA4] # euro sign is a different code point in ISO-8859-15
+        expect(e.length).to eq(1)
+        expect(e.unpack('C*')).to eq([0xA4]) # euro sign is a different code point in ISO-8859-15
 
         a = Thrift::Bytes.convert_to_utf8_byte_buffer e
-        a.encoding.should == Encoding::BINARY
-        a.length.should == 3
-        a.unpack('C*').should == [0xE2, 0x82, 0xAC]
+        expect(a.encoding).to eq(Encoding::BINARY)
+        expect(a.length).to eq(3)
+        expect(a.unpack('C*')).to eq([0xE2, 0x82, 0xAC])
       end
     end
 
     describe '.convert_to_string' do
       it 'should convert UTF-8 byte buffer to a UTF-8 String' do
         e = [0xE2, 0x82, 0xAC].pack("C*")
-        e.encoding.should == Encoding::BINARY
+        expect(e.encoding).to eq(Encoding::BINARY)
         a = Thrift::Bytes.convert_to_string e
-        a.encoding.should == Encoding::UTF_8
-        a.should == "\u20AC"
+        expect(a.encoding).to eq(Encoding::UTF_8)
+        expect(a).to eq("\u20AC")
       end
     end
 
@@ -102,14 +102,14 @@
     describe '.empty_byte_buffer' do
       it 'should create an empty buffer' do
         b = Thrift::Bytes.empty_byte_buffer
-        b.length.should == 0
+        expect(b.length).to eq(0)
       end
 
       it 'should create an empty buffer of given size' do
         b = Thrift::Bytes.empty_byte_buffer 2
-        b.length.should == 2
-        b[0].should == 0
-        b[1].should == 0
+        expect(b.length).to eq(2)
+        expect(b[0]).to eq(0)
+        expect(b[1]).to eq(0)
       end
     end
 
@@ -117,16 +117,16 @@
       it 'should be a no-op' do
         e = 'STRING'
         a = Thrift::Bytes.force_binary_encoding e
-        a.should == e
-        a.should be(e)
+        expect(a).to eq(e)
+        expect(a).to be(e)
       end
     end
 
     describe '.get_string_byte' do
       it 'should get the byte at index' do
         s = "\x41\x42"
-        Thrift::Bytes.get_string_byte(s, 0).should == 0x41
-        Thrift::Bytes.get_string_byte(s, 1).should == 0x42
+        expect(Thrift::Bytes.get_string_byte(s, 0)).to eq(0x41)
+        expect(Thrift::Bytes.get_string_byte(s, 1)).to eq(0x42)
       end
     end
 
@@ -134,8 +134,8 @@
       it 'should set byte value at index' do
         s = "\x41\x42"
         Thrift::Bytes.set_string_byte(s, 0, 0x43)
-        s[0].should == 0x43
-        s.should == 'CB'
+        expect(s[0]).to eq(0x43)
+        expect(s).to eq('CB')
       end
     end
 
@@ -143,8 +143,8 @@
       it 'should be a no-op' do
         e = 'STRING'
         a = Thrift::Bytes.convert_to_utf8_byte_buffer e
-        a.should == e
-        a.should be(e)
+        expect(a).to eq(e)
+        expect(a).to be(e)
       end
     end
 
@@ -152,8 +152,8 @@
       it 'should be a no-op' do
         e = 'STRING'
         a = Thrift::Bytes.convert_to_string e
-        a.should == e
-        a.should be(e)
+        expect(a).to eq(e)
+        expect(a).to be(e)
       end
     end
   end
diff --git a/lib/rb/spec/client_spec.rb b/lib/rb/spec/client_spec.rb
index f8ffe8a..d5d4cee 100644
--- a/lib/rb/spec/client_spec.rb
+++ b/lib/rb/spec/client_spec.rb
@@ -26,74 +26,73 @@
   end
 
   before(:each) do
-    @prot = mock("MockProtocol")
+    @prot = double("MockProtocol")
     @client = ClientSpec.new(@prot)
   end
 
   describe Thrift::Client do
     it "should re-use iprot for oprot if not otherwise specified" do
-      @client.instance_variable_get(:'@iprot').should eql(@prot)
-      @client.instance_variable_get(:'@oprot').should eql(@prot)
+      expect(@client.instance_variable_get(:'@iprot')).to eql(@prot)
+      expect(@client.instance_variable_get(:'@oprot')).to eql(@prot)
     end
 
     it "should send a test message" do
-      @prot.should_receive(:write_message_begin).with('testMessage', Thrift::MessageTypes::CALL, 0)
-      mock_args = mock('#<TestMessage_args:mock>')
-      mock_args.should_receive(:foo=).with('foo')
-      mock_args.should_receive(:bar=).with(42)
-      mock_args.should_receive(:write).with(@prot)
-      @prot.should_receive(:write_message_end)
-      @prot.should_receive(:trans) do
-        mock('trans').tap do |trans|
-          trans.should_receive(:flush)
+      expect(@prot).to receive(:write_message_begin).with('testMessage', Thrift::MessageTypes::CALL, 0)
+      mock_args = double('#<TestMessage_args:mock>')
+      expect(mock_args).to receive(:foo=).with('foo')
+      expect(mock_args).to receive(:bar=).with(42)
+      expect(mock_args).to receive(:write).with(@prot)
+      expect(@prot).to receive(:write_message_end)
+      expect(@prot).to receive(:trans) do
+        double('trans').tap do |trans|
+          expect(trans).to receive(:flush)
         end
       end
-      klass = stub("TestMessage_args", :new => mock_args)
+      klass = double("TestMessage_args", :new => mock_args)
       @client.send_message('testMessage', klass, :foo => 'foo', :bar => 42)
     end
 
     it "should increment the sequence id when sending messages" do
-      pending "it seems sequence ids are completely ignored right now" do
-        @prot.should_receive(:write_message_begin).with('testMessage',  Thrift::MessageTypes::CALL, 0).ordered
-        @prot.should_receive(:write_message_begin).with('testMessage2', Thrift::MessageTypes::CALL, 1).ordered
-        @prot.should_receive(:write_message_begin).with('testMessage3', Thrift::MessageTypes::CALL, 2).ordered
-        @prot.stub!(:write_message_end)
-        @prot.stub!(:trans).and_return mock("trans").as_null_object
-        @client.send_message('testMessage', mock("args class").as_null_object)
-        @client.send_message('testMessage2', mock("args class").as_null_object)
-        @client.send_message('testMessage3', mock("args class").as_null_object)
-      end
+      pending "it seems sequence ids are completely ignored right now"
+      @prot.expect(:write_message_begin).with('testMessage',  Thrift::MessageTypes::CALL, 0).ordered
+      @prot.expect(:write_message_begin).with('testMessage2', Thrift::MessageTypes::CALL, 1).ordered
+      @prot.expect(:write_message_begin).with('testMessage3', Thrift::MessageTypes::CALL, 2).ordered
+      @prot.stub!(:write_message_end)
+      @prot.stub!(:trans).and_return double("trans").as_null_object
+      @client.send_message('testMessage', double("args class").as_null_object)
+      @client.send_message('testMessage2', double("args class").as_null_object)
+      @client.send_message('testMessage3', double("args class").as_null_object)
     end
 
     it "should receive a test message" do
-      @prot.should_receive(:read_message_begin).and_return [nil, Thrift::MessageTypes::CALL, 0]
-      @prot.should_receive(:read_message_end)
-      mock_klass = mock("#<MockClass:mock>")
-      mock_klass.should_receive(:read).with(@prot)
-      @client.receive_message(stub("MockClass", :new => mock_klass))
+      expect(@prot).to receive(:read_message_begin).and_return [nil, Thrift::MessageTypes::CALL, 0]
+      expect(@prot).to receive(:read_message_end)
+      mock_klass = double("#<MockClass:mock>")
+      expect(mock_klass).to receive(:read).with(@prot)
+      @client.receive_message(double("MockClass", :new => mock_klass))
     end
 
     it "should handle received exceptions" do
-      @prot.should_receive(:read_message_begin).and_return [nil, Thrift::MessageTypes::EXCEPTION, 0]
-      @prot.should_receive(:read_message_end)
-      Thrift::ApplicationException.should_receive(:new).and_return do
+      expect(@prot).to receive(:read_message_begin).and_return [nil, Thrift::MessageTypes::EXCEPTION, 0]
+      expect(@prot).to receive(:read_message_end)
+      expect(Thrift::ApplicationException).to receive(:new) do
         StandardError.new.tap do |mock_exc|
-          mock_exc.should_receive(:read).with(@prot)
+          expect(mock_exc).to receive(:read).with(@prot)
         end
       end
-      lambda { @client.receive_message(nil) }.should raise_error(StandardError)
+      expect { @client.receive_message(nil) }.to raise_error(StandardError)
     end
 
     it "should close the transport if an error occurs while sending a message" do
-      @prot.stub!(:write_message_begin)
-      @prot.should_not_receive(:write_message_end)
-      mock_args = mock("#<TestMessage_args:mock>")
-      mock_args.should_receive(:write).with(@prot).and_raise(StandardError)
-      trans = mock("MockTransport")
-      @prot.stub!(:trans).and_return(trans)
-      trans.should_receive(:close)
-      klass = mock("TestMessage_args", :new => mock_args)
-      lambda { @client.send_message("testMessage", klass) }.should raise_error(StandardError)
+      allow(@prot).to receive(:write_message_begin)
+      expect(@prot).not_to receive(:write_message_end)
+      mock_args = double("#<TestMessage_args:mock>")
+      expect(mock_args).to receive(:write).with(@prot).and_raise(StandardError)
+      trans = double("MockTransport")
+      allow(@prot).to receive(:trans).and_return(trans)
+      expect(trans).to receive(:close)
+      klass = double("TestMessage_args", :new => mock_args)
+      expect { @client.send_message("testMessage", klass) }.to raise_error(StandardError)
     end
   end
 end
diff --git a/lib/rb/spec/compact_protocol_spec.rb b/lib/rb/spec/compact_protocol_spec.rb
index daad583..513dd69 100644
--- a/lib/rb/spec/compact_protocol_spec.rb
+++ b/lib/rb/spec/compact_protocol_spec.rb
@@ -42,7 +42,7 @@
         proto.send(writer(primitive_type), value)
         # puts "buf: #{trans.inspect_buffer}" if primitive_type == :i64
         read_back = proto.send(reader(primitive_type))
-        read_back.should == value
+        expect(read_back).to eq(value)
       end
     end
   end
@@ -62,10 +62,10 @@
 
         proto = Thrift::CompactProtocol.new(trans)
         name, type, id = proto.read_field_begin
-        type.should == thrift_type
-        id.should == 15
+        expect(type).to eq(thrift_type)
+        expect(id).to eq(15)
         read_back = proto.send(reader(primitive_type))
-        read_back.should == value
+        expect(read_back).to eq(value)
         proto.read_field_end
       end
     end
@@ -75,13 +75,13 @@
     trans = Thrift::MemoryBufferTransport.new
     proto = Thrift::CompactProtocol.new(trans)
 
-    struct = CompactProtoTestStruct.new
+    struct = Thrift::Test::CompactProtoTestStruct.new
     # sets and maps don't hash well... not sure what to do here.
     struct.write(proto)
 
-    struct2 = CompactProtoTestStruct.new
+    struct2 = Thrift::Test::CompactProtoTestStruct.new
     struct2.read(proto)    
-    struct2.should == struct
+    expect(struct2).to eq(struct)
   end
 
   it "should make method calls correctly" do
@@ -91,19 +91,19 @@
     client_in_trans = Thrift::MemoryBufferTransport.new
     client_in_proto = Thrift::CompactProtocol.new(client_in_trans)
 
-    processor = Srv::Processor.new(JankyHandler.new)
+    processor = Thrift::Test::Srv::Processor.new(JankyHandler.new)
 
-    client = Srv::Client.new(client_in_proto, client_out_proto)
+    client = Thrift::Test::Srv::Client.new(client_in_proto, client_out_proto)
     client.send_Janky(1)
     # puts client_out_trans.inspect_buffer
     processor.process(client_out_proto, client_in_proto)
-    client.recv_Janky.should == 2
+    expect(client.recv_Janky).to eq(2)
   end
   
   it "should deal with fields following fields that have non-delta ids" do
-    brcp = BreaksRubyCompactProtocol.new(
+    brcp = Thrift::Test::BreaksRubyCompactProtocol.new(
       :field1 => "blah", 
-      :field2 => BigFieldIdStruct.new(
+      :field2 => Thrift::Test::BigFieldIdStruct.new(
         :field1 => "string1", 
         :field2 => "string2"), 
       :field3 => 3)
@@ -111,20 +111,25 @@
     bytes = ser.serialize(brcp)
 
     deser = Thrift::Deserializer.new(Thrift::CompactProtocolFactory.new)
-    brcp2 = BreaksRubyCompactProtocol.new
+    brcp2 = Thrift::Test::BreaksRubyCompactProtocol.new
     deser.deserialize(brcp2, bytes)
-    brcp2.should == brcp
+    expect(brcp2).to eq(brcp)
   end
   
   it "should deserialize an empty map to an empty hash" do
-    struct = SingleMapTestStruct.new(:i32_map => {})
+    struct = Thrift::Test::SingleMapTestStruct.new(:i32_map => {})
     ser = Thrift::Serializer.new(Thrift::CompactProtocolFactory.new)
     bytes = ser.serialize(struct)
 
     deser = Thrift::Deserializer.new(Thrift::CompactProtocolFactory.new)
-    struct2 = SingleMapTestStruct.new
+    struct2 = Thrift::Test::SingleMapTestStruct.new
     deser.deserialize(struct2, bytes)
-    struct.should == struct2
+    expect(struct).to eq(struct2)
+  end
+  
+  it "should provide a reasonable to_s" do
+    trans = Thrift::MemoryBufferTransport.new
+    expect(Thrift::CompactProtocol.new(trans).to_s).to eq("compact(memory)")
   end
   
   class JankyHandler
@@ -141,3 +146,13 @@
     "read_#{sym.to_s}"
   end
 end
+
+describe Thrift::CompactProtocolFactory do
+  it "should create a CompactProtocol" do
+    expect(Thrift::CompactProtocolFactory.new.get_protocol(double("MockTransport"))).to be_instance_of(Thrift::CompactProtocol)
+  end
+
+  it "should provide a reasonable to_s" do
+    expect(Thrift::CompactProtocolFactory.new.to_s).to eq("compact")
+  end
+end
diff --git a/lib/rb/spec/exception_spec.rb b/lib/rb/spec/exception_spec.rb
index d1da621..379ae69 100644
--- a/lib/rb/spec/exception_spec.rb
+++ b/lib/rb/spec/exception_spec.rb
@@ -24,107 +24,107 @@
   describe Thrift::Exception do
     it "should have an accessible message" do
       e = Thrift::Exception.new("test message")
-      e.message.should == "test message"
+      expect(e.message).to eq("test message")
     end
   end
 
   describe Thrift::ApplicationException do
     it "should inherit from Thrift::Exception" do
-      Thrift::ApplicationException.superclass.should == Thrift::Exception
+      expect(Thrift::ApplicationException.superclass).to eq(Thrift::Exception)
     end
 
     it "should have an accessible type and message" do
       e = Thrift::ApplicationException.new
-      e.type.should == Thrift::ApplicationException::UNKNOWN
-      e.message.should be_nil
+      expect(e.type).to eq(Thrift::ApplicationException::UNKNOWN)
+      expect(e.message).to be_nil
       e = Thrift::ApplicationException.new(Thrift::ApplicationException::UNKNOWN_METHOD, "test message")
-      e.type.should == Thrift::ApplicationException::UNKNOWN_METHOD
-      e.message.should == "test message"
+      expect(e.type).to eq(Thrift::ApplicationException::UNKNOWN_METHOD)
+      expect(e.message).to eq("test message")
     end
 
     it "should read a struct off of a protocol" do
-      prot = mock("MockProtocol")
-      prot.should_receive(:read_struct_begin).ordered
-      prot.should_receive(:read_field_begin).exactly(3).times.and_return(
+      prot = double("MockProtocol")
+      expect(prot).to receive(:read_struct_begin).ordered
+      expect(prot).to receive(:read_field_begin).exactly(3).times.and_return(
         ["message", Thrift::Types::STRING, 1],
         ["type", Thrift::Types::I32, 2],
         [nil, Thrift::Types::STOP, 0]
       )
-      prot.should_receive(:read_string).ordered.and_return "test message"
-      prot.should_receive(:read_i32).ordered.and_return Thrift::ApplicationException::BAD_SEQUENCE_ID
-      prot.should_receive(:read_field_end).exactly(2).times
-      prot.should_receive(:read_struct_end).ordered
+      expect(prot).to receive(:read_string).ordered.and_return "test message"
+      expect(prot).to receive(:read_i32).ordered.and_return Thrift::ApplicationException::BAD_SEQUENCE_ID
+      expect(prot).to receive(:read_field_end).exactly(2).times
+      expect(prot).to receive(:read_struct_end).ordered
 
       e = Thrift::ApplicationException.new
       e.read(prot)
-      e.message.should == "test message"
-      e.type.should == Thrift::ApplicationException::BAD_SEQUENCE_ID
+      expect(e.message).to eq("test message")
+      expect(e.type).to eq(Thrift::ApplicationException::BAD_SEQUENCE_ID)
     end
 
     it "should skip bad fields when reading a struct" do
-      prot = mock("MockProtocol")
-      prot.should_receive(:read_struct_begin).ordered
-      prot.should_receive(:read_field_begin).exactly(5).times.and_return(
+      prot = double("MockProtocol")
+      expect(prot).to receive(:read_struct_begin).ordered
+      expect(prot).to receive(:read_field_begin).exactly(5).times.and_return(
         ["type", Thrift::Types::I32, 2],
         ["type", Thrift::Types::STRING, 2],
         ["message", Thrift::Types::MAP, 1],
         ["message", Thrift::Types::STRING, 3],
         [nil, Thrift::Types::STOP, 0]
       )
-      prot.should_receive(:read_i32).and_return Thrift::ApplicationException::INVALID_MESSAGE_TYPE
-      prot.should_receive(:skip).with(Thrift::Types::STRING).twice
-      prot.should_receive(:skip).with(Thrift::Types::MAP)
-      prot.should_receive(:read_field_end).exactly(4).times
-      prot.should_receive(:read_struct_end).ordered
+      expect(prot).to receive(:read_i32).and_return Thrift::ApplicationException::INVALID_MESSAGE_TYPE
+      expect(prot).to receive(:skip).with(Thrift::Types::STRING).twice
+      expect(prot).to receive(:skip).with(Thrift::Types::MAP)
+      expect(prot).to receive(:read_field_end).exactly(4).times
+      expect(prot).to receive(:read_struct_end).ordered
 
       e = Thrift::ApplicationException.new
       e.read(prot)
-      e.message.should be_nil
-      e.type.should == Thrift::ApplicationException::INVALID_MESSAGE_TYPE
+      expect(e.message).to be_nil
+      expect(e.type).to eq(Thrift::ApplicationException::INVALID_MESSAGE_TYPE)
     end
 
     it "should write a Thrift::ApplicationException struct to the oprot" do
-      prot = mock("MockProtocol")
-      prot.should_receive(:write_struct_begin).with("Thrift::ApplicationException").ordered
-      prot.should_receive(:write_field_begin).with("message", Thrift::Types::STRING, 1).ordered
-      prot.should_receive(:write_string).with("test message").ordered
-      prot.should_receive(:write_field_begin).with("type", Thrift::Types::I32, 2).ordered
-      prot.should_receive(:write_i32).with(Thrift::ApplicationException::UNKNOWN_METHOD).ordered
-      prot.should_receive(:write_field_end).twice
-      prot.should_receive(:write_field_stop).ordered
-      prot.should_receive(:write_struct_end).ordered
+      prot = double("MockProtocol")
+      expect(prot).to receive(:write_struct_begin).with("Thrift::ApplicationException").ordered
+      expect(prot).to receive(:write_field_begin).with("message", Thrift::Types::STRING, 1).ordered
+      expect(prot).to receive(:write_string).with("test message").ordered
+      expect(prot).to receive(:write_field_begin).with("type", Thrift::Types::I32, 2).ordered
+      expect(prot).to receive(:write_i32).with(Thrift::ApplicationException::UNKNOWN_METHOD).ordered
+      expect(prot).to receive(:write_field_end).twice
+      expect(prot).to receive(:write_field_stop).ordered
+      expect(prot).to receive(:write_struct_end).ordered
 
       e = Thrift::ApplicationException.new(Thrift::ApplicationException::UNKNOWN_METHOD, "test message")
       e.write(prot)
     end
 
     it "should skip nil fields when writing to the oprot" do
-      prot = mock("MockProtocol")
-      prot.should_receive(:write_struct_begin).with("Thrift::ApplicationException").ordered
-      prot.should_receive(:write_field_begin).with("message", Thrift::Types::STRING, 1).ordered
-      prot.should_receive(:write_string).with("test message").ordered
-      prot.should_receive(:write_field_end).ordered
-      prot.should_receive(:write_field_stop).ordered
-      prot.should_receive(:write_struct_end).ordered
+      prot = double("MockProtocol")
+      expect(prot).to receive(:write_struct_begin).with("Thrift::ApplicationException").ordered
+      expect(prot).to receive(:write_field_begin).with("message", Thrift::Types::STRING, 1).ordered
+      expect(prot).to receive(:write_string).with("test message").ordered
+      expect(prot).to receive(:write_field_end).ordered
+      expect(prot).to receive(:write_field_stop).ordered
+      expect(prot).to receive(:write_struct_end).ordered
 
       e = Thrift::ApplicationException.new(nil, "test message")
       e.write(prot)
 
-      prot = mock("MockProtocol")
-      prot.should_receive(:write_struct_begin).with("Thrift::ApplicationException").ordered
-      prot.should_receive(:write_field_begin).with("type", Thrift::Types::I32, 2).ordered
-      prot.should_receive(:write_i32).with(Thrift::ApplicationException::BAD_SEQUENCE_ID).ordered
-      prot.should_receive(:write_field_end).ordered
-      prot.should_receive(:write_field_stop).ordered
-      prot.should_receive(:write_struct_end).ordered
+      prot = double("MockProtocol")
+      expect(prot).to receive(:write_struct_begin).with("Thrift::ApplicationException").ordered
+      expect(prot).to receive(:write_field_begin).with("type", Thrift::Types::I32, 2).ordered
+      expect(prot).to receive(:write_i32).with(Thrift::ApplicationException::BAD_SEQUENCE_ID).ordered
+      expect(prot).to receive(:write_field_end).ordered
+      expect(prot).to receive(:write_field_stop).ordered
+      expect(prot).to receive(:write_struct_end).ordered
 
       e = Thrift::ApplicationException.new(Thrift::ApplicationException::BAD_SEQUENCE_ID)
       e.write(prot)
 
-      prot = mock("MockProtocol")
-      prot.should_receive(:write_struct_begin).with("Thrift::ApplicationException").ordered
-      prot.should_receive(:write_field_stop).ordered
-      prot.should_receive(:write_struct_end).ordered
+      prot = double("MockProtocol")
+      expect(prot).to receive(:write_struct_begin).with("Thrift::ApplicationException").ordered
+      expect(prot).to receive(:write_field_stop).ordered
+      expect(prot).to receive(:write_struct_end).ordered
 
       e = Thrift::ApplicationException.new(nil)
       e.write(prot)
@@ -134,8 +134,8 @@
   describe Thrift::ProtocolException do
     it "should have an accessible type" do
       prot = Thrift::ProtocolException.new(Thrift::ProtocolException::SIZE_LIMIT, "message")
-      prot.type.should == Thrift::ProtocolException::SIZE_LIMIT
-      prot.message.should == "message"
+      expect(prot.type).to eq(Thrift::ProtocolException::SIZE_LIMIT)
+      expect(prot.message).to eq("message")
     end
   end
 end
diff --git a/lib/rb/spec/flat_spec.rb b/lib/rb/spec/flat_spec.rb
new file mode 100644
index 0000000..893056c
--- /dev/null
+++ b/lib/rb/spec/flat_spec.rb
@@ -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.
+#
+
+require 'spec_helper'
+
+describe 'generation' do
+  before do
+    require 'namespaced_nonblocking_service'
+  end
+
+  it "did not generate the wrong files" do
+    prefix = File.expand_path("../gen-rb/flat", __FILE__)
+    ["namespaced_spec_namespace/namespaced_nonblocking_service.rb",
+     "namespaced_spec_namespace/thrift_namespaced_spec_constants.rb",
+     "namespaced_spec_namespace/thrift_namespaced_spec_types.rb",
+     "other_namespace/referenced_constants.rb",
+     "other_namespace/referenced_types.rb"
+    ].each do |name|
+      expect(File.exist?(File.join(prefix, name))).not_to be_truthy
+    end
+  end
+
+  it "generated the right files" do
+    prefix = File.expand_path("../gen-rb/flat", __FILE__)
+    ["namespaced_nonblocking_service.rb",
+     "thrift_namespaced_spec_constants.rb",
+     "thrift_namespaced_spec_types.rb",
+     "referenced_constants.rb",
+     "referenced_types.rb"
+    ].each do |name|
+      expect(File.exist?(File.join(prefix, name))).to be_truthy
+    end
+  end
+
+  it "has a service class in the right place" do
+    expect(defined?(NamespacedSpecNamespace::NamespacedNonblockingService)).to be_truthy
+  end
+
+  it "has a struct in the right place" do
+    expect(defined?(NamespacedSpecNamespace::Hello)).to be_truthy
+  end
+
+  it "required an included file" do
+    expect(defined?(OtherNamespace::SomeEnum)).to be_truthy
+  end
+end
diff --git a/lib/rb/spec/http_client_spec.rb b/lib/rb/spec/http_client_spec.rb
index 793fc73..df472ab 100644
--- a/lib/rb/spec/http_client_spec.rb
+++ b/lib/rb/spec/http_client_spec.rb
@@ -25,28 +25,32 @@
     before(:each) do
       @client = Thrift::HTTPClientTransport.new("http://my.domain.com/path/to/service?param=value")
     end
+    
+    it "should provide a reasonable to_s" do
+      @client.to_s == "http://my.domain.com/path/to/service?param=value"
+    end
 
     it "should always be open" do
-      @client.should be_open
+      expect(@client).to be_open
       @client.close
-      @client.should be_open
+      expect(@client).to be_open
     end
 
     it "should post via HTTP and return the results" do
       @client.write "a test"
       @client.write " frame"
-      Net::HTTP.should_receive(:new).with("my.domain.com", 80).and_return do
-        mock("Net::HTTP").tap do |http|
-          http.should_receive(:use_ssl=).with(false)
-          http.should_receive(:post).with("/path/to/service?param=value", "a test frame", {"Content-Type"=>"application/x-thrift"}).and_return do
-            mock("Net::HTTPOK").tap do |response|
-              response.should_receive(:body).and_return "data"
+      expect(Net::HTTP).to receive(:new).with("my.domain.com", 80) do
+        double("Net::HTTP").tap do |http|
+          expect(http).to receive(:use_ssl=).with(false)
+          expect(http).to receive(:post).with("/path/to/service?param=value", "a test frame", {"Content-Type"=>"application/x-thrift"}) do
+            double("Net::HTTPOK").tap do |response|
+              expect(response).to receive(:body).and_return "data"
             end
           end
         end
       end
       @client.flush
-      @client.read(10).should == "data"
+      expect(@client.read(10)).to eq("data")
     end
 
     it "should send custom headers if defined" do
@@ -55,18 +59,33 @@
       headers = {"Content-Type"=>"application/x-thrift"}.merge(custom_headers)
 
       @client.add_headers(custom_headers)
-      Net::HTTP.should_receive(:new).with("my.domain.com", 80).and_return do
-        mock("Net::HTTP").tap do |http|
-          http.should_receive(:use_ssl=).with(false)
-          http.should_receive(:post).with("/path/to/service?param=value", "test", headers).and_return do
-            mock("Net::HTTPOK").tap do |response|
-              response.should_receive(:body).and_return "data"
+      expect(Net::HTTP).to receive(:new).with("my.domain.com", 80) do
+        double("Net::HTTP").tap do |http|
+          expect(http).to receive(:use_ssl=).with(false)
+          expect(http).to receive(:post).with("/path/to/service?param=value", "test", headers) do
+            double("Net::HTTPOK").tap do |response|
+              expect(response).to receive(:body).and_return "data"
             end
           end
         end
       end
       @client.flush
     end
+
+    it 'should reset the outbuf on HTTP failures' do
+      @client.write "test"
+
+      expect(Net::HTTP).to receive(:new).with("my.domain.com", 80) do
+        double("Net::HTTP").tap do |http|
+          expect(http).to receive(:use_ssl=).with(false)
+          expect(http).to receive(:post).with("/path/to/service?param=value", "test", {"Content-Type"=>"application/x-thrift"}) { raise Net::ReadTimeout }
+        end
+      end
+
+      @client.flush  rescue
+      expect(@client.instance_variable_get(:@outbuf)).to eq(Thrift::Bytes.empty_byte_buffer)
+    end
+
   end
 
   describe 'ssl enabled' do
@@ -80,20 +99,20 @@
 
       client.write "test"
 
-      Net::HTTP.should_receive(:new).with("my.domain.com", 443).and_return do
-        mock("Net::HTTP").tap do |http|
-          http.should_receive(:use_ssl=).with(true)
-          http.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
-          http.should_receive(:post).with(@service_path, "test",
-              "Content-Type" => "application/x-thrift").and_return do
-            mock("Net::HTTPOK").tap do |response|
-              response.should_receive(:body).and_return "data"
+      expect(Net::HTTP).to receive(:new).with("my.domain.com", 443) do
+        double("Net::HTTP").tap do |http|
+          expect(http).to receive(:use_ssl=).with(true)
+          expect(http).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
+          expect(http).to receive(:post).with(@service_path, "test",
+              "Content-Type" => "application/x-thrift") do
+            double("Net::HTTPOK").tap do |response|
+              expect(response).to receive(:body).and_return "data"
             end
           end
         end
       end
       client.flush
-      client.read(4).should == "data"
+      expect(client.read(4)).to eq("data")
     end
 
     it "should set SSL verify mode when specified" do
@@ -101,20 +120,20 @@
           :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE)
 
       client.write "test"
-      Net::HTTP.should_receive(:new).with("my.domain.com", 443).and_return do
-        mock("Net::HTTP").tap do |http|
-          http.should_receive(:use_ssl=).with(true)
-          http.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
-          http.should_receive(:post).with(@service_path, "test",
-              "Content-Type" => "application/x-thrift").and_return do
-            mock("Net::HTTPOK").tap do |response|
-              response.should_receive(:body).and_return "data"
+      expect(Net::HTTP).to receive(:new).with("my.domain.com", 443) do
+        double("Net::HTTP").tap do |http|
+          expect(http).to receive(:use_ssl=).with(true)
+          expect(http).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
+          expect(http).to receive(:post).with(@service_path, "test",
+              "Content-Type" => "application/x-thrift") do
+            double("Net::HTTPOK").tap do |response|
+              expect(response).to receive(:body).and_return "data"
             end
           end
         end
       end
       client.flush
-      client.read(4).should == "data"
+      expect(client.read(4)).to eq("data")
     end
   end
 end
diff --git a/lib/rb/spec/json_protocol_spec.rb b/lib/rb/spec/json_protocol_spec.rb
index 2f7f1e6..fe1af7b 100644
--- a/lib/rb/spec/json_protocol_spec.rb
+++ b/lib/rb/spec/json_protocol_spec.rb
@@ -30,252 +30,257 @@
 
     it "should write json escaped char" do
       @prot.write_json_escape_char("\n")
-      @trans.read(@trans.available).should == '\u000a'
+      expect(@trans.read(@trans.available)).to eq('\u000a')
 
       @prot.write_json_escape_char(" ")
-      @trans.read(@trans.available).should == '\u0020'
+      expect(@trans.read(@trans.available)).to eq('\u0020')
     end
 
     it "should write json char" do
       @prot.write_json_char("\n")
-      @trans.read(@trans.available).should == '\\n'
+      expect(@trans.read(@trans.available)).to eq('\\n')
 
       @prot.write_json_char(" ")
-      @trans.read(@trans.available).should == ' '
+      expect(@trans.read(@trans.available)).to eq(' ')
 
       @prot.write_json_char("\\")
-      @trans.read(@trans.available).should == "\\\\"
+      expect(@trans.read(@trans.available)).to eq("\\\\")
 
       @prot.write_json_char("@")
-      @trans.read(@trans.available).should == '@'
+      expect(@trans.read(@trans.available)).to eq('@')
     end
 
     it "should write json string" do
       @prot.write_json_string("this is a \\ json\nstring")
-      @trans.read(@trans.available).should == "\"this is a \\\\ json\\nstring\""
+      expect(@trans.read(@trans.available)).to eq("\"this is a \\\\ json\\nstring\"")
     end
 
     it "should write json base64" do
       @prot.write_json_base64("this is a base64 string")
-      @trans.read(@trans.available).should == "\"\"dGhpcyBpcyBhIGJhc2U2NCBzdHJpbmc=\\n\"\""
+      expect(@trans.read(@trans.available)).to eq("\"dGhpcyBpcyBhIGJhc2U2NCBzdHJpbmc=\"")
     end
 
     it "should write json integer" do
       @prot.write_json_integer(45)
-      @trans.read(@trans.available).should == "45"
+      expect(@trans.read(@trans.available)).to eq("45")
 
       @prot.write_json_integer(33000)
-      @trans.read(@trans.available).should == "33000"
+      expect(@trans.read(@trans.available)).to eq("33000")
 
       @prot.write_json_integer(3000000000)
-      @trans.read(@trans.available).should == "3000000000"
+      expect(@trans.read(@trans.available)).to eq("3000000000")
 
       @prot.write_json_integer(6000000000)
-      @trans.read(@trans.available).should == "6000000000"
+      expect(@trans.read(@trans.available)).to eq("6000000000")
     end
 
     it "should write json double" do
       @prot.write_json_double(12.3)
-      @trans.read(@trans.available).should == "12.3"
+      expect(@trans.read(@trans.available)).to eq("12.3")
 
       @prot.write_json_double(-3.21)
-      @trans.read(@trans.available).should == "-3.21"
+      expect(@trans.read(@trans.available)).to eq("-3.21")
 
       @prot.write_json_double(((+1.0/0.0)/(+1.0/0.0)))
-      @trans.read(@trans.available).should == "\"NaN\""
+      expect(@trans.read(@trans.available)).to eq("\"NaN\"")
 
       @prot.write_json_double((+1.0/0.0))
-      @trans.read(@trans.available).should == "\"Infinity\""
+      expect(@trans.read(@trans.available)).to eq("\"Infinity\"")
 
       @prot.write_json_double((-1.0/0.0))
-      @trans.read(@trans.available).should == "\"-Infinity\""
+      expect(@trans.read(@trans.available)).to eq("\"-Infinity\"")
     end
 
     it "should write json object start" do
       @prot.write_json_object_start
-      @trans.read(@trans.available).should == "{"
+      expect(@trans.read(@trans.available)).to eq("{")
     end
 
     it "should write json object end" do
       @prot.write_json_object_end
-      @trans.read(@trans.available).should == "}"
+      expect(@trans.read(@trans.available)).to eq("}")
     end
 
     it "should write json array start" do
       @prot.write_json_array_start
-      @trans.read(@trans.available).should == "["
+      expect(@trans.read(@trans.available)).to eq("[")
     end
 
     it "should write json array end" do
       @prot.write_json_array_end
-      @trans.read(@trans.available).should == "]"
+      expect(@trans.read(@trans.available)).to eq("]")
     end
 
     it "should write message begin" do
       @prot.write_message_begin("name", 12, 32)
-      @trans.read(@trans.available).should == "[1,\"name\",12,32"
+      expect(@trans.read(@trans.available)).to eq("[1,\"name\",12,32")
     end
 
     it "should write message end" do
       @prot.write_message_end
-      @trans.read(@trans.available).should == "]"
+      expect(@trans.read(@trans.available)).to eq("]")
     end
 
     it "should write struct begin" do
       @prot.write_struct_begin("name")
-      @trans.read(@trans.available).should == "{"
+      expect(@trans.read(@trans.available)).to eq("{")
     end
 
     it "should write struct end" do
       @prot.write_struct_end
-      @trans.read(@trans.available).should == "}"
+      expect(@trans.read(@trans.available)).to eq("}")
     end
 
     it "should write field begin" do
       @prot.write_field_begin("name", Thrift::Types::STRUCT, 32)
-      @trans.read(@trans.available).should == "32{\"rec\""
+      expect(@trans.read(@trans.available)).to eq("32{\"rec\"")
     end
 
     it "should write field end" do
       @prot.write_field_end
-      @trans.read(@trans.available).should == "}"
+      expect(@trans.read(@trans.available)).to eq("}")
     end
 
     it "should write field stop" do
       @prot.write_field_stop
-      @trans.read(@trans.available).should == ""
+      expect(@trans.read(@trans.available)).to eq("")
     end
 
     it "should write map begin" do
       @prot.write_map_begin(Thrift::Types::STRUCT, Thrift::Types::LIST, 32)
-      @trans.read(@trans.available).should == "[\"rec\",\"lst\",32,{"
+      expect(@trans.read(@trans.available)).to eq("[\"rec\",\"lst\",32,{")
     end
 
     it "should write map end" do
       @prot.write_map_end
-      @trans.read(@trans.available).should == "}]"
+      expect(@trans.read(@trans.available)).to eq("}]")
     end
 
     it "should write list begin" do
       @prot.write_list_begin(Thrift::Types::STRUCT, 32)
-      @trans.read(@trans.available).should == "[\"rec\",32"
+      expect(@trans.read(@trans.available)).to eq("[\"rec\",32")
     end
 
     it "should write list end" do
       @prot.write_list_end
-      @trans.read(@trans.available).should == "]"
+      expect(@trans.read(@trans.available)).to eq("]")
     end
 
     it "should write set begin" do
       @prot.write_set_begin(Thrift::Types::STRUCT, 32)
-      @trans.read(@trans.available).should == "[\"rec\",32"
+      expect(@trans.read(@trans.available)).to eq("[\"rec\",32")
     end
 
     it "should write set end" do
       @prot.write_set_end
-      @trans.read(@trans.available).should == "]"
+      expect(@trans.read(@trans.available)).to eq("]")
     end
 
     it "should write bool" do
       @prot.write_bool(true)
-      @trans.read(@trans.available).should == "1"
+      expect(@trans.read(@trans.available)).to eq("1")
 
       @prot.write_bool(false)
-      @trans.read(@trans.available).should == "0"
+      expect(@trans.read(@trans.available)).to eq("0")
     end
 
     it "should write byte" do
       @prot.write_byte(100)
-      @trans.read(@trans.available).should == "100"
+      expect(@trans.read(@trans.available)).to eq("100")
     end
 
     it "should write i16" do
       @prot.write_i16(1000)
-      @trans.read(@trans.available).should == "1000"
+      expect(@trans.read(@trans.available)).to eq("1000")
     end
 
     it "should write i32" do
       @prot.write_i32(3000000000)
-      @trans.read(@trans.available).should == "3000000000"
+      expect(@trans.read(@trans.available)).to eq("3000000000")
     end
 
     it "should write i64" do
       @prot.write_i64(6000000000)
-      @trans.read(@trans.available).should == "6000000000"
+      expect(@trans.read(@trans.available)).to eq("6000000000")
     end
 
     it "should write double" do
       @prot.write_double(1.23)
-      @trans.read(@trans.available).should == "1.23"
+      expect(@trans.read(@trans.available)).to eq("1.23")
 
       @prot.write_double(-32.1)
-      @trans.read(@trans.available).should == "-32.1"
+      expect(@trans.read(@trans.available)).to eq("-32.1")
 
       @prot.write_double(((+1.0/0.0)/(+1.0/0.0)))
-      @trans.read(@trans.available).should == "\"NaN\""
+      expect(@trans.read(@trans.available)).to eq("\"NaN\"")
 
       @prot.write_double((+1.0/0.0))
-      @trans.read(@trans.available).should == "\"Infinity\""
+      expect(@trans.read(@trans.available)).to eq("\"Infinity\"")
 
       @prot.write_double((-1.0/0.0))
-      @trans.read(@trans.available).should == "\"-Infinity\""
+      expect(@trans.read(@trans.available)).to eq("\"-Infinity\"")
     end
 
     if RUBY_VERSION >= '1.9'
       it 'should write string' do
         @prot.write_string('this is a test string')
         a = @trans.read(@trans.available)
-        a.should == '"this is a test string"'.force_encoding(Encoding::BINARY)
-        a.encoding.should == Encoding::BINARY
+        expect(a).to eq('"this is a test string"'.force_encoding(Encoding::BINARY))
+        expect(a.encoding).to eq(Encoding::BINARY)
       end
 
       it 'should write string with unicode characters' do
         @prot.write_string("this is a test string with unicode characters: \u20AC \u20AD")
         a = @trans.read(@trans.available)
-        a.should == "\"this is a test string with unicode characters: \u20AC \u20AD\"".force_encoding(Encoding::BINARY)
-        a.encoding.should == Encoding::BINARY
+        expect(a).to eq("\"this is a test string with unicode characters: \u20AC \u20AD\"".force_encoding(Encoding::BINARY))
+        expect(a.encoding).to eq(Encoding::BINARY)
       end
     else
       it 'should write string' do
         @prot.write_string('this is a test string')
-        @trans.read(@trans.available).should == '"this is a test string"'
+        expect(@trans.read(@trans.available)).to eq('"this is a test string"')
       end
     end
 
     it "should write binary" do
       @prot.write_binary("this is a base64 string")
-      @trans.read(@trans.available).should == "\"\"dGhpcyBpcyBhIGJhc2U2NCBzdHJpbmc=\\n\"\""
+      expect(@trans.read(@trans.available)).to eq("\"dGhpcyBpcyBhIGJhc2U2NCBzdHJpbmc=\"")
+    end
+
+    it "should write long binary" do
+      @prot.write_binary((0...256).to_a.pack('C*'))
+      expect(@trans.read(@trans.available)).to eq("\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==\"")
     end
 
     it "should get type name for type id" do
       expect {@prot.get_type_name_for_type_id(Thrift::Types::STOP)}.to raise_error(NotImplementedError)
       expect {@prot.get_type_name_for_type_id(Thrift::Types::VOID)}.to raise_error(NotImplementedError)
-      @prot.get_type_name_for_type_id(Thrift::Types::BOOL).should == "tf"
-      @prot.get_type_name_for_type_id(Thrift::Types::BYTE).should == "i8"
-      @prot.get_type_name_for_type_id(Thrift::Types::DOUBLE).should == "dbl"
-      @prot.get_type_name_for_type_id(Thrift::Types::I16).should == "i16"
-      @prot.get_type_name_for_type_id(Thrift::Types::I32).should == "i32"
-      @prot.get_type_name_for_type_id(Thrift::Types::I64).should == "i64"
-      @prot.get_type_name_for_type_id(Thrift::Types::STRING).should == "str"
-      @prot.get_type_name_for_type_id(Thrift::Types::STRUCT).should == "rec"
-      @prot.get_type_name_for_type_id(Thrift::Types::MAP).should == "map"
-      @prot.get_type_name_for_type_id(Thrift::Types::SET).should == "set"
-      @prot.get_type_name_for_type_id(Thrift::Types::LIST).should == "lst"
+      expect(@prot.get_type_name_for_type_id(Thrift::Types::BOOL)).to eq("tf")
+      expect(@prot.get_type_name_for_type_id(Thrift::Types::BYTE)).to eq("i8")
+      expect(@prot.get_type_name_for_type_id(Thrift::Types::DOUBLE)).to eq("dbl")
+      expect(@prot.get_type_name_for_type_id(Thrift::Types::I16)).to eq("i16")
+      expect(@prot.get_type_name_for_type_id(Thrift::Types::I32)).to eq("i32")
+      expect(@prot.get_type_name_for_type_id(Thrift::Types::I64)).to eq("i64")
+      expect(@prot.get_type_name_for_type_id(Thrift::Types::STRING)).to eq("str")
+      expect(@prot.get_type_name_for_type_id(Thrift::Types::STRUCT)).to eq("rec")
+      expect(@prot.get_type_name_for_type_id(Thrift::Types::MAP)).to eq("map")
+      expect(@prot.get_type_name_for_type_id(Thrift::Types::SET)).to eq("set")
+      expect(@prot.get_type_name_for_type_id(Thrift::Types::LIST)).to eq("lst")
     end
 
     it "should get type id for type name" do
       expect {@prot.get_type_id_for_type_name("pp")}.to raise_error(NotImplementedError)
-      @prot.get_type_id_for_type_name("tf").should == Thrift::Types::BOOL
-      @prot.get_type_id_for_type_name("i8").should == Thrift::Types::BYTE
-      @prot.get_type_id_for_type_name("dbl").should == Thrift::Types::DOUBLE
-      @prot.get_type_id_for_type_name("i16").should == Thrift::Types::I16
-      @prot.get_type_id_for_type_name("i32").should == Thrift::Types::I32
-      @prot.get_type_id_for_type_name("i64").should == Thrift::Types::I64
-      @prot.get_type_id_for_type_name("str").should == Thrift::Types::STRING
-      @prot.get_type_id_for_type_name("rec").should == Thrift::Types::STRUCT
-      @prot.get_type_id_for_type_name("map").should == Thrift::Types::MAP
-      @prot.get_type_id_for_type_name("set").should == Thrift::Types::SET
-      @prot.get_type_id_for_type_name("lst").should == Thrift::Types::LIST
+      expect(@prot.get_type_id_for_type_name("tf")).to eq(Thrift::Types::BOOL)
+      expect(@prot.get_type_id_for_type_name("i8")).to eq(Thrift::Types::BYTE)
+      expect(@prot.get_type_id_for_type_name("dbl")).to eq(Thrift::Types::DOUBLE)
+      expect(@prot.get_type_id_for_type_name("i16")).to eq(Thrift::Types::I16)
+      expect(@prot.get_type_id_for_type_name("i32")).to eq(Thrift::Types::I32)
+      expect(@prot.get_type_id_for_type_name("i64")).to eq(Thrift::Types::I64)
+      expect(@prot.get_type_id_for_type_name("str")).to eq(Thrift::Types::STRING)
+      expect(@prot.get_type_id_for_type_name("rec")).to eq(Thrift::Types::STRUCT)
+      expect(@prot.get_type_id_for_type_name("map")).to eq(Thrift::Types::MAP)
+      expect(@prot.get_type_id_for_type_name("set")).to eq(Thrift::Types::SET)
+      expect(@prot.get_type_id_for_type_name("lst")).to eq(Thrift::Types::LIST)
     end
 
     it "should read json syntax char" do
@@ -287,47 +292,68 @@
 
     it "should read json escape char" do
       @trans.write('0054')
-      @prot.read_json_escape_char.should == 'T'
+      expect(@prot.read_json_escape_char).to eq('T')
+
+      @trans.write("\"\\\"\"")
+      expect(@prot.read_json_string(false)).to eq("\"")
+
+      @trans.write("\"\\\\\"")
+      expect(@prot.read_json_string(false)).to eq("\\")
+
+      @trans.write("\"\\/\"")
+      expect(@prot.read_json_string(false)).to eq("\/")
+
+      @trans.write("\"\\b\"")
+      expect(@prot.read_json_string(false)).to eq("\b")
+
+      @trans.write("\"\\f\"")
+      expect(@prot.read_json_string(false)).to eq("\f")
+
+      @trans.write("\"\\n\"")
+      expect(@prot.read_json_string(false)).to eq("\n")
+
+      @trans.write("\"\\r\"")
+      expect(@prot.read_json_string(false)).to eq("\r")
+
+      @trans.write("\"\\t\"")
+      expect(@prot.read_json_string(false)).to eq("\t")
     end
 
     it "should read json string" do
       @trans.write("\"\\P")
       expect {@prot.read_json_string(false)}.to raise_error(Thrift::ProtocolException)
 
-      @trans.write("\"\\n\"")
-      @prot.read_json_string(false).should == "\\n"
-
       @trans.write("\"this is a test string\"")
-      @prot.read_json_string.should == "this is a test string"
+      expect(@prot.read_json_string).to eq("this is a test string")
     end
 
     it "should read json base64" do
       @trans.write("\"dGhpcyBpcyBhIHRlc3Qgc3RyaW5n\"")
-      @prot.read_json_base64.should == "this is a test string"
+      expect(@prot.read_json_base64).to eq("this is a test string")
     end
 
     it "should is json numeric" do
-      @prot.is_json_numeric("A").should == false
-      @prot.is_json_numeric("+").should == true
-      @prot.is_json_numeric("-").should == true
-      @prot.is_json_numeric(".").should == true
-      @prot.is_json_numeric("0").should == true
-      @prot.is_json_numeric("1").should == true
-      @prot.is_json_numeric("2").should == true
-      @prot.is_json_numeric("3").should == true
-      @prot.is_json_numeric("4").should == true
-      @prot.is_json_numeric("5").should == true
-      @prot.is_json_numeric("6").should == true
-      @prot.is_json_numeric("7").should == true
-      @prot.is_json_numeric("8").should == true
-      @prot.is_json_numeric("9").should == true
-      @prot.is_json_numeric("E").should == true
-      @prot.is_json_numeric("e").should == true
+      expect(@prot.is_json_numeric("A")).to eq(false)
+      expect(@prot.is_json_numeric("+")).to eq(true)
+      expect(@prot.is_json_numeric("-")).to eq(true)
+      expect(@prot.is_json_numeric(".")).to eq(true)
+      expect(@prot.is_json_numeric("0")).to eq(true)
+      expect(@prot.is_json_numeric("1")).to eq(true)
+      expect(@prot.is_json_numeric("2")).to eq(true)
+      expect(@prot.is_json_numeric("3")).to eq(true)
+      expect(@prot.is_json_numeric("4")).to eq(true)
+      expect(@prot.is_json_numeric("5")).to eq(true)
+      expect(@prot.is_json_numeric("6")).to eq(true)
+      expect(@prot.is_json_numeric("7")).to eq(true)
+      expect(@prot.is_json_numeric("8")).to eq(true)
+      expect(@prot.is_json_numeric("9")).to eq(true)
+      expect(@prot.is_json_numeric("E")).to eq(true)
+      expect(@prot.is_json_numeric("e")).to eq(true)
     end
 
     it "should read json numeric chars" do
       @trans.write("1.453E45T")
-      @prot.read_json_numeric_chars.should == "1.453E45"
+      expect(@prot.read_json_numeric_chars).to eq("1.453E45")
     end
 
     it "should read json integer" do
@@ -336,7 +362,7 @@
       @prot.read_string
 
       @trans.write("1453T")
-      @prot.read_json_integer.should == 1453
+      expect(@prot.read_json_integer).to eq(1453)
     end
 
     it "should read json double" do
@@ -348,37 +374,37 @@
       expect {@prot.read_json_double}.to raise_error(Thrift::ProtocolException)
 
       @trans.write("1.453e01\"\"")
-      @prot.read_json_double.should == 14.53
+      expect(@prot.read_json_double).to eq(14.53)
       @prot.read_string
 
       @trans.write("\"NaN\"")
-      @prot.read_json_double.nan?.should == true
+      expect(@prot.read_json_double.nan?).to eq(true)
 
       @trans.write("\"Infinity\"")
-      @prot.read_json_double.should == +1.0/0.0
+      expect(@prot.read_json_double).to eq(+1.0/0.0)
 
       @trans.write("\"-Infinity\"")
-      @prot.read_json_double.should == -1.0/0.0
+      expect(@prot.read_json_double).to eq(-1.0/0.0)
     end
 
     it "should read json object start" do
       @trans.write("{")
-      @prot.read_json_object_start.should == nil
+      expect(@prot.read_json_object_start).to eq(nil)
     end
 
     it "should read json object end" do
       @trans.write("}")
-      @prot.read_json_object_end.should == nil
+      expect(@prot.read_json_object_end).to eq(nil)
     end
 
     it "should read json array start" do
       @trans.write("[")
-      @prot.read_json_array_start.should == nil
+      expect(@prot.read_json_array_start).to eq(nil)
     end
 
     it "should read json array end" do
       @trans.write("]")
-      @prot.read_json_array_end.should == nil
+      expect(@prot.read_json_array_end).to eq(nil)
     end
 
     it "should read_message_begin" do
@@ -386,128 +412,141 @@
       expect {@prot.read_message_begin}.to raise_error(Thrift::ProtocolException)
 
       @trans.write("[1,\"name\",12,32\"\"")
-      @prot.read_message_begin.should == ["name", 12, 32]
+      expect(@prot.read_message_begin).to eq(["name", 12, 32])
     end
 
     it "should read message end" do
       @trans.write("]")
-      @prot.read_message_end.should == nil
+      expect(@prot.read_message_end).to eq(nil)
     end
 
     it "should read struct begin" do
       @trans.write("{")
-      @prot.read_struct_begin.should == nil
+      expect(@prot.read_struct_begin).to eq(nil)
     end
 
     it "should read struct end" do
       @trans.write("}")
-      @prot.read_struct_end.should == nil
+      expect(@prot.read_struct_end).to eq(nil)
     end
 
     it "should read field begin" do
       @trans.write("1{\"rec\"")
-      @prot.read_field_begin.should == [nil, 12, 1]
+      expect(@prot.read_field_begin).to eq([nil, 12, 1])
     end
 
     it "should read field end" do
       @trans.write("}")
-      @prot.read_field_end.should == nil
+      expect(@prot.read_field_end).to eq(nil)
     end
 
     it "should read map begin" do
       @trans.write("[\"rec\",\"lst\",2,{")
-      @prot.read_map_begin.should == [12, 15, 2]
+      expect(@prot.read_map_begin).to eq([12, 15, 2])
     end
 
     it "should read map end" do
       @trans.write("}]")
-      @prot.read_map_end.should == nil
+      expect(@prot.read_map_end).to eq(nil)
     end
 
     it "should read list begin" do
       @trans.write("[\"rec\",2\"\"")
-      @prot.read_list_begin.should == [12, 2]
+      expect(@prot.read_list_begin).to eq([12, 2])
     end
 
     it "should read list end" do
       @trans.write("]")
-      @prot.read_list_end.should == nil
+      expect(@prot.read_list_end).to eq(nil)
     end
 
     it "should read set begin" do
       @trans.write("[\"rec\",2\"\"")
-      @prot.read_set_begin.should == [12, 2]
+      expect(@prot.read_set_begin).to eq([12, 2])
     end
 
     it "should read set end" do
       @trans.write("]")
-      @prot.read_set_end.should == nil
+      expect(@prot.read_set_end).to eq(nil)
     end
 
     it "should read bool" do
       @trans.write("0\"\"")
-      @prot.read_bool.should == false
+      expect(@prot.read_bool).to eq(false)
       @prot.read_string
 
       @trans.write("1\"\"")
-      @prot.read_bool.should == true
+      expect(@prot.read_bool).to eq(true)
     end
 
     it "should read byte" do
       @trans.write("60\"\"")
-      @prot.read_byte.should == 60
+      expect(@prot.read_byte).to eq(60)
     end
 
     it "should read i16" do
       @trans.write("1000\"\"")
-      @prot.read_i16.should == 1000
+      expect(@prot.read_i16).to eq(1000)
     end
 
     it "should read i32" do
       @trans.write("3000000000\"\"")
-      @prot.read_i32.should == 3000000000
+      expect(@prot.read_i32).to eq(3000000000)
     end
 
     it "should read i64" do
       @trans.write("6000000000\"\"")
-      @prot.read_i64.should == 6000000000
+      expect(@prot.read_i64).to eq(6000000000)
     end
 
     it "should read double" do
       @trans.write("12.23\"\"")
-      @prot.read_double.should == 12.23
+      expect(@prot.read_double).to eq(12.23)
     end
 
     if RUBY_VERSION >= '1.9'
       it 'should read string' do
         @trans.write('"this is a test string"'.force_encoding(Encoding::BINARY))
         a = @prot.read_string
-        a.should == 'this is a test string'
-        a.encoding.should == Encoding::UTF_8
+        expect(a).to eq('this is a test string')
+        expect(a.encoding).to eq(Encoding::UTF_8)
       end
 
       it 'should read string with unicode characters' do
         @trans.write('"this is a test string with unicode characters: \u20AC \u20AD"'.force_encoding(Encoding::BINARY))
         a = @prot.read_string
-        a.should == "this is a test string with unicode characters: \u20AC \u20AD"
-        a.encoding.should == Encoding::UTF_8
+        expect(a).to eq("this is a test string with unicode characters: \u20AC \u20AD")
+        expect(a.encoding).to eq(Encoding::UTF_8)
       end
     else
       it 'should read string' do
         @trans.write('"this is a test string"')
-        @prot.read_string.should == 'this is a test string'
+        expect(@prot.read_string).to eq('this is a test string')
       end
     end
 
     it "should read binary" do
       @trans.write("\"dGhpcyBpcyBhIHRlc3Qgc3RyaW5n\"")
-      @prot.read_binary.should == "this is a test string"
+      expect(@prot.read_binary).to eq("this is a test string")
+    end
+
+    it "should read long binary" do
+      @trans.write("\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==\"")
+      expect(@prot.read_binary.bytes.to_a).to eq((0...256).to_a)
+    end
+  
+    it "should provide a reasonable to_s" do
+      expect(@prot.to_s).to eq("json(memory)")
     end
   end
 
   describe Thrift::JsonProtocolFactory do
     it "should create a JsonProtocol" do
-      Thrift::JsonProtocolFactory.new.get_protocol(mock("MockTransport")).should be_instance_of(Thrift::JsonProtocol)
+      expect(Thrift::JsonProtocolFactory.new.get_protocol(double("MockTransport"))).to be_instance_of(Thrift::JsonProtocol)
+    end
+
+    it "should provide a reasonable to_s" do
+      expect(Thrift::JsonProtocolFactory.new.to_s).to eq("json")
     end
   end
 end
diff --git a/lib/rb/spec/namespaced_spec.rb b/lib/rb/spec/namespaced_spec.rb
new file mode 100644
index 0000000..4d6d369
--- /dev/null
+++ b/lib/rb/spec/namespaced_spec.rb
@@ -0,0 +1,67 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'spec_helper'
+
+describe 'namespaced generation' do
+  before do
+    require 'namespaced_spec_namespace/namespaced_nonblocking_service'
+  end
+
+  it "generated the right files" do
+    prefix = File.expand_path("../gen-rb", __FILE__)
+    ["namespaced_spec_namespace/namespaced_nonblocking_service.rb",
+     "namespaced_spec_namespace/thrift_namespaced_spec_constants.rb",
+     "namespaced_spec_namespace/thrift_namespaced_spec_types.rb",
+     "other_namespace/referenced_constants.rb",
+     "other_namespace/referenced_types.rb"
+    ].each do |name|
+      expect(File.exist?(File.join(prefix, name))).to be_truthy
+    end
+  end
+
+  it "did not generate the wrong files" do
+    prefix = File.expand_path("../gen-rb", __FILE__)
+    ["namespaced_nonblocking_service.rb",
+     "thrift_namespaced_spec_constants.rb",
+     "thrift_namespaced_spec_types.rb",
+     "referenced_constants.rb",
+     "referenced_types.rb"
+    ].each do |name|
+      expect(File.exist?(File.join(prefix, name))).not_to be_truthy
+    end
+  end
+
+  it "has a service class in the right place" do
+    expect(defined?(NamespacedSpecNamespace::NamespacedNonblockingService)).to be_truthy
+  end
+
+  it "has a struct in the right place" do
+    expect(defined?(NamespacedSpecNamespace::Hello)).to be_truthy
+  end
+
+  it "required an included file" do
+    expect(defined?(OtherNamespace::SomeEnum)).to be_truthy
+  end
+
+  it "extended a service" do
+    require "extended/extended_service"
+  end
+
+end
diff --git a/lib/rb/spec/nonblocking_server_spec.rb b/lib/rb/spec/nonblocking_server_spec.rb
index 712cf45..613d883 100644
--- a/lib/rb/spec/nonblocking_server_spec.rb
+++ b/lib/rb/spec/nonblocking_server_spec.rb
@@ -176,8 +176,8 @@
 
     it "should handle basic message passing" do
       client = setup_client
-      client.greeting(true).should == SpecNamespace::Hello.new
-      client.greeting(false).should == SpecNamespace::Hello.new(:greeting => 'Aloha!')
+      expect(client.greeting(true)).to eq(SpecNamespace::Hello.new)
+      expect(client.greeting(false)).to eq(SpecNamespace::Hello.new(:greeting => 'Aloha!'))
       @server.shutdown
     end
 
@@ -195,7 +195,7 @@
       end
       4.times { trans_queue.pop }
       setup_client.unblock(4)
-      4.times { queue.pop.should be_true }
+      4.times { expect(queue.pop).to be_truthy }
       @server.shutdown
     end
 
@@ -212,15 +212,15 @@
       queues[4] << :hello
       queues[5] << :hello
       queues[6] << :hello
-      3.times { result.pop.should == SpecNamespace::Hello.new }
-      client.greeting(true).should == SpecNamespace::Hello.new
+      3.times { expect(result.pop).to eq(SpecNamespace::Hello.new) }
+      expect(client.greeting(true)).to eq(SpecNamespace::Hello.new)
       queues[5] << [:unblock, 4]
-      4.times { result.pop.should be_true }
+      4.times { expect(result.pop).to be_truthy }
       queues[2] << :hello
-      result.pop.should == SpecNamespace::Hello.new
-      client.greeting(false).should == SpecNamespace::Hello.new(:greeting => 'Aloha!')
+      expect(result.pop).to eq(SpecNamespace::Hello.new)
+      expect(client.greeting(false)).to eq(SpecNamespace::Hello.new(:greeting => 'Aloha!'))
       7.times { queues.shift << :exit }
-      client.greeting(true).should == SpecNamespace::Hello.new
+      expect(client.greeting(true)).to eq(SpecNamespace::Hello.new)
       @server.shutdown
     end
 
@@ -229,7 +229,7 @@
       client = setup_client
       client.greeting(false) # force a message pass
       @server.shutdown
-      @server_thread.join(2).should be_an_instance_of(Thread)
+      expect(@server_thread.join(2)).to be_an_instance_of(Thread)
     end
 
     it "should continue processing active messages when shutting down" do
@@ -238,8 +238,8 @@
       client << :sleep
       sleep 0.1 # give the server time to start processing the client's message
       @server.shutdown
-      @server_thread.join(2).should be_an_instance_of(Thread)
-      result.pop.should == :slept
+      expect(@server_thread.join(2)).to be_an_instance_of(Thread)
+      expect(result.pop).to eq(:slept)
     end
 
     it "should kill active messages when they don't expire while shutting down" do
@@ -249,15 +249,15 @@
       sleep 0.1 # start processing the client's message
       @server.shutdown(1)
       @catch_exceptions = true
-      @server_thread.join(3).should_not be_nil
-      result.should be_empty
+      expect(@server_thread.join(3)).not_to be_nil
+      expect(result).to be_empty
     end
 
     it "should allow shutting down in response to a message" do
       client = setup_client
-      client.greeting(true).should == SpecNamespace::Hello.new
+      expect(client.greeting(true)).to eq(SpecNamespace::Hello.new)
       client.shutdown
-      @server_thread.join(2).should_not be_nil
+      expect(@server_thread.join(2)).not_to be_nil
     end
   end
 end
diff --git a/lib/rb/spec/processor_spec.rb b/lib/rb/spec/processor_spec.rb
index 989f5cc..d30553f 100644
--- a/lib/rb/spec/processor_spec.rb
+++ b/lib/rb/spec/processor_spec.rb
@@ -27,52 +27,52 @@
 
   describe Thrift::Processor do
     before(:each) do
-      @processor = ProcessorSpec.new(mock("MockHandler"))
-      @prot = mock("MockProtocol")
+      @processor = ProcessorSpec.new(double("MockHandler"))
+      @prot = double("MockProtocol")
     end
 
     def mock_trans(obj)
-      obj.should_receive(:trans).ordered.and_return do
-        mock("trans").tap do |trans|
-          trans.should_receive(:flush).ordered
+      expect(obj).to receive(:trans).ordered do
+        double("trans").tap do |trans|
+          expect(trans).to receive(:flush).ordered
         end
       end
     end
 
     it "should call process_<message> when it receives that message" do
-      @prot.should_receive(:read_message_begin).ordered.and_return ['testMessage', Thrift::MessageTypes::CALL, 17]
-      @processor.should_receive(:process_testMessage).with(17, @prot, @prot).ordered
-      @processor.process(@prot, @prot).should == true
+      expect(@prot).to receive(:read_message_begin).ordered.and_return ['testMessage', Thrift::MessageTypes::CALL, 17]
+      expect(@processor).to receive(:process_testMessage).with(17, @prot, @prot).ordered
+      expect(@processor.process(@prot, @prot)).to eq(true)
     end
 
     it "should raise an ApplicationException when the received message cannot be processed" do
-      @prot.should_receive(:read_message_begin).ordered.and_return ['testMessage', Thrift::MessageTypes::CALL, 4]
-      @prot.should_receive(:skip).with(Thrift::Types::STRUCT).ordered
-      @prot.should_receive(:read_message_end).ordered
-      @prot.should_receive(:write_message_begin).with('testMessage', Thrift::MessageTypes::EXCEPTION, 4).ordered
-      e = mock(Thrift::ApplicationException)
-      e.should_receive(:write).with(@prot).ordered
-      Thrift::ApplicationException.should_receive(:new).with(Thrift::ApplicationException::UNKNOWN_METHOD, "Unknown function testMessage").and_return(e)
-      @prot.should_receive(:write_message_end).ordered
+      expect(@prot).to receive(:read_message_begin).ordered.and_return ['testMessage', Thrift::MessageTypes::CALL, 4]
+      expect(@prot).to receive(:skip).with(Thrift::Types::STRUCT).ordered
+      expect(@prot).to receive(:read_message_end).ordered
+      expect(@prot).to receive(:write_message_begin).with('testMessage', Thrift::MessageTypes::EXCEPTION, 4).ordered
+      e = double(Thrift::ApplicationException)
+      expect(e).to receive(:write).with(@prot).ordered
+      expect(Thrift::ApplicationException).to receive(:new).with(Thrift::ApplicationException::UNKNOWN_METHOD, "Unknown function testMessage").and_return(e)
+      expect(@prot).to receive(:write_message_end).ordered
       mock_trans(@prot)
       @processor.process(@prot, @prot)
     end
 
     it "should pass args off to the args class" do
-      args_class = mock("MockArgsClass")
-      args = mock("#<MockArgsClass:mock>").tap do |args|
-        args.should_receive(:read).with(@prot).ordered
+      args_class = double("MockArgsClass")
+      args = double("#<MockArgsClass:mock>").tap do |args|
+        expect(args).to receive(:read).with(@prot).ordered
       end
-      args_class.should_receive(:new).and_return args
-      @prot.should_receive(:read_message_end).ordered
-      @processor.read_args(@prot, args_class).should eql(args)
+      expect(args_class).to receive(:new).and_return args
+      expect(@prot).to receive(:read_message_end).ordered
+      expect(@processor.read_args(@prot, args_class)).to eql(args)
     end
 
     it "should write out a reply when asked" do
-      @prot.should_receive(:write_message_begin).with('testMessage', Thrift::MessageTypes::REPLY, 23).ordered
-      result = mock("MockResult")
-      result.should_receive(:write).with(@prot).ordered
-      @prot.should_receive(:write_message_end).ordered
+      expect(@prot).to receive(:write_message_begin).with('testMessage', Thrift::MessageTypes::REPLY, 23).ordered
+      result = double("MockResult")
+      expect(result).to receive(:write).with(@prot).ordered
+      expect(@prot).to receive(:write_message_end).ordered
       mock_trans(@prot)
       @processor.write_result(result, @prot, 'testMessage', 23)
     end
diff --git a/lib/rb/spec/serializer_spec.rb b/lib/rb/spec/serializer_spec.rb
index 599b454..2a7dc6d 100644
--- a/lib/rb/spec/serializer_spec.rb
+++ b/lib/rb/spec/serializer_spec.rb
@@ -25,19 +25,19 @@
     it "should serialize structs to binary by default" do
       serializer = Thrift::Serializer.new(Thrift::BinaryProtocolAcceleratedFactory.new)
       data = serializer.serialize(SpecNamespace::Hello.new(:greeting => "'Ello guv'nor!"))
-      data.should == "\x0B\x00\x01\x00\x00\x00\x0E'Ello guv'nor!\x00"
+      expect(data).to eq("\x0B\x00\x01\x00\x00\x00\x0E'Ello guv'nor!\x00")
     end
 
     it "should serialize structs to the given protocol" do
-      protocol = Thrift::BaseProtocol.new(mock("transport"))
-      protocol.should_receive(:write_struct_begin).with("SpecNamespace::Hello")
-      protocol.should_receive(:write_field_begin).with("greeting", Thrift::Types::STRING, 1)
-      protocol.should_receive(:write_string).with("Good day")
-      protocol.should_receive(:write_field_end)
-      protocol.should_receive(:write_field_stop)
-      protocol.should_receive(:write_struct_end)
-      protocol_factory = mock("ProtocolFactory")
-      protocol_factory.stub!(:get_protocol).and_return(protocol)
+      protocol = Thrift::BaseProtocol.new(double("transport"))
+      expect(protocol).to receive(:write_struct_begin).with("SpecNamespace::Hello")
+      expect(protocol).to receive(:write_field_begin).with("greeting", Thrift::Types::STRING, 1)
+      expect(protocol).to receive(:write_string).with("Good day")
+      expect(protocol).to receive(:write_field_end)
+      expect(protocol).to receive(:write_field_stop)
+      expect(protocol).to receive(:write_struct_end)
+      protocol_factory = double("ProtocolFactory")
+      allow(protocol_factory).to receive(:get_protocol).and_return(protocol)
       serializer = Thrift::Serializer.new(protocol_factory)
       serializer.serialize(SpecNamespace::Hello.new(:greeting => "Good day"))
     end
@@ -47,21 +47,21 @@
     it "should deserialize structs from binary by default" do
       deserializer = Thrift::Deserializer.new
       data = "\x0B\x00\x01\x00\x00\x00\x0E'Ello guv'nor!\x00"
-      deserializer.deserialize(SpecNamespace::Hello.new, data).should == SpecNamespace::Hello.new(:greeting => "'Ello guv'nor!")
+      expect(deserializer.deserialize(SpecNamespace::Hello.new, data)).to eq(SpecNamespace::Hello.new(:greeting => "'Ello guv'nor!"))
     end
 
     it "should deserialize structs from the given protocol" do
-      protocol = Thrift::BaseProtocol.new(mock("transport"))
-      protocol.should_receive(:read_struct_begin).and_return("SpecNamespace::Hello")
-      protocol.should_receive(:read_field_begin).and_return(["greeting", Thrift::Types::STRING, 1],
+      protocol = Thrift::BaseProtocol.new(double("transport"))
+      expect(protocol).to receive(:read_struct_begin).and_return("SpecNamespace::Hello")
+      expect(protocol).to receive(:read_field_begin).and_return(["greeting", Thrift::Types::STRING, 1],
                                                             [nil, Thrift::Types::STOP, 0])
-      protocol.should_receive(:read_string).and_return("Good day")
-      protocol.should_receive(:read_field_end)
-      protocol.should_receive(:read_struct_end)
-      protocol_factory = mock("ProtocolFactory")
-      protocol_factory.stub!(:get_protocol).and_return(protocol)
+      expect(protocol).to receive(:read_string).and_return("Good day")
+      expect(protocol).to receive(:read_field_end)
+      expect(protocol).to receive(:read_struct_end)
+      protocol_factory = double("ProtocolFactory")
+      allow(protocol_factory).to receive(:get_protocol).and_return(protocol)
       deserializer = Thrift::Deserializer.new(protocol_factory)
-      deserializer.deserialize(SpecNamespace::Hello.new, "").should == SpecNamespace::Hello.new(:greeting => "Good day")
+      expect(deserializer.deserialize(SpecNamespace::Hello.new, "")).to eq(SpecNamespace::Hello.new(:greeting => "Good day"))
     end
   end
 end
diff --git a/lib/rb/spec/server_socket_spec.rb b/lib/rb/spec/server_socket_spec.rb
index 1301d54..ec9e550 100644
--- a/lib/rb/spec/server_socket_spec.rb
+++ b/lib/rb/spec/server_socket_spec.rb
@@ -28,52 +28,57 @@
     end
 
     it "should create a handle when calling listen" do
-      TCPServer.should_receive(:new).with(nil, 1234)
+      expect(TCPServer).to receive(:new).with(nil, 1234)
       @socket.listen
     end
 
     it "should accept an optional host argument" do
       @socket = Thrift::ServerSocket.new('localhost', 1234)
-      TCPServer.should_receive(:new).with('localhost', 1234)
+      expect(TCPServer).to receive(:new).with('localhost', 1234)
+      @socket.to_s == "server(localhost:1234)"
       @socket.listen
     end
 
     it "should create a Thrift::Socket to wrap accepted sockets" do
-      handle = mock("TCPServer")
-      TCPServer.should_receive(:new).with(nil, 1234).and_return(handle)
+      handle = double("TCPServer")
+      expect(TCPServer).to receive(:new).with(nil, 1234).and_return(handle)
       @socket.listen
-      sock = mock("sock")
-      handle.should_receive(:accept).and_return(sock)
-      trans = mock("Socket")
-      Thrift::Socket.should_receive(:new).and_return(trans)
-      trans.should_receive(:handle=).with(sock)
-      @socket.accept.should == trans
+      sock = double("sock")
+      expect(handle).to receive(:accept).and_return(sock)
+      trans = double("Socket")
+      expect(Thrift::Socket).to receive(:new).and_return(trans)
+      expect(trans).to receive(:handle=).with(sock)
+      expect(@socket.accept).to eq(trans)
     end
 
     it "should close the handle when closed" do
-      handle = mock("TCPServer", :closed? => false)
-      TCPServer.should_receive(:new).with(nil, 1234).and_return(handle)
+      handle = double("TCPServer", :closed? => false)
+      expect(TCPServer).to receive(:new).with(nil, 1234).and_return(handle)
       @socket.listen
-      handle.should_receive(:close)
+      expect(handle).to receive(:close)
       @socket.close
     end
 
     it "should return nil when accepting if there is no handle" do
-      @socket.accept.should be_nil
+      expect(@socket.accept).to be_nil
     end
 
     it "should return true for closed? when appropriate" do
-      handle = mock("TCPServer", :closed? => false)
-      TCPServer.stub!(:new).and_return(handle)
+      handle = double("TCPServer", :closed? => false)
+      allow(TCPServer).to receive(:new).and_return(handle)
       @socket.listen
-      @socket.should_not be_closed
-      handle.stub!(:close)
+      expect(@socket).not_to be_closed
+      allow(handle).to receive(:close)
       @socket.close
-      @socket.should be_closed
+      expect(@socket).to be_closed
       @socket.listen
-      @socket.should_not be_closed
-      handle.stub!(:closed?).and_return(true)
-      @socket.should be_closed
+      expect(@socket).not_to be_closed
+      allow(handle).to receive(:closed?).and_return(true)
+      expect(@socket).to be_closed
+    end
+
+    it "should provide a reasonable to_s" do
+      expect(@socket.to_s).to eq("socket(:1234)")
     end
   end
 end
diff --git a/lib/rb/spec/server_spec.rb b/lib/rb/spec/server_spec.rb
index eaecbda..57f5237 100644
--- a/lib/rb/spec/server_spec.rb
+++ b/lib/rb/spec/server_spec.rb
@@ -21,95 +21,135 @@
 describe 'Server' do
 
   describe Thrift::BaseServer do
-    it "should default to BaseTransportFactory and BinaryProtocolFactory when not specified" do
-      server = Thrift::BaseServer.new(mock("Processor"), mock("BaseServerTransport"))
-      server.instance_variable_get(:'@transport_factory').should be_an_instance_of(Thrift::BaseTransportFactory)
-      server.instance_variable_get(:'@protocol_factory').should be_an_instance_of(Thrift::BinaryProtocolFactory)
+    before(:each) do
+      @processor = double("Processor")
+      @serverTrans = double("ServerTransport")
+      @trans = double("BaseTransport")
+      @prot = double("BaseProtocol")
+      @server = described_class.new(@processor, @serverTrans, @trans, @prot)
     end
 
-    # serve is a noop, so can't test that
+    it "should default to BaseTransportFactory and BinaryProtocolFactory when not specified" do
+      @server = Thrift::BaseServer.new(double("Processor"), double("BaseServerTransport"))
+      expect(@server.instance_variable_get(:'@transport_factory')).to be_an_instance_of(Thrift::BaseTransportFactory)
+      expect(@server.instance_variable_get(:'@protocol_factory')).to be_an_instance_of(Thrift::BinaryProtocolFactory)
+    end
+
+    it "should not serve" do
+      expect { @server.serve()}.to raise_error(NotImplementedError)
+    end
+    
+    it "should provide a reasonable to_s" do
+      expect(@serverTrans).to receive(:to_s).once.and_return("serverTrans")
+      expect(@trans).to receive(:to_s).once.and_return("trans")
+      expect(@prot).to receive(:to_s).once.and_return("prot")
+      expect(@server.to_s).to eq("server(prot(trans(serverTrans)))")
+    end
   end
 
   describe Thrift::SimpleServer do
     before(:each) do
-      @processor = mock("Processor")
-      @serverTrans = mock("ServerTransport")
-      @trans = mock("BaseTransport")
-      @prot = mock("BaseProtocol")
-      @client = mock("Client")
+      @processor = double("Processor")
+      @serverTrans = double("ServerTransport")
+      @trans = double("BaseTransport")
+      @prot = double("BaseProtocol")
+      @client = double("Client")
       @server = described_class.new(@processor, @serverTrans, @trans, @prot)
     end
     
+    it "should provide a reasonable to_s" do
+      expect(@serverTrans).to receive(:to_s).once.and_return("serverTrans")
+      expect(@trans).to receive(:to_s).once.and_return("trans")
+      expect(@prot).to receive(:to_s).once.and_return("prot")
+      expect(@server.to_s).to eq("simple(server(prot(trans(serverTrans))))")
+    end
+    
     it "should serve in the main thread" do
-      @serverTrans.should_receive(:listen).ordered
-      @serverTrans.should_receive(:accept).exactly(3).times.and_return(@client)
-      @trans.should_receive(:get_transport).exactly(3).times.with(@client).and_return(@trans)
-      @prot.should_receive(:get_protocol).exactly(3).times.with(@trans).and_return(@prot)
+      expect(@serverTrans).to receive(:listen).ordered
+      expect(@serverTrans).to receive(:accept).exactly(3).times.and_return(@client)
+      expect(@trans).to receive(:get_transport).exactly(3).times.with(@client).and_return(@trans)
+      expect(@prot).to receive(:get_protocol).exactly(3).times.with(@trans).and_return(@prot)
       x = 0
-      @processor.should_receive(:process).exactly(3).times.with(@prot, @prot).and_return do
+      expect(@processor).to receive(:process).exactly(3).times.with(@prot, @prot) do
         case (x += 1)
         when 1 then raise Thrift::TransportException
         when 2 then raise Thrift::ProtocolException
         when 3 then throw :stop
         end
       end
-      @trans.should_receive(:close).exactly(3).times
-      @serverTrans.should_receive(:close).ordered
-      lambda { @server.serve }.should throw_symbol(:stop)
+      expect(@trans).to receive(:close).exactly(3).times
+      expect(@serverTrans).to receive(:close).ordered
+      expect { @server.serve }.to throw_symbol(:stop)
     end
   end
 
   describe Thrift::ThreadedServer do
     before(:each) do
-      @processor = mock("Processor")
-      @serverTrans = mock("ServerTransport")
-      @trans = mock("BaseTransport")
-      @prot = mock("BaseProtocol")
-      @client = mock("Client")
+      @processor = double("Processor")
+      @serverTrans = double("ServerTransport")
+      @trans = double("BaseTransport")
+      @prot = double("BaseProtocol")
+      @client = double("Client")
       @server = described_class.new(@processor, @serverTrans, @trans, @prot)
     end
 
+    it "should provide a reasonable to_s" do
+      expect(@serverTrans).to receive(:to_s).once.and_return("serverTrans")
+      expect(@trans).to receive(:to_s).once.and_return("trans")
+      expect(@prot).to receive(:to_s).once.and_return("prot")
+      expect(@server.to_s).to eq("threaded(server(prot(trans(serverTrans))))")
+    end
+    
     it "should serve using threads" do
-      @serverTrans.should_receive(:listen).ordered
-      @serverTrans.should_receive(:accept).exactly(3).times.and_return(@client)
-      @trans.should_receive(:get_transport).exactly(3).times.with(@client).and_return(@trans)
-      @prot.should_receive(:get_protocol).exactly(3).times.with(@trans).and_return(@prot)
-      Thread.should_receive(:new).with(@prot, @trans).exactly(3).times.and_yield(@prot, @trans)
+      expect(@serverTrans).to receive(:listen).ordered
+      expect(@serverTrans).to receive(:accept).exactly(3).times.and_return(@client)
+      expect(@trans).to receive(:get_transport).exactly(3).times.with(@client).and_return(@trans)
+      expect(@prot).to receive(:get_protocol).exactly(3).times.with(@trans).and_return(@prot)
+      expect(Thread).to receive(:new).with(@prot, @trans).exactly(3).times.and_yield(@prot, @trans)
       x = 0
-      @processor.should_receive(:process).exactly(3).times.with(@prot, @prot).and_return do
+      expect(@processor).to receive(:process).exactly(3).times.with(@prot, @prot) do
         case (x += 1)
         when 1 then raise Thrift::TransportException
         when 2 then raise Thrift::ProtocolException
         when 3 then throw :stop
         end
       end
-      @trans.should_receive(:close).exactly(3).times
-      @serverTrans.should_receive(:close).ordered
-      lambda { @server.serve }.should throw_symbol(:stop)
+      expect(@trans).to receive(:close).exactly(3).times
+      expect(@serverTrans).to receive(:close).ordered
+      expect { @server.serve }.to throw_symbol(:stop)
     end
   end
 
   describe Thrift::ThreadPoolServer do
     before(:each) do
-      @processor = mock("Processor")
-      @server_trans = mock("ServerTransport")
-      @trans = mock("BaseTransport")
-      @prot = mock("BaseProtocol")
-      @client = mock("Client")
+      @processor = double("Processor")
+      @server_trans = double("ServerTransport")
+      @trans = double("BaseTransport")
+      @prot = double("BaseProtocol")
+      @client = double("Client")
       @server = described_class.new(@processor, @server_trans, @trans, @prot)
+      sleep(0.15)
     end
 
+    it "should provide a reasonable to_s" do
+      expect(@server_trans).to receive(:to_s).once.and_return("server_trans")
+      expect(@trans).to receive(:to_s).once.and_return("trans")
+      expect(@prot).to receive(:to_s).once.and_return("prot")
+      expect(@server.to_s).to eq("threadpool(server(prot(trans(server_trans))))")
+    end
+    
     it "should serve inside a thread" do
       exception_q = @server.instance_variable_get(:@exception_q)
-      described_class.any_instance.should_receive(:serve) do 
+      expect_any_instance_of(described_class).to receive(:serve) do 
         exception_q.push(StandardError.new('ERROR'))
       end
       expect { @server.rescuable_serve }.to(raise_error('ERROR'))
+      sleep(0.15)
     end
 
     it "should avoid running the server twice when retrying rescuable_serve" do
       exception_q = @server.instance_variable_get(:@exception_q)
-      described_class.any_instance.should_receive(:serve) do 
+      expect_any_instance_of(described_class).to receive(:serve) do 
         exception_q.push(StandardError.new('ERROR1'))
         exception_q.push(StandardError.new('ERROR2'))
       end
@@ -118,29 +158,29 @@
     end
 
     it "should serve using a thread pool" do
-      thread_q = mock("SizedQueue")
-      exception_q = mock("Queue")
+      thread_q = double("SizedQueue")
+      exception_q = double("Queue")
       @server.instance_variable_set(:@thread_q, thread_q)
       @server.instance_variable_set(:@exception_q, exception_q)
-      @server_trans.should_receive(:listen).ordered
-      thread_q.should_receive(:push).with(:token)
-      thread_q.should_receive(:pop)
-      Thread.should_receive(:new).and_yield
-      @server_trans.should_receive(:accept).exactly(3).times.and_return(@client)
-      @trans.should_receive(:get_transport).exactly(3).times.and_return(@trans)
-      @prot.should_receive(:get_protocol).exactly(3).times.and_return(@prot)
+      expect(@server_trans).to receive(:listen).ordered
+      expect(thread_q).to receive(:push).with(:token)
+      expect(thread_q).to receive(:pop)
+      expect(Thread).to receive(:new).and_yield
+      expect(@server_trans).to receive(:accept).exactly(3).times.and_return(@client)
+      expect(@trans).to receive(:get_transport).exactly(3).times.and_return(@trans)
+      expect(@prot).to receive(:get_protocol).exactly(3).times.and_return(@prot)
       x = 0
       error = RuntimeError.new("Stopped")
-      @processor.should_receive(:process).exactly(3).times.with(@prot, @prot).and_return do
+      expect(@processor).to receive(:process).exactly(3).times.with(@prot, @prot) do
         case (x += 1)
         when 1 then raise Thrift::TransportException
         when 2 then raise Thrift::ProtocolException
         when 3 then raise error
         end
       end
-      @trans.should_receive(:close).exactly(3).times
-      exception_q.should_receive(:push).with(error).and_throw(:stop)
-      @server_trans.should_receive(:close)
+      expect(@trans).to receive(:close).exactly(3).times
+      expect(exception_q).to receive(:push).with(error).and_throw(:stop)
+      expect(@server_trans).to receive(:close)
       expect { @server.serve }.to(throw_symbol(:stop))
     end
   end
diff --git a/lib/rb/spec/socket_spec.rb b/lib/rb/spec/socket_spec.rb
index e6b6732..202c745 100644
--- a/lib/rb/spec/socket_spec.rb
+++ b/lib/rb/spec/socket_spec.rb
@@ -25,37 +25,44 @@
   describe Thrift::Socket do
     before(:each) do
       @socket = Thrift::Socket.new
-      @handle = mock("Handle", :closed? => false)
-      @handle.stub!(:close)
-      @handle.stub!(:connect_nonblock)
-      @handle.stub!(:setsockopt)
-      ::Socket.stub!(:new).and_return(@handle)
+      @handle = double("Handle", :closed? => false)
+      allow(@handle).to receive(:close)
+      allow(@handle).to receive(:connect_nonblock)
+      allow(@handle).to receive(:setsockopt)
+      allow(::Socket).to receive(:new).and_return(@handle)
     end
 
     it_should_behave_like "a socket"
 
     it "should raise a TransportException when it cannot open a socket" do
-      ::Socket.should_receive(:new).and_raise(StandardError)
-      lambda { @socket.open }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::NOT_OPEN }
+      expect(::Socket).to receive(:getaddrinfo).with("localhost", 9090, nil, ::Socket::SOCK_STREAM).and_return([[]])
+      expect { @socket.open }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) }
     end
 
     it "should open a ::Socket with default args" do
-      ::Socket.should_receive(:new).and_return(mock("Handle", :connect_nonblock => true, :setsockopt => nil))
-      ::Socket.should_receive(:getaddrinfo).with("localhost", 9090, nil, ::Socket::SOCK_STREAM).and_return([[]])
-      ::Socket.should_receive(:sockaddr_in)
+      expect(::Socket).to receive(:new).and_return(double("Handle", :connect_nonblock => true, :setsockopt => nil))
+      expect(::Socket).to receive(:getaddrinfo).with("localhost", 9090, nil, ::Socket::SOCK_STREAM).and_return([[]])
+      expect(::Socket).to receive(:sockaddr_in)
+      @socket.to_s == "socket(localhost:9090)"
       @socket.open
     end
 
     it "should accept host/port options" do
-      ::Socket.should_receive(:new).and_return(mock("Handle", :connect_nonblock => true, :setsockopt => nil))
-      ::Socket.should_receive(:getaddrinfo).with("my.domain", 1234, nil, ::Socket::SOCK_STREAM).and_return([[]])
-      ::Socket.should_receive(:sockaddr_in)
-      Thrift::Socket.new('my.domain', 1234).open
+      expect(::Socket).to receive(:new).and_return(double("Handle", :connect_nonblock => true, :setsockopt => nil))
+      expect(::Socket).to receive(:getaddrinfo).with("my.domain", 1234, nil, ::Socket::SOCK_STREAM).and_return([[]])
+      expect(::Socket).to receive(:sockaddr_in)
+      @socket = Thrift::Socket.new('my.domain', 1234).open
+      @socket.to_s == "socket(my.domain:1234)"
     end
 
     it "should accept an optional timeout" do
-      ::Socket.stub!(:new)
-      Thrift::Socket.new('localhost', 8080, 5).timeout.should == 5
+      allow(::Socket).to receive(:new)
+      expect(Thrift::Socket.new('localhost', 8080, 5).timeout).to eq(5)
+    end
+
+    it "should provide a reasonable to_s" do
+      allow(::Socket).to receive(:new)
+      expect(Thrift::Socket.new('myhost', 8090).to_s).to eq("socket(myhost:8090)")
     end
   end
 end
diff --git a/lib/rb/spec/socket_spec_shared.rb b/lib/rb/spec/socket_spec_shared.rb
index 5fddc16..32bdb71 100644
--- a/lib/rb/spec/socket_spec_shared.rb
+++ b/lib/rb/spec/socket_spec_shared.rb
@@ -21,84 +21,84 @@
 
 shared_examples_for "a socket" do
   it "should open a socket" do
-    @socket.open.should == @handle
+    expect(@socket.open).to eq(@handle)
   end
 
   it "should be open whenever it has a handle" do
-    @socket.should_not be_open
+    expect(@socket).not_to be_open
     @socket.open
-    @socket.should be_open
+    expect(@socket).to be_open
     @socket.handle = nil
-    @socket.should_not be_open
+    expect(@socket).not_to be_open
     @socket.handle = @handle
     @socket.close
-    @socket.should_not be_open
+    expect(@socket).not_to be_open
   end
 
   it "should write data to the handle" do
     @socket.open
-    @handle.should_receive(:write).with("foobar")
+    expect(@handle).to receive(:write).with("foobar")
     @socket.write("foobar")
-    @handle.should_receive(:write).with("fail").and_raise(StandardError)
-    lambda { @socket.write("fail") }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::NOT_OPEN }
+    expect(@handle).to receive(:write).with("fail").and_raise(StandardError)
+    expect { @socket.write("fail") }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) }
   end
 
   it "should raise an error when it cannot read from the handle" do
     @socket.open
-    @handle.should_receive(:readpartial).with(17).and_raise(StandardError)
-    lambda { @socket.read(17) }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::NOT_OPEN }
+    expect(@handle).to receive(:readpartial).with(17).and_raise(StandardError)
+    expect { @socket.read(17) }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) }
   end
 
   it "should return the data read when reading from the handle works" do
     @socket.open
-    @handle.should_receive(:readpartial).with(17).and_return("test data")
-    @socket.read(17).should == "test data"
+    expect(@handle).to receive(:readpartial).with(17).and_return("test data")
+    expect(@socket.read(17)).to eq("test data")
   end
 
   it "should declare itself as closed when it has an error" do
     @socket.open
-    @handle.should_receive(:write).with("fail").and_raise(StandardError)
-    @socket.should be_open
-    lambda { @socket.write("fail") }.should raise_error
-    @socket.should_not be_open
+    expect(@handle).to receive(:write).with("fail").and_raise(StandardError)
+    expect(@socket).to be_open
+    expect { @socket.write("fail") }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) }
+    expect(@socket).not_to be_open
   end
 
   it "should raise an error when the stream is closed" do
     @socket.open
-    @handle.stub!(:closed?).and_return(true)
-    @socket.should_not be_open
-    lambda { @socket.write("fail") }.should raise_error(IOError, "closed stream")
-    lambda { @socket.read(10) }.should raise_error(IOError, "closed stream")
+    allow(@handle).to receive(:closed?).and_return(true)
+    expect(@socket).not_to be_open
+    expect { @socket.write("fail") }.to raise_error(IOError, "closed stream")
+    expect { @socket.read(10) }.to raise_error(IOError, "closed stream")
   end
 
   it "should support the timeout accessor for read" do
     @socket.timeout = 3
     @socket.open
-    IO.should_receive(:select).with([@handle], nil, nil, 3).and_return([[@handle], [], []])
-    @handle.should_receive(:readpartial).with(17).and_return("test data")
-    @socket.read(17).should == "test data"
+    expect(IO).to receive(:select).with([@handle], nil, nil, 3).and_return([[@handle], [], []])
+    expect(@handle).to receive(:readpartial).with(17).and_return("test data")
+    expect(@socket.read(17)).to eq("test data")
   end
 
   it "should support the timeout accessor for write" do
     @socket.timeout = 3
     @socket.open
-    IO.should_receive(:select).with(nil, [@handle], nil, 3).twice.and_return([[], [@handle], []])
-    @handle.should_receive(:write_nonblock).with("test data").and_return(4)
-    @handle.should_receive(:write_nonblock).with(" data").and_return(5)
-    @socket.write("test data").should == 9
+    expect(IO).to receive(:select).with(nil, [@handle], nil, 3).twice.and_return([[], [@handle], []])
+    expect(@handle).to receive(:write_nonblock).with("test data").and_return(4)
+    expect(@handle).to receive(:write_nonblock).with(" data").and_return(5)
+    expect(@socket.write("test data")).to eq(9)
   end
 
   it "should raise an error when read times out" do
     @socket.timeout = 0.5
     @socket.open
-    IO.should_receive(:select).once {sleep(0.5); nil}
-    lambda { @socket.read(17) }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::TIMED_OUT }
+    expect(IO).to receive(:select).once {sleep(0.5); nil}
+    expect { @socket.read(17) }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::TIMED_OUT) }
   end
 
   it "should raise an error when write times out" do
     @socket.timeout = 0.5
     @socket.open
-    IO.should_receive(:select).with(nil, [@handle], nil, 0.5).any_number_of_times.and_return(nil)
-    lambda { @socket.write("test data") }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::TIMED_OUT }
+    allow(IO).to receive(:select).with(nil, [@handle], nil, 0.5).and_return(nil)
+    expect { @socket.write("test data") }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::TIMED_OUT) }
   end
 end
diff --git a/lib/rb/spec/spec_helper.rb b/lib/rb/spec/spec_helper.rb
index 8664b66..5bf98d0 100644
--- a/lib/rb/spec/spec_helper.rb
+++ b/lib/rb/spec/spec_helper.rb
@@ -54,8 +54,11 @@
 require 'nonblocking_service'
 
 module Fixtures
-  COMPACT_PROTOCOL_TEST_STRUCT = COMPACT_TEST.dup
+  COMPACT_PROTOCOL_TEST_STRUCT = Thrift::Test::COMPACT_TEST.dup
   COMPACT_PROTOCOL_TEST_STRUCT.a_binary = [0,1,2,3,4,5,6,7,8].pack('c*')
   COMPACT_PROTOCOL_TEST_STRUCT.set_byte_map = nil
   COMPACT_PROTOCOL_TEST_STRUCT.map_byte_map = nil
 end
+
+$:.unshift File.join(File.dirname(__FILE__), *%w[gen-rb/flat])
+
diff --git a/lib/rb/spec/ssl_server_socket_spec.rb b/lib/rb/spec/ssl_server_socket_spec.rb
new file mode 100644
index 0000000..82e6518
--- /dev/null
+++ b/lib/rb/spec/ssl_server_socket_spec.rb
@@ -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.
+#
+
+require 'spec_helper'
+require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared")
+
+describe 'SSLServerSocket' do
+
+  describe Thrift::SSLServerSocket do
+    before(:each) do
+      @socket = Thrift::SSLServerSocket.new(1234)
+    end
+
+    it "should provide a reasonable to_s" do
+      expect(@socket.to_s).to eq("ssl(socket(:1234))")
+    end
+  end
+end
diff --git a/lib/rb/spec/ssl_socket_spec.rb b/lib/rb/spec/ssl_socket_spec.rb
new file mode 100644
index 0000000..808d8d5
--- /dev/null
+++ b/lib/rb/spec/ssl_socket_spec.rb
@@ -0,0 +1,78 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'spec_helper'
+require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared")
+
+describe 'SSLSocket' do
+
+  describe Thrift::SSLSocket do
+    before(:each) do
+      @context = OpenSSL::SSL::SSLContext.new
+      @socket = Thrift::SSLSocket.new
+      @simple_socket_handle = double("Handle", :closed? => false)
+      allow(@simple_socket_handle).to receive(:close)
+      allow(@simple_socket_handle).to receive(:connect_nonblock)
+      allow(@simple_socket_handle).to receive(:setsockopt)
+
+      @handle = double(double("SSLHandle", :connect_nonblock => true, :post_connection_check => true), :closed? => false)
+      allow(@handle).to receive(:connect_nonblock)
+      allow(@handle).to receive(:close)
+      allow(@handle).to receive(:post_connection_check)
+
+      allow(::Socket).to receive(:new).and_return(@simple_socket_handle)
+      allow(OpenSSL::SSL::SSLSocket).to receive(:new).and_return(@handle)
+    end
+
+    it_should_behave_like "a socket"
+
+    it "should raise a TransportException when it cannot open a ssl socket" do
+      expect(::Socket).to receive(:getaddrinfo).with("localhost", 9090, nil, ::Socket::SOCK_STREAM).and_return([[]])
+      expect { @socket.open }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) }
+    end
+
+    it "should open a ::Socket with default args" do
+      expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(@simple_socket_handle, nil).and_return(@handle)
+      expect(@handle).to receive(:post_connection_check).with('localhost')
+      @socket.open
+    end
+
+    it "should accept host/port options" do
+      handle = double("Handle", :connect_nonblock => true, :setsockopt => nil)
+      allow(::Socket).to receive(:new).and_return(handle)
+      expect(::Socket).to receive(:getaddrinfo).with("my.domain", 1234, nil, ::Socket::SOCK_STREAM).and_return([[]])
+      expect(::Socket).to receive(:sockaddr_in)
+      expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(handle, nil).and_return(@handle)
+      expect(@handle).to receive(:post_connection_check).with('my.domain')
+      Thrift::SSLSocket.new('my.domain', 1234, 6000, nil).open
+    end
+
+    it "should accept an optional timeout" do
+      expect(Thrift::SSLSocket.new('localhost', 8080, 5).timeout).to eq(5)
+    end
+
+    it "should accept an optional context" do
+      expect(Thrift::SSLSocket.new('localhost', 8080, 5, @context).ssl_context).to eq(@context)
+    end
+
+    it "should provide a reasonable to_s" do
+      expect(Thrift::SSLSocket.new('myhost', 8090).to_s).to eq("ssl(socket(myhost:8090))")
+    end
+  end
+end
diff --git a/lib/rb/spec/struct_nested_containers_spec.rb b/lib/rb/spec/struct_nested_containers_spec.rb
index dc8ce5f..d063569 100644
--- a/lib/rb/spec/struct_nested_containers_spec.rb
+++ b/lib/rb/spec/struct_nested_containers_spec.rb
@@ -39,9 +39,9 @@
           thrift_struct.value = [ [1, 2, 3], [2, 3, 4] ]
           thrift_struct.validate
         end
-        a.should == b
+        expect(a).to eq(b)
         b.value.push [3, 4, 5]
-        a.should_not == b
+        expect(a).not_to eq(b)
       end
     end
 
@@ -52,9 +52,9 @@
           thrift_struct.value = [ [1, 2, 3], [2, 3, 4] ].to_set
           thrift_struct.validate
         end
-        a.should == b
+        expect(a).to eq(b)
         b.value.add [3, 4, 5]
-        a.should_not == b
+        expect(a).not_to eq(b)
       end
     end
 
@@ -65,9 +65,9 @@
           thrift_struct.value = { [1, 2, 3] => 1, [2, 3, 4] => 2 }
           thrift_struct.validate
         end
-        a.should == b
+        expect(a).to eq(b)
         b.value[[3, 4, 5]] = 3
-        a.should_not == b
+        expect(a).not_to eq(b)
       end
     end
 
@@ -78,9 +78,9 @@
           thrift_struct.value = { 1 => [1, 2, 3], 2 => [2, 3, 4] }
           thrift_struct.validate
         end
-        a.should == b
+        expect(a).to eq(b)
         b.value[3] = [3, 4, 5]
-        a.should_not == b
+        expect(a).not_to eq(b)
       end
     end
 
@@ -91,9 +91,9 @@
           thrift_struct.value = [ [1, 2, 3].to_set, [2, 3, 4].to_set ]
           thrift_struct.validate
         end
-        a.should == b
+        expect(a).to eq(b)
         b.value.push([3, 4, 5].to_set)
-        a.should_not == b
+        expect(a).not_to eq(b)
       end
     end
 
@@ -104,9 +104,9 @@
           thrift_struct.value = [ [1, 2, 3].to_set, [2, 3, 4].to_set ].to_set
           thrift_struct.validate
         end
-        a.should == b
+        expect(a).to eq(b)
         b.value.add([3, 4, 5].to_set)
-        a.should_not == b
+        expect(a).not_to eq(b)
       end
     end
 
@@ -117,9 +117,9 @@
           thrift_struct.value = { [1, 2, 3].to_set => 1, [2, 3, 4].to_set => 2 }
           thrift_struct.validate
         end
-        a.should == b
+        expect(a).to eq(b)
         b.value[[3, 4, 5].to_set] = 3
-        a.should_not == b
+        expect(a).not_to eq(b)
       end
     end
 
@@ -130,9 +130,9 @@
           thrift_struct.value = { 1 => [1, 2, 3].to_set, 2 => [2, 3, 4].to_set }
           thrift_struct.validate
         end
-        a.should == b
+        expect(a).to eq(b)
         b.value[3] = [3, 4, 5].to_set
-        a.should_not == b
+        expect(a).not_to eq(b)
       end
     end
 
@@ -143,9 +143,9 @@
           thrift_struct.value = [ {1 => 2, 3 => 4}, {2 => 3, 4 => 5} ]
           thrift_struct.validate
         end
-        a.should == b
+        expect(a).to eq(b)
         b.value.push({ 3 => 4, 5 => 6 })
-        a.should_not == b
+        expect(a).not_to eq(b)
       end
     end
 
@@ -156,9 +156,9 @@
           thrift_struct.value = [ {1 => 2, 3 => 4}, {2 => 3, 4 => 5} ].to_set
           thrift_struct.validate
         end
-        a.should == b
+        expect(a).to eq(b)
         b.value.add({ 3 => 4, 5 => 6 })
-        a.should_not == b
+        expect(a).not_to eq(b)
       end
     end
 
@@ -169,9 +169,9 @@
           thrift_struct.value = { { 1 => 2, 3 => 4} => 1, {2 => 3, 4 => 5}  => 2 }
           thrift_struct.validate
         end
-        a.should == b
+        expect(a).to eq(b)
         b.value[{3 => 4, 5 => 6}] = 3
-        a.should_not == b
+        expect(a).not_to eq(b)
       end
     end
 
@@ -182,9 +182,9 @@
           thrift_struct.value = { 1 => { 1 => 2, 3 => 4}, 2 => {2 => 3, 4 => 5} }
           thrift_struct.validate
         end
-        a.should == b
+        expect(a).to eq(b)
         b.value[3] = { 3 => 4, 5 => 6 }
-        a.should_not == b
+        expect(a).not_to eq(b)
       end
     end
   end
diff --git a/lib/rb/spec/struct_spec.rb b/lib/rb/spec/struct_spec.rb
index 6534d61..bbd502b 100644
--- a/lib/rb/spec/struct_spec.rb
+++ b/lib/rb/spec/struct_spec.rb
@@ -25,7 +25,7 @@
     it "should iterate over all fields properly" do
       fields = {}
       SpecNamespace::Foo.new.each_field { |fid,field_info| fields[fid] = field_info }
-      fields.should == SpecNamespace::Foo::FIELDS
+      expect(fields).to eq(SpecNamespace::Foo::FIELDS)
     end
 
     it "should initialize all fields to defaults" do
@@ -39,19 +39,19 @@
     end
 
     def validate_default_arguments(object)
-      object.simple.should == 53
-      object.words.should == "words"
-      object.hello.should == SpecNamespace::Hello.new(:greeting => 'hello, world!')
-      object.ints.should == [1, 2, 2, 3]
-      object.complex.should be_nil
-      object.shorts.should == Set.new([5, 17, 239])
+      expect(object.simple).to eq(53)
+      expect(object.words).to eq("words")
+      expect(object.hello).to eq(SpecNamespace::Hello.new(:greeting => 'hello, world!'))
+      expect(object.ints).to eq([1, 2, 2, 3])
+      expect(object.complex).to be_nil
+      expect(object.shorts).to eq(Set.new([5, 17, 239]))
     end
 
     it "should not share default values between instances" do
       begin
         struct = SpecNamespace::Foo.new
         struct.ints << 17
-        SpecNamespace::Foo.new.ints.should == [1,2,2,3]
+        expect(SpecNamespace::Foo.new.ints).to eq([1,2,2,3])
       ensure
         # ensure no leakage to other tests
         SpecNamespace::Foo::FIELDS[4][:default] = [1,2,2,3]
@@ -60,48 +60,48 @@
 
     it "should properly initialize boolean values" do
       struct = SpecNamespace::BoolStruct.new(:yesno => false)
-      struct.yesno.should be_false
+      expect(struct.yesno).to be_falsey
     end
 
     it "should have proper == semantics" do
-      SpecNamespace::Foo.new.should_not == SpecNamespace::Hello.new
-      SpecNamespace::Foo.new.should == SpecNamespace::Foo.new
-      SpecNamespace::Foo.new(:simple => 52).should_not == SpecNamespace::Foo.new
+      expect(SpecNamespace::Foo.new).not_to eq(SpecNamespace::Hello.new)
+      expect(SpecNamespace::Foo.new).to eq(SpecNamespace::Foo.new)
+      expect(SpecNamespace::Foo.new(:simple => 52)).not_to eq(SpecNamespace::Foo.new)
     end
 
     it "should print enum value names in inspect" do
-      SpecNamespace::StructWithSomeEnum.new(:some_enum => SpecNamespace::SomeEnum::ONE).inspect.should == "<SpecNamespace::StructWithSomeEnum some_enum:ONE (0)>"
+      expect(SpecNamespace::StructWithSomeEnum.new(:some_enum => SpecNamespace::SomeEnum::ONE).inspect).to eq("<SpecNamespace::StructWithSomeEnum some_enum:ONE (0)>")
 
-      SpecNamespace::StructWithEnumMap.new(:my_map => {SpecNamespace::SomeEnum::ONE => [SpecNamespace::SomeEnum::TWO]}).inspect.should == "<SpecNamespace::StructWithEnumMap my_map:{ONE (0): [TWO (1)]}>"
+      expect(SpecNamespace::StructWithEnumMap.new(:my_map => {SpecNamespace::SomeEnum::ONE => [SpecNamespace::SomeEnum::TWO]}).inspect).to eq("<SpecNamespace::StructWithEnumMap my_map:{ONE (0): [TWO (1)]}>")
     end
 
     it "should pretty print binary fields" do
-      SpecNamespace::Foo2.new(:my_binary => "\001\002\003").inspect.should == "<SpecNamespace::Foo2 my_binary:010203>"
+      expect(SpecNamespace::Foo2.new(:my_binary => "\001\002\003").inspect).to eq("<SpecNamespace::Foo2 my_binary:010203>")
     end
 
     it "should offer field? methods" do
-      SpecNamespace::Foo.new.opt_string?.should be_false
-      SpecNamespace::Foo.new(:simple => 52).simple?.should be_true
-      SpecNamespace::Foo.new(:my_bool => false).my_bool?.should be_true
-      SpecNamespace::Foo.new(:my_bool => true).my_bool?.should be_true
+      expect(SpecNamespace::Foo.new.opt_string?).to be_falsey
+      expect(SpecNamespace::Foo.new(:simple => 52).simple?).to be_truthy
+      expect(SpecNamespace::Foo.new(:my_bool => false).my_bool?).to be_truthy
+      expect(SpecNamespace::Foo.new(:my_bool => true).my_bool?).to be_truthy
     end
 
     it "should be comparable" do
       s1 = SpecNamespace::StructWithSomeEnum.new(:some_enum => SpecNamespace::SomeEnum::ONE)
       s2 = SpecNamespace::StructWithSomeEnum.new(:some_enum => SpecNamespace::SomeEnum::TWO)
 
-      (s1 <=> s2).should == -1
-      (s2 <=> s1).should == 1
-      (s1 <=> s1).should == 0
-      (s1 <=> SpecNamespace::StructWithSomeEnum.new()).should == -1
+      expect(s1 <=> s2).to eq(-1)
+      expect(s2 <=> s1).to eq(1)
+      expect(s1 <=> s1).to eq(0)
+      expect(s1 <=> SpecNamespace::StructWithSomeEnum.new()).to eq(-1)
     end
 
     it "should read itself off the wire" do
       struct = SpecNamespace::Foo.new
-      prot = Thrift::BaseProtocol.new(mock("transport"))
-      prot.should_receive(:read_struct_begin).twice
-      prot.should_receive(:read_struct_end).twice
-      prot.should_receive(:read_field_begin).and_return(
+      prot = Thrift::BaseProtocol.new(double("transport"))
+      expect(prot).to receive(:read_struct_begin).twice
+      expect(prot).to receive(:read_struct_end).twice
+      expect(prot).to receive(:read_field_begin).and_return(
         ['complex', Thrift::Types::MAP, 5], # Foo
         ['words', Thrift::Types::STRING, 2], # Foo
         ['hello', Thrift::Types::STRUCT, 3], # Foo
@@ -112,49 +112,49 @@
         ['shorts', Thrift::Types::SET, 6], # Foo
         [nil, Thrift::Types::STOP, 0] # Hello
       )
-      prot.should_receive(:read_field_end).exactly(7).times
-      prot.should_receive(:read_map_begin).and_return(
+      expect(prot).to receive(:read_field_end).exactly(7).times
+      expect(prot).to receive(:read_map_begin).and_return(
         [Thrift::Types::I32, Thrift::Types::MAP, 2], # complex
           [Thrift::Types::STRING, Thrift::Types::DOUBLE, 2], # complex/1/value
           [Thrift::Types::STRING, Thrift::Types::DOUBLE, 1] # complex/2/value
       )
-      prot.should_receive(:read_map_end).exactly(3).times
-      prot.should_receive(:read_list_begin).and_return([Thrift::Types::I32, 4])
-      prot.should_receive(:read_list_end)
-      prot.should_receive(:read_set_begin).and_return([Thrift::Types::I16, 2])
-      prot.should_receive(:read_set_end)
-      prot.should_receive(:read_i32).and_return(
+      expect(prot).to receive(:read_map_end).exactly(3).times
+      expect(prot).to receive(:read_list_begin).and_return([Thrift::Types::I32, 4])
+      expect(prot).to receive(:read_list_end)
+      expect(prot).to receive(:read_set_begin).and_return([Thrift::Types::I16, 2])
+      expect(prot).to receive(:read_set_end)
+      expect(prot).to receive(:read_i32).and_return(
         1, 14,        # complex keys
         42,           # simple
         4, 23, 4, 29  # ints
       )
-      prot.should_receive(:read_string).and_return("pi", "e", "feigenbaum", "apple banana", "what's up?")
-      prot.should_receive(:read_double).and_return(Math::PI, Math::E, 4.669201609)
-      prot.should_receive(:read_i16).and_return(2, 3)
-      prot.should_not_receive(:skip)
+      expect(prot).to receive(:read_string).and_return("pi", "e", "feigenbaum", "apple banana", "what's up?")
+      expect(prot).to receive(:read_double).and_return(Math::PI, Math::E, 4.669201609)
+      expect(prot).to receive(:read_i16).and_return(2, 3)
+      expect(prot).not_to receive(:skip)
       struct.read(prot)
 
-      struct.simple.should == 42
-      struct.complex.should == {1 => {"pi" => Math::PI, "e" => Math::E}, 14 => {"feigenbaum" => 4.669201609}}
-      struct.hello.should == SpecNamespace::Hello.new(:greeting => "what's up?")
-      struct.words.should == "apple banana"
-      struct.ints.should == [4, 23, 4, 29]
-      struct.shorts.should == Set.new([3, 2])
+      expect(struct.simple).to eq(42)
+      expect(struct.complex).to eq({1 => {"pi" => Math::PI, "e" => Math::E}, 14 => {"feigenbaum" => 4.669201609}})
+      expect(struct.hello).to eq(SpecNamespace::Hello.new(:greeting => "what's up?"))
+      expect(struct.words).to eq("apple banana")
+      expect(struct.ints).to eq([4, 23, 4, 29])
+      expect(struct.shorts).to eq(Set.new([3, 2]))
     end
 
     it "should serialize false boolean fields correctly" do
       b = SpecNamespace::BoolStruct.new(:yesno => false)
       prot = Thrift::BinaryProtocol.new(Thrift::MemoryBufferTransport.new)
-      prot.should_receive(:write_bool).with(false)
+      expect(prot).to receive(:write_bool).with(false)
       b.write(prot)
     end
 
     it "should skip unexpected fields in structs and use default values" do
       struct = SpecNamespace::Foo.new
-      prot = Thrift::BaseProtocol.new(mock("transport"))
-      prot.should_receive(:read_struct_begin)
-      prot.should_receive(:read_struct_end)
-      prot.should_receive(:read_field_begin).and_return(
+      prot = Thrift::BaseProtocol.new(double("transport"))
+      expect(prot).to receive(:read_struct_begin)
+      expect(prot).to receive(:read_struct_end)
+      expect(prot).to receive(:read_field_begin).and_return(
         ['simple', Thrift::Types::I32, 1],
         ['complex', Thrift::Types::STRUCT, 5],
         ['thinz', Thrift::Types::MAP, 7],
@@ -162,55 +162,55 @@
         ['words', Thrift::Types::STRING, 2],
         [nil, Thrift::Types::STOP, 0]
       )
-      prot.should_receive(:read_field_end).exactly(5).times
-      prot.should_receive(:read_i32).and_return(42)
-      prot.should_receive(:read_string).and_return("foobar")
-      prot.should_receive(:skip).with(Thrift::Types::STRUCT)
-      prot.should_receive(:skip).with(Thrift::Types::MAP)
+      expect(prot).to receive(:read_field_end).exactly(5).times
+      expect(prot).to receive(:read_i32).and_return(42)
+      expect(prot).to receive(:read_string).and_return("foobar")
+      expect(prot).to receive(:skip).with(Thrift::Types::STRUCT)
+      expect(prot).to receive(:skip).with(Thrift::Types::MAP)
       # prot.should_receive(:read_map_begin).and_return([Thrift::Types::I32, Thrift::Types::I32, 0])
       # prot.should_receive(:read_map_end)
-      prot.should_receive(:skip).with(Thrift::Types::I32)
+      expect(prot).to receive(:skip).with(Thrift::Types::I32)
       struct.read(prot)
 
-      struct.simple.should == 42
-      struct.complex.should be_nil
-      struct.words.should == "foobar"
-      struct.hello.should == SpecNamespace::Hello.new(:greeting => 'hello, world!')
-      struct.ints.should == [1, 2, 2, 3]
-      struct.shorts.should == Set.new([5, 17, 239])
+      expect(struct.simple).to eq(42)
+      expect(struct.complex).to be_nil
+      expect(struct.words).to eq("foobar")
+      expect(struct.hello).to eq(SpecNamespace::Hello.new(:greeting => 'hello, world!'))
+      expect(struct.ints).to eq([1, 2, 2, 3])
+      expect(struct.shorts).to eq(Set.new([5, 17, 239]))
     end
 
     it "should write itself to the wire" do
-      prot = Thrift::BaseProtocol.new(mock("transport")) #mock("Protocol")
-      prot.should_receive(:write_struct_begin).with("SpecNamespace::Foo")
-      prot.should_receive(:write_struct_begin).with("SpecNamespace::Hello")
-      prot.should_receive(:write_struct_end).twice
-      prot.should_receive(:write_field_begin).with('ints', Thrift::Types::LIST, 4)
-      prot.should_receive(:write_i32).with(1)
-      prot.should_receive(:write_i32).with(2).twice
-      prot.should_receive(:write_i32).with(3)
-      prot.should_receive(:write_field_begin).with('complex', Thrift::Types::MAP, 5)
-      prot.should_receive(:write_i32).with(5)
-      prot.should_receive(:write_string).with('foo')
-      prot.should_receive(:write_double).with(1.23)
-      prot.should_receive(:write_field_begin).with('shorts', Thrift::Types::SET, 6)
-      prot.should_receive(:write_i16).with(5)
-      prot.should_receive(:write_i16).with(17)
-      prot.should_receive(:write_i16).with(239)
-      prot.should_receive(:write_field_stop).twice
-      prot.should_receive(:write_field_end).exactly(6).times
-      prot.should_receive(:write_field_begin).with('simple', Thrift::Types::I32, 1)
-      prot.should_receive(:write_i32).with(53)
-      prot.should_receive(:write_field_begin).with('hello', Thrift::Types::STRUCT, 3)
-      prot.should_receive(:write_field_begin).with('greeting', Thrift::Types::STRING, 1)
-      prot.should_receive(:write_string).with('hello, world!')
-      prot.should_receive(:write_map_begin).with(Thrift::Types::I32, Thrift::Types::MAP, 1)
-      prot.should_receive(:write_map_begin).with(Thrift::Types::STRING, Thrift::Types::DOUBLE, 1)
-      prot.should_receive(:write_map_end).twice
-      prot.should_receive(:write_list_begin).with(Thrift::Types::I32, 4)
-      prot.should_receive(:write_list_end)
-      prot.should_receive(:write_set_begin).with(Thrift::Types::I16, 3)
-      prot.should_receive(:write_set_end)
+      prot = Thrift::BaseProtocol.new(double("transport")) #mock("Protocol")
+      expect(prot).to receive(:write_struct_begin).with("SpecNamespace::Foo")
+      expect(prot).to receive(:write_struct_begin).with("SpecNamespace::Hello")
+      expect(prot).to receive(:write_struct_end).twice
+      expect(prot).to receive(:write_field_begin).with('ints', Thrift::Types::LIST, 4)
+      expect(prot).to receive(:write_i32).with(1)
+      expect(prot).to receive(:write_i32).with(2).twice
+      expect(prot).to receive(:write_i32).with(3)
+      expect(prot).to receive(:write_field_begin).with('complex', Thrift::Types::MAP, 5)
+      expect(prot).to receive(:write_i32).with(5)
+      expect(prot).to receive(:write_string).with('foo')
+      expect(prot).to receive(:write_double).with(1.23)
+      expect(prot).to receive(:write_field_begin).with('shorts', Thrift::Types::SET, 6)
+      expect(prot).to receive(:write_i16).with(5)
+      expect(prot).to receive(:write_i16).with(17)
+      expect(prot).to receive(:write_i16).with(239)
+      expect(prot).to receive(:write_field_stop).twice
+      expect(prot).to receive(:write_field_end).exactly(6).times
+      expect(prot).to receive(:write_field_begin).with('simple', Thrift::Types::I32, 1)
+      expect(prot).to receive(:write_i32).with(53)
+      expect(prot).to receive(:write_field_begin).with('hello', Thrift::Types::STRUCT, 3)
+      expect(prot).to receive(:write_field_begin).with('greeting', Thrift::Types::STRING, 1)
+      expect(prot).to receive(:write_string).with('hello, world!')
+      expect(prot).to receive(:write_map_begin).with(Thrift::Types::I32, Thrift::Types::MAP, 1)
+      expect(prot).to receive(:write_map_begin).with(Thrift::Types::STRING, Thrift::Types::DOUBLE, 1)
+      expect(prot).to receive(:write_map_end).twice
+      expect(prot).to receive(:write_list_begin).with(Thrift::Types::I32, 4)
+      expect(prot).to receive(:write_list_end)
+      expect(prot).to receive(:write_set_begin).with(Thrift::Types::I16, 3)
+      expect(prot).to receive(:write_set_end)
 
       struct = SpecNamespace::Foo.new
       struct.words = nil
@@ -221,50 +221,50 @@
     it "should raise an exception if presented with an unknown container" do
       # yeah this is silly, but I'm going for code coverage here
       struct = SpecNamespace::Foo.new
-      lambda { struct.send :write_container, nil, nil, {:type => "foo"} }.should raise_error(StandardError, "Not a container type: foo")
+      expect { struct.send :write_container, nil, nil, {:type => "foo"} }.to raise_error(StandardError, "Not a container type: foo")
     end
 
     it "should support optional type-checking in Thrift::Struct.new" do
       Thrift.type_checking = true
       begin
-        lambda { SpecNamespace::Hello.new(:greeting => 3) }.should raise_error(Thrift::TypeError, "Expected Types::STRING, received Fixnum for field greeting")
+        expect { SpecNamespace::Hello.new(:greeting => 3) }.to raise_error(Thrift::TypeError, /Expected Types::STRING, received (Integer|Fixnum) for field greeting/)
       ensure
         Thrift.type_checking = false
       end
-      lambda { SpecNamespace::Hello.new(:greeting => 3) }.should_not raise_error(Thrift::TypeError)
+      expect { SpecNamespace::Hello.new(:greeting => 3) }.not_to raise_error
     end
 
     it "should support optional type-checking in field accessors" do
       Thrift.type_checking = true
       begin
         hello = SpecNamespace::Hello.new
-        lambda { hello.greeting = 3 }.should raise_error(Thrift::TypeError, "Expected Types::STRING, received Fixnum for field greeting")
+        expect { hello.greeting = 3 }.to raise_error(Thrift::TypeError, /Expected Types::STRING, received (Integer|Fixnum) for field greeting/)
       ensure
         Thrift.type_checking = false
       end
-      lambda { hello.greeting = 3 }.should_not raise_error(Thrift::TypeError)
+      expect { hello.greeting = 3 }.not_to raise_error
     end
 
     it "should raise an exception when unknown types are given to Thrift::Struct.new" do
-      lambda { SpecNamespace::Hello.new(:fish => 'salmon') }.should raise_error(Exception, "Unknown key given to SpecNamespace::Hello.new: fish")
+      expect { SpecNamespace::Hello.new(:fish => 'salmon') }.to raise_error(Exception, "Unknown key given to SpecNamespace::Hello.new: fish")
     end
 
     it "should support `raise Xception, 'message'` for Exception structs" do
       begin
         raise SpecNamespace::Xception, "something happened"
       rescue Thrift::Exception => e
-        e.message.should == "something happened"
-        e.code.should == 1
+        expect(e.message).to eq("something happened")
+        expect(e.code).to eq(1)
         # ensure it gets serialized properly, this is the really important part
-        prot = Thrift::BaseProtocol.new(mock("trans"))
-        prot.should_receive(:write_struct_begin).with("SpecNamespace::Xception")
-        prot.should_receive(:write_struct_end)
-        prot.should_receive(:write_field_begin).with('message', Thrift::Types::STRING, 1)#, "something happened")
-        prot.should_receive(:write_string).with("something happened")
-        prot.should_receive(:write_field_begin).with('code', Thrift::Types::I32, 2)#, 1)
-        prot.should_receive(:write_i32).with(1)
-        prot.should_receive(:write_field_stop)
-        prot.should_receive(:write_field_end).twice
+        prot = Thrift::BaseProtocol.new(double("trans"))
+        expect(prot).to receive(:write_struct_begin).with("SpecNamespace::Xception")
+        expect(prot).to receive(:write_struct_end)
+        expect(prot).to receive(:write_field_begin).with('message', Thrift::Types::STRING, 1)#, "something happened")
+        expect(prot).to receive(:write_string).with("something happened")
+        expect(prot).to receive(:write_field_begin).with('code', Thrift::Types::I32, 2)#, 1)
+        expect(prot).to receive(:write_i32).with(1)
+        expect(prot).to receive(:write_field_stop)
+        expect(prot).to receive(:write_field_end).twice
 
         e.write(prot)
       end
@@ -274,17 +274,17 @@
       begin
         raise SpecNamespace::Xception, :message => "something happened", :code => 5
       rescue Thrift::Exception => e
-        e.message.should == "something happened"
-        e.code.should == 5
-        prot = Thrift::BaseProtocol.new(mock("trans"))
-        prot.should_receive(:write_struct_begin).with("SpecNamespace::Xception")
-        prot.should_receive(:write_struct_end)
-        prot.should_receive(:write_field_begin).with('message', Thrift::Types::STRING, 1)
-        prot.should_receive(:write_string).with("something happened")
-        prot.should_receive(:write_field_begin).with('code', Thrift::Types::I32, 2)
-        prot.should_receive(:write_i32).with(5)
-        prot.should_receive(:write_field_stop)
-        prot.should_receive(:write_field_end).twice
+        expect(e.message).to eq("something happened")
+        expect(e.code).to eq(5)
+        prot = Thrift::BaseProtocol.new(double("trans"))
+        expect(prot).to receive(:write_struct_begin).with("SpecNamespace::Xception")
+        expect(prot).to receive(:write_struct_end)
+        expect(prot).to receive(:write_field_begin).with('message', Thrift::Types::STRING, 1)
+        expect(prot).to receive(:write_string).with("something happened")
+        expect(prot).to receive(:write_field_begin).with('code', Thrift::Types::I32, 2)
+        expect(prot).to receive(:write_i32).with(5)
+        expect(prot).to receive(:write_field_stop)
+        expect(prot).to receive(:write_field_end).twice
 
         e.write(prot)
       end
diff --git a/lib/rb/spec/thin_http_server_spec.rb b/lib/rb/spec/thin_http_server_spec.rb
index f17ea92..665391b 100644
--- a/lib/rb/spec/thin_http_server_spec.rb
+++ b/lib/rb/spec/thin_http_server_spec.rb
@@ -19,27 +19,28 @@
 
 require 'spec_helper'
 require 'rack/test'
+require 'thrift/server/thin_http_server'
 
 describe Thrift::ThinHTTPServer do
 
-  let(:processor) { mock('processor') }
+  let(:processor) { double('processor') }
 
   describe "#initialize" do
 
     context "when using the defaults" do
 
       it "binds to port 80, with host 0.0.0.0, a path of '/'" do
-        Thin::Server.should_receive(:new).with('0.0.0.0', 80, an_instance_of(Rack::Builder))
+        expect(Thin::Server).to receive(:new).with('0.0.0.0', 80, an_instance_of(Rack::Builder))
         Thrift::ThinHTTPServer.new(processor)
       end
 
       it 'creates a ThinHTTPServer::RackApplicationContext' do
-        Thrift::ThinHTTPServer::RackApplication.should_receive(:for).with("/", processor, an_instance_of(Thrift::BinaryProtocolFactory)).and_return(anything)
+        expect(Thrift::ThinHTTPServer::RackApplication).to receive(:for).with("/", processor, an_instance_of(Thrift::BinaryProtocolFactory)).and_return(anything)
         Thrift::ThinHTTPServer.new(processor)
       end
 
       it "uses the BinaryProtocolFactory" do
-        Thrift::BinaryProtocolFactory.should_receive(:new)
+        expect(Thrift::BinaryProtocolFactory).to receive(:new)
         Thrift::ThinHTTPServer.new(processor)
       end
 
@@ -51,7 +52,7 @@
         ip = "192.168.0.1"
         port = 3000
         path = "/thin"
-        Thin::Server.should_receive(:new).with(ip, port, an_instance_of(Rack::Builder))
+        expect(Thin::Server).to receive(:new).with(ip, port, an_instance_of(Rack::Builder))
         Thrift::ThinHTTPServer.new(processor,
                            :ip => ip,
                            :port => port,
@@ -59,7 +60,7 @@
       end
 
       it 'creates a ThinHTTPServer::RackApplicationContext with a different protocol factory' do
-        Thrift::ThinHTTPServer::RackApplication.should_receive(:for).with("/", processor, an_instance_of(Thrift::JsonProtocolFactory)).and_return(anything)
+        expect(Thrift::ThinHTTPServer::RackApplication).to receive(:for).with("/", processor, an_instance_of(Thrift::JsonProtocolFactory)).and_return(anything)
         Thrift::ThinHTTPServer.new(processor,
                            :protocol_factory => Thrift::JsonProtocolFactory.new)
       end
@@ -71,12 +72,12 @@
   describe "#serve" do
 
     it 'starts the Thin server' do
-      underlying_thin_server = mock('thin server', :start => true)
-      Thin::Server.stub(:new).and_return(underlying_thin_server)
+      underlying_thin_server = double('thin server', :start => true)
+      allow(Thin::Server).to receive(:new).and_return(underlying_thin_server)
 
       thin_thrift_server = Thrift::ThinHTTPServer.new(processor)
 
-      underlying_thin_server.should_receive(:start)
+      expect(underlying_thin_server).to receive(:start)
       thin_thrift_server.serve
     end
   end
@@ -86,8 +87,8 @@
 describe Thrift::ThinHTTPServer::RackApplication do
   include Rack::Test::Methods
 
-  let(:processor) { mock('processor') }
-  let(:protocol_factory) { mock('protocol factory') }
+  let(:processor) { double('processor') }
+  let(:protocol_factory) { double('protocol factory') }
 
   def app
     Thrift::ThinHTTPServer::RackApplication.for("/", processor, protocol_factory)
@@ -98,13 +99,13 @@
     it 'receives a non-POST' do
       header('Content-Type', "application/x-thrift")
       get "/"
-      last_response.status.should be 404
+      expect(last_response.status).to be 404
     end
 
     it 'receives a header other than application/x-thrift' do
       header('Content-Type', "application/json")
       post "/"
-      last_response.status.should be 404
+      expect(last_response.status).to be 404
     end
 
   end
@@ -112,26 +113,26 @@
   context "200 response" do
 
     before do
-      protocol_factory.stub(:get_protocol)
-      processor.stub(:process)
+      allow(protocol_factory).to receive(:get_protocol)
+      allow(processor).to receive(:process)
     end
 
     it 'creates an IOStreamTransport' do
       header('Content-Type', "application/x-thrift")
-      Thrift::IOStreamTransport.should_receive(:new).with(an_instance_of(Rack::Lint::InputWrapper), an_instance_of(Rack::Response))
+      expect(Thrift::IOStreamTransport).to receive(:new).with(an_instance_of(Rack::Lint::InputWrapper), an_instance_of(Rack::Response))
       post "/"
     end
 
     it 'fetches the right protocol based on the Transport' do
       header('Content-Type', "application/x-thrift")
-      protocol_factory.should_receive(:get_protocol).with(an_instance_of(Thrift::IOStreamTransport))
+      expect(protocol_factory).to receive(:get_protocol).with(an_instance_of(Thrift::IOStreamTransport))
       post "/"
     end
 
     it 'status code 200' do
       header('Content-Type', "application/x-thrift")
       post "/"
-      last_response.ok?.should be_true
+      expect(last_response.ok?).to be_truthy
     end
 
   end
diff --git a/lib/rb/spec/types_spec.rb b/lib/rb/spec/types_spec.rb
index b2c3a20..d595ab5 100644
--- a/lib/rb/spec/types_spec.rb
+++ b/lib/rb/spec/types_spec.rb
@@ -31,85 +31,88 @@
 
   context 'type checking' do
     it "should return the proper name for each type" do
-      Thrift.type_name(Thrift::Types::I16).should == "Types::I16"
-      Thrift.type_name(Thrift::Types::VOID).should == "Types::VOID"
-      Thrift.type_name(Thrift::Types::LIST).should == "Types::LIST"
-      Thrift.type_name(42).should be_nil
+      expect(Thrift.type_name(Thrift::Types::I16)).to eq("Types::I16")
+      expect(Thrift.type_name(Thrift::Types::VOID)).to eq("Types::VOID")
+      expect(Thrift.type_name(Thrift::Types::LIST)).to eq("Types::LIST")
+      expect(Thrift.type_name(42)).to be_nil
     end
 
     it "should check types properly" do
       # lambda { Thrift.check_type(nil, Thrift::Types::STOP) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(3,              {:type => Thrift::Types::STOP},   :foo) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(nil,            {:type => Thrift::Types::VOID},   :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(3,              {:type => Thrift::Types::VOID},   :foo) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(true,           {:type => Thrift::Types::BOOL},   :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(3,              {:type => Thrift::Types::BOOL},   :foo) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(42,             {:type => Thrift::Types::BYTE},   :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(42,             {:type => Thrift::Types::I16},    :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(42,             {:type => Thrift::Types::I32},    :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(42,             {:type => Thrift::Types::I64},    :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(3.14,           {:type => Thrift::Types::I32},    :foo) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(3.14,           {:type => Thrift::Types::DOUBLE}, :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(3,              {:type => Thrift::Types::DOUBLE}, :foo) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type("3",            {:type => Thrift::Types::STRING}, :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(3,              {:type => Thrift::Types::STRING}, :foo) }.should raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(3,              {:type => Thrift::Types::STOP},   :foo) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(nil,            {:type => Thrift::Types::VOID},   :foo) }.not_to raise_error
+      expect { Thrift.check_type(3,              {:type => Thrift::Types::VOID},   :foo) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(true,           {:type => Thrift::Types::BOOL},   :foo) }.not_to raise_error
+      expect { Thrift.check_type(3,              {:type => Thrift::Types::BOOL},   :foo) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(42,             {:type => Thrift::Types::BYTE},   :foo) }.not_to raise_error
+      expect { Thrift.check_type(42,             {:type => Thrift::Types::I16},    :foo) }.not_to raise_error
+      expect { Thrift.check_type(42,             {:type => Thrift::Types::I32},    :foo) }.not_to raise_error
+      expect { Thrift.check_type(42,             {:type => Thrift::Types::I64},    :foo) }.not_to raise_error
+      expect { Thrift.check_type(3.14,           {:type => Thrift::Types::I32},    :foo) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(3.14,           {:type => Thrift::Types::DOUBLE}, :foo) }.not_to raise_error
+      expect { Thrift.check_type(3,              {:type => Thrift::Types::DOUBLE}, :foo) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type("3",            {:type => Thrift::Types::STRING}, :foo) }.not_to raise_error
+      expect { Thrift.check_type(3,              {:type => Thrift::Types::STRING}, :foo) }.to raise_error(Thrift::TypeError)
       hello = SpecNamespace::Hello.new
-      lambda { Thrift.check_type(hello,          {:type => Thrift::Types::STRUCT, :class => SpecNamespace::Hello}, :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type("foo",          {:type => Thrift::Types::STRUCT}, :foo) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type({:foo => 1},    {:type => Thrift::Types::MAP},    :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type([1],            {:type => Thrift::Types::MAP},    :foo) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type([1],            {:type => Thrift::Types::LIST},   :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type({:foo => 1},    {:type => Thrift::Types::LIST},   :foo) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(Set.new([1,2]), {:type => Thrift::Types::SET},    :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type([1,2],          {:type => Thrift::Types::SET},    :foo) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type({:foo => true}, {:type => Thrift::Types::SET},    :foo) }.should raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(hello,          {:type => Thrift::Types::STRUCT, :class => SpecNamespace::Hello}, :foo) }.not_to raise_error
+      expect { Thrift.check_type("foo",          {:type => Thrift::Types::STRUCT}, :foo) }.to raise_error(Thrift::TypeError)
+      field = {:type => Thrift::Types::MAP, :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRING}}
+      expect { Thrift.check_type({1 => "one"},   field,                            :foo) }.not_to raise_error
+      expect { Thrift.check_type([1],            field,                            :foo) }.to raise_error(Thrift::TypeError)
+      field = {:type => Thrift::Types::LIST, :element => {:type => Thrift::Types::I32}}
+      expect { Thrift.check_type([1],            field,                            :foo) }.not_to raise_error
+      expect { Thrift.check_type({:foo => 1},    field,                            :foo) }.to raise_error(Thrift::TypeError)
+      field = {:type => Thrift::Types::SET, :element => {:type => Thrift::Types::I32}}
+      expect { Thrift.check_type(Set.new([1,2]), field,                            :foo) }.not_to raise_error
+      expect { Thrift.check_type([1,2],          field,                            :foo) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type({:foo => true}, field,                            :foo) }.to raise_error(Thrift::TypeError)
     end
 
     it "should error out if nil is passed and skip_types is false" do
-      lambda { Thrift.check_type(nil, {:type => Thrift::Types::BOOL},   :foo, false) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(nil, {:type => Thrift::Types::BYTE},   :foo, false) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(nil, {:type => Thrift::Types::I16},    :foo, false) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(nil, {:type => Thrift::Types::I32},    :foo, false) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(nil, {:type => Thrift::Types::I64},    :foo, false) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(nil, {:type => Thrift::Types::DOUBLE}, :foo, false) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(nil, {:type => Thrift::Types::STRING}, :foo, false) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(nil, {:type => Thrift::Types::STRUCT}, :foo, false) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(nil, {:type => Thrift::Types::LIST},   :foo, false) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(nil, {:type => Thrift::Types::SET},    :foo, false) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(nil, {:type => Thrift::Types::MAP},    :foo, false) }.should raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(nil, {:type => Thrift::Types::BOOL},   :foo, false) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(nil, {:type => Thrift::Types::BYTE},   :foo, false) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(nil, {:type => Thrift::Types::I16},    :foo, false) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(nil, {:type => Thrift::Types::I32},    :foo, false) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(nil, {:type => Thrift::Types::I64},    :foo, false) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(nil, {:type => Thrift::Types::DOUBLE}, :foo, false) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(nil, {:type => Thrift::Types::STRING}, :foo, false) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(nil, {:type => Thrift::Types::STRUCT}, :foo, false) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(nil, {:type => Thrift::Types::LIST},   :foo, false) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(nil, {:type => Thrift::Types::SET},    :foo, false) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(nil, {:type => Thrift::Types::MAP},    :foo, false) }.to raise_error(Thrift::TypeError)
     end
 
     it "should check element types on containers" do
       field = {:type => Thrift::Types::LIST, :element => {:type => Thrift::Types::I32}}
-      lambda { Thrift.check_type([1, 2], field, :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type([1, nil, 2], field, :foo) }.should raise_error(Thrift::TypeError)
+      expect { Thrift.check_type([1, 2], field, :foo) }.not_to raise_error
+      expect { Thrift.check_type([1, nil, 2], field, :foo) }.to raise_error(Thrift::TypeError)
       field = {:type => Thrift::Types::MAP, :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRING}}
-      lambda { Thrift.check_type({1 => "one", 2 => "two"}, field, :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type({1 => "one", nil => "nil"}, field, :foo) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type({1 => nil, 2 => "two"}, field, :foo) }.should raise_error(Thrift::TypeError)
+      expect { Thrift.check_type({1 => "one", 2 => "two"}, field, :foo) }.not_to raise_error
+      expect { Thrift.check_type({1 => "one", nil => "nil"}, field, :foo) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type({1 => nil, 2 => "two"}, field, :foo) }.to raise_error(Thrift::TypeError)
       field = {:type => Thrift::Types::SET, :element => {:type => Thrift::Types::I32}}
-      lambda { Thrift.check_type(Set.new([1, 2]), field, :foo) }.should_not raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(Set.new([1, nil, 2]), field, :foo) }.should raise_error(Thrift::TypeError)
-      lambda { Thrift.check_type(Set.new([1, 2.3, 2]), field, :foo) }.should raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(Set.new([1, 2]), field, :foo) }.not_to raise_error
+      expect { Thrift.check_type(Set.new([1, nil, 2]), field, :foo) }.to raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(Set.new([1, 2.3, 2]), field, :foo) }.to raise_error(Thrift::TypeError)
 
       field = {:type => Thrift::Types::STRUCT, :class => SpecNamespace::Hello}
-      lambda { Thrift.check_type(SpecNamespace::BoolStruct, field, :foo) }.should raise_error(Thrift::TypeError)
+      expect { Thrift.check_type(SpecNamespace::BoolStruct, field, :foo) }.to raise_error(Thrift::TypeError)
     end
 
     it "should give the Thrift::TypeError a readable message" do
-      msg = "Expected Types::STRING, received Fixnum for field foo"
-      lambda { Thrift.check_type(3, {:type => Thrift::Types::STRING}, :foo) }.should raise_error(Thrift::TypeError, msg)
-      msg = "Expected Types::STRING, received Fixnum for field foo.element"
+      msg = /Expected Types::STRING, received (Integer|Fixnum) for field foo/
+      expect { Thrift.check_type(3, {:type => Thrift::Types::STRING}, :foo) }.to raise_error(Thrift::TypeError, msg)
+      msg = /Expected Types::STRING, received (Integer|Fixnum) for field foo.element/
       field = {:type => Thrift::Types::LIST, :element => {:type => Thrift::Types::STRING}}
-      lambda { Thrift.check_type([3], field, :foo) }.should raise_error(Thrift::TypeError, msg)
+      expect { Thrift.check_type([3], field, :foo) }.to raise_error(Thrift::TypeError, msg)
       msg = "Expected Types::I32, received NilClass for field foo.element.key"
       field = {:type => Thrift::Types::LIST,
                :element => {:type => Thrift::Types::MAP,
                             :key => {:type => Thrift::Types::I32},
                             :value => {:type => Thrift::Types::I32}}}
-      lambda { Thrift.check_type([{nil => 3}], field, :foo) }.should raise_error(Thrift::TypeError, msg)
+      expect { Thrift.check_type([{nil => 3}], field, :foo) }.to raise_error(Thrift::TypeError, msg)
       msg = "Expected Types::I32, received NilClass for field foo.element.value"
-      lambda { Thrift.check_type([{1 => nil}], field, :foo) }.should raise_error(Thrift::TypeError, msg)
+      expect { Thrift.check_type([{1 => nil}], field, :foo) }.to raise_error(Thrift::TypeError, msg)
     end
   end
 end
diff --git a/lib/rb/spec/union_spec.rb b/lib/rb/spec/union_spec.rb
index dd84906..0ce6306 100644
--- a/lib/rb/spec/union_spec.rb
+++ b/lib/rb/spec/union_spec.rb
@@ -24,73 +24,85 @@
   describe Thrift::Union do
     it "should return nil value in unset union" do
       union = SpecNamespace::My_union.new
-      union.get_set_field.should == nil
-      union.get_value.should == nil
+      expect(union.get_set_field).to eq(nil)
+      expect(union.get_value).to eq(nil)
     end
 
     it "should set a field and be accessible through get_value and the named field accessor" do
       union = SpecNamespace::My_union.new
       union.integer32 = 25
-      union.get_set_field.should == :integer32
-      union.get_value.should == 25
-      union.integer32.should == 25
+      expect(union.get_set_field).to eq(:integer32)
+      expect(union.get_value).to eq(25)
+      expect(union.integer32).to eq(25)
     end
 
     it "should work correctly when instantiated with static field constructors" do
       union = SpecNamespace::My_union.integer32(5)
-      union.get_set_field.should == :integer32
-      union.integer32.should == 5
+      expect(union.get_set_field).to eq(:integer32)
+      expect(union.integer32).to eq(5)
     end
 
     it "should raise for wrong set field" do
       union = SpecNamespace::My_union.new
       union.integer32 = 25
-      lambda { union.some_characters }.should raise_error(RuntimeError, "some_characters is not union's set field.")
+      expect { union.some_characters }.to raise_error(RuntimeError, "some_characters is not union's set field.")
+    end
+
+    it "should raise for wrong set field when hash initialized and type checking is off" do
+      Thrift.type_checking = false
+      union = SpecNamespace::My_union.new({incorrect_field: :incorrect})
+      example = lambda { Thrift::Serializer.new.serialize(union) }
+      expect(example).to raise_error(RuntimeError, "set_field is not valid for this union!")
     end
 
     it "should not be equal to nil" do
       union = SpecNamespace::My_union.new
-      union.should_not == nil
+      expect(union).not_to eq(nil)
+    end
+
+    it "should not be equal with an empty String" do
+      union = SpecNamespace::My_union.new
+      expect(union).not_to eq('')
     end
 
     it "should not equate two different unions, i32 vs. string" do
       union = SpecNamespace::My_union.new(:integer32, 25)
       other_union = SpecNamespace::My_union.new(:some_characters, "blah!")
-      union.should_not == other_union
+      expect(union).not_to eq(other_union)
     end
 
     it "should properly reset setfield and setvalue" do
       union = SpecNamespace::My_union.new(:integer32, 25)
-      union.get_set_field.should == :integer32
+      expect(union.get_set_field).to eq(:integer32)
       union.some_characters = "blah!"
-      union.get_set_field.should == :some_characters
-      union.get_value.should == "blah!"
-      lambda { union.integer32 }.should raise_error(RuntimeError, "integer32 is not union's set field.")
+      expect(union.get_set_field).to eq(:some_characters)
+      expect(union.get_value).to eq("blah!")
+      expect { union.integer32 }.to raise_error(RuntimeError, "integer32 is not union's set field.")
     end
 
     it "should not equate two different unions with different values" do
       union = SpecNamespace::My_union.new(:integer32, 25)
       other_union = SpecNamespace::My_union.new(:integer32, 400)
-      union.should_not == other_union
+      expect(union).not_to eq(other_union)
     end
 
     it "should not equate two different unions with different fields" do
       union = SpecNamespace::My_union.new(:integer32, 25)
       other_union = SpecNamespace::My_union.new(:other_i32, 25)
-      union.should_not == other_union
+      expect(union).not_to eq(other_union)
     end
 
     it "should inspect properly" do
       union = SpecNamespace::My_union.new(:integer32, 25)
-      union.inspect.should == "<SpecNamespace::My_union integer32: 25>"
+      expect(union.inspect).to eq("<SpecNamespace::My_union integer32: 25>")
     end
 
     it "should not allow setting with instance_variable_set" do
       union = SpecNamespace::My_union.new(:integer32, 27)
       union.instance_variable_set(:@some_characters, "hallo!")
-      union.get_set_field.should == :integer32
-      union.get_value.should == 27
-      lambda { union.some_characters }.should raise_error(RuntimeError, "some_characters is not union's set field.")
+      expect(union.get_set_field).to eq(:integer32)
+      expect(union.get_value).to eq(27)
+      expect { union.some_characters }.to raise_error(RuntimeError, "some_characters is not union's set field.")
     end
 
     it "should serialize to binary correctly" do
@@ -102,7 +114,7 @@
 
       other_union = SpecNamespace::My_union.new(:integer32, 25)
       other_union.read(proto)
-      other_union.should == union
+      expect(other_union).to eq(union)
     end
 
     it "should serialize to json correctly" do
@@ -114,24 +126,24 @@
 
       other_union = SpecNamespace::My_union.new(:integer32, 25)
       other_union.read(proto)
-      other_union.should == union
+      expect(other_union).to eq(union)
     end
 
     it "should raise when validating unset union" do
       union = SpecNamespace::My_union.new
-      lambda { union.validate }.should raise_error(StandardError, "Union fields are not set.")
+      expect { union.validate }.to raise_error(StandardError, "Union fields are not set.")
 
       other_union = SpecNamespace::My_union.new(:integer32, 1)
-      lambda { other_union.validate }.should_not raise_error(StandardError, "Union fields are not set.")
+      expect { other_union.validate }.not_to raise_error
     end
 
     it "should validate an enum field properly" do
       union = SpecNamespace::TestUnion.new(:enum_field, 3)
-      union.get_set_field.should == :enum_field
-      lambda { union.validate }.should raise_error(Thrift::ProtocolException, "Invalid value of field enum_field!")
+      expect(union.get_set_field).to eq(:enum_field)
+      expect { union.validate }.to raise_error(Thrift::ProtocolException, "Invalid value of field enum_field!")
 
       other_union = SpecNamespace::TestUnion.new(:enum_field, 1)
-      lambda { other_union.validate }.should_not raise_error(Thrift::ProtocolException, "Invalid value of field enum_field!")
+      expect { other_union.validate }.not_to raise_error
     end
 
     it "should properly serialize and match structs with a union" do
@@ -146,37 +158,37 @@
       other_union = SpecNamespace::My_union.new(:some_characters, "hello there")
       swu2 = SpecNamespace::Struct_with_union.new(:fun_union => other_union)
 
-      swu2.should_not == swu
+      expect(swu2).not_to eq(swu)
 
       swu2.read(proto)
-      swu2.should == swu
+      expect(swu2).to eq(swu)
     end
 
     it "should support old style constructor" do
       union = SpecNamespace::My_union.new(:integer32 => 26)
-      union.get_set_field.should == :integer32
-      union.get_value.should == 26
+      expect(union.get_set_field).to eq(:integer32)
+      expect(union.get_value).to eq(26)
     end
 
     it "should not throw an error when inspected and unset" do
-      lambda{SpecNamespace::TestUnion.new().inspect}.should_not raise_error
+      expect{SpecNamespace::TestUnion.new().inspect}.not_to raise_error
     end
 
     it "should print enum value name when inspected" do
-      SpecNamespace::My_union.new(:some_enum => SpecNamespace::SomeEnum::ONE).inspect.should == "<SpecNamespace::My_union some_enum: ONE (0)>"
+      expect(SpecNamespace::My_union.new(:some_enum => SpecNamespace::SomeEnum::ONE).inspect).to eq("<SpecNamespace::My_union some_enum: ONE (0)>")
 
-      SpecNamespace::My_union.new(:my_map => {SpecNamespace::SomeEnum::ONE => [SpecNamespace::SomeEnum::TWO]}).inspect.should == "<SpecNamespace::My_union my_map: {ONE (0): [TWO (1)]}>"
+      expect(SpecNamespace::My_union.new(:my_map => {SpecNamespace::SomeEnum::ONE => [SpecNamespace::SomeEnum::TWO]}).inspect).to eq("<SpecNamespace::My_union my_map: {ONE (0): [TWO (1)]}>")
     end
 
     it "should offer field? methods" do
-      SpecNamespace::My_union.new.some_enum?.should be_false
-      SpecNamespace::My_union.new(:some_enum => SpecNamespace::SomeEnum::ONE).some_enum?.should be_true
-      SpecNamespace::My_union.new(:im_true => false).im_true?.should be_true
-      SpecNamespace::My_union.new(:im_true => true).im_true?.should be_true
+      expect(SpecNamespace::My_union.new.some_enum?).to be_falsey
+      expect(SpecNamespace::My_union.new(:some_enum => SpecNamespace::SomeEnum::ONE).some_enum?).to be_truthy
+      expect(SpecNamespace::My_union.new(:im_true => false).im_true?).to be_truthy
+      expect(SpecNamespace::My_union.new(:im_true => true).im_true?).to be_truthy
     end
 
     it "should pretty print binary fields" do
-      SpecNamespace::TestUnion.new(:binary_field => "\001\002\003").inspect.should == "<SpecNamespace::TestUnion binary_field: 010203>"
+      expect(SpecNamespace::TestUnion.new(:binary_field => "\001\002\003").inspect).to eq("<SpecNamespace::TestUnion binary_field: 010203>")
     end
 
     it "should be comparable" do
@@ -195,7 +207,7 @@
       for y in 0..3
         for x in 0..3
           # puts "#{objs[y].inspect} <=> #{objs[x].inspect} should == #{relationships[y][x]}"
-          (objs[y] <=> objs[x]).should == relationships[y][x]
+          expect(objs[y] <=> objs[x]).to eq(relationships[y][x])
         end
       end
     end
diff --git a/lib/rb/spec/unix_socket_spec.rb b/lib/rb/spec/unix_socket_spec.rb
index cb6cff3..8623e95 100644
--- a/lib/rb/spec/unix_socket_spec.rb
+++ b/lib/rb/spec/unix_socket_spec.rb
@@ -26,21 +26,26 @@
     before(:each) do
       @path = '/tmp/thrift_spec_socket'
       @socket = Thrift::UNIXSocket.new(@path)
-      @handle = mock("Handle", :closed? => false)
-      @handle.stub!(:close)
-      ::UNIXSocket.stub!(:new).and_return(@handle)
+      @handle = double("Handle", :closed? => false)
+      allow(@handle).to receive(:close)
+      allow(::UNIXSocket).to receive(:new).and_return(@handle)
     end
 
     it_should_behave_like "a socket"
 
     it "should raise a TransportException when it cannot open a socket" do
-      ::UNIXSocket.should_receive(:new).and_raise(StandardError)
-      lambda { @socket.open }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::NOT_OPEN }
+      expect(::UNIXSocket).to receive(:new).and_raise(StandardError)
+      expect { @socket.open }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) }
     end
 
     it "should accept an optional timeout" do
-      ::UNIXSocket.stub!(:new)
-      Thrift::UNIXSocket.new(@path, 5).timeout.should == 5
+      allow(::UNIXSocket).to receive(:new)
+      expect(Thrift::UNIXSocket.new(@path, 5).timeout).to eq(5)
+    end
+    
+    it "should provide a reasonable to_s" do
+      allow(::UNIXSocket).to receive(:new)
+      expect(Thrift::UNIXSocket.new(@path).to_s).to eq("domain(#{@path})")
     end
   end
 
@@ -51,57 +56,61 @@
     end
 
     it "should create a handle when calling listen" do
-      UNIXServer.should_receive(:new).with(@path)
+      expect(UNIXServer).to receive(:new).with(@path)
       @socket.listen
     end
 
     it "should create a Thrift::UNIXSocket to wrap accepted sockets" do
-      handle = mock("UNIXServer")
-      UNIXServer.should_receive(:new).with(@path).and_return(handle)
+      handle = double("UNIXServer")
+      expect(UNIXServer).to receive(:new).with(@path).and_return(handle)
       @socket.listen
-      sock = mock("sock")
-      handle.should_receive(:accept).and_return(sock)
-      trans = mock("UNIXSocket")
-      Thrift::UNIXSocket.should_receive(:new).and_return(trans)
-      trans.should_receive(:handle=).with(sock)
-      @socket.accept.should == trans
+      sock = double("sock")
+      expect(handle).to receive(:accept).and_return(sock)
+      trans = double("UNIXSocket")
+      expect(Thrift::UNIXSocket).to receive(:new).and_return(trans)
+      expect(trans).to receive(:handle=).with(sock)
+      expect(@socket.accept).to eq(trans)
     end
 
     it "should close the handle when closed" do
-      handle = mock("UNIXServer", :closed? => false)
-      UNIXServer.should_receive(:new).with(@path).and_return(handle)
+      handle = double("UNIXServer", :closed? => false)
+      expect(UNIXServer).to receive(:new).with(@path).and_return(handle)
       @socket.listen
-      handle.should_receive(:close)
-      File.stub!(:delete)
+      expect(handle).to receive(:close)
+      allow(File).to receive(:delete)
       @socket.close
     end
 
     it "should delete the socket when closed" do
-      handle = mock("UNIXServer", :closed? => false)
-      UNIXServer.should_receive(:new).with(@path).and_return(handle)
+      handle = double("UNIXServer", :closed? => false)
+      expect(UNIXServer).to receive(:new).with(@path).and_return(handle)
       @socket.listen
-      handle.stub!(:close)
-      File.should_receive(:delete).with(@path)
+      allow(handle).to receive(:close)
+      expect(File).to receive(:delete).with(@path)
       @socket.close
     end
 
     it "should return nil when accepting if there is no handle" do
-      @socket.accept.should be_nil
+      expect(@socket.accept).to be_nil
     end
 
     it "should return true for closed? when appropriate" do
-      handle = mock("UNIXServer", :closed? => false)
-      UNIXServer.stub!(:new).and_return(handle)
-      File.stub!(:delete)
+      handle = double("UNIXServer", :closed? => false)
+      allow(UNIXServer).to receive(:new).and_return(handle)
+      allow(File).to receive(:delete)
       @socket.listen
-      @socket.should_not be_closed
-      handle.stub!(:close)
+      expect(@socket).not_to be_closed
+      allow(handle).to receive(:close)
       @socket.close
-      @socket.should be_closed
+      expect(@socket).to be_closed
       @socket.listen
-      @socket.should_not be_closed
-      handle.stub!(:closed?).and_return(true)
-      @socket.should be_closed
+      expect(@socket).not_to be_closed
+      allow(handle).to receive(:closed?).and_return(true)
+      expect(@socket).to be_closed
+    end
+
+    it "should provide a reasonable to_s" do
+      expect(@socket.to_s).to eq("domain(#{@path})")
     end
   end
 end
diff --git a/lib/rb/thrift.gemspec b/lib/rb/thrift.gemspec
index daff1de..e53194e 100644
--- a/lib/rb/thrift.gemspec
+++ b/lib/rb/thrift.gemspec
@@ -3,14 +3,14 @@
 
 Gem::Specification.new do |s|
   s.name        = 'thrift'
-  s.version     = '0.9.1.1'
-  s.authors     = ['Thrift Developers']
+  s.version     = '1.0.0'
+  s.authors     = ['Apache Thrift Developers']
   s.email       = ['dev@thrift.apache.org']
   s.homepage    = 'http://thrift.apache.org'
   s.summary     = %q{Ruby bindings for Apache Thrift}
   s.description = %q{Ruby bindings for the Apache Thrift RPC system}
-  s.license = 'Apache 2.0'
-  s.extensions = ['ext/extconf.rb']
+  s.license     = 'Apache-2.0'
+  s.extensions  = ['ext/extconf.rb']
 
   s.has_rdoc      = true
   s.rdoc_options  = %w[--line-numbers --inline-source --title Thrift --main README]
@@ -23,15 +23,18 @@
   s.test_files = Dir.glob("{test,spec,benchmark}/**/*")
   s.executables =  Dir.glob("{bin}/**/*")
 
-  s.extra_rdoc_files  = %w[CHANGELOG README] + Dir.glob("{ext,lib}/**/*.{c,h,rb}")
+  s.extra_rdoc_files  = %w[README.md] + Dir.glob("{ext,lib}/**/*.{c,h,rb}")
 
   s.require_paths = %w[lib ext]
 
-  s.add_development_dependency 'rspec', '~> 2.10.0'
-  s.add_development_dependency "rack", "~> 1.5.2"
-  s.add_development_dependency "rack-test", "~> 0.6.2"
-  s.add_development_dependency "thin", "~> 1.5.0"
-  s.add_development_dependency "bundler", "~> 1.3.1"
-  s.add_development_dependency 'rake'
+  s.add_development_dependency 'bundler',            '~> 1.11'
+  s.add_development_dependency 'pry',                '~> 0.11.3'
+  s.add_development_dependency 'pry-byebug',         '~> 3.6'
+  s.add_development_dependency 'pry-stack_explorer', '~> 0.4.9.2'
+  s.add_development_dependency 'rack',               '~> 2.0'
+  s.add_development_dependency 'rack-test',          '~> 0.8.3'
+  s.add_development_dependency 'rake',               '~> 12.3'
+  s.add_development_dependency 'rspec',              '~> 3.7'
+  s.add_development_dependency 'thin',               '~> 1.7'
 end
 
diff --git a/lib/rs/Cargo.toml b/lib/rs/Cargo.toml
new file mode 100644
index 0000000..ed32179
--- /dev/null
+++ b/lib/rs/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "thrift"
+description = "Rust bindings for the Apache Thrift RPC system"
+version = "1.0.0"
+license = "Apache-2.0"
+authors = ["Apache Thrift Developers <dev@thrift.apache.org>"]
+homepage = "http://thrift.apache.org"
+documentation = "https://thrift.apache.org"
+readme = "README.md"
+exclude = ["Makefile*", "test/**", "*.iml"]
+keywords = ["thrift"]
+
+[dependencies]
+byteorder = "~1.2.1"
+integer-encoding = "~1.0.4"
+log = "~0.3.8"
+threadpool = "~1.7.1"
+try_from = "~0.2.2"
+
diff --git a/lib/rs/Makefile.am b/lib/rs/Makefile.am
new file mode 100644
index 0000000..0a34120
--- /dev/null
+++ b/lib/rs/Makefile.am
@@ -0,0 +1,46 @@
+#
+# 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.
+#
+
+SUBDIRS = .
+
+if WITH_TESTS
+SUBDIRS += test
+endif
+
+install:
+	@echo '##############################################################'
+	@echo '##############################################################'
+	@echo 'The Rust client library should be installed via a Cargo.toml dependency - please see /lib/rs/README.md'
+	@echo '##############################################################'
+	@echo '##############################################################'
+
+check-local:
+	$(CARGO) test
+
+all-local:
+	$(CARGO) build
+
+clean-local:
+	$(CARGO) clean
+	-$(RM) Cargo.lock
+
+EXTRA_DIST = \
+	src \
+	Cargo.toml \
+	README.md
diff --git a/lib/rs/README.md b/lib/rs/README.md
new file mode 100644
index 0000000..7c37a10
--- /dev/null
+++ b/lib/rs/README.md
@@ -0,0 +1,111 @@
+# Rust Thrift library
+
+## Overview
+
+This crate implements the components required to build a working Thrift server
+and client. It is divided into the following modules:
+
+ 1. errors
+ 2. protocol
+ 3. transport
+ 4. server
+ 5. autogen
+
+The modules are layered as shown. The `generated` layer is code generated by the
+Thrift compiler's Rust plugin. It uses the components defined in this crate to
+serialize and deserialize types and implement RPC. Users interact with these
+types and services by writing their own code on top.
+
+ ```text
+ +-----------+
+ |  app dev  |
+ +-----------+
+ | generated | <-> errors/results
+ +-----------+
+ |  protocol |
+ +-----------+
+ | transport |
+ +-----------+
+ ```
+
+## Using this crate
+
+Add `thrift = "x.y.z"` to your `Cargo.toml`, where `x.y.z` is the version of the
+Thrift compiler you're using.
+
+## API Documentation
+
+Full [Rustdoc](https://docs.rs/thrift/)
+
+## Compatibility
+
+The Rust library and auto-generated code targets Rust versions 1.28+.
+It does not currently use any Rust 2018 features.
+
+### Breaking Changes
+
+Breaking changes are minimized. When they are made they will be outlined below with transition guidelines.
+
+##### Thrift 0.12.0
+
+* **[THRIFT-4529]** - Rust enum variants are now camel-cased instead of uppercased to conform to Rust naming conventions
+
+    Previously, enum variants were uppercased in the auto-generated code.
+    For example, the following thrift enum:
+
+    ```thrift
+    // THRIFT
+    enum Operation {
+      ADD,
+      SUBTRACT,
+      MULTIPLY,
+      DIVIDE,
+    }
+    ```
+    
+    used to generate:
+    
+    ```rust
+    // OLD AUTO-GENERATED RUST
+    pub enum Operation {
+       ADD,
+       SUBTRACT,
+       MULTIPLY,
+       DIVIDE,
+     }
+    ```
+    It *now* generates:
+    ```rust
+    // NEW AUTO-GENERATED RUST
+    pub enum Operation {
+       Add,
+       Subtract,
+       Multiply,
+       Divide,
+     }
+    ```
+    
+    You will have to change all enum variants in your code to use camel-cased names.
+    This should be a search and replace.
+
+## Contributing
+
+Bug reports and PRs are always welcome! Please see the
+[Thrift website](https://thrift.apache.org/) for more details.
+
+Thrift Rust support requires code in several directories:
+
+* `compiler/cpp/src/thrift/generate/t_rs_generator.cc`: binding code generator
+* `lib/rs`: runtime library
+* `lib/rs/test`: supplemental tests
+* `tutorial/rs`: tutorial client and server
+* `test/rs`: cross-language test client and server
+
+All library code, test code and auto-generated code compiles and passes clippy
+without warnings. All new code must do the same! When making changes ensure that:
+
+* `rustc` does does output any warnings
+* `clippy` with default settings does not output any warnings (includes auto-generated code)
+* `cargo test` is successful
+* `make precross` and `make check` are successful
+* `tutorial/bin/tutorial_client` and `tutorial/bin/tutorial_server` communicate
diff --git a/lib/rs/RELEASING.md b/lib/rs/RELEASING.md
new file mode 100644
index 0000000..073d7a0
--- /dev/null
+++ b/lib/rs/RELEASING.md
@@ -0,0 +1,57 @@
+# Publishing the thrift crate
+
+Publishing the Rust thrift crate is straightforward, and involves two major steps:
+
+1. Setting up your [crates.io](https://www.crates.io) account _(one-time)_
+
+2. Packaging/publishing the Rust thrift crate itself
+
+## Set up your crates.io account (one-time)
+
+1. Go to [crates.io](https://www.crates.io) and click the `Log In` button at the top right.
+
+   Log in **as the Github user with write permissions to the thrift repo!**
+
+2. Click your user icon button at the top right and select `Account Settings`.
+
+3. Click `New Token` next to `API Access`.
+
+   This generates a new API key that cargo uses to publish packages to crates.io.
+   Store this API key somewhere safe. If you will only use this Github account to
+   publish crates to crates.io you can follow the instructions to save the
+   generated key to `~/.cargo/credentials`.
+
+## Package and Publish
+
+You can use the automated script or run the release steps manually.
+
+**Important**: `cargo` expects that version numbers follow the semantic versioning format.
+This means that `THRIFT_RELEASE_VERSION` must have a major, minor and patch number, i.e., must
+be in the form `#.##.##`.
+
+#### Automated
+
+Run `./release.sh [THRIFT_RELEASE_VERSION]`.
+
+_Requires you to have stored your credentials in `~/.cargo/credentials`._
+
+#### Manual
+
+1. Edit `Cargo.toml` and update the `version = 1.0` key to `version = [THRIFT_RELEASE_VERSION]`
+
+2. `git add Cargo.toml`
+
+3. `git commit -m "Update thrift crate version to [THRIFT_RELEASE_VERSION]" -m "Client: rs"`
+
+4. `cargo login`
+
+    _(not required if you have stored your credentials in `~/.cargo/credentials`)_
+
+5. `cargo clean`
+
+6. `cargo package`
+
+   This step fails if there are any uncommitted or ignored files. Do **not** use the `--allow-dirty`
+   flag! Instead, add the highlighted files as entries in the `Cargo.toml` `exclude` key.
+
+7. `cargo publish`
diff --git a/lib/rs/release.sh b/lib/rs/release.sh
new file mode 100755
index 0000000..c4e5b48
--- /dev/null
+++ b/lib/rs/release.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+set -o errexit
+set -o pipefail
+set -o nounset
+
+if ! [[ $# -eq 1 && $1 =~ ^[0-9](\.[0-9][0-9]*){2}$ ]]; then
+    (>&2 echo "Usage: ./publish-crate.sh [THRIFT_RELEASE_VERSION] ")
+    (>&2 echo "       THRIFT_RELEASE_VERSION is in semantic versioning format, i.e. #.##.##")
+    exit 1
+fi
+
+THRIFT_RELEASE_VERSION=${1:-}
+
+echo "Updating Cargo.toml to ${THRIFT_RELEASE_VERSION}"
+sed -i.old -e "s/^version = .*$/version = \"${THRIFT_RELEASE_VERSION}\"/g" Cargo.toml
+rm Cargo.toml.old
+
+echo "Committing updated Cargo.toml"
+git add Cargo.toml
+git commit -m "Update thrift crate version to ${THRIFT_RELEASE_VERSION}" -m "Client: rs"
+
+echo "Packaging and releasing rust thrift crate with version ${THRIFT_RELEASE_VERSION}"
+cargo clean
+cargo package
+cargo publish
diff --git a/lib/rs/src/autogen.rs b/lib/rs/src/autogen.rs
new file mode 100644
index 0000000..54d4080
--- /dev/null
+++ b/lib/rs/src/autogen.rs
@@ -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.
+
+//! Thrift compiler auto-generated support.
+//!
+//!
+//! Types and functions used internally by the Thrift compiler's Rust plugin
+//! to implement required functionality. Users should never have to use code
+//! in this module directly.
+
+use protocol::{TInputProtocol, TOutputProtocol};
+
+/// Specifies the minimum functionality an auto-generated client should provide
+/// to communicate with a Thrift server.
+pub trait TThriftClient {
+    /// Returns the input protocol used to read serialized Thrift messages
+    /// from the Thrift server.
+    fn i_prot_mut(&mut self) -> &mut TInputProtocol;
+    /// Returns the output protocol used to write serialized Thrift messages
+    /// to the Thrift server.
+    fn o_prot_mut(&mut self) -> &mut TOutputProtocol;
+    /// Returns the sequence number of the last message written to the Thrift
+    /// server. Returns `0` if no messages have been written. Sequence
+    /// numbers should *never* be negative, and this method returns an `i32`
+    /// simply because the Thrift protocol encodes sequence numbers as `i32` on
+    /// the wire.
+    fn sequence_number(&self) -> i32; // FIXME: consider returning a u32
+    /// Increments the sequence number, indicating that a message with that
+    /// number has been sent to the Thrift server.
+    fn increment_sequence_number(&mut self) -> i32;
+}
diff --git a/lib/rs/src/errors.rs b/lib/rs/src/errors.rs
new file mode 100644
index 0000000..16a2576
--- /dev/null
+++ b/lib/rs/src/errors.rs
@@ -0,0 +1,670 @@
+// 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.
+
+use std::convert::{From, Into};
+use std::error::Error as StdError;
+use std::fmt::{Debug, Display, Formatter};
+use std::{error, fmt, io, string};
+use try_from::TryFrom;
+
+use protocol::{TFieldIdentifier, TInputProtocol, TOutputProtocol, TStructIdentifier, TType};
+
+// FIXME: should all my error structs impl error::Error as well?
+// FIXME: should all fields in TransportError, ProtocolError and ApplicationError be optional?
+
+/// Error type returned by all runtime library functions.
+///
+/// `thrift::Error` is used throughout this crate as well as in auto-generated
+/// Rust code. It consists of four variants defined by convention across Thrift
+/// implementations:
+///
+/// 1. `Transport`: errors encountered while operating on I/O channels
+/// 2. `Protocol`: errors encountered during runtime-library processing
+/// 3. `Application`: errors encountered within auto-generated code
+/// 4. `User`: IDL-defined exception structs
+///
+/// The `Application` variant also functions as a catch-all: all handler errors
+/// are automatically turned into application errors.
+///
+/// All error variants except `Error::User` take an eponymous struct with two
+/// required fields:
+///
+/// 1. `kind`: variant-specific enum identifying the error sub-type
+/// 2. `message`: human-readable error info string
+///
+/// `kind` is defined by convention while `message` is freeform. If none of the
+/// enumerated kinds are suitable use `Unknown`.
+///
+/// To simplify error creation convenience constructors are defined for all
+/// variants, and conversions from their structs (`thrift::TransportError`,
+/// `thrift::ProtocolError` and `thrift::ApplicationError` into `thrift::Error`.
+///
+/// # Examples
+///
+/// Create a `TransportError`.
+///
+/// ```
+/// use thrift;
+/// use thrift::{TransportError, TransportErrorKind};
+///
+/// // explicit
+/// let err0: thrift::Result<()> = Err(
+///   thrift::Error::Transport(
+///     TransportError {
+///       kind: TransportErrorKind::TimedOut,
+///       message: format!("connection to server timed out")
+///     }
+///   )
+/// );
+///
+/// // use conversion
+/// let err1: thrift::Result<()> = Err(
+///   thrift::Error::from(
+///     TransportError {
+///       kind: TransportErrorKind::TimedOut,
+///       message: format!("connection to server timed out")
+///     }
+///   )
+/// );
+///
+/// // use struct constructor
+/// let err2: thrift::Result<()> = Err(
+///   thrift::Error::Transport(
+///     TransportError::new(
+///       TransportErrorKind::TimedOut,
+///       "connection to server timed out"
+///     )
+///   )
+/// );
+///
+///
+/// // use error variant constructor
+/// let err3: thrift::Result<()> = Err(
+///   thrift::new_transport_error(
+///     TransportErrorKind::TimedOut,
+///     "connection to server timed out"
+///   )
+/// );
+/// ```
+///
+/// Create an error from a string.
+///
+/// ```
+/// use thrift;
+/// use thrift::{ApplicationError, ApplicationErrorKind};
+///
+/// // we just use `From::from` to convert a `String` into a `thrift::Error`
+/// let err0: thrift::Result<()> = Err(
+///   thrift::Error::from("This is an error")
+/// );
+///
+/// // err0 is equivalent to...
+/// let err1: thrift::Result<()> = Err(
+///   thrift::Error::Application(
+///     ApplicationError {
+///       kind: ApplicationErrorKind::Unknown,
+///       message: format!("This is an error")
+///     }
+///   )
+/// );
+/// ```
+///
+/// Return an IDL-defined exception.
+///
+/// ```text
+/// // Thrift IDL exception definition.
+/// exception Xception {
+///   1: i32 errorCode,
+///   2: string message
+/// }
+/// ```
+///
+/// ```
+/// use std::convert::From;
+/// use std::error::Error;
+/// use std::fmt;
+/// use std::fmt::{Display, Formatter};
+///
+/// // auto-generated by the Thrift compiler
+/// #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+/// pub struct Xception {
+///   pub error_code: Option<i32>,
+///   pub message: Option<String>,
+/// }
+///
+/// // auto-generated by the Thrift compiler
+/// impl Error for Xception {
+///   fn description(&self) -> &str {
+///     "remote service threw Xception"
+///   }
+/// }
+///
+/// // auto-generated by the Thrift compiler
+/// impl From<Xception> for thrift::Error {
+///   fn from(e: Xception) -> Self {
+///     thrift::Error::User(Box::new(e))
+///   }
+/// }
+///
+/// // auto-generated by the Thrift compiler
+/// impl Display for Xception {
+///   fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+///     self.description().fmt(f)
+///   }
+/// }
+///
+/// // in user code...
+/// let err: thrift::Result<()> = Err(
+///   thrift::Error::from(Xception { error_code: Some(1), message: None })
+/// );
+/// ```
+pub enum Error {
+    /// Errors encountered while operating on I/O channels.
+    ///
+    /// These include *connection closed* and *bind failure*.
+    Transport(TransportError),
+    /// Errors encountered during runtime-library processing.
+    ///
+    /// These include *message too large* and *unsupported protocol version*.
+    Protocol(ProtocolError),
+    /// Errors encountered within auto-generated code, or when incoming
+    /// or outgoing messages violate the Thrift spec.
+    ///
+    /// These include *out-of-order messages* and *missing required struct
+    /// fields*.
+    ///
+    /// This variant also functions as a catch-all: errors from handler
+    /// functions are automatically returned as an `ApplicationError`.
+    Application(ApplicationError),
+    /// IDL-defined exception structs.
+    User(Box<error::Error + Sync + Send>),
+}
+
+impl Error {
+    /// Create an `ApplicationError` from its wire representation.
+    ///
+    /// Application code **should never** call this method directly.
+    pub fn read_application_error_from_in_protocol(
+        i: &mut TInputProtocol,
+    ) -> ::Result<ApplicationError> {
+        let mut message = "general remote error".to_owned();
+        let mut kind = ApplicationErrorKind::Unknown;
+
+        i.read_struct_begin()?;
+
+        loop {
+            let field_ident = i.read_field_begin()?;
+
+            if field_ident.field_type == TType::Stop {
+                break;
+            }
+
+            let id = field_ident
+                .id
+                .expect("sender should always specify id for non-STOP field");
+
+            match id {
+                1 => {
+                    let remote_message = i.read_string()?;
+                    i.read_field_end()?;
+                    message = remote_message;
+                }
+                2 => {
+                    let remote_type_as_int = i.read_i32()?;
+                    let remote_kind: ApplicationErrorKind = TryFrom::try_from(remote_type_as_int)
+                        .unwrap_or(ApplicationErrorKind::Unknown);
+                    i.read_field_end()?;
+                    kind = remote_kind;
+                }
+                _ => {
+                    i.skip(field_ident.field_type)?;
+                }
+            }
+        }
+
+        i.read_struct_end()?;
+
+        Ok(ApplicationError {
+            kind: kind,
+            message: message,
+        })
+    }
+
+    /// Convert an `ApplicationError` into its wire representation and write
+    /// it to the remote.
+    ///
+    /// Application code **should never** call this method directly.
+    pub fn write_application_error_to_out_protocol(
+        e: &ApplicationError,
+        o: &mut TOutputProtocol,
+    ) -> ::Result<()> {
+        o.write_struct_begin(&TStructIdentifier {
+            name: "TApplicationException".to_owned(),
+        })?;
+
+        let message_field = TFieldIdentifier::new("message", TType::String, 1);
+        let type_field = TFieldIdentifier::new("type", TType::I32, 2);
+
+        o.write_field_begin(&message_field)?;
+        o.write_string(&e.message)?;
+        o.write_field_end()?;
+
+        o.write_field_begin(&type_field)?;
+        o.write_i32(e.kind as i32)?;
+        o.write_field_end()?;
+
+        o.write_field_stop()?;
+        o.write_struct_end()?;
+
+        o.flush()
+    }
+}
+
+impl error::Error for Error {
+    fn description(&self) -> &str {
+        match *self {
+            Error::Transport(ref e) => TransportError::description(e),
+            Error::Protocol(ref e) => ProtocolError::description(e),
+            Error::Application(ref e) => ApplicationError::description(e),
+            Error::User(ref e) => e.description(),
+        }
+    }
+}
+
+impl Debug for Error {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        match *self {
+            Error::Transport(ref e) => Debug::fmt(e, f),
+            Error::Protocol(ref e) => Debug::fmt(e, f),
+            Error::Application(ref e) => Debug::fmt(e, f),
+            Error::User(ref e) => Debug::fmt(e, f),
+        }
+    }
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        match *self {
+            Error::Transport(ref e) => Display::fmt(e, f),
+            Error::Protocol(ref e) => Display::fmt(e, f),
+            Error::Application(ref e) => Display::fmt(e, f),
+            Error::User(ref e) => Display::fmt(e, f),
+        }
+    }
+}
+
+impl From<String> for Error {
+    fn from(s: String) -> Self {
+        Error::Application(ApplicationError {
+            kind: ApplicationErrorKind::Unknown,
+            message: s,
+        })
+    }
+}
+
+impl<'a> From<&'a str> for Error {
+    fn from(s: &'a str) -> Self {
+        Error::Application(ApplicationError {
+            kind: ApplicationErrorKind::Unknown,
+            message: String::from(s),
+        })
+    }
+}
+
+impl From<TransportError> for Error {
+    fn from(e: TransportError) -> Self {
+        Error::Transport(e)
+    }
+}
+
+impl From<ProtocolError> for Error {
+    fn from(e: ProtocolError) -> Self {
+        Error::Protocol(e)
+    }
+}
+
+impl From<ApplicationError> for Error {
+    fn from(e: ApplicationError) -> Self {
+        Error::Application(e)
+    }
+}
+
+/// Create a new `Error` instance of type `Transport` that wraps a
+/// `TransportError`.
+pub fn new_transport_error<S: Into<String>>(kind: TransportErrorKind, message: S) -> Error {
+    Error::Transport(TransportError::new(kind, message))
+}
+
+/// Information about I/O errors.
+#[derive(Debug, Eq, PartialEq)]
+pub struct TransportError {
+    /// I/O error variant.
+    ///
+    /// If a specific `TransportErrorKind` does not apply use
+    /// `TransportErrorKind::Unknown`.
+    pub kind: TransportErrorKind,
+    /// Human-readable error message.
+    pub message: String,
+}
+
+impl TransportError {
+    /// Create a new `TransportError`.
+    pub fn new<S: Into<String>>(kind: TransportErrorKind, message: S) -> TransportError {
+        TransportError {
+            kind: kind,
+            message: message.into(),
+        }
+    }
+}
+
+/// I/O error categories.
+///
+/// This list may grow, and it is not recommended to match against it.
+#[derive(Clone, Copy, Eq, Debug, PartialEq)]
+pub enum TransportErrorKind {
+    /// Catch-all I/O error.
+    Unknown = 0,
+    /// An I/O operation was attempted when the transport channel was not open.
+    NotOpen = 1,
+    /// The transport channel cannot be opened because it was opened previously.
+    AlreadyOpen = 2,
+    /// An I/O operation timed out.
+    TimedOut = 3,
+    /// A read could not complete because no bytes were available.
+    EndOfFile = 4,
+    /// An invalid (buffer/message) size was requested or received.
+    NegativeSize = 5,
+    /// Too large a buffer or message size was requested or received.
+    SizeLimit = 6,
+}
+
+impl TransportError {
+    fn description(&self) -> &str {
+        match self.kind {
+            TransportErrorKind::Unknown => "transport error",
+            TransportErrorKind::NotOpen => "not open",
+            TransportErrorKind::AlreadyOpen => "already open",
+            TransportErrorKind::TimedOut => "timed out",
+            TransportErrorKind::EndOfFile => "end of file",
+            TransportErrorKind::NegativeSize => "negative size message",
+            TransportErrorKind::SizeLimit => "message too long",
+        }
+    }
+}
+
+impl Display for TransportError {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        write!(f, "{}", self.description())
+    }
+}
+
+impl TryFrom<i32> for TransportErrorKind {
+    type Err = Error;
+    fn try_from(from: i32) -> Result<Self, Self::Err> {
+        match from {
+            0 => Ok(TransportErrorKind::Unknown),
+            1 => Ok(TransportErrorKind::NotOpen),
+            2 => Ok(TransportErrorKind::AlreadyOpen),
+            3 => Ok(TransportErrorKind::TimedOut),
+            4 => Ok(TransportErrorKind::EndOfFile),
+            5 => Ok(TransportErrorKind::NegativeSize),
+            6 => Ok(TransportErrorKind::SizeLimit),
+            _ => Err(Error::Protocol(ProtocolError {
+                kind: ProtocolErrorKind::Unknown,
+                message: format!("cannot convert {} to TransportErrorKind", from),
+            })),
+        }
+    }
+}
+
+impl From<io::Error> for Error {
+    fn from(err: io::Error) -> Self {
+        match err.kind() {
+            io::ErrorKind::ConnectionReset
+            | io::ErrorKind::ConnectionRefused
+            | io::ErrorKind::NotConnected => Error::Transport(TransportError {
+                kind: TransportErrorKind::NotOpen,
+                message: err.description().to_owned(),
+            }),
+            io::ErrorKind::AlreadyExists => Error::Transport(TransportError {
+                kind: TransportErrorKind::AlreadyOpen,
+                message: err.description().to_owned(),
+            }),
+            io::ErrorKind::TimedOut => Error::Transport(TransportError {
+                kind: TransportErrorKind::TimedOut,
+                message: err.description().to_owned(),
+            }),
+            io::ErrorKind::UnexpectedEof => Error::Transport(TransportError {
+                kind: TransportErrorKind::EndOfFile,
+                message: err.description().to_owned(),
+            }),
+            _ => {
+                Error::Transport(TransportError {
+                    kind: TransportErrorKind::Unknown,
+                    message: err.description().to_owned(), // FIXME: use io error's debug string
+                })
+            }
+        }
+    }
+}
+
+impl From<string::FromUtf8Error> for Error {
+    fn from(err: string::FromUtf8Error) -> Self {
+        Error::Protocol(ProtocolError {
+            kind: ProtocolErrorKind::InvalidData,
+            message: err.description().to_owned(), // FIXME: use fmt::Error's debug string
+        })
+    }
+}
+
+/// Create a new `Error` instance of type `Protocol` that wraps a
+/// `ProtocolError`.
+pub fn new_protocol_error<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> Error {
+    Error::Protocol(ProtocolError::new(kind, message))
+}
+
+/// Information about errors that occur in the runtime library.
+#[derive(Debug, Eq, PartialEq)]
+pub struct ProtocolError {
+    /// Protocol error variant.
+    ///
+    /// If a specific `ProtocolErrorKind` does not apply use
+    /// `ProtocolErrorKind::Unknown`.
+    pub kind: ProtocolErrorKind,
+    /// Human-readable error message.
+    pub message: String,
+}
+
+impl ProtocolError {
+    /// Create a new `ProtocolError`.
+    pub fn new<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> ProtocolError {
+        ProtocolError {
+            kind: kind,
+            message: message.into(),
+        }
+    }
+}
+
+/// Runtime library error categories.
+///
+/// This list may grow, and it is not recommended to match against it.
+#[derive(Clone, Copy, Eq, Debug, PartialEq)]
+pub enum ProtocolErrorKind {
+    /// Catch-all runtime-library error.
+    Unknown = 0,
+    /// An invalid argument was supplied to a library function, or invalid data
+    /// was received from a Thrift endpoint.
+    InvalidData = 1,
+    /// An invalid size was received in an encoded field.
+    NegativeSize = 2,
+    /// Thrift message or field was too long.
+    SizeLimit = 3,
+    /// Unsupported or unknown Thrift protocol version.
+    BadVersion = 4,
+    /// Unsupported Thrift protocol, server or field type.
+    NotImplemented = 5,
+    /// Reached the maximum nested depth to which an encoded Thrift field could
+    /// be skipped.
+    DepthLimit = 6,
+}
+
+impl ProtocolError {
+    fn description(&self) -> &str {
+        match self.kind {
+            ProtocolErrorKind::Unknown => "protocol error",
+            ProtocolErrorKind::InvalidData => "bad data",
+            ProtocolErrorKind::NegativeSize => "negative message size",
+            ProtocolErrorKind::SizeLimit => "message too long",
+            ProtocolErrorKind::BadVersion => "invalid thrift version",
+            ProtocolErrorKind::NotImplemented => "not implemented",
+            ProtocolErrorKind::DepthLimit => "maximum skip depth reached",
+        }
+    }
+}
+
+impl Display for ProtocolError {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        write!(f, "{}", self.description())
+    }
+}
+
+impl TryFrom<i32> for ProtocolErrorKind {
+    type Err = Error;
+    fn try_from(from: i32) -> Result<Self, Self::Err> {
+        match from {
+            0 => Ok(ProtocolErrorKind::Unknown),
+            1 => Ok(ProtocolErrorKind::InvalidData),
+            2 => Ok(ProtocolErrorKind::NegativeSize),
+            3 => Ok(ProtocolErrorKind::SizeLimit),
+            4 => Ok(ProtocolErrorKind::BadVersion),
+            5 => Ok(ProtocolErrorKind::NotImplemented),
+            6 => Ok(ProtocolErrorKind::DepthLimit),
+            _ => Err(Error::Protocol(ProtocolError {
+                kind: ProtocolErrorKind::Unknown,
+                message: format!("cannot convert {} to ProtocolErrorKind", from),
+            })),
+        }
+    }
+}
+
+/// Create a new `Error` instance of type `Application` that wraps an
+/// `ApplicationError`.
+pub fn new_application_error<S: Into<String>>(kind: ApplicationErrorKind, message: S) -> Error {
+    Error::Application(ApplicationError::new(kind, message))
+}
+
+/// Information about errors in auto-generated code or in user-implemented
+/// service handlers.
+#[derive(Debug, Eq, PartialEq)]
+pub struct ApplicationError {
+    /// Application error variant.
+    ///
+    /// If a specific `ApplicationErrorKind` does not apply use
+    /// `ApplicationErrorKind::Unknown`.
+    pub kind: ApplicationErrorKind,
+    /// Human-readable error message.
+    pub message: String,
+}
+
+impl ApplicationError {
+    /// Create a new `ApplicationError`.
+    pub fn new<S: Into<String>>(kind: ApplicationErrorKind, message: S) -> ApplicationError {
+        ApplicationError {
+            kind: kind,
+            message: message.into(),
+        }
+    }
+}
+
+/// Auto-generated or user-implemented code error categories.
+///
+/// This list may grow, and it is not recommended to match against it.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum ApplicationErrorKind {
+    /// Catch-all application error.
+    Unknown = 0,
+    /// Made service call to an unknown service method.
+    UnknownMethod = 1,
+    /// Received an unknown Thrift message type. That is, not one of the
+    /// `thrift::protocol::TMessageType` variants.
+    InvalidMessageType = 2,
+    /// Method name in a service reply does not match the name of the
+    /// receiving service method.
+    WrongMethodName = 3,
+    /// Received an out-of-order Thrift message.
+    BadSequenceId = 4,
+    /// Service reply is missing required fields.
+    MissingResult = 5,
+    /// Auto-generated code failed unexpectedly.
+    InternalError = 6,
+    /// Thrift protocol error. When possible use `Error::ProtocolError` with a
+    /// specific `ProtocolErrorKind` instead.
+    ProtocolError = 7,
+    /// *Unknown*. Included only for compatibility with existing Thrift implementations.
+    InvalidTransform = 8, // ??
+    /// Thrift endpoint requested, or is using, an unsupported encoding.
+    InvalidProtocol = 9, // ??
+    /// Thrift endpoint requested, or is using, an unsupported auto-generated client type.
+    UnsupportedClientType = 10, // ??
+}
+
+impl ApplicationError {
+    fn description(&self) -> &str {
+        match self.kind {
+            ApplicationErrorKind::Unknown => "service error",
+            ApplicationErrorKind::UnknownMethod => "unknown service method",
+            ApplicationErrorKind::InvalidMessageType => "wrong message type received",
+            ApplicationErrorKind::WrongMethodName => "unknown method reply received",
+            ApplicationErrorKind::BadSequenceId => "out of order sequence id",
+            ApplicationErrorKind::MissingResult => "missing method result",
+            ApplicationErrorKind::InternalError => "remote service threw exception",
+            ApplicationErrorKind::ProtocolError => "protocol error",
+            ApplicationErrorKind::InvalidTransform => "invalid transform",
+            ApplicationErrorKind::InvalidProtocol => "invalid protocol requested",
+            ApplicationErrorKind::UnsupportedClientType => "unsupported protocol client",
+        }
+    }
+}
+
+impl Display for ApplicationError {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        write!(f, "{}", self.description())
+    }
+}
+
+impl TryFrom<i32> for ApplicationErrorKind {
+    type Err = Error;
+    fn try_from(from: i32) -> Result<Self, Self::Err> {
+        match from {
+            0 => Ok(ApplicationErrorKind::Unknown),
+            1 => Ok(ApplicationErrorKind::UnknownMethod),
+            2 => Ok(ApplicationErrorKind::InvalidMessageType),
+            3 => Ok(ApplicationErrorKind::WrongMethodName),
+            4 => Ok(ApplicationErrorKind::BadSequenceId),
+            5 => Ok(ApplicationErrorKind::MissingResult),
+            6 => Ok(ApplicationErrorKind::InternalError),
+            7 => Ok(ApplicationErrorKind::ProtocolError),
+            8 => Ok(ApplicationErrorKind::InvalidTransform),
+            9 => Ok(ApplicationErrorKind::InvalidProtocol),
+            10 => Ok(ApplicationErrorKind::UnsupportedClientType),
+            _ => Err(Error::Application(ApplicationError {
+                kind: ApplicationErrorKind::Unknown,
+                message: format!("cannot convert {} to ApplicationErrorKind", from),
+            })),
+        }
+    }
+}
diff --git a/lib/rs/src/lib.rs b/lib/rs/src/lib.rs
new file mode 100644
index 0000000..ca5c7d6
--- /dev/null
+++ b/lib/rs/src/lib.rs
@@ -0,0 +1,87 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+//! Rust runtime library for the Apache Thrift RPC system.
+//!
+//! This crate implements the components required to build a working
+//! Thrift server and client. It is divided into the following modules:
+//!
+//! 1. errors
+//! 2. protocol
+//! 3. transport
+//! 4. server
+//! 5. autogen
+//!
+//! The modules are layered as shown in the diagram below. The `autogen'd`
+//! layer is generated by the Thrift compiler's Rust plugin. It uses the
+//! types and functions defined in this crate to serialize and deserialize
+//! messages and implement RPC. Users interact with these types and services
+//! by writing their own code that uses the auto-generated clients and
+//! servers.
+//!
+//! ```text
+//! +-----------+
+//! | user app  |
+//! +-----------+
+//! | autogen'd | (uses errors, autogen)
+//! +-----------+
+//! |  protocol |
+//! +-----------+
+//! | transport |
+//! +-----------+
+//! ```
+
+#![crate_type = "lib"]
+#![doc(test(attr(allow(unused_variables), deny(warnings))))]
+
+extern crate byteorder;
+extern crate integer_encoding;
+extern crate threadpool;
+extern crate try_from;
+
+#[macro_use]
+extern crate log;
+
+// NOTE: this macro has to be defined before any modules. See:
+// https://danielkeep.github.io/quick-intro-to-macros.html#some-more-gotchas
+
+/// Assert that an expression returning a `Result` is a success. If it is,
+/// return the value contained in the result, i.e. `expr.unwrap()`.
+#[cfg(test)]
+macro_rules! assert_success {
+    ($e: expr) => {{
+        let res = $e;
+        assert!(res.is_ok());
+        res.unwrap()
+    }};
+}
+
+pub mod protocol;
+pub mod server;
+pub mod transport;
+
+mod errors;
+pub use errors::*;
+
+mod autogen;
+pub use autogen::*;
+
+/// Result type returned by all runtime library functions.
+///
+/// As is convention this is a typedef of `std::result::Result`
+/// with `E` defined as the `thrift::Error` type.
+pub type Result<T> = std::result::Result<T, self::Error>;
diff --git a/lib/rs/src/protocol/binary.rs b/lib/rs/src/protocol/binary.rs
new file mode 100644
index 0000000..19aff3d
--- /dev/null
+++ b/lib/rs/src/protocol/binary.rs
@@ -0,0 +1,957 @@
+// 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.
+
+use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
+use std::convert::From;
+use try_from::TryFrom;
+
+use super::{
+    TFieldIdentifier, TInputProtocol, TInputProtocolFactory, TListIdentifier, TMapIdentifier,
+    TMessageIdentifier, TMessageType,
+};
+use super::{TOutputProtocol, TOutputProtocolFactory, TSetIdentifier, TStructIdentifier, TType};
+use transport::{TReadTransport, TWriteTransport};
+use {ProtocolError, ProtocolErrorKind};
+
+const BINARY_PROTOCOL_VERSION_1: u32 = 0x80010000;
+
+/// Read messages encoded in the Thrift simple binary encoding.
+///
+/// There are two available modes: `strict` and `non-strict`, where the
+/// `non-strict` version does not check for the protocol version in the
+/// received message header.
+///
+/// # Examples
+///
+/// Create and use a `TBinaryInputProtocol`.
+///
+/// ```no_run
+/// use thrift::protocol::{TBinaryInputProtocol, TInputProtocol};
+/// use thrift::transport::TTcpChannel;
+///
+/// let mut channel = TTcpChannel::new();
+/// channel.open("localhost:9090").unwrap();
+///
+/// let mut protocol = TBinaryInputProtocol::new(channel, true);
+///
+/// let recvd_bool = protocol.read_bool().unwrap();
+/// let recvd_string = protocol.read_string().unwrap();
+/// ```
+#[derive(Debug)]
+pub struct TBinaryInputProtocol<T>
+where
+    T: TReadTransport,
+{
+    strict: bool,
+    pub transport: T, // FIXME: shouldn't be public
+}
+
+impl<'a, T> TBinaryInputProtocol<T>
+where
+    T: TReadTransport,
+{
+    /// Create a `TBinaryInputProtocol` that reads bytes from `transport`.
+    ///
+    /// Set `strict` to `true` if all incoming messages contain the protocol
+    /// version number in the protocol header.
+    pub fn new(transport: T, strict: bool) -> TBinaryInputProtocol<T> {
+        TBinaryInputProtocol {
+            strict: strict,
+            transport: transport,
+        }
+    }
+}
+
+impl<T> TInputProtocol for TBinaryInputProtocol<T>
+where
+    T: TReadTransport,
+{
+    #[cfg_attr(feature = "cargo-clippy", allow(collapsible_if))]
+    fn read_message_begin(&mut self) -> ::Result<TMessageIdentifier> {
+        let mut first_bytes = vec![0; 4];
+        self.transport.read_exact(&mut first_bytes[..])?;
+
+        // the thrift version header is intentionally negative
+        // so the first check we'll do is see if the sign bit is set
+        // and if so - assume it's the protocol-version header
+        if first_bytes[0] >= 8 {
+            // apparently we got a protocol-version header - check
+            // it, and if it matches, read the rest of the fields
+            if first_bytes[0..2] != [0x80, 0x01] {
+                Err(::Error::Protocol(ProtocolError {
+                    kind: ProtocolErrorKind::BadVersion,
+                    message: format!("received bad version: {:?}", &first_bytes[0..2]),
+                }))
+            } else {
+                let message_type: TMessageType = TryFrom::try_from(first_bytes[3])?;
+                let name = self.read_string()?;
+                let sequence_number = self.read_i32()?;
+                Ok(TMessageIdentifier::new(name, message_type, sequence_number))
+            }
+        } else {
+            // apparently we didn't get a protocol-version header,
+            // which happens if the sender is not using the strict protocol
+            if self.strict {
+                // we're in strict mode however, and that always
+                // requires the protocol-version header to be written first
+                Err(::Error::Protocol(ProtocolError {
+                    kind: ProtocolErrorKind::BadVersion,
+                    message: format!("received bad version: {:?}", &first_bytes[0..2]),
+                }))
+            } else {
+                // in the non-strict version the first message field
+                // is the message name. strings (byte arrays) are length-prefixed,
+                // so we've just read the length in the first 4 bytes
+                let name_size = BigEndian::read_i32(&first_bytes) as usize;
+                let mut name_buf: Vec<u8> = vec![0; name_size];
+                self.transport.read_exact(&mut name_buf)?;
+                let name = String::from_utf8(name_buf)?;
+
+                // read the rest of the fields
+                let message_type: TMessageType = self.read_byte().and_then(TryFrom::try_from)?;
+                let sequence_number = self.read_i32()?;
+                Ok(TMessageIdentifier::new(name, message_type, sequence_number))
+            }
+        }
+    }
+
+    fn read_message_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn read_struct_begin(&mut self) -> ::Result<Option<TStructIdentifier>> {
+        Ok(None)
+    }
+
+    fn read_struct_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn read_field_begin(&mut self) -> ::Result<TFieldIdentifier> {
+        let field_type_byte = self.read_byte()?;
+        let field_type = field_type_from_u8(field_type_byte)?;
+        let id = match field_type {
+            TType::Stop => Ok(0),
+            _ => self.read_i16(),
+        }?;
+        Ok(TFieldIdentifier::new::<Option<String>, String, i16>(
+            None, field_type, id,
+        ))
+    }
+
+    fn read_field_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn read_bytes(&mut self) -> ::Result<Vec<u8>> {
+        let num_bytes = self.transport.read_i32::<BigEndian>()? as usize;
+        let mut buf = vec![0u8; num_bytes];
+        self.transport
+            .read_exact(&mut buf)
+            .map(|_| buf)
+            .map_err(From::from)
+    }
+
+    fn read_bool(&mut self) -> ::Result<bool> {
+        let b = self.read_i8()?;
+        match b {
+            0 => Ok(false),
+            _ => Ok(true),
+        }
+    }
+
+    fn read_i8(&mut self) -> ::Result<i8> {
+        self.transport.read_i8().map_err(From::from)
+    }
+
+    fn read_i16(&mut self) -> ::Result<i16> {
+        self.transport.read_i16::<BigEndian>().map_err(From::from)
+    }
+
+    fn read_i32(&mut self) -> ::Result<i32> {
+        self.transport.read_i32::<BigEndian>().map_err(From::from)
+    }
+
+    fn read_i64(&mut self) -> ::Result<i64> {
+        self.transport.read_i64::<BigEndian>().map_err(From::from)
+    }
+
+    fn read_double(&mut self) -> ::Result<f64> {
+        self.transport.read_f64::<BigEndian>().map_err(From::from)
+    }
+
+    fn read_string(&mut self) -> ::Result<String> {
+        let bytes = self.read_bytes()?;
+        String::from_utf8(bytes).map_err(From::from)
+    }
+
+    fn read_list_begin(&mut self) -> ::Result<TListIdentifier> {
+        let element_type: TType = self.read_byte().and_then(field_type_from_u8)?;
+        let size = self.read_i32()?;
+        Ok(TListIdentifier::new(element_type, size))
+    }
+
+    fn read_list_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn read_set_begin(&mut self) -> ::Result<TSetIdentifier> {
+        let element_type: TType = self.read_byte().and_then(field_type_from_u8)?;
+        let size = self.read_i32()?;
+        Ok(TSetIdentifier::new(element_type, size))
+    }
+
+    fn read_set_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn read_map_begin(&mut self) -> ::Result<TMapIdentifier> {
+        let key_type: TType = self.read_byte().and_then(field_type_from_u8)?;
+        let value_type: TType = self.read_byte().and_then(field_type_from_u8)?;
+        let size = self.read_i32()?;
+        Ok(TMapIdentifier::new(key_type, value_type, size))
+    }
+
+    fn read_map_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    // utility
+    //
+
+    fn read_byte(&mut self) -> ::Result<u8> {
+        self.transport.read_u8().map_err(From::from)
+    }
+}
+
+/// Factory for creating instances of `TBinaryInputProtocol`.
+#[derive(Default)]
+pub struct TBinaryInputProtocolFactory;
+
+impl TBinaryInputProtocolFactory {
+    /// Create a `TBinaryInputProtocolFactory`.
+    pub fn new() -> TBinaryInputProtocolFactory {
+        TBinaryInputProtocolFactory {}
+    }
+}
+
+impl TInputProtocolFactory for TBinaryInputProtocolFactory {
+    fn create(&self, transport: Box<TReadTransport + Send>) -> Box<TInputProtocol + Send> {
+        Box::new(TBinaryInputProtocol::new(transport, true))
+    }
+}
+
+/// Write messages using the Thrift simple binary encoding.
+///
+/// There are two available modes: `strict` and `non-strict`, where the
+/// `strict` version writes the protocol version number in the outgoing message
+/// header and the `non-strict` version does not.
+///
+/// # Examples
+///
+/// Create and use a `TBinaryOutputProtocol`.
+///
+/// ```no_run
+/// use thrift::protocol::{TBinaryOutputProtocol, TOutputProtocol};
+/// use thrift::transport::TTcpChannel;
+///
+/// let mut channel = TTcpChannel::new();
+/// channel.open("localhost:9090").unwrap();
+///
+/// let mut protocol = TBinaryOutputProtocol::new(channel, true);
+///
+/// protocol.write_bool(true).unwrap();
+/// protocol.write_string("test_string").unwrap();
+/// ```
+#[derive(Debug)]
+pub struct TBinaryOutputProtocol<T>
+where
+    T: TWriteTransport,
+{
+    strict: bool,
+    pub transport: T, // FIXME: do not make public; only public for testing!
+}
+
+impl<T> TBinaryOutputProtocol<T>
+where
+    T: TWriteTransport,
+{
+    /// Create a `TBinaryOutputProtocol` that writes bytes to `transport`.
+    ///
+    /// Set `strict` to `true` if all outgoing messages should contain the
+    /// protocol version number in the protocol header.
+    pub fn new(transport: T, strict: bool) -> TBinaryOutputProtocol<T> {
+        TBinaryOutputProtocol {
+            strict: strict,
+            transport: transport,
+        }
+    }
+}
+
+impl<T> TOutputProtocol for TBinaryOutputProtocol<T>
+where
+    T: TWriteTransport,
+{
+    fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()> {
+        if self.strict {
+            let message_type: u8 = identifier.message_type.into();
+            let header = BINARY_PROTOCOL_VERSION_1 | (message_type as u32);
+            self.transport.write_u32::<BigEndian>(header)?;
+            self.write_string(&identifier.name)?;
+            self.write_i32(identifier.sequence_number)
+        } else {
+            self.write_string(&identifier.name)?;
+            self.write_byte(identifier.message_type.into())?;
+            self.write_i32(identifier.sequence_number)
+        }
+    }
+
+    fn write_message_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn write_struct_begin(&mut self, _: &TStructIdentifier) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn write_struct_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()> {
+        if identifier.id.is_none() && identifier.field_type != TType::Stop {
+            return Err(::Error::Protocol(ProtocolError {
+                kind: ProtocolErrorKind::Unknown,
+                message: format!(
+                    "cannot write identifier {:?} without sequence number",
+                    &identifier
+                ),
+            }));
+        }
+
+        self.write_byte(field_type_to_u8(identifier.field_type))?;
+        if let Some(id) = identifier.id {
+            self.write_i16(id)
+        } else {
+            Ok(())
+        }
+    }
+
+    fn write_field_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn write_field_stop(&mut self) -> ::Result<()> {
+        self.write_byte(field_type_to_u8(TType::Stop))
+    }
+
+    fn write_bytes(&mut self, b: &[u8]) -> ::Result<()> {
+        self.write_i32(b.len() as i32)?;
+        self.transport.write_all(b).map_err(From::from)
+    }
+
+    fn write_bool(&mut self, b: bool) -> ::Result<()> {
+        if b {
+            self.write_i8(1)
+        } else {
+            self.write_i8(0)
+        }
+    }
+
+    fn write_i8(&mut self, i: i8) -> ::Result<()> {
+        self.transport.write_i8(i).map_err(From::from)
+    }
+
+    fn write_i16(&mut self, i: i16) -> ::Result<()> {
+        self.transport.write_i16::<BigEndian>(i).map_err(From::from)
+    }
+
+    fn write_i32(&mut self, i: i32) -> ::Result<()> {
+        self.transport.write_i32::<BigEndian>(i).map_err(From::from)
+    }
+
+    fn write_i64(&mut self, i: i64) -> ::Result<()> {
+        self.transport.write_i64::<BigEndian>(i).map_err(From::from)
+    }
+
+    fn write_double(&mut self, d: f64) -> ::Result<()> {
+        self.transport.write_f64::<BigEndian>(d).map_err(From::from)
+    }
+
+    fn write_string(&mut self, s: &str) -> ::Result<()> {
+        self.write_bytes(s.as_bytes())
+    }
+
+    fn write_list_begin(&mut self, identifier: &TListIdentifier) -> ::Result<()> {
+        self.write_byte(field_type_to_u8(identifier.element_type))?;
+        self.write_i32(identifier.size)
+    }
+
+    fn write_list_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> ::Result<()> {
+        self.write_byte(field_type_to_u8(identifier.element_type))?;
+        self.write_i32(identifier.size)
+    }
+
+    fn write_set_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()> {
+        let key_type = identifier
+            .key_type
+            .expect("map identifier to write should contain key type");
+        self.write_byte(field_type_to_u8(key_type))?;
+        let val_type = identifier
+            .value_type
+            .expect("map identifier to write should contain value type");
+        self.write_byte(field_type_to_u8(val_type))?;
+        self.write_i32(identifier.size)
+    }
+
+    fn write_map_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn flush(&mut self) -> ::Result<()> {
+        self.transport.flush().map_err(From::from)
+    }
+
+    // utility
+    //
+
+    fn write_byte(&mut self, b: u8) -> ::Result<()> {
+        self.transport.write_u8(b).map_err(From::from)
+    }
+}
+
+/// Factory for creating instances of `TBinaryOutputProtocol`.
+#[derive(Default)]
+pub struct TBinaryOutputProtocolFactory;
+
+impl TBinaryOutputProtocolFactory {
+    /// Create a `TBinaryOutputProtocolFactory`.
+    pub fn new() -> TBinaryOutputProtocolFactory {
+        TBinaryOutputProtocolFactory {}
+    }
+}
+
+impl TOutputProtocolFactory for TBinaryOutputProtocolFactory {
+    fn create(&self, transport: Box<TWriteTransport + Send>) -> Box<TOutputProtocol + Send> {
+        Box::new(TBinaryOutputProtocol::new(transport, true))
+    }
+}
+
+fn field_type_to_u8(field_type: TType) -> u8 {
+    match field_type {
+        TType::Stop => 0x00,
+        TType::Void => 0x01,
+        TType::Bool => 0x02,
+        TType::I08 => 0x03, // equivalent to TType::Byte
+        TType::Double => 0x04,
+        TType::I16 => 0x06,
+        TType::I32 => 0x08,
+        TType::I64 => 0x0A,
+        TType::String | TType::Utf7 => 0x0B,
+        TType::Struct => 0x0C,
+        TType::Map => 0x0D,
+        TType::Set => 0x0E,
+        TType::List => 0x0F,
+        TType::Utf8 => 0x10,
+        TType::Utf16 => 0x11,
+    }
+}
+
+fn field_type_from_u8(b: u8) -> ::Result<TType> {
+    match b {
+        0x00 => Ok(TType::Stop),
+        0x01 => Ok(TType::Void),
+        0x02 => Ok(TType::Bool),
+        0x03 => Ok(TType::I08), // Equivalent to TType::Byte
+        0x04 => Ok(TType::Double),
+        0x06 => Ok(TType::I16),
+        0x08 => Ok(TType::I32),
+        0x0A => Ok(TType::I64),
+        0x0B => Ok(TType::String), // technically, also a UTF7, but we'll treat it as string
+        0x0C => Ok(TType::Struct),
+        0x0D => Ok(TType::Map),
+        0x0E => Ok(TType::Set),
+        0x0F => Ok(TType::List),
+        0x10 => Ok(TType::Utf8),
+        0x11 => Ok(TType::Utf16),
+        unkn => Err(::Error::Protocol(ProtocolError {
+            kind: ProtocolErrorKind::InvalidData,
+            message: format!("cannot convert {} to TType", unkn),
+        })),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use protocol::{
+        TFieldIdentifier, TInputProtocol, TListIdentifier, TMapIdentifier, TMessageIdentifier,
+        TMessageType, TOutputProtocol, TSetIdentifier, TStructIdentifier, TType,
+    };
+    use transport::{ReadHalf, TBufferChannel, TIoChannel, WriteHalf};
+
+    use super::*;
+
+    #[test]
+    fn must_write_strict_message_call_begin() {
+        let (_, mut o_prot) = test_objects(true);
+
+        let ident = TMessageIdentifier::new("test", TMessageType::Call, 1);
+        assert!(o_prot.write_message_begin(&ident).is_ok());
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 16] = [
+            0x80,
+            0x01,
+            0x00,
+            0x01,
+            0x00,
+            0x00,
+            0x00,
+            0x04,
+            0x74,
+            0x65,
+            0x73,
+            0x74,
+            0x00,
+            0x00,
+            0x00,
+            0x01,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_write_non_strict_message_call_begin() {
+        let (_, mut o_prot) = test_objects(false);
+
+        let ident = TMessageIdentifier::new("test", TMessageType::Call, 1);
+        assert!(o_prot.write_message_begin(&ident).is_ok());
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 13] = [
+            0x00,
+            0x00,
+            0x00,
+            0x04,
+            0x74,
+            0x65,
+            0x73,
+            0x74,
+            0x01,
+            0x00,
+            0x00,
+            0x00,
+            0x01,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_write_strict_message_reply_begin() {
+        let (_, mut o_prot) = test_objects(true);
+
+        let ident = TMessageIdentifier::new("test", TMessageType::Reply, 10);
+        assert!(o_prot.write_message_begin(&ident).is_ok());
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 16] = [
+            0x80,
+            0x01,
+            0x00,
+            0x02,
+            0x00,
+            0x00,
+            0x00,
+            0x04,
+            0x74,
+            0x65,
+            0x73,
+            0x74,
+            0x00,
+            0x00,
+            0x00,
+            0x0A,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_write_non_strict_message_reply_begin() {
+        let (_, mut o_prot) = test_objects(false);
+
+        let ident = TMessageIdentifier::new("test", TMessageType::Reply, 10);
+        assert!(o_prot.write_message_begin(&ident).is_ok());
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 13] = [
+            0x00,
+            0x00,
+            0x00,
+            0x04,
+            0x74,
+            0x65,
+            0x73,
+            0x74,
+            0x02,
+            0x00,
+            0x00,
+            0x00,
+            0x0A,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_strict_message_begin() {
+        let (mut i_prot, mut o_prot) = test_objects(true);
+
+        let sent_ident = TMessageIdentifier::new("test", TMessageType::Call, 1);
+        assert!(o_prot.write_message_begin(&sent_ident).is_ok());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let received_ident = assert_success!(i_prot.read_message_begin());
+        assert_eq!(&received_ident, &sent_ident);
+    }
+
+    #[test]
+    fn must_round_trip_non_strict_message_begin() {
+        let (mut i_prot, mut o_prot) = test_objects(false);
+
+        let sent_ident = TMessageIdentifier::new("test", TMessageType::Call, 1);
+        assert!(o_prot.write_message_begin(&sent_ident).is_ok());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let received_ident = assert_success!(i_prot.read_message_begin());
+        assert_eq!(&received_ident, &sent_ident);
+    }
+
+    #[test]
+    fn must_write_message_end() {
+        assert_no_write(|o| o.write_message_end(), true);
+    }
+
+    #[test]
+    fn must_write_struct_begin() {
+        assert_no_write(
+            |o| o.write_struct_begin(&TStructIdentifier::new("foo")),
+            true,
+        );
+    }
+
+    #[test]
+    fn must_write_struct_end() {
+        assert_no_write(|o| o.write_struct_end(), true);
+    }
+
+    #[test]
+    fn must_write_field_begin() {
+        let (_, mut o_prot) = test_objects(true);
+
+        assert!(o_prot
+            .write_field_begin(&TFieldIdentifier::new("some_field", TType::String, 22))
+            .is_ok());
+
+        let expected: [u8; 3] = [0x0B, 0x00, 0x16];
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_field_begin() {
+        let (mut i_prot, mut o_prot) = test_objects(true);
+
+        let sent_field_ident = TFieldIdentifier::new("foo", TType::I64, 20);
+        assert!(o_prot.write_field_begin(&sent_field_ident).is_ok());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let expected_ident = TFieldIdentifier {
+            name: None,
+            field_type: TType::I64,
+            id: Some(20),
+        }; // no name
+        let received_ident = assert_success!(i_prot.read_field_begin());
+        assert_eq!(&received_ident, &expected_ident);
+    }
+
+    #[test]
+    fn must_write_stop_field() {
+        let (_, mut o_prot) = test_objects(true);
+
+        assert!(o_prot.write_field_stop().is_ok());
+
+        let expected: [u8; 1] = [0x00];
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_field_stop() {
+        let (mut i_prot, mut o_prot) = test_objects(true);
+
+        assert!(o_prot.write_field_stop().is_ok());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let expected_ident = TFieldIdentifier {
+            name: None,
+            field_type: TType::Stop,
+            id: Some(0),
+        }; // we get id 0
+
+        let received_ident = assert_success!(i_prot.read_field_begin());
+        assert_eq!(&received_ident, &expected_ident);
+    }
+
+    #[test]
+    fn must_write_field_end() {
+        assert_no_write(|o| o.write_field_end(), true);
+    }
+
+    #[test]
+    fn must_write_list_begin() {
+        let (_, mut o_prot) = test_objects(true);
+
+        assert!(o_prot
+            .write_list_begin(&TListIdentifier::new(TType::Bool, 5))
+            .is_ok());
+
+        let expected: [u8; 5] = [0x02, 0x00, 0x00, 0x00, 0x05];
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_list_begin() {
+        let (mut i_prot, mut o_prot) = test_objects(true);
+
+        let ident = TListIdentifier::new(TType::List, 900);
+        assert!(o_prot.write_list_begin(&ident).is_ok());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let received_ident = assert_success!(i_prot.read_list_begin());
+        assert_eq!(&received_ident, &ident);
+    }
+
+    #[test]
+    fn must_write_list_end() {
+        assert_no_write(|o| o.write_list_end(), true);
+    }
+
+    #[test]
+    fn must_write_set_begin() {
+        let (_, mut o_prot) = test_objects(true);
+
+        assert!(o_prot
+            .write_set_begin(&TSetIdentifier::new(TType::I16, 7))
+            .is_ok());
+
+        let expected: [u8; 5] = [0x06, 0x00, 0x00, 0x00, 0x07];
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_set_begin() {
+        let (mut i_prot, mut o_prot) = test_objects(true);
+
+        let ident = TSetIdentifier::new(TType::I64, 2000);
+        assert!(o_prot.write_set_begin(&ident).is_ok());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let received_ident_result = i_prot.read_set_begin();
+        assert!(received_ident_result.is_ok());
+        assert_eq!(&received_ident_result.unwrap(), &ident);
+    }
+
+    #[test]
+    fn must_write_set_end() {
+        assert_no_write(|o| o.write_set_end(), true);
+    }
+
+    #[test]
+    fn must_write_map_begin() {
+        let (_, mut o_prot) = test_objects(true);
+
+        assert!(o_prot
+            .write_map_begin(&TMapIdentifier::new(TType::I64, TType::Struct, 32))
+            .is_ok());
+
+        let expected: [u8; 6] = [0x0A, 0x0C, 0x00, 0x00, 0x00, 0x20];
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_map_begin() {
+        let (mut i_prot, mut o_prot) = test_objects(true);
+
+        let ident = TMapIdentifier::new(TType::Map, TType::Set, 100);
+        assert!(o_prot.write_map_begin(&ident).is_ok());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let received_ident = assert_success!(i_prot.read_map_begin());
+        assert_eq!(&received_ident, &ident);
+    }
+
+    #[test]
+    fn must_write_map_end() {
+        assert_no_write(|o| o.write_map_end(), true);
+    }
+
+    #[test]
+    fn must_write_bool_true() {
+        let (_, mut o_prot) = test_objects(true);
+
+        assert!(o_prot.write_bool(true).is_ok());
+
+        let expected: [u8; 1] = [0x01];
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_write_bool_false() {
+        let (_, mut o_prot) = test_objects(true);
+
+        assert!(o_prot.write_bool(false).is_ok());
+
+        let expected: [u8; 1] = [0x00];
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_read_bool_true() {
+        let (mut i_prot, _) = test_objects(true);
+
+        set_readable_bytes!(i_prot, &[0x01]);
+
+        let read_bool = assert_success!(i_prot.read_bool());
+        assert_eq!(read_bool, true);
+    }
+
+    #[test]
+    fn must_read_bool_false() {
+        let (mut i_prot, _) = test_objects(true);
+
+        set_readable_bytes!(i_prot, &[0x00]);
+
+        let read_bool = assert_success!(i_prot.read_bool());
+        assert_eq!(read_bool, false);
+    }
+
+    #[test]
+    fn must_allow_any_non_zero_value_to_be_interpreted_as_bool_true() {
+        let (mut i_prot, _) = test_objects(true);
+
+        set_readable_bytes!(i_prot, &[0xAC]);
+
+        let read_bool = assert_success!(i_prot.read_bool());
+        assert_eq!(read_bool, true);
+    }
+
+    #[test]
+    fn must_write_bytes() {
+        let (_, mut o_prot) = test_objects(true);
+
+        let bytes: [u8; 10] = [0x0A, 0xCC, 0xD1, 0x84, 0x99, 0x12, 0xAB, 0xBB, 0x45, 0xDF];
+
+        assert!(o_prot.write_bytes(&bytes).is_ok());
+
+        let buf = o_prot.transport.write_bytes();
+        assert_eq!(&buf[0..4], [0x00, 0x00, 0x00, 0x0A]); // length
+        assert_eq!(&buf[4..], bytes); // actual bytes
+    }
+
+    #[test]
+    fn must_round_trip_bytes() {
+        let (mut i_prot, mut o_prot) = test_objects(true);
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let bytes: [u8; 25] = [
+            0x20,
+            0xFD,
+            0x18,
+            0x84,
+            0x99,
+            0x12,
+            0xAB,
+            0xBB,
+            0x45,
+            0xDF,
+            0x34,
+            0xDC,
+            0x98,
+            0xA4,
+            0x6D,
+            0xF3,
+            0x99,
+            0xB4,
+            0xB7,
+            0xD4,
+            0x9C,
+            0xA5,
+            0xB3,
+            0xC9,
+            0x88,
+        ];
+
+        assert!(o_prot.write_bytes(&bytes).is_ok());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let received_bytes = assert_success!(i_prot.read_bytes());
+        assert_eq!(&received_bytes, &bytes);
+    }
+
+    fn test_objects(
+        strict: bool,
+    ) -> (
+        TBinaryInputProtocol<ReadHalf<TBufferChannel>>,
+        TBinaryOutputProtocol<WriteHalf<TBufferChannel>>,
+    ) {
+        let mem = TBufferChannel::with_capacity(40, 40);
+
+        let (r_mem, w_mem) = mem.split().unwrap();
+
+        let i_prot = TBinaryInputProtocol::new(r_mem, strict);
+        let o_prot = TBinaryOutputProtocol::new(w_mem, strict);
+
+        (i_prot, o_prot)
+    }
+
+    fn assert_no_write<F>(mut write_fn: F, strict: bool)
+    where
+        F: FnMut(&mut TBinaryOutputProtocol<WriteHalf<TBufferChannel>>) -> ::Result<()>,
+    {
+        let (_, mut o_prot) = test_objects(strict);
+        assert!(write_fn(&mut o_prot).is_ok());
+        assert_eq!(o_prot.transport.write_bytes().len(), 0);
+    }
+}
diff --git a/lib/rs/src/protocol/compact.rs b/lib/rs/src/protocol/compact.rs
new file mode 100644
index 0000000..df5edaa
--- /dev/null
+++ b/lib/rs/src/protocol/compact.rs
@@ -0,0 +1,2386 @@
+// 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.
+
+use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
+use integer_encoding::{VarIntReader, VarIntWriter};
+use std::convert::From;
+use std::io;
+use try_from::TryFrom;
+
+use super::{
+    TFieldIdentifier, TInputProtocol, TInputProtocolFactory, TListIdentifier, TMapIdentifier,
+    TMessageIdentifier, TMessageType,
+};
+use super::{TOutputProtocol, TOutputProtocolFactory, TSetIdentifier, TStructIdentifier, TType};
+use transport::{TReadTransport, TWriteTransport};
+
+const COMPACT_PROTOCOL_ID: u8 = 0x82;
+const COMPACT_VERSION: u8 = 0x01;
+const COMPACT_VERSION_MASK: u8 = 0x1F;
+
+/// Read messages encoded in the Thrift compact protocol.
+///
+/// # Examples
+///
+/// Create and use a `TCompactInputProtocol`.
+///
+/// ```no_run
+/// use thrift::protocol::{TCompactInputProtocol, TInputProtocol};
+/// use thrift::transport::TTcpChannel;
+///
+/// let mut channel = TTcpChannel::new();
+/// channel.open("localhost:9090").unwrap();
+///
+/// let mut protocol = TCompactInputProtocol::new(channel);
+///
+/// let recvd_bool = protocol.read_bool().unwrap();
+/// let recvd_string = protocol.read_string().unwrap();
+/// ```
+#[derive(Debug)]
+pub struct TCompactInputProtocol<T>
+where
+    T: TReadTransport,
+{
+    // Identifier of the last field deserialized for a struct.
+    last_read_field_id: i16,
+    // Stack of the last read field ids (a new entry is added each time a nested struct is read).
+    read_field_id_stack: Vec<i16>,
+    // Boolean value for a field.
+    // Saved because boolean fields and their value are encoded in a single byte,
+    // and reading the field only occurs after the field id is read.
+    pending_read_bool_value: Option<bool>,
+    // Underlying transport used for byte-level operations.
+    transport: T,
+}
+
+impl<T> TCompactInputProtocol<T>
+where
+    T: TReadTransport,
+{
+    /// Create a `TCompactInputProtocol` that reads bytes from `transport`.
+    pub fn new(transport: T) -> TCompactInputProtocol<T> {
+        TCompactInputProtocol {
+            last_read_field_id: 0,
+            read_field_id_stack: Vec::new(),
+            pending_read_bool_value: None,
+            transport: transport,
+        }
+    }
+
+    fn read_list_set_begin(&mut self) -> ::Result<(TType, i32)> {
+        let header = self.read_byte()?;
+        let element_type = collection_u8_to_type(header & 0x0F)?;
+
+        let element_count;
+        let possible_element_count = (header & 0xF0) >> 4;
+        if possible_element_count != 15 {
+            // high bits set high if count and type encoded separately
+            element_count = possible_element_count as i32;
+        } else {
+            element_count = self.transport.read_varint::<u32>()? as i32;
+        }
+
+        Ok((element_type, element_count))
+    }
+}
+
+impl<T> TInputProtocol for TCompactInputProtocol<T>
+where
+    T: TReadTransport,
+{
+    fn read_message_begin(&mut self) -> ::Result<TMessageIdentifier> {
+        let compact_id = self.read_byte()?;
+        if compact_id != COMPACT_PROTOCOL_ID {
+            Err(::Error::Protocol(::ProtocolError {
+                kind: ::ProtocolErrorKind::BadVersion,
+                message: format!("invalid compact protocol header {:?}", compact_id),
+            }))
+        } else {
+            Ok(())
+        }?;
+
+        let type_and_byte = self.read_byte()?;
+        let received_version = type_and_byte & COMPACT_VERSION_MASK;
+        if received_version != COMPACT_VERSION {
+            Err(::Error::Protocol(::ProtocolError {
+                kind: ::ProtocolErrorKind::BadVersion,
+                message: format!(
+                    "cannot process compact protocol version {:?}",
+                    received_version
+                ),
+            }))
+        } else {
+            Ok(())
+        }?;
+
+        // NOTE: unsigned right shift will pad with 0s
+        let message_type: TMessageType = TMessageType::try_from(type_and_byte >> 5)?;
+        let sequence_number = self.read_i32()?;
+        let service_call_name = self.read_string()?;
+
+        self.last_read_field_id = 0;
+
+        Ok(TMessageIdentifier::new(
+            service_call_name,
+            message_type,
+            sequence_number,
+        ))
+    }
+
+    fn read_message_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn read_struct_begin(&mut self) -> ::Result<Option<TStructIdentifier>> {
+        self.read_field_id_stack.push(self.last_read_field_id);
+        self.last_read_field_id = 0;
+        Ok(None)
+    }
+
+    fn read_struct_end(&mut self) -> ::Result<()> {
+        self.last_read_field_id = self
+            .read_field_id_stack
+            .pop()
+            .expect("should have previous field ids");
+        Ok(())
+    }
+
+    fn read_field_begin(&mut self) -> ::Result<TFieldIdentifier> {
+        // we can read at least one byte, which is:
+        // - the type
+        // - the field delta and the type
+        let field_type = self.read_byte()?;
+        let field_delta = (field_type & 0xF0) >> 4;
+        let field_type = match field_type & 0x0F {
+            0x01 => {
+                self.pending_read_bool_value = Some(true);
+                Ok(TType::Bool)
+            }
+            0x02 => {
+                self.pending_read_bool_value = Some(false);
+                Ok(TType::Bool)
+            }
+            ttu8 => u8_to_type(ttu8),
+        }?;
+
+        match field_type {
+            TType::Stop => Ok(
+                TFieldIdentifier::new::<Option<String>, String, Option<i16>>(
+                    None,
+                    TType::Stop,
+                    None,
+                ),
+            ),
+            _ => {
+                if field_delta != 0 {
+                    self.last_read_field_id += field_delta as i16;
+                } else {
+                    self.last_read_field_id = self.read_i16()?;
+                };
+
+                Ok(TFieldIdentifier {
+                    name: None,
+                    field_type: field_type,
+                    id: Some(self.last_read_field_id),
+                })
+            }
+        }
+    }
+
+    fn read_field_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn read_bool(&mut self) -> ::Result<bool> {
+        match self.pending_read_bool_value.take() {
+            Some(b) => Ok(b),
+            None => {
+                let b = self.read_byte()?;
+                match b {
+                    0x01 => Ok(true),
+                    0x02 => Ok(false),
+                    unkn => Err(::Error::Protocol(::ProtocolError {
+                        kind: ::ProtocolErrorKind::InvalidData,
+                        message: format!("cannot convert {} into bool", unkn),
+                    })),
+                }
+            }
+        }
+    }
+
+    fn read_bytes(&mut self) -> ::Result<Vec<u8>> {
+        let len = self.transport.read_varint::<u32>()?;
+        let mut buf = vec![0u8; len as usize];
+        self.transport
+            .read_exact(&mut buf)
+            .map_err(From::from)
+            .map(|_| buf)
+    }
+
+    fn read_i8(&mut self) -> ::Result<i8> {
+        self.read_byte().map(|i| i as i8)
+    }
+
+    fn read_i16(&mut self) -> ::Result<i16> {
+        self.transport.read_varint::<i16>().map_err(From::from)
+    }
+
+    fn read_i32(&mut self) -> ::Result<i32> {
+        self.transport.read_varint::<i32>().map_err(From::from)
+    }
+
+    fn read_i64(&mut self) -> ::Result<i64> {
+        self.transport.read_varint::<i64>().map_err(From::from)
+    }
+
+    fn read_double(&mut self) -> ::Result<f64> {
+        self.transport.read_f64::<BigEndian>().map_err(From::from)
+    }
+
+    fn read_string(&mut self) -> ::Result<String> {
+        let bytes = self.read_bytes()?;
+        String::from_utf8(bytes).map_err(From::from)
+    }
+
+    fn read_list_begin(&mut self) -> ::Result<TListIdentifier> {
+        let (element_type, element_count) = self.read_list_set_begin()?;
+        Ok(TListIdentifier::new(element_type, element_count))
+    }
+
+    fn read_list_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn read_set_begin(&mut self) -> ::Result<TSetIdentifier> {
+        let (element_type, element_count) = self.read_list_set_begin()?;
+        Ok(TSetIdentifier::new(element_type, element_count))
+    }
+
+    fn read_set_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn read_map_begin(&mut self) -> ::Result<TMapIdentifier> {
+        let element_count = self.transport.read_varint::<u32>()? as i32;
+        if element_count == 0 {
+            Ok(TMapIdentifier::new(None, None, 0))
+        } else {
+            let type_header = self.read_byte()?;
+            let key_type = collection_u8_to_type((type_header & 0xF0) >> 4)?;
+            let val_type = collection_u8_to_type(type_header & 0x0F)?;
+            Ok(TMapIdentifier::new(key_type, val_type, element_count))
+        }
+    }
+
+    fn read_map_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    // utility
+    //
+
+    fn read_byte(&mut self) -> ::Result<u8> {
+        let mut buf = [0u8; 1];
+        self.transport
+            .read_exact(&mut buf)
+            .map_err(From::from)
+            .map(|_| buf[0])
+    }
+}
+
+impl<T> io::Seek for TCompactInputProtocol<T>
+where
+    T: io::Seek + TReadTransport,
+{
+    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
+        self.transport.seek(pos)
+    }
+}
+
+/// Factory for creating instances of `TCompactInputProtocol`.
+#[derive(Default)]
+pub struct TCompactInputProtocolFactory;
+
+impl TCompactInputProtocolFactory {
+    /// Create a `TCompactInputProtocolFactory`.
+    pub fn new() -> TCompactInputProtocolFactory {
+        TCompactInputProtocolFactory {}
+    }
+}
+
+impl TInputProtocolFactory for TCompactInputProtocolFactory {
+    fn create(&self, transport: Box<TReadTransport + Send>) -> Box<TInputProtocol + Send> {
+        Box::new(TCompactInputProtocol::new(transport))
+    }
+}
+
+/// Write messages using the Thrift compact protocol.
+///
+/// # Examples
+///
+/// Create and use a `TCompactOutputProtocol`.
+///
+/// ```no_run
+/// use thrift::protocol::{TCompactOutputProtocol, TOutputProtocol};
+/// use thrift::transport::TTcpChannel;
+///
+/// let mut channel = TTcpChannel::new();
+/// channel.open("localhost:9090").unwrap();
+///
+/// let mut protocol = TCompactOutputProtocol::new(channel);
+///
+/// protocol.write_bool(true).unwrap();
+/// protocol.write_string("test_string").unwrap();
+/// ```
+#[derive(Debug)]
+pub struct TCompactOutputProtocol<T>
+where
+    T: TWriteTransport,
+{
+    // Identifier of the last field serialized for a struct.
+    last_write_field_id: i16,
+    // Stack of the last written field ids (new entry added each time a nested struct is written).
+    write_field_id_stack: Vec<i16>,
+    // Field identifier of the boolean field to be written.
+    // Saved because boolean fields and their value are encoded in a single byte
+    pending_write_bool_field_identifier: Option<TFieldIdentifier>,
+    // Underlying transport used for byte-level operations.
+    transport: T,
+}
+
+impl<T> TCompactOutputProtocol<T>
+where
+    T: TWriteTransport,
+{
+    /// Create a `TCompactOutputProtocol` that writes bytes to `transport`.
+    pub fn new(transport: T) -> TCompactOutputProtocol<T> {
+        TCompactOutputProtocol {
+            last_write_field_id: 0,
+            write_field_id_stack: Vec::new(),
+            pending_write_bool_field_identifier: None,
+            transport: transport,
+        }
+    }
+
+    // FIXME: field_type as unconstrained u8 is bad
+    fn write_field_header(&mut self, field_type: u8, field_id: i16) -> ::Result<()> {
+        let field_delta = field_id - self.last_write_field_id;
+        if field_delta > 0 && field_delta < 15 {
+            self.write_byte(((field_delta as u8) << 4) | field_type)?;
+        } else {
+            self.write_byte(field_type)?;
+            self.write_i16(field_id)?;
+        }
+        self.last_write_field_id = field_id;
+        Ok(())
+    }
+
+    fn write_list_set_begin(&mut self, element_type: TType, element_count: i32) -> ::Result<()> {
+        let elem_identifier = collection_type_to_u8(element_type);
+        if element_count <= 14 {
+            let header = (element_count as u8) << 4 | elem_identifier;
+            self.write_byte(header)
+        } else {
+            let header = 0xF0 | elem_identifier;
+            self.write_byte(header)?;
+            self.transport
+                .write_varint(element_count as u32)
+                .map_err(From::from)
+                .map(|_| ())
+        }
+    }
+
+    fn assert_no_pending_bool_write(&self) {
+        if let Some(ref f) = self.pending_write_bool_field_identifier {
+            panic!("pending bool field {:?} not written", f)
+        }
+    }
+}
+
+impl<T> TOutputProtocol for TCompactOutputProtocol<T>
+where
+    T: TWriteTransport,
+{
+    fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()> {
+        self.write_byte(COMPACT_PROTOCOL_ID)?;
+        self.write_byte((u8::from(identifier.message_type) << 5) | COMPACT_VERSION)?;
+        self.write_i32(identifier.sequence_number)?;
+        self.write_string(&identifier.name)?;
+        Ok(())
+    }
+
+    fn write_message_end(&mut self) -> ::Result<()> {
+        self.assert_no_pending_bool_write();
+        Ok(())
+    }
+
+    fn write_struct_begin(&mut self, _: &TStructIdentifier) -> ::Result<()> {
+        self.write_field_id_stack.push(self.last_write_field_id);
+        self.last_write_field_id = 0;
+        Ok(())
+    }
+
+    fn write_struct_end(&mut self) -> ::Result<()> {
+        self.assert_no_pending_bool_write();
+        self.last_write_field_id = self
+            .write_field_id_stack
+            .pop()
+            .expect("should have previous field ids");
+        Ok(())
+    }
+
+    fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()> {
+        match identifier.field_type {
+            TType::Bool => {
+                if self.pending_write_bool_field_identifier.is_some() {
+                    panic!(
+                        "should not have a pending bool while writing another bool with id: \
+                         {:?}",
+                        identifier
+                    )
+                }
+                self.pending_write_bool_field_identifier = Some(identifier.clone());
+                Ok(())
+            }
+            _ => {
+                let field_type = type_to_u8(identifier.field_type);
+                let field_id = identifier.id.expect("non-stop field should have field id");
+                self.write_field_header(field_type, field_id)
+            }
+        }
+    }
+
+    fn write_field_end(&mut self) -> ::Result<()> {
+        self.assert_no_pending_bool_write();
+        Ok(())
+    }
+
+    fn write_field_stop(&mut self) -> ::Result<()> {
+        self.assert_no_pending_bool_write();
+        self.write_byte(type_to_u8(TType::Stop))
+    }
+
+    fn write_bool(&mut self, b: bool) -> ::Result<()> {
+        match self.pending_write_bool_field_identifier.take() {
+            Some(pending) => {
+                let field_id = pending.id.expect("bool field should have a field id");
+                let field_type_as_u8 = if b { 0x01 } else { 0x02 };
+                self.write_field_header(field_type_as_u8, field_id)
+            }
+            None => {
+                if b {
+                    self.write_byte(0x01)
+                } else {
+                    self.write_byte(0x02)
+                }
+            }
+        }
+    }
+
+    fn write_bytes(&mut self, b: &[u8]) -> ::Result<()> {
+        self.transport.write_varint(b.len() as u32)?;
+        self.transport.write_all(b).map_err(From::from)
+    }
+
+    fn write_i8(&mut self, i: i8) -> ::Result<()> {
+        self.write_byte(i as u8)
+    }
+
+    fn write_i16(&mut self, i: i16) -> ::Result<()> {
+        self.transport
+            .write_varint(i)
+            .map_err(From::from)
+            .map(|_| ())
+    }
+
+    fn write_i32(&mut self, i: i32) -> ::Result<()> {
+        self.transport
+            .write_varint(i)
+            .map_err(From::from)
+            .map(|_| ())
+    }
+
+    fn write_i64(&mut self, i: i64) -> ::Result<()> {
+        self.transport
+            .write_varint(i)
+            .map_err(From::from)
+            .map(|_| ())
+    }
+
+    fn write_double(&mut self, d: f64) -> ::Result<()> {
+        self.transport.write_f64::<BigEndian>(d).map_err(From::from)
+    }
+
+    fn write_string(&mut self, s: &str) -> ::Result<()> {
+        self.write_bytes(s.as_bytes())
+    }
+
+    fn write_list_begin(&mut self, identifier: &TListIdentifier) -> ::Result<()> {
+        self.write_list_set_begin(identifier.element_type, identifier.size)
+    }
+
+    fn write_list_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> ::Result<()> {
+        self.write_list_set_begin(identifier.element_type, identifier.size)
+    }
+
+    fn write_set_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()> {
+        if identifier.size == 0 {
+            self.write_byte(0)
+        } else {
+            self.transport.write_varint(identifier.size as u32)?;
+
+            let key_type = identifier
+                .key_type
+                .expect("map identifier to write should contain key type");
+            let key_type_byte = collection_type_to_u8(key_type) << 4;
+
+            let val_type = identifier
+                .value_type
+                .expect("map identifier to write should contain value type");
+            let val_type_byte = collection_type_to_u8(val_type);
+
+            let map_type_header = key_type_byte | val_type_byte;
+            self.write_byte(map_type_header)
+        }
+    }
+
+    fn write_map_end(&mut self) -> ::Result<()> {
+        Ok(())
+    }
+
+    fn flush(&mut self) -> ::Result<()> {
+        self.transport.flush().map_err(From::from)
+    }
+
+    // utility
+    //
+
+    fn write_byte(&mut self, b: u8) -> ::Result<()> {
+        self.transport.write(&[b]).map_err(From::from).map(|_| ())
+    }
+}
+
+/// Factory for creating instances of `TCompactOutputProtocol`.
+#[derive(Default)]
+pub struct TCompactOutputProtocolFactory;
+
+impl TCompactOutputProtocolFactory {
+    /// Create a `TCompactOutputProtocolFactory`.
+    pub fn new() -> TCompactOutputProtocolFactory {
+        TCompactOutputProtocolFactory {}
+    }
+}
+
+impl TOutputProtocolFactory for TCompactOutputProtocolFactory {
+    fn create(&self, transport: Box<TWriteTransport + Send>) -> Box<TOutputProtocol + Send> {
+        Box::new(TCompactOutputProtocol::new(transport))
+    }
+}
+
+fn collection_type_to_u8(field_type: TType) -> u8 {
+    match field_type {
+        TType::Bool => 0x01,
+        f => type_to_u8(f),
+    }
+}
+
+fn type_to_u8(field_type: TType) -> u8 {
+    match field_type {
+        TType::Stop => 0x00,
+        TType::I08 => 0x03, // equivalent to TType::Byte
+        TType::I16 => 0x04,
+        TType::I32 => 0x05,
+        TType::I64 => 0x06,
+        TType::Double => 0x07,
+        TType::String => 0x08,
+        TType::List => 0x09,
+        TType::Set => 0x0A,
+        TType::Map => 0x0B,
+        TType::Struct => 0x0C,
+        _ => panic!(format!(
+            "should not have attempted to convert {} to u8",
+            field_type
+        )),
+    }
+}
+
+fn collection_u8_to_type(b: u8) -> ::Result<TType> {
+    match b {
+        0x01 => Ok(TType::Bool),
+        o => u8_to_type(o),
+    }
+}
+
+fn u8_to_type(b: u8) -> ::Result<TType> {
+    match b {
+        0x00 => Ok(TType::Stop),
+        0x03 => Ok(TType::I08), // equivalent to TType::Byte
+        0x04 => Ok(TType::I16),
+        0x05 => Ok(TType::I32),
+        0x06 => Ok(TType::I64),
+        0x07 => Ok(TType::Double),
+        0x08 => Ok(TType::String),
+        0x09 => Ok(TType::List),
+        0x0A => Ok(TType::Set),
+        0x0B => Ok(TType::Map),
+        0x0C => Ok(TType::Struct),
+        unkn => Err(::Error::Protocol(::ProtocolError {
+            kind: ::ProtocolErrorKind::InvalidData,
+            message: format!("cannot convert {} into TType", unkn),
+        })),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use protocol::{
+        TFieldIdentifier, TInputProtocol, TListIdentifier, TMapIdentifier, TMessageIdentifier,
+        TMessageType, TOutputProtocol, TSetIdentifier, TStructIdentifier, TType,
+    };
+    use transport::{ReadHalf, TBufferChannel, TIoChannel, WriteHalf};
+
+    use super::*;
+
+    #[test]
+    fn must_write_message_begin_0() {
+        let (_, mut o_prot) = test_objects();
+
+        assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new(
+            "foo",
+            TMessageType::Call,
+            431
+        )));
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 8] = [
+            0x82, /* protocol ID */
+            0x21, /* message type | protocol version */
+            0xDE,
+            0x06, /* zig-zag varint sequence number */
+            0x03, /* message-name length */
+            0x66,
+            0x6F,
+            0x6F /* "foo" */,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_write_message_begin_1() {
+        let (_, mut o_prot) = test_objects();
+
+        assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new(
+            "bar",
+            TMessageType::Reply,
+            991828
+        )));
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 9] = [
+            0x82, /* protocol ID */
+            0x41, /* message type | protocol version */
+            0xA8,
+            0x89,
+            0x79, /* zig-zag varint sequence number */
+            0x03, /* message-name length */
+            0x62,
+            0x61,
+            0x72 /* "bar" */,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_message_begin() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        let ident = TMessageIdentifier::new("service_call", TMessageType::Call, 1283948);
+
+        assert_success!(o_prot.write_message_begin(&ident));
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let res = assert_success!(i_prot.read_message_begin());
+        assert_eq!(&res, &ident);
+    }
+
+    #[test]
+    fn must_write_message_end() {
+        assert_no_write(|o| o.write_message_end());
+    }
+
+    // NOTE: structs and fields are tested together
+    //
+
+    #[test]
+    fn must_write_struct_with_delta_fields() {
+        let (_, mut o_prot) = test_objects();
+
+        // no bytes should be written however
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // write three fields with tiny field ids
+        // since they're small the field ids will be encoded as deltas
+
+        // since this is the first field (and it's zero) it gets the full varint write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 0)));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 0 and < 15 it can be encoded as a delta
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I16, 4)));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 0 and < 15 it can be encoded as a delta
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::List, 9)));
+        assert_success!(o_prot.write_field_end());
+
+        // now, finish the struct off
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 5] = [
+            0x03, /* field type */
+            0x00, /* first field id */
+            0x44, /* field delta (4) | field type */
+            0x59, /* field delta (5) | field type */
+            0x00 /* field stop */,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_struct_with_delta_fields() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        // no bytes should be written however
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // write three fields with tiny field ids
+        // since they're small the field ids will be encoded as deltas
+
+        // since this is the first field (and it's zero) it gets the full varint write
+        let field_ident_1 = TFieldIdentifier::new("foo", TType::I08, 0);
+        assert_success!(o_prot.write_field_begin(&field_ident_1));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 0 and < 15 it can be encoded as a delta
+        let field_ident_2 = TFieldIdentifier::new("foo", TType::I16, 4);
+        assert_success!(o_prot.write_field_begin(&field_ident_2));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 0 and < 15 it can be encoded as a delta
+        let field_ident_3 = TFieldIdentifier::new("foo", TType::List, 9);
+        assert_success!(o_prot.write_field_begin(&field_ident_3));
+        assert_success!(o_prot.write_field_end());
+
+        // now, finish the struct off
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        // read the struct back
+        assert_success!(i_prot.read_struct_begin());
+
+        let read_ident_1 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_2 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_3 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_4 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
+
+        assert_success!(i_prot.read_struct_end());
+    }
+
+    #[test]
+    fn must_write_struct_with_non_zero_initial_field_and_delta_fields() {
+        let (_, mut o_prot) = test_objects();
+
+        // no bytes should be written however
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // write three fields with tiny field ids
+        // since they're small the field ids will be encoded as deltas
+
+        // gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 1)));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 0 and < 15 it can be encoded as a delta
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2)));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 0 and < 15 it can be encoded as a delta
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 6)));
+        assert_success!(o_prot.write_field_end());
+
+        // now, finish the struct off
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 4] = [
+            0x15, /* field delta (1) | field type */
+            0x1A, /* field delta (1) | field type */
+            0x48, /* field delta (4) | field type */
+            0x00 /* field stop */,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_struct_with_non_zero_initial_field_and_delta_fields() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        // no bytes should be written however
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // write three fields with tiny field ids
+        // since they're small the field ids will be encoded as deltas
+
+        // gets a delta write
+        let field_ident_1 = TFieldIdentifier::new("foo", TType::I32, 1);
+        assert_success!(o_prot.write_field_begin(&field_ident_1));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 0 and < 15 it can be encoded as a delta
+        let field_ident_2 = TFieldIdentifier::new("foo", TType::Set, 2);
+        assert_success!(o_prot.write_field_begin(&field_ident_2));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 0 and < 15 it can be encoded as a delta
+        let field_ident_3 = TFieldIdentifier::new("foo", TType::String, 6);
+        assert_success!(o_prot.write_field_begin(&field_ident_3));
+        assert_success!(o_prot.write_field_end());
+
+        // now, finish the struct off
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        // read the struct back
+        assert_success!(i_prot.read_struct_begin());
+
+        let read_ident_1 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_2 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_3 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_4 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
+
+        assert_success!(i_prot.read_struct_end());
+    }
+
+    #[test]
+    fn must_write_struct_with_long_fields() {
+        let (_, mut o_prot) = test_objects();
+
+        // no bytes should be written however
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // write three fields with field ids that cannot be encoded as deltas
+
+        // since this is the first field (and it's zero) it gets the full varint write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 0)));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta is > 15 it is encoded as a zig-zag varint
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 16)));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta is > 15 it is encoded as a zig-zag varint
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 99)));
+        assert_success!(o_prot.write_field_end());
+
+        // now, finish the struct off
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 8] = [
+            0x05, /* field type */
+            0x00, /* first field id */
+            0x06, /* field type */
+            0x20, /* zig-zag varint field id */
+            0x0A, /* field type */
+            0xC6,
+            0x01, /* zig-zag varint field id */
+            0x00 /* field stop */,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_struct_with_long_fields() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        // no bytes should be written however
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // write three fields with field ids that cannot be encoded as deltas
+
+        // since this is the first field (and it's zero) it gets the full varint write
+        let field_ident_1 = TFieldIdentifier::new("foo", TType::I32, 0);
+        assert_success!(o_prot.write_field_begin(&field_ident_1));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta is > 15 it is encoded as a zig-zag varint
+        let field_ident_2 = TFieldIdentifier::new("foo", TType::I64, 16);
+        assert_success!(o_prot.write_field_begin(&field_ident_2));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta is > 15 it is encoded as a zig-zag varint
+        let field_ident_3 = TFieldIdentifier::new("foo", TType::Set, 99);
+        assert_success!(o_prot.write_field_begin(&field_ident_3));
+        assert_success!(o_prot.write_field_end());
+
+        // now, finish the struct off
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        // read the struct back
+        assert_success!(i_prot.read_struct_begin());
+
+        let read_ident_1 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_2 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_3 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_4 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
+
+        assert_success!(i_prot.read_struct_end());
+    }
+
+    #[test]
+    fn must_write_struct_with_mix_of_long_and_delta_fields() {
+        let (_, mut o_prot) = test_objects();
+
+        // no bytes should be written however
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // write three fields with field ids that cannot be encoded as deltas
+
+        // since the delta is > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9)));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta is > 15 it is encoded as a zig-zag varint
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 1000)));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta is > 15 it is encoded as a zig-zag varint
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2001)));
+        assert_success!(o_prot.write_field_end());
+
+        // since this is only 3 up from the previous it is recorded as a delta
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Set, 2004)));
+        assert_success!(o_prot.write_field_end());
+
+        // now, finish the struct off
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 10] = [
+            0x16, /* field delta (1) | field type */
+            0x85, /* field delta (8) | field type */
+            0x0A, /* field type */
+            0xD0,
+            0x0F, /* zig-zag varint field id */
+            0x0A, /* field type */
+            0xA2,
+            0x1F, /* zig-zag varint field id */
+            0x3A, /* field delta (3) | field type */
+            0x00 /* field stop */,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_struct_with_mix_of_long_and_delta_fields() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        // no bytes should be written however
+        let struct_ident = TStructIdentifier::new("foo");
+        assert_success!(o_prot.write_struct_begin(&struct_ident));
+
+        // write three fields with field ids that cannot be encoded as deltas
+
+        // since the delta is > 0 and < 15 it gets a delta write
+        let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
+        assert_success!(o_prot.write_field_begin(&field_ident_1));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 0 and < 15 it gets a delta write
+        let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9);
+        assert_success!(o_prot.write_field_begin(&field_ident_2));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta is > 15 it is encoded as a zig-zag varint
+        let field_ident_3 = TFieldIdentifier::new("foo", TType::Set, 1000);
+        assert_success!(o_prot.write_field_begin(&field_ident_3));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta is > 15 it is encoded as a zig-zag varint
+        let field_ident_4 = TFieldIdentifier::new("foo", TType::Set, 2001);
+        assert_success!(o_prot.write_field_begin(&field_ident_4));
+        assert_success!(o_prot.write_field_end());
+
+        // since this is only 3 up from the previous it is recorded as a delta
+        let field_ident_5 = TFieldIdentifier::new("foo", TType::Set, 2004);
+        assert_success!(o_prot.write_field_begin(&field_ident_5));
+        assert_success!(o_prot.write_field_end());
+
+        // now, finish the struct off
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        // read the struct back
+        assert_success!(i_prot.read_struct_begin());
+
+        let read_ident_1 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_2 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_3 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_4 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_4
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_5 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_5,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_5
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_6 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_6,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
+
+        assert_success!(i_prot.read_struct_end());
+    }
+
+    #[test]
+    fn must_write_nested_structs_0() {
+        // last field of the containing struct is a delta
+        // first field of the the contained struct is a delta
+
+        let (_, mut o_prot) = test_objects();
+
+        // start containing struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // containing struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
+        assert_success!(o_prot.write_field_end());
+
+        // containing struct
+        // since this delta > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9)));
+        assert_success!(o_prot.write_field_end());
+
+        // start contained struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // contained struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 7)));
+        assert_success!(o_prot.write_field_end());
+
+        // contained struct
+        // since this delta > 15 it gets a full write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 24)));
+        assert_success!(o_prot.write_field_end());
+
+        // end contained struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        // end containing struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 7] = [
+            0x16, /* field delta (1) | field type */
+            0x85, /* field delta (8) | field type */
+            0x73, /* field delta (7) | field type */
+            0x07, /* field type */
+            0x30, /* zig-zag varint field id */
+            0x00, /* field stop - contained */
+            0x00 /* field stop - containing */,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_nested_structs_0() {
+        // last field of the containing struct is a delta
+        // first field of the the contained struct is a delta
+
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        // start containing struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // containing struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
+        assert_success!(o_prot.write_field_begin(&field_ident_1));
+        assert_success!(o_prot.write_field_end());
+
+        // containing struct
+        // since this delta > 0 and < 15 it gets a delta write
+        let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9);
+        assert_success!(o_prot.write_field_begin(&field_ident_2));
+        assert_success!(o_prot.write_field_end());
+
+        // start contained struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // contained struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        let field_ident_3 = TFieldIdentifier::new("foo", TType::I08, 7);
+        assert_success!(o_prot.write_field_begin(&field_ident_3));
+        assert_success!(o_prot.write_field_end());
+
+        // contained struct
+        // since this delta > 15 it gets a full write
+        let field_ident_4 = TFieldIdentifier::new("foo", TType::Double, 24);
+        assert_success!(o_prot.write_field_begin(&field_ident_4));
+        assert_success!(o_prot.write_field_end());
+
+        // end contained struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        // end containing struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        // read containing struct back
+        assert_success!(i_prot.read_struct_begin());
+
+        let read_ident_1 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_2 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        // read contained struct back
+        assert_success!(i_prot.read_struct_begin());
+
+        let read_ident_3 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_4 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_4
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        // end contained struct
+        let read_ident_6 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_6,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
+        assert_success!(i_prot.read_struct_end());
+
+        // end containing struct
+        let read_ident_7 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_7,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
+        assert_success!(i_prot.read_struct_end());
+    }
+
+    #[test]
+    fn must_write_nested_structs_1() {
+        // last field of the containing struct is a delta
+        // first field of the the contained struct is a full write
+
+        let (_, mut o_prot) = test_objects();
+
+        // start containing struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // containing struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
+        assert_success!(o_prot.write_field_end());
+
+        // containing struct
+        // since this delta > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I32, 9)));
+        assert_success!(o_prot.write_field_end());
+
+        // start contained struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // contained struct
+        // since this delta > 15 it gets a full write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 24)));
+        assert_success!(o_prot.write_field_end());
+
+        // contained struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 27)));
+        assert_success!(o_prot.write_field_end());
+
+        // end contained struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        // end containing struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 7] = [
+            0x16, /* field delta (1) | field type */
+            0x85, /* field delta (8) | field type */
+            0x07, /* field type */
+            0x30, /* zig-zag varint field id */
+            0x33, /* field delta (3) | field type */
+            0x00, /* field stop - contained */
+            0x00 /* field stop - containing */,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_nested_structs_1() {
+        // last field of the containing struct is a delta
+        // first field of the the contained struct is a full write
+
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        // start containing struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // containing struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
+        assert_success!(o_prot.write_field_begin(&field_ident_1));
+        assert_success!(o_prot.write_field_end());
+
+        // containing struct
+        // since this delta > 0 and < 15 it gets a delta write
+        let field_ident_2 = TFieldIdentifier::new("foo", TType::I32, 9);
+        assert_success!(o_prot.write_field_begin(&field_ident_2));
+        assert_success!(o_prot.write_field_end());
+
+        // start contained struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // contained struct
+        // since this delta > 15 it gets a full write
+        let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 24);
+        assert_success!(o_prot.write_field_begin(&field_ident_3));
+        assert_success!(o_prot.write_field_end());
+
+        // contained struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 27);
+        assert_success!(o_prot.write_field_begin(&field_ident_4));
+        assert_success!(o_prot.write_field_end());
+
+        // end contained struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        // end containing struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        // read containing struct back
+        assert_success!(i_prot.read_struct_begin());
+
+        let read_ident_1 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_2 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        // read contained struct back
+        assert_success!(i_prot.read_struct_begin());
+
+        let read_ident_3 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_4 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_4
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        // end contained struct
+        let read_ident_6 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_6,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
+        assert_success!(i_prot.read_struct_end());
+
+        // end containing struct
+        let read_ident_7 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_7,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
+        assert_success!(i_prot.read_struct_end());
+    }
+
+    #[test]
+    fn must_write_nested_structs_2() {
+        // last field of the containing struct is a full write
+        // first field of the the contained struct is a delta write
+
+        let (_, mut o_prot) = test_objects();
+
+        // start containing struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // containing struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
+        assert_success!(o_prot.write_field_end());
+
+        // containing struct
+        // since this delta > 15 it gets a full write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 21)));
+        assert_success!(o_prot.write_field_end());
+
+        // start contained struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // contained struct
+        // since this delta > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 7)));
+        assert_success!(o_prot.write_field_end());
+
+        // contained struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 10)));
+        assert_success!(o_prot.write_field_end());
+
+        // end contained struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        // end containing struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 7] = [
+            0x16, /* field delta (1) | field type */
+            0x08, /* field type */
+            0x2A, /* zig-zag varint field id */
+            0x77, /* field delta(7) | field type */
+            0x33, /* field delta (3) | field type */
+            0x00, /* field stop - contained */
+            0x00 /* field stop - containing */,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_nested_structs_2() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        // start containing struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // containing struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
+        assert_success!(o_prot.write_field_begin(&field_ident_1));
+        assert_success!(o_prot.write_field_end());
+
+        // containing struct
+        // since this delta > 15 it gets a full write
+        let field_ident_2 = TFieldIdentifier::new("foo", TType::String, 21);
+        assert_success!(o_prot.write_field_begin(&field_ident_2));
+        assert_success!(o_prot.write_field_end());
+
+        // start contained struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // contained struct
+        // since this delta > 0 and < 15 it gets a delta write
+        let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 7);
+        assert_success!(o_prot.write_field_begin(&field_ident_3));
+        assert_success!(o_prot.write_field_end());
+
+        // contained struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 10);
+        assert_success!(o_prot.write_field_begin(&field_ident_4));
+        assert_success!(o_prot.write_field_end());
+
+        // end contained struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        // end containing struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        // read containing struct back
+        assert_success!(i_prot.read_struct_begin());
+
+        let read_ident_1 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_2 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        // read contained struct back
+        assert_success!(i_prot.read_struct_begin());
+
+        let read_ident_3 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_4 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_4
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        // end contained struct
+        let read_ident_6 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_6,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
+        assert_success!(i_prot.read_struct_end());
+
+        // end containing struct
+        let read_ident_7 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_7,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
+        assert_success!(i_prot.read_struct_end());
+    }
+
+    #[test]
+    fn must_write_nested_structs_3() {
+        // last field of the containing struct is a full write
+        // first field of the the contained struct is a full write
+
+        let (_, mut o_prot) = test_objects();
+
+        // start containing struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // containing struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I64, 1)));
+        assert_success!(o_prot.write_field_end());
+
+        // containing struct
+        // since this delta > 15 it gets a full write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::String, 21)));
+        assert_success!(o_prot.write_field_end());
+
+        // start contained struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // contained struct
+        // since this delta > 15 it gets a full write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Double, 21)));
+        assert_success!(o_prot.write_field_end());
+
+        // contained struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::I08, 27)));
+        assert_success!(o_prot.write_field_end());
+
+        // end contained struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        // end containing struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 8] = [
+            0x16, /* field delta (1) | field type */
+            0x08, /* field type */
+            0x2A, /* zig-zag varint field id */
+            0x07, /* field type */
+            0x2A, /* zig-zag varint field id */
+            0x63, /* field delta (6) | field type */
+            0x00, /* field stop - contained */
+            0x00 /* field stop - containing */,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_nested_structs_3() {
+        // last field of the containing struct is a full write
+        // first field of the the contained struct is a full write
+
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        // start containing struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // containing struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        let field_ident_1 = TFieldIdentifier::new("foo", TType::I64, 1);
+        assert_success!(o_prot.write_field_begin(&field_ident_1));
+        assert_success!(o_prot.write_field_end());
+
+        // containing struct
+        // since this delta > 15 it gets a full write
+        let field_ident_2 = TFieldIdentifier::new("foo", TType::String, 21);
+        assert_success!(o_prot.write_field_begin(&field_ident_2));
+        assert_success!(o_prot.write_field_end());
+
+        // start contained struct
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // contained struct
+        // since this delta > 15 it gets a full write
+        let field_ident_3 = TFieldIdentifier::new("foo", TType::Double, 21);
+        assert_success!(o_prot.write_field_begin(&field_ident_3));
+        assert_success!(o_prot.write_field_end());
+
+        // contained struct
+        // since the delta is > 0 and < 15 it gets a delta write
+        let field_ident_4 = TFieldIdentifier::new("foo", TType::I08, 27);
+        assert_success!(o_prot.write_field_begin(&field_ident_4));
+        assert_success!(o_prot.write_field_end());
+
+        // end contained struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        // end containing struct
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        // read containing struct back
+        assert_success!(i_prot.read_struct_begin());
+
+        let read_ident_1 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_2 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        // read contained struct back
+        assert_success!(i_prot.read_struct_begin());
+
+        let read_ident_3 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_4 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_4
+            }
+        );
+        assert_success!(i_prot.read_field_end());
+
+        // end contained struct
+        let read_ident_6 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_6,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
+        assert_success!(i_prot.read_struct_end());
+
+        // end containing struct
+        let read_ident_7 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_7,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
+        assert_success!(i_prot.read_struct_end());
+    }
+
+    #[test]
+    fn must_write_bool_field() {
+        let (_, mut o_prot) = test_objects();
+
+        // no bytes should be written however
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+
+        // write three fields with field ids that cannot be encoded as deltas
+
+        // since the delta is > 0 and < 16 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
+        assert_success!(o_prot.write_bool(true));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 0 and < 15 it gets a delta write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 9)));
+        assert_success!(o_prot.write_bool(false));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 15 it gets a full write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 26)));
+        assert_success!(o_prot.write_bool(true));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 15 it gets a full write
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 45)));
+        assert_success!(o_prot.write_bool(false));
+        assert_success!(o_prot.write_field_end());
+
+        // now, finish the struct off
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 7] = [
+            0x11, /* field delta (1) | true */
+            0x82, /* field delta (8) | false */
+            0x01, /* true */
+            0x34, /* field id */
+            0x02, /* false */
+            0x5A, /* field id */
+            0x00 /* stop field */,
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_bool_field() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        // no bytes should be written however
+        let struct_ident = TStructIdentifier::new("foo");
+        assert_success!(o_prot.write_struct_begin(&struct_ident));
+
+        // write two fields
+
+        // since the delta is > 0 and < 16 it gets a delta write
+        let field_ident_1 = TFieldIdentifier::new("foo", TType::Bool, 1);
+        assert_success!(o_prot.write_field_begin(&field_ident_1));
+        assert_success!(o_prot.write_bool(true));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 0 and < 15 it gets a delta write
+        let field_ident_2 = TFieldIdentifier::new("foo", TType::Bool, 9);
+        assert_success!(o_prot.write_field_begin(&field_ident_2));
+        assert_success!(o_prot.write_bool(false));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 15 it gets a full write
+        let field_ident_3 = TFieldIdentifier::new("foo", TType::Bool, 26);
+        assert_success!(o_prot.write_field_begin(&field_ident_3));
+        assert_success!(o_prot.write_bool(true));
+        assert_success!(o_prot.write_field_end());
+
+        // since this delta > 15 it gets a full write
+        let field_ident_4 = TFieldIdentifier::new("foo", TType::Bool, 45);
+        assert_success!(o_prot.write_field_begin(&field_ident_4));
+        assert_success!(o_prot.write_bool(false));
+        assert_success!(o_prot.write_field_end());
+
+        // now, finish the struct off
+        assert_success!(o_prot.write_field_stop());
+        assert_success!(o_prot.write_struct_end());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        // read the struct back
+        assert_success!(i_prot.read_struct_begin());
+
+        let read_ident_1 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
+        let read_value_1 = assert_success!(i_prot.read_bool());
+        assert_eq!(read_value_1, true);
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_2 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
+        let read_value_2 = assert_success!(i_prot.read_bool());
+        assert_eq!(read_value_2, false);
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_3 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
+        let read_value_3 = assert_success!(i_prot.read_bool());
+        assert_eq!(read_value_3, true);
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_4 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_4
+            }
+        );
+        let read_value_4 = assert_success!(i_prot.read_bool());
+        assert_eq!(read_value_4, false);
+        assert_success!(i_prot.read_field_end());
+
+        let read_ident_5 = assert_success!(i_prot.read_field_begin());
+        assert_eq!(
+            read_ident_5,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
+
+        assert_success!(i_prot.read_struct_end());
+    }
+
+    #[test]
+    #[should_panic]
+    fn must_fail_if_write_field_end_without_writing_bool_value() {
+        let (_, mut o_prot) = test_objects();
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
+        o_prot.write_field_end().unwrap();
+    }
+
+    #[test]
+    #[should_panic]
+    fn must_fail_if_write_stop_field_without_writing_bool_value() {
+        let (_, mut o_prot) = test_objects();
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
+        o_prot.write_field_stop().unwrap();
+    }
+
+    #[test]
+    #[should_panic]
+    fn must_fail_if_write_struct_end_without_writing_bool_value() {
+        let (_, mut o_prot) = test_objects();
+        assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
+        assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
+        o_prot.write_struct_end().unwrap();
+    }
+
+    #[test]
+    #[should_panic]
+    fn must_fail_if_write_struct_end_without_any_fields() {
+        let (_, mut o_prot) = test_objects();
+        o_prot.write_struct_end().unwrap();
+    }
+
+    #[test]
+    fn must_write_field_end() {
+        assert_no_write(|o| o.write_field_end());
+    }
+
+    #[test]
+    fn must_write_small_sized_list_begin() {
+        let (_, mut o_prot) = test_objects();
+
+        assert_success!(o_prot.write_list_begin(&TListIdentifier::new(TType::I64, 4)));
+
+        let expected: [u8; 1] = [0x46 /* size | elem_type */];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_small_sized_list_begin() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        let ident = TListIdentifier::new(TType::I08, 10);
+
+        assert_success!(o_prot.write_list_begin(&ident));
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let res = assert_success!(i_prot.read_list_begin());
+        assert_eq!(&res, &ident);
+    }
+
+    #[test]
+    fn must_write_large_sized_list_begin() {
+        let (_, mut o_prot) = test_objects();
+
+        let res = o_prot.write_list_begin(&TListIdentifier::new(TType::List, 9999));
+        assert!(res.is_ok());
+
+        let expected: [u8; 3] = [
+            0xF9, /* 0xF0 | elem_type */
+            0x8F, 0x4E, /* size as varint */
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_large_sized_list_begin() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        let ident = TListIdentifier::new(TType::Set, 47381);
+
+        assert_success!(o_prot.write_list_begin(&ident));
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let res = assert_success!(i_prot.read_list_begin());
+        assert_eq!(&res, &ident);
+    }
+
+    #[test]
+    fn must_write_list_end() {
+        assert_no_write(|o| o.write_list_end());
+    }
+
+    #[test]
+    fn must_write_small_sized_set_begin() {
+        let (_, mut o_prot) = test_objects();
+
+        assert_success!(o_prot.write_set_begin(&TSetIdentifier::new(TType::Struct, 2)));
+
+        let expected: [u8; 1] = [0x2C /* size | elem_type */];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_small_sized_set_begin() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        let ident = TSetIdentifier::new(TType::I16, 7);
+
+        assert_success!(o_prot.write_set_begin(&ident));
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let res = assert_success!(i_prot.read_set_begin());
+        assert_eq!(&res, &ident);
+    }
+
+    #[test]
+    fn must_write_large_sized_set_begin() {
+        let (_, mut o_prot) = test_objects();
+
+        assert_success!(o_prot.write_set_begin(&TSetIdentifier::new(TType::Double, 23891)));
+
+        let expected: [u8; 4] = [
+            0xF7, /* 0xF0 | elem_type */
+            0xD3, 0xBA, 0x01, /* size as varint */
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_large_sized_set_begin() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        let ident = TSetIdentifier::new(TType::Map, 3928429);
+
+        assert_success!(o_prot.write_set_begin(&ident));
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let res = assert_success!(i_prot.read_set_begin());
+        assert_eq!(&res, &ident);
+    }
+
+    #[test]
+    fn must_write_set_end() {
+        assert_no_write(|o| o.write_set_end());
+    }
+
+    #[test]
+    fn must_write_zero_sized_map_begin() {
+        let (_, mut o_prot) = test_objects();
+
+        assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::String, TType::I32, 0)));
+
+        let expected: [u8; 1] = [0x00]; // since size is zero we don't write anything
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_read_zero_sized_map_begin() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Double, TType::I32, 0)));
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let res = assert_success!(i_prot.read_map_begin());
+        assert_eq!(
+            &res,
+            &TMapIdentifier {
+                key_type: None,
+                value_type: None,
+                size: 0,
+            }
+        );
+    }
+
+    #[test]
+    fn must_write_map_begin() {
+        let (_, mut o_prot) = test_objects();
+
+        assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(
+            TType::Double,
+            TType::String,
+            238
+        )));
+
+        let expected: [u8; 3] = [
+            0xEE, 0x01, /* size as varint */
+            0x78, /* key type | val type */
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_map_begin() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        let ident = TMapIdentifier::new(TType::Map, TType::List, 1928349);
+
+        assert_success!(o_prot.write_map_begin(&ident));
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        let res = assert_success!(i_prot.read_map_begin());
+        assert_eq!(&res, &ident);
+    }
+
+    #[test]
+    fn must_write_map_end() {
+        assert_no_write(|o| o.write_map_end());
+    }
+
+    #[test]
+    fn must_write_map_with_bool_key_and_value() {
+        let (_, mut o_prot) = test_objects();
+
+        assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Bool, TType::Bool, 1)));
+        assert_success!(o_prot.write_bool(true));
+        assert_success!(o_prot.write_bool(false));
+        assert_success!(o_prot.write_map_end());
+
+        let expected: [u8; 4] = [
+            0x01, /* size as varint */
+            0x11, /* key type | val type */
+            0x01, /* key: true */
+            0x02, /* val: false */
+        ];
+
+        assert_eq_written_bytes!(o_prot, expected);
+    }
+
+    #[test]
+    fn must_round_trip_map_with_bool_value() {
+        let (mut i_prot, mut o_prot) = test_objects();
+
+        let map_ident = TMapIdentifier::new(TType::Bool, TType::Bool, 2);
+        assert_success!(o_prot.write_map_begin(&map_ident));
+        assert_success!(o_prot.write_bool(true));
+        assert_success!(o_prot.write_bool(false));
+        assert_success!(o_prot.write_bool(false));
+        assert_success!(o_prot.write_bool(true));
+        assert_success!(o_prot.write_map_end());
+
+        copy_write_buffer_to_read_buffer!(o_prot);
+
+        // map header
+        let rcvd_ident = assert_success!(i_prot.read_map_begin());
+        assert_eq!(&rcvd_ident, &map_ident);
+        // key 1
+        let b = assert_success!(i_prot.read_bool());
+        assert_eq!(b, true);
+        // val 1
+        let b = assert_success!(i_prot.read_bool());
+        assert_eq!(b, false);
+        // key 2
+        let b = assert_success!(i_prot.read_bool());
+        assert_eq!(b, false);
+        // val 2
+        let b = assert_success!(i_prot.read_bool());
+        assert_eq!(b, true);
+        // map end
+        assert_success!(i_prot.read_map_end());
+    }
+
+    #[test]
+    fn must_read_map_end() {
+        let (mut i_prot, _) = test_objects();
+        assert!(i_prot.read_map_end().is_ok()); // will blow up if we try to read from empty buffer
+    }
+
+    fn test_objects() -> (
+        TCompactInputProtocol<ReadHalf<TBufferChannel>>,
+        TCompactOutputProtocol<WriteHalf<TBufferChannel>>,
+    ) {
+        let mem = TBufferChannel::with_capacity(80, 80);
+
+        let (r_mem, w_mem) = mem.split().unwrap();
+
+        let i_prot = TCompactInputProtocol::new(r_mem);
+        let o_prot = TCompactOutputProtocol::new(w_mem);
+
+        (i_prot, o_prot)
+    }
+
+    fn assert_no_write<F>(mut write_fn: F)
+    where
+        F: FnMut(&mut TCompactOutputProtocol<WriteHalf<TBufferChannel>>) -> ::Result<()>,
+    {
+        let (_, mut o_prot) = test_objects();
+        assert!(write_fn(&mut o_prot).is_ok());
+        assert_eq!(o_prot.transport.write_bytes().len(), 0);
+    }
+}
diff --git a/lib/rs/src/protocol/mod.rs b/lib/rs/src/protocol/mod.rs
new file mode 100644
index 0000000..11c0289
--- /dev/null
+++ b/lib/rs/src/protocol/mod.rs
@@ -0,0 +1,969 @@
+// 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.
+
+//! Types used to send and receive primitives between a Thrift client and server.
+//!
+//! # Examples
+//!
+//! Create and use a `TInputProtocol`.
+//!
+//! ```no_run
+//! use thrift::protocol::{TBinaryInputProtocol, TInputProtocol};
+//! use thrift::transport::TTcpChannel;
+//!
+//! // create the I/O channel
+//! let mut channel = TTcpChannel::new();
+//! channel.open("127.0.0.1:9090").unwrap();
+//!
+//! // create the protocol to decode bytes into types
+//! let mut protocol = TBinaryInputProtocol::new(channel, true);
+//!
+//! // read types from the wire
+//! let field_identifier = protocol.read_field_begin().unwrap();
+//! let field_contents = protocol.read_string().unwrap();
+//! let field_end = protocol.read_field_end().unwrap();
+//! ```
+//!
+//! Create and use a `TOutputProtocol`.
+//!
+//! ```no_run
+//! use thrift::protocol::{TBinaryOutputProtocol, TFieldIdentifier, TOutputProtocol, TType};
+//! use thrift::transport::TTcpChannel;
+//!
+//! // create the I/O channel
+//! let mut channel = TTcpChannel::new();
+//! channel.open("127.0.0.1:9090").unwrap();
+//!
+//! // create the protocol to encode types into bytes
+//! let mut protocol = TBinaryOutputProtocol::new(channel, true);
+//!
+//! // write types
+//! protocol.write_field_begin(&TFieldIdentifier::new("string_thing", TType::String, 1)).unwrap();
+//! protocol.write_string("foo").unwrap();
+//! protocol.write_field_end().unwrap();
+//! ```
+
+use std::convert::From;
+use std::fmt;
+use std::fmt::{Display, Formatter};
+use try_from::TryFrom;
+
+use transport::{TReadTransport, TWriteTransport};
+use {ProtocolError, ProtocolErrorKind};
+
+#[cfg(test)]
+macro_rules! assert_eq_written_bytes {
+    ($o_prot:ident, $expected_bytes:ident) => {{
+        assert_eq!($o_prot.transport.write_bytes(), &$expected_bytes);
+    }};
+}
+
+// FIXME: should take both read and write
+#[cfg(test)]
+macro_rules! copy_write_buffer_to_read_buffer {
+    ($o_prot:ident) => {{
+        $o_prot.transport.copy_write_buffer_to_read_buffer();
+    }};
+}
+
+#[cfg(test)]
+macro_rules! set_readable_bytes {
+    ($i_prot:ident, $bytes:expr) => {
+        $i_prot.transport.set_readable_bytes($bytes);
+    };
+}
+
+mod binary;
+mod compact;
+mod multiplexed;
+mod stored;
+
+pub use self::binary::{
+    TBinaryInputProtocol, TBinaryInputProtocolFactory, TBinaryOutputProtocol,
+    TBinaryOutputProtocolFactory,
+};
+pub use self::compact::{
+    TCompactInputProtocol, TCompactInputProtocolFactory, TCompactOutputProtocol,
+    TCompactOutputProtocolFactory,
+};
+pub use self::multiplexed::TMultiplexedOutputProtocol;
+pub use self::stored::TStoredInputProtocol;
+
+// Default maximum depth to which `TInputProtocol::skip` will skip a Thrift
+// field. A default is necessary because Thrift structs or collections may
+// contain nested structs and collections, which could result in indefinite
+// recursion.
+const MAXIMUM_SKIP_DEPTH: i8 = 64;
+
+/// Converts a stream of bytes into Thrift identifiers, primitives,
+/// containers, or structs.
+///
+/// This trait does not deal with higher-level Thrift concepts like structs or
+/// exceptions - only with primitives and message or container boundaries. Once
+/// bytes are read they are deserialized and an identifier (for example
+/// `TMessageIdentifier`) or a primitive is returned.
+///
+/// All methods return a `thrift::Result`. If an `Err` is returned the protocol
+/// instance and its underlying transport should be terminated.
+///
+/// # Examples
+///
+/// Create and use a `TInputProtocol`
+///
+/// ```no_run
+/// use thrift::protocol::{TBinaryInputProtocol, TInputProtocol};
+/// use thrift::transport::TTcpChannel;
+///
+/// let mut channel = TTcpChannel::new();
+/// channel.open("127.0.0.1:9090").unwrap();
+///
+/// let mut protocol = TBinaryInputProtocol::new(channel, true);
+///
+/// let field_identifier = protocol.read_field_begin().unwrap();
+/// let field_contents = protocol.read_string().unwrap();
+/// let field_end = protocol.read_field_end().unwrap();
+/// ```
+pub trait TInputProtocol {
+    /// Read the beginning of a Thrift message.
+    fn read_message_begin(&mut self) -> ::Result<TMessageIdentifier>;
+    /// Read the end of a Thrift message.
+    fn read_message_end(&mut self) -> ::Result<()>;
+    /// Read the beginning of a Thrift struct.
+    fn read_struct_begin(&mut self) -> ::Result<Option<TStructIdentifier>>;
+    /// Read the end of a Thrift struct.
+    fn read_struct_end(&mut self) -> ::Result<()>;
+    /// Read the beginning of a Thrift struct field.
+    fn read_field_begin(&mut self) -> ::Result<TFieldIdentifier>;
+    /// Read the end of a Thrift struct field.
+    fn read_field_end(&mut self) -> ::Result<()>;
+    /// Read a bool.
+    fn read_bool(&mut self) -> ::Result<bool>;
+    /// Read a fixed-length byte array.
+    fn read_bytes(&mut self) -> ::Result<Vec<u8>>;
+    /// Read a word.
+    fn read_i8(&mut self) -> ::Result<i8>;
+    /// Read a 16-bit signed integer.
+    fn read_i16(&mut self) -> ::Result<i16>;
+    /// Read a 32-bit signed integer.
+    fn read_i32(&mut self) -> ::Result<i32>;
+    /// Read a 64-bit signed integer.
+    fn read_i64(&mut self) -> ::Result<i64>;
+    /// Read a 64-bit float.
+    fn read_double(&mut self) -> ::Result<f64>;
+    /// Read a fixed-length string (not null terminated).
+    fn read_string(&mut self) -> ::Result<String>;
+    /// Read the beginning of a list.
+    fn read_list_begin(&mut self) -> ::Result<TListIdentifier>;
+    /// Read the end of a list.
+    fn read_list_end(&mut self) -> ::Result<()>;
+    /// Read the beginning of a set.
+    fn read_set_begin(&mut self) -> ::Result<TSetIdentifier>;
+    /// Read the end of a set.
+    fn read_set_end(&mut self) -> ::Result<()>;
+    /// Read the beginning of a map.
+    fn read_map_begin(&mut self) -> ::Result<TMapIdentifier>;
+    /// Read the end of a map.
+    fn read_map_end(&mut self) -> ::Result<()>;
+    /// Skip a field with type `field_type` recursively until the default
+    /// maximum skip depth is reached.
+    fn skip(&mut self, field_type: TType) -> ::Result<()> {
+        self.skip_till_depth(field_type, MAXIMUM_SKIP_DEPTH)
+    }
+    /// Skip a field with type `field_type` recursively up to `depth` levels.
+    fn skip_till_depth(&mut self, field_type: TType, depth: i8) -> ::Result<()> {
+        if depth == 0 {
+            return Err(::Error::Protocol(ProtocolError {
+                kind: ProtocolErrorKind::DepthLimit,
+                message: format!("cannot parse past {:?}", field_type),
+            }));
+        }
+
+        match field_type {
+            TType::Bool => self.read_bool().map(|_| ()),
+            TType::I08 => self.read_i8().map(|_| ()),
+            TType::I16 => self.read_i16().map(|_| ()),
+            TType::I32 => self.read_i32().map(|_| ()),
+            TType::I64 => self.read_i64().map(|_| ()),
+            TType::Double => self.read_double().map(|_| ()),
+            TType::String => self.read_string().map(|_| ()),
+            TType::Struct => {
+                self.read_struct_begin()?;
+                loop {
+                    let field_ident = self.read_field_begin()?;
+                    if field_ident.field_type == TType::Stop {
+                        break;
+                    }
+                    self.skip_till_depth(field_ident.field_type, depth - 1)?;
+                }
+                self.read_struct_end()
+            }
+            TType::List => {
+                let list_ident = self.read_list_begin()?;
+                for _ in 0..list_ident.size {
+                    self.skip_till_depth(list_ident.element_type, depth - 1)?;
+                }
+                self.read_list_end()
+            }
+            TType::Set => {
+                let set_ident = self.read_set_begin()?;
+                for _ in 0..set_ident.size {
+                    self.skip_till_depth(set_ident.element_type, depth - 1)?;
+                }
+                self.read_set_end()
+            }
+            TType::Map => {
+                let map_ident = self.read_map_begin()?;
+                for _ in 0..map_ident.size {
+                    let key_type = map_ident
+                        .key_type
+                        .expect("non-zero sized map should contain key type");
+                    let val_type = map_ident
+                        .value_type
+                        .expect("non-zero sized map should contain value type");
+                    self.skip_till_depth(key_type, depth - 1)?;
+                    self.skip_till_depth(val_type, depth - 1)?;
+                }
+                self.read_map_end()
+            }
+            u => Err(::Error::Protocol(ProtocolError {
+                kind: ProtocolErrorKind::Unknown,
+                message: format!("cannot skip field type {:?}", &u),
+            })),
+        }
+    }
+
+    // utility (DO NOT USE IN GENERATED CODE!!!!)
+    //
+
+    /// Read an unsigned byte.
+    ///
+    /// This method should **never** be used in generated code.
+    fn read_byte(&mut self) -> ::Result<u8>;
+}
+
+/// Converts Thrift identifiers, primitives, containers or structs into a
+/// stream of bytes.
+///
+/// This trait does not deal with higher-level Thrift concepts like structs or
+/// exceptions - only with primitives and message or container boundaries.
+/// Write methods take an identifier (for example, `TMessageIdentifier`) or a
+/// primitive. Any or all of the fields in an identifier may be omitted when
+/// writing to the transport. Write methods may even be noops. All of this is
+/// transparent to the caller; as long as a matching `TInputProtocol`
+/// implementation is used, received messages will be decoded correctly.
+///
+/// All methods return a `thrift::Result`. If an `Err` is returned the protocol
+/// instance and its underlying transport should be terminated.
+///
+/// # Examples
+///
+/// Create and use a `TOutputProtocol`
+///
+/// ```no_run
+/// use thrift::protocol::{TBinaryOutputProtocol, TFieldIdentifier, TOutputProtocol, TType};
+/// use thrift::transport::TTcpChannel;
+///
+/// let mut channel = TTcpChannel::new();
+/// channel.open("127.0.0.1:9090").unwrap();
+///
+/// let mut protocol = TBinaryOutputProtocol::new(channel, true);
+///
+/// protocol.write_field_begin(&TFieldIdentifier::new("string_thing", TType::String, 1)).unwrap();
+/// protocol.write_string("foo").unwrap();
+/// protocol.write_field_end().unwrap();
+/// ```
+pub trait TOutputProtocol {
+    /// Write the beginning of a Thrift message.
+    fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()>;
+    /// Write the end of a Thrift message.
+    fn write_message_end(&mut self) -> ::Result<()>;
+    /// Write the beginning of a Thrift struct.
+    fn write_struct_begin(&mut self, identifier: &TStructIdentifier) -> ::Result<()>;
+    /// Write the end of a Thrift struct.
+    fn write_struct_end(&mut self) -> ::Result<()>;
+    /// Write the beginning of a Thrift field.
+    fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()>;
+    /// Write the end of a Thrift field.
+    fn write_field_end(&mut self) -> ::Result<()>;
+    /// Write a STOP field indicating that all the fields in a struct have been
+    /// written.
+    fn write_field_stop(&mut self) -> ::Result<()>;
+    /// Write a bool.
+    fn write_bool(&mut self, b: bool) -> ::Result<()>;
+    /// Write a fixed-length byte array.
+    fn write_bytes(&mut self, b: &[u8]) -> ::Result<()>;
+    /// Write an 8-bit signed integer.
+    fn write_i8(&mut self, i: i8) -> ::Result<()>;
+    /// Write a 16-bit signed integer.
+    fn write_i16(&mut self, i: i16) -> ::Result<()>;
+    /// Write a 32-bit signed integer.
+    fn write_i32(&mut self, i: i32) -> ::Result<()>;
+    /// Write a 64-bit signed integer.
+    fn write_i64(&mut self, i: i64) -> ::Result<()>;
+    /// Write a 64-bit float.
+    fn write_double(&mut self, d: f64) -> ::Result<()>;
+    /// Write a fixed-length string.
+    fn write_string(&mut self, s: &str) -> ::Result<()>;
+    /// Write the beginning of a list.
+    fn write_list_begin(&mut self, identifier: &TListIdentifier) -> ::Result<()>;
+    /// Write the end of a list.
+    fn write_list_end(&mut self) -> ::Result<()>;
+    /// Write the beginning of a set.
+    fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> ::Result<()>;
+    /// Write the end of a set.
+    fn write_set_end(&mut self) -> ::Result<()>;
+    /// Write the beginning of a map.
+    fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()>;
+    /// Write the end of a map.
+    fn write_map_end(&mut self) -> ::Result<()>;
+    /// Flush buffered bytes to the underlying transport.
+    fn flush(&mut self) -> ::Result<()>;
+
+    // utility (DO NOT USE IN GENERATED CODE!!!!)
+    //
+
+    /// Write an unsigned byte.
+    ///
+    /// This method should **never** be used in generated code.
+    fn write_byte(&mut self, b: u8) -> ::Result<()>; // FIXME: REMOVE
+}
+
+impl<P> TInputProtocol for Box<P>
+where
+    P: TInputProtocol + ?Sized,
+{
+    fn read_message_begin(&mut self) -> ::Result<TMessageIdentifier> {
+        (**self).read_message_begin()
+    }
+
+    fn read_message_end(&mut self) -> ::Result<()> {
+        (**self).read_message_end()
+    }
+
+    fn read_struct_begin(&mut self) -> ::Result<Option<TStructIdentifier>> {
+        (**self).read_struct_begin()
+    }
+
+    fn read_struct_end(&mut self) -> ::Result<()> {
+        (**self).read_struct_end()
+    }
+
+    fn read_field_begin(&mut self) -> ::Result<TFieldIdentifier> {
+        (**self).read_field_begin()
+    }
+
+    fn read_field_end(&mut self) -> ::Result<()> {
+        (**self).read_field_end()
+    }
+
+    fn read_bool(&mut self) -> ::Result<bool> {
+        (**self).read_bool()
+    }
+
+    fn read_bytes(&mut self) -> ::Result<Vec<u8>> {
+        (**self).read_bytes()
+    }
+
+    fn read_i8(&mut self) -> ::Result<i8> {
+        (**self).read_i8()
+    }
+
+    fn read_i16(&mut self) -> ::Result<i16> {
+        (**self).read_i16()
+    }
+
+    fn read_i32(&mut self) -> ::Result<i32> {
+        (**self).read_i32()
+    }
+
+    fn read_i64(&mut self) -> ::Result<i64> {
+        (**self).read_i64()
+    }
+
+    fn read_double(&mut self) -> ::Result<f64> {
+        (**self).read_double()
+    }
+
+    fn read_string(&mut self) -> ::Result<String> {
+        (**self).read_string()
+    }
+
+    fn read_list_begin(&mut self) -> ::Result<TListIdentifier> {
+        (**self).read_list_begin()
+    }
+
+    fn read_list_end(&mut self) -> ::Result<()> {
+        (**self).read_list_end()
+    }
+
+    fn read_set_begin(&mut self) -> ::Result<TSetIdentifier> {
+        (**self).read_set_begin()
+    }
+
+    fn read_set_end(&mut self) -> ::Result<()> {
+        (**self).read_set_end()
+    }
+
+    fn read_map_begin(&mut self) -> ::Result<TMapIdentifier> {
+        (**self).read_map_begin()
+    }
+
+    fn read_map_end(&mut self) -> ::Result<()> {
+        (**self).read_map_end()
+    }
+
+    fn read_byte(&mut self) -> ::Result<u8> {
+        (**self).read_byte()
+    }
+}
+
+impl<P> TOutputProtocol for Box<P>
+where
+    P: TOutputProtocol + ?Sized,
+{
+    fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()> {
+        (**self).write_message_begin(identifier)
+    }
+
+    fn write_message_end(&mut self) -> ::Result<()> {
+        (**self).write_message_end()
+    }
+
+    fn write_struct_begin(&mut self, identifier: &TStructIdentifier) -> ::Result<()> {
+        (**self).write_struct_begin(identifier)
+    }
+
+    fn write_struct_end(&mut self) -> ::Result<()> {
+        (**self).write_struct_end()
+    }
+
+    fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()> {
+        (**self).write_field_begin(identifier)
+    }
+
+    fn write_field_end(&mut self) -> ::Result<()> {
+        (**self).write_field_end()
+    }
+
+    fn write_field_stop(&mut self) -> ::Result<()> {
+        (**self).write_field_stop()
+    }
+
+    fn write_bool(&mut self, b: bool) -> ::Result<()> {
+        (**self).write_bool(b)
+    }
+
+    fn write_bytes(&mut self, b: &[u8]) -> ::Result<()> {
+        (**self).write_bytes(b)
+    }
+
+    fn write_i8(&mut self, i: i8) -> ::Result<()> {
+        (**self).write_i8(i)
+    }
+
+    fn write_i16(&mut self, i: i16) -> ::Result<()> {
+        (**self).write_i16(i)
+    }
+
+    fn write_i32(&mut self, i: i32) -> ::Result<()> {
+        (**self).write_i32(i)
+    }
+
+    fn write_i64(&mut self, i: i64) -> ::Result<()> {
+        (**self).write_i64(i)
+    }
+
+    fn write_double(&mut self, d: f64) -> ::Result<()> {
+        (**self).write_double(d)
+    }
+
+    fn write_string(&mut self, s: &str) -> ::Result<()> {
+        (**self).write_string(s)
+    }
+
+    fn write_list_begin(&mut self, identifier: &TListIdentifier) -> ::Result<()> {
+        (**self).write_list_begin(identifier)
+    }
+
+    fn write_list_end(&mut self) -> ::Result<()> {
+        (**self).write_list_end()
+    }
+
+    fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> ::Result<()> {
+        (**self).write_set_begin(identifier)
+    }
+
+    fn write_set_end(&mut self) -> ::Result<()> {
+        (**self).write_set_end()
+    }
+
+    fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()> {
+        (**self).write_map_begin(identifier)
+    }
+
+    fn write_map_end(&mut self) -> ::Result<()> {
+        (**self).write_map_end()
+    }
+
+    fn flush(&mut self) -> ::Result<()> {
+        (**self).flush()
+    }
+
+    fn write_byte(&mut self, b: u8) -> ::Result<()> {
+        (**self).write_byte(b)
+    }
+}
+
+/// Helper type used by servers to create `TInputProtocol` instances for
+/// accepted client connections.
+///
+/// # Examples
+///
+/// Create a `TInputProtocolFactory` and use it to create a `TInputProtocol`.
+///
+/// ```no_run
+/// use thrift::protocol::{TBinaryInputProtocolFactory, TInputProtocolFactory};
+/// use thrift::transport::TTcpChannel;
+///
+/// let mut channel = TTcpChannel::new();
+/// channel.open("127.0.0.1:9090").unwrap();
+///
+/// let factory = TBinaryInputProtocolFactory::new();
+/// let protocol = factory.create(Box::new(channel));
+/// ```
+pub trait TInputProtocolFactory {
+    // Create a `TInputProtocol` that reads bytes from `transport`.
+    fn create(&self, transport: Box<TReadTransport + Send>) -> Box<TInputProtocol + Send>;
+}
+
+impl<T> TInputProtocolFactory for Box<T>
+where
+    T: TInputProtocolFactory + ?Sized,
+{
+    fn create(&self, transport: Box<TReadTransport + Send>) -> Box<TInputProtocol + Send> {
+        (**self).create(transport)
+    }
+}
+
+/// Helper type used by servers to create `TOutputProtocol` instances for
+/// accepted client connections.
+///
+/// # Examples
+///
+/// Create a `TOutputProtocolFactory` and use it to create a `TOutputProtocol`.
+///
+/// ```no_run
+/// use thrift::protocol::{TBinaryOutputProtocolFactory, TOutputProtocolFactory};
+/// use thrift::transport::TTcpChannel;
+///
+/// let mut channel = TTcpChannel::new();
+/// channel.open("127.0.0.1:9090").unwrap();
+///
+/// let factory = TBinaryOutputProtocolFactory::new();
+/// let protocol = factory.create(Box::new(channel));
+/// ```
+pub trait TOutputProtocolFactory {
+    /// Create a `TOutputProtocol` that writes bytes to `transport`.
+    fn create(&self, transport: Box<TWriteTransport + Send>) -> Box<TOutputProtocol + Send>;
+}
+
+impl<T> TOutputProtocolFactory for Box<T>
+where
+    T: TOutputProtocolFactory + ?Sized,
+{
+    fn create(&self, transport: Box<TWriteTransport + Send>) -> Box<TOutputProtocol + Send> {
+        (**self).create(transport)
+    }
+}
+
+/// Thrift message identifier.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct TMessageIdentifier {
+    /// Service call the message is associated with.
+    pub name: String,
+    /// Message type.
+    pub message_type: TMessageType,
+    /// Ordered sequence number identifying the message.
+    pub sequence_number: i32,
+}
+
+impl TMessageIdentifier {
+    /// Create a `TMessageIdentifier` for a Thrift service-call named `name`
+    /// with message type `message_type` and sequence number `sequence_number`.
+    pub fn new<S: Into<String>>(
+        name: S,
+        message_type: TMessageType,
+        sequence_number: i32,
+    ) -> TMessageIdentifier {
+        TMessageIdentifier {
+            name: name.into(),
+            message_type: message_type,
+            sequence_number: sequence_number,
+        }
+    }
+}
+
+/// Thrift struct identifier.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct TStructIdentifier {
+    /// Name of the encoded Thrift struct.
+    pub name: String,
+}
+
+impl TStructIdentifier {
+    /// Create a `TStructIdentifier` for a struct named `name`.
+    pub fn new<S: Into<String>>(name: S) -> TStructIdentifier {
+        TStructIdentifier { name: name.into() }
+    }
+}
+
+/// Thrift field identifier.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct TFieldIdentifier {
+    /// Name of the Thrift field.
+    ///
+    /// `None` if it's not sent over the wire.
+    pub name: Option<String>,
+    /// Field type.
+    ///
+    /// This may be a primitive, container, or a struct.
+    pub field_type: TType,
+    /// Thrift field id.
+    ///
+    /// `None` only if `field_type` is `TType::Stop`.
+    pub id: Option<i16>,
+}
+
+impl TFieldIdentifier {
+    /// Create a `TFieldIdentifier` for a field named `name` with type
+    /// `field_type` and field id `id`.
+    ///
+    /// `id` should be `None` if `field_type` is `TType::Stop`.
+    pub fn new<N, S, I>(name: N, field_type: TType, id: I) -> TFieldIdentifier
+    where
+        N: Into<Option<S>>,
+        S: Into<String>,
+        I: Into<Option<i16>>,
+    {
+        TFieldIdentifier {
+            name: name.into().map(|n| n.into()),
+            field_type: field_type,
+            id: id.into(),
+        }
+    }
+}
+
+/// Thrift list identifier.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct TListIdentifier {
+    /// Type of the elements in the list.
+    pub element_type: TType,
+    /// Number of elements in the list.
+    pub size: i32,
+}
+
+impl TListIdentifier {
+    /// Create a `TListIdentifier` for a list with `size` elements of type
+    /// `element_type`.
+    pub fn new(element_type: TType, size: i32) -> TListIdentifier {
+        TListIdentifier {
+            element_type: element_type,
+            size: size,
+        }
+    }
+}
+
+/// Thrift set identifier.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct TSetIdentifier {
+    /// Type of the elements in the set.
+    pub element_type: TType,
+    /// Number of elements in the set.
+    pub size: i32,
+}
+
+impl TSetIdentifier {
+    /// Create a `TSetIdentifier` for a set with `size` elements of type
+    /// `element_type`.
+    pub fn new(element_type: TType, size: i32) -> TSetIdentifier {
+        TSetIdentifier {
+            element_type: element_type,
+            size: size,
+        }
+    }
+}
+
+/// Thrift map identifier.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct TMapIdentifier {
+    /// Map key type.
+    pub key_type: Option<TType>,
+    /// Map value type.
+    pub value_type: Option<TType>,
+    /// Number of entries in the map.
+    pub size: i32,
+}
+
+impl TMapIdentifier {
+    /// Create a `TMapIdentifier` for a map with `size` entries of type
+    /// `key_type -> value_type`.
+    pub fn new<K, V>(key_type: K, value_type: V, size: i32) -> TMapIdentifier
+    where
+        K: Into<Option<TType>>,
+        V: Into<Option<TType>>,
+    {
+        TMapIdentifier {
+            key_type: key_type.into(),
+            value_type: value_type.into(),
+            size: size,
+        }
+    }
+}
+
+/// Thrift message types.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum TMessageType {
+    /// Service-call request.
+    Call,
+    /// Service-call response.
+    Reply,
+    /// Unexpected error in the remote service.
+    Exception,
+    /// One-way service-call request (no response is expected).
+    OneWay,
+}
+
+impl Display for TMessageType {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        match *self {
+            TMessageType::Call => write!(f, "Call"),
+            TMessageType::Reply => write!(f, "Reply"),
+            TMessageType::Exception => write!(f, "Exception"),
+            TMessageType::OneWay => write!(f, "OneWay"),
+        }
+    }
+}
+
+impl From<TMessageType> for u8 {
+    fn from(message_type: TMessageType) -> Self {
+        match message_type {
+            TMessageType::Call => 0x01,
+            TMessageType::Reply => 0x02,
+            TMessageType::Exception => 0x03,
+            TMessageType::OneWay => 0x04,
+        }
+    }
+}
+
+impl TryFrom<u8> for TMessageType {
+    type Err = ::Error;
+    fn try_from(b: u8) -> ::Result<Self> {
+        match b {
+            0x01 => Ok(TMessageType::Call),
+            0x02 => Ok(TMessageType::Reply),
+            0x03 => Ok(TMessageType::Exception),
+            0x04 => Ok(TMessageType::OneWay),
+            unkn => Err(::Error::Protocol(ProtocolError {
+                kind: ProtocolErrorKind::InvalidData,
+                message: format!("cannot convert {} to TMessageType", unkn),
+            })),
+        }
+    }
+}
+
+/// Thrift struct-field types.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum TType {
+    /// Indicates that there are no more serialized fields in this Thrift struct.
+    Stop,
+    /// Void (`()`) field.
+    Void,
+    /// Boolean.
+    Bool,
+    /// Signed 8-bit int.
+    I08,
+    /// Double-precision number.
+    Double,
+    /// Signed 16-bit int.
+    I16,
+    /// Signed 32-bit int.
+    I32,
+    /// Signed 64-bit int.
+    I64,
+    /// UTF-8 string.
+    String,
+    /// UTF-7 string. *Unsupported*.
+    Utf7,
+    /// Thrift struct.
+    Struct,
+    /// Map.
+    Map,
+    /// Set.
+    Set,
+    /// List.
+    List,
+    /// UTF-8 string.
+    Utf8,
+    /// UTF-16 string. *Unsupported*.
+    Utf16,
+}
+
+impl Display for TType {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        match *self {
+            TType::Stop => write!(f, "STOP"),
+            TType::Void => write!(f, "void"),
+            TType::Bool => write!(f, "bool"),
+            TType::I08 => write!(f, "i08"),
+            TType::Double => write!(f, "double"),
+            TType::I16 => write!(f, "i16"),
+            TType::I32 => write!(f, "i32"),
+            TType::I64 => write!(f, "i64"),
+            TType::String => write!(f, "string"),
+            TType::Utf7 => write!(f, "UTF7"),
+            TType::Struct => write!(f, "struct"),
+            TType::Map => write!(f, "map"),
+            TType::Set => write!(f, "set"),
+            TType::List => write!(f, "list"),
+            TType::Utf8 => write!(f, "UTF8"),
+            TType::Utf16 => write!(f, "UTF16"),
+        }
+    }
+}
+
+/// Compare the expected message sequence number `expected` with the received
+/// message sequence number `actual`.
+///
+/// Return `()` if `actual == expected`, `Err` otherwise.
+pub fn verify_expected_sequence_number(expected: i32, actual: i32) -> ::Result<()> {
+    if expected == actual {
+        Ok(())
+    } else {
+        Err(::Error::Application(::ApplicationError {
+            kind: ::ApplicationErrorKind::BadSequenceId,
+            message: format!("expected {} got {}", expected, actual),
+        }))
+    }
+}
+
+/// Compare the expected service-call name `expected` with the received
+/// service-call name `actual`.
+///
+/// Return `()` if `actual == expected`, `Err` otherwise.
+pub fn verify_expected_service_call(expected: &str, actual: &str) -> ::Result<()> {
+    if expected == actual {
+        Ok(())
+    } else {
+        Err(::Error::Application(::ApplicationError {
+            kind: ::ApplicationErrorKind::WrongMethodName,
+            message: format!("expected {} got {}", expected, actual),
+        }))
+    }
+}
+
+/// Compare the expected message type `expected` with the received message type
+/// `actual`.
+///
+/// Return `()` if `actual == expected`, `Err` otherwise.
+pub fn verify_expected_message_type(expected: TMessageType, actual: TMessageType) -> ::Result<()> {
+    if expected == actual {
+        Ok(())
+    } else {
+        Err(::Error::Application(::ApplicationError {
+            kind: ::ApplicationErrorKind::InvalidMessageType,
+            message: format!("expected {} got {}", expected, actual),
+        }))
+    }
+}
+
+/// Check if a required Thrift struct field exists.
+///
+/// Return `()` if it does, `Err` otherwise.
+pub fn verify_required_field_exists<T>(field_name: &str, field: &Option<T>) -> ::Result<()> {
+    match *field {
+        Some(_) => Ok(()),
+        None => Err(::Error::Protocol(::ProtocolError {
+            kind: ::ProtocolErrorKind::Unknown,
+            message: format!("missing required field {}", field_name),
+        })),
+    }
+}
+
+/// Extract the field id from a Thrift field identifier.
+///
+/// `field_ident` must *not* have `TFieldIdentifier.field_type` of type `TType::Stop`.
+///
+/// Return `TFieldIdentifier.id` if an id exists, `Err` otherwise.
+pub fn field_id(field_ident: &TFieldIdentifier) -> ::Result<i16> {
+    field_ident.id.ok_or_else(|| {
+        ::Error::Protocol(::ProtocolError {
+            kind: ::ProtocolErrorKind::Unknown,
+            message: format!("missing field in in {:?}", field_ident),
+        })
+    })
+}
+
+#[cfg(test)]
+mod tests {
+
+    use std::io::Cursor;
+
+    use super::*;
+    use transport::{TReadTransport, TWriteTransport};
+
+    #[test]
+    fn must_create_usable_input_protocol_from_concrete_input_protocol() {
+        let r: Box<TReadTransport> = Box::new(Cursor::new([0, 1, 2]));
+        let mut t = TCompactInputProtocol::new(r);
+        takes_input_protocol(&mut t)
+    }
+
+    #[test]
+    fn must_create_usable_input_protocol_from_boxed_input() {
+        let r: Box<TReadTransport> = Box::new(Cursor::new([0, 1, 2]));
+        let mut t: Box<TInputProtocol> = Box::new(TCompactInputProtocol::new(r));
+        takes_input_protocol(&mut t)
+    }
+
+    #[test]
+    fn must_create_usable_output_protocol_from_concrete_output_protocol() {
+        let w: Box<TWriteTransport> = Box::new(vec![0u8; 10]);
+        let mut t = TCompactOutputProtocol::new(w);
+        takes_output_protocol(&mut t)
+    }
+
+    #[test]
+    fn must_create_usable_output_protocol_from_boxed_output() {
+        let w: Box<TWriteTransport> = Box::new(vec![0u8; 10]);
+        let mut t: Box<TOutputProtocol> = Box::new(TCompactOutputProtocol::new(w));
+        takes_output_protocol(&mut t)
+    }
+
+    fn takes_input_protocol<R>(t: &mut R)
+    where
+        R: TInputProtocol,
+    {
+        t.read_byte().unwrap();
+    }
+
+    fn takes_output_protocol<W>(t: &mut W)
+    where
+        W: TOutputProtocol,
+    {
+        t.flush().unwrap();
+    }
+}
diff --git a/lib/rs/src/protocol/multiplexed.rs b/lib/rs/src/protocol/multiplexed.rs
new file mode 100644
index 0000000..aaee44f
--- /dev/null
+++ b/lib/rs/src/protocol/multiplexed.rs
@@ -0,0 +1,239 @@
+// 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.
+
+use super::{
+    TFieldIdentifier, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType,
+    TOutputProtocol, TSetIdentifier, TStructIdentifier,
+};
+
+/// `TOutputProtocol` that prefixes the service name to all outgoing Thrift
+/// messages.
+///
+/// A `TMultiplexedOutputProtocol` should be used when multiple Thrift services
+/// send messages over a single I/O channel. By prefixing service identifiers
+/// to outgoing messages receivers are able to demux them and route them to the
+/// appropriate service processor. Rust receivers must use a `TMultiplexedProcessor`
+/// to process incoming messages, while other languages must use their
+/// corresponding multiplexed processor implementations.
+///
+/// For example, given a service `TestService` and a service call `test_call`,
+/// this implementation would identify messages as originating from
+/// `TestService:test_call`.
+///
+/// # Examples
+///
+/// Create and use a `TMultiplexedOutputProtocol`.
+///
+/// ```no_run
+/// use thrift::protocol::{TMessageIdentifier, TMessageType, TOutputProtocol};
+/// use thrift::protocol::{TBinaryOutputProtocol, TMultiplexedOutputProtocol};
+/// use thrift::transport::TTcpChannel;
+///
+/// let mut channel = TTcpChannel::new();
+/// channel.open("localhost:9090").unwrap();
+///
+/// let protocol = TBinaryOutputProtocol::new(channel, true);
+/// let mut protocol = TMultiplexedOutputProtocol::new("service_name", protocol);
+///
+/// let ident = TMessageIdentifier::new("svc_call", TMessageType::Call, 1);
+/// protocol.write_message_begin(&ident).unwrap();
+/// ```
+#[derive(Debug)]
+pub struct TMultiplexedOutputProtocol<P>
+where
+    P: TOutputProtocol,
+{
+    service_name: String,
+    inner: P,
+}
+
+impl<P> TMultiplexedOutputProtocol<P>
+where
+    P: TOutputProtocol,
+{
+    /// Create a `TMultiplexedOutputProtocol` that identifies outgoing messages
+    /// as originating from a service named `service_name` and sends them over
+    /// the `wrapped` `TOutputProtocol`. Outgoing messages are encoded and sent
+    /// by `wrapped`, not by this instance.
+    pub fn new(service_name: &str, wrapped: P) -> TMultiplexedOutputProtocol<P> {
+        TMultiplexedOutputProtocol {
+            service_name: service_name.to_owned(),
+            inner: wrapped,
+        }
+    }
+}
+
+// FIXME: avoid passthrough methods
+impl<P> TOutputProtocol for TMultiplexedOutputProtocol<P>
+where
+    P: TOutputProtocol,
+{
+    fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()> {
+        match identifier.message_type {
+            // FIXME: is there a better way to override identifier here?
+            TMessageType::Call | TMessageType::OneWay => {
+                let identifier = TMessageIdentifier {
+                    name: format!("{}:{}", self.service_name, identifier.name),
+                    ..*identifier
+                };
+                self.inner.write_message_begin(&identifier)
+            }
+            _ => self.inner.write_message_begin(identifier),
+        }
+    }
+
+    fn write_message_end(&mut self) -> ::Result<()> {
+        self.inner.write_message_end()
+    }
+
+    fn write_struct_begin(&mut self, identifier: &TStructIdentifier) -> ::Result<()> {
+        self.inner.write_struct_begin(identifier)
+    }
+
+    fn write_struct_end(&mut self) -> ::Result<()> {
+        self.inner.write_struct_end()
+    }
+
+    fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()> {
+        self.inner.write_field_begin(identifier)
+    }
+
+    fn write_field_end(&mut self) -> ::Result<()> {
+        self.inner.write_field_end()
+    }
+
+    fn write_field_stop(&mut self) -> ::Result<()> {
+        self.inner.write_field_stop()
+    }
+
+    fn write_bytes(&mut self, b: &[u8]) -> ::Result<()> {
+        self.inner.write_bytes(b)
+    }
+
+    fn write_bool(&mut self, b: bool) -> ::Result<()> {
+        self.inner.write_bool(b)
+    }
+
+    fn write_i8(&mut self, i: i8) -> ::Result<()> {
+        self.inner.write_i8(i)
+    }
+
+    fn write_i16(&mut self, i: i16) -> ::Result<()> {
+        self.inner.write_i16(i)
+    }
+
+    fn write_i32(&mut self, i: i32) -> ::Result<()> {
+        self.inner.write_i32(i)
+    }
+
+    fn write_i64(&mut self, i: i64) -> ::Result<()> {
+        self.inner.write_i64(i)
+    }
+
+    fn write_double(&mut self, d: f64) -> ::Result<()> {
+        self.inner.write_double(d)
+    }
+
+    fn write_string(&mut self, s: &str) -> ::Result<()> {
+        self.inner.write_string(s)
+    }
+
+    fn write_list_begin(&mut self, identifier: &TListIdentifier) -> ::Result<()> {
+        self.inner.write_list_begin(identifier)
+    }
+
+    fn write_list_end(&mut self) -> ::Result<()> {
+        self.inner.write_list_end()
+    }
+
+    fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> ::Result<()> {
+        self.inner.write_set_begin(identifier)
+    }
+
+    fn write_set_end(&mut self) -> ::Result<()> {
+        self.inner.write_set_end()
+    }
+
+    fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()> {
+        self.inner.write_map_begin(identifier)
+    }
+
+    fn write_map_end(&mut self) -> ::Result<()> {
+        self.inner.write_map_end()
+    }
+
+    fn flush(&mut self) -> ::Result<()> {
+        self.inner.flush()
+    }
+
+    // utility
+    //
+
+    fn write_byte(&mut self, b: u8) -> ::Result<()> {
+        self.inner.write_byte(b)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use protocol::{TBinaryOutputProtocol, TMessageIdentifier, TMessageType, TOutputProtocol};
+    use transport::{TBufferChannel, TIoChannel, WriteHalf};
+
+    use super::*;
+
+    #[test]
+    fn must_write_message_begin_with_prefixed_service_name() {
+        let mut o_prot = test_objects();
+
+        let ident = TMessageIdentifier::new("bar", TMessageType::Call, 2);
+        assert_success!(o_prot.write_message_begin(&ident));
+
+        #[cfg_attr(rustfmt, rustfmt::skip)]
+        let expected: [u8; 19] = [
+            0x80,
+            0x01, /* protocol identifier */
+            0x00,
+            0x01, /* message type */
+            0x00,
+            0x00,
+            0x00,
+            0x07,
+            0x66,
+            0x6F,
+            0x6F, /* "foo" */
+            0x3A, /* ":" */
+            0x62,
+            0x61,
+            0x72, /* "bar" */
+            0x00,
+            0x00,
+            0x00,
+            0x02 /* sequence number */,
+        ];
+
+        assert_eq!(o_prot.inner.transport.write_bytes(), expected);
+    }
+
+    fn test_objects() -> TMultiplexedOutputProtocol<TBinaryOutputProtocol<WriteHalf<TBufferChannel>>>
+    {
+        let c = TBufferChannel::with_capacity(40, 40);
+        let (_, w_chan) = c.split().unwrap();
+        let prot = TBinaryOutputProtocol::new(w_chan, true);
+        TMultiplexedOutputProtocol::new("foo", prot)
+    }
+}
diff --git a/lib/rs/src/protocol/stored.rs b/lib/rs/src/protocol/stored.rs
new file mode 100644
index 0000000..8c55978
--- /dev/null
+++ b/lib/rs/src/protocol/stored.rs
@@ -0,0 +1,196 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use std::convert::Into;
+
+use super::{
+    TFieldIdentifier, TInputProtocol, TListIdentifier, TMapIdentifier, TMessageIdentifier,
+    TSetIdentifier, TStructIdentifier,
+};
+use ProtocolErrorKind;
+
+/// `TInputProtocol` required to use a `TMultiplexedProcessor`.
+///
+/// A `TMultiplexedProcessor` reads incoming message identifiers to determine to
+/// which `TProcessor` requests should be forwarded. However, once read, those
+/// message identifier bytes are no longer on the wire. Since downstream
+/// processors expect to read message identifiers from the given input protocol
+/// we need some way of supplying a `TMessageIdentifier` with the service-name
+/// stripped. This implementation stores the received `TMessageIdentifier`
+/// (without the service name) and passes it to the wrapped `TInputProtocol`
+/// when `TInputProtocol::read_message_begin(...)` is called. It delegates all
+/// other calls directly to the wrapped `TInputProtocol`.
+///
+/// This type **should not** be used by application code.
+///
+/// # Examples
+///
+/// Create and use a `TStoredInputProtocol`.
+///
+/// ```no_run
+/// use thrift;
+/// use thrift::protocol::{TInputProtocol, TMessageIdentifier, TMessageType, TOutputProtocol};
+/// use thrift::protocol::{TBinaryInputProtocol, TBinaryOutputProtocol, TStoredInputProtocol};
+/// use thrift::server::TProcessor;
+/// use thrift::transport::{TIoChannel, TTcpChannel};
+///
+/// // sample processor
+/// struct ActualProcessor;
+/// impl TProcessor for ActualProcessor {
+///     fn process(
+///         &self,
+///         _: &mut TInputProtocol,
+///         _: &mut TOutputProtocol
+///     ) -> thrift::Result<()> {
+///         unimplemented!()
+///     }
+/// }
+/// let processor = ActualProcessor {};
+///
+/// // construct the shared transport
+/// let mut channel = TTcpChannel::new();
+/// channel.open("localhost:9090").unwrap();
+///
+/// let (i_chan, o_chan) = channel.split().unwrap();
+///
+/// // construct the actual input and output protocols
+/// let mut i_prot = TBinaryInputProtocol::new(i_chan, true);
+/// let mut o_prot = TBinaryOutputProtocol::new(o_chan, true);
+///
+/// // message identifier received from remote and modified to remove the service name
+/// let new_msg_ident = TMessageIdentifier::new("service_call", TMessageType::Call, 1);
+///
+/// // construct the proxy input protocol
+/// let mut proxy_i_prot = TStoredInputProtocol::new(&mut i_prot, new_msg_ident);
+/// let res = processor.process(&mut proxy_i_prot, &mut o_prot);
+/// ```
+// FIXME: implement Debug
+pub struct TStoredInputProtocol<'a> {
+    inner: &'a mut TInputProtocol,
+    message_ident: Option<TMessageIdentifier>,
+}
+
+impl<'a> TStoredInputProtocol<'a> {
+    /// Create a `TStoredInputProtocol` that delegates all calls other than
+    /// `TInputProtocol::read_message_begin(...)` to a `wrapped`
+    /// `TInputProtocol`. `message_ident` is the modified message identifier -
+    /// with service name stripped - that will be passed to
+    /// `wrapped.read_message_begin(...)`.
+    pub fn new(
+        wrapped: &mut TInputProtocol,
+        message_ident: TMessageIdentifier,
+    ) -> TStoredInputProtocol {
+        TStoredInputProtocol {
+            inner: wrapped,
+            message_ident: message_ident.into(),
+        }
+    }
+}
+
+impl<'a> TInputProtocol for TStoredInputProtocol<'a> {
+    fn read_message_begin(&mut self) -> ::Result<TMessageIdentifier> {
+        self.message_ident.take().ok_or_else(|| {
+            ::errors::new_protocol_error(
+                ProtocolErrorKind::Unknown,
+                "message identifier already read",
+            )
+        })
+    }
+
+    fn read_message_end(&mut self) -> ::Result<()> {
+        self.inner.read_message_end()
+    }
+
+    fn read_struct_begin(&mut self) -> ::Result<Option<TStructIdentifier>> {
+        self.inner.read_struct_begin()
+    }
+
+    fn read_struct_end(&mut self) -> ::Result<()> {
+        self.inner.read_struct_end()
+    }
+
+    fn read_field_begin(&mut self) -> ::Result<TFieldIdentifier> {
+        self.inner.read_field_begin()
+    }
+
+    fn read_field_end(&mut self) -> ::Result<()> {
+        self.inner.read_field_end()
+    }
+
+    fn read_bytes(&mut self) -> ::Result<Vec<u8>> {
+        self.inner.read_bytes()
+    }
+
+    fn read_bool(&mut self) -> ::Result<bool> {
+        self.inner.read_bool()
+    }
+
+    fn read_i8(&mut self) -> ::Result<i8> {
+        self.inner.read_i8()
+    }
+
+    fn read_i16(&mut self) -> ::Result<i16> {
+        self.inner.read_i16()
+    }
+
+    fn read_i32(&mut self) -> ::Result<i32> {
+        self.inner.read_i32()
+    }
+
+    fn read_i64(&mut self) -> ::Result<i64> {
+        self.inner.read_i64()
+    }
+
+    fn read_double(&mut self) -> ::Result<f64> {
+        self.inner.read_double()
+    }
+
+    fn read_string(&mut self) -> ::Result<String> {
+        self.inner.read_string()
+    }
+
+    fn read_list_begin(&mut self) -> ::Result<TListIdentifier> {
+        self.inner.read_list_begin()
+    }
+
+    fn read_list_end(&mut self) -> ::Result<()> {
+        self.inner.read_list_end()
+    }
+
+    fn read_set_begin(&mut self) -> ::Result<TSetIdentifier> {
+        self.inner.read_set_begin()
+    }
+
+    fn read_set_end(&mut self) -> ::Result<()> {
+        self.inner.read_set_end()
+    }
+
+    fn read_map_begin(&mut self) -> ::Result<TMapIdentifier> {
+        self.inner.read_map_begin()
+    }
+
+    fn read_map_end(&mut self) -> ::Result<()> {
+        self.inner.read_map_end()
+    }
+
+    // utility
+    //
+
+    fn read_byte(&mut self) -> ::Result<u8> {
+        self.inner.read_byte()
+    }
+}
diff --git a/lib/rs/src/server/mod.rs b/lib/rs/src/server/mod.rs
new file mode 100644
index 0000000..70b381a
--- /dev/null
+++ b/lib/rs/src/server/mod.rs
@@ -0,0 +1,124 @@
+// 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.
+
+//! Types used to implement a Thrift server.
+
+use protocol::{TInputProtocol, TMessageIdentifier, TMessageType, TOutputProtocol};
+use {ApplicationError, ApplicationErrorKind};
+
+mod multiplexed;
+mod threaded;
+
+pub use self::multiplexed::TMultiplexedProcessor;
+pub use self::threaded::TServer;
+
+/// Handles incoming Thrift messages and dispatches them to the user-defined
+/// handler functions.
+///
+/// An implementation is auto-generated for each Thrift service. When used by a
+/// server (for example, a `TSimpleServer`), it will demux incoming service
+/// calls and invoke the corresponding user-defined handler function.
+///
+/// # Examples
+///
+/// Create and start a server using the auto-generated `TProcessor` for
+/// a Thrift service `SimpleService`.
+///
+/// ```no_run
+/// use thrift;
+/// use thrift::protocol::{TInputProtocol, TOutputProtocol};
+/// use thrift::server::TProcessor;
+///
+/// //
+/// // auto-generated
+/// //
+///
+/// // processor for `SimpleService`
+/// struct SimpleServiceSyncProcessor;
+/// impl SimpleServiceSyncProcessor {
+///     fn new<H: SimpleServiceSyncHandler>(processor: H) -> SimpleServiceSyncProcessor {
+///         unimplemented!();
+///     }
+/// }
+///
+/// // `TProcessor` implementation for `SimpleService`
+/// impl TProcessor for SimpleServiceSyncProcessor {
+///     fn process(&self, i: &mut TInputProtocol, o: &mut TOutputProtocol) -> thrift::Result<()> {
+///         unimplemented!();
+///     }
+/// }
+///
+/// // service functions for SimpleService
+/// trait SimpleServiceSyncHandler {
+///     fn service_call(&self) -> thrift::Result<()>;
+/// }
+///
+/// //
+/// // user-code follows
+/// //
+///
+/// // define a handler that will be invoked when `service_call` is received
+/// struct SimpleServiceHandlerImpl;
+/// impl SimpleServiceSyncHandler for SimpleServiceHandlerImpl {
+///     fn service_call(&self) -> thrift::Result<()> {
+///         unimplemented!();
+///     }
+/// }
+///
+/// // instantiate the processor
+/// let processor = SimpleServiceSyncProcessor::new(SimpleServiceHandlerImpl {});
+///
+/// // at this point you can pass the processor to the server
+/// // let server = TServer::new(..., processor);
+/// ```
+pub trait TProcessor {
+    /// Process a Thrift service call.
+    ///
+    /// Reads arguments from `i`, executes the user's handler code, and writes
+    /// the response to `o`.
+    ///
+    /// Returns `()` if the handler was executed; `Err` otherwise.
+    fn process(&self, i: &mut TInputProtocol, o: &mut TOutputProtocol) -> ::Result<()>;
+}
+
+/// Convenience function used in generated `TProcessor` implementations to
+/// return an `ApplicationError` if thrift message processing failed.
+pub fn handle_process_result(
+    msg_ident: &TMessageIdentifier,
+    res: ::Result<()>,
+    o_prot: &mut TOutputProtocol,
+) -> ::Result<()> {
+    if let Err(e) = res {
+        let e = match e {
+            ::Error::Application(a) => a,
+            _ => ApplicationError::new(ApplicationErrorKind::Unknown, format!("{:?}", e)),
+        };
+
+        let ident = TMessageIdentifier::new(
+            msg_ident.name.clone(),
+            TMessageType::Exception,
+            msg_ident.sequence_number,
+        );
+
+        o_prot.write_message_begin(&ident)?;
+        ::Error::write_application_error_to_out_protocol(&e, o_prot)?;
+        o_prot.write_message_end()?;
+        o_prot.flush()
+    } else {
+        Ok(())
+    }
+}
diff --git a/lib/rs/src/server/multiplexed.rs b/lib/rs/src/server/multiplexed.rs
new file mode 100644
index 0000000..e433794
--- /dev/null
+++ b/lib/rs/src/server/multiplexed.rs
@@ -0,0 +1,351 @@
+// 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.
+
+use std::collections::HashMap;
+use std::convert::Into;
+use std::fmt;
+use std::fmt::{Debug, Formatter};
+use std::sync::{Arc, Mutex};
+
+use protocol::{TInputProtocol, TMessageIdentifier, TOutputProtocol, TStoredInputProtocol};
+
+use super::{handle_process_result, TProcessor};
+
+const MISSING_SEPARATOR_AND_NO_DEFAULT: &'static str =
+    "missing service separator and no default processor set";
+type ThreadSafeProcessor = Box<TProcessor + Send + Sync>;
+
+/// A `TProcessor` that can demux service calls to multiple underlying
+/// Thrift services.
+///
+/// Users register service-specific `TProcessor` instances with a
+/// `TMultiplexedProcessor`, and then register that processor with a server
+/// implementation. Following that, all incoming service calls are automatically
+/// routed to the service-specific `TProcessor`.
+///
+/// A `TMultiplexedProcessor` can only handle messages sent by a
+/// `TMultiplexedOutputProtocol`.
+#[derive(Default)]
+pub struct TMultiplexedProcessor {
+    stored: Mutex<StoredProcessors>,
+}
+
+#[derive(Default)]
+struct StoredProcessors {
+    processors: HashMap<String, Arc<ThreadSafeProcessor>>,
+    default_processor: Option<Arc<ThreadSafeProcessor>>,
+}
+
+impl TMultiplexedProcessor {
+    /// Create a new `TMultiplexedProcessor` with no registered service-specific
+    /// processors.
+    pub fn new() -> TMultiplexedProcessor {
+        TMultiplexedProcessor {
+            stored: Mutex::new(StoredProcessors {
+                processors: HashMap::new(),
+                default_processor: None,
+            }),
+        }
+    }
+
+    /// Register a service-specific `processor` for the service named
+    /// `service_name`. This implementation is also backwards-compatible with
+    /// non-multiplexed clients. Set `as_default` to `true` to allow
+    /// non-namespaced requests to be dispatched to a default processor.
+    ///
+    /// Returns success if a new entry was inserted. Returns an error if:
+    /// * A processor exists for `service_name`
+    /// * You attempt to register a processor as default, and an existing default exists
+    #[cfg_attr(feature = "cargo-clippy", allow(map_entry))]
+    pub fn register<S: Into<String>>(
+        &mut self,
+        service_name: S,
+        processor: Box<TProcessor + Send + Sync>,
+        as_default: bool,
+    ) -> ::Result<()> {
+        let mut stored = self.stored.lock().unwrap();
+
+        let name = service_name.into();
+        if !stored.processors.contains_key(&name) {
+            let processor = Arc::new(processor);
+
+            if as_default {
+                if stored.default_processor.is_none() {
+                    stored.processors.insert(name, processor.clone());
+                    stored.default_processor = Some(processor.clone());
+                    Ok(())
+                } else {
+                    Err("cannot reset default processor".into())
+                }
+            } else {
+                stored.processors.insert(name, processor);
+                Ok(())
+            }
+        } else {
+            Err(format!("cannot overwrite existing processor for service {}", name).into())
+        }
+    }
+
+    fn process_message(
+        &self,
+        msg_ident: &TMessageIdentifier,
+        i_prot: &mut TInputProtocol,
+        o_prot: &mut TOutputProtocol,
+    ) -> ::Result<()> {
+        let (svc_name, svc_call) = split_ident_name(&msg_ident.name);
+        debug!("routing svc_name {:?} svc_call {}", &svc_name, &svc_call);
+
+        let processor: Option<Arc<ThreadSafeProcessor>> = {
+            let stored = self.stored.lock().unwrap();
+            if let Some(name) = svc_name {
+                stored.processors.get(name).cloned()
+            } else {
+                stored.default_processor.clone()
+            }
+        };
+
+        match processor {
+            Some(arc) => {
+                let new_msg_ident = TMessageIdentifier::new(
+                    svc_call,
+                    msg_ident.message_type,
+                    msg_ident.sequence_number,
+                );
+                let mut proxy_i_prot = TStoredInputProtocol::new(i_prot, new_msg_ident);
+                (*arc).process(&mut proxy_i_prot, o_prot)
+            }
+            None => Err(missing_processor_message(svc_name).into()),
+        }
+    }
+}
+
+impl TProcessor for TMultiplexedProcessor {
+    fn process(&self, i_prot: &mut TInputProtocol, o_prot: &mut TOutputProtocol) -> ::Result<()> {
+        let msg_ident = i_prot.read_message_begin()?;
+
+        debug!("process incoming msg id:{:?}", &msg_ident);
+        let res = self.process_message(&msg_ident, i_prot, o_prot);
+
+        handle_process_result(&msg_ident, res, o_prot)
+    }
+}
+
+impl Debug for TMultiplexedProcessor {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        let stored = self.stored.lock().unwrap();
+        write!(
+            f,
+            "TMultiplexedProcess {{ registered_count: {:?} default: {:?} }}",
+            stored.processors.keys().len(),
+            stored.default_processor.is_some()
+        )
+    }
+}
+
+fn split_ident_name(ident_name: &str) -> (Option<&str>, &str) {
+    ident_name
+        .find(':')
+        .map(|pos| {
+            let (svc_name, svc_call) = ident_name.split_at(pos);
+            let (_, svc_call) = svc_call.split_at(1); // remove colon from service call name
+            (Some(svc_name), svc_call)
+        })
+        .or_else(|| Some((None, ident_name)))
+        .unwrap()
+}
+
+fn missing_processor_message(svc_name: Option<&str>) -> String {
+    match svc_name {
+        Some(name) => format!("no processor found for service {}", name),
+        None => MISSING_SEPARATOR_AND_NO_DEFAULT.to_owned(),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::convert::Into;
+    use std::sync::atomic::{AtomicBool, Ordering};
+    use std::sync::Arc;
+
+    use protocol::{TBinaryInputProtocol, TBinaryOutputProtocol, TMessageIdentifier, TMessageType};
+    use transport::{ReadHalf, TBufferChannel, TIoChannel, WriteHalf};
+    use {ApplicationError, ApplicationErrorKind};
+
+    use super::*;
+
+    #[test]
+    fn should_split_name_into_proper_separator_and_service_call() {
+        let ident_name = "foo:bar_call";
+        let (serv, call) = split_ident_name(&ident_name);
+        assert_eq!(serv, Some("foo"));
+        assert_eq!(call, "bar_call");
+    }
+
+    #[test]
+    fn should_return_full_ident_if_no_separator_exists() {
+        let ident_name = "bar_call";
+        let (serv, call) = split_ident_name(&ident_name);
+        assert_eq!(serv, None);
+        assert_eq!(call, "bar_call");
+    }
+
+    #[test]
+    fn should_write_error_if_no_separator_found_and_no_default_processor_exists() {
+        let (mut i, mut o) = build_objects();
+
+        let sent_ident = TMessageIdentifier::new("foo", TMessageType::Call, 10);
+        o.write_message_begin(&sent_ident).unwrap();
+        o.flush().unwrap();
+        o.transport.copy_write_buffer_to_read_buffer();
+        o.transport.empty_write_buffer();
+
+        let p = TMultiplexedProcessor::new();
+        p.process(&mut i, &mut o).unwrap(); // at this point an error should be written out
+
+        i.transport.set_readable_bytes(&o.transport.write_bytes());
+        let rcvd_ident = i.read_message_begin().unwrap();
+        let expected_ident = TMessageIdentifier::new("foo", TMessageType::Exception, 10);
+        assert_eq!(rcvd_ident, expected_ident);
+        let rcvd_err = ::Error::read_application_error_from_in_protocol(&mut i).unwrap();
+        let expected_err = ApplicationError::new(
+            ApplicationErrorKind::Unknown,
+            MISSING_SEPARATOR_AND_NO_DEFAULT,
+        );
+        assert_eq!(rcvd_err, expected_err);
+    }
+
+    #[test]
+    fn should_write_error_if_separator_exists_and_no_processor_found() {
+        let (mut i, mut o) = build_objects();
+
+        let sent_ident = TMessageIdentifier::new("missing:call", TMessageType::Call, 10);
+        o.write_message_begin(&sent_ident).unwrap();
+        o.flush().unwrap();
+        o.transport.copy_write_buffer_to_read_buffer();
+        o.transport.empty_write_buffer();
+
+        let p = TMultiplexedProcessor::new();
+        p.process(&mut i, &mut o).unwrap(); // at this point an error should be written out
+
+        i.transport.set_readable_bytes(&o.transport.write_bytes());
+        let rcvd_ident = i.read_message_begin().unwrap();
+        let expected_ident = TMessageIdentifier::new("missing:call", TMessageType::Exception, 10);
+        assert_eq!(rcvd_ident, expected_ident);
+        let rcvd_err = ::Error::read_application_error_from_in_protocol(&mut i).unwrap();
+        let expected_err = ApplicationError::new(
+            ApplicationErrorKind::Unknown,
+            missing_processor_message(Some("missing")),
+        );
+        assert_eq!(rcvd_err, expected_err);
+    }
+
+    #[derive(Default)]
+    struct Service {
+        pub invoked: Arc<AtomicBool>,
+    }
+
+    impl TProcessor for Service {
+        fn process(&self, _: &mut TInputProtocol, _: &mut TOutputProtocol) -> ::Result<()> {
+            let res = self
+                .invoked
+                .compare_and_swap(false, true, Ordering::Relaxed);
+            if res {
+                Ok(())
+            } else {
+                Err("failed swap".into())
+            }
+        }
+    }
+
+    #[test]
+    fn should_route_call_to_correct_processor() {
+        let (mut i, mut o) = build_objects();
+
+        // build the services
+        let svc_1 = Service {
+            invoked: Arc::new(AtomicBool::new(false)),
+        };
+        let atm_1 = svc_1.invoked.clone();
+        let svc_2 = Service {
+            invoked: Arc::new(AtomicBool::new(false)),
+        };
+        let atm_2 = svc_2.invoked.clone();
+
+        // register them
+        let mut p = TMultiplexedProcessor::new();
+        p.register("service_1", Box::new(svc_1), false).unwrap();
+        p.register("service_2", Box::new(svc_2), false).unwrap();
+
+        // make the service call
+        let sent_ident = TMessageIdentifier::new("service_1:call", TMessageType::Call, 10);
+        o.write_message_begin(&sent_ident).unwrap();
+        o.flush().unwrap();
+        o.transport.copy_write_buffer_to_read_buffer();
+        o.transport.empty_write_buffer();
+
+        p.process(&mut i, &mut o).unwrap();
+
+        // service 1 should have been invoked, not service 2
+        assert_eq!(atm_1.load(Ordering::Relaxed), true);
+        assert_eq!(atm_2.load(Ordering::Relaxed), false);
+    }
+
+    #[test]
+    fn should_route_call_to_correct_processor_if_no_separator_exists_and_default_processor_set() {
+        let (mut i, mut o) = build_objects();
+
+        // build the services
+        let svc_1 = Service {
+            invoked: Arc::new(AtomicBool::new(false)),
+        };
+        let atm_1 = svc_1.invoked.clone();
+        let svc_2 = Service {
+            invoked: Arc::new(AtomicBool::new(false)),
+        };
+        let atm_2 = svc_2.invoked.clone();
+
+        // register them
+        let mut p = TMultiplexedProcessor::new();
+        p.register("service_1", Box::new(svc_1), false).unwrap();
+        p.register("service_2", Box::new(svc_2), true).unwrap(); // second processor is default
+
+        // make the service call (it's an old client, so we have to be backwards compatible)
+        let sent_ident = TMessageIdentifier::new("old_call", TMessageType::Call, 10);
+        o.write_message_begin(&sent_ident).unwrap();
+        o.flush().unwrap();
+        o.transport.copy_write_buffer_to_read_buffer();
+        o.transport.empty_write_buffer();
+
+        p.process(&mut i, &mut o).unwrap();
+
+        // service 2 should have been invoked, not service 1
+        assert_eq!(atm_1.load(Ordering::Relaxed), false);
+        assert_eq!(atm_2.load(Ordering::Relaxed), true);
+    }
+
+    fn build_objects() -> (
+        TBinaryInputProtocol<ReadHalf<TBufferChannel>>,
+        TBinaryOutputProtocol<WriteHalf<TBufferChannel>>,
+    ) {
+        let c = TBufferChannel::with_capacity(128, 128);
+        let (r_c, w_c) = c.split().unwrap();
+        (
+            TBinaryInputProtocol::new(r_c, true),
+            TBinaryOutputProtocol::new(w_c, true),
+        )
+    }
+}
diff --git a/lib/rs/src/server/threaded.rs b/lib/rs/src/server/threaded.rs
new file mode 100644
index 0000000..8139a4e
--- /dev/null
+++ b/lib/rs/src/server/threaded.rs
@@ -0,0 +1,234 @@
+// 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.
+
+use std::net::{TcpListener, TcpStream};
+use std::sync::Arc;
+use threadpool::ThreadPool;
+
+use protocol::{TInputProtocol, TInputProtocolFactory, TOutputProtocol, TOutputProtocolFactory};
+use transport::{TIoChannel, TReadTransportFactory, TTcpChannel, TWriteTransportFactory};
+use {ApplicationError, ApplicationErrorKind};
+
+use super::TProcessor;
+
+/// Fixed-size thread-pool blocking Thrift server.
+///
+/// A `TServer` listens on a given address and submits accepted connections
+/// to an **unbounded** queue. Connections from this queue are serviced by
+/// the first available worker thread from a **fixed-size** thread pool. Each
+/// accepted connection is handled by that worker thread, and communication
+/// over this thread occurs sequentially and synchronously (i.e. calls block).
+/// Accepted connections have an input half and an output half, each of which
+/// uses a `TTransport` and `TInputProtocol`/`TOutputProtocol` to translate
+/// messages to and from byes. Any combination of `TInputProtocol`, `TOutputProtocol`
+/// and `TTransport` may be used.
+///
+/// # Examples
+///
+/// Creating and running a `TServer` using Thrift-compiler-generated
+/// service code.
+///
+/// ```no_run
+/// use thrift;
+/// use thrift::protocol::{TInputProtocolFactory, TOutputProtocolFactory};
+/// use thrift::protocol::{TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory};
+/// use thrift::protocol::{TInputProtocol, TOutputProtocol};
+/// use thrift::transport::{TBufferedReadTransportFactory, TBufferedWriteTransportFactory,
+///                         TReadTransportFactory, TWriteTransportFactory};
+/// use thrift::server::{TProcessor, TServer};
+///
+/// //
+/// // auto-generated
+/// //
+///
+/// // processor for `SimpleService`
+/// struct SimpleServiceSyncProcessor;
+/// impl SimpleServiceSyncProcessor {
+///     fn new<H: SimpleServiceSyncHandler>(processor: H) -> SimpleServiceSyncProcessor {
+///         unimplemented!();
+///     }
+/// }
+///
+/// // `TProcessor` implementation for `SimpleService`
+/// impl TProcessor for SimpleServiceSyncProcessor {
+///     fn process(&self, i: &mut TInputProtocol, o: &mut TOutputProtocol) -> thrift::Result<()> {
+///         unimplemented!();
+///     }
+/// }
+///
+/// // service functions for SimpleService
+/// trait SimpleServiceSyncHandler {
+///     fn service_call(&self) -> thrift::Result<()>;
+/// }
+///
+/// //
+/// // user-code follows
+/// //
+///
+/// // define a handler that will be invoked when `service_call` is received
+/// struct SimpleServiceHandlerImpl;
+/// impl SimpleServiceSyncHandler for SimpleServiceHandlerImpl {
+///     fn service_call(&self) -> thrift::Result<()> {
+///         unimplemented!();
+///     }
+/// }
+///
+/// // instantiate the processor
+/// let processor = SimpleServiceSyncProcessor::new(SimpleServiceHandlerImpl {});
+///
+/// // instantiate the server
+/// let i_tr_fact: Box<TReadTransportFactory> = Box::new(TBufferedReadTransportFactory::new());
+/// let i_pr_fact: Box<TInputProtocolFactory> = Box::new(TBinaryInputProtocolFactory::new());
+/// let o_tr_fact: Box<TWriteTransportFactory> = Box::new(TBufferedWriteTransportFactory::new());
+/// let o_pr_fact: Box<TOutputProtocolFactory> = Box::new(TBinaryOutputProtocolFactory::new());
+///
+/// let mut server = TServer::new(
+///     i_tr_fact,
+///     i_pr_fact,
+///     o_tr_fact,
+///     o_pr_fact,
+///     processor,
+///     10
+/// );
+///
+/// // start listening for incoming connections
+/// match server.listen("127.0.0.1:8080") {
+///   Ok(_)  => println!("listen completed"),
+///   Err(e) => println!("listen failed with error {:?}", e),
+/// }
+/// ```
+#[derive(Debug)]
+pub struct TServer<PRC, RTF, IPF, WTF, OPF>
+where
+    PRC: TProcessor + Send + Sync + 'static,
+    RTF: TReadTransportFactory + 'static,
+    IPF: TInputProtocolFactory + 'static,
+    WTF: TWriteTransportFactory + 'static,
+    OPF: TOutputProtocolFactory + 'static,
+{
+    r_trans_factory: RTF,
+    i_proto_factory: IPF,
+    w_trans_factory: WTF,
+    o_proto_factory: OPF,
+    processor: Arc<PRC>,
+    worker_pool: ThreadPool,
+}
+
+impl<PRC, RTF, IPF, WTF, OPF> TServer<PRC, RTF, IPF, WTF, OPF>
+where
+    PRC: TProcessor + Send + Sync + 'static,
+    RTF: TReadTransportFactory + 'static,
+    IPF: TInputProtocolFactory + 'static,
+    WTF: TWriteTransportFactory + 'static,
+    OPF: TOutputProtocolFactory + 'static,
+{
+    /// Create a `TServer`.
+    ///
+    /// Each accepted connection has an input and output half, each of which
+    /// requires a `TTransport` and `TProtocol`. `TServer` uses
+    /// `read_transport_factory` and `input_protocol_factory` to create
+    /// implementations for the input, and `write_transport_factory` and
+    /// `output_protocol_factory` to create implementations for the output.
+    pub fn new(
+        read_transport_factory: RTF,
+        input_protocol_factory: IPF,
+        write_transport_factory: WTF,
+        output_protocol_factory: OPF,
+        processor: PRC,
+        num_workers: usize,
+    ) -> TServer<PRC, RTF, IPF, WTF, OPF> {
+        TServer {
+            r_trans_factory: read_transport_factory,
+            i_proto_factory: input_protocol_factory,
+            w_trans_factory: write_transport_factory,
+            o_proto_factory: output_protocol_factory,
+            processor: Arc::new(processor),
+            worker_pool: ThreadPool::with_name("Thrift service processor".to_owned(), num_workers),
+        }
+    }
+
+    /// Listen for incoming connections on `listen_address`.
+    ///
+    /// `listen_address` should be in the form `host:port`,
+    /// for example: `127.0.0.1:8080`.
+    ///
+    /// Return `()` if successful.
+    ///
+    /// Return `Err` when the server cannot bind to `listen_address` or there
+    /// is an unrecoverable error.
+    pub fn listen(&mut self, listen_address: &str) -> ::Result<()> {
+        let listener = TcpListener::bind(listen_address)?;
+        for stream in listener.incoming() {
+            match stream {
+                Ok(s) => {
+                    let (i_prot, o_prot) = self.new_protocols_for_connection(s)?;
+                    let processor = self.processor.clone();
+                    self.worker_pool
+                        .execute(move || handle_incoming_connection(processor, i_prot, o_prot));
+                }
+                Err(e) => {
+                    warn!("failed to accept remote connection with error {:?}", e);
+                }
+            }
+        }
+
+        Err(::Error::Application(ApplicationError {
+            kind: ApplicationErrorKind::Unknown,
+            message: "aborted listen loop".into(),
+        }))
+    }
+
+    fn new_protocols_for_connection(
+        &mut self,
+        stream: TcpStream,
+    ) -> ::Result<(Box<TInputProtocol + Send>, Box<TOutputProtocol + Send>)> {
+        // create the shared tcp stream
+        let channel = TTcpChannel::with_stream(stream);
+
+        // split it into two - one to be owned by the
+        // input tran/proto and the other by the output
+        let (r_chan, w_chan) = channel.split()?;
+
+        // input protocol and transport
+        let r_tran = self.r_trans_factory.create(Box::new(r_chan));
+        let i_prot = self.i_proto_factory.create(r_tran);
+
+        // output protocol and transport
+        let w_tran = self.w_trans_factory.create(Box::new(w_chan));
+        let o_prot = self.o_proto_factory.create(w_tran);
+
+        Ok((i_prot, o_prot))
+    }
+}
+
+fn handle_incoming_connection<PRC>(
+    processor: Arc<PRC>,
+    i_prot: Box<TInputProtocol>,
+    o_prot: Box<TOutputProtocol>,
+) where
+    PRC: TProcessor,
+{
+    let mut i_prot = i_prot;
+    let mut o_prot = o_prot;
+    loop {
+        let r = processor.process(&mut *i_prot, &mut *o_prot);
+        if let Err(e) = r {
+            warn!("processor completed with error: {:?}", e);
+            break;
+        }
+    }
+}
diff --git a/lib/rs/src/transport/buffered.rs b/lib/rs/src/transport/buffered.rs
new file mode 100644
index 0000000..87cfeff
--- /dev/null
+++ b/lib/rs/src/transport/buffered.rs
@@ -0,0 +1,483 @@
+// 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.
+
+use std::cmp;
+use std::io;
+use std::io::{Read, Write};
+
+use super::{TReadTransport, TReadTransportFactory, TWriteTransport, TWriteTransportFactory};
+
+/// Default capacity of the read buffer in bytes.
+const READ_CAPACITY: usize = 4096;
+
+/// Default capacity of the write buffer in bytes..
+const WRITE_CAPACITY: usize = 4096;
+
+/// Transport that reads messages via an internal buffer.
+///
+/// A `TBufferedReadTransport` maintains a fixed-size internal read buffer.
+/// On a call to `TBufferedReadTransport::read(...)` one full message - both
+/// fixed-length header and bytes - is read from the wrapped channel and buffered.
+/// Subsequent read calls are serviced from the internal buffer until it is
+/// exhausted, at which point the next full message is read from the wrapped
+/// channel.
+///
+/// # Examples
+///
+/// Create and use a `TBufferedReadTransport`.
+///
+/// ```no_run
+/// use std::io::Read;
+/// use thrift::transport::{TBufferedReadTransport, TTcpChannel};
+///
+/// let mut c = TTcpChannel::new();
+/// c.open("localhost:9090").unwrap();
+///
+/// let mut t = TBufferedReadTransport::new(c);
+///
+/// t.read(&mut vec![0u8; 1]).unwrap();
+/// ```
+#[derive(Debug)]
+pub struct TBufferedReadTransport<C>
+where
+    C: Read,
+{
+    buf: Box<[u8]>,
+    pos: usize,
+    cap: usize,
+    chan: C,
+}
+
+impl<C> TBufferedReadTransport<C>
+where
+    C: Read,
+{
+    /// Create a `TBufferedTransport` with default-sized internal read and
+    /// write buffers that wraps the given `TIoChannel`.
+    pub fn new(channel: C) -> TBufferedReadTransport<C> {
+        TBufferedReadTransport::with_capacity(READ_CAPACITY, channel)
+    }
+
+    /// Create a `TBufferedTransport` with an internal read buffer of size
+    /// `read_capacity` and an internal write buffer of size
+    /// `write_capacity` that wraps the given `TIoChannel`.
+    pub fn with_capacity(read_capacity: usize, channel: C) -> TBufferedReadTransport<C> {
+        TBufferedReadTransport {
+            buf: vec![0; read_capacity].into_boxed_slice(),
+            pos: 0,
+            cap: 0,
+            chan: channel,
+        }
+    }
+
+    fn get_bytes(&mut self) -> io::Result<&[u8]> {
+        if self.cap - self.pos == 0 {
+            self.pos = 0;
+            self.cap = self.chan.read(&mut self.buf)?;
+        }
+
+        Ok(&self.buf[self.pos..self.cap])
+    }
+
+    fn consume(&mut self, consumed: usize) {
+        // TODO: was a bug here += <-- test somehow
+        self.pos = cmp::min(self.cap, self.pos + consumed);
+    }
+}
+
+impl<C> Read for TBufferedReadTransport<C>
+where
+    C: Read,
+{
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut bytes_read = 0;
+
+        loop {
+            let nread = {
+                let avail_bytes = self.get_bytes()?;
+                let avail_space = buf.len() - bytes_read;
+                let nread = cmp::min(avail_space, avail_bytes.len());
+                buf[bytes_read..(bytes_read + nread)].copy_from_slice(&avail_bytes[..nread]);
+                nread
+            };
+
+            self.consume(nread);
+            bytes_read += nread;
+
+            if bytes_read == buf.len() || nread == 0 {
+                break;
+            }
+        }
+
+        Ok(bytes_read)
+    }
+}
+
+/// Factory for creating instances of `TBufferedReadTransport`.
+#[derive(Default)]
+pub struct TBufferedReadTransportFactory;
+
+impl TBufferedReadTransportFactory {
+    pub fn new() -> TBufferedReadTransportFactory {
+        TBufferedReadTransportFactory {}
+    }
+}
+
+impl TReadTransportFactory for TBufferedReadTransportFactory {
+    /// Create a `TBufferedReadTransport`.
+    fn create(&self, channel: Box<Read + Send>) -> Box<TReadTransport + Send> {
+        Box::new(TBufferedReadTransport::new(channel))
+    }
+}
+
+/// Transport that writes messages via an internal buffer.
+///
+/// A `TBufferedWriteTransport` maintains a fixed-size internal write buffer.
+/// All writes are made to this buffer and are sent to the wrapped channel only
+/// when `TBufferedWriteTransport::flush()` is called. On a flush a fixed-length
+/// header with a count of the buffered bytes is written, followed by the bytes
+/// themselves.
+///
+/// # Examples
+///
+/// Create and use a `TBufferedWriteTransport`.
+///
+/// ```no_run
+/// use std::io::Write;
+/// use thrift::transport::{TBufferedWriteTransport, TTcpChannel};
+///
+/// let mut c = TTcpChannel::new();
+/// c.open("localhost:9090").unwrap();
+///
+/// let mut t = TBufferedWriteTransport::new(c);
+///
+/// t.write(&[0x00]).unwrap();
+/// t.flush().unwrap();
+/// ```
+#[derive(Debug)]
+pub struct TBufferedWriteTransport<C>
+where
+    C: Write,
+{
+    buf: Vec<u8>,
+    cap: usize,
+    channel: C,
+}
+
+impl<C> TBufferedWriteTransport<C>
+where
+    C: Write,
+{
+    /// Create a `TBufferedTransport` with default-sized internal read and
+    /// write buffers that wraps the given `TIoChannel`.
+    pub fn new(channel: C) -> TBufferedWriteTransport<C> {
+        TBufferedWriteTransport::with_capacity(WRITE_CAPACITY, channel)
+    }
+
+    /// Create a `TBufferedTransport` with an internal read buffer of size
+    /// `read_capacity` and an internal write buffer of size
+    /// `write_capacity` that wraps the given `TIoChannel`.
+    pub fn with_capacity(write_capacity: usize, channel: C) -> TBufferedWriteTransport<C> {
+        assert!(
+            write_capacity > 0,
+            "write buffer size must be a positive integer"
+        );
+
+        TBufferedWriteTransport {
+            buf: Vec::with_capacity(write_capacity),
+            cap: write_capacity,
+            channel: channel,
+        }
+    }
+}
+
+impl<C> Write for TBufferedWriteTransport<C>
+where
+    C: Write,
+{
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        if !buf.is_empty() {
+            let mut avail_bytes;
+
+            loop {
+                avail_bytes = cmp::min(buf.len(), self.cap - self.buf.len());
+
+                if avail_bytes == 0 {
+                    self.flush()?;
+                } else {
+                    break;
+                }
+            }
+
+            let avail_bytes = avail_bytes;
+
+            self.buf.extend_from_slice(&buf[..avail_bytes]);
+            assert!(self.buf.len() <= self.cap, "copy overflowed buffer");
+
+            Ok(avail_bytes)
+        } else {
+            Ok(0)
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.channel.write_all(&self.buf)?;
+        self.channel.flush()?;
+        self.buf.clear();
+        Ok(())
+    }
+}
+
+/// Factory for creating instances of `TBufferedWriteTransport`.
+#[derive(Default)]
+pub struct TBufferedWriteTransportFactory;
+
+impl TBufferedWriteTransportFactory {
+    pub fn new() -> TBufferedWriteTransportFactory {
+        TBufferedWriteTransportFactory {}
+    }
+}
+
+impl TWriteTransportFactory for TBufferedWriteTransportFactory {
+    /// Create a `TBufferedWriteTransport`.
+    fn create(&self, channel: Box<Write + Send>) -> Box<TWriteTransport + Send> {
+        Box::new(TBufferedWriteTransport::new(channel))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::io::{Read, Write};
+
+    use super::*;
+    use transport::TBufferChannel;
+
+    #[test]
+    fn must_return_zero_if_read_buffer_is_empty() {
+        let mem = TBufferChannel::with_capacity(10, 0);
+        let mut t = TBufferedReadTransport::with_capacity(10, mem);
+
+        let mut b = vec![0; 10];
+        let read_result = t.read(&mut b);
+
+        assert_eq!(read_result.unwrap(), 0);
+    }
+
+    #[test]
+    fn must_return_zero_if_caller_reads_into_zero_capacity_buffer() {
+        let mem = TBufferChannel::with_capacity(10, 0);
+        let mut t = TBufferedReadTransport::with_capacity(10, mem);
+
+        let read_result = t.read(&mut []);
+
+        assert_eq!(read_result.unwrap(), 0);
+    }
+
+    #[test]
+    fn must_return_zero_if_nothing_more_can_be_read() {
+        let mem = TBufferChannel::with_capacity(4, 0);
+        let mut t = TBufferedReadTransport::with_capacity(4, mem);
+
+        t.chan.set_readable_bytes(&[0, 1, 2, 3]);
+
+        // read buffer is exactly the same size as bytes available
+        let mut buf = vec![0u8; 4];
+        let read_result = t.read(&mut buf);
+
+        // we've read exactly 4 bytes
+        assert_eq!(read_result.unwrap(), 4);
+        assert_eq!(&buf, &[0, 1, 2, 3]);
+
+        // try read again
+        let buf_again = vec![0u8; 4];
+        let read_result = t.read(&mut buf);
+
+        // this time, 0 bytes and we haven't changed the buffer
+        assert_eq!(read_result.unwrap(), 0);
+        assert_eq!(&buf_again, &[0, 0, 0, 0])
+    }
+
+    #[test]
+    fn must_fill_user_buffer_with_only_as_many_bytes_as_available() {
+        let mem = TBufferChannel::with_capacity(4, 0);
+        let mut t = TBufferedReadTransport::with_capacity(4, mem);
+
+        t.chan.set_readable_bytes(&[0, 1, 2, 3]);
+
+        // read buffer is much larger than the bytes available
+        let mut buf = vec![0u8; 8];
+        let read_result = t.read(&mut buf);
+
+        // we've read exactly 4 bytes
+        assert_eq!(read_result.unwrap(), 4);
+        assert_eq!(&buf[..4], &[0, 1, 2, 3]);
+
+        // try read again
+        let read_result = t.read(&mut buf[4..]);
+
+        // this time, 0 bytes and we haven't changed the buffer
+        assert_eq!(read_result.unwrap(), 0);
+        assert_eq!(&buf, &[0, 1, 2, 3, 0, 0, 0, 0])
+    }
+
+    #[test]
+    fn must_read_successfully() {
+        // this test involves a few loops within the buffered transport
+        // itself where it has to drain the underlying transport in order
+        // to service a read
+
+        // we have a much smaller buffer than the
+        // underlying transport has bytes available
+        let mem = TBufferChannel::with_capacity(10, 0);
+        let mut t = TBufferedReadTransport::with_capacity(2, mem);
+
+        // fill the underlying transport's byte buffer
+        let mut readable_bytes = [0u8; 10];
+        for i in 0..10 {
+            readable_bytes[i] = i as u8;
+        }
+
+        t.chan.set_readable_bytes(&readable_bytes);
+
+        // we ask to read into a buffer that's much larger
+        // than the one the buffered transport has; as a result
+        // it's going to have to keep asking the underlying
+        // transport for more bytes
+        let mut buf = [0u8; 8];
+        let read_result = t.read(&mut buf);
+
+        // we should have read 8 bytes
+        assert_eq!(read_result.unwrap(), 8);
+        assert_eq!(&buf, &[0, 1, 2, 3, 4, 5, 6, 7]);
+
+        // let's clear out the buffer and try read again
+        for i in 0..8 {
+            buf[i] = 0;
+        }
+        let read_result = t.read(&mut buf);
+
+        // this time we were only able to read 2 bytes
+        // (all that's remaining from the underlying transport)
+        // let's also check that the remaining bytes are untouched
+        assert_eq!(read_result.unwrap(), 2);
+        assert_eq!(&buf[0..2], &[8, 9]);
+        assert_eq!(&buf[2..], &[0, 0, 0, 0, 0, 0]);
+
+        // try read again (we should get 0)
+        // and all the existing bytes were untouched
+        let read_result = t.read(&mut buf);
+        assert_eq!(read_result.unwrap(), 0);
+        assert_eq!(&buf[0..2], &[8, 9]);
+        assert_eq!(&buf[2..], &[0, 0, 0, 0, 0, 0]);
+    }
+
+    #[test]
+    fn must_return_error_when_nothing_can_be_written_to_underlying_channel() {
+        let mem = TBufferChannel::with_capacity(0, 0);
+        let mut t = TBufferedWriteTransport::with_capacity(1, mem);
+
+        let b = vec![0; 10];
+        let r = t.write(&b);
+
+        // should have written 1 byte
+        assert_eq!(r.unwrap(), 1);
+
+        // let's try again...
+        let r = t.write(&b[1..]);
+
+        // this time we'll error out because the auto-flush failed
+        assert!(r.is_err());
+    }
+
+    #[test]
+    fn must_return_zero_if_caller_calls_write_with_empty_buffer() {
+        let mem = TBufferChannel::with_capacity(0, 10);
+        let mut t = TBufferedWriteTransport::with_capacity(10, mem);
+
+        let r = t.write(&[]);
+        let expected: [u8; 0] = [];
+
+        assert_eq!(r.unwrap(), 0);
+        assert_eq_transport_written_bytes!(t, expected);
+    }
+
+    #[test]
+    fn must_auto_flush_if_write_buffer_full() {
+        let mem = TBufferChannel::with_capacity(0, 8);
+        let mut t = TBufferedWriteTransport::with_capacity(4, mem);
+
+        let b0 = [0x00, 0x01, 0x02, 0x03];
+        let b1 = [0x04, 0x05, 0x06, 0x07];
+
+        // write the first 4 bytes; we've now filled the transport's write buffer
+        let r = t.write(&b0);
+        assert_eq!(r.unwrap(), 4);
+
+        // try write the next 4 bytes; this causes the transport to auto-flush the first 4 bytes
+        let r = t.write(&b1);
+        assert_eq!(r.unwrap(), 4);
+
+        // check that in writing the second 4 bytes we auto-flushed the first 4 bytes
+        assert_eq_transport_num_written_bytes!(t, 4);
+        assert_eq_transport_written_bytes!(t, b0);
+        t.channel.empty_write_buffer();
+
+        // now flush the transport to push the second 4 bytes to the underlying channel
+        assert!(t.flush().is_ok());
+
+        // check that we wrote out the second 4 bytes
+        assert_eq_transport_written_bytes!(t, b1);
+    }
+
+    #[test]
+    fn must_write_to_inner_transport_on_flush() {
+        let mem = TBufferChannel::with_capacity(10, 10);
+        let mut t = TBufferedWriteTransport::new(mem);
+
+        let b: [u8; 5] = [0, 1, 2, 3, 4];
+        assert_eq!(t.write(&b).unwrap(), 5);
+        assert_eq_transport_num_written_bytes!(t, 0);
+
+        assert!(t.flush().is_ok());
+
+        assert_eq_transport_written_bytes!(t, b);
+    }
+
+    #[test]
+    fn must_write_successfully_after_flush() {
+        let mem = TBufferChannel::with_capacity(0, 5);
+        let mut t = TBufferedWriteTransport::with_capacity(5, mem);
+
+        // write and flush
+        let b: [u8; 5] = [0, 1, 2, 3, 4];
+        assert_eq!(t.write(&b).unwrap(), 5);
+        assert!(t.flush().is_ok());
+
+        // check the flushed bytes
+        assert_eq_transport_written_bytes!(t, b);
+
+        // reset our underlying transport
+        t.channel.empty_write_buffer();
+
+        // write and flush again
+        assert_eq!(t.write(&b).unwrap(), 5);
+        assert!(t.flush().is_ok());
+
+        // check the flushed bytes
+        assert_eq_transport_written_bytes!(t, b);
+    }
+}
diff --git a/lib/rs/src/transport/framed.rs b/lib/rs/src/transport/framed.rs
new file mode 100644
index 0000000..a009307
--- /dev/null
+++ b/lib/rs/src/transport/framed.rs
@@ -0,0 +1,459 @@
+// 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.
+
+use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
+use std::cmp;
+use std::io;
+use std::io::{Read, Write};
+
+use super::{TReadTransport, TReadTransportFactory, TWriteTransport, TWriteTransportFactory};
+
+/// Default capacity of the read buffer in bytes.
+const READ_CAPACITY: usize = 4096;
+
+/// Default capacity of the write buffer in bytes.
+const WRITE_CAPACITY: usize = 4096;
+
+/// Transport that reads framed messages.
+///
+/// A `TFramedReadTransport` maintains a fixed-size internal read buffer.
+/// On a call to `TFramedReadTransport::read(...)` one full message - both
+/// fixed-length header and bytes - is read from the wrapped channel and
+/// buffered. Subsequent read calls are serviced from the internal buffer
+/// until it is exhausted, at which point the next full message is read
+/// from the wrapped channel.
+///
+/// # Examples
+///
+/// Create and use a `TFramedReadTransport`.
+///
+/// ```no_run
+/// use std::io::Read;
+/// use thrift::transport::{TFramedReadTransport, TTcpChannel};
+///
+/// let mut c = TTcpChannel::new();
+/// c.open("localhost:9090").unwrap();
+///
+/// let mut t = TFramedReadTransport::new(c);
+///
+/// t.read(&mut vec![0u8; 1]).unwrap();
+/// ```
+#[derive(Debug)]
+pub struct TFramedReadTransport<C>
+where
+    C: Read,
+{
+    buf: Vec<u8>,
+    pos: usize,
+    cap: usize,
+    chan: C,
+}
+
+impl<C> TFramedReadTransport<C>
+where
+    C: Read,
+{
+    /// Create a `TFramedReadTransport` with a default-sized
+    /// internal read buffer that wraps the given `TIoChannel`.
+    pub fn new(channel: C) -> TFramedReadTransport<C> {
+        TFramedReadTransport::with_capacity(READ_CAPACITY, channel)
+    }
+
+    /// Create a `TFramedTransport` with an internal read buffer
+    /// of size `read_capacity` that wraps the given `TIoChannel`.
+    pub fn with_capacity(read_capacity: usize, channel: C) -> TFramedReadTransport<C> {
+        TFramedReadTransport {
+            buf: vec![0; read_capacity], // FIXME: do I actually have to do this?
+            pos: 0,
+            cap: 0,
+            chan: channel,
+        }
+    }
+}
+
+impl<C> Read for TFramedReadTransport<C>
+where
+    C: Read,
+{
+    fn read(&mut self, b: &mut [u8]) -> io::Result<usize> {
+        if self.cap - self.pos == 0 {
+            let message_size = self.chan.read_i32::<BigEndian>()? as usize;
+
+            let buf_capacity = cmp::max(message_size, READ_CAPACITY);
+            self.buf.resize(buf_capacity, 0);
+
+            self.chan.read_exact(&mut self.buf[..message_size])?;
+            self.cap = message_size as usize;
+            self.pos = 0;
+        }
+
+        let nread = cmp::min(b.len(), self.cap - self.pos);
+        b[..nread].clone_from_slice(&self.buf[self.pos..self.pos + nread]);
+        self.pos += nread;
+
+        Ok(nread)
+    }
+}
+
+/// Factory for creating instances of `TFramedReadTransport`.
+#[derive(Default)]
+pub struct TFramedReadTransportFactory;
+
+impl TFramedReadTransportFactory {
+    pub fn new() -> TFramedReadTransportFactory {
+        TFramedReadTransportFactory {}
+    }
+}
+
+impl TReadTransportFactory for TFramedReadTransportFactory {
+    /// Create a `TFramedReadTransport`.
+    fn create(&self, channel: Box<Read + Send>) -> Box<TReadTransport + Send> {
+        Box::new(TFramedReadTransport::new(channel))
+    }
+}
+
+/// Transport that writes framed messages.
+///
+/// A `TFramedWriteTransport` maintains a fixed-size internal write buffer. All
+/// writes are made to this buffer and are sent to the wrapped channel only
+/// when `TFramedWriteTransport::flush()` is called. On a flush a fixed-length
+/// header with a count of the buffered bytes is written, followed by the bytes
+/// themselves.
+///
+/// # Examples
+///
+/// Create and use a `TFramedWriteTransport`.
+///
+/// ```no_run
+/// use std::io::Write;
+/// use thrift::transport::{TFramedWriteTransport, TTcpChannel};
+///
+/// let mut c = TTcpChannel::new();
+/// c.open("localhost:9090").unwrap();
+///
+/// let mut t = TFramedWriteTransport::new(c);
+///
+/// t.write(&[0x00]).unwrap();
+/// t.flush().unwrap();
+/// ```
+#[derive(Debug)]
+pub struct TFramedWriteTransport<C>
+where
+    C: Write,
+{
+    buf: Vec<u8>,
+    channel: C,
+}
+
+impl<C> TFramedWriteTransport<C>
+where
+    C: Write,
+{
+    /// Create a `TFramedWriteTransport` with default-sized internal
+    /// write buffer that wraps the given `TIoChannel`.
+    pub fn new(channel: C) -> TFramedWriteTransport<C> {
+        TFramedWriteTransport::with_capacity(WRITE_CAPACITY, channel)
+    }
+
+    /// Create a `TFramedWriteTransport` with an internal write buffer
+    /// of size `write_capacity` that wraps the given `TIoChannel`.
+    pub fn with_capacity(write_capacity: usize, channel: C) -> TFramedWriteTransport<C> {
+        TFramedWriteTransport {
+            buf: Vec::with_capacity(write_capacity),
+            channel,
+        }
+    }
+}
+
+impl<C> Write for TFramedWriteTransport<C>
+where
+    C: Write,
+{
+    fn write(&mut self, b: &[u8]) -> io::Result<usize> {
+        let current_capacity = self.buf.capacity();
+        let available_space = current_capacity - self.buf.len();
+        if b.len() > available_space {
+            let additional_space = cmp::max(b.len() - available_space, current_capacity);
+            self.buf.reserve(additional_space);
+        }
+
+        self.buf.extend_from_slice(b);
+        Ok(b.len())
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        let message_size = self.buf.len();
+
+        if let 0 = message_size {
+            return Ok(());
+        } else {
+            self.channel.write_i32::<BigEndian>(message_size as i32)?;
+        }
+
+        // will spin if the underlying channel can't be written to
+        let mut byte_index = 0;
+        while byte_index < message_size {
+            let nwrite = self.channel.write(&self.buf[byte_index..message_size])?;
+            byte_index = cmp::min(byte_index + nwrite, message_size);
+        }
+
+        let buf_capacity = cmp::min(self.buf.capacity(), WRITE_CAPACITY);
+        self.buf.resize(buf_capacity, 0);
+        self.buf.clear();
+
+        self.channel.flush()
+    }
+}
+
+/// Factory for creating instances of `TFramedWriteTransport`.
+#[derive(Default)]
+pub struct TFramedWriteTransportFactory;
+
+impl TFramedWriteTransportFactory {
+    pub fn new() -> TFramedWriteTransportFactory {
+        TFramedWriteTransportFactory {}
+    }
+}
+
+impl TWriteTransportFactory for TFramedWriteTransportFactory {
+    /// Create a `TFramedWriteTransport`.
+    fn create(&self, channel: Box<Write + Send>) -> Box<TWriteTransport + Send> {
+        Box::new(TFramedWriteTransport::new(channel))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use transport::mem::TBufferChannel;
+
+    // FIXME: test a forced reserve
+
+    #[test]
+    fn must_read_message_smaller_than_initial_buffer_size() {
+        let c = TBufferChannel::with_capacity(10, 10);
+        let mut t = TFramedReadTransport::with_capacity(8, c);
+
+        t.chan.set_readable_bytes(&[
+            0x00, 0x00, 0x00, 0x04, /* message size */
+            0x00, 0x01, 0x02, 0x03, /* message body */
+        ]);
+
+        let mut buf = vec![0; 8];
+
+        // we've read exactly 4 bytes
+        assert_eq!(t.read(&mut buf).unwrap(), 4);
+        assert_eq!(&buf[..4], &[0x00, 0x01, 0x02, 0x03]);
+    }
+
+    #[test]
+    fn must_read_message_greater_than_initial_buffer_size() {
+        let c = TBufferChannel::with_capacity(10, 10);
+        let mut t = TFramedReadTransport::with_capacity(2, c);
+
+        t.chan.set_readable_bytes(&[
+            0x00, 0x00, 0x00, 0x04, /* message size */
+            0x00, 0x01, 0x02, 0x03, /* message body */
+        ]);
+
+        let mut buf = vec![0; 8];
+
+        // we've read exactly 4 bytes
+        assert_eq!(t.read(&mut buf).unwrap(), 4);
+        assert_eq!(&buf[..4], &[0x00, 0x01, 0x02, 0x03]);
+    }
+
+    #[test]
+    fn must_read_multiple_messages_in_sequence_correctly() {
+        let c = TBufferChannel::with_capacity(10, 10);
+        let mut t = TFramedReadTransport::with_capacity(2, c);
+
+        //
+        // 1st message
+        //
+
+        t.chan.set_readable_bytes(&[
+            0x00, 0x00, 0x00, 0x04, /* message size */
+            0x00, 0x01, 0x02, 0x03, /* message body */
+        ]);
+
+        let mut buf = vec![0; 8];
+
+        // we've read exactly 4 bytes
+        assert_eq!(t.read(&mut buf).unwrap(), 4);
+        assert_eq!(&buf, &[0x00, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00]);
+
+        //
+        // 2nd message
+        //
+
+        t.chan.set_readable_bytes(&[
+            0x00, 0x00, 0x00, 0x01, /* message size */
+            0x04, /* message body */
+        ]);
+
+        let mut buf = vec![0; 8];
+
+        // we've read exactly 1 byte
+        assert_eq!(t.read(&mut buf).unwrap(), 1);
+        assert_eq!(&buf, &[0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
+    }
+
+    #[test]
+    fn must_write_message_smaller_than_buffer_size() {
+        let mem = TBufferChannel::with_capacity(0, 0);
+        let mut t = TFramedWriteTransport::with_capacity(20, mem);
+
+        let b = vec![0; 10];
+
+        // should have written 10 bytes
+        assert_eq!(t.write(&b).unwrap(), 10);
+    }
+
+    #[test]
+    fn must_return_zero_if_caller_calls_write_with_empty_buffer() {
+        let mem = TBufferChannel::with_capacity(0, 10);
+        let mut t = TFramedWriteTransport::with_capacity(10, mem);
+
+        let expected: [u8; 0] = [];
+
+        assert_eq!(t.write(&[]).unwrap(), 0);
+        assert_eq_transport_written_bytes!(t, expected);
+    }
+
+    #[test]
+    fn must_write_to_inner_transport_on_flush() {
+        let mem = TBufferChannel::with_capacity(10, 10);
+        let mut t = TFramedWriteTransport::new(mem);
+
+        let b: [u8; 5] = [0x00, 0x01, 0x02, 0x03, 0x04];
+        assert_eq!(t.write(&b).unwrap(), 5);
+        assert_eq_transport_num_written_bytes!(t, 0);
+
+        assert!(t.flush().is_ok());
+
+        let expected_bytes = [
+            0x00, 0x00, 0x00, 0x05, /* message size */
+            0x00, 0x01, 0x02, 0x03, 0x04, /* message body */
+        ];
+
+        assert_eq_transport_written_bytes!(t, expected_bytes);
+    }
+
+    #[test]
+    fn must_write_message_greater_than_buffer_size_00() {
+        let mem = TBufferChannel::with_capacity(0, 10);
+
+        // IMPORTANT: DO **NOT** CHANGE THE WRITE_CAPACITY OR THE NUMBER OF BYTES TO BE WRITTEN!
+        // these lengths were chosen to be just long enough
+        // that doubling the capacity is a **worse** choice than
+        // simply resizing the buffer to b.len()
+
+        let mut t = TFramedWriteTransport::with_capacity(1, mem);
+        let b = [0x00, 0x01, 0x02];
+
+        // should have written 3 bytes
+        assert_eq!(t.write(&b).unwrap(), 3);
+        assert_eq_transport_num_written_bytes!(t, 0);
+
+        assert!(t.flush().is_ok());
+
+        let expected_bytes = [
+            0x00, 0x00, 0x00, 0x03, /* message size */
+            0x00, 0x01, 0x02, /* message body */
+        ];
+
+        assert_eq_transport_written_bytes!(t, expected_bytes);
+    }
+
+    #[test]
+    fn must_write_message_greater_than_buffer_size_01() {
+        let mem = TBufferChannel::with_capacity(0, 10);
+
+        // IMPORTANT: DO **NOT** CHANGE THE WRITE_CAPACITY OR THE NUMBER OF BYTES TO BE WRITTEN!
+        // these lengths were chosen to be just long enough
+        // that doubling the capacity is a **better** choice than
+        // simply resizing the buffer to b.len()
+
+        let mut t = TFramedWriteTransport::with_capacity(2, mem);
+        let b = [0x00, 0x01, 0x02];
+
+        // should have written 3 bytes
+        assert_eq!(t.write(&b).unwrap(), 3);
+        assert_eq_transport_num_written_bytes!(t, 0);
+
+        assert!(t.flush().is_ok());
+
+        let expected_bytes = [
+            0x00, 0x00, 0x00, 0x03, /* message size */
+            0x00, 0x01, 0x02, /* message body */
+        ];
+
+        assert_eq_transport_written_bytes!(t, expected_bytes);
+    }
+
+    #[test]
+    fn must_return_error_if_nothing_can_be_written_to_inner_transport_on_flush() {
+        let mem = TBufferChannel::with_capacity(0, 0);
+        let mut t = TFramedWriteTransport::with_capacity(1, mem);
+
+        let b = vec![0; 10];
+
+        // should have written 10 bytes
+        assert_eq!(t.write(&b).unwrap(), 10);
+
+        // let's flush
+        let r = t.flush();
+
+        // this time we'll error out because the flush can't write to the underlying channel
+        assert!(r.is_err());
+    }
+
+    #[test]
+    fn must_write_successfully_after_flush() {
+        // IMPORTANT: write capacity *MUST* be greater
+        // than message sizes used in this test + 4-byte frame header
+        let mem = TBufferChannel::with_capacity(0, 10);
+        let mut t = TFramedWriteTransport::with_capacity(5, mem);
+
+        // write and flush
+        let first_message: [u8; 5] = [0x00, 0x01, 0x02, 0x03, 0x04];
+        assert_eq!(t.write(&first_message).unwrap(), 5);
+        assert!(t.flush().is_ok());
+
+        let mut expected = Vec::new();
+        expected.write_all(&[0x00, 0x00, 0x00, 0x05]).unwrap(); // message size
+        expected.extend_from_slice(&first_message);
+
+        // check the flushed bytes
+        assert_eq!(t.channel.write_bytes(), expected);
+
+        // reset our underlying transport
+        t.channel.empty_write_buffer();
+
+        let second_message: [u8; 3] = [0x05, 0x06, 0x07];
+        assert_eq!(t.write(&second_message).unwrap(), 3);
+        assert!(t.flush().is_ok());
+
+        expected.clear();
+        expected.write_all(&[0x00, 0x00, 0x00, 0x03]).unwrap(); // message size
+        expected.extend_from_slice(&second_message);
+
+        // check the flushed bytes
+        assert_eq!(t.channel.write_bytes(), expected);
+    }
+}
diff --git a/lib/rs/src/transport/mem.rs b/lib/rs/src/transport/mem.rs
new file mode 100644
index 0000000..82c4b57
--- /dev/null
+++ b/lib/rs/src/transport/mem.rs
@@ -0,0 +1,385 @@
+// 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.
+
+use std::cmp;
+use std::io;
+use std::sync::{Arc, Mutex};
+
+use super::{ReadHalf, TIoChannel, WriteHalf};
+
+/// In-memory read and write channel with fixed-size read and write buffers.
+///
+/// On a `write` bytes are written to the internal write buffer. Writes are no
+/// longer accepted once this buffer is full. Callers must `empty_write_buffer()`
+/// before subsequent writes are accepted.
+///
+/// You can set readable bytes in the internal read buffer by filling it with
+/// `set_readable_bytes(...)`. Callers can then read until the buffer is
+/// depleted. No further reads are accepted until the internal read buffer is
+/// replenished again.
+#[derive(Debug)]
+pub struct TBufferChannel {
+    read: Arc<Mutex<ReadData>>,
+    write: Arc<Mutex<WriteData>>,
+}
+
+#[derive(Debug)]
+struct ReadData {
+    buf: Box<[u8]>,
+    pos: usize,
+    idx: usize,
+    cap: usize,
+}
+
+#[derive(Debug)]
+struct WriteData {
+    buf: Box<[u8]>,
+    pos: usize,
+    cap: usize,
+}
+
+impl TBufferChannel {
+    /// Constructs a new, empty `TBufferChannel` with the given
+    /// read buffer capacity and write buffer capacity.
+    pub fn with_capacity(read_capacity: usize, write_capacity: usize) -> TBufferChannel {
+        TBufferChannel {
+            read: Arc::new(Mutex::new(ReadData {
+                buf: vec![0; read_capacity].into_boxed_slice(),
+                idx: 0,
+                pos: 0,
+                cap: read_capacity,
+            })),
+            write: Arc::new(Mutex::new(WriteData {
+                buf: vec![0; write_capacity].into_boxed_slice(),
+                pos: 0,
+                cap: write_capacity,
+            })),
+        }
+    }
+
+    /// Return a copy of the bytes held by the internal read buffer.
+    /// Returns an empty vector if no readable bytes are present.
+    pub fn read_bytes(&self) -> Vec<u8> {
+        let rdata = self.read.as_ref().lock().unwrap();
+        let mut buf = vec![0u8; rdata.idx];
+        buf.copy_from_slice(&rdata.buf[..rdata.idx]);
+        buf
+    }
+
+    // FIXME: do I really need this API call?
+    // FIXME: should this simply reset to the last set of readable bytes?
+    /// Reset the number of readable bytes to zero.
+    ///
+    /// Subsequent calls to `read` will return nothing.
+    pub fn empty_read_buffer(&mut self) {
+        let mut rdata = self.read.as_ref().lock().unwrap();
+        rdata.pos = 0;
+        rdata.idx = 0;
+    }
+
+    /// Copy bytes from the source buffer `buf` into the internal read buffer,
+    /// overwriting any existing bytes. Returns the number of bytes copied,
+    /// which is `min(buf.len(), internal_read_buf.len())`.
+    pub fn set_readable_bytes(&mut self, buf: &[u8]) -> usize {
+        self.empty_read_buffer();
+        let mut rdata = self.read.as_ref().lock().unwrap();
+        let max_bytes = cmp::min(rdata.cap, buf.len());
+        rdata.buf[..max_bytes].clone_from_slice(&buf[..max_bytes]);
+        rdata.idx = max_bytes;
+        max_bytes
+    }
+
+    /// Return a copy of the bytes held by the internal write buffer.
+    /// Returns an empty vector if no bytes were written.
+    pub fn write_bytes(&self) -> Vec<u8> {
+        let wdata = self.write.as_ref().lock().unwrap();
+        let mut buf = vec![0u8; wdata.pos];
+        buf.copy_from_slice(&wdata.buf[..wdata.pos]);
+        buf
+    }
+
+    /// Resets the internal write buffer, making it seem like no bytes were
+    /// written. Calling `write_buffer` after this returns an empty vector.
+    pub fn empty_write_buffer(&mut self) {
+        let mut wdata = self.write.as_ref().lock().unwrap();
+        wdata.pos = 0;
+    }
+
+    /// Overwrites the contents of the read buffer with the contents of the
+    /// write buffer. The write buffer is emptied after this operation.
+    pub fn copy_write_buffer_to_read_buffer(&mut self) {
+        // FIXME: redo this entire method
+        let buf = {
+            let wdata = self.write.as_ref().lock().unwrap();
+            let b = &wdata.buf[..wdata.pos];
+            let mut b_ret = vec![0; b.len()];
+            b_ret.copy_from_slice(b);
+            b_ret
+        };
+
+        let bytes_copied = self.set_readable_bytes(&buf);
+        assert_eq!(bytes_copied, buf.len());
+
+        self.empty_write_buffer();
+    }
+}
+
+impl TIoChannel for TBufferChannel {
+    fn split(self) -> ::Result<(ReadHalf<Self>, WriteHalf<Self>)>
+    where
+        Self: Sized,
+    {
+        Ok((
+            ReadHalf {
+                handle: TBufferChannel {
+                    read: self.read.clone(),
+                    write: self.write.clone(),
+                },
+            },
+            WriteHalf {
+                handle: TBufferChannel {
+                    read: self.read.clone(),
+                    write: self.write.clone(),
+                },
+            },
+        ))
+    }
+}
+
+impl io::Read for TBufferChannel {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut rdata = self.read.as_ref().lock().unwrap();
+        let nread = cmp::min(buf.len(), rdata.idx - rdata.pos);
+        buf[..nread].clone_from_slice(&rdata.buf[rdata.pos..rdata.pos + nread]);
+        rdata.pos += nread;
+        Ok(nread)
+    }
+}
+
+impl io::Write for TBufferChannel {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let mut wdata = self.write.as_ref().lock().unwrap();
+        let nwrite = cmp::min(buf.len(), wdata.cap - wdata.pos);
+        let (start, end) = (wdata.pos, wdata.pos + nwrite);
+        wdata.buf[start..end].clone_from_slice(&buf[..nwrite]);
+        wdata.pos += nwrite;
+        Ok(nwrite)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(()) // nothing to do on flush
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::io::{Read, Write};
+
+    use super::TBufferChannel;
+
+    #[test]
+    fn must_empty_write_buffer() {
+        let mut t = TBufferChannel::with_capacity(0, 1);
+
+        let bytes_to_write: [u8; 1] = [0x01];
+        let result = t.write(&bytes_to_write);
+        assert_eq!(result.unwrap(), 1);
+        assert_eq!(&t.write_bytes(), &bytes_to_write);
+
+        t.empty_write_buffer();
+        assert_eq!(t.write_bytes().len(), 0);
+    }
+
+    #[test]
+    fn must_accept_writes_after_buffer_emptied() {
+        let mut t = TBufferChannel::with_capacity(0, 2);
+
+        let bytes_to_write: [u8; 2] = [0x01, 0x02];
+
+        // first write (all bytes written)
+        let result = t.write(&bytes_to_write);
+        assert_eq!(result.unwrap(), 2);
+        assert_eq!(&t.write_bytes(), &bytes_to_write);
+
+        // try write again (nothing should be written)
+        let result = t.write(&bytes_to_write);
+        assert_eq!(result.unwrap(), 0);
+        assert_eq!(&t.write_bytes(), &bytes_to_write); // still the same as before
+
+        // now reset the buffer
+        t.empty_write_buffer();
+        assert_eq!(t.write_bytes().len(), 0);
+
+        // now try write again - the write should succeed
+        let result = t.write(&bytes_to_write);
+        assert_eq!(result.unwrap(), 2);
+        assert_eq!(&t.write_bytes(), &bytes_to_write);
+    }
+
+    #[test]
+    fn must_accept_multiple_writes_until_buffer_is_full() {
+        let mut t = TBufferChannel::with_capacity(0, 10);
+
+        // first write (all bytes written)
+        let bytes_to_write_0: [u8; 2] = [0x01, 0x41];
+        let write_0_result = t.write(&bytes_to_write_0);
+        assert_eq!(write_0_result.unwrap(), 2);
+        assert_eq!(t.write_bytes(), &bytes_to_write_0);
+
+        // second write (all bytes written, starting at index 2)
+        let bytes_to_write_1: [u8; 7] = [0x24, 0x41, 0x32, 0x33, 0x11, 0x98, 0xAF];
+        let write_1_result = t.write(&bytes_to_write_1);
+        assert_eq!(write_1_result.unwrap(), 7);
+        assert_eq!(&t.write_bytes()[2..], &bytes_to_write_1);
+
+        // third write (only 1 byte written - that's all we have space for)
+        let bytes_to_write_2: [u8; 3] = [0xBF, 0xDA, 0x98];
+        let write_2_result = t.write(&bytes_to_write_2);
+        assert_eq!(write_2_result.unwrap(), 1);
+        assert_eq!(&t.write_bytes()[9..], &bytes_to_write_2[0..1]); // how does this syntax work?!
+
+        // fourth write (no writes are accepted)
+        let bytes_to_write_3: [u8; 3] = [0xBF, 0xAA, 0xFD];
+        let write_3_result = t.write(&bytes_to_write_3);
+        assert_eq!(write_3_result.unwrap(), 0);
+
+        // check the full write buffer
+        let mut expected: Vec<u8> = Vec::with_capacity(10);
+        expected.extend_from_slice(&bytes_to_write_0);
+        expected.extend_from_slice(&bytes_to_write_1);
+        expected.extend_from_slice(&bytes_to_write_2[0..1]);
+        assert_eq!(t.write_bytes(), &expected[..]);
+    }
+
+    #[test]
+    fn must_empty_read_buffer() {
+        let mut t = TBufferChannel::with_capacity(1, 0);
+
+        let bytes_to_read: [u8; 1] = [0x01];
+        let result = t.set_readable_bytes(&bytes_to_read);
+        assert_eq!(result, 1);
+        assert_eq!(t.read_bytes(), &bytes_to_read);
+
+        t.empty_read_buffer();
+        assert_eq!(t.read_bytes().len(), 0);
+    }
+
+    #[test]
+    fn must_allow_readable_bytes_to_be_set_after_read_buffer_emptied() {
+        let mut t = TBufferChannel::with_capacity(1, 0);
+
+        let bytes_to_read_0: [u8; 1] = [0x01];
+        let result = t.set_readable_bytes(&bytes_to_read_0);
+        assert_eq!(result, 1);
+        assert_eq!(t.read_bytes(), &bytes_to_read_0);
+
+        t.empty_read_buffer();
+        assert_eq!(t.read_bytes().len(), 0);
+
+        let bytes_to_read_1: [u8; 1] = [0x02];
+        let result = t.set_readable_bytes(&bytes_to_read_1);
+        assert_eq!(result, 1);
+        assert_eq!(t.read_bytes(), &bytes_to_read_1);
+    }
+
+    #[test]
+    fn must_accept_multiple_reads_until_all_bytes_read() {
+        let mut t = TBufferChannel::with_capacity(10, 0);
+
+        let readable_bytes: [u8; 10] = [0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0x00, 0x1A, 0x2B, 0x3C, 0x4D];
+
+        // check that we're able to set the bytes to be read
+        let result = t.set_readable_bytes(&readable_bytes);
+        assert_eq!(result, 10);
+        assert_eq!(t.read_bytes(), &readable_bytes);
+
+        // first read
+        let mut read_buf_0 = vec![0; 5];
+        let read_result = t.read(&mut read_buf_0);
+        assert_eq!(read_result.unwrap(), 5);
+        assert_eq!(read_buf_0.as_slice(), &(readable_bytes[0..5]));
+
+        // second read
+        let mut read_buf_1 = vec![0; 4];
+        let read_result = t.read(&mut read_buf_1);
+        assert_eq!(read_result.unwrap(), 4);
+        assert_eq!(read_buf_1.as_slice(), &(readable_bytes[5..9]));
+
+        // third read (only 1 byte remains to be read)
+        let mut read_buf_2 = vec![0; 3];
+        let read_result = t.read(&mut read_buf_2);
+        assert_eq!(read_result.unwrap(), 1);
+        read_buf_2.truncate(1); // FIXME: does the caller have to do this?
+        assert_eq!(read_buf_2.as_slice(), &(readable_bytes[9..]));
+
+        // fourth read (nothing should be readable)
+        let mut read_buf_3 = vec![0; 10];
+        let read_result = t.read(&mut read_buf_3);
+        assert_eq!(read_result.unwrap(), 0);
+        read_buf_3.truncate(0);
+
+        // check that all the bytes we received match the original (again!)
+        let mut bytes_read = Vec::with_capacity(10);
+        bytes_read.extend_from_slice(&read_buf_0);
+        bytes_read.extend_from_slice(&read_buf_1);
+        bytes_read.extend_from_slice(&read_buf_2);
+        bytes_read.extend_from_slice(&read_buf_3);
+        assert_eq!(&bytes_read, &readable_bytes);
+    }
+
+    #[test]
+    fn must_allow_reads_to_succeed_after_read_buffer_replenished() {
+        let mut t = TBufferChannel::with_capacity(3, 0);
+
+        let readable_bytes_0: [u8; 3] = [0x02, 0xAB, 0x33];
+
+        // check that we're able to set the bytes to be read
+        let result = t.set_readable_bytes(&readable_bytes_0);
+        assert_eq!(result, 3);
+        assert_eq!(t.read_bytes(), &readable_bytes_0);
+
+        let mut read_buf = vec![0; 4];
+
+        // drain the read buffer
+        let read_result = t.read(&mut read_buf);
+        assert_eq!(read_result.unwrap(), 3);
+        assert_eq!(t.read_bytes(), &read_buf[0..3]);
+
+        // check that a subsequent read fails
+        let read_result = t.read(&mut read_buf);
+        assert_eq!(read_result.unwrap(), 0);
+
+        // we don't modify the read buffer on failure
+        let mut expected_bytes = Vec::with_capacity(4);
+        expected_bytes.extend_from_slice(&readable_bytes_0);
+        expected_bytes.push(0x00);
+        assert_eq!(&read_buf, &expected_bytes);
+
+        // replenish the read buffer again
+        let readable_bytes_1: [u8; 2] = [0x91, 0xAA];
+
+        // check that we're able to set the bytes to be read
+        let result = t.set_readable_bytes(&readable_bytes_1);
+        assert_eq!(result, 2);
+        assert_eq!(t.read_bytes(), &readable_bytes_1);
+
+        // read again
+        let read_result = t.read(&mut read_buf);
+        assert_eq!(read_result.unwrap(), 2);
+        assert_eq!(t.read_bytes(), &read_buf[0..2]);
+    }
+}
diff --git a/lib/rs/src/transport/mod.rs b/lib/rs/src/transport/mod.rs
new file mode 100644
index 0000000..a623350
--- /dev/null
+++ b/lib/rs/src/transport/mod.rs
@@ -0,0 +1,291 @@
+// 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.
+
+//! Types used to send and receive bytes over an I/O channel.
+//!
+//! The core types are the `TReadTransport`, `TWriteTransport` and the
+//! `TIoChannel` traits, through which `TInputProtocol` or
+//! `TOutputProtocol` can receive and send primitives over the wire. While
+//! `TInputProtocol` and `TOutputProtocol` instances deal with language primitives
+//! the types in this module understand only bytes.
+
+use std::io;
+use std::io::{Read, Write};
+use std::ops::{Deref, DerefMut};
+
+#[cfg(test)]
+macro_rules! assert_eq_transport_num_written_bytes {
+    ($transport:ident, $num_written_bytes:expr) => {{
+        assert_eq!($transport.channel.write_bytes().len(), $num_written_bytes);
+    }};
+}
+
+#[cfg(test)]
+macro_rules! assert_eq_transport_written_bytes {
+    ($transport:ident, $expected_bytes:ident) => {{
+        assert_eq!($transport.channel.write_bytes(), &$expected_bytes);
+    }};
+}
+
+mod buffered;
+mod framed;
+mod mem;
+mod socket;
+
+pub use self::buffered::{
+    TBufferedReadTransport, TBufferedReadTransportFactory, TBufferedWriteTransport,
+    TBufferedWriteTransportFactory,
+};
+pub use self::framed::{
+    TFramedReadTransport, TFramedReadTransportFactory, TFramedWriteTransport,
+    TFramedWriteTransportFactory,
+};
+pub use self::mem::TBufferChannel;
+pub use self::socket::TTcpChannel;
+
+/// Identifies a transport used by a `TInputProtocol` to receive bytes.
+pub trait TReadTransport: Read {}
+
+/// Helper type used by a server to create `TReadTransport` instances for
+/// accepted client connections.
+pub trait TReadTransportFactory {
+    /// Create a `TTransport` that wraps a channel over which bytes are to be read.
+    fn create(&self, channel: Box<Read + Send>) -> Box<TReadTransport + Send>;
+}
+
+/// Identifies a transport used by `TOutputProtocol` to send bytes.
+pub trait TWriteTransport: Write {}
+
+/// Helper type used by a server to create `TWriteTransport` instances for
+/// accepted client connections.
+pub trait TWriteTransportFactory {
+    /// Create a `TTransport` that wraps a channel over which bytes are to be sent.
+    fn create(&self, channel: Box<Write + Send>) -> Box<TWriteTransport + Send>;
+}
+
+impl<T> TReadTransport for T where T: Read {}
+
+impl<T> TWriteTransport for T where T: Write {}
+
+// FIXME: implement the Debug trait for boxed transports
+
+impl<T> TReadTransportFactory for Box<T>
+where
+    T: TReadTransportFactory + ?Sized,
+{
+    fn create(&self, channel: Box<Read + Send>) -> Box<TReadTransport + Send> {
+        (**self).create(channel)
+    }
+}
+
+impl<T> TWriteTransportFactory for Box<T>
+where
+    T: TWriteTransportFactory + ?Sized,
+{
+    fn create(&self, channel: Box<Write + Send>) -> Box<TWriteTransport + Send> {
+        (**self).create(channel)
+    }
+}
+
+/// Identifies a splittable bidirectional I/O channel used to send and receive bytes.
+pub trait TIoChannel: Read + Write {
+    /// Split the channel into a readable half and a writable half, where the
+    /// readable half implements `io::Read` and the writable half implements
+    /// `io::Write`. Returns `None` if the channel was not initialized, or if it
+    /// cannot be split safely.
+    ///
+    /// Returned halves may share the underlying OS channel or buffer resources.
+    /// Implementations **should ensure** that these two halves can be safely
+    /// used independently by concurrent threads.
+    fn split(self) -> ::Result<(::transport::ReadHalf<Self>, ::transport::WriteHalf<Self>)>
+    where
+        Self: Sized;
+}
+
+/// The readable half of an object returned from `TIoChannel::split`.
+#[derive(Debug)]
+pub struct ReadHalf<C>
+where
+    C: Read,
+{
+    handle: C,
+}
+
+/// The writable half of an object returned from `TIoChannel::split`.
+#[derive(Debug)]
+pub struct WriteHalf<C>
+where
+    C: Write,
+{
+    handle: C,
+}
+
+impl<C> ReadHalf<C>
+where
+    C: Read,
+{
+    /// Create a `ReadHalf` associated with readable `handle`
+    pub fn new(handle: C) -> ReadHalf<C> {
+        ReadHalf { handle }
+    }
+}
+
+impl<C> WriteHalf<C>
+where
+    C: Write,
+{
+    /// Create a `WriteHalf` associated with writable `handle`
+    pub fn new(handle: C) -> WriteHalf<C> {
+        WriteHalf { handle }
+    }
+}
+
+impl<C> Read for ReadHalf<C>
+where
+    C: Read,
+{
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.handle.read(buf)
+    }
+}
+
+impl<C> Write for WriteHalf<C>
+where
+    C: Write,
+{
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.handle.write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.handle.flush()
+    }
+}
+
+impl<C> Deref for ReadHalf<C>
+where
+    C: Read,
+{
+    type Target = C;
+
+    fn deref(&self) -> &Self::Target {
+        &self.handle
+    }
+}
+
+impl<C> DerefMut for ReadHalf<C>
+where
+    C: Read,
+{
+    fn deref_mut(&mut self) -> &mut C {
+        &mut self.handle
+    }
+}
+
+impl<C> Deref for WriteHalf<C>
+where
+    C: Write,
+{
+    type Target = C;
+
+    fn deref(&self) -> &Self::Target {
+        &self.handle
+    }
+}
+
+impl<C> DerefMut for WriteHalf<C>
+where
+    C: Write,
+{
+    fn deref_mut(&mut self) -> &mut C {
+        &mut self.handle
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use std::io::Cursor;
+
+    use super::*;
+
+    #[test]
+    fn must_create_usable_read_channel_from_concrete_read_type() {
+        let r = Cursor::new([0, 1, 2]);
+        let _ = TBufferedReadTransport::new(r);
+    }
+
+    #[test]
+    fn must_create_usable_read_channel_from_boxed_read() {
+        let r: Box<Read> = Box::new(Cursor::new([0, 1, 2]));
+        let _ = TBufferedReadTransport::new(r);
+    }
+
+    #[test]
+    fn must_create_usable_write_channel_from_concrete_write_type() {
+        let w = vec![0u8; 10];
+        let _ = TBufferedWriteTransport::new(w);
+    }
+
+    #[test]
+    fn must_create_usable_write_channel_from_boxed_write() {
+        let w: Box<Write> = Box::new(vec![0u8; 10]);
+        let _ = TBufferedWriteTransport::new(w);
+    }
+
+    #[test]
+    fn must_create_usable_read_transport_from_concrete_read_transport() {
+        let r = Cursor::new([0, 1, 2]);
+        let mut t = TBufferedReadTransport::new(r);
+        takes_read_transport(&mut t)
+    }
+
+    #[test]
+    fn must_create_usable_read_transport_from_boxed_read() {
+        let r = Cursor::new([0, 1, 2]);
+        let mut t: Box<TReadTransport> = Box::new(TBufferedReadTransport::new(r));
+        takes_read_transport(&mut t)
+    }
+
+    #[test]
+    fn must_create_usable_write_transport_from_concrete_write_transport() {
+        let w = vec![0u8; 10];
+        let mut t = TBufferedWriteTransport::new(w);
+        takes_write_transport(&mut t)
+    }
+
+    #[test]
+    fn must_create_usable_write_transport_from_boxed_write() {
+        let w = vec![0u8; 10];
+        let mut t: Box<TWriteTransport> = Box::new(TBufferedWriteTransport::new(w));
+        takes_write_transport(&mut t)
+    }
+
+    fn takes_read_transport<R>(t: &mut R)
+    where
+        R: TReadTransport,
+    {
+        t.bytes();
+    }
+
+    fn takes_write_transport<W>(t: &mut W)
+    where
+        W: TWriteTransport,
+    {
+        t.flush().unwrap();
+    }
+}
diff --git a/lib/rs/src/transport/socket.rs b/lib/rs/src/transport/socket.rs
new file mode 100644
index 0000000..0bef67b
--- /dev/null
+++ b/lib/rs/src/transport/socket.rs
@@ -0,0 +1,168 @@
+// 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.
+
+use std::convert::From;
+use std::io;
+use std::io::{ErrorKind, Read, Write};
+use std::net::{Shutdown, TcpStream};
+
+use super::{ReadHalf, TIoChannel, WriteHalf};
+use {new_transport_error, TransportErrorKind};
+
+/// Bidirectional TCP/IP channel.
+///
+/// # Examples
+///
+/// Create a `TTcpChannel`.
+///
+/// ```no_run
+/// use std::io::{Read, Write};
+/// use thrift::transport::TTcpChannel;
+///
+/// let mut c = TTcpChannel::new();
+/// c.open("localhost:9090").unwrap();
+///
+/// let mut buf = vec![0u8; 4];
+/// c.read(&mut buf).unwrap();
+/// c.write(&vec![0, 1, 2]).unwrap();
+/// ```
+///
+/// Create a `TTcpChannel` by wrapping an existing `TcpStream`.
+///
+/// ```no_run
+/// use std::io::{Read, Write};
+/// use std::net::TcpStream;
+/// use thrift::transport::TTcpChannel;
+///
+/// let stream = TcpStream::connect("127.0.0.1:9189").unwrap();
+///
+/// // no need to call c.open() since we've already connected above
+/// let mut c = TTcpChannel::with_stream(stream);
+///
+/// let mut buf = vec![0u8; 4];
+/// c.read(&mut buf).unwrap();
+/// c.write(&vec![0, 1, 2]).unwrap();
+/// ```
+#[derive(Debug, Default)]
+pub struct TTcpChannel {
+    stream: Option<TcpStream>,
+}
+
+impl TTcpChannel {
+    /// Create an uninitialized `TTcpChannel`.
+    ///
+    /// The returned instance must be opened using `TTcpChannel::open(...)`
+    /// before it can be used.
+    pub fn new() -> TTcpChannel {
+        TTcpChannel { stream: None }
+    }
+
+    /// Create a `TTcpChannel` that wraps an existing `TcpStream`.
+    ///
+    /// The passed-in stream is assumed to have been opened before being wrapped
+    /// by the created `TTcpChannel` instance.
+    pub fn with_stream(stream: TcpStream) -> TTcpChannel {
+        TTcpChannel {
+            stream: Some(stream),
+        }
+    }
+
+    /// Connect to `remote_address`, which should have the form `host:port`.
+    pub fn open(&mut self, remote_address: &str) -> ::Result<()> {
+        if self.stream.is_some() {
+            Err(new_transport_error(
+                TransportErrorKind::AlreadyOpen,
+                "tcp connection previously opened",
+            ))
+        } else {
+            match TcpStream::connect(&remote_address) {
+                Ok(s) => {
+                    self.stream = Some(s);
+                    Ok(())
+                }
+                Err(e) => Err(From::from(e)),
+            }
+        }
+    }
+
+    /// Shut down this channel.
+    ///
+    /// Both send and receive halves are closed, and this instance can no
+    /// longer be used to communicate with another endpoint.
+    pub fn close(&mut self) -> ::Result<()> {
+        self.if_set(|s| s.shutdown(Shutdown::Both))
+            .map_err(From::from)
+    }
+
+    fn if_set<F, T>(&mut self, mut stream_operation: F) -> io::Result<T>
+    where
+        F: FnMut(&mut TcpStream) -> io::Result<T>,
+    {
+        if let Some(ref mut s) = self.stream {
+            stream_operation(s)
+        } else {
+            Err(io::Error::new(
+                ErrorKind::NotConnected,
+                "tcp endpoint not connected",
+            ))
+        }
+    }
+}
+
+impl TIoChannel for TTcpChannel {
+    fn split(self) -> ::Result<(ReadHalf<Self>, WriteHalf<Self>)>
+    where
+        Self: Sized,
+    {
+        let mut s = self;
+
+        s.stream
+            .as_mut()
+            .and_then(|s| s.try_clone().ok())
+            .map(|cloned| {
+                let read_half = ReadHalf::new(TTcpChannel {
+                    stream: s.stream.take(),
+                });
+                let write_half = WriteHalf::new(TTcpChannel {
+                    stream: Some(cloned),
+                });
+                (read_half, write_half)
+            })
+            .ok_or_else(|| {
+                new_transport_error(
+                    TransportErrorKind::Unknown,
+                    "cannot clone underlying tcp stream",
+                )
+            })
+    }
+}
+
+impl Read for TTcpChannel {
+    fn read(&mut self, b: &mut [u8]) -> io::Result<usize> {
+        self.if_set(|s| s.read(b))
+    }
+}
+
+impl Write for TTcpChannel {
+    fn write(&mut self, b: &[u8]) -> io::Result<usize> {
+        self.if_set(|s| s.write(b))
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.if_set(|s| s.flush())
+    }
+}
diff --git a/lib/rs/test/Cargo.toml b/lib/rs/test/Cargo.toml
new file mode 100644
index 0000000..50dec19
--- /dev/null
+++ b/lib/rs/test/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "kitchen-sink"
+version = "0.1.0"
+license = "Apache-2.0"
+authors = ["Apache Thrift Developers <dev@thrift.apache.org>"]
+publish = false
+
+[dependencies]
+clap = "<2.28.0"
+ordered-float = "0.3.0"
+try_from = "0.2.0"
+
+[dependencies.thrift]
+path = "../"
+
diff --git a/lib/rs/test/Makefile.am b/lib/rs/test/Makefile.am
new file mode 100644
index 0000000..8edd756
--- /dev/null
+++ b/lib/rs/test/Makefile.am
@@ -0,0 +1,54 @@
+#
+# 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.
+#
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+stubs: thrifts/Base_One.thrift thrifts/Base_Two.thrift thrifts/Midlayer.thrift thrifts/Ultimate.thrift $(top_builddir)/test/Recursive.thrift $(THRIFT)
+	$(THRIFT) -I ./thrifts -out src --gen rs thrifts/Base_One.thrift
+	$(THRIFT) -I ./thrifts -out src --gen rs thrifts/Base_Two.thrift
+	$(THRIFT) -I ./thrifts -out src --gen rs thrifts/Midlayer.thrift
+	$(THRIFT) -I ./thrifts -out src --gen rs thrifts/Ultimate.thrift
+	$(THRIFT) -out src --gen rs $(top_builddir)/test/Recursive.thrift
+
+check: stubs
+	$(CARGO) build
+	$(CARGO) test
+	[ -d bin ] || mkdir bin
+	cp target/debug/kitchen_sink_server bin/kitchen_sink_server
+	cp target/debug/kitchen_sink_client bin/kitchen_sink_client
+
+clean-local:
+	$(CARGO) clean
+	-$(RM) Cargo.lock
+	-$(RM) src/base_one.rs
+	-$(RM) src/base_two.rs
+	-$(RM) src/midlayer.rs
+	-$(RM) src/ultimate.rs
+	-$(RM) -r bin
+
+EXTRA_DIST = \
+	Cargo.toml \
+	thrifts/Base_One.thrift \
+	thrifts/Base_Two.thrift \
+	thrifts/Midlayer.thrift \
+	thrifts/Ultimate.thrift \
+	src/lib.rs \
+	src/bin/kitchen_sink_server.rs \
+	src/bin/kitchen_sink_client.rs
+
diff --git a/lib/rs/test/src/bin/kitchen_sink_client.rs b/lib/rs/test/src/bin/kitchen_sink_client.rs
new file mode 100644
index 0000000..d295c88
--- /dev/null
+++ b/lib/rs/test/src/bin/kitchen_sink_client.rs
@@ -0,0 +1,239 @@
+// 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.
+
+#[macro_use]
+extern crate clap;
+
+extern crate kitchen_sink;
+extern crate thrift;
+
+use std::convert::Into;
+
+use kitchen_sink::base_two::{TNapkinServiceSyncClient, TRamenServiceSyncClient};
+use kitchen_sink::midlayer::{MealServiceSyncClient, TMealServiceSyncClient};
+use kitchen_sink::recursive;
+use kitchen_sink::recursive::{CoRec, CoRec2, RecList, RecTree, TTestServiceSyncClient};
+use kitchen_sink::ultimate::{FullMealServiceSyncClient, TFullMealServiceSyncClient};
+use thrift::protocol::{
+    TBinaryInputProtocol, TBinaryOutputProtocol, TCompactInputProtocol, TCompactOutputProtocol,
+    TInputProtocol, TOutputProtocol,
+};
+use thrift::transport::{
+    ReadHalf, TFramedReadTransport, TFramedWriteTransport, TIoChannel, TTcpChannel, WriteHalf,
+};
+
+fn main() {
+    match run() {
+        Ok(()) => println!("kitchen sink client completed successfully"),
+        Err(e) => {
+            println!("kitchen sink client failed with error {:?}", e);
+            std::process::exit(1);
+        }
+    }
+}
+
+fn run() -> thrift::Result<()> {
+    let matches = clap_app!(rust_kitchen_sink_client =>
+        (version: "0.1.0")
+        (author: "Apache Thrift Developers <dev@thrift.apache.org>")
+        (about: "Thrift Rust kitchen sink client")
+        (@arg host: --host +takes_value "Host on which the Thrift test server is located")
+        (@arg port: --port +takes_value "Port on which the Thrift test server is listening")
+        (@arg protocol: --protocol +takes_value "Thrift protocol implementation to use (\"binary\", \"compact\")")
+        (@arg service: --service +takes_value "Service type to contact (\"part\", \"full\", \"recursive\")")
+    )
+            .get_matches();
+
+    let host = matches.value_of("host").unwrap_or("127.0.0.1");
+    let port = value_t!(matches, "port", u16).unwrap_or(9090);
+    let protocol = matches.value_of("protocol").unwrap_or("compact");
+    let service = matches.value_of("service").unwrap_or("part");
+
+    let (i_chan, o_chan) = tcp_channel(host, port)?;
+    let (i_tran, o_tran) = (
+        TFramedReadTransport::new(i_chan),
+        TFramedWriteTransport::new(o_chan),
+    );
+
+    let (i_prot, o_prot): (Box<TInputProtocol>, Box<TOutputProtocol>) = match protocol {
+        "binary" => (
+            Box::new(TBinaryInputProtocol::new(i_tran, true)),
+            Box::new(TBinaryOutputProtocol::new(o_tran, true)),
+        ),
+        "compact" => (
+            Box::new(TCompactInputProtocol::new(i_tran)),
+            Box::new(TCompactOutputProtocol::new(o_tran)),
+        ),
+        unmatched => return Err(format!("unsupported protocol {}", unmatched).into()),
+    };
+
+    run_client(service, i_prot, o_prot)
+}
+
+fn run_client(
+    service: &str,
+    i_prot: Box<TInputProtocol>,
+    o_prot: Box<TOutputProtocol>,
+) -> thrift::Result<()> {
+    match service {
+        "full" => exec_full_meal_client(i_prot, o_prot),
+        "part" => exec_meal_client(i_prot, o_prot),
+        "recursive" => exec_recursive_client(i_prot, o_prot),
+        _ => Err(thrift::Error::from(format!(
+            "unknown service type {}",
+            service
+        ))),
+    }
+}
+
+fn tcp_channel(
+    host: &str,
+    port: u16,
+) -> thrift::Result<(ReadHalf<TTcpChannel>, WriteHalf<TTcpChannel>)> {
+    let mut c = TTcpChannel::new();
+    c.open(&format!("{}:{}", host, port))?;
+    c.split()
+}
+
+fn exec_meal_client(
+    i_prot: Box<TInputProtocol>,
+    o_prot: Box<TOutputProtocol>,
+) -> thrift::Result<()> {
+    let mut client = MealServiceSyncClient::new(i_prot, o_prot);
+
+    // client.full_meal(); // <-- IMPORTANT: if you uncomment this, compilation *should* fail
+    // this is because the MealService struct does not contain the appropriate service marker
+
+    // only the following three calls work
+    execute_call("part", "ramen", || client.ramen(50)).map(|_| ())?;
+    execute_call("part", "meal", || client.meal()).map(|_| ())?;
+    execute_call("part", "napkin", || client.napkin()).map(|_| ())?;
+
+    Ok(())
+}
+
+fn exec_full_meal_client(
+    i_prot: Box<TInputProtocol>,
+    o_prot: Box<TOutputProtocol>,
+) -> thrift::Result<()> {
+    let mut client = FullMealServiceSyncClient::new(i_prot, o_prot);
+
+    execute_call("full", "ramen", || client.ramen(100)).map(|_| ())?;
+    execute_call("full", "meal", || client.meal()).map(|_| ())?;
+    execute_call("full", "napkin", || client.napkin()).map(|_| ())?;
+    execute_call("full", "full meal", || client.full_meal()).map(|_| ())?;
+
+    Ok(())
+}
+
+fn exec_recursive_client(
+    i_prot: Box<TInputProtocol>,
+    o_prot: Box<TOutputProtocol>,
+) -> thrift::Result<()> {
+    let mut client = recursive::TestServiceSyncClient::new(i_prot, o_prot);
+
+    let tree = RecTree {
+        children: Some(vec![Box::new(RecTree {
+            children: Some(vec![
+                Box::new(RecTree {
+                    children: None,
+                    item: Some(3),
+                }),
+                Box::new(RecTree {
+                    children: None,
+                    item: Some(4),
+                }),
+            ]),
+            item: Some(2),
+        })]),
+        item: Some(1),
+    };
+
+    let expected_tree = RecTree {
+        children: Some(vec![Box::new(RecTree {
+            children: Some(vec![
+                Box::new(RecTree {
+                    children: Some(Vec::new()), // remote returns an empty list
+                    item: Some(3),
+                }),
+                Box::new(RecTree {
+                    children: Some(Vec::new()), // remote returns an empty list
+                    item: Some(4),
+                }),
+            ]),
+            item: Some(2),
+        })]),
+        item: Some(1),
+    };
+
+    let returned_tree = execute_call("recursive", "echo_tree", || client.echo_tree(tree.clone()))?;
+    if returned_tree != expected_tree {
+        return Err(format!(
+            "mismatched recursive tree {:?} {:?}",
+            expected_tree, returned_tree
+        )
+        .into());
+    }
+
+    let list = RecList {
+        nextitem: Some(Box::new(RecList {
+            nextitem: Some(Box::new(RecList {
+                nextitem: None,
+                item: Some(3),
+            })),
+            item: Some(2),
+        })),
+        item: Some(1),
+    };
+    let returned_list = execute_call("recursive", "echo_list", || client.echo_list(list.clone()))?;
+    if returned_list != list {
+        return Err(format!("mismatched recursive list {:?} {:?}", list, returned_list).into());
+    }
+
+    let co_rec = CoRec {
+        other: Some(Box::new(CoRec2 {
+            other: Some(CoRec {
+                other: Some(Box::new(CoRec2 { other: None })),
+            }),
+        })),
+    };
+    let returned_co_rec = execute_call("recursive", "echo_co_rec", || {
+        client.echo_co_rec(co_rec.clone())
+    })?;
+    if returned_co_rec != co_rec {
+        return Err(format!("mismatched co_rec {:?} {:?}", co_rec, returned_co_rec).into());
+    }
+
+    Ok(())
+}
+
+fn execute_call<F, R>(service_type: &str, call_name: &str, mut f: F) -> thrift::Result<R>
+where
+    F: FnMut() -> thrift::Result<R>,
+{
+    let res = f();
+
+    match res {
+        Ok(_) => println!("{}: completed {} call", service_type, call_name),
+        Err(ref e) => println!(
+            "{}: failed {} call with error {:?}",
+            service_type, call_name, e
+        ),
+    }
+
+    res
+}
diff --git a/lib/rs/test/src/bin/kitchen_sink_server.rs b/lib/rs/test/src/bin/kitchen_sink_server.rs
new file mode 100644
index 0000000..73801ea
--- /dev/null
+++ b/lib/rs/test/src/bin/kitchen_sink_server.rs
@@ -0,0 +1,313 @@
+// 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.
+
+#[macro_use]
+extern crate clap;
+extern crate kitchen_sink;
+extern crate thrift;
+
+use thrift::protocol::{
+    TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory, TCompactInputProtocolFactory,
+    TCompactOutputProtocolFactory, TInputProtocolFactory, TOutputProtocolFactory,
+};
+use thrift::server::TServer;
+use thrift::transport::{
+    TFramedReadTransportFactory, TFramedWriteTransportFactory, TReadTransportFactory,
+    TWriteTransportFactory,
+};
+
+use kitchen_sink::base_one::Noodle;
+use kitchen_sink::base_two::{
+    BrothType, Napkin, NapkinServiceSyncHandler, Ramen, RamenServiceSyncHandler,
+};
+use kitchen_sink::midlayer::{
+    Dessert, Meal, MealServiceSyncHandler, MealServiceSyncProcessor, Pie,
+};
+use kitchen_sink::recursive;
+use kitchen_sink::ultimate::FullMealAndDrinksServiceSyncHandler;
+use kitchen_sink::ultimate::{
+    Drink, FullMeal, FullMealAndDrinks, FullMealAndDrinksServiceSyncProcessor,
+    FullMealServiceSyncHandler,
+};
+
+fn main() {
+    match run() {
+        Ok(()) => println!("kitchen sink server completed successfully"),
+        Err(e) => {
+            println!("kitchen sink server failed with error {:?}", e);
+            std::process::exit(1);
+        }
+    }
+}
+
+fn run() -> thrift::Result<()> {
+    let matches = clap_app!(rust_kitchen_sink_server =>
+        (version: "0.1.0")
+        (author: "Apache Thrift Developers <dev@thrift.apache.org>")
+        (about: "Thrift Rust kitchen sink test server")
+        (@arg port: --port +takes_value "port on which the test server listens")
+        (@arg protocol: --protocol +takes_value "Thrift protocol implementation to use (\"binary\", \"compact\")")
+        (@arg service: --service +takes_value "Service type to contact (\"part\", \"full\", \"recursive\")")
+    )
+            .get_matches();
+
+    let port = value_t!(matches, "port", u16).unwrap_or(9090);
+    let protocol = matches.value_of("protocol").unwrap_or("compact");
+    let service = matches.value_of("service").unwrap_or("part");
+    let listen_address = format!("127.0.0.1:{}", port);
+
+    println!("binding to {}", listen_address);
+
+    let r_transport_factory = TFramedReadTransportFactory::new();
+    let w_transport_factory = TFramedWriteTransportFactory::new();
+
+    let (i_protocol_factory, o_protocol_factory): (
+        Box<TInputProtocolFactory>,
+        Box<TOutputProtocolFactory>,
+    ) = match &*protocol {
+        "binary" => (
+            Box::new(TBinaryInputProtocolFactory::new()),
+            Box::new(TBinaryOutputProtocolFactory::new()),
+        ),
+        "compact" => (
+            Box::new(TCompactInputProtocolFactory::new()),
+            Box::new(TCompactOutputProtocolFactory::new()),
+        ),
+        unknown => {
+            return Err(format!("unsupported transport type {}", unknown).into());
+        }
+    };
+
+    // FIXME: should processor be boxed as well?
+    //
+    // [sigh] I hate Rust generics implementation
+    //
+    // I would have preferred to build a server here, return it, and then do
+    // the common listen-and-handle stuff, but since the server doesn't have a
+    // common type (because each match arm instantiates a server with a
+    // different processor) this isn't possible.
+    //
+    // Since what I'm doing is uncommon I'm just going to duplicate the code
+    match &*service {
+        "part" => run_meal_server(
+            &listen_address,
+            r_transport_factory,
+            i_protocol_factory,
+            w_transport_factory,
+            o_protocol_factory,
+        ),
+        "full" => run_full_meal_server(
+            &listen_address,
+            r_transport_factory,
+            i_protocol_factory,
+            w_transport_factory,
+            o_protocol_factory,
+        ),
+        "recursive" => run_recursive_server(
+            &listen_address,
+            r_transport_factory,
+            i_protocol_factory,
+            w_transport_factory,
+            o_protocol_factory,
+        ),
+        unknown => Err(format!("unsupported service type {}", unknown).into()),
+    }
+}
+
+fn run_meal_server<RTF, IPF, WTF, OPF>(
+    listen_address: &str,
+    r_transport_factory: RTF,
+    i_protocol_factory: IPF,
+    w_transport_factory: WTF,
+    o_protocol_factory: OPF,
+) -> thrift::Result<()>
+where
+    RTF: TReadTransportFactory + 'static,
+    IPF: TInputProtocolFactory + 'static,
+    WTF: TWriteTransportFactory + 'static,
+    OPF: TOutputProtocolFactory + 'static,
+{
+    let processor = MealServiceSyncProcessor::new(PartHandler {});
+    let mut server = TServer::new(
+        r_transport_factory,
+        i_protocol_factory,
+        w_transport_factory,
+        o_protocol_factory,
+        processor,
+        1,
+    );
+
+    server.listen(listen_address)
+}
+
+fn run_full_meal_server<RTF, IPF, WTF, OPF>(
+    listen_address: &str,
+    r_transport_factory: RTF,
+    i_protocol_factory: IPF,
+    w_transport_factory: WTF,
+    o_protocol_factory: OPF,
+) -> thrift::Result<()>
+where
+    RTF: TReadTransportFactory + 'static,
+    IPF: TInputProtocolFactory + 'static,
+    WTF: TWriteTransportFactory + 'static,
+    OPF: TOutputProtocolFactory + 'static,
+{
+    let processor = FullMealAndDrinksServiceSyncProcessor::new(FullHandler {});
+    let mut server = TServer::new(
+        r_transport_factory,
+        i_protocol_factory,
+        w_transport_factory,
+        o_protocol_factory,
+        processor,
+        1,
+    );
+
+    server.listen(listen_address)
+}
+
+struct PartHandler;
+
+impl MealServiceSyncHandler for PartHandler {
+    fn handle_meal(&self) -> thrift::Result<Meal> {
+        println!("part: handling meal call");
+        Ok(meal())
+    }
+}
+
+impl RamenServiceSyncHandler for PartHandler {
+    fn handle_ramen(&self, _: i32) -> thrift::Result<Ramen> {
+        println!("part: handling ramen call");
+        Ok(ramen())
+    }
+}
+
+impl NapkinServiceSyncHandler for PartHandler {
+    fn handle_napkin(&self) -> thrift::Result<Napkin> {
+        println!("part: handling napkin call");
+        Ok(napkin())
+    }
+}
+
+// full service
+//
+
+struct FullHandler;
+
+impl FullMealAndDrinksServiceSyncHandler for FullHandler {
+    fn handle_full_meal_and_drinks(&self) -> thrift::Result<FullMealAndDrinks> {
+        println!("full_meal_and_drinks: handling full meal and drinks call");
+        Ok(FullMealAndDrinks::new(full_meal(), Drink::CanadianWhisky))
+    }
+
+    fn handle_best_pie(&self) -> thrift::Result<Pie> {
+        println!("full_meal_and_drinks: handling pie call");
+        Ok(Pie::MississippiMud) // I prefer Pie::Pumpkin, but I have to check that casing works
+    }
+}
+
+impl FullMealServiceSyncHandler for FullHandler {
+    fn handle_full_meal(&self) -> thrift::Result<FullMeal> {
+        println!("full: handling full meal call");
+        Ok(full_meal())
+    }
+}
+
+impl MealServiceSyncHandler for FullHandler {
+    fn handle_meal(&self) -> thrift::Result<Meal> {
+        println!("full: handling meal call");
+        Ok(meal())
+    }
+}
+
+impl RamenServiceSyncHandler for FullHandler {
+    fn handle_ramen(&self, _: i32) -> thrift::Result<Ramen> {
+        println!("full: handling ramen call");
+        Ok(ramen())
+    }
+}
+
+impl NapkinServiceSyncHandler for FullHandler {
+    fn handle_napkin(&self) -> thrift::Result<Napkin> {
+        println!("full: handling napkin call");
+        Ok(napkin())
+    }
+}
+
+fn full_meal() -> FullMeal {
+    FullMeal::new(meal(), Dessert::Port("Graham's Tawny".to_owned()))
+}
+
+fn meal() -> Meal {
+    Meal::new(noodle(), ramen())
+}
+
+fn noodle() -> Noodle {
+    Noodle::new("spelt".to_owned(), 100)
+}
+
+fn ramen() -> Ramen {
+    Ramen::new("Mr Ramen".to_owned(), 72, BrothType::Miso)
+}
+
+fn napkin() -> Napkin {
+    Napkin {}
+}
+
+fn run_recursive_server<RTF, IPF, WTF, OPF>(
+    listen_address: &str,
+    r_transport_factory: RTF,
+    i_protocol_factory: IPF,
+    w_transport_factory: WTF,
+    o_protocol_factory: OPF,
+) -> thrift::Result<()>
+where
+    RTF: TReadTransportFactory + 'static,
+    IPF: TInputProtocolFactory + 'static,
+    WTF: TWriteTransportFactory + 'static,
+    OPF: TOutputProtocolFactory + 'static,
+{
+    let processor = recursive::TestServiceSyncProcessor::new(RecursiveTestServerHandler {});
+    let mut server = TServer::new(
+        r_transport_factory,
+        i_protocol_factory,
+        w_transport_factory,
+        o_protocol_factory,
+        processor,
+        1,
+    );
+
+    server.listen(listen_address)
+}
+
+struct RecursiveTestServerHandler;
+impl recursive::TestServiceSyncHandler for RecursiveTestServerHandler {
+    fn handle_echo_tree(&self, tree: recursive::RecTree) -> thrift::Result<recursive::RecTree> {
+        println!("{:?}", tree);
+        Ok(tree)
+    }
+
+    fn handle_echo_list(&self, lst: recursive::RecList) -> thrift::Result<recursive::RecList> {
+        println!("{:?}", lst);
+        Ok(lst)
+    }
+
+    fn handle_echo_co_rec(&self, item: recursive::CoRec) -> thrift::Result<recursive::CoRec> {
+        println!("{:?}", item);
+        Ok(item)
+    }
+}
diff --git a/lib/rs/test/src/lib.rs b/lib/rs/test/src/lib.rs
new file mode 100644
index 0000000..e5e176e
--- /dev/null
+++ b/lib/rs/test/src/lib.rs
@@ -0,0 +1,57 @@
+// 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.
+
+extern crate ordered_float;
+extern crate thrift;
+extern crate try_from;
+
+pub mod base_one;
+pub mod base_two;
+pub mod midlayer;
+pub mod ultimate;
+pub mod recursive;
+
+#[cfg(test)]
+mod tests {
+
+    use std::default::Default;
+
+    use super::*;
+
+    #[test]
+    fn must_be_able_to_use_constructor() {
+        let _ = midlayer::Meal::new(Some(base_one::Noodle::default()), None);
+    }
+
+    #[test]
+    fn must_be_able_to_use_constructor_with_no_fields() {
+        let _ = midlayer::Meal::new(None, None);
+    }
+
+    #[test]
+    fn must_be_able_to_use_constructor_without_option_wrap() {
+        let _ = midlayer::Meal::new(base_one::Noodle::default(), None);
+    }
+
+    #[test]
+    fn must_be_able_to_use_defaults() {
+        let _ = midlayer::Meal {
+            noodle: Some(base_one::Noodle::default()),
+            ..Default::default()
+        };
+    }
+}
diff --git a/lib/rs/test/thrifts/Base_One.thrift b/lib/rs/test/thrifts/Base_One.thrift
new file mode 100644
index 0000000..c5fa6c2
--- /dev/null
+++ b/lib/rs/test/thrifts/Base_One.thrift
@@ -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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+typedef i64 Temperature
+
+typedef i8 Size
+
+typedef string Location
+
+const i32 BoilingPoint = 100
+
+const list<Temperature> Temperatures = [10, 11, 22, 33]
+
+// IMPORTANT: temps should end with ".0" because this tests
+// that we don't have a problem with const float list generation
+const list<double> CommonTemperatures = [300.0, 450.0]
+
+const double MealsPerDay = 2.5;
+
+const string DefaultRecipeName = "Soup-rise of the Day"
+const binary DefaultRecipeBinary = "Soup-rise of the 01010101"
+
+struct Noodle {
+  1: string flourType
+  2: Temperature cookTemp
+}
+
+struct Spaghetti {
+  1: optional list<Noodle> noodles
+}
+
+const Noodle SpeltNoodle = { "flourType": "spelt", "cookTemp": 110 }
+
+struct MeasuringSpoon {
+  1: Size size
+}
+
+struct MeasuringCup {
+  1: double millis
+}
+
+union MeasuringAids {
+  1: MeasuringSpoon spoon
+  2: MeasuringCup cup
+}
+
+struct CookingTemperatures {
+  1: set<double> commonTemperatures
+  2: list<double> usedTemperatures
+  3: map<double, double> fahrenheitToCentigradeConversions
+}
+
+struct Recipe {
+  1: string recipeName
+  2: string cuisine
+  3: i8 page
+}
+
+union CookingTools {
+  1: set<MeasuringSpoon> measuringSpoons
+  2: map<Size, Location> measuringCups,
+  3: list<Recipe> recipes
+}
+
diff --git a/lib/rs/test/thrifts/Base_Two.thrift b/lib/rs/test/thrifts/Base_Two.thrift
new file mode 100644
index 0000000..caa6acb
--- /dev/null
+++ b/lib/rs/test/thrifts/Base_Two.thrift
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+const i32 WaterWeight = 200
+
+enum brothType {
+  Miso,
+  shouyu,
+}
+
+struct Ramen {
+  1: optional string ramenType
+  2: required i32 noodleCount
+  3: brothType broth
+}
+
+struct Napkin {
+  // empty
+}
+
+service NapkinService {
+  Napkin napkin()
+}
+
+service RamenService extends NapkinService {
+  Ramen ramen(1: i32 requestedNoodleCount)
+}
+
+/* const struct CookedRamen = { "bar": 10 } */
+
diff --git a/lib/rs/test/thrifts/Midlayer.thrift b/lib/rs/test/thrifts/Midlayer.thrift
new file mode 100644
index 0000000..16ff49b
--- /dev/null
+++ b/lib/rs/test/thrifts/Midlayer.thrift
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+include "Base_One.thrift"
+include "Base_Two.thrift"
+
+const i32 WaterBoilingPoint = Base_One.BoilingPoint
+
+const map<string, Base_One.Temperature> TemperatureNames = { "freezing": 0, "boiling": 100 }
+
+const map<set<i32>, map<list<string>, string>> MyConstNestedMap = {
+  [0, 1, 2, 3]: { ["foo"]: "bar" },
+  [20]: { ["nut", "ton"] : "bar" },
+  [30, 40]: { ["bouncy", "tinkly"]: "castle" }
+}
+
+const list<list<i32>> MyConstNestedList = [
+  [0, 1, 2],
+  [3, 4, 5],
+  [6, 7, 8]
+]
+
+const set<set<i32>> MyConstNestedSet = [
+  [0, 1, 2],
+  [3, 4, 5],
+  [6, 7, 8]
+]
+
+enum Pie {
+  PUMPKIN,
+  apple, // intentionally poorly cased
+  STRAWBERRY_RHUBARB,
+  Key_Lime, // intentionally poorly cased
+  coconut_Cream, // intentionally poorly cased
+  mississippi_mud, // intentionally poorly cased
+}
+
+struct Meal {
+  1: Base_One.Noodle noodle
+  2: Base_Two.Ramen ramen
+}
+
+union Dessert  {
+  1: string port
+  2: string iceWine
+}
+
+service MealService extends Base_Two.RamenService {
+  Meal meal()
+}
+
diff --git a/lib/rs/test/thrifts/Ultimate.thrift b/lib/rs/test/thrifts/Ultimate.thrift
new file mode 100644
index 0000000..72fa100
--- /dev/null
+++ b/lib/rs/test/thrifts/Ultimate.thrift
@@ -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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+include "Midlayer.thrift"
+
+enum Drink {
+  WATER,
+  WHISKEY,
+  WINE,
+  scotch, // intentionally poorly cased
+  LATE_HARVEST_WINE,
+  India_Pale_Ale, // intentionally poorly cased
+  apple_cider, // intentially poorly cased
+  belgian_Ale, // intentionally poorly cased
+  Canadian_whisky, // intentionally poorly cased
+}
+
+const map<i8, Midlayer.Pie> RankedPies = {
+  1: Midlayer.Pie.PUMPKIN,
+  2: Midlayer.Pie.STRAWBERRY_RHUBARB,
+  3: Midlayer.Pie.apple,
+  4: Midlayer.Pie.mississippi_mud,
+  5: Midlayer.Pie.coconut_Cream,
+  6: Midlayer.Pie.Key_Lime,
+}
+
+struct FullMeal {
+  1: required Midlayer.Meal meal
+  2: required Midlayer.Dessert dessert
+}
+
+struct FullMealAndDrinks {
+  1: required FullMeal fullMeal
+  2: optional Drink drink
+}
+
+service FullMealService extends Midlayer.MealService {
+  FullMeal fullMeal()
+}
+
+service FullMealAndDrinksService extends FullMealService {
+  FullMealAndDrinks fullMealAndDrinks()
+
+  Midlayer.Pie bestPie()
+}
+
diff --git a/lib/st/README b/lib/st/README.md
similarity index 100%
rename from lib/st/README
rename to lib/st/README.md
diff --git a/lib/st/coding_standards.md b/lib/st/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/st/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/st/package.xml b/lib/st/package.xml
index 72194fc..f83936a 100644
--- a/lib/st/package.xml
+++ b/lib/st/package.xml
@@ -17,7 +17,7 @@
  specific language governing permissions and limitations
  under the License.
  -->
-<!-- Apache Thrift Smalltalk library version 1.0 -->
+<!-- Apache Thrift Smalltalk library version 1.0.0 -->
 <package>
   <name>libthrift-st</name>
   <file>thrift.st</file>
diff --git a/lib/swift/Makefile.am b/lib/swift/Makefile.am
new file mode 100644
index 0000000..6b88b06
--- /dev/null
+++ b/lib/swift/Makefile.am
@@ -0,0 +1,46 @@
+#
+# 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.
+#
+
+SUBDIRS = .
+
+all-local:
+	swift build --configuration release
+
+install-exec-hook:
+	swift install
+
+clean-local:
+	swift package clean
+	rm -rf .build
+
+precross:
+	swift
+
+check-local:
+	swift test
+
+EXTRA_DIST = \
+	Package.swift \
+	Sources \
+	Tests \
+	README.md
+
+MAINTAINERCLEANFILES = \
+	Makefile \
+	Makefile.in
diff --git a/lib/swift/Package.swift b/lib/swift/Package.swift
new file mode 100644
index 0000000..b533f60
--- /dev/null
+++ b/lib/swift/Package.swift
@@ -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.
+ */
+
+import PackageDescription
+
+let package = Package(
+	name: "Thrift"
+)
diff --git a/lib/swift/README.md b/lib/swift/README.md
new file mode 100644
index 0000000..6f10961
--- /dev/null
+++ b/lib/swift/README.md
@@ -0,0 +1,215 @@
+Thrift Swift Library
+=========================
+
+License
+-------
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+
+## Build
+    swift build
+
+## Test
+    swift test
+
+## Install Library
+##### Cocoapods
+Add the following to your podfile
+```ruby
+    pod 'Thrift-swift3', :git => 'git@github.com:apache/thrift.git', :branch => 'master'
+```
+
+##### SPM
+Unfortunately due to some limitations in SPM, the Package manifest and Sources directory must be at the root of the project.
+To get around that for the time being, you can use this mirrored repo.
+Add the following to your Package.swift
+```swift
+dependencies: [
+    .Package(url: "https://github.com/apocolipse/Thrift-Swift.git", majorVersion: 1)
+]
+```
+
+## Thrift Compiler
+
+You can compile IDL sources for Swift 3 with the following command:
+
+    thrift --gen swift thrift_file
+
+## Client Example
+```swift
+let transport = TSocketTransport(hostname: "localhost", port: 9090)!
+
+//  var proto = TCompactProtocol(transport: transport)
+let proto = TBinaryProtocol(on: transport)
+//  var client = HermesClient(inoutProtocol: proto)
+let client = ThriftTestClient(inoutProtocol: proto)
+do {
+    try client.testVoid()
+} catch let error {
+    print("\(error)")
+}
+```
+
+## Library Notes
+- Eliminated Protocol Factories, They were only used in async clients and server implementations, where Generics provide a better alternative.
+- Swifty Errors, All `TError` types have a nested `ErrorCode` Enum as well as some extra flavor where needed.
+- Value typed everything.  `TTransport` operates on value typed `Data` rather than reference typed `NSData` or `UnsafeBufferPointer`s
+- Swift 3 Named protocols.  Swift 3 naming conventions suggest the elimination of redundant words that can be inferred from variable/function signatures.  This renaming is applied throughout the Swift 3 library converting most naming conventions used in the Swift2/Cocoa library to Swift 3-esque naming conventions. eg.
+```swift
+func readString() throws -> String
+func writeString(_ val: String) throws
+```
+have been renamed to eliminate redundant words:
+```swift
+func read() throws -> String
+func write(_ val: String) throws
+```
+
+- Eliminated `THTTPTransport` that uses `NSURLConnection` due to it being deprecated and not available at all in Swift 3 for Linux.  `THTTPSessionTransport` from the Swift2/Cocoa library that uses `NSURLSession` has been renamed to `THTTPTransport` for this library and leverages `URLSession`, providing both synchronous (with semaphores) and asynchronous behavior.
+- Probably some More things I've missed here.
+
+## Generator Notes
+#### Generator Flags
+| Flag          | Description           |
+| ------------- |:-------------:|
+| async_clients | Generate clients which invoke asynchronously via block syntax. Asynchronous classes are appended with `_Async` |
+| no_strict*    | Generates non-strict structs      |
+| debug_descriptions | Allow use of debugDescription so the app can add description via a cateogory/extension      |
+| log_unexpected | Log every time an unexpected field ID or type is encountered. |
+| safe_enums     | Generate enum types with an unknown case to handle unspecified values rather than throw a serialization error  |
+
+
+
+*Most thrift libraries allow empty initialization of Structs, initializing `required` fields with nil/null/None (Python and Node generators).  Swift on the other hand requires initializers to initialize all non-Optional fields, and thus the Swift 3 generator does not provide default values (unlike the Swift 2/Cocoa generator).  In other languages, this allows the sending of NULL values in fields that are marked `required`, and thus will throw an error in Swift clients attempting to validate fields.  The `no_strict` option here will ignore the validation check, as well as behave similar to the Swift2/Cocoa generator and initialize required fields with empty initializers (where possible).
+
+
+## Whats implemented
+#### Library
+##### Transports
+- [x] TSocketTransport - CFSocket and PosixSocket variants available. CFSocket variant only currently available for Darwin platforms
+- [x] THTTPTransport - Currently only available for Darwin platforms, Swift Foundation URLSession implementation needs completion on linux.
+- [x] TSocketServer - Uses CFSockets only for binding, should be working on linux
+- [x] TFramedTransport
+- [x] TMemoryBufferTransport
+- [x] TFileTransport - A few variants using File handles and file descriptors.
+- [x] TStreamTransport - Fully functional in Darwin, Foundation backing not yet completed in Linux (This limits TCFSocketTransport to Darwin)
+- [ ] HTTPServer - Currently there is no lightweight  HTTPServer implementation the Swift Standard Library, so other 3rd party alternatives are required and out of scope for the Thrift library.  Examples using Perfect will be provided.
+- [ ] Other (gz, etc)
+
+##### Protocols
+- [x] TBinaryProtocol
+- [x] TCompactProtocol
+- [ ] TJSONProtocol - This will need to be implemented
+
+##### Generator
+- [x] Code Complete Generator
+- [x] Async clients
+- [x] Documentation Generation - Generator will transplant IDL docs to Swift code for easy lookup in Xcode
+- [ ] Default Values - TODO
+- [ ] no_strict mode - TODO
+- [ ] Namespacing - Still haven't nailed down a good paradigm for namespacing.  It will likely involve creating subdirectories for different namespaces and expecting the developer to import each subdirectory as separate modules.  It could extend to creating SPM Package manifests with sub-modules within the generated module
+
+
+
+## Example HTTP Server with Perfect
+```swift
+import PerfectLib
+import PerfectHTTP
+import PerfectHTTPServer
+import Dispatch
+
+let logQueue = DispatchQueue(label: "log", qos: .background, attributes: .concurrent)
+let pQueue = DispatchQueue(label: "log", qos: .userInitiated, attributes: .concurrent)
+
+
+class TPerfectServer<InProtocol: TProtocol, OutProtocol: TProtocol> {
+
+ private var server = HTTPServer()
+ private var processor: TProcessor
+
+ init(address: String? = nil,
+      path: String? = nil,
+      port: Int,
+      processor: TProcessor,
+      inProtocol: InProtocol.Type,
+      outProtocol: OutProtocol.Type) throws {
+
+   self.processor = processor
+
+   if let address = address {
+     server.serverAddress = address
+   }
+   server.serverPort = UInt16(port)
+
+   var routes = Routes()
+   var uri = "/"
+   if let path = path {
+     uri += path
+   }
+   routes.add(method: .post, uri: uri) { request, response in
+     pQueue.async {
+       response.setHeader(.contentType, value: "application/x-thrift")
+
+       let itrans = TMemoryBufferTransport()
+       if let bytes = request.postBodyBytes {
+         let data = Data(bytes: bytes)
+         itrans.reset(readBuffer: data)
+       }
+
+       let otrans = TMemoryBufferTransport(flushHandler: { trans, buff in
+         let array = buff.withUnsafeBytes {
+           Array<UInt8>(UnsafeBufferPointer(start: $0, count: buff.count))
+         }
+         response.status = .ok
+         response.setBody(bytes: array)
+         response.completed()
+       })
+
+       let inproto = InProtocol(on: itrans)
+       let outproto = OutProtocol(on: otrans)
+
+       do {
+         try processor.process(on: inproto, outProtocol: outproto)
+         try otrans.flush()
+       } catch {
+         response.status = .badRequest
+         response.completed()
+       }
+     }
+   }
+   server.addRoutes(routes)
+ }
+
+ func serve() throws {
+   try server.start()
+ }
+}
+```
+
+#### Example Usage
+```swift
+class ServiceHandler : Service {
+    ...
+}
+let server = try? TPerfectServer(port: 9090,
+                                processor: ServiceProcessor(service: ServiceHandler()),
+                                inProtocol: TBinaryProtocol.self,
+                                outProtocol: TBinaryProtocol.self)
+
+try? server?.serve()
+```
diff --git a/lib/swift/Sources/LinuxHelper.swift b/lib/swift/Sources/LinuxHelper.swift
new file mode 100644
index 0000000..66d92bb
--- /dev/null
+++ b/lib/swift/Sources/LinuxHelper.swift
@@ -0,0 +1,46 @@
+/*
+ * 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 Foundation
+import CoreFoundation
+
+#if os(Linux)
+/// Extensions for Linux for incomplete Foundation API's.
+/// swift-corelibs-foundation is not yet 1:1 with OSX/iOS Foundation
+
+extension CFSocketError {
+  public static let success = kCFSocketSuccess
+}
+  
+extension UInt {
+  public static func &(lhs: UInt, rhs: Int) -> UInt {
+    let cast = unsafeBitCast(rhs, to: UInt.self)
+    return lhs & cast
+  }
+}
+
+#else
+extension CFStreamPropertyKey {
+  static let shouldCloseNativeSocket  = CFStreamPropertyKey(kCFStreamPropertyShouldCloseNativeSocket)
+  // Exists as Stream.PropertyKey.socketSecuritylevelKey but doesn't work with CFReadStreamSetProperty
+  static let socketSecurityLevel      = CFStreamPropertyKey(kCFStreamPropertySocketSecurityLevel)
+  static let SSLSettings              = CFStreamPropertyKey(kCFStreamPropertySSLSettings)
+}
+#endif
diff --git a/lib/swift/Sources/TApplicationError.swift b/lib/swift/Sources/TApplicationError.swift
new file mode 100644
index 0000000..bc39396
--- /dev/null
+++ b/lib/swift/Sources/TApplicationError.swift
@@ -0,0 +1,157 @@
+/*
+* 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.
+*/
+
+
+public struct TApplicationError : TError {
+  public enum Code : TErrorCode {
+    case unknown
+    case unknownMethod(methodName: String?)
+    case invalidMessageType
+    case wrongMethodName(methodName: String?)
+    case badSequenceId
+    case missingResult(methodName: String?)
+    case internalError
+    case protocolError
+    case invalidTransform
+    case invalidProtocol
+    case unsupportedClientType
+    
+    
+    /// Initialize a TApplicationError with a Thrift error code
+    /// Normally this would be achieved with RawRepresentable however
+    /// by doing this we can allow for associated properties on enum cases for
+    /// case specific context data in a Swifty, type-safe manner.
+    ///
+    /// - parameter thriftErrorCode: Integer TApplicationError(exception) error code.  
+    ///                              Default to 0 (.unknown)
+    public init(thriftErrorCode: Int) {
+      switch thriftErrorCode {
+      case 1:  self = .unknownMethod(methodName: nil)
+      case 2:  self = .invalidMessageType
+      case 3:  self = .wrongMethodName(methodName: nil)
+      case 4:  self = .badSequenceId
+      case 5:  self = .missingResult(methodName: nil)
+      case 6:  self = .internalError
+      case 7:  self = .protocolError
+      case 8:  self = .invalidProtocol
+      case 9:  self = .invalidTransform
+      case 10: self = .unsupportedClientType
+      default: self = .unknown
+      }
+    }
+    public var thriftErrorCode: Int {
+      switch self {
+      case .unknown:                return 0
+      case .unknownMethod:          return 1
+      case .invalidMessageType:     return 2
+      case .wrongMethodName:        return 3
+      case .badSequenceId:          return 4
+      case .missingResult:          return 5
+      case .internalError:          return 6
+      case .protocolError:          return 7
+      case .invalidProtocol:        return 8
+      case .invalidTransform:       return 9
+      case .unsupportedClientType:  return 10
+      }
+    }
+    
+    public var description: String {
+      /// Output "for #methodName" if method is not nil else empty
+      let methodUnwrap: (String?) -> String =  { method in
+        return "\(method == nil ? "" : " for \(method ?? "")")"
+      }
+      switch self {
+      case .unknown:                      return "Unknown TApplicationError"
+      case .unknownMethod(let method):    return "Unknown Method\(methodUnwrap(method))"
+      case .invalidMessageType:           return "Invalid Message Type"
+      case .wrongMethodName(let method):  return "Wrong Method Name\(methodUnwrap(method))"
+      case .badSequenceId:                return "Bad Sequence ID"
+      case .missingResult(let method):    return "Missing Result\(methodUnwrap(method))"
+      case .internalError:                return "Internal Error"
+      case .protocolError:                return "Protocol Error"
+      case .invalidProtocol:              return "Invalid Protocol"
+      case .invalidTransform:             return "Invalid Transform"
+      case .unsupportedClientType:        return "Unsupported Client Type"
+      }
+    }
+  }
+
+  public init() { }
+  
+  public init(thriftErrorCode code: Int, message: String? = nil) {
+    self.error = Code(thriftErrorCode: code)
+    self.message = message
+  }
+  
+  public var error: Code = .unknown
+  public var message: String? = nil
+  public static var defaultCase: Code { return .unknown }
+}
+
+extension TApplicationError : TSerializable {
+  public static var thriftType: TType { return .struct }
+  
+  public static func read(from proto: TProtocol) throws -> TApplicationError {
+    var errorCode: Int = 0
+    var message: String? = nil
+    _ = try proto.readStructBegin()
+    fields: while true {
+      let (_, fieldType, fieldID) = try proto.readFieldBegin()
+      
+      switch (fieldID, fieldType) {
+      case (_, .stop):
+        break fields
+      case (1, .string):
+        message = try proto.read()
+      case (2, .i32):
+        errorCode = Int(try proto.read() as Int32)
+      
+      case let (_, unknownType):
+        try proto.skip(type: unknownType)
+      }
+      
+      try proto.readFieldEnd()
+    }
+    try proto.readStructEnd()
+    return TApplicationError(thriftErrorCode: errorCode, message: message)
+  }
+
+  public func write(to proto: TProtocol) throws {
+    try proto.writeStructBegin(name: "TApplicationException")
+    
+    try proto.writeFieldBegin(name: "message", type: .string, fieldID: 1)
+    try proto.write(message ?? "")
+    try proto.writeFieldEnd()
+    
+    try proto.writeFieldBegin(name: "type", type: .i32, fieldID: 2)
+    let val = Int32(error.thriftErrorCode)
+    try proto.write(val)
+    try proto.writeFieldEnd()
+    try proto.writeFieldStop()
+    try proto.writeStructEnd()
+  }
+  
+  public var hashValue: Int {
+    return error.thriftErrorCode &+ (message?.hashValue ?? 0)
+  }
+}
+
+public func ==(lhs: TApplicationError, rhs: TApplicationError) -> Bool {
+  return lhs.error.thriftErrorCode == rhs.error.thriftErrorCode && lhs.message == rhs.message
+}
diff --git a/lib/swift/Sources/TBinary.swift b/lib/swift/Sources/TBinary.swift
new file mode 100644
index 0000000..4be5644
--- /dev/null
+++ b/lib/swift/Sources/TBinary.swift
@@ -0,0 +1,32 @@
+/*
+ * 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 Foundation
+
+extension Data : TSerializable {
+  public static var thriftType: TType { return .string }
+  
+  public static func read(from proto: TProtocol) throws -> Data {
+    return try proto.read() as Data
+  }
+  
+  public func write(to proto: TProtocol) throws {
+    try proto.write(self)
+  }
+}
diff --git a/lib/swift/Sources/TBinaryProtocol.swift b/lib/swift/Sources/TBinaryProtocol.swift
new file mode 100644
index 0000000..a97249a
--- /dev/null
+++ b/lib/swift/Sources/TBinaryProtocol.swift
@@ -0,0 +1,384 @@
+/*
+ * 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 Foundation
+
+public struct TBinaryProtocolVersion {
+  static let version1    = Int32(bitPattern: 0x80010000)
+  static let versionMask = Int32(bitPattern: 0xffff0000)
+}
+
+public class TBinaryProtocol: TProtocol {
+  public var messageSizeLimit: UInt32  = 0
+  
+  public var transport: TTransport
+  
+  // class level properties for setting global config (useful for server in lieu of Factory design)
+  public static var strictRead: Bool = false
+  public static var strictWrite: Bool = true
+
+  private var strictRead: Bool
+  private var strictWrite: Bool
+  
+  var currentMessageName: String?
+  var currentFieldName: String?
+  
+  
+  public convenience init(transport: TTransport, strictRead: Bool, strictWrite: Bool) {
+    self.init(on: transport)
+    self.strictRead = strictRead
+    self.strictWrite = strictWrite
+  }
+  
+  public required init(on transport: TTransport) {
+    self.transport = transport
+    self.strictWrite = TBinaryProtocol.strictWrite
+    self.strictRead = TBinaryProtocol.strictRead
+  }
+  
+  func readStringBody(_ size: Int) throws -> String {
+    
+    var data = Data()
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport read failed")) {
+      data = try self.transport.readAll(size: size)
+    }
+    
+    return String(data: data, encoding: String.Encoding.utf8) ?? ""
+  }
+  
+  /// Mark: - TProtocol
+  
+  public func readMessageBegin() throws -> (String, TMessageType, Int32) {
+    let size: Int32 = try read()
+    var messageName = ""
+    var type = TMessageType.exception
+    
+    if size < 0 {
+      let version = size & TBinaryProtocolVersion.versionMask
+      if version != TBinaryProtocolVersion.version1 {
+        throw TProtocolError(error: .badVersion(expected: "\(TBinaryProtocolVersion.version1)",
+                                                got: "\(version)"))
+      }
+      type = TMessageType(rawValue: Int32(size) & 0x00FF) ?? type
+      messageName = try read()
+    } else {
+      if strictRead {
+        let errorMessage = "Missing message version, old client? Message Name: \(currentMessageName ?? "")"
+        throw TProtocolError(error: .invalidData,
+                             message: errorMessage)
+      }
+      if messageSizeLimit > 0 && size > Int32(messageSizeLimit) {
+        throw TProtocolError(error: .sizeLimit(limit: Int(messageSizeLimit), got: Int(size)))
+      }
+      
+      messageName = try readStringBody(Int(size))
+      type = TMessageType(rawValue: Int32(try read() as UInt8)) ?? type
+    }
+    
+    let seqID: Int32 = try read()
+    return (messageName, type, seqID)
+  }
+  
+  public func readMessageEnd() throws {
+    return
+  }
+  
+  public func readStructBegin() throws -> String {
+    return ""
+  }
+  
+  public func readStructEnd() throws {
+    return
+  }
+  
+  public func readFieldBegin() throws -> (String, TType, Int32) {
+    
+    let fieldType = TType(rawValue: Int32(try read() as UInt8)) ?? TType.stop
+    var fieldID: Int32 = 0
+    
+    if fieldType != .stop {
+      fieldID = Int32(try read() as Int16)
+    }
+    
+    return ("", fieldType, fieldID)
+  }
+  
+  public func readFieldEnd() throws {
+    return
+  }
+  
+  public func readMapBegin() throws -> (TType, TType, Int32) {
+    var raw = Int32(try read() as UInt8)
+    guard let keyType = TType(rawValue: raw) else {
+      throw TProtocolError(message: "Unknown value for keyType TType: \(raw)")
+    }
+    
+    raw = Int32(try read() as UInt8)
+    guard let valueType = TType(rawValue: raw) else {
+      throw TProtocolError(message: "Unknown value for valueType TType: \(raw)")
+    }
+    let size: Int32 = try read()
+    
+    return (keyType, valueType, size)
+  }
+  
+  public func readMapEnd() throws {
+    return
+  }
+  
+  public func readSetBegin() throws -> (TType, Int32) {
+    let raw = Int32(try read() as UInt8)
+    guard let elementType = TType(rawValue: raw) else {
+      throw TProtocolError(message: "Unknown value for elementType TType: \(raw)")
+    }
+    
+    let size: Int32 = try read()
+    
+    return (elementType, size)
+  }
+  
+  public func readSetEnd() throws {
+    return
+  }
+  
+  public func readListBegin() throws -> (TType, Int32) {
+    let raw = Int32(try read() as UInt8)
+    guard let elementType = TType(rawValue: raw) else {
+      throw TProtocolError(message: "Unknown value for elementType TType: \(raw)")
+    }
+    let size: Int32 = try read()
+    
+    return (elementType, size)
+  }
+  
+  public func readListEnd() throws {
+    return
+  }
+  
+  public func read() throws -> String {
+    let data: Data = try read()
+    guard let str = String.init(data: data, encoding: .utf8) else {
+      throw TProtocolError(error: .invalidData, message: "Couldn't encode UTF-8 from data read")
+    }
+    return str
+  }
+  
+  public func read() throws -> Bool {
+    return (try read() as UInt8) == 1
+  }
+  
+  public func read() throws -> UInt8 {
+    var buff = Data()
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
+      buff = try self.transport.readAll(size: 1)
+    }
+    return buff[0]
+  }
+  
+  public func read() throws -> Int16 {
+    var buff = Data()
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
+      buff = try self.transport.readAll(size: 2)
+    }
+    var ret = Int16(buff[0] & 0xff) << 8
+    ret |=    Int16(buff[1] & 0xff)
+    return ret
+  }
+  
+  public func read() throws -> Int32 {
+    var buff = Data()
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
+      buff = try self.transport.readAll(size: 4)
+    }
+    var ret = Int32(buff[0] & 0xff) << 24
+    ret |=    Int32(buff[1] & 0xff) << 16
+    ret |=    Int32(buff[2] & 0xff) << 8
+    ret |=    Int32(buff[3] & 0xff)
+    
+    return ret
+  }
+  
+  public func read() throws -> Int64 {
+    var buff = Data()
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
+      buff = try self.transport.readAll(size: 8)
+    }
+    var ret = Int64(buff[0] & 0xff) << 56
+    ret |=    Int64(buff[1] & 0xff) << 48
+    ret |=    Int64(buff[2] & 0xff) << 40
+    ret |=    Int64(buff[3] & 0xff) << 32
+    ret |=    Int64(buff[4] & 0xff) << 24
+    ret |=    Int64(buff[5] & 0xff) << 16
+    ret |=    Int64(buff[6] & 0xff) << 8
+    ret |=    Int64(buff[7] & 0xff)
+    
+    return ret
+  }
+  
+  public func read() throws -> Double {
+    let val = try read() as Int64
+    return Double(bitPattern: UInt64(bitPattern: val))
+  }
+  
+  public func read() throws -> Data {
+    let size = Int(try read() as Int32)
+    var data = Data()
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
+      data = try self.transport.readAll(size: size)
+    }
+    
+    return data
+  }
+  
+  // Write methods
+  
+  public func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws {
+    if strictWrite {
+      let version = TBinaryProtocolVersion.version1 | Int32(messageType.rawValue)
+      try write(version)
+      try write(name)
+      try write(sequenceID)
+    } else {
+      try write(name)
+      try write(UInt8(messageType.rawValue))
+      try write(sequenceID)
+    }
+    currentMessageName = name
+  }
+  
+  public func writeMessageEnd() throws {
+    currentMessageName = nil
+  }
+  
+  public func writeStructBegin(name: String) throws {
+    return
+  }
+  
+  public func writeStructEnd() throws {
+    return
+  }
+  
+  public func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws {
+    try write(UInt8(fieldType.rawValue))
+    try write(Int16(fieldID))
+  }
+  
+  public func writeFieldStop() throws {
+    try write(UInt8(TType.stop.rawValue))
+  }
+  
+  public func writeFieldEnd() throws {
+    return
+  }
+  
+  public func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws {
+    try write(UInt8(keyType.rawValue))
+    try write(UInt8(valueType.rawValue))
+    try write(size)
+  }
+  
+  public func writeMapEnd() throws {
+    return
+  }
+  
+  public func writeSetBegin(elementType: TType, size: Int32) throws {
+    try write(UInt8(elementType.rawValue))
+    try write(size)
+  }
+  
+  public func writeSetEnd() throws {
+    return
+  }
+  
+  public func writeListBegin(elementType: TType, size: Int32) throws {
+    try write(UInt8(elementType.rawValue))
+    try write(size)
+  }
+  
+  public func writeListEnd() throws {
+    return
+  }
+  
+  public func write(_ value: String) throws {
+    try write(value.data(using: .utf8)!)
+  }
+  
+  public func write(_ value: Bool) throws {
+    let byteVal: UInt8 = value ? 1 : 0
+    try write(byteVal)
+  }
+  
+  public func write(_ value: UInt8) throws {
+    let buff = Data(bytes: [value])
+    
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) {
+      try self.transport.write(data: buff)
+    }
+  }
+  
+  public func write(_ value: Int16) throws {
+    var buff = Data()
+    buff.append(Data(bytes: [UInt8(0xff & (value >> 8))]))
+    buff.append(Data(bytes: [UInt8(0xff & (value))]))
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) {
+      try self.transport.write(data: buff)
+    }
+  }
+  
+  public func write(_ value: Int32) throws {
+    var buff = Data()
+    buff.append(Data(bytes: [UInt8(0xff & (value >> 24))]))
+    buff.append(Data(bytes: [UInt8(0xff & (value >> 16))]))
+    buff.append(Data(bytes: [UInt8(0xff & (value >> 8))]))
+    buff.append(Data(bytes: [UInt8(0xff & (value))]))
+    
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) {
+      try self.transport.write(data: buff)
+    }
+  }
+  
+  public func write(_ value: Int64) throws {
+    var buff = Data()
+    buff.append(Data(bytes: [UInt8(0xff & (value >> 56))]))
+    buff.append(Data(bytes: [UInt8(0xff & (value >> 48))]))
+    buff.append(Data(bytes: [UInt8(0xff & (value >> 40))]))
+    buff.append(Data(bytes: [UInt8(0xff & (value >> 32))]))
+    buff.append(Data(bytes: [UInt8(0xff & (value >> 24))]))
+    buff.append(Data(bytes: [UInt8(0xff & (value >> 16))]))
+    buff.append(Data(bytes: [UInt8(0xff & (value >> 8))]))
+    buff.append(Data(bytes: [UInt8(0xff & (value))]))
+    
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) {
+      try self.transport.write(data: buff)
+    }
+  }
+  
+  public func write(_ value: Double) throws {
+    // Notably unsafe, since Double and Int64 are the same size, this should work fine
+    try self.write(Int64(bitPattern: value.bitPattern))
+  }
+  
+  public func write(_ data: Data) throws {
+    try write(Int32(data.count))
+    
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) {
+      try self.transport.write(data: data)
+    }
+  }
+}
diff --git a/lib/swift/Sources/TClient.swift b/lib/swift/Sources/TClient.swift
new file mode 100644
index 0000000..cc3288a
--- /dev/null
+++ b/lib/swift/Sources/TClient.swift
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+
+open class TClient {
+  public let inProtocol: TProtocol
+  public let outProtocol: TProtocol
+
+  required public init(inoutProtocol: TProtocol) {
+    self.inProtocol = inoutProtocol
+    self.outProtocol = inoutProtocol
+  }
+
+  required public init(inProtocol: TProtocol, outProtocol: TProtocol) {
+    self.inProtocol = inProtocol
+    self.outProtocol = outProtocol
+  }
+}
+
+
+open class TAsyncClient<Protocol: TProtocol, Factory: TAsyncTransportFactory> {
+  public var factory: Factory
+  public init(with protocol: Protocol.Type, factory: Factory) {
+    self.factory = factory
+  }
+}
+
+
+public enum TAsyncResult<T> {
+  case success(T)
+  case error(Swift.Error)
+  
+  public func value() throws -> T {
+    switch self {
+    case .success(let t): return t
+    case .error(let e): throw e
+    }
+  }
+}
diff --git a/lib/swift/Sources/TCompactProtocol.swift b/lib/swift/Sources/TCompactProtocol.swift
new file mode 100644
index 0000000..59773c3
--- /dev/null
+++ b/lib/swift/Sources/TCompactProtocol.swift
@@ -0,0 +1,575 @@
+/*
+* 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 Foundation
+import CoreFoundation
+
+public enum TCType: UInt8 {
+  case stop          = 0x00
+  case boolean_TRUE  = 0x01
+  case boolean_FALSE = 0x02
+  case i8            = 0x03
+  case i16           = 0x04
+  case i32           = 0x05
+  case i64           = 0x06
+  case double        = 0x07
+  case binary        = 0x08
+  case list          = 0x09
+  case set           = 0x0A
+  case map           = 0x0B
+  case `struct`      = 0x0C
+  
+  public static let typeMask: UInt8 = 0xE0 // 1110 0000
+  public static let typeBits: UInt8 = 0x07 // 0000 0111
+  public static let typeShiftAmount = 5
+ 
+}
+
+
+public class TCompactProtocol: TProtocol {
+  public static let protocolID: UInt8  = 0x82
+  public static let version: UInt8     = 1
+  public static let versionMask: UInt8 = 0x1F // 0001 1111
+  
+  public var transport: TTransport
+  
+  var lastField: [UInt8] = []
+  var lastFieldId: UInt8 = 0
+  
+  var boolFieldName: String?
+  var boolFieldType: TType?
+  var boolFieldId: Int32?
+  var booleanValue: Bool?
+  
+  var currentMessageName: String?
+
+  public required init(on transport: TTransport) {
+    self.transport = transport
+  }
+
+  
+  /// Mark: - TCompactProtocol helpers
+  
+  func writebyteDirect(_ byte: UInt8) throws {
+    let byte = Data(bytes: [byte])
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) {
+      try self.transport.write(data: byte)
+    }
+  }
+  
+  func writeVarint32(_ val: UInt32) throws {
+    var val = val
+    var i32buf = [UInt8](repeating: 0, count: 5)
+    var idx = 0
+    while true {
+      if (val & ~0x7F) == 0 {
+        i32buf[idx] = UInt8(val)
+        idx += 1
+        break
+      } else {
+        i32buf[idx] = UInt8((val & 0x7F) | 0x80)
+        idx += 1
+        val >>= 7
+      }
+    }
+    
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) {
+      try self.transport.write(data: Data(bytes: i32buf[0..<idx]))
+    }
+  }
+  
+  func writeVarint64(_ val: UInt64) throws {
+    var val = val
+    var varint64out = [UInt8](repeating: 0, count: 10)
+    var idx = 0
+    while true {
+      if (val & ~0x7F) == 0{
+        varint64out[idx] = UInt8(val)
+        idx += 1
+        break
+      } else {
+        varint64out[idx] = UInt8(val & 0x7F) | 0x80
+        idx += 1
+        val >>= 7
+      }
+    }
+    
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) {
+      try self.transport.write(data: Data(bytes: varint64out[0..<idx]))
+    }
+  
+  }
+  
+  func writeCollectionBegin(_ elementType: TType, size: Int32) throws {
+    let ctype = compactType(elementType).rawValue
+    if size <= 14 {
+      try writebyteDirect(UInt8(size << 4) | ctype)
+    } else {
+      try writebyteDirect(0xF0 | ctype)
+      try writeVarint32(UInt32(size))
+    }
+  }
+  
+  func readBinary(_ size: Int) throws -> Data {
+    var result = Data()
+    if size != 0 {
+      try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
+        result = try self.transport.readAll(size: size)
+      }
+    }
+    return result
+  }
+  
+  func readVarint32() throws -> UInt32 {
+    var result: UInt32 = 0
+    var shift: UInt32 = 0
+    while true {
+      let byte: UInt8 = try read()
+      
+      result |= UInt32(byte & 0x7F) << shift
+      if (byte & 0x80) == 0 {
+        break
+      }
+      
+      shift += 7
+    }
+    
+    return result
+  }
+  
+  func readVarint64() throws -> UInt64 {
+    var result: UInt64 = 0
+    var shift: UInt64 = 0
+    
+    while true {
+      let byte: UInt8 = try read()
+      
+      result |= UInt64(byte & 0x7F) << shift
+      if (byte & 0x80) == 0 {
+        break
+      }
+      
+      shift += 7
+    }
+    return result
+  }
+  
+
+  func ttype(_ compactTypeVal: UInt8) throws -> TType {
+    guard let compactType = TCType(rawValue: compactTypeVal) else {
+      throw TProtocolError(message: "Unknown TCType value: \(compactTypeVal)")
+    }
+    
+    switch compactType {
+    case .stop: return .stop;
+    case .boolean_FALSE, .boolean_TRUE: return .bool;
+    case .i8: return .i8;
+    case .i16: return .i16;
+    case .i32: return .i32;
+    case .i64: return .i64;
+    case .double: return .double;
+    case .binary: return .string;
+    case .list: return .list;
+    case .set: return .set;
+    case .map: return .map;
+    case .struct: return .struct;
+    }
+  }
+  
+  func compactType(_ ttype: TType) -> TCType {
+    switch ttype {
+    case .stop:   return .stop
+    case .void:   return .i8
+    case .bool:   return .boolean_FALSE
+    case .i8:   return .i8
+    case .double: return .double
+    case .i16:    return .i16
+    case .i32:    return .i32
+    case .i64:    return .i64
+    case .string: return .binary
+    case .struct: return .struct
+    case .map:    return .map
+    case .set:    return .set
+    case .list:   return .list
+    case .utf8:   return .binary
+    case .utf16:  return .binary
+    }
+  }
+  
+  /// ZigZag encoding maps signed integers to unsigned integers so that
+  /// numbers with a small absolute value (for instance, -1) have
+  /// a small varint encoded value too. It does this in a way that
+  /// "zig-zags" back and forth through the positive and negative integers,
+  /// so that -1 is encoded as 1, 1 is encoded as 2, -2 is encoded as 3, and so
+  ///
+  /// - parameter n: number to zigzag
+  ///
+  /// - returns: zigzaged UInt32
+  func i32ToZigZag(_ n : Int32) -> UInt32 {
+    return UInt32(bitPattern: Int32(n << 1) ^ Int32(n >> 31))
+  }
+
+  func i64ToZigZag(_ n : Int64) -> UInt64 {
+    return UInt64(bitPattern: Int64(n << 1) ^ Int64(n >> 63))
+  }
+
+  func zigZagToi32(_ n: UInt32) -> Int32 {
+    return Int32(n >> 1) ^ (-Int32(n & 1))
+  }
+  
+  func zigZagToi64(_ n: UInt64) -> Int64 {
+    return Int64(n >> 1) ^ (-Int64(n & 1))
+  }
+  
+  
+  
+  /// Mark: - TProtocol  
+  
+  public func readMessageBegin() throws -> (String, TMessageType, Int32) {
+    let protocolId: UInt8 = try read()
+    
+    if protocolId != TCompactProtocol.protocolID {
+      let expected = String(format:"%2X", TCompactProtocol.protocolID)
+      let got      = String(format:"%2X", protocolId)
+      throw TProtocolError(message: "Wrong Protocol ID \(got)",
+                           extendedError: .mismatchedProtocol(expected: expected, got: got))
+
+    }
+
+    let versionAndType: UInt8 = try read()
+    let version: UInt8 = versionAndType & TCompactProtocol.versionMask
+    if version != TCompactProtocol.version {
+      throw TProtocolError(error: .badVersion(expected: "\(TCompactProtocol.version)",
+                                              got:"\(version)"))
+
+    }
+    
+    let type = (versionAndType >> UInt8(TCType.typeShiftAmount)) & TCType.typeBits
+    guard let mtype = TMessageType(rawValue: Int32(type)) else {
+      throw TProtocolError(message: "Unknown TMessageType value: \(type)")
+    }
+    let sequenceId = try readVarint32()
+    let name: String = try read()
+    
+    return (name, mtype, Int32(sequenceId))
+  }
+  
+  public func readMessageEnd() throws { }
+  
+  public func readStructBegin() throws -> String {
+    lastField.append(lastFieldId)
+    lastFieldId = 0
+    return ""
+  }
+  
+  public func readStructEnd() throws {
+    lastFieldId = lastField.last ?? 0
+    lastField.removeLast()
+  }
+  
+  public func readFieldBegin() throws -> (String, TType, Int32) {
+    let byte: UInt8 = try read()
+    guard let type = TCType(rawValue: byte & 0x0F) else {
+      throw TProtocolError(message: "Unknown TCType \(byte & 0x0F)")
+    }
+    
+    // if it's a stop, then we can return immediately, as the struct is over
+    if type == .stop {
+      return ("", .stop, 0)
+    }
+    
+    var fieldId: Int16 = 0
+    
+    // mask off the 4MSB of the type header.  it could contain a field id delta
+    let modifier = (byte & 0xF0) >> 4
+    if modifier == 0 {
+      // not a delta.  look ahead for the zigzag varint field id
+      fieldId = try read()
+    } else {
+      // has a delta.  add the delta to the last Read field id.
+      fieldId = Int16(lastFieldId + modifier)
+    }
+    
+    let fieldType = try ttype(type.rawValue)
+    
+    // if this happens to be a boolean field, the value is encoded in the type
+    if type == .boolean_TRUE || type == .boolean_FALSE {
+      // save the boolean value in a special instance variable
+      booleanValue = type == .boolean_TRUE
+    }
+    
+    // push the new field onto the field stack so we can keep the deltas going
+    lastFieldId = UInt8(fieldId)
+    return ("", fieldType, Int32(fieldId))
+  }
+  
+  public func readFieldEnd() throws { }
+  
+  public func read() throws -> String {
+    let length = try readVarint32()
+    
+    var result: String
+    
+    if length != 0 {
+      let data = try readBinary(Int(length))
+      result = String(data: data, encoding: String.Encoding.utf8) ?? ""
+    } else {
+      result = ""
+    }
+    
+    return result
+  }
+  
+  public func read() throws -> Bool {
+    if let val = booleanValue {
+      self.booleanValue = nil
+      return val
+    } else {
+      let result = try read() as UInt8
+      return TCType(rawValue: result) == .boolean_TRUE
+    }
+  }
+  
+  public func read() throws -> UInt8 {
+    var buff: UInt8 = 0
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
+      buff = try self.transport.readAll(size: 1)[0]
+    }
+    return buff
+  }
+  
+  public func read() throws -> Int16 {
+    let v = try readVarint32()
+    return Int16(zigZagToi32(v))
+  }
+  
+  public func read() throws -> Int32 {
+    let v = try readVarint32()
+    return zigZagToi32(v)
+  }
+  
+  public func read() throws -> Int64 {
+    let v = try readVarint64()
+    return zigZagToi64(v)
+  }
+  
+  public func read() throws -> Double {
+    var buff = Data()
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
+      buff = try self.transport.readAll(size: 8)
+    }
+    
+    let i64: UInt64 = buff.withUnsafeBytes { (ptr: UnsafePointer<UInt8>) -> UInt64 in
+      return UnsafePointer<UInt64>(OpaquePointer(ptr)).pointee
+    }
+    let bits = CFSwapInt64LittleToHost(i64)
+    return Double(bitPattern: bits)
+  }
+  
+  public func read() throws -> Data {
+    let length = try readVarint32()
+    return try readBinary(Int(length))
+  }
+  
+  public func readMapBegin() throws -> (TType, TType, Int32) {
+    var keyAndValueType: UInt8 = 8
+    let size = try readVarint32()
+    if size != 0 {
+      keyAndValueType = try read()
+    }
+    
+    let keyType = try ttype(keyAndValueType >> 4)
+    let valueType = try ttype(keyAndValueType & 0xF)
+    
+    return (keyType, valueType, Int32(size))
+  }
+  
+  public func readMapEnd() throws { }
+  
+  public func readSetBegin() throws -> (TType, Int32) {
+    return try readListBegin()
+  }
+  
+  public func readSetEnd() throws { }
+  
+  public func readListBegin() throws -> (TType, Int32) {
+    let sizeAndType: UInt8 = try read()
+    var size: UInt32 = UInt32(sizeAndType >> 4) & 0x0f
+    if size == 15 {
+      size = try readVarint32()
+    }
+    let elementType = try ttype(sizeAndType & 0x0F)
+    
+    return (elementType, Int32(size))
+  }
+  
+  public func readListEnd() throws { }
+  
+  public func writeMessageBegin(name: String,
+                                type messageType: TMessageType,
+                                sequenceID: Int32) throws {
+    try writebyteDirect(TCompactProtocol.protocolID)
+    let nextByte: UInt8 = (TCompactProtocol.version & TCompactProtocol.versionMask) |
+                          (UInt8((UInt32(messageType.rawValue) << UInt32(TCType.typeShiftAmount))) &
+                          TCType.typeMask)
+    try writebyteDirect(nextByte)
+    try writeVarint32(UInt32(sequenceID))
+    try write(name)
+    
+    currentMessageName = name
+  }
+  
+  public func writeMessageEnd() throws {
+    currentMessageName = nil
+  }
+  
+  public func writeStructBegin(name: String) throws {
+    lastField.append(lastFieldId)
+    lastFieldId = 0
+  }
+  
+  public func writeStructEnd() throws {
+    lastFieldId = lastField.last ?? 0
+    lastField.removeLast()
+  }
+  
+  public func writeFieldBegin(name: String,
+                              type fieldType: TType,
+                              fieldID: Int32) throws {
+    if fieldType == .bool {
+      boolFieldName = name
+      boolFieldType = fieldType
+      boolFieldId = fieldID
+      return
+    } else {
+      try writeFieldBeginInternal(name: name,
+                                  type: fieldType,
+                                  fieldID: fieldID,
+                                  typeOverride: 0xFF)
+    }
+  }
+  
+  func writeFieldBeginInternal(name: String,
+                               type fieldType: TType,
+                               fieldID: Int32,
+                               typeOverride: UInt8) throws {
+    
+    let typeToWrite = typeOverride == 0xFF ? compactType(fieldType).rawValue : typeOverride
+    
+    // check if we can use delta encoding for the field id
+    let diff = UInt8(fieldID) - lastFieldId
+    if (UInt8(fieldID) > lastFieldId) && (diff <= 15) {
+      // Write them together
+      try writebyteDirect((UInt8(fieldID) - lastFieldId) << 4 | typeToWrite)
+      
+    } else {
+      // Write them separate
+      try writebyteDirect(typeToWrite)
+      try write(Int16(fieldID))
+    }
+    
+    lastFieldId = UInt8(fieldID)
+      
+  }
+  
+  public func writeFieldStop() throws {
+    try writebyteDirect(TCType.stop.rawValue)
+  }
+  
+  public func writeFieldEnd() throws { }
+  
+  public func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws {
+    if size == 0 {
+      try writebyteDirect(0)
+    } else {
+      try writeVarint32(UInt32(size))
+      
+      let compactedTypes = compactType(keyType).rawValue << 4 | compactType(valueType).rawValue
+      try writebyteDirect(compactedTypes)
+    }
+  }
+  
+  public func writeMapEnd() throws { }
+  
+  public func writeSetBegin(elementType: TType, size: Int32) throws {
+    try writeCollectionBegin(elementType, size: size)
+  }
+  
+  public func writeSetEnd() throws { }
+  
+  public func writeListBegin(elementType: TType, size: Int32) throws {
+    try writeCollectionBegin(elementType, size: size)
+  }
+  
+  public func writeListEnd() throws { }
+  
+  public func write(_ value: String) throws {
+    try write(value.data(using: String.Encoding.utf8)!)
+  }
+  
+  public func write(_ value: Bool) throws {
+    if let boolFieldId = boolFieldId, let boolFieldType = boolFieldType,
+       let boolFieldName = boolFieldName {
+      
+      // we haven't written the field header yet
+      let compactType: TCType = value ? .boolean_TRUE : .boolean_FALSE
+      try writeFieldBeginInternal(name: boolFieldName, type: boolFieldType, fieldID: boolFieldId,
+                                  typeOverride: compactType.rawValue)
+      self.boolFieldId = nil
+      self.boolFieldType = nil
+      self.boolFieldName = nil
+    } else {
+      // we're not part of a field, so just write the value.
+      try writebyteDirect(value ? TCType.boolean_TRUE.rawValue : TCType.boolean_FALSE.rawValue)
+    }
+  }
+
+  public func write(_ value: UInt8) throws {
+    try writebyteDirect(value)
+  }
+
+  public func write(_ value: Int16) throws {
+    try writeVarint32(i32ToZigZag(Int32(value)))
+  }
+  
+  public func write(_ value: Int32) throws {
+    try writeVarint32(i32ToZigZag(value))
+  }
+  
+  public func write(_ value: Int64) throws {
+    try writeVarint64(i64ToZigZag(value))
+  }
+  
+  public func write(_ value: Double) throws {
+    var bits = CFSwapInt64HostToLittle(value.bitPattern)
+    let data = withUnsafePointer(to: &bits) {
+      return Data(bytes: UnsafePointer<UInt8>(OpaquePointer($0)), count: MemoryLayout<UInt64>.size)
+    }
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) {
+      try self.transport.write(data: data)
+    }
+  }
+  
+  public func write(_ data: Data) throws {
+    try writeVarint32(UInt32(data.count))
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Write Failed")) {
+      try self.transport.write(data: data)
+    }
+  }
+}
diff --git a/lib/swift/Sources/TEnum.swift b/lib/swift/Sources/TEnum.swift
new file mode 100644
index 0000000..fedfdb1
--- /dev/null
+++ b/lib/swift/Sources/TEnum.swift
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+
+public protocol TEnum : TSerializable, Hashable {
+  var rawValue: Int32 { get }
+}
+
+extension TEnum {
+  public static var thriftType: TType { return .i32 }
+  public var hashValue: Int { return rawValue.hashValue }
+
+  public func write(to proto: TProtocol) throws {
+    try proto.write(rawValue)
+  }
+}
diff --git a/lib/swift/Sources/TError.swift b/lib/swift/Sources/TError.swift
new file mode 100644
index 0000000..79edba6
--- /dev/null
+++ b/lib/swift/Sources/TError.swift
@@ -0,0 +1,77 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+
+/// TErrorCode
+///
+/// Protocol for TError conformers' enum's to conform to.
+/// Generic Int Thrift error code to allow error cases to have
+/// associated values.
+public protocol TErrorCode : CustomStringConvertible {
+  var thriftErrorCode: Int { get }
+}
+
+/// TError
+///
+/// Base protocol for all Thrift Error(Exception) types to conform to
+public protocol TError : Error, CustomStringConvertible {
+
+  /// Enum for error cases.  Can be typealiased to any conforming enum
+  /// or defined nested.
+  associatedtype Code: TErrorCode
+  
+  /// Error Case, value from internal enum
+  var error: Code { get set }
+  
+  /// Optional additional message
+  var message: String? { get set }
+  
+  /// Default error case for the error type, used for generic init()
+  static var defaultCase: Code { get }
+  
+  init()
+}
+
+extension TError {
+  /// Human readable description of error. Default provided for you in the
+  /// format \(Self.self): \(error.errorDescription) \n message
+  /// eg:
+  ///
+  ///     TApplicationError (1): Invalid Message Type
+  ///     An unknown Error has occured.
+  public var description: String {
+    var out = "\(Self.self) (\(error.thriftErrorCode)): " + error.description + "\n"
+    if let message = message {
+      out += "Message: \(message)"
+    }
+    return out
+  }
+
+  /// Simple default Initializer for TError's
+  ///
+  /// - parameter error:   ErrorCode value.  Default: defaultCase
+  /// - parameter message: Custom message with error.  Optional
+  ///
+  /// - returns: <#return value description#>
+  public init(error: Code, message: String? = nil) {
+    self.init()
+    self.error = error
+    self.message = message
+  }
+}
diff --git a/lib/swift/Sources/TFileHandleTransport.swift b/lib/swift/Sources/TFileHandleTransport.swift
new file mode 100644
index 0000000..f315fef
--- /dev/null
+++ b/lib/swift/Sources/TFileHandleTransport.swift
@@ -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.
+*/
+
+import Foundation
+
+public class TFileHandleTransport: TTransport {
+  var inputFileHandle: FileHandle
+  var outputFileHandle: FileHandle
+  
+  public init(inputFileHandle: FileHandle, outputFileHandle: FileHandle) {
+    self.inputFileHandle = inputFileHandle
+    self.outputFileHandle = outputFileHandle
+  }
+  
+  public convenience init(fileHandle: FileHandle) {
+    self.init(inputFileHandle: fileHandle, outputFileHandle: fileHandle)
+  }
+  
+  public func read(size: Int) throws -> Data {
+    var data = Data()
+    while data.count < size {
+      let read = inputFileHandle.readData(ofLength: size - data.count)
+      data.append(read)
+      if read.count == 0 {
+        break
+      }
+    }
+    return data
+  }
+  
+  public func write(data: Data) throws {
+    outputFileHandle.write(data)
+  }
+  
+  public func flush() throws {
+    return
+  }
+}
+
+
diff --git a/lib/swift/Sources/TFileTransport.swift b/lib/swift/Sources/TFileTransport.swift
new file mode 100644
index 0000000..fe2253d
--- /dev/null
+++ b/lib/swift/Sources/TFileTransport.swift
@@ -0,0 +1,101 @@
+/*
+* 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 Foundation
+
+#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+  import Darwin
+#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android)
+  import Glibc
+#endif
+
+/// TFileTransport
+/// Foundation-less Swift File transport.
+/// Uses C fopen/fread/fwrite,
+/// provided by Glibc in linux and Darwin on OSX/iOS
+public class TFileTransport: TTransport {
+  var fileHandle: UnsafeMutablePointer<FILE>? = nil
+  
+  public init (fileHandle: UnsafeMutablePointer<FILE>) {
+    self.fileHandle = fileHandle
+  }
+
+  public convenience init(filename: String) throws {
+    var fileHandle: UnsafeMutablePointer<FILE>?
+    filename.withCString({ cFilename in
+      "rw".withCString({ cMode in
+        fileHandle = fopen(cFilename, cMode)
+      })
+    })
+    if let fileHandle = fileHandle {
+      self.init(fileHandle: fileHandle)
+    } else {
+      throw TTransportError(error: .notOpen)
+    }
+  }
+  
+  deinit {
+    fclose(self.fileHandle)
+  }
+  
+  public func readAll(size: Int) throws -> Data {
+    let read = try self.read(size: size)
+    
+    if read.count != size {
+      throw TTransportError(error: .endOfFile)
+    }
+    return read
+  }
+  
+  public func read(size: Int) throws -> Data {
+    // set up read buffer, position 0
+    var read = Data(capacity: size)
+    var position = 0
+    
+    // read character buffer
+    var nextChar: UInt8 = 0
+    
+    // continue until we've read size bytes
+    while read.count < size {
+      if fread(&nextChar, 1, 1, self.fileHandle) == 1 {
+        read[position] = nextChar
+
+        // Increment output byte pointer
+        position += 1
+        
+      } else {
+        throw TTransportError(error: .endOfFile)
+      }
+    }
+    return read
+  }
+  
+  public func write(data: Data) throws {
+    let bytesWritten = data.withUnsafeBytes {
+      fwrite($0, 1, data.count, self.fileHandle)
+    }
+    if bytesWritten != data.count {
+      throw TTransportError(error: .unknown)
+    }
+  }
+  
+  public func flush() throws {
+    return
+  }
+}
diff --git a/lib/swift/Sources/TFramedTransport.swift b/lib/swift/Sources/TFramedTransport.swift
new file mode 100644
index 0000000..ca385d6
--- /dev/null
+++ b/lib/swift/Sources/TFramedTransport.swift
@@ -0,0 +1,123 @@
+/*
+* 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 Foundation
+
+public class TFramedTransport: TTransport {
+  public static let headerSize    = 4
+  public static let initFrameSize = 1024
+  private static let defaultMaxLength = 16384000
+
+  public var transport: TTransport
+  private var writeBuffer = Data()
+
+  private var maxSize     = TFramedTransport.defaultMaxLength
+  private var remainingBytes = 0
+
+
+  public init(transport: TTransport, maxSize: Int) {
+    self.transport = transport
+    self.maxSize = maxSize
+  }
+
+  public convenience init(transport: TTransport) {
+    self.init(transport: transport, maxSize: TFramedTransport.defaultMaxLength)
+  }
+
+  func readHeader() throws {
+    let read = try transport.readAll(size: TFramedTransport.headerSize)
+    remainingBytes = Int(decodeFrameSize(data: read))
+  }
+
+  /// Mark: - TTransport
+
+  public func read(size: Int) throws -> Data {
+    while (remainingBytes <= 0) {
+        try readHeader()
+    }
+
+    let toRead = min(size, remainingBytes)
+
+    if toRead < 0 {
+        try close()
+        throw TTransportError(error: .negativeSize,
+                              message:  "Read a negative frame size (\(toRead))!")
+    }
+
+    if toRead > maxSize {
+        try close()
+        throw TTransportError(error: .sizeLimit(limit: maxSize, got: toRead))
+    }
+
+    return try transport.readAll(size: toRead)
+  }
+
+  public func flush() throws {
+    // copy buffer and reset
+    let buff = writeBuffer
+    writeBuffer = Data()
+
+    if buff.count - TFramedTransport.headerSize < 0 {
+      throw TTransportError(error: .unknown)
+    }
+
+    let frameSize = encodeFrameSize(size: UInt32(buff.count))
+
+    try transport.write(data: frameSize)
+    try transport.write(data: buff)
+    try transport.flush()
+  }
+
+  public func write(data: Data) throws {
+    writeBuffer.append(data)
+  }
+
+
+
+  private func encodeFrameSize(size: UInt32) -> Data {
+    var data = Data()
+    data.append(Data(bytes: [UInt8(0xff & (size >> 24))]))
+    data.append(Data(bytes: [UInt8(0xff & (size >> 16))]))
+    data.append(Data(bytes: [UInt8(0xff & (size >> 8))]))
+    data.append(Data(bytes: [UInt8(0xff & (size))]))
+
+    return data
+  }
+
+  private func decodeFrameSize(data: Data) -> UInt32 {
+    var size: UInt32
+    size  = (UInt32(data[0] & 0xff) << 24)
+    size |= (UInt32(data[1] & 0xff) << 16)
+    size |= (UInt32(data[2] & 0xff) <<  8)
+    size |= (UInt32(data[3] & 0xff))
+    return size
+  }
+
+  public func close() throws {
+    try transport.close()
+  }
+
+  public func open() throws {
+    try transport.open()
+  }
+
+  public func isOpen() throws -> Bool {
+    return try transport.isOpen()
+  }
+}
diff --git a/lib/swift/Sources/THTTPSessionTransport.swift b/lib/swift/Sources/THTTPSessionTransport.swift
new file mode 100644
index 0000000..3c0af8e
--- /dev/null
+++ b/lib/swift/Sources/THTTPSessionTransport.swift
@@ -0,0 +1,184 @@
+/*
+* 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 Foundation
+import Dispatch
+
+
+public class THTTPSessionTransport: TAsyncTransport {
+  public class Factory : TAsyncTransportFactory {
+    public var responseValidate: ((HTTPURLResponse?, Data?) throws -> Void)?
+    
+    var session: URLSession
+    var url: URL
+    
+    public class func setupDefaultsForSessionConfiguration(_ config: URLSessionConfiguration, withProtocolName protocolName: String?) {
+      var thriftContentType = "application/x-thrift"
+      
+      if let protocolName = protocolName {
+        thriftContentType += "; p=\(protocolName)"
+      }
+      
+      config.requestCachePolicy = .reloadIgnoringLocalCacheData
+      config.urlCache = nil
+      
+      config.httpShouldUsePipelining  = true
+      config.httpShouldSetCookies     = true
+      config.httpAdditionalHeaders    = ["Content-Type": thriftContentType,
+                                         "Accept": thriftContentType,
+                                         "User-Agent": "Thrift/Swift (Session)"]
+      
+      
+    }
+    
+    public init(session: URLSession, url: URL) {
+      self.session = session
+      self.url = url
+    }
+    
+    public func newTransport() -> THTTPSessionTransport {
+      return THTTPSessionTransport(factory: self)
+    }
+    
+    func validateResponse(_ response: HTTPURLResponse?, data: Data?) throws {
+      try responseValidate?(response, data)
+    }
+    
+    func taskWithRequest(_ request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> ()) throws -> URLSessionTask {
+      
+      let newTask: URLSessionTask? = session.dataTask(with: request, completionHandler: completionHandler)
+      if let newTask = newTask {
+        return newTask
+      } else {
+        throw TTransportError(error: .unknown, message: "Failed to create session data task")
+      }
+    }    
+  }
+  
+  var factory: Factory
+  var requestData = Data()
+  var responseData = Data()
+  var responseDataOffset: Int = 0
+  
+  init(factory: Factory) {
+    self.factory = factory
+  }
+  
+  public func readAll(size: Int) throws -> Data {
+    let read = try self.read(size: size)
+    if read.count != size {
+      throw TTransportError(error: .endOfFile)
+    }
+    return read
+  }
+  
+  public func read(size: Int) throws -> Data {
+    let avail = responseData.count - responseDataOffset
+    let (start, stop) = (responseDataOffset, responseDataOffset + min(size, avail))
+    let read = responseData.subdata(in: start..<stop)
+    responseDataOffset += read.count
+    return read
+  }
+  
+  public func write(data: Data) throws {
+    requestData.append(data)
+  }
+  
+  public func flush(_ completed: @escaping (TAsyncTransport, Error?) -> Void) {
+    var error: Error?
+    var task: URLSessionTask?
+    
+    var request = URLRequest(url: factory.url)
+    request.httpMethod = "POST"
+    request.httpBody =  requestData
+
+    requestData = Data()
+
+    do {
+      task = try factory.taskWithRequest(request, completionHandler: { (data, response, taskError) in
+
+        // Check if there was an error with the network
+        if taskError != nil {
+            error = TTransportError(error: .timedOut)
+            completed(self, error)
+            return
+        }
+
+        // Check response type
+        if taskError == nil && !(response is HTTPURLResponse) {
+            error = THTTPTransportError(error: .invalidResponse)
+            completed(self, error)
+            return
+        }
+        
+        // Check status code
+        if let httpResponse = response as? HTTPURLResponse {
+          if taskError == nil && httpResponse.statusCode != 200 {
+            if httpResponse.statusCode == 401 {
+              error = THTTPTransportError(error: .authentication)
+            } else {
+              error = THTTPTransportError(error: .invalidStatus(statusCode: httpResponse.statusCode))
+            }
+          }
+          
+          // Allow factory to check
+          if error != nil {
+            do {
+              try self.factory.validateResponse(httpResponse, data: data)
+            } catch let validateError {
+              error = validateError
+            }
+          }
+          
+          self.responseDataOffset = 0
+          if error != nil {
+            self.responseData = Data()
+          } else {
+            self.responseData = data ?? Data()
+          }
+          completed(self, error)
+        }
+      })
+      
+    } catch let taskError {
+      error = taskError
+    }
+    
+    if let error = error, task == nil {
+      completed(self, error)
+    }
+    task?.resume()
+  }
+
+  public func flush() throws {
+    let completed = DispatchSemaphore(value: 0)
+    var internalError: Error?
+    
+    flush() { _, error in
+      internalError = error
+      completed.signal()
+    }
+    
+    _ = completed.wait(timeout: DispatchTime.distantFuture)
+    
+    if let error = internalError {
+      throw error
+    }
+  }
+}
diff --git a/lib/swift/Sources/TList.swift b/lib/swift/Sources/TList.swift
new file mode 100644
index 0000000..c239d10
--- /dev/null
+++ b/lib/swift/Sources/TList.swift
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+public struct TList<Element : TSerializable> : RandomAccessCollection, MutableCollection, ExpressibleByArrayLiteral, TSerializable, Hashable {
+  public typealias Storage = Array<Element>
+  public typealias Indices = Storage.Indices
+
+  internal var storage = Storage()
+  public init() { }
+  public init(arrayLiteral elements: Element...) {
+    self.storage = Storage(elements)
+  }
+  public init<Source : Sequence>(_ sequence: Source) where Source.Iterator.Element == Element {
+    storage = Storage(sequence)
+  }
+
+  /// Mark: Hashable
+  public var hashValue : Int {
+    let prime = 31
+    var result = 1
+    for element in storage {
+      result = prime &* result &+ element.hashValue
+    }
+    return result
+  }
+  
+  /// Mark: TSerializable
+  public static var thriftType : TType { return .list }
+
+  public static func read(from proto: TProtocol) throws -> TList {
+    let (elementType, size) = try proto.readListBegin()
+    if elementType != Element.thriftType {
+      throw TProtocolError(error: .invalidData,
+                           extendedError: .unexpectedType(type: elementType))
+    }
+    var list = TList()
+    for _ in 0..<size {
+      let element = try Element.read(from: proto)
+      list.storage.append(element)
+    }
+    try proto.readListEnd()
+    return list
+  }
+  
+  public func write(to proto: TProtocol) throws {
+    try proto.writeListBegin(elementType: Element.thriftType, size: Int32(self.count))
+    for element in self.storage {
+      try Element.write(element, to: proto)
+    }
+    try proto.writeListEnd()
+  }
+
+  /// Mark: MutableCollection
+  
+  public typealias SubSequence = Storage.SubSequence
+  public typealias Index = Storage.Index
+  
+  public subscript(position: Storage.Index) -> Element {
+    get {
+      return storage[position]
+    }
+    set {
+      storage[position] = newValue
+    }
+  }
+  
+  public subscript(range: Range<Index>) -> SubSequence {
+    get {
+      return storage[range]
+    }
+    set {
+      storage[range] = newValue
+    }
+  }
+  
+  public var startIndex: Index {
+    return storage.startIndex
+  }
+  public var endIndex: Index {
+    return storage.endIndex
+  }
+  
+  public func formIndex(after i: inout Index) {
+    storage.formIndex(after: &i)
+  }
+  
+  public func formIndex(before i: inout Int) {
+    storage.formIndex(before: &i)
+  }
+  
+  public func index(after i: Index) -> Index {
+    return storage.index(after: i)
+  }
+
+  public func index(before i: Int) -> Int {
+    return storage.index(before: i)
+  }
+
+}
+
+extension TList : RangeReplaceableCollection {
+  public mutating func replaceSubrange<C: Collection>(_ subrange: Range<Index>, with newElements: C)
+    where C.Iterator.Element == Element {
+    storage.replaceSubrange(subrange, with: newElements)
+  }
+}
+
+extension TList : CustomStringConvertible, CustomDebugStringConvertible {
+  
+  public var description : String {
+    return storage.description
+  }
+  
+  public var debugDescription : String {
+    return storage.debugDescription
+  }
+  
+}
+
+public func ==<Element>(lhs: TList<Element>, rhs: TList<Element>) -> Bool {
+  return lhs.storage.elementsEqual(rhs.storage) { $0 == $1 }
+}
diff --git a/lib/swift/Sources/TMap.swift b/lib/swift/Sources/TMap.swift
new file mode 100644
index 0000000..8980377
--- /dev/null
+++ b/lib/swift/Sources/TMap.swift
@@ -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.
+ */
+
+public struct TMap<Key : TSerializable & Hashable, Value : TSerializable>: Collection, ExpressibleByDictionaryLiteral, Hashable, TSerializable {
+  public typealias Storage = Dictionary<Key, Value>
+  public typealias Element = Storage.Element
+  public typealias Index = Storage.Index
+  public typealias IndexDistance = Storage.IndexDistance
+  public typealias Indices = Storage.Indices
+  public typealias SubSequence = Storage.SubSequence
+  internal var storage = Storage()
+  
+  /// Mark: Be Like Dictionary
+  
+  public func indexForKey(_ key: Key) -> Index? {
+    return storage.index(forKey: key)
+  }
+  
+  public mutating func updateValue(_ value: Value, forKey key: Key) -> Value? {
+    return updateValue(value, forKey: key)
+  }
+  
+  public mutating func removeAtIndex(_ index: DictionaryIndex<Key, Value>) -> (Key, Value) {
+    return removeAtIndex(index)
+  }
+  
+  public mutating func removeValueForKey(_ key: Key) -> Value? {
+    return storage.removeValue(forKey: key)
+  }
+  
+  public init(minimumCapacity: Int) {
+    storage = Storage(minimumCapacity: minimumCapacity)
+  }
+  
+  /// init from Dictionary<K,V>
+  public init(_ dict: [Key: Value]) {
+    storage = dict
+  }
+
+  /// read only access to storage if needed as Dictionary<K,V>
+  public var dictionary: [Key: Value] {
+    return storage
+  }
+  
+  public subscript (key: Key) -> Value? {
+    get {
+      return storage[key]
+    }
+    set {
+      storage[key] = newValue
+    }
+  }
+  
+  /// Mark: Collection
+  
+  public var indices: Indices {
+    return storage.indices
+  }
+  
+  public func distance(from start: Index, to end: Index) -> IndexDistance {
+    return storage.distance(from: start, to: end)
+  }
+  
+  public func index(_ i: Index, offsetBy n: IndexDistance) -> Index {
+    return storage.index(i, offsetBy: n)
+  }
+  
+  public func index(_ i: Index, offsetBy n: IndexDistance, limitedBy limit: Index) -> Index? {
+    return storage.index(i, offsetBy: n, limitedBy: limit)
+  }
+  
+  public subscript(position: Index) -> Element {
+    return storage[position]
+  }
+  
+  /// Mark: IndexableBase
+  
+  public var startIndex: Index { return storage.startIndex }
+  public var endIndex: Index { return storage.endIndex }
+  public func index(after i: Index) -> Index {
+    return storage.index(after: i)
+  }
+  
+  public func formIndex(after i: inout Index) {
+    storage.formIndex(after: &i)
+  }
+  
+  public subscript(bounds: Range<Index>) -> SubSequence {
+    return storage[bounds]
+  }
+  
+  /// Mark: DictionaryLiteralConvertible
+  
+  public init(dictionaryLiteral elements: (Key, Value)...) {
+    storage = Storage()
+    for (key, value) in elements {
+      storage[key] = value
+    }
+  }
+
+  /// Mark: Hashable
+  
+  public var hashValue: Int {
+    let prime = 31
+    var result = 1
+    for (key, value) in storage {
+      result = prime &* result &+ key.hashValue
+      result = prime &* result &+ value.hashValue
+    }
+    return result
+  }
+  
+  /// Mark: TSerializable
+  
+  public static var thriftType : TType { return .map }
+  public init() {
+    storage = Storage()
+  }
+   
+  public static func read(from proto: TProtocol) throws -> TMap {
+
+    let (keyType, valueType, size) = try proto.readMapBegin()
+    if size > 0 {
+      if keyType != Key.thriftType {
+        throw TProtocolError(error: .invalidData,
+                             message: "Unexpected TMap Key Type",
+                             extendedError: .unexpectedType(type: keyType))
+      }
+      if valueType != Value.thriftType {
+        throw TProtocolError(error: .invalidData,
+                             message: "Unexpected TMap Value Type",
+                             extendedError: .unexpectedType(type: valueType))
+      }
+    }
+
+    var map = TMap()
+    for _ in 0..<size {
+      let key = try Key.read(from: proto)
+      let value = try Value.read(from: proto)
+      map.storage[key] = value
+    }
+    try proto.readMapEnd()
+    return map
+  }
+  
+  public func write(to proto: TProtocol) throws {
+    try proto.writeMapBegin(keyType: Key.thriftType,
+                            valueType: Value.thriftType, size: Int32(self.count))
+    for (key, value) in self.storage {
+      try Key.write(key, to: proto)
+      try Value.write(value, to: proto)
+    }
+    try proto.writeMapEnd()
+  }
+}
+
+/// Mark: CustomStringConvertible, CustomDebugStringConvertible
+
+extension TMap : CustomStringConvertible, CustomDebugStringConvertible {
+  
+  public var description : String {
+    return storage.description
+  }
+  
+  public var debugDescription : String {
+    return storage.debugDescription
+  }
+  
+}
+
+/// Mark: Equatable
+
+public func ==<Key, Value>(lhs: TMap<Key,Value>, rhs: TMap<Key, Value>) -> Bool {
+  if lhs.count != rhs.count {
+    return false
+  }
+  return lhs.storage.elementsEqual(rhs.storage) { $0.key == $1.key && $0.value == $1.value }
+}
diff --git a/lib/swift/Sources/TMemoryBufferTransport.swift b/lib/swift/Sources/TMemoryBufferTransport.swift
new file mode 100644
index 0000000..bd58b6e
--- /dev/null
+++ b/lib/swift/Sources/TMemoryBufferTransport.swift
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Foundation
+
+public class TMemoryBufferTransport : TTransport {
+  public private(set) var readBuffer = Data()
+  public private(set) var writeBuffer = Data()
+  
+  public private(set) var position = 0
+
+  public var bytesRemainingInBuffer: Int {
+    return readBuffer.count - position
+  }
+  
+  public func consumeBuffer(size: Int) {
+    position += size
+  }
+  public func clear() {
+    readBuffer = Data()
+    writeBuffer = Data()
+  }
+  
+  
+  private var flushHandler: ((TMemoryBufferTransport, Data) -> ())?
+  
+  public init(flushHandler: ((TMemoryBufferTransport, Data) -> ())? = nil) {
+    self.flushHandler = flushHandler
+  }
+  
+  public convenience init(readBuffer: Data, flushHandler: ((TMemoryBufferTransport, Data) -> ())? = nil) {
+    self.init()
+    self.readBuffer = readBuffer
+  }
+  
+  public func reset(readBuffer: Data = Data(), writeBuffer: Data = Data()) {
+    self.readBuffer = readBuffer
+    self.writeBuffer = writeBuffer
+  }
+  
+  public func read(size: Int) throws -> Data {
+    let amountToRead = min(bytesRemainingInBuffer, size)
+    if amountToRead > 0 {
+      let ret = readBuffer.subdata(in: Range(uncheckedBounds: (lower: position, upper: position + amountToRead)))
+      position += ret.count
+      return ret
+    }
+    return Data()
+  }
+  
+  public func write(data: Data) throws {
+    writeBuffer.append(data)
+  }
+  
+  public func flush() throws {
+    flushHandler?(self, writeBuffer)
+  }
+}
diff --git a/lib/swift/Sources/TMultiplexedProtocol.swift b/lib/swift/Sources/TMultiplexedProtocol.swift
new file mode 100644
index 0000000..73a8d51
--- /dev/null
+++ b/lib/swift/Sources/TMultiplexedProtocol.swift
@@ -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.
+*/
+
+public class TMultiplexedProtocol<Protocol: TProtocol>: TWrappedProtocol<Protocol> {
+  public let separator = ":"
+
+  public var serviceName = ""
+  
+  public convenience init(on transport: TTransport, serviceName: String) {
+    self.init(on: transport)
+    self.serviceName = serviceName    
+  }
+
+  override public func writeMessageBegin(name: String,
+                                         type messageType: TMessageType,
+                                         sequenceID: Int32) throws {
+    switch messageType {
+    case .call, .oneway:
+      var serviceFunction = serviceName
+      serviceFunction += serviceName == "" ? "" : separator
+      serviceFunction += name
+      return try super.writeMessageBegin(name: serviceFunction,
+                                         type: messageType,
+                                         sequenceID: sequenceID)
+    default:
+      return try super.writeMessageBegin(name: name,
+                                         type: messageType,
+                                         sequenceID: sequenceID)
+    }
+  }
+}
diff --git a/lib/swift/Sources/TProcessor.swift b/lib/swift/Sources/TProcessor.swift
new file mode 100644
index 0000000..7ff222e
--- /dev/null
+++ b/lib/swift/Sources/TProcessor.swift
@@ -0,0 +1,29 @@
+/*
+* 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.
+*/
+
+
+public typealias TProcessorMessageHandler<T> = (Int, TProtocol, TProtocol, T) -> Void
+
+public protocol TProcessor {
+  associatedtype Service
+  var service: Service { get set }
+  func process(on inProtocol: TProtocol, outProtocol: TProtocol) throws
+  init(service: Service)
+}
+
diff --git a/lib/swift/Sources/TProtocol.swift b/lib/swift/Sources/TProtocol.swift
new file mode 100644
index 0000000..a4e4a20
--- /dev/null
+++ b/lib/swift/Sources/TProtocol.swift
@@ -0,0 +1,182 @@
+/*
+* 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 Foundation
+//
+
+public enum TMessageType: Int32 {
+  case call = 1
+  case reply = 2
+  case exception = 3
+  case oneway = 4
+}
+
+public enum TType: Int32 {
+  case stop     = 0
+  case void     = 1
+  case bool     = 2
+  case i8       = 3
+  case double   = 4
+  case i16      = 6
+  case i32      = 8
+  case i64      = 10
+  case string   = 11
+  case `struct` = 12
+  case map      = 13
+  case set      = 14
+  case list     = 15
+  case utf8     = 16
+  case utf16    = 17
+}
+
+public protocol TProtocol {
+  var transport: TTransport { get set }
+  init(on transport: TTransport)
+  // Reading Methods
+  
+  func readMessageBegin() throws -> (String, TMessageType, Int32)
+  func readMessageEnd() throws
+  func readStructBegin() throws -> String
+  func readStructEnd() throws
+  func readFieldBegin() throws -> (String, TType, Int32)
+  func readFieldEnd() throws
+  func readMapBegin() throws -> (TType, TType, Int32)
+  func readMapEnd() throws
+  func readSetBegin() throws -> (TType, Int32)
+  func readSetEnd() throws
+  func readListBegin() throws -> (TType, Int32)
+  func readListEnd() throws
+  
+  func read() throws -> String
+  func read() throws -> Bool
+  func read() throws -> UInt8
+  func read() throws -> Int16
+  func read() throws -> Int32
+  func read() throws -> Int64
+  func read() throws -> Double
+  func read() throws -> Data
+  
+  // Writing methods
+  
+  func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws
+  func writeMessageEnd() throws
+  func writeStructBegin(name: String) throws
+  func writeStructEnd() throws
+  func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws
+  func writeFieldStop() throws
+  func writeFieldEnd() throws
+  func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws
+  func writeMapEnd() throws
+  func writeSetBegin(elementType: TType, size: Int32) throws
+  func writeSetEnd() throws
+  func writeListBegin(elementType: TType, size: Int32) throws
+  func writeListEnd() throws
+
+  func write(_ value: String) throws
+  func write(_ value: Bool) throws
+  func write(_ value: UInt8) throws
+  func write(_ value: Int16) throws
+  func write(_ value: Int32) throws
+  func write(_ value: Int64) throws
+  func write(_ value: Double) throws
+  func write(_ value: Data) throws
+}
+
+public extension TProtocol {
+  public func writeFieldValue(_ value: TSerializable, name: String, type: TType, id: Int32) throws {
+    try writeFieldBegin(name: name, type: type, fieldID: id)
+    try value.write(to: self)
+    try writeFieldEnd()
+  }
+
+  public func validateValue(_ value: Any?, named name: String) throws {
+    if value == nil {
+      throw TProtocolError(error: .unknown, message: "Missing required value for field: \(name)")
+    }
+  }
+  
+  public func readResultMessageBegin() throws {
+    let (_, type, _) = try readMessageBegin();
+    if type == .exception {
+      let x = try readException()
+      throw x
+    }
+    return
+  }
+  
+  public func readException() throws -> TApplicationError {
+    return try TApplicationError.read(from: self)
+  }
+  
+  public func writeException(messageName name: String, sequenceID: Int32, ex: TApplicationError) throws {
+    try writeMessageBegin(name: name, type: .exception, sequenceID: sequenceID)
+    try ex.write(to: self)
+    try writeMessageEnd()
+  }
+  
+  public func skip(type: TType) throws {
+    switch type {
+    case .bool:   _ = try read() as Bool
+    case .i8:   _ = try read() as UInt8
+    case .i16:    _ = try read() as Int16
+    case .i32:    _ = try read() as Int32
+    case .i64:    _ = try read() as Int64
+    case .double: _ = try read() as Double
+    case .string: _ = try read() as String
+      
+    case .struct:
+      _ = try readStructBegin()
+      while true {
+        let (_, fieldType, _) = try readFieldBegin()
+        if fieldType == .stop {
+          break
+        }
+        try skip(type: fieldType)
+        try readFieldEnd()
+      }
+      try readStructEnd()
+      
+      
+    case .map:
+      let (keyType, valueType, size) = try readMapBegin()
+      for _ in 0..<size {
+        try skip(type: keyType)
+        try skip(type: valueType)
+      }
+      try readMapEnd()
+      
+      
+    case .set:
+      let (elemType, size) = try readSetBegin()
+      for _ in 0..<size {
+        try skip(type: elemType)
+      }
+      try readSetEnd()
+      
+    case .list:
+      let (elemType, size) = try readListBegin()
+      for _ in 0..<size {
+        try skip(type: elemType)
+      }
+      try readListEnd()
+    default:
+      return
+    }
+  }
+}
diff --git a/lib/swift/Sources/TProtocolError.swift b/lib/swift/Sources/TProtocolError.swift
new file mode 100644
index 0000000..a5d14f9
--- /dev/null
+++ b/lib/swift/Sources/TProtocolError.swift
@@ -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.
+*/
+
+import Foundation
+
+public struct TProtocolError : TError {
+  public init() { }
+
+  public enum Code : TErrorCode {
+    case unknown
+    case invalidData
+    case negativeSize
+    case sizeLimit(limit: Int, got: Int)
+    case badVersion(expected: String, got: String)
+    case notImplemented
+    case depthLimit
+
+    public var thriftErrorCode: Int {
+      switch self {
+      case .unknown:        return 0
+      case .invalidData:    return 1
+      case .negativeSize:   return 2
+      case .sizeLimit:      return 3
+      case .badVersion:     return 4
+      case .notImplemented: return 5
+      case .depthLimit:     return 6
+      }
+
+    }
+    public var description: String {
+      switch self {
+      case .unknown:        return "Unknown TProtocolError"
+      case .invalidData:    return "Invalid Data"
+      case .negativeSize:   return "Negative Size"
+      case .sizeLimit(let limit, let got):
+        return "Message exceeds size limit of \(limit) (received: \(got)"
+      case .badVersion(let expected, let got):
+        return "Bad Version. (Expected: \(expected), Got: \(got)"
+      case .notImplemented: return "Not Implemented"
+      case .depthLimit:     return "Depth Limit"
+      }
+    }
+  }
+
+  public enum ExtendedErrorCode : TErrorCode {
+    case unknown
+    case missingRequiredField(fieldName: String)
+    case unexpectedType(type: TType)
+    case mismatchedProtocol(expected: String, got: String)
+    public var thriftErrorCode: Int {
+      switch self {
+      case .unknown:              return 1000
+      case .missingRequiredField: return 1001
+      case .unexpectedType:       return 1002
+      case .mismatchedProtocol:   return 1003
+      }
+    }
+    public var description: String {
+      switch self {
+      case .unknown:                                    return "Unknown TProtocolExtendedError"
+      case .missingRequiredField(let fieldName):        return "Missing Required Field: \(fieldName)"
+      case .unexpectedType(let type):                   return "Unexpected Type \(type.self)"
+      case .mismatchedProtocol(let expected, let got):  return "Mismatched Protocol.  (Expected: \(expected), got \(got))"
+      }
+    }
+  }
+
+  public var extendedError: ExtendedErrorCode? = nil
+
+  public init(error: Code = .unknown,
+              message: String? = nil,
+              extendedError: ExtendedErrorCode? = nil) {
+    self.error = error
+    self.message = message
+    self.extendedError = extendedError
+  }
+
+  /// Mark: TError
+  public var error: Code = .unknown
+  public var message: String? = nil
+  public static var defaultCase: Code { return .unknown }
+
+  public var description: String {
+    var out = "\(TProtocolError.self):  (\(error.thriftErrorCode) \(error.description)\n"
+    if let extendedError = extendedError {
+      out += "TProtocolExtendedError (\(extendedError.thriftErrorCode)): \(extendedError.description)"
+    }
+    if let message = message {
+      out += "Message: \(message)"
+    }
+    return out
+  }
+}
+
+
+/// Wrapper for Transport errors in Protocols.  Inspired by Thrift-Cocoa PROTOCOL_TRANSPORT_ERROR
+/// macro.  Modified to be more Swift-y.  Catches any TError thrown within the block and
+/// rethrows a given TProtocolError, the original error's description is appended to the new
+/// TProtocolError's message.  sourceFile, sourceLine, sourceMethod are auto-populated and should
+/// be ignored when calling.
+///
+/// - parameter error:        TProtocolError to throw if the block throws
+/// - parameter sourceFile:   throwing file, autopopulated
+/// - parameter sourceLine:   throwing line, autopopulated
+/// - parameter sourceMethod: throwing method, autopopulated
+/// - parameter block:        throwing block
+///
+/// - throws: TProtocolError  Default is TProtocolError.ErrorCode.unknown.  Underlying
+///                           error's description appended to TProtocolError.message
+func ProtocolTransportTry(error: TProtocolError = TProtocolError(),
+                          sourceFile: String = #file,
+                          sourceLine: Int = #line,
+                          sourceMethod: String = #function,
+                          block: () throws -> ()) throws {
+  // Need mutable copy
+  var error = error
+  do {
+    try block()
+  } catch let err as TError {
+    var message = error.message ?? ""
+    message += "\nFile: \(sourceFile)\n"
+    message += "Line: \(sourceLine)\n"
+    message += "Method: \(sourceMethod)"
+    message += "\nOriginal Error:\n" + err.description
+    error.message = message
+    throw error
+  }
+}
+
+
diff --git a/lib/swift/Sources/TSSLSocketTransport.swift b/lib/swift/Sources/TSSLSocketTransport.swift
new file mode 100644
index 0000000..c2b5902
--- /dev/null
+++ b/lib/swift/Sources/TSSLSocketTransport.swift
@@ -0,0 +1,229 @@
+/*
+* 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 Foundation
+import CoreFoundation
+
+#if os(Linux)
+public class TSSLSocketTransport {
+  init(hostname: String, port: UInt16) {
+    // FIXME!
+    assert(false, "Security not available in Linux, TSSLSocketTransport Unavilable for now")
+  }
+}
+#else
+let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian
+let htons  = isLittleEndian ? _OSSwapInt16 : { $0 }
+let htonl  = isLittleEndian ? _OSSwapInt32 : { $0 }
+
+public class TSSLSocketTransport: TStreamTransport {
+  var sslHostname: String
+  var sd: Int32 = 0
+  
+  public init(hostname: String, port: UInt16) throws {
+    sslHostname = hostname
+    var readStream: Unmanaged<CFReadStream>?
+    var writeStream: Unmanaged<CFWriteStream>?
+    
+    /* create a socket structure */
+    var pin: sockaddr_in = sockaddr_in()
+    var hp: UnsafeMutablePointer<hostent>? = nil
+    for i in 0..<10 {
+      
+      hp = gethostbyname(hostname.cString(using: String.Encoding.utf8)!)
+      if hp == nil {
+        print("failed to resolve hostname \(hostname)")
+        herror("resolv")
+        if i == 9 {
+          super.init(inputStream: nil, outputStream: nil) // have to init before throwing
+          throw TSSLSocketTransportError(error: .hostanameResolution(hostname: hostname))
+        }
+        Thread.sleep(forTimeInterval: 0.2)
+      } else {
+        break
+      }
+    }
+    pin.sin_family  = UInt8(AF_INET)
+    pin.sin_addr    = in_addr(s_addr: UInt32((hp?.pointee.h_addr_list.pointee?.pointee)!)) // Is there a better way to get this???
+    pin.sin_port    = htons(port)
+    
+    /* create the socket */
+    sd = socket(Int32(AF_INET), Int32(SOCK_STREAM), Int32(IPPROTO_TCP))
+    if sd == -1 {
+      super.init(inputStream: nil, outputStream: nil) // have to init before throwing
+      throw TSSLSocketTransportError(error: .socketCreate(port: Int(port)))
+    }
+    
+    /* open a connection */
+    // need a non-self ref to sd, otherwise the j complains
+    let sd_local = sd
+    let connectResult = withUnsafePointer(to: &pin) {
+      connect(sd_local, UnsafePointer<sockaddr>(OpaquePointer($0)), socklen_t(MemoryLayout<sockaddr_in>.size))
+    }
+    if connectResult == -1 {
+      super.init(inputStream: nil, outputStream: nil) // have to init before throwing
+      throw TSSLSocketTransportError(error: .connect)
+    }
+    
+    CFStreamCreatePairWithSocket(kCFAllocatorDefault, sd, &readStream, &writeStream)
+    
+    CFReadStreamSetProperty(readStream?.takeRetainedValue(), .socketNativeHandle, kCFBooleanTrue)
+    CFWriteStreamSetProperty(writeStream?.takeRetainedValue(), .socketNativeHandle, kCFBooleanTrue)
+    
+    var inputStream: InputStream? = nil
+    var outputStream: OutputStream? = nil
+    if readStream != nil && writeStream != nil {
+      
+      CFReadStreamSetProperty(readStream?.takeRetainedValue(),
+                              .socketSecurityLevel,
+                              kCFStreamSocketSecurityLevelTLSv1)
+      
+      let settings: [String: Bool] = [kCFStreamSSLValidatesCertificateChain as String: true]
+      
+      CFReadStreamSetProperty(readStream?.takeRetainedValue(),
+                              .SSLSettings,
+                              settings as CFTypeRef!)
+      
+      CFWriteStreamSetProperty(writeStream?.takeRetainedValue(),
+                              .SSLSettings,
+                              settings as CFTypeRef!)
+      
+      inputStream = readStream!.takeRetainedValue()
+      inputStream?.schedule(in: .current, forMode: .defaultRunLoopMode)
+      inputStream?.open()
+      
+      outputStream = writeStream!.takeRetainedValue()
+      outputStream?.schedule(in: .current, forMode: .defaultRunLoopMode)
+      outputStream?.open()
+      
+      readStream?.release()
+      writeStream?.release()
+    }
+    
+    
+    super.init(inputStream: inputStream, outputStream: outputStream)
+    self.input?.delegate = self
+    self.output?.delegate = self
+  }
+  
+  func recoverFromTrustFailure(_ myTrust: SecTrust, lastTrustResult: SecTrustResultType) -> Bool {
+    let trustTime = SecTrustGetVerifyTime(myTrust)
+    let currentTime = CFAbsoluteTimeGetCurrent()
+    
+    let timeIncrement = 31536000 // from TSSLSocketTransport.m
+    let newTime = currentTime - Double(timeIncrement)
+    
+    if trustTime - newTime != 0 {
+      let newDate = CFDateCreate(nil, newTime)
+      SecTrustSetVerifyDate(myTrust, newDate!)
+      
+      var tr = lastTrustResult
+      let success = withUnsafeMutablePointer(to: &tr) { trPtr -> Bool in
+        if SecTrustEvaluate(myTrust, trPtr) != errSecSuccess {
+          return false
+        }
+        return true
+      }
+      if !success { return false }
+    }
+    if lastTrustResult == .proceed || lastTrustResult == .unspecified {
+        return false
+    }
+
+    print("TSSLSocketTransport: Unable to recover certificate trust failure")
+    return true
+  }
+  
+  public func isOpen() -> Bool {
+    return sd > 0
+  }
+}
+
+extension TSSLSocketTransport: StreamDelegate {
+  public func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
+    
+    switch eventCode {
+    case Stream.Event(): break
+    case Stream.Event.hasBytesAvailable: break
+    case Stream.Event.openCompleted: break
+    case Stream.Event.hasSpaceAvailable:
+      var proceed = false
+      var trustResult: SecTrustResultType = .invalid
+
+      var newPolicies: CFMutableArray?
+      
+      repeat {
+        let trust: SecTrust = aStream.property(forKey: .SSLPeerTrust) as! SecTrust
+        
+        // Add new policy to current list of policies
+        let policy = SecPolicyCreateSSL(false, sslHostname as CFString?)
+        var ppolicy = policy // mutable for pointer
+        let policies: UnsafeMutablePointer<CFArray?>? = nil
+        if SecTrustCopyPolicies(trust, policies!) != errSecSuccess {
+          break
+        }
+        withUnsafeMutablePointer(to: &ppolicy) { ptr in
+          newPolicies = CFArrayCreateMutableCopy(nil, 0, policies?.pointee)
+          CFArrayAppendValue(newPolicies, ptr)
+        }
+        
+        // update trust policies
+        if SecTrustSetPolicies(trust, newPolicies!) != errSecSuccess {
+          break
+        }
+        
+        // Evaluate the trust chain
+        let success = withUnsafeMutablePointer(to: &trustResult) { trustPtr -> Bool in
+          if SecTrustEvaluate(trust, trustPtr) != errSecSuccess {
+            return false
+          }
+          return true
+        }
+        
+        if !success {
+          break
+        }
+        
+        
+        switch trustResult {
+        case .proceed:      proceed = true
+        case .unspecified:  proceed = true
+        case .recoverableTrustFailure:
+          proceed = self.recoverFromTrustFailure(trust, lastTrustResult: trustResult)
+          
+        case .deny:         break
+        case .fatalTrustFailure: break
+        case .otherError:   break
+        case .invalid:      break
+        default: break
+        }
+      } while false
+  
+      if !proceed {
+        print("TSSLSocketTransport: Cannot trust certificate.  Result: \(trustResult)")
+        aStream.close()
+      }
+      
+    case Stream.Event.errorOccurred: break
+    case Stream.Event.endEncountered: break
+    default: break
+    }
+  }
+}
+#endif
diff --git a/lib/swift/Sources/TSSLSocketTransportError.swift b/lib/swift/Sources/TSSLSocketTransportError.swift
new file mode 100644
index 0000000..fda162b
--- /dev/null
+++ b/lib/swift/Sources/TSSLSocketTransportError.swift
@@ -0,0 +1,48 @@
+/*
+* 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.
+*/
+
+public struct TSSLSocketTransportError: TError {
+  public enum ErrorCode: TErrorCode {
+    case hostanameResolution(hostname: String)
+    case socketCreate(port: Int)
+    case connect
+  
+    public var thriftErrorCode: Int {
+      switch self {
+      case .hostanameResolution:  return -10000
+      case .socketCreate:         return -10001
+      case .connect:              return -10002
+      }
+    }
+  
+    public var description: String {
+      switch self {
+      case .hostanameResolution(let hostname):  return "Failed to resolve hostname: \(hostname)"
+      case .socketCreate(let port):             return "Could not create socket on port: \(port)"
+      case .connect:                            return "Connect error"
+      }
+    }
+  
+  }
+  public var error: ErrorCode = .connect
+  public var message: String?
+  public static var defaultCase: ErrorCode { return .connect }
+  
+  public init() { }
+}
diff --git a/lib/swift/Sources/TSerializable.swift b/lib/swift/Sources/TSerializable.swift
new file mode 100644
index 0000000..b45096b
--- /dev/null
+++ b/lib/swift/Sources/TSerializable.swift
@@ -0,0 +1,136 @@
+/*
+ * 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 Foundation
+
+
+public protocol TSerializable {
+  var hashValue: Int { get }
+
+  /// TType for instance
+  static var thriftType: TType { get }
+
+  /// Read TSerializable instance from Protocol
+  static func read(from proto: TProtocol) throws -> Self
+
+  /// Write TSerializable instance to Protocol
+  func write(to proto: TProtocol) throws
+
+}
+
+extension TSerializable {
+  public static func write(_ value: Self, to proto: TProtocol) throws {
+    try value.write(to: proto)
+  }
+
+  /// convenience for member access
+  public var thriftType: TType { return Self.thriftType }
+}
+
+public func ==<T>(lhs: T, rhs: T) -> Bool where T : TSerializable {
+  return lhs.hashValue == rhs.hashValue
+}
+
+/// Default read/write for primitave Thrift types:
+/// Bool, Int8 (byte), Int16, Int32, Int64, Double, String
+
+extension Bool : TSerializable {
+  public static var thriftType: TType { return .bool }
+
+  public static func read(from proto: TProtocol) throws -> Bool {
+    return try proto.read()
+  }
+
+  public func write(to proto: TProtocol) throws {
+    try proto.write(self)
+  }
+}
+
+extension Int8 : TSerializable {
+  public static var thriftType: TType { return .i8 }
+
+  public static func read(from proto: TProtocol) throws -> Int8 {
+    return Int8(try proto.read() as UInt8)
+  }
+
+  public func write(to proto: TProtocol) throws {
+    try proto.write(UInt8(self))
+  }
+}
+
+extension Int16 : TSerializable {
+  public static var thriftType: TType { return .i16 }
+
+  public static func read(from proto: TProtocol) throws -> Int16 {
+    return try proto.read()
+  }
+
+  public func write(to proto: TProtocol) throws {
+    try proto.write(self)
+  }
+}
+
+extension Int32 : TSerializable {
+  public static var thriftType: TType { return .i32 }
+
+  public static func read(from proto: TProtocol) throws -> Int32 {
+    return try proto.read()
+  }
+
+  public func write(to proto: TProtocol) throws {
+    try proto.write(self)
+  }
+}
+
+
+extension Int64 : TSerializable {
+  public static var thriftType: TType { return .i64 }
+
+  public static func read(from proto: TProtocol) throws -> Int64 {
+    return try proto.read()
+  }
+
+  public func write(to proto: TProtocol) throws {
+    try proto.write(self)
+  }
+}
+
+extension Double : TSerializable {
+  public static var thriftType: TType { return .double }
+
+  public static func read(from proto: TProtocol) throws -> Double {
+    return try proto.read()
+  }
+
+  public func write(to proto: TProtocol) throws {
+    try proto.write(self)
+  }
+}
+
+extension String : TSerializable {
+  public static var thriftType: TType { return .string }
+
+  public static func read(from proto: TProtocol) throws -> String {
+    return try proto.read()
+  }
+
+  public func write(to proto: TProtocol) throws {
+    try proto.write(self)
+  }
+}
diff --git a/lib/swift/Sources/TSet.swift b/lib/swift/Sources/TSet.swift
new file mode 100644
index 0000000..1ecd170
--- /dev/null
+++ b/lib/swift/Sources/TSet.swift
@@ -0,0 +1,189 @@
+/*
+ * 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 Foundation
+
+public struct TSet<Element : TSerializable & Hashable> : SetAlgebra, Hashable, Collection, ExpressibleByArrayLiteral, TSerializable {
+  /// Typealias for Storage type
+  public typealias Storage = Set<Element>
+  
+  
+  /// Internal Storage used for TSet (Set\<Element\>)
+  internal var storage : Storage
+  
+  
+  /// Mark: Collection
+  
+  public typealias Indices = Storage.Indices
+  public typealias Index = Storage.Index
+  public typealias IndexDistance = Storage.IndexDistance
+  public typealias SubSequence = Storage.SubSequence
+  
+  
+  public var indices: Indices { return storage.indices }
+  
+  // Must implement isEmpty even though both SetAlgebra and Collection provide it due to their conflciting default implementations
+  public var isEmpty: Bool { return storage.isEmpty }
+  
+  public func distance(from start: Index, to end: Index) -> IndexDistance {
+    return storage.distance(from: start, to: end)
+  }
+  
+  public func index(_ i: Index, offsetBy n: IndexDistance) -> Index {
+    return storage.index(i, offsetBy: n)
+  }
+  
+  public func index(_ i: Index, offsetBy n: IndexDistance, limitedBy limit: Index) -> Index? {
+    return storage.index(i, offsetBy: n, limitedBy: limit)
+  }
+  
+  #if swift(>=3.2)
+  public subscript (position: Storage.Index) -> Element {
+      return storage[position]
+    }
+  #else
+  public subscript (position: Storage.Index) -> Element? {
+    return storage[position]
+  }
+  #endif
+  
+  /// Mark: SetAlgebra
+  internal init(storage: Set<Element>) {
+    self.storage = storage
+  }
+  
+  public func contains(_ member: Element) -> Bool {
+    return storage.contains(member)
+  }
+  
+  public mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element) {
+    return storage.insert(newMember)
+  }
+  
+  public mutating func remove(_ member: Element) -> Element? {
+    return storage.remove(member)
+  }
+  
+  public func union(_ other: TSet<Element>) -> TSet {
+    return TSet(storage: storage.union(other.storage))
+  }
+  
+  public mutating func formIntersection(_ other: TSet<Element>) {
+    return storage.formIntersection(other.storage)
+  }
+  
+  public mutating func formSymmetricDifference(_ other: TSet<Element>) {
+    return storage.formSymmetricDifference(other.storage)
+  }
+  
+  public mutating func formUnion(_ other: TSet<Element>) {
+    return storage.formUnion(other.storage)
+  }
+  
+  public func intersection(_ other: TSet<Element>) -> TSet {
+    return TSet(storage: storage.intersection(other.storage))
+  }
+  
+  public func symmetricDifference(_ other: TSet<Element>) -> TSet {
+    return TSet(storage: storage.symmetricDifference(other.storage))
+  }
+  
+  public mutating func update(with newMember: Element) -> Element? {
+    return storage.update(with: newMember)
+  }
+  
+  /// Mark: IndexableBase
+  
+  public var startIndex: Index { return storage.startIndex }
+  public var endIndex: Index { return storage.endIndex }
+  public func index(after i: Index) -> Index {
+    return storage.index(after: i)
+  }
+
+  public func formIndex(after i: inout Storage.Index) {
+    storage.formIndex(after: &i)
+  }
+  
+  public subscript(bounds: Range<Index>) -> SubSequence {
+    return storage[bounds]
+  }
+
+  
+  /// Mark: Hashable
+  public var hashValue : Int {
+    let prime = 31
+    var result = 1
+    for element in storage {
+      result = prime &* result &+ element.hashValue
+    }
+    return result
+  }
+  
+  /// Mark: TSerializable
+  public static var thriftType : TType { return .set }
+  
+  public init() {
+    storage = Storage()
+  }
+  
+  public init(arrayLiteral elements: Element...) {
+    self.storage = Storage(elements)
+  }
+  
+  public init<Source : Sequence>(_ sequence: Source) where Source.Iterator.Element == Element {
+    storage = Storage(sequence)
+  }
+  
+  public static func read(from proto: TProtocol) throws -> TSet {
+    let (elementType, size) = try proto.readSetBegin()
+    if elementType != Element.thriftType {
+      throw TProtocolError(error: .invalidData,
+                           extendedError: .unexpectedType(type: elementType))
+    }
+    var set = TSet()
+    for _ in 0..<size {
+      let element = try Element.read(from: proto)
+      set.storage.insert(element)
+    }
+    try proto.readSetEnd()
+    return set
+  }
+  
+  public func write(to proto: TProtocol) throws {
+    try proto.writeSetBegin(elementType: Element.thriftType, size: Int32(self.count))
+    for element in self.storage {
+      try Element.write(element, to: proto)
+    }
+    try proto.writeSetEnd()
+  }
+}
+
+extension TSet: CustomStringConvertible, CustomDebugStringConvertible {
+  public var description : String {
+    return storage.description
+  }
+  public var debugDescription : String {
+    return storage.debugDescription
+  }
+  
+}
+
+public func ==<Element>(lhs: TSet<Element>, rhs: TSet<Element>) -> Bool {
+  return lhs.storage == rhs.storage
+}
diff --git a/lib/swift/Sources/TSocketServer.swift b/lib/swift/Sources/TSocketServer.swift
new file mode 100644
index 0000000..0224e67
--- /dev/null
+++ b/lib/swift/Sources/TSocketServer.swift
@@ -0,0 +1,149 @@
+/*
+* 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.
+*/
+
+#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+  import Darwin
+#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android)
+  import Glibc
+  import Dispatch
+#endif
+
+import Foundation
+import CoreFoundation
+
+public let TSocketServerClientConnectionFinished = "TSocketServerClientConnectionFinished"
+public let TSocketServerProcessorKey = "TSocketServerProcessor"
+public let TSocketServerTransportKey = "TSocketServerTransport"
+
+class TSocketServer<InProtocol: TProtocol, OutProtocol: TProtocol, Processor: TProcessor, Service> where Processor.Service == Service {
+  var socketFileHandle: FileHandle
+  var processingQueue =  DispatchQueue(label: "TSocketServer.processing",
+                                       qos: .background,
+                                       attributes: .concurrent)
+  var serviceHandler: Service
+
+  public init(port: Int,
+              service: Service,
+              inProtocol: InProtocol.Type,
+              outProtocol: OutProtocol.Type,
+              processor: Processor.Type) throws {
+    // set service handler
+    self.serviceHandler = service
+
+    // create a socket
+    var fd: Int32 = -1
+    #if os(Linux)
+      let sock = CFSocketCreate(kCFAllocatorDefault, PF_INET, Int32(SOCK_STREAM.rawValue), Int32(IPPROTO_TCP), 0, nil, nil)
+    #else
+      let sock = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, 0, nil, nil)
+    #endif
+    if sock != nil {
+      CFSocketSetSocketFlags(sock, CFSocketGetSocketFlags(sock) & ~kCFSocketCloseOnInvalidate)
+
+      fd = CFSocketGetNative(sock)
+      var yes = 1
+      setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, UInt32(MemoryLayout<Int>.size))
+
+      #if os(Linux)
+        var addr = sockaddr_in(sin_family: sa_family_t(AF_INET),
+                               sin_port: in_port_t(port.bigEndian),
+                               sin_addr: in_addr(s_addr: in_addr_t(0)),
+                               sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
+      #else
+        var addr = sockaddr_in(sin_len: UInt8(MemoryLayout<sockaddr_in>.size),
+                               sin_family: sa_family_t(AF_INET),
+                               sin_port: in_port_t(port.bigEndian),
+                               sin_addr: in_addr(s_addr: in_addr_t(0)),
+                               sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
+      #endif
+
+      let ptr = withUnsafePointer(to: &addr) {
+        return UnsafePointer<UInt8>(OpaquePointer($0))
+      }
+
+      let address = Data(bytes: ptr, count: MemoryLayout<sockaddr_in>.size)
+
+      let cfaddr = address.withUnsafeBytes {
+        CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, $0, address.count, nil)
+      }
+      if CFSocketSetAddress(sock, cfaddr) != CFSocketError.success { //kCFSocketSuccess {
+        CFSocketInvalidate(sock)
+        print("TSocketServer: Could not bind to address")
+        throw TTransportError(error: .notOpen, message: "Could not bind to address")
+      }
+
+    } else {
+      print("TSocketServer: No server socket")
+      throw TTransportError(error: .notOpen, message: "Could not create socket")
+    }
+
+    // wrap it in a file handle so we can get messages from it
+    socketFileHandle = FileHandle(fileDescriptor: fd, closeOnDealloc: true)
+
+    // throw away our socket
+    CFSocketInvalidate(sock)
+
+    // register for notifications of accepted incoming connections
+    _ = NotificationCenter.default.addObserver(forName: .NSFileHandleConnectionAccepted,
+                                               object: nil, queue: nil) {
+                                                [weak self] notification in
+                                                guard let strongSelf = self else { return }
+                                                strongSelf.connectionAccepted(strongSelf.socketFileHandle)
+
+    }
+
+    // tell socket to listen
+    socketFileHandle.acceptConnectionInBackgroundAndNotify()
+
+    print("TSocketServer: Listening on TCP port \(port)")
+  }
+
+  deinit {
+    NotificationCenter.default.removeObserver(self)
+  }
+
+  func connectionAccepted(_ socket: FileHandle) {
+    // Now that we have a client connected, handle the request on queue
+    processingQueue.async {
+      self.handleClientConnection(socket)
+    }
+  }
+
+  func handleClientConnection(_ clientSocket: FileHandle) {
+
+    let transport = TFileHandleTransport(fileHandle: clientSocket)
+    let processor = Processor(service: serviceHandler)
+
+    let inProtocol = InProtocol(on: transport)
+    let outProtocol = OutProtocol(on: transport)
+
+    do {
+      try processor.process(on: inProtocol, outProtocol: outProtocol)
+    } catch let error {
+      print("Error processign request: \(error)")
+    }
+    DispatchQueue.main.async {
+      NotificationCenter.default
+        .post(name: Notification.Name(rawValue: TSocketServerClientConnectionFinished),
+              object: self,
+              userInfo: [TSocketServerProcessorKey: processor,
+                         TSocketServerTransportKey: transport])
+    }
+  }
+}
diff --git a/lib/swift/Sources/TSocketTransport.swift b/lib/swift/Sources/TSocketTransport.swift
new file mode 100644
index 0000000..0316e37
--- /dev/null
+++ b/lib/swift/Sources/TSocketTransport.swift
@@ -0,0 +1,210 @@
+
+/*
+ * 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.
+ */
+
+
+#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
+  import Darwin
+#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android)
+  import Glibc
+  import Dispatch
+#endif
+
+import Foundation
+import CoreFoundation
+
+private struct Sys {
+  #if os(Linux)
+  static let read = Glibc.read
+  static let write = Glibc.write
+  static let close = Glibc.close
+  #else
+  static let read = Darwin.read
+  static let write = Darwin.write
+  static let close = Darwin.close
+  #endif
+}
+
+extension in_addr {
+  public init?(hostent: hostent?) {
+    guard let host = hostent, host.h_addr_list != nil, host.h_addr_list.pointee != nil else {
+      return nil
+    }
+    self.init()
+    memcpy(&self, host.h_addr_list.pointee!, Int(host.h_length))
+    
+  }
+}
+
+
+#if os(Linux)
+  /// TCFSocketTransport currently unavailable
+  /// remove comments and build to see why/fix
+  /// currently CF[Read|Write]Stream's can't cast to [Input|Output]Streams which breaks thigns
+#else
+extension Stream.PropertyKey {
+  static let SSLPeerTrust = Stream.PropertyKey(kCFStreamPropertySSLPeerTrust as String)
+}
+
+/// TCFSocketTransport, uses CFSockets and (NS)Stream's
+public class TCFSocketTransport: TStreamTransport {
+    public init?(hostname: String, port: Int, secure: Bool = false) {
+    
+    var inputStream: InputStream
+    var outputStream: OutputStream
+    
+    var readStream:  Unmanaged<CFReadStream>?
+    var writeStream:  Unmanaged<CFWriteStream>?
+    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
+                                       hostname as CFString!,
+                                       UInt32(port),
+                                       &readStream,
+                                       &writeStream)
+    
+    if let readStream = readStream?.takeRetainedValue(),
+      let writeStream = writeStream?.takeRetainedValue() {
+        CFReadStreamSetProperty(readStream, .shouldCloseNativeSocket, kCFBooleanTrue)
+        CFWriteStreamSetProperty(writeStream, .shouldCloseNativeSocket, kCFBooleanTrue)
+      
+        if secure {
+            CFReadStreamSetProperty(readStream, .socketSecurityLevel, StreamSocketSecurityLevel.negotiatedSSL.rawValue as CFString)
+            CFWriteStreamSetProperty(writeStream, .socketSecurityLevel, StreamSocketSecurityLevel.negotiatedSSL.rawValue as CFString)
+        }
+
+      inputStream = readStream as InputStream
+      inputStream.schedule(in: .current, forMode: .defaultRunLoopMode)
+      inputStream.open()
+      
+      outputStream = writeStream as OutputStream
+      outputStream.schedule(in: .current, forMode: .defaultRunLoopMode)
+      outputStream.open()
+      
+    } else {
+      
+      if readStream != nil {
+        readStream?.release()
+      }
+      if writeStream != nil {
+        writeStream?.release()
+      }
+      super.init(inputStream: nil, outputStream: nil)
+      return nil
+    }
+    
+    super.init(inputStream: inputStream, outputStream: outputStream)
+    
+    self.input?.delegate = self
+    self.output?.delegate = self
+  }
+}
+
+extension TCFSocketTransport: StreamDelegate { }
+#endif
+
+
+/// TSocketTransport, posix sockets.  Supports IPv4 only for now
+public class TSocketTransport : TTransport {
+  public var socketDescriptor: Int32
+  
+  
+  
+  /// Initialize from an already set up socketDescriptor.
+  /// Expects socket thats already bound/connected (i.e. from listening)
+  ///
+  /// - parameter socketDescriptor: posix socket descriptor (Int32)
+  public init(socketDescriptor: Int32) {
+    self.socketDescriptor = socketDescriptor
+  }
+  
+  
+  public convenience init(hostname: String, port: Int) throws {
+    guard let hp = gethostbyname(hostname.cString(using: .utf8)!)?.pointee,
+      let hostAddr = in_addr(hostent: hp) else {
+        throw TTransportError(error: .unknown, message: "Invalid address: \(hostname)")
+    }
+    
+    
+    
+    #if os(Linux)
+      let sock = socket(AF_INET, Int32(SOCK_STREAM.rawValue), 0)
+      var addr = sockaddr_in(sin_family: sa_family_t(AF_INET),
+                             sin_port: in_port_t(htons(UInt16(port))),
+                             sin_addr: hostAddr,
+                             sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
+    #else
+      let sock = socket(AF_INET, SOCK_STREAM, 0)
+      
+      var addr = sockaddr_in(sin_len: UInt8(MemoryLayout<sockaddr_in>.size),
+                             sin_family: sa_family_t(AF_INET),
+                             sin_port: in_port_t(htons(UInt16(port))),
+                             sin_addr: in_addr(s_addr: in_addr_t(0)),
+                             sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
+      
+    #endif
+    
+    let addrPtr = withUnsafePointer(to: &addr){ UnsafePointer<sockaddr>(OpaquePointer($0)) }
+    
+    let connected = connect(sock, addrPtr, UInt32(MemoryLayout<sockaddr_in>.size))
+    if connected != 0 {
+      throw TTransportError(error: .notOpen, message: "Error binding to host: \(hostname) \(port)")
+    }
+    
+    self.init(socketDescriptor: sock)
+  }
+  
+  deinit {
+    close()
+  }
+  
+  public func readAll(size: Int) throws -> Data {
+    var out = Data()
+    while out.count < size {
+      out.append(try self.read(size: size))
+    }
+    return out
+  }
+  
+  public func read(size: Int) throws -> Data {
+    var buff = Array<UInt8>.init(repeating: 0, count: size)
+    let readBytes = Sys.read(socketDescriptor, &buff, size)
+    
+    return Data(bytes: buff[0..<readBytes])
+  }
+  
+  public func write(data: Data) {
+    var bytesToWrite = data.count
+    var writeBuffer = data
+    while bytesToWrite > 0 {
+      let written = writeBuffer.withUnsafeBytes {
+        Sys.write(socketDescriptor, $0, writeBuffer.count)
+      }
+      writeBuffer = writeBuffer.subdata(in: written ..< writeBuffer.count)
+      bytesToWrite -= written
+    }
+  }
+  
+  public func flush() throws {
+    // nothing to do
+  }
+  
+  public func close() {
+    shutdown(socketDescriptor, Int32(SHUT_RDWR))
+    _ = Sys.close(socketDescriptor)
+  }
+}
diff --git a/lib/swift/Sources/TStreamTransport.swift b/lib/swift/Sources/TStreamTransport.swift
new file mode 100644
index 0000000..26bc1b8
--- /dev/null
+++ b/lib/swift/Sources/TStreamTransport.swift
@@ -0,0 +1,143 @@
+/*
+ * 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 Foundation
+import CoreFoundation
+
+#if os(Linux)
+  /// Currently unavailable in Linux
+  /// Remove comments and build to fix
+  /// Currently kConstants for CFSockets don't exist in linux and not all have been moved
+  /// to property structs yet
+#else
+  // Must inherit NSObject for NSStreamDelegate conformance
+  public class TStreamTransport : NSObject, TTransport {
+    public var input: InputStream? = nil
+    public var output: OutputStream? = nil
+    
+    public init(inputStream: InputStream?, outputStream: OutputStream?) {
+      input   = inputStream
+      output  = outputStream
+    }
+    
+    public convenience init(inputStream: InputStream?) {
+      self.init(inputStream: inputStream, outputStream: nil)
+    }
+    
+    public convenience init(outputStream: OutputStream?) {
+      self.init(inputStream: nil, outputStream: outputStream)
+    }
+    
+    deinit {
+      close()
+    }
+    
+    public func readAll(size: Int) throws -> Data {
+      guard let input = input else {
+        throw TTransportError(error: .unknown)
+      }
+      
+      var read = Data()
+      while read.count < size {
+        var buffer = Array<UInt8>(repeating: 0, count: size - read.count)
+        
+        let bytesRead = buffer.withUnsafeMutableBufferPointer { bufferPtr in
+          return input.read(bufferPtr.baseAddress!, maxLength: size - read.count)
+        }
+        
+        if bytesRead <= 0 {
+          throw TTransportError(error: .notOpen)
+        }
+        read.append(Data(bytes: buffer))
+      }
+      return read
+    }
+    
+    public func read(size: Int) throws -> Data {
+      guard let input = input else {
+        throw TTransportError(error: .unknown)
+      }
+      
+      var read = Data()
+      while read.count < size {
+        var buffer = Array<UInt8>(repeating: 0, count: size - read.count)
+        let bytesRead = buffer.withUnsafeMutableBufferPointer {
+          input.read($0.baseAddress!, maxLength: size - read.count)
+        }
+        
+        if bytesRead <= 0 {
+          break
+        }
+        
+        read.append(Data(bytes: buffer))
+      }
+      return read
+    }
+    
+    public func write(data: Data) throws {
+      guard let output = output else {
+        throw TTransportError(error: .unknown)
+      }
+      
+      var bytesWritten = 0
+      while bytesWritten < data.count {
+        bytesWritten = data.withUnsafeBytes {
+          return output.write($0, maxLength: data.count)
+        }
+        
+        if bytesWritten == -1 {
+          throw TTransportError(error: .notOpen)
+        } else if bytesWritten == 0 {
+          throw TTransportError(error: .endOfFile)
+        }
+      }
+    }
+    
+    
+    public func flush() throws {
+      return
+    }
+    
+    public func close() {
+      
+      if input != nil {
+        // Close and reset inputstream
+        if let cf: CFReadStream = input {
+          CFReadStreamSetProperty(cf, .shouldCloseNativeSocket, kCFBooleanTrue)
+        }
+        
+        input?.delegate = nil
+        input?.close()
+        input?.remove(from: .current, forMode: .defaultRunLoopMode)
+        input = nil
+      }
+      
+      if output != nil {
+        // Close and reset output stream
+        if let cf: CFWriteStream = output {
+          CFWriteStreamSetProperty(cf, .shouldCloseNativeSocket, kCFBooleanTrue)
+        }
+        output?.delegate = nil
+        output?.close()
+        output?.remove(from: .current, forMode: .defaultRunLoopMode)
+        output = nil
+      }
+    }
+  }
+#endif
diff --git a/lib/swift/Sources/TStruct.swift b/lib/swift/Sources/TStruct.swift
new file mode 100644
index 0000000..f172a32
--- /dev/null
+++ b/lib/swift/Sources/TStruct.swift
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+/// Protocol for Generated Structs to conform to
+/// Dictionary maps field names to internal IDs and uses Reflection
+/// to iterate through all fields.  
+/// `writeFieldValue(_:name:type:id:)` calls `TSerializable.write(to:)` internally
+/// giving a nice recursive behavior for nested TStructs, TLists, TMaps, and TSets
+public protocol TStruct : TSerializable {
+  static var fieldIds: [String: Int32] { get }
+  static var structName: String { get }
+}
+
+public extension TStruct {
+  public static var fieldIds: [String: (id: Int32, type: TType)] { return [:] }
+  public static var thriftType: TType { return .struct }
+  
+  public func write(to proto: TProtocol) throws {
+    // Write struct name first
+    try proto.writeStructBegin(name: Self.structName)
+    
+    try self.forEach { name, value, id in
+      // Write to protocol
+      try proto.writeFieldValue(value, name: name,
+                                type: value.thriftType, id: id)
+    }
+    try proto.writeFieldStop()
+    try proto.writeStructEnd()
+  }
+  
+  public var hashValue: Int {
+    let prime = 31
+    var result = 1
+    self.forEach { _, value, _ in
+      result = prime &* result &+ (value.hashValue)
+    }
+    return result
+  }
+  
+  /// Provides a block for handling each (available) thrift property using reflection
+  /// Caveat: Skips over optional values
+  
+  
+  /// Provides a block for handling each (available) thrift property using reflection
+  ///
+  /// - parameter block: block for handling property
+  ///
+  /// - throws: rethrows any Error thrown in block
+  private func forEach(_ block: (_ name: String, _ value: TSerializable, _ id: Int32) throws -> Void) rethrows {
+    // Mirror the object, getting (name: String?, value: Any) for every property
+    let mirror = Mirror(reflecting: self)
+    
+    // Iterate through all children, ignore empty property names
+    for (propName, propValue) in mirror.children {
+      guard let propName = propName else { continue }
+
+      if let tval = unwrap(any: propValue) as? TSerializable, let id = Self.fieldIds[propName] {
+        try block(propName, tval, id)
+      }
+    }
+  }
+  
+  
+  /// Any can mysteriously be an Optional<Any> at the same time,
+  /// this checks and always returns Optional<Any> without double wrapping
+  /// we then try to bind value as TSerializable to ignore any extension properties
+  /// and the like and verify the property exists and grab the Thrift
+  /// property ID at the same time
+  ///
+  /// - parameter any: Any instance to attempt to unwrap
+  ///
+  /// - returns: Unwrapped Any as Optional<Any>
+  private func unwrap(any: Any) -> Any? {
+    let mi = Mirror(reflecting: any)
+    
+    if mi.displayStyle != .optional { return any }
+    if mi.children.count == 0 { return nil }
+    
+    let (_, some) = mi.children.first!
+    return some
+  }
+}
+
diff --git a/lib/swift/Sources/TTransport.swift b/lib/swift/Sources/TTransport.swift
new file mode 100644
index 0000000..e82bbe1
--- /dev/null
+++ b/lib/swift/Sources/TTransport.swift
@@ -0,0 +1,64 @@
+/*
+* 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 Foundation
+
+public protocol TTransport {
+  
+  // Required
+  func read(size: Int) throws -> Data
+  func write(data: Data) throws
+  func flush() throws
+
+  // Optional (default provided)
+  func readAll(size: Int) throws -> Data
+  func isOpen() throws -> Bool
+  func open() throws
+  func close() throws
+}
+
+public extension TTransport {
+  func isOpen() throws -> Bool { return true }
+  func open() throws { }
+  func close() throws { }
+  
+  func readAll(size: Int) throws -> Data {
+    var buff = Data()
+    var have = 0
+    while have < size {
+      let chunk = try self.read(size: size - have)
+      have += chunk.count
+      buff.append(chunk)
+      if chunk.count == 0 {
+        throw TTransportError(error: .endOfFile)
+      }
+    }
+    return buff
+  }
+}
+
+public protocol TAsyncTransport : TTransport {
+  // Factory
+  func flush(_ completion: @escaping (TAsyncTransport, Error?) ->())
+}
+
+public protocol TAsyncTransportFactory {
+  associatedtype Transport : TAsyncTransport
+  func newTransport() -> Transport
+}
diff --git a/lib/swift/Sources/TTransportError.swift b/lib/swift/Sources/TTransportError.swift
new file mode 100644
index 0000000..3fd0059
--- /dev/null
+++ b/lib/swift/Sources/TTransportError.swift
@@ -0,0 +1,86 @@
+/*
+* 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.
+*/
+
+public struct TTransportError: TError {
+  public enum ErrorCode: TErrorCode {
+    case unknown
+    case notOpen
+    case alreadyOpen
+    case timedOut
+    case endOfFile
+    case negativeSize
+    case sizeLimit(limit: Int, got: Int)
+    
+    public var thriftErrorCode: Int {
+      switch self {
+      case .unknown:      return 0
+      case .notOpen:      return 1
+      case .alreadyOpen:  return 2
+      case .timedOut:     return 3
+      case .endOfFile:    return 4
+      case .negativeSize: return 5
+      case .sizeLimit:    return 6
+      }
+    }
+    public var description: String {
+      switch self {
+      case .unknown:      return "Unknown TTransportError"
+      case .notOpen:      return "Not Open"
+      case .alreadyOpen:  return "Already Open"
+      case .timedOut:     return "Timed Out"
+      case .endOfFile:    return "End Of File"
+      case .negativeSize: return "Negative Size"
+      case .sizeLimit(let limit, let got):
+        return "Message exceeds size limit of \(limit) (received: \(got)"
+      }
+    }
+  }
+  public var error: ErrorCode = .unknown
+  public var message: String? = nil
+  public static var defaultCase: ErrorCode { return .unknown }
+  
+  public init() { }
+
+}
+
+/// THTTPTransportError
+///
+/// Error's thrown on HTTP Transport
+public struct THTTPTransportError: TError {
+  public enum ErrorCode: TErrorCode {
+    case invalidResponse
+    case invalidStatus(statusCode: Int)
+    case authentication
+    
+    public var description: String {
+      switch self {
+      case .invalidResponse:                return "Invalid HTTP Response"
+      case .invalidStatus(let statusCode):  return "Invalid HTTP Status Code (\(statusCode))"
+      case .authentication:                 return "Authentication Error"
+      }
+    }
+    public var thriftErrorCode: Int { return 0 }
+  }
+  public var error: ErrorCode = .invalidResponse
+  public var message: String? = nil
+  public static var defaultCase: ErrorCode { return .invalidResponse }
+  
+  public init() { }
+}
+
diff --git a/lib/swift/Sources/TWrappedProtocol.swift b/lib/swift/Sources/TWrappedProtocol.swift
new file mode 100644
index 0000000..8e8577b
--- /dev/null
+++ b/lib/swift/Sources/TWrappedProtocol.swift
@@ -0,0 +1,208 @@
+/*
+* 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 Foundation // For (NS)Data
+
+
+/// Generic protocol, implementes TProtocol and wraps a concrete protocol.
+/// Useful for generically subclassing protocols to override specific methods 
+/// (i.e. TMultiplexedProtocol)
+open class TWrappedProtocol<Protocol: TProtocol> : TProtocol {
+  var concreteProtocol: Protocol
+  
+  public var transport: TTransport {
+    get {
+      return concreteProtocol.transport
+    }
+    set {
+      concreteProtocol.transport = newValue
+    }
+  }
+
+  public required init(on transport: TTransport) {
+    self.concreteProtocol = Protocol(on: transport)
+  }
+  
+  // Read methods
+  
+  public func readMessageBegin() throws -> (String, TMessageType, Int32) {
+    return try concreteProtocol.readMessageBegin()
+  }
+  
+  public func readMessageEnd() throws {
+    try concreteProtocol.readMessageEnd()
+  }
+  
+  public func readStructBegin() throws -> String {
+    return try concreteProtocol.readStructBegin()
+  }
+  
+  public func readStructEnd() throws {
+    try concreteProtocol.readStructEnd()
+  }
+  
+  public func readFieldBegin() throws -> (String, TType, Int32) {
+    return try concreteProtocol.readFieldBegin()
+  }
+  
+  public func readFieldEnd() throws {
+    try concreteProtocol.readFieldEnd()
+  }
+  
+  public func readMapBegin() throws -> (TType, TType, Int32) {
+    return try concreteProtocol.readMapBegin()
+  }
+  
+  public func readMapEnd() throws {
+    try concreteProtocol.readMapEnd()
+  }
+  
+  public func readSetBegin() throws -> (TType, Int32) {
+    return try concreteProtocol.readSetBegin()
+  }
+  
+  public func readSetEnd() throws {
+    try concreteProtocol.readSetEnd()
+  }
+  
+  public func readListBegin() throws -> (TType, Int32) {
+    return try concreteProtocol.readListBegin()
+  }
+  
+  public func readListEnd() throws {
+    try concreteProtocol.readListEnd()
+  }
+  
+  public func read() throws -> String {
+    return try concreteProtocol.read()
+  }
+  
+  public func read() throws -> Bool {
+    return try concreteProtocol.read()
+  }
+  
+  public func read() throws -> UInt8 {
+    return try concreteProtocol.read()
+  }
+  
+  public func read() throws -> Int16 {
+    return try concreteProtocol.read()
+  }
+  
+  public func read() throws -> Int32 {
+    return try concreteProtocol.read()
+  }
+  
+  public func read() throws -> Int64 {
+    return try concreteProtocol.read()
+  }
+  
+  public func read() throws -> Double {
+    return try concreteProtocol.read()
+  }
+  
+  public func read() throws -> Data {
+    return try concreteProtocol.read()
+  }
+  
+  // Write methods
+  
+  public func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws {
+    return try concreteProtocol.writeMessageBegin(name: name, type: messageType, sequenceID: sequenceID)
+  }
+  
+  public func writeMessageEnd() throws {
+    try concreteProtocol.writeMessageEnd()
+  }
+  
+  public func writeStructBegin(name: String) throws {
+    try concreteProtocol.writeStructBegin(name: name)
+  }
+  
+  public func writeStructEnd() throws {
+    try concreteProtocol.writeStructEnd()
+  }
+  
+  public func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws {
+    try concreteProtocol.writeFieldBegin(name: name, type: fieldType, fieldID: fieldID)
+  }
+  
+  public func writeFieldStop() throws {
+    try concreteProtocol.writeFieldStop()
+  }
+  
+  public func writeFieldEnd() throws {
+    try concreteProtocol.writeFieldEnd()
+  }
+  
+  public func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws {
+    try concreteProtocol.writeMapBegin(keyType: keyType, valueType: valueType, size: size)
+  }
+  
+  public func writeMapEnd() throws {
+    try concreteProtocol.writeMapEnd()
+  }
+  
+  public func writeSetBegin(elementType: TType, size: Int32) throws {
+    try concreteProtocol.writeSetBegin(elementType: elementType, size: size)
+  }
+  
+  public func writeSetEnd() throws {
+    try concreteProtocol.writeSetEnd()
+  }
+  
+  public func writeListBegin(elementType: TType, size: Int32) throws {
+    try concreteProtocol.writeListBegin(elementType: elementType, size: size)
+  }
+  
+  public func writeListEnd() throws {
+    try concreteProtocol.writeListEnd()
+  }
+  public func write(_ value: String) throws {
+    try concreteProtocol.write(value)
+  }
+  
+  public func write(_ value: Bool) throws {
+    try concreteProtocol.write(value)
+  }
+  
+  public func write(_ value: UInt8) throws {
+    try concreteProtocol.write(value)
+  }
+
+  public func write(_ value: Int16) throws {
+    try concreteProtocol.write(value)
+  }
+  
+  public func write(_ value: Int32) throws {
+    try concreteProtocol.write(value)
+  }
+  
+  public func write(_ value: Int64) throws {
+    try concreteProtocol.write(value)
+  }
+  
+  public func write(_ value: Double) throws {
+    try concreteProtocol.write(value)
+  }
+
+  public func write(_ data: Data) throws {
+    try concreteProtocol.write(data)
+  }
+}
diff --git a/lib/swift/Sources/Thrift.swift b/lib/swift/Sources/Thrift.swift
new file mode 100644
index 0000000..5bd1758
--- /dev/null
+++ b/lib/swift/Sources/Thrift.swift
@@ -0,0 +1,3 @@
+class Thrift {
+	let version = "1.1.0"
+}
diff --git a/lib/swift/Tests/LinuxMain.swift b/lib/swift/Tests/LinuxMain.swift
new file mode 100644
index 0000000..288fec9
--- /dev/null
+++ b/lib/swift/Tests/LinuxMain.swift
@@ -0,0 +1,8 @@
+import XCTest
+@testable import ThriftTests
+
+XCTMain([
+     testCase(ThriftTests.allTests),
+     testCase(TBinaryProtocolTests.allTests),
+     testCase(TCompactProtocolTests.allTests),
+])
diff --git a/lib/swift/Tests/ThriftTests/TBinaryProtocolTests.swift b/lib/swift/Tests/ThriftTests/TBinaryProtocolTests.swift
new file mode 100644
index 0000000..56a5572
--- /dev/null
+++ b/lib/swift/Tests/ThriftTests/TBinaryProtocolTests.swift
@@ -0,0 +1,168 @@
+//
+//  TBinaryProtocolTests.swift
+//  Thrift
+//
+//  Created by Christopher Simpson on 8/18/16.
+//
+//
+
+import XCTest
+import Foundation
+@testable import Thrift
+
+
+/// Testing Binary protocol read/write against itself
+/// Uses separate read/write transport/protocols 
+class TBinaryProtocolTests: XCTestCase {
+  var transport: TMemoryBufferTransport = TMemoryBufferTransport(flushHandler: {
+    $0.reset(readBuffer: $1)
+  })
+  
+  var proto: TBinaryProtocol!
+  
+  override func setUp() {
+    super.setUp()
+    proto = TBinaryProtocol(on: transport)
+    transport.reset()
+  }
+  
+  override func tearDown() {
+    super.tearDown()
+    transport.reset()
+  }
+  
+  func testInt8WriteRead() {
+    let writeVal: UInt8 = 250
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: UInt8 = (try? proto.read()) ?? 0
+    XCTAssertEqual(writeVal, readVal, "Error with UInt8, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testInt16WriteRead() {
+
+    let writeVal: Int16 = 12312
+    try? proto.write(writeVal)
+    try? transport.flush()
+    let readVal: Int16 = (try? proto.read()) ?? 0
+    XCTAssertEqual(writeVal, readVal, "Error with Int16, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testInt32WriteRead() {
+    let writeVal: Int32 = 2029234
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Int32 = (try? proto.read()) ?? 0
+    XCTAssertEqual(writeVal, readVal, "Error with Int32, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testInt64WriteRead() {
+    let writeVal: Int64 = 234234981374134
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Int64 = (try? proto.read()) ?? 0
+    XCTAssertEqual(writeVal, readVal, "Error with Int64, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testDoubleWriteRead() {
+    let writeVal: Double = 3.1415926
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Double = (try? proto.read()) ?? 0.0
+    XCTAssertEqual(writeVal, readVal, "Error with Double, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testBoolWriteRead() {
+    let writeVal: Bool = true
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Bool = (try? proto.read()) ?? false
+    XCTAssertEqual(writeVal, readVal, "Error with Bool, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testStringWriteRead() {
+    let writeVal: String = "Hello World"
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: String!
+    do {
+      readVal = try proto.read()
+    } catch let error {
+      XCTAssertFalse(true, "Error reading \(error)")
+      return
+    }
+    
+    XCTAssertEqual(writeVal, readVal, "Error with String, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testDataWriteRead() {
+    let writeVal: Data = "Data World".data(using: .utf8)!
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Data = (try? proto.read()) ?? "Goodbye World".data(using: .utf8)!
+    XCTAssertEqual(writeVal, readVal, "Error with Data, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testStructWriteRead() {
+    let msg = "Test Protocol Error"
+    let writeVal = TApplicationError(error: .protocolError, message: msg)
+    do {
+      try writeVal.write(to: proto)
+      try? transport.flush()
+
+    } catch let error {
+      XCTAssertFalse(true, "Caught Error attempting to write \(error)")
+    }
+    
+    do {
+      let readVal = try TApplicationError.read(from: proto)
+      XCTAssertEqual(readVal.error.thriftErrorCode, writeVal.error.thriftErrorCode, "Error case mismatch, expected \(readVal.error) got \(writeVal.error)")
+      XCTAssertEqual(readVal.message, writeVal.message, "Error message mismatch, expected \(readVal.message) got \(writeVal.message)")
+    } catch let error {
+      XCTAssertFalse(true, "Caught Error attempting to read \(error)")
+    }
+  }
+  func testUnsafeBitcastUpdate() {
+    let value: Double = 3.14159
+    let val: Int64 = 31415926
+    let uval: UInt64 = 31415926
+    
+    let i64 = Int64(bitPattern: value.bitPattern)
+    let ubc = unsafeBitCast(value, to: Int64.self)
+    
+    XCTAssertEqual(i64, ubc, "Bitcast Double-> i64 Values don't match")
+    
+    let dbl = Double(bitPattern: UInt64(val))
+    let ubdb = unsafeBitCast(val, to: Double.self)
+    
+    XCTAssertEqual(dbl, ubdb, "Bitcast i64 -> Double Values don't match")
+    
+    let db2 = Double(bitPattern: uval)
+    let usbc2 = unsafeBitCast(uval, to: Double.self)
+    
+    XCTAssertEqual(db2, usbc2, "Bitcast u64 -> Double Values don't match")
+
+    
+  }
+  
+  static var allTests : [(String, (TBinaryProtocolTests) -> () throws -> Void)] {
+    return [
+      ("testInt8WriteRead", testInt8WriteRead),
+      ("testInt16WriteRead", testInt16WriteRead),
+      ("testInt32WriteRead", testInt32WriteRead),
+      ("testInt64WriteRead", testInt64WriteRead),
+      ("testDoubleWriteRead", testDoubleWriteRead),
+      ("testBoolWriteRead", testBoolWriteRead),
+      ("testStringWriteRead", testStringWriteRead),
+      ("testDataWriteRead", testDataWriteRead),
+      ("testStructWriteRead", testStructWriteRead)
+    ]
+  }
+}
diff --git a/lib/swift/Tests/ThriftTests/TCompactProtocolTests.swift b/lib/swift/Tests/ThriftTests/TCompactProtocolTests.swift
new file mode 100644
index 0000000..882c260
--- /dev/null
+++ b/lib/swift/Tests/ThriftTests/TCompactProtocolTests.swift
@@ -0,0 +1,210 @@
+//
+//  TCompactProtocolTests.swift
+//  Thrift
+//
+//  Created by Christopher Simpson on 8/19/16.
+//
+//
+
+import XCTest
+import Foundation
+@testable import Thrift
+
+
+/// Testing Binary protocol read/write against itself
+/// Uses separate read/write transport/protocols
+class TCompactProtocolTests: XCTestCase {
+  var transport: TMemoryBufferTransport = TMemoryBufferTransport(flushHandler: {
+    $0.reset(readBuffer: $1)
+  })
+  var proto: TCompactProtocol!
+  
+  override func setUp() {
+    super.setUp()
+    proto = TCompactProtocol(on: transport)
+    transport.reset()
+  }
+  
+  override func tearDown() {
+    super.tearDown()
+    transport.reset()
+  }
+  
+  func testInt8WriteRead() {
+    let writeVal: UInt8 = 250
+    try? proto.write(writeVal)
+    try? transport.flush()
+    let readVal: UInt8 = (try? proto.read()) ?? 0
+    XCTAssertEqual(writeVal, readVal, "Error with UInt8, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testInt16WriteRead() {
+    let writeVal: Int16 = 12312
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Int16 = (try? proto.read()) ?? 0
+    XCTAssertEqual(writeVal, readVal, "Error with Int16, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testInt32WriteRead() {
+    let writeVal: Int32 = 2029234
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Int32 = (try? proto.read()) ?? 0
+    XCTAssertEqual(writeVal, readVal, "Error with Int32, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testInt64WriteRead() {
+    let writeVal: Int64 = 234234981374134
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Int64 = (try? proto.read()) ?? 0
+    XCTAssertEqual(writeVal, readVal, "Error with Int64, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testDoubleWriteRead() {
+    let writeVal: Double = 3.1415926
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Double = (try? proto.read()) ?? 0.0
+    XCTAssertEqual(writeVal, readVal, "Error with Double, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testBoolWriteRead() {
+    let writeVal: Bool = true
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Bool = (try? proto.read()) ?? false
+    XCTAssertEqual(writeVal, readVal, "Error with Bool, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testStringWriteRead() {
+    let writeVal: String = "Hello World"
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: String!
+    do {
+      readVal = try proto.read()
+    } catch let error {
+      XCTAssertFalse(true, "Error reading \(error)")
+      return
+    }
+    
+    XCTAssertEqual(writeVal, readVal, "Error with String, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testDataWriteRead() {
+    let writeVal: Data = "Data World".data(using: .utf8)!
+    try? proto.write(writeVal)
+    try? transport.flush()
+
+    let readVal: Data = (try? proto.read()) ?? "Goodbye World".data(using: .utf8)!
+    XCTAssertEqual(writeVal, readVal, "Error with Data, wrote \(writeVal) but read \(readVal)")
+  }
+  
+  func testStructWriteRead() {
+    let msg = "Test Protocol Error"
+    let writeVal = TApplicationError(error: .protocolError, message: msg)
+    do {
+      try writeVal.write(to: proto)
+      try transport.flush()
+
+    } catch let error {
+      XCTAssertFalse(true, "Caught Error attempting to write \(error)")
+    }
+    
+    do {
+      let readVal = try TApplicationError.read(from: proto)
+      XCTAssertEqual(readVal.error.thriftErrorCode, writeVal.error.thriftErrorCode, "Error case mismatch, expected \(readVal.error) got \(writeVal.error)")
+      XCTAssertEqual(readVal.message, writeVal.message, "Error message mismatch, expected \(readVal.message) got \(writeVal.message)")
+    } catch let error {
+      XCTAssertFalse(true, "Caught Error attempting to read \(error)")
+    }
+  }
+  
+  func testInt32ZigZag() {
+    let zero: Int32 = 0
+    let one: Int32 = 1
+    let nOne: Int32 = -1
+    let two: Int32 = 2
+    let nTwo: Int32 = -2
+    let max = Int32.max
+    let min = Int32.min
+
+    XCTAssertEqual(proto.i32ToZigZag(zero), UInt32(0), "Error 32bit zigzag on \(zero)")
+    XCTAssertEqual(proto.zigZagToi32(0), zero, "Error 32bit zigzag on \(zero)")
+
+    XCTAssertEqual(proto.i32ToZigZag(nOne), UInt32(1), "Error 32bit zigzag on \(nOne)")
+    XCTAssertEqual(proto.zigZagToi32(1), nOne, "Error 32bit zigzag on \(nOne)")
+
+    XCTAssertEqual(proto.i32ToZigZag(one), UInt32(2), "Error 32bit zigzag on \(one)")
+    XCTAssertEqual(proto.zigZagToi32(2), one, "Error 32bit zigzag on \(one)")
+
+    XCTAssertEqual(proto.i32ToZigZag(nTwo), UInt32(3), "Error 32bit zigzag on \(nTwo)")
+    XCTAssertEqual(proto.zigZagToi32(3), nTwo, "Error 32bit zigzag on \(nTwo)")
+
+    XCTAssertEqual(proto.i32ToZigZag(two), UInt32(4), "Error 32bit zigzag on \(two)")
+    XCTAssertEqual(proto.zigZagToi32(4), two, "Error 32bit zigzag on \(two)")
+
+    let uMaxMinusOne: UInt32 = UInt32.max - 1
+    XCTAssertEqual(proto.i32ToZigZag(max), uMaxMinusOne, "Error 32bit zigzag on \(max)")
+    XCTAssertEqual(proto.zigZagToi32(uMaxMinusOne), max, "Error 32bit zigzag on \(max)")
+
+    XCTAssertEqual(proto.i32ToZigZag(min), UInt32.max, "Error 32bit zigzag on \(min)")
+    XCTAssertEqual(proto.zigZagToi32(UInt32.max), min, "Error 32bit zigzag on \(min)")
+  }
+
+  func testInt64ZigZag() {
+    let zero: Int64 = 0
+    let one: Int64 = 1
+    let nOne: Int64 = -1
+    let two: Int64 = 2
+    let nTwo: Int64 = -2
+    let max = Int64.max
+    let min = Int64.min
+
+    XCTAssertEqual(proto.i64ToZigZag(zero), UInt64(0), "Error 64bit zigzag on \(zero)")
+    XCTAssertEqual(proto.zigZagToi64(0), zero, "Error 64bit zigzag on \(zero)")
+
+    XCTAssertEqual(proto.i64ToZigZag(nOne), UInt64(1), "Error 64bit zigzag on \(nOne)")
+    XCTAssertEqual(proto.zigZagToi64(1), nOne, "Error 64bit zigzag on \(nOne)")
+
+    XCTAssertEqual(proto.i64ToZigZag(one), UInt64(2), "Error 64bit zigzag on \(one)")
+    XCTAssertEqual(proto.zigZagToi64(2), one, "Error 64bit zigzag on \(one)")
+
+    XCTAssertEqual(proto.i64ToZigZag(nTwo), UInt64(3), "Error 64bit zigzag on \(nTwo)")
+    XCTAssertEqual(proto.zigZagToi64(3), nTwo, "Error 64bit zigzag on \(nTwo)")
+
+    XCTAssertEqual(proto.i64ToZigZag(two), UInt64(4), "Error 64bit zigzag on \(two)")
+    XCTAssertEqual(proto.zigZagToi64(4), two, "Error 64bit zigzag on \(two)")
+
+    let uMaxMinusOne: UInt64 = UInt64.max - 1
+    XCTAssertEqual(proto.i64ToZigZag(max), uMaxMinusOne, "Error 64bit zigzag on \(max)")
+    XCTAssertEqual(proto.zigZagToi64(uMaxMinusOne), max, "Error 64bit zigzag on \(max)")
+
+    XCTAssertEqual(proto.i64ToZigZag(min), UInt64.max, "Error 64bit zigzag on \(min)")
+    XCTAssertEqual(proto.zigZagToi64(UInt64.max), min, "Error 64bit zigzag on \(min)")
+  }
+  
+  static var allTests : [(String, (TCompactProtocolTests) -> () throws -> Void)] {
+    return [
+      ("testInt8WriteRead", testInt8WriteRead),
+      ("testInt16WriteRead", testInt16WriteRead),
+      ("testInt32WriteRead", testInt32WriteRead),
+      ("testInt64WriteRead", testInt64WriteRead),
+      ("testDoubleWriteRead", testDoubleWriteRead),
+      ("testBoolWriteRead", testBoolWriteRead),
+      ("testStringWriteRead", testStringWriteRead),
+      ("testDataWriteRead", testDataWriteRead),
+      ("testStructWriteRead", testStructWriteRead),
+      ("testInt32ZigZag", testInt32ZigZag),
+      ("testInt64ZigZag", testInt64ZigZag)
+    ]
+  }
+}
diff --git a/lib/swift/Tests/ThriftTests/ThriftTests.swift b/lib/swift/Tests/ThriftTests/ThriftTests.swift
new file mode 100644
index 0000000..9316100
--- /dev/null
+++ b/lib/swift/Tests/ThriftTests/ThriftTests.swift
@@ -0,0 +1,18 @@
+import XCTest
+@testable import Thrift
+
+class ThriftTests: XCTestCase {
+  func testVersion() {
+    XCTAssertEqual(Thrift().version, "1.1.0")
+  }
+
+  func test_in_addr_extension() {
+
+  }
+
+  static var allTests : [(String, (ThriftTests) -> () throws -> Void)] {
+    return [
+      ("testVersion", testVersion),
+    ]
+  }
+}
diff --git a/lib/ts/coding_standards.md b/lib/ts/coding_standards.md
new file mode 100644
index 0000000..fa0390b
--- /dev/null
+++ b/lib/ts/coding_standards.md
@@ -0,0 +1 @@
+Please follow [General Coding Standards](/doc/coding_standards.md)
diff --git a/lib/ts/thrift.d.ts b/lib/ts/thrift.d.ts
new file mode 100644
index 0000000..0ba46c9
--- /dev/null
+++ b/lib/ts/thrift.d.ts
@@ -0,0 +1,699 @@
+/*
+ * 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.
+ */
+
+declare module Thrift {
+  /**
+   * Thrift JavaScript library version.
+   */
+  var Version: string;
+
+  /**
+   * Thrift IDL type string to Id mapping.
+   * @property {number}  STOP   - End of a set of fields.
+   * @property {number}  VOID   - No value (only legal for return types).
+   * @property {number}  BOOL   - True/False integer.
+   * @property {number}  BYTE   - Signed 8 bit integer.
+   * @property {number}  I08    - Signed 8 bit integer.     
+   * @property {number}  DOUBLE - 64 bit IEEE 854 floating point.
+   * @property {number}  I16    - Signed 16 bit integer.
+   * @property {number}  I32    - Signed 32 bit integer.
+   * @property {number}  I64    - Signed 64 bit integer.
+   * @property {number}  STRING - Array of bytes representing a string of characters.
+   * @property {number}  UTF7   - Array of bytes representing a string of UTF7 encoded characters.
+   * @property {number}  STRUCT - A multifield type.
+   * @property {number}  MAP    - A collection type (map/associative-array/dictionary).
+   * @property {number}  SET    - A collection type (unordered and without repeated values).
+   * @property {number}  LIST   - A collection type (unordered).
+   * @property {number}  UTF8   - Array of bytes representing a string of UTF8 encoded characters.
+   * @property {number}  UTF16  - Array of bytes representing a string of UTF16 encoded characters.
+   */
+  interface Type {
+    'STOP': number;
+    'VOID': number;
+    'BOOL': number;
+    'BYTE': number;
+    'I08': number;
+    'DOUBLE': number;
+    'I16': number;
+    'I32': number;
+    'I64': number;
+    'STRING': number;
+    'UTF7': number;
+    'STRUCT': number;
+    'MAP': number;
+    'SET': number;
+    'LIST': number;
+    'UTF8': number;
+    'UTF16': number;
+  }
+  var Type: Type;
+
+  /**
+   * Thrift RPC message type string to Id mapping.
+   * @property {number}  CALL      - RPC call sent from client to server.
+   * @property {number}  REPLY     - RPC call normal response from server to client.
+   * @property {number}  EXCEPTION - RPC call exception response from server to client.
+   * @property {number}  ONEWAY    - Oneway RPC call from client to server with no response.
+   */
+  interface MessageType {
+    'CALL': number;
+    'REPLY': number;
+    'EXCEPTION': number;
+    'ONEWAY': number;
+  }
+  var MessageType: MessageType;
+
+  /**
+   * Utility function returning the count of an object's own properties.
+   * @param {object} obj - Object to test.
+   * @returns {number} number of object's own properties
+   */
+  function objectLength(obj: Object): number;
+
+  /**
+   * Utility function to establish prototype inheritance.
+   * @param {function} constructor - Contstructor function to set as derived.
+   * @param {function} superConstructor - Contstructor function to set as base.
+   * @param {string} [name] - Type name to set as name property in derived prototype.
+   */
+  function inherits(constructor: Function, superConstructor: Function, name?: string): void;
+
+  /**
+   * TException is the base class for all Thrift exceptions types.
+   */
+  class TException implements Error {
+    name: string;
+    message: string;
+
+    /**
+     * Initializes a Thrift TException instance.
+     * @param {string} message - The TException message (distinct from the Error message).
+     */
+    constructor(message: string);
+
+    /**
+     * Returns the message set on the exception.
+     * @returns {string} exception message
+     */
+    getMessage(): string;
+  }
+
+  /**
+   * Thrift Application Exception type string to Id mapping.
+   * @property {number}  UNKNOWN                 - Unknown/undefined.
+   * @property {number}  UNKNOWN_METHOD          - Client attempted to call a method unknown to the server.
+   * @property {number}  INVALID_MESSAGE_TYPE    - Client passed an unknown/unsupported MessageType.
+   * @property {number}  WRONG_METHOD_NAME       - Unused.
+   * @property {number}  BAD_SEQUENCE_ID         - Unused in Thrift RPC, used to flag proprietary sequence number errors.
+   * @property {number}  MISSING_RESULT          - Raised by a server processor if a handler fails to supply the required return result.
+   * @property {number}  INTERNAL_ERROR          - Something bad happened.
+   * @property {number}  PROTOCOL_ERROR          - The protocol layer failed to serialize or deserialize data.
+   * @property {number}  INVALID_TRANSFORM       - Unused.
+   * @property {number}  INVALID_PROTOCOL        - The protocol (or version) is not supported.
+   * @property {number}  UNSUPPORTED_CLIENT_TYPE - Unused.
+   */
+  interface TApplicationExceptionType {
+    'UNKNOWN': number;
+    'UNKNOWN_METHOD': number;
+    'INVALID_MESSAGE_TYPE': number;
+    'WRONG_METHOD_NAME': number;
+    'BAD_SEQUENCE_ID': number;
+    'MISSING_RESULT': number;
+    'INTERNAL_ERROR': number;
+    'PROTOCOL_ERROR': number;
+    'INVALID_TRANSFORM': number;
+    'INVALID_PROTOCOL': number;
+    'UNSUPPORTED_CLIENT_TYPE': number;
+  }
+  var TApplicationExceptionType: TApplicationExceptionType;
+
+  /**
+   * TApplicationException is the exception class used to propagate exceptions from an RPC server back to a calling client.
+   */
+  class TApplicationException extends TException {
+    message: string;
+    code: number;
+
+    /**
+     * Initializes a Thrift TApplicationException instance.
+     * @param {string} message - The TApplicationException message (distinct from the Error message).
+     * @param {Thrift.TApplicationExceptionType} [code] - The TApplicationExceptionType code.
+     */
+    constructor(message: string, code?: number);
+
+    /**
+     * Read a TApplicationException from the supplied protocol.
+     * @param {object} input - The input protocol to read from.
+     */
+    read(input: Object): void;
+
+    /**
+     * Write a TApplicationException to the supplied protocol.
+     * @param {object} output - The output protocol to write to.
+     */
+    write(output: Object): void;
+
+    /**
+     * Returns the application exception code set on the exception.
+     * @returns {Thrift.TApplicationExceptionType} exception code
+     */
+    getCode(): number;
+  }
+
+  /**
+   * The Apache Thrift Transport layer performs byte level I/O between RPC
+   * clients and servers. The JavaScript Transport object type uses Http[s]/XHR and is
+   * the sole browser based Thrift transport. Target servers must implement the http[s] 
+   * transport (see: node.js example server).
+   */
+  class TXHRTransport {
+    url: string;
+    wpos: number;
+    rpos: number;
+    useCORS: any;
+    send_buf: string;
+    recv_buf: string;
+
+    /**
+     * If you do not specify a url then you must handle XHR operations on
+     * your own. This type can also be constructed using the Transport alias
+     * for backward compatibility.
+     * @param {string} [url] - The URL to connect to.
+     * @param {object} [options] - Options.
+     */
+    constructor(url?: string, options?: Object);
+
+    /**
+     * Gets the browser specific XmlHttpRequest Object.
+     * @returns {object} the browser XHR interface object
+     */
+    getXmlHttpRequestObject(): Object;
+
+    /**
+     * Sends the current XRH request if the transport was created with a URL and
+     * the async parameter if false. If the transport was not created with a URL
+     * or the async parameter is True or the URL is an empty string, the current 
+     * send buffer is returned.
+     * @param {object} async - If true the current send buffer is returned.
+     * @param {function} callback - Optional async completion callback.
+     * @returns {undefined|string} Nothing or the current send buffer.
+     */
+    flush(async: any, callback?: Function): string;
+
+    /**
+     * Creates a jQuery XHR object to be used for a Thrift server call.
+     * @param {object} client - The Thrift Service client object generated by the IDL compiler.
+     * @param {object} postData - The message to send to the server.
+     * @param {function} args - The function to call if the request succeeds.
+     * @param {function} recv_method - The Thrift Service Client receive method for the call.
+     * @returns {object} A new jQuery XHR object.
+     */
+    jqRequest(client: Object, postData: any, args: Function, recv_method: Function): Object;
+
+    /**
+     * Sets the buffer to use when receiving server responses.
+     * @param {string} buf - The buffer to receive server responses.
+     */
+    setRecvBuffer(buf: string): void;
+
+    /**
+     * Returns true if the transport is open, in browser based JavaScript
+     * this function always returns true.
+     * @returns {boolean} Always True.
+     */
+    isOpen(): boolean;
+
+    /**
+     * Opens the transport connection, in browser based JavaScript
+     * this function is a nop.
+     */
+    open(): void;
+
+    /**
+     * Closes the transport connection, in browser based JavaScript
+     * this function is a nop.
+     */
+    close(): void;
+
+    /**
+     * Returns the specified number of characters from the response
+     * buffer.
+     * @param {number} len - The number of characters to return.
+     * @returns {string} Characters sent by the server.
+     */
+    read(len: number): string;
+
+    /**
+     * Returns the entire response buffer.
+     * @returns {string} Characters sent by the server.
+     */
+    readAll(): string;
+
+    /**
+     * Sets the send buffer to buf.
+     * @param {string} buf - The buffer to send.
+     */
+    write(buf: string): void;
+
+    /**
+     * Returns the send buffer.
+     * @returns {string} The send buffer.
+     */
+    getSendBuffer(): string;
+  }
+
+  /**
+   * Old alias of the TXHRTransport for backwards compatibility.
+   */
+  class Transport extends TXHRTransport { }
+
+  /**
+   * The Apache Thrift Transport layer performs byte level I/O 
+   * between RPC clients and servers. The JavaScript TWebSocketTransport object 
+   * uses the WebSocket protocol. Target servers must implement WebSocket.
+   */
+  class TWebSocketTransport {
+    url: string;           //Where to connect
+    socket: any;           //The web socket
+    callbacks: Function[]; //Pending callbacks
+    send_pending: any[];   //Buffers/Callback pairs waiting to be sent
+    send_buf: string;      //Outbound data, immutable until sent
+    recv_buf: string;      //Inbound data
+    rb_wpos: number;       //Network write position in receive buffer
+    rb_rpos: number;       //Client read position in receive buffer
+
+    /**
+     * Constructor Function for the WebSocket transport.
+     * @param {string } [url] - The URL to connect to.
+     */
+    constructor(url: string);
+
+    __reset(url: string): void;
+
+    /**
+     * Sends the current WS request and registers callback. The async 
+     * parameter is ignored (WS flush is always async) and the callback 
+     * function parameter is required.
+     * @param {object} async - Ignored.
+     * @param {function} callback - The client completion callback.
+     * @returns {undefined|string} Nothing (undefined) 
+     */
+    flush(async: any, callback: Function): string;
+
+    __onOpen(): void;
+
+    __onClose(): void;
+
+    __onMessage(): void;
+
+    __onError(): void;
+
+    /**
+     * Sets the buffer to use when receiving server responses.
+     * @param {string} buf - The buffer to receive server responses.
+     */
+    setRecvBuffer(buf: string): void;
+
+    /**
+     * Returns true if the transport is open
+     * @returns {boolean} 
+     */
+    isOpen(): boolean;
+
+    /**
+     * Opens the transport connection
+     */
+    open(): void;
+
+    /**
+     * Closes the transport connection
+     */
+    close(): void;
+
+    /**
+     * Returns the specified number of characters from the response
+     * buffer.
+     * @param {number} len - The number of characters to return.
+     * @returns {string} Characters sent by the server.
+     */
+    read(len: number): string;
+
+    /**
+     * Returns the entire response buffer.
+     * @returns {string} Characters sent by the server.
+     */
+    readAll(): string;
+
+    /**
+     * Sets the send buffer to buf.
+     * @param {string} buf - The buffer to send.
+     */
+    write(buf: string): void;
+
+    /**
+     * Returns the send buffer.
+     * @returns {string} The send buffer.
+     */
+    getSendBuffer(): string;
+  }
+
+  /**
+   * Apache Thrift Protocols perform serialization which enables cross 
+   * language RPC. The Protocol type is the JavaScript browser implementation 
+   * of the Apache Thrift TJSONProtocol.
+   */
+  class TJSONProtocol {
+    transport: Object;
+
+    /**
+     * Thrift IDL type Id to string mapping.
+     * The mapping table looks as follows:
+     * Thrift.Type.BOOL   -> "tf": True/False integer.
+     * Thrift.Type.BYTE   -> "i8": Signed 8 bit integer.
+     * Thrift.Type.I16    -> "i16": Signed 16 bit integer.
+     * Thrift.Type.I32    -> "i32": Signed 32 bit integer.
+     * Thrift.Type.I64    -> "i64": Signed 64 bit integer.
+     * Thrift.Type.DOUBLE -> "dbl": 64 bit IEEE 854 floating point.
+     * Thrift.Type.STRUCT -> "rec": A multifield type.
+     * Thrift.Type.STRING -> "str": Array of bytes representing a string of characters.
+     * Thrift.Type.MAP    -> "map": A collection type (map/associative-array/dictionary).
+     * Thrift.Type.LIST   -> "lst": A collection type (unordered).
+     * Thrift.Type.SET    -> "set": A collection type (unordered and without repeated values).
+     */
+    Type: { [k: number]: string };
+
+    /**
+     * Thrift IDL type string to Id mapping.
+     * The mapping table looks as follows:
+     * "tf"  -> Thrift.Type.BOOL  
+     * "i8"  -> Thrift.Type.BYTE  
+     * "i16" -> Thrift.Type.I16   
+     * "i32" -> Thrift.Type.I32   
+     * "i64" -> Thrift.Type.I64   
+     * "dbl" -> Thrift.Type.DOUBLE
+     * "rec" -> Thrift.Type.STRUCT
+     * "str" -> Thrift.Type.STRING
+     * "map" -> Thrift.Type.MAP   
+     * "lst" -> Thrift.Type.LIST  
+     * "set" -> Thrift.Type.SET   
+     */
+    RType: { [k: string]: number };
+
+    /**
+     * The TJSONProtocol version number.
+     */
+    Version: number;
+
+    /**
+     * Initializes a Thrift JSON protocol instance.
+     * @param {Thrift.Transport} transport - The transport to serialize to/from.
+     */
+    constructor(transport: Object);
+
+    /**
+     * Returns the underlying transport.
+     * @returns {Thrift.Transport} The underlying transport.
+     */
+    getTransport(): Object;
+
+    /**
+     * Serializes the beginning of a Thrift RPC message.
+     * @param {string} name - The service method to call.
+     * @param {Thrift.MessageType} messageType - The type of method call.
+     * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift).
+     */
+    writeMessageBegin(name: string, messageType: number, seqid: number): void;
+
+    /**
+     * Serializes the end of a Thrift RPC message.
+     */
+    writeMessageEnd(): void;
+
+    /**
+     * Serializes the beginning of a struct.
+     * @param {string} name - The name of the struct.
+     */
+    writeStructBegin(name?: string): void;
+
+    /**
+     * Serializes the end of a struct.
+     */
+    writeStructEnd(): void;
+
+    /**
+     * Serializes the beginning of a struct field.
+     * @param {string} name - The name of the field.
+     * @param {Thrift.Protocol.Type} fieldType - The data type of the field.
+     * @param {number} fieldId - The field's unique identifier.
+     */
+    writeFieldBegin(name: string, fieldType: number, fieldId: number): void;
+
+    /**
+     * Serializes the end of a field.
+     */
+    writeFieldEnd(): void;
+
+    /**
+     * Serializes the end of the set of fields for a struct.
+     */
+    writeFieldStop(): void;
+
+    /**
+     * Serializes the beginning of a map collection.
+     * @param {Thrift.Type} keyType - The data type of the key.
+     * @param {Thrift.Type} valType - The data type of the value.
+     * @param {number} [size] - The number of elements in the map (ignored).
+     */
+    writeMapBegin(keyType: number, valType: number, size?: number): void;
+
+    /**
+     * Serializes the end of a map.
+     */
+    writeMapEnd(): void;
+
+    /**
+     * Serializes the beginning of a list collection.
+     * @param {Thrift.Type} elemType - The data type of the elements.
+     * @param {number} size - The number of elements in the list.
+     */
+    writeListBegin(elemType: number, size: number): void;
+
+    /**
+     * Serializes the end of a list.
+     */
+    writeListEnd(): void;
+
+    /**
+     * Serializes the beginning of a set collection.
+     * @param {Thrift.Type} elemType - The data type of the elements.
+     * @param {number} size - The number of elements in the list.
+     */
+    writeSetBegin(elemType: number, size: number): void;
+
+    /**
+     * Serializes the end of a set.
+     */
+    writeSetEnd(): void;
+
+    /** Serializes a boolean */
+    writeBool(value: boolean): void;
+
+    /** Serializes a number */
+    writeByte(i8: number): void;
+
+    /** Serializes a number */
+    writeI16(i16: number): void;
+
+    /** Serializes a number */
+    writeI32(i32: number): void;
+
+    /** Serializes a number */
+    writeI64(i64: number): void;
+
+    /** Serializes a number */
+    writeDouble(dbl: number): void;
+
+    /** Serializes a string */
+    writeString(str: string): void;
+
+    /** Serializes a string */
+    writeBinary(str: string): void;
+
+    /**
+       @class
+       @name AnonReadMessageBeginReturn
+       @property {string} fname - The name of the service method.
+       @property {Thrift.MessageType} mtype - The type of message call.
+       @property {number} rseqid - The sequence number of the message (0 in Thrift RPC).
+     */
+    /** 
+     * Deserializes the beginning of a message. 
+     * @returns {AnonReadMessageBeginReturn}
+     */
+    readMessageBegin(): { fname: string; mtype: number; rseqid: number };
+
+    /** Deserializes the end of a message. */
+    readMessageEnd(): void;
+
+    /** 
+     * Deserializes the beginning of a struct. 
+     * @param {string} [name] - The name of the struct (ignored).
+     * @returns {object} - An object with an empty string fname property.
+     */
+    readStructBegin(name?: string): { fname: string };
+
+    /** Deserializes the end of a struct. */
+    readStructEnd(): void;
+
+    /**
+       @class
+       @name AnonReadFieldBeginReturn
+       @property {string} fname - The name of the field (always '').
+       @property {Thrift.Type} ftype - The data type of the field.
+       @property {number} fid - The unique identifier of the field.
+     */
+    /** 
+     * Deserializes the beginning of a field. 
+     * @returns {AnonReadFieldBeginReturn}
+     */
+    readFieldBegin(): { fname: string; ftype: number; fid: number };
+
+    /** Deserializes the end of a field. */
+    readFieldEnd(): void;
+
+    /**
+       @class
+       @name AnonReadMapBeginReturn
+       @property {Thrift.Type} ktype - The data type of the key.
+       @property {Thrift.Type} vtype - The data type of the value.
+       @property {number} size - The number of elements in the map.
+     */
+    /** 
+     * Deserializes the beginning of a map. 
+     * @returns {AnonReadMapBeginReturn}
+     */
+    readMapBegin(): { ktype: number; vtype: number; size: number };
+
+    /** Deserializes the end of a map. */
+    readMapEnd(): void;
+
+    /**
+       @class
+       @name AnonReadColBeginReturn
+       @property {Thrift.Type} etype - The data type of the element.
+       @property {number} size - The number of elements in the collection.
+     */
+    /** 
+     * Deserializes the beginning of a list. 
+     * @returns {AnonReadColBeginReturn}
+     */
+    readListBegin(): { etype: number; size: number };
+
+    /** Deserializes the end of a list. */
+    readListEnd(): void;
+
+    /** 
+     * Deserializes the beginning of a set. 
+     * @param {Thrift.Type} elemType - The data type of the elements (ignored).
+     * @param {number} size - The number of elements in the list (ignored).
+     * @returns {AnonReadColBeginReturn}
+     */
+    readSetBegin(elemType?: number, size?: number): { etype: number; size: number };
+
+    /** Deserializes the end of a set. */
+    readSetEnd(): void;
+
+    /** Returns an object with a value property set to 
+     *  False unless the next number in the protocol buffer 
+     *  is 1, in which case the value property is True. */
+    readBool(): Object;
+
+    /** Returns an object with a value property set to the 
+        next value found in the protocol buffer. */
+    readByte(): Object;
+
+    /** Returns an object with a value property set to the 
+        next value found in the protocol buffer. */
+    readI16(): Object;
+
+    /** Returns an object with a value property set to the 
+        next value found in the protocol buffer. */
+    readI32(f?: any): Object;
+
+    /** Returns an object with a value property set to the 
+        next value found in the protocol buffer. */
+    readI64(): Object;
+
+    /** Returns an object with a value property set to the 
+        next value found in the protocol buffer. */
+    readDouble(): Object;
+
+    /** Returns an object with a value property set to the 
+        next value found in the protocol buffer. */
+    readString(): Object;
+
+    /** Returns an object with a value property set to the 
+        next value found in the protocol buffer. */
+    readBinary(): Object;
+
+    /** 
+     * Method to arbitrarily skip over data (not implemented).
+     */
+    skip(type: number): void;
+  }
+
+  /**
+   * Old alias of the TXHRTransport for backwards compatibility.
+   */
+  class Protocol extends TJSONProtocol { }
+
+  class MultiplexProtocol extends TJSONProtocol {
+    serviceName: string;
+
+    /**
+     * Initializes a MutilplexProtocol Implementation as a Wrapper for Thrift.Protocol.
+     * @param {string} srvName
+     * @param {Thrift.Transport} trans
+     * @param {any} [strictRead]
+     * @param {any} [strictWrite]
+     */
+    constructor(srvName: string, trans: Object, strictRead?: any, strictWrite?: any);
+
+    /**
+     * Override writeMessageBegin method of prototype
+     * Serializes the beginning of a Thrift RPC message.
+     * @param {string} name - The service method to call.
+     * @param {Thrift.MessageType} messageType - The type of method call.
+     * @param {number} seqid - The sequence number of this call (always 0 in Apache Thrift).
+     */
+    writeMessageBegin(name: string, type: number, seqid: number): void;
+  }
+
+  class Multiplexer {
+    seqid: number;
+
+    /**
+     * Instantiates a multiplexed client for a specific service.
+     * @param {String} serviceName - The transport to serialize to/from.
+     * @param {Thrift.ServiceClient} SCl - The Service Client Class.
+     * @param {Thrift.Transport} transport - Thrift.Transport instance which provides remote host:port.
+     */
+    createClient(serviceName: string, SCl: any, transport: Object): any;
+  }
+}
diff --git a/lib/xml/Makefile.am b/lib/xml/Makefile.am
new file mode 100644
index 0000000..bcad6bd
--- /dev/null
+++ b/lib/xml/Makefile.am
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+
+SUBDIRS =
+
+if WITH_JAVA
+# Schema validation test depends on java
+SUBDIRS += test
+endif
+
+EXTRA_DIST = \
+  thrift-idl.xsd \
+  test
diff --git a/lib/xml/test/Makefile.am b/lib/xml/test/Makefile.am
new file mode 100644
index 0000000..bb87a52
--- /dev/null
+++ b/lib/xml/test/Makefile.am
@@ -0,0 +1,26 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+check:
+	$(ANT) $(ANT_FLAGS) test
+
+# Make sure this doesn't fail if ant is not configured.
+clean-local:
+	ANT=$(ANT) ; if test -z "$$ANT" ; then ANT=: ; fi ; \
+	$$ANT $(ANT_FLAGS) clean
diff --git a/lib/xml/test/build.xml b/lib/xml/test/build.xml
new file mode 100644
index 0000000..f0e95cf
--- /dev/null
+++ b/lib/xml/test/build.xml
@@ -0,0 +1,112 @@
+<!--
+ 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.
+-->
+<project name="XML Schema Test" default="test" basedir=".">
+
+  <description>XML Schema Validation Test</description>
+
+  <property name="xml.dir" location="${basedir}/.." />
+  <property name="gen.xml.dir" location="${basedir}/../gen-xml" />
+  <property name="idl.xml.schema" location="${xml.dir}/thrift-idl.xsd" />
+
+  <property name="thrift.dir" location="../../../" />
+  <property name="thrift.test.dir" location="${thrift.dir}/test" />
+  <property name="thrift.compiler" location="${thrift.dir}/compiler/cpp/thrift" />
+
+  <property file="${basedir}/build.properties" />
+
+  <target name="compiler.check">
+    <fail>
+      <condition>
+        <not>
+          <resourcecount count="1">
+            <fileset id="fs" file="${thrift.compiler}"/>
+          </resourcecount>
+        </not>
+      </condition>
+      Thrift compiler is missing !
+    </fail>
+  </target>
+
+  <target name="init" depends="compiler.check, mkdirs">
+    <tstamp />
+  </target>
+
+  <target name="mkdirs">
+    <mkdir dir="${gen.xml.dir}"/>
+  </target>
+
+  <target name="generate" depends="init">
+    <generate-xml file="${thrift.test.dir}/ThriftTest.thrift"/>
+    <generate-xml file="${thrift.test.dir}/Include.thrift"/>
+    <generate-xml file="${thrift.test.dir}/Recursive.thrift"/>
+    <generate-xml file="${thrift.test.dir}/ManyOptionals.thrift"/>
+    <generate-xml file="${thrift.test.dir}/OptionalRequiredTest.thrift"/>
+    <generate-xml file="${thrift.test.dir}/ConstantsDemo.thrift"/>
+    <generate-xml file="${thrift.test.dir}/TypedefTest.thrift" />
+    <generate-xml file="${thrift.test.dir}/AnnotationTest.thrift" />
+    <generate-xml file="${thrift.test.dir}/DocTest.thrift" />
+    <generate-xml file="${thrift.test.dir}/EnumTest.thrift" />
+    <generate-xml file="${thrift.test.dir}/ManyTypedefs.thrift" />
+  </target>
+
+  <target name="test" description="run schema validation"
+          depends="validate-generated-xml"/>
+    
+  <target name="validate-generated-xml" depends="init, generate">
+    <validate-xml file="${gen.xml.dir}/ThriftTest.xml"/>
+    <validate-xml file="${gen.xml.dir}/Include.xml"/>
+    <validate-xml file="${gen.xml.dir}/Recursive.xml"/>
+    <validate-xml file="${gen.xml.dir}/ManyOptionals.xml"/>
+    <validate-xml file="${gen.xml.dir}/OptionalRequiredTest.xml"/>
+    <validate-xml file="${gen.xml.dir}/ConstantsDemo.xml"/>
+    <validate-xml file="${gen.xml.dir}/TypedefTest.xml"/>
+    <validate-xml file="${gen.xml.dir}/AnnotationTest.xml"/>
+    <validate-xml file="${gen.xml.dir}/DocTest.xml"/>
+    <validate-xml file="${gen.xml.dir}/EnumTest.xml"/>
+    <validate-xml file="${gen.xml.dir}/ManyTypedefs.xml"/>
+  </target>
+
+  <target name="clean">
+    <delete dir="${build.dir}" />
+    <delete dir="${gen.xml.dir}" />
+  </target>
+
+  <macrodef name="generate-xml">
+    <attribute name="file" />
+    <sequential>
+      <exec executable="${thrift.compiler}" failonerror="true">
+        <arg line="-gen xml:merge"/>
+        <arg line="-out ${gen.xml.dir}"/>
+        <arg line="@{file}"/>
+      </exec>
+    </sequential>
+  </macrodef>
+
+  <macrodef name="validate-xml">
+    <attribute name="file" />
+    <sequential>
+      <echo message="validating generated XML: @{file}" />
+      <schemavalidate file="@{file}">
+        <schema namespace="http://thrift.apache.org/xml/idl" 
+                file="${idl.xml.schema}" />
+      </schemavalidate>
+    </sequential>
+  </macrodef>
+
+</project>
diff --git a/lib/xml/thrift-idl.xsd b/lib/xml/thrift-idl.xsd
new file mode 100644
index 0000000..09dd695
--- /dev/null
+++ b/lib/xml/thrift-idl.xsd
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+        targetNamespace="http://thrift.apache.org/xml/idl" 
+        xmlns:tns="http://thrift.apache.org/xml/idl" 
+        elementFormDefault="qualified">
+
+  <element name="idl" type="tns:IDL" />
+  <element name="document" type="tns:Document" />
+
+  <complexType name="IDL">
+    <sequence>
+      <element ref="tns:document" minOccurs="1" maxOccurs="unbounded"/>
+    </sequence>
+  </complexType>
+
+  <complexType name="Document">
+    <sequence>
+      <choice minOccurs="0" maxOccurs="unbounded">
+        <element name="include" type="tns:Include" />
+        <element name="namespace" type="tns:Namespace" />
+      </choice>
+      <choice minOccurs="0" maxOccurs="unbounded">
+        <element name="exception" type="tns:Exception" />
+        <element name="typedef" type="tns:Typedef" />
+        <element name="service" type="tns:Service" />
+        <element name="struct" type="tns:Struct" />
+        <element name="const" type="tns:Const" />
+        <element name="union" type="tns:Union" />
+        <element name="enum" type="tns:Enum" />
+      </choice>
+    </sequence>
+    <attribute name="name" type="string" use="required" />
+    <attribute name="targetNamespace" type="anyURI" use="optional" />
+    <attribute name="doc" type="string" use="optional" />
+  </complexType>
+
+  <complexType name="Include">
+    <attribute name="file" type="string" use="optional" />
+    <attribute name="name" type="string" use="required" />
+  </complexType>
+
+  <complexType name="Namespace">
+    <sequence>
+      <element name="annotation" type="tns:Annotation" 
+               minOccurs="0" maxOccurs="unbounded" />
+    </sequence>
+    <attribute name="name" type="string" use="required" />
+    <attribute name="value" type="string" use="required" />
+    <attribute name="doc" type="string" use="optional" />
+  </complexType>
+
+  <group name="AbstractStruct">
+    <sequence>
+      <element name="field" type="tns:Field" 
+               minOccurs="0" maxOccurs="unbounded" />
+      <element name="annotation" type="tns:Annotation" 
+               minOccurs="0" maxOccurs="unbounded" />
+    </sequence>
+  </group>
+
+  <attributeGroup name="StructAttributes">
+    <attribute name="name" type="string" use="required" />
+    <attribute name="doc" type="string" use="optional" />
+  </attributeGroup>
+
+  <complexType name="Exception">
+    <group ref="tns:AbstractStruct" />
+    <attributeGroup ref="tns:StructAttributes" />
+  </complexType>
+
+  <complexType name="Service">
+    <sequence>
+      <element name="method" type="tns:Method" 
+               minOccurs="0" maxOccurs="unbounded" />
+      <element name="annotation" type="tns:Annotation" 
+               minOccurs="0" maxOccurs="unbounded" />
+    </sequence>
+    <attribute name="name" type="string" use="required" />
+    <attribute name="targetNamespace" type="string" use="required" />
+    <attribute name="parent-module" type="string" use="optional" />
+    <attribute name="parent-id" type="string" use="optional" /> 
+    <attribute name="doc" type="string" use="optional" />
+  </complexType>
+
+  <complexType name="Method">
+    <sequence>
+      <element name="returns" type="tns:ThriftType" />
+      <element name="arg" type="tns:Field" 
+               minOccurs="0" maxOccurs="unbounded" />
+      <element name="throws" type="tns:Field" 
+               minOccurs="0" maxOccurs="unbounded" />
+      <element name="annotation" type="tns:Annotation" 
+               minOccurs="0" maxOccurs="unbounded" />
+    </sequence>
+    <attribute name="name" type="string" use="required" />
+    <attribute name="oneway" type="boolean" use="optional" />
+    <attribute name="doc" type="string" use="optional" />
+  </complexType>
+
+  <complexType name="Typedef">
+    <complexContent>
+      <extension base="tns:ThriftType">
+        <sequence>
+          <element name="annotation" type="tns:Annotation" 
+                   minOccurs="0" maxOccurs="unbounded" />
+        </sequence>
+        <attribute name="name" type="string" use="required" />
+        <attribute name="doc" type="string" use="optional" />
+      </extension>
+    </complexContent>
+  </complexType>
+
+  <complexType name="Struct">
+    <group ref="tns:AbstractStruct" />
+    <attributeGroup ref="tns:StructAttributes" />
+  </complexType>
+
+  <complexType name="Union">
+    <group ref="tns:AbstractStruct" />
+    <attributeGroup ref="tns:StructAttributes" />
+  </complexType>
+
+  <complexType name="Enum">
+    <sequence>
+      <element name="member" minOccurs="1" maxOccurs="unbounded">
+        <complexType>
+          <sequence>
+            <element name="annotation" type="tns:Annotation" 
+                     minOccurs="0" maxOccurs="unbounded" />
+          </sequence>
+          <attribute name="name" type="string" use="required" />
+          <attribute name="value" type="int" />
+          <attribute name="explicit" type="boolean" />
+          <attribute name="doc" type="string" />
+        </complexType>
+      </element>
+      <element name="annotation" type="tns:Annotation" 
+                minOccurs="0" maxOccurs="unbounded" />
+    </sequence>
+    <attribute name="name" type="string" use="required" />
+    <attribute name="doc" type="string" />
+  </complexType>
+
+  <complexType name="Field">
+    <complexContent>
+      <extension base="tns:ThriftType">
+        <sequence>
+          <element name="default" minOccurs="0" maxOccurs="1">
+            <complexType>
+              <group ref="tns:ConstValue" />
+            </complexType>
+          </element>
+          <element name="annotation" type="tns:Annotation" 
+                   minOccurs="0" maxOccurs="unbounded" />
+        </sequence>
+        <attribute name="field-id" type="long" />
+        <attribute name="name" type="string" use="required" />
+        <attribute name="required" type="tns:Requiredness" />
+        <attribute name="doc" type="string" />
+      </extension>
+    </complexContent>
+  </complexType>
+
+  <simpleType name="Requiredness">
+    <restriction base="string">
+      <enumeration value="required" />
+      <enumeration value="optional" />
+    </restriction>
+  </simpleType>
+
+  <complexType name="Annotation">
+    <attribute name="key" type="string" />
+    <attribute name="value" type="string" />
+  </complexType>
+
+  <complexType name="Const">
+    <complexContent>
+      <extension base="tns:ThriftType">
+        <sequence>
+          <group ref="tns:ConstValue" />
+        </sequence>
+        <attribute name="name" type="string" use="required" />
+        <attribute name="doc" type="string" />
+      </extension>
+    </complexContent>
+  </complexType>
+
+  <complexType name="ConstList">
+    <sequence>
+      <element name="entry" minOccurs="0" maxOccurs="unbounded">
+        <complexType>
+          <group ref="tns:ConstValue" />
+        </complexType>
+      </element>
+    </sequence>
+  </complexType>
+
+  <complexType name="ConstMap">
+    <sequence>
+      <element name="entry" minOccurs="0" maxOccurs="unbounded">
+        <complexType>
+          <sequence>
+            <element name="key">
+              <complexType>
+                <group ref="tns:ConstValue" />
+              </complexType>
+            </element>
+            <element name="value">
+              <complexType>
+                <group ref="tns:ConstValue" />
+              </complexType>
+            </element>
+          </sequence>
+        </complexType>
+      </element>
+    </sequence>
+  </complexType>
+
+  <group name="ConstValue">
+    <choice>
+      <element name="string" type="string" />
+      <element name="double" type="double" />
+      <element name="list" type="tns:ConstList" />
+      <element name="map" type="tns:ConstMap" />
+      <element name="int" type="long" />
+    </choice>
+  </group>
+
+  <complexType name="ThriftType">
+    <sequence>
+      <choice minOccurs="0" maxOccurs="1">
+        <element name="elemType" type="tns:ThriftType" />
+        <sequence>
+          <element name="keyType" type="tns:ThriftType" 
+                   minOccurs="1" maxOccurs="1" />
+          <element name="valueType" type="tns:ThriftType" 
+                   minOccurs="1" maxOccurs="1" />
+        </sequence>
+      </choice>
+    </sequence>
+    <attribute name="type" type="tns:TypeIdentifier" use="required" />
+    <attribute name="type-module" type="string" />
+    <attribute name="type-id" type="string" />
+  </complexType>
+
+  <simpleType name="TypeIdentifier">
+    <restriction base="string">
+      <enumeration value="void" />
+      <enumeration value="bool" />
+      <enumeration value="byte" />
+      <enumeration value="i8" />
+      <enumeration value="i16" />
+      <enumeration value="i32" />
+      <enumeration value="i64" />
+      <enumeration value="double" />
+      <enumeration value="binary" />
+      <enumeration value="string" />
+      <enumeration value="id" />
+      <enumeration value="map" />
+      <enumeration value="set" />
+      <enumeration value="list" />
+    </restriction>
+  </simpleType>
+
+</schema>
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..b265aa6
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,2183 @@
+{
+  "name": "thrift",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "@babel/code-frame": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
+      "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
+      "dev": true,
+      "requires": {
+        "@babel/highlight": "^7.0.0"
+      }
+    },
+    "@babel/highlight": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
+      "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.0.0",
+        "esutils": "^2.0.2",
+        "js-tokens": "^4.0.0"
+      }
+    },
+    "@types/node": {
+      "version": "10.12.6",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.6.tgz",
+      "integrity": "sha512-+ZWB5Ec1iki99xQFzBlivlKxSZQ+fuUKBott8StBOnLN4dWbRHlgdg1XknpW6g0tweniN5DcOqA64CJyOUPSAw==",
+      "dev": true
+    },
+    "@types/q": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.1.tgz",
+      "integrity": "sha512-eqz8c/0kwNi/OEHQfvIuJVLTst3in0e7uTKeuY+WL/zfKn0xVujOTp42bS/vUUokhK5P2BppLd9JXMOMHcgbjA==",
+      "dev": true
+    },
+    "abbrev": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz",
+      "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=",
+      "dev": true
+    },
+    "acorn": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.2.tgz",
+      "integrity": "sha512-GXmKIvbrN3TV7aVqAzVFaMW8F8wzVX7voEBRO3bDA64+EX37YSayggRJP5Xig6HYHBkWKpFg9W5gg6orklubhg==",
+      "dev": true
+    },
+    "acorn-jsx": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.0.tgz",
+      "integrity": "sha512-XkB50fn0MURDyww9+UYL3c1yLbOBz0ZFvrdYlGB8l+Ije1oSC75qAqrzSPjYQbdnQUzhlUGNKuesryAv0gxZOg==",
+      "dev": true
+    },
+    "ajv": {
+      "version": "6.5.4",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz",
+      "integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==",
+      "dev": true,
+      "requires": {
+        "fast-deep-equal": "^2.0.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      }
+    },
+    "amdefine": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+      "dev": true,
+      "optional": true
+    },
+    "ansi-escapes": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
+      "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==",
+      "dev": true
+    },
+    "ansi-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+      "dev": true
+    },
+    "ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "requires": {
+        "color-convert": "^1.9.0"
+      }
+    },
+    "aproba": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+      "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+      "dev": true
+    },
+    "are-we-there-yet": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+      "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+      "dev": true,
+      "requires": {
+        "delegates": "^1.0.0",
+        "readable-stream": "^2.0.6"
+      }
+    },
+    "argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "requires": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "array-union": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+      "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+      "dev": true,
+      "requires": {
+        "array-uniq": "^1.0.1"
+      }
+    },
+    "array-uniq": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+      "dev": true
+    },
+    "arrify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+      "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+      "dev": true
+    },
+    "async": {
+      "version": "1.5.2",
+      "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz",
+      "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+      "dev": true
+    },
+    "async-limiter": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
+      "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
+    },
+    "babylon": {
+      "version": "7.0.0-beta.19",
+      "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz",
+      "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==",
+      "dev": true
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "dev": true
+    },
+    "bindings": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz",
+      "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==",
+      "dev": true
+    },
+    "bl": {
+      "version": "1.2.2",
+      "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
+      "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.3.5",
+        "safe-buffer": "^5.1.1"
+      }
+    },
+    "bluebird": {
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz",
+      "integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg==",
+      "dev": true
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "buffer-alloc": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
+      "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
+      "dev": true,
+      "requires": {
+        "buffer-alloc-unsafe": "^1.1.0",
+        "buffer-fill": "^1.0.0"
+      }
+    },
+    "buffer-alloc-unsafe": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
+      "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
+      "dev": true
+    },
+    "buffer-equals": {
+      "version": "1.0.4",
+      "resolved": "http://registry.npmjs.org/buffer-equals/-/buffer-equals-1.0.4.tgz",
+      "integrity": "sha1-A1O1T9B/2VZBcGca5vZrnPENJ/U=",
+      "dev": true
+    },
+    "buffer-fill": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
+      "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=",
+      "dev": true
+    },
+    "caller-path": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
+      "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
+      "dev": true,
+      "requires": {
+        "callsites": "^0.2.0"
+      }
+    },
+    "callsites": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
+      "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
+      "dev": true
+    },
+    "catharsis": {
+      "version": "0.8.9",
+      "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz",
+      "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=",
+      "dev": true,
+      "requires": {
+        "underscore-contrib": "~0.3.0"
+      }
+    },
+    "chalk": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+      "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      }
+    },
+    "chardet": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+      "dev": true
+    },
+    "chownr": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
+      "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
+      "dev": true
+    },
+    "circular-json": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
+      "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
+      "dev": true
+    },
+    "cli-cursor": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+      "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+      "dev": true,
+      "requires": {
+        "restore-cursor": "^2.0.0"
+      }
+    },
+    "cli-width": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+      "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
+      "dev": true
+    },
+    "code-point-at": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+      "dev": true
+    },
+    "color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "requires": {
+        "color-name": "1.1.3"
+      }
+    },
+    "color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+      "dev": true
+    },
+    "commander": {
+      "version": "2.19.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
+      "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==",
+      "dev": true
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "connect": {
+      "version": "3.6.6",
+      "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz",
+      "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=",
+      "dev": true,
+      "requires": {
+        "debug": "2.6.9",
+        "finalhandler": "1.1.0",
+        "parseurl": "~1.3.2",
+        "utils-merge": "1.0.1"
+      }
+    },
+    "console-control-strings": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+      "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
+      "dev": true
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
+    },
+    "cross-spawn": {
+      "version": "6.0.5",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+      "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+      "dev": true,
+      "requires": {
+        "nice-try": "^1.0.4",
+        "path-key": "^2.0.1",
+        "semver": "^5.5.0",
+        "shebang-command": "^1.2.0",
+        "which": "^1.2.9"
+      }
+    },
+    "debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "requires": {
+        "ms": "2.0.0"
+      }
+    },
+    "decompress-response": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
+      "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
+      "dev": true,
+      "requires": {
+        "mimic-response": "^1.0.0"
+      }
+    },
+    "deep-equal": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
+      "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
+      "dev": true
+    },
+    "deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+      "dev": true
+    },
+    "deep-is": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+      "dev": true
+    },
+    "define-properties": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+      "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+      "dev": true,
+      "requires": {
+        "object-keys": "^1.0.12"
+      }
+    },
+    "defined": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+      "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
+      "dev": true
+    },
+    "del": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
+      "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
+      "dev": true,
+      "requires": {
+        "globby": "^5.0.0",
+        "is-path-cwd": "^1.0.0",
+        "is-path-in-cwd": "^1.0.0",
+        "object-assign": "^4.0.1",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0",
+        "rimraf": "^2.2.8"
+      }
+    },
+    "delegates": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+      "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+      "dev": true
+    },
+    "detect-libc": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+      "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
+      "dev": true
+    },
+    "doctrine": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+      "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+      "dev": true,
+      "requires": {
+        "esutils": "^2.0.2"
+      }
+    },
+    "ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+      "dev": true
+    },
+    "encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+      "dev": true
+    },
+    "end-of-stream": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
+      "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+      "dev": true,
+      "requires": {
+        "once": "^1.4.0"
+      }
+    },
+    "es-abstract": {
+      "version": "1.12.0",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
+      "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
+      "dev": true,
+      "requires": {
+        "es-to-primitive": "^1.1.1",
+        "function-bind": "^1.1.1",
+        "has": "^1.0.1",
+        "is-callable": "^1.1.3",
+        "is-regex": "^1.0.4"
+      }
+    },
+    "es-to-primitive": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
+      "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
+      "dev": true,
+      "requires": {
+        "is-callable": "^1.1.4",
+        "is-date-object": "^1.0.1",
+        "is-symbol": "^1.0.2"
+      }
+    },
+    "escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+      "dev": true
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "dev": true
+    },
+    "escodegen": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz",
+      "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=",
+      "dev": true,
+      "requires": {
+        "esprima": "^2.7.1",
+        "estraverse": "^1.9.1",
+        "esutils": "^2.0.2",
+        "optionator": "^0.8.1",
+        "source-map": "~0.2.0"
+      },
+      "dependencies": {
+        "esprima": {
+          "version": "2.7.3",
+          "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+          "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+          "dev": true
+        },
+        "estraverse": {
+          "version": "1.9.3",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz",
+          "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=",
+          "dev": true
+        }
+      }
+    },
+    "eslint": {
+      "version": "5.7.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.7.0.tgz",
+      "integrity": "sha512-zYCeFQahsxffGl87U2aJ7DPyH8CbWgxBC213Y8+TCanhUTf2gEvfq3EKpHmEcozTLyPmGe9LZdMAwC/CpJBM5A==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.0.0",
+        "ajv": "^6.5.3",
+        "chalk": "^2.1.0",
+        "cross-spawn": "^6.0.5",
+        "debug": "^4.0.1",
+        "doctrine": "^2.1.0",
+        "eslint-scope": "^4.0.0",
+        "eslint-utils": "^1.3.1",
+        "eslint-visitor-keys": "^1.0.0",
+        "espree": "^4.0.0",
+        "esquery": "^1.0.1",
+        "esutils": "^2.0.2",
+        "file-entry-cache": "^2.0.0",
+        "functional-red-black-tree": "^1.0.1",
+        "glob": "^7.1.2",
+        "globals": "^11.7.0",
+        "ignore": "^4.0.6",
+        "imurmurhash": "^0.1.4",
+        "inquirer": "^6.1.0",
+        "is-resolvable": "^1.1.0",
+        "js-yaml": "^3.12.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.3.0",
+        "lodash": "^4.17.5",
+        "minimatch": "^3.0.4",
+        "mkdirp": "^0.5.1",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.8.2",
+        "path-is-inside": "^1.0.2",
+        "pluralize": "^7.0.0",
+        "progress": "^2.0.0",
+        "regexpp": "^2.0.1",
+        "require-uncached": "^1.0.3",
+        "semver": "^5.5.1",
+        "strip-ansi": "^4.0.0",
+        "strip-json-comments": "^2.0.1",
+        "table": "^5.0.2",
+        "text-table": "^0.2.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
+          "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "ms": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+          "dev": true
+        }
+      }
+    },
+    "eslint-config-prettier": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-3.1.0.tgz",
+      "integrity": "sha512-QYGfmzuc4q4J6XIhlp8vRKdI/fI0tQfQPy1dME3UOLprE+v4ssH/3W9LM2Q7h5qBcy5m0ehCrBDU2YF8q6OY8w==",
+      "dev": true,
+      "requires": {
+        "get-stdin": "^6.0.0"
+      }
+    },
+    "eslint-plugin-prettier": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.0.tgz",
+      "integrity": "sha512-4g11opzhqq/8+AMmo5Vc2Gn7z9alZ4JqrbZ+D4i8KlSyxeQhZHlmIrY8U9Akf514MoEhogPa87Jgkq87aZ2Ohw==",
+      "dev": true,
+      "requires": {
+        "prettier-linter-helpers": "^1.0.0"
+      }
+    },
+    "eslint-scope": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz",
+      "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==",
+      "dev": true,
+      "requires": {
+        "esrecurse": "^4.1.0",
+        "estraverse": "^4.1.1"
+      }
+    },
+    "eslint-utils": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz",
+      "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==",
+      "dev": true
+    },
+    "eslint-visitor-keys": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
+      "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==",
+      "dev": true
+    },
+    "espree": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz",
+      "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==",
+      "dev": true,
+      "requires": {
+        "acorn": "^6.0.2",
+        "acorn-jsx": "^5.0.0",
+        "eslint-visitor-keys": "^1.0.0"
+      }
+    },
+    "esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true
+    },
+    "esquery": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
+      "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^4.0.0"
+      }
+    },
+    "esrecurse": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+      "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^4.1.0"
+      }
+    },
+    "estraverse": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+      "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+      "dev": true
+    },
+    "esutils": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+      "dev": true
+    },
+    "expand-template": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.1.tgz",
+      "integrity": "sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg==",
+      "dev": true
+    },
+    "external-editor": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
+      "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
+      "dev": true,
+      "requires": {
+        "chardet": "^0.7.0",
+        "iconv-lite": "^0.4.24",
+        "tmp": "^0.0.33"
+      }
+    },
+    "fast-deep-equal": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+      "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+      "dev": true
+    },
+    "fast-diff": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
+      "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
+      "dev": true
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
+      "dev": true
+    },
+    "fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+      "dev": true
+    },
+    "figures": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+      "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+      "dev": true,
+      "requires": {
+        "escape-string-regexp": "^1.0.5"
+      }
+    },
+    "file-entry-cache": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
+      "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
+      "dev": true,
+      "requires": {
+        "flat-cache": "^1.2.1",
+        "object-assign": "^4.0.1"
+      }
+    },
+    "finalhandler": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz",
+      "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=",
+      "dev": true,
+      "requires": {
+        "debug": "2.6.9",
+        "encodeurl": "~1.0.1",
+        "escape-html": "~1.0.3",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.2",
+        "statuses": "~1.3.1",
+        "unpipe": "~1.0.0"
+      }
+    },
+    "flat-cache": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz",
+      "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=",
+      "dev": true,
+      "requires": {
+        "circular-json": "^0.3.1",
+        "del": "^2.0.2",
+        "graceful-fs": "^4.1.2",
+        "write": "^0.2.1"
+      }
+    },
+    "for-each": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+      "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+      "dev": true,
+      "requires": {
+        "is-callable": "^1.1.3"
+      }
+    },
+    "fs-constants": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+      "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+      "dev": true
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
+    },
+    "functional-red-black-tree": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+      "dev": true
+    },
+    "gauge": {
+      "version": "2.7.4",
+      "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+      "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+      "dev": true,
+      "requires": {
+        "aproba": "^1.0.3",
+        "console-control-strings": "^1.0.0",
+        "has-unicode": "^2.0.0",
+        "object-assign": "^4.1.0",
+        "signal-exit": "^3.0.0",
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1",
+        "wide-align": "^1.1.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+          "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+          "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+          "dev": true,
+          "requires": {
+            "number-is-nan": "^1.0.0"
+          }
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "dev": true,
+          "requires": {
+            "code-point-at": "^1.0.0",
+            "is-fullwidth-code-point": "^1.0.0",
+            "strip-ansi": "^3.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "3.0.1",
+          "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+          "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^2.0.0"
+          }
+        }
+      }
+    },
+    "get-stdin": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
+      "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
+      "dev": true
+    },
+    "github-from-package": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+      "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=",
+      "dev": true
+    },
+    "glob": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+      "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+      "dev": true,
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "globals": {
+      "version": "11.8.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.8.0.tgz",
+      "integrity": "sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA==",
+      "dev": true
+    },
+    "globby": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
+      "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
+      "dev": true,
+      "requires": {
+        "array-union": "^1.0.1",
+        "arrify": "^1.0.0",
+        "glob": "^7.0.3",
+        "object-assign": "^4.0.1",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
+      }
+    },
+    "graceful-fs": {
+      "version": "4.1.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+      "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
+      "dev": true
+    },
+    "handlebars": {
+      "version": "4.0.12",
+      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz",
+      "integrity": "sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==",
+      "dev": true,
+      "requires": {
+        "async": "^2.5.0",
+        "optimist": "^0.6.1",
+        "source-map": "^0.6.1",
+        "uglify-js": "^3.1.4"
+      },
+      "dependencies": {
+        "async": {
+          "version": "2.6.1",
+          "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz",
+          "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==",
+          "dev": true,
+          "requires": {
+            "lodash": "^4.17.10"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1"
+      }
+    },
+    "has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+      "dev": true
+    },
+    "has-symbols": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
+      "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
+      "dev": true
+    },
+    "has-unicode": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+      "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+      "dev": true
+    },
+    "iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "dev": true,
+      "requires": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      }
+    },
+    "ignore": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+      "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+      "dev": true
+    },
+    "imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+      "dev": true
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+      "dev": true
+    },
+    "ini": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+      "dev": true
+    },
+    "inquirer": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz",
+      "integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==",
+      "dev": true,
+      "requires": {
+        "ansi-escapes": "^3.0.0",
+        "chalk": "^2.0.0",
+        "cli-cursor": "^2.1.0",
+        "cli-width": "^2.0.0",
+        "external-editor": "^3.0.0",
+        "figures": "^2.0.0",
+        "lodash": "^4.17.10",
+        "mute-stream": "0.0.7",
+        "run-async": "^2.2.0",
+        "rxjs": "^6.1.0",
+        "string-width": "^2.1.0",
+        "strip-ansi": "^4.0.0",
+        "through": "^2.3.6"
+      }
+    },
+    "is-callable": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
+      "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
+      "dev": true
+    },
+    "is-date-object": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
+      "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
+      "dev": true
+    },
+    "is-fullwidth-code-point": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+      "dev": true
+    },
+    "is-path-cwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
+      "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
+      "dev": true
+    },
+    "is-path-in-cwd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
+      "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
+      "dev": true,
+      "requires": {
+        "is-path-inside": "^1.0.0"
+      }
+    },
+    "is-path-inside": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
+      "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
+      "dev": true,
+      "requires": {
+        "path-is-inside": "^1.0.1"
+      }
+    },
+    "is-promise": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+      "dev": true
+    },
+    "is-regex": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
+      "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
+      "dev": true,
+      "requires": {
+        "has": "^1.0.1"
+      }
+    },
+    "is-resolvable": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
+      "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
+      "dev": true
+    },
+    "is-symbol": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
+      "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
+      "dev": true,
+      "requires": {
+        "has-symbols": "^1.0.0"
+      }
+    },
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+      "dev": true
+    },
+    "istanbul": {
+      "version": "0.4.5",
+      "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz",
+      "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=",
+      "dev": true,
+      "requires": {
+        "abbrev": "1.0.x",
+        "async": "1.x",
+        "escodegen": "1.8.x",
+        "esprima": "2.7.x",
+        "glob": "^5.0.15",
+        "handlebars": "^4.0.1",
+        "js-yaml": "3.x",
+        "mkdirp": "0.5.x",
+        "nopt": "3.x",
+        "once": "1.x",
+        "resolve": "1.1.x",
+        "supports-color": "^3.1.0",
+        "which": "^1.1.1",
+        "wordwrap": "^1.0.0"
+      },
+      "dependencies": {
+        "esprima": {
+          "version": "2.7.3",
+          "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+          "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+          "dev": true
+        },
+        "glob": {
+          "version": "5.0.15",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+          "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+          "dev": true,
+          "requires": {
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "2 || 3",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true
+    },
+    "js-yaml": {
+      "version": "3.12.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
+      "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
+      "dev": true,
+      "requires": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      }
+    },
+    "js2xmlparser": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz",
+      "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=",
+      "dev": true,
+      "requires": {
+        "xmlcreate": "^1.0.1"
+      }
+    },
+    "jsdoc": {
+      "version": "3.5.5",
+      "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz",
+      "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==",
+      "dev": true,
+      "requires": {
+        "babylon": "7.0.0-beta.19",
+        "bluebird": "~3.5.0",
+        "catharsis": "~0.8.9",
+        "escape-string-regexp": "~1.0.5",
+        "js2xmlparser": "~3.0.0",
+        "klaw": "~2.0.0",
+        "marked": "~0.3.6",
+        "mkdirp": "~0.5.1",
+        "requizzle": "~0.2.1",
+        "strip-json-comments": "~2.0.1",
+        "taffydb": "2.6.2",
+        "underscore": "~1.8.3"
+      }
+    },
+    "json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true
+    },
+    "json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+      "dev": true
+    },
+    "klaw": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz",
+      "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.9"
+      }
+    },
+    "levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2"
+      }
+    },
+    "lodash": {
+      "version": "4.17.11",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+      "dev": true
+    },
+    "marked": {
+      "version": "0.3.19",
+      "resolved": "http://registry.npmjs.org/marked/-/marked-0.3.19.tgz",
+      "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==",
+      "dev": true
+    },
+    "mimic-fn": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+      "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+      "dev": true
+    },
+    "mimic-response": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+      "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
+      "dev": true
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "minimist": {
+      "version": "0.0.8",
+      "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+      "dev": true
+    },
+    "mkdirp": {
+      "version": "0.5.1",
+      "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "dev": true,
+      "requires": {
+        "minimist": "0.0.8"
+      }
+    },
+    "ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "mute-stream": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+      "dev": true
+    },
+    "nan": {
+      "version": "2.10.0",
+      "resolved": "http://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
+      "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
+      "dev": true
+    },
+    "natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+      "dev": true
+    },
+    "nice-try": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+      "dev": true
+    },
+    "node-abi": {
+      "version": "2.4.5",
+      "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.5.tgz",
+      "integrity": "sha512-aa/UC6Nr3+tqhHGRsAuw/edz7/q9nnetBrKWxj6rpTtm+0X9T1qU7lIEHMS3yN9JwAbRiKUbRRFy1PLz/y3aaA==",
+      "dev": true,
+      "requires": {
+        "semver": "^5.4.1"
+      }
+    },
+    "node-int64": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+      "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs="
+    },
+    "noop-logger": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
+      "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=",
+      "dev": true
+    },
+    "nopt": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+      "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+      "dev": true,
+      "requires": {
+        "abbrev": "1"
+      }
+    },
+    "npmlog": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+      "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+      "dev": true,
+      "requires": {
+        "are-we-there-yet": "~1.1.2",
+        "console-control-strings": "~1.1.0",
+        "gauge": "~2.7.3",
+        "set-blocking": "~2.0.0"
+      }
+    },
+    "number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+      "dev": true
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+      "dev": true
+    },
+    "object-inspect": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz",
+      "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==",
+      "dev": true
+    },
+    "object-keys": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
+      "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==",
+      "dev": true
+    },
+    "on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+      "dev": true,
+      "requires": {
+        "ee-first": "1.1.1"
+      }
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true,
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "onetime": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+      "dev": true,
+      "requires": {
+        "mimic-fn": "^1.0.0"
+      }
+    },
+    "optimist": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+      "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+      "dev": true,
+      "requires": {
+        "minimist": "~0.0.1",
+        "wordwrap": "~0.0.2"
+      },
+      "dependencies": {
+        "wordwrap": {
+          "version": "0.0.3",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+          "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
+          "dev": true
+        }
+      }
+    },
+    "optionator": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+      "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+      "dev": true,
+      "requires": {
+        "deep-is": "~0.1.3",
+        "fast-levenshtein": "~2.0.4",
+        "levn": "~0.3.0",
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2",
+        "wordwrap": "~1.0.0"
+      }
+    },
+    "os-homedir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+      "dev": true
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+      "dev": true
+    },
+    "parseurl": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+      "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=",
+      "dev": true
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true
+    },
+    "path-is-inside": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+      "dev": true
+    },
+    "path-key": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+      "dev": true
+    },
+    "path-parse": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+      "dev": true
+    },
+    "pify": {
+      "version": "2.3.0",
+      "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+      "dev": true
+    },
+    "pinkie": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+      "dev": true
+    },
+    "pinkie-promise": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "dev": true,
+      "requires": {
+        "pinkie": "^2.0.0"
+      }
+    },
+    "pluralize": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
+      "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
+      "dev": true
+    },
+    "prebuild-install": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-4.0.0.tgz",
+      "integrity": "sha512-7tayxeYboJX0RbVzdnKyGl2vhQRWr6qfClEXDhOkXjuaOKCw2q8aiuFhONRYVsG/czia7KhpykIlI2S2VaPunA==",
+      "dev": true,
+      "requires": {
+        "detect-libc": "^1.0.3",
+        "expand-template": "^1.0.2",
+        "github-from-package": "0.0.0",
+        "minimist": "^1.2.0",
+        "mkdirp": "^0.5.1",
+        "node-abi": "^2.2.0",
+        "noop-logger": "^0.1.1",
+        "npmlog": "^4.0.1",
+        "os-homedir": "^1.0.1",
+        "pump": "^2.0.1",
+        "rc": "^1.1.6",
+        "simple-get": "^2.7.0",
+        "tar-fs": "^1.13.0",
+        "tunnel-agent": "^0.6.0",
+        "which-pm-runs": "^1.0.0"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "dev": true
+        }
+      }
+    },
+    "prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+      "dev": true
+    },
+    "prettier": {
+      "version": "1.14.3",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz",
+      "integrity": "sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg==",
+      "dev": true
+    },
+    "prettier-linter-helpers": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+      "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+      "dev": true,
+      "requires": {
+        "fast-diff": "^1.1.2"
+      }
+    },
+    "process-nextick-args": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+      "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+      "dev": true
+    },
+    "progress": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz",
+      "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==",
+      "dev": true
+    },
+    "pump": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+      "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "punycode": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+      "dev": true
+    },
+    "q": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
+      "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
+    },
+    "rc": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+      "dev": true,
+      "requires": {
+        "deep-extend": "^0.6.0",
+        "ini": "~1.3.0",
+        "minimist": "^1.2.0",
+        "strip-json-comments": "~2.0.1"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "dev": true
+        }
+      }
+    },
+    "readable-stream": {
+      "version": "2.3.6",
+      "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+      "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+      "dev": true,
+      "requires": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "regexpp": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
+      "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
+      "dev": true
+    },
+    "require-uncached": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
+      "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
+      "dev": true,
+      "requires": {
+        "caller-path": "^0.1.0",
+        "resolve-from": "^1.0.0"
+      }
+    },
+    "requizzle": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz",
+      "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=",
+      "dev": true,
+      "requires": {
+        "underscore": "~1.6.0"
+      },
+      "dependencies": {
+        "underscore": {
+          "version": "1.6.0",
+          "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
+          "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=",
+          "dev": true
+        }
+      }
+    },
+    "resolve": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+      "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
+      "dev": true
+    },
+    "resolve-from": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
+      "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
+      "dev": true
+    },
+    "restore-cursor": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+      "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+      "dev": true,
+      "requires": {
+        "onetime": "^2.0.0",
+        "signal-exit": "^3.0.2"
+      }
+    },
+    "resumer": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz",
+      "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=",
+      "dev": true,
+      "requires": {
+        "through": "~2.3.4"
+      }
+    },
+    "rimraf": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+      "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+      "dev": true,
+      "requires": {
+        "glob": "^7.0.5"
+      }
+    },
+    "run-async": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+      "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+      "dev": true,
+      "requires": {
+        "is-promise": "^2.1.0"
+      }
+    },
+    "rxjs": {
+      "version": "6.3.3",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
+      "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
+      "dev": true,
+      "requires": {
+        "tslib": "^1.9.0"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
+    },
+    "semver": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+      "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
+      "dev": true
+    },
+    "set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+      "dev": true
+    },
+    "shebang-command": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "dev": true,
+      "requires": {
+        "shebang-regex": "^1.0.0"
+      }
+    },
+    "shebang-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+      "dev": true
+    },
+    "signal-exit": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+      "dev": true
+    },
+    "simple-concat": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
+      "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=",
+      "dev": true
+    },
+    "simple-get": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz",
+      "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==",
+      "dev": true,
+      "requires": {
+        "decompress-response": "^3.3.0",
+        "once": "^1.3.1",
+        "simple-concat": "^1.0.0"
+      }
+    },
+    "slice-ansi": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
+      "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==",
+      "dev": true,
+      "requires": {
+        "is-fullwidth-code-point": "^2.0.0"
+      }
+    },
+    "source-map": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz",
+      "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "amdefine": ">=0.0.4"
+      }
+    },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+      "dev": true
+    },
+    "statuses": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
+      "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=",
+      "dev": true
+    },
+    "string-width": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+      "dev": true,
+      "requires": {
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^4.0.0"
+      }
+    },
+    "string.prototype.trim": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz",
+      "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.2",
+        "es-abstract": "^1.5.0",
+        "function-bind": "^1.0.2"
+      }
+    },
+    "string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "strip-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+      "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "^3.0.0"
+      }
+    },
+    "strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+      "dev": true
+    },
+    "supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "requires": {
+        "has-flag": "^3.0.0"
+      }
+    },
+    "table": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/table/-/table-5.1.0.tgz",
+      "integrity": "sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==",
+      "dev": true,
+      "requires": {
+        "ajv": "^6.5.3",
+        "lodash": "^4.17.10",
+        "slice-ansi": "1.0.0",
+        "string-width": "^2.1.1"
+      }
+    },
+    "taffydb": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz",
+      "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=",
+      "dev": true
+    },
+    "tape": {
+      "version": "4.9.1",
+      "resolved": "https://registry.npmjs.org/tape/-/tape-4.9.1.tgz",
+      "integrity": "sha512-6fKIXknLpoe/Jp4rzHKFPpJUHDHDqn8jus99IfPnHIjyz78HYlefTGD3b5EkbQzuLfaEvmfPK3IolLgq2xT3kw==",
+      "dev": true,
+      "requires": {
+        "deep-equal": "~1.0.1",
+        "defined": "~1.0.0",
+        "for-each": "~0.3.3",
+        "function-bind": "~1.1.1",
+        "glob": "~7.1.2",
+        "has": "~1.0.3",
+        "inherits": "~2.0.3",
+        "minimist": "~1.2.0",
+        "object-inspect": "~1.6.0",
+        "resolve": "~1.7.1",
+        "resumer": "~0.0.0",
+        "string.prototype.trim": "~1.1.2",
+        "through": "~2.3.8"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "dev": true
+        },
+        "resolve": {
+          "version": "1.7.1",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz",
+          "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==",
+          "dev": true,
+          "requires": {
+            "path-parse": "^1.0.5"
+          }
+        }
+      }
+    },
+    "tar-fs": {
+      "version": "1.16.3",
+      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz",
+      "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==",
+      "dev": true,
+      "requires": {
+        "chownr": "^1.0.1",
+        "mkdirp": "^0.5.1",
+        "pump": "^1.0.0",
+        "tar-stream": "^1.1.2"
+      },
+      "dependencies": {
+        "pump": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz",
+          "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==",
+          "dev": true,
+          "requires": {
+            "end-of-stream": "^1.1.0",
+            "once": "^1.3.1"
+          }
+        }
+      }
+    },
+    "tar-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
+      "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
+      "dev": true,
+      "requires": {
+        "bl": "^1.0.0",
+        "buffer-alloc": "^1.2.0",
+        "end-of-stream": "^1.0.0",
+        "fs-constants": "^1.0.0",
+        "readable-stream": "^2.3.0",
+        "to-buffer": "^1.1.1",
+        "xtend": "^4.0.0"
+      }
+    },
+    "text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+      "dev": true
+    },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+      "dev": true
+    },
+    "tmp": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+      "dev": true,
+      "requires": {
+        "os-tmpdir": "~1.0.2"
+      }
+    },
+    "to-buffer": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
+      "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==",
+      "dev": true
+    },
+    "tslib": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
+      "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
+      "dev": true
+    },
+    "tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "~1.1.2"
+      }
+    },
+    "typescript": {
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz",
+      "integrity": "sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==",
+      "dev": true
+    },
+    "uglify-js": {
+      "version": "3.4.9",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
+      "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "commander": "~2.17.1",
+        "source-map": "~0.6.1"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "2.17.1",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
+          "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
+          "dev": true,
+          "optional": true
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "underscore": {
+      "version": "1.8.3",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
+      "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=",
+      "dev": true
+    },
+    "underscore-contrib": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz",
+      "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=",
+      "dev": true,
+      "requires": {
+        "underscore": "1.6.0"
+      },
+      "dependencies": {
+        "underscore": {
+          "version": "1.6.0",
+          "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
+          "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=",
+          "dev": true
+        }
+      }
+    },
+    "unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+      "dev": true
+    },
+    "uri-js": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+      "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+      "dev": true,
+      "requires": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "utf-8-validate": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-4.0.2.tgz",
+      "integrity": "sha512-CS63Ssp6zynBQ4IxVzgjP5Abdo6LuJ87HFIcgIiVUeY96+MTHkqKtrUhphbwQ6jX8aSGZv8zX6l1DCPpfcAnxA==",
+      "dev": true,
+      "requires": {
+        "bindings": "~1.3.0",
+        "nan": "~2.10.0",
+        "prebuild-install": "~4.0.0"
+      }
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
+    "utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+      "dev": true
+    },
+    "which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "requires": {
+        "isexe": "^2.0.0"
+      }
+    },
+    "which-pm-runs": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
+      "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=",
+      "dev": true
+    },
+    "wide-align": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+      "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+      "dev": true,
+      "requires": {
+        "string-width": "^1.0.2 || 2"
+      }
+    },
+    "wordwrap": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+      "dev": true
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
+    },
+    "write": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
+      "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
+      "dev": true,
+      "requires": {
+        "mkdirp": "^0.5.1"
+      }
+    },
+    "ws": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
+      "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
+      "requires": {
+        "async-limiter": "~1.0.0"
+      }
+    },
+    "xmlcreate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz",
+      "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=",
+      "dev": true
+    },
+    "xtend": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+      "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
+      "dev": true
+    }
+  }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..99553ee
--- /dev/null
+++ b/package.json
@@ -0,0 +1,66 @@
+{
+  "name": "thrift",
+  "description": "node.js bindings for the Apache Thrift RPC system",
+  "homepage": "http://thrift.apache.org/",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/apache/thrift.git"
+  },
+  "version": "1.0.0",
+  "author": {
+    "name": "Apache Thrift Developers",
+    "email": "dev@thrift.apache.org",
+    "url": "http://thrift.apache.org"
+  },
+  "license": "Apache-2.0",
+  "licenses": [
+    {
+      "type": "Apache-2.0",
+      "url": "http://www.apache.org/licenses/LICENSE-2.0"
+    }
+  ],
+  "bugs": {
+    "mail": "dev@thrift.apache.org",
+    "url": "https://issues.apache.org/jira/browse/THRIFT"
+  },
+  "files": [
+    "lib/nodejs/lib/thrift",
+    "lib/nodejs/README.md"
+  ],
+  "directories": {
+    "lib": "./lib/nodejs/lib/thrift"
+  },
+  "main": "./lib/nodejs/lib/thrift",
+  "engines": {
+    "node": ">= 4.1.0"
+  },
+  "dependencies": {
+    "node-int64": "^0.4.0",
+    "q": "^1.5.0",
+    "ws": "^5.0.0"
+  },
+  "devDependencies": {
+    "buffer-equals": "^1.0.4",
+    "commander": "^2.14.1",
+    "connect": "^3.6.6",
+    "eslint": "^5.7.0",
+    "eslint-config-prettier": "^3.1.0",
+    "eslint-plugin-prettier": "^3.0.0",
+    "istanbul": "^0.4.5",
+    "jsdoc": "^3.5.5",
+    "prettier": "^1.14.3",
+    "tape": "^4.9.0",
+    "utf-8-validate": "^4.0.0",
+    "typescript": "^3.1.6",
+    "@types/node": "^10.12.6",
+    "@types/q": "^1.5.1"
+  },
+  "scripts": {
+    "cover": "lib/nodejs/test/testAll.sh COVER",
+    "test": "lib/nodejs/test/testAll.sh",
+    "test-ts": "lib/nodets/test/testAll.sh",
+    "prettier": "prettier --write '**/*.js'",
+    "lint": "eslint lib/nodejs/. --ext .js",
+    "lint-tests": "eslint lib/nodejs/test/. --ext .js"
+  }
+}
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
new file mode 100644
index 0000000..180388a
--- /dev/null
+++ b/phpcs.xml.dist
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<ruleset name="Apache_Thrift">
+    <description>The coding standard for thrift.</description>
+
+    <file>lib/php/lib</file>
+    <file>lib/php/test</file>
+    <exclude-pattern>lib/php/test/packages/*</exclude-pattern>
+
+    <arg name="basepath" value="."/>
+    <arg name="colors" />
+    <arg name="parallel" value="4" />
+
+    <rule ref="PSR2">
+        <exclude name="PSR2.Methods.MethodDeclaration.Underscore"/>
+        <exclude name="PSR2.Classes.PropertyDeclaration.Underscore"/>
+    </rule>
+
+    <rule ref="PSR1.Files.SideEffects">
+        <exclude-pattern>lib/php/test/*</exclude-pattern>
+    </rule>
+    <rule ref="Generic.Files.LineLength">
+        <exclude-pattern>lib/php/test/*</exclude-pattern>
+    </rule>
+
+</ruleset>
diff --git a/pull_request_template.md b/pull_request_template.md
new file mode 100644
index 0000000..0b6965b
--- /dev/null
+++ b/pull_request_template.md
@@ -0,0 +1,19 @@
+Some helpful tips for a successful Apache Thrift PR:
+
+* Did you test your changes locally or using CI in your fork?
+* Is the Apache Jira THRIFT ticket identifier in the PR title?
+* Is the Apache Jira THRIFT ticket identifier in the commit message?
+* Did you squash your changes to a single commit?
+* Are these changes backwards compatible? (please say so in PR description)
+* Do you need to update the language-specific README?
+
+Example ideal pull request title:
+
+        THRIFT-9999: an example pull request title
+
+Example ideal commit message:
+
+        THRIFT-9999: [summary of fix, one line if possible]
+        Client: [language(s) affected, comma separated, use lib/ directory names please]
+
+For more information about committing, see CONTRIBUTING.md
diff --git a/rat_exclude b/rat_exclude
deleted file mode 100644
index feafe8b..0000000
--- a/rat_exclude
+++ /dev/null
@@ -1,35 +0,0 @@
-.gitignore
-CHANGES
-CONTRIBUTORS
-autoscan.log
-config.guess
-config.log
-config.status
-config.sub
-configure
-configure.scan
-depcomp
-install-sh
-libtool
-ltmain.sh
-missing
-stamp-h1
-ylwrap
-*.m4
-autom4te.cache
-thrifty.h
-thrifty.hh
-version.h
-version.h.in
-md5.c
-md5.h
-doc
-lib/erl/vsn.mk
-/lib/erl/build/**/*
-lib/erl/src/Makefile
-thrift.appup.src
-OCamlMakefile
-README-OCamlMakefile
-TODO
-Manifest
-setup.rb
diff --git a/sonar-project.properties b/sonar-project.properties
index b465fd1..bd5ecc2 100755
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -16,7 +16,7 @@
 services that work efficiently and seamlessly between all major languages.
 
 # Apache Thrift Version
-sonar.projectVersion=1.0.0-dev
+sonar.projectVersion=1.0.0
 # use this to set another version string
 # $ sonar-runner -D sonar.projectVersion=`git rev-parse HEAD`
 # set projectDate in combination with projectVersion for imports of old releases
@@ -31,7 +31,7 @@
 sonar.sourceEncoding=UTF-8
 
 # scm
-sonar.scm.url=scm:git:https://git-wip-us.apache.org/repos/asf/thrift
+sonar.scm.url=scm:git:https://github.com/apache/thrift.git
 
 # cppcheck -q --error-exitcode=0 --xml . 2> cppcheck-result.xml
 sonar.cxx.cppcheck.reportPath=cppcheck-result.xml
@@ -54,15 +54,15 @@
 module1.sonar.projectBaseDir=lib/java
 module1.sonar.sources=src
 module1.sonar.tests=test
-module1.sonar.binaries=build/libthrift-1.0.0.jar
-module1.sonar.libraries=build/lib/*.jar
+module1.sonar.binaries=build/libs/libthrift-1.0.0.jar
+module1.sonar.libraries=build/deps/*.jar
 module1.sonar.language=java
 
 module2.sonar.projectName=Apache Thrift - Java Tutorial
 module2.sonar.projectBaseDir=.
 module2.sonar.sources=tutorial/java/src, tutorial/java/gen-java
 module2.sonar.binaries=tutorial/java/tutorial.jar
-module2.sonar.libraries=lib/java/build/lib/*.jar,lib/java/build/libthrift-1.0.0.jar
+module2.sonar.libraries=lib/java/build/deps/*.jar,lib/java/build/libs/libthrift-1.0.0.jar
 module2.sonar.language=java
 
 module3.sonar.projectName=Apache Thrift - JavaScript Library
diff --git a/test/AnnotationTest.thrift b/test/AnnotationTest.thrift
index dac476f..7e24e1c 100644
--- a/test/AnnotationTest.thrift
+++ b/test/AnnotationTest.thrift
@@ -28,6 +28,7 @@
   cpp.type = "DenseFoo",
   python.type = "DenseFoo",
   java.final = "",
+  annotation.without.value,
 )
 
 exception foo_error {
@@ -51,11 +52,20 @@
 /* Note that annotations on senum values are not supported. */
 senum seasons {
   "Spring",
-  "Summer", 
+  "Summer",
   "Fall",
   "Winter"
 } ( foo = "bar" )
 
+struct ostr_default {
+  1: i32 bar;
+}
+
+struct ostr_custom {
+  1: i32 bar;
+} (cpp.customostream)
+
+
 service foo_service {
   void foo() ( foo = "bar" )
 } (a.b="c")
diff --git a/test/ConstantsDemo.thrift b/test/ConstantsDemo.thrift
index 7d971e6..a54534d 100644
--- a/test/ConstantsDemo.thrift
+++ b/test/ConstantsDemo.thrift
@@ -18,6 +18,7 @@
  */
 
 namespace cpp yozone
+namespace erl consts_
 
 struct thing {
   1: i32 hello,
@@ -40,12 +41,16 @@
 //const map<enumconstants,string> GEN_ENUM_NAMES = {ONE : "HOWDY", TWO: "PARTNER"}
 
 const i32 hex_const = 0x0001F
+const i32 negative_hex_constant = -0x0001F
 
 const i32 GEN_ME = -3523553
 const double GEn_DUB = 325.532
 const double GEn_DU = 085.2355
 const string GEN_STRING = "asldkjasfd"
 
+const double e10 = 1e10   // fails with 0.9.3 and earlier
+const double e11 = -1e10  
+
 const map<i32,i32> GEN_MAP = { 35532 : 233, 43523 : 853 }
 const list<i32> GEN_LIST = [ 235235, 23598352, 3253523 ]
 
diff --git a/test/DebugProtoTest.thrift b/test/DebugProtoTest.thrift
index e2bba40..b6a7659 100644
--- a/test/DebugProtoTest.thrift
+++ b/test/DebugProtoTest.thrift
@@ -20,6 +20,7 @@
 namespace c_glib TTest
 namespace cpp thrift.test.debug
 namespace java thrift.test
+namespace rb thrift.test
 
 struct Doubles {
  1: double nan,
@@ -27,7 +28,7 @@
  3: double neginf,
  4: double repeating,
  5: double big,
- 6: double small,
+ 6: double tiny,
  7: double zero,
  8: double negzero,
 }
@@ -35,7 +36,7 @@
 struct OneOfEach {
   1: bool im_true,
   2: bool im_false,
-  3: byte a_bite = 0x7f,
+  3: i8 a_bite = 0x7f,
   4: i16 integer16 = 0x7fff,
   5: i32 integer32,
   6: i64 integer64 = 10000000000,
@@ -44,7 +45,7 @@
   9: string zomg_unicode,
   10: bool what_who,
   11: binary base64,
-  12: list<byte> byte_list = [1, 2, 3],
+  12: list<i8> byte_list = [1, 2, 3],
   13: list<i16> i16_list = [1,2,3],
   14: list<i64> i64_list = [1,2,3]
 }
@@ -61,7 +62,7 @@
 
 struct HolyMoley {
   1: list<OneOfEach> big,
-  2: set<list<string>> contain,
+  2: set<list<string> (python.immutable = "")> contain,
   3: map<string,list<Bonk>> bonks,
 }
 
@@ -71,11 +72,15 @@
 }
 
 struct Empty {
-}
+} (
+  python.immutable = "",
+)
 
 struct Wrapper {
   1: Empty foo
-}
+} (
+  python.immutable = "",
+)
 
 struct RandomStuff {
   1: i32 a,
@@ -100,7 +105,7 @@
 
 struct CompactProtoTestStruct {
   // primitive fields
-  1: byte   a_byte;
+  1: i8     a_byte;
   2: i16    a_i16;
   3: i32    a_i32;
   4: i64    a_i64;
@@ -110,9 +115,9 @@
   8: bool   true_field;
   9: bool   false_field;
   10: Empty empty_struct_field;
-  
+
   // primitives in lists
-  11: list<byte>    byte_list;
+  11: list<i8>      byte_list;
   12: list<i16>     i16_list;
   13: list<i32>     i32_list;
   14: list<i64>     i64_list;
@@ -121,9 +126,9 @@
   17: list<binary>  binary_list;
   18: list<bool>    boolean_list;
   19: list<Empty>   struct_list;
-  
+
   // primitives in sets
-  20: set<byte>     byte_set;
+  20: set<i8>       byte_set;
   21: set<i16>      i16_set;
   22: set<i32>      i32_set;
   23: set<i64>      i64_set;
@@ -132,33 +137,33 @@
   26: set<binary>   binary_set;
   27: set<bool>     boolean_set;
   28: set<Empty>    struct_set;
-  
+
   // maps
   // primitives as keys
-  29: map<byte, byte>             byte_byte_map;
-  30: map<i16, byte>              i16_byte_map;
-  31: map<i32, byte>              i32_byte_map;
-  32: map<i64, byte>              i64_byte_map;
-  33: map<double, byte>           double_byte_map;
-  34: map<string, byte>           string_byte_map;
-  35: map<binary, byte>           binary_byte_map;
-  36: map<bool, byte>             boolean_byte_map;
+  29: map<i8, i8>               byte_byte_map;
+  30: map<i16, i8>              i16_byte_map;
+  31: map<i32, i8>              i32_byte_map;
+  32: map<i64, i8>              i64_byte_map;
+  33: map<double, i8>           double_byte_map;
+  34: map<string, i8>           string_byte_map;
+  35: map<binary, i8>           binary_byte_map;
+  36: map<bool, i8>             boolean_byte_map;
   // primitives as values
-  37: map<byte, i16>              byte_i16_map;
-  38: map<byte, i32>              byte_i32_map;
-  39: map<byte, i64>              byte_i64_map;
-  40: map<byte, double>           byte_double_map;
-  41: map<byte, string>           byte_string_map;
-  42: map<byte, binary>           byte_binary_map;
-  43: map<byte, bool>             byte_boolean_map;
+  37: map<i8, i16>              byte_i16_map;
+  38: map<i8, i32>              byte_i32_map;
+  39: map<i8, i64>              byte_i64_map;
+  40: map<i8, double>           byte_double_map;
+  41: map<i8, string>           byte_string_map;
+  42: map<i8, binary>           byte_binary_map;
+  43: map<i8, bool>             byte_boolean_map;
   // collections as keys
-  44: map<list<byte>, byte>       list_byte_map;
-  45: map<set<byte>, byte>        set_byte_map;
-  46: map<map<byte,byte>, byte>   map_byte_map;
+  44: map<list<i8> (python.immutable = ""), i8>       list_byte_map;
+  45: map<set<i8> (python.immutable = ""), i8>        set_byte_map;
+  46: map<map<i8,i8> (python.immutable = ""), i8>     map_byte_map;
   // collections as values
-  47: map<byte, map<byte,byte>>   byte_map_map;
-  48: map<byte, set<byte>>        byte_set_map;
-  49: map<byte, list<byte>>       byte_list_map;
+  47: map<i8, map<i8,i8>>     byte_map_map;
+  48: map<i8, set<i8>>        byte_set_map;
+  49: map<i8, list<i8>>       byte_list_map;
 }
 
 // To be used to test the serialization of an empty map
@@ -243,6 +248,8 @@
   void methodWithDefaultArgs(1: i32 something = MYCONST);
 
   oneway void onewayMethod();
+
+  bool declaredExceptionMethod(1: bool shouldThrow) throws (1: ExceptionWithAMap xwamap);
 }
 
 service Inherited extends Srv {
@@ -254,10 +261,10 @@
 // The only purpose of this thing is to increase the size of the generated code
 // so that ZlibTest has more highly compressible data to play with.
 struct BlowUp {
-  1: map<list<i32>,set<map<i32,string>>> b1;
-  2: map<list<i32>,set<map<i32,string>>> b2;
-  3: map<list<i32>,set<map<i32,string>>> b3;
-  4: map<list<i32>,set<map<i32,string>>> b4;
+  1: map<list<i32>(python.immutable = ""),set<map<i32,string> (python.immutable = "")>> b1;
+  2: map<list<i32>(python.immutable = ""),set<map<i32,string> (python.immutable = "")>> b2;
+  3: map<list<i32>(python.immutable = ""),set<map<i32,string> (python.immutable = "")>> b3;
+  4: map<list<i32>(python.immutable = ""),set<map<i32,string> (python.immutable = "")>> b4;
 }
 
 
@@ -364,4 +371,8 @@
   optional i32 field10;
   optional i32 field11;
   optional i32 field12;
-}
\ No newline at end of file
+}
+
+struct ListDoublePerf {
+  1: list<double> field;
+}
diff --git a/test/DenseLinkingTest.thrift b/test/DenseLinkingTest.thrift
index cf61496..3a5b957 100644
--- a/test/DenseLinkingTest.thrift
+++ b/test/DenseLinkingTest.thrift
@@ -34,6 +34,7 @@
 */
 
 namespace cpp thrift.test
+namespace java thrift.test
 
 struct OneOfEachZZ {
   1: bool im_true,
@@ -90,3 +91,8 @@
 service Srv {
   i32 Janky(1: i32 arg)
 }
+
+service UnderscoreSrv {
+  i64 some_rpc_call(1: string message)
+}
+
diff --git a/test/DocTest.thrift b/test/DocTest.thrift
index cb355ae..d702b2c 100644
--- a/test/DocTest.thrift
+++ b/test/DocTest.thrift
@@ -58,7 +58,7 @@
   1:  string string_thing
 
   /** doct text goes before a comma */
-  4:  byte   byte_thing,
+  4:  i8     byte_thing,
 
   9:  i32    i32_thing,
   11: i64    i64_thing
@@ -74,7 +74,7 @@
 
 struct Xtruct2
 {
-  1: byte   byte_thing,
+  1: i8     byte_thing,
   2: Xtruct struct_thing,
   3: i32    i32_thing
 }
@@ -117,7 +117,7 @@
   /** And this is how you would document functions in a service */
   void         testVoid(),
   string       testString(1: string thing),
-  byte         testByte(1: byte thing),
+  i8           testByte(1: byte thing),
   i32          testI32(1: i32 thing),
 
   /** Like this one */
@@ -155,7 +155,7 @@
 typedef i32 TrivialMultiLine
 
 /**
- * This is the cannonical example
+ * This is the canonical example
  * of a multiline docstring.
  */
 typedef i32 StandardMultiLine
@@ -244,4 +244,44 @@
 */
 typedef i32 TotallyDegenerate
 
+/**no room for newline here*/
+
+/* * / */
+typedef i32 TestFor3501a
+
+/**
+ * /
+ */
+typedef i32 TestFor3501b
+
+
+/* Comment-end tokens can of course have more than one asterisk */
+struct TestFor3709_00 { /* ? */ 1: i32 foo }
+/* Comment-end tokens can of course have more than one asterisk **/
+struct TestFor3709_01 { /* ? */ 1: i32 foo }
+/* Comment-end tokens can of course have more than one asterisk ***/
+struct TestFor3709_02 { /* ? */ 1: i32 foo }
+/** Comment-end tokens can of course have more than one asterisk */
+struct TestFor3709_03 { /* ? */ 1: i32 foo }
+/** Comment-end tokens can of course have more than one asterisk **/
+struct TestFor3709_04 { /* ? */ 1: i32 foo }
+/** Comment-end tokens can of course have more than one asterisk ***/
+struct TestFor3709_05 { /* ? */ 1: i32 foo }
+/*** Comment-end tokens can of course have more than one asterisk */
+struct TestFor3709_06 { /* ? */ 1: i32 foo }
+/*** Comment-end tokens can of course have more than one asterisk **/
+struct TestFor3709_07 { /* ? */ 1: i32 foo }
+/*** Comment-end tokens can of course have more than one asterisk ***/
+struct TestFor3709_08 { /* ? */ 1: i32 foo }
+
+struct TestFor3709 {
+  /** This is a comment */
+  1: required string id,
+  /** This is also a comment **/
+  2: required string typeId,
+  /** Yet another comment! */
+  3: required i32 endTimestamp
+}
+
+
 /* THE END */
diff --git a/test/DoubleConstantsTest.thrift b/test/DoubleConstantsTest.thrift
new file mode 100644
index 0000000..c9212ab
--- /dev/null
+++ b/test/DoubleConstantsTest.thrift
@@ -0,0 +1,17 @@
+namespace java thrift.test
+namespace cpp thrift.test
+
+// more tests on double constants (precision and type checks)
+const double DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST = 1
+const double DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST = -100
+const double DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST = 9223372036854775807
+const double DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST = -9223372036854775807
+const double DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST = 3.14159265359
+const double DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST = 1000000.1
+const double DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST = -1000000.1
+const double DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST = 1.7e+308
+const double DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST = 9223372036854775816.43
+const double DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST = -1.7e+308
+const double DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST = -9223372036854775816.43
+
+const list<double> DOUBLE_LIST_TEST = [1,-100,100,9223372036854775807,-9223372036854775807,3.14159265359,1000000.1,-1000000.1,1.7e+308,-1.7e+308,9223372036854775816.43,-9223372036854775816.43]
diff --git a/test/EnumContainersTest.thrift b/test/EnumContainersTest.thrift
new file mode 100644
index 0000000..3b6408f
--- /dev/null
+++ b/test/EnumContainersTest.thrift
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+namespace java thrift.test.enumcontainers
+
+enum GreekGodGoddess {
+    ARES,
+    APHRODITE,
+    ZEUS,
+    POSEIDON,
+    HERA,
+}
+
+typedef GreekGodGoddess GreekGodGoddessType
+typedef i32 Power
+
+struct GodBean {
+    1: optional map<GreekGodGoddessType, Power> power,
+    2: optional set<GreekGodGoddessType> goddess,
+    3: optional map<string, GreekGodGoddess> byAlias,
+    4: optional set<string> images,
+}
+
+const map<GreekGodGoddessType, string> ATTRIBUTES =
+{
+    GreekGodGoddess.ZEUS: "lightning bolt",
+    GreekGodGoddess.POSEIDON: "trident",
+}
+
+const set<GreekGodGoddessType> BEAUTY = [ GreekGodGoddess.APHRODITE, GreekGodGoddess.HERA ]
diff --git a/test/EnumTest.thrift b/test/EnumTest.thrift
new file mode 100644
index 0000000..7961f38
--- /dev/null
+++ b/test/EnumTest.thrift
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+namespace c_glib TTest
+
+enum MyEnum1 {
+  ME1_0 = 0,
+  ME1_1 = 1,
+  ME1_2,
+  ME1_3,
+  ME1_5 = 5,
+  ME1_6,
+}
+
+enum MyEnum2 {
+  ME2_0,
+  ME2_1,
+  ME2_2,
+}
+
+enum MyEnum2_again {
+  // enum value identifiers may appear again in another enum type
+  ME0_1,
+  ME1_1,
+  ME2_1,
+  ME3_1,
+}
+
+enum MyEnum3 {
+  ME3_0,
+  ME3_1,
+  ME3_N2 = -2,
+  ME3_N1,
+  ME3_D0,
+  ME3_D1,
+  ME3_9 = 9,
+  ME3_10,
+}
+
+enum MyEnum4 {
+  ME4_A = 0x7ffffffd
+  ME4_B
+  ME4_C
+  // attempting to define another enum value here fails
+  // with an overflow error, as we overflow values that can be
+  // represented with an i32.
+}
+
+enum MyEnum5 {
+  e1        // fails with 0.9.3 and earlier
+  e2 = 42   // fails with 0.9.3 and earlier
+}
+
+enum MyEnumWithCustomOstream {
+  custom1 = 1,
+  CustoM2
+} (cpp.customostream)
+
+struct MyStruct {
+  1: MyEnum2 me2_2 = MyEnum1.ME2_2
+  2: MyEnum3 me3_n2 = MyEnum3.ME3_N2
+  3: MyEnum3 me3_d1 = MyEnum3.ME3_D1
+}
+
+struct EnumTestStruct {
+  1: MyEnum3 a_enum;
+  2: list<MyEnum3> enum_list;
+  3: set<MyEnum3> enum_set;
+  4: map<MyEnum3, MyEnum3> enum_enum_map;
+  // collections as keys
+  44: map<list<MyEnum3> (python.immutable = ""), MyEnum3> list_enum_map;
+  45: map<set<MyEnum3> (python.immutable = ""), MyEnum3> set_enum_map;
+  46: map<map<MyEnum3,MyEnum3> (python.immutable = ""), MyEnum3> map_enum_map;
+  // collections as values
+  47: map<MyEnum3, map<MyEnum3, MyEnum3>> enum_map_map;
+  48: map<MyEnum3, set<MyEnum3>> enum_set_map;
+  49: map<MyEnum3, list<MyEnum3>> enum_list_map;
+}
+
+const EnumTestStruct ENUM_TEST = {
+  'a_enum': MyEnum3.ME3_D1,
+  'enum_list': [MyEnum3.ME3_D1, MyEnum3.ME3_0, MyEnum3.ME3_N2],
+  'enum_set': [MyEnum3.ME3_D1, MyEnum3.ME3_N1],
+  'enum_enum_map': {MyEnum3.ME3_D1: MyEnum3.ME3_0, MyEnum3.ME3_0: MyEnum3.ME3_D1},
+  'list_enum_map': {[MyEnum3.ME3_D1, MyEnum3.ME3_0]: MyEnum3.ME3_0, [MyEnum3.ME3_D1]: MyEnum3.ME3_0, [MyEnum3.ME3_0]: MyEnum3.ME3_D1},
+  'set_enum_map': {[MyEnum3.ME3_D1, MyEnum3.ME3_0]: MyEnum3.ME3_0, [MyEnum3.ME3_D1]: MyEnum3.ME3_0},
+  'map_enum_map': {{MyEnum3.ME3_N1: MyEnum3.ME3_10}: MyEnum3.ME3_1},
+  'enum_map_map': {MyEnum3.ME3_N1: {MyEnum3.ME3_D1: MyEnum3.ME3_D1}},
+  'enum_set_map': {MyEnum3.ME3_N2: [MyEnum3.ME3_D1, MyEnum3.ME3_N1], MyEnum3.ME3_10: [MyEnum3.ME3_D1, MyEnum3.ME3_N1]},
+  'enum_list_map': {MyEnum3.ME3_D1: [MyEnum3.ME3_10], MyEnum3.ME3_0: [MyEnum3.ME3_9, MyEnum3.ME3_10]},
+}
+
+service EnumTestService {
+  MyEnum3 testEnum(1: MyEnum3 enum1),
+  list<MyEnum3> testEnumList(1: list<MyEnum3> enum1),
+  set<MyEnum3> testEnumSet(1: set<MyEnum3> enum1),
+  map<MyEnum3, MyEnum3> testEnumMap(1: map<MyEnum3, MyEnum3> enum1),
+  EnumTestStruct testEnumStruct(1: EnumTestStruct enum1),
+}
diff --git a/test/FastbinaryTest.py b/test/FastbinaryTest.py
deleted file mode 100755
index 7f6efae..0000000
--- a/test/FastbinaryTest.py
+++ /dev/null
@@ -1,222 +0,0 @@
-#!/usr/bin/env python
-
-#
-# 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.
-#
-
-r"""
-thrift --gen py DebugProtoTest.thrift
-./FastbinaryTest.py
-"""
-
-# TODO(dreiss): Test error cases.  Check for memory leaks.
-
-import sys
-sys.path.append('./gen-py')
-
-import math
-from DebugProtoTest import Srv
-from DebugProtoTest.ttypes import *
-from thrift.transport import TTransport
-from thrift.protocol import TBinaryProtocol
-
-import timeit
-from cStringIO import StringIO
-from copy import deepcopy
-from pprint import pprint
-
-class TDevNullTransport(TTransport.TTransportBase):
-  def __init__(self):
-    pass
-  def isOpen(self):
-    return True
-
-ooe1 = OneOfEach()
-ooe1.im_true   = True;
-ooe1.im_false  = False;
-ooe1.a_bite    = 0xd6;
-ooe1.integer16 = 27000;
-ooe1.integer32 = 1<<24;
-ooe1.integer64 = 6000 * 1000 * 1000;
-ooe1.double_precision = math.pi;
-ooe1.some_characters  = "Debug THIS!";
-ooe1.zomg_unicode     = "\xd7\n\a\t";
-
-ooe2 = OneOfEach();
-ooe2.integer16 = 16;
-ooe2.integer32 = 32;
-ooe2.integer64 = 64;
-ooe2.double_precision = (math.sqrt(5)+1)/2;
-ooe2.some_characters  = ":R (me going \"rrrr\")";
-ooe2.zomg_unicode     = "\xd3\x80\xe2\x85\xae\xce\x9d\x20"\
-                        "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe"\
-                        "\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"\
-                        "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba"\
-                        "\xc7\x83\xe2\x80\xbc";
-
-hm = HolyMoley({"big":[], "contain":set(), "bonks":{}})
-hm.big.append(ooe1)
-hm.big.append(ooe2)
-hm.big[0].a_bite = 0x22;
-hm.big[1].a_bite = 0x22;
-
-hm.contain.add(("and a one", "and a two"))
-hm.contain.add(("then a one, two", "three!", "FOUR!"))
-hm.contain.add(())
-
-hm.bonks["nothing"] = [];
-hm.bonks["something"] = [
-  Bonk({"type":1, "message":"Wait."}),
-  Bonk({"type":2, "message":"What?"}),
-]
-hm.bonks["poe"] = [
-  Bonk({"type":3, "message":"quoth"}),
-  Bonk({"type":4, "message":"the raven"}),
-  Bonk({"type":5, "message":"nevermore"}),
-]
-
-rs = RandomStuff()
-rs.a = 1
-rs.b = 2
-rs.c = 3
-rs.myintlist = range(20)
-rs.maps = {1:Wrapper({"foo":Empty()}),2:Wrapper({"foo":Empty()})}
-rs.bigint = 124523452435L
-rs.triple = 3.14
-
-# make sure this splits two buffers in a buffered protocol
-rshuge = RandomStuff()
-rshuge.myintlist=range(10000)
-
-my_zero = Srv.Janky_result({"arg":5})
-
-def checkWrite(o):
-  trans_fast = TTransport.TMemoryBuffer()
-  trans_slow = TTransport.TMemoryBuffer()
-  prot_fast = TBinaryProtocol.TBinaryProtocolAccelerated(trans_fast)
-  prot_slow = TBinaryProtocol.TBinaryProtocol(trans_slow)
-
-  o.write(prot_fast)
-  o.write(prot_slow)
-  ORIG = trans_slow.getvalue()
-  MINE = trans_fast.getvalue()
-  if ORIG != MINE:
-    print "mine: %s\norig: %s" % (repr(MINE), repr(ORIG))
-
-def checkRead(o):
-  prot = TBinaryProtocol.TBinaryProtocol(TTransport.TMemoryBuffer())
-  o.write(prot)
-
-  slow_version_binary = prot.trans.getvalue()
-
-  prot = TBinaryProtocol.TBinaryProtocolAccelerated(
-           TTransport.TMemoryBuffer(slow_version_binary))
-  c = o.__class__()
-  c.read(prot)
-  if c != o:
-    print "copy: "
-    pprint(eval(repr(c)))
-    print "orig: "
-    pprint(eval(repr(o)))
-
-  prot = TBinaryProtocol.TBinaryProtocolAccelerated(
-           TTransport.TBufferedTransport(
-             TTransport.TMemoryBuffer(slow_version_binary)))
-  c = o.__class__()
-  c.read(prot)
-  if c != o:
-    print "copy: "
-    pprint(eval(repr(c)))
-    print "orig: "
-    pprint(eval(repr(o)))
-
-
-def doTest():
-  checkWrite(hm)
-  no_set = deepcopy(hm)
-  no_set.contain = set()
-  checkRead(no_set)
-  checkWrite(rs)
-  checkRead(rs)
-  checkWrite(rshuge)
-  checkRead(rshuge)
-  checkWrite(my_zero)
-  checkRead(my_zero)
-  checkRead(Backwards({"first_tag2":4, "second_tag1":2}))
-
-  # One case where the serialized form changes, but only superficially.
-  o = Backwards({"first_tag2":4, "second_tag1":2})
-  trans_fast = TTransport.TMemoryBuffer()
-  trans_slow = TTransport.TMemoryBuffer()
-  prot_fast = TBinaryProtocol.TBinaryProtocolAccelerated(trans_fast)
-  prot_slow = TBinaryProtocol.TBinaryProtocol(trans_slow)
-
-  o.write(prot_fast)
-  o.write(prot_slow)
-  ORIG = trans_slow.getvalue()
-  MINE = trans_fast.getvalue()
-  if ORIG == MINE:
-    print "That shouldn't happen."
-
-
-  prot = TBinaryProtocol.TBinaryProtocolAccelerated(TTransport.TMemoryBuffer())
-  o.write(prot)
-  prot = TBinaryProtocol.TBinaryProtocol(
-           TTransport.TMemoryBuffer(
-             prot.trans.getvalue()))
-  c = o.__class__()
-  c.read(prot)
-  if c != o:
-    print "copy: "
-    pprint(eval(repr(c)))
-    print "orig: "
-    pprint(eval(repr(o)))
-
-
-
-def doBenchmark():
-
-  iters = 25000
-
-  setup = """
-from __main__ import hm, rs, TDevNullTransport
-from thrift.protocol import TBinaryProtocol
-trans = TDevNullTransport()
-prot = TBinaryProtocol.TBinaryProtocol%s(trans)
-"""
-
-  setup_fast = setup % "Accelerated"
-  setup_slow = setup % ""
-
-  print "Starting Benchmarks"
-
-  print "HolyMoley Standard = %f" % \
-      timeit.Timer('hm.write(prot)', setup_slow).timeit(number=iters)
-  print "HolyMoley Acceler. = %f" % \
-      timeit.Timer('hm.write(prot)', setup_fast).timeit(number=iters)
-
-  print "FastStruct Standard = %f" % \
-      timeit.Timer('rs.write(prot)', setup_slow).timeit(number=iters)
-  print "FastStruct Acceler. = %f" % \
-      timeit.Timer('rs.write(prot)', setup_fast).timeit(number=iters)
-
-
-
-doTest()
-doBenchmark()
-
diff --git a/test/FullCamelTest.thrift b/test/FullCamelTest.thrift
new file mode 100644
index 0000000..cee4dd8
--- /dev/null
+++ b/test/FullCamelTest.thrift
@@ -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.
+ */
+
+namespace java thrift.test.fullcamel
+
+struct OneOfEachZZ {
+  1: bool im_true,
+  2: bool im_false,
+  3: byte a_bite,
+  4: i16 integer16,
+  5: i32 integer32,
+  6: i64 integer64,
+  7: double double_precision,
+  8: string some_characters,
+  9: string zomg_unicode,
+  10: bool what_who,
+}
+
+service UnderscoreSrv {
+  i64 some_rpc_call(1: string message)
+}
+
diff --git a/test/JavaDeepCopyTest.thrift b/test/JavaDeepCopyTest.thrift
new file mode 100644
index 0000000..fc974ae
--- /dev/null
+++ b/test/JavaDeepCopyTest.thrift
@@ -0,0 +1,19 @@
+include "JavaTypes.thrift"
+
+namespace java thrift.test
+
+struct DeepCopyFoo {
+  1: optional list<DeepCopyBar> l,
+  2: optional set<DeepCopyBar> s,
+  3: optional map<string, DeepCopyBar> m,
+  4: optional list<JavaTypes.Object> li,
+  5: optional set<JavaTypes.Object> si,
+  6: optional map<string, JavaTypes.Object> mi,
+  7: optional DeepCopyBar bar,
+}
+
+struct DeepCopyBar {
+  1: optional string a,
+  2: optional i32 b,
+  3: optional bool c,
+}
diff --git a/test/JavaTypes.thrift b/test/JavaTypes.thrift
new file mode 100644
index 0000000..8c733ad
--- /dev/null
+++ b/test/JavaTypes.thrift
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+namespace java thrift.test
+
+struct Integer {
+  1: i32 val
+}
+
+struct String {
+  1: string val
+}
+
+struct Boolean {
+  1: bool val
+}
+
+struct Double {
+  1: double val
+}
+
+struct Long {
+  1: i64 val
+}
+
+struct Byte {
+  1: byte val
+}
+
+struct Float {
+  1: double val
+}
+
+struct List {
+  1: list<string> vals
+}
+
+struct ArrayList {
+  1: list<string> vals
+}
+
+struct SortedMap {
+  1: map<string, string> vals
+}
+
+struct TreeMap {
+  1: map<string, string> vals
+}
+
+struct HashMap {
+  1: map<string, String> vals
+}
+
+struct Map {
+  1: map<double, Double> vals
+}
+
+struct Object {
+  1: Integer integer,
+  2: String str,
+  3: Boolean boolean_field,
+  4: Double dbl,
+  5: Byte bite,
+  6: map<i32, Integer> intmap,
+  7: Map somemap,
+}
+
+exception Exception {
+  1: string msg
+}
+
+service AsyncNonblockingService {
+  Object mymethod(
+    1: Integer integer,
+    2: String str,
+    3: Boolean boolean_field,
+    4: Double dbl,
+    5: Byte bite,
+    6: map<i32, Integer> intmap,
+    7: Map somemap,
+  ) throws (1:Exception ex);
+}
+
+struct SafeBytes {
+  1: binary bytes;
+}
+
diff --git a/test/JsDeepConstructorTest.thrift b/test/JsDeepConstructorTest.thrift
new file mode 100644
index 0000000..ef5126f
--- /dev/null
+++ b/test/JsDeepConstructorTest.thrift
@@ -0,0 +1,18 @@
+struct Simple {
+  1: string value
+}
+
+struct Complex {
+  1: Simple struct_field
+  2: list<Simple> struct_list_field
+  3: set<Simple> struct_set_field
+  4: map<string,Simple> struct_map_field
+  5: list<set<map<string,list<Simple>>>> struct_nested_containers_field
+  6: map<string, list<map<string,Simple>> > struct_nested_containers_field2
+  7: list<list<string>> list_of_list_field
+  8: list<list<list<string>>> list_of_list_of_list_field
+}
+
+struct ComplexList {
+  1: list<Complex> struct_list_field;
+}
diff --git a/test/Makefile.am b/test/Makefile.am
index 175f477..68f1986 100755
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -17,45 +17,110 @@
 # under the License.
 #
 
-SUBDIRS = nodejs
+SUBDIRS = features
+PRECROSS_TARGET =
+
+if WITH_C_GLIB
+SUBDIRS += c_glib
+PRECROSS_TARGET += precross-c_glib
+endif
+
+if WITH_CL
+SUBDIRS += cl
+PRECROSS_TARGET += precross-cl
+endif
+
+if WITH_MONO
+SUBDIRS += csharp
+PRECROSS_TARGET += precross-csharp
+endif
 
 if WITH_CPP
 SUBDIRS += cpp
+PRECROSS_TARGET += precross-cpp
 endif
 
 if WITH_PERL
 SUBDIRS += perl
+PRECROSS_TARGET += precross-perl
 endif
 
 if WITH_PHP
 SUBDIRS += php
+PRECROSS_TARGET += precross-php
+endif
+
+if WITH_DART
+SUBDIRS += dart
+PRECROSS_TARGET += precross-dart
 endif
 
 if WITH_PYTHON
 SUBDIRS += py
-SUBDIRS += py.twisted
+PRECROSS_TARGET += precross-py
 SUBDIRS += py.tornado
+if WITH_TWISTED_TEST
+SUBDIRS += py.twisted
+endif
 endif
 
 if WITH_RUBY
 SUBDIRS += rb
+PRECROSS_TARGET += precross-rb
 endif
 
 if WITH_HASKELL
 SUBDIRS += hs
 endif
 
+if WITH_HAXE
+SUBDIRS += haxe
+endif
+
+if WITH_DOTNETCORE
+SUBDIRS += netcore
+endif
+
+if WITH_GO
+SUBDIRS += go
+PRECROSS_TARGET += precross-go
+endif
+
+if WITH_ERLANG
+SUBDIRS += erl
+PRECROSS_TARGET += precross-erl
+endif
+
+if WITH_LUA
+SUBDIRS += lua
+PRECROSS_TARGET += precross-lua
+endif
+
+if WITH_RS
+SUBDIRS += rs
+PRECROSS_TARGET += precross-rs
+endif
+
 #
 # generate html for ThriftTest.thrift
 #
 check-local:
 	$(top_builddir)/compiler/cpp/thrift --gen html -r $(top_srcdir)/test/ThriftTest.thrift
 
+clean-local:
+	rm -rf $(top_srcdir)/test/gen-html
+
 EXTRA_DIST = \
-	test.sh \
+	audit \
+	crossrunner \
+	keys \
+	c_glib \
+	cl \
 	cpp \
+	dart \
+	erl \
 	hs \
-	nodejs \
+	lua \
 	ocaml \
 	perl \
 	php \
@@ -63,19 +128,43 @@
 	py.twisted \
 	py.tornado \
 	rb \
+	rs \
 	threads \
 	AnnotationTest.thrift \
 	BrokenConstants.thrift \
 	ConstantsDemo.thrift \
 	DebugProtoTest.thrift \
+	DoubleConstantsTest.thrift \
 	DenseLinkingTest.thrift \
 	DocTest.thrift \
+	EnumTest.thrift \
+	FullCamelTest.thrift \
 	Include.thrift \
 	JavaBeansTest.thrift \
+	JavaDeepCopyTest.thrift \
+	JavaTypes.thrift \
+	JsDeepConstructorTest.thrift \
 	ManyOptionals.thrift \
 	ManyTypedefs.thrift \
+	NameConflictTest.thrift \
 	OptionalRequiredTest.thrift \
+	Recursive.thrift \
+	ReuseObjects.thrift \
+	EnumContainersTest.thrift \
 	SmallTest.thrift \
 	StressTest.thrift \
 	ThriftTest.thrift \
-	FastbinaryTest.py
+	TypedefTest.thrift \
+	UnsafeTypes.thrift \
+	known_failures_Linux.json \
+	test.py \
+	tests.json \
+	rebuild_known_failures.sh \
+	result.js \
+	index.html \
+	README.md \
+	valgrind.suppress
+
+precross-%:
+	$(MAKE) -C $* precross
+precross: $(PRECROSS_TARGET)
diff --git a/test/NameConflictTest.thrift b/test/NameConflictTest.thrift
new file mode 100644
index 0000000..d3efb47
--- /dev/null
+++ b/test/NameConflictTest.thrift
@@ -0,0 +1,110 @@
+// Naming testcases, sepcifically for these tickets (but not limited to them)
+// THRIFT-2508 Uncompileable C# code due to language keywords in IDL
+// THRIFT-2557 error CS0542 member names cannot be the same as their enclosing type
+
+
+struct using {
+    1: double single
+    2: double integer
+}
+
+struct delegate {
+    1: string partial
+    2: delegate delegate
+}
+
+struct get {
+    1: bool sbyte
+}
+
+struct partial {
+    1: using using
+    2: bool read
+    3: bool write
+}
+
+enum Maybe {
+  JUST = 1,
+  TRUE = 2,
+  FALSE = 3
+}
+
+enum Either {
+  LEFT = 1,
+  RIGHT = 2
+}
+
+struct foldr {
+  1: string id
+}
+
+struct of {
+  1: string let
+  2: string where
+}
+
+struct ofOf {
+  1: of Of
+}
+
+
+struct ClassAndProp {
+  1: bool ClassAndProp
+  2: bool ClassAndProp_
+  3: bool ClassAndProp__
+  4: bool ClassAndProper
+}
+
+struct second_chance {
+  1: bool SECOND_CHANCE
+  2: bool SECOND_CHANCE_
+  3: bool SECOND_CHANCE__
+  4: bool SECOND_CHANCES
+}
+
+struct NOW_EAT_THIS {
+  1: bool now_eat_this
+  2: bool now_eat_this_
+  3: bool now_eat_this__
+  4: bool now_eat_this_and_this
+}
+
+struct TheEdgeCase {
+  1: bool theEdgeCase
+  2: bool theEdgeCase_
+  3: bool theEdgeCase__
+  4: bool TheEdgeCase
+  5: bool TheEdgeCase_
+  6: bool TheEdgeCase__
+}
+
+struct Tricky_ {
+  1: bool tricky
+  2: bool Tricky
+}
+
+struct Nested {
+  1: ClassAndProp ClassAndProp
+  2: second_chance second_chance
+  3: NOW_EAT_THIS NOW_EAT_THIS
+  4: TheEdgeCase TheEdgeCase
+  5: Tricky_ Tricky_
+  6: Nested Nested
+}
+
+exception Problem_ {
+  1: bool problem
+  2: bool Problem
+}
+
+
+service extern {
+    delegate event(1: partial get)
+    void Foo(1: Nested Foo_args) throws (1: Problem_ Foo_result)
+}
+
+service qualified {
+    Maybe maybe(1: Maybe foldr)
+    Either either(1: foldr of)
+}
+// eof
diff --git a/test/OptionalRequiredTest.thrift b/test/OptionalRequiredTest.thrift
index dcdd0f2..a608898 100644
--- a/test/OptionalRequiredTest.thrift
+++ b/test/OptionalRequiredTest.thrift
@@ -80,3 +80,9 @@
   5: required binary req_bin;
   6: optional binary opt_bin;
 }
+
+struct Binaries {
+  4: binary bin;
+  5: required binary req_bin;
+  6: optional binary opt_bin;
+}
diff --git a/test/README.md b/test/README.md
new file mode 100755
index 0000000..0682f5d
--- /dev/null
+++ b/test/README.md
@@ -0,0 +1,185 @@
+# Apache Thrift - integration test suite
+
+This is the cross everything integration test suite for Apache Thrift.
+
+## Run
+
+### A. Using Make
+
+The test can be executed by:
+
+    make cross
+
+This starts the [test.py](test.py) script which does the real cross test with
+different transports, protocols and languages.
+
+Note that this skips any language that is not built locally. It also skips
+tests that are known to be failing. If you need more control over which tests
+to run, read following section.
+
+### B. Using test script directly
+
+Alternatively, you can invoke [test.py](test.py) directly. You need to run`make
+precross` once before executing it for the first time.
+
+For example, if you changed something in `nodejs` library and need to verify
+the patch, you can skip everything except `nodejs` itself and some reference
+implementation (currently `cpp` and `java` are recommended) like this:
+
+    ./configure --without-c_glib -without-csharp --without-erlang --without-lua ...
+    make precross -j8
+    test/test.py --server cpp,java --client nodejs
+    test/test.py --server nodejs --client cpp,java
+
+Another useful flag is --regex. For example, to run all tests that involve
+Java TBinaryProtocol:
+
+    test/test.py --regex "java.*binary"
+
+## Test case definition file
+
+The cross test cases are defined in [tests.json](tests.json).
+The root element is collection of test target definitions.
+Each test target definition looks like this:
+
+    {
+      "name": "somelib",
+
+      "client": {
+        "command": ["somelib_client_executable"],
+        "workdir": "somelib/bin",
+        "protocols": ["binary"],
+        "transports": ["buffered"],
+        "sockets": ["ip"],
+      },
+      "server": {
+        "command": ["somelib_server_executable"],
+        "workdir": "somelib/bin",
+        "protocols": ["binary"],
+        "transports": ["buffered"],
+        "sockets": ["ip", "ip-ssl"],
+      }
+    }
+
+Either client or server definition or both should be present.
+
+Parameters that are common to both `client` and `server` can be put to target
+definition root:
+
+    {
+      "name": "somelib",
+
+      "workdir": "somelib/bin",
+      "protocols": ["binary"],
+      "transports": ["buffered"],
+      "sockets": ["ip"],
+
+      "client": { "command": ["somelib_client_executable"] },
+      "server": {
+        "command": ["somelib_server_executable"],
+        "sockets": ["ip-ssl"]
+      }
+    }
+
+For the complete list of supported keys and their effect, see source code
+comment at the opt of [crossrunner/collect.py](crossrunner/collect.py).
+
+
+## List of known failures
+
+Since many cross tests currently fail (mainly due to partial incompatibility
+around exception handling), the test script specifically report for "not known
+before" failures.
+
+For this purpose, test cases known to (occasionally) fail are listed in
+`known_failures_<platform>.json` where `<platform>` matches with python
+`platform.system()` string.
+
+Currently, only Linux version is included.
+
+FYI, the file is initially generated by
+
+    test/test.py --update-expected-failures=overwrite
+
+after a full test run, then repeatedly
+
+    test/test.py --skip-known-failures
+    test/test.py --update-expected-failures=merge
+
+to update the known failures, run
+
+    make fail
+
+## Test executable specification
+
+### Command line parameters
+
+Unit tests for languages are usually located under lib/<lang>/test/
+cross language tests according to [ThriftTest.thrift](ThriftTest.thrift) shall be
+provided for every language including executables with the following command
+line interface:
+
+**Server command line interface:**
+
+    $ ./cpp/TestServer -h
+    Allowed options:
+      -h [ --help ]               produce help message
+      --port arg (=9090)          Port number to listen
+      --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)
+      --named-pipe arg            Windows Named Pipe (e.g. MyThriftPipe)
+      --server-type arg (=simple) type of server, "simple", "thread-pool",
+                                  "threaded", or "nonblocking"
+      --transport arg (=buffered) transport: buffered, framed, http, anonpipe
+      --protocol arg (=binary)    protocol: binary, compact, json
+      --ssl                       Encrypted Transport using SSL
+      --processor-events          processor-events
+      -n [ --workers ] arg (=4)   Number of thread pools workers. Only valid for
+                              thread-pool server type
+
+**Client command line interface:**
+
+    $ ./cpp/TestClient -h
+    Allowed options:
+      -h [ --help ]               produce help message
+      --host arg (=localhost)     Host to connect
+      --port arg (=9090)          Port number to connect
+      --domain-socket arg         Domain Socket (e.g. /tmp/ThriftTest.thrift),
+                                  instead of host and port
+      --named-pipe arg            Windows Named Pipe (e.g. MyThriftPipe)
+      --anon-pipes hRead hWrite   Windows Anonymous Pipes pair (handles)
+      --transport arg (=buffered) Transport: buffered, framed, http, evhttp
+      --protocol arg (=binary)    Protocol: binary, compact, json
+      --ssl                       Encrypted Transport using SSL
+      -n [ --testloops ] arg (=1) Number of Tests
+      -t [ --threads ] arg (=1)   Number of Test threads
+
+If you have executed the **make check** or **make cross** then you will be able to browse
+[gen-html/ThriftTest.html](gen-html/ThriftTest.html) with the test documentation.
+
+### Return code
+
+The return code (exit code) shall be 0 on success, or an integer in the range 1 - 255 on errors.
+In order to signal failed tests, the return code shall be composed from these bits to indicate
+failing tests:
+
+      #define TEST_BASETYPES     1  // 0000 0001
+      #define TEST_STRUCTS       2  // 0000 0010
+      #define TEST_CONTAINERS    4  // 0000 0100
+      #define TEST_EXCEPTIONS    8  // 0000 1000
+      #define TEST_UNKNOWN      64  // 0100 0000 (Failed to prepare environemt etc.)
+      #define TEST_TIMEOUT     128  // 1000 0000
+      #define TEST_NOTUSED      48  // 0011 0000 (reserved bits)
+
+Tests that have not been executed at all count as errors.
+
+**Example:**
+
+During tests, the test client notices that some of the Struct tests fail.
+Furthermore, due to some other problem none of the Exception tests is executed.
+Therefore, the test client returns the code `10 = 2 | 8`, indicating the failure
+of both test 2 (TEST_STRUCTS) and test 8 (TEST_EXCEPTIONS).
+
+
+## SSL
+Test Keys and Certificates are provided in multiple formats under the following
+directory [test/keys](keys)
diff --git a/test/Recursive.thrift b/test/Recursive.thrift
new file mode 100644
index 0000000..c982582
--- /dev/null
+++ b/test/Recursive.thrift
@@ -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.
+ */
+
+struct RecTree {
+  1: list<RecTree> children
+  2: i16 item
+}
+
+struct RecList {
+  1: RecList & nextitem
+  3: i16 item
+}
+
+struct CoRec {
+  1:  CoRec2 & other
+}
+
+struct CoRec2 {
+  1: CoRec other
+}
+
+struct VectorTest {
+  1: list<RecList> lister;
+}
+
+service TestService
+{
+  RecTree echoTree(1:RecTree tree)
+  RecList echoList(1:RecList lst)
+  CoRec echoCoRec(1:CoRec item)
+}
diff --git a/test/ReuseObjects.thrift b/test/ReuseObjects.thrift
new file mode 100644
index 0000000..2dd6c6e
--- /dev/null
+++ b/test/ReuseObjects.thrift
@@ -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.
+ */
+
+// The java codegenerator has option to reuse objects for deserialization
+
+namespace java thrift.test
+
+include "ThriftTest.thrift"
+
+struct Reuse {
+  1: i32 val1;
+  2: set<string> val2;
+}
+
diff --git a/test/StressTest.thrift b/test/StressTest.thrift
index e09a1fc..431811b 100644
--- a/test/StressTest.thrift
+++ b/test/StressTest.thrift
@@ -19,16 +19,17 @@
 
 namespace cpp test.stress
 namespace d thrift.test.stress
+namespace go stress
 
 service Service {
 
   void echoVoid(),
-  byte echoByte(1: byte arg),
+  i8 echoByte(1: i8 arg),
   i32 echoI32(1: i32 arg),
   i64 echoI64(1: i64 arg),
   string echoString(1: string arg),
-  list<byte>  echoList(1: list<byte> arg),
-  set<byte>  echoSet(1: set<byte> arg),
-  map<byte, byte>  echoMap(1: map<byte, byte> arg),
+  list<i8>  echoList(1: list<i8> arg),
+  set<i8>  echoSet(1: set<i8> arg),
+  map<i8, i8>  echoMap(1: map<i8, i8> arg),
 }
 
diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift
index 500f0ea..3499ab5 100644
--- a/test/ThriftTest.thrift
+++ b/test/ThriftTest.thrift
@@ -31,10 +31,13 @@
 namespace st ThriftTest
 namespace py ThriftTest
 namespace py.twisted ThriftTest
-namespace go ThriftTest
+namespace go thrifttest
 namespace php ThriftTest
 namespace delphi Thrift.Test
 namespace cocoa ThriftTest
+namespace lua ThriftTest
+namespace xsd test (uri = 'http://thrift.apache.org/ns/ThriftTest')
+namespace netcore ThriftTest
 
 // Presence of namespaces and sub-namespaces for which there is
 // no generator should compile with warnings only
@@ -78,14 +81,14 @@
 struct Xtruct
 {
   1:  string string_thing,
-  4:  byte   byte_thing,
+  4:  i8     byte_thing,
   9:  i32    i32_thing,
   11: i64    i64_thing
 }
 
 struct Xtruct2
 {
-  1: byte   byte_thing,
+  1: i8     byte_thing,  // used to be byte, hence the name
   2: Xtruct struct_thing,
   3: i32    i32_thing
 }
@@ -103,15 +106,24 @@
 {
   1: map<Numberz, UserId> userMap,
   2: list<Xtruct> xtructs
-}
+} (python.immutable= "")
 
 struct CrazyNesting {
   1: string string_field,
   2: optional set<Insanity> set_field,
-  3: required list< map<set<i32>,map<i32,set<list<map<Insanity,string>>>>>> list_field,
+  // Do not insert line break as test/go/Makefile.am is removing this line with pattern match
+  3: required list<map<set<i32> (python.immutable = ""), map<i32,set<list<map<Insanity,string>(python.immutable = "")> (python.immutable = "")>>>> list_field,
   4: binary binary_field
 }
 
+union SomeUnion {
+  1: map<Numberz, UserId> map_thing,
+  2: string string_thing,
+  3: i32 i32_thing,
+  4: Xtruct3 xtruct_thing,
+  5: Insanity insanity_thing
+}
+
 exception Xception {
   1: i32 errorCode,
   2: string message
@@ -134,88 +146,103 @@
    * Prints "testVoid()" and returns nothing.
    */
   void         testVoid(),
-  
+
   /**
    * Prints 'testString("%s")' with thing as '%s'
    * @param string thing - the string to print
    * @return string - returns the string 'thing'
    */
   string       testString(1: string thing),
-  
+
+  /**
+   * Prints 'testBool("%s")' where '%s' with thing as 'true' or 'false'
+   * @param bool  thing - the bool data to print
+   * @return bool  - returns the bool 'thing'
+   */
+  bool         testBool(1: bool thing),
+
   /**
    * Prints 'testByte("%d")' with thing as '%d'
-   * @param byte thing - the byte to print
-   * @return byte - returns the byte 'thing'
+   * The types i8 and byte are synonyms, use of i8 is encouraged, byte still exists for the sake of compatibility.
+   * @param byte thing - the i8/byte to print
+   * @return i8 - returns the i8/byte 'thing'
    */
-  byte         testByte(1: byte thing),
-  
+  i8           testByte(1: i8 thing),
+
   /**
    * Prints 'testI32("%d")' with thing as '%d'
    * @param i32 thing - the i32 to print
    * @return i32 - returns the i32 'thing'
    */
   i32          testI32(1: i32 thing),
- 
+
   /**
    * Prints 'testI64("%d")' with thing as '%d'
    * @param i64 thing - the i64 to print
    * @return i64 - returns the i64 'thing'
    */
   i64          testI64(1: i64 thing),
-  
+
   /**
    * Prints 'testDouble("%f")' with thing as '%f'
    * @param double thing - the double to print
    * @return double - returns the double 'thing'
    */
   double       testDouble(1: double thing),
-  
+
   /**
-   * Prints 'testStruct("{%s}")' where thing has been formatted into a string of comma seperated values
+   * Prints 'testBinary("%s")' where '%s' is a hex-formatted string of thing's data
+   * @param binary  thing - the binary data to print
+   * @return binary  - returns the binary 'thing'
+   */
+  binary       testBinary(1: binary thing),
+
+  /**
+   * Prints 'testStruct("{%s}")' where thing has been formatted into a string of comma separated values
    * @param Xtruct thing - the Xtruct to print
    * @return Xtruct - returns the Xtruct 'thing'
    */
   Xtruct       testStruct(1: Xtruct thing),
-  
+
   /**
    * Prints 'testNest("{%s}")' where thing has been formatted into a string of the nested struct
    * @param Xtruct2 thing - the Xtruct2 to print
    * @return Xtruct2 - returns the Xtruct2 'thing'
    */
   Xtruct2      testNest(1: Xtruct2 thing),
- 
+
   /**
    * Prints 'testMap("{%s")' where thing has been formatted into a string of  'key => value' pairs
-   *  seperated by commas and new lines
+   *  separated by commas and new lines
    * @param map<i32,i32> thing - the map<i32,i32> to print
    * @return map<i32,i32> - returns the map<i32,i32> 'thing'
    */
   map<i32,i32> testMap(1: map<i32,i32> thing),
-  
+
   /**
    * Prints 'testStringMap("{%s}")' where thing has been formatted into a string of  'key => value' pairs
-   *  seperated by commas and new lines
+   *  separated by commas and new lines
    * @param map<string,string> thing - the map<string,string> to print
    * @return map<string,string> - returns the map<string,string> 'thing'
    */
   map<string,string> testStringMap(1: map<string,string> thing),
-  
+
   /**
    * Prints 'testSet("{%s}")' where thing has been formatted into a string of  values
-   *  seperated by commas and new lines
+   *  separated by commas and new lines
    * @param set<i32> thing - the set<i32> to print
    * @return set<i32> - returns the set<i32> 'thing'
    */
   set<i32>     testSet(1: set<i32> thing),
-  
+
   /**
    * Prints 'testList("{%s}")' where thing has been formatted into a string of  values
-   *  seperated by commas and new lines
+   *  separated by commas and new lines
    * @param list<i32> thing - the list<i32> to print
    * @return list<i32> - returns the list<i32> 'thing'
    */
   list<i32>    testList(1: list<i32> thing),
-  
+
   /**
    * Prints 'testEnum("%d")' where thing has been formatted into it's numeric value
    * @param Numberz thing - the Numberz to print
@@ -242,27 +269,27 @@
    * So you think you've got this all worked, out eh?
    *
    * Creates a the returned map with these values and prints it out:
-   *   { 1 => { 2 => argument, 
-   *            3 => argument, 
+   *   { 1 => { 2 => argument,
+   *            3 => argument,
    *          },
    *     2 => { 6 => <empty Insanity struct>, },
    *   }
-   * @return map<UserId, map<Numberz,Insanity>> - a map with the above values 
+   * @return map<UserId, map<Numberz,Insanity>> - a map with the above values
    */
   map<UserId, map<Numberz,Insanity>> testInsanity(1: Insanity argument),
 
   /**
    * Prints 'testMulti()'
-   * @param byte arg0 - 
-   * @param i32 arg1 - 
-   * @param i64 arg2 - 
-   * @param map<i16, string> arg3 - 
-   * @param Numberz arg4 - 
-   * @param UserId arg5 - 
+   * @param i8 arg0 -
+   * @param i32 arg1 -
+   * @param i64 arg2 -
+   * @param map<i16, string> arg3 -
+   * @param Numberz arg4 -
+   * @param UserId arg5 -
    * @return Xtruct - returns an Xtruct with string_thing = "Hello2, byte_thing = arg0, i32_thing = arg1
    *    and i64_thing = arg2
    */
-  Xtruct testMulti(1: byte arg0, 2: i32 arg1, 3: i64 arg2, 4: map<i16, string> arg3, 5: Numberz arg4, 6: UserId arg5),
+  Xtruct testMulti(1: i8 arg0, 2: i32 arg1, 3: i64 arg2, 4: map<i16, string> arg3, 5: Numberz arg4, 6: UserId arg5),
 
   /**
    * Print 'testException(%s)' with arg as '%s'
@@ -277,7 +304,7 @@
    * Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s'
    * @param string arg - a string indication what type of exception to throw
    * if arg0 == "Xception" throw Xception with errorCode = 1001 and message = "This is an Xception"
-   * elsen if arg0 == "Xception2" throw Xception2 with errorCode = 2002 and message = "This is an Xception2"
+   * elsen if arg0 == "Xception2" throw Xception2 with errorCode = 2002 and struct_thing.string_thing = "This is an Xception2"
    * else do not throw anything
    * @return Xtruct - an Xtruct with string_thing = arg1
    */
@@ -294,7 +321,12 @@
 
 service SecondService
 {
-  void blahBlah()
+  /**
+   * Prints 'testString("%s")' with thing as '%s'
+   * @param string thing - the string to print
+   * @return string - returns the string 'thing'
+   */
+  string secondtestString(1: string thing)
 }
 
 struct VersioningTestV1 {
@@ -307,7 +339,7 @@
        1: i32 begin_in_both,
 
        2: i32 newint,
-       3: byte newbyte,
+       3: i8 newbyte,
        4: i16 newshort,
        5: i64 newlong,
        6: double newdouble
diff --git a/test/TypedefTest.thrift b/test/TypedefTest.thrift
new file mode 100644
index 0000000..9437478
--- /dev/null
+++ b/test/TypedefTest.thrift
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+namespace cpp thrift.test
+
+typedef i32 MyInt32
+typedef string MyString;
+
+struct TypedefTestStruct {
+  1: MyInt32 field_MyInt32;
+  2: MyString field_MyString;
+  3: i32 field_Int32;
+  4: string field_String;
+}
+
+typedef TypedefTestStruct MyStruct,
\ No newline at end of file
diff --git a/test/UnsafeTypes.thrift b/test/UnsafeTypes.thrift
new file mode 100644
index 0000000..b38c905
--- /dev/null
+++ b/test/UnsafeTypes.thrift
@@ -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.
+ */
+
+namespace java thrift.test
+
+struct UnsafeBytes {
+  1: binary bytes;
+}
diff --git a/test/audit/README.md b/test/audit/README.md
new file mode 100644
index 0000000..412f8d5
--- /dev/null
+++ b/test/audit/README.md
@@ -0,0 +1,40 @@
+Typical usage
+=============
+```
+thrift.exe --audit <oldFile> <newFile>
+```
+Example run
+===========
+```
+> thrift.exe --audit test.thrift break1.thrift
+[Thrift Audit Failure:break1.thrift] New Thrift File has missing function base_function3
+[Thrift Audit Warning:break1.thrift] Constant const3 has different value
+```
+
+Problems that the audit tool can catch
+======================================
+Errors
+* Removing an enum value
+* Changing the type of a struct field
+* Changing the required-ness of a struct field
+* Removing a struct field
+* Adding a required struct field
+* Adding a struct field 'in the middle'.  This usually indicates an old ID has been recycled
+* Struct removed
+* Oneway-ness change
+* Return type change
+* Missing function
+* Missing service
+* Change in service inheritance
+
+Warnings
+* Removing a language namespace declaration
+* Changing a namespace
+* Changing an enum value's name
+* Removing an enum class
+* Default value changed
+* Struct field name change
+* Removed constant
+* Type of constant changed
+* Value of constant changed
+    
\ No newline at end of file
diff --git a/test/audit/break1.thrift b/test/audit/break1.thrift
new file mode 100644
index 0000000..f77f672
--- /dev/null
+++ b/test/audit/break1.thrift
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+
+//Thrift Method removed from service base.
+
+namespace cpp test
+
+//constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3= [23, 32],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break10.thrift b/test/audit/break10.thrift
new file mode 100644
index 0000000..00690aa
--- /dev/null
+++ b/test/audit/break10.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+//break10 - Struct field removed from struct2 id =1
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break11.thrift b/test/audit/break11.thrift
new file mode 100644
index 0000000..a4e0a7d
--- /dev/null
+++ b/test/audit/break11.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+//break11 - Struct field removed from struct3 id =7
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break12.thrift b/test/audit/break12.thrift
new file mode 100644
index 0000000..e5522ed
--- /dev/null
+++ b/test/audit/break12.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// derived1_function1 return type changed from enum1 to enum2
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum2 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break13.thrift b/test/audit/break13.thrift
new file mode 100644
index 0000000..66975cd
--- /dev/null
+++ b/test/audit/break13.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// derived1_function6 return type changed from struct1 to struct2
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct2 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break14.thrift b/test/audit/break14.thrift
new file mode 100644
index 0000000..4ccd503
--- /dev/null
+++ b/test/audit/break14.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+// derived1_function6 return type changed from string to double 
+
+namespace cpp test
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    double derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break15.thrift b/test/audit/break15.thrift
new file mode 100644
index 0000000..95f69e6
--- /dev/null
+++ b/test/audit/break15.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+// break15 - derived2_function1 return type changed from list<i32> to list<i16>
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i16> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break16.thrift b/test/audit/break16.thrift
new file mode 100644
index 0000000..cdcff7d
--- /dev/null
+++ b/test/audit/break16.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// break 16 - derived2_function5 return type changed from map<test_enum1, test_enum2> to map<test_enum3, test_enum2>
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum3, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break17.thrift b/test/audit/break17.thrift
new file mode 100644
index 0000000..353b142
--- /dev/null
+++ b/test/audit/break17.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//break17 - derived2_function6 return type changed from map<struct1,struct2> to map<struct1, struct3>
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct3> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break18.thrift b/test/audit/break18.thrift
new file mode 100644
index 0000000..c778b6a
--- /dev/null
+++ b/test/audit/break18.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//break18- oneway removed from base_oneway
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break19.thrift b/test/audit/break19.thrift
new file mode 100644
index 0000000..1a0b229
--- /dev/null
+++ b/test/audit/break19.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//break19 - oneway added to base_function1
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    oneway void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break2.thrift b/test/audit/break2.thrift
new file mode 100644
index 0000000..6f4fe2d
--- /dev/null
+++ b/test/audit/break2.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+//Struct field changed in test_struct1
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i32 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break20.thrift b/test/audit/break20.thrift
new file mode 100644
index 0000000..9ae5f00
--- /dev/null
+++ b/test/audit/break20.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+// break 20 - first enum value removed from enum1
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break21.thrift b/test/audit/break21.thrift
new file mode 100644
index 0000000..f7da400
--- /dev/null
+++ b/test/audit/break21.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+//break21- last enum value removed from enum2
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break22.thrift b/test/audit/break22.thrift
new file mode 100644
index 0000000..3808349
--- /dev/null
+++ b/test/audit/break22.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+//break22 - in-between enum value removed from enum1
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break23.thrift b/test/audit/break23.thrift
new file mode 100644
index 0000000..ff95a42
--- /dev/null
+++ b/test/audit/break23.thrift
@@ -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.
+ */
+
+//break23 - required struct field added to struct4
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2,
+    3: required i64 struct4_member3
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break24.thrift b/test/audit/break24.thrift
new file mode 100644
index 0000000..bb4d5b9
--- /dev/null
+++ b/test/audit/break24.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//break24 - removed inheritance from derived1.
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break25.thrift b/test/audit/break25.thrift
new file mode 100644
index 0000000..6efe97e
--- /dev/null
+++ b/test/audit/break25.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//Changed inheritance of derived2
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends derived1 {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break26.thrift b/test/audit/break26.thrift
new file mode 100644
index 0000000..6576d9b
--- /dev/null
+++ b/test/audit/break26.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//break26 - Field type changed in base_function1 argument id=3
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: double function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
+
diff --git a/test/audit/break27.thrift b/test/audit/break27.thrift
new file mode 100644
index 0000000..b556706
--- /dev/null
+++ b/test/audit/break27.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+// break27 - argument changed base_function2 list<enum1> to list<enum3> id =8
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum3> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break28.thrift b/test/audit/break28.thrift
new file mode 100644
index 0000000..c64e558
--- /dev/null
+++ b/test/audit/break28.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+//break28- derived1_function5 arguement type changed map<i64, double> to list<i64>
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: list<i64> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break29.thrift b/test/audit/break29.thrift
new file mode 100644
index 0000000..52f3081
--- /dev/null
+++ b/test/audit/break29.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//break29 - base_function2 arguemnt type changed list<string> to string
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: string function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break3.thrift b/test/audit/break3.thrift
new file mode 100644
index 0000000..ded9972
--- /dev/null
+++ b/test/audit/break3.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//break3 - Struct field changed in test_struct1(enum1 to enum2)
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum2 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break30.thrift b/test/audit/break30.thrift
new file mode 100644
index 0000000..818dd6e
--- /dev/null
+++ b/test/audit/break30.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+// break30- derived1_function6 argument changed struct1 to map<struct1,struct1>
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    map<test_struct1,test_struct1> derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break31.thrift b/test/audit/break31.thrift
new file mode 100644
index 0000000..7ca3804
--- /dev/null
+++ b/test/audit/break31.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//break31 - Exception removed to base_function2
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break32.thrift b/test/audit/break32.thrift
new file mode 100644
index 0000000..ca3f8a8
--- /dev/null
+++ b/test/audit/break32.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//break32- Exception1 field type changed for id =1
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i64 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break33.thrift b/test/audit/break33.thrift
new file mode 100644
index 0000000..42dbb82
--- /dev/null
+++ b/test/audit/break33.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//break33 - derived1_function1 exception type changed.
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception1 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break34.thrift b/test/audit/break34.thrift
new file mode 100644
index 0000000..af93e65
--- /dev/null
+++ b/test/audit/break34.thrift
@@ -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.
+ */
+
+//break34 - Field added to struct with Field ID being in between two existing field IDs
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    6: map<test_enum1, test_enum2> struct3_member6,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break4.thrift b/test/audit/break4.thrift
new file mode 100644
index 0000000..6a28ec0
--- /dev/null
+++ b/test/audit/break4.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+//Field type changed in test_struct1(bool to string)
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: string struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 =[23, 32],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break5.thrift b/test/audit/break5.thrift
new file mode 100644
index 0000000..18c22d1
--- /dev/null
+++ b/test/audit/break5.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+// member field type changed in test_struct1(bool to list<bool>)
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: list<bool> struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break6.thrift b/test/audit/break6.thrift
new file mode 100644
index 0000000..9b7a300
--- /dev/null
+++ b/test/audit/break6.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Field type changed in test_struct2 (list<double> to list<i16>)
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<i16> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break7.thrift b/test/audit/break7.thrift
new file mode 100644
index 0000000..b31c2df
--- /dev/null
+++ b/test/audit/break7.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+//break7 - requiredness removed in struct6
+
+namespace cpp test
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break8.thrift b/test/audit/break8.thrift
new file mode 100644
index 0000000..9acac09
--- /dev/null
+++ b/test/audit/break8.thrift
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//break8 - requiredness addedd in struct5
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: required string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/break9.thrift b/test/audit/break9.thrift
new file mode 100644
index 0000000..62b319d
--- /dev/null
+++ b/test/audit/break9.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+//break9 - Struct field removed from struct1
+
+
+namespace cpp test
+//Constants
+
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/test.thrift b/test/audit/test.thrift
new file mode 100644
index 0000000..e9834b3
--- /dev/null
+++ b/test/audit/test.thrift
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+namespace cpp test
+
+//Constants
+const i32 const1 = 123;
+const double const2 = 23.3;
+const map<string,string> const3 = {"hello":"world", "thrift":"audit"};
+
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.5,
+    5: string struct1_member5 = "Audit test",
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 struct1_member9
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> struct2_member2,
+    3: list<i64> struct2_member3 = [23, 32 ],
+    4: list<double> struct2_member4,
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:2, 3:4},
+    2: map<i64, double> struct3_member2 = {10:1.1, 20:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1,
+    2: string struct5_member2 = "Thrift Audit Test"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base {
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/audit/thrift_audit_test.pl b/test/audit/thrift_audit_test.pl
new file mode 100644
index 0000000..69ed4dc
--- /dev/null
+++ b/test/audit/thrift_audit_test.pl
@@ -0,0 +1,261 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+
+#break1 - Thrift method removed from service base
+#break2 - Struct field changed in test_struct1(i16 to i32)
+#break3 - Struct field changed in test_struct1(enum1 to enum2)
+#break4 - Field type changed in test_struct1(bool to string)
+#break5- member field type changed in test_struct1(bool to list<bool>)
+#break6-  Field type changed in test_struct2 (list<double> to list<i16>)
+#break7 - requiredness removed in struct6
+#break8 - requiredness addedd in struct5
+#break9 - Struct field removed from struct1
+#break10 - Struct field removed from struct2 id = 1
+#break11 - Struct field removed from struct3 last id
+#break12 -  derived1_function1 return type changed from enum1 to enum2
+#break13 - derived1_function6 return type changed from struct1 to struct2
+#break14 -  derived1_function4 return type changed from string to double 
+#break15 - derived2_function1 return type changed from list<i32> to list<i16>
+#break16 - derived2_function5 return type changed from map<test_enum1,test_enum2> to map<test_enum3, test_enum2>
+#break17 - derived2_function6 return type changed from map<struct1,struct2> to map<struct1, struct3>
+#break18- oneway removed from base_oneway
+#break19 - oneway added to base_function1
+#break20 - first enum value removed from enum1
+#break21- last enum value removed from enum2
+#break22 - in-between enum value removed from enum1
+#break23 - required struct field added to struct4
+#break24 - removed inheritance of derived1.
+#break25 - changed inheritance of derived2.
+#break26 - Field type changed in base_function1 argument id=3
+#break27 - argument changed base_function2 list<enum1> to list<enum3> id =8
+#break28- derived1_function5 arguement type changed map<i64, double> to list<i64>
+#break29 - base_function2 arguemnt type changed list<string> to string
+#break30- derived1_function6 argument changed struct1 to map<struct1,struct1>
+#break31 - Exception removed to base_function2
+#break32- Exception1 field type changed for id =1
+#break33 - derived1_function1 exception type changed.
+#break34 - Field added to struct with Field ID being in between two existing field IDs
+
+#warning.thrift
+#Changing defaults
+#Id=1 struct5
+#id=2 struct5 
+#id=4 struct2(list<double>)
+#id=3 struct2(list<i64>  default values removed)
+#id 4 struct1 change in double value
+#id 5 struct1 (default string value removed)
+#id=1 struct3 (change in map values)
+#id2 struct3 (change in map keys)
+
+#change in inheritance for derived1 and derived2
+
+#change in struct field names
+#id9 struct1
+#id2 struct2
+
+use strict;
+use warnings;
+use Getopt::Std;
+
+# globals
+my $gArguments = "";                # arguments that will be passed to AuditTool
+my $gAuditToolPath = "";
+my $gPreviousThriftPath;            # previous thrift path
+my $gCurrentThriftPath;             # current thrift path
+my $gThriftFileFolder;
+my $gBreakingFilesCount =34; 
+
+my $gVerbose = 0;
+#functions
+sub auditBreakingChanges;
+sub auditNonBreakingChanges;
+
+main();
+
+sub main
+{
+    parseOptions();
+    auditBreakingChanges();
+    auditNonBreakingChanges();
+}
+
+sub parseOptions
+{
+    my %options = ();
+    if ( getopts ('vf:o:t:',\%options) )
+    {
+        # current (new) thrift folder
+        if ($options{'f'})
+        {
+            $gThriftFileFolder = $options{'f'};
+            $gPreviousThriftPath = $gThriftFileFolder."/test.thrift";
+        }
+        else
+        {
+            die "Missing Folder containing thrift files\n";
+        }
+
+        if($options{'t'})
+        {
+            $gAuditToolPath = $options{'t'};
+        }
+        else
+        {
+            die "Audit Tool Path required \n";
+        }
+
+        if ($options{'v'})
+        {
+            $gVerbose = 1;
+        }
+
+    }
+}
+
+sub auditBreakingChanges
+{
+    my $breakingFileBaseName = $gThriftFileFolder."/break";
+    my $newThriftFile;
+    for(my $i=1; $i <= $gBreakingFilesCount; $i++)
+    {
+        $newThriftFile = $breakingFileBaseName."$i.thrift";
+        my $arguments =  $gPreviousThriftPath." ".$newThriftFile;
+        my ($exitCode, $output) = callThriftAuditTool($arguments);
+        print $output if $gVerbose eq 1;
+
+        if($exitCode == 1)
+        {
+            # thrift_audit returns 1 when it is not able to find files or other non-audit failures
+            print "exiting with exit code =1 i = ".$i."\n";
+            print $output;
+            exit $exitCode;
+        }
+        if($exitCode != 2)
+        {
+            # thrift-audit return 2 for audit failures. So for Breaking changes we should get 2 as return value.
+            print $output;
+            die "\nTEST FAILURE: Breaking Change not detected for thrift file $newThriftFile, code=$exitCode \n";
+        }
+        if(index($output,getMessageSubString("break$i")) == -1)
+        {
+            #Audit tool detected failure, but not the expected one. The change in breaking thrift file does not match getMessageSubString()
+            print $output;
+            die "\nTest FAILURE: Audit tool detected failure, but not the expected one!\n";
+        }
+        else
+        {
+            #Thrift audit tool has detected audit failure and has returned exited to status code 2
+            print "Test Pass: Audit Failure detected for thrift file break$i.thrift \n";
+        }
+    }
+
+}
+
+sub auditNonBreakingChanges
+{
+    my $breakingFileBaseName = $gThriftFileFolder."/warning";
+    my $newThriftFile;
+    $newThriftFile = $breakingFileBaseName.".thrift";
+    my $arguments =  $gPreviousThriftPath." ".$newThriftFile;
+    my ($exitCode, $output) = callThriftAuditTool($arguments);
+    print $output if $gVerbose eq 1;
+
+    if($exitCode == 1)
+    {
+        # thrift_audit returns 1 when it is not able to find files or other non-audit failures
+        print "exiting with exit code = 1  for file warning.thrift\n";
+        exit $exitCode;
+    }
+    elsif($exitCode != 0)
+    {
+        # thrift-audit return 0 if there are no audit failures.
+        die "\nTEST FAILURE: Non Breaking changes returned failure for thrift file $newThriftFile \n";
+    }
+    else
+    {
+        #Thrift audit tool has exited with status 0. 
+        print "Test Pass: Audit tool exits with success for warnings \n";
+    }
+
+
+}
+
+# -----------------------------------------------------------------------------------------------------
+# call thriftAuditTool script
+sub callThriftAuditTool ( $ )
+{
+    my $args = shift;
+
+    my $command = "$gAuditToolPath --audit $args";
+    my $output = `$command 2>&1`;
+    my $exitCode = $? >> 8;
+
+    return ($exitCode,$output);
+}
+
+sub getMessageSubString( $ )
+{
+    my $fileName = shift;
+    my %lookupTable = (
+        "break1"  => "base_function3",
+        "break2"  => "test_struct1",
+        "break3"  => "test_struct1",
+        "break4"  => "test_struct1",
+        "break5"  => "test_struct1",
+        "break6"  => "test_struct2",
+        "break7"  => "test_struct6",
+        "break8"  => "test_struct5",
+        "break9"  => "test_struct1",
+        "break10" => "test_struct2",
+        "break11" => "test_struct3",
+        "break12" => "derived1_function1",
+        "break13" => "derived1_function6",
+        "break14" => "derived1_function4",
+        "break15" => "derived2_function1",
+        "break16" => "derived2_function5",
+        "break17" => "derived2_function6",
+        "break18" => "base_oneway",
+        "break19" => "base_function1",
+        "break20" => "test_enum1",
+        "break21" => "test_enum2",
+        "break22" => "test_enum1",
+        "break23" => "test_struct4",
+        "break24" => "derived1",
+        "break25" => "derived2",
+        "break26" => "base_function1",
+        "break27" => "base_function2_args",
+        "break28" => "derived1_function5_args",
+        "break29" => "base_function2_args",
+        "break30" => "derived1_function6",
+        "break31" => "base_function2_exception",
+        "break32" => "test_exception1",
+        "break33" => "derived1_function1_exception",
+        "break34" => "test_struct3",
+    );
+    if (not exists $lookupTable{ $fileName })
+    {
+        print "in the null case\n";
+        return "NULL";
+    }
+    
+    my $retval = $lookupTable{ $fileName };
+    print "$fileName => $retval\n";
+    return $lookupTable{ $fileName };
+}
diff --git a/test/audit/warning.thrift b/test/audit/warning.thrift
new file mode 100644
index 0000000..5392d5c
--- /dev/null
+++ b/test/audit/warning.thrift
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+
+namespace cpp test
+
+//Constants
+
+const i32 const1 = 123;
+const double const2 = 23.2;
+const map<string,string> const3 = {"hello":"class", "thrift":"audit"};
+
+//Exception
+exception test_exception1 {
+    1: i32 code;
+    2: string json;
+}
+exception test_exception2 {
+    1: i32 code;
+    2: string json;
+}
+
+//Enums
+
+enum test_enum1 {
+    enum1_value0 = 0,
+    enum1_value1 = 1,
+    enum1_value2 = 2,
+    enum1_value5 = 5,
+    enum1_value7 = 7,
+    enum1_value8 = 8
+}
+
+enum test_enum2 {
+    enum2_value0 = 0,
+    enum2_value1 = 1,
+    enum2_value2 = 2,
+    enum2_value3 = 3
+}
+
+enum test_enum3 {
+    enum3_value1 = 0,
+    enum3_value2 = 1
+}
+
+struct test_struct1 {
+    1: i16 struct1_member1,
+    2: i32 struct1_member2,
+    3: i64 struct1_member3,
+    4: double struct1_member4 = 2.4,
+    5: string struct1_member5,
+    6: bool struct1_member6,
+    7: byte struct1_member7,
+    8: binary struct1_member8,
+    9: test_enum1 changed19
+}
+
+struct test_struct2 {
+    1: list<i16> struct2_member1,
+    2: list<i32> changed22,
+    3: list<i64> struct2_member3,
+    4: list<double> struct2_member4 =[1.0, 2.1],
+    5: list<string> struct2_member5,
+    6: list<bool> struct2_member6,
+    7: list<byte> struct2_member7,
+    8: list<binary> struct2_member8,
+    9: list<test_enum1> struct2_member9
+}
+
+struct test_struct3 {
+    1: map<i16, i32> struct3_member1 = {1:10, 2:20},
+    2: map<i64, double> struct3_member2 = {1:1.1, 2:2.1},
+    3: map<string, bool> struct3_member3,
+    4: map<byte, test_enum1> struct3_member4,
+    5: map<test_enum2, test_enum3 > struct3_member5,
+    7: map<double, string> struct3_member7
+}
+
+struct test_struct4 {
+    1: i32 struct4_member1,
+    2: optional i32 struct4_member2
+}
+
+struct test_struct5{
+    1: double struct5_member1 = 1.1,
+    2: string struct5_member2 = "Thrift Audit Tess"
+}
+struct test_struct6 {
+    1: i32 struct6_member1,
+    2: required i32 struct6_member2
+}
+
+service base {
+    oneway void base_oneway(
+        1: i32 arg1),
+
+    void base_function1(
+        1: i16 function1_arg1,
+        2: i32 function1_arg2,
+        3: i64 function1_arg3,
+        4: double function1_arg4,
+        5: string function1_arg5,
+        6: bool function1_arg6,
+        7: test_enum1 function1_arg7,
+        8: test_struct1 function1_arg8),
+
+    void base_function2(
+        1: list<i16> function2_arg1,
+        2: list<i32> function2_arg2,
+        3: list<i64> function2_arg3,
+        4: list<double> function2_arg4,
+        5: list<string> function2_arg5,
+        6: list<bool> function2_arg6,
+        7: list<byte> function2_arg7,
+        8: list<test_enum1> function2_arg8,
+        9: list<test_struct1> function2_arg9) throws (1:test_exception2 e),
+
+    void base_function3(),
+
+}
+
+service derived1 extends base{
+    
+    test_enum1 derived1_function1(
+        1: i64 function1_arg1,
+        2: double function1_arg2,
+        3: test_enum1 function1_arg3) throws (1:test_exception2 e),
+
+    i64 derived1_function2(
+        1: list<i64> function2_arg1,
+        2: list<double> function2_arg2,
+        3: list<string> function2_arg3,
+        4: list<byte> function2_arg4,
+        5: list<test_enum1> function2_arg5) throws (1:test_exception2 e),
+
+    double derived1_function3(
+        1: string function3_arg1,
+        2: bool function3_arg2) throws (1:test_exception2 e),
+
+    string derived1_function4(
+        1: string function4_arg1,
+        2: bool function4_arg2) throws (1:test_exception2 e),
+
+
+    bool derived1_function5(
+        1: map<i64, double> function5_arg1,
+        2: map<string, bool> function5_arg2,
+        3: map<test_enum1, test_enum2> function5_arg3) throws (1:test_exception2 e),
+
+    test_struct1 derived1_function6(
+        1: double function6_arg1) throws (1:test_exception2 e),
+}
+
+service derived2 extends base {
+
+    list<i32> derived2_function1(
+        1: i32 function1_arg1) throws (1:test_exception2 e),
+    
+    list<test_enum1> derived2_function2(
+        1:i64 function2_arg2) throws (1:test_exception2 e),
+
+    list<test_struct1> derived2_function3(
+        1:double function3_arg1) throws(1:test_exception2 e),
+
+    map<double, string> derived2_function4(
+        1:string function4_arg1) throws(1:test_exception2 e),
+
+    map<test_enum1, test_enum2> derived2_function5(
+        1:bool function5_arg1) throws(1:test_exception2 e),
+
+    map<test_struct1, test_struct2> derived2_function6(
+        1:bool function6_arg1) throws(1:test_exception2 e),
+    
+}
diff --git a/test/c_glib/Makefile.am b/test/c_glib/Makefile.am
new file mode 100755
index 0000000..4a03d29
--- /dev/null
+++ b/test/c_glib/Makefile.am
@@ -0,0 +1,74 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+AUTOMAKE_OPTIONS = subdir-objects serial-tests
+
+noinst_LTLIBRARIES = libtestcglib.la
+nodist_libtestcglib_la_SOURCES = \
+	gen-c_glib/t_test_second_service.c \
+	gen-c_glib/t_test_second_service.h \
+	gen-c_glib/t_test_thrift_test.c \
+	gen-c_glib/t_test_thrift_test.h \
+	gen-c_glib/t_test_thrift_test_types.c \
+	gen-c_glib/t_test_thrift_test_types.h
+
+libtestcglib_la_LIBADD = $(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+precross: libtestcglib.la test_client test_server
+
+check_PROGRAMS = \
+	test_client \
+	test_server
+
+test_client_SOURCES = \
+	src/test_client.c
+
+test_client_LDADD = \
+	libtestcglib.la \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+test_server_SOURCES = \
+	src/thrift_test_handler.c \
+	src/thrift_test_handler.h \
+	src/thrift_second_service_handler.c \
+	src/thrift_second_service_handler.h \
+	src/test_server.c
+
+test_server_LDADD = \
+	libtestcglib.la \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+#
+# Common thrift code generation rules
+#
+gen-c_glib/t_test_second_service.c  gen-c_glib/t_test_second_service.h  gen-c_glib/t_test_thrift_test.c  gen-c_glib/t_test_thrift_test.h  gen-c_glib/t_test_thrift_test_types.c  gen-c_glib/t_test_thrift_test_types.h: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT)
+	$(THRIFT) --gen c_glib -r $<
+
+AM_CFLAGS = -g -Wall -Wextra $(GLIB_CFLAGS) $(GOBJECT_CFLAGS)
+AM_CXXFLAGS = $(AM_CFLAGS)
+AM_CPPFLAGS = -I$(top_srcdir)/lib/c_glib/src -Igen-c_glib
+AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) @GCOV_LDFLAGS@
+
+clean-local:
+	$(RM) gen-c_glib/*
+
+EXTRA_DIST = \
+	src/test_client.c \
+	src/thrift_test_handler.c \
+	src/thrift_test_handler.h \
+	src/test_server.c
diff --git a/test/c_glib/src/test_client.c b/test/c_glib/src/test_client.c
new file mode 100644
index 0000000..ef24ab7
--- /dev/null
+++ b/test/c_glib/src/test_client.c
@@ -0,0 +1,1804 @@
+/*
+ * 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.
+ */
+
+#include <glib-object.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/time.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/protocol/thrift_binary_protocol.h>
+#include <thrift/c_glib/protocol/thrift_compact_protocol.h>
+#include <thrift/c_glib/protocol/thrift_multiplexed_protocol.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport.h>
+#include <thrift/c_glib/transport/thrift_framed_transport.h>
+#include <thrift/c_glib/transport/thrift_ssl_socket.h>
+#include <thrift/c_glib/transport/thrift_socket.h>
+#include <thrift/c_glib/transport/thrift_transport.h>
+
+#include "../gen-c_glib/t_test_second_service.h"
+#include "../gen-c_glib/t_test_thrift_test.h"
+
+/* Handle SIGPIPE signals (indicating the server has closed the
+   connection prematurely) by outputting an error message before
+   exiting. */
+static void
+sigpipe_handler (int signal_number)
+{
+  THRIFT_UNUSED_VAR (signal_number);
+
+  /* Flush standard output to make sure the test results so far are
+     logged */
+  fflush (stdout);
+
+  fputs ("Broken pipe (server closed connection prematurely)\n", stderr);
+  fflush (stderr);
+
+  /* Re-raise the signal, this time invoking the default signal
+     handler, to terminate the program */
+  raise (SIGPIPE);
+}
+
+/* Compare two gint32 values. Used for sorting and finding integer
+   values within a GList. */
+static gint
+gint32_compare (gconstpointer a, gconstpointer b)
+{
+  gint32 int32_a = *(gint32 *)a;
+  gint32 int32_b = *(gint32 *)b;
+  int result = 0;
+
+  if (int32_a < int32_b)
+    result = -1;
+  else if (int32_a > int32_b)
+    result = 1;
+
+  return result;
+}
+
+/**
+ * It gets a multiplexed protocol which uses a concrete protocol underneath
+ * @param  protocol_name  the fully qualified protocol path (e.g. "binary:multi")
+ * @param  transport      the underlying transport
+ * @param  service_name   the single supported service name
+ * @todo                  need to allow multiple services to fully test multiplexed
+ * @return                a multiplexed protocol wrapping the correct underlying protocol
+ */
+ThriftProtocol *
+get_multiplexed_protocol(gchar *protocol_name, ThriftTransport *transport, gchar *service_name)
+{
+  ThriftProtocol * multiplexed_protocol = NULL;
+
+  if ( strncmp(protocol_name, "binary:", 7) == 0) {
+    multiplexed_protocol = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
+                 "transport", transport,
+                 NULL);
+  } else if ( strncmp(protocol_name, "compact:", 8) == 0) {
+    multiplexed_protocol = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL,
+                 "transport", transport,
+                 NULL);
+  } else {
+    fprintf(stderr, "Unknown multiplex protocol name: %s\n", protocol_name);
+    return NULL;
+  }
+
+  return g_object_new (THRIFT_TYPE_MULTIPLEXED_PROTOCOL,
+          "transport",      transport,
+          "protocol",       multiplexed_protocol,
+          "service-name",   service_name,
+          NULL);
+}
+
+int
+main (int argc, char **argv)
+{
+  static gchar *  host = NULL;
+  static gint     port = 9090;
+  static gboolean ssl  = FALSE;
+  static gchar *  transport_option = NULL;
+  static gchar *  protocol_option = NULL;
+  static gint     num_tests = 1;
+
+  static
+    GOptionEntry option_entries[] ={
+    { "host",            'h', 0, G_OPTION_ARG_STRING,   &host,
+      "Host to connect (=localhost)", NULL },
+    { "port",            'p', 0, G_OPTION_ARG_INT,      &port,
+      "Port number to connect (=9090)", NULL },
+    { "ssl",             's', 0, G_OPTION_ARG_NONE,     &ssl,
+      "Enable SSL", NULL },
+    { "transport",       't', 0, G_OPTION_ARG_STRING,   &transport_option,
+      "Transport: buffered, framed (=buffered)", NULL },
+    { "protocol",        'r', 0, G_OPTION_ARG_STRING,   &protocol_option,
+      "Protocol: binary, compact, multi, multic (=binary)", NULL },
+    { "testloops",       'n', 0, G_OPTION_ARG_INT,      &num_tests,
+      "Number of tests (=1)", NULL },
+    { NULL }
+  };
+
+  struct sigaction sigpipe_action;
+
+  GType  socket_type    = THRIFT_TYPE_SOCKET;
+  gchar *socket_name    = "ip";
+  GType  transport_type = THRIFT_TYPE_BUFFERED_TRANSPORT;
+  gchar *transport_name = "buffered";
+  GType  protocol_type  = THRIFT_TYPE_BINARY_PROTOCOL;
+  gchar *protocol_name  = "binary";
+
+  ThriftSocket    *socket = NULL;
+  ThriftTransport *transport = NULL;
+  ThriftProtocol  *protocol = NULL;
+  ThriftProtocol  *protocol2 = NULL;            // for multiplexed tests
+
+  TTestThriftTestIf *test_client = NULL;
+  TTestSecondServiceIf *second_service = NULL;  // for multiplexed tests
+
+  struct timeval time_start, time_stop, time_elapsed;
+  guint64 time_elapsed_usec, time_total_usec = 0;
+  guint64 time_min_usec = G_MAXUINT64, time_max_usec = 0, time_avg_usec;
+
+  GOptionContext *option_context;
+  gboolean options_valid = TRUE;
+  int test_num = 0;
+  int fail_count = 0;
+  GError *error = NULL;
+
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init ();
+#endif
+
+  /* Configure and parse our command-line options */
+  option_context = g_option_context_new (NULL);
+  g_option_context_add_main_entries (option_context,
+                                     option_entries,
+                                     NULL);
+  if (!g_option_context_parse (option_context,
+                               &argc,
+                               &argv,
+                               &error)) {
+    fprintf (stderr, "%s\n", error->message);
+    return 255;
+  }
+  g_option_context_free (option_context);
+
+  /* Set remaining default values for unspecified options */
+  if (host == NULL)
+    host = g_strdup ("localhost");
+
+  /* Validate the parsed options */
+  if (protocol_option != NULL) {
+    if (strncmp (protocol_option, "compact", 8) == 0) {
+      protocol_type = THRIFT_TYPE_COMPACT_PROTOCOL;
+      protocol_name = "compact";
+    }
+    else if (strncmp (protocol_option, "multi", 6) == 0) {
+      protocol_type = THRIFT_TYPE_MULTIPLEXED_PROTOCOL;
+      protocol_name = "binary:multi";
+    }
+    else if (strncmp (protocol_option, "multic", 7) == 0) {
+      protocol_type = THRIFT_TYPE_MULTIPLEXED_PROTOCOL;
+      protocol_name = "compact:multic";
+    }
+    else if (strncmp (protocol_option, "binary", 7) == 0) {
+      printf("We are going with default protocol\n");
+    }
+    else {
+      fprintf (stderr, "Unknown protocol type %s\n", protocol_option);
+      options_valid = FALSE;
+    }
+  }
+
+  if (transport_option != NULL) {
+    if (strncmp (transport_option, "framed", 7) == 0) {
+      transport_type = THRIFT_TYPE_FRAMED_TRANSPORT;
+      transport_name = "framed";
+    }
+    else if (strncmp (transport_option, "buffered", 9) != 0) {
+      fprintf (stderr, "Unknown transport type %s\n", transport_option);
+      options_valid = FALSE;
+    }
+  }
+
+  if (ssl) {
+    socket_type = THRIFT_TYPE_SSL_SOCKET;
+    socket_name = "ip-ssl";
+    printf("Type name %s\n", g_type_name (socket_type));
+  }
+
+  if (!options_valid)
+    return 254;
+
+  printf ("Connecting (%s/%s) to: %s/%s:%d\n",
+          transport_name,
+          protocol_name,
+          socket_name,
+          host,
+          port);
+
+  /* Install our SIGPIPE handler, which outputs an error message to
+     standard error before exiting so testers can know what
+     happened */
+  memset (&sigpipe_action, 0, sizeof (sigpipe_action));
+  sigpipe_action.sa_handler = sigpipe_handler;
+  sigpipe_action.sa_flags = SA_RESETHAND;
+  sigaction (SIGPIPE, &sigpipe_action, NULL);
+
+  if (ssl) {
+    thrift_ssl_socket_initialize_openssl();
+  }
+
+  /* Establish all our connection objects */
+  socket = g_object_new (socket_type,
+                         "hostname", host,
+                         "port",     port,
+                         NULL);
+
+  if (ssl && !thrift_ssl_load_cert_from_file(THRIFT_SSL_SOCKET(socket), "../keys/CA.pem")) {
+    fprintf(stderr, "Unable to load validation certificate ../keys/CA.pem - did you run in the test/c_glib directory?\n");
+    g_clear_object (&socket);
+    return 253;
+  }
+
+  transport = g_object_new (transport_type,
+                            "transport", socket,
+                            NULL);
+
+  if(protocol_type==THRIFT_TYPE_MULTIPLEXED_PROTOCOL) {
+    // TODO: A multiplexed test should also test "Second" (see Java TestServer)
+    // The context comes from the name of the thrift file. If multiple thrift
+    // schemas are used we have to redo the way this is done.
+    protocol = get_multiplexed_protocol(protocol_name, transport, "ThriftTest");
+    if (NULL == protocol) {
+      g_clear_object (&transport);
+      g_clear_object (&socket);
+      return 252;
+    }
+
+    // Make a second protocol and client running on the same multiplexed transport
+    protocol2 = get_multiplexed_protocol(protocol_name, transport, "SecondService");
+    second_service = g_object_new (T_TEST_TYPE_SECOND_SERVICE_CLIENT,
+                                "input_protocol",  protocol2,
+                                "output_protocol", protocol2,
+                                NULL);
+
+  }else{
+    protocol = g_object_new (protocol_type,
+           "transport", transport,
+           NULL);
+  }
+
+  test_client = g_object_new (T_TEST_TYPE_THRIFT_TEST_CLIENT,
+                              "input_protocol",  protocol,
+                              "output_protocol", protocol,
+                              NULL);
+
+  /* Execute the actual tests */
+  for (test_num = 0; test_num < num_tests; ++test_num) {
+    if (thrift_transport_open (transport, &error)) {
+      gchar   *string  = NULL;
+      gboolean boolean = 0;
+      gint8    byte    = 0;
+      gint32   int32   = 0;
+      gint64   int64   = 0;
+      gdouble  dub     = 0;
+
+      gint byte_thing, i32_thing, inner_byte_thing, inner_i32_thing;
+      gint64 i64_thing, inner_i64_thing;
+
+      TTestXtruct  *xtruct_out,  *xtruct_out2, *xtruct_in,  *inner_xtruct_in;
+      TTestXtruct2 *xtruct2_out, *xtruct2_in;
+
+      GHashTable *map_out, *map_in, *inner_map_in;
+      GHashTable *set_out, *set_in;
+      gpointer key, value;
+      gint32 *i32_key_ptr, *i32_value_ptr;
+      GHashTableIter hash_table_iter, inner_hash_table_iter;
+      GList *keys_out, *keys_in, *keys_elem;
+
+      GArray *list_out, *list_in;
+
+      TTestNumberz numberz;
+      TTestNumberz numberz2;
+
+      TTestUserId user_id, *user_id_ptr, *user_id_ptr2;
+
+      TTestInsanity *insanity_out, *insanity_in;
+      GHashTable *user_map;
+      GHashTableIter user_map_iter;
+      GPtrArray *xtructs;
+
+      TTestXception  *xception  = NULL;
+      TTestXception2 *xception2 = NULL;
+
+      gboolean oneway_result;
+      struct timeval oneway_start, oneway_end, oneway_elapsed;
+      gint oneway_elapsed_usec;
+
+      gboolean first;
+      gint32 i, j;
+
+      printf ("Test #%d, connect %s:%d\n", test_num + 1, host, port);
+      gettimeofday (&time_start, NULL);
+
+      /* These test routines have been ported from the C++ test
+         client, care being taken to ensure their output remains as
+         close as possible to the original to facilitate diffs.
+
+         For simplicity comments have been omitted, but every routine
+         has the same basic structure:
+
+         - Create and populate data structures as necessary.
+
+         - Format and output (to the console) a representation of the
+           outgoing data.
+
+         - Issue the remote method call to the server.
+
+         - Format and output a representation of the returned data.
+
+         - Verify the returned data matches what was expected.
+
+         - Deallocate any created data structures.
+
+         Note the recognized values and expected behaviour of each
+         remote method are described in ThriftTest.thrift, which
+         you'll find in the top-level "test" folder. */
+
+      /**
+       * VOID TEST
+       */
+      printf ("testVoid()");
+      if (t_test_thrift_test_if_test_void (test_client, &error)) {
+        printf (" = void\n");
+      }
+      else {
+        if(error!=NULL){
+          printf ("%s\n", error->message);
+          g_error_free (error);
+          error = NULL;
+        }
+        fail_count++;
+      }
+
+      /**
+       * STRING TEST
+       */
+      printf ("testString(\"Test\")");
+      if (t_test_thrift_test_if_test_string (test_client,
+                                             &string,
+                                             "Test",
+                                             &error)) {
+        printf (" = \"%s\"\n", string);
+        if (strncmp (string, "Test", 5) != 0)
+          fail_count++;
+
+        g_free (string);
+        string = NULL;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      /**
+       * Multiplexed Test - do this right in the middle of the normal Test Client run
+       */
+      if (second_service) {
+        printf ("testSecondServiceMultiplexSecondTestString(\"2nd\")");
+        if (t_test_second_service_if_secondtest_string (second_service,
+                                                        &string,
+                                                        "2nd",
+                                                        &error)) {
+          printf (" = \"%s\"\n", string);
+          if (strcmp (string, "testString(\"2nd\")") != 0) {
+            ++fail_count;
+          }
+
+          g_free (string);
+          string = NULL;
+        } else {
+          printf ("%s\n", error->message);
+          g_error_free (error);
+          error = NULL;
+
+          ++fail_count;
+        }
+      }
+
+      /**
+       * BOOL TEST
+       */
+      printf ("testByte(true)");
+      if (t_test_thrift_test_if_test_bool (test_client,
+                                           &boolean,
+                                           1,
+                                           &error)) {
+        printf (" = %s\n", boolean ? "true" : "false");
+        if (boolean != 1)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+      printf ("testByte(false)");
+      if (t_test_thrift_test_if_test_bool (test_client,
+                                           &boolean,
+                                           0,
+                                           &error)) {
+        printf (" = %s\n", boolean ? "true" : "false");
+        if (boolean != 0)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      /**
+       * BYTE TEST
+       */
+      printf ("testByte(1)");
+      if (t_test_thrift_test_if_test_byte (test_client,
+                                           &byte,
+                                           1,
+                                           &error)) {
+        printf (" = %d\n", byte);
+        if (byte != 1)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+      printf ("testByte(-1)");
+      if (t_test_thrift_test_if_test_byte (test_client,
+                                           &byte,
+                                           -1,
+                                           &error)) {
+        printf (" = %d\n", byte);
+        if (byte != -1)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      /**
+       * I32 TEST
+       */
+      printf ("testI32(-1)");
+      if (t_test_thrift_test_if_test_i32 (test_client,
+                                          &int32,
+                                          -1,
+                                          &error)) {
+        printf (" = %d\n", int32);
+        if (int32 != -1)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      /**
+       * I64 TEST
+       */
+      printf ("testI64(-34359738368)");
+      if (t_test_thrift_test_if_test_i64 (test_client,
+                                          &int64,
+                                          (gint64)-34359738368,
+                                          &error)) {
+        printf (" = %" PRId64 "\n", int64);
+        if (int64 != (gint64)-34359738368)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      /**
+       * DOUBLE TEST
+       */
+      printf("testDouble(-5.2098523)");
+      if (t_test_thrift_test_if_test_double (test_client,
+                                             &dub,
+                                             -5.2098523,
+                                             &error)) {
+        printf (" = %f\n", dub);
+        if ((dub - (-5.2098523)) > 0.001)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      /**
+       * BINARY TEST
+       */
+      printf ("testBinary(empty)");
+      GByteArray *emptyArray = g_byte_array_new();
+      GByteArray *result = NULL;
+      if (t_test_thrift_test_if_test_binary (test_client,
+                                             &result,
+                                             emptyArray,
+                                             &error)) {
+        GBytes *response = g_byte_array_free_to_bytes(result);  // frees result
+        result = NULL;
+        gsize siz = g_bytes_get_size(response);
+        if (siz == 0) {
+          printf(" = empty\n");
+        } else {
+          printf(" = not empty (%ld bytes)\n", (long)siz);
+          ++fail_count;
+        }
+        g_bytes_unref(response);
+      } else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+      g_byte_array_unref(emptyArray);
+      emptyArray = NULL;
+
+      // TODO: add testBinary() with data
+      printf ("testBinary([-128..127]) = {");
+      const signed char bin_data[256]
+        = {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114,
+           -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99,
+           -98,  -97,  -96,  -95,  -94,  -93,  -92,  -91,  -90,  -89,  -88,  -87,  -86,  -85,  -84,
+           -83,  -82,  -81,  -80,  -79,  -78,  -77,  -76,  -75,  -74,  -73,  -72,  -71,  -70,  -69,
+           -68,  -67,  -66,  -65,  -64,  -63,  -62,  -61,  -60,  -59,  -58,  -57,  -56,  -55,  -54,
+           -53,  -52,  -51,  -50,  -49,  -48,  -47,  -46,  -45,  -44,  -43,  -42,  -41,  -40,  -39,
+           -38,  -37,  -36,  -35,  -34,  -33,  -32,  -31,  -30,  -29,  -28,  -27,  -26,  -25,  -24,
+           -23,  -22,  -21,  -20,  -19,  -18,  -17,  -16,  -15,  -14,  -13,  -12,  -11,  -10,  -9,
+           -8,   -7,   -6,   -5,   -4,   -3,   -2,   -1,   0,    1,    2,    3,    4,    5,    6,
+           7,    8,    9,    10,   11,   12,   13,   14,   15,   16,   17,   18,   19,   20,   21,
+           22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,
+           37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51,
+           52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,   64,   65,   66,
+           67,   68,   69,   70,   71,   72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
+           82,   83,   84,   85,   86,   87,   88,   89,   90,   91,   92,   93,   94,   95,   96,
+           97,   98,   99,   100,  101,  102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
+           112,  113,  114,  115,  116,  117,  118,  119,  120,  121,  122,  123,  124,  125,  126,
+           127};
+      GByteArray *fullArray = g_byte_array_new();
+      g_byte_array_append(fullArray, (guint8 *)(&bin_data[0]), 256);
+      if (t_test_thrift_test_if_test_binary (test_client,
+                                             &result,
+                                             fullArray,
+                                             &error)) {
+        GBytes *response = g_byte_array_free_to_bytes(result);  // frees result
+        result = NULL;
+        gsize siz = g_bytes_get_size(response);
+        gconstpointer ptr = g_bytes_get_data(response, &siz);
+        if (siz == 256) {
+          gboolean first = 1;
+          gboolean failed = 0;
+          int i;
+
+          for (i = 0; i < 256; ++i) {
+            if (!first)
+              printf(",");
+            else
+              first = 0;
+            int val = ((signed char *)ptr)[i];
+            printf("%d", val);
+            if (!failed && val != i - 128) {
+              failed = 1;
+            }
+          }
+          printf("} ");
+          if (failed) {
+            printf("FAIL (bad content) size %ld OK\n", (long)siz);
+            ++fail_count;
+          } else {
+            printf("OK size %ld OK\n", (long)siz);
+          }
+        } else {
+          printf(" = bad size %ld\n", (long)siz);
+          ++fail_count;
+        }
+        g_bytes_unref(response);
+      } else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+      g_byte_array_unref(fullArray);
+      fullArray = NULL;
+
+      /**
+       * STRUCT TEST
+       */
+      printf ("testStruct({\"Zero\", 1, -3, -5})");
+      xtruct_out = g_object_new (T_TEST_TYPE_XTRUCT,
+                                 "string_thing", "Zero",
+                                 "byte_thing",        1,
+                                 "i32_thing",        -3,
+                                 "i64_thing",      -5LL,
+                                 NULL);
+      xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL);
+
+      if (t_test_thrift_test_if_test_struct (test_client,
+                                             &xtruct_in,
+                                             xtruct_out,
+                                             &error)) {
+        g_object_get (xtruct_in,
+                      "string_thing", &string,
+                      "byte_thing",   &byte_thing,
+                      "i32_thing",    &i32_thing,
+                      "i64_thing",    &i64_thing,
+                      NULL);
+
+        printf (" = {\"%s\", %d, %d, %" PRId64 "}\n",
+                string,
+                byte_thing,
+                i32_thing,
+                i64_thing);
+        if ((string == NULL || strncmp (string, "Zero", 5) != 0) ||
+            byte_thing != 1 ||
+            i32_thing != -3 ||
+            i64_thing != (gint64)-5)
+          fail_count++;
+
+        if (string) {
+          g_free (string);
+          string = NULL;
+        }
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+      // g_clear_object(&xtruct_out); used below
+      g_clear_object(&xtruct_in);
+
+      /**
+       * NESTED STRUCT TEST
+       */
+      printf ("testNest({1, {\"Zero\", 1, -3, -5}), 5}");
+      xtruct2_out = g_object_new (T_TEST_TYPE_XTRUCT2,
+                                  "byte_thing",            1,
+                                  "struct_thing", xtruct_out,
+                                  "i32_thing",             5,
+                                  NULL);
+      xtruct2_in = g_object_new (T_TEST_TYPE_XTRUCT2, NULL);
+
+      if (t_test_thrift_test_if_test_nest (test_client,
+                                           &xtruct2_in,
+                                           xtruct2_out,
+                                           &error)) {
+        g_object_get (xtruct2_in,
+                      "byte_thing",   &byte_thing,
+                      "struct_thing", &xtruct_in,
+                      "i32_thing",    &i32_thing,
+                      NULL);
+        g_object_get (xtruct_in,
+                      "string_thing", &string,
+                      "byte_thing",   &inner_byte_thing,
+                      "i32_thing",    &inner_i32_thing,
+                      "i64_thing",    &inner_i64_thing,
+                      NULL);
+
+        printf (" = {%d, {\"%s\", %d, %d, %" PRId64 "}, %d}\n",
+                byte_thing,
+                string,
+                inner_byte_thing,
+                inner_i32_thing,
+                inner_i64_thing,
+                i32_thing);
+        if (byte_thing != 1 ||
+            (string == NULL || strncmp (string, "Zero", 5) != 0) ||
+            inner_byte_thing != 1 ||
+            inner_i32_thing != -3 ||
+            inner_i64_thing != (gint64)-5 ||
+            i32_thing != 5)
+          fail_count++;
+
+        if (string) {
+          g_free(string);
+          string = NULL;
+        }
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      g_clear_object(&xtruct_in);
+      g_clear_object(&xtruct2_in);
+      g_clear_object(&xtruct2_out);
+      g_clear_object(&xtruct_out);
+
+      /**
+       * MAP TEST
+       */
+      map_out = g_hash_table_new_full (g_int_hash,
+                                       g_int_equal,
+                                       g_free,
+                                       g_free);
+      for (i = 0; i < 5; ++i) {
+        i32_key_ptr   = g_malloc (sizeof *i32_key_ptr);
+        i32_value_ptr = g_malloc (sizeof *i32_value_ptr);
+
+        *i32_key_ptr   = i;
+        *i32_value_ptr = i - 10;
+
+        g_hash_table_insert (map_out, i32_key_ptr, i32_value_ptr);
+      }
+      printf ("testMap({");
+      first = TRUE;
+      g_hash_table_iter_init (&hash_table_iter, map_out);
+      while (g_hash_table_iter_next (&hash_table_iter,
+                                     &key,
+                                     &value)) {
+        if (first)
+          first = FALSE;
+        else
+          printf (", ");
+
+        printf ("%d => %d", *(gint32 *)key, *(gint32 *)value);
+      }
+      printf ("})");
+
+      map_in = g_hash_table_new_full (g_int_hash,
+                                      g_int_equal,
+                                      g_free,
+                                      g_free);
+
+      if (t_test_thrift_test_if_test_map (test_client,
+                                          &map_in,
+                                          map_out,
+                                          &error)) {
+        printf (" = {");
+        first = TRUE;
+        g_hash_table_iter_init (&hash_table_iter, map_in);
+        while (g_hash_table_iter_next (&hash_table_iter,
+                                       &key,
+                                       &value)) {
+          if (first)
+            first = FALSE;
+          else
+            printf (", ");
+
+          printf ("%d => %d", *(gint32 *)key, *(gint32 *)value);
+        }
+        printf ("}\n");
+
+        if (g_hash_table_size (map_in) != g_hash_table_size (map_out))
+          fail_count++;
+        else {
+          g_hash_table_iter_init (&hash_table_iter, map_out);
+          while (g_hash_table_iter_next (&hash_table_iter,
+                                         &key,
+                                         &value)) {
+            gpointer in_value = g_hash_table_lookup (map_in, key);
+            if (in_value == NULL ||
+                *(gint32 *)in_value != *(gint32 *)value) {
+              fail_count++;
+              break;
+            }
+          }
+        }
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      g_hash_table_unref (map_in);
+      g_hash_table_unref (map_out);
+
+      /**
+       * STRING MAP TEST
+       */
+      map_out = g_hash_table_new_full (g_str_hash,
+                                       g_str_equal,
+                                       NULL,
+                                       NULL);
+      g_hash_table_insert (map_out, "a",    "2");
+      g_hash_table_insert (map_out, "b",    "blah");
+      g_hash_table_insert (map_out, "some", "thing");
+      printf ("testStringMap({");
+      first = TRUE;
+      g_hash_table_iter_init (&hash_table_iter, map_out);
+      while (g_hash_table_iter_next (&hash_table_iter,
+                                     &key,
+                                     &value)) {
+        if (first)
+          first = FALSE;
+        else
+          printf (", ");
+
+        printf ("\"%s\" => \"%s\"", (gchar *)key, (gchar *)value);
+      }
+      printf (")}");
+
+      map_in = g_hash_table_new_full (g_str_hash,
+                                      g_str_equal,
+                                      g_free,
+                                      g_free);
+
+      if (t_test_thrift_test_if_test_string_map (test_client,
+                                                 &map_in,
+                                                 map_out,
+                                                 &error)) {
+        printf (" = {");
+        first = TRUE;
+        g_hash_table_iter_init (&hash_table_iter, map_in);
+        while (g_hash_table_iter_next (&hash_table_iter,
+                                       &key,
+                                       &value)) {
+          if (first)
+            first = FALSE;
+          else
+            printf (", ");
+
+          printf ("\"%s\" => \"%s\"", (gchar *)key, (gchar *)value);
+        }
+        printf ("}\n");
+
+        if (g_hash_table_size (map_in) != g_hash_table_size (map_out))
+          fail_count++;
+        else {
+          g_hash_table_iter_init (&hash_table_iter, map_out);
+          while (g_hash_table_iter_next (&hash_table_iter,
+                                         &key,
+                                         &value)) {
+            gpointer in_value = g_hash_table_lookup (map_in, key);
+            if (in_value == NULL ||
+                strcmp ((gchar *)in_value, (gchar *)value) != 0) {
+              fail_count++;
+              break;
+            }
+          }
+        }
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      g_hash_table_unref (map_in);
+      g_hash_table_unref (map_out);
+
+      /**
+       * SET TEST
+       */
+      set_out = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL);
+      for (i = -2; i < 3; ++i) {
+        i32_key_ptr = g_malloc (sizeof *i32_key_ptr);
+        *i32_key_ptr = i;
+
+        g_hash_table_insert (set_out, i32_key_ptr, NULL);
+      }
+      printf ("testSet({");
+      first = TRUE;
+      keys_out = g_hash_table_get_keys (set_out);
+      keys_elem = keys_out;
+      while (keys_elem != NULL) {
+        if (first)
+          first = FALSE;
+        else
+          printf (", ");
+
+        printf ("%d", *(gint32 *)keys_elem->data);
+
+        keys_elem = keys_elem->next;
+      }
+      printf ("})");
+
+      set_in = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL);
+
+      if (t_test_thrift_test_if_test_set (test_client,
+                                          &set_in,
+                                          set_out,
+                                          &error)) {
+        printf(" = {");
+        first = TRUE;
+        keys_in = g_hash_table_get_keys (set_in);
+        keys_elem = keys_in;
+        while (keys_elem != NULL) {
+          if (first)
+            first = FALSE;
+          else
+            printf (", ");
+
+          printf ("%d", *(gint32 *)keys_elem->data);
+
+          keys_elem = keys_elem->next;
+        }
+        printf ("}\n");
+
+        if (g_list_length (keys_in) != g_list_length (keys_out))
+          fail_count++;
+        else {
+          keys_elem = keys_out;
+          while (keys_elem != NULL) {
+            if (g_list_find_custom (keys_in,
+                                    keys_elem->data,
+                                    gint32_compare) == NULL) {
+              fail_count++;
+              break;
+            }
+
+            keys_elem = keys_elem->next;
+          }
+        }
+
+        g_list_free (keys_in);
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      g_hash_table_unref (set_in);
+      g_list_free (keys_out);
+      g_hash_table_unref (set_out);
+
+      /**
+       * LIST TEST
+       */
+      list_out = g_array_new (FALSE, TRUE, sizeof (gint32));
+      for (i = -2; i < 3; ++i) {
+        g_array_append_val (list_out, i);
+      }
+      printf ("testList({");
+      first = TRUE;
+      for (i = 0; i < (gint32)list_out->len; ++i) {
+        if (first)
+          first = FALSE;
+        else
+          printf (", ");
+
+        printf ("%d", g_array_index (list_out, gint32, i));
+      }
+      printf ("})");
+
+      list_in = g_array_new (FALSE, TRUE, sizeof (gint32));
+
+      if (t_test_thrift_test_if_test_list (test_client,
+                                           &list_in,
+                                           list_out,
+                                           &error)) {
+        printf (" = {");
+        first = TRUE;
+        for (i = 0; i < (gint32)list_in->len; ++i) {
+          if (first)
+            first = FALSE;
+          else
+            printf (", ");
+
+          printf ("%d", g_array_index (list_in, gint32, i));
+        }
+        printf ("}\n");
+
+        if (list_in->len != list_out->len ||
+            memcmp (list_in->data,
+                    list_out->data,
+                    list_in->len * sizeof (gint32)) != 0)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      g_array_unref (list_in);
+      g_array_unref (list_out);
+
+      /**
+       * ENUM TEST
+       */
+      printf("testEnum(ONE)");
+      if (t_test_thrift_test_if_test_enum (test_client,
+                                           &numberz,
+                                           T_TEST_NUMBERZ_ONE,
+                                           &error)) {
+        printf(" = %d\n", numberz);
+        if (numberz != T_TEST_NUMBERZ_ONE)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      printf("testEnum(TWO)");
+      if (t_test_thrift_test_if_test_enum (test_client,
+                                           &numberz,
+                                           T_TEST_NUMBERZ_TWO,
+                                           &error)) {
+        printf(" = %d\n", numberz);
+        if (numberz != T_TEST_NUMBERZ_TWO)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      printf("testEnum(THREE)");
+      if (t_test_thrift_test_if_test_enum (test_client,
+                                           &numberz,
+                                           T_TEST_NUMBERZ_THREE,
+                                           &error)) {
+        printf(" = %d\n", numberz);
+        if (numberz != T_TEST_NUMBERZ_THREE)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      printf("testEnum(FIVE)");
+      if (t_test_thrift_test_if_test_enum (test_client,
+                                           &numberz,
+                                           T_TEST_NUMBERZ_FIVE,
+                                           &error)) {
+        printf(" = %d\n", numberz);
+        if (numberz != T_TEST_NUMBERZ_FIVE)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      printf("testEnum(EIGHT)");
+      if (t_test_thrift_test_if_test_enum (test_client,
+                                           &numberz,
+                                           T_TEST_NUMBERZ_EIGHT,
+                                           &error)) {
+        printf(" = %d\n", numberz);
+        if (numberz != T_TEST_NUMBERZ_EIGHT)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      /**
+       * TYPEDEF TEST
+       */
+      printf ("testTypedef(309858235082523)");
+      if (t_test_thrift_test_if_test_typedef (test_client,
+                                              &user_id,
+                                              309858235082523LL,
+                                              &error)) {
+        printf(" = %" PRId64 "\n", user_id);
+        if (user_id != 309858235082523LL)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      /**
+       * NESTED MAP TEST
+       */
+      printf ("testMapMap(1)");
+      map_in = g_hash_table_new_full (g_int_hash,
+                                      g_int_equal,
+                                      g_free,
+                                      (GDestroyNotify)g_hash_table_unref);
+      if (t_test_thrift_test_if_test_map_map (test_client,
+                                              &map_in,
+                                              1,
+                                              &error)) {
+        g_hash_table_iter_init (&hash_table_iter, map_in);
+
+        printf (" = {");
+        while (g_hash_table_iter_next (&hash_table_iter,
+                                       &key,
+                                       &value)) {
+          printf ("%d => {", *(gint32 *)key);
+
+          g_hash_table_iter_init (&inner_hash_table_iter,
+                                  (GHashTable *)value);
+          while (g_hash_table_iter_next (&inner_hash_table_iter,
+                                         &key,
+                                         &value)) {
+            printf ("%d => %d, ", *(gint32 *)key, *(gint32 *)value);
+          }
+
+          printf ("}, ");
+        }
+        printf ("}\n");
+
+        if (g_hash_table_size (map_in) != 2)
+          fail_count++;
+        else {
+          gint32 inner_keys[] = {1, 2, 3, 4};
+          gint32 i32_key;
+
+          i32_key = -4;
+          inner_map_in = g_hash_table_lookup (map_in, &i32_key);
+          if (inner_map_in == NULL ||
+              g_hash_table_size (inner_map_in) != 4)
+            fail_count++;
+          else {
+            keys_in = g_hash_table_get_keys (inner_map_in);
+            keys_in = g_list_sort (keys_in, gint32_compare);
+
+            for (i = 0; i < 4; i++) {
+              keys_elem = g_list_nth (keys_in, 3 - i);
+
+              if (*(gint32 *)keys_elem->data != (-1 * inner_keys[i]) ||
+                  *(gint32 *)g_hash_table_lookup (inner_map_in,
+                                                  keys_elem->data) !=
+                  (-1 * inner_keys[i])) {
+                fail_count++;
+                break;
+              }
+            }
+
+            g_list_free (keys_in);
+          }
+
+          i32_key = 4;
+          inner_map_in = g_hash_table_lookup (map_in, &i32_key);
+          if (inner_map_in == NULL ||
+              g_hash_table_size (inner_map_in) != 4)
+            fail_count++;
+          else {
+            keys_in = g_hash_table_get_keys (inner_map_in);
+            keys_in = g_list_sort (keys_in, gint32_compare);
+
+            for (i = 0; i < 4; i++) {
+              keys_elem = g_list_nth (keys_in, i);
+
+              if (*(gint32 *)keys_elem->data != inner_keys[i] ||
+                  *(gint32 *)g_hash_table_lookup (inner_map_in,
+                                                  keys_elem->data) !=
+                  inner_keys[i]) {
+                fail_count++;
+                break;
+              }
+            }
+
+            g_list_free (keys_in);
+          }
+        }
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      g_hash_table_unref (map_in);
+
+      /**
+       * INSANITY TEST
+       */
+      insanity_out = g_object_new (T_TEST_TYPE_INSANITY, NULL);
+      g_object_get (insanity_out,
+                    "userMap", &user_map,
+                    "xtructs", &xtructs,
+                    NULL);
+
+      numberz = T_TEST_NUMBERZ_FIVE;
+      numberz2 = T_TEST_NUMBERZ_EIGHT;
+      user_id_ptr = g_malloc (sizeof *user_id_ptr);
+      *user_id_ptr = 5;
+      user_id_ptr2 = g_malloc (sizeof *user_id_ptr);
+      *user_id_ptr2 = 8;
+      g_hash_table_insert (user_map, (gpointer)numberz, user_id_ptr);
+      g_hash_table_insert (user_map, (gpointer)numberz2, user_id_ptr2);
+      g_hash_table_unref (user_map);
+
+      xtruct_out = g_object_new (T_TEST_TYPE_XTRUCT,
+                                 "string_thing", "Hello2",
+                                 "byte_thing",   2,
+                                 "i32_thing",    2,
+                                 "i64_thing",    2LL,
+                                 NULL);
+      xtruct_out2 = g_object_new (T_TEST_TYPE_XTRUCT,
+                                 "string_thing", "Goodbye4",
+                                 "byte_thing",   4,
+                                 "i32_thing",    4,
+                                 "i64_thing",    4LL,
+                                 NULL);
+      g_ptr_array_add (xtructs, xtruct_out2);
+      g_ptr_array_add (xtructs, xtruct_out);
+      g_ptr_array_unref (xtructs);
+
+      map_in = g_hash_table_new_full (g_int64_hash,
+                                      g_int64_equal,
+                                      g_free,
+                                      (GDestroyNotify)g_hash_table_unref);
+
+      printf("testInsanity()");
+      if (t_test_thrift_test_if_test_insanity (test_client,
+                                               &map_in,
+                                               insanity_out,
+                                               &error)) {
+        printf (" = {");
+        g_hash_table_iter_init (&hash_table_iter, map_in);
+        while (g_hash_table_iter_next (&hash_table_iter,
+                                       &key,
+                                       &value)) {
+          printf ("%" PRId64 " => {", *(TTestUserId *)key);
+
+          g_hash_table_iter_init (&inner_hash_table_iter,
+                                  (GHashTable *)value);
+          while (g_hash_table_iter_next (&inner_hash_table_iter,
+                                         &key,
+                                         &value)) {
+            printf ("%d => {", (TTestNumberz)key);
+
+            g_object_get ((TTestInsanity *)value,
+                          "userMap", &user_map,
+                          "xtructs", &xtructs,
+                          NULL);
+
+            printf ("{");
+            g_hash_table_iter_init (&user_map_iter, user_map);
+            while (g_hash_table_iter_next (&user_map_iter,
+                                           &key,
+                                           &value)) {
+              printf ("%d => %" PRId64 ", ",
+                      (TTestNumberz)key,
+                      *(TTestUserId *)value);
+            }
+            printf ("}, ");
+            g_hash_table_unref (user_map);
+
+            printf("{");
+            for (i = 0; i < (gint32)xtructs->len; ++i) {
+              xtruct_in = g_ptr_array_index (xtructs, i);
+              g_object_get (xtruct_in,
+                            "string_thing", &string,
+                            "byte_thing",   &byte_thing,
+                            "i32_thing",    &i32_thing,
+                            "i64_thing",    &i64_thing,
+                            NULL);
+
+              printf ("{\"%s\", %d, %d, %" PRId64 "}, ",
+                      string,
+                      byte_thing,
+                      i32_thing,
+                      i64_thing);
+            }
+            printf ("}");
+            g_ptr_array_unref (xtructs);
+
+            printf ("}, ");
+          }
+          printf("}, ");
+        }
+        printf("}\n");
+
+        if (g_hash_table_size (map_in) != 2)
+          fail_count++;
+        else {
+          TTestNumberz numberz_key_values[] = {
+            T_TEST_NUMBERZ_TWO, T_TEST_NUMBERZ_THREE
+          };
+          gint user_map_values[] = { 5, 8 };
+          TTestUserId user_id_key;
+
+          user_id_key = 1;
+          inner_map_in = g_hash_table_lookup (map_in, &user_id_key);
+          if (inner_map_in == NULL ||
+              g_hash_table_size (inner_map_in) != 2)
+            fail_count++;
+          else {
+            TTestNumberz numberz_key;
+
+            for (i = 0; i < 2; ++i) {
+              numberz_key = numberz_key_values[i];
+              insanity_in =
+                g_hash_table_lookup (inner_map_in,
+                                     (gconstpointer)numberz_key);
+              if (insanity_in == NULL)
+                fail_count++;
+              else {
+                g_object_get (insanity_in,
+                              "userMap", &user_map,
+                              "xtructs", &xtructs,
+                              NULL);
+
+                if (user_map == NULL)
+                  fail_count++;
+                else {
+                  if (g_hash_table_size (user_map) != 2)
+                    fail_count++;
+                  else {
+                    for (j = 0; j < 2; ++j) {
+                      numberz_key = (TTestNumberz)user_map_values[j];
+
+                      value =
+                        g_hash_table_lookup (user_map,
+                                             (gconstpointer)numberz_key);
+                      if (value == NULL ||
+                          *(TTestUserId *)value != (TTestUserId)user_map_values[j])
+                        fail_count++;
+                    }
+                  }
+
+                  g_hash_table_unref (user_map);
+                }
+
+                if (xtructs == NULL)
+                  fail_count++;
+                else {
+                  if (xtructs->len != 2)
+                    fail_count++;
+                  else {
+                    xtruct_in = g_ptr_array_index (xtructs, 0);
+                    g_object_get (xtruct_in,
+                                  "string_thing", &string,
+                                  "byte_thing",   &byte_thing,
+                                  "i32_thing",    &i32_thing,
+                                  "i64_thing",    &i64_thing,
+                                  NULL);
+                    if ((string == NULL ||
+                         strncmp (string, "Goodbye4", 9) != 0) ||
+                        byte_thing != 4 ||
+                        i32_thing != 4 ||
+                        i64_thing != 4)
+                      fail_count++;
+
+                    if (string != NULL)
+                      g_free (string);
+
+                    xtruct_in = g_ptr_array_index (xtructs, 1);
+                    g_object_get (xtruct_in,
+                                  "string_thing", &string,
+                                  "byte_thing",   &byte_thing,
+                                  "i32_thing",    &i32_thing,
+                                  "i64_thing",    &i64_thing,
+                                  NULL);
+                    if ((string == NULL ||
+                         strncmp (string, "Hello2", 7) != 0) ||
+                        byte_thing != 2 ||
+                        i32_thing != 2 ||
+                        i64_thing != 2)
+                      fail_count++;
+
+                    if (string != NULL)
+                      g_free (string);
+                  }
+
+                  g_ptr_array_unref (xtructs);
+                }
+              }
+            }
+          }
+
+          user_id_key = 2;
+          inner_map_in = g_hash_table_lookup (map_in, &user_id_key);
+          if (inner_map_in == NULL ||
+              g_hash_table_size (inner_map_in) != 1)
+            fail_count++;
+          else {
+            insanity_in =
+              g_hash_table_lookup (inner_map_in,
+                                   (gconstpointer)T_TEST_NUMBERZ_SIX);
+            if (insanity_in == NULL)
+              fail_count++;
+            else {
+              g_object_get (insanity_in,
+                            "userMap", &user_map,
+                            "xtructs", &xtructs,
+                            NULL);
+
+              if (user_map == NULL)
+                fail_count++;
+              else {
+                if (g_hash_table_size (user_map) != 0)
+                  fail_count++;
+
+                g_hash_table_unref (user_map);
+              }
+
+              if (xtructs == NULL)
+                fail_count++;
+              else {
+                if (xtructs->len != 0)
+                  fail_count++;
+
+                g_ptr_array_unref (xtructs);
+              }
+            }
+          }
+        }
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      g_hash_table_unref (map_in);
+      g_clear_object (&insanity_out);
+
+      /* test exception */
+      printf ("testClient.testException(\"Xception\") =>");
+      if (!t_test_thrift_test_if_test_exception (test_client,
+                                                 "Xception",
+                                                 &xception,
+                                                 &error) &&
+          xception != NULL) {
+        g_object_get (xception,
+                      "errorCode", &int32,
+                      "message",   &string,
+                      NULL);
+        printf ("  {%u, \"%s\"}\n", int32, string);
+        g_free (string);
+
+        g_clear_object (&xception);
+
+        g_error_free (error);
+        error = NULL;
+      }
+      else {
+        printf ("  void\nFAILURE\n");
+        fail_count++;
+
+        if (xception != NULL) {
+          g_object_unref (xception);
+          xception = NULL;
+        }
+
+        if (error != NULL) {
+          g_error_free (error);
+          error = NULL;
+        }
+      }
+
+      printf ("testClient.testException(\"TException\") =>");
+      if (!t_test_thrift_test_if_test_exception (test_client,
+                                                 "TException",
+                                                 &xception,
+                                                 &error) &&
+          xception == NULL &&
+          error != NULL) {
+        printf ("  Caught TException\n");
+
+        g_error_free (error);
+        error = NULL;
+      }
+      else {
+        printf ("  void\nFAILURE\n");
+        fail_count++;
+
+        g_clear_object (&xception);
+
+        if (error != NULL) {
+          g_error_free (error);
+          error = NULL;
+        }
+      }
+
+      printf ("testClient.testException(\"success\") =>");
+      if (t_test_thrift_test_if_test_exception (test_client,
+                                                "success",
+                                                &xception,
+                                                &error))
+        printf ("  void\n");
+      else {
+        printf ("  void\nFAILURE\n");
+        fail_count++;
+
+        g_clear_object (&xception);
+
+        g_error_free (error);
+        error = NULL;
+      }
+
+      g_assert (error == NULL);
+
+      /* test multi exception */
+      printf ("testClient.testMultiException(\"Xception\", \"test 1\") =>");
+      xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL);
+      if (!t_test_thrift_test_if_test_multi_exception (test_client,
+                                                       &xtruct_in,
+                                                       "Xception",
+                                                       "test 1",
+                                                       &xception,
+                                                       &xception2,
+                                                       &error) &&
+          xception != NULL &&
+          xception2 == NULL) {
+        g_object_get (xception,
+                      "errorCode", &int32,
+                      "message",   &string,
+                      NULL);
+        printf ("  {%u, \"%s\"}\n", int32, string);
+        g_free (string);
+
+        g_object_unref (xception);
+        xception = NULL;
+
+        g_error_free (error);
+        error = NULL;
+      }
+      else {
+        printf ("  result\nFAILURE\n");
+        fail_count++;
+
+        g_clear_object (&xception);
+        g_clear_object (&xception2);
+
+        if (error != NULL) {
+          g_error_free (error);
+          error = NULL;
+        }
+      }
+      g_object_unref (xtruct_in);
+
+      printf ("testClient.testMultiException(\"Xception2\", \"test 2\") =>");
+      xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL);
+      if (!t_test_thrift_test_if_test_multi_exception (test_client,
+                                                       &xtruct_in,
+                                                       "Xception2",
+                                                       "test 2",
+                                                       &xception,
+                                                       &xception2,
+                                                       &error) &&
+          xception == NULL &&
+          xception2 != NULL) {
+        g_object_get (xception2,
+                      "errorCode",    &int32,
+                      "struct_thing", &inner_xtruct_in,
+                      NULL);
+        g_object_get (inner_xtruct_in,
+                      "string_thing", &string,
+                      NULL);
+        printf ("  {%u, {\"%s\"}}\n", int32, string);
+        g_free (string);
+
+        g_clear_object (&inner_xtruct_in);
+        g_clear_object (&xception2);
+
+        g_error_free (error);
+        error = NULL;
+      }
+      else {
+        printf ("  result\nFAILURE\n");
+        fail_count++;
+
+        g_clear_object (&xception);
+        g_clear_object (&xception2);
+
+        if (error != NULL) {
+          g_error_free (error);
+          error = NULL;
+        }
+      }
+      g_clear_object (&xtruct_in);
+
+      printf ("testClient.testMultiException(\"success\", \"test 3\") =>");
+      xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL);
+      if (t_test_thrift_test_if_test_multi_exception (test_client,
+                                                      &xtruct_in,
+                                                      "success",
+                                                      "test 3",
+                                                      &xception,
+                                                      &xception2,
+                                                      &error) &&
+          xception == NULL &&
+          xception2 == NULL) {
+        g_object_get (xtruct_in,
+                      "string_thing", &string,
+                      NULL);
+        printf ("  {{\"%s\"}}\n", string);
+        g_free (string);
+      }
+      else {
+        printf ("  result\nFAILURE\n");
+        fail_count++;
+
+        g_clear_object (&xception);
+        g_clear_object (&xception2);
+
+        if (error != NULL) {
+          g_error_free (error);
+          error = NULL;
+        }
+      }
+      g_clear_object (&xtruct_in);
+
+      /* test oneway void */
+      printf ("testClient.testOneway(1) =>");
+      gettimeofday (&oneway_start, NULL);
+      oneway_result = t_test_thrift_test_if_test_oneway (test_client,
+                                                         1,
+                                                         &error);
+      gettimeofday (&oneway_end, NULL);
+      timersub (&oneway_end, &oneway_start, &oneway_elapsed);
+      oneway_elapsed_usec =
+        oneway_elapsed.tv_sec * 1000 * 1000 + oneway_elapsed.tv_usec;
+
+      if (oneway_result) {
+        if (oneway_elapsed_usec > 200 * 1000) {
+          printf ("  FAILURE - took %.2f ms\n",
+                  (double)oneway_elapsed_usec / 1000.0);
+          fail_count++;
+        }
+        else
+          printf ("  success - took %.2f ms\n",
+                  (double)oneway_elapsed_usec / 1000.0);
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      /**
+       * redo a simple test after the oneway to make sure we aren't "off by
+       * one" -- if the server treated oneway void like normal void, this next
+       * test will fail since it will get the void confirmation rather than
+       * the correct result. In this circumstance, the client will receive the
+       * error:
+       *
+       *   application error: Wrong method name
+       */
+      /**
+       * I32 TEST
+       */
+      printf ("re-test testI32(-1)");
+      if (t_test_thrift_test_if_test_i32 (test_client,
+                                          &int32,
+                                          -1,
+                                          &error)) {
+        printf (" = %d\n", int32);
+        if (int32 != -1)
+          fail_count++;
+      }
+      else {
+        printf ("%s\n", error->message);
+        g_error_free (error);
+        error = NULL;
+
+        fail_count++;
+      }
+
+      gettimeofday (&time_stop, NULL);
+      timersub (&time_stop, &time_start, &time_elapsed);
+      time_elapsed_usec =
+        time_elapsed.tv_sec * 1000 * 1000 + time_elapsed.tv_usec;
+
+      printf("Total time: %" PRIu64 " us\n", time_elapsed_usec);
+
+      time_total_usec += time_elapsed_usec;
+      if (time_elapsed_usec < time_min_usec)
+        time_min_usec = time_elapsed_usec;
+      if (time_elapsed_usec > time_max_usec)
+        time_max_usec = time_elapsed_usec;
+
+      thrift_transport_close (transport, &error);
+    }
+    else {
+      printf ("Connect failed: %s\n", error->message);
+      g_error_free (error);
+      error = NULL;
+
+      return 1;
+    }
+  }
+
+  /* All done---output statistics */
+  puts ("\nAll tests done.");
+  printf("Number of failures: %d\n", fail_count);
+
+  time_avg_usec = time_total_usec / num_tests;
+
+  printf ("Min time: %" PRIu64 " us\n", time_min_usec);
+  printf ("Max time: %" PRIu64 " us\n", time_max_usec);
+  printf ("Avg time: %" PRIu64 " us\n", time_avg_usec);
+
+  g_clear_object(&second_service);
+  g_clear_object(&protocol2);
+  g_clear_object(&test_client);
+  g_clear_object(&protocol);
+  g_clear_object(&transport);
+  g_clear_object(&socket);
+
+  if (ssl) {
+    thrift_ssl_socket_finalize_openssl();
+  }
+
+  return fail_count;
+}
diff --git a/test/c_glib/src/test_server.c b/test/c_glib/src/test_server.c
new file mode 100644
index 0000000..2d716ec
--- /dev/null
+++ b/test/c_glib/src/test_server.c
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ */
+
+#include <glib-object.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/processor/thrift_multiplexed_processor.h>
+#include <thrift/c_glib/protocol/thrift_binary_protocol_factory.h>
+#include <thrift/c_glib/protocol/thrift_compact_protocol_factory.h>
+#include <thrift/c_glib/server/thrift_server.h>
+#include <thrift/c_glib/server/thrift_simple_server.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport_factory.h>
+#include <thrift/c_glib/transport/thrift_framed_transport.h>
+#include <thrift/c_glib/transport/thrift_framed_transport_factory.h>
+#include <thrift/c_glib/transport/thrift_server_socket.h>
+#include <thrift/c_glib/transport/thrift_server_transport.h>
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/transport/thrift_transport_factory.h>
+
+#include "../gen-c_glib/t_test_thrift_test.h"
+#include "../gen-c_glib/t_test_second_service.h"
+
+#include "thrift_test_handler.h"
+#include "thrift_second_service_handler.h"
+
+/* Our server object, declared globally so it is accessible within the SIGINT
+   signal handler */
+ThriftServer *server = NULL;
+
+/* A flag that indicates whether the server was interrupted with SIGINT
+   (i.e. Ctrl-C) so we can tell whether its termination was abnormal */
+gboolean sigint_received = FALSE;
+
+/* Handle SIGINT ("Ctrl-C") signals by gracefully stopping the server */
+static void
+sigint_handler (int signal_number)
+{
+  THRIFT_UNUSED_VAR (signal_number);
+
+  /* Take note we were called */
+  sigint_received = TRUE;
+
+  /* Shut down the server gracefully */
+  if (server != NULL)
+    thrift_server_stop (server);
+}
+
+int
+main (int argc, char **argv)
+{
+  static gint   port = 9090;
+  static gchar *server_type_option = NULL;
+  static gchar *transport_option = NULL;
+  static gchar *protocol_option = NULL;
+  static gint   string_limit = 0;
+  static gint   container_limit = 0;
+
+  static
+    GOptionEntry option_entries[] = {
+    { "port",            0, 0, G_OPTION_ARG_INT,      &port,
+      "Port number to connect (=9090)", NULL },
+    { "server-type",     0, 0, G_OPTION_ARG_STRING,   &server_type_option,
+      "Type of server: simple (=simple)", NULL },
+    { "transport",       0, 0, G_OPTION_ARG_STRING,   &transport_option,
+      "Transport: buffered, framed (=buffered)", NULL },
+    { "protocol",        0, 0, G_OPTION_ARG_STRING,   &protocol_option,
+      "Protocol: binary, compact (=binary)", NULL },
+    { "string-limit",    0, 0, G_OPTION_ARG_INT,      &string_limit,
+      "Max string length (=none)", NULL },
+    { "container-limit", 0, 0, G_OPTION_ARG_INT,      &container_limit,
+      "Max container length (=none)", NULL },
+    { NULL }
+  };
+
+  gchar *server_name            = "simple";
+  gchar *transport_name         = "buffered";
+  GType  transport_factory_type = THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY;
+  gchar *protocol_name          = "binary";
+  GType  protocol_factory_type  = THRIFT_TYPE_BINARY_PROTOCOL_FACTORY;
+
+  TTestThriftTestHandler *handler;
+  TTestThriftTestHandler *handler_second_service = NULL;
+  ThriftProcessor        *processor;
+  ThriftProcessor        *processor_test = NULL;
+  ThriftProcessor        *processor_second_service = NULL;
+  ThriftServerTransport  *server_transport;
+  ThriftTransportFactory *transport_factory;
+  ThriftProtocolFactory  *protocol_factory;
+
+  struct sigaction sigint_action;
+
+  GOptionContext *option_context;
+  gboolean        options_valid = TRUE;
+
+  GError *error = NULL;
+
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init ();
+#endif
+
+  /* Configure and parse our command-line options */
+  option_context = g_option_context_new (NULL);
+  g_option_context_add_main_entries (option_context,
+                                     option_entries,
+                                     NULL);
+  if (g_option_context_parse (option_context,
+                              &argc,
+                              &argv,
+                              &error) == FALSE) {
+    fprintf (stderr, "%s\n", error->message);
+    return 255;
+  }
+  g_option_context_free (option_context);
+
+  /* Validate the parsed options */
+  if (server_type_option != NULL &&
+      strncmp (server_type_option, "simple", 7) != 0) {
+    fprintf (stderr, "Unknown server type %s\n", protocol_option);
+    options_valid = FALSE;
+  }
+
+  if (protocol_option != NULL) {
+    if (strncmp (protocol_option, "compact", 8) == 0) {
+      protocol_factory_type = THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY;
+      protocol_name = "compact";
+    }
+    else if (strncmp (protocol_option, "multi", 6) == 0) {
+	protocol_name = "binary:multi";
+    }
+    else if (strncmp (protocol_option, "multic", 7) == 0) {
+	protocol_factory_type = THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY;
+	protocol_name = "compact:multic";
+    }
+    else if (strncmp (protocol_option, "binary", 7) != 0) {
+      fprintf (stderr, "Unknown protocol type %s\n", protocol_option);
+      options_valid = FALSE;
+    }
+  }
+
+  if (transport_option != NULL) {
+    if (strncmp (transport_option, "framed", 7) == 0) {
+      transport_factory_type = THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY;
+      transport_name = "framed";
+    }
+    else if (strncmp (transport_option, "buffered", 9) != 0) {
+      fprintf (stderr, "Unknown transport type %s\n", transport_option);
+      options_valid = FALSE;
+    }
+  }
+
+  if (!options_valid)
+    return 254;
+
+  /* Establish all our connection objects */
+  handler           = g_object_new (TYPE_THRIFT_TEST_HANDLER,
+                                    NULL);
+
+
+
+  if(strstr(protocol_name, ":multi")){
+      /* When a multiplexed processor is involved the handler is not
+         registered as usual. We create the processor and the real
+         processor is registered. Multiple processors can be registered
+         at once. This is why we don't have a constructor property */
+      processor = g_object_new (THRIFT_TYPE_MULTIPLEXED_PROCESSOR,
+					 NULL);
+
+      handler_second_service = g_object_new (TYPE_SECOND_SERVICE_HANDLER,
+     	                                    NULL);
+
+      processor_test = g_object_new (T_TEST_TYPE_THRIFT_TEST_PROCESSOR,
+				    "handler", handler,
+				    NULL);
+      processor_second_service =   g_object_new (T_TEST_TYPE_SECOND_SERVICE_PROCESSOR,
+				    "handler", handler_second_service,
+				    NULL);
+
+      /* We register a test processor with Multiplexed name ThriftTest */
+      if(!thrift_multiplexed_processor_register_processor(processor,
+						      "ThriftTest", processor_test,
+						      &error)){
+	    g_message ("thrift_server_serve: %s",
+	               error != NULL ? error->message : "(null)");
+	    g_clear_error (&error);
+      }
+      /* We register a second test processor with Multiplexed name SecondService
+       * we are responsible of freeing the processor when it's not used anymore */
+      if(!thrift_multiplexed_processor_register_processor(processor,
+						      "SecondService", processor_second_service,
+						      &error)){
+	    g_message ("thrift_server_serve: %s",
+	               error != NULL ? error->message : "(null)");
+	    g_clear_error (&error);
+      }
+
+  }else{
+      processor = g_object_new (T_TEST_TYPE_THRIFT_TEST_PROCESSOR,
+                                        "handler", handler,
+                                        NULL);
+  }
+  server_transport  = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+                                    "port", port,
+                                    NULL);
+  transport_factory = g_object_new (transport_factory_type,
+                                    NULL);
+
+  if (strstr (protocol_name, "compact") != NULL) {
+    protocol_factory  = g_object_new (protocol_factory_type,
+                                      "string_limit", string_limit,
+                                      "container_limit", container_limit,
+                                      NULL);
+  } else {
+    protocol_factory  = g_object_new (protocol_factory_type,
+                                      NULL);
+  }
+
+  server = g_object_new (THRIFT_TYPE_SIMPLE_SERVER,
+                         "processor",                processor,
+                         "server_transport",         server_transport,
+                         "input_transport_factory",  transport_factory,
+                         "output_transport_factory", transport_factory,
+                         "input_protocol_factory",   protocol_factory,
+                         "output_protocol_factory",  protocol_factory,
+                         NULL);
+
+  /* Install our SIGINT handler, which handles Ctrl-C being pressed by stopping
+     the server gracefully */
+  memset (&sigint_action, 0, sizeof (sigint_action));
+  sigint_action.sa_handler = sigint_handler;
+  sigint_action.sa_flags = SA_RESETHAND;
+  sigaction (SIGINT, &sigint_action, NULL);
+
+  printf ("Starting \"%s\" server (%s/%s) listen on: %d\n",
+          server_name,
+          transport_name,
+          protocol_name,
+          port);
+  fflush (stdout);
+
+  /* Serve clients until SIGINT is received (Ctrl-C is pressed) */
+  thrift_server_serve (server, &error);
+
+  /* If the server stopped for any reason other than being interrupted by the
+     user, report the error */
+  if (!sigint_received) {
+    g_message ("thrift_server_serve: %s",
+               error != NULL ? error->message : "(null)");
+    g_clear_error (&error);
+  }
+
+  puts ("done.");
+
+  g_object_unref (server);
+  g_object_unref (protocol_factory);
+  g_object_unref (transport_factory);
+  g_object_unref (server_transport);
+  g_object_unref (processor);
+  g_object_unref (handler);
+  if(handler_second_service){
+      g_object_unref (handler_second_service);
+  }
+  if(processor_test){
+      g_object_unref (processor_test);
+  }
+  if(processor_second_service){
+      g_object_unref (processor_second_service);
+  }
+
+  return 0;
+}
diff --git a/test/c_glib/src/thrift_second_service_handler.c b/test/c_glib/src/thrift_second_service_handler.c
new file mode 100644
index 0000000..66ac7bc
--- /dev/null
+++ b/test/c_glib/src/thrift_second_service_handler.c
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/thrift_application_exception.h>
+
+#include "thrift_second_service_handler.h"
+
+/* A handler that implements the TTestSecondServiceIf interface */
+
+G_DEFINE_TYPE (SecondServiceHandler,
+               second_service_handler,
+	       T_TEST_TYPE_SECOND_SERVICE_HANDLER);
+
+
+gboolean
+second_service_handler_secondtest_string (TTestSecondServiceIf  *iface,
+                                 gchar             **_return,
+                                 const gchar        *thing,
+                                 GError            **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+  gchar buffer[256];
+
+  printf ("testSecondServiceMultiplexSecondTestString(\"%s\")\n", thing);
+  snprintf(buffer, 255, "testString(\"%s\")", thing);
+  *_return = g_strdup (buffer);
+
+  return TRUE;
+}
+
+static void
+second_service_handler_init (SecondServiceHandler *self)
+{
+  THRIFT_UNUSED_VAR (self);
+}
+
+static void
+second_service_handler_class_init (SecondServiceHandlerClass *klass)
+{
+  TTestSecondServiceHandlerClass *base_class =
+      T_TEST_SECOND_SERVICE_HANDLER_CLASS (klass);
+
+
+  base_class->secondtest_string =
+      second_service_handler_secondtest_string;
+
+}
diff --git a/test/c_glib/src/thrift_second_service_handler.h b/test/c_glib/src/thrift_second_service_handler.h
new file mode 100644
index 0000000..bbe048c
--- /dev/null
+++ b/test/c_glib/src/thrift_second_service_handler.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#ifndef _SECOND_SERVICE_HANDLER_H
+#define _SECOND_SERVICE_HANDLER_H
+
+#include <glib-object.h>
+#include <stdio.h>
+
+#include "../gen-c_glib/t_test_second_service.h"
+
+G_BEGIN_DECLS
+
+/* A handler that implements the TTestSecondServiceIf interface */
+
+#define TYPE_SECOND_SERVICE_HANDLER (second_service_handler_get_type ())
+
+#define SECOND_SERVICE_HANDLER(obj)                                \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                           \
+                               TYPE_SECOND_SERVICE_HANDLER,        \
+                               SecondServiceHandler))
+#define IS_SECOND_SERVICE_HANDLER(obj)                             \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                           \
+                               TYPE_SECOND_SERVICE_HANDLER))
+#define SECOND_SERVICE_HANDLER_CLASS(c)                    \
+  (G_TYPE_CHECK_CLASS_CAST ((c),                        \
+                            TYPE_SECOND_SERVICE_HANDLER,   \
+                            SecondServiceHandlerClass))
+#define IS_SECOND_SERVICE_HANDLER_CLASS(c)                 \
+  (G_TYPE_CHECK_CLASS_TYPE ((c),                        \
+                            TYPE_SECOND_SERVICE_HANDLER))
+#define SECOND_SERVICE_HANDLER_GET_CLASS(obj)              \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                    \
+                              TYPE_SECOND_SERVICE_HANDLER, \
+                              SecondServiceHandlerClass))
+
+typedef struct _SecondServiceHandler SecondServiceHandler;
+typedef struct _SecondServiceHandlerClass SecondServiceHandlerClass;
+
+struct _SecondServiceHandler {
+  TTestSecondServiceHandler parent;
+};
+
+struct _SecondServiceHandlerClass {
+  TTestSecondServiceHandlerClass parent;
+
+};
+
+/* Used by SECOND_SERVICE_HANDLER_GET_TYPE */
+GType second_service_handler_get_type (void);
+
+gboolean second_service_handler_blah_blah (TTestSecondServiceIf *iface, GError **error);
+gboolean second_service_handler_secondtest_string          (TTestSecondServiceIf *iface, gchar ** _return, const gchar * thing, GError **error);
+
+G_END_DECLS
+
+#endif /* _SECOND_SERVICE_HANDLER_H */
diff --git a/test/c_glib/src/thrift_test_handler.c b/test/c_glib/src/thrift_test_handler.c
new file mode 100644
index 0000000..1d8bcb2
--- /dev/null
+++ b/test/c_glib/src/thrift_test_handler.c
@@ -0,0 +1,837 @@
+/*
+ * 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.
+ */
+
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/thrift_application_exception.h>
+
+#include "thrift_test_handler.h"
+
+/* A handler that implements the TTestThriftTestIf interface */
+
+G_DEFINE_TYPE (ThriftTestHandler,
+               thrift_test_handler,
+               T_TEST_TYPE_THRIFT_TEST_HANDLER);
+
+gboolean
+thrift_test_handler_test_void (TTestThriftTestIf  *iface,
+                               GError            **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testVoid()\n");
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_string (TTestThriftTestIf  *iface,
+                                 gchar             **_return,
+                                 const gchar        *thing,
+                                 GError            **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testString(\"%s\")\n", thing);
+  *_return = g_strdup (thing);
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_bool (TTestThriftTestIf  *iface,
+                               gboolean           *_return,
+                               const gboolean      thing,
+                               GError            **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testBool(%s)\n", thing ? "true" : "false");
+  *_return = thing;
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_byte (TTestThriftTestIf  *iface,
+                               gint8              *_return,
+                               const gint8         thing,
+                               GError            **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testByte(%d)\n", (gint)thing);
+  *_return = thing;
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_i32 (TTestThriftTestIf  *iface,
+                              gint32             *_return,
+                              const gint32        thing,
+                              GError            **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testI32(%d)\n", thing);
+  *_return = thing;
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_i64 (TTestThriftTestIf  *iface,
+                              gint64             *_return,
+                              const gint64        thing,
+                              GError            **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testI64(%" PRId64 ")\n", thing);
+  *_return = thing;
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_double (TTestThriftTestIf  *iface,
+                                 gdouble            *_return,
+                                 const gdouble       thing,
+                                 GError            **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testDouble(%f)\n", thing);
+  *_return = thing;
+
+  return TRUE;
+}
+
+gboolean 
+thrift_test_handler_test_binary (TTestThriftTestIf *iface,
+                                 GByteArray ** _return,
+                                 const GByteArray * thing,
+                                 GError **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testBinary()\n");  // TODO: hex output
+  g_byte_array_ref((GByteArray *)thing);
+  *_return = (GByteArray *)thing;
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_struct (TTestThriftTestIf  *iface,
+                                 TTestXtruct       **_return,
+                                 const TTestXtruct  *thing,
+                                 GError            **error)
+{
+  gchar *string_thing = NULL;
+  gint   byte_thing;
+  gint   i32_thing;
+  gint64 i64_thing;
+
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  g_object_get ((TTestXtruct *)thing,
+                "string_thing", &string_thing,
+                "byte_thing",   &byte_thing,
+                "i32_thing",    &i32_thing,
+                "i64_thing",    &i64_thing,
+                NULL);
+
+  printf ("testStruct({\"%s\", %d, %d, %" PRId64 "})\n",
+          string_thing,
+          (gint)byte_thing,
+          i32_thing,
+          i64_thing);
+
+  g_object_set (*_return,
+                "string_thing", string_thing,
+                "byte_thing",   byte_thing,
+                "i32_thing",    i32_thing,
+                "i64_thing",    i64_thing,
+                NULL);
+
+  if (string_thing != NULL)
+    g_free (string_thing);
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_nest (TTestThriftTestIf   *iface,
+                               TTestXtruct2       **_return,
+                               const TTestXtruct2  *thing,
+                               GError             **error)
+{
+  gchar *inner_string_thing = NULL;
+  gint   byte_thing, inner_byte_thing;
+  gint   i32_thing, inner_i32_thing;
+  gint64 inner_i64_thing;
+  TTestXtruct *struct_thing;
+
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  g_object_get ((TTestXtruct2 *)thing,
+                "byte_thing",   &byte_thing,
+                "struct_thing", &struct_thing,
+                "i32_thing",    &i32_thing,
+                NULL);
+  g_object_get (struct_thing,
+                "string_thing", &inner_string_thing,
+                "byte_thing",   &inner_byte_thing,
+                "i32_thing",    &inner_i32_thing,
+                "i64_thing",    &inner_i64_thing,
+                NULL);
+
+  printf ("testNest({%d, {\"%s\", %d, %d, %" PRId64 "}, %d})\n",
+          byte_thing,
+          inner_string_thing,
+          inner_byte_thing,
+          inner_i32_thing,
+          inner_i64_thing,
+          i32_thing);
+
+  g_object_set (*_return,
+                "byte_thing",   byte_thing,
+                "struct_thing", struct_thing,
+                "i32_thing",    i32_thing,
+                NULL);
+
+  if (inner_string_thing != NULL)
+    g_free (inner_string_thing);
+  g_object_unref (struct_thing);
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_map (TTestThriftTestIf  *iface,
+                              GHashTable        **_return,
+                              const GHashTable   *thing,
+                              GError            **error)
+{
+  GHashTableIter hash_table_iter;
+  gpointer key;
+  gpointer value;
+  gboolean first = TRUE;
+
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testMap({");
+  g_hash_table_iter_init (&hash_table_iter, (GHashTable *)thing);
+  while (g_hash_table_iter_next (&hash_table_iter,
+                                 &key,
+                                 &value)) {
+    gint32 *new_key;
+    gint32 *new_value;
+
+    if (first)
+      first = FALSE;
+    else
+      printf (", ");
+
+    printf ("%d => %d", *(gint32 *)key, *(gint32 *)value);
+
+    new_key = g_malloc (sizeof *new_key);
+    *new_key = *(gint32 *)key;
+    new_value = g_malloc (sizeof *new_value);
+    *new_value = *(gint32 *)value;
+    g_hash_table_insert (*_return, new_key, new_value);
+  }
+  printf ("})\n");
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_string_map (TTestThriftTestIf  *iface,
+                                     GHashTable        **_return,
+                                     const GHashTable   *thing,
+                                     GError            **error)
+{
+  GHashTableIter hash_table_iter;
+  gpointer key;
+  gpointer value;
+  gboolean first = TRUE;
+
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testStringMap({");
+  g_hash_table_iter_init (&hash_table_iter, (GHashTable *)thing);
+  while (g_hash_table_iter_next (&hash_table_iter,
+                                 &key,
+                                 &value)) {
+    gchar *new_key;
+    gchar *new_value;
+
+    if (first)
+      first = FALSE;
+    else
+      printf (", ");
+
+    printf ("%s => %s", (gchar *)key, (gchar *)value);
+
+    new_key = g_strdup ((gchar *)key);
+    new_value = g_strdup ((gchar *)value);
+    g_hash_table_insert (*_return, new_key, new_value);
+  }
+  printf ("})\n");
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_set (TTestThriftTestIf  *iface,
+                              GHashTable        **_return,
+                              const GHashTable   *thing,
+                              GError            **error)
+{
+  GHashTableIter hash_table_iter;
+  gpointer key;
+  gboolean first = TRUE;
+
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testSet({");
+  g_hash_table_iter_init (&hash_table_iter, (GHashTable *)thing);
+  while (g_hash_table_iter_next (&hash_table_iter,
+                                 &key,
+                                 NULL)) {
+    gint32 *new_key;
+
+    if (first)
+      first = FALSE;
+    else
+      printf (", ");
+
+    printf ("%d", *(gint32 *)key);
+
+    new_key = g_malloc (sizeof *new_key);
+    *new_key = *(gint32 *)key;
+    g_hash_table_insert (*_return, new_key, NULL);
+  }
+  printf ("})\n");
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_list (TTestThriftTestIf  *iface,
+                               GArray            **_return,
+                               const GArray       *thing,
+                               GError            **error)
+{
+  guint i;
+  gboolean first = TRUE;
+
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testList({");
+  for (i = 0; i < thing->len; i += 1) {
+    gint32 value;
+    gint32 *new_value;
+
+    if (first)
+      first = FALSE;
+    else
+      printf (", ");
+
+    value = g_array_index (thing, gint32, i);
+    printf ("%d", value);
+
+    new_value = g_malloc (sizeof *new_value);
+    *new_value = value;
+    g_array_append_val (*_return, *new_value);
+  }
+  printf ("})\n");
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_enum (TTestThriftTestIf   *iface,
+                               TTestNumberz        *_return,
+                               const TTestNumberz   thing,
+                               GError             **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testEnum(%d)\n", thing);
+  *_return = thing;
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_typedef (TTestThriftTestIf  *iface,
+                                  TTestUserId        *_return,
+                                  const TTestUserId   thing,
+                                  GError            **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testTypedef(%" PRId64 ")\n", thing);
+  *_return = thing;
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_map_map (TTestThriftTestIf  *iface,
+                                  GHashTable        **_return,
+                                  const gint32        hello,
+                                  GError            **error)
+{
+  GHashTable *positive;
+  GHashTable *negative;
+  gint32 *key;
+  gint32 *value;
+  guint i;
+
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testMapMap(%d)\n", hello);
+
+  positive = g_hash_table_new_full (g_int_hash,
+                                    g_int_equal,
+                                    g_free,
+                                    g_free);
+  negative = g_hash_table_new_full (g_int_hash,
+                                    g_int_equal,
+                                    g_free,
+                                    g_free);
+
+  for (i = 1; i < 5; i += 1) {
+    key = g_malloc (sizeof *key);
+    value = g_malloc (sizeof *value);
+    *key = i;
+    *value = i;
+    g_hash_table_insert (positive, key, value);
+
+    key = g_malloc (sizeof *key);
+    value = g_malloc (sizeof *value);
+    *key = -i;
+    *value = -i;
+    g_hash_table_insert (negative, key, value);
+  }
+
+  key = g_malloc (sizeof *key);
+  *key = 4;
+  g_hash_table_insert (*_return, key, positive);
+
+  key = g_malloc (sizeof *key);
+  *key = -4;
+  g_hash_table_insert (*_return, key, negative);
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_insanity (TTestThriftTestIf    *iface,
+                                   GHashTable          **_return,
+                                   const TTestInsanity  *argument,
+                                   GError              **error)
+{
+  TTestXtruct *xtruct_in;
+
+  gchar *string_thing = NULL;
+  gint   byte_thing;
+  gint   i32_thing;
+  gint64 i64_thing;
+
+  GPtrArray *xtructs;
+
+  TTestInsanity *looney;
+
+  GHashTable *user_map;
+  GHashTable *first_map;
+  GHashTable *second_map;
+
+  GHashTableIter hash_table_iter;
+  GHashTableIter inner_hash_table_iter;
+  GHashTableIter user_map_iter;
+
+  gpointer key;
+  gpointer value;
+
+  TTestUserId *user_id;
+
+  guint i;
+
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testInsanity()\n");
+
+  first_map = g_hash_table_new_full (g_direct_hash,
+                                     g_direct_equal,
+                                     NULL,
+                                     g_object_unref);
+  second_map = g_hash_table_new_full (g_direct_hash,
+                                      g_direct_equal,
+                                      NULL,
+                                      g_object_unref);
+
+  g_hash_table_insert (first_map,
+                       GINT_TO_POINTER (T_TEST_NUMBERZ_TWO),
+                       (gpointer)argument);
+  g_hash_table_insert (first_map,
+                       GINT_TO_POINTER (T_TEST_NUMBERZ_THREE),
+                       (gpointer)argument);
+
+  /* Increment argument's ref count by two because first_map now holds
+     two references to it and the caller is not aware we have made any
+     additional references to argument.  (That is, caller owns argument
+     and will unref it explicitly in addition to unref-ing *_return.)
+
+     We do this instead of creating a copy of argument in order to mimic
+     the C++ implementation (and since, frankly, the world needs less
+     argument, not more). */
+  g_object_ref ((gpointer)argument);
+  g_object_ref ((gpointer)argument);
+
+  looney = g_object_new (T_TEST_TYPE_INSANITY, NULL);
+  g_hash_table_insert (second_map,
+                       GINT_TO_POINTER (T_TEST_NUMBERZ_SIX),
+                       looney);
+
+  user_id = g_malloc (sizeof *user_id);
+  *user_id = 1;
+  g_hash_table_insert (*_return, user_id, first_map);
+
+  user_id = g_malloc (sizeof *user_id);
+  *user_id = 2;
+  g_hash_table_insert (*_return, user_id, second_map);
+
+  printf ("return");
+  printf (" = {");
+  g_hash_table_iter_init (&hash_table_iter, *_return);
+  while (g_hash_table_iter_next (&hash_table_iter,
+                                 &key,
+                                 &value)) {
+    printf ("%" PRId64 " => {", *(TTestUserId *)key);
+
+    g_hash_table_iter_init (&inner_hash_table_iter,
+                            (GHashTable *)value);
+    while (g_hash_table_iter_next (&inner_hash_table_iter,
+                                   &key,
+                                   &value)) {
+      printf ("%d => {", (TTestNumberz)key);
+
+      g_object_get ((TTestInsanity *)value,
+                    "userMap", &user_map,
+                    "xtructs", &xtructs,
+                    NULL);
+
+      printf ("{");
+      g_hash_table_iter_init (&user_map_iter, user_map);
+      while (g_hash_table_iter_next (&user_map_iter,
+                                     &key,
+                                     &value)) {
+        printf ("%d => %" PRId64 ", ",
+                (TTestNumberz)key,
+                *(TTestUserId *)value);
+      }
+      printf ("}, ");
+      g_hash_table_unref (user_map);
+
+      printf ("{");
+      for (i = 0; i < xtructs->len; ++i) {
+        xtruct_in = g_ptr_array_index (xtructs, i);
+        g_object_get (xtruct_in,
+                      "string_thing", &string_thing,
+                      "byte_thing",   &byte_thing,
+                      "i32_thing",    &i32_thing,
+                      "i64_thing",    &i64_thing,
+                      NULL);
+
+        printf ("{\"%s\", %d, %d, %" PRId64 "}, ",
+                string_thing,
+                byte_thing,
+                i32_thing,
+                i64_thing);
+      }
+      printf ("}");
+      g_ptr_array_unref (xtructs);
+
+      printf ("}, ");
+    }
+    printf ("}, ");
+  }
+  printf ("}\n");
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_multi (TTestThriftTestIf   *iface,
+                                TTestXtruct        **_return,
+                                const gint8          arg0,
+                                const gint32         arg1,
+                                const gint64         arg2,
+                                const GHashTable    *arg3,
+                                const TTestNumberz   arg4,
+                                const TTestUserId    arg5,
+                                GError             **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+  THRIFT_UNUSED_VAR (arg3);
+  THRIFT_UNUSED_VAR (arg4);
+  THRIFT_UNUSED_VAR (arg5);
+
+  printf ("testMulti()\n");
+
+  g_object_set (*_return,
+                "string_thing", g_strdup ("Hello2"),
+                "byte_thing",   arg0,
+                "i32_thing",    arg1,
+                "i64_thing",    arg2,
+                NULL);
+
+  return TRUE;
+}
+
+gboolean
+thrift_test_handler_test_exception (TTestThriftTestIf  *iface,
+                                    const gchar        *arg,
+                                    TTestXception     **err1,
+                                    GError            **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+
+  TTestXtruct *xtruct;
+  gboolean result;
+
+  printf ("testException(%s)\n", arg);
+
+  /* Unlike argument objects, exception objects are not pre-created */
+  g_assert (*err1 == NULL);
+
+  if (strncmp (arg, "Xception", 9) == 0) {
+    /* "Throw" a custom exception: Set the corresponding exception
+       argument, set *error to NULL and return FALSE */
+    *err1 = g_object_new (T_TEST_TYPE_XCEPTION,
+                          "errorCode", 1001,
+                          "message",   g_strdup (arg),
+                          NULL);
+    *error = NULL;
+    result = FALSE;
+  }
+  else if (strncmp (arg, "TException", 11) == 0) {
+    /* "Throw" a generic TException (ThriftApplicationException): Set
+       all exception arguments to NULL, set *error and return FALSE */
+    *err1 = NULL;
+    g_set_error (error,
+                 thrift_application_exception_error_quark (),
+                 THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN,
+                 "Default TException.");
+    result = FALSE;
+  }
+  else {
+    *err1 = NULL;
+    *error = NULL;
+
+    /* This code is duplicated from the C++ test suite, though it
+       appears to serve no purpose */
+    xtruct = g_object_new (T_TEST_TYPE_XTRUCT,
+                           "string_thing", g_strdup (arg),
+                           NULL);
+    g_object_unref (xtruct);
+
+    result = TRUE;
+  }
+
+  return result;
+}
+
+gboolean
+thrift_test_handler_test_multi_exception (TTestThriftTestIf  *iface,
+                                          TTestXtruct       **_return,
+                                          const gchar        *arg0,
+                                          const gchar        *arg1,
+                                          TTestXception     **err1,
+                                          TTestXception2    **err2,
+                                          GError            **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  TTestXtruct *struct_thing;
+  gboolean result;
+
+  printf ("testMultiException(%s, %s)\n", arg0, arg1);
+
+  g_assert (*err1 == NULL);
+  g_assert (*err2 == NULL);
+
+  if (strncmp (arg0, "Xception", 8) == 0 && strlen(arg0) == 8) {
+    *err1 = g_object_new (T_TEST_TYPE_XCEPTION,
+                          "errorCode", 1001,
+                          "message",   g_strdup ("This is an Xception"),
+                          NULL);
+    result = FALSE;
+  }
+  else if (strncmp (arg0, "Xception2", 9) == 0) {
+    *err2 = g_object_new (T_TEST_TYPE_XCEPTION2,
+                          "errorCode", 2002,
+                          NULL);
+
+    g_object_get (*err2,
+                  "struct_thing", &struct_thing,
+                  NULL);
+    g_object_set (struct_thing,
+                  "string_thing", g_strdup ("This is an Xception2"),
+                  NULL);
+    g_object_set (*err2,
+                  "struct_thing", struct_thing,
+                  NULL);
+    g_object_unref (struct_thing);
+
+    result = FALSE;
+  }
+  else {
+    g_object_set (*_return,
+                  "string_thing", g_strdup (arg1),
+                  NULL);
+    result = TRUE;
+  }
+
+  return result;
+}
+
+gboolean
+thrift_test_handler_test_oneway (TTestThriftTestIf  *iface,
+                                 const gint32        secondsToSleep,
+                                 GError            **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("testOneway(%d): Sleeping...\n", secondsToSleep);
+  sleep (secondsToSleep);
+  printf ("testOneway(%d): done sleeping!\n", secondsToSleep);
+
+  return TRUE;
+}
+
+static void
+thrift_test_handler_init (ThriftTestHandler *self)
+{
+  THRIFT_UNUSED_VAR (self);
+}
+
+static void
+thrift_test_handler_class_init (ThriftTestHandlerClass *klass)
+{
+  TTestThriftTestHandlerClass *base_class =
+    T_TEST_THRIFT_TEST_HANDLER_CLASS (klass);
+
+  base_class->test_void =
+    klass->test_void =
+    thrift_test_handler_test_void;
+  base_class->test_string =
+    klass->test_string =
+    thrift_test_handler_test_string;
+  base_class->test_bool =
+    klass->test_bool =
+    thrift_test_handler_test_bool;
+  base_class->test_byte =
+    klass->test_byte =
+    thrift_test_handler_test_byte;
+  base_class->test_i32 =
+    klass->test_i32 =
+    thrift_test_handler_test_i32;
+  base_class->test_i64 =
+    klass->test_i64 =
+    thrift_test_handler_test_i64;
+  base_class->test_double =
+    klass->test_double =
+    thrift_test_handler_test_double;
+  base_class->test_binary =
+    klass->test_binary =
+    thrift_test_handler_test_binary;
+  base_class->test_struct =
+    klass->test_struct =
+    thrift_test_handler_test_struct;
+  base_class->test_nest =
+    klass->test_nest =
+    thrift_test_handler_test_nest;
+  base_class->test_map =
+    klass->test_map =
+    thrift_test_handler_test_map;
+  base_class->test_string_map =
+    klass->test_string_map =
+    thrift_test_handler_test_string_map;
+  base_class->test_set =
+    klass->test_set =
+    thrift_test_handler_test_set;
+  base_class->test_list =
+    klass->test_list =
+    thrift_test_handler_test_list;
+  base_class->test_enum =
+    klass->test_enum =
+    thrift_test_handler_test_enum;
+  base_class->test_typedef =
+    klass->test_typedef =
+    thrift_test_handler_test_typedef;
+  base_class->test_map_map =
+    klass->test_map_map =
+    thrift_test_handler_test_map_map;
+  base_class->test_insanity =
+    klass->test_insanity =
+    thrift_test_handler_test_insanity;
+  base_class->test_multi =
+    klass->test_multi =
+    thrift_test_handler_test_multi;
+  base_class->test_exception =
+    klass->test_exception =
+    thrift_test_handler_test_exception;
+  base_class->test_multi_exception =
+    klass->test_multi_exception =
+    thrift_test_handler_test_multi_exception;
+  base_class->test_oneway =
+    klass->test_oneway =
+    thrift_test_handler_test_oneway;
+}
diff --git a/test/c_glib/src/thrift_test_handler.h b/test/c_glib/src/thrift_test_handler.h
new file mode 100644
index 0000000..b64cb16
--- /dev/null
+++ b/test/c_glib/src/thrift_test_handler.h
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_TEST_HANDLER_H
+#define _THRIFT_TEST_HANDLER_H
+
+#include <glib-object.h>
+#include <stdio.h>
+
+#include "../gen-c_glib/t_test_thrift_test.h"
+
+G_BEGIN_DECLS
+
+/* A handler that implements the TTestThriftTestIf interface */
+
+#define TYPE_THRIFT_TEST_HANDLER (thrift_test_handler_get_type ())
+
+#define THRIFT_TEST_HANDLER(obj)                                \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                           \
+                               TYPE_THRIFT_TEST_HANDLER,        \
+                               ThriftTestHandler))
+#define IS_THRIFT_TEST_HANDLER(obj)                             \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                           \
+                               TYPE_THRIFT_TEST_HANDLER))
+#define THRIFT_TEST_HANDLER_CLASS(c)                    \
+  (G_TYPE_CHECK_CLASS_CAST ((c),                        \
+                            TYPE_THRIFT_TEST_HANDLER,   \
+                            ThriftTestHandlerClass))
+#define IS_THRIFT_TEST_HANDLER_CLASS(c)                 \
+  (G_TYPE_CHECK_CLASS_TYPE ((c),                        \
+                            TYPE_THRIFT_TEST_HANDLER))
+#define THRIFT_TEST_HANDLER_GET_CLASS(obj)              \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                    \
+                              TYPE_THRIFT_TEST_HANDLER, \
+                              ThriftTestHandlerClass))
+
+typedef struct _ThriftTestHandler ThriftTestHandler;
+typedef struct _ThriftTestHandlerClass ThriftTestHandlerClass;
+
+struct _ThriftTestHandler {
+  TTestThriftTestHandler parent;
+};
+
+struct _ThriftTestHandlerClass {
+  TTestThriftTestHandlerClass parent;
+
+  gboolean (*test_void)            (TTestThriftTestIf    *iface,
+                                    GError              **error);
+  gboolean (*test_string)          (TTestThriftTestIf    *iface,
+                                    gchar               **_return,
+                                    const gchar          *thing,
+                                    GError              **error);
+  gboolean (*test_bool)            (TTestThriftTestIf    *iface,
+                                    gboolean*_return,
+                                    const gboolean        thing,
+                                    GError              **error);
+  gboolean (*test_byte)            (TTestThriftTestIf    *iface,
+                                    gint8*_return,
+                                    const gint8           thing,
+                                    GError              **error);
+  gboolean (*test_i32)             (TTestThriftTestIf    *iface,
+                                    gint32*_return,
+                                    const gint32          thing,
+                                    GError              **error);
+  gboolean (*test_i64)             (TTestThriftTestIf    *iface,
+                                    gint64*_return,
+                                    const gint64          thing,
+                                    GError              **error);
+  gboolean (*test_double)          (TTestThriftTestIf    *iface,
+                                    gdouble*_return,
+                                    const gdouble         thing,
+                                    GError              **error);
+  gboolean (*test_binary)          (TTestThriftTestIf    *iface,
+                                    GByteArray        **_return,
+                                    const GByteArray     *thing,
+                                    GError              **error);
+  gboolean (*test_struct)          (TTestThriftTestIf    *iface,
+                                    TTestXtruct         **_return,
+                                    const TTestXtruct    *thing,
+                                    GError              **error);
+  gboolean (*test_nest)            (TTestThriftTestIf    *iface,
+                                    TTestXtruct2        **_return,
+                                    const TTestXtruct2   *thing,
+                                    GError              **error);
+  gboolean (*test_map)             (TTestThriftTestIf    *iface,
+                                    GHashTable          **_return,
+                                    const GHashTable     *thing,
+                                    GError              **error);
+  gboolean (*test_string_map)      (TTestThriftTestIf    *iface,
+                                    GHashTable          **_return,
+                                    const GHashTable     *thing,
+                                    GError              **error);
+  gboolean (*test_set)             (TTestThriftTestIf    *iface,
+                                    GHashTable          **_return,
+                                    const GHashTable     *thing,
+                                    GError              **error);
+  gboolean (*test_list)            (TTestThriftTestIf    *iface,
+                                    GArray              **_return,
+                                    const GArray         *thing,
+                                    GError              **error);
+  gboolean (*test_enum)            (TTestThriftTestIf    *iface,
+                                    TTestNumberz*_return,
+                                    const TTestNumberz    thing,
+                                    GError              **error);
+  gboolean (*test_typedef)         (TTestThriftTestIf    *iface,
+                                    TTestUserId*_return,
+                                    const TTestUserId     thing,
+                                    GError              **error);
+  gboolean (*test_map_map)         (TTestThriftTestIf    *iface,
+                                    GHashTable          **_return,
+                                    const gint32          hello,
+                                    GError              **error);
+  gboolean (*test_insanity)        (TTestThriftTestIf    *iface,
+                                    GHashTable          **_return,
+                                    const TTestInsanity  *argument,
+                                    GError              **error);
+  gboolean (*test_multi)           (TTestThriftTestIf    *iface,
+                                    TTestXtruct         **_return,
+                                    const gint8           arg0,
+                                    const gint32          arg1,
+                                    const gint64          arg2,
+                                    const GHashTable     *arg3,
+                                    const TTestNumberz    arg4,
+                                    const TTestUserId     arg5,
+                                    GError              **error);
+  gboolean (*test_exception)       (TTestThriftTestIf    *iface,
+                                    const gchar          *arg,
+                                    TTestXception       **err1,
+                                    GError              **error);
+  gboolean (*test_multi_exception) (TTestThriftTestIf    *iface,
+                                    TTestXtruct         **_return,
+                                    const gchar          *arg0,
+                                    const gchar          *arg1,
+                                    TTestXception       **err1,
+                                    TTestXception2      **err2,
+                                    GError              **error);
+  gboolean (*test_oneway)          (TTestThriftTestIf    *iface,
+                                    const gint32          secondsToSleep,
+                                    GError              **error);
+};
+
+/* Used by THRIFT_TEST_HANDLER_GET_TYPE */
+GType thrift_test_handler_get_type (void);
+
+gboolean thrift_test_handler_test_void            (TTestThriftTestIf    *iface,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_string          (TTestThriftTestIf    *iface,
+                                                   gchar               **_return,
+                                                   const gchar          *thing,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_byte            (TTestThriftTestIf    *iface,
+                                                   gint8*_return,
+                                                   const gint8           thing,
+                                                   GError              **error);
+gboolean t_test_thrift_test_if_test_i32           (TTestThriftTestIf    *iface,
+                                                   gint32*_return,
+                                                   const gint32          thing,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_i64             (TTestThriftTestIf    *iface,
+                                                   gint64*_return,
+                                                   const gint64          thing,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_double          (TTestThriftTestIf    *iface,
+                                                   gdouble*_return,
+                                                   const gdouble         thing,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_struct          (TTestThriftTestIf    *iface,
+                                                   TTestXtruct         **_return,
+                                                   const TTestXtruct    *thing,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_nest            (TTestThriftTestIf    *iface,
+                                                   TTestXtruct2        **_return,
+                                                   const TTestXtruct2   *thing,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_map             (TTestThriftTestIf    *iface,
+                                                   GHashTable          **_return,
+                                                   const GHashTable     *thing,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_string_map      (TTestThriftTestIf    *iface,
+                                                   GHashTable          **_return,
+                                                   const GHashTable     *thing,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_set             (TTestThriftTestIf    *iface,
+                                                   GHashTable          **_return,
+                                                   const GHashTable     *thing,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_list            (TTestThriftTestIf    *iface,
+                                                   GArray              **_return,
+                                                   const GArray         *thing,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_typedef         (TTestThriftTestIf    *iface,
+                                                   TTestUserId*_return,
+                                                   const TTestUserId     thing,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_map_map         (TTestThriftTestIf    *iface,
+                                                   GHashTable          **_return,
+                                                   const gint32          hello,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_insanity        (TTestThriftTestIf    *iface,
+                                                   GHashTable          **_return,
+                                                   const TTestInsanity  *argument,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_multi           (TTestThriftTestIf    *iface,
+                                                   TTestXtruct         **_return,
+                                                   const gint8           arg0,
+                                                   const gint32          arg1,
+                                                   const gint64          arg2,
+                                                   const GHashTable     *arg3,
+                                                   const TTestNumberz    arg4,
+                                                   const TTestUserId     arg5,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_exception       (TTestThriftTestIf    *iface,
+                                                   const gchar          *arg,
+                                                   TTestXception       **err1,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_multi_exception (TTestThriftTestIf    *iface,
+                                                   TTestXtruct         **_return,
+                                                   const gchar          *arg0,
+                                                   const gchar          *arg1,
+                                                   TTestXception       **err1,
+                                                   TTestXception2      **err2,
+                                                   GError              **error);
+gboolean thrift_test_handler_test_oneway          (TTestThriftTestIf    *iface,
+                                                   const gint32          secondsToSleep,
+                                                   GError              **error);
+
+G_END_DECLS
+
+#endif /* _THRIFT_TEST_HANDLER_H */
diff --git a/test/cl/Makefile.am b/test/cl/Makefile.am
new file mode 100755
index 0000000..b5e72bc
--- /dev/null
+++ b/test/cl/Makefile.am
@@ -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.
+#
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) --gen cl ../ThriftTest.thrift
+
+TestServer: make-test-server.lisp
+	$(SBCL) --script make-test-server.lisp
+
+TestClient: make-test-client.lisp
+	$(SBCL) --script make-test-client.lisp
+
+precross: stubs TestServer TestClient
+
+clean-local:
+	$(RM) -r gen-cl
+	$(RM) TestServer
+	$(RM) TestClient
+
+EXTRA_DIST = \
+	implementation.lisp \
+	make-test-client.lisp \
+	make-test-server.lisp \
+	tests.lisp
diff --git a/test/cl/implementation.lisp b/test/cl/implementation.lisp
new file mode 100644
index 0000000..0caf7be
--- /dev/null
+++ b/test/cl/implementation.lisp
@@ -0,0 +1,136 @@
+(in-package #:thrift.test-implementation)
+
+;;;; Licensed under the Apache License, Version 2.0 (the "License");
+;;;; you may not use this file except in compliance with the License.
+;;;; You may obtain a copy of the License at
+;;;;
+;;;;     http://www.apache.org/licenses/LICENSE-2.0
+;;;;
+;;;; Unless required by applicable law or agreed to in writing, software
+;;;; distributed under the License is distributed on an "AS IS" BASIS,
+;;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;;;; See the License for the specific language governing permissions and
+;;;; limitations under the License.
+
+(defun thrift.test.thrift-test-implementation:test-void ()
+  (format t "testVoid()~%"))
+
+(defun thrift.test.thrift-test-implementation:test-string (thing)
+  (format t "testString(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-bool (thing)
+  (format t "testBool(~a)~%" (if thing "true" "false"))
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-byte (thing)
+  (format t "testByte(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-i32 (thing)
+  (format t "testI32(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-i64 (thing)
+  (format t "testI64(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-double (thing)
+  (format t "testDouble(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-binary (thing)
+  (format t "testBinary(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-struct (thing)
+  (format t "testStruct(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-nest (thing)
+  (format t "testNest(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-map (thing)
+  (format t "testMap(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-string-map (thing)
+  (format t "testStringMap(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-set (thing)
+  (format t "testSet(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-list (thing)
+  (format t "testList(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-enum (thing)
+  (format t "testEnum(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-typedef (thing)
+  (format t "testTypedef(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-map-map (hello)
+  (format t "testMapMap(~a)~%" hello)
+  '((-4 . ((-4 . -4) (-3 . -3) (-2 . -2) (-1 . -1))) (4 . ((1 . 1) (2 . 2) (3 . 3) (4 . 4)))))
+
+(defun thrift.test.thrift-test-implementation:test-insanity (argument)
+  (let ((result `((1 . ((2 . ,argument) (3 . ,argument)))
+                  (2 . ((6 . ,(thrift.test::make-insanity :user-map nil :xtructs nil)))))))
+    (format t "~a~%" result)
+    result))
+
+(defun thrift.test.thrift-test-implementation:test-multi (arg0 arg1 arg2 arg3 arg4 arg5)
+  (declare (ignorable arg3 arg4 arg5))
+  (format t "testMulti()~%")
+  (thrift.test:make-xtruct :string-thing "Hello2"
+                           :byte-thing arg0
+                           :i32-thing arg1
+                           :i64-thing arg2))
+
+(defun thrift.test.thrift-test-implementation:test-exception (arg)
+  (format t "testException(~a)~%" arg)
+  (cond
+    ((string= arg "Xception") (error 'thrift.test:xception
+                                     :error-code 1001
+                                     :message arg))
+    ((string= arg "TException") (error 'thrift.test:xception
+                                       :error-code 0
+                                       :message "Stuff!"))))
+
+(defun thrift.test.thrift-test-implementation:test-multi-exception (arg0 arg1)
+  (format t "testMultiException(~a, ~a)~%" arg0 arg1)
+  (cond
+    ((string= arg0 "Xception") (error 'thrift.test:xception
+                                     :error-code 1001
+                                     :message "This is an Xception"))
+    ((string= arg0 "Xception2") (error 'thrift.test:xception2
+                                     :error-code 2002
+                                     :struct-thing (thrift.test:make-xtruct :string-thing "This is an Xception2"
+                                                                            :byte-thing 0
+                                                                            :i32-thing 0
+                                                                            :i64-thing 0))))
+  (thrift.test:make-xtruct :string-thing arg1
+                           :byte-thing 0
+                           :i32-thing 0
+                           :i64-thing 0))
+
+(defun thrift.test.thrift-test-implementation:test-oneway (seconds)
+  (format t "testOneway(~a): Sleeping...~%" seconds)
+  (sleep seconds)
+  (format t "testOneway(~a): done sleeping!~%" seconds))
+
+;;; Removed from the IDL definition.
+#+(or)
+(defun thrift.test.second-service-implementation:blah-blah ()
+  (format t "blahBlah()~%"))
+
+(defun thrift.test.second-service-implementation:secondtest-string (thing)
+  (format t "secondtestString(~a)~%" thing)
+  (concatenate 'string "testString(\"" thing "\")"))
+
diff --git a/test/cl/make-test-client.lisp b/test/cl/make-test-client.lisp
new file mode 100644
index 0000000..509669d
--- /dev/null
+++ b/test/cl/make-test-client.lisp
@@ -0,0 +1,93 @@
+(in-package #:cl-user)
+
+;;;; Licensed under the Apache License, Version 2.0 (the "License");
+;;;; you may not use this file except in compliance with the License.
+;;;; You may obtain a copy of the License at
+;;;;
+;;;;     http://www.apache.org/licenses/LICENSE-2.0
+;;;;
+;;;; Unless required by applicable law or agreed to in writing, software
+;;;; distributed under the License is distributed on an "AS IS" BASIS,
+;;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;;;; See the License for the specific language governing permissions and
+;;;; limitations under the License.
+
+#+(or) (when (not (boundp 'sb-impl::default-external-format)
+                 (setf sb-impl::default-external-format :UTF-8)))
+
+(require "asdf")
+(load (merge-pathnames "../../lib/cl/load-locally.lisp" *load-truename*))
+(asdf:load-system :net.didierverna.clon)
+(asdf:load-system :fiasco)
+(asdf:load-asd (merge-pathnames "gen-cl/ThriftTest/thrift-gen-ThriftTest.asd" *load-truename*))
+(asdf:load-system :thrift-gen-thrifttest)
+
+(net.didierverna.clon:nickname-package)
+
+(defpackage #:thrift-cross
+  (:use #:common-lisp #:fiasco)
+  (:export #:cross-test))
+
+(in-package #:thrift-cross)
+
+(defparameter *prot* nil)
+
+(load (merge-pathnames "tests.lisp" *load-truename*) :external-format :UTF-8)
+
+(clon:defsynopsis ()
+  (text :contents "The Common Lisp client for Thrift's cross-language test suite.")
+  (group (:header "Allowed options:")
+    (flag :short-name "h" :long-name "help"
+          :description "Print this help and exit.")
+    (stropt :long-name "host"
+            :description "The host to connect to."
+            :default-value "localhost"
+            :argument-name "ARG")
+    (stropt :long-name "port"
+            :description "Number of the port to listen for connections on."
+            :default-value "9090"
+            :argument-name "ARG"
+            :argument-type :optional)
+    (stropt :long-name "transport"
+            :description "Transport: transport to use (\"buffered\", \"framed\")"
+            :default-value "buffered"
+            :argument-name "ARG")
+    (stropt :long-name "protocol"
+            :description "Protocol: protocol to use (\"binary\", \"multi\")"
+            :default-value "binary"
+            :argument-name "ARG")))
+
+(defun main ()
+  "Entry point for our standalone application."
+  (clon:make-context)
+  (when (clon:getopt :short-name "h")
+    (clon:help)
+    (clon:exit))
+  (let ((port "9090")
+        (host "localhost")
+        (framed nil)
+        (multiplexed nil))
+    (clon:do-cmdline-options (option name value source)
+      (print (list option name value source))
+      (if (string= name "host")
+          (setf host value))
+      (if (string= name "port")
+          (setf port value))
+      (if (string= name "transport")
+          (cond ((string= value "buffered") (setf framed nil))
+                ((string= value "framed") (setf framed t))
+                (t (error "Unsupported transport."))))
+      (if (string= name "protocol")
+          (cond ((string= value "binary") (setf multiplexed nil))
+                ((string= value "multi") (setf multiplexed t))
+                (t (error "Unsupported protocol.")))))
+    (terpri)
+    (setf *prot* (thrift.implementation::client (puri:parse-uri
+                                                 (concatenate 'string "thrift://" host ":" port))
+                                                :framed framed
+                                                :multiplexed multiplexed))
+    (let ((result (cross-test :multiplexed multiplexed)))
+      (thrift.implementation::close *prot*)
+      (clon:exit result))))
+
+(clon:dump "TestClient" main)
diff --git a/test/cl/make-test-server.lisp b/test/cl/make-test-server.lisp
new file mode 100644
index 0000000..293c879
--- /dev/null
+++ b/test/cl/make-test-server.lisp
@@ -0,0 +1,80 @@
+(in-package #:cl-user)
+
+;;;; Licensed under the Apache License, Version 2.0 (the "License");
+;;;; you may not use this file except in compliance with the License.
+;;;; You may obtain a copy of the License at
+;;;;
+;;;;     http://www.apache.org/licenses/LICENSE-2.0
+;;;;
+;;;; Unless required by applicable law or agreed to in writing, software
+;;;; distributed under the License is distributed on an "AS IS" BASIS,
+;;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;;;; See the License for the specific language governing permissions and
+;;;; limitations under the License.
+
+(require "asdf")
+(load (merge-pathnames "../../lib/cl/load-locally.lisp" *load-truename*))
+(asdf:load-system :net.didierverna.clon)
+(asdf:load-asd (merge-pathnames "gen-cl/ThriftTest/thrift-gen-ThriftTest.asd" *load-truename*))
+(asdf:load-system :thrift-gen-thrifttest)
+(load (merge-pathnames "implementation.lisp" *load-truename*))
+
+(net.didierverna.clon:nickname-package)
+
+(clon:defsynopsis ()
+  (text :contents "The Common Lisp server for Thrift's cross-language test suite.")
+  (group (:header "Allowed options:")
+    (flag :short-name "h" :long-name "help"
+          :description "Print this help and exit.")
+    (stropt :long-name "port"
+            :description "Number of the port to listen for connections on."
+            :default-value "9090"
+            :argument-name "ARG"
+            :argument-type :optional)
+    (stropt :long-name "server-type"
+            :description "The type of server, currently only \"simple\" is available."
+            :default-value "simple"
+            :argument-name "ARG")
+    (stropt :long-name "transport"
+            :description "Transport: transport to use (\"buffered\" or \"framed\")"
+            :default-value "buffered"
+            :argument-name "ARG")
+    (stropt :long-name "protocol"
+            :description "Protocol: protocol to use (\"binary\" or \"multi\")"
+            :default-value "binary"
+            :argument-name "ARG")))
+
+(defun main ()
+  "Entry point for our standalone application."
+  (clon:make-context)
+  (when (clon:getopt :short-name "h")
+    (clon:help)
+    (clon:exit))
+  (let ((port "9090")
+        (framed nil)
+        (multiplexed nil))
+    (clon:do-cmdline-options (option name value source)
+      (print (list option name value source))
+      (if (string= name "port")
+          (setf port value))
+      (if (string= name "transport")
+          (cond ((string= value "buffered") (setf framed nil))
+                ((string= value "framed") (setf framed t))
+                (t (error "Unsupported transport."))))
+      (if (string= name "protocol")
+          (cond ((string= value "binary") (setf multiplexed nil))
+                ((string= value "multi") (setf multiplexed t))
+                (t (error "Unsupported protocol.")))))
+    (terpri)
+    (let ((services (if multiplexed
+                        (list thrift.test:thrift-test thrift.test:second-service)
+                        thrift.test:thrift-test)))
+      (thrift:serve (puri:parse-uri (concatenate 'string
+                                                 "thrift://127.0.0.1:"
+                                                 port))
+                    services
+                    :framed framed
+                    :multiplexed multiplexed)))
+  (clon:exit))
+
+(clon:dump "TestServer" main)
diff --git a/test/cl/tests.lisp b/test/cl/tests.lisp
new file mode 100644
index 0000000..c5035fd
--- /dev/null
+++ b/test/cl/tests.lisp
@@ -0,0 +1,240 @@
+(in-package #:thrift-cross)
+
+;;;; Licensed under the Apache License, Version 2.0 (the "License");
+;;;; you may not use this file except in compliance with the License.
+;;;; You may obtain a copy of the License at
+;;;;
+;;;;     http://www.apache.org/licenses/LICENSE-2.0
+;;;;
+;;;; Unless required by applicable law or agreed to in writing, software
+;;;; distributed under the License is distributed on an "AS IS" BASIS,
+;;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;;;; See the License for the specific language governing permissions and
+;;;; limitations under the License.
+
+;;;; The tests here only make sense in the context of a TestServer
+;;;; running and the dynamic variable thrift-cross::*prot*
+;;;; being set with a client connection to the TestServer. Normally,
+;;;; this is handled in make-test-client.lisp.
+
+
+;;; Standard Thrift cross-test error codes
+(defparameter *test_basetypes* 1)
+(defparameter *test_structs* 2)
+(defparameter *test_containers* 4)
+(defparameter *test_exceptions* 8)
+(defparameter *test_unknown* 64)
+(defparameter *test_timeout* 128)
+
+(defun cross-test (&key (multiplexed nil))
+  "The main cross-test runner."
+  (let ((result nil))
+    (handler-case
+        (progn
+          (unless (run-package-tests :package :base-types)
+            (pushnew *test_basetypes* result))
+          (unless (run-package-tests :package :structs)
+            (pushnew *test_structs* result))
+          (unless (run-package-tests :package :containers)
+            (pushnew *test_containers* result))
+          (unless (run-package-tests :package :exceptions)
+            (pushnew *test_exceptions* result))
+          (unless (run-package-tests :package :misc)
+            (pushnew *test_unknown* result))
+
+          ;; It doesn't seem like anyone actually uses
+          ;; the second test service when testing multiplexing,
+          ;; so this would fail against servers in other
+          ;; languages. For now, anyway.
+          #+(or)
+          (when multiplexed
+            (unless (run-package-tests :package :multiplex)
+              (pushnew *test_unknown* result))))
+      (error (e) (pushnew *test_unknown* result)))
+    (apply #'+ result)))
+
+(fiasco:define-test-package #:base-types)
+
+(in-package #:base-types)
+
+(defconstant *lang-string* "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語")
+
+(defparameter *trick-string* (format nil "quote: \" backslash: \\ newline: ~% backspace: ~C ~
+                                          tab: ~T junk: !@#$%&()(&%$#{}{}<><><" #\backspace))
+
+(defconstant *binary-sequence* #(128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127))
+
+(deftest void-test ()
+  (is (null (thrift.test.thrift-test:test-void thrift-cross::*prot*))))
+
+(deftest boolean-test ()
+  (is (thrift.test.thrift-test:test-bool thrift-cross::*prot* t))
+  (is (not (thrift.test.thrift-test:test-bool thrift-cross::*prot* nil))))
+
+(deftest integer-test ()
+  (is (= (thrift.test.thrift-test:test-byte thrift-cross::*prot* 127) 127))
+  (is (= (thrift.test.thrift-test:test-byte thrift-cross::*prot* -128) -128))
+  (is (= (thrift.test.thrift-test:test-byte thrift-cross::*prot* 42) 42))
+  (is (= (thrift.test.thrift-test:test-byte thrift-cross::*prot* 0) 0))
+  (is (= (thrift.test.thrift-test:test-i32 thrift-cross::*prot* 0) 0))
+  (is (= (thrift.test.thrift-test:test-i32 thrift-cross::*prot* 2147483647) 2147483647))
+  (is (= (thrift.test.thrift-test:test-i32 thrift-cross::*prot* -2147483648) -2147483648))
+  (is (= (thrift.test.thrift-test:test-i64 thrift-cross::*prot* 0) 0))
+  (is (= (thrift.test.thrift-test:test-i64 thrift-cross::*prot* 9223372036854775807) 9223372036854775807))
+  (is (= (thrift.test.thrift-test:test-i64 thrift-cross::*prot* -9223372036854775808) -9223372036854775808)))
+
+(deftest double-test ()
+  (is (= (thrift.test.thrift-test:test-double thrift-cross::*prot* 0.0) 0))
+  (is (= (thrift.test.thrift-test:test-double thrift-cross::*prot* 42.0) 42))
+  (is (= (thrift.test.thrift-test:test-double thrift-cross::*prot* -555.0) -555))
+  (is (= (thrift.test.thrift-test:test-double thrift-cross::*prot* -52.3678) -52.3678)))
+
+(deftest string-test ()
+  (is (string= (thrift.test.thrift-test:test-string thrift-cross::*prot* "") ""))
+  (is (string= (thrift.test.thrift-test:test-string thrift-cross::*prot* "(defun botsbuildbots () (botsbuilsbots))")
+               "(defun botsbuildbots () (botsbuilsbots))"))
+  (is (string= (thrift.test.thrift-test:test-string thrift-cross::*prot* *lang-string*) *lang-string*))
+  (is (string= (thrift.test.thrift-test:test-string thrift-cross::*prot* *trick-string*) *trick-string*)))
+
+(deftest binary-test ()
+  (is (equalp (thrift.test.thrift-test:test-binary thrift-cross::*prot* #()) #()))
+  (is (equalp (thrift.test.thrift-test:test-binary thrift-cross::*prot* *binary-sequence*) *binary-sequence*)))
+
+(deftest enum-test ()
+  (is (= (thrift.test.thrift-test:test-enum thrift-cross::*prot* thrift.test:numberz.five) thrift.test:numberz.five))
+  (is (= (thrift.test.thrift-test:test-enum thrift-cross::*prot* thrift.test:numberz.eight) thrift.test:numberz.eight))
+  (is (= (thrift.test.thrift-test:test-enum thrift-cross::*prot* thrift.test:numberz.one) thrift.test:numberz.one)))
+
+(deftest typedef-test ()
+  (is (= (thrift.test.thrift-test:test-typedef thrift-cross::*prot* 309858235082523) 309858235082523)))
+
+(fiasco:define-test-package #:structs)
+
+(in-package #:structs)
+
+(defparameter *test-struct* (thrift.test:make-xtruct :string-thing "Hell is empty."
+                                                     :byte-thing -2
+                                                     :i32-thing 42
+                                                     :i64-thing 42424242))
+
+(defparameter *test-nest* (thrift.test:make-xtruct2 :byte-thing 42
+                                                    :struct-thing *test-struct*
+                                                    :i32-thing -42))
+
+(deftest struct-test ()
+  (let ((rec-struct (thrift.test.thrift-test:test-struct thrift-cross::*prot* *test-struct*)))
+    (is (string= (thrift.test:xtruct-string-thing *test-struct*)
+                 (thrift.test:xtruct-string-thing rec-struct)))
+    (is (= (thrift.test:xtruct-byte-thing *test-struct*)
+           (thrift.test:xtruct-byte-thing rec-struct)))
+    (is (= (thrift.test:xtruct-i32-thing *test-struct*)
+           (thrift.test:xtruct-i32-thing rec-struct)))
+    (is (= (thrift.test:xtruct-i64-thing *test-struct*)
+           (thrift.test:xtruct-i64-thing rec-struct)))))
+
+(deftest nest-test ()
+  (let* ((rec-nest (thrift.test.thrift-test:test-nest thrift-cross::*prot* *test-nest*))
+         (rec-struct (thrift.test:xtruct2-struct-thing rec-nest)))
+    (is (string= (thrift.test:xtruct-string-thing *test-struct*)
+                 (thrift.test:xtruct-string-thing rec-struct)))
+    (is (= (thrift.test:xtruct-byte-thing *test-struct*)
+           (thrift.test:xtruct-byte-thing rec-struct)))
+    (is (= (thrift.test:xtruct-i32-thing *test-struct*)
+           (thrift.test:xtruct-i32-thing rec-struct)))
+    (is (= (thrift.test:xtruct-i64-thing *test-struct*)
+           (thrift.test:xtruct-i64-thing rec-struct)))
+    (is (= (thrift.test:xtruct2-byte-thing *test-nest*)
+           (thrift.test:xtruct2-byte-thing rec-nest)))
+    (is (= (thrift.test:xtruct2-i32-thing *test-nest*)
+           (thrift.test:xtruct2-i32-thing rec-nest)))))
+
+(fiasco:define-test-package #:containers)
+
+(in-package #:containers)
+
+(deftest list-test ()
+  (is (null (thrift.test.thrift-test:test-list thrift-cross::*prot* nil)))
+  (is (equal (thrift.test.thrift-test:test-list thrift-cross::*prot* '(42 -42 0 5)) '(42 -42 0 5))))
+
+(deftest set-test ()
+  (is (null (thrift.test.thrift-test:test-set thrift-cross::*prot* nil)))
+  (is (equal (sort (thrift.test.thrift-test:test-set thrift-cross::*prot* (list 42 -42 0 5)) #'<)
+             '(-42 0 5 42))))
+
+(defun map= (map1 map2 &key (car-predicate #'equal) (cdr-predicate #'equal))
+  "Compare two assoc maps according to the predicates given."
+  (not (set-exclusive-or map1 map2 :test (lambda (el1 el2)
+                                           (and (funcall car-predicate
+                                                         (car el1)
+                                                         (car el2))
+                                                (funcall cdr-predicate
+                                                         (cdr el1)
+                                                         (cdr el2)))))))
+
+(deftest map-test ()
+  (is (null (thrift.test.thrift-test:test-map thrift-cross::*prot* nil)))
+  (is (map= (thrift.test.thrift-test:test-map thrift-cross::*prot* '((0 . 1) (42 . -42) (5 . 5)))
+            '((0 . 1) (42 . -42) (5 . 5))))
+  (is (map= (thrift.test.thrift-test:test-map-map thrift-cross::*prot* 42)
+            '((-4 . ((-4 . -4) (-3 . -3) (-2 . -2) (-1 . -1)))
+              (4 . ((1 . 1) (2 . 2) (3 . 3) (4 . 4))))
+            :cdr-predicate #'map=)))
+
+(fiasco:define-test-package #:exceptions)
+
+(in-package #:exceptions)
+
+(defun test-xception (expected-code expected-message function &rest args)
+  "A helper function to test whether xception is signalled, and whether its fields have the expected values."
+  (handler-case (progn (apply function args)
+                       nil)
+    (thrift.test:xception (ex) (and (= (thrift.test::xception-error-code ex) expected-code)
+                                    (string= (thrift.test::xception-message ex) expected-message)))))
+
+(defun test-xception2 (expected-code expected-message function &rest args)
+  "A helper function to test whether xception2 is signalled, and whether its fields have the expected values."
+  (handler-case (progn (apply function args)
+                       nil)
+    (thrift.test:xception2 (ex) (and (= (thrift.test::xception2-error-code ex) expected-code)
+                                     (string= (thrift.test::xtruct-string-thing
+                                               (thrift.test::xception2-struct-thing ex))
+                                              expected-message)))))
+
+(deftest exception-test ()
+  (is (test-xception 1001 "Xception" #'thrift.test.thrift-test:test-exception thrift-cross::*prot* "Xception"))
+  (signals thrift:application-error (thrift.test.thrift-test:test-exception thrift-cross::*prot* "TException"))
+  (finishes (thrift.test.thrift-test:test-exception thrift-cross::*prot* "success")))
+
+(deftest multi-exception-test ()
+  (is (test-xception 1001
+                     "This is an Xception"
+                     #'thrift.test.thrift-test:test-multi-exception
+                     thrift-cross::*prot*
+                     "Xception"
+                     "meaningless"))
+  (is (test-xception2 2002
+                      "This is an Xception2"
+                      #'thrift.test.thrift-test:test-multi-exception
+                      thrift-cross::*prot*
+                      "Xception2"
+                      "meaningless too!"))
+  (is (string= "foobar" (thrift.test:xtruct-string-thing
+                         (thrift.test.thrift-test:test-multi-exception thrift-cross::*prot*
+                                                           "success!"
+                                                           "foobar")))))
+
+(fiasco:define-test-package #:misc)
+
+(in-package #:misc)
+
+(deftest oneway-test ()
+  (is (null (thrift.test.thrift-test:test-oneway thrift-cross::*prot* 1))))
+
+(fiasco:define-test-package #:multiplex)
+
+(in-package #:multiplex)
+
+(deftest multiplex-test ()
+  ;; Removed from the IDL definition.
+  ;; (finishes (thrift.test.second-service:blah-blah thrift-cross::*prot*))
+  (is (string= "asd" (thrift.test.second-service:secondtest-string thrift-cross::*prot* "asd"))))
diff --git a/test/cpp/CMakeLists.txt b/test/cpp/CMakeLists.txt
new file mode 100755
index 0000000..95d2991
--- /dev/null
+++ b/test/cpp/CMakeLists.txt
@@ -0,0 +1,92 @@
+#
+# 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.
+#
+
+# Contains the thrift specific LINK_AGAINST_THRIFT_LIBRARY
+include(ThriftMacros)
+
+include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
+
+find_package(OpenSSL REQUIRED)
+include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
+
+find_package(Libevent REQUIRED)  # Libevent comes with CMake support from upstream
+include_directories(SYSTEM ${LIBEVENT_INCLUDE_DIRS})
+
+find_package(ZLIB REQUIRED)
+include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
+
+#Make sure gen-cpp files can be included
+include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen-cpp")
+include_directories("${PROJECT_SOURCE_DIR}/lib/cpp/src")
+
+set(crosstestgencpp_SOURCES
+    gen-cpp/SecondService.cpp
+    gen-cpp/ThriftTest.cpp
+    gen-cpp/ThriftTest_types.cpp
+    gen-cpp/ThriftTest_constants.cpp
+    src/ThriftTest_extras.cpp
+)
+add_library(crosstestgencpp STATIC ${crosstestgencpp_SOURCES})
+LINK_AGAINST_THRIFT_LIBRARY(crosstestgencpp thrift)
+
+set(crossstressgencpp_SOURCES
+    gen-cpp/Service.cpp
+    gen-cpp/StressTest_types.cpp
+    gen-cpp/StressTest_constants.cpp
+)
+add_library(crossstressgencpp STATIC ${crossstressgencpp_SOURCES})
+LINK_AGAINST_THRIFT_LIBRARY(crossstressgencpp thrift)
+
+add_executable(TestServer src/TestServer.cpp)
+target_link_libraries(TestServer crosstestgencpp ${Boost_LIBRARIES} ${LIBEVENT_LIB})
+LINK_AGAINST_THRIFT_LIBRARY(TestServer thrift)
+LINK_AGAINST_THRIFT_LIBRARY(TestServer thriftnb)
+LINK_AGAINST_THRIFT_LIBRARY(TestServer thriftz)
+
+add_executable(TestClient src/TestClient.cpp)
+target_link_libraries(TestClient crosstestgencpp ${Boost_LIBRARIES} ${LIBEVENT_LIB})
+LINK_AGAINST_THRIFT_LIBRARY(TestClient thrift)
+LINK_AGAINST_THRIFT_LIBRARY(TestClient thriftnb)
+LINK_AGAINST_THRIFT_LIBRARY(TestClient thriftz)
+
+add_executable(StressTest src/StressTest.cpp)
+target_link_libraries(StressTest crossstressgencpp ${Boost_LIBRARIES} ${LIBEVENT_LIB})
+LINK_AGAINST_THRIFT_LIBRARY(StressTest thrift)
+LINK_AGAINST_THRIFT_LIBRARY(StressTest thriftnb)
+add_test(NAME StressTest COMMAND StressTest)
+
+add_executable(StressTestNonBlocking src/StressTestNonBlocking.cpp)
+target_link_libraries(StressTestNonBlocking crossstressgencpp ${Boost_LIBRARIES} ${LIBEVENT_LIB})
+LINK_AGAINST_THRIFT_LIBRARY(StressTestNonBlocking thrift)
+LINK_AGAINST_THRIFT_LIBRARY(StressTestNonBlocking thriftnb)
+LINK_AGAINST_THRIFT_LIBRARY(StressTestNonBlocking thriftz)
+add_test(NAME StressTestNonBlocking COMMAND StressTestNonBlocking)
+
+#
+# Common thrift code generation rules
+#
+
+add_custom_command(OUTPUT gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest.h gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp
+    COMMAND ${THRIFT_COMPILER} --gen cpp:templates,cob_style -r ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
+)
+
+add_custom_command(OUTPUT gen-cpp/StressTest_types.cpp gen-cpp/StressTest_constants.cpp gen-cpp/Service.cpp
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/StressTest.thrift
+)
diff --git a/test/cpp/Makefile.am b/test/cpp/Makefile.am
index ec4ba99..e8be80a 100755
--- a/test/cpp/Makefile.am
+++ b/test/cpp/Makefile.am
@@ -16,15 +16,30 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-.NOTPARALLEL:
+AUTOMAKE_OPTIONS = subdir-objects serial-tests
+
+BUILT_SOURCES = gen-cpp/ThriftTest.cpp \
+                gen-cpp/ThriftTest_types.cpp \
+                gen-cpp/ThriftTest_constants.cpp \
+                gen-cpp/SecondService.cpp \
+                gen-cpp/StressTest_types.cpp \
+                gen-cpp/StressTest_constants.cpp \
+                gen-cpp/Service.cpp
+
 noinst_LTLIBRARIES = libtestgencpp.la libstresstestgencpp.la
 nodist_libtestgencpp_la_SOURCES = \
+	gen-cpp/SecondService.cpp \
+	gen-cpp/SecondService.h \
+	gen-cpp/SecondService.tcc \
 	gen-cpp/ThriftTest_constants.cpp \
-	gen-cpp/ThriftTest_types.cpp \
 	gen-cpp/ThriftTest_constants.h \
+	gen-cpp/ThriftTest_types.cpp \
 	gen-cpp/ThriftTest_types.h \
 	gen-cpp/ThriftTest_types.tcc \
-	gen-cpp/ThriftTest.tcc
+	gen-cpp/ThriftTest.cpp \
+	gen-cpp/ThriftTest.h \
+	gen-cpp/ThriftTest.tcc \
+	src/ThriftTest_extras.cpp
 
 libtestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la
 
@@ -38,6 +53,8 @@
 
 libstresstestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la
 
+precross: TestServer TestClient
+
 check_PROGRAMS = \
 	TestServer \
 	TestClient \
@@ -56,7 +73,7 @@
 	$(top_builddir)/lib/cpp/libthrift.la \
 	$(top_builddir)/lib/cpp/libthriftz.la \
 	$(top_builddir)/lib/cpp/libthriftnb.la \
-	-levent -lboost_program_options
+	-levent -lboost_program_options -lboost_system -lboost_filesystem $(ZLIB_LIBS)
 
 TestClient_SOURCES = \
 	src/TestClient.cpp
@@ -66,7 +83,7 @@
 	$(top_builddir)/lib/cpp/libthrift.la \
 	$(top_builddir)/lib/cpp/libthriftz.la \
 	$(top_builddir)/lib/cpp/libthriftnb.la \
-	-levent -lboost_program_options
+	-levent -lboost_program_options -lboost_system -lboost_filesystem $(ZLIB_LIBS)
 
 StressTest_SOURCES = \
 	src/StressTest.cpp
@@ -85,28 +102,24 @@
 #
 # Common thrift code generation rules
 #
-THRIFT = $(top_builddir)/compiler/cpp/thrift
-
-gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp: $(top_srcdir)/test/ThriftTest.thrift
+gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/SecondService.tcc: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT)
 	$(THRIFT) --gen cpp:templates,cob_style -r $<
 
-gen-cpp/ThriftTest.cpp gen-cpp/StressTest_types.cpp gen-cpp/StressTest_constants.cpp: $(top_srcdir)/test/StressTest.thrift
+gen-cpp/StressTest_types.cpp gen-cpp/StressTest_constants.cpp gen-cpp/Service.cpp: $(top_srcdir)/test/StressTest.thrift $(THRIFT)
 	$(THRIFT) --gen cpp $<
 
-INCLUDES = \
-	-I$(top_srcdir)/lib/cpp/src -Igen-cpp
-
-AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS)
-AM_CXXFLAGS = -Wall
-AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS)
+AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -Igen-cpp
+AM_CXXFLAGS = -Wall -Wextra -pedantic -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
+AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS) $(ZLIB_LIBS)
 
 clean-local:
-	$(RM) -r gen-cpp
+	$(RM) gen-cpp/*
+
+style-local:
+	$(CPPSTYLE_CMD)
 
 EXTRA_DIST = \
 	src/TestClient.cpp \
 	src/TestServer.cpp \
 	src/StressTest.cpp \
-	src/StressTestNonBlocking.cpp \
-	realloc/realloc_test.c \
-	realloc/Makefile
+	src/StressTestNonBlocking.cpp
diff --git a/test/cpp/realloc/Makefile b/test/cpp/realloc/Makefile
deleted file mode 100644
index f89bbb3..0000000
--- a/test/cpp/realloc/Makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-# This probably should not go into "make check", because it is an experiment,
-# not a test.  Specifically, it is meant to determine how likely realloc is
-# to avoid a copy.  This is poorly documented.
-
-run: realloc_test
-	for it in 1 4 64 ; do \
-		for nb in 1 8 64 512 ; do \
-			for mins in 64 512 ; do \
-				for maxs in 2048 262144 ; do \
-					for db in 8 64 ; do \
-						./realloc_test $$nb $$mins $$maxs $$db $$it \
-					; done \
-				; done \
-			; done \
-		; done \
-	; done \
-	> raw_stats
-
-CFLAGS = -Wall -g -std=c99
-LDLIBS = -ldl
-realloc_test: realloc_test.c
diff --git a/test/cpp/realloc/realloc_test.c b/test/cpp/realloc/realloc_test.c
deleted file mode 100644
index f9763ad..0000000
--- a/test/cpp/realloc/realloc_test.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#define _GNU_SOURCE
-#include <stdlib.h>
-#include <stdio.h>
-#include <time.h>
-#include <dlfcn.h>
-
-int copies;
-int non_copies;
-
-void *realloc(void *ptr, size_t size) {
-  static void *(*real_realloc)(void*, size_t) = NULL;
-  if (real_realloc == NULL) {
-    real_realloc = (void* (*) (void*, size_t)) dlsym(RTLD_NEXT, "realloc");
-  }
-
-  void *ret_ptr = (*real_realloc)(ptr, size);
-
-  if (ret_ptr == ptr) {
-    non_copies++;
-  } else {
-    copies++;
-  }
-
-  return ret_ptr;
-}
-
-
-struct TMemoryBuffer {
-  void* ptr;
-  int size;
-};
-
-int main(int argc, char *argv[]) {
-  int num_buffers;
-  int init_size;
-  int max_size;
-  int doublings;
-  int iterations;
-
-  if (argc < 6 ||
-      argc > 7 ||
-      (num_buffers = atoi(argv[1])) == 0 ||
-      (init_size = atoi(argv[2])) == 0 ||
-      (max_size = atoi(argv[3])) == 0 ||
-      init_size > max_size ||
-      (iterations = atoi(argv[4])) == 0 ||
-      (doublings = atoi(argv[5])) == 0 ||
-      (argc == 7 && atoi(argv[6]) == 0)) {
-    fprintf(stderr, "usage: realloc_test <num_buffers> <init_size> <max_size> <doublings> <iterations> [seed]\n");
-    exit(EXIT_FAILURE);
-  }
-
-  for ( int i = 0 ; i < argc ; i++ ) {
-    printf("%s ", argv[i]);
-  }
-  printf("\n");
-
-  if (argc == 7) {
-    srand(atoi(argv[6]));
-  } else {
-    srand(time(NULL));
-  }
-
-  struct TMemoryBuffer* buffers = calloc(num_buffers, sizeof(*buffers));
-  if (buffers == NULL) abort();
-
-  for ( int i = 0 ; i < num_buffers ; i++ ) {
-    buffers[i].size = max_size;
-  }
-
-  while (iterations --> 0) {
-    for ( int i = 0 ; i < doublings * num_buffers ; i++ ) {
-      struct TMemoryBuffer* buf = &buffers[rand() % num_buffers];
-      buf->size *= 2;
-      if (buf->size <= max_size) {
-        buf->ptr = realloc(buf->ptr, buf->size);
-      } else {
-        free(buf->ptr);
-        buf->size = init_size;
-        buf->ptr = malloc(buf->size);
-      }
-      if (buf->ptr == NULL) abort();
-    }
-  }
-
-  printf("Non-copied %d/%d (%.2f%%)\n", non_copies, copies + non_copies, 100.0 * non_copies / (copies + non_copies));
-  return 0;
-}
diff --git a/test/cpp/src/StressTest.cpp b/test/cpp/src/StressTest.cpp
index 7da3db0..585f89a 100644
--- a/test/cpp/src/StressTest.cpp
+++ b/test/cpp/src/StressTest.cpp
@@ -33,15 +33,16 @@
 #include <thrift/TLogging.h>
 
 #include "Service.h"
-
 #include <iostream>
 #include <set>
 #include <stdexcept>
 #include <sstream>
 #include <map>
+#if _WIN32
+#include <thrift/windows/TWinsockSingleton.h>
+#endif
 
 using namespace std;
-using namespace boost;
 
 using namespace apache::thrift;
 using namespace apache::thrift::protocol;
@@ -52,23 +53,18 @@
 using namespace test::stress;
 
 struct eqstr {
-  bool operator()(const char* s1, const char* s2) const {
-    return strcmp(s1, s2) == 0;
-  }
+  bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) == 0; }
 };
 
 struct ltstr {
-  bool operator()(const char* s1, const char* s2) const {
-    return strcmp(s1, s2) < 0;
-  }
+  bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; }
 };
 
-
 // typedef hash_map<const char*, int, hash<const char*>, eqstr> count_map;
 typedef map<const char*, int, ltstr> count_map;
 
 class Server : public ServiceIf {
- public:
+public:
   Server() {}
 
   void count(const char* method) {
@@ -87,67 +83,92 @@
     return counts_;
   }
 
-  int8_t echoByte(const int8_t arg) {return arg;}
-  int32_t echoI32(const int32_t arg) {return arg;}
-  int64_t echoI64(const int64_t arg) {return arg;}
-  void echoString(string& out, const string &arg) {
+  int8_t echoByte(const int8_t arg) { return arg; }
+  int32_t echoI32(const int32_t arg) { return arg; }
+  int64_t echoI64(const int64_t arg) { return arg; }
+  void echoString(string& out, const string& arg) {
     if (arg != "hello") {
       T_ERROR_ABORT("WRONG STRING (%s)!!!!", arg.c_str());
     }
     out = arg;
   }
-  void echoList(vector<int8_t> &out, const vector<int8_t> &arg) { out = arg; }
-  void echoSet(set<int8_t> &out, const set<int8_t> &arg) { out = arg; }
-  void echoMap(map<int8_t, int8_t> &out, const map<int8_t, int8_t> &arg) { out = arg; }
+  void echoList(vector<int8_t>& out, const vector<int8_t>& arg) { out = arg; }
+  void echoSet(set<int8_t>& out, const set<int8_t>& arg) { out = arg; }
+  void echoMap(map<int8_t, int8_t>& out, const map<int8_t, int8_t>& arg) { out = arg; }
 
 private:
   count_map counts_;
   Mutex lock_;
-
 };
 
-class ClientThread: public Runnable {
+enum TransportOpenCloseBehavior {
+  OpenAndCloseTransportInThread,
+  DontOpenAndCloseTransportInThread
+};
+class ClientThread : public Runnable {
 public:
-
-  ClientThread(boost::shared_ptr<TTransport>transport, boost::shared_ptr<ServiceClient> client, Monitor& monitor, size_t& workerCount, size_t loopCount, TType loopType) :
-    _transport(transport),
-    _client(client),
-    _monitor(monitor),
-    _workerCount(workerCount),
-    _loopCount(loopCount),
-    _loopType(loopType)
-  {}
+  ClientThread(std::shared_ptr<TTransport> transport,
+               std::shared_ptr<ServiceIf> client,
+               Monitor& monitor,
+               size_t& workerCount,
+               size_t loopCount,
+               TType loopType,
+               TransportOpenCloseBehavior behavior)
+    : _transport(transport),
+      _client(client),
+      _monitor(monitor),
+      _workerCount(workerCount),
+      _loopCount(loopCount),
+      _loopType(loopType),
+      _behavior(behavior) {}
 
   void run() {
 
     // Wait for all worker threads to start
 
-    {Synchronized s(_monitor);
-      while(_workerCount == 0) {
+    {
+      Synchronized s(_monitor);
+      while (_workerCount == 0) {
         _monitor.wait();
       }
     }
 
     _startTime = Util::currentTime();
+    if(_behavior == OpenAndCloseTransportInThread) {
+      _transport->open();
+    }
 
-    _transport->open();
-
-    switch(_loopType) {
-    case T_VOID: loopEchoVoid(); break;
-    case T_BYTE: loopEchoByte(); break;
-    case T_I32: loopEchoI32(); break;
-    case T_I64: loopEchoI64(); break;
-    case T_STRING: loopEchoString(); break;
-    default: cerr << "Unexpected loop type" << _loopType << endl; break;
+    switch (_loopType) {
+    case T_VOID:
+      loopEchoVoid();
+      break;
+    case T_BYTE:
+      loopEchoByte();
+      break;
+    case T_I32:
+      loopEchoI32();
+      break;
+    case T_I64:
+      loopEchoI64();
+      break;
+    case T_STRING:
+      loopEchoString();
+      break;
+    default:
+      cerr << "Unexpected loop type" << _loopType << endl;
+      break;
     }
 
     _endTime = Util::currentTime();
 
-    _transport->close();
+    if(_behavior == OpenAndCloseTransportInThread) {
+      _transport->close();
+    }
 
     _done = true;
 
-    {Synchronized s(_monitor);
+    {
+      Synchronized s(_monitor);
 
       _workerCount--;
 
@@ -168,7 +189,8 @@
     for (size_t ix = 0; ix < _loopCount; ix++) {
       int8_t arg = 1;
       int8_t result;
-      result =_client->echoByte(arg);
+      result = _client->echoByte(arg);
+      (void)result;
       assert(result == arg);
     }
   }
@@ -177,7 +199,8 @@
     for (size_t ix = 0; ix < _loopCount; ix++) {
       int32_t arg = 1;
       int32_t result;
-      result =_client->echoI32(arg);
+      result = _client->echoI32(arg);
+      (void)result;
       assert(result == arg);
     }
   }
@@ -186,7 +209,8 @@
     for (size_t ix = 0; ix < _loopCount; ix++) {
       int64_t arg = 1;
       int64_t result;
-      result =_client->echoI64(arg);
+      result = _client->echoI64(arg);
+      (void)result;
       assert(result == arg);
     }
   }
@@ -200,8 +224,8 @@
     }
   }
 
-  boost::shared_ptr<TTransport> _transport;
-  boost::shared_ptr<ServiceClient> _client;
+  std::shared_ptr<TTransport> _transport;
+  std::shared_ptr<ServiceIf> _client;
   Monitor& _monitor;
   size_t& _workerCount;
   size_t _loopCount;
@@ -210,18 +234,41 @@
   int64_t _endTime;
   bool _done;
   Monitor _sleep;
+  TransportOpenCloseBehavior _behavior;
 };
 
+class TStartObserver : public apache::thrift::server::TServerEventHandler {
+public:
+  TStartObserver() : awake_(false) {}
+  virtual void preServe() {
+    apache::thrift::concurrency::Synchronized s(m_);
+    awake_ = true;
+    m_.notifyAll();
+  }
+  void waitForService() {
+    apache::thrift::concurrency::Synchronized s(m_);
+    while (!awake_)
+      m_.waitForever();
+  }
 
-int main(int argc, char **argv) {
+private:
+  apache::thrift::concurrency::Monitor m_;
+  bool awake_;
+};
+
+int main(int argc, char** argv) {
+#if _WIN32
+  transport::TWinsockSingleton::create();
+#endif
 
   int port = 9091;
+  string clientType = "regular";
   string serverType = "thread-pool";
   string protocolType = "binary";
   size_t workerCount = 4;
   size_t clientCount = 20;
   size_t loopCount = 50000;
-  TType loopType  = T_VOID;
+  TType loopType = T_VOID;
   string callName = "echoVoid";
   bool runServer = true;
   bool logRequests = false;
@@ -230,28 +277,34 @@
 
   ostringstream usage;
 
-  usage <<
-    argv[0] << " [--port=<port number>] [--server] [--server-type=<server-type>] [--protocol-type=<protocol-type>] [--workers=<worker-count>] [--clients=<client-count>] [--loop=<loop-count>]" << endl <<
-    "\tclients        Number of client threads to create - 0 implies no clients, i.e. server only.  Default is " << clientCount << endl <<
-    "\thelp           Prints this help text." << endl <<
-    "\tcall           Service method to call.  Default is " << callName << endl <<
-    "\tloop           The number of remote thrift calls each client makes.  Default is " << loopCount << endl <<
-    "\tport           The port the server and clients should bind to for thrift network connections.  Default is " << port << endl <<
-    "\tserver         Run the Thrift server in this process.  Default is " << runServer << endl <<
-    "\tserver-type    Type of server, \"simple\" or \"thread-pool\".  Default is " << serverType << endl <<
-    "\tprotocol-type  Type of protocol, \"binary\", \"ascii\", or \"xml\".  Default is " << protocolType << endl <<
-    "\tlog-request    Log all request to ./requestlog.tlog. Default is " << logRequests << endl <<
-    "\treplay-request Replay requests from log file (./requestlog.tlog) Default is " << replayRequests << endl <<
-    "\tworkers        Number of thread pools workers.  Only valid for thread-pool server type.  Default is " << workerCount << endl;
+  usage << argv[0] << " [--port=<port number>] [--server] [--server-type=<server-type>] "
+                      "[--protocol-type=<protocol-type>] [--workers=<worker-count>] "
+                      "[--clients=<client-count>] [--loop=<loop-count>] "
+                      "[--client-type=<client-type>]" << endl
+        << "\tclients        Number of client threads to create - 0 implies no clients, i.e. "
+                            "server only.  Default is " << clientCount << endl
+        << "\thelp           Prints this help text." << endl
+        << "\tcall           Service method to call.  Default is " << callName << endl
+        << "\tloop           The number of remote thrift calls each client makes.  Default is " << loopCount << endl
+        << "\tport           The port the server and clients should bind to "
+                            "for thrift network connections.  Default is " << port << endl
+        << "\tserver         Run the Thrift server in this process.  Default is " << runServer << endl
+        << "\tserver-type    Type of server, \"simple\" or \"thread-pool\".  Default is " << serverType << endl
+        << "\tprotocol-type  Type of protocol, \"binary\", \"ascii\", or \"xml\".  Default is " << protocolType << endl
+        << "\tlog-request    Log all request to ./requestlog.tlog. Default is " << logRequests << endl
+        << "\treplay-request Replay requests from log file (./requestlog.tlog) Default is " << replayRequests << endl
+        << "\tworkers        Number of thread pools workers.  Only valid "
+                            "for thread-pool server type.  Default is " << workerCount << endl
+        << "\tclient-type    Type of client, \"regular\" or \"concurrent\".  Default is " << clientType << endl
+        << endl;
 
-
-  map<string, string>  args;
+  map<string, string> args;
 
   for (int ix = 1; ix < argc; ix++) {
 
     string arg(argv[ix]);
 
-    if (arg.compare(0,2, "--") == 0) {
+    if (arg.compare(0, 2, "--") == 0) {
 
       size_t end = arg.find_first_of("=", 2);
 
@@ -263,7 +316,7 @@
         args[key] = "true";
       }
     } else {
-      throw invalid_argument("Unexcepted command line token: "+arg);
+      throw invalid_argument("Unexcepted command line token: " + arg);
     }
   }
 
@@ -313,145 +366,189 @@
 
       } else {
 
-        throw invalid_argument("Unknown server type "+serverType);
+        throw invalid_argument("Unknown server type " + serverType);
       }
     }
+    if (!args["client-type"].empty()) {
+      clientType = args["client-type"];
 
+      if (clientType == "regular") {
+
+      } else if (clientType == "concurrent") {
+
+      } else {
+
+        throw invalid_argument("Unknown client type " + clientType);
+      }
+    }
     if (!args["workers"].empty()) {
       workerCount = atoi(args["workers"].c_str());
     }
 
-  } catch(std::exception& e) {
+  } catch (std::exception& e) {
     cerr << e.what() << endl;
-    cerr << usage;
+    cerr << usage.str();
   }
 
-  boost::shared_ptr<PlatformThreadFactory> threadFactory = boost::shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory());
+  std::shared_ptr<PlatformThreadFactory> threadFactory
+      = std::shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory());
 
   // Dispatcher
-  boost::shared_ptr<Server> serviceHandler(new Server());
+  std::shared_ptr<Server> serviceHandler(new Server());
 
   if (replayRequests) {
-    boost::shared_ptr<Server> serviceHandler(new Server());
-    boost::shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler));
+    std::shared_ptr<Server> serviceHandler(new Server());
+    std::shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler));
 
     // Transports
-    boost::shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath));
+    std::shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath));
     fileTransport->setChunkSize(2 * 1024 * 1024);
     fileTransport->setMaxEventSize(1024 * 16);
     fileTransport->seekToEnd();
 
     // Protocol Factory
-    boost::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+    std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
 
-    TFileProcessor fileProcessor(serviceProcessor,
-                                 protocolFactory,
-                                 fileTransport);
+    TFileProcessor fileProcessor(serviceProcessor, protocolFactory, fileTransport);
 
     fileProcessor.process(0, true);
     exit(0);
   }
 
-
   if (runServer) {
 
-    boost::shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler));
+    std::shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler));
 
     // Transport
-    boost::shared_ptr<TServerSocket> serverSocket(new TServerSocket(port));
+    std::shared_ptr<TServerSocket> serverSocket(new TServerSocket(port));
 
     // Transport Factory
-    boost::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
+    std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
 
     // Protocol Factory
-    boost::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+    std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
 
     if (logRequests) {
       // initialize the log file
-      boost::shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath));
+      std::shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath));
       fileTransport->setChunkSize(2 * 1024 * 1024);
       fileTransport->setMaxEventSize(1024 * 16);
 
-      transportFactory =
-        boost::shared_ptr<TTransportFactory>(new TPipedTransportFactory(fileTransport));
+      transportFactory
+          = std::shared_ptr<TTransportFactory>(new TPipedTransportFactory(fileTransport));
     }
 
-    boost::shared_ptr<Thread> serverThread;
+    std::shared_ptr<TServer> server;
 
     if (serverType == "simple") {
 
-      serverThread = threadFactory->newThread(boost::shared_ptr<TServer>(new TSimpleServer(serviceProcessor, serverSocket, transportFactory, protocolFactory)));
+      server.reset(
+          new TSimpleServer(serviceProcessor, serverSocket, transportFactory, protocolFactory));
 
     } else if (serverType == "threaded") {
 
-      serverThread = threadFactory->newThread(boost::shared_ptr<TServer>(new TThreadedServer(serviceProcessor, serverSocket, transportFactory, protocolFactory)));
+      server.reset(
+          new TThreadedServer(serviceProcessor, serverSocket, transportFactory, protocolFactory));
 
     } else if (serverType == "thread-pool") {
 
-      boost::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(workerCount);
+      std::shared_ptr<ThreadManager> threadManager
+          = ThreadManager::newSimpleThreadManager(workerCount);
 
       threadManager->threadFactory(threadFactory);
       threadManager->start();
-      serverThread = threadFactory->newThread(boost::shared_ptr<TServer>(new TThreadPoolServer(serviceProcessor, serverSocket, transportFactory, protocolFactory, threadManager)));
+      server.reset(new TThreadPoolServer(serviceProcessor,
+                                         serverSocket,
+                                         transportFactory,
+                                         protocolFactory,
+                                         threadManager));
     }
 
+    std::shared_ptr<TStartObserver> observer(new TStartObserver);
+    server->setServerEventHandler(observer);
+    std::shared_ptr<Thread> serverThread = threadFactory->newThread(server);
+
     cerr << "Starting the server on port " << port << endl;
 
     serverThread->start();
+    observer->waitForService();
 
     // If we aren't running clients, just wait forever for external clients
-
     if (clientCount == 0) {
       serverThread->join();
     }
   }
 
-  if (clientCount > 0) {
+  if (clientCount > 0) { //FIXME: start here for client type?
 
     Monitor monitor;
 
     size_t threadCount = 0;
 
-    set<boost::shared_ptr<Thread> > clientThreads;
+    set<std::shared_ptr<Thread> > clientThreads;
 
-    if (callName == "echoVoid") { loopType = T_VOID;}
-    else if (callName == "echoByte") { loopType = T_BYTE;}
-    else if (callName == "echoI32") { loopType = T_I32;}
-    else if (callName == "echoI64") { loopType = T_I64;}
-    else if (callName == "echoString") { loopType = T_STRING;}
-    else {throw invalid_argument("Unknown service call "+callName);}
-
-    for (size_t ix = 0; ix < clientCount; ix++) {
-
-      boost::shared_ptr<TSocket> socket(new TSocket("127.0.0.1", port));
-      boost::shared_ptr<TBufferedTransport> bufferedSocket(new TBufferedTransport(socket, 2048));
-      boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(bufferedSocket));
-      boost::shared_ptr<ServiceClient> serviceClient(new ServiceClient(protocol));
-
-      clientThreads.insert(threadFactory->newThread(boost::shared_ptr<ClientThread>(new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType))));
+    if (callName == "echoVoid") {
+      loopType = T_VOID;
+    } else if (callName == "echoByte") {
+      loopType = T_BYTE;
+    } else if (callName == "echoI32") {
+      loopType = T_I32;
+    } else if (callName == "echoI64") {
+      loopType = T_I64;
+    } else if (callName == "echoString") {
+      loopType = T_STRING;
+    } else {
+      throw invalid_argument("Unknown service call " + callName);
     }
 
-    for (std::set<boost::shared_ptr<Thread> >::const_iterator thread = clientThreads.begin(); thread != clientThreads.end(); thread++) {
+    if(clientType == "regular") {
+      for (size_t ix = 0; ix < clientCount; ix++) {
+
+        std::shared_ptr<TSocket> socket(new TSocket("127.0.0.1", port));
+        std::shared_ptr<TBufferedTransport> bufferedSocket(new TBufferedTransport(socket, 2048));
+        std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(bufferedSocket));
+        std::shared_ptr<ServiceClient> serviceClient(new ServiceClient(protocol));
+
+        clientThreads.insert(threadFactory->newThread(std::shared_ptr<ClientThread>(
+            new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType, OpenAndCloseTransportInThread))));
+      }
+    } else if(clientType == "concurrent") {
+      std::shared_ptr<TSocket> socket(new TSocket("127.0.0.1", port));
+      std::shared_ptr<TBufferedTransport> bufferedSocket(new TBufferedTransport(socket, 2048));
+      std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(bufferedSocket));
+      //std::shared_ptr<ServiceClient> serviceClient(new ServiceClient(protocol));
+      std::shared_ptr<ServiceConcurrentClient> serviceClient(new ServiceConcurrentClient(protocol));
+      socket->open();
+      for (size_t ix = 0; ix < clientCount; ix++) {
+        clientThreads.insert(threadFactory->newThread(std::shared_ptr<ClientThread>(
+            new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType, DontOpenAndCloseTransportInThread))));
+      }
+    }
+
+    for (std::set<std::shared_ptr<Thread> >::const_iterator thread = clientThreads.begin();
+         thread != clientThreads.end();
+         thread++) {
       (*thread)->start();
     }
 
     int64_t time00;
     int64_t time01;
 
-    {Synchronized s(monitor);
+    {
+      Synchronized s(monitor);
       threadCount = clientCount;
 
-      cerr << "Launch "<< clientCount << " client threads" << endl;
+      cerr << "Launch " << clientCount << " " << clientType << " client threads" << endl;
 
-      time00 =  Util::currentTime();
+      time00 = Util::currentTime();
 
       monitor.notifyAll();
 
-      while(threadCount > 0) {
+      while (threadCount > 0) {
         monitor.wait();
       }
 
-      time01 =  Util::currentTime();
+      time01 = Util::currentTime();
     }
 
     int64_t firstTime = 9223372036854775807LL;
@@ -461,9 +558,12 @@
     int64_t minTime = 9223372036854775807LL;
     int64_t maxTime = 0;
 
-    for (set<boost::shared_ptr<Thread> >::iterator ix = clientThreads.begin(); ix != clientThreads.end(); ix++) {
+    for (set<std::shared_ptr<Thread> >::iterator ix = clientThreads.begin();
+         ix != clientThreads.end();
+         ix++) {
 
-      boost::shared_ptr<ClientThread> client = dynamic_pointer_cast<ClientThread>((*ix)->runnable());
+      std::shared_ptr<ClientThread> client
+          = std::dynamic_pointer_cast<ClientThread>((*ix)->runnable());
 
       int64_t delta = client->_endTime - client->_startTime;
 
@@ -485,13 +585,13 @@
         maxTime = delta;
       }
 
-      averageTime+= delta;
+      averageTime += delta;
     }
 
     averageTime /= clientCount;
 
-
-    cout <<  "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl;
+    cout << "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount
+         << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl;
 
     count_map count = serviceHandler->getCount();
     count_map::iterator iter;
diff --git a/test/cpp/src/StressTestNonBlocking.cpp b/test/cpp/src/StressTestNonBlocking.cpp
index c230c84..1d3ed73 100644
--- a/test/cpp/src/StressTestNonBlocking.cpp
+++ b/test/cpp/src/StressTestNonBlocking.cpp
@@ -29,23 +29,23 @@
 #include <thrift/server/TNonblockingServer.h>
 #include <thrift/transport/TServerSocket.h>
 #include <thrift/transport/TSocket.h>
+#include <thrift/transport/TNonblockingServerSocket.h>
 #include <thrift/transport/TTransportUtils.h>
 #include <thrift/transport/TFileTransport.h>
 #include <thrift/TLogging.h>
 
 #include "Service.h"
 
-#include <unistd.h>
-#include <boost/shared_ptr.hpp>
-
 #include <iostream>
 #include <set>
 #include <stdexcept>
 #include <sstream>
 #include <map>
+#if _WIN32
+#include <thrift/windows/TWinsockSingleton.h>
+#endif
 
 using namespace std;
-using namespace boost;
 
 using namespace apache::thrift;
 using namespace apache::thrift::protocol;
@@ -56,23 +56,18 @@
 using namespace test::stress;
 
 struct eqstr {
-  bool operator()(const char* s1, const char* s2) const {
-    return strcmp(s1, s2) == 0;
-  }
+  bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) == 0; }
 };
 
 struct ltstr {
-  bool operator()(const char* s1, const char* s2) const {
-    return strcmp(s1, s2) < 0;
-  }
+  bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; }
 };
 
-
 // typedef hash_map<const char*, int, hash<const char*>, eqstr> count_map;
 typedef map<const char*, int, ltstr> count_map;
 
 class Server : public ServiceIf {
- public:
+public:
   Server() {}
 
   void count(const char* method) {
@@ -84,7 +79,7 @@
   void echoVoid() {
     count("echoVoid");
     // Sleep to simulate work
-    usleep(5000);
+    THRIFT_SLEEP_USEC(1);
     return;
   }
 
@@ -93,58 +88,73 @@
     return counts_;
   }
 
-  int8_t echoByte(const int8_t arg) {return arg;}
-  int32_t echoI32(const int32_t arg) {return arg;}
-  int64_t echoI64(const int64_t arg) {return arg;}
-  void echoString(string& out, const string &arg) {
+  int8_t echoByte(const int8_t arg) { return arg; }
+  int32_t echoI32(const int32_t arg) { return arg; }
+  int64_t echoI64(const int64_t arg) { return arg; }
+  void echoString(string& out, const string& arg) {
     if (arg != "hello") {
       T_ERROR_ABORT("WRONG STRING (%s)!!!!", arg.c_str());
     }
     out = arg;
   }
-  void echoList(vector<int8_t> &out, const vector<int8_t> &arg) { out = arg; }
-  void echoSet(set<int8_t> &out, const set<int8_t> &arg) { out = arg; }
-  void echoMap(map<int8_t, int8_t> &out, const map<int8_t, int8_t> &arg) { out = arg; }
+  void echoList(vector<int8_t>& out, const vector<int8_t>& arg) { out = arg; }
+  void echoSet(set<int8_t>& out, const set<int8_t>& arg) { out = arg; }
+  void echoMap(map<int8_t, int8_t>& out, const map<int8_t, int8_t>& arg) { out = arg; }
 
 private:
   count_map counts_;
   Mutex lock_;
-
 };
 
-class ClientThread: public Runnable {
+class ClientThread : public Runnable {
 public:
-
-  ClientThread(boost::shared_ptr<TTransport>transport, boost::shared_ptr<ServiceClient> client, Monitor& monitor, size_t& workerCount, size_t loopCount, TType loopType) :
-    _transport(transport),
-    _client(client),
-    _monitor(monitor),
-    _workerCount(workerCount),
-    _loopCount(loopCount),
-    _loopType(loopType)
-  {}
+  ClientThread(std::shared_ptr<TTransport> transport,
+               std::shared_ptr<ServiceClient> client,
+               Monitor& monitor,
+               size_t& workerCount,
+               size_t loopCount,
+               TType loopType)
+    : _transport(transport),
+      _client(client),
+      _monitor(monitor),
+      _workerCount(workerCount),
+      _loopCount(loopCount),
+      _loopType(loopType) {}
 
   void run() {
 
     // Wait for all worker threads to start
 
-    {Synchronized s(_monitor);
-        while(_workerCount == 0) {
-          _monitor.wait();
-        }
+    {
+      Synchronized s(_monitor);
+      while (_workerCount == 0) {
+        _monitor.wait();
+      }
     }
 
     _startTime = Util::currentTime();
 
     _transport->open();
 
-    switch(_loopType) {
-    case T_VOID: loopEchoVoid(); break;
-    case T_BYTE: loopEchoByte(); break;
-    case T_I32: loopEchoI32(); break;
-    case T_I64: loopEchoI64(); break;
-    case T_STRING: loopEchoString(); break;
-    default: cerr << "Unexpected loop type" << _loopType << endl; break;
+    switch (_loopType) {
+    case T_VOID:
+      loopEchoVoid();
+      break;
+    case T_BYTE:
+      loopEchoByte();
+      break;
+    case T_I32:
+      loopEchoI32();
+      break;
+    case T_I64:
+      loopEchoI64();
+      break;
+    case T_STRING:
+      loopEchoString();
+      break;
+    default:
+      cerr << "Unexpected loop type" << _loopType << endl;
+      break;
     }
 
     _endTime = Util::currentTime();
@@ -153,7 +163,8 @@
 
     _done = true;
 
-    {Synchronized s(_monitor);
+    {
+      Synchronized s(_monitor);
 
       _workerCount--;
 
@@ -174,7 +185,8 @@
     for (size_t ix = 0; ix < _loopCount; ix++) {
       int8_t arg = 1;
       int8_t result;
-      result =_client->echoByte(arg);
+      result = _client->echoByte(arg);
+      (void)result;
       assert(result == arg);
     }
   }
@@ -183,7 +195,8 @@
     for (size_t ix = 0; ix < _loopCount; ix++) {
       int32_t arg = 1;
       int32_t result;
-      result =_client->echoI32(arg);
+      result = _client->echoI32(arg);
+      (void)result;
       assert(result == arg);
     }
   }
@@ -192,7 +205,8 @@
     for (size_t ix = 0; ix < _loopCount; ix++) {
       int64_t arg = 1;
       int64_t result;
-      result =_client->echoI64(arg);
+      result = _client->echoI64(arg);
+      (void)result;
       assert(result == arg);
     }
   }
@@ -206,8 +220,8 @@
     }
   }
 
-  boost::shared_ptr<TTransport> _transport;
-  boost::shared_ptr<ServiceClient> _client;
+  std::shared_ptr<TTransport> _transport;
+  std::shared_ptr<ServiceClient> _client;
   Monitor& _monitor;
   size_t& _workerCount;
   size_t _loopCount;
@@ -218,16 +232,18 @@
   Monitor _sleep;
 };
 
-
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
+#if _WIN32
+  transport::TWinsockSingleton::create();
+#endif
 
   int port = 9091;
   string serverType = "simple";
   string protocolType = "binary";
-  size_t workerCount = 4;
-  size_t clientCount = 20;
-  size_t loopCount = 50000;
-  TType loopType  = T_VOID;
+  uint32_t workerCount = 4;
+  uint32_t clientCount = 20;
+  uint32_t loopCount = 1000;
+  TType loopType = T_VOID;
   string callName = "echoVoid";
   bool runServer = true;
   bool logRequests = false;
@@ -236,28 +252,34 @@
 
   ostringstream usage;
 
-  usage <<
-    argv[0] << " [--port=<port number>] [--server] [--server-type=<server-type>] [--protocol-type=<protocol-type>] [--workers=<worker-count>] [--clients=<client-count>] [--loop=<loop-count>]" << endl <<
-    "\tclients        Number of client threads to create - 0 implies no clients, i.e. server only.  Default is " << clientCount << endl <<
-    "\thelp           Prints this help text." << endl <<
-    "\tcall           Service method to call.  Default is " << callName << endl <<
-    "\tloop           The number of remote thrift calls each client makes.  Default is " << loopCount << endl <<
-    "\tport           The port the server and clients should bind to for thrift network connections.  Default is " << port << endl <<
-    "\tserver         Run the Thrift server in this process.  Default is " << runServer << endl <<
-    "\tserver-type    Type of server, \"simple\" or \"thread-pool\".  Default is " << serverType << endl <<
-    "\tprotocol-type  Type of protocol, \"binary\", \"ascii\", or \"xml\".  Default is " << protocolType << endl <<
-    "\tlog-request    Log all request to ./requestlog.tlog. Default is " << logRequests << endl <<
-    "\treplay-request Replay requests from log file (./requestlog.tlog) Default is " << replayRequests << endl <<
-    "\tworkers        Number of thread pools workers.  Only valid for thread-pool server type.  Default is " << workerCount << endl;
+  usage << argv[0] << " [--port=<port number>] [--server] [--server-type=<server-type>] "
+                      "[--protocol-type=<protocol-type>] [--workers=<worker-count>] "
+                      "[--clients=<client-count>] [--loop=<loop-count>]" << endl
+        << "\tclients        Number of client threads to create - 0 implies no clients, i.e. "
+           "server only.  Default is " << clientCount << endl
+        << "\thelp           Prints this help text." << endl
+        << "\tcall           Service method to call.  Default is " << callName << endl
+        << "\tloop           The number of remote thrift calls each client makes.  Default is "
+        << loopCount << endl << "\tport           The port the server and clients should bind to "
+                                "for thrift network connections.  Default is " << port << endl
+        << "\tserver         Run the Thrift server in this process.  Default is " << runServer
+        << endl << "\tserver-type    Type of server, \"simple\" or \"thread-pool\".  Default is "
+        << serverType << endl
+        << "\tprotocol-type  Type of protocol, \"binary\", \"ascii\", or \"xml\".  Default is "
+        << protocolType << endl
+        << "\tlog-request    Log all request to ./requestlog.tlog. Default is " << logRequests
+        << endl << "\treplay-request Replay requests from log file (./requestlog.tlog) Default is "
+        << replayRequests << endl << "\tworkers        Number of thread pools workers.  Only valid "
+                                     "for thread-pool server type.  Default is " << workerCount
+        << endl;
 
-
-  map<string, string>  args;
+  map<string, string> args;
 
   for (int ix = 1; ix < argc; ix++) {
 
     string arg(argv[ix]);
 
-    if (arg.compare(0,2, "--") == 0) {
+    if (arg.compare(0, 2, "--") == 0) {
 
       size_t end = arg.find_first_of("=", 2);
 
@@ -269,7 +291,7 @@
         args[key] = "true";
       }
     } else {
-      throw invalid_argument("Unexcepted command line token: "+arg);
+      throw invalid_argument("Unexcepted command line token: " + arg);
     }
   }
 
@@ -316,74 +338,83 @@
       workerCount = atoi(args["workers"].c_str());
     }
 
-  } catch(std::exception& e) {
+  } catch (std::exception& e) {
     cerr << e.what() << endl;
-    cerr << usage;
+    cerr << usage.str();
   }
 
-  boost::shared_ptr<PlatformThreadFactory> threadFactory = boost::shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory());
+  std::shared_ptr<PlatformThreadFactory> threadFactory
+      = std::shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory());
 
   // Dispatcher
-  boost::shared_ptr<Server> serviceHandler(new Server());
+  std::shared_ptr<Server> serviceHandler(new Server());
 
   if (replayRequests) {
-    boost::shared_ptr<Server> serviceHandler(new Server());
-    boost::shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler));
+    std::shared_ptr<Server> serviceHandler(new Server());
+    std::shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler));
 
     // Transports
-    boost::shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath));
+    std::shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath));
     fileTransport->setChunkSize(2 * 1024 * 1024);
     fileTransport->setMaxEventSize(1024 * 16);
     fileTransport->seekToEnd();
 
     // Protocol Factory
-    boost::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+    std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
 
-    TFileProcessor fileProcessor(serviceProcessor,
-                                 protocolFactory,
-                                 fileTransport);
+    TFileProcessor fileProcessor(serviceProcessor, protocolFactory, fileTransport);
 
     fileProcessor.process(0, true);
     exit(0);
   }
 
-
   if (runServer) {
 
-    boost::shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler));
+    std::shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler));
 
     // Protocol Factory
-    boost::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+    std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
 
     // Transport Factory
-    boost::shared_ptr<TTransportFactory>      transportFactory;
+    std::shared_ptr<TTransportFactory> transportFactory;
 
     if (logRequests) {
       // initialize the log file
-      boost::shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath));
+      std::shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath));
       fileTransport->setChunkSize(2 * 1024 * 1024);
       fileTransport->setMaxEventSize(1024 * 16);
 
-      transportFactory =
-        boost::shared_ptr<TTransportFactory>(new TPipedTransportFactory(fileTransport));
+      transportFactory
+          = std::shared_ptr<TTransportFactory>(new TPipedTransportFactory(fileTransport));
     }
 
-    boost::shared_ptr<Thread> serverThread;
-    boost::shared_ptr<Thread> serverThread2;
+    std::shared_ptr<Thread> serverThread;
+    std::shared_ptr<Thread> serverThread2;
+    std::shared_ptr<transport::TNonblockingServerSocket> nbSocket1;
+    std::shared_ptr<transport::TNonblockingServerSocket> nbSocket2;
 
     if (serverType == "simple") {
 
-      serverThread = threadFactory->newThread(boost::shared_ptr<TServer>(new TNonblockingServer(serviceProcessor, protocolFactory, port)));
-      serverThread2 = threadFactory->newThread(boost::shared_ptr<TServer>(new TNonblockingServer(serviceProcessor, protocolFactory, port+1)));
+      nbSocket1.reset(new transport::TNonblockingServerSocket(port));
+      serverThread = threadFactory->newThread(std::shared_ptr<TServer>(
+          new TNonblockingServer(serviceProcessor, protocolFactory, nbSocket1)));
+      nbSocket2.reset(new transport::TNonblockingServerSocket(port + 1));
+      serverThread2 = threadFactory->newThread(std::shared_ptr<TServer>(
+          new TNonblockingServer(serviceProcessor, protocolFactory, nbSocket2)));
 
     } else if (serverType == "thread-pool") {
 
-      boost::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(workerCount);
+      std::shared_ptr<ThreadManager> threadManager
+          = ThreadManager::newSimpleThreadManager(workerCount);
 
       threadManager->threadFactory(threadFactory);
       threadManager->start();
-      serverThread = threadFactory->newThread(boost::shared_ptr<TServer>(new TNonblockingServer(serviceProcessor, protocolFactory, port, threadManager)));
-      serverThread2 = threadFactory->newThread(boost::shared_ptr<TServer>(new TNonblockingServer(serviceProcessor, protocolFactory, port+1, threadManager)));
+      nbSocket1.reset(new transport::TNonblockingServerSocket(port));
+      serverThread = threadFactory->newThread(std::shared_ptr<TServer>(
+          new TNonblockingServer(serviceProcessor, protocolFactory, nbSocket1, threadManager)));
+      nbSocket2.reset(new transport::TNonblockingServerSocket(port + 1));
+      serverThread2 = threadFactory->newThread(std::shared_ptr<TServer>(
+          new TNonblockingServer(serviceProcessor, protocolFactory, nbSocket2, threadManager)));
     }
 
     cerr << "Starting the server on port " << port << " and " << (port + 1) << endl;
@@ -397,7 +428,7 @@
       serverThread2->join();
     }
   }
-  sleep(1);
+  THRIFT_SLEEP_SEC(1);
 
   if (clientCount > 0) {
 
@@ -405,46 +436,57 @@
 
     size_t threadCount = 0;
 
-    set<boost::shared_ptr<Thread> > clientThreads;
+    set<std::shared_ptr<Thread> > clientThreads;
 
-    if (callName == "echoVoid") { loopType = T_VOID;}
-    else if (callName == "echoByte") { loopType = T_BYTE;}
-    else if (callName == "echoI32") { loopType = T_I32;}
-    else if (callName == "echoI64") { loopType = T_I64;}
-    else if (callName == "echoString") { loopType = T_STRING;}
-    else {throw invalid_argument("Unknown service call "+callName);}
-
-    for (size_t ix = 0; ix < clientCount; ix++) {
-
-      boost::shared_ptr<TSocket> socket(new TSocket("127.0.0.1", port + (ix % 2)));
-      boost::shared_ptr<TFramedTransport> framedSocket(new TFramedTransport(socket));
-      boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(framedSocket));
-      boost::shared_ptr<ServiceClient> serviceClient(new ServiceClient(protocol));
-
-      clientThreads.insert(threadFactory->newThread(boost::shared_ptr<ClientThread>(new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType))));
+    if (callName == "echoVoid") {
+      loopType = T_VOID;
+    } else if (callName == "echoByte") {
+      loopType = T_BYTE;
+    } else if (callName == "echoI32") {
+      loopType = T_I32;
+    } else if (callName == "echoI64") {
+      loopType = T_I64;
+    } else if (callName == "echoString") {
+      loopType = T_STRING;
+    } else {
+      throw invalid_argument("Unknown service call " + callName);
     }
 
-    for (std::set<boost::shared_ptr<Thread> >::const_iterator thread = clientThreads.begin(); thread != clientThreads.end(); thread++) {
+    for (uint32_t ix = 0; ix < clientCount; ix++) {
+
+      std::shared_ptr<TSocket> socket(new TSocket("127.0.0.1", port + (ix % 2)));
+      std::shared_ptr<TFramedTransport> framedSocket(new TFramedTransport(socket));
+      std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(framedSocket));
+      std::shared_ptr<ServiceClient> serviceClient(new ServiceClient(protocol));
+
+      clientThreads.insert(threadFactory->newThread(std::shared_ptr<ClientThread>(
+          new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType))));
+    }
+
+    for (std::set<std::shared_ptr<Thread> >::const_iterator thread = clientThreads.begin();
+         thread != clientThreads.end();
+         thread++) {
       (*thread)->start();
     }
 
     int64_t time00;
     int64_t time01;
 
-    {Synchronized s(monitor);
+    {
+      Synchronized s(monitor);
       threadCount = clientCount;
 
-      cerr << "Launch "<< clientCount << " client threads" << endl;
+      cerr << "Launch " << clientCount << " client threads" << endl;
 
-      time00 =  Util::currentTime();
+      time00 = Util::currentTime();
 
       monitor.notifyAll();
 
-      while(threadCount > 0) {
+      while (threadCount > 0) {
         monitor.wait();
       }
 
-      time01 =  Util::currentTime();
+      time01 = Util::currentTime();
     }
 
     int64_t firstTime = 9223372036854775807LL;
@@ -454,9 +496,12 @@
     int64_t minTime = 9223372036854775807LL;
     int64_t maxTime = 0;
 
-    for (set<boost::shared_ptr<Thread> >::iterator ix = clientThreads.begin(); ix != clientThreads.end(); ix++) {
+    for (set<std::shared_ptr<Thread> >::iterator ix = clientThreads.begin();
+         ix != clientThreads.end();
+         ix++) {
 
-      boost::shared_ptr<ClientThread> client = dynamic_pointer_cast<ClientThread>((*ix)->runnable());
+      std::shared_ptr<ClientThread> client
+          = std::dynamic_pointer_cast<ClientThread>((*ix)->runnable());
 
       int64_t delta = client->_endTime - client->_startTime;
 
@@ -478,13 +523,13 @@
         maxTime = delta;
       }
 
-      averageTime+= delta;
+      averageTime += delta;
     }
 
     averageTime /= clientCount;
 
-
-    cout <<  "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl;
+    cout << "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount
+         << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl;
 
     count_map count = serviceHandler->getCount();
     count_map::iterator iter;
diff --git a/test/cpp/src/TestClient.cpp b/test/cpp/src/TestClient.cpp
index fbf04f0..89f3fd1 100644
--- a/test/cpp/src/TestClient.cpp
+++ b/test/cpp/src/TestClient.cpp
@@ -1,4 +1,4 @@
-/*
+/*
  * 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
@@ -17,226 +17,355 @@
  * under the License.
  */
 
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-
+#include <limits>
+#include <locale>
+#include <ios>
 #include <iostream>
-#include <unistd.h>
-#include <sys/time.h>
+#include <sstream>
 #include <thrift/protocol/TBinaryProtocol.h>
+#include <thrift/protocol/TCompactProtocol.h>
+#include <thrift/protocol/THeaderProtocol.h>
 #include <thrift/protocol/TJSONProtocol.h>
+#include <thrift/protocol/TMultiplexedProtocol.h>
 #include <thrift/transport/THttpClient.h>
 #include <thrift/transport/TTransportUtils.h>
 #include <thrift/transport/TSocket.h>
 #include <thrift/transport/TSSLSocket.h>
+#include <thrift/transport/TZlibTransport.h>
 #include <thrift/async/TEvhttpClientChannel.h>
 #include <thrift/server/TNonblockingServer.h> // <event.h>
 
-#include <boost/shared_ptr.hpp>
-#include <boost/program_options.hpp>
-#include <tr1/functional>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
 
+#include <boost/algorithm/string.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+#include <boost/random/random_device.hpp>
+#if _WIN32
+#include <thrift/windows/TWinsockSingleton.h>
+#endif
+
+#include "SecondService.h"
 #include "ThriftTest.h"
 
-using namespace boost;
 using namespace std;
 using namespace apache::thrift;
+using namespace apache::thrift::async;
 using namespace apache::thrift::protocol;
 using namespace apache::thrift::transport;
 using namespace thrift::test;
-using namespace apache::thrift::async;
-
-//extern uint32_t g_socket_syscalls;
 
 // Current time, microseconds since the epoch
-uint64_t now()
-{
+uint64_t now() {
   int64_t ret;
   struct timeval tv;
 
-  gettimeofday(&tv, NULL);
+  THRIFT_GETTIMEOFDAY(&tv, NULL);
   ret = tv.tv_sec;
-  ret = ret*1000*1000 + tv.tv_usec;
+  ret = ret * 1000 * 1000 + tv.tv_usec;
   return ret;
 }
 
-static void testString_clientReturn(const char* host, int port, event_base *base, TProtocolFactory* protocolFactory, ThriftTestCobClient* client) {
-  (void) host;
-  (void) port;
-  (void) protocolFactory;
+static void testString_clientReturn(event_base* base,
+                                    int testNr,
+                                    ThriftTestCobClient* client) {
   try {
     string s;
     client->recv_testString(s);
-    cout << "testString: " << s << endl;
+    std::ostringstream os;
+    os << "test" << testNr;
+    const bool ok = (s == os.str());
+    cout << "testString: " << s << " " << ((ok) ? "ok" : "failed") << endl;
   } catch (TException& exn) {
-    cout << "Error: " << exn.what() << endl;    
+    cout << "Error: " << exn.what() << endl;
   }
 
-  event_base_loopbreak(base); // end test
+  if (testNr == 9)
+    event_base_loopbreak(base); // end test
 }
 
-static void testVoid_clientReturn(const char* host, int port, event_base *base, TProtocolFactory* protocolFactory, ThriftTestCobClient* client) {
+static void testVoid_clientReturn(event_base* base, ThriftTestCobClient* client) {
   try {
     client->recv_testVoid();
     cout << "testVoid" << endl;
 
-    // next test
-    delete client;
-    boost::shared_ptr<TAsyncChannel> channel(new TEvhttpClientChannel(host, "/", host, port, base));
-    client = new ThriftTestCobClient(channel, protocolFactory);
-    client->testString(tr1::bind(testString_clientReturn, host, port, base, protocolFactory, std::tr1::placeholders::_1), "Test");
+    for (int testNr = 0; testNr < 10; ++testNr) {
+      std::ostringstream os;
+      os << "test" << testNr;
+      client->testString(std::bind(testString_clientReturn,
+                                    base,
+                                    testNr,
+                                    std::placeholders::_1),
+                       os.str());
+    }
   } catch (TException& exn) {
-    cout << "Error: " << exn.what() << endl;    
+    cout << "Error: " << exn.what() << endl;
   }
 }
 
+// Workaround for absense of C++11 "auto" keyword.
+template <typename T>
+bool print_eq(T expected, T actual) {
+  cout << "(" << actual << ")" << endl;
+  if (expected != actual) {
+    cout << "*** FAILED ***" << endl << "Expected: " << expected << " but got: " << actual << endl;
+    return false;
+  }
+  return true;
+}
+
+#define BASETYPE_IDENTITY_TEST(func, value)                                                        \
+  cout << #func "(" << value << ") = ";                                                            \
+  try {                                                                                            \
+    if (!print_eq(value, testClient.func(value)))                                                  \
+      return_code |= ERR_BASETYPES;                                                                \
+  } catch (TTransportException&) {                                                                 \
+    throw;                                                                                         \
+  } catch (exception & ex) {                                                                       \
+    cout << "*** FAILED ***" << endl << ex.what() << endl;                                         \
+    return_code |= ERR_BASETYPES;                                                                  \
+  }
+
+int binary_test(ThriftTestClient& testClient, string::size_type siz);
+
+BOOST_CONSTEXPR_OR_CONST int ERR_BASETYPES = 1;
+BOOST_CONSTEXPR_OR_CONST int ERR_STRUCTS = 2;
+BOOST_CONSTEXPR_OR_CONST int ERR_CONTAINERS = 4;
+BOOST_CONSTEXPR_OR_CONST int ERR_EXCEPTIONS = 8;
+BOOST_CONSTEXPR_OR_CONST int ERR_UNKNOWN = 64;
+
 int main(int argc, char** argv) {
+  cout.precision(19);
+
+  string testDir  = boost::filesystem::system_complete(argv[0]).parent_path().parent_path().parent_path().string();
+  string caPath   = testDir + "/keys/CA.pem";
+  string certPath = testDir + "/keys/client.crt";
+  string keyPath  = testDir + "/keys/client.key";
+
+#if _WIN32
+  transport::TWinsockSingleton::create();
+#endif
   string host = "localhost";
   int port = 9090;
   int numTests = 1;
   bool ssl = false;
+  bool zlib = false;
   string transport_type = "buffered";
   string protocol_type = "binary";
   string domain_socket = "";
+  bool abstract_namespace = false;
+  bool noinsane = false;
 
-  program_options::options_description desc("Allowed options");
+  int return_code = 0;
+
+  boost::program_options::options_description desc("Allowed options");
   desc.add_options()
       ("help,h", "produce help message")
-      ("host", program_options::value<string>(&host)->default_value(host), "Host to connect")
-      ("port", program_options::value<int>(&port)->default_value(port), "Port number to connect")
-	  ("domain-socket", program_options::value<string>(&domain_socket)->default_value(domain_socket), "Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port")
-      ("transport", program_options::value<string>(&transport_type)->default_value(transport_type), "Transport: buffered, framed, http, evhttp")
-      ("protocol", program_options::value<string>(&protocol_type)->default_value(protocol_type), "Protocol: binary, json")
-	  ("ssl", "Encrypted Transport using SSL")
-      ("testloops,n", program_options::value<int>(&numTests)->default_value(numTests), "Number of Tests")
-  ;
+      ("host",
+          boost::program_options::value<string>(&host)->default_value(host),
+          "Host to connect")
+      ("port",
+          boost::program_options::value<int>(&port)->default_value(port),
+          "Port number to connect")
+      ("domain-socket",
+          boost::program_options::value<string>(&domain_socket)->default_value(domain_socket),
+          "Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port")
+      ("abstract-namespace",
+          "Look for the domain socket in the Abstract Namespace"
+          " (no connection with filesystem pathnames)")
+      ("transport",
+          boost::program_options::value<string>(&transport_type)->default_value(transport_type),
+          "Transport: buffered, framed, http, evhttp, zlib")
+      ("protocol",
+          boost::program_options::value<string>(&protocol_type)->default_value(protocol_type),
+          "Protocol: binary, compact, header, json, multi, multic, multih, multij")
+      ("ssl",
+          "Encrypted Transport using SSL")
+      ("zlib",
+          "Wrap Transport with Zlib")
+      ("testloops,n",
+          boost::program_options::value<int>(&numTests)->default_value(numTests),
+          "Number of Tests")
+      ("noinsane",
+          "Do not run insanity test");
 
-  program_options::variables_map vm;
-  program_options::store(program_options::parse_command_line(argc, argv, desc), vm);
-  program_options::notify(vm);    
+  boost::program_options::variables_map vm;
+  boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
+  boost::program_options::notify(vm);
 
   if (vm.count("help")) {
-    cout << desc << "\n";
-    return 1;
+    cout << desc << endl;
+    return ERR_UNKNOWN;
   }
 
-  try {   
+  try {
     if (!protocol_type.empty()) {
       if (protocol_type == "binary") {
+      } else if (protocol_type == "compact") {
+      } else if (protocol_type == "header") {
       } else if (protocol_type == "json") {
+      } else if (protocol_type == "multi") {
+      } else if (protocol_type == "multic") {
+      } else if (protocol_type == "multih") {
+      } else if (protocol_type == "multij") {
       } else {
-          throw invalid_argument("Unknown protocol type "+protocol_type);
+        throw invalid_argument("Unknown protocol type " + protocol_type);
       }
     }
 
-	if (!transport_type.empty()) {
+    if (!transport_type.empty()) {
       if (transport_type == "buffered") {
       } else if (transport_type == "framed") {
       } else if (transport_type == "http") {
       } else if (transport_type == "evhttp") {
+      } else if (transport_type == "zlib") {
+        // crosstest will pass zlib as a transport and as a flag right now..
       } else {
-          throw invalid_argument("Unknown transport type "+transport_type);
+        throw invalid_argument("Unknown transport type " + transport_type);
       }
     }
 
-  } catch (std::exception& e) {
+  } catch (exception& e) {
     cerr << e.what() << endl;
-    cout << desc << "\n";
-    return 1;
+    cout << desc << endl;
+    return ERR_UNKNOWN;
   }
 
   if (vm.count("ssl")) {
     ssl = true;
   }
 
-  boost::shared_ptr<TTransport> transport;
-  boost::shared_ptr<TProtocol> protocol;
+  if (vm.count("zlib")) {
+    zlib = true;
+  }
 
-  boost::shared_ptr<TSocket> socket;
-  boost::shared_ptr<TSSLSocketFactory> factory;
+  if (vm.count("abstract-namespace")) {
+    abstract_namespace = true;
+  }
+
+  if (vm.count("noinsane")) {
+    noinsane = true;
+  }
+
+  // THRIFT-4164: The factory MUST outlive any sockets it creates for correct behavior!
+  std::shared_ptr<TSSLSocketFactory> factory;
+  std::shared_ptr<TSocket> socket;
+  std::shared_ptr<TTransport> transport;
+  std::shared_ptr<TProtocol> protocol;
+  std::shared_ptr<TProtocol> protocol2;  // SecondService for multiplexed
 
   if (ssl) {
-    factory = boost::shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory());
+    cout << "Client Certificate File: " << certPath << endl;
+    cout << "Client Key         File: " << keyPath << endl;
+    cout << "CA                 File: " << caPath << endl;
+
+    factory = std::shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory());
     factory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
-    factory->loadTrustedCertificates("./trusted-ca-certificate.pem");
+    factory->loadTrustedCertificates(caPath.c_str());
+    factory->loadCertificate(certPath.c_str());
+    factory->loadPrivateKey(keyPath.c_str());
     factory->authenticate(true);
     socket = factory->createSocket(host, port);
   } else {
     if (domain_socket != "") {
-      socket = boost::shared_ptr<TSocket>(new TSocket(domain_socket));
+      if (abstract_namespace) {
+        std::string abstract_socket("\0", 1);
+        abstract_socket += domain_socket;
+        socket = std::shared_ptr<TSocket>(new TSocket(abstract_socket));
+      } else {
+        socket = std::shared_ptr<TSocket>(new TSocket(domain_socket));
+      }
       port = 0;
-    }
-    else {
-      socket = boost::shared_ptr<TSocket>(new TSocket(host, port));
+    } else {
+      socket = std::shared_ptr<TSocket>(new TSocket(host, port));
     }
   }
 
   if (transport_type.compare("http") == 0) {
-    boost::shared_ptr<TTransport> httpSocket(new THttpClient(socket, host, "/service"));
-    transport = httpSocket;
-  } else if (transport_type.compare("framed") == 0){
-    boost::shared_ptr<TFramedTransport> framedSocket(new TFramedTransport(socket));
-    transport = framedSocket;
-  } else{
-    boost::shared_ptr<TBufferedTransport> bufferedSocket(new TBufferedTransport(socket));
-    transport = bufferedSocket;
+    transport = std::make_shared<THttpClient>(socket, host, "/service");
+  } else if (transport_type.compare("framed") == 0) {
+    transport = std::make_shared<TFramedTransport>(socket);
+  } else {
+    transport = std::make_shared<TBufferedTransport>(socket);
   }
 
-  if (protocol_type.compare("json") == 0) {
-    boost::shared_ptr<TProtocol> jsonProtocol(new TJSONProtocol(transport));
-    protocol = jsonProtocol;
-  } else{
-    boost::shared_ptr<TBinaryProtocol> binaryProtocol(new TBinaryProtocol(transport));
-    protocol = binaryProtocol;
+  if (zlib) {
+    transport = std::make_shared<TZlibTransport>(transport);
+  }
+
+  if (protocol_type == "json" || protocol_type == "multij") {
+    protocol = std::make_shared<TJSONProtocol>(transport);
+  } else if (protocol_type == "compact" || protocol_type == "multic") {
+    protocol = std::make_shared<TCompactProtocol>(transport);
+  } else if (protocol_type == "header" || protocol_type == "multih") {
+    protocol = std::make_shared<THeaderProtocol>(transport);
+  } else {
+    protocol = std::make_shared<TBinaryProtocol>(transport);
+  }
+
+  if (boost::starts_with(protocol_type, "multi")) {
+  protocol2 = std::make_shared<TMultiplexedProtocol>(protocol, "SecondService");
+  // we don't need access to the original protocol any more, so...
+  protocol = std::make_shared<TMultiplexedProtocol>(protocol, "ThriftTest");
   }
 
   // Connection info
-  cout << "Connecting (" << transport_type << "/" << protocol_type << ") to: " << domain_socket;
+  cout << "Connecting (" << transport_type << "/" << protocol_type << ") to: ";
+  if (abstract_namespace) {
+    cout << '@';
+  }
+  cout << domain_socket;
   if (port != 0) {
     cout << host << ":" << port;
   }
   cout << endl;
 
   if (transport_type.compare("evhttp") == 0) {
-    event_base *base = event_base_new();
+    event_base* base = event_base_new();
     cout << "Libevent Version: " << event_get_version() << endl;
     cout << "Libevent Method: " << event_base_get_method(base) << endl;
 #if LIBEVENT_VERSION_NUMBER >= 0x02000000
     cout << "Libevent Features: 0x" << hex << event_base_get_features(base) << endl;
 #endif
 
-    boost::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+    std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
 
-    boost::shared_ptr<TAsyncChannel> channel(new TEvhttpClientChannel(host.c_str(), "/", host.c_str(), port, base));
+    std::shared_ptr<TAsyncChannel> channel(
+        new TEvhttpClientChannel(host.c_str(), "/", host.c_str(), port, base));
     ThriftTestCobClient* client = new ThriftTestCobClient(channel, protocolFactory.get());
-    client->testVoid(tr1::bind(testVoid_clientReturn, host.c_str(), port, base, protocolFactory.get(), std::tr1::placeholders::_1));
-    
+    client->testVoid(std::bind(testVoid_clientReturn,
+                                base,
+                                std::placeholders::_1));
+
     event_base_loop(base, 0);
     return 0;
   }
 
-
   ThriftTestClient testClient(protocol);
 
   uint64_t time_min = 0;
   uint64_t time_max = 0;
   uint64_t time_tot = 0;
 
-  int failCount = 0;
   int test = 0;
   for (test = 0; test < numTests; ++test) {
 
     try {
       transport->open();
-    } catch (TTransportException& ttx) {
-      printf("Connect failed: %s\n", ttx.what());
-      return 1;
+    } catch (TTransportException& ex) {
+      cout << "Connect failed: " << ex.what() << endl;
+      return ERR_UNKNOWN;
     }
 
     /**
      * CONNECT TEST
      */
-    printf("Test #%d, connect %s:%d\n", test+1, host.c_str(), port);
+    printf("Test #%d, connect %s:%d\n", test + 1, host.c_str(), port);
 
     uint64_t start = now();
 
@@ -244,63 +373,225 @@
      * VOID TEST
      */
     try {
-      printf("testVoid()");
+      cout << "testVoid()" << flush;
       testClient.testVoid();
-      printf(" = void\n");
-    } catch (TApplicationException& tax) {
-      printf("%s\n", tax.what());
-      failCount++;
+      cout << " = void" << endl;
+    } catch (TTransportException&) {
+      // Stop here if transport got broken
+      throw;
+    } catch (exception& ex) {
+      cout << "*** FAILED ***" << endl << ex.what() << endl;
+      return_code |= ERR_BASETYPES;
     }
 
     /**
      * STRING TEST
      */
-    printf("testString(\"Test\")");
+    cout << "testString(\"Test\")" << flush;
     string s;
     testClient.testString(s, "Test");
-    printf(" = \"%s\"\n", s.c_str());
-    if (s != "Test")
-        failCount++;
+    cout << " = " << s << endl;
+    if (s != "Test") {
+      cout << "*** FAILED ***" << endl;
+      return_code |= ERR_BASETYPES;
+    }
+
+    //
+    // Multiplexed protocol - call another service method
+    // in the middle of the ThriftTest
+    //
+    if (boost::starts_with(protocol_type, "multi")) {
+    SecondServiceClient ssc(protocol2);
+    // transport is already open...
+
+        try {
+          cout << "secondService.secondTestString(\"foo\") => " << flush;
+        std::string result;
+      ssc.secondtestString(result, "foo");
+      cout << "{" << result << "}" << endl;
+      } catch (std::exception& e) {
+      cout << "  *** FAILED *** " << e.what() << endl;
+      return_code |= ERR_EXCEPTIONS;
+    }
+    }
+
+    try {
+#ifdef _MSC_VER
+#pragma warning( push )
+#pragma warning( disable : 4566 )
+#endif
+      string str(
+          "}{Afrikaans, Alemannisch, Aragonés, العربية, مصرى, "
+          "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, "
+          "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, "
+          "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, "
+          "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, "
+          "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, "
+          "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, "
+          "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, "
+          "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, "
+          "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, "
+          "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, "
+          "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, "
+          "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, "
+          "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa "
+          "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa "
+          "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪"
+          "Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, "
+          "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, "
+          "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, "
+          "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple "
+          "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, "
+          "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, "
+          "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, "
+          "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, "
+          "Bân-lâm-gú, 粵語");
+#ifdef _MSC_VER
+#pragma warning( pop )
+#endif
+      cout << "testString(" << str << ") = " << flush;
+      testClient.testString(s, str);
+      cout << s << endl;
+      if (s != str) {
+        cout.imbue(locale("en_US.UTF8"));
+        cout << "*** FAILED ***" << endl << "Expected string: " << str << " but got: " << s << endl << "CLEAR";
+        return_code |= ERR_BASETYPES;
+      }
+    } catch (TTransportException&) {
+      throw;
+    } catch (exception& ex) {
+      cout << "*** FAILED ***" << endl << ex.what() << endl;
+      return_code |= ERR_BASETYPES;
+      return return_code;
+    }
+    try {
+      string str(
+          "quote: \" backslash:"
+          " forwardslash-escaped: \\/ "
+          " backspace: \b formfeed: \f newline: \n return: \r tab: "
+          " now-all-of-them-together: \"\\\\/\b\n\r\t"
+          " now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><"
+          " char-to-test-json-parsing: ]] \"]] \\\" }}}{ [[[ ");
+      cout << "testString(" << str << ") = " << flush;
+      testClient.testString(s, str);
+      cout << s << endl;
+      if (s != str) {
+        cout.imbue(locale("en_US.UTF8"));
+        cout << "*** FAILED ***" << endl
+             << "Expected string: " << str << " but got: " << s << endl
+             << "CLEAR";
+        ;
+        return_code |= ERR_BASETYPES;
+      }
+    } catch (TTransportException&) {
+      throw;
+    } catch (exception& ex) {
+      cout << "*** FAILED ***" << endl << ex.what() << endl;
+      return_code |= ERR_BASETYPES;
+      return return_code;
+    }
+
+    /**
+     * BOOL TEST
+     */
+    cout << boolalpha;
+    BASETYPE_IDENTITY_TEST(testBool, true);
+    BASETYPE_IDENTITY_TEST(testBool, false);
 
     /**
      * BYTE TEST
      */
-    printf("testByte(1)");
-    uint8_t u8 = testClient.testByte(1);
-    printf(" = %d\n", (int)u8);
-    if (u8 != 1)
-        failCount++;
+    BASETYPE_IDENTITY_TEST(testByte, (int8_t)0);
+    BASETYPE_IDENTITY_TEST(testByte, (int8_t)-1);
+    BASETYPE_IDENTITY_TEST(testByte, (int8_t)42);
+    BASETYPE_IDENTITY_TEST(testByte, (int8_t)-42);
+    BASETYPE_IDENTITY_TEST(testByte, (int8_t)127);
+    BASETYPE_IDENTITY_TEST(testByte, (int8_t)-128);
 
     /**
      * I32 TEST
      */
-    printf("testI32(-1)");
-    int32_t i32 = testClient.testI32(-1);
-    printf(" = %d\n", i32);
-    if (i32 != -1)
-        failCount++;
+    BASETYPE_IDENTITY_TEST(testI32, 0);
+    BASETYPE_IDENTITY_TEST(testI32, -1);
+    BASETYPE_IDENTITY_TEST(testI32, 190000013);
+    BASETYPE_IDENTITY_TEST(testI32, -190000013);
+    BASETYPE_IDENTITY_TEST(testI32, (numeric_limits<int32_t>::max)());
+    BASETYPE_IDENTITY_TEST(testI32, (numeric_limits<int32_t>::min)());
 
     /**
      * I64 TEST
      */
-    printf("testI64(-34359738368)");
-    int64_t i64 = testClient.testI64(-34359738368LL);
-    printf(" = %"PRId64"\n", i64);
-    if (i64 != -34359738368LL)
-        failCount++;
+    BASETYPE_IDENTITY_TEST(testI64, (int64_t)0);
+    BASETYPE_IDENTITY_TEST(testI64, (int64_t)-1);
+    BASETYPE_IDENTITY_TEST(testI64, (int64_t)7000000000000000123LL);
+    BASETYPE_IDENTITY_TEST(testI64, (int64_t)-7000000000000000123LL);
+    BASETYPE_IDENTITY_TEST(testI64, (int64_t)pow(static_cast<double>(2LL), 32));
+    BASETYPE_IDENTITY_TEST(testI64, (int64_t)-pow(static_cast<double>(2LL), 32));
+    BASETYPE_IDENTITY_TEST(testI64, (int64_t)pow(static_cast<double>(2LL), 32) + 1);
+    BASETYPE_IDENTITY_TEST(testI64, (int64_t)-pow(static_cast<double>(2LL), 32) - 1);
+    BASETYPE_IDENTITY_TEST(testI64, (numeric_limits<int64_t>::max)());
+    BASETYPE_IDENTITY_TEST(testI64, (numeric_limits<int64_t>::min)());
+
     /**
      * DOUBLE TEST
      */
-    printf("testDouble(-5.2098523)");
-    double dub = testClient.testDouble(-5.2098523);
-    printf(" = %f\n", dub);
-    if ((dub - (-5.2098523)) > 0.001)
-        failCount++;
+    // Comparing double values with plain equality because Thrift handles full precision of double
+    BASETYPE_IDENTITY_TEST(testDouble, 0.0);
+    BASETYPE_IDENTITY_TEST(testDouble, -1.0);
+    BASETYPE_IDENTITY_TEST(testDouble, -5.2098523);
+    BASETYPE_IDENTITY_TEST(testDouble, -0.000341012439638598279);
+    BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast<double>(2), 32));
+    BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast<double>(2), 32) + 1);
+    BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast<double>(2), 53) - 1);
+    BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast<double>(2), 32));
+    BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast<double>(2), 32) - 1);
+    BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast<double>(2), 53) + 1);
+
+    try {
+      double expected = pow(static_cast<double>(10), 307);
+      cout << "testDouble(" << expected << ") = " << flush;
+      double actual = testClient.testDouble(expected);
+      cout << "(" << actual << ")" << endl;
+      if (expected - actual > pow(static_cast<double>(10), 292)) {
+        cout << "*** FAILED ***" << endl
+             << "Expected: " << expected << " but got: " << actual << endl;
+      }
+    } catch (TTransportException&) {
+      throw;
+    } catch (exception& ex) {
+      cout << "*** FAILED ***" << endl << ex.what() << endl;
+      return_code |= ERR_BASETYPES;
+    }
+
+    try {
+      double expected = pow(static_cast<double>(10), -292);
+      cout << "testDouble(" << expected << ") = " << flush;
+      double actual = testClient.testDouble(expected);
+      cout << "(" << actual << ")" << endl;
+      if (expected - actual > pow(static_cast<double>(10), -307)) {
+        cout << "*** FAILED ***" << endl
+             << "Expected: " << expected << " but got: " << actual << endl;
+      }
+    } catch (TTransportException&) {
+      throw;
+    } catch (exception& ex) {
+      cout << "*** FAILED ***" << endl << ex.what() << endl;
+      return_code |= ERR_BASETYPES;
+    }
+
+    /**
+     * BINARY TEST
+     */
+    for (string::size_type i = 0; i < 131073 && !return_code; ) {
+      return_code |= binary_test(testClient, i);
+      if (i > 0) { i *= 2; } else { ++i; }
+    }
+
 
     /**
      * STRUCT TEST
      */
-    printf("testStruct({\"Zero\", 1, -3, -5})");
+    cout << "testStruct({\"Zero\", 1, -3, -5})" << flush;
     Xtruct out;
     out.string_thing = "Zero";
     out.byte_thing = 1;
@@ -308,18 +599,20 @@
     out.i64_thing = -5;
     Xtruct in;
     testClient.testStruct(in, out);
-    printf(" = {\"%s\", %d, %d, %"PRId64"}\n",
+    printf(" = {\"%s\", %d, %d, %" PRId64 "}\n",
            in.string_thing.c_str(),
            (int)in.byte_thing,
            in.i32_thing,
            in.i64_thing);
-    if (in != out)
-    	failCount++;
+    if (in != out) {
+      cout << "*** FAILED ***" << endl;
+      return_code |= ERR_STRUCTS;
+    }
 
     /**
      * NESTED STRUCT TEST
      */
-    printf("testNest({1, {\"Zero\", 1, -3, -5}), 5}");
+    cout << "testNest({1, {\"Zero\", 1, -3, -5}), 5}" << flush;
     Xtruct2 out2;
     out2.byte_thing = 1;
     out2.struct_thing = out;
@@ -327,55 +620,85 @@
     Xtruct2 in2;
     testClient.testNest(in2, out2);
     in = in2.struct_thing;
-    printf(" = {%d, {\"%s\", %d, %d, %"PRId64"}, %d}\n",
+    printf(" = {%d, {\"%s\", %d, %d, %" PRId64 "}, %d}\n",
            in2.byte_thing,
            in.string_thing.c_str(),
            (int)in.byte_thing,
            in.i32_thing,
            in.i64_thing,
            in2.i32_thing);
-    if (in2 != out2)
-    	failCount++;
+    if (in2 != out2) {
+      cout << "*** FAILED ***" << endl;
+      return_code |= ERR_STRUCTS;
+    }
 
     /**
      * MAP TEST
      */
-    map<int32_t,int32_t> mapout;
+    map<int32_t, int32_t> mapout;
     for (int32_t i = 0; i < 5; ++i) {
-      mapout.insert(make_pair(i, i-10));
+      mapout.insert(make_pair(i, i - 10));
     }
-    printf("testMap({");
+    cout << "testMap({" << flush;
     map<int32_t, int32_t>::const_iterator m_iter;
     bool first = true;
     for (m_iter = mapout.begin(); m_iter != mapout.end(); ++m_iter) {
       if (first) {
         first = false;
       } else {
-        printf(", ");
+        cout << ",";
       }
-      printf("%d => %d", m_iter->first, m_iter->second);
+      cout << m_iter->first << " => " << m_iter->second;
     }
-    printf("})");
-    map<int32_t,int32_t> mapin;
+    cout << "})";
+    map<int32_t, int32_t> mapin;
     testClient.testMap(mapin, mapout);
-    printf(" = {");
+    cout << " = {";
     first = true;
     for (m_iter = mapin.begin(); m_iter != mapin.end(); ++m_iter) {
       if (first) {
         first = false;
       } else {
-        printf(", ");
+        cout << ",";
       }
-      printf("%d => %d", m_iter->first, m_iter->second);
+      cout << m_iter->first << " => " << m_iter->second;
     }
-    printf("}\n");
-    if (mapin != mapout)
-    	failCount++;
+    cout << "}" << endl;
+    if (mapin != mapout) {
+      cout << "*** FAILED ***" << endl;
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * STRING MAP TEST
-     *  missing
      */
+    cout << "testStringMap({a => 2, b => blah, some => thing}) = {" << flush;
+    map<string, string> smapin;
+    map<string, string> smapout;
+    smapin["a"] = "2";
+    smapin["b"] = "blah";
+    smapin["some"] = "thing";
+    try {
+      testClient.testStringMap(smapout, smapin);
+      first = true;
+      for (map<string, string>::const_iterator it = smapout.begin(); it != smapout.end(); ++it) {
+        if (first)
+          cout << ",";
+        else
+          first = false;
+        cout << it->first << " => " << it->second;
+      }
+      cout << "}" << endl;
+      if (smapin != smapout) {
+        cout << "*** FAILED ***" << endl;
+        return_code |= ERR_CONTAINERS;
+      }
+    } catch (TTransportException&) {
+      throw;
+    } catch (exception& ex) {
+      cout << "*** FAILED ***" << endl << ex.what() << endl;
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * SET TEST
@@ -384,254 +707,367 @@
     for (int32_t i = -2; i < 3; ++i) {
       setout.insert(i);
     }
-    printf("testSet({");
+    cout << "testSet({" << flush;
     set<int32_t>::const_iterator s_iter;
     first = true;
     for (s_iter = setout.begin(); s_iter != setout.end(); ++s_iter) {
       if (first) {
         first = false;
       } else {
-        printf(", ");
+        cout << ",";
       }
-      printf("%d", *s_iter);
+      cout << *s_iter;
     }
-    printf("})");
+    cout << "})";
     set<int32_t> setin;
     testClient.testSet(setin, setout);
-    printf(" = {");
+    cout << " = {";
     first = true;
     for (s_iter = setin.begin(); s_iter != setin.end(); ++s_iter) {
       if (first) {
         first = false;
       } else {
-        printf(", ");
+        cout << ",";
       }
-      printf("%d", *s_iter);
+      cout << *s_iter;
     }
-    printf("}\n");
-    if (setin != setout)
-    	failCount++;
+    cout << "}" << endl;
+    if (setin != setout) {
+      cout << "*** FAILED ***" << endl;
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * LIST TEST
      */
-    vector<int32_t> listout;
-    for (int32_t i = -2; i < 3; ++i) {
-      listout.push_back(i);
-    }
-    printf("testList({");
-    vector<int32_t>::const_iterator l_iter;
-    first = true;
-    for (l_iter = listout.begin(); l_iter != listout.end(); ++l_iter) {
-      if (first) {
-        first = false;
-      } else {
-        printf(", ");
+    cout << "testList(empty)" << flush;
+    try {
+      vector<int32_t> listout;
+      testClient.testList(listout, vector<int32_t>());
+      if (!listout.empty()) {
+        cout << "*** FAILED ***" << endl;
+        cout << "invalid length: " << listout.size() << endl;
+        return_code |= ERR_CONTAINERS;
       }
-      printf("%d", *l_iter);
+    } catch (TTransportException&) {
+      throw;
+    } catch (exception& ex) {
+      cout << "*** FAILED ***" << endl << ex.what() << endl;
+      return_code |= ERR_CONTAINERS;
     }
-    printf("})");
-    vector<int32_t> listin;
-    testClient.testList(listin, listout);
-    printf(" = {");
-    first = true;
-    for (l_iter = listin.begin(); l_iter != listin.end(); ++l_iter) {
-      if (first) {
-        first = false;
-      } else {
-        printf(", ");
+    try {
+      vector<int32_t> listout;
+      for (int32_t i = -2; i < 3; ++i) {
+        listout.push_back(i);
       }
-      printf("%d", *l_iter);
+      cout << "testList({" << flush;
+      vector<int32_t>::const_iterator l_iter;
+      first = true;
+      for (l_iter = listout.begin(); l_iter != listout.end(); ++l_iter) {
+        if (first) {
+          first = false;
+        } else {
+          cout << ",";
+        }
+        cout << *l_iter;
+      }
+      cout << "})";
+      vector<int32_t> listin;
+      testClient.testList(listin, listout);
+      cout << " = {";
+      first = true;
+      for (l_iter = listin.begin(); l_iter != listin.end(); ++l_iter) {
+        if (first) {
+          first = false;
+        } else {
+          cout << ",";
+        }
+        cout << *l_iter;
+      }
+      cout << "}" << endl;
+      if (listin != listout) {
+        cout << "*** FAILED ***" << endl;
+        return_code |= ERR_CONTAINERS;
+      }
+    } catch (TTransportException&) {
+      throw;
+    } catch (exception& ex) {
+      cout << "*** FAILED ***" << endl << ex.what() << endl;
+      return_code |= ERR_CONTAINERS;
     }
-    printf("}\n");
-    if (listin != listout)
-    	failCount++;
 
     /**
      * ENUM TEST
      */
-    printf("testEnum(ONE)");
+    cout << "testEnum(ONE)" << flush;
     Numberz::type ret = testClient.testEnum(Numberz::ONE);
-    printf(" = %d\n", ret);
-    if (ret != Numberz::ONE)
-    	failCount++;
+    cout << " = " << ret << endl;
+    if (ret != Numberz::ONE) {
+      cout << "*** FAILED ***" << endl;
+      return_code |= ERR_STRUCTS;
+    }
 
-    printf("testEnum(TWO)");
+    cout << "testEnum(TWO)" << flush;
     ret = testClient.testEnum(Numberz::TWO);
-    printf(" = %d\n", ret);
-    if (ret != Numberz::TWO)
-    	failCount++;
+    cout << " = " << ret << endl;
+    if (ret != Numberz::TWO) {
+      cout << "*** FAILED ***" << endl;
+      return_code |= ERR_STRUCTS;
+    }
 
-    printf("testEnum(THREE)");
+    cout << "testEnum(THREE)" << flush;
     ret = testClient.testEnum(Numberz::THREE);
-    printf(" = %d\n", ret);
-    if (ret != Numberz::THREE)
-    	failCount++;
+    cout << " = " << ret << endl;
+    if (ret != Numberz::THREE) {
+      cout << "*** FAILED ***" << endl;
+      return_code |= ERR_STRUCTS;
+    }
 
-    printf("testEnum(FIVE)");
+    cout << "testEnum(FIVE)" << flush;
     ret = testClient.testEnum(Numberz::FIVE);
-    printf(" = %d\n", ret);
-    if (ret != Numberz::FIVE)
-    	failCount++;
+    cout << " = " << ret << endl;
+    if (ret != Numberz::FIVE) {
+      cout << "*** FAILED ***" << endl;
+      return_code |= ERR_STRUCTS;
+    }
 
-    printf("testEnum(EIGHT)");
+    cout << "testEnum(EIGHT)" << flush;
     ret = testClient.testEnum(Numberz::EIGHT);
-    printf(" = %d\n", ret);
-    if (ret != Numberz::EIGHT)
-    	failCount++;
+    cout << " = " << ret << endl;
+    if (ret != Numberz::EIGHT) {
+      cout << "*** FAILED ***" << endl;
+      return_code |= ERR_STRUCTS;
+    }
 
     /**
      * TYPEDEF TEST
      */
-    printf("testTypedef(309858235082523)");
+    cout << "testTypedef(309858235082523)" << flush;
     UserId uid = testClient.testTypedef(309858235082523LL);
-    printf(" = %"PRId64"\n", uid);
-    if (uid != 309858235082523LL)
-    	failCount++;
+    cout << " = " << uid << endl;
+    if (uid != 309858235082523LL) {
+      cout << "*** FAILED ***" << endl;
+      return_code |= ERR_STRUCTS;
+    }
 
     /**
      * NESTED MAP TEST
      */
-    printf("testMapMap(1)");
+    cout << "testMapMap(1)" << flush;
     map<int32_t, map<int32_t, int32_t> > mm;
     testClient.testMapMap(mm, 1);
-    printf(" = {");
+    cout << " = {";
     map<int32_t, map<int32_t, int32_t> >::const_iterator mi;
     for (mi = mm.begin(); mi != mm.end(); ++mi) {
       printf("%d => {", mi->first);
       map<int32_t, int32_t>::const_iterator mi2;
       for (mi2 = mi->second.begin(); mi2 != mi->second.end(); ++mi2) {
-        printf("%d => %d, ", mi2->first, mi2->second);
+        cout << mi2->first << " => " << mi2->second;
       }
-      printf("}, ");
+      cout << "}, ";
     }
-    printf("}\n");
+    cout << "}" << endl;
+    if (mm.size() != 2 ||
+        mm[-4][-4] != -4 ||
+        mm[-4][-3] != -3 ||
+        mm[-4][-2] != -2 ||
+        mm[-4][-1] != -1 ||
+        mm[4][4] != 4 ||
+        mm[4][3] != 3 ||
+        mm[4][2] != 2 ||
+        mm[4][1] != 1) {
+      cout << "*** FAILED ***" << endl;
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * INSANITY TEST
      */
-    Insanity insane;
-    insane.userMap.insert(make_pair(Numberz::FIVE, 5000));
-    Xtruct truck;
-    truck.string_thing = "Truck";
-    truck.byte_thing = 8;
-    truck.i32_thing = 8;
-    truck.i64_thing = 8;
-    insane.xtructs.push_back(truck);
-    printf("testInsanity()");
-    map<UserId, map<Numberz::type,Insanity> > whoa;
-    testClient.testInsanity(whoa, insane);
-    printf(" = {");
-    map<UserId, map<Numberz::type,Insanity> >::const_iterator i_iter;
-    for (i_iter = whoa.begin(); i_iter != whoa.end(); ++i_iter) {
-      printf("%"PRId64" => {", i_iter->first);
-      map<Numberz::type,Insanity>::const_iterator i2_iter;
-      for (i2_iter = i_iter->second.begin();
-           i2_iter != i_iter->second.end();
-           ++i2_iter) {
-        printf("%d => {", i2_iter->first);
-        map<Numberz::type, UserId> userMap = i2_iter->second.userMap;
-        map<Numberz::type, UserId>::const_iterator um;
-        printf("{");
-        for (um = userMap.begin(); um != userMap.end(); ++um) {
-          printf("%d => %"PRId64", ", um->first, um->second);
-        }
-        printf("}, ");
+    if (!noinsane) {
+      Insanity insane;
+      insane.userMap.insert(make_pair(Numberz::FIVE, 5));
+      insane.userMap.insert(make_pair(Numberz::EIGHT, 8));
+      Xtruct truck;
+      truck.string_thing = "Goodbye4";
+      truck.byte_thing = 4;
+      truck.i32_thing = 4;
+      truck.i64_thing = 4;
+      Xtruct truck2;
+      truck2.string_thing = "Hello2";
+      truck2.byte_thing = 2;
+      truck2.i32_thing = 2;
+      truck2.i64_thing = 2;
+      insane.xtructs.push_back(truck);
+      insane.xtructs.push_back(truck2);
+      cout << "testInsanity()" << flush;
+      map<UserId, map<Numberz::type, Insanity> > whoa;
+      testClient.testInsanity(whoa, insane);
+      cout << " = {";
+      map<UserId, map<Numberz::type, Insanity> >::const_iterator i_iter;
+      for (i_iter = whoa.begin(); i_iter != whoa.end(); ++i_iter) {
+        printf("%" PRId64 " => {", i_iter->first);
+        map<Numberz::type, Insanity>::const_iterator i2_iter;
+        for (i2_iter = i_iter->second.begin(); i2_iter != i_iter->second.end(); ++i2_iter) {
+          printf("%d => {", i2_iter->first);
+          map<Numberz::type, UserId> userMap = i2_iter->second.userMap;
+          map<Numberz::type, UserId>::const_iterator um;
+          cout << "{";
+          for (um = userMap.begin(); um != userMap.end(); ++um) {
+            cout << um->first << " => " << um->second;
+          }
+          cout << "}, ";
 
-        vector<Xtruct> xtructs = i2_iter->second.xtructs;
-        vector<Xtruct>::const_iterator x;
-        printf("{");
-        for (x = xtructs.begin(); x != xtructs.end(); ++x) {
-          printf("{\"%s\", %d, %d, %"PRId64"}, ",
-                 x->string_thing.c_str(),
-                 (int)x->byte_thing,
-                 x->i32_thing,
-                 x->i64_thing);
-        }
-        printf("}");
+          vector<Xtruct> xtructs = i2_iter->second.xtructs;
+          vector<Xtruct>::const_iterator x;
+          cout << "{";
+          for (x = xtructs.begin(); x != xtructs.end(); ++x) {
+            printf("{\"%s\", %d, %d, %" PRId64 "}, ",
+                   x->string_thing.c_str(),
+                   (int)x->byte_thing,
+                   x->i32_thing,
+                   x->i64_thing);
+          }
+          cout << "}";
 
-        printf("}, ");
+          cout << "}, ";
+        }
+        cout << "}, ";
       }
-      printf("}, ");
+      cout << "}" << endl;
+      bool failed = false;
+      map<UserId, map<Numberz::type, Insanity> >::const_iterator it1 = whoa.find(UserId(1));
+      if (whoa.size() != 2) {
+        failed = true;
+      }
+      if (it1 == whoa.end()) {
+        failed = true;
+      } else {
+        map<Numberz::type, Insanity>::const_iterator it12 = it1->second.find(Numberz::TWO);
+        if (it12 == it1->second.end() || it12->second != insane) {
+          failed = true;
+        }
+        map<Numberz::type, Insanity>::const_iterator it13 = it1->second.find(Numberz::THREE);
+        if (it13 == it1->second.end() || it13->second != insane) {
+          failed = true;
+        }
+      }
+      map<UserId, map<Numberz::type, Insanity> >::const_iterator it2 = whoa.find(UserId(2));
+      if (it2 == whoa.end()) {
+        failed = true;
+      } else {
+        map<Numberz::type, Insanity>::const_iterator it26 = it2->second.find(Numberz::SIX);
+        if (it26 == it2->second.end() || it26->second != Insanity()) {
+          failed = true;
+        }
+      }
+      if (failed) {
+        cout << "*** FAILED ***" << endl;
+        return_code |= ERR_STRUCTS;
+      }
     }
-    printf("}\n");
+
+    /**
+     * MULTI TEST
+     */
+    cout << "testMulti()" << endl;
+    try {
+      map<int16_t, string> mul_map;
+      Xtruct mul_result;
+      mul_map[1] = "blah";
+      mul_map[2] = "thing";
+      testClient.testMulti(mul_result, 42, 4242, 424242, mul_map, Numberz::EIGHT, UserId(24));
+      Xtruct xxs;
+      xxs.string_thing = "Hello2";
+      xxs.byte_thing = 42;
+      xxs.i32_thing = 4242;
+      xxs.i64_thing = 424242;
+      if (mul_result != xxs) {
+        cout << "*** FAILED ***" << endl;
+        return_code |= ERR_STRUCTS;
+      }
+    } catch (TTransportException&) {
+      throw;
+    } catch (exception& ex) {
+      cout << "*** FAILED ***" << endl << ex.what() << endl;
+      return_code |= ERR_STRUCTS;
+    }
 
     /* test exception */
 
     try {
-      printf("testClient.testException(\"Xception\") =>");
+      cout << "testClient.testException(\"Xception\") =>" << flush;
       testClient.testException("Xception");
-      printf("  void\nFAILURE\n");
-      failCount++;
+      cout << "  void\n*** FAILED ***" << endl;
+      return_code |= ERR_EXCEPTIONS;
 
-    } catch(Xception& e) {
+    } catch (Xception& e) {
       printf("  {%u, \"%s\"}\n", e.errorCode, e.message.c_str());
     }
 
     try {
-        printf("testClient.testException(\"TException\") =>");
-        testClient.testException("TException");
-        printf("  void\nFAILURE\n");
-        failCount++;
+      cout << "testClient.testException(\"TException\") =>" << flush;
+      testClient.testException("TException");
+      cout << "  void\n*** FAILED ***" << endl;
+      return_code |= ERR_EXCEPTIONS;
 
-      } catch(TException& e) {
-        printf("  Caught TException\n");
-      }
+    } catch (const TException&) {
+      cout << "  Caught TException" << endl;
+    }
 
     try {
-      printf("testClient.testException(\"success\") =>");
+      cout << "testClient.testException(\"success\") =>" << flush;
       testClient.testException("success");
-      printf("  void\n");
-    } catch(...) {
-      printf("  exception\nFAILURE\n");
-      failCount++;
+      cout << "  void" << endl;
+    } catch (exception & ex) {                                                                       \
+      cout << "*** FAILED ***" << endl << ex.what() << endl;
+      return_code |= ERR_EXCEPTIONS;
     }
 
     /* test multi exception */
 
     try {
-      printf("testClient.testMultiException(\"Xception\", \"test 1\") =>");
+      cout << "testClient.testMultiException(\"Xception\", \"test 1\") =>" << flush;
       Xtruct result;
       testClient.testMultiException(result, "Xception", "test 1");
-      printf("  result\nFAILURE\n");
-      failCount++;
-    } catch(Xception& e) {
+      cout << "  result\n*** FAILED ***" << endl;
+      return_code |= ERR_EXCEPTIONS;
+    } catch (Xception& e) {
       printf("  {%u, \"%s\"}\n", e.errorCode, e.message.c_str());
     }
 
     try {
-      printf("testClient.testMultiException(\"Xception2\", \"test 2\") =>");
+      cout << "testClient.testMultiException(\"Xception2\", \"test 2\") =>" << flush;
       Xtruct result;
       testClient.testMultiException(result, "Xception2", "test 2");
-      printf("  result\nFAILURE\n");
-      failCount++;
+      cout << "  result\n*** FAILED ***" << endl;
+      return_code |= ERR_EXCEPTIONS;
 
-    } catch(Xception2& e) {
+    } catch (Xception2& e) {
       printf("  {%u, {\"%s\"}}\n", e.errorCode, e.struct_thing.string_thing.c_str());
     }
 
     try {
-      printf("testClient.testMultiException(\"success\", \"test 3\") =>");
+      cout << "testClient.testMultiException(\"success\", \"test 3\") =>" << flush;
       Xtruct result;
       testClient.testMultiException(result, "success", "test 3");
       printf("  {{\"%s\"}}\n", result.string_thing.c_str());
-    } catch(...) {
-      printf("  exception\nFAILURE\n");
-      failCount++;
+    } catch (exception & ex) {                                                                       \
+      cout << "*** FAILED ***" << endl << ex.what() << endl;
+      return_code |= ERR_EXCEPTIONS;
     }
 
     /* test oneway void */
     {
-        printf("testClient.testOneway(3) =>");
-        uint64_t startOneway = now();
-        testClient.testOneway(3);
-        uint64_t elapsed = now() - startOneway;
-        if (elapsed > 200 * 1000) { // 0.2 seconds
-            printf("  FAILURE - took %.2f ms\n", (double)elapsed/1000.0);
-            failCount++;
-        } else {
-            printf("  success - took %.2f ms\n", (double)elapsed/1000.0);
-        }
+      cout << "testClient.testOneway(1) =>" << flush;
+      uint64_t startOneway = now();
+      testClient.testOneway(1);
+      uint64_t elapsed = now() - startOneway;
+      if (elapsed > 200 * 1000) { // 0.2 seconds
+        printf("*** FAILED *** - took %.2f ms\n", (double)elapsed / 1000.0);
+      return_code |= ERR_BASETYPES;
+      } else {
+        printf("  success - took %.2f ms\n", (double)elapsed / 1000.0);
+      }
     }
 
     /**
@@ -645,17 +1081,18 @@
     /**
      * I32 TEST
      */
-    printf("re-test testI32(-1)");
-    i32 = testClient.testI32(-1);
-    printf(" = %d\n", i32);
+    cout << "re-test testI32(-1)" << flush;
+    int i32 = testClient.testI32(-1);
+    cout << " = " << i32 << endl;
     if (i32 != -1)
-        failCount++;
+      return_code |= ERR_BASETYPES;
 
+    cout << endl << "All tests done." << endl << flush;
 
     uint64_t stop = now();
-    uint64_t tot = stop-start;
+    uint64_t tot = stop - start;
 
-    printf("Total time: %"PRIu64" us\n", stop-start);
+    cout << "Total time: " << stop - start << " us" << endl;
 
     time_tot += tot;
     if (time_min == 0 || tot < time_min) {
@@ -665,17 +1102,79 @@
       time_max = tot;
     }
 
+    cout << flush;
     transport->close();
   }
 
-  //  printf("\nSocket syscalls: %u", g_socket_syscalls);
-  printf("\nAll tests done.\n");
 
   uint64_t time_avg = time_tot / numTests;
 
-  printf("Min time: %"PRIu64" us\n", time_min);
-  printf("Max time: %"PRIu64" us\n", time_max);
-  printf("Avg time: %"PRIu64" us\n", time_avg);
+  cout << "Min time: " << time_min << " us" << endl;
+  cout << "Max time: " << time_max << " us" << endl;
+  cout << "Avg time: " << time_avg << " us" << endl;
 
-  return failCount;
+  return return_code;
+}
+
+void binary_fill(std::string& str, string::size_type siz)
+{
+    static const signed char bin_data[256]
+        = {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114,
+           -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99,
+           -98,  -97,  -96,  -95,  -94,  -93,  -92,  -91,  -90,  -89,  -88,  -87,  -86,  -85,  -84,
+           -83,  -82,  -81,  -80,  -79,  -78,  -77,  -76,  -75,  -74,  -73,  -72,  -71,  -70,  -69,
+           -68,  -67,  -66,  -65,  -64,  -63,  -62,  -61,  -60,  -59,  -58,  -57,  -56,  -55,  -54,
+           -53,  -52,  -51,  -50,  -49,  -48,  -47,  -46,  -45,  -44,  -43,  -42,  -41,  -40,  -39,
+           -38,  -37,  -36,  -35,  -34,  -33,  -32,  -31,  -30,  -29,  -28,  -27,  -26,  -25,  -24,
+           -23,  -22,  -21,  -20,  -19,  -18,  -17,  -16,  -15,  -14,  -13,  -12,  -11,  -10,  -9,
+           -8,   -7,   -6,   -5,   -4,   -3,   -2,   -1,   0,    1,    2,    3,    4,    5,    6,
+           7,    8,    9,    10,   11,   12,   13,   14,   15,   16,   17,   18,   19,   20,   21,
+           22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,
+           37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51,
+           52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,   64,   65,   66,
+           67,   68,   69,   70,   71,   72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
+           82,   83,   84,   85,   86,   87,   88,   89,   90,   91,   92,   93,   94,   95,   96,
+           97,   98,   99,   100,  101,  102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
+           112,  113,  114,  115,  116,  117,  118,  119,  120,  121,  122,  123,  124,  125,  126,
+           127};
+
+    str.resize(siz);
+    char *ptr = &str[0];
+    string::size_type pos = 0;
+    for (string::size_type i = 0; i < siz; ++i)
+    {
+        if (pos == 255) { pos = 0; } else { ++pos; }
+        *ptr++ = bin_data[pos];
+    }
+}
+
+int binary_test(ThriftTestClient& testClient, string::size_type siz)
+{
+    string bin_request;
+    string bin_result;
+
+    cout << "testBinary(siz = " << siz << ")" << endl;
+    binary_fill(bin_request, siz);
+    try {
+        testClient.testBinary(bin_result, bin_request);
+
+        if (bin_request.size() != bin_result.size()) {
+            cout << "*** FAILED: request size " << bin_request.size() << "; result size " << bin_result.size() << endl;
+            return ERR_BASETYPES;
+        }
+
+        for (string::size_type i = 0; i < siz; ++i) {
+            if (bin_request.at(i) != bin_result.at(i)) {
+                cout << "*** FAILED: at position " << i << " request[i] is h" << hex << bin_request.at(i) << " result[i] is h" << hex << bin_result.at(i) << endl;
+                return ERR_BASETYPES;
+            }
+        }
+    } catch (TTransportException&) {
+        throw;
+    } catch (exception& ex) {
+        cout << "*** FAILED ***" << endl << ex.what() << endl;
+        return ERR_BASETYPES;
+    }
+
+    return 0;
 }
diff --git a/test/cpp/src/TestServer.cpp b/test/cpp/src/TestServer.cpp
index c99fbac..6222017 100644
--- a/test/cpp/src/TestServer.cpp
+++ b/test/cpp/src/TestServer.cpp
@@ -17,61 +17,93 @@
  * under the License.
  */
 
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-
-#include <thrift/concurrency/ThreadManager.h>
-#include <thrift/concurrency/PlatformThreadFactory.h>
-#include <thrift/protocol/TBinaryProtocol.h>
-#include <thrift/protocol/TJSONProtocol.h>
-#include <thrift/server/TSimpleServer.h>
-#include <thrift/server/TThreadedServer.h>
-#include <thrift/server/TThreadPoolServer.h>
-#include <thrift/async/TEvhttpServer.h>
 #include <thrift/async/TAsyncBufferProcessor.h>
 #include <thrift/async/TAsyncProtocolProcessor.h>
+#include <thrift/async/TEvhttpServer.h>
+#include <thrift/concurrency/PlatformThreadFactory.h>
+#include <thrift/concurrency/ThreadManager.h>
+#include <thrift/processor/TMultiplexedProcessor.h>
+#include <thrift/protocol/TBinaryProtocol.h>
+#include <thrift/protocol/TCompactProtocol.h>
+#include <thrift/protocol/THeaderProtocol.h>
+#include <thrift/protocol/TJSONProtocol.h>
 #include <thrift/server/TNonblockingServer.h>
-#include <thrift/transport/TServerSocket.h>
-#include <thrift/transport/TSSLServerSocket.h>
-#include <thrift/transport/TSSLSocket.h>
+#include <thrift/server/TSimpleServer.h>
+#include <thrift/server/TThreadPoolServer.h>
+#include <thrift/server/TThreadedServer.h>
 #include <thrift/transport/THttpServer.h>
 #include <thrift/transport/THttpTransport.h>
+#include <thrift/transport/TNonblockingSSLServerSocket.h>
+#include <thrift/transport/TNonblockingServerSocket.h>
+#include <thrift/transport/TSSLServerSocket.h>
+#include <thrift/transport/TSSLSocket.h>
+#include <thrift/transport/TServerSocket.h>
 #include <thrift/transport/TTransportUtils.h>
+#include <thrift/transport/TZlibTransport.h>
+
+#include "SecondService.h"
 #include "ThriftTest.h"
 
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
 #include <iostream>
 #include <stdexcept>
 #include <sstream>
 
+#include <boost/algorithm/string.hpp>
 #include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
 
-#include <signal.h>
+#if _WIN32
+#include <thrift/windows/TWinsockSingleton.h>
+#endif
 
 using namespace std;
-using namespace boost;
 
 using namespace apache::thrift;
+using namespace apache::thrift::async;
 using namespace apache::thrift::concurrency;
 using namespace apache::thrift::protocol;
 using namespace apache::thrift::transport;
 using namespace apache::thrift::server;
-using namespace apache::thrift::async;
 
 using namespace thrift::test;
 
+// to handle a controlled shutdown, signal handling is mandatory
+#ifdef HAVE_SIGNAL_H
+apache::thrift::concurrency::Monitor gMonitor;
+void signal_handler(int signum)
+{
+  if (signum == SIGINT) {
+    gMonitor.notifyAll();
+  }
+}
+#endif
+
 class TestHandler : public ThriftTestIf {
- public:
+public:
   TestHandler() {}
 
-  void testVoid() {
-    printf("testVoid()\n");
-  }
+  void testVoid() { printf("testVoid()\n"); }
 
-  void testString(string& out, const string &thing) {
+  void testString(string& out, const string& thing) {
     printf("testString(\"%s\")\n", thing.c_str());
     out = thing;
   }
 
+  bool testBool(const bool thing) {
+    printf("testBool(%s)\n", thing ? "true" : "false");
+    return thing;
+  }
+
   int8_t testByte(const int8_t thing) {
     printf("testByte(%d)\n", (int)thing);
     return thing;
@@ -83,7 +115,7 @@
   }
 
   int64_t testI64(const int64_t thing) {
-    printf("testI64(%"PRId64")\n", thing);
+    printf("testI64(%" PRId64 ")\n", thing);
     return thing;
   }
 
@@ -92,18 +124,35 @@
     return thing;
   }
 
-  void testStruct(Xtruct& out, const Xtruct &thing) {
-    printf("testStruct({\"%s\", %d, %d, %"PRId64"})\n", thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing);
+  void testBinary(std::string& _return, const std::string& thing) {
+    std::ostringstream hexstr;
+    hexstr << std::hex << thing;
+    printf("testBinary(%lu: %s)\n", safe_numeric_cast<unsigned long>(thing.size()), hexstr.str().c_str());
+    _return = thing;
+  }
+
+  void testStruct(Xtruct& out, const Xtruct& thing) {
+    printf("testStruct({\"%s\", %d, %d, %" PRId64 "})\n",
+           thing.string_thing.c_str(),
+           (int)thing.byte_thing,
+           thing.i32_thing,
+           thing.i64_thing);
     out = thing;
   }
 
   void testNest(Xtruct2& out, const Xtruct2& nest) {
-    const Xtruct &thing = nest.struct_thing;
-    printf("testNest({%d, {\"%s\", %d, %d, %"PRId64"}, %d})\n", (int)nest.byte_thing, thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing, nest.i32_thing);
+    const Xtruct& thing = nest.struct_thing;
+    printf("testNest({%d, {\"%s\", %d, %d, %" PRId64 "}, %d})\n",
+           (int)nest.byte_thing,
+           thing.string_thing.c_str(),
+           (int)thing.byte_thing,
+           thing.i32_thing,
+           thing.i64_thing,
+           nest.i32_thing);
     out = nest;
   }
 
-  void testMap(map<int32_t, int32_t> &out, const map<int32_t, int32_t> &thing) {
+  void testMap(map<int32_t, int32_t>& out, const map<int32_t, int32_t>& thing) {
     printf("testMap({");
     map<int32_t, int32_t>::const_iterator m_iter;
     bool first = true;
@@ -119,7 +168,8 @@
     out = thing;
   }
 
-  void testStringMap(map<std::string, std::string> &out, const map<std::string, std::string> &thing) {
+  void testStringMap(map<std::string, std::string>& out,
+                     const map<std::string, std::string>& thing) {
     printf("testMap({");
     map<std::string, std::string>::const_iterator m_iter;
     bool first = true;
@@ -135,7 +185,7 @@
     out = thing;
   }
 
-  void testSet(set<int32_t> &out, const set<int32_t> &thing) {
+  void testSet(set<int32_t>& out, const set<int32_t>& thing) {
     printf("testSet({");
     set<int32_t>::const_iterator s_iter;
     bool first = true;
@@ -151,7 +201,7 @@
     out = thing;
   }
 
-  void testList(vector<int32_t> &out, const vector<int32_t> &thing) {
+  void testList(vector<int32_t>& out, const vector<int32_t>& thing) {
     printf("testList({");
     vector<int32_t>::const_iterator l_iter;
     bool first = true;
@@ -173,54 +223,33 @@
   }
 
   UserId testTypedef(const UserId thing) {
-    printf("testTypedef(%"PRId64")\n", thing);
+    printf("testTypedef(%" PRId64 ")\n", thing);
     return thing;
   }
 
-  void testMapMap(map<int32_t, map<int32_t,int32_t> > &mapmap, const int32_t hello) {
+  void testMapMap(map<int32_t, map<int32_t, int32_t> >& mapmap, const int32_t hello) {
     printf("testMapMap(%d)\n", hello);
 
-    map<int32_t,int32_t> pos;
-    map<int32_t,int32_t> neg;
+    map<int32_t, int32_t> pos;
+    map<int32_t, int32_t> neg;
     for (int i = 1; i < 5; i++) {
-      pos.insert(make_pair(i,i));
-      neg.insert(make_pair(-i,-i));
+      pos.insert(make_pair(i, i));
+      neg.insert(make_pair(-i, -i));
     }
 
     mapmap.insert(make_pair(4, pos));
     mapmap.insert(make_pair(-4, neg));
-
   }
 
-  void testInsanity(map<UserId, map<Numberz::type,Insanity> > &insane, const Insanity &argument) {
-    (void) argument;
+  void testInsanity(map<UserId, map<Numberz::type, Insanity> >& insane, const Insanity& argument) {
     printf("testInsanity()\n");
 
-    Xtruct hello;
-    hello.string_thing = "Hello2";
-    hello.byte_thing = 2;
-    hello.i32_thing = 2;
-    hello.i64_thing = 2;
-
-    Xtruct goodbye;
-    goodbye.string_thing = "Goodbye4";
-    goodbye.byte_thing = 4;
-    goodbye.i32_thing = 4;
-    goodbye.i64_thing = 4;
-
-    Insanity crazy;
-    crazy.userMap.insert(make_pair(Numberz::EIGHT, 8));
-    crazy.xtructs.push_back(goodbye);
-
     Insanity looney;
-    crazy.userMap.insert(make_pair(Numberz::FIVE, 5));
-    crazy.xtructs.push_back(hello);
-
     map<Numberz::type, Insanity> first_map;
     map<Numberz::type, Insanity> second_map;
 
-    first_map.insert(make_pair(Numberz::TWO, crazy));
-    first_map.insert(make_pair(Numberz::THREE, crazy));
+    first_map.insert(make_pair(Numberz::TWO, argument));
+    first_map.insert(make_pair(Numberz::THREE, argument));
 
     second_map.insert(make_pair(Numberz::SIX, looney));
 
@@ -229,19 +258,17 @@
 
     printf("return");
     printf(" = {");
-    map<UserId, map<Numberz::type,Insanity> >::const_iterator i_iter;
+    map<UserId, map<Numberz::type, Insanity> >::const_iterator i_iter;
     for (i_iter = insane.begin(); i_iter != insane.end(); ++i_iter) {
-      printf("%"PRId64" => {", i_iter->first);
-      map<Numberz::type,Insanity>::const_iterator i2_iter;
-      for (i2_iter = i_iter->second.begin();
-           i2_iter != i_iter->second.end();
-           ++i2_iter) {
+      printf("%" PRId64 " => {", i_iter->first);
+      map<Numberz::type, Insanity>::const_iterator i2_iter;
+      for (i2_iter = i_iter->second.begin(); i2_iter != i_iter->second.end(); ++i2_iter) {
         printf("%d => {", i2_iter->first);
         map<Numberz::type, UserId> userMap = i2_iter->second.userMap;
         map<Numberz::type, UserId>::const_iterator um;
         printf("{");
         for (um = userMap.begin(); um != userMap.end(); ++um) {
-          printf("%d => %"PRId64", ", um->first, um->second);
+          printf("%d => %" PRId64 ", ", um->first, um->second);
         }
         printf("}, ");
 
@@ -249,7 +276,11 @@
         vector<Xtruct>::const_iterator x;
         printf("{");
         for (x = xtructs.begin(); x != xtructs.end(); ++x) {
-          printf("{\"%s\", %d, %d, %"PRId64"}, ", x->string_thing.c_str(), (int)x->byte_thing, x->i32_thing, x->i64_thing);
+          printf("{\"%s\", %d, %d, %" PRId64 "}, ",
+                 x->string_thing.c_str(),
+                 (int)x->byte_thing,
+                 x->i32_thing,
+                 x->i64_thing);
         }
         printf("}");
 
@@ -258,15 +289,19 @@
       printf("}, ");
     }
     printf("}\n");
-
-
   }
 
-  void testMulti(Xtruct &hello, const int8_t arg0, const int32_t arg1, const int64_t arg2, const std::map<int16_t, std::string>  &arg3, const Numberz::type arg4, const UserId arg5) {
-    (void) arg3;
-    (void) arg4;
-    (void) arg5;
-    
+  void testMulti(Xtruct& hello,
+                 const int8_t arg0,
+                 const int32_t arg1,
+                 const int64_t arg2,
+                 const std::map<int16_t, std::string>& arg3,
+                 const Numberz::type arg4,
+                 const UserId arg5) {
+    (void)arg3;
+    (void)arg4;
+    (void)arg5;
+
     printf("testMulti()\n");
 
     hello.string_thing = "Hello2";
@@ -275,9 +310,7 @@
     hello.i64_thing = (int64_t)arg2;
   }
 
-  void testException(const std::string &arg)
-    throw(Xception, apache::thrift::TException)
-  {
+  void testException(const std::string& arg) {
     printf("testException(%s)\n", arg.c_str());
     if (arg.compare("Xception") == 0) {
       Xception e;
@@ -294,7 +327,9 @@
     }
   }
 
-  void testMultiException(Xtruct &result, const std::string &arg0, const std::string &arg1) throw(Xception, Xception2) {
+  void testMultiException(Xtruct& result,
+                          const std::string& arg0,
+                          const std::string& arg1) {
 
     printf("testMultiException(%s, %s)\n", arg0.c_str(), arg1.c_str());
 
@@ -314,35 +349,35 @@
     }
   }
 
-  void testOneway(int sleepFor) {
-    printf("testOneway(%d): Sleeping...\n", sleepFor);
-    sleep(sleepFor);
-    printf("testOneway(%d): done sleeping!\n", sleepFor);
+  void testOneway(const int32_t aNum) {
+    printf("testOneway(%d): call received\n", aNum);
   }
 };
 
+class SecondHandler : public SecondServiceIf
+{
+  public:
+    void secondtestString(std::string& result, const std::string& thing)
+    { result = "testString(\"" + thing + "\")"; }
+};
 
 class TestProcessorEventHandler : public TProcessorEventHandler {
   virtual void* getContext(const char* fn_name, void* serverContext) {
-    (void) serverContext;
+    (void)serverContext;
     return new std::string(fn_name);
   }
   virtual void freeContext(void* ctx, const char* fn_name) {
-    (void) fn_name;
+    (void)fn_name;
     delete static_cast<std::string*>(ctx);
   }
-  virtual void preRead(void* ctx, const char* fn_name) {
-    communicate("preRead", ctx, fn_name);
-  }
+  virtual void preRead(void* ctx, const char* fn_name) { communicate("preRead", ctx, fn_name); }
   virtual void postRead(void* ctx, const char* fn_name, uint32_t bytes) {
-    (void) bytes;
+    (void)bytes;
     communicate("postRead", ctx, fn_name);
   }
-  virtual void preWrite(void* ctx, const char* fn_name) {
-    communicate("preWrite", ctx, fn_name);
-  }
+  virtual void preWrite(void* ctx, const char* fn_name) { communicate("preWrite", ctx, fn_name); }
   virtual void postWrite(void* ctx, const char* fn_name, uint32_t bytes) {
-    (void) bytes;
+    (void)bytes;
     communicate("postWrite", ctx, fn_name);
   }
   virtual void asyncComplete(void* ctx, const char* fn_name) {
@@ -357,175 +392,220 @@
   }
 };
 
-
 class TestHandlerAsync : public ThriftTestCobSvIf {
 public:
-  TestHandlerAsync(boost::shared_ptr<TestHandler>& handler) : _delegate(handler) {}
+  TestHandlerAsync(std::shared_ptr<TestHandler>& handler) : _delegate(handler) {}
   virtual ~TestHandlerAsync() {}
 
-  virtual void testVoid(std::tr1::function<void()> cob) {
+  virtual void testVoid(std::function<void()> cob) {
     _delegate->testVoid();
     cob();
   }
 
-  virtual void testString(std::tr1::function<void(std::string const& _return)> cob, const std::string& thing) {
+  virtual void testString(std::function<void(std::string const& _return)> cob,
+                          const std::string& thing) {
     std::string res;
     _delegate->testString(res, thing);
     cob(res);
   }
 
-  virtual void testByte(std::tr1::function<void(int8_t const& _return)> cob, const int8_t thing) {
+  virtual void testBool(std::function<void(bool const& _return)> cob, const bool thing) {
+    bool res = _delegate->testBool(thing);
+    cob(res);
+  }
+
+  virtual void testByte(std::function<void(int8_t const& _return)> cob, const int8_t thing) {
     int8_t res = _delegate->testByte(thing);
     cob(res);
   }
 
-  virtual void testI32(std::tr1::function<void(int32_t const& _return)> cob, const int32_t thing) {
+  virtual void testI32(std::function<void(int32_t const& _return)> cob, const int32_t thing) {
     int32_t res = _delegate->testI32(thing);
     cob(res);
   }
 
-  virtual void testI64(std::tr1::function<void(int64_t const& _return)> cob, const int64_t thing) {
+  virtual void testI64(std::function<void(int64_t const& _return)> cob, const int64_t thing) {
     int64_t res = _delegate->testI64(thing);
     cob(res);
   }
 
-  virtual void testDouble(std::tr1::function<void(double const& _return)> cob, const double thing) {
+  virtual void testDouble(std::function<void(double const& _return)> cob, const double thing) {
     double res = _delegate->testDouble(thing);
     cob(res);
   }
 
-  virtual void testStruct(std::tr1::function<void(Xtruct const& _return)> cob, const Xtruct& thing) {
+  virtual void testBinary(std::function<void(std::string const& _return)> cob,
+                          const std::string& thing) {
+    std::string res;
+    _delegate->testBinary(res, thing);
+    cob(res);
+  }
+
+  virtual void testStruct(std::function<void(Xtruct const& _return)> cob, const Xtruct& thing) {
     Xtruct res;
     _delegate->testStruct(res, thing);
     cob(res);
   }
 
-  virtual void testNest(std::tr1::function<void(Xtruct2 const& _return)> cob, const Xtruct2& thing) {
+  virtual void testNest(std::function<void(Xtruct2 const& _return)> cob, const Xtruct2& thing) {
     Xtruct2 res;
     _delegate->testNest(res, thing);
     cob(res);
   }
 
-  virtual void testMap(std::tr1::function<void(std::map<int32_t, int32_t>  const& _return)> cob, const std::map<int32_t, int32_t> & thing) {
+  virtual void testMap(std::function<void(std::map<int32_t, int32_t> const& _return)> cob,
+                       const std::map<int32_t, int32_t>& thing) {
     std::map<int32_t, int32_t> res;
     _delegate->testMap(res, thing);
     cob(res);
   }
 
-  virtual void testStringMap(std::tr1::function<void(std::map<std::string, std::string>  const& _return)> cob, const std::map<std::string, std::string> & thing) {
+  virtual void testStringMap(
+      std::function<void(std::map<std::string, std::string> const& _return)> cob,
+      const std::map<std::string, std::string>& thing) {
     std::map<std::string, std::string> res;
     _delegate->testStringMap(res, thing);
     cob(res);
   }
 
-  virtual void testSet(std::tr1::function<void(std::set<int32_t>  const& _return)> cob, const std::set<int32_t> & thing) {
+  virtual void testSet(std::function<void(std::set<int32_t> const& _return)> cob,
+                       const std::set<int32_t>& thing) {
     std::set<int32_t> res;
     _delegate->testSet(res, thing);
     cob(res);
   }
 
-  virtual void testList(std::tr1::function<void(std::vector<int32_t>  const& _return)> cob, const std::vector<int32_t> & thing) {
+  virtual void testList(std::function<void(std::vector<int32_t> const& _return)> cob,
+                        const std::vector<int32_t>& thing) {
     std::vector<int32_t> res;
     _delegate->testList(res, thing);
     cob(res);
   }
 
-  virtual void testEnum(std::tr1::function<void(Numberz::type const& _return)> cob, const Numberz::type thing) {
+  virtual void testEnum(std::function<void(Numberz::type const& _return)> cob,
+                        const Numberz::type thing) {
     Numberz::type res = _delegate->testEnum(thing);
     cob(res);
   }
 
-  virtual void testTypedef(std::tr1::function<void(UserId const& _return)> cob, const UserId thing) {
+  virtual void testTypedef(std::function<void(UserId const& _return)> cob, const UserId thing) {
     UserId res = _delegate->testTypedef(thing);
     cob(res);
   }
 
-  virtual void testMapMap(std::tr1::function<void(std::map<int32_t, std::map<int32_t, int32_t> >  const& _return)> cob, const int32_t hello) {
+  virtual void testMapMap(
+      std::function<void(std::map<int32_t, std::map<int32_t, int32_t> > const& _return)> cob,
+      const int32_t hello) {
     std::map<int32_t, std::map<int32_t, int32_t> > res;
     _delegate->testMapMap(res, hello);
     cob(res);
   }
 
-  virtual void testInsanity(std::tr1::function<void(std::map<UserId, std::map<Numberz::type, Insanity> >  const& _return)> cob, const Insanity& argument) {
-    std::map<UserId, std::map<Numberz::type, Insanity> > res; 
+  virtual void testInsanity(
+      std::function<void(std::map<UserId, std::map<Numberz::type, Insanity> > const& _return)> cob,
+      const Insanity& argument) {
+    std::map<UserId, std::map<Numberz::type, Insanity> > res;
     _delegate->testInsanity(res, argument);
     cob(res);
- }
+  }
 
-  virtual void testMulti(std::tr1::function<void(Xtruct const& _return)> cob, const int8_t arg0, const int32_t arg1, const int64_t arg2, const std::map<int16_t, std::string> & arg3, const Numberz::type arg4, const UserId arg5) {
+  virtual void testMulti(std::function<void(Xtruct const& _return)> cob,
+                         const int8_t arg0,
+                         const int32_t arg1,
+                         const int64_t arg2,
+                         const std::map<int16_t, std::string>& arg3,
+                         const Numberz::type arg4,
+                         const UserId arg5) {
     Xtruct res;
     _delegate->testMulti(res, arg0, arg1, arg2, arg3, arg4, arg5);
     cob(res);
   }
 
-  virtual void testException(std::tr1::function<void()> cob, std::tr1::function<void(::apache::thrift::TDelayedException* _throw)> exn_cob, const std::string& arg) {
+  virtual void testException(
+      std::function<void()> cob,
+      std::function<void(::apache::thrift::TDelayedException* _throw)> exn_cob,
+      const std::string& arg) {
     try {
       _delegate->testException(arg);
-    } catch(const apache::thrift::TException& e) {
+    } catch (const apache::thrift::TException& e) {
       exn_cob(apache::thrift::TDelayedException::delayException(e));
       return;
     }
     cob();
   }
 
-  virtual void testMultiException(std::tr1::function<void(Xtruct const& _return)> cob, std::tr1::function<void(::apache::thrift::TDelayedException* _throw)> exn_cob, const std::string& arg0, const std::string& arg1) {
+  virtual void testMultiException(
+      std::function<void(Xtruct const& _return)> cob,
+      std::function<void(::apache::thrift::TDelayedException* _throw)> exn_cob,
+      const std::string& arg0,
+      const std::string& arg1) {
     Xtruct res;
     try {
       _delegate->testMultiException(res, arg0, arg1);
-    } catch(const apache::thrift::TException& e) {
+    } catch (const apache::thrift::TException& e) {
       exn_cob(apache::thrift::TDelayedException::delayException(e));
       return;
     }
     cob(res);
   }
 
-  virtual void testOneway(std::tr1::function<void()> cob, const int32_t secondsToSleep) {
+  virtual void testOneway(std::function<void()> cob, const int32_t secondsToSleep) {
     _delegate->testOneway(secondsToSleep);
     cob();
   }
 
 protected:
-  boost::shared_ptr<TestHandler> _delegate;
+  std::shared_ptr<TestHandler> _delegate;
 };
 
+namespace po = boost::program_options;
 
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
+
+  string testDir = boost::filesystem::system_complete(argv[0]).parent_path().parent_path().parent_path().string();
+  string certPath = testDir + "/keys/server.crt";
+  string keyPath = testDir + "/keys/server.key";
+
+#if _WIN32
+  transport::TWinsockSingleton::create();
+#endif
   int port = 9090;
   bool ssl = false;
+  bool zlib = false;
   string transport_type = "buffered";
   string protocol_type = "binary";
   string server_type = "simple";
   string domain_socket = "";
+  bool abstract_namespace = false;
   size_t workers = 4;
+  int string_limit = 0;
+  int container_limit = 0;
 
- 
-  program_options::options_description desc("Allowed options");
+  po::options_description desc("Allowed options");
   desc.add_options()
-      ("help,h", "produce help message")
-      ("port", program_options::value<int>(&port)->default_value(port), "Port number to listen")
-	  ("domain-socket", program_options::value<string>(&domain_socket)->default_value(domain_socket),
-	    "Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)")
-      ("server-type", program_options::value<string>(&server_type)->default_value(server_type),
-        "type of server, \"simple\", \"thread-pool\", \"threaded\", or \"nonblocking\"")
-      ("transport", program_options::value<string>(&transport_type)->default_value(transport_type),
-        "transport: buffered, framed, http")
-      ("protocol", program_options::value<string>(&protocol_type)->default_value(protocol_type),
-        "protocol: binary, json")
-	  ("ssl", "Encrypted Transport using SSL")
-	  ("processor-events", "processor-events")
-      ("workers,n", program_options::value<size_t>(&workers)->default_value(workers),
-        "Number of thread pools workers. Only valid for thread-pool server type")
-  ;
+    ("help,h", "produce help message")
+    ("port", po::value<int>(&port)->default_value(port), "Port number to listen")
+    ("domain-socket", po::value<string>(&domain_socket) ->default_value(domain_socket), "Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)")
+    ("abstract-namespace", "Create the domain socket in the Abstract Namespace (no connection with filesystem pathnames)")
+    ("server-type", po::value<string>(&server_type)->default_value(server_type), "type of server, \"simple\", \"thread-pool\", \"threaded\", or \"nonblocking\"")
+    ("transport", po::value<string>(&transport_type)->default_value(transport_type), "transport: buffered, framed, http, zlib")
+    ("protocol", po::value<string>(&protocol_type)->default_value(protocol_type), "protocol: binary, compact, header, json, multi, multic, multih, multij")
+    ("ssl", "Encrypted Transport using SSL")
+    ("zlib", "Wrapped Transport using Zlib")
+    ("processor-events", "processor-events")
+    ("workers,n", po::value<size_t>(&workers)->default_value(workers), "Number of thread pools workers. Only valid for thread-pool server type")
+    ("string-limit", po::value<int>(&string_limit))
+    ("container-limit", po::value<int>(&container_limit));
 
-  program_options::variables_map vm;
-  program_options::store(program_options::parse_command_line(argc, argv, desc), vm);
-  program_options::notify(vm);    
+  po::variables_map vm;
+  po::store(po::parse_command_line(argc, argv, desc), vm);
+  po::notify(vm);
 
   if (vm.count("help")) {
-      cout << desc << "\n";
-      return 1;
+    cout << desc << "\n";
+    return 1;
   }
-  
+
   try {
     if (!server_type.empty()) {
       if (server_type == "simple") {
@@ -533,24 +613,32 @@
       } else if (server_type == "threaded") {
       } else if (server_type == "nonblocking") {
       } else {
-          throw invalid_argument("Unknown server type "+server_type);
-      }
-    }
-    
-    if (!protocol_type.empty()) {
-      if (protocol_type == "binary") {
-      } else if (protocol_type == "json") {
-      } else {
-          throw invalid_argument("Unknown protocol type "+protocol_type);
+        throw invalid_argument("Unknown server type " + server_type);
       }
     }
 
-	if (!transport_type.empty()) {
+    if (!protocol_type.empty()) {
+      if (protocol_type == "binary") {
+      } else if (protocol_type == "compact") {
+      } else if (protocol_type == "json") {
+      } else if (protocol_type == "header") {
+      } else if (protocol_type == "multi") {  // multiplexed binary
+      } else if (protocol_type == "multic") { // multiplexed compact
+      } else if (protocol_type == "multih") { // multiplexed header
+      } else if (protocol_type == "multij") { // multiplexed json
+      } else {
+        throw invalid_argument("Unknown protocol type " + protocol_type);
+      }
+    }
+
+    if (!transport_type.empty()) {
       if (transport_type == "buffered") {
       } else if (transport_type == "framed") {
       } else if (transport_type == "http") {
+      } else if (transport_type == "zlib") {
+        // crosstester will pass zlib as a flag and a transport right now...
       } else {
-          throw invalid_argument("Unknown transport type "+transport_type);
+        throw invalid_argument("Unknown transport type " + transport_type);
       }
     }
 
@@ -562,123 +650,196 @@
 
   if (vm.count("ssl")) {
     ssl = true;
-    signal(SIGPIPE, SIG_IGN);
+  }
+
+  if (vm.count("zlib")) {
+    zlib = true;
+  }
+
+#if defined(HAVE_SIGNAL_H) && defined(SIGPIPE)
+  if (ssl) {
+    signal(SIGPIPE, SIG_IGN); // for OpenSSL, otherwise we end abruptly
+  }
+#endif
+
+  if (vm.count("abstract-namespace")) {
+    abstract_namespace = true;
   }
 
   // Dispatcher
-  boost::shared_ptr<TProtocolFactory> protocolFactory;
-  if (protocol_type == "json") {
-    boost::shared_ptr<TProtocolFactory> jsonProtocolFactory(new TJSONProtocolFactory());
+  std::shared_ptr<TProtocolFactory> protocolFactory;
+  if (protocol_type == "json" || protocol_type == "multij") {
+    std::shared_ptr<TProtocolFactory> jsonProtocolFactory(new TJSONProtocolFactory());
     protocolFactory = jsonProtocolFactory;
+  } else if (protocol_type == "compact" || protocol_type == "multic") {
+    TCompactProtocolFactoryT<TBufferBase> *compactProtocolFactory = new TCompactProtocolFactoryT<TBufferBase>();
+    compactProtocolFactory->setContainerSizeLimit(container_limit);
+    compactProtocolFactory->setStringSizeLimit(string_limit);
+    protocolFactory.reset(compactProtocolFactory);
+  } else if (protocol_type == "header" || protocol_type == "multih") {
+    std::shared_ptr<TProtocolFactory> headerProtocolFactory(new THeaderProtocolFactory());
+    protocolFactory = headerProtocolFactory;
   } else {
-    boost::shared_ptr<TProtocolFactory> binaryProtocolFactory(new TBinaryProtocolFactoryT<TBufferBase>());
-    protocolFactory = binaryProtocolFactory;
+    TBinaryProtocolFactoryT<TBufferBase>* binaryProtocolFactory = new TBinaryProtocolFactoryT<TBufferBase>();
+    binaryProtocolFactory->setContainerSizeLimit(container_limit);
+    binaryProtocolFactory->setStringSizeLimit(string_limit);
+    protocolFactory.reset(binaryProtocolFactory);
   }
 
-  // Processor
-  boost::shared_ptr<TestHandler> testHandler(new TestHandler());
-  boost::shared_ptr<ThriftTestProcessor> testProcessor(new ThriftTestProcessor(testHandler));
-  
+  // Processors
+  std::shared_ptr<TestHandler> testHandler(new TestHandler());
+  std::shared_ptr<TProcessor> testProcessor(new ThriftTestProcessor(testHandler));
+
   if (vm.count("processor-events")) {
-    testProcessor->setEventHandler(boost::shared_ptr<TProcessorEventHandler>(
-          new TestProcessorEventHandler()));
+    testProcessor->setEventHandler(
+        std::shared_ptr<TProcessorEventHandler>(new TestProcessorEventHandler()));
   }
-  
+
   // Transport
-  boost::shared_ptr<TSSLSocketFactory> sslSocketFactory;
-  boost::shared_ptr<TServerSocket> serverSocket;
+  std::shared_ptr<TSSLSocketFactory> sslSocketFactory;
+  std::shared_ptr<TServerSocket> serverSocket;
 
   if (ssl) {
-    sslSocketFactory = boost::shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory());
-    sslSocketFactory->loadCertificate("./server-certificate.pem");
-    sslSocketFactory->loadPrivateKey("./server-private-key.pem");
+    sslSocketFactory = std::shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory());
+    sslSocketFactory->loadCertificate(certPath.c_str());
+    sslSocketFactory->loadPrivateKey(keyPath.c_str());
     sslSocketFactory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
-    serverSocket = boost::shared_ptr<TServerSocket>(new TSSLServerSocket(port, sslSocketFactory));
+    if (server_type != "nonblocking") {
+      serverSocket = std::shared_ptr<TServerSocket>(new TSSLServerSocket(port, sslSocketFactory));
+    }
   } else {
-	if (domain_socket != "") {
-	  unlink(domain_socket.c_str());
-	  serverSocket = boost::shared_ptr<TServerSocket>(new TServerSocket(domain_socket));
-	  port = 0;
-	}
-	else {
-      serverSocket = boost::shared_ptr<TServerSocket>(new TServerSocket(port));
-	}
+    if (domain_socket != "") {
+      if (abstract_namespace) {
+        std::string abstract_socket("\0", 1);
+        abstract_socket += domain_socket;
+        serverSocket = std::shared_ptr<TServerSocket>(new TServerSocket(abstract_socket));
+      } else {
+        unlink(domain_socket.c_str());
+        serverSocket = std::shared_ptr<TServerSocket>(new TServerSocket(domain_socket));
+      }
+      port = 0;
+    } else {
+      serverSocket = std::shared_ptr<TServerSocket>(new TServerSocket(port));
+    }
   }
 
   // Factory
-  boost::shared_ptr<TTransportFactory> transportFactory;
-  
+  std::shared_ptr<TTransportFactory> transportFactory;
+
   if (transport_type == "http" && server_type != "nonblocking") {
-    boost::shared_ptr<TTransportFactory> httpTransportFactory(new THttpServerTransportFactory()); 
-    transportFactory = httpTransportFactory;
+    transportFactory = std::make_shared<THttpServerTransportFactory>();
   } else if (transport_type == "framed") {
-    boost::shared_ptr<TTransportFactory> framedTransportFactory(new TFramedTransportFactory()); 
-    transportFactory = framedTransportFactory;
+    transportFactory = std::make_shared<TFramedTransportFactory>();
   } else {
-    boost::shared_ptr<TTransportFactory> bufferedTransportFactory(new TBufferedTransportFactory()); 
-    transportFactory = bufferedTransportFactory;
+    transportFactory = std::make_shared<TBufferedTransportFactory>();
+  }
+
+  if (zlib) {
+    // hmm.. doesn't seem to be a way to make it wrap the others...
+    transportFactory = std::make_shared<TZlibTransportFactory>();
   }
 
   // Server Info
-  cout << "Starting \"" << server_type << "\" server ("
-    << transport_type << "/" << protocol_type << ") listen on: " << domain_socket;
+  cout << "Starting \"" << server_type << "\" server (" << transport_type << "/" << protocol_type
+       << ") listen on: ";
+  if (abstract_namespace) {
+    cout << '@';
+  }
+  cout << domain_socket;
   if (port != 0) {
     cout << port;
   }
   cout << endl;
 
+  // Multiplexed Processor if needed
+  if (boost::starts_with(protocol_type, "multi")) {
+    std::shared_ptr<SecondHandler> secondHandler(new SecondHandler());
+    std::shared_ptr<SecondServiceProcessor> secondProcessor(new SecondServiceProcessor(secondHandler));
+
+    std::shared_ptr<TMultiplexedProcessor> multiplexedProcessor(new TMultiplexedProcessor());
+    multiplexedProcessor->registerDefault(testProcessor); // non-multi clients go to the default processor (multi:binary, multic:compact, ...)
+    multiplexedProcessor->registerProcessor("ThriftTest", testProcessor);
+    multiplexedProcessor->registerProcessor("SecondService", secondProcessor);
+    testProcessor = std::dynamic_pointer_cast<TProcessor>(multiplexedProcessor);
+  }
+
   // Server
+  std::shared_ptr<apache::thrift::server::TServer> server;
+
   if (server_type == "simple") {
-    TSimpleServer simpleServer(testProcessor,
-                               serverSocket,
-                               transportFactory,
-                               protocolFactory);
-
-    simpleServer.serve();
-
+    server.reset(new TSimpleServer(testProcessor, serverSocket, transportFactory, protocolFactory));
   } else if (server_type == "thread-pool") {
 
-    boost::shared_ptr<ThreadManager> threadManager =
-      ThreadManager::newSimpleThreadManager(workers);
+    std::shared_ptr<PlatformThreadFactory> threadFactory
+        = std::shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory());
 
-    boost::shared_ptr<PlatformThreadFactory> threadFactory =
-      boost::shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory());
-
+    std::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(workers);
     threadManager->threadFactory(threadFactory);
-
     threadManager->start();
 
-    TThreadPoolServer threadPoolServer(testProcessor,
+    server.reset(new TThreadPoolServer(testProcessor,
                                        serverSocket,
                                        transportFactory,
                                        protocolFactory,
-                                       threadManager);
-
-    threadPoolServer.serve();
-
+                                       threadManager));
   } else if (server_type == "threaded") {
-
-    TThreadedServer threadedServer(testProcessor,
-                                   serverSocket,
-                                   transportFactory,
-                                   protocolFactory);
-
-    threadedServer.serve();
-
+    server.reset(
+        new TThreadedServer(testProcessor, serverSocket, transportFactory, protocolFactory));
   } else if (server_type == "nonblocking") {
-    if(transport_type == "http") {
-      boost::shared_ptr<TestHandlerAsync> testHandlerAsync(new TestHandlerAsync(testHandler));
-      boost::shared_ptr<TAsyncProcessor> testProcessorAsync(new ThriftTestAsyncProcessor(testHandlerAsync));
-      boost::shared_ptr<TAsyncBufferProcessor> testBufferProcessor(new TAsyncProtocolProcessor(testProcessorAsync, protocolFactory));
-      
+    if (transport_type == "http") {
+      std::shared_ptr<TestHandlerAsync> testHandlerAsync(new TestHandlerAsync(testHandler));
+      std::shared_ptr<TAsyncProcessor> testProcessorAsync(
+          new ThriftTestAsyncProcessor(testHandlerAsync));
+      std::shared_ptr<TAsyncBufferProcessor> testBufferProcessor(
+          new TAsyncProtocolProcessor(testProcessorAsync, protocolFactory));
+
+      // not loading nonblockingServer into "server" because
+      // TEvhttpServer doesn't inherit from TServer, and doesn't
+      // provide a stop method.
       TEvhttpServer nonblockingServer(testBufferProcessor, port);
       nonblockingServer.serve();
-} else {
-      TNonblockingServer nonblockingServer(testProcessor, port);
-      nonblockingServer.serve();
+    } else if (transport_type == "framed") {
+      std::shared_ptr<transport::TNonblockingServerTransport> nbSocket;
+      nbSocket.reset(
+          ssl ? new transport::TNonblockingSSLServerSocket(port, sslSocketFactory)
+              : new transport::TNonblockingServerSocket(port));
+      server.reset(new TNonblockingServer(testProcessor, protocolFactory, nbSocket));
+    } else {
+      cerr << "server-type nonblocking requires transport of http or framed" << endl;
+      exit(1);
     }
   }
 
+  if (server.get() != NULL) {
+    if (protocol_type == "header") {
+      // Tell the server to use the same protocol for input / output
+      // if using header
+      server->setOutputProtocolFactory(std::shared_ptr<TProtocolFactory>());
+    }
+    
+    apache::thrift::concurrency::PlatformThreadFactory factory;
+    factory.setDetached(false);
+    std::shared_ptr<apache::thrift::concurrency::Runnable> serverThreadRunner(server);
+    std::shared_ptr<apache::thrift::concurrency::Thread> thread
+        = factory.newThread(serverThreadRunner);
+
+#ifdef HAVE_SIGNAL_H
+    signal(SIGINT, signal_handler);
+#endif
+
+    thread->start();
+    gMonitor.waitForever();         // wait for a shutdown signal
+    
+#ifdef HAVE_SIGNAL_H
+    signal(SIGINT, SIG_DFL);
+#endif
+
+    server->stop();
+    thread->join();
+    server.reset();
+  }
+
   cout << "done." << endl;
   return 0;
 }
+
diff --git a/test/cpp/src/ThriftTest_extras.cpp b/test/cpp/src/ThriftTest_extras.cpp
new file mode 100644
index 0000000..af5606e
--- /dev/null
+++ b/test/cpp/src/ThriftTest_extras.cpp
@@ -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.
+ */
+
+// Extra functions required for ThriftTest_types to work
+
+#include <thrift/protocol/TDebugProtocol.h>
+#include "gen-cpp/ThriftTest_types.h"
+
+namespace thrift {
+namespace test {
+
+bool Insanity::operator<(thrift::test::Insanity const& other) const {
+  using apache::thrift::ThriftDebugString;
+  return ThriftDebugString(*this) < ThriftDebugString(other);
+}
+}
+}
diff --git a/test/crossrunner/__init__.py b/test/crossrunner/__init__.py
new file mode 100644
index 0000000..9d0b83a
--- /dev/null
+++ b/test/crossrunner/__init__.py
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+
+from .test import test_name  # noqa
+from .collect import collect_cross_tests, collect_feature_tests  # noqa
+from .run import TestDispatcher  # noqa
+from .report import generate_known_failures, load_known_failures  # noqa
diff --git a/test/crossrunner/collect.py b/test/crossrunner/collect.py
new file mode 100644
index 0000000..e2d8978
--- /dev/null
+++ b/test/crossrunner/collect.py
@@ -0,0 +1,164 @@
+#
+# 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 platform
+import re
+from itertools import product
+
+from .util import merge_dict
+from .test import TestEntry
+
+# Those keys are passed to execution as is.
+# Note that there are keys other than these, namely:
+# delay: After server is started, client start is delayed for the value
+# (seconds).
+# timeout: Test timeout after client is started (seconds).
+# platforms: Supported platforms. Should match platform.system() value.
+# protocols: list of supported protocols
+# transports: list of supported transports
+# sockets: list of supported sockets
+#
+# protocols and transports entries can be colon separated "spec:impl" pair
+# (e.g. binary:accel) where test is run for any matching "spec" while actual
+# argument passed to test executable is "impl".
+# Otherwise "spec" is equivalent to "spec:spec" pair.
+# (e.g. "binary" is equivalent to "binary:binary" in tests.json)
+#
+VALID_JSON_KEYS = [
+    'name',  # name of the library, typically a language name
+    'workdir',  # work directory where command is executed
+    'command',  # test command
+    'extra_args',  # args appended to command after other args are appended
+    'remote_args',  # args added to the other side of the program
+    'join_args',  # whether args should be passed as single concatenated string
+    'env',  # additional environmental variable
+]
+
+DEFAULT_MAX_DELAY = 5
+DEFAULT_SIGNAL = 1
+DEFAULT_TIMEOUT = 5
+
+
+def _collect_testlibs(config, server_match, client_match=[None]):
+    """Collects server/client configurations from library configurations"""
+    def expand_libs(config):
+        for lib in config:
+            sv = lib.pop('server', None)
+            cl = lib.pop('client', None)
+            yield lib, sv, cl
+
+    def yield_testlibs(base_configs, configs, match):
+        for base, conf in zip(base_configs, configs):
+            if conf:
+                if not match or base['name'] in match:
+                    platforms = conf.get('platforms') or base.get('platforms')
+                    if not platforms or platform.system() in platforms:
+                        yield merge_dict(base, conf)
+
+    libs, svs, cls = zip(*expand_libs(config))
+    servers = list(yield_testlibs(libs, svs, server_match))
+    clients = list(yield_testlibs(libs, cls, client_match))
+    return servers, clients
+
+
+def collect_features(config, match):
+    res = list(map(re.compile, match))
+    return list(filter(lambda c: any(map(lambda r: r.search(c['name']), res)), config))
+
+
+def _do_collect_tests(servers, clients):
+    def intersection(key, o1, o2):
+        """intersection of two collections.
+        collections are replaced with sets the first time"""
+        def cached_set(o, key):
+            v = o[key]
+            if not isinstance(v, set):
+                v = set(v)
+                o[key] = v
+            return v
+        return cached_set(o1, key) & cached_set(o2, key)
+
+    def intersect_with_spec(key, o1, o2):
+        # store as set of (spec, impl) tuple
+        def cached_set(o):
+            def to_spec_impl_tuples(values):
+                for v in values:
+                    spec, _, impl = v.partition(':')
+                    yield spec, impl or spec
+            v = o[key]
+            if not isinstance(v, set):
+                v = set(to_spec_impl_tuples(set(v)))
+                o[key] = v
+            return v
+        for spec1, impl1 in cached_set(o1):
+            for spec2, impl2 in cached_set(o2):
+                if spec1 == spec2:
+                    name = impl1 if impl1 == impl2 else '%s-%s' % (impl1, impl2)
+                    yield name, impl1, impl2
+
+    def maybe_max(key, o1, o2, default):
+        """maximum of two if present, otherwise default value"""
+        v1 = o1.get(key)
+        v2 = o2.get(key)
+        return max(v1, v2) if v1 and v2 else v1 or v2 or default
+
+    def filter_with_validkeys(o):
+        ret = {}
+        for key in VALID_JSON_KEYS:
+            if key in o:
+                ret[key] = o[key]
+        return ret
+
+    def merge_metadata(o, **ret):
+        for key in VALID_JSON_KEYS:
+            if key in o:
+                ret[key] = o[key]
+        return ret
+
+    for sv, cl in product(servers, clients):
+        for proto, proto1, proto2 in intersect_with_spec('protocols', sv, cl):
+            for trans, trans1, trans2 in intersect_with_spec('transports', sv, cl):
+                for sock in intersection('sockets', sv, cl):
+                    yield {
+                        'server': merge_metadata(sv, **{'protocol': proto1, 'transport': trans1}),
+                        'client': merge_metadata(cl, **{'protocol': proto2, 'transport': trans2}),
+                        'delay': maybe_max('delay', sv, cl, DEFAULT_MAX_DELAY),
+                        'stop_signal': maybe_max('stop_signal', sv, cl, DEFAULT_SIGNAL),
+                        'timeout': maybe_max('timeout', sv, cl, DEFAULT_TIMEOUT),
+                        'protocol': proto,
+                        'transport': trans,
+                        'socket': sock
+                    }
+
+
+def _filter_entries(tests, regex):
+    if regex:
+        return filter(lambda t: re.search(regex, TestEntry.get_name(**t)), tests)
+    return tests
+
+
+def collect_cross_tests(tests_dict, server_match, client_match, regex):
+    sv, cl = _collect_testlibs(tests_dict, server_match, client_match)
+    return list(_filter_entries(_do_collect_tests(sv, cl), regex))
+
+
+def collect_feature_tests(tests_dict, features_dict, server_match, feature_match, regex):
+    sv, _ = _collect_testlibs(tests_dict, server_match)
+    ft = collect_features(features_dict, feature_match)
+    return list(_filter_entries(_do_collect_tests(sv, ft), regex))
diff --git a/test/crossrunner/compat.py b/test/crossrunner/compat.py
new file mode 100644
index 0000000..f1ca91b
--- /dev/null
+++ b/test/crossrunner/compat.py
@@ -0,0 +1,24 @@
+import os
+import sys
+
+if sys.version_info[0] == 2:
+    _ENCODE = sys.getfilesystemencoding()
+
+    def path_join(*args):
+        bin_args = map(lambda a: a.decode(_ENCODE), args)
+        return os.path.join(*bin_args).encode(_ENCODE)
+
+    def str_join(s, l):
+        bin_args = map(lambda a: a.decode(_ENCODE), l)
+        b = s.decode(_ENCODE)
+        return b.join(bin_args).encode(_ENCODE)
+
+    logfile_open = open
+
+else:
+
+    path_join = os.path.join
+    str_join = str.join
+
+    def logfile_open(*args):
+        return open(*args, errors='replace')
diff --git a/test/crossrunner/report.py b/test/crossrunner/report.py
new file mode 100644
index 0000000..5baf161
--- /dev/null
+++ b/test/crossrunner/report.py
@@ -0,0 +1,441 @@
+#
+# 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.
+#
+
+from __future__ import print_function
+import datetime
+import json
+import multiprocessing
+import os
+import platform
+import re
+import subprocess
+import sys
+import time
+import traceback
+
+from .compat import logfile_open, path_join, str_join
+from .test import TestEntry
+
+LOG_DIR = 'log'
+RESULT_HTML = 'index.html'
+RESULT_JSON = 'results.json'
+FAIL_JSON = 'known_failures_%s.json'
+
+
+def generate_known_failures(testdir, overwrite, save, out):
+    def collect_failures(results):
+        success_index = 5
+        for r in results:
+            if not r[success_index]:
+                yield TestEntry.get_name(*r)
+    try:
+        with logfile_open(path_join(testdir, RESULT_JSON), 'r') as fp:
+            results = json.load(fp)
+    except IOError:
+        sys.stderr.write('Unable to load last result. Did you run tests ?\n')
+        return False
+    fails = collect_failures(results['results'])
+    if not overwrite:
+        known = load_known_failures(testdir)
+        known.extend(fails)
+        fails = known
+    fails_json = json.dumps(sorted(set(fails)), indent=2, separators=(',', ': '))
+    if save:
+        with logfile_open(os.path.join(testdir, FAIL_JSON % platform.system()), 'w+') as fp:
+            fp.write(fails_json)
+        sys.stdout.write('Successfully updated known failures.\n')
+    if out:
+        sys.stdout.write(fails_json)
+        sys.stdout.write('\n')
+    return True
+
+
+def load_known_failures(testdir):
+    try:
+        with logfile_open(path_join(testdir, FAIL_JSON % platform.system()), 'r') as fp:
+            return json.load(fp)
+    except IOError:
+        return []
+
+
+class TestReporter(object):
+    # Unfortunately, standard library doesn't handle timezone well
+    # DATETIME_FORMAT = '%a %b %d %H:%M:%S %Z %Y'
+    DATETIME_FORMAT = '%a %b %d %H:%M:%S %Y'
+
+    def __init__(self):
+        self._log = multiprocessing.get_logger()
+        self._lock = multiprocessing.Lock()
+
+    @classmethod
+    def test_logfile(cls, test_name, prog_kind, dir=None):
+        relpath = path_join('log', '%s_%s.log' % (test_name, prog_kind))
+        return relpath if not dir else os.path.realpath(path_join(dir, relpath))
+
+    def _start(self):
+        self._start_time = time.time()
+
+    @property
+    def _elapsed(self):
+        return time.time() - self._start_time
+
+    @classmethod
+    def _format_date(cls):
+        return '%s' % datetime.datetime.now().strftime(cls.DATETIME_FORMAT)
+
+    def _print_date(self):
+        print(self._format_date(), file=self.out)
+
+    def _print_bar(self, out=None):
+        print(
+            '===============================================================================',
+            file=(out or self.out))
+
+    def _print_exec_time(self):
+        print('Test execution took {:.1f} seconds.'.format(self._elapsed), file=self.out)
+
+
+class ExecReporter(TestReporter):
+    def __init__(self, testdir, test, prog):
+        super(ExecReporter, self).__init__()
+        self._test = test
+        self._prog = prog
+        self.logpath = self.test_logfile(test.name, prog.kind, testdir)
+        self.out = None
+
+    def begin(self):
+        self._start()
+        self._open()
+        if self.out and not self.out.closed:
+            self._print_header()
+        else:
+            self._log.debug('Output stream is not available.')
+
+    def end(self, returncode):
+        self._lock.acquire()
+        try:
+            if self.out and not self.out.closed:
+                self._print_footer(returncode)
+                self._close()
+                self.out = None
+            else:
+                self._log.debug('Output stream is not available.')
+        finally:
+            self._lock.release()
+
+    def killed(self):
+        print(file=self.out)
+        print('Server process is successfully killed.', file=self.out)
+        self.end(None)
+
+    def died(self):
+        print(file=self.out)
+        print('*** Server process has died unexpectedly ***', file=self.out)
+        self.end(None)
+
+    _init_failure_exprs = {
+        'server': list(map(re.compile, [
+            '[Aa]ddress already in use',
+            'Could not bind',
+            'EADDRINUSE',
+        ])),
+        'client': list(map(re.compile, [
+            '[Cc]onnection refused',
+            'Could not connect to',
+            'Could not open UNIX ',       # domain socket (rb)
+            'ECONNREFUSED',
+            'econnrefused',               # erl
+            'CONNECTION-REFUSED-ERROR',   # cl
+            'connect ENOENT',             # nodejs domain socket
+            'No such file or directory',  # domain socket
+            'Sockets.TcpClient.Connect',  # csharp
+        ])),
+    }
+
+    def maybe_false_positive(self):
+        """Searches through log file for socket bind error.
+        Returns True if suspicious expression is found, otherwise False"""
+        try:
+            if self.out and not self.out.closed:
+                self.out.flush()
+            exprs = self._init_failure_exprs[self._prog.kind]
+
+            def match(line):
+                for expr in exprs:
+                    if expr.search(line):
+                        self._log.info("maybe false positive: %s" % line)
+                        return True
+
+            with logfile_open(self.logpath, 'r') as fp:
+                if any(map(match, fp)):
+                    return True
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except Exception as ex:
+            self._log.warn('[%s]: Error while detecting false positive: %s' % (self._test.name, str(ex)))
+            self._log.info(traceback.print_exc())
+        return False
+
+    def _open(self):
+        self.out = logfile_open(self.logpath, 'w+')
+
+    def _close(self):
+        self.out.close()
+
+    def _print_header(self):
+        self._print_date()
+        print('Executing: %s' % str_join(' ', self._prog.command), file=self.out)
+        print('Directory: %s' % self._prog.workdir, file=self.out)
+        print('config:delay: %s' % self._test.delay, file=self.out)
+        print('config:timeout: %s' % self._test.timeout, file=self.out)
+        self._print_bar()
+        self.out.flush()
+
+    def _print_footer(self, returncode=None):
+        self._print_bar()
+        if returncode is not None:
+            print('Return code: %d (negative values indicate kill by signal)' % returncode, file=self.out)
+        else:
+            print('Process is killed.', file=self.out)
+        self._print_exec_time()
+        self._print_date()
+
+
+class SummaryReporter(TestReporter):
+    def __init__(self, basedir, testdir_relative, concurrent=True):
+        super(SummaryReporter, self).__init__()
+        self._basedir = basedir
+        self._testdir_rel = testdir_relative
+        self.logdir = path_join(self.testdir, LOG_DIR)
+        self.out_path = path_join(self.testdir, RESULT_JSON)
+        self.concurrent = concurrent
+        self.out = sys.stdout
+        self._platform = platform.system()
+        self._revision = self._get_revision()
+        self._tests = []
+        if not os.path.exists(self.logdir):
+            os.mkdir(self.logdir)
+        self._known_failures = load_known_failures(self.testdir)
+        self._unexpected_success = []
+        self._flaky_success = []
+        self._unexpected_failure = []
+        self._expected_failure = []
+        self._print_header()
+
+    @property
+    def testdir(self):
+        return path_join(self._basedir, self._testdir_rel)
+
+    def _result_string(self, test):
+        if test.success:
+            if test.retry_count == 0:
+                return 'success'
+            elif test.retry_count == 1:
+                return 'flaky(1 retry)'
+            else:
+                return 'flaky(%d retries)' % test.retry_count
+        elif test.expired:
+            return 'failure(timeout)'
+        else:
+            return 'failure(%d)' % test.returncode
+
+    def _get_revision(self):
+        p = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'],
+                             cwd=self.testdir, stdout=subprocess.PIPE)
+        out, _ = p.communicate()
+        return out.strip()
+
+    def _format_test(self, test, with_result=True):
+        name = '%s-%s' % (test.server.name, test.client.name)
+        trans = '%s-%s' % (test.transport, test.socket)
+        if not with_result:
+            return '{:24s}{:18s}{:25s}'.format(name[:23], test.protocol[:17], trans[:24])
+        else:
+            return '{:24s}{:18s}{:25s}{:s}\n'.format(name[:23], test.protocol[:17],
+                                                     trans[:24], self._result_string(test))
+
+    def _print_test_header(self):
+        self._print_bar()
+        print(
+            '{:24s}{:18s}{:25s}{:s}'.format('server-client:', 'protocol:', 'transport:', 'result:'),
+            file=self.out)
+
+    def _print_header(self):
+        self._start()
+        print('Apache Thrift - Integration Test Suite', file=self.out)
+        self._print_date()
+        self._print_test_header()
+
+    def _print_unexpected_failure(self):
+        if len(self._unexpected_failure) > 0:
+            self.out.writelines([
+                '*** Following %d failures were unexpected ***:\n' % len(self._unexpected_failure),
+                'If it is introduced by you, please fix it before submitting the code.\n',
+                # 'If not, please report at https://issues.apache.org/jira/browse/THRIFT\n',
+            ])
+            self._print_test_header()
+            for i in self._unexpected_failure:
+                self.out.write(self._format_test(self._tests[i]))
+            self._print_bar()
+        else:
+            print('No unexpected failures.', file=self.out)
+
+    def _print_flaky_success(self):
+        if len(self._flaky_success) > 0:
+            print(
+                'Following %d tests were expected to cleanly succeed but needed retry:' % len(self._flaky_success),
+                file=self.out)
+            self._print_test_header()
+            for i in self._flaky_success:
+                self.out.write(self._format_test(self._tests[i]))
+            self._print_bar()
+
+    def _print_unexpected_success(self):
+        if len(self._unexpected_success) > 0:
+            print(
+                'Following %d tests were known to fail but succeeded (maybe flaky):' % len(self._unexpected_success),
+                file=self.out)
+            self._print_test_header()
+            for i in self._unexpected_success:
+                self.out.write(self._format_test(self._tests[i]))
+            self._print_bar()
+
+    def _http_server_command(self, port):
+        if sys.version_info[0] < 3:
+            return 'python -m SimpleHTTPServer %d' % port
+        else:
+            return 'python -m http.server %d' % port
+
+    def _print_footer(self):
+        fail_count = len(self._expected_failure) + len(self._unexpected_failure)
+        self._print_bar()
+        self._print_unexpected_success()
+        self._print_flaky_success()
+        self._print_unexpected_failure()
+        self._write_html_data()
+        self._assemble_log('unexpected failures', self._unexpected_failure)
+        self._assemble_log('known failures', self._expected_failure)
+        self.out.writelines([
+            'You can browse results at:\n',
+            '\tfile://%s/%s\n' % (self.testdir, RESULT_HTML),
+            '# If you use Chrome, run:\n',
+            '# \tcd %s\n#\t%s\n' % (self._basedir, self._http_server_command(8001)),
+            '# then browse:\n',
+            '# \thttp://localhost:%d/%s/\n' % (8001, self._testdir_rel),
+            'Full log for each test is here:\n',
+            '\ttest/log/server_client_protocol_transport_client.log\n',
+            '\ttest/log/server_client_protocol_transport_server.log\n',
+            '%d failed of %d tests in total.\n' % (fail_count, len(self._tests)),
+        ])
+        self._print_exec_time()
+        self._print_date()
+
+    def _render_result(self, test):
+        return [
+            test.server.name,
+            test.client.name,
+            test.protocol,
+            test.transport,
+            test.socket,
+            test.success,
+            test.as_expected,
+            test.returncode,
+            {
+                'server': self.test_logfile(test.name, test.server.kind),
+                'client': self.test_logfile(test.name, test.client.kind),
+            },
+        ]
+
+    def _write_html_data(self):
+        """Writes JSON data to be read by result html"""
+        results = [self._render_result(r) for r in self._tests]
+        with logfile_open(self.out_path, 'w+') as fp:
+            fp.write(json.dumps({
+                'date': self._format_date(),
+                'revision': str(self._revision),
+                'platform': self._platform,
+                'duration': '{:.1f}'.format(self._elapsed),
+                'results': results,
+            }, indent=2))
+
+    def _assemble_log(self, title, indexes):
+        if len(indexes) > 0:
+            def add_prog_log(fp, test, prog_kind):
+                print('*************************** %s message ***************************' % prog_kind,
+                      file=fp)
+                path = self.test_logfile(test.name, prog_kind, self.testdir)
+                if os.path.exists(path):
+                    with logfile_open(path, 'r') as prog_fp:
+                        print(prog_fp.read(), file=fp)
+            filename = title.replace(' ', '_') + '.log'
+            with logfile_open(os.path.join(self.logdir, filename), 'w+') as fp:
+                for test in map(self._tests.__getitem__, indexes):
+                    fp.write('TEST: [%s]\n' % test.name)
+                    add_prog_log(fp, test, test.server.kind)
+                    add_prog_log(fp, test, test.client.kind)
+                    fp.write('**********************************************************************\n\n')
+            print('%s are logged to %s/%s/%s' % (title.capitalize(), self._testdir_rel, LOG_DIR, filename))
+
+    def end(self):
+        self._print_footer()
+        return len(self._unexpected_failure) == 0
+
+    def add_test(self, test_dict):
+        test = TestEntry(self.testdir, **test_dict)
+        self._lock.acquire()
+        try:
+            if not self.concurrent:
+                self.out.write(self._format_test(test, False))
+                self.out.flush()
+            self._tests.append(test)
+            return len(self._tests) - 1
+        finally:
+            self._lock.release()
+
+    def add_result(self, index, returncode, expired, retry_count):
+        self._lock.acquire()
+        try:
+            failed = returncode is None or returncode != 0
+            flaky = not failed and retry_count != 0
+            test = self._tests[index]
+            known = test.name in self._known_failures
+            if failed:
+                if known:
+                    self._log.debug('%s failed as expected' % test.name)
+                    self._expected_failure.append(index)
+                else:
+                    self._log.info('unexpected failure: %s' % test.name)
+                    self._unexpected_failure.append(index)
+            elif flaky and not known:
+                self._log.info('unexpected flaky success: %s' % test.name)
+                self._flaky_success.append(index)
+            elif not flaky and known:
+                self._log.info('unexpected success: %s' % test.name)
+                self._unexpected_success.append(index)
+            test.success = not failed
+            test.returncode = returncode
+            test.retry_count = retry_count
+            test.expired = expired
+            test.as_expected = known == failed
+            if not self.concurrent:
+                self.out.write(self._result_string(test) + '\n')
+            else:
+                self.out.write(self._format_test(test))
+        finally:
+            self._lock.release()
diff --git a/test/crossrunner/run.py b/test/crossrunner/run.py
new file mode 100644
index 0000000..ef8fb60
--- /dev/null
+++ b/test/crossrunner/run.py
@@ -0,0 +1,425 @@
+#
+# 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 contextlib
+import multiprocessing
+import multiprocessing.managers
+import os
+import platform
+import random
+import socket
+import subprocess
+import sys
+import time
+
+from .compat import str_join
+from .report import ExecReporter, SummaryReporter
+from .test import TestEntry
+from .util import domain_socket_path
+
+RESULT_ERROR = 64
+RESULT_TIMEOUT = 128
+SIGNONE = 0
+SIGKILL = 15
+
+# globals
+ports = None
+stop = None
+
+
+class ExecutionContext(object):
+    def __init__(self, cmd, cwd, env, stop_signal, is_server, report):
+        self._log = multiprocessing.get_logger()
+        self.cmd = cmd
+        self.cwd = cwd
+        self.env = env
+        self.stop_signal = stop_signal
+        self.is_server = is_server
+        self.report = report
+        self.expired = False
+        self.killed = False
+        self.proc = None
+
+    def _popen_args(self):
+        args = {
+            'cwd': self.cwd,
+            'env': self.env,
+            'stdout': self.report.out,
+            'stderr': subprocess.STDOUT,
+        }
+        # make sure child processes doesn't remain after killing
+        if platform.system() == 'Windows':
+            DETACHED_PROCESS = 0x00000008
+            args.update(creationflags=DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP)
+        else:
+            args.update(preexec_fn=os.setsid)
+        return args
+
+    def start(self):
+        joined = str_join(' ', self.cmd)
+        self._log.debug('COMMAND: %s', joined)
+        self._log.debug('WORKDIR: %s', self.cwd)
+        self._log.debug('LOGFILE: %s', self.report.logpath)
+        self.report.begin()
+        self.proc = subprocess.Popen(self.cmd, **self._popen_args())
+        self._log.debug('    PID: %d', self.proc.pid)
+        self._log.debug('   PGID: %d', os.getpgid(self.proc.pid))
+        return self._scoped()
+
+    @contextlib.contextmanager
+    def _scoped(self):
+        yield self
+        if self.is_server:
+            # the server is supposed to run until we stop it
+            if self.returncode is not None:
+                self.report.died()
+            else:
+                if self.stop_signal != SIGNONE:
+                    if self.sigwait(self.stop_signal):
+                        self.report.end(self.returncode)
+                    else:
+                        self.report.killed()
+                else:
+                    self.sigwait(SIGKILL)
+        else:
+            # the client is supposed to exit normally
+            if self.returncode is not None:
+                self.report.end(self.returncode)
+            else:
+                self.sigwait(SIGKILL)
+                self.report.killed()
+        self._log.debug('[{0}] exited with return code {1}'.format(self.proc.pid, self.returncode))
+
+    # Send a signal to the process and then wait for it to end
+    # If the signal requested is SIGNONE, no signal is sent, and
+    # instead we just wait for the process to end; further if it
+    # does not end normally with SIGNONE, we mark it as expired.
+    # If the process fails to end and the signal is not SIGKILL,
+    # it re-runs with SIGKILL so that a real process kill occurs
+    # returns True if the process ended, False if it may not have
+    def sigwait(self, sig=SIGKILL, timeout=2):
+        try:
+            if sig != SIGNONE:
+                self._log.debug('[{0}] send signal {1}'.format(self.proc.pid, sig))
+                if sig == SIGKILL:
+                    self.killed = True
+                try:
+                    if platform.system() != 'Windows':
+                        os.killpg(os.getpgid(self.proc.pid), sig)
+                    else:
+                        self.proc.send_signal(sig)
+                except Exception:
+                    self._log.info('[{0}] Failed to kill process'.format(self.proc.pid), exc_info=sys.exc_info())
+            self._log.debug('[{0}] wait begin, timeout {1} sec(s)'.format(self.proc.pid, timeout))
+            self.proc.communicate(timeout=timeout)
+            self._log.debug('[{0}] process ended with return code {1}'.format(self.proc.pid, self.returncode))
+            self.report.end(self.returncode)
+            return True
+        except subprocess.TimeoutExpired:
+            self._log.info('[{0}] timeout waiting for process to end'.format(self.proc.pid))
+            if sig == SIGNONE:
+                self.expired = True
+            return False if sig == SIGKILL else self.sigwait(SIGKILL, 1)
+
+    # called on the client process to wait for it to end naturally
+    def wait(self, timeout):
+        self.sigwait(SIGNONE, timeout)
+
+    @property
+    def returncode(self):
+        return self.proc.returncode if self.proc else None
+
+
+def exec_context(port, logdir, test, prog, is_server):
+    report = ExecReporter(logdir, test, prog)
+    prog.build_command(port)
+    return ExecutionContext(prog.command, prog.workdir, prog.env, prog.stop_signal, is_server, report)
+
+
+def run_test(testdir, logdir, test_dict, max_retry, async_mode=True):
+    logger = multiprocessing.get_logger()
+
+    def ensure_socket_open(sv, port, test):
+        slept = 0.1
+        time.sleep(slept)
+        sleep_step = 0.1
+        while True:
+            if slept > test.delay:
+                logger.warn('[{0}] slept for {1} seconds but server is not open'.format(sv.proc.pid, slept))
+                return False
+            if test.socket == 'domain':
+                if not os.path.exists(domain_socket_path(port)):
+                    logger.debug('[{0}] domain(unix) socket not available yet. slept for {1} seconds so far'.format(sv.proc.pid, slept))
+                    time.sleep(sleep_step)
+                    slept += sleep_step
+            elif test.socket == 'abstract':
+                return True
+            else:
+                # Create sockets every iteration because refused sockets cannot be
+                # reused on some systems.
+                sock4 = socket.socket()
+                sock6 = socket.socket(family=socket.AF_INET6)
+                try:
+                    if sock4.connect_ex(('127.0.0.1', port)) == 0 \
+                            or sock6.connect_ex(('::1', port)) == 0:
+                        return True
+                    if sv.proc.poll() is not None:
+                        logger.warn('[{0}] server process is exited'.format(sv.proc.pid))
+                        return False
+                    logger.debug('[{0}] socket not available yet. slept for {1} seconds so far'.format(sv.proc.pid, slept))
+                    time.sleep(sleep_step)
+                    slept += sleep_step
+                finally:
+                    sock4.close()
+                    sock6.close()
+            logger.debug('[{0}] server ready - waited for {1} seconds'.format(sv.proc.pid, slept))
+            return True
+
+    try:
+        max_bind_retry = 3
+        retry_count = 0
+        bind_retry_count = 0
+        test = TestEntry(testdir, **test_dict)
+        while True:
+            if stop.is_set():
+                logger.debug('Skipping because shutting down')
+                return (retry_count, None)
+            logger.debug('Start')
+            with PortAllocator.alloc_port_scoped(ports, test.socket) as port:
+                logger.debug('Start with port %d' % port)
+                sv = exec_context(port, logdir, test, test.server, True)
+                cl = exec_context(port, logdir, test, test.client, False)
+
+                logger.debug('Starting server')
+                with sv.start():
+                    port_ok = ensure_socket_open(sv, port, test)
+                    if port_ok:
+                        connect_retry_count = 0
+                        max_connect_retry = 12
+                        connect_retry_wait = 0.25
+                        while True:
+                            if sv.proc.poll() is not None:
+                                logger.info('not starting client because server process is absent')
+                                break
+                            logger.debug('Starting client')
+                            cl.start()
+                            logger.debug('Waiting client (up to %d secs)' % test.timeout)
+                            cl.wait(test.timeout)
+                            if not cl.report.maybe_false_positive() or connect_retry_count >= max_connect_retry:
+                                if connect_retry_count > 0 and connect_retry_count < max_connect_retry:
+                                    logger.info('[%s]: Connected after %d retry (%.2f sec each)' % (test.server.name, connect_retry_count, connect_retry_wait))
+                                # Wait for 50ms to see if server does not die at the end.
+                                time.sleep(0.05)
+                                break
+                            logger.debug('Server may not be ready, waiting %.2f second...' % connect_retry_wait)
+                            time.sleep(connect_retry_wait)
+                            connect_retry_count += 1
+
+            if sv.report.maybe_false_positive() and bind_retry_count < max_bind_retry:
+                logger.warn('[%s]: Detected socket bind failure, retrying...', test.server.name)
+                bind_retry_count += 1
+            else:
+                result = RESULT_TIMEOUT if cl.expired else cl.returncode if (cl.proc and cl.proc.poll()) is not None else RESULT_ERROR
+
+                # For servers that handle a controlled shutdown by signal
+                # if they are killed, or return an error code, that is a
+                # problem.  For servers that are not signal-aware, we simply
+                # kill them off; if we didn't kill them off, something else
+                # happened (crashed?)
+                if test.server.stop_signal != 0:
+                    if sv.killed or sv.returncode > 0:
+                        result |= RESULT_ERROR
+                else:
+                    if not sv.killed:
+                        result |= RESULT_ERROR
+
+                if result == 0 or retry_count >= max_retry:
+                    return (retry_count, result)
+                else:
+                    logger.info('[%s-%s]: test failed, retrying...', test.server.name, test.client.name)
+                    retry_count += 1
+    except Exception:
+        if not async_mode:
+            raise
+        logger.warn('Error executing [%s]', test.name, exc_info=True)
+        return (retry_count, RESULT_ERROR)
+    except:
+        logger.info('Interrupted execution', exc_info=True)
+        if not async_mode:
+            raise
+        stop.set()
+        return (retry_count, RESULT_ERROR)
+
+
+class PortAllocator(object):
+    def __init__(self):
+        self._log = multiprocessing.get_logger()
+        self._lock = multiprocessing.Lock()
+        self._ports = set()
+        self._dom_ports = set()
+        self._last_alloc = 0
+
+    def _get_tcp_port(self):
+        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        sock.bind(('', 0))
+        port = sock.getsockname()[1]
+        self._lock.acquire()
+        try:
+            ok = port not in self._ports
+            if ok:
+                self._ports.add(port)
+                self._last_alloc = time.time()
+        finally:
+            self._lock.release()
+            sock.close()
+        return port if ok else self._get_tcp_port()
+
+    def _get_domain_port(self):
+        port = random.randint(1024, 65536)
+        self._lock.acquire()
+        try:
+            ok = port not in self._dom_ports
+            if ok:
+                self._dom_ports.add(port)
+        finally:
+            self._lock.release()
+        return port if ok else self._get_domain_port()
+
+    def alloc_port(self, socket_type):
+        if socket_type in ('domain', 'abstract'):
+            return self._get_domain_port()
+        else:
+            return self._get_tcp_port()
+
+    # static method for inter-process invokation
+    @staticmethod
+    @contextlib.contextmanager
+    def alloc_port_scoped(allocator, socket_type):
+        port = allocator.alloc_port(socket_type)
+        yield port
+        allocator.free_port(socket_type, port)
+
+    def free_port(self, socket_type, port):
+        self._log.debug('free_port')
+        self._lock.acquire()
+        try:
+            if socket_type == 'domain':
+                self._dom_ports.remove(port)
+                path = domain_socket_path(port)
+                if os.path.exists(path):
+                    os.remove(path)
+            elif socket_type == 'abstract':
+                self._dom_ports.remove(port)
+            else:
+                self._ports.remove(port)
+        except IOError:
+            self._log.info('Error while freeing port', exc_info=sys.exc_info())
+        finally:
+            self._lock.release()
+
+
+class NonAsyncResult(object):
+    def __init__(self, value):
+        self._value = value
+
+    def get(self, timeout=None):
+        return self._value
+
+    def wait(self, timeout=None):
+        pass
+
+    def ready(self):
+        return True
+
+    def successful(self):
+        return self._value == 0
+
+
+class TestDispatcher(object):
+    def __init__(self, testdir, basedir, logdir_rel, concurrency):
+        self._log = multiprocessing.get_logger()
+        self.testdir = testdir
+        self._report = SummaryReporter(basedir, logdir_rel, concurrency > 1)
+        self.logdir = self._report.testdir
+        # seems needed for python 2.x to handle keyboard interrupt
+        self._stop = multiprocessing.Event()
+        self._async = concurrency > 1
+        if not self._async:
+            self._pool = None
+            global stop
+            global ports
+            stop = self._stop
+            ports = PortAllocator()
+        else:
+            self._m = multiprocessing.managers.BaseManager()
+            self._m.register('ports', PortAllocator)
+            self._m.start()
+            self._pool = multiprocessing.Pool(concurrency, self._pool_init, (self._m.address,))
+        self._log.debug(
+            'TestDispatcher started with %d concurrent jobs' % concurrency)
+
+    def _pool_init(self, address):
+        global stop
+        global m
+        global ports
+        stop = self._stop
+        m = multiprocessing.managers.BaseManager(address)
+        m.connect()
+        ports = m.ports()
+
+    def _dispatch_sync(self, test, cont, max_retry):
+        r = run_test(self.testdir, self.logdir, test, max_retry, async_mode=False)
+        cont(r)
+        return NonAsyncResult(r)
+
+    def _dispatch_async(self, test, cont, max_retry):
+        self._log.debug('_dispatch_async')
+        return self._pool.apply_async(func=run_test, args=(self.testdir, self.logdir, test, max_retry), callback=cont)
+
+    def dispatch(self, test, max_retry):
+        index = self._report.add_test(test)
+
+        def cont(result):
+            if not self._stop.is_set():
+                if result and len(result) == 2:
+                    retry_count, returncode = result
+                else:
+                    retry_count = 0
+                    returncode = RESULT_ERROR
+                self._log.debug('freeing port')
+                self._log.debug('adding result')
+                self._report.add_result(index, returncode, returncode == RESULT_TIMEOUT, retry_count)
+                self._log.debug('finish continuation')
+        fn = self._dispatch_async if self._async else self._dispatch_sync
+        return fn(test, cont, max_retry)
+
+    def wait(self):
+        if self._async:
+            self._pool.close()
+            self._pool.join()
+            self._m.shutdown()
+        return self._report.end()
+
+    def terminate(self):
+        self._stop.set()
+        if self._async:
+            self._pool.terminate()
+            self._pool.join()
+            self._m.shutdown()
diff --git a/test/crossrunner/setup.cfg b/test/crossrunner/setup.cfg
new file mode 100644
index 0000000..7da1f96
--- /dev/null
+++ b/test/crossrunner/setup.cfg
@@ -0,0 +1,2 @@
+[flake8]
+max-line-length = 100
diff --git a/test/crossrunner/test.py b/test/crossrunner/test.py
new file mode 100644
index 0000000..0e91284
--- /dev/null
+++ b/test/crossrunner/test.py
@@ -0,0 +1,149 @@
+#
+# 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 copy
+import multiprocessing
+import os
+import sys
+from .compat import path_join
+from .util import merge_dict, domain_socket_path
+
+
+class TestProgram(object):
+    def __init__(self, kind, name, protocol, transport, socket, workdir, stop_signal, command, env=None,
+                 extra_args=[], extra_args2=[], join_args=False, **kwargs):
+
+        self.kind = kind
+        self.name = name
+        self.protocol = protocol
+        self.transport = transport
+        self.socket = socket
+        self.workdir = workdir
+        self.stop_signal = stop_signal
+        self.command = None
+        self._base_command = self._fix_cmd_path(command)
+        if env:
+            self.env = copy.copy(os.environ)
+            self.env.update(env)
+        else:
+            self.env = os.environ
+        self._extra_args = extra_args
+        self._extra_args2 = extra_args2
+        self._join_args = join_args
+
+    def _fix_cmd_path(self, cmd):
+        # if the arg is a file in the current directory, make it path
+        def abs_if_exists(arg):
+            p = path_join(self.workdir, arg)
+            return p if os.path.exists(p) else arg
+
+        if cmd[0] == 'python':
+            cmd[0] = sys.executable
+        else:
+            cmd[0] = abs_if_exists(cmd[0])
+        return cmd
+
+    def _socket_args(self, socket, port):
+        return {
+            'ip-ssl': ['--ssl'],
+            'domain': ['--domain-socket=%s' % domain_socket_path(port)],
+            'abstract': ['--abstract-namespace', '--domain-socket=%s' % domain_socket_path(port)],
+        }.get(socket, None)
+
+    def _transport_args(self, transport):
+        return {
+            'zlib': ['--zlib'],
+        }.get(transport, None)
+
+    def build_command(self, port):
+        cmd = copy.copy(self._base_command)
+        args = copy.copy(self._extra_args2)
+        args.append('--protocol=' + self.protocol)
+        args.append('--transport=' + self.transport)
+        transport_args = self._transport_args(self.transport)
+        if transport_args:
+            args += transport_args
+        socket_args = self._socket_args(self.socket, port)
+        if socket_args:
+            args += socket_args
+        args.append('--port=%d' % port)
+        if self._join_args:
+            cmd.append('%s' % " ".join(args))
+        else:
+            cmd.extend(args)
+        if self._extra_args:
+            cmd.extend(self._extra_args)
+        self.command = cmd
+        return self.command
+
+
+class TestEntry(object):
+    def __init__(self, testdir, server, client, delay, timeout, **kwargs):
+        self.testdir = testdir
+        self._log = multiprocessing.get_logger()
+        self._config = kwargs
+        self.protocol = kwargs['protocol']
+        self.transport = kwargs['transport']
+        self.socket = kwargs['socket']
+        srv_dict = self._fix_workdir(merge_dict(self._config, server))
+        cli_dict = self._fix_workdir(merge_dict(self._config, client))
+        cli_dict['extra_args2'] = srv_dict.pop('remote_args', [])
+        srv_dict['extra_args2'] = cli_dict.pop('remote_args', [])
+        self.server = TestProgram('server', **srv_dict)
+        self.client = TestProgram('client', **cli_dict)
+        self.delay = delay
+        self.timeout = timeout
+        self._name = None
+        # results
+        self.success = None
+        self.as_expected = None
+        self.returncode = None
+        self.expired = False
+        self.retry_count = 0
+
+    def _fix_workdir(self, config):
+        key = 'workdir'
+        path = config.get(key, None)
+        if not path:
+            path = self.testdir
+        if os.path.isabs(path):
+            path = os.path.realpath(path)
+        else:
+            path = os.path.realpath(path_join(self.testdir, path))
+        config.update({key: path})
+        return config
+
+    @classmethod
+    def get_name(cls, server, client, protocol, transport, socket, *args, **kwargs):
+        return '%s-%s_%s_%s-%s' % (server, client, protocol, transport, socket)
+
+    @property
+    def name(self):
+        if not self._name:
+            self._name = self.get_name(
+                self.server.name, self.client.name, self.protocol, self.transport, self.socket)
+        return self._name
+
+    @property
+    def transport_name(self):
+        return '%s-%s' % (self.transport, self.socket)
+
+
+def test_name(server, client, protocol, transport, socket, **kwargs):
+    return TestEntry.get_name(server['name'], client['name'], protocol, transport, socket)
diff --git a/test/crossrunner/util.py b/test/crossrunner/util.py
new file mode 100644
index 0000000..c214df8
--- /dev/null
+++ b/test/crossrunner/util.py
@@ -0,0 +1,35 @@
+#
+# 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 copy
+
+
+def domain_socket_path(port):
+    return '/tmp/ThriftTest.thrift.%d' % port
+
+
+def merge_dict(base, update):
+    """Update dict concatenating list values"""
+    res = copy.deepcopy(base)
+    for k, v in list(update.items()):
+        if k in list(res.keys()) and isinstance(v, list):
+            res[k].extend(v)
+        else:
+            res[k] = v
+    return res
diff --git a/test/csharp/Makefile.am b/test/csharp/Makefile.am
new file mode 100644
index 0000000..ad166e3
--- /dev/null
+++ b/test/csharp/Makefile.am
@@ -0,0 +1,95 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+GENERATED = \
+	gen-csharp/Thrift/Test/Bonk.cs \
+	gen-csharp/Thrift/Test/Bools.cs \
+	gen-csharp/Thrift/Test/BoolTest.cs \
+	gen-csharp/Thrift/Test/CrazyNesting.cs \
+	gen-csharp/Thrift/Test/EmptyStruct.cs \
+	gen-csharp/Thrift/Test/GuessProtocolStruct.cs \
+	gen-csharp/Thrift/Test/Insanity.cs \
+	gen-csharp/Thrift/Test/LargeDeltas.cs \
+	gen-csharp/Thrift/Test/ListBonks.cs \
+	gen-csharp/Thrift/Test/ListTypeVersioningV1.cs \
+	gen-csharp/Thrift/Test/ListTypeVersioningV2.cs \
+	gen-csharp/Thrift/Test/NestedListsBonk.cs \
+	gen-csharp/Thrift/Test/NestedListsI32x2.cs \
+	gen-csharp/Thrift/Test/NestedListsI32x3.cs \
+	gen-csharp/Thrift/Test/NestedMixedx2.cs \
+	gen-csharp/Thrift/Test/Numberz.cs \
+	gen-csharp/Thrift/Test/OneField.cs \
+	gen-csharp/Thrift/Test/SecondService.cs \
+	gen-csharp/Thrift/Test/StructA.cs \
+	gen-csharp/Thrift/Test/StructB.cs \
+	gen-csharp/Thrift/Test/ThriftTest.Constants.cs \
+	gen-csharp/Thrift/Test/ThriftTest.cs \
+	gen-csharp/Thrift/Test/VersioningTestV1.cs \
+	gen-csharp/Thrift/Test/VersioningTestV2.cs \
+	gen-csharp/Thrift/Test/Xception.cs \
+	gen-csharp/Thrift/Test/Xception2.cs \
+	gen-csharp/Thrift/Test/Xtruct.cs \
+	gen-csharp/Thrift/Test/Xtruct2.cs \
+	gen-csharp/Thrift/Test/Xtruct3.cs
+
+BUILT_SOURCES = $(GENERATED)
+
+if MONO_MCS
+CSC = mcs
+else
+CSC = gmcs
+endif
+
+if NET_2_0
+CSC_DEFINES = -d:NET_2_0
+endif
+
+LIBDIR = $(top_builddir)/lib/csharp
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+$(GENERATED): $(top_srcdir)/test/ThriftTest.thrift $(THRIFT)
+	$(THRIFT) --gen csharp -o . $<
+
+precross: TestClientServer.exe
+
+ThriftImpl.dll: $(GENERATED) $(LIBDIR)/Thrift.dll
+	$(CSC) $(CSC_DEFINES) -t:library -out:$@ -reference:$(LIBDIR)/Thrift.dll $(GENERATED)
+
+SRCS = TestClient.cs TestServer.cs Program.cs
+
+TestClientServer.exe: $(SRCS) ThriftImpl.dll
+	$(CSC) $(CSC_DEFINES) -out:$@ -reference:$(LIBDIR)/Thrift.dll -reference:ThriftImpl.dll $(SRCS)
+
+clean-local:
+	$(RM) -rf gen-csharp *.exe *.dll
+
+TESTPORT = 9500
+check-local: TestClientServer.exe
+	MONO_PATH=$(LIBDIR) timeout 10 mono TestClientServer.exe server --port=$(TESTPORT) &
+	sleep 1
+	MONO_PATH=$(LIBDIR) mono TestClientServer.exe client --port=$(TESTPORT)
+
+EXTRA_DIST = \
+	Properties/AssemblyInfo.cs \
+	ThriftTest.csproj \
+	ThriftTest.sln \
+	Program.cs \
+	TestServer.cs \
+	TestClient.cs
diff --git a/test/csharp/Program.cs b/test/csharp/Program.cs
new file mode 100644
index 0000000..8ec00e3
--- /dev/null
+++ b/test/csharp/Program.cs
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+
+using System;
+using Thrift.Transport;
+using Thrift.Protocol;
+using Thrift.Test; //generated code
+
+namespace Test
+{
+    class Program
+    {
+        static int Main(string[] args)
+        {
+            if (args.Length == 0)
+            {
+                Console.WriteLine("must provide 'server' or 'client' arg");
+                return -1;
+            }
+
+            try
+            {
+                Console.SetBufferSize(Console.BufferWidth, 4096);
+            }
+            catch (Exception)
+            {
+                Console.WriteLine("Failed to grow scroll-back buffer");
+            }
+
+            string[] subArgs = new string[args.Length - 1];
+            for(int i = 1; i < args.Length; i++)
+            {
+                subArgs[i-1] = args[i];
+            }
+            if (args[0] == "client")
+            {
+                return TestClient.Execute(subArgs);
+            }
+            else if (args[0] == "server")
+            {
+                return TestServer.Execute(subArgs) ? 0 : 1;
+            }
+            else
+            {
+                Console.WriteLine("first argument must be 'server' or 'client'");
+            }
+            return 0;
+        }
+    }
+}
diff --git a/test/csharp/Properties/AssemblyInfo.cs b/test/csharp/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..b1101a1
--- /dev/null
+++ b/test/csharp/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ThriftTest")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f41b193b-f1ab-48ee-8843-f88e43084e26")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/test/csharp/TestClient.cs b/test/csharp/TestClient.cs
new file mode 100644
index 0000000..949c06e
--- /dev/null
+++ b/test/csharp/TestClient.cs
@@ -0,0 +1,870 @@
+/*
+ * 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.
+ */
+
+using System;
+using System.Linq;
+using System.Diagnostics;
+using System.Collections.Generic;
+using System.Threading;
+using System.Security.Cryptography.X509Certificates;
+using Thrift.Collections;
+using Thrift.Protocol;
+using Thrift.Transport;
+using Thrift.Test;
+using System.Security.Authentication;
+
+namespace Test
+{
+    public class TestClient
+    {
+        public class TestParams
+        {
+            public int numIterations = 1;
+            public string host = "localhost";
+            public int port = 9090;
+            public string url;
+            public string pipe;
+            public bool buffered;
+            public bool framed;
+            public string protocol;
+            public bool encrypted = false;
+            public bool multiplexed = false;
+            protected bool _isFirstTransport = true;
+
+
+            public TTransport CreateTransport()
+            {
+                if (url == null)
+                {
+                    // endpoint transport
+                    TTransport trans = null;
+                    if (pipe != null)
+                        trans = new TNamedPipeClientTransport(pipe);
+                    else
+                    {
+                        if (encrypted)
+                        {
+                            string certPath = "../keys/client.p12";
+                            X509Certificate cert = new X509Certificate2(certPath, "thrift");
+                            trans = new TTLSSocket(host, port, 0, cert, 
+                                (o, c, chain, errors) => true, 
+                                null, SslProtocols.Tls);
+                        }
+                        else
+                        {
+                            trans = new TSocket(host, port);
+                        }
+                    }
+
+                    // layered transport
+                    if (buffered)
+                        trans = new TBufferedTransport(trans);
+                    if (framed)
+                        trans = new TFramedTransport(trans);
+
+                    if (_isFirstTransport)
+                    {
+                        //ensure proper open/close of transport
+                        trans.Open();
+                        trans.Close();
+                        _isFirstTransport = false;
+                    }
+                    return trans;
+                }
+                else
+                {
+                    return new THttpClient(new Uri(url));
+                }
+            }
+
+            public TProtocol CreateProtocol(TTransport transport)
+            {
+                if (protocol == "compact")
+                    return new TCompactProtocol(transport);
+                else if (protocol == "json")
+                    return new TJSONProtocol(transport);
+                else
+                    return new TBinaryProtocol(transport);
+            }
+        };
+
+        private const int ErrorBaseTypes = 1;
+        private const int ErrorStructs = 2;
+        private const int ErrorContainers = 4;
+        private const int ErrorExceptions = 8;
+        private const int ErrorProtocol = 16;
+        private const int ErrorUnknown = 64;
+
+        private class ClientTest
+        {
+            private readonly TestParams param;
+            private readonly TTransport transport;
+            private readonly SecondService.Client second;
+            private readonly ThriftTest.Client client;
+            private readonly int numIterations;
+            private bool done;
+
+            public int ReturnCode { get; set; }
+
+            public ClientTest(TestParams paramin)
+            {
+                param = paramin;
+                transport = param.CreateTransport();
+                TProtocol protocol = param.CreateProtocol(transport);
+                if (param.multiplexed)
+                {
+                    second = new SecondService.Client(new TMultiplexedProtocol(protocol, "SecondService"));
+                }
+                client = new ThriftTest.Client(protocol);
+                numIterations = param.numIterations;
+            }
+            public void Execute()
+            {
+                if (done)
+                {
+                    Console.WriteLine("Execute called more than once");
+                    throw new InvalidOperationException();
+                }
+
+                for (int i = 0; i < numIterations; i++)
+                {
+                    try
+                    {
+                        if (!transport.IsOpen)
+                            transport.Open();
+                    }
+                    catch (TTransportException ex)
+                    {
+                        Console.WriteLine("*** FAILED ***");
+                        Console.WriteLine("Connect failed: " + ex.Message);
+                        ReturnCode |= ErrorUnknown;
+                        Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                        continue;
+                    }
+
+                    try
+                    {
+                        ReturnCode |= ExecuteClientTest(client, second, param);
+                    }
+                    catch (Exception ex)
+                    {
+                        Console.WriteLine("*** FAILED ***");
+                        Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                        ReturnCode |= ErrorUnknown;
+                    }
+                }
+                try
+                {
+                    transport.Close();
+                }
+                catch(Exception ex)
+                {
+                    Console.WriteLine("Error while closing transport");
+                    Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                }
+                done = true;
+            }
+        }
+
+        public static int Execute(string[] args)
+        {
+            try
+            {
+                TestParams param = new TestParams();
+                int numThreads = 1;
+                try
+                {
+                    for (int i = 0; i < args.Length; i++)
+                    {
+                        if (args[i] == "-u")
+                        {
+                            param.url = args[++i];
+                        }
+                        else if (args[i] == "-n")
+                        {
+                            param.numIterations = Convert.ToInt32(args[++i]);
+                        }
+                        else if (args[i] == "-pipe")  // -pipe <name>
+                        {
+                            param.pipe = args[++i];
+                            Console.WriteLine("Using named pipes transport");
+                        }
+                        else if (args[i].Contains("--host="))
+                        {
+                            param.host = args[i].Substring(args[i].IndexOf("=") + 1);
+                        }
+                        else if (args[i].Contains("--port="))
+                        {
+                            param.port = int.Parse(args[i].Substring(args[i].IndexOf("=")+1));
+                        }
+                        else if (args[i] == "-b" || args[i] == "--buffered" || args[i] == "--transport=buffered")
+                        {
+                            param.buffered = true;
+                            Console.WriteLine("Using buffered sockets");
+                        }
+                        else if (args[i] == "-f" || args[i] == "--framed"  || args[i] == "--transport=framed")
+                        {
+                            param.framed = true;
+                            Console.WriteLine("Using framed transport");
+                        }
+                        else if (args[i] == "-t")
+                        {
+                            numThreads = Convert.ToInt32(args[++i]);
+                        }
+                        else if (args[i] == "--compact" || args[i] == "--protocol=compact" || args[i] == "--protocol=multic")
+                        {
+                            param.protocol = "compact";
+                            Console.WriteLine("Using compact protocol");
+                        }
+                        else if (args[i] == "--json" || args[i] == "--protocol=json" || args[i] == "--protocol=multij")
+                        {
+                            param.protocol = "json";
+                            Console.WriteLine("Using JSON protocol");
+                        }
+                        else if (args[i] == "--ssl")
+                        {
+                            param.encrypted = true;
+                            Console.WriteLine("Using encrypted transport");
+                        }
+
+                        if (args[i].StartsWith("--protocol=multi"))
+                        {
+                            param.multiplexed = true;
+                        }
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    Console.WriteLine("Error while  parsing arguments");
+                    Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                    return ErrorUnknown;
+                }
+
+                var tests = Enumerable.Range(0, numThreads).Select(_ => new ClientTest(param)).ToArray();
+                //issue tests on separate threads simultaneously
+                var threads = tests.Select(test => new Thread(test.Execute)).ToArray();
+                DateTime start = DateTime.Now;
+                foreach (var t in threads)
+                    t.Start();
+                foreach (var t in threads)
+                    t.Join();
+                Console.WriteLine("Total time: " + (DateTime.Now - start));
+                Console.WriteLine();
+                return tests.Select(t => t.ReturnCode).Aggregate((r1, r2) => r1 | r2);
+            }
+            catch (Exception outerEx)
+            {
+                Console.WriteLine("*** FAILED ***");
+                Console.WriteLine("Unexpected error");
+                Console.WriteLine(outerEx.Message + " ST: " + outerEx.StackTrace);
+                return ErrorUnknown;
+            }
+        }
+
+        public static string BytesToHex(byte[] data) {
+            return BitConverter.ToString(data).Replace("-", string.Empty);
+        }
+
+        public static byte[] PrepareTestData(bool randomDist, bool huge)
+        {
+            // huge = true tests for THRIFT-4372
+            byte[] retval = new byte[huge ? 0x12345 : 0x100];
+            int initLen = retval.Length;
+
+            // linear distribution, unless random is requested
+            if (!randomDist) {
+                for (var i = 0; i < initLen; ++i) {
+                    retval[i] = (byte)i;
+                }
+                return retval;
+            }
+
+            // random distribution
+            for (var i = 0; i < initLen; ++i) {
+                retval[i] = (byte)0;
+            }
+            var rnd = new Random();
+            for (var i = 1; i < initLen; ++i) {
+                while( true) {
+                    int nextPos = rnd.Next() % initLen;
+                    if (retval[nextPos] == 0) {
+                        retval[nextPos] = (byte)i;
+                        break;
+                    }
+                }
+            }
+            return retval;
+        }
+
+        public static int ExecuteClientTest(ThriftTest.Client client, SecondService.Client second, TestParams param)
+        {
+            int returnCode = 0;
+
+            Console.Write("testVoid()");
+            client.testVoid();
+            Console.WriteLine(" = void");
+
+            Console.Write("testString(\"Test\")");
+            string s = client.testString("Test");
+            Console.WriteLine(" = \"" + s + "\"");
+            if ("Test" != s)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            if (param.multiplexed)
+            {
+                Console.WriteLine("secondTestString(\"Test2\")");
+                s = second.secondtestString("Test2");
+              Console.WriteLine(" = \"" + s + "\"");
+              if ("testString(\"Test2\")" != s)
+              {
+                  Console.WriteLine("*** FAILED ***");
+                  returnCode |= ErrorProtocol;
+              }
+            }
+
+            Console.Write("testBool(true)");
+            bool t = client.testBool((bool)true);
+            Console.WriteLine(" = " + t);
+            if (!t)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+            Console.Write("testBool(false)");
+            bool f = client.testBool((bool)false);
+            Console.WriteLine(" = " + f);
+            if (f)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testByte(1)");
+            sbyte i8 = client.testByte((sbyte)1);
+            Console.WriteLine(" = " + i8);
+            if (1 != i8)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testI32(-1)");
+            int i32 = client.testI32(-1);
+            Console.WriteLine(" = " + i32);
+            if (-1 != i32)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testI64(-34359738368)");
+            long i64 = client.testI64(-34359738368);
+            Console.WriteLine(" = " + i64);
+            if (-34359738368 != i64)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            // TODO: Validate received message
+            Console.Write("testDouble(5.325098235)");
+            double dub = client.testDouble(5.325098235);
+            Console.WriteLine(" = " + dub);
+            if (5.325098235 != dub)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+            Console.Write("testDouble(-0.000341012439638598279)");
+            dub = client.testDouble(-0.000341012439638598279);
+            Console.WriteLine(" = " + dub);
+            if (-0.000341012439638598279 != dub)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            for (i32 = 0; i32 < 2; ++i32)
+            {
+                var huge = (i32 > 0);
+                byte[] binOut = PrepareTestData(false,huge);
+                Console.Write("testBinary(" + BytesToHex(binOut) + ")");
+                try
+                {
+                    byte[] binIn = client.testBinary(binOut);
+                    Console.WriteLine(" = " + BytesToHex(binIn));
+                    if (binIn.Length != binOut.Length)
+                    {
+                        Console.WriteLine("*** FAILED ***");
+                        returnCode |= ErrorBaseTypes;
+                    }
+                    for (int ofs = 0; ofs < Math.Min(binIn.Length, binOut.Length); ++ofs)
+                        if (binIn[ofs] != binOut[ofs])
+                        {
+                            Console.WriteLine("*** FAILED ***");
+                            returnCode |= ErrorBaseTypes;
+                        }
+                }
+                catch (Thrift.TApplicationException ex)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorBaseTypes;
+                    Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                }
+            }
+
+            // binary equals? only with hashcode option enabled ...
+            Console.WriteLine("Test CrazyNesting");
+            if( typeof(CrazyNesting).GetMethod("Equals").DeclaringType == typeof(CrazyNesting))
+            {
+                CrazyNesting one = new CrazyNesting();
+                CrazyNesting two = new CrazyNesting();
+                one.String_field = "crazy";
+                two.String_field = "crazy";
+                one.Binary_field = new byte[10] { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xFF };
+                two.Binary_field = new byte[10] { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xFF };
+                if (!one.Equals(two))
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorContainers;
+                    throw new Exception("CrazyNesting.Equals failed");
+                }
+            }
+
+            // TODO: Validate received message
+            Console.Write("testStruct({\"Zero\", 1, -3, -5})");
+            Xtruct o = new Xtruct();
+            o.String_thing = "Zero";
+            o.Byte_thing = (sbyte)1;
+            o.I32_thing = -3;
+            o.I64_thing = -5;
+            Xtruct i = client.testStruct(o);
+            Console.WriteLine(" = {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}");
+
+            // TODO: Validate received message
+            Console.Write("testNest({1, {\"Zero\", 1, -3, -5}, 5})");
+            Xtruct2 o2 = new Xtruct2();
+            o2.Byte_thing = (sbyte)1;
+            o2.Struct_thing = o;
+            o2.I32_thing = 5;
+            Xtruct2 i2 = client.testNest(o2);
+            i = i2.Struct_thing;
+            Console.WriteLine(" = {" + i2.Byte_thing + ", {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}, " + i2.I32_thing + "}");
+
+            Dictionary<int, int> mapout = new Dictionary<int, int>();
+            for (int j = 0; j < 5; j++)
+            {
+                mapout[j] = j - 10;
+            }
+            Console.Write("testMap({");
+            bool first = true;
+            foreach (int key in mapout.Keys)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(key + " => " + mapout[key]);
+            }
+            Console.Write("})");
+
+            Dictionary<int, int> mapin = client.testMap(mapout);
+
+            Console.Write(" = {");
+            first = true;
+            foreach (int key in mapin.Keys)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(key + " => " + mapin[key]);
+            }
+            Console.WriteLine("}");
+
+            // TODO: Validate received message
+            List<int> listout = new List<int>();
+            for (int j = -2; j < 3; j++)
+            {
+                listout.Add(j);
+            }
+            Console.Write("testList({");
+            first = true;
+            foreach (int j in listout)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.Write("})");
+
+            List<int> listin = client.testList(listout);
+
+            Console.Write(" = {");
+            first = true;
+            foreach (int j in listin)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.WriteLine("}");
+
+            //set
+            // TODO: Validate received message
+            THashSet<int> setout = new THashSet<int>();
+            for (int j = -2; j < 3; j++)
+            {
+                setout.Add(j);
+            }
+            Console.Write("testSet({");
+            first = true;
+            foreach (int j in setout)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.Write("})");
+
+            THashSet<int> setin = client.testSet(setout);
+
+            Console.Write(" = {");
+            first = true;
+            foreach (int j in setin)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.WriteLine("}");
+
+
+            Console.Write("testEnum(ONE)");
+            Numberz ret = client.testEnum(Numberz.ONE);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.ONE != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(TWO)");
+            ret = client.testEnum(Numberz.TWO);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.TWO != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(THREE)");
+            ret = client.testEnum(Numberz.THREE);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.THREE != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(FIVE)");
+            ret = client.testEnum(Numberz.FIVE);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.FIVE != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(EIGHT)");
+            ret = client.testEnum(Numberz.EIGHT);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.EIGHT != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testTypedef(309858235082523)");
+            long uid = client.testTypedef(309858235082523L);
+            Console.WriteLine(" = " + uid);
+            if (309858235082523L != uid)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            // TODO: Validate received message
+            Console.Write("testMapMap(1)");
+            Dictionary<int, Dictionary<int, int>> mm = client.testMapMap(1);
+            Console.Write(" = {");
+            foreach (int key in mm.Keys)
+            {
+                Console.Write(key + " => {");
+                Dictionary<int, int> m2 = mm[key];
+                foreach (int k2 in m2.Keys)
+                {
+                    Console.Write(k2 + " => " + m2[k2] + ", ");
+                }
+                Console.Write("}, ");
+            }
+            Console.WriteLine("}");
+
+            // TODO: Validate received message
+            Insanity insane = new Insanity();
+            insane.UserMap = new Dictionary<Numberz, long>();
+            insane.UserMap[Numberz.FIVE] = 5000L;
+            Xtruct truck = new Xtruct();
+            truck.String_thing = "Truck";
+            truck.Byte_thing = (sbyte)8;
+            truck.I32_thing = 8;
+            truck.I64_thing = 8;
+            insane.Xtructs = new List<Xtruct>();
+            insane.Xtructs.Add(truck);
+            Console.Write("testInsanity()");
+            Dictionary<long, Dictionary<Numberz, Insanity>> whoa = client.testInsanity(insane);
+            Console.Write(" = {");
+            foreach (long key in whoa.Keys)
+            {
+                Dictionary<Numberz, Insanity> val = whoa[key];
+                Console.Write(key + " => {");
+
+                foreach (Numberz k2 in val.Keys)
+                {
+                    Insanity v2 = val[k2];
+
+                    Console.Write(k2 + " => {");
+                    Dictionary<Numberz, long> userMap = v2.UserMap;
+
+                    Console.Write("{");
+                    if (userMap != null)
+                    {
+                        foreach (Numberz k3 in userMap.Keys)
+                        {
+                            Console.Write(k3 + " => " + userMap[k3] + ", ");
+                        }
+                    }
+                    else
+                    {
+                        Console.Write("null");
+                    }
+                    Console.Write("}, ");
+
+                    List<Xtruct> xtructs = v2.Xtructs;
+
+                    Console.Write("{");
+                    if (xtructs != null)
+                    {
+                        foreach (Xtruct x in xtructs)
+                        {
+                            Console.Write("{\"" + x.String_thing + "\", " + x.Byte_thing + ", " + x.I32_thing + ", " + x.I32_thing + "}, ");
+                        }
+                    }
+                    else
+                    {
+                        Console.Write("null");
+                    }
+                    Console.Write("}");
+
+                    Console.Write("}, ");
+                }
+                Console.Write("}, ");
+            }
+            Console.WriteLine("}");
+
+            sbyte arg0 = 1;
+            int arg1 = 2;
+            long arg2 = long.MaxValue;
+            Dictionary<short, string> multiDict = new Dictionary<short, string>();
+            multiDict[1] = "one";
+            Numberz arg4 = Numberz.FIVE;
+            long arg5 = 5000000;
+            Console.Write("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")");
+            Xtruct multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5);
+            Console.Write(" = Xtruct(byte_thing:" + multiResponse.Byte_thing + ",String_thing:" + multiResponse.String_thing
+                        + ",i32_thing:" + multiResponse.I32_thing + ",i64_thing:" + multiResponse.I64_thing + ")\n");
+
+            try
+            {
+                Console.WriteLine("testException(\"Xception\")");
+                client.testException("Xception");
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Xception ex)
+            {
+                if (ex.ErrorCode != 1001 || ex.Message != "Xception")
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testException(\"TException\")");
+                client.testException("TException");
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Thrift.TException)
+            {
+                // OK
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testException(\"ok\")");
+                client.testException("ok");
+                // OK
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+
+            try
+            {
+                Console.WriteLine("testMultiException(\"Xception\", ...)");
+                client.testMultiException("Xception", "ignore");
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Xception ex)
+            {
+                if (ex.ErrorCode != 1001 || ex.Message != "This is an Xception")
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testMultiException(\"Xception2\", ...)");
+                client.testMultiException("Xception2", "ignore");
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Xception2 ex)
+            {
+                if (ex.ErrorCode != 2002 || ex.Struct_thing.String_thing != "This is an Xception2")
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testMultiException(\"success\", \"OK\")");
+                if ("OK" != client.testMultiException("success", "OK").String_thing)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+
+            Stopwatch sw = new Stopwatch();
+            sw.Start();
+            Console.WriteLine("Test Oneway(1)");
+            client.testOneway(1);
+            sw.Stop();
+            if (sw.ElapsedMilliseconds > 1000)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("Test Calltime()");
+            var times = 50;
+            sw.Reset();
+            sw.Start();
+            for (int k = 0; k < times; ++k)
+                client.testVoid();
+            sw.Stop();
+            Console.WriteLine(" = {0} ms a testVoid() call", sw.ElapsedMilliseconds / times);
+            return returnCode;
+        }
+    }
+}
diff --git a/test/csharp/TestServer.cs b/test/csharp/TestServer.cs
new file mode 100644
index 0000000..bf645c2
--- /dev/null
+++ b/test/csharp/TestServer.cs
@@ -0,0 +1,535 @@
+/*
+ * 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.
+ */
+
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+using System;
+using System.Collections.Generic;
+using System.Security.Cryptography.X509Certificates;
+using Thrift.Collections;
+using Thrift.Test; //generated code
+using Thrift.Transport;
+using Thrift.Protocol;
+using Thrift.Server;
+using Thrift;
+using System.Threading;
+using System.Text;
+using System.Security.Authentication;
+
+namespace Test
+{
+    public class TestServer
+    {
+        public static int _clientID = -1;
+        public delegate void TestLogDelegate(string msg, params object[] values);
+
+        public class TradeServerEventHandler : TServerEventHandler
+        {
+            public int callCount = 0;
+            public void preServe()
+            {
+                callCount++;
+            }
+            public Object createContext(Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output)
+            {
+                callCount++;
+                return null;
+            }
+            public void deleteContext(Object serverContext, Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output)
+            {
+                callCount++;
+            }
+            public void processContext(Object serverContext, Thrift.Transport.TTransport transport)
+            {
+                callCount++;
+            }
+        };
+
+
+        public class TestHandler : ThriftTest.Iface, Thrift.TControllingHandler
+        {
+            public TServer server { get; set; }
+            private int handlerID;
+            private StringBuilder reusableStringBuilder = new StringBuilder();
+            private TestLogDelegate testLogDelegate;
+
+            public TestHandler()
+            {
+                handlerID = Interlocked.Increment(ref _clientID);
+                testLogDelegate += testConsoleLogger;
+                testLogDelegate.Invoke("New TestHandler instance created");
+            }
+
+            public void testConsoleLogger(string msg, params object[] values)
+            {
+                reusableStringBuilder.Clear();
+                reusableStringBuilder.AppendFormat("handler{0:D3}:",handlerID);
+                reusableStringBuilder.AppendFormat(msg, values);
+                reusableStringBuilder.AppendLine();
+                Console.Write( reusableStringBuilder.ToString() );
+            }
+
+            public void testVoid()
+            {
+                testLogDelegate.Invoke("testVoid()");
+            }
+
+            public string testString(string thing)
+            {
+                testLogDelegate.Invoke("testString({0})", thing);
+                return thing;
+            }
+
+            public bool testBool(bool thing)
+            {
+                testLogDelegate.Invoke("testBool({0})", thing);
+                return thing;
+            }
+
+            public sbyte testByte(sbyte thing)
+            {
+                testLogDelegate.Invoke("testByte({0})", thing);
+                return thing;
+            }
+
+            public int testI32(int thing)
+            {
+                testLogDelegate.Invoke("testI32({0})", thing);
+                return thing;
+            }
+
+            public long testI64(long thing)
+            {
+                testLogDelegate.Invoke("testI64({0})", thing);
+                return thing;
+            }
+
+            public double testDouble(double thing)
+            {
+                testLogDelegate.Invoke("testDouble({0})", thing);
+                return thing;
+            }
+
+            public byte[] testBinary(byte[] thing)
+            {
+                string hex = BitConverter.ToString(thing).Replace("-", string.Empty);
+                testLogDelegate.Invoke("testBinary({0:X})", hex);
+                return thing;
+            }
+
+            public Xtruct testStruct(Xtruct thing)
+            {
+                testLogDelegate.Invoke("testStruct({{\"{0}\", {1}, {2}, {3}}})", thing.String_thing, thing.Byte_thing, thing.I32_thing, thing.I64_thing);
+                return thing;
+            }
+
+            public Xtruct2 testNest(Xtruct2 nest)
+            {
+                Xtruct thing = nest.Struct_thing;
+                testLogDelegate.Invoke("testNest({{{0}, {{\"{1}\", {2}, {3}, {4}, {5}}}}})",
+                                 nest.Byte_thing,
+                                 thing.String_thing,
+                                 thing.Byte_thing,
+                                 thing.I32_thing,
+                                 thing.I64_thing,
+                                 nest.I32_thing);
+                return nest;
+            }
+
+            public Dictionary<int, int> testMap(Dictionary<int, int> thing)
+            {
+                reusableStringBuilder.Clear();
+                reusableStringBuilder.Append("testMap({{");
+                bool first = true;
+                foreach (int key in thing.Keys)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        reusableStringBuilder.Append(", ");
+                    }
+                    reusableStringBuilder.AppendFormat("{0} => {1}", key, thing[key]);
+                }
+                reusableStringBuilder.Append("}})");
+                testLogDelegate.Invoke(reusableStringBuilder.ToString());
+                return thing;
+            }
+
+            public Dictionary<string, string> testStringMap(Dictionary<string, string> thing)
+            {
+                reusableStringBuilder.Clear();
+                reusableStringBuilder.Append("testStringMap({{");
+                bool first = true;
+                foreach (string key in thing.Keys)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        reusableStringBuilder.Append(", ");
+                    }
+                    reusableStringBuilder.AppendFormat("{0} => {1}", key, thing[key]);
+                }
+                reusableStringBuilder.Append("}})");
+                testLogDelegate.Invoke(reusableStringBuilder.ToString());
+                return thing;
+            }
+
+            public THashSet<int> testSet(THashSet<int> thing)
+            {
+                reusableStringBuilder.Clear();
+                reusableStringBuilder.Append("testSet({{");
+                bool first = true;
+                foreach (int elem in thing)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        reusableStringBuilder.Append(", ");
+                    }
+                    reusableStringBuilder.AppendFormat("{0}", elem);
+                }
+                reusableStringBuilder.Append("}})");
+                testLogDelegate.Invoke(reusableStringBuilder.ToString());
+                return thing;
+            }
+
+            public List<int> testList(List<int> thing)
+            {
+                reusableStringBuilder.Clear();
+                reusableStringBuilder.Append("testList({{");
+                bool first = true;
+                foreach (int elem in thing)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        reusableStringBuilder.Append(", ");
+                    }
+                    reusableStringBuilder.AppendFormat("{0}", elem);
+                }
+                reusableStringBuilder.Append("}})");
+                testLogDelegate.Invoke(reusableStringBuilder.ToString());
+                return thing;
+            }
+
+            public Numberz testEnum(Numberz thing)
+            {
+                testLogDelegate.Invoke("testEnum({0})", thing);
+                return thing;
+            }
+
+            public long testTypedef(long thing)
+            {
+                testLogDelegate.Invoke("testTypedef({0})", thing);
+                return thing;
+            }
+
+            public Dictionary<int, Dictionary<int, int>> testMapMap(int hello)
+            {
+                testLogDelegate.Invoke("testMapMap({0})", hello);
+                Dictionary<int, Dictionary<int, int>> mapmap =
+                  new Dictionary<int, Dictionary<int, int>>();
+
+                Dictionary<int, int> pos = new Dictionary<int, int>();
+                Dictionary<int, int> neg = new Dictionary<int, int>();
+                for (int i = 1; i < 5; i++)
+                {
+                    pos[i] = i;
+                    neg[-i] = -i;
+                }
+
+                mapmap[4] = pos;
+                mapmap[-4] = neg;
+
+                return mapmap;
+            }
+
+            // Insanity
+            // returns:
+            // { 1 => { 2 => argument,
+            //          3 => argument,
+            //        },
+            //   2 => { 6 => <empty Insanity struct>, },
+            // }
+            public Dictionary<long, Dictionary<Numberz, Insanity>> testInsanity(Insanity argument)
+            {
+                testLogDelegate.Invoke("testInsanity()");
+
+                Dictionary<Numberz, Insanity> first_map = new Dictionary<Numberz, Insanity>();
+                Dictionary<Numberz, Insanity> second_map = new Dictionary<Numberz, Insanity>(); ;
+
+                first_map[Numberz.TWO] = argument;
+                first_map[Numberz.THREE] = argument;
+
+                second_map[Numberz.SIX] = new Insanity();
+
+                Dictionary<long, Dictionary<Numberz, Insanity>> insane =
+                  new Dictionary<long, Dictionary<Numberz, Insanity>>();
+                insane[(long)1] = first_map;
+                insane[(long)2] = second_map;
+
+                return insane;
+            }
+
+            public Xtruct testMulti(sbyte arg0, int arg1, long arg2, Dictionary<short, string> arg3, Numberz arg4, long arg5)
+            {
+                testLogDelegate.Invoke("testMulti()");
+
+                Xtruct hello = new Xtruct(); ;
+                hello.String_thing = "Hello2";
+                hello.Byte_thing = arg0;
+                hello.I32_thing = arg1;
+                hello.I64_thing = arg2;
+                return hello;
+            }
+
+            /**
+             * Print 'testException(%s)' with arg as '%s'
+             * @param string arg - a string indication what type of exception to throw
+             * if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
+             * elsen if arg == "TException" throw TException
+             * else do not throw anything
+             */
+            public void testException(string arg)
+            {
+                testLogDelegate.Invoke("testException({0})", arg);
+                if (arg == "Xception")
+                {
+                    Xception x = new Xception();
+                    x.ErrorCode = 1001;
+                    x.Message = arg;
+                    throw x;
+                }
+                if (arg == "TException")
+                {
+                    throw new Thrift.TException();
+                }
+                return;
+            }
+
+            public Xtruct testMultiException(string arg0, string arg1)
+            {
+                testLogDelegate.Invoke("testMultiException({0}, {1})", arg0,arg1);
+                if (arg0 == "Xception")
+                {
+                    Xception x = new Xception();
+                    x.ErrorCode = 1001;
+                    x.Message = "This is an Xception";
+                    throw x;
+                }
+                else if (arg0 == "Xception2")
+                {
+                    Xception2 x = new Xception2();
+                    x.ErrorCode = 2002;
+                    x.Struct_thing = new Xtruct();
+                    x.Struct_thing.String_thing = "This is an Xception2";
+                    throw x;
+                }
+
+                Xtruct result = new Xtruct();
+                result.String_thing = arg1;
+                return result;
+            }
+
+            public void testStop()
+            {
+                if (server != null)
+                {
+                    server.Stop();
+                }
+            }
+
+            public void testOneway(int arg)
+            {
+                testLogDelegate.Invoke("testOneway({0}), sleeping...", arg);
+                System.Threading.Thread.Sleep(arg * 1000);
+                testLogDelegate.Invoke("testOneway finished");
+            }
+
+        } // class TestHandler
+
+        private enum ServerType
+        {
+            TSimpleServer,
+            TThreadedServer,
+            TThreadPoolServer,
+        }
+
+        private enum ProcessorFactoryType
+        {
+            TSingletonProcessorFactory,
+            TPrototypeProcessorFactory,
+        }
+
+        public static bool Execute(string[] args)
+        {
+            try
+            {
+                bool useBufferedSockets = false, useFramed = false, useEncryption = false, compact = false, json = false;
+                ServerType serverType = ServerType.TSimpleServer;
+                ProcessorFactoryType processorFactoryType = ProcessorFactoryType.TSingletonProcessorFactory;
+                int port = 9090;
+                string pipe = null;
+                for (int i = 0; i < args.Length; i++)
+                {
+                    if (args[i] == "-pipe")  // -pipe name
+                    {
+                        pipe = args[++i];
+                    }
+                    else if (args[i].Contains("--port="))
+                    {
+                        port = int.Parse(args[i].Substring(args[i].IndexOf("=") + 1));
+                    }
+                    else if (args[i] == "-b" || args[i] == "--buffered" || args[i] == "--transport=buffered")
+                    {
+                        useBufferedSockets = true;
+                    }
+                    else if (args[i] == "-f" || args[i] == "--framed" || args[i] == "--transport=framed")
+                    {
+                        useFramed = true;
+                    }
+                    else if (args[i] == "--compact" || args[i] == "--protocol=compact")
+                    {
+                        compact = true;
+                    }
+                    else if (args[i] == "--json" || args[i] == "--protocol=json")
+                    {
+                        json = true;
+                    }
+                    else if (args[i] == "--threaded" || args[i] == "--server-type=threaded")
+                    {
+                        serverType = ServerType.TThreadedServer;
+                    }
+                    else if (args[i] == "--threadpool" || args[i] == "--server-type=threadpool")
+                    {
+                        serverType = ServerType.TThreadPoolServer;
+                    }
+                    else if (args[i] == "--prototype" || args[i] == "--processor=prototype")
+                    {
+                        processorFactoryType = ProcessorFactoryType.TPrototypeProcessorFactory;
+                    }
+                    else if (args[i] == "--ssl")
+                    {
+                        useEncryption = true;
+                    }
+                }
+
+                // Transport
+                TServerTransport trans;
+                if (pipe != null)
+                {
+                    trans = new TNamedPipeServerTransport(pipe);
+                }
+                else
+                {
+                    if (useEncryption)
+                    {
+                        string certPath = "../keys/server.p12";
+                        trans = new TTLSServerSocket(port, 0, useBufferedSockets, new X509Certificate2(certPath, "thrift"), 
+                            null,
+                            null, SslProtocols.Tls);
+                    }
+                    else
+                    {
+                        trans = new TServerSocket(port, 0, useBufferedSockets);
+                    }
+                }
+
+                TProtocolFactory proto;
+                if (compact)
+                    proto = new TCompactProtocol.Factory();
+                else if (json)
+                    proto = new TJSONProtocol.Factory();
+                else
+                    proto = new TBinaryProtocol.Factory();
+
+                TProcessorFactory processorFactory;
+                if (processorFactoryType == ProcessorFactoryType.TPrototypeProcessorFactory)
+                {
+                    processorFactory = new TPrototypeProcessorFactory<ThriftTest.Processor, TestHandler>();
+                }
+                else
+                {
+                    // Processor
+                    TestHandler testHandler = new TestHandler();
+                    ThriftTest.Processor testProcessor = new ThriftTest.Processor(testHandler);
+                    processorFactory = new TSingletonProcessorFactory(testProcessor);
+                }
+
+                TTransportFactory transFactory;
+                if (useFramed)
+                    transFactory = new TFramedTransport.Factory();
+                else
+                    transFactory = new TTransportFactory();
+
+                TServer serverEngine;
+                switch (serverType)
+                {
+                    case ServerType.TThreadPoolServer:
+                        serverEngine = new TThreadPoolServer(processorFactory, trans, transFactory, proto);
+                        break;
+                    case ServerType.TThreadedServer:
+                        serverEngine = new TThreadedServer(processorFactory, trans, transFactory, proto);
+                        break;
+                    default:
+                        serverEngine = new TSimpleServer(processorFactory, trans, transFactory, proto);
+                        break;
+                }
+
+                //Server event handler
+                TradeServerEventHandler serverEvents = new TradeServerEventHandler();
+                serverEngine.setEventHandler(serverEvents);
+
+                // Run it
+                string where = (pipe != null ? "on pipe " + pipe : "on port " + port);
+                Console.WriteLine("Starting the " + serverType.ToString() + " " + where +
+                    (processorFactoryType == ProcessorFactoryType.TPrototypeProcessorFactory ? " with processor prototype factory " : "") +
+                    (useBufferedSockets ? " with buffered socket" : "") +
+                    (useFramed ? " with framed transport" : "") +
+                    (useEncryption ? " with encryption" : "") +
+                    (compact ? " with compact protocol" : "") +
+                    (json ? " with json protocol" : "") +
+                    "...");
+                serverEngine.Serve();
+
+            }
+            catch (Exception x)
+            {
+                Console.Error.Write(x);
+                return false;
+            }
+            Console.WriteLine("done.");
+            return true;
+        }
+    }
+}
diff --git a/test/csharp/ThriftTest.csproj b/test/csharp/ThriftTest.csproj
new file mode 100644
index 0000000..63629eb
--- /dev/null
+++ b/test/csharp/ThriftTest.csproj
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ThriftTest</RootNamespace>
+    <AssemblyName>ThriftTest</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.0</ApplicationVersion>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="ThriftImpl, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>.\ThriftImpl.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TestClient.cs" />
+    <Compile Include="TestServer.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\lib\csharp\Thrift.csproj">
+      <Project>{499EB63C-D74C-47E8-AE48-A2FC94538E9D}</Project>
+      <Name>Thrift</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>rmdir /s /q "$(ProjectDir)gen-csharp"
+del /f /q "$(ProjectDir)ThriftImpl.dll"
+SET OUTPUT_DIR=$(ProjectDir)
+SET THRIFT_FILE=$(ProjectDir)\..\ThriftTest.thrift
+for %25%25I in ("%25OUTPUT_DIR%25") do set SHORT_DIR=%25%25~fsI
+for %25%25I in ("%25THRIFT_FILE%25") do set THRIFT_SHORT=%25%25~fsI
+"$(ProjectDir)\..\..\compiler\cpp\thrift.exe" --gen csharp -o %25SHORT_DIR%25 %25THRIFT_SHORT%25
+$(MSBuildToolsPath)\Csc.exe /t:library /out:"$(ProjectDir)ThriftImpl.dll" /recurse:"$(ProjectDir)gen-csharp"\* /reference:"$(ProjectDir)..\..\lib\csharp\bin\Debug\Thrift.dll"</PreBuildEvent>
+  </PropertyGroup>
+</Project>
diff --git a/test/csharp/ThriftTest.sln b/test/csharp/ThriftTest.sln
new file mode 100644
index 0000000..1765a03
--- /dev/null
+++ b/test/csharp/ThriftTest.sln
@@ -0,0 +1,17 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftTest", "ThriftTest.csproj", "{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/test/dart/Makefile.am b/test/dart/Makefile.am
new file mode 100644
index 0000000..9750ec2
--- /dev/null
+++ b/test/dart/Makefile.am
@@ -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.
+#
+
+gen-dart/thrift_test/lib/thrift_test.dart: ../ThriftTest.thrift
+	$(THRIFT) --gen dart ../ThriftTest.thrift
+
+pub-get-gen: gen-dart/thrift_test/lib/thrift_test.dart
+	cd gen-dart/thrift_test; ${DARTPUB} get
+
+pub-get: pub-get-gen
+	cd test_client; ${DARTPUB} get
+
+stubs: gen-dart/thrift_test/lib/thrift_test.dart pub-get
+
+precross: stubs
+
+check: stubs
+
+clean-local:
+	$(RM) -r gen-dart test_client/.pub
+	find . -type d -name "packages" | xargs $(RM) -r
+	find . -type f -name ".packages" | xargs $(RM)
+	find . -type f -name "pubspec.lock" | xargs $(RM)
+
+client: stubs
+	${DART} test_client/bin/main.dart
diff --git a/test/dart/test_client/.analysis_options b/test/dart/test_client/.analysis_options
new file mode 100644
index 0000000..a10d4c5
--- /dev/null
+++ b/test/dart/test_client/.analysis_options
@@ -0,0 +1,2 @@
+analyzer:
+  strong-mode: true
diff --git a/test/dart/test_client/bin/main.dart b/test/dart/test_client/bin/main.dart
new file mode 100644
index 0000000..996844b
--- /dev/null
+++ b/test/dart/test_client/bin/main.dart
@@ -0,0 +1,337 @@
+/// 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 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:args/args.dart';
+import 'package:collection/collection.dart';
+import 'package:http/http.dart' as http;
+import 'package:thrift/thrift.dart';
+import 'package:thrift/thrift_console.dart';
+import 'package:thrift_test/thrift_test.dart';
+
+const TEST_BASETYPES = 1; // 0000 0001
+const TEST_STRUCTS = 2; // 0000 0010
+const TEST_CONTAINERS = 4; // 0000 0100
+const TEST_EXCEPTIONS = 8; // 0000 1000
+const TEST_UNKNOWN = 64; // 0100 0000 (Failed to prepare environemt etc.)
+const TEST_TIMEOUT = 128; // 1000 0000
+const TEST_NOTUSED = 48; // 0011 0000 (reserved bits)
+
+typedef Future FutureFunction();
+
+class TTest {
+  final int errorCode;
+  final String name;
+  final FutureFunction func;
+
+  TTest(this.errorCode, this.name, this.func);
+}
+
+class TTestError extends Error {
+  final actual;
+  final expected;
+
+  TTestError(this.actual, this.expected);
+
+  String toString() => '$actual != $expected';
+}
+
+List<TTest> _tests;
+ThriftTestClient client;
+bool verbose;
+
+/// Adapted from TestClient.php
+main(List<String> args) async {
+  ArgResults results = _parseArgs(args);
+
+  if (results == null) {
+    exit(TEST_UNKNOWN);
+  }
+
+  verbose = results['verbose'] == true;
+
+  await _initTestClient(
+      host: results['host'],
+      port: int.parse(results['port']),
+      transportType: results['transport'],
+      protocolType: results['protocol']).catchError((e) {
+    stdout.writeln('Error:');
+    stdout.writeln('$e');
+    if (e is Error) {
+      stdout.writeln('${e.stackTrace}');
+    }
+    exit(TEST_UNKNOWN);
+  });
+
+  // run tests
+  _tests = _createTests();
+
+  int result = 0;
+
+  for (TTest test in _tests) {
+    if (verbose) stdout.write('${test.name}... ');
+    try {
+      await test.func();
+      if (verbose) stdout.writeln('success!');
+    } catch (e) {
+      if (verbose) stdout.writeln('$e');
+      result = result | test.errorCode;
+    }
+  }
+
+  exit(result);
+}
+
+ArgResults _parseArgs(List<String> args) {
+  var parser = new ArgParser();
+  parser.addOption('host', defaultsTo: 'localhost', help: 'The server host');
+  parser.addOption('port', defaultsTo: '9090', help: 'The port to connect to');
+  parser.addOption('transport',
+      defaultsTo: 'buffered',
+      allowed: ['buffered', 'framed', 'http'],
+      help: 'The transport name',
+      allowedHelp: {
+        'buffered': 'TBufferedTransport',
+        'framed': 'TFramedTransport'
+      });
+  parser.addOption('protocol',
+      defaultsTo: 'binary',
+      allowed: ['binary', 'compact', 'json'],
+      help: 'The protocol name',
+      allowedHelp: {
+        'binary': 'TBinaryProtocol',
+        'compact': 'TCompactProtocol',
+        'json': 'TJsonProtocol'
+      });
+  parser.addFlag('verbose', defaultsTo: false);
+
+  ArgResults results;
+  try {
+    results = parser.parse(args);
+  } catch (e) {
+    stdout.writeln('$e\n');
+  }
+
+  if (results == null) stdout.write(parser.usage);
+
+  return results;
+}
+
+TProtocolFactory getProtocolFactory(String protocolType) {
+  if (protocolType == 'binary') {
+    return new TBinaryProtocolFactory();
+  } else if (protocolType == 'compact') {
+    return new TCompactProtocolFactory();
+  } else if (protocolType == 'json') {
+    return new TJsonProtocolFactory();
+  }
+
+  throw new ArgumentError.value(protocolType);
+}
+
+Future _initTestClient(
+    {String host, int port, String transportType, String protocolType}) async {
+  TTransport transport;
+  var protocolFactory = getProtocolFactory(protocolType);
+
+  if (transportType == 'http') {
+    var httpClient = new http.IOClient();
+    var uri = Uri.parse('http://$host:$port');
+    var config = new THttpConfig(uri, {});
+    transport = new THttpClientTransport(httpClient, config);
+  } else {
+    var socket = await Socket.connect(host, port);
+    transport = new TClientSocketTransport(new TTcpSocket(socket));
+    if (transportType == 'framed') {
+      transport = new TFramedTransport(transport);
+    }
+  }
+
+  var protocol = protocolFactory.getProtocol(transport);
+  client = new ThriftTestClient(protocol);
+
+  await transport.open();
+}
+
+List<TTest> _createTests() {
+  List<TTest> tests = [];
+
+  var xtruct = new Xtruct()
+    ..string_thing = 'Zero'
+    ..byte_thing = 1
+    ..i32_thing = -3
+    ..i64_thing = -5;
+
+  tests.add(new TTest(TEST_BASETYPES, 'testVoid', () async {
+    await client.testVoid();
+  }));
+
+  tests.add(new TTest(TEST_BASETYPES, 'testString', () async {
+    var input = 'Test';
+    var result = await client.testString(input);
+    if (result != input) throw new TTestError(result, input);
+  }));
+
+  tests.add(new TTest(TEST_BASETYPES, 'testBool', () async {
+    var input = true;
+    var result = await client.testBool(input);
+    if (result != input) throw new TTestError(result, input);
+  }));
+
+  tests.add(new TTest(TEST_BASETYPES, 'testByte', () async {
+    var input = 64;
+    var result = await client.testByte(input);
+    if (result != input) throw new TTestError(result, input);
+  }));
+
+  tests.add(new TTest(TEST_BASETYPES, 'testI32', () async {
+    var input = 2147483647;
+    var result = await client.testI32(input);
+    if (result != input) throw new TTestError(result, input);
+  }));
+
+  tests.add(new TTest(TEST_BASETYPES, 'testI64', () async {
+    var input = 9223372036854775807;
+    var result = await client.testI64(input);
+    if (result != input) throw new TTestError(result, input);
+  }));
+
+  tests.add(new TTest(TEST_BASETYPES, 'testDouble', () async {
+    var input = 3.1415926;
+    var result = await client.testDouble(input);
+    if (result != input) throw new TTestError(result, input);
+  }));
+
+  tests.add(new TTest(TEST_BASETYPES, 'testBinary', () async {
+    var utf8Codec = const Utf8Codec();
+    var input = utf8Codec.encode('foo');
+    var result = await client.testBinary(input);
+    var equality = const ListEquality();
+    if (!equality.equals(result, input)) throw new TTestError(result, input);
+  }));
+
+  tests.add(new TTest(TEST_CONTAINERS, 'testStruct', () async {
+    var result = await client.testStruct(xtruct);
+    if ('$result' != '$xtruct') throw new TTestError(result, xtruct);
+  }));
+
+  tests.add(new TTest(TEST_CONTAINERS, 'testNest', () async {
+    var input = new Xtruct2()
+      ..byte_thing = 1
+      ..struct_thing = xtruct
+      ..i32_thing = -3;
+
+    var result = await client.testNest(input);
+    if ('$result' != '$input') throw new TTestError(result, input);
+  }));
+
+  tests.add(new TTest(TEST_CONTAINERS, 'testMap', () async {
+    Map<int, int> input = {1: -10, 2: -9, 3: -8, 4: -7, 5: -6};
+
+    var result = await client.testMap(input);
+    var equality = const MapEquality();
+    if (!equality.equals(result, input)) throw new TTestError(result, input);
+  }));
+
+  tests.add(new TTest(TEST_CONTAINERS, 'testSet', () async {
+    var input = new Set<int>.from([-2, -1, 0, 1, 2]);
+    var result = await client.testSet(input);
+    var equality = const SetEquality();
+    if (!equality.equals(result, input)) throw new TTestError(result, input);
+  }));
+
+  tests.add(new TTest(TEST_CONTAINERS, 'testList', () async {
+    var input = [-2, -1, 0, 1, 2];
+    var result = await client.testList(input);
+    var equality = const ListEquality();
+    if (!equality.equals(result, input)) throw new TTestError(result, input);
+  }));
+
+  tests.add(new TTest(TEST_CONTAINERS, 'testEnum', () async {
+    await _testEnum(Numberz.ONE);
+    await _testEnum(Numberz.TWO);
+    await _testEnum(Numberz.THREE);
+    await _testEnum(Numberz.FIVE);
+    await _testEnum(Numberz.EIGHT);
+  }));
+
+  tests.add(new TTest(TEST_BASETYPES, 'testTypedef', () async {
+    var input = 309858235082523;
+    var result = await client.testTypedef(input);
+    if (result != input) throw new TTestError(result, input);
+  }));
+
+  tests.add(new TTest(TEST_CONTAINERS, 'testMapMap', () async {
+    Map<int, Map<int, int>> result = await client.testMapMap(1);
+    if (result.isEmpty || result[result.keys.first].isEmpty) {
+      throw new TTestError(result, 'Map<int, Map<int, int>>');
+    }
+  }));
+
+  tests.add(new TTest(TEST_CONTAINERS, 'testInsanity', () async {
+    var input = new Insanity();
+    input.userMap = {Numberz.FIVE: 5000};
+    input.xtructs = [xtruct];
+
+    Map<int, Map<int, Insanity>> result = await client.testInsanity(input);
+    if (result.isEmpty || result[result.keys.first].isEmpty) {
+      throw new TTestError(result, 'Map<int, Map<int, Insanity>>');
+    }
+  }));
+
+  tests.add(new TTest(TEST_CONTAINERS, 'testMulti', () async {
+    var input = new Xtruct()
+      ..string_thing = 'Hello2'
+      ..byte_thing = 123
+      ..i32_thing = 456
+      ..i64_thing = 789;
+
+    var result = await client.testMulti(input.byte_thing, input.i32_thing,
+        input.i64_thing, {1: 'one'}, Numberz.EIGHT, 5678);
+    if ('$result' != '$input') throw new TTestError(result, input);
+  }));
+
+  tests.add(new TTest(TEST_EXCEPTIONS, 'testException', () async {
+    try {
+      await client.testException('Xception');
+    } on Xception catch (_) {
+      return;
+    }
+
+    throw new TTestError(null, 'Xception');
+  }));
+
+  tests.add(new TTest(TEST_EXCEPTIONS, 'testMultiException', () async {
+    try {
+      await client.testMultiException('Xception2', 'foo');
+    } on Xception2 catch (_) {
+      return;
+    }
+
+    throw new TTestError(null, 'Xception2');
+  }));
+
+  return tests;
+}
+
+Future _testEnum(int input) async {
+  var result = await client.testEnum(input);
+  if (result != input) throw new TTestError(result, input);
+}
diff --git a/test/dart/test_client/pubspec.yaml b/test/dart/test_client/pubspec.yaml
new file mode 100644
index 0000000..d1642f8
--- /dev/null
+++ b/test/dart/test_client/pubspec.yaml
@@ -0,0 +1,36 @@
+# 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.
+
+name: thrift_test_client
+version: 1.0.0
+description: A client integration test for the Dart Thrift library
+author: Apache Thrift Developers <dev@thrift.apache.org>
+homepage: http://thrift.apache.org
+
+environment:
+  sdk: ">=1.13.0 <2.0.0"
+
+dependencies:
+  args: ^0.13.0
+  http: ^0.11.0
+  thrift:
+    path: ../../../lib/dart
+  thrift_test:
+    path: ../gen-dart/thrift_test
+
+dev_dependencies:
+  test: "^0.12.0"
diff --git a/test/erl/Makefile.am b/test/erl/Makefile.am
new file mode 100644
index 0000000..ff25e89
--- /dev/null
+++ b/test/erl/Makefile.am
@@ -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.
+#
+
+THRIFT_FILES = $(wildcard ../*.thrift)
+
+if ERLANG_OTP16
+ERL_FLAG = erl:otp16
+else
+ERL_FLAG = erl
+endif
+# make sure ThriftTest.thrift is generated last to prevent conflicts with other *.thrift files
+.generated: $(THRIFT_FILES)
+	for f in $(THRIFT_FILES) ; do \
+	  $(THRIFT) --gen $(ERL_FLAG) -o src $$f ; \
+	done ; \
+	$(THRIFT) --gen $(ERL_FLAG) -o src ../ThriftTest.thrift
+	touch .generated
+
+precross: .generated
+	$(REBAR) compile
+
+clean:
+	rm -f .generated
+	rm -rf src/gen-erl
+	$(REBAR) clean
diff --git a/test/erl/rebar.config b/test/erl/rebar.config
new file mode 100644
index 0000000..59a0788
--- /dev/null
+++ b/test/erl/rebar.config
@@ -0,0 +1,6 @@
+{sub_dirs, ["../../lib/erl"]}.
+
+{erl_opts, [
+  debug_info,
+  {i, "../../lib/erl/include"}
+]}.
diff --git a/test/erl/src/test_client.erl b/test/erl/src/test_client.erl
new file mode 100644
index 0000000..9bad592
--- /dev/null
+++ b/test/erl/src/test_client.erl
@@ -0,0 +1,174 @@
+%%
+%% 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.
+%%
+
+-module(test_client).
+
+-export([start/0, start/1]).
+
+-include("gen-erl/thrift_test_types.hrl").
+
+-record(options, {port = 9090,
+                  client_opts = []}).
+
+parse_args(Args) -> parse_args(Args, #options{}).
+parse_args([], Opts) ->
+  Opts;
+parse_args([Head | Rest], Opts) ->
+    NewOpts =
+        case Head of
+            "--port=" ++ Port ->
+                case string:to_integer(Port) of
+                  {IntPort,_} when is_integer(IntPort) ->
+                    Opts#options{port = IntPort};
+                  _Else ->
+                    erlang:error({bad_arg, Head})
+                end;
+            "--transport=" ++ Trans ->
+                % TODO: Enable Buffered and HTTP transport
+                case Trans of
+                    "framed" ->
+                        Opts#options{client_opts = [{framed, true} | Opts#options.client_opts]};
+                    _Else ->
+                        Opts
+                end;
+            "--ssl" ->
+                ssl:start(),
+                SslOptions =
+                    {ssloptions, [
+                        {cacertfile, "../keys/CA.pem"},
+                        {certfile, "../keys/client.pem"},
+                        {keyfile, "../keys/client.key"}
+                    ]},
+                Opts#options{client_opts = [{ssltransport, true} | [SslOptions | Opts#options.client_opts]]};
+            "--protocol=" ++ Proto ->
+                Opts#options{client_opts = [{protocol, list_to_atom(Proto)}]};
+            _Else ->
+                erlang:error({bad_arg, Head})
+        end,
+    parse_args(Rest, NewOpts).
+
+start() -> start(init:get_plain_arguments()).
+start(Args) ->
+  #options{port = Port, client_opts = ClientOpts} = parse_args(Args),
+  {ok, Client0} = thrift_client_util:new(
+    "127.0.0.1", Port, thrift_test_thrift, ClientOpts),
+
+  DemoXtruct = #'thrift.test.Xtruct'{
+                  string_thing = <<"Zero">>,
+                  byte_thing = 1,
+                  i32_thing = 9128361,
+                  i64_thing = 9223372036854775807},
+
+  DemoNest = #'thrift.test.Xtruct2'{
+    byte_thing = 7,
+    struct_thing = DemoXtruct,
+    % Note that we don't set i32_thing, it will come back as undefined
+    % from the Python server, but 0 from the C++ server, since it is not
+    % optional
+    i32_thing = 2},
+
+  % Is it safe to match these things?
+  DemoDict = dict:from_list([ {Key, Key-10} || Key <- lists:seq(0,10) ]),
+  DemoSet = sets:from_list([ Key || Key <- lists:seq(-3,3) ]),
+
+  DemoInsane = #'thrift.test.Insanity'{
+    userMap = dict:from_list([{?THRIFT_TEST_NUMBERZ_FIVE, 5000}]),
+    xtructs = [#'thrift.test.Xtruct'{ string_thing = <<"Truck">>, byte_thing = 8, i32_thing = 8, i64_thing = 8}]},
+
+  error_logger:info_msg("testVoid"),
+  {Client01, {ok, ok}} = thrift_client:call(Client0, testVoid, []),
+
+  error_logger:info_msg("testString"),
+  {Client02, {ok, <<"Test">>}}      = thrift_client:call(Client01, testString, ["Test"]),
+  error_logger:info_msg("testString"),
+  {Client03, {ok, <<"Test">>}}      = thrift_client:call(Client02, testString, [<<"Test">>]),
+  error_logger:info_msg("testByte"),
+  {Client04, {ok, 63}}              = thrift_client:call(Client03, testByte, [63]),
+  error_logger:info_msg("testI32"),
+  {Client05, {ok, -1}}              = thrift_client:call(Client04, testI32, [-1]),
+  error_logger:info_msg("testI32"),
+  {Client06, {ok, 0}}               = thrift_client:call(Client05, testI32, [0]),
+  error_logger:info_msg("testI64"),
+  {Client07, {ok, -34359738368}}    = thrift_client:call(Client06, testI64, [-34359738368]),
+  error_logger:info_msg("testDouble"),
+  {Client08, {ok, -5.2098523}}      = thrift_client:call(Client07, testDouble, [-5.2098523]),
+  %% TODO: add testBinary() call
+  error_logger:info_msg("testStruct"),
+  {Client09, {ok, DemoXtruct}}      = thrift_client:call(Client08, testStruct, [DemoXtruct]),
+  error_logger:info_msg("testNest"),
+  {Client10, {ok, DemoNest}}        = thrift_client:call(Client09, testNest, [DemoNest]),
+  error_logger:info_msg("testMap"),
+  {Client11, {ok, DemoDict}}        = thrift_client:call(Client10, testMap, [DemoDict]),
+  error_logger:info_msg("testSet"),
+  {Client12, {ok, DemoSet}}         = thrift_client:call(Client11, testSet, [DemoSet]),
+  error_logger:info_msg("testList"),
+  {Client13, {ok, [-1,2,3]}}        = thrift_client:call(Client12, testList, [[-1,2,3]]),
+  error_logger:info_msg("testEnum"),
+  {Client14, {ok, 1}}               = thrift_client:call(Client13, testEnum, [?THRIFT_TEST_NUMBERZ_ONE]),
+  error_logger:info_msg("testTypedef"),
+  {Client15, {ok, 309858235082523}} = thrift_client:call(Client14, testTypedef, [309858235082523]),
+  error_logger:info_msg("testInsanity"),
+  {Client16, {ok, InsaneResult}}    = thrift_client:call(Client15, testInsanity, [DemoInsane]),
+  io:format("~p~n", [InsaneResult]),
+
+  {Client17, {ok, #'thrift.test.Xtruct'{string_thing = <<"Message">>}}} =
+    thrift_client:call(Client16, testMultiException, ["Safe", "Message"]),
+
+  Client18 =
+    try
+      {ClientS1, Result1} = thrift_client:call(Client17, testMultiException, ["Xception", "Message"]),
+      io:format("Unexpected return! ~p~n", [Result1]),
+      ClientS1
+    catch
+      throw:{ClientS2, {exception, ExnS1 = #'thrift.test.Xception'{}}} ->
+        #'thrift.test.Xception'{errorCode = 1001, message = <<"This is an Xception">>} = ExnS1,
+        ClientS2;
+      throw:{ClientS2, {exception, _ExnS1 = #'thrift.test.Xception2'{}}} ->
+        io:format("Wrong exception type!~n", []),
+        ClientS2
+    end,
+
+  Client19 =
+    try
+      {ClientS3, Result2} = thrift_client:call(Client18, testMultiException, ["Xception2", "Message"]),
+      io:format("Unexpected return! ~p~n", [Result2]),
+      ClientS3
+    catch
+      throw:{ClientS4, {exception, _ExnS2 = #'thrift.test.Xception'{}}} ->
+        io:format("Wrong exception type!~n", []),
+        ClientS4;
+      throw:{ClientS4, {exception, ExnS2 = #'thrift.test.Xception2'{}}} ->
+        #'thrift.test.Xception2'{errorCode = 2002,
+                   struct_thing = #'thrift.test.Xtruct'{
+                     string_thing = <<"This is an Xception2">>}} = ExnS2,
+        ClientS4
+    end,
+
+  %% Started = erlang:monotonic_time(milli_seconds),
+  {_, StartSec, StartUSec} = erlang:timestamp(),
+  error_logger:info_msg("testOneway"),
+  {Client20, {ok, ok}} = thrift_client:call(Client19, testOneway, [1]),
+  {_, EndSec, EndUSec} = erlang:timestamp(),
+  Elapsed = (EndSec - StartSec) * 1000 + (EndUSec - StartUSec) / 1000,
+  if
+    Elapsed > 1000 -> exit(1);
+    true -> true
+  end,
+
+  thrift_client:close(Client20).
diff --git a/test/erl/src/test_thrift_server.erl b/test/erl/src/test_thrift_server.erl
new file mode 100644
index 0000000..dad8dec
--- /dev/null
+++ b/test/erl/src/test_thrift_server.erl
@@ -0,0 +1,233 @@
+%%
+%% 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.
+%%
+
+-module(test_thrift_server).
+
+-export([start/0, start/1, start_link/2, handle_function/2]).
+
+-include("thrift_constants.hrl").
+-include("gen-erl/thrift_test_types.hrl").
+
+-record(options, {port = 9090,
+                  server_opts = []}).
+
+parse_args(Args) -> parse_args(Args, #options{}).
+parse_args([], Opts) ->
+  Opts;
+parse_args([Head | Rest], Opts) ->
+    NewOpts =
+        case Head of
+            "--port=" ++ Port ->
+                case string:to_integer(Port) of
+                  {IntPort,_} when is_integer(IntPort) ->
+                    Opts#options{port = IntPort};
+                  _Else ->
+                    erlang:error({bad_arg, Head})
+                end;
+            "--transport=" ++ Trans ->
+                case Trans of
+                    "framed" ->
+                        Opts#options{server_opts = [{framed, true} | Opts#options.server_opts]};
+                    _Else ->
+                        Opts
+                end;
+            "--ssl" ->
+                ssl:start(),
+                SslOptions =
+                    {ssloptions, [
+                         {certfile, "../keys/server.pem"}
+                        ,{keyfile,  "../keys/server.key"}
+                    ]},
+                Opts#options{server_opts = [{ssltransport, true} | [SslOptions | Opts#options.server_opts]]};
+            "--protocol=" ++ Proto ->
+                Opts#options{server_opts = [{protocol, list_to_atom(Proto)} | Opts#options.server_opts]};
+            _Else ->
+                erlang:error({bad_arg, Head})
+        end,
+    parse_args(Rest, NewOpts).
+
+start() -> start(init:get_plain_arguments()).
+start(Args) ->
+    #options{port = Port, server_opts = ServerOpts} = parse_args(Args),
+    spawn(fun() -> start_link(Port, ServerOpts), receive after infinity -> ok end end).
+
+start_link(Port, ServerOpts) ->
+    thrift_socket_server:start([{handler, ?MODULE},
+                                {service, thrift_test_thrift},
+                                {port, Port}] ++
+                               ServerOpts).
+
+
+handle_function(testVoid, {}) ->
+    io:format("testVoid~n"),
+    ok;
+
+handle_function(testString, {S}) when is_binary(S) ->
+    io:format("testString: ~p~n", [S]),
+    {reply, S};
+
+handle_function(testBool, {B}) when is_boolean(B) ->
+    io:format("testBool: ~p~n", [B]),
+    {reply, B};
+
+handle_function(testByte, {I8}) when is_integer(I8) ->
+    io:format("testByte: ~p~n", [I8]),
+    {reply, I8};
+
+handle_function(testI32, {I32}) when is_integer(I32) ->
+    io:format("testI32: ~p~n", [I32]),
+    {reply, I32};
+
+handle_function(testI64, {I64}) when is_integer(I64) ->
+    io:format("testI64: ~p~n", [I64]),
+    {reply, I64};
+
+handle_function(testDouble, {Double}) when is_float(Double) ->
+    io:format("testDouble: ~p~n", [Double]),
+    {reply, Double};
+
+handle_function(testBinary, {S}) when is_binary(S) ->
+    io:format("testBinary: ~p~n", [S]),
+    {reply, S};
+
+handle_function(testStruct,
+                {Struct = #'thrift.test.Xtruct'{string_thing = String,
+                                                byte_thing = Byte,
+                                                i32_thing = I32,
+                                                i64_thing = I64}})
+when is_binary(String),
+     is_integer(Byte),
+     is_integer(I32),
+     is_integer(I64) ->
+    io:format("testStruct: ~p~n", [Struct]),
+    {reply, Struct};
+
+handle_function(testNest,
+                {Nest}) when is_record(Nest, 'thrift.test.Xtruct2'),
+                             is_record(Nest#'thrift.test.Xtruct2'.struct_thing, 'thrift.test.Xtruct') ->
+    io:format("testNest: ~p~n", [Nest]),
+    {reply, Nest};
+
+handle_function(testMap, {Map}) ->
+    io:format("testMap: ~p~n", [dict:to_list(Map)]),
+    {reply, Map};
+
+handle_function(testStringMap, {Map}) ->
+    io:format("testStringMap: ~p~n", [dict:to_list(Map)]),
+    {reply, Map};
+
+handle_function(testSet, {Set}) ->
+    true = sets:is_set(Set),
+    io:format("testSet: ~p~n", [sets:to_list(Set)]),
+    {reply, Set};
+
+handle_function(testList, {List}) when is_list(List) ->
+    io:format("testList: ~p~n", [List]),
+    {reply, List};
+
+handle_function(testEnum, {Enum}) when is_integer(Enum) ->
+    io:format("testEnum: ~p~n", [Enum]),
+    {reply, Enum};
+
+handle_function(testTypedef, {UserID}) when is_integer(UserID) ->
+    io:format("testTypedef: ~p~n", [UserID]),
+    {reply, UserID};
+
+handle_function(testMapMap, {Hello}) ->
+    io:format("testMapMap: ~p~n", [Hello]),
+
+    PosList = [{I, I}   || I <- lists:seq(1, 4)],
+    NegList = [{-I, -I} || I <- lists:seq(1, 4)],
+
+    MapMap = dict:from_list([{4,  dict:from_list(PosList)},
+                             {-4, dict:from_list(NegList)}]),
+    {reply, MapMap};
+
+handle_function(testInsanity, {Insanity}) when is_record(Insanity, 'thrift.test.Insanity') ->
+    Hello = #'thrift.test.Xtruct'{string_thing = <<"Hello2">>,
+                                  byte_thing = 2,
+                                  i32_thing = 2,
+                                  i64_thing = 2},
+
+    Goodbye = #'thrift.test.Xtruct'{string_thing = <<"Goodbye4">>,
+                                   byte_thing = 4,
+                                    i32_thing = 4,
+                                    i64_thing = 4},
+    Crazy = #'thrift.test.Insanity'{
+               userMap = dict:from_list([{?THRIFT_TEST_NUMBERZ_EIGHT, 8}]),
+               xtructs = [Goodbye]
+              },
+
+    Looney = #'thrift.test.Insanity'{},
+
+    FirstMap = dict:from_list([{?THRIFT_TEST_NUMBERZ_TWO, Insanity},
+                               {?THRIFT_TEST_NUMBERZ_THREE, Insanity}]),
+
+    SecondMap = dict:from_list([{?THRIFT_TEST_NUMBERZ_SIX, Looney}]),
+
+    Insane = dict:from_list([{1, FirstMap},
+                             {2, SecondMap}]),
+
+    io:format("Return = ~p~n", [Insane]),
+
+    {reply, Insane};
+
+handle_function(testMulti, Args = {Arg0, Arg1, Arg2, _Arg3, Arg4, Arg5})
+  when is_integer(Arg0),
+       is_integer(Arg1),
+       is_integer(Arg2),
+       is_integer(Arg4),
+       is_integer(Arg5) ->
+
+    io:format("testMulti(~p)~n", [Args]),
+    {reply, #'thrift.test.Xtruct'{string_thing = <<"Hello2">>,
+                                  byte_thing = Arg0,
+                                  i32_thing = Arg1,
+                                  i64_thing = Arg2}};
+
+handle_function(testException, {String}) when is_binary(String) ->
+    io:format("testException(~p)~n", [String]),
+    case String of
+        <<"Xception">> ->
+            throw(#'thrift.test.Xception'{errorCode = 1001,
+                            message = String});
+        <<"TException">> ->
+            throw({?TApplicationException_Structure});
+        _ ->
+            ok
+    end;
+
+handle_function(testMultiException, {Arg0, Arg1}) ->
+    io:format("testMultiException(~p, ~p)~n", [Arg0, Arg1]),
+    case Arg0 of
+        <<"Xception">> ->
+            throw(#'thrift.test.Xception'{errorCode = 1001,
+                                   message = <<"This is an Xception">>});
+        <<"Xception2">> ->
+            throw(#'thrift.test.Xception2'{errorCode = 2002,
+                                    struct_thing =
+                                    #'thrift.test.Xtruct'{string_thing = <<"This is an Xception2">>}});
+        _ ->
+            {reply, #'thrift.test.Xtruct'{string_thing = Arg1}}
+    end;
+
+handle_function(testOneway, {Seconds}) ->
+    io:format("testOneway: ~p~n", [Seconds]),
+    timer:sleep(1000 * Seconds),
+    ok.
diff --git a/test/erl/src/thrift_test.app.src b/test/erl/src/thrift_test.app.src
new file mode 100644
index 0000000..80ef996
--- /dev/null
+++ b/test/erl/src/thrift_test.app.src
@@ -0,0 +1,54 @@
+%%
+%% 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.
+%%
+%%% -*- mode:erlang -*-
+{application, thrift_test, [
+  % A quick description of the application.
+  {description, "Thrift cross language test"},
+
+  % The version of the applicaton
+  {vsn, "1.0.0"},
+
+  % All modules used by the application.
+  {modules, [
+    test_client,
+    test_thrift_server
+  ]},
+
+  % All of the registered names the application uses. This can be ignored.
+  {registered, []},
+
+  % Applications that are to be started prior to this one. This can be ignored
+  % leave it alone unless you understand it well and let the .rel files in
+  % your release handle this.
+  {applications, [kernel, stdlib]},
+
+  % OTP application loader will load, but not start, included apps. Again
+  % this can be ignored as well.  To load but not start an application it
+  % is easier to include it in the .rel file followed by the atom 'none'
+  {included_applications, []},
+
+  % configuration parameters similar to those in the config file specified
+  % on the command line. can be fetched with gas:get_env
+  {env, [
+    % If an error/crash occurs during processing of a function,
+    % should the TApplicationException serialized back to the client
+    % include the erlang backtrace?
+    {exceptions_include_traces, true}
+  ]}
+]}.
diff --git a/test/features/Makefile.am b/test/features/Makefile.am
new file mode 100644
index 0000000..337d789
--- /dev/null
+++ b/test/features/Makefile.am
@@ -0,0 +1,30 @@
+# 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.
+#
+
+EXTRA_DIST = \
+	local_thrift \
+	index.html \
+	container_limit.py \
+	index.html \
+	known_failures_Linux.json \
+	Makefile.am \
+        nosslv3.sh \
+	string_limit.py \
+	tests.json \
+	theader_binary.py \
+	setup.cfg \
+        tls.sh \
+	util.py
diff --git a/test/features/container_limit.py b/test/features/container_limit.py
new file mode 100644
index 0000000..88f8487
--- /dev/null
+++ b/test/features/container_limit.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+
+import argparse
+import sys
+
+from util import add_common_args, init_protocol
+from local_thrift import thrift  # noqa
+from thrift.Thrift import TMessageType, TType
+
+
+# TODO: generate from ThriftTest.thrift
+def test_list(proto, value):
+    method_name = 'testList'
+    ttype = TType.LIST
+    etype = TType.I32
+    proto.writeMessageBegin(method_name, TMessageType.CALL, 3)
+    proto.writeStructBegin(method_name + '_args')
+    proto.writeFieldBegin('thing', ttype, 1)
+    proto.writeListBegin(etype, len(value))
+    for e in value:
+        proto.writeI32(e)
+    proto.writeListEnd()
+    proto.writeFieldEnd()
+    proto.writeFieldStop()
+    proto.writeStructEnd()
+    proto.writeMessageEnd()
+    proto.trans.flush()
+
+    _, mtype, _ = proto.readMessageBegin()
+    assert mtype == TMessageType.REPLY
+    proto.readStructBegin()
+    _, ftype, fid = proto.readFieldBegin()
+    assert fid == 0
+    assert ftype == ttype
+    etype2, len2 = proto.readListBegin()
+    assert etype == etype2
+    assert len2 == len(value)
+    for i in range(len2):
+        v = proto.readI32()
+        assert v == value[i]
+    proto.readListEnd()
+    proto.readFieldEnd()
+    _, ftype, _ = proto.readFieldBegin()
+    assert ftype == TType.STOP
+    proto.readStructEnd()
+    proto.readMessageEnd()
+
+
+def main(argv):
+    p = argparse.ArgumentParser()
+    add_common_args(p)
+    p.add_argument('--limit', type=int)
+    args = p.parse_args()
+    proto = init_protocol(args)
+    # TODO: test set and map
+    test_list(proto, list(range(args.limit - 1)))
+    test_list(proto, list(range(args.limit - 1)))
+    print('[OK]: limit - 1')
+    test_list(proto, list(range(args.limit)))
+    test_list(proto, list(range(args.limit)))
+    print('[OK]: just limit')
+    try:
+        test_list(proto, list(range(args.limit + 1)))
+    except Exception:
+        print('[OK]: limit + 1')
+    else:
+        print('[ERROR]: limit + 1')
+        assert False
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
diff --git a/test/features/index.html b/test/features/index.html
new file mode 100644
index 0000000..34a0010
--- /dev/null
+++ b/test/features/index.html
@@ -0,0 +1,51 @@
+<!--
+ 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.
+
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Apache Thrift - integration test suite</title>
+<link rel="stylesheet" type="text/css" href="http://cdn.datatables.net/1.10.4/css/jquery.dataTables.css">
+<script type="text/javascript" charset="utf-8" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
+<script type="text/javascript" charset="utf-8" src="http://cdn.datatables.net/1.10.4/js/jquery.dataTables.js"></script>
+<script src="../result.js">
+</script>
+</head>
+<body>
+<h2>Apache Thrift - integration test suite: Results</h2>
+<table id="test_results" class="display">
+    <thead>
+        <tr>
+            <th>Server</th>
+            <th>Client</th>
+            <th>Protocol</th>
+            <th>Transport</th>
+            <th>Result (log)</th>
+            <th>Expected</th>
+        </tr>
+    </thead>
+</table>
+<h2>Test Information</h2>
+<pre id="test_info"></pre>
+
+<a href="log">browse raw log files</a>
+
+</body>
+</html>
diff --git a/test/features/known_failures_Linux.json b/test/features/known_failures_Linux.json
new file mode 100644
index 0000000..8376968
--- /dev/null
+++ b/test/features/known_failures_Linux.json
@@ -0,0 +1,50 @@
+[
+    "c_glib-limit_container_length_binary_buffered-ip",
+    "c_glib-limit_string_length_binary_buffered-ip",
+    "cl-limit_string_length_binary_buffered-ip",
+    "cl-limit_container_length_binary_buffered-ip",
+    "cpp-theader_framed_binary_multih-header_buffered-ip",
+    "cpp-theader_framed_compact_multih-header_buffered-ip",
+    "cpp-theader_unframed_binary_multih-header_buffered-ip",
+    "cpp-theader_unframed_compact_multih-header_buffered-ip",
+    "csharp-limit_container_length_binary_buffered-ip",
+    "csharp-limit_container_length_compact_buffered-ip",
+    "csharp-limit_string_length_binary_buffered-ip",
+    "csharp-limit_string_length_compact_buffered-ip",
+    "d-limit_container_length_binary_buffered-ip",
+    "d-limit_container_length_compact_buffered-ip",
+    "d-limit_string_length_binary_buffered-ip",
+    "d-limit_string_length_compact_buffered-ip",
+    "erl-limit_container_length_binary_buffered-ip",
+    "erl-limit_container_length_compact_buffered-ip",
+    "erl-limit_string_length_binary_buffered-ip",
+    "erl-limit_string_length_compact_buffered-ip",
+    "go-limit_container_length_binary_buffered-ip",
+    "go-limit_container_length_compact_buffered-ip",
+    "go-limit_string_length_binary_buffered-ip",
+    "go-limit_string_length_compact_buffered-ip",
+    "hs-limit_container_length_binary_buffered-ip",
+    "hs-limit_container_length_compact_buffered-ip",
+    "hs-limit_string_length_binary_buffered-ip",
+    "hs-limit_string_length_compact_buffered-ip",
+    "nodejs-limit_container_length_binary_buffered-ip",
+    "nodejs-limit_container_length_compact_buffered-ip",
+    "nodejs-limit_string_length_binary_buffered-ip",
+    "nodejs-limit_string_length_compact_buffered-ip",
+    "perl-limit_container_length_binary_buffered-ip",
+    "perl-limit_string_length_binary_buffered-ip",
+    "rb-limit_container_length_accel-binary_buffered-ip",
+    "rb-limit_container_length_binary_buffered-ip",
+    "rb-limit_container_length_compact_buffered-ip",
+    "rb-limit_string_length_accel-binary_buffered-ip",
+    "rb-limit_string_length_binary_buffered-ip",
+    "rb-limit_string_length_compact_buffered-ip",
+    "rs-limit_container_length_binary_buffered-ip",
+    "rs-limit_container_length_compact_buffered-ip",
+    "rs-limit_container_length_multic-compact_buffered-ip",
+    "rs-limit_string_length_binary_buffered-ip",
+    "rs-limit_string_length_compact_buffered-ip",
+    "rs-limit_string_length_multic-compact_buffered-ip",
+    "netcore-limit_string_length_compact_buffered-ip",
+    "netcore-limit_container_length_compact_buffered-ip"
+]
diff --git a/test/features/local_thrift/__init__.py b/test/features/local_thrift/__init__.py
new file mode 100644
index 0000000..c85cebe
--- /dev/null
+++ b/test/features/local_thrift/__init__.py
@@ -0,0 +1,32 @@
+#
+# 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 glob
+import os
+import sys
+
+_SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__))
+_ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(_SCRIPT_DIR)))
+_LIBDIR = os.path.join(_ROOT_DIR, 'lib', 'py', 'build', 'lib.*')
+
+for libpath in glob.glob(_LIBDIR):
+    if libpath.endswith('-%d.%d' % (sys.version_info[0], sys.version_info[1])):
+        sys.path.insert(0, libpath)
+        thrift = __import__('thrift')
+        break
diff --git a/test/features/nosslv3.sh b/test/features/nosslv3.sh
new file mode 100755
index 0000000..38cca07
--- /dev/null
+++ b/test/features/nosslv3.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+#
+# Checks to make sure SSLv3 is not allowed by a server.
+#
+
+THRIFTHOST=localhost
+THRIFTPORT=9090
+
+while [[ $# -ge 1 ]]; do
+  arg="$1"
+  argIN=(${arg//=/ })
+
+  case ${argIN[0]} in
+    -h|--host)
+    THRIFTHOST=${argIN[1]}
+    shift # past argument
+    ;;
+    -p|--port)
+    THRIFTPORT=${argIN[1]}
+    shift # past argument
+    ;;
+    *)
+          # unknown option ignored
+    ;;
+  esac
+
+  shift   # past argument or value
+done
+
+function nosslv3
+{
+  local nego
+  local negodenied
+  local opensslv
+
+  opensslv=$(openssl version | cut -d' ' -f2)
+  if [[ $opensslv > "1.0" ]]; then
+    echo "[pass] OpenSSL 1.1 or later - no need to check ssl3"
+    return 0
+  fi
+
+  # echo "openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -ssl3 2>&1 < /dev/null"
+  nego=$(openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -ssl3 2>&1 < /dev/null)
+  negodenied=$?
+
+  if [[ $negodenied -ne 0 ]]; then
+    echo "[pass] SSLv3 negotiation disabled"
+    echo $nego
+    return 0
+  fi
+
+  echo "[fail] SSLv3 negotiation enabled!  stdout:"
+  echo $nego
+  return 1
+}
+
+nosslv3
+exit $?
diff --git a/test/features/setup.cfg b/test/features/setup.cfg
new file mode 100644
index 0000000..7da1f96
--- /dev/null
+++ b/test/features/setup.cfg
@@ -0,0 +1,2 @@
+[flake8]
+max-line-length = 100
diff --git a/test/features/string_limit.py b/test/features/string_limit.py
new file mode 100644
index 0000000..b8991d6
--- /dev/null
+++ b/test/features/string_limit.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+
+import argparse
+import sys
+
+from util import add_common_args, init_protocol
+from local_thrift import thrift  # noqa
+from thrift.Thrift import TMessageType, TType
+
+
+# TODO: generate from ThriftTest.thrift
+def test_string(proto, value):
+    method_name = 'testString'
+    ttype = TType.STRING
+    proto.writeMessageBegin(method_name, TMessageType.CALL, 3)
+    proto.writeStructBegin(method_name + '_args')
+    proto.writeFieldBegin('thing', ttype, 1)
+    proto.writeString(value)
+    proto.writeFieldEnd()
+    proto.writeFieldStop()
+    proto.writeStructEnd()
+    proto.writeMessageEnd()
+    proto.trans.flush()
+
+    _, mtype, _ = proto.readMessageBegin()
+    assert mtype == TMessageType.REPLY
+    proto.readStructBegin()
+    _, ftype, fid = proto.readFieldBegin()
+    assert fid == 0
+    assert ftype == ttype
+    result = proto.readString()
+    proto.readFieldEnd()
+    _, ftype, _ = proto.readFieldBegin()
+    assert ftype == TType.STOP
+    proto.readStructEnd()
+    proto.readMessageEnd()
+    assert value == result
+
+
+def main(argv):
+    p = argparse.ArgumentParser()
+    add_common_args(p)
+    p.add_argument('--limit', type=int)
+    args = p.parse_args()
+    proto = init_protocol(args)
+    test_string(proto, 'a' * (args.limit - 1))
+    test_string(proto, 'a' * (args.limit - 1))
+    print('[OK]: limit - 1')
+    test_string(proto, 'a' * args.limit)
+    test_string(proto, 'a' * args.limit)
+    print('[OK]: just limit')
+    try:
+        test_string(proto, 'a' * (args.limit + 1))
+    except Exception:
+        print('[OK]: limit + 1')
+    else:
+        print('[ERROR]: limit + 1')
+        assert False
+
+
+if __name__ == '__main__':
+    main(sys.argv[1:])
diff --git a/test/features/tests.json b/test/features/tests.json
new file mode 100644
index 0000000..41e07d7
--- /dev/null
+++ b/test/features/tests.json
@@ -0,0 +1,114 @@
+[
+  {
+    "description": "THeader detects unframed binary wire format",
+    "name": "theader_unframed_binary",
+    "command": [
+      "python",
+      "theader_binary.py",
+      "--override-protocol=binary",
+      "--override-transport=buffered"
+    ],
+    "protocols": ["header"],
+    "transports": ["buffered"],
+    "sockets": ["ip"],
+    "workdir": "features"
+  },
+  {
+    "description": "THeader detects framed binary wire format",
+    "name": "theader_framed_binary",
+    "command": [
+      "python",
+      "theader_binary.py",
+      "--override-protocol=binary",
+      "--override-transport=framed"
+    ],
+    "protocols": ["header"],
+    "transports": ["buffered"],
+    "sockets": ["ip"],
+    "workdir": "features"
+  },
+  {
+    "description": "THeader detects unframed compact wire format",
+    "name": "theader_unframed_compact",
+    "command": [
+      "python",
+      "theader_binary.py",
+      "--override-protocol=compact",
+      "--override-transport=buffered"
+    ],
+    "protocols": ["header"],
+    "transports": ["buffered"],
+    "sockets": ["ip"],
+    "workdir": "features"
+  },
+  {
+    "description": "THeader detects framed compact wire format",
+    "name": "theader_framed_compact",
+    "command": [
+      "python",
+      "theader_binary.py",
+      "--override-protocol=compact",
+      "--override-transport=framed"
+    ],
+    "protocols": ["header"],
+    "transports": ["buffered"],
+    "sockets": ["ip"],
+    "workdir": "features"
+  },
+  {
+    "name": "limit_string_length",
+    "command": [
+      "python",
+      "string_limit.py",
+      "--limit=50"
+    ],
+    "remote_args": [
+      "--string-limit=50"
+    ],
+    "protocols": [
+      "compact"
+    ],
+    "transports": ["buffered"],
+    "sockets": ["ip"],
+    "workdir": "features"
+  },
+  {
+    "name": "limit_container_length",
+    "command": [
+      "python",
+      "container_limit.py",
+      "--limit=50"
+    ],
+    "remote_args": [
+      "--container-limit=50"
+    ],
+    "protocols": [
+      "compact"
+    ],
+    "transports": ["buffered"],
+    "sockets": ["ip"],
+    "workdir": "features"
+  },
+  {
+    "name": "nosslv3",
+    "comment": "check to make sure SSLv3 is not supported",
+    "command": [
+      "nosslv3.sh"
+    ],
+    "protocols": ["binary"],
+    "transports": ["buffered"],
+    "sockets": ["ip-ssl"],
+    "workdir": "features"
+  },
+  {
+    "name": "tls",
+    "comment": "check to make sure TLSv1.0 or later is supported",
+    "command": [
+      "tls.sh"
+    ],
+    "protocols": ["binary"],
+    "transports": ["buffered"],
+    "sockets": ["ip-ssl"],
+    "workdir": "features"
+  }
+]
diff --git a/test/features/theader_binary.py b/test/features/theader_binary.py
new file mode 100644
index 0000000..451399a
--- /dev/null
+++ b/test/features/theader_binary.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+
+import argparse
+import socket
+import sys
+
+from util import add_common_args
+from local_thrift import thrift  # noqa
+from thrift.Thrift import TMessageType, TType
+from thrift.transport.TSocket import TSocket
+from thrift.transport.TTransport import TBufferedTransport, TFramedTransport
+from thrift.protocol.TBinaryProtocol import TBinaryProtocol
+from thrift.protocol.TCompactProtocol import TCompactProtocol
+
+
+def test_void(proto):
+    proto.writeMessageBegin('testVoid', TMessageType.CALL, 3)
+    proto.writeStructBegin('testVoid_args')
+    proto.writeFieldStop()
+    proto.writeStructEnd()
+    proto.writeMessageEnd()
+    proto.trans.flush()
+
+    _, mtype, _ = proto.readMessageBegin()
+    assert mtype == TMessageType.REPLY
+    proto.readStructBegin()
+    _, ftype, _ = proto.readFieldBegin()
+    assert ftype == TType.STOP
+    proto.readStructEnd()
+    proto.readMessageEnd()
+
+
+# THeader stack should accept binary protocol with optionally framed transport
+def main(argv):
+    p = argparse.ArgumentParser()
+    add_common_args(p)
+    # Since THeaderTransport acts as framed transport when detected frame, we
+    # cannot use --transport=framed as it would result in 2 layered frames.
+    p.add_argument('--override-transport')
+    p.add_argument('--override-protocol')
+    args = p.parse_args()
+    assert args.protocol == 'header'
+    assert args.transport == 'buffered'
+    assert not args.ssl
+
+    sock = TSocket(args.host, args.port, socket_family=socket.AF_INET)
+    if not args.override_transport or args.override_transport == 'buffered':
+        trans = TBufferedTransport(sock)
+    elif args.override_transport == 'framed':
+        print('TFRAMED')
+        trans = TFramedTransport(sock)
+    else:
+        raise ValueError('invalid transport')
+    trans.open()
+
+    if not args.override_protocol or args.override_protocol == 'binary':
+        proto = TBinaryProtocol(trans)
+    elif args.override_protocol == 'compact':
+        proto = TCompactProtocol(trans)
+    else:
+        raise ValueError('invalid transport')
+
+    test_void(proto)
+    test_void(proto)
+
+    trans.close()
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
diff --git a/test/features/tls.sh b/test/features/tls.sh
new file mode 100755
index 0000000..dada6ab
--- /dev/null
+++ b/test/features/tls.sh
@@ -0,0 +1,71 @@
+#!/bin/bash
+
+#
+# Checks to make sure TLSv1.0 or later is allowed by a server.
+#
+
+THRIFTHOST=localhost
+THRIFTPORT=9090
+
+while [[ $# -ge 1 ]]; do
+  arg="$1"
+  argIN=(${arg//=/ })
+
+  case ${argIN[0]} in
+    -h|--host)
+    THRIFTHOST=${argIN[1]}
+    shift # past argument
+    ;;
+    -p|--port)
+    THRIFTPORT=${argIN[1]}
+    shift # past argument
+    ;;
+    *)
+          # unknown option ignored
+    ;;
+  esac
+
+  shift   # past argument or value
+done
+
+declare -A EXPECT_NEGOTIATE
+EXPECT_NEGOTIATE[tls1]=1
+EXPECT_NEGOTIATE[tls1_1]=1
+EXPECT_NEGOTIATE[tls1_2]=1
+
+failures=0
+
+function tls
+{
+  for PROTO in "${!EXPECT_NEGOTIATE[@]}"; do
+
+    local nego
+    local negodenied
+    local res
+
+    echo "openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -$PROTO 2>&1 < /dev/null"
+    nego=$(openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -$PROTO 2>&1 < /dev/null)
+    negodenied=$?
+    echo "result of command: $negodenied"
+
+    res="enabled"; if [[ ${EXPECT_NEGOTIATE[$PROTO]} -eq 0 ]]; then res="disabled"; fi
+
+    if [[ $negodenied -ne ${EXPECT_NEGOTIATE[$PROTO]} ]]; then
+      echo "$PROTO negotiation allowed"
+    else
+      echo "[warn] $PROTO negotiation did not work"
+      echo $nego
+      ((failures++))
+    fi
+  done
+}
+
+tls
+
+if [[ $failures -eq 3 ]]; then
+  echo "[fail] At least one of TLSv1.0, TLSv1.1, or TLSv1.2 needs to work, but does not"
+  exit $failures
+fi
+
+echo "[pass] At least one of TLSv1.0, TLSv1.1, or TLSv1.2 worked"
+exit 0
diff --git a/test/features/util.py b/test/features/util.py
new file mode 100644
index 0000000..3abbbbd
--- /dev/null
+++ b/test/features/util.py
@@ -0,0 +1,40 @@
+import argparse
+import socket
+
+from local_thrift import thrift  # noqa
+from thrift.transport.TSocket import TSocket
+from thrift.transport.TTransport import TBufferedTransport, TFramedTransport
+from thrift.transport.THttpClient import THttpClient
+from thrift.protocol.TBinaryProtocol import TBinaryProtocol
+from thrift.protocol.TCompactProtocol import TCompactProtocol
+from thrift.protocol.TJSONProtocol import TJSONProtocol
+
+
+def add_common_args(p):
+    p.add_argument('--host', default='localhost')
+    p.add_argument('--port', type=int, default=9090)
+    p.add_argument('--protocol', default='binary')
+    p.add_argument('--transport', default='buffered')
+    p.add_argument('--ssl', action='store_true')
+
+
+def parse_common_args(argv):
+    p = argparse.ArgumentParser()
+    add_common_args(p)
+    return p.parse_args(argv)
+
+
+def init_protocol(args):
+    sock = TSocket(args.host, args.port, socket_family=socket.AF_INET)
+    sock.setTimeout(500)
+    trans = {
+        'buffered': TBufferedTransport,
+        'framed': TFramedTransport,
+        'http': THttpClient,
+    }[args.transport](sock)
+    trans.open()
+    return {
+        'binary': TBinaryProtocol,
+        'compact': TCompactProtocol,
+        'json': TJSONProtocol,
+    }[args.protocol](trans)
diff --git a/test/go/Makefile.am b/test/go/Makefile.am
new file mode 100644
index 0000000..6da8339
--- /dev/null
+++ b/test/go/Makefile.am
@@ -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.
+#
+
+BUILT_SOURCES = gopath
+
+THRIFTCMD = $(THRIFT) -out src/gen --gen go:thrift_import=thrift$(COMPILER_EXTRAFLAG)
+THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift
+
+precross: bin/testclient bin/testserver
+
+ThriftTest.thrift: $(THRIFTTEST)
+	grep -v list.*map.*list.*map $(THRIFTTEST) > ThriftTest.thrift
+
+.PHONY: gopath
+
+# Thrift for GO has problems with complex map keys: THRIFT-2063
+gopath: $(THRIFT) ThriftTest.thrift
+	mkdir -p src/gen
+	$(THRIFTCMD) ThriftTest.thrift
+	$(THRIFTCMD) ../StressTest.thrift
+	GOPATH=`pwd` $(GO) get github.com/golang/mock/gomock || true
+	sed -i 's/\"context\"/\"golang.org\/x\/net\/context\"/g' src/github.com/golang/mock/gomock/controller.go || true
+	GOPATH=`pwd` $(GO) get github.com/golang/mock/gomock
+	ln -nfs ../../../lib/go/thrift src/thrift
+	touch gopath
+
+bin/testclient: gopath
+	GOPATH=`pwd` $(GO) install bin/testclient
+
+bin/testserver: gopath
+	GOPATH=`pwd` $(GO) install bin/testserver
+
+bin/stress: gopath
+	GOPATH=`pwd` $(GO) install bin/stress
+
+clean-local:
+	$(RM) -r src/gen src/github.com/golang src/thrift bin pkg gopath ThriftTest.thrift
+
+check_PROGRAMS: bin/testclient bin/testserver bin/stress
+
+check: gopath genmock
+	GOPATH=`pwd` $(GO) test -v common/...
+
+genmock: gopath
+	GOPATH=`pwd` $(GO) install github.com/golang/mock/mockgen
+	GOPATH=`pwd` bin/mockgen -destination=src/common/mock_handler.go -package=common gen/thrifttest ThriftTest
+
+EXTRA_DIST = \
+	src/bin \
+	src/common
diff --git a/test/go/src/bin/stress/main.go b/test/go/src/bin/stress/main.go
new file mode 100644
index 0000000..f2e0f20
--- /dev/null
+++ b/test/go/src/bin/stress/main.go
@@ -0,0 +1,254 @@
+/*
+ * 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 main
+
+import (
+	"context"
+	"flag"
+	"fmt"
+	"gen/stress"
+	"log"
+	_ "net/http/pprof"
+	"os"
+	"runtime"
+	"runtime/pprof"
+	"sync"
+	"sync/atomic"
+	"thrift"
+	"time"
+)
+
+var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
+var memprofile = flag.String("memprofile", "", "write memory profile to this file")
+
+var (
+	host      = flag.String("host", "localhost", "Host to connect")
+	port      = flag.Int64("port", 9091, "Port number to connect")
+	loop      = flag.Int("loops", 50000, "The number of remote thrift calls each client makes")
+	runserver = flag.Int("server", 1, "Run the Thrift server in this process")
+	clients   = flag.Int("clients", 20, "Number of client threads to create - 0 implies no clients, i.e. server only")
+	callName  = flag.String("call", "echoVoid", "Service method to call, one of echoVoid, echoByte, echoI32, echoI64, echoString, echiList, echoSet, echoMap")
+	compact   = flag.Bool("compact", false, "Use compact protocol instead of binary.")
+	framed    = flag.Bool("framed", false, "Use framed transport instead of buffered.")
+)
+var hostPort string
+
+type callT int64
+
+const (
+	echoVoid callT = iota
+	echoByte
+	echoI32
+	echoI64
+	echoString
+	echiList
+	echoSet
+	echoMap
+)
+
+var callTMap = map[string]callT{
+	"echoVoid":   echoVoid,
+	"echoByte":   echoByte,
+	"echoI32":    echoI32,
+	"echoI64":    echoI64,
+	"echoString": echoString,
+	"echiList":   echiList,
+	"echoSet":    echoSet,
+	"echoMap":    echoMap,
+}
+var callType callT
+
+var ready, done sync.WaitGroup
+
+var clicounter int64 = 0
+var counter int64 = 0
+
+func main() {
+	flag.Parse()
+	if *memprofile != "" {
+		runtime.MemProfileRate = 100
+	}
+	var ok bool
+	if callType, ok = callTMap[*callName]; !ok {
+		log.Fatal("Unknown service call", *callName)
+	}
+	if *cpuprofile != "" {
+		f, err := os.Create(*cpuprofile)
+		if err != nil {
+			log.Fatal(err)
+		}
+		pprof.StartCPUProfile(f)
+		defer pprof.StopCPUProfile()
+	}
+	hostPort = fmt.Sprintf("%s:%d", *host, *port)
+	var protocolFactory thrift.TProtocolFactory
+	var transportFactory thrift.TTransportFactory
+
+	if *compact {
+		protocolFactory = thrift.NewTCompactProtocolFactory()
+	} else {
+		protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()
+	}
+
+	if *framed {
+		transportFactory = thrift.NewTTransportFactory()
+		transportFactory = thrift.NewTFramedTransportFactory(transportFactory)
+	} else {
+		transportFactory = thrift.NewTBufferedTransportFactory(8192)
+	}
+
+	if *runserver > 0 {
+		serverTransport, err := thrift.NewTServerSocket(hostPort)
+		if err != nil {
+			log.Fatalf("Unable to create server socket: %s", err)
+		}
+
+		processor := stress.NewServiceProcessor(&handler{})
+		server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
+		if *clients == 0 {
+			server.Serve()
+		} else {
+			go server.Serve()
+		}
+	}
+	//start clients
+	if *clients != 0 {
+		ready.Add(*clients + 1)
+		done.Add(*clients)
+		for i := 0; i < *clients; i++ {
+			go client(protocolFactory)
+		}
+		ready.Done()
+		ready.Wait()
+		//run!
+		startTime := time.Now()
+		//wait for completion
+		done.Wait()
+		endTime := time.Now()
+		duration := endTime.Sub(startTime)
+		log.Printf("%d calls in %v (%f calls per second)\n", clicounter, duration, float64(clicounter)/duration.Seconds())
+	}
+	if *memprofile != "" {
+		f, err := os.Create(*memprofile)
+		if err != nil {
+			log.Fatal(err)
+		}
+		pprof.WriteHeapProfile(f)
+		f.Close()
+		return
+	}
+}
+
+func client(protocolFactory thrift.TProtocolFactory) {
+	trans, err := thrift.NewTSocket(hostPort)
+	if err != nil {
+		log.Fatalf("Unable to create server socket: %s", err)
+	}
+	btrans := thrift.NewTBufferedTransport(trans, 2048)
+	client := stress.NewServiceClientFactory(btrans, protocolFactory)
+	err = trans.Open()
+	if err != nil {
+		log.Fatalf("Unable to open connection: %s", err)
+	}
+	ready.Done()
+	ready.Wait()
+	switch callType {
+	case echoVoid:
+		for i := 0; i < *loop; i++ {
+			client.EchoVoid()
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echoByte:
+		for i := 0; i < *loop; i++ {
+			client.EchoByte(42)
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echoI32:
+		for i := 0; i < *loop; i++ {
+			client.EchoI32(4242)
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echoI64:
+		for i := 0; i < *loop; i++ {
+			client.EchoI64(424242)
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echoString:
+		for i := 0; i < *loop; i++ {
+			client.EchoString("TestString")
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echiList:
+		l := []int8{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8}
+		for i := 0; i < *loop; i++ {
+			client.EchoList(l)
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echoSet:
+		s := map[int8]struct{}{-10: {}, -9: {}, -8: {}, -7: {}, -6: {}, -5: {}, -4: {}, -3: {}, -2: {}, -1: {}, 0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {}, 8: {}}
+		for i := 0; i < *loop; i++ {
+			client.EchoSet(s)
+			atomic.AddInt64(&clicounter, 1)
+		}
+	case echoMap:
+		m := map[int8]int8{-10: 10, -9: 9, -8: 8, -7: 7, -6: 6, -5: 5, -4: 4, -3: 3, -2: 2, -1: 1, 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8}
+		for i := 0; i < *loop; i++ {
+			client.EchoMap(m)
+			atomic.AddInt64(&clicounter, 1)
+		}
+	}
+
+	done.Done()
+}
+
+type handler struct{}
+
+func (h *handler) EchoVoid(ctx context.Context) (err error) {
+	atomic.AddInt64(&counter, 1)
+	return nil
+}
+func (h *handler) EchoByte(ctx context.Context, arg int8) (r int8, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoI32(ctx context.Context, arg int32) (r int32, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoI64(ctx context.Context, arg int64) (r int64, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoString(ctx context.Context, arg string) (r string, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoList(ctx context.Context, arg []int8) (r []int8, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoSet(ctx context.Context, arg map[int8]struct{}) (r map[int8]struct{}, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
+func (h *handler) EchoMap(ctx context.Context, arg map[int8]int8) (r map[int8]int8, err error) {
+	atomic.AddInt64(&counter, 1)
+	return arg, nil
+}
diff --git a/test/go/src/bin/testclient/main.go b/test/go/src/bin/testclient/main.go
new file mode 100644
index 0000000..4357ee8
--- /dev/null
+++ b/test/go/src/bin/testclient/main.go
@@ -0,0 +1,316 @@
+/*
+ * 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 main
+
+import (
+	"common"
+	"context"
+	"flag"
+	"gen/thrifttest"
+	t "log"
+	"reflect"
+	"thrift"
+)
+
+var host = flag.String("host", "localhost", "Host to connect")
+var port = flag.Int64("port", 9090, "Port number to connect")
+var domain_socket = flag.String("domain-socket", "", "Domain Socket (e.g. /tmp/thrifttest.thrift), instead of host and port")
+var transport = flag.String("transport", "buffered", "Transport: buffered, framed, http, zlib")
+var protocol = flag.String("protocol", "binary", "Protocol: binary, compact, json")
+var ssl = flag.Bool("ssl", false, "Encrypted Transport using SSL")
+var zlib = flag.Bool("zlib", false, "Wrapped Transport using Zlib")
+var testloops = flag.Int("testloops", 1, "Number of Tests")
+
+func main() {
+	flag.Parse()
+	client, _, err := common.StartClient(*host, *port, *domain_socket, *transport, *protocol, *ssl)
+	if err != nil {
+		t.Fatalf("Unable to start client: ", err)
+	}
+	for i := 0; i < *testloops; i++ {
+		callEverything(client)
+	}
+}
+
+var rmapmap = map[int32]map[int32]int32{
+	-4: map[int32]int32{-4: -4, -3: -3, -2: -2, -1: -1},
+	4:  map[int32]int32{4: 4, 3: 3, 2: 2, 1: 1},
+}
+
+var xxs = &thrifttest.Xtruct{
+	StringThing: "Hello2",
+	ByteThing:   42,
+	I32Thing:    4242,
+	I64Thing:    424242,
+}
+
+var xcept = &thrifttest.Xception{ErrorCode: 1001, Message: "Xception"}
+var defaultCtx = context.Background()
+
+func callEverything(client *thrifttest.ThriftTestClient) {
+	var err error
+	if err = client.TestVoid(defaultCtx); err != nil {
+		t.Fatalf("Unexpected error in TestVoid() call: ", err)
+	}
+
+	thing, err := client.TestString(defaultCtx, "thing")
+	if err != nil {
+		t.Fatalf("Unexpected error in TestString() call: ", err)
+	}
+	if thing != "thing" {
+		t.Fatalf("Unexpected TestString() result, expected 'thing' got '%s' ", thing)
+	}
+
+	bl, err := client.TestBool(defaultCtx, true)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestBool() call: ", err)
+	}
+	if !bl {
+		t.Fatalf("Unexpected TestBool() result expected true, got %f ", bl)
+	}
+	bl, err = client.TestBool(defaultCtx, false)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestBool() call: ", err)
+	}
+	if bl {
+		t.Fatalf("Unexpected TestBool() result expected false, got %f ", bl)
+	}
+
+	b, err := client.TestByte(defaultCtx, 42)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestByte() call: ", err)
+	}
+	if b != 42 {
+		t.Fatalf("Unexpected TestByte() result expected 42, got %d ", b)
+	}
+
+	i32, err := client.TestI32(defaultCtx, 4242)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestI32() call: ", err)
+	}
+	if i32 != 4242 {
+		t.Fatalf("Unexpected TestI32() result expected 4242, got %d ", i32)
+	}
+
+	i64, err := client.TestI64(defaultCtx, 424242)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestI64() call: ", err)
+	}
+	if i64 != 424242 {
+		t.Fatalf("Unexpected TestI64() result expected 424242, got %d ", i64)
+	}
+
+	d, err := client.TestDouble(defaultCtx, 42.42)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestDouble() call: ", err)
+	}
+	if d != 42.42 {
+		t.Fatalf("Unexpected TestDouble() result expected 42.42, got %f ", d)
+	}
+
+	binout := make([]byte, 256)
+	for i := 0; i < 256; i++ {
+		binout[i] = byte(i)
+	}
+	bin, err := client.TestBinary(defaultCtx, binout)
+	for i := 0; i < 256; i++ {
+		if binout[i] != bin[i] {
+			t.Fatalf("Unexpected TestBinary() result expected %d, got %d ", binout[i], bin[i])
+		}
+	}
+
+	xs := thrifttest.NewXtruct()
+	xs.StringThing = "thing"
+	xs.ByteThing = 42
+	xs.I32Thing = 4242
+	xs.I64Thing = 424242
+	xsret, err := client.TestStruct(defaultCtx, xs)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestStruct() call: ", err)
+	}
+	if *xs != *xsret {
+		t.Fatalf("Unexpected TestStruct() result expected %#v, got %#v ", xs, xsret)
+	}
+
+	x2 := thrifttest.NewXtruct2()
+	x2.StructThing = xs
+	x2ret, err := client.TestNest(defaultCtx, x2)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestNest() call: ", err)
+	}
+	if !reflect.DeepEqual(x2, x2ret) {
+		t.Fatalf("Unexpected TestNest() result expected %#v, got %#v ", x2, x2ret)
+	}
+
+	m := map[int32]int32{1: 2, 3: 4, 5: 42}
+	mret, err := client.TestMap(defaultCtx, m)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestMap() call: ", err)
+	}
+	if !reflect.DeepEqual(m, mret) {
+		t.Fatalf("Unexpected TestMap() result expected %#v, got %#v ", m, mret)
+	}
+
+	sm := map[string]string{"a": "2", "b": "blah", "some": "thing"}
+	smret, err := client.TestStringMap(defaultCtx, sm)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestStringMap() call: ", err)
+	}
+	if !reflect.DeepEqual(sm, smret) {
+		t.Fatalf("Unexpected TestStringMap() result expected %#v, got %#v ", sm, smret)
+	}
+
+	s := []int32{1, 2, 42}
+	sret, err := client.TestSet(defaultCtx, s)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestSet() call: ", err)
+	}
+	// Sets can be in any order, but Go slices are ordered, so reflect.DeepEqual won't work.
+	stemp := map[int32]struct{}{}
+	for _, val := range s {
+		stemp[val] = struct{}{}
+	}
+	for _, val := range sret {
+		if _, ok := stemp[val]; !ok {
+			t.Fatalf("Unexpected TestSet() result expected %#v, got %#v ", s, sret)
+		}
+	}
+
+	l := []int32{1, 2, 42}
+	lret, err := client.TestList(defaultCtx, l)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestList() call: ", err)
+	}
+	if !reflect.DeepEqual(l, lret) {
+		t.Fatalf("Unexpected TestList() result expected %#v, got %#v ", l, lret)
+	}
+
+	eret, err := client.TestEnum(defaultCtx, thrifttest.Numberz_TWO)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestEnum() call: ", err)
+	}
+	if eret != thrifttest.Numberz_TWO {
+		t.Fatalf("Unexpected TestEnum() result expected %#v, got %#v ", thrifttest.Numberz_TWO, eret)
+	}
+
+	tret, err := client.TestTypedef(defaultCtx, thrifttest.UserId(42))
+	if err != nil {
+		t.Fatalf("Unexpected error in TestTypedef() call: ", err)
+	}
+	if tret != thrifttest.UserId(42) {
+		t.Fatalf("Unexpected TestTypedef() result expected %#v, got %#v ", thrifttest.UserId(42), tret)
+	}
+
+	mapmap, err := client.TestMapMap(defaultCtx, 42)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestMapMap() call: ", err)
+	}
+	if !reflect.DeepEqual(mapmap, rmapmap) {
+		t.Fatalf("Unexpected TestMapMap() result expected %#v, got %#v ", rmapmap, mapmap)
+	}
+
+	crazy := thrifttest.NewInsanity()
+	crazy.UserMap = map[thrifttest.Numberz]thrifttest.UserId{
+		thrifttest.Numberz_FIVE:  5,
+		thrifttest.Numberz_EIGHT: 8,
+	}
+	truck1 := thrifttest.NewXtruct()
+	truck1.StringThing = "Goodbye4"
+	truck1.ByteThing = 4
+	truck1.I32Thing = 4
+	truck1.I64Thing = 4
+	truck2 := thrifttest.NewXtruct()
+	truck2.StringThing = "Hello2"
+	truck2.ByteThing = 2
+	truck2.I32Thing = 2
+	truck2.I64Thing = 2
+	crazy.Xtructs = []*thrifttest.Xtruct{
+		truck1,
+		truck2,
+	}
+	insanity, err := client.TestInsanity(defaultCtx, crazy)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestInsanity() call: ", err)
+	}
+	if !reflect.DeepEqual(crazy, insanity[1][2]) {
+		t.Fatalf("Unexpected TestInsanity() first result expected %#v, got %#v ",
+			crazy,
+			insanity[1][2])
+	}
+	if !reflect.DeepEqual(crazy, insanity[1][3]) {
+		t.Fatalf("Unexpected TestInsanity() second result expected %#v, got %#v ",
+			crazy,
+			insanity[1][3])
+	}
+	if len(insanity[2][6].UserMap) > 0 || len(insanity[2][6].Xtructs) > 0 {
+		t.Fatalf("Unexpected TestInsanity() non-empty result got %#v ",
+			insanity[2][6])
+	}
+
+	xxsret, err := client.TestMulti(defaultCtx, 42, 4242, 424242, map[int16]string{1: "blah", 2: "thing"}, thrifttest.Numberz_EIGHT, thrifttest.UserId(24))
+	if err != nil {
+		t.Fatalf("Unexpected error in TestMulti() call: ", err)
+	}
+	if !reflect.DeepEqual(xxs, xxsret) {
+		t.Fatalf("Unexpected TestMulti() result expected %#v, got %#v ", xxs, xxsret)
+	}
+
+	err = client.TestException(defaultCtx, "Xception")
+	if err == nil {
+		t.Fatalf("Expecting exception in TestException() call")
+	}
+	if !reflect.DeepEqual(err, xcept) {
+		t.Fatalf("Unexpected TestException() result expected %#v, got %#v ", xcept, err)
+	}
+
+	err = client.TestException(defaultCtx, "TException")
+	_, ok := err.(thrift.TApplicationException)
+	if err == nil || !ok {
+		t.Fatalf("Unexpected TestException() result expected ApplicationError, got %#v ", err)
+	}
+
+	ign, err := client.TestMultiException(defaultCtx, "Xception", "ignoreme")
+	if ign != nil || err == nil {
+		t.Fatalf("Expecting exception in TestMultiException() call")
+	}
+	if !reflect.DeepEqual(err, &thrifttest.Xception{ErrorCode: 1001, Message: "This is an Xception"}) {
+		t.Fatalf("Unexpected TestMultiException() %#v ", err)
+	}
+
+	ign, err = client.TestMultiException(defaultCtx, "Xception2", "ignoreme")
+	if ign != nil || err == nil {
+		t.Fatalf("Expecting exception in TestMultiException() call")
+	}
+	expecting := &thrifttest.Xception2{ErrorCode: 2002, StructThing: &thrifttest.Xtruct{StringThing: "This is an Xception2"}}
+
+	if !reflect.DeepEqual(err, expecting) {
+		t.Fatalf("Unexpected TestMultiException() %#v ", err)
+	}
+
+	err = client.TestOneway(defaultCtx, 2)
+	if err != nil {
+		t.Fatalf("Unexpected error in TestOneway() call: ", err)
+	}
+
+	//Make sure the connection still alive
+	if err = client.TestVoid(defaultCtx); err != nil {
+		t.Fatalf("Unexpected error in TestVoid() call: ", err)
+	}
+}
diff --git a/test/go/src/bin/testserver/main.go b/test/go/src/bin/testserver/main.go
new file mode 100644
index 0000000..ca2d967
--- /dev/null
+++ b/test/go/src/bin/testserver/main.go
@@ -0,0 +1,71 @@
+/*
+ * 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 main
+
+import (
+	"common"
+	"flag"
+	"fmt"
+	"log"
+	"net/http"
+	"thrift"
+)
+
+var host = flag.String("host", "localhost", "Host to connect")
+var port = flag.Int64("port", 9090, "Port number to connect")
+var domain_socket = flag.String("domain-socket", "", "Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port")
+var transport = flag.String("transport", "buffered", "Transport: buffered, framed, http, zlib")
+var protocol = flag.String("protocol", "binary", "Protocol: binary, compact, json")
+var ssl = flag.Bool("ssl", false, "Encrypted Transport using SSL")
+var zlib = flag.Bool("zlib", false, "Wrapped Transport using Zlib")
+var certPath = flag.String("certPath", "keys", "Directory that contains SSL certificates")
+
+func main() {
+	flag.Parse()
+
+	processor, serverTransport, transportFactory, protocolFactory, err := common.GetServerParams(*host, *port, *domain_socket, *transport, *protocol, *ssl, *certPath, common.PrintingHandler)
+
+	if err != nil {
+		log.Fatalf("Unable to process server params: ", err)
+	}
+
+	if *transport == "http" {
+		http.HandleFunc("/", thrift.NewThriftHandlerFunc(processor, protocolFactory, protocolFactory))
+
+		if *ssl {
+			err := http.ListenAndServeTLS(fmt.Sprintf(":%d", *port),
+				*certPath+"/server.pem", *certPath+"/server.key", nil)
+
+			if err != nil {
+				fmt.Println(err)
+				return
+			}
+		} else {
+			http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)
+		}
+	} else {
+		server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
+		if err = server.Listen(); err != nil {
+			return
+		}
+		go server.AcceptLoop()
+		server.Serve()
+	}
+}
diff --git a/test/go/src/common/client.go b/test/go/src/common/client.go
new file mode 100644
index 0000000..236ce43
--- /dev/null
+++ b/test/go/src/common/client.go
@@ -0,0 +1,109 @@
+/*
+ * 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 common
+
+import (
+	"compress/zlib"
+	"crypto/tls"
+	"flag"
+	"fmt"
+	"gen/thrifttest"
+	"net/http"
+	"thrift"
+)
+
+var debugClientProtocol bool
+
+func init() {
+	flag.BoolVar(&debugClientProtocol, "debug_client_protocol", false, "turn client protocol trace on")
+}
+
+func StartClient(
+	host string,
+	port int64,
+	domain_socket string,
+	transport string,
+	protocol string,
+	ssl bool) (client *thrifttest.ThriftTestClient, trans thrift.TTransport, err error) {
+
+	hostPort := fmt.Sprintf("%s:%d", host, port)
+
+	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:
+		return nil, nil, fmt.Errorf("Invalid protocol specified %s", protocol)
+	}
+	if debugClientProtocol {
+		protocolFactory = thrift.NewTDebugProtocolFactory(protocolFactory, "client:")
+	}
+	if ssl {
+		trans, err = thrift.NewTSSLSocket(hostPort, &tls.Config{InsecureSkipVerify: true})
+	} else {
+		if domain_socket != "" {
+			trans, err = thrift.NewTSocket(domain_socket)
+		} else {
+			trans, err = thrift.NewTSocket(hostPort)
+		}
+	}
+	if err != nil {
+		return nil, nil, err
+	}
+	switch transport {
+	case "http":
+		if ssl {
+			tr := &http.Transport{
+				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+			}
+			client := &http.Client{Transport: tr}
+			trans, err = thrift.NewTHttpPostClientWithOptions(fmt.Sprintf("https://%s/", hostPort), thrift.THttpClientOptions{Client: client})
+			fmt.Println(hostPort)
+		} else {
+			trans, err = thrift.NewTHttpPostClient(fmt.Sprintf("http://%s/", hostPort))
+		}
+	case "framed":
+		trans = thrift.NewTFramedTransport(trans)
+	case "buffered":
+		trans = thrift.NewTBufferedTransport(trans, 8192)
+	case "zlib":
+		trans, err = thrift.NewTZlibTransport(trans, zlib.BestCompression)
+	case "":
+		trans = trans
+	default:
+		return nil, nil, fmt.Errorf("Invalid transport specified %s", transport)
+	}
+	if err != nil {
+		return nil, nil, err
+	}
+	if err = trans.Open(); err != nil {
+		return nil, nil, err
+	}
+	iprot := protocolFactory.GetProtocol(trans)
+	oprot := protocolFactory.GetProtocol(trans)
+	client = thrifttest.NewThriftTestClient(thrift.NewTStandardClient(iprot, oprot))
+	return
+}
diff --git a/test/go/src/common/clientserver_test.go b/test/go/src/common/clientserver_test.go
new file mode 100644
index 0000000..9f93c4c
--- /dev/null
+++ b/test/go/src/common/clientserver_test.go
@@ -0,0 +1,335 @@
+/*
+ * 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 common
+
+import (
+	"context"
+	"errors"
+	"gen/thrifttest"
+	"reflect"
+	"sync"
+	"testing"
+	"thrift"
+
+	"github.com/golang/mock/gomock"
+)
+
+type test_unit struct {
+	host          string
+	port          int64
+	domain_socket string
+	transport     string
+	protocol      string
+	ssl           bool
+}
+
+var units = []test_unit{
+	{"127.0.0.1", 9095, "", "", "binary", false},
+	{"127.0.0.1", 9091, "", "", "compact", false},
+	{"127.0.0.1", 9092, "", "", "binary", true},
+	{"127.0.0.1", 9093, "", "", "compact", true},
+}
+
+func TestAllConnection(t *testing.T) {
+	certPath = "../../../keys"
+	wg := &sync.WaitGroup{}
+	wg.Add(len(units))
+	for _, unit := range units {
+		go func(u test_unit) {
+			defer wg.Done()
+			doUnit(t, &u)
+		}(unit)
+	}
+	wg.Wait()
+}
+
+func doUnit(t *testing.T, unit *test_unit) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
+	handler := NewMockThriftTest(ctrl)
+
+	processor, serverTransport, transportFactory, protocolFactory, err := GetServerParams(unit.host, unit.port, unit.domain_socket, unit.transport, unit.protocol, unit.ssl, "../../../keys", handler)
+
+	server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
+	if err = server.Listen(); err != nil {
+		t.Errorf("Unable to start server: %v", err)
+		return
+	}
+	go server.AcceptLoop()
+	defer server.Stop()
+	client, trans, err := StartClient(unit.host, unit.port, unit.domain_socket, unit.transport, unit.protocol, unit.ssl)
+	if err != nil {
+		t.Errorf("Unable to start client: %v", err)
+		return
+	}
+	defer trans.Close()
+	callEverythingWithMock(t, client, handler)
+}
+
+var rmapmap = map[int32]map[int32]int32{
+	-4: map[int32]int32{-4: -4, -3: -3, -2: -2, -1: -1},
+	4:  map[int32]int32{4: 4, 3: 3, 2: 2, 1: 1},
+}
+
+var xxs = &thrifttest.Xtruct{
+	StringThing: "Hello2",
+	ByteThing:   42,
+	I32Thing:    4242,
+	I64Thing:    424242,
+}
+
+var xcept = &thrifttest.Xception{ErrorCode: 1001, Message: "some"}
+var defaultCtx = context.Background()
+
+func callEverythingWithMock(t *testing.T, client *thrifttest.ThriftTestClient, handler *MockThriftTest) {
+	gomock.InOrder(
+		handler.EXPECT().TestVoid(gomock.Any()),
+		handler.EXPECT().TestString(gomock.Any(), "thing").Return("thing", nil),
+		handler.EXPECT().TestBool(gomock.Any(), true).Return(true, nil),
+		handler.EXPECT().TestBool(gomock.Any(), false).Return(false, nil),
+		handler.EXPECT().TestByte(gomock.Any(), int8(42)).Return(int8(42), nil),
+		handler.EXPECT().TestI32(gomock.Any(), int32(4242)).Return(int32(4242), nil),
+		handler.EXPECT().TestI64(gomock.Any(), int64(424242)).Return(int64(424242), nil),
+		// TODO: add TestBinary()
+		handler.EXPECT().TestDouble(gomock.Any(), float64(42.42)).Return(float64(42.42), nil),
+		handler.EXPECT().TestStruct(gomock.Any(), &thrifttest.Xtruct{StringThing: "thing", ByteThing: 42, I32Thing: 4242, I64Thing: 424242}).Return(&thrifttest.Xtruct{StringThing: "thing", ByteThing: 42, I32Thing: 4242, I64Thing: 424242}, nil),
+		handler.EXPECT().TestNest(gomock.Any(), &thrifttest.Xtruct2{StructThing: &thrifttest.Xtruct{StringThing: "thing", ByteThing: 42, I32Thing: 4242, I64Thing: 424242}}).Return(&thrifttest.Xtruct2{StructThing: &thrifttest.Xtruct{StringThing: "thing", ByteThing: 42, I32Thing: 4242, I64Thing: 424242}}, nil),
+		handler.EXPECT().TestMap(gomock.Any(), map[int32]int32{1: 2, 3: 4, 5: 42}).Return(map[int32]int32{1: 2, 3: 4, 5: 42}, nil),
+		handler.EXPECT().TestStringMap(gomock.Any(), map[string]string{"a": "2", "b": "blah", "some": "thing"}).Return(map[string]string{"a": "2", "b": "blah", "some": "thing"}, nil),
+		handler.EXPECT().TestSet(gomock.Any(), []int32{1, 2, 42}).Return([]int32{1, 2, 42}, nil),
+		handler.EXPECT().TestList(gomock.Any(), []int32{1, 2, 42}).Return([]int32{1, 2, 42}, nil),
+		handler.EXPECT().TestEnum(gomock.Any(), thrifttest.Numberz_TWO).Return(thrifttest.Numberz_TWO, nil),
+		handler.EXPECT().TestTypedef(gomock.Any(), thrifttest.UserId(42)).Return(thrifttest.UserId(42), nil),
+		handler.EXPECT().TestMapMap(gomock.Any(), int32(42)).Return(rmapmap, nil),
+		// TODO: not testing insanity
+		handler.EXPECT().TestMulti(gomock.Any(), int8(42), int32(4242), int64(424242), map[int16]string{1: "blah", 2: "thing"}, thrifttest.Numberz_EIGHT, thrifttest.UserId(24)).Return(xxs, nil),
+		handler.EXPECT().TestException(gomock.Any(), "some").Return(xcept),
+		handler.EXPECT().TestException(gomock.Any(), "TException").Return(errors.New("Just random exception")),
+		handler.EXPECT().TestMultiException(gomock.Any(), "Xception", "ignoreme").Return(nil, &thrifttest.Xception{ErrorCode: 1001, Message: "This is an Xception"}),
+		handler.EXPECT().TestMultiException(gomock.Any(), "Xception2", "ignoreme").Return(nil, &thrifttest.Xception2{ErrorCode: 2002, StructThing: &thrifttest.Xtruct{StringThing: "This is an Xception2"}}),
+		handler.EXPECT().TestOneway(gomock.Any(), int32(2)).Return(nil),
+		handler.EXPECT().TestVoid(gomock.Any()),
+	)
+	var err error
+	if err = client.TestVoid(defaultCtx); err != nil {
+		t.Errorf("Unexpected error in TestVoid() call: %s", err)
+	}
+
+	thing, err := client.TestString(defaultCtx, "thing")
+	if err != nil {
+		t.Errorf("Unexpected error in TestString() call: %s", err)
+	}
+	if thing != "thing" {
+		t.Errorf("Unexpected TestString() result, expected 'thing' got '%s' ", thing)
+	}
+
+	bl, err := client.TestBool(defaultCtx, true)
+	if err != nil {
+		t.Errorf("Unexpected error in TestBool() call: %s", err)
+	}
+	if !bl {
+		t.Errorf("Unexpected TestBool() result expected true, got %v ", bl)
+	}
+	bl, err = client.TestBool(defaultCtx, false)
+	if err != nil {
+		t.Errorf("Unexpected error in TestBool() call: %s", err)
+	}
+	if bl {
+		t.Errorf("Unexpected TestBool() result expected false, got %v ", bl)
+	}
+
+	b, err := client.TestByte(defaultCtx, 42)
+	if err != nil {
+		t.Errorf("Unexpected error in TestByte() call: %s", err)
+	}
+	if b != 42 {
+		t.Errorf("Unexpected TestByte() result expected 42, got %d ", b)
+	}
+
+	i32, err := client.TestI32(defaultCtx, 4242)
+	if err != nil {
+		t.Errorf("Unexpected error in TestI32() call: %s", err)
+	}
+	if i32 != 4242 {
+		t.Errorf("Unexpected TestI32() result expected 4242, got %d ", i32)
+	}
+
+	i64, err := client.TestI64(defaultCtx, 424242)
+	if err != nil {
+		t.Errorf("Unexpected error in TestI64() call: %s", err)
+	}
+	if i64 != 424242 {
+		t.Errorf("Unexpected TestI64() result expected 424242, got %d ", i64)
+	}
+
+	d, err := client.TestDouble(defaultCtx, 42.42)
+	if err != nil {
+		t.Errorf("Unexpected error in TestDouble() call: %s", err)
+	}
+	if d != 42.42 {
+		t.Errorf("Unexpected TestDouble() result expected 42.42, got %f ", d)
+	}
+
+	// TODO: add TestBinary() call
+
+	xs := thrifttest.NewXtruct()
+	xs.StringThing = "thing"
+	xs.ByteThing = 42
+	xs.I32Thing = 4242
+	xs.I64Thing = 424242
+	xsret, err := client.TestStruct(defaultCtx, xs)
+	if err != nil {
+		t.Errorf("Unexpected error in TestStruct() call: %s", err)
+	}
+	if *xs != *xsret {
+		t.Errorf("Unexpected TestStruct() result expected %#v, got %#v ", xs, xsret)
+	}
+
+	x2 := thrifttest.NewXtruct2()
+	x2.StructThing = xs
+	x2ret, err := client.TestNest(defaultCtx, x2)
+	if err != nil {
+		t.Errorf("Unexpected error in TestNest() call: %s", err)
+	}
+	if !reflect.DeepEqual(x2, x2ret) {
+		t.Errorf("Unexpected TestNest() result expected %#v, got %#v ", x2, x2ret)
+	}
+
+	m := map[int32]int32{1: 2, 3: 4, 5: 42}
+	mret, err := client.TestMap(defaultCtx, m)
+	if err != nil {
+		t.Errorf("Unexpected error in TestMap() call: %s", err)
+	}
+	if !reflect.DeepEqual(m, mret) {
+		t.Errorf("Unexpected TestMap() result expected %#v, got %#v ", m, mret)
+	}
+
+	sm := map[string]string{"a": "2", "b": "blah", "some": "thing"}
+	smret, err := client.TestStringMap(defaultCtx, sm)
+	if err != nil {
+		t.Errorf("Unexpected error in TestStringMap() call: %s", err)
+	}
+	if !reflect.DeepEqual(sm, smret) {
+		t.Errorf("Unexpected TestStringMap() result expected %#v, got %#v ", sm, smret)
+	}
+
+	s := []int32{1, 2, 42}
+	sret, err := client.TestSet(defaultCtx, s)
+	if err != nil {
+		t.Errorf("Unexpected error in TestSet() call: %s", err)
+	}
+	// Sets can be in any order, but Go slices are ordered, so reflect.DeepEqual won't work.
+	stemp := map[int32]struct{}{}
+	for _, val := range s {
+		stemp[val] = struct{}{}
+	}
+	for _, val := range sret {
+		if _, ok := stemp[val]; !ok {
+			t.Fatalf("Unexpected TestSet() result expected %#v, got %#v ", s, sret)
+		}
+	}
+
+	l := []int32{1, 2, 42}
+	lret, err := client.TestList(defaultCtx, l)
+	if err != nil {
+		t.Errorf("Unexpected error in TestList() call: %s", err)
+	}
+	if !reflect.DeepEqual(l, lret) {
+		t.Errorf("Unexpected TestList() result expected %#v, got %#v ", l, lret)
+	}
+
+	eret, err := client.TestEnum(defaultCtx, thrifttest.Numberz_TWO)
+	if err != nil {
+		t.Errorf("Unexpected error in TestEnum() call: %s", err)
+	}
+	if eret != thrifttest.Numberz_TWO {
+		t.Errorf("Unexpected TestEnum() result expected %#v, got %#v ", thrifttest.Numberz_TWO, eret)
+	}
+
+	tret, err := client.TestTypedef(defaultCtx, thrifttest.UserId(42))
+	if err != nil {
+		t.Errorf("Unexpected error in TestTypedef() call: %s", err)
+	}
+	if tret != thrifttest.UserId(42) {
+		t.Errorf("Unexpected TestTypedef() result expected %#v, got %#v ", thrifttest.UserId(42), tret)
+	}
+
+	mapmap, err := client.TestMapMap(defaultCtx, 42)
+	if err != nil {
+		t.Errorf("Unexpected error in TestMapmap() call: %s", err)
+	}
+	if !reflect.DeepEqual(mapmap, rmapmap) {
+		t.Errorf("Unexpected TestMapmap() result expected %#v, got %#v ", rmapmap, mapmap)
+	}
+
+	xxsret, err := client.TestMulti(defaultCtx, 42, 4242, 424242, map[int16]string{1: "blah", 2: "thing"}, thrifttest.Numberz_EIGHT, thrifttest.UserId(24))
+	if err != nil {
+		t.Errorf("Unexpected error in TestMulti() call: %s", err)
+	}
+	if !reflect.DeepEqual(xxs, xxsret) {
+		t.Errorf("Unexpected TestMulti() result expected %#v, got %#v ", xxs, xxsret)
+	}
+
+	err = client.TestException(defaultCtx, "some")
+	if err == nil {
+		t.Errorf("Expecting exception in TestException() call")
+	}
+	if !reflect.DeepEqual(err, xcept) {
+		t.Errorf("Unexpected TestException() result expected %#v, got %#v ", xcept, err)
+	}
+
+	// TODO: connection is being closed on this
+	err = client.TestException(defaultCtx, "TException")
+	if err == nil {
+		t.Error("expected exception got nil")
+	} else if tex, ok := err.(thrift.TApplicationException); !ok {
+		t.Errorf("Unexpected TestException() result expected ApplicationError, got %T ", err)
+	} else if tex.TypeId() != thrift.INTERNAL_ERROR {
+		t.Errorf("expected internal_error got %v", tex.TypeId())
+	}
+
+	ign, err := client.TestMultiException(defaultCtx, "Xception", "ignoreme")
+	if ign != nil || err == nil {
+		t.Errorf("Expecting exception in TestMultiException() call")
+	}
+	if !reflect.DeepEqual(err, &thrifttest.Xception{ErrorCode: 1001, Message: "This is an Xception"}) {
+		t.Errorf("Unexpected TestMultiException() %#v ", err)
+	}
+
+	ign, err = client.TestMultiException(defaultCtx, "Xception2", "ignoreme")
+	if ign != nil || err == nil {
+		t.Errorf("Expecting exception in TestMultiException() call")
+	}
+	expecting := &thrifttest.Xception2{ErrorCode: 2002, StructThing: &thrifttest.Xtruct{StringThing: "This is an Xception2"}}
+
+	if !reflect.DeepEqual(err, expecting) {
+		t.Errorf("Unexpected TestMultiException() %#v ", err)
+	}
+
+	err = client.TestOneway(defaultCtx, 2)
+	if err != nil {
+		t.Errorf("Unexpected error in TestOneway() call: %s", err)
+	}
+
+	//Make sure the connection still alive
+	if err = client.TestVoid(defaultCtx); err != nil {
+		t.Errorf("Unexpected error in TestVoid() call: %s", err)
+	}
+}
diff --git a/test/go/src/common/context_test.go b/test/go/src/common/context_test.go
new file mode 100644
index 0000000..e64dbb9
--- /dev/null
+++ b/test/go/src/common/context_test.go
@@ -0,0 +1,98 @@
+/*
+ * 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 common
+
+import (
+	"context"
+	"fmt"
+	"net"
+	"net/http"
+	"net/url"
+	"os"
+	"syscall"
+	"testing"
+	"thrift"
+	"time"
+)
+
+type slowHttpHandler struct{}
+
+func (slowHttpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	time.Sleep(1 * time.Second)
+}
+
+func TestHttpContextTimeout(t *testing.T) {
+	certPath = "../../../keys"
+
+	unit := test_unit{"127.0.0.1", 9096, "", "http", "binary", false}
+
+	server := &http.Server{Addr: unit.host + fmt.Sprintf(":%d", unit.port), Handler: slowHttpHandler{}}
+	go server.ListenAndServe()
+
+	client, trans, err := StartClient(unit.host, unit.port, unit.domain_socket, unit.transport, unit.protocol, unit.ssl)
+	if err != nil {
+		t.Errorf("Unable to start client: %v", err)
+		return
+	}
+	defer trans.Close()
+
+	unwrapErr := func(err error) error {
+		for {
+			switch err.(type) {
+			case thrift.TTransportException:
+				err = err.(thrift.TTransportException).Err()
+			case *url.Error:
+				err = err.(*url.Error).Err
+			case *net.OpError:
+				err = err.(*net.OpError).Err
+			case *os.SyscallError:
+				err = err.(*os.SyscallError).Err
+			default:
+				return err
+			}
+		}
+	}
+
+	serverStartupDeadline := time.Now().Add(5 * time.Second)
+	for {
+		ctx, _ := context.WithTimeout(context.Background(), 50*time.Millisecond)
+		err = client.TestVoid(ctx)
+		err = unwrapErr(err)
+		if err != syscall.ECONNREFUSED || time.Now().After(serverStartupDeadline) {
+			break
+		}
+		time.Sleep(time.Millisecond)
+	}
+
+	if err == nil {
+		t.Errorf("Request completed (should have timed out)")
+		return
+	}
+
+	// We've got to switch on `err.Error()` here since go1.7 doesn't properly return
+	// `context.DeadlineExceeded` error and `http.errRequestCanceled` is not exported.
+	// See https://github.com/golang/go/issues/17711
+	switch err.Error() {
+	case context.DeadlineExceeded.Error(), "net/http: request canceled":
+		// Expected error
+	default:
+		t.Errorf("Unexpected error: %s", err)
+	}
+}
diff --git a/test/go/src/common/printing_handler.go b/test/go/src/common/printing_handler.go
new file mode 100644
index 0000000..2b22d0c
--- /dev/null
+++ b/test/go/src/common/printing_handler.go
@@ -0,0 +1,384 @@
+/*
+ * 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 common
+
+import (
+	"context"
+	"encoding/hex"
+	"errors"
+	"fmt"
+	. "gen/thrifttest"
+	"time"
+)
+
+var PrintingHandler = &printingHandler{}
+
+type printingHandler struct{}
+
+// Prints "testVoid()" and returns nothing.
+func (p *printingHandler) TestVoid(ctx context.Context) (err error) {
+	fmt.Println("testVoid()")
+	return nil
+}
+
+// Prints 'testString("%s")' with thing as '%s'
+// @param string thing - the string to print
+// @return string - returns the string 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestString(ctx context.Context, thing string) (r string, err error) {
+	fmt.Printf("testString(\"%s\")\n", thing)
+	return thing, nil
+}
+
+// Prints 'testBool("%t")' with thing as 'true' or 'false'
+// @param bool thing - the bool to print
+// @return bool - returns the bool 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestBool(ctx context.Context, thing bool) (r bool, err error) {
+	fmt.Printf("testBool(%t)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testByte("%d")' with thing as '%d'
+// @param byte thing - the byte to print
+// @return byte - returns the byte 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestByte(ctx context.Context, thing int8) (r int8, err error) {
+	fmt.Printf("testByte(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testI32("%d")' with thing as '%d'
+// @param i32 thing - the i32 to print
+// @return i32 - returns the i32 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestI32(ctx context.Context, thing int32) (r int32, err error) {
+	fmt.Printf("testI32(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testI64("%d")' with thing as '%d'
+// @param i64 thing - the i64 to print
+// @return i64 - returns the i64 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestI64(ctx context.Context, thing int64) (r int64, err error) {
+	fmt.Printf("testI64(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testDouble("%f")' with thing as '%f'
+// @param double thing - the double to print
+// @return double - returns the double 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestDouble(ctx context.Context, thing float64) (r float64, err error) {
+	fmt.Printf("testDouble(%f)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testBinary("%s")' where '%s' is a hex-formatted string of thing's data
+// @param []byte thing - the binary to print
+// @return []byte - returns the binary 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestBinary(ctx context.Context, thing []byte) (r []byte, err error) {
+	fmt.Printf("testBinary(%s)\n", hex.EncodeToString(thing))
+	return thing, nil
+}
+
+// Prints 'testStruct("{%s}")' where thing has been formatted into a string of comma separated values
+// @param Xtruct thing - the Xtruct to print
+// @return Xtruct - returns the Xtruct 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestStruct(ctx context.Context, thing *Xtruct) (r *Xtruct, err error) {
+	fmt.Printf("testStruct({\"%s\", %d, %d, %d})\n", thing.StringThing, thing.ByteThing, thing.I32Thing, thing.I64Thing)
+	return thing, err
+}
+
+// Prints 'testNest("{%s}")' where thing has been formatted into a string of the nested struct
+// @param Xtruct2 thing - the Xtruct2 to print
+// @return Xtruct2 - returns the Xtruct2 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestNest(ctx context.Context, nest *Xtruct2) (r *Xtruct2, err error) {
+	thing := nest.StructThing
+	fmt.Printf("testNest({%d, {\"%s\", %d, %d, %d}, %d})\n", nest.ByteThing, thing.StringThing, thing.ByteThing, thing.I32Thing, thing.I64Thing, nest.I32Thing)
+	return nest, nil
+}
+
+// Prints 'testMap("{%s")' where thing has been formatted into a string of  'key => value' pairs
+//  separated by commas and new lines
+// @param map<i32,i32> thing - the map<i32,i32> to print
+// @return map<i32,i32> - returns the map<i32,i32> 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestMap(ctx context.Context, thing map[int32]int32) (r map[int32]int32, err error) {
+	fmt.Printf("testMap({")
+	first := true
+	for k, v := range thing {
+		if first {
+			first = false
+		} else {
+			fmt.Printf(", ")
+		}
+		fmt.Printf("%d => %d", k, v)
+	}
+	fmt.Printf("})\n")
+	return thing, nil
+}
+
+// Prints 'testStringMap("{%s}")' where thing has been formatted into a string of  'key => value' pairs
+//  separated by commas and new lines
+// @param map<string,string> thing - the map<string,string> to print
+// @return map<string,string> - returns the map<string,string> 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestStringMap(ctx context.Context, thing map[string]string) (r map[string]string, err error) {
+	fmt.Printf("testStringMap({")
+	first := true
+	for k, v := range thing {
+		if first {
+			first = false
+		} else {
+			fmt.Printf(", ")
+		}
+		fmt.Printf("%s => %s", k, v)
+	}
+	fmt.Printf("})\n")
+	return thing, nil
+}
+
+// Prints 'testSet("{%s}")' where thing has been formatted into a string of  values
+//  separated by commas and new lines
+// @param set<i32> thing - the set<i32> to print
+// @return set<i32> - returns the set<i32> 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestSet(ctx context.Context, thing []int32) (r []int32, err error) {
+	fmt.Printf("testSet({")
+	first := true
+	for k, _ := range thing {
+		if first {
+			first = false
+		} else {
+			fmt.Printf(", ")
+		}
+		fmt.Printf("%d", k)
+	}
+	fmt.Printf("})\n")
+	return thing, nil
+}
+
+// Prints 'testList("{%s}")' where thing has been formatted into a string of  values
+//  separated by commas and new lines
+// @param list<i32> thing - the list<i32> to print
+// @return list<i32> - returns the list<i32> 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestList(ctx context.Context, thing []int32) (r []int32, err error) {
+	fmt.Printf("testList({")
+	for i, v := range thing {
+		if i != 0 {
+			fmt.Printf(", ")
+		}
+		fmt.Printf("%d", v)
+	}
+	fmt.Printf("})\n")
+	return thing, nil
+}
+
+// Prints 'testEnum("%d")' where thing has been formatted into it's numeric value
+// @param Numberz thing - the Numberz to print
+// @return Numberz - returns the Numberz 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestEnum(ctx context.Context, thing Numberz) (r Numberz, err error) {
+	fmt.Printf("testEnum(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testTypedef("%d")' with thing as '%d'
+// @param UserId thing - the UserId to print
+// @return UserId - returns the UserId 'thing'
+//
+// Parameters:
+//  - Thing
+func (p *printingHandler) TestTypedef(ctx context.Context, thing UserId) (r UserId, err error) {
+	fmt.Printf("testTypedef(%d)\n", thing)
+	return thing, nil
+}
+
+// Prints 'testMapMap("%d")' with hello as '%d'
+// @param i32 hello - the i32 to print
+// @return map<i32,map<i32,i32>> - returns a dictionary with these values:
+//   {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2 => 2, 3 => 3, 4 => 4, }, }
+//
+// Parameters:
+//  - Hello
+func (p *printingHandler) TestMapMap(ctx context.Context, hello int32) (r map[int32]map[int32]int32, err error) {
+	fmt.Printf("testMapMap(%d)\n", hello)
+
+	r = map[int32]map[int32]int32{
+		-4: map[int32]int32{-4: -4, -3: -3, -2: -2, -1: -1},
+		4:  map[int32]int32{4: 4, 3: 3, 2: 2, 1: 1},
+	}
+	return
+}
+
+// So you think you've got this all worked, out eh?
+//
+// Creates a the returned map with these values and prints it out:
+//   { 1 => { 2 => argument,
+//            3 => argument,
+//          },
+//     2 => { 6 => <empty Insanity struct>, },
+//   }
+// @return map<UserId, map<Numberz,Insanity>> - a map with the above values
+//
+// Parameters:
+//  - Argument
+func (p *printingHandler) TestInsanity(ctx context.Context, argument *Insanity) (r map[UserId]map[Numberz]*Insanity, err error) {
+	fmt.Printf("testInsanity()\n")
+	r = make(map[UserId]map[Numberz]*Insanity)
+	r[1] = map[Numberz]*Insanity{
+		2: argument,
+		3: argument,
+	}
+	r[2] = map[Numberz]*Insanity{
+		6: NewInsanity(),
+	}
+	return
+}
+
+// Prints 'testMulti()'
+// @param byte arg0 -
+// @param i32 arg1 -
+// @param i64 arg2 -
+// @param map<i16, string> arg3 -
+// @param Numberz arg4 -
+// @param UserId arg5 -
+// @return Xtruct - returns an Xtruct with StringThing = "Hello2, ByteThing = arg0, I32Thing = arg1
+//    and I64Thing = arg2
+//
+// Parameters:
+//  - Arg0
+//  - Arg1
+//  - Arg2
+//  - Arg3
+//  - Arg4
+//  - Arg5
+func (p *printingHandler) TestMulti(ctx context.Context, arg0 int8, arg1 int32, arg2 int64, arg3 map[int16]string, arg4 Numberz, arg5 UserId) (r *Xtruct, err error) {
+	fmt.Printf("testMulti()\n")
+	r = NewXtruct()
+
+	r.StringThing = "Hello2"
+	r.ByteThing = arg0
+	r.I32Thing = arg1
+	r.I64Thing = arg2
+	return
+}
+
+// Print 'testException(%s)' with arg as '%s'
+// @param string arg - a string indication what type of exception to throw
+// if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
+// elsen if arg == "TException" throw TException
+// else do not throw anything
+//
+// Parameters:
+//  - Arg
+func (p *printingHandler) TestException(ctx context.Context, arg string) (err error) {
+	fmt.Printf("testException(%s)\n", arg)
+	switch arg {
+	case "Xception":
+		e := NewXception()
+		e.ErrorCode = 1001
+		e.Message = arg
+		return e
+	case "TException":
+		return errors.New("Just TException")
+	}
+	return
+}
+
+// Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s'
+// @param string arg - a string indication what type of exception to throw
+// if arg0 == "Xception" throw Xception with errorCode = 1001 and message = "This is an Xception"
+// elsen if arg0 == "Xception2" throw Xception2 with errorCode = 2002 and message = "This is an Xception2"
+// else do not throw anything
+// @return Xtruct - an Xtruct with StringThing = arg1
+//
+// Parameters:
+//  - Arg0
+//  - Arg1
+func (p *printingHandler) TestMultiException(ctx context.Context, arg0 string, arg1 string) (r *Xtruct, err error) {
+	fmt.Printf("testMultiException(%s, %s)\n", arg0, arg1)
+	switch arg0 {
+
+	case "Xception":
+		e := NewXception()
+		e.ErrorCode = 1001
+		e.Message = "This is an Xception"
+		return nil, e
+	case "Xception2":
+		e := NewXception2()
+		e.ErrorCode = 2002
+		e.StructThing = NewXtruct()
+		e.StructThing.StringThing = "This is an Xception2"
+		return nil, e
+	default:
+		r = NewXtruct()
+		r.StringThing = arg1
+		return
+	}
+}
+
+// Print 'testOneway(%d): Sleeping...' with secondsToSleep as '%d'
+// sleep 'secondsToSleep'
+// Print 'testOneway(%d): done sleeping!' with secondsToSleep as '%d'
+// @param i32 secondsToSleep - the number of seconds to sleep
+//
+// Parameters:
+//  - SecondsToSleep
+func (p *printingHandler) TestOneway(ctx context.Context, secondsToSleep int32) (err error) {
+	fmt.Printf("testOneway(%d): Sleeping...\n", secondsToSleep)
+	time.Sleep(time.Second * time.Duration(secondsToSleep))
+	fmt.Printf("testOneway(%d): done sleeping!\n", secondsToSleep)
+	return
+}
diff --git a/test/go/src/common/server.go b/test/go/src/common/server.go
new file mode 100644
index 0000000..5ac4400
--- /dev/null
+++ b/test/go/src/common/server.go
@@ -0,0 +1,111 @@
+/*
+ * 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 common
+
+import (
+	"compress/zlib"
+	"crypto/tls"
+	"flag"
+	"fmt"
+	"gen/thrifttest"
+	"thrift"
+)
+
+var (
+	debugServerProtocol bool
+	certPath            string
+)
+
+func init() {
+	flag.BoolVar(&debugServerProtocol, "debug_server_protocol", false, "turn server protocol trace on")
+}
+
+func GetServerParams(
+	host string,
+	port int64,
+	domain_socket string,
+	transport string,
+	protocol string,
+	ssl bool,
+	certPath string,
+	handler thrifttest.ThriftTest) (thrift.TProcessor, thrift.TServerTransport, thrift.TTransportFactory, thrift.TProtocolFactory, error) {
+
+	var err error
+	hostPort := fmt.Sprintf("%s:%d", host, port)
+
+	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:
+		return nil, nil, nil, nil, fmt.Errorf("Invalid protocol specified %s", protocol)
+	}
+	if debugServerProtocol {
+		protocolFactory = thrift.NewTDebugProtocolFactory(protocolFactory, "server:")
+	}
+
+	var serverTransport thrift.TServerTransport
+	if ssl {
+		cfg := new(tls.Config)
+		if cert, err := tls.LoadX509KeyPair(certPath+"/server.crt", certPath+"/server.key"); err != nil {
+			return nil, nil, nil, nil, err
+		} else {
+			cfg.Certificates = append(cfg.Certificates, cert)
+		}
+		serverTransport, err = thrift.NewTSSLServerSocket(hostPort, cfg)
+	} else {
+		if domain_socket != "" {
+			serverTransport, err = thrift.NewTServerSocket(domain_socket)
+		} else {
+			serverTransport, err = thrift.NewTServerSocket(hostPort)
+		}
+	}
+	if err != nil {
+		return nil, nil, nil, nil, err
+	}
+
+	var transportFactory thrift.TTransportFactory
+
+	switch transport {
+	case "http":
+		// there is no such factory, and we don't need any
+		transportFactory = nil
+	case "framed":
+		transportFactory = thrift.NewTTransportFactory()
+		transportFactory = thrift.NewTFramedTransportFactory(transportFactory)
+	case "buffered":
+		transportFactory = thrift.NewTBufferedTransportFactory(8192)
+	case "zlib":
+		transportFactory = thrift.NewTZlibTransportFactory(zlib.BestCompression)
+	case "":
+		transportFactory = thrift.NewTTransportFactory()
+	default:
+		return nil, nil, nil, nil, fmt.Errorf("Invalid transport specified %s", transport)
+	}
+	processor := thrifttest.NewThriftTestProcessor(handler)
+
+	return processor, serverTransport, transportFactory, protocolFactory, nil
+}
diff --git a/test/go/src/common/simple_handler.go b/test/go/src/common/simple_handler.go
new file mode 100644
index 0000000..0c9463d
--- /dev/null
+++ b/test/go/src/common/simple_handler.go
@@ -0,0 +1,155 @@
+/*
+ * 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 common
+
+import (
+	"errors"
+	. "gen/thrifttest"
+	"time"
+)
+
+var SimpleHandler = &simpleHandler{}
+
+type simpleHandler struct{}
+
+func (p *simpleHandler) TestVoid() (err error) {
+	return nil
+}
+
+func (p *simpleHandler) TestString(thing string) (r string, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestBool(thing []byte) (r []byte, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestByte(thing int8) (r int8, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestI32(thing int32) (r int32, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestI64(thing int64) (r int64, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestDouble(thing float64) (r float64, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestBinary(thing []byte) (r []byte, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestStruct(thing *Xtruct) (r *Xtruct, err error) {
+	return r, err
+}
+
+func (p *simpleHandler) TestNest(nest *Xtruct2) (r *Xtruct2, err error) {
+	return nest, nil
+}
+
+func (p *simpleHandler) TestMap(thing map[int32]int32) (r map[int32]int32, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestStringMap(thing map[string]string) (r map[string]string, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestSet(thing []int32) (r []int32, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestList(thing []int32) (r []int32, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestEnum(thing Numberz) (r Numberz, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestTypedef(thing UserId) (r UserId, err error) {
+	return thing, nil
+}
+
+func (p *simpleHandler) TestMapMap(hello int32) (r map[int32]map[int32]int32, err error) {
+
+	r = map[int32]map[int32]int32{
+		-4: map[int32]int32{-4: -4, -3: -3, -2: -2, -1: -1},
+		4:  map[int32]int32{4: 4, 3: 3, 2: 2, 1: 1},
+	}
+	return
+}
+
+func (p *simpleHandler) TestInsanity(argument *Insanity) (r map[UserId]map[Numberz]*Insanity, err error) {
+	return nil, errors.New("No Insanity")
+}
+
+func (p *simpleHandler) TestMulti(arg0 int8, arg1 int32, arg2 int64, arg3 map[int16]string, arg4 Numberz, arg5 UserId) (r *Xtruct, err error) {
+	r = NewXtruct()
+
+	r.StringThing = "Hello2"
+	r.ByteThing = arg0
+	r.I32Thing = arg1
+	r.I64Thing = arg2
+	return
+}
+
+func (p *simpleHandler) TestException(arg string) (err error) {
+	switch arg {
+	case "Xception":
+		e := NewXception()
+		e.ErrorCode = 1001
+		e.Message = arg
+		return e
+	case "TException":
+		return errors.New("Just TException")
+	}
+	return
+}
+
+func (p *simpleHandler) TestMultiException(arg0 string, arg1 string) (r *Xtruct, err error) {
+	switch arg0 {
+
+	case "Xception":
+		e := NewXception()
+		e.ErrorCode = 1001
+		e.Message = "This is an Xception"
+		return nil, e
+	case "Xception2":
+		e := NewXception2()
+		e.ErrorCode = 2002
+		e.StructThing.StringThing = "This is an Xception2"
+		return nil, e
+	default:
+		r = NewXtruct()
+		r.StringThing = arg1
+		return
+	}
+}
+
+func (p *simpleHandler) TestOneway(secondsToSleep int32) (err error) {
+	time.Sleep(time.Second * time.Duration(secondsToSleep))
+	return
+}
diff --git a/test/haxe/Makefile.am b/test/haxe/Makefile.am
new file mode 100644
index 0000000..6c0483e
--- /dev/null
+++ b/test/haxe/Makefile.am
@@ -0,0 +1,104 @@
+#
+# 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.
+#
+
+THRIFTCMD = $(THRIFT) --gen haxe -r
+THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift
+
+BIN_CPP = bin/Main-debug
+BIN_PHP = bin/php/Main-debug.php
+BIN_PHP_WEB = bin/php-web-server/Main-debug.php
+
+gen-haxe/thrift/test/ThriftTest.hx: $(THRIFTTEST)
+	$(THRIFTCMD) $(THRIFTTEST)
+
+all-local: $(BIN_CPP) $(BIN_PHP) $(BIN_PHP_WEB)
+
+$(BIN_CPP): \
+		src/*.hx \
+		../../lib/haxe/src/org/apache/thrift/**/*.hx \
+		gen-haxe/thrift/test/ThriftTest.hx
+	$(HAXE) --cwd .  cpp.hxml
+
+$(BIN_PHP): \
+		src/*.hx \
+		../../lib/haxe/src/org/apache/thrift/**/*.hx \
+		gen-haxe/thrift/test/ThriftTest.hx
+	$(HAXE) --cwd .  php.hxml
+
+$(BIN_PHP_WEB): \
+		src/*.hx \
+		../../lib/haxe/src/org/apache/thrift/**/*.hx \
+		gen-haxe/thrift/test/ThriftTest.hx
+	$(HAXE) --cwd .  php-web-server.hxml
+
+
+
+#TODO: other haxe targets
+#    $(HAXE)  --cwd .  csharp
+#    $(HAXE)  --cwd .  flash
+#    $(HAXE)  --cwd .  java
+#    $(HAXE)  --cwd .  javascript
+#    $(HAXE)  --cwd .  neko
+#    $(HAXE)  --cwd .  python  # needs Haxe 3.2.0
+
+
+clean-local:
+	$(RM) -r gen-haxe bin
+
+.NOTPARALLEL:
+
+check: check_cpp \
+	check_php \
+	check_php_web 
+
+check_cpp: $(BIN_CPP) 
+	timeout 20 $(BIN_CPP) server &
+	sleep 1
+	$(BIN_CPP) client
+	sleep 10
+
+check_php: $(BIN_PHP) 
+	timeout 20 php -f $(BIN_PHP) server &
+	sleep 1
+	php -f $(BIN_PHP) client
+	sleep 10
+
+check_php_web: $(BIN_PHP_WEB) $(BIN_CPP)
+	timeout 20 php -S 127.0.0.1:9090 router.php &
+	sleep 1
+	$(BIN_CPP) client --transport http
+	sleep 10
+
+
+EXTRA_DIST = \
+	src \
+	cpp.hxml \
+	csharp.hxml \
+	flash.hxml \
+	java.hxml \
+	javascript.hxml \
+	neko.hxml \
+	php.hxml \
+	python.hxml \
+	router.php \
+	project.hide \
+	php-web-server.hxml \
+	TestClientServer.hxproj \
+	make_all.bat \
+	make_all.sh
diff --git a/test/haxe/TestClientServer.hxproj b/test/haxe/TestClientServer.hxproj
new file mode 100644
index 0000000..6696d80
--- /dev/null
+++ b/test/haxe/TestClientServer.hxproj
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project version="2">
+  <!-- Output SWF options -->
+  <output>
+    <movie outputType="Application" />
+    <movie input="" />
+    <movie path="bin/TestClientServer" />
+    <movie fps="30" />
+    <movie width="800" />
+    <movie height="600" />
+    <movie version="1" />
+    <movie minorVersion="0" />
+    <movie platform="C++" />
+    <movie background="#FFFFFF" />
+  </output>
+  <!-- Other classes to be compiled into your SWF -->
+  <classpaths>
+    <class path="src" />
+    <class path="gen-haxe" />
+    <class path="../../lib/haxe/src" />
+  </classpaths>
+  <!-- Build options -->
+  <build>
+    <option directives="" />
+    <option flashStrict="False" />
+    <option noInlineOnDebug="False" />
+    <option mainClass="Main" />
+    <option enabledebug="False" />
+    <option additional="" />
+  </build>
+  <!-- haxelib libraries -->
+  <haxelib>
+    <!-- example: <library name="..." /> -->
+  </haxelib>
+  <!-- Class files to compile (other referenced classes will automatically be included) -->
+  <compileTargets>
+    <!-- example: <compile path="..." /> -->
+  </compileTargets>
+  <!-- Paths to exclude from the Project Explorer tree -->
+  <hiddenPaths>
+    <hidden path="obj" />
+    <hidden path="cpp.hxml" />
+    <hidden path="csharp.hxml" />
+    <hidden path="flash.hxml" />
+    <hidden path="java.hxml" />
+    <hidden path="javascript.hxml" />
+    <hidden path="make_all.bat" />
+    <hidden path="make_all.sh" />
+    <hidden path="Makefile.am" />
+    <hidden path="neko.hxml" />
+    <hidden path="php.hxml" />
+    <hidden path="project.hide" />
+    <hidden path="python.hxml" />
+  </hiddenPaths>
+  <!-- Executed before build -->
+  <preBuildCommand>thrift -r -gen haxe  ../ThriftTest.thrift</preBuildCommand>
+  <!-- Executed after build -->
+  <postBuildCommand alwaysRun="False" />
+  <!-- Other project options -->
+  <options>
+    <option showHiddenPaths="False" />
+    <option testMovie="Unknown" />
+    <option testMovieCommand="" />
+  </options>
+  <!-- Plugin storage -->
+  <storage />
+</project>
\ No newline at end of file
diff --git a/test/haxe/cpp.hxml b/test/haxe/cpp.hxml
new file mode 100644
index 0000000..6adb52d
--- /dev/null
+++ b/test/haxe/cpp.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#CPP target
+-cpp bin
+
+#To produce 64 bit binaries the file should define the HXCPP_M64 compile variable:
+#-D HXCPP_M64
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/csharp.hxml b/test/haxe/csharp.hxml
new file mode 100644
index 0000000..295c017
--- /dev/null
+++ b/test/haxe/csharp.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#CSHARP target
+-cs bin/Tutorial.exe
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/flash.hxml b/test/haxe/flash.hxml
new file mode 100644
index 0000000..a1f0568
--- /dev/null
+++ b/test/haxe/flash.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Flash target
+-swf bin/Tutorial.swf
+
+#Add debug information
+-debug
+
+# we need some goodies from sys.net
+# --macro allowPackage("sys")
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/java.hxml b/test/haxe/java.hxml
new file mode 100644
index 0000000..c615565
--- /dev/null
+++ b/test/haxe/java.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src 
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Java target
+-java bin/Tutorial.jar
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/javascript.hxml b/test/haxe/javascript.hxml
new file mode 100644
index 0000000..b2b3876
--- /dev/null
+++ b/test/haxe/javascript.hxml
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#JavaScript target
+-js bin/Tutorial.js
+
+#You can use -D source-map-content (requires Haxe 3.1+) to have the .hx 
+#files directly embedded into the map file, this way you only have to 
+#upload it, and it will be always in sync with the compiled .js even if 
+#you modify your .hx files.
+-D source-map-content
+
+#Generate source map and add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/make_all.bat b/test/haxe/make_all.bat
new file mode 100644
index 0000000..eaeba89
--- /dev/null
+++ b/test/haxe/make_all.bat
@@ -0,0 +1,68 @@
+@echo off
+rem /*
+rem  * Licensed to the Apache Software Foundation (ASF) under one
+rem  * or more contributor license agreements. See the NOTICE file
+rem  * distributed with this work for additional information
+rem  * regarding copyright ownership. The ASF licenses this file
+rem  * to you under the Apache License, Version 2.0 (the
+rem  * "License"); you may not use this file except in compliance
+rem  * with the License. You may obtain a copy of the License at
+rem  *
+rem  *   http://www.apache.org/licenses/LICENSE-2.0
+rem  *
+rem  * Unless required by applicable law or agreed to in writing,
+rem  * software distributed under the License is distributed on an
+rem  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem  * KIND, either express or implied. See the License for the
+rem  * specific language governing permissions and limitations
+rem  * under the License.
+rem  */
+
+setlocal
+if "%HOMEDRIVE%"=="" goto MISSINGVARS
+if "%HOMEPATH%"=="" goto MISSINGVARS
+if "%HAXEPATH%"=="" goto NOTINSTALLED
+
+set path=%HAXEPATH%;%HAXEPATH%\..\neko;%path%
+
+rem # invoke Thrift comnpiler
+thrift -r -gen haxe   ..\ThriftTest.thrift
+if errorlevel 1 goto STOP
+
+rem # invoke Haxe compiler for all targets
+for %%a in (*.hxml) do (
+	rem * filter Python, as it is not supported by Haxe 3.1.3 (but will be in 3.1.4)
+	if not "%%a"=="python.hxml" (
+		echo --------------------------
+		echo Building %%a ...
+		echo --------------------------
+		haxe  --cwd .  %%a
+	)
+)
+
+
+echo.
+echo done.
+pause
+goto eof
+
+:NOTINSTALLED
+echo FATAL: Either Haxe is not installed, or the HAXEPATH variable is not set.
+pause
+goto eof
+
+:MISSINGVARS
+echo FATAL: Unable to locate home folder.
+echo.
+echo Both HOMEDRIVE and HOMEPATH need to be set to point to your Home folder.
+echo The current values are:
+echo HOMEDRIVE=%HOMEDRIVE%
+echo HOMEPATH=%HOMEPATH%
+pause
+goto eof
+
+:STOP
+pause
+goto eof
+
+:eof
diff --git a/test/haxe/make_all.sh b/test/haxe/make_all.sh
new file mode 100755
index 0000000..eb2c9c2
--- /dev/null
+++ b/test/haxe/make_all.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# 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.
+#
+
+# invoke Thrift comnpiler
+../../compiler/cpp/thrift -r -gen haxe  ../ThriftTest.thrift
+
+# output folder
+if [ ! -d bin ]; then
+  mkdir  bin
+fi
+
+# invoke Haxe compiler
+for target in *.hxml; do 
+  echo --------------------------
+  echo Building ${target} ...
+  echo --------------------------
+  if [ ! -d bin/${target} ]; then
+    mkdir  bin/${target}
+  fi
+  haxe  --cwd .  ${target} 
+done
+
+
+#eof
diff --git a/test/haxe/neko.hxml b/test/haxe/neko.hxml
new file mode 100644
index 0000000..6161f69
--- /dev/null
+++ b/test/haxe/neko.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#neko target
+-neko bin/Tutorial.n
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/php-web-server.hxml b/test/haxe/php-web-server.hxml
new file mode 100644
index 0000000..395a852
--- /dev/null
+++ b/test/haxe/php-web-server.hxml
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#PHP target
+-php bin/php-web-server/
+--php-front Main-debug.php
+
+#defines
+-D phpwebserver
+
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
diff --git a/test/haxe/php.hxml b/test/haxe/php.hxml
new file mode 100644
index 0000000..9651898
--- /dev/null
+++ b/test/haxe/php.hxml
@@ -0,0 +1,40 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#PHP target
+-php bin/php/
+--php-front Main-debug.php
+
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
diff --git a/test/haxe/project.hide b/test/haxe/project.hide
new file mode 100644
index 0000000..a1c09ba
--- /dev/null
+++ b/test/haxe/project.hide
@@ -0,0 +1,76 @@
+{
+     "type" : 0
+    ,"target" : 4
+    ,"name" : "Apache Thrift cross-platform test client/server"
+    ,"main" : null
+    ,"projectPackage" : ""
+    ,"company" : "Apache Software Foundation (ASF)"
+    ,"license" : "Apache License, Version 2.0"
+    ,"url" : "http://www.apache.org/licenses/LICENSE-2.0"
+    ,"targetData" : [
+         {
+             "pathToHxml" : "flash.hxml"
+            ,"runActionType" : 1
+            ,"runActionText" : "bin/Tutorial.swf"
+        }
+        ,{
+             "pathToHxml" : "javascript.hxml"
+            ,"runActionType" : 1
+            ,"runActionText" : "bin\\index.html"
+        }
+        ,{
+             "pathToHxml" : "neko.hxml"
+            ,"runActionType" : 2
+            ,"runActionText" : "neko bin/Tutorial.n"
+        }
+        ,{
+             "pathToHxml" : "php.hxml"
+        }
+        ,{
+             "pathToHxml" : "cpp.hxml"
+            ,"runActionType" : 2
+            ,"runActionText" : "bin/Main-debug.exe  client --protocol json"
+        }
+        ,{
+             "pathToHxml" : "java.hxml"
+        }
+        ,{
+             "pathToHxml" : "csharp.hxml"
+        }
+        ,{
+             "pathToHxml" : "python.hxml"
+            ,"runActionType" : 2
+            ,"runActionText" : "python bin/Tutorial.py"
+        }
+    ]
+    ,"files" : [
+         {
+             "path" : "src\\TestClient.hx"
+            ,"useTabs" : true
+            ,"indentSize" : 4
+            ,"foldedRegions" : [
+
+            ]
+            ,"activeLine" : 188
+        }
+        ,{
+             "path" : "src\\TestServer.hx"
+            ,"useTabs" : true
+            ,"indentSize" : 4
+            ,"foldedRegions" : [
+
+            ]
+            ,"activeLine" : 88
+        }
+    ]
+    ,"activeFile" : "src\\TestClient.hx"
+    ,"openFLTarget" : null
+    ,"openFLBuildMode" : "Debug"
+    ,"runActionType" : null
+    ,"runActionText" : null
+    ,"buildActionCommand" : null
+    ,"hiddenItems" : [
+
+    ]
+    ,"showHiddenItems" : false
+}
\ No newline at end of file
diff --git a/test/haxe/python.hxml b/test/haxe/python.hxml
new file mode 100644
index 0000000..f2c19fa
--- /dev/null
+++ b/test/haxe/python.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Python target
+-python bin/Tutorial.py
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/test/haxe/router.php b/test/haxe/router.php
new file mode 100644
index 0000000..e34135c
--- /dev/null
+++ b/test/haxe/router.php
@@ -0,0 +1,31 @@
+<?php
+/*
+ * 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
+ */
+
+
+
+//router file to run testing web server
+
+//set_time_limit(1);
+
+require_once  dirname(__FILE__) . '/bin/php-web-server/Main-debug.php';
+
+
diff --git a/test/haxe/src/Arguments.hx b/test/haxe/src/Arguments.hx
new file mode 100644
index 0000000..cc10749
--- /dev/null
+++ b/test/haxe/src/Arguments.hx
@@ -0,0 +1,335 @@
+/*
+ * 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;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+import haxe.io.Path;
+
+using StringTools;
+
+
+enum ProtocolType {
+    binary;
+    json;
+    compact;
+}
+
+enum EndpointTransport {
+    socket;
+    http;
+}
+
+enum ServerType {
+    simple;
+    /*
+    threadpool;
+    threaded;
+    nonblocking;
+    */
+}
+
+
+class Arguments
+{
+    public var printHelpOnly(default,null) : Bool = false;
+
+    public var server(default,null) : Bool = false;
+    public var servertype(default,null) : ServerType = simple;
+
+    public var host(default,null) : String = "localhost";
+    public var port(default,null) : Int = 9090;
+
+    public var protocol(default,null) : ProtocolType = binary;
+    public var transport(default,null) : EndpointTransport = socket;
+    public var framed(default,null) : Bool = false;
+    public var buffered(default,null) : Bool = false;
+
+    public var numIterations(default,null) : Int = 1;
+    public var numThreads(default,null) : Int = 1;
+    public var skipSpeedTest(default,null) : Bool = false;
+
+
+    public function new() {
+        #if sys
+          #if !phpwebserver
+          try {
+              ParseArgs();
+          } catch (e : String) {
+            trace(GetHelp());
+            throw e;
+          }
+          #else
+            //forcing server
+            server = true;
+            transport = http;
+          #end
+        #else
+        trace("WN: Platform does not support program arguments, using defaults.");
+        #end
+    }
+
+    #if sys
+
+    private static function GetHelp() : String {
+        var sProg = Path.withoutDirectory( Sys.executablePath());
+        return "\n"
+            +sProg+"  [client|server]  [options]\n"
+            +"\n"
+            +"Modus: Either client or server, the default is client.\n"
+            +"\n"
+            +"Common options:\n"
+            +"  -h [ --help ]               produce help message\n"
+            +"  --port arg (=9090)          Port number to listen / connect to\n"
+            /* not supported yet
+            +"  --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)\n"
+            +"  --named-pipe arg            Windows Named Pipe (e.g. MyThriftPipe)\n"
+            */
+            +"  --protocol arg (=binary)    protocol: binary, compact, json\n"
+            /* not supported yet
+            +"  --ssl                       Encrypted Transport using SSL\n"
+            */
+            +"\n"
+            +"Server only options:\n"
+            +"  --transport arg (=sockets)  Transport: buffered, framed, http, anonpipe\n"
+            /* not supported yet
+            +"  --processor-events          processor-events\n"
+            +"  --server-type arg (=simple) type of server, \"simple\", \"thread-pool\", \n"
+            +"                              \"threaded\", or \"nonblocking\"\n"
+            +"  -n [ --workers ] arg (=4)   Number of thread pools workers. Only valid for \n"
+            +"                              thread-pool server type\n"
+            */
+            +"\n"
+            +"Client only options:\n"
+            +"  --host arg (=localhost)     Host to connect\n"
+            +"  --transport arg (=sockets)  Transport: buffered, framed, http, evhttp\n"
+            /* not supported yet
+            +"  --anon-pipes hRead hWrite   Windows Anonymous Pipes pair (handles)\n"
+            */
+            +"  -n [ --testloops ] arg (=1) Number of Tests\n"
+            +"  -t [ --threads ] arg (=1)   Number of Test threads\n"
+            +"  --skip-speed-test           Skip the speed test\n"
+            +"\n"
+            +"All arguments are optional.\n"
+            ;
+    }
+
+
+    private function ParseArgs() : Void {
+
+        var args = Sys.args().copy();
+        if( (args == null) || (args.length <= 0)) {
+            server = false;
+            numThreads = 1;
+            return;
+        }
+
+        var arg = args.shift();
+        if ( arg == "client") {
+            server = false;
+            numThreads = 1;
+        }
+        else if ( arg == "server") {
+            server = true;
+            numThreads = 4;
+        }
+        else if ( (arg == "-h") || (arg == "--help")) {
+            // -h [ --help ]               produce help message
+            Sys.println( GetHelp());
+            printHelpOnly = true;
+            return;
+        }
+        else {
+            throw "First argument must be 'server' or 'client'";
+        }
+
+
+        while( args.length > 0) {
+            arg = args.shift();
+
+            if ( (arg == "-h") || (arg == "--help")) {
+                // -h [ --help ]               produce help message
+                Sys.println( GetHelp());
+                printHelpOnly = true;
+                return;
+            }
+            else if (arg == "--port") {
+                // --port arg (=9090)          Port number to listen
+                arg = args.shift();
+                var tmp = Std.parseInt(arg);
+                if( tmp != null) {
+                    port = tmp;
+                } else {
+                    throw "Invalid port number "+arg;
+                }
+            }
+            else if (arg == "--domain-socket") {
+                //   --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)
+                throw "domain sockets not supported yet";
+            }
+            else if (arg == "--named-pipe") {
+                //   --named-pipe arg            Windows Named Pipe (e.g. MyThriftPipe)
+                throw "named pipes not supported yet";
+            }
+            else if (arg == "--protocol") {
+                // --protocol arg (=binary)    protocol: binary, compact, json
+                arg = args.shift();
+                if( arg == "binary") {
+                    protocol = binary;
+                } else if( arg == "compact") {
+                    protocol = compact;
+                } else if( arg == "json") {
+                    protocol = json;
+                } else {
+                    InvalidArg(arg);
+                }
+            }
+            else if (arg == "--ssl") {
+                // --ssl                       Encrypted Transport using SSL
+                throw "SSL not supported yet";
+            }
+            else {
+                //Server only options:
+                if( server) {
+                    ParseServerArgument( arg, args);
+                } else {
+                    ParseClientArgument( arg, args);
+                }
+            }
+        }
+    }
+
+
+    private function ParseServerArgument( arg : String, args : Array<String>) : Void {
+        if (arg == "--transport") {
+            //  --transport arg (=sockets)  Transport: buffered, framed, http, anonpipe
+            arg = args.shift();
+            if( arg == "buffered") {
+                buffered = true;
+            } else if( arg == "framed") {
+                framed = true;
+            } else if( arg == "http") {
+                transport = http;
+            } else if( arg == "anonpipe") {
+                throw "Anon pipes transport not supported yet";
+            } else {
+                InvalidArg(arg);
+            }
+        }
+        else if (arg == "--processor-events") {
+            throw "Processor events not supported yet";
+        }
+        else if (arg == "--server-type") {
+            //  --server-type arg (=simple) type of server,
+            // one of "simple", "thread-pool", "threaded", "nonblocking"
+            arg = args.shift();
+            if( arg == "simple") {
+                servertype = simple;
+            } else if( arg == "thread-pool") {
+                throw arg+" server not supported yet";
+            } else if( arg == "threaded") {
+                throw arg+" server not supported yet";
+            } else if( arg == "nonblocking") {
+                throw arg+" server not supported yet";
+            } else {
+                InvalidArg(arg);
+            }
+        }
+        else if ((arg == "-n") || (arg == "--workers")) {
+            //  -n [ --workers ] arg (=4)   Number of thread pools workers. Only valid for
+            //                              thread-pool server type
+            arg = args.shift();
+            var tmp = Std.parseInt(arg);
+            if( tmp != null) {
+                numThreads = tmp;
+            } else{
+                throw "Invalid number "+arg;
+            }
+        }
+        else {
+            InvalidArg(arg);
+        }
+    }
+
+
+    private function ParseClientArgument( arg : String, args : Array<String>) : Void {
+        if (arg == "--host") {
+            //  --host arg (=localhost)     Host to connect
+            host = args.shift();
+        }
+        else if (arg == "--transport") {
+            //  --transport arg (=sockets)  Transport: buffered, framed, http, evhttp
+            arg = args.shift();
+            if( arg == "buffered") {
+                buffered = true;
+            } else if( arg == "framed") {
+                framed = true;
+            } else if( arg == "http") {
+                transport = http;
+            } else if( arg == "evhttp") {
+                throw "evhttp transport not supported yet";
+            } else {
+                InvalidArg(arg);
+            }
+        }
+        else if (arg == "--anon-pipes") {
+            //  --anon-pipes hRead hWrite   Windows Anonymous Pipes pair (handles)
+            throw "Anon pipes transport not supported yet";
+        }
+        else if ((arg == "-n") || (arg == "--testloops")) {
+            //  -n [ --testloops ] arg (=1) Number of Tests
+            arg = args.shift();
+            var tmp = Std.parseInt(arg);
+            if( tmp != null) {
+                numIterations = tmp;
+            } else {
+                throw "Invalid number "+arg;
+            }
+        }
+        else if ((arg == "-t") || (arg == "--threads")) {
+            //  -t [ --threads ] arg (=1)   Number of Test threads
+            arg = args.shift();
+            var tmp = Std.parseInt(arg);
+            if( tmp != null) {
+                numThreads = tmp;
+            } else {
+                throw "Invalid number "+arg;
+            }
+        }
+        else if (arg == "--skip-speed-test") {
+            //  --skip-speed-test              Skip the speed test
+            skipSpeedTest = true;
+        }
+        else {
+            InvalidArg(arg);
+        }
+    }
+
+
+    #end
+
+
+    private function InvalidArg( arg : String) : Void {
+        throw 'Invalid argument $arg';
+    }
+}
diff --git a/test/haxe/src/Main.hx b/test/haxe/src/Main.hx
new file mode 100644
index 0000000..9eb828f
--- /dev/null
+++ b/test/haxe/src/Main.hx
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import thrift.test.*;  // generated code
+
+class Main
+{
+    static function main() {
+        #if phpwebserver
+        initPhpWebServer();
+        //check method
+        if(php.Web.getMethod() != 'POST') {
+          Sys.println('http endpoint for thrift test server');
+          return;
+        }
+        #end
+
+        try {
+            var args = new Arguments();
+
+            if( args.printHelpOnly)
+                return;
+
+            if (args.server)
+                TestServer.Execute(args);
+            else
+                TestClient.Execute(args);
+
+            trace("Completed.");
+        } catch (e : String) {
+            trace(e);
+        }
+    }
+
+    #if phpwebserver
+    private static function initPhpWebServer()
+    {
+        //remap trace to error log
+        haxe.Log.trace = function(v:Dynamic, ?infos:haxe.PosInfos)
+        {
+          // handle trace
+          var newValue : Dynamic;
+          if (infos != null && infos.customParams!=null) {
+            var extra:String = "";
+            for( v in infos.customParams )
+              extra += "," + v;
+            newValue = v + extra;
+          }
+          else {
+            newValue = v;
+          }
+          var msg = infos != null ? infos.fileName + ':' + infos.lineNumber + ': ' : '';
+          Sys.stderr().writeString('${msg}${newValue}\n');
+        }
+    }
+    #end
+
+}
diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx
new file mode 100644
index 0000000..853319e
--- /dev/null
+++ b/test/haxe/src/TestClient.hx
@@ -0,0 +1,937 @@
+/*
+ * 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;
+
+import haxe.Int32;
+import haxe.Int64;
+import haxe.io.Bytes;
+import haxe.Timer;
+import haxe.ds.IntMap;
+import haxe.ds.StringMap;
+import haxe.ds.ObjectMap;
+
+import org.apache.thrift.*;
+import org.apache.thrift.helper.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+#if cpp
+import cpp.vm.Thread;
+#else
+// no thread support (yet)
+#end
+
+import thrift.test.*;  // generated code
+
+
+using StringTools;
+
+class TestResults {
+    private var successCnt : Int = 0;
+    private var errorCnt : Int = 0;
+    private var failedTests : String = "";
+    private var print_direct : Bool = false;
+
+    public static var EXITCODE_SUCCESS            = 0x00;  // no errors bits set
+    //
+    public static var EXITCODE_FAILBIT_BASETYPES  = 0x01;
+    public static var EXITCODE_FAILBIT_STRUCTS    = 0x02;
+    public static var EXITCODE_FAILBIT_CONTAINERS = 0x04;
+    public static var EXITCODE_FAILBIT_EXCEPTIONS = 0x08;
+    //
+    public static var EXITCODE_ALL_FAILBITS       = 0x0F;
+    //
+    private var testsExecuted : Int = 0;
+    private var testsFailed : Int = 0;
+    private var currentTest : Int = 0;
+
+
+    public function new(direct : Bool) {
+        print_direct = direct;
+    }
+
+    public function StartTestGroup( groupBit : Int) : Void {
+        currentTest = groupBit;
+        testsExecuted |= groupBit;
+    }
+
+    public function Expect( expr : Bool, msg : String) : Void {
+        if ( expr) {
+            ++successCnt;
+        } else {
+            ++errorCnt;
+            testsFailed |= currentTest;
+            failedTests += "\n  " + msg;
+            if( print_direct) {
+                trace('FAIL: $msg');
+            }
+        }
+    }
+
+    public function CalculateExitCode() : Int {
+        var notExecuted : Int = EXITCODE_ALL_FAILBITS & (~testsExecuted);
+        return testsFailed | notExecuted;
+    }
+
+    public function PrintSummary() : Void {
+        var total = successCnt + errorCnt;
+        var sp = Math.round((1000 * successCnt) / total) / 10;
+        var ep = Math.round((1000 * errorCnt) / total) / 10;
+
+        trace('===========================');
+        trace('Tests executed    $total');
+        trace('Tests succeeded   $successCnt ($sp%)');
+        trace('Tests failed      $errorCnt ($ep%)');
+        if ( errorCnt > 0)
+        {
+            trace('===========================');
+            trace('FAILED TESTS: $failedTests');
+        }
+        trace('===========================');
+    }
+}
+
+
+class TestClient {
+
+    public static function Execute(args : Arguments) :  Void
+    {
+        var exitCode = 0xFF;
+        try
+        {
+            var difft = Timer.stamp();
+
+            if ( args.numThreads > 1) {
+                #if cpp
+                exitCode = MultiThreadClient(args);
+                #else
+                trace('Threads not supported/implemented for this platform.');
+                exitCode = SingleThreadClient(args);
+                #end
+            } else {
+                exitCode = SingleThreadClient(args);
+            }
+
+            difft = Math.round( 1000 * (Timer.stamp() - difft)) / 1000;
+            trace('total test time: $difft seconds');
+        }
+        catch (e : TException)
+        {
+            trace('TException: $e');
+            exitCode = 0xFF;
+        }
+        catch (e : Dynamic)
+        {
+            trace('Exception: $e');
+            exitCode = 0xFF;
+        }
+
+        #if sys
+        Sys.exit( exitCode);
+        #end
+    }
+
+
+    public static function SingleThreadClient(args : Arguments) :  Int
+    {
+        var rslt = new TestResults(true);
+        RunClient(args,rslt);
+        rslt.PrintSummary();
+        return rslt.CalculateExitCode();
+    }
+
+
+    #if cpp
+    public static function MultiThreadClient(args : Arguments) :  Int
+    {
+        var threads = new List<Thread>();
+        for( test in 0 ... args.numThreads) {
+            threads.add( StartThread( args));
+        }
+        var exitCode : Int = 0;
+        for( thread in threads) {
+            exitCode |= Thread.readMessage(true);
+        }
+        return exitCode;
+    }
+    #end
+
+    #if cpp
+    private static function StartThread(args : Arguments) : Thread {
+        var thread = Thread.create(
+            function() : Void {
+                var rslt = new TestResults(false);
+                var main : Thread = Thread.readMessage(true);
+                try
+                {
+                    RunClient(args,rslt);
+                }
+                catch (e : TException)
+                {
+                    rslt.Expect( false, '$e');
+                    trace('$e');
+                }
+                catch (e : Dynamic)
+                {
+                    rslt.Expect( false, '$e');
+                    trace('$e');
+                }
+                main.sendMessage( rslt.CalculateExitCode());
+            });
+
+        thread.sendMessage(Thread.current());
+        return thread;
+    }
+    #end
+
+
+    public static function RunClient(args : Arguments, rslt : TestResults)
+    {
+        var transport : TTransport = null;
+        switch (args.transport)
+        {
+            case socket:
+                transport = new TSocket(args.host, args.port);
+            case http:
+                var uri = 'http://${args.host}:${args.port}';
+                trace('- http client : ${uri}');
+                transport = new THttpClient(uri);
+            default:
+                throw "Unhandled transport";
+        }
+
+        // optional: layered transport
+        if ( args.framed) {
+            trace("- framed transport");
+            transport = new TFramedTransport(transport);
+        }
+        if ( args.buffered) {
+            trace("- buffered transport");
+            transport = new TBufferedTransport(transport);
+        }
+
+        // protocol
+        var protocol : TProtocol = null;
+        switch( args.protocol)
+        {
+        case binary:
+            trace("- binary protocol");
+            protocol = new TBinaryProtocol(transport);
+        case json:
+            trace("- json protocol");
+            protocol = new TJSONProtocol(transport);
+        case compact:
+            trace("- compact protocol");
+            protocol = new TCompactProtocol(transport);
+        }
+
+        // some quick and basic unit tests
+        HaxeBasicsTest( args, rslt);
+        ModuleUnitTests( args, rslt);
+
+        // now run the test code
+        trace('- ${args.numIterations} iterations');
+        for( i in 0 ... args.numIterations) {
+            ClientTest( transport, protocol, args, rslt);
+        }
+    }
+
+
+    public static function HaxeBasicsTest( args : Arguments, rslt : TestResults) : Void
+    {
+        // We need to test a few basic things used in the ClientTest
+        // Anything else beyond this scope should go into /lib/haxe/ instead
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);
+
+        var map32 = new IntMap<Int32>();
+        var map64 = new Int64Map<Int32>();
+
+        rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #1");
+        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #2");
+        rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map<Int32> Test #3");
+        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #4");
+
+        map32.set( 42, 815);
+        map64.set( Int64.make(0,42), 815);
+        map32.set( -517, 23);
+        map64.set( Int64.neg(Int64.make(0,517)), 23);
+        map32.set( 0, -123);
+        map64.set( Int64.make(0,0), -123);
+
+        //trace('map32 = $map32');
+        //trace('map64 = $map64');
+
+        rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #10");
+        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #11");
+        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #12");
+        rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #13");
+        rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #14");
+        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #15");
+        rslt.Expect( map32.get( -517) == map64.get( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #16");
+        rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #Int64.make(-5,17)");
+        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map<Int32> Test #18");
+        rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map<Int32> Test #19");
+        rslt.Expect( map32.remove( -517) == map64.remove( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #20");
+        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #21");
+        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #22");
+        rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #23");
+        rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #24");
+        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #25");
+        rslt.Expect( map32.get( -517) == map64.get( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #26");
+        rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #27");
+        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map<Int32> Test #28");
+
+        map32.set( 42, 1);
+        map64.set( Int64.make(0,42), 1);
+        map32.set( -517, -2);
+        map64.set( Int64.neg(Int64.make(0,517)), -2);
+        map32.set( 0, 3);
+        map64.set( Int64.make(0,0), 3);
+
+        var c32 = 0;
+        var ksum32 = 0;
+        for (key in map32.keys()) {
+            ++c32;
+            ksum32 += key;
+        }
+        var c64 = 0;
+        var ksum64 = Int64.make(0,0);
+        for (key in map64.keys()) {
+            ++c64;
+            ksum64 = Int64.add( ksum64, key);
+        }
+        rslt.Expect( c32 == c64, "Int64Map<Int32> Test #30");
+        rslt.Expect( '$ksum64' == '$ksum32', '$ksum64 == $ksum32   Test #31');
+
+        //compare without spaces because differ in php and cpp
+        var s32 = map32.toString().replace(' ', '');
+        var s64 = map64.toString().replace(' ', '');
+        rslt.Expect( s32 == s64, "Int64Map<Int32>.toString(): " + ' ("$s32" == "$s64") Test #32');
+
+        map32.remove( 42);
+        map64.remove( Int64.make(0,42));
+        map32.remove( -517);
+        map64.remove( Int64.neg(Int64.make(0,517)));
+        map32.remove( 0);
+        map64.remove( Int64.make(0,0));
+
+        rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #90");
+        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #91");
+        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #92");
+        rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #93");
+        rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #94");
+        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #95");
+        rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map<Int32> Test #96");
+        rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #97");
+        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0, 0)), "Int64Map<Int32> Test #98");
+    }
+
+
+    // core module unit tests
+    public static function ModuleUnitTests( args : Arguments, rslt : TestResults) : Void {
+        #if debug
+
+        try {
+            BitConverter.UnitTest();
+            rslt.Expect( true, 'BitConverter.UnitTest  Test #100');
+        }
+        catch( e : Dynamic) {
+            rslt.Expect( false, 'BitConverter.UnitTest: $e  Test #100');
+        }
+
+        try {
+            ZigZag.UnitTest();
+            rslt.Expect( true, 'ZigZag.UnitTest  Test #101');
+        }
+        catch( e : Dynamic) {
+            rslt.Expect( false, 'ZigZag.UnitTest: $e  Test #101');
+        }
+
+        #end
+    }
+
+
+    public static function BytesToHex(data : Bytes) : String {
+        var hex = "";
+        for ( i in 0 ... data.length) {
+            hex += StringTools.hex( data.get(i), 2);
+        }
+        return hex;
+    }
+
+    public static function PrepareTestData(randomDist : Bool) : Bytes    {
+        var retval = Bytes.alloc(0x100);
+        var initLen : Int = (retval.length > 0x100 ? 0x100 : retval.length);
+
+        // linear distribution, unless random is requested
+        if (!randomDist) {
+            for (i in 0 ... initLen) {
+                retval.set(i, i % 0x100);
+            }
+            return retval;
+        }
+
+        // random distribution
+        for (i in 0 ... initLen) {
+            retval.set(i, 0);
+        }
+        for (i in 1 ... initLen) {
+            while( true) {
+                var nextPos = Std.random(initLen);
+                if (retval.get(nextPos) == 0) {
+                    retval.set( nextPos, i % 0x100);
+                    break;
+                }
+            }
+        }
+        return retval;
+    }
+
+
+    public static function ClientTest( transport : TTransport, protocol : TProtocol,
+                                       args : Arguments, rslt : TestResults) : Void
+    {
+        var client = new ThriftTestImpl(protocol,protocol);
+        try
+        {
+            if (!transport.isOpen())
+            {
+                transport.open();
+            }
+        }
+        catch (e : TException)
+        {
+            rslt.Expect( false, 'unable to open transport: $e');
+            return;
+        }
+        catch (e : Dynamic)
+        {
+            rslt.Expect( false, 'unable to open transport: $e');
+            return;
+        }
+
+        var start = Date.now();
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_EXCEPTIONS);
+
+        // if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
+        trace('testException("Xception")');
+        try {
+            client.testException("Xception");
+            rslt.Expect( false, 'testException("Xception") should throw');
+        }
+        catch (e : Xception)
+        {
+            rslt.Expect( e.message == "Xception", 'testException("Xception")  -  e.message == "Xception"');
+            rslt.Expect( e.errorCode == 1001, 'testException("Xception")  -  e.errorCode == 1001');
+        }
+        catch (e : TException)
+        {
+            rslt.Expect( false, 'testException("Xception")  -  ${e} : ${e.errorMsg}');
+        }
+        catch (e : Dynamic)
+        {
+            rslt.Expect( false, 'testException("Xception")  -  $e');
+        }
+
+        // if arg == "TException" throw TException
+        trace('testException("TException")');
+        try {
+            client.testException("TException");
+            rslt.Expect( false, 'testException("TException") should throw');
+        }
+        catch (e : TException)
+        {
+            rslt.Expect( true, 'testException("TException")  -  $e : ${e.errorMsg}');
+        }
+        catch (e : Dynamic)
+        {
+            rslt.Expect( false, 'testException("TException")  -  $e');
+        }
+
+        // reopen the transport, just in case the server closed his end
+        if (transport.isOpen())
+            transport.close();
+        transport.open();
+
+        // else do not throw anything
+        trace('testException("bla")');
+        try {
+            client.testException("bla");
+            rslt.Expect( true, 'testException("bla") should not throw');
+        }
+        catch (e : TException)
+        {
+            rslt.Expect( false, 'testException("bla")  -  ${e} : ${e.errorMsg}');
+        }
+        catch (e : Dynamic)
+        {
+            rslt.Expect( false, 'testException("bla")  -  $e');
+        }
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);
+
+        trace('testVoid()');
+        client.testVoid();
+        trace(' = void');
+        rslt.Expect(true,"testVoid()");  // bump counter
+
+        trace('testBool(${true})');
+        var b = client.testBool(true);
+        trace(' = $b');
+        rslt.Expect(b, '$b == "${true}"');
+        trace('testBool(${false})');
+        b = client.testBool(false);
+        trace(' = $b');
+        rslt.Expect( ! b, '$b == "${false}"');
+
+        trace('testString("Test")');
+        var s = client.testString("Test");
+        trace(' = "$s"');
+        rslt.Expect(s == "Test", '$s == "Test"');
+
+        trace('testByte(1)');
+        var i8 = client.testByte(1);
+        trace(' = $i8');
+        rslt.Expect(i8 == 1, '$i8 == 1');
+
+        trace('testI32(-1)');
+        var i32 = client.testI32(-1);
+        trace(' = $i32');
+        rslt.Expect(i32 == -1, '$i32 == -1');
+
+        trace('testI64(-34359738368)');
+        var i64 = client.testI64( Int64.make( 0xFFFFFFF8, 0x00000000)); // -34359738368
+        trace(' = $i64');
+        rslt.Expect( Int64.compare( i64, Int64.make( 0xFFFFFFF8, 0x00000000)) == 0,
+                     Int64.toStr(i64) +" == "+Int64.toStr(Int64.make( 0xFFFFFFF8, 0x00000000)));
+
+        // edge case: the largest negative Int64 has no positive Int64 equivalent
+        trace('testI64(-9223372036854775808)');
+        i64 = client.testI64( Int64.make( 0x80000000, 0x00000000)); // -9223372036854775808
+        trace(' = $i64');
+        rslt.Expect( Int64.compare( i64, Int64.make( 0x80000000, 0x00000000)) == 0,
+                     Int64.toStr(i64) +" == "+Int64.toStr(Int64.make( 0x80000000, 0x00000000)));
+
+        trace('testDouble(5.325098235)');
+        var dub = client.testDouble(5.325098235);
+        trace(' = $dub');
+        rslt.Expect(dub == 5.325098235, '$dub == 5.325098235');
+
+        var binOut = PrepareTestData(true);
+        trace('testBinary('+BytesToHex(binOut)+')');
+        try {
+            var binIn = client.testBinary(binOut);
+            trace('testBinary() = '+BytesToHex(binIn));
+            rslt.Expect( binIn.length == binOut.length, '${binIn.length} == ${binOut.length}');
+            var len = ((binIn.length < binOut.length)  ?  binIn.length  : binOut.length);
+            for (ofs in 0 ... len) {
+                if (binIn.get(ofs) != binOut.get(ofs)) {
+                    rslt.Expect( false, 'testBinary('+BytesToHex(binOut)+'): content mismatch at offset $ofs');
+                }
+            }
+        }
+        catch (e : TApplicationException) {
+            trace('testBinary('+BytesToHex(binOut)+'): '+e.errorMsg);  // may not be supported by the server
+        }
+
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_STRUCTS);
+
+        trace('testStruct({"Zero", 1, -3, -5})');
+        var o = new Xtruct();
+        o.string_thing = "Zero";
+        o.byte_thing = 1;
+        o.i32_thing = -3;
+        o.i64_thing = Int64.make(0,-5);
+        var i = client.testStruct(o);
+        trace(' = {"' + i.string_thing + '", ' + i.byte_thing +', '
+                      + i.i32_thing +', '+ Int64.toStr(i.i64_thing) + '}');
+        rslt.Expect( i.string_thing == o.string_thing, "i.string_thing == o.string_thing");
+        rslt.Expect( i.byte_thing == o.byte_thing, "i.byte_thing == o.byte_thing");
+        rslt.Expect( i.i32_thing == o.i32_thing, "i.i64_thing == o.i64_thing");
+        rslt.Expect( i.i32_thing == o.i32_thing, "i.i64_thing == o.i64_thing");
+
+        trace('testNest({1, {\"Zero\", 1, -3, -5}, 5})');
+        var o2 = new Xtruct2();
+        o2.byte_thing = 1;
+        o2.struct_thing = o;
+        o2.i32_thing = 5;
+        var i2 = client.testNest(o2);
+        i = i2.struct_thing;
+        trace(" = {" + i2.byte_thing + ", {\"" + i.string_thing + "\", "
+              + i.byte_thing + ", " + i.i32_thing + ", " + Int64.toStr(i.i64_thing) + "}, "
+              + i2.i32_thing + "}");
+        rslt.Expect( i2.byte_thing == o2.byte_thing, "i2.byte_thing == o2.byte_thing");
+        rslt.Expect( i2.i32_thing == o2.i32_thing, "i2.i32_thing == o2.i32_thing");
+        rslt.Expect( i.string_thing == o.string_thing, "i.string_thing == o.string_thing");
+        rslt.Expect( i.byte_thing == o.byte_thing, "i.byte_thing == o.byte_thing");
+        rslt.Expect( i.i32_thing == o.i32_thing, "i.i32_thing == o.i32_thing");
+        rslt.Expect( Int64.compare( i.i64_thing, o.i64_thing) == 0, "i.i64_thing == o.i64_thing");
+
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_CONTAINERS);
+
+        var mapout = new IntMap< haxe.Int32>();
+        for ( j in 0 ... 5)
+        {
+            mapout.set(j, j - 10);
+        }
+        trace("testMap({");
+        var first : Bool = true;
+        for( key in mapout.keys())
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                trace(", ");
+            }
+            trace(key + " => " + mapout.get(key));
+        }
+        trace("})");
+
+        var mapin = client.testMap(mapout);
+
+        trace(" = {");
+        first = true;
+        for( key in mapin.keys())
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                trace(", ");
+            }
+            trace(key + " => " + mapin.get(key));
+            rslt.Expect( mapin.get(key) == mapout.get(key), ' mapin.get($key) == mapout.get($key)');
+        }
+        trace("}");
+        for( key in mapout.keys())
+        {
+            rslt.Expect(mapin.exists(key), 'mapin.exists($key)');
+        }
+
+        var listout = new List<Int>();
+        for (j in -2 ... 3)
+        {
+            listout.add(j);
+        }
+        trace("testList({");
+        first = true;
+        for( j in listout)
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                trace(", ");
+            }
+            trace(j);
+        }
+        trace("})");
+
+        var listin = client.testList(listout);
+
+        trace(" = {");
+        first = true;
+        for( j in listin)
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                trace(", ");
+            }
+            trace(j);
+        }
+        trace("}");
+
+        rslt.Expect(listin.length == listout.length, "listin.length == listout.length");
+        var literout = listout.iterator();
+        var literin = listin.iterator();
+        while( literin.hasNext()) {
+            rslt.Expect(literin.next() == literout.next(), "literin[i] == literout[i]");
+        }
+
+        //set
+        var setout = new IntSet();
+        for (j in -2 ... 3)
+        {
+            setout.add(j);
+        }
+        trace("testSet({");
+        first = true;
+        for( j in setout)
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                trace(", ");
+            }
+            trace(j);
+        }
+        trace("})");
+
+        var setin = client.testSet(setout);
+
+        trace(" = {");
+        first = true;
+        for( j in setin)
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                trace(", ");
+            }
+            trace(j);
+            rslt.Expect(setout.contains(j), 'setout.contains($j)');
+        }
+        trace("}");
+        rslt.Expect(setin.size == setout.size, "setin.length == setout.length");
+
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);
+
+        trace("testEnum(ONE)");
+        var ret = client.testEnum(Numberz.ONE);
+        trace(" = " + ret);
+        rslt.Expect(ret == Numberz.ONE, '$ret == Numberz.ONE');
+
+        trace("testEnum(TWO)");
+        ret = client.testEnum(Numberz.TWO);
+        trace(" = " + ret);
+        rslt.Expect(ret == Numberz.TWO, '$ret == Numberz.TWO');
+
+        trace("testEnum(THREE)");
+        ret = client.testEnum(Numberz.THREE);
+        trace(" = " + ret);
+        rslt.Expect(ret == Numberz.THREE, '$ret == Numberz.THREE');
+
+        trace("testEnum(FIVE)");
+        ret = client.testEnum(Numberz.FIVE);
+        trace(" = " + ret);
+        rslt.Expect(ret == Numberz.FIVE, '$ret == Numberz.FIVE');
+
+        trace("testEnum(EIGHT)");
+        ret = client.testEnum(Numberz.EIGHT);
+        trace(" = " + ret);
+        rslt.Expect(ret == Numberz.EIGHT, '$ret == Numberz.EIGHT');
+
+        trace("testTypedef(309858235082523)");
+        var uid = client.testTypedef( Int64.make( 0x119D0, 0x7E08671B));  // 309858235082523
+        trace(" = " + uid);
+        rslt.Expect( Int64.compare( uid, Int64.make( 0x119D0, 0x7E08671B)) == 0,
+                     Int64.toStr(uid)+" == "+Int64.toStr(Int64.make( 0x119D0, 0x7E08671B)));
+
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_CONTAINERS);
+
+        trace("testMapMap(1)");
+        var mm = client.testMapMap(1);
+        trace(" = {");
+        for( key in mm.keys())
+        {
+            trace(key + " => {");
+            var m2 = mm.get(key);
+            for( k2 in m2.keys())
+            {
+                trace(k2 + " => " + m2.get(k2) + ", ");
+            }
+            trace("}, ");
+        }
+        trace("}");
+
+        var pos = mm.get(4);
+        var neg = mm.get(-4);
+        rslt.Expect( (pos != null) && (neg != null), "(pos != null) && (neg != null)");
+        for (i in 1 ... 5) {
+            rslt.Expect( pos.get(i) == i, 'pos.get($i) == $i');
+            rslt.Expect( neg.get(-i) == -i, 'neg.get(-$i) == -$i');
+        }
+        rslt.Expect( ! pos.exists(0), '!pos.exists(0)');
+        rslt.Expect( ! neg.exists(-0), '!neg.exists(-0)');
+        rslt.Expect( ! pos.exists(42), '!pos.exists(42)');
+        rslt.Expect( ! neg.exists(-42), '!neg.exists(-42)');
+
+
+        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_STRUCTS);
+
+        var insane = new Insanity();
+        insane.userMap = new IntMap< Int64>();
+        insane.userMap.set( Numberz.FIVE, Int64.make(0,5000));
+        var truck = new Xtruct();
+        truck.string_thing = "Truck";
+        truck.byte_thing = 8;
+        truck.i32_thing = 8;
+        truck.i64_thing = Int64.make(0,8);
+        insane.xtructs = new List<Xtruct>();
+        insane.xtructs.add(truck);
+        trace("testInsanity()");
+        var whoa = client.testInsanity(insane);
+        trace(" = {");
+        for( key in whoa.keys())
+        {
+            var val = whoa.get(key);
+            trace(key + " => {");
+
+            for( k2 in val.keys())
+            {
+                var v2 = val.get(k2);
+
+                trace(k2 + " => {");
+                var userMap = v2.userMap;
+
+                trace("{");
+                if (userMap != null)
+                {
+                    for( k3 in userMap.keys())
+                    {
+                        trace(k3 + " => " + userMap.get(k3) + ", ");
+                    }
+                }
+                else
+                {
+                    trace("null");
+                }
+                trace("}, ");
+
+                var xtructs = v2.xtructs;
+
+                trace("{");
+                if (xtructs != null)
+                {
+                    for( x in xtructs)
+                    {
+                        trace("{\"" + x.string_thing + "\", "
+                              + x.byte_thing + ", " + x.i32_thing + ", "
+                              + x.i32_thing + "}, ");
+                    }
+                }
+                else
+                {
+                    trace("null");
+                }
+                trace("}");
+
+                trace("}, ");
+            }
+            trace("}, ");
+        }
+        trace("}");
+
+
+		/**
+		* So you think you've got this all worked, out eh?
+		*
+		* Creates a the returned map with these values and prints it out:
+		*   { 1 => { 2 => argument,
+		*            3 => argument,
+		*          },
+		*     2 => { 6 => <empty Insanity struct>, },
+		*   }
+		* @return map<UserId, map<Numberz,Insanity>> - a map with the above values
+		*/
+		
+        var first_map = whoa.get(Int64.make(0,1));
+        var second_map = whoa.get(Int64.make(0,2));
+        rslt.Expect( (first_map != null) && (second_map != null), "(first_map != null) && (second_map != null)");
+        if ((first_map != null) && (second_map != null))
+        {
+            var crazy2 = first_map.get(Numberz.TWO);
+            var crazy3 = first_map.get(Numberz.THREE);
+            var looney = second_map.get(Numberz.SIX);
+            rslt.Expect( (crazy2 != null) && (crazy3 != null) && (looney != null),
+                        "(crazy2 != null) && (crazy3 != null) && (looney != null)");
+
+            var crz2iter = crazy2.xtructs.iterator();
+            var crz3iter = crazy3.xtructs.iterator();
+            rslt.Expect( crz2iter.hasNext() && crz3iter.hasNext(), "crz2iter.hasNext() && crz3iter.hasNext()");
+            var goodbye2 = crz2iter.next();
+            var goodbye3 = crz3iter.next();
+            rslt.Expect( ! (crz2iter.hasNext() || crz3iter.hasNext()), "! (crz2iter.hasNext() || crz3iter.hasNext())");
+
+			rslt.Expect( Int64.compare( crazy2.userMap.get(Numberz.FIVE), insane.userMap.get(Numberz.FIVE)) == 0, "crazy2.userMap[5] == insane.userMap[5]");
+			rslt.Expect( truck.string_thing == goodbye2.string_thing, "truck.string_thing == goodbye2.string_thing");
+			rslt.Expect( truck.byte_thing  == goodbye2.byte_thing, "truck.byte_thing  == goodbye2.byte_thing");
+			rslt.Expect( truck.i32_thing  == goodbye2.i32_thing, "truck.i32_thing  == goodbye2.i32_thing");
+			rslt.Expect( Int64.compare( truck.i64_thing, goodbye2.i64_thing) == 0, "truck.i64_thing  == goodbye2.i64_thing");
+
+			rslt.Expect( Int64.compare( crazy3.userMap.get(Numberz.FIVE), insane.userMap.get(Numberz.FIVE)) == 0, "crazy3.userMap[5] == insane.userMap[5]");
+			rslt.Expect( truck.string_thing == goodbye3.string_thing, "truck.string_thing == goodbye3.string_thing");
+			rslt.Expect( truck.byte_thing  == goodbye3.byte_thing, "truck.byte_thing  == goodbye3.byte_thing");
+			rslt.Expect( truck.i32_thing  == goodbye3.i32_thing, "truck.i32_thing  == goodbye3.i32_thing");
+			rslt.Expect( Int64.compare( truck.i64_thing, goodbye3.i64_thing) == 0, "truck.i64_thing  == goodbye3.i64_thing");
+			
+			rslt.Expect( ! looney.isSet(1), "! looney.isSet(1)");
+			rslt.Expect( ! looney.isSet(2), "! looney.isSet(2)");
+        }
+
+        var arg0 = 1;
+        var arg1 = 2;
+        var arg2 = Int64.make( 0x7FFFFFFF,0xFFFFFFFF);
+        var multiDict = new IntMap< String>();
+        multiDict.set(1, "one");
+        var arg4 = Numberz.FIVE;
+        var arg5 = Int64.make(0,5000000);
+        trace("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")");
+        var multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5);
+        trace(" = Xtruct(byte_thing:" + multiResponse.byte_thing + ",string_thing:" + multiResponse.string_thing
+                    + ",i32_thing:" + multiResponse.i32_thing
+                    + ",i64_thing:" + Int64.toStr(multiResponse.i64_thing) + ")");
+
+        rslt.Expect( multiResponse.string_thing == "Hello2", 'multiResponse.String_thing == "Hello2"');
+        rslt.Expect( multiResponse.byte_thing == arg0, 'multiResponse.Byte_thing == arg0');
+        rslt.Expect( multiResponse.i32_thing == arg1, 'multiResponse.I32_thing == arg1');
+        rslt.Expect( Int64.compare( multiResponse.i64_thing, arg2) == 0, 'multiResponse.I64_thing == arg2');
+
+
+        rslt.StartTestGroup( 0);
+
+        trace("Test Oneway(1)");
+        client.testOneway(1);
+
+        if( ! args.skipSpeedTest) {
+            trace("Test Calltime()");
+            var difft = Timer.stamp();
+            for ( k in 0 ... 1000) {
+                client.testVoid();
+            }
+            difft = Math.round( 1000 * (Timer.stamp() - difft)) / 1000;
+            trace('$difft ms per testVoid() call');
+        }
+    }
+}
diff --git a/test/haxe/src/TestMacro.hx b/test/haxe/src/TestMacro.hx
new file mode 100644
index 0000000..a620760
--- /dev/null
+++ b/test/haxe/src/TestMacro.hx
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package ;
+
+import haxe.macro.Context;
+import haxe.macro.Expr;
+
+/****
+ * If you call the Thrift compiler this way (e.g. by changing the prebuild command)
+ *
+ *     thrift -r -gen haxe:buildmacro=TestMacro.handle()   ../ThriftTest.thrift
+ *
+ * the TestMacro.handle() function implemented below is called for each generated class
+ * and interface. Use "thrift --help" to get more info about other available options.
+ */
+class TestMacro
+{
+  public static function handle( ) : Array< Field> {
+    trace('TestMacro called for ' + Context.getLocalType());
+    return Context.getBuildFields();
+  }
+
+}
diff --git a/test/haxe/src/TestServer.hx b/test/haxe/src/TestServer.hx
new file mode 100644
index 0000000..450c8f2
--- /dev/null
+++ b/test/haxe/src/TestServer.hx
@@ -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;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import thrift.test.*;  // generated code
+
+
+class TestServer
+{
+    public static function Execute(args : Arguments) :  Void
+    {
+        try
+        {
+            // Transport
+            var transport : TServerTransport = null;
+            switch( args.transport) {
+            case socket:
+                trace("- socket port "+args.port);
+                transport = new TServerSocket( args.port);
+            case http:
+                trace("- http");
+                #if !phpwebserver
+                  throw "HTTP server not implemented yet";
+                 //transport = new THttpServer( targetHost);
+                #else
+                transport =    new TWrappingServerTransport(
+                        new TStreamTransport(
+                          new TFileStream("php://input", Read),
+                          new TFileStream("php://output", Append)
+                          )
+                        );
+
+                #end
+            default:
+                throw "Unhandled transport";
+            }
+
+            // optional: layered transport
+            var transfactory : TTransportFactory = null;
+            if ( args.framed) {
+                trace("- framed transport");
+                transfactory = new TFramedTransportFactory();
+            }
+            if ( args.buffered) {
+                trace("- buffered transport");
+                transfactory = new TBufferedTransportFactory();
+            }
+
+            // protocol
+            var protfactory : TProtocolFactory = null;
+            switch( args.protocol)
+            {
+            case binary:
+                trace("- binary protocol");
+                protfactory = new TBinaryProtocolFactory();
+            case json:
+                trace("- json protocol");
+                protfactory = new TJSONProtocolFactory();
+            case compact:
+                trace("- compact protocol");
+                protfactory = new TCompactProtocolFactory();
+            }
+
+
+            // Processor
+            var handler = new TestServerHandler();
+            var processor = new ThriftTestProcessor(handler);
+
+            // Simple Server
+            var server : TServer = null;
+            switch( args.servertype)
+            {
+            case simple:
+                var simpleServer = new TSimpleServer( processor, transport, transfactory, protfactory);
+                #if phpwebserver
+                simpleServer.runOnce = true;
+                #end
+                server = simpleServer;
+
+            default:
+                throw "Unhandled server type";
+            }
+
+
+            /*
+            // Server event handler
+            if( args.serverEvents) {
+                var events = new TestServerEventHandler();
+                server.setEventHandler(serverEvents);
+                handler.server = serverEngine;
+            }
+            */
+
+            // Run it
+            server.Serve();
+            trace("done.");
+
+        }
+        catch (x : TException)
+        {
+            trace('$x ${x.errorID} ${x.errorMsg}');
+        }
+        catch (x : Dynamic)
+        {
+            trace('$x');
+        }
+    }
+}
diff --git a/test/haxe/src/TestServerEventHandler.hx b/test/haxe/src/TestServerEventHandler.hx
new file mode 100644
index 0000000..d17567c
--- /dev/null
+++ b/test/haxe/src/TestServerEventHandler.hx
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import thrift.test.*;  // generated code
+
+
+class TestServerEventHandler : TServerEventHandler
+{
+    public int callCount = 0;
+    public void preServe()
+    {
+        callCount++;
+    }
+    public Object createContext(Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output)
+    {
+        callCount++;
+        return null;
+    }
+    public void deleteContext(Object serverContext, Thrift.Protocol.TProtocol input, Thrift.Protocol.TProtocol output)
+    {
+        callCount++;
+    }
+    public void processContext(Object serverContext, Thrift.Transport.TTransport transport)
+    {
+        callCount++;
+    }
+}
+
+    
\ No newline at end of file
diff --git a/test/haxe/src/TestServerHandler.hx b/test/haxe/src/TestServerHandler.hx
new file mode 100644
index 0000000..b8a2590
--- /dev/null
+++ b/test/haxe/src/TestServerHandler.hx
@@ -0,0 +1,479 @@
+/*
+ * 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;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+import org.apache.thrift.helper.*;
+
+import haxe.Int32;
+import haxe.Int64;
+import haxe.io.Bytes;
+import haxe.ds.IntMap;
+import haxe.ds.StringMap;
+import haxe.ds.ObjectMap;
+
+import thrift.test.*;  // generated code
+
+
+class TestServerHandler implements ThriftTest {
+
+    public var server:TServer;
+
+    public function new() {
+    }
+
+    /**
+    * Prints "testVoid()" and returns nothing.
+    */
+    public function testVoid():Void
+    {
+        trace("testVoid()");
+    }
+
+    /**
+    * Prints 'testBool("%s")' where '%s' with thing as 'true' or 'false'
+    * @param bool  thing - the bool data to print
+    * @return bool  - returns the bool 'thing'
+    *
+    * @param thing
+    */
+    public function testBool(thing : Bool) : Bool
+    {
+        trace('testBool($thing)');
+        return thing;
+    }
+
+    /**
+    * Prints 'testString("%s")' with thing as '%s'
+    * @param string thing - the string to print
+    * @return string - returns the string 'thing'
+    *
+    * @param thing
+    */
+    public function testString(thing:String):String
+    {
+        trace("teststring(\"" + thing + "\")");
+        return thing;
+    }
+
+    /**
+    * Prints 'testByte("%d")' with thing as '%d'
+    * @param byte thing - the byte to print
+    * @return byte - returns the byte 'thing'
+    *
+    * @param thing
+    */
+    public function testByte(thing:haxe.Int32):haxe.Int32
+    {
+        trace("testByte(" + thing + ")");
+        return thing;
+    }
+
+    /**
+    * Prints 'testI32("%d")' with thing as '%d'
+    * @param i32 thing - the i32 to print
+    * @return i32 - returns the i32 'thing'
+    *
+    * @param thing
+    */
+    public function testI32(thing:haxe.Int32):haxe.Int32
+    {
+        trace("testI32(" + thing + ")");
+        return thing;
+    }
+
+    /**
+    * Prints 'testI64("%d")' with thing as '%d'
+    * @param i64 thing - the i64 to print
+    * @return i64 - returns the i64 'thing'
+    *
+    * @param thing
+    */
+    public function testI64(thing:haxe.Int64):haxe.Int64
+    {
+        trace("testI64(" + thing + ")");
+        return thing;
+    }
+
+    /**
+    * Prints 'testDouble("%f")' with thing as '%f'
+    * @param double thing - the double to print
+    * @return double - returns the double 'thing'
+    *
+    * @param thing
+    */
+    public function testDouble(thing:Float):Float
+    {
+        trace("testDouble(" + thing + ")");
+        return thing;
+    }
+
+    /**
+     * Prints 'testBinary("%s")' where '%s' is a hex-formatted string of thing's data
+     * @param binary  thing - the binary data to print
+     * @return binary  - returns the binary 'thing'
+     *
+     * @param thing
+     */
+    public function testBinary(thing : haxe.io.Bytes) : haxe.io.Bytes
+    {
+        var hex = "";
+        for ( i in 0 ... thing.length) {
+            hex += StringTools.hex( thing.get(i), 2);
+        }
+        trace('testBinary($hex)');
+        return thing;
+    }
+
+    /**
+    * Prints 'testStruct("{%s}")' where thing has been formatted
+    *  into a string of comma separated values
+    * @param Xtruct thing - the Xtruct to print
+    * @return Xtruct - returns the Xtruct 'thing'
+    *
+    * @param thing
+    */
+    public function testStruct(thing:Xtruct):Xtruct
+    {
+        trace("testStruct({" +
+                          "\"" + thing.string_thing + "\", " +
+                          thing.byte_thing + ", " +
+                          thing.i32_thing + ", " +
+                          Int64.toStr(thing.i64_thing) + "})");
+        return thing;
+    }
+
+    /**
+    * Prints 'testNest("{%s}")' where thing has been formatted
+    *  into a string of the nested struct
+    * @param Xtruct2 thing - the Xtruct2 to print
+    * @return Xtruct2 - returns the Xtruct2 'thing'
+    *
+    * @param thing
+    */
+    public function testNest(nest:Xtruct2):Xtruct2
+    {
+        var thing:Xtruct = nest.struct_thing;
+        trace("testNest({" +
+                          nest.byte_thing + ", {" +
+                          "\"" + thing.string_thing + "\", " +
+                          thing.byte_thing + ", " +
+                          thing.i32_thing + ", " +
+                          Int64.toStr(thing.i64_thing) + "}, " +
+                          nest.i32_thing + "})");
+        return nest;
+    }
+
+    /**
+    * Prints 'testMap("{%s")' where thing has been formatted
+    *  into a string of  'key => value' pairs
+    *  separated by commas and new lines
+    * @param map<i32,i32> thing - the map<i32,i32> to print
+    * @return map<i32,i32> - returns the map<i32,i32> 'thing'
+    *
+    * @param thing
+    */
+    public function testMap(thing:IntMap<haxe.Int32>):IntMap<haxe.Int32>
+    {
+        trace("testMap({");
+        var first:Bool = true;
+        for (key in thing.keys()) {
+            if (first) {
+                first = false;
+            } else {
+                trace(", ");
+            };
+            trace(key + " => " + thing.get(key));
+        };
+        trace("})");
+        return thing;
+    }
+
+    /**
+    * Prints 'testStringMap("{%s}")' where thing has been formatted
+    *  into a string of  'key => value' pairs
+    *  separated by commas and new lines
+    * @param map<string,string> thing - the map<string,string> to print
+    * @return map<string,string> - returns the map<string,string> 'thing'
+    *
+    * @param thing
+    */
+    public function testStringMap(thing:StringMap<String>):StringMap<String>
+    {
+        trace("testStringMap({");
+        var first:Bool = true;
+        for (key in thing.keys()) {
+            if (first) {
+                first = false;
+            } else {
+                trace(", ");
+            };
+            trace(key + " => " + thing.get(key));
+        };
+        trace("})");
+        return thing;
+    }
+
+    /**
+    * Prints 'testSet("{%s}")' where thing has been formatted
+    *  into a string of  values
+    *  separated by commas and new lines
+    * @param set<i32> thing - the set<i32> to print
+    * @return set<i32> - returns the set<i32> 'thing'
+    *
+    * @param thing
+    */
+    public function testSet(thing:IntSet):IntSet
+    {
+        trace("testSet({");
+        var first:Bool = true;
+        for (elem in thing) {
+            if (first) {
+                first = false;
+            } else {
+                trace(", ");
+            };
+            trace(elem);
+        };
+        trace("})");
+        return thing;
+    }
+
+    /**
+    * Prints 'testList("{%s}")' where thing has been formatted
+    *  into a string of  values
+    *  separated by commas and new lines
+    * @param list<i32> thing - the list<i32> to print
+    * @return list<i32> - returns the list<i32> 'thing'
+    *
+    * @param thing
+    */
+    public function testList(thing:List<haxe.Int32>):List<haxe.Int32>
+    {
+        trace("testList({");
+        var first:Bool = true;
+        for (elem in thing) {
+            if (first) {
+                first = false;
+            } else {
+                trace(", ");
+            };
+            trace(elem);
+        };
+        trace("})");
+        return thing;
+    }
+
+    /**
+    * Prints 'testEnum("%d")' where thing has been formatted into it's numeric value
+    * @param Numberz thing - the Numberz to print
+    * @return Numberz - returns the Numberz 'thing'
+    *
+    * @param thing
+    */
+    public function testEnum(thing:Int):Int
+    {
+        trace("testEnum(" + thing + ")");
+        return thing;
+    }
+
+    /**
+    * Prints 'testTypedef("%d")' with thing as '%d'
+    * @param UserId thing - the UserId to print
+    * @return UserId - returns the UserId 'thing'
+    *
+    * @param thing
+    */
+    public function testTypedef(thing:haxe.Int64):haxe.Int64
+    {
+        trace("testTypedef(" + thing + ")");
+        return thing;
+    }
+
+    /**
+    * Prints 'testMapMap("%d")' with hello as '%d'
+    * @param i32 hello - the i32 to print
+    * @return map<i32,map<i32,i32>> - returns a dictionary with these values:
+    *   {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, },
+    *     4 => {1 => 1, 2 => 2, 3 => 3, 4 => 4, }, }
+    *
+    * @param hello
+    */
+    public function testMapMap(hello:haxe.Int32):IntMap<IntMap<haxe.Int32>>
+    {
+        trace("testMapMap(" + hello + ")");
+        var mapmap = new IntMap<IntMap<Int>>();
+        var pos = new IntMap<Int>();
+        var neg = new IntMap<Int>();
+        for (i in 1 ... 5) {
+            pos.set(i, i);
+            neg.set(-i, -i);
+        };
+        mapmap.set(4, pos);
+        mapmap.set(-4, neg);
+        return mapmap;
+    }
+
+    /**
+    * So you think you've got this all worked, out eh?
+    *
+    * Creates a the returned map with these values and prints it out:
+    *   { 1 => { 2 => argument,
+    *            3 => argument,
+    *          },
+    *     2 => { 6 => <empty Insanity struct>, },
+    *   }
+    * @return map<UserId, map<Numberz,Insanity>> - a map with the above values
+    *
+    * @param argument
+    */
+    public function testInsanity(argument : Insanity) : Int64Map< IntMap< Insanity>>
+    {
+        trace("testInsanity()");
+
+        var first_map = new IntMap< Insanity>();
+        first_map.set(Numberz.TWO, argument);
+        first_map.set(Numberz.THREE, argument);
+
+        var second_map = new IntMap< Insanity>();
+        var looney = new Insanity();
+        second_map.set(Numberz.SIX, looney);
+
+        var insane = new Int64Map< IntMap< Insanity>>();
+        insane.set( Int64.make(0,1), first_map);
+        insane.set( Int64.make(0,2), second_map);
+
+        return insane;
+    }
+
+    /**
+    * Prints 'testMulti()'
+    * @param byte arg0 -
+    * @param i32 arg1 -
+    * @param i64 arg2 -
+    * @param map<i16, string> arg3 -
+    * @param Numberz arg4 -
+    * @param UserId arg5 -
+    * @return Xtruct - returns an Xtruct
+    *    with string_thing = "Hello2, byte_thing = arg0, i32_thing = arg1
+    *    and i64_thing = arg2
+    *
+    * @param arg0
+    * @param arg1
+    * @param arg2
+    * @param arg3
+    * @param arg4
+    * @param arg5
+    */
+    public function testMulti(arg0:haxe.Int32, arg1:haxe.Int32, arg2:haxe.Int64,
+        arg3:IntMap<String>, arg4:Int, arg5:haxe.Int64):Xtruct
+    {
+        trace("testMulti()");
+        var hello = new Xtruct();
+        hello.string_thing = "Hello2";
+        hello.byte_thing = arg0;
+        hello.i32_thing = arg1;
+        hello.i64_thing = arg2;
+        return hello;
+    }
+
+    /**
+    * Print 'testException(%s)' with arg as '%s'
+    * @param string arg - a string indication what type of exception to throw
+    * if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
+    * elsen if arg == "TException" throw TException
+    * else do not throw anything
+    *
+    * @param arg
+    */
+    public function testException(arg:String):Void
+    {
+        trace("testException(" + arg + ")");
+        if (arg == "Xception") {
+            var x = new Xception();
+            x.errorCode = 1001;
+            x.message = arg;
+            throw x;
+        };
+        if (arg == "TException") {
+            throw new TException();
+        };
+        return;
+    }
+
+    /**
+    * Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s'
+    * @param string arg - a string indication what type of exception to throw
+    * if arg0 == "Xception"
+    * throw Xception with errorCode = 1001 and message = "This is an Xception"
+    * else if arg0 == "Xception2"
+    * throw Xception2 with errorCode = 2002 and message = "This is an Xception2"
+    * else do not throw anything
+    * @return Xtruct - an Xtruct with string_thing = arg1
+    *
+    * @param arg0
+    * @param arg1
+    */
+    public function testMultiException(arg0:String, arg1:String):Xtruct
+    {
+        trace("testMultiException(" + arg0 + ", " + arg1 + ")");
+        if (arg0 == "Xception") {
+            var x = new Xception();
+            x.errorCode = 1001;
+            x.message = "This is an Xception";
+            throw x;
+        } else if (arg0 == "Xception2") {
+            var x = new Xception2();
+            x.errorCode = 2002;
+            x.struct_thing = new Xtruct();
+            x.struct_thing.string_thing = "This is an Xception2";
+            throw x;
+        };
+        var result = new Xtruct();
+        result.string_thing = arg1;
+        return result;
+    }
+
+    /**
+    * Print 'testOneway(%d): Sleeping...' with secondsToSleep as '%d'
+    * sleep 'secondsToSleep'
+    * Print 'testOneway(%d): done sleeping!' with secondsToSleep as '%d'
+    * @param i32 secondsToSleep - the number of seconds to sleep
+    *
+    * @param secondsToSleep
+    */
+    public function testOneway(secondsToSleep:haxe.Int32):Void
+    {
+        trace("testOneway(" + secondsToSleep + "), sleeping...");
+        Sys.sleep(secondsToSleep);
+        trace("testOneway finished");
+    }
+
+    public function testStop():Void
+    {
+        if (server != null) {
+            server.Stop();
+        };
+    }
+}
diff --git a/test/hs/CMakeLists.txt b/test/hs/CMakeLists.txt
new file mode 100644
index 0000000..eaca3fa
--- /dev/null
+++ b/test/hs/CMakeLists.txt
@@ -0,0 +1,114 @@
+#
+# 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.
+#
+
+set(hs_test_gen
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ConstantsDemo_Consts.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ConstantsDemo_Types.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/DebugProtoTest_Consts.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/DebugProtoTest_Types.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/EmptyService_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/EmptyService.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/EmptyService_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Include_Consts.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Include_Types.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Inherited_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Inherited.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Inherited_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ReverseOrderService_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ReverseOrderService.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ReverseOrderService_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/SecondService_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/SecondService.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/SecondService_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ServiceForExceptionWithAMap_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ServiceForExceptionWithAMap.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ServiceForExceptionWithAMap_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Srv_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Srv.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Srv_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ThriftTest_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ThriftTest_Consts.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ThriftTest.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ThriftTest_Iface.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/ThriftTest_Types.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Yowza_Client.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Yowza.hs
+    ${CMAKE_CURRENT_BINARY_DIR}/gen-hs/Yowza_Iface.hs
+)
+
+set(hs_crosstest_apps
+    ${CMAKE_CURRENT_BINARY_DIR}/TestServer
+    ${CMAKE_CURRENT_BINARY_DIR}/TestClient
+)
+set(hs_crosstest_args
+    -igen-hs
+    -odir=${CMAKE_CURRENT_BINARY_DIR}
+    -hidir=${CMAKE_CURRENT_BINARY_DIR}
+)
+
+if (CMAKE_BUILD_TYPE STREQUAL "Debug")
+  set(hs_optimize -O0)
+else()
+  set(hs_optimize -O1)
+endif()
+
+add_custom_command(
+    OUTPUT ${hs_crosstest_apps}
+    COMMAND ${GHC} ${hs_optimize} ${hs_crosstest_args} ${CMAKE_CURRENT_SOURCE_DIR}/TestServer.hs -o TestServer
+    COMMAND ${GHC} ${hs_optimize} ${hs_crosstest_args} ${CMAKE_CURRENT_SOURCE_DIR}/TestClient.hs -o TestClient
+    DEPENDS ${hs_test_gen} haskell_library TestServer.hs TestClient.hs
+)
+add_custom_target(haskell_crosstest ALL
+    COMMENT "Building Haskell cross test executables"
+    DEPENDS ${hs_crosstest_apps}
+)
+
+set(hs_test_sources
+    ConstantsDemo_Main.hs
+    DebugProtoTest_Main.hs
+    Include_Main.hs
+    ThriftTest_Main.hs
+)
+set(hs_test_args
+    -Wall
+    -XScopedTypeVariables
+    -i${PROJECT_SOURCE_DIR}/lib/hs/src
+    -i${CMAKE_CURRENT_BINARY_DIR}/gen-hs
+)
+add_custom_target(haskell_tests ALL DEPENDS ${hs_test_gen})
+foreach(SRC ${hs_test_sources})
+    get_filename_component(BASE ${SRC} NAME_WE)
+    add_test(NAME HaskellTests-${BASE}
+        COMMAND ${RUN_HASKELL} ${hs_test_args} ${SRC}
+        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+endforeach()
+
+set(hs_test_gen_sources
+    ${PROJECT_SOURCE_DIR}/test/ConstantsDemo.thrift
+    ${PROJECT_SOURCE_DIR}/test/DebugProtoTest.thrift
+    ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
+    ${PROJECT_SOURCE_DIR}/test/Include.thrift
+)
+add_custom_command(OUTPUT ${hs_test_gen}
+    COMMAND ${THRIFT_COMPILER} --gen hs ${PROJECT_SOURCE_DIR}/test/ConstantsDemo.thrift
+    COMMAND ${THRIFT_COMPILER} --gen hs ${PROJECT_SOURCE_DIR}/test/DebugProtoTest.thrift
+    COMMAND ${THRIFT_COMPILER} --gen hs ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
+    COMMAND ${THRIFT_COMPILER} --gen hs ${PROJECT_SOURCE_DIR}/test/Include.thrift
+    DEPENDS ${hs_test_gen_sources}
+)
diff --git a/test/hs/DebugProtoTest_Main.hs b/test/hs/DebugProtoTest_Main.hs
old mode 100755
new mode 100644
index 29393db..fb28963
--- a/test/hs/DebugProtoTest_Main.hs
+++ b/test/hs/DebugProtoTest_Main.hs
@@ -24,7 +24,9 @@
 
 import qualified Control.Exception
 import qualified Data.ByteString.Lazy as DBL
-import qualified Data.Maybe
+import qualified Data.HashMap.Strict as Map
+import qualified Data.HashSet as Set
+import qualified Data.Vector as Vector
 import qualified Network
 
 import Thrift.Protocol.Binary
@@ -61,61 +63,61 @@
     structMethod _ = do
         ThriftTestUtils.serverLog "Got structMethod call"
         return $ Types.CompactProtoTestStruct {
-            Types.f_CompactProtoTestStruct_a_byte = Just 0x01,
-            Types.f_CompactProtoTestStruct_a_i16 = Just 0x02,
-            Types.f_CompactProtoTestStruct_a_i32 = Just 0x03,
-            Types.f_CompactProtoTestStruct_a_i64 = Just 0x04,
-            Types.f_CompactProtoTestStruct_a_double = Just 0.1,
-            Types.f_CompactProtoTestStruct_a_string = Just "abcdef",
-            Types.f_CompactProtoTestStruct_a_binary = Just DBL.empty,
-            Types.f_CompactProtoTestStruct_true_field = Just True,
-            Types.f_CompactProtoTestStruct_false_field = Just False,
-            Types.f_CompactProtoTestStruct_empty_struct_field = Just Types.Empty,
+            Types.compactProtoTestStruct_a_byte = 0x01,
+            Types.compactProtoTestStruct_a_i16 = 0x02,
+            Types.compactProtoTestStruct_a_i32 = 0x03,
+            Types.compactProtoTestStruct_a_i64 = 0x04,
+            Types.compactProtoTestStruct_a_double = 0.1,
+            Types.compactProtoTestStruct_a_string = "abcdef",
+            Types.compactProtoTestStruct_a_binary = DBL.empty,
+            Types.compactProtoTestStruct_true_field = True,
+            Types.compactProtoTestStruct_false_field = False,
+            Types.compactProtoTestStruct_empty_struct_field = Types.Empty,
             
-            Types.f_CompactProtoTestStruct_byte_list = Nothing,
-            Types.f_CompactProtoTestStruct_i16_list = Nothing,
-            Types.f_CompactProtoTestStruct_i32_list = Nothing,
-            Types.f_CompactProtoTestStruct_i64_list = Nothing,
-            Types.f_CompactProtoTestStruct_double_list = Nothing,
-            Types.f_CompactProtoTestStruct_string_list = Nothing,
-            Types.f_CompactProtoTestStruct_binary_list = Nothing,
-            Types.f_CompactProtoTestStruct_boolean_list = Nothing,
-            Types.f_CompactProtoTestStruct_struct_list = Nothing,
+            Types.compactProtoTestStruct_byte_list = Vector.empty,
+            Types.compactProtoTestStruct_i16_list = Vector.empty,
+            Types.compactProtoTestStruct_i32_list = Vector.empty,
+            Types.compactProtoTestStruct_i64_list = Vector.empty,
+            Types.compactProtoTestStruct_double_list = Vector.empty,
+            Types.compactProtoTestStruct_string_list = Vector.empty,
+            Types.compactProtoTestStruct_binary_list = Vector.empty,
+            Types.compactProtoTestStruct_boolean_list = Vector.empty,
+            Types.compactProtoTestStruct_struct_list = Vector.empty,
 
-            Types.f_CompactProtoTestStruct_byte_set = Nothing,
-            Types.f_CompactProtoTestStruct_i16_set = Nothing,
-            Types.f_CompactProtoTestStruct_i32_set = Nothing,
-            Types.f_CompactProtoTestStruct_i64_set = Nothing,
-            Types.f_CompactProtoTestStruct_double_set = Nothing,
-            Types.f_CompactProtoTestStruct_string_set = Nothing,
-            Types.f_CompactProtoTestStruct_binary_set = Nothing,
-            Types.f_CompactProtoTestStruct_boolean_set = Nothing,
-            Types.f_CompactProtoTestStruct_struct_set = Nothing,
+            Types.compactProtoTestStruct_byte_set = Set.empty,
+            Types.compactProtoTestStruct_i16_set = Set.empty,
+            Types.compactProtoTestStruct_i32_set = Set.empty,
+            Types.compactProtoTestStruct_i64_set = Set.empty,
+            Types.compactProtoTestStruct_double_set = Set.empty,
+            Types.compactProtoTestStruct_string_set = Set.empty,
+            Types.compactProtoTestStruct_binary_set = Set.empty,
+            Types.compactProtoTestStruct_boolean_set = Set.empty,
+            Types.compactProtoTestStruct_struct_set = Set.empty,
 
-            Types.f_CompactProtoTestStruct_byte_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_i16_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_i32_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_i64_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_double_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_string_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_binary_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_boolean_byte_map = Nothing,
+            Types.compactProtoTestStruct_byte_byte_map = Map.empty,
+            Types.compactProtoTestStruct_i16_byte_map = Map.empty,
+            Types.compactProtoTestStruct_i32_byte_map = Map.empty,
+            Types.compactProtoTestStruct_i64_byte_map = Map.empty,
+            Types.compactProtoTestStruct_double_byte_map = Map.empty,
+            Types.compactProtoTestStruct_string_byte_map = Map.empty,
+            Types.compactProtoTestStruct_binary_byte_map = Map.empty,
+            Types.compactProtoTestStruct_boolean_byte_map = Map.empty,
 
-            Types.f_CompactProtoTestStruct_byte_i16_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_i32_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_i64_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_double_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_string_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_binary_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_boolean_map = Nothing,
+            Types.compactProtoTestStruct_byte_i16_map = Map.empty,
+            Types.compactProtoTestStruct_byte_i32_map = Map.empty,
+            Types.compactProtoTestStruct_byte_i64_map = Map.empty,
+            Types.compactProtoTestStruct_byte_double_map = Map.empty,
+            Types.compactProtoTestStruct_byte_string_map = Map.empty,
+            Types.compactProtoTestStruct_byte_binary_map = Map.empty,
+            Types.compactProtoTestStruct_byte_boolean_map = Map.empty,
 
-            Types.f_CompactProtoTestStruct_list_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_set_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_map_byte_map = Nothing,
+            Types.compactProtoTestStruct_list_byte_map = Map.empty,
+            Types.compactProtoTestStruct_set_byte_map = Map.empty,
+            Types.compactProtoTestStruct_map_byte_map = Map.empty,
 
-            Types.f_CompactProtoTestStruct_byte_map_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_set_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_list_map = Nothing }
+            Types.compactProtoTestStruct_byte_map_map = Map.empty,
+            Types.compactProtoTestStruct_byte_set_map = Map.empty,
+            Types.compactProtoTestStruct_byte_list_map = Map.empty }
 
     methodWithDefaultArgs _ arg = do
         ThriftTestUtils.serverLog $ "Got methodWithDefaultArgs: " ++ show arg
@@ -127,7 +129,7 @@
 instance IIface.Inherited_Iface InheritedHandler where
     identity _ arg = do
         ThriftTestUtils.serverLog $ "Got identity method: " ++ show arg
-        return $ Data.Maybe.fromJust arg
+        return arg
 
 client :: (String, Network.PortID) -> IO ()
 client addr = do
diff --git a/test/hs/Include_Main.hs b/test/hs/Include_Main.hs
new file mode 100644
index 0000000..d3977a1
--- /dev/null
+++ b/test/hs/Include_Main.hs
@@ -0,0 +1,7 @@
+module Main where
+
+import Include_Types
+import ThriftTest_Types
+
+main :: IO ()
+main = putStrLn ("Includes work: " ++ (show (IncludeTest $ Bools True False)))
diff --git a/test/hs/Makefile.am b/test/hs/Makefile.am
index d6d8ff4..1748906 100644
--- a/test/hs/Makefile.am
+++ b/test/hs/Makefile.am
@@ -17,14 +17,25 @@
 # under the License.
 #
 
-THRIFT = $(top_srcdir)/compiler/cpp/thrift
-
-stubs: ../ConstantsDemo.thrift ../DebugProtoTest.thrift ../ThriftTest.thrift
+stubs: $(THRIFT) ../ConstantsDemo.thrift ../DebugProtoTest.thrift ../ThriftTest.thrift ../Include.thrift
 	$(THRIFT) --gen hs ../ConstantsDemo.thrift
 	$(THRIFT) --gen hs ../DebugProtoTest.thrift
 	$(THRIFT) --gen hs ../ThriftTest.thrift
+	$(THRIFT) --gen hs ../Include.thrift
 
 check: stubs
 	sh run-test.sh ConstantsDemo
 	sh run-test.sh DebugProtoTest
 	sh run-test.sh ThriftTest
+	sh run-test.sh Include
+
+clean-local:
+	$(RM) -r gen-hs
+	$(RM) *.hi
+	$(RM) *.o
+
+all-local: stubs
+	ghc -igen-hs TestServer.hs
+	ghc -igen-hs TestClient.hs
+
+precross: all-local
diff --git a/test/hs/TestClient.hs b/test/hs/TestClient.hs
new file mode 100644
index 0000000..93fb591
--- /dev/null
+++ b/test/hs/TestClient.hs
@@ -0,0 +1,306 @@
+--
+-- 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.
+--
+
+{-# LANGUAGE OverloadedStrings, RecordWildCards, ScopedTypeVariables #-}
+module Main where
+
+import Control.Exception
+import Control.Monad
+import Data.Functor
+import Data.List.Split
+import Data.String
+import Network
+import Network.URI
+import System.Environment
+import System.Exit
+import qualified Data.ByteString.Lazy as LBS
+import qualified Data.HashMap.Strict as Map
+import qualified Data.HashSet as Set
+import qualified Data.Vector as Vector
+import qualified System.IO as IO
+
+import ThriftTest_Iface
+import ThriftTest_Types
+import qualified ThriftTest_Client as Client
+
+import Thrift.Transport
+import Thrift.Transport.Framed
+import Thrift.Transport.Handle
+import Thrift.Transport.HttpClient
+import Thrift.Protocol
+import Thrift.Protocol.Binary
+import Thrift.Protocol.Compact
+import Thrift.Protocol.Header
+import Thrift.Protocol.JSON
+
+data Options = Options
+  { host         :: String
+  , port         :: Int
+  , domainSocket :: String
+  , transport    :: String
+  , protocol     :: ProtocolType
+  -- TODO: Haskell lib does not have SSL support
+  , ssl          :: Bool
+  , testLoops    :: Int
+  }
+  deriving (Show, Eq)
+
+data TransportType = Buffered IO.Handle
+                   | Framed (FramedTransport IO.Handle)
+                   | Http HttpClient
+                   | NoTransport String
+
+getTransport :: String -> String -> Int -> (IO TransportType)
+getTransport "buffered" host port = do
+  h <- hOpen (host, PortNumber $ fromIntegral port)
+  IO.hSetBuffering h $ IO.BlockBuffering Nothing
+  return $ Buffered h
+getTransport "framed" host port = do
+  h <- hOpen (host, PortNumber $ fromIntegral port)
+  t <- openFramedTransport h
+  return $ Framed t
+getTransport "http" host port = let uriStr = "http://" ++ host ++ ":" ++ show port in
+                                case parseURI uriStr of
+                                  Nothing -> do return (NoTransport $ "Failed to parse URI: " ++ uriStr)
+                                  Just(uri) -> do
+                                    t <- openHttpClient uri
+                                    return $ Http t
+getTransport t host port = do return (NoTransport $ "Unsupported transport: " ++ t)
+
+data ProtocolType = Binary
+                  | Compact
+                  | JSON
+                  | Header
+                  deriving (Show, Eq)
+
+getProtocol :: String -> ProtocolType
+getProtocol "binary"  = Binary
+getProtocol "compact" = Compact
+getProtocol "json"    = JSON
+getProtocol "header" = Header
+getProtocol p = error $ "Unsupported Protocol: " ++ p
+
+defaultOptions :: Options
+defaultOptions = Options
+  { port         = 9090
+  , domainSocket = ""
+  , host         = "localhost"
+  , transport    = "buffered"
+  , protocol     = Binary
+  , ssl          = False
+  , testLoops    = 1
+  }
+
+runClient :: Protocol p => p -> IO ()
+runClient p = do
+  let prot = (p,p)
+  putStrLn "Starting Tests"
+
+  -- VOID Test
+  putStrLn "testVoid"
+  Client.testVoid prot
+
+  -- String Test
+  putStrLn "testString"
+  s <- Client.testString prot "Test"
+  when (s /= "Test") exitFailure
+
+  -- Bool Test
+  putStrLn "testBool"
+  bool <- Client.testBool prot True
+  when (not bool) exitFailure
+  putStrLn "testBool"
+  bool <- Client.testBool prot False
+  when (bool) exitFailure
+
+  -- Byte Test
+  putStrLn "testByte"
+  byte <- Client.testByte prot 1
+  when (byte /= 1) exitFailure
+
+  -- I32 Test
+  putStrLn "testI32"
+  i32 <- Client.testI32 prot (-1)
+  when (i32 /= -1) exitFailure
+
+  -- I64 Test
+  putStrLn "testI64"
+  i64 <- Client.testI64 prot (-34359738368)
+  when (i64 /= -34359738368) exitFailure
+
+  -- Double Test
+  putStrLn "testDouble"
+  dub <- Client.testDouble prot (-5.2098523)
+  when (abs (dub + 5.2098523) > 0.001) exitFailure
+
+  -- Binary Test
+  putStrLn "testBinary"
+  bin <- Client.testBinary prot (LBS.pack . reverse $ [-128..127])
+  when ((reverse [-128..127]) /= LBS.unpack bin) exitFailure
+  
+  -- Struct Test
+  let structIn = Xtruct{ xtruct_string_thing = "Zero"
+                       , xtruct_byte_thing   = 1
+                       , xtruct_i32_thing    = -3
+                       , xtruct_i64_thing    = -5
+                       }
+  putStrLn "testStruct"
+  structOut <- Client.testStruct prot structIn
+  when (structIn /= structOut) exitFailure
+
+  -- Nested Struct Test
+  let nestIn = Xtruct2{ xtruct2_byte_thing   = 1
+                      , xtruct2_struct_thing = structIn
+                      , xtruct2_i32_thing    = 5
+                      }
+  putStrLn "testNest"
+  nestOut <- Client.testNest prot nestIn
+  when (nestIn /= nestOut) exitFailure
+
+  -- Map Test
+  let mapIn = Map.fromList $ map (\i -> (i, i-10)) [1..5]
+  putStrLn "testMap"
+  mapOut <- Client.testMap prot mapIn
+  when (mapIn /= mapOut) exitFailure
+
+  -- Set Test
+  let setIn = Set.fromList [-2..3]
+  putStrLn "testSet"
+  setOut <- Client.testSet prot setIn
+  when (setIn /= setOut) exitFailure
+
+  -- List Test
+  let listIn = Vector.fromList [-2..3]
+  putStrLn "testList"
+  listOut <- Client.testList prot listIn
+  when (listIn /= listOut) exitFailure
+
+  -- Enum Test
+  putStrLn "testEnum"
+  numz1 <- Client.testEnum prot ONE
+  when (numz1 /= ONE) exitFailure
+
+  putStrLn "testEnum"
+  numz2 <- Client.testEnum prot TWO
+  when (numz2 /= TWO) exitFailure
+
+  putStrLn "testEnum"
+  numz5 <- Client.testEnum prot FIVE
+  when (numz5 /= FIVE) exitFailure
+
+  -- Typedef Test
+  putStrLn "testTypedef"
+  uid <- Client.testTypedef prot 309858235082523
+  when (uid /= 309858235082523) exitFailure
+
+  -- Nested Map Test
+  putStrLn "testMapMap"
+  _ <- Client.testMapMap prot 1
+
+  -- Exception Test
+  putStrLn "testException"
+  exn1 <- try $ Client.testException prot "Xception"
+  case exn1 of
+    Left (Xception _ _) -> return ()
+    _ -> putStrLn (show exn1) >> exitFailure
+
+  putStrLn "testException"
+  exn2 <- try $ Client.testException prot "TException"
+  case exn2 of
+    Left (_ :: SomeException) -> return ()
+    Right _ -> exitFailure
+
+  putStrLn "testException"
+  exn3 <- try $ Client.testException prot "success"
+  case exn3 of
+    Left (_ :: SomeException) -> exitFailure
+    Right _ -> return ()
+
+  -- Multi Exception Test
+  putStrLn "testMultiException"
+  multi1 <- try $ Client.testMultiException prot "Xception" "test 1"
+  case multi1 of
+    Left (Xception _ _) -> return ()
+    _ -> exitFailure
+
+  putStrLn "testMultiException"
+  multi2 <- try $ Client.testMultiException prot "Xception2" "test 2"
+  case multi2 of
+    Left (Xception2 _ _) -> return ()
+    _ -> exitFailure
+
+  putStrLn "testMultiException"
+  multi3 <- try $ Client.testMultiException prot "success" "test 3"
+  case multi3 of
+    Left (_ :: SomeException) -> exitFailure
+    Right _ -> return ()
+
+
+main :: IO ()
+main = do
+  options <- flip parseFlags defaultOptions <$> getArgs
+  case options of
+    Nothing -> showHelp
+    Just Options{..} -> do
+      trans <- Main.getTransport transport host port
+      case trans of
+        Buffered t -> runTest testLoops protocol t
+        Framed t   -> runTest testLoops protocol t
+        Http t     -> runTest testLoops protocol t
+        NoTransport err -> putStrLn err
+  where
+    makeClient p t = case p of
+                       Binary  -> runClient $ BinaryProtocol t
+                       Compact -> runClient $ CompactProtocol t
+                       JSON    -> runClient $ JSONProtocol t
+                       Header  -> createHeaderProtocol t t >>= runClient
+    runTest loops p t = do
+      let client = makeClient p t
+      replicateM_ loops client
+      putStrLn "COMPLETED SUCCESSFULLY"
+
+parseFlags :: [String] -> Options -> Maybe Options
+parseFlags (flag : flags) opts = do
+  let pieces = splitOn "=" flag
+  case pieces of
+    "--port" : arg : _ -> parseFlags flags opts{ port = read arg }
+    "--domain-socket" : arg : _ -> parseFlags flags opts{ domainSocket = read arg }
+    "--host" : arg : _ -> parseFlags flags opts{ host = arg }
+    "--transport" : arg : _ -> parseFlags flags opts{ transport = arg }
+    "--protocol" : arg : _ -> parseFlags flags opts{ protocol = getProtocol arg }
+    "-n" : arg : _ -> parseFlags flags opts{ testLoops = read arg }
+    "--h" : _ -> Nothing
+    "--help" : _ -> Nothing
+    "--ssl" : _ -> parseFlags flags opts{ ssl = True }
+    "--processor-events" : _ -> parseFlags flags opts
+    _ -> Nothing
+parseFlags [] opts = Just opts
+
+showHelp :: IO ()
+showHelp = putStrLn
+  "Allowed options:\n\
+  \  -h [ --help ]               produce help message\n\
+  \  --host arg (=localhost)     Host to connect\n\
+  \  --port arg (=9090)          Port number to connect\n\
+  \  --domain-socket arg         Domain Socket (e.g. /tmp/ThriftTest.thrift),\n\
+  \                              instead of host and port\n\
+  \  --transport arg (=buffered) Transport: buffered, framed, http\n\
+  \  --protocol arg (=binary)    Protocol: binary, compact, json\n\
+  \  --ssl                       Encrypted Transport using SSL\n\
+  \  -n [ --testloops ] arg (=1) Number of Tests"
diff --git a/test/hs/TestServer.hs b/test/hs/TestServer.hs
new file mode 100644
index 0000000..b7731ab
--- /dev/null
+++ b/test/hs/TestServer.hs
@@ -0,0 +1,312 @@
+--
+-- 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.
+--
+
+{-# LANGUAGE OverloadedStrings,RecordWildCards #-}
+module Main where
+
+import Control.Exception
+import Control.Monad
+import Data.Functor
+import Data.HashMap.Strict (HashMap)
+import Data.List
+import Data.List.Split
+import Data.String
+import Network
+import System.Environment
+import System.Exit
+import System.IO
+import Control.Concurrent (threadDelay)
+import qualified System.IO as IO
+import qualified Data.HashMap.Strict as Map
+import qualified Data.HashSet as Set
+import qualified Data.Text.Lazy as Text
+import qualified Data.Vector as Vector
+
+import ThriftTest
+import ThriftTest_Iface
+import ThriftTest_Types
+
+import Thrift
+import Thrift.Server
+import Thrift.Transport.Framed
+import Thrift.Transport.Handle
+import Thrift.Protocol.Binary
+import Thrift.Protocol.Compact
+import Thrift.Protocol.Header
+import Thrift.Protocol.JSON
+
+data Options = Options
+  { port         :: Int
+  , domainSocket :: String
+  , serverType   :: ServerType
+  , transport    :: String
+  , protocol     :: ProtocolType
+  , ssl          :: Bool
+  , workers      :: Int
+  }
+
+data ServerType = Simple
+                | ThreadPool
+                | Threaded
+                | NonBlocking
+                deriving (Show, Eq)
+
+instance IsString ServerType where
+  fromString "simple"      = Simple
+  fromString "thread-pool" = ThreadPool
+  fromString "threaded"    = Threaded
+  fromString "nonblocking" = NonBlocking
+  fromString _ = error "not a valid server type"
+
+data TransportType = Buffered (Socket -> (IO IO.Handle))
+                   | Framed (Socket -> (IO (FramedTransport IO.Handle)))
+                   | NoTransport String
+
+getTransport :: String -> TransportType
+getTransport "buffered" = Buffered $ \s -> do
+  (h, _, _) <- (accept s)
+  IO.hSetBuffering h $ IO.BlockBuffering Nothing
+  return h
+getTransport "framed" = Framed $ \s -> do
+  (h, _, _) <- (accept s)
+  openFramedTransport h
+getTransport t = NoTransport $ "Unsupported transport: " ++ t
+
+data ProtocolType = Binary
+                  | Compact
+                  | JSON
+                  | Header
+
+getProtocol :: String -> ProtocolType
+getProtocol "binary"  = Binary
+getProtocol "compact" = Compact
+getProtocol "json"    = JSON
+getProtocol "header"  = Header
+getProtocol p = error $"Unsupported Protocol: " ++ p
+
+defaultOptions :: Options
+defaultOptions = Options
+  { port         = 9090
+  , domainSocket = ""
+  , serverType   = Threaded
+  , transport    = "buffered"
+  , protocol     = Binary
+  -- TODO: Haskell lib does not have SSL support
+  , ssl          = False
+  , workers      = 4
+  }
+
+stringifyMap :: (Show a, Show b) => Map.HashMap a b -> String
+stringifyMap = Data.List.intercalate ", " . Data.List.map joinKV . Map.toList
+  where joinKV (k, v) = show k ++ " => " ++ show v
+
+stringifySet :: Show a => Set.HashSet a -> String
+stringifySet = Data.List.intercalate ", " . Data.List.map show . Set.toList
+
+stringifyList :: Show a => Vector.Vector a -> String
+stringifyList = Data.List.intercalate ", " . Data.List.map show . Vector.toList
+
+data TestHandler = TestHandler
+instance ThriftTest_Iface TestHandler where
+  testVoid _ = System.IO.putStrLn "testVoid()"
+
+  testString _ s = do
+    System.IO.putStrLn $ "testString(" ++ show s ++ ")"
+    return s
+
+  testBool _ x = do
+    System.IO.putStrLn $ "testBool(" ++ show x ++ ")"
+    return x
+
+  testByte _ x = do
+    System.IO.putStrLn $ "testByte(" ++ show x ++ ")"
+    return x
+
+  testI32 _ x = do
+    System.IO.putStrLn $ "testI32(" ++ show x ++ ")"
+    return x
+
+  testI64 _ x = do
+    System.IO.putStrLn $ "testI64(" ++ show x ++ ")"
+    return x
+
+  testDouble _ x = do
+    System.IO.putStrLn $ "testDouble(" ++ show x ++ ")"
+    return x
+
+  testBinary _ x = do
+    System.IO.putStrLn $ "testBinary(" ++ show x ++ ")"
+    return x
+
+  testStruct _ struct@Xtruct{..} = do
+    System.IO.putStrLn $ "testStruct({" ++ show xtruct_string_thing
+                      ++ ", " ++ show xtruct_byte_thing
+                      ++ ", " ++ show xtruct_i32_thing
+                      ++ ", " ++ show xtruct_i64_thing
+                      ++ "})"
+    return struct
+
+  testNest _ nest@Xtruct2{..} = do
+    let Xtruct{..} = xtruct2_struct_thing
+    System.IO.putStrLn $ "testNest({" ++ show xtruct2_byte_thing
+                   ++ "{, " ++ show xtruct_string_thing
+                   ++  ", " ++ show xtruct_byte_thing
+                   ++  ", " ++ show xtruct_i32_thing
+                   ++  ", " ++ show xtruct_i64_thing
+                   ++ "}, " ++ show xtruct2_i32_thing
+    return nest
+
+  testMap _ m = do
+    System.IO.putStrLn $ "testMap({" ++ stringifyMap m ++ "})"
+    return m
+
+  testStringMap _ m = do
+    System.IO.putStrLn $ "testStringMap(" ++ stringifyMap m ++ "})"
+    return m
+
+  testSet _ x = do
+    System.IO.putStrLn $ "testSet({" ++ stringifySet x ++ "})"
+    return x
+
+  testList _ x = do
+    System.IO.putStrLn $ "testList(" ++ stringifyList x ++ "})"
+    return x
+
+  testEnum _ x = do
+    System.IO.putStrLn $ "testEnum(" ++ show x ++ ")"
+    return x
+
+  testTypedef _ x = do
+    System.IO.putStrLn $ "testTypedef(" ++ show x ++ ")"
+    return x
+
+  testMapMap _ x = do
+    System.IO.putStrLn $ "testMapMap(" ++ show x ++ ")"
+    return $ Map.fromList [ (-4, Map.fromList [ (-4, -4)
+                                              , (-3, -3)
+                                              , (-2, -2)
+                                              , (-1, -1)
+                                              ])
+                          , (4,  Map.fromList [ (1, 1)
+                                              , (2, 2)
+                                              , (3, 3)
+                                              , (4, 4)
+                                              ])
+                          ]
+
+  testInsanity _ x = do
+    System.IO.putStrLn "testInsanity()"
+    return $ Map.fromList [ (1, Map.fromList [ (TWO  , x)
+                                             , (THREE, x)
+                                             ])
+                          , (2, Map.fromList [ (SIX, default_Insanity)
+                                             ])
+                          ]
+
+  testMulti _ byte i32 i64 _ _ _ = do
+    System.IO.putStrLn "testMulti()"
+    return Xtruct{ xtruct_string_thing = Text.pack "Hello2"
+                 , xtruct_byte_thing   = byte
+                 , xtruct_i32_thing    = i32
+                 , xtruct_i64_thing    = i64
+                 }
+
+  testException _ s = do
+    System.IO.putStrLn $ "testException(" ++ show s ++ ")"
+    case s of
+      "Xception"   -> throw $ Xception 1001 s
+      "TException" -> throw ThriftException
+      _ -> return ()
+
+  testMultiException _ s1 s2 = do
+    System.IO.putStrLn $ "testMultiException(" ++ show s1 ++ ", " ++ show s2 ++  ")"
+    case s1 of
+      "Xception"   -> throw $ Xception 1001 "This is an Xception"
+      "Xception2"  -> throw $ Xception2 2002 $ Xtruct "This is an Xception2" 0 0 0
+      "TException" -> throw ThriftException
+      _ -> return default_Xtruct{ xtruct_string_thing = s2 }
+
+  testOneway _ i = do
+    System.IO.putStrLn $ "testOneway(" ++ show i ++ "): Sleeping..."
+    threadDelay $ (fromIntegral i) * 1000000
+    System.IO.putStrLn $ "testOneway(" ++ show i ++ "): done sleeping!"
+
+main :: IO ()
+main = do
+  options <- flip parseFlags defaultOptions <$> getArgs
+  case options of
+    Nothing -> showHelp
+    Just Options{..} -> do
+      case Main.getTransport transport of
+        Buffered f -> runServer protocol f port
+        Framed   f -> runServer protocol f port
+        NoTransport err -> putStrLn err
+      System.IO.putStrLn $ "Starting \"" ++ show serverType ++ "\" server (" ++
+        show transport ++ ") listen on: " ++ domainSocket ++ show port
+      where
+        acceptor p f socket = do
+          t <- f socket
+          return (p t, p t)
+
+        headerAcceptor f socket = do
+          t <- f socket
+          p <- createHeaderProtocol1 t
+          return (p, p)
+
+        doRunServer p f = do
+          runThreadedServer (acceptor p f) TestHandler ThriftTest.process . PortNumber . fromIntegral
+
+        runServer p f port = case p of
+          Binary  -> doRunServer BinaryProtocol f port
+          Compact -> doRunServer CompactProtocol f port
+          JSON    -> doRunServer JSONProtocol f port
+          Header  -> runThreadedServer (headerAcceptor f) TestHandler ThriftTest.process (PortNumber $ fromIntegral port)
+
+parseFlags :: [String] -> Options -> Maybe Options
+parseFlags (flag : flags) opts = do
+  let pieces = splitOn "=" flag
+  case pieces of
+    "--port" : arg : _ -> parseFlags flags opts{ port = read arg }
+    "--domain-socket" : arg : _ -> parseFlags flags opts{ domainSocket = read arg }
+    "--server-type" : arg : _ -> parseFlags flags opts{ serverType = fromString arg }
+    "--transport" : arg : _ -> parseFlags flags opts{ transport = arg }
+    "--protocol" : arg : _ -> parseFlags flags opts{ protocol = getProtocol arg }
+    "--workers" : arg : _ -> parseFlags flags opts{ workers = read arg }
+    "-n" : arg : _ -> parseFlags flags opts{ workers = read arg }
+    "--h" : _ -> Nothing
+    "--help" : _ -> Nothing
+    "--ssl" : _ -> parseFlags flags opts{ ssl = True }
+    "--processor-events" : _ -> parseFlags flags opts
+    _ -> Nothing
+parseFlags [] opts = Just opts
+
+showHelp :: IO ()
+showHelp = System.IO.putStrLn
+  "Allowed options:\n\
+  \  -h [ --help ]               produce help message\n\
+  \  --port arg (=9090)          Port number to listen\n\
+  \  --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)\n\
+  \  --server-type arg (=simple) type of server, \"simple\", \"thread-pool\",\n\
+  \                              \"threaded\", or \"nonblocking\"\n\
+  \  --transport arg (=buffered) transport: buffered, framed\n\
+  \  --protocol arg (=binary)    protocol: binary, compact, json\n\
+  \  --ssl                       Encrypted Transport using SSL\n\
+  \  --processor-events          processor-events\n\
+  \  -n [ --workers ] arg (=4)   Number of thread pools workers. Only valid for\n\
+  \                              thread-pool server type"
diff --git a/test/hs/ThriftTestUtils.hs b/test/hs/ThriftTestUtils.hs
index 93fa122..9c19b56 100644
--- a/test/hs/ThriftTestUtils.hs
+++ b/test/hs/ThriftTestUtils.hs
@@ -60,6 +60,6 @@
     Control.Concurrent.threadDelay $ 500 * 1000 -- unit is in _micro_seconds
     Control.Concurrent.yield
 
-    _ <- client serverAddress
+    client serverAddress
 
     testLog "SUCCESS"
diff --git a/test/hs/ThriftTest_Main.hs b/test/hs/ThriftTest_Main.hs
old mode 100755
new mode 100644
index 3612935..670023e
--- a/test/hs/ThriftTest_Main.hs
+++ b/test/hs/ThriftTest_Main.hs
@@ -47,124 +47,80 @@
 instance Iface.ThriftTest_Iface TestHandler where
     testVoid _ = return ()
 
-    testString _ (Just s) = do
+    testString _ s = do
         ThriftTestUtils.serverLog $ show s
         return s
 
-    testString _ Nothing = do
-        error $ "Unsupported testString form"
-
-    testByte _ (Just x) = do
+    testByte _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testByte _ Nothing = do
-        error $ "Unsupported testByte form"
-
-    testI32 _ (Just x) = do
+    testI32 _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testI32 _ Nothing = do
-        error $ "Unsupported testI32 form"
-
-    testI64 _ (Just x) = do
+    testI64 _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testI64 _ Nothing = do
-        error $ "Unsupported testI64 form"
-
-    testDouble _ (Just x) = do
+    testDouble _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testDouble _ Nothing = do
-        error $ "Unsupported testDouble form"
-
-    testStruct _ (Just x) = do
+    testBinary _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testStruct _ Nothing = do
-        error $ "Unsupported testStruct form"
-
-    testNest _ (Just x) = do
+    testStruct _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testNest _ Nothing = do
-        error $ "Unsupported testNest form"
-
-    testMap _ (Just x) = do
+    testNest _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testMap _ Nothing = do
-        error $ "Unsupported testMap form"
-
-    testStringMap _ (Just x) = do
+    testMap _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testStringMap _ Nothing = do
-        error $ "Unsupported testMap form"
-
-    testSet _ (Just x) = do
+    testStringMap _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testSet _ Nothing = do
-        error $ "Unsupported testSet form"
-
-    testList _ (Just x) = do
+    testSet _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testList _ Nothing = do
-        error $ "Unsupported testList form"
-
-    testEnum _ (Just x) = do
+    testList _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testEnum _ Nothing = do
-        error $ "Unsupported testEnum form"
-
-    testTypedef _ (Just x) = do
+    testEnum _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testTypedef _ Nothing = do
-        error $ "Unsupported testTypedef form"
+    testTypedef _ x = do
+        ThriftTestUtils.serverLog $ show x
+        return x
 
-    testMapMap _ (Just _) = do
+    testMapMap _ _ = do
         return (Map.fromList [(1, Map.fromList [(2, 2)])])
 
-    testMapMap _ Nothing = do
-        error $ "Unsupported testMapMap form"
-
-    testInsanity _ (Just x) = do
+    testInsanity _ x = do
         return (Map.fromList [(1, Map.fromList [(Types.ONE, x)])])
 
-    testInsanity _ Nothing = do
-        error $ "Unsupported testInsanity form"
-
     testMulti _ _ _ _ _ _ _ = do
-        return (Types.Xtruct Nothing Nothing Nothing Nothing)
+        return (Types.Xtruct "" 0 0 0)
 
     testException _ _ = do
-        Control.Exception.throw (Types.Xception (Just 1) (Just "bya"))
+        Control.Exception.throw (Types.Xception 1 "bya")
 
     testMultiException _ _ _ = do
-        Control.Exception.throw (Types.Xception (Just 1) (Just "xyz"))
+        Control.Exception.throw (Types.Xception 1 "xyz")
 
-    testOneway _ (Just i) = do
+    testOneway _ i = do
         ThriftTestUtils.serverLog $ show i
 
-    testOneway _ Nothing = do
-        error $ "Unsupported testOneway form"
-
 
 client :: (String, Network.PortID) -> IO ()
 client addr = do
@@ -198,6 +154,8 @@
     v9 <- Client.testDouble ps (-3.14)
     ThriftTestUtils.clientLog $ show v9
 
+    -- TODO: Client.testBinary ...
+	
     v10 <- Client.testMap ps (Map.fromList [(1,1),(2,2),(3,3)])
     ThriftTestUtils.clientLog $ show v10
 
@@ -210,7 +168,7 @@
     v13 <- Client.testSet ps (Set.fromList [1,2,3,4,5])
     ThriftTestUtils.clientLog $ show v13
 
-    v14 <- Client.testStruct ps (Types.Xtruct (Just "hi") (Just 4) (Just 5) Nothing)
+    v14 <- Client.testStruct ps (Types.Xtruct "hi" 4 5 0)
     ThriftTestUtils.clientLog $ show v14
 
     (testException ps "bad") `Control.Exception.catch` testExceptionHandler
@@ -222,7 +180,7 @@
 
     tClose to
   where testException ps msg = do
-            Client.testException ps "e"
+            _ <- Client.testException ps "e"
             ThriftTestUtils.clientLog msg
             return ()
 
diff --git a/test/hs/run-test.sh b/test/hs/run-test.sh
old mode 100644
new mode 100755
index ac5190d..ecafc18
--- a/test/hs/run-test.sh
+++ b/test/hs/run-test.sh
@@ -29,30 +29,6 @@
     BASE=../..
 fi
 
-if [ -z $THRIFT_BIN ]; then
-    THRIFT_BIN=$BASE/compiler/cpp/thrift 
-fi
-
-if [ ! -x "$THRIFT_BIN" ]; then
-    printf "Could not find thrift binary; pass it as environment variable THRIFT_BIN\n"
-    exit 1
-fi
-
-# Figure out what file to generate bindings from
-if [ -z $THRIFT_FILE ]; then
-    THRIFT_FILE=$BASE/test/$1.thrift
-fi
-
-if [ ! -e $THRIFT_FILE ]; then
-    printf "Missing thrift file $THRIFT_FILE \n"
-    exit 2
-fi
-
-if [ ! -e "$THRIFT_FILE" ]; then
-    printf "Could not find thrift file to run; pass it as environment variable THRIFT_FILE\n"
-    exit 1
-fi
-
 # Figure out what file to run has a server
 if [ -z $TEST_SOURCE_FILE ]; then
     TEST_SOURCE_FILE=$BASE/test/hs/$1_Main.hs
@@ -63,9 +39,5 @@
     exit 3
 fi
 
-# Actually run the server bits
-printf "Generating bindings... \n"
-$THRIFT_BIN --gen hs $THRIFT_FILE
-
 printf "Running test... \n"
-runhaskell -Wall -i$BASE/lib/hs/src -igen-hs $TEST_SOURCE_FILE
+runhaskell -Wall -XScopedTypeVariables -i$BASE/lib/hs/src -igen-hs $TEST_SOURCE_FILE
diff --git a/test/index.html b/test/index.html
new file mode 100644
index 0000000..3611a92
--- /dev/null
+++ b/test/index.html
@@ -0,0 +1,51 @@
+<!--
+ 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.
+
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Apache Thrift - integration test suite</title>
+<link rel="stylesheet" type="text/css" href="http://cdn.datatables.net/1.10.4/css/jquery.dataTables.css">
+<script type="text/javascript" charset="utf-8" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
+<script type="text/javascript" charset="utf-8" src="http://cdn.datatables.net/1.10.4/js/jquery.dataTables.js"></script>
+<script src="result.js">
+</script>
+</head>
+<body>
+<h2>Apache Thrift - integration test suite: Results</h2>
+<table id="test_results" class="display">
+    <thead>
+        <tr>
+            <th>Server</th>
+            <th>Client</th>
+            <th>Protocol</th>
+            <th>Transport</th>
+            <th>Result (log)</th>
+            <th>Expected</th>
+        </tr>
+    </thead>
+</table>
+<h2>Test Information</h2>
+<pre id="test_info"></pre>
+
+<a href="log">browse raw log</a>
+
+</body>
+</html>
diff --git a/test/keys/CA.pem b/test/keys/CA.pem
new file mode 100644
index 0000000..a747b9a
--- /dev/null
+++ b/test/keys/CA.pem
@@ -0,0 +1,82 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 16582080088954381212 (0xe61f61fc3b34239c)
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, ST=Maryland, L=Forest Hill, O=The Apache Software Foundation, OU=Apache Thrift, CN=localhost/emailAddress=dev@thrift.apache.org
+        Validity
+            Not Before: Apr  7 18:58:00 2014 GMT
+            Not After : Jun 24 18:58:00 2022 GMT
+        Subject: C=US, ST=Maryland, L=Forest Hill, O=The Apache Software Foundation, OU=Apache Thrift, CN=localhost/emailAddress=dev@thrift.apache.org
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:aa:13:d4:c4:f7:01:17:a7:92:d1:b4:b4:15:0d:
+                    21:90:19:5e:fc:fb:b6:6d:3f:f2:3f:65:a2:7a:43:
+                    a6:46:95:fc:43:16:f6:63:14:5e:f7:b1:e3:61:02:
+                    f9:4a:95:89:bf:8d:f9:48:1d:82:e7:34:e0:b2:48:
+                    df:08:d9:7c:3a:2f:d3:1b:0b:e8:ef:c2:41:0a:7d:
+                    0a:38:78:3a:31:66:73:99:8c:d1:79:27:5f:e5:66:
+                    d0:5e:3a:8c:0c:92:18:73:04:c1:f5:45:db:37:e7:
+                    5f:c7:8c:a3:60:e9:92:a0:d8:29:5d:77:48:fb:1d:
+                    b0:ed:12:2c:4e:2e:02:db:3d:1a:41:71:a6:2b:2e:
+                    b3:4c:6a:c7:f7:1d:a9:7e:c7:cf:db:f2:e7:b6:f3:
+                    1f:77:1d:24:01:1a:66:66:30:85:30:02:29:c4:bb:
+                    f7:cd:3f:89:4b:1a:5f:f4:91:96:fb:e9:39:f2:46:
+                    96:12:3d:8a:23:b5:2e:82:9e:41:fe:40:b6:27:b1:
+                    14:44:5c:96:30:0f:55:e4:bb:ad:8b:8a:99:17:c0:
+                    29:11:4e:76:79:9d:4b:03:31:7e:85:3c:a8:23:40:
+                    54:02:58:35:c6:fc:dd:3d:eb:e3:d1:51:00:02:86:
+                    1a:d7:b0:9f:a0:17:73:6a:5a:d0:e6:b6:b8:55:40:
+                    5e:27
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                28:F2:FD:30:CD:03:F1:DC:41:1E:C4:93:C6:97:13:CA:D4:FA:60:2A
+            X509v3 Authority Key Identifier: 
+                keyid:28:F2:FD:30:CD:03:F1:DC:41:1E:C4:93:C6:97:13:CA:D4:FA:60:2A
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha1WithRSAEncryption
+         46:15:18:89:b2:57:17:d1:a2:64:c1:9a:73:4f:04:94:76:07:
+         1f:29:ba:6f:34:46:c2:36:d5:68:85:f4:15:4c:8e:1a:fe:83:
+         79:53:ec:aa:0d:92:60:de:f3:9a:3a:e8:80:66:ac:87:70:89:
+         59:f2:ac:9e:b0:28:11:37:7d:78:4e:5e:3f:25:0f:be:09:6f:
+         26:2a:3d:66:79:38:28:e5:81:71:71:96:26:4f:db:ec:23:70:
+         be:37:39:fc:e0:32:0d:80:8f:66:c7:ac:a4:b4:8b:77:40:e2:
+         99:44:3a:73:c8:f9:14:cf:1b:32:27:c2:78:db:b0:da:8a:60:
+         eb:8d:34:7e:7d:3c:03:d4:38:74:f7:17:9e:32:74:9a:e7:37:
+         95:d4:71:03:c8:94:ea:09:7b:ad:2d:eb:70:43:f2:32:7e:63:
+         01:84:8c:7e:9e:f0:79:7f:ae:e9:cf:f9:be:0e:fe:95:d2:bd:
+         c8:a7:81:c2:71:d9:c3:50:31:89:6d:fa:ad:a2:ab:00:01:34:
+         10:58:ef:96:5a:eb:30:07:a9:8e:84:36:ef:3d:3c:61:46:96:
+         6a:e8:09:20:5a:ab:f8:4b:eb:b7:33:61:8e:af:9a:7d:16:b0:
+         60:6a:f0:30:e5:b2:8e:e7:80:b4:a1:02:a9:37:fe:5f:b5:ae:
+         65:e9:6b:34
+-----BEGIN CERTIFICATE-----
+MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD
+VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs
+MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV
+BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3
+DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy
+MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU
+MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh
+cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ
+bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ
+GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6
+L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg
+2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw
+AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX
+wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n
+AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME
+GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
+DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5
+U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm
+T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD
+1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I
+p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO
+r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0
+-----END CERTIFICATE-----
diff --git a/test/keys/README.md b/test/keys/README.md
new file mode 100755
index 0000000..010835d
--- /dev/null
+++ b/test/keys/README.md
@@ -0,0 +1,102 @@
+# Test Keys and Certificates
+This folder is dedicated to test keys and certificates provided in multiple formats.
+Primary use are unit test suites and cross language tests.
+
+    test/keys
+
+**The files in this directory must never be used on production systems.**
+
+## SSL Keys and Certificates
+
+
+## create certificates
+
+we use the following parameters for test key and certificate creation
+
+    C=US,
+    ST=Maryland,
+    L=Forest Hill,
+    O=The Apache Software Foundation,
+    OU=Apache Thrift,
+    CN=localhost/emailAddress=dev@thrift.apache.org
+
+### create self-signed server key and certificate
+
+    openssl req -new -x509 -nodes  -days 3000 -out server.crt -keyout server.key
+    openssl x509 -in server.crt -text > CA.pem
+    cat server.crt server.key > server.pem
+
+Export password is "thrift" without the quotes
+
+    openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.p12
+
+### create client key and certificate
+
+    openssl genrsa -out client.key
+
+create a signing request:
+
+    openssl req -new -key client.key -out client.csr
+
+sign the client certificate with the server.key
+
+    openssl x509 -req -days 3000 -in client.csr -CA CA.pem -CAkey server.key -set_serial 01 -out client.crt
+
+export certificate in PKCS12 format (Export password is "thrift" without the quotes)
+
+    openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12
+
+export certificate in PEM format for OpenSSL usage
+
+    openssl pkcs12 -in client.p12 -out client.pem -clcerts
+
+### create client key and certificate with altnames
+
+copy openssl.cnf from your system e.g. /etc/ssl/openssl.cnf and append following to the end of [ v3_req ]
+
+    subjectAltName=@alternate_names
+
+    [ alternate_names ]
+    IP.1=127.0.0.1
+    IP.2=::1
+    IP.3=::ffff:127.0.0.1
+
+create a signing request:
+
+    openssl req -new -key client_v3.key -out client_v3.csr -config openssl.cnf \
+        -subj "/C=US/ST=Maryland/L=Forest Hill/O=The Apache Software Foundation/OU=Apache Thrift/CN=localhost" -extensions v3_req
+
+sign the client certificate with the server.key
+
+    openssl x509 -req -days 3000 -in client_v3.csr -CA CA.pem -CAkey server.key -set_serial 01 -out client_v3.crt -extensions v3_req -extfile openssl.cnf
+
+## Java key and certificate import
+Java Test Environment uses key and trust store password "thrift" without the quotes
+
+list keystore entries
+
+    keytool -list -storepass thrift -keystore ../../lib/java/test/.keystore
+
+list truststore entries
+
+    keytool -list -storepass thrift -keystore ../../lib/java/test/.truststore
+
+
+delete an entry
+
+    keytool -delete -storepass thrift -keystore ../../lib/java/test/.truststore -alias ssltest
+
+
+import certificate into truststore
+
+    keytool -importcert -storepass thrift -keystore ../../lib/java/test/.truststore -alias localhost --file server.crt
+
+import key into keystore
+
+    keytool -importkeystore -storepass thrift -keystore ../../lib/java/test/.keystore -srcstoretype pkcs12 -srckeystore server.p12
+
+# Test SSL server and clients
+
+    openssl s_client -connect localhost:9090
+    openssl s_server -accept 9090 -www
+
diff --git a/test/keys/client.crt b/test/keys/client.crt
new file mode 100644
index 0000000..80a9ad0
--- /dev/null
+++ b/test/keys/client.crt
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID2DCCAsACAQEwDQYJKoZIhvcNAQELBQAwgbExCzAJBgNVBAYTAlVTMREwDwYD
+VQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRo
+ZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRo
+cmlmdDESMBAGA1UEAwwJbG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhy
+aWZ0LmFwYWNoZS5vcmcwHhcNMTUxMjIzMDcwNzUwWhcNMjQwMzEwMDcwNzUwWjCB
+sTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1hcnlsYW5kMRQwEgYDVQQHDAtGb3Jl
+c3QgSGlsbDEnMCUGA1UECgweVGhlIEFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9u
+MRYwFAYDVQQLDA1BcGFjaGUgVGhyaWZ0MRIwEAYDVQQDDAlsb2NhbGhvc3QxJDAi
+BgkqhkiG9w0BCQEWFWRldkB0aHJpZnQuYXBhY2hlLm9yZzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALl/bJhg17Pu1t785JIuwlh7e2E51eoWFvuxMWfH
+dsUAVqDaOz99O5sv8pgWKXrkPBttE98T+Mx/Pwz5JHs4Qcre3A5adm6cdab0AKug
+eVG1PvHrWzV4aheg4KUfVSiMz8BG2K3Q1VGvZkgMRa/Q409FKjU6Z4D9vBG4Pas3
+PN5FxnAL6P70yWCEr2Vu/tWJlCN+qrRDfSaE2hqmT1irxaoPa61GvuRVsGQ3TeoE
+mGfENtvFqC6qQWuSCbG5aI47Rv66pqoWWxqkrcolNc7+vhx6rW+wdFO3IlqIT8IG
+sdQVp+Y4ir/dGp2ejzqGZCremPJ1uEKjLMpIukdg25ymHC0CAwEAATANBgkqhkiG
+9w0BAQsFAAOCAQEABcRdwc9mdY9zOvTixtThHrciVvqwp6RaiQqMEVomozYilZDR
+J90M3H6KnlADJbCv0FXujsaApB53awq5I7sObAYWFhDJZ9LKlw0lDF7KchLXiAlk
+XVyvL2nJjuJcxPCFPWktwrw5bTguRCBzG12Hzikn+xs6uPur7VQYM33jbXEda5PS
+UEqvAVWaONJCX8MDYOscVoJF0ESyI+fN92ipFaXR7fGajod/rc0AfeN2GVMZETve
+21pkUyDwwCGA44uvNUCd1e32NxE3ah9UApCRn5sGJ64R6urpFTXT3IALF3kaOO7U
+VsMhFrUiZ7+Bw5nIeiK0QOF6Eipj+bJvrLZpSg==
+-----END CERTIFICATE-----
diff --git a/test/keys/client.key b/test/keys/client.key
new file mode 100644
index 0000000..25dcfd7
--- /dev/null
+++ b/test/keys/client.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAuX9smGDXs+7W3vzkki7CWHt7YTnV6hYW+7ExZ8d2xQBWoNo7
+P307my/ymBYpeuQ8G20T3xP4zH8/DPkkezhByt7cDlp2bpx1pvQAq6B5UbU+8etb
+NXhqF6DgpR9VKIzPwEbYrdDVUa9mSAxFr9DjT0UqNTpngP28Ebg9qzc83kXGcAvo
+/vTJYISvZW7+1YmUI36qtEN9JoTaGqZPWKvFqg9rrUa+5FWwZDdN6gSYZ8Q228Wo
+LqpBa5IJsblojjtG/rqmqhZbGqStyiU1zv6+HHqtb7B0U7ciWohPwgax1BWn5jiK
+v90anZ6POoZkKt6Y8nW4QqMsyki6R2DbnKYcLQIDAQABAoIBAFotbCmXysUaczLs
+VmIKgUhqn0xgxXGLU5kARzhga4jR5UtFTFBNHVEQOitdesTXd7ENkf98whMIOSqh
+Y+7TJojtVqVTrQeQ4FFNhZXp6ZCjP/pzpF+WLl1WRF+Bn/Cao9ShnGzDfTC8yEh2
+Ttpt/lNnGGHQBslakLc8jh5SODEFfbugX8SdTCwZYsesKNrXm1pS/5IEunPqaRi0
+II0EcnqHEsgqSo+CljpW7uNxSryA2vSAVdlPej6+9FZjdIHLP5AEKYvk7e9D2CMV
+1+grNe/QkQppShizPirbb93tHm86v5bkDFCM9yWrhcMcjvILMXETxIppMGPmacRu
+jqtYcAECgYEA8VDzylTz4kS3+D3n3hTgb41XVYa7feUsh99GWRO1wXIFpHjCIRjA
+9r/BXW9+Rx3puVPhS8hwLQ4BLdA7lFpV1C8ag0e3+vn6zVirnz1jtI+uHMvStzhO
+d6i0nf+w4HYXo7mN6o9ZdHEfC8SFNbymhCoVKh2DILDwb4EX9RXNpy0CgYEAxMj4
++vrklJ/ilH+Ry1zst4zQYIwmm3QWjarDrypGucHgd4jg5v9A/CJIKUi8x0MjrcuN
+wVb7R8XJyYzFQRXIUXR6GnLeeSnfpxzt4YlifCvXxnOi8w4fv7KeGBV5np1Egpo8
+nWNyZFxdvQDuCopr3SUoS9JI8JPwVgA7T+7DaQECgYAGoavhbo45NJw9pS3fC4HT
+bvXscsRqREcCAN/FCOagx0piZ7MmB7Ed1s0wjSTSPX8zyZtSYtK6Wj0sDiHlBMqB
+Bz5aRzlGG2KKDBrDSIOZ7aziO7Oxt0lovmkgQmuQ743cwPemb4QM0CMDRsZGYMXO
+sf1c5+y3lEU3Ozv2T0AUjQKBgBlnzOUyMQKTJcCAO8ViiNkln91nGrDlKug9TKg3
+sAvZYO5tyINqHuyuTFywHFcpbtjIN9PnM+fPPD7+IpVFh6gkfoMdo2VHJ62+iWOd
+xg475s6jLT1t7GFmYQzA8QOuUCMAYKT9Ks6UMjHthc3skwJpAqvPSUVuBBBGVWH7
+dFUBAoGBAL67ARLujiAEVNHt5rajixB6ncl7/R+Z2uawI1JfmdnCZonAKVZYHuXU
+/4j2+o4QhJIPLtWIoaxAkMigQtAkesqirn3Kk/c7kZRIoN549HTJuwZqYqNp7CB/
+kVi5R335+M9z49i6qA0RZsJGSoSBk7PufG4RmLimcRbGwrY93sPD
+-----END RSA PRIVATE KEY-----
diff --git a/test/keys/client.p12 b/test/keys/client.p12
new file mode 100644
index 0000000..5d2669c
--- /dev/null
+++ b/test/keys/client.p12
Binary files differ
diff --git a/test/keys/client.pem b/test/keys/client.pem
new file mode 100644
index 0000000..66ef626
--- /dev/null
+++ b/test/keys/client.pem
@@ -0,0 +1,60 @@
+Bag Attributes
+    localKeyID: 39 EC 3D 5B 28 17 DA DD 09 7A 62 68 D5 44 1F C7 E2 F8 E0 CD 
+subject=/C=US/ST=Maryland/L=Forest Hill/O=The Apache Software Foundation/OU=Apache Thrift/CN=localhost/emailAddress=dev@thrift.apache.org
+issuer=/C=US/ST=Maryland/L=Forest Hill/O=The Apache Software Foundation/OU=Apache Thrift/CN=localhost/emailAddress=dev@thrift.apache.org
+-----BEGIN CERTIFICATE-----
+MIID2DCCAsACAQEwDQYJKoZIhvcNAQELBQAwgbExCzAJBgNVBAYTAlVTMREwDwYD
+VQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRo
+ZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRo
+cmlmdDESMBAGA1UEAwwJbG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhy
+aWZ0LmFwYWNoZS5vcmcwHhcNMTUxMjIzMDcwNzUwWhcNMjQwMzEwMDcwNzUwWjCB
+sTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1hcnlsYW5kMRQwEgYDVQQHDAtGb3Jl
+c3QgSGlsbDEnMCUGA1UECgweVGhlIEFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9u
+MRYwFAYDVQQLDA1BcGFjaGUgVGhyaWZ0MRIwEAYDVQQDDAlsb2NhbGhvc3QxJDAi
+BgkqhkiG9w0BCQEWFWRldkB0aHJpZnQuYXBhY2hlLm9yZzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALl/bJhg17Pu1t785JIuwlh7e2E51eoWFvuxMWfH
+dsUAVqDaOz99O5sv8pgWKXrkPBttE98T+Mx/Pwz5JHs4Qcre3A5adm6cdab0AKug
+eVG1PvHrWzV4aheg4KUfVSiMz8BG2K3Q1VGvZkgMRa/Q409FKjU6Z4D9vBG4Pas3
+PN5FxnAL6P70yWCEr2Vu/tWJlCN+qrRDfSaE2hqmT1irxaoPa61GvuRVsGQ3TeoE
+mGfENtvFqC6qQWuSCbG5aI47Rv66pqoWWxqkrcolNc7+vhx6rW+wdFO3IlqIT8IG
+sdQVp+Y4ir/dGp2ejzqGZCremPJ1uEKjLMpIukdg25ymHC0CAwEAATANBgkqhkiG
+9w0BAQsFAAOCAQEABcRdwc9mdY9zOvTixtThHrciVvqwp6RaiQqMEVomozYilZDR
+J90M3H6KnlADJbCv0FXujsaApB53awq5I7sObAYWFhDJZ9LKlw0lDF7KchLXiAlk
+XVyvL2nJjuJcxPCFPWktwrw5bTguRCBzG12Hzikn+xs6uPur7VQYM33jbXEda5PS
+UEqvAVWaONJCX8MDYOscVoJF0ESyI+fN92ipFaXR7fGajod/rc0AfeN2GVMZETve
+21pkUyDwwCGA44uvNUCd1e32NxE3ah9UApCRn5sGJ64R6urpFTXT3IALF3kaOO7U
+VsMhFrUiZ7+Bw5nIeiK0QOF6Eipj+bJvrLZpSg==
+-----END CERTIFICATE-----
+Bag Attributes
+    localKeyID: 39 EC 3D 5B 28 17 DA DD 09 7A 62 68 D5 44 1F C7 E2 F8 E0 CD 
+Key Attributes: <No Attributes>
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIRKol42bAS3ACAggA
+MBQGCCqGSIb3DQMHBAjOulcyHMaWsQSCBMgbeXQ8pIYTENKm08UPeqxkCR2nLxSO
+gtRmBxDYjqYv35y4K8KhybBvSBlIPgE5jEWxUCcc1Qvy5ydUQ/X9pmkU8dnmAmDC
+o0zwd3lt2eNPy+4WliqFDVmHrLfYQFOoIrHjuzC0lI4C2iPOjxhfa1zFumedgwGS
+Gx10X5uEVH5N64fW6B3BvzQM0rn2qr0ONuSRmteRtI8NsznfkgeJ9a4CIAF7E5Z2
+JTGI12edNzzUJ1JhX47ZW4miQwCU5Lcy01UZqTFuUpmK7FUQegtLy3e5eDKq+bIg
+ZYq6Hx7lu8hjT5kWZGKy71aYmHKEjI0f727cAbqDTG5uZBHBjwK/3p/znQVQXxBb
+1+E9CiKeFdXj2ElptsnDyoTvrSwJ/Jqu1wkXBcH5Embg7aJMod1IOs6OQB1rPDvd
+FFa84zbqRNWHSxxxYZxcB8YZinL6/dQJnisKu9LMQd3BBGsGWqH8Zz5tEvXjS5Kv
+3g9JRa7QDkSF005x6U+q/678G2MG+W+NWqje3NZx9Psh/Ptm+h+q9n2GSvnibiK5
+mEj9FIwGquGpbZUTK5aXHcKN657dKiICsEJeNar1iZznRmzrMbZJ+DxqJnTw+GAv
+7Yb63/CNAtqSxiyNHGZ6NM2ZA9vAKY1HXn0RVC0y1+9FmNpSRwv3u/+ydSCnJonR
+GEKjzOqM9Dn7qxd+h4UnnA7hXWxITageB6G6KmfiXRxhiWyqtOICdCneCwpq8UZ4
+e0fm05NRW6M2mqGQHsMNSvTWddwz5b8wgw4eVsb+xQytxVdj9lpBuB9KyjQjxUgU
+3oZx4KyWLoEWjkztPAiK3uv5GfotNIMdznRfON1+xm1M5swtn3y3Ru1f6STZC7Sp
+qvbG7jPmpB5gLEUri+chw+aKUYbJ0b820Od4FLQYnwLWr46VelYmV44xuR06wgqP
+1HchMSsHtS+ZlIiQQU9jhdyTrl86EQHH33dh+Sua8AhfewPRy2VFp3Zk34AUsWcX
+EfIYGemhqUD3drG0SMVbFFNOaFGp9e0tQouYOC6/qFBv/SNgQz3mAEkciJYbUuUZ
+V4YQPvtdvSrISV0e7bjFgdSEjG7P7F6CFrWTrjUlHZuWj6/rJ3+/1PHeJViyhsrJ
+ZYFe14W/48PDxBRl4IEAmxcN1Eb2Ez9eCqv0HW77HviG6zIgnkPrhWHjFGUpxKk4
+jLfuB2Tfq9F7ozv4L2QAn+F/yKt1Rm2Hh5J61eUJtAT60pajg+gJtjmpu5Pr4HDn
+b6p3xmYwaL5Let1zCAbbMfdlDK14YjdOdM/BEKpXb9y4EIubX5AMY4ljXeG9gx+T
+B1TuQVdJ0P5wIK/D10TQzAWDKam0kv3RXidlzRxpZ3snRnN/L3EVd58Rntj1Oc0y
+FiIiSKRszDbPzKDxQE2sNgQcdO24JNLSa/sZYtq2gRgspl/YqIDo4ZYqi9x8F5OS
+rdPU5D/H8LWR4vpJLL8DYrHh5qFG3BX2OJIhPRS+48pDYtrRjp7S/1ZU64OJAytk
+99hDqSrn1j2a6yFE8L2Ptz+4UCF2OQXEc9Rqqeb8QEUuMSkNH4oQ+A2F6uzLpZi0
+XH64R2niNC56LxV2i+3T5KREFLahyk8epLZlv8YdxYR4Sb7J/5yiooK3g9hmYVKO
+zLc=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/test/keys/client_v3.crt b/test/keys/client_v3.crt
new file mode 100644
index 0000000..a47f156
--- /dev/null
+++ b/test/keys/client_v3.crt
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIECDCCAvCgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UEBhMCVVMx
+ETAPBgNVBAgMCE1hcnlsYW5kMRQwEgYDVQQHDAtGb3Jlc3QgSGlsbDEnMCUGA1UE
+CgweVGhlIEFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9uMRYwFAYDVQQLDA1BcGFj
+aGUgVGhyaWZ0MRIwEAYDVQQDDAlsb2NhbGhvc3QxJDAiBgkqhkiG9w0BCQEWFWRl
+dkB0aHJpZnQuYXBhY2hlLm9yZzAeFw0xNjAyMjIxMTU4NDFaFw0yNDA1MTAxMTU4
+NDFaMIGLMQswCQYDVQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcM
+C0ZvcmVzdCBIaWxsMScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5k
+YXRpb24xFjAUBgNVBAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9z
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALZ0wiQnXg5QMZZWugd/
+O3woatyHuczJuFSmYiRGWLr3PugB+xtvjy0rTcE2MNx/bdsVxrapCKA+tMFORbEl
+sF6jk0H+B7BzGoIwHr6N8GP1VOoA2esrhsNEz22aJI00VaFTFE8G/qgFcihyaVWH
+ZsLa3MakOzFUmOBaV2tLBjCjaznqXw3eo3XwUI0BkgS9b9vqXjScmfWXDw5+1is4
+bCgumG2zj9EpLypc9qCGNKFBO2YIg0XsIIJ8RprlianjL6P4MfC6GPOyW4NbZaLd
+ESv/bumpVyuV/C/xqkPahvOwBuPE1loxZZPx6Qv368qn7SVNVZOLyX722spooA5G
+6csCAwEAAaNPME0wCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwMwYDVR0RBCwwKocE
+fwAAAYcQAAAAAAAAAAAAAAAAAAAAAYcQAAAAAAAAAAAAAP//fwAAATANBgkqhkiG
+9w0BAQsFAAOCAQEABUEmeQkG/PS935jMHDrg/5zm4X2xrnFtmTwb0jdxfau6z/7h
+AbxD5ioyY7FUTNCzI6SyMo9vJJtYCTCuEGr84JjT2R7232z60k4c1z/av01W3Orv
+ExHfAZ8llhkfu0209T5TaIYCB7hDFj5KDbta8c6fEcwtmlHQWj3M31lSNsr4ZtWW
+wObhK3sqTsOluHbhKNwlNEat48lbOQUC19I1Wi3dAS6n8lr0lEhfGKvqxu0ViASS
+N1nLfdkREGp39bYpKg0n6EFw5bYyV4qE3cnIedFJp7NIOM/6xndJMh/c5l6N2uyZ
+upArRQpw/3j+HkL1x9bs+900QK0GI6AxgjbopA==
+-----END CERTIFICATE-----
diff --git a/test/keys/client_v3.key b/test/keys/client_v3.key
new file mode 100644
index 0000000..b989f73
--- /dev/null
+++ b/test/keys/client_v3.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAtnTCJCdeDlAxlla6B387fChq3Ie5zMm4VKZiJEZYuvc+6AH7
+G2+PLStNwTYw3H9t2xXGtqkIoD60wU5FsSWwXqOTQf4HsHMagjAevo3wY/VU6gDZ
+6yuGw0TPbZokjTRVoVMUTwb+qAVyKHJpVYdmwtrcxqQ7MVSY4FpXa0sGMKNrOepf
+Dd6jdfBQjQGSBL1v2+peNJyZ9ZcPDn7WKzhsKC6YbbOP0SkvKlz2oIY0oUE7ZgiD
+RewggnxGmuWJqeMvo/gx8LoY87Jbg1tlot0RK/9u6alXK5X8L/GqQ9qG87AG48TW
+WjFlk/HpC/fryqftJU1Vk4vJfvbaymigDkbpywIDAQABAoIBAQCJpyUhaaIIYnBG
+4D+RkGgsj8Gvh6ah3j53ft/kRj6DMC4BlB0C4fO/PEB5WI0cjfcvpwo4nOapHyX4
+ATmLIMgjXn2m+CSM9wo01mEbmrKWd20M7n96cWhGwg9MvVJ+RdGk2K0lwj02PoWW
+Blt576GTuNN/+j++Q/jiqsXxaLTO0/Wj+4b2gQh3n8I0u6bkolDLoERKIdrLGHH+
+FU3sk8bpUhHmeiUTfwwci+juhtOY9e30AEst6xakCHbq1lRRyEYPtWL7oLds6yv0
+UAKP7wS9Yl6dcekXSF1RZpB+fovTW+qPYn8aEuksaMz0wK96FCOjVNGYxMp+Xnvl
+sKx63UZBAoGBAOCbCbJtO0HsgIauvCvGZ50aZ1vDvQReCwri4ioutEg4JCAXHEsX
++axz2J5j3UEQhGKr0EX9BG6YbxGW0Mmjf3QxeRB+0WLpMMY2SFt93oC2R1AX9l0I
+h50O6tYv5SXm96pKxwRz01d84mCJgwn/G+cZ/EJj4rfZsNbQst6JQFvzAoGBAM/1
+gLVQt5l+IK+6s68EnADI66i7cKe6sj3rFRTahZJxL2vY28J9EB2mF/XEgARSNJQV
+X/H9zDrwKm9MX87/eCH2nEbc+5qSGpDPQm482C9DqsMitxCKD8bble1BlpjFb8hr
+R0Q3v5q8u5uomLBds5eUBeRKMtu9tOMA9KRSDGjJAoGAF44K2Ux9T2+XFwjSMSEQ
+krhHKKeBdijKrayXnWbif0Rr/XWPAQ0VoRFRIWNFu+IYkCSGpiBfy51u4IBZixv7
+bNsXYDR8jwv3koH02qt7nzH+jpbEvoL7fewnkqjZNj1fsds/vebLvjwZnZguRukb
+KwRdoTTKfQ92bUDb0VzBhCMCgYB7H+3ObDXoCQctRCsyilYbGNp+EkxG4oC5rD/V
+EvRWmfDrt3+VjRpHk5lIB8mLxWgf7O/bhNqwYpWdQ+jN0++6nBo20oudHrff2PaJ
+8jhE85lc42bjwfpJUKVZzaVuWicu0GVnfGJTKT8ikBWnBjNYoWlDmrK164H3jQ9L
+YtC6EQKBgQCabFXXHx5cIJ2XOm4K/nTOG7ClvD80xapqyGroQd9E/cJUHHPp/wQ4
+c1dMO5EViM7JRsKfxkl9vM5o9IM7swlYh4EMFSLJNjzgOY9XVkvQh0uGbiJOBO4f
+inUuWn1YWUj/HFtrT+0No+cYvZVcMKrFAy3K/AwpTbfKCk6roullNA==
+-----END RSA PRIVATE KEY-----
diff --git a/test/keys/server.crt b/test/keys/server.crt
new file mode 100644
index 0000000..8a5ef3c
--- /dev/null
+++ b/test/keys/server.crt
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD
+VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs
+MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV
+BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3
+DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy
+MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU
+MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh
+cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ
+bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ
+GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6
+L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg
+2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw
+AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX
+wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n
+AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME
+GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
+DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5
+U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm
+T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD
+1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I
+p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO
+r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0
+-----END CERTIFICATE-----
diff --git a/test/keys/server.key b/test/keys/server.key
new file mode 100644
index 0000000..263cfce
--- /dev/null
+++ b/test/keys/server.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR
+tLQVDSGQGV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCy
+SN8I2Xw6L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/H
+jKNg6ZKg2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQB
+GmZmMIUwAinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xk
+u62LipkXwCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDm
+trhVQF4nAgMBAAECggEAW/y52YYW6ypROGbZ94DQpFV0kLO7qT8q0Ksxw5sPNaIt
+fEPRIymDa8ikyHWJS5Oxmw84wo5jnJV26jaLmwe2Lupq7Xf1lqej8f5LJtuv7cQR
+xfzp1vM65KJFFJHp6WqjGqJ6HSSZOpVDsnQYcXQjQCdpyAmaSWd3p+FqYSZ1mQmD
+bFNI7jqpczWSZhTdotQ7p7Hn9TVCehflP3yGIB3bQ+wCcCB85dOBz201L+YgaIck
+Sz43A4NvWaQIRLRDw7s9GW4jY5T0Jv282WIeAlVpVxLIwu48r4R4yGTIx9Ydowvq
+57+Y5iPPjAXxu0V9t00oS3bYxDaKh2DUfc/5zowq8QKBgQDYNVPXmaG0aIH4vjQ9
+7fRdw/UDkYcQbn6CnglQOu77/S8ogQzpKCVJgJgkZNqOVtQMEPzekGEcLTbje1gU
+8Bky2k+PL9UwbFy0emnOVh4rqrNXHsRvJcehNT/PRb5hjF3MUMFV/0iD4b+naFaE
+jrSWiZ2ZXj2qfwAK52GFbtOuBQKBgQDJYQuGiY0r22E4waJmCSKczoBT3cwlVzWj
+V2ljgA9RHLNTVkvNNYQLGu2qngFrtwpeaSnsMDerVG4wKAQWyCnYzxVrlnC4uDrJ
+HXuFEltBWi9Ffbgfsnd3749AT0oBP1NT2tMleguyf5DFgjCR3VRJLdrVaaZ8row/
+LqKcFMqnOwKBgB+OIO99l7E584Y3VG6ZdSneOLtNmRXX2pT7tcZE465ZdHGH7Dd3
+SYHhx9K/+Xn+yDH+pLli/xlarAEldmSP6k2WuTfftlC78AfTOfAId5zN7CDR9791
+Fx67I9X/itq33tS8EIuZl57P6uXm/4GXRloWOa8xpvRkVsBApuYPl8t1AoGATQDS
+y2sllDObBXzlgGbV2WgNIgSZ311toTv3jJiXQsjauW8yJRHln+l4H9mzaWDgkiFc
+ang1kUoDqF5k0eFQPxtQcYdhKwEnWWfwp33RbzfxA32DPnubuzzbZhfrkHaKgnIW
+cyor9uFYlm2l7ODZLfJez2RKyTplXnOSsmQw6akCgYAz3dj9Hskyj+HVJ+ht1OcE
+c7ai/ESkSA7Vajp0tjJp0EKjW/zq8DvUSXOtcdnJgkKycFluLwbmnaN4txBds1C1
+Qr8Rt2sUCCBNZe1L6DHe3XBdbkJe9sgZVNTjtUSQrzy8UhvsCqG4YWeCu07Szcbc
+rdPUV9/uQkdx8VrShxlD8A==
+-----END PRIVATE KEY-----
diff --git a/test/keys/server.p12 b/test/keys/server.p12
new file mode 100644
index 0000000..f3908a4
--- /dev/null
+++ b/test/keys/server.p12
Binary files differ
diff --git a/test/keys/server.pem b/test/keys/server.pem
new file mode 100644
index 0000000..c45a9f8
--- /dev/null
+++ b/test/keys/server.pem
@@ -0,0 +1,53 @@
+-----BEGIN CERTIFICATE-----
+MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD
+VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs
+MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV
+BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3
+DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy
+MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU
+MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh
+cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ
+bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ
+GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6
+L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg
+2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw
+AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX
+wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n
+AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME
+GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
+DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5
+U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm
+T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD
+1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I
+p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO
+r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR
+tLQVDSGQGV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCy
+SN8I2Xw6L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/H
+jKNg6ZKg2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQB
+GmZmMIUwAinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xk
+u62LipkXwCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDm
+trhVQF4nAgMBAAECggEAW/y52YYW6ypROGbZ94DQpFV0kLO7qT8q0Ksxw5sPNaIt
+fEPRIymDa8ikyHWJS5Oxmw84wo5jnJV26jaLmwe2Lupq7Xf1lqej8f5LJtuv7cQR
+xfzp1vM65KJFFJHp6WqjGqJ6HSSZOpVDsnQYcXQjQCdpyAmaSWd3p+FqYSZ1mQmD
+bFNI7jqpczWSZhTdotQ7p7Hn9TVCehflP3yGIB3bQ+wCcCB85dOBz201L+YgaIck
+Sz43A4NvWaQIRLRDw7s9GW4jY5T0Jv282WIeAlVpVxLIwu48r4R4yGTIx9Ydowvq
+57+Y5iPPjAXxu0V9t00oS3bYxDaKh2DUfc/5zowq8QKBgQDYNVPXmaG0aIH4vjQ9
+7fRdw/UDkYcQbn6CnglQOu77/S8ogQzpKCVJgJgkZNqOVtQMEPzekGEcLTbje1gU
+8Bky2k+PL9UwbFy0emnOVh4rqrNXHsRvJcehNT/PRb5hjF3MUMFV/0iD4b+naFaE
+jrSWiZ2ZXj2qfwAK52GFbtOuBQKBgQDJYQuGiY0r22E4waJmCSKczoBT3cwlVzWj
+V2ljgA9RHLNTVkvNNYQLGu2qngFrtwpeaSnsMDerVG4wKAQWyCnYzxVrlnC4uDrJ
+HXuFEltBWi9Ffbgfsnd3749AT0oBP1NT2tMleguyf5DFgjCR3VRJLdrVaaZ8row/
+LqKcFMqnOwKBgB+OIO99l7E584Y3VG6ZdSneOLtNmRXX2pT7tcZE465ZdHGH7Dd3
+SYHhx9K/+Xn+yDH+pLli/xlarAEldmSP6k2WuTfftlC78AfTOfAId5zN7CDR9791
+Fx67I9X/itq33tS8EIuZl57P6uXm/4GXRloWOa8xpvRkVsBApuYPl8t1AoGATQDS
+y2sllDObBXzlgGbV2WgNIgSZ311toTv3jJiXQsjauW8yJRHln+l4H9mzaWDgkiFc
+ang1kUoDqF5k0eFQPxtQcYdhKwEnWWfwp33RbzfxA32DPnubuzzbZhfrkHaKgnIW
+cyor9uFYlm2l7ODZLfJez2RKyTplXnOSsmQw6akCgYAz3dj9Hskyj+HVJ+ht1OcE
+c7ai/ESkSA7Vajp0tjJp0EKjW/zq8DvUSXOtcdnJgkKycFluLwbmnaN4txBds1C1
+Qr8Rt2sUCCBNZe1L6DHe3XBdbkJe9sgZVNTjtUSQrzy8UhvsCqG4YWeCu07Szcbc
+rdPUV9/uQkdx8VrShxlD8A==
+-----END PRIVATE KEY-----
diff --git a/test/known_failures_Linux.json b/test/known_failures_Linux.json
new file mode 100644
index 0000000..1ab2af5
--- /dev/null
+++ b/test/known_failures_Linux.json
@@ -0,0 +1,494 @@
+[
+  "c_glib-rs_multi_buffered-ip",
+  "c_glib-rs_multi_framed-ip",
+  "c_glib-rs_multic_buffered-ip",
+  "c_glib-rs_multic_framed-ip",
+  "cl-c_glib_binary_buffered-ip",
+  "cl-c_glib_binary_framed-ip",
+  "cl-c_glib_multi-binary_buffered-ip",
+  "cl-c_glib_multi-binary_framed-ip",
+  "cl-c_glib_multi_buffered-ip",
+  "cl-c_glib_multi_framed-ip",
+  "cl-go_binary_buffered-ip",
+  "cl-go_binary_framed-ip",
+  "cl-rb_binary-accel_buffered-ip",
+  "cl-rb_binary-accel_framed-ip",
+  "cl-rb_binary_buffered-ip",
+  "cl-rb_binary_framed-ip",
+  "cl-rs_binary_buffered-ip",
+  "cl-rs_binary_framed-ip",
+  "cl-rs_multi-binary_buffered-ip",
+  "cl-rs_multi-binary_framed-ip",
+  "cl-rs_multi_buffered-ip",
+  "cl-rs_multi_framed-ip",
+  "cpp-dart_binary_http-ip",
+  "cpp-dart_compact_http-ip",
+  "cpp-dart_json_http-ip",
+  "cpp-dart_multi-binary_http-ip",
+  "cpp-dart_multic-compact_http-ip",
+  "cpp-dart_multij-json_http-ip",
+  "cpp-go_binary_http-ip",
+  "cpp-go_binary_http-ip-ssl",
+  "cpp-go_compact_http-ip",
+  "cpp-go_compact_http-ip-ssl",
+  "cpp-go_json_http-ip",
+  "cpp-go_json_http-ip-ssl",
+  "cpp-go_multi-binary_http-ip",
+  "cpp-go_multi-binary_http-ip-ssl",
+  "cpp-go_multic-compact_http-ip",
+  "cpp-go_multic-compact_http-ip-ssl",
+  "cpp-go_multij-json_http-ip",
+  "cpp-go_multij-json_http-ip-ssl",
+  "cpp-java_binary_http-ip",
+  "cpp-java_binary_http-ip-ssl",
+  "cpp-java_compact_http-ip",
+  "cpp-java_compact_http-ip-ssl",
+  "cpp-java_json_http-ip",
+  "cpp-java_json_http-ip-ssl",
+  "cpp-java_multi-binary_http-ip",
+  "cpp-java_multi-binary_http-ip-ssl",
+  "cpp-java_multi_http-ip",
+  "cpp-java_multi_http-ip-ssl",
+  "cpp-java_multic-compact_http-ip",
+  "cpp-java_multic-compact_http-ip-ssl",
+  "cpp-java_multic_http-ip",
+  "cpp-java_multic_http-ip-ssl",
+  "cpp-java_multij-json_http-ip",
+  "cpp-java_multij-json_http-ip-ssl",
+  "cpp-java_multij_http-ip",
+  "cpp-java_multij_http-ip-ssl",
+  "cpp-nodejs_binary_http-domain",
+  "cpp-nodejs_binary_http-ip",
+  "cpp-nodejs_binary_http-ip-ssl",
+  "cpp-nodejs_compact_http-domain",
+  "cpp-nodejs_compact_http-ip",
+  "cpp-nodejs_compact_http-ip-ssl",
+  "cpp-nodejs_json_http-domain",
+  "cpp-nodejs_json_http-ip",
+  "cpp-nodejs_json_http-ip-ssl",
+  "cpp-nodejs_multi-binary_http-domain",
+  "cpp-nodejs_multi-binary_http-ip",
+  "cpp-nodejs_multi-binary_http-ip-ssl",
+  "cpp-nodejs_multic-compact_http-domain",
+  "cpp-nodejs_multic-compact_http-ip",
+  "cpp-nodejs_multic-compact_http-ip-ssl",
+  "cpp-nodejs_multij-json_http-domain",
+  "cpp-nodejs_multij-json_http-ip",
+  "cpp-nodejs_multij-json_http-ip-ssl",
+  "cpp-py3_binary-accel_http-ip",
+  "cpp-py3_binary-accel_http-ip-ssl",
+  "cpp-py3_binary_http-ip",
+  "cpp-py3_binary_http-ip-ssl",
+  "cpp-py3_compact-accelc_http-ip",
+  "cpp-py3_compact-accelc_http-ip-ssl",
+  "cpp-py3_compact_http-ip",
+  "cpp-py3_compact_http-ip-ssl",
+  "cpp-py3_header_http-ip",
+  "cpp-py3_header_http-ip-ssl",
+  "cpp-py3_json_http-ip",
+  "cpp-py3_json_http-ip-ssl",
+  "cpp-py3_multi-accel_http-ip",
+  "cpp-py3_multi-accel_http-ip-ssl",
+  "cpp-py3_multi-binary_http-ip",
+  "cpp-py3_multi-binary_http-ip-ssl",
+  "cpp-py3_multi-multia_http-ip",
+  "cpp-py3_multi-multia_http-ip-ssl",
+  "cpp-py3_multi_http-ip",
+  "cpp-py3_multi_http-ip-ssl",
+  "cpp-py3_multic-accelc_http-ip",
+  "cpp-py3_multic-accelc_http-ip-ssl",
+  "cpp-py3_multic-compact_http-ip",
+  "cpp-py3_multic-compact_http-ip-ssl",
+  "cpp-py3_multic-multiac_http-ip",
+  "cpp-py3_multic-multiac_http-ip-ssl",
+  "cpp-py3_multic_http-ip",
+  "cpp-py3_multic_http-ip-ssl",
+  "cpp-py3_multih-header_http-ip",
+  "cpp-py3_multih-header_http-ip-ssl",
+  "cpp-py3_multij-json_http-ip",
+  "cpp-py3_multij-json_http-ip-ssl",
+  "cpp-py3_multij_http-ip",
+  "cpp-py3_multij_http-ip-ssl",
+  "cpp-py_binary-accel_http-ip",
+  "cpp-py_binary-accel_http-ip-ssl",
+  "cpp-py_binary_http-ip",
+  "cpp-py_binary_http-ip-ssl",
+  "cpp-py_compact-accelc_http-ip",
+  "cpp-py_compact-accelc_http-ip-ssl",
+  "cpp-py_compact_http-ip",
+  "cpp-py_compact_http-ip-ssl",
+  "cpp-py_header_http-ip",
+  "cpp-py_header_http-ip-ssl",
+  "cpp-py_json_http-ip",
+  "cpp-py_json_http-ip-ssl",
+  "cpp-py_multi-accel_http-ip",
+  "cpp-py_multi-accel_http-ip-ssl",
+  "cpp-py_multi-binary_http-ip",
+  "cpp-py_multi-binary_http-ip-ssl",
+  "cpp-py_multi-multia_http-ip",
+  "cpp-py_multi-multia_http-ip-ssl",
+  "cpp-py_multi_http-ip",
+  "cpp-py_multi_http-ip-ssl",
+  "cpp-py_multic-accelc_http-ip",
+  "cpp-py_multic-accelc_http-ip-ssl",
+  "cpp-py_multic-compact_http-ip",
+  "cpp-py_multic-compact_http-ip-ssl",
+  "cpp-py_multic-multiac_http-ip",
+  "cpp-py_multic-multiac_http-ip-ssl",
+  "cpp-py_multic_http-ip",
+  "cpp-py_multic_http-ip-ssl",
+  "cpp-py_multih-header_http-ip",
+  "cpp-py_multih-header_http-ip-ssl",
+  "cpp-py_multij-json_http-ip",
+  "cpp-py_multij-json_http-ip-ssl",
+  "cpp-py_multij_http-ip",
+  "cpp-py_multij_http-ip-ssl",
+  "cpp-rs_multi_buffered-ip",
+  "cpp-rs_multi_framed-ip",
+  "cpp-rs_multic_buffered-ip",
+  "cpp-rs_multic_framed-ip",
+  "csharp-rb_binary-accel_buffered-ip-ssl",
+  "csharp-rb_binary-accel_framed-ip-ssl",
+  "csharp-rb_binary_buffered-ip-ssl",
+  "csharp-rb_binary_framed-ip-ssl",
+  "csharp-rb_compact_buffered-ip-ssl",
+  "csharp-rb_compact_framed-ip-ssl",
+  "csharp-rb_json_buffered-ip-ssl",
+  "csharp-rb_json_framed-ip-ssl",
+  "d-cl_binary_buffered-ip",
+  "d-cl_binary_framed-ip",
+  "d-cpp_binary_buffered-ip",
+  "d-cpp_binary_buffered-ip-ssl",
+  "d-cpp_binary_framed-ip",
+  "d-cpp_binary_framed-ip-ssl",
+  "d-cpp_binary_http-ip",
+  "d-cpp_binary_http-ip-ssl",
+  "d-cpp_compact_buffered-ip",
+  "d-cpp_compact_buffered-ip-ssl",
+  "d-cpp_compact_framed-ip",
+  "d-cpp_compact_framed-ip-ssl",
+  "d-cpp_compact_http-ip",
+  "d-cpp_compact_http-ip-ssl",
+  "d-cpp_json_buffered-ip",
+  "d-cpp_json_buffered-ip-ssl",
+  "d-cpp_json_framed-ip",
+  "d-cpp_json_framed-ip-ssl",
+  "d-cpp_json_http-ip",
+  "d-cpp_json_http-ip-ssl",
+  "d-d_binary_http-ip",
+  "d-d_compact_http-ip",
+  "d-d_json_http-ip",
+  "d-dart_binary_http-ip",
+  "d-dart_compact_http-ip",
+  "d-dart_json_http-ip",
+  "d-go_binary_http-ip",
+  "d-go_binary_http-ip-ssl",
+  "d-go_compact_http-ip",
+  "d-go_compact_http-ip-ssl",
+  "d-go_json_http-ip",
+  "d-go_json_http-ip-ssl",
+  "d-java_binary_http-ip",
+  "d-java_binary_http-ip-ssl",
+  "d-java_compact_http-ip",
+  "d-java_compact_http-ip-ssl",
+  "d-java_json_http-ip",
+  "d-java_json_http-ip-ssl",
+  "d-js_json_http-ip",
+  "d-nodejs_binary_buffered-ip",
+  "d-nodejs_binary_buffered-ip-ssl",
+  "d-nodejs_binary_framed-ip",
+  "d-nodejs_binary_framed-ip-ssl",
+  "d-nodejs_binary_http-ip",
+  "d-nodejs_binary_http-ip-ssl",
+  "d-nodejs_compact_buffered-ip",
+  "d-nodejs_compact_buffered-ip-ssl",
+  "d-nodejs_compact_framed-ip",
+  "d-nodejs_compact_framed-ip-ssl",
+  "d-nodejs_compact_http-ip",
+  "d-nodejs_compact_http-ip-ssl",
+  "d-nodejs_json_buffered-ip",
+  "d-nodejs_json_buffered-ip-ssl",
+  "d-nodejs_json_framed-ip",
+  "d-nodejs_json_framed-ip-ssl",
+  "d-nodejs_json_http-ip",
+  "d-nodejs_json_http-ip-ssl",
+  "d-nodets_binary_buffered-ip",
+  "d-py3_binary-accel_buffered-ip",
+  "d-py3_binary-accel_buffered-ip-ssl",
+  "d-py3_binary-accel_framed-ip",
+  "d-py3_binary-accel_framed-ip-ssl",
+  "d-py3_binary-accel_http-ip",
+  "d-py3_binary-accel_http-ip-ssl",
+  "d-py3_binary_buffered-ip",
+  "d-py3_binary_buffered-ip-ssl",
+  "d-py3_binary_framed-ip",
+  "d-py3_binary_framed-ip-ssl",
+  "d-py3_binary_http-ip",
+  "d-py3_binary_http-ip-ssl",
+  "d-py3_compact-accelc_buffered-ip",
+  "d-py3_compact-accelc_buffered-ip-ssl",
+  "d-py3_compact-accelc_framed-ip",
+  "d-py3_compact-accelc_framed-ip-ssl",
+  "d-py3_compact-accelc_http-ip",
+  "d-py3_compact-accelc_http-ip-ssl",
+  "d-py3_compact_buffered-ip",
+  "d-py3_compact_buffered-ip-ssl",
+  "d-py3_compact_framed-ip",
+  "d-py3_compact_framed-ip-ssl",
+  "d-py3_compact_http-ip",
+  "d-py3_compact_http-ip-ssl",
+  "d-py3_json_buffered-ip",
+  "d-py3_json_buffered-ip-ssl",
+  "d-py3_json_framed-ip",
+  "d-py3_json_framed-ip-ssl",
+  "d-py3_json_http-ip",
+  "d-py3_json_http-ip-ssl",
+  "d-py_binary-accel_buffered-ip",
+  "d-py_binary-accel_buffered-ip-ssl",
+  "d-py_binary-accel_framed-ip",
+  "d-py_binary-accel_framed-ip-ssl",
+  "d-py_binary-accel_http-ip",
+  "d-py_binary-accel_http-ip-ssl",
+  "d-py_binary_buffered-ip",
+  "d-py_binary_buffered-ip-ssl",
+  "d-py_binary_framed-ip",
+  "d-py_binary_framed-ip-ssl",
+  "d-py_binary_http-ip",
+  "d-py_binary_http-ip-ssl",
+  "d-py_compact-accelc_buffered-ip",
+  "d-py_compact-accelc_buffered-ip-ssl",
+  "d-py_compact-accelc_framed-ip",
+  "d-py_compact-accelc_framed-ip-ssl",
+  "d-py_compact-accelc_http-ip",
+  "d-py_compact-accelc_http-ip-ssl",
+  "d-py_compact_buffered-ip",
+  "d-py_compact_buffered-ip-ssl",
+  "d-py_compact_framed-ip",
+  "d-py_compact_framed-ip-ssl",
+  "d-py_compact_http-ip",
+  "d-py_compact_http-ip-ssl",
+  "d-py_json_buffered-ip",
+  "d-py_json_buffered-ip-ssl",
+  "d-py_json_framed-ip",
+  "d-py_json_framed-ip-ssl",
+  "d-py_json_http-ip",
+  "d-py_json_http-ip-ssl",
+  "erl-cpp_binary_buffered-ip",
+  "erl-cpp_compact_buffered-ip",
+  "erl-csharp_binary_buffered-ip",
+  "erl-csharp_compact_buffered-ip",
+  "erl-nodejs_binary_buffered-ip",
+  "erl-nodejs_compact_buffered-ip",
+  "erl-nodets_binary_buffered-ip",
+  "erl-rb_binary-accel_buffered-ip",
+  "erl-rb_binary-accel_buffered-ip-ssl",
+  "erl-rb_binary-accel_framed-ip",
+  "erl-rb_binary-accel_framed-ip-ssl",
+  "erl-rb_binary_buffered-ip",
+  "erl-rb_binary_buffered-ip-ssl",
+  "erl-rb_binary_framed-ip",
+  "erl-rb_binary_framed-ip-ssl",
+  "erl-rb_compact_buffered-ip",
+  "erl-rb_compact_buffered-ip-ssl",
+  "erl-rb_compact_framed-ip",
+  "erl-rb_compact_framed-ip-ssl",
+  "go-cpp_binary_http-ip",
+  "go-cpp_binary_http-ip-ssl",
+  "go-cpp_compact_http-ip",
+  "go-cpp_compact_http-ip-ssl",
+  "go-cpp_json_http-ip",
+  "go-cpp_json_http-ip-ssl",
+  "go-d_binary_http-ip",
+  "go-d_binary_http-ip-ssl",
+  "go-d_compact_http-ip",
+  "go-d_compact_http-ip-ssl",
+  "go-d_json_http-ip",
+  "go-d_json_http-ip-ssl",
+  "go-dart_binary_http-ip",
+  "go-dart_compact_http-ip",
+  "go-dart_json_http-ip",
+  "go-java_binary_http-ip",
+  "go-java_binary_http-ip-ssl",
+  "go-java_compact_http-ip",
+  "go-java_compact_http-ip-ssl",
+  "go-java_json_http-ip",
+  "go-java_json_http-ip-ssl",
+  "go-py3_binary-accel_zlib-ip-ssl",
+  "go-py3_compact-accelc_zlib-ip-ssl",
+  "go-py_binary-accel_zlib-ip-ssl",
+  "go-py_compact-accelc_zlib-ip-ssl",
+  "hs-csharp_binary_buffered-ip",
+  "hs-csharp_binary_framed-ip",
+  "hs-csharp_compact_buffered-ip",
+  "hs-csharp_compact_framed-ip",
+  "nodejs-cpp_binary_http-domain",
+  "nodejs-cpp_binary_http-ip",
+  "nodejs-cpp_binary_http-ip-ssl",
+  "nodejs-cpp_compact_http-domain",
+  "nodejs-cpp_compact_http-ip",
+  "nodejs-cpp_compact_http-ip-ssl",
+  "nodejs-cpp_json_buffered-ip-ssl",
+  "nodejs-cpp_json_http-domain",
+  "nodejs-cpp_json_http-ip",
+  "nodejs-cpp_json_http-ip-ssl",
+  "nodejs-d_binary_http-ip",
+  "nodejs-d_binary_http-ip-ssl",
+  "nodejs-d_compact_http-ip",
+  "nodejs-d_compact_http-ip-ssl",
+  "nodejs-d_json_http-ip",
+  "nodejs-d_json_http-ip-ssl",
+  "nodejs-dart_binary_http-ip",
+  "nodejs-dart_compact_http-ip",
+  "nodejs-dart_json_http-ip",
+  "nodejs-go_binary_http-ip",
+  "nodejs-go_binary_http-ip-ssl",
+  "nodejs-go_compact_http-ip",
+  "nodejs-go_compact_http-ip-ssl",
+  "nodejs-go_json_http-ip",
+  "nodejs-go_json_http-ip-ssl",
+  "nodejs-hs_binary_http-ip",
+  "nodejs-hs_compact_http-ip",
+  "nodejs-hs_json_http-ip",
+  "nodejs-java_binary_http-ip",
+  "nodejs-java_binary_http-ip-ssl",
+  "nodejs-java_compact_http-ip",
+  "nodejs-java_compact_http-ip-ssl",
+  "nodejs-java_json_http-ip",
+  "nodejs-java_json_http-ip-ssl",
+  "nodejs-js_json_http-ip",
+  "nodejs-lua_binary_http-ip",
+  "nodejs-lua_compact_http-ip",
+  "nodejs-lua_json_http-ip",
+  "nodejs-py3_binary-accel_http-ip",
+  "nodejs-py3_binary-accel_http-ip-ssl",
+  "nodejs-py3_binary_http-ip",
+  "nodejs-py3_binary_http-ip-ssl",
+  "nodejs-py3_compact-accelc_http-ip",
+  "nodejs-py3_compact-accelc_http-ip-ssl",
+  "nodejs-py3_compact_http-ip",
+  "nodejs-py3_compact_http-ip-ssl",
+  "nodejs-py3_json_http-ip",
+  "nodejs-py3_json_http-ip-ssl",
+  "nodejs-py_binary-accel_http-ip",
+  "nodejs-py_binary-accel_http-ip-ssl",
+  "nodejs-py_binary_http-ip",
+  "nodejs-py_binary_http-ip-ssl",
+  "nodejs-py_compact-accelc_http-ip",
+  "nodejs-py_compact-accelc_http-ip-ssl",
+  "nodejs-py_compact_http-ip",
+  "nodejs-py_compact_http-ip-ssl",
+  "nodejs-py_json_http-ip",
+  "nodejs-py_json_http-ip-ssl",
+  "perl-rs_multi_buffered-ip",
+  "perl-rs_multi_framed-ip",
+  "py-cpp_accel-binary_http-ip",
+  "py-cpp_accel-binary_http-ip-ssl",
+  "py-cpp_accel-binary_zlib-ip",
+  "py-cpp_accel-binary_zlib-ip-ssl",
+  "py-cpp_accelc-compact_http-ip",
+  "py-cpp_accelc-compact_http-ip-ssl",
+  "py-cpp_accelc-compact_zlib-ip",
+  "py-cpp_accelc-compact_zlib-ip-ssl",
+  "py-cpp_binary_http-ip",
+  "py-cpp_binary_http-ip-ssl",
+  "py-cpp_compact_http-ip",
+  "py-cpp_compact_http-ip-ssl",
+  "py-cpp_header_http-ip",
+  "py-cpp_header_http-ip-ssl",
+  "py-cpp_json_http-ip",
+  "py-cpp_json_http-ip-ssl",
+  "py-d_accel-binary_http-ip",
+  "py-d_accel-binary_http-ip-ssl",
+  "py-d_accelc-compact_http-ip",
+  "py-d_accelc-compact_http-ip-ssl",
+  "py-d_binary_http-ip",
+  "py-d_binary_http-ip-ssl",
+  "py-d_compact_http-ip",
+  "py-d_compact_http-ip-ssl",
+  "py-d_json_http-ip",
+  "py-d_json_http-ip-ssl",
+  "py-dart_accel-binary_http-ip",
+  "py-dart_accelc-compact_http-ip",
+  "py-dart_binary_http-ip",
+  "py-dart_compact_http-ip",
+  "py-dart_json_http-ip",
+  "py-hs_accel-binary_http-ip",
+  "py-hs_accelc-compact_http-ip",
+  "py-hs_binary_http-ip",
+  "py-hs_compact_http-ip",
+  "py-hs_header_http-ip",
+  "py-hs_json_http-ip",
+  "py-java_accel-binary_http-ip",
+  "py-java_accel-binary_http-ip-ssl",
+  "py-java_accelc-compact_http-ip",
+  "py-java_accelc-compact_http-ip-ssl",
+  "py-java_binary_http-ip",
+  "py-java_binary_http-ip-ssl",
+  "py-java_compact_http-ip",
+  "py-java_compact_http-ip-ssl",
+  "py-java_json_http-ip",
+  "py-java_json_http-ip-ssl",
+  "py-lua_accel-binary_http-ip",
+  "py-lua_accelc-compact_http-ip",
+  "py-lua_binary_http-ip",
+  "py-lua_compact_http-ip",
+  "py-lua_json_http-ip",
+  "py3-cpp_accel-binary_http-ip",
+  "py3-cpp_accel-binary_http-ip-ssl",
+  "py3-cpp_accel-binary_zlib-ip",
+  "py3-cpp_accel-binary_zlib-ip-ssl",
+  "py3-cpp_accelc-compact_http-ip",
+  "py3-cpp_accelc-compact_http-ip-ssl",
+  "py3-cpp_accelc-compact_zlib-ip",
+  "py3-cpp_accelc-compact_zlib-ip-ssl",
+  "py3-cpp_binary_http-ip",
+  "py3-cpp_binary_http-ip-ssl",
+  "py3-cpp_compact_http-ip",
+  "py3-cpp_compact_http-ip-ssl",
+  "py3-cpp_header_http-ip",
+  "py3-cpp_header_http-ip-ssl",
+  "py3-cpp_json_http-ip",
+  "py3-cpp_json_http-ip-ssl",
+  "py3-d_accel-binary_http-ip",
+  "py3-d_accel-binary_http-ip-ssl",
+  "py3-d_accelc-compact_http-ip",
+  "py3-d_accelc-compact_http-ip-ssl",
+  "py3-d_binary_http-ip",
+  "py3-d_binary_http-ip-ssl",
+  "py3-d_compact_http-ip",
+  "py3-d_compact_http-ip-ssl",
+  "py3-d_json_http-ip",
+  "py3-d_json_http-ip-ssl",
+  "py3-dart_accel-binary_http-ip",
+  "py3-dart_accelc-compact_http-ip",
+  "py3-dart_binary_http-ip",
+  "py3-dart_compact_http-ip",
+  "py3-dart_json_http-ip",
+  "py3-hs_accel-binary_http-ip",
+  "py3-hs_accelc-compact_http-ip",
+  "py3-hs_binary_http-ip",
+  "py3-hs_compact_http-ip",
+  "py3-hs_header_http-ip",
+  "py3-hs_json_http-ip",
+  "py3-java_accel-binary_http-ip",
+  "py3-java_accel-binary_http-ip-ssl",
+  "py3-java_accelc-compact_http-ip",
+  "py3-java_accelc-compact_http-ip-ssl",
+  "py3-java_binary_http-ip",
+  "py3-java_binary_http-ip-ssl",
+  "py3-java_compact_http-ip",
+  "py3-java_compact_http-ip-ssl",
+  "py3-java_json_http-ip",
+  "py3-java_json_http-ip-ssl",
+  "py3-lua_accel-binary_http-ip",
+  "py3-lua_accelc-compact_http-ip",
+  "py3-lua_binary_http-ip",
+  "py3-lua_compact_http-ip",
+  "py3-lua_json_http-ip",
+  "rb-cpp_json_buffered-domain",
+  "rb-cpp_json_buffered-ip",
+  "rb-cpp_json_buffered-ip-ssl",
+  "rb-cpp_json_framed-domain",
+  "rb-cpp_json_framed-ip",
+  "rb-cpp_json_framed-ip-ssl"
+]
\ No newline at end of file
diff --git a/test/lua/Makefile.am b/test/lua/Makefile.am
new file mode 100644
index 0000000..ed8c5ae
--- /dev/null
+++ b/test/lua/Makefile.am
@@ -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.
+#
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+# Remove "MapType =" line to ignore some map bug for now
+stubs: ../ThriftTest.thrift $(THRIFT)
+	$(THRIFT) --gen lua $<
+	$(SED) -i.bak 's/MapType =//g' gen-lua/ThriftTest_ttypes.lua
+	$(RM) gen-lua/ThriftTest_ttypes.lua.bak
+
+precross: stubs
+
+clean-local:
+	$(RM) -r gen-lua
diff --git a/test/lua/test_basic_client.lua b/test/lua/test_basic_client.lua
new file mode 100644
index 0000000..77d8d07
--- /dev/null
+++ b/test/lua/test_basic_client.lua
@@ -0,0 +1,179 @@
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+
+--   http://www.apache.org/licenses/LICENSE-2.0
+
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+
+
+require('TSocket')
+require('TBufferedTransport')
+require('TFramedTransport')
+require('THttpTransport')
+require('TCompactProtocol')
+require('TJsonProtocol')
+require('TBinaryProtocol')
+require('ThriftTest_ThriftTest')
+require('liblualongnumber')
+
+local client
+
+function teardown()
+  if client then
+    -- close the connection
+    client:close()
+  end
+end
+
+function parseArgs(rawArgs)
+  local opt = {
+    protocol='binary',
+    transport='buffered',
+    port='9090',
+  }
+  for i, str in pairs(rawArgs) do
+    if i > 0 then
+      k, v = string.match(str, '--(%w+)=(%w+)')
+      assert(opt[k] ~= nil, 'Unknown argument')
+      opt[k] = v
+    end
+  end
+  return opt
+end
+
+function assertEqual(val1, val2, msg)
+  assert(val1 == val2, msg)
+end
+
+function testBasicClient(rawArgs)
+  local opt = parseArgs(rawArgs)
+  local socket = TSocket:new{
+    port = tonumber(opt.port)
+  }
+  assert(socket, 'Failed to create client socket')
+  socket:setTimeout(5000)
+
+  local transports = {
+    buffered = TBufferedTransport,
+    framed = TFramedTransport,
+    http = THttpTransport,
+  }
+  assert(transports[opt.transport] ~= nil)
+  local transport = transports[opt.transport]:new{
+    trans = socket,
+    isServer = false
+  }
+
+  local protocols = {
+    binary = TBinaryProtocol,
+    compact = TCompactProtocol,
+    json = TJSONProtocol,
+  }
+  assert(protocols[opt.protocol] ~= nil)
+  local protocol = protocols[opt.protocol]:new{
+    trans = transport
+  }
+  assert(protocol, 'Failed to create binary protocol')
+
+  client = ThriftTestClient:new{
+    protocol = protocol
+  }
+  assert(client, 'Failed to create client')
+
+  -- Open the transport
+  local status, _ = pcall(transport.open, transport)
+  assert(status, 'Failed to connect to server')
+
+  -- String
+  assertEqual(client:testString('lala'),  'lala',  'Failed testString')
+  assertEqual(client:testString('wahoo'), 'wahoo', 'Failed testString')
+
+  -- Bool
+  assertEqual(client:testBool(true), true, 'Failed testBool true')
+  assertEqual(client:testBool(false), false, 'Failed testBool false')
+
+  -- Byte
+  assertEqual(client:testByte(0x01), 1,    'Failed testByte 1')
+  assertEqual(client:testByte(0x40), 64,   'Failed testByte 2')
+  assertEqual(client:testByte(0x7f), 127,  'Failed testByte 3')
+  assertEqual(client:testByte(0x80), -128, 'Failed testByte 4')
+  assertEqual(client:testByte(0xbf), -65,  'Failed testByte 5')
+  assertEqual(client:testByte(0xff), -1,   'Failed testByte 6')
+  assertEqual(client:testByte(128), -128,  'Failed testByte 7')
+  assertEqual(client:testByte(255), -1,    'Failed testByte 8')
+
+  -- I32
+  assertEqual(client:testI32(0x00000001), 1,           'Failed testI32 1')
+  assertEqual(client:testI32(0x40000000), 1073741824,  'Failed testI32 2')
+  assertEqual(client:testI32(0x7fffffff), 2147483647,  'Failed testI32 3')
+  assertEqual(client:testI32(0x80000000), -2147483648, 'Failed testI32 4')
+  assertEqual(client:testI32(0xbfffffff), -1073741825, 'Failed testI32 5')
+  assertEqual(client:testI32(0xffffffff), -1,          'Failed testI32 6')
+  assertEqual(client:testI32(2147483648), -2147483648, 'Failed testI32 7')
+  assertEqual(client:testI32(4294967295), -1,          'Failed testI32 8')
+
+  -- I64 (lua only supports 16 decimal precision so larger numbers are
+  -- initialized by their string value)
+  local long = liblualongnumber.new
+  assertEqual(client:testI64(long(0x0000000000000001)),
+                   long(1),
+                   'Failed testI64 1')
+  assertEqual(client:testI64(long(0x4000000000000000)),
+                   long(4611686018427387904),
+                   'Failed testI64 2')
+  assertEqual(client:testI64(long('0x7fffffffffffffff')),
+                   long('9223372036854775807'),
+                   'Failed testI64 3')
+  assertEqual(client:testI64(long(0x8000000000000000)),
+                   long(-9223372036854775808),
+                   'Failed testI64 4')
+  assertEqual(client:testI64(long('0xbfffffffffffffff')),
+                   long('-4611686018427387905'),
+                   'Failed testI64 5')
+  assertEqual(client:testI64(long('0xffffffffffffffff')),
+                   long(-1),
+                   'Failed testI64 6')
+
+  -- Double
+  assertEqual(
+      client:testDouble(1.23456789), 1.23456789, 'Failed testDouble 1')
+  assertEqual(
+      client:testDouble(0.123456789), 0.123456789, 'Failed testDouble 2')
+  assertEqual(
+      client:testDouble(0.123456789), 0.123456789, 'Failed testDouble 3')
+
+  -- TODO testBinary() ...
+	  
+  -- Accuracy of 16 decimal digits (rounds)
+  local a, b = 1.12345678906666663, 1.12345678906666661
+  assertEqual(a, b)
+  assertEqual(client:testDouble(a), b, 'Failed testDouble 5')
+
+  -- Struct
+  local o = Xtruct:new{
+    string_thing = 'Zero',
+    byte_thing = 1,
+    i32_thing = -3,
+    i64_thing = long(-5)
+  }
+  local r = client:testStruct(o)
+  assertEqual(o.string_thing, r.string_thing, 'Failed testStruct 1')
+  assertEqual(o.byte_thing, r.byte_thing, 'Failed testStruct 2')
+  assertEqual(o.i32_thing, r.i32_thing, 'Failed testStruct 3')
+  assertEqual(o.i64_thing, r.i64_thing, 'Failed testStruct 4')
+
+  -- TODO add list map set exception etc etc
+end
+
+testBasicClient(arg)
+teardown()
diff --git a/test/lua/test_basic_server.lua b/test/lua/test_basic_server.lua
new file mode 100644
index 0000000..acd2d79
--- /dev/null
+++ b/test/lua/test_basic_server.lua
@@ -0,0 +1,142 @@
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+
+--   http://www.apache.org/licenses/LICENSE-2.0
+
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+
+require('ThriftTest_ThriftTest')
+require('TSocket')
+require('TBufferedTransport')
+require('TFramedTransport')
+require('THttpTransport')
+require('TCompactProtocol')
+require('TJsonProtocol')
+require('TBinaryProtocol')
+require('TServer')
+require('liblualongnumber')
+
+--------------------------------------------------------------------------------
+-- Handler
+TestHandler = ThriftTestIface:new{}
+
+-- Stops the server
+function TestHandler:testVoid()
+end
+
+function TestHandler:testString(str)
+  return str
+end
+
+function TestHandler:testBool(bool)
+  return bool
+end
+
+function TestHandler:testByte(byte)
+  return byte
+end
+
+function TestHandler:testI32(i32)
+  return i32
+end
+
+function TestHandler:testI64(i64)
+  return i64
+end
+
+function TestHandler:testDouble(d)
+  return d
+end
+
+function TestHandler:testBinary(by)
+  return by
+end
+
+function TestHandler:testStruct(thing)
+  return thing
+end
+
+--------------------------------------------------------------------------------
+-- Test
+local server
+
+function teardown()
+  if server then
+    server:close()
+  end
+end
+
+function parseArgs(rawArgs)
+  local opt = {
+    protocol='binary',
+    transport='buffered',
+    port='9090',
+  }
+  for i, str in pairs(rawArgs) do
+    if i > 0 then
+      k, v = string.match(str, '--(%w+)=(%w+)')
+      assert(opt[k] ~= nil, 'Unknown argument')
+      opt[k] = v
+    end
+  end
+  return opt
+end
+
+function testBasicServer(rawArgs)
+  local opt = parseArgs(rawArgs)
+  -- Handler & Processor
+  local handler = TestHandler:new{}
+  assert(handler, 'Failed to create handler')
+  local processor = ThriftTestProcessor:new{
+    handler = handler
+  }
+  assert(processor, 'Failed to create processor')
+
+  -- Server Socket
+  local socket = TServerSocket:new{
+    port = opt.port
+  }
+  assert(socket, 'Failed to create server socket')
+
+  -- Transport & Factory
+  local transports = {
+    buffered = TBufferedTransportFactory,
+    framed = TFramedTransportFactory,
+    http = THttpTransportFactory,
+  }
+  assert(transports[opt.transport], 'Failed to create framed transport factory')
+  local trans_factory = transports[opt.transport]:new{}
+  local protocols = {
+    binary = TBinaryProtocolFactory,
+    compact = TCompactProtocolFactory,
+    json = TJSONProtocolFactory,
+  }
+  local prot_factory = protocols[opt.protocol]:new{}
+  assert(prot_factory, 'Failed to create binary protocol factory')
+
+  -- Simple Server
+  server = TSimpleServer:new{
+    processor = processor,
+    serverTransport = socket,
+    transportFactory = trans_factory,
+    protocolFactory = prot_factory
+  }
+  assert(server, 'Failed to create server')
+
+  -- Serve
+  server:serve()
+  server = nil
+end
+
+testBasicServer(arg)
+teardown()
diff --git a/test/netcore/Client/.gitignore b/test/netcore/Client/.gitignore
new file mode 100644
index 0000000..67d5510
--- /dev/null
+++ b/test/netcore/Client/.gitignore
@@ -0,0 +1,2 @@
+# ignore for autogenerated files
+/ThriftTest
diff --git a/test/netcore/Client/Client.csproj b/test/netcore/Client/Client.csproj
new file mode 100644
index 0000000..f16af39
--- /dev/null
+++ b/test/netcore/Client/Client.csproj
@@ -0,0 +1,31 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.0</TargetFramework>
+    <AssemblyName>Client</AssemblyName>
+    <PackageId>Client</PackageId>
+    <OutputType>Exe</OutputType>
+    <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
+    <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
+    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
+    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
+    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
+    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="System.Net.Http.WinHttpHandler" Version="[4.4,)" />
+    <PackageReference Include="System.Runtime.Serialization.Primitives" Version="[4.3,)" />
+    <PackageReference Include="System.ServiceModel.Primitives" Version="[4.4,)" />
+    <PackageReference Include="System.Threading" Version="[4.3,)" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\lib\netcore\Thrift\Thrift.csproj" />
+  </ItemGroup>
+  <Target Name="PreBuild" BeforeTargets="_GenerateRestoreProjectSpec;Restore;Compile">
+    <Exec Condition="'$(OS)' == 'Windows_NT'" Command="where thrift" ConsoleToMSBuild="true">
+      <Output TaskParameter="ConsoleOutput" PropertyName="PathToThrift" />
+    </Exec>
+    <Exec Condition="Exists('$(PathToThrift)')" Command="&quot;$(PathToThrift)&quot; -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../ThriftTest.thrift" />
+    <Exec Condition="Exists('thrift')" Command="thrift -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../ThriftTest.thrift" />
+    <Exec Condition="Exists('$(ProjectDir)/../../../compiler/cpp/thrift')" Command="$(ProjectDir)/../../../compiler/cpp/thrift -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../ThriftTest.thrift" />
+  </Target>
+</Project>
diff --git a/test/netcore/Client/Program.cs b/test/netcore/Client/Program.cs
new file mode 100644
index 0000000..72139d9
--- /dev/null
+++ b/test/netcore/Client/Program.cs
@@ -0,0 +1,72 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using ThriftTest;
+
+namespace Client
+{
+    public class Program
+    {
+        public static int Main(string[] args)
+        {
+            try
+            {
+                Console.SetBufferSize(Console.BufferWidth, 4096);
+            }
+            catch (Exception)
+            {
+                Console.WriteLine("Failed to grow scroll-back buffer");
+            }
+
+            // split mode and options
+            var subArgs = new List<string>(args);
+            var firstArg = string.Empty;
+            if (subArgs.Count > 0)
+            { 
+                firstArg = subArgs[0];
+                subArgs.RemoveAt(0);
+            }
+
+            // run whatever mode is choosen
+            switch(firstArg)
+            {
+                case "client":
+                    return TestClient.Execute(subArgs);
+                case "--help":
+                    PrintHelp();
+                    return 0;
+                default:
+                    PrintHelp();
+                    return -1;
+            }
+        }
+
+        private static void PrintHelp()
+        {
+            Console.WriteLine("Usage:");
+            Console.WriteLine("  Client  client  [options]'");
+            Console.WriteLine("  Client  --help");
+            Console.WriteLine("");
+
+            TestClient.PrintOptionsHelp();
+        }
+    }
+}
+
+
diff --git a/test/netcore/Client/Properties/AssemblyInfo.cs b/test/netcore/Client/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..157152b
--- /dev/null
+++ b/test/netcore/Client/Properties/AssemblyInfo.cs
@@ -0,0 +1,43 @@
+// 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.
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+
+[assembly: AssemblyTitle("Client")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+
+[assembly: Guid("B0C13DA0-3117-4844-8AE8-B1775E46223D")]
+
diff --git a/test/netcore/Client/TestClient.cs b/test/netcore/Client/TestClient.cs
new file mode 100644
index 0000000..8be198c
--- /dev/null
+++ b/test/netcore/Client/TestClient.cs
@@ -0,0 +1,943 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Reflection;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.ServiceModel;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Thrift.Collections;
+using Thrift.Protocols;
+using Thrift.Transports;
+using Thrift.Transports.Client;
+
+namespace ThriftTest
+{
+    public class TestClient
+    {
+        private class TestParams
+        {
+            public int numIterations = 1;
+            public IPAddress host = IPAddress.Any;
+            public int port = 9090;
+            public int numThreads = 1;
+            public string url;
+            public string pipe;
+            public bool buffered;
+            public bool framed;
+            public string protocol;
+            public bool encrypted = false;
+
+            internal void Parse( List<string> args)
+            {
+                for (var i = 0; i < args.Count; ++i)
+                {
+                    if (args[i] == "-u")
+                    {
+                        url = args[++i];
+                    }
+                    else if (args[i] == "-n")
+                    {
+                        numIterations = Convert.ToInt32(args[++i]);
+                    }
+                    else if (args[i].StartsWith("--pipe="))
+                    {
+                        pipe = args[i].Substring(args[i].IndexOf("=") + 1);
+                        Console.WriteLine("Using named pipes transport");
+                    }
+                    else if (args[i].StartsWith("--host="))
+                    {
+                        // check there for ipaddress
+                        host = new IPAddress(Encoding.Unicode.GetBytes(args[i].Substring(args[i].IndexOf("=") + 1)));
+                    }
+                    else if (args[i].StartsWith("--port="))
+                    {
+                        port = int.Parse(args[i].Substring(args[i].IndexOf("=") + 1));
+                    }
+                    else if (args[i] == "-b" || args[i] == "--buffered" || args[i] == "--transport=buffered")
+                    {
+                        buffered = true;
+                        Console.WriteLine("Using buffered sockets");
+                    }
+                    else if (args[i] == "-f" || args[i] == "--framed" || args[i] == "--transport=framed")
+                    {
+                        framed = true;
+                        Console.WriteLine("Using framed transport");
+                    }
+                    else if (args[i] == "-t")
+                    {
+                        numThreads = Convert.ToInt32(args[++i]);
+                    }
+                    else if (args[i] == "--binary" || args[i] == "--protocol=binary")
+                    {
+                        protocol = "binary";
+                        Console.WriteLine("Using binary protocol");
+                    }
+                    else if (args[i] == "--compact" || args[i] == "--protocol=compact")
+                    {
+                        protocol = "compact";
+                        Console.WriteLine("Using compact protocol");
+                    }
+                    else if (args[i] == "--json" || args[i] == "--protocol=json")
+                    {
+                        protocol = "json";
+                        Console.WriteLine("Using JSON protocol");
+                    }
+                    else if (args[i] == "--ssl")
+                    {
+                        encrypted = true;
+                        Console.WriteLine("Using encrypted transport");
+                    }
+                    else
+                    {
+                        //throw new ArgumentException(args[i]);
+                    }
+                }
+            }
+
+            private static X509Certificate2 GetClientCert()
+            {
+                var clientCertName = "client.p12";
+                var possiblePaths = new List<string>
+                {
+                    "../../../keys/",
+                    "../../keys/",
+                    "../keys/",
+                    "keys/",
+                };
+
+                string existingPath = null;
+                foreach (var possiblePath in possiblePaths)
+                {
+                    var path = Path.GetFullPath(possiblePath + clientCertName);
+                    if (File.Exists(path))
+                    {
+                        existingPath = path;
+                        break;
+                    }
+                }
+
+                if (string.IsNullOrEmpty(existingPath))
+                {
+                    throw new FileNotFoundException($"Cannot find file: {clientCertName}");
+                }
+            
+                var cert = new X509Certificate2(existingPath, "thrift");
+
+                return cert;
+            }
+            
+            public TClientTransport CreateTransport()
+            {
+                if (url == null)
+                {
+                    // endpoint transport
+                    TClientTransport trans = null;
+
+                    if (pipe != null)
+                    {
+                        trans = new TNamedPipeClientTransport(pipe);
+                    }
+                    else
+                    {
+                        if (encrypted)
+                        {
+                           var cert = GetClientCert();
+                        
+                            if (cert == null || !cert.HasPrivateKey)
+                            {
+                                throw new InvalidOperationException("Certificate doesn't contain private key");
+                            }
+                            
+                            trans = new TTlsSocketClientTransport(host, port, 0, cert, 
+                                (sender, certificate, chain, errors) => true,
+                                null, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12);
+                        }
+                        else
+                        {
+                            trans = new TSocketClientTransport(host, port);
+                        }
+                    }
+
+                    // layered transport
+                    if (buffered)
+                    {
+                        trans = new TBufferedClientTransport(trans);
+                    }
+
+                    if (framed)
+                    {
+                        trans = new TFramedClientTransport(trans);
+                    }
+
+                    return trans;
+                }
+
+                return new THttpClientTransport(new Uri(url), null);
+            }
+
+            public TProtocol CreateProtocol(TClientTransport transport)
+            {
+                if (protocol == "compact")
+                {
+                    return new TCompactProtocol(transport);
+                }
+
+                if (protocol == "json")
+                {
+                    return new TJsonProtocol(transport);
+                }
+
+                return new TBinaryProtocol(transport);
+            }
+        }
+
+
+        private const int ErrorBaseTypes = 1;
+        private const int ErrorStructs = 2;
+        private const int ErrorContainers = 4;
+        private const int ErrorExceptions = 8;
+        private const int ErrorUnknown = 64;
+
+        private class ClientTest
+        {
+            private readonly TClientTransport transport;
+            private readonly ThriftTest.Client client;
+            private readonly int numIterations;
+            private bool done;
+
+            public int ReturnCode { get; set; }
+
+            public ClientTest(TestParams param)
+            {
+                transport = param.CreateTransport();
+                client = new ThriftTest.Client(param.CreateProtocol(transport));
+                numIterations = param.numIterations;
+            }
+
+            public void Execute()
+            {
+                var token = CancellationToken.None;
+
+                if (done)
+                {
+                    Console.WriteLine("Execute called more than once");
+                    throw new InvalidOperationException();
+                }
+
+                for (var i = 0; i < numIterations; i++)
+                {
+                    try
+                    {
+                        if (!transport.IsOpen)
+                        {
+                            transport.OpenAsync(token).GetAwaiter().GetResult();
+                        }
+                    }
+                    catch (TTransportException ex)
+                    {
+                        Console.WriteLine("*** FAILED ***");
+                        Console.WriteLine("Connect failed: " + ex.Message);
+                        ReturnCode |= ErrorUnknown;
+                        Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                        continue;
+                    }
+                    catch (Exception ex)
+                    {
+                        Console.WriteLine("*** FAILED ***");
+                        Console.WriteLine("Connect failed: " + ex.Message);
+                        ReturnCode |= ErrorUnknown;
+                        Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                        continue;
+                    }
+
+                    try
+                    {
+                        ReturnCode |= ExecuteClientTestAsync(client).GetAwaiter().GetResult(); ;
+                    }
+                    catch (Exception ex)
+                    {
+                        Console.WriteLine("*** FAILED ***");
+                        Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                        ReturnCode |= ErrorUnknown;
+                    }
+                }
+                try
+                {
+                    transport.Close();
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("Error while closing transport");
+                    Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                }
+                done = true;
+            }
+        }
+
+        internal static void PrintOptionsHelp()
+        {
+            Console.WriteLine("Client options:");
+            Console.WriteLine("  -u <URL>");
+            Console.WriteLine("  -t <# of threads to run>        default = 1");
+            Console.WriteLine("  -n <# of iterations>            per thread");
+            Console.WriteLine("  --pipe=<pipe name>");
+            Console.WriteLine("  --host=<IP address>");
+            Console.WriteLine("  --port=<port number>");
+            Console.WriteLine("  --transport=<transport name>    one of buffered,framed  (defaults to none)");
+            Console.WriteLine("  --protocol=<protocol name>      one of compact,json  (defaults to binary)");
+            Console.WriteLine("  --ssl");
+            Console.WriteLine();
+        }
+
+        public static int Execute(List<string> args)
+        {
+            try
+            {
+                var param = new TestParams();
+
+                try
+                {
+                    param.Parse(args);
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    Console.WriteLine("Error while  parsing arguments");
+                    Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                    return ErrorUnknown;
+                }
+
+                var tests = Enumerable.Range(0, param.numThreads).Select(_ => new ClientTest(param)).ToArray();
+
+                //issue tests on separate threads simultaneously
+                var threads = tests.Select(test => new Task(test.Execute)).ToArray();
+                var start = DateTime.Now;
+                foreach (var t in threads)
+                {
+                    t.Start();
+                }
+
+                Task.WaitAll(threads);
+
+                Console.WriteLine("Total time: " + (DateTime.Now - start));
+                Console.WriteLine();
+                return tests.Select(t => t.ReturnCode).Aggregate((r1, r2) => r1 | r2);
+            }
+            catch (Exception outerEx)
+            {
+                Console.WriteLine("*** FAILED ***");
+                Console.WriteLine("Unexpected error");
+                Console.WriteLine(outerEx.Message + " ST: " + outerEx.StackTrace);
+                return ErrorUnknown;
+            }
+        }
+
+        public static string BytesToHex(byte[] data)
+        {
+            return BitConverter.ToString(data).Replace("-", string.Empty);
+        }
+
+        public static byte[] PrepareTestData(bool randomDist)
+        {
+            var retval = new byte[0x100];
+            var initLen = Math.Min(0x100, retval.Length);
+
+            // linear distribution, unless random is requested
+            if (!randomDist)
+            {
+                for (var i = 0; i < initLen; ++i)
+                {
+                    retval[i] = (byte)i;
+                }
+                return retval;
+            }
+
+            // random distribution
+            for (var i = 0; i < initLen; ++i)
+            {
+                retval[i] = (byte)0;
+            }
+            var rnd = new Random();
+            for (var i = 1; i < initLen; ++i)
+            {
+                while (true)
+                {
+                    var nextPos = rnd.Next() % initLen;
+                    if (retval[nextPos] == 0)
+                    {
+                        retval[nextPos] = (byte)i;
+                        break;
+                    }
+                }
+            }
+            return retval;
+        }
+
+        public static async Task<int> ExecuteClientTestAsync(ThriftTest.Client client)
+        {
+            var token = CancellationToken.None;
+            var returnCode = 0;
+
+            Console.Write("testVoid()");
+            await client.testVoidAsync(token);
+            Console.WriteLine(" = void");
+
+            Console.Write("testString(\"Test\")");
+            var s = await client.testStringAsync("Test", token);
+            Console.WriteLine(" = \"" + s + "\"");
+            if ("Test" != s)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testBool(true)");
+            var t = await client.testBoolAsync((bool)true, token);
+            Console.WriteLine(" = " + t);
+            if (!t)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+            Console.Write("testBool(false)");
+            var f = await client.testBoolAsync((bool)false, token);
+            Console.WriteLine(" = " + f);
+            if (f)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testByte(1)");
+            var i8 = await client.testByteAsync((sbyte)1, token);
+            Console.WriteLine(" = " + i8);
+            if (1 != i8)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testI32(-1)");
+            var i32 = await client.testI32Async(-1, token);
+            Console.WriteLine(" = " + i32);
+            if (-1 != i32)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("testI64(-34359738368)");
+            var i64 = await client.testI64Async(-34359738368, token);
+            Console.WriteLine(" = " + i64);
+            if (-34359738368 != i64)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            // TODO: Validate received message
+            Console.Write("testDouble(5.325098235)");
+            var dub = await client.testDoubleAsync(5.325098235, token);
+            Console.WriteLine(" = " + dub);
+            if (5.325098235 != dub)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+            Console.Write("testDouble(-0.000341012439638598279)");
+            dub = await client.testDoubleAsync(-0.000341012439638598279, token);
+            Console.WriteLine(" = " + dub);
+            if (-0.000341012439638598279 != dub)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            var binOut = PrepareTestData(true);
+            Console.Write("testBinary(" + BytesToHex(binOut) + ")");
+            try
+            {
+                var binIn = await client.testBinaryAsync(binOut, token);
+                Console.WriteLine(" = " + BytesToHex(binIn));
+                if (binIn.Length != binOut.Length)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorBaseTypes;
+                }
+                for (var ofs = 0; ofs < Math.Min(binIn.Length, binOut.Length); ++ofs)
+                    if (binIn[ofs] != binOut[ofs])
+                    {
+                        Console.WriteLine("*** FAILED ***");
+                        returnCode |= ErrorBaseTypes;
+                    }
+            }
+            catch (Thrift.TApplicationException ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+
+            // binary equals? only with hashcode option enabled ...
+            Console.WriteLine("Test CrazyNesting");
+            var one = new CrazyNesting();
+            var two = new CrazyNesting();
+            one.String_field = "crazy";
+            two.String_field = "crazy";
+            one.Binary_field = new byte[] { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xFF };
+            two.Binary_field = new byte[10] { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xFF };
+            if (typeof(CrazyNesting).GetMethod("Equals")?.DeclaringType == typeof(CrazyNesting))
+            {
+                if (!one.Equals(two))
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorContainers;
+                    throw new Exception("CrazyNesting.Equals failed");
+                }
+            }
+
+            // TODO: Validate received message
+            Console.Write("testStruct({\"Zero\", 1, -3, -5})");
+            var o = new Xtruct();
+            o.String_thing = "Zero";
+            o.Byte_thing = (sbyte)1;
+            o.I32_thing = -3;
+            o.I64_thing = -5;
+            var i = await client.testStructAsync(o, token);
+            Console.WriteLine(" = {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}");
+
+            // TODO: Validate received message
+            Console.Write("testNest({1, {\"Zero\", 1, -3, -5}, 5})");
+            var o2 = new Xtruct2();
+            o2.Byte_thing = (sbyte)1;
+            o2.Struct_thing = o;
+            o2.I32_thing = 5;
+            var i2 = await client.testNestAsync(o2, token);
+            i = i2.Struct_thing;
+            Console.WriteLine(" = {" + i2.Byte_thing + ", {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}, " + i2.I32_thing + "}");
+
+            var mapout = new Dictionary<int, int>();
+            for (var j = 0; j < 5; j++)
+            {
+                mapout[j] = j - 10;
+            }
+            Console.Write("testMap({");
+            var first = true;
+            foreach (var key in mapout.Keys)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(key + " => " + mapout[key]);
+            }
+            Console.Write("})");
+
+            var mapin = await client.testMapAsync(mapout, token);
+
+            Console.Write(" = {");
+            first = true;
+            foreach (var key in mapin.Keys)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(key + " => " + mapin[key]);
+            }
+            Console.WriteLine("}");
+
+            // TODO: Validate received message
+            var listout = new List<int>();
+            for (var j = -2; j < 3; j++)
+            {
+                listout.Add(j);
+            }
+            Console.Write("testList({");
+            first = true;
+            foreach (var j in listout)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.Write("})");
+
+            var listin = await client.testListAsync(listout, token);
+
+            Console.Write(" = {");
+            first = true;
+            foreach (var j in listin)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.WriteLine("}");
+
+            //set
+            // TODO: Validate received message
+            var setout = new THashSet<int>();
+            for (var j = -2; j < 3; j++)
+            {
+                setout.Add(j);
+            }
+            Console.Write("testSet({");
+            first = true;
+            foreach (int j in setout)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.Write("})");
+
+            var setin = await client.testSetAsync(setout, token);
+
+            Console.Write(" = {");
+            first = true;
+            foreach (int j in setin)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    Console.Write(", ");
+                }
+                Console.Write(j);
+            }
+            Console.WriteLine("}");
+
+
+            Console.Write("testEnum(ONE)");
+            var ret = await client.testEnumAsync(Numberz.ONE, token);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.ONE != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(TWO)");
+            ret = await client.testEnumAsync(Numberz.TWO, token);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.TWO != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(THREE)");
+            ret = await client.testEnumAsync(Numberz.THREE, token);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.THREE != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(FIVE)");
+            ret = await client.testEnumAsync(Numberz.FIVE, token);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.FIVE != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testEnum(EIGHT)");
+            ret = await client.testEnumAsync(Numberz.EIGHT, token);
+            Console.WriteLine(" = " + ret);
+            if (Numberz.EIGHT != ret)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            Console.Write("testTypedef(309858235082523)");
+            var uid = await client.testTypedefAsync(309858235082523L, token);
+            Console.WriteLine(" = " + uid);
+            if (309858235082523L != uid)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorStructs;
+            }
+
+            // TODO: Validate received message
+            Console.Write("testMapMap(1)");
+            var mm = await client.testMapMapAsync(1, token);
+            Console.Write(" = {");
+            foreach (var key in mm.Keys)
+            {
+                Console.Write(key + " => {");
+                var m2 = mm[key];
+                foreach (var k2 in m2.Keys)
+                {
+                    Console.Write(k2 + " => " + m2[k2] + ", ");
+                }
+                Console.Write("}, ");
+            }
+            Console.WriteLine("}");
+
+            // TODO: Validate received message
+            var insane = new Insanity();
+            insane.UserMap = new Dictionary<Numberz, long>();
+            insane.UserMap[Numberz.FIVE] = 5000L;
+            var truck = new Xtruct();
+            truck.String_thing = "Truck";
+            truck.Byte_thing = (sbyte)8;
+            truck.I32_thing = 8;
+            truck.I64_thing = 8;
+            insane.Xtructs = new List<Xtruct>();
+            insane.Xtructs.Add(truck);
+            Console.Write("testInsanity()");
+            var whoa = await client.testInsanityAsync(insane, token);
+            Console.Write(" = {");
+            foreach (var key in whoa.Keys)
+            {
+                var val = whoa[key];
+                Console.Write(key + " => {");
+
+                foreach (var k2 in val.Keys)
+                {
+                    var v2 = val[k2];
+
+                    Console.Write(k2 + " => {");
+                    var userMap = v2.UserMap;
+
+                    Console.Write("{");
+                    if (userMap != null)
+                    {
+                        foreach (var k3 in userMap.Keys)
+                        {
+                            Console.Write(k3 + " => " + userMap[k3] + ", ");
+                        }
+                    }
+                    else
+                    {
+                        Console.Write("null");
+                    }
+                    Console.Write("}, ");
+
+                    var xtructs = v2.Xtructs;
+
+                    Console.Write("{");
+                    if (xtructs != null)
+                    {
+                        foreach (var x in xtructs)
+                        {
+                            Console.Write("{\"" + x.String_thing + "\", " + x.Byte_thing + ", " + x.I32_thing + ", " + x.I32_thing + "}, ");
+                        }
+                    }
+                    else
+                    {
+                        Console.Write("null");
+                    }
+                    Console.Write("}");
+
+                    Console.Write("}, ");
+                }
+                Console.Write("}, ");
+            }
+            Console.WriteLine("}");
+
+            sbyte arg0 = 1;
+            var arg1 = 2;
+            var arg2 = long.MaxValue;
+            var multiDict = new Dictionary<short, string>();
+            multiDict[1] = "one";
+
+            var tmpMultiDict = new List<string>();
+            foreach (var pair in multiDict)
+                tmpMultiDict.Add(pair.Key +" => "+ pair.Value);
+
+            var arg4 = Numberz.FIVE;
+            long arg5 = 5000000;
+            Console.Write("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + ",{" + string.Join(",", tmpMultiDict) + "}," + arg4 + "," + arg5 + ")");
+            var multiResponse = await client.testMultiAsync(arg0, arg1, arg2, multiDict, arg4, arg5, token);
+            Console.Write(" = Xtruct(byte_thing:" + multiResponse.Byte_thing + ",String_thing:" + multiResponse.String_thing
+                          + ",i32_thing:" + multiResponse.I32_thing + ",i64_thing:" + multiResponse.I64_thing + ")\n");
+
+            try
+            {
+                Console.WriteLine("testException(\"Xception\")");
+                await client.testExceptionAsync("Xception", token);
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Xception ex)
+            {
+                if (ex.ErrorCode != 1001 || ex.Message != "Xception")
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testException(\"TException\")");
+                await client.testExceptionAsync("TException", token);
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Thrift.TException)
+            {
+                // OK
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testException(\"ok\")");
+                await client.testExceptionAsync("ok", token);
+                // OK
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+
+            try
+            {
+                Console.WriteLine("testMultiException(\"Xception\", ...)");
+                await client.testMultiExceptionAsync("Xception", "ignore", token);
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Xception ex)
+            {
+                if (ex.ErrorCode != 1001 || ex.Message != "This is an Xception")
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testMultiException(\"Xception2\", ...)");
+                await client.testMultiExceptionAsync("Xception2", "ignore", token);
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+            }
+            catch (Xception2 ex)
+            {
+                if (ex.ErrorCode != 2002 || ex.Struct_thing.String_thing != "This is an Xception2")
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+            try
+            {
+                Console.WriteLine("testMultiException(\"success\", \"OK\")");
+                if ("OK" != (await client.testMultiExceptionAsync("success", "OK", token)).String_thing)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorExceptions;
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorExceptions;
+                Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+            }
+
+            var sw = new Stopwatch();
+            sw.Start();
+            Console.WriteLine("Test Oneway(1)");
+            await client.testOnewayAsync(1, token);
+            sw.Stop();
+            if (sw.ElapsedMilliseconds > 1000)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
+
+            Console.Write("Test Calltime()");
+            var times = 50;
+            sw.Reset();
+            sw.Start();
+            for (var k = 0; k < times; ++k)
+                await client.testVoidAsync(token);
+            sw.Stop();
+            Console.WriteLine(" = {0} ms a testVoid() call", sw.ElapsedMilliseconds / times);
+            return returnCode;
+        }
+    }
+}
diff --git a/test/netcore/Makefile.am b/test/netcore/Makefile.am
new file mode 100644
index 0000000..376ffb7
--- /dev/null
+++ b/test/netcore/Makefile.am
@@ -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.
+#
+
+SUBDIRS = . 
+
+all-local:
+	$(DOTNETCORE) build
+
+precross:
+	$(DOTNETCORE) build
+
+clean-local:
+	$(RM) -r Client/bin
+	$(RM) -r Server/bin
+	$(RM) -r Client/obj
+	$(RM) -r Server/obj
+	$(RM) -r ThriftTest/ThriftTest
+
+EXTRA_DIST = \
+	Client \
+	README.md \
+	Server \
+	ThriftTest.sln \
+	build.cmd \
+	build.sh
diff --git a/test/netcore/README.md b/test/netcore/README.md
new file mode 100644
index 0000000..ed728d1
--- /dev/null
+++ b/test/netcore/README.md
@@ -0,0 +1,20 @@
+# Apache Thrift net-core-lib tests
+
+Tests for Thrift client library ported to Microsoft .Net Core 
+
+# Content
+- ThriftTest - tests for Thrift library 
+
+# Reused components 
+- NET Core Standard 1.6 (SDK 2.0.0)
+
+# How to build on Windows
+- Get Thrift IDL compiler executable, add to some folder and add path to this folder into PATH variable
+- Open ThriftTest.sln in Visual Studio and build
+or 
+- Build with scripts
+
+# How to build on Unix
+- Ensure you have .NET Core 2.0.0 SDK installed or use the Ubuntu Xenial docker image
+- Follow common build practice for Thrift: bootstrap, configure, and make precross
+
diff --git a/test/netcore/Server/.gitignore b/test/netcore/Server/.gitignore
new file mode 100644
index 0000000..67d5510
--- /dev/null
+++ b/test/netcore/Server/.gitignore
@@ -0,0 +1,2 @@
+# ignore for autogenerated files
+/ThriftTest
diff --git a/test/netcore/Server/Program.cs b/test/netcore/Server/Program.cs
new file mode 100644
index 0000000..e647e5b
--- /dev/null
+++ b/test/netcore/Server/Program.cs
@@ -0,0 +1,72 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using ThriftTest;
+
+namespace Server
+{
+    public class Program
+    {
+        public static int Main(string[] args)
+        {
+            try
+            {
+                Console.SetBufferSize(Console.BufferWidth, 4096);
+            }
+            catch (Exception)
+            {
+                Console.WriteLine("Failed to grow scroll-back buffer");
+            }
+
+            // split mode and options
+            var subArgs = new List<string>(args);
+            var firstArg = string.Empty;
+            if (subArgs.Count > 0)
+            { 
+                firstArg = subArgs[0];
+                subArgs.RemoveAt(0);
+            }
+
+            // run whatever mode is choosen
+            switch(firstArg)
+            {
+                case "server":
+                    return TestServer.Execute(subArgs);
+                case "--help":
+                    PrintHelp();
+                    return 0;
+                default:
+                    PrintHelp();
+                    return -1;
+            }
+        }
+
+        private static void PrintHelp()
+        {
+            Console.WriteLine("Usage:");
+            Console.WriteLine("  Server  server  [options]'");
+            Console.WriteLine("  Server  --help");
+            Console.WriteLine("");
+
+            TestServer.PrintOptionsHelp();
+        }
+    }
+}
+
+
diff --git a/test/netcore/Server/Properties/AssemblyInfo.cs b/test/netcore/Server/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..265495c
--- /dev/null
+++ b/test/netcore/Server/Properties/AssemblyInfo.cs
@@ -0,0 +1,43 @@
+// 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.
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+
+[assembly: AssemblyTitle("Server")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+
+[assembly: Guid("B0C13DA0-3117-4844-8AE8-B1775E46223D")]
+
diff --git a/test/netcore/Server/Server.csproj b/test/netcore/Server/Server.csproj
new file mode 100644
index 0000000..2f9b4b1
--- /dev/null
+++ b/test/netcore/Server/Server.csproj
@@ -0,0 +1,31 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.0</TargetFramework>
+    <AssemblyName>Server</AssemblyName>
+    <PackageId>Server</PackageId>
+    <OutputType>Exe</OutputType>
+    <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
+    <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
+    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
+    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
+    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
+    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="System.Net.Http.WinHttpHandler" Version="[4.4,)" />
+    <PackageReference Include="System.Runtime.Serialization.Primitives" Version="[4.3,)" />
+    <PackageReference Include="System.ServiceModel.Primitives" Version="[4.4,)" />
+    <PackageReference Include="System.Threading" Version="[4.3,)" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\lib\netcore\Thrift\Thrift.csproj" />
+  </ItemGroup>
+  <Target Name="PreBuild" BeforeTargets="_GenerateRestoreProjectSpec;Restore;Compile">
+    <Exec Condition="'$(OS)' == 'Windows_NT'" Command="where thrift" ConsoleToMSBuild="true">
+      <Output TaskParameter="ConsoleOutput" PropertyName="PathToThrift" />
+    </Exec>
+    <Exec Condition="Exists('$(PathToThrift)')" Command="&quot;$(PathToThrift)&quot; -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../ThriftTest.thrift" />
+    <Exec Condition="Exists('thrift')" Command="thrift -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../ThriftTest.thrift" />
+    <Exec Condition="Exists('$(ProjectDir)/../../../compiler/cpp/thrift')" Command="$(ProjectDir)/../../../compiler/cpp/thrift -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../ThriftTest.thrift" />
+  </Target>
+</Project>
\ No newline at end of file
diff --git a/test/netcore/Server/TestServer.cs b/test/netcore/Server/TestServer.cs
new file mode 100644
index 0000000..bfd3335
--- /dev/null
+++ b/test/netcore/Server/TestServer.cs
@@ -0,0 +1,594 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Thrift;
+using Thrift.Collections;
+using Thrift.Protocols;
+using Thrift.Server;
+using Thrift.Transports;
+using Thrift.Transports.Server;
+
+namespace ThriftTest
+{
+    internal class ServerParam
+    {
+        internal bool useBufferedSockets = false;
+        internal bool useFramed = false;
+        internal bool useEncryption = false;
+        internal bool compact = false;
+        internal bool json = false;
+        internal int port = 9090;
+        internal string pipe = null;
+
+        internal void Parse(List<string> args)
+        {
+            for (var i = 0; i < args.Count; i++)
+            {
+                if (args[i].StartsWith("--pipe="))
+                {
+                    pipe = args[i].Substring(args[i].IndexOf("=") + 1);
+                }
+                else if (args[i].StartsWith("--port="))
+                {
+                    port = int.Parse(args[i].Substring(args[i].IndexOf("=") + 1));
+                }
+                else if (args[i] == "-b" || args[i] == "--buffered" || args[i] == "--transport=buffered")
+                {
+                    useBufferedSockets = true;
+                }
+                else if (args[i] == "-f" || args[i] == "--framed" || args[i] == "--transport=framed")
+                {
+                    useFramed = true;
+                }
+                else if (args[i] == "--binary" || args[i] == "--protocol=binary")
+                {
+                    // nothing needed
+                }
+                else if (args[i] == "--compact" || args[i] == "--protocol=compact")
+                {
+                    compact = true;
+                }
+                else if (args[i] == "--json" || args[i] == "--protocol=json")
+                {
+                    json = true;
+                }
+                else if (args[i] == "--threaded" || args[i] == "--server-type=threaded")
+                {
+                    throw new NotImplementedException(args[i]);
+                }
+                else if (args[i] == "--threadpool" || args[i] == "--server-type=threadpool")
+                {
+                    throw new NotImplementedException(args[i]);
+                }
+                else if (args[i] == "--prototype" || args[i] == "--processor=prototype")
+                {
+                    throw new NotImplementedException(args[i]);
+                }
+                else if (args[i] == "--ssl")
+                {
+                    useEncryption = true;
+                }
+                else
+                {
+                    //throw new ArgumentException(args[i]);
+                }
+            }
+
+        }
+    }
+
+    public class TestServer
+    {
+        public static int _clientID = -1;
+        public delegate void TestLogDelegate(string msg, params object[] values);
+
+        public class MyServerEventHandler : TServerEventHandler
+        {
+            public int callCount = 0;
+
+            public Task PreServeAsync(CancellationToken cancellationToken)
+            {
+                callCount++;
+                return Task.CompletedTask;
+            }
+
+            public Task<object> CreateContextAsync(TProtocol input, TProtocol output, CancellationToken cancellationToken)
+            {
+                callCount++;
+                return Task.FromResult<object>(null);
+            }
+
+            public Task DeleteContextAsync(object serverContext, TProtocol input, TProtocol output, CancellationToken cancellationToken)
+            {
+                callCount++;
+                return Task.CompletedTask;
+            }
+
+            public Task ProcessContextAsync(object serverContext, TClientTransport transport, CancellationToken cancellationToken)
+            {
+                callCount++;
+                return Task.CompletedTask;
+            }
+        }
+
+        public class TestHandlerAsync : ThriftTest.IAsync
+        {
+            public TBaseServer server { get; set; }
+            private int handlerID;
+            private StringBuilder sb = new StringBuilder();
+            private TestLogDelegate logger;
+
+            public TestHandlerAsync()
+            {
+                handlerID = Interlocked.Increment(ref _clientID);
+                logger += testConsoleLogger;
+                logger.Invoke("New TestHandler instance created");
+            }
+
+            public void testConsoleLogger(string msg, params object[] values)
+            {
+                sb.Clear();
+                sb.AppendFormat("handler{0:D3}:", handlerID);
+                sb.AppendFormat(msg, values);
+                sb.AppendLine();
+                Console.Write(sb.ToString());
+            }
+
+            public Task testVoidAsync(CancellationToken cancellationToken)
+            {
+                logger.Invoke("testVoid()");
+                return Task.CompletedTask;
+            }
+
+            public Task<string> testStringAsync(string thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testString({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task<bool> testBoolAsync(bool thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testBool({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task<sbyte> testByteAsync(sbyte thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testByte({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task<int> testI32Async(int thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testI32({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task<long> testI64Async(long thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testI64({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task<double> testDoubleAsync(double thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testDouble({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task<byte[]> testBinaryAsync(byte[] thing, CancellationToken cancellationToken)
+            {
+                var hex = BitConverter.ToString(thing).Replace("-", string.Empty);
+                logger.Invoke("testBinary({0:X})", hex);
+                return Task.FromResult(thing);
+            }
+
+            public Task<Xtruct> testStructAsync(Xtruct thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testStruct({{\"{0}\", {1}, {2}, {3}}})", thing.String_thing, thing.Byte_thing, thing.I32_thing, thing.I64_thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task<Xtruct2> testNestAsync(Xtruct2 nest, CancellationToken cancellationToken)
+            {
+                var thing = nest.Struct_thing;
+                logger.Invoke("testNest({{{0}, {{\"{1}\", {2}, {3}, {4}, {5}}}}})",
+                    nest.Byte_thing,
+                    thing.String_thing,
+                    thing.Byte_thing,
+                    thing.I32_thing,
+                    thing.I64_thing,
+                    nest.I32_thing);
+                return Task.FromResult(nest);
+            }
+
+            public Task<Dictionary<int, int>> testMapAsync(Dictionary<int, int> thing, CancellationToken cancellationToken)
+            {
+                sb.Clear();
+                sb.Append("testMap({{");
+                var first = true;
+                foreach (var key in thing.Keys)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        sb.Append(", ");
+                    }
+                    sb.AppendFormat("{0} => {1}", key, thing[key]);
+                }
+                sb.Append("}})");
+                logger.Invoke(sb.ToString());
+                return Task.FromResult(thing);
+            }
+
+            public Task<Dictionary<string, string>> testStringMapAsync(Dictionary<string, string> thing, CancellationToken cancellationToken)
+            {
+                sb.Clear();
+                sb.Append("testStringMap({{");
+                var first = true;
+                foreach (var key in thing.Keys)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        sb.Append(", ");
+                    }
+                    sb.AppendFormat("{0} => {1}", key, thing[key]);
+                }
+                sb.Append("}})");
+                logger.Invoke(sb.ToString());
+                return Task.FromResult(thing);
+            }
+
+            public Task<THashSet<int>> testSetAsync(THashSet<int> thing, CancellationToken cancellationToken)
+            {
+                sb.Clear();
+                sb.Append("testSet({{");
+                var first = true;
+                foreach (int elem in thing)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        sb.Append(", ");
+                    }
+                    sb.AppendFormat("{0}", elem);
+                }
+                sb.Append("}})");
+                logger.Invoke(sb.ToString());
+                return Task.FromResult(thing);
+            }
+
+            public Task<List<int>> testListAsync(List<int> thing, CancellationToken cancellationToken)
+            {
+                sb.Clear();
+                sb.Append("testList({{");
+                var first = true;
+                foreach (var elem in thing)
+                {
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        sb.Append(", ");
+                    }
+                    sb.AppendFormat("{0}", elem);
+                }
+                sb.Append("}})");
+                logger.Invoke(sb.ToString());
+                return Task.FromResult(thing);
+            }
+
+            public Task<Numberz> testEnumAsync(Numberz thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testEnum({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task<long> testTypedefAsync(long thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testTypedef({0})", thing);
+                return Task.FromResult(thing);
+            }
+
+            public Task<Dictionary<int, Dictionary<int, int>>> testMapMapAsync(int hello, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testMapMap({0})", hello);
+                var mapmap = new Dictionary<int, Dictionary<int, int>>();
+
+                var pos = new Dictionary<int, int>();
+                var neg = new Dictionary<int, int>();
+                for (var i = 1; i < 5; i++)
+                {
+                    pos[i] = i;
+                    neg[-i] = -i;
+                }
+
+                mapmap[4] = pos;
+                mapmap[-4] = neg;
+
+                return Task.FromResult(mapmap);
+            }
+
+            public Task<Dictionary<long, Dictionary<Numberz, Insanity>>> testInsanityAsync(Insanity argument, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testInsanity()");
+
+                /** from ThriftTest.thrift:
+                 * So you think you've got this all worked, out eh?
+                 *
+                 * Creates a the returned map with these values and prints it out:
+                 *   { 1 => { 2 => argument,
+                 *            3 => argument,
+                 *          },
+                 *     2 => { 6 => <empty Insanity struct>, },
+                 *   }
+                 * @return map<UserId, map<Numberz,Insanity>> - a map with the above values
+                 */
+
+                var first_map = new Dictionary<Numberz, Insanity>();
+                var second_map = new Dictionary<Numberz, Insanity>(); ;
+
+                first_map[Numberz.TWO] = argument;
+                first_map[Numberz.THREE] = argument;
+
+                second_map[Numberz.SIX] = new Insanity();
+
+                var insane = new Dictionary<long, Dictionary<Numberz, Insanity>>
+                {
+                    [1] = first_map,
+                    [2] = second_map
+                };
+
+                return Task.FromResult(insane);
+            }
+
+            public Task<Xtruct> testMultiAsync(sbyte arg0, int arg1, long arg2, Dictionary<short, string> arg3, Numberz arg4, long arg5,
+                CancellationToken cancellationToken)
+            {
+                logger.Invoke("testMulti()");
+
+                var hello = new Xtruct(); ;
+                hello.String_thing = "Hello2";
+                hello.Byte_thing = arg0;
+                hello.I32_thing = arg1;
+                hello.I64_thing = arg2;
+                return Task.FromResult(hello);
+            }
+
+            public Task testExceptionAsync(string arg, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testException({0})", arg);
+                if (arg == "Xception")
+                {
+                    var x = new Xception
+                    {
+                        ErrorCode = 1001,
+                        Message = arg
+                    };
+                    throw x;
+                }
+                if (arg == "TException")
+                {
+                    throw new TException();
+                }
+                return Task.CompletedTask;
+            }
+
+            public Task<Xtruct> testMultiExceptionAsync(string arg0, string arg1, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testMultiException({0}, {1})", arg0, arg1);
+                if (arg0 == "Xception")
+                {
+                    var x = new Xception
+                    {
+                        ErrorCode = 1001,
+                        Message = "This is an Xception"
+                    };
+                    throw x;
+                }
+
+                if (arg0 == "Xception2")
+                {
+                    var x = new Xception2
+                    {
+                        ErrorCode = 2002,
+                        Struct_thing = new Xtruct { String_thing = "This is an Xception2" }
+                    };
+                    throw x;
+                }
+
+                var result = new Xtruct { String_thing = arg1 };
+                return Task.FromResult(result);
+            }
+
+            public Task testOnewayAsync(int secondsToSleep, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testOneway({0}), sleeping...", secondsToSleep);
+                Task.Delay(secondsToSleep * 1000, cancellationToken).GetAwaiter().GetResult();
+                logger.Invoke("testOneway finished");
+
+                return Task.CompletedTask;
+            }
+        }
+
+        internal static void PrintOptionsHelp()
+        {
+            Console.WriteLine("Server options:");
+            Console.WriteLine("  --pipe=<pipe name>");
+            Console.WriteLine("  --port=<port number>");
+            Console.WriteLine("  --transport=<transport name>    one of buffered,framed  (defaults to none)");
+            Console.WriteLine("  --protocol=<protocol name>      one of compact,json  (defaults to binary)");
+            Console.WriteLine("  --server-type=<type>            one of threaded,threadpool  (defaults to simple)");
+            Console.WriteLine("  --processor=<prototype>");
+            Console.WriteLine("  --ssl");
+            Console.WriteLine();
+        }
+
+        private static X509Certificate2 GetServerCert()
+        {
+            var serverCertName = "server.p12";
+            var possiblePaths = new List<string>
+            {
+                "../../../keys/",
+                "../../keys/",
+                "../keys/",
+                "keys/",
+            };
+                        
+            string existingPath = null;
+            foreach (var possiblePath in possiblePaths)
+            {
+                var path = Path.GetFullPath(possiblePath + serverCertName);
+                if (File.Exists(path))
+                {
+                    existingPath = path;
+                    break;
+                }
+            }
+                        
+            if (string.IsNullOrEmpty(existingPath))
+            {
+                throw new FileNotFoundException($"Cannot find file: {serverCertName}");
+            }
+                                    
+            var cert = new X509Certificate2(existingPath, "thrift");
+                        
+            return cert;
+        }
+
+        public static int Execute(List<string> args)
+        {
+            var loggerFactory = new LoggerFactory();//.AddConsole().AddDebug();
+            var logger = new LoggerFactory().CreateLogger("Test");
+
+            try
+            {
+                var param = new ServerParam();
+
+                try
+                {
+                    param.Parse(args);
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    Console.WriteLine("Error while  parsing arguments");
+                    Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                    return 1;
+                }
+
+
+                // Transport
+                TServerTransport trans;
+                if (param.pipe != null)
+                {
+                    trans = new TNamedPipeServerTransport(param.pipe);
+                }
+//                else if (param.useFramed)
+//                {
+//                    trans = new TServerFramedTransport(param.port);
+//                }
+                else
+                {
+                    if (param.useEncryption)
+                    {
+                        var cert = GetServerCert();
+                        
+                        if (cert == null || !cert.HasPrivateKey)
+                        {
+                            throw new InvalidOperationException("Certificate doesn't contain private key");
+                        }
+                        
+                        trans = new TTlsServerSocketTransport(param.port, param.useBufferedSockets, param.useFramed, cert, 
+                            (sender, certificate, chain, errors) => true, 
+                            null, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12);
+                    }
+                    else
+                    {
+                        trans = new TServerSocketTransport(param.port, 0, param.useBufferedSockets, param.useFramed);
+                    }
+                }
+
+                ITProtocolFactory proto;
+                if (param.compact)
+                    proto = new TCompactProtocol.Factory();
+                else if (param.json)
+                    proto = new TJsonProtocol.Factory();
+                else
+                    proto = new TBinaryProtocol.Factory();
+
+                ITProcessorFactory processorFactory;
+
+                // Processor
+                var testHandler = new TestHandlerAsync();
+                var testProcessor = new ThriftTest.AsyncProcessor(testHandler);
+                processorFactory = new SingletonTProcessorFactory(testProcessor);
+
+                TTransportFactory transFactory = new TTransportFactory(); 
+
+                TBaseServer serverEngine = new AsyncBaseServer(processorFactory, trans, transFactory, transFactory, proto, proto, logger);
+
+                //Server event handler
+                var serverEvents = new MyServerEventHandler();
+                serverEngine.SetEventHandler(serverEvents);
+
+                // Run it
+                var where = (! string.IsNullOrEmpty(param.pipe)) ? "on pipe " + param.pipe : "on port " + param.port;
+                Console.WriteLine("Starting the AsyncBaseServer " + where +
+                                  " with processor TPrototypeProcessorFactory prototype factory " +
+                                  (param.useBufferedSockets ? " with buffered socket" : "") +
+                                  (param.useFramed ? " with framed transport" : "") +
+                                  (param.useEncryption ? " with encryption" : "") +
+                                  (param.compact ? " with compact protocol" : "") +
+                                  (param.json ? " with json protocol" : "") +
+                                  "...");
+                serverEngine.ServeAsync(CancellationToken.None).GetAwaiter().GetResult();
+                Console.ReadLine();
+            }
+            catch (Exception x)
+            {
+                Console.Error.Write(x);
+                return 1;
+            }
+            Console.WriteLine("done.");
+            return 0;
+        }
+    }
+
+}
diff --git a/test/netcore/ThriftTest.sln b/test/netcore/ThriftTest.sln
new file mode 100644
index 0000000..2ab241a
--- /dev/null
+++ b/test/netcore/ThriftTest.sln
@@ -0,0 +1,64 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26730.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift", "..\..\lib\netcore\Thrift\Thrift.csproj", "{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Client\Client.csproj", "{21039F25-6ED7-4E80-A545-EBC93472EBD1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{0C6E8685-F191-4479-9842-882A38961127}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x64.Build.0 = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x86.Build.0 = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x64.ActiveCfg = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x64.Build.0 = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x86.ActiveCfg = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x86.Build.0 = Release|Any CPU
+		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Debug|x64.Build.0 = Debug|Any CPU
+		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Debug|x86.Build.0 = Debug|Any CPU
+		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Release|x64.ActiveCfg = Release|Any CPU
+		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Release|x64.Build.0 = Release|Any CPU
+		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Release|x86.ActiveCfg = Release|Any CPU
+		{21039F25-6ED7-4E80-A545-EBC93472EBD1}.Release|x86.Build.0 = Release|Any CPU
+		{0C6E8685-F191-4479-9842-882A38961127}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0C6E8685-F191-4479-9842-882A38961127}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0C6E8685-F191-4479-9842-882A38961127}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{0C6E8685-F191-4479-9842-882A38961127}.Debug|x64.Build.0 = Debug|Any CPU
+		{0C6E8685-F191-4479-9842-882A38961127}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{0C6E8685-F191-4479-9842-882A38961127}.Debug|x86.Build.0 = Debug|Any CPU
+		{0C6E8685-F191-4479-9842-882A38961127}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0C6E8685-F191-4479-9842-882A38961127}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0C6E8685-F191-4479-9842-882A38961127}.Release|x64.ActiveCfg = Release|Any CPU
+		{0C6E8685-F191-4479-9842-882A38961127}.Release|x64.Build.0 = Release|Any CPU
+		{0C6E8685-F191-4479-9842-882A38961127}.Release|x86.ActiveCfg = Release|Any CPU
+		{0C6E8685-F191-4479-9842-882A38961127}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {52CE9A12-F6CB-4F0C-BB42-0105612F5FF4}
+	EndGlobalSection
+EndGlobal
diff --git a/test/netcore/build.cmd b/test/netcore/build.cmd
new file mode 100644
index 0000000..9b84ef2
--- /dev/null
+++ b/test/netcore/build.cmd
@@ -0,0 +1,25 @@
+@echo off
+rem /*
+rem  * Licensed to the Apache Software Foundation (ASF) under one
+rem  * or more contributor license agreements. See the NOTICE file
+rem  * distributed with this work for additional information
+rem  * regarding copyright ownership. The ASF licenses this file
+rem  * to you under the Apache License, Version 2.0 (the
+rem  * "License"); you may not use this file except in compliance
+rem  * with the License. You may obtain a copy of the License at
+rem  *
+rem  *   http://www.apache.org/licenses/LICENSE-2.0
+rem  *
+rem  * Unless required by applicable law or agreed to in writing,
+rem  * software distributed under the License is distributed on an
+rem  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem  * KIND, either express or implied. See the License for the
+rem  * specific language governing permissions and limitations
+rem  * under the License.
+rem  */
+setlocal
+
+dotnet --info
+dotnet build
+
+:eof
diff --git a/test/netcore/build.sh b/test/netcore/build.sh
new file mode 100755
index 0000000..c97e310
--- /dev/null
+++ b/test/netcore/build.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+#
+# 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.
+#
+
+#exit if any command fails
+set -e
+
+dotnet --info
+dotnet build
diff --git a/test/nodejs/Makefile.am b/test/nodejs/Makefile.am
deleted file mode 100755
index f796b07..0000000
--- a/test/nodejs/Makefile.am
+++ /dev/null
@@ -1,42 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-
-THRIFT = $(top_srcdir)/compiler/cpp/thrift
-
-stubs: ../ThriftTest.thrift
-	$(THRIFT) --gen js:node ../ThriftTest.thrift
-
-check: stubs
-	@if which nodeunit &> /dev/null ; then \
-		echo "   Testing thrift/binary"; \
-		NODE_PATH=../../lib/nodejs/lib:../../lib/nodejs/lib/thrift:$(NODE_PATH) nodeunit ../../lib/nodejs/test/binary.test.js; \
-	fi
-	@if which node &> /dev/null ; then \
-		echo "   Testing Client/Server"; \
-		timeout -s14 5 $(MAKE) server & \
-		sleep 1; $(MAKE) client; sleep 2; \
-	fi
-
-clean-local:
-	$(RM) -r gen-nodejs
-
-server:
-	NODE_PATH=../../lib/nodejs/lib:../../lib/nodejs/lib/thrift:$(NODE_PATH) node server.js
-
-client:
-	NODE_PATH=../../lib/nodejs/lib:../../lib/nodejs/lib/thrift:$(NODE_PATH) node client.js
diff --git a/test/nodejs/client.js b/test/nodejs/client.js
deleted file mode 100644
index d96400e..0000000
--- a/test/nodejs/client.js
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-var thrift = require('thrift');
-var ttransport = require('transport');
-var assert = require('assert');
-
-var ThriftTest = require('./gen-nodejs/ThriftTest'),
-    ttypes = require('./gen-nodejs/ThriftTest_types');
-
-var connection = thrift.createConnection('localhost', 9090, { 'transport': ttransport.TFramedTransport }),
-//var connection = thrift.createConnection('localhost', 9090),
-    client = thrift.createClient(ThriftTest, connection);
-
-connection.on('error', function(err) {
-  assert(false, err);
-});
-
- // deepEqual doesn't work with fields using node-int64
-function checkRecursively(map1, map2) {
-  if (typeof map1 !== 'function' && typeof map2 !== 'function') {
-    if (!map1 || typeof map1 !== 'object') {
-        assert.equal(map1, map2);
-    } else {
-      for (var key in map1) {
-        checkRecursively(map1[key], map2[key]);
-      }
-    }
-  }
-}
-
-
-client.testVoid(function(err, response) {
-  assert( ! err);
-  assert.equal(undefined, response); //void
-});
-
-
-client.testString("Test", function(err, response) {
-  assert( ! err);
-  assert.equal("Test", response);
-});
-
-client.testString("", function(err, response) {
-  assert( ! err);
-  assert.equal("", response);
-});
-
-// all Languages in UTF-8
-var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語";
-client.testString(stringTest, function(err, response) {
-  assert( ! err);
-  assert.equal(stringTest, response);
-});
-
-var specialCharacters = 'quote: \" backslash:' +
-    ' forwardslash-escaped: \/ ' +
-    ' backspace: \b formfeed: \f newline: \n return: \r tab: ' +
-    ' now-all-of-them-together: "\\\/\b\n\r\t' +
-    ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><';
-client.testString(specialCharacters, function(err, response) {
-  assert( ! err);
-  assert.equal(specialCharacters, response);
-});
-
-
-client.testByte(1, function(err, response) {
-  assert( ! err);
-  assert.equal(1, response);
-});
-client.testByte(0, function(err, response) {
-  assert( ! err);
-  assert.equal(0, response);
-});
-client.testByte(-1, function(err, response) {
-  assert( ! err);
-  assert.equal(-1, response);
-});
-client.testByte(-127, function(err, response) {
-  assert( ! err);
-  assert.equal(-127, response);
-});
-
-client.testI32(-1, function(err, response) {
-  assert( ! err);
-  assert.equal(-1, response);
-});
-
-client.testI64(5, function(err, response) {
-  assert( ! err);
-  assert.equal(5, response);
-});
-client.testI64(-5, function(err, response) {
-  assert( ! err);
-  assert.equal(-5, response);
-});
-client.testI64(-34359738368, function(err, response) {
-  assert( ! err);
-  assert.equal(-34359738368, response);
-});
-
-client.testDouble(-5.2098523, function(err, response) {
-  assert( ! err);
-  assert.equal(-5.2098523, response);
-});
-client.testDouble(7.012052175215044, function(err, response) {
-  assert( ! err);
-  assert.equal(7.012052175215044, response);
-});
-
-
-var out = new ttypes.Xtruct({
-  string_thing: 'Zero',
-  byte_thing: 1,
-  i32_thing: -3,
-  i64_thing: 1000000
-});
-client.testStruct(out, function(err, response) {
-  assert( ! err);
-  checkRecursively(out, response);
-});
-
-
-var out2 = new ttypes.Xtruct2();
-out2.byte_thing = 1;
-out2.struct_thing = out;
-out2.i32_thing = 5;
-client.testNest(out2, function(err, response) {
-  assert( ! err);
-  checkRecursively(out2, response);
-});
-
-
-var mapout = {};
-for (var i = 0; i < 5; ++i) {
-  mapout[i] = i-10;
-}
-client.testMap(mapout, function(err, response) {
-  assert( ! err);
-  assert.deepEqual(mapout, response);
-});
-
-
-var mapTestInput = {
-  "a":"123", "a b":"with spaces ", "same":"same", "0":"numeric key",
-  "longValue":stringTest, stringTest:"long key"
-};
-client.testStringMap(mapTestInput, function(err, response) {
-  assert( ! err);
-  assert.deepEqual(mapTestInput, response);
-});
-
-
-var setTestInput = [1,2,3];
-client.testSet(setTestInput, function(err, response) {
-  assert( ! err);
-  assert.deepEqual(setTestInput, response);
-});
-client.testList(setTestInput, function(err, response) {
-  assert( ! err);
-  assert.deepEqual(setTestInput, response);
-});
-
-client.testEnum(ttypes.Numberz.ONE, function(err, response) {
-  assert( ! err);
-  assert.equal(ttypes.Numberz.ONE, response);
-});
-
-client.testTypedef(69, function(err, response) {
-  assert( ! err);
-  assert.equal(69, response);
-});
-
-
-var mapMapTest = {
-  "4": {"1":1, "2":2, "3":3, "4":4},
-  "-4": {"-4":-4, "-3":-3, "-2":-2, "-1":-1}
-};
-client.testMapMap(mapMapTest, function(err, response) {
-  assert( ! err);
-  assert.deepEqual(mapMapTest, response);
-});
-
-var crazy = new ttypes.Insanity({
-  "userMap":{ "5":5, "8":8 },
-  "xtructs":[new ttypes.Xtruct({
-      "string_thing":"Goodbye4",
-      "byte_thing":4,
-      "i32_thing":4,
-      "i64_thing":4
-    }), new ttypes.Xtruct({
-      "string_thing":"Hello2",
-      "byte_thing":2,
-      "i32_thing":2,
-      "i64_thing":2
-    })]
-});
-var insanity = {
-  "1":{ "2": crazy, "3": crazy },
-  "2":{ "6":{ "userMap":null, "xtructs":null } }
-};
-client.testInsanity(crazy, function(err, response) {
-  assert( ! err);
-  checkRecursively(insanity, response);
-});
-
-
-client.testException('TException', function(err, response) {
-  //assert(err); //BUG?
-  assert( ! response);
-});
-client.testException('Xception', function(err, response) {
-  assert( ! response);
-  assert.equal(err.errorCode, 1001);
-  assert.equal('Xception', err.message);
-});
-client.testException('no Exception', function(err, response) {
-  assert( ! err);
-  assert.equal(undefined, response); //void
-});
-
-
-client.testOneway(1, function(err, response) {
-  assert(false); //should not answer
-});
-
-/**
- * redo a simple test after the oneway to make sure we aren't "off by one" --
- * if the server treated oneway void like normal void, this next test will
- * fail since it will get the void confirmation rather than the correct
- * result. In this circumstance, the client will throw the exception:
- *
- *   TApplicationException: Wrong method namea
- */
-client.testI32(-1, function(err, response) {
-  assert( ! err);
-  assert.equal(-1, response);
-});
-
-setTimeout(function() {
-  console.log("Server successfully tested!");
-  connection.end();
-}, 1500);
-
-// to make it also run on expresso
-exports.expressoTest = function() {};
-
diff --git a/test/nodejs/package.json b/test/nodejs/package.json
deleted file mode 100755
index 85adef1..0000000
--- a/test/nodejs/package.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
-  "name": "thrift-nodejs-test",
-  "version": "1.0.0-dev",
-  "description": "node.js test server and client for the Apache Thrift",
-  "homepage": "http://thrift.apache.org/",
-  "repository":
-    { "type" : "git",
-      "url" : "https://git-wip-us.apache.org/repos/asf/thrift.git"
-    },
-  "author":
-    { "name": "Apache Thrift Developers",
-      "email": "dev@thrift.apache.org",
-      "url": "http://thrift.apache.org"
-    },
-  "licenses":
-    [ { "type": "Apache-2.0",
-        "url": "http://www.apache.org/licenses/LICENSE-2.0"
-      }
-    ],
-  "bugs":
-    { "mail": "dev@thrift.apache.org",
-      "url": "https://issues.apache.org/jira/browse/THRIFT"
-    },
-  "directories" : { "lib" : "../lib/nodejs/lib/thrift" },
-  "main": "../lib/nodejs/lib/thrift",
-  "scripts": {
-    "start": "node ./http-server"
-  },
-  "engines": { "node": ">= 0.2.4" }
-}
diff --git a/test/nodejs/server.js b/test/nodejs/server.js
deleted file mode 100644
index 28eeeae..0000000
--- a/test/nodejs/server.js
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * 'License'); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-var thrift = require('thrift');
-var Thrift = thrift.Thrift;
-var ttransport = require('transport');
-
-var ThriftTest = require('./gen-nodejs/ThriftTest'),
-    ttypes = require('./gen-nodejs/ThriftTest_types');
-
-
-var server = thrift.createServer(ThriftTest, {
-  testVoid: function(result) {
-    console.log('testVoid()');
-    result(null);
-  },
-
-  testString: function(thing, result) {
-    console.log('testString(\'' + thing + '\')');
-    result(null, thing);
-  },
-
-  testByte: function(thing, result) {
-    console.log('testByte(' + thing + ')');
-    result(null, thing);
-  },
-
-  testI32: function(thing, result) {
-    console.log('testI32(' + thing + ')');
-    result(null, thing);
-  },
-
-  testI64: function(thing, result) {
-    console.log('testI64(' + thing + ')');
-    result(null, thing);
-  },
-
-  testDouble: function(thing, result) {
-    console.log('testDouble(' + thing + ')');
-    result(null, thing);
-  },
-
-  testStruct: function(thing, result) {
-    console.log('testStruct(');
-    console.log(thing);
-    console.log(')');
-    result(null, thing);
-  },
-
-  testNest: function(nest, result) {
-    console.log('testNest(');
-    console.log(nest);
-    console.log(')');
-    result(null, nest);
-  },
-
-  testMap: function(thing, result) {
-    console.log('testMap(');
-    console.log(thing);
-    console.log(')');
-    result(null, thing);
-  },
-
-  testStringMap: function(thing, result) {
-    console.log('testStringMap(');
-    console.log(thing);
-    console.log(')');
-    result(null, thing);
-  },
-
-  testSet: function(thing, result) {
-    console.log('testSet(');
-    console.log(thing);
-    console.log(')');
-    result(null, thing);
-  },
-
-  testList: function(thing, result) {
-    console.log('testList(');
-    console.log(thing);
-    console.log(')');
-    result(null, thing);
-  },
-
-  testEnum: function(thing, result) {
-    console.log('testEnum(' + thing + ')');
-    result(null, thing);
-  },
-
-  testTypedef: function(thing, result) {
-    console.log('testTypedef(' + thing + ')');
-    result(null, thing);
-  },
-
-  testMapMap: function(hello, result) {
-    console.log('testMapMap(' + hello + ')');
-
-    var mapmap = [];
-    var pos = [];
-    var neg = [];
-    for (var i = 1; i < 5; i++) {
-      pos[i] = i;
-      neg[-i] = -i;
-    }
-    mapmap[4] = pos;
-    mapmap[-4] = neg;
-
-    result(null, mapmap);
-  },
-
-  testInsanity: function(argument, result) {
-    console.log('testInsanity(');
-    console.log(argument);
-    console.log(')');
-
-    var hello = new ttypes.Xtruct();
-    hello.string_thing = 'Hello2';
-    hello.byte_thing = 2;
-    hello.i32_thing = 2;
-    hello.i64_thing = 2;
-
-    var goodbye = new ttypes.Xtruct();
-    goodbye.string_thing = 'Goodbye4';
-    goodbye.byte_thing = 4;
-    goodbye.i32_thing = 4;
-    goodbye.i64_thing = 4;
-
-    var crazy = new ttypes.Insanity();
-    crazy.userMap = [];
-    crazy.userMap[ttypes.Numberz.EIGHT] = 8;
-    crazy.userMap[ttypes.Numberz.FIVE] = 5;
-    crazy.xtructs = [goodbye, hello];
-
-    var first_map = [];
-    var second_map = [];
-
-    first_map[ttypes.Numberz.TWO] = crazy;
-    first_map[ttypes.Numberz.THREE] = crazy;
-
-    var looney = new ttypes.Insanity();
-    second_map[ttypes.Numberz.SIX] = looney;
-
-    var insane = [];
-    insane[1] = first_map;
-    insane[2] = second_map;
-
-    console.log('insane result:');
-    console.log(insane);
-    result(null, insane);
-  },
-
-  testMulti: function(arg0, arg1, arg2, arg3, arg4, arg5, result) {
-    console.log('testMulti()');
-
-    var hello = new ttypes.Xtruct();;
-    hello.string_thing = 'Hello2';
-    hello.byte_thing = arg0;
-    hello.i32_thing = arg1;
-    hello.i64_thing = arg2;
-    result(null, hello);
-  },
-
-  testException: function(arg, result) {
-    console.log('testException('+arg+')');
-    if (arg === 'Xception') {
-      var x = new ttypes.Xception();
-      x.errorCode = 1001;
-      x.message = arg;
-      result(x);
-    } else if (arg === 'TException') {
-      result(new Thrift.TException(arg));
-    } else {
-      result(null);
-    }
-  },
-
-  testMultiException: function(arg0, arg1, result) {
-    console.log('testMultiException(' + arg0 + ', ' + arg1 + ')');
-    if (arg0 === ('Xception')) {
-      var x = new ttypes.Xception();
-      x.errorCode = 1001;
-      x.message = 'This is an Xception';
-      result(x);
-    } else if (arg0 === ('Xception2')) {
-      var x = new ttypes.Xception2();
-      x.errorCode = 2002;
-      x.struct_thing = new ttypes.Xtruct();
-      x.struct_thing.string_thing = 'This is an Xception2';
-      result(x);
-    }
-
-    var res = new ttypes.Xtruct();
-    res.string_thing = arg1;
-    result(null, res);
-  },
-
-  testOneway: function(sleepFor, result) {
-    console.log('testOneway(' + sleepFor + ') => sleeping...');
-    setTimeout(function(){
-      console.log('Done sleeping for testOneway!');
-    }, sleepFor*1000); //seconds
-  }
-}, { //server options
-  'transport': ttransport.TFramedTransport
-});
-
-server.listen(9090);
diff --git a/test/ocaml/server/TestServer.ml b/test/ocaml/server/TestServer.ml
index 3f5c9ee..efe0f4b 100644
--- a/test/ocaml/server/TestServer.ml
+++ b/test/ocaml/server/TestServer.ml
@@ -36,6 +36,7 @@
   method testI32 x = p "testI32(%d)\n" (sod x); (sod x)
   method testI64 x = p "testI64(%s)\n" (Int64.to_string (sod x)); (sod x)
   method testDouble x = p "testDouble(%f)\n" (sod x); (sod x)
+  method testBinary x = p "testBinary(%s)\n" (sod x); (sod x)
   method testStruct x = p "testStruct(---)\n"; (sod x)
   method testNest x = p "testNest(---)\n"; (sod x)
   method testMap x = p "testMap(---)\n"; (sod x)
diff --git a/test/perl/Makefile.am b/test/perl/Makefile.am
index 291106b..165b9a7 100644
--- a/test/perl/Makefile.am
+++ b/test/perl/Makefile.am
@@ -17,11 +17,11 @@
 # under the License.
 #
 
-THRIFT = $(top_srcdir)/compiler/cpp/thrift
-
 stubs: ../ThriftTest.thrift
 	$(THRIFT) --gen perl ../ThriftTest.thrift
 
+precross: stubs
+
 check: stubs
 
 clean-local:
diff --git a/test/perl/TestClient.pl b/test/perl/TestClient.pl
old mode 100644
new mode 100755
index af80d46..96e3bec
--- a/test/perl/TestClient.pl
+++ b/test/perl/TestClient.pl
@@ -19,10 +19,11 @@
 # under the License.
 #
 
-require 5.6.0;
+use 5.10.0;
 use strict;
 use warnings;
 use Data::Dumper;
+use Getopt::Long qw(GetOptions);
 use Time::HiRes qw(gettimeofday);
 
 use lib '../../lib/perl/lib';
@@ -30,104 +31,227 @@
 
 use Thrift;
 use Thrift::BinaryProtocol;
-use Thrift::Socket;
 use Thrift::BufferedTransport;
+use Thrift::FramedTransport;
+use Thrift::MultiplexedProtocol;
+use Thrift::SSLSocket;
+use Thrift::Socket;
+use Thrift::UnixSocket;
 
+use ThriftTest::SecondService;
 use ThriftTest::ThriftTest;
 use ThriftTest::Types;
 
 $|++;
 
-my $host = 'localhost';
-my $port = 9090;
+sub usage {
+    print <<"EOF";
+Usage: $0 [OPTIONS]
 
+Options:                          (default)
+  --ca                                         CA to validate server with.
+  --cert                                       Certificate to use.
+                                               Required if using --ssl.
+  --ciphers                                    Acceptable cipher list.
+  --domain-socket <file>                       Use a unix domain socket.
+  --help                                       Show usage.
+  --key                                        Certificate key.
+                                               Required if using --ssl.
+  --port <portnum>                9090         Port to use.
+  --protocol {binary}             binary       Protocol to use.
+  --ssl                                        If present, use SSL.
+  --transport {buffered|framed}   buffered     Transport to use.
 
-my $socket = new Thrift::Socket($host, $port);
+EOF
+}
 
-my $bufferedSocket = new Thrift::BufferedTransport($socket, 1024, 1024);
-my $transport = $bufferedSocket;
-my $protocol = new Thrift::BinaryProtocol($transport);
-my $testClient = new ThriftTest::ThriftTestClient($protocol);
+my %opts = (
+    'port' => 9090,
+    'protocol' => 'binary',
+    'transport' => 'buffered'
+);
 
-eval{
-$transport->open();
-}; if($@){
+GetOptions(\%opts, qw (
+    ca=s
+    cert=s
+    ciphers=s
+    key=s
+    domain-socket=s
+    help
+    host=s
+    port=i
+    protocol=s
+    ssl
+    transport=s
+)) || exit 1;
+
+if ($opts{help}) {
+    usage();
+    exit 0;
+}
+
+my $socket = undef;
+if ($opts{'domain-socket'}) {
+    $socket = Thrift::UnixSocket->new($opts{'domain-socket'});
+}
+elsif ($opts{ssl}) {
+  $socket = Thrift::SSLSocket->new(\%opts);
+}
+else {
+  $socket = Thrift::Socket->new($opts{host}, $opts{port});
+}
+
+my $transport;
+if ($opts{transport} eq 'buffered') {
+    $transport = Thrift::BufferedTransport->new($socket, 1024, 1024);
+}
+elsif ($opts{transport} eq 'framed') {
+    $transport = Thrift::FramedTransport->new($socket);
+}
+else {
+    usage();
+    exit 1;
+}
+
+my $protocol;
+my $protocol2;
+if ($opts{protocol} eq 'binary' || $opts{protocol} eq 'multi') {
+    $protocol = Thrift::BinaryProtocol->new($transport);
+}
+else {
+    usage();
+    exit 1;
+}
+
+my $secondService = undef;
+if (index($opts{protocol}, 'multi') == 0) {
+  $protocol2     = Thrift::MultiplexedProtocol->new($protocol, 'SecondService');
+  $protocol      = Thrift::MultiplexedProtocol->new($protocol, 'ThriftTest');
+  $secondService = ThriftTest::SecondServiceClient->new($protocol2);
+}
+
+my $testClient = ThriftTest::ThriftTestClient->new($protocol);
+
+eval {
+  $transport->open();
+};
+if($@){
     die(Dumper($@));
 }
+
+use constant ERR_BASETYPES => 1;
+use constant ERR_STRUCTS => 2;
+use constant ERR_CONTAINERS => 4;
+use constant ERR_EXCEPTIONS => 8;
+use constant ERR_PROTOCOL => 16;
+use constant ERR_UNKNOWN => 64;
+
 my $start = gettimeofday();
 
 #
 # VOID TEST
 #
-print("testVoid()");
+print('testVoid()');
 $testClient->testVoid();
 print(" = void\n");
 
 #
 # STRING TEST
 #
-print("testString(\"Test\")");
-my $s = $testClient->testString("Test");
-print(" = \"$s\"\n");
+print('testString("Test")');
+my $s = $testClient->testString('Test');
+print(qq| = "$s"\n|);
+exit(ERR_BASETYPES) if ($s ne 'Test');
+
+#
+# MULTIPLEXED TEST
+#
+if (index($opts{protocol}, 'multi') == 0) {
+    print('secondtestString("Test2")');
+    $s = $secondService->secondtestString('Test2');
+    print(qq| = "$s"\n|);
+    exit(ERR_PROTOCOL) if ($s ne 'testString("Test2")');
+}
+
+#
+# BOOL TEST
+#
+print('testBool(1)');
+my $t = $testClient->testBool(1);
+print(" = $t\n");
+exit(ERR_BASETYPES) if ($t ne 1);
+print('testBool(0)');
+my $f = $testClient->testBool(0);
+print(" = $f\n");
+exit(ERR_BASETYPES) if ($f ne q||);
+
 
 #
 # BYTE TEST
 #
-print("testByte(1)");
+print('testByte(1)');
 my $u8 = $testClient->testByte(1);
 print(" = $u8\n");
 
 #
 # I32 TEST
 #
-print("testI32(-1)");
+print('testI32(-1)');
 my $i32 = $testClient->testI32(-1);
 print(" = $i32\n");
+exit(ERR_BASETYPES) if ($i32 ne -1);
 
 #
-#I64 TEST
+# I64 TEST
 #
-print("testI64(-34359738368)");
+print('testI64(-34359738368)');
 my $i64 = $testClient->testI64(-34359738368);
 print(" = $i64\n");
+exit(ERR_BASETYPES) if ($i64 ne -34359738368);
 
 #
 # DOUBLE TEST
 #
-print("testDouble(-852.234234234)");
+print('testDouble(-852.234234234)');
 my $dub = $testClient->testDouble(-852.234234234);
 print(" = $dub\n");
+exit(ERR_BASETYPES) if ($dub ne -852.234234234);
+
+#
+# BINARY TEST   ---  TODO
+#
+
 
 #
 # STRUCT TEST
 #
-print("testStruct({\"Zero\", 1, -3, -5})");
-my $out = new ThriftTest::Xtruct();
-$out->string_thing("Zero");
+print('testStruct({"Zero", 1, -3, -5})');
+my $out = ThriftTest::Xtruct->new();
+$out->string_thing('Zero');
 $out->byte_thing(1);
 $out->i32_thing(-3);
 $out->i64_thing(-5);
 my $in = $testClient->testStruct($out);
-print(" = {\"".$in->string_thing."\", ".
-        $in->byte_thing.", ".
-        $in->i32_thing.", ".
+print(' = {"'.$in->string_thing.'", '.
+        $in->byte_thing.', '.
+        $in->i32_thing.', '.
         $in->i64_thing."}\n");
 
 #
 # NESTED STRUCT TEST
 #
-print("testNest({1, {\"Zero\", 1, -3, -5}, 5}");
-my $out2 = new ThriftTest::Xtruct2();
+print('testNest({1, {"Zero", 1, -3, -5}, 5}');
+my $out2 = ThriftTest::Xtruct2->new();
 $out2->byte_thing(1);
 $out2->struct_thing($out);
 $out2->i32_thing(5);
 my $in2 = $testClient->testNest($out2);
 $in = $in2->struct_thing;
-print(" = {".$in2->byte_thing.", {\"".
-      $in->string_thing."\", ".
-      $in->byte_thing.", ".
-      $in->i32_thing.", ".
-      $in->i64_thing."}, ".
+print(' = {'.$in2->byte_thing.', {"'.
+      $in->string_thing.'", '.
+      $in->byte_thing.', '.
+      $in->i32_thing.', '.
+      $in->i64_thing.'}, '.
       $in2->i32_thing."}\n");
 
 #
@@ -137,28 +261,30 @@
 for (my $i = 0; $i < 5; ++$i) {
   $mapout->{$i} = $i-10;
 }
-print("testMap({");
+print('testMap({');
 my $first = 1;
 while( my($key,$val) = each %$mapout) {
     if ($first) {
         $first = 0;
-    } else {
-        print(", ");
+    }
+    else {
+        print(', ');
     }
     print("$key => $val");
 }
-print("})");
+print('})');
 
 
 my $mapin = $testClient->testMap($mapout);
-print(" = {");
+print(' = {');
 
 $first = 1;
 while( my($key,$val) = each %$mapin){
     if ($first) {
         $first = 0;
-    } else {
-        print(", ");
+    }
+    else {
+        print(', ');
     }
     print("$key => $val");
 }
@@ -172,11 +298,11 @@
     push(@$setout, $i);
 }
 
-print("testSet({".join(",",@$setout)."})");
+print('testSet({'.join(',',@$setout).'})');
 
 my $setin = $testClient->testSet($setout);
 
-print(" = {".join(",",@$setout)."}\n");
+print(' = {'.join(',',@$setout)."}\n");
 
 #
 # LIST TEST
@@ -186,105 +312,111 @@
     push(@$listout, $i);
 }
 
-print("testList({".join(",",@$listout)."})");
+print('testList({'.join(',',@$listout).'})');
 
 my $listin = $testClient->testList($listout);
 
-print(" = {".join(",",@$listin)."}\n");
+print(' = {'.join(',',@$listin)."}\n");
 
 #
 # ENUM TEST
 #
-print("testEnum(ONE)");
+print('testEnum(ONE)');
 my $ret = $testClient->testEnum(ThriftTest::Numberz::ONE);
 print(" = $ret\n");
 
-print("testEnum(TWO)");
+print('testEnum(TWO)');
 $ret = $testClient->testEnum(ThriftTest::Numberz::TWO);
 print(" = $ret\n");
 
-print("testEnum(THREE)");
+print('testEnum(THREE)');
 $ret = $testClient->testEnum(ThriftTest::Numberz::THREE);
 print(" = $ret\n");
 
-print("testEnum(FIVE)");
+print('testEnum(FIVE)');
 $ret = $testClient->testEnum(ThriftTest::Numberz::FIVE);
 print(" = $ret\n");
 
-print("testEnum(EIGHT)");
+print('testEnum(EIGHT)');
 $ret = $testClient->testEnum(ThriftTest::Numberz::EIGHT);
 print(" = $ret\n");
 
 #
 # TYPEDEF TEST
 #
-print("testTypedef(309858235082523)");
+print('testTypedef(309858235082523)');
 my $uid = $testClient->testTypedef(309858235082523);
 print(" = $uid\n");
 
 #
 # NESTED MAP TEST
 #
-print("testMapMap(1)");
+print('testMapMap(1)');
 my $mm = $testClient->testMapMap(1);
-print(" = {");
+print(' = {');
 while( my ($key,$val) = each %$mm) {
     print("$key => {");
     while( my($k2,$v2) = each %$val) {
         print("$k2 => $v2, ");
     }
-    print("}, ");
+    print('}, ');
 }
 print("}\n");
 
 #
 # INSANITY TEST
 #
-my $insane = new ThriftTest::Insanity();
+my $insane = ThriftTest::Insanity->new();
 $insane->{userMap}->{ThriftTest::Numberz::FIVE} = 5000;
-my $truck = new ThriftTest::Xtruct();
-$truck->string_thing("Truck");
-$truck->byte_thing(8);
-$truck->i32_thing(8);
-$truck->i64_thing(8);
+my $truck = ThriftTest::Xtruct->new();
+$truck->string_thing('Hello2');
+$truck->byte_thing(2);
+$truck->i32_thing(2);
+$truck->i64_thing(2);
+my $truck2 = ThriftTest::Xtruct->new();
+$truck2->string_thing('Goodbye4');
+$truck2->byte_thing(4);
+$truck2->i32_thing(4);
+$truck2->i64_thing(4);
 push(@{$insane->{xtructs}}, $truck);
+push(@{$insane->{xtructs}}, $truck2);
 
-print("testInsanity()");
+print('testInsanity()');
 my $whoa = $testClient->testInsanity($insane);
-print(" = {");
+print(' = {');
 while( my ($key,$val) = each %$whoa) {
     print("$key => {");
     while( my($k2,$v2) = each %$val) {
         print("$k2 => {");
         my $userMap = $v2->{userMap};
-        print("{");
-        if (ref($userMap) eq "HASH") {
+        print('{');
+        if (ref($userMap) eq 'HASH') {
             while( my($k3,$v3) = each %$userMap) {
                 print("$k3 => $v3, ");
             }
         }
-        print("}, ");
+        print('}, ');
 
         my $xtructs = $v2->{xtructs};
-        print("{");
-        if (ref($xtructs) eq "ARRAY") {
+        print('{');
+        if (ref($xtructs) eq 'ARRAY') {
             foreach my $x (@$xtructs) {
-                print("{\"".$x->{string_thing}."\", ".
-                      $x->{byte_thing}.", ".$x->{i32_thing}.", ".$x->{i64_thing}."}, ");
+                print('{"'.$x->{string_thing}.'", '.
+                      $x->{byte_thing}.', '.$x->{i32_thing}.', '.$x->{i64_thing}.'}, ');
             }
         }
-        print("}");
+        print('}');
 
-        print("}, ");
+        print('}, ');
     }
-    print("}, ");
+    print('}, ');
 }
 print("}\n");
 
 #
 # EXCEPTION TEST
 #
-print("testException('Xception')");
+print(q|testException('Xception')|);
 eval {
     $testClient->testException('Xception');
     print("  void\nFAILURE\n");
@@ -297,7 +429,7 @@
 # Normal tests done.
 #
 my $stop = gettimeofday();
-my $elp  = sprintf("%d",1000*($stop - $start), 0);
+my $elp  = sprintf('%d',1000*($stop - $start), 0);
 print("Total time: $elp ms\n");
 
 #
diff --git a/test/perl/TestServer.pl b/test/perl/TestServer.pl
new file mode 100644
index 0000000..d2b9a38
--- /dev/null
+++ b/test/perl/TestServer.pl
@@ -0,0 +1,411 @@
+#!/usr/bin/env perl
+
+#
+# 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.
+#
+
+use 5.10.0;
+use strict;
+use warnings;
+use Data::Dumper;
+use Getopt::Long qw(GetOptions);
+use Time::HiRes qw(gettimeofday);
+
+$SIG{INT} = \&sigint_handler;
+
+use lib '../../lib/perl/lib';
+use lib 'gen-perl';
+
+use Thrift;
+use Thrift::BinaryProtocol;
+use Thrift::BufferedTransport;
+use Thrift::FramedTransport;
+use Thrift::MultiplexedProcessor;
+use Thrift::SSLServerSocket;
+use Thrift::ServerSocket;
+use Thrift::Server;
+use Thrift::UnixServerSocket;
+
+use ThriftTest::SecondService;
+use ThriftTest::ThriftTest;
+use ThriftTest::Types;
+
+$|++;
+
+sub usage {
+    print <<"EOF";
+Usage: $0 [OPTIONS]
+
+Options:                          (default)
+  --ca                                         Certificate authority file (optional).
+  --cert                                       Certificate file.
+                                               Required if using --ssl.
+  --ciphers                                    Acceptable cipher list.
+  --domain-socket <file>                       Use a unix domain socket.
+  --help                                       Show usage.
+  --key                                        Private key file for certificate.
+                                               Required if using --ssl and private key is
+                                               not in the certificate file.
+  --port <portnum>                9090         Port to use.
+  --protocol {binary}             binary       Protocol to use.
+  --ssl                                        If present, use SSL/TLS.
+  --transport {buffered|framed}   buffered     Transport to use.
+
+EOF
+}
+
+my %opts = (
+    'port' => 9090,
+    'protocol' => 'binary',
+    'transport' => 'buffered'
+);
+
+GetOptions(\%opts, qw (
+    ca=s
+    cert=s
+    ciphers=s
+    domain-socket=s
+    help
+    host=s
+    key=s
+    port=i
+    protocol=s
+    ssl
+    transport=s
+)) || exit 1;
+
+if ($opts{help}) {
+    usage();
+    exit 0;
+}
+
+if ($opts{ssl} and not defined $opts{cert}) {
+    usage();
+    exit 1;
+}
+
+my $handler    = ThriftTestHandler->new();
+my $handler2   = SecondServiceHandler->new();
+my $processor  = ThriftTest::ThriftTestProcessor->new($handler);
+my $processor2 = ThriftTest::SecondServiceProcessor->new($handler2);
+
+my $serversocket;
+if ($opts{'domain-socket'}) {
+    unlink($opts{'domain-socket'});
+    $serversocket = Thrift::UnixServerSocket->new($opts{'domain-socket'});
+}
+elsif ($opts{ssl}) {
+    $serversocket = Thrift::SSLServerSocket->new(\%opts);
+}
+else {
+    $serversocket = Thrift::ServerSocket->new(\%opts);
+}
+my $transport;
+if ($opts{transport} eq 'buffered') {
+    $transport = Thrift::BufferedTransportFactory->new();
+}
+elsif ($opts{transport} eq 'framed') {
+    $transport = Thrift::FramedTransportFactory->new();
+}
+else {
+    usage();
+    exit 1;
+}
+my $protocol;
+if ($opts{protocol} eq 'binary' || $opts{protocol} eq 'multi') {
+    $protocol = Thrift::BinaryProtocolFactory->new();
+}
+else {
+    usage();
+    exit 1;
+}
+
+if (index($opts{protocol}, 'multi') == 0) {
+  my $newProcessor = Thrift::MultiplexedProcessor->new($protocol);
+  $newProcessor->defaultProcessor($processor);
+  $newProcessor->registerProcessor('ThriftTest', $processor);
+  $newProcessor->registerProcessor('SecondService', $processor2);
+  $processor = $newProcessor;
+}
+
+my $ssltag = '';
+if ($opts{ssl}) {
+    $ssltag = '(SSL)';
+}
+my $listening_on = "$opts{port} $ssltag";
+if ($opts{'domain-socket'}) {
+    $listening_on = $opts{'domain-socket'};
+}
+my $server = Thrift::SimpleServer->new($processor, $serversocket, $transport, $protocol);
+print qq|Starting "simple" server ($opts{transport}/$opts{protocol}) listen on: $listening_on\n|;
+$server->serve();
+print "done.\n";
+
+sub sigint_handler {
+  print "received SIGINT, stopping...\n";
+  $server->stop();
+}
+
+###
+### Test server implementation
+###
+
+package ThriftTestHandler;
+
+use base qw( ThriftTest::ThriftTestIf );
+
+sub new {
+    my $classname = shift;
+    my $self = {};
+    return bless($self, $classname);
+}
+
+sub testVoid {
+  print("testVoid()\n");
+}
+
+sub testString {
+  my $self = shift;
+  my $thing = shift;
+  print("testString($thing)\n");
+  return $thing;
+}
+
+sub testBool {
+  my $self = shift;
+  my $thing = shift;
+  my $str = $thing ? 'true' : 'false';
+  print("testBool($str)\n");
+  return $thing;
+}
+
+sub testByte {
+  my $self = shift;
+  my $thing = shift;
+  print("testByte($thing)\n");
+  return $thing;
+}
+
+sub testI32 {
+  my $self = shift;
+  my $thing = shift;
+  print("testI32($thing)\n");
+  return $thing;
+}
+
+sub testI64 {
+  my $self = shift;
+  my $thing = shift;
+  print("testI64($thing)\n");
+  return $thing;
+}
+
+sub testDouble {
+  my $self = shift;
+  my $thing = shift;
+  print("testDouble($thing)\n");
+  return $thing;
+}
+
+sub testBinary {
+    my $self = shift;
+    my $thing = shift;
+    my @bytes = split //, $thing;
+    print 'testBinary(';
+    printf( '%02lx', ord $_ ) foreach (@bytes);
+    print ")\n";
+    return $thing;
+}
+
+sub testStruct {
+  my $self = shift;
+  my $thing = shift;
+  printf(qq|testStruct({"%s", %d, %d, %lld})\n|,
+           $thing->{string_thing},
+           $thing->{byte_thing},
+           $thing->{i32_thing},
+           $thing->{i64_thing});
+  return $thing;
+}
+
+sub testNest {
+  my $self = shift;
+  my $nest = shift;
+  my $thing = $nest->{struct_thing};
+  printf(qq|testNest({%d, {"%s", %d, %d, %lld}, %d})\n|,
+           $nest->{byte_thing},
+           $thing->{string_thing},
+           $thing->{byte_thing},
+           $thing->{i32_thing},
+           $thing->{i64_thing},
+           $nest->{i32_thing});
+  return $nest;
+}
+
+sub testMap {
+  my $self = shift;
+  my $thing = shift;
+  printf "testMap({%s})\n",
+    join( ', ',
+          map { $_ . ' => ' . $thing->{$_} }
+          sort keys %$thing
+    );
+  return $thing;
+}
+
+sub testStringMap {
+  my $self = shift;
+  my $thing = shift;
+  printf "testStringMap({%s})\n",
+    join( ', ',
+          map { $_ . ' => ' . $thing->{$_} }
+          sort keys %$thing
+    );
+  return $thing;
+}
+
+sub testSet {
+  my $self = shift;
+  my $thing = shift;
+  my @result = sort keys %$thing;
+  printf "testSet({%s})\n", join(', ', @result );
+  return \@result;
+}
+
+sub testList {
+  my $self = shift;
+  my $thing = shift;
+  print "testList({%s})\n", join(', ', @$thing);
+  return $thing;
+}
+
+sub testEnum {
+  my $self = shift;
+  my $thing = shift;
+  print "testEnum($thing)\n";
+  return $thing;
+}
+
+sub testTypedef {
+  my $self = shift;
+  my $thing = shift;
+  print("testTypedef($thing)\n");
+  return $thing;
+}
+
+sub testMapMap {
+  my $self = shift;
+  my $hello = shift;
+
+  printf("testMapMap(%d)\n", $hello);
+  my $result = { 4 => { 1 => 1, 2 => 2, 3 => 3, 4 => 4 }, -4 => { -1 => -1, -2 => -2, -3 => -3, -4 => -4 } };
+  return $result;
+}
+
+sub testInsanity {
+  my $self = shift;
+  my $argument = shift;
+  print("testInsanity()\n");
+
+  my $hello = ThriftTest::Xtruct->new({string_thing => 'Hello2', byte_thing => 2, i32_thing => 2, i64_thing => 2});
+  my @hellos;
+  push(@hellos, $hello);
+  my $goodbye = ThriftTest::Xtruct->new({string_thing => 'Goodbye4', byte_thing => 4, i32_thing => 4, i64_thing => 4});
+  my @goodbyes;
+  push(@goodbyes, $goodbye);
+  my $crazy = ThriftTest::Insanity->new({userMap => { ThriftTest::Numberz::EIGHT => 8 }, xtructs => \@goodbyes});
+  my $loony = ThriftTest::Insanity->new();
+  my $result = { 1 => { ThriftTest::Numberz::TWO => $argument, ThriftTest::Numberz::THREE => $argument },
+                 2 => { ThriftTest::Numberz::SIX => $loony } };
+  return $result;
+}
+
+sub testMulti {
+  my $self = shift;
+  my $arg0 = shift;
+  my $arg1 = shift;
+  my $arg2 = shift;
+  my $arg3 = shift;
+  my $arg4 = shift;
+  my $arg5 = shift;
+
+  print("testMulti()\n");
+  return ThriftTest::Xtruct->new({string_thing => 'Hello2', byte_thing => $arg0, i32_thing => $arg1, i64_thing => $arg2});
+}
+
+sub testException {
+  my $self = shift;
+  my $arg = shift;
+  print("testException($arg)\n");
+  if ($arg eq 'Xception') {
+      die ThriftTest::Xception->new({errorCode => 1001, message => $arg});
+  }
+  elsif ($arg eq 'TException') {
+      die 'astring'; # all unhandled exceptions become TExceptions
+  }
+  else {
+      return ThriftTest::Xtruct->new({string_thing => $arg});
+  }
+}
+
+sub testMultiException {
+  my $self = shift;
+  my $arg0 = shift;
+  my $arg1 = shift;
+
+  printf("testMultiException(%s, %s)\n", $arg0, $arg1);
+  if ($arg0 eq 'Xception') {
+    die ThriftTest::Xception->new({errorCode => 1001, message => 'This is an Xception'});
+  }
+  elsif ($arg0 eq 'Xception2') {
+    my $struct_thing = ThriftTest::Xtruct->new({string_thing => 'This is an Xception2'});
+    die ThriftTest::Xception2->new({errorCode => 2002, struct_thing => $struct_thing});
+  }
+  else {
+    return ThriftTest::Xtruct->new({string_thing => $arg1});
+  }
+}
+
+sub testOneway {
+  my $self = shift;
+  my $num = shift;
+  print("testOneway($num): received\n");
+}
+
+###
+### Test server implementation
+###
+
+package SecondServiceHandler;
+
+use base qw( ThriftTest::SecondServiceIf );
+
+sub new {
+    my $classname = shift;
+    my $self = {};
+    return bless($self, $classname);
+}
+
+sub secondtestString {
+  my $self = shift;
+  my $thing = shift;
+  print("testString($thing)\n");
+  return qq|testString("$thing")|;
+}
+
+1;
diff --git a/test/php/Makefile.am b/test/php/Makefile.am
index 1625903..72f7fc5 100755
--- a/test/php/Makefile.am
+++ b/test/php/Makefile.am
@@ -17,16 +17,23 @@
 # under the License.
 #
 
-THRIFT = $(top_srcdir)/compiler/cpp/thrift
-
 stubs: ../ThriftTest.thrift
 	$(THRIFT) --gen php ../ThriftTest.thrift
 	$(THRIFT) --gen php:inlined ../ThriftTest.thrift
+	$(MKDIR_P) gen-php-classmap
+	$(THRIFT) -out gen-php-classmap --gen php ../ThriftTest.thrift
 
-check: stubs
+php_ext_dir:
+	mkdir -p php_ext_dir
+	ln -s ../../../lib/php/src/ext/thrift_protocol/modules/thrift_protocol.so php_ext_dir/
+	ln -s "$$(php-config --extension-dir)/sockets.so" php_ext_dir/
+
+precross: stubs php_ext_dir
+
+check: stubs php_ext_dir
 
 clean-local:
-	$(RM) -r gen-php gen-phpi
+	$(RM) -r gen-php gen-phpi gen-php-classmap php_ext_dir
 
-client: stubs
+client: stubs php_ext_dir
 	php TestClient.php
diff --git a/test/php/TestClassmap.php b/test/php/TestClassmap.php
new file mode 100644
index 0000000..6fd1594
--- /dev/null
+++ b/test/php/TestClassmap.php
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+<?php
+$GEN_DIR = 'gen-php-classmap';
+include_once('TestClient.php');
+?>
diff --git a/test/php/TestClient.php b/test/php/TestClient.php
index c334aee..acd901d 100755
--- a/test/php/TestClient.php
+++ b/test/php/TestClient.php
@@ -2,7 +2,8 @@
 
 namespace test\php;
 
-require_once __DIR__.'/../../lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php';
+/** @var \Composer\Autoload\ClassLoader $loader */
+$loader = require __DIR__ . '/../../vendor/autoload.php';
 
 use Thrift\ClassLoader\ThriftClassLoader;
 
@@ -13,10 +14,14 @@
   $MODE = 'normal';
 }
 
-$loader = new ThriftClassLoader();
-$loader->registerNamespace('Thrift', __DIR__ . '/../../lib/php/lib');
-$loader->registerDefinition('ThriftTest', $GEN_DIR);
-$loader->register();
+
+if ($GEN_DIR == 'gen-php') {
+  $loader->addPsr4('', $GEN_DIR);
+} else {
+  $loader = new ThriftClassLoader();
+  $loader->registerDefinition('ThriftTest', $GEN_DIR);
+  $loader->register();
+}
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -38,8 +43,11 @@
  */
 
 /** Include the Thrift base */
-/** Include the binary protocol */
+/** Include the protocols */
 use Thrift\Protocol\TBinaryProtocol;
+use Thrift\Protocol\TBinaryProtocolAccelerated;
+use Thrift\Protocol\TCompactProtocol;
+use Thrift\Protocol\TJSONProtocol;
 
 /** Include the socket layer */
 use Thrift\Transport\TSocket;
@@ -49,6 +57,26 @@
 use Thrift\Transport\TFramedTransport;
 use Thrift\Transport\TBufferedTransport;
 
+function makeProtocol($transport, $PROTO)
+{
+  if ($PROTO == 'binary') {
+    return new TBinaryProtocol($transport);
+  } else if ($PROTO == 'compact') {
+    return new TCompactProtocol($transport);
+  } else if ($PROTO == 'json') {
+    return new TJSONProtocol($transport);
+  } else if ($PROTO == 'accel') {
+    if (!function_exists('thrift_protocol_write_binary')) {
+      echo "Acceleration extension is not loaded\n";
+      exit(1);
+    }
+    return new TBinaryProtocolAccelerated($transport);
+  }
+
+  echo "--protocol must be one of {binary|compact|json|accel}\n";
+  exit(1);
+}
+
 $host = 'localhost';
 $port = 9090;
 
@@ -60,6 +88,16 @@
   $host = $argv[1];
 }
 
+foreach ($argv as $arg) {
+  if (substr($arg, 0, 7) == '--port=') {
+    $port = substr($arg, 7);
+  } else if (substr($arg, 0, 12) == '--transport=') {
+    $MODE = substr($arg, 12);
+  } else if (substr($arg, 0, 11) == '--protocol=') {
+    $PROTO = substr($arg, 11);
+  }
+}
+
 $hosts = array('localhost');
 
 $socket = new TSocket($host, $port);
@@ -72,12 +110,12 @@
 } else if ($MODE == 'framed') {
   $framedSocket = new TFramedTransport($socket);
   $transport = $framedSocket;
-  $protocol = new TBinaryProtocol($transport);
+  $protocol = makeProtocol($transport, $PROTO);
   $testClient = new \ThriftTest\ThriftTestClient($protocol);
 } else {
   $bufferedSocket = new TBufferedTransport($socket, 1024, 1024);
   $transport = $bufferedSocket;
-  $protocol = new TBinaryProtocol($transport);
+  $protocol = makeProtocol($transport, $PROTO);
   $testClient = new \ThriftTest\ThriftTestClient($protocol);
 }
 
@@ -85,6 +123,12 @@
 
 $start = microtime(true);
 
+define('ERR_BASETYPES', 1);
+define('ERR_STRUCTS', 2);
+define('ERR_CONTAINERS', 4);
+define('ERR_EXCEPTIONS', 8);
+define('ERR_UNKNOWN', 64);
+$exitcode = 0;
 /**
  * VOID TEST
  */
@@ -92,40 +136,57 @@
 $testClient->testVoid();
 print_r(" = void\n");
 
+function roundtrip($testClient, $method, $value) {
+  global $exitcode;
+  print_r("$method($value)");
+  $ret = $testClient->$method($value);
+  print_r(" = \"$ret\"\n");
+  if ($value !== $ret) {
+    print_r("*** FAILED ***\n");
+    $exitcode |= ERR_BASETYPES;
+  }
+}
+
 /**
  * STRING TEST
  */
-print_r("testString(\"Test\")");
-$s = $testClient->testString("Test");
-print_r(" = \"$s\"\n");
+roundtrip($testClient, 'testString', "Test");
+
+/**
+ * BOOL TEST
+ */
+roundtrip($testClient, 'testBool', true);
+roundtrip($testClient, 'testBool', false);
 
 /**
  * BYTE TEST
  */
-print_r("testByte(1)");
-$u8 = $testClient->testByte(1);
-print_r(" = $u8\n");
+roundtrip($testClient, 'testByte', 1);
+roundtrip($testClient, 'testByte', -1);
+roundtrip($testClient, 'testByte', 127);
+roundtrip($testClient, 'testByte', -128);
 
 /**
  * I32 TEST
  */
-print_r("testI32(-1)");
-$i32 = $testClient->testI32(-1);
-print_r(" = $i32\n");
+roundtrip($testClient, 'testI32', -1);
 
 /**
  * I64 TEST
  */
-print_r("testI64(-34359738368)");
-$i64 = $testClient->testI64(-34359738368);
-print_r(" = $i64\n");
+roundtrip($testClient, 'testI64', 0);
+roundtrip($testClient, 'testI64', 1);
+roundtrip($testClient, 'testI64', -1);
+roundtrip($testClient, 'testI64', -34359738368);
 
 /**
  * DOUBLE TEST
  */
-print_r("testDouble(-852.234234234)");
-$dub = $testClient->testDouble(-852.234234234);
-print_r(" = $dub\n");
+roundtrip($testClient, 'testDouble', -852.234234234);
+
+/**
+ * BINARY TEST  --  TODO
+ */
 
 /**
  * STRUCT TEST
@@ -142,6 +203,11 @@
         $in->i32_thing.", ".
         $in->i64_thing."}\n");
 
+if ($in != $out) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
+
 /**
  * NESTED STRUCT TEST
  */
@@ -159,6 +225,11 @@
         $in->i64_thing."}, ".
         $in2->i32_thing."}\n");
 
+if ($in2 != $out2) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
+
 /**
  * MAP TEST
  */
@@ -191,36 +262,69 @@
 }
 print_r("}\n");
 
+if ($mapin != $mapout) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_CONTAINERS;
+}
+
+$mapout = array();
+for ($i = 0; $i < 10; $i++) {
+    $mapout["key$i"] = "val$i";
+}
+print_r('testStringMap({');
+$first = true;
+foreach ($mapout as $key => $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r("\"$key\" => \"$val\"");
+}
+print_r("})");
+$mapin = $testClient->testStringMap($mapout);
+print_r(" = {");
+$first = true;
+foreach ($mapin as $key => $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r("\"$key\" => \"$val\"");
+}
+print_r("}\n");
+ksort($mapin);
+if ($mapin != $mapout) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_CONTAINERS;
+}
+
 /**
  * SET TEST
  */
 $setout = array();;
 for ($i = -2; $i < 3; ++$i) {
-  $setout []= $i;
+  $setout[$i]= true;
 }
 print_r("testSet({");
-$first = true;
-foreach ($setout as $val) {
-  if ($first) {
-    $first = false;
-  } else {
-    print_r(", ");
-  }
-  print_r($val);
-}
+echo implode(',', array_keys($setout));
 print_r("})");
 $setin = $testClient->testSet($setout);
 print_r(" = {");
-$first = true;
-foreach ($setin as $val) {
-  if ($first) {
-    $first = false;
-  } else {
-    print_r(", ");
-  }
-  print_r($val);
-}
+echo implode(', ', array_keys($setin));
 print_r("}\n");
+// Order of keys in set does not matter
+ksort($setin);
+if ($setout !== $setin) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_CONTAINERS;
+}
+// Regression test for corrupted array
+if ($setin[2] !== $setout[2] || is_int($setin[2])) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_CONTAINERS;
+}
 
 /**
  * LIST TEST
@@ -252,6 +356,10 @@
   print_r($val);
 }
 print_r("}\n");
+if ($listin !== $listout) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_CONTAINERS;
+}
 
 /**
  * ENUM TEST
@@ -259,22 +367,42 @@
 print_r("testEnum(ONE)");
 $ret = $testClient->testEnum(\ThriftTest\Numberz::ONE);
 print_r(" = $ret\n");
+if ($ret != \ThriftTest\Numberz::ONE) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
 
 print_r("testEnum(TWO)");
 $ret = $testClient->testEnum(\ThriftTest\Numberz::TWO);
 print_r(" = $ret\n");
+if ($ret != \ThriftTest\Numberz::TWO) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
 
 print_r("testEnum(THREE)");
 $ret = $testClient->testEnum(\ThriftTest\Numberz::THREE);
 print_r(" = $ret\n");
+if ($ret != \ThriftTest\Numberz::THREE) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
 
 print_r("testEnum(FIVE)");
 $ret = $testClient->testEnum(\ThriftTest\Numberz::FIVE);
 print_r(" = $ret\n");
+if ($ret != \ThriftTest\Numberz::FIVE) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
 
 print_r("testEnum(EIGHT)");
 $ret = $testClient->testEnum(\ThriftTest\Numberz::EIGHT);
 print_r(" = $ret\n");
+if ($ret != \ThriftTest\Numberz::EIGHT) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
 
 /**
  * TYPEDEF TEST
@@ -282,6 +410,10 @@
 print_r("testTypedef(309858235082523)");
 $uid = $testClient->testTypedef(309858235082523);
 print_r(" = $uid\n");
+if ($uid !== 309858235082523) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_STRUCTS;
+}
 
 /**
  * NESTED MAP TEST
@@ -297,6 +429,14 @@
   print_r("}, ");
 }
 print_r("}\n");
+$expected_mm = [
+  -4 => [-4 => -4, -3 => -3, -2 => -2, -1 => -1],
+  4 => [4 => 4, 3 => 3, 2 => 2, 1 => 1],
+];
+if ($mm != $expected_mm) {
+    echo "**FAILED**\n";
+    $exitcode |= ERR_CONTAINERS;
+}
 
 /**
  * INSANITY TEST
@@ -348,10 +488,29 @@
 try {
   $testClient->testException('Xception');
   print_r("  void\nFAILURE\n");
+  $exitcode |= ERR_EXCEPTIONS;
 } catch (\ThriftTest\Xception $x) {
   print_r(' caught xception '.$x->errorCode.': '.$x->message."\n");
 }
 
+// Regression test for THRIFT-4263
+print_r("testBinarySerializer_Deserialize('foo')");
+try {
+  \Thrift\Serializer\TBinarySerializer::deserialize(base64_decode('foo'), \ThriftTest\Xtruct2::class);
+  echo "**FAILED**\n";
+  $exitcode |= ERR_STRUCTS;
+} catch (\Thrift\Exception\TTransportException $happy_exception) {
+  // We expected this due to binary data of base64_decode('foo') is less then 4
+  // bytes and it tries to find thrift version number in the transport by
+  // reading i32() at the beginning.  Casting to string validates that
+  // exception is still accessible in memory and not corrupted.  Without patch,
+  // PHP will error log that the exception doesn't have any tostring method,
+  // which is a lie due to corrupted memory.
+  for($i=99; $i > 0; $i--) {
+    (string)$happy_exception;
+  }
+  print_r("  SUCCESS\n");
+}
 
 /**
  * Normal tests done.
@@ -365,34 +524,34 @@
  * Extraneous "I don't trust PHP to pack/unpack integer" tests
  */
 
+if ($protocol instanceof TBinaryProtocolAccelerated) {
+    // Regression check: check that method name is not double-freed
+    // Method name should not be an interned string.
+    $method_name = "Void";
+    $method_name = "test$method_name";
+
+    $seqid = 0;
+    $args = new \ThriftTest\ThriftTest_testVoid_args();
+    thrift_protocol_write_binary($protocol, $method_name, \Thrift\Type\TMessageType::CALL, $args, $seqid, $protocol->isStrictWrite());
+    $testClient->recv_testVoid();
+
+}
+
 // Max I32
 $num = pow(2, 30) + (pow(2, 30) - 1);
-$num2 = $testClient->testI32($num);
-if ($num != $num2) {
-  print "Missed $num = $num2\n";
-}
+roundtrip($testClient, 'testI32', $num);
 
 // Min I32
 $num = 0 - pow(2, 31);
-$num2 = $testClient->testI32($num);
-if ($num != $num2) {
-  print "Missed $num = $num2\n";
-}
+roundtrip($testClient, 'testI32', $num);
 
 // Max I64
 $num = pow(2, 62) + (pow(2, 62) - 1);
-$num2 = $testClient->testI64($num);
-if ($num != $num2) {
-  print "Missed $num = $num2\n";
-}
+roundtrip($testClient, 'testI64', $num);
 
 // Min I64
-$num = 0 - pow(2, 63);
-$num2 = $testClient->testI64($num);
-if ($num != $num2) {
-  print "Missed $num = $num2\n";
-}
+$num = 0 - pow(2, 62) - pow(2, 62);
+roundtrip($testClient, 'testI64', $num);
 
 $transport->close();
-return;
-
+exit($exitcode);
diff --git a/test/php/test_php.ini b/test/php/test_php.ini
new file mode 100644
index 0000000..3f9bb21
--- /dev/null
+++ b/test/php/test_php.ini
@@ -0,0 +1,2 @@
+extension=thrift_protocol.so
+extension=sockets.so
diff --git a/test/py.tornado/setup.cfg b/test/py.tornado/setup.cfg
new file mode 100644
index 0000000..ae587c4
--- /dev/null
+++ b/test/py.tornado/setup.cfg
@@ -0,0 +1,3 @@
+[flake8]
+ignore = E402
+max-line-length = 100
diff --git a/test/py.tornado/test_suite.py b/test/py.tornado/test_suite.py
index f04ba04..447fde6 100755
--- a/test/py.tornado/test_suite.py
+++ b/test/py.tornado/test_suite.py
@@ -21,191 +21,207 @@
 
 import datetime
 import glob
+import os
 import sys
 import time
 import unittest
 
-sys.path.insert(0, './gen-py.tornado')
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+basepath = os.path.abspath(os.path.dirname(__file__))
+sys.path.insert(0, basepath + '/gen-py.tornado')
+sys.path.insert(0, glob.glob(os.path.join(basepath, '../../lib/py/build/lib*'))[0])
 
 try:
     __import__('tornado')
 except ImportError:
-    print "module `tornado` not found, skipping test"
+    print("module `tornado` not found, skipping test")
     sys.exit(0)
 
-from tornado import gen, ioloop, stack_context
-from tornado.testing import AsyncTestCase, get_unused_port
+from tornado import gen
+from tornado.testing import AsyncTestCase, get_unused_port, gen_test
 
 from thrift import TTornado
+from thrift.Thrift import TApplicationException
 from thrift.protocol import TBinaryProtocol
 
 from ThriftTest import ThriftTest
-from ThriftTest.ttypes import *
+from ThriftTest.ttypes import Xception, Xtruct
 
 
 class TestHandler(object):
     def __init__(self, test_instance):
         self.test_instance = test_instance
 
-    def testVoid(self, callback):
-        callback()
+    def testVoid(self):
+        pass
 
-    def testString(self, s, callback):
-        callback(s)
+    def testString(self, s):
+        if s == 'unexpected_error':
+            raise Exception(s)
+        return s
 
-    def testByte(self, b, callback):
-        callback(b)
+    def testByte(self, b):
+        return b
 
-    def testI16(self, i16, callback):
-        callback(i16)
+    def testI16(self, i16):
+        return i16
 
-    def testI32(self, i32, callback):
-        callback(i32)
+    def testI32(self, i32):
+        return i32
 
-    def testI64(self, i64, callback):
-        callback(i64)
+    def testI64(self, i64):
+        return i64
 
-    def testDouble(self, dub, callback):
-        callback(dub)
+    def testDouble(self, dub):
+        return dub
 
-    def testStruct(self, thing, callback):
-        callback(thing)
+    def testBinary(self, thing):
+        return thing
 
-    def testException(self, s, callback):
+    def testStruct(self, thing):
+        return thing
+
+    def testException(self, s):
         if s == 'Xception':
             x = Xception()
             x.errorCode = 1001
             x.message = s
             raise x
         elif s == 'throw_undeclared':
-            raise ValueError("foo")
-        callback()
+            raise ValueError('testing undeclared exception')
 
-    def testOneway(self, seconds, callback=None):
+    def testOneway(self, seconds):
         start = time.time()
+
         def fire_oneway():
             end = time.time()
             self.test_instance.stop((start, end, seconds))
 
-        ioloop.IOLoop.instance().add_timeout(
+        self.test_instance.io_loop.add_timeout(
             datetime.timedelta(seconds=seconds),
             fire_oneway)
+        raise Exception('testing exception in oneway method')
 
-        if callback:
-            callback()
+    def testNest(self, thing):
+        return thing
 
-    def testNest(self, thing, callback):
-        callback(thing)
+    @gen.coroutine
+    def testMap(self, thing):
+        yield gen.moment
+        raise gen.Return(thing)
 
-    def testMap(self, thing, callback):
-        callback(thing)
+    def testSet(self, thing):
+        return thing
 
-    def testSet(self, thing, callback):
-        callback(thing)
+    def testList(self, thing):
+        return thing
 
-    def testList(self, thing, callback):
-        callback(thing)
+    def testEnum(self, thing):
+        return thing
 
-    def testEnum(self, thing, callback):
-        callback(thing)
-
-    def testTypedef(self, thing, callback):
-        callback(thing)
+    def testTypedef(self, thing):
+        return thing
 
 
 class ThriftTestCase(AsyncTestCase):
-    def get_new_ioloop(self):
-        return ioloop.IOLoop.instance()
-
     def setUp(self):
+        super(ThriftTestCase, self).setUp()
+
         self.port = get_unused_port()
-        self.io_loop = self.get_new_ioloop()
 
         # server
         self.handler = TestHandler(self)
         self.processor = ThriftTest.Processor(self.handler)
         self.pfactory = TBinaryProtocol.TBinaryProtocolFactory()
 
-        self.server = TTornado.TTornadoServer(self.processor, self.pfactory)
+        self.server = TTornado.TTornadoServer(self.processor, self.pfactory, io_loop=self.io_loop)
         self.server.bind(self.port)
         self.server.start(1)
 
         # client
-        transport = TTornado.TTornadoStreamTransport('localhost', self.port)
+        transport = TTornado.TTornadoStreamTransport('localhost', self.port, io_loop=self.io_loop)
         pfactory = TBinaryProtocol.TBinaryProtocolFactory()
+        self.io_loop.run_sync(transport.open)
         self.client = ThriftTest.Client(transport, pfactory)
-        transport.open(callback=self.stop)
-        self.wait(timeout=1)
 
+    @gen_test
     def test_void(self):
-        self.client.testVoid(callback=self.stop)
-        v = self.wait(timeout=1)
-        self.assertEquals(v, None)
+        v = yield self.client.testVoid()
+        self.assertEqual(v, None)
 
+    @gen_test
     def test_string(self):
-        self.client.testString('Python', callback=self.stop)
-        v = self.wait(timeout=1)
-        self.assertEquals(v, 'Python')
+        v = yield self.client.testString('Python')
+        self.assertEqual(v, 'Python')
 
+    @gen_test
     def test_byte(self):
-        self.client.testByte(63, callback=self.stop)
-        v = self.wait(timeout=1)
-        self.assertEquals(v, 63)
+        v = yield self.client.testByte(63)
+        self.assertEqual(v, 63)
 
+    @gen_test
     def test_i32(self):
-        self.client.testI32(-1, callback=self.stop)
-        v = self.wait(timeout=1)
-        self.assertEquals(v, -1)
+        v = yield self.client.testI32(-1)
+        self.assertEqual(v, -1)
 
-        self.client.testI32(0, callback=self.stop)
-        v = self.wait(timeout=1)
-        self.assertEquals(v, 0)
+        v = yield self.client.testI32(0)
+        self.assertEqual(v, 0)
 
+    @gen_test
     def test_i64(self):
-        self.client.testI64(-34359738368, callback=self.stop)
-        v = self.wait(timeout=1)
-        self.assertEquals(v, -34359738368)
+        v = yield self.client.testI64(-34359738368)
+        self.assertEqual(v, -34359738368)
 
+    @gen_test
     def test_double(self):
-        self.client.testDouble(-5.235098235, callback=self.stop)
-        v = self.wait(timeout=1)
-        self.assertEquals(v, -5.235098235)
+        v = yield self.client.testDouble(-5.235098235)
+        self.assertEqual(v, -5.235098235)
 
+    @gen_test
     def test_struct(self):
         x = Xtruct()
         x.string_thing = "Zero"
         x.byte_thing = 1
         x.i32_thing = -3
         x.i64_thing = -5
-        self.client.testStruct(x, callback=self.stop)
+        y = yield self.client.testStruct(x)
 
-        y = self.wait(timeout=1)
-        self.assertEquals(y.string_thing, "Zero")
-        self.assertEquals(y.byte_thing, 1)
-        self.assertEquals(y.i32_thing, -3)
-        self.assertEquals(y.i64_thing, -5)
+        self.assertEqual(y.string_thing, "Zero")
+        self.assertEqual(y.byte_thing, 1)
+        self.assertEqual(y.i32_thing, -3)
+        self.assertEqual(y.i64_thing, -5)
 
+    @gen_test
+    def test_oneway(self):
+        self.client.testOneway(1)
+        v = yield self.client.testI32(-1)
+        self.assertEqual(v, -1)
+
+    @gen_test
+    def test_map(self):
+        """
+        TestHandler.testMap is a coroutine, this test checks if gen.Return() from a coroutine works.
+        """
+        expected = {1: 1}
+        res = yield self.client.testMap(expected)
+        self.assertEqual(res, expected)
+
+    @gen_test
     def test_exception(self):
-        self.client.testException('Safe', callback=self.stop)
-        v = self.wait(timeout=1)
-
-        self.client.testException('Xception', callback=self.stop)
-        ex = self.wait(timeout=1)
-        if type(ex) == Xception:
-            self.assertEquals(ex.errorCode, 1001)
-            self.assertEquals(ex.message, 'Xception')
+        try:
+            yield self.client.testException('Xception')
+        except Xception as ex:
+            self.assertEqual(ex.errorCode, 1001)
+            self.assertEqual(ex.message, 'Xception')
+        else:
+            self.fail("should have gotten exception")
+        try:
+            yield self.client.testException('throw_undeclared')
+        except TApplicationException:
+            pass
         else:
             self.fail("should have gotten exception")
 
-    def test_oneway(self):
-        def return_from_send():
-            self.stop('done with send')
-        self.client.testOneway(0.5, callback=return_from_send)
-        self.assertEquals(self.wait(timeout=1), 'done with send')
-
-        start, end, seconds = self.wait(timeout=1)
-        self.assertAlmostEquals(seconds, (end - start), places=3)
+        yield self.client.testException('Safe')
 
 
 def suite():
diff --git a/test/py.twisted/Makefile.am b/test/py.twisted/Makefile.am
index 4723b7d..d11908c 100644
--- a/test/py.twisted/Makefile.am
+++ b/test/py.twisted/Makefile.am
@@ -17,14 +17,14 @@
 # under the License.
 #
 
-THRIFT = $(top_srcdir)/compiler/cpp/thrift
+TRIAL ?= trial
 
 stubs: ../ThriftTest.thrift ../SmallTest.thrift
 	$(THRIFT) --gen py:twisted ../ThriftTest.thrift
 	$(THRIFT) --gen py:twisted ../SmallTest.thrift
 
 check: stubs
-	$(TRIAL) test_suite.py
+	$(TRIAL) ./test_suite.py
 
 clean-local:
 	$(RM) -r gen-py.twisted
diff --git a/test/py.twisted/setup.cfg b/test/py.twisted/setup.cfg
new file mode 100644
index 0000000..ae587c4
--- /dev/null
+++ b/test/py.twisted/setup.cfg
@@ -0,0 +1,3 @@
+[flake8]
+ignore = E402
+max-line-length = 100
diff --git a/test/py.twisted/test_suite.py b/test/py.twisted/test_suite.py
old mode 100644
new mode 100755
index 0289de5..02eb7f1
--- a/test/py.twisted/test_suite.py
+++ b/test/py.twisted/test_suite.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python
+
 #
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements. See the NOTICE file
@@ -17,12 +19,19 @@
 # under the License.
 #
 
-import sys, glob, time
-sys.path.insert(0, './gen-py.twisted')
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+import glob
+import os
+import sys
+import time
+
+basepath = os.path.abspath(os.path.dirname(__file__))
+sys.path.insert(0, os.path.join(basepath, 'gen-py.twisted'))
+sys.path.insert(0, glob.glob(os.path.join(basepath, '../../lib/py/build/lib.*'))[0])
+
+from thrift.Thrift import TApplicationException
 
 from ThriftTest import ThriftTest
-from ThriftTest.ttypes import *
+from ThriftTest.ttypes import Xception, Xtruct
 from thrift.transport import TTwisted
 from thrift.protocol import TBinaryProtocol
 
@@ -30,40 +39,41 @@
 from twisted.internet import defer, reactor
 from twisted.internet.protocol import ClientCreator
 
-from zope.interface import implements
+from zope.interface import implementer
 
-import random
 
+@implementer(ThriftTest.Iface)
 class TestHandler:
-    implements(ThriftTest.Iface)
-
     def __init__(self):
         self.onewaysQueue = defer.DeferredQueue()
 
     def testVoid(self):
         pass
- 
+
     def testString(self, s):
         return s
- 
+
     def testByte(self, b):
         return b
- 
+
     def testI16(self, i16):
         return i16
- 
+
     def testI32(self, i32):
         return i32
- 
+
     def testI64(self, i64):
         return i64
- 
+
     def testDouble(self, dub):
         return dub
- 
+
+    def testBinary(self, thing):
+        return thing
+
     def testStruct(self, thing):
         return thing
- 
+
     def testException(self, s):
         if s == 'Xception':
             x = Xception()
@@ -72,31 +82,32 @@
             raise x
         elif s == "throw_undeclared":
             raise ValueError("foo")
- 
+
     def testOneway(self, seconds):
         def fireOneway(t):
             self.onewaysQueue.put((t, time.time(), seconds))
         reactor.callLater(seconds, fireOneway, time.time())
-        return d
- 
+        raise Exception('')
+
     def testNest(self, thing):
         return thing
- 
+
     def testMap(self, thing):
         return thing
- 
+
     def testSet(self, thing):
         return thing
- 
+
     def testList(self, thing):
         return thing
- 
+
     def testEnum(self, thing):
         return thing
- 
+
     def testTypedef(self, thing):
         return thing
 
+
 class ThriftTestCase(unittest.TestCase):
 
     @defer.inlineCallbacks
@@ -105,16 +116,15 @@
         self.processor = ThriftTest.Processor(self.handler)
         self.pfactory = TBinaryProtocol.TBinaryProtocolFactory()
 
-        self.server = reactor.listenTCP(0,
-            TTwisted.ThriftServerFactory(self.processor,
-            self.pfactory), interface="127.0.0.1")
+        self.server = reactor.listenTCP(
+            0, TTwisted.ThriftServerFactory(self.processor, self.pfactory), interface="127.0.0.1")
 
         self.portNo = self.server.getHost().port
 
         self.txclient = yield ClientCreator(reactor,
-            TTwisted.ThriftClientProtocol,
-            ThriftTest.Client,
-            self.pfactory).connectTCP("127.0.0.1", self.portNo)
+                                            TTwisted.ThriftClientProtocol,
+                                            ThriftTest.Client,
+                                            self.pfactory).connectTCP("127.0.0.1", self.portNo)
         self.client = self.txclient.client
 
     @defer.inlineCallbacks
@@ -129,7 +139,7 @@
     @defer.inlineCallbacks
     def testString(self):
         self.assertEquals((yield self.client.testString('Python')), 'Python')
- 
+
     @defer.inlineCallbacks
     def testByte(self):
         self.assertEquals((yield self.client.testByte(63)), 63)
@@ -147,7 +157,9 @@
     def testDouble(self):
         self.assertEquals((yield self.client.testDouble(-5.235098235)), -5.235098235)
 
-    @defer.inlineCallbacks 
+    # TODO: def testBinary(self) ...
+
+    @defer.inlineCallbacks
     def testStruct(self):
         x = Xtruct()
         x.string_thing = "Zero"
@@ -155,30 +167,32 @@
         x.i32_thing = -3
         x.i64_thing = -5
         y = yield self.client.testStruct(x)
- 
+
         self.assertEquals(y.string_thing, "Zero")
         self.assertEquals(y.byte_thing, 1)
         self.assertEquals(y.i32_thing, -3)
         self.assertEquals(y.i64_thing, -5)
- 
+
     @defer.inlineCallbacks
     def testException(self):
-        yield self.client.testException('Safe')
         try:
             yield self.client.testException('Xception')
             self.fail("should have gotten exception")
-        except Xception, x:
+        except Xception as x:
             self.assertEquals(x.errorCode, 1001)
             self.assertEquals(x.message, 'Xception')
 
         try:
             yield self.client.testException("throw_undeclared")
-            self.fail("should have thrown exception")
-        except Exception: # type is undefined
+            self.fail("should have gotten exception")
+        except TApplicationException:
             pass
- 
+
+        yield self.client.testException('Safe')
+
     @defer.inlineCallbacks
     def testOneway(self):
-        yield self.client.testOneway(2)
+        yield self.client.testOneway(1)
         start, end, seconds = yield self.handler.onewaysQueue.get()
-        self.assertAlmostEquals(seconds, (end - start), places=2)
+        self.assertAlmostEquals(seconds, (end - start), places=1)
+        self.assertEquals((yield self.client.testI32(-1)), -1)
diff --git a/test/py/CMakeLists.txt b/test/py/CMakeLists.txt
new file mode 100644
index 0000000..fbc2217
--- /dev/null
+++ b/test/py/CMakeLists.txt
@@ -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.
+#
+
+add_test(NAME python_test_generate
+    COMMAND ${CMAKE_COMMAND}
+            -DTHRIFTCOMPILER=$<TARGET_FILE:thrift-compiler>
+            -DMY_PROJECT_DIR=${PROJECT_SOURCE_DIR}
+            -DMY_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
+            -DMY_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
+    -P ${CMAKE_CURRENT_SOURCE_DIR}/generate.cmake
+)
+
+add_test(NAME python_test
+    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/RunClientServer.py --gen-base=${CMAKE_CURRENT_BINARY_DIR}
+    DEPENDS python_test_generate
+    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
diff --git a/test/py/FastbinaryTest.py b/test/py/FastbinaryTest.py
new file mode 100755
index 0000000..05c0bb6
--- /dev/null
+++ b/test/py/FastbinaryTest.py
@@ -0,0 +1,256 @@
+#!/usr/bin/env python
+
+#
+# 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.
+#
+
+r"""
+PYTHONPATH=./gen-py:../../lib/py/build/lib... ./FastbinaryTest.py
+"""
+
+# TODO(dreiss): Test error cases.  Check for memory leaks.
+
+from __future__ import print_function
+
+import math
+import os
+import sys
+import timeit
+
+from copy import deepcopy
+from pprint import pprint
+
+from thrift.transport import TTransport
+from thrift.protocol.TBinaryProtocol import TBinaryProtocol, TBinaryProtocolAccelerated
+from thrift.protocol.TCompactProtocol import TCompactProtocol, TCompactProtocolAccelerated
+
+from DebugProtoTest import Srv
+from DebugProtoTest.ttypes import Backwards, Bonk, Empty, HolyMoley, OneOfEach, RandomStuff, Wrapper
+
+
+class TDevNullTransport(TTransport.TTransportBase):
+    def __init__(self):
+        pass
+
+    def isOpen(self):
+        return True
+
+
+ooe1 = OneOfEach()
+ooe1.im_true = True
+ooe1.im_false = False
+ooe1.a_bite = 0xd6
+ooe1.integer16 = 27000
+ooe1.integer32 = 1 << 24
+ooe1.integer64 = 6000 * 1000 * 1000
+ooe1.double_precision = math.pi
+ooe1.some_characters = "Debug THIS!"
+ooe1.zomg_unicode = u"\xd7\n\a\t"
+
+ooe2 = OneOfEach()
+ooe2.integer16 = 16
+ooe2.integer32 = 32
+ooe2.integer64 = 64
+ooe2.double_precision = (math.sqrt(5) + 1) / 2
+ooe2.some_characters = ":R (me going \"rrrr\")"
+ooe2.zomg_unicode = u"\xd3\x80\xe2\x85\xae\xce\x9d\x20"\
+                    u"\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe"\
+                    u"\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"\
+                    u"\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba"\
+                    u"\xc7\x83\xe2\x80\xbc"
+
+if sys.version_info[0] == 2 and os.environ.get('THRIFT_TEST_PY_NO_UTF8STRINGS'):
+    ooe1.zomg_unicode = ooe1.zomg_unicode.encode('utf8')
+    ooe2.zomg_unicode = ooe2.zomg_unicode.encode('utf8')
+
+hm = HolyMoley(**{"big": [], "contain": set(), "bonks": {}})
+hm.big.append(ooe1)
+hm.big.append(ooe2)
+hm.big[0].a_bite = 0x22
+hm.big[1].a_bite = 0x22
+
+hm.contain.add(("and a one", "and a two"))
+hm.contain.add(("then a one, two", "three!", "FOUR!"))
+if sys.version_info[0] == 2 and os.environ.get('THRIFT_TEST_PY_NO_UTF8STRINGS'):
+    hm.contain.add((u"\xd7\n\a\t".encode('utf8'),))
+else:
+    hm.contain.add((u"\xd7\n\a\t",))
+hm.contain.add(())
+
+hm.bonks["nothing"] = []
+hm.bonks["something"] = [
+    Bonk(**{"type": 1, "message": "Wait."}),
+    Bonk(**{"type": 2, "message": "What?"}),
+]
+hm.bonks["poe"] = [
+    Bonk(**{"type": 3, "message": "quoth"}),
+    Bonk(**{"type": 4, "message": "the raven"}),
+    Bonk(**{"type": 5, "message": "nevermore"}),
+]
+
+rs = RandomStuff()
+rs.a = 1
+rs.b = 2
+rs.c = 3
+rs.myintlist = list(range(20))
+rs.maps = {1: Wrapper(**{"foo": Empty()}), 2: Wrapper(**{"foo": Empty()})}
+rs.bigint = 124523452435
+rs.triple = 3.14
+
+# make sure this splits two buffers in a buffered protocol
+rshuge = RandomStuff()
+rshuge.myintlist = list(range(10000))
+
+my_zero = Srv.Janky_result(**{"success": 5})
+
+
+class Test(object):
+    def __init__(self, fast, slow):
+        self._fast = fast
+        self._slow = slow
+
+    def _check_write(self, o):
+        trans_fast = TTransport.TMemoryBuffer()
+        trans_slow = TTransport.TMemoryBuffer()
+        prot_fast = self._fast(trans_fast, fallback=False)
+        prot_slow = self._slow(trans_slow)
+
+        o.write(prot_fast)
+        o.write(prot_slow)
+        ORIG = trans_slow.getvalue()
+        MINE = trans_fast.getvalue()
+        if ORIG != MINE:
+            print("actual  : %s\nexpected: %s" % (repr(MINE), repr(ORIG)))
+            raise Exception('write value mismatch')
+
+    def _check_read(self, o):
+        prot = self._slow(TTransport.TMemoryBuffer())
+        o.write(prot)
+
+        slow_version_binary = prot.trans.getvalue()
+
+        prot = self._fast(
+            TTransport.TMemoryBuffer(slow_version_binary), fallback=False)
+        c = o.__class__()
+        c.read(prot)
+        if c != o:
+            print("actual  : ")
+            pprint(repr(c))
+            print("expected: ")
+            pprint(repr(o))
+            raise Exception('read value mismatch')
+
+        prot = self._fast(
+            TTransport.TBufferedTransport(
+                TTransport.TMemoryBuffer(slow_version_binary)), fallback=False)
+        c = o.__class__()
+        c.read(prot)
+        if c != o:
+            print("actual  : ")
+            pprint(repr(c))
+            print("expected: ")
+            pprint(repr(o))
+            raise Exception('read value mismatch')
+
+    def do_test(self):
+        self._check_write(HolyMoley())
+        self._check_read(HolyMoley())
+
+        self._check_write(hm)
+        no_set = deepcopy(hm)
+        no_set.contain = set()
+        self._check_read(no_set)
+        self._check_read(hm)
+
+        self._check_write(rs)
+        self._check_read(rs)
+
+        self._check_write(rshuge)
+        self._check_read(rshuge)
+
+        self._check_write(my_zero)
+        self._check_read(my_zero)
+
+        self._check_read(Backwards(**{"first_tag2": 4, "second_tag1": 2}))
+
+        # One case where the serialized form changes, but only superficially.
+        o = Backwards(**{"first_tag2": 4, "second_tag1": 2})
+        trans_fast = TTransport.TMemoryBuffer()
+        trans_slow = TTransport.TMemoryBuffer()
+        prot_fast = self._fast(trans_fast, fallback=False)
+        prot_slow = self._slow(trans_slow)
+
+        o.write(prot_fast)
+        o.write(prot_slow)
+        ORIG = trans_slow.getvalue()
+        MINE = trans_fast.getvalue()
+        assert id(ORIG) != id(MINE)
+
+        prot = self._fast(TTransport.TMemoryBuffer(), fallback=False)
+        o.write(prot)
+        prot = self._slow(
+            TTransport.TMemoryBuffer(prot.trans.getvalue()))
+        c = o.__class__()
+        c.read(prot)
+        if c != o:
+            print("copy: ")
+            pprint(repr(c))
+            print("orig: ")
+            pprint(repr(o))
+
+
+def do_test(fast, slow):
+    Test(fast, slow).do_test()
+
+
+def do_benchmark(protocol, iters=5000, skip_slow=False):
+    setup = """
+from __main__ import hm, rs, TDevNullTransport
+from thrift.protocol.{0} import {0}{1}
+trans = TDevNullTransport()
+prot = {0}{1}(trans{2})
+"""
+
+    setup_fast = setup.format(protocol, 'Accelerated', ', fallback=False')
+    if not skip_slow:
+        setup_slow = setup.format(protocol, '', '')
+
+    print("Starting Benchmarks")
+
+    if not skip_slow:
+        print("HolyMoley Standard = %f" %
+              timeit.Timer('hm.write(prot)', setup_slow).timeit(number=iters))
+
+    print("HolyMoley Acceler. = %f" %
+          timeit.Timer('hm.write(prot)', setup_fast).timeit(number=iters))
+
+    if not skip_slow:
+        print("FastStruct Standard = %f" %
+              timeit.Timer('rs.write(prot)', setup_slow).timeit(number=iters))
+
+    print("FastStruct Acceler. = %f" %
+          timeit.Timer('rs.write(prot)', setup_fast).timeit(number=iters))
+
+
+if __name__ == '__main__':
+    print('Testing TBinaryAccelerated')
+    do_test(TBinaryProtocolAccelerated, TBinaryProtocol)
+    do_benchmark('TBinaryProtocol')
+    print('Testing TCompactAccelerated')
+    do_test(TCompactProtocolAccelerated, TCompactProtocol)
+    do_benchmark('TCompactProtocol')
diff --git a/test/py/Makefile.am b/test/py/Makefile.am
old mode 100755
new mode 100644
index 6b31769..8296200
--- a/test/py/Makefile.am
+++ b/test/py/Makefile.am
@@ -16,26 +16,43 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-.NOTPARALLEL:
-THRIFT = $(top_srcdir)/compiler/cpp/thrift
+AUTOMAKE_OPTIONS = serial-tests
 
 py_unit_tests = RunClientServer.py
 
 thrift_gen =                                    \
         gen-py/ThriftTest/__init__.py           \
         gen-py/DebugProtoTest/__init__.py \
+        gen-py/DoubleConstantsTest/__init__.py \
+        gen-py/Recursive/__init__.py \
         gen-py-default/ThriftTest/__init__.py           \
         gen-py-default/DebugProtoTest/__init__.py \
+        gen-py-default/DoubleConstantsTest/__init__.py \
+        gen-py-default/Recursive/__init__.py \
         gen-py-slots/ThriftTest/__init__.py           \
         gen-py-slots/DebugProtoTest/__init__.py \
-        gen-py-newstyle/ThriftTest/__init__.py           \
-        gen-py-newstyle/DebugProtoTest/__init__.py \
-        gen-py-newstyleslots/ThriftTest/__init__.py           \
-        gen-py-newstyleslots/DebugProtoTest/__init__.py \
+        gen-py-slots/DoubleConstantsTest/__init__.py \
+        gen-py-slots/Recursive/__init__.py \
+        gen-py-oldstyle/ThriftTest/__init__.py \
+        gen-py-oldstyle/DebugProtoTest/__init__.py \
+        gen-py-oldstyle/DoubleConstantsTest/__init__.py \
+        gen-py-oldstyle/Recursive/__init__.py \
+        gen-py-no_utf8strings/ThriftTest/__init__.py \
+        gen-py-no_utf8strings/DebugProtoTest/__init__.py \
+        gen-py-no_utf8strings/DoubleConstantsTest/__init__.py \
+        gen-py-no_utf8strings/Recursive/__init__.py \
         gen-py-dynamic/ThriftTest/__init__.py           \
         gen-py-dynamic/DebugProtoTest/__init__.py \
+        gen-py-dynamic/DoubleConstantsTest/__init__.py \
+        gen-py-dynamic/Recursive/__init__.py \
         gen-py-dynamicslots/ThriftTest/__init__.py           \
-        gen-py-dynamicslots/DebugProtoTest/__init__.py
+        gen-py-dynamicslots/DebugProtoTest/__init__.py \
+        gen-py-dynamicslots/DoubleConstantsTest/__init__.py \
+        gen-py-dynamicslots/Recursive/__init__.py
+
+
+precross: $(thrift_gen)
+BUILT_SOURCES = $(thrift_gen)
 
 helper_scripts=                                 \
         TestClient.py                           \
@@ -49,30 +66,32 @@
 TESTS= $(py_unit_tests)
 
 
-gen-py/%/__init__.py: ../%.thrift
+gen-py/%/__init__.py: ../%.thrift $(THRIFT)
 	$(THRIFT) --gen py  $<
-	test -d gen-py-default || mkdir gen-py-default
+
+gen-py-default/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-default || $(MKDIR_P) gen-py-default
 	$(THRIFT) --gen py -out gen-py-default $<
 
-gen-py-slots/%/__init__.py: ../%.thrift
-	test -d gen-py-slots || mkdir gen-py-slots
+gen-py-slots/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-slots || $(MKDIR_P) gen-py-slots
 	$(THRIFT) --gen py:slots -out gen-py-slots $<
 
-gen-py-newstyle/%/__init__.py: ../%.thrift
-	test -d gen-py-newstyle || mkdir gen-py-newstyle
-	$(THRIFT) --gen py:new_style -out gen-py-newstyle $<
+gen-py-oldstyle/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-oldstyle || $(MKDIR_P) gen-py-oldstyle
+	$(THRIFT) --gen py:old_style -out gen-py-oldstyle $<
 
-gen-py-newstyleslots/%/__init__.py: ../%.thrift
-	test -d gen-py-newstyleslots || mkdir gen-py-newstyleslots
-	$(THRIFT) --gen py:new_style,slots -out gen-py-newstyleslots $<
+gen-py-no_utf8strings/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-no_utf8strings || $(MKDIR_P) gen-py-no_utf8strings
+	$(THRIFT) --gen py:no_utf8strings -out gen-py-no_utf8strings $<
 
-gen-py-dynamic/%/__init__.py: ../%.thrift
-	test -d gen-py-dynamic || mkdir gen-py-dynamic
+gen-py-dynamic/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-dynamic || $(MKDIR_P) gen-py-dynamic
 	$(THRIFT) --gen py:dynamic -out gen-py-dynamic $<
 
-gen-py-dynamicslots/%/__init__.py: ../%.thrift
-	test -d gen-py-dynamicslots || mkdir gen-py-dynamicslots
+gen-py-dynamicslots/%/__init__.py: ../%.thrift $(THRIFT)
+	test -d gen-py-dynamicslots || $(MKDIR_P) gen-py-dynamicslots
 	$(THRIFT) --gen py:dynamic,slots -out gen-py-dynamicslots $<
 
 clean-local:
-	$(RM) -r gen-py gen-py-slots gen-py-default gen-py-newstyle gen-py-newstyleslots gen-py-dynamic gen-py-dynamicslots
+	$(RM) -r gen-py gen-py-slots gen-py-default gen-py-oldstyle gen-py-no_utf8strings gen-py-dynamic gen-py-dynamicslots
diff --git a/test/py/RunClientServer.py b/test/py/RunClientServer.py
index db0bfa4..56a408e 100755
--- a/test/py/RunClientServer.py
+++ b/test/py/RunClientServer.py
@@ -20,174 +20,304 @@
 #
 
 from __future__ import division
-import time
-import subprocess
-import sys
+from __future__ import print_function
+import platform
+import copy
 import os
 import signal
+import socket
+import subprocess
+import sys
+import time
 from optparse import OptionParser
 
-parser = OptionParser()
-parser.add_option('--genpydirs', type='string', dest='genpydirs',
-    default='default,slots,newstyle,newstyleslots,dynamic,dynamicslots',
-    help='directory extensions for generated code, used as suffixes for \"gen-py-*\" added sys.path for individual tests')
-parser.add_option("--port", type="int", dest="port", default=9090,
-    help="port number for server to listen on")
-parser.add_option('-v', '--verbose', action="store_const", 
-    dest="verbose", const=2,
-    help="verbose output")
-parser.add_option('-q', '--quiet', action="store_const", 
-    dest="verbose", const=0,
-    help="minimal output")
-parser.set_defaults(verbose=1)
-options, args = parser.parse_args()
+from util import local_libpath
 
-generated_dirs = []
-for gp_dir in options.genpydirs.split(','):
-  generated_dirs.append('gen-py-%s' % (gp_dir))
+SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
 
-SCRIPTS = ['TSimpleJSONProtocolTest.py',
-           'SerializationTest.py',
-           'TestEof.py',
-           'TestSyntax.py',
-           'TestSocket.py']
+SCRIPTS = [
+    'FastbinaryTest.py',
+    'TestFrozen.py',
+    'TestRenderedDoubleConstants.py',
+    'TSimpleJSONProtocolTest.py',
+    'SerializationTest.py',
+    'TestEof.py',
+    'TestSyntax.py',
+    'TestSocket.py',
+]
 FRAMED = ["TNonblockingServer"]
 SKIP_ZLIB = ['TNonblockingServer', 'THttpServer']
-SKIP_SSL = ['TNonblockingServer', 'THttpServer']
-EXTRA_DELAY = dict(TProcessPoolServer=3.5)
+SKIP_SSL = ['THttpServer']
+EXTRA_DELAY = dict(TProcessPoolServer=5.5)
 
-PROTOS= [
+PROTOS = [
     'accel',
+    'accelc',
     'binary',
-    'compact']
-# FIXME: add json
-# disabled because json HTTP test hangs... why?
+    'compact',
+    'json',
+    'header',
+]
 
-SERVERS = [
-  "TSimpleServer",
-  "TThreadedServer",
-  "TThreadPoolServer",
-  "TProcessPoolServer", # new!
-  "TForkingServer",
-  "TNonblockingServer",
-  "THttpServer" ]
 
-# Test for presence of multiprocessing module, and if it is not present, then
-# remove it from the list of available servers.
-try:
-  import multiprocessing
-except:
-  print 'Warning: the multiprocessing module is unavailable. Skipping tests for TProcessPoolServer'
-  SERVERS.remove('TProcessPoolServer')
-
-try:
-  import ssl
-except:
-  print 'Warning, no ssl module available. Skipping all SSL tests.'
-  SKIP_SSL.extend(SERVERS)
-
-# commandline permits a single class name to be specified to override SERVERS=[...]
-if len(args) == 1:
-  if args[0] in SERVERS:
-    SERVERS = args
-  else:
-    print 'Unavailable server type "%s", please choose one of: %s' % (args[0], SERVERS)
-    sys.exit(0)
+def default_servers():
+    servers = [
+        'TSimpleServer',
+        'TThreadedServer',
+        'TThreadPoolServer',
+        'TNonblockingServer',
+        'THttpServer',
+    ]
+    if platform.system() != 'Windows':
+        servers.append('TProcessPoolServer')
+        servers.append('TForkingServer')
+    return servers
 
 
 def relfile(fname):
-    return os.path.join(os.path.dirname(__file__), fname)
+    return os.path.join(SCRIPT_DIR, fname)
 
-def runScriptTest(genpydir, script):
-  script_args = [sys.executable, relfile(script) ]
-  script_args.append('--genpydir=%s' % genpydir)
-  serverproc = subprocess.Popen(script_args)
-  print '\nTesting script: %s\n----' % (' '.join(script_args))
-  ret = subprocess.call(script_args)
-  if ret != 0:
-    raise Exception("Script subprocess failed, retcode=%d, args: %s" % (ret, ' '.join(script_args)))
-  
-def runServiceTest(genpydir, server_class, proto, port, use_zlib, use_ssl):
-  # Build command line arguments
-  server_args = [sys.executable, relfile('TestServer.py') ]
-  cli_args = [sys.executable, relfile('TestClient.py') ]
-  for which in (server_args, cli_args):
-    which.append('--genpydir=%s' % genpydir)
-    which.append('--proto=%s' % proto) # accel, binary or compact
-    which.append('--port=%d' % port) # default to 9090
-    if use_zlib:
-      which.append('--zlib')
-    if use_ssl:
-      which.append('--ssl')
-    if options.verbose == 0:
-      which.append('-q')
-    if options.verbose == 2:
-      which.append('-v')
-  # server-specific option to select server class
-  server_args.append(server_class)
-  # client-specific cmdline options
-  if server_class in FRAMED:
-    cli_args.append('--framed')
-  if server_class == 'THttpServer':
-    cli_args.append('--http=/')
-  if options.verbose > 0:
-    print 'Testing server %s: %s' % (server_class, ' '.join(server_args))
-  serverproc = subprocess.Popen(server_args)
-  time.sleep(0.15)
-  try:
-    if options.verbose > 0:
-      print 'Testing client: %s' % (' '.join(cli_args))
-    ret = subprocess.call(cli_args)
+
+def setup_pypath(libdir, gendir):
+    dirs = [libdir, gendir]
+    env = copy.deepcopy(os.environ)
+    pypath = env.get('PYTHONPATH', None)
+    if pypath:
+        dirs.append(pypath)
+    env['PYTHONPATH'] = os.pathsep.join(dirs)
+    if gendir.endswith('gen-py-no_utf8strings'):
+        env['THRIFT_TEST_PY_NO_UTF8STRINGS'] = '1'
+    return env
+
+
+def runScriptTest(libdir, genbase, genpydir, script):
+    env = setup_pypath(libdir, os.path.join(genbase, genpydir))
+    script_args = [sys.executable, relfile(script)]
+    print('\nTesting script: %s\n----' % (' '.join(script_args)))
+    ret = subprocess.call(script_args, env=env)
     if ret != 0:
-      raise Exception("Client subprocess failed, retcode=%d, args: %s" % (ret, ' '.join(cli_args)))
-  finally:
-    # check that server didn't die
-    serverproc.poll()
-    if serverproc.returncode is not None:
-      print 'FAIL: Server process (%s) failed with retcode %d' % (' '.join(server_args), serverproc.returncode)
-      raise Exception('Server subprocess %s died, args: %s' % (server_class, ' '.join(server_args)))
-    else:
-      extra_sleep = EXTRA_DELAY.get(server_class, 0)
-      if extra_sleep > 0 and options.verbose > 0:
-        print 'Giving %s (proto=%s,zlib=%s,ssl=%s) an extra %d seconds for child processes to terminate via alarm' % (server_class,
-              proto, use_zlib, use_ssl, extra_sleep)
-        time.sleep(extra_sleep)
-      os.kill(serverproc.pid, signal.SIGKILL)
-  # wait for shutdown
-  time.sleep(0.05)
+        print('*** FAILED ***', file=sys.stderr)
+        print('LIBDIR: %s' % libdir, file=sys.stderr)
+        print('PY_GEN: %s' % genpydir, file=sys.stderr)
+        print('SCRIPT: %s' % script, file=sys.stderr)
+        raise Exception("Script subprocess failed, retcode=%d, args: %s" % (ret, ' '.join(script_args)))
 
-test_count = 0
-# run tests without a client/server first
-print '----------------'
-print ' Executing individual test scripts with various generated code directories'
-print ' Directories to be tested: ' + ', '.join(generated_dirs)
-print ' Scripts to be tested: ' + ', '.join(SCRIPTS)
-print '----------------'
-for genpydir in generated_dirs:
-  for script in SCRIPTS:
-    runScriptTest(genpydir, script)
-  
-print '----------------'
-print ' Executing Client/Server tests with various generated code directories'
-print ' Servers to be tested: ' + ', '.join(SERVERS)
-print ' Directories to be tested: ' + ', '.join(generated_dirs)
-print ' Protocols to be tested: ' + ', '.join(PROTOS)
-print ' Options to be tested: ZLIB(yes/no), SSL(yes/no)'
-print '----------------'
-for try_server in SERVERS:
-  for genpydir in generated_dirs:
-    for try_proto in PROTOS:
-      for with_zlib in (False, True):
+
+def runServiceTest(libdir, genbase, genpydir, server_class, proto, port, use_zlib, use_ssl, verbose):
+    env = setup_pypath(libdir, os.path.join(genbase, genpydir))
+    # Build command line arguments
+    server_args = [sys.executable, relfile('TestServer.py')]
+    cli_args = [sys.executable, relfile('TestClient.py')]
+    for which in (server_args, cli_args):
+        which.append('--protocol=%s' % proto)  # accel, binary, compact or json
+        which.append('--port=%d' % port)  # default to 9090
+        if use_zlib:
+            which.append('--zlib')
+        if use_ssl:
+            which.append('--ssl')
+        if verbose == 0:
+            which.append('-q')
+        if verbose == 2:
+            which.append('-v')
+    # server-specific option to select server class
+    server_args.append(server_class)
+    # client-specific cmdline options
+    if server_class in FRAMED:
+        cli_args.append('--transport=framed')
+    else:
+        cli_args.append('--transport=buffered')
+    if server_class == 'THttpServer':
+        cli_args.append('--http=/')
+    if verbose > 0:
+        print('Testing server %s: %s' % (server_class, ' '.join(server_args)))
+    serverproc = subprocess.Popen(server_args, env=env)
+
+    def ensureServerAlive():
+        if serverproc.poll() is not None:
+            print(('FAIL: Server process (%s) failed with retcode %d')
+                  % (' '.join(server_args), serverproc.returncode))
+            raise Exception('Server subprocess %s died, args: %s'
+                            % (server_class, ' '.join(server_args)))
+
+    # Wait for the server to start accepting connections on the given port.
+    sleep_time = 0.1  # Seconds
+    max_attempts = 100
+    attempt = 0
+    while True:
+        sock4 = socket.socket()
+        sock6 = socket.socket(socket.AF_INET6)
+        try:
+            if sock4.connect_ex(('127.0.0.1', port)) == 0 \
+                    or sock6.connect_ex(('::1', port)) == 0:
+                break
+            attempt += 1
+            if attempt >= max_attempts:
+                raise Exception("TestServer not ready on port %d after %.2f seconds"
+                                % (port, sleep_time * attempt))
+            ensureServerAlive()
+            time.sleep(sleep_time)
+        finally:
+            sock4.close()
+            sock6.close()
+
+    try:
+        if verbose > 0:
+            print('Testing client: %s' % (' '.join(cli_args)))
+        ret = subprocess.call(cli_args, env=env)
+        if ret != 0:
+            print('*** FAILED ***', file=sys.stderr)
+            print('LIBDIR: %s' % libdir, file=sys.stderr)
+            print('PY_GEN: %s' % genpydir, file=sys.stderr)
+            raise Exception("Client subprocess failed, retcode=%d, args: %s" % (ret, ' '.join(cli_args)))
+    finally:
+        # check that server didn't die
+        ensureServerAlive()
+        extra_sleep = EXTRA_DELAY.get(server_class, 0)
+        if extra_sleep > 0 and verbose > 0:
+            print('Giving %s (proto=%s,zlib=%s,ssl=%s) an extra %d seconds for child'
+                  'processes to terminate via alarm'
+                  % (server_class, proto, use_zlib, use_ssl, extra_sleep))
+            time.sleep(extra_sleep)
+        sig = signal.SIGKILL if platform.system() != 'Windows' else signal.SIGABRT
+        os.kill(serverproc.pid, sig)
+        serverproc.wait()
+
+
+class TestCases(object):
+    def __init__(self, genbase, libdir, port, gendirs, servers, verbose):
+        self.genbase = genbase
+        self.libdir = libdir
+        self.port = port
+        self.verbose = verbose
+        self.gendirs = gendirs
+        self.servers = servers
+
+    def default_conf(self):
+        return {
+            'gendir': self.gendirs[0],
+            'server': self.servers[0],
+            'proto': PROTOS[0],
+            'zlib': False,
+            'ssl': False,
+        }
+
+    def run(self, conf, test_count):
+        with_zlib = conf['zlib']
+        with_ssl = conf['ssl']
+        try_server = conf['server']
+        try_proto = conf['proto']
+        genpydir = conf['gendir']
         # skip any servers that don't work with the Zlib transport
         if with_zlib and try_server in SKIP_ZLIB:
-          continue
-        for with_ssl in (False, True):
-          # skip any servers that don't work with SSL
-          if with_ssl and try_server in SKIP_SSL:
-            continue
-          test_count += 1
-          if options.verbose > 0:
-            print '\nTest run #%d:  (includes %s) Server=%s,  Proto=%s,  zlib=%s,  SSL=%s' % (test_count, genpydir, try_server, try_proto, with_zlib, with_ssl)
-          runServiceTest(genpydir, try_server, try_proto, options.port, with_zlib, with_ssl)
-          if options.verbose > 0:
-            print 'OK: Finished (includes %s)  %s / %s proto / zlib=%s / SSL=%s.   %d combinations tested.' % (genpydir, try_server, try_proto, with_zlib, with_ssl, test_count)
+            return False
+        # skip any servers that don't work with SSL
+        if with_ssl and try_server in SKIP_SSL:
+            return False
+        if self.verbose > 0:
+            print('\nTest run #%d:  (includes %s) Server=%s,  Proto=%s,  zlib=%s,  SSL=%s'
+                  % (test_count, genpydir, try_server, try_proto, with_zlib, with_ssl))
+        runServiceTest(self.libdir, self.genbase, genpydir, try_server, try_proto, self.port, with_zlib, with_ssl, self.verbose)
+        if self.verbose > 0:
+            print('OK: Finished (includes %s)  %s / %s proto / zlib=%s / SSL=%s.   %d combinations tested.'
+                  % (genpydir, try_server, try_proto, with_zlib, with_ssl, test_count))
+        return True
+
+    def test_feature(self, name, values):
+        test_count = 0
+        conf = self.default_conf()
+        for try_server in values:
+            conf[name] = try_server
+            if self.run(conf, test_count):
+                test_count += 1
+        return test_count
+
+    def run_all_tests(self):
+        test_count = 0
+        for try_server in self.servers:
+            for genpydir in self.gendirs:
+                for try_proto in PROTOS:
+                    for with_zlib in (False, True):
+                        # skip any servers that don't work with the Zlib transport
+                        if with_zlib and try_server in SKIP_ZLIB:
+                            continue
+                        for with_ssl in (False, True):
+                            # skip any servers that don't work with SSL
+                            if with_ssl and try_server in SKIP_SSL:
+                                continue
+                            test_count += 1
+                            if self.verbose > 0:
+                                print('\nTest run #%d:  (includes %s) Server=%s,  Proto=%s,  zlib=%s,  SSL=%s'
+                                      % (test_count, genpydir, try_server, try_proto, with_zlib, with_ssl))
+                            runServiceTest(self.libdir, self.genbase, genpydir, try_server, try_proto, self.port, with_zlib, with_ssl)
+                            if self.verbose > 0:
+                                print('OK: Finished (includes %s)  %s / %s proto / zlib=%s / SSL=%s.   %d combinations tested.'
+                                      % (genpydir, try_server, try_proto, with_zlib, with_ssl, test_count))
+        return test_count
+
+
+def main():
+    parser = OptionParser()
+    parser.add_option('--all', action="store_true", dest='all')
+    parser.add_option('--genpydirs', type='string', dest='genpydirs',
+                      default='default,slots,oldstyle,no_utf8strings,dynamic,dynamicslots',
+                      help='directory extensions for generated code, used as suffixes for \"gen-py-*\" added sys.path for individual tests')
+    parser.add_option("--port", type="int", dest="port", default=9090,
+                      help="port number for server to listen on")
+    parser.add_option('-v', '--verbose', action="store_const",
+                      dest="verbose", const=2,
+                      help="verbose output")
+    parser.add_option('-q', '--quiet', action="store_const",
+                      dest="verbose", const=0,
+                      help="minimal output")
+    parser.add_option('-L', '--libdir', dest="libdir", default=local_libpath(),
+                      help="directory path that contains Thrift Python library")
+    parser.add_option('--gen-base', dest="gen_base", default=SCRIPT_DIR,
+                      help="directory path that contains Thrift Python library")
+    parser.set_defaults(verbose=1)
+    options, args = parser.parse_args()
+
+    generated_dirs = []
+    for gp_dir in options.genpydirs.split(','):
+        generated_dirs.append('gen-py-%s' % (gp_dir))
+
+    # commandline permits a single class name to be specified to override SERVERS=[...]
+    servers = default_servers()
+    if len(args) == 1:
+        if args[0] in servers:
+            servers = args
+        else:
+            print('Unavailable server type "%s", please choose one of: %s' % (args[0], servers))
+            sys.exit(0)
+
+    tests = TestCases(options.gen_base, options.libdir, options.port, generated_dirs, servers, options.verbose)
+
+    # run tests without a client/server first
+    print('----------------')
+    print(' Executing individual test scripts with various generated code directories')
+    print(' Directories to be tested: ' + ', '.join(generated_dirs))
+    print(' Scripts to be tested: ' + ', '.join(SCRIPTS))
+    print('----------------')
+    for genpydir in generated_dirs:
+        for script in SCRIPTS:
+            runScriptTest(options.libdir, options.gen_base, genpydir, script)
+
+    print('----------------')
+    print(' Executing Client/Server tests with various generated code directories')
+    print(' Servers to be tested: ' + ', '.join(servers))
+    print(' Directories to be tested: ' + ', '.join(generated_dirs))
+    print(' Protocols to be tested: ' + ', '.join(PROTOS))
+    print(' Options to be tested: ZLIB(yes/no), SSL(yes/no)')
+    print('----------------')
+
+    if options.all:
+        tests.run_all_tests()
+    else:
+        tests.test_feature('gendir', generated_dirs)
+        tests.test_feature('server', servers)
+        tests.test_feature('proto', PROTOS)
+        tests.test_feature('zlib', [False, True])
+        tests.test_feature('ssl', [False, True])
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/test/py/SerializationTest.py b/test/py/SerializationTest.py
index 946f848..ef79835 100755
--- a/test/py/SerializationTest.py
+++ b/test/py/SerializationTest.py
@@ -19,343 +19,439 @@
 # under the License.
 #
 
-import sys, glob
-from optparse import OptionParser
-parser = OptionParser()
-parser.add_option('--genpydir', type='string', dest='genpydir', default='gen-py')
-options, args = parser.parse_args()
-del sys.argv[1:] # clean up hack so unittest doesn't complain
-sys.path.insert(0, options.genpydir)
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+from ThriftTest.ttypes import (
+    Bonk,
+    Bools,
+    LargeDeltas,
+    ListBonks,
+    NestedListsBonk,
+    NestedListsI32x2,
+    NestedListsI32x3,
+    NestedMixedx2,
+    Numberz,
+    VersioningTestV1,
+    VersioningTestV2,
+    Xtruct,
+    Xtruct2,
+)
 
-from ThriftTest.ttypes import *
+from Recursive.ttypes import RecTree
+from Recursive.ttypes import RecList
+from Recursive.ttypes import CoRec
+from Recursive.ttypes import CoRec2
+from Recursive.ttypes import VectorTest
 from DebugProtoTest.ttypes import CompactProtoTestStruct, Empty
 from thrift.transport import TTransport
-from thrift.transport import TSocket
 from thrift.protocol import TBinaryProtocol, TCompactProtocol, TJSONProtocol
 from thrift.TSerialization import serialize, deserialize
+import sys
 import unittest
-import time
+
 
 class AbstractTest(unittest.TestCase):
 
-  def setUp(self):
-      self.v1obj = VersioningTestV1(
-          begin_in_both=12345,
-          old_string='aaa',
-          end_in_both=54321,
-          )
+    def setUp(self):
+        self.v1obj = VersioningTestV1(
+            begin_in_both=12345,
+            old_string='aaa',
+            end_in_both=54321,
+        )
 
-      self.v2obj = VersioningTestV2(
-          begin_in_both=12345,
-          newint=1,
-          newbyte=2,
-          newshort=3,
-          newlong=4,
-          newdouble=5.0,
-          newstruct=Bonk(message="Hello!", type=123),
-          newlist=[7,8,9],
-          newset=set([42,1,8]),
-          newmap={1:2,2:3},
-          newstring="Hola!",
-          end_in_both=54321,
-          )
+        self.v2obj = VersioningTestV2(
+            begin_in_both=12345,
+            newint=1,
+            newbyte=2,
+            newshort=3,
+            newlong=4,
+            newdouble=5.0,
+            newstruct=Bonk(message="Hello!", type=123),
+            newlist=[7, 8, 9],
+            newset=set([42, 1, 8]),
+            newmap={1: 2, 2: 3},
+            newstring="Hola!",
+            end_in_both=54321,
+        )
 
-      self.bools = Bools(im_true=True, im_false=False)
-      self.bools_flipped = Bools(im_true=False, im_false=True)
+        self.bools = Bools(im_true=True, im_false=False)
+        self.bools_flipped = Bools(im_true=False, im_false=True)
 
-      self.large_deltas = LargeDeltas (
-          b1=self.bools,
-          b10=self.bools_flipped,
-          b100=self.bools,
-          check_true=True,
-          b1000=self.bools_flipped,
-          check_false=False,
-          vertwo2000=VersioningTestV2(newstruct=Bonk(message='World!', type=314)),
-          a_set2500=set(['lazy', 'brown', 'cow']),
-          vertwo3000=VersioningTestV2(newset=set([2, 3, 5, 7, 11])),
-          big_numbers=[2**8, 2**16, 2**31-1, -(2**31-1)]
-          )
+        self.large_deltas = LargeDeltas(
+            b1=self.bools,
+            b10=self.bools_flipped,
+            b100=self.bools,
+            check_true=True,
+            b1000=self.bools_flipped,
+            check_false=False,
+            vertwo2000=VersioningTestV2(newstruct=Bonk(message='World!', type=314)),
+            a_set2500=set(['lazy', 'brown', 'cow']),
+            vertwo3000=VersioningTestV2(newset=set([2, 3, 5, 7, 11])),
+            big_numbers=[2 ** 8, 2 ** 16, 2 ** 31 - 1, -(2 ** 31 - 1)]
+        )
 
-      self.compact_struct = CompactProtoTestStruct(
-          a_byte = 127,
-          a_i16=32000,
-          a_i32=1000000000,
-          a_i64=0xffffffffff,
-          a_double=5.6789,
-          a_string="my string",
-          true_field=True,
-          false_field=False,
-          empty_struct_field=Empty(),
-          byte_list=[-127, -1, 0, 1, 127],
-          i16_list=[-1, 0, 1, 0x7fff],
-          i32_list= [-1, 0, 0xff, 0xffff, 0xffffff, 0x7fffffff],
-          i64_list=[-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff],
-          double_list=[0.1, 0.2, 0.3],
-          string_list=["first", "second", "third"],
-          boolean_list=[True, True, True, False, False, False],
-          struct_list=[Empty(), Empty()],
-          byte_set=set([-127, -1, 0, 1, 127]),
-          i16_set=set([-1, 0, 1, 0x7fff]),
-          i32_set=set([1, 2, 3]),
-          i64_set=set([-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff]),
-          double_set=set([0.1, 0.2, 0.3]),
-          string_set=set(["first", "second", "third"]),
-          boolean_set=set([True, False]),
-          #struct_set=set([Empty()]), # unhashable instance
-          byte_byte_map={1 : 2},
-          i16_byte_map={1 : 1, -1 : 1, 0x7fff : 1},
-          i32_byte_map={1 : 1, -1 : 1, 0x7fffffff : 1},
-          i64_byte_map={0 : 1,  1 : 1, -1 : 1, 0x7fffffffffffffff : 1},
-          double_byte_map={-1.1 : 1, 1.1 : 1},
-          string_byte_map={"first" : 1, "second" : 2, "third" : 3, "" : 0},
-          boolean_byte_map={True : 1, False: 0},
-          byte_i16_map={1 : 1, 2 : -1, 3 : 0x7fff},
-          byte_i32_map={1 : 1, 2 : -1, 3 : 0x7fffffff},
-          byte_i64_map={1 : 1, 2 : -1, 3 : 0x7fffffffffffffff},
-          byte_double_map={1 : 0.1, 2 : -0.1, 3 : 1000000.1},
-          byte_string_map={1 : "", 2 : "blah", 3 : "loooooooooooooong string"},
-          byte_boolean_map={1 : True, 2 : False},
-          #list_byte_map # unhashable
-          #set_byte_map={set([1, 2, 3]) : 1, set([0, 1]) : 2, set([]) : 0}, # unhashable
-          #map_byte_map # unhashable
-          byte_map_map={0 : {}, 1 : {1 : 1}, 2 : {1 : 1, 2 : 2}},
-          byte_set_map={0 : set([]), 1 : set([1]), 2 : set([1, 2])},
-          byte_list_map={0 : [], 1 : [1], 2 : [1, 2]},
-          )
+        self.compact_struct = CompactProtoTestStruct(
+            a_byte=127,
+            a_i16=32000,
+            a_i32=1000000000,
+            a_i64=0xffffffffff,
+            a_double=5.6789,
+            a_string="my string",
+            true_field=True,
+            false_field=False,
+            empty_struct_field=Empty(),
+            byte_list=[-127, -1, 0, 1, 127],
+            i16_list=[-1, 0, 1, 0x7fff],
+            i32_list=[-1, 0, 0xff, 0xffff, 0xffffff, 0x7fffffff],
+            i64_list=[-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff],
+            double_list=[0.1, 0.2, 0.3],
+            string_list=["first", "second", "third"],
+            boolean_list=[True, True, True, False, False, False],
+            struct_list=[Empty(), Empty()],
+            byte_set=set([-127, -1, 0, 1, 127]),
+            i16_set=set([-1, 0, 1, 0x7fff]),
+            i32_set=set([1, 2, 3]),
+            i64_set=set([-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff]),
+            double_set=set([0.1, 0.2, 0.3]),
+            string_set=set(["first", "second", "third"]),
+            boolean_set=set([True, False]),
+            # struct_set=set([Empty()]), # unhashable instance
+            byte_byte_map={1: 2},
+            i16_byte_map={1: 1, -1: 1, 0x7fff: 1},
+            i32_byte_map={1: 1, -1: 1, 0x7fffffff: 1},
+            i64_byte_map={0: 1, 1: 1, -1: 1, 0x7fffffffffffffff: 1},
+            double_byte_map={-1.1: 1, 1.1: 1},
+            string_byte_map={"first": 1, "second": 2, "third": 3, "": 0},
+            boolean_byte_map={True: 1, False: 0},
+            byte_i16_map={1: 1, 2: -1, 3: 0x7fff},
+            byte_i32_map={1: 1, 2: -1, 3: 0x7fffffff},
+            byte_i64_map={1: 1, 2: -1, 3: 0x7fffffffffffffff},
+            byte_double_map={1: 0.1, 2: -0.1, 3: 1000000.1},
+            byte_string_map={1: "", 2: "blah", 3: "loooooooooooooong string"},
+            byte_boolean_map={1: True, 2: False},
+            # list_byte_map # unhashable
+            # set_byte_map={set([1, 2, 3]) : 1, set([0, 1]) : 2, set([]) : 0}, # unhashable
+            # map_byte_map # unhashable
+            byte_map_map={0: {}, 1: {1: 1}, 2: {1: 1, 2: 2}},
+            byte_set_map={0: set([]), 1: set([1]), 2: set([1, 2])},
+            byte_list_map={0: [], 1: [1], 2: [1, 2]},
+        )
 
-      self.nested_lists_i32x2 = NestedListsI32x2(
-                                              [
-                                                [ 1, 1, 2 ],
-                                                [ 2, 7, 9 ],
-                                                [ 3, 5, 8 ]
-                                              ]
-                                            )
+        self.nested_lists_i32x2 = NestedListsI32x2(
+            [
+                [1, 1, 2],
+                [2, 7, 9],
+                [3, 5, 8]
+            ]
+        )
 
-      self.nested_lists_i32x3 = NestedListsI32x3(
-                                              [
-                                                [
-                                                  [ 2, 7, 9 ],
-                                                  [ 3, 5, 8 ]
-                                                ],
-                                                [
-                                                  [ 1, 1, 2 ],
-                                                  [ 1, 4, 9 ]
-                                                ]
-                                              ]
-                                            )
+        self.nested_lists_i32x3 = NestedListsI32x3(
+            [
+                [
+                    [2, 7, 9],
+                    [3, 5, 8]
+                ],
+                [
+                    [1, 1, 2],
+                    [1, 4, 9]
+                ]
+            ]
+        )
 
-      self.nested_mixedx2 = NestedMixedx2( int_set_list=[
-                                            set([1,2,3]),
-                                            set([1,4,9]),
-                                            set([1,2,3,5,8,13,21]),
-                                            set([-1, 0, 1])
-                                            ],
-                                            # note, the sets below are sets of chars, since the strings are iterated
-                                            map_int_strset={ 10:set('abc'), 20:set('def'), 30:set('GHI') },
-                                            map_int_strset_list=[
-                                                                 { 10:set('abc'), 20:set('def'), 30:set('GHI') },
-                                                                 { 100:set('lmn'), 200:set('opq'), 300:set('RST') },
-                                                                 { 1000:set('uvw'), 2000:set('wxy'), 3000:set('XYZ') }
-                                                                 ]
-                                          )
+        self.nested_mixedx2 = NestedMixedx2(int_set_list=[
+            set([1, 2, 3]),
+            set([1, 4, 9]),
+            set([1, 2, 3, 5, 8, 13, 21]),
+            set([-1, 0, 1])
+        ],
+            # note, the sets below are sets of chars, since the strings are iterated
+            map_int_strset={10: set('abc'), 20: set('def'), 30: set('GHI')},
+            map_int_strset_list=[
+                {10: set('abc'), 20: set('def'), 30: set('GHI')},
+                {100: set('lmn'), 200: set('opq'), 300: set('RST')},
+                {1000: set('uvw'), 2000: set('wxy'), 3000: set('XYZ')}]
+        )
 
-      self.nested_lists_bonk = NestedListsBonk(
-                                              [
-                                                [
-                                                  [
-                                                    Bonk(message='inner A first', type=1),
-                                                    Bonk(message='inner A second', type=1)
-                                                  ],
-                                                  [
-                                                  Bonk(message='inner B first', type=2),
-                                                  Bonk(message='inner B second', type=2)
-                                                  ]
-                                                ]
-                                              ]
-                                            )
+        self.nested_lists_bonk = NestedListsBonk(
+            [
+                [
+                    [
+                        Bonk(message='inner A first', type=1),
+                        Bonk(message='inner A second', type=1)
+                    ],
+                    [
+                        Bonk(message='inner B first', type=2),
+                        Bonk(message='inner B second', type=2)
+                    ]
+                ]
+            ]
+        )
 
-      self.list_bonks = ListBonks(
-                                    [
-                                      Bonk(message='inner A', type=1),
-                                      Bonk(message='inner B', type=2),
-                                      Bonk(message='inner C', type=0)
-                                    ]
-                                  )
+        self.list_bonks = ListBonks(
+            [
+                Bonk(message='inner A', type=1),
+                Bonk(message='inner B', type=2),
+                Bonk(message='inner C', type=0)
+            ]
+        )
 
-  def _serialize(self, obj):
-    trans = TTransport.TMemoryBuffer()
-    prot = self.protocol_factory.getProtocol(trans)
-    obj.write(prot)
-    return trans.getvalue()
+    def _serialize(self, obj):
+        trans = TTransport.TMemoryBuffer()
+        prot = self.protocol_factory.getProtocol(trans)
+        obj.write(prot)
+        return trans.getvalue()
 
-  def _deserialize(self, objtype, data):
-    prot = self.protocol_factory.getProtocol(TTransport.TMemoryBuffer(data))
-    ret = objtype()
-    ret.read(prot)
-    return ret
+    def _deserialize(self, objtype, data):
+        prot = self.protocol_factory.getProtocol(TTransport.TMemoryBuffer(data))
+        ret = objtype()
+        ret.read(prot)
+        return ret
 
-  def testForwards(self):
-    obj = self._deserialize(VersioningTestV2, self._serialize(self.v1obj))
-    self.assertEquals(obj.begin_in_both, self.v1obj.begin_in_both)
-    self.assertEquals(obj.end_in_both, self.v1obj.end_in_both)
+    def testForwards(self):
+        obj = self._deserialize(VersioningTestV2, self._serialize(self.v1obj))
+        self.assertEquals(obj.begin_in_both, self.v1obj.begin_in_both)
+        self.assertEquals(obj.end_in_both, self.v1obj.end_in_both)
 
-  def testBackwards(self):
-    obj = self._deserialize(VersioningTestV1, self._serialize(self.v2obj))
-    self.assertEquals(obj.begin_in_both, self.v2obj.begin_in_both)
-    self.assertEquals(obj.end_in_both, self.v2obj.end_in_both)
+    def testBackwards(self):
+        obj = self._deserialize(VersioningTestV1, self._serialize(self.v2obj))
+        self.assertEquals(obj.begin_in_both, self.v2obj.begin_in_both)
+        self.assertEquals(obj.end_in_both, self.v2obj.end_in_both)
 
-  def testSerializeV1(self):
-    obj = self._deserialize(VersioningTestV1, self._serialize(self.v1obj))
-    self.assertEquals(obj, self.v1obj)
+    def testSerializeV1(self):
+        obj = self._deserialize(VersioningTestV1, self._serialize(self.v1obj))
+        self.assertEquals(obj, self.v1obj)
 
-  def testSerializeV2(self):
-    obj = self._deserialize(VersioningTestV2, self._serialize(self.v2obj))
-    self.assertEquals(obj, self.v2obj)
+    def testSerializeV2(self):
+        obj = self._deserialize(VersioningTestV2, self._serialize(self.v2obj))
+        self.assertEquals(obj, self.v2obj)
 
-  def testBools(self):
-    self.assertNotEquals(self.bools, self.bools_flipped)
-    self.assertNotEquals(self.bools, self.v1obj)
-    obj = self._deserialize(Bools, self._serialize(self.bools))
-    self.assertEquals(obj, self.bools)
-    obj = self._deserialize(Bools, self._serialize(self.bools_flipped))
-    self.assertEquals(obj, self.bools_flipped)
-    rep = repr(self.bools)
-    self.assertTrue(len(rep) > 0)
+    def testBools(self):
+        self.assertNotEquals(self.bools, self.bools_flipped)
+        self.assertNotEquals(self.bools, self.v1obj)
+        obj = self._deserialize(Bools, self._serialize(self.bools))
+        self.assertEquals(obj, self.bools)
+        obj = self._deserialize(Bools, self._serialize(self.bools_flipped))
+        self.assertEquals(obj, self.bools_flipped)
+        rep = repr(self.bools)
+        self.assertTrue(len(rep) > 0)
 
-  def testLargeDeltas(self):
-    # test large field deltas (meaningful in CompactProto only)
-    obj = self._deserialize(LargeDeltas, self._serialize(self.large_deltas))
-    self.assertEquals(obj, self.large_deltas)
-    rep = repr(self.large_deltas)
-    self.assertTrue(len(rep) > 0)
+    def testLargeDeltas(self):
+        # test large field deltas (meaningful in CompactProto only)
+        obj = self._deserialize(LargeDeltas, self._serialize(self.large_deltas))
+        self.assertEquals(obj, self.large_deltas)
+        rep = repr(self.large_deltas)
+        self.assertTrue(len(rep) > 0)
 
-  def testNestedListsI32x2(self):
-    obj = self._deserialize(NestedListsI32x2, self._serialize(self.nested_lists_i32x2))
-    self.assertEquals(obj, self.nested_lists_i32x2)
-    rep = repr(self.nested_lists_i32x2)
-    self.assertTrue(len(rep) > 0)
+    def testNestedListsI32x2(self):
+        obj = self._deserialize(NestedListsI32x2, self._serialize(self.nested_lists_i32x2))
+        self.assertEquals(obj, self.nested_lists_i32x2)
+        rep = repr(self.nested_lists_i32x2)
+        self.assertTrue(len(rep) > 0)
 
-  def testNestedListsI32x3(self):
-    obj = self._deserialize(NestedListsI32x3, self._serialize(self.nested_lists_i32x3))
-    self.assertEquals(obj, self.nested_lists_i32x3)
-    rep = repr(self.nested_lists_i32x3)
-    self.assertTrue(len(rep) > 0)
+    def testNestedListsI32x3(self):
+        obj = self._deserialize(NestedListsI32x3, self._serialize(self.nested_lists_i32x3))
+        self.assertEquals(obj, self.nested_lists_i32x3)
+        rep = repr(self.nested_lists_i32x3)
+        self.assertTrue(len(rep) > 0)
 
-  def testNestedMixedx2(self):
-    obj = self._deserialize(NestedMixedx2, self._serialize(self.nested_mixedx2))
-    self.assertEquals(obj, self.nested_mixedx2)
-    rep = repr(self.nested_mixedx2)
-    self.assertTrue(len(rep) > 0)
+    def testNestedMixedx2(self):
+        obj = self._deserialize(NestedMixedx2, self._serialize(self.nested_mixedx2))
+        self.assertEquals(obj, self.nested_mixedx2)
+        rep = repr(self.nested_mixedx2)
+        self.assertTrue(len(rep) > 0)
 
-  def testNestedListsBonk(self):
-    obj = self._deserialize(NestedListsBonk, self._serialize(self.nested_lists_bonk))
-    self.assertEquals(obj, self.nested_lists_bonk)
-    rep = repr(self.nested_lists_bonk)
-    self.assertTrue(len(rep) > 0)
+    def testNestedListsBonk(self):
+        obj = self._deserialize(NestedListsBonk, self._serialize(self.nested_lists_bonk))
+        self.assertEquals(obj, self.nested_lists_bonk)
+        rep = repr(self.nested_lists_bonk)
+        self.assertTrue(len(rep) > 0)
 
-  def testListBonks(self):
-    obj = self._deserialize(ListBonks, self._serialize(self.list_bonks))
-    self.assertEquals(obj, self.list_bonks)
-    rep = repr(self.list_bonks)
-    self.assertTrue(len(rep) > 0)
+    def testListBonks(self):
+        obj = self._deserialize(ListBonks, self._serialize(self.list_bonks))
+        self.assertEquals(obj, self.list_bonks)
+        rep = repr(self.list_bonks)
+        self.assertTrue(len(rep) > 0)
 
-  def testCompactStruct(self):
-    # test large field deltas (meaningful in CompactProto only)
-    obj = self._deserialize(CompactProtoTestStruct, self._serialize(self.compact_struct))
-    self.assertEquals(obj, self.compact_struct)
-    rep = repr(self.compact_struct)
-    self.assertTrue(len(rep) > 0)
+    def testCompactStruct(self):
+        # test large field deltas (meaningful in CompactProto only)
+        obj = self._deserialize(CompactProtoTestStruct, self._serialize(self.compact_struct))
+        self.assertEquals(obj, self.compact_struct)
+        rep = repr(self.compact_struct)
+        self.assertTrue(len(rep) > 0)
+
+    def testIntegerLimits(self):
+        if (sys.version_info[0] == 2 and sys.version_info[1] <= 6):
+            print('Skipping testIntegerLimits for Python 2.6')
+            return
+        bad_values = [CompactProtoTestStruct(a_byte=128), CompactProtoTestStruct(a_byte=-129),
+                      CompactProtoTestStruct(a_i16=32768), CompactProtoTestStruct(a_i16=-32769),
+                      CompactProtoTestStruct(a_i32=2147483648), CompactProtoTestStruct(a_i32=-2147483649),
+                      CompactProtoTestStruct(a_i64=9223372036854775808), CompactProtoTestStruct(a_i64=-9223372036854775809)
+                      ]
+
+        for value in bad_values:
+            self.assertRaises(Exception, self._serialize, value)
+
+    def testRecTree(self):
+        """Ensure recursive tree node can be created."""
+        children = []
+        for idx in range(1, 5):
+            node = RecTree(item=idx, children=None)
+            children.append(node)
+
+        parent = RecTree(item=0, children=children)
+        serde_parent = self._deserialize(RecTree, self._serialize(parent))
+        self.assertEquals(0, serde_parent.item)
+        self.assertEquals(4, len(serde_parent.children))
+        for child in serde_parent.children:
+            # Cannot use assertIsInstance in python 2.6?
+            self.assertTrue(isinstance(child, RecTree))
+
+    def _buildLinkedList(self):
+        head = cur = RecList(item=0)
+        for idx in range(1, 5):
+            node = RecList(item=idx)
+            cur.nextitem = node
+            cur = node
+        return head
+
+    def _collapseLinkedList(self, head):
+        out_list = []
+        cur = head
+        while cur is not None:
+            out_list.append(cur.item)
+            cur = cur.nextitem
+        return out_list
+
+    def testRecList(self):
+        """Ensure recursive linked list can be created."""
+        rec_list = self._buildLinkedList()
+        serde_list = self._deserialize(RecList, self._serialize(rec_list))
+        out_list = self._collapseLinkedList(serde_list)
+        self.assertEquals([0, 1, 2, 3, 4], out_list)
+
+    def testCoRec(self):
+        """Ensure co-recursive structures can be created."""
+        item1 = CoRec()
+        item2 = CoRec2()
+
+        item1.other = item2
+        item2.other = item1
+
+        # NOTE [econner724,2017-06-21]: These objects cannot be serialized as serialization
+        # results in an infinite loop. fbthrift also suffers from this
+        # problem.
+
+    def testRecVector(self):
+        """Ensure a list of recursive nodes can be created."""
+        mylist = [self._buildLinkedList(), self._buildLinkedList()]
+        myvec = VectorTest(lister=mylist)
+
+        serde_vec = self._deserialize(VectorTest, self._serialize(myvec))
+        golden_list = [0, 1, 2, 3, 4]
+        for cur_list in serde_vec.lister:
+            out_list = self._collapseLinkedList(cur_list)
+            self.assertEqual(golden_list, out_list)
+
 
 class NormalBinaryTest(AbstractTest):
-  protocol_factory = TBinaryProtocol.TBinaryProtocolFactory()
+    protocol_factory = TBinaryProtocol.TBinaryProtocolFactory()
+
 
 class AcceleratedBinaryTest(AbstractTest):
-  protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory()
+    protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False)
+
 
 class CompactProtocolTest(AbstractTest):
-  protocol_factory = TCompactProtocol.TCompactProtocolFactory()
+    protocol_factory = TCompactProtocol.TCompactProtocolFactory()
+
+
+class AcceleratedCompactTest(AbstractTest):
+    protocol_factory = TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False)
+
 
 class JSONProtocolTest(AbstractTest):
-  protocol_factory = TJSONProtocol.TJSONProtocolFactory()
+    protocol_factory = TJSONProtocol.TJSONProtocolFactory()
+
 
 class AcceleratedFramedTest(unittest.TestCase):
-  def testSplit(self):
-    """Test FramedTransport and BinaryProtocolAccelerated
+    def testSplit(self):
+        """Test FramedTransport and BinaryProtocolAccelerated
 
-    Tests that TBinaryProtocolAccelerated and TFramedTransport
-    play nicely together when a read spans a frame"""
+        Tests that TBinaryProtocolAccelerated and TFramedTransport
+        play nicely together when a read spans a frame"""
 
-    protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory()
-    bigstring = "".join(chr(byte) for byte in range(ord("a"), ord("z")+1))
+        protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory()
+        bigstring = "".join(chr(byte) for byte in range(ord("a"), ord("z") + 1))
 
-    databuf = TTransport.TMemoryBuffer()
-    prot = protocol_factory.getProtocol(databuf)
-    prot.writeI32(42)
-    prot.writeString(bigstring)
-    prot.writeI16(24)
-    data = databuf.getvalue()
-    cutpoint = len(data)/2
-    parts = [ data[:cutpoint], data[cutpoint:] ]
+        databuf = TTransport.TMemoryBuffer()
+        prot = protocol_factory.getProtocol(databuf)
+        prot.writeI32(42)
+        prot.writeString(bigstring)
+        prot.writeI16(24)
+        data = databuf.getvalue()
+        cutpoint = len(data) // 2
+        parts = [data[:cutpoint], data[cutpoint:]]
 
-    framed_buffer = TTransport.TMemoryBuffer()
-    framed_writer = TTransport.TFramedTransport(framed_buffer)
-    for part in parts:
-      framed_writer.write(part)
-      framed_writer.flush()
-    self.assertEquals(len(framed_buffer.getvalue()), len(data) + 8)
+        framed_buffer = TTransport.TMemoryBuffer()
+        framed_writer = TTransport.TFramedTransport(framed_buffer)
+        for part in parts:
+            framed_writer.write(part)
+            framed_writer.flush()
+        self.assertEquals(len(framed_buffer.getvalue()), len(data) + 8)
 
-    # Recreate framed_buffer so we can read from it.
-    framed_buffer = TTransport.TMemoryBuffer(framed_buffer.getvalue())
-    framed_reader = TTransport.TFramedTransport(framed_buffer)
-    prot = protocol_factory.getProtocol(framed_reader)
-    self.assertEqual(prot.readI32(), 42)
-    self.assertEqual(prot.readString(), bigstring)
-    self.assertEqual(prot.readI16(), 24)
+        # Recreate framed_buffer so we can read from it.
+        framed_buffer = TTransport.TMemoryBuffer(framed_buffer.getvalue())
+        framed_reader = TTransport.TFramedTransport(framed_buffer)
+        prot = protocol_factory.getProtocol(framed_reader)
+        self.assertEqual(prot.readI32(), 42)
+        self.assertEqual(prot.readString(), bigstring)
+        self.assertEqual(prot.readI16(), 24)
+
 
 class SerializersTest(unittest.TestCase):
 
-  def testSerializeThenDeserialize(self):
-    obj = Xtruct2(i32_thing=1,
-                  struct_thing=Xtruct(string_thing="foo"))
+    def testSerializeThenDeserialize(self):
+        obj = Xtruct2(i32_thing=1,
+                      struct_thing=Xtruct(string_thing="foo"))
 
-    s1 = serialize(obj)
-    for i in range(10):
-      self.assertEquals(s1, serialize(obj))
-      objcopy = Xtruct2()
-      deserialize(objcopy, serialize(obj))
-      self.assertEquals(obj, objcopy)
+        s1 = serialize(obj)
+        for i in range(10):
+            self.assertEquals(s1, serialize(obj))
+            objcopy = Xtruct2()
+            deserialize(objcopy, serialize(obj))
+            self.assertEquals(obj, objcopy)
 
-    obj = Xtruct(string_thing="bar")
-    objcopy = Xtruct()
-    deserialize(objcopy, serialize(obj))
-    self.assertEquals(obj, objcopy)
+        obj = Xtruct(string_thing="bar")
+        objcopy = Xtruct()
+        deserialize(objcopy, serialize(obj))
+        self.assertEquals(obj, objcopy)
 
-    # test booleans
-    obj = Bools(im_true=True, im_false=False)
-    objcopy = Bools()
-    deserialize(objcopy, serialize(obj))
-    self.assertEquals(obj, objcopy)
-    
-    # test enums
-    for num, name in Numberz._VALUES_TO_NAMES.iteritems():
-      obj = Bonk(message='enum Numberz value %d is string %s' % (num, name), type=num)
-      objcopy = Bonk()
-      deserialize(objcopy, serialize(obj))
-      self.assertEquals(obj, objcopy)
-  
+        # test booleans
+        obj = Bools(im_true=True, im_false=False)
+        objcopy = Bools()
+        deserialize(objcopy, serialize(obj))
+        self.assertEquals(obj, objcopy)
+
+        # test enums
+        for num, name in Numberz._VALUES_TO_NAMES.items():
+            obj = Bonk(message='enum Numberz value %d is string %s' % (num, name), type=num)
+            objcopy = Bonk()
+            deserialize(objcopy, serialize(obj))
+            self.assertEquals(obj, objcopy)
+
 
 def suite():
-  suite = unittest.TestSuite()
-  loader = unittest.TestLoader()
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
 
-  suite.addTest(loader.loadTestsFromTestCase(NormalBinaryTest))
-  suite.addTest(loader.loadTestsFromTestCase(AcceleratedBinaryTest))
-  suite.addTest(loader.loadTestsFromTestCase(CompactProtocolTest))
-  suite.addTest(loader.loadTestsFromTestCase(JSONProtocolTest))
-  suite.addTest(loader.loadTestsFromTestCase(AcceleratedFramedTest))
-  suite.addTest(loader.loadTestsFromTestCase(SerializersTest))
-  return suite
+    suite.addTest(loader.loadTestsFromTestCase(NormalBinaryTest))
+    suite.addTest(loader.loadTestsFromTestCase(AcceleratedBinaryTest))
+    suite.addTest(loader.loadTestsFromTestCase(AcceleratedCompactTest))
+    suite.addTest(loader.loadTestsFromTestCase(CompactProtocolTest))
+    suite.addTest(loader.loadTestsFromTestCase(JSONProtocolTest))
+    suite.addTest(loader.loadTestsFromTestCase(AcceleratedFramedTest))
+    suite.addTest(loader.loadTestsFromTestCase(SerializersTest))
+    return suite
+
 
 if __name__ == "__main__":
-  unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
+    unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
diff --git a/test/py/TSimpleJSONProtocolTest.py b/test/py/TSimpleJSONProtocolTest.py
index 080293a..7298760 100644
--- a/test/py/TSimpleJSONProtocolTest.py
+++ b/test/py/TSimpleJSONProtocolTest.py
@@ -19,17 +19,7 @@
 # under the License.
 #
 
-import sys
-import glob
-from optparse import OptionParser
-parser = OptionParser()
-parser.add_option('--genpydir', type='string', dest='genpydir', default='gen-py')
-options, args = parser.parse_args()
-del sys.argv[1:] # clean up hack so unittest doesn't complain
-sys.path.insert(0, options.genpydir)
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
-
-from ThriftTest.ttypes import *
+from ThriftTest.ttypes import Bonk, VersioningTestV1, VersioningTestV2
 from thrift.protocol import TJSONProtocol
 from thrift.transport import TTransport
 
@@ -38,82 +28,81 @@
 
 
 class SimpleJSONProtocolTest(unittest.TestCase):
-  protocol_factory = TJSONProtocol.TSimpleJSONProtocolFactory()
+    protocol_factory = TJSONProtocol.TSimpleJSONProtocolFactory()
 
-  def _assertDictEqual(self, a ,b, msg=None):
-    if hasattr(self, 'assertDictEqual'):
-      # assertDictEqual only in Python 2.7. Depends on your machine.
-      self.assertDictEqual(a, b, msg)
-      return
-    
-    # Substitute implementation not as good as unittest library's
-    self.assertEquals(len(a), len(b), msg)
-    for k, v in a.iteritems():
-      self.assertTrue(k in b, msg)
-      self.assertEquals(b.get(k), v, msg)
+    def _assertDictEqual(self, a, b, msg=None):
+        if hasattr(self, 'assertDictEqual'):
+            # assertDictEqual only in Python 2.7. Depends on your machine.
+            self.assertDictEqual(a, b, msg)
+            return
 
-  def _serialize(self, obj):
-    trans = TTransport.TMemoryBuffer()
-    prot = self.protocol_factory.getProtocol(trans)
-    obj.write(prot)
-    return trans.getvalue()
+        # Substitute implementation not as good as unittest library's
+        self.assertEquals(len(a), len(b), msg)
+        for k, v in a.iteritems():
+            self.assertTrue(k in b, msg)
+            self.assertEquals(b.get(k), v, msg)
 
-  def _deserialize(self, objtype, data):
-    prot = self.protocol_factory.getProtocol(TTransport.TMemoryBuffer(data))
-    ret = objtype()
-    ret.read(prot)
-    return ret
+    def _serialize(self, obj):
+        trans = TTransport.TMemoryBuffer()
+        prot = self.protocol_factory.getProtocol(trans)
+        obj.write(prot)
+        return trans.getvalue()
 
-  def testWriteOnly(self):
-    self.assertRaises(NotImplementedError,
-                      self._deserialize, VersioningTestV1, '{}')
+    def _deserialize(self, objtype, data):
+        prot = self.protocol_factory.getProtocol(TTransport.TMemoryBuffer(data))
+        ret = objtype()
+        ret.read(prot)
+        return ret
 
-  def testSimpleMessage(self):
-      v1obj = VersioningTestV1(
-          begin_in_both=12345,
-          old_string='aaa',
-          end_in_both=54321)
-      expected = dict(begin_in_both=v1obj.begin_in_both,
-                      old_string=v1obj.old_string,
-                      end_in_both=v1obj.end_in_both)
-      actual = json.loads(self._serialize(v1obj))
+    def testWriteOnly(self):
+        self.assertRaises(NotImplementedError,
+                          self._deserialize, VersioningTestV1, b'{}')
 
-      self._assertDictEqual(expected, actual)
-     
-  def testComplicated(self):
-      v2obj = VersioningTestV2(
-          begin_in_both=12345,
-          newint=1,
-          newbyte=2,
-          newshort=3,
-          newlong=4,
-          newdouble=5.0,
-          newstruct=Bonk(message="Hello!", type=123),
-          newlist=[7,8,9],
-          newset=set([42,1,8]),
-          newmap={1:2,2:3},
-          newstring="Hola!",
-          end_in_both=54321)
-      expected = dict(begin_in_both=v2obj.begin_in_both,
-                      newint=v2obj.newint,
-                      newbyte=v2obj.newbyte,
-                      newshort=v2obj.newshort,
-                      newlong=v2obj.newlong,
-                      newdouble=v2obj.newdouble,
-                      newstruct=dict(message=v2obj.newstruct.message,
-                                     type=v2obj.newstruct.type),
-                      newlist=v2obj.newlist,
-                      newset=list(v2obj.newset),
-                      newmap=v2obj.newmap,
-                      newstring=v2obj.newstring,
-                      end_in_both=v2obj.end_in_both)
-      
-      # Need to load/dump because map keys get escaped.
-      expected = json.loads(json.dumps(expected))
-      actual = json.loads(self._serialize(v2obj))
-      self._assertDictEqual(expected, actual)
+    def testSimpleMessage(self):
+        v1obj = VersioningTestV1(
+            begin_in_both=12345,
+            old_string='aaa',
+            end_in_both=54321)
+        expected = dict(begin_in_both=v1obj.begin_in_both,
+                        old_string=v1obj.old_string,
+                        end_in_both=v1obj.end_in_both)
+        actual = json.loads(self._serialize(v1obj).decode('ascii'))
+
+        self._assertDictEqual(expected, actual)
+
+    def testComplicated(self):
+        v2obj = VersioningTestV2(
+            begin_in_both=12345,
+            newint=1,
+            newbyte=2,
+            newshort=3,
+            newlong=4,
+            newdouble=5.0,
+            newstruct=Bonk(message="Hello!", type=123),
+            newlist=[7, 8, 9],
+            newset=set([42, 1, 8]),
+            newmap={1: 2, 2: 3},
+            newstring="Hola!",
+            end_in_both=54321)
+        expected = dict(begin_in_both=v2obj.begin_in_both,
+                        newint=v2obj.newint,
+                        newbyte=v2obj.newbyte,
+                        newshort=v2obj.newshort,
+                        newlong=v2obj.newlong,
+                        newdouble=v2obj.newdouble,
+                        newstruct=dict(message=v2obj.newstruct.message,
+                                       type=v2obj.newstruct.type),
+                        newlist=v2obj.newlist,
+                        newset=list(v2obj.newset),
+                        newmap=v2obj.newmap,
+                        newstring=v2obj.newstring,
+                        end_in_both=v2obj.end_in_both)
+
+        # Need to load/dump because map keys get escaped.
+        expected = json.loads(json.dumps(expected))
+        actual = json.loads(self._serialize(v2obj).decode('ascii'))
+        self._assertDictEqual(expected, actual)
 
 
 if __name__ == '__main__':
-  unittest.main()
-
+    unittest.main()
diff --git a/test/py/TestClient.py b/test/py/TestClient.py
index 471e030..ddcce8d 100755
--- a/test/py/TestClient.py
+++ b/test/py/TestClient.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-
+# -*- coding: utf-8 -*-
 #
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements. See the NOTICE file
@@ -19,224 +19,428 @@
 # under the License.
 #
 
-import sys, glob, os
-sys.path.insert(0, glob.glob(os.path.join(os.path.dirname(__file__),'../../lib/py/build/lib.*'))[0])
-
-import unittest
+import os
+import sys
 import time
+import unittest
 from optparse import OptionParser
 
-parser = OptionParser()
-parser.add_option('--genpydir', type='string', dest='genpydir',
-                  default='gen-py',
-                  help='include this local directory in sys.path for locating generated code')
-parser.add_option("--port", type="int", dest="port",
-    help="connect to server at port")
-parser.add_option("--host", type="string", dest="host",
-    help="connect to server")
-parser.add_option("--zlib", action="store_true", dest="zlib",
-    help="use zlib wrapper for compressed transport")
-parser.add_option("--ssl", action="store_true", dest="ssl",
-    help="use SSL for encrypted transport")
-parser.add_option("--framed", action="store_true", dest="framed",
-    help="use framed transport")
-parser.add_option("--http", dest="http_path",
-    help="Use the HTTP transport with the specified path")
-parser.add_option('-v', '--verbose', action="store_const", 
-    dest="verbose", const=2,
-    help="verbose output")
-parser.add_option('-q', '--quiet', action="store_const", 
-    dest="verbose", const=0,
-    help="minimal output")
-parser.add_option('--proto',  dest="proto", type="string",
-    help="protocol to use, one of: accel, binary, compact")
-parser.set_defaults(framed=False, http_path=None, verbose=1, host='localhost', port=9090, proto='binary')
-options, args = parser.parse_args()
+from util import local_libpath
 
-sys.path.insert(0, options.genpydir)
+SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
 
-from ThriftTest import ThriftTest
-from ThriftTest.ttypes import *
-from thrift.transport import TTransport
-from thrift.transport import TSocket
-from thrift.transport import THttpClient
-from thrift.transport import TZlibTransport
-from thrift.protocol import TBinaryProtocol
-from thrift.protocol import TCompactProtocol
-from thrift.protocol import TJSONProtocol
 
 class AbstractTest(unittest.TestCase):
-  def setUp(self):
-    if options.http_path:
-      self.transport = THttpClient.THttpClient(options.host, port=options.port, path=options.http_path)
-    else:
-      if options.ssl:
-        from thrift.transport import TSSLSocket
-        socket = TSSLSocket.TSSLSocket(options.host, options.port, validate=False)
-      else:
-        socket = TSocket.TSocket(options.host, options.port)
-      # frame or buffer depending upon args
-      if options.framed:
-        self.transport = TTransport.TFramedTransport(socket)
-      else:
-        self.transport = TTransport.TBufferedTransport(socket)
-      if options.zlib:
-        self.transport = TZlibTransport.TZlibTransport(self.transport, 9)
-    self.transport.open()
-    protocol = self.protocol_factory.getProtocol(self.transport)
-    self.client = ThriftTest.Client(protocol)
+    def setUp(self):
+        if options.trans == 'http':
+            uri = '{0}://{1}:{2}{3}'.format(('https' if options.ssl else 'http'),
+                                            options.host,
+                                            options.port,
+                                            (options.http_path if options.http_path else '/'))
+            if options.ssl:
+                __cafile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "CA.pem")
+                __certfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "client.crt")
+                __keyfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "client.key")
+                self.transport = THttpClient.THttpClient(uri, cafile=__cafile, cert_file=__certfile, key_file=__keyfile)
+            else:
+                self.transport = THttpClient.THttpClient(uri)
+        else:
+            if options.ssl:
+                from thrift.transport import TSSLSocket
+                socket = TSSLSocket.TSSLSocket(options.host, options.port, validate=False)
+            else:
+                socket = TSocket.TSocket(options.host, options.port)
+            # frame or buffer depending upon args
+            self.transport = TTransport.TBufferedTransport(socket)
+            if options.trans == 'framed':
+                self.transport = TTransport.TFramedTransport(socket)
+            elif options.trans == 'buffered':
+                self.transport = TTransport.TBufferedTransport(socket)
+            elif options.trans == '':
+                raise AssertionError('Unknown --transport option: %s' % options.trans)
+            if options.zlib:
+                self.transport = TZlibTransport.TZlibTransport(self.transport, 9)
+        self.transport.open()
+        protocol = self.get_protocol(self.transport)
+        self.client = ThriftTest.Client(protocol)
+        # for multiplexed services:
+        protocol2 = self.get_protocol2(self.transport)
+        self.client2 = SecondService.Client(protocol2) if protocol2 is not None else None
 
-  def tearDown(self):
-    # Close!
-    self.transport.close()
+    def tearDown(self):
+        self.transport.close()
 
-  def testVoid(self):
-    self.client.testVoid()
+    def testVoid(self):
+        print('testVoid')
+        self.client.testVoid()
 
-  def testString(self):
-    self.assertEqual(self.client.testString('Python' * 20), 'Python' * 20)
-    self.assertEqual(self.client.testString(''), '')
+    def testString(self):
+        print('testString')
+        self.assertEqual(self.client.testString('Python' * 20), 'Python' * 20)
+        self.assertEqual(self.client.testString(''), '')
+        s1 = u'\b\t\n/\\\\\r{}:パイソン"'
+        s2 = u"""Afrikaans, Alemannisch, Aragonés, العربية, مصرى,
+        Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška,
+        Беларуская, Беларуская (тарашкевіца), Български, Bamanankan,
+        বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн,
+        Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg,
+        Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English,
+        Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt,
+        Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego,
+        Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski,
+        Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia,
+        Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa,
+        ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар,
+        Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino,
+        Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa
+        Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa
+        Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪
+        Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad,
+        Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو,
+        Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română,
+        Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple
+        English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk,
+        Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog,
+        Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük,
+        Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文,
+        Bân-lâm-gú, 粵語"""
+        if sys.version_info[0] == 2 and os.environ.get('THRIFT_TEST_PY_NO_UTF8STRINGS'):
+            s1 = s1.encode('utf8')
+            s2 = s2.encode('utf8')
+        self.assertEqual(self.client.testString(s1), s1)
+        self.assertEqual(self.client.testString(s2), s2)
 
-  def testByte(self):
-    self.assertEqual(self.client.testByte(63), 63)
-    self.assertEqual(self.client.testByte(-127), -127)
+    def testMultiplexed(self):
+        if self.client2 is not None:
+            print('testMultiplexed')
+            self.assertEqual(self.client2.secondtestString('foobar'), 'testString("foobar")')
 
-  def testI32(self):
-    self.assertEqual(self.client.testI32(-1), -1)
-    self.assertEqual(self.client.testI32(0), 0)
+    def testBool(self):
+        print('testBool')
+        self.assertEqual(self.client.testBool(True), True)
+        self.assertEqual(self.client.testBool(False), False)
 
-  def testI64(self):
-    self.assertEqual(self.client.testI64(1), 1)
-    self.assertEqual(self.client.testI64(-34359738368), -34359738368)
+    def testByte(self):
+        print('testByte')
+        self.assertEqual(self.client.testByte(63), 63)
+        self.assertEqual(self.client.testByte(-127), -127)
 
-  def testDouble(self):
-    self.assertEqual(self.client.testDouble(-5.235098235), -5.235098235)
-    self.assertEqual(self.client.testDouble(0), 0)
-    self.assertEqual(self.client.testDouble(-1), -1)
+    def testI32(self):
+        print('testI32')
+        self.assertEqual(self.client.testI32(-1), -1)
+        self.assertEqual(self.client.testI32(0), 0)
 
-  def testStruct(self):
-    x = Xtruct()
-    x.string_thing = "Zero"
-    x.byte_thing = 1
-    x.i32_thing = -3
-    x.i64_thing = -5
-    y = self.client.testStruct(x)
-    self.assertEqual(y, x)
+    def testI64(self):
+        print('testI64')
+        self.assertEqual(self.client.testI64(1), 1)
+        self.assertEqual(self.client.testI64(-34359738368), -34359738368)
 
-  def testNest(self):
-    inner = Xtruct(string_thing="Zero", byte_thing=1, i32_thing=-3,
-      i64_thing=-5)
-    x = Xtruct2(struct_thing=inner, byte_thing=0, i32_thing=0)
-    y = self.client.testNest(x)
-    self.assertEqual(y, x)
+    def testDouble(self):
+        print('testDouble')
+        self.assertEqual(self.client.testDouble(-5.235098235), -5.235098235)
+        self.assertEqual(self.client.testDouble(0), 0)
+        self.assertEqual(self.client.testDouble(-1), -1)
+        self.assertEqual(self.client.testDouble(-0.000341012439638598279), -0.000341012439638598279)
 
-  def testMap(self):
-    x = {0:1, 1:2, 2:3, 3:4, -1:-2}
-    y = self.client.testMap(x)
-    self.assertEqual(y, x)
+    def testBinary(self):
+        print('testBinary')
+        val = bytearray([i for i in range(0, 256)])
+        self.assertEqual(bytearray(self.client.testBinary(bytes(val))), val)
 
-  def testSet(self):
-    x = set([8, 1, 42])
-    y = self.client.testSet(x)
-    self.assertEqual(y, x)
+    def testStruct(self):
+        print('testStruct')
+        x = Xtruct()
+        x.string_thing = "Zero"
+        x.byte_thing = 1
+        x.i32_thing = -3
+        x.i64_thing = -5
+        y = self.client.testStruct(x)
+        self.assertEqual(y, x)
 
-  def testList(self):
-    x = [1, 4, 9, -42]
-    y = self.client.testList(x)
-    self.assertEqual(y, x)
+    def testNest(self):
+        print('testNest')
+        inner = Xtruct(string_thing="Zero", byte_thing=1, i32_thing=-3, i64_thing=-5)
+        x = Xtruct2(struct_thing=inner, byte_thing=0, i32_thing=0)
+        y = self.client.testNest(x)
+        self.assertEqual(y, x)
 
-  def testEnum(self):
-    x = Numberz.FIVE
-    y = self.client.testEnum(x)
-    self.assertEqual(y, x)
+    def testMap(self):
+        print('testMap')
+        x = {0: 1, 1: 2, 2: 3, 3: 4, -1: -2}
+        y = self.client.testMap(x)
+        self.assertEqual(y, x)
 
-  def testTypedef(self):
-    x = 0xffffffffffffff # 7 bytes of 0xff
-    y = self.client.testTypedef(x)
-    self.assertEqual(y, x)
+    def testSet(self):
+        print('testSet')
+        x = set([8, 1, 42])
+        y = self.client.testSet(x)
+        self.assertEqual(y, x)
 
-  def testMapMap(self):
-    # does not work: dict() is not a hashable type, so a dict() cannot be used as a key in another dict()
-    #x = { {1:10, 2:20}, {1:100, 2:200, 3:300}, {1:1000, 2:2000, 3:3000, 4:4000} }
-    try:
-      y = self.client.testMapMap()
-    except:
-      pass
+    def testList(self):
+        print('testList')
+        x = [1, 4, 9, -42]
+        y = self.client.testList(x)
+        self.assertEqual(y, x)
 
-  def testMulti(self):
-    xpected = Xtruct(string_thing='Hello2', byte_thing=74, i32_thing=0xff00ff, i64_thing=0xffffffffd0d0)
-    y = self.client.testMulti(xpected.byte_thing,
-          xpected.i32_thing,
-          xpected.i64_thing,
-          { 0:'abc' },
-          Numberz.FIVE,
-          0xf0f0f0)  
-    self.assertEqual(y, xpected)
+    def testEnum(self):
+        print('testEnum')
+        x = Numberz.FIVE
+        y = self.client.testEnum(x)
+        self.assertEqual(y, x)
 
-  def testException(self):
-    self.client.testException('Safe')
-    try:
-      self.client.testException('Xception')
-      self.fail("should have gotten exception")
-    except Xception, x:
-      self.assertEqual(x.errorCode, 1001)
-      self.assertEqual(x.message, 'Xception')
-      # TODO ensure same behavior for repr within generated python variants
-      # ensure exception's repr method works
-      #x_repr = repr(x)
-      #self.assertEqual(x_repr, 'Xception(errorCode=1001, message=\'Xception\')')
+    def testTypedef(self):
+        print('testTypedef')
+        x = 0xffffffffffffff  # 7 bytes of 0xff
+        y = self.client.testTypedef(x)
+        self.assertEqual(y, x)
 
-    try:
-      self.client.testException("throw_undeclared")
-      self.fail("should have thrown exception")
-    except Exception: # type is undefined
-      pass
+    def testMapMap(self):
+        print('testMapMap')
+        x = {
+            -4: {-4: -4, -3: -3, -2: -2, -1: -1},
+            4: {4: 4, 3: 3, 2: 2, 1: 1},
+        }
+        y = self.client.testMapMap(42)
+        self.assertEqual(y, x)
 
-  def testOneway(self):
-    start = time.time()
-    self.client.testOneway(1) # type is int, not float
-    end = time.time()
-    self.assertTrue(end - start < 3,
-                    "oneway sleep took %f sec" % (end - start))
-  
-  def testOnewayThenNormal(self):
-    self.client.testOneway(1) # type is int, not float
-    self.assertEqual(self.client.testString('Python'), 'Python')
+    def testMulti(self):
+        print('testMulti')
+        xpected = Xtruct(string_thing='Hello2', byte_thing=74, i32_thing=0xff00ff, i64_thing=0xffffffffd0d0)
+        y = self.client.testMulti(xpected.byte_thing,
+                                  xpected.i32_thing,
+                                  xpected.i64_thing,
+                                  {0: 'abc'},
+                                  Numberz.FIVE,
+                                  0xf0f0f0)
+        self.assertEqual(y, xpected)
 
-class NormalBinaryTest(AbstractTest):
-  protocol_factory = TBinaryProtocol.TBinaryProtocolFactory()
+    def testException(self):
+        print('testException')
+        self.client.testException('Safe')
+        try:
+            self.client.testException('Xception')
+            self.fail("should have gotten exception")
+        except Xception as x:
+            self.assertEqual(x.errorCode, 1001)
+            self.assertEqual(x.message, 'Xception')
+            # TODO ensure same behavior for repr within generated python variants
+            # ensure exception's repr method works
+            # x_repr = repr(x)
+            # self.assertEqual(x_repr, 'Xception(errorCode=1001, message=\'Xception\')')
 
-class CompactTest(AbstractTest):
-  protocol_factory = TCompactProtocol.TCompactProtocolFactory()
+        try:
+            self.client.testException('TException')
+            self.fail("should have gotten exception")
+        except TException as x:
+            pass
 
-class JSONTest(AbstractTest):
-  protocol_factory = TJSONProtocol.TJSONProtocolFactory()
+        # Should not throw
+        self.client.testException('success')
 
-class AcceleratedBinaryTest(AbstractTest):
-  protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory()
+    def testMultiException(self):
+        print('testMultiException')
+        try:
+            self.client.testMultiException('Xception', 'ignore')
+        except Xception as ex:
+            self.assertEqual(ex.errorCode, 1001)
+            self.assertEqual(ex.message, 'This is an Xception')
+
+        try:
+            self.client.testMultiException('Xception2', 'ignore')
+        except Xception2 as ex:
+            self.assertEqual(ex.errorCode, 2002)
+            self.assertEqual(ex.struct_thing.string_thing, 'This is an Xception2')
+
+        y = self.client.testMultiException('success', 'foobar')
+        self.assertEqual(y.string_thing, 'foobar')
+
+    def testOneway(self):
+        print('testOneway')
+        start = time.time()
+        self.client.testOneway(1)  # type is int, not float
+        end = time.time()
+        self.assertTrue(end - start < 3,
+                        "oneway sleep took %f sec" % (end - start))
+
+    def testOnewayThenNormal(self):
+        print('testOnewayThenNormal')
+        self.client.testOneway(1)  # type is int, not float
+        self.assertEqual(self.client.testString('Python'), 'Python')
+
+
+class MultiplexedOptionalTest(AbstractTest):
+    def get_protocol2(self, transport):
+        return None
+
+
+class BinaryTest(MultiplexedOptionalTest):
+    def get_protocol(self, transport):
+        return TBinaryProtocol.TBinaryProtocolFactory().getProtocol(transport)
+
+
+class MultiplexedBinaryTest(MultiplexedOptionalTest):
+    def get_protocol(self, transport):
+        wrapped_proto = TBinaryProtocol.TBinaryProtocolFactory().getProtocol(transport)
+        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "ThriftTest")
+
+    def get_protocol2(self, transport):
+        wrapped_proto = TBinaryProtocol.TBinaryProtocolFactory().getProtocol(transport)
+        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "SecondService")
+
+
+class AcceleratedBinaryTest(MultiplexedOptionalTest):
+    def get_protocol(self, transport):
+        return TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False).getProtocol(transport)
+
+
+class MultiplexedAcceleratedBinaryTest(MultiplexedOptionalTest):
+    def get_protocol(self, transport):
+        wrapped_proto = TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False).getProtocol(transport)
+        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "ThriftTest")
+
+    def get_protocol2(self, transport):
+        wrapped_proto = TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False).getProtocol(transport)
+        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "SecondService")
+
+
+class CompactTest(MultiplexedOptionalTest):
+    def get_protocol(self, transport):
+        return TCompactProtocol.TCompactProtocolFactory().getProtocol(transport)
+
+
+class MultiplexedCompactTest(MultiplexedOptionalTest):
+    def get_protocol(self, transport):
+        wrapped_proto = TCompactProtocol.TCompactProtocolFactory().getProtocol(transport)
+        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "ThriftTest")
+
+    def get_protocol2(self, transport):
+        wrapped_proto = TCompactProtocol.TCompactProtocolFactory().getProtocol(transport)
+        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "SecondService")
+
+
+class AcceleratedCompactTest(MultiplexedOptionalTest):
+    def get_protocol(self, transport):
+        return TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False).getProtocol(transport)
+
+
+class MultiplexedAcceleratedCompactTest(MultiplexedOptionalTest):
+    def get_protocol(self, transport):
+        wrapped_proto = TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False).getProtocol(transport)
+        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "ThriftTest")
+
+    def get_protocol2(self, transport):
+        wrapped_proto = TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False).getProtocol(transport)
+        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "SecondService")
+
+
+class JSONTest(MultiplexedOptionalTest):
+    def get_protocol(self, transport):
+        return TJSONProtocol.TJSONProtocolFactory().getProtocol(transport)
+
+
+class MultiplexedJSONTest(MultiplexedOptionalTest):
+    def get_protocol(self, transport):
+        wrapped_proto = TJSONProtocol.TJSONProtocolFactory().getProtocol(transport)
+        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "ThriftTest")
+
+    def get_protocol2(self, transport):
+        wrapped_proto = TJSONProtocol.TJSONProtocolFactory().getProtocol(transport)
+        return TMultiplexedProtocol.TMultiplexedProtocol(wrapped_proto, "SecondService")
+
+
+class HeaderTest(MultiplexedOptionalTest):
+    def get_protocol(self, transport):
+        factory = THeaderProtocol.THeaderProtocolFactory()
+        return factory.getProtocol(transport)
+
 
 def suite():
-  suite = unittest.TestSuite()
-  loader = unittest.TestLoader()
-  if options.proto == 'binary': # look for --proto on cmdline
-    suite.addTest(loader.loadTestsFromTestCase(NormalBinaryTest))
-  elif options.proto == 'accel':
-    suite.addTest(loader.loadTestsFromTestCase(AcceleratedBinaryTest))
-  elif options.proto == 'compact':
-    suite.addTest(loader.loadTestsFromTestCase(CompactTest))
-  elif options.proto == 'json':
-    suite.addTest(loader.loadTestsFromTestCase(JSONTest))
-  else:
-    raise AssertionError('Unknown protocol given with --proto: %s' % options.proto)
-  return suite
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
+    if options.proto == 'binary':  # look for --proto on cmdline
+        suite.addTest(loader.loadTestsFromTestCase(BinaryTest))
+    elif options.proto == 'accel':
+        suite.addTest(loader.loadTestsFromTestCase(AcceleratedBinaryTest))
+    elif options.proto == 'accelc':
+        suite.addTest(loader.loadTestsFromTestCase(AcceleratedCompactTest))
+    elif options.proto == 'compact':
+        suite.addTest(loader.loadTestsFromTestCase(CompactTest))
+    elif options.proto == 'header':
+        suite.addTest(loader.loadTestsFromTestCase(HeaderTest))
+    elif options.proto == 'json':
+        suite.addTest(loader.loadTestsFromTestCase(JSONTest))
+    elif options.proto == 'multi':
+        suite.addTest(loader.loadTestsFromTestCase(MultiplexedBinaryTest))
+    elif options.proto == 'multia':
+        suite.addTest(loader.loadTestsFromTestCase(MultiplexedAcceleratedBinaryTest))
+    elif options.proto == 'multiac':
+        suite.addTest(loader.loadTestsFromTestCase(MultiplexedAcceleratedCompactTest))
+    elif options.proto == 'multic':
+        suite.addTest(loader.loadTestsFromTestCase(MultiplexedCompactTest))
+    elif options.proto == 'multij':
+        suite.addTest(loader.loadTestsFromTestCase(MultiplexedJSONTest))
+    else:
+        raise AssertionError('Unknown protocol given with --protocol: %s' % options.proto)
+    return suite
+
 
 class OwnArgsTestProgram(unittest.TestProgram):
     def parseArgs(self, argv):
         if args:
             self.testNames = args
         else:
-            self.testNames = (self.defaultTest,)
+            self.testNames = ([self.defaultTest])
         self.createTests()
 
+
 if __name__ == "__main__":
-  OwnArgsTestProgram(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=1))
+    parser = OptionParser()
+    parser.add_option('--libpydir', type='string', dest='libpydir',
+                      help='include this directory in sys.path for locating library code')
+    parser.add_option('--genpydir', type='string', dest='genpydir',
+                      help='include this directory in sys.path for locating generated code')
+    parser.add_option("--port", type="int", dest="port",
+                      help="connect to server at port")
+    parser.add_option("--host", type="string", dest="host",
+                      help="connect to server")
+    parser.add_option("--zlib", action="store_true", dest="zlib",
+                      help="use zlib wrapper for compressed transport")
+    parser.add_option("--ssl", action="store_true", dest="ssl",
+                      help="use SSL for encrypted transport")
+    parser.add_option("--http", dest="http_path",
+                      help="Use the HTTP transport with the specified path")
+    parser.add_option('-v', '--verbose', action="store_const",
+                      dest="verbose", const=2,
+                      help="verbose output")
+    parser.add_option('-q', '--quiet', action="store_const",
+                      dest="verbose", const=0,
+                      help="minimal output")
+    parser.add_option('--protocol', dest="proto", type="string",
+                      help="protocol to use, one of: accel, accelc, binary, compact, header, json, multi, multia, multiac, multic, multij")
+    parser.add_option('--transport', dest="trans", type="string",
+                      help="transport to use, one of: buffered, framed, http")
+    parser.set_defaults(framed=False, http_path=None, verbose=1, host='localhost', port=9090, proto='binary')
+    options, args = parser.parse_args()
+
+    if options.genpydir:
+        sys.path.insert(0, os.path.join(SCRIPT_DIR, options.genpydir))
+    sys.path.insert(0, local_libpath())
+
+    if options.http_path:
+        options.trans = 'http'
+
+    from ThriftTest import SecondService
+    from ThriftTest import ThriftTest
+    from ThriftTest.ttypes import Xtruct, Xtruct2, Numberz, Xception, Xception2
+    from thrift.Thrift import TException
+    from thrift.transport import TTransport
+    from thrift.transport import TSocket
+    from thrift.transport import THttpClient
+    from thrift.transport import TZlibTransport
+    from thrift.protocol import TBinaryProtocol
+    from thrift.protocol import TCompactProtocol
+    from thrift.protocol import THeaderProtocol
+    from thrift.protocol import TJSONProtocol
+    from thrift.protocol import TMultiplexedProtocol
+
+    OwnArgsTestProgram(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=1))
diff --git a/test/py/TestEof.py b/test/py/TestEof.py
index a9d81f1..0b4a829 100755
--- a/test/py/TestEof.py
+++ b/test/py/TestEof.py
@@ -19,118 +19,114 @@
 # under the License.
 #
 
-import sys, glob
-from optparse import OptionParser
-parser = OptionParser()
-parser.add_option('--genpydir', type='string', dest='genpydir', default='gen-py')
-options, args = parser.parse_args()
-del sys.argv[1:] # clean up hack so unittest doesn't complain
-sys.path.insert(0, options.genpydir)
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
-
-from ThriftTest import ThriftTest
-from ThriftTest.ttypes import *
+from ThriftTest.ttypes import Xtruct
 from thrift.transport import TTransport
-from thrift.transport import TSocket
 from thrift.protocol import TBinaryProtocol
 from thrift.protocol import TCompactProtocol
 import unittest
-import time
+
 
 class TestEof(unittest.TestCase):
 
-  def make_data(self, pfactory=None):
-    trans = TTransport.TMemoryBuffer()
-    if pfactory:
-      prot = pfactory.getProtocol(trans)
-    else:
-      prot = TBinaryProtocol.TBinaryProtocol(trans)
+    def make_data(self, pfactory=None):
+        trans = TTransport.TMemoryBuffer()
+        if pfactory:
+            prot = pfactory.getProtocol(trans)
+        else:
+            prot = TBinaryProtocol.TBinaryProtocol(trans)
 
-    x = Xtruct()
-    x.string_thing = "Zero"
-    x.byte_thing = 0
+        x = Xtruct()
+        x.string_thing = "Zero"
+        x.byte_thing = 0
 
-    x.write(prot)
+        x.write(prot)
 
-    x = Xtruct()
-    x.string_thing = "One"
-    x.byte_thing = 1
+        x = Xtruct()
+        x.string_thing = "One"
+        x.byte_thing = 1
 
-    x.write(prot)
+        x.write(prot)
 
-    return trans.getvalue()
+        return trans.getvalue()
 
-  def testTransportReadAll(self):
-    """Test that readAll on any type of transport throws an EOFError"""
-    trans = TTransport.TMemoryBuffer(self.make_data())
-    trans.readAll(1)
+    def testTransportReadAll(self):
+        """Test that readAll on any type of transport throws an EOFError"""
+        trans = TTransport.TMemoryBuffer(self.make_data())
+        trans.readAll(1)
 
-    try:
-      trans.readAll(10000)
-    except EOFError:
-      return
+        try:
+            trans.readAll(10000)
+        except EOFError:
+            return
 
-    self.fail("Should have gotten EOFError")
+        self.fail("Should have gotten EOFError")
 
-  def eofTestHelper(self, pfactory):
-    trans = TTransport.TMemoryBuffer(self.make_data(pfactory))
-    prot = pfactory.getProtocol(trans)
+    def eofTestHelper(self, pfactory):
+        trans = TTransport.TMemoryBuffer(self.make_data(pfactory))
+        prot = pfactory.getProtocol(trans)
 
-    x = Xtruct()
-    x.read(prot)
-    self.assertEqual(x.string_thing, "Zero")
-    self.assertEqual(x.byte_thing, 0)
-
-    x = Xtruct()
-    x.read(prot)
-    self.assertEqual(x.string_thing, "One")
-    self.assertEqual(x.byte_thing, 1)
-
-    try:
-      x = Xtruct()
-      x.read(prot)
-    except EOFError:
-      return
-
-    self.fail("Should have gotten EOFError")
-
-  def eofTestHelperStress(self, pfactory):
-    """Teest the ability of TBinaryProtocol to deal with the removal of every byte in the file"""
-    # TODO: we should make sure this covers more of the code paths
-
-    data = self.make_data(pfactory)
-    for i in xrange(0, len(data) + 1):
-      trans = TTransport.TMemoryBuffer(data[0:i])
-      prot = pfactory.getProtocol(trans)
-      try:
         x = Xtruct()
         x.read(prot)
+        self.assertEqual(x.string_thing, "Zero")
+        self.assertEqual(x.byte_thing, 0)
+
+        x = Xtruct()
         x.read(prot)
-        x.read(prot)
-      except EOFError:
-        continue
-      self.fail("Should have gotten an EOFError")
+        self.assertEqual(x.string_thing, "One")
+        self.assertEqual(x.byte_thing, 1)
 
-  def testBinaryProtocolEof(self):
-    """Test that TBinaryProtocol throws an EOFError when it reaches the end of the stream"""
-    self.eofTestHelper(TBinaryProtocol.TBinaryProtocolFactory())
-    self.eofTestHelperStress(TBinaryProtocol.TBinaryProtocolFactory())
+        try:
+            x = Xtruct()
+            x.read(prot)
+        except EOFError:
+            return
 
-  def testBinaryProtocolAcceleratedEof(self):
-    """Test that TBinaryProtocolAccelerated throws an EOFError when it reaches the end of the stream"""
-    self.eofTestHelper(TBinaryProtocol.TBinaryProtocolAcceleratedFactory())
-    self.eofTestHelperStress(TBinaryProtocol.TBinaryProtocolAcceleratedFactory())
+        self.fail("Should have gotten EOFError")
 
-  def testCompactProtocolEof(self):
-    """Test that TCompactProtocol throws an EOFError when it reaches the end of the stream"""
-    self.eofTestHelper(TCompactProtocol.TCompactProtocolFactory())
-    self.eofTestHelperStress(TCompactProtocol.TCompactProtocolFactory())
+    def eofTestHelperStress(self, pfactory):
+        """Test the ability of TBinaryProtocol to deal with the removal of every byte in the file"""
+        # TODO: we should make sure this covers more of the code paths
+
+        data = self.make_data(pfactory)
+        for i in range(0, len(data) + 1):
+            trans = TTransport.TMemoryBuffer(data[0:i])
+            prot = pfactory.getProtocol(trans)
+            try:
+                x = Xtruct()
+                x.read(prot)
+                x.read(prot)
+                x.read(prot)
+            except EOFError:
+                continue
+            self.fail("Should have gotten an EOFError")
+
+    def testBinaryProtocolEof(self):
+        """Test that TBinaryProtocol throws an EOFError when it reaches the end of the stream"""
+        self.eofTestHelper(TBinaryProtocol.TBinaryProtocolFactory())
+        self.eofTestHelperStress(TBinaryProtocol.TBinaryProtocolFactory())
+
+    def testBinaryProtocolAcceleratedBinaryEof(self):
+        """Test that TBinaryProtocolAccelerated throws an EOFError when it reaches the end of the stream"""
+        self.eofTestHelper(TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False))
+        self.eofTestHelperStress(TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False))
+
+    def testCompactProtocolEof(self):
+        """Test that TCompactProtocol throws an EOFError when it reaches the end of the stream"""
+        self.eofTestHelper(TCompactProtocol.TCompactProtocolFactory())
+        self.eofTestHelperStress(TCompactProtocol.TCompactProtocolFactory())
+
+    def testCompactProtocolAcceleratedCompactEof(self):
+        """Test that TCompactProtocolAccelerated throws an EOFError when it reaches the end of the stream"""
+        self.eofTestHelper(TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False))
+        self.eofTestHelperStress(TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False))
+
 
 def suite():
-  suite = unittest.TestSuite()
-  loader = unittest.TestLoader()
-  suite.addTest(loader.loadTestsFromTestCase(TestEof))
-  return suite
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
+    suite.addTest(loader.loadTestsFromTestCase(TestEof))
+    return suite
+
 
 if __name__ == "__main__":
-  unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
+    unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
diff --git a/test/py/TestFrozen.py b/test/py/TestFrozen.py
new file mode 100755
index 0000000..6d2595c
--- /dev/null
+++ b/test/py/TestFrozen.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+
+#
+# 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.
+#
+
+from DebugProtoTest.ttypes import CompactProtoTestStruct, Empty, Wrapper
+from thrift.Thrift import TFrozenDict
+from thrift.transport import TTransport
+from thrift.protocol import TBinaryProtocol, TCompactProtocol
+import collections
+import unittest
+
+
+class TestFrozenBase(unittest.TestCase):
+    def _roundtrip(self, src, dst):
+        otrans = TTransport.TMemoryBuffer()
+        optoro = self.protocol(otrans)
+        src.write(optoro)
+        itrans = TTransport.TMemoryBuffer(otrans.getvalue())
+        iproto = self.protocol(itrans)
+        return dst.read(iproto) or dst
+
+    def test_dict_is_hashable_only_after_frozen(self):
+        d0 = {}
+        self.assertFalse(isinstance(d0, collections.Hashable))
+        d1 = TFrozenDict(d0)
+        self.assertTrue(isinstance(d1, collections.Hashable))
+
+    def test_struct_with_collection_fields(self):
+        pass
+
+    def test_set(self):
+        """Test that annotated set field can be serialized and deserialized"""
+        x = CompactProtoTestStruct(set_byte_map={
+            frozenset([42, 100, -100]): 99,
+            frozenset([0]): 100,
+            frozenset([]): 0,
+        })
+        x2 = self._roundtrip(x, CompactProtoTestStruct())
+        self.assertEqual(x2.set_byte_map[frozenset([42, 100, -100])], 99)
+        self.assertEqual(x2.set_byte_map[frozenset([0])], 100)
+        self.assertEqual(x2.set_byte_map[frozenset([])], 0)
+
+    def test_map(self):
+        """Test that annotated map field can be serialized and deserialized"""
+        x = CompactProtoTestStruct(map_byte_map={
+            TFrozenDict({42: 42, 100: -100}): 99,
+            TFrozenDict({0: 0}): 100,
+            TFrozenDict({}): 0,
+        })
+        x2 = self._roundtrip(x, CompactProtoTestStruct())
+        self.assertEqual(x2.map_byte_map[TFrozenDict({42: 42, 100: -100})], 99)
+        self.assertEqual(x2.map_byte_map[TFrozenDict({0: 0})], 100)
+        self.assertEqual(x2.map_byte_map[TFrozenDict({})], 0)
+
+    def test_list(self):
+        """Test that annotated list field can be serialized and deserialized"""
+        x = CompactProtoTestStruct(list_byte_map={
+            (42, 100, -100): 99,
+            (0,): 100,
+            (): 0,
+        })
+        x2 = self._roundtrip(x, CompactProtoTestStruct())
+        self.assertEqual(x2.list_byte_map[(42, 100, -100)], 99)
+        self.assertEqual(x2.list_byte_map[(0,)], 100)
+        self.assertEqual(x2.list_byte_map[()], 0)
+
+    def test_empty_struct(self):
+        """Test that annotated empty struct can be serialized and deserialized"""
+        x = CompactProtoTestStruct(empty_struct_field=Empty())
+        x2 = self._roundtrip(x, CompactProtoTestStruct())
+        self.assertEqual(x2.empty_struct_field, Empty())
+
+    def test_struct(self):
+        """Test that annotated struct can be serialized and deserialized"""
+        x = Wrapper(foo=Empty())
+        self.assertEqual(x.foo, Empty())
+        x2 = self._roundtrip(x, Wrapper)
+        self.assertEqual(x2.foo, Empty())
+
+
+class TestFrozen(TestFrozenBase):
+    def protocol(self, trans):
+        return TBinaryProtocol.TBinaryProtocolFactory().getProtocol(trans)
+
+
+class TestFrozenAcceleratedBinary(TestFrozenBase):
+    def protocol(self, trans):
+        return TBinaryProtocol.TBinaryProtocolAcceleratedFactory(fallback=False).getProtocol(trans)
+
+
+class TestFrozenAcceleratedCompact(TestFrozenBase):
+    def protocol(self, trans):
+        return TCompactProtocol.TCompactProtocolAcceleratedFactory(fallback=False).getProtocol(trans)
+
+
+def suite():
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
+    suite.addTest(loader.loadTestsFromTestCase(TestFrozen))
+    suite.addTest(loader.loadTestsFromTestCase(TestFrozenAcceleratedBinary))
+    suite.addTest(loader.loadTestsFromTestCase(TestFrozenAcceleratedCompact))
+    return suite
+
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
diff --git a/test/py/TestRenderedDoubleConstants.py b/test/py/TestRenderedDoubleConstants.py
new file mode 100644
index 0000000..20903d8
--- /dev/null
+++ b/test/py/TestRenderedDoubleConstants.py
@@ -0,0 +1,177 @@
+#
+# 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 unittest
+
+from DoubleConstantsTest import constants
+
+#
+# In order to run the test under Windows. We need to create symbolic link
+# name 'thrift' to '../src' folder by using:
+#
+# mklink /D thrift ..\src
+#
+
+
+class TestRenderedDoubleConstants(unittest.TestCase):
+    ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST = \
+        "failed to verify a double constant generated by Thrift (expected = %f, got = %f)"
+    ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_LIST_TEST =\
+        "failed to verify a list item by Thrift (expected = %f, got = %f)"
+    ASSERTION_MESSAGE_FOR_TYPE_CHECKS = "the rendered variable with name %s is not of double type"
+
+    # to make sure the variables inside Thrift files are generated correctly
+    def test_rendered_double_constants(self):
+        EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT = 1.0
+        EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT = -100.0
+        EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT = 9223372036854775807.0
+        EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT = -9223372036854775807.0
+        EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS = 3.14159265359
+        EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE = 1000000.1
+        EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE = -1000000.1
+        EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE = 1.7e+308
+        EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE = 9223372036854775816.43
+        EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE = -1.7e+308
+        EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE = -9223372036854775816.43
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_INT_CONSTANT, constants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT,
+            places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT,
+                constants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT,
+            places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT,
+                constants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT,
+            places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT,
+                constants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST,
+            EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS,
+                constants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE,
+            places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE,
+                constants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST,
+            EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE,
+                constants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_DOUBLE,
+                constants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST,
+            EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE,
+                constants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST, EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_SMALL_DOUBLE,
+                constants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST))
+        self.assertAlmostEqual(
+            constants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST,
+            EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE, places=7,
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_RENDERED_DOUBLE_CONSTANTS_TEST % (
+                EXPECTED_DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE,
+                constants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST))
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_INT_CONSTANT_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_NEGATIVE_INT_CONSTANT_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_LARGEST_INT_CONSTANT_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_SMALLEST_INT_CONSTANT_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_DOUBLE_WITH_MANY_DECIMALS_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_FRACTIONAL_DOUBLE_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_NEGATIVE_FRACTIONAL_DOUBLE_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_LARGE_DOUBLE_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_LARGE_FRACTIONAL_DOUBLE_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_SMALL_DOUBLE_TEST")
+        self.assertTrue(
+            isinstance(constants.DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST, float),
+            msg=TestRenderedDoubleConstants.ASSERTION_MESSAGE_FOR_TYPE_CHECKS %
+            "DOUBLE_ASSIGNED_TO_NEGATIVE_BUT_LARGE_FRACTIONAL_DOUBLE_TEST")
+
+    # to make sure the variables inside Thrift files are generated correctly
+    def test_rendered_double_list(self):
+        EXPECTED_DOUBLE_LIST = [1.0, -100.0, 100.0, 9223372036854775807.0, -9223372036854775807.0, 3.14159265359,
+                                1000000.1, -1000000.1, 1.7e+308, -1.7e+308, 9223372036854775816.43,
+                                -9223372036854775816.43]
+        self.assertEqual(len(constants.DOUBLE_LIST_TEST), len(EXPECTED_DOUBLE_LIST))
+        for i, expectedValue in enumerate(EXPECTED_DOUBLE_LIST):
+            self.assertAlmostEqual(constants.DOUBLE_LIST_TEST[i], expectedValue, places=7)
+
+
+def suite():
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
+    suite.addTest(loader.loadTestsFromTestCase(TestRenderedDoubleConstants))
+    return suite
+
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
diff --git a/test/py/TestServer.py b/test/py/TestServer.py
index 334f25c..aba0d42 100755
--- a/test/py/TestServer.py
+++ b/test/py/TestServer.py
@@ -19,224 +19,324 @@
 # under the License.
 #
 from __future__ import division
-import sys, glob, time, os
-sys.path.insert(0, glob.glob(os.path.join(os.path.dirname(__file__),'../../lib/py/build/lib.*'))[0])
+import logging
+import os
+import signal
+import sys
+import time
 from optparse import OptionParser
 
-parser = OptionParser()
-parser.add_option('--genpydir', type='string', dest='genpydir',
-                  default='gen-py',
-                  help='include this local directory in sys.path for locating generated code')
-parser.add_option("--port", type="int", dest="port",
-    help="port number for server to listen on")
-parser.add_option("--zlib", action="store_true", dest="zlib",
-    help="use zlib wrapper for compressed transport")
-parser.add_option("--ssl", action="store_true", dest="ssl",
-    help="use SSL for encrypted transport")
-parser.add_option('-v', '--verbose', action="store_const", 
-    dest="verbose", const=2,
-    help="verbose output")
-parser.add_option('-q', '--quiet', action="store_const", 
-    dest="verbose", const=0,
-    help="minimal output")
-parser.add_option('--proto',  dest="proto", type="string",
-    help="protocol to use, one of: accel, binary, compact, json")
-parser.set_defaults(port=9090, verbose=1, proto='binary')
-options, args = parser.parse_args()
+from util import local_libpath
 
-sys.path.insert(0, options.genpydir)
-
-from ThriftTest import ThriftTest
-from ThriftTest.ttypes import *
-from thrift.Thrift import TException
-from thrift.transport import TTransport
-from thrift.transport import TSocket
-from thrift.transport import TZlibTransport
-from thrift.protocol import TBinaryProtocol
-from thrift.protocol import TCompactProtocol
-from thrift.protocol import TJSONProtocol
-from thrift.server import TServer, TNonblockingServer, THttpServer
-
-PROT_FACTORIES = {'binary': TBinaryProtocol.TBinaryProtocolFactory,
-    'accel': TBinaryProtocol.TBinaryProtocolAcceleratedFactory,
-    'compact': TCompactProtocol.TCompactProtocolFactory,
-    'json': TJSONProtocol.TJSONProtocolFactory}
-
-class TestHandler:
-
-  def testVoid(self):
-    if options.verbose > 1:
-      print 'testVoid()'
-
-  def testString(self, str):
-    if options.verbose > 1:
-      print 'testString(%s)' % str
-    return str
-
-  def testByte(self, byte):
-    if options.verbose > 1:
-      print 'testByte(%d)' % byte
-    return byte
-
-  def testI16(self, i16):
-    if options.verbose > 1:
-      print 'testI16(%d)' % i16
-    return i16
-
-  def testI32(self, i32):
-    if options.verbose > 1:
-      print 'testI32(%d)' % i32
-    return i32
-
-  def testI64(self, i64):
-    if options.verbose > 1:
-      print 'testI64(%d)' % i64
-    return i64
-
-  def testDouble(self, dub):
-    if options.verbose > 1:
-      print 'testDouble(%f)' % dub
-    return dub
-
-  def testStruct(self, thing):
-    if options.verbose > 1:
-      print 'testStruct({%s, %d, %d, %d})' % (thing.string_thing, thing.byte_thing, thing.i32_thing, thing.i64_thing)
-    return thing
-
-  def testException(self, arg):
-    #if options.verbose > 1:
-    print 'testException(%s)' % arg
-    if arg == 'Xception':
-      raise Xception(errorCode=1001, message=arg)
-    elif arg == 'TException':
-      raise TException(message='This is a TException')
-
-  def testMultiException(self, arg0, arg1):
-    if options.verbose > 1:
-      print 'testMultiException(%s, %s)' % (arg0, arg1)
-    if arg0 == 'Xception':
-      raise Xception(errorCode=1001, message='This is an Xception')
-    elif arg0 == 'Xception2':
-      raise Xception2(
-        errorCode=2002,
-        struct_thing=Xtruct(string_thing='This is an Xception2'))
-    return Xtruct(string_thing=arg1)
-
-  def testOneway(self, seconds):
-    if options.verbose > 1:
-      print 'testOneway(%d) => sleeping...' % seconds
-    time.sleep(seconds / 3) # be quick
-    if options.verbose > 1:
-      print 'done sleeping'
-
-  def testNest(self, thing):
-    if options.verbose > 1:
-      print 'testNest(%s)' % thing
-    return thing
-
-  def testMap(self, thing):
-    if options.verbose > 1:
-      print 'testMap(%s)' % thing
-    return thing
-
-  def testSet(self, thing):
-    if options.verbose > 1:
-      print 'testSet(%s)' % thing
-    return thing
-
-  def testList(self, thing):
-    if options.verbose > 1:
-      print 'testList(%s)' % thing
-    return thing
-
-  def testEnum(self, thing):
-    if options.verbose > 1:
-      print 'testEnum(%s)' % thing
-    return thing
-
-  def testTypedef(self, thing):
-    if options.verbose > 1:
-      print 'testTypedef(%s)' % thing
-    return thing
-
-  def testMapMap(self, thing):
-    if options.verbose > 1:
-      print 'testMapMap(%s)' % thing
-    return {thing: {thing: thing}}
-
-  def testInsanity(self, argument):
-    if options.verbose > 1:
-      print 'testInsanity(%s)' % argument
-    return {123489: {Numberz.ONE:argument}}
-
-  def testMulti(self, arg0, arg1, arg2, arg3, arg4, arg5):
-    if options.verbose > 1:
-      print 'testMulti(%s)' % [arg0, arg1, arg2, arg3, arg4, arg5]
-    return Xtruct(string_thing='Hello2',
-                  byte_thing=arg0, i32_thing=arg1, i64_thing=arg2)
+SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
 
 
-# set up the protocol factory form the --proto option
-pfactory_cls = PROT_FACTORIES.get(options.proto, None)
-if pfactory_cls is None:
-  raise AssertionError('Unknown --proto option: %s' % options.proto)
-pfactory = pfactory_cls()
+class TestHandler(object):
+    def testVoid(self):
+        if options.verbose > 1:
+            logging.info('testVoid()')
 
-# get the server type (TSimpleServer, TNonblockingServer, etc...)
-if len(args) > 1:
-  raise AssertionError('Only one server type may be specified, not multiple types.')
-server_type = args[0]
+    def testString(self, str):
+        if options.verbose > 1:
+            logging.info('testString(%s)' % str)
+        return str
 
-# Set up the handler and processor objects
-handler = TestHandler()
-processor = ThriftTest.Processor(handler)
+    def testBool(self, boolean):
+        if options.verbose > 1:
+            logging.info('testBool(%s)' % str(boolean).lower())
+        return boolean
 
-# Handle THttpServer as a special case
-if server_type == 'THttpServer':
-  server =THttpServer.THttpServer(processor, ('', options.port), pfactory)
-  server.serve()
-  sys.exit(0)
+    def testByte(self, byte):
+        if options.verbose > 1:
+            logging.info('testByte(%d)' % byte)
+        return byte
 
-# set up server transport and transport factory
-host = None
-if options.ssl:
-  from thrift.transport import TSSLSocket
-  transport = TSSLSocket.TSSLServerSocket(host, options.port, certfile='test_cert.pem')
-else:
-  transport = TSocket.TServerSocket(host, options.port)
-tfactory = TTransport.TBufferedTransportFactory()
+    def testI16(self, i16):
+        if options.verbose > 1:
+            logging.info('testI16(%d)' % i16)
+        return i16
 
-# if --zlib, then wrap server transport, and use a different transport factory
-if options.zlib:
-  transport = TZlibTransport.TZlibTransport(transport) # wrap  with zlib
-  tfactory = TZlibTransport.TZlibTransportFactory()
+    def testI32(self, i32):
+        if options.verbose > 1:
+            logging.info('testI32(%d)' % i32)
+        return i32
 
-# do server-specific setup here:
-if server_type == "TNonblockingServer":
-  server = TNonblockingServer.TNonblockingServer(processor, transport, inputProtocolFactory=pfactory)
-elif server_type == "TProcessPoolServer":
-  import signal
-  from thrift.server import TProcessPoolServer
-  server = TProcessPoolServer.TProcessPoolServer(processor, transport, tfactory, pfactory)
-  server.setNumWorkers(5)
-  def set_alarm():
-    def clean_shutdown(signum, frame):
-      for worker in server.workers:
-        if options.verbose > 0:
-          print 'Terminating worker: %s' % worker
-        worker.terminate()
-      if options.verbose > 0:
-        print 'Requesting server to stop()'
-      try:
-        server.stop()
-      except:
+    def testI64(self, i64):
+        if options.verbose > 1:
+            logging.info('testI64(%d)' % i64)
+        return i64
+
+    def testDouble(self, dub):
+        if options.verbose > 1:
+            logging.info('testDouble(%f)' % dub)
+        return dub
+
+    def testBinary(self, thing):
+        if options.verbose > 1:
+            logging.info('testBinary()')  # TODO: hex output
+        return thing
+
+    def testStruct(self, thing):
+        if options.verbose > 1:
+            logging.info('testStruct({%s, %s, %s, %s})' % (thing.string_thing, thing.byte_thing, thing.i32_thing, thing.i64_thing))
+        return thing
+
+    def testException(self, arg):
+        # if options.verbose > 1:
+        logging.info('testException(%s)' % arg)
+        if arg == 'Xception':
+            raise Xception(errorCode=1001, message=arg)
+        elif arg == 'TException':
+            raise TException(message='This is a TException')
+
+    def testMultiException(self, arg0, arg1):
+        if options.verbose > 1:
+            logging.info('testMultiException(%s, %s)' % (arg0, arg1))
+        if arg0 == 'Xception':
+            raise Xception(errorCode=1001, message='This is an Xception')
+        elif arg0 == 'Xception2':
+            raise Xception2(
+                errorCode=2002,
+                struct_thing=Xtruct(string_thing='This is an Xception2'))
+        return Xtruct(string_thing=arg1)
+
+    def testOneway(self, seconds):
+        if options.verbose > 1:
+            logging.info('testOneway(%d) => sleeping...' % seconds)
+        time.sleep(seconds / 3)  # be quick
+        if options.verbose > 1:
+            logging.info('done sleeping')
+
+    def testNest(self, thing):
+        if options.verbose > 1:
+            logging.info('testNest(%s)' % thing)
+        return thing
+
+    def testMap(self, thing):
+        if options.verbose > 1:
+            logging.info('testMap(%s)' % thing)
+        return thing
+
+    def testStringMap(self, thing):
+        if options.verbose > 1:
+            logging.info('testStringMap(%s)' % thing)
+        return thing
+
+    def testSet(self, thing):
+        if options.verbose > 1:
+            logging.info('testSet(%s)' % thing)
+        return thing
+
+    def testList(self, thing):
+        if options.verbose > 1:
+            logging.info('testList(%s)' % thing)
+        return thing
+
+    def testEnum(self, thing):
+        if options.verbose > 1:
+            logging.info('testEnum(%s)' % thing)
+        return thing
+
+    def testTypedef(self, thing):
+        if options.verbose > 1:
+            logging.info('testTypedef(%s)' % thing)
+        return thing
+
+    def testMapMap(self, thing):
+        if options.verbose > 1:
+            logging.info('testMapMap(%s)' % thing)
+        return {
+            -4: {
+                -4: -4,
+                -3: -3,
+                -2: -2,
+                -1: -1,
+            },
+            4: {
+                4: 4,
+                3: 3,
+                2: 2,
+                1: 1,
+            },
+        }
+
+    def testInsanity(self, argument):
+        if options.verbose > 1:
+            logging.info('testInsanity(%s)' % argument)
+        return {
+            1: {
+                2: argument,
+                3: argument,
+            },
+            2: {6: Insanity()},
+        }
+
+    def testMulti(self, arg0, arg1, arg2, arg3, arg4, arg5):
+        if options.verbose > 1:
+            logging.info('testMulti(%s)' % [arg0, arg1, arg2, arg3, arg4, arg5])
+        return Xtruct(string_thing='Hello2',
+                      byte_thing=arg0, i32_thing=arg1, i64_thing=arg2)
+
+
+def main(options):
+    # set up the protocol factory form the --protocol option
+    prot_factories = {
+        'accel': TBinaryProtocol.TBinaryProtocolAcceleratedFactory(),
+        'accelc': TCompactProtocol.TCompactProtocolAcceleratedFactory(),
+        'binary': TBinaryProtocol.TBinaryProtocolFactory(),
+        'compact': TCompactProtocol.TCompactProtocolFactory(),
+        'header': THeaderProtocol.THeaderProtocolFactory(allowed_client_types=[
+            THeaderTransport.THeaderClientType.HEADERS,
+            THeaderTransport.THeaderClientType.FRAMED_BINARY,
+            THeaderTransport.THeaderClientType.UNFRAMED_BINARY,
+            THeaderTransport.THeaderClientType.FRAMED_COMPACT,
+            THeaderTransport.THeaderClientType.UNFRAMED_COMPACT,
+        ]),
+        'json': TJSONProtocol.TJSONProtocolFactory(),
+    }
+    pfactory = prot_factories.get(options.proto, None)
+    if pfactory is None:
+        raise AssertionError('Unknown --protocol option: %s' % options.proto)
+    try:
+        pfactory.string_length_limit = options.string_limit
+        pfactory.container_length_limit = options.container_limit
+    except Exception:
+        # Ignore errors for those protocols that does not support length limit
         pass
-    signal.signal(signal.SIGALRM, clean_shutdown)
-    signal.alarm(2)
-  set_alarm()
-else:
-  # look up server class dynamically to instantiate server
-  ServerClass = getattr(TServer, server_type)
-  server = ServerClass(processor, transport, tfactory, pfactory)
-# enter server main loop
-server.serve()
+
+    # get the server type (TSimpleServer, TNonblockingServer, etc...)
+    if len(args) > 1:
+        raise AssertionError('Only one server type may be specified, not multiple types.')
+    server_type = args[0]
+    if options.trans == 'http':
+        server_type = 'THttpServer'
+
+    # Set up the handler and processor objects
+    handler = TestHandler()
+    processor = ThriftTest.Processor(handler)
+
+    global server
+
+    # Handle THttpServer as a special case
+    if server_type == 'THttpServer':
+        if options.ssl:
+            __certfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "server.crt")
+            __keyfile = os.path.join(os.path.dirname(SCRIPT_DIR), "keys", "server.key")
+            server = THttpServer.THttpServer(processor, ('', options.port), pfactory, cert_file=__certfile, key_file=__keyfile)
+        else:
+            server = THttpServer.THttpServer(processor, ('', options.port), pfactory)
+        server.serve()
+        sys.exit(0)
+
+    # set up server transport and transport factory
+
+    abs_key_path = os.path.join(os.path.dirname(SCRIPT_DIR), 'keys', 'server.pem')
+
+    host = None
+    if options.ssl:
+        from thrift.transport import TSSLSocket
+        transport = TSSLSocket.TSSLServerSocket(host, options.port, certfile=abs_key_path)
+    else:
+        transport = TSocket.TServerSocket(host, options.port)
+    tfactory = TTransport.TBufferedTransportFactory()
+    if options.trans == 'buffered':
+        tfactory = TTransport.TBufferedTransportFactory()
+    elif options.trans == 'framed':
+        tfactory = TTransport.TFramedTransportFactory()
+    elif options.trans == '':
+        raise AssertionError('Unknown --transport option: %s' % options.trans)
+    else:
+        tfactory = TTransport.TBufferedTransportFactory()
+    # if --zlib, then wrap server transport, and use a different transport factory
+    if options.zlib:
+        transport = TZlibTransport.TZlibTransport(transport)  # wrap  with zlib
+        tfactory = TZlibTransport.TZlibTransportFactory()
+
+    # do server-specific setup here:
+    if server_type == "TNonblockingServer":
+        server = TNonblockingServer.TNonblockingServer(processor, transport, inputProtocolFactory=pfactory)
+    elif server_type == "TProcessPoolServer":
+        import signal
+        from thrift.server import TProcessPoolServer
+        server = TProcessPoolServer.TProcessPoolServer(processor, transport, tfactory, pfactory)
+        server.setNumWorkers(5)
+
+        def set_alarm():
+            def clean_shutdown(signum, frame):
+                for worker in server.workers:
+                    if options.verbose > 0:
+                        logging.info('Terminating worker: %s' % worker)
+                    worker.terminate()
+                if options.verbose > 0:
+                    logging.info('Requesting server to stop()')
+                try:
+                    server.stop()
+                except Exception:
+                    pass
+            signal.signal(signal.SIGALRM, clean_shutdown)
+            signal.alarm(4)
+        set_alarm()
+    else:
+        # look up server class dynamically to instantiate server
+        ServerClass = getattr(TServer, server_type)
+        server = ServerClass(processor, transport, tfactory, pfactory)
+    # enter server main loop
+    server.serve()
+
+
+def exit_gracefully(signum, frame):
+    print("SIGINT received\n")
+    server.shutdown()   # doesn't work properly, yet
+    sys.exit(0)
+
+
+if __name__ == '__main__':
+    signal.signal(signal.SIGINT, exit_gracefully)
+
+    parser = OptionParser()
+    parser.add_option('--libpydir', type='string', dest='libpydir',
+                      help='include this directory to sys.path for locating library code')
+    parser.add_option('--genpydir', type='string', dest='genpydir',
+                      default='gen-py',
+                      help='include this directory to sys.path for locating generated code')
+    parser.add_option("--port", type="int", dest="port",
+                      help="port number for server to listen on")
+    parser.add_option("--zlib", action="store_true", dest="zlib",
+                      help="use zlib wrapper for compressed transport")
+    parser.add_option("--ssl", action="store_true", dest="ssl",
+                      help="use SSL for encrypted transport")
+    parser.add_option('-v', '--verbose', action="store_const",
+                      dest="verbose", const=2,
+                      help="verbose output")
+    parser.add_option('-q', '--quiet', action="store_const",
+                      dest="verbose", const=0,
+                      help="minimal output")
+    parser.add_option('--protocol', dest="proto", type="string",
+                      help="protocol to use, one of: accel, accelc, binary, compact, json")
+    parser.add_option('--transport', dest="trans", type="string",
+                      help="transport to use, one of: buffered, framed, http")
+    parser.add_option('--container-limit', dest='container_limit', type='int', default=None)
+    parser.add_option('--string-limit', dest='string_limit', type='int', default=None)
+    parser.set_defaults(port=9090, verbose=1, proto='binary', transport='buffered')
+    options, args = parser.parse_args()
+
+    # Print TServer log to stdout so that the test-runner can redirect it to log files
+    logging.basicConfig(level=options.verbose)
+
+    sys.path.insert(0, os.path.join(SCRIPT_DIR, options.genpydir))
+    sys.path.insert(0, local_libpath())
+
+    from ThriftTest import ThriftTest
+    from ThriftTest.ttypes import Xtruct, Xception, Xception2, Insanity
+    from thrift.Thrift import TException
+    from thrift.transport import THeaderTransport
+    from thrift.transport import TTransport
+    from thrift.transport import TSocket
+    from thrift.transport import TZlibTransport
+    from thrift.protocol import TBinaryProtocol
+    from thrift.protocol import TCompactProtocol
+    from thrift.protocol import THeaderProtocol
+    from thrift.protocol import TJSONProtocol
+    from thrift.server import TServer, TNonblockingServer, THttpServer
+
+    sys.exit(main(options))
diff --git a/test/py/TestSocket.py b/test/py/TestSocket.py
index b9bdf27..619eb10 100755
--- a/test/py/TestSocket.py
+++ b/test/py/TestSocket.py
@@ -19,29 +19,16 @@
 # under the License.
 #
 
-import sys, glob
-from optparse import OptionParser
-parser = OptionParser()
-parser.add_option('--genpydir', type='string', dest='genpydir', default='gen-py')
-options, args = parser.parse_args()
-del sys.argv[1:] # clean up hack so unittest doesn't complain
-sys.path.insert(0, options.genpydir)
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
-
-from ThriftTest import ThriftTest
-from ThriftTest.ttypes import *
-from thrift.transport import TTransport
 from thrift.transport import TSocket
-from thrift.protocol import TBinaryProtocol
 import unittest
 import time
 import socket
 import random
-from optparse import OptionParser
+
 
 class TimeoutTest(unittest.TestCase):
     def setUp(self):
-        for i in xrange(50):
+        for i in range(50):
             try:
                 # find a port we can use
                 self.listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -49,7 +36,7 @@
                 self.listen_sock.bind(('localhost', self.port))
                 self.listen_sock.listen(5)
                 break
-            except:
+            except Exception:
                 if i == 49:
                     raise
 
@@ -58,12 +45,12 @@
 
         try:
             leaky = []
-            for i in xrange(100):
+            for i in range(100):
                 socket = TSocket.TSocket('localhost', self.port)
                 socket.setTimeout(10)
                 socket.open()
                 leaky.append(socket)
-        except:
+        except Exception:
             self.assert_(time.time() - starttime < 5.0)
 
     def testWriteTimeout(self):
@@ -75,15 +62,17 @@
             socket.open()
             lsock = self.listen_sock.accept()
             while True:
-                socket.write("hi" * 100)
+                lsock.write("hi" * 100)
 
-        except:
+        except Exception:
             self.assert_(time.time() - starttime < 5.0)
 
-suite = unittest.TestSuite()
-loader = unittest.TestLoader()
 
-suite.addTest(loader.loadTestsFromTestCase(TimeoutTest))
+if __name__ == '__main__':
+    suite = unittest.TestSuite()
+    loader = unittest.TestLoader()
 
-testRunner = unittest.TextTestRunner(verbosity=2)
-testRunner.run(suite)
+    suite.addTest(loader.loadTestsFromTestCase(TimeoutTest))
+
+    testRunner = unittest.TextTestRunner(verbosity=2)
+    testRunner.run(suite)
diff --git a/test/py/TestSyntax.py b/test/py/TestSyntax.py
index 9f71cf5..dbe7975 100755
--- a/test/py/TestSyntax.py
+++ b/test/py/TestSyntax.py
@@ -19,15 +19,6 @@
 # under the License.
 #
 
-import sys, glob
-from optparse import OptionParser
-parser = OptionParser()
-parser.add_option('--genpydir', type='string', dest='genpydir', default='gen-py')
-options, args = parser.parse_args()
-del sys.argv[1:] # clean up hack so unittest doesn't complain
-sys.path.insert(0, options.genpydir)
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
-
 # Just import these generated files to make sure they are syntactically valid
-from DebugProtoTest import EmptyService
-from DebugProtoTest import Inherited
+from DebugProtoTest import EmptyService  # noqa
+from DebugProtoTest import Inherited  # noqa
diff --git a/test/py/explicit_module/runtest.sh b/test/py/explicit_module/runtest.sh
index 2e5a4f1..6d73462 100755
--- a/test/py/explicit_module/runtest.sh
+++ b/test/py/explicit_module/runtest.sh
@@ -22,6 +22,7 @@
 rm -rf gen-py
 ../../../compiler/cpp/thrift --gen py test1.thrift || exit 1
 ../../../compiler/cpp/thrift --gen py test2.thrift || exit 1
+../../../compiler/cpp/thrift --gen py test3.thrift && exit 1  # Fail since test3.thrift has python keywords
 PYTHONPATH=./gen-py python -c 'import foo.bar.baz' || exit 1
 PYTHONPATH=./gen-py python -c 'import test2' || exit 1
 PYTHONPATH=./gen-py python -c 'import test1' &>/dev/null && exit 1  # Should fail.
diff --git a/test/py/explicit_module/test3.thrift b/test/py/explicit_module/test3.thrift
new file mode 100644
index 0000000..154786b
--- /dev/null
+++ b/test/py/explicit_module/test3.thrift
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+namespace py validations
+
+struct from {
+  1: i32 def;
+}
+
diff --git a/test/py/generate.cmake b/test/py/generate.cmake
new file mode 100644
index 0000000..4ed14cc
--- /dev/null
+++ b/test/py/generate.cmake
@@ -0,0 +1,36 @@
+macro(GENERATE FILENAME GENERATOR OUTPUTDIR)
+  file(MAKE_DIRECTORY ${MY_CURRENT_BINARY_DIR}/${OUTPUTDIR})
+  execute_process(COMMAND ${THRIFTCOMPILER} --gen ${GENERATOR} -out ${MY_CURRENT_BINARY_DIR}/${OUTPUTDIR} ${FILENAME}
+                  RESULT_VARIABLE CMD_RESULT)
+  if(CMD_RESULT)
+        message(FATAL_ERROR "Error generating ${FILENAME} with generator ${GENERATOR}")
+  endif()
+endmacro(GENERATE)
+
+generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py gen-py-default)
+generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:slots gen-py-slots)
+generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:old_style gen-py-oldstyle)
+generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:no_utf8strings gen-py-no_utf8strings)
+generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:dynamic gen-py-dynamic)
+generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:dynamic,slots gen-py-dynamicslots)
+
+generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py gen-py-default)
+generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:slots gen-py-slots)
+generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:old_style gen-py-oldstyle)
+generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:no_utf8strings gen-py-no_utf8strings)
+generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:dynamic gen-py-dynamic)
+generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:dynamic,slots gen-py-dynamicslots)
+
+generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py gen-py-default)
+generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:slots gen-py-slots)
+generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:old_style gen-py-oldstyle)
+generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:no_utf8strings gen-py-no_utf8strings)
+generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:dynamic gen-py-dynamic)
+generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:dynamic,slots gen-py-dynamicslots)
+
+generate(${MY_PROJECT_DIR}/test/Recursive.thrift py gen-py-default)
+generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:slots gen-py-slots)
+generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:old_style gen-py-oldstyle)
+generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:no_utf8strings gen-py-no_utf8strings)
+generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:dynamic gen-py-dynamic)
+generate(${MY_PROJECT_DIR}/test/Recursive.thrift py:dynamic,slots gen-py-dynamicslots)
diff --git a/test/py/setup.cfg b/test/py/setup.cfg
new file mode 100644
index 0000000..7da1f96
--- /dev/null
+++ b/test/py/setup.cfg
@@ -0,0 +1,2 @@
+[flake8]
+max-line-length = 100
diff --git a/test/py/test_cert.pem b/test/py/test_cert.pem
deleted file mode 100644
index 9b1a51f..0000000
--- a/test/py/test_cert.pem
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIB+zCCAWQCCQDyq++o7K0rpTANBgkqhkiG9w0BAQUFADBCMQswCQYDVQQGEwJV
-UzEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBh
-bnkgTHRkMB4XDTExMDMxNjEzMTQ1NVoXDTIxMDMxMzEzMTQ1NVowQjELMAkGA1UE
-BhMCVVMxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwTRGVmYXVsdCBD
-b21wYW55IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA9lmCuVQRqRBR
-OYVH+FMChSoF8IjMwfrpnC65J9RR88dUIZbjC2b+JPT5qiUVQft2NzPPwiBnXI2s
-j6AmHYVKoWGB24hNX8bj2cjtxdPpT2rvfAlIK0pat1C+kCxgRHIg++S7o6GEJOkw
-OQiopsUroAsIbSRT/Ird/A0+KeSqQ0sCAwEAATANBgkqhkiG9w0BAQUFAAOBgQDf
-WseEh6/3gWl/G44MyjljBvgRAa0c+eqFL/cVl7Zfh03/KOXMlPV5/snVUYBOJCCI
-qPuQwWToT+Q36kNQyMnG4e4gh+DmsiIhgQgA3lVSNDhPPfRrG1vDeeXXtybpEoke
-fI6o9a9olzrKWNvW+/8P9xIDlP0SRZxL66464LAQnw==
------END CERTIFICATE-----
------BEGIN RSA PRIVATE KEY-----
-MIICXwIBAAKBgQD2WYK5VBGpEFE5hUf4UwKFKgXwiMzB+umcLrkn1FHzx1QhluML
-Zv4k9PmqJRVB+3Y3M8/CIGdcjayPoCYdhUqhYYHbiE1fxuPZyO3F0+lPau98CUgr
-Slq3UL6QLGBEciD75LujoYQk6TA5CKimxSugCwhtJFP8it38DT4p5KpDSwIDAQAB
-AoGBAMcnA7Q5T3GifFeI9O6+hLoMh/K1VPq4kmStrQeS8JGoIc5pwbC1GV3dIXy4
-L+BAnofv/dQNCCJdchRGPqn82J/aOA/sMsJJ6VzTSr9NNVl9lgQHdLjEDoZ15yxT
-vVSc4nG2xBs7uZ/24fN/SJZVFO3+EdphOvrp7uEXLiXlqvopAkEA/h7XGlrULBIN
-ekjAzEJEchlZb4xJdPrH3P4LZs92ZlcO88GFr5wfOz1ytafLiZA9EzYwLIQTPdsk
-HHynJeZWtwJBAPgr9PYUJOdkhUeWVSN2PyqvWKrdQVKvM1VwNgRFaSPXgBd0WGIN
-Eym1b7wt6ngwNtfLx9FUOR6nl7MklsFLBA0CQQDnSiibqynLxs6PiyI3huUHOH1H
-YtcE6q/4Ox0jgRYRhZFtWKkVsbJXV9FM9yDw3uBH2R01lyxwM0GF0ArOGvy3AkEA
-7eEcjh/i+9Wzl1n3Q+WdSKoJAMbSTZJYT0Ye0NtDm7J+On0wFtRXkPw0HRmaDRiS
-CSlw4CquEb8tPu8Mfj0MpQJBAKwTLSdHsy0vxQQJXm0lTI+Ck9KJUM9vJzFuCL/x
-G6fmsqEttxjhyLnze+iIIRAu/IV+A5UrWnI1h728y/wRejw=
------END RSA PRIVATE KEY-----
diff --git a/test/py/test_cert.readme b/test/py/test_cert.readme
deleted file mode 100644
index 08bbbc9..0000000
--- a/test/py/test_cert.readme
+++ /dev/null
@@ -1,7 +0,0 @@
-NOTE:
-The test_cert.pem file in this directory must never be used on production systems.
-
-The key it represents is a self-signed key intended only for use by the unit
-testing framework.  It is a publicly exposed private key.
-
-Do not use test_cert.pem in production environments under any circumstances.
diff --git a/test/py/util.py b/test/py/util.py
new file mode 100644
index 0000000..c2b3f5c
--- /dev/null
+++ b/test/py/util.py
@@ -0,0 +1,32 @@
+#
+# 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 glob
+import os
+import sys
+
+_SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
+_ROOT_DIR = os.path.dirname(os.path.dirname(_SCRIPT_DIR))
+
+
+def local_libpath():
+    globdir = os.path.join(_ROOT_DIR, 'lib', 'py', 'build', 'lib.*')
+    for libpath in glob.glob(globdir):
+        if libpath.endswith('-%d.%d' % (sys.version_info[0], sys.version_info[1])):
+            return libpath
diff --git a/test/rb/Gemfile b/test/rb/Gemfile
index 8301e44..4ff0539 100644
--- a/test/rb/Gemfile
+++ b/test/rb/Gemfile
@@ -2,5 +2,6 @@
 
 require "rubygems"
 
-gem "rack", "~> 1.5.2"
-gem "thin", "~> 1.5.0"
+gem 'rack', '~> 2.0', '>= 2.0.4'
+gem 'thin', '~> 1.7', '>= 1.7.2'
+gem 'test-unit', '~> 3.2', '>= 3.2.7'
diff --git a/test/rb/Makefile.am b/test/rb/Makefile.am
index 9cdd99b..cfdc149 100644
--- a/test/rb/Makefile.am
+++ b/test/rb/Makefile.am
@@ -17,11 +17,12 @@
 # under the License.
 #
 
-THRIFT = $(top_srcdir)/compiler/cpp/thrift
-
-stubs: ../ThriftTest.thrift ../SmallTest.thrift
+stubs: $(THRIFT) ../ThriftTest.thrift ../SmallTest.thrift
 	$(THRIFT) --gen rb ../ThriftTest.thrift
 	$(THRIFT) --gen rb ../SmallTest.thrift
+	$(THRIFT) --gen rb ../Recursive.thrift
+
+precross: stubs
 
 check: stubs
 if HAVE_BUNDLER
diff --git a/test/rb/core/transport/test_transport.rb b/test/rb/core/transport/test_transport.rb
index 52755c1..37afa85 100644
--- a/test/rb/core/transport/test_transport.rb
+++ b/test/rb/core/transport/test_transport.rb
@@ -51,7 +51,7 @@
   
   # TODO:
   # This doesn't necessarily test he right thing.
-  # It _looks_ like read isn't guarenteed to return the length
+  # It _looks_ like read isn't guaranteed to return the length
   # you ask for and read_all is. This means our test needs to check
   # for blocking. -- Kevin Clark 3/27/08
   def test_read_all
diff --git a/test/rb/generation/test_recursive.rb b/test/rb/generation/test_recursive.rb
new file mode 100644
index 0000000..e912f72
--- /dev/null
+++ b/test/rb/generation/test_recursive.rb
@@ -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.
+#
+
+require File.join(File.dirname(__FILE__), '../test_helper')
+require 'recursive_types'
+
+class TestRecursiveGeneration < Test::Unit::TestCase
+  CHILD_ITEM = "child item"
+  PARENT_ITEM = "parent item"
+
+  def test_can_create_recursive_tree
+
+    child_tree = RecTree.new
+    child_tree.item = CHILD_ITEM
+
+    parent_tree = RecTree.new
+    parent_tree.item = PARENT_ITEM
+    parent_tree.children = [child_tree]
+
+    assert_equal(PARENT_ITEM, parent_tree.item)
+    assert_equal(1, parent_tree.children.length)
+    assert_equal(CHILD_ITEM, parent_tree.children.first.item)
+    assert_nil(parent_tree.children.first.children)
+  end
+end
diff --git a/test/rb/integration/TestClient.rb b/test/rb/integration/TestClient.rb
new file mode 100755
index 0000000..639aca9
--- /dev/null
+++ b/test/rb/integration/TestClient.rb
@@ -0,0 +1,381 @@
+#!/usr/bin/env ruby
+# encoding: utf-8
+
+#
+# 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.
+#
+
+$:.push File.dirname(__FILE__) + '/..'
+
+require 'test_helper'
+require 'thrift'
+require 'thrift_test'
+
+$domain_socket = nil
+$host = "localhost"
+$port = 9090
+$protocolType = "binary"
+$ssl = false
+$transport = "buffered"
+
+ARGV.each do|a|
+  if a == "--help"
+    puts "Allowed options:"
+    puts "\t -h [ --help ] \t produce help message"
+    puts "\t--domain-socket arg (=) \t Unix domain socket path"
+    puts "\t--host arg (=localhost) \t Host to connect \t not valid with domain-socket"
+    puts "\t--port arg (=9090) \t Port number to listen \t not valid with domain-socket"
+    puts "\t--protocol arg (=binary) \t protocol: accel, binary, compact, json"
+    puts "\t--ssl \t use ssl \t not valid with domain-socket"
+    puts "\t--transport arg (=buffered) transport: buffered, framed, http"
+    exit
+  elsif a.start_with?("--domain-socket")
+    $domain_socket = a.split("=")[1]
+  elsif a.start_with?("--host")
+    $host = a.split("=")[1]
+  elsif a.start_with?("--protocol")
+    $protocolType = a.split("=")[1]
+  elsif a == "--ssl"
+    $ssl = true
+  elsif a.start_with?("--transport")
+    $transport = a.split("=")[1]
+  elsif a.start_with?("--port")
+    $port = a.split("=")[1].to_i
+  end
+end
+
+class SimpleClientTest < Test::Unit::TestCase
+  def setup
+    unless @socket
+      if $domain_socket.to_s.strip.empty?
+        if $ssl
+          # the working directory for ruby crosstest is test/rb/gen-rb
+          keysDir = File.join(File.dirname(File.dirname(Dir.pwd)), "keys")
+          ctx = OpenSSL::SSL::SSLContext.new
+          ctx.ca_file = File.join(keysDir, "CA.pem")
+          ctx.cert = OpenSSL::X509::Certificate.new(File.open(File.join(keysDir, "client.crt")))
+          ctx.cert_store = OpenSSL::X509::Store.new
+          ctx.cert_store.add_file(File.join(keysDir, 'server.pem'))
+          ctx.key = OpenSSL::PKey::RSA.new(File.open(File.join(keysDir, "client.key")))
+          ctx.options = OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
+          ctx.ssl_version = :SSLv23
+          ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
+          @socket = Thrift::SSLSocket.new($host, $port, nil, ctx)
+        else
+          @socket = Thrift::Socket.new($host, $port)
+        end
+      else
+        @socket = Thrift::UNIXSocket.new($domain_socket)
+      end
+      
+      if $transport == "buffered"
+        transportFactory = Thrift::BufferedTransport.new(@socket)
+      elsif $transport == "framed"
+        transportFactory = Thrift::FramedTransport.new(@socket)
+      else
+        raise 'Unknown transport type'
+      end
+
+      if $protocolType == "binary"
+        @protocol = Thrift::BinaryProtocol.new(transportFactory)
+      elsif $protocolType == "compact"
+        @protocol = Thrift::CompactProtocol.new(transportFactory)
+      elsif $protocolType == "json"
+        @protocol = Thrift::JsonProtocol.new(transportFactory)
+      elsif $protocolType == "accel"
+        @protocol = Thrift::BinaryProtocolAccelerated.new(transportFactory)
+      else
+        raise 'Unknown protocol type'
+      end
+      @client = Thrift::Test::ThriftTest::Client.new(@protocol)
+      @socket.open
+    end
+  end
+
+  def teardown
+    @socket.close
+  end
+
+  def test_void
+    p 'test_void'
+    @client.testVoid()
+  end
+
+  def test_string
+    p 'test_string'
+    test_string =
+      'quote: \" backslash:' +
+      ' forwardslash-escaped: \/ ' +
+      ' backspace: \b formfeed: \f newline: \n return: \r tab: ' +
+      ' now-all-of-them-together: "\\\/\b\n\r\t' +
+      ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><' +
+      ' char-to-test-json-parsing: ]] \"]] \\" }}}{ [[[ '
+    test_string = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " +
+      "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " +
+      "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, " +
+      "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, " +
+      "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, " +
+      "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, " +
+      "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, " +
+      "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, " +
+      "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, " +
+      "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, " +
+      "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, " +
+      "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, " +
+      "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, " +
+      "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa " +
+      "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa " +
+      "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪" +
+      "Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, " +
+      "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, " +
+      "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, " +
+      "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple " +
+      "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, " +
+      "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, " +
+      "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, " +
+      "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, " +
+      "Bân-lâm-gú, 粵語"
+
+    result_string = @client.testString(test_string)
+    assert_equal(test_string, result_string.force_encoding(Encoding::UTF_8))
+  end
+
+  def test_bool
+    p 'test_bool'
+    assert_equal(@client.testBool(true), true)
+    assert_equal(@client.testBool(false), false)
+  end
+
+  def test_byte
+    p 'test_byte'
+    val = 120
+    assert_equal(@client.testByte(val), val)
+    assert_equal(@client.testByte(-val), -val)
+  end
+
+  def test_i32
+    p 'test_i32'
+    val = 2000000032
+    assert_equal(@client.testI32(val), val)
+    assert_equal(@client.testI32(-val), -val)
+  end
+
+  def test_i64
+    p 'test_i64'
+    val = 9000000000000000064
+    assert_equal(@client.testI64(val), val)
+    assert_equal(@client.testI64(-val), -val)
+  end
+
+  def test_double
+    p 'test_double'
+    val = 3.14159265358979323846
+    assert_equal(@client.testDouble(val), val)
+    assert_equal(@client.testDouble(-val), -val)
+    assert_kind_of(Float, @client.testDouble(val))
+  end
+
+  def test_binary
+    p 'test_binary'
+    val = (0...256).reverse_each.to_a
+    ret = @client.testBinary(val.pack('C*'))
+    assert_equal(val, ret.bytes.to_a)
+  end
+
+  def test_map
+    p 'test_map'
+    val = {1 => 1, 2 => 2, 3 => 3}
+    assert_equal(@client.testMap(val), val)
+    assert_kind_of(Hash, @client.testMap(val))
+  end
+
+  def test_string_map
+    p 'test_string_map'
+    val = {'a' => '2', 'b' => 'blah', 'some' => 'thing'}
+    ret = @client.testStringMap(val)
+    assert_equal(val, ret)
+    assert_kind_of(Hash, ret)
+  end
+
+  def test_list
+    p 'test_list'
+    val = [1,2,3,4,5]
+    assert_equal(@client.testList(val), val)
+    assert_kind_of(Array, @client.testList(val))
+  end
+
+  def test_enum
+    p 'test_enum'
+    val = Thrift::Test::Numberz::SIX
+    ret = @client.testEnum(val)
+
+    assert_equal(ret, 6)
+    assert_kind_of(Fixnum, ret)
+  end
+
+  def test_typedef
+    p 'test_typedef'
+    #UserId  testTypedef(1: UserId thing),
+    assert_equal(@client.testTypedef(309858235082523), 309858235082523)
+    assert_kind_of(Fixnum, @client.testTypedef(309858235082523))
+    true
+  end
+
+  def test_set
+    p 'test_set'
+    val = Set.new([1,2,3])
+    assert_equal(@client.testSet(val), val)
+    assert_kind_of(Set, @client.testSet(val))
+  end
+
+  def get_struct
+    Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 })
+  end
+
+  def test_struct
+    p 'test_struct'
+    ret = @client.testStruct(get_struct)
+
+    # TODO: not sure what unspecified "default" requiredness values should be
+    assert(ret.byte_thing == nil || ret.byte_thing == 0)
+    assert(ret.i64_thing == nil || ret.i64_thing == 0)
+
+    assert_equal(ret.string_thing, 'hi!')
+    assert_equal(ret.i32_thing, 4)
+    assert_kind_of(Thrift::Test::Xtruct, ret)
+  end
+
+  def test_nest
+    p 'test_nest'
+    struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10})
+
+    ret = @client.testNest(struct2)
+
+    # TODO: not sure what unspecified "default" requiredness values should be
+    assert(ret.struct_thing.byte_thing == nil || ret.struct_thing.byte_thing == 0)
+    assert(ret.struct_thing.i64_thing == nil || ret.struct_thing.i64_thing == 0)
+
+    assert_equal(ret.struct_thing.string_thing, 'hi!')
+    assert_equal(ret.struct_thing.i32_thing, 4)
+    assert_equal(ret.i32_thing, 10)
+
+    assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing)
+    assert_kind_of(Thrift::Test::Xtruct2, ret)
+  end
+
+  def test_insanity
+    p 'test_insanity'
+    insane = Thrift::Test::Insanity.new({
+      'userMap' => {
+        Thrift::Test::Numberz::FIVE => 5,
+        Thrift::Test::Numberz::EIGHT => 8,
+      },
+      'xtructs' => [
+        Thrift::Test::Xtruct.new({
+          'string_thing' => 'Goodbye4',
+          'byte_thing' => 4,
+          'i32_thing' => 4,
+          'i64_thing' => 4,
+        }),
+        Thrift::Test::Xtruct.new({
+          'string_thing' => 'Hello2',
+          'byte_thing' => 2,
+          'i32_thing' => 2,
+          'i64_thing' => 2,
+        })
+      ]
+    })
+
+    ret = @client.testInsanity(insane)
+
+    assert_equal(insane, ret[1][2])
+    assert_equal(insane, ret[1][3])
+
+    assert(ret[2][6].userMap == nil || ret[2][6].userMap.length == 0)
+    assert(ret[2][6].xtructs == nil || ret[2][6].xtructs.length == 0)
+  end
+
+  def test_map_map
+    p 'test_map_map'
+    ret = @client.testMapMap(4)
+    assert_kind_of(Hash, ret)
+    expected = {
+      -4 => {
+        -4 => -4,
+        -3 => -3,
+        -2 => -2,
+        -1 => -1,
+      },
+      4 => {
+        4 => 4,
+        3 => 3,
+        2 => 2,
+        1 => 1,
+      }
+    }
+    assert_equal(expected, ret)
+  end
+
+  def test_multi
+    p 'test_multi'
+    ret = @client.testMulti(42, 4242, 424242, {1 => 'blah', 2 => 'thing'}, Thrift::Test::Numberz::EIGHT, 24)
+    expected = Thrift::Test::Xtruct.new({
+      :string_thing => 'Hello2',
+      :byte_thing =>   42,
+      :i32_thing =>    4242,
+      :i64_thing =>    424242
+    })
+    assert_equal(expected, ret)
+  end
+
+  def test_exception
+    p 'test_exception'
+    assert_raise Thrift::Test::Xception do
+      @client.testException('Xception')
+    end
+    begin
+      @client.testException('TException')
+    rescue => e
+      assert e.class.ancestors.include?(Thrift::Exception)
+    end
+    assert_nothing_raised do
+      @client.testException('test')
+    end
+  end
+
+  def test_multi_exception
+    p 'test_multi_exception'
+    assert_raise Thrift::Test::Xception do
+      @client.testMultiException("Xception", "test 1")
+    end
+    assert_raise Thrift::Test::Xception2 do
+      @client.testMultiException("Xception2", "test 2")
+    end
+    assert_equal( @client.testMultiException("Success", "test 3").string_thing, "test 3")
+  end
+
+  def test_oneway
+    p 'test_oneway'
+    time1 = Time.now.to_f
+    @client.testOneway(1)
+    time2 = Time.now.to_f
+    assert_operator (time2-time1), :<, 0.1
+  end
+
+end
+
diff --git a/test/rb/integration/TestServer.rb b/test/rb/integration/TestServer.rb
new file mode 100755
index 0000000..7caf6a8
--- /dev/null
+++ b/test/rb/integration/TestServer.rb
@@ -0,0 +1,188 @@
+#!/usr/bin/env ruby
+
+#
+# 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.
+#
+
+$:.push File.dirname(__FILE__) + '/..'
+
+require 'test_helper'
+require 'thrift'
+require 'thrift_test'
+require 'thrift_test_types'
+
+class SimpleHandler
+  [:testVoid, :testString, :testBool, :testByte, :testI32, :testI64, :testDouble, :testBinary,
+   :testStruct, :testMap, :testStringMap, :testSet, :testList, :testNest, :testEnum, :testTypedef,
+   :testEnum, :testTypedef, :testMultiException].each do |meth|
+
+    define_method(meth) do |thing|
+      p meth
+      p thing
+      thing
+    end
+
+  end
+
+  def testVoid()
+  end
+
+  def testInsanity(thing)
+    return {
+      1 => {
+        2 => thing,
+        3 => thing
+      },
+      2 => {
+        6 => Thrift::Test::Insanity::new()
+      }
+    }
+  end
+
+  def testMapMap(thing)
+    return {
+      -4 => {
+        -4 => -4,
+        -3 => -3,
+        -2 => -2,
+        -1 => -1,
+      },
+      4 => {
+        4 => 4,
+        3 => 3,
+        2 => 2,
+        1 => 1,
+      }
+    }
+  end
+
+  def testMulti(arg0, arg1, arg2, arg3, arg4, arg5)
+    return Thrift::Test::Xtruct.new({
+      'string_thing' => 'Hello2',
+      'byte_thing' => arg0,
+      'i32_thing' => arg1,
+      'i64_thing' => arg2,
+    })
+  end
+
+  def testException(thing)
+    if thing == "Xception"
+      raise Thrift::Test::Xception, :errorCode => 1001, :message => thing
+    elsif thing == "TException"
+      raise Thrift::Exception, :message => thing
+    else
+      # no-op
+    end
+  end
+
+  def testMultiException(arg0, arg1)
+    if arg0 == "Xception2"
+      raise Thrift::Test::Xception2, :errorCode => 2002, :struct_thing => ::Thrift::Test::Xtruct.new({ :string_thing => 'This is an Xception2' })
+    elsif arg0 == "Xception"
+      raise Thrift::Test::Xception, :errorCode => 1001, :message => 'This is an Xception'
+    else
+      return ::Thrift::Test::Xtruct.new({'string_thing' => arg1})
+    end
+  end
+
+  def testOneway(arg0)
+    sleep(arg0)
+  end
+
+end
+
+domain_socket = nil
+port = 9090
+protocol = "binary"
+@protocolFactory = nil
+ssl = false
+transport = "buffered"
+@transportFactory = nil
+
+ARGV.each do|a|
+  if a == "--help"
+    puts "Allowed options:"
+    puts "\t -h [ --help ] \t produce help message"
+    puts "\t--domain-socket arg (=) \t Unix domain socket path"
+    puts "\t--port arg (=9090) \t Port number to listen \t not valid with domain-socket"
+    puts "\t--protocol arg (=binary) \t protocol: accel, binary, compact, json"
+    puts "\t--ssl \t use ssl \t not valid with domain-socket"
+    puts "\t--transport arg (=buffered) transport: buffered, framed, http"
+    exit
+  elsif a.start_with?("--domain-socket")
+    domain_socket = a.split("=")[1]
+  elsif a.start_with?("--protocol")
+    protocol = a.split("=")[1]
+  elsif a == "--ssl"
+    ssl = true
+  elsif a.start_with?("--transport")
+    transport = a.split("=")[1]
+  elsif a.start_with?("--port")
+    port = a.split("=")[1].to_i 
+  end
+end
+
+if protocol == "binary" || protocol.to_s.strip.empty?
+  @protocolFactory = Thrift::BinaryProtocolFactory.new
+elsif protocol == "compact"
+  @protocolFactory = Thrift::CompactProtocolFactory.new
+elsif protocol == "json"
+  @protocolFactory = Thrift::JsonProtocolFactory.new
+elsif protocol == "accel"
+  @protocolFactory = Thrift::BinaryProtocolAcceleratedFactory.new
+else
+  raise 'Unknown protocol type'
+end
+
+if transport == "buffered" || transport.to_s.strip.empty?
+  @transportFactory = Thrift::BufferedTransportFactory.new
+elsif transport == "framed"
+  @transportFactory = Thrift::FramedTransportFactory.new
+else
+  raise 'Unknown transport type'
+end
+
+@handler = SimpleHandler.new
+@processor = Thrift::Test::ThriftTest::Processor.new(@handler)
+@transport = nil
+if domain_socket.to_s.strip.empty?
+  if ssl
+    # the working directory for ruby crosstest is test/rb/gen-rb
+    keysDir = File.join(File.dirname(File.dirname(Dir.pwd)), "keys")
+    ctx = OpenSSL::SSL::SSLContext.new
+    ctx.ca_file = File.join(keysDir, "CA.pem")
+    ctx.cert = OpenSSL::X509::Certificate.new(File.open(File.join(keysDir, "server.crt")))
+    ctx.cert_store = OpenSSL::X509::Store.new
+    ctx.cert_store.add_file(File.join(keysDir, 'client.pem'))
+    ctx.key = OpenSSL::PKey::RSA.new(File.open(File.join(keysDir, "server.key")))
+    ctx.options = OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
+    ctx.ssl_version = :SSLv23
+    ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
+    @transport = Thrift::SSLServerSocket.new(nil, port, ctx)
+  else
+    @transport = Thrift::ServerSocket.new(port)
+  end
+else
+  @transport = Thrift::UNIXServerSocket.new(domain_socket)
+end
+
+@server = Thrift::ThreadedServer.new(@processor, @transport, @transportFactory, @protocolFactory)
+
+puts "Starting TestServer #{@server.to_s}"
+@server.serve
+puts "done."
diff --git a/test/rb/integration/accelerated_buffered_client.rb b/test/rb/integration/accelerated_buffered_client.rb
deleted file mode 100644
index 7cec1df..0000000
--- a/test/rb/integration/accelerated_buffered_client.rb
+++ /dev/null
@@ -1,163 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-require File.join(File.dirname(__FILE__), '../test_helper')
-
-require 'thrift'
-require 'ThriftTest'
-
-class AcceleratedBufferedClientTest < Test::Unit::TestCase
-  def setup
-    unless @socket
-      @socket   = Thrift::Socket.new('localhost', 9090)
-      @protocol = Thrift::BinaryProtocolAccelerated.new(Thrift::BufferedTransport.new(@socket))
-      @client   = Thrift::Test::ThriftTest::Client.new(@protocol)
-      @socket.open
-    end
-  end
-  
-  def test_string
-    assert_equal(@client.testString('string'), 'string')
-  end
-
-  def test_byte
-    val = 8
-    assert_equal(@client.testByte(val), val)
-    assert_equal(@client.testByte(-val), -val)
-  end
-
-  def test_i32
-    val = 32
-    assert_equal(@client.testI32(val), val)
-    assert_equal(@client.testI32(-val), -val)
-  end
-
-  def test_i64
-    val = 64
-    assert_equal(@client.testI64(val), val)
-    assert_equal(@client.testI64(-val), -val)
-  end
-
-  def test_double
-    val = 3.14
-    assert_equal(@client.testDouble(val), val)
-    assert_equal(@client.testDouble(-val), -val)
-    assert_kind_of(Float, @client.testDouble(val))
-  end
-
-  def test_map
-    val = {1 => 1, 2 => 2, 3 => 3}
-    assert_equal(@client.testMap(val), val)
-    assert_kind_of(Hash, @client.testMap(val))
-  end
-
-  def test_list
-    val = [1,2,3,4,5]
-    assert_equal(@client.testList(val), val)
-    assert_kind_of(Array, @client.testList(val))
-  end
-
-  def test_enum
-    val = Thrift::Test::Numberz::SIX
-    ret = @client.testEnum(val)
-
-    assert_equal(ret, 6)
-    assert_kind_of(Fixnum, ret)
-  end
-
-  def test_typedef
-    #UserId  testTypedef(1: UserId thing),
-    true
-  end
-
-  def test_set
-    val = Set.new([1,2,3])
-    assert_equal(@client.testSet(val), val)
-    assert_kind_of(Set, @client.testSet(val))
-  end
-
-  def get_struct
-    Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 })
-  end
-
-  def test_struct
-    ret = @client.testStruct(get_struct)
-
-    assert_nil(ret.byte_thing, nil)
-    assert_nil(ret.i64_thing, nil)
-    assert_equal(ret.string_thing, 'hi!')
-    assert_equal(ret.i32_thing, 4)
-    assert_kind_of(Thrift::Test::Xtruct, ret)
-  end
-
-  def test_nest
-    struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10})
-
-    ret = @client.testNest(struct2)
-
-    assert_nil(ret.struct_thing.byte_thing, nil)
-    assert_nil(ret.struct_thing.i64_thing, nil)
-    assert_equal(ret.struct_thing.string_thing, 'hi!')
-    assert_equal(ret.struct_thing.i32_thing, 4)
-    assert_equal(ret.i32_thing, 10)
-
-    assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing)
-    assert_kind_of(Thrift::Test::Xtruct2, ret)
-  end
-
-  def test_insane
-    insane = Thrift::Test::Insanity.new({
-      'userMap' => { Thrift::Test::Numberz::ONE => 44 },
-      'xtructs' => [get_struct,
-        Thrift::Test::Xtruct.new({
-          'string_thing' => 'hi again',
-          'i32_thing' => 12
-        })
-      ]
-    })
-
-    ret = @client.testInsanity(insane)
-
-    assert_not_nil(ret[44])
-    assert_not_nil(ret[44][1])
-
-    struct = ret[44][1]
-
-    assert_equal(struct.userMap[Thrift::Test::Numberz::ONE], 44)
-    assert_equal(struct.xtructs[1].string_thing, 'hi again')
-    assert_equal(struct.xtructs[1].i32_thing, 12)
-
-    assert_kind_of(Hash, struct.userMap)
-    assert_kind_of(Array, struct.xtructs)
-    assert_kind_of(Thrift::Test::Insanity, struct)
-  end
-
-  def test_map_map
-    ret = @client.testMapMap(4)
-    assert_kind_of(Hash, ret)
-    assert_equal(ret, { 4 => { 4 => 4}})
-  end
-
-  def test_exception
-    assert_raise Thrift::Test::Xception do
-      @client.testException('foo')
-    end
-  end
-end
-
diff --git a/test/rb/integration/accelerated_buffered_server.rb b/test/rb/integration/accelerated_buffered_server.rb
deleted file mode 100644
index 1ca66e5..0000000
--- a/test/rb/integration/accelerated_buffered_server.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-$:.push File.dirname(__FILE__) + '/../gen-rb'
-$:.push File.join(File.dirname(__FILE__), '../../../lib/rb/lib')
-$:.push File.join(File.dirname(__FILE__), '../../../lib/rb/ext')
-
-require 'thrift'
-require 'ThriftTest'
-
-class SimpleHandler
-  [:testString, :testByte, :testI32, :testI64, :testDouble,
-   :testStruct, :testMap, :testSet, :testList, :testNest,
-   :testEnum, :testTypedef].each do |meth|
-
-    define_method(meth) do |thing|
-      thing
-    end
-
-  end
-
-  def testInsanity(thing)
-    num, uid = thing.userMap.find { true }
-    return {uid => {num => thing}}
-  end
-
-  def testMapMap(thing)
-    return {thing => {thing => thing}}
-  end
-
-  def testEnum(thing)
-    return thing
-  end
-
-  def testTypedef(thing)
-    return thing
-  end
-
-  def testException(thing)
-    raise Thrift::Test::Xception, :message => 'error'
-  end
-end
-
-@handler   = SimpleHandler.new
-@processor = Thrift::Test::ThriftTest::Processor.new(@handler)
-@transport = Thrift::ServerSocket.new(9090)
-@server    = Thrift::ThreadedServer.new(@processor, @transport, Thrift::BufferedTransportFactory.new, Thrift::BinaryProtocolAcceleratedFactory.new)
-
-@server.serve
diff --git a/test/rb/integration/buffered_client.rb b/test/rb/integration/buffered_client.rb
deleted file mode 100644
index 1a925cc..0000000
--- a/test/rb/integration/buffered_client.rb
+++ /dev/null
@@ -1,163 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-require File.join(File.dirname(__FILE__), '../test_helper')
-
-require 'thrift'
-require 'ThriftTest'
-
-class BufferedClientTest < Test::Unit::TestCase
-  def setup
-    unless @socket
-      @socket   = Thrift::Socket.new('localhost', 9090)
-      @protocol = Thrift::BinaryProtocol.new(Thrift::BufferedTransport.new(@socket))
-      @client   = Thrift::Test::ThriftTest::Client.new(@protocol)
-      @socket.open
-    end
-  end
-  
-  def test_string
-    assert_equal(@client.testString('string'), 'string')
-  end
-
-  def test_byte
-    val = 8
-    assert_equal(@client.testByte(val), val)
-    assert_equal(@client.testByte(-val), -val)
-  end
-
-  def test_i32
-    val = 32
-    assert_equal(@client.testI32(val), val)
-    assert_equal(@client.testI32(-val), -val)
-  end
-
-  def test_i64
-    val = 64
-    assert_equal(@client.testI64(val), val)
-    assert_equal(@client.testI64(-val), -val)
-  end
-
-  def test_double
-    val = 3.14
-    assert_equal(@client.testDouble(val), val)
-    assert_equal(@client.testDouble(-val), -val)
-    assert_kind_of(Float, @client.testDouble(val))
-  end
-
-  def test_map
-    val = {1 => 1, 2 => 2, 3 => 3}
-    assert_equal(@client.testMap(val), val)
-    assert_kind_of(Hash, @client.testMap(val))
-  end
-
-  def test_list
-    val = [1,2,3,4,5]
-    assert_equal(@client.testList(val), val)
-    assert_kind_of(Array, @client.testList(val))
-  end
-
-  def test_enum
-    val = Thrift::Test::Numberz::SIX
-    ret = @client.testEnum(val)
-
-    assert_equal(ret, 6)
-    assert_kind_of(Fixnum, ret)
-  end
-
-  def test_typedef
-    #UserId  testTypedef(1: UserId thing),
-    true
-  end
-
-  def test_set
-    val = Set.new([1,2,3])
-    assert_equal(@client.testSet(val), val)
-    assert_kind_of(Set, @client.testSet(val))
-  end
-
-  def get_struct
-    Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 })
-  end
-
-  def test_struct
-    ret = @client.testStruct(get_struct)
-
-    assert_nil(ret.byte_thing, nil)
-    assert_nil(ret.i64_thing, nil)
-    assert_equal(ret.string_thing, 'hi!')
-    assert_equal(ret.i32_thing, 4)
-    assert_kind_of(Thrift::Test::Xtruct, ret)
-  end
-
-  def test_nest
-    struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10})
-
-    ret = @client.testNest(struct2)
-
-    assert_nil(ret.struct_thing.byte_thing, nil)
-    assert_nil(ret.struct_thing.i64_thing, nil)
-    assert_equal(ret.struct_thing.string_thing, 'hi!')
-    assert_equal(ret.struct_thing.i32_thing, 4)
-    assert_equal(ret.i32_thing, 10)
-
-    assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing)
-    assert_kind_of(Thrift::Test::Xtruct2, ret)
-  end
-
-  def test_insane
-    insane = Thrift::Test::Insanity.new({
-      'userMap' => { Thrift::Test::Numberz::ONE => 44 },
-      'xtructs' => [get_struct,
-        Thrift::Test::Xtruct.new({
-          'string_thing' => 'hi again',
-          'i32_thing' => 12
-        })
-      ]
-    })
-
-    ret = @client.testInsanity(insane)
-
-    assert_not_nil(ret[44])
-    assert_not_nil(ret[44][1])
-
-    struct = ret[44][1]
-
-    assert_equal(struct.userMap[Thrift::Test::Numberz::ONE], 44)
-    assert_equal(struct.xtructs[1].string_thing, 'hi again')
-    assert_equal(struct.xtructs[1].i32_thing, 12)
-
-    assert_kind_of(Hash, struct.userMap)
-    assert_kind_of(Array, struct.xtructs)
-    assert_kind_of(Thrift::Test::Insanity, struct)
-  end
-
-  def test_map_map
-    ret = @client.testMapMap(4)
-    assert_kind_of(Hash, ret)
-    assert_equal(ret, { 4 => { 4 => 4}})
-  end
-
-  def test_exception
-    assert_raise Thrift::Test::Xception do
-      @client.testException('foo')
-    end
-  end
-end
-
diff --git a/test/rb/integration/simple_client.rb b/test/rb/integration/simple_client.rb
deleted file mode 100644
index 1064822..0000000
--- a/test/rb/integration/simple_client.rb
+++ /dev/null
@@ -1,163 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-require File.join(File.dirname(__FILE__), '../test_helper')
-
-require 'thrift'
-require 'ThriftTest'
-
-class SimpleClientTest < Test::Unit::TestCase
-  def setup    
-    unless @socket
-      @socket   = Thrift::Socket.new('localhost', 9090)
-      @protocol = Thrift::BinaryProtocol.new(@socket)
-      @client   = Thrift::Test::ThriftTest::Client.new(@protocol)
-      @socket.open
-    end
-  end
-  
-  def test_string
-    assert_equal(@client.testString('string'), 'string')
-  end
-
-  def test_byte
-    val = 8
-    assert_equal(@client.testByte(val), val)
-    assert_equal(@client.testByte(-val), -val)
-  end
-
-  def test_i32
-    val = 32
-    assert_equal(@client.testI32(val), val)
-    assert_equal(@client.testI32(-val), -val)
-  end
-
-  def test_i64
-    val = 64
-    assert_equal(@client.testI64(val), val)
-    assert_equal(@client.testI64(-val), -val)
-  end
-
-  def test_double
-    val = 3.14
-    assert_equal(@client.testDouble(val), val)
-    assert_equal(@client.testDouble(-val), -val)
-    assert_kind_of(Float, @client.testDouble(val))
-  end
-
-  def test_map
-    val = {1 => 1, 2 => 2, 3 => 3}
-    assert_equal(@client.testMap(val), val)
-    assert_kind_of(Hash, @client.testMap(val))
-  end
-
-  def test_list
-    val = [1,2,3,4,5]
-    assert_equal(@client.testList(val), val)
-    assert_kind_of(Array, @client.testList(val))
-  end
-
-  def test_enum
-    val = Thrift::Test::Numberz::SIX
-    ret = @client.testEnum(val)
-
-    assert_equal(ret, 6)
-    assert_kind_of(Fixnum, ret)
-  end
-
-  def test_typedef
-    #UserId  testTypedef(1: UserId thing),
-    true
-  end
-
-  def test_set
-    val = Set.new([1,2,3])
-    assert_equal(@client.testSet(val), val)
-    assert_kind_of(Set, @client.testSet(val))
-  end
-
-  def get_struct
-    Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 })
-  end
-
-  def test_struct
-    ret = @client.testStruct(get_struct)
-
-    assert_nil(ret.byte_thing, nil)
-    assert_nil(ret.i64_thing, nil)
-    assert_equal(ret.string_thing, 'hi!')
-    assert_equal(ret.i32_thing, 4)
-    assert_kind_of(Thrift::Test::Xtruct, ret)
-  end
-
-  def test_nest
-    struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10})
-
-    ret = @client.testNest(struct2)
-
-    assert_nil(ret.struct_thing.byte_thing, nil)
-    assert_nil(ret.struct_thing.i64_thing, nil)
-    assert_equal(ret.struct_thing.string_thing, 'hi!')
-    assert_equal(ret.struct_thing.i32_thing, 4)
-    assert_equal(ret.i32_thing, 10)
-
-    assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing)
-    assert_kind_of(Thrift::Test::Xtruct2, ret)
-  end
-
-  def test_insane
-    insane = Thrift::Test::Insanity.new({
-      'userMap' => { Thrift::Test::Numberz::ONE => 44 },
-      'xtructs' => [get_struct,
-        Thrift::Test::Xtruct.new({
-          'string_thing' => 'hi again',
-          'i32_thing' => 12
-        })
-      ]
-    })
-
-    ret = @client.testInsanity(insane)
-
-    assert_not_nil(ret[44])
-    assert_not_nil(ret[44][1])
-
-    struct = ret[44][1]
-
-    assert_equal(struct.userMap[Thrift::Test::Numberz::ONE], 44)
-    assert_equal(struct.xtructs[1].string_thing, 'hi again')
-    assert_equal(struct.xtructs[1].i32_thing, 12)
-
-    assert_kind_of(Hash, struct.userMap)
-    assert_kind_of(Array, struct.xtructs)
-    assert_kind_of(Thrift::Test::Insanity, struct)
-  end
-
-  def test_map_map
-    ret = @client.testMapMap(4)
-    assert_kind_of(Hash, ret)
-    assert_equal(ret, { 4 => { 4 => 4}})
-  end
-
-  def test_exception
-    assert_raise Thrift::Test::Xception do
-      @client.testException('foo')
-    end
-  end
-end
-
diff --git a/test/rb/integration/simple_server.rb b/test/rb/integration/simple_server.rb
deleted file mode 100644
index 3518d2e..0000000
--- a/test/rb/integration/simple_server.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-$:.push File.dirname(__FILE__) + '/../gen-rb'
-$:.push File.join(File.dirname(__FILE__), '../../../lib/rb/lib')
-
-require 'thrift'
-require 'ThriftTest'
-
-class SimpleHandler
-  [:testString, :testByte, :testI32, :testI64, :testDouble,
-   :testStruct, :testMap, :testSet, :testList, :testNest,
-   :testEnum, :testTypedef].each do |meth|
-
-    define_method(meth) do |thing|
-      thing
-    end
-
-  end
-
-  def testInsanity(thing)
-    num, uid = thing.userMap.find { true }
-    return {uid => {num => thing}}
-  end
-
-  def testMapMap(thing)
-    return {thing => {thing => thing}}
-  end
-
-  def testEnum(thing)
-    return thing
-  end
-
-  def testTypedef(thing)
-    return thing
-  end
-
-  def testException(thing)
-    raise Thrift::Test::Xception, :message => 'error'
-  end
-end
-
-@handler   = SimpleHandler.new
-@processor = Thrift::Test::ThriftTest::Processor.new(@handler)
-@transport = Thrift::ServerSocket.new(9090)
-@server    = Thrift::ThreadedServer.new(@processor, @transport)
-
-@server.serve
diff --git a/test/rb/integration/test_simple_handler.rb b/test/rb/integration/test_simple_handler.rb
deleted file mode 100644
index c34aa7e..0000000
--- a/test/rb/integration/test_simple_handler.rb
+++ /dev/null
@@ -1,211 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-require File.join(File.dirname(__FILE__), '../test_helper')
-
-require 'thrift'
-require 'ThriftTest'
-
-class TestHandler
-  [:testString, :testByte, :testI32, :testI64, :testDouble,
-   :testStruct, :testMap, :testSet, :testList, :testNest,
-   :testEnum, :testTypedef].each do |meth|
-
-    define_method(meth) do |thing|
-      thing
-    end
-
-  end
-
-  def testInsanity(thing)
-    num, uid = thing.userMap.find { true }
-    return {uid => {num => thing}}
-  end
-
-  def testMapMap(thing)
-    return {thing => {thing => thing}}
-  end
-
-  def testEnum(thing)
-    return thing
-  end
-
-  def testTypedef(thing)
-    return thing
-  end
-
-  def testException(thing)
-    raise Thrift::Test::Xception, :message => 'error'
-  end
-
-end
-class TestThrift < Test::Unit::TestCase
-
-  @@INIT = nil
-
-  def setup
-    if @@INIT.nil?
-      # Initialize the server
-      @handler   = TestHandler.new()
-      @processor = Thrift::Test::ThriftTest::Processor.new(@handler)
-      @transport = Thrift::ServerSocket.new(9090)
-      @server    = Thrift::ThreadedServer.new(@processor, @transport)
-
-      @thread    = Thread.new { @server.serve }
-
-      # And the Client
-      @socket   = Thrift::Socket.new('localhost', 9090)
-      @protocol = Thrift::BinaryProtocol.new(@socket)
-      @client   = Thrift::Test::ThriftTest::Client.new(@protocol)
-      @socket.open
-    end
-  end
-
-  def test_string
-    assert_equal(@client.testString('string'), 'string')
-  end
-
-  def test_byte
-    val = 8
-    assert_equal(@client.testByte(val), val)
-    assert_equal(@client.testByte(-val), -val)
-  end
-
-  def test_i32
-    val = 32
-    assert_equal(@client.testI32(val), val)
-    assert_equal(@client.testI32(-val), -val)
-  end
-
-  def test_i64
-    val = 64
-    assert_equal(@client.testI64(val), val)
-    assert_equal(@client.testI64(-val), -val)
-  end
-
-  def test_double
-    val = 3.14
-    assert_equal(@client.testDouble(val), val)
-    assert_equal(@client.testDouble(-val), -val)
-    assert_kind_of(Float, @client.testDouble(val))
-  end
-
-  def test_map
-    val = {1 => 1, 2 => 2, 3 => 3}
-    assert_equal(@client.testMap(val), val)
-    assert_kind_of(Hash, @client.testMap(val))
-  end
-
-  def test_list
-    val = [1,2,3,4,5]
-    assert_equal(@client.testList(val), val)
-    assert_kind_of(Array, @client.testList(val))
-  end
-
-  def test_enum
-    val = Thrift::Test::Numberz::SIX
-    ret = @client.testEnum(val)
-
-    assert_equal(ret, 6)
-    assert_kind_of(Fixnum, ret)
-  end
-
-  def test_typedef
-    #UserId  testTypedef(1: UserId thing),
-    true
-  end
-
-  def test_set
-    val = Set.new([1, 2, 3])
-    assert_equal(val, @client.testSet(val))
-    assert_kind_of(Set, @client.testSet(val))
-  end
-
-  def get_struct
-    Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 })
-  end
-
-  def test_struct
-    ret = @client.testStruct(get_struct)
-
-    assert_nil(ret.byte_thing, nil)
-    assert_nil(ret.i64_thing, nil)
-    assert_equal(ret.string_thing, 'hi!')
-    assert_equal(ret.i32_thing, 4)
-    assert_kind_of(Thrift::Test::Xtruct, ret)
-  end
-
-  def test_nest
-    struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10})
-
-    ret = @client.testNest(struct2)
-
-    assert_nil(ret.struct_thing.byte_thing, nil)
-    assert_nil(ret.struct_thing.i64_thing, nil)
-    assert_equal(ret.struct_thing.string_thing, 'hi!')
-    assert_equal(ret.struct_thing.i32_thing, 4)
-    assert_equal(ret.i32_thing, 10)
-
-    assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing)
-    assert_kind_of(Thrift::Test::Xtruct2, ret)
-  end
-
-  def test_insane
-    insane = Thrift::Test::Insanity.new({
-      'userMap' => { Thrift::Test::Numberz::ONE => 44 },
-      'xtructs' => [get_struct,
-        Thrift::Test::Xtruct.new({
-          'string_thing' => 'hi again',
-          'i32_thing' => 12
-        })
-      ]
-    })
-
-    ret = @client.testInsanity(insane)
-
-    assert_not_nil(ret[44])
-    assert_not_nil(ret[44][1])
-
-    struct = ret[44][1]
-
-    assert_equal(struct.userMap[Thrift::Test::Numberz::ONE], 44)
-    assert_equal(struct.xtructs[1].string_thing, 'hi again')
-    assert_equal(struct.xtructs[1].i32_thing, 12)
-
-    assert_kind_of(Hash, struct.userMap)
-    assert_kind_of(Array, struct.xtructs)
-    assert_kind_of(Thrift::Test::Insanity, struct)
-  end
-
-  def test_map_map
-    ret = @client.testMapMap(4)
-    assert_kind_of(Hash, ret)
-    assert_equal(ret, { 4 => { 4 => 4}})
-  end
-
-  def test_exception
-    assert_raise Thrift::Test::Xception do
-      @client.testException('foo')
-    end
-  end
-
-  def teardown
-  end
-
-end
diff --git a/test/rebuild_known_failures.sh b/test/rebuild_known_failures.sh
new file mode 100644
index 0000000..08869fe
--- /dev/null
+++ b/test/rebuild_known_failures.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+if [ -z $1 ]; then
+  echo Usage: $0 LANGUAGE
+  echo Re-list all failures of a specific LANGUAGE into known_failures_Linux.json
+  echo LANGUAGE should be library name like cpp, java, py etc
+  exit 1
+fi
+
+if [ -z $PYTHON]; then
+  PYTHON=python
+fi
+
+TARGET_LANG=$1
+OUT_FILE=known_failures_Linux.json
+echo Rebuilding known failures for $TARGET_LANG
+
+TMPFILE=.__tmp__rebuild__
+grep -v -e "\"$1-" -e "\-$1_" $OUT_FILE > $TMPFILE
+mv $TMPFILE $OUT_FILE
+$PYTHON test.py --client $1
+$PYTHON test.py -U merge
+$PYTHON test.py --server $1
+$PYTHON test.py -U merge
diff --git a/test/result.js b/test/result.js
new file mode 100644
index 0000000..18b1a59
--- /dev/null
+++ b/test/result.js
@@ -0,0 +1,64 @@
+/*
+ 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.
+
+*/
+
+$.getJSON('results.json', function(results) {
+    $(document).ready(function() {
+        var transport = 3;
+        var socket = 4;
+        var success = 5;
+        var expected = 6;
+        var returnCode = 7;
+        var logFile = 8;
+        testTable = $('#test_results').DataTable({
+            data: results['results'],
+            columnDefs: [
+                {
+                    targets: 3,
+                    render: function(data, type, row) {
+                        return row[transport] + '-' + row[socket];
+                    },
+                },
+                {
+                    targets: 4,
+                    render: function(data, type, row) {
+                        return (row[success] ? 'success' : 'failure')
+                                + '(' + (row[returnCode] == 128 ? 'timeout' : row[returnCode]) + ')'
+                                + '(<a href="' + row[logFile].server + '">Server</a>, '
+                                + '<a href="' + row[logFile].client + '">Client</a>)';
+                    },
+                },
+                {
+                    targets: 5,
+                    render: function(data, type, row) {
+                        // 'yes' rather than 'expected' to ease search
+                        return row[expected] ? 'yes' : 'unexpected';
+                    },
+                }
+            ],
+        });
+        $('#test_results_filter label input').focus().val('unexpected failure');
+        $('#test_info').text(
+            "Test Date:     " + results['date'] + "\n" +
+            "Revision:      " + results['revision'] + "\n" +
+            "Platform:      " + results['platform'] + "\n" +
+            "Test duration: " + results['duration']) + " seconds";
+    });
+});
+
diff --git a/test/rs/Cargo.toml b/test/rs/Cargo.toml
new file mode 100644
index 0000000..9b35e3c
--- /dev/null
+++ b/test/rs/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "thrift-test"
+version = "0.1.0"
+license = "Apache-2.0"
+authors = ["Apache Thrift Developers <dev@thrift.apache.org>"]
+publish = false
+
+[dependencies]
+clap = "<2.28.0"
+env_logger = "0.4.0"
+log = "0.3.7"
+ordered-float = "0.3.0"
+try_from = "0.2.0"
+
+[dependencies.thrift]
+path = "../../lib/rs"
+
diff --git a/test/rs/Makefile.am b/test/rs/Makefile.am
new file mode 100644
index 0000000..54905b4
--- /dev/null
+++ b/test/rs/Makefile.am
@@ -0,0 +1,40 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) -I ./thrifts -out src --gen rs ../ThriftTest.thrift
+
+precross: stubs
+	$(CARGO) build
+	[ -d bin ] || mkdir bin
+	cp target/debug/test_server bin/test_server
+	cp target/debug/test_client bin/test_client
+
+clean-local:
+	$(CARGO) clean
+	-$(RM) Cargo.lock
+	-$(RM) src/thrift_test.rs
+	-$(RM) -r bin
+
+EXTRA_DIST = \
+	Cargo.toml \
+        src/lib.rs \
+	src/bin/test_server.rs \
+	src/bin/test_client.rs
+
diff --git a/test/rs/src/bin/test_client.rs b/test/rs/src/bin/test_client.rs
new file mode 100644
index 0000000..29b5b88
--- /dev/null
+++ b/test/rs/src/bin/test_client.rs
@@ -0,0 +1,605 @@
+// 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.
+
+#[macro_use]
+extern crate log;
+extern crate env_logger;
+
+#[macro_use]
+extern crate clap;
+extern crate ordered_float;
+extern crate thrift;
+extern crate thrift_test; // huh. I have to do this to use my lib
+
+use ordered_float::OrderedFloat;
+use std::collections::{BTreeMap, BTreeSet};
+use std::fmt::Debug;
+
+use thrift::protocol::{TBinaryInputProtocol, TBinaryOutputProtocol, TCompactInputProtocol,
+                       TCompactOutputProtocol, TInputProtocol, TMultiplexedOutputProtocol,
+                       TOutputProtocol};
+use thrift::transport::{ReadHalf, TBufferedReadTransport, TBufferedWriteTransport,
+                        TFramedReadTransport, TFramedWriteTransport, TIoChannel, TReadTransport,
+                        TTcpChannel, TWriteTransport, WriteHalf};
+use thrift_test::*;
+
+fn main() {
+    env_logger::init().expect("logger setup failed");
+
+    debug!("initialized logger - running cross-test client");
+
+    match run() {
+        Ok(()) => info!("cross-test client succeeded"),
+        Err(e) => {
+            info!("cross-test client failed with error {:?}", e);
+            std::process::exit(1);
+        }
+    }
+}
+
+fn run() -> thrift::Result<()> {
+    // unsupported options:
+    // --domain-socket
+    // --named-pipe
+    // --anon-pipes
+    // --ssl
+    // --threads
+    let matches = clap_app!(rust_test_client =>
+        (version: "1.0")
+        (author: "Apache Thrift Developers <dev@thrift.apache.org>")
+        (about: "Rust Thrift test client")
+        (@arg host: --host +takes_value "Host on which the Thrift test server is located")
+        (@arg port: --port +takes_value "Port on which the Thrift test server is listening")
+        (@arg transport: --transport +takes_value "Thrift transport implementation to use (\"buffered\", \"framed\")")
+        (@arg protocol: --protocol +takes_value "Thrift protocol implementation to use (\"binary\", \"compact\")")
+        (@arg testloops: -n --testloops +takes_value "Number of times to run tests")
+    )
+        .get_matches();
+
+    let host = matches.value_of("host").unwrap_or("127.0.0.1");
+    let port = value_t!(matches, "port", u16).unwrap_or(9090);
+    let testloops = value_t!(matches, "testloops", u8).unwrap_or(1);
+    let transport = matches.value_of("transport").unwrap_or("buffered");
+    let protocol = matches.value_of("protocol").unwrap_or("binary");
+
+
+    let mut thrift_test_client = {
+        let (i_prot, o_prot) = build_protocols(host, port, transport, protocol, "ThriftTest")?;
+        ThriftTestSyncClient::new(i_prot, o_prot)
+    };
+
+    let mut second_service_client = if protocol.starts_with("multi") {
+        let (i_prot, o_prot) = build_protocols(host, port, transport, protocol, "SecondService")?;
+        Some(SecondServiceSyncClient::new(i_prot, o_prot))
+    } else {
+        None
+    };
+
+    info!(
+        "connecting to {}:{} with {}+{} stack",
+        host,
+        port,
+        protocol,
+        transport
+    );
+
+    for _ in 0..testloops {
+        make_thrift_calls(&mut thrift_test_client, &mut second_service_client)?
+    }
+
+    Ok(())
+}
+
+fn build_protocols(
+    host: &str,
+    port: u16,
+    transport: &str,
+    protocol: &str,
+    service_name: &str,
+) -> thrift::Result<(Box<TInputProtocol>, Box<TOutputProtocol>)> {
+    let (i_chan, o_chan) = tcp_channel(host, port)?;
+
+    let (i_tran, o_tran): (Box<TReadTransport>, Box<TWriteTransport>) = match transport {
+        "buffered" => {
+            (Box::new(TBufferedReadTransport::new(i_chan)),
+             Box::new(TBufferedWriteTransport::new(o_chan)))
+        }
+        "framed" => {
+            (Box::new(TFramedReadTransport::new(i_chan)),
+             Box::new(TFramedWriteTransport::new(o_chan)))
+        }
+        unmatched => return Err(format!("unsupported transport {}", unmatched).into()),
+    };
+
+    let (i_prot, o_prot): (Box<TInputProtocol>, Box<TOutputProtocol>) = match protocol {
+        "binary" => {
+            (Box::new(TBinaryInputProtocol::new(i_tran, true)),
+             Box::new(TBinaryOutputProtocol::new(o_tran, true)))
+        }
+        "multi" => {
+            (Box::new(TBinaryInputProtocol::new(i_tran, true)),
+             Box::new(
+                TMultiplexedOutputProtocol::new(
+                    service_name,
+                    TBinaryOutputProtocol::new(o_tran, true),
+                ),
+            ))
+        }
+        "compact" => {
+            (Box::new(TCompactInputProtocol::new(i_tran)),
+             Box::new(TCompactOutputProtocol::new(o_tran)))
+        }
+        "multic" => {
+            (Box::new(TCompactInputProtocol::new(i_tran)),
+             Box::new(TMultiplexedOutputProtocol::new(service_name, TCompactOutputProtocol::new(o_tran)),))
+        }
+        unmatched => return Err(format!("unsupported protocol {}", unmatched).into()),
+    };
+
+    Ok((i_prot, o_prot))
+}
+
+// FIXME: expose "open" through the client interface so I don't have to early
+// open
+fn tcp_channel(
+    host: &str,
+    port: u16,
+) -> thrift::Result<(ReadHalf<TTcpChannel>, WriteHalf<TTcpChannel>)> {
+    let mut c = TTcpChannel::new();
+    c.open(&format!("{}:{}", host, port))?;
+    c.split()
+}
+
+type BuildThriftTestClient = ThriftTestSyncClient<Box<TInputProtocol>, Box<TOutputProtocol>>;
+type BuiltSecondServiceClient = SecondServiceSyncClient<Box<TInputProtocol>, Box<TOutputProtocol>>;
+
+#[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
+fn make_thrift_calls(
+    thrift_test_client: &mut BuildThriftTestClient,
+    second_service_client: &mut Option<BuiltSecondServiceClient>,
+) -> Result<(), thrift::Error> {
+    info!("testVoid");
+    thrift_test_client.test_void()?;
+
+    info!("testString");
+    verify_expected_result(
+        thrift_test_client.test_string("thing".to_owned()),
+        "thing".to_owned(),
+    )?;
+
+    info!("testBool");
+    verify_expected_result(thrift_test_client.test_bool(true), true)?;
+
+    info!("testBool");
+    verify_expected_result(thrift_test_client.test_bool(false), false)?;
+
+    info!("testByte");
+    verify_expected_result(thrift_test_client.test_byte(42), 42)?;
+
+    info!("testi32");
+    verify_expected_result(thrift_test_client.test_i32(1159348374), 1159348374)?;
+
+    info!("testi64");
+    // try!(verify_expected_result(thrift_test_client.test_i64(-8651829879438294565),
+    // -8651829879438294565));
+    verify_expected_result(
+        thrift_test_client.test_i64(i64::min_value()),
+        i64::min_value(),
+    )?;
+
+    info!("testDouble");
+    verify_expected_result(
+        thrift_test_client.test_double(OrderedFloat::from(42.42)),
+        OrderedFloat::from(42.42),
+    )?;
+
+    info!("testTypedef");
+    {
+        let u_snd: UserId = 2348;
+        let u_cmp: UserId = 2348;
+        verify_expected_result(thrift_test_client.test_typedef(u_snd), u_cmp)?;
+    }
+
+    info!("testEnum");
+    {
+        verify_expected_result(thrift_test_client.test_enum(Numberz::Two), Numberz::Two)?;
+    }
+
+    info!("testBinary");
+    {
+        let b_snd = vec![0x77, 0x30, 0x30, 0x74, 0x21, 0x20, 0x52, 0x75, 0x73, 0x74];
+        let b_cmp = vec![0x77, 0x30, 0x30, 0x74, 0x21, 0x20, 0x52, 0x75, 0x73, 0x74];
+        verify_expected_result(thrift_test_client.test_binary(b_snd), b_cmp)?;
+    }
+
+    info!("testStruct");
+    {
+        let x_snd = Xtruct {
+            string_thing: Some("foo".to_owned()),
+            byte_thing: Some(12),
+            i32_thing: Some(219129),
+            i64_thing: Some(12938492818),
+        };
+        let x_cmp = Xtruct {
+            string_thing: Some("foo".to_owned()),
+            byte_thing: Some(12),
+            i32_thing: Some(219129),
+            i64_thing: Some(12938492818),
+        };
+        verify_expected_result(thrift_test_client.test_struct(x_snd), x_cmp)?;
+    }
+
+    // Xtruct again, with optional values
+    // FIXME: apparently the erlang thrift server does not like opt-in-req-out
+    // parameters that are undefined. Joy.
+    // {
+    // let x_snd = Xtruct { string_thing: Some("foo".to_owned()), byte_thing: None,
+    // i32_thing: None, i64_thing: Some(12938492818) };
+    // let x_cmp = Xtruct { string_thing: Some("foo".to_owned()), byte_thing:
+    // Some(0), i32_thing: Some(0), i64_thing: Some(12938492818) }; // the C++
+    // server is responding correctly
+    // try!(verify_expected_result(thrift_test_client.test_struct(x_snd), x_cmp));
+    // }
+    //
+
+    info!("testNest"); // (FIXME: try Xtruct2 with optional values)
+    {
+        let x_snd = Xtruct2 {
+            byte_thing: Some(32),
+            struct_thing: Some(
+                Xtruct {
+                    string_thing: Some("foo".to_owned()),
+                    byte_thing: Some(1),
+                    i32_thing: Some(324382098),
+                    i64_thing: Some(12938492818),
+                },
+            ),
+            i32_thing: Some(293481098),
+        };
+        let x_cmp = Xtruct2 {
+            byte_thing: Some(32),
+            struct_thing: Some(
+                Xtruct {
+                    string_thing: Some("foo".to_owned()),
+                    byte_thing: Some(1),
+                    i32_thing: Some(324382098),
+                    i64_thing: Some(12938492818),
+                },
+            ),
+            i32_thing: Some(293481098),
+        };
+        verify_expected_result(thrift_test_client.test_nest(x_snd), x_cmp)?;
+    }
+
+    // do the multiplexed calls while making the main ThriftTest calls
+    if let Some(ref mut client) = second_service_client.as_mut() {
+        info!("SecondService secondtestString");
+        {
+            verify_expected_result(
+                client.secondtest_string("test_string".to_owned()),
+                "testString(\"test_string\")".to_owned(),
+            )?;
+        }
+    }
+
+    info!("testList");
+    {
+        let mut v_snd: Vec<i32> = Vec::new();
+        v_snd.push(29384);
+        v_snd.push(238);
+        v_snd.push(32498);
+
+        let mut v_cmp: Vec<i32> = Vec::new();
+        v_cmp.push(29384);
+        v_cmp.push(238);
+        v_cmp.push(32498);
+
+        verify_expected_result(thrift_test_client.test_list(v_snd), v_cmp)?;
+    }
+
+    info!("testSet");
+    {
+        let mut s_snd: BTreeSet<i32> = BTreeSet::new();
+        s_snd.insert(293481);
+        s_snd.insert(23);
+        s_snd.insert(3234);
+
+        let mut s_cmp: BTreeSet<i32> = BTreeSet::new();
+        s_cmp.insert(293481);
+        s_cmp.insert(23);
+        s_cmp.insert(3234);
+
+        verify_expected_result(thrift_test_client.test_set(s_snd), s_cmp)?;
+    }
+
+    info!("testMap");
+    {
+        let mut m_snd: BTreeMap<i32, i32> = BTreeMap::new();
+        m_snd.insert(2, 4);
+        m_snd.insert(4, 6);
+        m_snd.insert(8, 7);
+
+        let mut m_cmp: BTreeMap<i32, i32> = BTreeMap::new();
+        m_cmp.insert(2, 4);
+        m_cmp.insert(4, 6);
+        m_cmp.insert(8, 7);
+
+        verify_expected_result(thrift_test_client.test_map(m_snd), m_cmp)?;
+    }
+
+    info!("testStringMap");
+    {
+        let mut m_snd: BTreeMap<String, String> = BTreeMap::new();
+        m_snd.insert("2".to_owned(), "4_string".to_owned());
+        m_snd.insert("4".to_owned(), "6_string".to_owned());
+        m_snd.insert("8".to_owned(), "7_string".to_owned());
+
+        let mut m_rcv: BTreeMap<String, String> = BTreeMap::new();
+        m_rcv.insert("2".to_owned(), "4_string".to_owned());
+        m_rcv.insert("4".to_owned(), "6_string".to_owned());
+        m_rcv.insert("8".to_owned(), "7_string".to_owned());
+
+        verify_expected_result(thrift_test_client.test_string_map(m_snd), m_rcv)?;
+    }
+
+    // nested map
+    // expect : {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2
+    // => 2, 3 => 3, 4 => 4, }, }
+    info!("testMapMap");
+    {
+        let mut m_cmp_nested_0: BTreeMap<i32, i32> = BTreeMap::new();
+        for i in (-4 as i32)..0 {
+            m_cmp_nested_0.insert(i, i);
+        }
+        let mut m_cmp_nested_1: BTreeMap<i32, i32> = BTreeMap::new();
+        for i in 1..5 {
+            m_cmp_nested_1.insert(i, i);
+        }
+
+        let mut m_cmp: BTreeMap<i32, BTreeMap<i32, i32>> = BTreeMap::new();
+        m_cmp.insert(-4, m_cmp_nested_0);
+        m_cmp.insert(4, m_cmp_nested_1);
+
+        verify_expected_result(thrift_test_client.test_map_map(42), m_cmp)?;
+    }
+
+    info!("testMulti");
+    {
+        let mut m_snd: BTreeMap<i16, String> = BTreeMap::new();
+        m_snd.insert(1298, "fizz".to_owned());
+        m_snd.insert(-148, "buzz".to_owned());
+
+        let s_cmp = Xtruct {
+            string_thing: Some("Hello2".to_owned()),
+            byte_thing: Some(1),
+            i32_thing: Some(-123948),
+            i64_thing: Some(-19234123981),
+        };
+
+        verify_expected_result(
+            thrift_test_client.test_multi(1, -123948, -19234123981, m_snd, Numberz::Eight, 81),
+            s_cmp,
+        )?;
+    }
+
+    // Insanity
+    // returns:
+    // { 1 => { 2 => argument,
+    //          3 => argument,
+    //        },
+    //   2 => { 6 => <empty Insanity struct>, },
+    // }
+    {
+        let mut arg_map_usermap: BTreeMap<Numberz, i64> = BTreeMap::new();
+        arg_map_usermap.insert(Numberz::One, 4289);
+        arg_map_usermap.insert(Numberz::Eight, 19);
+
+        let mut arg_vec_xtructs: Vec<Xtruct> = Vec::new();
+        arg_vec_xtructs.push(
+            Xtruct {
+                string_thing: Some("foo".to_owned()),
+                byte_thing: Some(8),
+                i32_thing: Some(29),
+                i64_thing: Some(92384),
+            },
+        );
+        arg_vec_xtructs.push(
+            Xtruct {
+                string_thing: Some("bar".to_owned()),
+                byte_thing: Some(28),
+                i32_thing: Some(2),
+                i64_thing: Some(-1281),
+            },
+        );
+        arg_vec_xtructs.push(
+            Xtruct {
+                string_thing: Some("baz".to_owned()),
+                byte_thing: Some(0),
+                i32_thing: Some(3948539),
+                i64_thing: Some(-12938492),
+            },
+        );
+
+        let mut s_cmp_nested_1: BTreeMap<Numberz, Insanity> = BTreeMap::new();
+        let insanity = Insanity {
+            user_map: Some(arg_map_usermap),
+            xtructs: Some(arg_vec_xtructs),
+        };
+        s_cmp_nested_1.insert(Numberz::Two, insanity.clone());
+        s_cmp_nested_1.insert(Numberz::Three, insanity.clone());
+
+        let mut s_cmp_nested_2: BTreeMap<Numberz, Insanity> = BTreeMap::new();
+        let empty_insanity = Insanity {
+            user_map: Some(BTreeMap::new()),
+            xtructs: Some(Vec::new()),
+        };
+        s_cmp_nested_2.insert(Numberz::Six, empty_insanity);
+
+        let mut s_cmp: BTreeMap<UserId, BTreeMap<Numberz, Insanity>> = BTreeMap::new();
+        s_cmp.insert(1 as UserId, s_cmp_nested_1);
+        s_cmp.insert(2 as UserId, s_cmp_nested_2);
+
+        verify_expected_result(thrift_test_client.test_insanity(insanity.clone()), s_cmp)?;
+    }
+
+    info!("testException - remote throws Xception");
+    {
+        let r = thrift_test_client.test_exception("Xception".to_owned());
+        let x = match r {
+            Err(thrift::Error::User(ref e)) => {
+                match e.downcast_ref::<Xception>() {
+                    Some(x) => Ok(x),
+                    None => Err(thrift::Error::User("did not get expected Xception struct".into()),),
+                }
+            }
+            _ => Err(thrift::Error::User("did not get exception".into())),
+        }?;
+
+        let x_cmp = Xception {
+            error_code: Some(1001),
+            message: Some("Xception".to_owned()),
+        };
+
+        verify_expected_result(Ok(x), &x_cmp)?;
+    }
+
+    info!("testException - remote throws TApplicationException");
+    {
+        let r = thrift_test_client.test_exception("TException".to_owned());
+        match r {
+            Err(thrift::Error::Application(ref e)) => {
+                info!("received an {:?}", e);
+                Ok(())
+            }
+            _ => Err(thrift::Error::User("did not get exception".into())),
+        }?;
+    }
+
+    info!("testException - remote succeeds");
+    {
+        let r = thrift_test_client.test_exception("foo".to_owned());
+        match r {
+            Ok(_) => Ok(()),
+            _ => Err(thrift::Error::User("received an exception".into())),
+        }?;
+    }
+
+    info!("testMultiException - remote throws Xception");
+    {
+        let r =
+            thrift_test_client.test_multi_exception("Xception".to_owned(), "ignored".to_owned());
+        let x = match r {
+            Err(thrift::Error::User(ref e)) => {
+                match e.downcast_ref::<Xception>() {
+                    Some(x) => Ok(x),
+                    None => Err(thrift::Error::User("did not get expected Xception struct".into()),),
+                }
+            }
+            _ => Err(thrift::Error::User("did not get exception".into())),
+        }?;
+
+        let x_cmp = Xception {
+            error_code: Some(1001),
+            message: Some("This is an Xception".to_owned()),
+        };
+
+        verify_expected_result(Ok(x), &x_cmp)?;
+    }
+
+    info!("testMultiException - remote throws Xception2");
+    {
+        let r =
+            thrift_test_client.test_multi_exception("Xception2".to_owned(), "ignored".to_owned());
+        let x = match r {
+            Err(thrift::Error::User(ref e)) => {
+                match e.downcast_ref::<Xception2>() {
+                    Some(x) => Ok(x),
+                    None => Err(thrift::Error::User("did not get expected Xception struct".into()),),
+                }
+            }
+            _ => Err(thrift::Error::User("did not get exception".into())),
+        }?;
+
+        let x_cmp = Xception2 {
+            error_code: Some(2002),
+            struct_thing: Some(
+                Xtruct {
+                    string_thing: Some("This is an Xception2".to_owned()),
+                    // since this is an OPT_IN_REQ_OUT field the sender sets a default
+                    byte_thing: Some(0),
+                    // since this is an OPT_IN_REQ_OUT field the sender sets a default
+                    i32_thing: Some(0),
+                    // since this is an OPT_IN_REQ_OUT field the sender sets a default
+                    i64_thing: Some(0),
+                },
+            ),
+        };
+
+        verify_expected_result(Ok(x), &x_cmp)?;
+    }
+
+    info!("testMultiException - remote succeeds");
+    {
+        let r = thrift_test_client.test_multi_exception("haha".to_owned(), "RETURNED".to_owned());
+        let x = match r {
+            Err(e) => Err(thrift::Error::User(format!("received an unexpected exception {:?}", e).into(),),),
+            _ => r,
+        }?;
+
+        let x_cmp = Xtruct {
+            string_thing: Some("RETURNED".to_owned()),
+            // since this is an OPT_IN_REQ_OUT field the sender sets a default
+            byte_thing: Some(0),
+            // since this is an OPT_IN_REQ_OUT field the sender sets a default
+            i32_thing: Some(0),
+            // since this is an OPT_IN_REQ_OUT field the sender sets a default
+            i64_thing: Some(0),
+        };
+
+        verify_expected_result(Ok(x), x_cmp)?;
+    }
+
+    info!("testOneWay - remote sleeps for 1 second");
+    {
+        thrift_test_client.test_oneway(1)?;
+    }
+
+    // final test to verify that the connection is still writable after the one-way
+    // call
+    thrift_test_client.test_void()
+}
+
+#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
+fn verify_expected_result<T: Debug + PartialEq + Sized>(
+    actual: Result<T, thrift::Error>,
+    expected: T,
+) -> Result<(), thrift::Error> {
+    info!("*** EXPECTED: Ok({:?})", expected);
+    info!("*** ACTUAL  : {:?}", actual);
+    match actual {
+        Ok(v) => {
+            if v == expected {
+                info!("*** OK ***");
+                Ok(())
+            } else {
+                info!("*** FAILED ***");
+                Err(thrift::Error::User(format!("expected {:?} but got {:?}", &expected, &v).into()),)
+            }
+        }
+        Err(e) => Err(e),
+    }
+}
diff --git a/test/rs/src/bin/test_server.rs b/test/rs/src/bin/test_server.rs
new file mode 100644
index 0000000..81c1ec7
--- /dev/null
+++ b/test/rs/src/bin/test_server.rs
@@ -0,0 +1,398 @@
+// 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.
+
+#[macro_use]
+extern crate log;
+extern crate env_logger;
+
+#[macro_use]
+extern crate clap;
+extern crate ordered_float;
+extern crate thrift;
+extern crate thrift_test;
+
+use ordered_float::OrderedFloat;
+use std::collections::{BTreeMap, BTreeSet};
+use std::thread;
+use std::time::Duration;
+
+use thrift::protocol::{TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory,
+                       TCompactInputProtocolFactory, TCompactOutputProtocolFactory,
+                       TInputProtocolFactory, TOutputProtocolFactory};
+use thrift::server::{TMultiplexedProcessor, TServer};
+use thrift::transport::{TBufferedReadTransportFactory, TBufferedWriteTransportFactory,
+                        TFramedReadTransportFactory, TFramedWriteTransportFactory,
+                        TReadTransportFactory, TWriteTransportFactory};
+use thrift_test::*;
+
+fn main() {
+    env_logger::init().expect("logger setup failed");
+
+    debug!("initialized logger - running cross-test server");
+
+    match run() {
+        Ok(()) => info!("cross-test server succeeded"),
+        Err(e) => {
+            info!("cross-test server failed with error {:?}", e);
+            std::process::exit(1);
+        }
+    }
+}
+
+fn run() -> thrift::Result<()> {
+
+    // unsupported options:
+    // --domain-socket
+    // --named-pipe
+    // --ssl
+    let matches = clap_app!(rust_test_client =>
+        (version: "1.0")
+        (author: "Apache Thrift Developers <dev@thrift.apache.org>")
+        (about: "Rust Thrift test server")
+        (@arg port: --port +takes_value "port on which the test server listens")
+        (@arg transport: --transport +takes_value "transport implementation to use (\"buffered\", \"framed\")")
+        (@arg protocol: --protocol +takes_value "protocol implementation to use (\"binary\", \"compact\")")
+        (@arg server_type: --server_type +takes_value "type of server instantiated (\"simple\", \"thread-pool\")")
+        (@arg workers: -n --workers +takes_value "number of thread-pool workers (\"4\")")
+    )
+            .get_matches();
+
+    let port = value_t!(matches, "port", u16).unwrap_or(9090);
+    let transport = matches.value_of("transport").unwrap_or("buffered");
+    let protocol = matches.value_of("protocol").unwrap_or("binary");
+    let server_type = matches.value_of("server_type").unwrap_or("thread-pool");
+    let workers = value_t!(matches, "workers", usize).unwrap_or(4);
+    let listen_address = format!("127.0.0.1:{}", port);
+
+    info!("binding to {}", listen_address);
+
+    let (i_transport_factory, o_transport_factory): (Box<TReadTransportFactory>,
+                                                     Box<TWriteTransportFactory>) =
+        match &*transport {
+            "buffered" => {
+                (Box::new(TBufferedReadTransportFactory::new()),
+                 Box::new(TBufferedWriteTransportFactory::new()))
+            }
+            "framed" => {
+                (Box::new(TFramedReadTransportFactory::new()),
+                 Box::new(TFramedWriteTransportFactory::new()))
+            }
+            unknown => {
+                return Err(format!("unsupported transport type {}", unknown).into());
+            }
+        };
+
+    let (i_protocol_factory, o_protocol_factory): (Box<TInputProtocolFactory>,
+                                                   Box<TOutputProtocolFactory>) =
+        match &*protocol {
+            "binary" | "multi" | "multi:binary" => {
+                (Box::new(TBinaryInputProtocolFactory::new()),
+                 Box::new(TBinaryOutputProtocolFactory::new()))
+            }
+            "compact" | "multic" | "multi:compact" => {
+                (Box::new(TCompactInputProtocolFactory::new()),
+                 Box::new(TCompactOutputProtocolFactory::new()))
+            }
+            unknown => {
+                return Err(format!("unsupported transport type {}", unknown).into());
+            }
+        };
+
+    let test_processor = ThriftTestSyncProcessor::new(ThriftTestSyncHandlerImpl {});
+
+    match &*server_type {
+        "simple" | "thread-pool" => {
+            if protocol == "multi" || protocol == "multic" {
+                let second_service_processor = SecondServiceSyncProcessor::new(SecondServiceSyncHandlerImpl {},);
+
+                let mut multiplexed_processor = TMultiplexedProcessor::new();
+                multiplexed_processor
+                    .register("ThriftTest", Box::new(test_processor), true)?;
+                multiplexed_processor
+                    .register("SecondService", Box::new(second_service_processor), false)?;
+
+                let mut server = TServer::new(
+                    i_transport_factory,
+                    i_protocol_factory,
+                    o_transport_factory,
+                    o_protocol_factory,
+                    multiplexed_processor,
+                    workers,
+                );
+
+                server.listen(&listen_address)
+            } else {
+                let mut server = TServer::new(
+                    i_transport_factory,
+                    i_protocol_factory,
+                    o_transport_factory,
+                    o_protocol_factory,
+                    test_processor,
+                    workers,
+                );
+
+                server.listen(&listen_address)
+            }
+        }
+        unknown => Err(format!("unsupported server type {}", unknown).into()),
+    }
+}
+
+struct ThriftTestSyncHandlerImpl;
+impl ThriftTestSyncHandler for ThriftTestSyncHandlerImpl {
+    fn handle_test_void(&self) -> thrift::Result<()> {
+        info!("testVoid()");
+        Ok(())
+    }
+
+    fn handle_test_string(&self, thing: String) -> thrift::Result<String> {
+        info!("testString({})", &thing);
+        Ok(thing)
+    }
+
+    fn handle_test_bool(&self, thing: bool) -> thrift::Result<bool> {
+        info!("testBool({})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_byte(&self, thing: i8) -> thrift::Result<i8> {
+        info!("testByte({})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_i32(&self, thing: i32) -> thrift::Result<i32> {
+        info!("testi32({})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_i64(&self, thing: i64) -> thrift::Result<i64> {
+        info!("testi64({})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_double(&self, thing: OrderedFloat<f64>) -> thrift::Result<OrderedFloat<f64>> {
+        info!("testDouble({})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_binary(&self, thing: Vec<u8>) -> thrift::Result<Vec<u8>> {
+        info!("testBinary({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_struct(&self, thing: Xtruct) -> thrift::Result<Xtruct> {
+        info!("testStruct({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_nest(&self, thing: Xtruct2) -> thrift::Result<Xtruct2> {
+        info!("testNest({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_map(&self, thing: BTreeMap<i32, i32>) -> thrift::Result<BTreeMap<i32, i32>> {
+        info!("testMap({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_string_map(
+        &self,
+        thing: BTreeMap<String, String>,
+    ) -> thrift::Result<BTreeMap<String, String>> {
+        info!("testStringMap({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_set(&self, thing: BTreeSet<i32>) -> thrift::Result<BTreeSet<i32>> {
+        info!("testSet({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_list(&self, thing: Vec<i32>) -> thrift::Result<Vec<i32>> {
+        info!("testList({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_enum(&self, thing: Numberz) -> thrift::Result<Numberz> {
+        info!("testEnum({:?})", thing);
+        Ok(thing)
+    }
+
+    fn handle_test_typedef(&self, thing: UserId) -> thrift::Result<UserId> {
+        info!("testTypedef({})", thing);
+        Ok(thing)
+    }
+
+    /// @return map<i32,map<i32,i32>> - returns a dictionary with these values:
+    /// {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2 =>
+    /// 2, 3 => 3, 4 => 4, }, }
+    fn handle_test_map_map(&self, hello: i32) -> thrift::Result<BTreeMap<i32, BTreeMap<i32, i32>>> {
+        info!("testMapMap({})", hello);
+
+        let mut inner_map_0: BTreeMap<i32, i32> = BTreeMap::new();
+        for i in -4..(0 as i32) {
+            inner_map_0.insert(i, i);
+        }
+
+        let mut inner_map_1: BTreeMap<i32, i32> = BTreeMap::new();
+        for i in 1..5 {
+            inner_map_1.insert(i, i);
+        }
+
+        let mut ret_map: BTreeMap<i32, BTreeMap<i32, i32>> = BTreeMap::new();
+        ret_map.insert(-4, inner_map_0);
+        ret_map.insert(4, inner_map_1);
+
+        Ok(ret_map)
+    }
+
+    /// Creates a the returned map with these values and prints it out:
+    ///     { 1 => { 2 => argument,
+    ///              3 => argument,
+    ///            },
+    ///       2 => { 6 => <empty Insanity struct>, },
+    ///     }
+    /// return map<UserId, map<Numberz,Insanity>> - a map with the above values
+    fn handle_test_insanity(
+        &self,
+        argument: Insanity,
+    ) -> thrift::Result<BTreeMap<UserId, BTreeMap<Numberz, Insanity>>> {
+        info!("testInsanity({:?})", argument);
+        let mut map_0: BTreeMap<Numberz, Insanity> = BTreeMap::new();
+        map_0.insert(Numberz::Two, argument.clone());
+        map_0.insert(Numberz::Three, argument.clone());
+
+        let mut map_1: BTreeMap<Numberz, Insanity> = BTreeMap::new();
+        let insanity = Insanity {
+            user_map: None,
+            xtructs: None,
+        };
+        map_1.insert(Numberz::Six, insanity);
+
+        let mut ret: BTreeMap<UserId, BTreeMap<Numberz, Insanity>> = BTreeMap::new();
+        ret.insert(1, map_0);
+        ret.insert(2, map_1);
+
+        Ok(ret)
+    }
+
+    /// returns an Xtruct with:
+    /// string_thing = "Hello2", byte_thing = arg0, i32_thing = arg1 and
+    /// i64_thing = arg2
+    fn handle_test_multi(
+        &self,
+        arg0: i8,
+        arg1: i32,
+        arg2: i64,
+        _: BTreeMap<i16, String>,
+        _: Numberz,
+        _: UserId,
+    ) -> thrift::Result<Xtruct> {
+        let x_ret = Xtruct {
+            string_thing: Some("Hello2".to_owned()),
+            byte_thing: Some(arg0),
+            i32_thing: Some(arg1),
+            i64_thing: Some(arg2),
+        };
+
+        Ok(x_ret)
+    }
+
+    /// if arg == "Xception" throw Xception with errorCode = 1001 and message =
+    /// arg
+    /// else if arg == "TException" throw TException
+    /// else do not throw anything
+    fn handle_test_exception(&self, arg: String) -> thrift::Result<()> {
+        info!("testException({})", arg);
+
+        match &*arg {
+            "Xception" => {
+                Err(
+                    (Xception {
+                             error_code: Some(1001),
+                             message: Some(arg),
+                         })
+                        .into(),
+                )
+            }
+            "TException" => Err("this is a random error".into()),
+            _ => Ok(()),
+        }
+    }
+
+    /// if arg0 == "Xception":
+    /// throw Xception with errorCode = 1001 and message = "This is an
+    /// Xception"
+    /// else if arg0 == "Xception2":
+    /// throw Xception2 with errorCode = 2002 and struct_thing.string_thing =
+    /// "This is an Xception2"
+    // else:
+    //   do not throw anything and return Xtruct with string_thing = arg1
+    fn handle_test_multi_exception(&self, arg0: String, arg1: String) -> thrift::Result<Xtruct> {
+        match &*arg0 {
+            "Xception" => {
+                Err(
+                    (Xception {
+                             error_code: Some(1001),
+                             message: Some("This is an Xception".to_owned()),
+                         })
+                        .into(),
+                )
+            }
+            "Xception2" => {
+                Err(
+                    (Xception2 {
+                             error_code: Some(2002),
+                             struct_thing: Some(
+                            Xtruct {
+                                string_thing: Some("This is an Xception2".to_owned()),
+                                byte_thing: None,
+                                i32_thing: None,
+                                i64_thing: None,
+                            },
+                        ),
+                         })
+                        .into(),
+                )
+            }
+            _ => {
+                Ok(
+                    Xtruct {
+                        string_thing: Some(arg1),
+                        byte_thing: None,
+                        i32_thing: None,
+                        i64_thing: None,
+                    },
+                )
+            }
+        }
+    }
+
+    fn handle_test_oneway(&self, seconds_to_sleep: i32) -> thrift::Result<()> {
+        thread::sleep(Duration::from_secs(seconds_to_sleep as u64));
+        Ok(())
+    }
+}
+
+struct SecondServiceSyncHandlerImpl;
+impl SecondServiceSyncHandler for SecondServiceSyncHandlerImpl {
+    fn handle_secondtest_string(&self, thing: String) -> thrift::Result<String> {
+        info!("(second)testString({})", &thing);
+        let ret = format!("testString(\"{}\")", &thing);
+        Ok(ret)
+    }
+}
diff --git a/test/rs/src/lib.rs b/test/rs/src/lib.rs
new file mode 100644
index 0000000..479bf90
--- /dev/null
+++ b/test/rs/src/lib.rs
@@ -0,0 +1,23 @@
+// 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.
+
+extern crate ordered_float;
+extern crate thrift;
+extern crate try_from;
+
+mod thrift_test;
+pub use thrift_test::*;
diff --git a/test/test.py b/test/test.py
new file mode 100755
index 0000000..f59256a
--- /dev/null
+++ b/test/test.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python3
+#
+# 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.
+#
+
+#
+# Apache Thrift - integration (cross) test suite
+#
+# tests different server-client, protocol and transport combinations
+#
+# This script requires python 3.x due to the improvements in
+# subprocess management that are needed for reliability.
+#
+
+from __future__ import print_function
+from itertools import chain
+import json
+import logging
+import multiprocessing
+import argparse
+import os
+import sys
+
+import crossrunner
+from crossrunner.compat import path_join
+
+# 3.3 introduced subprocess timeouts on waiting for child
+req_version = (3, 3)
+cur_version = sys.version_info
+assert (cur_version >= req_version), "Python 3.3 or later is required for proper operation."
+
+
+ROOT_DIR = os.path.dirname(os.path.realpath(os.path.dirname(__file__)))
+TEST_DIR_RELATIVE = 'test'
+TEST_DIR = path_join(ROOT_DIR, TEST_DIR_RELATIVE)
+FEATURE_DIR_RELATIVE = path_join(TEST_DIR_RELATIVE, 'features')
+CONFIG_FILE = 'tests.json'
+
+
+def run_cross_tests(server_match, client_match, jobs, skip_known_failures, only_known_failures, retry_count, regex):
+    logger = multiprocessing.get_logger()
+    logger.debug('Collecting tests')
+    with open(path_join(TEST_DIR, CONFIG_FILE), 'r') as fp:
+        j = json.load(fp)
+    tests = crossrunner.collect_cross_tests(j, server_match, client_match, regex)
+    if not tests:
+        print('No test found that matches the criteria', file=sys.stderr)
+        print('  servers: %s' % server_match, file=sys.stderr)
+        print('  clients: %s' % client_match, file=sys.stderr)
+        return False
+    if only_known_failures:
+        logger.debug('Only running known failures')
+        known = crossrunner.load_known_failures(TEST_DIR)
+        tests = list(filter(lambda t: crossrunner.test_name(**t) in known, tests))
+    if skip_known_failures:
+        logger.debug('Skipping known failures')
+        known = crossrunner.load_known_failures(TEST_DIR)
+        tests = list(filter(lambda t: crossrunner.test_name(**t) not in known, tests))
+
+    dispatcher = crossrunner.TestDispatcher(TEST_DIR, ROOT_DIR, TEST_DIR_RELATIVE, jobs)
+    logger.debug('Executing %d tests' % len(tests))
+    try:
+        for r in [dispatcher.dispatch(test, retry_count) for test in tests]:
+            r.wait()
+        logger.debug('Waiting for completion')
+        return dispatcher.wait()
+    except (KeyboardInterrupt, SystemExit):
+        logger.debug('Interrupted, shutting down')
+        dispatcher.terminate()
+        return False
+
+
+def run_feature_tests(server_match, feature_match, jobs, skip_known_failures, only_known_failures, retry_count, regex):
+    basedir = path_join(ROOT_DIR, FEATURE_DIR_RELATIVE)
+    logger = multiprocessing.get_logger()
+    logger.debug('Collecting tests')
+    with open(path_join(TEST_DIR, CONFIG_FILE), 'r') as fp:
+        j = json.load(fp)
+    with open(path_join(basedir, CONFIG_FILE), 'r') as fp:
+        j2 = json.load(fp)
+    tests = crossrunner.collect_feature_tests(j, j2, server_match, feature_match, regex)
+    if not tests:
+        print('No test found that matches the criteria', file=sys.stderr)
+        print('  servers: %s' % server_match, file=sys.stderr)
+        print('  features: %s' % feature_match, file=sys.stderr)
+        return False
+    if only_known_failures:
+        logger.debug('Only running known failures')
+        known = crossrunner.load_known_failures(basedir)
+        tests = list(filter(lambda t: crossrunner.test_name(**t) in known, tests))
+    if skip_known_failures:
+        logger.debug('Skipping known failures')
+        known = crossrunner.load_known_failures(basedir)
+        tests = list(filter(lambda t: crossrunner.test_name(**t) not in known, tests))
+
+    dispatcher = crossrunner.TestDispatcher(TEST_DIR, ROOT_DIR, FEATURE_DIR_RELATIVE, jobs)
+    logger.debug('Executing %d tests' % len(tests))
+    try:
+        for r in [dispatcher.dispatch(test, retry_count) for test in tests]:
+            r.wait()
+        logger.debug('Waiting for completion')
+        return dispatcher.wait()
+    except (KeyboardInterrupt, SystemExit):
+        logger.debug('Interrupted, shutting down')
+        dispatcher.terminate()
+        return False
+
+
+def default_concurrenty():
+    try:
+        return int(os.environ.get('THRIFT_CROSSTEST_CONCURRENCY'))
+    except (TypeError, ValueError):
+        # Since much time is spent sleeping, use many threads
+        return int(multiprocessing.cpu_count() * 1.25) + 1
+
+
+def main(argv):
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--server', default='', nargs='*',
+                        help='list of servers to test')
+    parser.add_argument('--client', default='', nargs='*',
+                        help='list of clients to test')
+    parser.add_argument('-F', '--features', nargs='*', default=None,
+                        help='run server feature tests instead of cross language tests')
+    parser.add_argument('-R', '--regex', help='test name pattern to run')
+    parser.add_argument('-o', '--only-known_failures', action='store_true', dest='only_known_failures',
+                        help='only execute tests that are known to fail')
+    parser.add_argument('-s', '--skip-known-failures', action='store_true', dest='skip_known_failures',
+                        help='do not execute tests that are known to fail')
+    parser.add_argument('-r', '--retry-count', type=int,
+                        default=0, help='maximum retry on failure')
+    parser.add_argument('-j', '--jobs', type=int,
+                        default=default_concurrenty(),
+                        help='number of concurrent test executions')
+
+    g = parser.add_argument_group(title='Advanced')
+    g.add_argument('-v', '--verbose', action='store_const',
+                   dest='log_level', const=logging.DEBUG, default=logging.WARNING,
+                   help='show debug output for test runner')
+    g.add_argument('-P', '--print-expected-failures', choices=['merge', 'overwrite'],
+                   dest='print_failures',
+                   help="generate expected failures based on last result and print to stdout")
+    g.add_argument('-U', '--update-expected-failures', choices=['merge', 'overwrite'],
+                   dest='update_failures',
+                   help="generate expected failures based on last result and save to default file location")
+    options = parser.parse_args(argv)
+
+    logger = multiprocessing.log_to_stderr()
+    logger.setLevel(options.log_level)
+
+    if options.features is not None and options.client:
+        print('Cannot specify both --features and --client ', file=sys.stderr)
+        return 1
+
+    # Allow multiple args separated with ',' for backward compatibility
+    server_match = list(chain(*[x.split(',') for x in options.server]))
+    client_match = list(chain(*[x.split(',') for x in options.client]))
+
+    if options.update_failures or options.print_failures:
+        dire = path_join(ROOT_DIR, FEATURE_DIR_RELATIVE) if options.features is not None else TEST_DIR
+        res = crossrunner.generate_known_failures(
+            dire, options.update_failures == 'overwrite',
+            options.update_failures, options.print_failures)
+    elif options.features is not None:
+        features = options.features or ['.*']
+        res = run_feature_tests(server_match, features, options.jobs,
+                                options.skip_known_failures, options.only_known_failures,
+                                options.retry_count, options.regex)
+    else:
+        res = run_cross_tests(server_match, client_match, options.jobs,
+                              options.skip_known_failures, options.only_known_failures,
+                              options.retry_count, options.regex)
+    return 0 if res else 1
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
diff --git a/test/test.sh b/test/test.sh
deleted file mode 100755
index 351fa1c..0000000
--- a/test/test.sh
+++ /dev/null
@@ -1,234 +0,0 @@
-#!/bin/sh
-#
-# 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.
-#
-
-# Apache Thrift - integration test suite
-#
-# tests different client-server, protocol and transport combinations
-
-# related issues:
-# THRIFT-847 Test Framework harmonization across all languages
-# THRIFT-819 add Enumeration for protocol, transport and server types
-
-BASEDIR=$(dirname $0)
-cd $BASEDIR
-
-print_header() {
-  printf "%-16s %-11s %-17s %-s\n" "client-server:" "protocol:" "transport:" "result:"
-}
-
-intersection() {
-  return_value=""
-  for one in $1; do
-    for two in $2; do
-      if [ ${one} = ${two} ]; then
-        return_value=${return_value}" "${one}
-      fi
-    done;
-  done;
-  echo ${return_value};
-}
-
-do_test () {
-    client_server=$1
-    protocol=$2
-    transport=$3
-    client_exec=$4
-    server_exec=$5
-    server_startup_time=$6
-    client_delay=$7
-    
-    testname=${client_server}_${protocol}_${transport}
-    server_timeout=$((${server_startup_time}+${client_delay}))
-    printf "%-16s %-11s %-17s" ${client_server} ${protocol} ${transport} 
-    timeout $server_timeout $server_exec > log/${testname}_server.log 2>&1 &
-    sleep $server_startup_time
-    $client_exec > log/${testname}_client.log 2>&1
-    
-    if [ "$?" -eq "0" ]; then
-      echo " success"
-    else
-      echo " failure"
-      echo "=================== server message ==================="
-      tail log/${testname}_server.log 
-      echo "=================== client message ==================="
-      tail log/${testname}_client.log
-      echo "======================================================"
-      echo ""
-      print_header
-    fi
-    sleep ${client_delay}
-}
-
-echo "Apache Thrift - integration test suite"
-date
-echo "======================================================"
-
-rm -rf log
-mkdir -p log
-
-print_header
-
-#TODO add enum for parameters
-#TODO align program arguments across languages
-
-cpp_protocols="binary json"
-java_protocols="binary json compact"
-cpp_transports="buffered framed http"
-java_server_transports="buffered framed fastframed"
-java_client_transports=${java_server_transports}" http"
-# we need a test certificate first
-cpp_sockets="ip domain"
-java_sockets="ip ip-ssl"
-# TODO fastframed java transport is another implementation of framed transport
-
-
-ant -f ../lib/java/build.xml compile-test 1>/dev/null
-
-######### java client - java server #############
-for proto in $java_protocols; do
-  for trans in $java_server_transports; do
-    for sock in $java_sockets; do
-      case "$sock" in
-        "ip" ) extraparam="";;
-        "ip-ssl" ) extraparam="--ssl";;
-      esac
-      do_test "java-java" "${proto}" "${trans}-${sock}" \
-              "ant -f  ../lib/java/build.xml -Dno-gen-thrift=\"\" -Dtestargs \"--protocol=${proto} --transport=${trans} ${extraparam}\" testclient" \
-              "ant -f  ../lib/java/build.xml -Dno-gen-thrift=\"\" -Dtestargs \"--protocol=${proto} --transport=${trans} ${extraparam}\" testserver" \
-            "15" "15"
-    done
-  done
-done
-
-######### cpp client - cpp server ###############
-for proto in $cpp_protocols; do
-  for trans in $cpp_transports; do
-    for sock in $cpp_sockets; do
-      case "$sock" in
-       "ip" )     extraparam="";;
-       "ip-ssl" ) extraparam="--ssl";;
-       "domain" ) extraparam="--domain-socket=/tmp/ThriftTest.thrift";;
-      esac
-      do_test "cpp-cpp"   "${proto}" "${trans}-${sock}" \
-              "cpp/TestClient --protocol=${proto} --transport=${trans} ${extraparam}" \
-              "cpp/TestServer --protocol=${proto} --transport=${trans} ${extraparam}" \
-              "10" "10"
-    done
-  done
-done
-
-######### java client - cpp server ##############
-# warning: ssl over http is not supported in java client!
-for proto in $(intersection "${java_protocols}" "${cpp_protocols}"); do
-  for trans in $(intersection "${java_client_transports}" "${cpp_transports}"); do
-    for sock in $(intersection "${java_sockets}" "${cpp_sockets}"); do
-      case "$sock" in
-        "ip" ) extraparam="";;
-        "ip-ssl" ) extraparam="--ssl";;
-      esac
-      do_test "java-cpp" "${proto}" "${trans}-ip" \
-              "ant -f  ../lib/java/build.xml -Dno-gen-thrift=\"\" -Dtestargs \"--protocol=${proto} --transport=${trans} ${extraparam}\" testclient" \
-              "cpp/TestServer --protocol=${proto} --transport=${trans} ${extraparam}"\
-              "10" "15"
-    done
-  done
-done
-
-######### cpp client - java server ##############
-for proto in $(intersection "${cpp_protocols}" "${java_protocols}"); do
-  for trans in $(intersection "${cpp_transports}" "${java_server_transports}"); do
-    for sock in $(intersection "${java_sockets}" "${cpp_sockets}"); do
-      case "$sock" in
-        "ip" ) extraparam="";;
-        "ip-ssl" ) extraparam="--ssl";;
-      esac
-      do_test "cpp-java" "${proto}" "${trans}-ip" \
-              "cpp/TestClient --protocol=${proto} --transport=${trans}" \
-              "ant -f  ../lib/java/build.xml -Dno-gen-thrift=\"\" -Dtestargs \"--protocol=${proto} --transport=${trans}\" testserver" \
-              "15" "10"
-    done
-  done
-done
-
-# delete Unix Domain Socket used by cpp tests
-rm -f /tmp/ThriftTest.thrift
-
-do_test "py-py" "binary" "buffered-ip" \
-        "py/TestClient.py --proto=binary --port=9090 --host=localhost --genpydir=py/gen-py" \
-        "py/TestServer.py --proto=binary --port=9090 --genpydir=py/gen-py TSimpleServer" \
-        "10" "10"
-do_test "py-py" "json" "buffered-ip" \
-        "py/TestClient.py --proto=json --port=9090 --host=localhost --genpydir=py/gen-py" \
-        "py/TestServer.py --proto=json --port=9090 --genpydir=py/gen-py TSimpleServer" \
-        "10" "10"
-do_test "py-cpp" "binary" "buffered-ip" \
-        "py/TestClient.py --proto=binary --port=9090 --host=localhost --genpydir=py/gen-py" \
-        "cpp/TestServer" \
-        "10" "10"
-do_test "py-cpp" "json" "buffered-ip" \
-        "py/TestClient.py --proto=json --port=9090 --host=localhost --genpydir=py/gen-py" \
-        "cpp/TestServer --protocol=json" \
-        "10" "10"
-do_test "cpp-py" "binary" "buffered-ip" \
-        "cpp/TestClient --protocol=binary --port=9090" \
-        "py/TestServer.py --proto=binary --port=9090 --genpydir=py/gen-py TSimpleServer" \
-        "10" "10"
-do_test "cpp-py" "json" "buffered-ip" \
-        "cpp/TestClient --protocol=json --port=9090" \
-        "py/TestServer.py --proto=json --port=9090 --genpydir=py/gen-py TSimpleServer" \
-        "10" "10"
-do_test "py-java"  "binary" "buffered-ip" \
-        "py/TestClient.py --proto=binary --port=9090 --host=localhost --genpydir=py/gen-py" \
-        "ant -f  ../lib/java/build.xml -Dno-gen-thrift=\"\" testserver" \
-        "15" "15"
-do_test "py-java"  "json"   "json-ip" \
-        "py/TestClient.py --proto=json --port=9090 --host=localhost --genpydir=py/gen-py" \
-        "ant -f  ../lib/java/build.xml -Dno-gen-thrift=\"\" -Dtestargs \"--protocol=json\" testserver" \
-        "15" "10"
-do_test "java-py"  "binary" "buffered-ip" \
-        "ant -f  ../lib/java/build.xml -Dno-gen-thrift=\"\" testclient" \
-        "py/TestServer.py --proto=binary --port=9090 --genpydir=py/gen-py TSimpleServer" \
-        "10" "15"
-do_test "js-java"   "json "  "http-ip" \
-        "" \
-        "ant -f  ../lib/js/test/build.xml unittest" \
-        "10" "15"
-do_test "perl-cpp"  "binary" "buffered-ip" \
-        "perl -I perl/gen-perl/ -I../lib/perl/lib/ perl/TestClient.pl" \
-        "cpp/TestServer" \
-        "10" "10"
-do_test "php-cpp"  "binary" "buffered-ip" \
-        "make -C php/ client" \
-        "cpp/TestServer" \
-        "10" "10"
-do_test "nodejs-nodejs" "binary" "framed-ip" \
-        "make -C nodejs/ client" \
-        "make -C nodejs/ server" \
-        "1" "5"
-do_test "nodejs-cpp" "binary" "framed-ip" \
-        "make -C nodejs/ client" \
-        "cpp/TestServer --transport=framed" \
-        "1" "10"
-do_test "cpp-nodejs" "binary" "framed-ip" \
-        "cpp/TestClient --transport=framed" \
-        "make -C nodejs/ server" \
-        "1" "5"
-
-cd -
diff --git a/test/tests.json b/test/tests.json
new file mode 100644
index 0000000..43d6ded
--- /dev/null
+++ b/test/tests.json
@@ -0,0 +1,749 @@
+[
+  {
+    "name": "c_glib",
+    "platforms": [
+      "Linux"
+    ],
+    "server": {
+      "command": [
+        "test_server",
+        "--lt-debug"
+      ],
+      "protocols": [
+        "binary:multi",
+        "compact:multic"
+      ]
+    },
+    "client": {
+      "command": [
+        "test_client",
+        "--lt-debug"
+      ],
+      "protocols": [
+        "multi:binary",
+        "multic:compact"
+      ],
+      "sockets": [
+        "ip-ssl"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "multi",
+      "multic"
+    ],
+    "workdir": "c_glib"
+  },
+  {
+    "name": "cl",
+    "server": {
+      "command": ["TestServer"],
+      "workdir": "cl",
+      "protocols": ["binary", "multi"],
+      "transports": ["buffered", "framed"],
+      "sockets": ["ip"]
+    },
+    "client": {
+      "command": ["TestClient"],
+      "workdir": "cl",
+      "protocols": ["binary", "multi"],
+      "transports": ["buffered", "framed"],
+      "sockets": ["ip"]
+    }
+  },
+  {
+    "name": "d",
+    "server": {
+      "command": [
+        "thrift_test_server",
+        "--trace"
+      ]
+    },
+    "client": {
+      "command": [
+        "thrift_test_client"
+      ]
+    },
+    "transports": [
+      "http",
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "json"
+    ],
+    "workdir": "../lib/d/test"
+  },
+  {
+    "name": "go",
+    "server": {
+      "command": [
+        "testserver",
+        "--certPath=../../keys"
+      ]
+    },
+    "client": {
+      "timeout": 6,
+      "command": [
+        "testclient"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed",
+      "http",
+      "zlib"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "json"
+    ],
+    "workdir": "go/bin"
+  },
+  {
+    "name": "java",
+    "join_args": false,
+    "server": {
+      "delay": 15,
+      "command": [
+        "build/runserver"
+      ],
+      "protocols": [
+        "binary:multi",
+        "compact:multic",
+        "json:multij"
+      ]
+    },
+    "client": {
+      "timeout": 13,
+      "command": [
+        "build/runclient"
+      ],
+      "transports": [
+        "http"
+      ],
+      "protocols": [
+        "multi:binary",
+        "multic:compact",
+        "multij:json"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed",
+      "framed:fastframed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "json",
+      "multi",
+      "multic",
+      "multij"
+    ],
+    "workdir": "../lib/java"
+  },
+  {
+    "name": "nodejs",
+    "env": {
+      "NODE_PATH": "../lib"
+    },
+    "server": {
+      "command": [
+        "node",
+        "server.js",
+        "--type=tcp"
+      ]
+    },
+    "client": {
+      "timeout": 6,
+      "command": [
+        "node",
+        "client.js",
+        "--type=tcp"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed",
+      "http"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl",
+      "domain"
+    ],
+    "protocols": [
+      "compact",
+      "binary",
+      "json"
+    ],
+    "workdir": "../lib/nodejs/test"
+  },
+  {
+    "name": "hs",
+    "server": {
+      "command": [
+        "TestServer"
+      ]
+    },
+    "client": {
+      "timeout": 6,
+      "transports": [
+        "http"
+      ],
+      "command": [
+        "TestClient"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip"
+    ],
+    "protocols": [
+      "header",
+      "compact",
+      "binary",
+      "json"
+    ],
+    "workdir": "hs"
+  },
+  {
+    "name": "py",
+    "server": {
+      "extra_args": ["TSimpleServer"],
+      "command": [
+        "TestServer.py",
+        "--verbose",
+        "--genpydir=gen-py"
+      ]
+    },
+    "client": {
+      "timeout": 10,
+      "command": [
+        "TestClient.py",
+        "--verbose",
+        "--host=localhost",
+        "--genpydir=gen-py"
+      ],
+      "protocols": [
+        "multi",
+        "multi:multia",
+        "multic",
+        "multic:multiac",
+        "multij"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed",
+      "http",
+      "zlib"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "compact",
+      "binary",
+      "json",
+      "binary:accel",
+      "compact:accelc",
+      "header"
+    ],
+    "workdir": "py"
+  },
+  {
+    "comment": "Using 'python3' executable to test py2 and 3 at once",
+    "name": "py3",
+    "server": {
+      "extra_args": ["TSimpleServer"],
+      "command": [
+        "python3",
+        "TestServer.py",
+        "--verbose",
+        "--genpydir=gen-py"
+      ]
+    },
+    "client": {
+      "timeout": 10,
+      "command": [
+        "python3",
+        "TestClient.py",
+        "--host=localhost",
+        "--genpydir=gen-py"
+      ],
+      "protocols": [
+        "multi",
+        "multi:multia",
+        "multic",
+        "multic:multiac",
+        "multij"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed",
+      "http",
+      "zlib"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "compact",
+      "binary",
+      "json",
+      "binary:accel",
+      "compact:accelc",
+      "header"
+    ],
+    "workdir": "py"
+  },
+  {
+    "name": "cpp",
+    "server": {
+      "command": [
+        "TestServer"
+      ],
+      "protocols": [
+        "binary:multi",
+        "compact:multic",
+        "header:multih",
+        "json:multij"
+      ]
+    },
+    "client": {
+      "timeout": 8,
+      "command": [
+        "TestClient"
+      ],
+      "protocols": [
+        "multi:binary",
+        "multic:compact",
+        "multih:header",
+        "multij:json"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "http",
+      "framed",
+      "zlib"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl",
+      "domain"
+    ],
+    "protocols": [
+      "compact",
+      "binary",
+      "json",
+      "header",
+      "multi",
+      "multic",
+      "multih",
+      "multij"
+    ],
+    "workdir": "cpp"
+  },
+  {
+    "name": "rb",
+    "server": {
+      "command": [
+        "ruby",
+        "../integration/TestServer.rb"
+      ]
+    },
+    "client": {
+      "timeout": 5,
+      "command": [
+        "ruby",
+        "../integration/TestClient.rb",
+        "--"
+      ]
+    },
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "domain",
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "binary",
+      "binary:accel",
+      "compact",
+      "json"
+    ],
+    "workdir": "rb/gen-rb"
+  },
+  {
+    "name": "csharp",
+    "env": {
+      "MONO_PATH": "../../lib/csharp/"
+    },
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "json"
+    ],
+    "server": {
+      "command": [
+        "mono",
+        "TestClientServer.exe",
+        "server"
+      ]
+    },
+    "client": {
+      "timeout": 9,
+      "command": [
+        "mono",
+        "TestClientServer.exe",
+        "client"
+      ],
+      "protocols": [
+        "multi",
+        "multic",
+        "multi:binary",
+        "multic:compact"
+      ]
+    },
+    "workdir": "csharp"
+  },
+  {
+    "name": "netcore",
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "json"
+    ],
+    "server": {
+      "command": [
+        "dotnet",
+        "run",
+        "--no-build",
+        "--project=Server/Server.csproj",
+        "server"
+      ]
+    },
+    "client": {
+      "timeout": 10,
+      "command": [
+        "dotnet",
+        "run",
+        "--no-build",
+        "--project=Client/Client.csproj",
+        "client"
+      ]
+    },
+        "workdir": "netcore"
+  },
+  {
+    "name": "perl",
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl",
+      "domain"
+    ],
+    "protocols": [
+      "binary",
+      "multi"
+    ],
+    "client": {
+      "command": [
+        "perl",
+        "-Igen-perl/",
+        "-I../../lib/perl/lib/",
+        "TestClient.pl",
+        "--ca=../keys/CA.pem",
+        "--cert=../keys/client.crt",
+        "--key=../keys/client.key"
+      ],
+      "protocols": [
+        "multi:binary"
+      ]
+    },
+    "server": {
+      "command": [
+        "perl",
+        "-Igen-perl/",
+        "-I../../lib/perl/lib/",
+        "TestServer.pl",
+        "--cert=../keys/server.crt",
+        "--key=../keys/server.key"
+      ],
+      "protocols": [
+        "binary:multi"
+      ]
+    },
+    "workdir": "perl"
+  },
+  {
+    "name": "php",
+    "client": {
+      "timeout": 6,
+      "transports": [
+        "buffered",
+        "framed"
+      ],
+      "sockets": [
+        "ip"
+      ],
+      "protocols": [
+        "binary",
+        "compact",
+        "binary:accel"
+      ],
+      "command": [
+        "php",
+        "-dextension_dir=php_ext_dir",
+        "--php-ini=test_php.ini",
+        "--no-php-ini",
+        "-ddisplay_errors=stderr",
+        "-dlog_errors=0",
+        "-derror_reporting=E_ALL",
+        "TestClient.php"
+      ]
+    },
+    "workdir": "php"
+  },
+  {
+    "name": "dart",
+    "client": {
+      "transports": [
+        "buffered",
+        "framed",
+        "http"
+      ],
+      "sockets": [
+        "ip"
+      ],
+      "protocols": [
+        "binary",
+        "compact",
+        "json"
+      ],
+      "command": [
+        "dart",
+        "test_client/bin/main.dart"
+      ]
+    },
+    "workdir": "dart"
+  },
+  {
+    "name": "erl",
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "sockets": [
+      "ip",
+      "ip-ssl"
+    ],
+    "protocols": [
+      "binary",
+      "compact"
+    ],
+    "client": {
+      "command": [
+        "erl",
+        "+K",
+        "true",
+        "-noshell",
+        "-pa",
+        "../../lib/erl/ebin/",
+        "-pa",
+        "./ebin",
+        "-s",
+        "test_client",
+        "-s",
+        "init",
+        "stop",
+        "-extra"
+      ]
+    },
+    "server": {
+      "command": [
+        "erl",
+        "+K",
+        "true",
+        "-noshell",
+        "-pa",
+        "../../lib/erl/ebin/",
+        "-pa",
+        "./ebin",
+        "-s",
+        "test_thrift_server",
+        "-extra"
+      ]
+    },
+    "workdir": "erl"
+  },
+  {
+    "name": "js",
+    "transports": [
+      "http"
+    ],
+    "sockets": [
+      "ip"
+    ],
+    "protocols": [
+      "json"
+    ],
+    "client": {
+      "command": [
+        "phantomjs",
+        "test/phantom-client.js"
+      ]
+    },
+    "workdir": "../lib/js"
+  },
+  {
+    "name": "lua",
+    "TODO": "Add dll to LUA_CPATH",
+    "env": {
+      "LUA_PATH": ";;gen-lua/?.lua;../../lib/lua/?.lua",
+      "LUA_CPATH": ";;../../lib/lua/.libs/?.so"
+    },
+    "client": {
+      "timeout": 5,
+      "transports": [
+        "buffered",
+        "framed",
+        "http"
+      ],
+      "sockets": [
+        "ip"
+      ],
+      "protocols": [
+        "binary",
+        "compact",
+        "json"
+      ],
+      "command": [
+        "lua",
+        "test_basic_client.lua"
+      ]
+    },
+    "workdir": "lua"
+  },
+  {
+    "name": "rs",
+    "env": {
+      "RUST_BACKTRACE": "1",
+      "RUST_LOG": "info"
+    },
+    "server": {
+      "command": [
+        "test_server"
+      ],
+      "protocols": [
+        "binary:multi",
+        "compact:multic"
+      ]
+    },
+    "client": {
+      "timeout": 6,
+      "command": [
+        "test_client"
+      ],
+      "protocols": [
+        "multi:binary",
+        "multic:compact"
+      ]
+    },
+    "sockets": [
+      "ip"
+    ],
+    "transports": [
+      "buffered",
+      "framed"
+    ],
+    "protocols": [
+      "binary",
+      "compact",
+      "multi",
+      "multic"
+    ],
+    "workdir": "rs/bin"
+  },
+  {
+    "name": "nodets",
+    "env": {
+      "NODE_PATH": "../lib"
+    },
+    "server": {
+      "command": [
+        "runServer.sh"
+      ]
+    },
+    "client": {
+      "timeout": 6,
+      "command": [
+        "runClient.sh"
+      ]
+    },
+    "protocols": [
+      "binary"
+    ],
+    "sockets": [
+      "ip"
+    ],
+    "transports": [
+      "buffered"
+    ],
+    "workdir": "../lib/nodets/test"
+  }
+]
diff --git a/test/threads/ThreadsClient.cpp b/test/threads/ThreadsClient.cpp
index 70b08ad..9306a3f 100644
--- a/test/threads/ThreadsClient.cpp
+++ b/test/threads/ThreadsClient.cpp
@@ -28,6 +28,9 @@
 #include <thrift/concurrency/Monitor.h>
 #include <thrift/concurrency/ThreadManager.h>
 #include <thrift/concurrency/PlatformThreadFactory.h>
+#if _WIN32
+   #include <thrift/windows/TWinsockSingleton.h>
+#endif
 
 using boost::shared_ptr;
 using namespace apache::thrift;
@@ -37,6 +40,9 @@
 using namespace apache::thrift::concurrency;
 
 int main(int argc, char **argv) {
+#if _WIN32
+  transport::TWinsockSingleton::create();
+#endif
   int port = 9090;
   std::string host = "localhost";
 
diff --git a/test/threads/ThreadsServer.cpp b/test/threads/ThreadsServer.cpp
index 9c1a7d9..a267c3b 100644
--- a/test/threads/ThreadsServer.cpp
+++ b/test/threads/ThreadsServer.cpp
@@ -29,6 +29,9 @@
 #include <thrift/concurrency/Monitor.h>
 #include <thrift/concurrency/ThreadManager.h>
 #include <thrift/concurrency/PlatformThreadFactory.h>
+#if _WIN32
+   #include <thrift/windows/TWinsockSingleton.h>
+#endif
 
 using boost::shared_ptr;
 using namespace apache::thrift;
@@ -85,11 +88,12 @@
 protected:
   void go2sleep(int thread, int seconds) {
     Monitor m;
+    Synchronized s(m);
     for (int i = 0; i < seconds; ++i) {
       fprintf(stderr, "Thread %d: sleep %d\n", thread, i);
       try {
         m.wait(1000);
-      } catch(TimedOutException& e) {
+      } catch(const TimedOutException&) {
       }
     }
     fprintf(stderr, "THREAD %d DONE\n", thread);
@@ -101,6 +105,9 @@
 };
 
 int main(int argc, char **argv) {
+#if _WIN32
+  transport::TWinsockSingleton::create();
+#endif
   int port = 9090;
   shared_ptr<ThreadsTestHandler> handler(new ThreadsTestHandler());
   shared_ptr<TProcessor> processor(new ThreadsTestProcessor(handler));
diff --git a/test/valgrind.suppress b/test/valgrind.suppress
new file mode 100644
index 0000000..de17cb8
--- /dev/null
+++ b/test/valgrind.suppress
@@ -0,0 +1,53 @@
+{
+   boost/get_once_per_thread_epoch/ignore
+   Memcheck:Leak
+   match-leak-kinds: reachable
+   fun:malloc
+   fun:_ZN5boost6detail25get_once_per_thread_epochEv
+}
+{
+   boostthreads/once/ignore
+   Helgrind:Race
+   fun:_ZN5boost13thread_detail17enter_once_regionERNS_9once_flagE
+   fun:_ZN5boost6detail23get_current_thread_dataEv
+   fun:_ZN5boost6detail20interruption_checkerC1EP15pthread_mutex_tP14pthread_cond_t
+   fun:_ZN5boost22condition_variable_any4waitINS_11unique_lockINS_11timed_mutexEEEEEvRT_
+   fun:_ZN6apache6thrift11concurrency7Monitor4Impl11waitForeverEv
+   fun:_ZN6apache6thrift11concurrency7Monitor4Impl19waitForTimeRelativeEl
+   fun:_ZN6apache6thrift11concurrency7Monitor4Impl4waitEl
+   fun:_ZNK6apache6thrift11concurrency7Monitor4waitEl
+   fun:_ZN6apache6thrift11concurrency11BoostThread5startEv
+   fun:_ZN6apache6thrift11concurrency4test18ThreadFactoryTests12reapNThreadsEii
+   fun:main
+}
+{
+   pthread/creation-tls/ignore
+   Helgrind:Race
+   fun:mempcpy
+   fun:_dl_allocate_tls_init
+   fun:get_cached_stack
+   fun:allocate_stack
+   fun:pthread_create@@GLIBC_2.2*
+   obj:/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so
+   fun:_ZN6apache6thrift11concurrency13PthreadThread5startEv
+   fun:_ZN6apache6thrift11concurrency4test18ThreadFactoryTests12reapNThreadsEii
+   fun:main
+}
+{
+   boost-thread/creation-tls/ignore
+   Helgrind:Race
+   fun:mempcpy
+   fun:_dl_allocate_tls_init
+   fun:get_cached_stack
+   fun:allocate_stack
+   fun:pthread_create@@GLIBC_2.2.5
+   obj:/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so
+   fun:_ZN5boost6thread21start_thread_noexceptEv
+   fun:_ZN5boost6thread12start_threadEv
+   fun:_ZN5boost6threadC1ISt5_BindIFPFPvS3_ES3_EEEEOT_
+   fun:_ZN6apache6thrift11concurrency11BoostThread5startEv
+   fun:_ZN6apache6thrift11concurrency4test18ThreadFactoryTests12reapNThreadsEii
+   fun:main
+}
+
+
diff --git a/tutorial/Makefile.am b/tutorial/Makefile.am
index 5f65802..0499460 100755
--- a/tutorial/Makefile.am
+++ b/tutorial/Makefile.am
@@ -23,10 +23,18 @@
 # do nothing, just build the compiler
 else
 
+if WITH_C_GLIB
+SUBDIRS += c_glib
+endif
+
 if WITH_CPP
 SUBDIRS += cpp
 endif
 
+if WITH_D
+SUBDIRS += d
+endif
+
 if WITH_JAVA
 SUBDIRS += java
 SUBDIRS += js
@@ -42,28 +50,61 @@
 SUBDIRS += rb
 endif
 
+if WITH_HASKELL
+SUBDIRS += hs
+endif
+
+if WITH_HAXE
+SUBDIRS += haxe
+endif
+
+if WITH_DOTNETCORE
+SUBDIRS += netcore
+endif
+
 if WITH_GO
 SUBDIRS += go
 endif
 
+if WITH_NODEJS
+SUBDIRS += nodejs
+endif
+
+if WITH_DART
+SUBDIRS += dart
+endif
+
+if WITH_RS
+SUBDIRS += rs
+endif
+
+if WITH_CL
+SUBDIRS += cl
+endif
+
 #
 # generate html for ThriftTest.thrift
 #
 all-local:
 	$(top_builddir)/compiler/cpp/thrift --gen html -r $(top_srcdir)/tutorial/tutorial.thrift
+
+clean-local:
+	rm -rf $(top_srcdir)/tutorial/gen-html
+
 endif
 
-# Any folders or files not listed above being added to SUBDIR need to be placed here in 
-# EXTRA_DIST to be included in the release 
+# Any folders or files not listed above being added to SUBDIR need to be placed here in
+# EXTRA_DIST to be included in the release
 EXTRA_DIST = \
+	as3 \
 	csharp \
 	d \
 	delphi \
 	erl \
-	gen-html \
 	hs \
 	ocaml \
 	perl \
 	php \
 	shared.thrift \
-	tutorial.thrift
+	tutorial.thrift \
+	README.md
diff --git a/tutorial/README b/tutorial/README
deleted file mode 100644
index a29f977..0000000
--- a/tutorial/README
+++ /dev/null
@@ -1,42 +0,0 @@
-Thrift Tutorial
-
-License
-=======
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-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.
-
-Tutorial
-========
-
-1) First things first, you'll need to install the Thrift compiler and the
-   language libraries. Do that using the instructions in the top level
-   README file.
-
-2) Read tutorial.thrift to learn about the syntax of a Thrift file
-
-3) Compile the code for the language of your choice:
-
-     $ thrift
-     $ thrift -r --gen cpp tutorial.thrift
-
-4) Take a look at the generated code.
-
-5) Look in the language directories for sample client/server code.
-
-6) That's about it for now. This tutorial is intentionally brief. It should be
-   just enough to get you started and ready to build your own project.
diff --git a/tutorial/README.md b/tutorial/README.md
new file mode 100644
index 0000000..7772bf3
--- /dev/null
+++ b/tutorial/README.md
@@ -0,0 +1,42 @@
+Thrift Tutorial
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+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.
+
+Tutorial
+========
+
+1) First things first, you'll need to install the Thrift compiler and the
+   language libraries. Do that using the instructions in the top level
+   README.md file.
+
+2) Read tutorial.thrift to learn about the syntax of a Thrift file
+
+3) Compile the code for the language of your choice:
+
+     $ thrift
+     $ thrift -r --gen cpp tutorial.thrift
+
+4) Take a look at the generated code.
+
+5) Look in the language directories for sample client/server code.
+
+6) That's about it for now. This tutorial is intentionally brief. It should be
+   just enough to get you started and ready to build your own project.
diff --git a/tutorial/as3/build.xml b/tutorial/as3/build.xml
new file mode 100644
index 0000000..f7ed32d
--- /dev/null
+++ b/tutorial/as3/build.xml
@@ -0,0 +1,50 @@
+<project name="tutorial" default="dist" basedir=".">
+
+  <description>Thrift actionscript 3.0 tutorial.</description>
+
+  <property name="gen" location="gen-as3" />
+  <property name="src" location="src" />
+  <property name="thrift.src" location="../../lib/as3/src/" />
+  <property name="dist" location="dist" />
+
+  <property name="final.name" value="as3-tutorial" />
+  <property name="swf.name" value="${dist}/${final.name}.swf" />
+
+  <target name="flex.check" unless="FLEX_HOME">
+    <fail message='You must set the FLEX_HOME property pointing to your flex SDK, eg. ant -DFLEX_HOME="/Applications/Adobe Flex Builder 3/sdks/3.2.0"'/>
+  </target>
+
+  <target name="flex.init" depends="flex.check" unless="flex.finished">
+    <taskdef resource="flexTasks.tasks" classpath="${FLEX_HOME}/ant/lib/flexTasks.jar" />
+    <property name="flex.finished" value="true"/>
+  </target>
+
+  <target name="init">
+    <tstamp />
+    <mkdir dir="${dist}"/>
+  </target>
+
+  <target name="dist" depends="generate, flex.init, init">
+    <mxmlc output="${swf.name}" file="${src}/CalculatorUI.as">
+      <source-path path-element="${gen}" />
+      <source-path path-element="${src}" />
+      <source-path path-element="${thrift.src}" />
+    </mxmlc>
+  </target>
+
+  <target name="generate">
+    <!-- Generate the thrift gen-java source -->
+    <exec executable="../../compiler/cpp/thrift" failonerror="true">
+      <arg line="--gen as3 ../shared.thrift"/>
+    </exec>
+    <exec executable="../../compiler/cpp/thrift" failonerror="true">
+      <arg line="--gen as3 ../tutorial.thrift"/>
+    </exec>
+  </target>
+
+  <target name="clean">
+    <delete dir="${gen}"/>
+    <delete dir="${dist}" />
+  </target>
+
+</project>
diff --git a/tutorial/as3/src/CalculatorUI.as b/tutorial/as3/src/CalculatorUI.as
new file mode 100644
index 0000000..d996df5
--- /dev/null
+++ b/tutorial/as3/src/CalculatorUI.as
@@ -0,0 +1,142 @@
+package {
+  import flash.display.Sprite;
+  import flash.text.TextField;
+  import flash.text.TextFieldType;
+  import flash.events.MouseEvent;
+  import flash.system.Security;
+
+  import org.apache.thrift.transport.TSocket;
+  import org.apache.thrift.transport.TTransport;
+  import org.apache.thrift.protocol.TProtocol;
+  import org.apache.thrift.protocol.TBinaryProtocol;
+
+  /**
+   * Simple interface and connection logic implementation for tutorial.
+   */
+  public class CalculatorUI extends Sprite {
+    public static const BUTTON_PADDING:uint = 5;
+
+    private var mCalculatorClient:Calculator; // we use calculator through interface
+    private var mTransport:TTransport; // Transport, used to comunicate with server
+
+    private var mAddButton:Sprite;
+    private var mLeft:TextField;
+    private var mRight:TextField;
+    private var mResult:TextField;
+
+    private var pingButton:Sprite;
+
+    public function CalculatorUI() {
+      buildInterface();
+      initSecurity();
+      initConnection();
+    }
+
+    private function initSecurity():void {
+      Security.loadPolicyFile("xmlsocket://127.0.0.1:9092");
+    }
+
+    /**
+     * Example of initializing connection.
+     */
+    private function initConnection():void {
+      mTransport = new TSocket("127.0.0.1", 9090); // we connect to server
+      mTransport.open();
+      // initialize protocol:
+      var protocol:TProtocol = new TBinaryProtocol(mTransport, false, false);
+      mCalculatorClient = new CalculatorImpl(protocol); // finally, we create calculator client instance
+    }
+
+    private function onPingClick(me:MouseEvent):void {
+      if(!mTransport.isOpen()) return;
+      mCalculatorClient.ping(onPingError, onPingSuccess);
+    }
+
+    private function onPingError(error:Error):void {
+      trace("Error, while requesting ping.");
+      throw error;
+    }
+
+    private function onPingSuccess():void {
+      trace("Ping returned successfully");
+    }
+
+    private function onAddClick(me:MouseEvent):void {
+      if(!mTransport.isOpen()) return;
+      var num1:Number = Number(mLeft.text);
+      var num2:Number = Number(mRight.text);
+      mResult.text = "Processing...";
+      mCalculatorClient.add(num1, num2, onAddError, onAddSuccess);
+    }
+
+    private function onAddError(error:Error):void {
+      trace("Error, while requesting add.");
+      throw error;
+    }
+
+    private function onAddSuccess(res:Number):void {
+      mResult.text = String(res);
+    }
+
+    private function buildInterface():void {
+      addChild(pingButton = buildButton("PING"));
+      pingButton.x = (stage.stageWidth - pingButton.width) / 2;
+      pingButton.y = 10;
+      pingButton.addEventListener(MouseEvent.CLICK, onPingClick);
+
+      var top:Number = pingButton.y + pingButton.height + 20;
+      addChild(mLeft = buildDigitInput());
+      mLeft.x = 15;
+      mLeft.y = top + BUTTON_PADDING;
+      addChild(mRight = buildDigitInput());
+      mRight.x = mLeft.x + mLeft.width + 15;
+      mRight.y = top + BUTTON_PADDING;
+      addChild(mAddButton = buildButton("ADD"));
+      mAddButton.x = mRight.x + mRight.width + 15;
+      mAddButton.y = top;
+      mAddButton.addEventListener(MouseEvent.CLICK, onAddClick);
+      addChild(mResult = buildDigitInput());
+      mResult.x = mAddButton.x + mAddButton.width + 15;
+      mResult.y = top + BUTTON_PADDING;
+    }
+
+    /**
+     * Simple digit-only input field.
+     */
+    private function buildDigitInput():TextField {
+      var textField:TextField = new TextField;
+      textField.width = 75;
+      textField.height = 20;
+      textField.restrict = "0987654321.";
+      textField.type = TextFieldType.INPUT;
+      textField.background = true;
+      textField.backgroundColor = 0xaaaaff;
+      textField.textColor = 0xffff00;
+      return textField;
+    }
+
+    /**
+     * Simple button drawing.
+     */
+    private function buildButton(text:String):Sprite {
+      var button:Sprite = new Sprite;
+      var textField:TextField = new TextField;
+      textField.width = 4000;
+      textField.text = text;
+      textField.textColor = 0xffff00;
+      textField.width = textField.textWidth + 4;
+      textField.height = textField.textHeight + 4;
+      textField.mouseEnabled = false;
+      button.graphics.beginFill(0x0000ff);
+      button.graphics.lineStyle(0, 0x000000);
+      button.graphics.drawRoundRect(0, 0, textField.width + BUTTON_PADDING * 2,
+                                    textField.height + BUTTON_PADDING * 2, BUTTON_PADDING);
+      button.graphics.endFill();
+      button.addChild(textField);
+      textField.x = BUTTON_PADDING;
+      textField.y = BUTTON_PADDING;
+      button.useHandCursor = button.buttonMode = true;
+      return button;
+    }
+  }
+}
diff --git a/tutorial/c_glib/Makefile.am b/tutorial/c_glib/Makefile.am
new file mode 100755
index 0000000..4dbe655
--- /dev/null
+++ b/tutorial/c_glib/Makefile.am
@@ -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.
+#
+AUTOMAKE_OPTIONS = subdir-objects serial-tests
+
+BUILT_SOURCES = \
+	gen-c_glib/calculator.h \
+	gen-c_glib/shared_service.h \
+	gen-c_glib/shared_types.h \
+	gen-c_glib/tutorial_types.h
+
+AM_CFLAGS = -g -Wall -Wextra -pedantic $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(OPENSSL_INCLUDES) @GCOV_CFLAGS@
+AM_CPPFLAGS = -I$(top_srcdir)/lib/c_glib/src -Igen-c_glib
+AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) $(OPENSSL_LDFLAGS) $(OPENSSL_LIBS) @GCOV_LDFLAGS@
+
+noinst_LTLIBRARIES = \
+	libtutorialgencglib.la
+
+nodist_libtutorialgencglib_la_SOURCES = \
+	gen-c_glib/calculator.c \
+	gen-c_glib/calculator.h \
+	gen-c_glib/shared_service.c \
+	gen-c_glib/shared_service.h \
+	gen-c_glib/shared_types.c \
+	gen-c_glib/shared_types.h \
+	gen-c_glib/tutorial_types.c \
+	gen-c_glib/tutorial_types.h
+
+libtutorialgencglib_la_LIBADD = \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+libtutorialgencglib_la_CFLAGS = \
+	$(AM_CFLAGS) -Wno-unused-function
+
+noinst_PROGRAMS = \
+	tutorial_server \
+	tutorial_client
+
+tutorial_server_SOURCES = \
+	c_glib_server.c
+tutorial_server_LDFLAGS = $(OPENSSL_LIBS)
+
+tutorial_server_LDADD = \
+	libtutorialgencglib.la \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+tutorial_client_SOURCES = \
+	c_glib_client.c
+
+tutorial_client_LDADD = \
+	libtutorialgencglib.la \
+	$(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+
+gen-c_glib/calculator.c gen-c_glib/calculator.h gen-c_glib/shared_service.c gen-c_glib/shared_service.h gen-c_glib/shared_types.c gen-c_glib/shared_types.h gen-c_glib/tutorial_types.c gen-c_glib/tutorial_types.h: $(top_srcdir)/tutorial/tutorial.thrift
+	$(THRIFT) --gen c_glib -r $<
+
+clean-local:
+	$(RM) gen-c_glib/*
+
+tutorialserver: all
+	./tutorial_server
+
+tutorialclient: all
+	./tutorial_client
+
+EXTRA_DIST = \
+	c_glib_server.c \
+	c_glib_client.c
diff --git a/tutorial/c_glib/c_glib_client.c b/tutorial/c_glib/c_glib_client.c
new file mode 100644
index 0000000..986d517
--- /dev/null
+++ b/tutorial/c_glib/c_glib_client.c
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <glib-object.h>
+
+#include <thrift/c_glib/protocol/thrift_binary_protocol.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport.h>
+#include <thrift/c_glib/transport/thrift_socket.h>
+
+#include "gen-c_glib/calculator.h"
+
+int main (void)
+{
+  ThriftSocket *socket;
+  ThriftTransport *transport;
+  ThriftProtocol *protocol;
+  CalculatorIf *client;
+
+  GError *error = NULL;
+  InvalidOperation *invalid_operation = NULL;
+
+  Work *work;
+
+  gint32 sum;
+  gint32 diff;
+
+  int exit_status = 0;
+
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init ();
+#endif
+
+  socket    = g_object_new (THRIFT_TYPE_SOCKET,
+                            "hostname",  "localhost",
+                            "port",      9090,
+                            NULL);
+  transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+                            "transport", socket,
+                            NULL);
+  protocol  = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
+                            "transport", transport,
+                            NULL);
+
+  thrift_transport_open (transport, &error);
+
+
+  /* In the C (GLib) implementation of Thrift, service methods on the
+     server are accessed via a generated client class that implements
+     the service interface. In this tutorial, we access a Calculator
+     service through an instance of CalculatorClient, which implements
+     CalculatorIf. */
+  client = g_object_new (TYPE_CALCULATOR_CLIENT,
+                         "input_protocol",  protocol,
+                         "output_protocol", protocol,
+                         NULL);
+
+  /* Each of the client methods requires at least two parameters: A
+     pointer to the client-interface implementation (the client
+     object), and a handle to a GError structure to receive
+     information about any error that occurs.
+
+     On success, client methods return TRUE. A return value of FALSE
+     indicates an error occurred and the error parameter has been
+     set. */
+  if (!error && calculator_if_ping (client, &error)) {
+    puts ("ping()");
+  }
+
+  /* Service methods that return a value do so by passing the result
+     back via an output parameter (here, "sum"). */
+  if (!error && calculator_if_add (client, &sum, 1, 1, &error)) {
+    printf ("1+1=%d\n", sum);
+  }
+
+  /* Thrift structs are implemented as GObjects, with each of the
+     struct's members exposed as an object property. */
+  work = g_object_new (TYPE_WORK, NULL);
+
+  if (!error) {
+    g_object_set (work,
+                  "num1", 1,
+                  "num2", 0,
+                  "op",   OPERATION_DIVIDE,
+                  NULL);
+
+    /* Exceptions are passed back from service methods in a manner
+       similar to return values. */
+    if (calculator_if_calculate (client,
+                                 NULL,
+                                 1,
+                                 work,
+                                 &invalid_operation,
+                                 &error)) {
+      puts ("Whoa? We can divide by zero!");
+    }
+    else {
+      if (invalid_operation) {
+        gchar *why;
+
+        /* Like structs, exceptions are implemented as objects with
+           properties. */
+        g_object_get (invalid_operation, "why", &why, NULL);
+
+        printf ("InvalidOperation: %s\n", why);
+
+        if (why != NULL)
+          g_free (why);
+        g_object_unref (invalid_operation);
+        invalid_operation = NULL;
+      }
+
+      g_clear_error (&error);
+    }
+  }
+
+  if (!error) {
+    /* Struct objects can be reused across method invocations. */
+    g_object_set (work,
+                  "num1", 15,
+                  "num2", 10,
+                  "op",   OPERATION_SUBTRACT,
+                  NULL);
+
+    if (calculator_if_calculate (client,
+                                 &diff,
+                                 1,
+                                 work,
+                                 &invalid_operation,
+                                 &error)) {
+      printf ("15-10=%d\n", diff);
+    }
+  }
+
+  g_object_unref (work);
+
+  if (!error) {
+    SharedStruct *shared_struct;
+    gchar *value;
+
+    shared_struct = g_object_new (TYPE_SHARED_STRUCT, NULL);
+
+    /* As defined in the Thrift file, the Calculator service extends
+       the SharedService service. Correspondingly, in the generated
+       code CalculatorIf inherits from SharedServiceIf, and the parent
+       service's methods are accessible through a simple cast. */
+    if (shared_service_client_get_struct (SHARED_SERVICE_IF (client),
+                                          &shared_struct,
+                                          1,
+                                          &error)) {
+      g_object_get (shared_struct, "value", &value, NULL);
+      printf ("Check log: %s\n", value);
+      g_free (value);
+    }
+
+    g_object_unref (shared_struct);
+  }
+
+  if (error) {
+    printf ("ERROR: %s\n", error->message);
+    g_clear_error (&error);
+
+    exit_status = 1;
+  }
+
+  thrift_transport_close (transport, NULL);
+
+  g_object_unref (client);
+  g_object_unref (protocol);
+  g_object_unref (transport);
+  g_object_unref (socket);
+
+  return exit_status;
+}
diff --git a/tutorial/c_glib/c_glib_server.c b/tutorial/c_glib/c_glib_server.c
new file mode 100644
index 0000000..47bf47f
--- /dev/null
+++ b/tutorial/c_glib/c_glib_server.c
@@ -0,0 +1,527 @@
+/*
+ * 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.
+ */
+
+#include <glib-object.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/protocol/thrift_binary_protocol_factory.h>
+#include <thrift/c_glib/protocol/thrift_protocol_factory.h>
+#include <thrift/c_glib/server/thrift_server.h>
+#include <thrift/c_glib/server/thrift_simple_server.h>
+#include <thrift/c_glib/transport/thrift_buffered_transport_factory.h>
+#include <thrift/c_glib/transport/thrift_server_socket.h>
+#include <thrift/c_glib/transport/thrift_server_transport.h>
+
+#include "gen-c_glib/calculator.h"
+
+G_BEGIN_DECLS
+
+/* In the C (GLib) implementation of Thrift, the actual work done by a
+   server---that is, the code that runs when a client invokes a
+   service method---is defined in a separate "handler" class that
+   implements the service interface. Here we define the
+   TutorialCalculatorHandler class, which implements the CalculatorIf
+   interface and provides the behavior expected by tutorial clients.
+   (Typically this code would be placed in its own module but for
+   clarity this tutorial is presented entirely in a single file.)
+
+   For each service the Thrift compiler generates an abstract base
+   class from which handler implementations should inherit. In our
+   case TutorialCalculatorHandler inherits from CalculatorHandler,
+   defined in gen-c_glib/calculator.h.
+
+   If you're new to GObject, try not to be intimidated by the quantity
+   of code here---much of it is boilerplate and can mostly be
+   copied-and-pasted from existing work. For more information refer to
+   the GObject Reference Manual, available online at
+   https://developer.gnome.org/gobject/. */
+
+#define TYPE_TUTORIAL_CALCULATOR_HANDLER \
+  (tutorial_calculator_handler_get_type ())
+
+#define TUTORIAL_CALCULATOR_HANDLER(obj)                                \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                                   \
+                               TYPE_TUTORIAL_CALCULATOR_HANDLER,        \
+                               TutorialCalculatorHandler))
+#define TUTORIAL_CALCULATOR_HANDLER_CLASS(c)                    \
+  (G_TYPE_CHECK_CLASS_CAST ((c),                                \
+                            TYPE_TUTORIAL_CALCULATOR_HANDLER,   \
+                            TutorialCalculatorHandlerClass))
+#define IS_TUTORIAL_CALCULATOR_HANDLER(obj)                             \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                                   \
+                               TYPE_TUTORIAL_CALCULATOR_HANDLER))
+#define IS_TUTORIAL_CALCULATOR_HANDLER_CLASS(c)                 \
+  (G_TYPE_CHECK_CLASS_TYPE ((c),                                \
+                            TYPE_TUTORIAL_CALCULATOR_HANDLER))
+#define TUTORIAL_CALCULATOR_HANDLER_GET_CLASS(obj)              \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                            \
+                              TYPE_TUTORIAL_CALCULATOR_HANDLER, \
+                              TutorialCalculatorHandlerClass))
+
+struct _TutorialCalculatorHandler {
+  CalculatorHandler parent_instance;
+
+  /* private */
+  GHashTable *log;
+};
+typedef struct _TutorialCalculatorHandler TutorialCalculatorHandler;
+
+struct _TutorialCalculatorHandlerClass {
+  CalculatorHandlerClass parent_class;
+};
+typedef struct _TutorialCalculatorHandlerClass TutorialCalculatorHandlerClass;
+
+GType tutorial_calculator_handler_get_type (void);
+
+G_END_DECLS
+
+/* ---------------------------------------------------------------- */
+
+/* The implementation of TutorialCalculatorHandler follows. */
+
+G_DEFINE_TYPE (TutorialCalculatorHandler,
+               tutorial_calculator_handler,
+               TYPE_CALCULATOR_HANDLER)
+
+/* Each of a handler's methods accepts at least two parameters: A
+   pointer to the service-interface implementation (the handler object
+   itself) and a handle to a GError structure to receive information
+   about any error that occurs.
+
+   On success, a handler method returns TRUE. A return value of FALSE
+   indicates an error occurred and the error parameter has been
+   set. (Methods should not return FALSE without first setting the
+   error parameter.) */
+static gboolean
+tutorial_calculator_handler_ping (CalculatorIf  *iface,
+                                  GError       **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  puts ("ping()");
+
+  return TRUE;
+}
+
+/* Service-method parameters are passed through as parameters to the
+   handler method.
+
+   If the service method returns a value an output parameter, _return,
+   is additionally passed to the handler method. This parameter should
+   be set appropriately before the method returns, whenever it
+   succeeds.
+
+   The return value from this method happens to be of a base type,
+   i32, but note if a method returns a complex type such as a map or
+   list *_return will point to a pre-allocated data structure that
+   does not need to be re-allocated and should not be destroyed. */
+static gboolean
+tutorial_calculator_handler_add (CalculatorIf  *iface,
+                                 gint32        *_return,
+                                 const gint32   num1,
+                                 const gint32   num2,
+                                 GError       **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  printf ("add(%d,%d)\n", num1, num2);
+  *_return = num1 + num2;
+
+  return TRUE;
+}
+
+/* Any handler method can return a ThriftApplicationException to the
+   client by setting its error parameter appropriately and returning
+   FALSE. See the ThriftApplicationExceptionError enumeration defined
+   in thrift_application_exception.h for a list of recognized
+   exception types (GError codes).
+
+   If a service method can also throw a custom exception (that is, one
+   defined in the .thrift file) an additional output parameter will be
+   provided (here, "ouch") to hold an instance of the exception, when
+   necessary. Note there will be a separate parameter added for each
+   type of exception the method can throw.
+
+   Unlike return values, exception objects are never pre-created; this
+   is always the responsibility of the handler method. */
+static gboolean
+tutorial_calculator_handler_calculate (CalculatorIf      *iface,
+                                       gint32            *_return,
+                                       const gint32       logid,
+                                       const Work        *w,
+                                       InvalidOperation **ouch,
+                                       GError           **error)
+{
+  TutorialCalculatorHandler *self;
+
+  gint *log_key;
+  gchar log_value[12];
+  SharedStruct *log_struct;
+
+  gint num1;
+  gint num2;
+  Operation op;
+  gboolean result = TRUE;
+
+  THRIFT_UNUSED_VAR (error);
+
+  g_return_val_if_fail (IS_TUTORIAL_CALCULATOR_HANDLER (iface),
+                        FALSE);
+  self = TUTORIAL_CALCULATOR_HANDLER (iface);
+
+  /* Remember: Exception objects are never pre-created */
+  g_assert (*ouch == NULL);
+
+  /* Fetch the contents of our Work parameter.
+
+     Note that integer properties of thirty-two bits or fewer in width
+     are _always_ of type gint, regardless of the range of values they
+     hold. A common error is trying to retrieve, say, a structure
+     member defined in the .thrift file as type i16 into a variable of
+     type gint16, which will clobber variables adjacent on the
+     stack. Remember: If you're retrieving an integer property the
+     receiving variable must be of either type gint or gint64, as
+     appropriate. */
+  g_object_get ((Work *)w,
+                "num1", &num1,
+                "num2", &num2,
+                "op",   &op,
+                NULL);
+
+  printf ("calculate(%d,{%d,%d,%d})\n", logid, op, num1, num2);
+
+  switch (op) {
+  case OPERATION_ADD:
+    *_return = num1 + num2;
+    break;
+
+  case OPERATION_SUBTRACT:
+    *_return = num1 - num2;
+    break;
+
+  case OPERATION_MULTIPLY:
+    *_return = num1 * num2;
+    break;
+
+  case OPERATION_DIVIDE:
+    if (num2 == 0) {
+      /* For each custom exception type a subclass of ThriftStruct is
+         generated by the Thrift compiler. Throw an exception by
+         setting the corresponding output parameter to a new instance
+         of its type and returning FALSE. */
+      *ouch = g_object_new (TYPE_INVALID_OPERATION,
+                            "whatOp", op,
+                            "why",  g_strdup ("Cannot divide by 0"),
+                            NULL);
+      result = FALSE;
+
+      /* Note the call to g_strdup above: All the memory used by a
+         ThriftStruct's properties belongs to the object itself and
+         will be freed on destruction. Removing this call to g_strdup
+         will lead to a segmentation fault as the object tries to
+         release memory allocated statically to the program. */
+    }
+    else {
+      *_return = num1 / num2;
+    }
+    break;
+
+  default:
+    *ouch = g_object_new (TYPE_INVALID_OPERATION,
+                          "whatOp", op,
+                          "why",  g_strdup ("Invalid Operation"),
+                          NULL);
+    result = FALSE;
+  }
+
+  /* On success, log a record of the result to our hash table */
+  if (result) {
+    log_key = g_malloc (sizeof *log_key);
+    *log_key = logid;
+
+    snprintf (log_value, sizeof log_value, "%d", *_return);
+
+    log_struct = g_object_new (TYPE_SHARED_STRUCT,
+                               "key",   *log_key,
+                               "value",  g_strdup (log_value),
+                               NULL);
+    g_hash_table_replace (self->log, log_key, log_struct);
+  }
+
+  return result;
+}
+
+/* A one-way method has the same signature as an equivalent, regular
+   method that returns no value. */
+static gboolean
+tutorial_calculator_handler_zip (CalculatorIf  *iface,
+                                 GError       **error)
+{
+  THRIFT_UNUSED_VAR (iface);
+  THRIFT_UNUSED_VAR (error);
+
+  puts ("zip()");
+
+  return TRUE;
+}
+
+/* As specified in the .thrift file (tutorial.thrift), the Calculator
+   service extends the SharedService service. Correspondingly, in the
+   generated code the Calculator interface, CalculatorIf, extends the
+   SharedService interface, SharedServiceIf, and subclasses of
+   CalculatorHandler should implement its methods as well.
+
+   Here we provide an implementation for the getStruct method from the
+   parent service. */
+static gboolean
+tutorial_calculator_handler_get_struct (SharedServiceIf  *iface,
+                                        SharedStruct    **_return,
+                                        const gint32      key32,
+                                        GError          **error)
+{
+  gint key = (gint)key32;
+  TutorialCalculatorHandler *self;
+  SharedStruct *log_struct;
+  gint log_key;
+  gchar *log_value;
+
+  THRIFT_UNUSED_VAR (error);
+
+  g_return_val_if_fail (IS_TUTORIAL_CALCULATOR_HANDLER (iface),
+                        FALSE);
+  self = TUTORIAL_CALCULATOR_HANDLER (iface);
+
+  /* Remember: Complex return types are always pre-created and need
+     only be populated */
+  g_assert (*_return != NULL);
+
+  printf ("getStruct(%d)\n", key);
+
+  /* If the key exists in our log, return the corresponding logged
+     data (or an empty SharedStruct structure if it does not).
+
+     Incidentally, note we _must_ here copy the values from the hash
+     table into the return structure. All memory used by the return
+     structure belongs to the structure itself and will be freed once
+     a response is sent to the client. If we merely freed *_return and
+     set it to point to our hash-table entry, that would mean memory
+     would be released (effectively, data erased) out of the hash
+     table! */
+  log_struct = g_hash_table_lookup (self->log, &key);
+  if (log_struct != NULL) {
+    g_object_get (log_struct,
+                  "key",   &log_key,
+                  "value", &log_value,
+                  NULL);
+    g_object_set (*_return,
+                  "key",   log_key,
+                  "value", g_strdup (log_value),
+                  NULL);
+  }
+
+  return TRUE;
+}
+
+/* TutorialCalculatorHandler's instance finalizer (destructor) */
+static void
+tutorial_calculator_handler_finalize (GObject *object)
+{
+  TutorialCalculatorHandler *self =
+    TUTORIAL_CALCULATOR_HANDLER (object);
+
+  /* Free our calculation-log hash table */
+  g_hash_table_unref (self->log);
+  self->log = NULL;
+
+  /* Chain up to the parent class */
+  G_OBJECT_CLASS (tutorial_calculator_handler_parent_class)->
+    finalize (object);
+}
+
+/* TutorialCalculatorHandler's instance initializer (constructor) */
+static void
+tutorial_calculator_handler_init (TutorialCalculatorHandler *self)
+{
+  /* Create our calculation-log hash table */
+  self->log = g_hash_table_new_full (g_int_hash,
+                                     g_int_equal,
+                                     g_free,
+                                     g_object_unref);
+}
+
+/* TutorialCalculatorHandler's class initializer */
+static void
+tutorial_calculator_handler_class_init (TutorialCalculatorHandlerClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  SharedServiceHandlerClass *shared_service_handler_class =
+    SHARED_SERVICE_HANDLER_CLASS (klass);
+  CalculatorHandlerClass *calculator_handler_class =
+    CALCULATOR_HANDLER_CLASS (klass);
+
+  /* Register our destructor */
+  gobject_class->finalize = tutorial_calculator_handler_finalize;
+
+  /* Register our implementations of CalculatorHandler's methods */
+  calculator_handler_class->ping =
+    tutorial_calculator_handler_ping;
+  calculator_handler_class->add =
+    tutorial_calculator_handler_add;
+  calculator_handler_class->calculate =
+    tutorial_calculator_handler_calculate;
+  calculator_handler_class->zip =
+    tutorial_calculator_handler_zip;
+
+  /* Register our implementation of SharedServiceHandler's method */
+  shared_service_handler_class->get_struct =
+    tutorial_calculator_handler_get_struct;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* That ends the implementation of TutorialCalculatorHandler.
+   Everything below is fairly generic code that sets up a minimal
+   Thrift server for tutorial clients. */
+
+
+/* Our server object, declared globally so it is accessible within the
+   SIGINT signal handler */
+ThriftServer *server = NULL;
+
+/* A flag that indicates whether the server was interrupted with
+   SIGINT (i.e. Ctrl-C) so we can tell whether its termination was
+   abnormal */
+gboolean sigint_received = FALSE;
+
+/* Handle SIGINT ("Ctrl-C") signals by gracefully stopping the
+   server */
+static void
+sigint_handler (int signal_number)
+{
+  THRIFT_UNUSED_VAR (signal_number);
+
+  /* Take note we were called */
+  sigint_received = TRUE;
+
+  /* Shut down the server gracefully */
+  if (server != NULL)
+    thrift_server_stop (server);
+}
+
+int main (void)
+{
+  TutorialCalculatorHandler *handler;
+  CalculatorProcessor *processor;
+
+  ThriftServerTransport *server_transport;
+  ThriftTransportFactory *transport_factory;
+  ThriftProtocolFactory *protocol_factory;
+
+  struct sigaction sigint_action;
+
+  GError *error = NULL;
+  int exit_status = 0;
+
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+  g_type_init ();
+#endif
+
+  /* Create an instance of our handler, which provides the service's
+     methods' implementation */
+  handler =
+    g_object_new (TYPE_TUTORIAL_CALCULATOR_HANDLER,
+                  NULL);
+
+  /* Create an instance of the service's processor, automatically
+     generated by the Thrift compiler, which parses incoming messages
+     and dispatches them to the appropriate method in the handler */
+  processor =
+    g_object_new (TYPE_CALCULATOR_PROCESSOR,
+                  "handler", handler,
+                  NULL);
+
+  /* Create our server socket, which binds to the specified port and
+     listens for client connections */
+  server_transport =
+    g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+                  "port", 9090,
+                  NULL);
+
+  /* Create our transport factory, used by the server to wrap "raw"
+     incoming connections from the client (in this case with a
+     ThriftBufferedTransport to improve performance) */
+  transport_factory =
+    g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY,
+                  NULL);
+
+  /* Create our protocol factory, which determines which wire protocol
+     the server will use (in this case, Thrift's binary protocol) */
+  protocol_factory =
+    g_object_new (THRIFT_TYPE_BINARY_PROTOCOL_FACTORY,
+                  NULL);
+
+  /* Create the server itself */
+  server =
+    g_object_new (THRIFT_TYPE_SIMPLE_SERVER,
+                  "processor",                processor,
+                  "server_transport",         server_transport,
+                  "input_transport_factory",  transport_factory,
+                  "output_transport_factory", transport_factory,
+                  "input_protocol_factory",   protocol_factory,
+                  "output_protocol_factory",  protocol_factory,
+                  NULL);
+
+  /* Install our SIGINT handler, which handles Ctrl-C being pressed by
+     stopping the server gracefully (not strictly necessary, but a
+     nice touch) */
+  memset (&sigint_action, 0, sizeof (sigint_action));
+  sigint_action.sa_handler = sigint_handler;
+  sigint_action.sa_flags = SA_RESETHAND;
+  sigaction (SIGINT, &sigint_action, NULL);
+
+  /* Start the server, which will run until its stop method is invoked
+     (from within the SIGINT handler, in this case) */
+  puts ("Starting the server...");
+  thrift_server_serve (server, &error);
+
+  /* If the server stopped for any reason other than having been
+     interrupted by the user, report the error */
+  if (!sigint_received) {
+    g_message ("thrift_server_serve: %s",
+               error != NULL ? error->message : "(null)");
+    g_clear_error (&error);
+  }
+
+  puts ("done.");
+
+  g_object_unref (server);
+  g_object_unref (transport_factory);
+  g_object_unref (protocol_factory);
+  g_object_unref (server_transport);
+
+  g_object_unref (processor);
+  g_object_unref (handler);
+
+  return exit_status;
+}
diff --git a/tutorial/cl/Makefile.am b/tutorial/cl/Makefile.am
new file mode 100755
index 0000000..2b2013a
--- /dev/null
+++ b/tutorial/cl/Makefile.am
@@ -0,0 +1,65 @@
+#
+# 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.
+
+setup-local-lisp-env: ensure-externals.sh
+	bash ensure-externals.sh
+
+gen-cl: $(top_srcdir)/tutorial/tutorial.thrift
+	$(THRIFT) --gen cl -r $<
+
+ALL_FILE_PREREQS = \
+		   load-locally.lisp \
+		   make-tutorial-server.lisp \
+		   make-tutorial-client.lisp \
+		   shared-implementation.lisp \
+		   thrift-tutorial.asd \
+		   tutorial-implementation.lisp
+
+# NOTE: the server and client cannot be built in parallel
+# because on loading the make-tutorial-* scripts SBCL will
+# attempt to compile their dependencies. Unfortunately,
+# because their dependencies are shared, parallel jobs can
+# end up overwriting or corrupting the compiled files
+all-local: gen-cl setup-local-lisp-env $(ALL_FILE_PREREQS)
+	$(SBCL) --script make-tutorial-server.lisp
+	$(SBCL) --script make-tutorial-client.lisp
+
+tutorialserver: all
+	./TutorialServer
+
+tutorialclient: all
+	./TutorialClient
+
+clean-local:
+	-$(RM) -r gen-*
+	-$(RM) -r externals
+	-$(RM) -r quicklisp
+	-$(RM) -r lib
+	-$(RM) quicklisp.lisp
+	-$(RM) backport-update.zip
+	-$(RM) shared-implementation.fasl
+	-$(RM) tutorial-implementation.fasl
+	-$(RM) TutorialServer
+	-$(RM) TutorialClient
+
+EXTRA_DIST = \
+	tutorial-implementation.lisp \
+	shared-implementation.lisp \
+	thrift-tutorial.asd \
+	make-tutorial-server.lisp \
+	make-tutorial-client.lisp
diff --git a/tutorial/cl/ensure-externals.sh b/tutorial/cl/ensure-externals.sh
new file mode 120000
index 0000000..5ae8c56
--- /dev/null
+++ b/tutorial/cl/ensure-externals.sh
@@ -0,0 +1 @@
+../../lib/cl/ensure-externals.sh
\ No newline at end of file
diff --git a/tutorial/cl/load-locally.lisp b/tutorial/cl/load-locally.lisp
new file mode 100644
index 0000000..b52a0a2
--- /dev/null
+++ b/tutorial/cl/load-locally.lisp
@@ -0,0 +1,22 @@
+(in-package #:cl-user)
+
+;;;; Licensed under the Apache License, Version 2.0 (the "License");
+;;;; you may not use this file except in compliance with the License.
+;;;; You may obtain a copy of the License at
+;;;;
+;;;;     http://www.apache.org/licenses/LICENSE-2.0
+;;;;
+;;;; Unless required by applicable law or agreed to in writing, software
+;;;; distributed under the License is distributed on an "AS IS" BASIS,
+;;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;;;; See the License for the specific language governing permissions and
+;;;; limitations under the License.
+
+;;;; Just a script for loading the library itself, using bundled dependencies.
+;;;; This is an identical copy of the file in lib/cl.
+
+(require "asdf")
+
+(load (merge-pathnames "externals/bundle.lisp" *load-truename*))
+(asdf:load-asd (merge-pathnames "lib/de.setf.thrift-backport-update/thrift.asd" *load-truename*))
+(asdf:load-system :thrift)
diff --git a/tutorial/cl/make-tutorial-client.lisp b/tutorial/cl/make-tutorial-client.lisp
new file mode 100644
index 0000000..3a6d861
--- /dev/null
+++ b/tutorial/cl/make-tutorial-client.lisp
@@ -0,0 +1,51 @@
+(in-package #:cl-user)
+
+;;;; Licensed under the Apache License, Version 2.0 (the "License");
+;;;; you may not use this file except in compliance with the License.
+;;;; You may obtain a copy of the License at
+;;;;
+;;;;     http://www.apache.org/licenses/LICENSE-2.0
+;;;;
+;;;; Unless required by applicable law or agreed to in writing, software
+;;;; distributed under the License is distributed on an "AS IS" BASIS,
+;;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;;;; See the License for the specific language governing permissions and
+;;;; limitations under the License.
+
+(require "asdf")
+(load (merge-pathnames "load-locally.lisp" *load-truename*))
+(asdf:load-system :net.didierverna.clon)
+(asdf:load-asd (merge-pathnames "gen-cl/shared/thrift-gen-shared.asd" *load-truename*))
+(asdf:load-asd (merge-pathnames "gen-cl/tutorial/thrift-gen-tutorial.asd" *load-truename*))
+(asdf:load-asd (merge-pathnames "thrift-tutorial.asd" *load-truename*))
+(asdf:load-system :thrift-tutorial)
+
+(net.didierverna.clon:nickname-package)
+
+(defun main ()
+  "Entry point for the binary."
+  (thrift:with-client (prot #u"thrift://127.0.0.1:9090")
+    (tutorial.calculator:ping prot)
+    (format t "ping()~%")
+    (format t "1 + 1 = ~a~%" (tutorial.calculator:add prot 1 1))
+    (let ((work-instance (tutorial:make-work :num1 5
+                                             :num2 0
+                                             :op tutorial:operation.divide
+                                             :comment "Booya!")))
+      (handler-case (format t
+                            "5 / 0 = ~a - Oh, really? An exception should have been thrown here.~%"
+                            (tutorial.calculator:calculate prot 1 work-instance))
+        (tutorial:invalidoperation (e)
+          (format t "---~%(Expected) Invalid Operation caught: ~%~a~%---~%" e))))
+    (let ((work-instance (tutorial:make-work :num1 15
+                                             :num2 10
+                                             :op tutorial:operation.subtract
+                                             :comment "Playing nice this time.")))
+      (handler-case (format t
+                            "15 - 10 = ~a~%"
+                            (tutorial.calculator:calculate prot 1 work-instance))
+        (tutorial:invalidoperation (e)
+          (format t "---~%(Unexpected) Invalid Operation caught: ~%~a~%---~%" e))))
+    (format t "Check log: ~a~%" (shared.shared-service:get-struct prot 1))))
+
+(clon:dump "TutorialClient" main)
diff --git a/tutorial/cl/make-tutorial-server.lisp b/tutorial/cl/make-tutorial-server.lisp
new file mode 100644
index 0000000..4cf1a90
--- /dev/null
+++ b/tutorial/cl/make-tutorial-server.lisp
@@ -0,0 +1,29 @@
+(in-package #:cl-user)
+
+;;;; Licensed under the Apache License, Version 2.0 (the "License");
+;;;; you may not use this file except in compliance with the License.
+;;;; You may obtain a copy of the License at
+;;;;
+;;;;     http://www.apache.org/licenses/LICENSE-2.0
+;;;;
+;;;; Unless required by applicable law or agreed to in writing, software
+;;;; distributed under the License is distributed on an "AS IS" BASIS,
+;;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;;;; See the License for the specific language governing permissions and
+;;;; limitations under the License.
+
+(require "asdf")
+(load (merge-pathnames "load-locally.lisp" *load-truename*))
+(asdf:load-system :net.didierverna.clon)
+(asdf:load-asd (merge-pathnames "gen-cl/shared/thrift-gen-shared.asd" *load-truename*))
+(asdf:load-asd (merge-pathnames "gen-cl/tutorial/thrift-gen-tutorial.asd" *load-truename*))
+(asdf:load-asd (merge-pathnames "thrift-tutorial.asd" *load-truename*))
+(asdf:load-system :thrift-tutorial)
+
+(net.didierverna.clon:nickname-package)
+
+(defun main ()
+  "Entry point for the binary."
+  (thrift:serve #u"thrift://127.0.0.1:9090" tutorial:calculator))
+
+(clon:dump "TutorialServer" main)
diff --git a/tutorial/cl/shared-implementation.lisp b/tutorial/cl/shared-implementation.lisp
new file mode 100644
index 0000000..c197626
--- /dev/null
+++ b/tutorial/cl/shared-implementation.lisp
@@ -0,0 +1,25 @@
+(in-package #:shared-implementation)
+
+;;;; Licensed under the Apache License, Version 2.0 (the "License");
+;;;; you may not use this file except in compliance with the License.
+;;;; You may obtain a copy of the License at
+;;;;
+;;;;     http://www.apache.org/licenses/LICENSE-2.0
+;;;;
+;;;; Unless required by applicable law or agreed to in writing, software
+;;;; distributed under the License is distributed on an "AS IS" BASIS,
+;;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;;;; See the License for the specific language governing permissions and
+;;;; limitations under the License.
+
+(defvar *structs* (make-hash-table))
+
+(defun shared.shared-service-implementation:get-struct (key)
+  (format t "getStruct(~a)~%" key)
+  (gethash key *structs*))
+
+(defun add-log (key value)
+  (setf (gethash key *structs*)
+        (make-instance 'shared:sharedstruct
+                       :key key
+                       :value (write-to-string value))))
diff --git a/tutorial/cl/thrift-tutorial.asd b/tutorial/cl/thrift-tutorial.asd
new file mode 100644
index 0000000..8a03537
--- /dev/null
+++ b/tutorial/cl/thrift-tutorial.asd
@@ -0,0 +1,17 @@
+;;;; Licensed under the Apache License, Version 2.0 (the "License");
+;;;; you may not use this file except in compliance with the License.
+;;;; You may obtain a copy of the License at
+;;;;
+;;;;     http://www.apache.org/licenses/LICENSE-2.0
+;;;;
+;;;; Unless required by applicable law or agreed to in writing, software
+;;;; distributed under the License is distributed on an "AS IS" BASIS,
+;;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;;;; See the License for the specific language governing permissions and
+;;;; limitations under the License.
+
+(asdf:defsystem #:thrift-tutorial
+  :depends-on (#:thrift-gen-tutorial)
+  :serial t
+  :components ((:file "shared-implementation")
+               (:file "tutorial-implementation")))
diff --git a/tutorial/cl/tutorial-implementation.lisp b/tutorial/cl/tutorial-implementation.lisp
new file mode 100644
index 0000000..5c92fe4
--- /dev/null
+++ b/tutorial/cl/tutorial-implementation.lisp
@@ -0,0 +1,41 @@
+(in-package #:tutorial-implementation)
+
+;;;; Licensed under the Apache License, Version 2.0 (the "License");
+;;;; you may not use this file except in compliance with the License.
+;;;; You may obtain a copy of the License at
+;;;;
+;;;;     http://www.apache.org/licenses/LICENSE-2.0
+;;;;
+;;;; Unless required by applicable law or agreed to in writing, software
+;;;; distributed under the License is distributed on an "AS IS" BASIS,
+;;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+;;;; See the License for the specific language governing permissions and
+;;;; limitations under the License.
+
+(defun tutorial.calculator-implementation:ping ()
+  (format t "ping()~%"))
+
+(defun tutorial.calculator-implementation:add (num1 num2)
+  (format t "add(~a, ~a)~%" num1 num2)
+  (+ num1 num2))
+
+(defun tutorial.calculator-implementation:calculate (logid work)
+  (format t "calculate(~a, ~a)~%" logid work)
+  (handler-case
+      (let* ((num1 (tutorial:work-num1 work))
+             (num2 (tutorial:work-num2 work))
+             (op (tutorial:work-op work))
+             (result
+              (cond
+                ((= op tutorial:operation.add) (+ num1 num2))
+                ((= op tutorial:operation.subtract) (- num1 num2))
+                ((= op tutorial:operation.multiply) (* num1 num2))
+                ((= op tutorial:operation.divide) (/ num1 num2)))))
+        (shared-implementation::add-log logid result)
+        result)
+    (division-by-zero () (error 'tutorial:invalidoperation
+                                :why "Division by zero."
+                                :what-op (tutorial:work-op work)))))
+
+(defun tutorial.calculator-implementation:zip ()
+  (format t "zip()~%"))
diff --git a/tutorial/cpp/CMakeLists.txt b/tutorial/cpp/CMakeLists.txt
new file mode 100644
index 0000000..8634b41
--- /dev/null
+++ b/tutorial/cpp/CMakeLists.txt
@@ -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.
+#
+
+include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
+
+#Make sure gen-cpp files can be included
+include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen-cpp")
+include_directories("${PROJECT_SOURCE_DIR}/lib/cpp/src")
+
+include(ThriftMacros)
+
+set(tutorialgencpp_SOURCES
+    gen-cpp/Calculator.cpp
+    gen-cpp/SharedService.cpp
+    gen-cpp/shared_constants.cpp
+    gen-cpp/shared_types.cpp
+    gen-cpp/tutorial_constants.cpp
+    gen-cpp/tutorial_types.cpp
+)
+add_library(tutorialgencpp STATIC ${tutorialgencpp_SOURCES})
+LINK_AGAINST_THRIFT_LIBRARY(tutorialgencpp thrift)
+
+add_custom_command(OUTPUT gen-cpp/Calculator.cpp gen-cpp/SharedService.cpp gen-cpp/shared_constants.cpp gen-cpp/shared_types.cpp gen-cpp/tutorial_constants.cpp gen-cpp/tutorial_types.cpp
+    COMMAND ${THRIFT_COMPILER} --gen cpp -r ${PROJECT_SOURCE_DIR}/tutorial/tutorial.thrift
+)
+
+add_executable(TutorialServer CppServer.cpp)
+target_link_libraries(TutorialServer tutorialgencpp)
+LINK_AGAINST_THRIFT_LIBRARY(TutorialServer thrift)
+if (ZLIB_FOUND)
+  target_link_libraries(TutorialServer ${ZLIB_LIBRARIES})
+endif ()
+
+add_executable(TutorialClient CppClient.cpp)
+target_link_libraries(TutorialClient tutorialgencpp)
+LINK_AGAINST_THRIFT_LIBRARY(TutorialClient thrift)
+if (ZLIB_FOUND)
+  target_link_libraries(TutorialClient ${ZLIB_LIBRARIES})
+endif ()
diff --git a/tutorial/cpp/CppClient.cpp b/tutorial/cpp/CppClient.cpp
index ba71caa..5208411 100644
--- a/tutorial/cpp/CppClient.cpp
+++ b/tutorial/cpp/CppClient.cpp
@@ -17,9 +17,7 @@
  * under the License.
  */
 
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/time.h>
+#include <iostream>
 
 #include <thrift/protocol/TBinaryProtocol.h>
 #include <thrift/transport/TSocket.h>
@@ -35,22 +33,19 @@
 using namespace tutorial;
 using namespace shared;
 
-using namespace boost;
-
-int main(int argc, char** argv) {
-  shared_ptr<TTransport> socket(new TSocket("localhost", 9090));
-  shared_ptr<TTransport> transport(new TBufferedTransport(socket));
-  shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
+int main() {
+  std::shared_ptr<TTransport> socket(new TSocket("localhost", 9090));
+  std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
+  std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
   CalculatorClient client(protocol);
 
   try {
     transport->open();
 
     client.ping();
-    printf("ping()\n");
+    cout << "ping()" << endl;
 
-    int32_t sum = client.add(1,1);
-    printf("1+1=%d\n", sum);
+    cout << "1 + 1 = " << client.add(1, 1) << endl;
 
     Work work;
     work.op = Operation::DIVIDE;
@@ -59,26 +54,27 @@
 
     try {
       client.calculate(1, work);
-      printf("Whoa? We can divide by zero!\n");
-    } catch (InvalidOperation &io) {
-      printf("InvalidOperation: %s\n", io.why.c_str());
+      cout << "Whoa? We can divide by zero!" << endl;
+    } catch (InvalidOperation& io) {
+      cout << "InvalidOperation: " << io.why << endl;
+      // or using generated operator<<: cout << io << endl;
+      // or by using std::exception native method what(): cout << io.what() << endl;
     }
 
     work.op = Operation::SUBTRACT;
     work.num1 = 15;
     work.num2 = 10;
     int32_t diff = client.calculate(1, work);
-    printf("15-10=%d\n", diff);
+    cout << "15 - 10 = " << diff << endl;
 
     // Note that C++ uses return by reference for complex types to avoid
     // costly copy construction
     SharedStruct ss;
     client.getStruct(ss, 1);
-    printf("Check log: %s\n", ss.value.c_str());
+    cout << "Received log: " << ss << endl;
 
     transport->close();
-  } catch (TException &tx) {
-    printf("ERROR: %s\n", tx.what());
+  } catch (TException& tx) {
+    cout << "ERROR: " << tx.what() << endl;
   }
-
 }
diff --git a/tutorial/cpp/CppServer.cpp b/tutorial/cpp/CppServer.cpp
index d0dbad9..f7379d5 100644
--- a/tutorial/cpp/CppServer.cpp
+++ b/tutorial/cpp/CppServer.cpp
@@ -18,13 +18,15 @@
  */
 
 #include <thrift/concurrency/ThreadManager.h>
-#include <thrift/concurrency/PosixThreadFactory.h>
+#include <thrift/concurrency/PlatformThreadFactory.h>
 #include <thrift/protocol/TBinaryProtocol.h>
 #include <thrift/server/TSimpleServer.h>
 #include <thrift/server/TThreadPoolServer.h>
 #include <thrift/server/TThreadedServer.h>
 #include <thrift/transport/TServerSocket.h>
+#include <thrift/transport/TSocket.h>
 #include <thrift/transport/TTransportUtils.h>
+#include <thrift/TToString.h>
 
 #include <iostream>
 #include <stdexcept>
@@ -34,6 +36,7 @@
 
 using namespace std;
 using namespace apache::thrift;
+using namespace apache::thrift::concurrency;
 using namespace apache::thrift::protocol;
 using namespace apache::thrift::transport;
 using namespace apache::thrift::server;
@@ -41,23 +44,19 @@
 using namespace tutorial;
 using namespace shared;
 
-using namespace boost;
-
 class CalculatorHandler : public CalculatorIf {
- public:
+public:
   CalculatorHandler() {}
 
-  void ping() {
-    printf("ping()\n");
-  }
+  void ping() { cout << "ping()" << endl; }
 
   int32_t add(const int32_t n1, const int32_t n2) {
-    printf("add(%d,%d)\n", n1, n2);
+    cout << "add(" << n1 << ", " << n2 << ")" << endl;
     return n1 + n2;
   }
 
-  int32_t calculate(const int32_t logid, const Work &work) {
-    printf("calculate(%d,{%d,%d,%d})\n", logid, work.op, work.num1, work.num2);
+  int32_t calculate(const int32_t logid, const Work& work) {
+    cout << "calculate(" << logid << ", " << work << ")" << endl;
     int32_t val;
 
     switch (work.op) {
@@ -73,7 +72,7 @@
     case Operation::DIVIDE:
       if (work.num2 == 0) {
         InvalidOperation io;
-        io.what = work.op;
+        io.whatOp = work.op;
         io.why = "Cannot divide by 0";
         throw io;
       }
@@ -81,74 +80,100 @@
       break;
     default:
       InvalidOperation io;
-      io.what = work.op;
+      io.whatOp = work.op;
       io.why = "Invalid Operation";
       throw io;
     }
 
     SharedStruct ss;
     ss.key = logid;
-    char buffer[12];
-    snprintf(buffer, sizeof(buffer), "%d", val);
-    ss.value = buffer;
+    ss.value = to_string(val);
 
     log[logid] = ss;
 
     return val;
   }
 
-  void getStruct(SharedStruct &ret, const int32_t logid) {
-    printf("getStruct(%d)\n", logid);
+  void getStruct(SharedStruct& ret, const int32_t logid) {
+    cout << "getStruct(" << logid << ")" << endl;
     ret = log[logid];
   }
 
-  void zip() {
-    printf("zip()\n");
-  }
+  void zip() { cout << "zip()" << endl; }
 
 protected:
   map<int32_t, SharedStruct> log;
-
 };
 
-int main(int argc, char **argv) {
+/*
+  CalculatorIfFactory is code generated.
+  CalculatorCloneFactory is useful for getting access to the server side of the
+  transport.  It is also useful for making per-connection state.  Without this
+  CloneFactory, all connections will end up sharing the same handler instance.
+*/
+class CalculatorCloneFactory : virtual public CalculatorIfFactory {
+ public:
+  virtual ~CalculatorCloneFactory() {}
+  virtual CalculatorIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo)
+  {
+    std::shared_ptr<TSocket> sock = std::dynamic_pointer_cast<TSocket>(connInfo.transport);
+    cout << "Incoming connection\n";
+    cout << "\tSocketInfo: "  << sock->getSocketInfo() << "\n";
+    cout << "\tPeerHost: "    << sock->getPeerHost() << "\n";
+    cout << "\tPeerAddress: " << sock->getPeerAddress() << "\n";
+    cout << "\tPeerPort: "    << sock->getPeerPort() << "\n";
+    return new CalculatorHandler;
+  }
+  virtual void releaseHandler( ::shared::SharedServiceIf* handler) {
+    delete handler;
+  }
+};
 
-  shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
-  shared_ptr<CalculatorHandler> handler(new CalculatorHandler());
-  shared_ptr<TProcessor> processor(new CalculatorProcessor(handler));
-  shared_ptr<TServerTransport> serverTransport(new TServerSocket(9090));
-  shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
+int main() {
+  TThreadedServer server(
+    std::make_shared<CalculatorProcessorFactory>(std::make_shared<CalculatorCloneFactory>()),
+    std::make_shared<TServerSocket>(9090), //port
+    std::make_shared<TBufferedTransportFactory>(),
+    std::make_shared<TBinaryProtocolFactory>());
 
-  TSimpleServer server(processor,
-                       serverTransport,
-                       transportFactory,
-                       protocolFactory);
-
-
-  /**
-   * Or you could do one of these
-
-  shared_ptr<ThreadManager> threadManager =
-    ThreadManager::newSimpleThreadManager(workerCount);
-  shared_ptr<PosixThreadFactory> threadFactory =
-    shared_ptr<PosixThreadFactory>(new PosixThreadFactory());
-  threadManager->threadFactory(threadFactory);
-  threadManager->start();
-  TThreadPoolServer server(processor,
-                           serverTransport,
-                           transportFactory,
-                           protocolFactory,
-                           threadManager);
-
-  TThreadedServer server(processor,
-                         serverTransport,
-                         transportFactory,
-                         protocolFactory);
-
+  /*
+  // if you don't need per-connection state, do the following instead
+  TThreadedServer server(
+    std::make_shared<CalculatorProcessor>(std::make_shared<CalculatorHandler>()),
+    std::make_shared<TServerSocket>(9090), //port
+    std::make_shared<TBufferedTransportFactory>(),
+    std::make_shared<TBinaryProtocolFactory>());
   */
 
-  printf("Starting the server...\n");
+  /**
+   * Here are some alternate server types...
+
+  // This server only allows one connection at a time, but spawns no threads
+  TSimpleServer server(
+    std::make_shared<CalculatorProcessor>(std::make_shared<CalculatorHandler>()),
+    std::make_shared<TServerSocket>(9090),
+    std::make_shared<TBufferedTransportFactory>(),
+    std::make_shared<TBinaryProtocolFactory>());
+
+  const int workerCount = 4;
+
+  std::shared_ptr<ThreadManager> threadManager =
+    ThreadManager::newSimpleThreadManager(workerCount);
+  threadManager->threadFactory(
+    std::make_shared<PlatformThreadFactory>());
+  threadManager->start();
+
+  // This server allows "workerCount" connection at a time, and reuses threads
+  TThreadPoolServer server(
+    std::make_shared<CalculatorProcessorFactory>(std::make_shared<CalculatorCloneFactory>()),
+    std::make_shared<TServerSocket>(9090),
+    std::make_shared<TBufferedTransportFactory>(),
+    std::make_shared<TBinaryProtocolFactory>(),
+    threadManager);
+  */
+
+  cout << "Starting the server..." << endl;
   server.serve();
-  printf("done.\n");
+  cout << "Done." << endl;
   return 0;
 }
diff --git a/tutorial/cpp/Makefile.am b/tutorial/cpp/Makefile.am
index b829845..49cf3be 100755
--- a/tutorial/cpp/Makefile.am
+++ b/tutorial/cpp/Makefile.am
@@ -16,7 +16,11 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-.NOTPARALLEL:
+AUTOMAKE_OPTIONS = subdir-objects serial-tests
+
+BUILT_SOURCES = gen-cpp/shared_types.cpp \
+                gen-cpp/tutorial_types.cpp
+
 noinst_LTLIBRARIES = libtutorialgencpp.la
 nodist_libtutorialgencpp_la_SOURCES = \
 	gen-cpp/Calculator.cpp \
@@ -57,20 +61,15 @@
 #
 # Common thrift code generation rules
 #
-THRIFT = $(top_builddir)/compiler/cpp/thrift
-
-gen-cpp/Calculator.cpp gen-cpp/tutorial_types.cpp gen-cpp/tutorial_constants.cpp: $(top_srcdir)/tutorial/tutorial.thrift
+gen-cpp/Calculator.cpp gen-cpp/SharedService.cpp gen-cpp/shared_constants.cpp gen-cpp/shared_types.cpp gen-cpp/tutorial_constants.cpp gen-cpp/tutorial_types.cpp: $(top_srcdir)/tutorial/tutorial.thrift
 	$(THRIFT) --gen cpp -r $<
 
-INCLUDES = \
-	-I$(top_srcdir)/lib/cpp/src -Igen-cpp
-
-AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS)
-AM_CXXFLAGS = -Wall
+AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -Igen-cpp
+AM_CXXFLAGS = -Wall -Wextra -pedantic
 AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS)
 
 clean-local:
-	$(RM) -r gen-cpp
+	$(RM) gen-cpp/*
 
 tutorialserver: all
 	./TutorialServer
@@ -78,6 +77,10 @@
 tutorialclient: all
 	./TutorialClient
 
+style-local:
+	$(CPPSTYLE_CMD)
+
 EXTRA_DIST = \
+	CMakeLists.txt \
 	CppClient.cpp \
 	CppServer.cpp
diff --git a/tutorial/csharp/CsharpClient/CsharpClient.csproj b/tutorial/csharp/CsharpClient/CsharpClient.csproj
index 517ad83..1ea7ff6 100644
--- a/tutorial/csharp/CsharpClient/CsharpClient.csproj
+++ b/tutorial/csharp/CsharpClient/CsharpClient.csproj
@@ -1,88 +1,110 @@
-<?xml version="1.0" encoding="utf-8"?>

-<!--

-  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.

--->

-<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

-  <PropertyGroup>

-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

-    <ProductVersion>9.0.30729</ProductVersion>

-    <SchemaVersion>2.0</SchemaVersion>

-    <ProjectGuid>{18F24087-4760-43DA-ACAB-7B9F0E096B11}</ProjectGuid>

-    <OutputType>Exe</OutputType>

-    <AppDesignerFolder>Properties</AppDesignerFolder>

-    <RootNamespace>CsharpClient</RootNamespace>

-    <AssemblyName>CsharpClient</AssemblyName>

-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>

-    <FileAlignment>512</FileAlignment>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

-    <DebugSymbols>true</DebugSymbols>

-    <DebugType>full</DebugType>

-    <Optimize>false</Optimize>

-    <OutputPath>bin\Debug\</OutputPath>

-    <DefineConstants>DEBUG;TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

-    <DebugType>pdbonly</DebugType>

-    <Optimize>true</Optimize>

-    <OutputPath>bin\Release\</OutputPath>

-    <DefineConstants>TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-  </PropertyGroup>

-  <ItemGroup>

-    <Reference Include="System" />

-    <Reference Include="System.Core">

-      <RequiredTargetFramework>3.5</RequiredTargetFramework>

-    </Reference>

-    <Reference Include="System.Xml.Linq">

-      <RequiredTargetFramework>3.5</RequiredTargetFramework>

-    </Reference>

-    <Reference Include="System.Data.DataSetExtensions">

-      <RequiredTargetFramework>3.5</RequiredTargetFramework>

-    </Reference>

-    <Reference Include="System.Data" />

-    <Reference Include="System.Xml" />

-    <Reference Include="Thrift, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">

-      <SpecificVersion>False</SpecificVersion>

-      <HintPath>..\..\..\lib\csharp\src\bin\Release\Thrift.dll</HintPath>

-    </Reference>

-  </ItemGroup>

-  <ItemGroup>

-    <Compile Include="CsharpClient.cs" />

-    <Compile Include="Properties\AssemblyInfo.cs" />

-    <Compile Include="..\..\gen-csharp\Calculator.cs" />

-    <Compile Include="..\..\gen-csharp\Constants.cs" />

-    <Compile Include="..\..\gen-csharp\InvalidOperation.cs" />

-    <Compile Include="..\..\gen-csharp\Operation.cs" />

-    <Compile Include="..\..\gen-csharp\SharedService.cs" />

-    <Compile Include="..\..\gen-csharp\SharedStruct.cs" />

-    <Compile Include="..\..\gen-csharp\Work.cs" />

-  </ItemGroup>

-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

-       Other similar extension points exist, see Microsoft.Common.targets.

-  <Target Name="BeforeBuild">

-  </Target>

-  <Target Name="AfterBuild">

-  </Target>

-  -->

+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{18F24087-4760-43DA-ACAB-7B9F0E096B11}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>CsharpClient</RootNamespace>
+    <AssemblyName>CsharpClient</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\gen-csharp\Calculator.cs">
+      <Link>Calculator.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\InvalidOperation.cs">
+      <Link>InvalidOperation.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\Operation.cs">
+      <Link>Operation.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\SharedService.cs">
+      <Link>SharedService.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\SharedStruct.cs">
+      <Link>SharedStruct.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\tutorial.Constants.cs">
+      <Link>tutorial.Constants.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\Work.cs">
+      <Link>Work.cs</Link>
+    </Compile>
+    <Compile Include="CsharpClient.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\lib\csharp\src\Thrift.csproj">
+      <Project>{499eb63c-d74c-47e8-ae48-a2fc94538e9d}</Project>
+      <Name>Thrift</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent>pushd "$(SolutionDir)"
+thrift  -gen csharp   -r  ../tutorial.thrift
+popd
+</PreBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
 </Project>
\ No newline at end of file
diff --git a/tutorial/csharp/CsharpClient/Properties/AssemblyInfo.cs b/tutorial/csharp/CsharpClient/Properties/AssemblyInfo.cs
index ffbc40d..1ff658c 100644
--- a/tutorial/csharp/CsharpClient/Properties/AssemblyInfo.cs
+++ b/tutorial/csharp/CsharpClient/Properties/AssemblyInfo.cs
@@ -1,55 +1,55 @@
-/*

- * 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.

- */

-

-using System.Reflection;

-using System.Runtime.CompilerServices;

-using System.Runtime.InteropServices;

-

-// General Information about an assembly is controlled through the following

-// set of attributes. Change these attribute values to modify the information

-// associated with an assembly.

-[assembly: AssemblyTitle("CsharpClient")]

-[assembly: AssemblyDescription("")]

-[assembly: AssemblyConfiguration("")]

-[assembly: AssemblyCompany("")]

-[assembly: AssemblyProduct("CsharpClient")]

-[assembly: AssemblyCopyright("Copyright © 2010 The Apache Software Foundation")]

-[assembly: AssemblyTrademark("")]

-[assembly: AssemblyCulture("")]

-

-// Setting ComVisible to false makes the types in this assembly not visible

-// to COM components.  If you need to access a type in this assembly from

-// COM, set the ComVisible attribute to true on that type.

-[assembly: ComVisible(false)]

-

-// The following GUID is for the ID of the typelib if this project is exposed to COM

-[assembly: Guid("1a461214-fa28-452a-bd1d-d23ca8e947e3")]

-

-// Version information for an assembly consists of the following four values:

-//

-//      Major Version

-//      Minor Version

-//      Build Number

-//      Revision

-//

-// You can specify all the values or you can default the Build and Revision Numbers

-// by using the '*' as shown below:

-// [assembly: AssemblyVersion("1.0.*")]

-[assembly: AssemblyVersion("1.0.0.0")]

-[assembly: AssemblyFileVersion("1.0.0.0")]

+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CsharpClient")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("1a461214-fa28-452a-bd1d-d23ca8e947e3")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/tutorial/csharp/CsharpServer/CsharpServer.cs b/tutorial/csharp/CsharpServer/CsharpServer.cs
index 0d37c99..439790a 100644
--- a/tutorial/csharp/CsharpServer/CsharpServer.cs
+++ b/tutorial/csharp/CsharpServer/CsharpServer.cs
@@ -15,115 +15,115 @@
  * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations
  * under the License.
- */

-

-using System;

-using System.Collections.Generic;

-using Thrift.Server;

-using Thrift.Transport;

-

-namespace CSharpTutorial

-{

-    public class CalculatorHandler : Calculator.Iface

-    {

-        Dictionary<int, SharedStruct> log;

-

-        public CalculatorHandler()

-        {

-            log = new Dictionary<int, SharedStruct>();

-        }

-

-        public void ping()

-        {

-            Console.WriteLine("ping()");

-        }

-

-        public int add(int n1, int n2)

-        {

-            Console.WriteLine("add({0},{1})", n1, n2);

-            return n1 + n2;

-        }

-

-        public int calculate(int logid, Work work)

-        {

-            Console.WriteLine("calculate({0}, [{1},{2},{3}])", logid, work.Op, work.Num1, work.Num2);

-            int val = 0;

-            switch (work.Op)

-            {

-                case Operation.ADD:

-                    val = work.Num1 + work.Num2;

-                    break;

-

-                case Operation.SUBTRACT:

-                    val = work.Num1 - work.Num2;

-                    break;

-

-                case Operation.MULTIPLY:

-                    val = work.Num1 * work.Num2;

-                    break;

-

-                case Operation.DIVIDE:

-                    if (work.Num2 == 0)

-                    {

-                        InvalidOperation io = new InvalidOperation();

-                        io.What = (int)work.Op;

-                        io.Why = "Cannot divide by 0";

-                        throw io;

-                    }

-                    val = work.Num1 / work.Num2;

-                    break;

-

-                default:

-                    {

-                        InvalidOperation io = new InvalidOperation();

-                        io.What = (int)work.Op;

-                        io.Why = "Unknown operation";

-                        throw io;

-                    }

-            }

-

-            SharedStruct entry = new SharedStruct();

-            entry.Key = logid;

-            entry.Value = val.ToString();

-            log[logid] = entry;

-

-            return val;

-        }

-

-        public SharedStruct getStruct(int key)

-        {

-            Console.WriteLine("getStruct({0})", key);

-            return log[key];

-        }

-

-        public void zip()

-        {

-            Console.WriteLine("zip()");

-        }

-    }

-

-    public class CSharpServer

-    {

-        public static void Main()

-        {

-            try

-            {

-                CalculatorHandler handler = new CalculatorHandler();

-                Calculator.Processor processor = new Calculator.Processor(handler);

-                TServerTransport serverTransport = new TServerSocket(9090);

-                TServer server = new TSimpleServer(processor, serverTransport);

-

-                // Use this for a multithreaded server

-                // server = new TThreadPoolServer(processor, serverTransport);

-

-                Console.WriteLine("Starting the server...");

-                server.Serve();

-            }

-            catch (Exception x)

-            {

-                Console.WriteLine(x.StackTrace);

-            }

-            Console.WriteLine("done.");

-        }

-    }

-}

+ */
+
+using System;
+using System.Collections.Generic;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace CSharpTutorial
+{
+    public class CalculatorHandler : Calculator.Iface
+    {
+        Dictionary<int, SharedStruct> log;
+
+        public CalculatorHandler()
+        {
+            log = new Dictionary<int, SharedStruct>();
+        }
+
+        public void ping()
+        {
+            Console.WriteLine("ping()");
+        }
+
+        public int add(int n1, int n2)
+        {
+            Console.WriteLine("add({0},{1})", n1, n2);
+            return n1 + n2;
+        }
+
+        public int calculate(int logid, Work work)
+        {
+            Console.WriteLine("calculate({0}, [{1},{2},{3}])", logid, work.Op, work.Num1, work.Num2);
+            int val = 0;
+            switch (work.Op)
+            {
+                case Operation.ADD:
+                    val = work.Num1 + work.Num2;
+                    break;
+
+                case Operation.SUBTRACT:
+                    val = work.Num1 - work.Num2;
+                    break;
+
+                case Operation.MULTIPLY:
+                    val = work.Num1 * work.Num2;
+                    break;
+
+                case Operation.DIVIDE:
+                    if (work.Num2 == 0)
+                    {
+                        InvalidOperation io = new InvalidOperation();
+                        io.WhatOp = (int)work.Op;
+                        io.Why = "Cannot divide by 0";
+                        throw io;
+                    }
+                    val = work.Num1 / work.Num2;
+                    break;
+
+                default:
+                    {
+                        InvalidOperation io = new InvalidOperation();
+                        io.WhatOp = (int)work.Op;
+                        io.Why = "Unknown operation";
+                        throw io;
+                    }
+            }
+
+            SharedStruct entry = new SharedStruct();
+            entry.Key = logid;
+            entry.Value = val.ToString();
+            log[logid] = entry;
+
+            return val;
+        }
+
+        public SharedStruct getStruct(int key)
+        {
+            Console.WriteLine("getStruct({0})", key);
+            return log[key];
+        }
+
+        public void zip()
+        {
+            Console.WriteLine("zip()");
+        }
+    }
+
+    public class CSharpServer
+    {
+        public static void Main()
+        {
+            try
+            {
+                CalculatorHandler handler = new CalculatorHandler();
+                Calculator.Processor processor = new Calculator.Processor(handler);
+                TServerTransport serverTransport = new TServerSocket(9090);
+                TServer server = new TSimpleServer(processor, serverTransport);
+
+                // Use this for a multithreaded server
+                // server = new TThreadPoolServer(processor, serverTransport);
+
+                Console.WriteLine("Starting the server...");
+                server.Serve();
+            }
+            catch (Exception x)
+            {
+                Console.WriteLine(x.StackTrace);
+            }
+            Console.WriteLine("done.");
+        }
+    }
+}
diff --git a/tutorial/csharp/CsharpServer/CsharpServer.csproj b/tutorial/csharp/CsharpServer/CsharpServer.csproj
index aa2ac15..0748180 100644
--- a/tutorial/csharp/CsharpServer/CsharpServer.csproj
+++ b/tutorial/csharp/CsharpServer/CsharpServer.csproj
@@ -1,88 +1,111 @@
-<?xml version="1.0" encoding="utf-8"?>

-<!--

-  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.

--->

-<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

-  <PropertyGroup>

-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

-    <ProductVersion>9.0.30729</ProductVersion>

-    <SchemaVersion>2.0</SchemaVersion>

-    <ProjectGuid>{66707BAE-BBF9-4F03-B53E-BE3AD58322F8}</ProjectGuid>

-    <OutputType>Exe</OutputType>

-    <AppDesignerFolder>Properties</AppDesignerFolder>

-    <RootNamespace>CsharpServer</RootNamespace>

-    <AssemblyName>CsharpServer</AssemblyName>

-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>

-    <FileAlignment>512</FileAlignment>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

-    <DebugSymbols>true</DebugSymbols>

-    <DebugType>full</DebugType>

-    <Optimize>false</Optimize>

-    <OutputPath>bin\Debug\</OutputPath>

-    <DefineConstants>DEBUG;TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

-    <DebugType>pdbonly</DebugType>

-    <Optimize>true</Optimize>

-    <OutputPath>bin\Release\</OutputPath>

-    <DefineConstants>TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-  </PropertyGroup>

-  <ItemGroup>

-    <Reference Include="System" />

-    <Reference Include="System.Core">

-      <RequiredTargetFramework>3.5</RequiredTargetFramework>

-    </Reference>

-    <Reference Include="System.Xml.Linq">

-      <RequiredTargetFramework>3.5</RequiredTargetFramework>

-    </Reference>

-    <Reference Include="System.Data.DataSetExtensions">

-      <RequiredTargetFramework>3.5</RequiredTargetFramework>

-    </Reference>

-    <Reference Include="System.Data" />

-    <Reference Include="System.Xml" />

-    <Reference Include="Thrift, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">

-      <SpecificVersion>False</SpecificVersion>

-      <HintPath>..\..\..\lib\csharp\src\bin\Release\Thrift.dll</HintPath>

-    </Reference>

-  </ItemGroup>

-  <ItemGroup>

-    <Compile Include="CsharpServer.cs" />

-    <Compile Include="Properties\AssemblyInfo.cs" />

-    <Compile Include="..\..\gen-csharp\Calculator.cs" />

-    <Compile Include="..\..\gen-csharp\Constants.cs" />

-    <Compile Include="..\..\gen-csharp\InvalidOperation.cs" />

-    <Compile Include="..\..\gen-csharp\Operation.cs" />

-    <Compile Include="..\..\gen-csharp\SharedService.cs" />

-    <Compile Include="..\..\gen-csharp\SharedStruct.cs" />

-    <Compile Include="..\..\gen-csharp\Work.cs" />

-  </ItemGroup>

-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

-       Other similar extension points exist, see Microsoft.Common.targets.

-  <Target Name="BeforeBuild">

-  </Target>

-  <Target Name="AfterBuild">

-  </Target>

-  -->

+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{66707BAE-BBF9-4F03-B53E-BE3AD58322F8}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>CsharpServer</RootNamespace>
+    <AssemblyName>CsharpServer</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\gen-csharp\Calculator.cs">
+      <Link>Calculator.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\InvalidOperation.cs">
+      <Link>InvalidOperation.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\Operation.cs">
+      <Link>Operation.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\SharedService.cs">
+      <Link>SharedService.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\SharedStruct.cs">
+      <Link>SharedStruct.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\tutorial.Constants.cs">
+      <Link>tutorial.Constants.cs</Link>
+    </Compile>
+    <Compile Include="..\gen-csharp\Work.cs">
+      <Link>Work.cs</Link>
+    </Compile>
+    <Compile Include="CsharpServer.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\lib\csharp\src\Thrift.csproj">
+      <Project>{499eb63c-d74c-47e8-ae48-a2fc94538e9d}</Project>
+      <Name>Thrift</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent>pushd "$(SolutionDir)"
+thrift  -gen csharp   -r  ../tutorial.thrift
+popd
+
+</PreBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
 </Project>
\ No newline at end of file
diff --git a/tutorial/csharp/CsharpServer/Properties/AssemblyInfo.cs b/tutorial/csharp/CsharpServer/Properties/AssemblyInfo.cs
index 9981163..74fa476 100644
--- a/tutorial/csharp/CsharpServer/Properties/AssemblyInfo.cs
+++ b/tutorial/csharp/CsharpServer/Properties/AssemblyInfo.cs
@@ -1,55 +1,55 @@
-/*

- * 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.

- */

-

-using System.Reflection;

-using System.Runtime.CompilerServices;

-using System.Runtime.InteropServices;

-

-// General Information about an assembly is controlled through the following

-// set of attributes. Change these attribute values to modify the information

-// associated with an assembly.

-[assembly: AssemblyTitle("CsharpServer")]

-[assembly: AssemblyDescription("")]

-[assembly: AssemblyConfiguration("")]

-[assembly: AssemblyCompany("")]

-[assembly: AssemblyProduct("CsharpServer")]

-[assembly: AssemblyCopyright("Copyright © 2010 The Apache Software Foundation")]

-[assembly: AssemblyTrademark("")]

-[assembly: AssemblyCulture("")]

-

-// Setting ComVisible to false makes the types in this assembly not visible

-// to COM components.  If you need to access a type in this assembly from

-// COM, set the ComVisible attribute to true on that type.

-[assembly: ComVisible(false)]

-

-// The following GUID is for the ID of the typelib if this project is exposed to COM

-[assembly: Guid("e3b428f4-b2e9-4fc1-8a34-84abc4339860")]

-

-// Version information for an assembly consists of the following four values:

-//

-//      Major Version

-//      Minor Version

-//      Build Number

-//      Revision

-//

-// You can specify all the values or you can default the Build and Revision Numbers

-// by using the '*' as shown below:

-// [assembly: AssemblyVersion("1.0.*")]

-[assembly: AssemblyVersion("1.0.0.0")]

-[assembly: AssemblyFileVersion("1.0.0.0")]

+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CsharpServer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("e3b428f4-b2e9-4fc1-8a34-84abc4339860")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/tutorial/csharp/tutorial.sln b/tutorial/csharp/tutorial.sln
index 5c03e7c..ec57a18 100644
--- a/tutorial/csharp/tutorial.sln
+++ b/tutorial/csharp/tutorial.sln
@@ -1,39 +1,39 @@
-

-Microsoft Visual Studio Solution File, Format Version 11.00

-# Visual Studio 2010

-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\lib\csharp\src\Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}"

-EndProject

-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsharpClient", "CsharpClient\CsharpClient.csproj", "{18F24087-4760-43DA-ACAB-7B9F0E096B11}"

-	ProjectSection(ProjectDependencies) = postProject

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D} = {499EB63C-D74C-47E8-AE48-A2FC94538E9D}

-		{66707BAE-BBF9-4F03-B53E-BE3AD58322F8} = {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}

-	EndProjectSection

-EndProject

-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsharpServer", "CsharpServer\CsharpServer.csproj", "{66707BAE-BBF9-4F03-B53E-BE3AD58322F8}"

-	ProjectSection(ProjectDependencies) = postProject

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D} = {499EB63C-D74C-47E8-AE48-A2FC94538E9D}

-	EndProjectSection

-EndProject

-Global

-	GlobalSection(SolutionConfigurationPlatforms) = preSolution

-		Debug|Any CPU = Debug|Any CPU

-		Release|Any CPU = Release|Any CPU

-	EndGlobalSection

-	GlobalSection(ProjectConfigurationPlatforms) = postSolution

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU

-		{499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU

-		{18F24087-4760-43DA-ACAB-7B9F0E096B11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

-		{18F24087-4760-43DA-ACAB-7B9F0E096B11}.Debug|Any CPU.Build.0 = Debug|Any CPU

-		{18F24087-4760-43DA-ACAB-7B9F0E096B11}.Release|Any CPU.ActiveCfg = Release|Any CPU

-		{18F24087-4760-43DA-ACAB-7B9F0E096B11}.Release|Any CPU.Build.0 = Release|Any CPU

-		{66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

-		{66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Debug|Any CPU.Build.0 = Debug|Any CPU

-		{66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Release|Any CPU.ActiveCfg = Release|Any CPU

-		{66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Release|Any CPU.Build.0 = Release|Any CPU

-	EndGlobalSection

-	GlobalSection(SolutionProperties) = preSolution

-		HideSolutionNode = FALSE

-	EndGlobalSection

-EndGlobal

+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\lib\csharp\src\Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsharpClient", "CsharpClient\CsharpClient.csproj", "{18F24087-4760-43DA-ACAB-7B9F0E096B11}"
+    ProjectSection(ProjectDependencies) = postProject
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D} = {499EB63C-D74C-47E8-AE48-A2FC94538E9D}
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8} = {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}
+    EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CsharpServer", "CsharpServer\CsharpServer.csproj", "{66707BAE-BBF9-4F03-B53E-BE3AD58322F8}"
+    ProjectSection(ProjectDependencies) = postProject
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D} = {499EB63C-D74C-47E8-AE48-A2FC94538E9D}
+    EndProjectSection
+EndProject
+Global
+    GlobalSection(SolutionConfigurationPlatforms) = preSolution
+        Debug|Any CPU = Debug|Any CPU
+        Release|Any CPU = Release|Any CPU
+    EndGlobalSection
+    GlobalSection(ProjectConfigurationPlatforms) = postSolution
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+        {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU
+        {18F24087-4760-43DA-ACAB-7B9F0E096B11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+        {18F24087-4760-43DA-ACAB-7B9F0E096B11}.Debug|Any CPU.Build.0 = Debug|Any CPU
+        {18F24087-4760-43DA-ACAB-7B9F0E096B11}.Release|Any CPU.ActiveCfg = Release|Any CPU
+        {18F24087-4760-43DA-ACAB-7B9F0E096B11}.Release|Any CPU.Build.0 = Release|Any CPU
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+        {66707BAE-BBF9-4F03-B53E-BE3AD58322F8}.Release|Any CPU.Build.0 = Release|Any CPU
+    EndGlobalSection
+    GlobalSection(SolutionProperties) = preSolution
+        HideSolutionNode = FALSE
+    EndGlobalSection
+EndGlobal
diff --git a/tutorial/d/Makefile b/tutorial/d/Makefile
deleted file mode 100644
index fcee9af..0000000
--- a/tutorial/d/Makefile
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-LIB_D_DIR = ../../lib/d
-
-GEN_SRC = ../gen-d/share/SharedService.d ../gen-d/share/shared_types.d \
-	../gen-d/tutorial/tutorial_types.d ../gen-d/tutorial/Calculator.d
-
-default: server client async_client
-
-server: server.d
-	dmd -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd server.d ${GEN_SRC}
-
-client: client.d
-	dmd -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd client.d ${GEN_SRC}
-
-async_client: async_client.d
-	dmd -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd-event -L-lthriftd -L-levent async_client.d ${GEN_SRC}
-
-clean:
-	$(RM) -f server client async_client
diff --git a/tutorial/d/Makefile.am b/tutorial/d/Makefile.am
new file mode 100644
index 0000000..d8c8b29
--- /dev/null
+++ b/tutorial/d/Makefile.am
@@ -0,0 +1,46 @@
+#
+# 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.
+#
+
+LIB_D_DIR = $(top_srcdir)/lib/d
+
+GEN_SRC = gen-d/share/SharedService.d gen-d/share/shared_types.d \
+	gen-d/tutorial/tutorial_types.d gen-d/tutorial/Calculator.d
+
+$(GEN_SRC): $(top_srcdir)/tutorial/tutorial.thrift
+	$(top_builddir)/compiler/cpp/thrift --gen d -r $<
+
+server: server.d $(GEN_SRC)
+	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd server.d ${GEN_SRC}
+
+client: client.d $(GEN_SRC)
+	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd client.d ${GEN_SRC}
+
+PROGS = server client
+
+if WITH_D_EVENT_TESTS
+async_client: async_client.d $(GEN_SRC)
+	$(DMD) -I${LIB_D_DIR}/src -L-L${LIB_D_DIR} -L-lthriftd-event -L-lthriftd -L-levent async_client.d ${GEN_SRC}
+
+PROGS += async_client
+endif
+
+all-local: $(PROGS)
+
+clean:
+	$(RM) -f $(PROGS)
diff --git a/tutorial/d/server.d b/tutorial/d/server.d
index d32b937..cbcedcc 100644
--- a/tutorial/d/server.d
+++ b/tutorial/d/server.d
@@ -62,7 +62,7 @@
     case Operation.DIVIDE:
       if (work.num2 == 0) {
         auto io = new InvalidOperation();
-        io.what = work.op;
+        io.whatOp = work.op;
         io.why = "Cannot divide by 0";
         throw io;
       }
@@ -70,7 +70,7 @@
       break;
     default:
       auto io = new InvalidOperation();
-      io.what = work.op;
+      io.whatOp = work.op;
       io.why = "Invalid Operation";
       throw io;
     }
diff --git a/tutorial/dart/Makefile.am b/tutorial/dart/Makefile.am
new file mode 100644
index 0000000..0495aca
--- /dev/null
+++ b/tutorial/dart/Makefile.am
@@ -0,0 +1,73 @@
+#
+# 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.
+#
+
+BUILT_SOURCES = gen-dart/tutorial/lib/tutorial.dart gen-dart/shared/lib/shared.dart
+
+gen-dart/tutorial/lib/tutorial.dart gen-dart/shared/lib/shared.dart: $(top_srcdir)/tutorial/tutorial.thrift
+	$(THRIFT) --gen dart -r $<
+
+all-local: gen-dart/tutorial/lib/tutorial.dart pub-get
+
+clean-local:
+	$(RM) -r gen-*
+	find . -type d -name "packages" | xargs $(RM) -r
+	find . -type f -name ".packages" | xargs $(RM)
+	find . -type f -name "pubspec.lock" | xargs $(RM)
+
+pub-get: pub-get-gen pub-get-client pub-get-console-client pub-get-server
+
+pub-get-gen: pub-get-tutorial pub-get-shared
+
+pub-get-tutorial: gen-dart/tutorial/lib/tutorial.dart
+	cd gen-dart/tutorial; ${DARTPUB} get
+
+pub-get-shared: gen-dart/shared/lib/shared.dart
+	cd gen-dart/shared; ${DARTPUB} get
+
+pub-get-client:
+	cd client; ${DARTPUB} get
+
+pub-get-console-client:
+	cd console_client; ${DARTPUB} get
+
+pub-get-server:
+	cd server; ${DARTPUB} get
+
+tutorialserver: pub-get-gen pub-get-server
+	${DART} server/bin/main.dart
+
+tutorialclient: pub-get-gen pub-get-client
+	cd client; ${DARTPUB} serve
+
+tutorialconsoleclient: pub-get-console-client
+	${DART} console_client/bin/main.dart
+
+EXTRA_DIST = \
+	client/web/client.dart \
+	client/web/index.html \
+	client/web/styles.css \
+	client/pubspec.yaml \
+	console_client/bin/main.dart \
+	console_client/pubspec.yaml \
+	server/bin/main.dart \
+	server/pubspec.yaml \
+	console_client/.analysis_options \
+	client/.analysis_options \
+	server/.analysis_options \
+	build.sh
diff --git a/tutorial/dart/build.sh b/tutorial/dart/build.sh
new file mode 100644
index 0000000..eabe04a
--- /dev/null
+++ b/tutorial/dart/build.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+# 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.
+
+set -e;
+rm -r gen-dart || true;
+
+thrift --gen dart ../shared.thrift;
+cd gen-dart/shared;
+pub get;
+cd ../..;
+
+thrift --gen dart ../tutorial.thrift;
+cd gen-dart/tutorial;
+pub get;
+cd ../..;
+
+cd client;
+pub get;
+cd ..;
+
+cd console_client;
+pub get;
+cd ..;
+
+cd server;
+pub get;
+cd ..;
+
+dartfmt -w gen-dart;
+
+echo "\nEnjoy the Dart tutorial!";
+echo "\nTo run the server:";
+echo "> dart server/bin/main.dart";
+echo "\nTo run the client:";
+echo "# Serve the app from the client directory and view in a browser";
+echo "> cd client;";
+echo "> pub serve;";
+echo "\nTo run the console client:";
+echo "> dart console_client/bin/main.dart";
+echo "";
diff --git a/tutorial/dart/client/.analysis_options b/tutorial/dart/client/.analysis_options
new file mode 100644
index 0000000..a10d4c5
--- /dev/null
+++ b/tutorial/dart/client/.analysis_options
@@ -0,0 +1,2 @@
+analyzer:
+  strong-mode: true
diff --git a/tutorial/dart/client/pubspec.yaml b/tutorial/dart/client/pubspec.yaml
new file mode 100644
index 0000000..d8ede14
--- /dev/null
+++ b/tutorial/dart/client/pubspec.yaml
@@ -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.
+
+name: tutorial_client
+version: 1.0.0
+description: A Dart client implementation of the Apache Thrift tutorial
+author: Apache Thrift Developers <dev@thrift.apache.org>
+homepage: http://thrift.apache.org
+
+environment:
+  sdk: ">=1.13.0 <2.0.0"
+
+dependencies:
+  browser: ^0.10.0
+  shared:
+    path: ../gen-dart/shared
+  thrift:
+    path: ../../../lib/dart
+  tutorial:
+    path: ../gen-dart/tutorial
diff --git a/tutorial/dart/client/web/client.dart b/tutorial/dart/client/web/client.dart
new file mode 100644
index 0000000..4f02d0d
--- /dev/null
+++ b/tutorial/dart/client/web/client.dart
@@ -0,0 +1,278 @@
+/// 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 'dart:html';
+
+import 'package:thrift/thrift.dart';
+import 'package:thrift/thrift_browser.dart';
+import 'package:shared/shared.dart';
+import 'package:tutorial/tutorial.dart';
+
+/// Adapted from the AS3 tutorial
+void main() {
+  new CalculatorUI(querySelector('#output')).start();
+}
+
+class CalculatorUI {
+  final DivElement output;
+
+  CalculatorUI(this.output);
+
+  TTransport _transport;
+  Calculator _calculatorClient;
+
+  void start() {
+    _buildInterface();
+    _initConnection();
+  }
+
+  void _validate() {
+    if (!_transport.isOpen) {
+      window.alert("The transport is not open!");
+    }
+  }
+
+  void _initConnection() {
+    _transport = new TAsyncClientSocketTransport(
+        new TWebSocket(Uri.parse('ws://127.0.0.1:9090/ws')),
+        new TMessageReader(new TBinaryProtocolFactory()));
+    TProtocol protocol = new TBinaryProtocol(_transport);
+    _transport.open();
+
+    _calculatorClient = new CalculatorClient(protocol);
+  }
+
+  void _buildInterface() {
+    output.children.forEach((e) {
+      e.remove();
+    });
+
+    _buildPingComponent();
+
+    _buildAddComponent();
+
+    _buildCalculatorComponent();
+
+    _buildGetStructComponent();
+  }
+
+  void _buildPingComponent() {
+    output.append(new HeadingElement.h3()..text = "Ping");
+    ButtonElement pingButton = new ButtonElement()
+      ..text = "PING"
+      ..onClick.listen(_onPingClick);
+    output.append(pingButton);
+  }
+
+  void _onPingClick(MouseEvent e) {
+    _validate();
+
+    _calculatorClient.ping();
+  }
+
+  void _buildAddComponent() {
+    output.append(new HeadingElement.h3()..text = "Add");
+    InputElement num1 = new InputElement()
+      ..id = "add1"
+      ..type = "number"
+      ..style.fontSize = "14px"
+      ..style.width = "50px";
+    output.append(num1);
+    SpanElement op = new SpanElement()
+      ..text = "+"
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px";
+    output.append(op);
+    InputElement num2 = new InputElement()
+      ..id = "add2"
+      ..type = "number"
+      ..style.fontSize = "14px"
+      ..style.width = "50px"
+      ..style.marginLeft = "10px";
+    output.append(num2);
+    ButtonElement addButton = new ButtonElement()
+      ..text = "="
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px"
+      ..onClick.listen(_onAddClick);
+    output.append(addButton);
+    SpanElement result = new SpanElement()
+      ..id = "addResult"
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px";
+    output.append(result);
+  }
+
+  void _onAddClick(MouseEvent e) {
+    _validate();
+
+    InputElement num1 = querySelector("#add1");
+    InputElement num2 = querySelector("#add2");
+    SpanElement result = querySelector("#addResult");
+
+    _calculatorClient
+        .add(int.parse(num1.value), int.parse(num2.value))
+        .then((int n) {
+      result.text = "$n";
+    });
+  }
+
+  void _buildCalculatorComponent() {
+    output.append(new HeadingElement.h3()..text = "Calculator");
+    InputElement num1 = new InputElement()
+      ..id = "calc1"
+      ..type = "number"
+      ..style.fontSize = "14px"
+      ..style.width = "50px";
+    output.append(num1);
+    SelectElement op = new SelectElement()
+      ..id = "calcOp"
+      ..multiple = false
+      ..selectedIndex = 0
+      ..style.fontSize = "16px"
+      ..style.marginLeft = "10px"
+      ..style.width = "50px";
+    OptionElement addOp = new OptionElement()
+      ..text = "+"
+      ..value = Operation.ADD.toString();
+    op.add(addOp, 0);
+    OptionElement subtractOp = new OptionElement()
+      ..text = "-"
+      ..value = Operation.SUBTRACT.toString();
+    op.add(subtractOp, 1);
+    OptionElement multiplyOp = new OptionElement()
+      ..text = "*"
+      ..value = Operation.MULTIPLY.toString();
+    op.add(multiplyOp, 2);
+    OptionElement divideOp = new OptionElement()
+      ..text = "/"
+      ..value = Operation.DIVIDE.toString();
+    op.add(divideOp, 3);
+    output.append(op);
+    InputElement num2 = new InputElement()
+      ..id = "calc2"
+      ..type = "number"
+      ..style.fontSize = "14px"
+      ..style.width = "50px"
+      ..style.marginLeft = "10px";
+    output.append(num2);
+    ButtonElement calcButton = new ButtonElement()
+      ..text = "="
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px"
+      ..onClick.listen(_onCalcClick);
+    output.append(calcButton);
+    SpanElement result = new SpanElement()
+      ..id = "calcResult"
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px";
+    output.append(result);
+    output.append(new BRElement());
+    output.append(new BRElement());
+    LabelElement logIdLabel = new LabelElement()
+      ..text = "Log ID:"
+      ..style.fontSize = "14px";
+    output.append(logIdLabel);
+    InputElement logId = new InputElement()
+      ..id = "logId"
+      ..type = "number"
+      ..value = "1"
+      ..style.fontSize = "14px"
+      ..style.width = "50px"
+      ..style.marginLeft = "10px";
+    output.append(logId);
+    LabelElement commentLabel = new LabelElement()
+      ..text = "Comment:"
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px";
+    output.append(commentLabel);
+    InputElement comment = new InputElement()
+      ..id = "comment"
+      ..style.fontSize = "14px"
+      ..style.width = "100px"
+      ..style.marginLeft = "10px";
+    output.append(comment);
+  }
+
+  void _onCalcClick(MouseEvent e) {
+    _validate();
+
+    InputElement num1 = querySelector("#calc1");
+    InputElement num2 = querySelector("#calc2");
+    SelectElement op = querySelector("#calcOp");
+    SpanElement result = querySelector("#calcResult");
+    InputElement logId = querySelector("#logId");
+    InputElement comment = querySelector("#comment");
+
+    int logIdValue = int.parse(logId.value);
+    logId.value = (logIdValue + 1).toString();
+
+    Work work = new Work();
+    work.num1 = int.parse(num1.value);
+    work.num2 = int.parse(num2.value);
+    work.op = int.parse(op.options[op.selectedIndex].value);
+    work.comment = comment.value;
+
+    _calculatorClient.calculate(logIdValue, work).then((int n) {
+      result.text = "$n";
+    });
+  }
+
+  void _buildGetStructComponent() {
+    output.append(new HeadingElement.h3()..text = "Get Struct");
+    LabelElement logIdLabel = new LabelElement()
+      ..text = "Struct Key:"
+      ..style.fontSize = "14px";
+    output.append(logIdLabel);
+    InputElement logId = new InputElement()
+      ..id = "structKey"
+      ..type = "number"
+      ..value = "1"
+      ..style.fontSize = "14px"
+      ..style.width = "50px"
+      ..style.marginLeft = "10px";
+    output.append(logId);
+    ButtonElement getStructButton = new ButtonElement()
+      ..text = "GET"
+      ..style.fontSize = "14px"
+      ..style.marginLeft = "10px"
+      ..onClick.listen(_onGetStructClick);
+    output.append(getStructButton);
+    output.append(new BRElement());
+    output.append(new BRElement());
+    TextAreaElement result = new TextAreaElement()
+      ..id = "getStructResult"
+      ..style.fontSize = "14px"
+      ..style.width = "300px"
+      ..style.height = "50px"
+      ..style.marginLeft = "10px";
+    output.append(result);
+  }
+
+  void _onGetStructClick(MouseEvent e) {
+    _validate();
+
+    InputElement structKey = querySelector("#structKey");
+    TextAreaElement result = querySelector("#getStructResult");
+
+    _calculatorClient
+        .getStruct(int.parse(structKey.value))
+        .then((SharedStruct s) {
+      result.text = "${s.toString()}";
+    });
+  }
+}
diff --git a/tutorial/dart/client/web/index.html b/tutorial/dart/client/web/index.html
new file mode 100644
index 0000000..64b184e
--- /dev/null
+++ b/tutorial/dart/client/web/index.html
@@ -0,0 +1,36 @@
+<!--
+ * 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.
+-->
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Thrift Tutorial</title>
+    <link rel="stylesheet" href="styles.css">
+    <script async src="client.dart" type="application/dart"></script>
+    <script async src="packages/browser/dart.js"></script>
+</head>
+
+<body>
+
+  <div id="output"></div>
+
+</body>
+</html>
diff --git a/tutorial/dart/client/web/styles.css b/tutorial/dart/client/web/styles.css
new file mode 100644
index 0000000..c031502
--- /dev/null
+++ b/tutorial/dart/client/web/styles.css
@@ -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.
+ */
+@import url(https://fonts.googleapis.com/css?family=Roboto);
+
+html, body {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+    padding: 10px;
+    font-family: 'Roboto', sans-serif;
+}
+
+h3 {
+    border-bottom: solid;
+    border-width: thin;
+    padding-top: 20px;
+}
diff --git a/tutorial/dart/console_client/.analysis_options b/tutorial/dart/console_client/.analysis_options
new file mode 100644
index 0000000..a10d4c5
--- /dev/null
+++ b/tutorial/dart/console_client/.analysis_options
@@ -0,0 +1,2 @@
+analyzer:
+  strong-mode: true
diff --git a/tutorial/dart/console_client/bin/main.dart b/tutorial/dart/console_client/bin/main.dart
new file mode 100644
index 0000000..fda206a
--- /dev/null
+++ b/tutorial/dart/console_client/bin/main.dart
@@ -0,0 +1,149 @@
+/// 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 'dart:async';
+import 'dart:io';
+
+import 'package:args/args.dart';
+import 'package:logging/logging.dart';
+import 'package:thrift/thrift.dart';
+import 'package:thrift/thrift_console.dart';
+import 'package:tutorial/tutorial.dart';
+
+TTransport _transport;
+Calculator _calculator;
+int logid = 0;
+
+const Map<String, int> operationLookup = const {
+  '+': Operation.ADD,
+  '-': Operation.SUBTRACT,
+  '*': Operation.MULTIPLY,
+  '/': Operation.DIVIDE
+};
+
+main(List<String> args) {
+  Logger.root.level = Level.ALL;
+  Logger.root.onRecord.listen((LogRecord rec) {
+    print('${rec.level.name}: ${rec.time}: ${rec.message}');
+  });
+
+  var parser = new ArgParser();
+  parser.addOption('port', defaultsTo: '9090', help: 'The port to connect to');
+
+  ArgResults results;
+  try {
+    results = parser.parse(args);
+  } catch (e) {
+    results = null;
+  }
+
+  if (results == null) {
+    print(parser.usage);
+    exit(0);
+  }
+
+  int port = int.parse(results['port']);
+
+  _initConnection(port).then((_) => _run());
+}
+
+Future _initConnection(int port) async {
+  var socket = await Socket.connect('127.0.0.1', port);
+  _transport = new TAsyncClientSocketTransport(
+      new TTcpSocket(socket), new TMessageReader(new TBinaryProtocolFactory()));
+  TProtocol protocol = new TBinaryProtocol(_transport);
+  await _transport.open();
+
+  _calculator = new CalculatorClient(protocol);
+}
+
+Future _run() async {
+  _help();
+
+  while (true) {
+    stdout.write("> ");
+    var input = stdin.readLineSync();
+    var parts = input.split(' ');
+    var command = parts[0];
+    var args = parts.length > 1 ? parts.sublist(1) : [];
+
+    switch (command) {
+      case 'ping':
+        await _ping();
+        break;
+
+      case 'add':
+        await _add(int.parse(args[0]), int.parse(args[1]));
+        break;
+
+      case 'calc':
+        int op = operationLookup[args[1]];
+        if (!Operation.VALID_VALUES.contains(op)) {
+          stdout.writeln('Unknown operator ${args[1]}');
+          break;
+        }
+
+        var work = new Work()
+          ..num1 = int.parse(args[0])
+          ..op = op
+          ..num2 = int.parse(args[2])
+          ..comment = args.length > 3 ? args[3] : '';
+
+        await _calc(work);
+        break;
+
+      case 'struct':
+        await _struct(int.parse(args[0]));
+        break;
+
+      case 'help':
+      default:
+        _help();
+        break;
+    }
+  }
+}
+
+void _help() {
+  stdout.writeln('Commands:');
+  stdout.writeln('  help');
+  stdout.writeln('  ping');
+  stdout.writeln('  add x y');
+  stdout.writeln('  calc x op y [comment]');
+  stdout.writeln('  struct id');
+  stdout.writeln('');
+}
+
+Future _ping() async {
+  await _calculator.ping();
+  stdout.writeln('ping succeeded');
+}
+
+Future _add(int x, int y) async {
+  int result = await _calculator.add(x, y);
+  stdout.writeln('= $result');
+}
+
+Future _calc(Work work) async {
+  int result = await _calculator.calculate(logid++, work);
+  stdout.writeln('= $result');
+}
+
+Future _struct(int key) async {
+  var struct = await _calculator.getStruct(key);
+  stdout.writeln(struct.toString());
+}
diff --git a/tutorial/dart/console_client/pubspec.yaml b/tutorial/dart/console_client/pubspec.yaml
new file mode 100644
index 0000000..a34e26f
--- /dev/null
+++ b/tutorial/dart/console_client/pubspec.yaml
@@ -0,0 +1,36 @@
+# 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.
+
+name: tutorial_console_client
+version: 1.0.0
+description: >
+  A Dart console client to implementation of the Apache Thrift tutorial
+author: Apache Thrift Developers <dev@thrift.apache.org>
+homepage: http://thrift.apache.org
+
+environment:
+  sdk: ">=1.13.0 <2.0.0"
+
+dependencies:
+  args: ^0.13.0
+  collection: ^1.1.0
+  shared:
+    path: ../gen-dart/shared
+  thrift:
+    path: ../../../lib/dart
+  tutorial:
+    path: ../gen-dart/tutorial
diff --git a/tutorial/dart/server/.analysis_options b/tutorial/dart/server/.analysis_options
new file mode 100644
index 0000000..a10d4c5
--- /dev/null
+++ b/tutorial/dart/server/.analysis_options
@@ -0,0 +1,2 @@
+analyzer:
+  strong-mode: true
diff --git a/tutorial/dart/server/bin/main.dart b/tutorial/dart/server/bin/main.dart
new file mode 100644
index 0000000..b8ac30d
--- /dev/null
+++ b/tutorial/dart/server/bin/main.dart
@@ -0,0 +1,163 @@
+/// 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 'dart:async';
+import 'dart:io';
+
+import 'package:args/args.dart';
+import 'package:logging/logging.dart';
+import 'package:thrift/thrift.dart';
+import 'package:thrift/thrift_console.dart';
+import 'package:tutorial/tutorial.dart';
+import 'package:shared/shared.dart';
+
+TProtocol _protocol;
+TProcessor _processor;
+WebSocket _webSocket;
+
+main(List<String> args) {
+  Logger.root.level = Level.ALL;
+  Logger.root.onRecord.listen((LogRecord rec) {
+    print('${rec.level.name}: ${rec.time}: ${rec.message}');
+  });
+
+  var parser = new ArgParser();
+  parser.addOption('port', defaultsTo: '9090', help: 'The port to listen on');
+  parser.addOption('type',
+      defaultsTo: 'ws',
+      allowed: ['ws', 'tcp'],
+      help: 'The type of socket',
+      allowedHelp: {'ws': 'WebSocket', 'tcp': 'TCP Socket'});
+
+  ArgResults results;
+  try {
+    results = parser.parse(args);
+  } catch (e) {
+    results = null;
+  }
+
+  if (results == null) {
+    print(parser.usage);
+    exit(0);
+  }
+
+  int port = int.parse(results['port']);
+  String socketType = results['type'];
+
+  if (socketType == 'tcp') {
+    _runTcpServer(port);
+  } else if (socketType == 'ws') {
+    _runWebSocketServer(port);
+  }
+}
+
+Future _runWebSocketServer(int port) async {
+  var httpServer = await HttpServer.bind('127.0.0.1', port);
+  print('listening for WebSocket connections on $port');
+
+  httpServer.listen((HttpRequest request) async {
+    if (request.uri.path == '/ws') {
+      _webSocket = await WebSocketTransformer.upgrade(request);
+      await _initProcessor(new TWebSocket(_webSocket));
+    } else {
+      print('Invalid path: ${request.uri.path}');
+    }
+  });
+}
+
+Future _runTcpServer(int port) async {
+  var serverSocket = await ServerSocket.bind('127.0.0.1', port);
+  print('listening for TCP connections on $port');
+
+  Socket socket = await serverSocket.first;
+  await _initProcessor(new TTcpSocket(socket));
+}
+
+Future _initProcessor(TSocket socket) async {
+  TServerSocketTransport transport = new TServerSocketTransport(socket);
+  transport.onIncomingMessage.listen(_processMessage);
+  _processor = new CalculatorProcessor(new CalculatorServer());
+  _protocol = new TBinaryProtocol(transport);
+  await _protocol.transport.open();
+
+  print('connected');
+}
+
+Future _processMessage(_) async {
+  _processor.process(_protocol, _protocol);
+}
+
+class CalculatorServer implements Calculator {
+  final Map<int, SharedStruct> _log = {};
+
+  Future ping() async {
+    print('ping()');
+  }
+
+  Future<int> add(int num1, int num2) async {
+    print('add($num1, $num2)');
+
+    return num1 + num2;
+  }
+
+  Future<int> calculate(int logid, Work work) async {
+    print('calulate($logid, ${work.toString()})');
+
+    int val;
+
+    switch (work.op) {
+      case Operation.ADD:
+        val = work.num1 + work.num2;
+        break;
+
+      case Operation.SUBTRACT:
+        val = work.num1 - work.num2;
+        break;
+
+      case Operation.MULTIPLY:
+        val = work.num1 * work.num2;
+        break;
+
+      case Operation.DIVIDE:
+        if (work.num2 == 0) {
+          var x = new InvalidOperation();
+          x.whatOp = work.op;
+          x.why = 'Cannot divide by 0';
+          throw x;
+        }
+        val = (work.num1 / work.num2).floor();
+        break;
+    }
+
+    var log = new SharedStruct();
+    log.key = logid;
+    log.value = '$val "${work.comment}"';
+    this._log[logid] = log;
+
+    return val;
+  }
+
+  Future zip() async {
+    print('zip()');
+  }
+
+  Future<SharedStruct> getStruct(int key) async {
+    print('getStruct($key)');
+
+    return _log[key];
+  }
+}
diff --git a/tutorial/dart/server/pubspec.yaml b/tutorial/dart/server/pubspec.yaml
new file mode 100644
index 0000000..18d0737
--- /dev/null
+++ b/tutorial/dart/server/pubspec.yaml
@@ -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.
+
+name: tutorial_server
+version: 1.0.0
+description: A Dart server to support the Apache Thrift tutorial
+author: Apache Thrift Developers <dev@thrift.apache.org>
+homepage: http://thrift.apache.org
+
+environment:
+  sdk: ">=1.13.0 <2.0.0"
+
+dependencies:
+  args: ^0.13.0
+  shared:
+    path: ../gen-dart/shared
+  thrift:
+    path: ../../../lib/dart
+  tutorial:
+    path: ../gen-dart/tutorial
diff --git a/tutorial/delphi/DelphiClient/DelphiClient.dpr b/tutorial/delphi/DelphiClient/DelphiClient.dpr
index 0f380b0..74d0d45 100644
--- a/tutorial/delphi/DelphiClient/DelphiClient.dpr
+++ b/tutorial/delphi/DelphiClient/DelphiClient.dpr
@@ -26,7 +26,7 @@
   Generics.Collections,
   Thrift in '..\..\..\lib\delphi\src\Thrift.pas',
   Thrift.Collections in '..\..\..\lib\delphi\src\Thrift.Collections.pas',
-  Thrift.Console in '..\..\..\lib\delphi\src\Thrift.Console.pas',
+  Thrift.Exception in '..\..\..\lib\delphi\src\Thrift.Exception.pas',
   Thrift.Utils in '..\..\..\lib\delphi\src\Thrift.Utils.pas',
   Thrift.Stream in '..\..\..\lib\delphi\src\Thrift.Stream.pas',
   Thrift.Protocol in '..\..\..\lib\delphi\src\Thrift.Protocol.pas',
@@ -62,10 +62,10 @@
     transport.Open;
 
     client.ping;
-    Console.WriteLine('ping()');
+    WriteLn('ping()');
 
     sum := client.add( 1, 1);
-    Console.WriteLine( Format( '1+1=%d', [sum]));
+    WriteLn( Format( '1+1=%d', [sum]));
 
     work := TWorkImpl.Create;
 
@@ -74,11 +74,11 @@
     work.Num2 := 0;
     try
       quotient := client.calculate(1, work);
-      Console.WriteLine( 'Whoa we can divide by 0');
-      Console.WriteLine( Format('1/0=%d',[quotient]));
+      WriteLn( 'Whoa we can divide by 0');
+      WriteLn( Format('1/0=%d',[quotient]));
     except
       on io: TInvalidOperation
-      do Console.WriteLine( 'Invalid operation: ' + io.Why);
+      do WriteLn( 'Invalid operation: ' + io.Why);
     end;
 
     work.Op   := TOperation.SUBTRACT;
@@ -86,20 +86,20 @@
     work.Num2 := 10;
     try
       diff := client.calculate( 1, work);
-      Console.WriteLine( Format('15-10=%d', [diff]));
+      WriteLn( Format('15-10=%d', [diff]));
     except
       on io: TInvalidOperation
-      do Console.WriteLine( 'Invalid operation: ' + io.Why);
+      do WriteLn( 'Invalid operation: ' + io.Why);
     end;
 
     log := client.getStruct(1);
-    Console.WriteLine( Format( 'Check log: %s', [log.Value]));
+    WriteLn( Format( 'Check log: %s', [log.Value]));
 
     transport.Close();
 
   except
     on e : Exception
-    do Console.WriteLine( e.ClassName+': '+e.Message);
+    do WriteLn( e.ClassName+': '+e.Message);
   end;
 end;
 
diff --git a/tutorial/delphi/DelphiClient/DelphiClient.dproj b/tutorial/delphi/DelphiClient/DelphiClient.dproj
index ab0a1c1..d067992 100644
--- a/tutorial/delphi/DelphiClient/DelphiClient.dproj
+++ b/tutorial/delphi/DelphiClient/DelphiClient.dproj
@@ -52,7 +52,7 @@
 			</DelphiCompile>
 			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.pas"/>
 			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.Collections.pas"/>
-			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.Console.pas"/>
+			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.Exception.pas"/>
 			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.Utils.pas"/>
 			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.Stream.pas"/>
 			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.Protocol.pas"/>
@@ -82,8 +82,8 @@
 					<VersionInfo>
 						<VersionInfo Name="IncludeVerInfo">True</VersionInfo>
 						<VersionInfo Name="AutoIncBuild">False</VersionInfo>
-						<VersionInfo Name="MajorVer">1</VersionInfo>
-						<VersionInfo Name="MinorVer">0</VersionInfo>
+						<VersionInfo Name="MajorVer">0</VersionInfo>
+						<VersionInfo Name="MinorVer">12</VersionInfo>
 						<VersionInfo Name="Release">0</VersionInfo>
 						<VersionInfo Name="Build">0</VersionInfo>
 						<VersionInfo Name="Debug">False</VersionInfo>
diff --git a/tutorial/delphi/DelphiServer/DelphiServer.dpr b/tutorial/delphi/DelphiServer/DelphiServer.dpr
index 9d54a2e..5f42e7e 100644
--- a/tutorial/delphi/DelphiServer/DelphiServer.dpr
+++ b/tutorial/delphi/DelphiServer/DelphiServer.dpr
@@ -28,7 +28,7 @@
   Generics.Collections,
   Thrift in '..\..\..\lib\delphi\src\Thrift.pas',
   Thrift.Collections in '..\..\..\lib\delphi\src\Thrift.Collections.pas',
-  Thrift.Console in '..\..\..\lib\delphi\src\Thrift.Console.pas',
+  Thrift.Exception in '..\..\..\lib\delphi\src\Thrift.Exception.pas',
   Thrift.Utils in '..\..\..\lib\delphi\src\Thrift.Utils.pas',
   Thrift.Stream in '..\..\..\lib\delphi\src\Thrift.Stream.pas',
   Thrift.Protocol in '..\..\..\lib\delphi\src\Thrift.Protocol.pas',
@@ -86,13 +86,13 @@
 
 procedure TCalculatorHandler.ping;
 begin
-  Console.WriteLine( 'ping()');
+  WriteLn( 'ping()');
 end;
 
 
 function TCalculatorHandler.add(num1: Integer; num2: Integer): Integer;
 begin
-  Console.WriteLine( Format( 'add( %d, %d)', [num1, num2]));
+  WriteLn( Format( 'add( %d, %d)', [num1, num2]));
   result := num1 + num2;
 end;
 
@@ -101,7 +101,7 @@
 var entry : ISharedStruct;
 begin
   try
-    Console.WriteLine( Format('calculate( %d, [%d,%d,%d])', [logid, Ord(w.Op), w.Num1, w.Num2]));
+    WriteLn( Format('calculate( %d, [%d,%d,%d])', [logid, Ord(w.Op), w.Num1, w.Num2]));
 
     case w.Op of
       TOperation.ADD      :  result := w.Num1 + w.Num2;
@@ -126,14 +126,14 @@
 
 function TCalculatorHandler.getStruct(key: Integer): ISharedStruct;
 begin
-  Console.WriteLine( Format( 'getStruct(%d)', [key]));
+  WriteLn( Format( 'getStruct(%d)', [key]));
   result := FLog[key];
 end;
 
 
 procedure TCalculatorHandler.zip;
 begin
-  Console.WriteLine( 'zip()');
+  WriteLn( 'zip()');
 end;
 
 
@@ -152,14 +152,14 @@
     transport := TServerSocketImpl.Create( 9090);
     server    := TSimpleServer.Create( processor, transport);
 
-    Console.WriteLine( 'Starting the server...');
+    WriteLn( 'Starting the server...');
     server.Serve();
 
   except
-    on e: Exception do Console.WriteLine( e.Message);
+    on e: Exception do WriteLn( e.Message);
   end;
 
-  Console.WriteLine('done.');
+  WriteLn('done.');
 end;
 
 
diff --git a/tutorial/delphi/DelphiServer/DelphiServer.dproj b/tutorial/delphi/DelphiServer/DelphiServer.dproj
index c5071a3..e34a6a1 100644
--- a/tutorial/delphi/DelphiServer/DelphiServer.dproj
+++ b/tutorial/delphi/DelphiServer/DelphiServer.dproj
@@ -51,7 +51,7 @@
 			</DelphiCompile>
 			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.pas"/>
 			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.Collections.pas"/>
-			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.Console.pas"/>
+			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.Exception.pas"/>
 			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.Utils.pas"/>
 			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.Stream.pas"/>
 			<DCCReference Include="..\..\..\lib\delphi\src\Thrift.Protocol.pas"/>
@@ -81,8 +81,8 @@
 					<VersionInfo>
 						<VersionInfo Name="IncludeVerInfo">True</VersionInfo>
 						<VersionInfo Name="AutoIncBuild">False</VersionInfo>
-						<VersionInfo Name="MajorVer">1</VersionInfo>
-						<VersionInfo Name="MinorVer">0</VersionInfo>
+						<VersionInfo Name="MajorVer">0</VersionInfo>
+						<VersionInfo Name="MinorVer">12</VersionInfo>
 						<VersionInfo Name="Release">0</VersionInfo>
 						<VersionInfo Name="Build">0</VersionInfo>
 						<VersionInfo Name="Debug">False</VersionInfo>
diff --git a/tutorial/delphi/Tutorial.groupproj b/tutorial/delphi/Tutorial.groupproj
index 486e612..3a2a237 100644
--- a/tutorial/delphi/Tutorial.groupproj
+++ b/tutorial/delphi/Tutorial.groupproj
@@ -1,48 +1,48 @@
-	<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-		<PropertyGroup>
-			<ProjectGuid>{3D042C7F-3EF2-4574-8304-AB7FB79F814C}</ProjectGuid>
-		</PropertyGroup>
-		<ItemGroup>
-			<Projects Include="DelphiServer\DelphiServer.dproj">
-				<Dependencies/>
-			</Projects>
-			<Projects Include="DelphiClient\DelphiClient.dproj">
-				<Dependencies/>
-			</Projects>
-		</ItemGroup>
-		<ProjectExtensions>
-			<Borland.Personality>Default.Personality.12</Borland.Personality>
-			<Borland.ProjectType/>
-			<BorlandProject>
-				<Default.Personality/>
-			</BorlandProject>
-		</ProjectExtensions>
-		<Target Name="DelphiServer">
-			<MSBuild Projects="DelphiServer\DelphiServer.dproj"/>
-		</Target>
-		<Target Name="DelphiServer:Clean">
-			<MSBuild Projects="DelphiServer\DelphiServer.dproj" Targets="Clean"/>
-		</Target>
-		<Target Name="DelphiServer:Make">
-			<MSBuild Projects="DelphiServer\DelphiServer.dproj" Targets="Make"/>
-		</Target>
-		<Target Name="DelphiClient">
-			<MSBuild Projects="DelphiClient\DelphiClient.dproj"/>
-		</Target>
-		<Target Name="DelphiClient:Clean">
-			<MSBuild Projects="DelphiClient\DelphiClient.dproj" Targets="Clean"/>
-		</Target>
-		<Target Name="DelphiClient:Make">
-			<MSBuild Projects="DelphiClient\DelphiClient.dproj" Targets="Make"/>
-		</Target>
-		<Target Name="Build">
-			<CallTarget Targets="DelphiServer;DelphiClient"/>
-		</Target>
-		<Target Name="Clean">
-			<CallTarget Targets="DelphiServer:Clean;DelphiClient:Clean"/>
-		</Target>
-		<Target Name="Make">
-			<CallTarget Targets="DelphiServer:Make;DelphiClient:Make"/>
-		</Target>
-		<Import Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')" Project="$(BDS)\Bin\CodeGear.Group.Targets"/>
-	</Project>
+    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+        <PropertyGroup>
+            <ProjectGuid>{3D042C7F-3EF2-4574-8304-AB7FB79F814C}</ProjectGuid>
+        </PropertyGroup>
+        <ItemGroup>
+            <Projects Include="DelphiServer\DelphiServer.dproj">
+                <Dependencies/>
+            </Projects>
+            <Projects Include="DelphiClient\DelphiClient.dproj">
+                <Dependencies/>
+            </Projects>
+        </ItemGroup>
+        <ProjectExtensions>
+            <Borland.Personality>Default.Personality.12</Borland.Personality>
+            <Borland.ProjectType/>
+            <BorlandProject>
+                <Default.Personality/>
+            </BorlandProject>
+        </ProjectExtensions>
+        <Target Name="DelphiServer">
+            <MSBuild Projects="DelphiServer\DelphiServer.dproj"/>
+        </Target>
+        <Target Name="DelphiServer:Clean">
+            <MSBuild Projects="DelphiServer\DelphiServer.dproj" Targets="Clean"/>
+        </Target>
+        <Target Name="DelphiServer:Make">
+            <MSBuild Projects="DelphiServer\DelphiServer.dproj" Targets="Make"/>
+        </Target>
+        <Target Name="DelphiClient">
+            <MSBuild Projects="DelphiClient\DelphiClient.dproj"/>
+        </Target>
+        <Target Name="DelphiClient:Clean">
+            <MSBuild Projects="DelphiClient\DelphiClient.dproj" Targets="Clean"/>
+        </Target>
+        <Target Name="DelphiClient:Make">
+            <MSBuild Projects="DelphiClient\DelphiClient.dproj" Targets="Make"/>
+        </Target>
+        <Target Name="Build">
+            <CallTarget Targets="DelphiServer;DelphiClient"/>
+        </Target>
+        <Target Name="Clean">
+            <CallTarget Targets="DelphiServer:Clean;DelphiClient:Clean"/>
+        </Target>
+        <Target Name="Make">
+            <CallTarget Targets="DelphiServer:Make;DelphiClient:Make"/>
+        </Target>
+        <Import Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')" Project="$(BDS)\Bin\CodeGear.Group.Targets"/>
+    </Project>
diff --git a/tutorial/erl/README b/tutorial/erl/README.md
similarity index 100%
rename from tutorial/erl/README
rename to tutorial/erl/README.md
diff --git a/tutorial/erl/client.erl b/tutorial/erl/client.erl
index 5d40916..0374220 100644
--- a/tutorial/erl/client.erl
+++ b/tutorial/erl/client.erl
@@ -28,7 +28,7 @@
     ok.
 
 t() ->
-    Port = 9999,
+    Port = 9090,
 
     {ok, Client0} = thrift_client_util:new("127.0.0.1",
                                            Port,
@@ -44,7 +44,7 @@
     {Client3, {ok, Sum1}} = thrift_client:call(Client2, add, [1, 4]),
     io:format("1+4=~p~n", [Sum1]),
 
-    Work = #work{op=?tutorial_Operation_SUBTRACT,
+    Work = #'Work'{op=?TUTORIAL_OPERATION_SUBTRACT,
                  num1=15,
                  num2=10},
     {Client4, {ok, Diff}} = thrift_client:call(Client3, calculate, [1, Work]),
@@ -55,7 +55,7 @@
 
     Client6 =
         try
-            Work1 = #work{op=?tutorial_Operation_DIVIDE,
+            Work1 = #'Work'{op=?TUTORIAL_OPERATION_DIVIDE,
                           num1=1,
                           num2=0},
             {ClientS1, {ok, _Quot}} = thrift_client:call(Client5, calculate, [2, Work1]),
diff --git a/tutorial/erl/client.sh b/tutorial/erl/client.sh
deleted file mode 120000
index a417e0d..0000000
--- a/tutorial/erl/client.sh
+++ /dev/null
@@ -1 +0,0 @@
-server.sh
\ No newline at end of file
diff --git a/tutorial/erl/client.sh b/tutorial/erl/client.sh
new file mode 100755
index 0000000..775afb6
--- /dev/null
+++ b/tutorial/erl/client.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+ERL_THRIFT=../../lib/erl
+
+if ! [ -d ${ERL_THRIFT}/ebin ]; then
+    echo "Please build the Thrift library by running \`make' in ${ERL_THRIFT}"
+    exit 1
+fi
+
+if ! [ -d gen-erl ]; then
+  ../../compiler/cpp/thrift -r --gen erl ../tutorial.thrift
+fi
+
+
+erlc -I ${ERL_THRIFT}/include -I ${ERL_THRIFT}/ebin \
+     -I gen-erl -o gen-erl gen-erl/*.erl &&
+  erlc -I ${ERL_THRIFT}/include -I gen-erl *.erl &&
+  erl +K true -pa ${ERL_THRIFT}/ebin -pa gen-erl
diff --git a/tutorial/erl/json_client.erl b/tutorial/erl/json_client.erl
index 524e9ae..0b39ced 100644
--- a/tutorial/erl/json_client.erl
+++ b/tutorial/erl/json_client.erl
@@ -27,8 +27,8 @@
 
 -export([t/0]).
 
-%% Client constructor for the common-case of socket transports
-%% with the binary protocol
+%% Client constructor for the http transports
+%% with the json protocol
 new_client(Host, Path, Service, _Options) ->
     {ProtoOpts, TransOpts} = {[],[]},
     TransportFactory = fun() -> thrift_http_transport:new(Host, Path, TransOpts) end,
@@ -55,7 +55,7 @@
     {Client3, {ok, Sum1}} = thrift_client:call(Client2, add, [1, 4]),
     io:format("1+4=~p~n", [Sum1]),
 
-    Work = #work{op=?tutorial_Operation_SUBTRACT,
+    Work = #'Work'{op=?TUTORIAL_OPERATION_SUBTRACT,
                  num1=15,
                  num2=10},
     {Client4, {ok, Diff}} = thrift_client:call(Client3, calculate, [1, Work]),
@@ -66,7 +66,7 @@
 
     Client6 =
         try
-            Work1 = #work{op=?tutorial_Operation_DIVIDE,
+            Work1 = #'Work'{op=?TUTORIAL_OPERATION_DIVIDE,
                           num1=1,
                           num2=0},
             {ClientS1, {ok, _Quot}} = thrift_client:call(Client5, calculate, [2, Work1]),
diff --git a/tutorial/erl/server.erl b/tutorial/erl/server.erl
index 4915606..647cc24 100644
--- a/tutorial/erl/server.erl
+++ b/tutorial/erl/server.erl
@@ -36,25 +36,25 @@
     N1+N2.
 
 calculate(Logid, Work) ->
-    { Op, Num1, Num2 } = { Work#work.op, Work#work.num1, Work#work.num2 },
+    { Op, Num1, Num2 } = { Work#'Work'.op, Work#'Work'.num1, Work#'Work'.num2 },
     debug("calculate(~p, {~p,~p,~p})", [Logid, Op, Num1, Num2]),
     case Op of
-        ?tutorial_Operation_ADD      -> Num1 + Num2;
-        ?tutorial_Operation_SUBTRACT -> Num1 - Num2;
-        ?tutorial_Operation_MULTIPLY -> Num1 * Num2;
+        ?TUTORIAL_OPERATION_ADD      -> Num1 + Num2;
+        ?TUTORIAL_OPERATION_SUBTRACT -> Num1 - Num2;
+        ?TUTORIAL_OPERATION_MULTIPLY -> Num1 * Num2;
 
-        ?tutorial_Operation_DIVIDE when Num2 == 0 ->
-          throw(#invalidOperation{what=Op, why="Cannot divide by 0"});
-        ?tutorial_Operation_DIVIDE ->
+        ?TUTORIAL_OPERATION_DIVIDE when Num2 == 0 ->
+          throw(#'InvalidOperation'{whatOp=Op, why="Cannot divide by 0"});
+        ?TUTORIAL_OPERATION_DIVIDE ->
           Num1 div Num2;
 
         _Else ->
-          throw(#invalidOperation{what=Op, why="Invalid operation"})
+          throw(#'InvalidOperation'{whatOp=Op, why="Invalid operation"})
     end.
 
 getStruct(Key) ->
     debug("getStruct(~p)", [Key]),
-    #sharedStruct{key=Key, value="RARG"}.
+    #'SharedStruct'{key=Key, value="RARG"}.
 
 zip() ->
     debug("zip", []),
@@ -63,7 +63,7 @@
 %%
 
 start() ->
-    start(9999).
+    start(9090).
 
 start(Port) ->
     Handler   = ?MODULE,
diff --git a/tutorial/go/Makefile.am b/tutorial/go/Makefile.am
index 53c3980..bd57d65 100644
--- a/tutorial/go/Makefile.am
+++ b/tutorial/go/Makefile.am
@@ -17,30 +17,28 @@
 # under the License.
 #
 
-THRIFT = $(top_builddir)/compiler/cpp/thrift
-
 gen-go/tutorial/calculator.go gen-go/shared/shared_service.go: $(top_srcdir)/tutorial/tutorial.thrift
-	$(THRIFT) --gen go -r $<
+	$(THRIFT) --gen go$(COMPILER_EXTRAFLAG) -r $<
 
 all-local: gen-go/tutorial/calculator.go
 
-
-check: src/git.apache.org/thrift.git/lib/go/thrift
-	$(THRIFT) -r --gen go $(top_srcdir)/tutorial/tutorial.thrift
+check: src/github.com/apache/thrift/lib/go/thrift thirdparty-dep
+	$(THRIFT) -r --gen go$(COMPILER_EXTRAFLAG) $(top_srcdir)/tutorial/tutorial.thrift
 	cp -r gen-go/* src/
-	GOPATH=`pwd` $(GO) build ./...
-	GOPATH=`pwd` $(GO) build -o go-tutorial src/*.go
+	GOPATH=`pwd` $(GO) build -o go-tutorial ./src
 	GOPATH=`pwd` $(GO) build -o calculator-remote src/tutorial/calculator-remote/calculator-remote.go
 
-src/git.apache.org/thrift.git/lib/go/thrift:
-	mkdir -p src/git.apache.org/thrift.git/lib/go
-	ln -sf $(realpath $(top_srcdir)/lib/go/thrift) src/git.apache.org/thrift.git/lib/go/thrift
+src/github.com/apache/thrift/lib/go/thrift:
+	mkdir -p src/github.com/apache/thrift/lib/go
+	ln -sf $(realpath $(top_srcdir)/lib/go/thrift) src/github.com/apache/thrift/lib/go/thrift
+
+thirdparty-dep:
 
 tutorialserver: all
 	GOPATH=`pwd` $(GO) run src/*.go -server=true
 
 tutorialclient: all
-	GOPATH=`pwd` $(GO) run src/*.go 
+	GOPATH=`pwd` $(GO) run src/*.go
 
 tutorialsecureserver: all
 	GOPATH=`pwd` $(GO) run src/*.go -server=true -secure=true
@@ -49,7 +47,7 @@
 	GOPATH=`pwd` $(GO) run src/*.go -secure=true
 
 clean-local:
-	$(RM) -r gen-*
+	$(RM) -r gen-* src/shared src/tutorial src/git.apache.org go-tutorial calculator-remote
 
 EXTRA_DIST = \
 	src/client.go \
diff --git a/tutorial/go/server.crt b/tutorial/go/server.crt
index b345bf0..8a5ef3c 100644
--- a/tutorial/go/server.crt
+++ b/tutorial/go/server.crt
@@ -1,20 +1,25 @@
 -----BEGIN CERTIFICATE-----
-MIIDRjCCAi4CCQC7ZHL2gkCrNDANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJV
-UzEPMA0GA1UECAwGVGhyaWZ0MQ8wDQYDVQQHDAZUaHJpZnQxDzANBgNVBAoMBkFw
-YWNoZTEPMA0GA1UECwwGVGhyaWZ0MRIwEAYDVQQDDAlUaHJpZnQtR28wHhcNMTMw
-ODAyMTM0MzM0WhcNMTQwODAyMTM0MzM0WjBlMQswCQYDVQQGEwJVUzEPMA0GA1UE
-CAwGVGhyaWZ0MQ8wDQYDVQQHDAZUaHJpZnQxDzANBgNVBAoMBkFwYWNoZTEPMA0G
-A1UECwwGVGhyaWZ0MRIwEAYDVQQDDAlUaHJpZnQtR28wggEiMA0GCSqGSIb3DQEB
-AQUAA4IBDwAwggEKAoIBAQDBIkwFBgvHNS4yR8VYqYgd6bZtE1bJSdUHAOmASYwF
-Q5dDGltiwwWJiyLQ6njgcugqJ+5Icn2i7zd3kWXuTi6uNHlDzAy253uRj0skhXIA
-CYcMpNB5KI/bZd94VYg8ZG5x/or9mhpQNaZBKMpQ6bb1MvAlHfJO08y6YH2mZjfW
-SlpjEem51R8OK/3AM6mWZfWHeuSX+nzbChgRDZH4m9leWutgKyUgQtU7b5tEndsP
-qzGNeedaWGcyLT2dtD5PmsFbJ/RQXE3NEWACelJh7B1JjwB42HvZtl7m83GuY7ew
-eKlJP2HQAmmUkNTLdSa0yTzLuNitIKoh7RW5q4bl4zyNAgMBAAEwDQYJKoZIhvcN
-AQEFBQADggEBAB7r7lXn2M3SdyuXH+U6wbiNKPq8SX3sgncpaOluC36Phfdu38XJ
-NLovB05BIlkkExkv/IvjUZxGByd9WvNZBgajqll/FaK3Vv8cTo53yjxbQexFVK/m
-J4G9q/dGIV+B+8soVedoMTZOSmKhowM//9Oshs70foJLBJoHA5UdTdBxMvYcZBXV
-S9vUaVNEFd2cN0tyvguY8JNIPU8yEOUspR/uBeRRk3pRTbgcACC8+zYGUSuBiEf3
-SEKO2BHYBCkoodHWBWeMiiksYd3I5xOE9yS+Wn4eZlJBMTIjgxSddR1HH2cDSwET
-FzuW8WjtE1A28JL/hR6YcxaEDTulaFhaKs8=
+MIIENzCCAx+gAwIBAgIJAOYfYfw7NCOcMA0GCSqGSIb3DQEBBQUAMIGxMQswCQYD
+VQQGEwJVUzERMA8GA1UECAwITWFyeWxhbmQxFDASBgNVBAcMC0ZvcmVzdCBIaWxs
+MScwJQYDVQQKDB5UaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNV
+BAsMDUFwYWNoZSBUaHJpZnQxEjAQBgNVBAMMCWxvY2FsaG9zdDEkMCIGCSqGSIb3
+DQEJARYVZGV2QHRocmlmdC5hcGFjaGUub3JnMB4XDTE0MDQwNzE4NTgwMFoXDTIy
+MDYyNDE4NTgwMFowgbExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEU
+MBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRoZSBBcGFjaGUgU29mdHdh
+cmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRocmlmdDESMBAGA1UEAwwJ
+bG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhyaWZ0LmFwYWNoZS5vcmcw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqE9TE9wEXp5LRtLQVDSGQ
+GV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCySN8I2Xw6
+L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/HjKNg6ZKg
+2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQBGmZmMIUw
+AinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xku62LipkX
+wCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDmtrhVQF4n
+AgMBAAGjUDBOMB0GA1UdDgQWBBQo8v0wzQPx3EEexJPGlxPK1PpgKjAfBgNVHSME
+GDAWgBQo8v0wzQPx3EEexJPGlxPK1PpgKjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
+DQEBBQUAA4IBAQBGFRiJslcX0aJkwZpzTwSUdgcfKbpvNEbCNtVohfQVTI4a/oN5
+U+yqDZJg3vOaOuiAZqyHcIlZ8qyesCgRN314Tl4/JQ++CW8mKj1meTgo5YFxcZYm
+T9vsI3C+Nzn84DINgI9mx6yktIt3QOKZRDpzyPkUzxsyJ8J427DaimDrjTR+fTwD
+1Dh09xeeMnSa5zeV1HEDyJTqCXutLetwQ/IyfmMBhIx+nvB5f67pz/m+Dv6V0r3I
+p4HCcdnDUDGJbfqtoqsAATQQWO+WWuswB6mOhDbvPTxhRpZq6AkgWqv4S+u3M2GO
+r5p9FrBgavAw5bKO54C0oQKpN/5fta5l6Ws0
 -----END CERTIFICATE-----
diff --git a/tutorial/go/server.key b/tutorial/go/server.key
index 27d52f4..263cfce 100644
--- a/tutorial/go/server.key
+++ b/tutorial/go/server.key
@@ -1,27 +1,28 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEogIBAAKCAQEAwSJMBQYLxzUuMkfFWKmIHem2bRNWyUnVBwDpgEmMBUOXQxpb
-YsMFiYsi0Op44HLoKifuSHJ9ou83d5Fl7k4urjR5Q8wMtud7kY9LJIVyAAmHDKTQ
-eSiP22XfeFWIPGRucf6K/ZoaUDWmQSjKUOm29TLwJR3yTtPMumB9pmY31kpaYxHp
-udUfDiv9wDOplmX1h3rkl/p82woYEQ2R+JvZXlrrYCslIELVO2+bRJ3bD6sxjXnn
-WlhnMi09nbQ+T5rBWyf0UFxNzRFgAnpSYewdSY8AeNh72bZe5vNxrmO3sHipST9h
-0AJplJDUy3UmtMk8y7jYrSCqIe0VuauG5eM8jQIDAQABAoIBAEU9zpNef4qD/nP4
-V0BaR3qx971TWaIA3mcMZKqhs5mPigN8x5a45JtTTsAnz/5oM+QpPLysj26C5Rfx
-AOJXFVVPasprtYM9qoedIAuP7DcnM0vNKxDFAg5ej6fMwnMkbpRf9eTGAvkOwvRJ
-c39ey0FNadtkySKJvLR1M5ccvpgMnybCMDYsjDH0tAqWJcWsCX+/htk4rpg4V7yG
-JDg23yx4An+WWmPuR1zSQNx5mZBSg4RXYykr1MEKsHo+TDQ6IK6Wq2rtLUM0/0M6
-CJ80EswX6uY0Uh6eJH1o1BLJeAfNGk/a9MUUqPaWj7ospa5XJ0adG3Qq5MmF21Ft
-VbhRhQECgYEA/+2CcKlRlxoBzCRg8DdFf5OHE45EiUFAEX8/J9RWdLQSI/EwA6K2
-Q9CGy6WWKEFMHBHsxyV8Hx6dS+M+2UpM4h28Atiu/HLs3UZXrRv7FLJuXP7j+iBv
-oNo5+8sxcxL1GgJ3zcmSSHhMcZmbBowsYmx+lMDSSxGgXo2jEY3mZmkCgYEAwTBA
-KkO22D9263MYA/Exjcto+t5O7Q26gs/j2UscyBUn7fbcKofTvrWBBjMYMZvFokO8
-HM0PNTIpr0F9FPoUB2oky7VLmuoGf9smyZtl5fwIl6R/4MmStyAEUWnkI3qt/EOr
-5ZwrdzFdru6Z4zLYaW6bms+8A1G7GWnTNen+yIUCgYB57Lb14VRjfhpZHQOprUtI
-ygnSATcZhKJ3M33tBbXih18VDHRpZv0aNZ/iKRLuPp15yfhZr7wAP1+EpdBtSH50
-QuItIPnMfxvlFvvyFqB5bcAyQaRup0FHCnARSu5V+jQWnhJhUaSFLfqNLDa02dbT
-VQjA6VPGO7GBGk0TsdyP8QKBgE0OzvlMyzkUj325CeJAqdByS2yNkhPSPwwAmlTJ
-NjDE54lux0EbrqVKRq3PYZ4gEUP5GqauUJuaZ7AlQhxE6ApRF1498WtYX8FOC/ms
-x4dl8ZNzJSLnpGLxHWfQAhT40T9nSsCqe1fu0/x75dwPIu1jFiQ5Kjh0uFmZsYq2
-zE71AoGAIgX3hfqFTcQ0vQJ2bSk4Q2IBMRjW9maZDK/O009cWoVA1pq7qUFXX/Rl
-ADA5FD/HOZZ1QYEfRaIEItPZP6cbnza4mPVql6YwSqE5IV1DIefUkPzQVTWxSyPi
-FlH3RwTKS7V/qQ+7tPL7lGAsI6W/mtPM0TneDRcrpr6C9fghSDs=
------END RSA PRIVATE KEY-----
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqE9TE9wEXp5LR
+tLQVDSGQGV78+7ZtP/I/ZaJ6Q6ZGlfxDFvZjFF73seNhAvlKlYm/jflIHYLnNOCy
+SN8I2Xw6L9MbC+jvwkEKfQo4eDoxZnOZjNF5J1/lZtBeOowMkhhzBMH1Rds351/H
+jKNg6ZKg2Cldd0j7HbDtEixOLgLbPRpBcaYrLrNMasf3Hal+x8/b8ue28x93HSQB
+GmZmMIUwAinEu/fNP4lLGl/0kZb76TnyRpYSPYojtS6CnkH+QLYnsRREXJYwD1Xk
+u62LipkXwCkRTnZ5nUsDMX6FPKgjQFQCWDXG/N096+PRUQAChhrXsJ+gF3NqWtDm
+trhVQF4nAgMBAAECggEAW/y52YYW6ypROGbZ94DQpFV0kLO7qT8q0Ksxw5sPNaIt
+fEPRIymDa8ikyHWJS5Oxmw84wo5jnJV26jaLmwe2Lupq7Xf1lqej8f5LJtuv7cQR
+xfzp1vM65KJFFJHp6WqjGqJ6HSSZOpVDsnQYcXQjQCdpyAmaSWd3p+FqYSZ1mQmD
+bFNI7jqpczWSZhTdotQ7p7Hn9TVCehflP3yGIB3bQ+wCcCB85dOBz201L+YgaIck
+Sz43A4NvWaQIRLRDw7s9GW4jY5T0Jv282WIeAlVpVxLIwu48r4R4yGTIx9Ydowvq
+57+Y5iPPjAXxu0V9t00oS3bYxDaKh2DUfc/5zowq8QKBgQDYNVPXmaG0aIH4vjQ9
+7fRdw/UDkYcQbn6CnglQOu77/S8ogQzpKCVJgJgkZNqOVtQMEPzekGEcLTbje1gU
+8Bky2k+PL9UwbFy0emnOVh4rqrNXHsRvJcehNT/PRb5hjF3MUMFV/0iD4b+naFaE
+jrSWiZ2ZXj2qfwAK52GFbtOuBQKBgQDJYQuGiY0r22E4waJmCSKczoBT3cwlVzWj
+V2ljgA9RHLNTVkvNNYQLGu2qngFrtwpeaSnsMDerVG4wKAQWyCnYzxVrlnC4uDrJ
+HXuFEltBWi9Ffbgfsnd3749AT0oBP1NT2tMleguyf5DFgjCR3VRJLdrVaaZ8row/
+LqKcFMqnOwKBgB+OIO99l7E584Y3VG6ZdSneOLtNmRXX2pT7tcZE465ZdHGH7Dd3
+SYHhx9K/+Xn+yDH+pLli/xlarAEldmSP6k2WuTfftlC78AfTOfAId5zN7CDR9791
+Fx67I9X/itq33tS8EIuZl57P6uXm/4GXRloWOa8xpvRkVsBApuYPl8t1AoGATQDS
+y2sllDObBXzlgGbV2WgNIgSZ311toTv3jJiXQsjauW8yJRHln+l4H9mzaWDgkiFc
+ang1kUoDqF5k0eFQPxtQcYdhKwEnWWfwp33RbzfxA32DPnubuzzbZhfrkHaKgnIW
+cyor9uFYlm2l7ODZLfJez2RKyTplXnOSsmQw6akCgYAz3dj9Hskyj+HVJ+ht1OcE
+c7ai/ESkSA7Vajp0tjJp0EKjW/zq8DvUSXOtcdnJgkKycFluLwbmnaN4txBds1C1
+Qr8Rt2sUCCBNZe1L6DHe3XBdbkJe9sgZVNTjtUSQrzy8UhvsCqG4YWeCu07Szcbc
+rdPUV9/uQkdx8VrShxlD8A==
+-----END PRIVATE KEY-----
diff --git a/tutorial/go/src/client.go b/tutorial/go/src/client.go
index 543d7fb..e3ebe00 100644
--- a/tutorial/go/src/client.go
+++ b/tutorial/go/src/client.go
@@ -20,29 +20,36 @@
  */
 
 import (
-	"fmt"
-	"git.apache.org/thrift.git/lib/go/thrift"
-	"tutorial"
+	"context"
 	"crypto/tls"
+	"fmt"
+	"tutorial"
+
+	"github.com/apache/thrift/lib/go/thrift"
 )
 
+var defaultCtx = context.Background()
+
 func handleClient(client *tutorial.CalculatorClient) (err error) {
-	client.Ping()
+	client.Ping(defaultCtx)
 	fmt.Println("ping()")
 
-	sum, _ := client.Add(1, 1)
+	sum, _ := client.Add(defaultCtx, 1, 1)
 	fmt.Print("1+1=", sum, "\n")
 
 	work := tutorial.NewWork()
 	work.Op = tutorial.Operation_DIVIDE
 	work.Num1 = 1
 	work.Num2 = 0
-	quotient, ouch, err := client.Calculate(1, work)
+	quotient, err := client.Calculate(defaultCtx, 1, work)
 	if err != nil {
-		fmt.Println("Error during operation:", err)
+		switch v := err.(type) {
+		case *tutorial.InvalidOperation:
+			fmt.Println("Invalid operation:", v)
+		default:
+			fmt.Println("Error during operation:", err)
+		}
 		return err
-	} else if ouch != nil {
-		fmt.Println("Invalid operation:", ouch)
 	} else {
 		fmt.Println("Whoa we can divide by 0 with new value:", quotient)
 	}
@@ -50,17 +57,20 @@
 	work.Op = tutorial.Operation_SUBTRACT
 	work.Num1 = 15
 	work.Num2 = 10
-	diff, ouch, err := client.Calculate(1, work)
+	diff, err := client.Calculate(defaultCtx, 1, work)
 	if err != nil {
-		fmt.Println("Error during operation:", err)
+		switch v := err.(type) {
+		case *tutorial.InvalidOperation:
+			fmt.Println("Invalid operation:", v)
+		default:
+			fmt.Println("Error during operation:", err)
+		}
 		return err
-	} else if ouch != nil {
-		fmt.Println("Invalid operation:", ouch)
 	} else {
 		fmt.Print("15-10=", diff, "\n")
 	}
 
-	log, err := client.GetStruct(1)
+	log, err := client.GetStruct(defaultCtx, 1)
 	if err != nil {
 		fmt.Println("Unable to get struct:", err)
 		return err
@@ -84,10 +94,15 @@
 		fmt.Println("Error opening socket:", err)
 		return err
 	}
-	transport = transportFactory.GetTransport(transport)
+	transport, err = transportFactory.GetTransport(transport)
+	if err != nil {
+		return err
+	}
 	defer transport.Close()
 	if err := transport.Open(); err != nil {
 		return err
 	}
-	return handleClient(tutorial.NewCalculatorClientFactory(transport, protocolFactory))
+	iprot := protocolFactory.GetProtocol(transport)
+	oprot := protocolFactory.GetProtocol(transport)
+	return handleClient(tutorial.NewCalculatorClient(thrift.NewTStandardClient(iprot, oprot)))
 }
diff --git a/tutorial/go/src/handler.go b/tutorial/go/src/handler.go
index 3d4c18c..5c0eed0 100644
--- a/tutorial/go/src/handler.go
+++ b/tutorial/go/src/handler.go
@@ -20,6 +20,7 @@
  */
 
 import (
+	"context"
 	"fmt"
 	"shared"
 	"strconv"
@@ -34,17 +35,17 @@
 	return &CalculatorHandler{log: make(map[int]*shared.SharedStruct)}
 }
 
-func (p *CalculatorHandler) Ping() (err error) {
+func (p *CalculatorHandler) Ping(ctx context.Context) (err error) {
 	fmt.Print("ping()\n")
 	return nil
 }
 
-func (p *CalculatorHandler) Add(num1 int32, num2 int32) (retval17 int32, err error) {
+func (p *CalculatorHandler) Add(ctx context.Context, num1 int32, num2 int32) (retval17 int32, err 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 error) {
+func (p *CalculatorHandler) Calculate(ctx context.Context, logid int32, w *tutorial.Work) (val int32, err error) {
 	fmt.Print("calculate(", logid, ", {", w.Op, ",", w.Num1, ",", w.Num2, "})\n")
 	switch w.Op {
 	case tutorial.Operation_ADD:
@@ -58,17 +59,19 @@
 		break
 	case tutorial.Operation_DIVIDE:
 		if w.Num2 == 0 {
-			ouch = tutorial.NewInvalidOperation()
-			ouch.What = int32(w.Op)
+			ouch := tutorial.NewInvalidOperation()
+			ouch.WhatOp = int32(w.Op)
 			ouch.Why = "Cannot divide by 0"
+			err = ouch
 			return
 		}
 		val = w.Num1 / w.Num2
 		break
 	default:
-		ouch = tutorial.NewInvalidOperation()
-		ouch.What = int32(w.Op)
+		ouch := tutorial.NewInvalidOperation()
+		ouch.WhatOp = int32(w.Op)
 		ouch.Why = "Unknown operation"
+		err = ouch
 		return
 	}
 	entry := shared.NewSharedStruct()
@@ -84,16 +87,16 @@
 	   }
 	*/
 	p.log[k] = entry
-	return val, ouch, err
+	return val, err
 }
 
-func (p *CalculatorHandler) GetStruct(key int32) (*shared.SharedStruct, error) {
+func (p *CalculatorHandler) GetStruct(ctx context.Context, key int32) (*shared.SharedStruct, error) {
 	fmt.Print("getStruct(", key, ")\n")
 	v, _ := p.log[int(key)]
 	return v, nil
 }
 
-func (p *CalculatorHandler) Zip() (err error) {
+func (p *CalculatorHandler) Zip(ctx context.Context) (err error) {
 	fmt.Print("zip()\n")
 	return nil
 }
diff --git a/tutorial/go/src/main.go b/tutorial/go/src/main.go
index 96e5ec9..7730d7b 100644
--- a/tutorial/go/src/main.go
+++ b/tutorial/go/src/main.go
@@ -22,7 +22,7 @@
 import (
 	"flag"
 	"fmt"
-	"git.apache.org/thrift.git/lib/go/thrift"
+	"github.com/apache/thrift/lib/go/thrift"
 	"os"
 )
 
@@ -35,7 +35,7 @@
 func main() {
 	flag.Usage = Usage
 	server := flag.Bool("server", false, "Run server")
-	protocol := flag.String("P", "binary", "Specify the protocol (binary, compact, simplejson)")
+	protocol := flag.String("P", "binary", "Specify the protocol (binary, compact, json, simplejson)")
 	framed := flag.Bool("framed", false, "Use framed transport")
 	buffered := flag.Bool("buffered", false, "Use buffered transport")
 	addr := flag.String("addr", "localhost:9090", "Address to listen to")
diff --git a/tutorial/go/src/server.go b/tutorial/go/src/server.go
index ebcfe5b..95708eb 100644
--- a/tutorial/go/src/server.go
+++ b/tutorial/go/src/server.go
@@ -20,10 +20,10 @@
  */
 
 import (
-	"fmt"
-	"git.apache.org/thrift.git/lib/go/thrift"
-	"tutorial"
 	"crypto/tls"
+	"fmt"
+	"github.com/apache/thrift/lib/go/thrift"
+	"tutorial"
 )
 
 func runServer(transportFactory thrift.TTransportFactory, protocolFactory thrift.TProtocolFactory, addr string, secure bool) error {
diff --git a/tutorial/haxe/Makefile.am b/tutorial/haxe/Makefile.am
new file mode 100644
index 0000000..e6f2713
--- /dev/null
+++ b/tutorial/haxe/Makefile.am
@@ -0,0 +1,97 @@
+#
+# 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.
+#
+
+BIN_CPP = bin/Main-debug
+BIN_PHP = bin/php/Main-debug.php
+BIN_PHP_WEB = bin/php-web-server/Main-debug.php
+
+gen-haxe/tutorial/calculator.hx gen-haxe/shared/shared_service.hx: $(top_srcdir)/tutorial/tutorial.thrift
+	$(THRIFT) --gen haxe -r $<
+
+all-local: $(BIN_CPP) $(BIN_PHP) $(BIN_PHP_WEB)
+
+check: gen-haxe/tutorial/calculator.hx
+
+$(BIN_CPP): \
+		src/*.hx \
+		../../lib/haxe/src/org/apache/thrift/**/*.hx \
+		gen-haxe/tutorial/calculator.hx
+	$(HAXE) --cwd .  cpp.hxml
+
+$(BIN_PHP): \
+		src/*.hx \
+		../../lib/haxe/src/org/apache/thrift/**/*.hx \
+		gen-haxe/tutorial/calculator.hx
+	$(HAXE) --cwd .  php.hxml
+
+$(BIN_PHP_WEB): \
+		src/*.hx \
+		../../lib/haxe/src/org/apache/thrift/**/*.hx \
+		gen-haxe/tutorial/calculator.hx
+	$(HAXE) --cwd .  php-web-server.hxml
+
+tutorialserver: all
+	$(BIN_CPP) server
+
+tutorialserver_php: all
+	php -f $(BIN_PHP) server
+
+tutorialclient: all
+	$(BIN_CPP)
+
+tutorialclient_php: all
+	php -f $(BIN_PHP) 
+
+tutorialsecureserver: all
+	$(BIN_CPP) server secure
+
+tutorialsecureserver_php: all
+	php -f $(BIN_PHP) server secure
+
+tutorialsecureclient: all
+	$(BIN_CPP) secure
+
+tutorialsecureclient_php: all
+	php -f $(BIN_PHP) secure
+
+tutorialserver_php_http: all
+	php -S 127.0.0.1:9090 router.php
+
+tutorialclient_http: all
+	$(BIN_CPP) client http
+
+clean-local:
+	$(RM) -r gen-haxe bin
+
+EXTRA_DIST = \
+	src \
+	cpp.hxml \
+	csharp.hxml \
+	flash.hxml \
+	java.hxml \
+	javascript.hxml \
+	php-web-server.hxml \
+	neko.hxml \
+	php.hxml \
+	python.hxml \
+	router.php \
+	project.hide \
+	Tutorial.hxproj \
+	make_all.bat \
+	make_all.sh
diff --git a/tutorial/haxe/Tutorial.hxproj b/tutorial/haxe/Tutorial.hxproj
new file mode 100644
index 0000000..796f648
--- /dev/null
+++ b/tutorial/haxe/Tutorial.hxproj
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project version="2">
+  <!-- Output SWF options -->
+  <output>
+    <movie outputType="Application" />
+    <movie input="" />
+    <movie path="bin/HaxeTutorial" />
+    <movie fps="30" />
+    <movie width="800" />
+    <movie height="600" />
+    <movie version="1" />
+    <movie minorVersion="0" />
+    <movie platform="C++" />
+    <movie background="#FFFFFF" />
+  </output>
+  <!-- Other classes to be compiled into your SWF -->
+  <classpaths>
+    <class path="src" />
+    <class path="gen-haxe" />
+    <class path="../../lib/haxe/src" />
+  </classpaths>
+  <!-- Build options -->
+  <build>
+    <option directives="" />
+    <option flashStrict="False" />
+    <option noInlineOnDebug="False" />
+    <option mainClass="Main" />
+    <option enabledebug="False" />
+    <option additional="" />
+  </build>
+  <!-- haxelib libraries -->
+  <haxelib>
+    <!-- example: <library name="..." /> -->
+  </haxelib>
+  <!-- Class files to compile (other referenced classes will automatically be included) -->
+  <compileTargets>
+    <!-- example: <compile path="..." /> -->
+  </compileTargets>
+  <!-- Paths to exclude from the Project Explorer tree -->
+  <hiddenPaths>
+    <hidden path="obj" />
+    <hidden path="cpp.hxml" />
+    <hidden path="csharp.hxml" />
+    <hidden path="flash.hxml" />
+    <hidden path="java.hxml" />
+    <hidden path="javascript.hxml" />
+    <hidden path="make_all.bat" />
+    <hidden path="make_all.sh" />
+    <hidden path="Makefile.am" />
+    <hidden path="neko.hxml" />
+    <hidden path="php.hxml" />
+    <hidden path="project.hide" />
+    <hidden path="python.hxml" />
+  </hiddenPaths>
+  <!-- Executed before build -->
+  <preBuildCommand>thrift -r -gen haxe  ../tutorial.thrift</preBuildCommand>
+  <!-- Executed after build -->
+  <postBuildCommand alwaysRun="False" />
+  <!-- Other project options -->
+  <options>
+    <option showHiddenPaths="False" />
+    <option testMovie="Unknown" />
+    <option testMovieCommand="" />
+  </options>
+  <!-- Plugin storage -->
+  <storage />
+</project>
\ No newline at end of file
diff --git a/tutorial/haxe/cpp.hxml b/tutorial/haxe/cpp.hxml
new file mode 100644
index 0000000..6adb52d
--- /dev/null
+++ b/tutorial/haxe/cpp.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#CPP target
+-cpp bin
+
+#To produce 64 bit binaries the file should define the HXCPP_M64 compile variable:
+#-D HXCPP_M64
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/csharp.hxml b/tutorial/haxe/csharp.hxml
new file mode 100644
index 0000000..295c017
--- /dev/null
+++ b/tutorial/haxe/csharp.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#CSHARP target
+-cs bin/Tutorial.exe
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/flash.hxml b/tutorial/haxe/flash.hxml
new file mode 100644
index 0000000..a1f0568
--- /dev/null
+++ b/tutorial/haxe/flash.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Flash target
+-swf bin/Tutorial.swf
+
+#Add debug information
+-debug
+
+# we need some goodies from sys.net
+# --macro allowPackage("sys")
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/java.hxml b/tutorial/haxe/java.hxml
new file mode 100644
index 0000000..c615565
--- /dev/null
+++ b/tutorial/haxe/java.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src 
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Java target
+-java bin/Tutorial.jar
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/javascript.hxml b/tutorial/haxe/javascript.hxml
new file mode 100644
index 0000000..b2b3876
--- /dev/null
+++ b/tutorial/haxe/javascript.hxml
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#JavaScript target
+-js bin/Tutorial.js
+
+#You can use -D source-map-content (requires Haxe 3.1+) to have the .hx 
+#files directly embedded into the map file, this way you only have to 
+#upload it, and it will be always in sync with the compiled .js even if 
+#you modify your .hx files.
+-D source-map-content
+
+#Generate source map and add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/make_all.bat b/tutorial/haxe/make_all.bat
new file mode 100644
index 0000000..656dd15
--- /dev/null
+++ b/tutorial/haxe/make_all.bat
@@ -0,0 +1,68 @@
+@echo off
+rem /*
+rem  * Licensed to the Apache Software Foundation (ASF) under one
+rem  * or more contributor license agreements. See the NOTICE file
+rem  * distributed with this work for additional information
+rem  * regarding copyright ownership. The ASF licenses this file
+rem  * to you under the Apache License, Version 2.0 (the
+rem  * "License"); you may not use this file except in compliance
+rem  * with the License. You may obtain a copy of the License at
+rem  *
+rem  *   http://www.apache.org/licenses/LICENSE-2.0
+rem  *
+rem  * Unless required by applicable law or agreed to in writing,
+rem  * software distributed under the License is distributed on an
+rem  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem  * KIND, either express or implied. See the License for the
+rem  * specific language governing permissions and limitations
+rem  * under the License.
+rem  */
+
+setlocal
+if "%HOMEDRIVE%"=="" goto MISSINGVARS
+if "%HOMEPATH%"=="" goto MISSINGVARS
+if "%HAXEPATH%"=="" goto NOTINSTALLED
+
+set path=%HAXEPATH%;%HAXEPATH%\..\neko;%path%
+
+rem # invoke Thrift comnpiler
+thrift -r -gen haxe   ..\tutorial.thrift
+if errorlevel 1 goto STOP
+
+rem # invoke Haxe compiler for all targets
+for %%a in (*.hxml) do (
+	rem * filter Python, as it is not supported by Haxe 3.1.3 (but will be in 3.1.4)
+	if not "%%a"=="python.hxml" (
+		echo --------------------------
+		echo Building %%a ...
+		echo --------------------------
+		haxe  --cwd .  %%a
+	)
+)
+
+
+echo.
+echo done.
+pause
+goto eof
+
+:NOTINSTALLED
+echo FATAL: Either Haxe is not installed, or the HAXEPATH variable is not set.
+pause
+goto eof
+
+:MISSINGVARS
+echo FATAL: Unable to locate home folder.
+echo.
+echo Both HOMEDRIVE and HOMEPATH need to be set to point to your Home folder.
+echo The current values are:
+echo HOMEDRIVE=%HOMEDRIVE%
+echo HOMEPATH=%HOMEPATH%
+pause
+goto eof
+
+:STOP
+pause
+goto eof
+
+:eof
diff --git a/tutorial/haxe/make_all.sh b/tutorial/haxe/make_all.sh
new file mode 100644
index 0000000..2ee650d
--- /dev/null
+++ b/tutorial/haxe/make_all.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# 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.
+#
+
+# invoke Thrift comnpiler
+thrift -r -gen haxe  ../tutorial.thrift
+
+# output folder
+if [ ! -d bin ]; then
+  mkdir  bin
+fi
+
+# invoke Haxe compoiler
+for target in *.hxml; do 
+  echo --------------------------
+  echo Building ${target} ...
+  echo --------------------------
+  if [ ! -d bin/${target} ]; then
+    mkdir  bin/${target}
+  fi
+  haxe  --cwd .  ${target} 
+done
+
+
+#eof
diff --git a/tutorial/haxe/neko.hxml b/tutorial/haxe/neko.hxml
new file mode 100644
index 0000000..6161f69
--- /dev/null
+++ b/tutorial/haxe/neko.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#neko target
+-neko bin/Tutorial.n
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/php-web-server.hxml b/tutorial/haxe/php-web-server.hxml
new file mode 100644
index 0000000..395a852
--- /dev/null
+++ b/tutorial/haxe/php-web-server.hxml
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#PHP target
+-php bin/php-web-server/
+--php-front Main-debug.php
+
+#defines
+-D phpwebserver
+
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
diff --git a/tutorial/haxe/php.hxml b/tutorial/haxe/php.hxml
new file mode 100644
index 0000000..c2f6887
--- /dev/null
+++ b/tutorial/haxe/php.hxml
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#PHP target
+-php bin/php/
+--php-front Main-debug.php
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
diff --git a/tutorial/haxe/project.hide b/tutorial/haxe/project.hide
new file mode 100644
index 0000000..8d5d4ec
--- /dev/null
+++ b/tutorial/haxe/project.hide
@@ -0,0 +1,105 @@
+{
+     "type" : 0
+    ,"target" : 4
+    ,"name" : "Apache Thrift Tutorial"
+    ,"main" : null
+    ,"projectPackage" : ""
+    ,"company" : "Apache Software Foundation (ASF)"
+    ,"license" : "Apache License, Version 2.0"
+    ,"url" : "http://www.apache.org/licenses/LICENSE-2.0"
+    ,"targetData" : [
+         {
+             "pathToHxml" : "flash.hxml"
+            ,"runActionType" : 1
+            ,"runActionText" : "bin/Tutorial.swf"
+        }
+        ,{
+             "pathToHxml" : "javascript.hxml"
+            ,"runActionType" : 1
+            ,"runActionText" : "bin\\index.html"
+        }
+        ,{
+             "pathToHxml" : "neko.hxml"
+            ,"runActionType" : 2
+            ,"runActionText" : "neko bin/Tutorial.n"
+        }
+        ,{
+             "pathToHxml" : "php.hxml"
+        }
+        ,{
+             "pathToHxml" : "cpp.hxml"
+            ,"runActionType" : 2
+            ,"runActionText" : "bin/Main-debug.exe"
+        }
+        ,{
+             "pathToHxml" : "java.hxml"
+        }
+        ,{
+             "pathToHxml" : "csharp.hxml"
+            ,"runActionType" : 2
+            ,"runActionText" : "bin\\Tutorial.exe\\bin\\Main-Debug.exe"
+        }
+        ,{
+             "pathToHxml" : "python.hxml"
+            ,"runActionType" : 2
+            ,"runActionText" : "python bin/Tutorial.py"
+        }
+    ]
+    ,"files" : [
+         {
+             "path" : "src\\org\\apache\\thrift\\server\\TServer.hx"
+            ,"useTabs" : true
+            ,"indentSize" : 4
+            ,"foldedRegions" : [
+
+            ]
+            ,"activeLine" : 76
+        }
+        ,{
+             "path" : "src\\org\\apache\\thrift\\server\\TSimpleServer.hx"
+            ,"useTabs" : true
+            ,"indentSize" : 4
+            ,"foldedRegions" : [
+
+            ]
+            ,"activeLine" : 100
+        }
+        ,{
+             "path" : "src\\shared\\SharedServiceProcessor.hx"
+            ,"useTabs" : true
+            ,"indentSize" : 4
+            ,"foldedRegions" : [
+
+            ]
+            ,"activeLine" : 20
+        }
+        ,{
+             "path" : "src\\tutorial\\CalculatorProcessor.hx"
+            ,"useTabs" : true
+            ,"indentSize" : 4
+            ,"foldedRegions" : [
+
+            ]
+            ,"activeLine" : 79
+        }
+        ,{
+             "path" : "src\\Main.hx"
+            ,"useTabs" : true
+            ,"indentSize" : 4
+            ,"foldedRegions" : [
+
+            ]
+            ,"activeLine" : 0
+        }
+    ]
+    ,"activeFile" : "src\\Main.hx"
+    ,"openFLTarget" : null
+    ,"openFLBuildMode" : "Debug"
+    ,"runActionType" : null
+    ,"runActionText" : null
+    ,"buildActionCommand" : null
+    ,"hiddenItems" : [
+
+    ]
+    ,"showHiddenItems" : false
+}
\ No newline at end of file
diff --git a/tutorial/haxe/python.hxml b/tutorial/haxe/python.hxml
new file mode 100644
index 0000000..f2c19fa
--- /dev/null
+++ b/tutorial/haxe/python.hxml
@@ -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.
+#
+ 
+#integrate files to classpath
+-cp src
+-cp gen-haxe
+-cp ../../lib/haxe/src
+
+#this class wil be used as entry point for your app.
+-main Main
+
+#Python target
+-python bin/Tutorial.py
+
+#Add debug information
+-debug
+
+#dead code elimination : remove unused code
+#"-dce no" : do not remove unused code
+#"-dce std" : remove unused code in the std lib (default)
+#"-dce full" : remove all unused code
+-dce full
\ No newline at end of file
diff --git a/tutorial/haxe/router.php b/tutorial/haxe/router.php
new file mode 100644
index 0000000..e34135c
--- /dev/null
+++ b/tutorial/haxe/router.php
@@ -0,0 +1,31 @@
+<?php
+/*
+ * 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
+ */
+
+
+
+//router file to run testing web server
+
+//set_time_limit(1);
+
+require_once  dirname(__FILE__) . '/bin/php-web-server/Main-debug.php';
+
+
diff --git a/tutorial/haxe/src/CalculatorHandler.hx b/tutorial/haxe/src/CalculatorHandler.hx
new file mode 100644
index 0000000..e9752db
--- /dev/null
+++ b/tutorial/haxe/src/CalculatorHandler.hx
@@ -0,0 +1,101 @@
+/*
+ * 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;
+
+import haxe.ds.IntMap;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import tutorial.*;
+import shared.*;
+
+
+class CalculatorHandler implements Calculator {
+
+    private var log = new IntMap<SharedStruct>();
+
+    public function new() {
+    }
+
+    public function ping() : Void {
+        trace("ping()");
+    }
+
+
+    public function add( num1 : haxe.Int32, num2 : haxe.Int32) : haxe.Int32 {
+        trace('add( $num1, $num2)');
+        return num1 + num2;
+    }
+
+    public function calculate( logid : haxe.Int32, work : Work) : haxe.Int32  {
+        trace('calculate( $logid, '+work.op+","+work.num1+","+work.num2+")");
+
+        var val : haxe.Int32 = 0;
+        switch (work.op)
+        {
+            case Operation.ADD:
+                val = work.num1 + work.num2;
+
+            case Operation.SUBTRACT:
+                val = work.num1 - work.num2;
+
+            case Operation.MULTIPLY:
+                val = work.num1 * work.num2;
+
+            case Operation.DIVIDE:
+                if (work.num2 == 0)
+                {
+                    var io = new InvalidOperation();
+                    io.whatOp = work.op;
+                    io.why = "Cannot divide by 0";
+                    throw io;
+                }
+                val = Std.int( work.num1 / work.num2);
+
+            default:
+                var io = new InvalidOperation();
+                io.whatOp = work.op;
+                io.why = "Unknown operation";
+                throw io;
+        }
+
+        var entry = new SharedStruct();
+        entry.key = logid;
+        entry.value = '$val';
+        log.set(logid, entry);
+
+        return val;
+    }
+
+    public function getStruct( key : haxe.Int32) : SharedStruct {
+        trace('getStruct($key)');
+        return log.get(key);
+    }
+
+    // oneway method,  no args
+    public function zip() : Void {
+        trace("zip()");
+    }
+
+}
diff --git a/tutorial/haxe/src/Main.hx b/tutorial/haxe/src/Main.hx
new file mode 100644
index 0000000..6bebe71
--- /dev/null
+++ b/tutorial/haxe/src/Main.hx
@@ -0,0 +1,375 @@
+/*
+ * 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;
+
+import org.apache.thrift.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+import tutorial.*;
+import shared.*;
+
+
+enum Prot {
+    binary;
+    json;
+}
+
+enum Trns {
+    socket;
+    http;
+}
+
+class Main {
+
+    private static var server : Bool = false;
+    private static var framed : Bool = false;
+    private static var buffered : Bool = false;
+    private static var prot : Prot = binary;
+    private static var trns : Trns = socket;
+
+    private static var targetHost : String = "localhost";
+    private static var targetPort : Int = 9090;
+
+    static function main() {
+
+        #if ! (flash || js || phpwebserver)
+        try {
+              ParseArgs();
+        } catch (e : String) {
+            trace(e);
+            trace(GetHelp());
+            return;
+        }
+
+        #elseif  phpwebserver
+        //forcing server
+        server = true;
+        trns = http;
+        initPhpWebServer();
+        //check method
+        if(php.Web.getMethod() != 'POST') {
+          Sys.println('http endpoint for thrift test server');
+          return;
+        }
+        #end
+
+        try {
+            if (server)
+                RunServer();
+            else
+                RunClient();
+        } catch (e : String) {
+            trace(e);
+        }
+
+        trace("Completed.");
+    }
+
+    #if phpwebserver
+    private static function initPhpWebServer()
+    {
+        //remap trace to error log
+        haxe.Log.trace = function(v:Dynamic, ?infos:haxe.PosInfos)
+        {
+          // handle trace
+          var newValue : Dynamic;
+          if (infos != null && infos.customParams!=null) {
+            var extra:String = "";
+            for( v in infos.customParams )
+              extra += "," + v;
+            newValue = v + extra;
+          }
+          else {
+            newValue = v;
+          }
+          var msg = infos != null ? infos.fileName + ':' + infos.lineNumber + ': ' : '';
+          Sys.stderr().writeString('${msg}${newValue}\n');
+        }
+    }
+    #end
+
+
+    #if ! (flash || js)
+
+    private static function GetHelp() : String {
+        return Sys.executablePath()+"  modus  trnsOption  transport  protocol\n"
+        +"Options:\n"
+        +"  modus:       client, server   (default: client)\n"
+        +"  trnsOption:  framed, buffered (default: none)\n"
+        +"  transport:   socket, http     (default: socket)\n"
+        +"  protocol:    binary, json     (default: binary)\n"
+        +"\n"
+        +"All arguments are optional.\n";
+    }
+
+
+    private static function ParseArgs() : Void {
+        var step = 0;
+        for (arg in Sys.args()) {
+
+            // server|client
+            switch(step) {
+            case 0:
+                ++step;
+                if ( arg == "client")
+                    server = false;
+                else if ( arg == "server")
+                    server = true;
+                else
+                    throw "First argument must be 'server' or 'client'";
+
+            case 1:
+                if ( arg == "framed") {
+                    framed = true;
+                } else if ( arg == "buffered") {
+                    buffered = true;
+                } else if ( arg == "socket") {
+                    trns = socket;
+                    ++step;
+                } else if ( arg == "http") {
+                    trns = http;
+                    ++step;
+                } else {
+                    throw "Unknown transport "+arg;
+                }
+
+            case 2:
+                if ( arg == "binary") {
+                    prot = binary;
+                    ++step;
+                } else if ( arg == "json") {
+                    prot = json;
+                    ++step;
+                } else {
+                    throw "Unknown protocol "+arg;
+                }
+
+            default:
+                throw "Unexpected argument "+arg;
+            }
+
+            if ( framed && buffered)
+            {
+                trace("WN: framed supersedes buffered");
+            }
+
+        }
+    }
+
+    #end
+
+    private static function ClientSetup() : Calculator {
+         trace("Client configuration:");
+
+        // endpoint transport
+        var transport : TTransport;
+        switch(trns)
+        {
+        case socket:
+             trace('- socket transport $targetHost:$targetPort');
+            transport = new TSocket( targetHost, targetPort);
+        case http:
+            var uri = 'http://${targetHost}:${targetPort}';
+            trace('- HTTP transport $uri');
+            transport = new THttpClient(uri);
+        default:
+            throw "Unhandled transport";
+        }
+
+
+        // optinal layered transport
+        if ( framed) {
+            trace("- framed transport");
+            transport = new TFramedTransport(transport);
+        } else if ( buffered) {
+            trace("- buffered transport");
+            transport = new TBufferedTransport(transport);
+        }
+
+
+        // protocol
+        var protocol : TProtocol;
+        switch(prot)
+        {
+        case binary:
+             trace("- binary protocol");
+             protocol = new TBinaryProtocol( transport);
+        case json:
+             trace("- JSON protocol");
+             protocol = new TJSONProtocol( transport);
+        default:
+            throw "Unhandled protocol";
+        }
+
+
+        // put everything together
+        transport.open();
+        return new CalculatorImpl(protocol,protocol);
+    }
+
+
+    private static function RunClient() : Void {
+        var client = ClientSetup();
+
+        try {
+              client.ping();
+            trace("ping() successful");
+        } catch(error : TException) {
+            trace('ping() failed: $error');
+        } catch(error : Dynamic) {
+            trace('ping() failed: $error');
+        }
+
+        try {
+            var sum = client.add( 1, 1);
+            trace('1+1=$sum');
+        } catch(error : TException) {
+            trace('add() failed: $error');
+        } catch(error : Dynamic) {
+            trace('add() failed: $error');
+        }
+
+
+        var work = new tutorial.Work();
+        work.op = tutorial.Operation.DIVIDE;
+        work.num1 = 1;
+        work.num2 = 0;
+        try {
+            var quotient = client.calculate( 1, work);
+            trace('Whoa we can divide by 0! Result = $quotient');
+        } catch(error : TException) {
+            trace('calculate() failed: $error');
+        } catch(error : Dynamic) {
+            trace('calculate() failed: $error');
+        }
+
+        work.op = tutorial.Operation.SUBTRACT;
+        work.num1 = 15;
+        work.num2 = 10;
+        try {
+            var diff = client.calculate( 1, work);
+            trace('15-10=$diff');
+        } catch(error : TException) {
+            trace('calculate() failed: $error');
+        } catch(error : Dynamic) {
+            trace('calculate() failed: $error');
+        }
+
+
+        try {
+            var log : SharedStruct = client.getStruct( 1);
+            var logval = log.value;
+            trace('Check log: $logval');
+        } catch(error : TException) {
+            trace('getStruct() failed: $error');
+        } catch(error : Dynamic) {
+            trace('getStruct() failed: $error');
+        }
+    }
+
+
+    private static function ServerSetup() : TServer {
+         trace("Server configuration:");
+
+        // endpoint transport
+        var transport : TServerTransport = null;
+        switch(trns)
+        {
+        case socket:
+            #if (flash || js)
+            throw 'current platform does not support socket servers';
+            #else
+             trace('- socket transport port $targetPort');
+            transport = new TServerSocket( targetPort);
+            #end
+        case http:
+            #if !phpwebserver
+              throw "HTTP server not implemented yet";
+              //trace("- http transport");
+              //transport = new THttpClient( targetHost);
+            #else
+              trace("- http transport");
+              transport = new TWrappingServerTransport(
+                      new TStreamTransport(
+                        new TFileStream("php://input", Read),
+                        new TFileStream("php://output", Append)
+                        )
+                      );
+
+            #end
+        default:
+            throw "Unhandled transport";
+        }
+
+        // optional: layered transport
+        var transfactory : TTransportFactory = null;
+        if ( framed) {
+            trace("- framed transport");
+            transfactory = new TFramedTransportFactory();
+        } else if ( buffered) {
+            trace("- buffered transport");
+            transfactory = new TBufferedTransportFactory();
+        }
+
+        // protocol
+        var protfactory : TProtocolFactory = null;
+        switch(prot)
+        {
+        case binary:
+             trace("- binary protocol");
+             protfactory = new TBinaryProtocolFactory();
+        case json:
+            trace("- JSON protocol");
+             protfactory = new TJSONProtocolFactory();
+        default:
+            throw "Unhandled protocol";
+        }
+
+        var handler = new CalculatorHandler();
+        var processor = new CalculatorProcessor(handler);
+        var server = new TSimpleServer( processor, transport, transfactory, protfactory);
+        #if phpwebserver
+        server.runOnce = true;
+        #end
+
+        return server;
+    }
+
+
+    private static function RunServer() : Void {
+        try
+        {
+            var server = ServerSetup();
+
+            trace("\nStarting the server...");
+            server.Serve();
+        }
+        catch( e : Dynamic)
+        {
+            trace('RunServer() failed: $e');
+        }
+        trace("done.");
+    }
+
+}
+
diff --git a/tutorial/hs/HaskellClient.hs b/tutorial/hs/HaskellClient.hs
index a56187b..bd29df0 100644
--- a/tutorial/hs/HaskellClient.hs
+++ b/tutorial/hs/HaskellClient.hs
@@ -30,7 +30,9 @@
 import Thrift.Transport.Handle
 import Thrift.Server
 
+import Control.Exception
 import Data.Maybe
+import Data.Text.Lazy
 import Text.Printf
 import Network
 
@@ -46,28 +48,27 @@
   printf "1+1=%d\n" sum
 
 
-  let work = Work { f_Work_op = Just DIVIDE,
-                    f_Work_num1 = Just 1,
-                    f_Work_num2 = Just 0,
-                    f_Work_comment = Nothing
+  let work = Work { work_op = DIVIDE,
+                    work_num1 = 1,
+                    work_num2 = 0,
+                    work_comment = Nothing
                   }
 
-  -- TODO - get this one working
-  --catch (Client.calculate client 1 work) (\except ->
-  --     printf "InvalidOp %s" (show except))
+  Control.Exception.catch (printf "1/0=%d\n" =<< Client.calculate client 1 work)
+        (\e -> printf "InvalidOperation %s\n" (show (e :: InvalidOperation)))
 
 
-  let work = Work { f_Work_op = Just SUBTRACT,
-                    f_Work_num1 = Just 15,
-                    f_Work_num2 = Just 10,
-                    f_Work_comment = Nothing
+  let work = Work { work_op = SUBTRACT,
+                    work_num1 = 15,
+                    work_num2 = 10,
+                    work_comment = Nothing
                   }
 
   diff <- Client.calculate client 1 work
   printf "15-10=%d\n" diff
 
   log <- SClient.getStruct client 1
-  printf "Check log: %s\n"  $ fromJust $ f_SharedStruct_value log
+  printf "Check log: %s\n" $ unpack $ sharedStruct_value log
 
   -- Close!
   tClose transport
diff --git a/tutorial/hs/HaskellServer.hs b/tutorial/hs/HaskellServer.hs
index 4f9ab7c..cfe1344 100644
--- a/tutorial/hs/HaskellServer.hs
+++ b/tutorial/hs/HaskellServer.hs
@@ -17,6 +17,8 @@
 -- under the License.
 --
 
+{-# LANGUAGE OverloadedStrings #-}
+
 import qualified Calculator
 import Calculator_Iface
 import Tutorial_Types
@@ -28,6 +30,8 @@
 import Thrift.Transport
 import Thrift.Server
 
+import Data.Int
+import Data.String
 import Data.Maybe
 import Text.Printf
 import Control.Exception (throw)
@@ -36,7 +40,7 @@
 import Data.Map ((!))
 import Data.Monoid
 
-data CalculatorHandler = CalculatorHandler {mathLog :: MVar (M.Map Int SharedStruct)}
+data CalculatorHandler = CalculatorHandler {mathLog :: MVar (M.Map Int32 SharedStruct)}
 
 newCalculatorHandler = do
   log <- newMVar mempty
@@ -45,7 +49,7 @@
 instance SharedService_Iface CalculatorHandler where
   getStruct self k = do
     myLog <- readMVar (mathLog self)
-    return $ (myLog ! (fromJust k))
+    return $ (myLog ! k)
 
 
 instance Calculator_Iface CalculatorHandler where
@@ -53,8 +57,8 @@
     print "ping()"
 
   add _ n1 n2 = do
-    printf "add(%d,%d)\n" (fromJust n1) (fromJust n2)
-    return ((fromJust n1)+(fromJust n2))
+    printf "add(%d,%d)\n" n1 n2
+    return (n1 + n2)
 
   calculate self mlogid mwork = do
     printf "calculate(%d, %s)\n" logid (show work)
@@ -70,27 +74,24 @@
                     if num2 work == 0 then
                         throw $
                               InvalidOperation {
-                                 f_InvalidOperation_what = Just $ fromEnum $ op work,
-                                 f_InvalidOperation_why = Just "Cannot divide by 0"
+                                 invalidOperation_whatOp = fromIntegral $ fromEnum $ op work,
+                                 invalidOperation_why = "Cannot divide by 0"
                                             }
                     else
                         num1 work `div` num2 work
 
-    let logEntry = SharedStruct (Just logid) (Just (show val))
+    let logEntry = SharedStruct logid (fromString $ show $ val)
     modifyMVar_ (mathLog self) $ return .(M.insert logid logEntry)
 
-    return val
+    return $! val
 
    where
      -- stupid dynamic languages f'ing it up
-     num1 = fromJust . f_Work_num1
-     num2 = fromJust . f_Work_num2
-     op = fromJust . f_Work_op
-     logid = fromJust mlogid
-     work = fromJust mwork
-
-
-    --return val
+     num1 = work_num1
+     num2 = work_num2
+     op = work_op
+     logid = mlogid
+     work = mwork
 
   zip _ =
     print "zip()"
diff --git a/tutorial/hs/LICENSE b/tutorial/hs/LICENSE
new file mode 100644
index 0000000..3b6d7d7
--- /dev/null
+++ b/tutorial/hs/LICENSE
@@ -0,0 +1,239 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+--------------------------------------------------
+SOFTWARE DISTRIBUTED WITH THRIFT:
+
+The Apache Thrift software includes a number of subcomponents with
+separate copyright notices and license terms. Your use of the source
+code for the these subcomponents is subject to the terms and
+conditions of the following licenses.
+
+--------------------------------------------------
+Portions of the following files are licensed under the MIT License:
+
+  lib/erl/src/Makefile.am
+
+Please see doc/otp-base-license.txt for the full terms of this license.
+
+--------------------------------------------------
+For the aclocal/ax_boost_base.m4 and contrib/fb303/aclocal/ax_boost_base.m4 components:
+
+#   Copyright (c) 2007 Thomas Porschberg <thomas@randspringer.de>
+#
+#   Copying and distribution of this file, with or without
+#   modification, are permitted in any medium without royalty provided
+#   the copyright notice and this notice are preserved.
+
+--------------------------------------------------
+For the lib/nodejs/lib/thrift/json_parse.js:
+
+/*
+    json_parse.js
+    2015-05-02
+    Public Domain.
+    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+*/
+(By Douglas Crockford <douglas@crockford.com>)
+--------------------------------------------------
diff --git a/tutorial/hs/Makefile.am b/tutorial/hs/Makefile.am
new file mode 100755
index 0000000..a3eccc2
--- /dev/null
+++ b/tutorial/hs/Makefile.am
@@ -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.
+#
+
+all-local:
+	$(top_builddir)/compiler/cpp/thrift --gen hs -r $(top_srcdir)/tutorial/tutorial.thrift
+	$(CABAL) install
+
+install-exec-hook:
+	$(CABAL) install
+
+# Make sure this doesn't fail if Haskell is not configured.
+clean-local:
+	$(CABAL) clean
+	$(RM) -r gen-*
+
+check-local:
+	$(CABAL) check
+
+tutorialserver: all
+	dist/build/HaskellServer/HaskellServer
+
+tutorialclient: all
+	dist/build/HaskellClient/HaskellClient
+
+EXTRA_DIST = \
+	LICENSE
diff --git a/tutorial/hs/Setup.lhs b/tutorial/hs/Setup.lhs
new file mode 100644
index 0000000..c7df182
--- /dev/null
+++ b/tutorial/hs/Setup.lhs
@@ -0,0 +1,21 @@
+#!/usr/bin/env runhaskell
+
+> -- 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 Distribution.Simple
+> main = defaultMain
diff --git a/tutorial/hs/ThriftTutorial.cabal b/tutorial/hs/ThriftTutorial.cabal
old mode 100644
new mode 100755
index 1655ce7..62e682f
--- a/tutorial/hs/ThriftTutorial.cabal
+++ b/tutorial/hs/ThriftTutorial.cabal
@@ -18,31 +18,56 @@
 --
 
 Name:           ThriftTutorial
-Version:        0.1.0
-Cabal-Version:  >= 1.2
-License:        Apache2
+Version:        1.0.0
+Cabal-Version:  >= 1.4
+License:        OtherLicense
 Category:       Foreign
 Build-Type:     Simple
 Synopsis:       Thrift Tutorial library package
+Homepage:       http://thrift.apache.org
+Bug-Reports:    https://issues.apache.org/jira/browse/THRIFT
+Maintainer:     dev@thrift.apache.org
+License-File:   LICENSE
+
+Description:
+  Haskell tutorial for the Apache Thrift RPC system. Requires the use of the thrift code generator.
+
+flag network-uri
+   description: Get Network.URI from the network-uri package
+   default: True
 
 Executable HaskellServer
   Main-is: HaskellServer.hs
   Hs-Source-Dirs:
-    ., ../gen-hs/
+    ., gen-hs/
   Build-Depends:
-    base >=4, network, ghc-prim, containers, Thrift
-  ghc-options:
-    -fglasgow-exts
+    base >= 4, base < 5, ghc-prim, containers, thrift, vector, unordered-containers, text, hashable, bytestring, QuickCheck
   Extensions:
-    DeriveDataTypeable
+    DeriveDataTypeable,
+    ExistentialQuantification,
+    FlexibleInstances,
+    KindSignatures,
+    MagicHash,
+    RankNTypes,
+    ScopedTypeVariables,
+    TypeSynonymInstances
 
 Executable HaskellClient
   Main-is: HaskellClient.hs
   Hs-Source-Dirs:
-    ., ../gen-hs/
+    ., gen-hs/
   Build-Depends:
-    base >=4, network, ghc-prim, containers, Thrift
-  ghc-options:
-    -fglasgow-exts
+    base >= 4, base < 5, ghc-prim, containers, thrift, vector, QuickCheck
+  if flag(network-uri)
+     build-depends: network-uri >= 2.6, network >= 2.6
+  else
+     build-depends: network < 2.6
   Extensions:
-    DeriveDataTypeable
+    DeriveDataTypeable,
+    ExistentialQuantification,
+    FlexibleInstances,
+    KindSignatures,
+    MagicHash,
+    RankNTypes,
+    ScopedTypeVariables,
+    TypeSynonymInstances
diff --git a/tutorial/java/Makefile.am b/tutorial/java/Makefile.am
index aa8b80c..95908b1 100755
--- a/tutorial/java/Makefile.am
+++ b/tutorial/java/Makefile.am
@@ -41,4 +41,5 @@
 
 EXTRA_DIST = \
 	build.xml \
-	src
+	src \
+	README.md
diff --git a/tutorial/java/README b/tutorial/java/README
deleted file mode 100644
index c0811f7..0000000
--- a/tutorial/java/README
+++ /dev/null
@@ -1,20 +0,0 @@
-Thrift Java Tutorial
-==================================================
-1) Compile the Java library
-
-thrift/lib/java$ make
-or:
-thrift/lib/java$ ant
-
-4) Run the tutorial:
-
-start server and client with one step:
-thrift/tutorial/java$ make tutorial
-
-or:
-thrift/tutorial/java$ make tutorialserver
-thrift/tutorial/java$ make tutorialclient
-
-or:
-thrift/tutorial/java$ ant tutorialserver
-thrift/tutorial/java$ ant tutorialclient
diff --git a/tutorial/java/README.md b/tutorial/java/README.md
new file mode 100644
index 0000000..f109fea
--- /dev/null
+++ b/tutorial/java/README.md
@@ -0,0 +1,24 @@
+Thrift Java Tutorial
+==================================================
+1) Compile the Java library
+
+    thrift/lib/java$ make
+or:
+
+    thrift/lib/java$ ant
+
+4) Run the tutorial:
+
+start server and client with one step:
+
+    thrift/tutorial/java$ make tutorial
+
+or:
+
+    thrift/tutorial/java$ make tutorialserver
+    thrift/tutorial/java$ make tutorialclient
+
+or:
+
+    thrift/tutorial/java$ ant tutorialserver
+    thrift/tutorial/java$ ant tutorialclient
diff --git a/tutorial/java/build.xml b/tutorial/java/build.xml
index eceeca7..55cdb8f 100644
--- a/tutorial/java/build.xml
+++ b/tutorial/java/build.xml
@@ -25,11 +25,13 @@
   <property name="build" location="build" />
 
   <path id="libs.classpath">
-    <fileset dir="../../lib/java/build">
-      <include name="*.jar" />
-      <exclude name="-test.jar" />
+    <fileset dir="../../lib/java/build/libs">
+      <include name="libthrift*.jar" />
+      <exclude name="libthrift*test.jar" />
+      <exclude name="libthrift*javadoc.jar" />
+      <exclude name="libthrift*sources.jar" />
     </fileset>
-    <fileset dir="../../lib/java/build/lib">
+    <fileset dir="../../lib/java/build/deps">
       <include name="*.jar" />
     </fileset>
   </path>
@@ -42,7 +44,7 @@
     <pathelement path="${build}" />
     <pathelement path="tutorial.jar" />
   </path>
-  
+
   <target name="init">
     <tstamp />
     <mkdir dir="${build}"/>
@@ -50,8 +52,8 @@
   </target>
 
   <target name="compile" depends="init, generate">
-    <javac srcdir="${gen}" destdir="${build}" classpathref="libs.classpath" />
-    <javac srcdir="${src}" destdir="${build}" classpathref="build.classpath" />
+    <javac compiler="modern" includeantruntime="false" srcdir="${gen}" destdir="${build}" classpathref="libs.classpath" />
+    <javac compiler="modern" includeantruntime="false" srcdir="${src}" destdir="${build}" classpathref="build.classpath" />
   </target>
 
   <target name="test" depends="tutorial" />
diff --git a/tutorial/java/src/CalculatorHandler.java b/tutorial/java/src/CalculatorHandler.java
index 4216be5..92944b0 100644
--- a/tutorial/java/src/CalculatorHandler.java
+++ b/tutorial/java/src/CalculatorHandler.java
@@ -58,7 +58,7 @@
     case DIVIDE:
       if (work.num2 == 0) {
         InvalidOperation io = new InvalidOperation();
-        io.what = work.op.getValue();
+        io.whatOp = work.op.getValue();
         io.why = "Cannot divide by 0";
         throw io;
       }
@@ -66,7 +66,7 @@
       break;
     default:
       InvalidOperation io = new InvalidOperation();
-      io.what = work.op.getValue();
+      io.whatOp = work.op.getValue();
       io.why = "Unknown operation";
       throw io;
     }
diff --git a/tutorial/js/build.xml b/tutorial/js/build.xml
index 73d535d..03a6e7c 100644
--- a/tutorial/js/build.xml
+++ b/tutorial/js/build.xml
@@ -31,11 +31,13 @@
   <property name="thrift.java.dir" location="${thrift.dir}/lib/java" />
 
   <path id="libs.classpath">
-    <fileset dir="../../lib/java/build">
-      <include name="*.jar" />
-      <exclude name="-test.jar" />
+    <fileset dir="${thrift.java.dir}/build/libs">
+      <include name="libthrift*.jar" />
+      <exclude name="libthrift*test.jar" />
+      <exclude name="libthrift*javadoc.jar" />
+      <exclude name="libthrift*sources.jar" />
     </fileset>
-    <fileset dir="../../lib/java/build/lib">
+    <fileset dir="${thrift.java.dir}/build/deps">
       <include name="*.jar" />
     </fileset>
   </path>
@@ -51,13 +53,13 @@
   </target>
 
   <target name="compile" depends="init">
-    <javac srcdir="${gen}" destdir="${build}" classpathref="libs.classpath" />
-    <javac srcdir="${javasrc}" destdir="${build}" classpathref="build.classpath">
+    <javac compiler="modern" includeantruntime="false" srcdir="${gen}" destdir="${build}" classpathref="libs.classpath" />
+    <javac compiler="modern" includeantruntime="false" srcdir="${javasrc}" destdir="${build}" classpathref="build.classpath">
       <exclude name="JavaClient.java"/>
       <exclude name="JavaServer.java"/>
       <include name="CalculatorHandler.java"/>
     </javac>
-    <javac srcdir="${src}" destdir="${build}" classpathref="build.classpath">
+    <javac compiler="modern" includeantruntime="false" srcdir="${src}" destdir="${build}" classpathref="build.classpath">
       <compilerarg value="-Xlint:all"/>
     </javac>
   </target>
@@ -80,7 +82,7 @@
       <arg line="--gen js -r  ../tutorial.thrift"/>
     </exec>
   </target>
-  
+
   <target name="clean">
     <delete dir="${build}" />
     <delete dir="gen-js"/>
diff --git a/tutorial/js/tutorial.html b/tutorial/js/tutorial.html
index 131ffae..d020bed 100755
--- a/tutorial/js/tutorial.html
+++ b/tutorial/js/tutorial.html
@@ -22,7 +22,7 @@
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>Thrift Javascript Bindings - Tutorial Example</title>
 
-  <script src="../../lib/js/thrift.js"                   type="text/javascript"></script>
+  <script src="../../lib/js/src/thrift.js"  type="text/javascript"></script>
   <script src="gen-js/tutorial_types.js"    type="text/javascript"></script>
   <script src="gen-js/shared_types.js"      type="text/javascript"></script>
   <script src="gen-js/SharedService.js"     type="text/javascript"></script>
@@ -49,7 +49,7 @@
     var protocol  = new Thrift.Protocol(transport);
     var client    = new CalculatorClient(protocol);
 
-    var work = new Work()
+    var work = new Work();
     work.num1 = $("#num1").val();
     work.num2 = $("#num2").val();
     work.op = $("#op").val();
@@ -98,7 +98,7 @@
   </table>
   </form>
   
-  <p>This Java Script example uses <a href="https://git-wip-us.apache.org/repos/asf?p=thrift.git;a=blob;f=tutorial/tutorial.thrift;hb=HEAD">tutorial.thrift</a> and a Thrift server using JSON protocol and HTTP transport.
+  <p>This Java Script example uses <a href="https://github.com/apache/thrift/blob/master/tutorial/tutorial.thrift">tutorial.thrift</a> and a Thrift server using JSON protocol and HTTP transport.
   </p>
     <p>
         <a href="http://validator.w3.org/check/referer"><img
diff --git a/tutorial/netcore/.gitignore b/tutorial/netcore/.gitignore
new file mode 100644
index 0000000..9938bb2
--- /dev/null
+++ b/tutorial/netcore/.gitignore
@@ -0,0 +1 @@
+!**/*.pfx
\ No newline at end of file
diff --git a/tutorial/netcore/Client/Client.csproj b/tutorial/netcore/Client/Client.csproj
new file mode 100644
index 0000000..911272d
--- /dev/null
+++ b/tutorial/netcore/Client/Client.csproj
@@ -0,0 +1,19 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.0</TargetFramework>
+    <AssemblyName>Client</AssemblyName>
+    <PackageId>Client</PackageId>
+    <OutputType>Exe</OutputType>
+    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
+    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
+    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
+    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Interfaces\Interfaces.csproj" />
+    <ProjectReference Include="..\..\..\lib\netcore\Thrift\Thrift.csproj" />
+  </ItemGroup>
+
+</Project>
diff --git a/tutorial/netcore/Client/Program.cs b/tutorial/netcore/Client/Program.cs
new file mode 100644
index 0000000..ce5d8c7
--- /dev/null
+++ b/tutorial/netcore/Client/Program.cs
@@ -0,0 +1,355 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Security;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Thrift;
+using Thrift.Protocols;
+using Thrift.Transports;
+using Thrift.Transports.Client;
+using tutorial;
+using shared;
+
+namespace Client
+{
+    public class Program
+    {
+        private static readonly ILogger Logger = new LoggerFactory().AddConsole().AddDebug().CreateLogger(nameof(Client));
+
+        private static void DisplayHelp()
+        {
+            Logger.LogInformation(@"
+Usage: 
+    Client.exe -help
+        will diplay help information 
+
+    Client.exe -tr:<transport> -pr:<protocol> -mc:<numClients>
+        will run client with specified arguments (tcp transport and binary protocol by default) and with 1 client
+
+Options:
+    -tr (transport): 
+        tcp - (default) tcp transport will be used (host - ""localhost"", port - 9090)
+        tcpbuffered - buffered transport over tcp will be used (host - ""localhost"", port - 9090)
+        namedpipe - namedpipe transport will be used (pipe address - "".test"")
+        http - http transport will be used (address - ""http://localhost:9090"")        
+        tcptls - tcp tls transport will be used (host - ""localhost"", port - 9090)
+        framed - tcp framed transport will be used (host - ""localhost"", port - 9090)
+
+    -pr (protocol): 
+        binary - (default) binary protocol will be used
+        compact - compact protocol will be used
+        json - json protocol will be used
+        multiplexed - multiplexed protocol will be used
+
+    -mc (multiple clients):
+        <numClients> - number of multiple clients to connect to server (max 100, default 1)
+
+Sample:
+    Client.exe -tr:tcp -p:binary
+");
+        }
+
+        public static void Main(string[] args)
+        {
+            args = args ?? new string[0];
+
+            if (args.Any(x => x.StartsWith("-help", StringComparison.OrdinalIgnoreCase)))
+            {
+                DisplayHelp();
+                return;
+            }
+
+            Logger.LogInformation("Starting client...");
+
+            using (var source = new CancellationTokenSource())
+            {
+                RunAsync(args, source.Token).GetAwaiter().GetResult();
+            }
+        }
+
+        private static async Task RunAsync(string[] args, CancellationToken cancellationToken)
+        {
+            var numClients = GetNumberOfClients(args);
+
+            Logger.LogInformation($"Selected # of clients: {numClients}");
+
+            var transports = new TClientTransport[numClients];
+            for (int i = 0; i < numClients; i++)
+            {
+                var t = GetTransport(args);
+                transports[i] = t;
+            }
+            
+            Logger.LogInformation($"Selected client transport: {transports[0]}");
+
+            var protocols = new Tuple<Protocol, TProtocol>[numClients];
+            for (int i = 0; i < numClients; i++)
+            {
+                var p = GetProtocol(args, transports[i]);
+                protocols[i] = p;
+            }
+
+            Logger.LogInformation($"Selected client protocol: {protocols[0].Item1}");
+
+            var tasks = new Task[numClients];
+            for (int i = 0; i < numClients; i++)
+            {
+                var task = RunClientAsync(protocols[i], cancellationToken);
+                tasks[i] = task;
+            }
+
+            Task.WaitAll(tasks);
+
+            await Task.CompletedTask;
+        }
+
+        private static TClientTransport GetTransport(string[] args)
+        {
+            var transport = args.FirstOrDefault(x => x.StartsWith("-tr"))?.Split(':')?[1];
+
+            Transport selectedTransport;
+            if (Enum.TryParse(transport, true, out selectedTransport))
+            {
+                switch (selectedTransport)
+                {
+                    case Transport.Tcp:
+                        return new TSocketClientTransport(IPAddress.Loopback, 9090);
+                    case Transport.NamedPipe:
+                        return new TNamedPipeClientTransport(".test");
+                    case Transport.Http:
+                        return new THttpClientTransport(new Uri("http://localhost:9090"), null);
+                    case Transport.TcpBuffered:
+                        return new TBufferedClientTransport(new TSocketClientTransport(IPAddress.Loopback, 9090));
+                    case Transport.TcpTls:
+                        return new TTlsSocketClientTransport(IPAddress.Loopback, 9090, GetCertificate(), CertValidator, LocalCertificateSelectionCallback);
+                    case Transport.Framed:
+                        return new TFramedClientTransport(new TSocketClientTransport(IPAddress.Loopback, 9090));
+                }
+            }
+
+            return new TSocketClientTransport(IPAddress.Loopback, 9090);
+        }
+
+        private static int GetNumberOfClients(string[] args)
+        {
+            var numClients = args.FirstOrDefault(x => x.StartsWith("-mc"))?.Split(':')?[1];
+
+            Logger.LogInformation($"Selected # of clients: {numClients}");
+
+            int c;
+            if( int.TryParse(numClients, out c) && (0 < c) && (c <= 100))
+				return c;
+			else
+				return 1;
+        }
+
+        private static X509Certificate2 GetCertificate()
+        {
+            // due to files location in net core better to take certs from top folder
+            var certFile = GetCertPath(Directory.GetParent(Directory.GetCurrentDirectory()));
+            return new X509Certificate2(certFile, "ThriftTest");
+        }
+
+        private static string GetCertPath(DirectoryInfo di, int maxCount = 6)
+        {
+            var topDir = di;
+            var certFile =
+                topDir.EnumerateFiles("ThriftTest.pfx", SearchOption.AllDirectories)
+                    .FirstOrDefault();
+            if (certFile == null)
+            {
+                if (maxCount == 0)
+                    throw new FileNotFoundException("Cannot find file in directories");
+                return GetCertPath(di.Parent, maxCount - 1);
+            }
+
+            return certFile.FullName;
+        }
+
+        private static X509Certificate LocalCertificateSelectionCallback(object sender,
+            string targetHost, X509CertificateCollection localCertificates,
+            X509Certificate remoteCertificate, string[] acceptableIssuers)
+        {
+            return GetCertificate();
+        }
+
+        private static bool CertValidator(object sender, X509Certificate certificate,
+            X509Chain chain, SslPolicyErrors sslPolicyErrors)
+        {
+            return true;
+        }
+
+        private static Tuple<Protocol, TProtocol> GetProtocol(string[] args, TClientTransport transport)
+        {
+            var protocol = args.FirstOrDefault(x => x.StartsWith("-pr"))?.Split(':')?[1];
+
+            Protocol selectedProtocol;
+            if (Enum.TryParse(protocol, true, out selectedProtocol))
+            {
+                switch (selectedProtocol)
+                {
+                    case Protocol.Binary:
+                        return new Tuple<Protocol, TProtocol>(selectedProtocol, new TBinaryProtocol(transport));
+                    case Protocol.Compact:
+                        return new Tuple<Protocol, TProtocol>(selectedProtocol, new TCompactProtocol(transport));
+                    case Protocol.Json:
+                        return new Tuple<Protocol, TProtocol>(selectedProtocol, new TJsonProtocol(transport));
+                    case Protocol.Multiplexed:
+                        // it returns BinaryProtocol to avoid making wrapped protocol as public in TProtocolDecorator (in RunClientAsync it will be wrapped into Multiplexed protocol)
+                        return new Tuple<Protocol, TProtocol>(selectedProtocol, new TBinaryProtocol(transport));
+                }
+            }
+
+            return new Tuple<Protocol, TProtocol>(selectedProtocol, new TBinaryProtocol(transport));
+        }
+
+        private static async Task RunClientAsync(Tuple<Protocol, TProtocol> protocolTuple, CancellationToken cancellationToken)
+        {
+            try
+            {
+                var protocol = protocolTuple.Item2;
+                var protocolType = protocolTuple.Item1;
+
+                TBaseClient client = null;
+
+                try
+                {
+                    if (protocolType != Protocol.Multiplexed)
+                    {
+
+                        client = new Calculator.Client(protocol);
+                        await ExecuteCalculatorClientOperations(cancellationToken, (Calculator.Client)client);
+                    }
+                    else
+                    {
+                        // it uses binary protocol there  to create Multiplexed protocols
+                        var multiplex = new TMultiplexedProtocol(protocol, nameof(Calculator));
+                        client = new Calculator.Client(multiplex);
+                        await ExecuteCalculatorClientOperations(cancellationToken, (Calculator.Client)client);
+
+                        multiplex = new TMultiplexedProtocol(protocol, nameof(SharedService));
+                        client = new SharedService.Client(multiplex);
+                        await ExecuteSharedServiceClientOperations(cancellationToken, (SharedService.Client)client);
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Logger.LogError($"{client?.ClientId} " + ex);
+                }
+                finally
+                {
+                    protocol.Transport.Close();
+                }
+            }
+            catch (TApplicationException x)
+            {
+                Logger.LogError(x.ToString());
+            }
+        }
+
+        private static async Task ExecuteCalculatorClientOperations(CancellationToken cancellationToken, Calculator.Client client)
+        {
+            await client.OpenTransportAsync(cancellationToken);
+
+            // Async version
+
+            Logger.LogInformation($"{client.ClientId} PingAsync()");
+            await client.pingAsync(cancellationToken);
+
+            Logger.LogInformation($"{client.ClientId} AddAsync(1,1)");
+            var sum = await client.addAsync(1, 1, cancellationToken);
+            Logger.LogInformation($"{client.ClientId} AddAsync(1,1)={sum}");
+
+            var work = new Work
+            {
+                Op = Operation.DIVIDE,
+                Num1 = 1,
+                Num2 = 0
+            };
+
+            try
+            {
+                Logger.LogInformation($"{client.ClientId} CalculateAsync(1)");
+                await client.calculateAsync(1, work, cancellationToken);
+                Logger.LogInformation($"{client.ClientId} Whoa we can divide by 0");
+            }
+            catch (InvalidOperation io)
+            {
+                Logger.LogInformation($"{client.ClientId} Invalid operation: " + io);
+            }
+
+            work.Op = Operation.SUBTRACT;
+            work.Num1 = 15;
+            work.Num2 = 10;
+
+            try
+            {
+                Logger.LogInformation($"{client.ClientId} CalculateAsync(1)");
+                var diff = await client.calculateAsync(1, work, cancellationToken);
+                Logger.LogInformation($"{client.ClientId} 15-10={diff}");
+            }
+            catch (InvalidOperation io)
+            {
+                Logger.LogInformation($"{client.ClientId} Invalid operation: " + io);
+            }
+
+            Logger.LogInformation($"{client.ClientId} GetStructAsync(1)");
+            var log = await client.getStructAsync(1, cancellationToken);
+            Logger.LogInformation($"{client.ClientId} Check log: {log.Value}");
+
+            Logger.LogInformation($"{client.ClientId} ZipAsync() with delay 100mc on server side");
+            await client.zipAsync(cancellationToken);
+        }
+        private static async Task ExecuteSharedServiceClientOperations(CancellationToken cancellationToken, SharedService.Client client)
+        {
+            await client.OpenTransportAsync(cancellationToken);
+
+            // Async version
+
+            Logger.LogInformation($"{client.ClientId} SharedService GetStructAsync(1)");
+            var log = await client.getStructAsync(1, cancellationToken);
+            Logger.LogInformation($"{client.ClientId} SharedService Value: {log.Value}");
+        }
+
+
+        private enum Transport
+        {
+            Tcp,
+            NamedPipe,
+            Http,
+            TcpBuffered,
+            Framed,
+            TcpTls
+        }
+
+        private enum Protocol
+        {
+            Binary,
+            Compact,
+            Json,
+            Multiplexed
+        }
+    }
+}
diff --git a/tutorial/netcore/Client/Properties/AssemblyInfo.cs b/tutorial/netcore/Client/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..568382e
--- /dev/null
+++ b/tutorial/netcore/Client/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+
+[assembly: Guid("de78a01b-f7c6-49d1-97da-669d2ed37641")]
\ No newline at end of file
diff --git a/tutorial/netcore/Client/Properties/launchSettings.json b/tutorial/netcore/Client/Properties/launchSettings.json
new file mode 100644
index 0000000..6b7b60d
--- /dev/null
+++ b/tutorial/netcore/Client/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+  "profiles": {
+    "Client": {
+      "commandName": "Project",
+      "commandLineArgs": "-p:multiplexed"
+    }
+  }
+}
\ No newline at end of file
diff --git a/tutorial/netcore/Client/ThriftTest.pfx b/tutorial/netcore/Client/ThriftTest.pfx
new file mode 100644
index 0000000..f0ded28
--- /dev/null
+++ b/tutorial/netcore/Client/ThriftTest.pfx
Binary files differ
diff --git a/tutorial/netcore/Interfaces/.gitignore b/tutorial/netcore/Interfaces/.gitignore
new file mode 100644
index 0000000..2e7446e
--- /dev/null
+++ b/tutorial/netcore/Interfaces/.gitignore
@@ -0,0 +1,3 @@
+# ignore for autogenerated files
+/shared
+/tutorial
diff --git a/tutorial/netcore/Interfaces/Interfaces.csproj b/tutorial/netcore/Interfaces/Interfaces.csproj
new file mode 100644
index 0000000..4297a06
--- /dev/null
+++ b/tutorial/netcore/Interfaces/Interfaces.csproj
@@ -0,0 +1,30 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <AssemblyName>Interfaces</AssemblyName>
+    <PackageId>Interfaces</PackageId>
+    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
+    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
+    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
+    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="../../../lib/netcore/Thrift/Thrift.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="System.ServiceModel.Primitives" Version="[4.4,)" />
+  </ItemGroup>
+
+  <Target Name="PreBuild" BeforeTargets="_GenerateRestoreProjectSpec;Restore;Compile">
+    <Exec Condition="'$(OS)' == 'Windows_NT'" Command="where thrift" ConsoleToMSBuild="true">
+      <Output TaskParameter="ConsoleOutput" PropertyName="PathToThrift" />
+    </Exec>
+    <Exec Condition="Exists('$(PathToThrift)')" Command="$(PathToThrift) -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../tutorial.thrift" />
+    <Exec Condition="Exists('thrift')" Command="thrift -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../tutorial.thrift" />
+    <Exec Condition="Exists('./../../../compiler/cpp/thrift')" Command="./../../../compiler/cpp/thrift -out $(ProjectDir) -gen netcore:wcf,union,serial,hashcode -r ./../../tutorial.thrift" />
+  </Target>
+
+</Project>
diff --git a/tutorial/netcore/Interfaces/Properties/AssemblyInfo.cs b/tutorial/netcore/Interfaces/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..9126b17
--- /dev/null
+++ b/tutorial/netcore/Interfaces/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+
+[assembly: Guid("4d13163d-9067-4c9c-8af0-64e08451397d")]
\ No newline at end of file
diff --git a/tutorial/netcore/Makefile.am b/tutorial/netcore/Makefile.am
new file mode 100644
index 0000000..e305556
--- /dev/null
+++ b/tutorial/netcore/Makefile.am
@@ -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.
+#
+
+SUBDIRS = . 
+
+all-local:
+	$(DOTNETCORE) build
+
+clean-local:
+	$(RM) Interfaces.dll
+	$(RM) -r Client/bin
+	$(RM) -r Client/obj
+	$(RM) -r Server/bin
+	$(RM) -r Server/obj
+	$(RM) -r Interfaces/bin
+	$(RM) -r Interfaces/obj
+
+EXTRA_DIST = \
+	Client \
+	Interfaces \
+	README.md \
+	Server \
+	Tutorial.sln \
+	build.cmd \
+	build.sh
+			 
diff --git a/tutorial/netcore/README.md b/tutorial/netcore/README.md
new file mode 100644
index 0000000..626ef92
--- /dev/null
+++ b/tutorial/netcore/README.md
@@ -0,0 +1,278 @@
+# Building of samples for different platforms 
+
+# Reused components 
+- NET Core Standard 2.0
+- NET Core App 2.0
+
+# How to build
+- Download and install the latest .NET Core SDK for your platform https://www.microsoft.com/net/core#windowsvs2015 (archive for SDK 1.0.0-preview2-003121 located by: https://github.com/dotnet/core/blob/master/release-notes/download-archive.md)
+- Ensure that you have thrift.exe which supports netcore lib and it added to PATH 
+- Go to current folder 
+- Run **build.sh** or **build.cmd** from the root of cloned repository
+- Check tests in **src/Tests** folder
+- Continue with /tutorials/netcore 
+
+# How to run 
+
+Notes: dotnet run supports passing arguments to app after -- symbols (https://docs.microsoft.com/en-us/dotnet/articles/core/tools/dotnet-run) - example: **dotnet run -- -h** will show help for app
+
+- build 
+- go to folder (Client/Server) 
+- run with specifying of correct parameters **dotnet run -tr:tcp -pr:multiplexed**, **dotnet run -help** (later, after migration to csproj and latest SDK will be possibility to use more usable form **dotnet run -- arguments**)
+
+#Notes
+- Possible adding additional platforms after stabilization of .NET Core (runtimes, platforms (Red Hat Linux, OpenSuse, etc.) 
+
+#Known issues
+- In trace logging mode you can see some not important internal exceptions
+
+# Running of samples 
+Please install Thrift C# .NET Core library or copy sources and build them to correcly build and run samples 
+
+# NetCore Server
+
+Usage: 
+
+    Server.exe -h
+        will diplay help information 
+
+    Server.exe -tr:<transport> -pr:<protocol> 
+        will run server with specified arguments (tcp transport and binary protocol by default)
+
+Options:
+
+    -tr (transport): 
+        tcp - (default) tcp transport will be used (host - ""localhost"", port - 9090)
+        tcpbuffered - tcp buffered transport will be used (host - ""localhost"", port - 9090)
+        namedpipe - namedpipe transport will be used (pipe address - "".test"")
+        http - http transport will be used (http address - ""localhost:9090"")
+        tcptls - tcp transport with tls will be used (host - ""localhost"", port - 9090)
+        framed - tcp framed transport will be used (host - ""localhost"", port - 9090)
+
+    -pr (protocol): 
+        binary - (default) binary protocol will be used
+        compact - compact protocol will be used
+        json - json protocol will be used
+		
+Sample:
+
+    Server.exe -tr:tcp
+
+**Remarks**:
+
+    For TcpTls mode certificate's file ThriftTest.pfx should be in directory with binaries in case of command line usage (or at project level in case of debugging from IDE).
+    Password for certificate - "ThriftTest".
+
+
+
+# NetCore Client
+
+Usage: 
+
+    Client.exe -h
+        will diplay help information 
+
+    Client.exe -tr:<transport> -pr:<protocol> -mc:<numClients>
+        will run client with specified arguments (tcp transport and binary protocol by default)
+
+Options:
+
+    -tr (transport): 
+        tcp - (default) tcp transport will be used (host - ""localhost"", port - 9090)
+        tcpbuffered - buffered transport over tcp will be used (host - ""localhost"", port - 9090)
+        namedpipe - namedpipe transport will be used (pipe address - "".test"")
+        http - http transport will be used (address - ""http://localhost:9090"")        
+        tcptls - tcp tls transport will be used (host - ""localhost"", port - 9090)
+        framed - tcp framed transport will be used (host - ""localhost"", port - 9090)
+
+    -pr (protocol): 
+        binary - (default) binary protocol will be used
+        compact - compact protocol will be used
+        json - json protocol will be used
+        
+    -mc (multiple clients):
+        <numClients> - number of multiple clients to connect to server (max 100, default 1)
+
+Sample:
+
+    Client.exe -tr:tcp -pr:binary -mc:10
+
+Remarks:
+
+    For TcpTls mode certificate's file ThriftTest.pfx should be in directory 
+	with binaries in case of command line usage (or at project level in case of debugging from IDE).
+    Password for certificate - "ThriftTest".
+
+# How to test communication between NetCore and Python
+
+* Generate code with the latest **thrift.exe** util
+* Ensure that **thrift.exe** util generated folder **gen-py** with generated code for Python
+* Create **client.py** and **server.py** from the code examples below and save them to the folder with previosly generated folder **gen-py**
+* Run netcore samples (client and server) and python samples (client and server)
+
+Remarks:
+
+Samples of client and server code below use correct methods (operations) 
+and fields (properties) according to generated contracts from *.thrift files
+
+At Windows 10 add record **127.0.0.1 testserver** to **C:\Windows\System32\drivers\etc\hosts** file
+for correct work of python server
+
+
+**Python Client:**
+	
+```python
+import sys
+import glob
+sys.path.append('gen-py')
+
+from tutorial import Calculator
+from tutorial.ttypes import InvalidOperation, Operation, Work
+
+from thrift import Thrift
+from thrift.transport import TSocket
+from thrift.transport import TTransport
+from thrift.protocol import TBinaryProtocol
+
+
+def main():
+    # Make socket
+    transport = TSocket.TSocket('127.0.0.1', 9090)
+
+    # Buffering is critical. Raw sockets are very slow
+    transport = TTransport.TBufferedTransport(transport)
+
+    # Wrap in a protocol
+    protocol = TBinaryProtocol.TBinaryProtocol(transport)
+
+    # Create a client to use the protocol encoder
+    client = Calculator.Client(protocol)
+
+    # Connect!
+    transport.open()
+
+    client.Ping()
+    print('ping()')
+
+    sum = client.Add(1, 1)
+    print(('1+1=%d' % (sum)))
+
+    work = Work()
+
+    work.Op = Operation.Divide
+    work.Num1 = 1
+    work.Num2 = 0
+
+    try:
+        quotient = client.Calculate(1, work)
+        print('Whoa? You know how to divide by zero?')
+        print('FYI the answer is %d' % quotient)
+    except InvalidOperation as e:
+        print(('InvalidOperation: %r' % e))
+
+    work.Op = Operation.Substract
+    work.Num1 = 15
+    work.Num2 = 10
+
+    diff = client.Calculate(1, work)
+    print(('15-10=%d' % (diff)))
+
+    log = client.GetStruct(1)
+    print(('Check log: %s' % (log.Value)))
+
+    client.Zip()
+    print('zip()')
+
+    # Close!
+    transport.close()
+
+if __name__ == '__main__':
+  try:
+    main()
+  except Thrift.TException as tx:
+    print('%s' % tx.message)
+```
+
+
+**Python Server:**
+
+
+```python
+import glob
+import sys
+sys.path.append('gen-py')
+
+from tutorial import Calculator
+from tutorial.ttypes import InvalidOperation, Operation
+
+from shared.ttypes import SharedStruct
+
+from thrift.transport import TSocket
+from thrift.transport import TTransport
+from thrift.protocol import TBinaryProtocol
+from thrift.server import TServer
+
+
+class CalculatorHandler:
+    def __init__(self):
+        self.log = {}
+
+    def Ping(self):
+        print('ping()')
+
+    def Add(self, n1, n2):
+        print('add(%d,%d)' % (n1, n2))
+        return n1 + n2
+
+    def Calculate(self, logid, work):
+        print('calculate(%d, %r)' % (logid, work))
+
+        if work.Op == Operation.Add:
+            val = work.Num1 + work.Num2
+        elif work.Op == Operation.Substract:
+            val = work.Num1 - work.Num2
+        elif work.Op == Operation.Multiply:
+            val = work.Num1 * work.Num2
+        elif work.Op == Operation.Divide:
+            if work.Num2 == 0:
+                x = InvalidOperation()
+                x.WhatOp = work.Op
+                x.Why = 'Cannot divide by 0'
+                raise x
+            val = work.Num1 / work.Num2
+        else:
+            x = InvalidOperation()
+            x.WhatOp = work.Op
+            x.Why = 'Invalid operation'
+            raise x
+
+        log = SharedStruct()
+        log.Key = logid
+        log.Value = '%d' % (val)
+        self.log[logid] = log
+
+        return val
+
+    def GetStruct(self, key):
+        print('getStruct(%d)' % (key))
+        return self.log[key]
+
+    def Zip(self):
+        print('zip()')
+
+if __name__ == '__main__':
+    handler = CalculatorHandler()
+    processor = Calculator.Processor(handler)
+    transport = TSocket.TServerSocket(host="testserver", port=9090)
+    tfactory = TTransport.TBufferedTransportFactory()
+    pfactory = TBinaryProtocol.TBinaryProtocolFactory()
+
+    server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)
+    print('Starting the server...')
+    server.serve()
+    print('done.')
+
+    # You could do one of these for a multithreaded server
+    # server = TServer.TThreadedServer(processor, transport, tfactory, pfactory)
+    # server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory)
+```
diff --git a/tutorial/netcore/Server/Program.cs b/tutorial/netcore/Server/Program.cs
new file mode 100644
index 0000000..6a181ba
--- /dev/null
+++ b/tutorial/netcore/Server/Program.cs
@@ -0,0 +1,428 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Security;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Thrift;
+using Thrift.Protocols;
+using Thrift.Server;
+using Thrift.Transports;
+using Thrift.Transports.Server;
+using tutorial;
+using shared;
+
+namespace Server
+{
+    public class Program
+    {
+        private static readonly ILogger Logger = new LoggerFactory().AddConsole(LogLevel.Trace).AddDebug(LogLevel.Trace).CreateLogger(nameof(Server));
+
+        public static void Main(string[] args)
+        {
+            args = args ?? new string[0];
+
+            if (args.Any(x => x.StartsWith("-help", StringComparison.OrdinalIgnoreCase)))
+            {
+                DisplayHelp();
+                return;
+            }
+
+            using (var source = new CancellationTokenSource())
+            {
+                RunAsync(args, source.Token).GetAwaiter().GetResult();
+
+                Logger.LogInformation("Press any key to stop...");
+
+                Console.ReadLine();
+                source.Cancel();
+            }
+
+            Logger.LogInformation("Server stopped");
+        }
+
+        private static void DisplayHelp()
+        {
+            Logger.LogInformation(@"
+Usage: 
+    Server.exe -help
+        will diplay help information 
+
+    Server.exe -tr:<transport> -pr:<protocol>
+        will run server with specified arguments (tcp transport and binary protocol by default)
+
+Options:
+    -tr (transport): 
+        tcp - (default) tcp transport will be used (host - ""localhost"", port - 9090)
+        tcpbuffered - tcp buffered transport will be used (host - ""localhost"", port - 9090)
+        namedpipe - namedpipe transport will be used (pipe address - "".test"")
+        http - http transport will be used (http address - ""localhost:9090"")
+        tcptls - tcp transport with tls will be used (host - ""localhost"", port - 9090)
+        framed - tcp framed transport will be used (host - ""localhost"", port - 9090)
+
+    -pr (protocol): 
+        binary - (default) binary protocol will be used
+        compact - compact protocol will be used
+        json - json protocol will be used
+        multiplexed - multiplexed protocol will be used
+
+Sample:
+    Server.exe -tr:tcp 
+");
+        }
+
+        private static async Task RunAsync(string[] args, CancellationToken cancellationToken)
+        {
+            var selectedTransport = GetTransport(args);
+            var selectedProtocol = GetProtocol(args);
+
+            if (selectedTransport == Transport.Http)
+            {
+                new HttpServerSample().Run(cancellationToken);
+            }
+            else
+            {
+                await RunSelectedConfigurationAsync(selectedTransport, selectedProtocol, cancellationToken);
+            }
+        }
+
+        private static Protocol GetProtocol(string[] args)
+        {
+            var transport = args.FirstOrDefault(x => x.StartsWith("-pr"))?.Split(':')?[1];
+
+            Enum.TryParse(transport, true, out Protocol selectedProtocol);
+
+            return selectedProtocol;
+        }
+
+        private static Transport GetTransport(string[] args)
+        {
+            var transport = args.FirstOrDefault(x => x.StartsWith("-tr"))?.Split(':')?[1];
+
+            Enum.TryParse(transport, true, out Transport selectedTransport);
+
+            return selectedTransport;
+        }
+
+        private static async Task RunSelectedConfigurationAsync(Transport transport, Protocol protocol, CancellationToken cancellationToken)
+        {
+            var fabric = new LoggerFactory().AddConsole(LogLevel.Trace).AddDebug(LogLevel.Trace);
+            var handler = new CalculatorAsyncHandler();
+            ITAsyncProcessor processor = null;
+
+            TServerTransport serverTransport = null;
+
+            switch (transport)
+            {
+                case Transport.Tcp:
+                    serverTransport = new TServerSocketTransport(9090);
+                    break;
+                case Transport.TcpBuffered:
+                    serverTransport = new TServerSocketTransport(port: 9090, clientTimeout: 10000, useBufferedSockets: true);
+                    break;
+                case Transport.NamedPipe:
+                    serverTransport = new TNamedPipeServerTransport(".test");
+                    break;
+                case Transport.TcpTls:
+                    serverTransport = new TTlsServerSocketTransport(9090, false, GetCertificate(), ClientCertValidator, LocalCertificateSelectionCallback);
+                    break;
+                case Transport.Framed:
+                    serverTransport = new TServerFramedTransport(9090);
+                    break;
+            }
+
+            ITProtocolFactory inputProtocolFactory;
+            ITProtocolFactory outputProtocolFactory;
+
+            switch (protocol)
+            {
+                case Protocol.Binary:
+                {
+                    inputProtocolFactory = new TBinaryProtocol.Factory();
+                    outputProtocolFactory = new TBinaryProtocol.Factory();
+                    processor = new Calculator.AsyncProcessor(handler);
+                }
+                    break;
+                case Protocol.Compact:
+                {
+                    inputProtocolFactory = new TCompactProtocol.Factory();
+                    outputProtocolFactory = new TCompactProtocol.Factory();
+                    processor = new Calculator.AsyncProcessor(handler);
+                }
+                    break;
+                case Protocol.Json:
+                {
+                    inputProtocolFactory = new TJsonProtocol.Factory();
+                    outputProtocolFactory = new TJsonProtocol.Factory();
+                    processor = new Calculator.AsyncProcessor(handler);
+                }
+                    break;
+                case Protocol.Multiplexed:
+                {
+                    inputProtocolFactory = new TBinaryProtocol.Factory();
+                    outputProtocolFactory = new TBinaryProtocol.Factory();
+
+                    var calcHandler = new CalculatorAsyncHandler();
+                    var calcProcessor = new Calculator.AsyncProcessor(calcHandler);
+
+                    var sharedServiceHandler = new SharedServiceAsyncHandler();
+                    var sharedServiceProcessor = new SharedService.AsyncProcessor(sharedServiceHandler);
+
+                    var multiplexedProcessor = new TMultiplexedProcessor();
+                    multiplexedProcessor.RegisterProcessor(nameof(Calculator), calcProcessor);
+                    multiplexedProcessor.RegisterProcessor(nameof(SharedService), sharedServiceProcessor);
+
+                    processor = multiplexedProcessor;
+                }
+                    break;
+                default:
+                    throw new ArgumentOutOfRangeException(nameof(protocol), protocol, null);
+            }
+
+            try
+            {
+                Logger.LogInformation(
+                    $"Selected TAsyncServer with {serverTransport} transport, {processor} processor and {inputProtocolFactory} protocol factories");
+
+                var server = new AsyncBaseServer(processor, serverTransport, inputProtocolFactory, outputProtocolFactory, fabric);
+
+                Logger.LogInformation("Starting the server...");
+                await server.ServeAsync(cancellationToken);
+            }
+            catch (Exception x)
+            {
+                Logger.LogInformation(x.ToString());
+            }
+        }
+
+        private static X509Certificate2 GetCertificate()
+        {
+            // due to files location in net core better to take certs from top folder
+            var certFile = GetCertPath(Directory.GetParent(Directory.GetCurrentDirectory()));
+            return new X509Certificate2(certFile, "ThriftTest");
+        }
+
+        private static string GetCertPath(DirectoryInfo di, int maxCount = 6)
+        {
+            var topDir = di;
+            var certFile =
+                topDir.EnumerateFiles("ThriftTest.pfx", SearchOption.AllDirectories)
+                    .FirstOrDefault();
+            if (certFile == null)
+            {
+                if (maxCount == 0)
+                    throw new FileNotFoundException("Cannot find file in directories");
+                return GetCertPath(di.Parent, maxCount - 1);
+            }
+
+            return certFile.FullName;
+        }
+
+        private static X509Certificate LocalCertificateSelectionCallback(object sender,
+            string targetHost, X509CertificateCollection localCertificates,
+            X509Certificate remoteCertificate, string[] acceptableIssuers)
+        {
+            return GetCertificate();
+        }
+
+        private static bool ClientCertValidator(object sender, X509Certificate certificate,
+            X509Chain chain, SslPolicyErrors sslPolicyErrors)
+        {
+            return true;
+        }
+
+        private enum Transport
+        {
+            Tcp,
+            TcpBuffered,
+            NamedPipe,
+            Http,
+            TcpTls,
+            Framed
+        }
+
+        private enum Protocol
+        {
+            Binary,
+            Compact,
+            Json,
+            Multiplexed
+        }
+
+        public class HttpServerSample
+        {
+            public void Run(CancellationToken cancellationToken)
+            {
+                var config = new ConfigurationBuilder()
+                    .AddEnvironmentVariables(prefix: "ASPNETCORE_")
+                    .Build();
+
+                var host = new WebHostBuilder()
+                    .UseConfiguration(config)
+                    .UseKestrel()
+                    .UseUrls("http://localhost:9090")
+                    .UseContentRoot(Directory.GetCurrentDirectory())
+                    .UseStartup<Startup>()
+                    .Build();
+
+                host.RunAsync(cancellationToken).GetAwaiter().GetResult();
+            }
+
+            public class Startup
+            {
+                public Startup(IHostingEnvironment env)
+                {
+                    var builder = new ConfigurationBuilder()
+                        .SetBasePath(env.ContentRootPath)
+                        .AddEnvironmentVariables();
+
+                    Configuration = builder.Build();
+                }
+
+                public IConfigurationRoot Configuration { get; }
+
+                // This method gets called by the runtime. Use this method to add services to the container.
+                public void ConfigureServices(IServiceCollection services)
+                {
+                    services.AddTransient<Calculator.IAsync, CalculatorAsyncHandler>();
+                    services.AddTransient<ITAsyncProcessor, Calculator.AsyncProcessor>();
+                    services.AddTransient<THttpServerTransport, THttpServerTransport>();
+                }
+
+                // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+                public void Configure(IApplicationBuilder app, IHostingEnvironment env,
+                    ILoggerFactory loggerFactory)
+                {
+                    app.UseMiddleware<THttpServerTransport>();
+                }
+            }
+        }
+
+        public class CalculatorAsyncHandler : Calculator.IAsync
+        {
+            private readonly Dictionary<int, SharedStruct> _log = new Dictionary<int, SharedStruct>();
+
+            public CalculatorAsyncHandler()
+            {
+            }
+
+            public async Task<SharedStruct> getStructAsync(int key,
+                CancellationToken cancellationToken)
+            {
+                Logger.LogInformation("GetStructAsync({0})", key);
+                return await Task.FromResult(_log[key]);
+            }
+
+            public async Task pingAsync(CancellationToken cancellationToken)
+            {
+                Logger.LogInformation("PingAsync()");
+                await Task.CompletedTask;
+            }
+
+            public async Task<int> addAsync(int num1, int num2, CancellationToken cancellationToken)
+            {
+                Logger.LogInformation($"AddAsync({num1},{num2})");
+                return await Task.FromResult(num1 + num2);
+            }
+
+            public async Task<int> calculateAsync(int logid, Work w, CancellationToken cancellationToken)
+            {
+                Logger.LogInformation($"CalculateAsync({logid}, [{w.Op},{w.Num1},{w.Num2}])");
+
+                var val = 0;
+                switch (w.Op)
+                {
+                    case Operation.ADD:
+                        val = w.Num1 + w.Num2;
+                        break;
+
+                    case Operation.SUBTRACT:
+                        val = w.Num1 - w.Num2;
+                        break;
+
+                    case Operation.MULTIPLY:
+                        val = w.Num1 * w.Num2;
+                        break;
+
+                    case Operation.DIVIDE:
+                        if (w.Num2 == 0)
+                        {
+                            var io = new InvalidOperation
+                            {
+                                WhatOp = (int) w.Op,
+                                Why = "Cannot divide by 0"
+                            };
+
+                            throw io;
+                        }
+                        val = w.Num1 / w.Num2;
+                        break;
+
+                    default:
+                    {
+                        var io = new InvalidOperation
+                        {
+                            WhatOp = (int) w.Op,
+                            Why = "Unknown operation"
+                        };
+
+                        throw io;
+                    }
+                }
+
+                var entry = new SharedStruct
+                {
+                    Key = logid,
+                    Value = val.ToString()
+                };
+
+                _log[logid] = entry;
+
+                return await Task.FromResult(val);
+            }
+
+            public async Task zipAsync(CancellationToken cancellationToken)
+            {
+                Logger.LogInformation("ZipAsync() with delay 100mc");
+                await Task.Delay(100, CancellationToken.None);
+            }
+        }
+
+        public class SharedServiceAsyncHandler : SharedService.IAsync
+        {
+            public async Task<SharedStruct> getStructAsync(int key, CancellationToken cancellationToken)
+            {
+                Logger.LogInformation("GetStructAsync({0})", key);
+                return await Task.FromResult(new SharedStruct()
+                {
+                    Key = key,
+                    Value = "GetStructAsync"
+                });
+            }
+        }
+    }
+}
diff --git a/tutorial/netcore/Server/Properties/AssemblyInfo.cs b/tutorial/netcore/Server/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..a044235
--- /dev/null
+++ b/tutorial/netcore/Server/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Apache Software Foundation")]
+[assembly: AssemblyProduct("Thrift")]
+[assembly: AssemblyCopyright("The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+
+[assembly: Guid("e210fc10-5aff-4b04-ac21-58afc7b74b0c")]
\ No newline at end of file
diff --git a/tutorial/netcore/Server/Properties/launchSettings.json b/tutorial/netcore/Server/Properties/launchSettings.json
new file mode 100644
index 0000000..78076ff
--- /dev/null
+++ b/tutorial/netcore/Server/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+  "profiles": {
+    "Server": {
+      "commandName": "Project",
+      "commandLineArgs": "-p:multiplexed"
+    }
+  }
+}
\ No newline at end of file
diff --git a/tutorial/netcore/Server/Server.csproj b/tutorial/netcore/Server/Server.csproj
new file mode 100644
index 0000000..0fbd303
--- /dev/null
+++ b/tutorial/netcore/Server/Server.csproj
@@ -0,0 +1,26 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.0</TargetFramework>
+    <AssemblyName>Server</AssemblyName>
+    <PackageId>Server</PackageId>
+    <OutputType>Exe</OutputType>
+    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
+    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
+    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
+    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="../Interfaces/Interfaces.csproj" />
+    <ProjectReference Include="../../../lib/netcore/Thrift/Thrift.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore" Version="[2.0,)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="[2.0,)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="[2.0,)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="[2.0,)" />
+  </ItemGroup>
+
+</Project>
diff --git a/tutorial/netcore/Server/ThriftTest.pfx b/tutorial/netcore/Server/ThriftTest.pfx
new file mode 100644
index 0000000..f0ded28
--- /dev/null
+++ b/tutorial/netcore/Server/ThriftTest.pfx
Binary files differ
diff --git a/tutorial/netcore/Tutorial.sln b/tutorial/netcore/Tutorial.sln
new file mode 100644
index 0000000..2ddcd46
--- /dev/null
+++ b/tutorial/netcore/Tutorial.sln
@@ -0,0 +1,78 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26114.2
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift", "..\..\lib\netcore\Thrift\Thrift.csproj", "{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Interfaces", "Interfaces\Interfaces.csproj", "{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x64.Build.0 = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Debug|x86.Build.0 = Debug|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x64.ActiveCfg = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x64.Build.0 = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x86.ActiveCfg = Release|Any CPU
+		{C20EA2A9-7660-47DE-9A49-D1EF12FB2895}.Release|x86.Build.0 = Release|Any CPU
+		{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|x64.Build.0 = Debug|Any CPU
+		{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Debug|x86.Build.0 = Debug|Any CPU
+		{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|x64.ActiveCfg = Release|Any CPU
+		{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|x64.Build.0 = Release|Any CPU
+		{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|x86.ActiveCfg = Release|Any CPU
+		{B9E24D84-2712-4158-8F1A-DDE44CD1BB0A}.Release|x86.Build.0 = Release|Any CPU
+		{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|x64.Build.0 = Debug|Any CPU
+		{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Debug|x86.Build.0 = Debug|Any CPU
+		{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|x64.ActiveCfg = Release|Any CPU
+		{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|x64.Build.0 = Release|Any CPU
+		{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|x86.ActiveCfg = Release|Any CPU
+		{E4CA1EF0-B181-4A5D-A02C-DB0750A59CDF}.Release|x86.Build.0 = Release|Any CPU
+		{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|x64.Build.0 = Debug|Any CPU
+		{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Debug|x86.Build.0 = Debug|Any CPU
+		{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|x64.ActiveCfg = Release|Any CPU
+		{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|x64.Build.0 = Release|Any CPU
+		{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|x86.ActiveCfg = Release|Any CPU
+		{E08F5B84-2B4A-4E09-82D1-E0715775CE5E}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {070A5D1D-B29D-4603-999D-693DB444AD0D}
+	EndGlobalSection
+EndGlobal
diff --git a/tutorial/netcore/build.cmd b/tutorial/netcore/build.cmd
new file mode 100644
index 0000000..9b84ef2
--- /dev/null
+++ b/tutorial/netcore/build.cmd
@@ -0,0 +1,25 @@
+@echo off
+rem /*
+rem  * Licensed to the Apache Software Foundation (ASF) under one
+rem  * or more contributor license agreements. See the NOTICE file
+rem  * distributed with this work for additional information
+rem  * regarding copyright ownership. The ASF licenses this file
+rem  * to you under the Apache License, Version 2.0 (the
+rem  * "License"); you may not use this file except in compliance
+rem  * with the License. You may obtain a copy of the License at
+rem  *
+rem  *   http://www.apache.org/licenses/LICENSE-2.0
+rem  *
+rem  * Unless required by applicable law or agreed to in writing,
+rem  * software distributed under the License is distributed on an
+rem  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem  * KIND, either express or implied. See the License for the
+rem  * specific language governing permissions and limitations
+rem  * under the License.
+rem  */
+setlocal
+
+dotnet --info
+dotnet build
+
+:eof
diff --git a/tutorial/netcore/build.sh b/tutorial/netcore/build.sh
new file mode 100755
index 0000000..c97e310
--- /dev/null
+++ b/tutorial/netcore/build.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+#
+# 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.
+#
+
+#exit if any command fails
+set -e
+
+dotnet --info
+dotnet build
diff --git a/tutorial/nodejs/Makefile.am b/tutorial/nodejs/Makefile.am
new file mode 100644
index 0000000..1516fec
--- /dev/null
+++ b/tutorial/nodejs/Makefile.am
@@ -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.
+#
+
+gen-nodejs/Calculator.js gen-nodejs/SharedService.js: $(top_srcdir)/tutorial/tutorial.thrift
+	$(THRIFT) --gen js:node -r $<
+
+all-local: gen-nodejs/Calculator.js
+
+tutorialserver: all
+	NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeServer.js
+
+tutorialclient: all
+	NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeClient.js
+
+tutorialserver_promise: all
+	NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeServerPromise.js
+
+tutorialclient_promise: all
+	NODE_PATH="$(top_builddir)/lib/nodejs:$(top_builddir)/lib/nodejs/lib:$(NODEPATH)" $(NODEJS) NodeClientPromise.js
+
+
+clean-local:
+	$(RM) -r gen-*
+
+EXTRA_DIST = \
+	NodeServer.js \
+	NodeClient.js \
+	NodeServerPromise.js \
+	NodeClientPromise.js
diff --git a/tutorial/nodejs/NodeClient.js b/tutorial/nodejs/NodeClient.js
new file mode 100644
index 0000000..b4886e8
--- /dev/null
+++ b/tutorial/nodejs/NodeClient.js
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var thrift = require('thrift');
+var Calculator = require('./gen-nodejs/Calculator');
+var ttypes = require('./gen-nodejs/tutorial_types');
+const assert = require('assert');
+
+var transport = thrift.TBufferedTransport;
+var protocol = thrift.TBinaryProtocol;
+
+var connection = thrift.createConnection("localhost", 9090, {
+  transport : transport,
+  protocol : protocol
+});
+
+connection.on('error', function(err) {
+  assert(false, err);
+});
+
+// Create a Calculator client with the connection
+var client = thrift.createClient(Calculator, connection);
+
+
+client.ping(function(err, response) {
+  console.log('ping()');
+});
+
+
+client.add(1,1, function(err, response) {
+  console.log("1+1=" + response);
+});
+
+
+work = new ttypes.Work();
+work.op = ttypes.Operation.DIVIDE;
+work.num1 = 1;
+work.num2 = 0;
+
+client.calculate(1, work, function(err, message) {
+  if (err) {
+    console.log("InvalidOperation " + err);
+  } else {
+    console.log('Whoa? You know how to divide by zero?');
+  }
+});
+
+work.op = ttypes.Operation.SUBTRACT;
+work.num1 = 15;
+work.num2 = 10;
+
+client.calculate(1, work, function(err, message) {
+  console.log('15-10=' + message);
+
+  client.getStruct(1, function(err, message){
+    console.log('Check log: ' + message.value);
+
+    //close the connection once we're done
+    connection.end();
+  });
+});
diff --git a/tutorial/nodejs/NodeClientPromise.js b/tutorial/nodejs/NodeClientPromise.js
new file mode 100644
index 0000000..2cdc184
--- /dev/null
+++ b/tutorial/nodejs/NodeClientPromise.js
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var thrift = require('thrift');
+var Calculator = require('./gen-nodejs/Calculator');
+var ttypes = require('./gen-nodejs/tutorial_types');
+const assert = require('assert');
+
+var transport = thrift.TBufferedTransport;
+var protocol = thrift.TBinaryProtocol;
+
+var connection = thrift.createConnection("localhost", 9090, {
+  transport : transport,
+  protocol : protocol
+});
+
+connection.on('error', function(err) {
+  assert(false, err);
+});
+
+// Create a Calculator client with the connection
+var client = thrift.createClient(Calculator, connection);
+
+
+client.ping()
+  .then(function() {
+    console.log('ping()');
+  });
+
+client.add(1,1)
+  .then(function(response) {
+	  console.log("1+1=" + response);
+  });
+
+work = new ttypes.Work();
+work.op = ttypes.Operation.DIVIDE;
+work.num1 = 1;
+work.num2 = 0;
+
+client.calculate(1, work)
+  .then(function(message) {
+	console.log('Whoa? You know how to divide by zero?');
+  })
+  .fail(function(err) {
+    console.log("InvalidOperation " + err);
+  });
+
+
+work.op = ttypes.Operation.SUBTRACT;
+work.num1 = 15;
+work.num2 = 10;
+
+client.calculate(1, work)
+  .then(function(value) {
+	  console.log('15-10=' + value);
+	  return client.getStruct(1);
+  })
+  .then(function(message) {
+      console.log('Check log: ' + message.value);
+  })
+  .fin(function() {
+	  //close the connection once we're done
+      connection.end();
+  });
diff --git a/tutorial/nodejs/NodeServer.js b/tutorial/nodejs/NodeServer.js
new file mode 100644
index 0000000..55d3817
--- /dev/null
+++ b/tutorial/nodejs/NodeServer.js
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var thrift = require("thrift");
+var Calculator = require("./gen-nodejs/Calculator");
+var ttypes = require("./gen-nodejs/tutorial_types");
+var SharedStruct = require("./gen-nodejs/shared_types").SharedStruct;
+
+var data = {};
+
+var server = thrift.createServer(Calculator, {
+  ping: function(result) {
+    console.log("ping()");
+    result(null);
+  },
+
+  add: function(n1, n2, result) {
+    console.log("add(", n1, ",", n2, ")");
+    result(null, n1 + n2);
+  },
+
+  calculate: function(logid, work, result) {
+    console.log("calculate(", logid, ",", work, ")");
+
+    var val = 0;
+    if (work.op == ttypes.Operation.ADD) {
+      val = work.num1 + work.num2;
+    } else if (work.op === ttypes.Operation.SUBTRACT) {
+      val = work.num1 - work.num2;
+    } else if (work.op === ttypes.Operation.MULTIPLY) {
+      val = work.num1 * work.num2;
+    } else if (work.op === ttypes.Operation.DIVIDE) {
+      if (work.num2 === 0) {
+        var x = new ttypes.InvalidOperation();
+        x.whatOp = work.op;
+        x.why = 'Cannot divide by 0';
+        result(x);
+        return;
+      }
+      val = work.num1 / work.num2;
+    } else {
+      var x = new ttypes.InvalidOperation();
+      x.whatOp = work.op;
+      x.why = 'Invalid operation';
+      result(x);
+      return;
+    }
+
+    var entry = new SharedStruct();
+    entry.key = logid;
+    entry.value = ""+val;
+    data[logid] = entry;
+
+    result(null, val);
+  },
+
+  getStruct: function(key, result) {
+    console.log("getStruct(", key, ")");
+    result(null, data[key]);
+  },
+
+  zip: function() {
+    console.log("zip()");
+    result(null);
+  }
+
+});
+
+server.listen(9090);
diff --git a/tutorial/nodejs/NodeServerPromise.js b/tutorial/nodejs/NodeServerPromise.js
new file mode 100644
index 0000000..bff287b
--- /dev/null
+++ b/tutorial/nodejs/NodeServerPromise.js
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var thrift = require("thrift");
+var Calculator = require("./gen-nodejs/Calculator");
+var ttypes = require("./gen-nodejs/tutorial_types");
+var SharedStruct = require("./gen-nodejs/shared_types").SharedStruct;
+
+var data = {};
+
+var server = thrift.createServer(Calculator, {
+  ping: function() {
+    console.log("ping()");
+  },
+
+  add: function(n1, n2) {
+    console.log("add(", n1, ",", n2, ")");
+    return n1 + n2;
+  },
+
+  calculate: function(logid, work) {
+    console.log("calculate(", logid, ",", work, ")");
+
+    var val = 0;
+    if (work.op == ttypes.Operation.ADD) {
+      val = work.num1 + work.num2;
+    } else if (work.op === ttypes.Operation.SUBTRACT) {
+      val = work.num1 - work.num2;
+    } else if (work.op === ttypes.Operation.MULTIPLY) {
+      val = work.num1 * work.num2;
+    } else if (work.op === ttypes.Operation.DIVIDE) {
+      if (work.num2 === 0) {
+        var x = new ttypes.InvalidOperation();
+        x.whatOp = work.op;
+        x.why = 'Cannot divide by 0';
+		throw x;
+      }
+      val = work.num1 / work.num2;
+    } else {
+      var x = new ttypes.InvalidOperation();
+      x.whatOp = work.op;
+      x.why = 'Invalid operation';
+      throw x;
+    }
+
+    var entry = new SharedStruct();
+    entry.key = logid;
+    entry.value = ""+val;
+    data[logid] = entry;
+    return val;
+  },
+
+  getStruct: function(key) {
+    console.log("getStruct(", key, ")");
+    return data[key];
+  },
+
+  zip: function() {
+    console.log("zip()");
+  }
+
+});
+
+server.listen(9090);
diff --git a/tutorial/ocaml/CalcServer.ml b/tutorial/ocaml/CalcServer.ml
index 24d7d03..b5facb7 100755
--- a/tutorial/ocaml/CalcServer.ml
+++ b/tutorial/ocaml/CalcServer.ml
@@ -49,7 +49,7 @@
 	| Operation.DIVIDE ->
 	    if w#grab_num2 = Int32.zero then
 	      let io = new invalidOperation in
-		io#set_what (Operation.to_i w#grab_op) ;
+		io#set_whatOp (Operation.to_i w#grab_op) ;
 		io#set_why "Cannot divide by 0" ;
 		raise (InvalidOperation io)
 	    else
diff --git a/tutorial/ocaml/README b/tutorial/ocaml/README.md
similarity index 100%
rename from tutorial/ocaml/README
rename to tutorial/ocaml/README.md
diff --git a/tutorial/ocaml/_oasis b/tutorial/ocaml/_oasis
index 4cab080..745c096 100644
--- a/tutorial/ocaml/_oasis
+++ b/tutorial/ocaml/_oasis
@@ -1,5 +1,5 @@
 Name: tutorial
-Version: 1.0
+Version: 1.0.0
 OASISFormat: 0.3
 Synopsis: OCaml Tutorial example
 Authors: Apache Thrift Developers <dev@thrift.apache.org>
diff --git a/tutorial/perl/PerlClient.pl b/tutorial/perl/PerlClient.pl
index 1d59656..7c23289 100644
--- a/tutorial/perl/PerlClient.pl
+++ b/tutorial/perl/PerlClient.pl
@@ -37,10 +37,10 @@
 
 use Data::Dumper;
 
-my $socket    = new Thrift::Socket('localhost',9090);
-my $transport = new Thrift::BufferedTransport($socket,1024,1024);
-my $protocol  = new Thrift::BinaryProtocol($transport);
-my $client    = new tutorial::CalculatorClient($protocol);
+my $socket    = Thrift::Socket->new('localhost',9090);
+my $transport = Thrift::BufferedTransport->new($socket,1024,1024);
+my $protocol  = Thrift::BinaryProtocol->new($transport);
+my $client    = tutorial::CalculatorClient->new($protocol);
 
 
 eval{
@@ -53,7 +53,7 @@
     my $sum = $client->add(1,1);
     print "1+1=$sum\n";
 
-    my $work = new tutorial::Work();
+    my $work = tutorial::Work->new();
 
     $work->op(tutorial::Operation::DIVIDE);
     $work->num1(1);
@@ -63,7 +63,7 @@
         $client->calculate(1, $work);
         print "Whoa! We can divide by zero?\n";
     }; if($@) {
-        warn "InvalidOperation: ".Dumper($@);
+        warn 'InvalidOperation: '.Dumper($@);
     }
 
     $work->op(tutorial::Operation::SUBTRACT);
diff --git a/tutorial/perl/PerlServer.pl b/tutorial/perl/PerlServer.pl
index a40ec69..dfe6b89 100644
--- a/tutorial/perl/PerlServer.pl
+++ b/tutorial/perl/PerlServer.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/bin/env perl
 
 #
 # Licensed to the Apache Software Foundation (ASF) under one
@@ -67,20 +67,20 @@
   } elsif ($op == tutorial::Operation::DIVIDE) {
     if ($num2 == 0)
     {
-      my $x = new tutorial::InvalidOperation;
-      $x->what($op);
+      my $x = tutorial::InvalidOperation->new();
+      $x->whatOp($op);
       $x->why('Cannot divide by 0');
       die $x;
     }
     $val = $num1 / $num2;
   } else {
-    my $x = new tutorial::InvalidOperation;
-    $x->what($op);
+    my $x = tutorial::InvalidOperation->new();
+    $x->whatOp($op);
     $x->why('Invalid operation');
     die $x;
   }
 
-  my $log = new shared::SharedStruct;
+  my $log = shared::SharedStruct->new();
   $log->key($logid);
   $log->value(int($val));
   $self->{log}->{$logid} = $log;
@@ -104,10 +104,10 @@
 
 
 eval {
-  my $handler       = new CalculatorHandler;
-  my $processor     = new tutorial::CalculatorProcessor($handler);
-  my $serversocket  = new Thrift::ServerSocket(9090);
-  my $forkingserver = new Thrift::ForkingServer($processor, $serversocket);
+  my $handler       = CalculatorHandler->new();
+  my $processor     = tutorial::CalculatorProcessor->new($handler);
+  my $serversocket  = Thrift::ServerSocket->new(9090);
+  my $forkingserver = Thrift::ForkingServer->new($processor, $serversocket);
   print "Starting the server...\n";
   $forkingserver->serve();
   print "done.\n";
diff --git a/tutorial/php/PhpClient.php b/tutorial/php/PhpClient.php
index d262b8f..92dc3cb 100755
--- a/tutorial/php/PhpClient.php
+++ b/tutorial/php/PhpClient.php
@@ -5,7 +5,7 @@
 
 error_reporting(E_ALL);
 
-require_once __DIR__.'/../../lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php';
+require_once __DIR__.'/../../lib/php/lib/ClassLoader/ThriftClassLoader.php';
 
 use Thrift\ClassLoader\ThriftClassLoader;
 
diff --git a/tutorial/php/PhpServer.php b/tutorial/php/PhpServer.php
index 4af70a4..5a9b49b 100755
--- a/tutorial/php/PhpServer.php
+++ b/tutorial/php/PhpServer.php
@@ -5,7 +5,7 @@
 
 error_reporting(E_ALL);
 
-require_once __DIR__.'/../../lib/php/lib/Thrift/ClassLoader/ThriftClassLoader.php';
+require_once __DIR__.'/../../lib/php/lib/ClassLoader/ThriftClassLoader.php';
 
 use Thrift\ClassLoader\ThriftClassLoader;
 
@@ -79,7 +79,7 @@
       case \tutorial\Operation::DIVIDE:
         if ($w->num2 == 0) {
           $io = new \tutorial\InvalidOperation();
-          $io->what = $w->op;
+          $io->whatOp = $w->op;
           $io->why = "Cannot divide by 0";
           throw $io;
         }
@@ -87,7 +87,7 @@
         break;
       default:
         $io = new \tutorial\InvalidOperation();
-        $io->what = $w->op;
+        $io->whatOp = $w->op;
         $io->why = "Invalid Operation";
         throw $io;
     }
diff --git a/tutorial/php/runserver.py b/tutorial/php/runserver.py
index ae29fed..077daa1 100755
--- a/tutorial/php/runserver.py
+++ b/tutorial/php/runserver.py
@@ -26,7 +26,8 @@
 # chdir(2) into the tutorial directory.
 os.chdir(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
 
+
 class Handler(CGIHTTPServer.CGIHTTPRequestHandler):
-  cgi_directories  = ['/php']
+    cgi_directories = ['/php']
 
 BaseHTTPServer.HTTPServer(('', 8080), Handler).serve_forever()
diff --git a/tutorial/py.tornado/Makefile.am b/tutorial/py.tornado/Makefile.am
index 6ac6023..4b73c1e 100755
--- a/tutorial/py.tornado/Makefile.am
+++ b/tutorial/py.tornado/Makefile.am
@@ -17,8 +17,6 @@
 # under the License.
 #
 
-THRIFT = $(top_builddir)/compiler/cpp/thrift
-
 gen-py.tornado/tutorial/Calculator.py gen-py.tornado/shared/SharedService.py: $(top_srcdir)/tutorial/tutorial.thrift
 	$(THRIFT) --gen py:tornado -r $<
 
diff --git a/tutorial/py.tornado/PythonClient.py b/tutorial/py.tornado/PythonClient.py
index 95d78b8..426146f 100755
--- a/tutorial/py.tornado/PythonClient.py
+++ b/tutorial/py.tornado/PythonClient.py
@@ -19,18 +19,17 @@
 # under the License.
 #
 
-import sys
 import glob
-sys.path.append('gen-py.tornado')
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
-
 import logging
+import sys
+
+sys.path.append('gen-py.tornado')
+sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0])
 
 from tutorial import Calculator
 from tutorial.ttypes import Operation, Work, InvalidOperation
 
 from thrift import TTornado
-from thrift.transport import TSocket
 from thrift.transport import TTransport
 from thrift.protocol import TBinaryProtocol
 
@@ -38,39 +37,38 @@
 from tornado import ioloop
 
 
-@gen.engine
-def communicate(callback=None):
+@gen.coroutine
+def communicate():
     # create client
     transport = TTornado.TTornadoStreamTransport('localhost', 9090)
+    # open the transport, bail on error
+    try:
+        yield transport.open()
+        print('Transport is opened')
+    except TTransport.TTransportException as ex:
+        logging.error(ex)
+        raise gen.Return()
+
     pfactory = TBinaryProtocol.TBinaryProtocolFactory()
     client = Calculator.Client(transport, pfactory)
 
-    # open the transport, bail on error
-    try:
-        yield gen.Task(transport.open)
-    except TTransport.TTransportException as ex:
-        logging.error(ex)
-        if callback:
-            callback()
-        return
-
     # ping
-    yield gen.Task(client.ping)
-    print "ping()"
+    yield client.ping()
+    print("ping()")
 
     # add
-    sum_ = yield gen.Task(client.add, 1, 1)
-    print "1 + 1 = {}".format(sum_)
+    sum_ = yield client.add(1, 1)
+    print("1 + 1 = {0}".format(sum_))
 
     # make a oneway call without a callback (schedule the write and continue
     # without blocking)
     client.zip()
-    print "zip() without callback"
+    print("zip() without callback")
 
     # make a oneway call with a callback (we'll wait for the stream write to
     # complete before continuing)
-    yield gen.Task(client.zip)
-    print "zip() with callback"
+    client.zip()
+    print("zip() with callback")
 
     # calculate 1/0
     work = Work()
@@ -79,37 +77,31 @@
     work.num2 = 0
 
     try:
-        quotient = yield gen.Task(client.calculate, 1, work)
-        print "Whoa? You know how to divide by zero?"
+        quotient = yield client.calculate(1, work)
+        print("Whoa? You know how to divide by zero ? -> {0}".format(quotient))
     except InvalidOperation as io:
-        print "InvalidOperation: {}".format(io)
+        print("InvalidOperation: {0}".format(io))
 
     # calculate 15-10
     work.op = Operation.SUBTRACT
     work.num1 = 15
     work.num2 = 10
 
-    diff = yield gen.Task(client.calculate, 1, work)
-    print "15 - 10 = {}".format(diff)
+    diff = yield client.calculate(1, work)
+    print("15 - 10 = {0}".format(diff))
 
     # getStruct
-    log = yield gen.Task(client.getStruct, 1)
-    print "Check log: {}".format(log.value)
+    log = yield client.getStruct(1)
+    print("Check log: {0}".format(log.value))
 
     # close the transport
     client._transport.close()
-
-    if callback:
-        callback()
+    raise gen.Return()
 
 
 def main():
     # create an ioloop, do the above, then stop
-    io_loop = ioloop.IOLoop.instance()
-    def this_joint():
-        communicate(callback=io_loop.stop)
-    io_loop.add_callback(this_joint)
-    io_loop.start()
+    ioloop.IOLoop.current().run_sync(communicate)
 
 
 if __name__ == "__main__":
diff --git a/tutorial/py.tornado/PythonServer.py b/tutorial/py.tornado/PythonServer.py
index 52932ff..e0229a2 100755
--- a/tutorial/py.tornado/PythonServer.py
+++ b/tutorial/py.tornado/PythonServer.py
@@ -19,10 +19,11 @@
 # under the License.
 #
 
-import sys
 import glob
+import sys
+
 sys.path.append('gen-py.tornado')
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0])
 
 from tutorial import Calculator
 from tutorial.ttypes import Operation, InvalidOperation
@@ -30,10 +31,7 @@
 from shared.ttypes import SharedStruct
 
 from thrift import TTornado
-from thrift.transport import TSocket
-from thrift.transport import TTransport
 from thrift.protocol import TBinaryProtocol
-from thrift.server import TServer
 
 from tornado import ioloop
 
@@ -42,16 +40,15 @@
     def __init__(self):
         self.log = {}
 
-    def ping(self, callback):
-        print "ping()"
-        callback()
+    def ping(self):
+        print("ping()")
 
-    def add(self, n1, n2, callback):
-        print "add({}, {})".format(n1, n2)
-        callback(n1 + n2)
+    def add(self, n1, n2):
+        print("add({}, {})".format(n1, n2))
+        return n1 + n2
 
-    def calculate(self, logid, work, callback):
-        print "calculate({}, {})".format(logid, work)
+    def calculate(self, logid, work):
+        print("calculate({}, {})".format(logid, work))
 
         if work.op == Operation.ADD:
             val = work.num1 + work.num2
@@ -62,13 +59,13 @@
         elif work.op == Operation.DIVIDE:
             if work.num2 == 0:
                 x = InvalidOperation()
-                x.what = work.op
+                x.whatOp = work.op
                 x.why = "Cannot divide by 0"
                 raise x
             val = work.num1 / work.num2
         else:
             x = InvalidOperation()
-            x.what = work.op
+            x.whatOp = work.op
             x.why = "Invalid operation"
             raise x
 
@@ -76,15 +73,14 @@
         log.key = logid
         log.value = '%d' % (val)
         self.log[logid] = log
-        callback(val)
+        return val
 
-    def getStruct(self, key, callback):
-        print "getStruct({})".format(key)
-        callback(self.log[key])
+    def getStruct(self, key):
+        print("getStruct({})".format(key))
+        return self.log[key]
 
-    def zip(self, callback):
-        print "zip()"
-        callback()
+    def zip(self):
+        print("zip()")
 
 
 def main():
@@ -93,11 +89,11 @@
     pfactory = TBinaryProtocol.TBinaryProtocolFactory()
     server = TTornado.TTornadoServer(processor, pfactory)
 
-    print "Starting the server..."
+    print("Starting the server...")
     server.bind(9090)
     server.start(1)
     ioloop.IOLoop.instance().start()
-    print "done."
+    print("done.")
 
 
 if __name__ == "__main__":
diff --git a/tutorial/py.twisted/Makefile.am b/tutorial/py.twisted/Makefile.am
index c6cbd45..50cd342 100755
--- a/tutorial/py.twisted/Makefile.am
+++ b/tutorial/py.twisted/Makefile.am
@@ -17,8 +17,6 @@
 # under the License.
 #
 
-THRIFT = $(top_builddir)/compiler/cpp/thrift
-
 gen-py/tutorial/Calculator.py gen-py/shared/SharedService.py: $(top_srcdir)/tutorial/tutorial.thrift
 	$(THRIFT) --gen py:twisted -r $<
 
diff --git a/tutorial/py.twisted/PythonClient.py b/tutorial/py.twisted/PythonClient.py
index 9e086f0..63dde7e 100755
--- a/tutorial/py.twisted/PythonClient.py
+++ b/tutorial/py.twisted/PythonClient.py
@@ -19,51 +19,53 @@
 # under the License.
 #
 
-import sys, glob
+import glob
+import sys
 sys.path.append('gen-py.twisted')
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0])
 
 from tutorial import Calculator
-from tutorial.ttypes import *
+from tutorial.ttypes import InvalidOperation, Operation, Work
 
 from twisted.internet.defer import inlineCallbacks
 from twisted.internet import reactor
 from twisted.internet.protocol import ClientCreator
 
-from thrift import Thrift
 from thrift.transport import TTwisted
 from thrift.protocol import TBinaryProtocol
 
+
 @inlineCallbacks
 def main(client):
-  yield client.ping()
-  print 'ping()'
+    yield client.ping()
+    print('ping()')
 
-  sum = yield client.add(1,1)
-  print '1+1=%d' % (sum)
+    sum = yield client.add(1, 1)
+    print(('1+1=%d' % (sum)))
 
-  work = Work()
+    work = Work()
 
-  work.op = Operation.DIVIDE
-  work.num1 = 1
-  work.num2 = 0
+    work.op = Operation.DIVIDE
+    work.num1 = 1
+    work.num2 = 0
 
-  try:
-    quotient = yield client.calculate(1, work)
-    print 'Whoa? You know how to divide by zero?'
-  except InvalidOperation, io:
-    print 'InvalidOperation: %r' % io
+    try:
+        quotient = yield client.calculate(1, work)
+        print('Whoa? You know how to divide by zero?')
+        print('FYI the answer is %d' % quotient)
+    except InvalidOperation as e:
+        print(('InvalidOperation: %r' % e))
 
-  work.op = Operation.SUBTRACT
-  work.num1 = 15
-  work.num2 = 10
+    work.op = Operation.SUBTRACT
+    work.num1 = 15
+    work.num2 = 10
 
-  diff = yield client.calculate(1, work)
-  print '15-10=%d' % (diff)
+    diff = yield client.calculate(1, work)
+    print(('15-10=%d' % (diff)))
 
-  log = yield client.getStruct(1)
-  print 'Check log: %s' % (log.value)
-  reactor.stop()
+    log = yield client.getStruct(1)
+    print(('Check log: %s' % (log.value)))
+    reactor.stop()
 
 if __name__ == '__main__':
     d = ClientCreator(reactor,
diff --git a/tutorial/py.twisted/PythonServer.py b/tutorial/py.twisted/PythonServer.py
index f023cac..1b0e2d5 100755
--- a/tutorial/py.twisted/PythonServer.py
+++ b/tutorial/py.twisted/PythonServer.py
@@ -19,12 +19,13 @@
 # under the License.
 #
 
-import sys, glob
+import glob
+import sys
 sys.path.append('gen-py.twisted')
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0])
 
 from tutorial import Calculator
-from tutorial.ttypes import *
+from tutorial.ttypes import InvalidOperation, Operation
 
 from shared.ttypes import SharedStruct
 
@@ -33,61 +34,63 @@
 
 from thrift.transport import TTwisted
 from thrift.protocol import TBinaryProtocol
-from thrift.server import TServer
+
 
 class CalculatorHandler:
-  implements(Calculator.Iface)  
-  def __init__(self):
-    self.log = {}
+    implements(Calculator.Iface)
 
-  def ping(self):
-    print 'ping()'
+    def __init__(self):
+        self.log = {}
 
-  def add(self, n1, n2):
-    print 'add(%d,%d)' % (n1, n2)
-    return n1+n2
+    def ping(self):
+        print('ping()')
 
-  def calculate(self, logid, work):
-    print 'calculate(%d, %r)' % (logid, work)
+    def add(self, n1, n2):
+        print('add(%d,%d)' % (n1, n2))
+        return n1 + n2
 
-    if work.op == Operation.ADD:
-      val = work.num1 + work.num2
-    elif work.op == Operation.SUBTRACT:
-      val = work.num1 - work.num2
-    elif work.op == Operation.MULTIPLY:
-      val = work.num1 * work.num2
-    elif work.op == Operation.DIVIDE:
-      if work.num2 == 0:
-        x = InvalidOperation()
-        x.what = work.op
-        x.why = 'Cannot divide by 0'
-        raise x
-      val = work.num1 / work.num2
-    else:
-      x = InvalidOperation()
-      x.what = work.op
-      x.why = 'Invalid operation'
-      raise x
+    def calculate(self, logid, work):
+        print('calculate(%d, %r)' % (logid, work))
 
-    log = SharedStruct()
-    log.key = logid
-    log.value = '%d' % (val)
-    self.log[logid] = log
+        if work.op == Operation.ADD:
+            val = work.num1 + work.num2
+        elif work.op == Operation.SUBTRACT:
+            val = work.num1 - work.num2
+        elif work.op == Operation.MULTIPLY:
+            val = work.num1 * work.num2
+        elif work.op == Operation.DIVIDE:
+            if work.num2 == 0:
+                x = InvalidOperation()
+                x.whatOp = work.op
+                x.why = 'Cannot divide by 0'
+                raise x
+            val = work.num1 / work.num2
+        else:
+            x = InvalidOperation()
+            x.whatOp = work.op
+            x.why = 'Invalid operation'
+            raise x
 
-    return val
+        log = SharedStruct()
+        log.key = logid
+        log.value = '%d' % (val)
+        self.log[logid] = log
 
-  def getStruct(self, key):
-    print 'getStruct(%d)' % (key)
-    return self.log[key]
+        return val
 
-  def zip(self):
-    print 'zip()'
+    def getStruct(self, key):
+        print('getStruct(%d)' % (key))
+        return self.log[key]
+
+    def zip(self):
+        print('zip()')
 
 if __name__ == '__main__':
     handler = CalculatorHandler()
     processor = Calculator.Processor(handler)
     pfactory = TBinaryProtocol.TBinaryProtocolFactory()
-    server = reactor.listenTCP(9090,
-                TTwisted.ThriftServerFactory(processor,
-                pfactory), interface="127.0.0.1")
+    server = reactor.listenTCP(
+        9090,
+        TTwisted.ThriftServerFactory(processor, pfactory),
+        interface="127.0.0.1")
     reactor.run()
diff --git a/tutorial/py.twisted/PythonServer.tac b/tutorial/py.twisted/PythonServer.tac
index 1d0b6c4..0479636 100755
--- a/tutorial/py.twisted/PythonServer.tac
+++ b/tutorial/py.twisted/PythonServer.tac
@@ -22,12 +22,14 @@
 from twisted.application import internet, service
 from thrift.transport import TTwisted
 
-import sys, glob
+import glob
+import sys
 sys.path.append('gen-py.twisted')
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0])
 from tutorial import Calculator
-from tutorial.ttypes import *
 from PythonServer import CalculatorHandler
+from thrift.protocol import TBinaryProtocol
+
 
 def make_application():
     application = service.Application('CalcServer')
@@ -35,8 +37,9 @@
     handler = CalculatorHandler()
     processor = Calculator.Processor(handler)
 
-    serverFactory = TTwisted.ThriftServerFactory(processor,
-                                 TBinaryProtocol.TBinaryProtocolFactory())
+    serverFactory = TTwisted.ThriftServerFactory(
+        processor,
+        TBinaryProtocol.TBinaryProtocolFactory())
 
     calcService = internet.TCPServer(9090, serverFactory)
 
@@ -46,4 +49,5 @@
 
     return application
 
-application = make_application()
+if __name__ == '__main__':
+    application = make_application()
diff --git a/tutorial/py/Makefile.am b/tutorial/py/Makefile.am
index 2397a12..7db816d 100755
--- a/tutorial/py/Makefile.am
+++ b/tutorial/py/Makefile.am
@@ -17,8 +17,6 @@
 # under the License.
 #
 
-THRIFT = $(top_builddir)/compiler/cpp/thrift
-
 gen-py/tutorial/Calculator.py gen-py/shared/SharedService.py: $(top_srcdir)/tutorial/tutorial.thrift
 	$(THRIFT) --gen py -r $<
 
@@ -34,5 +32,6 @@
 	$(RM) -r gen-*
 
 EXTRA_DIST = \
+	setup.cfg \
 	PythonServer.py \
 	PythonClient.py
diff --git a/tutorial/py/PythonClient.py b/tutorial/py/PythonClient.py
index 0554ee1..a6c1966 100755
--- a/tutorial/py/PythonClient.py
+++ b/tutorial/py/PythonClient.py
@@ -19,65 +19,71 @@
 # under the License.
 #
 
-import sys, glob
+import sys
+import glob
 sys.path.append('gen-py')
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0])
 
 from tutorial import Calculator
-from tutorial.ttypes import *
+from tutorial.ttypes import InvalidOperation, Operation, Work
 
 from thrift import Thrift
 from thrift.transport import TSocket
 from thrift.transport import TTransport
 from thrift.protocol import TBinaryProtocol
 
-try:
 
-  # Make socket
-  transport = TSocket.TSocket('localhost', 9090)
+def main():
+    # Make socket
+    transport = TSocket.TSocket('localhost', 9090)
 
-  # Buffering is critical. Raw sockets are very slow
-  transport = TTransport.TBufferedTransport(transport)
+    # Buffering is critical. Raw sockets are very slow
+    transport = TTransport.TBufferedTransport(transport)
 
-  # Wrap in a protocol
-  protocol = TBinaryProtocol.TBinaryProtocol(transport)
+    # Wrap in a protocol
+    protocol = TBinaryProtocol.TBinaryProtocol(transport)
 
-  # Create a client to use the protocol encoder
-  client = Calculator.Client(protocol)
+    # Create a client to use the protocol encoder
+    client = Calculator.Client(protocol)
 
-  # Connect!
-  transport.open()
+    # Connect!
+    transport.open()
 
-  client.ping()
-  print 'ping()'
+    client.ping()
+    print('ping()')
 
-  sum = client.add(1,1)
-  print '1+1=%d' % (sum)
+    sum_ = client.add(1, 1)
+    print('1+1=%d' % sum_)
 
-  work = Work()
+    work = Work()
 
-  work.op = Operation.DIVIDE
-  work.num1 = 1
-  work.num2 = 0
+    work.op = Operation.DIVIDE
+    work.num1 = 1
+    work.num2 = 0
 
-  try:
-    quotient = client.calculate(1, work)
-    print 'Whoa? You know how to divide by zero?'
-  except InvalidOperation, io:
-    print 'InvalidOperation: %r' % io
+    try:
+        quotient = client.calculate(1, work)
+        print('Whoa? You know how to divide by zero?')
+        print('FYI the answer is %d' % quotient)
+    except InvalidOperation as e:
+        print('InvalidOperation: %r' % e)
 
-  work.op = Operation.SUBTRACT
-  work.num1 = 15
-  work.num2 = 10
+    work.op = Operation.SUBTRACT
+    work.num1 = 15
+    work.num2 = 10
 
-  diff = client.calculate(1, work)
-  print '15-10=%d' % (diff)
+    diff = client.calculate(1, work)
+    print('15-10=%d' % diff)
 
-  log = client.getStruct(1)
-  print 'Check log: %s' % (log.value)
+    log = client.getStruct(1)
+    print('Check log: %s' % log.value)
 
-  # Close!
-  transport.close()
+    # Close!
+    transport.close()
 
-except Thrift.TException, tx:
-  print '%s' % (tx.message)
+
+if __name__ == '__main__':
+    try:
+        main()
+    except Thrift.TException as tx:
+        print('%s' % tx.message)
diff --git a/tutorial/py/PythonServer.py b/tutorial/py/PythonServer.py
index 014a12e..e6421ef 100755
--- a/tutorial/py/PythonServer.py
+++ b/tutorial/py/PythonServer.py
@@ -19,12 +19,13 @@
 # under the License.
 #
 
-import sys, glob
+import glob
+import sys
 sys.path.append('gen-py')
-sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0])
 
 from tutorial import Calculator
-from tutorial.ttypes import *
+from tutorial.ttypes import InvalidOperation, Operation
 
 from shared.ttypes import SharedStruct
 
@@ -33,65 +34,70 @@
 from thrift.protocol import TBinaryProtocol
 from thrift.server import TServer
 
+
 class CalculatorHandler:
-  def __init__(self):
-    self.log = {}
+    def __init__(self):
+        self.log = {}
 
-  def ping(self):
-    print 'ping()'
+    def ping(self):
+        print('ping()')
 
-  def add(self, n1, n2):
-    print 'add(%d,%d)' % (n1, n2)
-    return n1+n2
+    def add(self, n1, n2):
+        print('add(%d,%d)' % (n1, n2))
+        return n1 + n2
 
-  def calculate(self, logid, work):
-    print 'calculate(%d, %r)' % (logid, work)
+    def calculate(self, logid, work):
+        print('calculate(%d, %r)' % (logid, work))
 
-    if work.op == Operation.ADD:
-      val = work.num1 + work.num2
-    elif work.op == Operation.SUBTRACT:
-      val = work.num1 - work.num2
-    elif work.op == Operation.MULTIPLY:
-      val = work.num1 * work.num2
-    elif work.op == Operation.DIVIDE:
-      if work.num2 == 0:
-        x = InvalidOperation()
-        x.what = work.op
-        x.why = 'Cannot divide by 0'
-        raise x
-      val = work.num1 / work.num2
-    else:
-      x = InvalidOperation()
-      x.what = work.op
-      x.why = 'Invalid operation'
-      raise x
+        if work.op == Operation.ADD:
+            val = work.num1 + work.num2
+        elif work.op == Operation.SUBTRACT:
+            val = work.num1 - work.num2
+        elif work.op == Operation.MULTIPLY:
+            val = work.num1 * work.num2
+        elif work.op == Operation.DIVIDE:
+            if work.num2 == 0:
+                x = InvalidOperation()
+                x.whatOp = work.op
+                x.why = 'Cannot divide by 0'
+                raise x
+            val = work.num1 / work.num2
+        else:
+            x = InvalidOperation()
+            x.whatOp = work.op
+            x.why = 'Invalid operation'
+            raise x
 
-    log = SharedStruct()
-    log.key = logid
-    log.value = '%d' % (val)
-    self.log[logid] = log
+        log = SharedStruct()
+        log.key = logid
+        log.value = '%d' % (val)
+        self.log[logid] = log
 
-    return val
+        return val
 
-  def getStruct(self, key):
-    print 'getStruct(%d)' % (key)
-    return self.log[key]
+    def getStruct(self, key):
+        print('getStruct(%d)' % (key))
+        return self.log[key]
 
-  def zip(self):
-    print 'zip()'
+    def zip(self):
+        print('zip()')
 
-handler = CalculatorHandler()
-processor = Calculator.Processor(handler)
-transport = TSocket.TServerSocket(port=9090)
-tfactory = TTransport.TBufferedTransportFactory()
-pfactory = TBinaryProtocol.TBinaryProtocolFactory()
 
-server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)
+if __name__ == '__main__':
+    handler = CalculatorHandler()
+    processor = Calculator.Processor(handler)
+    transport = TSocket.TServerSocket(host='127.0.0.1', port=9090)
+    tfactory = TTransport.TBufferedTransportFactory()
+    pfactory = TBinaryProtocol.TBinaryProtocolFactory()
 
-# You could do one of these for a multithreaded server
-#server = TServer.TThreadedServer(processor, transport, tfactory, pfactory)
-#server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory)
+    server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)
 
-print 'Starting the server...'
-server.serve()
-print 'done.'
+    # You could do one of these for a multithreaded server
+    # server = TServer.TThreadedServer(
+    #     processor, transport, tfactory, pfactory)
+    # server = TServer.TThreadPoolServer(
+    #     processor, transport, tfactory, pfactory)
+
+    print('Starting the server...')
+    server.serve()
+    print('done.')
diff --git a/tutorial/py/setup.cfg b/tutorial/py/setup.cfg
new file mode 100644
index 0000000..2a7120a
--- /dev/null
+++ b/tutorial/py/setup.cfg
@@ -0,0 +1,2 @@
+[flake8]
+ignore = E402
diff --git a/tutorial/rb/Makefile.am b/tutorial/rb/Makefile.am
index 369e903..9372413 100755
--- a/tutorial/rb/Makefile.am
+++ b/tutorial/rb/Makefile.am
@@ -17,8 +17,6 @@
 # under the License.
 #
 
-THRIFT = $(top_builddir)/compiler/cpp/thrift
-
 gen-py/calculator.rb gen-py/shared_service.rb: $(top_srcdir)/tutorial/tutorial.thrift
 	$(THRIFT) --gen rb -r $<
 
diff --git a/tutorial/rb/RubyServer.rb b/tutorial/rb/RubyServer.rb
index 22cec31..1d707d7 100755
--- a/tutorial/rb/RubyServer.rb
+++ b/tutorial/rb/RubyServer.rb
@@ -52,14 +52,14 @@
     elsif work.op == Operation::DIVIDE
       if work.num2 == 0
         x = InvalidOperation.new()
-        x.what = work.op
+        x.whatOp = work.op
         x.why = "Cannot divide by 0"
         raise x
       end
       val = work.num1 / work.num2
     else
       x = InvalidOperation.new()
-      x.what = work.op
+      x.whatOp = work.op
       x.why = "Invalid operation"
       raise x
     end
diff --git a/tutorial/rs/Cargo.toml b/tutorial/rs/Cargo.toml
new file mode 100644
index 0000000..210a0da
--- /dev/null
+++ b/tutorial/rs/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "thrift-tutorial"
+version = "0.1.0"
+license = "Apache-2.0"
+authors = ["Apache Thrift Developers <dev@thrift.apache.org>"]
+exclude = ["Makefile*", "shared.rs", "tutorial.rs"]
+publish = false
+
+[dependencies]
+clap = "<2.28.0"
+ordered-float = "0.3.0"
+try_from = "0.2.0"
+
+[dependencies.thrift]
+path = "../../lib/rs"
+
diff --git a/tutorial/rs/Makefile.am b/tutorial/rs/Makefile.am
new file mode 100644
index 0000000..666331e
--- /dev/null
+++ b/tutorial/rs/Makefile.am
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+gen-rs/tutorial.rs gen-rs/shared.rs: $(top_srcdir)/tutorial/tutorial.thrift
+	$(THRIFT) -out src --gen rs -r $<
+
+all-local: gen-rs/tutorial.rs
+	$(CARGO) build
+	[ -d bin ] || mkdir bin
+	cp target/debug/tutorial_server bin/tutorial_server
+	cp target/debug/tutorial_client bin/tutorial_client
+
+check: all
+
+tutorialserver: all
+	bin/tutorial_server	
+
+tutorialclient: all
+	bin/tutorial_client
+
+clean-local:
+	$(CARGO) clean
+	-$(RM) Cargo.lock
+	-$(RM) src/shared.rs
+	-$(RM) src/tutorial.rs
+	-$(RM) -r bin
+
+EXTRA_DIST = \
+	Cargo.toml \
+	src/lib.rs \
+	src/bin/tutorial_server.rs \
+	src/bin/tutorial_client.rs \
+	README.md
+
diff --git a/tutorial/rs/README.md b/tutorial/rs/README.md
new file mode 100644
index 0000000..384e9f8
--- /dev/null
+++ b/tutorial/rs/README.md
@@ -0,0 +1,317 @@
+# Rust Language Bindings for Thrift
+
+## Getting Started
+
+1. Get the [Thrift compiler](https://thrift.apache.org).
+
+2. Add the following crates to your `Cargo.toml`.
+
+```toml
+thrift = "x.y.z" # x.y.z is the version of the thrift compiler
+ordered_float = "0.3.0"
+try_from = "0.2.0"
+```
+
+3. Add the same crates to your `lib.rs` or `main.rs`.
+
+```rust
+extern crate ordered_float;
+extern crate thrift;
+extern crate try_from;
+```
+
+4. Generate Rust sources for your IDL (for example, `Tutorial.thrift`).
+
+```shell
+thrift -out my_rust_program/src --gen rs -r Tutorial.thrift
+```
+
+5. Use the generated source in your code.
+
+```rust
+// add extern crates here, or in your lib.rs
+extern crate ordered_float;
+extern crate thrift;
+extern crate try_from;
+
+// generated Rust module
+use tutorial;
+
+use thrift::protocol::{TCompactInputProtocol, TCompactOutputProtocol};
+use thrift::protocol::{TInputProtocol, TOutputProtocol};
+use thrift::transport::{TFramedReadTransport, TFramedWriteTransport};
+use thrift::transport::{TIoChannel, TTcpChannel};
+use tutorial::{CalculatorSyncClient, TCalculatorSyncClient};
+use tutorial::{Operation, Work};
+
+fn main() {
+    match run() {
+        Ok(()) => println!("client ran successfully"),
+        Err(e) => {
+            println!("client failed with {:?}", e);
+            std::process::exit(1);
+        }
+    }
+}
+
+fn run() -> thrift::Result<()> {
+    //
+    // build client
+    //
+
+    println!("connect to server on 127.0.0.1:9090");
+    let mut c = TTcpTransport::new();
+    c.open("127.0.0.1:9090")?;
+
+    let (i_chan, o_chan) = c.split()?;
+    
+    let i_prot = TCompactInputProtocol::new(
+        TFramedReadTransport::new(i_chan)
+    );
+    let o_prot = TCompactOutputProtocol::new(
+        TFramedWriteTransport::new(o_chan)
+    );
+
+    let client = CalculatorSyncClient::new(i_prot, o_prot);
+
+    //
+    // alright! - let's make some calls
+    //
+
+    // two-way, void return
+    client.ping()?;
+
+    // two-way with some return
+    let res = client.calculate(
+        72,
+        Work::new(7, 8, Operation::MULTIPLY, None)
+    )?;
+    println!("multiplied 7 and 8, got {}", res);
+
+    // two-way and returns a Thrift-defined exception
+    let res = client.calculate(
+        77,
+        Work::new(2, 0, Operation::DIVIDE, None)
+    );
+    match res {
+        Ok(v) => panic!("shouldn't have succeeded with result {}", v),
+        Err(e) => println!("divide by zero failed with {:?}", e),
+    }
+
+    // one-way
+    client.zip()?;
+
+    // done!
+    Ok(())
+}
+```
+
+## Code Generation
+
+### Thrift Files and Generated Modules
+
+The Thrift code generator takes each Thrift file and generates a Rust module
+with the same name snake-cased. For example, running the compiler on
+`ThriftTest.thrift` creates `thrift_test.rs`. To use these generated files add
+`mod ...` and `use ...` declarations to your `lib.rs` or `main.rs` - one for
+each generated file.
+
+### Results and Errors
+
+The Thrift runtime library defines a `thrift::Result` and a `thrift::Error` type,
+both of which are used throught the runtime library and in all generated code.
+Conversions are defined from `std::io::Error`, `str` and `String` into
+`thrift::Error`.
+
+### Thrift Type and their Rust Equivalents
+
+Thrift defines a number of types, each of which is translated into its Rust
+equivalent by the code generator.
+
+* Primitives (bool, i8, i16, i32, i64, double, string, binary)
+* Typedefs
+* Enums
+* Containers
+* Structs
+* Unions
+* Exceptions
+* Services
+* Constants (primitives, containers, structs)
+
+In addition, unless otherwise noted, thrift includes are translated into
+`use ...` statements in the generated code, and all declarations, parameters,
+traits and types in the generated code are namespaced appropriately.
+
+The following subsections cover each type and their generated Rust equivalent.
+
+### Primitives
+
+Thrift primitives have straightforward Rust equivalents.
+
+* bool: `bool`
+* i8: `i8`
+* i16: `i16`
+* i32: `i32`
+* i64: `i64`
+* double: `OrderedFloat<f64>`
+* string: `String`
+* binary: `Vec<u8>`
+
+### Typedefs
+
+A typedef is translated to a `pub type` declaration.
+
+```thrift
+typedef i64 UserId
+
+typedef map<string, UserId> MapType
+```
+```rust
+pub type UserId = i64;
+
+pub type MapType = BTreeMap<String, Bonk>;
+```
+
+### Enums
+
+A Thrift enum is represented as a Rust enum, and each variant is transcribed 1:1.
+
+```thrift
+enum Numberz
+{
+    ONE = 1,
+    TWO,
+    THREE,
+    FIVE = 5,
+    SIX,
+    EIGHT = 8
+}
+```
+
+```rust
+#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+pub enum Numberz {
+    ONE = 1,
+    TWO = 2,
+    THREE = 3,
+    FIVE = 5,
+    SIX = 6,
+    EIGHT = 8,
+}
+
+impl TryFrom<i32> for Numberz {
+    // ...
+}
+
+```
+
+### Containers
+
+Thrift has three container types: list, set and map. They are translated into
+Rust `Vec`, `BTreeSet` and `BTreeMap` respectively. Any Thrift type (this
+includes structs, enums and typedefs) can be a list/set element or a map
+key/value.
+
+#### List
+
+```thrift
+list <i32> numbers
+```
+
+```rust
+numbers: Vec<i32>
+```
+
+#### Set
+
+```thrift
+set <i32> numbers
+```
+
+```rust
+numbers: BTreeSet<i32>
+```
+
+#### Map
+
+```thrift
+map <string, i32> numbers
+```
+
+```rust
+numbers: BTreeMap<String, i32>
+```
+
+### Structs
+
+A Thrift struct is represented as a Rust struct, and each field transcribed 1:1.
+
+```thrift
+struct CrazyNesting {
+    1: string string_field,
+    2: optional set<Insanity> set_field,
+    3: required list<
+         map<set<i32>, map<i32,set<list<map<Insanity,string>>>>>
+       >
+    4: binary binary_field
+}
+```
+```rust
+#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+pub struct CrazyNesting {
+    pub string_field: Option<String>,
+    pub set_field: Option<BTreeSet<Insanity>>,
+    pub list_field: Vec<
+        BTreeMap<
+            BTreeSet<i32>,
+            BTreeMap<i32, BTreeSet<Vec<BTreeMap<Insanity, String>>>>
+        >
+    >,
+    pub binary_field: Option<Vec<u8>>,
+}
+
+impl CrazyNesting {
+    pub fn read_from_in_protocol(i_prot: &mut TInputProtocol)
+    ->
+    thrift::Result<CrazyNesting> {
+        // ...
+    }
+    pub fn write_to_out_protocol(&self, o_prot: &mut TOutputProtocol)
+    ->
+    thrift::Result<()> {
+        // ...
+    }
+}
+
+```
+##### Optionality
+
+Thrift has 3 "optionality" types:
+
+1. Required
+2. Optional
+3. Default
+
+The Rust code generator encodes *Required* fields as the bare type itself, while
+*Optional* and *Default* fields are encoded as `Option<TypeName>`.
+
+```thrift
+struct Foo {
+    1: required string bar  // 1. required
+    2: optional string baz  // 2. optional
+    3: string qux           // 3. default
+}
+```
+
+```rust
+pub struct Foo {
+    bar: String,            // 1. required
+    baz: Option<String>,    // 2. optional
+    qux: Option<String>,    // 3. default
+}
+```
+
+## Known Issues
+
+* Struct constants are not supported
+* Map, list and set constants require a const holder struct
diff --git a/tutorial/rs/src/bin/tutorial_client.rs b/tutorial/rs/src/bin/tutorial_client.rs
new file mode 100644
index 0000000..c80fafc
--- /dev/null
+++ b/tutorial/rs/src/bin/tutorial_client.rs
@@ -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.
+
+#[macro_use]
+extern crate clap;
+
+extern crate thrift;
+extern crate thrift_tutorial;
+
+use thrift::protocol::{TCompactInputProtocol, TCompactOutputProtocol};
+use thrift::transport::{
+    ReadHalf, TFramedReadTransport, TFramedWriteTransport, TIoChannel, TTcpChannel, WriteHalf,
+};
+
+use thrift_tutorial::shared::TSharedServiceSyncClient;
+use thrift_tutorial::tutorial::{CalculatorSyncClient, Operation, TCalculatorSyncClient, Work};
+
+fn main() {
+    match run() {
+        Ok(()) => println!("tutorial client ran successfully"),
+        Err(e) => {
+            println!("tutorial client failed with error {:?}", e);
+            std::process::exit(1);
+        }
+    }
+}
+
+fn run() -> thrift::Result<()> {
+    let options = clap_app!(rust_tutorial_client =>
+        (version: "0.1.0")
+        (author: "Apache Thrift Developers <dev@thrift.apache.org>")
+        (about: "Thrift Rust tutorial client")
+        (@arg host: --host +takes_value "host on which the tutorial server listens")
+        (@arg port: --port +takes_value "port on which the tutorial server listens")
+    );
+    let matches = options.get_matches();
+
+    // get any passed-in args or the defaults
+    let host = matches.value_of("host").unwrap_or("127.0.0.1");
+    let port = value_t!(matches, "port", u16).unwrap_or(9090);
+
+    // build our client and connect to the host:port
+    let mut client = new_client(host, port)?;
+
+    // alright!
+    // let's start making some calls
+
+    // let's start with a ping; the server should respond
+    println!("ping!");
+    client.ping()?;
+
+    // simple add
+    println!("add");
+    let res = client.add(1, 2)?;
+    println!("added 1, 2 and got {}", res);
+
+    let logid = 32;
+
+    // let's do...a multiply!
+    let res = client.calculate(logid, Work::new(7, 8, Operation::Multiply, None))?;
+    println!("multiplied 7 and 8 and got {}", res);
+
+    // let's get the log for it
+    let res = client.get_struct(32)?;
+    println!("got log {:?} for operation {}", res, logid);
+
+    // ok - let's be bad :(
+    // do a divide by 0
+    // logid doesn't matter; won't be recorded
+    let res = client.calculate(77, Work::new(2, 0, Operation::Divide, "we bad".to_owned()));
+
+    // we should have gotten an exception back
+    match res {
+        Ok(v) => panic!("should not have succeeded with result {}", v),
+        Err(e) => println!("divide by zero failed with error {:?}", e),
+    }
+
+    // let's do a one-way call
+    println!("zip");
+    client.zip()?;
+
+    // and then close out with a final ping
+    println!("ping!");
+    client.ping()?;
+
+    Ok(())
+}
+
+type ClientInputProtocol = TCompactInputProtocol<TFramedReadTransport<ReadHalf<TTcpChannel>>>;
+type ClientOutputProtocol = TCompactOutputProtocol<TFramedWriteTransport<WriteHalf<TTcpChannel>>>;
+
+fn new_client(
+    host: &str,
+    port: u16,
+) -> thrift::Result<CalculatorSyncClient<ClientInputProtocol, ClientOutputProtocol>> {
+    let mut c = TTcpChannel::new();
+
+    // open the underlying TCP stream
+    println!("connecting to tutorial server on {}:{}", host, port);
+    c.open(&format!("{}:{}", host, port))?;
+
+    // clone the TCP channel into two halves, one which
+    // we'll use for reading, the other for writing
+    let (i_chan, o_chan) = c.split()?;
+
+    // wrap the raw sockets (slow) with a buffered transport of some kind
+    let i_tran = TFramedReadTransport::new(i_chan);
+    let o_tran = TFramedWriteTransport::new(o_chan);
+
+    // now create the protocol implementations
+    let i_prot = TCompactInputProtocol::new(i_tran);
+    let o_prot = TCompactOutputProtocol::new(o_tran);
+
+    // we're done!
+    Ok(CalculatorSyncClient::new(i_prot, o_prot))
+}
diff --git a/tutorial/rs/src/bin/tutorial_server.rs b/tutorial/rs/src/bin/tutorial_server.rs
new file mode 100644
index 0000000..95b1a2b
--- /dev/null
+++ b/tutorial/rs/src/bin/tutorial_server.rs
@@ -0,0 +1,179 @@
+// 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.
+
+#[macro_use]
+extern crate clap;
+
+extern crate thrift;
+extern crate thrift_tutorial;
+
+use std::collections::HashMap;
+use std::convert::{From, Into};
+use std::default::Default;
+use std::sync::Mutex;
+
+use thrift::protocol::{TCompactInputProtocolFactory, TCompactOutputProtocolFactory};
+use thrift::server::TServer;
+
+use thrift::transport::{TFramedReadTransportFactory, TFramedWriteTransportFactory};
+use thrift_tutorial::shared::{SharedServiceSyncHandler, SharedStruct};
+use thrift_tutorial::tutorial::{CalculatorSyncHandler, CalculatorSyncProcessor};
+use thrift_tutorial::tutorial::{InvalidOperation, Operation, Work};
+
+fn main() {
+    match run() {
+        Ok(()) => println!("tutorial server ran successfully"),
+        Err(e) => {
+            println!("tutorial server failed with error {:?}", e);
+            std::process::exit(1);
+        }
+    }
+}
+
+fn run() -> thrift::Result<()> {
+    let options = clap_app!(rust_tutorial_server =>
+        (version: "0.1.0")
+        (author: "Apache Thrift Developers <dev@thrift.apache.org>")
+        (about: "Thrift Rust tutorial server")
+        (@arg port: --port +takes_value "port on which the tutorial server listens")
+    );
+    let matches = options.get_matches();
+
+    let port = value_t!(matches, "port", u16).unwrap_or(9090);
+    let listen_address = format!("127.0.0.1:{}", port);
+
+    println!("binding to {}", listen_address);
+
+    let i_tran_fact = TFramedReadTransportFactory::new();
+    let i_prot_fact = TCompactInputProtocolFactory::new();
+
+    let o_tran_fact = TFramedWriteTransportFactory::new();
+    let o_prot_fact = TCompactOutputProtocolFactory::new();
+
+    // demux incoming messages
+    let processor = CalculatorSyncProcessor::new(CalculatorServer {
+        ..Default::default()
+    });
+
+    // create the server and start listening
+    let mut server = TServer::new(
+        i_tran_fact,
+        i_prot_fact,
+        o_tran_fact,
+        o_prot_fact,
+        processor,
+        10,
+    );
+
+    server.listen(&listen_address)
+}
+
+/// Handles incoming Calculator service calls.
+struct CalculatorServer {
+    log: Mutex<HashMap<i32, SharedStruct>>,
+}
+
+impl Default for CalculatorServer {
+    fn default() -> CalculatorServer {
+        CalculatorServer {
+            log: Mutex::new(HashMap::new()),
+        }
+    }
+}
+
+// since Calculator extends SharedService we have to implement the
+// handler for both traits.
+//
+
+// SharedService handler
+impl SharedServiceSyncHandler for CalculatorServer {
+    fn handle_get_struct(&self, key: i32) -> thrift::Result<SharedStruct> {
+        let log = self.log.lock().unwrap();
+        log.get(&key)
+            .cloned()
+            .ok_or_else(|| format!("could not find log for key {}", key).into())
+    }
+}
+
+// Calculator handler
+impl CalculatorSyncHandler for CalculatorServer {
+    fn handle_ping(&self) -> thrift::Result<()> {
+        println!("pong!");
+        Ok(())
+    }
+
+    fn handle_add(&self, num1: i32, num2: i32) -> thrift::Result<i32> {
+        println!("handling add: n1:{} n2:{}", num1, num2);
+        Ok(num1 + num2)
+    }
+
+    fn handle_calculate(&self, logid: i32, w: Work) -> thrift::Result<i32> {
+        println!("handling calculate: l:{}, w:{:?}", logid, w);
+
+        let res = if let Some(ref op) = w.op {
+            if w.num1.is_none() || w.num2.is_none() {
+                Err(InvalidOperation {
+                    what_op: Some(*op as i32),
+                    why: Some("no operands specified".to_owned()),
+                })
+            } else {
+                // so that I don't have to call unwrap() multiple times below
+                let num1 = w.num1.as_ref().expect("operands checked");
+                let num2 = w.num2.as_ref().expect("operands checked");
+
+                match *op {
+                    Operation::Add => Ok(num1 + num2),
+                    Operation::Subtract => Ok(num1 - num2),
+                    Operation::Multiply => Ok(num1 * num2),
+                    Operation::Divide => {
+                        if *num2 == 0 {
+                            Err(InvalidOperation {
+                                what_op: Some(*op as i32),
+                                why: Some("divide by 0".to_owned()),
+                            })
+                        } else {
+                            Ok(num1 / num2)
+                        }
+                    }
+                }
+            }
+        } else {
+            Err(InvalidOperation::new(
+                None,
+                "no operation specified".to_owned(),
+            ))
+        };
+
+        // if the operation was successful log it
+        if let Ok(ref v) = res {
+            let mut log = self.log.lock().unwrap();
+            log.insert(logid, SharedStruct::new(logid, format!("{}", v)));
+        }
+
+        // the try! macro automatically maps errors
+        // but, since we aren't using that here we have to map errors manually
+        //
+        // exception structs defined in the IDL have an auto-generated
+        // impl of From::from
+        res.map_err(From::from)
+    }
+
+    fn handle_zip(&self) -> thrift::Result<()> {
+        println!("handling zip");
+        Ok(())
+    }
+}
diff --git a/tutorial/rs/src/lib.rs b/tutorial/rs/src/lib.rs
new file mode 100644
index 0000000..40007e5
--- /dev/null
+++ b/tutorial/rs/src/lib.rs
@@ -0,0 +1,23 @@
+// 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.
+
+extern crate ordered_float;
+extern crate thrift;
+extern crate try_from;
+
+pub mod shared;
+pub mod tutorial;
diff --git a/tutorial/shared.thrift b/tutorial/shared.thrift
index db4b694..f1685bd 100644
--- a/tutorial/shared.thrift
+++ b/tutorial/shared.thrift
@@ -22,11 +22,15 @@
  * these definitions.
  */
 
+namespace cl shared
 namespace cpp shared
 namespace d share // "shared" would collide with the eponymous D keyword.
+namespace dart shared
 namespace java shared
 namespace perl shared
 namespace php shared
+namespace haxe shared
+namespace netcore shared
 
 struct SharedStruct {
   1: i32 key
diff --git a/tutorial/tutorial.thrift b/tutorial/tutorial.thrift
index 3150151..e027546 100644
--- a/tutorial/tutorial.thrift
+++ b/tutorial/tutorial.thrift
@@ -32,7 +32,7 @@
  * The first thing to know about are types. The available types in Thrift are:
  *
  *  bool        Boolean, one byte
- *  byte        Signed byte
+ *  i8 (byte)   Signed 8-bit integer
  *  i16         Signed 16-bit integer
  *  i32         Signed 32-bit integer
  *  i64         Signed 64-bit integer
@@ -62,11 +62,16 @@
  * Thrift files can namespace, package, or prefix their output in various
  * target languages.
  */
+
+namespace cl tutorial
 namespace cpp tutorial
 namespace d tutorial
+namespace dart tutorial
 namespace java tutorial
 namespace php tutorial
 namespace perl tutorial
+namespace haxe tutorial
+namespace netcore tutorial
 
 /**
  * Thrift lets you do typedefs to get pretty names for your types. Standard
@@ -112,7 +117,7 @@
  * Structs can also be exceptions, if they are nasty.
  */
 exception InvalidOperation {
-  1: i32 what,
+  1: i32 whatOp,
   2: string why
 }